summaryrefslogtreecommitdiffstats
path: root/demos/gradients
Commit message (Expand)AuthorAgeFilesLines
* Update copyright year to 2010Jason McDonald2010-01-063-3/+3
* Ran the script utils/normalizeOlivier Goffart2009-11-181-3/+3
* Enable multitouch on the Gradients demoBenjamin Poulain2009-10-021-1/+3
* Update license headers again.Jason McDonald2009-09-093-12/+12
* Merge branch '4.5' into 4.6Thiago Macieira2009-08-313-39/+39
|\
| * Update tech preview license header.Jason McDonald2009-08-313-39/+39
| * Update license headers.Jason McDonald2009-08-113-3/+3
* | Rename demobase.pri to symbianpkgrules.priEspen Riskedal2009-08-211-1/+1
* | Merge commit 'qt/master'Jason Barron2009-08-133-3/+3
|\ \
| * | Update contact URL in license headers.Jason McDonald2009-08-123-3/+3
| |/
* | Merge commit 'qt/master-stable' into 4.6-mergedJason Barron2009-06-303-6/+6
|\ \ | |/
| * Update license headers as requested by the marketing department.Jason McDonald2009-06-163-6/+6
| * Long live Qt 4.5!Lars Knoll2009-03-236-0/+802
* Long live Qt for S60!axis2009-04-246-0/+804
le summary='file diffstat' width='100%'> -rw-r--r--.gitlab/ci/configure_debian10_aarch64_ninja.cmake67
-rw-r--r--.gitlab/ci/configure_debian10_iwyu.cmake4
-rw-r--r--.gitlab/ci/configure_debian10_ninja.cmake69
-rw-r--r--.gitlab/ci/configure_external_test.cmake3
-rw-r--r--.gitlab/ci/configure_fedora33_common.cmake6
-rw-r--r--.gitlab/ci/configure_fedora33_makefiles.cmake68
-rw-r--r--.gitlab/ci/configure_fedora33_ninja.cmake7
-rw-r--r--.gitlab/ci/configure_fedora33_ninja_multi.cmake2
-rw-r--r--.gitlab/ci/configure_fedora33_sphinx.cmake2
-rw-r--r--.gitlab/ci/configure_fedora33_sphinx_package.cmake13
-rw-r--r--.gitlab/ci/configure_fedora33_tidy.cmake3
-rw-r--r--.gitlab/ci/configure_intelclassic_makefiles.cmake1
-rw-r--r--.gitlab/ci/configure_inteloneapi_makefiles.cmake1
-rw-r--r--.gitlab/ci/configure_macos10.10_package.cmake4
-rw-r--r--.gitlab/ci/configure_macos_arm64_ninja.cmake3
-rw-r--r--.gitlab/ci/configure_macos_arm64_xcode.cmake2
-rw-r--r--.gitlab/ci/configure_macos_common.cmake18
-rw-r--r--.gitlab/ci/configure_macos_package.cmake4
-rw-r--r--.gitlab/ci/configure_macos_package_common.cmake26
-rw-r--r--.gitlab/ci/configure_macos_x86_64_makefiles.cmake3
-rw-r--r--.gitlab/ci/configure_macos_x86_64_ninja.cmake3
-rw-r--r--.gitlab/ci/configure_macos_x86_64_xcode.cmake2
-rw-r--r--.gitlab/ci/configure_sccache.cmake2
-rw-r--r--.gitlab/ci/configure_sphinx.cmake6
-rw-r--r--.gitlab/ci/configure_windows_common.cmake4
-rw-r--r--.gitlab/ci/configure_windows_vs2019_x64.cmake3
-rw-r--r--.gitlab/ci/configure_windows_vs2019_x64_ninja.cmake7
-rw-r--r--.gitlab/ci/ctest_build.cmake49
-rw-r--r--.gitlab/ci/ctest_configure.cmake32
-rw-r--r--.gitlab/ci/ctest_exclusions.cmake19
-rw-r--r--.gitlab/ci/ctest_test.cmake30
-rw-r--r--.gitlab/ci/ctest_test_external.cmake88
-rw-r--r--.gitlab/ci/docker/cuda10.2/Dockerfile5
-rwxr-xr-x.gitlab/ci/docker/cuda10.2/install_deps.sh13
-rw-r--r--.gitlab/ci/docker/debian10-aarch64/Dockerfile5
-rwxr-xr-x.gitlab/ci/docker/debian10-aarch64/install_deps.sh76
-rw-r--r--.gitlab/ci/docker/debian10/Dockerfile25
-rwxr-xr-x.gitlab/ci/docker/debian10/install_deps.sh83
-rwxr-xr-x.gitlab/ci/docker/debian10/install_iwyu.sh32
-rwxr-xr-x.gitlab/ci/docker/debian10/install_rvm.sh19
-rw-r--r--.gitlab/ci/docker/fedora33/Dockerfile18
-rwxr-xr-x.gitlab/ci/docker/fedora33/install_deps.sh82
-rwxr-xr-x.gitlab/ci/docker/fedora33/install_ispc.sh14
-rwxr-xr-x.gitlab/ci/docker/fedora33/install_rvm.sh21
-rwxr-xr-x.gitlab/ci/docker/ninja/centos7-aarch64.bash20
-rw-r--r--.gitlab/ci/docker/ninja/centos7-aarch64/Dockerfile7
-rwxr-xr-x.gitlab/ci/docker/ninja/centos7-aarch64/build_ninja.sh11
-rw-r--r--.gitlab/ci/download_python3.cmake41
-rw-r--r--.gitlab/ci/download_qt.cmake135
-rw-r--r--.gitlab/ci/download_qt_hashes.cmake14
-rw-r--r--.gitlab/ci/env.sh14
-rw-r--r--.gitlab/ci/env_debian10_ninja.cmake1
-rw-r--r--.gitlab/ci/env_fedora33_makefiles.cmake2
-rw-r--r--.gitlab/ci/env_intelclassic_common.sh9
-rw-r--r--.gitlab/ci/env_intelclassic_makefiles.sh1
-rw-r--r--.gitlab/ci/env_intelcompiler_license.sh8
-rw-r--r--.gitlab/ci/env_inteloneapi_common.sh7
-rw-r--r--.gitlab/ci/env_inteloneapi_makefiles.sh1
-rw-r--r--.gitlab/ci/gitlab_ci.cmake75
-rwxr-xr-x.gitlab/ci/ninja.ps118
-rwxr-xr-x.gitlab/ci/ninja.sh41
-rwxr-xr-x.gitlab/ci/sccache.sh58
-rwxr-xr-x.gitlab/ci/vcvarsall.ps19
-rwxr-xr-x.gitlab/ci/wix.ps118
-rw-r--r--.gitlab/os-linux.yml370
-rw-r--r--.gitlab/os-macos.yml187
-rw-r--r--.gitlab/os-windows.yml125
-rw-r--r--.gitlab/rules.yml63
-rw-r--r--.gitlab/upload.yml18
-rw-r--r--.hooks-config10
-rw-r--r--Auxiliary/CMakeLists.txt16
-rw-r--r--Auxiliary/bash-completion/CMakeLists.txt21
-rw-r--r--Auxiliary/bash-completion/cmake166
-rw-r--r--Auxiliary/bash-completion/cpack88
-rw-r--r--Auxiliary/bash-completion/ctest118
-rw-r--r--Auxiliary/cmake-mode.el473
-rw-r--r--Auxiliary/cmake.m444
-rw-r--r--Auxiliary/vim/cmake.vim.in130
-rwxr-xr-xAuxiliary/vim/extract-upper-case.pl213
-rw-r--r--Auxiliary/vim/indent/cmake.vim89
-rw-r--r--Auxiliary/vim/syntax/cmake.vim4099
-rw-r--r--CMakeCPack.cmake267
-rw-r--r--CMakeCPackOptions.cmake.in313
-rw-r--r--CMakeGraphVizOptions.cmake1
-rw-r--r--CMakeLists.txt1824
-rw-r--r--CMakeLogo.gifbin0 -> 4481 bytes-rw-r--r--CONTRIBUTING.rst80
-rw-r--r--CTestConfig.cmake17
-rw-r--r--CTestCustom.cmake.in139
-rw-r--r--CompileFlags.cmake138
-rw-r--r--Copyright.txt98
-rw-r--r--DartConfig.cmake10
-rw-r--r--Help/command/DEVICE_LINK_OPTIONS.txt12
-rw-r--r--Help/command/FIND_XXX.txt167
-rw-r--r--Help/command/FIND_XXX_ORDER.txt12
-rw-r--r--Help/command/FIND_XXX_ROOT.txt29
-rw-r--r--Help/command/LINK_OPTIONS_LINKER.txt22
-rw-r--r--Help/command/OPTIONS_SHELL.txt11
-rw-r--r--Help/command/add_compile_definitions.rst27
-rw-r--r--Help/command/add_compile_options.rst51
-rw-r--r--Help/command/add_custom_command.rst433
-rw-r--r--Help/command/add_custom_target.rst181
-rw-r--r--Help/command/add_definitions.rst35
-rw-r--r--Help/command/add_dependencies.rst26
-rw-r--r--Help/command/add_executable.rst109
-rw-r--r--Help/command/add_library.rst259
-rw-r--r--Help/command/add_link_options.rst35
-rw-r--r--Help/command/add_subdirectory.rst35
-rw-r--r--Help/command/add_test.rst82
-rw-r--r--Help/command/aux_source_directory.rst24
-rw-r--r--Help/command/break.rst12
-rw-r--r--Help/command/build_command.rst45
-rw-r--r--Help/command/build_name.rst15
-rw-r--r--Help/command/cmake_host_system_information.rst58
-rw-r--r--Help/command/cmake_language.rst227
-rw-r--r--Help/command/cmake_minimum_required.rst74
-rw-r--r--Help/command/cmake_parse_arguments.rst115
-rw-r--r--Help/command/cmake_path.rst784
-rw-r--r--Help/command/cmake_policy.rst111
-rw-r--r--Help/command/configure_file.rst183
-rw-r--r--Help/command/continue.rst16
-rw-r--r--Help/command/create_test_sourcelist.rst30
-rw-r--r--Help/command/ctest_build.rst85
-rw-r--r--Help/command/ctest_configure.rst50
-rw-r--r--Help/command/ctest_coverage.rst50
-rw-r--r--Help/command/ctest_empty_binary_directory.rst12
-rw-r--r--Help/command/ctest_memcheck.rst40
-rw-r--r--Help/command/ctest_read_custom_files.rst14
-rw-r--r--Help/command/ctest_run_script.rst15
-rw-r--r--Help/command/ctest_sleep.rst16
-rw-r--r--Help/command/ctest_start.rst88
-rw-r--r--Help/command/ctest_submit.rst130
-rw-r--r--Help/command/ctest_test.rst162
-rw-r--r--Help/command/ctest_update.rst43
-rw-r--r--Help/command/ctest_upload.rst26
-rw-r--r--Help/command/define_property.rst59
-rw-r--r--Help/command/else.rst10
-rw-r--r--Help/command/elseif.rst11
-rw-r--r--Help/command/enable_language.rst35
-rw-r--r--Help/command/enable_testing.rst20
-rw-r--r--Help/command/endforeach.rst14
-rw-r--r--Help/command/endfunction.rst14
-rw-r--r--Help/command/endif.rst14
-rw-r--r--Help/command/endmacro.rst14
-rw-r--r--Help/command/endwhile.rst14
-rw-r--r--Help/command/exec_program.rst26
-rw-r--r--Help/command/execute_process.rst158
-rw-r--r--Help/command/export.rst93
-rw-r--r--Help/command/export_library_dependencies.rst28
-rw-r--r--Help/command/file.rst1182
-rw-r--r--Help/command/find_file.rst37
-rw-r--r--Help/command/find_library.rst82
-rw-r--r--Help/command/find_package.rst540
-rw-r--r--Help/command/find_path.rst42
-rw-r--r--Help/command/find_program.rst36
-rw-r--r--Help/command/fltk_wrap_ui.rst14
-rw-r--r--Help/command/foreach.rst129
-rw-r--r--Help/command/function.rst75
-rw-r--r--Help/command/get_cmake_property.rst20
-rw-r--r--Help/command/get_directory_property.rst36
-rw-r--r--Help/command/get_filename_component.rst65
-rw-r--r--Help/command/get_property.rst101
-rw-r--r--Help/command/get_source_file_property.rst47
-rw-r--r--Help/command/get_target_property.rst27
-rw-r--r--Help/command/get_test_property.rst21
-rw-r--r--Help/command/if.rst355
-rw-r--r--Help/command/include.rst25
-rw-r--r--Help/command/include_directories.rst41
-rw-r--r--Help/command/include_external_msproject.rst27
-rw-r--r--Help/command/include_guard.rst48
-rw-r--r--Help/command/include_regular_expression.rst18
-rw-r--r--Help/command/install.rst762
-rw-r--r--Help/command/install_files.rst41
-rw-r--r--Help/command/install_programs.rst36
-rw-r--r--Help/command/install_targets.rst19
-rw-r--r--Help/command/link_directories.rst55
-rw-r--r--Help/command/link_libraries.rst19
-rw-r--r--Help/command/list.rst353
-rw-r--r--Help/command/load_cache.rst26
-rw-r--r--Help/command/load_command.rst23
-rw-r--r--Help/command/macro.rst151
-rw-r--r--Help/command/make_directory.rst14
-rw-r--r--Help/command/mark_as_advanced.rst28
-rw-r--r--Help/command/math.rst38
-rw-r--r--Help/command/message.rst191
-rw-r--r--Help/command/option.rst16
-rw-r--r--Help/command/output_required_files.rst19
-rw-r--r--Help/command/project.rst164
-rw-r--r--Help/command/qt_wrap_cpp.rst23
-rw-r--r--Help/command/qt_wrap_ui.rst26
-rw-r--r--Help/command/remove.rst14
-rw-r--r--Help/command/remove_definitions.rst11
-rw-r--r--Help/command/return.rst20
-rw-r--r--Help/command/separate_arguments.rst80
-rw-r--r--Help/command/set.rst104
-rw-r--r--Help/command/set_directory_properties.rst15
-rw-r--r--Help/command/set_property.rst112
-rw-r--r--Help/command/set_source_files_properties.rst43
-rw-r--r--Help/command/set_target_properties.rst20
-rw-r--r--Help/command/set_tests_properties.rst17
-rw-r--r--Help/command/site_name.rst12
-rw-r--r--Help/command/source_group.rst67
-rw-r--r--Help/command/string.rst612
-rw-r--r--Help/command/subdir_depends.rst13
-rw-r--r--Help/command/subdirs.rst26
-rw-r--r--Help/command/target_compile_definitions.rst50
-rw-r--r--Help/command/target_compile_features.rst37
-rw-r--r--Help/command/target_compile_options.rst52
-rw-r--r--Help/command/target_include_directories.rst64
-rw-r--r--Help/command/target_link_directories.rst57
-rw-r--r--Help/command/target_link_libraries.rst322
-rw-r--r--Help/command/target_link_options.rst54
-rw-r--r--Help/command/target_precompile_headers.rst125
-rw-r--r--Help/command/target_sources.rst48
-rw-r--r--Help/command/try_compile.rst214
-rw-r--r--Help/command/try_run.rst123
-rw-r--r--Help/command/unset.rst41
-rw-r--r--Help/command/use_mangled_mesa.rst15
-rw-r--r--Help/command/utility_source.rst24
-rw-r--r--Help/command/variable_requires.rst22
-rw-r--r--Help/command/variable_watch.rst48
-rw-r--r--Help/command/while.rst25
-rw-r--r--Help/command/write_file.rst22
-rw-r--r--Help/cpack_gen/archive.rst88
-rw-r--r--Help/cpack_gen/bundle.rst76
-rw-r--r--Help/cpack_gen/cygwin.rst30
-rw-r--r--Help/cpack_gen/deb.rst678
-rw-r--r--Help/cpack_gen/dmg.rst129
-rw-r--r--Help/cpack_gen/external.rst294
-rw-r--r--Help/cpack_gen/freebsd.rst149
-rw-r--r--Help/cpack_gen/ifw.rst407
-rw-r--r--Help/cpack_gen/nsis.rst203
-rw-r--r--Help/cpack_gen/nuget.rst255
-rw-r--r--Help/cpack_gen/packagemaker.rst87
-rw-r--r--Help/cpack_gen/productbuild.rst138
-rw-r--r--Help/cpack_gen/rpm.rst1035
-rw-r--r--Help/cpack_gen/wix.rst322
-rw-r--r--Help/dev/README.rst53
-rw-r--r--Help/dev/documentation.rst556
-rw-r--r--Help/dev/experimental.rst70
-rw-r--r--Help/dev/maint.rst369
-rw-r--r--Help/dev/review.rst541
-rw-r--r--Help/dev/source.rst244
-rw-r--r--Help/dev/testing.rst43
-rw-r--r--Help/envvar/ASM_DIALECT.rst22
-rw-r--r--Help/envvar/ASM_DIALECTFLAGS.rst15
-rw-r--r--Help/envvar/CC.rst19
-rw-r--r--Help/envvar/CCMAKE_COLORS.rst36
-rw-r--r--Help/envvar/CFLAGS.rst13
-rw-r--r--Help/envvar/CMAKE_APPLE_SILICON_PROCESSOR.rst13
-rw-r--r--Help/envvar/CMAKE_BUILD_PARALLEL_LEVEL.rst13
-rw-r--r--Help/envvar/CMAKE_CONFIG_TYPE.rst7
-rw-r--r--Help/envvar/CMAKE_EXPORT_COMPILE_COMMANDS.rst11
-rw-r--r--Help/envvar/CMAKE_GENERATOR.rst18
-rw-r--r--Help/envvar/CMAKE_GENERATOR_INSTANCE.rst9
-rw-r--r--Help/envvar/CMAKE_GENERATOR_PLATFORM.rst10
-rw-r--r--Help/envvar/CMAKE_GENERATOR_TOOLSET.rst10
-rw-r--r--Help/envvar/CMAKE_LANG_COMPILER_LAUNCHER.rst12
-rw-r--r--Help/envvar/CMAKE_MSVCIDE_RUN_PATH.rst10
-rw-r--r--Help/envvar/CMAKE_NO_VERBOSE.rst10
-rw-r--r--Help/envvar/CMAKE_OSX_ARCHITECTURES.rst10
-rw-r--r--Help/envvar/CMAKE_PREFIX_PATH.rst17
-rw-r--r--Help/envvar/CSFLAGS.rst15
-rw-r--r--Help/envvar/CTEST_INTERACTIVE_DEBUG_MODE.rst7
-rw-r--r--Help/envvar/CTEST_OUTPUT_ON_FAILURE.rst9
-rw-r--r--Help/envvar/CTEST_PARALLEL_LEVEL.rst7
-rw-r--r--Help/envvar/CTEST_PROGRESS_OUTPUT.rst18
-rw-r--r--Help/envvar/CTEST_USE_LAUNCHERS_DEFAULT.rst6
-rw-r--r--Help/envvar/CUDAARCHS.rst13
-rw-r--r--Help/envvar/CUDACXX.rst21
-rw-r--r--Help/envvar/CUDAFLAGS.rst15
-rw-r--r--Help/envvar/CUDAHOSTCXX.rst20
-rw-r--r--Help/envvar/CXX.rst19
-rw-r--r--Help/envvar/CXXFLAGS.rst13
-rw-r--r--Help/envvar/DASHBOARD_TEST_FROM_CTEST.rst8
-rw-r--r--Help/envvar/DESTDIR.rst21
-rw-r--r--Help/envvar/ENV_VAR.txt3
-rw-r--r--Help/envvar/FC.rst20
-rw-r--r--Help/envvar/FFLAGS.rst13
-rw-r--r--Help/envvar/ISPC.rst13
-rw-r--r--Help/envvar/ISPCFLAGS.rst15
-rw-r--r--Help/envvar/LDFLAGS.rst12
-rw-r--r--Help/envvar/MACOSX_DEPLOYMENT_TARGET.rst10
-rw-r--r--Help/envvar/OBJC.rst16
-rw-r--r--Help/envvar/OBJCXX.rst16
-rw-r--r--Help/envvar/PackageName_ROOT.rst19
-rw-r--r--Help/envvar/RC.rst19
-rw-r--r--Help/envvar/RCFLAGS.rst13
-rw-r--r--Help/envvar/SWIFTC.rst21
-rw-r--r--Help/envvar/VERBOSE.rst12
-rw-r--r--Help/generator/Borland Makefiles.rst4
-rw-r--r--Help/generator/CodeBlocks.rst35
-rw-r--r--Help/generator/CodeLite.rst30
-rw-r--r--Help/generator/Eclipse CDT4.rst25
-rw-r--r--Help/generator/Green Hills MULTI.rst88
-rw-r--r--Help/generator/Kate.rst26
-rw-r--r--Help/generator/MSYS Makefiles.rst12
-rw-r--r--Help/generator/MinGW Makefiles.rst13
-rw-r--r--Help/generator/NMake Makefiles JOM.rst7
-rw-r--r--Help/generator/NMake Makefiles.rst4
-rw-r--r--Help/generator/Ninja Multi-Config.rst163
-rw-r--r--Help/generator/Ninja.rst67
-rw-r--r--Help/generator/Sublime Text 2.rst25
-rw-r--r--Help/generator/Unix Makefiles.rst31
-rw-r--r--Help/generator/VS_TOOLSET_HOST_ARCH.txt11
-rw-r--r--Help/generator/Visual Studio 10 2010.rst44
-rw-r--r--Help/generator/Visual Studio 11 2012.rst49
-rw-r--r--Help/generator/Visual Studio 12 2013.rst49
-rw-r--r--Help/generator/Visual Studio 14 2015.rst65
-rw-r--r--Help/generator/Visual Studio 15 2017.rst66
-rw-r--r--Help/generator/Visual Studio 16 2019.rst56
-rw-r--r--Help/generator/Visual Studio 6.rst6
-rw-r--r--Help/generator/Visual Studio 7 .NET 2003.rst6
-rw-r--r--Help/generator/Visual Studio 7.rst6
-rw-r--r--Help/generator/Visual Studio 8 2005.rst6
-rw-r--r--Help/generator/Visual Studio 9 2008.rst33
-rw-r--r--Help/generator/Watcom WMake.rst4
-rw-r--r--Help/generator/Xcode.rst46
-rw-r--r--Help/guide/ide-integration/index.rst126
-rw-r--r--Help/guide/importing-exporting/Downstream/CMakeLists.txt15
-rw-r--r--Help/guide/importing-exporting/Downstream/main.cc23
-rw-r--r--Help/guide/importing-exporting/DownstreamComponents/CMakeLists.txt18
-rw-r--r--Help/guide/importing-exporting/DownstreamComponents/main.cc28
-rw-r--r--Help/guide/importing-exporting/Importing/CMakeLists.txt19
-rw-r--r--Help/guide/importing-exporting/MathFunctions/CMakeLists.txt78
-rw-r--r--Help/guide/importing-exporting/MathFunctions/Config.cmake.in5
-rw-r--r--Help/guide/importing-exporting/MathFunctions/MathFunctions.cxx10
-rw-r--r--Help/guide/importing-exporting/MathFunctions/MathFunctions.h5
-rw-r--r--Help/guide/importing-exporting/MathFunctionsComponents/Addition/Addition.cxx8
-rw-r--r--Help/guide/importing-exporting/MathFunctionsComponents/Addition/Addition.h5
-rw-r--r--Help/guide/importing-exporting/MathFunctionsComponents/Addition/CMakeLists.txt30
-rw-r--r--Help/guide/importing-exporting/MathFunctionsComponents/CMakeLists.txt39
-rw-r--r--Help/guide/importing-exporting/MathFunctionsComponents/Config.cmake.in11
-rw-r--r--Help/guide/importing-exporting/MathFunctionsComponents/MathFunctions.cxx10
-rw-r--r--Help/guide/importing-exporting/MathFunctionsComponents/MathFunctions.h5
-rw-r--r--Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/CMakeLists.txt30
-rw-r--r--Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/SquareRoot.cxx10
-rw-r--r--Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/SquareRoot.h5
-rw-r--r--Help/guide/importing-exporting/MyExe/CMakeLists.txt12
-rw-r--r--Help/guide/importing-exporting/MyExe/main.cxx16
-rw-r--r--Help/guide/importing-exporting/index.rst772
-rw-r--r--Help/guide/tutorial/Complete/CMakeLists.txt124
-rw-r--r--Help/guide/tutorial/Complete/CTestConfig.cmake7
-rw-r--r--Help/guide/tutorial/Complete/Config.cmake.in4
-rw-r--r--Help/guide/tutorial/Complete/License.txt2
-rw-r--r--Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt67
-rw-r--r--Help/guide/tutorial/Complete/MathFunctions/MakeTable.cxx25
-rw-r--r--Help/guide/tutorial/Complete/MathFunctions/MathFunctions.cxx19
-rw-r--r--Help/guide/tutorial/Complete/MathFunctions/MathFunctions.h14
-rw-r--r--Help/guide/tutorial/Complete/MathFunctions/mysqrt.cxx37
-rw-r--r--Help/guide/tutorial/Complete/MathFunctions/mysqrt.h6
-rw-r--r--Help/guide/tutorial/Complete/MultiCPackConfig.cmake6
-rw-r--r--Help/guide/tutorial/Complete/TutorialConfig.h.in3
-rw-r--r--Help/guide/tutorial/Complete/tutorial.cxx26
-rw-r--r--Help/guide/tutorial/Step1/tutorial.cxx22
-rw-r--r--Help/guide/tutorial/Step10/CMakeLists.txt73
-rw-r--r--Help/guide/tutorial/Step10/CTestConfig.cmake7
-rw-r--r--Help/guide/tutorial/Step10/License.txt2
-rw-r--r--Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt55
-rw-r--r--Help/guide/tutorial/Step10/MathFunctions/MakeTable.cxx25
-rw-r--r--Help/guide/tutorial/Step10/MathFunctions/MathFunctions.cxx19
-rw-r--r--Help/guide/tutorial/Step10/MathFunctions/MathFunctions.h14
-rw-r--r--Help/guide/tutorial/Step10/MathFunctions/mysqrt.cxx37
-rw-r--r--Help/guide/tutorial/Step10/MathFunctions/mysqrt.h6
-rw-r--r--Help/guide/tutorial/Step10/TutorialConfig.h.in3
-rw-r--r--Help/guide/tutorial/Step10/tutorial.cxx27
-rw-r--r--Help/guide/tutorial/Step11/CMakeLists.txt81
-rw-r--r--Help/guide/tutorial/Step11/CTestConfig.cmake7
-rw-r--r--Help/guide/tutorial/Step11/License.txt2
-rw-r--r--Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt59
-rw-r--r--Help/guide/tutorial/Step11/MathFunctions/MakeTable.cxx25
-rw-r--r--Help/guide/tutorial/Step11/MathFunctions/MathFunctions.cxx19
-rw-r--r--Help/guide/tutorial/Step11/MathFunctions/MathFunctions.h14
-rw-r--r--Help/guide/tutorial/Step11/MathFunctions/mysqrt.cxx37
-rw-r--r--Help/guide/tutorial/Step11/MathFunctions/mysqrt.h6
-rw-r--r--Help/guide/tutorial/Step11/TutorialConfig.h.in3
-rw-r--r--Help/guide/tutorial/Step11/tutorial.cxx26
-rw-r--r--Help/guide/tutorial/Step12/CMakeLists.txt120
-rw-r--r--Help/guide/tutorial/Step12/CTestConfig.cmake7
-rw-r--r--Help/guide/tutorial/Step12/Config.cmake.in4
-rw-r--r--Help/guide/tutorial/Step12/License.txt2
-rw-r--r--Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt63
-rw-r--r--Help/guide/tutorial/Step12/MathFunctions/MakeTable.cxx25
-rw-r--r--Help/guide/tutorial/Step12/MathFunctions/MathFunctions.cxx19
-rw-r--r--Help/guide/tutorial/Step12/MathFunctions/MathFunctions.h14
-rw-r--r--Help/guide/tutorial/Step12/MathFunctions/mysqrt.cxx37
-rw-r--r--Help/guide/tutorial/Step12/MathFunctions/mysqrt.h6
-rw-r--r--Help/guide/tutorial/Step12/TutorialConfig.h.in3
-rw-r--r--Help/guide/tutorial/Step12/tutorial.cxx26
-rw-r--r--Help/guide/tutorial/Step2/CMakeLists.txt21
-rw-r--r--Help/guide/tutorial/Step2/MathFunctions/MathFunctions.h1
-rw-r--r--Help/guide/tutorial/Step2/MathFunctions/mysqrt.cxx22
-rw-r--r--Help/guide/tutorial/Step2/TutorialConfig.h.in3
-rw-r--r--Help/guide/tutorial/Step2/tutorial.cxx26
-rw-r--r--Help/guide/tutorial/Step3/CMakeLists.txt34
-rw-r--r--Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt1
-rw-r--r--Help/guide/tutorial/Step3/MathFunctions/MathFunctions.h1
-rw-r--r--Help/guide/tutorial/Step3/MathFunctions/mysqrt.cxx24
-rw-r--r--Help/guide/tutorial/Step3/TutorialConfig.h.in4
-rw-r--r--Help/guide/tutorial/Step3/tutorial.cxx36
-rw-r--r--Help/guide/tutorial/Step4/CMakeLists.txt32
-rw-r--r--Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt7
-rw-r--r--Help/guide/tutorial/Step4/MathFunctions/MathFunctions.h1
-rw-r--r--Help/guide/tutorial/Step4/MathFunctions/mysqrt.cxx24
-rw-r--r--Help/guide/tutorial/Step4/TutorialConfig.h.in4
-rw-r--r--Help/guide/tutorial/Step4/tutorial.cxx36
-rw-r--r--Help/guide/tutorial/Step5/CMakeLists.txt66
-rw-r--r--Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt11
-rw-r--r--Help/guide/tutorial/Step5/MathFunctions/MathFunctions.h1
-rw-r--r--Help/guide/tutorial/Step5/MathFunctions/mysqrt.cxx24
-rw-r--r--Help/guide/tutorial/Step5/TutorialConfig.h.in4
-rw-r--r--Help/guide/tutorial/Step5/tutorial.cxx36
-rw-r--r--Help/guide/tutorial/Step6/CMakeLists.txt66
-rw-r--r--Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt32
-rw-r--r--Help/guide/tutorial/Step6/MathFunctions/MakeTable.cxx25
-rw-r--r--Help/guide/tutorial/Step6/MathFunctions/MathFunctions.h1
-rw-r--r--Help/guide/tutorial/Step6/MathFunctions/mysqrt.cxx32
-rw-r--r--Help/guide/tutorial/Step6/TutorialConfig.h.in4
-rw-r--r--Help/guide/tutorial/Step6/tutorial.cxx36
-rw-r--r--Help/guide/tutorial/Step7/CMakeLists.txt66
-rw-r--r--Help/guide/tutorial/Step7/License.txt2
-rw-r--r--Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt29
-rw-r--r--Help/guide/tutorial/Step7/MathFunctions/MakeTable.cxx25
-rw-r--r--Help/guide/tutorial/Step7/MathFunctions/MathFunctions.h1
-rw-r--r--Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx33
-rw-r--r--Help/guide/tutorial/Step7/TutorialConfig.h.in4
-rw-r--r--Help/guide/tutorial/Step7/tutorial.cxx36
-rw-r--r--Help/guide/tutorial/Step8/CMakeLists.txt73
-rw-r--r--Help/guide/tutorial/Step8/License.txt2
-rw-r--r--Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt29
-rw-r--r--Help/guide/tutorial/Step8/MathFunctions/MakeTable.cxx25
-rw-r--r--Help/guide/tutorial/Step8/MathFunctions/MathFunctions.h1
-rw-r--r--Help/guide/tutorial/Step8/MathFunctions/mysqrt.cxx33
-rw-r--r--Help/guide/tutorial/Step8/TutorialConfig.h.in4
-rw-r--r--Help/guide/tutorial/Step8/tutorial.cxx36
-rw-r--r--Help/guide/tutorial/Step9/CMakeLists.txt72
-rw-r--r--Help/guide/tutorial/Step9/CTestConfig.cmake7
-rw-r--r--Help/guide/tutorial/Step9/License.txt2
-rw-r--r--Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt27
-rw-r--r--Help/guide/tutorial/Step9/MathFunctions/MakeTable.cxx25
-rw-r--r--Help/guide/tutorial/Step9/MathFunctions/MathFunctions.cxx19
-rw-r--r--Help/guide/tutorial/Step9/MathFunctions/MathFunctions.h1
-rw-r--r--Help/guide/tutorial/Step9/MathFunctions/mysqrt.cxx33
-rw-r--r--Help/guide/tutorial/Step9/MathFunctions/mysqrt.h6
-rw-r--r--Help/guide/tutorial/Step9/TutorialConfig.h.in4
-rw-r--r--Help/guide/tutorial/Step9/tutorial.cxx36
-rw-r--r--Help/guide/tutorial/index.rst946
-rw-r--r--Help/guide/user-interaction/GUI-Add-Entry.pngbin0 -> 33430 bytes-rw-r--r--Help/guide/user-interaction/GUI-Choose-Generator.pngbin0 -> 42066 bytes-rw-r--r--Help/guide/user-interaction/GUI-Configure-Dialog.pngbin0 -> 35250 bytes-rw-r--r--Help/guide/user-interaction/GUI-Source-Binary.pngbin0 -> 61975 bytes-rw-r--r--Help/guide/user-interaction/VS-Choose-Arch.pngbin0 -> 11130 bytes-rw-r--r--Help/guide/user-interaction/index.rst767
-rw-r--r--Help/guide/using-dependencies/index.rst200
-rw-r--r--Help/include/COMPILE_DEFINITIONS_DISCLAIMER.txt18
-rw-r--r--Help/include/INTERFACE_INCLUDE_DIRECTORIES_WARNING.txt18
-rw-r--r--Help/include/INTERFACE_LINK_LIBRARIES_WARNING.txt10
-rw-r--r--Help/index.rst107
-rw-r--r--Help/manual/ID_RESERVE.txt7
-rw-r--r--Help/manual/LINKS.txt17
-rw-r--r--Help/manual/OPTIONS_BUILD.txt130
-rw-r--r--Help/manual/OPTIONS_HELP.txt136
-rw-r--r--Help/manual/ccmake.1.rst37
-rw-r--r--Help/manual/cmake-buildsystem.7.rst1021
-rw-r--r--Help/manual/cmake-commands.7.rst174
-rw-r--r--Help/manual/cmake-compile-features.7.rst381
-rw-r--r--Help/manual/cmake-developer.7.rst501
-rw-r--r--Help/manual/cmake-env-variables.7.rst96
-rw-r--r--Help/manual/cmake-file-api.7.rst1506
-rw-r--r--Help/manual/cmake-generator-expressions.7.rst1061
-rw-r--r--Help/manual/cmake-generators.7.rst120
-rw-r--r--Help/manual/cmake-gui.1.rst52
-rw-r--r--Help/manual/cmake-language.7.rst629
-rw-r--r--Help/manual/cmake-modules.7.rst322
-rw-r--r--Help/manual/cmake-packages.7.rst719
-rw-r--r--Help/manual/cmake-policies.7.rst330
-rw-r--r--Help/manual/cmake-presets.7.rst998
-rw-r--r--Help/manual/cmake-properties.7.rst587
-rw-r--r--Help/manual/cmake-qt.7.rst262
-rw-r--r--Help/manual/cmake-server.7.rst7
-rw-r--r--Help/manual/cmake-toolchains.7.rst672
-rw-r--r--Help/manual/cmake-variables.7.rst706
-rw-r--r--Help/manual/cmake.1.rst857
-rw-r--r--Help/manual/cpack-generators.7.rst29
-rw-r--r--Help/manual/cpack.1.rst113
-rw-r--r--Help/manual/ctest.1.rst1668
-rw-r--r--Help/manual/presets/example.json70
-rw-r--r--Help/manual/presets/schema.json1235
-rw-r--r--Help/module/AddFileDependencies.rst1
-rw-r--r--Help/module/AndroidTestUtilities.rst1
-rw-r--r--Help/module/BundleUtilities.rst1
-rw-r--r--Help/module/CMakeAddFortranSubdirectory.rst1
-rw-r--r--Help/module/CMakeBackwardCompatibilityCXX.rst1
-rw-r--r--Help/module/CMakeDependentOption.rst1
-rw-r--r--Help/module/CMakeDetermineVSServicePack.rst1
-rw-r--r--Help/module/CMakeExpandImportedTargets.rst1
-rw-r--r--Help/module/CMakeFindDependencyMacro.rst1
-rw-r--r--Help/module/CMakeFindFrameworks.rst1
-rw-r--r--Help/module/CMakeFindPackageMode.rst1
-rw-r--r--Help/module/CMakeForceCompiler.rst1
-rw-r--r--Help/module/CMakeGraphVizOptions.rst1
-rw-r--r--Help/module/CMakePackageConfigHelpers.rst1
-rw-r--r--Help/module/CMakeParseArguments.rst1
-rw-r--r--Help/module/CMakePrintHelpers.rst1
-rw-r--r--Help/module/CMakePrintSystemInformation.rst1
-rw-r--r--Help/module/CMakePushCheckState.rst1
-rw-r--r--Help/module/CMakeVerifyManifest.rst1
-rw-r--r--Help/module/CPack.rst1
-rw-r--r--Help/module/CPackArchive.rst6
-rw-r--r--Help/module/CPackBundle.rst4
-rw-r--r--Help/module/CPackComponent.rst1
-rw-r--r--Help/module/CPackCygwin.rst4
-rw-r--r--Help/module/CPackDMG.rst4
-rw-r--r--Help/module/CPackDeb.rst4
-rw-r--r--Help/module/CPackFreeBSD.rst6
-rw-r--r--Help/module/CPackIFW.rst1
-rw-r--r--Help/module/CPackIFWConfigureFile.rst1
-rw-r--r--Help/module/CPackNSIS.rst4
-rw-r--r--Help/module/CPackNuGet.rst6
-rw-r--r--Help/module/CPackPackageMaker.rst4
-rw-r--r--Help/module/CPackProductBuild.rst6
-rw-r--r--Help/module/CPackRPM.rst4
-rw-r--r--Help/module/CPackWIX.rst5
-rw-r--r--Help/module/CSharpUtilities.rst1
-rw-r--r--Help/module/CTest.rst1
-rw-r--r--Help/module/CTestCoverageCollectGCOV.rst1
-rw-r--r--Help/module/CTestScriptMode.rst1
-rw-r--r--Help/module/CTestUseLaunchers.rst1
-rw-r--r--Help/module/CheckCCompilerFlag.rst1
-rw-r--r--Help/module/CheckCSourceCompiles.rst1
-rw-r--r--Help/module/CheckCSourceRuns.rst1
-rw-r--r--Help/module/CheckCXXCompilerFlag.rst1
-rw-r--r--Help/module/CheckCXXSourceCompiles.rst1
-rw-r--r--Help/module/CheckCXXSourceRuns.rst1
-rw-r--r--Help/module/CheckCXXSymbolExists.rst1
-rw-r--r--Help/module/CheckCompilerFlag.rst1
-rw-r--r--Help/module/CheckFortranCompilerFlag.rst1
-rw-r--r--Help/module/CheckFortranFunctionExists.rst1
-rw-r--r--Help/module/CheckFortranSourceCompiles.rst1
-rw-r--r--Help/module/CheckFortranSourceRuns.rst1
-rw-r--r--Help/module/CheckFunctionExists.rst1
-rw-r--r--Help/module/CheckIPOSupported.rst1
-rw-r--r--Help/module/CheckIncludeFile.rst1
-rw-r--r--Help/module/CheckIncludeFileCXX.rst1
-rw-r--r--Help/module/CheckIncludeFiles.rst1
-rw-r--r--Help/module/CheckLanguage.rst1
-rw-r--r--Help/module/CheckLibraryExists.rst1
-rw-r--r--Help/module/CheckLinkerFlag.rst1
-rw-r--r--Help/module/CheckOBJCCompilerFlag.rst1
-rw-r--r--Help/module/CheckOBJCSourceCompiles.rst1
-rw-r--r--Help/module/CheckOBJCSourceRuns.rst1
-rw-r--r--Help/module/CheckOBJCXXCompilerFlag.rst1
-rw-r--r--Help/module/CheckOBJCXXSourceCompiles.rst1
-rw-r--r--Help/module/CheckOBJCXXSourceRuns.rst1
-rw-r--r--Help/module/CheckPIESupported.rst1
-rw-r--r--Help/module/CheckPrototypeDefinition.rst1
-rw-r--r--Help/module/CheckSourceCompiles.rst1
-rw-r--r--Help/module/CheckSourceRuns.rst1
-rw-r--r--Help/module/CheckStructHasMember.rst1
-rw-r--r--Help/module/CheckSymbolExists.rst1
-rw-r--r--Help/module/CheckTypeSize.rst1
-rw-r--r--Help/module/CheckVariableExists.rst1
-rw-r--r--Help/module/Dart.rst1
-rw-r--r--Help/module/DeployQt4.rst1
-rw-r--r--Help/module/Documentation.rst1
-rw-r--r--Help/module/ExternalData.rst1
-rw-r--r--Help/module/ExternalProject.rst1
-rw-r--r--Help/module/FeatureSummary.rst1
-rw-r--r--Help/module/FetchContent.rst1
-rw-r--r--Help/module/FindALSA.rst1
-rw-r--r--Help/module/FindASPELL.rst1
-rw-r--r--Help/module/FindAVIFile.rst1
-rw-r--r--Help/module/FindArmadillo.rst1
-rw-r--r--Help/module/FindBISON.rst1
-rw-r--r--Help/module/FindBLAS.rst1
-rw-r--r--Help/module/FindBZip2.rst1
-rw-r--r--Help/module/FindBacktrace.rst1
-rw-r--r--Help/module/FindBoost.rst1
-rw-r--r--Help/module/FindBullet.rst1
-rw-r--r--Help/module/FindCABLE.rst1
-rw-r--r--Help/module/FindCUDA.rst1
-rw-r--r--Help/module/FindCUDAToolkit.rst1
-rw-r--r--Help/module/FindCURL.rst1
-rw-r--r--Help/module/FindCVS.rst1
-rw-r--r--Help/module/FindCoin3D.rst1
-rw-r--r--Help/module/FindCups.rst1
-rw-r--r--Help/module/FindCurses.rst1
-rw-r--r--Help/module/FindCxxTest.rst1
-rw-r--r--Help/module/FindCygwin.rst1
-rw-r--r--Help/module/FindDCMTK.rst1
-rw-r--r--Help/module/FindDart.rst1
-rw-r--r--Help/module/FindDevIL.rst1
-rw-r--r--Help/module/FindDoxygen.rst1
-rw-r--r--Help/module/FindEXPAT.rst1
-rw-r--r--Help/module/FindEnvModules.rst1
-rw-r--r--Help/module/FindFLEX.rst1
-rw-r--r--Help/module/FindFLTK.rst1
-rw-r--r--Help/module/FindFLTK2.rst1
-rw-r--r--Help/module/FindFontconfig.rst1
-rw-r--r--Help/module/FindFreetype.rst1
-rw-r--r--Help/module/FindGCCXML.rst1
-rw-r--r--Help/module/FindGDAL.rst1
-rw-r--r--Help/module/FindGIF.rst1
-rw-r--r--Help/module/FindGLEW.rst1
-rw-r--r--Help/module/FindGLUT.rst1
-rw-r--r--Help/module/FindGSL.rst1
-rw-r--r--Help/module/FindGTK.rst1
-rw-r--r--Help/module/FindGTK2.rst1
-rw-r--r--Help/module/FindGTest.rst1
-rw-r--r--Help/module/FindGettext.rst1
-rw-r--r--Help/module/FindGit.rst1
-rw-r--r--Help/module/FindGnuTLS.rst1
-rw-r--r--Help/module/FindGnuplot.rst1
-rw-r--r--Help/module/FindHDF5.rst1
-rw-r--r--Help/module/FindHSPELL.rst1
-rw-r--r--Help/module/FindHTMLHelp.rst1
-rw-r--r--Help/module/FindHg.rst1
-rw-r--r--Help/module/FindICU.rst1
-rw-r--r--Help/module/FindITK.rst10
-rw-r--r--Help/module/FindIce.rst1
-rw-r--r--Help/module/FindIconv.rst1
-rw-r--r--Help/module/FindIcotool.rst1
-rw-r--r--Help/module/FindImageMagick.rst1
-rw-r--r--Help/module/FindIntl.rst1
-rw-r--r--Help/module/FindJNI.rst1
-rw-r--r--Help/module/FindJPEG.rst1
-rw-r--r--Help/module/FindJasper.rst1
-rw-r--r--Help/module/FindJava.rst1
-rw-r--r--Help/module/FindKDE3.rst1
-rw-r--r--Help/module/FindKDE4.rst1
-rw-r--r--Help/module/FindLAPACK.rst1
-rw-r--r--Help/module/FindLATEX.rst1
-rw-r--r--Help/module/FindLTTngUST.rst1
-rw-r--r--Help/module/FindLibArchive.rst1
-rw-r--r--Help/module/FindLibLZMA.rst1
-rw-r--r--Help/module/FindLibXml2.rst1
-rw-r--r--Help/module/FindLibXslt.rst1
-rw-r--r--Help/module/FindLibinput.rst1
-rw-r--r--Help/module/FindLua.rst1
-rw-r--r--Help/module/FindLua50.rst1
-rw-r--r--Help/module/FindLua51.rst1
-rw-r--r--Help/module/FindMFC.rst1
-rw-r--r--Help/module/FindMPEG.rst1
-rw-r--r--Help/module/FindMPEG2.rst1
-rw-r--r--Help/module/FindMPI.rst1
-rw-r--r--Help/module/FindMatlab.rst1
-rw-r--r--Help/module/FindMotif.rst1
-rw-r--r--Help/module/FindODBC.rst1
-rw-r--r--Help/module/FindOpenACC.rst1
-rw-r--r--Help/module/FindOpenAL.rst1
-rw-r--r--Help/module/FindOpenCL.rst1
-rw-r--r--Help/module/FindOpenGL.rst1
-rw-r--r--Help/module/FindOpenMP.rst1
-rw-r--r--Help/module/FindOpenSSL.rst1
-rw-r--r--Help/module/FindOpenSceneGraph.rst1
-rw-r--r--Help/module/FindOpenThreads.rst1
-rw-r--r--Help/module/FindPHP4.rst1
-rw-r--r--Help/module/FindPNG.rst1
-rw-r--r--Help/module/FindPackageHandleStandardArgs.rst1
-rw-r--r--Help/module/FindPackageMessage.rst1
-rw-r--r--Help/module/FindPatch.rst1
-rw-r--r--Help/module/FindPerl.rst1
-rw-r--r--Help/module/FindPerlLibs.rst1
-rw-r--r--Help/module/FindPhysFS.rst1
-rw-r--r--Help/module/FindPike.rst1
-rw-r--r--Help/module/FindPkgConfig.rst1
-rw-r--r--Help/module/FindPostgreSQL.rst1
-rw-r--r--Help/module/FindProducer.rst1
-rw-r--r--Help/module/FindProtobuf.rst1
-rw-r--r--Help/module/FindPython.rst1
-rw-r--r--Help/module/FindPython2.rst1
-rw-r--r--Help/module/FindPython3.rst1
-rw-r--r--Help/module/FindPythonInterp.rst1
-rw-r--r--Help/module/FindPythonLibs.rst1
-rw-r--r--Help/module/FindQt.rst1
-rw-r--r--Help/module/FindQt3.rst1
-rw-r--r--Help/module/FindQt4.rst1
-rw-r--r--Help/module/FindQuickTime.rst1
-rw-r--r--Help/module/FindRTI.rst1
-rw-r--r--Help/module/FindRuby.rst1
-rw-r--r--Help/module/FindSDL.rst1
-rw-r--r--Help/module/FindSDL_image.rst1
-rw-r--r--Help/module/FindSDL_mixer.rst1
-rw-r--r--Help/module/FindSDL_net.rst1
-rw-r--r--Help/module/FindSDL_sound.rst1
-rw-r--r--Help/module/FindSDL_ttf.rst1
-rw-r--r--Help/module/FindSQLite3.rst1
-rw-r--r--Help/module/FindSWIG.rst1
-rw-r--r--Help/module/FindSelfPackers.rst1
-rw-r--r--Help/module/FindSquish.rst1
-rw-r--r--Help/module/FindSubversion.rst1
-rw-r--r--Help/module/FindTCL.rst1
-rw-r--r--Help/module/FindTIFF.rst1
-rw-r--r--Help/module/FindTclStub.rst1
-rw-r--r--Help/module/FindTclsh.rst1
-rw-r--r--Help/module/FindThreads.rst1
-rw-r--r--Help/module/FindUnixCommands.rst1
-rw-r--r--Help/module/FindVTK.rst10
-rw-r--r--Help/module/FindVulkan.rst1
-rw-r--r--Help/module/FindWget.rst1
-rw-r--r--Help/module/FindWish.rst1
-rw-r--r--Help/module/FindX11.rst1
-rw-r--r--Help/module/FindXCTest.rst1
-rw-r--r--Help/module/FindXMLRPC.rst1
-rw-r--r--Help/module/FindXalanC.rst1
-rw-r--r--Help/module/FindXercesC.rst1
-rw-r--r--Help/module/FindZLIB.rst1
-rw-r--r--Help/module/Findosg.rst1
-rw-r--r--Help/module/FindosgAnimation.rst1
-rw-r--r--Help/module/FindosgDB.rst1
-rw-r--r--Help/module/FindosgFX.rst1
-rw-r--r--Help/module/FindosgGA.rst1
-rw-r--r--Help/module/FindosgIntrospection.rst1
-rw-r--r--Help/module/FindosgManipulator.rst1
-rw-r--r--Help/module/FindosgParticle.rst1
-rw-r--r--Help/module/FindosgPresentation.rst1
-rw-r--r--Help/module/FindosgProducer.rst1
-rw-r--r--Help/module/FindosgQt.rst1
-rw-r--r--Help/module/FindosgShadow.rst1
-rw-r--r--Help/module/FindosgSim.rst1
-rw-r--r--Help/module/FindosgTerrain.rst1
-rw-r--r--Help/module/FindosgText.rst1
-rw-r--r--Help/module/FindosgUtil.rst1
-rw-r--r--Help/module/FindosgViewer.rst1
-rw-r--r--Help/module/FindosgVolume.rst1
-rw-r--r--Help/module/FindosgWidget.rst1
-rw-r--r--Help/module/Findosg_functions.rst1
-rw-r--r--Help/module/FindwxWidgets.rst1
-rw-r--r--Help/module/FindwxWindows.rst1
-rw-r--r--Help/module/FortranCInterface.rst1
-rw-r--r--Help/module/GNUInstallDirs.rst1
-rw-r--r--Help/module/GenerateExportHeader.rst1
-rw-r--r--Help/module/GetPrerequisites.rst1
-rw-r--r--Help/module/GoogleTest.rst1
-rw-r--r--Help/module/InstallRequiredSystemLibraries.rst1
-rw-r--r--Help/module/MacroAddFileDependencies.rst1
-rw-r--r--Help/module/ProcessorCount.rst1
-rw-r--r--Help/module/SelectLibraryConfigurations.rst1
-rw-r--r--Help/module/SquishTestScript.rst1
-rw-r--r--Help/module/TestBigEndian.rst1
-rw-r--r--Help/module/TestCXXAcceptsFlag.rst1
-rw-r--r--Help/module/TestForANSIForScope.rst1
-rw-r--r--Help/module/TestForANSIStreamHeaders.rst1
-rw-r--r--Help/module/TestForSSTREAM.rst1
-rw-r--r--Help/module/TestForSTDNamespace.rst1
-rw-r--r--Help/module/UseEcos.rst1
-rw-r--r--Help/module/UseJava.rst1
-rw-r--r--Help/module/UseJavaClassFilelist.rst6
-rw-r--r--Help/module/UseJavaSymlinks.rst6
-rw-r--r--Help/module/UsePkgConfig.rst1
-rw-r--r--Help/module/UseSWIG.rst1
-rw-r--r--Help/module/Use_wxWindows.rst1
-rw-r--r--Help/module/UsewxWidgets.rst1
-rw-r--r--Help/module/WriteBasicConfigVersionFile.rst1
-rw-r--r--Help/module/WriteCompilerDetectionHeader.rst1
-rw-r--r--Help/policy/CMP0000.rst34
-rw-r--r--Help/policy/CMP0001.rst21
-rw-r--r--Help/policy/CMP0002.rst28
-rw-r--r--Help/policy/CMP0003.rst104
-rw-r--r--Help/policy/CMP0004.rst26
-rw-r--r--Help/policy/CMP0005.rst26
-rw-r--r--Help/policy/CMP0006.rst24
-rw-r--r--Help/policy/CMP0007.rst17
-rw-r--r--Help/policy/CMP0008.rst35
-rw-r--r--Help/policy/CMP0009.rst21
-rw-r--r--Help/policy/CMP0010.rst20
-rw-r--r--Help/policy/CMP0011.rst25
-rw-r--r--Help/policy/CMP0012.rst28
-rw-r--r--Help/policy/CMP0013.rst21
-rw-r--r--Help/policy/CMP0014.rst17
-rw-r--r--Help/policy/CMP0015.rst19
-rw-r--r--Help/policy/CMP0016.rst16
-rw-r--r--Help/policy/CMP0017.rst21
-rw-r--r--Help/policy/CMP0018.rst35
-rw-r--r--Help/policy/CMP0019.rst22
-rw-r--r--Help/policy/CMP0020.rst27
-rw-r--r--Help/policy/CMP0021.rst21
-rw-r--r--Help/policy/CMP0022.rst39
-rw-r--r--Help/policy/CMP0023.rst35
-rw-r--r--Help/policy/CMP0024.rst25
-rw-r--r--Help/policy/CMP0025.rst29
-rw-r--r--Help/policy/CMP0026.rst29
-rw-r--r--Help/policy/CMP0027.rst27
-rw-r--r--Help/policy/CMP0028.rst25
-rw-r--r--Help/policy/CMP0029.rst12
-rw-r--r--Help/policy/CMP0030.rst13
-rw-r--r--Help/policy/CMP0031.rst15
-rw-r--r--Help/policy/CMP0032.rst15
-rw-r--r--Help/policy/CMP0033.rst16
-rw-r--r--Help/policy/CMP0034.rst13
-rw-r--r--Help/policy/CMP0035.rst12
-rw-r--r--Help/policy/CMP0036.rst14
-rw-r--r--Help/policy/CMP0037.rst34
-rw-r--r--Help/policy/CMP0038.rst18
-rw-r--r--Help/policy/CMP0039.rst19
-rw-r--r--Help/policy/CMP0040.rst21
-rw-r--r--Help/policy/CMP0041.rst27
-rw-r--r--Help/policy/CMP0042.rst21
-rw-r--r--Help/policy/CMP0043.rst47
-rw-r--r--Help/policy/CMP0044.rst21
-rw-r--r--Help/policy/CMP0045.rst19
-rw-r--r--Help/policy/CMP0046.rst19
-rw-r--r--Help/policy/CMP0047.rst30
-rw-r--r--Help/policy/CMP0048.rst24
-rw-r--r--Help/policy/CMP0049.rst25
-rw-r--r--Help/policy/CMP0050.rst20
-rw-r--r--Help/policy/CMP0051.rst28
-rw-r--r--Help/policy/CMP0052.rst29
-rw-r--r--Help/policy/CMP0053.rst52
-rw-r--r--Help/policy/CMP0054.rst54
-rw-r--r--Help/policy/CMP0055.rst21
-rw-r--r--Help/policy/CMP0056.rst36
-rw-r--r--Help/policy/CMP0057.rst18
-rw-r--r--Help/policy/CMP0058.rst112
-rw-r--r--Help/policy/CMP0059.rst21
-rw-r--r--Help/policy/CMP0060.rst67
-rw-r--r--Help/policy/CMP0061.rst28
-rw-r--r--Help/policy/CMP0062.rst31
-rw-r--r--Help/policy/CMP0063.rst30
-rw-r--r--Help/policy/CMP0064.rst19
-rw-r--r--Help/policy/CMP0065.rst29
-rw-r--r--Help/policy/CMP0066.rst29
-rw-r--r--Help/policy/CMP0067.rst39
-rw-r--r--Help/policy/CMP0068.rst37
-rw-r--r--Help/policy/CMP0069.rst94
-rw-r--r--Help/policy/CMP0070.rst27
-rw-r--r--Help/policy/CMP0071.rst44
-rw-r--r--Help/policy/CMP0072.rst28
-rw-r--r--Help/policy/CMP0073.rst27
-rw-r--r--Help/policy/CMP0074.rst25
-rw-r--r--Help/policy/CMP0075.rst28
-rw-r--r--Help/policy/CMP0076.rst28
-rw-r--r--Help/policy/CMP0077.rst54
-rw-r--r--Help/policy/CMP0078.rst26
-rw-r--r--Help/policy/CMP0079.rst42
-rw-r--r--Help/policy/CMP0080.rst27
-rw-r--r--Help/policy/CMP0081.rst24
-rw-r--r--Help/policy/CMP0082.rst28
-rw-r--r--Help/policy/CMP0083.rst71
-rw-r--r--Help/policy/CMP0084.rst28
-rw-r--r--Help/policy/CMP0085.rst23
-rw-r--r--Help/policy/CMP0086.rst22
-rw-r--r--Help/policy/CMP0087.rst31
-rw-r--r--Help/policy/CMP0088.rst31
-rw-r--r--Help/policy/CMP0089.rst32
-rw-r--r--Help/policy/CMP0090.rst29
-rw-r--r--Help/policy/CMP0091.rst51
-rw-r--r--Help/policy/CMP0092.rst40
-rw-r--r--Help/policy/CMP0093.rst26
-rw-r--r--Help/policy/CMP0094.rst24
-rw-r--r--Help/policy/CMP0095.rst32
-rw-r--r--Help/policy/CMP0096.rst27
-rw-r--r--Help/policy/CMP0097.rst25
-rw-r--r--Help/policy/CMP0098.rst32
-rw-r--r--Help/policy/CMP0099.rst26
-rw-r--r--Help/policy/CMP0100.rst42
-rw-r--r--Help/policy/CMP0101.rst22
-rw-r--r--Help/policy/CMP0102.rst27
-rw-r--r--Help/policy/CMP0103.rst24
-rw-r--r--Help/policy/CMP0104.rst58
-rw-r--r--Help/policy/CMP0105.rst21
-rw-r--r--Help/policy/CMP0106.rst21
-rw-r--r--Help/policy/CMP0107.rst21
-rw-r--r--Help/policy/CMP0108.rst21
-rw-r--r--Help/policy/CMP0109.rst24
-rw-r--r--Help/policy/CMP0110.rst26
-rw-r--r--Help/policy/CMP0111.rst27
-rw-r--r--Help/policy/CMP0112.rst40
-rw-r--r--Help/policy/CMP0113.rst43
-rw-r--r--Help/policy/CMP0114.rst85
-rw-r--r--Help/policy/CMP0115.rst34
-rw-r--r--Help/policy/CMP0116.rst41
-rw-r--r--Help/policy/CMP0117.rst43
-rw-r--r--Help/policy/CMP0118.rst25
-rw-r--r--Help/policy/CMP0119.rst36
-rw-r--r--Help/policy/CMP0120.rst47
-rw-r--r--Help/policy/CMP0121.rst21
-rw-r--r--Help/policy/CMP0122.rst17
-rw-r--r--Help/policy/DEPRECATED.txt4
-rw-r--r--Help/policy/DISALLOWED_COMMAND.txt9
-rw-r--r--Help/prop_cache/ADVANCED.rst8
-rw-r--r--Help/prop_cache/HELPSTRING.rst7
-rw-r--r--Help/prop_cache/MODIFIED.rst7
-rw-r--r--Help/prop_cache/STRINGS.rst9
-rw-r--r--Help/prop_cache/TYPE.rst21
-rw-r--r--Help/prop_cache/VALUE.rst7
-rw-r--r--Help/prop_dir/ADDITIONAL_CLEAN_FILES.rst23
-rw-r--r--Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst17
-rw-r--r--Help/prop_dir/BINARY_DIR.rst7
-rw-r--r--Help/prop_dir/BUILDSYSTEM_TARGETS.rst13
-rw-r--r--Help/prop_dir/CACHE_VARIABLES.rst7
-rw-r--r--Help/prop_dir/CLEAN_NO_CUSTOM.rst6
-rw-r--r--Help/prop_dir/CMAKE_CONFIGURE_DEPENDS.rst9
-rw-r--r--Help/prop_dir/COMPILE_DEFINITIONS.rst31
-rw-r--r--Help/prop_dir/COMPILE_DEFINITIONS_CONFIG.rst19
-rw-r--r--Help/prop_dir/COMPILE_OPTIONS.rst16
-rw-r--r--Help/prop_dir/DEFINITIONS.rst13
-rw-r--r--Help/prop_dir/EXCLUDE_FROM_ALL.rst13
-rw-r--r--Help/prop_dir/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst34
-rw-r--r--Help/prop_dir/INCLUDE_DIRECTORIES.rst32
-rw-r--r--Help/prop_dir/INCLUDE_REGULAR_EXPRESSION.rst9
-rw-r--r--Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION.rst7
-rw-r--r--Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst8
-rw-r--r--Help/prop_dir/LABELS.rst15
-rw-r--r--Help/prop_dir/LINK_DIRECTORIES.rst17
-rw-r--r--Help/prop_dir/LINK_OPTIONS.rst19
-rw-r--r--Help/prop_dir/LISTFILE_STACK.rst10
-rw-r--r--Help/prop_dir/MACROS.rst8
-rw-r--r--Help/prop_dir/PARENT_DIRECTORY.rst8
-rw-r--r--Help/prop_dir/RULE_LAUNCH_COMPILE.rst7
-rw-r--r--Help/prop_dir/RULE_LAUNCH_CUSTOM.rst7
-rw-r--r--Help/prop_dir/RULE_LAUNCH_LINK.rst7
-rw-r--r--Help/prop_dir/SOURCE_DIR.rst7
-rw-r--r--Help/prop_dir/SUBDIRECTORIES.rst17
-rw-r--r--Help/prop_dir/TESTS.rst10
-rw-r--r--Help/prop_dir/TEST_INCLUDE_FILE.rst9
-rw-r--r--Help/prop_dir/TEST_INCLUDE_FILES.rst9
-rw-r--r--Help/prop_dir/VARIABLES.rst7
-rw-r--r--Help/prop_dir/VS_GLOBAL_SECTION_POST_section.rst31
-rw-r--r--Help/prop_dir/VS_GLOBAL_SECTION_PRE_section.rst22
-rw-r--r--Help/prop_dir/VS_STARTUP_PROJECT.rst20
-rw-r--r--Help/prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS.rst21
-rw-r--r--Help/prop_gbl/AUTOGEN_SOURCE_GROUP.rst18
-rw-r--r--Help/prop_gbl/AUTOGEN_TARGETS_FOLDER.rst9
-rw-r--r--Help/prop_gbl/AUTOMOC_SOURCE_GROUP.rst9
-rw-r--r--Help/prop_gbl/AUTOMOC_TARGETS_FOLDER.rst11
-rw-r--r--Help/prop_gbl/AUTORCC_SOURCE_GROUP.rst9
-rw-r--r--Help/prop_gbl/AUTOUIC_SOURCE_GROUP.rst9
-rw-r--r--Help/prop_gbl/CMAKE_CUDA_KNOWN_FEATURES.rst35
-rw-r--r--Help/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.rst354
-rw-r--r--Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst43
-rw-r--r--Help/prop_gbl/CMAKE_ROLE.rst22
-rw-r--r--Help/prop_gbl/DEBUG_CONFIGURATIONS.rst13
-rw-r--r--Help/prop_gbl/DISABLED_FEATURES.rst11
-rw-r--r--Help/prop_gbl/ECLIPSE_EXTRA_CPROJECT_CONTENTS.rst14
-rw-r--r--Help/prop_gbl/ECLIPSE_EXTRA_NATURES.rst10
-rw-r--r--Help/prop_gbl/ENABLED_FEATURES.rst11
-rw-r--r--Help/prop_gbl/ENABLED_LANGUAGES.rst6
-rw-r--r--Help/prop_gbl/FIND_LIBRARY_USE_LIB32_PATHS.rst14
-rw-r--r--Help/prop_gbl/FIND_LIBRARY_USE_LIB64_PATHS.rst12
-rw-r--r--Help/prop_gbl/FIND_LIBRARY_USE_LIBX32_PATHS.rst14
-rw-r--r--Help/prop_gbl/FIND_LIBRARY_USE_OPENBSD_VERSIONING.rst10
-rw-r--r--Help/prop_gbl/GENERATOR_IS_MULTI_CONFIG.rst15
-rw-r--r--Help/prop_gbl/GLOBAL_DEPENDS_DEBUG_MODE.rst8
-rw-r--r--Help/prop_gbl/GLOBAL_DEPENDS_NO_CYCLES.rst10
-rw-r--r--Help/prop_gbl/IN_TRY_COMPILE.rst7
-rw-r--r--Help/prop_gbl/JOB_POOLS.rst31
-rw-r--r--Help/prop_gbl/PACKAGES_FOUND.rst7
-rw-r--r--Help/prop_gbl/PACKAGES_NOT_FOUND.rst7
-rw-r--r--Help/prop_gbl/PREDEFINED_TARGETS_FOLDER.rst9
-rw-r--r--Help/prop_gbl/REPORT_UNDEFINED_PROPERTIES.rst8
-rw-r--r--Help/prop_gbl/RULE_LAUNCH_COMPILE.rst11
-rw-r--r--Help/prop_gbl/RULE_LAUNCH_CUSTOM.rst11
-rw-r--r--Help/prop_gbl/RULE_LAUNCH_LINK.rst11
-rw-r--r--Help/prop_gbl/RULE_MESSAGES.rst13
-rw-r--r--Help/prop_gbl/TARGET_ARCHIVES_MAY_BE_SHARED_LIBS.rst7
-rw-r--r--Help/prop_gbl/TARGET_MESSAGES.rst22
-rw-r--r--Help/prop_gbl/TARGET_SUPPORTS_SHARED_LIBS.rst9
-rw-r--r--Help/prop_gbl/USE_FOLDERS.rst10
-rw-r--r--Help/prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME.rst27
-rw-r--r--Help/prop_inst/CPACK_DESKTOP_SHORTCUTS.rst9
-rw-r--r--Help/prop_inst/CPACK_NEVER_OVERWRITE.rst8
-rw-r--r--Help/prop_inst/CPACK_PERMANENT.rst8
-rw-r--r--Help/prop_inst/CPACK_STARTUP_SHORTCUTS.rst9
-rw-r--r--Help/prop_inst/CPACK_START_MENU_SHORTCUTS.rst9
-rw-r--r--Help/prop_inst/CPACK_WIX_ACL.rst23
-rw-r--r--Help/prop_sf/ABSTRACT.rst9
-rw-r--r--Help/prop_sf/AUTORCC_OPTIONS.rst22
-rw-r--r--Help/prop_sf/AUTOUIC_OPTIONS.rst23
-rw-r--r--Help/prop_sf/COMPILE_DEFINITIONS.rst29
-rw-r--r--Help/prop_sf/COMPILE_DEFINITIONS_CONFIG.rst10
-rw-r--r--Help/prop_sf/COMPILE_FLAGS.rst19
-rw-r--r--Help/prop_sf/COMPILE_OPTIONS.rst34
-rw-r--r--Help/prop_sf/EXTERNAL_OBJECT.rst8
-rw-r--r--Help/prop_sf/Fortran_FORMAT.rst12
-rw-r--r--Help/prop_sf/Fortran_PREPROCESS.rst19
-rw-r--r--Help/prop_sf/GENERATED.rst48
-rw-r--r--Help/prop_sf/HEADER_FILE_ONLY.rst24
-rw-r--r--Help/prop_sf/INCLUDE_DIRECTORIES.rst20
-rw-r--r--Help/prop_sf/KEEP_EXTENSION.rst9
-rw-r--r--Help/prop_sf/LABELS.rst8
-rw-r--r--Help/prop_sf/LANGUAGE.rst17
-rw-r--r--Help/prop_sf/LOCATION.rst7
-rw-r--r--Help/prop_sf/MACOSX_PACKAGE_LOCATION.rst30
-rw-r--r--Help/prop_sf/OBJECT_DEPENDS.rst21
-rw-r--r--Help/prop_sf/OBJECT_OUTPUTS.rst12
-rw-r--r--Help/prop_sf/SKIP_AUTOGEN.rst19
-rw-r--r--Help/prop_sf/SKIP_AUTOMOC.rst17
-rw-r--r--Help/prop_sf/SKIP_AUTORCC.rst17
-rw-r--r--Help/prop_sf/SKIP_AUTOUIC.rst22
-rw-r--r--Help/prop_sf/SKIP_PRECOMPILE_HEADERS.rst15
-rw-r--r--Help/prop_sf/SKIP_UNITY_BUILD_INCLUSION.rst13
-rw-r--r--Help/prop_sf/SYMBOLIC.rst8
-rw-r--r--Help/prop_sf/Swift_DEPENDENCIES_FILE.rst7
-rw-r--r--Help/prop_sf/Swift_DIAGNOSTICS_FILE.rst6
-rw-r--r--Help/prop_sf/UNITY_GROUP.rst7
-rw-r--r--Help/prop_sf/VS_COPY_TO_OUT_DIR.rst8
-rw-r--r--Help/prop_sf/VS_CSHARP_tagname.rst22
-rw-r--r--Help/prop_sf/VS_DEPLOYMENT_CONTENT.rst14
-rw-r--r--Help/prop_sf/VS_DEPLOYMENT_LOCATION.rst11
-rw-r--r--Help/prop_sf/VS_INCLUDE_IN_VSIX.rst8
-rw-r--r--Help/prop_sf/VS_RESOURCE_GENERATOR.rst10
-rw-r--r--Help/prop_sf/VS_SETTINGS.rst20
-rw-r--r--Help/prop_sf/VS_SHADER_DISABLE_OPTIMIZATIONS.rst8
-rw-r--r--Help/prop_sf/VS_SHADER_ENABLE_DEBUG.rst8
-rw-r--r--Help/prop_sf/VS_SHADER_ENTRYPOINT.rst7
-rw-r--r--Help/prop_sf/VS_SHADER_FLAGS.rst6
-rw-r--r--Help/prop_sf/VS_SHADER_MODEL.rst7
-rw-r--r--Help/prop_sf/VS_SHADER_OBJECT_FILE_NAME.rst8
-rw-r--r--Help/prop_sf/VS_SHADER_OUTPUT_HEADER_FILE.rst7
-rw-r--r--Help/prop_sf/VS_SHADER_TYPE.rst6
-rw-r--r--Help/prop_sf/VS_SHADER_VARIABLE_NAME.rst7
-rw-r--r--Help/prop_sf/VS_TOOL_OVERRIDE.rst7
-rw-r--r--Help/prop_sf/VS_XAML_TYPE.rst9
-rw-r--r--Help/prop_sf/WRAP_EXCLUDE.rst11
-rw-r--r--Help/prop_sf/XCODE_EXPLICIT_FILE_TYPE.rst10
-rw-r--r--Help/prop_sf/XCODE_FILE_ATTRIBUTES.rst13
-rw-r--r--Help/prop_sf/XCODE_LAST_KNOWN_FILE_TYPE.rst11
-rw-r--r--Help/prop_test/ATTACHED_FILES.rst7
-rw-r--r--Help/prop_test/ATTACHED_FILES_ON_FAIL.rst7
-rw-r--r--Help/prop_test/COST.rst14
-rw-r--r--Help/prop_test/DEPENDS.rst22
-rw-r--r--Help/prop_test/DISABLED.rst17
-rw-r--r--Help/prop_test/ENVIRONMENT.rst9
-rw-r--r--Help/prop_test/FAIL_REGULAR_EXPRESSION.rst15
-rw-r--r--Help/prop_test/FIXTURES_CLEANUP.rst49
-rw-r--r--Help/prop_test/FIXTURES_REQUIRED.rst98
-rw-r--r--Help/prop_test/FIXTURES_SETUP.rst50
-rw-r--r--Help/prop_test/LABELS.rst6
-rw-r--r--Help/prop_test/MEASUREMENT.rst8
-rw-r--r--Help/prop_test/PASS_REGULAR_EXPRESSION.rst16
-rw-r--r--Help/prop_test/PROCESSORS.rst16
-rw-r--r--Help/prop_test/PROCESSOR_AFFINITY.rst13
-rw-r--r--Help/prop_test/REQUIRED_FILES.rst38
-rw-r--r--Help/prop_test/RESOURCE_GROUPS.rst72
-rw-r--r--Help/prop_test/RESOURCE_LOCK.rst18
-rw-r--r--Help/prop_test/RUN_SERIAL.rst8
-rw-r--r--Help/prop_test/SKIP_REGULAR_EXPRESSION.rst19
-rw-r--r--Help/prop_test/SKIP_RETURN_CODE.rst12
-rw-r--r--Help/prop_test/TIMEOUT.rst9
-rw-r--r--Help/prop_test/TIMEOUT_AFTER_MATCH.rst41
-rw-r--r--Help/prop_test/WILL_FAIL.rst7
-rw-r--r--Help/prop_test/WORKING_DIRECTORY.rst9
-rw-r--r--Help/prop_tgt/ADDITIONAL_CLEAN_FILES.rst25
-rw-r--r--Help/prop_tgt/AIX_EXPORT_ALL_SYMBOLS.rst14
-rw-r--r--Help/prop_tgt/ALIASED_TARGET.rst7
-rw-r--r--Help/prop_tgt/ALIAS_GLOBAL.rst19
-rw-r--r--Help/prop_tgt/ANDROID_ANT_ADDITIONAL_OPTIONS.rst10
-rw-r--r--Help/prop_tgt/ANDROID_API.rst10
-rw-r--r--Help/prop_tgt/ANDROID_API_MIN.rst9
-rw-r--r--Help/prop_tgt/ANDROID_ARCH.rst20
-rw-r--r--Help/prop_tgt/ANDROID_ASSETS_DIRECTORIES.rst11
-rw-r--r--Help/prop_tgt/ANDROID_GUI.rst17
-rw-r--r--Help/prop_tgt/ANDROID_JAR_DEPENDENCIES.rst9
-rw-r--r--Help/prop_tgt/ANDROID_JAR_DIRECTORIES.rst16
-rw-r--r--Help/prop_tgt/ANDROID_JAVA_SOURCE_DIR.rst10
-rw-r--r--Help/prop_tgt/ANDROID_NATIVE_LIB_DEPENDENCIES.rst16
-rw-r--r--Help/prop_tgt/ANDROID_NATIVE_LIB_DIRECTORIES.rst18
-rw-r--r--Help/prop_tgt/ANDROID_PROCESS_MAX.rst10
-rw-r--r--Help/prop_tgt/ANDROID_PROGUARD.rst11
-rw-r--r--Help/prop_tgt/ANDROID_PROGUARD_CONFIG_PATH.rst11
-rw-r--r--Help/prop_tgt/ANDROID_SECURE_PROPS_PATH.rst10
-rw-r--r--Help/prop_tgt/ANDROID_SKIP_ANT_STEP.rst8
-rw-r--r--Help/prop_tgt/ANDROID_STL_TYPE.rst29
-rw-r--r--Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.rst9
-rw-r--r--Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY_CONFIG.rst16
-rw-r--r--Help/prop_tgt/ARCHIVE_OUTPUT_NAME.rst8
-rw-r--r--Help/prop_tgt/ARCHIVE_OUTPUT_NAME_CONFIG.rst8
-rw-r--r--Help/prop_tgt/AUTOGEN_BUILD_DIR.rst19
-rw-r--r--Help/prop_tgt/AUTOGEN_ORIGIN_DEPENDS.rst40
-rw-r--r--Help/prop_tgt/AUTOGEN_PARALLEL.rst23
-rw-r--r--Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst36
-rw-r--r--Help/prop_tgt/AUTOMOC.rst248
-rw-r--r--Help/prop_tgt/AUTOMOC_COMPILER_PREDEFINES.rst26
-rw-r--r--Help/prop_tgt/AUTOMOC_DEPEND_FILTERS.rst109
-rw-r--r--Help/prop_tgt/AUTOMOC_EXECUTABLE.rst17
-rw-r--r--Help/prop_tgt/AUTOMOC_MACRO_NAMES.rst34
-rw-r--r--Help/prop_tgt/AUTOMOC_MOC_OPTIONS.rst17
-rw-r--r--Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst33
-rw-r--r--Help/prop_tgt/AUTORCC.rst62
-rw-r--r--Help/prop_tgt/AUTORCC_EXECUTABLE.rst17
-rw-r--r--Help/prop_tgt/AUTORCC_OPTIONS.rst28
-rw-r--r--Help/prop_tgt/AUTOUIC.rst85
-rw-r--r--Help/prop_tgt/AUTOUIC_EXECUTABLE.rst17
-rw-r--r--Help/prop_tgt/AUTOUIC_OPTIONS.rst32
-rw-r--r--Help/prop_tgt/AUTOUIC_SEARCH_PATHS.rst14
-rw-r--r--Help/prop_tgt/BINARY_DIR.rst8
-rw-r--r--Help/prop_tgt/BUILD_RPATH.rst15
-rw-r--r--Help/prop_tgt/BUILD_RPATH_USE_ORIGIN.rst26
-rw-r--r--Help/prop_tgt/BUILD_WITH_INSTALL_NAME_DIR.rst15
-rw-r--r--Help/prop_tgt/BUILD_WITH_INSTALL_RPATH.rst15
-rw-r--r--Help/prop_tgt/BUNDLE.rst9
-rw-r--r--Help/prop_tgt/BUNDLE_EXTENSION.rst8
-rw-r--r--Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst24
-rw-r--r--Help/prop_tgt/COMPATIBLE_INTERFACE_BOOL.rst20
-rw-r--r--Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MAX.rst18
-rw-r--r--Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MIN.rst18
-rw-r--r--Help/prop_tgt/COMPATIBLE_INTERFACE_STRING.rst16
-rw-r--r--Help/prop_tgt/COMPILE_DEFINITIONS.rst25
-rw-r--r--Help/prop_tgt/COMPILE_DEFINITIONS_CONFIG.rst16
-rw-r--r--Help/prop_tgt/COMPILE_FEATURES.rst15
-rw-r--r--Help/prop_tgt/COMPILE_FLAGS.rst11
-rw-r--r--Help/prop_tgt/COMPILE_OPTIONS.rst17
-rw-r--r--Help/prop_tgt/COMPILE_PDB_NAME.rst13
-rw-r--r--Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst12
-rw-r--r--Help/prop_tgt/COMPILE_PDB_NOTE.txt5
-rw-r--r--Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY.rst15
-rw-r--r--Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst18
-rw-r--r--Help/prop_tgt/CONFIG_OUTPUT_NAME.rst8
-rw-r--r--Help/prop_tgt/CONFIG_POSTFIX.rst13
-rw-r--r--Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst17
-rw-r--r--Help/prop_tgt/CUDA_ARCHITECTURES.rst42
-rw-r--r--Help/prop_tgt/CUDA_EXTENSIONS.rst19
-rw-r--r--Help/prop_tgt/CUDA_PTX_COMPILATION.rst14
-rw-r--r--Help/prop_tgt/CUDA_RESOLVE_DEVICE_SYMBOLS.rst27
-rw-r--r--Help/prop_tgt/CUDA_RUNTIME_LIBRARY-VALUES.txt9
-rw-r--r--Help/prop_tgt/CUDA_RUNTIME_LIBRARY.rst23
-rw-r--r--Help/prop_tgt/CUDA_SEPARABLE_COMPILATION.rst19
-rw-r--r--Help/prop_tgt/CUDA_STANDARD.rst34
-rw-r--r--Help/prop_tgt/CUDA_STANDARD_REQUIRED.rst20
-rw-r--r--Help/prop_tgt/CXX_EXTENSIONS.rst19
-rw-r--r--Help/prop_tgt/CXX_STANDARD.rst36
-rw-r--r--Help/prop_tgt/CXX_STANDARD_REQUIRED.rst20
-rw-r--r--Help/prop_tgt/C_EXTENSIONS.rst19
-rw-r--r--Help/prop_tgt/C_STANDARD.rst36
-rw-r--r--Help/prop_tgt/C_STANDARD_REQUIRED.rst20
-rw-r--r--Help/prop_tgt/DEBUG_POSTFIX.rst7
-rw-r--r--Help/prop_tgt/DEFINE_SYMBOL.rst11
-rw-r--r--Help/prop_tgt/DEPLOYMENT_ADDITIONAL_FILES.rst20
-rw-r--r--Help/prop_tgt/DEPLOYMENT_REMOTE_DIRECTORY.rst20
-rw-r--r--Help/prop_tgt/DEPRECATION.rst9
-rw-r--r--Help/prop_tgt/DISABLE_PRECOMPILE_HEADERS.rst10
-rw-r--r--Help/prop_tgt/DOTNET_TARGET_FRAMEWORK.rst15
-rw-r--r--Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst17
-rw-r--r--Help/prop_tgt/ENABLE_EXPORTS.rst31
-rw-r--r--Help/prop_tgt/EXCLUDE_FROM_ALL.rst28
-rw-r--r--Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD.rst8
-rw-r--r--Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG.rst10
-rw-r--r--Help/prop_tgt/EXPORT_COMPILE_COMMANDS.rst9
-rw-r--r--Help/prop_tgt/EXPORT_NAME.rst8
-rw-r--r--Help/prop_tgt/EXPORT_PROPERTIES.rst24
-rw-r--r--Help/prop_tgt/EchoString.rst7
-rw-r--r--Help/prop_tgt/FOLDER.rst13
-rw-r--r--Help/prop_tgt/FRAMEWORK.rst37
-rw-r--r--Help/prop_tgt/FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst28
-rw-r--r--Help/prop_tgt/FRAMEWORK_VERSION.rst10
-rw-r--r--Help/prop_tgt/Fortran_FORMAT.rst11
-rw-r--r--Help/prop_tgt/Fortran_MODULE_DIRECTORY.rst25
-rw-r--r--Help/prop_tgt/Fortran_PREPROCESS.rst25
-rw-r--r--Help/prop_tgt/GENERATOR_FILE_NAME.rst9
-rw-r--r--Help/prop_tgt/GHS_INTEGRITY_APP.rst12
-rw-r--r--Help/prop_tgt/GHS_NO_SOURCE_GROUP_FILE.rst15
-rw-r--r--Help/prop_tgt/GNUtoMS.rst17
-rw-r--r--Help/prop_tgt/HAS_CXX.rst7
-rw-r--r--Help/prop_tgt/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst32
-rw-r--r--Help/prop_tgt/IMPORTED.rst8
-rw-r--r--Help/prop_tgt/IMPORTED_COMMON_LANGUAGE_RUNTIME.rst10
-rw-r--r--Help/prop_tgt/IMPORTED_CONFIGURATIONS.rst11
-rw-r--r--Help/prop_tgt/IMPORTED_GLOBAL.rst32
-rw-r--r--Help/prop_tgt/IMPORTED_IMPLIB.rst9
-rw-r--r--Help/prop_tgt/IMPORTED_IMPLIB_CONFIG.rst7
-rw-r--r--Help/prop_tgt/IMPORTED_LIBNAME.rst25
-rw-r--r--Help/prop_tgt/IMPORTED_LIBNAME_CONFIG.rst9
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES.rst14
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG.rst8
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES.rst14
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG.rst8
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES.rst16
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES_CONFIG.rst13
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY.rst6
-rw-r--r--Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY_CONFIG.rst7
-rw-r--r--Help/prop_tgt/IMPORTED_LOCATION.rst31
-rw-r--r--Help/prop_tgt/IMPORTED_LOCATION_CONFIG.rst7
-rw-r--r--Help/prop_tgt/IMPORTED_NO_SONAME.rst9
-rw-r--r--Help/prop_tgt/IMPORTED_NO_SONAME_CONFIG.rst7
-rw-r--r--Help/prop_tgt/IMPORTED_OBJECTS.rst93
-rw-r--r--Help/prop_tgt/IMPORTED_OBJECTS_CONFIG.rst20
-rw-r--r--Help/prop_tgt/IMPORTED_SONAME.rst8
-rw-r--r--Help/prop_tgt/IMPORTED_SONAME_CONFIG.rst7
-rw-r--r--Help/prop_tgt/IMPORT_PREFIX.rst9
-rw-r--r--Help/prop_tgt/IMPORT_SUFFIX.rst9
-rw-r--r--Help/prop_tgt/INCLUDE_DIRECTORIES.rst24
-rw-r--r--Help/prop_tgt/INSTALL_NAME_DIR.rst18
-rw-r--r--Help/prop_tgt/INSTALL_REMOVE_ENVIRONMENT_RPATH.rst18
-rw-r--r--Help/prop_tgt/INSTALL_RPATH.rst16
-rw-r--r--Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst14
-rw-r--r--Help/prop_tgt/INTERFACE_AUTOUIC_OPTIONS.rst14
-rw-r--r--Help/prop_tgt/INTERFACE_BUILD_PROPERTY.txt16
-rw-r--r--Help/prop_tgt/INTERFACE_COMPILE_DEFINITIONS.rst9
-rw-r--r--Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst14
-rw-r--r--Help/prop_tgt/INTERFACE_COMPILE_OPTIONS.rst9
-rw-r--r--Help/prop_tgt/INTERFACE_INCLUDE_DIRECTORIES.rst29
-rw-r--r--Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst34
-rw-r--r--Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst11
-rw-r--r--Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst26
-rw-r--r--Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst11
-rw-r--r--Help/prop_tgt/INTERFACE_POSITION_INDEPENDENT_CODE.rst22
-rw-r--r--Help/prop_tgt/INTERFACE_PRECOMPILE_HEADERS.rst18
-rw-r--r--Help/prop_tgt/INTERFACE_SOURCES.rst20
-rw-r--r--Help/prop_tgt/INTERFACE_SYSTEM_INCLUDE_DIRECTORIES.rst28
-rw-r--r--Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst13
-rw-r--r--Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst12
-rw-r--r--Help/prop_tgt/IOS_INSTALL_COMBINED.rst19
-rw-r--r--Help/prop_tgt/ISPC_HEADER_DIRECTORY.rst13
-rw-r--r--Help/prop_tgt/ISPC_HEADER_SUFFIX.rst14
-rw-r--r--Help/prop_tgt/ISPC_INSTRUCTION_SETS.rst21
-rw-r--r--Help/prop_tgt/JOB_POOL_COMPILE.rst17
-rw-r--r--Help/prop_tgt/JOB_POOL_LINK.rst16
-rw-r--r--Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst23
-rw-r--r--Help/prop_tgt/LABELS.rst6
-rw-r--r--Help/prop_tgt/LANG_CLANG_TIDY.rst15
-rw-r--r--Help/prop_tgt/LANG_COMPILER_LAUNCHER.rst16
-rw-r--r--Help/prop_tgt/LANG_CPPCHECK.rst17
-rw-r--r--Help/prop_tgt/LANG_CPPLINT.rst15
-rw-r--r--Help/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE.rst15
-rw-r--r--Help/prop_tgt/LANG_VISIBILITY_PRESET.rst13
-rw-r--r--Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY.rst9
-rw-r--r--Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst17
-rw-r--r--Help/prop_tgt/LIBRARY_OUTPUT_NAME.rst8
-rw-r--r--Help/prop_tgt/LIBRARY_OUTPUT_NAME_CONFIG.rst8
-rw-r--r--Help/prop_tgt/LINKER_LANGUAGE.rst14
-rw-r--r--Help/prop_tgt/LINK_DEPENDS.rst18
-rw-r--r--Help/prop_tgt/LINK_DEPENDS_NO_SHARED.rst14
-rw-r--r--Help/prop_tgt/LINK_DIRECTORIES.rst20
-rw-r--r--Help/prop_tgt/LINK_FLAGS.rst16
-rw-r--r--Help/prop_tgt/LINK_FLAGS_CONFIG.rst11
-rw-r--r--Help/prop_tgt/LINK_INTERFACE_LIBRARIES.rst31
-rw-r--r--Help/prop_tgt/LINK_INTERFACE_LIBRARIES_CONFIG.rst20
-rw-r--r--Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY.rst12
-rw-r--r--Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG.rst8
-rw-r--r--Help/prop_tgt/LINK_LIBRARIES.rst19
-rw-r--r--Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt10
-rw-r--r--Help/prop_tgt/LINK_OPTIONS.rst30
-rw-r--r--Help/prop_tgt/LINK_SEARCH_END_STATIC.rst19
-rw-r--r--Help/prop_tgt/LINK_SEARCH_START_STATIC.rst20
-rw-r--r--Help/prop_tgt/LINK_WHAT_YOU_USE.rst17
-rw-r--r--Help/prop_tgt/LOCATION.rst28
-rw-r--r--Help/prop_tgt/LOCATION_CONFIG.rst20
-rw-r--r--Help/prop_tgt/MACHO_COMPATIBILITY_VERSION.rst27
-rw-r--r--Help/prop_tgt/MACHO_CURRENT_VERSION.rst27
-rw-r--r--Help/prop_tgt/MACOSX_BUNDLE.rst12
-rw-r--r--Help/prop_tgt/MACOSX_BUNDLE_INFO_PLIST.rst35
-rw-r--r--Help/prop_tgt/MACOSX_FRAMEWORK_INFO_PLIST.rst27
-rw-r--r--Help/prop_tgt/MACOSX_RPATH.rst23
-rw-r--r--Help/prop_tgt/MANUALLY_ADDED_DEPENDENCIES.rst10
-rw-r--r--Help/prop_tgt/MAP_IMPORTED_CONFIG_CONFIG.rst70
-rw-r--r--Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt20
-rw-r--r--Help/prop_tgt/MSVC_RUNTIME_LIBRARY.rst31
-rw-r--r--Help/prop_tgt/NAME.rst6
-rw-r--r--Help/prop_tgt/NO_SONAME.rst14
-rw-r--r--Help/prop_tgt/NO_SYSTEM_FROM_IMPORTED.rst15
-rw-r--r--Help/prop_tgt/OBJCXX_EXTENSIONS.rst22
-rw-r--r--Help/prop_tgt/OBJCXX_STANDARD.rst37
-rw-r--r--Help/prop_tgt/OBJCXX_STANDARD_REQUIRED.rst22
-rw-r--r--Help/prop_tgt/OBJC_EXTENSIONS.rst22
-rw-r--r--Help/prop_tgt/OBJC_STANDARD.rst37
-rw-r--r--Help/prop_tgt/OBJC_STANDARD_REQUIRED.rst22
-rw-r--r--Help/prop_tgt/OPTIMIZE_DEPENDENCIES.rst43
-rw-r--r--Help/prop_tgt/OSX_ARCHITECTURES.rst11
-rw-r--r--Help/prop_tgt/OSX_ARCHITECTURES_CONFIG.rst7
-rw-r--r--Help/prop_tgt/OUTPUT_NAME.rst22
-rw-r--r--Help/prop_tgt/OUTPUT_NAME_CONFIG.rst7
-rw-r--r--Help/prop_tgt/PCH_INSTANTIATE_TEMPLATES.rst13
-rw-r--r--Help/prop_tgt/PCH_WARN_INVALID.rst12
-rw-r--r--Help/prop_tgt/PDB_NAME.rst12
-rw-r--r--Help/prop_tgt/PDB_NAME_CONFIG.rst10
-rw-r--r--Help/prop_tgt/PDB_NOTE.txt9
-rw-r--r--Help/prop_tgt/PDB_OUTPUT_DIRECTORY.rst19
-rw-r--r--Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst19
-rw-r--r--Help/prop_tgt/POSITION_INDEPENDENT_CODE.rst16
-rw-r--r--Help/prop_tgt/POST_INSTALL_SCRIPT.rst9
-rw-r--r--Help/prop_tgt/PRECOMPILE_HEADERS.rst14
-rw-r--r--Help/prop_tgt/PRECOMPILE_HEADERS_REUSE_FROM.rst9
-rw-r--r--Help/prop_tgt/PREFIX.rst7
-rw-r--r--Help/prop_tgt/PRE_INSTALL_SCRIPT.rst9
-rw-r--r--Help/prop_tgt/PRIVATE_HEADER.rst11
-rw-r--r--Help/prop_tgt/PROJECT_LABEL.rst7
-rw-r--r--Help/prop_tgt/PUBLIC_HEADER.rst11
-rw-r--r--Help/prop_tgt/RESOURCE.rst58
-rw-r--r--Help/prop_tgt/RULE_LAUNCH_COMPILE.rst7
-rw-r--r--Help/prop_tgt/RULE_LAUNCH_CUSTOM.rst7
-rw-r--r--Help/prop_tgt/RULE_LAUNCH_LINK.rst7
-rw-r--r--Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.rst9
-rw-r--r--Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst17
-rw-r--r--Help/prop_tgt/RUNTIME_OUTPUT_NAME.rst8
-rw-r--r--Help/prop_tgt/RUNTIME_OUTPUT_NAME_CONFIG.rst8
-rw-r--r--Help/prop_tgt/SKIP_BUILD_RPATH.rst9
-rw-r--r--Help/prop_tgt/SOURCES.rst6
-rw-r--r--Help/prop_tgt/SOURCE_DIR.rst8
-rw-r--r--Help/prop_tgt/SOVERSION.rst37
-rw-r--r--Help/prop_tgt/STATIC_LIBRARY_FLAGS.rst17
-rw-r--r--Help/prop_tgt/STATIC_LIBRARY_FLAGS_CONFIG.rst12
-rw-r--r--Help/prop_tgt/STATIC_LIBRARY_OPTIONS.rst22
-rw-r--r--Help/prop_tgt/SUFFIX.rst7
-rw-r--r--Help/prop_tgt/Swift_DEPENDENCIES_FILE.rst7
-rw-r--r--Help/prop_tgt/Swift_LANGUAGE_VERSION.rst8
-rw-r--r--Help/prop_tgt/Swift_MODULE_DIRECTORY.rst12
-rw-r--r--Help/prop_tgt/Swift_MODULE_NAME.rst7
-rw-r--r--Help/prop_tgt/TYPE.rst9
-rw-r--r--Help/prop_tgt/UNITY_BUILD.rst87
-rw-r--r--Help/prop_tgt/UNITY_BUILD_BATCH_SIZE.rst25
-rw-r--r--Help/prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE.rst21
-rw-r--r--Help/prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE.rst21
-rw-r--r--Help/prop_tgt/UNITY_BUILD_MODE.rst60
-rw-r--r--Help/prop_tgt/UNITY_BUILD_UNIQUE_ID.rst55
-rw-r--r--Help/prop_tgt/VERSION.rst39
-rw-r--r--Help/prop_tgt/VISIBILITY_INLINES_HIDDEN.rst13
-rw-r--r--Help/prop_tgt/VS_CONFIGURATION_TYPE.rst14
-rw-r--r--Help/prop_tgt/VS_DEBUGGER_COMMAND.rst13
-rw-r--r--Help/prop_tgt/VS_DEBUGGER_COMMAND_ARGUMENTS.rst13
-rw-r--r--Help/prop_tgt/VS_DEBUGGER_ENVIRONMENT.rst13
-rw-r--r--Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst13
-rw-r--r--Help/prop_tgt/VS_DESKTOP_EXTENSIONS_VERSION.rst12
-rw-r--r--Help/prop_tgt/VS_DOTNET_DOCUMENTATION_FILE.rst8
-rw-r--r--Help/prop_tgt/VS_DOTNET_REFERENCEPROP_refname_TAG_tagname.rst16
-rw-r--r--Help/prop_tgt/VS_DOTNET_REFERENCES.rst7
-rw-r--r--Help/prop_tgt/VS_DOTNET_REFERENCES_COPY_LOCAL.rst9
-rw-r--r--Help/prop_tgt/VS_DOTNET_REFERENCE_refname.rst14
-rw-r--r--Help/prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION.rst11
-rw-r--r--Help/prop_tgt/VS_DPI_AWARE.rst16
-rw-r--r--Help/prop_tgt/VS_GLOBAL_KEYWORD.rst12
-rw-r--r--Help/prop_tgt/VS_GLOBAL_PROJECT_TYPES.rst15
-rw-r--r--Help/prop_tgt/VS_GLOBAL_ROOTNAMESPACE.rst7
-rw-r--r--Help/prop_tgt/VS_GLOBAL_variable.rst10
-rw-r--r--Help/prop_tgt/VS_IOT_EXTENSIONS_VERSION.rst12
-rw-r--r--Help/prop_tgt/VS_IOT_STARTUP_TASK.rst8
-rw-r--r--Help/prop_tgt/VS_JUST_MY_CODE_DEBUGGING.rst12
-rw-r--r--Help/prop_tgt/VS_KEYWORD.rst10
-rw-r--r--Help/prop_tgt/VS_MOBILE_EXTENSIONS_VERSION.rst12
-rw-r--r--Help/prop_tgt/VS_NO_SOLUTION_DEPLOY.rst48
-rw-r--r--Help/prop_tgt/VS_PACKAGE_REFERENCES.rst15
-rw-r--r--Help/prop_tgt/VS_PLATFORM_TOOLSET.rst12
-rw-r--r--Help/prop_tgt/VS_PROJECT_IMPORT.rst10
-rw-r--r--Help/prop_tgt/VS_SCC_AUXPATH.rst7
-rw-r--r--Help/prop_tgt/VS_SCC_LOCALPATH.rst7
-rw-r--r--Help/prop_tgt/VS_SCC_PROJECTNAME.rst7
-rw-r--r--Help/prop_tgt/VS_SCC_PROVIDER.rst7
-rw-r--r--Help/prop_tgt/VS_SDK_REFERENCES.rst9
-rw-r--r--Help/prop_tgt/VS_SOLUTION_DEPLOY.rst29
-rw-r--r--Help/prop_tgt/VS_SOURCE_SETTINGS_tool.rst21
-rw-r--r--Help/prop_tgt/VS_USER_PROPS.rst14
-rw-r--r--Help/prop_tgt/VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION.rst12
-rw-r--r--Help/prop_tgt/VS_WINRT_COMPONENT.rst13
-rw-r--r--Help/prop_tgt/VS_WINRT_EXTENSIONS.rst5
-rw-r--r--Help/prop_tgt/VS_WINRT_REFERENCES.rst7
-rw-r--r--Help/prop_tgt/WIN32_EXECUTABLE.rst17
-rw-r--r--Help/prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS.rst28
-rw-r--r--Help/prop_tgt/XCODE_ATTRIBUTE_an-attribute.rst22
-rw-r--r--Help/prop_tgt/XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY.rst8
-rw-r--r--Help/prop_tgt/XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY.rst8
-rw-r--r--Help/prop_tgt/XCODE_EMBED_type.rst14
-rw-r--r--Help/prop_tgt/XCODE_EMBED_type_PATH.rst9
-rw-r--r--Help/prop_tgt/XCODE_EXPLICIT_FILE_TYPE.rst10
-rw-r--r--Help/prop_tgt/XCODE_GENERATE_SCHEME.rst43
-rw-r--r--Help/prop_tgt/XCODE_LINK_BUILD_PHASE_MODE.rst55
-rw-r--r--Help/prop_tgt/XCODE_PRODUCT_TYPE.rst10
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER.rst14
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst14
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_ARGUMENTS.rst12
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_DEBUG_AS_ROOT.rst9
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING.rst15
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst14
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst14
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst14
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_ENVIRONMENT.rst14
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_EXECUTABLE.rst11
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_GUARD_MALLOC.rst14
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst15
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES.rst14
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE.rst14
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_MALLOC_STACK.rst14
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER.rst14
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP.rst14
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst14
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst15
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_WORKING_DIRECTORY.rst15
-rw-r--r--Help/prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS.rst14
-rw-r--r--Help/prop_tgt/XCTEST.rst15
-rw-r--r--Help/prop_tgt/XXX_OUTPUT_DIRECTORY.txt12
-rw-r--r--Help/prop_tgt/XXX_OUTPUT_NAME.txt5
-rw-r--r--Help/release/3.0.rst473
-rw-r--r--Help/release/3.1.rst425
-rw-r--r--Help/release/3.10.rst282
-rw-r--r--Help/release/3.11.rst307
-rw-r--r--Help/release/3.12.rst305
-rw-r--r--Help/release/3.13.rst289
-rw-r--r--Help/release/3.14.rst438
-rw-r--r--Help/release/3.15.rst396
-rw-r--r--Help/release/3.16.rst324
-rw-r--r--Help/release/3.17.rst357
-rw-r--r--Help/release/3.18.rst364
-rw-r--r--Help/release/3.19.rst442
-rw-r--r--Help/release/3.2.rst277
-rw-r--r--Help/release/3.20.rst349
-rw-r--r--Help/release/3.3.rst287
-rw-r--r--Help/release/3.4.rst273
-rw-r--r--Help/release/3.5.rst187
-rw-r--r--Help/release/3.6.rst318
-rw-r--r--Help/release/3.7.rst319
-rw-r--r--Help/release/3.8.rst417
-rw-r--r--Help/release/3.9.rst343
-rw-r--r--Help/release/dev.txt16
-rw-r--r--Help/release/dev/0-sample-topic.rst7
-rw-r--r--Help/release/dev/FindDevIL-imported-targets.rst4
-rw-r--r--Help/release/dev/FindIconv-version.rst4
-rw-r--r--Help/release/dev/FindIntl-version.rst4
-rw-r--r--Help/release/dev/UseSWIG-csharp.rst5
-rw-r--r--Help/release/dev/add_custom_command-DEPFILE-genex.rst5
-rw-r--r--Help/release/dev/c-std.rst6
-rw-r--r--Help/release/dev/cmake-install-prefix-command.rst8
-rw-r--r--Help/release/dev/cmake-presets-condition.rst4
-rw-r--r--Help/release/dev/cmake-presets-host-system-name.rst5
-rw-r--r--Help/release/dev/cmake-presets-optional-generator-and-binarydir.rst5
-rw-r--r--Help/release/dev/cmake-system-name-version.rst10
-rw-r--r--Help/release/dev/cpack-dmg-filesystem.rst5
-rw-r--r--Help/release/dev/cpack-nsis-executable-name.rst6
-rw-r--r--Help/release/dev/cxx-module-extensions.rst4
-rw-r--r--Help/release/dev/file-COPY_FILE.rst4
-rw-r--r--Help/release/dev/file-RENAME.rst6
-rw-r--r--Help/release/dev/fileapi-codemodel-directory.rst10
-rw-r--r--Help/release/dev/fujitsu-compiler-support.rst11
-rw-r--r--Help/release/dev/ifw-default-version-operator.rst7
-rw-r--r--Help/release/dev/list-index-arg-parsing.rst7
-rw-r--r--Help/release/dev/project-is-top-level.rst6
-rw-r--r--Help/release/dev/runtime-dll-deps.rst4
-rw-r--r--Help/release/index.rst38
-rw-r--r--Help/variable/ANDROID.rst7
-rw-r--r--Help/variable/APPLE.rst5
-rw-r--r--Help/variable/BORLAND.rst6
-rw-r--r--Help/variable/BUILD_SHARED_LIBS.rst10
-rw-r--r--Help/variable/CACHE.rst20
-rw-r--r--Help/variable/CMAKE_ABSOLUTE_DESTINATION_FILES.rst9
-rw-r--r--Help/variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS.rst8
-rw-r--r--Help/variable/CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_API.rst13
-rw-r--r--Help/variable/CMAKE_ANDROID_API_MIN.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_ARCH.rst21
-rw-r--r--Help/variable/CMAKE_ANDROID_ARCH_ABI.rst19
-rw-r--r--Help/variable/CMAKE_ANDROID_ARM_MODE.rst9
-rw-r--r--Help/variable/CMAKE_ANDROID_ARM_NEON.rst8
-rw-r--r--Help/variable/CMAKE_ANDROID_ASSETS_DIRECTORIES.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_EXCEPTIONS.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_GUI.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_JAR_DEPENDENCIES.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_JAR_DIRECTORIES.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_JAVA_SOURCE_DIR.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_NDK.rst9
-rw-r--r--Help/variable/CMAKE_ANDROID_NDK_DEPRECATED_HEADERS.rst11
-rw-r--r--Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG.rst8
-rw-r--r--Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst22
-rw-r--r--Help/variable/CMAKE_ANDROID_NDK_VERSION.rst8
-rw-r--r--Help/variable/CMAKE_ANDROID_PROCESS_MAX.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_PROGUARD.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_PROGUARD_CONFIG_PATH.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_RTTI.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_SECURE_PROPS_PATH.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_SKIP_ANT_STEP.rst7
-rw-r--r--Help/variable/CMAKE_ANDROID_STANDALONE_TOOLCHAIN.rst8
-rw-r--r--Help/variable/CMAKE_ANDROID_STL_TYPE.rst39
-rw-r--r--Help/variable/CMAKE_APPBUNDLE_PATH.rst6
-rw-r--r--Help/variable/CMAKE_APPLE_SILICON_PROCESSOR.rst14
-rw-r--r--Help/variable/CMAKE_AR.rst7
-rw-r--r--Help/variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY.rst9
-rw-r--r--Help/variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY_CONFIG.rst11
-rw-r--r--Help/variable/CMAKE_ARGC.rst8
-rw-r--r--Help/variable/CMAKE_ARGV0.rst9
-rw-r--r--Help/variable/CMAKE_AUTOGEN_ORIGIN_DEPENDS.rst13
-rw-r--r--Help/variable/CMAKE_AUTOGEN_PARALLEL.rst12
-rw-r--r--Help/variable/CMAKE_AUTOGEN_VERBOSE.rst15
-rw-r--r--Help/variable/CMAKE_AUTOMOC.rst7
-rw-r--r--Help/variable/CMAKE_AUTOMOC_COMPILER_PREDEFINES.rst10
-rw-r--r--Help/variable/CMAKE_AUTOMOC_DEPEND_FILTERS.rst14
-rw-r--r--Help/variable/CMAKE_AUTOMOC_MACRO_NAMES.rst22
-rw-r--r--Help/variable/CMAKE_AUTOMOC_MOC_OPTIONS.rst7
-rw-r--r--Help/variable/CMAKE_AUTOMOC_PATH_PREFIX.rst13
-rw-r--r--Help/variable/CMAKE_AUTOMOC_RELAXED_MODE.rst15
-rw-r--r--Help/variable/CMAKE_AUTORCC.rst7
-rw-r--r--Help/variable/CMAKE_AUTORCC_OPTIONS.rst16
-rw-r--r--Help/variable/CMAKE_AUTOUIC.rst7
-rw-r--r--Help/variable/CMAKE_AUTOUIC_OPTIONS.rst16
-rw-r--r--Help/variable/CMAKE_AUTOUIC_SEARCH_PATHS.rst13
-rw-r--r--Help/variable/CMAKE_BACKWARDS_COMPATIBILITY.rst4
-rw-r--r--Help/variable/CMAKE_BINARY_DIR.rst13
-rw-r--r--Help/variable/CMAKE_BUILD_RPATH.rst12
-rw-r--r--Help/variable/CMAKE_BUILD_RPATH_USE_ORIGIN.rst9
-rw-r--r--Help/variable/CMAKE_BUILD_TOOL.rst6
-rw-r--r--Help/variable/CMAKE_BUILD_TYPE.rst25
-rw-r--r--Help/variable/CMAKE_BUILD_WITH_INSTALL_NAME_DIR.rst9
-rw-r--r--Help/variable/CMAKE_BUILD_WITH_INSTALL_RPATH.rst11
-rw-r--r--Help/variable/CMAKE_CACHEFILE_DIR.rst7
-rw-r--r--Help/variable/CMAKE_CACHE_MAJOR_VERSION.rst8
-rw-r--r--Help/variable/CMAKE_CACHE_MINOR_VERSION.rst8
-rw-r--r--Help/variable/CMAKE_CACHE_PATCH_VERSION.rst8
-rw-r--r--Help/variable/CMAKE_CFG_INTDIR.rst52
-rw-r--r--Help/variable/CMAKE_CLANG_VFS_OVERLAY.rst9
-rw-r--r--Help/variable/CMAKE_CL_64.rst7
-rw-r--r--Help/variable/CMAKE_CODEBLOCKS_COMPILER_ID.rst15
-rw-r--r--Help/variable/CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES.rst9
-rw-r--r--Help/variable/CMAKE_CODELITE_USE_TARGETS.rst10
-rw-r--r--Help/variable/CMAKE_COLOR_MAKEFILE.rst7
-rw-r--r--Help/variable/CMAKE_COMMAND.rst8
-rw-r--r--Help/variable/CMAKE_COMPILER_2005.rst6
-rw-r--r--Help/variable/CMAKE_COMPILER_IS_GNUCC.rst7
-rw-r--r--Help/variable/CMAKE_COMPILER_IS_GNUCXX.rst7
-rw-r--r--Help/variable/CMAKE_COMPILER_IS_GNUG77.rst7
-rw-r--r--Help/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY.rst10
-rw-r--r--Help/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst13
-rw-r--r--Help/variable/CMAKE_CONFIGURATION_TYPES.rst10
-rw-r--r--Help/variable/CMAKE_CONFIG_POSTFIX.rst7
-rw-r--r--Help/variable/CMAKE_CPACK_COMMAND.rst10
-rw-r--r--Help/variable/CMAKE_CROSSCOMPILING.rst27
-rw-r--r--Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst18
-rw-r--r--Help/variable/CMAKE_CROSS_CONFIGS.rst17
-rw-r--r--Help/variable/CMAKE_CTEST_ARGUMENTS.rst8
-rw-r--r--Help/variable/CMAKE_CTEST_COMMAND.rst8
-rw-r--r--Help/variable/CMAKE_CUDA_ARCHITECTURES.rst35
-rw-r--r--Help/variable/CMAKE_CUDA_COMPILE_FEATURES.rst13
-rw-r--r--Help/variable/CMAKE_CUDA_EXTENSIONS.rst13
-rw-r--r--Help/variable/CMAKE_CUDA_HOST_COMPILER.rst25
-rw-r--r--Help/variable/CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS.rst8
-rw-r--r--Help/variable/CMAKE_CUDA_RUNTIME_LIBRARY.rst27
-rw-r--r--Help/variable/CMAKE_CUDA_SEPARABLE_COMPILATION.rst8
-rw-r--r--Help/variable/CMAKE_CUDA_STANDARD.rst13
-rw-r--r--Help/variable/CMAKE_CUDA_STANDARD_REQUIRED.rst13
-rw-r--r--Help/variable/CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES.rst9
-rw-r--r--Help/variable/CMAKE_CURRENT_BINARY_DIR.rst15
-rw-r--r--Help/variable/CMAKE_CURRENT_FUNCTION.rst12
-rw-r--r--Help/variable/CMAKE_CURRENT_FUNCTION_LIST_DIR.rst43
-rw-r--r--Help/variable/CMAKE_CURRENT_FUNCTION_LIST_FILE.rst11
-rw-r--r--Help/variable/CMAKE_CURRENT_FUNCTION_LIST_LINE.rst12
-rw-r--r--Help/variable/CMAKE_CURRENT_LIST_DIR.rst17
-rw-r--r--Help/variable/CMAKE_CURRENT_LIST_FILE.rst15
-rw-r--r--Help/variable/CMAKE_CURRENT_LIST_LINE.rst11
-rw-r--r--Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst12
-rw-r--r--Help/variable/CMAKE_CXX_COMPILE_FEATURES.rst13
-rw-r--r--Help/variable/CMAKE_CXX_EXTENSIONS.rst13
-rw-r--r--Help/variable/CMAKE_CXX_STANDARD.rst13
-rw-r--r--Help/variable/CMAKE_CXX_STANDARD_REQUIRED.rst13
-rw-r--r--Help/variable/CMAKE_C_COMPILE_FEATURES.rst13
-rw-r--r--Help/variable/CMAKE_C_EXTENSIONS.rst13
-rw-r--r--Help/variable/CMAKE_C_STANDARD.rst13
-rw-r--r--Help/variable/CMAKE_C_STANDARD_REQUIRED.rst13
-rw-r--r--Help/variable/CMAKE_DEBUG_POSTFIX.rst7
-rw-r--r--Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst23
-rw-r--r--Help/variable/CMAKE_DEFAULT_BUILD_TYPE.rst14
-rw-r--r--Help/variable/CMAKE_DEFAULT_CONFIGS.rst21
-rw-r--r--Help/variable/CMAKE_DEPENDS_IN_PROJECT_ONLY.rst12
-rw-r--r--Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst9
-rw-r--r--Help/variable/CMAKE_DIRECTORY_LABELS.rst8
-rw-r--r--Help/variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName.rst16
-rw-r--r--Help/variable/CMAKE_DISABLE_PRECOMPILE_HEADERS.rst8
-rw-r--r--Help/variable/CMAKE_DL_LIBS.rst7
-rw-r--r--Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK.rst18
-rw-r--r--Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION.rst22
-rw-r--r--Help/variable/CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES.rst12
-rw-r--r--Help/variable/CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT.rst13
-rw-r--r--Help/variable/CMAKE_ECLIPSE_MAKE_ARGUMENTS.rst11
-rw-r--r--Help/variable/CMAKE_ECLIPSE_RESOURCE_ENCODING.rst8
-rw-r--r--Help/variable/CMAKE_ECLIPSE_VERSION.rst12
-rw-r--r--Help/variable/CMAKE_EDIT_COMMAND.rst8
-rw-r--r--Help/variable/CMAKE_ENABLE_EXPORTS.rst10
-rw-r--r--Help/variable/CMAKE_ERROR_DEPRECATED.rst7
-rw-r--r--Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst10
-rw-r--r--Help/variable/CMAKE_EXECUTABLE_SUFFIX.rst9
-rw-r--r--Help/variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO.rst8
-rw-r--r--Help/variable/CMAKE_EXE_LINKER_FLAGS.rst6
-rw-r--r--Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst7
-rw-r--r--Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG_INIT.rst12
-rw-r--r--Help/variable/CMAKE_EXE_LINKER_FLAGS_INIT.rst13
-rw-r--r--Help/variable/CMAKE_EXPORT_COMPILE_COMMANDS.rst40
-rw-r--r--Help/variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY.rst18
-rw-r--r--Help/variable/CMAKE_EXPORT_PACKAGE_REGISTRY.rst17
-rw-r--r--Help/variable/CMAKE_EXTRA_GENERATOR.rst10
-rw-r--r--Help/variable/CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES.rst9
-rw-r--r--Help/variable/CMAKE_FIND_APPBUNDLE.rst24
-rw-r--r--Help/variable/CMAKE_FIND_DEBUG_MODE.rst25
-rw-r--r--Help/variable/CMAKE_FIND_FRAMEWORK.rst24
-rw-r--r--Help/variable/CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX.rst14
-rw-r--r--Help/variable/CMAKE_FIND_LIBRARY_PREFIXES.rst9
-rw-r--r--Help/variable/CMAKE_FIND_LIBRARY_SUFFIXES.rst9
-rw-r--r--Help/variable/CMAKE_FIND_NO_INSTALL_PREFIX.rst19
-rw-r--r--Help/variable/CMAKE_FIND_PACKAGE_NAME.rst8
-rw-r--r--Help/variable/CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY.rst26
-rw-r--r--Help/variable/CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY.rst26
-rw-r--r--Help/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.rst29
-rw-r--r--Help/variable/CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS.rst12
-rw-r--r--Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst18
-rw-r--r--Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst38
-rw-r--r--Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst22
-rw-r--r--Help/variable/CMAKE_FIND_ROOT_PATH.rst8
-rw-r--r--Help/variable/CMAKE_FIND_ROOT_PATH_MODE_INCLUDE.rst6
-rw-r--r--Help/variable/CMAKE_FIND_ROOT_PATH_MODE_LIBRARY.rst6
-rw-r--r--Help/variable/CMAKE_FIND_ROOT_PATH_MODE_PACKAGE.rst6
-rw-r--r--Help/variable/CMAKE_FIND_ROOT_PATH_MODE_PROGRAM.rst6
-rw-r--r--Help/variable/CMAKE_FIND_ROOT_PATH_MODE_XXX.txt8
-rw-r--r--Help/variable/CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH.rst26
-rw-r--r--Help/variable/CMAKE_FIND_USE_CMAKE_PATH.rst26
-rw-r--r--Help/variable/CMAKE_FIND_USE_CMAKE_SYSTEM_PATH.rst26
-rw-r--r--Help/variable/CMAKE_FIND_USE_PACKAGE_REGISTRY.rst32
-rw-r--r--Help/variable/CMAKE_FIND_USE_PACKAGE_ROOT_PATH.rst24
-rw-r--r--Help/variable/CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH.rst26
-rw-r--r--Help/variable/CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY.rst33
-rw-r--r--Help/variable/CMAKE_FOLDER.rst9
-rw-r--r--Help/variable/CMAKE_FRAMEWORK.rst9
-rw-r--r--Help/variable/CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst10
-rw-r--r--Help/variable/CMAKE_FRAMEWORK_PATH.rst7
-rw-r--r--Help/variable/CMAKE_Fortran_FORMAT.rst7
-rw-r--r--Help/variable/CMAKE_Fortran_MODDIR_DEFAULT.rst8
-rw-r--r--Help/variable/CMAKE_Fortran_MODDIR_FLAG.rst7
-rw-r--r--Help/variable/CMAKE_Fortran_MODOUT_FLAG.rst7
-rw-r--r--Help/variable/CMAKE_Fortran_MODULE_DIRECTORY.rst8
-rw-r--r--Help/variable/CMAKE_Fortran_PREPROCESS.rst10
-rw-r--r--Help/variable/CMAKE_GENERATOR.rst12
-rw-r--r--Help/variable/CMAKE_GENERATOR_INSTANCE.rst27
-rw-r--r--Help/variable/CMAKE_GENERATOR_PLATFORM.rst33
-rw-r--r--Help/variable/CMAKE_GENERATOR_TOOLSET.rst89
-rw-r--r--Help/variable/CMAKE_GHS_NO_SOURCE_GROUP_FILE.rst8
-rw-r--r--Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst28
-rw-r--r--Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET_NAME.rst15
-rw-r--r--Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET.rst20
-rw-r--r--Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET_NAME.rst15
-rw-r--r--Help/variable/CMAKE_GNUtoMS.rst8
-rw-r--r--Help/variable/CMAKE_HOME_DIRECTORY.rst9
-rw-r--r--Help/variable/CMAKE_HOST_APPLE.rst6
-rw-r--r--Help/variable/CMAKE_HOST_SOLARIS.rst8
-rw-r--r--Help/variable/CMAKE_HOST_SYSTEM.rst10
-rw-r--r--Help/variable/CMAKE_HOST_SYSTEM_NAME.rst8
-rw-r--r--Help/variable/CMAKE_HOST_SYSTEM_PROCESSOR.rst42
-rw-r--r--Help/variable/CMAKE_HOST_SYSTEM_VERSION.rst8
-rw-r--r--Help/variable/CMAKE_HOST_UNIX.rst7
-rw-r--r--Help/variable/CMAKE_HOST_WIN32.rst6
-rw-r--r--Help/variable/CMAKE_IGNORE_PATH.rst18
-rw-r--r--Help/variable/CMAKE_IMPORT_LIBRARY_PREFIX.rst9
-rw-r--r--Help/variable/CMAKE_IMPORT_LIBRARY_SUFFIX.rst9
-rw-r--r--Help/variable/CMAKE_INCLUDE_CURRENT_DIR.rst13
-rw-r--r--Help/variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE.rst12
-rw-r--r--Help/variable/CMAKE_INCLUDE_DIRECTORIES_BEFORE.rst9
-rw-r--r--Help/variable/CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE.rst8
-rw-r--r--Help/variable/CMAKE_INCLUDE_PATH.rst7
-rw-r--r--Help/variable/CMAKE_INSTALL_DEFAULT_COMPONENT_NAME.rst9
-rw-r--r--Help/variable/CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS.rst31
-rw-r--r--Help/variable/CMAKE_INSTALL_MESSAGE.rst32
-rw-r--r--Help/variable/CMAKE_INSTALL_NAME_DIR.rst8
-rw-r--r--Help/variable/CMAKE_INSTALL_PREFIX.rst23
-rw-r--r--Help/variable/CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT.rst16
-rw-r--r--Help/variable/CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH.rst11
-rw-r--r--Help/variable/CMAKE_INSTALL_RPATH.rst8
-rw-r--r--Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst13
-rw-r--r--Help/variable/CMAKE_INTERNAL_PLATFORM_ABI.rst6
-rw-r--r--Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION.rst10
-rw-r--r--Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst10
-rw-r--r--Help/variable/CMAKE_IOS_INSTALL_COMBINED.rst10
-rw-r--r--Help/variable/CMAKE_ISPC_HEADER_DIRECTORY.rst10
-rw-r--r--Help/variable/CMAKE_ISPC_HEADER_SUFFIX.rst10
-rw-r--r--Help/variable/CMAKE_ISPC_INSTRUCTION_SETS.rst9
-rw-r--r--Help/variable/CMAKE_JOB_POOLS.rst8
-rw-r--r--Help/variable/CMAKE_JOB_POOL_COMPILE.rst6
-rw-r--r--Help/variable/CMAKE_JOB_POOL_LINK.rst6
-rw-r--r--Help/variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER.rst8
-rw-r--r--Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_MACHINE.rst11
-rw-r--r--Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX.rst14
-rw-r--r--Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX.rst10
-rw-r--r--Help/variable/CMAKE_LANG_ARCHIVE_APPEND.rst10
-rw-r--r--Help/variable/CMAKE_LANG_ARCHIVE_CREATE.rst10
-rw-r--r--Help/variable/CMAKE_LANG_ARCHIVE_FINISH.rst10
-rw-r--r--Help/variable/CMAKE_LANG_BYTE_ORDER.rst20
-rw-r--r--Help/variable/CMAKE_LANG_CLANG_TIDY.rst15
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER.rst32
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_ABI.rst6
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_AR.rst9
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_ARCHITECTURE_ID.rst10
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN.rst13
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_ID.rst45
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_LAUNCHER.rst12
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_LOADED.rst7
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_PREDEFINES_COMMAND.rst10
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_RANLIB.rst9
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_TARGET.rst11
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_VERSION.rst12
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_VERSION_INTERNAL.rst10
-rw-r--r--Help/variable/CMAKE_LANG_COMPILE_OBJECT.rst7
-rw-r--r--Help/variable/CMAKE_LANG_CPPCHECK.rst8
-rw-r--r--Help/variable/CMAKE_LANG_CPPLINT.rst8
-rw-r--r--Help/variable/CMAKE_LANG_CREATE_SHARED_LIBRARY.rst8
-rw-r--r--Help/variable/CMAKE_LANG_CREATE_SHARED_MODULE.rst8
-rw-r--r--Help/variable/CMAKE_LANG_CREATE_STATIC_LIBRARY.rst7
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS.rst20
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_CONFIG.rst6
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_CONFIG_INIT.rst12
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_DEBUG.rst5
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_DEBUG_INIT.rst7
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_INIT.rst19
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_MINSIZEREL.rst5
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_MINSIZEREL_INIT.rst7
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_RELEASE.rst5
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_RELEASE_INIT.rst7
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO.rst5
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO_INIT.rst7
-rw-r--r--Help/variable/CMAKE_LANG_IGNORE_EXTENSIONS.rst7
-rw-r--r--Help/variable/CMAKE_LANG_IMPLICIT_INCLUDE_DIRECTORIES.rst14
-rw-r--r--Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst20
-rw-r--r--Help/variable/CMAKE_LANG_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES.rst8
-rw-r--r--Help/variable/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES.rst10
-rw-r--r--Help/variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE.rst8
-rw-r--r--Help/variable/CMAKE_LANG_LIBRARY_ARCHITECTURE.rst8
-rw-r--r--Help/variable/CMAKE_LANG_LINKER_PREFERENCE.rst11
-rw-r--r--Help/variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES.rst9
-rw-r--r--Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG.rst41
-rw-r--r--Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG_SEP.rst11
-rw-r--r--Help/variable/CMAKE_LANG_LINK_EXECUTABLE.rst6
-rw-r--r--Help/variable/CMAKE_LANG_LINK_LIBRARY_FILE_FLAG.rst10
-rw-r--r--Help/variable/CMAKE_LANG_LINK_LIBRARY_FLAG.rst9
-rw-r--r--Help/variable/CMAKE_LANG_LINK_LIBRARY_SUFFIX.rst8
-rw-r--r--Help/variable/CMAKE_LANG_OUTPUT_EXTENSION.rst7
-rw-r--r--Help/variable/CMAKE_LANG_PLATFORM_ID.rst6
-rw-r--r--Help/variable/CMAKE_LANG_SIMULATE_ID.rst9
-rw-r--r--Help/variable/CMAKE_LANG_SIMULATE_VERSION.rst9
-rw-r--r--Help/variable/CMAKE_LANG_SIZEOF_DATA_PTR.rst7
-rw-r--r--Help/variable/CMAKE_LANG_SOURCE_FILE_EXTENSIONS.rst6
-rw-r--r--Help/variable/CMAKE_LANG_STANDARD_INCLUDE_DIRECTORIES.rst16
-rw-r--r--Help/variable/CMAKE_LANG_STANDARD_LIBRARIES.rst14
-rw-r--r--Help/variable/CMAKE_LANG_VISIBILITY_PRESET.rst5
-rw-r--r--Help/variable/CMAKE_LIBRARY_ARCHITECTURE.rst7
-rw-r--r--Help/variable/CMAKE_LIBRARY_ARCHITECTURE_REGEX.rst7
-rw-r--r--Help/variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY.rst9
-rw-r--r--Help/variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst11
-rw-r--r--Help/variable/CMAKE_LIBRARY_PATH.rst7
-rw-r--r--Help/variable/CMAKE_LIBRARY_PATH_FLAG.rst7
-rw-r--r--Help/variable/CMAKE_LINK_DEF_FILE_FLAG.rst7
-rw-r--r--Help/variable/CMAKE_LINK_DEPENDS_NO_SHARED.rst8
-rw-r--r--Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst11
-rw-r--r--Help/variable/CMAKE_LINK_INTERFACE_LIBRARIES.rst8
-rw-r--r--Help/variable/CMAKE_LINK_LIBRARY_FILE_FLAG.rst7
-rw-r--r--Help/variable/CMAKE_LINK_LIBRARY_FLAG.rst7
-rw-r--r--Help/variable/CMAKE_LINK_LIBRARY_SUFFIX.rst6
-rw-r--r--Help/variable/CMAKE_LINK_SEARCH_END_STATIC.rst21
-rw-r--r--Help/variable/CMAKE_LINK_SEARCH_START_STATIC.rst22
-rw-r--r--Help/variable/CMAKE_LINK_WHAT_YOU_USE.rst8
-rw-r--r--Help/variable/CMAKE_MACOSX_BUNDLE.rst10
-rw-r--r--Help/variable/CMAKE_MACOSX_RPATH.rst7
-rw-r--r--Help/variable/CMAKE_MAJOR_VERSION.rst5
-rw-r--r--Help/variable/CMAKE_MAKE_PROGRAM.rst64
-rw-r--r--Help/variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG.rst8
-rw-r--r--Help/variable/CMAKE_MATCH_COUNT.rst11
-rw-r--r--Help/variable/CMAKE_MATCH_n.rst12
-rw-r--r--Help/variable/CMAKE_MAXIMUM_RECURSION_DEPTH.rst35
-rw-r--r--Help/variable/CMAKE_MESSAGE_CONTEXT.rst64
-rw-r--r--Help/variable/CMAKE_MESSAGE_CONTEXT_SHOW.rst17
-rw-r--r--Help/variable/CMAKE_MESSAGE_INDENT.rst34
-rw-r--r--Help/variable/CMAKE_MESSAGE_LOG_LEVEL.rst17
-rw-r--r--Help/variable/CMAKE_MFC_FLAG.rst20
-rw-r--r--Help/variable/CMAKE_MINIMUM_REQUIRED_VERSION.rst5
-rw-r--r--Help/variable/CMAKE_MINOR_VERSION.rst5
-rw-r--r--Help/variable/CMAKE_MODULE_LINKER_FLAGS.rst6
-rw-r--r--Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst6
-rw-r--r--Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG_INIT.rst12
-rw-r--r--Help/variable/CMAKE_MODULE_LINKER_FLAGS_INIT.rst13
-rw-r--r--Help/variable/CMAKE_MODULE_PATH.rst7
-rw-r--r--Help/variable/CMAKE_MSVCIDE_RUN_PATH.rst12
-rw-r--r--Help/variable/CMAKE_MSVC_RUNTIME_LIBRARY.rst34
-rw-r--r--Help/variable/CMAKE_NETRC.rst11
-rw-r--r--Help/variable/CMAKE_NETRC_FILE.rst11
-rw-r--r--Help/variable/CMAKE_NINJA_OUTPUT_PATH_PREFIX.rst29
-rw-r--r--Help/variable/CMAKE_NOT_USING_CONFIG_FLAGS.rst7
-rw-r--r--Help/variable/CMAKE_NO_BUILTIN_CHRPATH.rst17
-rw-r--r--Help/variable/CMAKE_NO_SYSTEM_FROM_IMPORTED.rst8
-rw-r--r--Help/variable/CMAKE_OBJCXX_EXTENSIONS.rst13
-rw-r--r--Help/variable/CMAKE_OBJCXX_STANDARD.rst13
-rw-r--r--Help/variable/CMAKE_OBJCXX_STANDARD_REQUIRED.rst13
-rw-r--r--Help/variable/CMAKE_OBJC_EXTENSIONS.rst13
-rw-r--r--Help/variable/CMAKE_OBJC_STANDARD.rst13
-rw-r--r--Help/variable/CMAKE_OBJC_STANDARD_REQUIRED.rst13
-rw-r--r--Help/variable/CMAKE_OBJECT_PATH_MAX.rst16
-rw-r--r--Help/variable/CMAKE_OPTIMIZE_DEPENDENCIES.rst6
-rw-r--r--Help/variable/CMAKE_OSX_ARCHITECTURES.rst10
-rw-r--r--Help/variable/CMAKE_OSX_DEPLOYMENT_TARGET.rst15
-rw-r--r--Help/variable/CMAKE_OSX_SYSROOT.rst13
-rw-r--r--Help/variable/CMAKE_OSX_VARIABLE.txt11
-rw-r--r--Help/variable/CMAKE_PARENT_LIST_FILE.rst9
-rw-r--r--Help/variable/CMAKE_PATCH_VERSION.rst5
-rw-r--r--Help/variable/CMAKE_PCH_INSTANTIATE_TEMPLATES.rst7
-rw-r--r--Help/variable/CMAKE_PCH_WARN_INVALID.rst7
-rw-r--r--Help/variable/CMAKE_PDB_OUTPUT_DIRECTORY.rst9
-rw-r--r--Help/variable/CMAKE_PDB_OUTPUT_DIRECTORY_CONFIG.rst11
-rw-r--r--Help/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst17
-rw-r--r--Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst37
-rw-r--r--Help/variable/CMAKE_POSITION_INDEPENDENT_CODE.rst9
-rw-r--r--Help/variable/CMAKE_PREFIX_PATH.rst15
-rw-r--r--Help/variable/CMAKE_PROGRAM_PATH.rst7
-rw-r--r--Help/variable/CMAKE_PROJECT_DESCRIPTION.rst37
-rw-r--r--Help/variable/CMAKE_PROJECT_HOMEPAGE_URL.rst37
-rw-r--r--Help/variable/CMAKE_PROJECT_INCLUDE.rst12
-rw-r--r--Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst12
-rw-r--r--Help/variable/CMAKE_PROJECT_NAME.rst35
-rw-r--r--Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst11
-rw-r--r--Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE.rst13
-rw-r--r--Help/variable/CMAKE_PROJECT_VERSION.rst37
-rw-r--r--Help/variable/CMAKE_PROJECT_VERSION_MAJOR.rst11
-rw-r--r--Help/variable/CMAKE_PROJECT_VERSION_MINOR.rst11
-rw-r--r--Help/variable/CMAKE_PROJECT_VERSION_PATCH.rst11
-rw-r--r--Help/variable/CMAKE_PROJECT_VERSION_TWEAK.rst11
-rw-r--r--Help/variable/CMAKE_RANLIB.rst7
-rw-r--r--Help/variable/CMAKE_ROOT.rst8
-rw-r--r--Help/variable/CMAKE_RULE_MESSAGES.rst10
-rw-r--r--Help/variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY.rst9
-rw-r--r--Help/variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst11
-rw-r--r--Help/variable/CMAKE_SCRIPT_MODE_FILE.rst9
-rw-r--r--Help/variable/CMAKE_SHARED_LIBRARY_PREFIX.rst8
-rw-r--r--Help/variable/CMAKE_SHARED_LIBRARY_SUFFIX.rst9
-rw-r--r--Help/variable/CMAKE_SHARED_LINKER_FLAGS.rst6
-rw-r--r--Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst7
-rw-r--r--Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG_INIT.rst12
-rw-r--r--Help/variable/CMAKE_SHARED_LINKER_FLAGS_INIT.rst13
-rw-r--r--Help/variable/CMAKE_SHARED_MODULE_PREFIX.rst8
-rw-r--r--Help/variable/CMAKE_SHARED_MODULE_SUFFIX.rst9
-rw-r--r--Help/variable/CMAKE_SIZEOF_VOID_P.rst8
-rw-r--r--Help/variable/CMAKE_SKIP_BUILD_RPATH.rst10
-rw-r--r--Help/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY.rst11
-rw-r--r--Help/variable/CMAKE_SKIP_INSTALL_RPATH.rst14
-rw-r--r--Help/variable/CMAKE_SKIP_INSTALL_RULES.rst8
-rw-r--r--Help/variable/CMAKE_SKIP_RPATH.rst10
-rw-r--r--Help/variable/CMAKE_SOURCE_DIR.rst13
-rw-r--r--Help/variable/CMAKE_STAGING_PREFIX.rst14
-rw-r--r--Help/variable/CMAKE_STATIC_LIBRARY_PREFIX.rst8
-rw-r--r--Help/variable/CMAKE_STATIC_LIBRARY_SUFFIX.rst9
-rw-r--r--Help/variable/CMAKE_STATIC_LINKER_FLAGS.rst12
-rw-r--r--Help/variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG.rst13
-rw-r--r--Help/variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG_INIT.rst12
-rw-r--r--Help/variable/CMAKE_STATIC_LINKER_FLAGS_INIT.rst13
-rw-r--r--Help/variable/CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS.rst27
-rw-r--r--Help/variable/CMAKE_SUBLIME_TEXT_2_EXCLUDE_BUILD_TREE.rst9
-rw-r--r--Help/variable/CMAKE_SUPPRESS_REGENERATION.rst13
-rw-r--r--Help/variable/CMAKE_SYSROOT.rst15
-rw-r--r--Help/variable/CMAKE_SYSROOT_COMPILE.rst11
-rw-r--r--Help/variable/CMAKE_SYSROOT_LINK.rst11
-rw-r--r--Help/variable/CMAKE_SYSTEM.rst10
-rw-r--r--Help/variable/CMAKE_SYSTEM_APPBUNDLE_PATH.rst9
-rw-r--r--Help/variable/CMAKE_SYSTEM_FRAMEWORK_PATH.rst10
-rw-r--r--Help/variable/CMAKE_SYSTEM_IGNORE_PATH.rst18
-rw-r--r--Help/variable/CMAKE_SYSTEM_INCLUDE_PATH.rst8
-rw-r--r--Help/variable/CMAKE_SYSTEM_LIBRARY_PATH.rst8
-rw-r--r--Help/variable/CMAKE_SYSTEM_NAME.rst23
-rw-r--r--Help/variable/CMAKE_SYSTEM_PREFIX_PATH.rst53
-rw-r--r--Help/variable/CMAKE_SYSTEM_PROCESSOR.rst13
-rw-r--r--Help/variable/CMAKE_SYSTEM_PROGRAM_PATH.rst8
-rw-r--r--Help/variable/CMAKE_SYSTEM_VERSION.rst28
-rw-r--r--Help/variable/CMAKE_Swift_LANGUAGE_VERSION.rst11
-rw-r--r--Help/variable/CMAKE_Swift_MODULE_DIRECTORY.rst10
-rw-r--r--Help/variable/CMAKE_Swift_NUM_THREADS.rst10
-rw-r--r--Help/variable/CMAKE_TOOLCHAIN_FILE.rst9
-rw-r--r--Help/variable/CMAKE_TRY_COMPILE_CONFIGURATION.rst10
-rw-r--r--Help/variable/CMAKE_TRY_COMPILE_PLATFORM_VARIABLES.rst28
-rw-r--r--Help/variable/CMAKE_TRY_COMPILE_TARGET_TYPE.rst17
-rw-r--r--Help/variable/CMAKE_TWEAK_VERSION.rst11
-rw-r--r--Help/variable/CMAKE_UNITY_BUILD.rst22
-rw-r--r--Help/variable/CMAKE_UNITY_BUILD_BATCH_SIZE.rst9
-rw-r--r--Help/variable/CMAKE_UNITY_BUILD_UNIQUE_ID.rst8
-rw-r--r--Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE.rst25
-rw-r--r--Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE_LANG.rst8
-rw-r--r--Help/variable/CMAKE_USE_RELATIVE_PATHS.rst5
-rw-r--r--Help/variable/CMAKE_VERBOSE_MAKEFILE.rst9
-rw-r--r--Help/variable/CMAKE_VERSION.rst51
-rw-r--r--Help/variable/CMAKE_VISIBILITY_INLINES_HIDDEN.rst5
-rw-r--r--Help/variable/CMAKE_VS_DEVENV_COMMAND.rst14
-rw-r--r--Help/variable/CMAKE_VS_GLOBALS.rst23
-rw-r--r--Help/variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD.rst10
-rw-r--r--Help/variable/CMAKE_VS_INCLUDE_PACKAGE_TO_DEFAULT_BUILD.rst10
-rw-r--r--Help/variable/CMAKE_VS_INTEL_Fortran_PROJECT_VERSION.rst7
-rw-r--r--Help/variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING.rst10
-rw-r--r--Help/variable/CMAKE_VS_MSBUILD_COMMAND.rst13
-rw-r--r--Help/variable/CMAKE_VS_NsightTegra_VERSION.rst9
-rw-r--r--Help/variable/CMAKE_VS_PLATFORM_NAME.rst12
-rw-r--r--Help/variable/CMAKE_VS_PLATFORM_NAME_DEFAULT.rst11
-rw-r--r--Help/variable/CMAKE_VS_PLATFORM_TOOLSET.rst12
-rw-r--r--Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst16
-rw-r--r--Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR.rst17
-rw-r--r--Help/variable/CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE.rst12
-rw-r--r--Help/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst33
-rw-r--r--Help/variable/CMAKE_VS_SDK_EXCLUDE_DIRECTORIES.rst6
-rw-r--r--Help/variable/CMAKE_VS_SDK_EXECUTABLE_DIRECTORIES.rst6
-rw-r--r--Help/variable/CMAKE_VS_SDK_INCLUDE_DIRECTORIES.rst6
-rw-r--r--Help/variable/CMAKE_VS_SDK_LIBRARY_DIRECTORIES.rst6
-rw-r--r--Help/variable/CMAKE_VS_SDK_LIBRARY_WINRT_DIRECTORIES.rst7
-rw-r--r--Help/variable/CMAKE_VS_SDK_REFERENCE_DIRECTORIES.rst6
-rw-r--r--Help/variable/CMAKE_VS_SDK_SOURCE_DIRECTORIES.rst6
-rw-r--r--Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.rst21
-rw-r--r--Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM.rst14
-rw-r--r--Help/variable/CMAKE_VS_WINRT_BY_DEFAULT.rst20
-rw-r--r--Help/variable/CMAKE_WARN_DEPRECATED.rst10
-rw-r--r--Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst9
-rw-r--r--Help/variable/CMAKE_WIN32_EXECUTABLE.rst7
-rw-r--r--Help/variable/CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS.rst8
-rw-r--r--Help/variable/CMAKE_XCODE_ATTRIBUTE_an-attribute.rst24
-rw-r--r--Help/variable/CMAKE_XCODE_BUILD_SYSTEM.rst24
-rw-r--r--Help/variable/CMAKE_XCODE_GENERATE_SCHEME.rst12
-rw-r--r--Help/variable/CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY.rst11
-rw-r--r--Help/variable/CMAKE_XCODE_LINK_BUILD_PHASE_MODE.rst9
-rw-r--r--Help/variable/CMAKE_XCODE_PLATFORM_TOOLSET.rst9
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER.rst14
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst14
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING.rst15
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst14
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst14
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst14
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_ENVIRONMENT.rst17
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC.rst14
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst15
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES.rst14
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE.rst14
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_MALLOC_STACK.rst14
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER.rst14
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP.rst14
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst14
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst15
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_WORKING_DIRECTORY.rst14
-rw-r--r--Help/variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS.rst14
-rw-r--r--Help/variable/CPACK_ABSOLUTE_DESTINATION_FILES.rst10
-rw-r--r--Help/variable/CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY.rst8
-rw-r--r--Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst11
-rw-r--r--Help/variable/CPACK_INCLUDE_TOPLEVEL_DIRECTORY.rst20
-rw-r--r--Help/variable/CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS.rst13
-rw-r--r--Help/variable/CPACK_PACKAGING_INSTALL_PREFIX.rst15
-rw-r--r--Help/variable/CPACK_SET_DESTDIR.rst31
-rw-r--r--Help/variable/CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst9
-rw-r--r--Help/variable/CTEST_BINARY_DIRECTORY.rst7
-rw-r--r--Help/variable/CTEST_BUILD_COMMAND.rst7
-rw-r--r--Help/variable/CTEST_BUILD_NAME.rst7
-rw-r--r--Help/variable/CTEST_BZR_COMMAND.rst7
-rw-r--r--Help/variable/CTEST_BZR_UPDATE_OPTIONS.rst7
-rw-r--r--Help/variable/CTEST_CHANGE_ID.rst11
-rw-r--r--Help/variable/CTEST_CHECKOUT_COMMAND.rst7
-rw-r--r--Help/variable/CTEST_CONFIGURATION_TYPE.rst10
-rw-r--r--Help/variable/CTEST_CONFIGURE_COMMAND.rst7
-rw-r--r--Help/variable/CTEST_COVERAGE_COMMAND.rst62
-rw-r--r--Help/variable/CTEST_COVERAGE_EXTRA_FLAGS.rst7
-rw-r--r--Help/variable/CTEST_CURL_OPTIONS.rst7
-rw-r--r--Help/variable/CTEST_CUSTOM_COVERAGE_EXCLUDE.rst7
-rw-r--r--Help/variable/CTEST_CUSTOM_ERROR_EXCEPTION.rst7
-rw-r--r--Help/variable/CTEST_CUSTOM_ERROR_MATCH.rst7
-rw-r--r--Help/variable/CTEST_CUSTOM_ERROR_POST_CONTEXT.rst7
-rw-r--r--Help/variable/CTEST_CUSTOM_ERROR_PRE_CONTEXT.rst7
-rw-r--r--Help/variable/CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE.rst8
-rw-r--r--Help/variable/CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS.rst8
-rw-r--r--Help/variable/CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS.rst8
-rw-r--r--Help/variable/CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE.rst8
-rw-r--r--Help/variable/CTEST_CUSTOM_MEMCHECK_IGNORE.rst7
-rw-r--r--Help/variable/CTEST_CUSTOM_POST_MEMCHECK.rst6
-rw-r--r--Help/variable/CTEST_CUSTOM_POST_TEST.rst6
-rw-r--r--Help/variable/CTEST_CUSTOM_PRE_MEMCHECK.rst7
-rw-r--r--Help/variable/CTEST_CUSTOM_PRE_TEST.rst6
-rw-r--r--Help/variable/CTEST_CUSTOM_TESTS_IGNORE.rst7
-rw-r--r--Help/variable/CTEST_CUSTOM_WARNING_EXCEPTION.rst7
-rw-r--r--Help/variable/CTEST_CUSTOM_WARNING_MATCH.rst7
-rw-r--r--Help/variable/CTEST_CUSTOM_XXX.txt2
-rw-r--r--Help/variable/CTEST_CVS_CHECKOUT.rst6
-rw-r--r--Help/variable/CTEST_CVS_COMMAND.rst7
-rw-r--r--Help/variable/CTEST_CVS_UPDATE_OPTIONS.rst7
-rw-r--r--Help/variable/CTEST_DROP_LOCATION.rst7
-rw-r--r--Help/variable/CTEST_DROP_METHOD.rst7
-rw-r--r--Help/variable/CTEST_DROP_SITE.rst7
-rw-r--r--Help/variable/CTEST_DROP_SITE_CDASH.rst7
-rw-r--r--Help/variable/CTEST_DROP_SITE_PASSWORD.rst7
-rw-r--r--Help/variable/CTEST_DROP_SITE_USER.rst7
-rw-r--r--Help/variable/CTEST_EXTRA_COVERAGE_GLOB.rst9
-rw-r--r--Help/variable/CTEST_GIT_COMMAND.rst7
-rw-r--r--Help/variable/CTEST_GIT_INIT_SUBMODULES.rst7
-rw-r--r--Help/variable/CTEST_GIT_UPDATE_CUSTOM.rst7
-rw-r--r--Help/variable/CTEST_GIT_UPDATE_OPTIONS.rst7
-rw-r--r--Help/variable/CTEST_HG_COMMAND.rst7
-rw-r--r--Help/variable/CTEST_HG_UPDATE_OPTIONS.rst7
-rw-r--r--Help/variable/CTEST_LABELS_FOR_SUBPROJECTS.rst7
-rw-r--r--Help/variable/CTEST_MEMORYCHECK_COMMAND.rst7
-rw-r--r--Help/variable/CTEST_MEMORYCHECK_COMMAND_OPTIONS.rst7
-rw-r--r--Help/variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst12
-rw-r--r--Help/variable/CTEST_MEMORYCHECK_SUPPRESSIONS_FILE.rst7
-rw-r--r--Help/variable/CTEST_MEMORYCHECK_TYPE.rst10
-rw-r--r--Help/variable/CTEST_NIGHTLY_START_TIME.rst11
-rw-r--r--Help/variable/CTEST_P4_CLIENT.rst7
-rw-r--r--Help/variable/CTEST_P4_COMMAND.rst7
-rw-r--r--Help/variable/CTEST_P4_OPTIONS.rst7
-rw-r--r--Help/variable/CTEST_P4_UPDATE_OPTIONS.rst7
-rw-r--r--Help/variable/CTEST_RESOURCE_SPEC_FILE.rst12
-rw-r--r--Help/variable/CTEST_RUN_CURRENT_SCRIPT.rst7
-rw-r--r--Help/variable/CTEST_SCP_COMMAND.rst6
-rw-r--r--Help/variable/CTEST_SITE.rst7
-rw-r--r--Help/variable/CTEST_SOURCE_DIRECTORY.rst7
-rw-r--r--Help/variable/CTEST_SUBMIT_URL.rst7
-rw-r--r--Help/variable/CTEST_SVN_COMMAND.rst7
-rw-r--r--Help/variable/CTEST_SVN_OPTIONS.rst7
-rw-r--r--Help/variable/CTEST_SVN_UPDATE_OPTIONS.rst7
-rw-r--r--Help/variable/CTEST_TEST_LOAD.rst9
-rw-r--r--Help/variable/CTEST_TEST_TIMEOUT.rst7
-rw-r--r--Help/variable/CTEST_TRIGGER_SITE.rst6
-rw-r--r--Help/variable/CTEST_UPDATE_COMMAND.rst7
-rw-r--r--Help/variable/CTEST_UPDATE_OPTIONS.rst7
-rw-r--r--Help/variable/CTEST_UPDATE_VERSION_ONLY.rst7
-rw-r--r--Help/variable/CTEST_UPDATE_VERSION_OVERRIDE.rst7
-rw-r--r--Help/variable/CTEST_USE_LAUNCHERS.rst7
-rw-r--r--Help/variable/CYGWIN.rst6
-rw-r--r--Help/variable/ENV.rst12
-rw-r--r--Help/variable/EXECUTABLE_OUTPUT_PATH.rst8
-rw-r--r--Help/variable/GHS-MULTI.rst6
-rw-r--r--Help/variable/IOS.rst6
-rw-r--r--Help/variable/LIBRARY_OUTPUT_PATH.rst9
-rw-r--r--Help/variable/MINGW.rst8
-rw-r--r--Help/variable/MSVC.rst7
-rw-r--r--Help/variable/MSVC10.rst7
-rw-r--r--Help/variable/MSVC11.rst7
-rw-r--r--Help/variable/MSVC12.rst7
-rw-r--r--Help/variable/MSVC14.rst9
-rw-r--r--Help/variable/MSVC60.rst8
-rw-r--r--Help/variable/MSVC70.rst8
-rw-r--r--Help/variable/MSVC71.rst8
-rw-r--r--Help/variable/MSVC80.rst7
-rw-r--r--Help/variable/MSVC90.rst7
-rw-r--r--Help/variable/MSVC_IDE.rst14
-rw-r--r--Help/variable/MSVC_TOOLSET_VERSION.rst24
-rw-r--r--Help/variable/MSVC_VERSION.rst24
-rw-r--r--Help/variable/MSYS.rst6
-rw-r--r--Help/variable/PROJECT-NAME_BINARY_DIR.rst8
-rw-r--r--Help/variable/PROJECT-NAME_DESCRIPTION.rst7
-rw-r--r--Help/variable/PROJECT-NAME_HOMEPAGE_URL.rst7
-rw-r--r--Help/variable/PROJECT-NAME_IS_TOP_LEVEL.rst11
-rw-r--r--Help/variable/PROJECT-NAME_SOURCE_DIR.rst8
-rw-r--r--Help/variable/PROJECT-NAME_VERSION.rst11
-rw-r--r--Help/variable/PROJECT-NAME_VERSION_MAJOR.rst5
-rw-r--r--Help/variable/PROJECT-NAME_VERSION_MINOR.rst5
-rw-r--r--Help/variable/PROJECT-NAME_VERSION_PATCH.rst5
-rw-r--r--Help/variable/PROJECT-NAME_VERSION_TWEAK.rst5
-rw-r--r--Help/variable/PROJECT_BINARY_DIR.rst6
-rw-r--r--Help/variable/PROJECT_DESCRIPTION.rst11
-rw-r--r--Help/variable/PROJECT_HOMEPAGE_URL.rst11
-rw-r--r--Help/variable/PROJECT_IS_TOP_LEVEL.rst21
-rw-r--r--Help/variable/PROJECT_NAME.rst8
-rw-r--r--Help/variable/PROJECT_SOURCE_DIR.rst8
-rw-r--r--Help/variable/PROJECT_VERSION.rst11
-rw-r--r--Help/variable/PROJECT_VERSION_MAJOR.rst5
-rw-r--r--Help/variable/PROJECT_VERSION_MINOR.rst5
-rw-r--r--Help/variable/PROJECT_VERSION_PATCH.rst5
-rw-r--r--Help/variable/PROJECT_VERSION_TWEAK.rst5
-rw-r--r--Help/variable/PackageName_ROOT.rst16
-rw-r--r--Help/variable/UNIX.rst7
-rw-r--r--Help/variable/WIN32.rst4
-rw-r--r--Help/variable/WINCE.rst7
-rw-r--r--Help/variable/WINDOWS_PHONE.rst7
-rw-r--r--Help/variable/WINDOWS_STORE.rst7
-rw-r--r--Help/variable/XCODE.rst6
-rw-r--r--Help/variable/XCODE_VERSION.rst7
-rw-r--r--Licenses/LGPLv2.1.txt502
-rw-r--r--Licenses/LGPLv3.txt165
-rw-r--r--Licenses/README.rst7
-rw-r--r--Modules/AddFileDependencies.cmake33
-rw-r--r--Modules/AndroidTestUtilities.cmake164
-rw-r--r--Modules/AndroidTestUtilities/PushToAndroidDevice.cmake176
-rw-r--r--Modules/BasicConfigVersion-AnyNewerVersion.cmake.in48
-rw-r--r--Modules/BasicConfigVersion-ExactVersion.cmake.in59
-rw-r--r--Modules/BasicConfigVersion-SameMajorVersion.cmake.in67
-rw-r--r--Modules/BasicConfigVersion-SameMinorVersion.cmake.in76
-rw-r--r--Modules/BundleUtilities.cmake1132
-rw-r--r--Modules/CMake.cmake7
-rw-r--r--Modules/CMakeASM-ATTInformation.cmake15
-rw-r--r--Modules/CMakeASMCompiler.cmake.in20
-rw-r--r--Modules/CMakeASMInformation.cmake100
-rw-r--r--Modules/CMakeASM_MASMInformation.cmake20
-rw-r--r--Modules/CMakeASM_NASMInformation.cmake53
-rw-r--r--Modules/CMakeAddFortranSubdirectory.cmake194
-rw-r--r--Modules/CMakeAddFortranSubdirectory/build_mingw.cmake.in2
-rw-r--r--Modules/CMakeAddFortranSubdirectory/config_mingw.cmake.in9
-rw-r--r--Modules/CMakeAddNewLanguage.txt31
-rw-r--r--Modules/CMakeBackwardCompatibilityC.cmake76
-rw-r--r--Modules/CMakeBackwardCompatibilityCXX.cmake49
-rw-r--r--Modules/CMakeBorlandFindMake.cmake7
-rw-r--r--Modules/CMakeBuildSettings.cmake.in13
-rw-r--r--Modules/CMakeCCompiler.cmake.in80
-rw-r--r--Modules/CMakeCCompilerABI.c27
-rw-r--r--Modules/CMakeCCompilerId.c.in90
-rw-r--r--Modules/CMakeCInformation.cmake195
-rw-r--r--Modules/CMakeCSharpCompiler.cmake.in10
-rw-r--r--Modules/CMakeCSharpCompilerId.cs.in63
-rw-r--r--Modules/CMakeCSharpInformation.cmake67
-rw-r--r--Modules/CMakeCUDACompiler.cmake.in69
-rw-r--r--Modules/CMakeCUDACompilerABI.cu18
-rw-r--r--Modules/CMakeCUDACompilerId.cu.in54
-rw-r--r--Modules/CMakeCUDAInformation.cmake198
-rw-r--r--Modules/CMakeCXXCompiler.cmake.in91
-rw-r--r--Modules/CMakeCXXCompilerABI.cpp18
-rw-r--r--Modules/CMakeCXXCompilerId.cpp.in87
-rw-r--r--Modules/CMakeCXXInformation.cmake282
-rw-r--r--Modules/CMakeCheckCompilerFlagCommonPatterns.cmake36
-rw-r--r--Modules/CMakeCommonLanguageInclude.cmake23
-rw-r--r--Modules/CMakeCompilerABI.h45
-rw-r--r--Modules/CMakeCompilerIdDetection.cmake155
-rw-r--r--Modules/CMakeConfigurableFile.in1
-rw-r--r--Modules/CMakeDependentOption.cmake64
-rw-r--r--Modules/CMakeDetermineASM-ATTCompiler.cmake10
-rw-r--r--Modules/CMakeDetermineASMCompiler.cmake257
-rw-r--r--Modules/CMakeDetermineASM_MASMCompiler.cmake18
-rw-r--r--Modules/CMakeDetermineASM_NASMCompiler.cmake30
-rw-r--r--Modules/CMakeDetermineCCompiler.cmake230
-rw-r--r--Modules/CMakeDetermineCSharpCompiler.cmake42
-rw-r--r--Modules/CMakeDetermineCUDACompiler.cmake615
-rw-r--r--Modules/CMakeDetermineCXXCompiler.cmake231
-rw-r--r--Modules/CMakeDetermineCompileFeatures.cmake171
-rw-r--r--Modules/CMakeDetermineCompiler.cmake166
-rw-r--r--Modules/CMakeDetermineCompilerABI.cmake192
-rw-r--r--Modules/CMakeDetermineCompilerId.cmake1090
-rw-r--r--Modules/CMakeDetermineFortranCompiler.cmake307
-rw-r--r--Modules/CMakeDetermineISPCCompiler.cmake96
-rw-r--r--Modules/CMakeDetermineJavaCompiler.cmake94
-rw-r--r--Modules/CMakeDetermineOBJCCompiler.cmake189
-rw-r--r--Modules/CMakeDetermineOBJCXXCompiler.cmake197
-rw-r--r--Modules/CMakeDetermineRCCompiler.cmake57
-rw-r--r--Modules/CMakeDetermineSwiftCompiler.cmake78
-rw-r--r--Modules/CMakeDetermineSystem.cmake196
-rw-r--r--Modules/CMakeDetermineVSServicePack.cmake174
-rw-r--r--Modules/CMakeExpandImportedTargets.cmake148
-rw-r--r--Modules/CMakeExportBuildSettings.cmake26
-rw-r--r--Modules/CMakeExtraGeneratorDetermineCompilerMacrosAndIncludeDirs.cmake114
-rw-r--r--Modules/CMakeFindBinUtils.cmake165
-rw-r--r--Modules/CMakeFindCodeBlocks.cmake33
-rw-r--r--Modules/CMakeFindDependencyMacro.cmake63
-rw-r--r--Modules/CMakeFindEclipseCDT4.cmake89
-rw-r--r--Modules/CMakeFindFrameworks.cmake45
-rw-r--r--Modules/CMakeFindJavaCommon.cmake31
-rw-r--r--Modules/CMakeFindKate.cmake21
-rw-r--r--Modules/CMakeFindPackageMode.cmake204
-rw-r--r--Modules/CMakeFindSublimeText2.cmake23
-rw-r--r--Modules/CMakeFindWMake.cmake7
-rw-r--r--Modules/CMakeFindXCode.cmake6
-rw-r--r--Modules/CMakeForceCompiler.cmake114
-rw-r--r--Modules/CMakeFortranCompiler.cmake.in69
-rw-r--r--Modules/CMakeFortranCompilerABI.F40
-rw-r--r--Modules/CMakeFortranCompilerId.F.in243
-rw-r--r--Modules/CMakeFortranInformation.cmake222
-rw-r--r--Modules/CMakeGenericSystem.cmake187
-rw-r--r--Modules/CMakeGraphVizOptions.cmake150
-rw-r--r--Modules/CMakeIOSInstallCombined.cmake329
-rw-r--r--Modules/CMakeISPCCompiler.cmake.in30
-rw-r--r--Modules/CMakeISPCCompilerABI.ispc20
-rw-r--r--Modules/CMakeISPCCompilerId.ispc.in62
-rw-r--r--Modules/CMakeISPCInformation.cmake65
-rw-r--r--Modules/CMakeImportBuildSettings.cmake13
-rw-r--r--Modules/CMakeInitializeConfigs.cmake39
-rw-r--r--Modules/CMakeJOMFindMake.cmake7
-rw-r--r--Modules/CMakeJavaCompiler.cmake.in13
-rw-r--r--Modules/CMakeJavaInformation.cmake49
-rw-r--r--Modules/CMakeLanguageInformation.cmake27
-rw-r--r--Modules/CMakeMSYSFindMake.cmake10
-rw-r--r--Modules/CMakeMinGWFindMake.cmake11
-rw-r--r--Modules/CMakeNMakeFindMake.cmake7
-rw-r--r--Modules/CMakeNinjaFindMake.cmake9
-rw-r--r--Modules/CMakeOBJCCompiler.cmake.in70
-rw-r--r--Modules/CMakeOBJCCompilerABI.m22
-rw-r--r--Modules/CMakeOBJCCompilerId.m.in63
-rw-r--r--Modules/CMakeOBJCInformation.cmake193
-rw-r--r--Modules/CMakeOBJCXXCompiler.cmake.in81
-rw-r--r--Modules/CMakeOBJCXXCompilerABI.mm22
-rw-r--r--Modules/CMakeOBJCXXCompilerId.mm.in70
-rw-r--r--Modules/CMakeOBJCXXInformation.cmake278
-rw-r--r--Modules/CMakePackageConfigHelpers.cmake344
-rw-r--r--Modules/CMakeParseArguments.cmake12
-rw-r--r--Modules/CMakeParseImplicitIncludeInfo.cmake262
-rw-r--r--Modules/CMakeParseImplicitLinkInfo.cmake239
-rw-r--r--Modules/CMakeParseLibraryArchitecture.cmake54
-rw-r--r--Modules/CMakePlatformId.h.in315
-rw-r--r--Modules/CMakePrintHelpers.cmake150
-rw-r--r--Modules/CMakePrintSystemInformation.cmake41
-rw-r--r--Modules/CMakePushCheckState.cmake91
-rw-r--r--Modules/CMakeRCCompiler.cmake.in6
-rw-r--r--Modules/CMakeRCInformation.cmake50
-rw-r--r--Modules/CMakeSwiftCompiler.cmake.in16
-rw-r--r--Modules/CMakeSwiftInformation.cmake103
-rw-r--r--Modules/CMakeSystem.cmake.in15
-rw-r--r--Modules/CMakeSystemSpecificInformation.cmake58
-rw-r--r--Modules/CMakeSystemSpecificInitialize.cmake23
-rw-r--r--Modules/CMakeTestASM-ATTCompiler.cmake13
-rw-r--r--Modules/CMakeTestASMCompiler.cmake25
-rw-r--r--Modules/CMakeTestASM_MASMCompiler.cmake13
-rw-r--r--Modules/CMakeTestASM_NASMCompiler.cmake13
-rw-r--r--Modules/CMakeTestCCompiler.cmake98
-rw-r--r--Modules/CMakeTestCSharpCompiler.cmake67
-rw-r--r--Modules/CMakeTestCUDACompiler.cmake98
-rw-r--r--Modules/CMakeTestCXXCompiler.cmake91
-rw-r--r--Modules/CMakeTestCompilerCommon.cmake34
-rw-r--r--Modules/CMakeTestFortranCompiler.cmake102
-rw-r--r--Modules/CMakeTestGNU.c10
-rw-r--r--Modules/CMakeTestISPCCompiler.cmake43
-rw-r--r--Modules/CMakeTestJavaCompiler.cmake10
-rw-r--r--Modules/CMakeTestOBJCCompiler.cmake95
-rw-r--r--Modules/CMakeTestOBJCXXCompiler.cmake94
-rw-r--r--Modules/CMakeTestRCCompiler.cmake13
-rw-r--r--Modules/CMakeTestSwiftCompiler.cmake64
-rw-r--r--Modules/CMakeUnixFindMake.cmake16
-rw-r--r--Modules/CMakeVerifyManifest.cmake110
-rw-r--r--Modules/CPack.cmake875
-rw-r--r--Modules/CPackComponent.cmake554
-rw-r--r--Modules/CPackIFW.cmake830
-rw-r--r--Modules/CPackIFWConfigureFile.cmake68
-rw-r--r--Modules/CSharpUtilities.cmake313
-rw-r--r--Modules/CTest.cmake267
-rw-r--r--Modules/CTestCoverageCollectGCOV.cmake352
-rw-r--r--Modules/CTestScriptMode.cmake20
-rw-r--r--Modules/CTestTargets.cmake93
-rw-r--r--Modules/CTestUseLaunchers.cmake73
-rw-r--r--Modules/CheckCCompilerFlag.cmake41
-rw-r--r--Modules/CheckCSourceCompiles.cmake77
-rw-r--r--Modules/CheckCSourceRuns.cmake78
-rw-r--r--Modules/CheckCXXCompilerFlag.cmake41
-rw-r--r--Modules/CheckCXXSourceCompiles.cmake77
-rw-r--r--Modules/CheckCXXSourceRuns.cmake78
-rw-r--r--Modules/CheckCXXSymbolExists.cmake78
-rw-r--r--Modules/CheckCompilerFlag.cmake41
-rw-r--r--Modules/CheckForPthreads.c15
-rw-r--r--Modules/CheckFortranCompilerFlag.cmake43
-rw-r--r--Modules/CheckFortranFunctionExists.cmake85
-rw-r--r--Modules/CheckFortranSourceCompiles.cmake98
-rw-r--r--Modules/CheckFortranSourceRuns.cmake92
-rw-r--r--Modules/CheckFunctionExists.c28
-rw-r--r--Modules/CheckFunctionExists.cmake121
-rw-r--r--Modules/CheckIPOSupported.cmake244
-rw-r--r--Modules/CheckIPOSupported/CMakeLists-C.txt.in8
-rw-r--r--Modules/CheckIPOSupported/CMakeLists-CXX.txt.in8
-rw-r--r--Modules/CheckIPOSupported/CMakeLists-Fortran.txt.in8
-rw-r--r--Modules/CheckIPOSupported/foo.c4
-rw-r--r--Modules/CheckIPOSupported/foo.cpp4
-rw-r--r--Modules/CheckIPOSupported/foo.f2
-rw-r--r--Modules/CheckIPOSupported/main.c6
-rw-r--r--Modules/CheckIPOSupported/main.cpp6
-rw-r--r--Modules/CheckIPOSupported/main.f3
-rw-r--r--Modules/CheckIncludeFile.c.in13
-rw-r--r--Modules/CheckIncludeFile.cmake132
-rw-r--r--Modules/CheckIncludeFile.cxx.in6
-rw-r--r--Modules/CheckIncludeFileCXX.cmake131
-rw-r--r--Modules/CheckIncludeFiles.cmake170
-rw-r--r--Modules/CheckLanguage.cmake112
-rw-r--r--Modules/CheckLibraryExists.cmake104
-rw-r--r--Modules/CheckLibraryExists.lists.in8
-rw-r--r--Modules/CheckLinkerFlag.cmake82
-rw-r--r--Modules/CheckOBJCCompilerFlag.cmake43
-rw-r--r--Modules/CheckOBJCSourceCompiles.cmake75
-rw-r--r--Modules/CheckOBJCSourceRuns.cmake76
-rw-r--r--Modules/CheckOBJCXXCompilerFlag.cmake43
-rw-r--r--Modules/CheckOBJCXXSourceCompiles.cmake75
-rw-r--r--Modules/CheckOBJCXXSourceRuns.cmake76
-rw-r--r--Modules/CheckPIESupported.cmake138
-rw-r--r--Modules/CheckPrototypeDefinition.c.in29
-rw-r--r--Modules/CheckPrototypeDefinition.cmake131
-rw-r--r--Modules/CheckSizeOf.cmake8
-rw-r--r--Modules/CheckSourceCompiles.cmake82
-rw-r--r--Modules/CheckSourceRuns.cmake80
-rw-r--r--Modules/CheckStructHasMember.cmake87
-rw-r--r--Modules/CheckSymbolExists.cmake168
-rw-r--r--Modules/CheckTypeSize.c.in47
-rw-r--r--Modules/CheckTypeSize.cmake294
-rw-r--r--Modules/CheckTypeSizeMap.cmake.in1
-rw-r--r--Modules/CheckVariableExists.c24
-rw-r--r--Modules/CheckVariableExists.cmake90
-rw-r--r--Modules/Compiler/ADSP-DetermineCompiler.cmake10
-rw-r--r--Modules/Compiler/ARMCC-ASM.cmake7
-rw-r--r--Modules/Compiler/ARMCC-C.cmake2
-rw-r--r--Modules/Compiler/ARMCC-CXX.cmake2
-rw-r--r--Modules/Compiler/ARMCC-DetermineCompiler.cmake16
-rw-r--r--Modules/Compiler/ARMCC.cmake39
-rw-r--r--Modules/Compiler/ARMClang-ASM.cmake9
-rw-r--r--Modules/Compiler/ARMClang-C-FeatureTests.cmake1
-rw-r--r--Modules/Compiler/ARMClang-C.cmake15
-rw-r--r--Modules/Compiler/ARMClang-CXX-FeatureTests.cmake1
-rw-r--r--Modules/Compiler/ARMClang-CXX.cmake3
-rw-r--r--Modules/Compiler/ARMClang-DetermineCompiler.cmake10
-rw-r--r--Modules/Compiler/ARMClang.cmake131
-rw-r--r--Modules/Compiler/Absoft-Fortran.cmake13
-rw-r--r--Modules/Compiler/AppleClang-ASM.cmake1
-rw-r--r--Modules/Compiler/AppleClang-C-FeatureTests.cmake11
-rw-r--r--Modules/Compiler/AppleClang-C.cmake31
-rw-r--r--Modules/Compiler/AppleClang-CXX-FeatureTests.cmake52
-rw-r--r--Modules/Compiler/AppleClang-CXX.cmake55
-rw-r--r--Modules/Compiler/AppleClang-DetermineCompiler.cmake7
-rw-r--r--Modules/Compiler/AppleClang-OBJC.cmake26
-rw-r--r--Modules/Compiler/AppleClang-OBJCXX.cmake52
-rw-r--r--Modules/Compiler/Borland-DetermineCompiler.cmake7
-rw-r--r--Modules/Compiler/Bruce-C-DetermineCompiler.cmake1
-rw-r--r--Modules/Compiler/Bruce-C.cmake9
-rw-r--r--Modules/Compiler/CCur-Fortran.cmake1
-rw-r--r--Modules/Compiler/CMakeCommonCompilerMacros.cmake172
-rw-r--r--Modules/Compiler/Clang-ASM.cmake5
-rw-r--r--Modules/Compiler/Clang-C-FeatureTests.cmake11
-rw-r--r--Modules/Compiler/Clang-C.cmake84
-rw-r--r--Modules/Compiler/Clang-CUDA.cmake35
-rw-r--r--Modules/Compiler/Clang-CXX-FeatureTests.cmake33
-rw-r--r--Modules/Compiler/Clang-CXX-TestableFeatures.cmake56
-rw-r--r--Modules/Compiler/Clang-CXX.cmake30
-rw-r--r--Modules/Compiler/Clang-DetermineCompiler.cmake4
-rw-r--r--Modules/Compiler/Clang-DetermineCompilerInternal.cmake15
-rw-r--r--Modules/Compiler/Clang-FindBinUtils.cmake43
-rw-r--r--Modules/Compiler/Clang-OBJC.cmake27
-rw-r--r--Modules/Compiler/Clang-OBJCXX.cmake11
-rw-r--r--Modules/Compiler/Clang.cmake244
-rw-r--r--Modules/Compiler/Comeau-CXX-DetermineCompiler.cmake7
-rw-r--r--Modules/Compiler/Compaq-C-DetermineCompiler.cmake8
-rw-r--r--Modules/Compiler/Compaq-CXX-DetermineCompiler.cmake8
-rw-r--r--Modules/Compiler/Cray-C.cmake24
-rw-r--r--Modules/Compiler/Cray-CXX.cmake26
-rw-r--r--Modules/Compiler/Cray-DetermineCompiler.cmake6
-rw-r--r--Modules/Compiler/Cray-Fortran.cmake25
-rw-r--r--Modules/Compiler/Cray.cmake17
-rw-r--r--Modules/Compiler/CrayPrgEnv-C.cmake7
-rw-r--r--Modules/Compiler/CrayPrgEnv-CXX.cmake7
-rw-r--r--Modules/Compiler/CrayPrgEnv-Fortran.cmake7
-rw-r--r--Modules/Compiler/CrayPrgEnv.cmake136
-rw-r--r--Modules/Compiler/Embarcadero-DetermineCompiler.cmake7
-rw-r--r--Modules/Compiler/Flang-FindBinUtils.cmake1
-rw-r--r--Modules/Compiler/Flang-Fortran.cmake16
-rw-r--r--Modules/Compiler/Fujitsu-C.cmake20
-rw-r--r--Modules/Compiler/Fujitsu-CXX.cmake47
-rw-r--r--Modules/Compiler/Fujitsu-DetermineCompiler.cmake17
-rw-r--r--Modules/Compiler/Fujitsu-Fortran.cmake16
-rw-r--r--Modules/Compiler/Fujitsu.cmake33
-rw-r--r--Modules/Compiler/FujitsuClang-C.cmake6
-rw-r--r--Modules/Compiler/FujitsuClang-CXX.cmake6
-rw-r--r--Modules/Compiler/FujitsuClang-DetermineCompiler.cmake9
-rw-r--r--Modules/Compiler/FujitsuClang.cmake11
-rw-r--r--Modules/Compiler/G95-Fortran.cmake13
-rw-r--r--Modules/Compiler/GHS-C.cmake10
-rw-r--r--Modules/Compiler/GHS-CXX.cmake10
-rw-r--r--Modules/Compiler/GHS-DetermineCompiler.cmake9
-rw-r--r--Modules/Compiler/GHS.cmake8
-rw-r--r--Modules/Compiler/GNU-ASM.cmake13
-rw-r--r--Modules/Compiler/GNU-C-DetermineCompiler.cmake11
-rw-r--r--Modules/Compiler/GNU-C-FeatureTests.cmake17
-rw-r--r--Modules/Compiler/GNU-C.cmake49
-rw-r--r--Modules/Compiler/GNU-CXX-DetermineCompiler.cmake15
-rw-r--r--Modules/Compiler/GNU-CXX-FeatureTests.cmake109
-rw-r--r--Modules/Compiler/GNU-CXX.cmake69
-rw-r--r--Modules/Compiler/GNU-FindBinUtils.cmake35
-rw-r--r--Modules/Compiler/GNU-Fortran.cmake28
-rw-r--r--Modules/Compiler/GNU-OBJC.cmake11
-rw-r--r--Modules/Compiler/GNU-OBJCXX.cmake19
-rw-r--r--Modules/Compiler/GNU.cmake122
-rw-r--r--Modules/Compiler/HP-ASM.cmake3
-rw-r--r--Modules/Compiler/HP-C-DetermineCompiler.cmake8
-rw-r--r--Modules/Compiler/HP-C.cmake7
-rw-r--r--Modules/Compiler/HP-CXX-DetermineCompiler.cmake8
-rw-r--r--Modules/Compiler/HP-CXX.cmake16
-rw-r--r--Modules/Compiler/HP-Fortran.cmake12
-rw-r--r--Modules/Compiler/IAR-ASM.cmake57
-rw-r--r--Modules/Compiler/IAR-C.cmake79
-rw-r--r--Modules/Compiler/IAR-CXX.cmake87
-rw-r--r--Modules/Compiler/IAR-DetermineCompiler.cmake39
-rw-r--r--Modules/Compiler/IAR-FindBinUtils.cmake64
-rw-r--r--Modules/Compiler/IAR.cmake115
-rw-r--r--Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake6
-rw-r--r--Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake6
-rw-r--r--Modules/Compiler/Intel-ASM.cmake12
-rw-r--r--Modules/Compiler/Intel-C-FeatureTests.cmake20
-rw-r--r--Modules/Compiler/Intel-C.cmake60
-rw-r--r--Modules/Compiler/Intel-CXX-FeatureTests.cmake111
-rw-r--r--Modules/Compiler/Intel-CXX.cmake104
-rw-r--r--Modules/Compiler/Intel-DetermineCompiler.cmake40
-rw-r--r--Modules/Compiler/Intel-Fortran.cmake27
-rw-r--r--Modules/Compiler/Intel-ISPC.cmake26
-rw-r--r--Modules/Compiler/Intel.cmake46
-rw-r--r--Modules/Compiler/IntelLLVM-ASM.cmake12
-rw-r--r--Modules/Compiler/IntelLLVM-C.cmake62
-rw-r--r--Modules/Compiler/IntelLLVM-CXX.cmake69
-rw-r--r--Modules/Compiler/IntelLLVM-DetermineCompiler.cmake41
-rw-r--r--Modules/Compiler/IntelLLVM-Fortran.cmake27
-rw-r--r--Modules/Compiler/IntelLLVM.cmake92
-rw-r--r--Modules/Compiler/MSVC-ASM.cmake1
-rw-r--r--Modules/Compiler/MSVC-C-FeatureTests.cmake7
-rw-r--r--Modules/Compiler/MSVC-C.cmake65
-rw-r--r--Modules/Compiler/MSVC-CXX-FeatureTests.cmake109
-rw-r--r--Modules/Compiler/MSVC-CXX.cmake74
-rw-r--r--Modules/Compiler/MSVC-DetermineCompiler.cmake19
-rw-r--r--Modules/Compiler/NAG-Fortran.cmake41
-rw-r--r--Modules/Compiler/NVHPC-C.cmake3
-rw-r--r--Modules/Compiler/NVHPC-CXX.cmake3
-rw-r--r--Modules/Compiler/NVHPC-DetermineCompiler.cmake9
-rw-r--r--Modules/Compiler/NVHPC-Fortran.cmake3
-rw-r--r--Modules/Compiler/NVHPC.cmake15
-rw-r--r--Modules/Compiler/NVIDIA-CUDA.cmake144
-rw-r--r--Modules/Compiler/NVIDIA-DetermineCompiler.cmake29
-rw-r--r--Modules/Compiler/OpenWatcom-C.cmake1
-rw-r--r--Modules/Compiler/OpenWatcom-CXX.cmake1
-rw-r--r--Modules/Compiler/OpenWatcom-DetermineCompiler.cmake10
-rw-r--r--Modules/Compiler/OpenWatcom.cmake118
-rw-r--r--Modules/Compiler/PGI-C.cmake20
-rw-r--r--Modules/Compiler/PGI-CXX.cmake28
-rw-r--r--Modules/Compiler/PGI-DetermineCompiler.cmake9
-rw-r--r--Modules/Compiler/PGI-Fortran.cmake16
-rw-r--r--Modules/Compiler/PGI.cmake42
-rw-r--r--Modules/Compiler/PathScale-C.cmake4
-rw-r--r--Modules/Compiler/PathScale-CXX.cmake4
-rw-r--r--Modules/Compiler/PathScale-DetermineCompiler.cmake9
-rw-r--r--Modules/Compiler/PathScale-Fortran.cmake9
-rw-r--r--Modules/Compiler/PathScale.cmake21
-rw-r--r--Modules/Compiler/QCC-ASM.cmake2
-rw-r--r--Modules/Compiler/QCC-C-FeatureTests.cmake1
-rw-r--r--Modules/Compiler/QCC-C.cmake5
-rw-r--r--Modules/Compiler/QCC-CXX-FeatureTests.cmake1
-rw-r--r--Modules/Compiler/QCC-CXX.cmake15
-rw-r--r--Modules/Compiler/QCC.cmake37
-rw-r--r--Modules/Compiler/SCO-C.cmake2
-rw-r--r--Modules/Compiler/SCO-CXX.cmake2
-rw-r--r--Modules/Compiler/SCO-DetermineCompiler.cmake2
-rw-r--r--Modules/Compiler/SCO.cmake21
-rw-r--r--Modules/Compiler/SDCC-C-DetermineCompiler.cmake16
-rw-r--r--Modules/Compiler/SunPro-ASM.cmake24
-rw-r--r--Modules/Compiler/SunPro-C-DetermineCompiler.cmake15
-rw-r--r--Modules/Compiler/SunPro-C-FeatureTests.cmake14
-rw-r--r--Modules/Compiler/SunPro-C.cmake59
-rw-r--r--Modules/Compiler/SunPro-CXX-DetermineCompiler.cmake15
-rw-r--r--Modules/Compiler/SunPro-CXX-FeatureTests.cmake68
-rw-r--r--Modules/Compiler/SunPro-CXX.cmake66
-rw-r--r--Modules/Compiler/SunPro-Fortran.cmake34
-rw-r--r--Modules/Compiler/SunPro.cmake10
-rw-r--r--Modules/Compiler/TI-ASM.cmake4
-rw-r--r--Modules/Compiler/TI-C.cmake67
-rw-r--r--Modules/Compiler/TI-CXX.cmake71
-rw-r--r--Modules/Compiler/TI-DetermineCompiler.cmake8
-rw-r--r--Modules/Compiler/TI.cmake41
-rw-r--r--Modules/Compiler/TinyCC-C-DetermineCompiler.cmake2
-rw-r--r--Modules/Compiler/TinyCC-C.cmake11
-rw-r--r--Modules/Compiler/VisualAge-C-DetermineCompiler.cmake4
-rw-r--r--Modules/Compiler/VisualAge-C.cmake1
-rw-r--r--Modules/Compiler/VisualAge-CXX-DetermineCompiler.cmake4
-rw-r--r--Modules/Compiler/VisualAge-CXX.cmake1
-rw-r--r--Modules/Compiler/VisualAge-Fortran.cmake1
-rw-r--r--Modules/Compiler/Watcom-DetermineCompiler.cmake10
-rw-r--r--Modules/Compiler/XL-ASM.cmake12
-rw-r--r--Modules/Compiler/XL-C-DetermineCompiler.cmake4
-rw-r--r--Modules/Compiler/XL-C.cmake23
-rw-r--r--Modules/Compiler/XL-CXX-DetermineCompiler.cmake4
-rw-r--r--Modules/Compiler/XL-CXX.cmake37
-rw-r--r--Modules/Compiler/XL-Fortran.cmake30
-rwxr-xr-xModules/Compiler/XL-Fortran/cpp29
-rw-r--r--Modules/Compiler/XL.cmake34
-rw-r--r--Modules/Compiler/XLClang-C-DetermineCompiler.cmake8
-rw-r--r--Modules/Compiler/XLClang-C.cmake22
-rw-r--r--Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake8
-rw-r--r--Modules/Compiler/XLClang-CXX.cmake29
-rw-r--r--Modules/Compiler/XLClang.cmake22
-rw-r--r--Modules/Compiler/zOS-C-DetermineCompiler.cmake4
-rw-r--r--Modules/Compiler/zOS-CXX-DetermineCompiler.cmake4
-rw-r--r--Modules/CompilerId/GHS_default.gpj.in8
-rw-r--r--Modules/CompilerId/GHS_lib.gpj.in3
-rw-r--r--Modules/CompilerId/VS-10.csproj.in55
-rw-r--r--Modules/CompilerId/VS-10.vcxproj.in71
-rw-r--r--Modules/CompilerId/VS-7.vcproj.in60
-rw-r--r--Modules/CompilerId/VS-Intel.vfproj.in42
-rw-r--r--Modules/CompilerId/VS-NsightTegra.vcxproj.in56
-rw-r--r--Modules/CompilerId/Xcode-3.pbxproj.in114
-rw-r--r--Modules/CompilerId/main.swift.in1
-rw-r--r--Modules/Dart.cmake125
-rw-r--r--Modules/DartConfiguration.tcl.in105
-rw-r--r--Modules/DeployQt4.cmake399
-rw-r--r--Modules/Documentation.cmake77
-rw-r--r--Modules/DummyCXXFile.cxx4
-rw-r--r--Modules/ExternalData.cmake1212
-rw-r--r--Modules/ExternalData_config.cmake.in6
-rw-r--r--Modules/ExternalProject-download.cmake.in173
-rw-r--r--Modules/ExternalProject-gitupdate.cmake.in277
-rw-r--r--Modules/ExternalProject-verify.cmake.in37
-rw-r--r--Modules/ExternalProject.cmake3694
-rw-r--r--Modules/FLTKCompatibility.cmake5
-rw-r--r--Modules/FeatureSummary.cmake749
-rw-r--r--Modules/FetchContent.cmake1218
-rw-r--r--Modules/FetchContent/CMakeLists.cmake.in27
-rw-r--r--Modules/FindALSA.cmake76
-rw-r--r--Modules/FindASPELL.cmake32
-rw-r--r--Modules/FindAVIFile.cmake38
-rw-r--r--Modules/FindArmadillo.cmake135
-rw-r--r--Modules/FindBISON.cmake307
-rw-r--r--Modules/FindBLAS.cmake1092
-rw-r--r--Modules/FindBZip2.cmake107
-rw-r--r--Modules/FindBacktrace.cmake91
-rw-r--r--Modules/FindBoost.cmake2557
-rw-r--r--Modules/FindBullet.cmake93
-rw-r--r--Modules/FindCABLE.cmake82
-rw-r--r--Modules/FindCUDA.cmake2172
-rw-r--r--Modules/FindCUDA/make2cmake.cmake106
-rw-r--r--Modules/FindCUDA/parse_cubin.cmake111
-rw-r--r--Modules/FindCUDA/run_nvcc.cmake306
-rw-r--r--Modules/FindCUDA/select_compute_arch.cmake298
-rw-r--r--Modules/FindCUDAToolkit.cmake949
-rw-r--r--Modules/FindCURL.cmake215
-rw-r--r--Modules/FindCVS.cmake73
-rw-r--r--Modules/FindCoin3D.cmake77
-rw-r--r--Modules/FindCups.cmake100
-rw-r--r--Modules/FindCurses.cmake276
-rw-r--r--Modules/FindCxxTest.cmake247
-rw-r--r--Modules/FindCygwin.cmake28
-rw-r--r--Modules/FindDCMTK.cmake322
-rw-r--r--Modules/FindDart.cmake33
-rw-r--r--Modules/FindDevIL.cmake139
-rw-r--r--Modules/FindDoxygen.cmake1177
-rw-r--r--Modules/FindEXPAT.cmake83
-rw-r--r--Modules/FindEnvModules.cmake335
-rw-r--r--Modules/FindFLEX.cmake265
-rw-r--r--Modules/FindFLTK.cmake340
-rw-r--r--Modules/FindFLTK2.cmake245
-rw-r--r--Modules/FindFontconfig.cmake103
-rw-r--r--Modules/FindFreetype.cmake204
-rw-r--r--Modules/FindGCCXML.cmake27
-rw-r--r--Modules/FindGDAL.cmake199
-rw-r--r--Modules/FindGIF.cmake128
-rw-r--r--Modules/FindGLEW.cmake350
-rw-r--r--Modules/FindGLU.cmake17
-rw-r--r--Modules/FindGLUT.cmake206
-rw-r--r--Modules/FindGSL.cmake231
-rw-r--r--Modules/FindGTK.cmake153
-rw-r--r--Modules/FindGTK2.cmake969
-rw-r--r--Modules/FindGTest.cmake294
-rw-r--r--Modules/FindGettext.cmake232
-rw-r--r--Modules/FindGit.cmake130
-rw-r--r--Modules/FindGnuTLS.cmake84
-rw-r--r--Modules/FindGnuplot.cmake55
-rw-r--r--Modules/FindHDF5.cmake1183
-rw-r--r--Modules/FindHSPELL.cmake45
-rw-r--r--Modules/FindHTMLHelp.cmake52
-rw-r--r--Modules/FindHg.cmake98
-rw-r--r--Modules/FindICU.cmake438
-rw-r--r--Modules/FindIce.cmake633
-rw-r--r--Modules/FindIconv.cmake178
-rw-r--r--Modules/FindIcotool.cmake52
-rw-r--r--Modules/FindImageMagick.cmake310
-rw-r--r--Modules/FindIntl.cmake181
-rw-r--r--Modules/FindJNI.cmake405
-rw-r--r--Modules/FindJPEG.cmake142
-rw-r--r--Modules/FindJasper.cmake47
-rw-r--r--Modules/FindJava.cmake364
-rw-r--r--Modules/FindKDE3.cmake360
-rw-r--r--Modules/FindKDE4.cmake103
-rw-r--r--Modules/FindLAPACK.cmake682
-rw-r--r--Modules/FindLATEX.cmake283
-rw-r--r--Modules/FindLTTngUST.cmake102
-rw-r--r--Modules/FindLibArchive.cmake80
-rw-r--r--Modules/FindLibLZMA.cmake126
-rw-r--r--Modules/FindLibXml2.cmake124
-rw-r--r--Modules/FindLibXslt.cmake134
-rw-r--r--Modules/FindLibinput.cmake84
-rw-r--r--Modules/FindLua.cmake239
-rw-r--r--Modules/FindLua50.cmake90
-rw-r--r--Modules/FindLua51.cmake84
-rw-r--r--Modules/FindMFC.cmake71
-rw-r--r--Modules/FindMPEG.cmake43
-rw-r--r--Modules/FindMPEG2.cmake50
-rw-r--r--Modules/FindMPI.cmake1817
-rw-r--r--Modules/FindMPI/fortranparam_mpi.f90.in4
-rw-r--r--Modules/FindMPI/libver_mpi.c20
-rw-r--r--Modules/FindMPI/libver_mpi.f90.in7
-rw-r--r--Modules/FindMPI/mpiver.f90.in10
-rw-r--r--Modules/FindMPI/test_mpi.c38
-rw-r--r--Modules/FindMPI/test_mpi.f90.in6
-rw-r--r--Modules/FindMatlab.cmake1899
-rw-r--r--Modules/FindMotif.cmake40
-rw-r--r--Modules/FindODBC.cmake233
-rw-r--r--Modules/FindOpenACC.cmake296
-rw-r--r--Modules/FindOpenAL.cmake96
-rw-r--r--Modules/FindOpenCL.cmake185
-rw-r--r--Modules/FindOpenGL.cmake583
-rw-r--r--Modules/FindOpenMP.cmake620
-rw-r--r--Modules/FindOpenSSL.cmake675
-rw-r--r--Modules/FindOpenSceneGraph.cmake232
-rw-r--r--Modules/FindOpenThreads.cmake103
-rw-r--r--Modules/FindPHP4.cmake82
-rw-r--r--Modules/FindPNG.cmake161
-rw-r--r--Modules/FindPackageHandleStandardArgs.cmake605
-rw-r--r--Modules/FindPackageMessage.cmake48
-rw-r--r--Modules/FindPatch.cmake71
-rw-r--r--Modules/FindPerl.cmake87
-rw-r--r--Modules/FindPerlLibs.cmake162
-rw-r--r--Modules/FindPhysFS.cmake42
-rw-r--r--Modules/FindPike.cmake31
-rw-r--r--Modules/FindPkgConfig.cmake917
-rw-r--r--Modules/FindPostgreSQL.cmake312
-rw-r--r--Modules/FindProducer.cmake66
-rw-r--r--Modules/FindProtobuf.cmake681
-rw-r--r--Modules/FindPython.cmake581
-rw-r--r--Modules/FindPython/Support.cmake3369
-rw-r--r--Modules/FindPython2.cmake430
-rw-r--r--Modules/FindPython3.cmake493
-rw-r--r--Modules/FindPythonInterp.cmake171
-rw-r--r--Modules/FindPythonLibs.cmake399
-rw-r--r--Modules/FindQt.cmake188
-rw-r--r--Modules/FindQt3.cmake306
-rw-r--r--Modules/FindQt4.cmake1346
-rw-r--r--Modules/FindQuickTime.cmake34
-rw-r--r--Modules/FindRTI.cmake102
-rw-r--r--Modules/FindRuby.cmake533
-rw-r--r--Modules/FindSDL.cmake237
-rw-r--r--Modules/FindSDL_image.cmake101
-rw-r--r--Modules/FindSDL_mixer.cmake101
-rw-r--r--Modules/FindSDL_net.cmake100
-rw-r--r--Modules/FindSDL_sound.cmake370
-rw-r--r--Modules/FindSDL_ttf.cmake100
-rw-r--r--Modules/FindSQLite3.cmake68
-rw-r--r--Modules/FindSWIG.cmake147
-rw-r--r--Modules/FindSelfPackers.cmake58
-rw-r--r--Modules/FindSquish.cmake289
-rw-r--r--Modules/FindSubversion.cmake169
-rw-r--r--Modules/FindTCL.cmake247
-rw-r--r--Modules/FindTIFF.cmake200
-rw-r--r--Modules/FindTclStub.cmake143
-rw-r--r--Modules/FindTclsh.cmake101
-rw-r--r--Modules/FindThreads.cmake258
-rw-r--r--Modules/FindUnixCommands.cmake71
-rw-r--r--Modules/FindVulkan.cmake115
-rw-r--r--Modules/FindWget.cmake32
-rw-r--r--Modules/FindWish.cmake85
-rw-r--r--Modules/FindX11.cmake898
-rw-r--r--Modules/FindXCTest.cmake222
-rw-r--r--Modules/FindXMLRPC.cmake129
-rw-r--r--Modules/FindXalanC.cmake155
-rw-r--r--Modules/FindXercesC.cmake149
-rw-r--r--Modules/FindZLIB.cmake154
-rw-r--r--Modules/Findosg.cmake49
-rw-r--r--Modules/FindosgAnimation.cmake46
-rw-r--r--Modules/FindosgDB.cmake54
-rw-r--r--Modules/FindosgFX.cmake46
-rw-r--r--Modules/FindosgGA.cmake46
-rw-r--r--Modules/FindosgIntrospection.cmake47
-rw-r--r--Modules/FindosgManipulator.cmake47
-rw-r--r--Modules/FindosgParticle.cmake46
-rw-r--r--Modules/FindosgPresentation.cmake48
-rw-r--r--Modules/FindosgProducer.cmake46
-rw-r--r--Modules/FindosgQt.cmake46
-rw-r--r--Modules/FindosgShadow.cmake46
-rw-r--r--Modules/FindosgSim.cmake46
-rw-r--r--Modules/FindosgTerrain.cmake46
-rw-r--r--Modules/FindosgText.cmake46
-rw-r--r--Modules/FindosgUtil.cmake46
-rw-r--r--Modules/FindosgViewer.cmake46
-rw-r--r--Modules/FindosgVolume.cmake46
-rw-r--r--Modules/FindosgWidget.cmake47
-rw-r--r--Modules/Findosg_functions.cmake86
-rw-r--r--Modules/FindwxWidgets.cmake1243
-rw-r--r--Modules/FindwxWindows.cmake730
-rw-r--r--Modules/FortranCInterface.cmake400
-rw-r--r--Modules/FortranCInterface/CMakeLists.txt107
-rw-r--r--Modules/FortranCInterface/Detect.cmake187
-rw-r--r--Modules/FortranCInterface/Input.cmake.in3
-rw-r--r--Modules/FortranCInterface/MYMODULE.c3
-rw-r--r--Modules/FortranCInterface/MY_MODULE.c3
-rw-r--r--Modules/FortranCInterface/Macro.h.in4
-rw-r--r--Modules/FortranCInterface/Output.cmake.in33
-rw-r--r--Modules/FortranCInterface/Verify/CMakeLists.txt26
-rw-r--r--Modules/FortranCInterface/Verify/VerifyC.c5
-rw-r--r--Modules/FortranCInterface/Verify/VerifyCXX.cxx4
-rw-r--r--Modules/FortranCInterface/Verify/VerifyFortran.f3
-rw-r--r--Modules/FortranCInterface/Verify/main.c16
-rw-r--r--Modules/FortranCInterface/call_mod.f906
-rw-r--r--Modules/FortranCInterface/call_sub.f4
-rw-r--r--Modules/FortranCInterface/main.F6
-rw-r--r--Modules/FortranCInterface/my_module.f908
-rw-r--r--Modules/FortranCInterface/my_module_.c3
-rw-r--r--Modules/FortranCInterface/my_sub.f2
-rw-r--r--Modules/FortranCInterface/mymodule.f908
-rw-r--r--Modules/FortranCInterface/mymodule_.c3
-rw-r--r--Modules/FortranCInterface/mysub.f2
-rw-r--r--Modules/FortranCInterface/symbol.c.in4
-rw-r--r--Modules/GNUInstallDirs.cmake423
-rw-r--r--Modules/GenerateExportHeader.cmake455
-rw-r--r--Modules/GetPrerequisites.cmake1048
-rw-r--r--Modules/GoogleTest.cmake560
-rw-r--r--Modules/GoogleTestAddTests.cmake188
-rw-r--r--Modules/ITKCompatibility.cmake7
-rw-r--r--Modules/InstallRequiredSystemLibraries.cmake784
-rw-r--r--Modules/IntelVSImplicitPath/CMakeLists.txt7
-rw-r--r--Modules/IntelVSImplicitPath/detect.cmake9
-rw-r--r--Modules/IntelVSImplicitPath/hello.f0
-rw-r--r--Modules/Internal/CMakeTryCompilerOrLinkerFlag.cmake158
-rw-r--r--Modules/Internal/CPack/CPack.DS_Store.inbin0 -> 12292 bytes-rw-r--r--Modules/Internal/CPack/CPack.Description.plist.in12
-rw-r--r--Modules/Internal/CPack/CPack.Info.plist.in37
-rw-r--r--Modules/Internal/CPack/CPack.NuGet.nuspec.in27
-rw-r--r--Modules/Internal/CPack/CPack.OSXScriptLauncher.inbin0 -> 29592 bytes-rw-r--r--Modules/Internal/CPack/CPack.OSXScriptLauncher.rsrc.inbin0 -> 362 bytes-rw-r--r--Modules/Internal/CPack/CPack.OSXX11.Info.plist.in47
-rw-r--r--Modules/Internal/CPack/CPack.OSXX11.main.scpt.inbin0 -> 1870 bytes-rwxr-xr-xModules/Internal/CPack/CPack.RuntimeScript.in87
-rwxr-xr-xModules/Internal/CPack/CPack.STGZ_Header.sh.in149
-rw-r--r--Modules/Internal/CPack/CPack.VolumeIcon.icns.inbin0 -> 45739 bytes-rw-r--r--Modules/Internal/CPack/CPack.background.png.inbin0 -> 44108 bytes-rw-r--r--Modules/Internal/CPack/CPack.distribution.dist.in9
-rw-r--r--Modules/Internal/CPack/CPackDeb.cmake793
-rw-r--r--Modules/Internal/CPack/CPackExternal.cmake53
-rw-r--r--Modules/Internal/CPack/CPackFreeBSD.cmake107
-rw-r--r--Modules/Internal/CPack/CPackNuGet.cmake440
-rw-r--r--Modules/Internal/CPack/CPackRPM.cmake1945
-rw-r--r--Modules/Internal/CPack/CPackWIX.cmake20
-rw-r--r--Modules/Internal/CPack/CPackZIP.cmake30
-rw-r--r--Modules/Internal/CPack/NSIS.InstallOptions.ini.in46
-rw-r--r--Modules/Internal/CPack/NSIS.template.in980
-rw-r--r--Modules/Internal/CPack/WIX.template.in47
-rw-r--r--Modules/Internal/CheckCompilerFlag.cmake79
-rw-r--r--Modules/Internal/CheckSourceCompiles.cmake127
-rw-r--r--Modules/Internal/CheckSourceRuns.cmake142
-rw-r--r--Modules/Internal/FeatureTesting.cmake119
-rw-r--r--Modules/KDE3Macros.cmake400
-rw-r--r--Modules/MacOSXBundleInfo.plist.in34
-rw-r--r--Modules/MacOSXFrameworkInfo.plist.in26
-rw-r--r--Modules/MacroAddFileDependencies.cmake29
-rw-r--r--Modules/MatlabTestsRedirect.cmake106
-rw-r--r--Modules/Platform/AIX-Clang-C.cmake1
-rw-r--r--Modules/Platform/AIX-Clang-CXX.cmake1
-rw-r--r--Modules/Platform/AIX-GNU-ASM.cmake2
-rw-r--r--Modules/Platform/AIX-GNU-C.cmake2
-rw-r--r--Modules/Platform/AIX-GNU-CXX.cmake3
-rw-r--r--Modules/Platform/AIX-GNU-Fortran.cmake2
-rw-r--r--Modules/Platform/AIX-GNU.cmake33
-rw-r--r--Modules/Platform/AIX-VisualAge-C.cmake1
-rw-r--r--Modules/Platform/AIX-VisualAge-CXX.cmake1
-rw-r--r--Modules/Platform/AIX-VisualAge-Fortran.cmake1
-rw-r--r--Modules/Platform/AIX-XL-ASM.cmake2
-rw-r--r--Modules/Platform/AIX-XL-C.cmake5
-rw-r--r--Modules/Platform/AIX-XL-CXX.cmake5
-rw-r--r--Modules/Platform/AIX-XL-Fortran.cmake2
-rw-r--r--Modules/Platform/AIX-XL.cmake41
-rw-r--r--Modules/Platform/AIX-XLClang-C.cmake2
-rw-r--r--Modules/Platform/AIX-XLClang-CXX.cmake2
-rw-r--r--Modules/Platform/AIX-XLClang.cmake15
-rw-r--r--Modules/Platform/AIX.cmake33
-rwxr-xr-xModules/Platform/AIX/ExportImportList60
-rw-r--r--Modules/Platform/ARTOS-GNU-C.cmake9
-rw-r--r--Modules/Platform/ARTOS.cmake17
-rw-r--r--Modules/Platform/Android-Clang-ASM.cmake2
-rw-r--r--Modules/Platform/Android-Clang-C.cmake2
-rw-r--r--Modules/Platform/Android-Clang-CXX.cmake9
-rw-r--r--Modules/Platform/Android-Clang.cmake91
-rw-r--r--Modules/Platform/Android-Common.cmake230
-rw-r--r--Modules/Platform/Android-Determine-C.cmake2
-rw-r--r--Modules/Platform/Android-Determine-CXX.cmake2
-rw-r--r--Modules/Platform/Android-Determine.cmake607
-rw-r--r--Modules/Platform/Android-GNU-C.cmake2
-rw-r--r--Modules/Platform/Android-GNU-CXX.cmake5
-rw-r--r--Modules/Platform/Android-GNU.cmake33
-rw-r--r--Modules/Platform/Android-Initialize.cmake117
-rw-r--r--Modules/Platform/Android.cmake42
-rw-r--r--Modules/Platform/Android/Determine-Compiler-NDK.cmake271
-rw-r--r--Modules/Platform/Android/Determine-Compiler-Standalone.cmake65
-rw-r--r--Modules/Platform/Android/Determine-Compiler.cmake97
-rw-r--r--Modules/Platform/Android/VCXProjInspect.vcxproj.in38
-rw-r--r--Modules/Platform/Android/abi-arm64-v8a-Clang.cmake4
-rw-r--r--Modules/Platform/Android/abi-arm64-v8a-GNU.cmake6
-rw-r--r--Modules/Platform/Android/abi-armeabi-Clang.cmake16
-rw-r--r--Modules/Platform/Android/abi-armeabi-GNU.cmake17
-rw-r--r--Modules/Platform/Android/abi-armeabi-v6-Clang.cmake15
-rw-r--r--Modules/Platform/Android/abi-armeabi-v6-GNU.cmake16
-rw-r--r--Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake25
-rw-r--r--Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake26
-rw-r--r--Modules/Platform/Android/abi-common-Clang.cmake6
-rw-r--r--Modules/Platform/Android/abi-common-GNU.cmake1
-rw-r--r--Modules/Platform/Android/abi-common.cmake39
-rw-r--r--Modules/Platform/Android/abi-mips-Clang.cmake1
-rw-r--r--Modules/Platform/Android/abi-mips-GNU.cmake3
-rw-r--r--Modules/Platform/Android/abi-mips64-Clang.cmake1
-rw-r--r--Modules/Platform/Android/abi-mips64-GNU.cmake3
-rw-r--r--Modules/Platform/Android/abi-x86-Clang.cmake1
-rw-r--r--Modules/Platform/Android/abi-x86-GNU.cmake2
-rw-r--r--Modules/Platform/Android/abi-x86_64-Clang.cmake1
-rw-r--r--Modules/Platform/Android/abi-x86_64-GNU.cmake2
-rw-r--r--Modules/Platform/Android/ndk-stl-c++.cmake21
-rw-r--r--Modules/Platform/Android/ndk-stl-c++_shared.cmake5
-rw-r--r--Modules/Platform/Android/ndk-stl-c++_static.cmake8
-rw-r--r--Modules/Platform/Android/ndk-stl-gabi++.cmake8
-rw-r--r--Modules/Platform/Android/ndk-stl-gabi++_shared.cmake4
-rw-r--r--Modules/Platform/Android/ndk-stl-gabi++_static.cmake4
-rw-r--r--Modules/Platform/Android/ndk-stl-gnustl.cmake10
-rw-r--r--Modules/Platform/Android/ndk-stl-gnustl_shared.cmake4
-rw-r--r--Modules/Platform/Android/ndk-stl-gnustl_static.cmake4
-rw-r--r--Modules/Platform/Android/ndk-stl-none.cmake3
-rw-r--r--Modules/Platform/Android/ndk-stl-stlport.cmake8
-rw-r--r--Modules/Platform/Android/ndk-stl-stlport_shared.cmake4
-rw-r--r--Modules/Platform/Android/ndk-stl-stlport_static.cmake4
-rw-r--r--Modules/Platform/Android/ndk-stl-system.cmake7
-rw-r--r--Modules/Platform/Apple-Absoft-Fortran.cmake7
-rw-r--r--Modules/Platform/Apple-Apple-Swift.cmake1
-rw-r--r--Modules/Platform/Apple-AppleClang-C.cmake6
-rw-r--r--Modules/Platform/Apple-AppleClang-CXX.cmake6
-rw-r--r--Modules/Platform/Apple-AppleClang-OBJC.cmake6
-rw-r--r--Modules/Platform/Apple-AppleClang-OBJCXX.cmake6
-rw-r--r--Modules/Platform/Apple-Clang-ASM.cmake2
-rw-r--r--Modules/Platform/Apple-Clang-C.cmake2
-rw-r--r--Modules/Platform/Apple-Clang-CXX.cmake2
-rw-r--r--Modules/Platform/Apple-Clang-OBJC.cmake2
-rw-r--r--Modules/Platform/Apple-Clang-OBJCXX.cmake2
-rw-r--r--Modules/Platform/Apple-Clang.cmake32
-rw-r--r--Modules/Platform/Apple-GNU-C.cmake4
-rw-r--r--Modules/Platform/Apple-GNU-CXX.cmake4
-rw-r--r--Modules/Platform/Apple-GNU-Fortran.cmake10
-rw-r--r--Modules/Platform/Apple-GNU-OBJC.cmake4
-rw-r--r--Modules/Platform/Apple-GNU-OBJCXX.cmake4
-rw-r--r--Modules/Platform/Apple-GNU.cmake57
-rw-r--r--Modules/Platform/Apple-Intel-C.cmake2
-rw-r--r--Modules/Platform/Apple-Intel-CXX.cmake2
-rw-r--r--Modules/Platform/Apple-Intel-Fortran.cmake8
-rw-r--r--Modules/Platform/Apple-Intel.cmake19
-rw-r--r--Modules/Platform/Apple-IntelLLVM-C.cmake2
-rw-r--r--Modules/Platform/Apple-IntelLLVM-CXX.cmake2
-rw-r--r--Modules/Platform/Apple-IntelLLVM-Fortran.cmake8
-rw-r--r--Modules/Platform/Apple-IntelLLVM.cmake17
-rw-r--r--Modules/Platform/Apple-NAG-Fortran.cmake15
-rw-r--r--Modules/Platform/Apple-NVIDIA-CUDA.cmake19
-rw-r--r--Modules/Platform/Apple-PGI-C.cmake2
-rw-r--r--Modules/Platform/Apple-PGI-CXX.cmake2
-rw-r--r--Modules/Platform/Apple-PGI-Fortran.cmake2
-rw-r--r--Modules/Platform/Apple-PGI.cmake11
-rw-r--r--Modules/Platform/Apple-VisualAge-C.cmake1
-rw-r--r--Modules/Platform/Apple-VisualAge-CXX.cmake1
-rw-r--r--Modules/Platform/Apple-XL-C.cmake7
-rw-r--r--Modules/Platform/Apple-XL-CXX.cmake7
-rw-r--r--Modules/Platform/BSDOS.cmake2
-rw-r--r--Modules/Platform/BeOS.cmake12
-rw-r--r--Modules/Platform/BlueGeneL.cmake40
-rw-r--r--Modules/Platform/BlueGeneP-base.cmake114
-rw-r--r--Modules/Platform/BlueGeneP-dynamic-GNU-C.cmake5
-rw-r--r--Modules/Platform/BlueGeneP-dynamic-GNU-CXX.cmake5
-rw-r--r--Modules/Platform/BlueGeneP-dynamic-GNU-Fortran.cmake5
-rw-r--r--Modules/Platform/BlueGeneP-dynamic-XL-C.cmake8
-rw-r--r--Modules/Platform/BlueGeneP-dynamic-XL-CXX.cmake8
-rw-r--r--Modules/Platform/BlueGeneP-dynamic-XL-Fortran.cmake5
-rw-r--r--Modules/Platform/BlueGeneP-dynamic.cmake8
-rw-r--r--Modules/Platform/BlueGeneP-static-GNU-C.cmake5
-rw-r--r--Modules/Platform/BlueGeneP-static-GNU-CXX.cmake5
-rw-r--r--Modules/Platform/BlueGeneP-static-GNU-Fortran.cmake5
-rw-r--r--Modules/Platform/BlueGeneP-static-XL-C.cmake8
-rw-r--r--Modules/Platform/BlueGeneP-static-XL-CXX.cmake8
-rw-r--r--Modules/Platform/BlueGeneP-static-XL-Fortran.cmake5
-rw-r--r--Modules/Platform/BlueGeneP-static.cmake8
-rw-r--r--Modules/Platform/BlueGeneQ-base.cmake166
-rw-r--r--Modules/Platform/BlueGeneQ-dynamic-GNU-C.cmake5
-rw-r--r--Modules/Platform/BlueGeneQ-dynamic-GNU-CXX.cmake5
-rw-r--r--Modules/Platform/BlueGeneQ-dynamic-GNU-Fortran.cmake5
-rw-r--r--Modules/Platform/BlueGeneQ-dynamic-XL-C.cmake8
-rw-r--r--Modules/Platform/BlueGeneQ-dynamic-XL-CXX.cmake8
-rw-r--r--Modules/Platform/BlueGeneQ-dynamic-XL-Fortran.cmake5
-rw-r--r--Modules/Platform/BlueGeneQ-dynamic.cmake6
-rw-r--r--Modules/Platform/BlueGeneQ-static-GNU-C.cmake5
-rw-r--r--Modules/Platform/BlueGeneQ-static-GNU-CXX.cmake5
-rw-r--r--Modules/Platform/BlueGeneQ-static-GNU-Fortran.cmake5
-rw-r--r--Modules/Platform/BlueGeneQ-static-XL-C.cmake8
-rw-r--r--Modules/Platform/BlueGeneQ-static-XL-CXX.cmake8
-rw-r--r--Modules/Platform/BlueGeneQ-static-XL-Fortran.cmake5
-rw-r--r--Modules/Platform/BlueGeneQ-static.cmake6
-rw-r--r--Modules/Platform/CYGWIN-Clang-C.cmake1
-rw-r--r--Modules/Platform/CYGWIN-Clang-CXX.cmake1
-rw-r--r--Modules/Platform/CYGWIN-Determine-CXX.cmake7
-rw-r--r--Modules/Platform/CYGWIN-GNU-C.cmake2
-rw-r--r--Modules/Platform/CYGWIN-GNU-CXX.cmake2
-rw-r--r--Modules/Platform/CYGWIN-GNU-Fortran.cmake2
-rw-r--r--Modules/Platform/CYGWIN-GNU.cmake54
-rw-r--r--Modules/Platform/CYGWIN-windres.cmake1
-rw-r--r--Modules/Platform/CYGWIN.cmake74
-rw-r--r--Modules/Platform/Catamount.cmake26
-rw-r--r--Modules/Platform/CrayLinuxEnvironment.cmake87
-rw-r--r--Modules/Platform/DOS-OpenWatcom-C.cmake1
-rw-r--r--Modules/Platform/DOS-OpenWatcom-CXX.cmake1
-rw-r--r--Modules/Platform/DOS-OpenWatcom.cmake28
-rw-r--r--Modules/Platform/DOS.cmake14
-rw-r--r--Modules/Platform/Darwin-Determine-CXX.cmake7
-rw-r--r--Modules/Platform/Darwin-Initialize.cmake318
-rw-r--r--Modules/Platform/Darwin.cmake239
-rw-r--r--Modules/Platform/DragonFly.cmake9
-rw-r--r--Modules/Platform/Euros.cmake19
-rw-r--r--Modules/Platform/FreeBSD-Determine-CXX.cmake3
-rw-r--r--Modules/Platform/FreeBSD.cmake29
-rw-r--r--Modules/Platform/Fuchsia.cmake28
-rw-r--r--Modules/Platform/GHS-MULTI-Determine.cmake56
-rw-r--r--Modules/Platform/GHS-MULTI.cmake17
-rw-r--r--Modules/Platform/GNU.cmake40
-rw-r--r--Modules/Platform/GNUtoMS_lib.bat.in4
-rw-r--r--Modules/Platform/GNUtoMS_lib.cmake10
-rw-r--r--Modules/Platform/Generic-ADSP-ASM.cmake7
-rw-r--r--Modules/Platform/Generic-ADSP-C.cmake22
-rw-r--r--Modules/Platform/Generic-ADSP-CXX.cmake20
-rw-r--r--Modules/Platform/Generic-ADSP-Common.cmake120
-rw-r--r--Modules/Platform/Generic-SDCC-C.cmake58
-rw-r--r--Modules/Platform/Generic.cmake17
-rw-r--r--Modules/Platform/HP-UX-GNU-ASM.cmake2
-rw-r--r--Modules/Platform/HP-UX-GNU-C.cmake2
-rw-r--r--Modules/Platform/HP-UX-GNU-CXX.cmake3
-rw-r--r--Modules/Platform/HP-UX-GNU-Fortran.cmake2
-rw-r--r--Modules/Platform/HP-UX-GNU.cmake20
-rw-r--r--Modules/Platform/HP-UX-HP-ASM.cmake2
-rw-r--r--Modules/Platform/HP-UX-HP-C.cmake6
-rw-r--r--Modules/Platform/HP-UX-HP-CXX.cmake14
-rw-r--r--Modules/Platform/HP-UX-HP-Fortran.cmake5
-rw-r--r--Modules/Platform/HP-UX-HP.cmake23
-rw-r--r--Modules/Platform/HP-UX.cmake47
-rw-r--r--Modules/Platform/Haiku.cmake131
-rw-r--r--Modules/Platform/Linux-Absoft-Fortran.cmake1
-rw-r--r--Modules/Platform/Linux-CCur-Fortran.cmake1
-rw-r--r--Modules/Platform/Linux-Clang-C.cmake1
-rw-r--r--Modules/Platform/Linux-Clang-CXX.cmake1
-rw-r--r--Modules/Platform/Linux-Determine-CXX.cmake3
-rw-r--r--Modules/Platform/Linux-Fujitsu-C.cmake1
-rw-r--r--Modules/Platform/Linux-Fujitsu-CXX.cmake1
-rw-r--r--Modules/Platform/Linux-Fujitsu.cmake17
-rw-r--r--Modules/Platform/Linux-GNU-C.cmake2
-rw-r--r--Modules/Platform/Linux-GNU-CXX.cmake2
-rw-r--r--Modules/Platform/Linux-GNU-Fortran.cmake3
-rw-r--r--Modules/Platform/Linux-GNU.cmake15
-rw-r--r--Modules/Platform/Linux-Intel-C.cmake3
-rw-r--r--Modules/Platform/Linux-Intel-CXX.cmake3
-rw-r--r--Modules/Platform/Linux-Intel-Fortran.cmake4
-rw-r--r--Modules/Platform/Linux-Intel.cmake59
-rw-r--r--Modules/Platform/Linux-IntelLLVM-C.cmake3
-rw-r--r--Modules/Platform/Linux-IntelLLVM-CXX.cmake3
-rw-r--r--Modules/Platform/Linux-IntelLLVM-Fortran.cmake4
-rw-r--r--Modules/Platform/Linux-IntelLLVM.cmake55
-rw-r--r--Modules/Platform/Linux-NAG-Fortran.cmake10
-rw-r--r--Modules/Platform/Linux-NVHPC-C.cmake2
-rw-r--r--Modules/Platform/Linux-NVHPC-CXX.cmake2
-rw-r--r--Modules/Platform/Linux-NVHPC-Fortran.cmake2
-rw-r--r--Modules/Platform/Linux-NVHPC.cmake15
-rw-r--r--Modules/Platform/Linux-OpenWatcom-C.cmake1
-rw-r--r--Modules/Platform/Linux-OpenWatcom-CXX.cmake1
-rw-r--r--Modules/Platform/Linux-OpenWatcom.cmake25
-rw-r--r--Modules/Platform/Linux-PGI-C.cmake2
-rw-r--r--Modules/Platform/Linux-PGI-CXX.cmake2
-rw-r--r--Modules/Platform/Linux-PGI-Fortran.cmake2
-rw-r--r--Modules/Platform/Linux-PGI.cmake21
-rw-r--r--Modules/Platform/Linux-PathScale-C.cmake2
-rw-r--r--Modules/Platform/Linux-PathScale-CXX.cmake2
-rw-r--r--Modules/Platform/Linux-PathScale-Fortran.cmake2
-rw-r--r--Modules/Platform/Linux-PathScale.cmake17
-rw-r--r--Modules/Platform/Linux-SunPro-CXX.cmake9
-rw-r--r--Modules/Platform/Linux-TinyCC-C.cmake5
-rw-r--r--Modules/Platform/Linux-VisualAge-C.cmake1
-rw-r--r--Modules/Platform/Linux-VisualAge-CXX.cmake1
-rw-r--r--Modules/Platform/Linux-VisualAge-Fortran.cmake1
-rw-r--r--Modules/Platform/Linux-XL-C.cmake1
-rw-r--r--Modules/Platform/Linux-XL-CXX.cmake1
-rw-r--r--Modules/Platform/Linux-XL-Fortran.cmake1
-rw-r--r--Modules/Platform/Linux-como.cmake17
-rw-r--r--Modules/Platform/Linux.cmake59
-rw-r--r--Modules/Platform/MP-RAS.cmake14
-rw-r--r--Modules/Platform/Midipix.cmake1
-rw-r--r--Modules/Platform/MirBSD.cmake1
-rw-r--r--Modules/Platform/NetBSD.cmake15
-rw-r--r--Modules/Platform/OS2-OpenWatcom-C.cmake1
-rw-r--r--Modules/Platform/OS2-OpenWatcom-CXX.cmake1
-rw-r--r--Modules/Platform/OS2-OpenWatcom.cmake35
-rw-r--r--Modules/Platform/OS2.cmake14
-rw-r--r--Modules/Platform/OSF1.cmake47
-rw-r--r--Modules/Platform/OpenBSD.cmake43
-rw-r--r--Modules/Platform/OpenVMS.cmake8
-rw-r--r--Modules/Platform/QNX.cmake19
-rw-r--r--Modules/Platform/RISCos.cmake6
-rw-r--r--Modules/Platform/SCO_SV.cmake3
-rw-r--r--Modules/Platform/SINIX.cmake7
-rw-r--r--Modules/Platform/SunOS-Clang-C.cmake1
-rw-r--r--Modules/Platform/SunOS-Clang-CXX.cmake1
-rw-r--r--Modules/Platform/SunOS-GNU-C.cmake2
-rw-r--r--Modules/Platform/SunOS-GNU-CXX.cmake2
-rw-r--r--Modules/Platform/SunOS-GNU-Fortran.cmake2
-rw-r--r--Modules/Platform/SunOS-GNU.cmake25
-rw-r--r--Modules/Platform/SunOS-PathScale-C.cmake2
-rw-r--r--Modules/Platform/SunOS-PathScale-CXX.cmake2
-rw-r--r--Modules/Platform/SunOS-PathScale-Fortran.cmake2
-rw-r--r--Modules/Platform/SunOS-PathScale.cmake21
-rw-r--r--Modules/Platform/SunOS.cmake23
-rw-r--r--Modules/Platform/Tru64.cmake2
-rw-r--r--Modules/Platform/ULTRIX.cmake5
-rw-r--r--Modules/Platform/UNIX_SV.cmake8
-rw-r--r--Modules/Platform/UnixPaths.cmake107
-rw-r--r--Modules/Platform/UnixWare.cmake8
-rw-r--r--Modules/Platform/Windows-Apple-Swift.cmake1
-rw-r--r--Modules/Platform/Windows-Borland-C.cmake1
-rw-r--r--Modules/Platform/Windows-Borland-CXX.cmake1
-rw-r--r--Modules/Platform/Windows-Clang-ASM.cmake2
-rw-r--r--Modules/Platform/Windows-Clang-C.cmake18
-rw-r--r--Modules/Platform/Windows-Clang-CXX.cmake19
-rw-r--r--Modules/Platform/Windows-Clang.cmake211
-rw-r--r--Modules/Platform/Windows-Determine-CXX.cmake7
-rw-r--r--Modules/Platform/Windows-Embarcadero-C.cmake3
-rw-r--r--Modules/Platform/Windows-Embarcadero-CXX.cmake3
-rw-r--r--Modules/Platform/Windows-Embarcadero.cmake139
-rw-r--r--Modules/Platform/Windows-Flang-Fortran.cmake8
-rw-r--r--Modules/Platform/Windows-G95-Fortran.cmake1
-rw-r--r--Modules/Platform/Windows-GNU-ASM.cmake2
-rw-r--r--Modules/Platform/Windows-GNU-C-ABI.cmake1
-rw-r--r--Modules/Platform/Windows-GNU-C.cmake2
-rw-r--r--Modules/Platform/Windows-GNU-CXX-ABI.cmake1
-rw-r--r--Modules/Platform/Windows-GNU-CXX.cmake2
-rw-r--r--Modules/Platform/Windows-GNU-Fortran-ABI.cmake1
-rw-r--r--Modules/Platform/Windows-GNU-Fortran.cmake5
-rw-r--r--Modules/Platform/Windows-GNU.cmake206
-rw-r--r--Modules/Platform/Windows-Intel-ASM.cmake2
-rw-r--r--Modules/Platform/Windows-Intel-C.cmake27
-rw-r--r--Modules/Platform/Windows-Intel-CXX.cmake28
-rw-r--r--Modules/Platform/Windows-Intel-Fortran.cmake44
-rw-r--r--Modules/Platform/Windows-Intel-ISPC.cmake8
-rw-r--r--Modules/Platform/Windows-Intel.cmake32
-rw-r--r--Modules/Platform/Windows-IntelLLVM-ASM.cmake2
-rw-r--r--Modules/Platform/Windows-IntelLLVM-C.cmake2
-rw-r--r--Modules/Platform/Windows-IntelLLVM-CXX.cmake3
-rw-r--r--Modules/Platform/Windows-IntelLLVM-Fortran.cmake44
-rw-r--r--Modules/Platform/Windows-IntelLLVM.cmake17
-rw-r--r--Modules/Platform/Windows-MSVC-C.cmake12
-rw-r--r--Modules/Platform/Windows-MSVC-CXX.cmake13
-rw-r--r--Modules/Platform/Windows-MSVC.cmake481
-rw-r--r--Modules/Platform/Windows-NVIDIA-CUDA.cmake88
-rw-r--r--Modules/Platform/Windows-OpenWatcom-C.cmake2
-rw-r--r--Modules/Platform/Windows-OpenWatcom-CXX.cmake2
-rw-r--r--Modules/Platform/Windows-OpenWatcom.cmake35
-rw-r--r--Modules/Platform/Windows-PGI-C.cmake2
-rw-r--r--Modules/Platform/Windows-PGI-Fortran.cmake2
-rw-r--r--Modules/Platform/Windows-PGI.cmake49
-rw-r--r--Modules/Platform/Windows-Watcom-C.cmake1
-rw-r--r--Modules/Platform/Windows-Watcom-CXX.cmake1
-rw-r--r--Modules/Platform/Windows-df.cmake60
-rw-r--r--Modules/Platform/Windows-windres.cmake1
-rw-r--r--Modules/Platform/Windows.cmake45
-rw-r--r--Modules/Platform/WindowsCE-MSVC-C.cmake1
-rw-r--r--Modules/Platform/WindowsCE-MSVC-CXX.cmake1
-rw-r--r--Modules/Platform/WindowsCE.cmake1
-rw-r--r--Modules/Platform/WindowsPaths.cmake96
-rw-r--r--Modules/Platform/WindowsPhone-Clang-ASM.cmake1
-rw-r--r--Modules/Platform/WindowsPhone-Clang-C.cmake1
-rw-r--r--Modules/Platform/WindowsPhone-Clang-CXX.cmake1
-rw-r--r--Modules/Platform/WindowsPhone-GNU-ASM.cmake1
-rw-r--r--Modules/Platform/WindowsPhone-GNU-C.cmake1
-rw-r--r--Modules/Platform/WindowsPhone-GNU-CXX.cmake1
-rw-r--r--Modules/Platform/WindowsPhone-MSVC-C.cmake1
-rw-r--r--Modules/Platform/WindowsPhone-MSVC-CXX.cmake1
-rw-r--r--Modules/Platform/WindowsPhone.cmake1
-rw-r--r--Modules/Platform/WindowsStore-Clang-ASM.cmake1
-rw-r--r--Modules/Platform/WindowsStore-Clang-C.cmake1
-rw-r--r--Modules/Platform/WindowsStore-Clang-CXX.cmake1
-rw-r--r--Modules/Platform/WindowsStore-GNU-ASM.cmake1
-rw-r--r--Modules/Platform/WindowsStore-GNU-C.cmake1
-rw-r--r--Modules/Platform/WindowsStore-GNU-CXX.cmake1
-rw-r--r--Modules/Platform/WindowsStore-MSVC-C.cmake1
-rw-r--r--Modules/Platform/WindowsStore-MSVC-CXX.cmake1
-rw-r--r--Modules/Platform/WindowsStore.cmake1
-rw-r--r--Modules/Platform/Xenix.cmake2
-rw-r--r--Modules/Platform/eCos.cmake65
-rw-r--r--Modules/Platform/gas.cmake19
-rw-r--r--Modules/Platform/iOS-Determine-CXX.cmake1
-rw-r--r--Modules/Platform/iOS-Initialize.cmake9
-rw-r--r--Modules/Platform/iOS.cmake1
-rw-r--r--Modules/Platform/kFreeBSD.cmake4
-rw-r--r--Modules/Platform/syllable.cmake33
-rw-r--r--Modules/Platform/tvOS-Determine-CXX.cmake1
-rw-r--r--Modules/Platform/tvOS-Initialize.cmake7
-rw-r--r--Modules/Platform/tvOS.cmake1
-rw-r--r--Modules/Platform/watchOS-Determine-CXX.cmake1
-rw-r--r--Modules/Platform/watchOS-Initialize.cmake7
-rw-r--r--Modules/Platform/watchOS.cmake1
-rw-r--r--Modules/ProcessorCount.cmake240
-rw-r--r--Modules/Qt4ConfigDependentSettings.cmake290
-rw-r--r--Modules/Qt4Macros.cmake516
-rw-r--r--Modules/RepositoryInfo.txt.in3
-rw-r--r--Modules/SelectLibraryConfigurations.cmake80
-rwxr-xr-xModules/Squish4RunTestCase.bat23
-rwxr-xr-xModules/Squish4RunTestCase.sh27
-rwxr-xr-xModules/SquishRunTestCase.bat11
-rwxr-xr-xModules/SquishRunTestCase.sh13
-rw-r--r--Modules/SquishTestScript.cmake85
-rw-r--r--Modules/SystemInformation.cmake93
-rw-r--r--Modules/SystemInformation.in88
-rw-r--r--Modules/TestBigEndian.cmake143
-rw-r--r--Modules/TestCXXAcceptsFlag.cmake44
-rw-r--r--Modules/TestEndianess.c.in23
-rw-r--r--Modules/TestForANSIForScope.cmake43
-rw-r--r--Modules/TestForANSIStreamHeaders.cmake33
-rw-r--r--Modules/TestForANSIStreamHeaders.cxx6
-rw-r--r--Modules/TestForAnsiForScope.cxx8
-rw-r--r--Modules/TestForSSTREAM.cmake41
-rw-r--r--Modules/TestForSSTREAM.cxx10
-rw-r--r--Modules/TestForSTDNamespace.cmake41
-rw-r--r--Modules/TestForSTDNamespace.cxx6
-rw-r--r--Modules/UseEcos.cmake236
-rw-r--r--Modules/UseJava.cmake1505
-rw-r--r--Modules/UseJava/ClassFilelist.cmake40
-rw-r--r--Modules/UseJava/ClearClassFiles.cmake17
-rw-r--r--Modules/UseJava/Symlinks.cmake20
-rw-r--r--Modules/UseJava/javaTargets.cmake.in39
-rw-r--r--Modules/UsePkgConfig.cmake75
-rw-r--r--Modules/UseQt4.cmake107
-rw-r--r--Modules/UseSWIG.cmake1021
-rw-r--r--Modules/UseSWIG/ManageSupportFiles.cmake31
-rw-r--r--Modules/Use_wxWindows.cmake69
-rw-r--r--Modules/UsewxWidgets.cmake101
-rw-r--r--Modules/VTKCompatibility.cmake42
-rw-r--r--Modules/WriteBasicConfigVersionFile.cmake51
-rw-r--r--Modules/WriteCompilerDetectionHeader.cmake720
-rw-r--r--Modules/ecos_clean.cmake16
-rw-r--r--Modules/exportheader.cmake.in42
-rw-r--r--Modules/kde3init_dummy.cpp.in6
-rw-r--r--Modules/kde3uic.cmake22
-rw-r--r--Modules/readme.txt4
-rw-r--r--Packaging/CMakeDMGBackground.tifbin0 -> 95690 bytes-rw-r--r--Packaging/CMakeDMGSetup.scpt57
-rw-r--r--Packaging/QtSDK/ToolsCMakeXX.cmake45
-rw-r--r--Packaging/QtSDK/qt.tools.cmake.xx.qs.in46
-rw-r--r--README.rst121
-rw-r--r--Source/.gitattributes4
-rw-r--r--Source/CMakeInstallDestinations.cmake59
-rw-r--r--Source/CMakeInstallSignTool.cmake.in51
-rw-r--r--Source/CMakeLists.txt1246
-rw-r--r--Source/CMakeSourceDir.txt.in1
-rwxr-xr-xSource/CMakeVersion.bash7
-rw-r--r--Source/CMakeVersion.cmake84
-rw-r--r--Source/CMakeVersion.rc.in28
-rw-r--r--Source/CPack/IFW/cmCPackIFWCommon.cxx137
-rw-r--r--Source/CPack/IFW/cmCPackIFWCommon.h78
-rw-r--r--Source/CPack/IFW/cmCPackIFWGenerator.cxx624
-rw-r--r--Source/CPack/IFW/cmCPackIFWGenerator.h153
-rw-r--r--Source/CPack/IFW/cmCPackIFWInstaller.cxx563
-rw-r--r--Source/CPack/IFW/cmCPackIFWInstaller.h137
-rw-r--r--Source/CPack/IFW/cmCPackIFWPackage.cxx758
-rw-r--r--Source/CPack/IFW/cmCPackIFWPackage.h150
-rw-r--r--Source/CPack/IFW/cmCPackIFWRepository.cxx283
-rw-r--r--Source/CPack/IFW/cmCPackIFWRepository.h85
-rw-r--r--Source/CPack/OSXLauncherScript.scptbin0 -> 3102 bytes-rw-r--r--Source/CPack/OSXScriptLauncher.cxx122
-rw-r--r--Source/CPack/WiX/cmCMakeToWixPath.cxx39
-rw-r--r--Source/CPack/WiX/cmCMakeToWixPath.h9
-rw-r--r--Source/CPack/WiX/cmCPackWIXGenerator.cxx1217
-rw-r--r--Source/CPack/WiX/cmCPackWIXGenerator.h172
-rw-r--r--Source/CPack/WiX/cmWIXAccessControlList.cxx128
-rw-r--r--Source/CPack/WiX/cmWIXAccessControlList.h30
-rw-r--r--Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx84
-rw-r--r--Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h30
-rw-r--r--Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx91
-rw-r--r--Source/CPack/WiX/cmWIXFeaturesSourceWriter.h28
-rw-r--r--Source/CPack/WiX/cmWIXFilesSourceWriter.cxx168
-rw-r--r--Source/CPack/WiX/cmWIXFilesSourceWriter.h38
-rw-r--r--Source/CPack/WiX/cmWIXPatch.cxx91
-rw-r--r--Source/CPack/WiX/cmWIXPatch.h34
-rw-r--r--Source/CPack/WiX/cmWIXPatchParser.cxx160
-rw-r--r--Source/CPack/WiX/cmWIXPatchParser.h92
-rw-r--r--Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx186
-rw-r--r--Source/CPack/WiX/cmWIXRichTextFormatWriter.h43
-rw-r--r--Source/CPack/WiX/cmWIXShortcut.cxx103
-rw-r--r--Source/CPack/WiX/cmWIXShortcut.h57
-rw-r--r--Source/CPack/WiX/cmWIXSourceWriter.cxx183
-rw-r--r--Source/CPack/WiX/cmWIXSourceWriter.h77
-rw-r--r--Source/CPack/cmCPackArchiveGenerator.cxx371
-rw-r--r--Source/CPack/cmCPackArchiveGenerator.h94
-rw-r--r--Source/CPack/cmCPackBundleGenerator.cxx275
-rw-r--r--Source/CPack/cmCPackBundleGenerator.h34
-rw-r--r--Source/CPack/cmCPackComponentGroup.cxx30
-rw-r--r--Source/CPack/cmCPackComponentGroup.h168
-rw-r--r--Source/CPack/cmCPackConfigure.h.in2
-rw-r--r--Source/CPack/cmCPackCygwinBinaryGenerator.cxx72
-rw-r--r--Source/CPack/cmCPackCygwinBinaryGenerator.h26
-rw-r--r--Source/CPack/cmCPackCygwinSourceGenerator.cxx158
-rw-r--r--Source/CPack/cmCPackCygwinSourceGenerator.h28
-rw-r--r--Source/CPack/cmCPackDebGenerator.cxx923
-rw-r--r--Source/CPack/cmCPackDebGenerator.h70
-rw-r--r--Source/CPack/cmCPackDragNDropGenerator.cxx928
-rw-r--r--Source/CPack/cmCPackDragNDropGenerator.h82
-rw-r--r--Source/CPack/cmCPackExternalGenerator.cxx328
-rw-r--r--Source/CPack/cmCPackExternalGenerator.h87
-rw-r--r--Source/CPack/cmCPackFreeBSDGenerator.cxx336
-rw-r--r--Source/CPack/cmCPackFreeBSDGenerator.h34
-rw-r--r--Source/CPack/cmCPackGenerator.cxx1634
-rw-r--r--Source/CPack/cmCPackGenerator.h340
-rw-r--r--Source/CPack/cmCPackGeneratorFactory.cxx166
-rw-r--r--Source/CPack/cmCPackGeneratorFactory.h45
-rw-r--r--Source/CPack/cmCPackLog.cxx164
-rw-r--r--Source/CPack/cmCPackLog.h140
-rw-r--r--Source/CPack/cmCPackNSISGenerator.cxx973
-rw-r--r--Source/CPack/cmCPackNSISGenerator.h86
-rw-r--r--Source/CPack/cmCPackNuGetGenerator.cxx142
-rw-r--r--Source/CPack/cmCPackNuGetGenerator.h34
-rw-r--r--Source/CPack/cmCPackOSXX11Generator.cxx273
-rw-r--r--Source/CPack/cmCPackOSXX11Generator.h39
-rw-r--r--Source/CPack/cmCPackPKGGenerator.cxx396
-rw-r--r--Source/CPack/cmCPackPKGGenerator.h95
-rw-r--r--Source/CPack/cmCPackPackageMakerGenerator.cxx578
-rw-r--r--Source/CPack/cmCPackPackageMakerGenerator.h50
-rw-r--r--Source/CPack/cmCPackProductBuildGenerator.cxx253
-rw-r--r--Source/CPack/cmCPackProductBuildGenerator.h50
-rw-r--r--Source/CPack/cmCPackRPMGenerator.cxx440
-rw-r--r--Source/CPack/cmCPackRPMGenerator.h69
-rw-r--r--Source/CPack/cmCPackSTGZGenerator.cxx115
-rw-r--r--Source/CPack/cmCPackSTGZGenerator.h31
-rw-r--r--Source/CPack/cpack.cxx474
-rw-r--r--Source/CTest/cmCTestBZR.cxx478
-rw-r--r--Source/CTest/cmCTestBZR.h51
-rw-r--r--Source/CTest/cmCTestBinPacker.cxx203
-rw-r--r--Source/CTest/cmCTestBinPacker.h28
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.cxx471
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.h72
-rw-r--r--Source/CTest/cmCTestBuildCommand.cxx150
-rw-r--r--Source/CTest/cmCTestBuildCommand.h63
-rw-r--r--Source/CTest/cmCTestBuildHandler.cxx1177
-rw-r--r--Source/CTest/cmCTestBuildHandler.h157
-rw-r--r--Source/CTest/cmCTestCVS.cxx282
-rw-r--r--Source/CTest/cmCTestCVS.h52
-rw-r--r--Source/CTest/cmCTestCommand.h28
-rw-r--r--Source/CTest/cmCTestConfigureCommand.cxx150
-rw-r--r--Source/CTest/cmCTestConfigureCommand.h46
-rw-r--r--Source/CTest/cmCTestConfigureHandler.cxx103
-rw-r--r--Source/CTest/cmCTestConfigureHandler.h26
-rw-r--r--Source/CTest/cmCTestCoverageCommand.cxx46
-rw-r--r--Source/CTest/cmCTestCoverageCommand.h49
-rw-r--r--Source/CTest/cmCTestCoverageHandler.cxx2356
-rw-r--r--Source/CTest/cmCTestCoverageHandler.h150
-rw-r--r--Source/CTest/cmCTestCurl.cxx272
-rw-r--r--Source/CTest/cmCTestCurl.h53
-rw-r--r--Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx27
-rw-r--r--Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h46
-rw-r--r--Source/CTest/cmCTestGIT.cxx656
-rw-r--r--Source/CTest/cmCTestGIT.h54
-rw-r--r--Source/CTest/cmCTestGenericHandler.cxx160
-rw-r--r--Source/CTest/cmCTestGenericHandler.h139
-rw-r--r--Source/CTest/cmCTestGlobalVC.cxx124
-rw-r--r--Source/CTest/cmCTestGlobalVC.h74
-rw-r--r--Source/CTest/cmCTestHG.cxx315
-rw-r--r--Source/CTest/cmCTestHG.h43
-rw-r--r--Source/CTest/cmCTestHandlerCommand.cxx247
-rw-r--r--Source/CTest/cmCTestHandlerCommand.h59
-rw-r--r--Source/CTest/cmCTestLaunch.cxx328
-rw-r--r--Source/CTest/cmCTestLaunch.h71
-rw-r--r--Source/CTest/cmCTestLaunchReporter.cxx316
-rw-r--r--Source/CTest/cmCTestLaunchReporter.h81
-rw-r--r--Source/CTest/cmCTestMemCheckCommand.cxx50
-rw-r--r--Source/CTest/cmCTestMemCheckCommand.h44
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.cxx1404
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.h158
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.cxx1442
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.h201
-rw-r--r--Source/CTest/cmCTestP4.cxx527
-rw-r--r--Source/CTest/cmCTestP4.h73
-rw-r--r--Source/CTest/cmCTestReadCustomFilesCommand.cxx22
-rw-r--r--Source/CTest/cmCTestReadCustomFilesCommand.h45
-rw-r--r--Source/CTest/cmCTestResourceAllocator.cxx86
-rw-r--r--Source/CTest/cmCTestResourceAllocator.h36
-rw-r--r--Source/CTest/cmCTestResourceGroupsLexerHelper.cxx55
-rw-r--r--Source/CTest/cmCTestResourceGroupsLexerHelper.h41
-rw-r--r--Source/CTest/cmCTestResourceSpec.cxx237
-rw-r--r--Source/CTest/cmCTestResourceSpec.h54
-rw-r--r--Source/CTest/cmCTestRunScriptCommand.cxx46
-rw-r--r--Source/CTest/cmCTestRunScriptCommand.h46
-rw-r--r--Source/CTest/cmCTestRunTest.cxx883
-rw-r--r--Source/CTest/cmCTestRunTest.h160
-rw-r--r--Source/CTest/cmCTestSVN.cxx564
-rw-r--r--Source/CTest/cmCTestSVN.h104
-rw-r--r--Source/CTest/cmCTestScriptHandler.cxx949
-rw-r--r--Source/CTest/cmCTestScriptHandler.h179
-rw-r--r--Source/CTest/cmCTestSleepCommand.cxx43
-rw-r--r--Source/CTest/cmCTestSleepCommand.h46
-rw-r--r--Source/CTest/cmCTestStartCommand.cxx180
-rw-r--r--Source/CTest/cmCTestStartCommand.h63
-rw-r--r--Source/CTest/cmCTestSubmitCommand.cxx201
-rw-r--r--Source/CTest/cmCTestSubmitCommand.h56
-rw-r--r--Source/CTest/cmCTestSubmitHandler.cxx906
-rw-r--r--Source/CTest/cmCTestSubmitHandler.h78
-rw-r--r--Source/CTest/cmCTestTestCommand.cxx152
-rw-r--r--Source/CTest/cmCTestTestCommand.h63
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx2459
-rw-r--r--Source/CTest/cmCTestTestHandler.h357
-rw-r--r--Source/CTest/cmCTestUpdateCommand.cxx86
-rw-r--r--Source/CTest/cmCTestUpdateCommand.h43
-rw-r--r--Source/CTest/cmCTestUpdateHandler.cxx353
-rw-r--r--Source/CTest/cmCTestUpdateHandler.h64
-rw-r--r--Source/CTest/cmCTestUploadCommand.cxx46
-rw-r--r--Source/CTest/cmCTestUploadCommand.h49
-rw-r--r--Source/CTest/cmCTestUploadHandler.cxx73
-rw-r--r--Source/CTest/cmCTestUploadHandler.h37
-rw-r--r--Source/CTest/cmCTestVC.cxx228
-rw-r--r--Source/CTest/cmCTestVC.h151
-rw-r--r--Source/CTest/cmParseBlanketJSCoverage.cxx139
-rw-r--r--Source/CTest/cmParseBlanketJSCoverage.h40
-rw-r--r--Source/CTest/cmParseCacheCoverage.cxx178
-rw-r--r--Source/CTest/cmParseCacheCoverage.h32
-rw-r--r--Source/CTest/cmParseCoberturaCoverage.cxx165
-rw-r--r--Source/CTest/cmParseCoberturaCoverage.h42
-rw-r--r--Source/CTest/cmParseDelphiCoverage.cxx232
-rw-r--r--Source/CTest/cmParseDelphiCoverage.h36
-rw-r--r--Source/CTest/cmParseGTMCoverage.cxx252
-rw-r--r--Source/CTest/cmParseGTMCoverage.h38
-rw-r--r--Source/CTest/cmParseJacocoCoverage.cxx178
-rw-r--r--Source/CTest/cmParseJacocoCoverage.h50
-rw-r--r--Source/CTest/cmParseMumpsCoverage.cxx144
-rw-r--r--Source/CTest/cmParseMumpsCoverage.h44
-rw-r--r--Source/CTest/cmParsePHPCoverage.cxx222
-rw-r--r--Source/CTest/cmParsePHPCoverage.h36
-rw-r--r--Source/CTest/cmProcess.cxx706
-rw-r--r--Source/CTest/cmProcess.h133
-rw-r--r--Source/Checks/Curses.cmake44
-rw-r--r--Source/Checks/Curses/CMakeLists.txt25
-rw-r--r--Source/Checks/Curses/CheckCurses.c15
-rw-r--r--Source/Checks/cm_c11_thread_local.c5
-rw-r--r--Source/Checks/cm_c11_thread_local.cmake37
-rw-r--r--Source/Checks/cm_cxx14_check.cmake40
-rw-r--r--Source/Checks/cm_cxx14_check.cpp15
-rw-r--r--Source/Checks/cm_cxx17_check.cmake40
-rw-r--r--Source/Checks/cm_cxx17_check.cpp44
-rw-r--r--Source/Checks/cm_cxx_features.cmake93
-rw-r--r--Source/Checks/cm_cxx_filesystem.cxx27
-rw-r--r--Source/Checks/cm_cxx_make_unique.cxx6
-rw-r--r--Source/Checks/cm_cxx_unique_ptr.cxx6
-rw-r--r--Source/Checks/cm_message_checks_compat.cmake13
-rw-r--r--Source/CursesDialog/.NoDartCoverage1
-rw-r--r--Source/CursesDialog/CMakeLists.txt63
-rw-r--r--Source/CursesDialog/ccmake.cxx212
-rw-r--r--Source/CursesDialog/cmCursesBoolWidget.cxx64
-rw-r--r--Source/CursesDialog/cmCursesBoolWidget.h30
-rw-r--r--Source/CursesDialog/cmCursesCacheEntryComposite.cxx109
-rw-r--r--Source/CursesDialog/cmCursesCacheEntryComposite.h42
-rw-r--r--Source/CursesDialog/cmCursesColor.cxx78
-rw-r--r--Source/CursesDialog/cmCursesColor.h24
-rw-r--r--Source/CursesDialog/cmCursesDummyWidget.cxx19
-rw-r--r--Source/CursesDialog/cmCursesDummyWidget.h25
-rw-r--r--Source/CursesDialog/cmCursesFilePathWidget.cxx13
-rw-r--r--Source/CursesDialog/cmCursesFilePathWidget.h16
-rw-r--r--Source/CursesDialog/cmCursesForm.cxx45
-rw-r--r--Source/CursesDialog/cmCursesForm.h63
-rw-r--r--Source/CursesDialog/cmCursesLabelWidget.cxx24
-rw-r--r--Source/CursesDialog/cmCursesLabelWidget.h29
-rw-r--r--Source/CursesDialog/cmCursesLongMessageForm.cxx200
-rw-r--r--Source/CursesDialog/cmCursesLongMessageForm.h60
-rw-r--r--Source/CursesDialog/cmCursesMainForm.cxx1075
-rw-r--r--Source/CursesDialog/cmCursesMainForm.h171
-rw-r--r--Source/CursesDialog/cmCursesOptionsWidget.cxx93
-rw-r--r--Source/CursesDialog/cmCursesOptionsWidget.h36
-rw-r--r--Source/CursesDialog/cmCursesPathWidget.cxx89
-rw-r--r--Source/CursesDialog/cmCursesPathWidget.h35
-rw-r--r--Source/CursesDialog/cmCursesStandardIncludes.h42
-rw-r--r--Source/CursesDialog/cmCursesStringWidget.cxx207
-rw-r--r--Source/CursesDialog/cmCursesStringWidget.h66
-rw-r--r--Source/CursesDialog/cmCursesWidget.cxx44
-rw-r--r--Source/CursesDialog/cmCursesWidget.h69
-rw-r--r--Source/CursesDialog/form/.NoDartCoverage1
-rw-r--r--Source/CursesDialog/form/.gitattributes1
-rw-r--r--Source/CursesDialog/form/CMakeLists.txt69
-rw-r--r--Source/CursesDialog/form/READ.ME15
-rw-r--r--Source/CursesDialog/form/cmFormConfigure.h.in11
-rw-r--r--Source/CursesDialog/form/eti.h52
-rw-r--r--Source/CursesDialog/form/fld_arg.c91
-rw-r--r--Source/CursesDialog/form/fld_attr.c110
-rw-r--r--Source/CursesDialog/form/fld_current.c124
-rw-r--r--Source/CursesDialog/form/fld_def.c346
-rw-r--r--Source/CursesDialog/form/fld_dup.c97
-rw-r--r--Source/CursesDialog/form/fld_ftchoice.c62
-rw-r--r--Source/CursesDialog/form/fld_ftlink.c83
-rw-r--r--Source/CursesDialog/form/fld_info.c91
-rw-r--r--Source/CursesDialog/form/fld_just.c81
-rw-r--r--Source/CursesDialog/form/fld_link.c90
-rw-r--r--Source/CursesDialog/form/fld_max.c74
-rw-r--r--Source/CursesDialog/form/fld_move.c62
-rw-r--r--Source/CursesDialog/form/fld_newftyp.c125
-rw-r--r--Source/CursesDialog/form/fld_opts.c124
-rw-r--r--Source/CursesDialog/form/fld_pad.c78
-rw-r--r--Source/CursesDialog/form/fld_page.c76
-rw-r--r--Source/CursesDialog/form/fld_stat.c73
-rw-r--r--Source/CursesDialog/form/fld_type.c51
-rw-r--r--Source/CursesDialog/form/fld_user.c67
-rw-r--r--Source/CursesDialog/form/form.h407
-rw-r--r--Source/CursesDialog/form/form.priv.h128
-rw-r--r--Source/CursesDialog/form/frm_cursor.c66
-rw-r--r--Source/CursesDialog/form/frm_data.c183
-rw-r--r--Source/CursesDialog/form/frm_def.c376
-rw-r--r--Source/CursesDialog/form/frm_driver.c3883
-rw-r--r--Source/CursesDialog/form/frm_hook.c140
-rw-r--r--Source/CursesDialog/form/frm_opts.c116
-rw-r--r--Source/CursesDialog/form/frm_page.c100
-rw-r--r--Source/CursesDialog/form/frm_post.c119
-rw-r--r--Source/CursesDialog/form/frm_req_name.c163
-rw-r--r--Source/CursesDialog/form/frm_scale.c63
-rw-r--r--Source/CursesDialog/form/frm_sub.c69
-rw-r--r--Source/CursesDialog/form/frm_user.c67
-rw-r--r--Source/CursesDialog/form/frm_win.c70
-rw-r--r--Source/CursesDialog/form/fty_alnum.c138
-rw-r--r--Source/CursesDialog/form/fty_alpha.c139
-rw-r--r--Source/CursesDialog/form/fty_enum.c295
-rw-r--r--Source/CursesDialog/form/fty_int.c161
-rw-r--r--Source/CursesDialog/form/fty_ipv4.c84
-rw-r--r--Source/CursesDialog/form/fty_num.c192
-rw-r--r--Source/CursesDialog/form/fty_regex.c264
-rw-r--r--Source/CursesDialog/form/llib-lform694
-rw-r--r--Source/CursesDialog/form/mf_common.h93
-rw-r--r--Source/CursesDialog/form/nc_alloc.h83
-rw-r--r--Source/LexerParser/.clang-tidy6
-rw-r--r--Source/LexerParser/.gitattributes21
-rw-r--r--Source/LexerParser/cmCTestResourceGroupsLexer.cxx2224
-rw-r--r--Source/LexerParser/cmCTestResourceGroupsLexer.h692
-rw-r--r--Source/LexerParser/cmCTestResourceGroupsLexer.in.l102
-rw-r--r--Source/LexerParser/cmCommandArgumentLexer.cxx2246
-rw-r--r--Source/LexerParser/cmCommandArgumentLexer.h689
-rw-r--r--Source/LexerParser/cmCommandArgumentLexer.in.l148
-rw-r--r--Source/LexerParser/cmCommandArgumentParser.cxx1849
-rw-r--r--Source/LexerParser/cmCommandArgumentParser.y192
-rw-r--r--Source/LexerParser/cmCommandArgumentParserTokens.h79
-rw-r--r--Source/LexerParser/cmDependsJavaLexer.cxx2819
-rw-r--r--Source/LexerParser/cmDependsJavaLexer.h689
-rw-r--r--Source/LexerParser/cmDependsJavaLexer.in.l181
-rw-r--r--Source/LexerParser/cmDependsJavaParser.cxx6604
-rw-r--r--Source/LexerParser/cmDependsJavaParser.y3215
-rw-r--r--Source/LexerParser/cmDependsJavaParserTokens.h170
-rw-r--r--Source/LexerParser/cmExprLexer.cxx2231
-rw-r--r--Source/LexerParser/cmExprLexer.h687
-rw-r--r--Source/LexerParser/cmExprLexer.in.l69
-rw-r--r--Source/LexerParser/cmExprParser.cxx1844
-rw-r--r--Source/LexerParser/cmExprParser.y178
-rw-r--r--Source/LexerParser/cmExprParserTokens.h81
-rw-r--r--Source/LexerParser/cmFortranLexer.cxx2616
-rw-r--r--Source/LexerParser/cmFortranLexer.h691
-rw-r--r--Source/LexerParser/cmFortranLexer.in.l189
-rw-r--r--Source/LexerParser/cmFortranParser.cxx2078
-rw-r--r--Source/LexerParser/cmFortranParser.y249
-rw-r--r--Source/LexerParser/cmFortranParserTokens.h119
-rw-r--r--Source/LexerParser/cmGccDepfileLexer.cxx2210
-rw-r--r--Source/LexerParser/cmGccDepfileLexer.h687
-rw-r--r--Source/LexerParser/cmGccDepfileLexer.in.l72
-rw-r--r--Source/LexerParser/cmListFileLexer.c2847
-rw-r--r--Source/LexerParser/cmListFileLexer.in.l560
-rw-r--r--Source/Modules/CheckCXXLinkerFlag.cmake29
-rw-r--r--Source/Modules/FindJsonCpp.cmake107
-rw-r--r--Source/Modules/FindLibRHash.cmake73
-rw-r--r--Source/Modules/FindLibUUID.cmake85
-rw-r--r--Source/Modules/FindLibUV.cmake123
-rw-r--r--Source/Modules/OverrideC.cmake3
-rw-r--r--Source/Modules/OverrideCXX.cmake3
-rw-r--r--Source/QtDialog/AddCacheEntry.cxx101
-rw-r--r--Source/QtDialog/AddCacheEntry.h33
-rw-r--r--Source/QtDialog/AddCacheEntry.ui97
-rw-r--r--Source/QtDialog/CMakeGUIExec.cxx15
-rw-r--r--Source/QtDialog/CMakeLists.txt352
-rw-r--r--Source/QtDialog/CMakeSetup.cxx316
-rw-r--r--Source/QtDialog/CMakeSetup.icnsbin0 -> 195235 bytes-rw-r--r--Source/QtDialog/CMakeSetup.icobin0 -> 159613 bytes-rw-r--r--Source/QtDialog/CMakeSetup.qrc8
-rw-r--r--Source/QtDialog/CMakeSetup.rc1
-rw-r--r--Source/QtDialog/CMakeSetup128.pngbin0 -> 7981 bytes-rw-r--r--Source/QtDialog/CMakeSetup32.pngbin0 -> 1632 bytes-rw-r--r--Source/QtDialog/CMakeSetup64.pngbin0 -> 3566 bytes-rw-r--r--Source/QtDialog/CMakeSetupDialog.cxx1481
-rw-r--r--Source/QtDialog/CMakeSetupDialog.h160
-rw-r--r--Source/QtDialog/CMakeSetupDialog.ui385
-rw-r--r--Source/QtDialog/Compilers.h22
-rw-r--r--Source/QtDialog/Compilers.ui87
-rw-r--r--Source/QtDialog/CrossCompiler.ui213
-rw-r--r--Source/QtDialog/Delete16.pngbin0 -> 538 bytes-rw-r--r--Source/QtDialog/EnvironmentDialog.cxx204
-rw-r--r--Source/QtDialog/EnvironmentDialog.h59
-rw-r--r--Source/QtDialog/EnvironmentDialog.ui124
-rw-r--r--Source/QtDialog/FirstConfigure.cxx744
-rw-r--r--Source/QtDialog/FirstConfigure.h217
-rw-r--r--Source/QtDialog/Info.plist.in34
-rw-r--r--Source/QtDialog/Plus16.pngbin0 -> 207 bytes-rw-r--r--Source/QtDialog/QCMake.cxx684
-rw-r--r--Source/QtDialog/QCMake.h214
-rw-r--r--Source/QtDialog/QCMakeCacheView.cxx729
-rw-r--r--Source/QtDialog/QCMakeCacheView.h166
-rw-r--r--Source/QtDialog/QCMakePreset.cxx53
-rw-r--r--Source/QtDialog/QCMakePreset.h31
-rw-r--r--Source/QtDialog/QCMakePresetComboBox.cxx64
-rw-r--r--Source/QtDialog/QCMakePresetComboBox.h35
-rw-r--r--Source/QtDialog/QCMakePresetItemModel.cxx143
-rw-r--r--Source/QtDialog/QCMakePresetItemModel.h45
-rw-r--r--Source/QtDialog/QCMakeWidgets.cxx157
-rw-r--r--Source/QtDialog/QCMakeWidgets.h78
-rw-r--r--Source/QtDialog/QtDialogCPack.cmake.in15
-rw-r--r--Source/QtDialog/RegexExplorer.cxx163
-rw-r--r--Source/QtDialog/RegexExplorer.h40
-rw-r--r--Source/QtDialog/RegexExplorer.ui182
-rw-r--r--Source/QtDialog/WarningMessagesDialog.cxx90
-rw-r--r--Source/QtDialog/WarningMessagesDialog.h64
-rw-r--r--Source/QtDialog/WarningMessagesDialog.ui173
-rw-r--r--Source/QtDialog/cmake-gui.desktop12
-rw-r--r--Source/QtDialog/cmakecache.xml8
-rw-r--r--Source/QtIFW/CMake.DeveloperReference.HTML.qs.in21
-rw-r--r--Source/QtIFW/CMake.Dialogs.QtGUI.qs.in21
-rw-r--r--Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in21
-rw-r--r--Source/QtIFW/CMake.qs.in24
-rw-r--r--Source/QtIFW/cmake.org.html7
-rw-r--r--Source/QtIFW/controlscript.qs6
-rw-r--r--Source/QtIFW/installscript.qs.in27
-rw-r--r--Source/bindexplib.cxx515
-rw-r--r--Source/bindexplib.h26
-rw-r--r--Source/cmAddCompileDefinitionsCommand.cxx16
-rw-r--r--Source/cmAddCompileDefinitionsCommand.h13
-rw-r--r--Source/cmAddCompileOptionsCommand.cxx16
-rw-r--r--Source/cmAddCompileOptionsCommand.h13
-rw-r--r--Source/cmAddCustomCommandCommand.cxx374
-rw-r--r--Source/cmAddCustomCommandCommand.h13
-rw-r--r--Source/cmAddCustomTargetCommand.cxx224
-rw-r--r--Source/cmAddCustomTargetCommand.h13
-rw-r--r--Source/cmAddDefinitionsCommand.cxx16
-rw-r--r--Source/cmAddDefinitionsCommand.h13
-rw-r--r--Source/cmAddDependenciesCommand.cxx49
-rw-r--r--Source/cmAddDependenciesCommand.h13
-rw-r--r--Source/cmAddExecutableCommand.cxx160
-rw-r--r--Source/cmAddExecutableCommand.h13
-rw-r--r--Source/cmAddLibraryCommand.cxx292
-rw-r--r--Source/cmAddLibraryCommand.h13
-rw-r--r--Source/cmAddLinkOptionsCommand.cxx16
-rw-r--r--Source/cmAddLinkOptionsCommand.h13
-rw-r--r--Source/cmAddSubDirectoryCommand.cxx108
-rw-r--r--Source/cmAddSubDirectoryCommand.h13
-rw-r--r--Source/cmAddTestCommand.cxx149
-rw-r--r--Source/cmAddTestCommand.h13
-rw-r--r--Source/cmAffinity.cxx65
-rw-r--r--Source/cmAffinity.h12
-rw-r--r--Source/cmAlgorithms.h145
-rw-r--r--Source/cmArchiveWrite.cxx440
-rw-r--r--Source/cmArchiveWrite.h182
-rw-r--r--Source/cmArgumentParser.cxx96
-rw-r--r--Source/cmArgumentParser.h147
-rw-r--r--Source/cmAuxSourceDirectoryCommand.cxx73
-rw-r--r--Source/cmAuxSourceDirectoryCommand.h13
-rw-r--r--Source/cmBase32.cxx93
-rw-r--r--Source/cmBase32.h29
-rw-r--r--Source/cmBinUtilsLinker.cxx16
-rw-r--r--Source/cmBinUtilsLinker.h27
-rw-r--r--Source/cmBinUtilsLinuxELFGetRuntimeDependenciesTool.cxx19
-rw-r--r--Source/cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h27
-rw-r--r--Source/cmBinUtilsLinuxELFLinker.cxx182
-rw-r--r--Source/cmBinUtilsLinuxELFLinker.h41
-rw-r--r--Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx85
-rw-r--r--Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h23
-rw-r--r--Source/cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.cxx19
-rw-r--r--Source/cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h26
-rw-r--r--Source/cmBinUtilsMacOSMachOLinker.cxx244
-rw-r--r--Source/cmBinUtilsMacOSMachOLinker.h56
-rw-r--r--Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx100
-rw-r--r--Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h22
-rw-r--r--Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx68
-rw-r--r--Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h22
-rw-r--r--Source/cmBinUtilsWindowsPEGetRuntimeDependenciesTool.cxx19
-rw-r--r--Source/cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h25
-rw-r--r--Source/cmBinUtilsWindowsPELinker.cxx123
-rw-r--r--Source/cmBinUtilsWindowsPELinker.h30
-rw-r--r--Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx68
-rw-r--r--Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h22
-rw-r--r--Source/cmBreakCommand.cxx74
-rw-r--r--Source/cmBreakCommand.h18
-rw-r--r--Source/cmBuildCommand.cxx130
-rw-r--r--Source/cmBuildCommand.h13
-rw-r--r--Source/cmBuildNameCommand.cxx61
-rw-r--r--Source/cmBuildNameCommand.h13
-rw-r--r--Source/cmCLocaleEnvironmentScope.cxx53
-rw-r--r--Source/cmCLocaleEnvironmentScope.h26
-rw-r--r--Source/cmCMakeHostSystemInformationCommand.cxx199
-rw-r--r--Source/cmCMakeHostSystemInformationCommand.h19
-rw-r--r--Source/cmCMakeLanguageCommand.cxx361
-rw-r--r--Source/cmCMakeLanguageCommand.h17
-rw-r--r--Source/cmCMakeMinimumRequired.cxx165
-rw-r--r--Source/cmCMakeMinimumRequired.h18
-rw-r--r--Source/cmCMakePath.cxx147
-rw-r--r--Source/cmCMakePath.h571
-rw-r--r--Source/cmCMakePathCommand.cxx998
-rw-r--r--Source/cmCMakePathCommand.h14
-rw-r--r--Source/cmCMakePolicyCommand.cxx224
-rw-r--r--Source/cmCMakePolicyCommand.h19
-rw-r--r--Source/cmCMakePresetsFile.cxx1103
-rw-r--r--Source/cmCMakePresetsFile.h362
-rw-r--r--Source/cmCMakePresetsFileInternal.h112
-rw-r--r--Source/cmCMakePresetsFileReadJSON.cxx1022
-rw-r--r--Source/cmCPackPropertiesGenerator.cxx45
-rw-r--r--Source/cmCPackPropertiesGenerator.h37
-rw-r--r--Source/cmCPluginAPI.cxx855
-rw-r--r--Source/cmCPluginAPI.h236
-rw-r--r--Source/cmCTest.cxx3700
-rw-r--r--Source/cmCTest.h580
-rw-r--r--Source/cmCacheManager.cxx619
-rw-r--r--Source/cmCacheManager.h215
-rw-r--r--Source/cmCallVisualStudioMacro.cxx461
-rw-r--r--Source/cmCallVisualStudioMacro.h33
-rw-r--r--Source/cmCommand.cxx59
-rw-r--r--Source/cmCommand.h97
-rw-r--r--Source/cmCommandArgumentParserHelper.cxx294
-rw-r--r--Source/cmCommandArgumentParserHelper.h91
-rw-r--r--Source/cmCommandLineArgument.h167
-rw-r--r--Source/cmCommands.cxx373
-rw-r--r--Source/cmCommands.h14
-rw-r--r--Source/cmCommonTargetGenerator.cxx294
-rw-r--r--Source/cmCommonTargetGenerator.h76
-rw-r--r--Source/cmComputeComponentGraph.cxx134
-rw-r--r--Source/cmComputeComponentGraph.h79
-rw-r--r--Source/cmComputeLinkDepends.cxx842
-rw-r--r--Source/cmComputeLinkDepends.h161
-rw-r--r--Source/cmComputeLinkInformation.cxx1897
-rw-r--r--Source/cmComputeLinkInformation.h216
-rw-r--r--Source/cmComputeTargetDepends.cxx730
-rw-r--r--Source/cmComputeTargetDepends.h106
-rw-r--r--Source/cmConditionEvaluator.cxx762
-rw-r--r--Source/cmConditionEvaluator.h86
-rw-r--r--Source/cmConfigure.cmake.h.in31
-rw-r--r--Source/cmConfigureFileCommand.cxx214
-rw-r--r--Source/cmConfigureFileCommand.h13
-rw-r--r--Source/cmConsoleBuf.cxx21
-rw-r--r--Source/cmConsoleBuf.h23
-rw-r--r--Source/cmContinueCommand.cxx35
-rw-r--r--Source/cmContinueCommand.h18
-rw-r--r--Source/cmConvertMSBuildXMLToJSON.py471
-rw-r--r--Source/cmCoreTryCompile.cxx1093
-rw-r--r--Source/cmCoreTryCompile.h49
-rw-r--r--Source/cmCreateTestSourceList.cxx155
-rw-r--r--Source/cmCreateTestSourceList.h13
-rw-r--r--Source/cmCryptoHash.cxx192
-rw-r--r--Source/cmCryptoHash.h86
-rw-r--r--Source/cmCurl.cxx97
-rw-r--r--Source/cmCurl.h13
-rw-r--r--Source/cmCustomCommand.cxx152
-rw-r--r--Source/cmCustomCommand.h121
-rw-r--r--Source/cmCustomCommandGenerator.cxx466
-rw-r--r--Source/cmCustomCommandGenerator.h66
-rw-r--r--Source/cmCustomCommandLines.cxx22
-rw-r--r--Source/cmCustomCommandLines.h29
-rw-r--r--Source/cmCustomCommandTypes.h29
-rw-r--r--Source/cmDefinePropertyCommand.cxx101
-rw-r--r--Source/cmDefinePropertyCommand.h13
-rw-r--r--Source/cmDefinitions.cxx109
-rw-r--r--Source/cmDefinitions.h68
-rw-r--r--Source/cmDepends.cxx247
-rw-r--r--Source/cmDepends.h112
-rw-r--r--Source/cmDependsC.cxx469
-rw-r--r--Source/cmDependsC.h94
-rw-r--r--Source/cmDependsCompiler.cxx252
-rw-r--r--Source/cmDependsCompiler.h60
-rw-r--r--Source/cmDependsFortran.cxx693
-rw-r--r--Source/cmDependsFortran.h92
-rw-r--r--Source/cmDependsJava.cxx30
-rw-r--r--Source/cmDependsJava.h37
-rw-r--r--Source/cmDependsJavaParserHelper.cxx335
-rw-r--r--Source/cmDependsJavaParserHelper.h98
-rw-r--r--Source/cmDocumentation.cxx708
-rw-r--r--Source/cmDocumentation.h126
-rw-r--r--Source/cmDocumentationEntry.h34
-rw-r--r--Source/cmDocumentationFormatter.cxx188
-rw-r--r--Source/cmDocumentationFormatter.h63
-rw-r--r--Source/cmDocumentationSection.cxx28
-rw-r--r--Source/cmDocumentationSection.h68
-rw-r--r--Source/cmDuration.cxx27
-rw-r--r--Source/cmDuration.h24
-rw-r--r--Source/cmDynamicLoader.cxx92
-rw-r--r--Source/cmDynamicLoader.h30
-rw-r--r--Source/cmELF.cxx840
-rw-r--r--Source/cmELF.h113
-rw-r--r--Source/cmEnableLanguageCommand.cxx28
-rw-r--r--Source/cmEnableLanguageCommand.h13
-rw-r--r--Source/cmEnableTestingCommand.cxx13
-rw-r--r--Source/cmEnableTestingCommand.h26
-rw-r--r--Source/cmExecProgramCommand.cxx290
-rw-r--r--Source/cmExecProgramCommand.h20
-rw-r--r--Source/cmExecuteProcessCommand.cxx527
-rw-r--r--Source/cmExecuteProcessCommand.h19
-rw-r--r--Source/cmExecutionStatus.h49
-rw-r--r--Source/cmExpandedCommandArgument.cxx39
-rw-r--r--Source/cmExpandedCommandArgument.h34
-rw-r--r--Source/cmExportBuildAndroidMKGenerator.cxx193
-rw-r--r--Source/cmExportBuildAndroidMKGenerator.h64
-rw-r--r--Source/cmExportBuildFileGenerator.cxx357
-rw-r--r--Source/cmExportBuildFileGenerator.h86
-rw-r--r--Source/cmExportCommand.cxx393
-rw-r--r--Source/cmExportCommand.h13
-rw-r--r--Source/cmExportFileGenerator.cxx1251
-rw-r--r--Source/cmExportFileGenerator.h224
-rw-r--r--Source/cmExportInstallAndroidMKGenerator.cxx138
-rw-r--r--Source/cmExportInstallAndroidMKGenerator.h70
-rw-r--r--Source/cmExportInstallFileGenerator.cxx535
-rw-r--r--Source/cmExportInstallFileGenerator.h104
-rw-r--r--Source/cmExportLibraryDependenciesCommand.cxx163
-rw-r--r--Source/cmExportLibraryDependenciesCommand.h13
-rw-r--r--Source/cmExportSet.cxx44
-rw-r--r--Source/cmExportSet.h62
-rw-r--r--Source/cmExportTryCompileFileGenerator.cxx139
-rw-r--r--Source/cmExportTryCompileFileGenerator.h59
-rw-r--r--Source/cmExprParserHelper.cxx119
-rw-r--r--Source/cmExprParserHelper.h59
-rw-r--r--Source/cmExternalMakefileProjectGenerator.cxx67
-rw-r--r--Source/cmExternalMakefileProjectGenerator.h110
-rw-r--r--Source/cmExtraCodeBlocksGenerator.cxx754
-rw-r--r--Source/cmExtraCodeBlocksGenerator.h52
-rw-r--r--Source/cmExtraCodeLiteGenerator.cxx683
-rw-r--r--Source/cmExtraCodeLiteGenerator.h68
-rw-r--r--Source/cmExtraEclipseCDT4Generator.cxx1209
-rw-r--r--Source/cmExtraEclipseCDT4Generator.h107
-rw-r--r--Source/cmExtraKateGenerator.cxx294
-rw-r--r--Source/cmExtraKateGenerator.h44
-rw-r--r--Source/cmExtraSublimeTextGenerator.cxx465
-rw-r--r--Source/cmExtraSublimeTextGenerator.h76
-rw-r--r--Source/cmFLTKWrapUICommand.cxx133
-rw-r--r--Source/cmFLTKWrapUICommand.h13
-rw-r--r--Source/cmFSPermissions.cxx34
-rw-r--r--Source/cmFSPermissions.h42
-rw-r--r--Source/cmFileAPI.cxx895
-rw-r--r--Source/cmFileAPI.h211
-rw-r--r--Source/cmFileAPICMakeFiles.cxx115
-rw-r--r--Source/cmFileAPICMakeFiles.h12
-rw-r--r--Source/cmFileAPICache.cxx108
-rw-r--r--Source/cmFileAPICache.h12
-rw-r--r--Source/cmFileAPICodemodel.cxx1851
-rw-r--r--Source/cmFileAPICodemodel.h12
-rw-r--r--Source/cmFileAPIToolchains.cxx151
-rw-r--r--Source/cmFileAPIToolchains.h12
-rw-r--r--Source/cmFileCommand.cxx3735
-rw-r--r--Source/cmFileCommand.h13
-rw-r--r--Source/cmFileCopier.cxx712
-rw-r--r--Source/cmFileCopier.h121
-rw-r--r--Source/cmFileInstaller.cxx351
-rw-r--r--Source/cmFileInstaller.h51
-rw-r--r--Source/cmFileLock.cxx88
-rw-r--r--Source/cmFileLock.h64
-rw-r--r--Source/cmFileLockPool.cxx153
-rw-r--r--Source/cmFileLockPool.h87
-rw-r--r--Source/cmFileLockResult.cxx87
-rw-r--r--Source/cmFileLockResult.h74
-rw-r--r--Source/cmFileLockUnix.cxx76
-rw-r--r--Source/cmFileLockWin32.cxx87
-rw-r--r--Source/cmFilePathChecksum.cxx86
-rw-r--r--Source/cmFilePathChecksum.h61
-rw-r--r--Source/cmFileTime.cxx51
-rw-r--r--Source/cmFileTime.h139
-rw-r--r--Source/cmFileTimeCache.cxx64
-rw-r--r--Source/cmFileTimeCache.h54
-rw-r--r--Source/cmFileTimes.cxx129
-rw-r--r--Source/cmFileTimes.h37
-rw-r--r--Source/cmFindBase.cxx405
-rw-r--r--Source/cmFindBase.h95
-rw-r--r--Source/cmFindCommon.cxx375
-rw-r--r--Source/cmFindCommon.h144
-rw-r--r--Source/cmFindFileCommand.cxx17
-rw-r--r--Source/cmFindFileCommand.h29
-rw-r--r--Source/cmFindLibraryCommand.cxx567
-rw-r--r--Source/cmFindLibraryCommand.h45
-rw-r--r--Source/cmFindPackageCommand.cxx2500
-rw-r--r--Source/cmFindPackageCommand.h255
-rw-r--r--Source/cmFindPathCommand.cxx168
-rw-r--r--Source/cmFindPathCommand.h39
-rw-r--r--Source/cmFindProgramCommand.cxx341
-rw-r--r--Source/cmFindProgramCommand.h39
-rw-r--r--Source/cmForEachCommand.cxx469
-rw-r--r--Source/cmForEachCommand.h14
-rw-r--r--Source/cmFortranParser.h182
-rw-r--r--Source/cmFortranParserImpl.cxx433
-rw-r--r--Source/cmFunctionBlocker.cxx48
-rw-r--r--Source/cmFunctionBlocker.h50
-rw-r--r--Source/cmFunctionCommand.cxx189
-rw-r--r--Source/cmFunctionCommand.h14
-rw-r--r--Source/cmGccDepfileLexerHelper.cxx149
-rw-r--r--Source/cmGccDepfileLexerHelper.h38
-rw-r--r--Source/cmGccDepfileReader.cxx46
-rw-r--r--Source/cmGccDepfileReader.h15
-rw-r--r--Source/cmGccDepfileReaderTypes.h14
-rw-r--r--Source/cmGeneratedFileStream.cxx242
-rw-r--r--Source/cmGeneratedFileStream.h159
-rw-r--r--Source/cmGeneratorExpression.cxx408
-rw-r--r--Source/cmGeneratorExpression.h209
-rw-r--r--Source/cmGeneratorExpressionContext.cxx25
-rw-r--r--Source/cmGeneratorExpressionContext.h44
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.cxx248
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.h100
-rw-r--r--Source/cmGeneratorExpressionEvaluationFile.cxx274
-rw-r--r--Source/cmGeneratorExpressionEvaluationFile.h64
-rw-r--r--Source/cmGeneratorExpressionEvaluator.cxx174
-rw-r--r--Source/cmGeneratorExpressionEvaluator.h115
-rw-r--r--Source/cmGeneratorExpressionLexer.cxx64
-rw-r--r--Source/cmGeneratorExpressionLexer.h50
-rw-r--r--Source/cmGeneratorExpressionNode.cxx2697
-rw-r--r--Source/cmGeneratorExpressionNode.h53
-rw-r--r--Source/cmGeneratorExpressionParser.cxx249
-rw-r--r--Source/cmGeneratorExpressionParser.h30
-rw-r--r--Source/cmGeneratorTarget.cxx7719
-rw-r--r--Source/cmGeneratorTarget.h1127
-rw-r--r--Source/cmGetCMakePropertyCommand.cxx52
-rw-r--r--Source/cmGetCMakePropertyCommand.h13
-rw-r--r--Source/cmGetDirectoryPropertyCommand.cxx108
-rw-r--r--Source/cmGetDirectoryPropertyCommand.h13
-rw-r--r--Source/cmGetFilenameComponentCommand.cxx140
-rw-r--r--Source/cmGetFilenameComponentCommand.h19
-rw-r--r--Source/cmGetPipes.cxx48
-rw-r--r--Source/cmGetPipes.h5
-rw-r--r--Source/cmGetPropertyCommand.cxx478
-rw-r--r--Source/cmGetPropertyCommand.h13
-rw-r--r--Source/cmGetSourceFilePropertyCommand.cxx75
-rw-r--r--Source/cmGetSourceFilePropertyCommand.h13
-rw-r--r--Source/cmGetTargetPropertyCommand.cxx88
-rw-r--r--Source/cmGetTargetPropertyCommand.h13
-rw-r--r--Source/cmGetTestPropertyCommand.cxx33
-rw-r--r--Source/cmGetTestPropertyCommand.h13
-rw-r--r--Source/cmGhsMultiGpj.cxx39
-rw-r--r--Source/cmGhsMultiGpj.h26
-rw-r--r--Source/cmGhsMultiTargetGenerator.cxx781
-rw-r--r--Source/cmGhsMultiTargetGenerator.h83
-rw-r--r--Source/cmGlobVerificationManager.cxx181
-rw-r--r--Source/cmGlobVerificationManager.h82
-rw-r--r--Source/cmGlobalBorlandMakefileGenerator.cxx96
-rw-r--r--Source/cmGlobalBorlandMakefileGenerator.h59
-rw-r--r--Source/cmGlobalCommonGenerator.cxx97
-rw-r--r--Source/cmGlobalCommonGenerator.h45
-rw-r--r--Source/cmGlobalGenerator.cxx3331
-rw-r--r--Source/cmGlobalGenerator.h759
-rw-r--r--Source/cmGlobalGeneratorFactory.h96
-rw-r--r--Source/cmGlobalGhsMultiGenerator.cxx744
-rw-r--r--Source/cmGlobalGhsMultiGenerator.h159
-rw-r--r--Source/cmGlobalJOMMakefileGenerator.cxx81
-rw-r--r--Source/cmGlobalJOMMakefileGenerator.h54
-rw-r--r--Source/cmGlobalMSYSMakefileGenerator.cxx88
-rw-r--r--Source/cmGlobalMSYSMakefileGenerator.h43
-rw-r--r--Source/cmGlobalMinGWMakefileGenerator.cxx58
-rw-r--r--Source/cmGlobalMinGWMakefileGenerator.h39
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.cxx94
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.h60
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx2918
-rw-r--r--Source/cmGlobalNinjaGenerator.h725
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.cxx1014
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.h287
-rw-r--r--Source/cmGlobalVisualStudio10Generator.cxx1655
-rw-r--r--Source/cmGlobalVisualStudio10Generator.h275
-rw-r--r--Source/cmGlobalVisualStudio11Generator.cxx302
-rw-r--r--Source/cmGlobalVisualStudio11Generator.h54
-rw-r--r--Source/cmGlobalVisualStudio12Generator.cxx242
-rw-r--r--Source/cmGlobalVisualStudio12Generator.h49
-rw-r--r--Source/cmGlobalVisualStudio14Generator.cxx370
-rw-r--r--Source/cmGlobalVisualStudio14Generator.h65
-rw-r--r--Source/cmGlobalVisualStudio71Generator.cxx218
-rw-r--r--Source/cmGlobalVisualStudio71Generator.h43
-rw-r--r--Source/cmGlobalVisualStudio7Generator.cxx719
-rw-r--r--Source/cmGlobalVisualStudio7Generator.h175
-rw-r--r--Source/cmGlobalVisualStudio8Generator.cxx394
-rw-r--r--Source/cmGlobalVisualStudio8Generator.h79
-rw-r--r--Source/cmGlobalVisualStudio9Generator.cxx158
-rw-r--r--Source/cmGlobalVisualStudio9Generator.h39
-rw-r--r--Source/cmGlobalVisualStudioGenerator.cxx969
-rw-r--r--Source/cmGlobalVisualStudioGenerator.h230
-rw-r--r--Source/cmGlobalVisualStudioVersionedGenerator.cxx634
-rw-r--r--Source/cmGlobalVisualStudioVersionedGenerator.h70
-rw-r--r--Source/cmGlobalWatcomWMakeGenerator.cxx91
-rw-r--r--Source/cmGlobalWatcomWMakeGenerator.h65
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx4827
-rw-r--r--Source/cmGlobalXCodeGenerator.h352
-rw-r--r--Source/cmGraphAdjacencyList.h49
-rw-r--r--Source/cmGraphVizWriter.cxx617
-rw-r--r--Source/cmGraphVizWriter.h137
-rw-r--r--Source/cmHexFileConverter.cxx212
-rw-r--r--Source/cmHexFileConverter.h26
-rw-r--r--Source/cmIDEFlagTable.h38
-rw-r--r--Source/cmIDEOptions.cxx257
-rw-r--r--Source/cmIDEOptions.h113
-rw-r--r--Source/cmIfCommand.cxx207
-rw-r--r--Source/cmIfCommand.h14
-rw-r--r--Source/cmIncludeCommand.cxx185
-rw-r--r--Source/cmIncludeCommand.h19
-rw-r--r--Source/cmIncludeDirectoryCommand.cxx132
-rw-r--r--Source/cmIncludeDirectoryCommand.h13
-rw-r--r--Source/cmIncludeExternalMSProjectCommand.cxx105
-rw-r--r--Source/cmIncludeExternalMSProjectCommand.h13
-rw-r--r--Source/cmIncludeGuardCommand.cxx108
-rw-r--r--Source/cmIncludeGuardCommand.h19
-rw-r--r--Source/cmIncludeRegularExpressionCommand.cxx24
-rw-r--r--Source/cmIncludeRegularExpressionCommand.h13
-rw-r--r--Source/cmInstallCommand.cxx1707
-rw-r--r--Source/cmInstallCommand.h13
-rw-r--r--Source/cmInstallCommandArguments.cxx222
-rw-r--r--Source/cmInstallCommandArguments.h73
-rw-r--r--Source/cmInstallDirectoryGenerator.cxx113
-rw-r--r--Source/cmInstallDirectoryGenerator.h51
-rw-r--r--Source/cmInstallExportGenerator.cxx222
-rw-r--r--Source/cmInstallExportGenerator.h73
-rw-r--r--Source/cmInstallFilesCommand.cxx160
-rw-r--r--Source/cmInstallFilesCommand.h13
-rw-r--r--Source/cmInstallFilesGenerator.cxx113
-rw-r--r--Source/cmInstallFilesGenerator.h53
-rw-r--r--Source/cmInstallGenerator.cxx207
-rw-r--r--Source/cmInstallGenerator.h83
-rw-r--r--Source/cmInstallProgramsCommand.cxx134
-rw-r--r--Source/cmInstallProgramsCommand.h13
-rw-r--r--Source/cmInstallScriptGenerator.cxx93
-rw-r--r--Source/cmInstallScriptGenerator.h45
-rw-r--r--Source/cmInstallSubdirectoryGenerator.cxx79
-rw-r--r--Source/cmInstallSubdirectoryGenerator.h40
-rw-r--r--Source/cmInstallTargetGenerator.cxx927
-rw-r--r--Source/cmInstallTargetGenerator.h135
-rw-r--r--Source/cmInstallTargetsCommand.cxx58
-rw-r--r--Source/cmInstallTargetsCommand.h13
-rw-r--r--Source/cmInstallType.h17
-rw-r--r--Source/cmInstalledFile.cxx107
-rw-r--r--Source/cmInstalledFile.h77
-rw-r--r--Source/cmJSONHelpers.h315
-rw-r--r--Source/cmLDConfigLDConfigTool.cxx71
-rw-r--r--Source/cmLDConfigLDConfigTool.h19
-rw-r--r--Source/cmLDConfigTool.cxx9
-rw-r--r--Source/cmLDConfigTool.h21
-rw-r--r--Source/cmLinkDirectoriesCommand.cxx84
-rw-r--r--Source/cmLinkDirectoriesCommand.h13
-rw-r--r--Source/cmLinkItem.cxx71
-rw-r--r--Source/cmLinkItem.h141
-rw-r--r--Source/cmLinkItemGraphVisitor.cxx140
-rw-r--r--Source/cmLinkItemGraphVisitor.h72
-rw-r--r--Source/cmLinkLibrariesCommand.cxx39
-rw-r--r--Source/cmLinkLibrariesCommand.h13
-rw-r--r--Source/cmLinkLineComputer.cxx273
-rw-r--r--Source/cmLinkLineComputer.h74
-rw-r--r--Source/cmLinkLineDeviceComputer.cxx216
-rw-r--r--Source/cmLinkLineDeviceComputer.h43
-rw-r--r--Source/cmLinkedTree.h189
-rw-r--r--Source/cmListCommand.cxx1547
-rw-r--r--Source/cmListCommand.h17
-rw-r--r--Source/cmListFileCache.cxx654
-rw-r--r--Source/cmListFileCache.h281
-rw-r--r--Source/cmListFileLexer.h68
-rw-r--r--Source/cmLoadCacheCommand.cxx183
-rw-r--r--Source/cmLoadCacheCommand.h13
-rw-r--r--Source/cmLoadCommandCommand.cxx271
-rw-r--r--Source/cmLoadCommandCommand.h13
-rw-r--r--Source/cmLocalCommonGenerator.cxx93
-rw-r--r--Source/cmLocalCommonGenerator.h48
-rw-r--r--Source/cmLocalGenerator.cxx4500
-rw-r--r--Source/cmLocalGenerator.h737
-rw-r--r--Source/cmLocalGhsMultiGenerator.cxx80
-rw-r--r--Source/cmLocalGhsMultiGenerator.h39
-rw-r--r--Source/cmLocalNinjaGenerator.cxx913
-rw-r--r--Source/cmLocalNinjaGenerator.h133
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx2239
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.h306
-rw-r--r--Source/cmLocalVisualStudio10Generator.cxx103
-rw-r--r--Source/cmLocalVisualStudio10Generator.h37
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx2172
-rw-r--r--Source/cmLocalVisualStudio7Generator.h160
-rw-r--r--Source/cmLocalVisualStudioGenerator.cxx244
-rw-r--r--Source/cmLocalVisualStudioGenerator.h57
-rw-r--r--Source/cmLocalXCodeGenerator.cxx132
-rw-r--r--Source/cmLocalXCodeGenerator.h41
-rw-r--r--Source/cmLocale.h26
-rw-r--r--Source/cmMSVC60LinkLineComputer.cxx40
-rw-r--r--Source/cmMSVC60LinkLineComputer.h26
-rw-r--r--Source/cmMachO.cxx355
-rw-r--r--Source/cmMachO.h44
-rw-r--r--Source/cmMacroCommand.cxx197
-rw-r--r--Source/cmMacroCommand.h14
-rw-r--r--Source/cmMakeDirectoryCommand.cxx26
-rw-r--r--Source/cmMakeDirectoryCommand.h22
-rw-r--r--Source/cmMakefile.cxx4517
-rw-r--r--Source/cmMakefile.h1097
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx677
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.h33
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx962
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.h45
-rw-r--r--Source/cmMakefileProfilingData.cxx114
-rw-r--r--Source/cmMakefileProfilingData.h27
-rw-r--r--Source/cmMakefileTargetGenerator.cxx2268
-rw-r--r--Source/cmMakefileTargetGenerator.h256
-rw-r--r--Source/cmMakefileUtilityTargetGenerator.cxx145
-rw-r--r--Source/cmMakefileUtilityTargetGenerator.h22
-rw-r--r--Source/cmMarkAsAdvancedCommand.cxx100
-rw-r--r--Source/cmMarkAsAdvancedCommand.h18
-rw-r--r--Source/cmMathCommand.cxx120
-rw-r--r--Source/cmMathCommand.h14
-rw-r--r--Source/cmMessageCommand.cxx228
-rw-r--r--Source/cmMessageCommand.h17
-rw-r--r--Source/cmMessageType.h18
-rw-r--r--Source/cmMessenger.cxx168
-rw-r--r--Source/cmMessenger.h58
-rw-r--r--Source/cmNewLineStyle.cxx65
-rw-r--r--Source/cmNewLineStyle.h36
-rw-r--r--Source/cmNinjaLinkLineComputer.cxx22
-rw-r--r--Source/cmNinjaLinkLineComputer.h30
-rw-r--r--Source/cmNinjaLinkLineDeviceComputer.cxx20
-rw-r--r--Source/cmNinjaLinkLineDeviceComputer.h31
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx1469
-rw-r--r--Source/cmNinjaNormalTargetGenerator.h59
-rw-r--r--Source/cmNinjaTargetGenerator.cxx1793
-rw-r--r--Source/cmNinjaTargetGenerator.h220
-rw-r--r--Source/cmNinjaTypes.h61
-rw-r--r--Source/cmNinjaUtilityTargetGenerator.cxx203
-rw-r--r--Source/cmNinjaUtilityTargetGenerator.h24
-rw-r--r--Source/cmOSXBundleGenerator.cxx217
-rw-r--r--Source/cmOSXBundleGenerator.h69
-rw-r--r--Source/cmOptionCommand.cxx86
-rw-r--r--Source/cmOptionCommand.h18
-rw-r--r--Source/cmOrderDirectories.cxx564
-rw-r--r--Source/cmOrderDirectories.h96
-rw-r--r--Source/cmOutputConverter.cxx529
-rw-r--r--Source/cmOutputConverter.h117
-rw-r--r--Source/cmOutputRequiredFilesCommand.cxx514
-rw-r--r--Source/cmOutputRequiredFilesCommand.h13
-rw-r--r--Source/cmParseArgumentsCommand.cxx222
-rw-r--r--Source/cmParseArgumentsCommand.h13
-rw-r--r--Source/cmPathLabel.cxx30
-rw-r--r--Source/cmPathLabel.h34
-rw-r--r--Source/cmPolicies.cxx443
-rw-r--r--Source/cmPolicies.h485
-rw-r--r--Source/cmProcessOutput.cxx170
-rw-r--r--Source/cmProcessOutput.h85
-rw-r--r--Source/cmProcessTools.cxx86
-rw-r--r--Source/cmProcessTools.h87
-rw-r--r--Source/cmProjectCommand.cxx402
-rw-r--r--Source/cmProjectCommand.h13
-rw-r--r--Source/cmProperty.h36
-rw-r--r--Source/cmPropertyDefinition.cxx39
-rw-r--r--Source/cmPropertyDefinition.h66
-rw-r--r--Source/cmPropertyMap.cxx78
-rw-r--r--Source/cmPropertyMap.h50
-rw-r--r--Source/cmQTWrapCPPCommand.cxx86
-rw-r--r--Source/cmQTWrapCPPCommand.h13
-rw-r--r--Source/cmQTWrapUICommand.cxx111
-rw-r--r--Source/cmQTWrapUICommand.h13
-rw-r--r--Source/cmQtAutoGen.cxx386
-rw-r--r--Source/cmQtAutoGen.h141
-rw-r--r--Source/cmQtAutoGenGlobalInitializer.cxx302
-rw-r--r--Source/cmQtAutoGenGlobalInitializer.h81
-rw-r--r--Source/cmQtAutoGenInitializer.cxx2039
-rw-r--r--Source/cmQtAutoGenInitializer.h258
-rw-r--r--Source/cmQtAutoGenerator.cxx495
-rw-r--r--Source/cmQtAutoGenerator.h175
-rw-r--r--Source/cmQtAutoMocUic.cxx2999
-rw-r--r--Source/cmQtAutoMocUic.h13
-rw-r--r--Source/cmQtAutoRcc.cxx527
-rw-r--r--Source/cmQtAutoRcc.h13
-rw-r--r--Source/cmRST.cxx475
-rw-r--r--Source/cmRST.h98
-rw-r--r--Source/cmRange.h236
-rw-r--r--Source/cmRemoveCommand.cxx57
-rw-r--r--Source/cmRemoveCommand.h18
-rw-r--r--Source/cmRemoveDefinitionsCommand.cxx16
-rw-r--r--Source/cmRemoveDefinitionsCommand.h13
-rw-r--r--Source/cmReturnCommand.cxx13
-rw-r--r--Source/cmReturnCommand.h14
-rw-r--r--Source/cmRulePlaceholderExpander.cxx374
-rw-r--r--Source/cmRulePlaceholderExpander.h89
-rw-r--r--Source/cmRuntimeDependencyArchive.cxx378
-rw-r--r--Source/cmRuntimeDependencyArchive.h67
-rw-r--r--Source/cmScanDepFormat.cxx265
-rw-r--r--Source/cmScanDepFormat.h30
-rw-r--r--Source/cmScriptGenerator.cxx176
-rw-r--r--Source/cmScriptGenerator.h91
-rw-r--r--Source/cmSearchPath.cxx221
-rw-r--r--Source/cmSearchPath.h51
-rw-r--r--Source/cmSeparateArgumentsCommand.cxx165
-rw-r--r--Source/cmSeparateArgumentsCommand.h18
-rw-r--r--Source/cmSetCommand.cxx160
-rw-r--r--Source/cmSetCommand.h18
-rw-r--r--Source/cmSetDirectoryPropertiesCommand.cxx39
-rw-r--r--Source/cmSetDirectoryPropertiesCommand.h13
-rw-r--r--Source/cmSetPropertyCommand.cxx798
-rw-r--r--Source/cmSetPropertyCommand.h55
-rw-r--r--Source/cmSetSourceFilesPropertiesCommand.cxx182
-rw-r--r--Source/cmSetSourceFilesPropertiesCommand.h13
-rw-r--r--Source/cmSetTargetPropertiesCommand.cxx55
-rw-r--r--Source/cmSetTargetPropertiesCommand.h13
-rw-r--r--Source/cmSetTestsPropertiesCommand.cxx50
-rw-r--r--Source/cmSetTestsPropertiesCommand.h13
-rw-r--r--Source/cmSiteNameCommand.cxx80
-rw-r--r--Source/cmSiteNameCommand.h18
-rw-r--r--Source/cmSourceFile.cxx471
-rw-r--r--Source/cmSourceFile.h183
-rw-r--r--Source/cmSourceFileLocation.cxx235
-rw-r--r--Source/cmSourceFileLocation.h103
-rw-r--r--Source/cmSourceFileLocationKind.h12
-rw-r--r--Source/cmSourceGroup.cxx145
-rw-r--r--Source/cmSourceGroup.h126
-rw-r--r--Source/cmSourceGroupCommand.cxx310
-rw-r--r--Source/cmSourceGroupCommand.h13
-rw-r--r--Source/cmStandardLevelResolver.cxx540
-rw-r--r--Source/cmStandardLevelResolver.h57
-rw-r--r--Source/cmStandardLexer.h80
-rw-r--r--Source/cmState.cxx1072
-rw-r--r--Source/cmState.h260
-rw-r--r--Source/cmStateDirectory.cxx664
-rw-r--r--Source/cmStateDirectory.h104
-rw-r--r--Source/cmStatePrivate.h100
-rw-r--r--Source/cmStateSnapshot.cxx448
-rw-r--r--Source/cmStateSnapshot.h88
-rw-r--r--Source/cmStateTypes.h62
-rw-r--r--Source/cmString.cxx154
-rw-r--r--Source/cmString.hxx937
-rw-r--r--Source/cmStringAlgorithms.cxx379
-rw-r--r--Source/cmStringAlgorithms.h325
-rw-r--r--Source/cmStringCommand.cxx1280
-rw-r--r--Source/cmStringCommand.h17
-rw-r--r--Source/cmStringReplaceHelper.cxx121
-rw-r--r--Source/cmStringReplaceHelper.h65
-rw-r--r--Source/cmSubcommandTable.cxx31
-rw-r--r--Source/cmSubcommandTable.h33
-rw-r--r--Source/cmSubdirCommand.cxx51
-rw-r--r--Source/cmSubdirCommand.h13
-rw-r--r--Source/cmSubdirDependsCommand.cxx11
-rw-r--r--Source/cmSubdirDependsCommand.h13
-rw-r--r--Source/cmSystemTools.cxx3255
-rw-r--r--Source/cmSystemTools.h510
-rw-r--r--Source/cmTarget.cxx2262
-rw-r--r--Source/cmTarget.h292
-rw-r--r--Source/cmTargetCompileDefinitionsCommand.cxx58
-rw-r--r--Source/cmTargetCompileDefinitionsCommand.h13
-rw-r--r--Source/cmTargetCompileFeaturesCommand.cxx57
-rw-r--r--Source/cmTargetCompileFeaturesCommand.h13
-rw-r--r--Source/cmTargetCompileOptionsCommand.cxx57
-rw-r--r--Source/cmTargetCompileOptionsCommand.h13
-rw-r--r--Source/cmTargetDepend.h61
-rw-r--r--Source/cmTargetExport.h36
-rw-r--r--Source/cmTargetIncludeDirectoriesCommand.cxx106
-rw-r--r--Source/cmTargetIncludeDirectoriesCommand.h13
-rw-r--r--Source/cmTargetLinkDirectoriesCommand.cxx70
-rw-r--r--Source/cmTargetLinkDirectoriesCommand.h13
-rw-r--r--Source/cmTargetLinkLibrariesCommand.cxx582
-rw-r--r--Source/cmTargetLinkLibrariesCommand.h13
-rw-r--r--Source/cmTargetLinkLibraryType.h10
-rw-r--r--Source/cmTargetLinkOptionsCommand.cxx50
-rw-r--r--Source/cmTargetLinkOptionsCommand.h13
-rw-r--r--Source/cmTargetPrecompileHeadersCommand.cxx86
-rw-r--r--Source/cmTargetPrecompileHeadersCommand.h13
-rw-r--r--Source/cmTargetPropCommandBase.cxx191
-rw-r--r--Source/cmTargetPropCommandBase.h60
-rw-r--r--Source/cmTargetPropertyComputer.cxx43
-rw-r--r--Source/cmTargetPropertyComputer.h102
-rw-r--r--Source/cmTargetSourcesCommand.cxx138
-rw-r--r--Source/cmTargetSourcesCommand.h13
-rw-r--r--Source/cmTest.cxx75
-rw-r--r--Source/cmTest.h67
-rw-r--r--Source/cmTestGenerator.cxx334
-rw-r--r--Source/cmTestGenerator.h57
-rw-r--r--Source/cmTimestamp.cxx196
-rw-r--r--Source/cmTimestamp.h31
-rw-r--r--Source/cmTransformDepfile.cxx122
-rw-r--r--Source/cmTransformDepfile.h16
-rw-r--r--Source/cmTryCompileCommand.cxx36
-rw-r--r--Source/cmTryCompileCommand.h39
-rw-r--r--Source/cmTryRunCommand.cxx376
-rw-r--r--Source/cmTryRunCommand.h53
-rw-r--r--Source/cmUVHandlePtr.cxx269
-rw-r--r--Source/cmUVHandlePtr.h271
-rw-r--r--Source/cmUVProcessChain.cxx396
-rw-r--r--Source/cmUVProcessChain.h97
-rw-r--r--Source/cmUVSignalHackRAII.h45
-rw-r--r--Source/cmUVStreambuf.h216
-rw-r--r--Source/cmUnsetCommand.cxx49
-rw-r--r--Source/cmUnsetCommand.h18
-rw-r--r--Source/cmUseMangledMesaCommand.cxx103
-rw-r--r--Source/cmUseMangledMesaCommand.h13
-rw-r--r--Source/cmUtilitySourceCommand.cxx118
-rw-r--r--Source/cmUtilitySourceCommand.h13
-rw-r--r--Source/cmUtils.hxx14
-rw-r--r--Source/cmUuid.cxx167
-rw-r--r--Source/cmUuid.h42
-rw-r--r--Source/cmVSSetupHelper.cxx493
-rw-r--r--Source/cmVSSetupHelper.h137
-rw-r--r--Source/cmVariableRequiresCommand.cxx64
-rw-r--r--Source/cmVariableRequiresCommand.h13
-rw-r--r--Source/cmVariableWatch.cxx86
-rw-r--r--Source/cmVariableWatch.h82
-rw-r--r--Source/cmVariableWatchCommand.cxx155
-rw-r--r--Source/cmVariableWatchCommand.h17
-rw-r--r--Source/cmVersion.cxx27
-rw-r--r--Source/cmVersion.h31
-rw-r--r--Source/cmVersionConfig.h.in8
-rw-r--r--Source/cmVersionMacros.h10
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx5088
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h260
-rw-r--r--Source/cmVisualStudioGeneratorOptions.cxx514
-rw-r--r--Source/cmVisualStudioGeneratorOptions.h101
-rw-r--r--Source/cmVisualStudioSlnData.cxx49
-rw-r--r--Source/cmVisualStudioSlnData.h51
-rw-r--r--Source/cmVisualStudioSlnParser.cxx629
-rw-r--r--Source/cmVisualStudioSlnParser.h104
-rw-r--r--Source/cmVisualStudioWCEPlatformParser.cxx139
-rw-r--r--Source/cmVisualStudioWCEPlatformParser.h68
-rw-r--r--Source/cmWhileCommand.cxx138
-rw-r--r--Source/cmWhileCommand.h14
-rw-r--r--Source/cmWorkerPool.cxx781
-rw-r--r--Source/cmWorkerPool.h221
-rw-r--r--Source/cmWorkingDirectory.cxx36
-rw-r--r--Source/cmWorkingDirectory.h44
-rw-r--r--Source/cmWriteFileCommand.cxx82
-rw-r--r--Source/cmWriteFileCommand.h17
-rw-r--r--Source/cmXCOFF.cxx356
-rw-r--r--Source/cmXCOFF.h65
-rw-r--r--Source/cmXCode21Object.cxx88
-rw-r--r--Source/cmXCode21Object.h22
-rw-r--r--Source/cmXCodeObject.cxx233
-rw-r--r--Source/cmXCodeObject.h179
-rw-r--r--Source/cmXCodeScheme.cxx455
-rw-r--r--Source/cmXCodeScheme.h75
-rw-r--r--Source/cmXMLParser.cxx204
-rw-r--r--Source/cmXMLParser.h108
-rw-r--r--Source/cmXMLSafe.cxx90
-rw-r--r--Source/cmXMLSafe.h34
-rw-r--r--Source/cmXMLWriter.cxx145
-rw-r--r--Source/cmXMLWriter.h195
-rw-r--r--Source/cm_codecvt.cxx244
-rw-r--r--Source/cm_codecvt.hxx63
-rw-r--r--Source/cm_get_date.c11
-rw-r--r--Source/cm_get_date.h16
-rw-r--r--Source/cm_sys_stat.h11
-rw-r--r--Source/cm_utf8.c106
-rw-r--r--Source/cm_utf8.h21
-rw-r--r--Source/cmake.cxx3557
-rw-r--r--Source/cmake.h829
-rw-r--r--Source/cmake.version.manifest18
-rw-r--r--Source/cmakemain.cxx967
-rw-r--r--Source/cmcldeps.cxx302
-rw-r--r--Source/cmcmd.cxx2412
-rw-r--r--Source/cmcmd.h41
-rw-r--r--Source/ctest.cxx231
-rw-r--r--Source/dir.dox7
-rw-r--r--Source/dir.dox.in7
-rw-r--r--Source/kwsys/.gitattributes13
-rw-r--r--Source/kwsys/Base64.c (renamed from Base64.c)0
-rw-r--r--Source/kwsys/Base64.h.in (renamed from Base64.h.in)0
-rw-r--r--Source/kwsys/CMakeLists.txt1147
-rw-r--r--Source/kwsys/CONTRIBUTING.rst49
-rw-r--r--Source/kwsys/CTestConfig.cmake11
-rw-r--r--Source/kwsys/CTestCustom.cmake.in18
-rw-r--r--Source/kwsys/CommandLineArguments.cxx (renamed from CommandLineArguments.cxx)0
-rw-r--r--Source/kwsys/CommandLineArguments.hxx.in (renamed from CommandLineArguments.hxx.in)0
-rw-r--r--Source/kwsys/Configure.h.in (renamed from Configure.h.in)0
-rw-r--r--Source/kwsys/Configure.hxx.in (renamed from Configure.hxx.in)0
-rw-r--r--Source/kwsys/ConsoleBuf.hxx.in (renamed from ConsoleBuf.hxx.in)0
-rw-r--r--Source/kwsys/Copyright.txt38
-rw-r--r--Source/kwsys/Directory.cxx (renamed from Directory.cxx)0
-rw-r--r--Source/kwsys/Directory.hxx.in (renamed from Directory.hxx.in)0
-rw-r--r--Source/kwsys/DynamicLoader.cxx (renamed from DynamicLoader.cxx)0
-rw-r--r--Source/kwsys/DynamicLoader.hxx.in (renamed from DynamicLoader.hxx.in)0
-rw-r--r--Source/kwsys/Encoding.h.in (renamed from Encoding.h.in)0
-rw-r--r--Source/kwsys/Encoding.hxx.in (renamed from Encoding.hxx.in)0
-rw-r--r--Source/kwsys/EncodingC.c (renamed from EncodingC.c)0
-rw-r--r--Source/kwsys/EncodingCXX.cxx (renamed from EncodingCXX.cxx)0
-rw-r--r--Source/kwsys/ExtraTest.cmake.in (renamed from ExtraTest.cmake.in)0
-rw-r--r--Source/kwsys/FStream.cxx (renamed from FStream.cxx)0
-rw-r--r--Source/kwsys/FStream.hxx.in (renamed from FStream.hxx.in)0
-rw-r--r--Source/kwsys/Glob.cxx (renamed from Glob.cxx)0
-rw-r--r--Source/kwsys/Glob.hxx.in (renamed from Glob.hxx.in)0
-rw-r--r--Source/kwsys/MD5.c (renamed from MD5.c)0
-rw-r--r--Source/kwsys/MD5.h.in (renamed from MD5.h.in)0
-rw-r--r--Source/kwsys/Process.h.in (renamed from Process.h.in)0
-rw-r--r--Source/kwsys/ProcessUNIX.c (renamed from ProcessUNIX.c)0
-rw-r--r--Source/kwsys/ProcessWin32.c (renamed from ProcessWin32.c)0
-rw-r--r--Source/kwsys/README.rst37
-rw-r--r--Source/kwsys/RegularExpression.cxx (renamed from RegularExpression.cxx)0
-rw-r--r--Source/kwsys/RegularExpression.hxx.in (renamed from RegularExpression.hxx.in)0
-rw-r--r--Source/kwsys/SharedForward.h.in (renamed from SharedForward.h.in)0
-rw-r--r--Source/kwsys/Status.cxx (renamed from Status.cxx)0
-rw-r--r--Source/kwsys/Status.hxx.in (renamed from Status.hxx.in)0
-rw-r--r--Source/kwsys/String.c (renamed from String.c)0
-rw-r--r--Source/kwsys/String.h.in (renamed from String.h.in)0
-rw-r--r--Source/kwsys/String.hxx.in (renamed from String.hxx.in)0
-rw-r--r--Source/kwsys/System.c (renamed from System.c)0
-rw-r--r--Source/kwsys/System.h.in (renamed from System.h.in)0
-rw-r--r--Source/kwsys/SystemInformation.cxx (renamed from SystemInformation.cxx)0
-rw-r--r--Source/kwsys/SystemInformation.hxx.in (renamed from SystemInformation.hxx.in)0
-rw-r--r--Source/kwsys/SystemTools.cxx (renamed from SystemTools.cxx)0
-rw-r--r--Source/kwsys/SystemTools.hxx.in (renamed from SystemTools.hxx.in)0
-rw-r--r--Source/kwsys/Terminal.c (renamed from Terminal.c)0
-rw-r--r--Source/kwsys/Terminal.h.in (renamed from Terminal.h.in)0
-rwxr-xr-xSource/kwsys/kwsysHeaderDump.pl (renamed from kwsysHeaderDump.pl)0
-rw-r--r--Source/kwsys/kwsysPlatformTests.cmake (renamed from kwsysPlatformTests.cmake)0
-rw-r--r--Source/kwsys/kwsysPlatformTestsC.c (renamed from kwsysPlatformTestsC.c)0
-rw-r--r--Source/kwsys/kwsysPlatformTestsCXX.cxx (renamed from kwsysPlatformTestsCXX.cxx)0
-rw-r--r--Source/kwsys/kwsysPrivate.h (renamed from kwsysPrivate.h)0
-rw-r--r--Source/kwsys/testCommandLineArguments.cxx (renamed from testCommandLineArguments.cxx)0
-rw-r--r--Source/kwsys/testCommandLineArguments1.cxx (renamed from testCommandLineArguments1.cxx)0
-rw-r--r--Source/kwsys/testConfigure.cxx (renamed from testConfigure.cxx)0
-rw-r--r--Source/kwsys/testConsoleBuf.cxx (renamed from testConsoleBuf.cxx)0
-rw-r--r--Source/kwsys/testConsoleBuf.hxx (renamed from testConsoleBuf.hxx)0
-rw-r--r--Source/kwsys/testConsoleBufChild.cxx (renamed from testConsoleBufChild.cxx)0
-rw-r--r--Source/kwsys/testDirectory.cxx (renamed from testDirectory.cxx)0
-rw-r--r--Source/kwsys/testDynamicLoader.cxx (renamed from testDynamicLoader.cxx)0
-rw-r--r--Source/kwsys/testDynload.c (renamed from testDynload.c)0
-rw-r--r--Source/kwsys/testDynloadImpl.c (renamed from testDynloadImpl.c)0
-rw-r--r--Source/kwsys/testDynloadImpl.h (renamed from testDynloadImpl.h)0
-rw-r--r--Source/kwsys/testDynloadUse.c (renamed from testDynloadUse.c)0
-rw-r--r--Source/kwsys/testEncode.c (renamed from testEncode.c)0
-rw-r--r--Source/kwsys/testEncoding.cxx (renamed from testEncoding.cxx)0
-rw-r--r--Source/kwsys/testFStream.cxx (renamed from testFStream.cxx)0
-rw-r--r--Source/kwsys/testFail.c (renamed from testFail.c)0
-rw-r--r--Source/kwsys/testProcess.c (renamed from testProcess.c)0
-rw-r--r--Source/kwsys/testSharedForward.c.in (renamed from testSharedForward.c.in)0
-rw-r--r--Source/kwsys/testStatus.cxx (renamed from testStatus.cxx)0
-rw-r--r--Source/kwsys/testSystemInformation.cxx (renamed from testSystemInformation.cxx)0
-rw-r--r--Source/kwsys/testSystemTools.bin (renamed from testSystemTools.bin)bin766 -> 766 bytes-rw-r--r--Source/kwsys/testSystemTools.cxx (renamed from testSystemTools.cxx)0
-rw-r--r--Source/kwsys/testSystemTools.h.in (renamed from testSystemTools.h.in)0
-rw-r--r--Source/kwsys/testTerminal.c (renamed from testTerminal.c)0
-rw-r--r--Templates/AppleInfo.plist34
-rw-r--r--Templates/CMakeVSMacros1.vsmacrosbin0 -> 88064 bytes-rw-r--r--Templates/CMakeVSMacros2.vsmacrosbin0 -> 63488 bytes-rw-r--r--Templates/CPack.GenericDescription.txt5
-rw-r--r--Templates/CPack.GenericLicense.txt5
-rw-r--r--Templates/CPack.GenericWelcome.txt1
-rw-r--r--Templates/CPackConfig.cmake.in20
-rw-r--r--Templates/CTestScript.cmake.in33
-rw-r--r--Templates/MSBuild/FlagTables/v10_CL.json981
-rw-r--r--Templates/MSBuild/FlagTables/v10_CSharp.json574
-rw-r--r--Templates/MSBuild/FlagTables/v10_Cuda.json244
-rw-r--r--Templates/MSBuild/FlagTables/v10_CudaHost.json149
-rw-r--r--Templates/MSBuild/FlagTables/v10_LIB.json297
-rw-r--r--Templates/MSBuild/FlagTables/v10_Link.json1137
-rw-r--r--Templates/MSBuild/FlagTables/v10_MASM.json295
-rw-r--r--Templates/MSBuild/FlagTables/v10_NASM.json201
-rw-r--r--Templates/MSBuild/FlagTables/v10_RC.json69
-rw-r--r--Templates/MSBuild/FlagTables/v11_CL.json1063
-rw-r--r--Templates/MSBuild/FlagTables/v11_CSharp.json574
-rw-r--r--Templates/MSBuild/FlagTables/v11_LIB.json297
-rw-r--r--Templates/MSBuild/FlagTables/v11_Link.json1272
-rw-r--r--Templates/MSBuild/FlagTables/v11_MASM.json295
-rw-r--r--Templates/MSBuild/FlagTables/v11_RC.json69
-rw-r--r--Templates/MSBuild/FlagTables/v12_CL.json1077
-rw-r--r--Templates/MSBuild/FlagTables/v12_CSharp.json574
-rw-r--r--Templates/MSBuild/FlagTables/v12_LIB.json297
-rw-r--r--Templates/MSBuild/FlagTables/v12_Link.json1272
-rw-r--r--Templates/MSBuild/FlagTables/v12_MASM.json295
-rw-r--r--Templates/MSBuild/FlagTables/v12_RC.json69
-rw-r--r--Templates/MSBuild/FlagTables/v140_CL.json1184
-rw-r--r--Templates/MSBuild/FlagTables/v140_CSharp.json574
-rw-r--r--Templates/MSBuild/FlagTables/v140_Link.json1316
-rw-r--r--Templates/MSBuild/FlagTables/v141_CL.json1268
-rw-r--r--Templates/MSBuild/FlagTables/v141_CSharp.json574
-rw-r--r--Templates/MSBuild/FlagTables/v141_Link.json1323
-rw-r--r--Templates/MSBuild/FlagTables/v142_CL.json1226
-rw-r--r--Templates/MSBuild/FlagTables/v142_CSharp.json592
-rw-r--r--Templates/MSBuild/FlagTables/v142_Link.json1330
-rw-r--r--Templates/MSBuild/FlagTables/v14_LIB.json311
-rw-r--r--Templates/MSBuild/FlagTables/v14_MASM.json295
-rw-r--r--Templates/MSBuild/FlagTables/v14_RC.json69
-rw-r--r--Templates/MSBuild/nasm.props.in17
-rw-r--r--Templates/MSBuild/nasm.targets41
-rw-r--r--Templates/MSBuild/nasm.xml110
-rw-r--r--Templates/TestDriver.cxx.in146
-rw-r--r--Templates/Windows/ApplicationIcon.pngbin0 -> 2335 bytes-rw-r--r--Templates/Windows/Logo.pngbin0 -> 488 bytes-rw-r--r--Templates/Windows/SmallLogo.pngbin0 -> 167 bytes-rw-r--r--Templates/Windows/SmallLogo44x44.pngbin0 -> 265 bytes-rw-r--r--Templates/Windows/SplashScreen.pngbin0 -> 909 bytes-rw-r--r--Templates/Windows/StoreLogo.pngbin0 -> 227 bytes-rw-r--r--Templates/Windows/Windows_TemporaryKey.pfxbin0 -> 2560 bytes-rw-r--r--Tests/.NoDartCoverage1
-rw-r--r--Tests/AliasTarget/CMakeLists.txt81
-rw-r--r--Tests/AliasTarget/bat.cpp28
-rw-r--r--Tests/AliasTarget/commandgenerator.cpp14
-rw-r--r--Tests/AliasTarget/empty.cpp7
-rw-r--r--Tests/AliasTarget/object.cpp5
-rw-r--r--Tests/AliasTarget/object.h4
-rw-r--r--Tests/AliasTarget/subdir/CMakeLists.txt8
-rw-r--r--Tests/AliasTarget/subdir/empty.cpp7
-rw-r--r--Tests/AliasTarget/targetgenerator.cpp12
-rw-r--r--Tests/Architecture/CMakeLists.txt59
-rw-r--r--Tests/Architecture/bar.c5
-rw-r--r--Tests/Architecture/foo.c4
-rw-r--r--Tests/ArgumentExpansion/CMakeLists.txt60
-rw-r--r--Tests/Assembler/CMakeLists.txt50
-rw-r--r--Tests/Assembler/main-linux-x86-gas.s28
-rw-r--r--Tests/Assembler/main.c14
-rw-r--r--Tests/BootstrapTest.cmake18
-rw-r--r--Tests/BuildDepends/CMakeLists.txt475
-rw-r--r--Tests/BuildDepends/Project/CMakeLists.txt225
-rw-r--r--Tests/BuildDepends/Project/External/CMakeLists.txt14
-rw-r--r--Tests/BuildDepends/Project/bar.cxx24
-rw-r--r--Tests/BuildDepends/Project/dep.cxx1
-rw-r--r--Tests/BuildDepends/Project/dep_custom.cxx1
-rw-r--r--Tests/BuildDepends/Project/dep_custom2.cxx2
-rw-r--r--Tests/BuildDepends/Project/generator.cxx19
-rw-r--r--Tests/BuildDepends/Project/link_depends_no_shared_check.cmake7
-rw-r--r--Tests/BuildDepends/Project/link_depends_no_shared_exe.c9
-rw-r--r--Tests/BuildDepends/Project/link_depends_no_shared_lib.c8
-rw-r--r--Tests/BuildDepends/Project/linkdep.cxx4
-rw-r--r--Tests/BuildDepends/Project/ninjadep.cpp8
-rw-r--r--Tests/BuildDepends/Project/object_depends.cxx4
-rw-r--r--Tests/BuildDepends/Project/object_depends_check.cmake7
-rw-r--r--Tests/BuildDepends/Project/zot.cxx15
-rw-r--r--Tests/BuildDepends/Project/zot_macro_dir.cxx7
-rw-r--r--Tests/BuildDepends/Project/zot_macro_tgt.cxx7
-rw-r--r--Tests/BuildDepends/Project/zot_pch.cxx6
-rw-r--r--Tests/BundleGeneratorTest/BundleIcon.icnsbin0 -> 33452 bytes-rw-r--r--Tests/BundleGeneratorTest/CMakeLists.txt33
-rw-r--r--Tests/BundleGeneratorTest/CustomVolumeIcon.icnsbin0 -> 37827 bytes-rw-r--r--Tests/BundleGeneratorTest/Executable.cxx7
-rw-r--r--Tests/BundleGeneratorTest/Info.plist14
-rw-r--r--Tests/BundleGeneratorTest/Library.cxx6
-rwxr-xr-xTests/BundleGeneratorTest/StartupCommand12
-rw-r--r--Tests/BundleTest/BundleLib.cxx62
-rw-r--r--Tests/BundleTest/BundleSubDir/CMakeLists.txt43
-rw-r--r--Tests/BundleTest/BundleTest.cxx21
-rw-r--r--Tests/BundleTest/CMakeLists.txt113
-rw-r--r--Tests/BundleTest/SomeRandomFile.txt0
-rw-r--r--Tests/BundleTest/randomResourceFile.plist.in9
-rw-r--r--Tests/BundleUtilities/CMakeLists.txt136
-rw-r--r--Tests/BundleUtilities/bundleutils.cmake45
-rw-r--r--Tests/BundleUtilities/framework.cpp9
-rw-r--r--Tests/BundleUtilities/framework.h17
-rw-r--r--Tests/BundleUtilities/module.cpp11
-rw-r--r--Tests/BundleUtilities/module.h7
-rw-r--r--Tests/BundleUtilities/shared.cpp9
-rw-r--r--Tests/BundleUtilities/shared.h17
-rw-r--r--Tests/BundleUtilities/shared2.cpp9
-rw-r--r--Tests/BundleUtilities/shared2.h17
-rw-r--r--Tests/BundleUtilities/testbundleutils1.cpp30
-rw-r--r--Tests/BundleUtilities/testbundleutils2.cpp30
-rw-r--r--Tests/BundleUtilities/testbundleutils3.cpp30
-rw-r--r--Tests/CFBundleTest/CMakeLists.txt65
-rw-r--r--Tests/CFBundleTest/ExportList_plugin.txt3
-rw-r--r--Tests/CFBundleTest/Info.plist.in54
-rw-r--r--Tests/CFBundleTest/InfoPlist.strings.in4
-rw-r--r--Tests/CFBundleTest/Localized.r18
-rw-r--r--Tests/CFBundleTest/Localized.rsrcbin0 -> 472 bytes-rw-r--r--Tests/CFBundleTest/PluginConfig.cmake21
-rw-r--r--Tests/CFBundleTest/README.txt16
-rw-r--r--Tests/CFBundleTest/VerifyResult.cmake29
-rw-r--r--Tests/CFBundleTest/np_macmain.cpp48
-rw-r--r--Tests/CMakeBuildTest.cmake.in60
-rw-r--r--Tests/CMakeCommands/add_compile_definitions/CMakeLists.txt15
-rw-r--r--Tests/CMakeCommands/add_compile_definitions/main.cpp17
-rw-r--r--Tests/CMakeCommands/add_compile_options/CMakeLists.txt21
-rw-r--r--Tests/CMakeCommands/add_compile_options/main.cpp11
-rw-r--r--Tests/CMakeCommands/add_link_options/CMakeLists.txt20
-rw-r--r--Tests/CMakeCommands/add_link_options/LinkOptionsExe.c4
-rw-r--r--Tests/CMakeCommands/link_directories/CMakeLists.txt30
-rw-r--r--Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c4
-rw-r--r--Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt50
-rw-r--r--Tests/CMakeCommands/target_compile_definitions/consumer.c44
-rw-r--r--Tests/CMakeCommands/target_compile_definitions/consumer.cpp37
-rw-r--r--Tests/CMakeCommands/target_compile_definitions/main.cpp17
-rw-r--r--Tests/CMakeCommands/target_compile_features/CMakeLists.txt65
-rw-r--r--Tests/CMakeCommands/target_compile_features/lib_auto_type.cpp6
-rw-r--r--Tests/CMakeCommands/target_compile_features/lib_auto_type.h8
-rw-r--r--Tests/CMakeCommands/target_compile_features/lib_restrict.c9
-rw-r--r--Tests/CMakeCommands/target_compile_features/lib_restrict.h7
-rw-r--r--Tests/CMakeCommands/target_compile_features/lib_user.cpp7
-rw-r--r--Tests/CMakeCommands/target_compile_features/main.c12
-rw-r--r--Tests/CMakeCommands/target_compile_features/main.cpp6
-rw-r--r--Tests/CMakeCommands/target_compile_features/restrict_user.c14
-rw-r--r--Tests/CMakeCommands/target_compile_options/CMakeLists.txt68
-rw-r--r--Tests/CMakeCommands/target_compile_options/consumer.c40
-rw-r--r--Tests/CMakeCommands/target_compile_options/consumer.cpp61
-rw-r--r--Tests/CMakeCommands/target_compile_options/main.cpp41
-rw-r--r--Tests/CMakeCommands/target_include_directories/CMakeLists.txt85
-rw-r--r--Tests/CMakeCommands/target_include_directories/c_only/c_only.h2
-rw-r--r--Tests/CMakeCommands/target_include_directories/consumer.c21
-rw-r--r--Tests/CMakeCommands/target_include_directories/consumer.cpp41
-rw-r--r--Tests/CMakeCommands/target_include_directories/cxx_only/cxx_only.h2
-rw-r--r--Tests/CMakeCommands/target_include_directories/main.cpp25
-rw-r--r--Tests/CMakeCommands/target_include_directories/relative_dir/consumer/consumer.h2
-rw-r--r--Tests/CMakeCommands/target_include_directories/relative_dir/relative_dir.h2
-rw-r--r--Tests/CMakeCommands/target_link_directories/CMakeLists.txt40
-rw-r--r--Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c7
-rw-r--r--Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt2
-rw-r--r--Tests/CMakeCommands/target_link_libraries/CMakeLists.txt151
-rw-r--r--Tests/CMakeCommands/target_link_libraries/SubDirA/CMakeLists.txt15
-rw-r--r--Tests/CMakeCommands/target_link_libraries/SubDirA/SubDirA.c14
-rw-r--r--Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt19
-rw-r--r--Tests/CMakeCommands/target_link_libraries/SubDirB/SubDirB.c14
-rw-r--r--Tests/CMakeCommands/target_link_libraries/SubDirC/CMakeLists.txt9
-rw-r--r--Tests/CMakeCommands/target_link_libraries/SubDirC/SubDirC.c11
-rw-r--r--Tests/CMakeCommands/target_link_libraries/TopDir.c20
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/CMakeLists.txt47
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022exe.cpp7
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022ifacelib.cpp9
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022ifacelib.h9
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022lib.cpp7
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022lib.h5
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib1.cpp12
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib1.h14
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib2.cpp8
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib2.h7
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib_user.cpp7
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib1.cpp5
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib1.h4
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib2.cpp5
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib2.h4
-rw-r--r--Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib_exe.cpp8
-rw-r--r--Tests/CMakeCommands/target_link_libraries/depA.cpp7
-rw-r--r--Tests/CMakeCommands/target_link_libraries/depA.h7
-rw-r--r--Tests/CMakeCommands/target_link_libraries/depB.cpp14
-rw-r--r--Tests/CMakeCommands/target_link_libraries/depB.h7
-rw-r--r--Tests/CMakeCommands/target_link_libraries/depC.cpp13
-rw-r--r--Tests/CMakeCommands/target_link_libraries/depC.h10
-rw-r--r--Tests/CMakeCommands/target_link_libraries/depD.cpp13
-rw-r--r--Tests/CMakeCommands/target_link_libraries/depD.h10
-rw-r--r--Tests/CMakeCommands/target_link_libraries/depG.cpp7
-rw-r--r--Tests/CMakeCommands/target_link_libraries/depG.h7
-rw-r--r--Tests/CMakeCommands/target_link_libraries/depIfaceOnly.cpp7
-rw-r--r--Tests/CMakeCommands/target_link_libraries/depIfaceOnly.h7
-rw-r--r--Tests/CMakeCommands/target_link_libraries/empty.cpp3
-rw-r--r--Tests/CMakeCommands/target_link_libraries/libgenex.cpp7
-rw-r--r--Tests/CMakeCommands/target_link_libraries/libgenex.h12
-rw-r--r--Tests/CMakeCommands/target_link_libraries/newsignature1.cpp18
-rw-r--r--Tests/CMakeCommands/target_link_libraries/subdir/CMakeLists.txt5
-rw-r--r--Tests/CMakeCommands/target_link_libraries/subdir/subdirlib.cpp7
-rw-r--r--Tests/CMakeCommands/target_link_libraries/subdir/subdirlib.h12
-rw-r--r--Tests/CMakeCommands/target_link_libraries/targetA.cpp18
-rw-r--r--Tests/CMakeCommands/target_link_libraries/targetB.cpp10
-rw-r--r--Tests/CMakeCommands/target_link_libraries/targetC.cpp15
-rw-r--r--Tests/CMakeCommands/target_link_options/CMakeLists.txt34
-rw-r--r--Tests/CMakeCommands/target_link_options/LinkOptionsLib.c7
-rw-r--r--Tests/CMakeCommands/target_sources/CMakeLists.txt36
-rw-r--r--Tests/CMakeCommands/target_sources/empty_1.cpp21
-rw-r--r--Tests/CMakeCommands/target_sources/empty_2.cpp7
-rw-r--r--Tests/CMakeCommands/target_sources/empty_3.cpp7
-rw-r--r--Tests/CMakeCommands/target_sources/main.cpp16
-rw-r--r--Tests/CMakeCommands/target_sources/subdir/CMakeLists.txt6
-rw-r--r--Tests/CMakeCommands/target_sources/subdir/subdir_empty_1.cpp21
-rw-r--r--Tests/CMakeCommands/target_sources/subdir/subdir_empty_2.cpp21
-rw-r--r--Tests/CMakeCopyright.cmake22
-rw-r--r--Tests/CMakeGUI/CMakeGUITest.cmake158
-rw-r--r--Tests/CMakeGUI/CMakeGUITest.cxx449
-rw-r--r--Tests/CMakeGUI/CMakeGUITest.h29
-rw-r--r--Tests/CMakeGUI/CMakeLists.txt95
-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/QCMakeCacheModelTest.cxx108
-rw-r--r--Tests/CMakeGUI/QCMakeCacheModelTest.h14
-rw-r--r--Tests/CMakeGUI/QCMakePresetComboBoxTest.cxx82
-rw-r--r--Tests/CMakeGUI/QCMakePresetComboBoxTest.h13
-rw-r--r--Tests/CMakeGUI/QCMakePresetItemModelTest.cxx166
-rw-r--r--Tests/CMakeGUI/QCMakePresetItemModelTest.h17
-rw-r--r--Tests/CMakeGUI/QCMakePresetTest.cxx85
-rw-r--r--Tests/CMakeGUI/QCMakePresetTest.h14
-rw-r--r--Tests/CMakeGUI/environment/CMakeLists.txt.in18
-rw-r--r--Tests/CMakeGUI/presetArg-noPresetBinaryChange/CMakePresets.json.in33
-rw-r--r--Tests/CMakeGUI/presetArg-preset/CMakePresets.json.in33
-rw-r--r--Tests/CMakeGUI/presetArg-presetBinary/CMakePresets.json.in33
-rw-r--r--Tests/CMakeGUI/presetArg-presetBinaryChange/CMakePresets.json.in39
-rw-r--r--Tests/CMakeGUI/presetArg-presetConfigExists/CMakeLists.txt.in2
-rw-r--r--Tests/CMakeGUI/presetArg-presetConfigExists/CMakePresets.json.in33
-rw-r--r--Tests/CMakeGUI/presetArg-presetConfigExists/CMakeSetup.ini.in2
-rw-r--r--Tests/CMakeGUI/simpleConfigure-fail/CMakeLists.txt.in5
-rw-r--r--Tests/CMakeGUI/simpleConfigure-success/CMakeLists.txt.in4
-rw-r--r--Tests/CMakeGUI/sourceBinaryArgs-binaryDir/CMakeLists.txt.in2
-rw-r--r--Tests/CMakeGUI/sourceBinaryArgs-noExistConfig/CMakeSetup.ini.in2
-rw-r--r--Tests/CMakeGUI/sourceBinaryArgs-noExistConfigExists/CMakeLists.txt.in2
-rw-r--r--Tests/CMakeGUI/sourceBinaryArgs-noExistConfigExists/CMakeSetup.ini.in2
-rw-r--r--Tests/CMakeGUI/sourceBinaryArgs-sourceDir/CMakeLists.txt.in2
-rw-r--r--Tests/CMakeInstall.cmake48
-rw-r--r--Tests/CMakeLib/CMakeLists.txt79
-rw-r--r--Tests/CMakeLib/PseudoMemcheck/CMakeLists.txt29
-rw-r--r--Tests/CMakeLib/PseudoMemcheck/NoLog/CMakeLists.txt14
-rw-r--r--Tests/CMakeLib/PseudoMemcheck/memtester.cxx.in84
-rw-r--r--Tests/CMakeLib/run_compile_commands.cxx159
-rw-r--r--Tests/CMakeLib/testAffinity.cxx18
-rw-r--r--Tests/CMakeLib/testArgumentParser.cxx148
-rw-r--r--Tests/CMakeLib/testCMExtAlgorithm.cxx118
-rw-r--r--Tests/CMakeLib/testCMExtMemory.cxx65
-rw-r--r--Tests/CMakeLib/testCMFilesystemPath.cxx1008
-rw-r--r--Tests/CMakeLib/testCTestBinPacker.cxx300
-rw-r--r--Tests/CMakeLib/testCTestResourceAllocator.cxx426
-rw-r--r--Tests/CMakeLib/testCTestResourceGroups.cxx141
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec.cxx119
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec1.json27
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec10.json15
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec11.json16
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec12.json1
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec13.json1
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec14.json12
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec15.json12
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec16.json12
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec17.json15
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec18.json15
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec19.json5
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec2.json8
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec20.json8
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec21.json5
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec22.json5
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec23.json7
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec24.json7
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec25.json8
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec26.json8
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec27.json8
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec28.json8
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec29.json5
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec3.json12
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec30.json5
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec31.json5
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec32.json5
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec33.json5
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec34.json5
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec35.json5
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec36.json4
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec4.json8
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec5.json6
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec6.json9
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec7.json12
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec8.json13
-rw-r--r--Tests/CMakeLib/testCTestResourceSpec_data/spec9.json14
-rw-r--r--Tests/CMakeLib/testEncoding.cxx52
-rw-r--r--Tests/CMakeLib/testFindPackageCommand.cxx71
-rw-r--r--Tests/CMakeLib/testGccDepfileReader.cxx142
-rw-r--r--Tests/CMakeLib/testGccDepfileReader_data/deps1.d20
-rw-r--r--Tests/CMakeLib/testGccDepfileReader_data/deps1.txt26
-rw-r--r--Tests/CMakeLib/testGccDepfileReader_data/deps2.d1
-rw-r--r--Tests/CMakeLib/testGccDepfileReader_data/deps2.txt5
-rw-r--r--Tests/CMakeLib/testGccDepfileReader_data/deps3.d2
-rw-r--r--Tests/CMakeLib/testGccDepfileReader_data/deps3.txt11
-rw-r--r--Tests/CMakeLib/testGccDepfileReader_data/deps4.d1
-rw-r--r--Tests/CMakeLib/testGccDepfileReader_data/deps5.d0
-rw-r--r--Tests/CMakeLib/testGccDepfileReader_data/deps5.txt2
-rw-r--r--Tests/CMakeLib/testGccDepfileReader_data/deps7.d6
-rw-r--r--Tests/CMakeLib/testGccDepfileReader_data/deps7.txt10
-rw-r--r--Tests/CMakeLib/testGeneratedFileStream.cxx88
-rw-r--r--Tests/CMakeLib/testJSONHelpers.cxx504
-rw-r--r--Tests/CMakeLib/testOptional.cxx808
-rw-r--r--Tests/CMakeLib/testRST.cxx86
-rw-r--r--Tests/CMakeLib/testRST.expect125
-rw-r--r--Tests/CMakeLib/testRST.rst132
-rw-r--r--Tests/CMakeLib/testRSTinclude1.rst6
-rw-r--r--Tests/CMakeLib/testRSTinclude2.rst3
-rw-r--r--Tests/CMakeLib/testRSTmod.cmake11
-rw-r--r--Tests/CMakeLib/testRSTtoc1.rst2
-rw-r--r--Tests/CMakeLib/testRSTtoc2.rst2
-rw-r--r--Tests/CMakeLib/testRange.cxx45
-rw-r--r--Tests/CMakeLib/testString.cxx1348
-rw-r--r--Tests/CMakeLib/testStringAlgorithms.cxx240
-rw-r--r--Tests/CMakeLib/testSystemTools.cxx99
-rw-r--r--Tests/CMakeLib/testUTF8.cxx197
-rw-r--r--Tests/CMakeLib/testUVProcessChain.cxx338
-rw-r--r--Tests/CMakeLib/testUVProcessChainHelper.cxx72
-rw-r--r--Tests/CMakeLib/testUVRAII.cxx230
-rw-r--r--Tests/CMakeLib/testUVStreambuf.cxx454
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser.cxx195
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser.h.in7
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/.gitattributes1
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/bom.sln-file2
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/err-data.sln-file6
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/err-empty.sln-file0
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-global.sln-file9
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-header.sln-file4
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-projectArgs.sln-file4
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-projectContents.sln-file6
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-projectSection.sln-file11
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-strayParen.sln-file4
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-strayQuote.sln-file4
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-strayQuote2.sln-file4
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-topLevel.sln-file4
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-unclosed.sln-file5
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/nobom.sln-file2
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser_data/valid.sln-file680
-rw-r--r--Tests/CMakeLib/testXMLParser.cxx16
-rw-r--r--Tests/CMakeLib/testXMLParser.h.in6
-rw-r--r--Tests/CMakeLib/testXMLParser.xml4
-rw-r--r--Tests/CMakeLib/testXMLSafe.cxx42
-rw-r--r--Tests/CMakeLists.txt3589
-rw-r--r--Tests/CMakeOnly/AllFindModules/CMakeLists.txt94
-rw-r--r--Tests/CMakeOnly/CMakeLists.txt107
-rw-r--r--Tests/CMakeOnly/CheckCXXCompilerFlag/CMakeLists.txt65
-rw-r--r--Tests/CMakeOnly/CheckCXXSymbolExists/CMakeLists.txt76
-rw-r--r--Tests/CMakeOnly/CheckLanguage/CMakeLists.txt33
-rw-r--r--Tests/CMakeOnly/CheckOBJCCompilerFlag/CMakeLists.txt7
-rw-r--r--Tests/CMakeOnly/CheckOBJCXXCompilerFlag/CMakeLists.txt7
-rw-r--r--Tests/CMakeOnly/CheckStructHasMember/CMakeLists.txt93
-rw-r--r--Tests/CMakeOnly/CheckStructHasMember/cm_cshm.h10
-rw-r--r--Tests/CMakeOnly/CheckStructHasMember/cm_cshm.hxx17
-rw-r--r--Tests/CMakeOnly/CheckSymbolExists/CMakeLists.txt51
-rw-r--r--Tests/CMakeOnly/CheckSymbolExists/cm_cse.h6
-rw-r--r--Tests/CMakeOnly/CompilerIdC/CMakeLists.txt21
-rw-r--r--Tests/CMakeOnly/CompilerIdCSharp/CMakeLists.txt21
-rw-r--r--Tests/CMakeOnly/CompilerIdCUDA/CMakeLists.txt14
-rw-r--r--Tests/CMakeOnly/CompilerIdCXX/CMakeLists.txt21
-rw-r--r--Tests/CMakeOnly/CompilerIdFortran/CMakeLists.txt21
-rw-r--r--Tests/CMakeOnly/CompilerIdOBJC/CMakeLists.txt14
-rw-r--r--Tests/CMakeOnly/CompilerIdOBJCXX/CMakeLists.txt14
-rw-r--r--Tests/CMakeOnly/LinkInterfaceLoop/CMakeLists.txt27
-rw-r--r--Tests/CMakeOnly/LinkInterfaceLoop/lib.c4
-rw-r--r--Tests/CMakeOnly/LinkInterfaceLoop/main.c4
-rw-r--r--Tests/CMakeOnly/MajorVersionSelection/CMakeLists.txt46
-rw-r--r--Tests/CMakeOnly/ProjectInclude/CMakeLists.txt4
-rw-r--r--Tests/CMakeOnly/ProjectInclude/include.cmake1
-rw-r--r--Tests/CMakeOnly/ProjectIncludeAny/CMakeLists.txt4
-rw-r--r--Tests/CMakeOnly/ProjectIncludeBefore/CMakeLists.txt5
-rw-r--r--Tests/CMakeOnly/ProjectIncludeBefore/include.cmake9
-rw-r--r--Tests/CMakeOnly/ProjectIncludeBeforeAny/CMakeLists.txt5
-rw-r--r--Tests/CMakeOnly/ProjectIncludeBeforeAny/include.cmake9
-rw-r--r--Tests/CMakeOnly/SelectLibraryConfigurations/CMakeLists.txt65
-rw-r--r--Tests/CMakeOnly/TargetScope/CMakeLists.txt13
-rw-r--r--Tests/CMakeOnly/TargetScope/Sib/CMakeLists.txt6
-rw-r--r--Tests/CMakeOnly/TargetScope/Sub/CMakeLists.txt9
-rw-r--r--Tests/CMakeOnly/TargetScope/Sub/Sub/CMakeLists.txt6
-rw-r--r--Tests/CMakeOnly/Test.cmake.in33
-rw-r--r--Tests/CMakeOnly/find_library/A/libtestA.a0
-rw-r--r--Tests/CMakeOnly/find_library/B/libtestB.a0
-rw-r--r--Tests/CMakeOnly/find_library/CMakeLists.txt110
-rw-r--r--Tests/CMakeOnly/find_library/lib/32/libtest5.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib/64/libtest2.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib/A/lib/libtest1.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib/A/lib32/libtest3.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib/A/lib64/libtest3.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib/A/libXYZ/libtest2.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib/A/libtest1.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib/A/libx32/libtest3.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib/XYZ/libtest1.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib/libtest1.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib/libtest2.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib/libtest3.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib/x32/libtest2.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib32/A/lib/libtest2.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib32/A/lib32/libtest4.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib32/A/libtest4.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib32/libtest4.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib64/A/lib/libtest2.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib64/A/lib64/libtest1.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib64/A/libtest1.a0
-rw-r--r--Tests/CMakeOnly/find_library/lib64/libtest1.a0
-rw-r--r--Tests/CMakeOnly/find_library/libXYZ/A/lib/libtest4.a0
-rw-r--r--Tests/CMakeOnly/find_library/libXYZ/A/libXYZ/libtest5.a0
-rw-r--r--Tests/CMakeOnly/find_library/libXYZ/A/libtest6.a0
-rw-r--r--Tests/CMakeOnly/find_library/libXYZ/libtest7.a0
-rw-r--r--Tests/CMakeOnly/find_library/libx32/A/lib/libtest2.a0
-rw-r--r--Tests/CMakeOnly/find_library/libx32/A/libtest1.a0
-rw-r--r--Tests/CMakeOnly/find_library/libx32/A/libx32/libtest1.a0
-rw-r--r--Tests/CMakeOnly/find_library/libx32/libtest1.a0
-rw-r--r--Tests/CMakeOnly/find_path/CMakeLists.txt31
-rw-r--r--Tests/CMakeOnly/find_path/include/arch/test1arch.h0
-rw-r--r--Tests/CMakeOnly/find_path/include/test1.h0
-rw-r--r--Tests/CMakeTestAllGenerators/RunCMake.cmake76
-rw-r--r--Tests/CMakeTests/.gitattributes1
-rw-r--r--Tests/CMakeTests/A/include/cmake_i_do_not_exist_in_the_system.h1
-rw-r--r--Tests/CMakeTests/CMakeHostSystemInformation-BadArg1.cmake1
-rw-r--r--Tests/CMakeTests/CMakeHostSystemInformation-BadArg2.cmake1
-rw-r--r--Tests/CMakeTests/CMakeHostSystemInformation-BadArg3.cmake1
-rw-r--r--Tests/CMakeTests/CMakeHostSystemInformation-QueryList.cmake5
-rw-r--r--Tests/CMakeTests/CMakeHostSystemInformationTest.cmake.in52
-rw-r--r--Tests/CMakeTests/CMakeLists.txt77
-rw-r--r--Tests/CMakeTests/CMakeMinimumRequiredTest.cmake.in18
-rw-r--r--Tests/CMakeTests/CMakeMinimumRequiredTestScript.cmake31
-rw-r--r--Tests/CMakeTests/CheckCMakeTest.cmake35
-rw-r--r--Tests/CMakeTests/CheckSourceTreeTest.cmake.in365
-rw-r--r--Tests/CMakeTests/CompilerIdVendorTest.cmake.in31
-rw-r--r--Tests/CMakeTests/DummyToolchain.cmake8
-rw-r--r--Tests/CMakeTests/EndStuffTest.cmake.in18
-rw-r--r--Tests/CMakeTests/EndStuffTestScript.cmake42
-rw-r--r--Tests/CMakeTests/ExecuteScriptTests.cmake63
-rw-r--r--Tests/CMakeTests/File-Copy-BadArg.cmake1
-rw-r--r--Tests/CMakeTests/File-Copy-BadPerm.cmake1
-rw-r--r--Tests/CMakeTests/File-Copy-BadRegex.cmake1
-rw-r--r--Tests/CMakeTests/File-Copy-EarlyArg.cmake1
-rw-r--r--Tests/CMakeTests/File-Copy-LateArg.cmake1
-rw-r--r--Tests/CMakeTests/File-Copy-NoDest.cmake1
-rw-r--r--Tests/CMakeTests/File-Copy-NoFile.cmake1
-rw-r--r--Tests/CMakeTests/File-Glob-NoArg.cmake2
-rw-r--r--Tests/CMakeTests/File-HASH-Input.txt1
-rw-r--r--Tests/CMakeTests/File-MD5-BadArg1.cmake1
-rw-r--r--Tests/CMakeTests/File-MD5-BadArg2.cmake1
-rw-r--r--Tests/CMakeTests/File-MD5-BadArg4.cmake1
-rw-r--r--Tests/CMakeTests/File-MD5-NoFile.cmake1
-rw-r--r--Tests/CMakeTests/File-MD5-Works.cmake2
-rw-r--r--Tests/CMakeTests/File-SHA1-Works.cmake2
-rw-r--r--Tests/CMakeTests/File-SHA224-Works.cmake2
-rw-r--r--Tests/CMakeTests/File-SHA256-Works.cmake2
-rw-r--r--Tests/CMakeTests/File-SHA384-Works.cmake2
-rw-r--r--Tests/CMakeTests/File-SHA3_224-Works.cmake2
-rw-r--r--Tests/CMakeTests/File-SHA3_256-Works.cmake2
-rw-r--r--Tests/CMakeTests/File-SHA3_384-Works.cmake2
-rw-r--r--Tests/CMakeTests/File-SHA3_512-Works.cmake2
-rw-r--r--Tests/CMakeTests/File-SHA512-Works.cmake2
-rw-r--r--Tests/CMakeTests/File-TIMESTAMP-BadArg1.cmake1
-rw-r--r--Tests/CMakeTests/File-TIMESTAMP-NoFile.cmake2
-rw-r--r--Tests/CMakeTests/File-TIMESTAMP-NotBogus.cmake25
-rw-r--r--Tests/CMakeTests/File-TIMESTAMP-Works.cmake2
-rw-r--r--Tests/CMakeTests/FileDownloadBadHashTest.cmake.in13
-rw-r--r--Tests/CMakeTests/FileDownloadInput.pngbin0 -> 194 bytes-rw-r--r--Tests/CMakeTests/FileDownloadTest.cmake.in181
-rw-r--r--Tests/CMakeTests/FileTest.cmake.in109
-rw-r--r--Tests/CMakeTests/FileTestScript.cmake227
-rw-r--r--Tests/CMakeTests/FileUploadTest.cmake.in52
-rw-r--r--Tests/CMakeTests/FindBaseTest.cmake.in62
-rw-r--r--Tests/CMakeTests/GetFilenameComponentRealpathTest.cmake.in72
-rw-r--r--Tests/CMakeTests/GetPrerequisitesTest.cmake.in156
-rw-r--r--Tests/CMakeTests/GetPropertyTest.cmake.in16
-rw-r--r--Tests/CMakeTests/IfTest.cmake.in158
-rw-r--r--Tests/CMakeTests/ImplicitLinkInfoTest.cmake.in554
-rw-r--r--Tests/CMakeTests/IncludeTest.cmake.in41
-rw-r--r--Tests/CMakeTests/ListTest.cmake.in163
-rw-r--r--Tests/CMakeTests/Make_Directory-NoArg.cmake1
-rw-r--r--Tests/CMakeTests/MathTest.cmake.in18
-rw-r--r--Tests/CMakeTests/MathTestScript.cmake18
-rw-r--r--Tests/CMakeTests/MessageTest.cmake.in30
-rw-r--r--Tests/CMakeTests/MessageTestScript.cmake4
-rw-r--r--Tests/CMakeTests/ModuleNoticesTest.cmake.in33
-rw-r--r--Tests/CMakeTests/PolicyCheckTest.cmake.in154
-rw-r--r--Tests/CMakeTests/ProcessorCountTest.cmake.in79
-rw-r--r--Tests/CMakeTests/PushCheckStateTest.cmake.in91
-rw-r--r--Tests/CMakeTests/String-MD5-BadArg1.cmake1
-rw-r--r--Tests/CMakeTests/String-MD5-BadArg2.cmake1
-rw-r--r--Tests/CMakeTests/String-MD5-BadArg4.cmake1
-rw-r--r--Tests/CMakeTests/String-MD5-Works.cmake2
-rw-r--r--Tests/CMakeTests/String-SHA1-Works.cmake2
-rw-r--r--Tests/CMakeTests/String-SHA224-Works.cmake2
-rw-r--r--Tests/CMakeTests/String-SHA256-Works.cmake2
-rw-r--r--Tests/CMakeTests/String-SHA384-Works.cmake2
-rw-r--r--Tests/CMakeTests/String-SHA3_224-Works.cmake2
-rw-r--r--Tests/CMakeTests/String-SHA3_256-Works.cmake2
-rw-r--r--Tests/CMakeTests/String-SHA3_384-Works.cmake2
-rw-r--r--Tests/CMakeTests/String-SHA3_512-Works.cmake2
-rw-r--r--Tests/CMakeTests/String-SHA512-Works.cmake2
-rw-r--r--Tests/CMakeTests/String-TIMESTAMP-AllSpecifiers.cmake11
-rw-r--r--Tests/CMakeTests/String-TIMESTAMP-BadArg1.cmake1
-rw-r--r--Tests/CMakeTests/String-TIMESTAMP-BadArg2.cmake1
-rw-r--r--Tests/CMakeTests/String-TIMESTAMP-BadArg3.cmake1
-rw-r--r--Tests/CMakeTests/String-TIMESTAMP-CustomFormatLocal.cmake2
-rw-r--r--Tests/CMakeTests/String-TIMESTAMP-CustomFormatUTC.cmake2
-rw-r--r--Tests/CMakeTests/String-TIMESTAMP-DefaultFormatLocal.cmake2
-rw-r--r--Tests/CMakeTests/String-TIMESTAMP-DefaultFormatUTC.cmake2
-rw-r--r--Tests/CMakeTests/String-TIMESTAMP-IncompleteSpecifier.cmake2
-rw-r--r--Tests/CMakeTests/String-TIMESTAMP-MonthWeekNames.cmake11
-rw-r--r--Tests/CMakeTests/String-TIMESTAMP-UnixTime.cmake22
-rw-r--r--Tests/CMakeTests/String-TIMESTAMP-UnknownSpecifier.cmake2
-rw-r--r--Tests/CMakeTests/StringTest.cmake.in101
-rw-r--r--Tests/CMakeTests/StringTestScript.cmake307
-rw-r--r--Tests/CMakeTests/ToolchainTest.cmake.in138
-rw-r--r--Tests/CMakeTests/VariableWatchTest.cmake.in31
-rw-r--r--Tests/CMakeTests/VersionTest.cmake.in106
-rw-r--r--Tests/CMakeTests/WhileTest.cmake.in17
-rw-r--r--Tests/CMakeTests/include/cmake_i_do_not_exist_in_the_system.h1
-rw-r--r--Tests/COnly/CMakeLists.txt17
-rw-r--r--Tests/COnly/conly.c20
-rw-r--r--Tests/COnly/foo.c1
-rw-r--r--Tests/COnly/foo.h1
-rw-r--r--Tests/COnly/libc1.c4
-rw-r--r--Tests/COnly/libc1.h1
-rw-r--r--Tests/COnly/libc2.c6
-rw-r--r--Tests/COnly/libc2.h11
-rw-r--r--Tests/COnly/testCModule.c9
-rw-r--r--Tests/CPackComponents/CMakeLists.txt128
-rw-r--r--Tests/CPackComponents/Issue 7470.html9
-rw-r--r--Tests/CPackComponents/VerifyResult.cmake48
-rw-r--r--Tests/CPackComponents/mylib.cpp8
-rw-r--r--Tests/CPackComponents/mylib.h1
-rw-r--r--Tests/CPackComponents/mylibapp.cpp6
-rw-r--r--Tests/CPackComponentsDEB/CMakeLists.txt147
-rw-r--r--Tests/CPackComponentsDEB/MyLibCPackConfig-components-depend1.cmake.in21
-rw-r--r--Tests/CPackComponentsDEB/MyLibCPackConfig-components-depend2.cmake.in30
-rw-r--r--Tests/CPackComponentsDEB/MyLibCPackConfig-components-description1.cmake.in23
-rw-r--r--Tests/CPackComponentsDEB/MyLibCPackConfig-components-description2.cmake.in26
-rw-r--r--Tests/CPackComponentsDEB/MyLibCPackConfig-components-lintian-dpkgdeb-checks.cmake.in15
-rw-r--r--Tests/CPackComponentsDEB/MyLibCPackConfig-components-shlibdeps1.cmake.in24
-rw-r--r--Tests/CPackComponentsDEB/MyLibCPackConfig-components-source.cmake.in33
-rw-r--r--Tests/CPackComponentsDEB/MyLibCPackConfig-compression.cmake.in11
-rw-r--r--Tests/CPackComponentsDEB/MyLibCPackConfig-shlibdeps-with-private-lib-failure.cmake.in24
-rw-r--r--Tests/CPackComponentsDEB/MyLibCPackConfig-shlibdeps-with-private-lib-success.cmake.in33
-rw-r--r--Tests/CPackComponentsDEB/RunCPackVerifyResult-components-depend1.cmake75
-rw-r--r--Tests/CPackComponentsDEB/RunCPackVerifyResult-components-depend2.cmake85
-rw-r--r--Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description1.cmake86
-rw-r--r--Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description2.cmake80
-rw-r--r--Tests/CPackComponentsDEB/RunCPackVerifyResult-components-lintian-dpkgdeb-checks.cmake78
-rw-r--r--Tests/CPackComponentsDEB/RunCPackVerifyResult-components-shlibdeps1.cmake75
-rw-r--r--Tests/CPackComponentsDEB/RunCPackVerifyResult-components-source.cmake68
-rw-r--r--Tests/CPackComponentsDEB/RunCPackVerifyResult-compression.cmake48
-rw-r--r--Tests/CPackComponentsDEB/RunCPackVerifyResult-shlibdeps-with-private-lib-failure.cmake19
-rw-r--r--Tests/CPackComponentsDEB/RunCPackVerifyResult-shlibdeps-with-private-lib-success.cmake75
-rw-r--r--Tests/CPackComponentsDEB/RunCPackVerifyResult.cmake237
-rw-r--r--Tests/CPackComponentsDEB/license.txt3
-rw-r--r--Tests/CPackComponentsDEB/mylib.cpp8
-rw-r--r--Tests/CPackComponentsDEB/mylib.h1
-rw-r--r--Tests/CPackComponentsDEB/mylibapp.cpp19
-rw-r--r--Tests/CPackComponentsDEB/shlibdeps-with-private-lib/CMakeLists.txt5
-rw-r--r--Tests/CPackComponentsDEB/shlibdeps-with-private-lib/myprivatelib.cpp8
-rw-r--r--Tests/CPackComponentsDEB/shlibdeps-with-private-lib/myprivatelib.h1
-rw-r--r--Tests/CPackComponentsForAll/CMakeLists.txt194
-rw-r--r--Tests/CPackComponentsForAll/MyLibCPackConfig-AllInOne.cmake.in26
-rw-r--r--Tests/CPackComponentsForAll/MyLibCPackConfig-IgnoreGroup.cmake.in65
-rw-r--r--Tests/CPackComponentsForAll/MyLibCPackConfig-OnePackPerGroup.cmake.in31
-rw-r--r--Tests/CPackComponentsForAll/RunCPackVerifyResult.cmake434
-rw-r--r--Tests/CPackComponentsForAll/license.txt3
-rw-r--r--Tests/CPackComponentsForAll/mylib17
-rw-r--r--Tests/CPackComponentsForAll/mylib.cpp8
-rw-r--r--Tests/CPackComponentsForAll/mylib.h1
-rw-r--r--Tests/CPackComponentsForAll/mylibapp.cpp6
-rw-r--r--Tests/CPackComponentsForAll/symlink_postinstall_expected.txt57
-rw-r--r--Tests/CPackComponentsPrefix/CMakeLists.txt14
-rw-r--r--Tests/CPackComponentsPrefix/file-development.txt1
-rw-r--r--Tests/CPackComponentsPrefix/file-runtime.txt1
-rw-r--r--Tests/CPackNSISGenerator/CMakeLists.txt23
-rw-r--r--Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake62
-rw-r--r--Tests/CPackNSISGenerator/header-icon.bmpbin0 -> 28166 bytes-rw-r--r--Tests/CPackNSISGenerator/header-image.bmpbin0 -> 28166 bytes-rw-r--r--Tests/CPackNSISGenerator/install.icobin0 -> 838 bytes-rw-r--r--Tests/CPackNSISGenerator/main.cpp4
-rw-r--r--Tests/CPackNSISGenerator/uninstall.icobin0 -> 838 bytes-rw-r--r--Tests/CPackTestAllGenerators/CMakeLists.txt5
-rw-r--r--Tests/CPackTestAllGenerators/RunCPack.cmake51
-rw-r--r--Tests/CPackUseDefaultVersion/CMakeLists.txt6
-rw-r--r--Tests/CPackUseProjectVersion/CMakeLists.txt6
-rw-r--r--Tests/CPackUseShortProjectVersion/CMakeLists.txt6
-rw-r--r--Tests/CPackWiXGenerator/CMakeLists.txt119
-rw-r--r--Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake79
-rw-r--r--Tests/CPackWiXGenerator/file with spaces.h0
-rw-r--r--Tests/CPackWiXGenerator/license.txt9
-rw-r--r--Tests/CPackWiXGenerator/mylib.cpp8
-rw-r--r--Tests/CPackWiXGenerator/mylib.h1
-rw-r--r--Tests/CPackWiXGenerator/mylibapp.cpp6
-rw-r--r--Tests/CPackWiXGenerator/myotherapp.cpp3
-rw-r--r--Tests/CPackWiXGenerator/patch.xml7
-rw-r--r--Tests/CSharpLinkFromCxx/.gitattributes1
-rw-r--r--Tests/CSharpLinkFromCxx/CMakeLists.txt19
-rw-r--r--Tests/CSharpLinkFromCxx/CSharpLinkFromCxx.cs16
-rw-r--r--Tests/CSharpLinkFromCxx/UsefulCSharpClass.cs12
-rw-r--r--Tests/CSharpLinkFromCxx/UsefulManagedCppClass.cpp15
-rw-r--r--Tests/CSharpLinkFromCxx/UsefulManagedCppClass.hpp16
-rw-r--r--Tests/CSharpLinkToCxx/CMakeLists.txt29
-rw-r--r--Tests/CSharpLinkToCxx/cli.cpp10
-rw-r--r--Tests/CSharpLinkToCxx/cli.hpp10
-rw-r--r--Tests/CSharpLinkToCxx/cpp_native.cpp10
-rw-r--r--Tests/CSharpLinkToCxx/cpp_native.hpp9
-rw-r--r--Tests/CSharpLinkToCxx/cpp_static.cpp3
-rw-r--r--Tests/CSharpLinkToCxx/csharp.cs16
-rw-r--r--Tests/CSharpOnly/CMakeLists.txt16
-rw-r--r--Tests/CSharpOnly/csharponly.cs13
-rw-r--r--Tests/CSharpOnly/empty.cs0
-rw-r--r--Tests/CSharpOnly/empty.txt0
-rw-r--r--Tests/CSharpOnly/lib1.cs10
-rw-r--r--Tests/CSharpOnly/lib2.cs10
-rw-r--r--Tests/CSharpOnly/nested/lib1.cs13
-rw-r--r--Tests/CSharpWin32GenEx/CMakeLists.txt5
-rw-r--r--Tests/CSharpWin32GenEx/csharpwin32genex.cs9
-rw-r--r--Tests/CTestBuildCommandProjectInSubdir/CTestBuildCommandProjectInSubdir.cmake.in11
-rw-r--r--Tests/CTestConfig/CMakeLists.txt56
-rw-r--r--Tests/CTestConfig/CTestConfig.cxx19
-rw-r--r--Tests/CTestConfig/ScriptWithArgs.cmake16
-rw-r--r--Tests/CTestConfig/dashboard.cmake.in49
-rw-r--r--Tests/CTestConfig/script.cmake.in29
-rw-r--r--Tests/CTestCoverageCollectGCOV/TestProject/3rdparty/foo.cpp3
-rw-r--r--Tests/CTestCoverageCollectGCOV/TestProject/CMakeLists.txt41
-rw-r--r--Tests/CTestCoverageCollectGCOV/TestProject/extra/extra.cpp3
-rw-r--r--Tests/CTestCoverageCollectGCOV/TestProject/extra/uncovered1.cpp0
-rw-r--r--Tests/CTestCoverageCollectGCOV/TestProject/fake_compile_time_gcno.cmake7
-rw-r--r--Tests/CTestCoverageCollectGCOV/TestProject/fake_run_time_gcda.cmake12
-rw-r--r--Tests/CTestCoverageCollectGCOV/TestProject/main.cpp3
-rw-r--r--Tests/CTestCoverageCollectGCOV/TestProject/uncovered2.cpp0
-rw-r--r--Tests/CTestCoverageCollectGCOV/fakegcov.cmake17
-rw-r--r--Tests/CTestCoverageCollectGCOV/test.cmake.in198
-rw-r--r--Tests/CTestLimitDashJ/CMakeLists.txt50
-rw-r--r--Tests/CTestLimitDashJ/CreateSleepDelete.cmake48
-rw-r--r--Tests/CTestScriptMode/CTestTestScriptMode.cmake.in14
-rw-r--r--Tests/CTestTest/SmallAndFast/CMakeLists.txt25
-rw-r--r--Tests/CTestTest/SmallAndFast/echoargs.c10
-rw-r--r--Tests/CTestTest/SmallAndFast/intentional_compile_error.cxx1
-rw-r--r--Tests/CTestTest/SmallAndFast/intentional_compile_warning.cxx11
-rw-r--r--Tests/CTestTest/test.cmake.in70
-rw-r--r--Tests/CTestTest2/test.cmake.in68
-rw-r--r--Tests/CTestTestBadExe/CMakeLists.txt7
-rw-r--r--Tests/CTestTestBadExe/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestBadExe/notAnExe.txt1
-rw-r--r--Tests/CTestTestBadExe/test.cmake.in23
-rw-r--r--Tests/CTestTestBadGenerator/CMakeLists.txt3
-rw-r--r--Tests/CTestTestBadGenerator/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestBadGenerator/test.cmake.in21
-rw-r--r--Tests/CTestTestChecksum/test.cmake.in27
-rw-r--r--Tests/CTestTestCostSerial/CMakeLists.txt13
-rw-r--r--Tests/CTestTestCostSerial/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestCostSerial/sleep.c16
-rw-r--r--Tests/CTestTestCostSerial/test.cmake.in30
-rw-r--r--Tests/CTestTestCrash/CMakeLists.txt7
-rw-r--r--Tests/CTestTestCrash/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestCrash/crash.cxx6
-rw-r--r--Tests/CTestTestCrash/test.cmake.in24
-rw-r--r--Tests/CTestTestCycle/CMakeLists.txt13
-rw-r--r--Tests/CTestTestCycle/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestCycle/simple.cxx5
-rw-r--r--Tests/CTestTestCycle/test.cmake.in21
-rw-r--r--Tests/CTestTestDepends/CMakeLists.txt13
-rw-r--r--Tests/CTestTestDepends/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestDepends/simple.cxx5
-rw-r--r--Tests/CTestTestDepends/test.cmake.in21
-rw-r--r--Tests/CTestTestEmptyBinaryDirectory/test.cmake.in66
-rw-r--r--Tests/CTestTestFailure/CMakeLists.txt8
-rw-r--r--Tests/CTestTestFailure/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestFailure/badCode.cxx4
-rw-r--r--Tests/CTestTestFailure/testNoBuild.cmake.in23
-rw-r--r--Tests/CTestTestFailure/testNoExe.cmake.in21
-rw-r--r--Tests/CTestTestFdSetSize/CMakeLists.txt9
-rw-r--r--Tests/CTestTestFdSetSize/sleep.c16
-rw-r--r--Tests/CTestTestFdSetSize/test.cmake.in24
-rw-r--r--Tests/CTestTestLabelRegExp/CTestTestfile.cmake.in8
-rw-r--r--Tests/CTestTestLabelRegExp/test.cmake.in41
-rw-r--r--Tests/CTestTestLaunchers/launcher_compiler_test_project/CMakeLists.txt7
-rw-r--r--Tests/CTestTestLaunchers/launcher_compiler_test_project/CTestConfig.cmake5
-rw-r--r--Tests/CTestTestLaunchers/launcher_compiler_test_project/build_error.cxx5
-rw-r--r--Tests/CTestTestLaunchers/launcher_custom_command_test_project/CMakeLists.txt19
-rw-r--r--Tests/CTestTestLaunchers/launcher_custom_command_test_project/CTestConfig.cmake5
-rw-r--r--Tests/CTestTestLaunchers/launcher_custom_command_test_project/command.cmake5
-rw-r--r--Tests/CTestTestLaunchers/launcher_linker_test_project/CMakeLists.txt7
-rw-r--r--Tests/CTestTestLaunchers/launcher_linker_test_project/CTestConfig.cmake5
-rw-r--r--Tests/CTestTestLaunchers/launcher_linker_test_project/link_error.cxx6
-rw-r--r--Tests/CTestTestLaunchers/test.cmake.in52
-rw-r--r--Tests/CTestTestMissingDependsExe/CMakeLists.txt10
-rw-r--r--Tests/CTestTestParallel/CMakeLists.txt15
-rw-r--r--Tests/CTestTestParallel/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestParallel/lockFile.c19
-rw-r--r--Tests/CTestTestParallel/test.cmake.in23
-rw-r--r--Tests/CTestTestResourceLock/CMakeLists.txt13
-rw-r--r--Tests/CTestTestResourceLock/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestResourceLock/lockFile.c27
-rw-r--r--Tests/CTestTestResourceLock/test.cmake.in21
-rw-r--r--Tests/CTestTestRunScript/hello.cmake.in2
-rw-r--r--Tests/CTestTestRunScript/test.cmake.in2
-rw-r--r--Tests/CTestTestScheduler/CMakeLists.txt9
-rw-r--r--Tests/CTestTestScheduler/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestScheduler/sleep.c20
-rw-r--r--Tests/CTestTestScheduler/test.cmake.in30
-rw-r--r--Tests/CTestTestSerialInDepends/CMakeLists.txt23
-rw-r--r--Tests/CTestTestSerialInDepends/test.ctest16
-rw-r--r--Tests/CTestTestSerialOrder/CMakeLists.txt40
-rw-r--r--Tests/CTestTestSerialOrder/test.cmake31
-rw-r--r--Tests/CTestTestSkipReturnCode/CMakeLists.txt8
-rw-r--r--Tests/CTestTestSkipReturnCode/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestSkipReturnCode/test.cmake.in23
-rw-r--r--Tests/CTestTestStopTime/CMakeLists.txt11
-rw-r--r--Tests/CTestTestStopTime/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestStopTime/GetDate.cmake133
-rw-r--r--Tests/CTestTestStopTime/sleep.c20
-rw-r--r--Tests/CTestTestStopTime/test.cmake.in33
-rw-r--r--Tests/CTestTestSubdir/CMakeLists.txt7
-rw-r--r--Tests/CTestTestSubdir/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestSubdir/subdir/CMakeLists.txt2
-rw-r--r--Tests/CTestTestSubdir/subdir/main.c4
-rw-r--r--Tests/CTestTestSubdir/subdir2/CMakeLists.txt2
-rw-r--r--Tests/CTestTestSubdir/subdir2/main.c4
-rw-r--r--Tests/CTestTestSubdir/subdir3/CMakeLists.txt2
-rw-r--r--Tests/CTestTestSubdir/subdir3/main.c4
-rw-r--r--Tests/CTestTestSubdir/test.cmake.in23
-rw-r--r--Tests/CTestTestTimeout/CMakeLists.txt21
-rw-r--r--Tests/CTestTestTimeout/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestTimeout/sleep.c21
-rw-r--r--Tests/CTestTestTimeout/test.cmake.in40
-rw-r--r--Tests/CTestTestTimeout/timeout.cmake6
-rw-r--r--Tests/CTestTestUpload/CMakeLists.txt4
-rw-r--r--Tests/CTestTestUpload/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestUpload/sleep.c20
-rw-r--r--Tests/CTestTestUpload/test.cmake.in19
-rw-r--r--Tests/CTestTestVerboseOutput/CMakeLists.txt11
-rw-r--r--Tests/CTestTestVerboseOutput/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestVerboseOutput/nop.c4
-rw-r--r--Tests/CTestTestVerboseOutput/test.cmake.in20
-rw-r--r--Tests/CTestTestZeroTimeout/CMakeLists.txt8
-rw-r--r--Tests/CTestTestZeroTimeout/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestZeroTimeout/sleep.c16
-rw-r--r--Tests/CTestTestZeroTimeout/test.cmake.in22
-rw-r--r--Tests/CTestUpdateBZR.cmake.in153
-rw-r--r--Tests/CTestUpdateCVS.cmake.in181
-rw-r--r--Tests/CTestUpdateCommon.cmake312
-rw-r--r--Tests/CTestUpdateGIT.cmake.in386
-rwxr-xr-xTests/CTestUpdateGIT.sh.in6
-rw-r--r--Tests/CTestUpdateHG.cmake.in185
-rw-r--r--Tests/CTestUpdateP4.cmake.in261
-rw-r--r--Tests/CTestUpdateSVN.cmake.in168
-rw-r--r--Tests/CheckCompilerRelatedVariables/CMakeLists.txt109
-rw-r--r--Tests/CheckFortran.cmake55
-rw-r--r--Tests/CheckSwift.cmake61
-rw-r--r--Tests/CoberturaCoverage/DartConfiguration.tcl.in8
-rw-r--r--Tests/CoberturaCoverage/coverage.xml.in112
-rw-r--r--Tests/CoberturaCoverage/src/main/java/org/cmake/CoverageTest.java52
-rw-r--r--Tests/CommandLength/CMakeLists.txt17
-rw-r--r--Tests/CommandLength/test.c4
-rw-r--r--Tests/CommandLineTest/CMakeLists.txt79
-rw-r--r--Tests/CommandLineTest/CommandLineTest.cxx4
-rw-r--r--Tests/CommandLineTest/PreLoad.cmake1
-rw-r--r--Tests/CompatibleInterface/CMakeLists.txt130
-rw-r--r--Tests/CompatibleInterface/bar.cpp7
-rw-r--r--Tests/CompatibleInterface/empty.cpp1
-rw-r--r--Tests/CompatibleInterface/foo.cpp4
-rw-r--r--Tests/CompatibleInterface/iface2.cpp7
-rw-r--r--Tests/CompatibleInterface/iface2.h13
-rw-r--r--Tests/CompatibleInterface/main.cpp56
-rw-r--r--Tests/CompileCommandOutput/CMakeLists.txt16
-rw-r--r--Tests/CompileCommandOutput/compile_command_output.cxx9
-rw-r--r--Tests/CompileCommandOutput/file with spaces.cxx1
-rw-r--r--Tests/CompileCommandOutput/file_with_underscores.cxx5
-rw-r--r--Tests/CompileCommandOutput/file_with_underscores.h1
-rw-r--r--Tests/CompileCommandOutput/relative.cxx5
-rw-r--r--Tests/CompileCommandOutput/relative.h11
-rw-r--r--Tests/CompileDefinitions/CMakeLists.txt19
-rw-r--r--Tests/CompileDefinitions/add_def_cmd/CMakeLists.txt12
-rw-r--r--Tests/CompileDefinitions/add_def_cmd_tprop/CMakeLists.txt16
-rw-r--r--Tests/CompileDefinitions/compiletest.c23
-rw-r--r--Tests/CompileDefinitions/compiletest.cpp112
-rw-r--r--Tests/CompileDefinitions/compiletest_mixed_c.c22
-rw-r--r--Tests/CompileDefinitions/compiletest_mixed_cxx.cpp23
-rw-r--r--Tests/CompileDefinitions/runtest.c42
-rw-r--r--Tests/CompileDefinitions/target_prop/CMakeLists.txt60
-rw-r--r--Tests/CompileDefinitions/target_prop/usetgt.c13
-rw-r--r--Tests/CompileFeatures/.gitattributes2
-rw-r--r--Tests/CompileFeatures/CMakeLists.txt375
-rw-r--r--Tests/CompileFeatures/c_function_prototypes.c9
-rw-r--r--Tests/CompileFeatures/c_restrict.c7
-rw-r--r--Tests/CompileFeatures/c_static_assert.c2
-rw-r--r--Tests/CompileFeatures/c_variadic_macros.c15
-rw-r--r--Tests/CompileFeatures/cxx_aggregate_default_initializers.cpp12
-rw-r--r--Tests/CompileFeatures/cxx_alias_templates.cpp11
-rw-r--r--Tests/CompileFeatures/cxx_alignas.cpp5
-rw-r--r--Tests/CompileFeatures/cxx_alignof.cpp5
-rw-r--r--Tests/CompileFeatures/cxx_attribute_deprecated.cpp7
-rw-r--r--Tests/CompileFeatures/cxx_attributes.cpp5
-rw-r--r--Tests/CompileFeatures/cxx_auto_type.cpp12
-rw-r--r--Tests/CompileFeatures/cxx_binary_literals.cpp6
-rw-r--r--Tests/CompileFeatures/cxx_constexpr.cpp5
-rw-r--r--Tests/CompileFeatures/cxx_contextual_conversions.cpp43
-rw-r--r--Tests/CompileFeatures/cxx_decltype.cpp7
-rw-r--r--Tests/CompileFeatures/cxx_decltype_auto.cpp6
-rw-r--r--Tests/CompileFeatures/cxx_decltype_incomplete_return_types.cpp19
-rw-r--r--Tests/CompileFeatures/cxx_default_function_template_args.cpp12
-rw-r--r--Tests/CompileFeatures/cxx_defaulted_functions.cpp10
-rw-r--r--Tests/CompileFeatures/cxx_defaulted_move_initializers.cpp7
-rw-r--r--Tests/CompileFeatures/cxx_delegating_constructors.cpp14
-rw-r--r--Tests/CompileFeatures/cxx_deleted_functions.cpp6
-rw-r--r--Tests/CompileFeatures/cxx_digit_separators.cpp6
-rw-r--r--Tests/CompileFeatures/cxx_enum_forward_declarations.cpp8
-rw-r--r--Tests/CompileFeatures/cxx_explicit_conversions.cpp8
-rw-r--r--Tests/CompileFeatures/cxx_extended_friend_declarations.cpp29
-rw-r--r--Tests/CompileFeatures/cxx_extern_templates.cpp12
-rw-r--r--Tests/CompileFeatures/cxx_final.cpp4
-rw-r--r--Tests/CompileFeatures/cxx_func_identifier.cpp6
-rw-r--r--Tests/CompileFeatures/cxx_generalized_initializers.cpp37
-rw-r--r--Tests/CompileFeatures/cxx_generic_lambdas.cpp6
-rw-r--r--Tests/CompileFeatures/cxx_inheriting_constructors.cpp21
-rw-r--r--Tests/CompileFeatures/cxx_inline_namespaces.cpp25
-rw-r--r--Tests/CompileFeatures/cxx_lambda_init_captures.cpp6
-rw-r--r--Tests/CompileFeatures/cxx_lambdas.cpp5
-rw-r--r--Tests/CompileFeatures/cxx_local_type_template_args.cpp35
-rw-r--r--Tests/CompileFeatures/cxx_long_long_type.cpp5
-rw-r--r--Tests/CompileFeatures/cxx_noexcept.cpp4
-rw-r--r--Tests/CompileFeatures/cxx_nonstatic_member_init.cpp4
-rw-r--r--Tests/CompileFeatures/cxx_nullptr.cpp9
-rw-r--r--Tests/CompileFeatures/cxx_override.cpp9
-rw-r--r--Tests/CompileFeatures/cxx_range_for.cpp9
-rw-r--r--Tests/CompileFeatures/cxx_raw_string_literals.cpp7
-rw-r--r--Tests/CompileFeatures/cxx_reference_qualified_functions.cpp13
-rw-r--r--Tests/CompileFeatures/cxx_relaxed_constexpr.cpp28
-rw-r--r--Tests/CompileFeatures/cxx_return_type_deduction.cpp10
-rw-r--r--Tests/CompileFeatures/cxx_right_angle_brackets.cpp14
-rw-r--r--Tests/CompileFeatures/cxx_rvalue_references.cpp4
-rw-r--r--Tests/CompileFeatures/cxx_sizeof_member.cpp10
-rw-r--r--Tests/CompileFeatures/cxx_static_assert.cpp2
-rw-r--r--Tests/CompileFeatures/cxx_strong_enums.cpp7
-rw-r--r--Tests/CompileFeatures/cxx_template_template_parameters.cpp16
-rw-r--r--Tests/CompileFeatures/cxx_thread_local.cpp2
-rw-r--r--Tests/CompileFeatures/cxx_trailing_return_types.cpp5
-rw-r--r--Tests/CompileFeatures/cxx_unicode_literals.cpp5
-rw-r--r--Tests/CompileFeatures/cxx_uniform_initialization.cpp12
-rw-r--r--Tests/CompileFeatures/cxx_unrestricted_unions.cpp17
-rw-r--r--Tests/CompileFeatures/cxx_user_literals.cpp7
-rw-r--r--Tests/CompileFeatures/cxx_variable_templates.cpp10
-rw-r--r--Tests/CompileFeatures/cxx_variadic_macros.cpp12
-rw-r--r--Tests/CompileFeatures/cxx_variadic_templates.cpp72
-rw-r--r--Tests/CompileFeatures/default_dialect.c31
-rw-r--r--Tests/CompileFeatures/default_dialect.cpp54
-rw-r--r--Tests/CompileFeatures/feature_test.c10
-rw-r--r--Tests/CompileFeatures/feature_test.cpp10
-rw-r--r--Tests/CompileFeatures/genex_test.c43
-rw-r--r--Tests/CompileFeatures/genex_test.cpp78
-rw-r--r--Tests/CompileFeatures/main.cpp6
-rw-r--r--Tests/CompileOptions/CMakeLists.txt74
-rw-r--r--Tests/CompileOptions/main.cpp66
-rw-r--r--Tests/CompileOptions/other.cpp4
-rw-r--r--Tests/Complex/CMakeLists.txt456
-rw-r--r--Tests/Complex/Cache/CMakeCache.txt34
-rw-r--r--Tests/Complex/Executable/A.cxx9
-rw-r--r--Tests/Complex/Executable/A.h7
-rw-r--r--Tests/Complex/Executable/A.hh2
-rw-r--r--Tests/Complex/Executable/A.txt1
-rw-r--r--Tests/Complex/Executable/CMakeLists.txt174
-rw-r--r--Tests/Complex/Executable/Included.cmake2
-rw-r--r--Tests/Complex/Executable/Sub1/NameConflictTest.c4
-rw-r--r--Tests/Complex/Executable/Sub2/NameConflictTest.c4
-rw-r--r--Tests/Complex/Executable/Temp/CMakeLists.txt8
-rw-r--r--Tests/Complex/Executable/cmVersion.h.in1
-rw-r--r--Tests/Complex/Executable/complex.cxx1086
-rw-r--r--Tests/Complex/Executable/complex.file.cxx8
-rw-r--r--Tests/Complex/Executable/complex_nobuild.c1
-rw-r--r--Tests/Complex/Executable/complex_nobuild.cxx1
-rw-r--r--Tests/Complex/Executable/notInAllExe.cxx10
-rw-r--r--Tests/Complex/Executable/testSystemDir.cxx6
-rw-r--r--Tests/Complex/Executable/testcflags.c26
-rw-r--r--Tests/Complex/Library/CMakeLists.txt140
-rw-r--r--Tests/Complex/Library/ExtraSources/file1.cxx4
-rw-r--r--Tests/Complex/Library/ExtraSources/file1.h1
-rw-r--r--Tests/Complex/Library/SystemDir/testSystemDir.h5
-rw-r--r--Tests/Complex/Library/TestLink.c8
-rw-r--r--Tests/Complex/Library/create_file.cxx25
-rw-r--r--Tests/Complex/Library/dummy0
-rw-r--r--Tests/Complex/Library/empty.h0
-rw-r--r--Tests/Complex/Library/file2.cxx10
-rw-r--r--Tests/Complex/Library/file2.h1
-rw-r--r--Tests/Complex/Library/notInAllLib.cxx8
-rw-r--r--Tests/Complex/Library/sharedFile.cxx6
-rw-r--r--Tests/Complex/Library/sharedFile.h12
-rw-r--r--Tests/Complex/Library/testConly.c14
-rw-r--r--Tests/Complex/Library/testConly.h12
-rw-r--r--Tests/Complex/Library/test_preprocess.cmake7
-rw-r--r--Tests/Complex/VarTests.cmake258
-rw-r--r--Tests/Complex/cmTestConfigure.h.in80
-rw-r--r--Tests/Complex/cmTestConfigureEscape.h.in1
-rw-r--r--Tests/Complex/cmTestGeneratedHeader.h.in1
-rw-r--r--Tests/ComplexOneConfig/CMakeLists.txt413
-rw-r--r--Tests/ComplexOneConfig/Cache/CMakeCache.txt34
-rw-r--r--Tests/ComplexOneConfig/Executable/A.cxx9
-rw-r--r--Tests/ComplexOneConfig/Executable/A.h7
-rw-r--r--Tests/ComplexOneConfig/Executable/A.hh2
-rw-r--r--Tests/ComplexOneConfig/Executable/A.txt1
-rw-r--r--Tests/ComplexOneConfig/Executable/CMakeLists.txt174
-rw-r--r--Tests/ComplexOneConfig/Executable/Included.cmake2
-rw-r--r--Tests/ComplexOneConfig/Executable/Sub1/NameConflictTest.c4
-rw-r--r--Tests/ComplexOneConfig/Executable/Sub2/NameConflictTest.c4
-rw-r--r--Tests/ComplexOneConfig/Executable/Temp/CMakeLists.txt8
-rw-r--r--Tests/ComplexOneConfig/Executable/cmVersion.h.in1
-rw-r--r--Tests/ComplexOneConfig/Executable/complex.cxx1086
-rw-r--r--Tests/ComplexOneConfig/Executable/complex.file.cxx8
-rw-r--r--Tests/ComplexOneConfig/Executable/complex_nobuild.c1
-rw-r--r--Tests/ComplexOneConfig/Executable/complex_nobuild.cxx1
-rw-r--r--Tests/ComplexOneConfig/Executable/notInAllExe.cxx10
-rw-r--r--Tests/ComplexOneConfig/Executable/testSystemDir.cxx6
-rw-r--r--Tests/ComplexOneConfig/Executable/testcflags.c26
-rw-r--r--Tests/ComplexOneConfig/Library/CMakeLists.txt140
-rw-r--r--Tests/ComplexOneConfig/Library/ExtraSources/file1.cxx4
-rw-r--r--Tests/ComplexOneConfig/Library/ExtraSources/file1.h1
-rw-r--r--Tests/ComplexOneConfig/Library/SystemDir/testSystemDir.h5
-rw-r--r--Tests/ComplexOneConfig/Library/TestLink.c8
-rw-r--r--Tests/ComplexOneConfig/Library/create_file.cxx25
-rw-r--r--Tests/ComplexOneConfig/Library/dummy0
-rw-r--r--Tests/ComplexOneConfig/Library/empty.h0
-rw-r--r--Tests/ComplexOneConfig/Library/file2.cxx10
-rw-r--r--Tests/ComplexOneConfig/Library/file2.h1
-rw-r--r--Tests/ComplexOneConfig/Library/notInAllLib.cxx8
-rw-r--r--Tests/ComplexOneConfig/Library/sharedFile.cxx6
-rw-r--r--Tests/ComplexOneConfig/Library/sharedFile.h12
-rw-r--r--Tests/ComplexOneConfig/Library/testConly.c14
-rw-r--r--Tests/ComplexOneConfig/Library/testConly.h12
-rw-r--r--Tests/ComplexOneConfig/Library/test_preprocess.cmake7
-rw-r--r--Tests/ComplexOneConfig/VarTests.cmake258
-rw-r--r--Tests/ComplexOneConfig/cmTestConfigure.h.in80
-rw-r--r--Tests/ComplexOneConfig/cmTestConfigureEscape.h.in1
-rw-r--r--Tests/ComplexOneConfig/cmTestGeneratedHeader.h.in1
-rw-r--r--Tests/ConfigSources/CMakeLists.txt179
-rw-r--r--Tests/ConfigSources/custom1.cpp.in13
-rw-r--r--Tests/ConfigSources/custom2.cpp.in13
-rw-r--r--Tests/ConfigSources/custom3.cpp.in13
-rw-r--r--Tests/ConfigSources/custom4.cpp.in13
-rw-r--r--Tests/ConfigSources/custom5.cpp.in13
-rw-r--r--Tests/ConfigSources/iface.h10
-rw-r--r--Tests/ConfigSources/iface_debug_src.cpp13
-rw-r--r--Tests/ConfigSources/iface_other_src.cpp13
-rw-r--r--Tests/ConfigSources/iface_src.cpp5
-rw-r--r--Tests/ConfigSources/main.cpp9
-rw-r--r--Tests/ConfigSources/main_debug.cpp20
-rw-r--r--Tests/ConfigSources/main_other.cpp20
-rw-r--r--Tests/ConfigSources/shared.cpp8
-rw-r--r--Tests/Contracts/Home.cmake19
-rw-r--r--Tests/Contracts/PLplot/CMakeLists.txt18
-rw-r--r--Tests/Contracts/PLplot/Configure.cmake4
-rw-r--r--Tests/Contracts/Trilinos/CMakeLists.txt86
-rw-r--r--Tests/Contracts/Trilinos/Configure.cmake7
-rw-r--r--Tests/Contracts/Trilinos/Dashboard.cmake.in63
-rw-r--r--Tests/Contracts/Trilinos/Patch.cmake38
-rw-r--r--Tests/Contracts/Trilinos/ValidateBuild.cmake.in39
-rw-r--r--Tests/Contracts/VTK/CMakeLists.txt30
-rw-r--r--Tests/Contracts/VTK/Configure.cmake3
-rw-r--r--Tests/Contracts/VTK/Dashboard.cmake.in37
-rw-r--r--Tests/CrossCompile/CMakeLists.txt13
-rw-r--r--Tests/CrossCompile/main.c4
-rw-r--r--Tests/Cuda/CMakeLists.txt34
-rw-r--r--Tests/Cuda/CXXStandardSetTwice/CMakeLists.txt12
-rw-r--r--Tests/Cuda/CXXStandardSetTwice/main.cu10
-rw-r--r--Tests/Cuda/Complex/CMakeLists.txt57
-rw-r--r--Tests/Cuda/Complex/dynamic.cpp11
-rw-r--r--Tests/Cuda/Complex/dynamic.cu73
-rw-r--r--Tests/Cuda/Complex/file1.cu10
-rw-r--r--Tests/Cuda/Complex/file1.h7
-rw-r--r--Tests/Cuda/Complex/file2.cu16
-rw-r--r--Tests/Cuda/Complex/file2.h10
-rw-r--r--Tests/Cuda/Complex/file3.cu48
-rw-r--r--Tests/Cuda/Complex/main.cpp27
-rw-r--r--Tests/Cuda/Complex/mixed.cpp22
-rw-r--r--Tests/Cuda/Complex/mixed.cu63
-rw-r--r--Tests/Cuda/ConsumeCompileFeatures/CMakeLists.txt16
-rw-r--r--Tests/Cuda/ConsumeCompileFeatures/main.cu20
-rw-r--r--Tests/Cuda/ConsumeCompileFeatures/static.cpp10
-rw-r--r--Tests/Cuda/ConsumeCompileFeatures/static.cu9
-rw-r--r--Tests/Cuda/IncludePathNoToolkit/CMakeLists.txt11
-rw-r--r--Tests/Cuda/IncludePathNoToolkit/main.cpp8
-rw-r--r--Tests/Cuda/MixedStandardLevels1/CMakeLists.txt12
-rw-r--r--Tests/Cuda/MixedStandardLevels1/lib.cpp7
-rw-r--r--Tests/Cuda/MixedStandardLevels1/main.cu9
-rw-r--r--Tests/Cuda/MixedStandardLevels2/CMakeLists.txt12
-rw-r--r--Tests/Cuda/MixedStandardLevels2/lib.cpp7
-rw-r--r--Tests/Cuda/MixedStandardLevels2/main.cu11
-rw-r--r--Tests/Cuda/MixedStandardLevels3/CMakeLists.txt10
-rw-r--r--Tests/Cuda/MixedStandardLevels3/lib.cpp7
-rw-r--r--Tests/Cuda/MixedStandardLevels3/main.cu5
-rw-r--r--Tests/Cuda/MixedStandardLevels4/CMakeLists.txt12
-rw-r--r--Tests/Cuda/MixedStandardLevels4/lib.cpp16
-rw-r--r--Tests/Cuda/MixedStandardLevels4/main.cu5
-rw-r--r--Tests/Cuda/MixedStandardLevels5/CMakeLists.txt11
-rw-r--r--Tests/Cuda/MixedStandardLevels5/lib.cpp13
-rw-r--r--Tests/Cuda/MixedStandardLevels5/main.cu8
-rw-r--r--Tests/Cuda/NotEnabled/CMakeLists.txt14
-rw-r--r--Tests/Cuda/NotEnabled/lib.cxx5
-rw-r--r--Tests/Cuda/NotEnabled/main.cxx9
-rw-r--r--Tests/Cuda/ObjectLibrary/CMakeLists.txt20
-rw-r--r--Tests/Cuda/ObjectLibrary/Conflicts/CMakeLists.txt2
-rw-r--r--Tests/Cuda/ObjectLibrary/Conflicts/static.cu18
-rw-r--r--Tests/Cuda/ObjectLibrary/main.cpp18
-rw-r--r--Tests/Cuda/ObjectLibrary/static.cpp6
-rw-r--r--Tests/Cuda/ObjectLibrary/static.cu18
-rw-r--r--Tests/Cuda/ProperDeviceLibraries/CMakeLists.txt49
-rw-r--r--Tests/Cuda/ProperDeviceLibraries/main.cu93
-rw-r--r--Tests/Cuda/ProperDeviceLibraries/use_pthreads.cu9
-rw-r--r--Tests/Cuda/ProperDeviceLibraries/use_pthreads.cxx9
-rw-r--r--Tests/Cuda/ProperLinkFlags/CMakeLists.txt24
-rw-r--r--Tests/Cuda/ProperLinkFlags/file1.cu10
-rw-r--r--Tests/Cuda/ProperLinkFlags/file1.h7
-rw-r--r--Tests/Cuda/ProperLinkFlags/main.cxx9
-rw-r--r--Tests/Cuda/SeparableCompCXXOnly/CMakeLists.txt3
-rw-r--r--Tests/Cuda/SeparableCompCXXOnly/main.cpp5
-rw-r--r--Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt35
-rw-r--r--Tests/Cuda/SharedRuntimePlusToolkit/curand.cpp65
-rw-r--r--Tests/Cuda/SharedRuntimePlusToolkit/main.cpp23
-rw-r--r--Tests/Cuda/SharedRuntimePlusToolkit/mixed.cpp16
-rw-r--r--Tests/Cuda/SharedRuntimePlusToolkit/nppif.cpp92
-rw-r--r--Tests/Cuda/SharedRuntimePlusToolkit/shared.cpp16
-rw-r--r--Tests/Cuda/SharedRuntimePlusToolkit/static.cpp16
-rw-r--r--Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt29
-rw-r--r--Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp59
-rw-r--r--Tests/Cuda/StaticRuntimePlusToolkit/main.cpp11
-rw-r--r--Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp8
-rw-r--r--Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp86
-rw-r--r--Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp8
-rw-r--r--Tests/Cuda/StaticRuntimePlusToolkit/static.cpp8
-rw-r--r--Tests/Cuda/Toolkit/CMakeLists.txt56
-rw-r--r--Tests/Cuda/Toolkit/main.cpp8
-rw-r--r--Tests/Cuda/WithC/CMakeLists.txt9
-rw-r--r--Tests/Cuda/WithC/cuda.cu16
-rw-r--r--Tests/Cuda/WithC/main.c14
-rw-r--r--Tests/CudaOnly/Architecture/CMakeLists.txt15
-rw-r--r--Tests/CudaOnly/Architecture/main.cu9
-rw-r--r--Tests/CudaOnly/CMakeLists.txt63
-rw-r--r--Tests/CudaOnly/CircularLinkLine/CMakeLists.txt33
-rw-r--r--Tests/CudaOnly/CircularLinkLine/file1.cu6
-rw-r--r--Tests/CudaOnly/CircularLinkLine/file2.cu6
-rw-r--r--Tests/CudaOnly/CircularLinkLine/file3.cu8
-rw-r--r--Tests/CudaOnly/CircularLinkLine/main.cu5
-rw-r--r--Tests/CudaOnly/CompileFlags/CMakeLists.txt16
-rw-r--r--Tests/CudaOnly/CompileFlags/main.cu13
-rw-r--r--Tests/CudaOnly/DontResolveDeviceSymbols/CMakeLists.txt49
-rw-r--r--Tests/CudaOnly/DontResolveDeviceSymbols/file1.cu69
-rw-r--r--Tests/CudaOnly/DontResolveDeviceSymbols/main.cu7
-rw-r--r--Tests/CudaOnly/DontResolveDeviceSymbols/verify.cmake14
-rw-r--r--Tests/CudaOnly/EnableStandard/CMakeLists.txt27
-rw-r--r--Tests/CudaOnly/EnableStandard/main.cu23
-rw-r--r--Tests/CudaOnly/EnableStandard/shared.cu15
-rw-r--r--Tests/CudaOnly/EnableStandard/static.cu9
-rw-r--r--Tests/CudaOnly/ExportPTX/CMakeLists.txt84
-rw-r--r--Tests/CudaOnly/ExportPTX/bin2c_wrapper.cmake19
-rw-r--r--Tests/CudaOnly/ExportPTX/kernelA.cu7
-rw-r--r--Tests/CudaOnly/ExportPTX/kernelB.cu8
-rw-r--r--Tests/CudaOnly/ExportPTX/main.cu28
-rw-r--r--Tests/CudaOnly/GPUDebugFlag/CMakeLists.txt22
-rw-r--r--Tests/CudaOnly/GPUDebugFlag/main.cu72
-rw-r--r--Tests/CudaOnly/PDB/CMakeLists.txt19
-rw-r--r--Tests/CudaOnly/PDB/check_pdbs.cmake10
-rw-r--r--Tests/CudaOnly/PDB/main.cu4
-rw-r--r--Tests/CudaOnly/ResolveDeviceSymbols/CMakeLists.txt62
-rw-r--r--Tests/CudaOnly/ResolveDeviceSymbols/file1.cu10
-rw-r--r--Tests/CudaOnly/ResolveDeviceSymbols/file1.h10
-rw-r--r--Tests/CudaOnly/ResolveDeviceSymbols/file2.cu9
-rw-r--r--Tests/CudaOnly/ResolveDeviceSymbols/file2.h12
-rw-r--r--Tests/CudaOnly/ResolveDeviceSymbols/file2_launch.cu18
-rw-r--r--Tests/CudaOnly/ResolveDeviceSymbols/main.cu58
-rw-r--r--Tests/CudaOnly/ResolveDeviceSymbols/verify.cmake14
-rw-r--r--Tests/CudaOnly/RuntimeControls/CMakeLists.txt58
-rw-r--r--Tests/CudaOnly/RuntimeControls/file1.cu18
-rw-r--r--Tests/CudaOnly/RuntimeControls/file2.cu18
-rw-r--r--Tests/CudaOnly/RuntimeControls/main.cu81
-rw-r--r--Tests/CudaOnly/RuntimeControls/no_runtime.cmake14
-rw-r--r--Tests/CudaOnly/RuntimeControls/uses_static_runtime.cmake14
-rw-r--r--Tests/CudaOnly/RuntimeControls/verify_runtime.cmake16
-rw-r--r--Tests/CudaOnly/SeparateCompilation/CMakeLists.txt59
-rw-r--r--Tests/CudaOnly/SeparateCompilation/file1.cu10
-rw-r--r--Tests/CudaOnly/SeparateCompilation/file1.h7
-rw-r--r--Tests/CudaOnly/SeparateCompilation/file2.cu16
-rw-r--r--Tests/CudaOnly/SeparateCompilation/file2.h10
-rw-r--r--Tests/CudaOnly/SeparateCompilation/file3.cu22
-rw-r--r--Tests/CudaOnly/SeparateCompilation/file4.cu23
-rw-r--r--Tests/CudaOnly/SeparateCompilation/file5.cu23
-rw-r--r--Tests/CudaOnly/SeparateCompilation/main.cu68
-rw-r--r--Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt42
-rw-r--r--Tests/CudaOnly/SharedRuntimePlusToolkit/curand.cu65
-rw-r--r--Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu23
-rw-r--r--Tests/CudaOnly/SharedRuntimePlusToolkit/mixed.cu16
-rw-r--r--Tests/CudaOnly/SharedRuntimePlusToolkit/nppif.cu92
-rw-r--r--Tests/CudaOnly/SharedRuntimePlusToolkit/shared.cu16
-rw-r--r--Tests/CudaOnly/SharedRuntimePlusToolkit/static.cu16
-rw-r--r--Tests/CudaOnly/SharedRuntimeViaCUDAFlags/CMakeLists.txt15
-rw-r--r--Tests/CudaOnly/SharedRuntimeViaCUDAFlags/main.cu5
-rw-r--r--Tests/CudaOnly/Standard98/CMakeLists.txt13
-rw-r--r--Tests/CudaOnly/Standard98/main.cu8
-rw-r--r--Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt35
-rw-r--r--Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu59
-rw-r--r--Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu11
-rw-r--r--Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu8
-rw-r--r--Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu86
-rw-r--r--Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu8
-rw-r--r--Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu8
-rw-r--r--Tests/CudaOnly/Toolkit/CMakeLists.txt61
-rw-r--r--Tests/CudaOnly/Toolkit/main.cu8
-rw-r--r--Tests/CudaOnly/ToolkitBeforeLang/CMakeLists.txt26
-rw-r--r--Tests/CudaOnly/ToolkitBeforeLang/main.cu8
-rw-r--r--Tests/CudaOnly/WithDefs/CMakeLists.txt38
-rw-r--r--Tests/CudaOnly/WithDefs/inc_cuda/inc_cuda.h1
-rw-r--r--Tests/CudaOnly/WithDefs/main.notcu96
-rw-r--r--Tests/CustComDepend/CMakeLists.txt14
-rw-r--r--Tests/CustComDepend/bar.h9
-rw-r--r--Tests/CustComDepend/foo.cxx13
-rw-r--r--Tests/CustomCommand/CMakeLists.txt588
-rw-r--r--Tests/CustomCommand/GeneratedHeader/CMakeLists.txt13
-rw-r--r--Tests/CustomCommand/GeneratedHeader/generated.h.in1
-rw-r--r--Tests/CustomCommand/GeneratedHeader/main.cpp5
-rw-r--r--Tests/CustomCommand/GeneratorInExtraDir/CMakeLists.txt8
-rw-r--r--Tests/CustomCommand/check_command_line.c.in36
-rw-r--r--Tests/CustomCommand/check_mark.cmake5
-rw-r--r--Tests/CustomCommand/compare_options.cmake14
-rw-r--r--Tests/CustomCommand/doc1.tex1
-rw-r--r--Tests/CustomCommand/empty_command.cxx4
-rw-r--r--Tests/CustomCommand/foo.h.in1
-rw-r--r--Tests/CustomCommand/foo.in32
-rw-r--r--Tests/CustomCommand/gen_redirect_in.c8
-rw-r--r--Tests/CustomCommand/generator.cxx18
-rw-r--r--Tests/CustomCommand/mac_fw.c4
-rw-r--r--Tests/CustomCommand/main.cxx6
-rw-r--r--Tests/CustomCommand/source_in_custom_target.cpp0
-rw-r--r--Tests/CustomCommand/subdir.h.in1
-rw-r--r--Tests/CustomCommand/tcat.cxx10
-rw-r--r--Tests/CustomCommand/wrapped.h1
-rw-r--r--Tests/CustomCommand/wrapper.cxx29
-rw-r--r--Tests/CustomCommandByproducts/CMakeLists.txt177
-rw-r--r--Tests/CustomCommandByproducts/CustomCommandByproducts.c16
-rw-r--r--Tests/CustomCommandByproducts/External/CMakeLists.txt4
-rw-r--r--Tests/CustomCommandByproducts/External/ExternalLibrary.c4
-rw-r--r--Tests/CustomCommandByproducts/ProducerExe.c4
-rw-r--r--Tests/CustomCommandByproducts/byproduct1.c.in1
-rw-r--r--Tests/CustomCommandByproducts/byproduct2.c.in1
-rw-r--r--Tests/CustomCommandByproducts/byproduct3.c.in1
-rw-r--r--Tests/CustomCommandByproducts/byproduct4.c.in1
-rw-r--r--Tests/CustomCommandByproducts/byproduct5.c.in1
-rw-r--r--Tests/CustomCommandByproducts/byproduct6.c.in1
-rw-r--r--Tests/CustomCommandByproducts/byproduct7.c.in1
-rw-r--r--Tests/CustomCommandByproducts/byproduct8.c.in1
-rw-r--r--Tests/CustomCommandByproducts/byproduct9.c.in1
-rw-r--r--Tests/CustomCommandByproducts/ninja-check.cmake20
-rw-r--r--Tests/CustomCommandWorkingDirectory/CMakeLists.txt64
-rw-r--r--Tests/CustomCommandWorkingDirectory/customTarget.c4
-rw-r--r--Tests/CustomCommandWorkingDirectory/working.c.in7
-rw-r--r--Tests/CxxDialect/CMakeLists.txt28
-rw-r--r--Tests/CxxDialect/use_constexpr.cxx10
-rw-r--r--Tests/CxxDialect/use_constexpr_and_typeof.cxx11
-rw-r--r--Tests/CxxDialect/use_typeof.cxx6
-rw-r--r--Tests/CxxOnly/CMakeLists.txt14
-rw-r--r--Tests/CxxOnly/cxxonly.cxx25
-rw-r--r--Tests/CxxOnly/libcxx1.cxx6
-rw-r--r--Tests/CxxOnly/libcxx1.h5
-rw-r--r--Tests/CxxOnly/libcxx2.cxx6
-rw-r--r--Tests/CxxOnly/libcxx2.h15
-rw-r--r--Tests/CxxOnly/test.C1
-rw-r--r--Tests/CxxOnly/test.CPP1
-rw-r--r--Tests/CxxOnly/testCxxModule.cxx9
-rw-r--r--Tests/CxxSubdirC/CMakeLists.txt4
-rw-r--r--Tests/CxxSubdirC/Cdir/CMakeLists.txt2
-rw-r--r--Tests/CxxSubdirC/Cdir/Cobj.c4
-rw-r--r--Tests/CxxSubdirC/main.cxx5
-rw-r--r--Tests/DelphiCoverage/DartConfiguration.tcl.in8
-rw-r--r--Tests/DelphiCoverage/UTCovTest(UTCovTest.pas).html.in117
-rw-r--r--Tests/DelphiCoverage/src/UTCovTest.pas75
-rw-r--r--Tests/Dependency/1/CMakeLists.txt3
-rw-r--r--Tests/Dependency/1/OneSrc.c3
-rw-r--r--Tests/Dependency/CMakeLists.txt54
-rw-r--r--Tests/Dependency/Case1/CMakeLists.txt19
-rw-r--r--Tests/Dependency/Case1/a.c4
-rw-r--r--Tests/Dependency/Case1/b.c6
-rw-r--r--Tests/Dependency/Case1/b2.c4
-rw-r--r--Tests/Dependency/Case1/c.c6
-rw-r--r--Tests/Dependency/Case1/c2.c6
-rw-r--r--Tests/Dependency/Case1/d.c6
-rw-r--r--Tests/Dependency/Case1/main.c10
-rw-r--r--Tests/Dependency/Case2/CMakeLists.txt22
-rw-r--r--Tests/Dependency/Case2/bar1.c10
-rw-r--r--Tests/Dependency/Case2/bar2.c5
-rw-r--r--Tests/Dependency/Case2/bar3.c5
-rw-r--r--Tests/Dependency/Case2/foo1.c5
-rw-r--r--Tests/Dependency/Case2/foo1b.c5
-rw-r--r--Tests/Dependency/Case2/foo1c.c5
-rw-r--r--Tests/Dependency/Case2/foo2.c5
-rw-r--r--Tests/Dependency/Case2/foo2b.c5
-rw-r--r--Tests/Dependency/Case2/foo2c.c5
-rw-r--r--Tests/Dependency/Case2/foo3.c5
-rw-r--r--Tests/Dependency/Case2/foo3b.c5
-rw-r--r--Tests/Dependency/Case2/foo3c.c4
-rw-r--r--Tests/Dependency/Case2/zot.c5
-rw-r--r--Tests/Dependency/Case3/CMakeLists.txt10
-rw-r--r--Tests/Dependency/Case3/bar.c5
-rw-r--r--Tests/Dependency/Case3/foo1.c5
-rw-r--r--Tests/Dependency/Case3/foo1b.c4
-rw-r--r--Tests/Dependency/Case3/foo2.c5
-rw-r--r--Tests/Dependency/Case4/CMakeLists.txt19
-rw-r--r--Tests/Dependency/Case4/bar.c5
-rw-r--r--Tests/Dependency/Case4/foo.c4
-rw-r--r--Tests/Dependency/Case5/CMakeLists.txt8
-rw-r--r--Tests/Dependency/Case5/bar.c12
-rw-r--r--Tests/Dependency/Case5/foo.c9
-rw-r--r--Tests/Dependency/Case5/main.c7
-rw-r--r--Tests/Dependency/Eight/CMakeLists.txt3
-rw-r--r--Tests/Dependency/Eight/EightSrc.c6
-rw-r--r--Tests/Dependency/Exec/CMakeLists.txt7
-rw-r--r--Tests/Dependency/Exec/ExecMain.c18
-rw-r--r--Tests/Dependency/Exec2/CMakeLists.txt12
-rw-r--r--Tests/Dependency/Exec2/ExecMain.c14
-rw-r--r--Tests/Dependency/Exec3/CMakeLists.txt6
-rw-r--r--Tests/Dependency/Exec3/ExecMain.c14
-rw-r--r--Tests/Dependency/Exec4/CMakeLists.txt6
-rw-r--r--Tests/Dependency/Exec4/ExecMain.c14
-rw-r--r--Tests/Dependency/Five/CMakeLists.txt3
-rw-r--r--Tests/Dependency/Five/FiveSrc.c6
-rw-r--r--Tests/Dependency/Four/CMakeLists.txt6
-rw-r--r--Tests/Dependency/Four/FourSrc.c15
-rw-r--r--Tests/Dependency/NoDepA/CMakeLists.txt1
-rw-r--r--Tests/Dependency/NoDepA/NoDepASrc.c3
-rw-r--r--Tests/Dependency/NoDepB/CMakeLists.txt3
-rw-r--r--Tests/Dependency/NoDepB/NoDepBSrc.c6
-rw-r--r--Tests/Dependency/NoDepC/CMakeLists.txt3
-rw-r--r--Tests/Dependency/NoDepC/NoDepCSrc.c6
-rw-r--r--Tests/Dependency/Seven/CMakeLists.txt3
-rw-r--r--Tests/Dependency/Seven/SevenSrc.c6
-rw-r--r--Tests/Dependency/Six/CMakeLists.txt12
-rw-r--r--Tests/Dependency/Six/SixASrc.c8
-rw-r--r--Tests/Dependency/Six/SixBSrc.c10
-rw-r--r--Tests/Dependency/Three/CMakeLists.txt3
-rw-r--r--Tests/Dependency/Three/ThreeSrc.c12
-rw-r--r--Tests/Dependency/Two/CMakeLists.txt20
-rw-r--r--Tests/Dependency/Two/TwoCustomSrc.c10
-rw-r--r--Tests/Dependency/Two/TwoSrc.c10
-rw-r--r--Tests/Dependency/Two/two-test.h.in1
-rw-r--r--Tests/DoubleProject/CMakeLists.txt3
-rw-r--r--Tests/DoubleProject/silly.c4
-rw-r--r--Tests/EmptyDepends/CMakeLists.txt15
-rw-r--r--Tests/EmptyLibrary/CMakeLists.txt4
-rw-r--r--Tests/EmptyLibrary/subdir/CMakeLists.txt1
-rw-r--r--Tests/EmptyLibrary/subdir/test.h1
-rw-r--r--Tests/EmptyProperty/CMakeLists.txt9
-rw-r--r--Tests/EmptyProperty/EmptyProperty.cxx4
-rw-r--r--Tests/EnforceConfig.cmake.in38
-rw-r--r--Tests/Environment/CMakeLists.txt26
-rw-r--r--Tests/Environment/main.cxx15
-rw-r--r--Tests/ExportImport/CMakeLists.txt83
-rw-r--r--Tests/ExportImport/Export/CMakeLists.txt686
-rw-r--r--Tests/ExportImport/Export/Interface/CMakeLists.txt104
-rw-r--r--Tests/ExportImport/Export/Interface/headergen.h.in1
-rw-r--r--Tests/ExportImport/Export/Interface/headeronly/headeronly.h10
-rw-r--r--Tests/ExportImport/Export/Interface/pch/pch.h1
-rw-r--r--Tests/ExportImport/Export/Interface/sharedlib.cpp7
-rw-r--r--Tests/ExportImport/Export/Interface/sharedlib/sharedlib.h7
-rw-r--r--Tests/ExportImport/Export/Interface/source_target.cpp13
-rw-r--r--Tests/ExportImport/Export/Interface/source_target_for_install.cpp13
-rw-r--r--Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt6
-rw-r--r--Tests/ExportImport/Export/SubDirLinkA/SubDirLinkA.c11
-rw-r--r--Tests/ExportImport/Export/SubDirLinkB/CMakeLists.txt4
-rw-r--r--Tests/ExportImport/Export/cmp0022.cpp7
-rw-r--r--Tests/ExportImport/Export/cmp0022.h4
-rw-r--r--Tests/ExportImport/Export/cmp0022_vs6_1.cpp1
-rw-r--r--Tests/ExportImport/Export/cmp0022_vs6_2.cpp1
-rw-r--r--Tests/ExportImport/Export/empty.cpp7
-rw-r--r--Tests/ExportImport/Export/include/abs/1a/testLibAbs1a.h1
-rw-r--r--Tests/ExportImport/Export/include/abs/1b/testLibAbs1b.h1
-rw-r--r--Tests/ExportImport/Export/include/abs/testLibAbs1.h1
-rw-r--r--Tests/ExportImport/Export/renamed/CMakeLists.txt20
-rw-r--r--Tests/ExportImport/Export/renamed/renamed.cxx7
-rw-r--r--Tests/ExportImport/Export/renamed/renamed.h12
-rw-r--r--Tests/ExportImport/Export/sub/testLib8C.c4
-rw-r--r--Tests/ExportImport/Export/sublib/CMakeLists.txt6
-rw-r--r--Tests/ExportImport/Export/sublib/subdir.cpp7
-rw-r--r--Tests/ExportImport/Export/sublib/subdir.h12
-rw-r--r--Tests/ExportImport/Export/systemlib.cpp6
-rw-r--r--Tests/ExportImport/Export/systemlib.h22
-rw-r--r--Tests/ExportImport/Export/testExe1.c22
-rw-r--r--Tests/ExportImport/Export/testExe1lib.c4
-rw-r--r--Tests/ExportImport/Export/testExe2.c15
-rw-r--r--Tests/ExportImport/Export/testExe2lib.c13
-rw-r--r--Tests/ExportImport/Export/testExe2libImp.c10
-rw-r--r--Tests/ExportImport/Export/testExe3.c20
-rw-r--r--Tests/ExportImport/Export/testExe4.c20
-rw-r--r--Tests/ExportImport/Export/testLib1.c4
-rw-r--r--Tests/ExportImport/Export/testLib1file1.txt1
-rw-r--r--Tests/ExportImport/Export/testLib1file2.txt1
-rw-r--r--Tests/ExportImport/Export/testLib2.c7
-rw-r--r--Tests/ExportImport/Export/testLib3.c13
-rw-r--r--Tests/ExportImport/Export/testLib3Imp.c13
-rw-r--r--Tests/ExportImport/Export/testLib3ImpDep.c10
-rw-r--r--Tests/ExportImport/Export/testLib4.c10
-rw-r--r--Tests/ExportImport/Export/testLib4.h2
-rw-r--r--Tests/ExportImport/Export/testLib4lib.c4
-rw-r--r--Tests/ExportImport/Export/testLib4libdbg.c14
-rw-r--r--Tests/ExportImport/Export/testLib4libopt.c14
-rw-r--r--Tests/ExportImport/Export/testLib5.c10
-rw-r--r--Tests/ExportImport/Export/testLib6.cxx6
-rw-r--r--Tests/ExportImport/Export/testLib6c.c5
-rw-r--r--Tests/ExportImport/Export/testLib7.c4
-rw-r--r--Tests/ExportImport/Export/testLib8A.c4
-rw-r--r--Tests/ExportImport/Export/testLib8B.c4
-rw-r--r--Tests/ExportImport/Export/testLib9.c15
-rw-r--r--Tests/ExportImport/Export/testLib9ObjIface.c11
-rw-r--r--Tests/ExportImport/Export/testLib9ObjPriv.c4
-rw-r--r--Tests/ExportImport/Export/testLib9ObjPub.c4
-rw-r--r--Tests/ExportImport/Export/testLibAbs1.c4
-rw-r--r--Tests/ExportImport/Export/testLibCycleA1.c5
-rw-r--r--Tests/ExportImport/Export/testLibCycleA2.c5
-rw-r--r--Tests/ExportImport/Export/testLibCycleA3.c5
-rw-r--r--Tests/ExportImport/Export/testLibCycleB1.c5
-rw-r--r--Tests/ExportImport/Export/testLibCycleB2.c5
-rw-r--r--Tests/ExportImport/Export/testLibCycleB3.c4
-rw-r--r--Tests/ExportImport/Export/testLibDepends.c24
-rw-r--r--Tests/ExportImport/Export/testLibNoSONAME.c10
-rw-r--r--Tests/ExportImport/Export/testLibPerConfigDest.c4
-rw-r--r--Tests/ExportImport/Export/testLibRequired.c4
-rw-r--r--Tests/ExportImport/Export/testSharedLibDepends.cpp9
-rw-r--r--Tests/ExportImport/Export/testSharedLibDepends.h14
-rw-r--r--Tests/ExportImport/Export/testSharedLibRequired.cpp7
-rw-r--r--Tests/ExportImport/Export/testSharedLibRequired.h12
-rw-r--r--Tests/ExportImport/Export/testSharedLibRequiredUser.cpp10
-rw-r--r--Tests/ExportImport/Export/testSharedLibRequiredUser.h12
-rw-r--r--Tests/ExportImport/Export/testSharedLibRequiredUser2.cpp8
-rw-r--r--Tests/ExportImport/Export/testSharedLibRequiredUser2.h13
-rw-r--r--Tests/ExportImport/Export/testStaticLibRequiredPrivate.c4
-rw-r--r--Tests/ExportImport/Export/testTopDirLib.c11
-rw-r--r--Tests/ExportImport/Import/A/CMakeLists.txt514
-rw-r--r--Tests/ExportImport/Import/A/SubDirLink.c14
-rw-r--r--Tests/ExportImport/Import/A/check_lib_nosoname.cmake7
-rw-r--r--Tests/ExportImport/Import/A/check_lib_soname.cmake7
-rw-r--r--Tests/ExportImport/Import/A/check_testLib1_genex.cmake11
-rw-r--r--Tests/ExportImport/Import/A/cmp0022NEW_test.cpp12
-rw-r--r--Tests/ExportImport/Import/A/cmp0022NEW_test_vs6_1.cpp1
-rw-r--r--Tests/ExportImport/Import/A/cmp0022NEW_test_vs6_2.cpp1
-rw-r--r--Tests/ExportImport/Import/A/cmp0022OLD_test.cpp12
-rw-r--r--Tests/ExportImport/Import/A/cmp0022OLD_test_vs6_1.cpp1
-rw-r--r--Tests/ExportImport/Import/A/cmp0022OLD_test_vs6_2.cpp1
-rw-r--r--Tests/ExportImport/Import/A/deps_iface.c32
-rw-r--r--Tests/ExportImport/Import/A/deps_shared_iface.cpp49
-rw-r--r--Tests/ExportImport/Import/A/excludedFromAll/CMakeLists.txt7
-rw-r--r--Tests/ExportImport/Import/A/excludedFromAll/excludedFromAll.cpp7
-rw-r--r--Tests/ExportImport/Import/A/excludedFromAll/excludedFromAll.h4
-rw-r--r--Tests/ExportImport/Import/A/framework_interface/CMakeLists.txt9
-rw-r--r--Tests/ExportImport/Import/A/framework_interface/framework_test.cpp6
-rw-r--r--Tests/ExportImport/Import/A/iface_test.cpp11
-rw-r--r--Tests/ExportImport/Import/A/imp_lib1.c6
-rw-r--r--Tests/ExportImport/Import/A/imp_mod1.c13
-rw-r--r--Tests/ExportImport/Import/A/imp_testExe1.c29
-rw-r--r--Tests/ExportImport/Import/A/imp_testExeAbs1.c13
-rw-r--r--Tests/ExportImport/Import/A/imp_testLib8.c8
-rw-r--r--Tests/ExportImport/Import/A/imp_testLib9.c16
-rw-r--r--Tests/ExportImport/Import/A/imp_testLinkOptions.cpp8
-rw-r--r--Tests/ExportImport/Import/A/renamed_test.cpp8
-rw-r--r--Tests/ExportImport/Import/A/test_system.cpp9
-rw-r--r--Tests/ExportImport/Import/CMakeLists.txt28
-rw-r--r--Tests/ExportImport/Import/Interface/CMakeLists.txt137
-rw-r--r--Tests/ExportImport/Import/Interface/headergentest.cpp11
-rw-r--r--Tests/ExportImport/Import/Interface/headeronlytest.cpp16
-rw-r--r--Tests/ExportImport/Import/Interface/interfacetest.cpp20
-rw-r--r--Tests/ExportImport/Import/Interface/pch_iface_test.cpp17
-rw-r--r--Tests/ExportImport/Import/Interface/source_target_test.cpp7
-rw-r--r--Tests/ExportImport/Import/imp_testTransExe1.c6
-rw-r--r--Tests/ExportImport/Import/try_compile/CMakeLists.txt36
-rw-r--r--Tests/ExportImport/Import/version_range/CMakeLists.txt15
-rw-r--r--Tests/ExportImport/InitialCache.cmake.in17
-rw-r--r--Tests/ExportImport/main.c4
-rw-r--r--Tests/ExternalOBJ/CMakeLists.txt63
-rw-r--r--Tests/ExternalOBJ/Object/CMakeLists.txt13
-rw-r--r--Tests/ExternalOBJ/Object/external_main.cxx4
-rw-r--r--Tests/ExternalOBJ/Object/external_object.cxx4
-rw-r--r--Tests/ExternalOBJ/Sub/CMakeLists.txt3
-rw-r--r--Tests/ExternalOBJ/executable.cxx5
-rw-r--r--Tests/ExternalProject/CMakeLists.txt744
-rw-r--r--Tests/ExternalProject/Example/CMakeLists.txt11
-rw-r--r--Tests/ExternalProject/cvsrepo.tgzbin0 -> 1317 bytes-rw-r--r--Tests/ExternalProject/gitrepo-sub-rec.tgzbin0 -> 2086 bytes-rw-r--r--Tests/ExternalProject/gitrepo-sub.tgzbin0 -> 2229 bytes-rwxr-xr-xTests/ExternalProject/gitrepo.bash129
-rw-r--r--Tests/ExternalProject/gitrepo.tgzbin0 -> 1817 bytes-rw-r--r--Tests/ExternalProject/hgrepo.tgzbin0 -> 2011 bytes-rw-r--r--Tests/ExternalProject/svnrepo.tgzbin0 -> 3673 bytes-rw-r--r--Tests/ExternalProjectLocal/CMakeLists.txt225
-rw-r--r--Tests/ExternalProjectLocal/Step1.tarbin0 -> 5632 bytes-rw-r--r--Tests/ExternalProjectLocal/Step1.tar.bz2bin0 -> 904 bytes-rw-r--r--Tests/ExternalProjectLocal/Step1.tgzbin0 -> 791 bytes-rw-r--r--Tests/ExternalProjectLocal/Step1.zipbin0 -> 1074 bytes-rw-r--r--Tests/ExternalProjectLocal/Step1NoDir.tarbin0 -> 5120 bytes-rw-r--r--Tests/ExternalProjectLocal/Step1NoDir.tar.bz2bin0 -> 852 bytes-rw-r--r--Tests/ExternalProjectLocal/Step1NoDir.tgzbin0 -> 770 bytes-rw-r--r--Tests/ExternalProjectLocal/Step1NoDir.zipbin0 -> 1038 bytes-rw-r--r--Tests/ExternalProjectLocal/Step1Patch.cmake25
-rw-r--r--Tests/ExternalProjectLocal/Step5/CMakeLists.txt71
-rw-r--r--Tests/ExternalProjectLocal/Step5/MathFunctions/CMakeLists.txt17
-rw-r--r--Tests/ExternalProjectLocal/Step5/MathFunctions/MakeTable.cxx32
-rw-r--r--Tests/ExternalProjectLocal/Step5/MathFunctions/MathFunctions.h1
-rw-r--r--Tests/ExternalProjectLocal/Step5/MathFunctions/mysqrt.cxx41
-rw-r--r--Tests/ExternalProjectLocal/Step5/TutorialConfig.h.in8
-rw-r--r--Tests/ExternalProjectLocal/Step5/tutorial.cxx34
-rw-r--r--Tests/ExternalProjectSourceSubdir/CMakeLists.txt10
-rw-r--r--Tests/ExternalProjectSourceSubdir/Example/subdir/CMakeLists.txt2
-rw-r--r--Tests/ExternalProjectSourceSubdirNotCMake/CMakeLists.txt20
-rw-r--r--Tests/ExternalProjectSourceSubdirNotCMake/Example/subdir/Makefile2
-rw-r--r--Tests/ExternalProjectSubdir/CMakeLists.txt26
-rw-r--r--Tests/ExternalProjectSubdir/Subdir1/CMakeLists.txt14
-rw-r--r--Tests/ExternalProjectUpdate/CMakeLists.txt133
-rw-r--r--Tests/ExternalProjectUpdate/ExternalProjectUpdateTest.cmake240
-rw-r--r--Tests/ExternalProjectUpdate/gitrepo.tgzbin0 -> 3397 bytes-rw-r--r--Tests/FindALSA/CMakeLists.txt10
-rw-r--r--Tests/FindALSA/Test/CMakeLists.txt16
-rw-r--r--Tests/FindALSA/Test/main.c10
-rw-r--r--Tests/FindBLAS/CMakeLists.txt10
-rw-r--r--Tests/FindBLAS/Test/CMakeLists.txt13
-rw-r--r--Tests/FindBLAS/Test/main.c16
-rw-r--r--Tests/FindBZip2/CMakeLists.txt10
-rw-r--r--Tests/FindBZip2/Test/CMakeLists.txt16
-rw-r--r--Tests/FindBZip2/Test/main.c23
-rw-r--r--Tests/FindBoost/CMakeLists.txt49
-rw-r--r--Tests/FindBoost/Test/CMakeLists.txt31
-rw-r--r--Tests/FindBoost/Test/main.cxx39
-rw-r--r--Tests/FindBoost/TestFail/CMakeLists.txt18
-rw-r--r--Tests/FindBoost/TestFail/main.cxx24
-rw-r--r--Tests/FindBoost/TestHeaders/CMakeLists.txt10
-rw-r--r--Tests/FindBoost/TestHeaders/main.cxx10
-rw-r--r--Tests/FindBoost/TestPython/CMakeLists.txt17
-rw-r--r--Tests/FindCURL/CMakeLists.txt10
-rw-r--r--Tests/FindCURL/Test/CMakeLists.txt16
-rw-r--r--Tests/FindCURL/Test/main.c17
-rw-r--r--Tests/FindCups/CMakeLists.txt10
-rw-r--r--Tests/FindCups/Test/CMakeLists.txt16
-rw-r--r--Tests/FindCups/Test/main.c12
-rw-r--r--Tests/FindDevIL/CMakeLists.txt10
-rw-r--r--Tests/FindDevIL/Test/CMakeLists.txt29
-rw-r--r--Tests/FindDevIL/Test/main.c10
-rw-r--r--Tests/FindDevIL/Test/main_ilu.c8
-rw-r--r--Tests/FindDoxygen/AllTarget/CMakeLists.txt42
-rw-r--r--Tests/FindDoxygen/CMakeLists.txt50
-rw-r--r--Tests/FindDoxygen/DotComponentTestTest/CMakeLists.txt18
-rw-r--r--Tests/FindDoxygen/QuotingTest/CMakeLists.txt34
-rw-r--r--Tests/FindDoxygen/SimpleTest/CMakeLists.txt61
-rw-r--r--Tests/FindDoxygen/SimpleTest/main.cpp4
-rw-r--r--Tests/FindDoxygen/SimpleTest/spaces_in_name.cpp.in4
-rw-r--r--Tests/FindDoxygen/StampFile/CMakeLists.txt43
-rw-r--r--Tests/FindDoxygen/StampFile/main.cpp4
-rw-r--r--Tests/FindDoxygen/StampFile/main2.cpp4
-rw-r--r--Tests/FindEXPAT/CMakeLists.txt10
-rw-r--r--Tests/FindEXPAT/Test/CMakeLists.txt16
-rw-r--r--Tests/FindEXPAT/Test/main.c21
-rw-r--r--Tests/FindEnvModules/CMakeLists.txt3
-rw-r--r--Tests/FindEnvModules/EnvModules.cmake33
-rw-r--r--Tests/FindFontconfig/CMakeLists.txt10
-rw-r--r--Tests/FindFontconfig/Test/CMakeLists.txt16
-rw-r--r--Tests/FindFontconfig/Test/main.c17
-rw-r--r--Tests/FindFreetype/CMakeLists.txt10
-rw-r--r--Tests/FindFreetype/Test/CMakeLists.txt16
-rw-r--r--Tests/FindFreetype/Test/main.c34
-rw-r--r--Tests/FindGDAL/CMakeLists.txt10
-rw-r--r--Tests/FindGDAL/Test/CMakeLists.txt16
-rw-r--r--Tests/FindGDAL/Test/main.c11
-rw-r--r--Tests/FindGIF/CMakeLists.txt10
-rw-r--r--Tests/FindGIF/Test/CMakeLists.txt16
-rw-r--r--Tests/FindGIF/Test/main.c34
-rw-r--r--Tests/FindGLEW/CMakeLists.txt10
-rw-r--r--Tests/FindGLEW/Test/CMakeLists.txt18
-rw-r--r--Tests/FindGLEW/Test/main.cpp8
-rw-r--r--Tests/FindGSL/CMakeLists.txt9
-rw-r--r--Tests/FindGSL/rng/CMakeLists.txt14
-rw-r--r--Tests/FindGSL/rng/main.cc25
-rw-r--r--Tests/FindGTK2/CMakeLists.txt320
-rw-r--r--Tests/FindGTK2/atk/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/atk/main.c7
-rw-r--r--Tests/FindGTK2/atkmm/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/atkmm/main.cpp8
-rw-r--r--Tests/FindGTK2/cairo/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/cairo/main.c50
-rw-r--r--Tests/FindGTK2/cairomm/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/cairomm/main.cpp64
-rw-r--r--Tests/FindGTK2/gdk/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/gdk/main.c7
-rw-r--r--Tests/FindGTK2/gdk_pixbuf/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/gdk_pixbuf/main.c10
-rw-r--r--Tests/FindGTK2/gdkmm/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/gdkmm/main.cpp7
-rw-r--r--Tests/FindGTK2/gio/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/gio/main.c8
-rw-r--r--Tests/FindGTK2/giomm/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/giomm/main.cpp7
-rw-r--r--Tests/FindGTK2/glib/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/glib/main.c11
-rw-r--r--Tests/FindGTK2/glibmm/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/glibmm/main.cpp7
-rw-r--r--Tests/FindGTK2/gmodule/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/gmodule/main.c7
-rw-r--r--Tests/FindGTK2/gobject/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/gobject/main.c70
-rw-r--r--Tests/FindGTK2/gthread/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/gthread/main.c7
-rw-r--r--Tests/FindGTK2/gtk/CMakeLists.txt14
-rw-r--r--Tests/FindGTK2/gtk/main.c15
-rw-r--r--Tests/FindGTK2/gtkmm/CMakeLists.txt19
-rw-r--r--Tests/FindGTK2/gtkmm/helloworld.cpp30
-rw-r--r--Tests/FindGTK2/gtkmm/helloworld.h20
-rw-r--r--Tests/FindGTK2/gtkmm/main.cpp14
-rw-r--r--Tests/FindGTK2/pango/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/pango/main.c7
-rw-r--r--Tests/FindGTK2/pangocairo/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/pangocairo/main.c68
-rw-r--r--Tests/FindGTK2/pangoft2/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/pangoft2/main.c8
-rw-r--r--Tests/FindGTK2/pangomm/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/pangomm/main.cpp8
-rw-r--r--Tests/FindGTK2/pangoxft/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/pangoxft/main.c7
-rw-r--r--Tests/FindGTK2/sigc++/CMakeLists.txt10
-rw-r--r--Tests/FindGTK2/sigc++/main.cpp30
-rw-r--r--Tests/FindGTest/CMakeLists.txt10
-rw-r--r--Tests/FindGTest/Test/CMakeLists.txt18
-rw-r--r--Tests/FindGTest/Test/main.cxx8
-rw-r--r--Tests/FindGit/CMakeLists.txt10
-rw-r--r--Tests/FindGit/Test/CMakeLists.txt13
-rw-r--r--Tests/FindGit/Test/RunGit.cmake20
-rw-r--r--Tests/FindGnuTLS/CMakeLists.txt10
-rw-r--r--Tests/FindGnuTLS/Test/CMakeLists.txt17
-rw-r--r--Tests/FindGnuTLS/Test/main.c21
-rw-r--r--Tests/FindICU/CMakeLists.txt10
-rw-r--r--Tests/FindICU/Test/CMakeLists.txt14
-rw-r--r--Tests/FindICU/Test/main.cpp23
-rw-r--r--Tests/FindIconv/CMakeLists.txt10
-rw-r--r--Tests/FindIconv/Test/CMakeLists.txt16
-rw-r--r--Tests/FindIconv/Test/main.cxx52
-rw-r--r--Tests/FindIntl/CMakeLists.txt10
-rw-r--r--Tests/FindIntl/Test/CMakeLists.txt14
-rw-r--r--Tests/FindIntl/Test/main.cxx11
-rw-r--r--Tests/FindJPEG/CMakeLists.txt10
-rw-r--r--Tests/FindJPEG/Test/CMakeLists.txt16
-rw-r--r--Tests/FindJPEG/Test/main.c17
-rw-r--r--Tests/FindJsonCpp/CMakeLists.txt10
-rw-r--r--Tests/FindJsonCpp/Test/CMakeLists.txt17
-rw-r--r--Tests/FindJsonCpp/Test/main.cxx8
-rw-r--r--Tests/FindLAPACK/CMakeLists.txt10
-rw-r--r--Tests/FindLAPACK/Test/CMakeLists.txt13
-rw-r--r--Tests/FindLAPACK/Test/main.c20
-rw-r--r--Tests/FindLTTngUST/CMakeLists.txt10
-rw-r--r--Tests/FindLTTngUST/Test/CMakeLists.txt18
-rw-r--r--Tests/FindLTTngUST/Test/main.c31
-rw-r--r--Tests/FindLibArchive/CMakeLists.txt10
-rw-r--r--Tests/FindLibArchive/Test/CMakeLists.txt14
-rw-r--r--Tests/FindLibArchive/Test/main.c7
-rw-r--r--Tests/FindLibLZMA/CMakeLists.txt10
-rw-r--r--Tests/FindLibLZMA/Test/CMakeLists.txt14
-rw-r--r--Tests/FindLibLZMA/Test/main.c15
-rw-r--r--Tests/FindLibRHash/CMakeLists.txt10
-rw-r--r--Tests/FindLibRHash/Test/CMakeLists.txt17
-rw-r--r--Tests/FindLibRHash/Test/main.c7
-rw-r--r--Tests/FindLibUV/CMakeLists.txt10
-rw-r--r--Tests/FindLibUV/Test/CMakeLists.txt17
-rw-r--r--Tests/FindLibUV/Test/main.c7
-rw-r--r--Tests/FindLibXml2/CMakeLists.txt10
-rw-r--r--Tests/FindLibXml2/Test/CMakeLists.txt20
-rw-r--r--Tests/FindLibXml2/Test/main.c19
-rw-r--r--Tests/FindLibXslt/CMakeLists.txt10
-rw-r--r--Tests/FindLibXslt/Test/CMakeLists.txt45
-rw-r--r--Tests/FindLibXslt/Test/libexslt.c16
-rw-r--r--Tests/FindLibXslt/Test/libxslt.c24
-rw-r--r--Tests/FindLibinput/CMakeLists.txt10
-rw-r--r--Tests/FindLibinput/Test/CMakeLists.txt14
-rw-r--r--Tests/FindLibinput/Test/main.c13
-rw-r--r--Tests/FindMPI/CMakeLists.txt21
-rw-r--r--Tests/FindMPI/Test/CMakeLists.txt46
-rw-r--r--Tests/FindMPI/Test/main.c7
-rw-r--r--Tests/FindMPI/Test/main.f907
-rw-r--r--Tests/FindMatlab/basic_checks/CMakeLists.txt85
-rw-r--r--Tests/FindMatlab/cmake_matlab_unit_tests1.m33
-rw-r--r--Tests/FindMatlab/cmake_matlab_unit_tests2.m6
-rw-r--r--Tests/FindMatlab/cmake_matlab_unit_tests3.m5
-rw-r--r--Tests/FindMatlab/cmake_matlab_unit_tests4.m28
-rw-r--r--Tests/FindMatlab/cmake_matlab_unit_tests5.m20
-rw-r--r--Tests/FindMatlab/cmake_matlab_unit_tests_timeout.m16
-rw-r--r--Tests/FindMatlab/components_checks/CMakeLists.txt31
-rw-r--r--Tests/FindMatlab/failure_reports/CMakeLists.txt55
-rw-r--r--Tests/FindMatlab/help_text1.m.txt2
-rw-r--r--Tests/FindMatlab/matlab_wrapper1.cpp27
-rw-r--r--Tests/FindMatlab/matlab_wrapper2.cpp22
-rw-r--r--Tests/FindMatlab/matlab_wrapper3.cpp29
-rw-r--r--Tests/FindMatlab/matlab_wrapper_failure.cpp13
-rw-r--r--Tests/FindMatlab/r2018a_check/CMakeLists.txt84
-rw-r--r--Tests/FindMatlab/versions_checks/CMakeLists.txt59
-rw-r--r--Tests/FindODBC/CMakeLists.txt10
-rw-r--r--Tests/FindODBC/Test/CMakeLists.txt14
-rw-r--r--Tests/FindODBC/Test/main.c12
-rw-r--r--Tests/FindOpenACC/CMakeLists.txt20
-rw-r--r--Tests/FindOpenACC/CTest/CMakeLists.txt13
-rw-r--r--Tests/FindOpenACC/CTest/main.c44
-rw-r--r--Tests/FindOpenACC/CXXTest/CMakeLists.txt13
-rw-r--r--Tests/FindOpenACC/CXXTest/main.cxx43
-rw-r--r--Tests/FindOpenACC/FortranTest/CMakeLists.txt11
-rw-r--r--Tests/FindOpenACC/FortranTest/main.f909
-rw-r--r--Tests/FindOpenCL/CMakeLists.txt10
-rw-r--r--Tests/FindOpenCL/Test/CMakeLists.txt14
-rw-r--r--Tests/FindOpenCL/Test/main.c17
-rw-r--r--Tests/FindOpenGL/CMakeLists.txt17
-rw-r--r--Tests/FindOpenGL/Test/CMakeLists.txt71
-rw-r--r--Tests/FindOpenGL/Test/main.c17
-rw-r--r--Tests/FindOpenMP/CMakeLists.txt21
-rw-r--r--Tests/FindOpenMP/Test/CMakeLists.txt70
-rw-r--r--Tests/FindOpenMP/Test/main.c7
-rw-r--r--Tests/FindOpenMP/Test/main.f90.in5
-rw-r--r--Tests/FindOpenMP/Test/scalprod.c16
-rw-r--r--Tests/FindOpenMP/Test/scalprod.f90.in19
-rw-r--r--Tests/FindOpenMP/Test/scaltest.c20
-rw-r--r--Tests/FindOpenMP/Test/scaltest.f90.in21
-rw-r--r--Tests/FindOpenSSL/CMakeLists.txt9
-rw-r--r--Tests/FindOpenSSL/rand/CMakeLists.txt14
-rw-r--r--Tests/FindOpenSSL/rand/main.cc21
-rw-r--r--Tests/FindPNG/CMakeLists.txt10
-rw-r--r--Tests/FindPNG/Test/CMakeLists.txt16
-rw-r--r--Tests/FindPNG/Test/main.c18
-rw-r--r--Tests/FindPackageModeMakefileTest/CMakeLists.txt45
-rw-r--r--Tests/FindPackageModeMakefileTest/FindFoo.cmake.in11
-rw-r--r--Tests/FindPackageModeMakefileTest/Makefile.in33
-rw-r--r--Tests/FindPackageModeMakefileTest/foo.cpp6
-rw-r--r--Tests/FindPackageModeMakefileTest/foo.h14
-rw-r--r--Tests/FindPackageModeMakefileTest/main.cpp8
-rw-r--r--Tests/FindPackageTest/.gitignore1
-rw-r--r--Tests/FindPackageTest/A/wibble-config.cmake1
-rw-r--r--Tests/FindPackageTest/B/wibble-config.cmake1
-rw-r--r--Tests/FindPackageTest/Baz 1.1/BazConfig.cmake1
-rw-r--r--Tests/FindPackageTest/Baz 1.1/BazConfigVersion.cmake8
-rw-r--r--Tests/FindPackageTest/Baz 1.2/CMake/BazConfig.cmake1
-rw-r--r--Tests/FindPackageTest/Baz 1.2/CMake/BazConfigVersion.cmake8
-rw-r--r--Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfig.cmake1
-rw-r--r--Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfigVersion.cmake7
-rw-r--r--Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfig.cmake1
-rw-r--r--Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfigVersion.cmake7
-rw-r--r--Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfig.cmake1
-rw-r--r--Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfigVersion.cmake7
-rw-r--r--Tests/FindPackageTest/CMakeLists.txt661
-rw-r--r--Tests/FindPackageTest/Exporter/CMakeLists.txt12
-rw-r--r--Tests/FindPackageTest/Exporter/CMakeTestExportPackageConfig.cmake.in1
-rw-r--r--Tests/FindPackageTest/Exporter/CMakeTestExportPackageConfigVersion.cmake.in6
-rw-r--r--Tests/FindPackageTest/Exporter/dummy.c4
-rw-r--r--Tests/FindPackageTest/FindLotsOfComponents.cmake10
-rw-r--r--Tests/FindPackageTest/FindPackageHandleStandardArgs.cmake1
-rw-r--r--Tests/FindPackageTest/FindPackageTest.cxx4
-rw-r--r--Tests/FindPackageTest/FindRecursiveA.cmake1
-rw-r--r--Tests/FindPackageTest/FindRecursiveB.cmake1
-rw-r--r--Tests/FindPackageTest/FindRecursiveC.cmake1
-rw-r--r--Tests/FindPackageTest/FindSomePackage.cmake5
-rw-r--r--Tests/FindPackageTest/FindUpperCasePackage.cmake5
-rw-r--r--Tests/FindPackageTest/FindVersionTestA.cmake18
-rw-r--r--Tests/FindPackageTest/FindVersionTestB.cmake18
-rw-r--r--Tests/FindPackageTest/FindVersionTestC.cmake18
-rw-r--r--Tests/FindPackageTest/FindVersionTestD.cmake18
-rw-r--r--Tests/FindPackageTest/PreferConfig/ABCConfig.cmake1
-rw-r--r--Tests/FindPackageTest/PreferConfig/FindABC.cmake1
-rw-r--r--Tests/FindPackageTest/PreferConfigOnlyModule/FindACME.cmake1
-rw-r--r--Tests/FindPackageTest/PreferConfigRecurse/ACMEConfig.cmake1
-rw-r--r--Tests/FindPackageTest/PreferConfigRecurse/FindACME.cmake1
-rw-r--r--Tests/FindPackageTest/RelocatableConfig.cmake.in11
-rw-r--r--Tests/FindPackageTest/SortLib-3.1.1/SortLibConfig.cmake2
-rw-r--r--Tests/FindPackageTest/SortLib-3.1.1/SortLibConfigVersion.cmake9
-rw-r--r--Tests/FindPackageTest/SortLib-3.10.1/SortLibConfig.cmake2
-rw-r--r--Tests/FindPackageTest/SortLib-3.10.1/SortLibConfigVersion.cmake9
-rw-r--r--Tests/FindPackageTest/SystemPackage/CMakeTestSystemPackageConfig.cmake1
-rw-r--r--Tests/FindPackageTest/TApp.app/Contents/Resources/TAppConfig.cmake1
-rw-r--r--Tests/FindPackageTest/TApp.app/Contents/Resources/cmake/tapp-config.cmake1
-rw-r--r--Tests/FindPackageTest/TFramework.framework/Versions/A/Resources/CMake/TFrameworkConfig.cmake1
-rw-r--r--Tests/FindPackageTest/TFramework.framework/Versions/A/Resources/tframework-config.cmake1
-rw-r--r--Tests/FindPackageTest/cmake/SetFoundFALSEConfig.cmake1
-rw-r--r--Tests/FindPackageTest/cmake/SetFoundResolvedConfig.cmake1
-rw-r--r--Tests/FindPackageTest/cmake/SetFoundTRUEConfig.cmake1
-rw-r--r--Tests/FindPackageTest/include/foo.h1
-rw-r--r--Tests/FindPackageTest/lib/Bar/BarConfig.cmake1
-rw-r--r--Tests/FindPackageTest/lib/Bar/cmake/bar-config.cmake1
-rw-r--r--Tests/FindPackageTest/lib/Blub/BlubConfig.cmake1
-rw-r--r--Tests/FindPackageTest/lib/RecursiveA/recursivea-config.cmake4
-rw-r--r--Tests/FindPackageTest/lib/TApp/TAppConfig.cmake2
-rw-r--r--Tests/FindPackageTest/lib/arch/Bar/BarConfig.cmake1
-rw-r--r--Tests/FindPackageTest/lib/arch/cmake/zot-4.0/zot-config-version.cmake7
-rw-r--r--Tests/FindPackageTest/lib/arch/cmake/zot-4.0/zot-config.cmake1
-rw-r--r--Tests/FindPackageTest/lib/arch/foo-1.2/CMake/FooConfig.cmake1
-rw-r--r--Tests/FindPackageTest/lib/arch/zot-3.1/zot-config-version.cmake7
-rw-r--r--Tests/FindPackageTest/lib/arch/zot-3.1/zot-config.cmake1
-rw-r--r--Tests/FindPackageTest/lib/cmake/zot-3.1/zot-config-version.cmake4
-rw-r--r--Tests/FindPackageTest/lib/cmake/zot-3.1/zot-config.cmake2
-rw-r--r--Tests/FindPackageTest/lib/cmake/zot-4.0/zot-config-version.cmake8
-rw-r--r--Tests/FindPackageTest/lib/cmake/zot-4.0/zot-config.cmake1
-rw-r--r--Tests/FindPackageTest/lib/foo-1.2/CMake/FooConfig.cmake1
-rw-r--r--Tests/FindPackageTest/lib/foo-1.2/foo-config.cmake1
-rw-r--r--Tests/FindPackageTest/lib/suffix/test/SuffixTestConfig.cmake1
-rw-r--r--Tests/FindPackageTest/lib/suffix/test/SuffixTestConfigVersion.cmake7
-rw-r--r--Tests/FindPackageTest/lib/zot-1.0/zot-config.cmake1
-rw-r--r--Tests/FindPackageTest/lib/zot-2.0/zot-config-version.cmake5
-rw-r--r--Tests/FindPackageTest/lib/zot-2.0/zot-config.cmake1
-rw-r--r--Tests/FindPackageTest/lib/zot-3.0/zot-config-version.cmake5
-rw-r--r--Tests/FindPackageTest/lib/zot-3.0/zot-config.cmake1
-rw-r--r--Tests/FindPackageTest/lib/zot-3.1/zot-config-version.cmake8
-rw-r--r--Tests/FindPackageTest/lib/zot-3.1/zot-config.cmake1
-rw-r--r--Tests/FindPackageTest/lib/zot/zot-config-version.cmake10
-rw-r--r--Tests/FindPackageTest/lib/zot/zot-config.cmake2
-rw-r--r--Tests/FindPatch/CMakeLists.txt8
-rw-r--r--Tests/FindPatch/Test/CMakeLists.txt77
-rw-r--r--Tests/FindPostgreSQL/CMakeLists.txt10
-rw-r--r--Tests/FindPostgreSQL/Test/CMakeLists.txt16
-rw-r--r--Tests/FindPostgreSQL/Test/main.c24
-rw-r--r--Tests/FindProtobuf/CMakeLists.txt10
-rw-r--r--Tests/FindProtobuf/Test/CMakeLists.txt54
-rw-r--r--Tests/FindProtobuf/Test/main-desc.cxx58
-rw-r--r--Tests/FindProtobuf/Test/main-generate.cxx8
-rw-r--r--Tests/FindProtobuf/Test/main-protoc.cxx8
-rw-r--r--Tests/FindProtobuf/Test/main.cxx8
-rw-r--r--Tests/FindProtobuf/Test/msgs/example.proto6
-rw-r--r--Tests/FindProtobuf/Test/msgs/example_desc.proto10
-rw-r--r--Tests/FindPython/ArtifactsInteractive/CMakeLists.txt24
-rw-r--r--Tests/FindPython/CMakeLists.txt716
-rw-r--r--Tests/FindPython/CustomFailureMessage/CMakeLists.txt79
-rw-r--r--Tests/FindPython/CustomFailureMessage/Check/CMakeLists.txt5
-rw-r--r--Tests/FindPython/ExactVersion/CMakeLists.txt56
-rw-r--r--Tests/FindPython/FindPythonScript.cmake9
-rw-r--r--Tests/FindPython/Implementation/CMakeLists.txt37
-rw-r--r--Tests/FindPython/IronPython/CMakeLists.txt31
-rw-r--r--Tests/FindPython/IronPython2/CMakeLists.txt31
-rw-r--r--Tests/FindPython/MultiplePackages/CMakeLists.txt33
-rw-r--r--Tests/FindPython/NumPy/CMakeLists.txt22
-rw-r--r--Tests/FindPython/NumPy/arraytest.c58
-rw-r--r--Tests/FindPython/NumPyOnly/CMakeLists.txt14
-rw-r--r--Tests/FindPython/PyPy/CMakeLists.txt37
-rw-r--r--Tests/FindPython/PyPy2/CMakeLists.txt37
-rw-r--r--Tests/FindPython/PyPy3/CMakeLists.txt37
-rw-r--r--Tests/FindPython/Python/CMakeLists.txt40
-rw-r--r--Tests/FindPython/Python2/CMakeLists.txt47
-rw-r--r--Tests/FindPython/Python2Embedded/CMakeLists.txt42
-rw-r--r--Tests/FindPython/Python2Fail/CMakeLists.txt14
-rw-r--r--Tests/FindPython/Python2Module/CMakeLists.txt37
-rw-r--r--Tests/FindPython/Python3/CMakeLists.txt99
-rw-r--r--Tests/FindPython/Python3Embedded/CMakeLists.txt42
-rw-r--r--Tests/FindPython/Python3Fail/CMakeLists.txt14
-rw-r--r--Tests/FindPython/Python3Module/CMakeLists.txt37
-rw-r--r--Tests/FindPython/RequiredArtifacts/CMakeLists.txt110
-rw-r--r--Tests/FindPython/RequiredArtifacts/Check/CMakeLists.txt41
-rw-r--r--Tests/FindPython/SOABI/CMakeLists.txt38
-rw-r--r--Tests/FindPython/UnversionedNames/CMakeLists.txt66
-rw-r--r--Tests/FindPython/VersionRange/CMakeLists.txt64
-rw-r--r--Tests/FindPython/VirtualEnv/CMakeLists.txt47
-rw-r--r--Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake6
-rw-r--r--Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake16
-rw-r--r--Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake7
-rw-r--r--Tests/FindPython/VirtualEnvConda/CMakeLists.txt46
-rw-r--r--Tests/FindPython/VirtualEnvConda/VirtualEnvDefault.cmake6
-rw-r--r--Tests/FindPython/VirtualEnvConda/VirtualEnvOnly.cmake16
-rw-r--r--Tests/FindPython/VirtualEnvConda/VirtualEnvStandard.cmake7
-rw-r--r--Tests/FindPython/display_time.c36
-rw-r--r--Tests/FindPython/display_time.h2
-rw-r--r--Tests/FindPython/main.c7
-rw-r--r--Tests/FindPython/spam.c41
-rw-r--r--Tests/FindRuby/CMakeLists.txt57
-rw-r--r--Tests/FindRuby/Fail/CMakeLists.txt5
-rw-r--r--Tests/FindRuby/FailExact/CMakeLists.txt8
-rw-r--r--Tests/FindRuby/Rvm/CMakeLists.txt75
-rw-r--r--Tests/FindRuby/Rvm/RvmDefault.cmake17
-rw-r--r--Tests/FindRuby/Rvm/RvmOnly.cmake41
-rw-r--r--Tests/FindRuby/Rvm/RvmStandard.cmake9
-rw-r--r--Tests/FindRuby/Test/CMakeLists.txt14
-rw-r--r--Tests/FindRuby/Test/ruby_version.c7
-rw-r--r--Tests/FindSDL/CMakeLists.txt10
-rw-r--r--Tests/FindSDL/Test/CMakeLists.txt19
-rw-r--r--Tests/FindSDL/Test/main.c18
-rw-r--r--Tests/FindSQLite3/CMakeLists.txt10
-rw-r--r--Tests/FindSQLite3/Test/CMakeLists.txt16
-rw-r--r--Tests/FindSQLite3/Test/main.c9
-rw-r--r--Tests/FindTIFF/CMakeLists.txt10
-rw-r--r--Tests/FindTIFF/Test/CMakeLists.txt23
-rw-r--r--Tests/FindTIFF/Test/main.c12
-rw-r--r--Tests/FindTIFF/Test/main.cxx16
-rw-r--r--Tests/FindThreads/C-only/CMakeLists.txt9
-rw-r--r--Tests/FindThreads/CMakeLists.txt11
-rw-r--r--Tests/FindThreads/CXX-only/CMakeLists.txt12
-rw-r--r--Tests/FindVulkan/CMakeLists.txt10
-rw-r--r--Tests/FindVulkan/Test/CMakeLists.txt24
-rw-r--r--Tests/FindVulkan/Test/Run-glslc.cmake20
-rw-r--r--Tests/FindVulkan/Test/main.c29
-rw-r--r--Tests/FindX11/CMakeLists.txt10
-rw-r--r--Tests/FindX11/Test/CMakeLists.txt106
-rw-r--r--Tests/FindX11/Test/main.c473
-rw-r--r--Tests/FindXalanC/CMakeLists.txt10
-rw-r--r--Tests/FindXalanC/Test/CMakeLists.txt14
-rw-r--r--Tests/FindXalanC/Test/main.cxx10
-rw-r--r--Tests/FindXercesC/CMakeLists.txt10
-rw-r--r--Tests/FindXercesC/Test/CMakeLists.txt14
-rw-r--r--Tests/FindXercesC/Test/main.cxx7
-rw-r--r--Tests/ForceInclude/CMakeLists.txt10
-rw-r--r--Tests/ForceInclude/foo.c10
-rw-r--r--Tests/ForceInclude/foo1.h1
-rw-r--r--Tests/ForceInclude/foo2.h1
-rw-r--r--Tests/Fortran/CMakeLists.txt148
-rw-r--r--Tests/Fortran/foo.f9
-rw-r--r--Tests/Fortran/hello.f6
-rw-r--r--Tests/Fortran/mainc.c5
-rw-r--r--Tests/Fortran/maincxx.c6
-rw-r--r--Tests/Fortran/myc.c12
-rw-r--r--Tests/Fortran/mycxx.cxx6
-rw-r--r--Tests/Fortran/mysub.f5
-rw-r--r--Tests/Fortran/testf.f7
-rw-r--r--Tests/Fortran/world.f6
-rw-r--r--Tests/Fortran/world_gnu.def2
-rw-r--r--Tests/Fortran/world_icl.def2
-rw-r--r--Tests/FortranC/CMakeLists.txt25
-rw-r--r--Tests/FortranC/Flags.cmake.in36
-rwxr-xr-xTests/FortranC/test_opt.sh.in18
-rw-r--r--Tests/FortranModules/CMakeLists.txt117
-rw-r--r--Tests/FortranModules/Executable/CMakeLists.txt8
-rw-r--r--Tests/FortranModules/Executable/main.f907
-rw-r--r--Tests/FortranModules/External/CMakeLists.txt3
-rw-r--r--Tests/FortranModules/External/a.f907
-rw-r--r--Tests/FortranModules/Library/CMakeLists.txt11
-rw-r--r--Tests/FortranModules/Library/a.f906
-rw-r--r--Tests/FortranModules/Library/b.f905
-rw-r--r--Tests/FortranModules/Library/main.f903
-rw-r--r--Tests/FortranModules/Subdir/CMakeLists.txt2
-rw-r--r--Tests/FortranModules/Subdir/subdir.f905
-rw-r--r--Tests/FortranModules/Submodules/CMakeLists.txt23
-rw-r--r--Tests/FortranModules/Submodules/child.f9010
-rw-r--r--Tests/FortranModules/Submodules/grandchild.f908
-rw-r--r--Tests/FortranModules/Submodules/greatgrandchild.f908
-rw-r--r--Tests/FortranModules/Submodules/main.f907
-rw-r--r--Tests/FortranModules/Submodules/parent.f9022
-rw-r--r--Tests/FortranModules/Submodules/sibling.f909
-rw-r--r--Tests/FortranModules/in_interface/main.f903
-rw-r--r--Tests/FortranModules/in_interface/module.f9012
-rw-r--r--Tests/FortranModules/include/test_preprocess.h5
-rw-r--r--Tests/FortranModules/non_pp_include.f903
-rw-r--r--Tests/FortranModules/test_module_implementation.f906
-rw-r--r--Tests/FortranModules/test_module_interface.f909
-rw-r--r--Tests/FortranModules/test_module_main.f904
-rw-r--r--Tests/FortranModules/test_non_pp_include_main.f905
-rw-r--r--Tests/FortranModules/test_preprocess.F9053
-rw-r--r--Tests/FortranModules/test_preprocess_module.F905
-rw-r--r--Tests/FortranModules/test_use_in_comment_fixedform.f7
-rw-r--r--Tests/FortranModules/test_use_in_comment_freeform.f907
-rw-r--r--Tests/FortranOnly/CMakeLists.txt160
-rw-r--r--Tests/FortranOnly/IntelIfDef.f3
-rw-r--r--Tests/FortranOnly/IntelIfDef.inc3
-rw-r--r--Tests/FortranOnly/checksayhello.cmake7
-rw-r--r--Tests/FortranOnly/checktestf2.cmake8
-rw-r--r--Tests/FortranOnly/hello.f5
-rw-r--r--Tests/FortranOnly/no_preprocess_source_fpp.fpp3
-rw-r--r--Tests/FortranOnly/no_preprocess_source_lower.f3
-rw-r--r--Tests/FortranOnly/no_preprocess_source_upper.F3
-rw-r--r--Tests/FortranOnly/no_preprocess_target_fpp.fpp3
-rw-r--r--Tests/FortranOnly/no_preprocess_target_lower.f3
-rw-r--r--Tests/FortranOnly/no_preprocess_target_upper.F3
-rw-r--r--Tests/FortranOnly/preprocess.F5
-rw-r--r--Tests/FortranOnly/preprocess2.f4
-rw-r--r--Tests/FortranOnly/preprocess3.f4
-rw-r--r--Tests/FortranOnly/testRC.rc0
-rw-r--r--Tests/FortranOnly/test_preprocess.cmake7
-rw-r--r--Tests/FortranOnly/testf.f6
-rw-r--r--Tests/FortranOnly/world.f4
-rw-r--r--Tests/Framework/CMakeLists.txt112
-rw-r--r--Tests/Framework/External/CMakeLists.txt5
-rw-r--r--Tests/Framework/External/external.c4
-rw-r--r--Tests/Framework/bar.cxx6
-rw-r--r--Tests/Framework/foo.cxx10
-rw-r--r--Tests/Framework/foo.h1
-rw-r--r--Tests/Framework/foo2.h1
-rw-r--r--Tests/Framework/fooBoth.h1
-rw-r--r--Tests/Framework/fooDeepPublic.h1
-rw-r--r--Tests/Framework/fooExtensionlessResource1
-rw-r--r--Tests/Framework/fooNeither.h1
-rw-r--r--Tests/Framework/fooPrivate.h1
-rw-r--r--Tests/Framework/fooPrivateExtensionlessHeader1
-rw-r--r--Tests/Framework/fooPublic.h1
-rw-r--r--Tests/Framework/fooPublicExtensionlessHeader1
-rw-r--r--Tests/Framework/space.c7
-rw-r--r--Tests/Framework/test.lua1
-rw-r--r--Tests/Framework/useExternal.c6
-rw-r--r--Tests/Framework/use_space.c8
-rw-r--r--Tests/FunctionTest/CMakeLists.txt176
-rw-r--r--Tests/FunctionTest/SubDirScope/CMakeLists.txt14
-rw-r--r--Tests/FunctionTest/Util.cmake3
-rw-r--r--Tests/FunctionTest/functionTest.c7
-rw-r--r--Tests/Fuzzing/README.rst8
-rw-r--r--Tests/Fuzzing/xml_parser_fuzzer.cc27
-rw-r--r--Tests/GeneratorExpression/CMP0044/CMakeLists.txt19
-rw-r--r--Tests/GeneratorExpression/CMP0044/cmp0044-check.cpp26
-rw-r--r--Tests/GeneratorExpression/CMakeLists.txt441
-rw-r--r--Tests/GeneratorExpression/check-common.cmake5
-rw-r--r--Tests/GeneratorExpression/check-part1.cmake64
-rw-r--r--Tests/GeneratorExpression/check-part2.cmake46
-rw-r--r--Tests/GeneratorExpression/check-part3.cmake66
-rw-r--r--Tests/GeneratorExpression/check-part4.cmake33
-rw-r--r--Tests/GeneratorExpression/check-part5.cmake1
-rw-r--r--Tests/GeneratorExpression/check_object_files.cmake26
-rw-r--r--Tests/GeneratorExpression/echo.c8
-rw-r--r--Tests/GeneratorExpression/empty.cpp7
-rw-r--r--Tests/GeneratorExpression/objlib1.c4
-rw-r--r--Tests/GeneratorExpression/objlib2.c4
-rw-r--r--Tests/GeneratorExpression/pwd.c32
-rw-r--r--Tests/GeneratorExpression/srcgenex.c.in12
-rw-r--r--Tests/GeneratorExpression/srcgenex_includes.c.in12
-rw-r--r--Tests/GeneratorExpression/srcgenex_includes.h.in7
-rw-r--r--Tests/GhsMulti/GhsMultiCompilerOptions/CMakeLists.txt92
-rw-r--r--Tests/GhsMulti/GhsMultiCompilerOptions/CMakeLists.txt.in32
-rw-r--r--Tests/GhsMulti/GhsMultiCompilerOptions/test.c4
-rw-r--r--Tests/GhsMulti/GhsMultiCopyFile/CMakeLists.txt30
-rw-r--r--Tests/GhsMulti/GhsMultiCopyFile/test.c4
-rw-r--r--Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt110
-rw-r--r--Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in108
-rw-r--r--Tests/GhsMulti/GhsMultiCustomTarget/exe1.c5
-rw-r--r--Tests/GhsMulti/GhsMultiCustomTarget/lib1.c4
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt12
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt11
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c8
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt17
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c17
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h3
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt28
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in16
-rw-r--r--Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in7
-rw-r--r--Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/CMakeLists.txt17
-rw-r--r--Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/main.c17
-rw-r--r--Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder/test.c4
-rw-r--r--Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder/testcase.c4
-rw-r--r--Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder_test.c4
-rw-r--r--Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder_test_0.c4
-rw-r--r--Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/test.c4
-rw-r--r--Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/testCase.c4
-rw-r--r--Tests/GhsMulti/GhsMultiExclude/CMakeLists.txt17
-rw-r--r--Tests/GhsMulti/GhsMultiExclude/exe1.c4
-rw-r--r--Tests/GhsMulti/GhsMultiExclude/lib1.c4
-rw-r--r--Tests/GhsMulti/GhsMultiExclude/verify.cmake54
-rw-r--r--Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt14
-rw-r--r--Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt8
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/CMakeLists.txt19
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/exe.c5
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/func.c4
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt3
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/Main.c8
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/CMakeLists.txt6
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Int/AppDD.int12
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Int/CMakeLists.txt1
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt2
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/HelperFun.c4
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/HelperFun.h1
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt21
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/exe.c5
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/func.c5
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/kernel.c15
-rw-r--r--Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/test.int8
-rw-r--r--Tests/GhsMulti/GhsMultiInterface/CMakeLists.txt8
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTest/CMakeLists.txt92
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTest/CMakeLists.txt.in43
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTest/exe1.c6
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTest/exe1.h6
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTest/func2.c4
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTest/func3.c4
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTest/func4.c4
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTest/func5.c4
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTest/func6.c4
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTest/func7.c4
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTestSub/CMakeLists.txt9
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/CMakeLists.txt12
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/exe1.c6
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/exe1.h6
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/CMakeLists.txt7
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func2.c4
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func3.c4
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func4.c4
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func5.c4
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func6.c4
-rw-r--r--Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func7.c4
-rw-r--r--Tests/GhsMulti/GhsMultiMultipleProjects/CMakeLists.txt17
-rw-r--r--Tests/GhsMulti/GhsMultiMultipleProjects/exe1.c5
-rw-r--r--Tests/GhsMulti/GhsMultiMultipleProjects/lib1.c4
-rw-r--r--Tests/GhsMulti/GhsMultiMultipleProjects/sub/CMakeLists.txt10
-rw-r--r--Tests/GhsMulti/GhsMultiMultipleProjects/sub/exe2.c6
-rw-r--r--Tests/GhsMulti/GhsMultiMultipleProjects/sub/lib2.c4
-rw-r--r--Tests/GhsMulti/GhsMultiMultipleProjects/sub2/CMakeLists.txt10
-rw-r--r--Tests/GhsMulti/GhsMultiMultipleProjects/sub2/exe3.c6
-rw-r--r--Tests/GhsMulti/GhsMultiMultipleProjects/sub2/lib3.c4
-rw-r--r--Tests/GhsMulti/GhsMultiMultipleProjects/verify.cmake58
-rw-r--r--Tests/GhsMulti/GhsMultiObjectLibrary/CMakeLists.txt13
-rw-r--r--Tests/GhsMulti/GhsMultiObjectLibrary/exe.c8
-rw-r--r--Tests/GhsMulti/GhsMultiObjectLibrary/sub/testOBJ.c4
-rw-r--r--Tests/GhsMulti/GhsMultiObjectLibrary/testOBJ.c4
-rw-r--r--Tests/GhsMulti/GhsMultiObjectLibrary/testOBJ.h1
-rw-r--r--Tests/GhsMulti/GhsMultiObjectLibrary/testOBJ2.c4
-rw-r--r--Tests/GhsMulti/GhsMultiPlatform/CMakeLists.txt34
-rw-r--r--Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt42
-rw-r--r--Tests/GhsMulti/GhsMultiRenameInstall/exe.c4
-rw-r--r--Tests/GhsMulti/GhsMultiRenameInstall/exe1.c5
-rw-r--r--Tests/GhsMulti/GhsMultiRenameInstall/lib1.c4
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/Atest3.c4
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/CMakeLists.txt45
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/cmake.rule1
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/object.o1
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/resource.pdf0
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/s2.h6
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/s4.h6
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/s5.h6
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/standard.h1
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/sub/testOBJ.c6
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/sub/testOBJ.h6
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/test1.c6
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/test1.h6
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/test2a.c4
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/test3.c4
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/test3.h1
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/test4.c4
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/test5.c4
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/test6.c4
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/test7.c4
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/testOBJ.c11
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/testOBJ.h6
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/textfile.txt1
-rw-r--r--Tests/GhsMulti/GhsMultiSrcGroups/textfile2.txt1
-rw-r--r--Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt10
-rw-r--r--Tests/GhsMulti/GhsMultiUnsupportedTargets/file.c4
-rw-r--r--Tests/GoogleTest/CMakeLists.txt10
-rw-r--r--Tests/GoogleTest/Test/CMakeLists.txt96
-rw-r--r--Tests/GoogleTest/Test/empty.cxx0
-rw-r--r--Tests/GoogleTest/Test/main1.cxx30
-rw-r--r--Tests/GoogleTest/Test/main2.cxx1
-rw-r--r--Tests/GoogleTest/Test/main2.h21
-rw-r--r--Tests/GoogleTest/Test/main3.cxx11
-rw-r--r--Tests/GoogleTest/Test/main4.cxx1
-rw-r--r--Tests/GoogleTest/Test/main4.h6
-rw-r--r--Tests/ISPC/CMakeLists.txt18
-rw-r--r--Tests/ISPC/ChainedStaticLibraries/CMakeLists.txt22
-rw-r--r--Tests/ISPC/ChainedStaticLibraries/extra.cxx17
-rw-r--r--Tests/ISPC/ChainedStaticLibraries/extra.ispc12
-rw-r--r--Tests/ISPC/ChainedStaticLibraries/main.cxx15
-rw-r--r--Tests/ISPC/ChainedStaticLibraries/simple.ispc12
-rw-r--r--Tests/ISPC/CustomHeaderSuffix/CMakeLists.txt23
-rw-r--r--Tests/ISPC/CustomHeaderSuffix/extra.cxx17
-rw-r--r--Tests/ISPC/CustomHeaderSuffix/extra.ispc12
-rw-r--r--Tests/ISPC/CustomHeaderSuffix/main.cxx15
-rw-r--r--Tests/ISPC/CustomHeaderSuffix/simple.ispc12
-rw-r--r--Tests/ISPC/Defines/CMakeLists.txt16
-rw-r--r--Tests/ISPC/Defines/main.cxx15
-rw-r--r--Tests/ISPC/Defines/simple.ispc15
-rw-r--r--Tests/ISPC/DynamicLibrary/CMakeLists.txt22
-rw-r--r--Tests/ISPC/DynamicLibrary/extra.cxx23
-rw-r--r--Tests/ISPC/DynamicLibrary/extra.ispc12
-rw-r--r--Tests/ISPC/DynamicLibrary/main.cxx17
-rw-r--r--Tests/ISPC/DynamicLibrary/shim.cxx0
-rw-r--r--Tests/ISPC/DynamicLibrary/simple.cxx23
-rw-r--r--Tests/ISPC/DynamicLibrary/simple.ispc12
-rw-r--r--Tests/ISPC/ObjectGenex/CMakeLists.txt45
-rw-r--r--Tests/ISPC/ObjectGenex/main.cxx87
-rw-r--r--Tests/ISPC/ObjectGenex/simple.ispc12
-rw-r--r--Tests/ISPC/ObjectLibrary/CMakeLists.txt18
-rw-r--r--Tests/ISPC/ObjectLibrary/extra.cxx17
-rw-r--r--Tests/ISPC/ObjectLibrary/main.cxx15
-rw-r--r--Tests/ISPC/ObjectLibrary/simple.ispc12
-rw-r--r--Tests/ISPC/ObjectLibrary/subdir/extra.ispc12
-rw-r--r--Tests/ISPC/ResponseAndDefine/CMakeLists.txt28
-rw-r--r--Tests/ISPC/ResponseAndDefine/main.cxx15
-rw-r--r--Tests/ISPC/ResponseAndDefine/simple.ispc16
-rw-r--r--Tests/ISPC/StaticLibrary/CMakeLists.txt15
-rw-r--r--Tests/ISPC/StaticLibrary/main.cxx15
-rw-r--r--Tests/ISPC/StaticLibrary/simple.ispc12
-rw-r--r--Tests/ISPC/SystemIncludes/CMakeLists.txt14
-rw-r--r--Tests/ISPC/SystemIncludes/main.cxx15
-rw-r--r--Tests/ISPC/SystemIncludes/simple.ispc9
-rw-r--r--Tests/ISPC/TryCompile/CMakeLists.txt16
-rw-r--r--Tests/ISPC/TryCompile/main.cxx19
-rw-r--r--Tests/ISPC/TryCompile/simple.ispc12
-rw-r--r--Tests/ImportedSameName/A/CMakeLists.txt8
-rw-r--r--Tests/ImportedSameName/A/a.c3
-rw-r--r--Tests/ImportedSameName/B/CMakeLists.txt8
-rw-r--r--Tests/ImportedSameName/B/b.c3
-rw-r--r--Tests/ImportedSameName/CMakeLists.txt8
-rw-r--r--Tests/ImportedSameName/main.c16
-rw-r--r--Tests/IncludeDirectories/CMP0021/CMakeLists.txt14
-rw-r--r--Tests/IncludeDirectories/CMP0021/includes/cmp0021/cmp0021.h2
-rw-r--r--Tests/IncludeDirectories/CMP0021/main.cpp11
-rw-r--r--Tests/IncludeDirectories/CMakeLists.txt137
-rw-r--r--Tests/IncludeDirectories/StandardIncludeDirectories/CMakeLists.txt5
-rw-r--r--Tests/IncludeDirectories/StandardIncludeDirectories/StdDir/StdIncDir.h0
-rw-r--r--Tests/IncludeDirectories/StandardIncludeDirectories/main.c5
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt76
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectories/config_specific/config_iface.h14
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectories/consumer.cpp8
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectories/imported_consumer.cpp7
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectories/systemlib.cpp7
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectories/systemlib/ordertest.h1
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectories/systemlib/systemlib.h19
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectories/systemlib_header_only/systemlib.h16
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectories/upstream.cpp7
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectories/upstream.h12
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectories/userlib/ordertest.h1
-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/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt180
-rw-r--r--Tests/IncludeDirectories/TargetIncludeDirectories/copy_includes.cpp7
-rw-r--r--Tests/IncludeDirectories/TargetIncludeDirectories/empty.cpp7
-rw-r--r--Tests/IncludeDirectories/TargetIncludeDirectories/main.c7
-rw-r--r--Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp20
-rw-r--r--Tests/IncludeDirectories/TargetIncludeDirectories/other.cpp7
-rw-r--r--Tests/IncludeDirectories/TargetIncludeDirectories/sing/ting/ting.h1
-rw-r--r--Tests/IncludeDirectories/empty.cpp7
-rw-r--r--Tests/IncludeDirectories/main.cpp23
-rw-r--r--Tests/IncludeDirectories/ordertest.cpp1
-rw-r--r--Tests/IncludeDirectoriesCPATH/CMakeLists.txt22
-rw-r--r--Tests/IncludeDirectoriesCPATH/consumer.cpp6
-rw-r--r--Tests/IncludeDirectoriesCPATH/viacpath/systemlib.h15
-rw-r--r--Tests/InterfaceLibrary/CMakeLists.txt87
-rw-r--r--Tests/InterfaceLibrary/broken.cpp2
-rw-r--r--Tests/InterfaceLibrary/definetestexe.cpp31
-rw-r--r--Tests/InterfaceLibrary/dummy.cpp5
-rw-r--r--Tests/InterfaceLibrary/excluded/CMakeLists.txt1
-rw-r--r--Tests/InterfaceLibrary/headerdir/CMakeLists.txt22
-rw-r--r--Tests/InterfaceLibrary/headerdir/iface_genheader.h.in1
-rw-r--r--Tests/InterfaceLibrary/headerdir/iface_header.h1
-rw-r--r--Tests/InterfaceLibrary/headerdir/iface_header_builddir.h.in1
-rw-r--r--Tests/InterfaceLibrary/ifacedir/CMakeLists.txt8
-rw-r--r--Tests/InterfaceLibrary/ifacedir/sub.cpp4
-rw-r--r--Tests/InterfaceLibrary/item.cpp4
-rw-r--r--Tests/InterfaceLibrary/item_fake.cpp5
-rw-r--r--Tests/InterfaceLibrary/libsdir/CMakeLists.txt28
-rw-r--r--Tests/InterfaceLibrary/libsdir/shareddependlib.cpp7
-rw-r--r--Tests/InterfaceLibrary/libsdir/shareddependlib/shareddependlib.h12
-rw-r--r--Tests/InterfaceLibrary/libsdir/sharedlib.cpp12
-rw-r--r--Tests/InterfaceLibrary/libsdir/sharedlib/sharedlib.h14
-rw-r--r--Tests/InterfaceLibrary/map_config.cpp15
-rw-r--r--Tests/InterfaceLibrary/obj.cpp4
-rw-r--r--Tests/InterfaceLibrary/sharedlibtestexe.cpp19
-rw-r--r--Tests/InterfaceLinkLibraries/CMakeLists.txt61
-rw-r--r--Tests/InterfaceLinkLibraries/bang.cpp15
-rw-r--r--Tests/InterfaceLinkLibraries/bang.h4
-rw-r--r--Tests/InterfaceLinkLibraries/bang_vs6_1.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/bang_vs6_2.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/bar.cpp26
-rw-r--r--Tests/InterfaceLinkLibraries/bar.h7
-rw-r--r--Tests/InterfaceLinkLibraries/bar_vs6_1.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/bar_vs6_2.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/bar_vs6_3.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/bar_vs6_4.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/foo.cpp15
-rw-r--r--Tests/InterfaceLinkLibraries/foo.h4
-rw-r--r--Tests/InterfaceLinkLibraries/foo_vs6_1.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/foo_vs6_2.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/foo_vs6_3.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/foo_vs6_4.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/main.cpp23
-rw-r--r--Tests/InterfaceLinkLibraries/main_vs6_1.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/main_vs6_2.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/main_vs6_3.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/main_vs6_4.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/zot.cpp6
-rw-r--r--Tests/InterfaceLinkLibraries/zot.h7
-rw-r--r--Tests/InterfaceLinkLibraries/zot_vs6_1.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/zot_vs6_2.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/zot_vs6_3.cpp1
-rw-r--r--Tests/InterfaceLinkLibraries/zot_vs6_4.cpp1
-rw-r--r--Tests/JCTest/CMakeLists.txt9
-rw-r--r--Tests/JCTest/TestTime.cxx11
-rw-r--r--Tests/JacocoCoverage/Coverage/src/main/java/org/cmake/CoverageTest.java52
-rw-r--r--Tests/JacocoCoverage/Coverage/target/site/jacoco.xml.in1
-rw-r--r--Tests/JacocoCoverage/DartConfiguration.tcl.in8
-rw-r--r--Tests/Java/A.java11
-rw-r--r--Tests/Java/CMakeLists.txt25
-rw-r--r--Tests/Java/HelloWorld.java11
-rw-r--r--Tests/JavaExportImport/BuildExport/CMakeLists.txt13
-rw-r--r--Tests/JavaExportImport/BuildExport/Foo.java11
-rw-r--r--Tests/JavaExportImport/CMakeLists.txt105
-rw-r--r--Tests/JavaExportImport/Import/CMakeLists.txt14
-rw-r--r--Tests/JavaExportImport/Import/Import.java10
-rw-r--r--Tests/JavaExportImport/InitialCache.cmake.in5
-rw-r--r--Tests/JavaExportImport/InstallExport/Bar.java11
-rw-r--r--Tests/JavaExportImport/InstallExport/CMakeLists.txt15
-rw-r--r--Tests/JavaExportImport/main.c4
-rw-r--r--Tests/JavaJavah/B.cpp10
-rw-r--r--Tests/JavaJavah/B.java19
-rw-r--r--Tests/JavaJavah/C.cpp10
-rw-r--r--Tests/JavaJavah/C.java19
-rw-r--r--Tests/JavaJavah/CMakeLists.txt28
-rw-r--r--Tests/JavaJavah/HelloWorld2.java15
-rw-r--r--Tests/JavaNativeHeaders/CMakeLists.txt31
-rw-r--r--Tests/JavaNativeHeaders/D.cpp10
-rw-r--r--Tests/JavaNativeHeaders/D.java19
-rw-r--r--Tests/JavaNativeHeaders/E.cpp10
-rw-r--r--Tests/JavaNativeHeaders/E.java19
-rw-r--r--Tests/JavaNativeHeaders/HelloWorld3.java15
-rw-r--r--Tests/JavaNativeHeaders/Import/CMakeLists.txt19
-rw-r--r--Tests/JavascriptCoverage/DartConfiguration.tcl.in8
-rw-r--r--Tests/JavascriptCoverage/output.json.in448
-rw-r--r--Tests/JavascriptCoverage/test.js53
-rw-r--r--Tests/JavascriptCoverage/test3.js37
-rw-r--r--Tests/Jump/CMakeLists.txt6
-rw-r--r--Tests/Jump/Executable/CMakeLists.txt6
-rw-r--r--Tests/Jump/Executable/jumpExecutable.cxx12
-rw-r--r--Tests/Jump/Library/CMakeLists.txt2
-rw-r--r--Tests/Jump/Library/Shared/CMakeLists.txt26
-rw-r--r--Tests/Jump/Library/Shared/jumpShared.cxx10
-rw-r--r--Tests/Jump/Library/Static/CMakeLists.txt1
-rw-r--r--Tests/Jump/Library/Static/jumpStatic.cxx4
-rw-r--r--Tests/LibName/CMakeLists.txt34
-rw-r--r--Tests/LibName/bar.c7
-rw-r--r--Tests/LibName/foo.c11
-rw-r--r--Tests/LibName/foobar.c10
-rw-r--r--Tests/LibName/use_ver_space.c9
-rw-r--r--Tests/LibName/ver_space.c7
-rw-r--r--Tests/LinkDirectory/CMakeLists.txt45
-rw-r--r--Tests/LinkDirectory/External/CMakeLists.txt34
-rw-r--r--Tests/LinkDirectory/External/myexe.c6
-rw-r--r--Tests/LinkDirectory/mylibA.c4
-rw-r--r--Tests/LinkDirectory/mylibB.c4
-rw-r--r--Tests/LinkFlags/CMakeLists.txt37
-rw-r--r--Tests/LinkFlags/LinkFlags.c4
-rw-r--r--Tests/LinkFlags/LinkFlagsExe.c9
-rw-r--r--Tests/LinkFlags/LinkFlagsLib.c9
-rw-r--r--Tests/LinkFlags/LinkerFlags/CMakeLists.txt11
-rw-r--r--Tests/LinkFlags/LinkerFlagsConfig/CMakeLists.txt11
-rw-r--r--Tests/LinkLanguage/CMakeLists.txt15
-rw-r--r--Tests/LinkLanguage/LinkLanguage.c5
-rw-r--r--Tests/LinkLanguage/foo.cxx6
-rw-r--r--Tests/LinkLine/CMakeLists.txt12
-rw-r--r--Tests/LinkLine/Exec.c9
-rw-r--r--Tests/LinkLine/One.c10
-rw-r--r--Tests/LinkLine/Two.c10
-rw-r--r--Tests/LinkLineOrder/CMakeLists.txt36
-rw-r--r--Tests/LinkLineOrder/Exec1.c8
-rw-r--r--Tests/LinkLineOrder/Exec2.c8
-rw-r--r--Tests/LinkLineOrder/NoDepA.c7
-rw-r--r--Tests/LinkLineOrder/NoDepB.c4
-rw-r--r--Tests/LinkLineOrder/NoDepC.c7
-rw-r--r--Tests/LinkLineOrder/NoDepE.c11
-rw-r--r--Tests/LinkLineOrder/NoDepF.c11
-rw-r--r--Tests/LinkLineOrder/NoDepX.c7
-rw-r--r--Tests/LinkLineOrder/NoDepY.c4
-rw-r--r--Tests/LinkLineOrder/NoDepZ.c7
-rw-r--r--Tests/LinkLineOrder/One.c10
-rw-r--r--Tests/LinkLineOrder/Two.c8
-rw-r--r--Tests/LinkStatic/CMakeLists.txt27
-rw-r--r--Tests/LinkStatic/LinkStatic.c5
-rw-r--r--Tests/LoadCommand/CMakeCommands/CMakeLists.txt14
-rw-r--r--Tests/LoadCommand/CMakeCommands/cmTestCommand.c186
-rw-r--r--Tests/LoadCommand/CMakeLists.txt52
-rw-r--r--Tests/LoadCommand/LoadedCommand.cxx.in32
-rw-r--r--Tests/LoadCommand/LoadedCommand.h.in3
-rw-r--r--Tests/LoadCommandOneConfig/CMakeCommands/CMakeLists.txt17
-rw-r--r--Tests/LoadCommandOneConfig/CMakeCommands/cmTestCommand.c186
-rw-r--r--Tests/LoadCommandOneConfig/CMakeLists.txt58
-rw-r--r--Tests/LoadCommandOneConfig/LoadedCommand.cxx.in32
-rw-r--r--Tests/LoadCommandOneConfig/LoadedCommand.h.in9
-rw-r--r--Tests/MFC/CMakeLists.txt61
-rw-r--r--Tests/MFC/CMakeLists.txt.in70
-rw-r--r--Tests/MFC/ValidateBuild.cmake.in68
-rw-r--r--Tests/MFC/mfc1/ChildFrm.cpp59
-rw-r--r--Tests/MFC/mfc1/ChildFrm.h30
-rw-r--r--Tests/MFC/mfc1/MainFrm.cpp96
-rw-r--r--Tests/MFC/mfc1/MainFrm.h35
-rw-r--r--Tests/MFC/mfc1/ReadMe.txt135
-rw-r--r--Tests/MFC/mfc1/Resource.h20
-rw-r--r--Tests/MFC/mfc1/mfc1.cpp144
-rw-r--r--Tests/MFC/mfc1/mfc1.h29
-rw-r--r--Tests/MFC/mfc1/mfc1.rc393
-rw-r--r--Tests/MFC/mfc1/mfc1.reg13
-rw-r--r--Tests/MFC/mfc1/mfc1.sln21
-rw-r--r--Tests/MFC/mfc1/mfc1.vcproj216
-rw-r--r--Tests/MFC/mfc1/mfc1Doc.cpp70
-rw-r--r--Tests/MFC/mfc1/mfc1Doc.h33
-rw-r--r--Tests/MFC/mfc1/mfc1View.cpp97
-rw-r--r--Tests/MFC/mfc1/mfc1View.h47
-rw-r--r--Tests/MFC/mfc1/res/Toolbar.bmpbin0 -> 1078 bytes-rw-r--r--Tests/MFC/mfc1/res/mfc1.icobin0 -> 21630 bytes-rw-r--r--Tests/MFC/mfc1/res/mfc1.manifest22
-rw-r--r--Tests/MFC/mfc1/res/mfc1.rc213
-rw-r--r--Tests/MFC/mfc1/res/mfc1Doc.icobin0 -> 1078 bytes-rw-r--r--Tests/MFC/mfc1/stdafx.cpp5
-rw-r--r--Tests/MFC/mfc1/stdafx.h70
-rw-r--r--Tests/MFC/try_compile/CMakeLists.txt15
-rw-r--r--Tests/MSManifest/CMakeLists.txt8
-rw-r--r--Tests/MSManifest/Subdir/CMakeLists.txt10
-rw-r--r--Tests/MSManifest/Subdir/check.cmake6
-rw-r--r--Tests/MSManifest/Subdir/main.c4
-rw-r--r--Tests/MSManifest/Subdir/test.manifest.in4
-rw-r--r--Tests/MSManifest/Subdir2/CMakeLists.txt13
-rw-r--r--Tests/MSManifest/Subdir2/check.cmake22
-rw-r--r--Tests/MSManifest/Subdir2/main.c4
-rw-r--r--Tests/MSManifest/Subdir2/test_manifest1.in5
-rw-r--r--Tests/MSManifest/Subdir2/test_manifest2.in12
-rw-r--r--Tests/MSManifest/Subdir2/test_manifest3.in9
-rw-r--r--Tests/MSVCRuntimeLibrary/CMakeLists.txt71
-rw-r--r--Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt59
-rw-r--r--Tests/MSVCRuntimeLibrary/Fortran/verify.F901
-rw-r--r--Tests/MSVCRuntimeLibrary/verify.c1
-rw-r--r--Tests/MSVCRuntimeLibrary/verify.cu1
-rw-r--r--Tests/MSVCRuntimeLibrary/verify.cxx1
-rw-r--r--Tests/MSVCRuntimeLibrary/verify.h29
-rw-r--r--Tests/MacRuntimePath/A/CMakeLists.txt79
-rw-r--r--Tests/MacRuntimePath/A/framework.cpp9
-rw-r--r--Tests/MacRuntimePath/A/framework.h17
-rw-r--r--Tests/MacRuntimePath/A/framework2.cpp9
-rw-r--r--Tests/MacRuntimePath/A/framework2.h17
-rw-r--r--Tests/MacRuntimePath/A/shared.cpp9
-rw-r--r--Tests/MacRuntimePath/A/shared.h17
-rw-r--r--Tests/MacRuntimePath/A/test1.cpp8
-rw-r--r--Tests/MacRuntimePath/A/test2.cpp8
-rw-r--r--Tests/MacRuntimePath/A/test3.cpp8
-rw-r--r--Tests/MacRuntimePath/B/CMakeLists.txt18
-rw-r--r--Tests/MacRuntimePath/CMakeLists.txt75
-rw-r--r--Tests/MacRuntimePath/InitialCache.cmake.in14
-rw-r--r--Tests/MacroTest/CMakeLists.txt91
-rw-r--r--Tests/MacroTest/context.cmake10
-rw-r--r--Tests/MacroTest/macroTest.c7
-rw-r--r--Tests/MakeClean/CMakeLists.txt50
-rw-r--r--Tests/MakeClean/ToClean/CMakeLists.txt122
-rw-r--r--Tests/MakeClean/ToClean/EmptySubDir/CMakeLists.txt17
-rw-r--r--Tests/MakeClean/ToClean/ToCleanFiles.cmake.in1
-rw-r--r--Tests/MakeClean/ToClean/toclean.cxx4
-rw-r--r--Tests/MakeClean/check_clean.c.in26
-rw-r--r--Tests/MathTest/CMakeLists.txt55
-rw-r--r--Tests/MathTest/MathTestExec.cxx46
-rw-r--r--Tests/MathTest/MathTestTests.h.in1
-rw-r--r--Tests/MissingInstall/CMakeLists.txt21
-rw-r--r--Tests/MissingInstall/ExpectInstallFail.cmake18
-rw-r--r--Tests/MissingInstall/mybin.cpp3
-rw-r--r--Tests/MissingSourceFile/CMakeLists.txt3
-rw-r--r--Tests/Module/CheckIPOSupported-C/CMakeLists.txt30
-rw-r--r--Tests/Module/CheckIPOSupported-C/bar.c4
-rw-r--r--Tests/Module/CheckIPOSupported-C/foo.c4
-rw-r--r--Tests/Module/CheckIPOSupported-C/main.c10
-rw-r--r--Tests/Module/CheckIPOSupported-CXX/CMakeLists.txt31
-rw-r--r--Tests/Module/CheckIPOSupported-CXX/bar.cpp4
-rw-r--r--Tests/Module/CheckIPOSupported-CXX/foo.cpp4
-rw-r--r--Tests/Module/CheckIPOSupported-CXX/main.cpp10
-rw-r--r--Tests/Module/CheckIPOSupported-Fortran/CMakeLists.txt20
-rw-r--r--Tests/Module/CheckIPOSupported-Fortran/foo.f2
-rw-r--r--Tests/Module/CheckIPOSupported-Fortran/main.f3
-rw-r--r--Tests/Module/CheckTypeSize/CMakeLists.txt39
-rw-r--r--Tests/Module/CheckTypeSize/CheckTypeSize.c161
-rw-r--r--Tests/Module/CheckTypeSize/CheckTypeSize.cxx199
-rw-r--r--Tests/Module/CheckTypeSize/config.h.in51
-rw-r--r--Tests/Module/CheckTypeSize/config.hxx.in33
-rw-r--r--Tests/Module/CheckTypeSize/someclass.hxx15
-rw-r--r--Tests/Module/CheckTypeSize/somestruct.h11
-rw-r--r--Tests/Module/ExternalData/.gitattributes5
-rw-r--r--Tests/Module/ExternalData/Alt/MyAlgoMap1-md5/dded55e43cd6529ee35d24113dfc87a31
-rw-r--r--Tests/Module/ExternalData/Alt/SHA1/85158f0c1996837976e858c42a9a7634bfe91b931
-rw-r--r--Tests/Module/ExternalData/CMakeLists.txt59
-rw-r--r--Tests/Module/ExternalData/Data Space.dat.md51
-rw-r--r--Tests/Module/ExternalData/Data.dat.md51
-rw-r--r--Tests/Module/ExternalData/Data1Check.cmake108
-rw-r--r--Tests/Module/ExternalData/Data2.dat.md51
-rw-r--r--Tests/Module/ExternalData/Data2/CMakeLists.txt11
-rw-r--r--Tests/Module/ExternalData/Data2/Data2Check.cmake12
-rw-r--r--Tests/Module/ExternalData/Data2/SeriesC_1_.my.dat.md51
-rw-r--r--Tests/Module/ExternalData/Data2/SeriesC_2_.my.dat.md51
-rw-r--r--Tests/Module/ExternalData/Data2/SeriesC_3_.my.dat.md51
-rw-r--r--Tests/Module/ExternalData/Data2b.dat.md51
-rw-r--r--Tests/Module/ExternalData/Data3/CMakeLists.txt14
-rw-r--r--Tests/Module/ExternalData/Data3/Data.dat.md51
-rw-r--r--Tests/Module/ExternalData/Data3/Data3Check.cmake25
-rw-r--r--Tests/Module/ExternalData/Data3/Other.dat.md51
-rw-r--r--Tests/Module/ExternalData/Data4/CMakeLists.txt15
-rw-r--r--Tests/Module/ExternalData/Data4/Data.dat.md51
-rw-r--r--Tests/Module/ExternalData/Data4/Data4Check.cmake26
-rw-r--r--Tests/Module/ExternalData/Data4/Other.dat.md51
-rw-r--r--Tests/Module/ExternalData/Data5/CMakeLists.txt29
-rw-r--r--Tests/Module/ExternalData/Data5/Data5.dat.md51
-rw-r--r--Tests/Module/ExternalData/Data5/Data5Check.cmake4
-rw-r--r--Tests/Module/ExternalData/DataAlgoMapA.dat.md51
-rw-r--r--Tests/Module/ExternalData/DataAlgoMapB.dat.sha11
-rw-r--r--Tests/Module/ExternalData/DataNoSymlinks/CMakeLists.txt8
-rw-r--r--Tests/Module/ExternalData/DataNoSymlinks/Data.dat.md51
-rw-r--r--Tests/Module/ExternalData/DataNoSymlinks/DataNoSymlinksCheck.cmake6
-rw-r--r--Tests/Module/ExternalData/DataScript.dat.md51
-rw-r--r--Tests/Module/ExternalData/DirRecurse/A.dat.md51
-rw-r--r--Tests/Module/ExternalData/DirRecurse/B.dat.md51
-rw-r--r--Tests/Module/ExternalData/DirRecurse/C.dat.md51
-rw-r--r--Tests/Module/ExternalData/DirRecurse/Sub1/A.dat.md51
-rw-r--r--Tests/Module/ExternalData/DirRecurse/Sub1/B.dat.md51
-rw-r--r--Tests/Module/ExternalData/DirRecurse/Sub1/C.dat.md51
-rw-r--r--Tests/Module/ExternalData/DirRecurse/Sub2/Dir/A.dat.md51
-rw-r--r--Tests/Module/ExternalData/DirRecurse/Sub2/Dir/B.dat.md51
-rw-r--r--Tests/Module/ExternalData/DirRecurse/Sub2/Dir/C.dat.md51
-rw-r--r--Tests/Module/ExternalData/Directory/A.dat.md51
-rw-r--r--Tests/Module/ExternalData/Directory/B.dat.md51
-rw-r--r--Tests/Module/ExternalData/Directory/C.dat.md51
-rw-r--r--Tests/Module/ExternalData/MD5/08cfcf221f76ace7b906b312284e73d71
-rw-r--r--Tests/Module/ExternalData/MD5/30ba0acdee9096b3b9fc6c69362c6b421
-rw-r--r--Tests/Module/ExternalData/MD5/31eff09e84fca01415f8cd9d82ec432b1
-rw-r--r--Tests/Module/ExternalData/MD5/401767f22a456b3522953722090a2c361
-rw-r--r--Tests/Module/ExternalData/MD5/8c018830e3efa5caf3c7415028335a571
-rw-r--r--Tests/Module/ExternalData/MD5/8f4add4581551facf27237e6577fd6621
-rw-r--r--Tests/Module/ExternalData/MD5/9d980b06c2f0fec3d4872d68175b98221
-rw-r--r--Tests/Module/ExternalData/MD5/aaad162b85f60d1eb57ca71a23e8efd71
-rw-r--r--Tests/Module/ExternalData/MD5/c1030719c95f3435d8abc39c0d4429461
-rw-r--r--Tests/Module/ExternalData/MD5/ce38ea6c3c1e00fa6405dd64b8bf6da01
-rw-r--r--Tests/Module/ExternalData/MD5/ecfa1ecd417d4253af81ae04d1bd65811
-rw-r--r--Tests/Module/ExternalData/MD5/f41c94425d01ecbbee70440b951cb0581
-rw-r--r--Tests/Module/ExternalData/MD5/f7ab5a04aae9cb9a520e70b20b9c8ed71
-rw-r--r--Tests/Module/ExternalData/MetaA.dat.md51
-rw-r--r--Tests/Module/ExternalData/MetaB.dat.md51
-rw-r--r--Tests/Module/ExternalData/MetaC.dat.md51
-rw-r--r--Tests/Module/ExternalData/MetaTop.dat.md51
-rw-r--r--Tests/Module/ExternalData/MultipleAlgorithmNoMD5.dat.md51
-rw-r--r--Tests/Module/ExternalData/MultipleAlgorithmNoMD5.dat.sha11
-rw-r--r--Tests/Module/ExternalData/MultipleAlgorithmNoSHA1.dat.md51
-rw-r--r--Tests/Module/ExternalData/MultipleAlgorithmNoSHA1.dat.sha11
-rw-r--r--Tests/Module/ExternalData/MyScript1.cmake5
-rw-r--r--Tests/Module/ExternalData/PairedA.dat.md51
-rw-r--r--Tests/Module/ExternalData/PairedB.dat.md51
-rw-r--r--Tests/Module/ExternalData/SHA1/2af59a7022024974f3b8521b7ed8137c996a79f11
-rw-r--r--Tests/Module/ExternalData/SHA224/3b679da7908562fe1cc28db47ffb89bae025f4551dceb343a58691741
-rw-r--r--Tests/Module/ExternalData/SHA256/969171a0dd70d49ce096bd3e8178c7e26c711c9b20dbcaa3853d869d3871f1331
-rw-r--r--Tests/Module/ExternalData/SHA3_256/c01b0bfd51ece4295c7b45493750a3612ecc483095eb1366f9f46b179550e2311
-rw-r--r--Tests/Module/ExternalData/SeriesA.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesA1.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesA2.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesA3.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesAn1.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesAn2.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesAn3.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesB.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesB_1.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesB_2.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesB_3.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesBn_1.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesBn_2.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesBn_3.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesC.1.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesC.2.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesC.3.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesC.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesCn.1.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesCn.2.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesCn.3.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesD-1.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesD-2.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesD-3.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesD.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesDn-1.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesDn-2.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesDn-3.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesMixed.1.dat.md51
-rw-r--r--Tests/Module/ExternalData/SeriesMixed.2.dat.sha11
-rw-r--r--Tests/Module/ExternalData/SeriesMixed.3.dat.sha2241
-rw-r--r--Tests/Module/ExternalData/SeriesMixed.4.dat.sha2561
-rw-r--r--Tests/Module/ExternalData/SeriesMixed.5.dat.sha3-2561
-rw-r--r--Tests/Module/FindDependency/CMakeLists.txt13
-rw-r--r--Tests/Module/FindDependency/main.cpp41
-rw-r--r--Tests/Module/FindDependency/packages/Pack1/Pack1Config.cmake9
-rw-r--r--Tests/Module/FindDependency/packages/Pack1/Pack1ConfigVersion.cmake11
-rw-r--r--Tests/Module/FindDependency/packages/Pack2/Pack2Config.cmake5
-rw-r--r--Tests/Module/FindDependency/packages/Pack2/Pack2ConfigVersion.cmake11
-rw-r--r--Tests/Module/FindDependency/packages/Pack3/Pack3Config.cmake5
-rw-r--r--Tests/Module/FindDependency/packages/Pack3/Pack3ConfigVersion.cmake11
-rw-r--r--Tests/Module/FindDependency/packages/Pack4/Pack4Config.cmake9
-rw-r--r--Tests/Module/FindDependency/packages/Pack4/Pack4ConfigVersion.cmake11
-rw-r--r--Tests/Module/FindDependency/packages/Pack5/Pack5Config.cmake3
-rw-r--r--Tests/Module/FindDependency/packages/Pack5/Pack5ConfigVersion.cmake11
-rw-r--r--Tests/Module/FindDependency/packages/Pack6/Pack6Config.cmake3
-rw-r--r--Tests/Module/FindDependency/packages/Pack6/Pack6ConfigVersion.cmake11
-rw-r--r--Tests/Module/FindDependency/packages/Pack7/Pack7Config.cmake14
-rw-r--r--Tests/Module/FindDependency/packages/Pack8/Pack8Config.cmake7
-rw-r--r--Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt219
-rw-r--r--Tests/Module/WriteCompilerDetectionHeader/c_undefined.c7
-rw-r--r--Tests/Module/WriteCompilerDetectionHeader/compile_tests.h27
-rw-r--r--Tests/Module/WriteCompilerDetectionHeader/main.c30
-rw-r--r--Tests/Module/WriteCompilerDetectionHeader/main.cpp17
-rw-r--r--Tests/Module/WriteCompilerDetectionHeader/main_bare.cpp23
-rw-r--r--Tests/Module/WriteCompilerDetectionHeader/main_multi.c30
-rw-r--r--Tests/Module/WriteCompilerDetectionHeader/multi_files.cpp17
-rw-r--r--Tests/ModuleDefinition/CMakeLists.txt38
-rw-r--r--Tests/ModuleDefinition/example_dll.c4
-rw-r--r--Tests/ModuleDefinition/example_dll.def2
-rw-r--r--Tests/ModuleDefinition/example_dll_2.c4
-rw-r--r--Tests/ModuleDefinition/example_dll_2.def2
-rw-r--r--Tests/ModuleDefinition/example_dll_gen.c4
-rw-r--r--Tests/ModuleDefinition/example_dll_gen.def.in2
-rw-r--r--Tests/ModuleDefinition/example_exe.c21
-rw-r--r--Tests/ModuleDefinition/example_exe.def2
-rw-r--r--Tests/ModuleDefinition/example_mod_1.c20
-rw-r--r--Tests/ModuleDefinition/split_dll.c9
-rw-r--r--Tests/ModuleDefinition/split_dll_1.def2
-rw-r--r--Tests/ModuleDefinition/split_dll_2.def2
-rw-r--r--Tests/MumpsCoverage/.gitattributes1
-rw-r--r--Tests/MumpsCoverage/DartConfiguration.cache.tcl.in8
-rw-r--r--Tests/MumpsCoverage/DartConfiguration.tcl.in8
-rw-r--r--Tests/MumpsCoverage/VistA-FOIA/Packages/Uncategorized/ZZCOVTST.m46
-rw-r--r--Tests/MumpsCoverage/ZZCOVTST.cmcov48
-rw-r--r--Tests/MumpsCoverage/ZZCOVTST.mcov41
-rw-r--r--Tests/MumpsCoverage/cache_coverage.cmcov.in2
-rw-r--r--Tests/MumpsCoverage/gtm_coverage.mcov.in2
-rw-r--r--Tests/NewlineArgs/CMakeLists.txt16
-rw-r--r--Tests/NewlineArgs/cxxonly.cxx18
-rw-r--r--Tests/NewlineArgs/libcxx1.cxx10
-rw-r--r--Tests/NewlineArgs/libcxx1.h9
-rw-r--r--Tests/NewlineArgs/libcxx2.h.in6
-rw-r--r--Tests/ObjC/CMakeLists.txt4
-rw-r--r--Tests/ObjC/c-file-extension-test/CMakeLists.txt5
-rw-r--r--Tests/ObjC/c-file-extension-test/main.m8
-rw-r--r--Tests/ObjC/cxx-file-extension-test/CMakeLists.txt8
-rw-r--r--Tests/ObjC/cxx-file-extension-test/main.m8
-rw-r--r--Tests/ObjC/objc-file-extension-test/CMakeLists.txt6
-rw-r--r--Tests/ObjC/objc-file-extension-test/main.m12
-rw-r--r--Tests/ObjC/simple-build-test/CMakeLists.txt11
-rw-r--r--Tests/ObjC/simple-build-test/foo.h9
-rw-r--r--Tests/ObjC/simple-build-test/foo.m7
-rw-r--r--Tests/ObjC/simple-build-test/main.m12
-rw-r--r--Tests/ObjCXX/CMakeLists.txt5
-rw-r--r--Tests/ObjCXX/ObjC++/CMakeLists.txt5
-rw-r--r--Tests/ObjCXX/ObjC++/objc++.mm23
-rw-r--r--Tests/ObjCXX/cxx-as-objcxx/CMakeLists.txt5
-rw-r--r--Tests/ObjCXX/cxx-as-objcxx/main.cpp6
-rw-r--r--Tests/ObjCXX/cxx-file-extension-test/CMakeLists.txt5
-rw-r--r--Tests/ObjCXX/cxx-file-extension-test/main.mm8
-rw-r--r--Tests/ObjCXX/objcxx-file-extension-test/CMakeLists.txt6
-rw-r--r--Tests/ObjCXX/objcxx-file-extension-test/main.mm14
-rw-r--r--Tests/ObjCXX/simple-build-test/CMakeLists.txt11
-rw-r--r--Tests/ObjCXX/simple-build-test/foo.h9
-rw-r--r--Tests/ObjCXX/simple-build-test/foo.mm7
-rw-r--r--Tests/ObjCXX/simple-build-test/main.mm14
-rw-r--r--Tests/ObjectLibrary/A/CMakeLists.txt24
-rw-r--r--Tests/ObjectLibrary/A/a.h6
-rw-r--r--Tests/ObjectLibrary/A/a1.c.in2
-rw-r--r--Tests/ObjectLibrary/A/a2.c5
-rw-r--r--Tests/ObjectLibrary/AB.def5
-rw-r--r--Tests/ObjectLibrary/B/CMakeLists.txt13
-rw-r--r--Tests/ObjectLibrary/B/b.h18
-rw-r--r--Tests/ObjectLibrary/B/b1.c5
-rw-r--r--Tests/ObjectLibrary/B/b2.c5
-rw-r--r--Tests/ObjectLibrary/CMakeLists.txt77
-rw-r--r--Tests/ObjectLibrary/ExportLanguages/CMakeLists.txt15
-rw-r--r--Tests/ObjectLibrary/ExportLanguages/ExportLanguagesTest/CMakeLists.txt14
-rw-r--r--Tests/ObjectLibrary/ExportLanguages/a.c4
-rw-r--r--Tests/ObjectLibrary/ExportLanguages/a.cxx4
-rw-r--r--Tests/ObjectLibrary/Transitive/CMakeLists.txt12
-rw-r--r--Tests/ObjectLibrary/Transitive/FooObject.c4
-rw-r--r--Tests/ObjectLibrary/Transitive/FooStatic.c4
-rw-r--r--Tests/ObjectLibrary/Transitive/Transitive.c7
-rw-r--r--Tests/ObjectLibrary/c.c14
-rw-r--r--Tests/ObjectLibrary/dummy.c4
-rw-r--r--Tests/ObjectLibrary/dummy.objbin0 -> 498 bytes-rw-r--r--Tests/ObjectLibrary/main.c12
-rw-r--r--Tests/ObjectLibrary/mainAB.c17
-rw-r--r--Tests/OutDir/CMakeLists.txt36
-rw-r--r--Tests/OutDir/OutDir.c20
-rw-r--r--Tests/OutDir/OutDir.cmake32
-rw-r--r--Tests/OutName/CMakeLists.txt6
-rw-r--r--Tests/OutName/main.c4
-rw-r--r--Tests/OutOfBinary/CMakeLists.txt4
-rw-r--r--Tests/OutOfBinary/outexe.c5
-rw-r--r--Tests/OutOfBinary/outlib.c4
-rw-r--r--Tests/OutOfSource/CMakeLists.txt18
-rw-r--r--Tests/OutOfSource/OutOfSourceSubdir/CMakeLists.txt62
-rw-r--r--Tests/OutOfSource/OutOfSourceSubdir/simple.cxx34
-rw-r--r--Tests/OutOfSource/OutOfSourceSubdir/simple.cxx.in1
-rw-r--r--Tests/OutOfSource/OutOfSourceSubdir/testlib.cxx6
-rw-r--r--Tests/OutOfSource/OutOfSourceSubdir/testlib.h11
-rw-r--r--Tests/OutOfSource/SubDir/CMakeLists.txt10
-rw-r--r--Tests/OutOfSource/SubDir/subdir.c4
-rw-r--r--Tests/OutOfSource/simple.cxx4
-rw-r--r--Tests/OutOfSource/testdp.h.in1
-rw-r--r--Tests/PDBDirectoryAndName/CMakeLists.txt103
-rw-r--r--Tests/PDBDirectoryAndName/check_pdbs.cmake10
-rw-r--r--Tests/PDBDirectoryAndName/myexe.c8
-rw-r--r--Tests/PDBDirectoryAndName/myexe2.c6
-rw-r--r--Tests/PDBDirectoryAndName/mylibA.c4
-rw-r--r--Tests/PDBDirectoryAndName/mylibB.c4
-rw-r--r--Tests/PDBDirectoryAndName/mylibC.c4
-rw-r--r--Tests/PDBDirectoryAndName/mylibD.c4
-rw-r--r--Tests/PerConfig/CMakeLists.txt34
-rw-r--r--Tests/PerConfig/pcShared.c5
-rw-r--r--Tests/PerConfig/pcShared.h16
-rw-r--r--Tests/PerConfig/pcStatic.c4
-rw-r--r--Tests/PerConfig/perconfig.c8
-rw-r--r--Tests/PerConfig/perconfig.cmake40
-rw-r--r--Tests/Plugin/CMakeLists.txt64
-rw-r--r--Tests/Plugin/PluginTest/CMakeLists.txt27
-rw-r--r--Tests/Plugin/check_mod_soname.cmake7
-rw-r--r--Tests/Plugin/include/DynamicLoader.hxx49
-rw-r--r--Tests/Plugin/include/example.h24
-rw-r--r--Tests/Plugin/src/DynamicLoader.cxx263
-rw-r--r--Tests/Plugin/src/example_exe.cxx52
-rw-r--r--Tests/Plugin/src/example_exe.h.in8
-rw-r--r--Tests/Plugin/src/example_mod_1.c21
-rw-r--r--Tests/Policy0002/A/CMakeLists.txt1
-rw-r--r--Tests/Policy0002/CMakeLists.txt5
-rw-r--r--Tests/Policy0002/policy0002.c4
-rw-r--r--Tests/PolicyScope/Bar.cmake8
-rw-r--r--Tests/PolicyScope/CMakeLists.txt112
-rw-r--r--Tests/PolicyScope/FindFoo.cmake2
-rw-r--r--Tests/PolicyScope/main.c4
-rw-r--r--Tests/PositionIndependentTargets/.gitattributes2
-rw-r--r--Tests/PositionIndependentTargets/CMakeLists.txt14
-rw-r--r--Tests/PositionIndependentTargets/global/CMakeLists.txt37
-rw-r--r--Tests/PositionIndependentTargets/interface/CMakeLists.txt27
-rw-r--r--Tests/PositionIndependentTargets/main.cpp5
-rw-r--r--Tests/PositionIndependentTargets/pic_lib.cpp12
-rw-r--r--Tests/PositionIndependentTargets/pic_main.cpp7
-rw-r--r--Tests/PositionIndependentTargets/pic_test.h20
-rw-r--r--Tests/PositionIndependentTargets/targets/CMakeLists.txt20
-rw-r--r--Tests/PreOrder/CMakeLists.txt6
-rw-r--r--Tests/PreOrder/Library/CMakeLists.txt2
-rw-r--r--Tests/PreOrder/Library/simpleLib.cxx3
-rw-r--r--Tests/PreOrder/simple.cxx6
-rw-r--r--Tests/PrecompiledHeader/CMakeLists.txt54
-rw-r--r--Tests/PrecompiledHeader/foo1.c8
-rw-r--r--Tests/PrecompiledHeader/foo2.c9
-rw-r--r--Tests/PrecompiledHeader/foo_precompile.c5
-rw-r--r--Tests/PrecompiledHeader/include/foo.h4
-rw-r--r--Tests/PrecompiledHeader/include/foo_precompiled.h1
-rw-r--r--Tests/Preprocess/CMakeLists.txt286
-rw-r--r--Tests/Preprocess/file_def.h1
-rw-r--r--Tests/Preprocess/preprocess.c192
-rw-r--r--Tests/Preprocess/preprocess.cxx215
-rw-r--r--Tests/Preprocess/preprocess.h.in10
-rw-r--r--Tests/Preprocess/target_def.h1
-rw-r--r--Tests/Properties/CMakeLists.txt353
-rw-r--r--Tests/Properties/SubDir/CMakeLists.txt2
-rw-r--r--Tests/Properties/SubDir/properties3.cxx9
-rw-r--r--Tests/Properties/SubDir2/CMakeLists.txt34
-rw-r--r--Tests/Properties/properties.h.in1
-rw-r--r--Tests/Properties/properties2.h1
-rw-r--r--Tests/Properties/subdirtest.cxx9
-rw-r--r--Tests/PythonCoverage/DartConfiguration.tcl.in8
-rw-r--r--Tests/PythonCoverage/coverage.xml.in35
-rw-r--r--Tests/PythonCoverage/coveragetest/foo.py8
-rw-r--r--Tests/PythonCoverage/coveragetest/test_foo.py11
-rw-r--r--Tests/Qt4And5Automoc/CMakeLists.txt29
-rw-r--r--Tests/Qt4And5Automoc/main.cpp.in18
-rw-r--r--Tests/Qt4Autogen/CMakeLists.txt11
-rw-r--r--Tests/Qt4Deploy/CMakeLists.txt71
-rw-r--r--Tests/Qt4Deploy/testdeploy.cpp29
-rw-r--r--Tests/Qt4Targets/CMakeLists.txt90
-rw-r--r--Tests/Qt4Targets/IncrementalMoc/CMakeLists.txt21
-rw-r--r--Tests/Qt4Targets/IncrementalMoc/foo.cpp7
-rw-r--r--Tests/Qt4Targets/IncrementalMoc/foo.h9
-rw-r--r--Tests/Qt4Targets/activeqtexe.cpp35
-rw-r--r--Tests/Qt4Targets/interface/myinterface.h11
-rw-r--r--Tests/Qt4Targets/main.cpp23
-rw-r--r--Tests/Qt4Targets/main_gen_test.cpp26
-rw-r--r--Tests/Qt4Targets/main_wrap_test.cpp11
-rw-r--r--Tests/Qt4Targets/mywrapobject.h22
-rw-r--r--Tests/Qt5Autogen/CMakeLists.txt8
-rw-r--r--Tests/QtAutogen/AutogenCoreTest.cmake55
-rw-r--r--Tests/QtAutogen/AutogenGuiTest.cmake55
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOff/CMakeLists.txt85
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOff/a_mc.hpp.in9
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOff/a_qt.cpp29
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOff/a_qt.hpp27
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOff/b_mc.cpp.in9
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOff/b_mc.hpp9
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOff/b_qt.cpp29
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOff/b_qt.hpp27
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOff/config.hpp.in8
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOff/configure_content.cmake10
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOff/main.cpp16
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOn/CMakeLists.txt91
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOn/object_invalid.hpp.in1
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOn/object_valid.hpp.in14
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOn/simpleLib.cpp.in9
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOn/simpleLib.hpp.in14
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOn/testGenFile.cpp8
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOn/testGenLib.cpp12
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOn/testGenLib.hpp17
-rw-r--r--Tests/QtAutogen/AutogenOriginDependsOn/testGenTarget.cpp9
-rw-r--r--Tests/QtAutogen/AutogenTargetDepends/CMakeLists.txt54
-rw-r--r--Tests/QtAutogen/AutogenTargetDepends/object_invalid.hpp.in1
-rw-r--r--Tests/QtAutogen/AutogenTargetDepends/object_valid.hpp.in14
-rw-r--r--Tests/QtAutogen/AutogenTargetDepends/testATDFile.cpp9
-rw-r--r--Tests/QtAutogen/AutogenTargetDepends/testATDTarget.cpp9
-rw-r--r--Tests/QtAutogen/Complex/Adir/CMakeLists.txt8
-rw-r--r--Tests/QtAutogen/Complex/Adir/libA.cpp12
-rw-r--r--Tests/QtAutogen/Complex/Adir/libA.h18
-rw-r--r--Tests/QtAutogen/Complex/Bdir/CMakeLists.txt9
-rw-r--r--Tests/QtAutogen/Complex/Bdir/libB.cpp12
-rw-r--r--Tests/QtAutogen/Complex/Bdir/libB.h22
-rw-r--r--Tests/QtAutogen/Complex/CMakeLists.txt85
-rw-r--r--Tests/QtAutogen/Complex/abc.cpp40
-rw-r--r--Tests/QtAutogen/Complex/abc.h17
-rw-r--r--Tests/QtAutogen/Complex/abc_p.h19
-rw-r--r--Tests/QtAutogen/Complex/bar.cpp17
-rw-r--r--Tests/QtAutogen/Complex/blub.cpp31
-rw-r--r--Tests/QtAutogen/Complex/blub.h15
-rw-r--r--Tests/QtAutogen/Complex/calwidget.cpp436
-rw-r--r--Tests/QtAutogen/Complex/calwidget.h127
-rw-r--r--Tests/QtAutogen/Complex/calwidget.ui32
-rw-r--r--Tests/QtAutogen/Complex/codeeditor.cpp149
-rw-r--r--Tests/QtAutogen/Complex/codeeditor.h100
-rw-r--r--Tests/QtAutogen/Complex/debug_class.cpp11
-rw-r--r--Tests/QtAutogen/Complex/debug_class.h19
-rw-r--r--Tests/QtAutogen/Complex/debug_class.ui45
-rw-r--r--Tests/QtAutogen/Complex/debug_resource.qrc5
-rw-r--r--Tests/QtAutogen/Complex/foo.cpp30
-rw-r--r--Tests/QtAutogen/Complex/foo.h20
-rw-r--r--Tests/QtAutogen/Complex/gadget.cpp4
-rw-r--r--Tests/QtAutogen/Complex/gadget.h19
-rw-r--r--Tests/QtAutogen/Complex/generated.cpp9
-rw-r--r--Tests/QtAutogen/Complex/generated.h21
-rw-r--r--Tests/QtAutogen/Complex/generated.txt.in1
-rw-r--r--Tests/QtAutogen/Complex/generated_resource.qrc.in5
-rw-r--r--Tests/QtAutogen/Complex/libC.cpp12
-rw-r--r--Tests/QtAutogen/Complex/libC.h22
-rw-r--r--Tests/QtAutogen/Complex/main.cpp94
-rw-r--r--Tests/QtAutogen/Complex/multiplewidgets.cpp19
-rw-r--r--Tests/QtAutogen/Complex/multiplewidgets.h35
-rw-r--r--Tests/QtAutogen/Complex/myinterface.h.in14
-rw-r--r--Tests/QtAutogen/Complex/myotherinterface.h.in14
-rw-r--r--Tests/QtAutogen/Complex/private_slot.cpp16
-rw-r--r--Tests/QtAutogen/Complex/private_slot.h20
-rw-r--r--Tests/QtAutogen/Complex/resourcetester.cpp26
-rw-r--r--Tests/QtAutogen/Complex/resourcetester.h17
-rw-r--r--Tests/QtAutogen/Complex/second_resource.qrc5
-rw-r--r--Tests/QtAutogen/Complex/second_widget.cpp16
-rw-r--r--Tests/QtAutogen/Complex/second_widget.h18
-rw-r--r--Tests/QtAutogen/Complex/second_widget.ui32
-rw-r--r--Tests/QtAutogen/Complex/sub/bar.h17
-rw-r--r--Tests/QtAutogen/Complex/targetObjectsTest.cpp5
-rw-r--r--Tests/QtAutogen/Complex/test.qrc5
-rw-r--r--Tests/QtAutogen/Complex/widget1.ui45
-rw-r--r--Tests/QtAutogen/Complex/widget2.ui29
-rw-r--r--Tests/QtAutogen/Complex/xyz.cpp15
-rw-r--r--Tests/QtAutogen/Complex/xyz.h17
-rw-r--r--Tests/QtAutogen/Complex/yaf.cpp20
-rw-r--r--Tests/QtAutogen/Complex/yaf.h15
-rw-r--r--Tests/QtAutogen/Complex/yaf_p.h19
-rw-r--r--Tests/QtAutogen/DefinesTest/CMakeLists.txt13
-rw-r--r--Tests/QtAutogen/DefinesTest/defines_test.cpp38
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt126
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/CMakeLists.txt28
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/data.qrc5
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/item.cpp20
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/item.hpp15
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/main.cpp15
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/CMakeLists.txt2
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/sda.cpp6
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/sda.hpp6
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/CMakeLists.txt5
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/sdb.cpp6
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/sdb.hpp6
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/CMakeLists.txt5
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/sdc.cpp6
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/sdc.hpp6
-rw-r--r--Tests/QtAutogen/GlobalAutogenTarget/GAT/view.ui24
-rw-r--r--Tests/QtAutogen/LowMinimumVersion/CMakeLists.txt16
-rw-r--r--Tests/QtAutogen/LowMinimumVersion/example.qrc5
-rw-r--r--Tests/QtAutogen/LowMinimumVersion/item.cpp20
-rw-r--r--Tests/QtAutogen/LowMinimumVersion/item.hpp15
-rw-r--r--Tests/QtAutogen/LowMinimumVersion/main.cpp10
-rw-r--r--Tests/QtAutogen/LowMinimumVersion/someText.txt1
-rw-r--r--Tests/QtAutogen/LowMinimumVersion/view.ui24
-rw-r--r--Tests/QtAutogen/MacOsFW/CMakeLists.txt21
-rw-r--r--Tests/QtAutogen/MacOsFW/src/CMakeLists.txt33
-rw-r--r--Tests/QtAutogen/MacOsFW/src/macos_fw_lib.cpp17
-rw-r--r--Tests/QtAutogen/MacOsFW/src/macos_fw_lib.h18
-rw-r--r--Tests/QtAutogen/MacOsFW/test/CMakeLists.txt19
-rw-r--r--Tests/QtAutogen/MacOsFW/test/testMacosFWLib.cpp43
-rw-r--r--Tests/QtAutogen/MacOsFW/test/testMacosFWLib.h7
-rw-r--r--Tests/QtAutogen/ManySources/CMakeLists.txt35
-rw-r--r--Tests/QtAutogen/ManySources/data.qrc.in7
-rw-r--r--Tests/QtAutogen/ManySources/item.cpp.in27
-rw-r--r--Tests/QtAutogen/ManySources/item.h.in15
-rw-r--r--Tests/QtAutogen/ManySources/main.cpp.in7
-rw-r--r--Tests/QtAutogen/ManySources/object.h.in15
-rw-r--r--Tests/QtAutogen/ManySources/view.ui.in24
-rw-r--r--Tests/QtAutogen/MocCMP0071/CMakeLists.txt6
-rw-r--r--Tests/QtAutogen/MocCMP0071/NEW/CMakeLists.txt16
-rw-r--r--Tests/QtAutogen/MocCMP0071/OLD/CMakeLists.txt18
-rw-r--r--Tests/QtAutogen/MocCMP0071/Obj.cpp21
-rw-r--r--Tests/QtAutogen/MocCMP0071/Obj.hpp19
-rw-r--r--Tests/QtAutogen/MocCMP0071/Obj_p.h14
-rw-r--r--Tests/QtAutogen/MocCMP0071/main.cpp7
-rw-r--r--Tests/QtAutogen/MocCMP0100/CMakeLists.txt9
-rw-r--r--Tests/QtAutogen/MocCMP0100/NEW/CMakeLists.txt10
-rw-r--r--Tests/QtAutogen/MocCMP0100/OLD/CMakeLists.txt31
-rw-r--r--Tests/QtAutogen/MocCMP0100/Obj.cpp31
-rw-r--r--Tests/QtAutogen/MocCMP0100/Obj.hh20
-rw-r--r--Tests/QtAutogen/MocCMP0100/Obj2.cpp31
-rw-r--r--Tests/QtAutogen/MocCMP0100/Obj2.hh20
-rw-r--r--Tests/QtAutogen/MocCMP0100/main.cpp9
-rw-r--r--Tests/QtAutogen/MocInclude/CMakeLists.txt112
-rw-r--r--Tests/QtAutogen/MocInclude/Common/DualSub/Second/Second.cpp11
-rw-r--r--Tests/QtAutogen/MocInclude/Common/DualSub/Second/Second.hpp14
-rw-r--r--Tests/QtAutogen/MocInclude/Common/DualSubMocked.cpp9
-rw-r--r--Tests/QtAutogen/MocInclude/Common/DualSubMocked.hpp15
-rw-r--r--Tests/QtAutogen/MocInclude/Common/ExternDot.cpp11
-rw-r--r--Tests/QtAutogen/MocInclude/Common/ExternDot.hpp15
-rw-r--r--Tests/QtAutogen/MocInclude/Common/ExternDotGenerated.cpp.in11
-rw-r--r--Tests/QtAutogen/MocInclude/Common/ExternDotGenerated.hpp.in15
-rw-r--r--Tests/QtAutogen/MocInclude/Common/InIncludes.in/SubOwnDot.cpp44
-rw-r--r--Tests/QtAutogen/MocInclude/Common/InIncludes.in/SubOwnDot.hpp17
-rw-r--r--Tests/QtAutogen/MocInclude/Common/InIncludes.in/SubOwnDot_p.hpp18
-rw-r--r--Tests/QtAutogen/MocInclude/Common/InIncludesMoc.cpp4
-rw-r--r--Tests/QtAutogen/MocInclude/Common/MixedCustom.cpp32
-rw-r--r--Tests/QtAutogen/MocInclude/Common/MixedCustom.hpp20
-rw-r--r--Tests/QtAutogen/MocInclude/Common/MixedSkipped.cpp40
-rw-r--r--Tests/QtAutogen/MocInclude/Common/MixedSkipped.hpp17
-rw-r--r--Tests/QtAutogen/MocInclude/Common/None.cpp21
-rw-r--r--Tests/QtAutogen/MocInclude/Common/None.hpp19
-rw-r--r--Tests/QtAutogen/MocInclude/Common/None_p.h14
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OtherUnderscore.cpp45
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OtherUnderscore.hpp19
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OtherUnderscoreExtra.cpp21
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OtherUnderscoreExtra.hpp18
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OtherUnderscoreExtra_p.hpp14
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSub.cpp46
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSub.hpp19
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSubDir/SubExtra.cpp21
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSubDir/SubExtra.hpp18
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSubDir/SubExtra_p.hpp14
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSub_p.hpp14
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OtherUnderscore_p.hpp14
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OwnDot.cpp40
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OwnDot.hpp19
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OwnDotUnderscore.cpp41
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OwnDotUnderscore.hpp19
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OwnDotUnderscore_p.h14
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OwnDot_p.h14
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OwnUnderscore.cpp23
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OwnUnderscore.hpp19
-rw-r--r--Tests/QtAutogen/MocInclude/Common/OwnUnderscore_p.h14
-rw-r--r--Tests/QtAutogen/MocInclude/Common/common.cpp.in32
-rw-r--r--Tests/QtAutogen/MocInclude/Common/moc_MixedCustom.cpp.in5
-rw-r--r--Tests/QtAutogen/MocInclude/Relaxed/CMakeLists.txt17
-rw-r--r--Tests/QtAutogen/MocInclude/Relaxed/RObjA.cpp12
-rw-r--r--Tests/QtAutogen/MocInclude/Relaxed/RObjA.hpp14
-rw-r--r--Tests/QtAutogen/MocInclude/Relaxed/RObjB.cpp23
-rw-r--r--Tests/QtAutogen/MocInclude/Relaxed/RObjB.hpp14
-rw-r--r--Tests/QtAutogen/MocInclude/Relaxed/RObjBExtra.hpp14
-rw-r--r--Tests/QtAutogen/MocInclude/Relaxed/RObjC.cpp31
-rw-r--r--Tests/QtAutogen/MocInclude/Relaxed/RObjC.hpp14
-rw-r--r--Tests/QtAutogen/MocInclude/Relaxed/relaxed.cpp21
-rw-r--r--Tests/QtAutogen/MocInclude/Strict/CMakeLists.txt14
-rw-r--r--Tests/QtAutogen/MocInclude/Strict/strict.cpp7
-rw-r--r--Tests/QtAutogen/MocInclude/main.cpp9
-rw-r--r--Tests/QtAutogen/MocIncludeSymlink/CMakeLists.txt81
-rw-r--r--Tests/QtAutogen/MocMacroName/CMakeLists.txt17
-rw-r--r--Tests/QtAutogen/MocMacroName/CustomMacros.hpp8
-rw-r--r--Tests/QtAutogen/MocMacroName/Gadget.cpp6
-rw-r--r--Tests/QtAutogen/MocMacroName/Gadget.hpp19
-rw-r--r--Tests/QtAutogen/MocMacroName/Object.cpp10
-rw-r--r--Tests/QtAutogen/MocMacroName/Object.hpp22
-rw-r--r--Tests/QtAutogen/MocMacroName/Object1Aliased.cpp9
-rw-r--r--Tests/QtAutogen/MocMacroName/Object1Aliased.hpp20
-rw-r--r--Tests/QtAutogen/MocMacroName/Object2Aliased.cpp9
-rw-r--r--Tests/QtAutogen/MocMacroName/Object2Aliased.hpp20
-rw-r--r--Tests/QtAutogen/MocMacroName/main.cpp13
-rw-r--r--Tests/QtAutogen/MocOnly/CMakeLists.txt29
-rw-r--r--Tests/QtAutogen/MocOnly/CfgDebug.cpp5
-rw-r--r--Tests/QtAutogen/MocOnly/CfgDebug.hpp15
-rw-r--r--Tests/QtAutogen/MocOnly/CfgOther.cpp5
-rw-r--r--Tests/QtAutogen/MocOnly/CfgOther.hpp15
-rw-r--r--Tests/QtAutogen/MocOnly/IncA.cpp19
-rw-r--r--Tests/QtAutogen/MocOnly/IncA.hpp15
-rw-r--r--Tests/QtAutogen/MocOnly/IncB.cpp19
-rw-r--r--Tests/QtAutogen/MocOnly/IncB.hpp15
-rw-r--r--Tests/QtAutogen/MocOnly/StyleA.cpp5
-rw-r--r--Tests/QtAutogen/MocOnly/StyleA.hpp17
-rw-r--r--Tests/QtAutogen/MocOnly/StyleB.cpp5
-rw-r--r--Tests/QtAutogen/MocOnly/StyleB.hpp16
-rw-r--r--Tests/QtAutogen/MocOnly/main.cpp27
-rw-r--r--Tests/QtAutogen/MocOptions/CMakeLists.txt9
-rw-r--r--Tests/QtAutogen/MocOptions/Object.cpp5
-rw-r--r--Tests/QtAutogen/MocOptions/Object.hpp13
-rw-r--r--Tests/QtAutogen/MocOptions/main.cpp7
-rw-r--r--Tests/QtAutogen/MocOsMacros/CMakeLists.txt32
-rw-r--r--Tests/QtAutogen/MocOsMacros/TestClass.cpp83
-rw-r--r--Tests/QtAutogen/MocOsMacros/TestClass.hpp57
-rw-r--r--Tests/QtAutogen/MocOsMacros/main.cpp33
-rw-r--r--Tests/QtAutogen/MocSkipSource/CMakeLists.txt43
-rw-r--r--Tests/QtAutogen/MocSkipSource/qItemA.cpp5
-rw-r--r--Tests/QtAutogen/MocSkipSource/qItemA.hpp13
-rw-r--r--Tests/QtAutogen/MocSkipSource/qItemB.cpp5
-rw-r--r--Tests/QtAutogen/MocSkipSource/qItemB.hpp13
-rw-r--r--Tests/QtAutogen/MocSkipSource/qItemC.cpp17
-rw-r--r--Tests/QtAutogen/MocSkipSource/qItemC.hpp13
-rw-r--r--Tests/QtAutogen/MocSkipSource/qItemD.cpp17
-rw-r--r--Tests/QtAutogen/MocSkipSource/qItemD.hpp13
-rw-r--r--Tests/QtAutogen/MocSkipSource/skipMoc.cpp16
-rw-r--r--Tests/QtAutogen/ObjectLibrary/CMakeLists.txt18
-rw-r--r--Tests/QtAutogen/ObjectLibrary/a/CMakeLists.txt2
-rw-r--r--Tests/QtAutogen/ObjectLibrary/a/classa.cpp8
-rw-r--r--Tests/QtAutogen/ObjectLibrary/a/classa.h23
-rw-r--r--Tests/QtAutogen/ObjectLibrary/b/classb.cpp8
-rw-r--r--Tests/QtAutogen/ObjectLibrary/b/classb.h23
-rw-r--r--Tests/QtAutogen/ObjectLibrary/main.cpp13
-rw-r--r--Tests/QtAutogen/Parallel/CMakeLists.txt10
-rw-r--r--Tests/QtAutogen/Parallel/aaa/bbb/data.qrc6
-rw-r--r--Tests/QtAutogen/Parallel/aaa/bbb/item.cpp22
-rw-r--r--Tests/QtAutogen/Parallel/aaa/bbb/item.hpp18
-rw-r--r--Tests/QtAutogen/Parallel/aaa/data.qrc6
-rw-r--r--Tests/QtAutogen/Parallel/aaa/item.cpp22
-rw-r--r--Tests/QtAutogen/Parallel/aaa/item.hpp18
-rw-r--r--Tests/QtAutogen/Parallel/aaa/view.ui24
-rw-r--r--Tests/QtAutogen/Parallel/bbb/aaa/data.qrc6
-rw-r--r--Tests/QtAutogen/Parallel/bbb/aaa/item.cpp22
-rw-r--r--Tests/QtAutogen/Parallel/bbb/aaa/item.hpp18
-rw-r--r--Tests/QtAutogen/Parallel/bbb/data.qrc6
-rw-r--r--Tests/QtAutogen/Parallel/bbb/item.cpp23
-rw-r--r--Tests/QtAutogen/Parallel/bbb/item.hpp17
-rw-r--r--Tests/QtAutogen/Parallel/bbb/view.ui24
-rw-r--r--Tests/QtAutogen/Parallel/ccc/data.qrc6
-rw-r--r--Tests/QtAutogen/Parallel/ccc/item.cpp25
-rw-r--r--Tests/QtAutogen/Parallel/ccc/item.hpp18
-rw-r--r--Tests/QtAutogen/Parallel/ccc/view.ui24
-rw-r--r--Tests/QtAutogen/Parallel/data.qrc5
-rw-r--r--Tests/QtAutogen/Parallel/item.cpp20
-rw-r--r--Tests/QtAutogen/Parallel/item.hpp15
-rw-r--r--Tests/QtAutogen/Parallel/main.cpp16
-rw-r--r--Tests/QtAutogen/Parallel/parallel.cmake24
-rw-r--r--Tests/QtAutogen/Parallel/view.ui24
-rw-r--r--Tests/QtAutogen/Parallel1/CMakeLists.txt10
-rw-r--r--Tests/QtAutogen/Parallel2/CMakeLists.txt10
-rw-r--r--Tests/QtAutogen/Parallel3/CMakeLists.txt10
-rw-r--r--Tests/QtAutogen/Parallel4/CMakeLists.txt10
-rw-r--r--Tests/QtAutogen/ParallelAUTO/CMakeLists.txt10
-rw-r--r--Tests/QtAutogen/RccEmpty/CMakeLists.txt8
-rw-r--r--Tests/QtAutogen/RccEmpty/rccEmpty.cpp9
-rw-r--r--Tests/QtAutogen/RccEmpty/rccEmptyRes.qrc4
-rw-r--r--Tests/QtAutogen/RccOffMocLibrary/CMakeLists.txt17
-rw-r--r--Tests/QtAutogen/RccOffMocLibrary/empty.cpp1
-rw-r--r--Tests/QtAutogen/RccOffMocLibrary/empty.h9
-rw-r--r--Tests/QtAutogen/RccOffMocLibrary/not_generated_file.qrc5
-rw-r--r--Tests/QtAutogen/RccOnly/CMakeLists.txt8
-rw-r--r--Tests/QtAutogen/RccOnly/rccOnly.cpp9
-rw-r--r--Tests/QtAutogen/RccOnly/rccOnlyRes.qrc5
-rw-r--r--Tests/QtAutogen/RccSkipSource/CMakeLists.txt23
-rw-r--r--Tests/QtAutogen/RccSkipSource/skipRcc.cpp9
-rw-r--r--Tests/QtAutogen/RccSkipSource/skipRccBad1.qrc5
-rw-r--r--Tests/QtAutogen/RccSkipSource/skipRccBad2.qrc5
-rw-r--r--Tests/QtAutogen/RccSkipSource/skipRccGood.qrc6
-rw-r--r--Tests/QtAutogen/RerunMocBasic/CMakeLists.txt161
-rw-r--r--Tests/QtAutogen/RerunMocBasic/MocBasic/CMakeLists.txt29
-rw-r--r--Tests/QtAutogen/RerunMocBasic/MocBasic/input.txt1
-rw-r--r--Tests/QtAutogen/RerunMocBasic/MocBasic/main.cpp.in25
-rw-r--r--Tests/QtAutogen/RerunMocBasic/MocBasic/myobject3a.h.in13
-rw-r--r--Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.cpp12
-rw-r--r--Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.h12
-rw-r--r--Tests/QtAutogen/RerunMocBasic/MocBasic/res1.qrc5
-rw-r--r--Tests/QtAutogen/RerunMocBasic/MocBasic/test1a.h.in8
-rw-r--r--Tests/QtAutogen/RerunMocBasic/MocBasic/test1b.h.in7
-rw-r--r--Tests/QtAutogen/RerunMocBasic/MocBasic/test1c.h.in6
-rw-r--r--Tests/QtAutogen/RerunMocBasic/dummy.cpp5
-rw-r--r--Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt96
-rw-r--r--Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/CMakeLists.txt.in9
-rw-r--r--Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/anotherobject.cpp15
-rw-r--r--Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/main.cpp.in6
-rw-r--r--Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.cpp6
-rw-r--r--Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.h13
-rw-r--r--Tests/QtAutogen/RerunMocOnMissingDependency/CMakeLists.txt80
-rw-r--r--Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/CMakeLists.txt.in7
-rw-r--r--Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/inc1/foo.h2
-rw-r--r--Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/inc2/foo.h2
-rw-r--r--Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/main.cpp9
-rw-r--r--Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/myobject.cpp6
-rw-r--r--Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/myobject.h10
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/CMakeLists.txt134
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/CMakeLists.txt31
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.cpp6
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.hpp18
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.json1
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA_Custom.json1
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleB.cpp6
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleB.hpp18
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleC.cpp6
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleC.hpp18
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleD.cpp6
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleD.hpp18
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleE.cpp9
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleE.hpp10
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleEInclude.hpp18
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/UtilityMacros.hpp7
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleB.json1
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleB_Custom.json1
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleC.json1
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleD.json1
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleE.json1
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/MocPlugin/main.cpp6
-rw-r--r--Tests/QtAutogen/RerunMocPlugin/dummy.cpp5
-rw-r--r--Tests/QtAutogen/RerunRccConfigChange/CMakeLists.txt47
-rw-r--r--Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/CMakeLists.txt26
-rw-r--r--Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/main.cpp5
-rw-r--r--Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resGen.qrc.in6
-rw-r--r--Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resGen/input1.txt.in1
-rw-r--r--Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resGen/input2.txt.in1
-rw-r--r--Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resPlain.qrc6
-rw-r--r--Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resPlain/input1.txt1
-rw-r--r--Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resPlain/input2.txt1
-rw-r--r--Tests/QtAutogen/RerunRccConfigChange/dummy.cpp5
-rw-r--r--Tests/QtAutogen/RerunRccDepends/CMakeLists.txt153
-rw-r--r--Tests/QtAutogen/RerunRccDepends/RccDepends/CMakeLists.txt33
-rw-r--r--Tests/QtAutogen/RerunRccDepends/RccDepends/main.cpp5
-rw-r--r--Tests/QtAutogen/RerunRccDepends/RccDepends/resGen/input.txt.in1
-rw-r--r--Tests/QtAutogen/RerunRccDepends/RccDepends/resGen/inputAdded.txt.in1
-rw-r--r--Tests/QtAutogen/RerunRccDepends/RccDepends/resGenA.qrc.in5
-rw-r--r--Tests/QtAutogen/RerunRccDepends/RccDepends/resGenB.qrc.in6
-rw-r--r--Tests/QtAutogen/RerunRccDepends/RccDepends/resPlain/input.txt.in1
-rw-r--r--Tests/QtAutogen/RerunRccDepends/RccDepends/resPlain/inputAdded.txt.in1
-rw-r--r--Tests/QtAutogen/RerunRccDepends/RccDepends/resPlainA.qrc.in5
-rw-r--r--Tests/QtAutogen/RerunRccDepends/RccDepends/resPlainB.qrc.in6
-rw-r--r--Tests/QtAutogen/RerunRccDepends/dummy.cpp5
-rw-r--r--Tests/QtAutogen/RerunUicOnFileChange/CMakeLists.txt102
-rw-r--r--Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/CMakeLists.txt.in11
-rw-r--r--Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/main.cpp9
-rw-r--r--Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/mainwindow.ui.in7
-rw-r--r--Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/mocwidget.h5
-rw-r--r--Tests/QtAutogen/SameName/CMakeLists.txt48
-rw-r--r--Tests/QtAutogen/SameName/aaa/bbb/data.qrc6
-rw-r--r--Tests/QtAutogen/SameName/aaa/bbb/item.cpp22
-rw-r--r--Tests/QtAutogen/SameName/aaa/bbb/item.hpp18
-rw-r--r--Tests/QtAutogen/SameName/aaa/data.qrc6
-rw-r--r--Tests/QtAutogen/SameName/aaa/item.cpp22
-rw-r--r--Tests/QtAutogen/SameName/aaa/item.hpp18
-rw-r--r--Tests/QtAutogen/SameName/aaa/view.ui24
-rw-r--r--Tests/QtAutogen/SameName/bbb/aaa/data.qrc6
-rw-r--r--Tests/QtAutogen/SameName/bbb/aaa/item.cpp22
-rw-r--r--Tests/QtAutogen/SameName/bbb/aaa/item.hpp18
-rw-r--r--Tests/QtAutogen/SameName/bbb/data.qrc6
-rw-r--r--Tests/QtAutogen/SameName/bbb/item.cpp23
-rw-r--r--Tests/QtAutogen/SameName/bbb/item.hpp17
-rw-r--r--Tests/QtAutogen/SameName/bbb/view.ui24
-rw-r--r--Tests/QtAutogen/SameName/ccc/data.qrc6
-rw-r--r--Tests/QtAutogen/SameName/ccc/item.cpp25
-rw-r--r--Tests/QtAutogen/SameName/ccc/item.hpp18
-rw-r--r--Tests/QtAutogen/SameName/ccc/view.ui24
-rw-r--r--Tests/QtAutogen/SameName/data.qrc5
-rw-r--r--Tests/QtAutogen/SameName/item.cpp20
-rw-r--r--Tests/QtAutogen/SameName/item.hpp15
-rw-r--r--Tests/QtAutogen/SameName/main.cpp31
-rw-r--r--Tests/QtAutogen/SameName/object.h13
-rw-r--r--Tests/QtAutogen/SameName/object.h++13
-rw-r--r--Tests/QtAutogen/SameName/object.hh13
-rw-r--r--Tests/QtAutogen/SameName/object.hpp13
-rw-r--r--Tests/QtAutogen/SameName/object.hxx13
-rw-r--r--Tests/QtAutogen/SameName/object_upper_ext.H13
-rw-r--r--Tests/QtAutogen/SameName/view.ui24
-rw-r--r--Tests/QtAutogen/StaticLibraryCycle/CMakeLists.txt20
-rw-r--r--Tests/QtAutogen/StaticLibraryCycle/a.cpp13
-rw-r--r--Tests/QtAutogen/StaticLibraryCycle/a.h15
-rw-r--r--Tests/QtAutogen/StaticLibraryCycle/b.cpp8
-rw-r--r--Tests/QtAutogen/StaticLibraryCycle/b.h13
-rw-r--r--Tests/QtAutogen/StaticLibraryCycle/c.cpp8
-rw-r--r--Tests/QtAutogen/StaticLibraryCycle/c.h13
-rw-r--r--Tests/QtAutogen/StaticLibraryCycle/main.cpp8
-rw-r--r--Tests/QtAutogen/TestMacros.cmake70
-rw-r--r--Tests/QtAutogen/Tests.cmake55
-rw-r--r--Tests/QtAutogen/UicInclude/CMakeLists.txt11
-rw-r--r--Tests/QtAutogen/UicInclude/PageC.ui24
-rw-r--r--Tests/QtAutogen/UicInclude/PageC2.ui24
-rw-r--r--Tests/QtAutogen/UicInclude/dirA/PageA.ui24
-rw-r--r--Tests/QtAutogen/UicInclude/dirB/PageB.ui24
-rw-r--r--Tests/QtAutogen/UicInclude/dirB/PageB2.ui24
-rw-r--r--Tests/QtAutogen/UicInclude/dirB/subB/PageBsub.ui24
-rw-r--r--Tests/QtAutogen/UicInclude/main.cpp18
-rw-r--r--Tests/QtAutogen/UicInclude/main.hpp6
-rw-r--r--Tests/QtAutogen/UicInclude/subC/PageCsub.ui24
-rw-r--r--Tests/QtAutogen/UicInterface/CMakeLists.txt58
-rw-r--r--Tests/QtAutogen/UicInterface/klocalizedstring.cpp12
-rw-r--r--Tests/QtAutogen/UicInterface/klocalizedstring.h17
-rw-r--r--Tests/QtAutogen/UicInterface/libwidget.cpp14
-rw-r--r--Tests/QtAutogen/UicInterface/libwidget.h26
-rw-r--r--Tests/QtAutogen/UicInterface/libwidget.ui32
-rw-r--r--Tests/QtAutogen/UicInterface/main.cpp67
-rw-r--r--Tests/QtAutogen/UicInterface/mywidget.cpp14
-rw-r--r--Tests/QtAutogen/UicInterface/mywidget.h26
-rw-r--r--Tests/QtAutogen/UicInterface/mywidget.ui32
-rw-r--r--Tests/QtAutogen/UicNoGui/CMakeLists.txt16
-rw-r--r--Tests/QtAutogen/UicNoGui/MocOnly/CMakeLists.txt3
-rw-r--r--Tests/QtAutogen/UicNoGui/MocOnly/main.cpp15
-rw-r--r--Tests/QtAutogen/UicNoGui/NoQt/CMakeLists.txt2
-rw-r--r--Tests/QtAutogen/UicNoGui/NoQt/main.cpp4
-rw-r--r--Tests/QtAutogen/UicNoGui/main.cpp9
-rw-r--r--Tests/QtAutogen/UicOnly/CMakeLists.txt8
-rw-r--r--Tests/QtAutogen/UicOnly/UicOnly.cpp18
-rw-r--r--Tests/QtAutogen/UicOnly/UicOnly.hpp15
-rw-r--r--Tests/QtAutogen/UicOnly/main.cpp7
-rw-r--r--Tests/QtAutogen/UicOnly/uiA.ui24
-rw-r--r--Tests/QtAutogen/UicOnly/uiB.ui24
-rw-r--r--Tests/QtAutogen/UicOnly/uiC.ui24
-rw-r--r--Tests/QtAutogen/UicOnly/uiD.ui24
-rw-r--r--Tests/QtAutogen/UicSkipSource/CMakeLists.txt22
-rw-r--r--Tests/QtAutogen/UicSkipSource/skipUic.cpp22
-rw-r--r--Tests/QtAutogen/UicSkipSource/skipUicGen.cpp8
-rw-r--r--Tests/QtAutogen/UicSkipSource/skipUicGen.hpp8
-rw-r--r--Tests/QtAutogen/UicSkipSource/skipUicNoGen1.cpp8
-rw-r--r--Tests/QtAutogen/UicSkipSource/skipUicNoGen1.hpp8
-rw-r--r--Tests/QtAutogen/UicSkipSource/skipUicNoGen2.cpp8
-rw-r--r--Tests/QtAutogen/UicSkipSource/skipUicNoGen2.hpp8
-rw-r--r--Tests/QtAutogen/UicSkipSource/ui_nogen1.h6
-rw-r--r--Tests/QtAutogen/UicSkipSource/ui_nogen2.h6
-rw-r--r--Tests/QtAutogen/UicSkipSource/uigen1.ui24
-rw-r--r--Tests/QtAutogen/UicSkipSource/uigen2.ui24
-rw-r--r--Tests/QtAutogen/UnityMocSource/CMakeLists.txt12
-rw-r--r--Tests/QtAutogen/UnityMocSource/library.cpp6
-rw-r--r--Tests/QtAutogen/UnityMocSource/main.cpp4
-rw-r--r--Tests/QtAutomocNoQt/CMakeLists.txt7
-rw-r--r--Tests/QtAutomocNoQt/main.c4
-rw-r--r--Tests/README.rst31
-rw-r--r--Tests/ReturnTest/CMakeLists.txt147
-rw-r--r--Tests/ReturnTest/include_return.cmake3
-rw-r--r--Tests/ReturnTest/returnTest.c7
-rw-r--r--Tests/ReturnTest/subdir/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ABI/C-stdout.txt1
-rw-r--r--Tests/RunCMake/ABI/C.cmake22
-rw-r--r--Tests/RunCMake/ABI/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ABI/CUDA.cmake13
-rw-r--r--Tests/RunCMake/ABI/CXX-stdout.txt1
-rw-r--r--Tests/RunCMake/ABI/CXX.cmake22
-rw-r--r--Tests/RunCMake/ABI/OBJC.cmake13
-rw-r--r--Tests/RunCMake/ABI/OBJCXX.cmake13
-rw-r--r--Tests/RunCMake/ABI/RunCMakeTest.cmake15
-rw-r--r--Tests/RunCMake/ABI/TestBigEndian-NoLang-result.txt1
-rw-r--r--Tests/RunCMake/ABI/TestBigEndian-NoLang-stderr.txt8
-rw-r--r--Tests/RunCMake/ABI/TestBigEndian-NoLang.cmake2
-rw-r--r--Tests/RunCMake/Android/BadSYSROOT-result.txt1
-rw-r--r--Tests/RunCMake/Android/BadSYSROOT-stderr.txt20
-rw-r--r--Tests/RunCMake/Android/BadSYSROOT.cmake0
-rw-r--r--Tests/RunCMake/Android/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Android/RunCMakeTest.cmake285
-rw-r--r--Tests/RunCMake/Android/android.c6
-rw-r--r--Tests/RunCMake/Android/android.cxx48
-rw-r--r--Tests/RunCMake/Android/android.h103
-rw-r--r--Tests/RunCMake/Android/android_lib.cxx4
-rw-r--r--Tests/RunCMake/Android/android_sysinc.c7
-rw-r--r--Tests/RunCMake/Android/android_sysinc.cxx7
-rw-r--r--Tests/RunCMake/Android/check_binary.cmake8
-rw-r--r--Tests/RunCMake/Android/common.cmake140
-rw-r--r--Tests/RunCMake/Android/ndk-arm64-v8a-stderr.txt7
-rw-r--r--Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt2
-rw-r--r--Tests/RunCMake/Android/ndk-arm64-v8a.cmake1
-rw-r--r--Tests/RunCMake/Android/ndk-armeabi-arm-stderr.txt7
-rw-r--r--Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt3
-rw-r--r--Tests/RunCMake/Android/ndk-armeabi-arm.cmake1
-rw-r--r--Tests/RunCMake/Android/ndk-armeabi-thumb-stderr.txt7
-rw-r--r--Tests/RunCMake/Android/ndk-armeabi-thumb-stdout.txt3
-rw-r--r--Tests/RunCMake/Android/ndk-armeabi-thumb.cmake1
-rw-r--r--Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stderr.txt7
-rw-r--r--Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stdout.txt3
-rw-r--r--Tests/RunCMake/Android/ndk-armeabi-v7a-neon.cmake1
-rw-r--r--Tests/RunCMake/Android/ndk-armeabi-v7a-stderr.txt7
-rw-r--r--Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt3
-rw-r--r--Tests/RunCMake/Android/ndk-armeabi-v7a.cmake1
-rw-r--r--Tests/RunCMake/Android/ndk-badabi-result.txt1
-rw-r--r--Tests/RunCMake/Android/ndk-badabi-stderr.txt5
-rw-r--r--Tests/RunCMake/Android/ndk-badabi.cmake0
-rw-r--r--Tests/RunCMake/Android/ndk-badarm-result.txt1
-rw-r--r--Tests/RunCMake/Android/ndk-badarm-stderr.txt6
-rw-r--r--Tests/RunCMake/Android/ndk-badarm.cmake0
-rw-r--r--Tests/RunCMake/Android/ndk-badneon-result.txt1
-rw-r--r--Tests/RunCMake/Android/ndk-badneon-stderr.txt6
-rw-r--r--Tests/RunCMake/Android/ndk-badneon.cmake0
-rw-r--r--Tests/RunCMake/Android/ndk-badstl-result.txt1
-rw-r--r--Tests/RunCMake/Android/ndk-badstl-stderr.txt9
-rw-r--r--Tests/RunCMake/Android/ndk-badstl.cmake1
-rw-r--r--Tests/RunCMake/Android/ndk-badver-result.txt1
-rw-r--r--Tests/RunCMake/Android/ndk-badver-stderr.txt13
-rw-r--r--Tests/RunCMake/Android/ndk-badver.cmake1
-rw-r--r--Tests/RunCMake/Android/ndk-badvernum-result.txt1
-rw-r--r--Tests/RunCMake/Android/ndk-badvernum-stderr.txt15
-rw-r--r--Tests/RunCMake/Android/ndk-badvernum.cmake1
-rw-r--r--Tests/RunCMake/Android/ndk-mips-stdout.txt2
-rw-r--r--Tests/RunCMake/Android/ndk-mips.cmake1
-rw-r--r--Tests/RunCMake/Android/ndk-mips64-stdout.txt2
-rw-r--r--Tests/RunCMake/Android/ndk-mips64.cmake1
-rw-r--r--Tests/RunCMake/Android/ndk-search-order.cmake17
-rw-r--r--Tests/RunCMake/Android/ndk-sysroot-armeabi-stdout.txt1
-rw-r--r--Tests/RunCMake/Android/ndk-sysroot-armeabi.cmake0
-rw-r--r--Tests/RunCMake/Android/ndk-x86-stderr.txt7
-rw-r--r--Tests/RunCMake/Android/ndk-x86-stdout.txt2
-rw-r--r--Tests/RunCMake/Android/ndk-x86.cmake1
-rw-r--r--Tests/RunCMake/Android/ndk-x86_64-stderr.txt7
-rw-r--r--Tests/RunCMake/Android/ndk-x86_64-stdout.txt2
-rw-r--r--Tests/RunCMake/Android/ndk-x86_64.cmake1
-rw-r--r--Tests/RunCMake/Android/standalone-stdout.txt1
-rw-r--r--Tests/RunCMake/Android/standalone-sysroot-stdout.txt1
-rw-r--r--Tests/RunCMake/Android/standalone-sysroot.cmake0
-rw-r--r--Tests/RunCMake/Android/standalone.cmake1
-rw-r--r--Tests/RunCMake/Android/sysinc/dlfcn.h1
-rw-r--r--Tests/RunCMake/AndroidMK/AndroidMK-check.cmake30
-rw-r--r--Tests/RunCMake/AndroidMK/AndroidMK.cmake13
-rw-r--r--Tests/RunCMake/AndroidMK/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/AndroidMK/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/AndroidMK/bar.c3
-rw-r--r--Tests/RunCMake/AndroidMK/expectedBuildAndroidMK.txt34
-rw-r--r--Tests/RunCMake/AndroidMK/expectedInstallAndroidMK.txt36
-rw-r--r--Tests/RunCMake/AndroidMK/foo.cxx3
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/RunCMakeTest.cmake21
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/SetupTest1.cmake17
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/SetupTest1Build-check.cmake5
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/SetupTest2.cmake30
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/SetupTest2Build-check.cmake7
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/SetupTest3.cmake33
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/SetupTest3Build-check.cmake6
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/SetupTest4.cmake13
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/SetupTest4Build-check.cmake5
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/check.cmake20
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/data/a.txt1
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/data/proto.proto1
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/data/subfolder/b.txt1
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/data/subfolder/protobuffer.p1
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/libs/exampleLib.so1
-rw-r--r--Tests/RunCMake/AndroidTestUtilities/libs/exampleLib.txt1
-rw-r--r--Tests/RunCMake/AppleSilicon/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/AppleSilicon/RunCMakeTest.cmake27
-rw-r--r--Tests/RunCMake/AppleSilicon/arm64-common.cmake10
-rw-r--r--Tests/RunCMake/AppleSilicon/arm64-env.cmake1
-rw-r--r--Tests/RunCMake/AppleSilicon/arm64-var.cmake1
-rw-r--r--Tests/RunCMake/AppleSilicon/arm64.c9
-rw-r--r--Tests/RunCMake/AppleSilicon/default.c14
-rw-r--r--Tests/RunCMake/AppleSilicon/default.cmake15
-rw-r--r--Tests/RunCMake/AppleSilicon/x86_64-common.cmake10
-rw-r--r--Tests/RunCMake/AppleSilicon/x86_64-env.cmake1
-rw-r--r--Tests/RunCMake/AppleSilicon/x86_64-var.cmake1
-rw-r--r--Tests/RunCMake/AppleSilicon/x86_64.c9
-rw-r--r--Tests/RunCMake/ArtifactOutputDirs/ArtifactOutputDirs.cmake27
-rw-r--r--Tests/RunCMake/ArtifactOutputDirs/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ArtifactOutputDirs/RunCMakeTest.cmake19
-rw-r--r--Tests/RunCMake/ArtifactOutputDirs/check.cmake21
-rw-r--r--Tests/RunCMake/ArtifactOutputDirs/lib.c4
-rw-r--r--Tests/RunCMake/ArtifactOutputDirs/main.c4
-rw-r--r--Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-result.txt1
-rw-r--r--Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-stdout.txt1
-rw-r--r--Tests/RunCMake/AutoExportDll/AIXExportExplicit.cmake7
-rw-r--r--Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.c8
-rw-r--r--Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.exp1
-rw-r--r--Tests/RunCMake/AutoExportDll/AIXExportExplicitMain.c7
-rw-r--r--Tests/RunCMake/AutoExportDll/AutoExport.cmake25
-rw-r--r--Tests/RunCMake/AutoExportDll/AutoExportBuild-stderr.txt1
-rw-r--r--Tests/RunCMake/AutoExportDll/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake68
-rw-r--r--Tests/RunCMake/AutoExportDll/cppCLI.cxx22
-rw-r--r--Tests/RunCMake/AutoExportDll/foo.c15
-rw-r--r--Tests/RunCMake/AutoExportDll/hello.cxx14
-rw-r--r--Tests/RunCMake/AutoExportDll/hello.h18
-rw-r--r--Tests/RunCMake/AutoExportDll/hello2.c8
-rw-r--r--Tests/RunCMake/AutoExportDll/nop.asm12
-rw-r--r--Tests/RunCMake/AutoExportDll/objlib.c4
-rw-r--r--Tests/RunCMake/AutoExportDll/say.cxx57
-rw-r--r--Tests/RunCMake/AutoExportDll/sub/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/AutoExportDll/sub/sub.cxx6
-rw-r--r--Tests/RunCMake/AutoExportDll/world.cxx6
-rw-r--r--Tests/RunCMake/Autogen/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Autogen/NoQt-stderr.txt8
-rw-r--r--Tests/RunCMake/Autogen/NoQt.cmake6
-rw-r--r--Tests/RunCMake/Autogen/QtInFunction.cmake13
-rw-r--r--Tests/RunCMake/Autogen/QtInFunctionNested-stderr.txt8
-rw-r--r--Tests/RunCMake/Autogen/QtInFunctionNested.cmake17
-rw-r--r--Tests/RunCMake/Autogen/QtInFunctionProperty.cmake21
-rw-r--r--Tests/RunCMake/Autogen/RunCMakeTest.cmake8
-rw-r--r--Tests/RunCMake/Autogen/empty.cpp0
-rw-r--r--Tests/RunCMake/BuildDepends/BuildUnderSource.c5
-rw-r--r--Tests/RunCMake/BuildDepends/BuildUnderSource.cmake9
-rw-r--r--Tests/RunCMake/BuildDepends/BuildUnderSource.step1.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/BuildUnderSource.step2.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/C-Exe-Manifest.cmake19
-rw-r--r--Tests/RunCMake/BuildDepends/C-Exe-Manifest.step1.cmake6
-rw-r--r--Tests/RunCMake/BuildDepends/C-Exe-Manifest.step2.cmake6
-rw-r--r--Tests/RunCMake/BuildDepends/C-Exe.cmake12
-rw-r--r--Tests/RunCMake/BuildDepends/C-Exe.step1.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/C-Exe.step2.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/BuildDepends/CompilerDependencies.cmake46
-rw-r--r--Tests/RunCMake/BuildDepends/CompilerDependencies.step1.cmake9
-rw-r--r--Tests/RunCMake/BuildDepends/CompilerDependencies.step2.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/Custom-Always.cmake24
-rw-r--r--Tests/RunCMake/BuildDepends/Custom-Symbolic-and-Byproduct.cmake29
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-result.txt1
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs.cmake10
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDependencies.cmake73
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDependencies.step1.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDependencies.step2.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake61
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake10
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake6
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDepfile.step3.cmake1
-rw-r--r--Tests/RunCMake/BuildDepends/DepfileSubdir/CMakeLists.txt22
-rw-r--r--Tests/RunCMake/BuildDepends/ExternalProject/CMakeLists.txt14
-rw-r--r--Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs-build1-stdout.txt2
-rw-r--r--Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs-build2-stdout.txt2
-rw-r--r--Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs.cmake19
-rw-r--r--Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs.step1.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs.step2.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/GNU-AS-stdout.txt4
-rw-r--r--Tests/RunCMake/BuildDepends/GNU-AS.cmake14
-rw-r--r--Tests/RunCMake/BuildDepends/GNU-AS.step1.cmake1
-rw-r--r--Tests/RunCMake/BuildDepends/GNU-AS.step2.cmake1
-rw-r--r--Tests/RunCMake/BuildDepends/GenerateDepFile.cmake6
-rw-r--r--Tests/RunCMake/BuildDepends/MakeCustomIncludes.cmake13
-rw-r--r--Tests/RunCMake/BuildDepends/MakeCustomIncludes.cxx6
-rw-r--r--Tests/RunCMake/BuildDepends/MakeCustomIncludes.step1.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/MakeCustomIncludes.step2.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/MakeDependencies.cmake13
-rw-r--r--Tests/RunCMake/BuildDepends/MakeDependencies.step1.cmake18
-rw-r--r--Tests/RunCMake/BuildDepends/MakeDependencies.step2.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/MakeInProjectOnly.c5
-rw-r--r--Tests/RunCMake/BuildDepends/MakeInProjectOnly.cmake16
-rw-r--r--Tests/RunCMake/BuildDepends/MakeInProjectOnly.step1.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/MakeInProjectOnly.step2.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/RepeatCMake-Custom-Script.cmake4
-rw-r--r--Tests/RunCMake/BuildDepends/RepeatCMake-Custom.cmake5
-rw-r--r--Tests/RunCMake/BuildDepends/RunCMakeTest.cmake166
-rw-r--r--Tests/RunCMake/BuildDepends/WriteDepfile.cmake8
-rw-r--r--Tests/RunCMake/BuildDepends/check.cmake37
-rw-r--r--Tests/RunCMake/BuildDepends/gnu_as.s1
-rw-r--r--Tests/RunCMake/BuildDepends/main.c4
-rw-r--r--Tests/RunCMake/BundleUtilities/CMP0080-COMMAND-OLD-stderr.txt9
-rw-r--r--Tests/RunCMake/BundleUtilities/CMP0080-COMMAND.cmake5
-rw-r--r--Tests/RunCMake/BundleUtilities/CMP0080-NEW-result.txt1
-rw-r--r--Tests/RunCMake/BundleUtilities/CMP0080-NEW-stderr.txt2
-rw-r--r--Tests/RunCMake/BundleUtilities/CMP0080-NEW.cmake2
-rw-r--r--Tests/RunCMake/BundleUtilities/CMP0080-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/BundleUtilities/CMP0080-OLD.cmake2
-rw-r--r--Tests/RunCMake/BundleUtilities/CMP0080-WARN-stderr.txt10
-rw-r--r--Tests/RunCMake/BundleUtilities/CMP0080-WARN.cmake1
-rw-r--r--Tests/RunCMake/BundleUtilities/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/BundleUtilities/ExecutableScripts.cmake18
-rw-r--r--Tests/RunCMake/BundleUtilities/RunCMakeTest.cmake12
-rwxr-xr-xTests/RunCMake/BundleUtilities/test.app/script3
-rwxr-xr-xTests/RunCMake/BundleUtilities/test.app/script.bat3
-rwxr-xr-xTests/RunCMake/BundleUtilities/test.app/script.sh3
-rw-r--r--Tests/RunCMake/Byproducts/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Byproducts/CleanByproducts.cmake93
-rw-r--r--Tests/RunCMake/Byproducts/RunCMakeTest.cmake58
-rw-r--r--Tests/RunCMake/Byproducts/files.cmake.in2
-rw-r--r--Tests/RunCMake/Byproducts/foo.cpp14
-rw-r--r--Tests/RunCMake/CMP0004/CMP0004-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0004/CMP0004-NEW-stderr.txt2
-rw-r--r--Tests/RunCMake/CMP0004/CMP0004-NEW.cmake9
-rw-r--r--Tests/RunCMake/CMP0004/CMP0004-OLD-result.txt1
-rw-r--r--Tests/RunCMake/CMP0004/CMP0004-OLD-stderr.txt2
-rw-r--r--Tests/RunCMake/CMP0004/CMP0004-OLD.cmake21
-rw-r--r--Tests/RunCMake/CMP0004/CMP0004-WARN-stderr.txt0
-rw-r--r--Tests/RunCMake/CMP0004/CMP0004-policy-genex-result.txt1
-rw-r--r--Tests/RunCMake/CMP0004/CMP0004-policy-genex-stderr.txt2
-rw-r--r--Tests/RunCMake/CMP0004/CMP0004-policy-genex.cmake14
-rw-r--r--Tests/RunCMake/CMP0004/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0004/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0004/empty.cpp0
-rw-r--r--Tests/RunCMake/CMP0019/CMP0019-NEW-stderr.txt6
-rw-r--r--Tests/RunCMake/CMP0019/CMP0019-NEW.cmake2
-rw-r--r--Tests/RunCMake/CMP0019/CMP0019-OLD-stderr.txt17
-rw-r--r--Tests/RunCMake/CMP0019/CMP0019-OLD.cmake2
-rw-r--r--Tests/RunCMake/CMP0019/CMP0019-WARN-stderr.txt47
-rw-r--r--Tests/RunCMake/CMP0019/CMP0019-WARN.cmake1
-rw-r--r--Tests/RunCMake/CMP0019/CMP0019-code.cmake9
-rw-r--r--Tests/RunCMake/CMP0019/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0019/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-NOWARN-exe-stderr.txt6
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-NOWARN-exe.cmake7
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-NOWARN-shared-stderr.txt6
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-NOWARN-shared.cmake10
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-NEW-stderr.txt6
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-NEW.cmake14
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-link_libraries-stderr.txt6
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-link_libraries.cmake9
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-stderr.txt6
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-NOWARN-static.cmake8
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-WARN-empty-old-result.txt1
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-WARN-empty-old-stderr.txt26
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-WARN-empty-old.cmake10
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-WARN-static-result.txt1
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-WARN-static-stderr.txt19
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-WARN-static.cmake11
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-WARN-stderr.txt24
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-WARN-tll-result.txt1
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-WARN-tll-stderr.txt17
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-WARN-tll.cmake13
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-WARN.cmake18
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-export-exe-stderr.txt6
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-export-exe.cmake9
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-export-result.txt1
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-export-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-export.cmake11
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-install-export-result.txt1
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-install-export-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0022/CMP0022-install-export.cmake12
-rw-r--r--Tests/RunCMake/CMP0022/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0022/RunCMakeTest.cmake14
-rw-r--r--Tests/RunCMake/CMP0022/dep1/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/CMP0022/dep2/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/CMP0022/dep3/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/CMP0022/empty.cpp7
-rw-r--r--Tests/RunCMake/CMP0022/empty_vs6_1.cpp1
-rw-r--r--Tests/RunCMake/CMP0022/empty_vs6_2.cpp1
-rw-r--r--Tests/RunCMake/CMP0022/empty_vs6_3.cpp1
-rw-r--r--Tests/RunCMake/CMP0022/empty_vs6_4.cpp1
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-NEW-stderr.txt7
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-NEW.cmake7
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-OLD-result.txt1
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-OLD.cmake7
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-WARN-stderr.txt12
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-WARN.cmake5
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-IMPORTED-result.txt1
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-IMPORTED.cmake7
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-NEW-stderr.txt7
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-NEW.cmake7
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-OLD-result.txt1
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-OLD.cmake7
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-WARN-stderr.txt12
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-WARN.cmake5
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-NEW-stderr.txt7
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-NEW.cmake7
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-OLD.cmake12
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-WARN-Dir/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-WARN-stderr.txt25
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-WARN.cmake8
-rw-r--r--Tests/RunCMake/CMP0026/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0026/LOCATION-and-TARGET_OBJECTS-result.txt1
-rw-r--r--Tests/RunCMake/CMP0026/LOCATION-and-TARGET_OBJECTS-stderr.txt12
-rw-r--r--Tests/RunCMake/CMP0026/LOCATION-and-TARGET_OBJECTS.cmake6
-rw-r--r--Tests/RunCMake/CMP0026/ObjlibNotDefined-result.txt1
-rw-r--r--Tests/RunCMake/CMP0026/ObjlibNotDefined-stderr.txt12
-rw-r--r--Tests/RunCMake/CMP0026/ObjlibNotDefined.cmake13
-rw-r--r--Tests/RunCMake/CMP0026/RunCMakeTest.cmake15
-rw-r--r--Tests/RunCMake/CMP0026/clear-cached-information-dir/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/CMP0026/clear-cached-information-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0026/clear-cached-information.cmake14
-rw-r--r--Tests/RunCMake/CMP0026/empty.cpp7
-rw-r--r--Tests/RunCMake/CMP0027/CMP0027-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0027/CMP0027-NEW-stderr.txt13
-rw-r--r--Tests/RunCMake/CMP0027/CMP0027-NEW.cmake10
-rw-r--r--Tests/RunCMake/CMP0027/CMP0027-OLD-result.txt1
-rw-r--r--Tests/RunCMake/CMP0027/CMP0027-OLD-stderr.txt13
-rw-r--r--Tests/RunCMake/CMP0027/CMP0027-OLD.cmake10
-rw-r--r--Tests/RunCMake/CMP0027/CMP0027-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0027/CMP0027-WARN-stderr.txt18
-rw-r--r--Tests/RunCMake/CMP0027/CMP0027-WARN.cmake8
-rw-r--r--Tests/RunCMake/CMP0027/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0027/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0027/empty.cpp0
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-NEW-iface-result.txt1
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-NEW-iface-stderr.txt6
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-NEW-iface.cmake7
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-NEW-stderr.txt6
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-NEW.cmake5
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-OLD-iface-result.txt1
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-OLD-iface-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-OLD-iface.cmake7
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-OLD-result.txt1
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-OLD.cmake5
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-WARN-iface-result.txt1
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-WARN-iface-stderr.txt11
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-WARN-iface.cmake5
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-WARN-stderr.txt11
-rw-r--r--Tests/RunCMake/CMP0028/CMP0028-WARN.cmake3
-rw-r--r--Tests/RunCMake/CMP0028/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0028/RunCMakeTest.cmake8
-rw-r--r--Tests/RunCMake/CMP0028/empty.cpp0
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-NEW-colon-result.txt1
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-NEW-colon-stderr.txt20
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-NEW-colon.cmake6
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-NEW-reserved-result.txt1
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-NEW-reserved-stderr.txt18
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-NEW-reserved.cmake6
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-NEW-space-result.txt1
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-NEW-space-stderr.txt20
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-NEW-space.cmake6
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-OLD-reserved-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-OLD-reserved.cmake6
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-OLD-space-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-OLD-space.cmake6
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-WARN-colon-result.txt1
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-WARN-colon-stderr.txt38
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-WARN-colon.cmake4
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-WARN-reserved-stderr.txt36
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-WARN-reserved.cmake4
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-WARN-space-result.txt1
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-WARN-space-stderr.txt37
-rw-r--r--Tests/RunCMake/CMP0037/CMP0037-WARN-space.cmake4
-rw-r--r--Tests/RunCMake/CMP0037/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0037/NEW-cond-package-result.txt1
-rw-r--r--Tests/RunCMake/CMP0037/NEW-cond-package-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0037/NEW-cond-package.cmake5
-rw-r--r--Tests/RunCMake/CMP0037/NEW-cond-package_source-result.txt1
-rw-r--r--Tests/RunCMake/CMP0037/NEW-cond-package_source-stderr.txt5
-rw-r--r--Tests/RunCMake/CMP0037/NEW-cond-package_source.cmake5
-rw-r--r--Tests/RunCMake/CMP0037/NEW-cond-test-result.txt1
-rw-r--r--Tests/RunCMake/CMP0037/NEW-cond-test-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0037/NEW-cond-test.cmake5
-rw-r--r--Tests/RunCMake/CMP0037/NEW-cond.cmake4
-rw-r--r--Tests/RunCMake/CMP0037/OLD-cond-package-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0037/OLD-cond-package.cmake5
-rw-r--r--Tests/RunCMake/CMP0037/OLD-cond-package_source-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0037/OLD-cond-package_source.cmake5
-rw-r--r--Tests/RunCMake/CMP0037/OLD-cond-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0037/OLD-cond-test-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0037/OLD-cond-test.cmake5
-rw-r--r--Tests/RunCMake/CMP0037/OLD-cond.cmake5
-rw-r--r--Tests/RunCMake/CMP0037/RunCMakeTest.cmake51
-rw-r--r--Tests/RunCMake/CMP0037/WARN-cond-package-stderr.txt11
-rw-r--r--Tests/RunCMake/CMP0037/WARN-cond-package.cmake5
-rw-r--r--Tests/RunCMake/CMP0037/WARN-cond-package_source-stderr.txt11
-rw-r--r--Tests/RunCMake/CMP0037/WARN-cond-package_source.cmake5
-rw-r--r--Tests/RunCMake/CMP0037/WARN-cond-test-stderr.txt11
-rw-r--r--Tests/RunCMake/CMP0037/WARN-cond-test.cmake5
-rw-r--r--Tests/RunCMake/CMP0037/WARN-cond.cmake4
-rw-r--r--Tests/RunCMake/CMP0037/empty.cpp7
-rw-r--r--Tests/RunCMake/CMP0038/CMP0038-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0038/CMP0038-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0038/CMP0038-NEW.cmake4
-rw-r--r--Tests/RunCMake/CMP0038/CMP0038-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0038/CMP0038-OLD.cmake4
-rw-r--r--Tests/RunCMake/CMP0038/CMP0038-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0038/CMP0038-WARN-stderr.txt9
-rw-r--r--Tests/RunCMake/CMP0038/CMP0038-WARN.cmake3
-rw-r--r--Tests/RunCMake/CMP0038/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0038/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0038/empty.cpp7
-rw-r--r--Tests/RunCMake/CMP0039/CMP0039-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0039/CMP0039-NEW-stderr.txt5
-rw-r--r--Tests/RunCMake/CMP0039/CMP0039-NEW.cmake7
-rw-r--r--Tests/RunCMake/CMP0039/CMP0039-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0039/CMP0039-OLD.cmake7
-rw-r--r--Tests/RunCMake/CMP0039/CMP0039-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0039/CMP0039-WARN-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0039/CMP0039-WARN.cmake5
-rw-r--r--Tests/RunCMake/CMP0039/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0039/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0040/CMP0040-NEW-existing-target-result.txt1
-rw-r--r--Tests/RunCMake/CMP0040/CMP0040-NEW-existing-target.cmake7
-rw-r--r--Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target-result.txt1
-rw-r--r--Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target.cmake5
-rw-r--r--Tests/RunCMake/CMP0040/CMP0040-OLD-existing-target-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0040/CMP0040-OLD-existing-target.cmake7
-rw-r--r--Tests/RunCMake/CMP0040/CMP0040-OLD-missing-target-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0040/CMP0040-OLD-missing-target.cmake5
-rw-r--r--Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target-result.txt1
-rw-r--r--Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target.cmake4
-rw-r--r--Tests/RunCMake/CMP0040/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0040/RunCMakeTest.cmake8
-rw-r--r--Tests/RunCMake/CMP0040/empty.cpp7
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-NEW-stderr.txt20
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-NEW.cmake12
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-OLD.cmake12
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-WARN-stderr.txt32
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-WARN.cmake10
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-tid-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-tid-NEW-stderr.txt22
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-tid-NEW.cmake11
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-tid-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-tid-OLD.cmake11
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-tid-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-tid-WARN-stderr.txt34
-rw-r--r--Tests/RunCMake/CMP0041/CMP0041-tid-WARN.cmake9
-rw-r--r--Tests/RunCMake/CMP0041/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0041/RunCMakeTest.cmake15
-rw-r--r--Tests/RunCMake/CMP0041/empty.cpp7
-rw-r--r--Tests/RunCMake/CMP0042/CMP0042-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0042/CMP0042-NEW.cmake4
-rw-r--r--Tests/RunCMake/CMP0042/CMP0042-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0042/CMP0042-OLD.cmake4
-rw-r--r--Tests/RunCMake/CMP0042/CMP0042-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0042/CMP0042-WARN-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0042/CMP0042-WARN.cmake9
-rw-r--r--Tests/RunCMake/CMP0042/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0042/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0042/empty.cpp7
-rw-r--r--Tests/RunCMake/CMP0043/CMP0043-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0043/CMP0043-NEW.cmake7
-rw-r--r--Tests/RunCMake/CMP0043/CMP0043-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0043/CMP0043-OLD.cmake7
-rw-r--r--Tests/RunCMake/CMP0043/CMP0043-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0043/CMP0043-WARN-stderr.txt5
-rw-r--r--Tests/RunCMake/CMP0043/CMP0043-WARN.cmake5
-rw-r--r--Tests/RunCMake/CMP0043/CMakeLists.txt7
-rw-r--r--Tests/RunCMake/CMP0043/RunCMakeTest.cmake7
-rw-r--r--Tests/RunCMake/CMP0043/empty.cpp7
-rw-r--r--Tests/RunCMake/CMP0045/CMP0045-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0045/CMP0045-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0045/CMP0045-NEW.cmake4
-rw-r--r--Tests/RunCMake/CMP0045/CMP0045-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0045/CMP0045-OLD.cmake4
-rw-r--r--Tests/RunCMake/CMP0045/CMP0045-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0045/CMP0045-WARN-stderr.txt9
-rw-r--r--Tests/RunCMake/CMP0045/CMP0045-WARN.cmake2
-rw-r--r--Tests/RunCMake/CMP0045/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0045/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0045/empty.cpp7
-rw-r--r--Tests/RunCMake/CMP0046/CMP0046-Duplicate-result.txt1
-rw-r--r--Tests/RunCMake/CMP0046/CMP0046-Duplicate-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0046/CMP0046-Duplicate.cmake9
-rw-r--r--Tests/RunCMake/CMP0046/CMP0046-NEW-existing-dependency.cmake5
-rw-r--r--Tests/RunCMake/CMP0046/CMP0046-NEW-missing-dependency-result.txt1
-rw-r--r--Tests/RunCMake/CMP0046/CMP0046-NEW-missing-dependency-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0046/CMP0046-NEW-missing-dependency.cmake4
-rw-r--r--Tests/RunCMake/CMP0046/CMP0046-OLD-existing-dependency-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0046/CMP0046-OLD-existing-dependency.cmake5
-rw-r--r--Tests/RunCMake/CMP0046/CMP0046-OLD-missing-dependency-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0046/CMP0046-OLD-missing-dependency.cmake4
-rw-r--r--Tests/RunCMake/CMP0046/CMP0046-WARN-missing-dependency-stderr.txt9
-rw-r--r--Tests/RunCMake/CMP0046/CMP0046-WARN-missing-dependency.cmake2
-rw-r--r--Tests/RunCMake/CMP0046/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0046/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/CMP0046/empty.cpp7
-rw-r--r--Tests/RunCMake/CMP0049/CMP0049-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0049/CMP0049-NEW-stderr.txt6
-rw-r--r--Tests/RunCMake/CMP0049/CMP0049-NEW.cmake5
-rw-r--r--Tests/RunCMake/CMP0049/CMP0049-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0049/CMP0049-OLD.cmake5
-rw-r--r--Tests/RunCMake/CMP0049/CMP0049-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0049/CMP0049-WARN-stderr.txt11
-rw-r--r--Tests/RunCMake/CMP0049/CMP0049-WARN.cmake3
-rw-r--r--Tests/RunCMake/CMP0049/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0049/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0049/empty.cpp7
-rw-r--r--Tests/RunCMake/CMP0050/CMP0050-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0050/CMP0050-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0050/CMP0050-NEW.cmake13
-rw-r--r--Tests/RunCMake/CMP0050/CMP0050-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0050/CMP0050-OLD.cmake13
-rw-r--r--Tests/RunCMake/CMP0050/CMP0050-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0050/CMP0050-WARN-stderr.txt9
-rw-r--r--Tests/RunCMake/CMP0050/CMP0050-WARN.cmake11
-rw-r--r--Tests/RunCMake/CMP0050/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0050/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0050/empty.cpp10
-rw-r--r--Tests/RunCMake/CMP0050/input.h.in2
-rw-r--r--Tests/RunCMake/CMP0051/CMP0051-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0051/CMP0051-NEW-stderr.txt1
-rw-r--r--Tests/RunCMake/CMP0051/CMP0051-NEW.cmake10
-rw-r--r--Tests/RunCMake/CMP0051/CMP0051-OLD-stderr.txt12
-rw-r--r--Tests/RunCMake/CMP0051/CMP0051-OLD.cmake10
-rw-r--r--Tests/RunCMake/CMP0051/CMP0051-WARN-Dir/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/CMP0051/CMP0051-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0051/CMP0051-WARN-stderr.txt31
-rw-r--r--Tests/RunCMake/CMP0051/CMP0051-WARN.cmake14
-rw-r--r--Tests/RunCMake/CMP0051/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0051/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0051/empty.cpp7
-rw-r--r--Tests/RunCMake/CMP0053/CMP0053-NEW-stderr.txt2
-rw-r--r--Tests/RunCMake/CMP0053/CMP0053-NEW.cmake8
-rw-r--r--Tests/RunCMake/CMP0053/CMP0053-OLD-stderr.txt13
-rw-r--r--Tests/RunCMake/CMP0053/CMP0053-OLD.cmake8
-rw-r--r--Tests/RunCMake/CMP0053/CMP0053-WARN-stderr.txt2
-rw-r--r--Tests/RunCMake/CMP0053/CMP0053-WARN.cmake6
-rw-r--r--Tests/RunCMake/CMP0053/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0053/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-NEW-stderr.txt1
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-NEW.cmake47
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-OLD.cmake47
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-WARN-stderr.txt23
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-WARN.cmake7
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-duplicate-warnings-stderr.txt24
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-duplicate-warnings.cmake12
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-keywords-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-keywords-NEW-stderr.txt8
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-keywords-NEW.cmake25
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-keywords-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-keywords-OLD.cmake9
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-keywords-WARN-stderr.txt25
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-keywords-WARN.cmake5
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-policy-command-scope-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-policy-command-scope.cmake53
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-policy-foreach-scope-stderr.txt54
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-policy-foreach-scope.cmake49
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-policy-nested-if-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-policy-nested-if.cmake41
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-policy-while-scope-stderr.txt54
-rw-r--r--Tests/RunCMake/CMP0054/CMP0054-policy-while-scope.cmake65
-rw-r--r--Tests/RunCMake/CMP0054/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0054/RunCMakeTest.cmake13
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-NEW-Out-of-Scope-result.txt1
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-NEW-Out-of-Scope-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-NEW-Out-of-Scope.cmake4
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-NEW-Reject-Arguments-result.txt1
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-NEW-Reject-Arguments-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-NEW-Reject-Arguments.cmake6
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope-result.txt1
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope.cmake4
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments-result.txt1
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments.cmake6
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-WARN-Out-of-Scope-result.txt1
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-WARN-Out-of-Scope-stderr.txt9
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-WARN-Out-of-Scope.cmake2
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-WARN-Reject-Arguments-result.txt1
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-WARN-Reject-Arguments-stderr.txt9
-rw-r--r--Tests/RunCMake/CMP0055/CMP0055-WARN-Reject-Arguments.cmake4
-rw-r--r--Tests/RunCMake/CMP0055/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0055/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/CMP0057/CMP0057-NEW.cmake31
-rw-r--r--Tests/RunCMake/CMP0057/CMP0057-OLD-result.txt1
-rw-r--r--Tests/RunCMake/CMP0057/CMP0057-OLD-stderr.txt8
-rw-r--r--Tests/RunCMake/CMP0057/CMP0057-OLD.cmake7
-rw-r--r--Tests/RunCMake/CMP0057/CMP0057-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0057/CMP0057-WARN-stderr.txt19
-rw-r--r--Tests/RunCMake/CMP0057/CMP0057-WARN.cmake5
-rw-r--r--Tests/RunCMake/CMP0057/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0057/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0059/CMP0059-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0059/CMP0059-NEW-stderr.txt2
-rw-r--r--Tests/RunCMake/CMP0059/CMP0059-NEW.cmake17
-rw-r--r--Tests/RunCMake/CMP0059/CMP0059-OLD-result.txt1
-rw-r--r--Tests/RunCMake/CMP0059/CMP0059-OLD-stderr.txt2
-rw-r--r--Tests/RunCMake/CMP0059/CMP0059-OLD.cmake17
-rw-r--r--Tests/RunCMake/CMP0059/CMP0059-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0059/CMP0059-WARN-stderr.txt18
-rw-r--r--Tests/RunCMake/CMP0059/CMP0059-WARN.cmake17
-rw-r--r--Tests/RunCMake/CMP0059/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0059/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0060/CMP0060-Common.cmake36
-rw-r--r--Tests/RunCMake/CMP0060/CMP0060-NEW.cmake2
-rw-r--r--Tests/RunCMake/CMP0060/CMP0060-OLD-Build-result.txt1
-rw-r--r--Tests/RunCMake/CMP0060/CMP0060-OLD-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CMP0060/CMP0060-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0060/CMP0060-OLD.cmake2
-rw-r--r--Tests/RunCMake/CMP0060/CMP0060-WARN-OFF-Build-result.txt1
-rw-r--r--Tests/RunCMake/CMP0060/CMP0060-WARN-OFF-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CMP0060/CMP0060-WARN-OFF.cmake1
-rw-r--r--Tests/RunCMake/CMP0060/CMP0060-WARN-ON-Build-result.txt1
-rw-r--r--Tests/RunCMake/CMP0060/CMP0060-WARN-ON-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CMP0060/CMP0060-WARN-ON-stderr.txt16
-rw-r--r--Tests/RunCMake/CMP0060/CMP0060-WARN-ON.cmake2
-rw-r--r--Tests/RunCMake/CMP0060/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/CMP0060/RunCMakeTest.cmake19
-rw-r--r--Tests/RunCMake/CMP0060/cmp0060.c4
-rw-r--r--Tests/RunCMake/CMP0060/main.c5
-rw-r--r--Tests/RunCMake/CMP0064/CMP0064-NEW.cmake5
-rw-r--r--Tests/RunCMake/CMP0064/CMP0064-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0064/CMP0064-OLD.cmake7
-rw-r--r--Tests/RunCMake/CMP0064/CMP0064-WARN-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0064/CMP0064-WARN.cmake7
-rw-r--r--Tests/RunCMake/CMP0064/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0064/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0065/BuildTargetInSubProject.cmake15
-rw-r--r--Tests/RunCMake/CMP0065/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0065/NEWBad.cmake4
-rw-r--r--Tests/RunCMake/CMP0065/NEWGood.cmake4
-rw-r--r--Tests/RunCMake/CMP0065/OLDBad1.cmake4
-rw-r--r--Tests/RunCMake/CMP0065/OLDBad2.cmake4
-rw-r--r--Tests/RunCMake/CMP0065/RunCMakeTest.cmake11
-rw-r--r--Tests/RunCMake/CMP0065/WARN-OFF.cmake3
-rw-r--r--Tests/RunCMake/CMP0065/WARN-ON-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0065/WARN-ON.cmake3
-rw-r--r--Tests/RunCMake/CMP0065/subproject/CMakeLists.txt22
-rw-r--r--Tests/RunCMake/CMP0065/subproject/main.c7
-rw-r--r--Tests/RunCMake/CMP0068/CMP0068-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0068/CMP0068-NEW.cmake6
-rw-r--r--Tests/RunCMake/CMP0068/CMP0068-OLD-result.txt1
-rw-r--r--Tests/RunCMake/CMP0068/CMP0068-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0068/CMP0068-OLD.cmake6
-rw-r--r--Tests/RunCMake/CMP0068/CMP0068-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0068/CMP0068-WARN-stderr.txt12
-rw-r--r--Tests/RunCMake/CMP0068/CMP0068-WARN.cmake12
-rw-r--r--Tests/RunCMake/CMP0068/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0068/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0068/empty.cpp7
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-result.txt1
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-stderr.txt6
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-NEW-cmake.cmake6
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-result.txt1
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-stderr.txt6
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-NEW-compiler.cmake7
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-NEW-generator-result.txt1
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-NEW-generator-stderr.txt6
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-NEW-generator.cmake7
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-OLD.cmake4
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-WARN-stderr.txt9
-rw-r--r--Tests/RunCMake/CMP0069/CMP0069-WARN.cmake4
-rw-r--r--Tests/RunCMake/CMP0069/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0069/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/CMP0069/main.cpp3
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-Common.cmake5
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-NEW.cmake4
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-OLD.cmake4
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-WARN.cmake2
-rw-r--r--Tests/RunCMake/CMP0081/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0081/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0081/empty.cpp7
-rw-r--r--Tests/RunCMake/CMP0102/CMP0102-Common.cmake2
-rw-r--r--Tests/RunCMake/CMP0102/CMP0102-NEW.cmake13
-rw-r--r--Tests/RunCMake/CMP0102/CMP0102-OLD.cmake18
-rw-r--r--Tests/RunCMake/CMP0102/CMP0102-WARN-Default.cmake16
-rw-r--r--Tests/RunCMake/CMP0102/CMP0102-WARN-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0102/CMP0102-WARN.cmake18
-rw-r--r--Tests/RunCMake/CMP0102/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0102/RunCMakeTest.cmake6
-rw-r--r--Tests/RunCMake/CMP0104/CMP0104-Common.cmake6
-rw-r--r--Tests/RunCMake/CMP0104/CMP0104-NEW.cmake6
-rw-r--r--Tests/RunCMake/CMP0104/CMP0104-OFF.cmake3
-rw-r--r--Tests/RunCMake/CMP0104/CMP0104-OLD.cmake14
-rw-r--r--Tests/RunCMake/CMP0104/CMP0104-WARN-stderr.txt8
-rw-r--r--Tests/RunCMake/CMP0104/CMP0104-WARN.cmake2
-rw-r--r--Tests/RunCMake/CMP0104/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0104/RunCMakeTest.cmake6
-rw-r--r--Tests/RunCMake/CMP0104/main.cu3
-rw-r--r--Tests/RunCMake/CMP0104/main.cxx3
-rw-r--r--Tests/RunCMake/CMP0106/CMP0106-Common.cmake10
-rw-r--r--Tests/RunCMake/CMP0106/CMP0106-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0106/CMP0106-NEW-stderr.txt9
-rw-r--r--Tests/RunCMake/CMP0106/CMP0106-NEW.cmake4
-rw-r--r--Tests/RunCMake/CMP0106/CMP0106-OLD.cmake9
-rw-r--r--Tests/RunCMake/CMP0106/CMP0106-WARN-ParaView-stderr.txt8
-rw-r--r--Tests/RunCMake/CMP0106/CMP0106-WARN-ParaView.cmake2
-rw-r--r--Tests/RunCMake/CMP0106/CMP0106-WARN-VTK-stderr.txt9
-rw-r--r--Tests/RunCMake/CMP0106/CMP0106-WARN-VTK.cmake2
-rw-r--r--Tests/RunCMake/CMP0106/CMP0106-WARN-stderr.txt37
-rw-r--r--Tests/RunCMake/CMP0106/CMP0106-WARN.cmake2
-rw-r--r--Tests/RunCMake/CMP0106/CMakeLists.txt7
-rw-r--r--Tests/RunCMake/CMP0106/RunCMakeTest.cmake7
-rw-r--r--Tests/RunCMake/CMP0106/subdir/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/CMP0111/CMP0111-Common.cmake10
-rw-r--r--Tests/RunCMake/CMP0111/CMP0111-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0111/CMP0111-NEW-stderr.txt17
-rw-r--r--Tests/RunCMake/CMP0111/CMP0111-NEW.cmake2
-rw-r--r--Tests/RunCMake/CMP0111/CMP0111-OLD.cmake2
-rw-r--r--Tests/RunCMake/CMP0111/CMP0111-WARN-stderr.txt39
-rw-r--r--Tests/RunCMake/CMP0111/CMP0111-WARN.cmake1
-rw-r--r--Tests/RunCMake/CMP0111/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0111/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0111/module.cpp4
-rw-r--r--Tests/RunCMake/CMP0115/CMP0115-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0115/CMP0115-NEW-stderr.txt17
-rw-r--r--Tests/RunCMake/CMP0115/CMP0115-NEW.cmake1
-rw-r--r--Tests/RunCMake/CMP0115/CMP0115-OLD-result.txt1
-rw-r--r--Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt22
-rw-r--r--Tests/RunCMake/CMP0115/CMP0115-OLD.cmake1
-rw-r--r--Tests/RunCMake/CMP0115/CMP0115-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt36
-rw-r--r--Tests/RunCMake/CMP0115/CMP0115-WARN.cmake1
-rw-r--r--Tests/RunCMake/CMP0115/CMP0115.cmake3
-rw-r--r--Tests/RunCMake/CMP0115/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0115/RunCMakeTest.cmake12
-rw-r--r--Tests/RunCMake/CMP0115/main.c4
-rw-r--r--Tests/RunCMake/CMP0116/CMP0116-Mixed-stderr.txt17
-rw-r--r--Tests/RunCMake/CMP0116/CMP0116-Mixed.cmake18
-rw-r--r--Tests/RunCMake/CMP0116/CMP0116-NEW-NOWARN.cmake3
-rw-r--r--Tests/RunCMake/CMP0116/CMP0116-NEW-WARN.cmake3
-rw-r--r--Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN.cmake3
-rw-r--r--Tests/RunCMake/CMP0116/CMP0116-OLD-WARN.cmake3
-rw-r--r--Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN-stderr.txt7
-rw-r--r--Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN.cmake3
-rw-r--r--Tests/RunCMake/CMP0116/CMP0116-WARN-WARN-stderr.txt16
-rw-r--r--Tests/RunCMake/CMP0116/CMP0116-WARN-WARN.cmake3
-rw-r--r--Tests/RunCMake/CMP0116/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0116/Common.cmake8
-rw-r--r--Tests/RunCMake/CMP0116/RunCMakeTest.cmake52
-rw-r--r--Tests/RunCMake/CMP0116/Subdirectory/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/CMP0116/WriteDepfile.cmake3
-rw-r--r--Tests/RunCMake/CMP0116/check.cmake18
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Helper.cmake14
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test1.cmake9
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test10.cmake65
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test11.cmake65
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test12.cmake65
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test13.cmake65
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test14.cmake65
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test15.cmake65
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test2.cmake12
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test3.cmake66
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test3b.cmake66
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test4.cmake66
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test4b.cmake66
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test5.cmake78
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test6.cmake44
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test7.cmake44
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test8.cmake50
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-Common-Test9.cmake50
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test1-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test1-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test1.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test10-stderr.txt42
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test10.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test11-stderr.txt55
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test11.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test12-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test12-stderr.txt51
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test12.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test13-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test13-stderr.txt64
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test13.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test14-stderr.txt42
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test14.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test15-stderr.txt55
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test15.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test2-stderr.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test2.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test3-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test3-stderr.txt87
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test3.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b-stderr.txt87
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test4-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test4-stderr.txt167
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test4.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b-stderr.txt167
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test5-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test5-stderr.txt174
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test5.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test6-stderr.txt36
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test6.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-stderr.txt74
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test7.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test8-stderr.txt36
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test8.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-stderr.txt74
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-NEW-Test9.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test1.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-stderr.txt51
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test10.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-stderr.txt67
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test11.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-stderr.txt51
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test12.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-stderr.txt51
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test13.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-stderr.txt51
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test14.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-stderr.txt67
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test15.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test2-stderr.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test2.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-stderr.txt87
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test3.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-stderr.txt87
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-stderr.txt95
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test4.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-stderr.txt95
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-stderr.txt111
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test5.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-stderr.txt45
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test6.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-stderr.txt77
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test7.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-stderr.txt45
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test8.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-stderr.txt61
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-OLD-Test9.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test1.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-stderr.txt51
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test10.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-stderr.txt90
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test11.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test12-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test12-stderr.txt51
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test12.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test13-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test13-stderr.txt74
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test13.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-stderr.txt51
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test14.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-stderr.txt90
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test15.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test2-stderr.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test2.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test3-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test3-stderr.txt87
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test3.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b-stderr.txt87
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test4-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test4-stderr.txt212
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test4.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b-stderr.txt212
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test5-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test5-stderr.txt213
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test5.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-stderr.txt45
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test6.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-stderr.txt100
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test7.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-stderr.txt45
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test8.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-stderr.txt84
-rw-r--r--Tests/RunCMake/CMP0118/CMP0118-WARN-Test9.cmake1
-rw-r--r--Tests/RunCMake/CMP0118/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/CMP0118/GenInSubdir-Common.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/GenInSubdir-NEW.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/GenInSubdir-OLD-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/GenInSubdir-OLD-stderr.txt8
-rw-r--r--Tests/RunCMake/CMP0118/GenInSubdir-OLD.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/GenInSubdir-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0118/GenInSubdir-WARN-stderr.txt8
-rw-r--r--Tests/RunCMake/CMP0118/GenInSubdir-WARN.cmake2
-rw-r--r--Tests/RunCMake/CMP0118/GenInSubdir/CMakeLists.txt9
-rw-r--r--Tests/RunCMake/CMP0118/RunCMakeTest.cmake59
-rw-r--r--Tests/RunCMake/CMP0118/source.cpp.in5
-rw-r--r--Tests/RunCMake/CMP0118/subdir-Common-Test10/CMakeLists.txt33
-rw-r--r--Tests/RunCMake/CMP0118/subdir-Common-Test11/CMakeLists.txt33
-rw-r--r--Tests/RunCMake/CMP0118/subdir-Common-Test12/CMakeLists.txt33
-rw-r--r--Tests/RunCMake/CMP0118/subdir-Common-Test13/CMakeLists.txt33
-rw-r--r--Tests/RunCMake/CMP0118/subdir-Common-Test14/CMakeLists.txt33
-rw-r--r--Tests/RunCMake/CMP0118/subdir-Common-Test15/CMakeLists.txt33
-rw-r--r--Tests/RunCMake/CMP0118/subdir-Common-Test6/CMakeLists.txt16
-rw-r--r--Tests/RunCMake/CMP0118/subdir-Common-Test7/CMakeLists.txt16
-rw-r--r--Tests/RunCMake/CMP0118/subdir-Common-Test8/CMakeLists.txt30
-rw-r--r--Tests/RunCMake/CMP0118/subdir-Common-Test9/CMakeLists.txt30
-rw-r--r--Tests/RunCMake/CMP0119/AltExtC.zzz4
-rw-r--r--Tests/RunCMake/CMP0119/AltExtCXX.zzz3
-rw-r--r--Tests/RunCMake/CMP0119/CMP0119-Common.cmake4
-rw-r--r--Tests/RunCMake/CMP0119/CMP0119-NEW.cmake6
-rw-r--r--Tests/RunCMake/CMP0119/CMP0119-OLD-build-result.txt1
-rw-r--r--Tests/RunCMake/CMP0119/CMP0119-OLD-build-stderr.txt1
-rw-r--r--Tests/RunCMake/CMP0119/CMP0119-OLD.cmake2
-rw-r--r--Tests/RunCMake/CMP0119/CMP0119-WARN-build-result.txt1
-rw-r--r--Tests/RunCMake/CMP0119/CMP0119-WARN-build-stderr.txt1
-rw-r--r--Tests/RunCMake/CMP0119/CMP0119-WARN.cmake2
-rw-r--r--Tests/RunCMake/CMP0119/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0119/RunCMakeTest.cmake17
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-ERANGE-Common.cmake8
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW-stderr.txt8
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-result.txt1
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-stderr.txt8
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt18
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-GET-Common.cmake4
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-GET-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-GET-NEW-stderr.txt8
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-GET-NEW.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-GET-OLD-stderr.txt1
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-GET-OLD.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-GET-WARN-stderr.txt11
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-GET-WARN.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-INSERT-Common.cmake4
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW-stderr.txt8
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-INSERT-OLD-stderr.txt1
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-INSERT-OLD.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-INSERT-WARN-stderr.txt11
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-INSERT-WARN.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-Common.cmake4
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW-stderr.txt8
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-OLD-stderr.txt1
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-OLD.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-WARN-stderr.txt11
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-WARN.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-Common.cmake4
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW-stderr.txt8
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-OLD-stderr.txt1
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-OLD.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-WARN-stderr.txt11
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-WARN.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-Common.cmake4
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW-stderr.txt8
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-OLD-stderr.txt1
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-OLD.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-WARN-stderr.txt11
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-WARN.cmake2
-rw-r--r--Tests/RunCMake/CMP0121/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0121/RunCMakeTest.cmake7
-rw-r--r--Tests/RunCMake/CMakeLists.txt837
-rw-r--r--Tests/RunCMake/CMakePresets/ArchToolsetStrategyDefault-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/ArchToolsetStrategyDefault-stderr.txt11
-rw-r--r--Tests/RunCMake/CMakePresets/ArchToolsetStrategyIgnore.cmake0
-rw-r--r--Tests/RunCMake/CMakePresets/ArchToolsetStrategyNone-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/ArchToolsetStrategyNone-stderr.txt11
-rw-r--r--Tests/RunCMake/CMakePresets/CMakeLists.txt.in4
-rw-r--r--Tests/RunCMake/CMakePresets/CMakePresets.json.in506
-rw-r--r--Tests/RunCMake/CMakePresets/CacheOverride.cmake2
-rw-r--r--Tests/RunCMake/CMakePresets/Comment-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/Comment-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/Comment.json.in11
-rw-r--r--Tests/RunCMake/CMakePresets/ConditionFuture-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/ConditionFuture-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/ConditionFuture.json.in11
-rw-r--r--Tests/RunCMake/CMakePresets/Conditions.json.in406
-rw-r--r--Tests/RunCMake/CMakePresets/CyclicInheritance0-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/CyclicInheritance0-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/CyclicInheritance0.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/CyclicInheritance1-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/CyclicInheritance1-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/CyclicInheritance1.json.in21
-rw-r--r--Tests/RunCMake/CMakePresets/CyclicInheritance2-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/CyclicInheritance2-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/CyclicInheritance2.json.in29
-rw-r--r--Tests/RunCMake/CMakePresets/Debug-stderr.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/Debug-stdout.txt4
-rw-r--r--Tests/RunCMake/CMakePresets/Debug.cmake4
-rw-r--r--Tests/RunCMake/CMakePresets/Debug.json.in19
-rw-r--r--Tests/RunCMake/CMakePresets/DebugBase.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/DisableWarningFlags.cmake1
-rw-r--r--Tests/RunCMake/CMakePresets/DocumentationExample.cmake5
-rw-r--r--Tests/RunCMake/CMakePresets/DuplicatePresets-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/DuplicatePresets-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/DuplicatePresets.json.in15
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyCacheKey-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyCacheKey-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyCacheKey.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyEnv-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyEnv-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyEnv.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyEnvKey-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyEnvKey-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyEnvKey.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyPenv-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyPenv-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyPenv.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyPresetName-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyPresetName-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/EmptyPresetName.json.in10
-rw-r--r--Tests/RunCMake/CMakePresets/EnvCycle-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/EnvCycle-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/EnvCycle.json.in14
-rw-r--r--Tests/RunCMake/CMakePresets/ErrorDeprecated-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/ErrorDeprecated-stderr.txt7
-rw-r--r--Tests/RunCMake/CMakePresets/ErrorDeprecated.cmake1
-rw-r--r--Tests/RunCMake/CMakePresets/ErrorDev-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/ErrorDev-stderr.txt8
-rw-r--r--Tests/RunCMake/CMakePresets/ErrorDev.cmake1
-rw-r--r--Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated.json.in16
-rw-r--r--Tests/RunCMake/CMakePresets/ErrorNoWarningDev-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/ErrorNoWarningDev-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/ErrorNoWarningDev.json.in16
-rw-r--r--Tests/RunCMake/CMakePresets/ExtraPresetField-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/ExtraPresetField-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/ExtraPresetField.json.in11
-rw-r--r--Tests/RunCMake/CMakePresets/ExtraRootField-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/ExtraRootField-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/ExtraRootField.json.in11
-rw-r--r--Tests/RunCMake/CMakePresets/ExtraVariableField-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/ExtraVariableField-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/ExtraVariableField.json.in16
-rw-r--r--Tests/RunCMake/CMakePresets/FuturePresetInstallDirField-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/FuturePresetInstallDirField-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/FuturePresetInstallDirField.json.in11
-rw-r--r--Tests/RunCMake/CMakePresets/Good-stdout.txt53
-rw-r--r--Tests/RunCMake/CMakePresets/Good.cmake52
-rw-r--r--Tests/RunCMake/CMakePresets/GoodBOM.cmake0
-rw-r--r--Tests/RunCMake/CMakePresets/GoodBOM.json.in10
-rw-r--r--Tests/RunCMake/CMakePresets/GoodBinaryCmdLine.cmake4
-rw-r--r--Tests/RunCMake/CMakePresets/GoodBinaryRelative.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/GoodBinaryUp.cmake4
-rw-r--r--Tests/RunCMake/CMakePresets/GoodGeneratorCmdLine.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/GoodInheritanceChild.cmake6
-rw-r--r--Tests/RunCMake/CMakePresets/GoodInheritanceMacro.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/GoodInheritanceMulti.cmake10
-rw-r--r--Tests/RunCMake/CMakePresets/GoodInheritanceMultiSecond.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/GoodInheritanceOverride.cmake18
-rw-r--r--Tests/RunCMake/CMakePresets/GoodInheritanceParent.cmake6
-rw-r--r--Tests/RunCMake/CMakePresets/GoodInstall.json.in30
-rw-r--r--Tests/RunCMake/CMakePresets/GoodInstallCommandLine.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/GoodInstallDefault.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/GoodInstallInherit.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/GoodInstallOverride.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/GoodNoArgs.cmake0
-rw-r--r--Tests/RunCMake/CMakePresets/GoodNoS.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/GoodNoSCache.cmake4
-rw-r--r--Tests/RunCMake/CMakePresets/GoodNoSCachePrep.cmake4
-rw-r--r--Tests/RunCMake/CMakePresets/GoodNoSourceArg.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/GoodSpaces-stdout.txt3
-rw-r--r--Tests/RunCMake/CMakePresets/GoodSpaces.cmake0
-rw-r--r--Tests/RunCMake/CMakePresets/GoodSpacesEq-stdout.txt3
-rw-r--r--Tests/RunCMake/CMakePresets/GoodSpacesEq.cmake0
-rw-r--r--Tests/RunCMake/CMakePresets/GoodUserFromMain.cmake0
-rw-r--r--Tests/RunCMake/CMakePresets/GoodUserFromMain.json.in10
-rw-r--r--Tests/RunCMake/CMakePresets/GoodUserFromMainUser.json.in4
-rw-r--r--Tests/RunCMake/CMakePresets/GoodUserFromUser.cmake0
-rw-r--r--Tests/RunCMake/CMakePresets/GoodUserFromUser.json.in4
-rw-r--r--Tests/RunCMake/CMakePresets/GoodUserFromUserUser.json.in10
-rw-r--r--Tests/RunCMake/CMakePresets/GoodUserOnly.cmake0
-rw-r--r--Tests/RunCMake/CMakePresets/GoodUserOnlyUser.json.in10
-rw-r--r--Tests/RunCMake/CMakePresets/GoodWindowsBackslash.cmake0
-rw-r--r--Tests/RunCMake/CMakePresets/HighVersion-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/HighVersion-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/HighVersion.json.in4
-rw-r--r--Tests/RunCMake/CMakePresets/HostSystemName.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/HostSystemName.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/HostSystemNameFuture-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/HostSystemNameFuture-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/HostSystemNameFuture.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidGenerator-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidGenerator-stderr.txt3
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidGeneratorCmdLine-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidGeneratorCmdLine-stderr.txt3
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidInheritance-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidInheritance-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidInheritance.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresetBinaryDir-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresetBinaryDir-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresetBinaryDir.json.in10
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresetGenerator-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresetGenerator-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresetGenerator.json.in10
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresetName-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresetName-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresetName.json.in10
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresetVendor-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresetVendor-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresetVendor.json.in11
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresets-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresets-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidPresets.json.in4
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidRegex-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidRegex-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidRegex.json.in15
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidRoot-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidRoot-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidRoot.json.in1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidToolsetStrategy-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidToolsetStrategy-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidToolsetStrategy.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidVariableValue-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidVariableValue-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidVariableValue.json.in15
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidVariables-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidVariables-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidVariables.json.in11
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidVendor-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidVendor-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidVendor.json.in5
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidVersion-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidVersion-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/InvalidVersion.json.in4
-rw-r--r--Tests/RunCMake/CMakePresets/JSONParseError-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/JSONParseError-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/JSONParseError.json.in0
-rw-r--r--Tests/RunCMake/CMakePresets/ListConditions-stdout.txt26
-rw-r--r--Tests/RunCMake/CMakePresets/ListPresets-stdout.txt6
-rw-r--r--Tests/RunCMake/CMakePresets/ListPresets.json.in36
-rw-r--r--Tests/RunCMake/CMakePresets/ListPresetsHidden-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/ListPresetsHidden-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/ListPresetsHidden-stdout.txt6
-rw-r--r--Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset-stdout.txt6
-rw-r--r--Tests/RunCMake/CMakePresets/ListPresetsWorkingDir-stdout.txt6
-rw-r--r--Tests/RunCMake/CMakePresets/LowVersion-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/LowVersion-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/LowVersion.json.in4
-rw-r--r--Tests/RunCMake/CMakePresets/MinimumRequiredEmpty.cmake0
-rw-r--r--Tests/RunCMake/CMakePresets/MinimumRequiredEmpty.json.in11
-rw-r--r--Tests/RunCMake/CMakePresets/MinimumRequiredInvalid-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/MinimumRequiredInvalid-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/MinimumRequiredInvalid.json.in11
-rw-r--r--Tests/RunCMake/CMakePresets/MinimumRequiredMajor-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/MinimumRequiredMajor-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/MinimumRequiredMajor.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/MinimumRequiredMinor-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/MinimumRequiredMinor-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/MinimumRequiredMinor.json.in14
-rw-r--r--Tests/RunCMake/CMakePresets/MinimumRequiredPatch-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/MinimumRequiredPatch-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/MinimumRequiredPatch.json.in15
-rw-r--r--Tests/RunCMake/CMakePresets/NoCMakePresets-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/NoCMakePresets-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/NoDebug-stdout.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/NoDebug.cmake4
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresetArgument-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresetArgument-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresetArgumentEq-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresetArgumentEq-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresetBinaryDir-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresetBinaryDir-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresetBinaryDir.json.in9
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresetGenerator-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresetGenerator-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresetGenerator.json.in9
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresetName-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresetName-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresetName.json.in9
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresets-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresets-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresets-stdout.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/NoPresets.json.in3
-rw-r--r--Tests/RunCMake/CMakePresets/NoSuchMacro-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/NoSuchMacro-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/NoSuchMacro.json.in10
-rw-r--r--Tests/RunCMake/CMakePresets/NoSuchPreset-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/NoSuchPreset-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/NoVariableValue-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/NoVariableValue-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/NoVariableValue.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/NoVersion-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/NoVersion-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/NoVersion.json.in3
-rw-r--r--Tests/RunCMake/CMakePresets/NoWarningFlags-stderr.txt23
-rw-r--r--Tests/RunCMake/CMakePresets/NoWarningFlags.cmake1
-rw-r--r--Tests/RunCMake/CMakePresets/OptionalBinaryDirField.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/OptionalBinaryDirField.json.in9
-rw-r--r--Tests/RunCMake/CMakePresets/OptionalGeneratorField.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/OptionalGeneratorField.json.in9
-rw-r--r--Tests/RunCMake/CMakePresets/PresetNotObject-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/PresetNotObject-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/PresetNotObject.json.in6
-rw-r--r--Tests/RunCMake/CMakePresets/RunCMakeTest.cmake289
-rw-r--r--Tests/RunCMake/CMakePresets/SimpleFalse-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/SimpleFalse-stderr.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/SimpleTrue.cmake0
-rw-r--r--Tests/RunCMake/CMakePresets/SubConditionNull-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/SubConditionNull-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/SubConditionNull.json.in14
-rw-r--r--Tests/RunCMake/CMakePresets/TestVariable.cmake25
-rw-r--r--Tests/RunCMake/CMakePresets/UnclosedMacro-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/UnclosedMacro-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/UnclosedMacro.json.in10
-rw-r--r--Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/UnknownToolsetStrategy-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/UnknownToolsetStrategy-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/UnknownToolsetStrategy.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/UseHiddenPreset-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/UseHiddenPreset-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/UserDuplicateCross-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/UserDuplicateCross-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/UserDuplicateCross.json.in10
-rw-r--r--Tests/RunCMake/CMakePresets/UserDuplicateCrossUser.json.in10
-rw-r--r--Tests/RunCMake/CMakePresets/UserDuplicateInUser-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/UserDuplicateInUser-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/UserDuplicateInUserUser.json.in15
-rw-r--r--Tests/RunCMake/CMakePresets/UserInheritance-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/UserInheritance-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/UserInheritance.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/UserInheritanceUser.json.in10
-rw-r--r--Tests/RunCMake/CMakePresets/VariableNotObject-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/VariableNotObject-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresets/VariableNotObject.json.in13
-rw-r--r--Tests/RunCMake/CMakePresets/VendorMacro-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/VendorMacro-stderr.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/VisualStudioGeneratorArch-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresets/VisualStudioGeneratorArch-stderr.txt5
-rw-r--r--Tests/RunCMake/CMakePresets/VisualStudioInheritanceChild.cmake4
-rw-r--r--Tests/RunCMake/CMakePresets/VisualStudioInheritanceMulti.cmake4
-rw-r--r--Tests/RunCMake/CMakePresets/VisualStudioInheritanceMultiSecond.cmake4
-rw-r--r--Tests/RunCMake/CMakePresets/VisualStudioInheritanceOverride.cmake4
-rw-r--r--Tests/RunCMake/CMakePresets/VisualStudioInheritanceParent.cmake4
-rw-r--r--Tests/RunCMake/CMakePresets/VisualStudioToolset.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/VisualStudioToolsetOverride.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/VisualStudioWin32.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/VisualStudioWin32Override.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/VisualStudioWin64.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/WarningFlags-stderr.txt34
-rw-r--r--Tests/RunCMake/CMakePresets/WarningFlags.cmake1
-rw-r--r--Tests/RunCMake/CMakePresets/Warnings.json.in50
-rw-r--r--Tests/RunCMake/CMakePresets/WarningsBase.cmake3
-rw-r--r--Tests/RunCMake/CMakePresets/check.cmake15
-rw-r--r--Tests/RunCMake/CMakePresets/main.c4
-rw-r--r--Tests/RunCMake/CMakePresets/validate_schema.cmake19
-rw-r--r--Tests/RunCMake/CMakePresets/validate_schema.py16
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/CMakeLists.txt.in3
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Condition.cmake0
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Condition.json.in22
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/ConditionFuture.json.in17
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Good-build-build-other-check.cmake5
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Good-build-macros-check.cmake14
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Good-build-noEnvironment-check.cmake6
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Good-build-withEnvironment-check.cmake8
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Good.cmake3
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Good.json.in78
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Invalid-build-badConfigurePreset-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Invalid-build-badConfigurePreset-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Invalid-build-hidden-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Invalid-build-hidden-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Invalid-build-vendorMacro-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Invalid-build-vendorMacro-stderr.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Invalid.cmake0
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Invalid.json.in23
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-build-badConfigurePreset-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-build-badConfigurePreset-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-configure-default-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-configure-default-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset.cmake0
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset.json.in16
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt6
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/ListPresets.cmake0
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in41
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset.cmake0
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset.json.in15
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported-build-x-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported-build-x-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported.json.in7
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake78
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/TestVariable.cmake14
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/check.cmake3
-rw-r--r--Tests/RunCMake/CMakePresetsTest/CMakeLists.txt.in3
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Condition.json.in22
-rw-r--r--Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsTest/ConditionFuture.json.in17
-rw-r--r--Tests/RunCMake/CMakePresetsTest/ConditionListPresets-test-x-stdout.txt3
-rw-r--r--Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsTest/ConditionRunTests.cmake2
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Good-indexFile.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Good-test-config-debug-stdout.txt5
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Good-test-config-release-stdout.txt5
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Good-test-exclude-stdout.txt7
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Good-test-index-stdout.txt7
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Good-test-indexFile-stdout.txt7
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Good-test-noEnvironment-stdout.txt8
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Good-test-showOnly-stdout.txt8
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Good-withEnvironment-check.cmake8
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Good.cmake27
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Good.json.in175
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Invalid-test-badConfigurePreset-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Invalid-test-badConfigurePreset-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Invalid-test-hidden-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Invalid-test-hidden-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Invalid-test-vendorMacro-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Invalid-test-vendorMacro-stderr.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Invalid.cmake0
-rw-r--r--Tests/RunCMake/CMakePresetsTest/Invalid.json.in23
-rw-r--r--Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-configure-default-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-configure-default-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-test-badConfigurePreset-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-test-badConfigurePreset-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset.cmake0
-rw-r--r--Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset.json.in16
-rw-r--r--Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt12
-rw-r--r--Tests/RunCMake/CMakePresetsTest/ListPresets.cmake0
-rw-r--r--Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsTest/NoConfigurePreset.cmake0
-rw-r--r--Tests/RunCMake/CMakePresetsTest/NoConfigurePreset.json.in15
-rw-r--r--Tests/RunCMake/CMakePresetsTest/NoTestsAction-test-noTestsAction-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsTest/NoTestsAction-test-noTestsAction-stderr.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsTest/NoTestsAction.cmake0
-rw-r--r--Tests/RunCMake/CMakePresetsTest/NoTestsAction.json.in19
-rw-r--r--Tests/RunCMake/CMakePresetsTest/PresetsUnsupported-test-x-result.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsTest/PresetsUnsupported-test-x-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakePresetsTest/PresetsUnsupported.json.in7
-rw-r--r--Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake111
-rw-r--r--Tests/RunCMake/CMakePresetsTest/check.cmake3
-rw-r--r--Tests/RunCMake/CMakeRelease/FileTable-stdout.txt44
-rw-r--r--Tests/RunCMake/CMakeRelease/FileTable.cmake21
-rw-r--r--Tests/RunCMake/CMakeRelease/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/CMakeRoleGlobalProperty/BuildAndTest/CMakeLists.txt10
-rw-r--r--Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt.in4
-rw-r--r--Tests/RunCMake/CMakeRoleGlobalProperty/FindDummyPackage.cmake8
-rw-r--r--Tests/RunCMake/CMakeRoleGlobalProperty/Project.cmake10
-rw-r--r--Tests/RunCMake/CMakeRoleGlobalProperty/RunCMakeTest.cmake17
-rw-r--r--Tests/RunCMake/CMakeRoleGlobalProperty/Script.cmake6
-rw-r--r--Tests/RunCMake/CMakeRoleGlobalProperty/sub/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/CMakeRoleGlobalProperty/test.cmake.in7
-rw-r--r--Tests/RunCMake/CPack/7Z/Helpers.cmake3
-rw-r--r--Tests/RunCMake/CPack/7Z/Prerequirements.cmake4
-rw-r--r--Tests/RunCMake/CPack/7Z/packaging_COMPONENT_default.cmake1
-rw-r--r--Tests/RunCMake/CPack/ArchiveCommon/common_helpers.cmake71
-rw-r--r--Tests/RunCMake/CPack/CMakeLists.txt21
-rw-r--r--Tests/RunCMake/CPack/CPackTestHelpers.cmake157
-rw-r--r--Tests/RunCMake/CPack/DEB/Helpers.cmake176
-rw-r--r--Tests/RunCMake/CPack/DEB/Prerequirements.cmake22
-rw-r--r--Tests/RunCMake/CPack/DEB/packaging_COMPONENT_default.cmake2
-rw-r--r--Tests/RunCMake/CPack/DEB/packaging_MONOLITHIC_default.cmake1
-rw-r--r--Tests/RunCMake/CPack/DragNDrop/Accept.txt1
-rw-r--r--Tests/RunCMake/CPack/DragNDrop/Helpers.cmake55
-rw-r--r--Tests/RunCMake/CPack/DragNDrop/Prerequirements.cmake8
-rw-r--r--Tests/RunCMake/CPack/DragNDrop/packaging_COMPONENT_default.cmake3
-rw-r--r--Tests/RunCMake/CPack/DragNDrop/packaging_MONOLITHIC_default.cmake2
-rw-r--r--Tests/RunCMake/CPack/External/Helpers.cmake31
-rw-r--r--Tests/RunCMake/CPack/External/Prerequirements.cmake0
-rw-r--r--Tests/RunCMake/CPack/README.txt256
-rw-r--r--Tests/RunCMake/CPack/RPM/Helpers.cmake94
-rw-r--r--Tests/RunCMake/CPack/RPM/Prerequirements.cmake23
-rw-r--r--Tests/RunCMake/CPack/RPM/default_expected_stderr.txt1
-rw-r--r--Tests/RunCMake/CPack/RPM/packaging_COMPONENT_default.cmake1
-rw-r--r--Tests/RunCMake/CPack/RunCMakeTest.cmake50
-rw-r--r--Tests/RunCMake/CPack/STGZ/Helpers.cmake75
-rw-r--r--Tests/RunCMake/CPack/STGZ/Prerequirements.cmake11
-rw-r--r--Tests/RunCMake/CPack/STGZ/packaging_COMPONENT_default.cmake1
-rw-r--r--Tests/RunCMake/CPack/TBZ2/Helpers.cmake3
-rw-r--r--Tests/RunCMake/CPack/TBZ2/Prerequirements.cmake4
-rw-r--r--Tests/RunCMake/CPack/TBZ2/packaging_COMPONENT_default.cmake1
-rw-r--r--Tests/RunCMake/CPack/TGZ/Helpers.cmake3
-rw-r--r--Tests/RunCMake/CPack/TGZ/Prerequirements.cmake4
-rw-r--r--Tests/RunCMake/CPack/TGZ/packaging_COMPONENT_default.cmake1
-rw-r--r--Tests/RunCMake/CPack/TXZ/Helpers.cmake3
-rw-r--r--Tests/RunCMake/CPack/TXZ/Prerequirements.cmake4
-rw-r--r--Tests/RunCMake/CPack/TXZ/packaging_COMPONENT_default.cmake1
-rw-r--r--Tests/RunCMake/CPack/TZ/Helpers.cmake3
-rw-r--r--Tests/RunCMake/CPack/TZ/Prerequirements.cmake4
-rw-r--r--Tests/RunCMake/CPack/TZ/packaging_COMPONENT_default.cmake1
-rw-r--r--Tests/RunCMake/CPack/VerifyResult.cmake142
-rw-r--r--Tests/RunCMake/CPack/ZIP/Helpers.cmake3
-rw-r--r--Tests/RunCMake/CPack/ZIP/Prerequirements.cmake4
-rw-r--r--Tests/RunCMake/CPack/ZIP/packaging_COMPONENT_default.cmake1
-rw-r--r--Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/ExpectedFiles.cmake3
-rw-r--r--Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/both-stderr.txt1
-rw-r--r--Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/test.cmake26
-rw-r--r--Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/ExpectedFiles.cmake9
-rw-r--r--Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/RPM-COMPONENT-stderr.txt2
-rw-r--r--Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/RPM-MONOLITHIC-stderr.txt1
-rw-r--r--Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/custom.spec.in80
-rw-r--r--Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/test.cmake9
-rw-r--r--Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake18
-rw-r--r--Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake20
-rw-r--r--Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake44
-rw-r--r--Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake53
-rw-r--r--Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/ExpectedFiles.cmake16
-rw-r--r--Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/VerifyResult.cmake59
-rw-r--r--Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/test.cmake55
-rw-r--r--Tests/RunCMake/CPack/tests/DEB_PACKAGE_VERSION_BACK_COMPATIBILITY/ExpectedFiles.cmake2
-rw-r--r--Tests/RunCMake/CPack/tests/DEB_PACKAGE_VERSION_BACK_COMPATIBILITY/VerifyResult.cmake11
-rw-r--r--Tests/RunCMake/CPack/tests/DEB_PACKAGE_VERSION_BACK_COMPATIBILITY/test.cmake7
-rw-r--r--Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/ExpectedFiles.cmake6
-rw-r--r--Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/VerifyResult.cmake39
-rw-r--r--Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/invalid_CMAKE_var-stderr.txt1
-rw-r--r--Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/invalid_CPACK_var-stderr.txt1
-rw-r--r--Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/test.cmake34
-rw-r--r--Tests/RunCMake/CPack/tests/DEPENDENCIES/DEB-stderr.txt1
-rw-r--r--Tests/RunCMake/CPack/tests/DEPENDENCIES/ExpectedFiles.cmake18
-rw-r--r--Tests/RunCMake/CPack/tests/DEPENDENCIES/VerifyResult.cmake82
-rw-r--r--Tests/RunCMake/CPack/tests/DEPENDENCIES/test.cmake60
-rw-r--r--Tests/RunCMake/CPack/tests/DIST/ExpectedFiles.cmake2
-rw-r--r--Tests/RunCMake/CPack/tests/DIST/VerifyResult.cmake16
-rw-r--r--Tests/RunCMake/CPack/tests/DIST/test.cmake3
-rw-r--r--Tests/RunCMake/CPack/tests/DMG_SLA/English.license.rtf7
-rw-r--r--Tests/RunCMake/CPack/tests/DMG_SLA/English.menu.txt9
-rw-r--r--Tests/RunCMake/CPack/tests/DMG_SLA/ExpectedFiles.cmake2
-rw-r--r--Tests/RunCMake/CPack/tests/DMG_SLA/German.license.txt3
-rw-r--r--Tests/RunCMake/CPack/tests/DMG_SLA/German.menu.txt9
-rw-r--r--Tests/RunCMake/CPack/tests/DMG_SLA/VerifyResult.cmake33
-rw-r--r--Tests/RunCMake/CPack/tests/DMG_SLA/test.cmake3
-rw-r--r--Tests/RunCMake/CPack/tests/EMPTY_DIR/ExpectedFiles.cmake7
-rw-r--r--Tests/RunCMake/CPack/tests/EMPTY_DIR/test.cmake14
-rw-r--r--Tests/RunCMake/CPack/tests/EXTERNAL/ExpectedFiles.cmake7
-rw-r--r--Tests/RunCMake/CPack/tests/EXTERNAL/VerifyResult.cmake3
-rw-r--r--Tests/RunCMake/CPack/tests/EXTERNAL/bad_major-stderr.txt6
-rw-r--r--Tests/RunCMake/CPack/tests/EXTERNAL/bad_minor-stderr.txt6
-rw-r--r--Tests/RunCMake/CPack/tests/EXTERNAL/create_package.cmake39
-rw-r--r--Tests/RunCMake/CPack/tests/EXTERNAL/expected-json-1.0.txt177
-rw-r--r--Tests/RunCMake/CPack/tests/EXTERNAL/invalid_bad-stderr.txt6
-rw-r--r--Tests/RunCMake/CPack/tests/EXTERNAL/stage_and_package-stderr.txt1
-rw-r--r--Tests/RunCMake/CPack/tests/EXTERNAL/stage_and_package-stdout.txt11
-rw-r--r--Tests/RunCMake/CPack/tests/EXTERNAL/test.cmake87
-rw-r--r--Tests/RunCMake/CPack/tests/EXTRA/DEB-stderr.txt6
-rw-r--r--Tests/RunCMake/CPack/tests/EXTRA/ExpectedFiles.cmake8
-rw-r--r--Tests/RunCMake/CPack/tests/EXTRA/VerifyResult.cmake18
-rw-r--r--Tests/RunCMake/CPack/tests/EXTRA/test.cmake35
-rw-r--r--Tests/RunCMake/CPack/tests/EXTRA_SLASH_IN_PATH/ExpectedFiles.cmake17
-rw-r--r--Tests/RunCMake/CPack/tests/EXTRA_SLASH_IN_PATH/VerifyResult.cmake7
-rw-r--r--Tests/RunCMake/CPack/tests/EXTRA_SLASH_IN_PATH/test.cmake41
-rw-r--r--Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/DEB-Prerequirements.cmake7
-rw-r--r--Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/ExpectedFiles.cmake6
-rw-r--r--Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/VerifyResult.cmake9
-rw-r--r--Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/test.cmake19
-rw-r--r--Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/DEB-Prerequirements.cmake7
-rw-r--r--Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/ExpectedFiles.cmake6
-rw-r--r--Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/VerifyResult.cmake8
-rw-r--r--Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/test.cmake15
-rw-r--r--Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/ExpectedFiles.cmake10
-rw-r--r--Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-COMPONENT-no_scripts_single_debug_info-stderr.txt1
-rw-r--r--Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-COMPONENT-single_debug_info-stderr.txt1
-rw-r--r--Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-Prerequirements.cmake11
-rw-r--r--Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/VerifyResult.cmake40
-rw-r--r--Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/test.cmake70
-rw-r--r--Tests/RunCMake/CPack/tests/LONG_FILENAMES/DEB-Prerequirements.cmake7
-rw-r--r--Tests/RunCMake/CPack/tests/LONG_FILENAMES/ExpectedFiles.cmake3
-rw-r--r--Tests/RunCMake/CPack/tests/LONG_FILENAMES/VerifyResult.cmake26
-rw-r--r--Tests/RunCMake/CPack/tests/LONG_FILENAMES/test.cmake13
-rw-r--r--Tests/RunCMake/CPack/tests/MAIN_COMPONENT/ExpectedFiles.cmake11
-rw-r--r--Tests/RunCMake/CPack/tests/MAIN_COMPONENT/RPM-invalid-stderr.txt1
-rw-r--r--Tests/RunCMake/CPack/tests/MAIN_COMPONENT/test.cmake10
-rw-r--r--Tests/RunCMake/CPack/tests/MD5SUMS/ExpectedFiles.cmake2
-rw-r--r--Tests/RunCMake/CPack/tests/MD5SUMS/VerifyResult.cmake3
-rw-r--r--Tests/RunCMake/CPack/tests/MD5SUMS/test.cmake5
-rw-r--r--Tests/RunCMake/CPack/tests/MINIMAL/ExpectedFiles.cmake2
-rw-r--r--Tests/RunCMake/CPack/tests/MINIMAL/test.cmake5
-rw-r--r--Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/ExpectedFiles.cmake6
-rw-r--r--Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/TGZ-invalid-stderr.txt2
-rw-r--r--Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/VerifyResult.cmake11
-rw-r--r--Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/test.cmake3
-rw-r--r--Tests/RunCMake/CPack/tests/PARTIALLY_RELOCATABLE_WARNING/ExpectedFiles.cmake4
-rw-r--r--Tests/RunCMake/CPack/tests/PARTIALLY_RELOCATABLE_WARNING/RPM-stderr.txt1
-rw-r--r--Tests/RunCMake/CPack/tests/PARTIALLY_RELOCATABLE_WARNING/test.cmake4
-rw-r--r--Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/ExpectedFiles.cmake8
-rw-r--r--Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/VerifyResult.cmake38
-rw-r--r--Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/test.cmake25
-rw-r--r--Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/ExpectedFiles.cmake19
-rw-r--r--Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/ZIP_COMPONENT-stdout.txt4
-rw-r--r--Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/ZIP_MONOLITHIC-stdout.txt4
-rw-r--r--Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/post.cmake2
-rw-r--r--Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/pre.cmake1
-rw-r--r--Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/test.cmake9
-rw-r--r--Tests/RunCMake/CPack/tests/PROJECT_META/ExpectedFiles.cmake9
-rw-r--r--Tests/RunCMake/CPack/tests/PROJECT_META/VerifyResult.cmake30
-rw-r--r--Tests/RunCMake/CPack/tests/PROJECT_META/test.cmake11
-rw-r--r--Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/ExpectedFiles.cmake30
-rw-r--r--Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/RPM-no_main_component-stderr.txt1
-rw-r--r--Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/test.cmake57
-rw-r--r--Tests/RunCMake/CPack/tests/SOURCE_PACKAGE/ExpectedFiles.cmake3
-rw-r--r--Tests/RunCMake/CPack/tests/SOURCE_PACKAGE/VerifyResult.cmake67
-rw-r--r--Tests/RunCMake/CPack/tests/SOURCE_PACKAGE/test.cmake7
-rw-r--r--Tests/RunCMake/CPack/tests/SUGGESTS/ExpectedFiles.cmake2
-rw-r--r--Tests/RunCMake/CPack/tests/SUGGESTS/RPM-stderr.txt1
-rw-r--r--Tests/RunCMake/CPack/tests/SUGGESTS/VerifyResult.cmake31
-rw-r--r--Tests/RunCMake/CPack/tests/SUGGESTS/test.cmake3
-rw-r--r--Tests/RunCMake/CPack/tests/SYMLINKS/ExpectedFiles.cmake12
-rw-r--r--Tests/RunCMake/CPack/tests/SYMLINKS/TGZ-Prerequirements.cmake5
-rw-r--r--Tests/RunCMake/CPack/tests/SYMLINKS/VerifyResult.cmake26
-rw-r--r--Tests/RunCMake/CPack/tests/SYMLINKS/test.cmake14
-rw-r--r--Tests/RunCMake/CPack/tests/THREADED/DEB-Prerequirements.cmake1
-rw-r--r--Tests/RunCMake/CPack/tests/THREADED/ExpectedFiles.cmake2
-rw-r--r--Tests/RunCMake/CPack/tests/THREADED/test.cmake7
-rw-r--r--Tests/RunCMake/CPack/tests/THREADED_ALL/DEB-Prerequirements.cmake1
-rw-r--r--Tests/RunCMake/CPack/tests/THREADED_ALL/ExpectedFiles.cmake2
-rw-r--r--Tests/RunCMake/CPack/tests/THREADED_ALL/test.cmake7
-rw-r--r--Tests/RunCMake/CPack/tests/TIMESTAMPS/ExpectedFiles.cmake2
-rw-r--r--Tests/RunCMake/CPack/tests/TIMESTAMPS/VerifyResult.cmake58
-rw-r--r--Tests/RunCMake/CPack/tests/TIMESTAMPS/test.cmake3
-rw-r--r--Tests/RunCMake/CPack/tests/USER_FILELIST/ExpectedFiles.cmake2
-rw-r--r--Tests/RunCMake/CPack/tests/USER_FILELIST/VerifyResult.cmake12
-rw-r--r--Tests/RunCMake/CPack/tests/USER_FILELIST/test.cmake13
-rw-r--r--Tests/RunCMake/CPack/tests/VERSION/ExpectedFiles.cmake3
-rw-r--r--Tests/RunCMake/CPack/tests/VERSION/VerifyResult.cmake17
-rw-r--r--Tests/RunCMake/CPack/tests/VERSION/test.cmake14
-rw-r--r--Tests/RunCMake/CPackCommandLine/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CPackCommandLine/MultiConfig-check-stdout.txt4
-rw-r--r--Tests/RunCMake/CPackCommandLine/MultiConfig-package-stdout.txt8
-rw-r--r--Tests/RunCMake/CPackCommandLine/MultiConfig.cmake9
-rw-r--r--Tests/RunCMake/CPackCommandLine/NotAGenerator-result.txt1
-rw-r--r--Tests/RunCMake/CPackCommandLine/NotAGenerator-stderr.txt1
-rw-r--r--Tests/RunCMake/CPackCommandLine/RunCMakeTest.cmake33
-rw-r--r--Tests/RunCMake/CPackCommandLine/foo.c4
-rw-r--r--Tests/RunCMake/CPackConfig/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/CPackConfig/Default-check.cmake7
-rw-r--r--Tests/RunCMake/CPackConfig/Default.cmake3
-rw-r--r--Tests/RunCMake/CPackConfig/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/CPackConfig/Simple-check.cmake3
-rw-r--r--Tests/RunCMake/CPackConfig/Simple.cmake1
-rw-r--r--Tests/RunCMake/CPackConfig/Special-check.cmake5
-rw-r--r--Tests/RunCMake/CPackConfig/Special.cmake3
-rw-r--r--Tests/RunCMake/CPackConfig/Verbatim-check.cmake10
-rw-r--r--Tests/RunCMake/CPackConfig/Verbatim.cmake5
-rw-r--r--Tests/RunCMake/CPackConfig/Version1-check.cmake6
-rw-r--r--Tests/RunCMake/CPackConfig/Version1.cmake1
-rw-r--r--Tests/RunCMake/CPackConfig/Version2-check.cmake6
-rw-r--r--Tests/RunCMake/CPackConfig/Version2.cmake1
-rw-r--r--Tests/RunCMake/CPackConfig/Version3-check.cmake6
-rw-r--r--Tests/RunCMake/CPackConfig/Version3.cmake1
-rw-r--r--Tests/RunCMake/CPackConfig/check.cmake10
-rw-r--r--Tests/RunCMake/CPackInstallProperties/Append-check.cmake3
-rw-r--r--Tests/RunCMake/CPackInstallProperties/Append.cmake2
-rw-r--r--Tests/RunCMake/CPackInstallProperties/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/CPackInstallProperties/FilenameGenex-check.cmake3
-rw-r--r--Tests/RunCMake/CPackInstallProperties/FilenameGenex.cmake7
-rw-r--r--Tests/RunCMake/CPackInstallProperties/MultipleValues-check.cmake3
-rw-r--r--Tests/RunCMake/CPackInstallProperties/MultipleValues.cmake1
-rw-r--r--Tests/RunCMake/CPackInstallProperties/PerConfigValue-check.cmake13
-rw-r--r--Tests/RunCMake/CPackInstallProperties/PerConfigValue.cmake14
-rw-r--r--Tests/RunCMake/CPackInstallProperties/Replace-check.cmake3
-rw-r--r--Tests/RunCMake/CPackInstallProperties/Replace.cmake2
-rw-r--r--Tests/RunCMake/CPackInstallProperties/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/CPackInstallProperties/Simple-check.cmake3
-rw-r--r--Tests/RunCMake/CPackInstallProperties/Simple.cmake1
-rw-r--r--Tests/RunCMake/CPackInstallProperties/ValueGenex-check.cmake3
-rw-r--r--Tests/RunCMake/CPackInstallProperties/ValueGenex.cmake7
-rw-r--r--Tests/RunCMake/CPackInstallProperties/check.cmake12
-rw-r--r--Tests/RunCMake/CPackInstallProperties/test.cpp3
-rw-r--r--Tests/RunCMake/CPackSymlinks/RunCMakeTest.cmake21
-rw-r--r--Tests/RunCMake/CPackSymlinks/SrcSymlinksCheck.cmake21
-rw-r--r--Tests/RunCMake/CPackSymlinks/SrcSymlinksTar-stdout.txt9
-rw-r--r--Tests/RunCMake/CPackSymlinks/testcpacksym.tarbin0 -> 20480 bytes-rw-r--r--Tests/RunCMake/CSharpCustomCommand/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CSharpCustomCommand/CommandWithOutput-check.cmake21
-rw-r--r--Tests/RunCMake/CSharpCustomCommand/CommandWithOutput.cmake13
-rw-r--r--Tests/RunCMake/CSharpCustomCommand/RunCMakeTest.cmake42
-rw-r--r--Tests/RunCMake/CSharpCustomCommand/TargetWithCommand-build-stdout.txt1
-rw-r--r--Tests/RunCMake/CSharpCustomCommand/TargetWithCommand.cmake4
-rw-r--r--Tests/RunCMake/CSharpCustomCommand/dummy.cs0
-rw-r--r--Tests/RunCMake/CSharpCustomCommand/test.cs.in8
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ImportLib.cmake45
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ImportLib.cs8
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ImportLibMixed.cxx8
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.cxx8
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.h13
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ImportLibNative.cxx8
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ImportLibNative.h13
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ImportLibPure.cxx8
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ImportLibSafe.cxx8
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cmake88
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cs13
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ReferenceImportMixed.cxx20
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ReferenceImportNative.cxx13
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ReferenceImportPure.cxx17
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/ReferenceImportSafe.cxx17
-rw-r--r--Tests/RunCMake/CSharpReferenceImport/RunCMakeTest.cmake41
-rw-r--r--Tests/RunCMake/CTest/BeforeProject-result.txt1
-rw-r--r--Tests/RunCMake/CTest/BeforeProject-stderr.txt6
-rw-r--r--Tests/RunCMake/CTest/BeforeProject.cmake2
-rw-r--r--Tests/RunCMake/CTest/CMakeCTestArguments-test-check.cmake4
-rw-r--r--Tests/RunCMake/CTest/CMakeCTestArguments.cmake2
-rw-r--r--Tests/RunCMake/CTest/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/CTest/CTestTestfile.cmake.in1
-rw-r--r--Tests/RunCMake/CTest/NotOn-check.cmake8
-rw-r--r--Tests/RunCMake/CTest/NotOn.cmake3
-rw-r--r--Tests/RunCMake/CTest/RunCMakeTest.cmake41
-rw-r--r--Tests/RunCMake/CTest/SingleConfig-test-stdout.txt8
-rw-r--r--Tests/RunCMake/CTest/SingleConfig.cmake6
-rw-r--r--Tests/RunCMake/CTest/Site.cmake5
-rw-r--r--Tests/RunCMake/CTest/TestfileErrors-Script.cmake4
-rw-r--r--Tests/RunCMake/CTest/TestfileErrors-test-result.txt1
-rw-r--r--Tests/RunCMake/CTest/TestfileErrors-test-stderr.txt11
-rw-r--r--Tests/RunCMake/CTest/TestfileErrors.cmake3
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt.in3
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/compare_options.cmake14
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stdout.txt13
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand.cmake10
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-stdout.txt7
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult.cmake19
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stderr.txt2
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stdout.txt2
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions.cmake8
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/test.cmake.in15
-rw-r--r--Tests/RunCMake/CTestCommandLine/BadCTestTestfile-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/BadCTestTestfile-stderr.txt6
-rw-r--r--Tests/RunCMake/CTestCommandLine/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CTestCommandLine/CMakeLists.txt.in4
-rw-r--r--Tests/RunCMake/CTestCommandLine/FailRegexFound-check.cmake13
-rw-r--r--Tests/RunCMake/CTestCommandLine/LabelCount-stdout.txt7
-rw-r--r--Tests/RunCMake/CTestCommandLine/MemCheckSan.cmake7
-rw-r--r--Tests/RunCMake/CTestCommandLine/MergeOutput-stdout.txt13
-rw-r--r--Tests/RunCMake/CTestCommandLine/MergeOutput.cmake4
-rw-r--r--Tests/RunCMake/CTestCommandLine/RequiredRegexFound-check.cmake13
-rw-r--r--Tests/RunCMake/CTestCommandLine/RequiredRegexNotFound-check.cmake16
-rw-r--r--Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake399
-rw-r--r--Tests/RunCMake/CTestCommandLine/SerialFailed-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/SerialFailed-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/SerialFailed-stdout.txt10
-rw-r--r--Tests/RunCMake/CTestCommandLine/SkipRegexFound-check.cmake13
-rw-r--r--Tests/RunCMake/CTestCommandLine/TestAffinity-stdout.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/TestOutputSize-check.cmake17
-rw-r--r--Tests/RunCMake/CTestCommandLine/TestOutputSize-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/TestOutputSize-stderr.txt2
-rw-r--r--Tests/RunCMake/CTestCommandLine/TestStdin-stdin.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/TestStdin-stdout.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/check-configuration-type-stderr.txt2
-rw-r--r--Tests/RunCMake/CTestCommandLine/init.cmake3
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests-script_error-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests-script_error-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests-script_legacy-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests-script_legacy-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests_bad-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests_bad-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests_error-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests_error-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests_legacy-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-after-timeout-cmake.cmake15
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-after-timeout-ctest-stdout.txt15
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-opt-after-timeout-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-opt-bad1-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-opt-bad1-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-opt-bad2-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-opt-bad2-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-opt-bad3-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-opt-bad3-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-opt-bad4-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-opt-bad4-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-opt-until-fail-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-opt-until-pass-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-until-fail-bad1-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-until-fail-bad1-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-until-fail-bad2-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-until-fail-bad2-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-until-fail-cmake.cmake17
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-until-fail-ctest-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-until-fail-ctest-stderr.txt3
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-until-fail-ctest-stdout.txt30
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-until-fail-good-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-until-pass-cmake.cmake15
-rw-r--r--Tests/RunCMake/CTestCommandLine/repeat-until-pass-ctest-stdout.txt15
-rw-r--r--Tests/RunCMake/CTestCommandLine/show-only_bad-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/show-only_bad-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/show-only_human-stdout.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/show-only_json-v1-check.cmake1
-rw-r--r--Tests/RunCMake/CTestCommandLine/show-only_json-v1_check.py173
-rw-r--r--Tests/RunCMake/CTestCommandLine/show_only_json_check.py24
-rw-r--r--Tests/RunCMake/CTestCommandLine/stop-on-failure-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/stop-on-failure-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/stop-on-failure-stdout.txt10
-rw-r--r--Tests/RunCMake/CTestCommandLine/test-dir-invalid-arg-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/test-dir-invalid-arg-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stdout.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/test-load-invalid-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/test-load-invalid-stdout.txt20
-rw-r--r--Tests/RunCMake/CTestCommandLine/test-load-pass-stdout.txt20
-rw-r--r--Tests/RunCMake/CTestCommandLine/test-load-wait-stdout.txt21
-rw-r--r--Tests/RunCMake/CTestCommandLine/test.cmake.in19
-rw-r--r--Tests/RunCMake/CTestCommandLine/test1-pass.cmake13
-rw-r--r--Tests/RunCMake/CTestCommandLine/test1-timeout.cmake14
-rw-r--r--Tests/RunCMake/CTestCommandLine/test1.cmake13
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/CMakeLists.txt.in9
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ResourceCommon.cmake23
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/RunCMakeTest.cmake181
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/checkfree1-ctest-s-res-cache-check.cmake1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/checkfree1-ctest-s-res-check.cmake1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/checkfree1-ctest-s-res-cmdline-check.cmake1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/checkfree1-ctest-s-res-variable-check.cmake1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/checkfree1.cmake7
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/checkfree2-ctest-s-res-check.cmake1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/checkfree2.cmake8
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/combine.cmake5
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-baddealloc-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-baddealloc.log2
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest1-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest1.log1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest2-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest2.log2
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest3-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest3.log3
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest4-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest4.log3
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest5-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-badtest5.log1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-good1.log14
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-good2.log0
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-leak-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-leak.log1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nobegin-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nobegin.log0
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noend-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noend.log1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noid-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-noid.log2
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nolog-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nores-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-nores.log2
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-notenough-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-verify-notenough.log2
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-noproc-count-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badcount-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badres-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets1-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets2-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets3-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets4-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets5-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets6-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-badwidgets7-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-good1-check.cmake20
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-good2-check.cmake6
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nocount-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nores-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc-write-proc-nowidgets-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ctresalloc.cxx400
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ensure_parallel-ctest-s-res-check.cmake16
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/ensure_parallel.cmake11
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/lotsoftests-ctest-s-res-check.cmake1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/lotsoftests.cmake16
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-cache-check.cmake3
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-cache-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-cache-stderr.txt14
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-check.cmake3
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-cmdline-check.cmake3
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-cmdline-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-cmdline-stderr.txt14
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-stderr.txt14
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-variable-check.cmake3
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-variable-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-variable-stderr.txt14
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough1.cmake5
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-check.cmake3
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-stderr.txt11
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough2.cmake5
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough3-ctest-s-res-check.cmake3
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough3-ctest-s-res-result.txt1
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough3-ctest-s-res-stderr.txt21
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/notenough3.cmake5
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/process_count-ctest-s-nores-check.cmake4
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/process_count-ctest-s-res-check.cmake9
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/process_count.cmake5
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/resspec.json59
-rw-r--r--Tests/RunCMake/CTestResourceAllocation/test.cmake.in34
-rw-r--r--Tests/RunCMake/CTestTimeout/Basic-stdout.txt6
-rw-r--r--Tests/RunCMake/CTestTimeout/CMakeLists.txt.in15
-rw-r--r--Tests/RunCMake/CTestTimeout/Fork-stdout.txt6
-rw-r--r--Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake22
-rw-r--r--Tests/RunCMake/CTestTimeout/TestTimeout.c24
-rw-r--r--Tests/RunCMake/CTestTimeout/test.cmake.in16
-rw-r--r--Tests/RunCMake/CTestTimeoutAfterMatch/CMakeLists.txt.in6
-rw-r--r--Tests/RunCMake/CTestTimeoutAfterMatch/MissingArg1-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestTimeoutAfterMatch/MissingArg2-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestTimeoutAfterMatch/RunCMakeTest.cmake11
-rw-r--r--Tests/RunCMake/CTestTimeoutAfterMatch/ShouldPass-stdout.txt6
-rw-r--r--Tests/RunCMake/CTestTimeoutAfterMatch/ShouldTimeout-stdout.txt1
-rw-r--r--Tests/RunCMake/CTestTimeoutAfterMatch/SleepFor1Second.cmake4
-rw-r--r--Tests/RunCMake/CTestTimeoutAfterMatch/test.cmake.in21
-rw-r--r--Tests/RunCMake/CacheNewline/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CacheNewline/CacheNewline-check.cmake16
-rw-r--r--Tests/RunCMake/CacheNewline/CacheNewline-stderr.txt2
-rw-r--r--Tests/RunCMake/CacheNewline/CacheNewline.cmake5
-rw-r--r--Tests/RunCMake/CacheNewline/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/CacheNewline/cache-regex.txt6
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/CheckCCompilerFlag.cmake24
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/CheckCUDACompilerFlag.cmake15
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/CheckCXXCompilerFlag.cmake17
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/CheckFortranCompilerFlag.cmake16
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/CheckISPCCompilerFlag.cmake13
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/CheckOBJCCompilerFlag.cmake14
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/CheckOBJCXXCompilerFlag.cmake14
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/NonExistentLanguage-result.txt1
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/NonExistentLanguage-stderr.txt2
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/NonExistentLanguage.cmake3
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/NotEnabledLanguage-result.txt1
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/NotEnabledLanguage-stderr.txt2
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/NotEnabledLanguage.cmake3
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/RunCMakeTest.cmake24
-rw-r--r--Tests/RunCMake/CheckIPOSupported/CMakeLists.txt7
-rw-r--r--Tests/RunCMake/CheckIPOSupported/RunCMakeTest.cmake13
-rw-r--r--Tests/RunCMake/CheckIPOSupported/cmp0069-is-old-result.txt1
-rw-r--r--Tests/RunCMake/CheckIPOSupported/cmp0069-is-old-stderr.txt16
-rw-r--r--Tests/RunCMake/CheckIPOSupported/cmp0069-is-old.cmake6
-rw-r--r--Tests/RunCMake/CheckIPOSupported/default-lang-none-result.txt1
-rw-r--r--Tests/RunCMake/CheckIPOSupported/default-lang-none-stderr.txt7
-rw-r--r--Tests/RunCMake/CheckIPOSupported/default-lang-none.cmake1
-rw-r--r--Tests/RunCMake/CheckIPOSupported/not-supported-by-cmake-result.txt1
-rw-r--r--Tests/RunCMake/CheckIPOSupported/not-supported-by-cmake-stderr.txt6
-rw-r--r--Tests/RunCMake/CheckIPOSupported/not-supported-by-cmake.cmake3
-rw-r--r--Tests/RunCMake/CheckIPOSupported/not-supported-by-compiler-result.txt1
-rw-r--r--Tests/RunCMake/CheckIPOSupported/not-supported-by-compiler-stderr.txt6
-rw-r--r--Tests/RunCMake/CheckIPOSupported/not-supported-by-compiler.cmake4
-rw-r--r--Tests/RunCMake/CheckIPOSupported/not-supported-by-generator-result.txt1
-rw-r--r--Tests/RunCMake/CheckIPOSupported/not-supported-by-generator-stderr.txt6
-rw-r--r--Tests/RunCMake/CheckIPOSupported/not-supported-by-generator.cmake6
-rw-r--r--Tests/RunCMake/CheckIPOSupported/save-to-result.cmake22
-rw-r--r--Tests/RunCMake/CheckIPOSupported/unparsed-arguments-result.txt1
-rw-r--r--Tests/RunCMake/CheckIPOSupported/unparsed-arguments-stderr.txt5
-rw-r--r--Tests/RunCMake/CheckIPOSupported/unparsed-arguments.cmake1
-rw-r--r--Tests/RunCMake/CheckIPOSupported/user-lang-unknown-result.txt1
-rw-r--r--Tests/RunCMake/CheckIPOSupported/user-lang-unknown-stderr.txt6
-rw-r--r--Tests/RunCMake/CheckIPOSupported/user-lang-unknown.cmake1
-rw-r--r--Tests/RunCMake/CheckLinkerFlag/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/CheckLinkerFlag/CheckCLinkerFlag.cmake3
-rw-r--r--Tests/RunCMake/CheckLinkerFlag/CheckCUDALinkerFlag.cmake3
-rw-r--r--Tests/RunCMake/CheckLinkerFlag/CheckCXXLinkerFlag.cmake3
-rw-r--r--Tests/RunCMake/CheckLinkerFlag/CheckFortranLinkerFlag.cmake3
-rw-r--r--Tests/RunCMake/CheckLinkerFlag/CheckLinkerFlag.cmake14
-rw-r--r--Tests/RunCMake/CheckLinkerFlag/CheckOBJCLinkerFlag.cmake3
-rw-r--r--Tests/RunCMake/CheckLinkerFlag/CheckOBJCXXLinkerFlag.cmake3
-rw-r--r--Tests/RunCMake/CheckLinkerFlag/RunCMakeTest.cmake18
-rw-r--r--Tests/RunCMake/CheckModules/CMP0075-stderr.txt61
-rw-r--r--Tests/RunCMake/CheckModules/CMP0075.cmake124
-rw-r--r--Tests/RunCMake/CheckModules/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/CheckModules/CheckIncludeFilesMissingLanguage-result.txt1
-rw-r--r--Tests/RunCMake/CheckModules/CheckIncludeFilesMissingLanguage-stderr.txt8
-rw-r--r--Tests/RunCMake/CheckModules/CheckIncludeFilesMissingLanguage.cmake3
-rw-r--r--Tests/RunCMake/CheckModules/CheckIncludeFilesOk.cmake6
-rw-r--r--Tests/RunCMake/CheckModules/CheckIncludeFilesOkNoC.cmake4
-rw-r--r--Tests/RunCMake/CheckModules/CheckIncludeFilesUnknownArgument-result.txt1
-rw-r--r--Tests/RunCMake/CheckModules/CheckIncludeFilesUnknownArgument-stderr.txt8
-rw-r--r--Tests/RunCMake/CheckModules/CheckIncludeFilesUnknownArgument.cmake3
-rw-r--r--Tests/RunCMake/CheckModules/CheckIncludeFilesUnknownLanguage-result.txt1
-rw-r--r--Tests/RunCMake/CheckModules/CheckIncludeFilesUnknownLanguage-stderr.txt10
-rw-r--r--Tests/RunCMake/CheckModules/CheckIncludeFilesUnknownLanguage.cmake3
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberMissingKey-result.txt1
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberMissingKey-stderr.txt8
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberMissingKey.cmake2
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberMissingLanguage-result.txt1
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberMissingLanguage-stderr.txt8
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberMissingLanguage.cmake2
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberOk.cmake6
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberTooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberTooManyArguments-stderr.txt8
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberTooManyArguments.cmake2
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberUnknownLanguage-result.txt1
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberUnknownLanguage-stderr.txt10
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberUnknownLanguage.cmake2
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberWrongKey-result.txt1
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberWrongKey-stderr.txt8
-rw-r--r--Tests/RunCMake/CheckModules/CheckStructHasMemberWrongKey.cmake2
-rw-r--r--Tests/RunCMake/CheckModules/CheckTypeSizeMissingLanguage-result.txt1
-rw-r--r--Tests/RunCMake/CheckModules/CheckTypeSizeMissingLanguage-stderr.txt8
-rw-r--r--Tests/RunCMake/CheckModules/CheckTypeSizeMissingLanguage.cmake2
-rw-r--r--Tests/RunCMake/CheckModules/CheckTypeSizeMixedArgs-result.txt1
-rw-r--r--Tests/RunCMake/CheckModules/CheckTypeSizeMixedArgs-stderr.txt10
-rw-r--r--Tests/RunCMake/CheckModules/CheckTypeSizeMixedArgs.cmake2
-rw-r--r--Tests/RunCMake/CheckModules/CheckTypeSizeOk.cmake12
-rw-r--r--Tests/RunCMake/CheckModules/CheckTypeSizeOkNoC.cmake4
-rw-r--r--Tests/RunCMake/CheckModules/CheckTypeSizeUnknownArgument-result.txt1
-rw-r--r--Tests/RunCMake/CheckModules/CheckTypeSizeUnknownArgument-stderr.txt8
-rw-r--r--Tests/RunCMake/CheckModules/CheckTypeSizeUnknownArgument.cmake2
-rw-r--r--Tests/RunCMake/CheckModules/CheckTypeSizeUnknownLanguage-result.txt1
-rw-r--r--Tests/RunCMake/CheckModules/CheckTypeSizeUnknownLanguage-stderr.txt10
-rw-r--r--Tests/RunCMake/CheckModules/CheckTypeSizeUnknownLanguage.cmake2
-rw-r--r--Tests/RunCMake/CheckModules/RunCMakeTest.cmake24
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/CheckCSourceCompiles.cmake15
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/CheckCUDASourceCompiles.cmake29
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/CheckCXXSourceCompiles.cmake28
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/CheckFortranSourceCompiles.cmake16
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/CheckISPCSourceCompiles.cmake20
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/CheckOBJCSourceCompiles.cmake16
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/CheckOBJCXXSourceCompiles.cmake19
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/NonExistentLanguage-result.txt1
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/NonExistentLanguage-stderr.txt2
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/NonExistentLanguage.cmake3
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/NotEnabledLanguage-result.txt1
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/NotEnabledLanguage-stderr.txt2
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/NotEnabledLanguage.cmake3
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/RunCMakeTest.cmake25
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/UnknownArgument-result.txt1
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/UnknownArgument-stderr.txt11
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/UnknownArgument.cmake5
-rw-r--r--Tests/RunCMake/CheckSourceRuns/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/CheckSourceRuns/CheckCSourceRuns.cmake15
-rw-r--r--Tests/RunCMake/CheckSourceRuns/CheckCUDASourceRuns.cmake23
-rw-r--r--Tests/RunCMake/CheckSourceRuns/CheckCXXSourceRuns.cmake22
-rw-r--r--Tests/RunCMake/CheckSourceRuns/CheckFortranSourceRuns.cmake16
-rw-r--r--Tests/RunCMake/CheckSourceRuns/CheckOBJCSourceRuns.cmake16
-rw-r--r--Tests/RunCMake/CheckSourceRuns/CheckOBJCXXSourceRuns.cmake19
-rw-r--r--Tests/RunCMake/CheckSourceRuns/NonExistentLanguage-result.txt1
-rw-r--r--Tests/RunCMake/CheckSourceRuns/NonExistentLanguage-stderr.txt2
-rw-r--r--Tests/RunCMake/CheckSourceRuns/NonExistentLanguage.cmake3
-rw-r--r--Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage-result.txt1
-rw-r--r--Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage-stderr.txt2
-rw-r--r--Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage.cmake3
-rw-r--r--Tests/RunCMake/CheckSourceRuns/RunCMakeTest.cmake21
-rw-r--r--Tests/RunCMake/CheckSourceRuns/UnknownArgument-result.txt1
-rw-r--r--Tests/RunCMake/CheckSourceRuns/UnknownArgument-stderr.txt24
-rw-r--r--Tests/RunCMake/CheckSourceRuns/UnknownArgument.cmake7
-rw-r--r--Tests/RunCMake/ClangTidy/C-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/ClangTidy/C-bad-Build-result.txt1
-rw-r--r--Tests/RunCMake/ClangTidy/C-bad-Build-stdout.txt2
-rw-r--r--Tests/RunCMake/ClangTidy/C-bad.cmake3
-rw-r--r--Tests/RunCMake/ClangTidy/C-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/ClangTidy/C-launch.cmake3
-rw-r--r--Tests/RunCMake/ClangTidy/C.cmake3
-rw-r--r--Tests/RunCMake/ClangTidy/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ClangTidy/CXX-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/ClangTidy/CXX-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/ClangTidy/CXX-launch.cmake3
-rw-r--r--Tests/RunCMake/ClangTidy/CXX.cmake3
-rw-r--r--Tests/RunCMake/ClangTidy/OBJC-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/ClangTidy/OBJC-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/ClangTidy/OBJC-launch.cmake3
-rw-r--r--Tests/RunCMake/ClangTidy/OBJC.cmake3
-rw-r--r--Tests/RunCMake/ClangTidy/OBJCXX-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/ClangTidy/OBJCXX-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/ClangTidy/OBJCXX-launch.cmake3
-rw-r--r--Tests/RunCMake/ClangTidy/OBJCXX.cmake3
-rw-r--r--Tests/RunCMake/ClangTidy/RunCMakeTest.cmake31
-rw-r--r--Tests/RunCMake/ClangTidy/main.c4
-rw-r--r--Tests/RunCMake/ClangTidy/main.cxx4
-rw-r--r--Tests/RunCMake/ClangTidy/main.m4
-rw-r--r--Tests/RunCMake/ClangTidy/main.mm4
-rw-r--r--Tests/RunCMake/CommandLine/.gitattributes2
-rw-r--r--Tests/RunCMake/CommandLine/B-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/B-no-arg-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/B-no-arg2-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/B-no-arg2-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Build-ninja-v-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Build.cmake5
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-bad-number-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-bad-number-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-good-number-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-good-number-trailing--target-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-number-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-number-trailing--target-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-space-bad-number-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-space-bad-number-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-space-good-number-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-space-good-number-trailing--target-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-bad-number-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-bad-number-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-good-number-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-good-number-trailing--target-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-trailing--invalid-target-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-trailing--invalid-target-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-trailing--target-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-space-bad-number-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-space-bad-number-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-space-good-number-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-space-good-number-trailing--target-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-fail-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-fail-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-jobs-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir.cmake1
-rw-r--r--Tests/RunCMake/CommandLine/BuildDir/CMakeLists.txt19
-rw-r--r--Tests/RunCMake/CommandLine/C-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/C-no-arg-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/C-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/C-no-file-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CommandLine/C_basic-stderr.txt4
-rw-r--r--Tests/RunCMake/CommandLine/C_basic-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/C_basic.cmake2
-rw-r--r--Tests/RunCMake/CommandLine/C_basic_fullpath-stderr.txt4
-rw-r--r--Tests/RunCMake/CommandLine/C_basic_fullpath-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/C_basic_fullpath.cmake2
-rw-r--r--Tests/RunCMake/CommandLine/C_basic_initial-cache.txt5
-rw-r--r--Tests/RunCMake/CommandLine/C_buildsrcdir-stderr.txt8
-rw-r--r--Tests/RunCMake/CommandLine/C_buildsrcdir-stdout.txt2
-rw-r--r--Tests/RunCMake/CommandLine/C_buildsrcdir.cmake0
-rw-r--r--Tests/RunCMake/CommandLine/C_buildsrcdir/initial-cache.txt6
-rw-r--r--Tests/RunCMake/CommandLine/C_buildsrcdir/src/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/CommandLine/C_buildsrcdir/src/PreLoad.cmake6
-rw-r--r--Tests/RunCMake/CommandLine/Cno-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Cno-file-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/D-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/D-no-arg-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/D-no-src-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/D-no-src-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/D_nested_cache-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/D_nested_cache.cmake1
-rw-r--r--Tests/RunCMake/CommandLine/D_typed_nested_cache-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/D_typed_nested_cache.cmake1
-rw-r--r--Tests/RunCMake/CommandLine/Dno-src-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Dno-src-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/E-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E-no-arg-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/E___run_co_compile-bad-iwyu-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E___run_co_compile-bad-iwyu-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/E___run_co_compile-no----result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E___run_co_compile-no----stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E___run_co_compile-no-cc-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E___run_co_compile-no-cc-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E___run_co_compile-no-iwyu-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E___run_co_compile-no-iwyu-stderr.txt6
-rw-r--r--Tests/RunCMake/CommandLine/E_capabilities-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_capabilities-arg-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_capabilities-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_cat_binary_files/binary.objbin0 -> 124 bytes-rw-r--r--Tests/RunCMake/CommandLine/E_cat_directory-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_cat_directory-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_cat_good_binary_cat-stdout.txtbin0 -> 248 bytes-rw-r--r--Tests/RunCMake/CommandLine/E_cat_good_cat-stdout.txt3
-rw-r--r--Tests/RunCMake/CommandLine/E_cat_non_existing_file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_cat_non_existing_file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_cat_non_readable_file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_cat_non_readable_file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_cat_option_not_handled-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_cat_option_not_handled-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_compare_files-different-eol-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_compare_files-ignore-eol-nonexistent-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_compare_files-invalid-arguments-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_compare_files-invalid-arguments-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy-one-source-directory-target-is-directory-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy-one-source-directory-target-is-directory-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_copy-one-source-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy-one-source-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy-three-source-files-target-is-directory-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy-three-source-files-target-is-directory-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_copy-three-source-files-target-is-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy-three-source-files-target-is-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy-two-good-and-one-bad-source-files-target-is-directory-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy-two-good-and-one-bad-source-files-target-is-directory-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy_directory-three-source-files-target-is-directory-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy_directory-three-source-files-target-is-directory-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_copy_directory-three-source-files-target-is-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy_directory-three-source-files-target-is-file-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/E_copy_directory-three-source-files-target-is-not-exist-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy_directory-three-source-files-target-is-not-exist-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_copy_if_different-one-source-directory-target-is-directory-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy_if_different-one-source-directory-target-is-directory-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_copy_if_different-three-source-files-target-is-directory-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy_if_different-three-source-files-target-is-directory-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_copy_if_different-three-source-files-target-is-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_copy_if_different-three-source-files-target-is-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_create_hardlink-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_create_hardlink-no-arg-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/E_create_hardlink-no-directory-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_create_hardlink-no-directory-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_create_hardlink-non-existent-source-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_create_hardlink-non-existent-source-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_create_hardlink-unresolved-symlink-prereq-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_create_hardlink-unresolved-symlink-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_create_hardlink-unresolved-symlink-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_create_symlink-broken-create-check.cmake10
-rw-r--r--Tests/RunCMake/CommandLine/E_create_symlink-broken-replace-check.cmake7
-rw-r--r--Tests/RunCMake/CommandLine/E_create_symlink-missing-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_create_symlink-missing-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_create_symlink-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_create_symlink-no-arg-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/E_create_symlink-no-replace-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_create_symlink-no-replace-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env-bad-arg1-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env-bad-arg1-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env-no-command0-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env-no-command0-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env-no-command1-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env-no-command1-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env-set-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env-set.cmake5
-rw-r--r--Tests/RunCMake/CommandLine/E_env-unset-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_env-unset.cmake5
-rw-r--r--Tests/RunCMake/CommandLine/E_false-extraargs-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_false-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_make_directory-directory-with-parent-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_make_directory-directory-with-parent-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_make_directory-directory-with-parent-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_make_directory-three-directories-check.cmake6
-rw-r--r--Tests/RunCMake/CommandLine/E_make_directory-three-directories-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_make_directory-three-directories-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_make_directory-two-directories-and-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_make_directory-two-directories-and-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-mixed-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-mixed-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-mixed-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-no-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-directory-with-parent-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-directory-with-parent-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-symlink-dir-check.cmake6
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-symlink-dir-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-symlink-file-check.cmake6
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-symlink-file-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-three-directories-check.cmake6
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-three-directories-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-two-directories-and-file-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_remove_directory-two-directories-and-file-stderr.txt0
-rw-r--r--Tests/RunCMake/CommandLine/E_rename-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rename-no-arg-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_bad_argument-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_bad_argument-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_directory_link_existing-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_directory_link_existing-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_empty_file_specified-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_empty_file_specified.cmake8
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_file_force_existing-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_file_force_existing-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_file_force_non_existing-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_file_link_existing-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_file_link_existing-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_file_link_non_existing-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_file_non_force_existing-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_file_non_force_existing-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_file_non_force_non_existing-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_file_non_force_non_existing-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_file_recursive_existing-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_file_recursive_existing-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_file_recursive_non_existing-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_file_recursive_non_existing-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_force_recursive_directory_with_files-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_force_recursive_directory_with_files-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_force_recursive_non_existing_file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_no_file_specified-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_no_file_specified-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_non_recursive_directory-two-directories-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_non_recursive_directory-two-directories-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_non_recursive_directory-two-directories-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_recursive_directory-two-directories-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_recursive_directory-two-directories-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_recursive_directory_link_existing-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_recursive_directory_link_existing-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_recursive_file_link_existing-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_recursive_file_link_existing-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_rm_recursive_file_link_non_existing-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_server-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_server-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha1sum-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha1sum-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha1sum-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha1sum-no-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha1sum-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha1sum-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha224sum-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha224sum-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha224sum-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha224sum-no-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha224sum-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha224sum-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha256sum-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha256sum-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha256sum-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha256sum-no-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha256sum-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha256sum-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha384sum-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha384sum-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha384sum-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha384sum-no-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha384sum-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha384sum-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha512sum-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha512sum-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha512sum-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha512sum-no-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha512sum-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha512sum-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sleep-bad-arg1-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sleep-bad-arg1-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sleep-bad-arg2-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sleep-bad-arg2-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sleep-no-args-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sleep-no-args-stderr.cmake2
-rw-r--r--Tests/RunCMake/CommandLine/E_time-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_time-no-arg-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/E_time-stdout.txt3
-rw-r--r--Tests/RunCMake/CommandLine/E_touch-nonexistent-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_touch-nonexistent-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_touch_nocreate-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_touch_nocreate-no-arg-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/EnvGenerator/CMakeLists.txt10
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-A-platform-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-A-platform-stderr-vs9.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-A-platform-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-G-implicit-platform-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-T-toolset-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-T-toolset-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-bad-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-bad-stderr.txt5
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-instance-invalid-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-instance-invalid-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-ninja-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-ninja-stderr.txt4
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-platform-invalid-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr-vs9.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-toolset-invalid-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-toolset-invalid-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-unset-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-unset-stderr.txt4
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-warnings-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-warnings-stderr.txt7
-rw-r--r--Tests/RunCMake/CommandLine/ExplicitDirs/CMakeLists.txt20
-rw-r--r--Tests/RunCMake/CommandLine/G_bad-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/G_bad-arg-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/G_no-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/G_no-arg-stderr.txt3
-rw-r--r--Tests/RunCMake/CommandLine/InvalidArg1-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/InvalidArg1-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/InvalidArg2-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/InvalidArg2-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/NoArgs-stdout.txt11
-rw-r--r--Tests/RunCMake/CommandLine/P_arbitrary_args.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/P_directory-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/P_directory-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/P_no-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/P_no-arg-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/P_no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/P_no-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/P_working-dir.cmake14
-rw-r--r--Tests/RunCMake/CommandLine/ProfilingTest-check.cmake31
-rw-r--r--Tests/RunCMake/CommandLine/ProfilingTest.cmake5
-rw-r--r--Tests/RunCMake/CommandLine/RunCMakeTest.cmake839
-rw-r--r--Tests/RunCMake/CommandLine/S-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/S-no-arg-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/S-no-arg2-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/S-no-arg2-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/U-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/U-no-arg-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/U-no-src-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/U-no-src-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Uno-src-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Uno-src-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/W_bad-arg1-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/W_bad-arg1-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/W_bad-arg2-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/W_bad-arg2-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/W_bad-arg3-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/W_bad-arg3-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Wdeprecated-stderr.txt4
-rw-r--r--Tests/RunCMake/CommandLine/Wdeprecated.cmake1
-rw-r--r--Tests/RunCMake/CommandLine/Wdev-stderr.txt11
-rw-r--r--Tests/RunCMake/CommandLine/Wdev.cmake6
-rw-r--r--Tests/RunCMake/CommandLine/Werror_deprecated-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Werror_deprecated-stderr.txt4
-rw-r--r--Tests/RunCMake/CommandLine/Werror_deprecated.cmake1
-rw-r--r--Tests/RunCMake/CommandLine/Werror_dev-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Werror_dev-stderr.txt11
-rw-r--r--Tests/RunCMake/CommandLine/Werror_dev.cmake7
-rw-r--r--Tests/RunCMake/CommandLine/Wizard-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Wizard-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Wno-deprecated.cmake1
-rw-r--r--Tests/RunCMake/CommandLine/Wno-dev.cmake6
-rw-r--r--Tests/RunCMake/CommandLine/Wno-error_deprecated-stderr.txt4
-rw-r--r--Tests/RunCMake/CommandLine/Wno-error_deprecated.cmake2
-rw-r--r--Tests/RunCMake/CommandLine/Wno-error_dev-stderr.txt11
-rw-r--r--Tests/RunCMake/CommandLine/Wno-error_dev.cmake7
-rw-r--r--Tests/RunCMake/CommandLine/build-bad-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/build-bad-dir-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/build-bad-generator-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/build-bad-generator-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/build-no-cache-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/build-no-cache-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/build-no-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/build-no-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/build-no-generator-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/build-no-generator-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/cache-bad-entry-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/cache-bad-entry-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/cache-bad-entry/CMakeCache.txt10
-rw-r--r--Tests/RunCMake/CommandLine/cache-bad-generator/CMakeCache.txt1
-rw-r--r--Tests/RunCMake/CommandLine/cache-empty-entry-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/cache-empty-entry-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/cache-empty-entry/CMakeCache.txt7
-rw-r--r--Tests/RunCMake/CommandLine/cache-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/cache-no-file-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/cache-no-generator/CMakeCache.txt0
-rw-r--r--Tests/RunCMake/CommandLine/cmake_depends-check.cmake14
-rw-r--r--Tests/RunCMake/CommandLine/cmake_depends-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/cmake_depends/.gitattributes2
-rw-r--r--Tests/RunCMake/CommandLine/cmake_depends/test.c2
-rw-r--r--Tests/RunCMake/CommandLine/cmake_depends/test.h3
-rw-r--r--Tests/RunCMake/CommandLine/cmake_depends/test_UTF-16LE.hbin0 -> 59 bytes-rw-r--r--Tests/RunCMake/CommandLine/compare_files/.gitattributes2
-rw-r--r--Tests/RunCMake/CommandLine/compare_files/crlf1
-rw-r--r--Tests/RunCMake/CommandLine/compare_files/empty10
-rw-r--r--Tests/RunCMake/CommandLine/compare_files/empty20
-rw-r--r--Tests/RunCMake/CommandLine/compare_files/lf1
-rw-r--r--Tests/RunCMake/CommandLine/copy_input/d1/d1.txt0
-rw-r--r--Tests/RunCMake/CommandLine/copy_input/d2/d2.txt0
-rw-r--r--Tests/RunCMake/CommandLine/copy_input/d3/d3.txt0
-rw-r--r--Tests/RunCMake/CommandLine/copy_input/f1.txt0
-rw-r--r--Tests/RunCMake/CommandLine/copy_input/f2.txt0
-rw-r--r--Tests/RunCMake/CommandLine/copy_input/f3.txt0
-rw-r--r--Tests/RunCMake/CommandLine/debug-output-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/debug-output.cmake0
-rw-r--r--Tests/RunCMake/CommandLine/debug-trycompile.cmake5
-rw-r--r--Tests/RunCMake/CommandLine/dir-install-options-to-vars/cmake_install.cmake15
-rw-r--r--Tests/RunCMake/CommandLine/dir-permissions-install-options-to-vars/cmake_install.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/env-export-compile-commands-override-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/env-export-compile-commands-set-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/env-export-compile-commands-unset-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/env-export-compile-commands/CMakeLists.txt7
-rw-r--r--Tests/RunCMake/CommandLine/install-bad-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-bad-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-afew-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-afew-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-all-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-all-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-assignment-at-the-beginning-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-assignment-at-the-beginning-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-assignment-at-the-end-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-assignment-at-the-end-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-comma-at-the-end-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-comma-at-the-end-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-invalid-assignment-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-invalid-assignment-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-invalid-comma1-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-invalid-comma1-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-invalid-comma2-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-invalid-comma2-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-none-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-default-dir-permissions-none-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-no-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-no-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-options-to-vars-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-options-to-vars-stderr.txt4
-rw-r--r--Tests/RunCMake/CommandLine/install-prefix-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/install-prefix-no-arg-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/lists-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/lists-no-file-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/llvm_rc_empty_preprocessor-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/llvm_rc_empty_preprocessor-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/llvm_rc_failing_first_command-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/llvm_rc_failing_first_command-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/llvm_rc_failing_second_command-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/llvm_rc_failing_second_command-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/llvm_rc_no_---result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/llvm_rc_no_---stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/llvm_rc_no_args-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/llvm_rc_no_args-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/no-S-B-stderr.txt4
-rw-r--r--Tests/RunCMake/CommandLine/profiling-all-params-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/profiling-all-params-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/profiling-invalid-format-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/profiling-invalid-format-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/profiling-missing-format-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/profiling-missing-format-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/profiling-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/profiling-missing-output-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/reject_fifo-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/reject_fifo-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/trace-expand-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/trace-expand-warn-uninitialized-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/trace-expand-warn-uninitialized.cmake4
-rw-r--r--Tests/RunCMake/CommandLine/trace-expand.cmake1
-rw-r--r--Tests/RunCMake/CommandLine/trace-json-v1-check.cmake11
-rwxr-xr-xTests/RunCMake/CommandLine/trace-json-v1-check.py76
-rw-r--r--Tests/RunCMake/CommandLine/trace-json-v1-expand-check.cmake11
-rw-r--r--Tests/RunCMake/CommandLine/trace-json-v1-expand.cmake1
-rw-r--r--Tests/RunCMake/CommandLine/trace-json-v1.cmake5
-rw-r--r--Tests/RunCMake/CommandLine/trace-only-this-file.cmake1
-rw-r--r--Tests/RunCMake/CommandLine/trace-redirect-check.cmake13
-rw-r--r--Tests/RunCMake/CommandLine/trace-redirect-nofile-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/trace-redirect-nofile-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/trace-redirect-nofile.cmake0
-rw-r--r--Tests/RunCMake/CommandLine/trace-redirect-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/trace-redirect.cmake0
-rw-r--r--Tests/RunCMake/CommandLine/trace-source-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/trace-source.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/trace-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/trace.cmake0
-rw-r--r--Tests/RunCMake/CommandLine/warn-uninitialized-stderr.txt53
-rw-r--r--Tests/RunCMake/CommandLine/warn-uninitialized.cmake18
-rw-r--r--Tests/RunCMake/CommandLineTar/7zip-gz-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/7zip-gz-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/7zip.cmake10
-rw-r--r--Tests/RunCMake/CommandLineTar/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CommandLineTar/RunCMakeTest.cmake36
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-file-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-format-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-format-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from1-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from1-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from2-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from2-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from3-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from3-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from3.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from4-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from4-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from4.txt2
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from5-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from5-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-from5.txt2
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-mtime1-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-mtime1-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-opt1-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-opt1-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-without-action-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-without-action-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/bad-wrong-flag-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/end-opt1-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/end-opt1-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLineTar/end-opt2-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/gnutar-gz.cmake10
-rw-r--r--Tests/RunCMake/CommandLineTar/gnutar.cmake10
-rw-r--r--Tests/RunCMake/CommandLineTar/pax-xz.cmake10
-rw-r--r--Tests/RunCMake/CommandLineTar/pax-zstd.cmake10
-rw-r--r--Tests/RunCMake/CommandLineTar/pax.cmake10
-rw-r--r--Tests/RunCMake/CommandLineTar/paxr-bz2.cmake10
-rw-r--r--Tests/RunCMake/CommandLineTar/paxr.cmake10
-rw-r--r--Tests/RunCMake/CommandLineTar/roundtrip.cmake93
-rw-r--r--Tests/RunCMake/CommandLineTar/test-file.txt0
-rw-r--r--Tests/RunCMake/CommandLineTar/without-files-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/zip-bz2-result.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/zip-bz2-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLineTar/zip-filtered.cmake28
-rw-r--r--Tests/RunCMake/CommandLineTar/zip.cmake10
-rw-r--r--Tests/RunCMake/CompatibleInterface/AutoUic-result.txt1
-rw-r--r--Tests/RunCMake/CompatibleInterface/AutoUic-stderr.txt11
-rw-r--r--Tests/RunCMake/CompatibleInterface/AutoUic.cmake19
-rw-r--r--Tests/RunCMake/CompatibleInterface/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CompatibleInterface/DebugProperties-result.txt1
-rw-r--r--Tests/RunCMake/CompatibleInterface/DebugProperties-stderr.txt101
-rw-r--r--Tests/RunCMake/CompatibleInterface/DebugProperties.cmake74
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceBool-builtin-prop-result.txt1
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceBool-builtin-prop-stderr.txt5
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceBool-builtin-prop.cmake11
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceBool-mismatch-depend-self-result.txt1
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceBool-mismatch-depend-self-stderr.txt3
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceBool-mismatch-depend-self.cmake11
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceBool-mismatch-depends-result.txt1
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceBool-mismatch-depends-stderr.txt3
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceBool-mismatch-depends.cmake10
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceBool-mismatched-use-result.txt1
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceBool-mismatched-use-stderr.txt4
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceBool-mismatched-use.cmake9
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceNumber-mismatched-use-result.txt1
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceNumber-mismatched-use-stderr.txt4
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceNumber-mismatched-use.cmake9
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-Bool-Conflict-result.txt1
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-Bool-Conflict-stderr.txt6
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-Bool-Conflict.cmake8
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-Bool-Min-Conflict-result.txt1
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-Bool-Min-Conflict-stderr.txt7
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-Bool-Min-Conflict.cmake9
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-builtin-prop-result.txt1
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-builtin-prop-stderr.txt5
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-builtin-prop.cmake9
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-mismatch-depend-self-result.txt1
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-mismatch-depend-self-stderr.txt3
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-mismatch-depend-self.cmake11
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-mismatch-depends-result.txt1
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-mismatch-depends-stderr.txt3
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-mismatch-depends.cmake10
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-mismatched-use-result.txt1
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-mismatched-use-stderr.txt4
-rw-r--r--Tests/RunCMake/CompatibleInterface/InterfaceString-mismatched-use.cmake9
-rw-r--r--Tests/RunCMake/CompatibleInterface/RunCMakeTest.cmake19
-rw-r--r--Tests/RunCMake/CompatibleInterface/empty.cpp1
-rw-r--r--Tests/RunCMake/CompatibleInterface/main.cpp5
-rw-r--r--Tests/RunCMake/CompileDefinitions/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CompileDefinitions/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/CompileDefinitions/SetEmpty-result.txt1
-rw-r--r--Tests/RunCMake/CompileDefinitions/SetEmpty-stderr.txt3
-rw-r--r--Tests/RunCMake/CompileDefinitions/SetEmpty.cmake12
-rw-r--r--Tests/RunCMake/CompileFeatures/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-stderr.txt7
-rw-r--r--Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle.cmake16
-rw-r--r--Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved.cmake14
-rw-r--r--Tests/RunCMake/CompileFeatures/NoSupportedCFeatures-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/NoSupportedCFeatures-stderr.txt8
-rw-r--r--Tests/RunCMake/CompileFeatures/NoSupportedCFeatures.cmake5
-rw-r--r--Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex-stderr.txt6
-rw-r--r--Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex.cmake5
-rw-r--r--Tests/RunCMake/CompileFeatures/NoSupportedCxxFeatures-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/NoSupportedCxxFeatures-stderr.txt8
-rw-r--r--Tests/RunCMake/CompileFeatures/NoSupportedCxxFeatures.cmake3
-rw-r--r--Tests/RunCMake/CompileFeatures/NoSupportedCxxFeaturesGenex-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/NoSupportedCxxFeaturesGenex-stderr.txt6
-rw-r--r--Tests/RunCMake/CompileFeatures/NoSupportedCxxFeaturesGenex.cmake3
-rw-r--r--Tests/RunCMake/CompileFeatures/NonValidTarget1-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/NonValidTarget1-stderr.txt9
-rw-r--r--Tests/RunCMake/CompileFeatures/NonValidTarget1.cmake17
-rw-r--r--Tests/RunCMake/CompileFeatures/NonValidTarget2-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/NonValidTarget2-stderr.txt9
-rw-r--r--Tests/RunCMake/CompileFeatures/NonValidTarget2.cmake10
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature-stderr.txt2
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature.cmake3
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeatureGenex-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeatureGenex-stderr.txt2
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeatureGenex.cmake3
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeatureTransitive-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeatureTransitive-stderr.txt2
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeatureTransitive.cmake6
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug-stderr.txt11
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug.cmake4
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugCommand-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugCommand-stderr.txt5
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugCommand.cmake4
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex-stderr.txt11
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex.cmake4
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive-stderr.txt11
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive.cmake6
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAStandard-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAStandard-stderr.txt4
-rw-r--r--Tests/RunCMake/CompileFeatures/NotAStandard.cmake2
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX11-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX11-stderr.txt3
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX11.cmake5
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX11Ext-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX11Ext-stderr.txt3
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX11Ext.cmake4
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX11ExtVariable-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX11ExtVariable-stderr.txt3
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX11ExtVariable.cmake4
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX11Variable-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX11Variable-stderr.txt3
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX11Variable.cmake5
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX98-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX98-stderr.txt3
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX98.cmake5
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX98Ext-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX98Ext-stderr.txt3
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX98Ext.cmake4
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX98ExtVariable-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX98ExtVariable-stderr.txt3
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX98ExtVariable.cmake4
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX98Variable-result.txt1
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX98Variable-stderr.txt3
-rw-r--r--Tests/RunCMake/CompileFeatures/RequireCXX98Variable.cmake5
-rw-r--r--Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake63
-rw-r--r--Tests/RunCMake/CompileFeatures/empty.c7
-rw-r--r--Tests/RunCMake/CompileFeatures/empty.cpp7
-rw-r--r--Tests/RunCMake/CompileFeatures/generate_feature_list.cmake43
-rw-r--r--Tests/RunCMake/CompilerArgs/C.cmake3
-rw-r--r--Tests/RunCMake/CompilerArgs/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CompilerArgs/CXX.cmake3
-rw-r--r--Tests/RunCMake/CompilerArgs/FindCCompiler.cmake2
-rw-r--r--Tests/RunCMake/CompilerArgs/FindCXXCompiler.cmake2
-rw-r--r--Tests/RunCMake/CompilerArgs/RunCMakeTest.cmake58
-rw-r--r--Tests/RunCMake/CompilerArgs/main.c10
-rw-r--r--Tests/RunCMake/CompilerArgs/main.cxx10
-rw-r--r--Tests/RunCMake/CompilerArgs/toolchain.cmake.in1
-rw-r--r--Tests/RunCMake/CompilerChange/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/CompilerChange/EmptyCompiler-override.cmake2
-rw-r--r--Tests/RunCMake/CompilerChange/EmptyCompiler-result.txt1
-rw-r--r--Tests/RunCMake/CompilerChange/EmptyCompiler-stderr.txt13
-rw-r--r--Tests/RunCMake/CompilerChange/EmptyCompiler.cmake2
-rw-r--r--Tests/RunCMake/CompilerChange/FindCompiler.cmake2
-rw-r--r--Tests/RunCMake/CompilerChange/FirstCompiler-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerChange/FirstCompiler.cmake3
-rw-r--r--Tests/RunCMake/CompilerChange/RunCMakeTest.cmake58
-rw-r--r--Tests/RunCMake/CompilerChange/SecondCompiler-stderr.txt4
-rw-r--r--Tests/RunCMake/CompilerChange/SecondCompiler-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerChange/SecondCompiler.cmake3
-rwxr-xr-xTests/RunCMake/CompilerChange/cc.sh.in2
-rw-r--r--Tests/RunCMake/CompilerLauncher/C-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/C-common.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/C-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/C-env-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/C-env.cmake1
-rw-r--r--Tests/RunCMake/CompilerLauncher/C-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/C-launch-env.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/C-launch.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/C.cmake2
-rw-r--r--Tests/RunCMake/CompilerLauncher/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CompilerLauncher/CUDA-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/CUDA-common.cmake4
-rw-r--r--Tests/RunCMake/CompilerLauncher/CUDA-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/CUDA-env-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/CUDA-env.cmake1
-rw-r--r--Tests/RunCMake/CompilerLauncher/CUDA-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/CUDA-launch-env.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/CUDA-launch.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/CUDA.cmake2
-rw-r--r--Tests/RunCMake/CompilerLauncher/CXX-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/CXX-common.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/CXX-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/CXX-env-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/CXX-env.cmake1
-rw-r--r--Tests/RunCMake/CompilerLauncher/CXX-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/CXX-launch-env.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/CXX-launch.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/CXX.cmake2
-rw-r--r--Tests/RunCMake/CompilerLauncher/Fortran-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/Fortran-common.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/Fortran-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/Fortran-env-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/Fortran-env.cmake1
-rw-r--r--Tests/RunCMake/CompilerLauncher/Fortran-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/Fortran-launch-env.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/Fortran-launch.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/Fortran.cmake2
-rw-r--r--Tests/RunCMake/CompilerLauncher/ISPC-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/ISPC-common.cmake8
-rw-r--r--Tests/RunCMake/CompilerLauncher/ISPC-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/ISPC-env-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/ISPC-env.cmake1
-rw-r--r--Tests/RunCMake/CompilerLauncher/ISPC-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/ISPC-launch-env.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/ISPC-launch.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/ISPC.cmake2
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJC-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJC-common.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJC-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJC-env-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJC-env.cmake1
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJC-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJC-launch-env.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJC-launch.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJC.cmake2
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJCXX-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJCXX-common.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJCXX-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJCXX-env-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJCXX-env.cmake1
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJCXX-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJCXX-launch-env.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJCXX-launch.cmake3
-rw-r--r--Tests/RunCMake/CompilerLauncher/OBJCXX.cmake2
-rw-r--r--Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake46
-rw-r--r--Tests/RunCMake/CompilerLauncher/main.F2
-rw-r--r--Tests/RunCMake/CompilerLauncher/main.c4
-rw-r--r--Tests/RunCMake/CompilerLauncher/main.cu4
-rw-r--r--Tests/RunCMake/CompilerLauncher/main.cxx4
-rw-r--r--Tests/RunCMake/CompilerLauncher/main.m4
-rw-r--r--Tests/RunCMake/CompilerLauncher/main.mm4
-rw-r--r--Tests/RunCMake/CompilerLauncher/test.ispc4
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerC-result.txt1
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerC-stderr-JOM.txt17
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerC-stderr-NMake.txt17
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerC-stderr.txt12
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerC.cmake3
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerCXX-result.txt1
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerCXX-stderr-JOM.txt17
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerCXX-stderr-NMake.txt17
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerCXX-stderr.txt12
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerCXX.cmake3
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerCandCXX-result.txt1
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerCandCXX-stderr-JOM.txt35
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerCandCXX-stderr-NMake.txt35
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerCandCXX-stderr.txt25
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerCandCXX.cmake4
-rw-r--r--Tests/RunCMake/CompilerNotFound/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CompilerNotFound/NoCompilerC-IDE-result.txt1
-rw-r--r--Tests/RunCMake/CompilerNotFound/NoCompilerC-IDE-stderr.txt5
-rw-r--r--Tests/RunCMake/CompilerNotFound/NoCompilerC-IDE.cmake3
-rw-r--r--Tests/RunCMake/CompilerNotFound/NoCompilerCXX-IDE-result.txt1
-rw-r--r--Tests/RunCMake/CompilerNotFound/NoCompilerCXX-IDE-stderr.txt5
-rw-r--r--Tests/RunCMake/CompilerNotFound/NoCompilerCXX-IDE.cmake3
-rw-r--r--Tests/RunCMake/CompilerNotFound/NoCompilerCandCXX-IDE-result.txt1
-rw-r--r--Tests/RunCMake/CompilerNotFound/NoCompilerCandCXX-IDE-stderr.txt11
-rw-r--r--Tests/RunCMake/CompilerNotFound/NoCompilerCandCXX-IDE.cmake4
-rw-r--r--Tests/RunCMake/CompilerNotFound/RunCMakeTest.cmake25
-rw-r--r--Tests/RunCMake/Configure/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Configure/ContinueAfterError-result.txt1
-rw-r--r--Tests/RunCMake/Configure/ContinueAfterError-stderr.txt13
-rw-r--r--Tests/RunCMake/Configure/ContinueAfterError-stdout.txt11
-rw-r--r--Tests/RunCMake/Configure/ContinueAfterError.cmake19
-rw-r--r--Tests/RunCMake/Configure/CustomTargetAfterError-result.txt1
-rw-r--r--Tests/RunCMake/Configure/CustomTargetAfterError-stderr.txt9
-rw-r--r--Tests/RunCMake/Configure/CustomTargetAfterError.cmake3
-rw-r--r--Tests/RunCMake/Configure/ErrorLogs-result.txt1
-rw-r--r--Tests/RunCMake/Configure/ErrorLogs-stderr.txt4
-rw-r--r--Tests/RunCMake/Configure/ErrorLogs-stdout.txt3
-rw-r--r--Tests/RunCMake/Configure/ErrorLogs.cmake3
-rw-r--r--Tests/RunCMake/Configure/FailCopyFileABI-check.cmake14
-rw-r--r--Tests/RunCMake/Configure/FailCopyFileABI-override.cmake6
-rw-r--r--Tests/RunCMake/Configure/FailCopyFileABI-stdout.txt4
-rw-r--r--Tests/RunCMake/Configure/FailCopyFileABI.cmake2
-rw-r--r--Tests/RunCMake/Configure/NoCMAKE_CROSS_CONFIGS-result.txt1
-rw-r--r--Tests/RunCMake/Configure/NoCMAKE_CROSS_CONFIGS-stderr.txt11
-rw-r--r--Tests/RunCMake/Configure/NoCMAKE_CROSS_CONFIGS.cmake1
-rw-r--r--Tests/RunCMake/Configure/NoCMAKE_DEFAULT_BUILD_TYPE-result.txt1
-rw-r--r--Tests/RunCMake/Configure/NoCMAKE_DEFAULT_BUILD_TYPE-stderr.txt11
-rw-r--r--Tests/RunCMake/Configure/NoCMAKE_DEFAULT_BUILD_TYPE.cmake1
-rw-r--r--Tests/RunCMake/Configure/NoCMAKE_DEFAULT_CONFIGS-result.txt1
-rw-r--r--Tests/RunCMake/Configure/NoCMAKE_DEFAULT_CONFIGS-stderr.txt11
-rw-r--r--Tests/RunCMake/Configure/NoCMAKE_DEFAULT_CONFIGS.cmake1
-rw-r--r--Tests/RunCMake/Configure/RemoveCache-stdout.txt1
-rw-r--r--Tests/RunCMake/Configure/RemoveCache.cmake17
-rw-r--r--Tests/RunCMake/Configure/RerunCMake-build1-check.cmake9
-rw-r--r--Tests/RunCMake/Configure/RerunCMake-build2-check.cmake9
-rw-r--r--Tests/RunCMake/Configure/RerunCMake-build3-result.txt1
-rw-r--r--Tests/RunCMake/Configure/RerunCMake-build3-stdout.txt1
-rw-r--r--Tests/RunCMake/Configure/RerunCMake-build4-result.txt1
-rw-r--r--Tests/RunCMake/Configure/RerunCMake-build4-stdout.txt1
-rw-r--r--Tests/RunCMake/Configure/RerunCMake.cmake17
-rw-r--r--Tests/RunCMake/Configure/RerunCMake.txt1
-rw-r--r--Tests/RunCMake/Configure/RunCMakeTest.cmake58
-rw-r--r--Tests/RunCMake/Cppcheck/C-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/Cppcheck/C-bad-Build-result.txt1
-rw-r--r--Tests/RunCMake/Cppcheck/C-bad-Build-stdout.txt2
-rw-r--r--Tests/RunCMake/Cppcheck/C-bad.cmake3
-rw-r--r--Tests/RunCMake/Cppcheck/C-error-Build-result.txt1
-rw-r--r--Tests/RunCMake/Cppcheck/C-error-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/Cppcheck/C-error.cmake3
-rw-r--r--Tests/RunCMake/Cppcheck/C-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/Cppcheck/C-launch.cmake3
-rw-r--r--Tests/RunCMake/Cppcheck/C.cmake4
-rw-r--r--Tests/RunCMake/Cppcheck/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Cppcheck/CXX-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/Cppcheck/CXX-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/Cppcheck/CXX-launch.cmake3
-rw-r--r--Tests/RunCMake/Cppcheck/CXX.cmake3
-rw-r--r--Tests/RunCMake/Cppcheck/RunCMakeTest.cmake24
-rw-r--r--Tests/RunCMake/Cppcheck/main.c4
-rw-r--r--Tests/RunCMake/Cppcheck/main.cxx4
-rw-r--r--Tests/RunCMake/Cpplint/C-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/Cpplint/C-error-Build-result.txt1
-rw-r--r--Tests/RunCMake/Cpplint/C-error-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/Cpplint/C-error-launch-Build-result.txt1
-rw-r--r--Tests/RunCMake/Cpplint/C-error-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/Cpplint/C-error-launch.cmake3
-rw-r--r--Tests/RunCMake/Cpplint/C-error.cmake3
-rw-r--r--Tests/RunCMake/Cpplint/C-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/Cpplint/C-launch.cmake3
-rw-r--r--Tests/RunCMake/Cpplint/C.cmake3
-rw-r--r--Tests/RunCMake/Cpplint/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Cpplint/CXX-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/Cpplint/CXX-error-Build-result.txt1
-rw-r--r--Tests/RunCMake/Cpplint/CXX-error-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/Cpplint/CXX-error-launch-Build-result.txt1
-rw-r--r--Tests/RunCMake/Cpplint/CXX-error-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/Cpplint/CXX-error-launch.cmake3
-rw-r--r--Tests/RunCMake/Cpplint/CXX-error.cmake3
-rw-r--r--Tests/RunCMake/Cpplint/CXX-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/Cpplint/CXX-launch.cmake3
-rw-r--r--Tests/RunCMake/Cpplint/CXX.cmake3
-rw-r--r--Tests/RunCMake/Cpplint/RunCMakeTest.cmake26
-rw-r--r--Tests/RunCMake/Cpplint/main.c4
-rw-r--r--Tests/RunCMake/Cpplint/main.cxx4
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomCommand-build-check.cmake5
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomCommand.cmake56
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg-build-check.cmake3
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg.cmake14
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomTarget-build-check.cmake1
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomTarget.cmake44
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg-build-check.cmake1
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg.cmake9
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddTest-check.cmake28
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddTest.cmake20
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddTest/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/CrosscompilingEmulatorProperty.cmake34
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/InitialCache.txt.in1
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake28
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/TryRun-stdout.txt1
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/TryRun.cmake18
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/generated_exe_emulator_unexpected.cxx9
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/simple_src_exiterror.cxx4
-rw-r--r--Tests/RunCMake/DependencyGraph/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeCommon.cmake40
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeFortran-both-build-check.cmake5
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeFortran-both-build-stderr.txt1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeFortran-both.cmake1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeFortran-middle-build-check.cmake6
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeFortran-middle-build-stderr.txt1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeFortran-middle.cmake1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeFortran-none-build-check.cmake6
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeFortran-none-build-stderr.txt1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeFortran-none.cmake1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeFortran-top-build-check.cmake5
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeFortran-top-build-stderr.txt1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeFortran-top.cmake1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeFortranCommon.cmake25
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeShared-both-build-check.cmake11
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeShared-both.cmake1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeShared-middle-build-check.cmake11
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeShared-middle.cmake1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeShared-none-build-check.cmake11
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeShared-none.cmake1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeShared-top-build-check.cmake11
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeShared-top.cmake1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeStatic-both-build-check.cmake8
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeStatic-both.cmake1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeStatic-middle-build-check.cmake10
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeStatic-middle.cmake1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeStatic-none-build-check.cmake10
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeStatic-none.cmake1
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeStatic-top-build-check.cmake8
-rw-r--r--Tests/RunCMake/DependencyGraph/OptimizeStatic-top.cmake1
-rw-r--r--Tests/RunCMake/DependencyGraph/Property.cmake24
-rw-r--r--Tests/RunCMake/DependencyGraph/RunCMakeTest.cmake61
-rw-r--r--Tests/RunCMake/DependencyGraph/WriteTargets.cmake16
-rw-r--r--Tests/RunCMake/DependencyGraph/mylib.c6
-rw-r--r--Tests/RunCMake/DependencyGraph/mylib.f903
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0029-NEW-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0029-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0029-NEW.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0029-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0029-OLD.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0029-WARN-stderr.txt7
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0029-WARN.cmake1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0030-NEW-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0030-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0030-NEW.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0030-OLD-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0030-OLD-stderr.txt15
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0030-OLD.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0030-WARN-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0030-WARN-stderr.txt12
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0030-WARN.cmake1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0031-NEW-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0031-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0031-NEW.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0031-OLD-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0031-OLD-stderr.txt4
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0031-OLD.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0031-WARN-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0031-WARN-stderr.txt12
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0031-WARN.cmake1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0032-NEW-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0032-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0032-NEW.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0032-OLD-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0032-OLD-stderr.txt4
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0032-OLD.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0032-WARN-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0032-WARN-stderr.txt12
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0032-WARN.cmake1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0033-NEW-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0033-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0033-NEW.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0033-OLD-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0033-OLD-stderr.txt4
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0033-OLD.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0033-WARN-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0033-WARN-stderr.txt12
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0033-WARN.cmake1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0034-NEW-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0034-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0034-NEW.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0034-OLD-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0034-OLD-stderr.txt4
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0034-OLD.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0034-WARN-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0034-WARN-stderr.txt12
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0034-WARN.cmake1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0035-NEW-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0035-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0035-NEW.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0035-OLD-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0035-OLD-stderr.txt4
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0035-OLD.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0035-WARN-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0035-WARN-stderr.txt12
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0035-WARN.cmake1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0036-NEW-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0036-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0036-NEW.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0036-OLD-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0036-OLD-stderr.txt4
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0036-OLD.cmake2
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0036-WARN-result.txt1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0036-WARN-stderr.txt12
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMP0036-WARN.cmake1
-rw-r--r--Tests/RunCMake/DisallowedCommands/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/DisallowedCommands/RunCMakeTest.cmake16
-rw-r--r--Tests/RunCMake/ExcludeFromAll/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ExcludeFromAll/RunCMakeTest.cmake26
-rw-r--r--Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-result.txt1
-rw-r--r--Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-stderr.txt3
-rw-r--r--Tests/RunCMake/ExcludeFromAll/error-on-mixed-config.cmake6
-rw-r--r--Tests/RunCMake/ExcludeFromAll/main.c4
-rw-r--r--Tests/RunCMake/ExcludeFromAll/single-config-build-check.cmake17
-rw-r--r--Tests/RunCMake/ExcludeFromAll/single-config.cmake7
-rw-r--r--Tests/RunCMake/ExportCompileCommands/BeforeProject-check.cmake4
-rw-r--r--Tests/RunCMake/ExportCompileCommands/BeforeProject.cmake3
-rw-r--r--Tests/RunCMake/ExportCompileCommands/BeforeProjectBEFORE.cmake1
-rw-r--r--Tests/RunCMake/ExportCompileCommands/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ExportCompileCommands/CustomCompileRule.cmake5
-rw-r--r--Tests/RunCMake/ExportCompileCommands/Properties.cmake22
-rw-r--r--Tests/RunCMake/ExportCompileCommands/PropertiesGenerateCommand-check.cmake32
-rw-r--r--Tests/RunCMake/ExportCompileCommands/PropertiesGenerateCommand.cmake7
-rw-r--r--Tests/RunCMake/ExportCompileCommands/RunCMakeTest.cmake12
-rw-r--r--Tests/RunCMake/ExportCompileCommands/empty.c0
-rw-r--r--Tests/RunCMake/ExportCompileCommands/expected_file.c0
-rw-r--r--Tests/RunCMake/ExportWithoutLanguage/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ExportWithoutLanguage/NoLanguage-result.txt1
-rw-r--r--Tests/RunCMake/ExportWithoutLanguage/NoLanguage-stderr.txt4
-rw-r--r--Tests/RunCMake/ExportWithoutLanguage/NoLanguage.cmake2
-rw-r--r--Tests/RunCMake/ExportWithoutLanguage/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/ExportWithoutLanguage/header.h5
-rw-r--r--Tests/RunCMake/ExternalData/BadAlgoMap1-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadAlgoMap1-stderr.txt9
-rw-r--r--Tests/RunCMake/ExternalData/BadAlgoMap1.cmake5
-rw-r--r--Tests/RunCMake/ExternalData/BadAlgoMap2-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadAlgoMap2-stderr.txt9
-rw-r--r--Tests/RunCMake/ExternalData/BadAlgoMap2.cmake5
-rw-r--r--Tests/RunCMake/ExternalData/BadArguments-stderr.txt7
-rw-r--r--Tests/RunCMake/ExternalData/BadArguments.cmake5
-rw-r--r--Tests/RunCMake/ExternalData/BadCustom1-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadCustom1-stderr.txt9
-rw-r--r--Tests/RunCMake/ExternalData/BadCustom1.cmake5
-rw-r--r--Tests/RunCMake/ExternalData/BadCustom2-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadCustom2-stderr.txt9
-rw-r--r--Tests/RunCMake/ExternalData/BadCustom2.cmake5
-rw-r--r--Tests/RunCMake/ExternalData/BadCustom3-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadCustom3-stderr.txt7
-rw-r--r--Tests/RunCMake/ExternalData/BadCustom3.cmake5
-rw-r--r--Tests/RunCMake/ExternalData/BadCustom4-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadCustom4-stderr.txt7
-rw-r--r--Tests/RunCMake/ExternalData/BadCustom4.cmake6
-rw-r--r--Tests/RunCMake/ExternalData/BadHashAlgo1-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadHashAlgo1-stderr.txt8
-rw-r--r--Tests/RunCMake/ExternalData/BadHashAlgo1.cmake3
-rw-r--r--Tests/RunCMake/ExternalData/BadHashAlgo1.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadOption1-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadOption1-stderr.txt9
-rw-r--r--Tests/RunCMake/ExternalData/BadOption1.cmake5
-rw-r--r--Tests/RunCMake/ExternalData/BadOption2-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadOption2-stderr.txt9
-rw-r--r--Tests/RunCMake/ExternalData/BadOption2.cmake5
-rw-r--r--Tests/RunCMake/ExternalData/BadRecurse1-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadRecurse1-stderr.txt6
-rw-r--r--Tests/RunCMake/ExternalData/BadRecurse1.cmake2
-rw-r--r--Tests/RunCMake/ExternalData/BadRecurse2-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadRecurse2-stderr.txt6
-rw-r--r--Tests/RunCMake/ExternalData/BadRecurse2.cmake2
-rw-r--r--Tests/RunCMake/ExternalData/BadRecurse3-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadRecurse3-stderr.txt9
-rw-r--r--Tests/RunCMake/ExternalData/BadRecurse3.cmake2
-rw-r--r--Tests/RunCMake/ExternalData/BadSeries1-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadSeries1-stderr.txt19
-rw-r--r--Tests/RunCMake/ExternalData/BadSeries1.cmake3
-rw-r--r--Tests/RunCMake/ExternalData/BadSeries2-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadSeries2-stderr.txt16
-rw-r--r--Tests/RunCMake/ExternalData/BadSeries2.cmake3
-rw-r--r--Tests/RunCMake/ExternalData/BadSeries3-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/BadSeries3-stderr.txt6
-rw-r--r--Tests/RunCMake/ExternalData/BadSeries3.cmake2
-rw-r--r--Tests/RunCMake/ExternalData/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ExternalData/Data.txt.md51
-rw-r--r--Tests/RunCMake/ExternalData/Directory1-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/Directory1-stderr.txt14
-rw-r--r--Tests/RunCMake/ExternalData/Directory1.cmake6
-rw-r--r--Tests/RunCMake/ExternalData/Directory1/DirData1.txt0
-rw-r--r--Tests/RunCMake/ExternalData/Directory2-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/Directory2-stderr.txt10
-rw-r--r--Tests/RunCMake/ExternalData/Directory2.cmake6
-rw-r--r--Tests/RunCMake/ExternalData/Directory2.md51
-rw-r--r--Tests/RunCMake/ExternalData/Directory2/DirData2.txt0
-rw-r--r--Tests/RunCMake/ExternalData/Directory3-stderr.txt15
-rw-r--r--Tests/RunCMake/ExternalData/Directory3.cmake6
-rw-r--r--Tests/RunCMake/ExternalData/Directory3/DirData3.txt0
-rw-r--r--Tests/RunCMake/ExternalData/Directory4-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/Directory4-stderr.txt6
-rw-r--r--Tests/RunCMake/ExternalData/Directory4.cmake6
-rw-r--r--Tests/RunCMake/ExternalData/Directory4/DirData4.txt0
-rw-r--r--Tests/RunCMake/ExternalData/Directory5-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/Directory5-stderr.txt14
-rw-r--r--Tests/RunCMake/ExternalData/Directory5.cmake6
-rw-r--r--Tests/RunCMake/ExternalData/LinkContentMD5-stdout.txt3
-rw-r--r--Tests/RunCMake/ExternalData/LinkContentMD5.cmake22
-rw-r--r--Tests/RunCMake/ExternalData/LinkContentSHA1-stdout.txt3
-rw-r--r--Tests/RunCMake/ExternalData/LinkContentSHA1.cmake22
-rw-r--r--Tests/RunCMake/ExternalData/LinkDirectory1-stdout.txt5
-rw-r--r--Tests/RunCMake/ExternalData/LinkDirectory1.cmake37
-rw-r--r--Tests/RunCMake/ExternalData/MissingData-stderr.txt15
-rw-r--r--Tests/RunCMake/ExternalData/MissingData-stdout.txt1
-rw-r--r--Tests/RunCMake/ExternalData/MissingData.cmake10
-rw-r--r--Tests/RunCMake/ExternalData/MissingDataWithAssociated-stderr.txt15
-rw-r--r--Tests/RunCMake/ExternalData/MissingDataWithAssociated-stdout.txt1
-rw-r--r--Tests/RunCMake/ExternalData/MissingDataWithAssociated.cmake10
-rw-r--r--Tests/RunCMake/ExternalData/NoLinkInSource-stderr.txt6
-rw-r--r--Tests/RunCMake/ExternalData/NoLinkInSource-stdout.txt1
-rw-r--r--Tests/RunCMake/ExternalData/NoLinkInSource.cmake14
-rw-r--r--Tests/RunCMake/ExternalData/NoURLTemplates-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/NoURLTemplates-stderr.txt5
-rw-r--r--Tests/RunCMake/ExternalData/NoURLTemplates.cmake2
-rw-r--r--Tests/RunCMake/ExternalData/NormalData1-stdout.txt1
-rw-r--r--Tests/RunCMake/ExternalData/NormalData1.cmake13
-rw-r--r--Tests/RunCMake/ExternalData/NormalData2-stdout.txt1
-rw-r--r--Tests/RunCMake/ExternalData/NormalData2.cmake14
-rw-r--r--Tests/RunCMake/ExternalData/NormalData3-stdout.txt1
-rw-r--r--Tests/RunCMake/ExternalData/NormalData3.cmake14
-rw-r--r--Tests/RunCMake/ExternalData/NormalDataSub1-stdout.txt1
-rw-r--r--Tests/RunCMake/ExternalData/NormalDataSub1.cmake13
-rw-r--r--Tests/RunCMake/ExternalData/NotUnderRoot-result.txt1
-rw-r--r--Tests/RunCMake/ExternalData/NotUnderRoot-stderr.txt12
-rw-r--r--Tests/RunCMake/ExternalData/NotUnderRoot.cmake5
-rw-r--r--Tests/RunCMake/ExternalData/ObjectStoreOnly.cmake3
-rw-r--r--Tests/RunCMake/ExternalData/RunCMakeTest.cmake40
-rw-r--r--Tests/RunCMake/ExternalData/Semicolon1-stdout.txt1
-rw-r--r--Tests/RunCMake/ExternalData/Semicolon1.cmake14
-rw-r--r--Tests/RunCMake/ExternalData/Semicolon2-stdout.txt1
-rw-r--r--Tests/RunCMake/ExternalData/Semicolon2.cmake14
-rw-r--r--Tests/RunCMake/ExternalData/Semicolon3-stdout.txt1
-rw-r--r--Tests/RunCMake/ExternalData/Semicolon3.cmake12
-rw-r--r--Tests/RunCMake/ExternalData/SubDirectory1-stdout.txt3
-rw-r--r--Tests/RunCMake/ExternalData/SubDirectory1.cmake5
-rw-r--r--Tests/RunCMake/ExternalData/SubDirectory1/CMakeLists.txt29
-rw-r--r--Tests/RunCMake/ExternalData/SubDirectory1/Data.txt.md51
-rw-r--r--Tests/RunCMake/ExternalProject/Add_StepDependencies.cmake25
-rw-r--r--Tests/RunCMake/ExternalProject/Add_StepDependencies_iface-result.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/Add_StepDependencies_iface-stderr.txt5
-rw-r--r--Tests/RunCMake/ExternalProject/Add_StepDependencies_iface.cmake4
-rw-r--r--Tests/RunCMake/ExternalProject/Add_StepDependencies_iface_step-result.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/Add_StepDependencies_iface_step-stderr.txt5
-rw-r--r--Tests/RunCMake/ExternalProject/Add_StepDependencies_iface_step.cmake11
-rw-r--r--Tests/RunCMake/ExternalProject/Add_StepDependencies_no_target.cmake15
-rw-r--r--Tests/RunCMake/ExternalProject/BadIndependentStep1-result.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/BadIndependentStep1-stderr.txt7
-rw-r--r--Tests/RunCMake/ExternalProject/BadIndependentStep1.cmake14
-rw-r--r--Tests/RunCMake/ExternalProject/BadIndependentStep2-result.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/BadIndependentStep2-stderr.txt7
-rw-r--r--Tests/RunCMake/ExternalProject/BadIndependentStep2.cmake13
-rw-r--r--Tests/RunCMake/ExternalProject/CMAKE_CACHE_ARGS-check.cmake44
-rw-r--r--Tests/RunCMake/ExternalProject/CMAKE_CACHE_ARGS.cmake13
-rw-r--r--Tests/RunCMake/ExternalProject/CMAKE_CACHE_DEFAULT_ARGS-check.cmake44
-rw-r--r--Tests/RunCMake/ExternalProject/CMAKE_CACHE_DEFAULT_ARGS.cmake13
-rw-r--r--Tests/RunCMake/ExternalProject/CMAKE_CACHE_mix-check.cmake26
-rw-r--r--Tests/RunCMake/ExternalProject/CMAKE_CACHE_mix.cmake10
-rw-r--r--Tests/RunCMake/ExternalProject/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake19
-rw-r--r--Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake28
-rw-r--r--Tests/RunCMake/ExternalProject/DownloadInactivityResume.cmake5
-rw-r--r--Tests/RunCMake/ExternalProject/DownloadInactivityTimeout-build-result.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/DownloadInactivityTimeout-build-stdout.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/DownloadInactivityTimeout.cmake5
-rw-r--r--Tests/RunCMake/ExternalProject/DownloadServer.py53
-rw-r--r--Tests/RunCMake/ExternalProject/DownloadTimeout-build-result.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/DownloadTimeout-build-stderr.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/DownloadTimeout.cmake5
-rw-r--r--Tests/RunCMake/ExternalProject/FetchGitTags.cmake67
-rw-r--r--Tests/RunCMake/ExternalProject/FetchGitTags/CMakeLists.txt15
-rw-r--r--Tests/RunCMake/ExternalProject/LogOutputOnFailure-build-result.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/LogOutputOnFailure-build-stderr.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/LogOutputOnFailure-build-stdout.txt8
-rw-r--r--Tests/RunCMake/ExternalProject/LogOutputOnFailure.cmake20
-rw-r--r--Tests/RunCMake/ExternalProject/LogOutputOnFailureMerged-build-result.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/LogOutputOnFailureMerged-build-stderr.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/LogOutputOnFailureMerged-build-stdout.txt7
-rw-r--r--Tests/RunCMake/ExternalProject/LogOutputOnFailureMerged.cmake21
-rw-r--r--Tests/RunCMake/ExternalProject/MultiCommand-build-stdout.txt15
-rw-r--r--Tests/RunCMake/ExternalProject/MultiCommand.cmake24
-rw-r--r--Tests/RunCMake/ExternalProject/NO_DEPENDS-CMP0114-Common.cmake17
-rw-r--r--Tests/RunCMake/ExternalProject/NO_DEPENDS-CMP0114-NEW-Direct-result.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/NO_DEPENDS-CMP0114-NEW-Direct-stderr.txt7
-rw-r--r--Tests/RunCMake/ExternalProject/NO_DEPENDS-CMP0114-NEW-Direct.cmake4
-rw-r--r--Tests/RunCMake/ExternalProject/NO_DEPENDS-CMP0114-NEW-result.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/NO_DEPENDS-CMP0114-NEW-stderr.txt16
-rw-r--r--Tests/RunCMake/ExternalProject/NO_DEPENDS-CMP0114-NEW.cmake2
-rw-r--r--Tests/RunCMake/ExternalProject/NO_DEPENDS-CMP0114-OLD-stderr.txt61
-rw-r--r--Tests/RunCMake/ExternalProject/NO_DEPENDS-CMP0114-OLD.cmake2
-rw-r--r--Tests/RunCMake/ExternalProject/NO_DEPENDS-CMP0114-WARN-stderr.txt119
-rw-r--r--Tests/RunCMake/ExternalProject/NO_DEPENDS-CMP0114-WARN.cmake2
-rw-r--r--Tests/RunCMake/ExternalProject/NoOptions-result.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/NoOptions-stderr.txt18
-rw-r--r--Tests/RunCMake/ExternalProject/NoOptions.cmake2
-rw-r--r--Tests/RunCMake/ExternalProject/PreserveEmptyArgs-build-stdout.txt21
-rw-r--r--Tests/RunCMake/ExternalProject/PreserveEmptyArgs.cmake13
-rw-r--r--Tests/RunCMake/ExternalProject/RunCMakeTest.cmake190
-rw-r--r--Tests/RunCMake/ExternalProject/SourceEmpty-result.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/SourceEmpty-stderr.txt18
-rw-r--r--Tests/RunCMake/ExternalProject/SourceEmpty.cmake5
-rw-r--r--Tests/RunCMake/ExternalProject/SourceMissing-result.txt1
-rw-r--r--Tests/RunCMake/ExternalProject/SourceMissing-stderr.txt18
-rw-r--r--Tests/RunCMake/ExternalProject/SourceMissing.cmake2
-rw-r--r--Tests/RunCMake/ExternalProject/Steps-CMP0114-Common.cmake34
-rw-r--r--Tests/RunCMake/ExternalProject/Steps-CMP0114-NEW-build-download-check.cmake3
-rw-r--r--Tests/RunCMake/ExternalProject/Steps-CMP0114-NEW-build-install-check.cmake3
-rw-r--r--Tests/RunCMake/ExternalProject/Steps-CMP0114-NEW-build-test-check.cmake2
-rw-r--r--Tests/RunCMake/ExternalProject/Steps-CMP0114-NEW-build-update-check.cmake3
-rw-r--r--Tests/RunCMake/ExternalProject/Steps-CMP0114-NEW.cmake2
-rw-r--r--Tests/RunCMake/ExternalProject/Steps-CMP0114-OLD-build-download-check.cmake3
-rw-r--r--Tests/RunCMake/ExternalProject/Steps-CMP0114-OLD-build-install-check.cmake3
-rw-r--r--Tests/RunCMake/ExternalProject/Steps-CMP0114-OLD-build-test-check.cmake2
-rw-r--r--Tests/RunCMake/ExternalProject/Steps-CMP0114-OLD-build-update-check.cmake3
-rw-r--r--Tests/RunCMake/ExternalProject/Steps-CMP0114-OLD.cmake2
-rw-r--r--Tests/RunCMake/ExternalProject/Substitutions-build-stdout.txt7
-rw-r--r--Tests/RunCMake/ExternalProject/Substitutions.cmake25
-rw-r--r--Tests/RunCMake/ExternalProject/UsesTerminal-check.cmake97
-rw-r--r--Tests/RunCMake/ExternalProject/UsesTerminal.cmake46
-rw-r--r--Tests/RunCMake/ExternalProject/Xcode-CMP0114-stderr.txt11
-rw-r--r--Tests/RunCMake/ExternalProject/Xcode-CMP0114.cmake2
-rw-r--r--Tests/RunCMake/ExternalProject/countArgs.cmake5
-rw-r--r--Tests/RunCMake/FPHSA/BadFoundVar-result.txt1
-rw-r--r--Tests/RunCMake/FPHSA/BadFoundVar-stderr.txt7
-rw-r--r--Tests/RunCMake/FPHSA/BadFoundVar.cmake3
-rw-r--r--Tests/RunCMake/FPHSA/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/FPHSA/CustomMessageConfig.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/CustomMessageConfigVersion.cmake4
-rw-r--r--Tests/RunCMake/FPHSA/FindBadFoundVar.cmake6
-rw-r--r--Tests/RunCMake/FPHSA/FindCustomMessage.cmake17
-rw-r--r--Tests/RunCMake/FPHSA/FindNameMismatch.cmake4
-rw-r--r--Tests/RunCMake/FPHSA/FindNameMismatchOld.cmake4
-rw-r--r--Tests/RunCMake/FPHSA/FindNameMismatchSuppressed.cmake6
-rw-r--r--Tests/RunCMake/FPHSA/FindNameMismatchSuppressedArg.cmake4
-rw-r--r--Tests/RunCMake/FPHSA/FindNameMismatchSuppressedCompat.cmake6
-rw-r--r--Tests/RunCMake/FPHSA/FindPseudo.cmake6
-rw-r--r--Tests/RunCMake/FPHSA/FindPseudoNoVersionVar.cmake6
-rw-r--r--Tests/RunCMake/FPHSA/FindPseudoRange.cmake7
-rw-r--r--Tests/RunCMake/FPHSA/FindUseComponents.cmake15
-rw-r--r--Tests/RunCMake/FPHSA/NameMismatch-stderr.txt23
-rw-r--r--Tests/RunCMake/FPHSA/NameMismatch.cmake7
-rw-r--r--Tests/RunCMake/FPHSA/RunCMakeTest.cmake67
-rw-r--r--Tests/RunCMake/FPHSA/all_optional_components.cmake14
-rw-r--r--Tests/RunCMake/FPHSA/any_version.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/any_version_VERSION_cache_variable-stdout.txt2
-rw-r--r--Tests/RunCMake/FPHSA/any_version_VERSION_cache_variable.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/any_version_find_0-stdout.txt2
-rw-r--r--Tests/RunCMake/FPHSA/any_version_find_0.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/custom_message_1-result.txt1
-rw-r--r--Tests/RunCMake/FPHSA/custom_message_1-stderr.txt7
-rw-r--r--Tests/RunCMake/FPHSA/custom_message_1.cmake4
-rw-r--r--Tests/RunCMake/FPHSA/custom_message_2-result.txt1
-rw-r--r--Tests/RunCMake/FPHSA/custom_message_2-stderr.txt8
-rw-r--r--Tests/RunCMake/FPHSA/custom_message_2.cmake5
-rw-r--r--Tests/RunCMake/FPHSA/custom_message_3-result.txt1
-rw-r--r--Tests/RunCMake/FPHSA/custom_message_3-stderr.txt9
-rw-r--r--Tests/RunCMake/FPHSA/custom_message_3.cmake5
-rw-r--r--Tests/RunCMake/FPHSA/exact_0-result.txt1
-rw-r--r--Tests/RunCMake/FPHSA/exact_0.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/exact_0_matching.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.1-result.txt1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.1.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.2.2-result.txt1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.2.2.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.2.3.3-result.txt1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.2.3.3.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.2.3.4.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.2.3.5-result.txt1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.2.3.5.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.2.3.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.2.4-result.txt1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.2.4.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.2.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.3-result.txt1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.3.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/exact_1.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/exact_2-result.txt1
-rw-r--r--Tests/RunCMake/FPHSA/exact_2.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/range_1-2-exclude-result.txt1
-rw-r--r--Tests/RunCMake/FPHSA/range_1-2-exclude-stderr.txt2
-rw-r--r--Tests/RunCMake/FPHSA/range_1-2-exclude.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/range_1-2-include.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/range_1-3.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/range_3-4-result.txt1
-rw-r--r--Tests/RunCMake/FPHSA/range_3-4-stderr.txt2
-rw-r--r--Tests/RunCMake/FPHSA/range_3-4.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/range_ignored-stderr.txt4
-rw-r--r--Tests/RunCMake/FPHSA/range_ignored.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/range_no-range.cmake1
-rw-r--r--Tests/RunCMake/FPHSA/required_and_optional_components.cmake14
-rw-r--r--Tests/RunCMake/FPHSA/required_components.cmake11
-rw-r--r--Tests/RunCMake/FPHSA/required_components_with_vars.cmake1
-rw-r--r--Tests/RunCMake/FeatureSummary/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomBadDefault-result.txt1
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomBadDefault-stderr.txt9
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomBadDefault.cmake8
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomDescription-stdout.txt91
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomDescription.cmake158
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomRequired-result.txt1
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomRequired-stderr.txt6
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomRequired-stdout.txt17
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomRequired.cmake16
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomRequiredListA-result.txt1
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomRequiredListA-stderr.txt6
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomRequiredListA-stdout.txt17
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomRequiredListA.cmake16
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomRequiredListB-result.txt1
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomRequiredListB-stderr.txt6
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomRequiredListB-stdout.txt17
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomRequiredListB.cmake16
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomTypes-stdout.txt29
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryCustomTypes.cmake36
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryDefaultDescription-stdout.txt46
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryDefaultDescription.cmake82
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryFatalOnMissingRequiredPackages-result.txt1
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryFatalOnMissingRequiredPackages-stderr.txt6
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryFatalOnMissingRequiredPackages-stdout.txt17
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryFatalOnMissingRequiredPackages.cmake12
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryIncludeQuietPackages-stdout.txt14
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryIncludeQuietPackages.cmake11
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryMultipleDepends-stdout.txt10
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryMultipleDepends.cmake12
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryPurpose-stdout.txt16
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryPurpose.cmake16
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryQuietOnEmpty-stdout.txt5
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryQuietOnEmpty.cmake14
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryTypes-stdout.txt45
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryTypes.cmake48
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryURLDescription-stdout.txt32
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryURLDescription.cmake28
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatAll-stdout.txt7
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatAll.cmake9
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatList-stdout.txt7
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatList.cmake9
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatListAll-result.txt1
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatListAll-stderr.txt6
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatListAll.cmake9
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatListUnknown-result.txt1
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatListUnknown-stderr.txt6
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatListUnknown.cmake9
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatOnce-stdout.txt4
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatOnce.cmake8
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatSingle-stdout.txt1
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatSingle.cmake9
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatSingleUnknown-result.txt1
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatSingleUnknown-stderr.txt6
-rw-r--r--Tests/RunCMake/FeatureSummary/FeatureSummaryWhatSingleUnknown.cmake9
-rw-r--r--Tests/RunCMake/FeatureSummary/FindBar.cmake2
-rw-r--r--Tests/RunCMake/FeatureSummary/FindBaz.cmake2
-rw-r--r--Tests/RunCMake/FeatureSummary/FindFoo.cmake4
-rw-r--r--Tests/RunCMake/FeatureSummary/RunCMakeTest.cmake23
-rw-r--r--Tests/RunCMake/FetchContent/CMakeLists.txt7
-rw-r--r--Tests/RunCMake/FetchContent/DirOverrides.cmake67
-rw-r--r--Tests/RunCMake/FetchContent/DirOverridesDisconnected.cmake18
-rw-r--r--Tests/RunCMake/FetchContent/DirectIgnoresDetails-stdout.txt1
-rw-r--r--Tests/RunCMake/FetchContent/DirectIgnoresDetails.cmake12
-rw-r--r--Tests/RunCMake/FetchContent/DownloadFile.cmake9
-rw-r--r--Tests/RunCMake/FetchContent/DownloadTwice-result.txt1
-rw-r--r--Tests/RunCMake/FetchContent/DownloadTwice-stderr.txt1
-rw-r--r--Tests/RunCMake/FetchContent/DownloadTwice.cmake9
-rw-r--r--Tests/RunCMake/FetchContent/FirstDetailsWin-stdout.txt1
-rw-r--r--Tests/RunCMake/FetchContent/FirstDetailsWin.cmake16
-rw-r--r--Tests/RunCMake/FetchContent/GetProperties.cmake67
-rw-r--r--Tests/RunCMake/FetchContent/MakeAvailable-stdout.txt3
-rw-r--r--Tests/RunCMake/FetchContent/MakeAvailable.cmake29
-rw-r--r--Tests/RunCMake/FetchContent/MakeAvailableTwice-stdout.txt4
-rw-r--r--Tests/RunCMake/FetchContent/MakeAvailableTwice.cmake12
-rw-r--r--Tests/RunCMake/FetchContent/MakeAvailableUndeclared-result.txt1
-rw-r--r--Tests/RunCMake/FetchContent/MakeAvailableUndeclared-stderr.txt1
-rw-r--r--Tests/RunCMake/FetchContent/MakeAvailableUndeclared.cmake3
-rw-r--r--Tests/RunCMake/FetchContent/ManualSourceDirectory.cmake8
-rw-r--r--Tests/RunCMake/FetchContent/ManualSourceDirectoryMissing-result.txt1
-rw-r--r--Tests/RunCMake/FetchContent/ManualSourceDirectoryMissing-stderr.txt2
-rw-r--r--Tests/RunCMake/FetchContent/ManualSourceDirectoryMissing.cmake8
-rw-r--r--Tests/RunCMake/FetchContent/ManualSourceDirectoryRelative-stderr.txt3
-rw-r--r--Tests/RunCMake/FetchContent/ManualSourceDirectoryRelative.cmake1
-rw-r--r--Tests/RunCMake/FetchContent/MissingDetails-result.txt1
-rw-r--r--Tests/RunCMake/FetchContent/MissingDetails-stderr.txt1
-rw-r--r--Tests/RunCMake/FetchContent/MissingDetails.cmake3
-rw-r--r--Tests/RunCMake/FetchContent/PreserveEmptyArgs-stdout.txt4
-rw-r--r--Tests/RunCMake/FetchContent/PreserveEmptyArgs.cmake13
-rw-r--r--Tests/RunCMake/FetchContent/RunCMakeTest.cmake62
-rw-r--r--Tests/RunCMake/FetchContent/SameGenerator.cmake17
-rw-r--r--Tests/RunCMake/FetchContent/ScriptMode.cmake35
-rw-r--r--Tests/RunCMake/FetchContent/UsesTerminalOverride-stdout.txt2
-rw-r--r--Tests/RunCMake/FetchContent/UsesTerminalOverride.cmake17
-rw-r--r--Tests/RunCMake/FetchContent/VarDefinitions.cmake75
-rw-r--r--Tests/RunCMake/FetchContent/WithProject/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/FetchContent/WithoutProject/ProjectSubdir/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/FetchContent/WithoutProject/confirmMessage.cmake1
-rw-r--r--Tests/RunCMake/FetchContent/countArgs.cmake5
-rw-r--r--Tests/RunCMake/FetchContent/dummyFile.txt1
-rw-r--r--Tests/RunCMake/FileAPI/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/FileAPI/ClientStateful-check.cmake68
-rw-r--r--Tests/RunCMake/FileAPI/ClientStateful-check.py258
-rw-r--r--Tests/RunCMake/FileAPI/ClientStateful-prep.cmake73
-rw-r--r--Tests/RunCMake/FileAPI/ClientStateful.cmake0
-rw-r--r--Tests/RunCMake/FileAPI/ClientStateless-check.cmake15
-rw-r--r--Tests/RunCMake/FileAPI/ClientStateless-check.py26
-rw-r--r--Tests/RunCMake/FileAPI/ClientStateless-prep.cmake5
-rw-r--r--Tests/RunCMake/FileAPI/ClientStateless.cmake0
-rw-r--r--Tests/RunCMake/FileAPI/DuplicateStateless-check.cmake20
-rw-r--r--Tests/RunCMake/FileAPI/DuplicateStateless-check.py31
-rw-r--r--Tests/RunCMake/FileAPI/DuplicateStateless-prep.cmake10
-rw-r--r--Tests/RunCMake/FileAPI/DuplicateStateless.cmake0
-rw-r--r--Tests/RunCMake/FileAPI/Empty-check.cmake8
-rw-r--r--Tests/RunCMake/FileAPI/Empty-check.py15
-rw-r--r--Tests/RunCMake/FileAPI/Empty-prep.cmake1
-rw-r--r--Tests/RunCMake/FileAPI/Empty.cmake0
-rw-r--r--Tests/RunCMake/FileAPI/EmptyClient-check.cmake9
-rw-r--r--Tests/RunCMake/FileAPI/EmptyClient-check.py20
-rw-r--r--Tests/RunCMake/FileAPI/EmptyClient-prep.cmake2
-rw-r--r--Tests/RunCMake/FileAPI/EmptyClient.cmake0
-rw-r--r--Tests/RunCMake/FileAPI/MixedStateless-check.cmake16
-rw-r--r--Tests/RunCMake/FileAPI/MixedStateless-check.py27
-rw-r--r--Tests/RunCMake/FileAPI/MixedStateless-prep.cmake6
-rw-r--r--Tests/RunCMake/FileAPI/MixedStateless.cmake0
-rw-r--r--Tests/RunCMake/FileAPI/Nothing-check.cmake1
-rw-r--r--Tests/RunCMake/FileAPI/Nothing-prep.cmake1
-rw-r--r--Tests/RunCMake/FileAPI/Nothing.cmake0
-rw-r--r--Tests/RunCMake/FileAPI/RunCMakeTest.cmake66
-rw-r--r--Tests/RunCMake/FileAPI/SharedStateless-check.cmake15
-rw-r--r--Tests/RunCMake/FileAPI/SharedStateless-check.py22
-rw-r--r--Tests/RunCMake/FileAPI/SharedStateless-prep.cmake6
-rw-r--r--Tests/RunCMake/FileAPI/SharedStateless.cmake0
-rw-r--r--Tests/RunCMake/FileAPI/Stale-check.cmake4
-rw-r--r--Tests/RunCMake/FileAPI/Stale-prep.cmake1
-rw-r--r--Tests/RunCMake/FileAPI/Stale.cmake0
-rw-r--r--Tests/RunCMake/FileAPI/alias/CMakeLists.txt10
-rw-r--r--Tests/RunCMake/FileAPI/cache-v2-ClientStateful-check.cmake11
-rw-r--r--Tests/RunCMake/FileAPI/cache-v2-ClientStateful-prep.cmake4
-rw-r--r--Tests/RunCMake/FileAPI/cache-v2-ClientStateless-check.cmake11
-rw-r--r--Tests/RunCMake/FileAPI/cache-v2-ClientStateless-prep.cmake2
-rw-r--r--Tests/RunCMake/FileAPI/cache-v2-SharedStateless-check.cmake10
-rw-r--r--Tests/RunCMake/FileAPI/cache-v2-SharedStateless-prep.cmake2
-rw-r--r--Tests/RunCMake/FileAPI/cache-v2-check.py134
-rw-r--r--Tests/RunCMake/FileAPI/cache-v2.cmake14
-rw-r--r--Tests/RunCMake/FileAPI/check_index.py164
-rw-r--r--Tests/RunCMake/FileAPI/cmakeFiles-v1-ClientStateful-check.cmake11
-rw-r--r--Tests/RunCMake/FileAPI/cmakeFiles-v1-ClientStateful-prep.cmake4
-rw-r--r--Tests/RunCMake/FileAPI/cmakeFiles-v1-ClientStateless-check.cmake11
-rw-r--r--Tests/RunCMake/FileAPI/cmakeFiles-v1-ClientStateless-prep.cmake2
-rw-r--r--Tests/RunCMake/FileAPI/cmakeFiles-v1-SharedStateless-check.cmake10
-rw-r--r--Tests/RunCMake/FileAPI/cmakeFiles-v1-SharedStateless-prep.cmake2
-rw-r--r--Tests/RunCMake/FileAPI/cmakeFiles-v1-check.py94
-rw-r--r--Tests/RunCMake/FileAPI/cmakeFiles-v1.cmake8
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-ClientStateful-check.cmake13
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-ClientStateful-prep.cmake4
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-ClientStateless-check.cmake13
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-ClientStateless-prep.cmake2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-SharedStateless-check.cmake12
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-SharedStateless-prep.cmake2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-check.py899
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/directories/alias.json16
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/directories/custom.json16
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json22
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir.json13
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir_dir.json11
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/directories/external.json78
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json19
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/directories/interface.json15
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/directories/object.json81
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/directories/top.json573
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/projects/alias.json14
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/projects/codemodel-v2.json29
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/projects/custom.json14
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/projects/cxx.json20
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/projects/external.json13
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/projects/imported.json17
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/projects/interface.json13
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/projects/object.json16
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_alias.json83
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_custom.json79
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_cxx.json107
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_external.json79
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_imported.json95
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_interface.json79
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_object.json91
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_top.json191
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_alias_exe.json107
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_exe.json143
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_lib.json108
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_exe.json154
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_lib.json82
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_exe.json143
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json216
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_exe.json143
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_lib.json108
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/custom_exe.json107
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/custom_tgt.json87
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_alias_exe.json107
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json232
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader.json161
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader_2arch.json237
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader_multigen.json206
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_lib.json84
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_exe.json154
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_lib.json82
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_exe.json107
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json192
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_compile_feature_exe.json110
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_compile_feature_exe_languagestandard.json36
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_exe.json110
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_static_exe.json107
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_static_lib.json84
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/generated_exe.json303
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/iface_srcs.json67
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/interface_exe.json152
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_exe.json90
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_interface_exe.json90
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_object_exe.json90
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_shared_exe.json90
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_static_exe.json90
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_alias.json70
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_custom.json70
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_cxx.json70
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_external.json70
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_imported.json70
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_interface.json70
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_object.json70
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_top.json70
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2.cmake53
-rw-r--r--Tests/RunCMake/FileAPI/custom/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/FileAPI/cxx/CMakeLists.txt32
-rw-r--r--Tests/RunCMake/FileAPI/dir/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/FileAPI/dir/dir/CMakeLists.txt0
-rw-r--r--Tests/RunCMake/FileAPI/dir/dirtest.cmake0
-rw-r--r--Tests/RunCMake/FileAPI/empty.c0
-rw-r--r--Tests/RunCMake/FileAPI/empty.cxx0
-rw-r--r--Tests/RunCMake/FileAPI/empty.h0
-rw-r--r--Tests/RunCMake/FileAPI/imported/CMakeLists.txt30
-rw-r--r--Tests/RunCMake/FileAPI/include_test.cmake9
-rw-r--r--Tests/RunCMake/FileAPI/interface/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/FileAPI/object/CMakeLists.txt13
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake11
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake4
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake11
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake2
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake10
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake2
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1-check.py86
-rw-r--r--Tests/RunCMake/FileAPI/toolchains-v1.cmake22
-rw-r--r--Tests/RunCMake/FileAPIDummyFile.cmake0
-rw-r--r--Tests/RunCMake/FileAPIExternalSource/CMakeLists.txt16
-rw-r--r--Tests/RunCMake/FileAPIExternalSource/empty.c0
-rw-r--r--Tests/RunCMake/File_Archive/7zip-with-bad-compression-result.txt1
-rw-r--r--Tests/RunCMake/File_Archive/7zip-with-bad-compression-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Archive/7zip-with-bad-compression.cmake6
-rw-r--r--Tests/RunCMake/File_Archive/7zip.cmake7
-rw-r--r--Tests/RunCMake/File_Archive/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/File_Archive/RunCMakeTest.cmake26
-rw-r--r--Tests/RunCMake/File_Archive/argument-validation-compression-level-1-result.txt1
-rw-r--r--Tests/RunCMake/File_Archive/argument-validation-compression-level-1-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Archive/argument-validation-compression-level-1.cmake8
-rw-r--r--Tests/RunCMake/File_Archive/argument-validation-compression-level-2-result.txt1
-rw-r--r--Tests/RunCMake/File_Archive/argument-validation-compression-level-2-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Archive/argument-validation-compression-level-2.cmake8
-rw-r--r--Tests/RunCMake/File_Archive/compression-level.cmake85
-rw-r--r--Tests/RunCMake/File_Archive/gnutar-gz-compression-level.cmake10
-rw-r--r--Tests/RunCMake/File_Archive/gnutar-gz.cmake8
-rw-r--r--Tests/RunCMake/File_Archive/gnutar.cmake7
-rw-r--r--Tests/RunCMake/File_Archive/pax-xz-compression-level.cmake10
-rw-r--r--Tests/RunCMake/File_Archive/pax-xz.cmake8
-rw-r--r--Tests/RunCMake/File_Archive/pax-zstd-compression-level.cmake10
-rw-r--r--Tests/RunCMake/File_Archive/pax-zstd.cmake8
-rw-r--r--Tests/RunCMake/File_Archive/pax.cmake7
-rw-r--r--Tests/RunCMake/File_Archive/paxr-bz2-compression-level.cmake10
-rw-r--r--Tests/RunCMake/File_Archive/paxr-bz2.cmake8
-rw-r--r--Tests/RunCMake/File_Archive/paxr.cmake7
-rw-r--r--Tests/RunCMake/File_Archive/roundtrip.cmake109
-rw-r--r--Tests/RunCMake/File_Archive/unsupported-compression-level-result.txt1
-rw-r--r--Tests/RunCMake/File_Archive/unsupported-compression-level-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Archive/unsupported-compression-level.cmake7
-rw-r--r--Tests/RunCMake/File_Archive/unsupported-format-result.txt1
-rw-r--r--Tests/RunCMake/File_Archive/unsupported-format-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Archive/unsupported-format.cmake5
-rw-r--r--Tests/RunCMake/File_Archive/zip-filtered.cmake26
-rw-r--r--Tests/RunCMake/File_Archive/zip-with-bad-compression-result.txt1
-rw-r--r--Tests/RunCMake/File_Archive/zip-with-bad-compression-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Archive/zip-with-bad-compression.cmake6
-rw-r--r--Tests/RunCMake/File_Archive/zip.cmake7
-rw-r--r--Tests/RunCMake/File_Configure/AngleBracketsContent-stderr.txt1
-rw-r--r--Tests/RunCMake/File_Configure/AngleBracketsContent.cmake6
-rw-r--r--Tests/RunCMake/File_Configure/AtOnly.cmake12
-rw-r--r--Tests/RunCMake/File_Configure/BadArgContent-result.txt0
-rw-r--r--Tests/RunCMake/File_Configure/BadArgContent-stderr.txt4
-rw-r--r--Tests/RunCMake/File_Configure/BadArgContent.cmake1
-rw-r--r--Tests/RunCMake/File_Configure/BadArgGeneratorExpressionOutput-result.txt1
-rw-r--r--Tests/RunCMake/File_Configure/BadArgGeneratorExpressionOutput-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Configure/BadArgGeneratorExpressionOutput.cmake4
-rw-r--r--Tests/RunCMake/File_Configure/BadArgOutput-result.txt1
-rw-r--r--Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt4
-rw-r--r--Tests/RunCMake/File_Configure/BadArgOutput.cmake1
-rw-r--r--Tests/RunCMake/File_Configure/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/File_Configure/DirOutput-stderr.txt1
-rw-r--r--Tests/RunCMake/File_Configure/DirOutput.cmake4
-rw-r--r--Tests/RunCMake/File_Configure/DirOutput.txt1
-rw-r--r--Tests/RunCMake/File_Configure/EscapeQuotes.cmake12
-rw-r--r--Tests/RunCMake/File_Configure/NewLineStyle-NoArg-result.txt1
-rw-r--r--Tests/RunCMake/File_Configure/NewLineStyle-NoArg-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Configure/NewLineStyle-NoArg.cmake6
-rw-r--r--Tests/RunCMake/File_Configure/NewLineStyle-ValidArg.cmake29
-rw-r--r--Tests/RunCMake/File_Configure/NewLineStyle-WrongArg-result.txt1
-rw-r--r--Tests/RunCMake/File_Configure/NewLineStyle-WrongArg-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Configure/NewLineStyle-WrongArg.cmake6
-rw-r--r--Tests/RunCMake/File_Configure/RunCMakeTest.cmake14
-rw-r--r--Tests/RunCMake/File_Configure/SubDir-check.cmake4
-rw-r--r--Tests/RunCMake/File_Configure/SubDir.cmake1
-rw-r--r--Tests/RunCMake/File_Configure/SubDir/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/File_Configure/UnrecognizedArgs-result.txt1
-rw-r--r--Tests/RunCMake/File_Configure/UnrecognizedArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/File_Configure/UnrecognizedArgs.cmake1
-rw-r--r--Tests/RunCMake/File_Generate/AdjacentInOut.cmake6
-rw-r--r--Tests/RunCMake/File_Generate/AdjacentInOut.in1
-rw-r--r--Tests/RunCMake/File_Generate/BadCondition-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/BadCondition-stderr.txt3
-rw-r--r--Tests/RunCMake/File_Generate/BadCondition.cmake5
-rw-r--r--Tests/RunCMake/File_Generate/CMP0070-NEW-check.cmake13
-rw-r--r--Tests/RunCMake/File_Generate/CMP0070-NEW.cmake2
-rw-r--r--Tests/RunCMake/File_Generate/CMP0070-OLD-check.cmake13
-rw-r--r--Tests/RunCMake/File_Generate/CMP0070-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/File_Generate/CMP0070-OLD.cmake3
-rw-r--r--Tests/RunCMake/File_Generate/CMP0070-WARN-check.cmake13
-rw-r--r--Tests/RunCMake/File_Generate/CMP0070-WARN-stderr.txt41
-rw-r--r--Tests/RunCMake/File_Generate/CMP0070-WARN.cmake2
-rw-r--r--Tests/RunCMake/File_Generate/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/File_Generate/COMPILE_LANGUAGE-genex.cmake6
-rw-r--r--Tests/RunCMake/File_Generate/CarryPermissions.cmake5
-rw-r--r--Tests/RunCMake/File_Generate/CommandConflict-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/CommandConflict-stderr.txt1
-rw-r--r--Tests/RunCMake/File_Generate/CommandConflict.cmake9
-rw-r--r--Tests/RunCMake/File_Generate/CustomFilePermissions.cmake15
-rw-r--r--Tests/RunCMake/File_Generate/CustomFilePermissionsVerify.cmake36
-rw-r--r--Tests/RunCMake/File_Generate/DebugEvaluate.cmake5
-rw-r--r--Tests/RunCMake/File_Generate/EmptyCondition1-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/EmptyCondition1-stderr.txt4
-rw-r--r--Tests/RunCMake/File_Generate/EmptyCondition1.cmake5
-rw-r--r--Tests/RunCMake/File_Generate/EmptyCondition2-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/EmptyCondition2-stderr.txt4
-rw-r--r--Tests/RunCMake/File_Generate/EmptyCondition2.cmake5
-rw-r--r--Tests/RunCMake/File_Generate/GenerateSource.cmake15
-rw-r--r--Tests/RunCMake/File_Generate/GenerateSource/CMakeLists.txt8
-rw-r--r--Tests/RunCMake/File_Generate/NewLineStyle-Default.cmake35
-rw-r--r--Tests/RunCMake/File_Generate/NewLineStyle-InvalidArg-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/NewLineStyle-InvalidArg-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Generate/NewLineStyle-InvalidArg.cmake7
-rw-r--r--Tests/RunCMake/File_Generate/NewLineStyle-NoArg-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/NewLineStyle-NoArg-stderr.txt4
-rw-r--r--Tests/RunCMake/File_Generate/NewLineStyle-NoArg.cmake7
-rw-r--r--Tests/RunCMake/File_Generate/NewLineStyle-Unix.cmake33
-rw-r--r--Tests/RunCMake/File_Generate/NewLineStyle-Win32.cmake33
-rw-r--r--Tests/RunCMake/File_Generate/NoSourcePermissions.cmake10
-rw-r--r--Tests/RunCMake/File_Generate/NoSourcePermissionsVerify.cmake36
-rw-r--r--Tests/RunCMake/File_Generate/OutputConflict-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/OutputConflict-stderr.txt6
-rw-r--r--Tests/RunCMake/File_Generate/OutputConflict.cmake4
-rw-r--r--Tests/RunCMake/File_Generate/OutputNameMatchesObjects-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt9
-rw-r--r--Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake8
-rw-r--r--Tests/RunCMake/File_Generate/OutputNameMatchesOtherSources.cmake14
-rw-r--r--Tests/RunCMake/File_Generate/OutputNameMatchesSources-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/OutputNameMatchesSources-stderr.txt7
-rw-r--r--Tests/RunCMake/File_Generate/OutputNameMatchesSources.cmake12
-rw-r--r--Tests/RunCMake/File_Generate/ReRunCMake.cmake5
-rw-r--r--Tests/RunCMake/File_Generate/RunCMakeTest.cmake157
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions1-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions1-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions1.cmake5
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions2-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions2-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions2.cmake5
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions3-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions3-stderr.txt5
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions3.cmake5
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions4-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions4-stderr.txt4
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions4.cmake4
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions5-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions5-stderr.txt4
-rw-r--r--Tests/RunCMake/File_Generate/SourcePermissions5.cmake4
-rw-r--r--Tests/RunCMake/File_Generate/SourceProperty-CMP0070-NEW-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/SourceProperty-CMP0070-NEW-stderr.txt11
-rw-r--r--Tests/RunCMake/File_Generate/SourceProperty-CMP0070-NEW.cmake8
-rw-r--r--Tests/RunCMake/File_Generate/SourceProperty-CMP0070-OLD-result.txt1
-rw-r--r--Tests/RunCMake/File_Generate/SourceProperty-CMP0070-OLD-stderr.txt23
-rw-r--r--Tests/RunCMake/File_Generate/SourceProperty-CMP0070-OLD.cmake8
-rw-r--r--Tests/RunCMake/File_Generate/SourceProperty-stderr.txt10
-rw-r--r--Tests/RunCMake/File_Generate/SourceProperty.cmake14
-rw-r--r--Tests/RunCMake/File_Generate/Target.cmake2
-rw-r--r--Tests/RunCMake/File_Generate/UseSourcePermissions.cmake11
-rw-r--r--Tests/RunCMake/File_Generate/UseSourcePermissionsVerify.cmake51
-rw-r--r--Tests/RunCMake/File_Generate/VerifyContent.cmake4
-rw-r--r--Tests/RunCMake/File_Generate/WriteIfDifferent.cmake5
-rw-r--r--Tests/RunCMake/File_Generate/empty.c8
-rw-r--r--Tests/RunCMake/File_Generate/empty.cpp7
-rw-r--r--Tests/RunCMake/File_Generate/input.txt1
-rwxr-xr-xTests/RunCMake/File_Generate/input_script.sh3
-rw-r--r--Tests/RunCMake/File_Generate/relative-input-NEW.txt1
-rw-r--r--Tests/RunCMake/File_Generate/sub1/CMakeLists.txt7
-rw-r--r--Tests/RunCMake/File_Generate/sub2/CMakeLists.txt7
-rw-r--r--Tests/RunCMake/FindBoost/CMP0093-NEW-stdout.txt1
-rw-r--r--Tests/RunCMake/FindBoost/CMP0093-NEW.cmake2
-rw-r--r--Tests/RunCMake/FindBoost/CMP0093-OLD-stdout.txt1
-rw-r--r--Tests/RunCMake/FindBoost/CMP0093-OLD.cmake2
-rw-r--r--Tests/RunCMake/FindBoost/CMP0093-UNSET-stdout.txt1
-rw-r--r--Tests/RunCMake/FindBoost/CMP0093-UNSET.cmake1
-rw-r--r--Tests/RunCMake/FindBoost/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage-stdout.txt2
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage.cmake2
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage/BoostConfig.cmake4
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage/BoostConfigVersion.cmake7
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/Boost-1.70.0/BoostConfig.cmake140
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/Boost-1.70.0/BoostConfigVersion.cmake12
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/BoostDetectToolset-1.70.0.cmake1
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/boost_chrono-config-version.cmake12
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/boost_chrono-config.cmake98
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/libboost_chrono-variant-shared.cmake62
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_chrono-1.70.0/libboost_chrono-variant-static.cmake58
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_headers-1.70.0/boost_headers-config-version.cmake12
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_headers-1.70.0/boost_headers-config.cmake20
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/boost_system-config-version.cmake12
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/boost_system-config.cmake98
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/libboost_system-variant-shared.cmake62
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_system-1.70.0/libboost_system-variant-static.cmake58
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/boost_timer-config-version.cmake12
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/boost_timer-config.cmake98
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/libboost_timer-variant-shared.cmake62
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackageFixtures/boost_timer-1.70.0/libboost_timer-variant-static.cmake58
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/BoostConfig.cmake26
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/BoostConfigVersion.cmake7
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_LowerCaseTargetPrefix/include/boost/version.hpp34
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/BoostConfig.cmake7
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/BoostConfigVersion.cmake7
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_MissingTarget/include/boost/version.hpp34
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_New/BoostConfig.cmake29
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_New/BoostConfigVersion.cmake7
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_New/include/boost/version.hpp34
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_date_time.a0
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_mpi_python.a0
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_python.a0
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_New/lib/libboost_python_release.a0
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/BoostConfig.cmake25
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/BoostConfigVersion.cmake7
-rw-r--r--Tests/RunCMake/FindBoost/CMakePackage_NoHeaderTarget/include/boost/version.hpp34
-rw-r--r--Tests/RunCMake/FindBoost/CommonNotFound-stderr.txt1
-rw-r--r--Tests/RunCMake/FindBoost/CommonNotFound-stdout.txt1
-rw-r--r--Tests/RunCMake/FindBoost/CommonNotFound.cmake2
-rw-r--r--Tests/RunCMake/FindBoost/CommonResults-stdout.txt13
-rw-r--r--Tests/RunCMake/FindBoost/CommonResults.cmake25
-rw-r--r--Tests/RunCMake/FindBoost/ConfigMode.cmake2
-rw-r--r--Tests/RunCMake/FindBoost/ConfigModeNotFound.cmake2
-rw-r--r--Tests/RunCMake/FindBoost/LegacyVars-LowercaseTargetPrefix-stdout.txt34
-rw-r--r--Tests/RunCMake/FindBoost/LegacyVars-LowercaseTargetPrefix.cmake6
-rw-r--r--Tests/RunCMake/FindBoost/LegacyVars-NoHeaderTarget.cmake6
-rw-r--r--Tests/RunCMake/FindBoost/LegacyVars-TargetsDefined-stdout.txt34
-rw-r--r--Tests/RunCMake/FindBoost/LegacyVars-TargetsDefined.cmake6
-rw-r--r--Tests/RunCMake/FindBoost/LegacyVars.cmake28
-rw-r--r--Tests/RunCMake/FindBoost/MissingTarget-stdout.txt22
-rw-r--r--Tests/RunCMake/FindBoost/MissingTarget.cmake25
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/chrono.hpp0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/config.hpp0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/system/config.hpp0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/timer.hpp0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/include/boost/version.hpp34
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_chrono-mt-1_70.lib0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_system-mt-1_70.lib0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/boost_timer-mt-1_70.lib0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono-mt-1_70.lib0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono.a0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_chrono.so.1.70.00
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system-mt-1_70.lib0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system.a0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_system.so.1.70.00
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer-mt-1_70.lib0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer.a0
-rw-r--r--Tests/RunCMake/FindBoost/MockInstalls/1.70.0/lib/libboost_timer.so.1.70.00
-rw-r--r--Tests/RunCMake/FindBoost/ModuleMode.cmake4
-rw-r--r--Tests/RunCMake/FindBoost/ModuleModeNotFound.cmake4
-rw-r--r--Tests/RunCMake/FindBoost/NoCXX-stderr.txt1
-rw-r--r--Tests/RunCMake/FindBoost/NoCXX.cmake1
-rw-r--r--Tests/RunCMake/FindBoost/RunCMakeTest.cmake28
-rw-r--r--Tests/RunCMake/FindGTK2/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/FindGTK2/FindGTK2RunTwice.cmake21
-rw-r--r--Tests/RunCMake/FindGTK2/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/FindLua/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/FindLua/FindLuaTest.cmake87
-rw-r--r--Tests/RunCMake/FindLua/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/FindLua/prefix1/include/lua.h8
-rw-r--r--Tests/RunCMake/FindLua/prefix2/include/lua5.1/lua.h8
-rw-r--r--Tests/RunCMake/FindLua/prefix2/include/lua5.2/lua.h8
-rw-r--r--Tests/RunCMake/FindLua/prefix2/include/lua5.3/lua.h8
-rw-r--r--Tests/RunCMake/FindLua/prefix2/include/lua5.9/lua.h8
-rw-r--r--Tests/RunCMake/FindMatlab/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/FindMatlab/MatlabTest1-result.txt1
-rw-r--r--Tests/RunCMake/FindMatlab/MatlabTest1-stderr.txt2
-rw-r--r--Tests/RunCMake/FindMatlab/MatlabTest1.cmake25
-rw-r--r--Tests/RunCMake/FindMatlab/MatlabTest2-result.txt1
-rw-r--r--Tests/RunCMake/FindMatlab/MatlabTest2-stderr.txt1
-rw-r--r--Tests/RunCMake/FindMatlab/MatlabTest2.cmake13
-rw-r--r--Tests/RunCMake/FindMatlab/RunCMakeTest.cmake62
-rw-r--r--Tests/RunCMake/FindMatlab/cmake_matlab_unit_tests2.m6
-rw-r--r--Tests/RunCMake/FindMatlab/matlab_wrapper1.cpp27
-rw-r--r--Tests/RunCMake/FindOpenGL/CMP0072-NEW-stdout.txt3
-rw-r--r--Tests/RunCMake/FindOpenGL/CMP0072-NEW.cmake2
-rw-r--r--Tests/RunCMake/FindOpenGL/CMP0072-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/FindOpenGL/CMP0072-OLD-stdout.txt3
-rw-r--r--Tests/RunCMake/FindOpenGL/CMP0072-OLD.cmake2
-rw-r--r--Tests/RunCMake/FindOpenGL/CMP0072-WARN-stderr.txt21
-rw-r--r--Tests/RunCMake/FindOpenGL/CMP0072-WARN-stdout.txt3
-rw-r--r--Tests/RunCMake/FindOpenGL/CMP0072-WARN.cmake1
-rw-r--r--Tests/RunCMake/FindOpenGL/CMP0072-common.cmake13
-rw-r--r--Tests/RunCMake/FindOpenGL/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/FindOpenGL/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/FindOpenSSL/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/FindOpenSSL/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/FindOpenSSL/version-exact.cmake19
-rw-r--r--Tests/RunCMake/FindOpenSSL/version-range.cmake37
-rw-r--r--Tests/RunCMake/FindOpenSSL/version.cmake19
-rw-r--r--Tests/RunCMake/FindPkgConfig/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_CMAKE_APPBUNDLE_PATH.cmake19
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_CMAKE_FRAMEWORK_PATH.cmake19
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_MATCHING_MODULE_NAME.cmake28
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE-stdout.txt1
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE.cmake9
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PKGCONFIG_PATH.cmake21
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_VARIABLE_PREFIX_PATH.cmake21
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake135
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_NO_PKGCONFIG_PATH.cmake38
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_PKGCONFIG_PATH.cmake59
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_ENVIRONMENT_PATH.cmake59
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_PATH.cmake59
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_VERSION_OPERATORS.cmake83
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_cache_variables.cmake17
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_extract_frameworks.cmake13
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_extract_frameworks_target.cmake29
-rw-r--r--Tests/RunCMake/FindPkgConfig/PkgConfigDoesNotExist-stdout.txt6
-rw-r--r--Tests/RunCMake/FindPkgConfig/PkgConfigDoesNotExist.cmake4
-rw-r--r--Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake32
-rwxr-xr-xTests/RunCMake/FindPkgConfig/dummy-pkg-config.bat27
-rwxr-xr-xTests/RunCMake/FindPkgConfig/dummy-pkg-config.sh23
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-bar/lib/i386-linux-gnu/pkgconfig/.placeholder0
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-bar/lib/pkgconfig/.placeholder0
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-bar/lib/x86_64-linux-gnu/pkgconfig/.placeholder0
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-bar/lib32/pkgconfig/.placeholder0
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-bar/lib64/pkgconfig/.placeholder0
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-bar/libx32/pkgconfig/.placeholder0
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-bletch/lib/pkgconfig/bletch-framework.pc9
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-bletch/lib/pkgconfig/bletch.pc12
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-foo/lib/i386-linux-gnu/pkgconfig/.placeholder0
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-foo/lib/pkgconfig/.placeholder0
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-foo/lib/x86_64-linux-gnu/pkgconfig/.placeholder0
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-foo/lib32/pkgconfig/.placeholder0
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-foo/lib64/pkgconfig/.placeholder0
-rw-r--r--Tests/RunCMake/FindPkgConfig/pc-foo/libx32/pkgconfig/.placeholder0
-rw-r--r--Tests/RunCMake/FindPkgConfig/target_subdir/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/FindSWIG/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/FindSWIG/RunCMakeTest.cmake7
-rw-r--r--Tests/RunCMake/FindSWIG/components-stdout.txt6
-rw-r--r--Tests/RunCMake/FindSWIG/components.cmake9
-rw-r--r--Tests/RunCMake/FindSWIG/missing-components-result.txt1
-rw-r--r--Tests/RunCMake/FindSWIG/missing-components-stderr.txt1
-rw-r--r--Tests/RunCMake/FindSWIG/missing-components.cmake3
-rw-r--r--Tests/RunCMake/FindSWIG/version-exact.cmake17
-rw-r--r--Tests/RunCMake/FindSWIG/version-range.cmake30
-rw-r--r--Tests/RunCMake/FindSWIG/version.cmake6
-rw-r--r--Tests/RunCMake/Framework/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Framework/FrameworkLayout.cmake28
-rw-r--r--Tests/RunCMake/Framework/FrameworkMultiConfigPostfix-build-final-check.cmake45
-rw-r--r--Tests/RunCMake/Framework/FrameworkMultiConfigPostfix.cmake25
-rw-r--r--Tests/RunCMake/Framework/FrameworkTypeSHARED-build-stdout.txt2
-rw-r--r--Tests/RunCMake/Framework/FrameworkTypeSTATIC-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Framework/InstallBeforeFramework-stderr.txt7
-rw-r--r--Tests/RunCMake/Framework/InstallBeforeFramework.cmake5
-rw-r--r--Tests/RunCMake/Framework/OSXFrameworkLayout-build-check.cmake50
-rw-r--r--Tests/RunCMake/Framework/RunCMakeTest.cmake83
-rw-r--r--Tests/RunCMake/Framework/deepresource.txt0
-rw-r--r--Tests/RunCMake/Framework/flatresource.txt0
-rw-r--r--Tests/RunCMake/Framework/foo.c4
-rw-r--r--Tests/RunCMake/Framework/foo.h1
-rw-r--r--Tests/RunCMake/Framework/iOSFrameworkLayout-build-check.cmake50
-rw-r--r--Tests/RunCMake/Framework/ios.cmake35
-rw-r--r--Tests/RunCMake/Framework/osx.cmake18
-rw-r--r--Tests/RunCMake/Framework/res.txt0
-rw-r--r--Tests/RunCMake/Framework/some.txt0
-rw-r--r--Tests/RunCMake/GNUInstallDirs/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Common.cmake26
-rw-r--r--Tests/RunCMake/GNUInstallDirs/GetAbs-stderr.txt12
-rw-r--r--Tests/RunCMake/GNUInstallDirs/GetAbs.cmake11
-rw-r--r--Tests/RunCMake/GNUInstallDirs/NoSystem-stderr.txt8
-rw-r--r--Tests/RunCMake/GNUInstallDirs/NoSystem.cmake2
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Opt-BSD-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Opt-Debian-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Opt-FreeBSD-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Opt-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Opt.cmake2
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Root-BSD-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Root-Debian-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Root-FreeBSD-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Root-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Root.cmake2
-rw-r--r--Tests/RunCMake/GNUInstallDirs/RunCMakeTest.cmake25
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Usr-BSD-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Usr-Debian-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Usr-FreeBSD-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Usr-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/Usr.cmake2
-rw-r--r--Tests/RunCMake/GNUInstallDirs/UsrLocal-BSD-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/UsrLocal-Debian-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/UsrLocal-FreeBSD-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/UsrLocal-stderr.txt30
-rw-r--r--Tests/RunCMake/GNUInstallDirs/UsrLocal.cmake2
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-TARGET_PROPERTY.cmake17
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_custom_command-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_custom_command-stderr.txt10
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_custom_command.cmake4
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_custom_target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_custom_target-stderr.txt10
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_custom_target.cmake3
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_executable-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_executable-stderr.txt10
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_executable.cmake1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_library-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_library-stderr.txt10
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_library.cmake1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_test-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_test-stderr.txt10
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-add_test.cmake5
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-install-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-install-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-install.cmake5
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-target_sources-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-target_sources-stderr.txt10
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-target_sources.cmake2
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-unknown-lang.cmake4
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/RunCMakeTest.cmake11
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANGUAGE/empty.c0
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-TARGET_PROPERTY.cmake17
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_custom_command-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_custom_command-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_custom_command.cmake4
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_custom_target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_custom_target-stderr.txt11
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_custom_target.cmake4
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_executable-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_executable-stderr.txt11
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_executable.cmake5
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_library-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_library-stderr.txt11
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_library.cmake2
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_test-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_test-stderr.txt11
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-add_test.cmake5
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-install-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-install-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-install.cmake5
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-target_sources-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-target_sources-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-target_sources.cmake2
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-unknown-lang.cmake4
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/RunCMakeTest.cmake11
-rw-r--r--Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/empty.c0
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_custom_command-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_custom_command-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_custom_command.cmake4
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_custom_target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_custom_target-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_custom_target.cmake3
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_executable-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_executable-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_executable.cmake1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_library-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_library-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_library.cmake1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_test-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_test-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-add_test.cmake5
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-install-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-install-stderr.txt7
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-install.cmake5
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-link_depends-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-link_depends-stderr.txt7
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-link_depends.cmake7
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_compile_definitions-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_compile_definitions-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_compile_definitions.cmake4
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_compile_options-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_compile_options-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_compile_options.cmake4
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_include_directories-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_include_directories-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_include_directories.cmake4
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_link_directories-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_link_directories-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_link_directories.cmake7
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_link_libraries-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_link_libraries-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_link_libraries.cmake7
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_sources-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_sources-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-target_sources.cmake2
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/DEVICE_LINK-try_compile.cmake9
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/RunCMakeTest.cmake18
-rw-r--r--Tests/RunCMake/GenEx-DEVICE_LINK/empty.c0
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/GENEX_EVAL-check.cmake6
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/GENEX_EVAL-recursion1-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/GENEX_EVAL-recursion1-stderr.txt26
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/GENEX_EVAL-recursion1.cmake9
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/GENEX_EVAL-recursion2-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/GENEX_EVAL-recursion2-stderr.txt26
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/GENEX_EVAL-recursion2.cmake10
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/GENEX_EVAL.cmake12
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/RunCMakeTest.cmake11
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-check.cmake6
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-no-arg-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-no-arg.cmake7
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-no-target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-no-target-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-no-target.cmake5
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-non-valid-target-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-non-valid-target.cmake5
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-recursion1-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-recursion1-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-recursion1.cmake9
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-recursion2-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-recursion2-stderr.txt26
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL-recursion2.cmake12
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/TARGET_GENEX_EVAL.cmake10
-rw-r--r--Tests/RunCMake/GenEx-GENEX_EVAL/empty.c0
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_custom_command-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_custom_command-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_custom_command.cmake4
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_custom_target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_custom_target-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_custom_target.cmake3
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_executable-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_executable-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_executable.cmake1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_library-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_library-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_library.cmake1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_test-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_test-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-add_test.cmake5
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-install-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-install-stderr.txt7
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-install.cmake5
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-link_depends-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-link_depends-stderr.txt7
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-link_depends.cmake7
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_compile_definitions-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_compile_definitions-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_compile_definitions.cmake4
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_compile_options-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_compile_options-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_compile_options.cmake4
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_include_directories-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_include_directories-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_include_directories.cmake4
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_link_directories-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_link_directories-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_link_directories.cmake7
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_link_libraries-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_link_libraries-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_link_libraries.cmake7
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_sources-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_sources-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-target_sources.cmake2
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/HOST_LINK-try_compile.cmake9
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/RunCMakeTest.cmake18
-rw-r--r--Tests/RunCMake/GenEx-HOST_LINK/empty.c0
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_custom_command-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_custom_command-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_custom_command.cmake4
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_custom_target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_custom_target-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_custom_target.cmake3
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_executable-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_executable-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_executable.cmake1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_library-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_library-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_library.cmake1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_test-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_test-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-add_test.cmake5
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-file_generate-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-file_generate-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-file_generate.cmake6
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-install-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-install-stderr.txt10
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-install.cmake5
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-target_sources-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-target_sources-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-target_sources.cmake2
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-unknown-lang.cmake4
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-wrong-usage1-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-wrong-usage1-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-wrong-usage1.cmake4
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-wrong-usage2-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-wrong-usage2-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-wrong-usage2.cmake4
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-wrong-usage3-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-wrong-usage3-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-wrong-usage3.cmake4
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-wrong-usage4-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-wrong-usage4-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/LINK_LANGUAGE-wrong-usage4.cmake7
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/RunCMakeTest.cmake15
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANGUAGE/empty.c0
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_custom_command-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_custom_command-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_custom_command.cmake4
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_custom_target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_custom_target-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_custom_target.cmake4
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_executable-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_executable-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_executable.cmake5
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_library-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_library-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_library.cmake2
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_test-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_test-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-add_test.cmake5
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-file_generate-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-file_generate-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-file_generate.cmake6
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-install-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-install-stderr.txt10
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-install.cmake5
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-target_sources-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-target_sources-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-target_sources.cmake2
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-unknown-lang.cmake4
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-wrong-usage1-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-wrong-usage1-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-wrong-usage1.cmake4
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-wrong-usage2-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-wrong-usage2-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-wrong-usage2.cmake4
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-wrong-usage3-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-wrong-usage3-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/LINK_LANG_AND_ID-wrong-usage3.cmake4
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/RunCMakeTest.cmake14
-rw-r--r--Tests/RunCMake/GenEx-LINK_LANG_AND_ID/empty.c0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_CONTENT_DIR-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_CONTENT_DIR-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_CONTENT_DIR.cmake2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR.cmake2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_PDB_FILE-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_PDB_FILE-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_PDB_FILE.cmake2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_PDB_FILE_BASE_NAME-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_PDB_FILE_BASE_NAME-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_PDB_FILE_BASE_NAME.cmake2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidCompiler-TARGET_PDB_FILE-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidCompiler-TARGET_PDB_FILE-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidCompiler-TARGET_PDB_FILE.cmake9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidCompiler-TARGET_PDB_FILE_BASE_NAME.cmake9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_CONTENT_DIR-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_CONTENT_DIR-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_CONTENT_DIR.cmake9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR.cmake9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_PDB_FILE-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_PDB_FILE-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_PDB_FILE.cmake9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_PDB_FILE_BASE_NAME-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_PDB_FILE_BASE_NAME-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_PDB_FILE_BASE_NAME.cmake9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/OUTPUT_NAME-recursion-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/OUTPUT_NAME-recursion-stderr.txt10
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/OUTPUT_NAME-recursion.cmake6
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/RunCMakeTest.cmake33
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE-recursion-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE-recursion-stderr.txt4
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE-recursion.cmake4
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_BASE_NAME-check.cmake2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_BASE_NAME-imported-target-check.cmake2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_BASE_NAME-imported-target.cmake106
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_BASE_NAME-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_BASE_NAME-non-valid-target-stderr.txt6
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_BASE_NAME-non-valid-target.cmake7
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_BASE_NAME.cmake135
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_DIR-dependency-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_DIR-dependency-stderr.txt6
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_DIR-dependency.cmake12
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_DIR-no-dependency.cmake12
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_PREFIX-check.cmake2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_PREFIX-imported-target-check.cmake2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_PREFIX-imported-target.cmake49
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_PREFIX-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_PREFIX-non-valid-target-stderr.txt6
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_PREFIX-non-valid-target.cmake7
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_PREFIX.cmake49
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_SUFFIX-check.cmake2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_SUFFIX-imported-target-check.cmake2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_SUFFIX-imported-target.cmake49
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_SUFFIX-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_SUFFIX-non-valid-target-stderr.txt6
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_SUFFIX-non-valid-target.cmake7
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_SUFFIX.cmake49
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_LINKER_FILE_BASE_NAME-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_LINKER_FILE_BASE_NAME-non-valid-target-stderr.txt6
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_LINKER_FILE_BASE_NAME-non-valid-target.cmake7
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_LINKER_FILE_PREFIX-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_LINKER_FILE_PREFIX-non-valid-target-stderr.txt6
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_LINKER_FILE_PREFIX-non-valid-target.cmake7
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_LINKER_FILE_SUFFIX-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_LINKER_FILE_SUFFIX-non-valid-target-stderr.txt6
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/TARGET_LINKER_FILE_SUFFIX-non-valid-target.cmake7
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ValidTarget-TARGET_PDB_FILE-check.cmake17
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ValidTarget-TARGET_PDB_FILE.cmake20
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ValidTarget-TARGET_PDB_FILE_BASE_NAME-check.cmake7
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ValidTarget-TARGET_PDB_FILE_BASE_NAME.cmake16
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/empty.c0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/RunCMakeTest.cmake7
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-check.cmake15
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static.cmake9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1-stderr.txt5
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1.cmake4
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2-stderr.txt5
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2.cmake6
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries.cmake5
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS.cmake37
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib1.c12
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib2.c6
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib3.c6
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/main.c4
-rw-r--r--Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/static.c3
-rw-r--r--Tests/RunCMake/GenerateExportHeader/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GenerateExportHeader/GEH-build-stderr.txt1
-rw-r--r--Tests/RunCMake/GenerateExportHeader/GEH-failures.cmake67
-rw-r--r--Tests/RunCMake/GenerateExportHeader/GEH-link-error-result.txt1
-rw-r--r--Tests/RunCMake/GenerateExportHeader/GEH-link-error-stderr.txt1
-rw-r--r--Tests/RunCMake/GenerateExportHeader/GEH.cmake130
-rw-r--r--Tests/RunCMake/GenerateExportHeader/RunCMakeTest.cmake37
-rw-r--r--Tests/RunCMake/GenerateExportHeader/c_identifier/CMakeLists.txt11
-rw-r--r--Tests/RunCMake/GenerateExportHeader/c_identifier/c_identifier_class.cpp7
-rw-r--r--Tests/RunCMake/GenerateExportHeader/c_identifier/c_identifier_class.h13
-rw-r--r--Tests/RunCMake/GenerateExportHeader/c_identifier/main.cpp8
-rw-r--r--Tests/RunCMake/GenerateExportHeader/exportheader_test.cpp169
-rw-r--r--Tests/RunCMake/GenerateExportHeader/includeguard/CMakeLists.txt19
-rw-r--r--Tests/RunCMake/GenerateExportHeader/includeguard/libincludeguard.cpp0
-rw-r--r--Tests/RunCMake/GenerateExportHeader/includeguard/main.cpp.in10
-rw-r--r--Tests/RunCMake/GenerateExportHeader/lib_shared_and_static/CMakeLists.txt33
-rw-r--r--Tests/RunCMake/GenerateExportHeader/lib_shared_and_static/libshared_and_static.cpp121
-rw-r--r--Tests/RunCMake/GenerateExportHeader/lib_shared_and_static/libshared_and_static.h83
-rw-r--r--Tests/RunCMake/GenerateExportHeader/libshared/CMakeLists.txt9
-rw-r--r--Tests/RunCMake/GenerateExportHeader/libshared/libshared.cpp117
-rw-r--r--Tests/RunCMake/GenerateExportHeader/libshared/libshared.h82
-rw-r--r--Tests/RunCMake/GenerateExportHeader/libstatic/CMakeLists.txt11
-rw-r--r--Tests/RunCMake/GenerateExportHeader/libstatic/libstatic.cpp125
-rw-r--r--Tests/RunCMake/GenerateExportHeader/libstatic/libstatic.h86
-rw-r--r--Tests/RunCMake/GenerateExportHeader/nodeprecated/CMakeLists.txt22
-rw-r--r--Tests/RunCMake/GenerateExportHeader/nodeprecated/CMakeLists.txt.in15
-rw-r--r--Tests/RunCMake/GenerateExportHeader/nodeprecated/src/main.cpp9
-rw-r--r--Tests/RunCMake/GenerateExportHeader/nodeprecated/src/someclass.cpp8
-rw-r--r--Tests/RunCMake/GenerateExportHeader/nodeprecated/src/someclass.h10
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/.gitattributes2
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/Empty/libshared_export.h42
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/Empty/libstatic_export.h42
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/MinGW/libshared_export.h42
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/MinGW/libstatic_export.h42
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/UNIX/libshared_export.h42
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/UNIX/libstatic_export.h42
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/UNIX_DeprecatedOnly/libshared_export.h42
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/UNIX_DeprecatedOnly/libstatic_export.h42
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/Win32-Clang/libshared_export.h42
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/Win32-Clang/libstatic_export.h42
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/Win32/libshared_export.h42
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/Win32/libstatic_export.h42
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/WinEmpty/libshared_export.h42
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/WinEmpty/libstatic_export.h42
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadAND-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt55
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadAND.cmake8
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadCONFIG-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt28
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadCONFIG.cmake5
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadIF-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadIF-stderr.txt15
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadIF.cmake5
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadInstallPrefix-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadInstallPrefix-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadInstallPrefix.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadNOT-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt54
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadNOT.cmake8
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadOR-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt55
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadOR.cmake8
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadSHELL_PATH-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadSHELL_PATH-stderr.txt26
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadSHELL_PATH.cmake5
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadStrEqual-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadStrEqual-stderr.txt40
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadStrEqual.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadTargetName-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadTargetName-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadTargetName.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadTargetTypeInterface-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadTargetTypeInterface-stderr.txt26
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadTargetTypeInterface.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadTargetTypeObject-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadTargetTypeObject-stderr.txt26
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadTargetTypeObject.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadZero-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadZero-stderr.txt17
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadZero.cmake5
-rw-r--r--Tests/RunCMake/GeneratorExpression/CMP0044-WARN-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/CMP0044-WARN-stderr.txt7
-rw-r--r--Tests/RunCMake/GeneratorExpression/CMP0044-WARN.cmake17
-rw-r--r--Tests/RunCMake/GeneratorExpression/CMP0085-NEW-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/CMP0085-NEW.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/CMP0085-OLD-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/CMP0085-OLD.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/CMP0085-WARN-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/CMP0085-WARN-stderr.txt33
-rw-r--r--Tests/RunCMake/GeneratorExpression/CMP0085-WARN.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GeneratorExpression/CONFIG-empty-entries-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/CONFIG-empty-entries.cmake9
-rw-r--r--Tests/RunCMake/GeneratorExpression/CONFIG-multiple-entries-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/CONFIG-multiple-entries.cmake8
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-Exclude-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-Exclude.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-Include-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-Include.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-InvalidOperator.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-empty-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/FILTER-empty.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/LINK_ONLY-not-linking-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/LINK_ONLY-not-linking-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpression/LINK_ONLY-not-linking.cmake1
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-CXX_COMPILER_ID-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-CXX_COMPILER_ID-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-CXX_COMPILER_ID.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-CXX_COMPILER_VERSION-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-CXX_COMPILER_VERSION-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-CXX_COMPILER_VERSION.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-C_COMPILER_ID-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-C_COMPILER_ID-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-C_COMPILER_ID.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-C_COMPILER_VERSION-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-C_COMPILER_VERSION-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-C_COMPILER_VERSION.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-Fortran_COMPILER_ID-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-Fortran_COMPILER_ID-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-Fortran_COMPILER_ID.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-Fortran_COMPILER_VERSION-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-Fortran_COMPILER_VERSION-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-Fortran_COMPILER_VERSION.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_POLICY-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_POLICY-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_POLICY.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PROPERTY-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PROPERTY-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PROPERTY.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-1.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-2.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-3.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-4.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/REMOVE_DUPLICATES-empty.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/ResultValidator.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake72
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-empty-arg-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-empty-arg-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-empty-arg.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-no-arg-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-no-arg.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-not-a-target-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-not-a-target.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_EXISTS.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-alias-target-check.cmake5
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-alias-target.cmake8
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-empty-arg-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-empty-arg-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-empty-arg.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-global-target-check.cmake5
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-global-target.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-target-check.cmake5
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-target.cmake4
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-no-arg-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-no-arg.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-not-a-target-check.cmake5
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-not-a-target.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-ALIAS_GLOBAL-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-ALIAS_GLOBAL.cmake16
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES-check.cmake17
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES.cmake23
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-LOCATION-stderr.txt12
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-LOCATION.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-SOURCES-check.cmake6
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-SOURCES.cmake5
-rw-r--r--Tests/RunCMake/GeneratorExpression/empty.c0
-rw-r--r--Tests/RunCMake/GeneratorExpression/empty2.c0
-rw-r--r--Tests/RunCMake/GeneratorExpression/empty3.c0
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadInstance-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadInstance-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadInstance-toolchain.cmake1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadInstance.cmake1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadInstanceToolchain-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadInstanceToolchain-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorInstance/BadInstanceToolchain.cmake1
-rw-r--r--Tests/RunCMake/GeneratorInstance/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GeneratorInstance/DefaultInstance.cmake13
-rw-r--r--Tests/RunCMake/GeneratorInstance/MissingInstance-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorInstance/MissingInstance-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorInstance/MissingInstance-toolchain.cmake1
-rw-r--r--Tests/RunCMake/GeneratorInstance/MissingInstance.cmake1
-rw-r--r--Tests/RunCMake/GeneratorInstance/MissingInstanceToolchain-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorInstance/MissingInstanceToolchain-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorInstance/MissingInstanceToolchain.cmake1
-rw-r--r--Tests/RunCMake/GeneratorInstance/NoInstance-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorInstance/NoInstance-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorInstance/NoInstance.cmake7
-rw-r--r--Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake22
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadPlatform-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadPlatform-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadPlatform-toolchain.cmake1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadPlatform.cmake1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadPlatformToolchain-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadPlatformToolchain-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadPlatformToolchain.cmake1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GeneratorPlatform/NoPlatform-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/NoPlatform-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorPlatform/NoPlatform.cmake7
-rw-r--r--Tests/RunCMake/GeneratorPlatform/RunCMakeTest.cmake28
-rw-r--r--Tests/RunCMake/GeneratorPlatform/TestPlatform-toolchain.cmake2
-rw-r--r--Tests/RunCMake/GeneratorPlatform/TestPlatformToolchain-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/TestPlatformToolchain-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorPlatform/TestPlatformToolchain.cmake16
-rw-r--r--Tests/RunCMake/GeneratorPlatform/TwoPlatforms-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/TwoPlatforms-stderr.txt1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/TwoPlatforms.cmake1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/x64Platform-stdout.txt2
-rw-r--r--Tests/RunCMake/GeneratorPlatform/x64Platform.cmake7
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolset-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolset-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolset-toolchain.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolset.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetFormat-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetFormat-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetFormat.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetHostArch-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetHostArch-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetHostArch.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetHostArchTwice-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetHostArchTwice-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetHostArchTwice.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetHostArchXcode-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetHostArchXcode-stderr.txt6
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetHostArchXcode.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetToolchain-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetToolchain-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetToolchain.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetVersion-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetVersion-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetVersion.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetVersionTwice-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetVersionTwice-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetVersionTwice.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GeneratorToolset/NoToolset-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/NoToolset-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorToolset/NoToolset.cmake7
-rw-r--r--Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake120
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolset-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolset-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolset-toolchain.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolset.cmake7
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetCudaBoth-stdout.txt2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetCudaBoth.cmake2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnly-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnly-stderr.txt12
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnly.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnlyOldLayout-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnlyOldLayout-stderr.txt12
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnlyOldLayout.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetCudaVersionOnly-stdout.txt2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetCudaVersionOnly.cmake2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetCustomFlagTableDir-check.cmake24
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetCustomFlagTableDir.cmake3
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetHostArchBoth-stdout.txt2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetHostArchBoth.cmake2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetHostArchNone-stdout.txt2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetHostArchNone.cmake15
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetHostArchOnly_x64-stdout.txt2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetHostArchOnly_x64.cmake2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetHostArchOnly_x86-stdout.txt2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetHostArchOnly_x86.cmake2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetToolchain-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetToolchain-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetToolchain.cmake25
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetVCTargetsPathOnly-stdout.txt2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetVCTargetsPathOnly.cmake2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetVersionBoth-stdout.txt2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetVersionBoth.cmake2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetVersionOnly-stdout.txt2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetVersionOnly.cmake2
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-stdout.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1.cmake8
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-stdout.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12.cmake8
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault1-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault1-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault1-stdout.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault1.cmake8
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-stdout.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12.cmake8
-rw-r--r--Tests/RunCMake/GeneratorToolset/TwoToolsets-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TwoToolsets-stderr.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TwoToolsets.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/VsNormal-stdout.txt2
-rw-r--r--Tests/RunCMake/GeneratorToolset/VsNormal.cmake6
-rw-r--r--Tests/RunCMake/GeneratorToolset/main.c4
-rw-r--r--Tests/RunCMake/GetPrerequisites/ExecutableScripts-stdout.txt3
-rw-r--r--Tests/RunCMake/GetPrerequisites/ExecutableScripts.cmake19
-rw-r--r--Tests/RunCMake/GetPrerequisites/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/GetPrerequisites/TargetMissing-stderr.txt3
-rw-r--r--Tests/RunCMake/GetPrerequisites/TargetMissing.cmake4
-rwxr-xr-xTests/RunCMake/GetPrerequisites/script3
-rwxr-xr-xTests/RunCMake/GetPrerequisites/script.bat3
-rwxr-xr-xTests/RunCMake/GetPrerequisites/script.sh3
-rw-r--r--Tests/RunCMake/GoogleTest/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-configuration-debug-stdout.txt5
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-configuration-release-stdout.txt5
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-discovery-POST_BUILD-timeout-build-result.txt1
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-discovery-POST_BUILD-timeout-build-stdout.txt7
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-discovery-POST_BUILD-timeout-test-result.txt1
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-discovery-POST_BUILD-timeout-test-stderr.txt2
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-discovery-POST_BUILD-timeout-test-stdout.txt18
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-discovery-PRE_TEST-timeout-test-result.txt1
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-discovery-PRE_TEST-timeout-test-stderr.txt8
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-discovery-PRE_TEST-timeout-test-stdout.txt1
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-property-timeout1-result.txt1
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-property-timeout1-stderr.txt1
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-property-timeout1-stdout.txt10
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-property-timeout2-result.txt1
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-property-timeout2-stderr.txt1
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-property-timeout2-stdout.txt10
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-skip-timeout-stdout.txt10
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-test-missing-result.txt1
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-test-missing-stderr.txt2
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-test1-stdout.txt35
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-test2-stdout.txt35
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest.cmake62
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTestDiscoveryMultiConfig.cmake16
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTestDiscoveryTimeout.cmake16
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTestXML-result-check.cmake4
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTestXML-special-result-check.cmake28
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTestXML.cmake24
-rw-r--r--Tests/RunCMake/GoogleTest/RunCMakeTest.cmake189
-rw-r--r--Tests/RunCMake/GoogleTest/configuration_gtest.cpp23
-rw-r--r--Tests/RunCMake/GoogleTest/fake_gtest.cpp48
-rw-r--r--Tests/RunCMake/GoogleTest/no_tests_defined.cpp4
-rw-r--r--Tests/RunCMake/GoogleTest/skip_test.cpp18
-rw-r--r--Tests/RunCMake/GoogleTest/timeout_test.cpp40
-rw-r--r--Tests/RunCMake/GoogleTest/xcode_sign_adhoc.cmake8
-rw-r--r--Tests/RunCMake/GoogleTest/xml_output.cpp37
-rw-r--r--Tests/RunCMake/Graphviz/CMakeGraphVizOptions.cmake.in1
-rw-r--r--Tests/RunCMake/Graphviz/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Graphviz/GraphvizTestProject.cmake69
-rw-r--r--Tests/RunCMake/Graphviz/RunCMakeTest.cmake82
-rw-r--r--Tests/RunCMake/Graphviz/default_options-check.cmake13
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_custom_targets.dot56
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_default_options.dot54
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_dependers_files.dot54
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_executables.dot47
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_external_libs.dot50
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_graphic_libs.dot39
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_interface_libs.dot47
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_module_libs.dot48
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_object_libs.dot52
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_per_target_files.dot54
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_shared_libs.dot48
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_static_libs.dot43
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_unknown_libs.dot52
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_header.dot54
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_name.dot54
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_node_prefix.dot54
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_target_dependencies.dot.GraphicApplication26
-rw-r--r--Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_target_dependers.dot.CompilerFlags.dependers30
-rw-r--r--Tests/RunCMake/Graphviz/no_dependers_files-check.cmake4
-rw-r--r--Tests/RunCMake/Graphviz/no_executables-check.cmake5
-rw-r--r--Tests/RunCMake/Graphviz/no_external_libs-check.cmake5
-rw-r--r--Tests/RunCMake/Graphviz/no_graphic_libs-check.cmake5
-rw-r--r--Tests/RunCMake/Graphviz/no_interface_libs-check.cmake5
-rw-r--r--Tests/RunCMake/Graphviz/no_module_libs-check.cmake5
-rw-r--r--Tests/RunCMake/Graphviz/no_object_libs-check.cmake5
-rw-r--r--Tests/RunCMake/Graphviz/no_per_target_files-check.cmake5
-rw-r--r--Tests/RunCMake/Graphviz/no_shared_libs-check.cmake5
-rw-r--r--Tests/RunCMake/Graphviz/no_static_libs-check.cmake5
-rw-r--r--Tests/RunCMake/Graphviz/no_unknown_libs-check.cmake5
-rw-r--r--Tests/RunCMake/Graphviz/set_graph_header-check.cmake5
-rw-r--r--Tests/RunCMake/Graphviz/set_graph_name-check.cmake5
-rw-r--r--Tests/RunCMake/Graphviz/set_node_prefix-check.cmake5
-rw-r--r--Tests/RunCMake/Graphviz/sub_directory_target/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/Graphviz/sub_directory_target/test.c4
-rw-r--r--Tests/RunCMake/Graphviz/test_project/core_library.c3
-rw-r--r--Tests/RunCMake/Graphviz/test_project/graphic_library.c3
-rw-r--r--Tests/RunCMake/Graphviz/test_project/main.c4
-rw-r--r--Tests/RunCMake/Graphviz/test_project/module.c3
-rw-r--r--Tests/RunCMake/Graphviz/test_project/system_library.c3
-rw-r--r--Tests/RunCMake/Graphviz/test_project/third_party_project/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/INSTALL_NAME_DIR.cmake15
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/RunCMakeTest.cmake69
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/empty-install-check.cmake1
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/empty.cmake3
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/empty_genex-install-check.cmake1
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/empty_genex.cmake3
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/none-install-check.cmake1
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/none.cmake3
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/prefix_genex-install-check.cmake6
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/prefix_genex.cmake3
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/simple-install-check.cmake1
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/simple.cmake3
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/simple_genex-install-check.cmake1
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/simple_genex.cmake3
-rw-r--r--Tests/RunCMake/INSTALL_NAME_DIR/test.c3
-rw-r--r--Tests/RunCMake/IfacePaths/BinInInstallPrefix-CMP0052-NEW-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/BinInInstallPrefix-CMP0052-NEW-stderr_INCLUDE_DIRECTORIES.txt6
-rw-r--r--Tests/RunCMake/IfacePaths/BinInInstallPrefix-CMP0052-OLD-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/BinInInstallPrefix-CMP0052-OLD-stderr.txt8
-rw-r--r--Tests/RunCMake/IfacePaths/BinInInstallPrefix-CMP0052-WARN-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/BinInInstallPrefix-CMP0052-WARN-stderr_INCLUDE_DIRECTORIES.txt20
-rw-r--r--Tests/RunCMake/IfacePaths/BinInInstallPrefix-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/BinInInstallPrefix-stderr_SOURCES.txt6
-rw-r--r--Tests/RunCMake/IfacePaths/BinaryDirectoryInInterface-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/BinaryDirectoryInInterface-stderr_INCLUDE_DIRECTORIES.txt6
-rw-r--r--Tests/RunCMake/IfacePaths/BinaryDirectoryInInterface-stderr_SOURCES.txt6
-rw-r--r--Tests/RunCMake/IfacePaths/BinaryDirectoryInInterface.cmake15
-rw-r--r--Tests/RunCMake/IfacePaths/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/IfacePaths/DirInInstallPrefix-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/DirInInstallPrefix.cmake14
-rw-r--r--Tests/RunCMake/IfacePaths/InstallInBinDir-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/InstallInBinDir-stderr_INCLUDE_DIRECTORIES.txt6
-rw-r--r--Tests/RunCMake/IfacePaths/InstallInBinDir-stderr_SOURCES.txt6
-rw-r--r--Tests/RunCMake/IfacePaths/InstallInSrcDir-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/InstallInSrcDir-stderr_INCLUDE_DIRECTORIES.txt6
-rw-r--r--Tests/RunCMake/IfacePaths/InstallInSrcDir-stderr_SOURCES.txt6
-rw-r--r--Tests/RunCMake/IfacePaths/InstallPrefixInInterface-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/InstallPrefixInInterface.cmake11
-rw-r--r--Tests/RunCMake/IfacePaths/InstallToPrefixInSrcDirInSource-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/InstallToPrefixInSrcDirOutOfSource-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/RelativePathInGenex-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/RelativePathInGenex-stderr_INCLUDE_DIRECTORIES.txt5
-rw-r--r--Tests/RunCMake/IfacePaths/RelativePathInGenex-stderr_SOURCES.txt4
-rw-r--r--Tests/RunCMake/IfacePaths/RelativePathInGenex.cmake13
-rw-r--r--Tests/RunCMake/IfacePaths/RelativePathInInterface-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/RelativePathInInterface-stderr_INCLUDE_DIRECTORIES.txt5
-rw-r--r--Tests/RunCMake/IfacePaths/RelativePathInInterface-stderr_SOURCES.txt4
-rw-r--r--Tests/RunCMake/IfacePaths/RelativePathInInterface.cmake14
-rw-r--r--Tests/RunCMake/IfacePaths/RunCMakeTest.cmake161
-rw-r--r--Tests/RunCMake/IfacePaths/SourceDirectoryInInterface-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/SourceDirectoryInInterface-stderr_INCLUDE_DIRECTORIES.txt6
-rw-r--r--Tests/RunCMake/IfacePaths/SourceDirectoryInInterface-stderr_SOURCES.txt6
-rw-r--r--Tests/RunCMake/IfacePaths/SourceDirectoryInInterface.cmake15
-rw-r--r--Tests/RunCMake/IfacePaths/SrcInInstallPrefix-CMP0052-NEW-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/SrcInInstallPrefix-CMP0052-NEW-stderr_INCLUDE_DIRECTORIES.txt6
-rw-r--r--Tests/RunCMake/IfacePaths/SrcInInstallPrefix-CMP0052-OLD-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/SrcInInstallPrefix-CMP0052-OLD-stderr.txt8
-rw-r--r--Tests/RunCMake/IfacePaths/SrcInInstallPrefix-CMP0052-WARN-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/SrcInInstallPrefix-CMP0052-WARN-stderr_INCLUDE_DIRECTORIES.txt20
-rw-r--r--Tests/RunCMake/IfacePaths/SrcInInstallPrefix-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/SrcInInstallPrefix-stderr_SOURCES.txt6
-rw-r--r--Tests/RunCMake/IfacePaths/empty.cpp0
-rw-r--r--Tests/RunCMake/IfacePaths/export-NOWARN-result.txt1
-rw-r--r--Tests/RunCMake/IfacePaths/export-NOWARN.cmake77
-rw-r--r--Tests/RunCMake/IncludeWhatYouUse/C-Build-stdout.txt4
-rw-r--r--Tests/RunCMake/IncludeWhatYouUse/C-launch-Build-stdout.txt4
-rw-r--r--Tests/RunCMake/IncludeWhatYouUse/C-launch.cmake3
-rw-r--r--Tests/RunCMake/IncludeWhatYouUse/C.cmake3
-rw-r--r--Tests/RunCMake/IncludeWhatYouUse/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/IncludeWhatYouUse/CXX-Build-stdout.txt4
-rw-r--r--Tests/RunCMake/IncludeWhatYouUse/CXX-launch-Build-stdout.txt4
-rw-r--r--Tests/RunCMake/IncludeWhatYouUse/CXX-launch.cmake3
-rw-r--r--Tests/RunCMake/IncludeWhatYouUse/CXX.cmake3
-rw-r--r--Tests/RunCMake/IncludeWhatYouUse/RunCMakeTest.cmake22
-rw-r--r--Tests/RunCMake/IncludeWhatYouUse/main.c4
-rw-r--r--Tests/RunCMake/IncludeWhatYouUse/main.cxx4
-rw-r--r--Tests/RunCMake/IncompatibleQt/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/IncompatibleQt/IncompatibleQt-result.txt1
-rw-r--r--Tests/RunCMake/IncompatibleQt/IncompatibleQt-stderr.txt3
-rw-r--r--Tests/RunCMake/IncompatibleQt/IncompatibleQt.cmake6
-rw-r--r--Tests/RunCMake/IncompatibleQt/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/IncompatibleQt/main.cpp8
-rw-r--r--Tests/RunCMake/InitialFlags/C-stdout.txt1
-rw-r--r--Tests/RunCMake/InitialFlags/C.cmake3
-rw-r--r--Tests/RunCMake/InitialFlags/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/InitialFlags/CXX-stdout.txt1
-rw-r--r--Tests/RunCMake/InitialFlags/CXX.cmake3
-rw-r--r--Tests/RunCMake/InitialFlags/RunCMakeTest.cmake7
-rw-r--r--Tests/RunCMake/InterfaceLibrary/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/InterfaceLibrary/ConfigSources.cmake2
-rw-r--r--Tests/RunCMake/InterfaceLibrary/EmptySources-build2-result.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/EmptySources-build2-stdout.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/EmptySources.cmake8
-rw-r--r--Tests/RunCMake/InterfaceLibrary/ExcludeFromAll-build1-check.cmake4
-rw-r--r--Tests/RunCMake/InterfaceLibrary/ExcludeFromAll-build2-check.cmake4
-rw-r--r--Tests/RunCMake/InterfaceLibrary/ExcludeFromAll-build3-result.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/ExcludeFromAll-build3-stdout.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/ExcludeFromAll.cmake7
-rw-r--r--Tests/RunCMake/InterfaceLibrary/IMPORTED_LIBNAME-bad-value-result.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/IMPORTED_LIBNAME-bad-value-stderr.txt44
-rw-r--r--Tests/RunCMake/InterfaceLibrary/IMPORTED_LIBNAME-bad-value.cmake6
-rw-r--r--Tests/RunCMake/InterfaceLibrary/IMPORTED_LIBNAME-non-iface-result.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/IMPORTED_LIBNAME-non-iface-stderr.txt45
-rw-r--r--Tests/RunCMake/InterfaceLibrary/IMPORTED_LIBNAME-non-iface.cmake17
-rw-r--r--Tests/RunCMake/InterfaceLibrary/IMPORTED_LIBNAME-non-imported-result.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/IMPORTED_LIBNAME-non-imported-stderr.txt21
-rw-r--r--Tests/RunCMake/InterfaceLibrary/IMPORTED_LIBNAME-non-imported.cmake5
-rw-r--r--Tests/RunCMake/InterfaceLibrary/PublicSources-build3-result.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/PublicSources-build3-stdout.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/PublicSources.cmake20
-rw-r--r--Tests/RunCMake/InterfaceLibrary/RunCMakeTest.cmake36
-rw-r--r--Tests/RunCMake/InterfaceLibrary/add_custom_command-TARGET-result.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/add_custom_command-TARGET-stderr.txt5
-rw-r--r--Tests/RunCMake/InterfaceLibrary/add_custom_command-TARGET.cmake6
-rw-r--r--Tests/RunCMake/InterfaceLibrary/genex_link-result.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/genex_link.cmake22
-rw-r--r--Tests/RunCMake/InterfaceLibrary/global-interface-result.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/global-interface-stderr.txt9
-rw-r--r--Tests/RunCMake/InterfaceLibrary/global-interface.cmake2
-rw-r--r--Tests/RunCMake/InterfaceLibrary/iface.c4
-rw-r--r--Tests/RunCMake/InterfaceLibrary/iface_broken.c1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/invalid_name-result.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/invalid_name-stderr.txt15
-rw-r--r--Tests/RunCMake/InterfaceLibrary/invalid_name.cmake6
-rw-r--r--Tests/RunCMake/InterfaceLibrary/invalid_signature-result.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/invalid_signature-stderr.txt74
-rw-r--r--Tests/RunCMake/InterfaceLibrary/invalid_signature.cmake20
-rw-r--r--Tests/RunCMake/InterfaceLibrary/no_shared_libs.cmake5
-rw-r--r--Tests/RunCMake/InterfaceLibrary/target_commands-result.txt1
-rw-r--r--Tests/RunCMake/InterfaceLibrary/target_commands-stderr.txt47
-rw-r--r--Tests/RunCMake/InterfaceLibrary/target_commands.cmake13
-rw-r--r--Tests/RunCMake/InterfaceLibrary/use_iface.c6
-rw-r--r--Tests/RunCMake/Languages/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Languages/DetermineFail-result.txt1
-rw-r--r--Tests/RunCMake/Languages/DetermineFail-stderr.txt5
-rw-r--r--Tests/RunCMake/Languages/DetermineFail.cmake2
-rw-r--r--Tests/RunCMake/Languages/ExternalCUDA.cmake8
-rw-r--r--Tests/RunCMake/Languages/LINKER_LANGUAGE-genex-result.txt1
-rw-r--r--Tests/RunCMake/Languages/LINKER_LANGUAGE-genex-stderr.txt9
-rw-r--r--Tests/RunCMake/Languages/LINKER_LANGUAGE-genex.cmake4
-rw-r--r--Tests/RunCMake/Languages/Modules/CMakeDetermineFailCompiler.cmake1
-rw-r--r--Tests/RunCMake/Languages/NoLangSHARED-result.txt1
-rw-r--r--Tests/RunCMake/Languages/NoLangSHARED-stderr.txt1
-rw-r--r--Tests/RunCMake/Languages/NoLangSHARED.cmake1
-rw-r--r--Tests/RunCMake/Languages/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/Languages/empty.c0
-rw-r--r--Tests/RunCMake/Languages/empty.cpp7
-rw-r--r--Tests/RunCMake/Languages/foo.nolang0
-rw-r--r--Tests/RunCMake/Languages/link-libraries-TARGET_FILE-genex-ok-result.txt1
-rw-r--r--Tests/RunCMake/Languages/link-libraries-TARGET_FILE-genex-ok.cmake6
-rw-r--r--Tests/RunCMake/Languages/link-libraries-TARGET_FILE-genex-result.txt1
-rw-r--r--Tests/RunCMake/Languages/link-libraries-TARGET_FILE-genex-stderr.txt9
-rw-r--r--Tests/RunCMake/Languages/link-libraries-TARGET_FILE-genex.cmake4
-rw-r--r--Tests/RunCMake/LinkStatic/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/LinkStatic/LINK_SEARCH_STATIC.cmake73
-rw-r--r--Tests/RunCMake/LinkStatic/LinkOptionsLib.c7
-rw-r--r--Tests/RunCMake/LinkStatic/LinkStatic.c5
-rw-r--r--Tests/RunCMake/LinkStatic/RunCMakeTest.cmake30
-rw-r--r--Tests/RunCMake/LinkStatic/STATIC_LIBRARY_OPTIONS-basic-check.cmake4
-rw-r--r--Tests/RunCMake/LinkStatic/STATIC_LIBRARY_OPTIONS-basic-result.txt1
-rw-r--r--Tests/RunCMake/LinkStatic/STATIC_LIBRARY_OPTIONS-genex-check.cmake7
-rw-r--r--Tests/RunCMake/LinkStatic/STATIC_LIBRARY_OPTIONS-genex-result.txt1
-rw-r--r--Tests/RunCMake/LinkStatic/STATIC_LIBRARY_OPTIONS-shared-check.cmake4
-rw-r--r--Tests/RunCMake/LinkStatic/STATIC_LIBRARY_OPTIONS-shared-result.txt1
-rw-r--r--Tests/RunCMake/LinkStatic/STATIC_LIBRARY_OPTIONS.cmake21
-rw-r--r--Tests/RunCMake/LinkWhatYouUse/C-Build-stdout.txt2
-rw-r--r--Tests/RunCMake/LinkWhatYouUse/C-launch-Build-stdout.txt2
-rw-r--r--Tests/RunCMake/LinkWhatYouUse/C-launch.cmake3
-rw-r--r--Tests/RunCMake/LinkWhatYouUse/C.cmake4
-rw-r--r--Tests/RunCMake/LinkWhatYouUse/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/LinkWhatYouUse/CXX-Build-stdout.txt2
-rw-r--r--Tests/RunCMake/LinkWhatYouUse/CXX-launch-Build-stdout.txt2
-rw-r--r--Tests/RunCMake/LinkWhatYouUse/CXX-launch.cmake3
-rw-r--r--Tests/RunCMake/LinkWhatYouUse/CXX.cmake4
-rw-r--r--Tests/RunCMake/LinkWhatYouUse/RunCMakeTest.cmake21
-rw-r--r--Tests/RunCMake/LinkWhatYouUse/main.c4
-rw-r--r--Tests/RunCMake/LinkWhatYouUse/main.cxx4
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-result.txt1
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW.cmake2
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-OLD.cmake2
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-WARN.cmake2
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-common.cmake37
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/empty.c0
-rw-r--r--Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-NEW.cmake2
-rw-r--r--Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-OLD.cmake2
-rw-r--r--Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-WARN.cmake2
-rw-r--r--Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-common.cmake12
-rw-r--r--Tests/RunCMake/MSVCRuntimeTypeInfo/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/MSVCRuntimeTypeInfo/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/MSVCWarningFlags/CMP0092-NEW.cmake2
-rw-r--r--Tests/RunCMake/MSVCWarningFlags/CMP0092-OLD.cmake2
-rw-r--r--Tests/RunCMake/MSVCWarningFlags/CMP0092-WARN.cmake2
-rw-r--r--Tests/RunCMake/MSVCWarningFlags/CMP0092-common.cmake12
-rw-r--r--Tests/RunCMake/MSVCWarningFlags/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/MSVCWarningFlags/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/MacOSVersions/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/MacOSVersions/MacOSVersions-build-check.cmake27
-rw-r--r--Tests/RunCMake/MacOSVersions/MacOSVersions.cmake9
-rw-r--r--Tests/RunCMake/MacOSVersions/RunCMakeTest.cmake11
-rw-r--r--Tests/RunCMake/MacOSVersions/foo.c4
-rw-r--r--Tests/RunCMake/Make/CMP0113-Common.cmake17
-rw-r--r--Tests/RunCMake/Make/CMP0113-NEW-build-gnu-stderr.txt5
-rw-r--r--Tests/RunCMake/Make/CMP0113-NEW-build-result.txt1
-rw-r--r--Tests/RunCMake/Make/CMP0113-NEW-build-stderr.txt1
-rw-r--r--Tests/RunCMake/Make/CMP0113-NEW-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Make/CMP0113-NEW.cmake2
-rw-r--r--Tests/RunCMake/Make/CMP0113-OLD-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Make/CMP0113-OLD.cmake2
-rw-r--r--Tests/RunCMake/Make/CMP0113-WARN-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Make/CMP0113-WARN.cmake2
-rw-r--r--Tests/RunCMake/Make/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Make/IncludeRegexSubdir-check.cmake4
-rw-r--r--Tests/RunCMake/Make/IncludeRegexSubdir.cmake3
-rw-r--r--Tests/RunCMake/Make/IncludeRegexSubdir/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/Make/MakefileConflict.cmake5
-rw-r--r--Tests/RunCMake/Make/RunCMakeTest.cmake72
-rw-r--r--Tests/RunCMake/Make/TargetMessages-OFF-build-check.cmake3
-rw-r--r--Tests/RunCMake/Make/TargetMessages-OFF-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Make/TargetMessages-OFF.cmake2
-rw-r--r--Tests/RunCMake/Make/TargetMessages-ON-build-check.cmake3
-rw-r--r--Tests/RunCMake/Make/TargetMessages-ON-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Make/TargetMessages-ON.cmake2
-rw-r--r--Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-check.cmake3
-rw-r--r--Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Make/TargetMessages-VAR-OFF.cmake1
-rw-r--r--Tests/RunCMake/Make/TargetMessages-VAR-ON-build-check.cmake3
-rw-r--r--Tests/RunCMake/Make/TargetMessages-VAR-ON-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Make/TargetMessages-VAR-ON.cmake1
-rw-r--r--Tests/RunCMake/Make/TargetMessages-validation.cmake10
-rw-r--r--Tests/RunCMake/Make/VerboseBuild-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Make/VerboseBuild-build-watcom-stdout.txt1
-rw-r--r--Tests/RunCMake/Make/VerboseBuild-nowork-gnu-stdout.txt1
-rw-r--r--Tests/RunCMake/Make/VerboseBuild.cmake8
-rw-r--r--Tests/RunCMake/Make/hello.c7
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/CMakeLists.txt.in2
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/CTestCustom.cmake3
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/FindRecursivePackage.cmake3
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/RunCMakeTest.cmake49
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/add_subdirectory-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/add_subdirectory-var-stderr.txt10
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/add_subdirectory.cmake2
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/add_subdirectory/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-default-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-default-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-invalid-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-invalid-var-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-var-stderr.txt34
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/ctest_run_script-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/ctest_run_script-var-stderr.txt51
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/ctest_run_script.cmake.in14
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/find_package-default-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/find_package-default-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/find_package-default-script-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/find_package-default-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/find_package-invalid-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/find_package-invalid-var-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/find_package-invalid-var-script-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/find_package-invalid-var-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/find_package-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/find_package-var-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/find_package-var-script-stderr.txt21
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/find_package-var-stderr.txt21
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/find_package.cmake2
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/function-default-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/function-default-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/function-default-script-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/function-default-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/function-invalid-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/function-invalid-var-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/function-invalid-var-script-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/function-invalid-var-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/function-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/function-var-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/function-var-script-stderr.txt21
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/function-var-stderr.txt21
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/function.cmake7
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/include-default-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/include-default-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/include-default-script-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/include-default-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/include-invalid-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/include-invalid-var-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/include-invalid-var-script-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/include-invalid-var-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/include-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/include-var-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/include-var-script-stderr.txt21
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/include-var-stderr.txt21
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/include.cmake2
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/include_recursive.cmake3
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/macro-default-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/macro-default-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/macro-default-script-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/macro-default-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/macro-invalid-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/macro-invalid-var-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/macro-invalid-var-script-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/macro-invalid-var-stderr.txt5
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/macro-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/macro-var-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/macro-var-script-stderr.txt21
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/macro-var-stderr.txt21
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/macro.cmake7
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/test.cmake.in21
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/try_compile-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/try_compile-var-stderr.txt48
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/try_compile.cmake6
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/try_compile/CMakeLists.txt13
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/variable_watch-default-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/variable_watch-default-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/variable_watch-default-script-stderr.txt6
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/variable_watch-default-stderr.txt6
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-var-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-var-script-stderr.txt6
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-var-stderr.txt6
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/variable_watch-var-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/variable_watch-var-script-result.txt1
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/variable_watch-var-script-stderr.txt22
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/variable_watch-var-stderr.txt22
-rw-r--r--Tests/RunCMake/MaxRecursionDepth/variable_watch.cmake9
-rw-r--r--Tests/RunCMake/MetaCompileFeatures/C.cmake27
-rw-r--r--Tests/RunCMake/MetaCompileFeatures/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/MetaCompileFeatures/CXX.cmake27
-rw-r--r--Tests/RunCMake/MetaCompileFeatures/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/MetaCompileFeatures/a.c0
-rw-r--r--Tests/RunCMake/MetaCompileFeatures/a.cxx0
-rw-r--r--Tests/RunCMake/MultiLint/C-Build-stdout.txt8
-rw-r--r--Tests/RunCMake/MultiLint/C-launch-Build-stdout.txt8
-rw-r--r--Tests/RunCMake/MultiLint/C-launch.cmake3
-rw-r--r--Tests/RunCMake/MultiLint/C.cmake6
-rw-r--r--Tests/RunCMake/MultiLint/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/MultiLint/CXX-Build-stdout.txt8
-rw-r--r--Tests/RunCMake/MultiLint/CXX-launch-Build-stdout.txt8
-rw-r--r--Tests/RunCMake/MultiLint/CXX-launch.cmake3
-rw-r--r--Tests/RunCMake/MultiLint/CXX.cmake6
-rw-r--r--Tests/RunCMake/MultiLint/RunCMakeTest.cmake27
-rw-r--r--Tests/RunCMake/MultiLint/main.c4
-rw-r--r--Tests/RunCMake/MultiLint/main.cxx4
-rw-r--r--Tests/RunCMake/Ninja/AssumedSources.cmake21
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-NEW-by-build-stdout.txt4
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-NEW-by.cmake3
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-NEW-no-build-result.txt1
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-NEW-no-build-stderr.txt1
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-NEW-no.cmake2
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-OLD-by-build-stdout.txt4
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-OLD-by-stderr.txt10
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-OLD-by.cmake3
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-OLD-no-build-stdout.txt4
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-OLD-no-stderr.txt10
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-OLD-no.cmake2
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-WARN-by-build-stdout.txt4
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-WARN-by.cmake2
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-WARN-no-build-stdout.txt4
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-WARN-no-stderr.txt19
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-WARN-no.cmake1
-rw-r--r--Tests/RunCMake/Ninja/CMP0058-common.cmake17
-rw-r--r--Tests/RunCMake/Ninja/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Ninja/ChangeBuildType.cmake12
-rw-r--r--Tests/RunCMake/Ninja/CheckNoPrefixSubDir.cmake7
-rw-r--r--Tests/RunCMake/Ninja/CheckNoPrefixSubDirScript.cmake8
-rw-r--r--Tests/RunCMake/Ninja/CheckOutput.cmake23
-rw-r--r--Tests/RunCMake/Ninja/CommandConcat.cmake14
-rw-r--r--Tests/RunCMake/Ninja/CustomCommandDepfile-check.cmake10
-rw-r--r--Tests/RunCMake/Ninja/CustomCommandDepfile.cmake22
-rw-r--r--Tests/RunCMake/Ninja/CustomCommandJobPool-check.cmake8
-rw-r--r--Tests/RunCMake/Ninja/CustomCommandJobPool.cmake18
-rw-r--r--Tests/RunCMake/Ninja/CustomCommandWorkingDirectory.cmake13
-rw-r--r--Tests/RunCMake/Ninja/Executable.cmake5
-rw-r--r--Tests/RunCMake/Ninja/JobPoolUsesTerminal-result.txt1
-rw-r--r--Tests/RunCMake/Ninja/JobPoolUsesTerminal-stderr.txt9
-rw-r--r--Tests/RunCMake/Ninja/JobPoolUsesTerminal.cmake2
-rw-r--r--Tests/RunCMake/Ninja/LooseObjectDepends.cmake26
-rw-r--r--Tests/RunCMake/Ninja/MyWindow.cpp7
-rw-r--r--Tests/RunCMake/Ninja/MyWindow.h16
-rw-r--r--Tests/RunCMake/Ninja/MyWindow.ui5
-rw-r--r--Tests/RunCMake/Ninja/NinjaToolMissing-result.txt1
-rw-r--r--Tests/RunCMake/Ninja/NinjaToolMissing-stderr.txt6
-rw-r--r--Tests/RunCMake/Ninja/NinjaToolMissing.cmake0
-rw-r--r--Tests/RunCMake/Ninja/NoWorkToDo-nowork-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/NoWorkToDo.cmake2
-rw-r--r--Tests/RunCMake/Ninja/PreventConfigureFileDupBuildRule.cmake5
-rw-r--r--Tests/RunCMake/Ninja/PreventTargetAliasesDupBuildRule.cmake41
-rw-r--r--Tests/RunCMake/Ninja/Qt5AutoMocDeps.cmake21
-rw-r--r--Tests/RunCMake/Ninja/QtSubDir1/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/Ninja/QtSubDir2/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/Ninja/QtSubDir3/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/Ninja/RspFileC.cmake2
-rw-r--r--Tests/RunCMake/Ninja/RspFileCXX.cmake2
-rw-r--r--Tests/RunCMake/Ninja/RspFileFortran.cmake2
-rw-r--r--Tests/RunCMake/Ninja/RunCMakeTest.cmake352
-rwxr-xr-xTests/RunCMake/Ninja/SelectCompiler/1/gcc2
-rwxr-xr-xTests/RunCMake/Ninja/SelectCompiler/2/cc2
-rw-r--r--Tests/RunCMake/Ninja/SelectCompilerUNIX-result.txt1
-rw-r--r--Tests/RunCMake/Ninja/SelectCompilerUNIX-stderr.txt6
-rw-r--r--Tests/RunCMake/Ninja/SelectCompilerUNIX.cmake3
-rw-r--r--Tests/RunCMake/Ninja/SelectCompilerWindows-result.txt1
-rw-r--r--Tests/RunCMake/Ninja/SelectCompilerWindows-stderr.txt6
-rw-r--r--Tests/RunCMake/Ninja/SelectCompilerWindows.cmake3
-rw-r--r--Tests/RunCMake/Ninja/SharedLib.cmake8
-rw-r--r--Tests/RunCMake/Ninja/StaticLib.cmake9
-rw-r--r--Tests/RunCMake/Ninja/SubDir-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/SubDir-install-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/SubDir-test-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/SubDir.cmake8
-rw-r--r--Tests/RunCMake/Ninja/SubDir/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/Ninja/SubDirBinary-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/SubDirBinary-install-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/SubDirBinary-test-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/SubDirConfigureFileDup/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/Ninja/SubDirPrefix.cmake8
-rw-r--r--Tests/RunCMake/Ninja/SubDirPrefix/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/Ninja/SubDirPrefix/greeting.c9
-rw-r--r--Tests/RunCMake/Ninja/SubDirPrefix/greeting.h4
-rw-r--r--Tests/RunCMake/Ninja/SubDirSource/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/Ninja/TwoLibs.cmake17
-rw-r--r--Tests/RunCMake/Ninja/VerboseBuild-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/VerboseBuild-nowork-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/VerboseBuild.cmake3
-rw-r--r--Tests/RunCMake/Ninja/app.cpp6
-rw-r--r--Tests/RunCMake/Ninja/app_qt.cpp11
-rw-r--r--Tests/RunCMake/Ninja/dep.c4
-rw-r--r--Tests/RunCMake/Ninja/greeting.c10
-rw-r--r--Tests/RunCMake/Ninja/greeting.h4
-rw-r--r--Tests/RunCMake/Ninja/greeting2.c7
-rw-r--r--Tests/RunCMake/Ninja/greeting2.h1
-rw-r--r--Tests/RunCMake/Ninja/hello.c7
-rw-r--r--Tests/RunCMake/Ninja/hello_sub_greeting.c7
-rw-r--r--Tests/RunCMake/Ninja/hello_with_greeting.c7
-rw-r--r--Tests/RunCMake/Ninja/hello_with_two_greetings.c9
-rw-r--r--Tests/RunCMake/Ninja/simple_lib.cpp6
-rw-r--r--Tests/RunCMake/Ninja/top.c7
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles-all-clean-ninja-check.cmake4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles-check.cmake8
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles-release-clean-build-check.cmake6
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles.cmake3
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/AutoMocExecutable.cmake10
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Clean-release-build-check.cmake16
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Clean-release-clean-build-check.cmake7
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Clean-release-notall-ninja-check.cmake16
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Clean.cmake17
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Common.cmake62
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CudaSimple-all-clean-build-check.cmake21
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CudaSimple-debug-target-build-check.cmake28
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CudaSimple.cmake22
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile-check.cmake10
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile.cmake20
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-build-check.cmake38
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-clean-again-ninja-check.cmake35
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-clean-ninja-check.cmake37
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-generated-stdout.txt12
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-in-release-graph-build-check.cmake43
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-in-release-graph-generated-stdout.txt12
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-clean-build-check.cmake29
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-generated-stdout.txt12
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-in-debug-graph-generated-stdout.txt12
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-in-debug-graph-ninja-check.cmake44
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-ninja-check.cmake46
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator.cmake56
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_cmd-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_cmd-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_out-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_out-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_raw-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_raw-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_dbg-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_dbg-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_dbg-release-ninja-stdout.txt2
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_dbgx-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_dbgx-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_dbgx-release-ninja-stdout.txt5
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_cmd-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_cmd-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_out-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_out-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex_out-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex_out-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct-debug-in-release-graph-ninja-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct-debug-in-release-graph-ninja-stderr.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct_if-debug-in-release-graph-ninja-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct_if-debug-in-release-graph-ninja-stderr.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct_if-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output-debug-in-release-graph-ninja-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output-debug-in-release-graph-ninja-stderr.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output_if-debug-in-release-graph-ninja-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output_if-debug-in-release-graph-ninja-stderr.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output_if-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_raw-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_raw-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_cmd-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_cmd-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_out-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_out-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex_out-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex_out-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_raw-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_raw-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-target_no_cross_byproduct-debug-in-release-graph-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-target_no_cross_byproduct-debug-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex.cmake191
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-command-ninja-check.cmake6
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-in-release-graph-postbuild-build-check.cmake8
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-target-build-check.cmake8
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-targetpostbuild-build-check.cmake12
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-minsizerel-command-ninja-check.cmake5
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-clean-build-check.cmake3
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-command-build-check.cmake5
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-leaf-byproduct-ninja-check.cmake5
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-leaf-custom-ninja-check.cmake6
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-leaf-exe-ninja-check.cmake7
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-postbuild-ninja-check.cmake11
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-target-ninja-check.cmake7
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-targetpostbuild-ninja-check.cmake13
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets.cmake51
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargetsSubdir/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/DefaultBuildFileConfig.cmake1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll-all-build-check.cmake9
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll.cmake12
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Framework.cmake22
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/FrameworkDependencyAutogen.cmake20
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Install-all-install-ninja-check.cmake39
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Install-debug-in-release-graph-install-ninja-check.cmake31
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Install-default-install-ninja-check.cmake31
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Install-release-install-build-check.cmake23
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Install.cmake10
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/InvalidCrossConfigs-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/InvalidCrossConfigs-stderr.txt5
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/InvalidCrossConfigs.cmake0
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/InvalidDefaultBuildFileConfig-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/InvalidDefaultBuildFileConfig-stderr.txt6
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/InvalidDefaultBuildFileConfig.cmake0
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsCross-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsCross-stderr.txt5
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsCross.cmake0
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsNoCross-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsNoCross-stderr.txt6
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsNoCross.cmake0
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/LongCommandLine.cmake16
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/NoUnusedVariables.cmake1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/PerConfigSources.cmake8
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/PostBuild-debug-in-release-graph-build-stdout.txt2
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/PostBuild-release-build-stdout.txt3
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/PostBuild.cmake6
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation-debug-in-release-graph-build-check.cmake7
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation-release-in-release-graph-build-check.cmake5
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation.cmake18
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Qt5-automoc-check-ninja-stdout.txt7
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Qt5-debug-in-release-graph-build-check.cmake7
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Qt5.cmake31
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake450
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-all-clean-again-ninja-check.cmake25
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-all-clean-build-check.cmake25
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-all-configs-build-check.cmake47
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-all-subdir-build-check.cmake49
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-all-top-ninja-check.cmake56
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-debug-in-release-graph-top-build-check.cmake53
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-debug-subdir-build-check.cmake31
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-debug-target-build-check.cmake31
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-debug-target-ninja-check.cmake33
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-all-ninja-check.cmake49
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-clean-minsizerel-ninja-check.cmake41
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-clean-ninja-check.cmake49
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-ninja-check.cmake51
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-minsizerel-top-ninja-check.cmake51
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-config-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-noconfig-ninja-stdout.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-release-file-ninja-check.cmake39
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-release-filename-build-check.cmake36
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-release-in-minsizerel-graph-subdir-ninja-check.cmake37
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-targets-debug-ninja-stdout.txt3
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-targets-default-ninja-stdout.txt3
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple-targets-release-ninja-stdout.txt3
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/Simple.cmake15
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-all-in-release-graph-build-check.cmake45
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-in-relwithdebinfo-graph-build-check.cmake45
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-relwithdebinfo-in-release-graph-build-check.cmake45
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-relwithdebinfo-in-release-graph-build-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-relwithdebinfo-in-release-graph-build-stderr.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-clean-all-in-release-graph-ninja-check.cmake31
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-debug-in-release-graph-build-check.cmake37
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-release-in-release-graph-ninja-check.cmake31
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-release-in-relwithdebinfo-graph-ninja-check.cmake44
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-release-graph-build-check.cmake37
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-release-graph-build-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-release-graph-build-stderr.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-relwithdebinfo-graph-ninja-check.cmake43
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs.cmake1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias-all-ninja-check.cmake56
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias-clean-ninja-check.cmake25
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias-target-ninja-check.cmake49
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias.cmake1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList-all-configs-build-check.cmake39
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList-all-relwithdebinfo-ninja-check.cmake46
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList-clean-configs-ninja-check.cmake32
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList-target-configs-ninja-check.cmake37
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList.cmake1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasListCross-target-configs-ninja-check.cmake37
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasListCross.cmake1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-all-ninja-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-all-ninja-stderr.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-clean-build-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-clean-build-stderr.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-target-ninja-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-target-ninja-stderr.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-debug-target-build-check.cmake31
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-debug-target-ninja-check.cmake32
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-all-build-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-all-build-stderr.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-clean-build-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-clean-build-stderr.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-target-ninja-result.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-target-ninja-stderr.txt1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleNoCross.cmake1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/SimpleSubdir/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/WriteFile.cmake1
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/badmoc.c7
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/echo.c21
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/empty.c0
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/generator.c101
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/generatorlib.c24
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/generatorobj.c24
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/main.c4
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/main.cu15
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/qt5.cxx9
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/qt5.h5
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/simplelib.c6
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/simplelib.cu9
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadObjSource1-result.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadObjSource1-stderr.txt9
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadObjSource1.cmake1
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadObjSource2.cmake1
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadSourceExpression1-result.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadSourceExpression1-stderr.txt8
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadSourceExpression1.cmake1
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadSourceExpression2-result.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadSourceExpression2-stderr.txt8
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadSourceExpression2.cmake1
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadSourceExpression3-result.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt9
-rw-r--r--Tests/RunCMake/ObjectLibrary/BadSourceExpression3.cmake2
-rw-r--r--Tests/RunCMake/ObjectLibrary/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ObjectLibrary/CheckTargetObjects.cmake32
-rw-r--r--Tests/RunCMake/ObjectLibrary/Dependencies.cmake7
-rw-r--r--Tests/RunCMake/ObjectLibrary/Export.cmake2
-rw-r--r--Tests/RunCMake/ObjectLibrary/Import.cmake12
-rw-r--r--Tests/RunCMake/ObjectLibrary/ImportMultiArch-check.cmake15
-rw-r--r--Tests/RunCMake/ObjectLibrary/ImportMultiArch.cmake13
-rw-r--r--Tests/RunCMake/ObjectLibrary/Install.cmake2
-rw-r--r--Tests/RunCMake/ObjectLibrary/InstallLinkedObj1-result.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/InstallLinkedObj1-stderr.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/InstallLinkedObj1.cmake6
-rw-r--r--Tests/RunCMake/ObjectLibrary/InstallLinkedObj2.cmake6
-rw-r--r--Tests/RunCMake/ObjectLibrary/InstallNotSupported-result.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/InstallNotSupported-stderr.txt5
-rw-r--r--Tests/RunCMake/ObjectLibrary/InstallNotSupported.cmake2
-rw-r--r--Tests/RunCMake/ObjectLibrary/LinkObjLHSShared.c17
-rw-r--r--Tests/RunCMake/ObjectLibrary/LinkObjLHSShared.cmake21
-rw-r--r--Tests/RunCMake/ObjectLibrary/LinkObjLHSStatic.cmake7
-rw-r--r--Tests/RunCMake/ObjectLibrary/LinkObjRHSObject-build-result.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/LinkObjRHSObject-build-stdout.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/LinkObjRHSObject.cmake12
-rw-r--r--Tests/RunCMake/ObjectLibrary/LinkObjRHSObject2-build-result.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/LinkObjRHSObject2.cmake12
-rw-r--r--Tests/RunCMake/ObjectLibrary/LinkObjRHSShared.cmake13
-rw-r--r--Tests/RunCMake/ObjectLibrary/LinkObjRHSShared2.cmake14
-rw-r--r--Tests/RunCMake/ObjectLibrary/LinkObjRHSStatic.cmake10
-rw-r--r--Tests/RunCMake/ObjectLibrary/LinkObjRHSStatic2.cmake11
-rw-r--r--Tests/RunCMake/ObjectLibrary/MissingSource-result.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/MissingSource-stderr.txt9
-rw-r--r--Tests/RunCMake/ObjectLibrary/MissingSource.cmake1
-rw-r--r--Tests/RunCMake/ObjectLibrary/ObjWithObj.cmake2
-rw-r--r--Tests/RunCMake/ObjectLibrary/OwnSources-result.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt13
-rw-r--r--Tests/RunCMake/ObjectLibrary/OwnSources.cmake2
-rw-r--r--Tests/RunCMake/ObjectLibrary/PostBuild-result.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/PostBuild-stderr.txt5
-rw-r--r--Tests/RunCMake/ObjectLibrary/PostBuild.cmake4
-rw-r--r--Tests/RunCMake/ObjectLibrary/PreBuild-result.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/PreBuild-stderr.txt5
-rw-r--r--Tests/RunCMake/ObjectLibrary/PreBuild.cmake4
-rw-r--r--Tests/RunCMake/ObjectLibrary/PreLink-result.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/PreLink-stderr.txt5
-rw-r--r--Tests/RunCMake/ObjectLibrary/PreLink.cmake4
-rw-r--r--Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake85
-rw-r--r--Tests/RunCMake/ObjectLibrary/TransitiveDependencies.cmake7
-rw-r--r--Tests/RunCMake/ObjectLibrary/a.c10
-rw-r--r--Tests/RunCMake/ObjectLibrary/b.c14
-rw-r--r--Tests/RunCMake/ObjectLibrary/bad.def0
-rw-r--r--Tests/RunCMake/ObjectLibrary/bad.obj0
-rw-r--r--Tests/RunCMake/ObjectLibrary/check_object_files.cmake17
-rw-r--r--Tests/RunCMake/ObjectLibrary/depends_lib.c7
-rw-r--r--Tests/RunCMake/ObjectLibrary/depends_main.c7
-rw-r--r--Tests/RunCMake/ObjectLibrary/depends_obj0.c4
-rw-r--r--Tests/RunCMake/ObjectLibrary/depends_obj1.c4
-rw-r--r--Tests/RunCMake/ObjectLibrary/exe.c14
-rw-r--r--Tests/RunCMake/ObjectLibrary/exe2.c6
-rw-r--r--Tests/RunCMake/ObjectLibrary/requires.c8
-rw-r--r--Tests/RunCMake/ObsoleteQtMacros/AutomocMacro-WARN-result.txt1
-rw-r--r--Tests/RunCMake/ObsoleteQtMacros/AutomocMacro-WARN-stderr.txt5
-rw-r--r--Tests/RunCMake/ObsoleteQtMacros/AutomocMacro-WARN.cmake7
-rw-r--r--Tests/RunCMake/ObsoleteQtMacros/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ObsoleteQtMacros/RunCMakeTest.cmake6
-rw-r--r--Tests/RunCMake/ObsoleteQtMacros/UseModulesMacro-WARN-result.txt1
-rw-r--r--Tests/RunCMake/ObsoleteQtMacros/UseModulesMacro-WARN-stderr.txt6
-rw-r--r--Tests/RunCMake/ObsoleteQtMacros/UseModulesMacro-WARN.cmake7
-rw-r--r--Tests/RunCMake/ObsoleteQtMacros/empty.cpp7
-rw-r--r--Tests/RunCMake/ParseImplicitData/CMakeLists.txt91
-rw-r--r--Tests/RunCMake/ParseImplicitData/README26
-rw-r--r--Tests/RunCMake/ParseImplicitData/aix-C-XL-13.1.3.input40
-rw-r--r--Tests/RunCMake/ParseImplicitData/aix-C-XLClang-16.1.0.1.input40
-rw-r--r--Tests/RunCMake/ParseImplicitData/aix-CXX-XL-13.1.3.input44
-rw-r--r--Tests/RunCMake/ParseImplicitData/aix-CXX-XLClang-16.1.0.1.input44
-rw-r--r--Tests/RunCMake/ParseImplicitData/craype-C-Cray-8.7.input53
-rw-r--r--Tests/RunCMake/ParseImplicitData/craype-C-Cray-9.0-hlist-ad.input54
-rw-r--r--Tests/RunCMake/ParseImplicitData/craype-C-GNU-7.3.0.input79
-rw-r--r--Tests/RunCMake/ParseImplicitData/craype-C-Intel-18.0.2.20180210.input40
-rw-r--r--Tests/RunCMake/ParseImplicitData/craype-CXX-Cray-8.7.input53
-rw-r--r--Tests/RunCMake/ParseImplicitData/craype-CXX-Cray-9.0-hlist-ad.input54
-rw-r--r--Tests/RunCMake/ParseImplicitData/craype-CXX-GNU-7.3.0.input82
-rw-r--r--Tests/RunCMake/ParseImplicitData/craype-CXX-Intel-18.0.2.20180210.input43
-rw-r--r--Tests/RunCMake/ParseImplicitData/craype-Fortran-Cray-8.7.input52
-rw-r--r--Tests/RunCMake/ParseImplicitData/craype-Fortran-Cray-9.0-hlist-ad.input53
-rw-r--r--Tests/RunCMake/ParseImplicitData/craype-Fortran-GNU-7.3.0.input83
-rw-r--r--Tests/RunCMake/ParseImplicitData/craype-Fortran-Intel-18.0.2.20180210.input80
-rw-r--r--Tests/RunCMake/ParseImplicitData/darwin-C-AppleClang-8.0.0.8000042.input50
-rw-r--r--Tests/RunCMake/ParseImplicitData/darwin-CXX-AppleClang-8.0.0.8000042.input52
-rw-r--r--Tests/RunCMake/ParseImplicitData/darwin_nostdinc-C-AppleClang-8.0.0.8000042.input44
-rw-r--r--Tests/RunCMake/ParseImplicitData/darwin_nostdinc-CXX-AppleClang-8.0.0.8000042.input44
-rw-r--r--Tests/RunCMake/ParseImplicitData/freebsd-C-Clang-3.3.0.input38
-rw-r--r--Tests/RunCMake/ParseImplicitData/freebsd-CXX-Clang-3.3.0.input45
-rw-r--r--Tests/RunCMake/ParseImplicitData/freebsd-Fortran-GNU-4.6.4.input78
-rw-r--r--Tests/RunCMake/ParseImplicitData/hand-C-empty.input14
-rw-r--r--Tests/RunCMake/ParseImplicitData/hand-C-relative.input23
-rw-r--r--Tests/RunCMake/ParseImplicitData/hand-CXX-empty.input14
-rw-r--r--Tests/RunCMake/ParseImplicitData/hand-CXX-relative.input23
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-C-GNU-7.3.0.input72
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-C-Intel-18.0.0.20170811.input43
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-C-NVHPC-21.1.0.input42
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-C-PGI-18.10.1.input36
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-C-XL-12.1.0.input42
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-C-XL-16.1.0.0.input40
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-CUDA-NVIDIA-10.1.168-CLANG.input242
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-CUDA-NVIDIA-10.1.168-XLClang-v.input51
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-CUDA-NVIDIA-9.2.148-GCC.input125
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-CXX-GNU-7.3.0.input76
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-CXX-Intel-18.0.0.20170811.input46
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-CXX-NVHPC-21.1.0.input42
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-CXX-PGI-18.10.1.input40
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-CXX-XL-12.1.0.input42
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-CXX-XL-16.1.0.0.input40
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-Fortran-GNU-7.3.0.input76
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-Fortran-PGI-18.10.1.input47
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux-Fortran-XL-14.1.0.input50
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux_nostdinc-C-PGI-18.10.1.input36
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux_nostdinc-C-XL-12.1.0.input42
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux_nostdinc-CXX-PGI-18.10.1.input40
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux_nostdinc-CXX-XL-12.1.0.input42
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux_nostdinc-Fortran-PGI-18.10.1.input47
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux_nostdinc_i-C-XL-12.1.0.input42
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux_nostdinc_i-CXX-XL-12.1.0.input42
-rw-r--r--Tests/RunCMake/ParseImplicitData/linux_pgf77-Fortran-PGI-18.10.1.input35
-rw-r--r--Tests/RunCMake/ParseImplicitData/mingw.org-C-GNU-4.9.3.input70
-rw-r--r--Tests/RunCMake/ParseImplicitData/mingw.org-CXX-GNU-4.9.3.input76
-rw-r--r--Tests/RunCMake/ParseImplicitData/netbsd-C-GNU-4.8.5.input60
-rw-r--r--Tests/RunCMake/ParseImplicitData/netbsd-CXX-GNU-4.8.5.input62
-rw-r--r--Tests/RunCMake/ParseImplicitData/netbsd_nostdinc-C-GNU-4.8.5.input58
-rw-r--r--Tests/RunCMake/ParseImplicitData/netbsd_nostdinc-CXX-GNU-4.8.5.input58
-rw-r--r--Tests/RunCMake/ParseImplicitData/openbsd-C-Clang-5.0.1.input37
-rw-r--r--Tests/RunCMake/ParseImplicitData/openbsd-CXX-Clang-5.0.1.input38
-rw-r--r--Tests/RunCMake/ParseImplicitData/sunos-C-SunPro-5.13.0.input35
-rw-r--r--Tests/RunCMake/ParseImplicitData/sunos-CXX-SunPro-5.13.0.input38
-rw-r--r--Tests/RunCMake/ParseImplicitData/sunos-Fortran-SunPro-8.8.0.input40
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/ParseImplicitIncludeInfo.cmake128
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/aix-C-XL-13.1.3.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/aix-C-XLClang-16.1.0.1.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/aix-CXX-XL-13.1.3.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/aix-CXX-XLClang-16.1.0.1.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/craype-C-Cray-8.7.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/craype-C-Cray-9.0-hlist-ad.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/craype-C-GNU-7.3.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/craype-C-Intel-18.0.2.20180210.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/craype-CXX-Cray-8.7.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/craype-CXX-Cray-9.0-hlist-ad.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/craype-CXX-GNU-7.3.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/craype-CXX-Intel-18.0.2.20180210.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/craype-Fortran-Cray-8.7.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/craype-Fortran-Cray-9.0-hlist-ad.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/craype-Fortran-GNU-7.3.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/craype-Fortran-Intel-18.0.2.20180210.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/darwin-C-AppleClang-8.0.0.8000042.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/darwin-CXX-AppleClang-8.0.0.8000042.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/darwin_nostdinc-C-AppleClang-8.0.0.8000042.output0
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/darwin_nostdinc-CXX-AppleClang-8.0.0.8000042.output0
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/freebsd-C-Clang-3.3.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/freebsd-CXX-Clang-3.3.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/freebsd-Fortran-GNU-4.6.4.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/hand-C-empty.output0
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/hand-C-relative.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/hand-CXX-empty.output0
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/hand-CXX-relative.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-C-GNU-7.3.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-C-Intel-18.0.0.20170811.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-C-NVHPC-21.1.0-empty.output0
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-C-PGI-18.10.1.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-C-XL-12.1.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-C-XL-16.1.0.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-CUDA-NVIDIA-10.1.168-CLANG.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-CUDA-NVIDIA-10.1.168-XLClang-v-empty.output0
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-CUDA-NVIDIA-9.2.148-GCC.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-CXX-GNU-7.3.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-CXX-Intel-18.0.0.20170811.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-CXX-NVHPC-21.1.0-empty.output0
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-CXX-PGI-18.10.1.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-CXX-XL-12.1.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-CXX-XL-16.1.0.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-Fortran-GNU-7.3.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-Fortran-PGI-18.10.1.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux-Fortran-XL-14.1.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux_nostdinc-C-PGI-18.10.1.output0
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux_nostdinc-C-XL-12.1.0.output0
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux_nostdinc-CXX-PGI-18.10.1.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux_nostdinc-CXX-XL-12.1.0.output0
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux_nostdinc-Fortran-PGI-18.10.1.output0
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux_nostdinc_i-C-XL-12.1.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux_nostdinc_i-CXX-XL-12.1.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/linux_pgf77-Fortran-PGI-18.10.1.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/mingw.org-C-GNU-4.9.3.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/mingw.org-CXX-GNU-4.9.3.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/netbsd-C-GNU-4.8.5.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/netbsd-CXX-GNU-4.8.5.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/netbsd_nostdinc-C-GNU-4.8.5.output0
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/netbsd_nostdinc-CXX-GNU-4.8.5.output0
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/openbsd-C-Clang-5.0.1.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/openbsd-CXX-Clang-5.0.1.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/sunos-C-SunPro-5.13.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/sunos-CXX-SunPro-5.13.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitIncludeInfo/results/sunos-Fortran-SunPro-8.8.0.output1
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/ParseImplicitLinkInfo.cmake174
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/aix-C-XL-13.1.3.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/aix-C-XLClang-16.1.0.1.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/aix-CXX-XL-13.1.3.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/aix-CXX-XLClang-16.1.0.1.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/craype-C-Cray-8.7.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/craype-C-Cray-9.0-hlist-ad.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/craype-C-GNU-7.3.0.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/craype-C-Intel-18.0.2.20180210.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/craype-CXX-Cray-8.7.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/craype-CXX-Cray-9.0-hlist-ad.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/craype-CXX-GNU-7.3.0.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/craype-CXX-Intel-18.0.2.20180210.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/craype-Fortran-Cray-8.7.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/craype-Fortran-Cray-9.0-hlist-ad.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/craype-Fortran-GNU-7.3.0.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/craype-Fortran-Intel-18.0.2.20180210.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/darwin-C-AppleClang-8.0.0.8000042.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/darwin-CXX-AppleClang-8.0.0.8000042.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/darwin_nostdinc-C-AppleClang-8.0.0.8000042.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/darwin_nostdinc-CXX-AppleClang-8.0.0.8000042.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/freebsd-C-Clang-3.3.0.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/freebsd-CXX-Clang-3.3.0.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/freebsd-Fortran-GNU-4.6.4.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/hand-C-empty.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/hand-C-relative.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/hand-CXX-empty.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/hand-CXX-relative.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-C-GNU-7.3.0.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-C-Intel-18.0.0.20170811.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-C-NVHPC-21.1.0.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-C-PGI-18.10.1.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-C-XL-12.1.0.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-C-XL-16.1.0.0.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CUDA-NVIDIA-10.1.168-CLANG.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CUDA-NVIDIA-10.1.168-XLClang-v.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CUDA-NVIDIA-9.2.148-GCC.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-GNU-7.3.0.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-Intel-18.0.0.20170811.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-NVHPC-21.1.0.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-PGI-18.10.1.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-XL-12.1.0.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-XL-16.1.0.0.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-Fortran-GNU-7.3.0.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-Fortran-PGI-18.10.1.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux-Fortran-XL-14.1.0.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux_nostdinc-C-PGI-18.10.1.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux_nostdinc-C-XL-12.1.0.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux_nostdinc-CXX-PGI-18.10.1.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux_nostdinc-CXX-XL-12.1.0.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux_nostdinc-Fortran-PGI-18.10.1.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux_nostdinc_i-C-XL-12.1.0.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/linux_pgf77-Fortran-PGI-18.10.1.output3
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/mingw.org-C-GNU-4.9.3.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/mingw.org-CXX-GNU-4.9.3.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/netbsd-C-GNU-4.8.5.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/netbsd-CXX-GNU-4.8.5.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/netbsd_nostdinc-C-GNU-4.8.5.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/netbsd_nostdinc-CXX-GNU-4.8.5.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/openbsd-C-Clang-5.0.1.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/openbsd-CXX-Clang-5.0.1.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/sunos-C-SunPro-5.13.0.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/sunos-CXX-SunPro-5.13.0.output2
-rw-r--r--Tests/RunCMake/ParseImplicitLinkInfo/results/sunos-Fortran-SunPro-8.8.0.output2
-rw-r--r--Tests/RunCMake/Policy/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Policy/InvalidMaxVersion-result.txt1
-rw-r--r--Tests/RunCMake/Policy/InvalidMaxVersion-stderr.txt5
-rw-r--r--Tests/RunCMake/Policy/InvalidMaxVersion.cmake5
-rw-r--r--Tests/RunCMake/Policy/InvalidRangeMaxVersionNotGiven-result.txt0
-rw-r--r--Tests/RunCMake/Policy/InvalidRangeMaxVersionNotGiven-stderr.txt5
-rw-r--r--Tests/RunCMake/Policy/InvalidRangeMaxVersionNotGiven.cmake1
-rw-r--r--Tests/RunCMake/Policy/InvalidRangeMinVersionNotGiven-result.txt1
-rw-r--r--Tests/RunCMake/Policy/InvalidRangeMinVersionNotGiven-stderr.txt5
-rw-r--r--Tests/RunCMake/Policy/InvalidRangeMinVersionNotGiven.cmake1
-rw-r--r--Tests/RunCMake/Policy/InvalidVersion-result.txt0
-rw-r--r--Tests/RunCMake/Policy/InvalidVersion-stderr.txt5
-rw-r--r--Tests/RunCMake/Policy/InvalidVersion.cmake5
-rw-r--r--Tests/RunCMake/Policy/MinVersionLargerThanMax-result.txt1
-rw-r--r--Tests/RunCMake/Policy/MinVersionLargerThanMax-stderr.txt4
-rw-r--r--Tests/RunCMake/Policy/MinVersionLargerThanMax.cmake1
-rw-r--r--Tests/RunCMake/Policy/RunCMakeTest.cmake19
-rw-r--r--Tests/RunCMake/Policy/TooManyVersionsGiven-result.txt1
-rw-r--r--Tests/RunCMake/Policy/TooManyVersionsGiven-stderr.txt4
-rw-r--r--Tests/RunCMake/Policy/TooManyVersionsGiven.cmake1
-rw-r--r--Tests/RunCMake/Policy/VersionLowerThan2_4-result.txt1
-rw-r--r--Tests/RunCMake/Policy/VersionLowerThan2_4-stderr.txt6
-rw-r--r--Tests/RunCMake/Policy/VersionLowerThan2_4.cmake1
-rw-r--r--Tests/RunCMake/Policy/VersionNotGiven-result.txt1
-rw-r--r--Tests/RunCMake/Policy/VersionNotGiven-stderr.txt4
-rw-r--r--Tests/RunCMake/Policy/VersionNotGiven.cmake1
-rw-r--r--Tests/RunCMake/Policy/VeryHighVersion-result.txt1
-rw-r--r--Tests/RunCMake/Policy/VeryHighVersion-stderr.txt7
-rw-r--r--Tests/RunCMake/Policy/VeryHighVersion.cmake1
-rw-r--r--Tests/RunCMake/PolicyScope/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/PolicyScope/NotClosed-result.txt1
-rw-r--r--Tests/RunCMake/PolicyScope/NotClosed-stderr.txt4
-rw-r--r--Tests/RunCMake/PolicyScope/NotClosed.cmake1
-rw-r--r--Tests/RunCMake/PolicyScope/NotOpened-result.txt1
-rw-r--r--Tests/RunCMake/PolicyScope/NotOpened-stderr.txt4
-rw-r--r--Tests/RunCMake/PolicyScope/NotOpened.cmake1
-rw-r--r--Tests/RunCMake/PolicyScope/RunCMakeTest.cmake6
-rw-r--r--Tests/RunCMake/PolicyScope/dir-in-macro-generate-time-result.txt1
-rw-r--r--Tests/RunCMake/PolicyScope/dir-in-macro-generate-time-stderr.txt5
-rw-r--r--Tests/RunCMake/PolicyScope/dir-in-macro-generate-time.cmake2
-rw-r--r--Tests/RunCMake/PolicyScope/dir-in-macro-include.cmake6
-rw-r--r--Tests/RunCMake/PolicyScope/dir1/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/PolicyScope/dir1/foo.cpp5
-rw-r--r--Tests/RunCMake/PolicyScope/parent-dir-generate-time-result.txt1
-rw-r--r--Tests/RunCMake/PolicyScope/parent-dir-generate-time.cmake7
-rw-r--r--Tests/RunCMake/PositionIndependentCode/CMP0083-cmp0083_new-check.cmake22
-rw-r--r--Tests/RunCMake/PositionIndependentCode/CMP0083-cmp0083_old-check.cmake20
-rw-r--r--Tests/RunCMake/PositionIndependentCode/CMP0083.cmake47
-rw-r--r--Tests/RunCMake/PositionIndependentCode/CMakeLists.txt8
-rw-r--r--Tests/RunCMake/PositionIndependentCode/CheckPIESupported.cmake18
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict1-result.txt1
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict1-stderr.txt3
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict1.cmake7
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict2-result.txt1
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict2-stderr.txt3
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict2.cmake9
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict3-result.txt1
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict3-stderr.txt4
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict3.cmake12
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict4-result.txt1
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict4-stderr.txt4
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict4.cmake8
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict5-result.txt1
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict5-stderr.txt3
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict5.cmake9
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict6-result.txt1
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict6-stderr.txt4
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Conflict6.cmake8
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Debug-result.txt1
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Debug-stderr.txt6
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Debug.cmake8
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Genex1-result.txt1
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Genex1-stderr.txt3
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Genex1.cmake9
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Genex2-result.txt1
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Genex2-stderr.txt3
-rw-r--r--Tests/RunCMake/PositionIndependentCode/Genex2.cmake9
-rw-r--r--Tests/RunCMake/PositionIndependentCode/PIE-pie_off-check.cmake7
-rw-r--r--Tests/RunCMake/PositionIndependentCode/PIE-pie_on-check.cmake7
-rw-r--r--Tests/RunCMake/PositionIndependentCode/PIE.cmake22
-rw-r--r--Tests/RunCMake/PositionIndependentCode/PIE_validator.cmake32
-rw-r--r--Tests/RunCMake/PositionIndependentCode/RunCMakeTest.cmake73
-rw-r--r--Tests/RunCMake/PositionIndependentCode/main.cpp5
-rw-r--r--Tests/RunCMake/PrecompileHeaders/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/PrecompileHeaders/CXXnotC.cmake15
-rw-r--r--Tests/RunCMake/PrecompileHeaders/DisabledPch-check.cmake15
-rw-r--r--Tests/RunCMake/PrecompileHeaders/DisabledPch.cmake14
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchDebugGenex-check.cmake17
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchDebugGenex.cmake9
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchInstantiateTemplates-check.cmake17
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchInstantiateTemplates.cmake16
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchInterface-check.cmake30
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchInterface.cmake24
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchMultilanguage-check.cmake30
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchMultilanguage.cmake14
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchPrologueEpilogue-check.cmake11
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchPrologueEpilogue.cmake11
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchReuseFrom.cmake30
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchReuseFromObjLib.cmake131
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchReuseFromPrefixed-build-stderr.txt2
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchReuseFromPrefixed.cmake29
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchReuseFromSubdir-build-stderr.txt2
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchReuseFromSubdir.cmake18
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchWarnInvalid-check.cmake22
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchWarnInvalid.cmake16
-rw-r--r--Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake30
-rw-r--r--Tests/RunCMake/PrecompileHeaders/SkipPrecompileHeaders.cmake13
-rw-r--r--Tests/RunCMake/PrecompileHeaders/empty.c3
-rw-r--r--Tests/RunCMake/PrecompileHeaders/foo.c13
-rw-r--r--Tests/RunCMake/PrecompileHeaders/foobar.c14
-rw-r--r--Tests/RunCMake/PrecompileHeaders/include/bar.h9
-rw-r--r--Tests/RunCMake/PrecompileHeaders/include/cxx_pch.h1
-rw-r--r--Tests/RunCMake/PrecompileHeaders/include/foo.h6
-rw-r--r--Tests/RunCMake/PrecompileHeaders/include/foo2.h6
-rw-r--r--Tests/RunCMake/PrecompileHeaders/include/foo_C.h1
-rw-r--r--Tests/RunCMake/PrecompileHeaders/include/foo_CXX.h1
-rw-r--r--Tests/RunCMake/PrecompileHeaders/main.cpp4
-rw-r--r--Tests/RunCMake/PrecompileHeaders/no_pch.c7
-rw-r--r--Tests/RunCMake/PrecompileHeaders/non-pch.cpp3
-rw-r--r--Tests/RunCMake/PrecompileHeaders/pch.h3
-rw-r--r--Tests/RunCMake/PrecompileHeaders/subdir/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/PrecompileHeaders/use_pch.cxx9
-rw-r--r--Tests/RunCMake/README.rst84
-rw-r--r--Tests/RunCMake/RunCMake.cmake248
-rw-r--r--Tests/RunCMake/RunCTest.cmake25
-rw-r--r--Tests/RunCMake/RuntimePath/A.c4
-rw-r--r--Tests/RunCMake/RuntimePath/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/RuntimePath/Genex.cmake29
-rw-r--r--Tests/RunCMake/RuntimePath/GenexCheck.cmake7
-rw-r--r--Tests/RunCMake/RuntimePath/Relative.cmake76
-rw-r--r--Tests/RunCMake/RuntimePath/RelativeCheck.cmake4
-rw-r--r--Tests/RunCMake/RuntimePath/RunCMakeTest.cmake32
-rw-r--r--Tests/RunCMake/RuntimePath/SymlinkImplicit.cmake17
-rw-r--r--Tests/RunCMake/RuntimePath/SymlinkImplicitCheck-result.txt1
-rw-r--r--Tests/RunCMake/RuntimePath/SymlinkImplicitCheck-stderr.txt22
-rw-r--r--Tests/RunCMake/RuntimePath/SymlinkImplicitCheck.cmake2
-rw-r--r--Tests/RunCMake/RuntimePath/main.c6
-rw-r--r--Tests/RunCMake/ScriptMode/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/ScriptMode/set_directory_properties.cmake1
-rw-r--r--Tests/RunCMake/SourceProperties/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/SourceProperties/RelativeIncludeDir-result.txt1
-rw-r--r--Tests/RunCMake/SourceProperties/RelativeIncludeDir-stderr.txt4
-rw-r--r--Tests/RunCMake/SourceProperties/RelativeIncludeDir.cmake4
-rw-r--r--Tests/RunCMake/SourceProperties/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/SourceProperties/empty.c5
-rw-r--r--Tests/RunCMake/Swift/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Swift/E.swift2
-rw-r--r--Tests/RunCMake/Swift/L.swift1
-rw-r--r--Tests/RunCMake/Swift/NotSupported-result.txt1
-rw-r--r--Tests/RunCMake/Swift/NotSupported-stderr.txt5
-rw-r--r--Tests/RunCMake/Swift/NotSupported.cmake1
-rw-r--r--Tests/RunCMake/Swift/RunCMakeTest.cmake23
-rw-r--r--Tests/RunCMake/Swift/SwiftMultiArch-result.txt1
-rw-r--r--Tests/RunCMake/Swift/SwiftMultiArch-stderr.txt4
-rw-r--r--Tests/RunCMake/Swift/SwiftMultiArch.cmake4
-rw-r--r--Tests/RunCMake/Swift/SwiftSimple.cmake2
-rw-r--r--Tests/RunCMake/Swift/Win32ExecutableDisallowed-result.txt1
-rw-r--r--Tests/RunCMake/Swift/Win32ExecutableDisallowed-stderr.txt4
-rw-r--r--Tests/RunCMake/Swift/Win32ExecutableDisallowed.cmake4
-rw-r--r--Tests/RunCMake/Swift/XcodeTooOld-result.txt1
-rw-r--r--Tests/RunCMake/Swift/XcodeTooOld-stderr.txt5
-rw-r--r--Tests/RunCMake/Swift/XcodeTooOld.cmake1
-rw-r--r--Tests/RunCMake/SymlinkTrees/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/SymlinkTrees/PrintTrees.cmake6
-rw-r--r--Tests/RunCMake/SymlinkTrees/RunCMakeTest.cmake34
-rw-r--r--Tests/RunCMake/SymlinkTrees/common_symlinks-stdout.txt4
-rw-r--r--Tests/RunCMake/SymlinkTrees/common_symlinks.cmake1
-rw-r--r--Tests/RunCMake/Syntax/.gitattributes3
-rw-r--r--Tests/RunCMake/Syntax/AtWithVariable-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/AtWithVariable.cmake9
-rw-r--r--Tests/RunCMake/Syntax/AtWithVariableAtOnly-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/AtWithVariableAtOnly.cmake8
-rw-r--r--Tests/RunCMake/Syntax/AtWithVariableAtOnlyFile-stderr.txt5
-rw-r--r--Tests/RunCMake/Syntax/AtWithVariableAtOnlyFile.cmake9
-rw-r--r--Tests/RunCMake/Syntax/AtWithVariableEmptyExpansion-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/AtWithVariableEmptyExpansion.cmake8
-rw-r--r--Tests/RunCMake/Syntax/AtWithVariableEmptyExpansionAtOnly-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/AtWithVariableEmptyExpansionAtOnly.cmake8
-rw-r--r--Tests/RunCMake/Syntax/AtWithVariableFile-stderr.txt5
-rw-r--r--Tests/RunCMake/Syntax/AtWithVariableFile.cmake8
-rw-r--r--Tests/RunCMake/Syntax/BOM-UTF-16-BE-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/BOM-UTF-16-BE-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/BOM-UTF-16-BE.cmakebin0 -> 54 bytes-rw-r--r--Tests/RunCMake/Syntax/BOM-UTF-16-LE-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/BOM-UTF-16-LE-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/BOM-UTF-16-LE.cmakebin0 -> 54 bytes-rw-r--r--Tests/RunCMake/Syntax/BOM-UTF-32-BE-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/BOM-UTF-32-BE-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/BOM-UTF-32-BE.cmakebin0 -> 108 bytes-rw-r--r--Tests/RunCMake/Syntax/BOM-UTF-32-LE-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/BOM-UTF-32-LE-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/BOM-UTF-32-LE.cmakebin0 -> 108 bytes-rw-r--r--Tests/RunCMake/Syntax/BOM-UTF-8-stdout.txt1
-rw-r--r--Tests/RunCMake/Syntax/BOM-UTF-8.cmake1
-rw-r--r--Tests/RunCMake/Syntax/Bracket0-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/Bracket0.cmake1
-rw-r--r--Tests/RunCMake/Syntax/Bracket1-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/Bracket1.cmake2
-rw-r--r--Tests/RunCMake/Syntax/Bracket2-stdout.txt2
-rw-r--r--Tests/RunCMake/Syntax/Bracket2.cmake2
-rw-r--r--Tests/RunCMake/Syntax/BracketBackslash-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/BracketBackslash-stderr.txt6
-rw-r--r--Tests/RunCMake/Syntax/BracketBackslash.cmake2
-rw-r--r--Tests/RunCMake/Syntax/BracketCRLF-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/BracketCRLF.cmake8
-rw-r--r--Tests/RunCMake/Syntax/BracketComment0-stdout.txt1
-rw-r--r--Tests/RunCMake/Syntax/BracketComment0.cmake5
-rw-r--r--Tests/RunCMake/Syntax/BracketComment1-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/BracketComment1-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/BracketComment1.cmake3
-rw-r--r--Tests/RunCMake/Syntax/BracketComment2-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/BracketComment2-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/BracketComment2.cmake3
-rw-r--r--Tests/RunCMake/Syntax/BracketComment3-stdout.txt1
-rw-r--r--Tests/RunCMake/Syntax/BracketComment3.cmake4
-rw-r--r--Tests/RunCMake/Syntax/BracketComment4-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/BracketComment4-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/BracketComment4.cmake3
-rw-r--r--Tests/RunCMake/Syntax/BracketComment5-stdout.txt1
-rw-r--r--Tests/RunCMake/Syntax/BracketComment5.cmake11
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace0-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace0-stderr.txt6
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace0.cmake1
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace1-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace1-stderr.txt6
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace1.cmake1
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace2-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace2-stderr.txt6
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace2.cmake1
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace3-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace3-stderr.txt6
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace3.cmake1
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace4-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace4-stderr.txt6
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace4.cmake1
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace5-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace5-stderr.txt6
-rw-r--r--Tests/RunCMake/Syntax/BracketNoSpace5.cmake1
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-At-NEW-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-At-NEW.cmake9
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-At-OLD-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-At-OLD.cmake9
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-At-WARN-newlines-stderr.txt27
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-At-WARN-newlines.cmake6
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-At-WARN-stderr.txt21
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-At-WARN.cmake4
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-Dollar-NEW-stderr.txt2
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-Dollar-NEW.cmake6
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-Dollar-OLD-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-Dollar-OLD-stderr.txt24
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-Dollar-OLD.cmake6
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NUL-stderr.txt56
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NUL.cmake6
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithCarriageReturn-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithCarriageReturn-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithCarriageReturn.cmake2
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithCarriageReturnQuoted.cmake2
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithEscapedSpaces-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithEscapedSpaces-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithEscapedSpaces.cmake2
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithEscapedSpacesQuoted.cmake2
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithEscapedTabs-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithEscapedTabs-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithEscapedTabs.cmake2
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithEscapedTabsQuoted.cmake2
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithNewline-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithNewline-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithNewline.cmake2
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithNewlineQuoted.cmake2
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithSpaces-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithSpaces-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithSpaces.cmake2
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithSpacesQuoted-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithSpacesQuoted-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithSpacesQuoted.cmake2
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithTabs-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithTabs-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithTabs.cmake2
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithTabsQuoted-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithTabsQuoted-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-NameWithTabsQuoted.cmake2
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-ParenInENV-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-ParenInENV.cmake3
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-ParenInQuotedENV-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-ParenInQuotedENV.cmake3
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-WARN-stderr.txt28
-rw-r--r--Tests/RunCMake/Syntax/CMP0053-WARN.cmake5
-rw-r--r--Tests/RunCMake/Syntax/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Syntax/CommandComments-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/CommandComments.cmake6
-rw-r--r--Tests/RunCMake/Syntax/CommandEOF-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/CommandEOF-stderr.txt6
-rw-r--r--Tests/RunCMake/Syntax/CommandEOF.cmake1
-rw-r--r--Tests/RunCMake/Syntax/CommandError0-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/CommandError0-stderr.txt6
-rw-r--r--Tests/RunCMake/Syntax/CommandError0.cmake2
-rw-r--r--Tests/RunCMake/Syntax/CommandError1-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/CommandError1-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/CommandError1.cmake1
-rw-r--r--Tests/RunCMake/Syntax/CommandError2-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/CommandError2-stderr.txt5
-rw-r--r--Tests/RunCMake/Syntax/CommandError2.cmake1
-rw-r--r--Tests/RunCMake/Syntax/CommandNewlines-stderr.txt3
-rw-r--r--Tests/RunCMake/Syntax/CommandNewlines.cmake10
-rw-r--r--Tests/RunCMake/Syntax/CommandSpaces-stderr.txt6
-rw-r--r--Tests/RunCMake/Syntax/CommandSpaces.cmake6
-rw-r--r--Tests/RunCMake/Syntax/CommandTabs-stderr.txt6
-rw-r--r--Tests/RunCMake/Syntax/CommandTabs.cmake6
-rw-r--r--Tests/RunCMake/Syntax/Escape1-stderr.txt3
-rw-r--r--Tests/RunCMake/Syntax/Escape1.cmake3
-rw-r--r--Tests/RunCMake/Syntax/Escape2-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/Escape2-stderr.txt13
-rw-r--r--Tests/RunCMake/Syntax/Escape2.cmake7
-rw-r--r--Tests/RunCMake/Syntax/EscapeChar-char-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/EscapeChar-char-stderr.txt.in12
-rw-r--r--Tests/RunCMake/Syntax/EscapeChar-char.cmake.in3
-rw-r--r--Tests/RunCMake/Syntax/EscapeCharsAllowed-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/EscapeCharsAllowed.cmake26
-rw-r--r--Tests/RunCMake/Syntax/EscapeCharsDisallowed.cmake42
-rw-r--r--Tests/RunCMake/Syntax/EscapeQuotes-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/EscapeQuotes.cmake9
-rw-r--r--Tests/RunCMake/Syntax/EscapedAt-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/EscapedAt.cmake5
-rw-r--r--Tests/RunCMake/Syntax/ExpandInAt-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/ExpandInAt.cmake6
-rw-r--r--Tests/RunCMake/Syntax/ForEachBracket1-stderr.txt2
-rw-r--r--Tests/RunCMake/Syntax/ForEachBracket1.cmake3
-rw-r--r--Tests/RunCMake/Syntax/FunctionBracket1-stderr.txt2
-rw-r--r--Tests/RunCMake/Syntax/FunctionBracket1.cmake6
-rw-r--r--Tests/RunCMake/Syntax/FunctionUnmatched-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/FunctionUnmatched-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/FunctionUnmatched.cmake2
-rw-r--r--Tests/RunCMake/Syntax/FunctionUnmatchedForeach-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/FunctionUnmatchedForeach-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/FunctionUnmatchedForeach.cmake5
-rw-r--r--Tests/RunCMake/Syntax/ImproperNesting-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/ImproperNesting-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/ImproperNesting.cmake7
-rw-r--r--Tests/RunCMake/Syntax/MacroBracket1-stderr.txt2
-rw-r--r--Tests/RunCMake/Syntax/MacroBracket1.cmake6
-rw-r--r--Tests/RunCMake/Syntax/MacroUnmatched-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/MacroUnmatched-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/MacroUnmatched.cmake2
-rw-r--r--Tests/RunCMake/Syntax/MacroUnmatchedForeach-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/MacroUnmatchedForeach-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/MacroUnmatchedForeach.cmake5
-rw-r--r--Tests/RunCMake/Syntax/NameWithCarriageReturn-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/NameWithCarriageReturn-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/NameWithCarriageReturn.cmake1
-rw-r--r--Tests/RunCMake/Syntax/NameWithCarriageReturnQuoted-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/NameWithCarriageReturnQuoted-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/NameWithCarriageReturnQuoted.cmake1
-rw-r--r--Tests/RunCMake/Syntax/NameWithEscapedSpaces-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/NameWithEscapedSpaces-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/NameWithEscapedSpaces.cmake1
-rw-r--r--Tests/RunCMake/Syntax/NameWithEscapedSpacesQuoted-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/NameWithEscapedSpacesQuoted-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/NameWithEscapedSpacesQuoted.cmake1
-rw-r--r--Tests/RunCMake/Syntax/NameWithEscapedTabs-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/NameWithEscapedTabs-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/NameWithEscapedTabs.cmake1
-rw-r--r--Tests/RunCMake/Syntax/NameWithEscapedTabsQuoted-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/NameWithEscapedTabsQuoted-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/NameWithEscapedTabsQuoted.cmake1
-rw-r--r--Tests/RunCMake/Syntax/NameWithNewline-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/NameWithNewline-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/NameWithNewline.cmake1
-rw-r--r--Tests/RunCMake/Syntax/NameWithNewlineQuoted-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/NameWithNewlineQuoted-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/NameWithNewlineQuoted.cmake1
-rw-r--r--Tests/RunCMake/Syntax/NameWithSpaces-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/NameWithSpaces-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/NameWithSpaces.cmake1
-rw-r--r--Tests/RunCMake/Syntax/NameWithSpacesQuoted-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/NameWithSpacesQuoted-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/NameWithSpacesQuoted.cmake1
-rw-r--r--Tests/RunCMake/Syntax/NameWithTabs-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/NameWithTabs-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/NameWithTabs.cmake1
-rw-r--r--Tests/RunCMake/Syntax/NameWithTabsQuoted-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/NameWithTabsQuoted-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/NameWithTabsQuoted.cmake1
-rw-r--r--Tests/RunCMake/Syntax/NullAfterBackslash-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/NullAfterBackslash-stderr.txt5
-rw-r--r--Tests/RunCMake/Syntax/NullAfterBackslash.cmakebin0 -> 113 bytes-rw-r--r--Tests/RunCMake/Syntax/NullTerminatedArgument-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/NullTerminatedArgument-stderr.txt5
-rw-r--r--Tests/RunCMake/Syntax/NullTerminatedArgument.cmakebin0 -> 106 bytes-rw-r--r--Tests/RunCMake/Syntax/OneLetter-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/OneLetter.cmake7
-rw-r--r--Tests/RunCMake/Syntax/Override.cmake6
-rw-r--r--Tests/RunCMake/Syntax/OverrideBreak-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/OverrideContinue-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/OverrideElse-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/OverrideElseIf-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/OverrideEndForeach-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/OverrideEndFunction-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/OverrideEndIf-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/OverrideEndMacro-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/OverrideEndWhile-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/OverrideForeach-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/OverrideFunction-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/OverrideIf-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/OverrideMacro-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/OverrideReturn-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/OverrideWhile-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/ParenInENV-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/ParenInENV-stderr.txt20
-rw-r--r--Tests/RunCMake/Syntax/ParenInENV.cmake2
-rw-r--r--Tests/RunCMake/Syntax/ParenInQuotedENV-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/ParenInQuotedENV.cmake2
-rw-r--r--Tests/RunCMake/Syntax/ParenInVarName0-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/ParenInVarName0-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/ParenInVarName0.cmake4
-rw-r--r--Tests/RunCMake/Syntax/ParenInVarName1-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/ParenInVarName1-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/ParenInVarName1.cmake4
-rw-r--r--Tests/RunCMake/Syntax/ParenNoSpace0-stdout.txt3
-rw-r--r--Tests/RunCMake/Syntax/ParenNoSpace0.cmake3
-rw-r--r--Tests/RunCMake/Syntax/ParenNoSpace1-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/ParenNoSpace1-stderr.txt22
-rw-r--r--Tests/RunCMake/Syntax/ParenNoSpace1.cmake3
-rw-r--r--Tests/RunCMake/Syntax/ParenNoSpace2-stdout.txt3
-rw-r--r--Tests/RunCMake/Syntax/ParenNoSpace2.cmake3
-rw-r--r--Tests/RunCMake/Syntax/QueryCache-stderr.txt2
-rw-r--r--Tests/RunCMake/Syntax/QueryCache.cmake6
-rw-r--r--Tests/RunCMake/Syntax/RunCMakeTest.cmake152
-rw-r--r--Tests/RunCMake/Syntax/String0-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/String0.cmake2
-rw-r--r--Tests/RunCMake/Syntax/String1-stderr.txt3
-rw-r--r--Tests/RunCMake/Syntax/String1.cmake3
-rw-r--r--Tests/RunCMake/Syntax/StringBackslash-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/StringBackslash-stderr.txt6
-rw-r--r--Tests/RunCMake/Syntax/StringBackslash.cmake2
-rw-r--r--Tests/RunCMake/Syntax/StringCRLF-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/StringCRLF.cmake6
-rw-r--r--Tests/RunCMake/Syntax/StringContinuation1-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/StringContinuation1-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/StringContinuation1.cmake2
-rw-r--r--Tests/RunCMake/Syntax/StringContinuation2-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/StringContinuation2-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/StringContinuation2.cmake2
-rw-r--r--Tests/RunCMake/Syntax/StringNoSpace-stderr.txt19
-rw-r--r--Tests/RunCMake/Syntax/StringNoSpace.cmake4
-rw-r--r--Tests/RunCMake/Syntax/Unquoted0-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/Unquoted0.cmake2
-rw-r--r--Tests/RunCMake/Syntax/Unquoted1-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/Unquoted1.cmake1
-rw-r--r--Tests/RunCMake/Syntax/Unquoted2-stderr.txt1
-rw-r--r--Tests/RunCMake/Syntax/Unquoted2.cmake3
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBrace0-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBrace0-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBrace0.cmake2
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBrace1-stderr.txt13
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBrace1.cmake3
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBrace2-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBrace2-stderr.txt12
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBrace2.cmake4
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBracket0-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBracket0-stderr.txt7
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBracket0.cmake1
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBracket1-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBracket1-stderr.txt7
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBracket1.cmake1
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBracketComment-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBracketComment-stderr.txt7
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedBracketComment.cmake2
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedCall1-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedCall1-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedCall1.cmake4
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedCall2-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedCall2-stderr.txt4
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedCall2.cmake6
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedString-result.txt1
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedString-stderr.txt7
-rw-r--r--Tests/RunCMake/Syntax/UnterminatedString.cmake1
-rw-r--r--Tests/RunCMake/Syntax/atfile.txt.in4
-rw-r--r--Tests/RunCMake/TargetObjects/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/TargetObjects/NoTarget-result.txt1
-rw-r--r--Tests/RunCMake/TargetObjects/NoTarget-stderr.txt24
-rw-r--r--Tests/RunCMake/TargetObjects/NoTarget.cmake7
-rw-r--r--Tests/RunCMake/TargetObjects/NotObjlibTarget-result.txt1
-rw-r--r--Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt9
-rw-r--r--Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake3
-rw-r--r--Tests/RunCMake/TargetObjects/RunCMakeTest.cmake8
-rw-r--r--Tests/RunCMake/TargetObjects/XcodeVariableNoGenexExpansion-result.txt1
-rw-r--r--Tests/RunCMake/TargetObjects/XcodeVariableNoGenexExpansion-stderr.txt10
-rw-r--r--Tests/RunCMake/TargetObjects/XcodeVariableNoGenexExpansion.cmake12
-rw-r--r--Tests/RunCMake/TargetPolicies/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/TargetPolicies/PolicyList-result.txt1
-rw-r--r--Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt40
-rw-r--r--Tests/RunCMake/TargetPolicies/PolicyList.cmake8
-rw-r--r--Tests/RunCMake/TargetPolicies/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/TargetPolicies/empty.cpp7
-rw-r--r--Tests/RunCMake/TargetProperties/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/TargetProperties/Deprecation-stderr.txt9
-rw-r--r--Tests/RunCMake/TargetProperties/Deprecation.cmake5
-rw-r--r--Tests/RunCMake/TargetProperties/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/TargetProperties/empty.cpp4
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-stderr.txt52
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName.cmake8
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName1/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName2/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName3/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName4/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName5/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName6/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName7/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName8/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-stderr.txt10
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget.cmake7
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-stderr.txt39
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference.cmake6
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/CMakeLists.txt8
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle1-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle1-stderr.txt10
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle1.cmake8
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle2-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle2-stderr.txt10
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle2.cmake8
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle3-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle3.cmake10
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle4-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle4-stderr.txt8
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle4.cmake14
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle5-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle5-stderr.txt8
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle5.cmake10
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle6-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle6-stderr.txt8
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle6.cmake14
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake11
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/empty.cpp7
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/main.cpp4
-rw-r--r--Tests/RunCMake/TargetSources/AddCustomTargetCheckProperty.cmake16
-rw-r--r--Tests/RunCMake/TargetSources/AddCustomTargetGenx.cmake2
-rw-r--r--Tests/RunCMake/TargetSources/AddCustomTargetInterfaceSources-result.txt1
-rw-r--r--Tests/RunCMake/TargetSources/AddCustomTargetInterfaceSources-stderr.txt4
-rw-r--r--Tests/RunCMake/TargetSources/AddCustomTargetInterfaceSources.cmake2
-rw-r--r--Tests/RunCMake/TargetSources/AddCustomTargetPrivateSources.cmake2
-rw-r--r--Tests/RunCMake/TargetSources/AddCustomTargetPublicSources-result.txt1
-rw-r--r--Tests/RunCMake/TargetSources/AddCustomTargetPublicSources-stderr.txt4
-rw-r--r--Tests/RunCMake/TargetSources/AddCustomTargetPublicSources.cmake2
-rw-r--r--Tests/RunCMake/TargetSources/AddCustomTargetSources-result.txt1
-rw-r--r--Tests/RunCMake/TargetSources/AddCustomTargetSources-stderr.txt4
-rw-r--r--Tests/RunCMake/TargetSources/AddCustomTargetSources.cmake2
-rw-r--r--Tests/RunCMake/TargetSources/CMP0026-LOCATION-result.txt1
-rw-r--r--Tests/RunCMake/TargetSources/CMP0026-LOCATION-stderr.txt10
-rw-r--r--Tests/RunCMake/TargetSources/CMP0026-LOCATION.cmake13
-rw-r--r--Tests/RunCMake/TargetSources/CMP0076-OLD-result.txt1
-rw-r--r--Tests/RunCMake/TargetSources/CMP0076-OLD-stderr.txt4
-rw-r--r--Tests/RunCMake/TargetSources/CMP0076-OLD.cmake10
-rw-r--r--Tests/RunCMake/TargetSources/CMP0076-WARN-result.txt1
-rw-r--r--Tests/RunCMake/TargetSources/CMP0076-WARN-stderr.txt21
-rw-r--r--Tests/RunCMake/TargetSources/CMP0076-WARN.cmake8
-rw-r--r--Tests/RunCMake/TargetSources/CMP0076-WARN/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/TargetSources/CMP0076-WARN/subdir_empty_1.cpp7
-rw-r--r--Tests/RunCMake/TargetSources/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/TargetSources/ConfigNotAllowed-result.txt1
-rw-r--r--Tests/RunCMake/TargetSources/ConfigNotAllowed-stderr.txt12
-rw-r--r--Tests/RunCMake/TargetSources/ConfigNotAllowed.cmake2
-rw-r--r--Tests/RunCMake/TargetSources/ExportBuild-result.txt1
-rw-r--r--Tests/RunCMake/TargetSources/ExportBuild.cmake5
-rw-r--r--Tests/RunCMake/TargetSources/OriginDebug-result.txt1
-rw-r--r--Tests/RunCMake/TargetSources/OriginDebug-stderr.txt31
-rw-r--r--Tests/RunCMake/TargetSources/OriginDebug.cmake20
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInInterface-stdout.txt1
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInInterface.cmake10
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirGenEx-stdout.txt1
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirGenEx.cmake10
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirGenEx/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirGenEx/subdir_empty_1.cpp7
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirInclude-stdout.txt1
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirInclude.cmake8
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirInclude/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirInclude/subdir_empty_1.cpp7
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirInterface-stdout.txt1
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirInterface.cmake11
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirInterface/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirInterface/subdir_empty_1.cpp7
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirInterface/subdir_empty_2.cpp7
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirPrivate-stdout.txt1
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirPrivate.cmake8
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirPrivate/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirPrivate/subdir_empty_1.cpp7
-rw-r--r--Tests/RunCMake/TargetSources/RelativePathInSubdirPrivate/subdir_empty_2.cpp7
-rw-r--r--Tests/RunCMake/TargetSources/RunCMakeTest.cmake22
-rw-r--r--Tests/RunCMake/TargetSources/empty_1.cpp7
-rw-r--r--Tests/RunCMake/TargetSources/empty_2.cpp7
-rw-r--r--Tests/RunCMake/TargetSources/empty_3.cpp7
-rw-r--r--Tests/RunCMake/TargetSources/empty_4.cpp7
-rw-r--r--Tests/RunCMake/TargetSources/main.cpp5
-rw-r--r--Tests/RunCMake/ToolchainFile/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/ToolchainFile/CallEnableLanguage-result.txt1
-rw-r--r--Tests/RunCMake/ToolchainFile/CallEnableLanguage-stderr.txt5
-rw-r--r--Tests/RunCMake/ToolchainFile/CallEnableLanguage-toolchain.cmake1
-rw-r--r--Tests/RunCMake/ToolchainFile/CallEnableLanguage.cmake0
-rw-r--r--Tests/RunCMake/ToolchainFile/CallProject-result.txt1
-rw-r--r--Tests/RunCMake/ToolchainFile/CallProject-stderr.txt5
-rw-r--r--Tests/RunCMake/ToolchainFile/CallProject-toolchain.cmake1
-rw-r--r--Tests/RunCMake/ToolchainFile/CallProject.cmake0
-rw-r--r--Tests/RunCMake/ToolchainFile/CheckLanguage-stdout.txt1
-rw-r--r--Tests/RunCMake/ToolchainFile/CheckLanguage-toolchain.cmake4
-rw-r--r--Tests/RunCMake/ToolchainFile/CheckLanguage.cmake2
-rw-r--r--Tests/RunCMake/ToolchainFile/FlagsInit-stdout.txt30
-rw-r--r--Tests/RunCMake/ToolchainFile/FlagsInit-toolchain.cmake7
-rw-r--r--Tests/RunCMake/ToolchainFile/FlagsInit.cmake7
-rw-r--r--Tests/RunCMake/ToolchainFile/IncludeDirectories-toolchain.cmake1
-rw-r--r--Tests/RunCMake/ToolchainFile/IncludeDirectories.c5
-rw-r--r--Tests/RunCMake/ToolchainFile/IncludeDirectories.cmake2
-rw-r--r--Tests/RunCMake/ToolchainFile/IncludeDirectories/IncDir.h1
-rw-r--r--Tests/RunCMake/ToolchainFile/LinkFlagsInit-stdout.txt60
-rw-r--r--Tests/RunCMake/ToolchainFile/LinkFlagsInit-toolchain.cmake5
-rw-r--r--Tests/RunCMake/ToolchainFile/LinkFlagsInit.cmake7
-rw-r--r--Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake20
-rw-r--r--Tests/RunCMake/TransformDepfile/RunCMakeTest.cmake21
-rw-r--r--Tests/RunCMake/TransformDepfile/deps-unix.d6
-rw-r--r--Tests/RunCMake/TransformDepfile/deps-unix.d.txt8
-rw-r--r--Tests/RunCMake/TransformDepfile/deps-unix.tlog.txt6
-rw-r--r--Tests/RunCMake/TransformDepfile/deps-windows.d6
-rw-r--r--Tests/RunCMake/TransformDepfile/deps-windows.d.txt8
-rw-r--r--Tests/RunCMake/TransformDepfile/deps-windows.tlog.txt6
-rw-r--r--Tests/RunCMake/TransformDepfile/empty.d0
-rw-r--r--Tests/RunCMake/TransformDepfile/empty.d.txt0
-rw-r--r--Tests/RunCMake/TransformDepfile/empty.tlog.txt0
-rw-r--r--Tests/RunCMake/TransformDepfile/gccdepfile.cmake16
-rw-r--r--Tests/RunCMake/TransformDepfile/invalid-gcc-result.txt1
-rw-r--r--Tests/RunCMake/TransformDepfile/invalid-tlog-result.txt1
-rw-r--r--Tests/RunCMake/TransformDepfile/invalid.d1
-rw-r--r--Tests/RunCMake/TransformDepfile/noexist.d.txt0
-rw-r--r--Tests/RunCMake/TransformDepfile/noexist.tlog.txt0
-rw-r--r--Tests/RunCMake/TransformDepfile/vstlog.cmake16
-rw-r--r--Tests/RunCMake/UnityBuild/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/UnityBuild/RunCMakeTest.cmake42
-rw-r--r--Tests/RunCMake/UnityBuild/f.c5
-rw-r--r--Tests/RunCMake/UnityBuild/f.cxx5
-rw-r--r--Tests/RunCMake/UnityBuild/func.c6
-rw-r--r--Tests/RunCMake/UnityBuild/func.h6
-rw-r--r--Tests/RunCMake/UnityBuild/main.c6
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_anon_ns-build-check.cmake10
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_anon_ns.cmake11
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_anon_ns_group_mode.cmake19
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_anon_ns_no_unity_build.cmake11
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_anon_ns_test_files.cmake31
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_batchsize-check.cmake11
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_batchsize.cmake16
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_c-check.cmake5
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_c.cmake12
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx-check.cmake11
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx.cmake17
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_group-check.cmake42
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_group.cmake39
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_c_batch-check.cmake5
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_c_batch.cmake15
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_c_group-check.cmake11
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_c_group.cmake17
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build-check.cmake5
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build.cmake10
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build_group-check.cmake5
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build_group.cmake16
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include-check.cmake7
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include.cmake13
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_cxx-check.cmake5
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_cxx.cmake12
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_cxx_group-check.cmake27
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_cxx_group.cmake27
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_default_batchsize-check.cmake7
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_default_batchsize.cmake15
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_invalid_mode-result.txt1
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_invalid_mode-stderr.txt5
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_invalid_mode.cmake12
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_object_library.cmake13
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_order-check.cmake7
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_order.cmake12
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_runtest.cmake9
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_skip-check.cmake14
-rw-r--r--Tests/RunCMake/UnityBuild/unitybuild_skip.cmake30
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0078-NEW-stdout.txt2
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0078-NEW.cmake2
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0078-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0078-OLD-stdout.txt2
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0078-OLD.cmake2
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0078-WARN-stderr.txt10
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0078-WARN-stdout.txt2
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0078-WARN.cmake1
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0078-common.cmake12
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0086-NEW-nuild-check.cmake4
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0086-NEW.cmake2
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0086-OLD-build-check.cmake4
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0086-OLD.cmake2
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0086-WARN-stderr.txt11
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0086-WARN.cmake1
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0086-common.cmake11
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0122-NEW-check.cmake10
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0122-NEW.cmake2
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0122-OLD-check.cmake10
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0122-OLD.cmake2
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0122-WARN-stderr.txt10
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0122-WARN.cmake1
-rw-r--r--Tests/RunCMake/UseSWIG/CMP0122-common.cmake12
-rw-r--r--Tests/RunCMake/UseSWIG/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/UseSWIG/RunCMakeTest.cmake29
-rw-r--r--Tests/RunCMake/UseSWIG/example.i2
-rw-r--r--Tests/RunCMake/VS10Project/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/VS10Project/CSharpSourceGroup/foo.cs3
-rw-r--r--Tests/RunCMake/VS10Project/CSharpSourceGroup/images/empty.bmp0
-rw-r--r--Tests/RunCMake/VS10Project/CSharpSourceGroup/nested/baz.cs3
-rw-r--r--Tests/RunCMake/VS10Project/CustomCommandGenex-check.cmake37
-rw-r--r--Tests/RunCMake/VS10Project/CustomCommandGenex.cmake21
-rw-r--r--Tests/RunCMake/VS10Project/Dir/DirNested/foo_nested.cpp3
-rw-r--r--Tests/RunCMake/VS10Project/Dir/foo.cpp3
-rw-r--r--Tests/RunCMake/VS10Project/ExplicitCMakeLists-check.cmake25
-rw-r--r--Tests/RunCMake/VS10Project/ExplicitCMakeLists.cmake3
-rw-r--r--Tests/RunCMake/VS10Project/InterfaceLibSources-check.cmake25
-rw-r--r--Tests/RunCMake/VS10Project/InterfaceLibSources.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/Prefixed/PrefixedNested/bar_nested.cpp3
-rw-r--r--Tests/RunCMake/VS10Project/Prefixed/bar.cpp3
-rw-r--r--Tests/RunCMake/VS10Project/RunCMakeTest.cmake70
-rw-r--r--Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake36
-rw-r--r--Tests/RunCMake/VS10Project/RuntimeLibrary.cmake20
-rw-r--r--Tests/RunCMake/VS10Project/SourceGroupCMakeLists-check.cmake11
-rw-r--r--Tests/RunCMake/VS10Project/SourceGroupCMakeLists.cmake3
-rw-r--r--Tests/RunCMake/VS10Project/SourceGroupHelpers.cmake35
-rw-r--r--Tests/RunCMake/VS10Project/SourceGroupTreeCMakeLists-check.cmake26
-rw-r--r--Tests/RunCMake/VS10Project/SourceGroupTreeCMakeLists.cmake45
-rw-r--r--Tests/RunCMake/VS10Project/UnityBuildNative-check.cmake45
-rw-r--r--Tests/RunCMake/VS10Project/UnityBuildNative.cmake12
-rw-r--r--Tests/RunCMake/VS10Project/UnityBuildNativeGrouped-check.cmake56
-rw-r--r--Tests/RunCMake/VS10Project/UnityBuildNativeGrouped.cmake20
-rw-r--r--Tests/RunCMake/VS10Project/UnityBuildPre2017-check.cmake48
-rw-r--r--Tests/RunCMake/VS10Project/UnityBuildPre2017.cmake12
-rw-r--r--Tests/RunCMake/VS10Project/UnityBuildPre2017Grouped-check.cmake59
-rw-r--r--Tests/RunCMake/VS10Project/UnityBuildPre2017Grouped.cmake20
-rw-r--r--Tests/RunCMake/VS10Project/VSDotnetTargetFrameworkVersion.cmake10
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpCompilerOpts-check.cmake64
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpCompilerOpts.cmake14
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpCustomTags-check.cmake34
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpCustomTags-stderr.txt3
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpCustomTags.cmake26
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpDefines-check.cmake64
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpDefines.cmake18
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpDeployFiles-check.cmake67
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpDeployFiles.cmake27
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpDocumentationFile-check.cmake26
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpDocumentationFile.cmake8
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpReferenceProps-check.cmake49
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpReferenceProps-stderr.txt8
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpReferenceProps.cmake19
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpWithoutSources-check.cmake5
-rw-r--r--Tests/RunCMake/VS10Project/VsCSharpWithoutSources.cmake7
-rw-r--r--Tests/RunCMake/VS10Project/VsConfigurationType-check.cmake24
-rw-r--r--Tests/RunCMake/VS10Project/VsConfigurationType.cmake3
-rw-r--r--Tests/RunCMake/VS10Project/VsCsharpSourceGroup-check.cmake23
-rw-r--r--Tests/RunCMake/VS10Project/VsCsharpSourceGroup.cmake22
-rw-r--r--Tests/RunCMake/VS10Project/VsCsharpSourceGroup.png0
-rw-r--r--Tests/RunCMake/VS10Project/VsCsharpSourceGroupHelpers.cmake15
-rw-r--r--Tests/RunCMake/VS10Project/VsCustomProps-check.cmake25
-rw-r--r--Tests/RunCMake/VS10Project/VsCustomProps.cmake7
-rw-r--r--Tests/RunCMake/VS10Project/VsDebuggerCommand-check.cmake24
-rw-r--r--Tests/RunCMake/VS10Project/VsDebuggerCommand.cmake6
-rw-r--r--Tests/RunCMake/VS10Project/VsDebuggerCommandArguments-check.cmake24
-rw-r--r--Tests/RunCMake/VS10Project/VsDebuggerCommandArguments.cmake6
-rw-r--r--Tests/RunCMake/VS10Project/VsDebuggerEnvironment-check.cmake24
-rw-r--r--Tests/RunCMake/VS10Project/VsDebuggerEnvironment.cmake6
-rw-r--r--Tests/RunCMake/VS10Project/VsDebuggerWorkingDir-check.cmake24
-rw-r--r--Tests/RunCMake/VS10Project/VsDebuggerWorkingDir.cmake6
-rw-r--r--Tests/RunCMake/VS10Project/VsDeployEnabled-check.cmake58
-rw-r--r--Tests/RunCMake/VS10Project/VsDeployEnabled.cmake12
-rw-r--r--Tests/RunCMake/VS10Project/VsDotnetTargetFramework-check.cmake40
-rw-r--r--Tests/RunCMake/VS10Project/VsDotnetTargetFramework.cmake11
-rw-r--r--Tests/RunCMake/VS10Project/VsDotnetTargetFrameworkVersion-check.cmake40
-rw-r--r--Tests/RunCMake/VS10Project/VsDpiAware-check.cmake41
-rw-r--r--Tests/RunCMake/VS10Project/VsDpiAware.cmake19
-rw-r--r--Tests/RunCMake/VS10Project/VsDpiAwareBadParam-result.txt1
-rw-r--r--Tests/RunCMake/VS10Project/VsDpiAwareBadParam-stderr.txt3
-rw-r--r--Tests/RunCMake/VS10Project/VsDpiAwareBadParam.cmake8
-rw-r--r--Tests/RunCMake/VS10Project/VsGlobals-check.cmake65
-rw-r--r--Tests/RunCMake/VS10Project/VsGlobals.cmake9
-rw-r--r--Tests/RunCMake/VS10Project/VsJustMyCode-check.cmake38
-rw-r--r--Tests/RunCMake/VS10Project/VsJustMyCode.cmake24
-rw-r--r--Tests/RunCMake/VS10Project/VsPackageReferences-check.cmake61
-rw-r--r--Tests/RunCMake/VS10Project/VsPackageReferences.cmake13
-rw-r--r--Tests/RunCMake/VS10Project/VsPlatformToolset-check.cmake36
-rw-r--r--Tests/RunCMake/VS10Project/VsPlatformToolset.cmake6
-rw-r--r--Tests/RunCMake/VS10Project/VsPrecompileHeaders-check.cmake66
-rw-r--r--Tests/RunCMake/VS10Project/VsPrecompileHeaders.cmake4
-rw-r--r--Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName-result.txt1
-rw-r--r--Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName-stderr.txt7
-rw-r--r--Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName.cmake9
-rw-r--r--Tests/RunCMake/VS10Project/VsProjectImport-check.cmake28
-rw-r--r--Tests/RunCMake/VS10Project/VsProjectImport.cmake11
-rw-r--r--Tests/RunCMake/VS10Project/VsSdkDirectories-check.cmake88
-rw-r--r--Tests/RunCMake/VS10Project/VsSdkDirectories.cmake11
-rw-r--r--Tests/RunCMake/VS10Project/VsSettings-check.cmake23
-rw-r--r--Tests/RunCMake/VS10Project/VsSettings.cmake5
-rw-r--r--Tests/RunCMake/VS10Project/VsSourceSettingsTool-check.cmake34
-rw-r--r--Tests/RunCMake/VS10Project/VsSourceSettingsTool.cmake5
-rw-r--r--Tests/RunCMake/VS10Project/VsSpectreMitigation-check.cmake30
-rw-r--r--Tests/RunCMake/VS10Project/VsSpectreMitigation.cmake8
-rw-r--r--Tests/RunCMake/VS10Project/VsTargetsFileReferences-check.cmake45
-rw-r--r--Tests/RunCMake/VS10Project/VsTargetsFileReferences.cmake9
-rw-r--r--Tests/RunCMake/VS10Project/VsVCTargetsPath-check.cmake32
-rw-r--r--Tests/RunCMake/VS10Project/VsVCTargetsPath.cmake3
-rw-r--r--Tests/RunCMake/VS10Project/VsWinRTByDefault-check.cmake66
-rw-r--r--Tests/RunCMake/VS10Project/VsWinRTByDefault.cmake16
-rw-r--r--Tests/RunCMake/VS10Project/bar.cpp3
-rw-r--r--Tests/RunCMake/VS10Project/baz.cpp3
-rw-r--r--Tests/RunCMake/VS10Project/empty.c0
-rw-r--r--Tests/RunCMake/VS10Project/empty.cxx0
-rw-r--r--Tests/RunCMake/VS10Project/foo.cpp3
-rw-r--r--Tests/RunCMake/VS10Project/foo.cs3
-rw-r--r--Tests/RunCMake/VS10Project/iface.h0
-rw-r--r--Tests/RunCMake/VS10Project/my.props5
-rw-r--r--Tests/RunCMake/VS10Project/shader.hlsl1
-rw-r--r--Tests/RunCMake/VS10Project/shader2.hlsl1
-rw-r--r--Tests/RunCMake/VS10ProjectWinCE/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/VS10ProjectWinCE/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy-check.cmake118
-rw-r--r--Tests/RunCMake/VS10ProjectWinCE/VsCEDebuggerDeploy.cmake14
-rw-r--r--Tests/RunCMake/VS10ProjectWinCE/VsCSharpCFProject-check.cmake54
-rw-r--r--Tests/RunCMake/VS10ProjectWinCE/VsCSharpCFProject.cmake8
-rw-r--r--Tests/RunCMake/VS10ProjectWinCE/foo.cpp3
-rw-r--r--Tests/RunCMake/VS10ProjectWinCE/foo.cs3
-rw-r--r--Tests/RunCMake/VSSolution/AddPackageToDefault-check.cmake29
-rw-r--r--Tests/RunCMake/VSSolution/AddPackageToDefault.cmake2
-rw-r--r--Tests/RunCMake/VSSolution/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/VSSolution/MorePost-check.cmake5
-rw-r--r--Tests/RunCMake/VSSolution/MorePost.cmake2
-rw-r--r--Tests/RunCMake/VSSolution/MorePre-check.cmake5
-rw-r--r--Tests/RunCMake/VSSolution/MorePre.cmake2
-rw-r--r--Tests/RunCMake/VSSolution/OnePost-check.cmake4
-rw-r--r--Tests/RunCMake/VSSolution/OnePost.cmake1
-rw-r--r--Tests/RunCMake/VSSolution/OnePre-check.cmake4
-rw-r--r--Tests/RunCMake/VSSolution/OnePre.cmake1
-rw-r--r--Tests/RunCMake/VSSolution/Override1-check.cmake4
-rw-r--r--Tests/RunCMake/VSSolution/Override1.cmake2
-rw-r--r--Tests/RunCMake/VSSolution/Override2-check.cmake4
-rw-r--r--Tests/RunCMake/VSSolution/Override2.cmake2
-rw-r--r--Tests/RunCMake/VSSolution/Override3-check.cmake3
-rw-r--r--Tests/RunCMake/VSSolution/Override3.cmake4
-rw-r--r--Tests/RunCMake/VSSolution/PrePost-check.cmake6
-rw-r--r--Tests/RunCMake/VSSolution/PrePost.cmake4
-rw-r--r--Tests/RunCMake/VSSolution/RunCMakeTest.cmake18
-rw-r--r--Tests/RunCMake/VSSolution/StartupProject-check.cmake5
-rw-r--r--Tests/RunCMake/VSSolution/StartupProject.cmake2
-rw-r--r--Tests/RunCMake/VSSolution/StartupProjectMissing-check.cmake5
-rw-r--r--Tests/RunCMake/VSSolution/StartupProjectMissing-stderr.txt4
-rw-r--r--Tests/RunCMake/VSSolution/StartupProjectMissing.cmake1
-rw-r--r--Tests/RunCMake/VSSolution/StartupProjectUseFolders-check.cmake9
-rw-r--r--Tests/RunCMake/VSSolution/StartupProjectUseFolders.cmake3
-rw-r--r--Tests/RunCMake/VSSolution/solution_parsing.cmake78
-rw-r--r--Tests/RunCMake/VisibilityPreset/CMP0063-Common.cmake7
-rw-r--r--Tests/RunCMake/VisibilityPreset/CMP0063-NEW.cmake8
-rw-r--r--Tests/RunCMake/VisibilityPreset/CMP0063-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/VisibilityPreset/CMP0063-OLD.cmake8
-rw-r--r--Tests/RunCMake/VisibilityPreset/CMP0063-WARN-exe-stderr.txt15
-rw-r--r--Tests/RunCMake/VisibilityPreset/CMP0063-WARN-exe.cmake11
-rw-r--r--Tests/RunCMake/VisibilityPreset/CMP0063-WARN-no.cmake8
-rw-r--r--Tests/RunCMake/VisibilityPreset/CMP0063-WARN-obj-stderr.txt15
-rw-r--r--Tests/RunCMake/VisibilityPreset/CMP0063-WARN-obj.cmake11
-rw-r--r--Tests/RunCMake/VisibilityPreset/CMP0063-WARN-sta-stderr.txt15
-rw-r--r--Tests/RunCMake/VisibilityPreset/CMP0063-WARN-sta.cmake11
-rw-r--r--Tests/RunCMake/VisibilityPreset/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/VisibilityPreset/PropertyTypo-result.txt1
-rw-r--r--Tests/RunCMake/VisibilityPreset/PropertyTypo-stderr.txt1
-rw-r--r--Tests/RunCMake/VisibilityPreset/PropertyTypo.cmake8
-rw-r--r--Tests/RunCMake/VisibilityPreset/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/VisibilityPreset/lib.cpp5
-rw-r--r--Tests/RunCMake/Win32GenEx/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Win32GenEx/RunCMakeTest.cmake28
-rw-r--r--Tests/RunCMake/Win32GenEx/Win32GenEx-debug.cmake1
-rw-r--r--Tests/RunCMake/Win32GenEx/Win32GenEx-release.cmake1
-rw-r--r--Tests/RunCMake/Win32GenEx/Win32GenEx.cmake7
-rw-r--r--Tests/RunCMake/Win32GenEx/main.c14
-rw-r--r--Tests/RunCMake/WorkingDirectory/CMakeLists.txt.in3
-rw-r--r--Tests/RunCMake/WorkingDirectory/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-check.cmake3
-rw-r--r--Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-result.txt1
-rw-r--r--Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-stdout.txt1
-rw-r--r--Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir.cmake7
-rw-r--r--Tests/RunCMake/WorkingDirectory/dirNotExist-result.txt1
-rw-r--r--Tests/RunCMake/WorkingDirectory/dirNotExist-stderr.txt1
-rw-r--r--Tests/RunCMake/WorkingDirectory/dirNotExist-stdout.txt10
-rw-r--r--Tests/RunCMake/WorkingDirectory/dirNotExist.cmake6
-rw-r--r--Tests/RunCMake/WorkingDirectory/test.cmake.in15
-rw-r--r--Tests/RunCMake/WriteBasicConfigVersionFile/All.cmake973
-rw-r--r--Tests/RunCMake/WriteBasicConfigVersionFile/ArchIndependent.cmake63
-rw-r--r--Tests/RunCMake/WriteBasicConfigVersionFile/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/WriteBasicConfigVersionFile/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-Direct-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-Direct-stderr.txt6
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-Direct.cmake2
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-stderr.txt6
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW.cmake2
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-OLD-Direct.cmake2
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-OLD.cmake2
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN-Direct-stderr.txt9
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN-Direct.cmake2
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN-stderr.txt18
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN.cmake2
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/EmptyPrefix-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/EmptyPrefix-stderr.txt5
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/EmptyPrefix.cmake10
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/ExtraArgs-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/ExtraArgs-stderr.txt5
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/ExtraArgs.cmake10
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/FileTypo-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/FileTypo-stderr.txt5
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/FileTypo.cmake7
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidArgs-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidArgs-stderr.txt11
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidArgs.cmake6
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidCXXFeature-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidCXXFeature-stderr.txt5
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidCXXFeature.cmake10
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidCompiler-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidCompiler-stderr.txt5
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidCompiler.cmake10
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidFeature-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidFeature-stderr.txt6
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidFeature.cmake10
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidPrefix-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidPrefix-stderr.txt5
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/InvalidPrefix.cmake10
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/MultiBadOutDir-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/MultiBadOutDir-stderr.txt6
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/MultiBadOutDir.cmake12
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/MultiNoOutFileVar-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/MultiNoOutFileVar-stderr.txt5
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/MultiNoOutFileVar.cmake11
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/MultiNoOutdir-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/MultiNoOutdir-stderr.txt5
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/MultiNoOutdir.cmake11
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/NoCompiler-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/NoCompiler-stderr.txt6
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/NoCompiler.cmake10
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/NoFeature-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/NoFeature-stderr.txt6
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/NoFeature.cmake10
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/OldVersion-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/OldVersion-stderr.txt9
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/OldVersion.cmake10
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/PrefixTypo-result.txt1
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/PrefixTypo-stderr.txt5
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/PrefixTypo.cmake7
-rw-r--r--Tests/RunCMake/WriteCompilerDetectionHeader/RunCMakeTest.cmake25
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOff-check.cmake14
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOff.cmake7
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnNoSubdir-build-check.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnNoSubdir-check.cmake14
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnNoSubdir.cmake7
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnWithSubdir-build-check.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnWithSubdir-check.cmake14
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnWithSubdir.cmake8
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/ExternalFramework.cmake2
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake43
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/func.m6
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/main.m6
-rw-r--r--Tests/RunCMake/XcodeProject/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/XcodeProject/DeploymentTarget.c26
-rw-r--r--Tests/RunCMake/XcodeProject/DeploymentTarget.cmake28
-rw-r--r--Tests/RunCMake/XcodeProject/ExplicitCMakeLists-check.cmake20
-rw-r--r--Tests/RunCMake/XcodeProject/ExplicitCMakeLists.cmake2
-rw-r--r--Tests/RunCMake/XcodeProject/ImplicitCMakeLists-check.cmake20
-rw-r--r--Tests/RunCMake/XcodeProject/ImplicitCMakeLists.cmake0
-rw-r--r--Tests/RunCMake/XcodeProject/InterfaceLibSources-check.cmake16
-rw-r--r--Tests/RunCMake/XcodeProject/InterfaceLibSources.cmake1
-rw-r--r--Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase.cmake132
-rw-r--r--Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase_BUILT_ONLY-check.cmake19
-rw-r--r--Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase_BUILT_ONLY.cmake1
-rw-r--r--Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase_Funcs.cmake57
-rw-r--r--Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase_INVALID-result.txt1
-rw-r--r--Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase_INVALID-stderr.txt1
-rw-r--r--Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase_INVALID.cmake4
-rw-r--r--Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase_KNOWN_LOCATION-check.cmake19
-rw-r--r--Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase_KNOWN_LOCATION.cmake1
-rw-r--r--Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase_NONE-check.cmake19
-rw-r--r--Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase_NONE.cmake1
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-result.txt1
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-stderr.txt10
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceFlags-result.txt1
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceFlags-stderr.txt10
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceFlags.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-result.txt1
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt10
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-result.txt1
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt10
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject/RunCMakeTest.cmake416
-rw-r--r--Tests/RunCMake/XcodeProject/SearchPaths-check.cmake76
-rw-r--r--Tests/RunCMake/XcodeProject/SearchPaths.cmake21
-rw-r--r--Tests/RunCMake/XcodeProject/XCTestAddBundle.cmake17
-rw-r--r--Tests/RunCMake/XcodeProject/XCTestLookup.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeAttributeGenex-check.cmake55
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeAttributeGenex.cmake16
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeAttributeGenexError-result.txt1
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeAttributeGenexError-stderr.txt6
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeAttributeGenexError.cmake4
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeAttributeLocation-check.cmake7
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeAttributeLocation.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeBundles-install-check.cmake8
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeBundles.cmake144
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeDependOnZeroCheck-build-stdout.txt3
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeDependOnZeroCheck.cmake4
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand-result.txt1
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand-stderr.txt13
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeFileType-check.cmake10
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeFileType.cmake4
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeGenerateTopLevelProjectOnly-check.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeGenerateTopLevelProjectOnly.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeGenerateTopLevelProjectOnlyWithObjectLibrary.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeIOSInstallCombined-cmakeinstall-check.cmake2
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeIOSInstallCombined-install-check.cmake30
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeIOSInstallCombined.cmake36
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeIOSInstallCombinedPrune-install-check.cmake26
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeIOSInstallCombinedPrune-install-stdout.txt2
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeIOSInstallCombinedPrune.cmake41
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeIOSInstallCombinedSingleArch-cmakeinstall-check.cmake2
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeIOSInstallCombinedSingleArch-install-check.cmake25
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeIOSInstallCombinedSingleArch.cmake24
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeInstallIOS-install-stdout.txt2
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeInstallIOS.cmake9
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeMultiplatform.cmake14
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeObjcFlags.cmake12
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeObjcxxFlags.cmake12
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeObjectLibsInTwoProjects.cmake5
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeObjectNeedsEscape-check.cmake7
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeObjectNeedsEscape.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeObjectNeedsQuote-check.cmake7
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeObjectNeedsQuote.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeOptimizationFlags-check.cmake7
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeOptimizationFlags.cmake20
-rw-r--r--Tests/RunCMake/XcodeProject/XcodePlatformFrameworks.cmake6
-rw-r--r--Tests/RunCMake/XcodeProject/XcodePrecompileHeaders-check.cmake35
-rw-r--r--Tests/RunCMake/XcodeProject/XcodePrecompileHeaders.cmake4
-rw-r--r--Tests/RunCMake/XcodeProject/XcodePreserveNonOptimizationFlags-check.cmake8
-rw-r--r--Tests/RunCMake/XcodeProject/XcodePreserveNonOptimizationFlags.cmake12
-rw-r--r--Tests/RunCMake/XcodeProject/XcodePreserveObjcFlag-check.cmake7
-rw-r--r--Tests/RunCMake/XcodeProject/XcodePreserveObjcFlag.cmake6
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeRemoveExcessiveISystem.cmake52
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeSchemaGeneration.cmake5
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake53
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake43
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeTbdStub-stdout.txt1
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeTbdStub.cmake2
-rw-r--r--Tests/RunCMake/XcodeProject/foo.cpp3
-rw-r--r--Tests/RunCMake/XcodeProject/foo.swift2
-rw-r--r--Tests/RunCMake/XcodeProject/iface.h0
-rw-r--r--Tests/RunCMake/XcodeProject/main.c0
-rw-r--r--Tests/RunCMake/XcodeProject/main.cpp4
-rw-r--r--Tests/RunCMake/XcodeProject/main.m3
-rw-r--r--Tests/RunCMake/XcodeProject/myfuncs.m3
-rw-r--r--Tests/RunCMake/XcodeProject/myfuncs.mm3
-rw-r--r--Tests/RunCMake/XcodeProject/osx.cmake18
-rw-r--r--Tests/RunCMake/XcodeProject/someFileWithoutSpecialChars0
-rw-r--r--Tests/RunCMake/XcodeProject/src-default0
-rw-r--r--Tests/RunCMake/XcodeProject/src-explicit0
-rw-r--r--Tests/RunCMake/XcodeProject/src-lastKnown0
-rw-r--r--Tests/RunCMake/XcodeProject/subproject/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/XcodeProject/subproject_two_object_libs/CMakeLists.txt31
-rw-r--r--Tests/RunCMake/XcodeProject/subproject_two_object_libs/dummy.cpp5
-rw-r--r--Tests/RunCMake/XcodeProject/subproject_with_object_lib/CMakeLists.txt7
-rw-r--r--Tests/RunCMake/XcodeProject/subproject_with_object_lib/dummy.cpp5
-rw-r--r--Tests/RunCMake/XcodeProject/use_cmath.cpp6
-rw-r--r--Tests/RunCMake/XcodeProject/zerocheck/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/add_custom_command/AppendLiteralQuotes-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/AppendLiteralQuotes-stderr.txt7
-rw-r--r--Tests/RunCMake/add_custom_command/AppendLiteralQuotes.cmake2
-rw-r--r--Tests/RunCMake/add_custom_command/AppendNoOutput-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/AppendNoOutput-stderr.txt4
-rw-r--r--Tests/RunCMake/add_custom_command/AppendNoOutput.cmake1
-rw-r--r--Tests/RunCMake/add_custom_command/AppendNotOutput-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt8
-rw-r--r--Tests/RunCMake/add_custom_command/AppendNotOutput.cmake1
-rw-r--r--Tests/RunCMake/add_custom_command/AssigningMultipleTargets.cmake13
-rw-r--r--Tests/RunCMake/add_custom_command/BadArgument-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/BadArgument-stderr.txt4
-rw-r--r--Tests/RunCMake/add_custom_command/BadArgument.cmake1
-rw-r--r--Tests/RunCMake/add_custom_command/BadByproduct-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/BadByproduct-stderr.txt67
-rw-r--r--Tests/RunCMake/add_custom_command/BadByproduct.cmake9
-rw-r--r--Tests/RunCMake/add_custom_command/BadCommand-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/BadCommand-stderr.txt21
-rw-r--r--Tests/RunCMake/add_custom_command/BadCommand.cmake3
-rw-r--r--Tests/RunCMake/add_custom_command/BadOutput-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/BadOutput-stderr.txt67
-rw-r--r--Tests/RunCMake/add_custom_command/BadOutput.cmake9
-rw-r--r--Tests/RunCMake/add_custom_command/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/add_custom_command/GeneratedProperty.cmake10
-rw-r--r--Tests/RunCMake/add_custom_command/LiteralQuotes-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/LiteralQuotes-stderr.txt7
-rw-r--r--Tests/RunCMake/add_custom_command/LiteralQuotes.cmake1
-rw-r--r--Tests/RunCMake/add_custom_command/NoArguments-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/NoArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/add_custom_command/NoArguments.cmake1
-rw-r--r--Tests/RunCMake/add_custom_command/NoOutputOrTarget-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/NoOutputOrTarget-stderr.txt4
-rw-r--r--Tests/RunCMake/add_custom_command/NoOutputOrTarget.cmake1
-rw-r--r--Tests/RunCMake/add_custom_command/OutputAndTarget-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/OutputAndTarget-stderr.txt5
-rw-r--r--Tests/RunCMake/add_custom_command/OutputAndTarget.cmake1
-rw-r--r--Tests/RunCMake/add_custom_command/PrintDir.cmake1
-rw-r--r--Tests/RunCMake/add_custom_command/RemoveEmptyCommands-check.cmake63
-rw-r--r--Tests/RunCMake/add_custom_command/RemoveEmptyCommands.cmake22
-rw-r--r--Tests/RunCMake/add_custom_command/RunCMakeTest.cmake45
-rw-r--r--Tests/RunCMake/add_custom_command/SourceByproducts-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/SourceByproducts-stderr.txt4
-rw-r--r--Tests/RunCMake/add_custom_command/SourceByproducts.cmake1
-rw-r--r--Tests/RunCMake/add_custom_command/SourceUsesTerminal-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/SourceUsesTerminal-stderr.txt4
-rw-r--r--Tests/RunCMake/add_custom_command/SourceUsesTerminal.cmake1
-rw-r--r--Tests/RunCMake/add_custom_command/TargetImported-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/TargetImported-stderr.txt4
-rw-r--r--Tests/RunCMake/add_custom_command/TargetImported.cmake2
-rw-r--r--Tests/RunCMake/add_custom_command/TargetLiteralQuotes-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/TargetLiteralQuotes-stderr.txt7
-rw-r--r--Tests/RunCMake/add_custom_command/TargetLiteralQuotes.cmake2
-rw-r--r--Tests/RunCMake/add_custom_command/TargetNotInDir-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/TargetNotInDir-stderr.txt4
-rw-r--r--Tests/RunCMake/add_custom_command/TargetNotInDir.cmake2
-rw-r--r--Tests/RunCMake/add_custom_command/TargetNotInDir/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/WorkingDirectory-build-multi-config-stdout.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/WorkingDirectory-build-single-config-stdout.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/WorkingDirectory.cmake9
-rw-r--r--Tests/RunCMake/add_custom_command/a.c3
-rw-r--r--Tests/RunCMake/add_custom_command/generate-once.cmake8
-rw-r--r--Tests/RunCMake/add_custom_target/BadByproduct-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_target/BadByproduct-stderr.txt67
-rw-r--r--Tests/RunCMake/add_custom_target/BadByproduct.cmake9
-rw-r--r--Tests/RunCMake/add_custom_target/BadCommand-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_target/BadCommand-stderr.txt21
-rw-r--r--Tests/RunCMake/add_custom_target/BadCommand.cmake4
-rw-r--r--Tests/RunCMake/add_custom_target/BadTargetName-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_target/BadTargetName-stderr.txt17
-rw-r--r--Tests/RunCMake/add_custom_target/BadTargetName.cmake3
-rw-r--r--Tests/RunCMake/add_custom_target/ByproductsNoCommand-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_target/ByproductsNoCommand-stderr.txt4
-rw-r--r--Tests/RunCMake/add_custom_target/ByproductsNoCommand.cmake1
-rw-r--r--Tests/RunCMake/add_custom_target/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/add_custom_target/CommandExpandsEmpty.cmake1
-rw-r--r--Tests/RunCMake/add_custom_target/GeneratedProperty.cmake14
-rw-r--r--Tests/RunCMake/add_custom_target/LiteralQuotes-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_target/LiteralQuotes-stderr.txt7
-rw-r--r--Tests/RunCMake/add_custom_target/LiteralQuotes.cmake1
-rw-r--r--Tests/RunCMake/add_custom_target/NoArguments-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_target/NoArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/add_custom_target/NoArguments.cmake1
-rw-r--r--Tests/RunCMake/add_custom_target/RunCMakeTest.cmake25
-rw-r--r--Tests/RunCMake/add_custom_target/TargetOrder.cmake31
-rw-r--r--Tests/RunCMake/add_custom_target/UsesTerminalNoCommand-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_target/UsesTerminalNoCommand-stderr.txt4
-rw-r--r--Tests/RunCMake/add_custom_target/UsesTerminalNoCommand.cmake1
-rw-r--r--Tests/RunCMake/add_dependencies/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/add_dependencies/NoTarget-result.txt1
-rw-r--r--Tests/RunCMake/add_dependencies/NoTarget-stderr.txt9
-rw-r--r--Tests/RunCMake/add_dependencies/NoTarget.cmake1
-rw-r--r--Tests/RunCMake/add_dependencies/ReadOnlyProperty-result.txt1
-rw-r--r--Tests/RunCMake/add_dependencies/ReadOnlyProperty-stderr.txt1
-rw-r--r--Tests/RunCMake/add_dependencies/ReadOnlyProperty.cmake6
-rw-r--r--Tests/RunCMake/add_dependencies/RetrieveDependencies.cmake16
-rw-r--r--Tests/RunCMake/add_dependencies/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/add_dependencies/a.c3
-rw-r--r--Tests/RunCMake/add_dependencies/b.c3
-rw-r--r--Tests/RunCMake/add_dependencies/c.c3
-rw-r--r--Tests/RunCMake/add_executable/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/add_executable/NoSources-result.txt1
-rw-r--r--Tests/RunCMake/add_executable/NoSources-stderr.txt6
-rw-r--r--Tests/RunCMake/add_executable/NoSources.cmake1
-rw-r--r--Tests/RunCMake/add_executable/NoSourcesButLinkObjects-result.txt1
-rw-r--r--Tests/RunCMake/add_executable/NoSourcesButLinkObjects-stderr.txt6
-rw-r--r--Tests/RunCMake/add_executable/NoSourcesButLinkObjects.cmake5
-rw-r--r--Tests/RunCMake/add_executable/OnlyObjectSources.cmake5
-rw-r--r--Tests/RunCMake/add_executable/RunCMakeTest.cmake7
-rw-r--r--Tests/RunCMake/add_executable/test.cpp0
-rw-r--r--Tests/RunCMake/add_library/CMP0073-stderr.txt10
-rw-r--r--Tests/RunCMake/add_library/CMP0073-stdout.txt3
-rw-r--r--Tests/RunCMake/add_library/CMP0073.cmake18
-rw-r--r--Tests/RunCMake/add_library/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/add_library/INTERFACEwithNoSources.cmake1
-rw-r--r--Tests/RunCMake/add_library/INTERFACEwithNoSourcesButLinkObjects.cmake5
-rw-r--r--Tests/RunCMake/add_library/INTERFACEwithOnlyObjectSources.cmake5
-rw-r--r--Tests/RunCMake/add_library/MODULEwithNoSources-result.txt1
-rw-r--r--Tests/RunCMake/add_library/MODULEwithNoSources-stderr.txt6
-rw-r--r--Tests/RunCMake/add_library/MODULEwithNoSources.cmake1
-rw-r--r--Tests/RunCMake/add_library/MODULEwithNoSourcesButLinkObjects-result.txt1
-rw-r--r--Tests/RunCMake/add_library/MODULEwithNoSourcesButLinkObjects-stderr.txt6
-rw-r--r--Tests/RunCMake/add_library/MODULEwithNoSourcesButLinkObjects.cmake5
-rw-r--r--Tests/RunCMake/add_library/MODULEwithOnlyObjectSources.cmake5
-rw-r--r--Tests/RunCMake/add_library/OBJECTwithNoSources-result.txt1
-rw-r--r--Tests/RunCMake/add_library/OBJECTwithNoSources-stderr.txt6
-rw-r--r--Tests/RunCMake/add_library/OBJECTwithNoSources.cmake1
-rw-r--r--Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-result.txt1
-rw-r--r--Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-stderr.txt6
-rw-r--r--Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects.cmake5
-rw-r--r--Tests/RunCMake/add_library/OBJECTwithOnlyObjectSources.cmake5
-rw-r--r--Tests/RunCMake/add_library/RunCMakeTest.cmake26
-rw-r--r--Tests/RunCMake/add_library/SHAREDwithNoSources-result.txt1
-rw-r--r--Tests/RunCMake/add_library/SHAREDwithNoSources-stderr.txt6
-rw-r--r--Tests/RunCMake/add_library/SHAREDwithNoSources.cmake1
-rw-r--r--Tests/RunCMake/add_library/SHAREDwithNoSourcesButLinkObjects-result.txt1
-rw-r--r--Tests/RunCMake/add_library/SHAREDwithNoSourcesButLinkObjects-stderr.txt6
-rw-r--r--Tests/RunCMake/add_library/SHAREDwithNoSourcesButLinkObjects.cmake5
-rw-r--r--Tests/RunCMake/add_library/SHAREDwithOnlyObjectSources.cmake5
-rw-r--r--Tests/RunCMake/add_library/STATICwithNoSources-result.txt1
-rw-r--r--Tests/RunCMake/add_library/STATICwithNoSources-stderr.txt6
-rw-r--r--Tests/RunCMake/add_library/STATICwithNoSources.cmake1
-rw-r--r--Tests/RunCMake/add_library/STATICwithNoSourcesButLinkObjects-result.txt1
-rw-r--r--Tests/RunCMake/add_library/STATICwithNoSourcesButLinkObjects-stderr.txt6
-rw-r--r--Tests/RunCMake/add_library/STATICwithNoSourcesButLinkObjects.cmake5
-rw-r--r--Tests/RunCMake/add_library/STATICwithOnlyObjectSources.cmake5
-rw-r--r--Tests/RunCMake/add_library/UNKNOWNwithNoSources.cmake1
-rw-r--r--Tests/RunCMake/add_library/UNKNOWNwithNoSourcesButLinkObjects.cmake5
-rw-r--r--Tests/RunCMake/add_library/UNKNOWNwithOnlyObjectSources-result.txt1
-rw-r--r--Tests/RunCMake/add_library/UNKNOWNwithOnlyObjectSources-stderr.txt4
-rw-r--r--Tests/RunCMake/add_library/UNKNOWNwithOnlyObjectSources.cmake5
-rw-r--r--Tests/RunCMake/add_library/empty.c0
-rw-r--r--Tests/RunCMake/add_library/test.cpp0
-rw-r--r--Tests/RunCMake/add_link_options/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/add_link_options/GENEX_LINK_LANG.cmake16
-rw-r--r--Tests/RunCMake/add_link_options/LINKER_SHELL_expansion-build-check.cmake2
-rw-r--r--Tests/RunCMake/add_link_options/LINKER_SHELL_expansion.cmake4
-rw-r--r--Tests/RunCMake/add_link_options/LINKER_expansion-build-check.cmake2
-rw-r--r--Tests/RunCMake/add_link_options/LINKER_expansion-list.cmake36
-rw-r--r--Tests/RunCMake/add_link_options/LINKER_expansion-validation.cmake18
-rw-r--r--Tests/RunCMake/add_link_options/LINKER_expansion.cmake4
-rw-r--r--Tests/RunCMake/add_link_options/LINK_OPTIONS-exe-check.cmake10
-rw-r--r--Tests/RunCMake/add_link_options/LINK_OPTIONS-exe-result.txt1
-rw-r--r--Tests/RunCMake/add_link_options/LINK_OPTIONS-mod-check.cmake10
-rw-r--r--Tests/RunCMake/add_link_options/LINK_OPTIONS-mod-result.txt1
-rw-r--r--Tests/RunCMake/add_link_options/LINK_OPTIONS-shared-check.cmake10
-rw-r--r--Tests/RunCMake/add_link_options/LINK_OPTIONS-shared-result.txt1
-rw-r--r--Tests/RunCMake/add_link_options/LINK_OPTIONS.cmake17
-rw-r--r--Tests/RunCMake/add_link_options/LinkOptionsExe.c4
-rw-r--r--Tests/RunCMake/add_link_options/LinkOptionsLib.c7
-rw-r--r--Tests/RunCMake/add_link_options/LinkOptionsLib.cxx7
-rw-r--r--Tests/RunCMake/add_link_options/RunCMakeTest.cmake53
-rw-r--r--Tests/RunCMake/add_link_options/bad_SHELL_usage-result.txt1
-rw-r--r--Tests/RunCMake/add_link_options/bad_SHELL_usage-stderr.txt4
-rw-r--r--Tests/RunCMake/add_link_options/bad_SHELL_usage.cmake6
-rw-r--r--Tests/RunCMake/add_link_options/dump.c13
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANGUAGE-exe-check.cmake2
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANGUAGE-exe-result.txt1
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANGUAGE-mod-check.cmake2
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANGUAGE-mod-result.txt1
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANGUAGE-shared_c-check.cmake5
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANGUAGE-shared_c-result.txt1
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANGUAGE-shared_cxx-check.cmake5
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANGUAGE-shared_cxx-result.txt1
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANGUAGE-validation.cmake17
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANGUAGE.cmake17
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANG_AND_ID-exe-check.cmake2
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANG_AND_ID-exe-result.txt1
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANG_AND_ID-mod-check.cmake2
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANG_AND_ID-mod-result.txt1
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANG_AND_ID-shared_c-check.cmake5
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANG_AND_ID-shared_c-result.txt1
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANG_AND_ID-shared_cxx-check.cmake5
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANG_AND_ID-shared_cxx-result.txt1
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANG_AND_ID-validation.cmake23
-rw-r--r--Tests/RunCMake/add_link_options/genex_LINK_LANG_AND_ID.cmake19
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-ExcludeFromAll/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-NEW-install-component-stdout.txt4
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-NEW-install-stdout.txt3
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-NEW.cmake3
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-Nested/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-Nested/sub/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-NestedSub/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-NestedSub/sub/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-None/CMakeLists.txt0
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-OLD-install-component-stdout.txt4
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-OLD-install-stdout.txt3
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-OLD.cmake3
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-Nested-install-component-stdout.txt4
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-Nested-install-stdout.txt3
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-Nested-stderr.txt7
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-Nested.cmake2
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-NestedSub-install-component-stdout.txt4
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-NestedSub-install-stdout.txt3
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-NestedSub-stderr.txt7
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-NestedSub.cmake1
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-NoTopInstall-install-component-stdout.txt3
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-NoTopInstall-install-stdout.txt2
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-NoTopInstall.cmake1
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-None-install-component-stdout.txt3
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-None-install-stdout.txt2
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-None.cmake2
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-install-component-stdout.txt4
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-install-stdout.txt3
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN-stderr.txt7
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082-WARN.cmake3
-rw-r--r--Tests/RunCMake/add_subdirectory/CMP0082/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/add_subdirectory/CMakeLists.txt10
-rw-r--r--Tests/RunCMake/add_subdirectory/DoesNotExist-result.txt1
-rw-r--r--Tests/RunCMake/add_subdirectory/DoesNotExist-stderr.txt5
-rw-r--r--Tests/RunCMake/add_subdirectory/DoesNotExist.cmake1
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll-build-sub-stderr.txt1
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake16
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt13
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/subsub.cpp4
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/bar.cpp1
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake34
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake37
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.cpp6
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/foo.h1
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/subinc.cpp4
-rw-r--r--Tests/RunCMake/add_subdirectory/ExcludeFromAll/zot.cpp4
-rw-r--r--Tests/RunCMake/add_subdirectory/Function-stdout.txt10
-rw-r--r--Tests/RunCMake/add_subdirectory/Function.cmake17
-rw-r--r--Tests/RunCMake/add_subdirectory/Function/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/add_subdirectory/Missing-result.txt1
-rw-r--r--Tests/RunCMake/add_subdirectory/Missing-stderr.txt8
-rw-r--r--Tests/RunCMake/add_subdirectory/Missing.cmake1
-rw-r--r--Tests/RunCMake/add_subdirectory/Missing/Missing.txt0
-rw-r--r--Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake60
-rw-r--r--Tests/RunCMake/add_subdirectory/main.cpp6
-rw-r--r--Tests/RunCMake/add_test/CMP0110-Common-AlphaNumeric.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-Common-BracketArgument.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-Common-EscapedSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-Common-FormerInvalidSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-Common-LeadingAndTrailingWhitespace.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-Common-OtherSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-Common-Quote.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-Common-Semicolon.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-Common-Space.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-Common-ValidSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-Common.cmake9
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-AlphaNumeric-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-AlphaNumeric.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-BracketArgument-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-BracketArgument.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-EscapedSpecialChars-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-EscapedSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-FormerInvalidSpecialChars-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-FormerInvalidSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-FormerInvalidSpecialCharsMC.cmake1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-GeneratorExpressionSyntax.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-LeadingAndTrailingWhitespace-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-LeadingAndTrailingWhitespace.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-OtherSpecialChars-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-OtherSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-Quote-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-Quote.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-Semicolon.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-Space.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-ValidSpecialChars-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-NEW-ValidSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-AlphaNumeric-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-AlphaNumeric.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-BracketArgument-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-BracketArgument.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-EscapedSpecialChars-ctest-result.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-EscapedSpecialChars-ctest-stderr.txt5
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-EscapedSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-FormerInvalidSpecialChars-ctest-result.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-FormerInvalidSpecialChars-ctest-stderr.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-FormerInvalidSpecialChars-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-FormerInvalidSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-FormerInvalidSpecialCharsMC-ctest-result.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-FormerInvalidSpecialCharsMC-ctest-stderr.txt3
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-FormerInvalidSpecialCharsMC.cmake1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-GeneratorExpressionSyntax.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-LeadingAndTrailingWhitespace-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-LeadingAndTrailingWhitespace.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-OtherSpecialChars-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-OtherSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-Quote-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-Quote.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-Semicolon-ctest-result.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-Semicolon-ctest-stderr.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-Semicolon-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-Semicolon.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-Space-ctest-result.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-Space-ctest-stderr.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-Space-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-Space.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-ValidSpecialChars-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-OLD-ValidSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-Test.cmake3
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-AlphaNumeric-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-AlphaNumeric.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-BracketArgument-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-BracketArgument-stderr.txt11
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-BracketArgument.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-EscapedSpecialChars-ctest-result.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-EscapedSpecialChars-ctest-stderr.txt5
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-EscapedSpecialChars-stderr.txt11
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-EscapedSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-FormerInvalidSpecialChars-ctest-result.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-FormerInvalidSpecialChars-ctest-stderr.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-FormerInvalidSpecialChars-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-FormerInvalidSpecialChars-stderr.txt13
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-FormerInvalidSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-FormerInvalidSpecialCharsMC-ctest-result.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-FormerInvalidSpecialCharsMC-ctest-stderr.txt3
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-FormerInvalidSpecialCharsMC-stderr.txt13
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-FormerInvalidSpecialCharsMC.cmake1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-GeneratorExpressionSyntax.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-LeadingAndTrailingWhitespace-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-LeadingAndTrailingWhitespace-stderr.txt11
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-LeadingAndTrailingWhitespace.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-OtherSpecialChars-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-OtherSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-Quote-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-Quote-stderr.txt11
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-Quote.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-Semicolon-ctest-result.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-Semicolon-ctest-stderr.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-Semicolon-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-Semicolon-stderr.txt11
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-Semicolon.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-Space-ctest-result.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-Space-ctest-stderr.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-Space-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-Space-stderr.txt11
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-Space.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-ValidSpecialChars-ctest-stdout.txt1
-rw-r--r--Tests/RunCMake/add_test/CMP0110-WARN-ValidSpecialChars.cmake2
-rw-r--r--Tests/RunCMake/add_test/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/add_test/RunCMakeTest.cmake35
-rw-r--r--Tests/RunCMake/alias_targets/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/alias_targets/RunCMakeTest.cmake24
-rw-r--r--Tests/RunCMake/alias_targets/add_dependencies-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/add_dependencies-stderr.txt5
-rw-r--r--Tests/RunCMake/alias_targets/add_dependencies.cmake9
-rw-r--r--Tests/RunCMake/alias_targets/add_executable-library-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/add_executable-library-stderr.txt5
-rw-r--r--Tests/RunCMake/alias_targets/add_executable-library.cmake6
-rw-r--r--Tests/RunCMake/alias_targets/add_library-executable-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/add_library-executable-stderr.txt5
-rw-r--r--Tests/RunCMake/alias_targets/add_library-executable.cmake6
-rw-r--r--Tests/RunCMake/alias_targets/alias-target-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/alias-target-stderr.txt5
-rw-r--r--Tests/RunCMake/alias_targets/alias-target.cmake8
-rw-r--r--Tests/RunCMake/alias_targets/duplicate-target-CMP0107-NEW-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/duplicate-target-CMP0107-NEW-stderr.txt30
-rw-r--r--Tests/RunCMake/alias_targets/duplicate-target-CMP0107-NEW.cmake4
-rw-r--r--Tests/RunCMake/alias_targets/duplicate-target-CMP0107-OLD.cmake4
-rw-r--r--Tests/RunCMake/alias_targets/duplicate-target.cmake20
-rw-r--r--Tests/RunCMake/alias_targets/empty.cpp7
-rw-r--r--Tests/RunCMake/alias_targets/exclude-from-all-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/exclude-from-all-stderr.txt4
-rw-r--r--Tests/RunCMake/alias_targets/exclude-from-all.cmake6
-rw-r--r--Tests/RunCMake/alias_targets/export-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/export-stderr.txt4
-rw-r--r--Tests/RunCMake/alias_targets/export.cmake8
-rw-r--r--Tests/RunCMake/alias_targets/get_property-subdir/CMakeLists.txt15
-rw-r--r--Tests/RunCMake/alias_targets/get_property.cmake59
-rw-r--r--Tests/RunCMake/alias_targets/imported-global-target-stderr.txt2
-rw-r--r--Tests/RunCMake/alias_targets/imported-global-target.cmake46
-rw-r--r--Tests/RunCMake/alias_targets/imported-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/imported-stderr.txt4
-rw-r--r--Tests/RunCMake/alias_targets/imported-target-stderr.txt2
-rw-r--r--Tests/RunCMake/alias_targets/imported-target-subdir1/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/alias_targets/imported-target-subdir2/CMakeLists.txt20
-rw-r--r--Tests/RunCMake/alias_targets/imported-target.cmake57
-rw-r--r--Tests/RunCMake/alias_targets/imported.cmake2
-rw-r--r--Tests/RunCMake/alias_targets/install-export-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/install-export-stderr.txt4
-rw-r--r--Tests/RunCMake/alias_targets/install-export.cmake9
-rw-r--r--Tests/RunCMake/alias_targets/invalid-name-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/invalid-name-stderr.txt4
-rw-r--r--Tests/RunCMake/alias_targets/invalid-name.cmake6
-rw-r--r--Tests/RunCMake/alias_targets/invalid-target-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/invalid-target-stderr.txt5
-rw-r--r--Tests/RunCMake/alias_targets/invalid-target.cmake2
-rw-r--r--Tests/RunCMake/alias_targets/multiple-targets-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/multiple-targets-stderr.txt4
-rw-r--r--Tests/RunCMake/alias_targets/multiple-targets.cmake7
-rw-r--r--Tests/RunCMake/alias_targets/name-conflict-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/name-conflict-stderr.txt5
-rw-r--r--Tests/RunCMake/alias_targets/name-conflict.cmake8
-rw-r--r--Tests/RunCMake/alias_targets/no-targets-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/no-targets-stderr.txt4
-rw-r--r--Tests/RunCMake/alias_targets/no-targets.cmake4
-rw-r--r--Tests/RunCMake/alias_targets/set_property-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/set_property-stderr.txt4
-rw-r--r--Tests/RunCMake/alias_targets/set_property.cmake8
-rw-r--r--Tests/RunCMake/alias_targets/set_target_properties-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/set_target_properties-stderr.txt4
-rw-r--r--Tests/RunCMake/alias_targets/set_target_properties.cmake8
-rw-r--r--Tests/RunCMake/alias_targets/target_include_directories-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/target_include_directories-stderr.txt4
-rw-r--r--Tests/RunCMake/alias_targets/target_include_directories.cmake8
-rw-r--r--Tests/RunCMake/alias_targets/target_link_libraries-result.txt1
-rw-r--r--Tests/RunCMake/alias_targets/target_link_libraries-stderr.txt4
-rw-r--r--Tests/RunCMake/alias_targets/target_link_libraries.cmake9
-rw-r--r--Tests/RunCMake/build_command/BeforeProject-stderr.txt7
-rw-r--r--Tests/RunCMake/build_command/BeforeProject.cmake3
-rw-r--r--Tests/RunCMake/build_command/CMP0061-NEW-stderr.txt10
-rw-r--r--Tests/RunCMake/build_command/CMP0061-NEW.cmake2
-rw-r--r--Tests/RunCMake/build_command/CMP0061-OLD-make-stderr.txt21
-rw-r--r--Tests/RunCMake/build_command/CMP0061-OLD-make.cmake2
-rw-r--r--Tests/RunCMake/build_command/CMP0061-OLD-other-stderr.txt21
-rw-r--r--Tests/RunCMake/build_command/CMP0061-OLD-other.cmake2
-rw-r--r--Tests/RunCMake/build_command/CMP0061Common.cmake10
-rw-r--r--Tests/RunCMake/build_command/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/build_command/ErrorsCommon.cmake55
-rw-r--r--Tests/RunCMake/build_command/ErrorsOFF-stderr.txt1
-rw-r--r--Tests/RunCMake/build_command/ErrorsOFF-stdout.txt1
-rw-r--r--Tests/RunCMake/build_command/ErrorsOFF.cmake2
-rw-r--r--Tests/RunCMake/build_command/ErrorsON-result.txt1
-rw-r--r--Tests/RunCMake/build_command/ErrorsON-stderr.txt21
-rw-r--r--Tests/RunCMake/build_command/ErrorsON-stdout.txt1
-rw-r--r--Tests/RunCMake/build_command/ErrorsON.cmake2
-rw-r--r--Tests/RunCMake/build_command/RunCMakeTest.cmake16
-rw-r--r--Tests/RunCMake/cmake_language/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/cmake_language/CheckIncludeGuard.cmake4
-rw-r--r--Tests/RunCMake/cmake_language/CheckProject/CMakeLists.txt19
-rw-r--r--Tests/RunCMake/cmake_language/CheckProject/lib.c0
-rw-r--r--Tests/RunCMake/cmake_language/RunCMakeTest.cmake84
-rw-r--r--Tests/RunCMake/cmake_language/call_double_evaluation-stderr.txt1
-rw-r--r--Tests/RunCMake/cmake_language/call_double_evaluation.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/call_expand_command_name-stderr.txt1
-rw-r--r--Tests/RunCMake/cmake_language/call_expand_command_name.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/call_expand_function_name-stderr.txt1
-rw-r--r--Tests/RunCMake/cmake_language/call_expand_function_name.cmake11
-rw-r--r--Tests/RunCMake/cmake_language/call_expanded_command-stderr.txt1
-rw-r--r--Tests/RunCMake/cmake_language/call_expanded_command.cmake6
-rw-r--r--Tests/RunCMake/cmake_language/call_expanded_command_and_arguments-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/call_expanded_command_and_arguments-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/call_expanded_command_and_arguments.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/call_expanded_command_with_explicit_argument-stderr.txt1
-rw-r--r--Tests/RunCMake/cmake_language/call_expanded_command_with_explicit_argument.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/call_invalid_command-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/call_invalid_command-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_language/call_invalid_command.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/call_message-stderr.txt1
-rw-r--r--Tests/RunCMake/cmake_language/call_message.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/call_message_fatal_error-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/call_message_fatal_error-stderr.txt5
-rw-r--r--Tests/RunCMake/cmake_language/call_message_fatal_error.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/call_no_parameters-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/call_no_parameters-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_language/call_no_parameters.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/call_preserve_arguments-stderr.txt6
-rw-r--r--Tests/RunCMake/cmake_language/call_preserve_arguments.cmake12
-rw-r--r--Tests/RunCMake/cmake_language/call_unknown_function-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/call_unknown_function-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_language/call_unknown_function.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/call_valid_command.cmake99
-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.txt1
-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/eval_expand_command_name-stderr.txt1
-rw-r--r--Tests/RunCMake/cmake_language/eval_expand_command_name.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/eval_expanded_command_and_arguments-stderr.txt1
-rw-r--r--Tests/RunCMake/cmake_language/eval_expanded_command_and_arguments.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/eval_extra_parameters_between_eval_and_code-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/eval_extra_parameters_between_eval_and_code-stderr.txt5
-rw-r--r--Tests/RunCMake/cmake_language/eval_extra_parameters_between_eval_and_code.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/eval_message-stderr.txt1
-rw-r--r--Tests/RunCMake/cmake_language/eval_message.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/eval_message_fatal_error-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/eval_message_fatal_error-stderr.txt5
-rw-r--r--Tests/RunCMake/cmake_language/eval_message_fatal_error.cmake5
-rw-r--r--Tests/RunCMake/cmake_language/eval_no_code-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/eval_no_code-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_language/eval_no_code.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/eval_no_parameters-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/eval_no_parameters-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_language/eval_no_parameters.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/eval_variable_outside_message-stderr.txt1
-rw-r--r--Tests/RunCMake/cmake_language/eval_variable_outside_message.cmake2
-rw-r--r--Tests/RunCMake/cmake_language/no_parameters-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/no_parameters-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_language/no_parameters.cmake1
-rw-r--r--Tests/RunCMake/cmake_language/unknown_meta_operation-result.txt1
-rw-r--r--Tests/RunCMake/cmake_language/unknown_meta_operation-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_language/unknown_meta_operation.cmake1
-rw-r--r--Tests/RunCMake/cmake_minimum_required/Before24-stderr.txt5
-rw-r--r--Tests/RunCMake/cmake_minimum_required/Before24.cmake1
-rw-r--r--Tests/RunCMake/cmake_minimum_required/Before2812-stderr.txt26
-rw-r--r--Tests/RunCMake/cmake_minimum_required/Before2812.cmake6
-rw-r--r--Tests/RunCMake/cmake_minimum_required/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/cmake_minimum_required/CompatBefore24-result.txt1
-rw-r--r--Tests/RunCMake/cmake_minimum_required/CompatBefore24-stderr.txt14
-rw-r--r--Tests/RunCMake/cmake_minimum_required/CompatBefore24.cmake2
-rw-r--r--Tests/RunCMake/cmake_minimum_required/Future.cmake1
-rw-r--r--Tests/RunCMake/cmake_minimum_required/PolicyBefore24-result.txt1
-rw-r--r--Tests/RunCMake/cmake_minimum_required/PolicyBefore24-stderr.txt6
-rw-r--r--Tests/RunCMake/cmake_minimum_required/PolicyBefore24.cmake2
-rw-r--r--Tests/RunCMake/cmake_minimum_required/Range-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_minimum_required/Range.cmake6
-rw-r--r--Tests/RunCMake/cmake_minimum_required/RangeBad-result.txt1
-rw-r--r--Tests/RunCMake/cmake_minimum_required/RangeBad-stderr.txt56
-rw-r--r--Tests/RunCMake/cmake_minimum_required/RangeBad.cmake10
-rw-r--r--Tests/RunCMake/cmake_minimum_required/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/cmake_minimum_required/Unknown-result.txt1
-rw-r--r--Tests/RunCMake/cmake_minimum_required/Unknown-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_minimum_required/Unknown.cmake1
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/ArgvN.cmake38
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/BadArgvN1-result.txt1
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/BadArgvN1-stderr.txt5
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/BadArgvN1.cmake4
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/BadArgvN2-result.txt1
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/BadArgvN2-stderr.txt5
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/BadArgvN2.cmake4
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/BadArgvN3-result.txt1
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/BadArgvN3-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/BadArgvN3.cmake1
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/BadArgvN4-result.txt1
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/BadArgvN4-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/BadArgvN4.cmake3
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/CornerCases.cmake54
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/CornerCasesArgvN.cmake53
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/Errors-result.txt1
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/Errors-stderr.txt44
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/Errors.cmake14
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/Initialization.cmake77
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/KeyWordsMissingValues.cmake133
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/Mix.cmake24
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake14
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/Utils.cmake21
-rw-r--r--Tests/RunCMake/cmake_parse_arguments/test_utils.cmake30
-rw-r--r--Tests/RunCMake/cmake_path/ABSOLUTE_PATH-OUTPUT_VARIABLE-invalid-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/ABSOLUTE_PATH-OUTPUT_VARIABLE-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/ABSOLUTE_PATH-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/ABSOLUTE_PATH-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/ABSOLUTE_PATH.cmake39
-rw-r--r--Tests/RunCMake/cmake_path/APPEND-OUTPUT_VARIABLE-invalid-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/APPEND-OUTPUT_VARIABLE-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/APPEND-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/APPEND.cmake77
-rw-r--r--Tests/RunCMake/cmake_path/APPEND_STRING-OUTPUT_VARIABLE-invalid-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/APPEND_STRING-OUTPUT_VARIABLE-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/APPEND_STRING-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/APPEND_STRING.cmake20
-rw-r--r--Tests/RunCMake/cmake_path/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/cmake_path/COMPARE-EQUAL-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/COMPARE-EQUAL-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/COMPARE-NOT_EQUAL-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/COMPARE-NOT_EQUAL-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/COMPARE-wrong-operator-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/COMPARE-wrong-operator-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_path/COMPARE-wrong-operator.cmake3
-rw-r--r--Tests/RunCMake/cmake_path/COMPARE.cmake22
-rw-r--r--Tests/RunCMake/cmake_path/CONVERT-TO_CMAKE_PATH_LIST-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/CONVERT-TO_CMAKE_PATH_LIST-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/CONVERT-TO_CMAKE_PATH_LIST-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/CONVERT-TO_NATIVE_PATH_LIST-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/CONVERT-TO_NATIVE_PATH_LIST-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/CONVERT-TO_NATIVE_PATH_LIST-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/CONVERT-wrong-operator-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/CONVERT-wrong-operator-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_path/CONVERT-wrong-operator.cmake2
-rw-r--r--Tests/RunCMake/cmake_path/CONVERT.cmake110
-rw-r--r--Tests/RunCMake/cmake_path/GET-EXTENSION-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-EXTENSION-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-EXTENSION-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-EXTENSION-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-FILENAME-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-FILENAME-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-FILENAME-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-FILENAME-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-PARENT_PATH-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-PARENT_PATH-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-PARENT_PATH-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-PARENT_PATH-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-RELATIVE_PART-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-RELATIVE_PART-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-RELATIVE_PART-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-RELATIVE_PART-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-ROOT_DIRECTORY-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-ROOT_DIRECTORY-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-ROOT_DIRECTORY-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-ROOT_DIRECTORY-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-ROOT_NAME-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-ROOT_NAME-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-ROOT_NAME-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-ROOT_NAME-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-ROOT_PATH-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-ROOT_PATH-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-ROOT_PATH-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-ROOT_PATH-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-STEM-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-STEM-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-STEM-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-STEM-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-wrong-operator-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/GET-wrong-operator-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_path/GET-wrong-operator.cmake3
-rw-r--r--Tests/RunCMake/cmake_path/GET.cmake248
-rw-r--r--Tests/RunCMake/cmake_path/HASH-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HASH-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HASH-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HASH-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HASH.cmake22
-rw-r--r--Tests/RunCMake/cmake_path/HAS_EXTENSION-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_EXTENSION-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_EXTENSION-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_EXTENSION-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_FILENAME-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_FILENAME-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_FILENAME-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_FILENAME-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_ITEM.cmake232
-rw-r--r--Tests/RunCMake/cmake_path/HAS_PARENT_PATH-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_PARENT_PATH-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_PARENT_PATH-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_PARENT_PATH-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_ROOT_DIRECTORY-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_ROOT_DIRECTORY-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_ROOT_DIRECTORY-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_ROOT_DIRECTORY-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_ROOT_NAME-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_ROOT_NAME-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_ROOT_NAME-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_ROOT_NAME-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_ROOT_PATH-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_ROOT_PATH-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_ROOT_PATH-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_ROOT_PATH-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_STEM-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_STEM-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_STEM-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/HAS_STEM-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/IS_ABSOLUTE-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/IS_ABSOLUTE-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/IS_ABSOLUTE-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/IS_ABSOLUTE-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/IS_ABSOLUTE.cmake48
-rw-r--r--Tests/RunCMake/cmake_path/IS_PREFIX-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/IS_PREFIX-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/IS_PREFIX-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/IS_PREFIX-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/IS_PREFIX.cmake27
-rw-r--r--Tests/RunCMake/cmake_path/IS_RELATIVE-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/IS_RELATIVE-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/IS_RELATIVE-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/IS_RELATIVE-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/IS_RELATIVE.cmake48
-rw-r--r--Tests/RunCMake/cmake_path/NATIVE_PATH-OUTPUT_VARIABLE-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/NATIVE_PATH-invalid-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/NATIVE_PATH-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/NATIVE_PATH-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/NATIVE_PATH-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/NATIVE_PATH.cmake37
-rw-r--r--Tests/RunCMake/cmake_path/NORMAL_PATH-OUTPUT_VARIABLE-invalid-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/NORMAL_PATH-OUTPUT_VARIABLE-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/NORMAL_PATH-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/NORMAL_PATH-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/NORMAL_PATH.cmake46
-rw-r--r--Tests/RunCMake/cmake_path/OUTPUT_VARIABLE-no-arg-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_path/PROXIMATE_PATH-OUTPUT_VARIABLE-invalid-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/PROXIMATE_PATH-OUTPUT_VARIABLE-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/PROXIMATE_PATH-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/PROXIMATE_PATH-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/RELATIVE_PATH-OUTPUT_VARIABLE-invalid-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/RELATIVE_PATH-OUTPUT_VARIABLE-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/RELATIVE_PATH-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/RELATIVE_PATH-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/RELATIVE_PATH.cmake76
-rw-r--r--Tests/RunCMake/cmake_path/REMOVE_EXTENSION-OUTPUT_VARIABLE-invalid-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REMOVE_EXTENSION-OUTPUT_VARIABLE-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REMOVE_EXTENSION-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REMOVE_EXTENSION-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REMOVE_EXTENSION.cmake52
-rw-r--r--Tests/RunCMake/cmake_path/REMOVE_FILENAME-OUTPUT_VARIABLE-invalid-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REMOVE_FILENAME-OUTPUT_VARIABLE-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REMOVE_FILENAME-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REMOVE_FILENAME-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REMOVE_FILENAME.cmake25
-rw-r--r--Tests/RunCMake/cmake_path/REPLACE_EXTENSION-OUTPUT_VARIABLE-invalid-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REPLACE_EXTENSION-OUTPUT_VARIABLE-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REPLACE_EXTENSION-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REPLACE_EXTENSION-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REPLACE_EXTENSION.cmake58
-rw-r--r--Tests/RunCMake/cmake_path/REPLACE_FILENAME-OUTPUT_VARIABLE-invalid-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REPLACE_FILENAME-OUTPUT_VARIABLE-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REPLACE_FILENAME-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REPLACE_FILENAME-wrong-path-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/REPLACE_FILENAME.cmake26
-rw-r--r--Tests/RunCMake/cmake_path/RunCMakeTest.cmake185
-rw-r--r--Tests/RunCMake/cmake_path/SET-missing-output-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/SET-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/cmake_path/SET.cmake43
-rw-r--r--Tests/RunCMake/cmake_path/call-cmake_path.cmake19
-rw-r--r--Tests/RunCMake/cmake_path/check_errors.cmake12
-rw-r--r--Tests/RunCMake/cmake_path/invalid-output-var-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_path/missing-output-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_path/unexpected-arg-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_path/wrong-path-stderr.txt2
-rw-r--r--Tests/RunCMake/color_warning.c7
-rw-r--r--Tests/RunCMake/configure_file/BadArg-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/BadArg-stderr.txt4
-rw-r--r--Tests/RunCMake/configure_file/BadArg.cmake1
-rw-r--r--Tests/RunCMake/configure_file/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/configure_file/DirInput-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/DirInput-stderr.txt8
-rw-r--r--Tests/RunCMake/configure_file/DirInput.cmake1
-rw-r--r--Tests/RunCMake/configure_file/DirOutput-stderr.txt1
-rw-r--r--Tests/RunCMake/configure_file/DirOutput.cmake4
-rw-r--r--Tests/RunCMake/configure_file/DirOutput.txt1
-rw-r--r--Tests/RunCMake/configure_file/NO-BOM.cmake2
-rw-r--r--Tests/RunCMake/configure_file/NO-BOM.txt.in1
-rw-r--r--Tests/RunCMake/configure_file/NewLineStyle-COPYONLY-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/NewLineStyle-COPYONLY-stderr.txt4
-rw-r--r--Tests/RunCMake/configure_file/NewLineStyle-COPYONLY.cmake3
-rw-r--r--Tests/RunCMake/configure_file/NewLineStyle-NoArg-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/NewLineStyle-NoArg-stderr.txt5
-rw-r--r--Tests/RunCMake/configure_file/NewLineStyle-NoArg.cmake3
-rw-r--r--Tests/RunCMake/configure_file/NewLineStyle-ValidArg.cmake17
-rw-r--r--Tests/RunCMake/configure_file/NewLineStyle-WrongArg-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/NewLineStyle-WrongArg-stderr.txt5
-rw-r--r--Tests/RunCMake/configure_file/NewLineStyle-WrongArg.cmake3
-rw-r--r--Tests/RunCMake/configure_file/NoSourcePermissions.cmake10
-rwxr-xr-xTests/RunCMake/configure_file/NoSourcePermissions.sh3
-rw-r--r--Tests/RunCMake/configure_file/Relative-In.txt1
-rw-r--r--Tests/RunCMake/configure_file/Relative-stderr.txt1
-rw-r--r--Tests/RunCMake/configure_file/Relative.cmake3
-rw-r--r--Tests/RunCMake/configure_file/RerunCMake-rerun-stderr.txt1
-rw-r--r--Tests/RunCMake/configure_file/RerunCMake-rerun-stdout.txt3
-rw-r--r--Tests/RunCMake/configure_file/RerunCMake-stderr.txt1
-rw-r--r--Tests/RunCMake/configure_file/RerunCMake-stdout.txt3
-rw-r--r--Tests/RunCMake/configure_file/RerunCMake.cmake4
-rw-r--r--Tests/RunCMake/configure_file/RerunCMake/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/configure_file/RunCMakeTest.cmake59
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissions.cmake34
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-stderr.txt5
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1.cmake5
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-stderr.txt5
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2.cmake5
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-stderr.txt5
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3.cmake5
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-stderr.txt4
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4.cmake4
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-stderr.txt4
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5.cmake6
-rw-r--r--Tests/RunCMake/configure_file/UTF16BE-BOM-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/UTF16BE-BOM-stderr.txt6
-rw-r--r--Tests/RunCMake/configure_file/UTF16BE-BOM.cmake2
-rw-r--r--Tests/RunCMake/configure_file/UTF16BE-BOM.txt.inbin0 -> 26 bytes-rw-r--r--Tests/RunCMake/configure_file/UTF16LE-BOM-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/UTF16LE-BOM-stderr.txt6
-rw-r--r--Tests/RunCMake/configure_file/UTF16LE-BOM.cmake2
-rw-r--r--Tests/RunCMake/configure_file/UTF16LE-BOM.txt.inbin0 -> 26 bytes-rw-r--r--Tests/RunCMake/configure_file/UTF32BE-BOM-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/UTF32BE-BOM-stderr.txt6
-rw-r--r--Tests/RunCMake/configure_file/UTF32BE-BOM.cmake2
-rw-r--r--Tests/RunCMake/configure_file/UTF32BE-BOM.txt.inbin0 -> 52 bytes-rw-r--r--Tests/RunCMake/configure_file/UTF32LE-BOM-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/UTF32LE-BOM-stderr.txt6
-rw-r--r--Tests/RunCMake/configure_file/UTF32LE-BOM.cmake2
-rw-r--r--Tests/RunCMake/configure_file/UTF32LE-BOM.txt.inbin0 -> 52 bytes-rw-r--r--Tests/RunCMake/configure_file/UTF8-BOM.cmake2
-rw-r--r--Tests/RunCMake/configure_file/UTF8-BOM.txt.in1
-rw-r--r--Tests/RunCMake/configure_file/UnknownArg-stderr.txt10
-rw-r--r--Tests/RunCMake/configure_file/UnknownArg.cmake2
-rw-r--r--Tests/RunCMake/configure_file/UseSourcePermissions.cmake40
-rw-r--r--Tests/RunCMake/configure_file/sourcefile.txt1
-rw-r--r--Tests/RunCMake/continue/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/continue/ContinueForEachInLists.cmake10
-rw-r--r--Tests/RunCMake/continue/ContinueForeach-stdout.txt4
-rw-r--r--Tests/RunCMake/continue/ContinueForeach.cmake8
-rw-r--r--Tests/RunCMake/continue/ContinueNestedForeach-stdout.txt6
-rw-r--r--Tests/RunCMake/continue/ContinueNestedForeach.cmake13
-rw-r--r--Tests/RunCMake/continue/ContinueWhile-stdout.txt6
-rw-r--r--Tests/RunCMake/continue/ContinueWhile.cmake10
-rw-r--r--Tests/RunCMake/continue/NoArgumentsToContinue-result.txt1
-rw-r--r--Tests/RunCMake/continue/NoArgumentsToContinue-stderr.txt4
-rw-r--r--Tests/RunCMake/continue/NoArgumentsToContinue.cmake3
-rw-r--r--Tests/RunCMake/continue/NoEnclosingBlock-result.txt1
-rw-r--r--Tests/RunCMake/continue/NoEnclosingBlock-stderr.txt5
-rw-r--r--Tests/RunCMake/continue/NoEnclosingBlock.cmake1
-rw-r--r--Tests/RunCMake/continue/NoEnclosingBlockInFunction-result.txt1
-rw-r--r--Tests/RunCMake/continue/NoEnclosingBlockInFunction-stderr.txt6
-rw-r--r--Tests/RunCMake/continue/NoEnclosingBlockInFunction.cmake8
-rw-r--r--Tests/RunCMake/continue/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/ctest_build/BuildChangeId-check.cmake12
-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/BuildFailure-CMP0061-OLD-result.txt1
-rw-r--r--Tests/RunCMake/ctest_build/BuildFailure-CMP0061-OLD-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_build/BuildFailure-result.txt1
-rw-r--r--Tests/RunCMake/ctest_build/BuildFailure-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_build/BuildQuiet-stdout.txt11
-rw-r--r--Tests/RunCMake/ctest_build/CMakeLists.txt.in6
-rw-r--r--Tests/RunCMake/ctest_build/IgnoreColor-stdout.txt2
-rw-r--r--Tests/RunCMake/ctest_build/RunCMakeTest.cmake59
-rw-r--r--Tests/RunCMake/ctest_build/test.cmake.in21
-rw-r--r--Tests/RunCMake/ctest_cmake_error/CMakeLists.txt.in4
-rw-r--r--Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorNonZero-stderr.txt4
-rw-r--r--Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorZero-stderr.txt4
-rw-r--r--Tests/RunCMake/ctest_cmake_error/CTestCaptureErrorZero-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_cmake_error/CoverageQuiet-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_cmake_error/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/ctest_cmake_error/test.cmake.in22
-rw-r--r--Tests/RunCMake/ctest_configure/CMakeLists.txt.in4
-rw-r--r--Tests/RunCMake/ctest_configure/ConfigureQuiet-stdout.txt8
-rw-r--r--Tests/RunCMake/ctest_configure/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/ctest_configure/test.cmake.in14
-rw-r--r--Tests/RunCMake/ctest_coverage/CMakeLists.txt.in4
-rw-r--r--Tests/RunCMake/ctest_coverage/CoverageQuiet-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_coverage/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/ctest_coverage/test.cmake.in18
-rw-r--r--Tests/RunCMake/ctest_disabled_test/CMakeLists.txt.in6
-rw-r--r--Tests/RunCMake/ctest_disabled_test/DisableAllTests-result.txt1
-rw-r--r--Tests/RunCMake/ctest_disabled_test/DisableAllTests-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_disabled_test/DisableAllTests-stdout.txt2
-rw-r--r--Tests/RunCMake/ctest_disabled_test/DisableCleanupTest-stdout.txt11
-rw-r--r--Tests/RunCMake/ctest_disabled_test/DisableFailingTest-stdout.txt9
-rw-r--r--Tests/RunCMake/ctest_disabled_test/DisableNotRunTest-result.txt1
-rw-r--r--Tests/RunCMake/ctest_disabled_test/DisableNotRunTest-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_disabled_test/DisableNotRunTest-stdout.txt17
-rw-r--r--Tests/RunCMake/ctest_disabled_test/DisableRequiredTest-stdout.txt13
-rw-r--r--Tests/RunCMake/ctest_disabled_test/DisableSetupTest-stdout.txt13
-rw-r--r--Tests/RunCMake/ctest_disabled_test/DisabledTest-result.txt1
-rw-r--r--Tests/RunCMake/ctest_disabled_test/DisabledTest-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_disabled_test/DisabledTest-stdout.txt17
-rw-r--r--Tests/RunCMake/ctest_disabled_test/RunCMakeTest.cmake89
-rw-r--r--Tests/RunCMake/ctest_disabled_test/test.cmake.in16
-rw-r--r--Tests/RunCMake/ctest_fixtures/CMakeLists.txt.in91
-rw-r--r--Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake87
-rw-r--r--Tests/RunCMake/ctest_fixtures/cyclicCleanup-result.txt1
-rw-r--r--Tests/RunCMake/ctest_fixtures/cyclicCleanup-stderr.txt3
-rw-r--r--Tests/RunCMake/ctest_fixtures/cyclicCleanup-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_fixtures/cyclicSetup-result.txt1
-rw-r--r--Tests/RunCMake/ctest_fixtures/cyclicSetup-stderr.txt3
-rw-r--r--Tests/RunCMake/ctest_fixtures/cyclicSetup-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_fixtures/exclude_any_bar-stdout.txt15
-rw-r--r--Tests/RunCMake/ctest_fixtures/exclude_any_foo-stdout.txt13
-rw-r--r--Tests/RunCMake/ctest_fixtures/exclude_any_foobar-stdout.txt9
-rw-r--r--Tests/RunCMake/ctest_fixtures/exclude_cleanup_bar-stdout.txt15
-rw-r--r--Tests/RunCMake/ctest_fixtures/exclude_cleanup_foo-stdout.txt15
-rw-r--r--Tests/RunCMake/ctest_fixtures/exclude_setup_bar-stdout.txt17
-rw-r--r--Tests/RunCMake/ctest_fixtures/exclude_setup_foo-stdout.txt15
-rw-r--r--Tests/RunCMake/ctest_fixtures/one-stdout.txt13
-rw-r--r--Tests/RunCMake/ctest_fixtures/setupFoo-stdout.txt7
-rw-r--r--Tests/RunCMake/ctest_fixtures/test.cmake.in16
-rw-r--r--Tests/RunCMake/ctest_fixtures/three-stdout.txt17
-rw-r--r--Tests/RunCMake/ctest_fixtures/two-stdout.txt11
-rw-r--r--Tests/RunCMake/ctest_fixtures/unused-stdout.txt9
-rw-r--r--Tests/RunCMake/ctest_fixtures/wontRun-stdout.txt14
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/CMakeLists.txt.in5
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/CTestConfig.cmake.in1
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/CTestConfigCTestScript-check.cmake36
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/CTestConfigCTestScript-stdout.txt10
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariable-check.cmake36
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariable-stdout.txt10
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-check.cmake34
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-result.txt1
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-stdout.txt9
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCMakeLists-result.txt1
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCMakeLists-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCMakeLists-stdout.txt6
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfig-result.txt1
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfig-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfig-stdout.txt9
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfigNoSummary-result.txt1
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfigNoSummary-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCTestConfigNoSummary-stdout.txt6
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCommandLine-result.txt1
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCommandLine-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/ModuleVariableCommandLine-stdout.txt6
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/MyExperimentalFeature/CMakeLists.txt33
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/MyExperimentalFeature/experimental.c16
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/MyProductionCode/CMakeLists.txt12
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/MyProductionCode/production.c16
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/MyThirdPartyDependency/CMakeLists.txt7
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/MyThirdPartyDependency/src/CMakeLists.txt10
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/MyThirdPartyDependency/src/thirdparty.c14
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/RunCMakeTest.cmake185
-rw-r--r--Tests/RunCMake/ctest_labels_for_subprojects/test.cmake.in21
-rw-r--r--Tests/RunCMake/ctest_memcheck/CMakeLists.txt.in7
-rw-r--r--Tests/RunCMake/ctest_memcheck/CTestConfig.cmake.in6
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyAddressLeakSanitizer-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyAddressLeakSanitizer-stdout.txt3
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyAddressSanitizer-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyAddressSanitizer-stdout.txt2
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyBC-result.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyBC-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyBC-stdout.txt3
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyBCNoLogFile-result.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyBCNoLogFile-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyBCNoLogFile-stdout.txt3
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyCudaSanitizer-result.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyCudaSanitizer-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyCudaSanitizer-stdout.txt13
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyLeakSanitizer-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyLeakSanitizer-stdout.txt3
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyLeakSanitizerPrintDefects-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyLeakSanitizerPrintDefects-stdout.txt3
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyMemorySanitizer-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyMemorySanitizer-stdout.txt2
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyPurify-result.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyPurify-stdout.txt8
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyPurifyNoLogFile-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyPurifyNoLogFile-stdout.txt3
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyQuiet-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyThreadSanitizer-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyThreadSanitizer-stdout.txt13
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyUndefinedBehaviorSanitizer-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyUndefinedBehaviorSanitizer-stdout.txt2
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrind-result.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrind-stdout.txt8
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindCustomOptions-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindCustomOptions-stdout.txt8
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindFailPost-result.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindFailPost-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindFailPost-stdout.txt8
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindFailPre-result.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindFailPre-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindFailPre-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindIgnoreMemcheck-result.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindIgnoreMemcheck-stdout.txt9
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindInvalidSupFile-result.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindInvalidSupFile-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindInvalidSupFile-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindNoDefects-result.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindNoDefects-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindNoDefects-stdout.txt8
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindNoLogFile-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindNoLogFile-stdout.txt3
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindPrePost-result.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindPrePost-stdout.txt8
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindTwoTargets-result.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/DummyValgrindTwoTargets-stdout.txt8
-rw-r--r--Tests/RunCMake/ctest_memcheck/NotExist-result.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/NotExist-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/NotExist-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake189
-rw-r--r--Tests/RunCMake/ctest_memcheck/Unknown-result.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/Unknown-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/Unknown-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_memcheck/test.cmake.in26
-rw-r--r--Tests/RunCMake/ctest_memcheck/testAddressLeakSanitizer.cmake47
-rw-r--r--Tests/RunCMake/ctest_memcheck/testAddressSanitizer.cmake58
-rw-r--r--Tests/RunCMake/ctest_memcheck/testCudaSanitizer.cmake279
-rw-r--r--Tests/RunCMake/ctest_memcheck/testLeakSanitizer.cmake47
-rw-r--r--Tests/RunCMake/ctest_memcheck/testMemorySanitizer.cmake27
-rw-r--r--Tests/RunCMake/ctest_memcheck/testThreadSanitizer.cmake47
-rw-r--r--Tests/RunCMake/ctest_memcheck/testUndefinedBehaviorSanitizer.cmake21
-rw-r--r--Tests/RunCMake/ctest_skipped_test/CMakeLists.txt.in12
-rw-r--r--Tests/RunCMake/ctest_skipped_test/RunCMakeTest.cmake51
-rw-r--r--Tests/RunCMake/ctest_skipped_test/SkipCleanupTest-stdout.txt11
-rw-r--r--Tests/RunCMake/ctest_skipped_test/SkipRequiredTest-stdout.txt13
-rw-r--r--Tests/RunCMake/ctest_skipped_test/SkipSetupTest-stdout.txt13
-rw-r--r--Tests/RunCMake/ctest_skipped_test/SkipTest-stdout.txt11
-rwxr-xr-xTests/RunCMake/ctest_skipped_test/skip.bat1
-rwxr-xr-xTests/RunCMake/ctest_skipped_test/skip.sh3
-rw-r--r--Tests/RunCMake/ctest_skipped_test/test.cmake.in16
-rw-r--r--Tests/RunCMake/ctest_start/AppendDifferentGroup-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_start/AppendDifferentGroup-stdout.txt8
-rw-r--r--Tests/RunCMake/ctest_start/AppendDifferentModel-check.cmake1
-rw-r--r--Tests/RunCMake/ctest_start/AppendDifferentModel-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_start/AppendDifferentModel-stdout.txt7
-rw-r--r--Tests/RunCMake/ctest_start/AppendDifferentTrack-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_start/AppendDifferentTrack-stdout.txt8
-rw-r--r--Tests/RunCMake/ctest_start/AppendNoMatchingTrack-stdout.txt7
-rw-r--r--Tests/RunCMake/ctest_start/AppendNoModel-check.cmake1
-rw-r--r--Tests/RunCMake/ctest_start/AppendNoModel-stdout.txt7
-rw-r--r--Tests/RunCMake/ctest_start/AppendOldContinuous-stdout.txt7
-rw-r--r--Tests/RunCMake/ctest_start/AppendOldNoModel-result.txt1
-rw-r--r--Tests/RunCMake/ctest_start/AppendOldNoModel-stderr.txt3
-rw-r--r--Tests/RunCMake/ctest_start/AppendOldNoModel-stdout.txt5
-rw-r--r--Tests/RunCMake/ctest_start/AppendSameModel-check.cmake1
-rw-r--r--Tests/RunCMake/ctest_start/AppendSameModel-stdout.txt7
-rw-r--r--Tests/RunCMake/ctest_start/CMakeLists.txt.in4
-rw-r--r--Tests/RunCMake/ctest_start/ConfigInBuild-stdout.txt6
-rw-r--r--Tests/RunCMake/ctest_start/ConfigInSource-stdout.txt6
-rw-r--r--Tests/RunCMake/ctest_start/FunctionScope-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_start/MissingGroupArg-result.txt1
-rw-r--r--Tests/RunCMake/ctest_start/MissingGroupArg-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_start/MissingGroupArgAppend-result.txt1
-rw-r--r--Tests/RunCMake/ctest_start/MissingGroupArgAppend-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_start/MissingGroupArgQuiet-result.txt1
-rw-r--r--Tests/RunCMake/ctest_start/MissingGroupArgQuiet-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_start/MissingTrackArg-result.txt1
-rw-r--r--Tests/RunCMake/ctest_start/MissingTrackArg-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_start/MissingTrackArgAppend-result.txt1
-rw-r--r--Tests/RunCMake/ctest_start/MissingTrackArgAppend-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_start/MissingTrackArgQuiet-result.txt1
-rw-r--r--Tests/RunCMake/ctest_start/MissingTrackArgQuiet-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_start/NoAppendDifferentGroup-stdout.txt7
-rw-r--r--Tests/RunCMake/ctest_start/NoAppendDifferentTrack-stdout.txt7
-rw-r--r--Tests/RunCMake/ctest_start/NoModel-result.txt1
-rw-r--r--Tests/RunCMake/ctest_start/NoModel-stderr.txt3
-rw-r--r--Tests/RunCMake/ctest_start/NoStartTimeNightly-result.txt1
-rw-r--r--Tests/RunCMake/ctest_start/NoStartTimeNightly-stderr.txt4
-rw-r--r--Tests/RunCMake/ctest_start/RunCMakeTest.cmake61
-rw-r--r--Tests/RunCMake/ctest_start/StartQuiet-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_start/TooManyArgs-result.txt1
-rw-r--r--Tests/RunCMake/ctest_start/TooManyArgs-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_start/WriteModelToTagContinuous-check.cmake1
-rw-r--r--Tests/RunCMake/ctest_start/WriteModelToTagExperimental-check.cmake1
-rw-r--r--Tests/RunCMake/ctest_start/WriteModelToTagNightly-check.cmake1
-rw-r--r--Tests/RunCMake/ctest_start/WriteModelToTagNoMatchingGroup-check.cmake1
-rw-r--r--Tests/RunCMake/ctest_start/WriteModelToTagNoMatchingTrack-check.cmake1
-rw-r--r--Tests/RunCMake/ctest_start/test.cmake.in35
-rw-r--r--Tests/RunCMake/ctest_submit/BadArg-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/BadArg-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_submit/BadFILES-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/BadFILES-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_submit/BadPARTS-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/BadPARTS-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_submit/CDashSubmitHeaders-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashSubmitHeaders-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashSubmitHeaders-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashSubmitQuiet-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashSubmitQuiet-stderr.txt3
-rw-r--r--Tests/RunCMake/ctest_submit/CDashSubmitQuiet-stdout.txt3
-rw-r--r--Tests/RunCMake/ctest_submit/CDashSubmitVerbose-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashSubmitVerbose-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashSubmitVerbose-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadFILES-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadFILES-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadFTP-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadFTP-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadHeaders-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadHeaders-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadHeaders-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadMissingFile-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadMissingFile-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadNone-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadNone-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadPARTS-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadPARTS-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadRetry-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadRetry-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/CDashUploadRetry-stdout.txt4
-rw-r--r--Tests/RunCMake/ctest_submit/CMakeLists.txt.in4
-rw-r--r--Tests/RunCMake/ctest_submit/CTestConfig.cmake.in9
-rw-r--r--Tests/RunCMake/ctest_submit/FILESNoBuildId-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/FILESNoBuildId-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/FILESNoBuildId-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/FailDrop-http-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/FailDrop-http-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_submit/FailDrop-http-stdout.txt2
-rw-r--r--Tests/RunCMake/ctest_submit/FailDrop-https-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/FailDrop-https-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_submit/FailDrop-https-stdout.txt2
-rw-r--r--Tests/RunCMake/ctest_submit/PARTSCDashUpload-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/PARTSCDashUpload-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_submit/PARTSCDashUploadType-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/PARTSCDashUploadType-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_submit/PARTSDone-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/PARTSDone-stderr.txt3
-rw-r--r--Tests/RunCMake/ctest_submit/RepeatRETURN_VALUE-result.txt1
-rw-r--r--Tests/RunCMake/ctest_submit/RepeatRETURN_VALUE-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_submit/RunCMakeTest.cmake53
-rw-r--r--Tests/RunCMake/ctest_submit/test.cmake.in17
-rw-r--r--Tests/RunCMake/ctest_test/CMakeLists.txt.in5
-rw-r--r--Tests/RunCMake/ctest_test/CTestTestLoadInvalid-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_test/CTestTestLoadInvalid-stdout.txt14
-rw-r--r--Tests/RunCMake/ctest_test/CTestTestLoadPass-stdout.txt14
-rw-r--r--Tests/RunCMake/ctest_test/CTestTestLoadWait-stdout.txt15
-rw-r--r--Tests/RunCMake/ctest_test/RunCMakeTest.cmake148
-rw-r--r--Tests/RunCMake/ctest_test/TestChangeId-check.cmake12
-rw-r--r--Tests/RunCMake/ctest_test/TestEnvironment-check.cmake10
-rw-r--r--Tests/RunCMake/ctest_test/TestLoadInvalid-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_test/TestLoadInvalid-stdout.txt14
-rw-r--r--Tests/RunCMake/ctest_test/TestLoadOrder-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_test/TestLoadOrder-stdout.txt14
-rw-r--r--Tests/RunCMake/ctest_test/TestLoadPass-stdout.txt14
-rw-r--r--Tests/RunCMake/ctest_test/TestLoadWait-stdout.txt15
-rw-r--r--Tests/RunCMake/ctest_test/TestOutputSize-check.cmake17
-rw-r--r--Tests/RunCMake/ctest_test/TestQuiet-stdout.txt2
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatAfterTimeout-stdout.txt10
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatAfterTimeout.cmake10
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatBad1-result.txt1
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatBad1-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatBad2-result.txt1
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatBad2-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatNotRun-result.txt1
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatNotRun-stderr.txt1
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatNotRun-stdout.txt5
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatNotRun.cmake10
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatUntilFail-stdout.txt13
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatUntilFail.cmake9
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatUntilPass-stdout.txt10
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatUntilPass.cmake9
-rw-r--r--Tests/RunCMake/ctest_test/stop-on-failure-stdout.txt13
-rw-r--r--Tests/RunCMake/ctest_test/test.cmake.in18
-rw-r--r--Tests/RunCMake/ctest_update/CMakeLists.txt.in4
-rw-r--r--Tests/RunCMake/ctest_update/RunCMakeTest.cmake25
-rw-r--r--Tests/RunCMake/ctest_update/UpdateActualVersion-check.cmake12
-rw-r--r--Tests/RunCMake/ctest_update/UpdateChangeId-check.cmake12
-rw-r--r--Tests/RunCMake/ctest_update/test.cmake.in18
-rw-r--r--Tests/RunCMake/ctest_upload/CMakeLists.txt.in4
-rw-r--r--Tests/RunCMake/ctest_upload/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/ctest_upload/UploadQuiet-stdout.txt1
-rw-r--r--Tests/RunCMake/ctest_upload/test.cmake.in14
-rw-r--r--Tests/RunCMake/execute_process/AnyCommandAbnormalExit-result.txt1
-rw-r--r--Tests/RunCMake/execute_process/AnyCommandAbnormalExit-stderr.txt4
-rw-r--r--Tests/RunCMake/execute_process/AnyCommandAbnormalExit.cmake5
-rw-r--r--Tests/RunCMake/execute_process/AnyCommandError-result.txt1
-rw-r--r--Tests/RunCMake/execute_process/AnyCommandError-stderr.txt5
-rw-r--r--Tests/RunCMake/execute_process/AnyCommandError.cmake6
-rw-r--r--Tests/RunCMake/execute_process/AnyCommandGood.cmake4
-rw-r--r--Tests/RunCMake/execute_process/AnyCommandTimeout-result.txt1
-rw-r--r--Tests/RunCMake/execute_process/AnyCommandTimeout-stderr.txt2
-rw-r--r--Tests/RunCMake/execute_process/AnyCommandTimeout.cmake15
-rw-r--r--Tests/RunCMake/execute_process/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/execute_process/CommandError-result.txt1
-rw-r--r--Tests/RunCMake/execute_process/CommandError-stderr.txt2
-rw-r--r--Tests/RunCMake/execute_process/CommandError.cmake3
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand-result.txt1
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand-stderr.txt5
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand-stdout.txt12
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand.cmake41
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand2-result.txt1
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand2-stderr.txt5
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand2-stdout.txt12
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand3-result.txt1
-rw-r--r--Tests/RunCMake/execute_process/EchoCommand3-stderr.txt2
-rw-r--r--Tests/RunCMake/execute_process/EchoVariable-stderr.txt3
-rw-r--r--Tests/RunCMake/execute_process/EchoVariable-stdout.txt1
-rw-r--r--Tests/RunCMake/execute_process/EchoVariable.cmake23
-rw-r--r--Tests/RunCMake/execute_process/EchoVariableOutput.cmake2
-rw-r--r--Tests/RunCMake/execute_process/Encoding.cmake6
-rw-r--r--Tests/RunCMake/execute_process/EncodingMissing-result.txt1
-rw-r--r--Tests/RunCMake/execute_process/EncodingMissing-stderr.txt4
-rw-r--r--Tests/RunCMake/execute_process/EncodingMissing.cmake1
-rw-r--r--Tests/RunCMake/execute_process/EncodingUTF-8-stderr.txt1
-rw-r--r--Tests/RunCMake/execute_process/EncodingUTF8-stderr.txt1
-rw-r--r--Tests/RunCMake/execute_process/ExitValues-stdout.txt14
-rw-r--r--Tests/RunCMake/execute_process/ExitValues.cmake120
-rw-r--r--Tests/RunCMake/execute_process/LastCommandAbnormalExit-1.cmake13
-rw-r--r--Tests/RunCMake/execute_process/LastCommandAbnormalExit-2-result.txt1
-rw-r--r--Tests/RunCMake/execute_process/LastCommandAbnormalExit-2-stderr.txt2
-rw-r--r--Tests/RunCMake/execute_process/LastCommandAbnormalExit-2.cmake13
-rw-r--r--Tests/RunCMake/execute_process/LastCommandError-result.txt1
-rw-r--r--Tests/RunCMake/execute_process/LastCommandError-stderr.txt2
-rw-r--r--Tests/RunCMake/execute_process/LastCommandError.cmake19
-rw-r--r--Tests/RunCMake/execute_process/LastCommandGood.cmake15
-rw-r--r--Tests/RunCMake/execute_process/LastCommandTimeout-result.txt1
-rw-r--r--Tests/RunCMake/execute_process/LastCommandTimeout-stderr.txt2
-rw-r--r--Tests/RunCMake/execute_process/LastCommandTimeout.cmake15
-rw-r--r--Tests/RunCMake/execute_process/MergeOutput-stdout.txt10
-rw-r--r--Tests/RunCMake/execute_process/MergeOutput.cmake4
-rw-r--r--Tests/RunCMake/execute_process/MergeOutputFile-stderr.txt10
-rw-r--r--Tests/RunCMake/execute_process/MergeOutputFile.cmake7
-rw-r--r--Tests/RunCMake/execute_process/MergeOutputVars-stderr.txt10
-rw-r--r--Tests/RunCMake/execute_process/MergeOutputVars.cmake6
-rw-r--r--Tests/RunCMake/execute_process/RunCMakeTest.cmake42
-rw-r--r--Tests/RunCMake/exit_code.c31
-rw-r--r--Tests/RunCMake/export/AppendExport-result.txt1
-rw-r--r--Tests/RunCMake/export/AppendExport-stderr.txt4
-rw-r--r--Tests/RunCMake/export/AppendExport.cmake9
-rw-r--r--Tests/RunCMake/export/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/export/CustomTarget-result.txt1
-rw-r--r--Tests/RunCMake/export/CustomTarget-stderr.txt4
-rw-r--r--Tests/RunCMake/export/CustomTarget.cmake2
-rw-r--r--Tests/RunCMake/export/DependOnDoubleExport-result.txt1
-rw-r--r--Tests/RunCMake/export/DependOnDoubleExport-stderr.txt12
-rw-r--r--Tests/RunCMake/export/DependOnDoubleExport.cmake7
-rw-r--r--Tests/RunCMake/export/DependOnNotExport-result.txt1
-rw-r--r--Tests/RunCMake/export/DependOnNotExport-stderr.txt6
-rw-r--r--Tests/RunCMake/export/DependOnNotExport.cmake4
-rw-r--r--Tests/RunCMake/export/Empty.cmake1
-rw-r--r--Tests/RunCMake/export/ExportPropertiesUndefined.cmake11
-rw-r--r--Tests/RunCMake/export/ForbiddenToExportImportedProperties-result.txt1
-rw-r--r--Tests/RunCMake/export/ForbiddenToExportImportedProperties-stderr.txt3
-rw-r--r--Tests/RunCMake/export/ForbiddenToExportImportedProperties.cmake12
-rw-r--r--Tests/RunCMake/export/ForbiddenToExportInterfaceProperties-result.txt1
-rw-r--r--Tests/RunCMake/export/ForbiddenToExportInterfaceProperties-stderr.txt3
-rw-r--r--Tests/RunCMake/export/ForbiddenToExportInterfaceProperties.cmake12
-rw-r--r--Tests/RunCMake/export/ForbiddenToExportPropertyWithGenExp-result.txt1
-rw-r--r--Tests/RunCMake/export/ForbiddenToExportPropertyWithGenExp-stderr.txt3
-rw-r--r--Tests/RunCMake/export/ForbiddenToExportPropertyWithGenExp.cmake12
-rw-r--r--Tests/RunCMake/export/NamelinkOnlyExport.cmake9
-rw-r--r--Tests/RunCMake/export/NoExportSet-result.txt1
-rw-r--r--Tests/RunCMake/export/NoExportSet-stderr.txt4
-rw-r--r--Tests/RunCMake/export/NoExportSet.cmake2
-rw-r--r--Tests/RunCMake/export/OldIface-result.txt1
-rw-r--r--Tests/RunCMake/export/OldIface-stderr.txt4
-rw-r--r--Tests/RunCMake/export/OldIface.cmake11
-rw-r--r--Tests/RunCMake/export/Repeat-CMP0103-NEW-result.txt1
-rw-r--r--Tests/RunCMake/export/Repeat-CMP0103-NEW-stderr.txt17
-rw-r--r--Tests/RunCMake/export/Repeat-CMP0103-NEW.cmake2
-rw-r--r--Tests/RunCMake/export/Repeat-CMP0103-OLD.cmake2
-rw-r--r--Tests/RunCMake/export/Repeat-CMP0103-WARN-stderr.txt26
-rw-r--r--Tests/RunCMake/export/Repeat-CMP0103-WARN.cmake1
-rw-r--r--Tests/RunCMake/export/Repeat.cmake5
-rw-r--r--Tests/RunCMake/export/Repeat/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/export/RunCMakeTest.cmake20
-rw-r--r--Tests/RunCMake/export/SeparateNamelinkExport.cmake16
-rw-r--r--Tests/RunCMake/export/TargetNotFound-result.txt1
-rw-r--r--Tests/RunCMake/export/TargetNotFound-stderr.txt4
-rw-r--r--Tests/RunCMake/export/TargetNotFound.cmake1
-rw-r--r--Tests/RunCMake/export/UnknownExport-result.txt1
-rw-r--r--Tests/RunCMake/export/UnknownExport-stderr.txt4
-rw-r--r--Tests/RunCMake/export/UnknownExport.cmake2
-rw-r--r--Tests/RunCMake/export/empty.cpp7
-rw-r--r--Tests/RunCMake/fake_build_command.c6
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-all-perms-result.txt1
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-all-perms-stderr.txt5
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-all-perms.cmake6
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-invalid-path-result.txt1
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-invalid-path-stderr.txt6
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-invalid-path.cmake4
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-invalid-perms-result.txt1
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-invalid-perms-stderr.txt4
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-invalid-perms.cmake5
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-no-keyword-result.txt1
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-no-keyword-stderr.txt4
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-no-keyword.cmake5
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-no-perms-result.txt1
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-no-perms-stderr.txt4
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-no-perms.cmake5
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-ok.cmake5
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-override.cmake6
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-write-only-result.txt1
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-write-only-stderr.txt6
-rw-r--r--Tests/RunCMake/file-CHMOD/CHMOD-write-only.cmake6
-rw-r--r--Tests/RunCMake/file-CHMOD/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/file-CHMOD/RunCMakeTest.cmake19
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake55
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs1-result.txt1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs1-stderr.txt18
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs1.cmake2
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs2-result.txt1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs2-stderr.txt23
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs2.cmake15
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-all-check.cmake44
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-all-stderr.txt119
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-conflict-all-result.txt1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-conflict-all-stderr.txt7
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-conflict.cmake54
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-notfile-all-result.txt1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-notfile-all-stderr.txt5
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-notfile.cmake30
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-unresolved-all-result.txt1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-unresolved-all-stderr.txt2
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-unresolved.cmake18
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux.cmake169
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/topexe.c9
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/toplib.c8
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-all-check.cmake181
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-conflict-all-result.txt1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-conflict-all-stderr.txt7
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-conflict.cmake55
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-notfile-all-result.txt1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-notfile-all-stderr.txt5
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-notfile.cmake30
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-unresolved-all-result.txt1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-unresolved-all-stderr.txt2
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-unresolved.cmake18
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos.cmake227
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos/topexe.c7
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos/toplib.c6
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/project-stderr.txt13
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/project.cmake1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/unsupported-result.txt1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/unsupported-stderr.txt5
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/unsupported.cmake2
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/variable-propagation-all-result.txt1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/variable-propagation-all-stderr.txt6
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/variable-propagation-dev-result.txt1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/variable-propagation-dev-stderr.txt6
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/variable-propagation.cmake17
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-all-check.cmake38
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-conflict-all-result.txt1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-conflict-all-stderr.txt7
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-conflict.cmake47
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-notfile-all-result.txt1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-notfile-all-stderr.txt5
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-notfile.cmake28
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-unresolved-all-result.txt1
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-unresolved-all-stderr.txt2
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-unresolved.cmake18
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows.cmake114
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows/topexe.c7
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows/toplib.c6
-rw-r--r--Tests/RunCMake/file-RPATH/Common.cmake64
-rw-r--r--Tests/RunCMake/file-RPATH/ELF.cmake9
-rwxr-xr-xTests/RunCMake/file-RPATH/ELF/elf32lsb.binbin0 -> 2824 bytes-rwxr-xr-xTests/RunCMake/file-RPATH/ELF/elf32msb.binbin0 -> 17984 bytes-rwxr-xr-xTests/RunCMake/file-RPATH/ELF/elf64lsb.binbin0 -> 4320 bytes-rwxr-xr-xTests/RunCMake/file-RPATH/ELF/elf64msb.binbin0 -> 18704 bytes-rw-r--r--Tests/RunCMake/file-RPATH/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/file-RPATH/XCOFF.cmake7
-rw-r--r--Tests/RunCMake/file-RPATH/XCOFF/xcoff32.binbin0 -> 1706 bytes-rw-r--r--Tests/RunCMake/file-RPATH/XCOFF/xcoff64.binbin0 -> 2291 bytes-rw-r--r--Tests/RunCMake/file/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/file/COPY_FILE-arg-missing-result.txt1
-rw-r--r--Tests/RunCMake/file/COPY_FILE-arg-missing-stderr.txt3
-rw-r--r--Tests/RunCMake/file/COPY_FILE-arg-missing.cmake1
-rw-r--r--Tests/RunCMake/file/COPY_FILE-arg-unknown-result.txt1
-rw-r--r--Tests/RunCMake/file/COPY_FILE-arg-unknown-stderr.txt5
-rw-r--r--Tests/RunCMake/file/COPY_FILE-arg-unknown.cmake1
-rw-r--r--Tests/RunCMake/file/COPY_FILE-dir-to-file-capture-stdout.txt1
-rw-r--r--Tests/RunCMake/file/COPY_FILE-dir-to-file-capture.cmake8
-rw-r--r--Tests/RunCMake/file/COPY_FILE-dir-to-file-fail-result.txt1
-rw-r--r--Tests/RunCMake/file/COPY_FILE-dir-to-file-fail-stderr.txt6
-rw-r--r--Tests/RunCMake/file/COPY_FILE-dir-to-file-fail.cmake4
-rw-r--r--Tests/RunCMake/file/COPY_FILE-dirlink-to-file-capture-stdout.txt1
-rw-r--r--Tests/RunCMake/file/COPY_FILE-dirlink-to-file-capture.cmake8
-rw-r--r--Tests/RunCMake/file/COPY_FILE-dirlink-to-file-fail-result.txt1
-rw-r--r--Tests/RunCMake/file/COPY_FILE-dirlink-to-file-fail-stderr.txt6
-rw-r--r--Tests/RunCMake/file/COPY_FILE-dirlink-to-file-fail.cmake4
-rw-r--r--Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-capture.cmake9
-rw-r--r--Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-fail-result.txt1
-rw-r--r--Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-fail-stderr.txt6
-rw-r--r--Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-fail.cmake5
-rw-r--r--Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-no-overwrite.cmake12
-rw-r--r--Tests/RunCMake/file/COPY_FILE-file-replace.cmake9
-rw-r--r--Tests/RunCMake/file/COPY_FILE-file-to-dir-capture-stdout.txt1
-rw-r--r--Tests/RunCMake/file/COPY_FILE-file-to-dir-capture.cmake9
-rw-r--r--Tests/RunCMake/file/COPY_FILE-file-to-dir-fail-result.txt1
-rw-r--r--Tests/RunCMake/file/COPY_FILE-file-to-dir-fail-stderr.txt6
-rw-r--r--Tests/RunCMake/file/COPY_FILE-file-to-dir-fail.cmake5
-rw-r--r--Tests/RunCMake/file/COPY_FILE-file-to-file.cmake10
-rw-r--r--Tests/RunCMake/file/COPY_FILE-link-to-file.cmake10
-rw-r--r--Tests/RunCMake/file/CREATE_LINK-COPY_ON_ERROR.cmake11
-rw-r--r--Tests/RunCMake/file/CREATE_LINK-SYMBOLIC-noexist.cmake4
-rw-r--r--Tests/RunCMake/file/CREATE_LINK-SYMBOLIC.cmake4
-rw-r--r--Tests/RunCMake/file/CREATE_LINK-noarg-result.txt1
-rw-r--r--Tests/RunCMake/file/CREATE_LINK-noarg-stderr.txt4
-rw-r--r--Tests/RunCMake/file/CREATE_LINK-noarg.cmake1
-rw-r--r--Tests/RunCMake/file/CREATE_LINK-noexist-stderr.txt1
-rw-r--r--Tests/RunCMake/file/CREATE_LINK-noexist.cmake4
-rw-r--r--Tests/RunCMake/file/CREATE_LINK.cmake11
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-hash-mismatch-result.txt1
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-hash-mismatch-stderr.txt12
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-hash-mismatch.cmake10
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-hash-mismatch.txt0
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-result.txt1
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-stderr.txt4
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-httpheader-not-set.cmake1
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-netrc-bad-result.txt1
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-netrc-bad-stderr.txt19
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-netrc-bad.cmake15
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-netrc-bad.txt0
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-no-save-hash-result.txt1
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-no-save-hash-stderr.txt4
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-no-save-hash.cmake8
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-no-save-hash.txt0
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-pass-not-set-result.txt1
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-pass-not-set-stderr.txt4
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-pass-not-set.cmake1
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set-result.txt1
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set-stderr.txt4
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set.cmake1
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set-result.txt1
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set-stderr.txt4
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set.cmake1
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-unused-argument-result.txt0
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-unused-argument-stderr.txt5
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-unused-argument.cmake8
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-unused-argument.txt0
-rw-r--r--Tests/RunCMake/file/FileOpenFailRead-result.txt1
-rw-r--r--Tests/RunCMake/file/FileOpenFailRead-stderr.txt6
-rw-r--r--Tests/RunCMake/file/FileOpenFailRead.cmake1
-rw-r--r--Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake-build-stdout.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake-rebuild-stdout.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake-stdout.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake.cmake10
-rw-r--r--Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-RerunCMake-build-stdout.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-RerunCMake-rebuild_first-stdout.txt2
-rw-r--r--Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-RerunCMake-rebuild_second-stdout.txt2
-rw-r--r--Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-RerunCMake-stdout.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-RerunCMake.cmake16
-rw-r--r--Tests/RunCMake/file/GLOB-error-CONFIGURE_DEPENDS-SCRIPT_MODE-result.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-error-CONFIGURE_DEPENDS-SCRIPT_MODE-stderr.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-error-CONFIGURE_DEPENDS-SCRIPT_MODE.cmake1
-rw-r--r--Tests/RunCMake/file/GLOB-error-CONFIGURE_DEPENDS-modified-result.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-error-CONFIGURE_DEPENDS-modified-stderr.txt7
-rw-r--r--Tests/RunCMake/file/GLOB-error-CONFIGURE_DEPENDS-modified.cmake21
-rw-r--r--Tests/RunCMake/file/GLOB-error-LIST_DIRECTORIES-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-error-LIST_DIRECTORIES-no-arg-stderr.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-error-LIST_DIRECTORIES-no-arg.cmake1
-rw-r--r--Tests/RunCMake/file/GLOB-error-LIST_DIRECTORIES-not-boolean-result.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-error-LIST_DIRECTORIES-not-boolean-stderr.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-error-LIST_DIRECTORIES-not-boolean.cmake1
-rw-r--r--Tests/RunCMake/file/GLOB-error-RELATIVE-no-arg-result.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-error-RELATIVE-no-arg-stderr.txt4
-rw-r--r--Tests/RunCMake/file/GLOB-error-RELATIVE-no-arg.cmake1
-rw-r--r--Tests/RunCMake/file/GLOB-noexp-CONFIGURE_DEPENDS-result.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-noexp-CONFIGURE_DEPENDS-stderr.txt4
-rw-r--r--Tests/RunCMake/file/GLOB-noexp-CONFIGURE_DEPENDS.cmake1
-rw-r--r--Tests/RunCMake/file/GLOB-noexp-FOLLOW_SYMLINKS.cmake1
-rw-r--r--Tests/RunCMake/file/GLOB-noexp-LIST_DIRECTORIES.cmake1
-rw-r--r--Tests/RunCMake/file/GLOB-noexp-RELATIVE-result.txt1
-rw-r--r--Tests/RunCMake/file/GLOB-noexp-RELATIVE-stderr.txt4
-rw-r--r--Tests/RunCMake/file/GLOB-noexp-RELATIVE.cmake1
-rw-r--r--Tests/RunCMake/file/GLOB-sort-dedup-stderr.txt2
-rw-r--r--Tests/RunCMake/file/GLOB-sort-dedup.cmake21
-rw-r--r--Tests/RunCMake/file/GLOB-stderr.txt6
-rw-r--r--Tests/RunCMake/file/GLOB-warn-CONFIGURE_DEPENDS-late-stderr.txt6
-rw-r--r--Tests/RunCMake/file/GLOB-warn-CONFIGURE_DEPENDS-late.cmake11
-rw-r--r--Tests/RunCMake/file/GLOB.cmake25
-rw-r--r--Tests/RunCMake/file/GLOB_RECURSE-cyclic-recursion-stderr.txt15
-rw-r--r--Tests/RunCMake/file/GLOB_RECURSE-cyclic-recursion.cmake20
-rw-r--r--Tests/RunCMake/file/GLOB_RECURSE-noexp-FOLLOW_SYMLINKS-result.txt1
-rw-r--r--Tests/RunCMake/file/GLOB_RECURSE-noexp-FOLLOW_SYMLINKS-stderr.txt4
-rw-r--r--Tests/RunCMake/file/GLOB_RECURSE-noexp-FOLLOW_SYMLINKS.cmake1
-rw-r--r--Tests/RunCMake/file/GLOB_RECURSE-stderr.txt6
-rw-r--r--Tests/RunCMake/file/GLOB_RECURSE-warn-CONFIGURE_DEPENDS-ninja-version-stderr.txt13
-rw-r--r--Tests/RunCMake/file/GLOB_RECURSE-warn-CONFIGURE_DEPENDS-ninja-version.cmake6
-rw-r--r--Tests/RunCMake/file/GLOB_RECURSE.cmake25
-rw-r--r--Tests/RunCMake/file/INSTALL-DIRECTORY-stdout.txt8
-rw-r--r--Tests/RunCMake/file/INSTALL-DIRECTORY.cmake10
-rw-r--r--Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad-result.txt1
-rw-r--r--Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad-stderr.txt15
-rw-r--r--Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad.cmake5
-rw-r--r--Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-stdout.txt8
-rw-r--r--Tests/RunCMake/file/INSTALL-FILES_FROM_DIR.cmake7
-rw-r--r--Tests/RunCMake/file/INSTALL-FOLLOW_SYMLINK_CHAIN.cmake168
-rw-r--r--Tests/RunCMake/file/INSTALL-MESSAGE-bad-result.txt1
-rw-r--r--Tests/RunCMake/file/INSTALL-MESSAGE-bad-stderr.txt32
-rw-r--r--Tests/RunCMake/file/INSTALL-MESSAGE-bad.cmake6
-rw-r--r--Tests/RunCMake/file/INSTALL-SYMLINK-stdout.txt3
-rw-r--r--Tests/RunCMake/file/INSTALL-SYMLINK.cmake13
-rw-r--r--Tests/RunCMake/file/LOCK-error-file-create-fail-result.txt1
-rw-r--r--Tests/RunCMake/file/LOCK-error-file-create-fail-stderr.txt8
-rw-r--r--Tests/RunCMake/file/LOCK-error-file-create-fail.cmake3
-rw-r--r--Tests/RunCMake/file/LOCK-error-guard-incorrect-result.txt1
-rw-r--r--Tests/RunCMake/file/LOCK-error-guard-incorrect-stderr.txt6
-rw-r--r--Tests/RunCMake/file/LOCK-error-guard-incorrect.cmake1
-rw-r--r--Tests/RunCMake/file/LOCK-error-incorrect-timeout-result.txt1
-rw-r--r--Tests/RunCMake/file/LOCK-error-incorrect-timeout-stderr.txt4
-rw-r--r--Tests/RunCMake/file/LOCK-error-incorrect-timeout-trail-result.txt1
-rw-r--r--Tests/RunCMake/file/LOCK-error-incorrect-timeout-trail-stderr.txt4
-rw-r--r--Tests/RunCMake/file/LOCK-error-incorrect-timeout-trail.cmake1
-rw-r--r--Tests/RunCMake/file/LOCK-error-incorrect-timeout.cmake1
-rw-r--r--Tests/RunCMake/file/LOCK-error-lock-fail-result.txt1
-rw-r--r--Tests/RunCMake/file/LOCK-error-lock-fail-stderr.txt6
-rw-r--r--Tests/RunCMake/file/LOCK-error-lock-fail.cmake6
-rw-r--r--Tests/RunCMake/file/LOCK-error-negative-timeout-result.txt1
-rw-r--r--Tests/RunCMake/file/LOCK-error-negative-timeout-stderr.txt4
-rw-r--r--Tests/RunCMake/file/LOCK-error-negative-timeout.cmake1
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-function-result.txt1
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-function-stderr.txt8
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-function.cmake1
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-guard-result.txt1
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-guard-stderr.txt4
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-guard.cmake1
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-path-result.txt1
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-path-stderr.txt4
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-path.cmake1
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-result-variable-result.txt1
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-result-variable-stderr.txt4
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-result-variable.cmake1
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-timeout-result.txt1
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-timeout-stderr.txt4
-rw-r--r--Tests/RunCMake/file/LOCK-error-no-timeout.cmake1
-rw-r--r--Tests/RunCMake/file/LOCK-error-timeout-result.txt1
-rw-r--r--Tests/RunCMake/file/LOCK-error-timeout-stderr.txt12
-rw-r--r--Tests/RunCMake/file/LOCK-error-timeout-stdout.txt1
-rw-r--r--Tests/RunCMake/file/LOCK-error-timeout.cmake17
-rw-r--r--Tests/RunCMake/file/LOCK-error-unknown-option-result.txt1
-rw-r--r--Tests/RunCMake/file/LOCK-error-unknown-option-stderr.txt6
-rw-r--r--Tests/RunCMake/file/LOCK-error-unknown-option.cmake1
-rw-r--r--Tests/RunCMake/file/LOCK-lowercase.cmake11
-rw-r--r--Tests/RunCMake/file/LOCK-stdout.txt11
-rw-r--r--Tests/RunCMake/file/LOCK.cmake40
-rw-r--r--Tests/RunCMake/file/READ_ELF-result.txt1
-rw-r--r--Tests/RunCMake/file/READ_ELF-stderr.txt2
-rw-r--r--Tests/RunCMake/file/READ_ELF.cmake2
-rw-r--r--Tests/RunCMake/file/READ_SYMLINK-noexist-result.txt1
-rw-r--r--Tests/RunCMake/file/READ_SYMLINK-noexist-stderr.txt6
-rw-r--r--Tests/RunCMake/file/READ_SYMLINK-noexist.cmake1
-rw-r--r--Tests/RunCMake/file/READ_SYMLINK-notsymlink-result.txt1
-rw-r--r--Tests/RunCMake/file/READ_SYMLINK-notsymlink-stderr.txt6
-rw-r--r--Tests/RunCMake/file/READ_SYMLINK-notsymlink.cmake2
-rw-r--r--Tests/RunCMake/file/READ_SYMLINK.cmake13
-rw-r--r--Tests/RunCMake/file/REAL_PATH-no-base-dir-result.txt1
-rw-r--r--Tests/RunCMake/file/REAL_PATH-no-base-dir-stderr.txt2
-rw-r--r--Tests/RunCMake/file/REAL_PATH-no-base-dir.cmake2
-rw-r--r--Tests/RunCMake/file/REAL_PATH-unexpected-arg-result.txt1
-rw-r--r--Tests/RunCMake/file/REAL_PATH-unexpected-arg-stderr.txt2
-rw-r--r--Tests/RunCMake/file/REAL_PATH-unexpected-arg.cmake2
-rw-r--r--Tests/RunCMake/file/REAL_PATH.cmake14
-rw-r--r--Tests/RunCMake/file/REMOVE-empty-stderr.txt11
-rw-r--r--Tests/RunCMake/file/REMOVE-empty.cmake2
-rw-r--r--Tests/RunCMake/file/RENAME-arg-missing-result.txt1
-rw-r--r--Tests/RunCMake/file/RENAME-arg-missing-stderr.txt3
-rw-r--r--Tests/RunCMake/file/RENAME-arg-missing.cmake1
-rw-r--r--Tests/RunCMake/file/RENAME-arg-unknown-result.txt1
-rw-r--r--Tests/RunCMake/file/RENAME-arg-unknown-stderr.txt5
-rw-r--r--Tests/RunCMake/file/RENAME-arg-unknown.cmake1
-rw-r--r--Tests/RunCMake/file/RENAME-file-NO_REPLACE-capture-stdout.txt1
-rw-r--r--Tests/RunCMake/file/RENAME-file-NO_REPLACE-capture.cmake9
-rw-r--r--Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail-result.txt1
-rw-r--r--Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail-stderr.txt13
-rw-r--r--Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail.cmake5
-rw-r--r--Tests/RunCMake/file/RENAME-file-replace.cmake9
-rw-r--r--Tests/RunCMake/file/RENAME-file-to-dir-capture-stdout.txt1
-rw-r--r--Tests/RunCMake/file/RENAME-file-to-dir-capture.cmake9
-rw-r--r--Tests/RunCMake/file/RENAME-file-to-dir-fail-result.txt1
-rw-r--r--Tests/RunCMake/file/RENAME-file-to-dir-fail-stderr.txt13
-rw-r--r--Tests/RunCMake/file/RENAME-file-to-dir-fail.cmake5
-rw-r--r--Tests/RunCMake/file/RENAME-file-to-file.cmake10
-rw-r--r--Tests/RunCMake/file/RunCMakeTest.cmake182
-rw-r--r--Tests/RunCMake/file/SIZE-error-does-not-exist-result.txt1
-rw-r--r--Tests/RunCMake/file/SIZE-error-does-not-exist-stderr.txt6
-rw-r--r--Tests/RunCMake/file/SIZE-error-does-not-exist.cmake3
-rw-r--r--Tests/RunCMake/file/SIZE.cmake9
-rw-r--r--Tests/RunCMake/file/TOUCH-error-in-source-directory-result.txt1
-rw-r--r--Tests/RunCMake/file/TOUCH-error-in-source-directory-stderr.txt1
-rw-r--r--Tests/RunCMake/file/TOUCH-error-in-source-directory.cmake2
-rw-r--r--Tests/RunCMake/file/TOUCH-error-missing-directory-result.txt1
-rw-r--r--Tests/RunCMake/file/TOUCH-error-missing-directory-stderr.txt1
-rw-r--r--Tests/RunCMake/file/TOUCH-error-missing-directory.cmake1
-rw-r--r--Tests/RunCMake/file/TOUCH-result.txt1
-rw-r--r--Tests/RunCMake/file/TOUCH-stderr.txt9
-rw-r--r--Tests/RunCMake/file/TOUCH.cmake16
-rw-r--r--Tests/RunCMake/file/UPLOAD-httpheader-not-set-result.txt1
-rw-r--r--Tests/RunCMake/file/UPLOAD-httpheader-not-set-stderr.txt4
-rw-r--r--Tests/RunCMake/file/UPLOAD-httpheader-not-set.cmake1
-rw-r--r--Tests/RunCMake/file/UPLOAD-netrc-bad-result.txt1
-rw-r--r--Tests/RunCMake/file/UPLOAD-netrc-bad-stderr.txt19
-rw-r--r--Tests/RunCMake/file/UPLOAD-netrc-bad.cmake15
-rw-r--r--Tests/RunCMake/file/UPLOAD-netrc-bad.txt0
-rw-r--r--Tests/RunCMake/file/UPLOAD-pass-not-set-result.txt1
-rw-r--r--Tests/RunCMake/file/UPLOAD-pass-not-set-stderr.txt4
-rw-r--r--Tests/RunCMake/file/UPLOAD-pass-not-set.cmake1
-rw-r--r--Tests/RunCMake/file/UPLOAD-tls-cainfo-not-set-result.txt1
-rw-r--r--Tests/RunCMake/file/UPLOAD-tls-cainfo-not-set-stderr.txt4
-rw-r--r--Tests/RunCMake/file/UPLOAD-tls-cainfo-not-set.cmake1
-rw-r--r--Tests/RunCMake/file/UPLOAD-tls-verify-not-set-result.txt1
-rw-r--r--Tests/RunCMake/file/UPLOAD-tls-verify-not-set-stderr.txt4
-rw-r--r--Tests/RunCMake/file/UPLOAD-tls-verify-not-set.cmake1
-rw-r--r--Tests/RunCMake/file/UPLOAD-unused-argument-result.txt0
-rw-r--r--Tests/RunCMake/file/UPLOAD-unused-argument-stderr.txt5
-rw-r--r--Tests/RunCMake/file/UPLOAD-unused-argument.cmake8
-rw-r--r--Tests/RunCMake/file/UPLOAD-unused-argument.txt0
-rw-r--r--Tests/RunCMake/file/dir/empty.txt0
-rw-r--r--Tests/RunCMake/file/from/a.txt0
-rw-r--r--Tests/RunCMake/file/from/a/b.txt0
-rw-r--r--Tests/RunCMake/file/from/a/b/c.txt0
-rw-r--r--Tests/RunCMake/file/subdir_test_unlock/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/file/timeout-script.cmake5
-rw-r--r--Tests/RunCMake/find_dependency/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/find_dependency/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/find_dependency/bad-version-exact-result.txt1
-rw-r--r--Tests/RunCMake/find_dependency/bad-version-exact-stderr.txt11
-rw-r--r--Tests/RunCMake/find_dependency/bad-version-exact.cmake5
-rw-r--r--Tests/RunCMake/find_dependency/bad-version-fuzzy-result.txt1
-rw-r--r--Tests/RunCMake/find_dependency/bad-version-fuzzy-stderr.txt11
-rw-r--r--Tests/RunCMake/find_dependency/bad-version-fuzzy.cmake5
-rw-r--r--Tests/RunCMake/find_dependency/basic.cmake5
-rw-r--r--Tests/RunCMake/find_dependency/invalid-arg-result.txt1
-rw-r--r--Tests/RunCMake/find_dependency/invalid-arg-stderr.txt5
-rw-r--r--Tests/RunCMake/find_dependency/invalid-arg.cmake5
-rw-r--r--Tests/RunCMake/find_dependency/realistic.cmake3
-rw-r--r--Tests/RunCMake/find_dependency/share/cmake/Pack1/Pack1Config.cmake2
-rw-r--r--Tests/RunCMake/find_dependency/share/cmake/Pack1/Pack1ConfigVersion.cmake11
-rw-r--r--Tests/RunCMake/find_dependency/share/cmake/Pack2/Pack2Config.cmake6
-rw-r--r--Tests/RunCMake/find_dependency/share/cmake/Pack2/Pack2ConfigVersion.cmake11
-rw-r--r--Tests/RunCMake/find_file/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/find_file/FromPATHEnv-stdout-cygwin.txt9
-rw-r--r--Tests/RunCMake/find_file/FromPATHEnv-stdout-windows.txt9
-rw-r--r--Tests/RunCMake/find_file/FromPATHEnv-stdout.txt9
-rw-r--r--Tests/RunCMake/find_file/FromPATHEnv.cmake24
-rw-r--r--Tests/RunCMake/find_file/FromPrefixPath-stdout.txt6
-rw-r--r--Tests/RunCMake/find_file/FromPrefixPath.cmake19
-rw-r--r--Tests/RunCMake/find_file/PrefixInPATH-stderr.txt13
-rw-r--r--Tests/RunCMake/find_file/PrefixInPATH-stdout-cygwin.txt4
-rw-r--r--Tests/RunCMake/find_file/PrefixInPATH-stdout-windows.txt4
-rw-r--r--Tests/RunCMake/find_file/PrefixInPATH-stdout.txt4
-rw-r--r--Tests/RunCMake/find_file/PrefixInPATH.cmake14
-rw-r--r--Tests/RunCMake/find_file/Required-result.txt1
-rw-r--r--Tests/RunCMake/find_file/Required-stderr.txt4
-rw-r--r--Tests/RunCMake/find_file/Required-stdout.txt1
-rw-r--r--Tests/RunCMake/find_file/Required.cmake12
-rw-r--r--Tests/RunCMake/find_file/RunCMakeTest.cmake6
-rw-r--r--Tests/RunCMake/find_file/include/PrefixInPATH.h0
-rw-r--r--Tests/RunCMake/find_library/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/find_library/Created-stderr.txt2
-rw-r--r--Tests/RunCMake/find_library/Created.cmake16
-rw-r--r--Tests/RunCMake/find_library/FromPATHEnv-stderr.txt28
-rw-r--r--Tests/RunCMake/find_library/FromPATHEnv-stdout-cygwin.txt6
-rw-r--r--Tests/RunCMake/find_library/FromPATHEnv-stdout-windows.txt6
-rw-r--r--Tests/RunCMake/find_library/FromPATHEnv-stdout.txt6
-rw-r--r--Tests/RunCMake/find_library/FromPATHEnv.cmake35
-rw-r--r--Tests/RunCMake/find_library/FromPrefixPath-stdout.txt6
-rw-r--r--Tests/RunCMake/find_library/FromPrefixPath.cmake24
-rw-r--r--Tests/RunCMake/find_library/LibArchLink-stderr.txt2
-rw-r--r--Tests/RunCMake/find_library/LibArchLink.cmake24
-rw-r--r--Tests/RunCMake/find_library/LibSymLink-stderr.txt2
-rw-r--r--Tests/RunCMake/find_library/LibSymLink.cmake17
-rw-r--r--Tests/RunCMake/find_library/PrefixInPATH-stderr.txt14
-rw-r--r--Tests/RunCMake/find_library/PrefixInPATH-stdout-cygwin.txt4
-rw-r--r--Tests/RunCMake/find_library/PrefixInPATH-stdout-windows.txt4
-rw-r--r--Tests/RunCMake/find_library/PrefixInPATH-stdout.txt4
-rw-r--r--Tests/RunCMake/find_library/PrefixInPATH.cmake17
-rw-r--r--Tests/RunCMake/find_library/Required-result.txt1
-rw-r--r--Tests/RunCMake/find_library/Required-stderr.txt4
-rw-r--r--Tests/RunCMake/find_library/Required-stdout.txt1
-rw-r--r--Tests/RunCMake/find_library/Required.cmake14
-rw-r--r--Tests/RunCMake/find_library/RunCMakeTest.cmake11
-rw-r--r--Tests/RunCMake/find_library/lib/libPrefixInPATH.a0
-rw-r--r--Tests/RunCMake/find_package/CMP0074-OLD-stderr.txt12
-rw-r--r--Tests/RunCMake/find_package/CMP0074-OLD.cmake2
-rw-r--r--Tests/RunCMake/find_package/CMP0074-WARN-stderr.txt32
-rw-r--r--Tests/RunCMake/find_package/CMP0074-WARN.cmake2
-rw-r--r--Tests/RunCMake/find_package/CMP0074-common.cmake46
-rw-r--r--Tests/RunCMake/find_package/CMP0084-NEW-stderr.txt20
-rw-r--r--Tests/RunCMake/find_package/CMP0084-NEW.cmake7
-rw-r--r--Tests/RunCMake/find_package/CMP0084-OLD.cmake7
-rw-r--r--Tests/RunCMake/find_package/CMP0084-WARN-stderr.txt8
-rw-r--r--Tests/RunCMake/find_package/CMP0084-WARN.cmake6
-rw-r--r--Tests/RunCMake/find_package/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/find_package/ComponentRequiredAndOptional-result.txt1
-rw-r--r--Tests/RunCMake/find_package/ComponentRequiredAndOptional-stderr.txt8
-rw-r--r--Tests/RunCMake/find_package/ComponentRequiredAndOptional.cmake1
-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.cmake82
-rw-r--r--Tests/RunCMake/find_package/FromPATHEnv-stderr.txt20
-rw-r--r--Tests/RunCMake/find_package/FromPATHEnv-stdout.txt9
-rw-r--r--Tests/RunCMake/find_package/FromPATHEnv.cmake33
-rw-r--r--Tests/RunCMake/find_package/FromPrefixPath-stdout.txt9
-rw-r--r--Tests/RunCMake/find_package/FromPrefixPath.cmake29
-rw-r--r--Tests/RunCMake/find_package/MissingConfig-stderr.txt4
-rw-r--r--Tests/RunCMake/find_package/MissingConfig-stdout.txt1
-rw-r--r--Tests/RunCMake/find_package/MissingConfig.cmake2
-rw-r--r--Tests/RunCMake/find_package/MissingConfigDebug-stderr.txt18
-rw-r--r--Tests/RunCMake/find_package/MissingConfigDebug.cmake4
-rw-r--r--Tests/RunCMake/find_package/MissingConfigNormal-stdout.txt1
-rw-r--r--Tests/RunCMake/find_package/MissingConfigOneName-stdout.txt1
-rw-r--r--Tests/RunCMake/find_package/MissingConfigOneName.cmake1
-rw-r--r--Tests/RunCMake/find_package/MissingConfigRequired-result.txt1
-rw-r--r--Tests/RunCMake/find_package/MissingConfigRequired-stderr.txt13
-rw-r--r--Tests/RunCMake/find_package/MissingConfigRequired.cmake2
-rw-r--r--Tests/RunCMake/find_package/MissingConfigVersion-stdout.txt1
-rw-r--r--Tests/RunCMake/find_package/MissingConfigVersion.cmake1
-rw-r--r--Tests/RunCMake/find_package/MissingModule-stderr.txt26
-rw-r--r--Tests/RunCMake/find_package/MissingModule.cmake2
-rw-r--r--Tests/RunCMake/find_package/MissingModuleRequired-result.txt1
-rw-r--r--Tests/RunCMake/find_package/MissingModuleRequired-stderr.txt21
-rw-r--r--Tests/RunCMake/find_package/MissingModuleRequired.cmake2
-rw-r--r--Tests/RunCMake/find_package/MissingNormal-stderr.txt23
-rw-r--r--Tests/RunCMake/find_package/MissingNormal.cmake2
-rw-r--r--Tests/RunCMake/find_package/MissingNormalRequired-result.txt1
-rw-r--r--Tests/RunCMake/find_package/MissingNormalRequired-stderr.txt17
-rw-r--r--Tests/RunCMake/find_package/MissingNormalRequired.cmake2
-rw-r--r--Tests/RunCMake/find_package/MissingNormalVersion-stderr.txt17
-rw-r--r--Tests/RunCMake/find_package/MissingNormalVersion.cmake1
-rw-r--r--Tests/RunCMake/find_package/MissingNormalWarnNoModuleNew-stderr.txt30
-rw-r--r--Tests/RunCMake/find_package/MissingNormalWarnNoModuleNew.cmake3
-rw-r--r--Tests/RunCMake/find_package/MissingNormalWarnNoModuleOld-stderr.txt30
-rw-r--r--Tests/RunCMake/find_package/MissingNormalWarnNoModuleOld.cmake2
-rw-r--r--Tests/RunCMake/find_package/MixedModeOptions-result.txt1
-rw-r--r--Tests/RunCMake/find_package/MixedModeOptions-stderr.txt14
-rw-r--r--Tests/RunCMake/find_package/MixedModeOptions.cmake1
-rw-r--r--Tests/RunCMake/find_package/PackageRoot-stderr.txt43
-rw-r--r--Tests/RunCMake/find_package/PackageRoot.cmake53
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/BarConfig.cmake9
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/FindBar.cmake9
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/FindFoo.cmake11
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/ResolvedConfig.cmake1
-rwxr-xr-xTests/RunCMake/find_package/PackageRoot/bar/cmake_root/bin/bar.exe0
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/bar/cmake_root/include/bar.h0
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/bar/cmake_root/include/zot/zot.h0
-rwxr-xr-xTests/RunCMake/find_package/PackageRoot/bar/env_root/bin/bar.exe0
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/bar/env_root/include/bar.h0
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/bar/env_root/include/zot/zot.h0
-rwxr-xr-xTests/RunCMake/find_package/PackageRoot/foo/cmake_root/bin/bar.exe0
-rwxr-xr-xTests/RunCMake/find_package/PackageRoot/foo/cmake_root/bin/foo.exe0
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/foo/cmake_root/cmake/BarConfig.cmake9
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/foo/cmake_root/include/bar.h0
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/foo/cmake_root/include/foo.h0
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/foo/cmake_root/include/zot/zot.h0
-rwxr-xr-xTests/RunCMake/find_package/PackageRoot/foo/env_root/bin/bar.exe0
-rwxr-xr-xTests/RunCMake/find_package/PackageRoot/foo/env_root/bin/foo.exe0
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/foo/env_root/cmake/BarConfig.cmake9
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/foo/env_root/include/bar.h0
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/foo/env_root/include/foo.h0
-rw-r--r--Tests/RunCMake/find_package/PackageRoot/foo/env_root/include/zot/zot.h0
-rw-r--r--Tests/RunCMake/find_package/PackageRootNestedConfig-stderr.txt298
-rw-r--r--Tests/RunCMake/find_package/PackageRootNestedConfig.cmake141
-rw-r--r--Tests/RunCMake/find_package/PackageRootNestedModule-stderr.txt298
-rw-r--r--Tests/RunCMake/find_package/PackageRootNestedModule.cmake141
-rw-r--r--Tests/RunCMake/find_package/PolicyPop-result.txt1
-rw-r--r--Tests/RunCMake/find_package/PolicyPop-stderr.txt5
-rw-r--r--Tests/RunCMake/find_package/PolicyPop.cmake1
-rw-r--r--Tests/RunCMake/find_package/PolicyPop/PolicyPopConfig.cmake0
-rw-r--r--Tests/RunCMake/find_package/PolicyPop/PolicyPopConfigVersion.cmake3
-rw-r--r--Tests/RunCMake/find_package/PolicyPush-result.txt1
-rw-r--r--Tests/RunCMake/find_package/PolicyPush-stderr.txt5
-rw-r--r--Tests/RunCMake/find_package/PolicyPush.cmake1
-rw-r--r--Tests/RunCMake/find_package/PolicyPush/PolicyPushConfig.cmake0
-rw-r--r--Tests/RunCMake/find_package/PolicyPush/PolicyPushConfigVersion.cmake3
-rw-r--r--Tests/RunCMake/find_package/RunCMakeTest.cmake45
-rw-r--r--Tests/RunCMake/find_package/SetFoundFALSE-stderr.txt9
-rw-r--r--Tests/RunCMake/find_package/SetFoundFALSE.cmake2
-rw-r--r--Tests/RunCMake/find_package/SetFoundFALSEConfig.cmake1
-rw-r--r--Tests/RunCMake/find_package/SetFoundResolved-stderr.txt10
-rw-r--r--Tests/RunCMake/find_package/SetFoundResolved.cmake17
-rw-r--r--Tests/RunCMake/find_package/VersionRange.cmake37
-rw-r--r--Tests/RunCMake/find_package/VersionRange2.cmake37
-rw-r--r--Tests/RunCMake/find_package/VersionRange3.cmake49
-rw-r--r--Tests/RunCMake/find_package/VersionRange4.cmake39
-rw-r--r--Tests/RunCMake/find_package/VersionRangeCfg/VersionRangeCfgConfig.cmake0
-rw-r--r--Tests/RunCMake/find_package/VersionRangeCfg/VersionRangeCfgConfigVersion.cmake74
-rw-r--r--Tests/RunCMake/find_package/VersionRangeConfig.cmake23
-rw-r--r--Tests/RunCMake/find_package/VersionRangeConfig2.cmake23
-rw-r--r--Tests/RunCMake/find_package/VersionRangeConfigStd.cmake23
-rw-r--r--Tests/RunCMake/find_package/VersionRangeConfigStd2.cmake23
-rw-r--r--Tests/RunCMake/find_package/VersionRangeStd/VersionRangeStdConfig.cmake0
-rw-r--r--Tests/RunCMake/find_package/VersionRangeStd/VersionRangeStdConfigVersion.cmake24
-rw-r--r--Tests/RunCMake/find_package/VersionRangeWithEXACT-result.txt1
-rw-r--r--Tests/RunCMake/find_package/VersionRangeWithEXACT-stderr.txt2
-rw-r--r--Tests/RunCMake/find_package/VersionRangeWithEXACT.cmake1
-rw-r--r--Tests/RunCMake/find_package/VersionedA-1/VersionedAConfig.cmake0
-rw-r--r--Tests/RunCMake/find_package/VersionedA-1/VersionedAConfigVersion.cmake4
-rw-r--r--Tests/RunCMake/find_package/VersionedA-2/VersionedAConfig.cmake0
-rw-r--r--Tests/RunCMake/find_package/VersionedA-2/VersionedAConfigVersion.cmake4
-rw-r--r--Tests/RunCMake/find_package/WrongVersion-stderr.txt11
-rw-r--r--Tests/RunCMake/find_package/WrongVersion.cmake2
-rw-r--r--Tests/RunCMake/find_package/WrongVersionConfig-stderr.txt11
-rw-r--r--Tests/RunCMake/find_package/WrongVersionConfig.cmake2
-rw-r--r--Tests/RunCMake/find_package/WrongVersionRange-result.txt1
-rw-r--r--Tests/RunCMake/find_package/WrongVersionRange-stderr.txt28
-rw-r--r--Tests/RunCMake/find_package/WrongVersionRange.cmake9
-rw-r--r--Tests/RunCMake/find_path/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/find_path/EmptyOldStyle-stdout.txt1
-rw-r--r--Tests/RunCMake/find_path/EmptyOldStyle.cmake2
-rw-r--r--Tests/RunCMake/find_path/Frameworks/Foo.framework/Headers/Some/Dir/Header.h0
-rw-r--r--Tests/RunCMake/find_path/FrameworksWithSubdirs-stdout.txt1
-rw-r--r--Tests/RunCMake/find_path/FrameworksWithSubdirs.cmake3
-rw-r--r--Tests/RunCMake/find_path/FromPATHEnv-stderr.txt27
-rw-r--r--Tests/RunCMake/find_path/FromPATHEnv-stdout-cygwin.txt9
-rw-r--r--Tests/RunCMake/find_path/FromPATHEnv-stdout-windows.txt9
-rw-r--r--Tests/RunCMake/find_path/FromPATHEnv-stdout.txt9
-rw-r--r--Tests/RunCMake/find_path/FromPATHEnv.cmake37
-rw-r--r--Tests/RunCMake/find_path/PrefixInPATH-stdout-cygwin.txt4
-rw-r--r--Tests/RunCMake/find_path/PrefixInPATH-stdout-windows.txt4
-rw-r--r--Tests/RunCMake/find_path/PrefixInPATH-stdout.txt4
-rw-r--r--Tests/RunCMake/find_path/PrefixInPATH.cmake8
-rw-r--r--Tests/RunCMake/find_path/Required-result.txt1
-rw-r--r--Tests/RunCMake/find_path/Required-stderr.txt4
-rw-r--r--Tests/RunCMake/find_path/Required-stdout.txt1
-rw-r--r--Tests/RunCMake/find_path/Required.cmake12
-rw-r--r--Tests/RunCMake/find_path/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/find_path/include/PrefixInPATH.h0
-rwxr-xr-xTests/RunCMake/find_program/A/testA1
-rwxr-xr-xTests/RunCMake/find_program/A/testAandB1
-rwxr-xr-xTests/RunCMake/find_program/B/testAandB1
-rwxr-xr-xTests/RunCMake/find_program/B/testB1
-rw-r--r--Tests/RunCMake/find_program/BundleSpaceInName-stdout.txt1
-rw-r--r--Tests/RunCMake/find_program/BundleSpaceInName.cmake8
-rw-r--r--Tests/RunCMake/find_program/CMP0109-Common.cmake7
-rw-r--r--Tests/RunCMake/find_program/CMP0109-NEW-stdout.txt2
-rw-r--r--Tests/RunCMake/find_program/CMP0109-NEW.cmake2
-rw-r--r--Tests/RunCMake/find_program/CMP0109-OLD-stdout.txt2
-rw-r--r--Tests/RunCMake/find_program/CMP0109-OLD.cmake2
-rw-r--r--Tests/RunCMake/find_program/CMP0109-WARN-stderr.txt29
-rw-r--r--Tests/RunCMake/find_program/CMP0109-WARN-stdout.txt2
-rw-r--r--Tests/RunCMake/find_program/CMP0109-WARN.cmake1
-rw-r--r--Tests/RunCMake/find_program/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/find_program/DirsPerName-stdout.txt2
-rw-r--r--Tests/RunCMake/find_program/DirsPerName.cmake12
-rw-r--r--Tests/RunCMake/find_program/EnvAndHints-stderr.txt28
-rw-r--r--Tests/RunCMake/find_program/EnvAndHints-stdout.txt4
-rw-r--r--Tests/RunCMake/find_program/EnvAndHints.cmake33
-rw-r--r--Tests/RunCMake/find_program/NamesPerDir-stdout.txt2
-rw-r--r--Tests/RunCMake/find_program/NamesPerDir.cmake12
-rw-r--r--Tests/RunCMake/find_program/RelAndAbsPath-stdout.txt8
-rw-r--r--Tests/RunCMake/find_program/RelAndAbsPath.cmake84
-rw-r--r--Tests/RunCMake/find_program/Required-result.txt1
-rw-r--r--Tests/RunCMake/find_program/Required-stderr.txt4
-rw-r--r--Tests/RunCMake/find_program/Required-stdout.txt1
-rw-r--r--Tests/RunCMake/find_program/Required.cmake12
-rw-r--r--Tests/RunCMake/find_program/RunCMakeTest.cmake28
-rwxr-xr-xTests/RunCMake/find_program/Win/testCom.com0
-rwxr-xr-xTests/RunCMake/find_program/Win/testCom.exe0
-rwxr-xr-xTests/RunCMake/find_program/Win/testExe.exe0
-rw-r--r--Tests/RunCMake/find_program/WindowsCom-stdout.txt1
-rw-r--r--Tests/RunCMake/find_program/WindowsCom.cmake6
-rw-r--r--Tests/RunCMake/find_program/WindowsExe-stdout.txt1
-rw-r--r--Tests/RunCMake/find_program/WindowsExe.cmake6
-rwxr-xr-xTests/RunCMake/find_program/testCWD1
-rw-r--r--Tests/RunCMake/foreach/BadRangeInFunction-result.txt1
-rw-r--r--Tests/RunCMake/foreach/BadRangeInFunction-stderr.txt5
-rw-r--r--Tests/RunCMake/foreach/BadRangeInFunction.cmake5
-rw-r--r--Tests/RunCMake/foreach/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/foreach/RunCMakeTest.cmake22
-rw-r--r--Tests/RunCMake/foreach/foreach-ITEMS-multiple-iter-vars-test-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-ITEMS-multiple-iter-vars-test-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-ITEMS-multiple-iter-vars-test.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-ITEMS-with-ZIP_LISTS-mix-test-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-ITEMS-with-ZIP_LISTS-mix-test-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-ITEMS-with-ZIP_LISTS-mix-test.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-LISTS-multiple-iter-vars-test-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-LISTS-multiple-iter-vars-test-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-LISTS-multiple-iter-vars-test.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-LISTS-with-ZIP_LISTS-mix-test-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-LISTS-with-ZIP_LISTS-mix-test-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-LISTS-with-ZIP_LISTS-mix-test.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-invalid-test-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-invalid-test-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-invalid-test.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-out-of-range-test-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-out-of-range-test-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-RANGE-out-of-range-test.cmake3
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-1-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-1-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-1.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-2-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-2-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-2.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-multiple-iter-vars-test-stdout.txt6
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-multiple-iter-vars-test.cmake42
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-test-stdout.txt19
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-test.cmake68
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-ITEMS-mix-test-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-ITEMS-mix-test-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-ITEMS-mix-test.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-LISTS-mix-test-result.txt1
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-LISTS-mix-test-stderr.txt4
-rw-r--r--Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-LISTS-mix-test.cmake2
-rw-r--r--Tests/RunCMake/foreach/foreach-all-test-stdout.txt44
-rw-r--r--Tests/RunCMake/foreach/foreach-all-test.cmake67
-rw-r--r--Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION-stdout.txt7
-rw-r--r--Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION.cmake94
-rw-r--r--Tests/RunCMake/function/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/function/DummyMacro.cmake20
-rw-r--r--Tests/RunCMake/function/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/get_filename_component/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/get_filename_component/IncorrectArguments-result.txt1
-rw-r--r--Tests/RunCMake/get_filename_component/IncorrectArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/get_filename_component/IncorrectArguments.cmake2
-rw-r--r--Tests/RunCMake/get_filename_component/KnownComponents.cmake161
-rwxr-xr-xTests/RunCMake/get_filename_component/KnownComponents.sh1
-rw-r--r--Tests/RunCMake/get_filename_component/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/get_filename_component/UnknownComponent-result.txt1
-rw-r--r--Tests/RunCMake/get_filename_component/UnknownComponent-stderr.txt4
-rw-r--r--Tests/RunCMake/get_filename_component/UnknownComponent.cmake2
-rw-r--r--Tests/RunCMake/get_property/BadArgument-result.txt1
-rw-r--r--Tests/RunCMake/get_property/BadArgument-stderr.txt4
-rw-r--r--Tests/RunCMake/get_property/BadArgument.cmake1
-rw-r--r--Tests/RunCMake/get_property/BadDirectory-result.txt1
-rw-r--r--Tests/RunCMake/get_property/BadDirectory-stderr.txt6
-rw-r--r--Tests/RunCMake/get_property/BadDirectory.cmake1
-rw-r--r--Tests/RunCMake/get_property/BadScope-result.txt1
-rw-r--r--Tests/RunCMake/get_property/BadScope-stderr.txt5
-rw-r--r--Tests/RunCMake/get_property/BadScope.cmake1
-rw-r--r--Tests/RunCMake/get_property/BadTarget-result.txt1
-rw-r--r--Tests/RunCMake/get_property/BadTarget-stderr.txt5
-rw-r--r--Tests/RunCMake/get_property/BadTarget.cmake1
-rw-r--r--Tests/RunCMake/get_property/BadTest-result.txt1
-rw-r--r--Tests/RunCMake/get_property/BadTest-stderr.txt4
-rw-r--r--Tests/RunCMake/get_property/BadTest.cmake1
-rw-r--r--Tests/RunCMake/get_property/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/get_property/DebugConfigurations-stderr.txt11
-rw-r--r--Tests/RunCMake/get_property/DebugConfigurations.cmake41
-rw-r--r--Tests/RunCMake/get_property/GlobalName-result.txt1
-rw-r--r--Tests/RunCMake/get_property/GlobalName-stderr.txt4
-rw-r--r--Tests/RunCMake/get_property/GlobalName.cmake1
-rw-r--r--Tests/RunCMake/get_property/IsMultiConfig-stdout.txt1
-rw-r--r--Tests/RunCMake/get_property/IsMultiConfig.cmake2
-rw-r--r--Tests/RunCMake/get_property/MissingArgument-result.txt1
-rw-r--r--Tests/RunCMake/get_property/MissingArgument-stderr.txt4
-rw-r--r--Tests/RunCMake/get_property/MissingArgument.cmake1
-rw-r--r--Tests/RunCMake/get_property/NoCache-result.txt1
-rw-r--r--Tests/RunCMake/get_property/NoCache-stderr.txt4
-rw-r--r--Tests/RunCMake/get_property/NoCache.cmake1
-rw-r--r--Tests/RunCMake/get_property/NoProperty-result.txt1
-rw-r--r--Tests/RunCMake/get_property/NoProperty-stderr.txt4
-rw-r--r--Tests/RunCMake/get_property/NoProperty.cmake1
-rw-r--r--Tests/RunCMake/get_property/NoSource-result.txt1
-rw-r--r--Tests/RunCMake/get_property/NoSource-stderr.txt4
-rw-r--r--Tests/RunCMake/get_property/NoSource.cmake1
-rw-r--r--Tests/RunCMake/get_property/NoTarget-result.txt1
-rw-r--r--Tests/RunCMake/get_property/NoTarget-stderr.txt4
-rw-r--r--Tests/RunCMake/get_property/NoTarget.cmake1
-rw-r--r--Tests/RunCMake/get_property/NoTest-result.txt1
-rw-r--r--Tests/RunCMake/get_property/NoTest-stderr.txt4
-rw-r--r--Tests/RunCMake/get_property/NoTest.cmake1
-rw-r--r--Tests/RunCMake/get_property/NotMultiConfig-stdout.txt1
-rw-r--r--Tests/RunCMake/get_property/NotMultiConfig.cmake1
-rw-r--r--Tests/RunCMake/get_property/RunCMakeTest.cmake38
-rw-r--r--Tests/RunCMake/get_property/VariableName-result.txt1
-rw-r--r--Tests/RunCMake/get_property/VariableName-stderr.txt4
-rw-r--r--Tests/RunCMake/get_property/VariableName.cmake1
-rw-r--r--Tests/RunCMake/get_property/cache_properties-stderr.txt3
-rw-r--r--Tests/RunCMake/get_property/cache_properties.cmake15
-rw-r--r--Tests/RunCMake/get_property/directory_properties-stderr.txt30
-rw-r--r--Tests/RunCMake/get_property/directory_properties.cmake39
-rw-r--r--Tests/RunCMake/get_property/directory_properties/CMakeLists.txt9
-rw-r--r--Tests/RunCMake/get_property/directory_properties/sub1/CMakeLists.txt0
-rw-r--r--Tests/RunCMake/get_property/directory_properties/sub2/CMakeLists.txt0
-rw-r--r--Tests/RunCMake/get_property/get_directory_property_empty-result.txt1
-rw-r--r--Tests/RunCMake/get_property/get_directory_property_empty-stderr.txt4
-rw-r--r--Tests/RunCMake/get_property/get_directory_property_empty.cmake1
-rw-r--r--Tests/RunCMake/get_property/get_directory_property_missing-result.txt1
-rw-r--r--Tests/RunCMake/get_property/get_directory_property_missing-stderr.txt4
-rw-r--r--Tests/RunCMake/get_property/get_directory_property_missing.cmake1
-rw-r--r--Tests/RunCMake/get_property/get_directory_property_missingWithDir-result.txt1
-rw-r--r--Tests/RunCMake/get_property/get_directory_property_missingWithDir-stderr.txt4
-rw-r--r--Tests/RunCMake/get_property/get_directory_property_missingWithDir.cmake1
-rw-r--r--Tests/RunCMake/get_property/global_properties-stderr.txt6
-rw-r--r--Tests/RunCMake/get_property/global_properties.cmake16
-rw-r--r--Tests/RunCMake/get_property/install_properties-stderr.txt3
-rw-r--r--Tests/RunCMake/get_property/install_properties.cmake18
-rw-r--r--Tests/RunCMake/get_property/source_properties-stderr.txt12
-rw-r--r--Tests/RunCMake/get_property/source_properties.cmake25
-rw-r--r--Tests/RunCMake/get_property/source_properties_failures-result.txt1
-rw-r--r--Tests/RunCMake/get_property/source_properties_failures-stderr.txt66
-rw-r--r--Tests/RunCMake/get_property/source_properties_failures.cmake14
-rw-r--r--Tests/RunCMake/get_property/target_properties-stderr.txt16
-rw-r--r--Tests/RunCMake/get_property/target_properties.cmake25
-rw-r--r--Tests/RunCMake/get_property/test_properties-stderr.txt6
-rw-r--r--Tests/RunCMake/get_property/test_properties.cmake17
-rw-r--r--Tests/RunCMake/if/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/if/InvalidArgument1-result.txt1
-rw-r--r--Tests/RunCMake/if/InvalidArgument1-stderr.txt8
-rw-r--r--Tests/RunCMake/if/InvalidArgument1.cmake2
-rw-r--r--Tests/RunCMake/if/IsDirectory-stdout.txt1
-rw-r--r--Tests/RunCMake/if/IsDirectory.cmake5
-rw-r--r--Tests/RunCMake/if/IsDirectoryLong-stdout.txt1
-rw-r--r--Tests/RunCMake/if/IsDirectoryLong.cmake10
-rw-r--r--Tests/RunCMake/if/MatchesSelf.cmake4
-rw-r--r--Tests/RunCMake/if/RunCMakeTest.cmake15
-rw-r--r--Tests/RunCMake/if/TestNameThatDoesNotExist-stdout.txt1
-rw-r--r--Tests/RunCMake/if/TestNameThatDoesNotExist.cmake6
-rw-r--r--Tests/RunCMake/if/TestNameThatExists-stdout.txt1
-rw-r--r--Tests/RunCMake/if/TestNameThatExists.cmake7
-rw-r--r--Tests/RunCMake/if/duplicate-deep-else-result.txt1
-rw-r--r--Tests/RunCMake/if/duplicate-deep-else-stderr.txt4
-rw-r--r--Tests/RunCMake/if/duplicate-deep-else.cmake7
-rw-r--r--Tests/RunCMake/if/duplicate-else-after-elseif-result.txt1
-rw-r--r--Tests/RunCMake/if/duplicate-else-after-elseif-stderr.txt4
-rw-r--r--Tests/RunCMake/if/duplicate-else-after-elseif.cmake5
-rw-r--r--Tests/RunCMake/if/duplicate-else-result.txt1
-rw-r--r--Tests/RunCMake/if/duplicate-else-stderr.txt4
-rw-r--r--Tests/RunCMake/if/duplicate-else.cmake4
-rw-r--r--Tests/RunCMake/if/elseif-message-result.txt1
-rw-r--r--Tests/RunCMake/if/elseif-message-stderr.txt8
-rw-r--r--Tests/RunCMake/if/elseif-message.cmake4
-rw-r--r--Tests/RunCMake/if/misplaced-elseif-result.txt1
-rw-r--r--Tests/RunCMake/if/misplaced-elseif-stderr.txt4
-rw-r--r--Tests/RunCMake/if/misplaced-elseif.cmake4
-rw-r--r--Tests/RunCMake/include/CMP0024-NEW-result.txt1
-rw-r--r--Tests/RunCMake/include/CMP0024-NEW-stderr.txt8
-rw-r--r--Tests/RunCMake/include/CMP0024-NEW.cmake9
-rw-r--r--Tests/RunCMake/include/CMP0024-WARN-result.txt1
-rw-r--r--Tests/RunCMake/include/CMP0024-WARN-stderr.txt14
-rw-r--r--Tests/RunCMake/include/CMP0024-WARN.cmake7
-rw-r--r--Tests/RunCMake/include/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/include/EmptyString-stderr.txt5
-rw-r--r--Tests/RunCMake/include/EmptyString.cmake1
-rw-r--r--Tests/RunCMake/include/EmptyStringOptional-stderr.txt5
-rw-r--r--Tests/RunCMake/include/EmptyStringOptional.cmake1
-rw-r--r--Tests/RunCMake/include/ExportExportInclude-result.txt1
-rw-r--r--Tests/RunCMake/include/ExportExportInclude-stderr.txt6
-rw-r--r--Tests/RunCMake/include/ExportExportInclude.cmake6
-rw-r--r--Tests/RunCMake/include/IncludeIsDirectory-result.txt1
-rw-r--r--Tests/RunCMake/include/IncludeIsDirectory-stderr.txt6
-rw-r--r--Tests/RunCMake/include/IncludeIsDirectory.cmake1
-rw-r--r--Tests/RunCMake/include/IncludeMalformed-result.txt1
-rw-r--r--Tests/RunCMake/include/IncludeMalformed-stderr.txt13
-rw-r--r--Tests/RunCMake/include/IncludeMalformed.cmake1
-rw-r--r--Tests/RunCMake/include/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/include/empty.cpp7
-rw-r--r--Tests/RunCMake/include/malformedInclude.cmake1
-rw-r--r--Tests/RunCMake/include/subdir1/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/include/subdir2/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/include_directories/CMP0021-result.txt1
-rw-r--r--Tests/RunCMake/include_directories/CMP0021-stderr.txt4
-rw-r--r--Tests/RunCMake/include_directories/CMP0021.cmake9
-rw-r--r--Tests/RunCMake/include_directories/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/include_directories/DebugIncludes-result.txt1
-rw-r--r--Tests/RunCMake/include_directories/DebugIncludes-stderr.txt53
-rw-r--r--Tests/RunCMake/include_directories/DebugIncludes.cmake55
-rw-r--r--Tests/RunCMake/include_directories/DirectoryBefore-stdout.txt1
-rw-r--r--Tests/RunCMake/include_directories/DirectoryBefore.cmake4
-rw-r--r--Tests/RunCMake/include_directories/ImportedTarget-result.txt1
-rw-r--r--Tests/RunCMake/include_directories/ImportedTarget-stderr.txt13
-rw-r--r--Tests/RunCMake/include_directories/ImportedTarget.cmake9
-rw-r--r--Tests/RunCMake/include_directories/NotFoundContent-result.txt1
-rw-r--r--Tests/RunCMake/include_directories/NotFoundContent-stderr.txt6
-rw-r--r--Tests/RunCMake/include_directories/NotFoundContent.cmake9
-rw-r--r--Tests/RunCMake/include_directories/RunCMakeTest.cmake13
-rw-r--r--Tests/RunCMake/include_directories/TID-bad-target-result.txt1
-rw-r--r--Tests/RunCMake/include_directories/TID-bad-target-stderr.txt4
-rw-r--r--Tests/RunCMake/include_directories/TID-bad-target.cmake6
-rw-r--r--Tests/RunCMake/include_directories/empty.cpp0
-rw-r--r--Tests/RunCMake/include_directories/incomplete-genex.cmake23
-rw-r--r--Tests/RunCMake/include_directories/install_config-result.txt1
-rw-r--r--Tests/RunCMake/include_directories/install_config-stderr.txt5
-rw-r--r--Tests/RunCMake/include_directories/install_config.cmake6
-rw-r--r--Tests/RunCMake/include_external_msproject/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/include_external_msproject/CustomConfig-check.cmake1
-rw-r--r--Tests/RunCMake/include_external_msproject/CustomConfig.cmake3
-rw-r--r--Tests/RunCMake/include_external_msproject/CustomGuid-check.cmake1
-rw-r--r--Tests/RunCMake/include_external_msproject/CustomGuid.cmake2
-rw-r--r--Tests/RunCMake/include_external_msproject/CustomGuidTypePlatform-check.cmake1
-rw-r--r--Tests/RunCMake/include_external_msproject/CustomGuidTypePlatform.cmake5
-rw-r--r--Tests/RunCMake/include_external_msproject/CustomTypePlatform-check.cmake1
-rw-r--r--Tests/RunCMake/include_external_msproject/CustomTypePlatform.cmake3
-rw-r--r--Tests/RunCMake/include_external_msproject/RunCMakeTest.cmake11
-rw-r--r--Tests/RunCMake/include_external_msproject/SkipGetTargetFrameworkProperties-check.cmake21
-rw-r--r--Tests/RunCMake/include_external_msproject/SkipGetTargetFrameworkProperties.cmake5
-rw-r--r--Tests/RunCMake/include_external_msproject/check_utils.cmake138
-rw-r--r--Tests/RunCMake/include_external_msproject/main.cpp3
-rw-r--r--Tests/RunCMake/include_guard/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/include_guard/DirectoryScope.cmake19
-rw-r--r--Tests/RunCMake/include_guard/GlobalScope.cmake11
-rw-r--r--Tests/RunCMake/include_guard/InvalidArgumentsNumber-result.txt1
-rw-r--r--Tests/RunCMake/include_guard/InvalidArgumentsNumber-stderr.txt5
-rw-r--r--Tests/RunCMake/include_guard/InvalidArgumentsNumber.cmake1
-rw-r--r--Tests/RunCMake/include_guard/InvalidScope-result.txt1
-rw-r--r--Tests/RunCMake/include_guard/InvalidScope-stderr.txt4
-rw-r--r--Tests/RunCMake/include_guard/InvalidScope.cmake1
-rw-r--r--Tests/RunCMake/include_guard/RunCMakeTest.cmake7
-rw-r--r--Tests/RunCMake/include_guard/Scripts/DirScript.cmake12
-rw-r--r--Tests/RunCMake/include_guard/Scripts/GlobScript.cmake12
-rw-r--r--Tests/RunCMake/include_guard/Scripts/VarScript.cmake12
-rw-r--r--Tests/RunCMake/include_guard/VariableScope.cmake24
-rw-r--r--Tests/RunCMake/include_guard/global_script_dir/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/include_guard/sub_dir_script1/CMakeLists.txt9
-rw-r--r--Tests/RunCMake/include_guard/sub_dir_script1/sub_dir_script3/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/include_guard/sub_dir_script2/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/install/CMP0062-NEW-result.txt1
-rw-r--r--Tests/RunCMake/install/CMP0062-NEW-stderr.txt11
-rw-r--r--Tests/RunCMake/install/CMP0062-NEW.cmake6
-rw-r--r--Tests/RunCMake/install/CMP0062-OLD-result.txt1
-rw-r--r--Tests/RunCMake/install/CMP0062-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/install/CMP0062-OLD.cmake6
-rw-r--r--Tests/RunCMake/install/CMP0062-WARN-result.txt1
-rw-r--r--Tests/RunCMake/install/CMP0062-WARN-stderr.txt16
-rw-r--r--Tests/RunCMake/install/CMP0062-WARN.cmake5
-rw-r--r--Tests/RunCMake/install/CMP0087-NEW-check.cmake7
-rw-r--r--Tests/RunCMake/install/CMP0087-NEW.cmake3
-rw-r--r--Tests/RunCMake/install/CMP0087-NEW/CMakeLists.txt7
-rw-r--r--Tests/RunCMake/install/CMP0087-OLD-check.cmake8
-rw-r--r--Tests/RunCMake/install/CMP0087-OLD.cmake3
-rw-r--r--Tests/RunCMake/install/CMP0087-OLD/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/install/CMP0087-WARN-stderr.txt5
-rw-r--r--Tests/RunCMake/install/CMP0087-WARN.cmake2
-rw-r--r--Tests/RunCMake/install/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/install/DIRECTORY-DESTINATION-TYPE-result.txt1
-rw-r--r--Tests/RunCMake/install/DIRECTORY-DESTINATION-TYPE-stderr.txt5
-rw-r--r--Tests/RunCMake/install/DIRECTORY-DESTINATION-TYPE.cmake1
-rw-r--r--Tests/RunCMake/install/DIRECTORY-DESTINATION-bad-result.txt1
-rw-r--r--Tests/RunCMake/install/DIRECTORY-DESTINATION-bad-stderr.txt6
-rw-r--r--Tests/RunCMake/install/DIRECTORY-DESTINATION-bad.cmake1
-rw-r--r--Tests/RunCMake/install/DIRECTORY-DIRECTORY-bad-result.txt1
-rw-r--r--Tests/RunCMake/install/DIRECTORY-DIRECTORY-bad-stderr.txt6
-rw-r--r--Tests/RunCMake/install/DIRECTORY-DIRECTORY-bad.cmake1
-rw-r--r--Tests/RunCMake/install/DIRECTORY-MESSAGE_NEVER-check.cmake13
-rw-r--r--Tests/RunCMake/install/DIRECTORY-MESSAGE_NEVER.cmake3
-rw-r--r--Tests/RunCMake/install/DIRECTORY-OPTIONAL-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/DIRECTORY-OPTIONAL.cmake1
-rw-r--r--Tests/RunCMake/install/DIRECTORY-PATTERN-MESSAGE_NEVER-result.txt1
-rw-r--r--Tests/RunCMake/install/DIRECTORY-PATTERN-MESSAGE_NEVER-stderr.txt4
-rw-r--r--Tests/RunCMake/install/DIRECTORY-PATTERN-MESSAGE_NEVER.cmake1
-rw-r--r--Tests/RunCMake/install/DIRECTORY-PATTERN-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/DIRECTORY-PATTERN.cmake36
-rw-r--r--Tests/RunCMake/install/DIRECTORY-TYPE-Cache-all-check.cmake42
-rw-r--r--Tests/RunCMake/install/DIRECTORY-TYPE-Cache.cmake13
-rw-r--r--Tests/RunCMake/install/DIRECTORY-TYPE-CacheDependent-all-check.cmake24
-rw-r--r--Tests/RunCMake/install/DIRECTORY-TYPE-CacheDependent.cmake7
-rw-r--r--Tests/RunCMake/install/DIRECTORY-TYPE-all-check.cmake42
-rw-r--r--Tests/RunCMake/install/DIRECTORY-TYPE.cmake13
-rw-r--r--Tests/RunCMake/install/DIRECTORY-message-check.cmake28
-rw-r--r--Tests/RunCMake/install/DIRECTORY-message-lazy-check.cmake24
-rw-r--r--Tests/RunCMake/install/DIRECTORY-message-lazy.cmake3
-rw-r--r--Tests/RunCMake/install/DIRECTORY-message.cmake3
-rw-r--r--Tests/RunCMake/install/Deprecated-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/Deprecated.cmake13
-rw-r--r--Tests/RunCMake/install/EXPORT-NamelinkOnly.cmake12
-rw-r--r--Tests/RunCMake/install/EXPORT-OldIFace.cmake8
-rw-r--r--Tests/RunCMake/install/EXPORT-OldIFace/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/install/EXPORT-SeparateNamelink.cmake19
-rw-r--r--Tests/RunCMake/install/EXPORT-UnknownExport-result.txt1
-rw-r--r--Tests/RunCMake/install/EXPORT-UnknownExport-stderr.txt1
-rw-r--r--Tests/RunCMake/install/EXPORT-UnknownExport.cmake5
-rw-r--r--Tests/RunCMake/install/FILES-DESTINATION-TYPE-result.txt1
-rw-r--r--Tests/RunCMake/install/FILES-DESTINATION-TYPE-stderr.txt5
-rw-r--r--Tests/RunCMake/install/FILES-DESTINATION-TYPE.cmake1
-rw-r--r--Tests/RunCMake/install/FILES-DESTINATION-bad-result.txt1
-rw-r--r--Tests/RunCMake/install/FILES-DESTINATION-bad-stderr.txt6
-rw-r--r--Tests/RunCMake/install/FILES-DESTINATION-bad.cmake1
-rw-r--r--Tests/RunCMake/install/FILES-EXCLUDE_FROM_ALL-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/FILES-EXCLUDE_FROM_ALL-exc-check.cmake1
-rw-r--r--Tests/RunCMake/install/FILES-EXCLUDE_FROM_ALL-uns-check.cmake1
-rw-r--r--Tests/RunCMake/install/FILES-EXCLUDE_FROM_ALL.cmake3
-rw-r--r--Tests/RunCMake/install/FILES-EXTRA_ISPC_TARGET_OBJECTS-all-check.cmake11
-rw-r--r--Tests/RunCMake/install/FILES-EXTRA_ISPC_TARGET_OBJECTS.cmake4
-rw-r--r--Tests/RunCMake/install/FILES-OPTIONAL-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/FILES-OPTIONAL.cmake1
-rw-r--r--Tests/RunCMake/install/FILES-PERMISSIONS-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/FILES-PERMISSIONS.cmake5
-rw-r--r--Tests/RunCMake/install/FILES-RENAME-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/FILES-RENAME-bad-result.txt1
-rw-r--r--Tests/RunCMake/install/FILES-RENAME-bad-stderr.txt6
-rw-r--r--Tests/RunCMake/install/FILES-RENAME-bad.cmake4
-rw-r--r--Tests/RunCMake/install/FILES-RENAME.cmake4
-rw-r--r--Tests/RunCMake/install/FILES-TARGET_OBJECTS-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/FILES-TARGET_OBJECTS.cmake3
-rw-r--r--Tests/RunCMake/install/FILES-TYPE-Cache-all-check.cmake29
-rw-r--r--Tests/RunCMake/install/FILES-TYPE-Cache.cmake13
-rw-r--r--Tests/RunCMake/install/FILES-TYPE-CacheDependent-all-check.cmake17
-rw-r--r--Tests/RunCMake/install/FILES-TYPE-CacheDependent.cmake7
-rw-r--r--Tests/RunCMake/install/FILES-TYPE-all-check.cmake29
-rw-r--r--Tests/RunCMake/install/FILES-TYPE.cmake13
-rw-r--r--Tests/RunCMake/install/InstallRequiredSystemLibraries-stderr.txt1
-rw-r--r--Tests/RunCMake/install/InstallRequiredSystemLibraries.cmake10
-rw-r--r--Tests/RunCMake/install/PRE_POST_INSTALL_SCRIPT-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/PRE_POST_INSTALL_SCRIPT.cmake7
-rw-r--r--Tests/RunCMake/install/RunCMakeTest.cmake177
-rw-r--r--Tests/RunCMake/install/SCRIPT-COMPONENT-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/SCRIPT-COMPONENT-dev-check.cmake1
-rw-r--r--Tests/RunCMake/install/SCRIPT-COMPONENT-uns-check.cmake1
-rw-r--r--Tests/RunCMake/install/SCRIPT-COMPONENT.cmake5
-rw-r--r--Tests/RunCMake/install/SCRIPT-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/SCRIPT.cmake4
-rw-r--r--Tests/RunCMake/install/SkipInstallRulesNoWarning1-check.cmake9
-rw-r--r--Tests/RunCMake/install/SkipInstallRulesNoWarning1.cmake1
-rw-r--r--Tests/RunCMake/install/SkipInstallRulesNoWarning2-check.cmake9
-rw-r--r--Tests/RunCMake/install/SkipInstallRulesNoWarning2.cmake1
-rw-r--r--Tests/RunCMake/install/SkipInstallRulesWarning-check.cmake9
-rw-r--r--Tests/RunCMake/install/SkipInstallRulesWarning-stderr.txt3
-rw-r--r--Tests/RunCMake/install/SkipInstallRulesWarning.cmake2
-rw-r--r--Tests/RunCMake/install/TARGETS-Apple-Defaults-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-Apple-Defaults-stderr.txt12
-rw-r--r--Tests/RunCMake/install/TARGETS-Apple-Defaults.cmake8
-rw-r--r--Tests/RunCMake/install/TARGETS-CONFIGURATIONS-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/TARGETS-CONFIGURATIONS.cmake2
-rw-r--r--Tests/RunCMake/install/TARGETS-DESTINATION-bad-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-DESTINATION-bad-stderr.txt6
-rw-r--r--Tests/RunCMake/install/TARGETS-DESTINATION-bad.cmake3
-rw-r--r--Tests/RunCMake/install/TARGETS-Defaults-Cache-all-check.cmake46
-rw-r--r--Tests/RunCMake/install/TARGETS-Defaults-Cache-stderr.txt2
-rw-r--r--Tests/RunCMake/install/TARGETS-Defaults-Cache.cmake20
-rw-r--r--Tests/RunCMake/install/TARGETS-Defaults-all-check.cmake52
-rw-r--r--Tests/RunCMake/install/TARGETS-Defaults-stderr.txt2
-rw-r--r--Tests/RunCMake/install/TARGETS-Defaults.cmake28
-rw-r--r--Tests/RunCMake/install/TARGETS-EXCLUDE_FROM_ALL-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/TARGETS-EXCLUDE_FROM_ALL-exc-check.cmake1
-rw-r--r--Tests/RunCMake/install/TARGETS-EXCLUDE_FROM_ALL-uns-check.cmake1
-rw-r--r--Tests/RunCMake/install/TARGETS-EXCLUDE_FROM_ALL.cmake5
-rw-r--r--Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-check-common.cmake32
-rw-r--r--Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-check.cmake63
-rw-r--r--Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-stderr.txt23
-rw-r--r--Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath.cmake72
-rw-r--r--Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-old_rpath-check.cmake15
-rw-r--r--Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-old_rpath.cmake18
-rw-r--r--Tests/RunCMake/install/TARGETS-ImportedGlobal-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-ImportedGlobal-stderr.txt4
-rw-r--r--Tests/RunCMake/install/TARGETS-ImportedGlobal.cmake3
-rw-r--r--Tests/RunCMake/install/TARGETS-InstallFromSubDir-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/TARGETS-InstallFromSubDir.cmake4
-rw-r--r--Tests/RunCMake/install/TARGETS-InstallFromSubDir/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-all-check.cmake73
-rw-r--r--Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-all-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-all-stderr.txt5
-rw-r--r--Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-all.cmake9
-rw-r--r--Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-exc-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-exc-stderr.txt5
-rw-r--r--Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-exc.cmake10
-rw-r--r--Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-dev-check.cmake11
-rw-r--r--Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-lib-check.cmake50
-rw-r--r--Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-uns-check.cmake38
-rw-r--r--Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT.cmake68
-rw-r--r--Tests/RunCMake/install/TARGETS-OPTIONAL-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/TARGETS-OPTIONAL.cmake4
-rw-r--r--Tests/RunCMake/install/TARGETS-OUTPUT_NAME-all-check.cmake13
-rw-r--r--Tests/RunCMake/install/TARGETS-OUTPUT_NAME.cmake27
-rw-r--r--Tests/RunCMake/install/TARGETS-Parts-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/TARGETS-Parts.cmake7
-rw-r--r--Tests/RunCMake/install/TARGETS-RPATH-all-check.cmake14
-rw-r--r--Tests/RunCMake/install/TARGETS-RPATH.cmake14
-rw-r--r--Tests/RunCMake/install/dir/empty.txt0
-rw-r--r--Tests/RunCMake/install/empty.c0
-rw-r--r--Tests/RunCMake/install/install_script.cmake5
-rw-r--r--Tests/RunCMake/install/main.c4
-rw-r--r--Tests/RunCMake/install/obj1.c7
-rw-r--r--Tests/RunCMake/install/obj1.h6
-rw-r--r--Tests/RunCMake/install/obj1.ispc4
-rw-r--r--Tests/RunCMake/install/obj2.c4
-rw-r--r--Tests/RunCMake/install/obj2.h6
-rw-r--r--Tests/RunCMake/install/obj2.ispc4
-rw-r--r--Tests/RunCMake/install/obj3.c7
-rw-r--r--Tests/RunCMake/install/obj3.h6
-rw-r--r--Tests/RunCMake/install/obj4.c7
-rw-r--r--Tests/RunCMake/install/obj4.h6
-rw-r--r--Tests/RunCMake/install/obj5.c7
-rw-r--r--Tests/RunCMake/install/obj5.h6
-rw-r--r--Tests/RunCMake/install/pattern/empty.c0
-rw-r--r--Tests/RunCMake/install/pattern/empty.h0
-rw-r--r--Tests/RunCMake/install/pattern/empty.txt0
-rw-r--r--Tests/RunCMake/install/postinstall.cmake1
-rw-r--r--Tests/RunCMake/install/preinstall.cmake1
-rwxr-xr-xTests/RunCMake/install/script2
-rwxr-xr-xTests/RunCMake/install/script.bat1
-rw-r--r--Tests/RunCMake/install/testobj1.c9
-rw-r--r--Tests/RunCMake/list/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/list/EmptyFilterRegex-result.txt1
-rw-r--r--Tests/RunCMake/list/EmptyFilterRegex-stderr.txt0
-rw-r--r--Tests/RunCMake/list/EmptyFilterRegex.cmake2
-rw-r--r--Tests/RunCMake/list/EmptyGet0-result.txt1
-rw-r--r--Tests/RunCMake/list/EmptyGet0-stderr.txt4
-rw-r--r--Tests/RunCMake/list/EmptyGet0.cmake2
-rw-r--r--Tests/RunCMake/list/EmptyInsert-1-result.txt1
-rw-r--r--Tests/RunCMake/list/EmptyInsert-1-stderr.txt4
-rw-r--r--Tests/RunCMake/list/EmptyInsert-1.cmake2
-rw-r--r--Tests/RunCMake/list/EmptyRemoveAt0-result.txt1
-rw-r--r--Tests/RunCMake/list/EmptyRemoveAt0-stderr.txt4
-rw-r--r--Tests/RunCMake/list/EmptyRemoveAt0.cmake2
-rw-r--r--Tests/RunCMake/list/FILTER-NotList.cmake6
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-InvalidMode-result.txt1
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-InvalidMode-stderr.txt4
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-InvalidMode.cmake2
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-InvalidOperator-result.txt1
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-InvalidOperator-stderr.txt4
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-InvalidOperator.cmake2
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-InvalidRegex-result.txt1
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-InvalidRegex-stderr.txt4
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-InvalidRegex.cmake2
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-TooManyArguments.cmake2
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-Valid0-result.txt1
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-Valid0-stderr.txt2
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-Valid0.cmake4
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-Valid1-result.txt1
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-Valid1-stderr.txt2
-rw-r--r--Tests/RunCMake/list/FILTER-REGEX-Valid1.cmake4
-rw-r--r--Tests/RunCMake/list/GET-CMP0007-WARN-stderr.txt17
-rw-r--r--Tests/RunCMake/list/GET-CMP0007-WARN.cmake7
-rw-r--r--Tests/RunCMake/list/GET-InvalidIndex-result.txt1
-rw-r--r--Tests/RunCMake/list/GET-InvalidIndex-stderr.txt4
-rw-r--r--Tests/RunCMake/list/GET-InvalidIndex.cmake2
-rw-r--r--Tests/RunCMake/list/INSERT-InvalidIndex-result.txt1
-rw-r--r--Tests/RunCMake/list/INSERT-InvalidIndex-stderr.txt4
-rw-r--r--Tests/RunCMake/list/INSERT-InvalidIndex.cmake2
-rw-r--r--Tests/RunCMake/list/InvalidSubcommand-result.txt1
-rw-r--r--Tests/RunCMake/list/InvalidSubcommand-stderr.txt4
-rw-r--r--Tests/RunCMake/list/InvalidSubcommand.cmake1
-rw-r--r--Tests/RunCMake/list/JOIN-NoArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/JOIN-NoArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/JOIN-NoArguments.cmake1
-rw-r--r--Tests/RunCMake/list/JOIN-NoVariable-result.txt1
-rw-r--r--Tests/RunCMake/list/JOIN-NoVariable-stderr.txt4
-rw-r--r--Tests/RunCMake/list/JOIN-NoVariable.cmake1
-rw-r--r--Tests/RunCMake/list/JOIN-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/JOIN-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/JOIN-TooManyArguments.cmake1
-rw-r--r--Tests/RunCMake/list/JOIN.cmake18
-rw-r--r--Tests/RunCMake/list/LENGTH-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/LENGTH-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/LENGTH-TooManyArguments.cmake1
-rw-r--r--Tests/RunCMake/list/NoArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/NoArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/NoArguments.cmake1
-rw-r--r--Tests/RunCMake/list/POP_BACK-NoArgs-result.txt1
-rw-r--r--Tests/RunCMake/list/POP_BACK-NoArgs-stderr.txt1
-rw-r--r--Tests/RunCMake/list/POP_BACK-NoArgs.cmake1
-rw-r--r--Tests/RunCMake/list/POP_BACK.cmake79
-rw-r--r--Tests/RunCMake/list/POP_FRONT-NoArgs-result.txt1
-rw-r--r--Tests/RunCMake/list/POP_FRONT-NoArgs-stderr.txt1
-rw-r--r--Tests/RunCMake/list/POP_FRONT-NoArgs.cmake1
-rw-r--r--Tests/RunCMake/list/POP_FRONT.cmake92
-rw-r--r--Tests/RunCMake/list/PREPEND-NoArgs-result.txt1
-rw-r--r--Tests/RunCMake/list/PREPEND-NoArgs-stderr.txt1
-rw-r--r--Tests/RunCMake/list/PREPEND-NoArgs.cmake1
-rw-r--r--Tests/RunCMake/list/PREPEND.cmake33
-rw-r--r--Tests/RunCMake/list/REMOVE_AT-EmptyList-result.txt1
-rw-r--r--Tests/RunCMake/list/REMOVE_AT-EmptyList-stderr.txt4
-rw-r--r--Tests/RunCMake/list/REMOVE_AT-EmptyList.cmake6
-rw-r--r--Tests/RunCMake/list/REMOVE_AT-InvalidIndex-result.txt1
-rw-r--r--Tests/RunCMake/list/REMOVE_AT-InvalidIndex-stderr.txt4
-rw-r--r--Tests/RunCMake/list/REMOVE_AT-InvalidIndex.cmake2
-rw-r--r--Tests/RunCMake/list/REMOVE_AT-NotList-result.txt1
-rw-r--r--Tests/RunCMake/list/REMOVE_AT-NotList-stderr.txt4
-rw-r--r--Tests/RunCMake/list/REMOVE_AT-NotList.cmake6
-rw-r--r--Tests/RunCMake/list/REMOVE_DUPLICATES-NotList.cmake6
-rw-r--r--Tests/RunCMake/list/REMOVE_DUPLICATES-PreserveOrder.cmake5
-rw-r--r--Tests/RunCMake/list/REMOVE_DUPLICATES-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/REMOVE_DUPLICATES-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/REMOVE_DUPLICATES-TooManyArguments.cmake1
-rw-r--r--Tests/RunCMake/list/REMOVE_ITEM-NoItemArg.cmake5
-rw-r--r--Tests/RunCMake/list/REMOVE_ITEM-NotList.cmake6
-rw-r--r--Tests/RunCMake/list/REVERSE-NotList.cmake6
-rw-r--r--Tests/RunCMake/list/REVERSE-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/REVERSE-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/REVERSE-TooManyArguments.cmake1
-rw-r--r--Tests/RunCMake/list/RunCMakeTest.cmake115
-rw-r--r--Tests/RunCMake/list/SORT-BadCaseOption-result.txt1
-rw-r--r--Tests/RunCMake/list/SORT-BadCaseOption-stderr.txt4
-rw-r--r--Tests/RunCMake/list/SORT-BadCaseOption.cmake1
-rw-r--r--Tests/RunCMake/list/SORT-BadCompareOption-result.txt1
-rw-r--r--Tests/RunCMake/list/SORT-BadCompareOption-stderr.txt5
-rw-r--r--Tests/RunCMake/list/SORT-BadCompareOption.cmake1
-rw-r--r--Tests/RunCMake/list/SORT-BadOrderOption-result.txt1
-rw-r--r--Tests/RunCMake/list/SORT-BadOrderOption-stderr.txt5
-rw-r--r--Tests/RunCMake/list/SORT-BadOrderOption.cmake1
-rw-r--r--Tests/RunCMake/list/SORT-DuplicateCaseOption-result.txt1
-rw-r--r--Tests/RunCMake/list/SORT-DuplicateCaseOption-stderr.txt4
-rw-r--r--Tests/RunCMake/list/SORT-DuplicateCaseOption.cmake2
-rw-r--r--Tests/RunCMake/list/SORT-DuplicateCompareOption-result.txt1
-rw-r--r--Tests/RunCMake/list/SORT-DuplicateCompareOption-stderr.txt4
-rw-r--r--Tests/RunCMake/list/SORT-DuplicateCompareOption.cmake2
-rw-r--r--Tests/RunCMake/list/SORT-DuplicateOrderOption-result.txt1
-rw-r--r--Tests/RunCMake/list/SORT-DuplicateOrderOption-stderr.txt4
-rw-r--r--Tests/RunCMake/list/SORT-DuplicateOrderOption.cmake2
-rw-r--r--Tests/RunCMake/list/SORT-NoCaseOption-result.txt1
-rw-r--r--Tests/RunCMake/list/SORT-NoCaseOption-stderr.txt4
-rw-r--r--Tests/RunCMake/list/SORT-NoCaseOption.cmake1
-rw-r--r--Tests/RunCMake/list/SORT-NotList.cmake6
-rw-r--r--Tests/RunCMake/list/SORT-WrongOption-result.txt1
-rw-r--r--Tests/RunCMake/list/SORT-WrongOption-stderr.txt4
-rw-r--r--Tests/RunCMake/list/SORT-WrongOption.cmake1
-rw-r--r--Tests/RunCMake/list/SORT.cmake114
-rw-r--r--Tests/RunCMake/list/SUBLIST-InvalidIndex-result.txt1
-rw-r--r--Tests/RunCMake/list/SUBLIST-InvalidIndex-stderr.txt4
-rw-r--r--Tests/RunCMake/list/SUBLIST-InvalidIndex.cmake2
-rw-r--r--Tests/RunCMake/list/SUBLIST-InvalidLength-result.txt1
-rw-r--r--Tests/RunCMake/list/SUBLIST-InvalidLength-stderr.txt4
-rw-r--r--Tests/RunCMake/list/SUBLIST-InvalidLength.cmake2
-rw-r--r--Tests/RunCMake/list/SUBLIST-NoArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/SUBLIST-NoArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/SUBLIST-NoArguments.cmake1
-rw-r--r--Tests/RunCMake/list/SUBLIST-NoVariable-result.txt1
-rw-r--r--Tests/RunCMake/list/SUBLIST-NoVariable-stderr.txt4
-rw-r--r--Tests/RunCMake/list/SUBLIST-NoVariable.cmake2
-rw-r--r--Tests/RunCMake/list/SUBLIST-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/SUBLIST-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/SUBLIST-TooManyArguments.cmake1
-rw-r--r--Tests/RunCMake/list/SUBLIST.cmake46
-rw-r--r--Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-APPEND.cmake48
-rw-r--r--Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-GENEX_STRIP.cmake49
-rw-r--r--Tests/RunCMake/list/TRANSFORM-InvalidAction-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-InvalidAction-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-InvalidAction.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-NoAction-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-NoAction-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-NoAction.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-PREPEND.cmake48
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex-stderr.txt5
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1-stderr.txt5
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2-stderr.txt5
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-REPLACE.cmake48
-rw-r--r--Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-STRIP.cmake49
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument-stderr.txt5
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex-stderr.txt5
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments-stderr.txt5
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-TOLOWER.cmake48
-rw-r--r--Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments.cmake2
-rw-r--r--Tests/RunCMake/list/TRANSFORM-TOUPPER.cmake48
-rw-r--r--Tests/RunCMake/load_cache/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/load_cache/NewForm_Project.cmake16
-rw-r--r--Tests/RunCMake/load_cache/NewForm_Script.cmake16
-rw-r--r--Tests/RunCMake/load_cache/OldForm_Script-result.txt1
-rw-r--r--Tests/RunCMake/load_cache/OldForm_Script-stderr.txt2
-rw-r--r--Tests/RunCMake/load_cache/OldForm_Script.cmake13
-rw-r--r--Tests/RunCMake/load_cache/RunCMakeTest.cmake13
-rw-r--r--Tests/RunCMake/math/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/math/MATH-DivideByZero-result.txt1
-rw-r--r--Tests/RunCMake/math/MATH-DivideByZero-stderr.txt4
-rw-r--r--Tests/RunCMake/math/MATH-DivideByZero.cmake1
-rw-r--r--Tests/RunCMake/math/MATH-DoubleOption-result.txt1
-rw-r--r--Tests/RunCMake/math/MATH-DoubleOption-stderr.txt4
-rw-r--r--Tests/RunCMake/math/MATH-DoubleOption.cmake1
-rw-r--r--Tests/RunCMake/math/MATH-InvalidExpression-result.txt1
-rw-r--r--Tests/RunCMake/math/MATH-InvalidExpression-stderr.txt5
-rw-r--r--Tests/RunCMake/math/MATH-InvalidExpression.cmake1
-rw-r--r--Tests/RunCMake/math/MATH-ToleratedExpression-stderr.txt8
-rw-r--r--Tests/RunCMake/math/MATH-ToleratedExpression.cmake4
-rw-r--r--Tests/RunCMake/math/MATH-TooManyArguments-result.txt1
-rw-r--r--Tests/RunCMake/math/MATH-TooManyArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/math/MATH-TooManyArguments.cmake1
-rw-r--r--Tests/RunCMake/math/MATH-WrongArgument-result.txt1
-rw-r--r--Tests/RunCMake/math/MATH-WrongArgument-stderr.txt4
-rw-r--r--Tests/RunCMake/math/MATH-WrongArgument.cmake1
-rw-r--r--Tests/RunCMake/math/MATH.cmake12
-rw-r--r--Tests/RunCMake/math/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/message/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/message/RunCMakeTest.cmake99
-rw-r--r--Tests/RunCMake/message/defaultmessage-result.txt1
-rw-r--r--Tests/RunCMake/message/defaultmessage-stderr.txt11
-rw-r--r--Tests/RunCMake/message/defaultmessage.cmake4
-rw-r--r--Tests/RunCMake/message/errormessage_deprecated-result.txt1
-rw-r--r--Tests/RunCMake/message/errormessage_deprecated-stderr.txt4
-rw-r--r--Tests/RunCMake/message/errormessage_deprecated.cmake3
-rw-r--r--Tests/RunCMake/message/errormessage_dev-result.txt1
-rw-r--r--Tests/RunCMake/message/errormessage_dev-stderr.txt5
-rw-r--r--Tests/RunCMake/message/errormessage_dev.cmake3
-rw-r--r--Tests/RunCMake/message/message-all-loglevels.cmake10
-rw-r--r--Tests/RunCMake/message/message-checks-stderr.txt3
-rw-r--r--Tests/RunCMake/message/message-checks-stdout.txt10
-rw-r--r--Tests/RunCMake/message/message-checks.cmake13
-rw-r--r--Tests/RunCMake/message/message-context-cache-stdout.txt8
-rw-r--r--Tests/RunCMake/message/message-context-cli-stdout.txt8
-rw-r--r--Tests/RunCMake/message/message-context-cli-wins-cache-stdout.txt5
-rw-r--r--Tests/RunCMake/message/message-context.cmake27
-rw-r--r--Tests/RunCMake/message/message-indent-multiline-stderr.txt3
-rw-r--r--Tests/RunCMake/message/message-indent-multiline-stdout.txt8
-rw-r--r--Tests/RunCMake/message/message-indent-multiline.cmake13
-rw-r--r--Tests/RunCMake/message/message-indent-stdout.txt13
-rw-r--r--Tests/RunCMake/message/message-indent.cmake19
-rw-r--r--Tests/RunCMake/message/message-internal-warning-stderr.txt13
-rw-r--r--Tests/RunCMake/message/message-internal-warning.cmake5
-rw-r--r--Tests/RunCMake/message/message-log-level-debug-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-log-level-debug-stdout.txt3
-rw-r--r--Tests/RunCMake/message/message-log-level-default-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-log-level-default-stdout.txt1
-rw-r--r--Tests/RunCMake/message/message-log-level-invalid-result.txt1
-rw-r--r--Tests/RunCMake/message/message-log-level-invalid-stderr.txt1
-rw-r--r--Tests/RunCMake/message/message-log-level-notice-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-log-level-override-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-log-level-override-stdout.txt3
-rw-r--r--Tests/RunCMake/message/message-log-level-status-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-log-level-status-stdout.txt1
-rw-r--r--Tests/RunCMake/message/message-log-level-trace-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-log-level-trace-stdout.txt4
-rw-r--r--Tests/RunCMake/message/message-log-level-verbose-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-log-level-verbose-stdout.txt2
-rw-r--r--Tests/RunCMake/message/message-log-level-warning-stderr.txt9
-rw-r--r--Tests/RunCMake/message/message-loglevel-debug-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-loglevel-debug-stdout.txt3
-rw-r--r--Tests/RunCMake/message/message-loglevel-default-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-loglevel-default-stdout.txt1
-rw-r--r--Tests/RunCMake/message/message-loglevel-invalid-result.txt1
-rw-r--r--Tests/RunCMake/message/message-loglevel-invalid-stderr.txt1
-rw-r--r--Tests/RunCMake/message/message-loglevel-notice-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-loglevel-status-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-loglevel-status-stdout.txt1
-rw-r--r--Tests/RunCMake/message/message-loglevel-trace-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-loglevel-trace-stdout.txt4
-rw-r--r--Tests/RunCMake/message/message-loglevel-verbose-stderr.txt12
-rw-r--r--Tests/RunCMake/message/message-loglevel-verbose-stdout.txt2
-rw-r--r--Tests/RunCMake/message/message-loglevel-warning-stderr.txt9
-rw-r--r--Tests/RunCMake/message/nomessage-internal-warning-stderr.txt0
-rw-r--r--Tests/RunCMake/message/nomessage-internal-warning.cmake5
-rw-r--r--Tests/RunCMake/message/nomessage-result.txt1
-rw-r--r--Tests/RunCMake/message/nomessage.cmake8
-rw-r--r--Tests/RunCMake/message/warnmessage-result.txt1
-rw-r--r--Tests/RunCMake/message/warnmessage-rootdir-stderr.txt1
-rw-r--r--Tests/RunCMake/message/warnmessage-rootdir.cmake5
-rw-r--r--Tests/RunCMake/message/warnmessage-stderr.txt11
-rw-r--r--Tests/RunCMake/message/warnmessage.cmake8
-rw-r--r--Tests/RunCMake/no_install_prefix/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/no_install_prefix/RunCMakeTest.cmake15
-rw-r--r--Tests/RunCMake/no_install_prefix/do_test.cmake2
-rw-r--r--Tests/RunCMake/no_install_prefix/no_install_prefix-result.txt1
-rw-r--r--Tests/RunCMake/no_install_prefix/no_install_prefix-stderr.txt18
-rw-r--r--Tests/RunCMake/no_install_prefix/no_install_prefix.cmake2
-rw-r--r--Tests/RunCMake/no_install_prefix/with_install_prefix-result.txt1
-rw-r--r--Tests/RunCMake/no_install_prefix/with_install_prefix.cmake2
-rw-r--r--Tests/RunCMake/option/CMP0077-NEW.cmake14
-rw-r--r--Tests/RunCMake/option/CMP0077-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/option/CMP0077-OLD.cmake9
-rw-r--r--Tests/RunCMake/option/CMP0077-SECOND-PASS.cmake14
-rw-r--r--Tests/RunCMake/option/CMP0077-WARN-stderr.txt7
-rw-r--r--Tests/RunCMake/option/CMP0077-WARN.cmake5
-rw-r--r--Tests/RunCMake/option/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/option/RunCMakeTest.cmake6
-rw-r--r--Tests/RunCMake/print_stdin.c18
-rw-r--r--Tests/RunCMake/project/CMP0048-NEW-stdout.txt30
-rw-r--r--Tests/RunCMake/project/CMP0048-NEW.cmake14
-rw-r--r--Tests/RunCMake/project/CMP0048-OLD-VERSION-result.txt1
-rw-r--r--Tests/RunCMake/project/CMP0048-OLD-VERSION-stderr.txt4
-rw-r--r--Tests/RunCMake/project/CMP0048-OLD-VERSION.cmake2
-rw-r--r--Tests/RunCMake/project/CMP0048-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/project/CMP0048-OLD-stdout.txt2
-rw-r--r--Tests/RunCMake/project/CMP0048-OLD.cmake6
-rw-r--r--Tests/RunCMake/project/CMP0048-WARN-stderr.txt12
-rw-r--r--Tests/RunCMake/project/CMP0048-WARN.cmake3
-rw-r--r--Tests/RunCMake/project/CMP0096-NEW-stdout.txt30
-rw-r--r--Tests/RunCMake/project/CMP0096-NEW.cmake6
-rw-r--r--Tests/RunCMake/project/CMP0096-OLD-stdout.txt20
-rw-r--r--Tests/RunCMake/project/CMP0096-OLD.cmake3
-rw-r--r--Tests/RunCMake/project/CMP0096-WARN-stdout.txt20
-rw-r--r--Tests/RunCMake/project/CMP0096-WARN.cmake3
-rw-r--r--Tests/RunCMake/project/CMP0096-common.cmake9
-rw-r--r--Tests/RunCMake/project/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/project/ExplicitRC.cmake1
-rw-r--r--Tests/RunCMake/project/LanguagesEmpty-stdout.txt1
-rw-r--r--Tests/RunCMake/project/LanguagesEmpty.cmake3
-rw-r--r--Tests/RunCMake/project/LanguagesImplicit-stdout.txt1
-rw-r--r--Tests/RunCMake/project/LanguagesImplicit.cmake3
-rw-r--r--Tests/RunCMake/project/LanguagesNONE-stdout.txt1
-rw-r--r--Tests/RunCMake/project/LanguagesNONE.cmake3
-rw-r--r--Tests/RunCMake/project/LanguagesTwice-result.txt1
-rw-r--r--Tests/RunCMake/project/LanguagesTwice-stderr.txt4
-rw-r--r--Tests/RunCMake/project/LanguagesTwice.cmake2
-rw-r--r--Tests/RunCMake/project/LanguagesUnordered-stderr.txt1
-rw-r--r--Tests/RunCMake/project/LanguagesUnordered.cmake1
-rw-r--r--Tests/RunCMake/project/PrintVersions.cmake6
-rw-r--r--Tests/RunCMake/project/ProjectDescription-stdout.txt1
-rw-r--r--Tests/RunCMake/project/ProjectDescription.cmake6
-rw-r--r--Tests/RunCMake/project/ProjectDescription2-result.txt1
-rw-r--r--Tests/RunCMake/project/ProjectDescription2-stderr.txt1
-rw-r--r--Tests/RunCMake/project/ProjectDescription2.cmake2
-rw-r--r--Tests/RunCMake/project/ProjectDescriptionNoArg-stderr.txt2
-rw-r--r--Tests/RunCMake/project/ProjectDescriptionNoArg.cmake2
-rw-r--r--Tests/RunCMake/project/ProjectDescriptionNoArg2-stderr.txt2
-rw-r--r--Tests/RunCMake/project/ProjectDescriptionNoArg2.cmake2
-rw-r--r--Tests/RunCMake/project/ProjectHomepage-stdout.txt3
-rw-r--r--Tests/RunCMake/project/ProjectHomepage.cmake14
-rw-r--r--Tests/RunCMake/project/ProjectHomepage2-result.txt1
-rw-r--r--Tests/RunCMake/project/ProjectHomepage2-stderr.txt4
-rw-r--r--Tests/RunCMake/project/ProjectHomepage2.cmake2
-rw-r--r--Tests/RunCMake/project/ProjectHomepageNoArg-stderr.txt5
-rw-r--r--Tests/RunCMake/project/ProjectHomepageNoArg.cmake2
-rw-r--r--Tests/RunCMake/project/ProjectIsTopLevel-stdout.txt2
-rw-r--r--Tests/RunCMake/project/ProjectIsTopLevel.cmake9
-rw-r--r--Tests/RunCMake/project/ProjectIsTopLevelMultiple-stdout.txt3
-rw-r--r--Tests/RunCMake/project/ProjectIsTopLevelMultiple.cmake14
-rw-r--r--Tests/RunCMake/project/ProjectIsTopLevelSubdirectory-stdout.txt6
-rw-r--r--Tests/RunCMake/project/ProjectIsTopLevelSubdirectory.cmake8
-rw-r--r--Tests/RunCMake/project/ProjectIsTopLevelSubdirectory/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/project/ProjectTwice.cmake26
-rw-r--r--Tests/RunCMake/project/RunCMakeTest.cmake37
-rw-r--r--Tests/RunCMake/project/VersionAndLanguagesEmpty-stdout.txt2
-rw-r--r--Tests/RunCMake/project/VersionAndLanguagesEmpty.cmake5
-rw-r--r--Tests/RunCMake/project/VersionEmpty-stdout.txt2
-rw-r--r--Tests/RunCMake/project/VersionEmpty.cmake6
-rw-r--r--Tests/RunCMake/project/VersionInvalid-result.txt1
-rw-r--r--Tests/RunCMake/project/VersionInvalid-stderr.txt4
-rw-r--r--Tests/RunCMake/project/VersionInvalid.cmake3
-rw-r--r--Tests/RunCMake/project/VersionMax.cmake32
-rw-r--r--Tests/RunCMake/project/VersionMissingLanguages-result.txt1
-rw-r--r--Tests/RunCMake/project/VersionMissingLanguages-stderr.txt5
-rw-r--r--Tests/RunCMake/project/VersionMissingLanguages.cmake3
-rw-r--r--Tests/RunCMake/project/VersionMissingValueOkay-stderr.txt2
-rw-r--r--Tests/RunCMake/project/VersionMissingValueOkay-stdout.txt2
-rw-r--r--Tests/RunCMake/project/VersionMissingValueOkay.cmake6
-rw-r--r--Tests/RunCMake/project/VersionTwice-result.txt1
-rw-r--r--Tests/RunCMake/project/VersionTwice-stderr.txt4
-rw-r--r--Tests/RunCMake/project/VersionTwice.cmake3
-rw-r--r--Tests/RunCMake/project_injected/CMP0048-WARN-stderr.txt12
-rw-r--r--Tests/RunCMake/project_injected/CMP0048-WARN.cmake0
-rw-r--r--Tests/RunCMake/project_injected/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/project_injected/RunCMakeTest.cmake12
-rw-r--r--Tests/RunCMake/pseudo_cppcheck.c40
-rw-r--r--Tests/RunCMake/pseudo_cpplint.c21
-rw-r--r--Tests/RunCMake/pseudo_emulator.c14
-rw-r--r--Tests/RunCMake/pseudo_emulator_custom_command.c32
-rw-r--r--Tests/RunCMake/pseudo_emulator_custom_command_arg.c30
-rw-r--r--Tests/RunCMake/pseudo_iwyu.c8
-rw-r--r--Tests/RunCMake/pseudo_llvm-rc.c30
-rw-r--r--Tests/RunCMake/pseudo_tidy.c20
-rw-r--r--Tests/RunCMake/return/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/return/ReturnFromForeach-result.txt1
-rw-r--r--Tests/RunCMake/return/ReturnFromForeach.cmake10
-rw-r--r--Tests/RunCMake/return/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/separate_arguments/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/separate_arguments/EmptyCommand.cmake6
-rw-r--r--Tests/RunCMake/separate_arguments/MultipleArguments-result.txt1
-rw-r--r--Tests/RunCMake/separate_arguments/MultipleArguments-stderr.txt4
-rw-r--r--Tests/RunCMake/separate_arguments/MultipleArguments.cmake2
-rw-r--r--Tests/RunCMake/separate_arguments/MultipleCommands-result.txt1
-rw-r--r--Tests/RunCMake/separate_arguments/MultipleCommands-stderr.txt19
-rw-r--r--Tests/RunCMake/separate_arguments/MultipleCommands.cmake6
-rw-r--r--Tests/RunCMake/separate_arguments/NativeCommand.cmake24
-rw-r--r--Tests/RunCMake/separate_arguments/PlainCommand.cmake8
-rw-r--r--Tests/RunCMake/separate_arguments/ProgramCommand.cmake48
-rw-r--r--Tests/RunCMake/separate_arguments/ProgramCommandWithSeparateArgs.cmake28
-rw-r--r--Tests/RunCMake/separate_arguments/ProgramOnly-result.txt1
-rw-r--r--Tests/RunCMake/separate_arguments/ProgramOnly-stderr.txt5
-rw-r--r--Tests/RunCMake/separate_arguments/ProgramOnly.cmake2
-rw-r--r--Tests/RunCMake/separate_arguments/RunCMakeTest.cmake15
-rw-r--r--Tests/RunCMake/separate_arguments/SeparateArgsOnly-result.txt1
-rw-r--r--Tests/RunCMake/separate_arguments/SeparateArgsOnly-stderr.txt4
-rw-r--r--Tests/RunCMake/separate_arguments/SeparateArgsOnly.cmake2
-rw-r--r--Tests/RunCMake/separate_arguments/UnixCommand.cmake13
-rw-r--r--Tests/RunCMake/separate_arguments/WindowsCommand.cmake13
-rw-r--r--Tests/RunCMake/set/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/set/ExtraEnvValue-stderr.txt6
-rw-r--r--Tests/RunCMake/set/ExtraEnvValue.cmake1
-rw-r--r--Tests/RunCMake/set/ParentPulling-stderr.txt3
-rw-r--r--Tests/RunCMake/set/ParentPulling.cmake13
-rw-r--r--Tests/RunCMake/set/ParentPullingRecursive-stderr.txt144
-rw-r--r--Tests/RunCMake/set/ParentPullingRecursive.cmake104
-rw-r--r--Tests/RunCMake/set/ParentScope-result.txt1
-rw-r--r--Tests/RunCMake/set/ParentScope.cmake33
-rw-r--r--Tests/RunCMake/set/RunCMakeTest.cmake7
-rw-r--r--Tests/RunCMake/set/UnknownCacheType-stderr.txt5
-rw-r--r--Tests/RunCMake/set/UnknownCacheType.cmake1
-rw-r--r--Tests/RunCMake/set_property/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/set_property/COMPILE_DEFINITIONS-stdout.txt2
-rw-r--r--Tests/RunCMake/set_property/COMPILE_DEFINITIONS.cmake3
-rw-r--r--Tests/RunCMake/set_property/COMPILE_FEATURES-stdout.txt1
-rw-r--r--Tests/RunCMake/set_property/COMPILE_FEATURES.cmake2
-rw-r--r--Tests/RunCMake/set_property/COMPILE_OPTIONS-stdout.txt2
-rw-r--r--Tests/RunCMake/set_property/COMPILE_OPTIONS.cmake3
-rw-r--r--Tests/RunCMake/set_property/Common.cmake28
-rw-r--r--Tests/RunCMake/set_property/IMPORTED_GLOBAL-result.txt1
-rw-r--r--Tests/RunCMake/set_property/IMPORTED_GLOBAL-stderr.txt61
-rw-r--r--Tests/RunCMake/set_property/IMPORTED_GLOBAL-stdout.txt17
-rw-r--r--Tests/RunCMake/set_property/IMPORTED_GLOBAL.cmake53
-rw-r--r--Tests/RunCMake/set_property/IMPORTED_GLOBAL/CMakeLists.txt8
-rw-r--r--Tests/RunCMake/set_property/INCLUDE_DIRECTORIES-stdout.txt2
-rw-r--r--Tests/RunCMake/set_property/INCLUDE_DIRECTORIES.cmake3
-rw-r--r--Tests/RunCMake/set_property/LINK_DIRECTORIES-stdout.txt2
-rw-r--r--Tests/RunCMake/set_property/LINK_DIRECTORIES.cmake3
-rw-r--r--Tests/RunCMake/set_property/LINK_LIBRARIES-stdout.txt1
-rw-r--r--Tests/RunCMake/set_property/LINK_LIBRARIES.cmake2
-rw-r--r--Tests/RunCMake/set_property/LINK_OPTIONS-stdout.txt2
-rw-r--r--Tests/RunCMake/set_property/LINK_OPTIONS.cmake3
-rw-r--r--Tests/RunCMake/set_property/RunCMakeTest.cmake15
-rw-r--r--Tests/RunCMake/set_property/SOURCES-stdout.txt1
-rw-r--r--Tests/RunCMake/set_property/SOURCES.cmake2
-rw-r--r--Tests/RunCMake/set_property/SOURCE_FILE-result.txt1
-rw-r--r--Tests/RunCMake/set_property/SOURCE_FILE-stderr.txt22
-rw-r--r--Tests/RunCMake/set_property/SOURCE_FILE.cmake4
-rw-r--r--Tests/RunCMake/set_property/TYPE-result.txt1
-rw-r--r--Tests/RunCMake/set_property/TYPE-stderr.txt1
-rw-r--r--Tests/RunCMake/set_property/TYPE.cmake2
-rw-r--r--Tests/RunCMake/set_property/USER_PROP-stdout.txt2
-rw-r--r--Tests/RunCMake/set_property/USER_PROP.cmake3
-rw-r--r--Tests/RunCMake/set_property/USER_PROP_INHERITED-stdout.txt29
-rw-r--r--Tests/RunCMake/set_property/USER_PROP_INHERITED.cmake83
-rw-r--r--Tests/RunCMake/set_property/USER_PROP_INHERITED/CMakeLists.txt21
-rw-r--r--Tests/RunCMake/set_property/test.cpp0
-rw-r--r--Tests/RunCMake/string/Append.cmake58
-rw-r--r--Tests/RunCMake/string/AppendNoArgs-result.txt1
-rw-r--r--Tests/RunCMake/string/AppendNoArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/string/AppendNoArgs.cmake1
-rw-r--r--Tests/RunCMake/string/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/string/Concat.cmake19
-rw-r--r--Tests/RunCMake/string/ConcatNoArgs-result.txt1
-rw-r--r--Tests/RunCMake/string/ConcatNoArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/string/ConcatNoArgs.cmake1
-rw-r--r--Tests/RunCMake/string/Hex.cmake20
-rw-r--r--Tests/RunCMake/string/HexNotEnoughArgs-result.txt1
-rw-r--r--Tests/RunCMake/string/HexNotEnoughArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/string/HexNotEnoughArgs.cmake1
-rw-r--r--Tests/RunCMake/string/HexTooManyArgs-result.txt1
-rw-r--r--Tests/RunCMake/string/HexTooManyArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/string/HexTooManyArgs.cmake1
-rw-r--r--Tests/RunCMake/string/JSON.cmake342
-rw-r--r--Tests/RunCMake/string/JSONNoArgs-result.txt1
-rw-r--r--Tests/RunCMake/string/JSONNoArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/string/JSONNoArgs.cmake1
-rw-r--r--Tests/RunCMake/string/JSONNoJson-result.txt1
-rw-r--r--Tests/RunCMake/string/JSONNoJson-stderr.txt4
-rw-r--r--Tests/RunCMake/string/JSONNoJson.cmake1
-rw-r--r--Tests/RunCMake/string/JSONOneArg-result.txt1
-rw-r--r--Tests/RunCMake/string/JSONOneArg-stderr.txt4
-rw-r--r--Tests/RunCMake/string/JSONOneArg.cmake1
-rw-r--r--Tests/RunCMake/string/JSONWrongMode-result.txt1
-rw-r--r--Tests/RunCMake/string/JSONWrongMode-stderr.txt5
-rw-r--r--Tests/RunCMake/string/JSONWrongMode.cmake1
-rw-r--r--Tests/RunCMake/string/Join.cmake16
-rw-r--r--Tests/RunCMake/string/JoinNoArgs-result.txt1
-rw-r--r--Tests/RunCMake/string/JoinNoArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/string/JoinNoArgs.cmake1
-rw-r--r--Tests/RunCMake/string/JoinNoVar-result.txt1
-rw-r--r--Tests/RunCMake/string/JoinNoVar-stderr.txt4
-rw-r--r--Tests/RunCMake/string/JoinNoVar.cmake1
-rw-r--r--Tests/RunCMake/string/Prepend.cmake58
-rw-r--r--Tests/RunCMake/string/PrependNoArgs-result.txt1
-rw-r--r--Tests/RunCMake/string/PrependNoArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/string/PrependNoArgs.cmake1
-rw-r--r--Tests/RunCMake/string/RegexClear-stderr.txt54
-rw-r--r--Tests/RunCMake/string/RegexClear.cmake54
-rw-r--r--Tests/RunCMake/string/RegexMultiMatchClear-stderr.txt12
-rw-r--r--Tests/RunCMake/string/RegexMultiMatchClear.cmake20
-rw-r--r--Tests/RunCMake/string/Repeat.cmake45
-rw-r--r--Tests/RunCMake/string/RepeatNegativeCount-result.txt1
-rw-r--r--Tests/RunCMake/string/RepeatNegativeCount-stderr.txt4
-rw-r--r--Tests/RunCMake/string/RepeatNegativeCount.cmake1
-rw-r--r--Tests/RunCMake/string/RepeatNoArgs-result.txt1
-rw-r--r--Tests/RunCMake/string/RepeatNoArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/string/RepeatNoArgs.cmake1
-rw-r--r--Tests/RunCMake/string/RunCMakeTest.cmake50
-rw-r--r--Tests/RunCMake/string/Timestamp-result.txt1
-rw-r--r--Tests/RunCMake/string/Timestamp-stderr.txt1
-rw-r--r--Tests/RunCMake/string/Timestamp.cmake3
-rw-r--r--Tests/RunCMake/string/TimestampEmpty-result.txt1
-rw-r--r--Tests/RunCMake/string/TimestampEmpty-stderr.txt1
-rw-r--r--Tests/RunCMake/string/TimestampEmpty.cmake3
-rw-r--r--Tests/RunCMake/string/TimestampInvalid-result.txt1
-rw-r--r--Tests/RunCMake/string/TimestampInvalid-stderr.txt1
-rw-r--r--Tests/RunCMake/string/TimestampInvalid.cmake3
-rw-r--r--Tests/RunCMake/string/TimestampInvalid2-result.txt1
-rw-r--r--Tests/RunCMake/string/TimestampInvalid2-stderr.txt1
-rw-r--r--Tests/RunCMake/string/TimestampInvalid2.cmake3
-rw-r--r--Tests/RunCMake/string/UTF-16BE-stderr.txt2
-rw-r--r--Tests/RunCMake/string/UTF-16BE.cmake4
-rw-r--r--Tests/RunCMake/string/UTF-16BE.txtbin0 -> 83 bytes-rw-r--r--Tests/RunCMake/string/UTF-16LE-stderr.txt2
-rw-r--r--Tests/RunCMake/string/UTF-16LE.cmake4
-rw-r--r--Tests/RunCMake/string/UTF-16LE.txtbin0 -> 83 bytes-rw-r--r--Tests/RunCMake/string/UTF-32BE-stderr.txt2
-rw-r--r--Tests/RunCMake/string/UTF-32BE.cmake4
-rw-r--r--Tests/RunCMake/string/UTF-32BE.txtbin0 -> 165 bytes-rw-r--r--Tests/RunCMake/string/UTF-32LE-stderr.txt2
-rw-r--r--Tests/RunCMake/string/UTF-32LE.cmake4
-rw-r--r--Tests/RunCMake/string/UTF-32LE.txtbin0 -> 165 bytes-rw-r--r--Tests/RunCMake/string/Uuid.cmake17
-rw-r--r--Tests/RunCMake/string/UuidBadNamespace-result.txt1
-rw-r--r--Tests/RunCMake/string/UuidBadNamespace-stderr.txt4
-rw-r--r--Tests/RunCMake/string/UuidBadNamespace.cmake4
-rw-r--r--Tests/RunCMake/string/UuidBadType-result.txt1
-rw-r--r--Tests/RunCMake/string/UuidBadType-stderr.txt4
-rw-r--r--Tests/RunCMake/string/UuidBadType.cmake4
-rw-r--r--Tests/RunCMake/string/UuidMissingNameValue-result.txt1
-rw-r--r--Tests/RunCMake/string/UuidMissingNameValue-stderr.txt4
-rw-r--r--Tests/RunCMake/string/UuidMissingNameValue.cmake4
-rw-r--r--Tests/RunCMake/string/UuidMissingNamespace-result.txt1
-rw-r--r--Tests/RunCMake/string/UuidMissingNamespace-stderr.txt4
-rw-r--r--Tests/RunCMake/string/UuidMissingNamespace.cmake4
-rw-r--r--Tests/RunCMake/string/UuidMissingNamespaceValue-result.txt1
-rw-r--r--Tests/RunCMake/string/UuidMissingNamespaceValue-stderr.txt4
-rw-r--r--Tests/RunCMake/string/UuidMissingNamespaceValue.cmake4
-rw-r--r--Tests/RunCMake/string/UuidMissingTypeValue-result.txt1
-rw-r--r--Tests/RunCMake/string/UuidMissingTypeValue-stderr.txt4
-rw-r--r--Tests/RunCMake/string/UuidMissingTypeValue.cmake4
-rw-r--r--Tests/RunCMake/string/cmake/Finddummy.cmake4
-rw-r--r--Tests/RunCMake/string/json/unicode.json8
-rw-r--r--Tests/RunCMake/string/subdir/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/target_compile_definitions/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/target_compile_definitions/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/target_compile_definitions/empty_keyword_args.cmake5
-rw-r--r--Tests/RunCMake/target_compile_definitions/unknown_imported_target.cmake11
-rw-r--r--Tests/RunCMake/target_compile_features/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/target_compile_features/RunCMakeTest.cmake15
-rw-r--r--Tests/RunCMake/target_compile_features/alias_target-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_features/alias_target-stderr.txt4
-rw-r--r--Tests/RunCMake/target_compile_features/alias_target.cmake5
-rw-r--r--Tests/RunCMake/target_compile_features/cxx_not_enabled-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_features/cxx_not_enabled-stderr.txt4
-rw-r--r--Tests/RunCMake/target_compile_features/cxx_not_enabled.cmake2
-rw-r--r--Tests/RunCMake/target_compile_features/empty.c7
-rw-r--r--Tests/RunCMake/target_compile_features/empty.cpp7
-rw-r--r--Tests/RunCMake/target_compile_features/empty_keyword_args.cmake5
-rw-r--r--Tests/RunCMake/target_compile_features/imported_target-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_features/imported_target-stderr.txt5
-rw-r--r--Tests/RunCMake/target_compile_features/imported_target.cmake10
-rw-r--r--Tests/RunCMake/target_compile_features/invalid_args-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_features/invalid_args-stderr.txt4
-rw-r--r--Tests/RunCMake/target_compile_features/invalid_args.cmake4
-rw-r--r--Tests/RunCMake/target_compile_features/invalid_args_on_interface-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_features/invalid_args_on_interface-stderr.txt5
-rw-r--r--Tests/RunCMake/target_compile_features/invalid_args_on_interface.cmake4
-rw-r--r--Tests/RunCMake/target_compile_features/no_matching_c_feature-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_features/no_matching_c_feature-stderr.txt8
-rw-r--r--Tests/RunCMake/target_compile_features/no_matching_c_feature.cmake16
-rw-r--r--Tests/RunCMake/target_compile_features/no_matching_cxx_feature-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_features/no_matching_cxx_feature-stderr.txt8
-rw-r--r--Tests/RunCMake/target_compile_features/no_matching_cxx_feature.cmake27
-rw-r--r--Tests/RunCMake/target_compile_features/no_target-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_features/no_target-stderr.txt5
-rw-r--r--Tests/RunCMake/target_compile_features/no_target.cmake3
-rw-r--r--Tests/RunCMake/target_compile_features/not_a_c_feature-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_features/not_a_c_feature-stderr.txt5
-rw-r--r--Tests/RunCMake/target_compile_features/not_a_c_feature.cmake7
-rw-r--r--Tests/RunCMake/target_compile_features/not_a_cxx_feature-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_features/not_a_cxx_feature-stderr.txt5
-rw-r--r--Tests/RunCMake/target_compile_features/not_a_cxx_feature.cmake7
-rw-r--r--Tests/RunCMake/target_compile_features/not_enough_args-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_features/not_enough_args-stderr.txt4
-rw-r--r--Tests/RunCMake/target_compile_features/not_enough_args.cmake4
-rw-r--r--Tests/RunCMake/target_compile_features/utility_target-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_features/utility_target-stderr.txt4
-rw-r--r--Tests/RunCMake/target_compile_features/utility_target.cmake4
-rw-r--r--Tests/RunCMake/target_compile_options/BEFORE_keyword.cmake8
-rw-r--r--Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-NEW-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-OLD-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-OLD-stdout.txt1
-rw-r--r--Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword.cmake15
-rw-r--r--Tests/RunCMake/target_compile_options/CMP0101.c9
-rw-r--r--Tests/RunCMake/target_compile_options/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/target_compile_options/RunCMakeTest.cmake21
-rw-r--r--Tests/RunCMake/target_compile_options/empty_keyword_args.cmake5
-rw-r--r--Tests/RunCMake/target_include_directories/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/target_include_directories/RunCMakeTest.cmake6
-rw-r--r--Tests/RunCMake/target_include_directories/empty_keyword_args.cmake5
-rw-r--r--Tests/RunCMake/target_include_directories/include_after.cmake18
-rw-r--r--Tests/RunCMake/target_include_directories/include_before.cmake18
-rw-r--r--Tests/RunCMake/target_include_directories/include_default.cmake18
-rw-r--r--Tests/RunCMake/target_link_directories/CMP0099-NEW-basic-check.cmake4
-rw-r--r--Tests/RunCMake/target_link_directories/CMP0099-NEW-basic-result.txt1
-rw-r--r--Tests/RunCMake/target_link_directories/CMP0099-NEW.cmake4
-rw-r--r--Tests/RunCMake/target_link_directories/CMP0099-OLD-basic-check.cmake4
-rw-r--r--Tests/RunCMake/target_link_directories/CMP0099-OLD-basic-result.txt1
-rw-r--r--Tests/RunCMake/target_link_directories/CMP0099-OLD.cmake4
-rw-r--r--Tests/RunCMake/target_link_directories/CMP0099.cmake14
-rw-r--r--Tests/RunCMake/target_link_directories/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/target_link_directories/RunCMakeTest.cmake44
-rw-r--r--Tests/RunCMake/target_link_directories/empty_keyword_args.cmake5
-rw-r--r--Tests/RunCMake/target_link_directories/exe.c4
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANGUAGE-LINKER_LANGUAGE-check.cmake5
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANGUAGE-LINKER_LANGUAGE-result.txt1
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANGUAGE-basic-check.cmake2
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANGUAGE-basic-result.txt1
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANGUAGE-interface-check.cmake4
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANGUAGE-interface-result.txt1
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANGUAGE-validation.cmake20
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANGUAGE.cmake23
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANG_AND_ID-LINKER_LANGUAGE-check.cmake5
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANG_AND_ID-LINKER_LANGUAGE-result.txt1
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANG_AND_ID-basic-check.cmake2
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANG_AND_ID-basic-result.txt1
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANG_AND_ID-interface-check.cmake4
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANG_AND_ID-interface-result.txt1
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANG_AND_ID-validation.cmake26
-rw-r--r--Tests/RunCMake/target_link_directories/genex_LINK_LANG_AND_ID.cmake29
-rw-r--r--Tests/RunCMake/target_link_directories/lib.c7
-rw-r--r--Tests/RunCMake/target_link_libraries-ALIAS/AliasTargets.cmake39
-rw-r--r--Tests/RunCMake/target_link_libraries-ALIAS/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/target_link_libraries-ALIAS/RunCMakeTest.cmake25
-rw-r--r--Tests/RunCMake/target_link_libraries-ALIAS/func.c7
-rw-r--r--Tests/RunCMake/target_link_libraries-ALIAS/lib.c10
-rw-r--r--Tests/RunCMake/target_link_libraries-ALIAS/main.c12
-rw-r--r--Tests/RunCMake/target_link_libraries-ALIAS/sub_dir/CMakeLists.txt7
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/RunCMakeTest.cmake42
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-mix-lang-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-mix-lang-stderr.txt2
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-mix-lang.cmake8
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-usage-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-usage-stderr.txt8
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-usage.cmake4
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/empty.c0
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/func.c7
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/func.cxx18
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/genex.cmake81
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/lib.c10
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/main.c20
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/main.cxx12
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/RunCMakeTest.cmake38
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/bad-mix-lang-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/bad-mix-lang-stderr.txt2
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/bad-mix-lang.cmake8
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/basic-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/empty.c0
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/exe_c-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/exe_cxx-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/func.c7
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/func.cxx7
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/genex.cmake73
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/interface-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/lib.c10
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/main.c12
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/main.cxx12
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/no_language-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0023-NEW-2-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0023-NEW-2-stderr.txt11
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0023-NEW-2.cmake11
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0023-NEW-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0023-NEW-stderr.txt11
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0023-NEW.cmake11
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0023-WARN-2-stderr.txt16
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0023-WARN-2.cmake9
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0023-WARN-stderr.txt16
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0023-WARN.cmake9
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW-stdout.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW.cmake2
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stdout.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD.cmake2
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stderr.txt35
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stdout.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN.cmake1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-common.cmake6
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-stderr.txt6
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus.cmake6
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-stdout.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-NEW.cmake2
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-OLD-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-OLD-stderr.txt16
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-OLD.cmake2
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-WARN-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-WARN-stderr.txt5
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-WARN.cmake1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-common.cmake6
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0108-NEW-self-link-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0108-NEW-self-link-stderr.txt5
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0108-NEW-self-link.cmake4
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0108-OLD-self-link.cmake4
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0108-self-link.cmake9
-rw-r--r--Tests/RunCMake/target_link_libraries/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/target_link_libraries/ConfigCase-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/ConfigCase-stderr.txt13
-rw-r--r--Tests/RunCMake/target_link_libraries/ConfigCase.cmake6
-rw-r--r--Tests/RunCMake/target_link_libraries/ImportedTarget.cmake2
-rw-r--r--Tests/RunCMake/target_link_libraries/ImportedTargetFailure-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/ImportedTargetFailure-stderr.txt5
-rw-r--r--Tests/RunCMake/target_link_libraries/ImportedTargetFailure.cmake2
-rw-r--r--Tests/RunCMake/target_link_libraries/MixedSignature-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/MixedSignature-stderr.txt5
-rw-r--r--Tests/RunCMake/target_link_libraries/MixedSignature.cmake6
-rw-r--r--Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake32
-rw-r--r--Tests/RunCMake/target_link_libraries/Separate-PRIVATE-LINK_PRIVATE-uses-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/Separate-PRIVATE-LINK_PRIVATE-uses.cmake9
-rw-r--r--Tests/RunCMake/target_link_libraries/SharedDepNotTarget.cmake11
-rw-r--r--Tests/RunCMake/target_link_libraries/StaticPrivateDepNotExported-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/StaticPrivateDepNotExported-stderr.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/StaticPrivateDepNotExported.cmake6
-rw-r--r--Tests/RunCMake/target_link_libraries/StaticPrivateDepNotTarget.cmake5
-rw-r--r--Tests/RunCMake/target_link_libraries/UNKNOWN-IMPORTED-GLOBAL.cmake5
-rw-r--r--Tests/RunCMake/target_link_libraries/empty.c0
-rw-r--r--Tests/RunCMake/target_link_libraries/empty.cpp7
-rw-r--r--Tests/RunCMake/target_link_libraries/empty_keyword_args.cmake4
-rw-r--r--Tests/RunCMake/target_link_libraries/empty_vs6_1.cpp1
-rw-r--r--Tests/RunCMake/target_link_libraries/empty_vs6_2.cpp1
-rw-r--r--Tests/RunCMake/target_link_libraries/empty_vs6_3.cpp1
-rw-r--r--Tests/RunCMake/target_link_libraries/lib.c10
-rw-r--r--Tests/RunCMake/target_link_options/CMP0099-NEW-basic-check.cmake4
-rw-r--r--Tests/RunCMake/target_link_options/CMP0099-NEW-basic-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/CMP0099-NEW.cmake4
-rw-r--r--Tests/RunCMake/target_link_options/CMP0099-OLD-basic-check.cmake4
-rw-r--r--Tests/RunCMake/target_link_options/CMP0099-OLD-basic-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/CMP0099-OLD.cmake4
-rw-r--r--Tests/RunCMake/target_link_options/CMP0099.cmake19
-rw-r--r--Tests/RunCMake/target_link_options/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/target_link_options/LINKER_expansion-LINKER-check.cmake2
-rw-r--r--Tests/RunCMake/target_link_options/LINKER_expansion-LINKER_SHELL-check.cmake2
-rw-r--r--Tests/RunCMake/target_link_options/LINKER_expansion-validation.cmake15
-rw-r--r--Tests/RunCMake/target_link_options/LINKER_expansion.cmake56
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS-basic-check.cmake7
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS-basic-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS-exe-check.cmake7
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS-exe-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS-interface-check.cmake4
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS-interface-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS-interface-static-check.cmake4
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS-interface-static-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS-mod-check.cmake7
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS-mod-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS-shared-check.cmake7
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS-shared-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS-static-check.cmake7
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS-static-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/LINK_OPTIONS.cmake55
-rw-r--r--Tests/RunCMake/target_link_options/LinkOptionsDevice.cu14
-rw-r--r--Tests/RunCMake/target_link_options/LinkOptionsExe.c4
-rw-r--r--Tests/RunCMake/target_link_options/LinkOptionsLib.c7
-rw-r--r--Tests/RunCMake/target_link_options/RunCMakeTest.cmake102
-rw-r--r--Tests/RunCMake/target_link_options/bad_SHELL_usage-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/bad_SHELL_usage-stderr.txt4
-rw-r--r--Tests/RunCMake/target_link_options/bad_SHELL_usage.cmake5
-rw-r--r--Tests/RunCMake/target_link_options/dump.c13
-rw-r--r--Tests/RunCMake/target_link_options/empty_keyword_args.cmake5
-rw-r--r--Tests/RunCMake/target_link_options/genex_DEVICE_LINK-CMP0105_NEW-check.cmake4
-rw-r--r--Tests/RunCMake/target_link_options/genex_DEVICE_LINK-CMP0105_NEW-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_DEVICE_LINK-device-check.cmake3
-rw-r--r--Tests/RunCMake/target_link_options/genex_DEVICE_LINK-device-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_DEVICE_LINK-host_link_options-check.cmake4
-rw-r--r--Tests/RunCMake/target_link_options/genex_DEVICE_LINK-host_link_options-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_DEVICE_LINK-interface-check.cmake3
-rw-r--r--Tests/RunCMake/target_link_options/genex_DEVICE_LINK-interface-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_DEVICE_LINK-no_device-check.cmake3
-rw-r--r--Tests/RunCMake/target_link_options/genex_DEVICE_LINK-no_device-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_DEVICE_LINK-private-check.cmake3
-rw-r--r--Tests/RunCMake/target_link_options/genex_DEVICE_LINK-private-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_DEVICE_LINK-validation.cmake22
-rw-r--r--Tests/RunCMake/target_link_options/genex_DEVICE_LINK.cmake59
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANGUAGE-LINKER_LANGUAGE-check.cmake5
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANGUAGE-LINKER_LANGUAGE-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANGUAGE-exe-check.cmake2
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANGUAGE-exe-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANGUAGE-interface-check.cmake5
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANGUAGE-interface-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANGUAGE-mod-check.cmake2
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANGUAGE-mod-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANGUAGE-shared_c-check.cmake5
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANGUAGE-shared_c-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANGUAGE-validation.cmake17
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANGUAGE.cmake32
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANG_AND_ID-LINKER_LANGUAGE-check.cmake5
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANG_AND_ID-LINKER_LANGUAGE-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANG_AND_ID-exe-check.cmake2
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANG_AND_ID-exe-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANG_AND_ID-interface-check.cmake5
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANG_AND_ID-interface-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANG_AND_ID-mod-check.cmake2
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANG_AND_ID-mod-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANG_AND_ID-shared_c-check.cmake5
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANG_AND_ID-shared_c-result.txt1
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANG_AND_ID-validation.cmake23
-rw-r--r--Tests/RunCMake/target_link_options/genex_LINK_LANG_AND_ID.cmake41
-rw-r--r--Tests/RunCMake/target_sources/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/target_sources/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/target_sources/empty_keyword_args.cmake5
-rw-r--r--Tests/RunCMake/test_include_dirs/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/test_include_dirs/RunCMakeTest.cmake17
-rw-r--r--Tests/RunCMake/test_include_dirs/TID-test-stdout.txt17
-rw-r--r--Tests/RunCMake/test_include_dirs/TID.cmake29
-rw-r--r--Tests/RunCMake/test_include_dirs/add-tests.cmake8
-rw-r--r--Tests/RunCMake/test_include_dirs/dummy.cpp4
-rw-r--r--Tests/RunCMake/try_compile/BadLinkLibraries-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/BadLinkLibraries-stderr.txt5
-rw-r--r--Tests/RunCMake/try_compile/BadLinkLibraries.cmake3
-rw-r--r--Tests/RunCMake/try_compile/BadSources1-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/BadSources1-stderr.txt12
-rw-r--r--Tests/RunCMake/try_compile/BadSources1.cmake1
-rw-r--r--Tests/RunCMake/try_compile/BadSources2-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/BadSources2-stderr.txt12
-rw-r--r--Tests/RunCMake/try_compile/BadSources2.cmake5
-rw-r--r--Tests/RunCMake/try_compile/CMP0056-stderr.txt24
-rw-r--r--Tests/RunCMake/try_compile/CMP0056-stdout.txt4
-rw-r--r--Tests/RunCMake/try_compile/CMP0056.cmake68
-rw-r--r--Tests/RunCMake/try_compile/CMP0066-stderr.txt26
-rw-r--r--Tests/RunCMake/try_compile/CMP0066-stdout.txt4
-rw-r--r--Tests/RunCMake/try_compile/CMP0066.cmake58
-rw-r--r--Tests/RunCMake/try_compile/CMP0067-stderr.txt36
-rw-r--r--Tests/RunCMake/try_compile/CMP0067.cmake40
-rw-r--r--Tests/RunCMake/try_compile/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/try_compile/CStandard-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/CStandard-stderr.txt7
-rw-r--r--Tests/RunCMake/try_compile/CStandard.cmake7
-rw-r--r--Tests/RunCMake/try_compile/CStandardGNU.c10
-rw-r--r--Tests/RunCMake/try_compile/CStandardGNU.cmake23
-rw-r--r--Tests/RunCMake/try_compile/CStandardNoDefault.cmake9
-rw-r--r--Tests/RunCMake/try_compile/CleanupNoFollowSymlink.cmake21
-rw-r--r--Tests/RunCMake/try_compile/CopyFileErrorNoCopyFile-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/CopyFileErrorNoCopyFile-stderr.txt4
-rw-r--r--Tests/RunCMake/try_compile/CopyFileErrorNoCopyFile.cmake2
-rw-r--r--Tests/RunCMake/try_compile/CudaStandard-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/CudaStandard-stderr.txt7
-rw-r--r--Tests/RunCMake/try_compile/CudaStandard.cmake7
-rw-r--r--Tests/RunCMake/try_compile/CudaStandardNoDefault.cmake9
-rw-r--r--Tests/RunCMake/try_compile/CxxStandard-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/CxxStandard-stderr.txt7
-rw-r--r--Tests/RunCMake/try_compile/CxxStandard.cmake7
-rw-r--r--Tests/RunCMake/try_compile/CxxStandardGNU.cmake23
-rw-r--r--Tests/RunCMake/try_compile/CxxStandardGNU.cxx11
-rw-r--r--Tests/RunCMake/try_compile/CxxStandardNoDefault.cmake9
-rw-r--r--Tests/RunCMake/try_compile/ISPCDuplicateTarget-stderr.txt1
-rw-r--r--Tests/RunCMake/try_compile/ISPCDuplicateTarget.cmake8
-rw-r--r--Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja-stderr.txt1
-rw-r--r--Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja.cmake11
-rw-r--r--Tests/RunCMake/try_compile/ISPCInvalidTarget-stderr.txt1
-rw-r--r--Tests/RunCMake/try_compile/ISPCInvalidTarget.cmake7
-rw-r--r--Tests/RunCMake/try_compile/ISPCTargets-stderr.txt1
-rw-r--r--Tests/RunCMake/try_compile/ISPCTargets-stdout.txt1
-rw-r--r--Tests/RunCMake/try_compile/ISPCTargets.cmake7
-rw-r--r--Tests/RunCMake/try_compile/LinkOptions.cmake40
-rw-r--r--Tests/RunCMake/try_compile/NoArgs-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/NoArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/try_compile/NoArgs.cmake1
-rw-r--r--Tests/RunCMake/try_compile/NoCopyFile-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/NoCopyFile-stderr.txt4
-rw-r--r--Tests/RunCMake/try_compile/NoCopyFile.cmake2
-rw-r--r--Tests/RunCMake/try_compile/NoCopyFile2-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/NoCopyFile2-stderr.txt4
-rw-r--r--Tests/RunCMake/try_compile/NoCopyFile2.cmake2
-rw-r--r--Tests/RunCMake/try_compile/NoCopyFileError-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/NoCopyFileError-stderr.txt4
-rw-r--r--Tests/RunCMake/try_compile/NoCopyFileError.cmake2
-rw-r--r--Tests/RunCMake/try_compile/NoOutputVariable-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/NoOutputVariable-stderr.txt4
-rw-r--r--Tests/RunCMake/try_compile/NoOutputVariable.cmake2
-rw-r--r--Tests/RunCMake/try_compile/NoOutputVariable2-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/NoOutputVariable2-stderr.txt4
-rw-r--r--Tests/RunCMake/try_compile/NoOutputVariable2.cmake2
-rw-r--r--Tests/RunCMake/try_compile/NoSources-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/NoSources-stderr.txt4
-rw-r--r--Tests/RunCMake/try_compile/NoSources.cmake1
-rw-r--r--Tests/RunCMake/try_compile/NonSourceCompileDefinitions-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/NonSourceCompileDefinitions-stderr.txt4
-rw-r--r--Tests/RunCMake/try_compile/NonSourceCompileDefinitions.cmake2
-rw-r--r--Tests/RunCMake/try_compile/NonSourceCopyFile-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/NonSourceCopyFile-stderr.txt4
-rw-r--r--Tests/RunCMake/try_compile/NonSourceCopyFile.cmake2
-rw-r--r--Tests/RunCMake/try_compile/ObjCStandard-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/ObjCStandard-stderr.txt7
-rw-r--r--Tests/RunCMake/try_compile/ObjCStandard.cmake7
-rw-r--r--Tests/RunCMake/try_compile/ObjCxxStandard-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/ObjCxxStandard-stderr.txt7
-rw-r--r--Tests/RunCMake/try_compile/ObjCxxStandard.cmake7
-rw-r--r--Tests/RunCMake/try_compile/OneArg-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/OneArg-stderr.txt4
-rw-r--r--Tests/RunCMake/try_compile/OneArg.cmake1
-rw-r--r--Tests/RunCMake/try_compile/PlatformVariables.cmake23
-rw-r--r--Tests/RunCMake/try_compile/RerunCMake-nowork-ninja-no-console-stdout.txt1
-rw-r--r--Tests/RunCMake/try_compile/RerunCMake-rerun-ninja-no-console-stdout.txt5
-rw-r--r--Tests/RunCMake/try_compile/RerunCMake-rerun-stderr.txt2
-rw-r--r--Tests/RunCMake/try_compile/RerunCMake-rerun-stdout.txt3
-rw-r--r--Tests/RunCMake/try_compile/RerunCMake-stderr.txt2
-rw-r--r--Tests/RunCMake/try_compile/RerunCMake-stdout.txt3
-rw-r--r--Tests/RunCMake/try_compile/RerunCMake.cmake7
-rw-r--r--Tests/RunCMake/try_compile/RunCMakeTest.cmake117
-rw-r--r--Tests/RunCMake/try_compile/TargetTypeExe.cmake14
-rw-r--r--Tests/RunCMake/try_compile/TargetTypeInvalid-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/TargetTypeInvalid-stderr.txt5
-rw-r--r--Tests/RunCMake/try_compile/TargetTypeInvalid.cmake2
-rw-r--r--Tests/RunCMake/try_compile/TargetTypeStatic.cmake14
-rw-r--r--Tests/RunCMake/try_compile/TwoArgs-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/TwoArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/try_compile/TwoArgs.cmake1
-rw-r--r--Tests/RunCMake/try_compile/WarnDeprecated.cmake19
-rw-r--r--Tests/RunCMake/try_compile/lib.c4
-rw-r--r--Tests/RunCMake/try_compile/main.c8
-rw-r--r--Tests/RunCMake/try_compile/other.c4
-rw-r--r--Tests/RunCMake/try_compile/proj/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/try_compile/src.c7
-rw-r--r--Tests/RunCMake/try_compile/src.cu4
-rw-r--r--Tests/RunCMake/try_compile/src.cxx4
-rw-r--r--Tests/RunCMake/try_compile/src.ispc4
-rw-r--r--Tests/RunCMake/try_compile/src.m4
-rw-r--r--Tests/RunCMake/try_compile/src.mm4
-rw-r--r--Tests/RunCMake/try_run/BadLinkLibraries-result.txt1
-rw-r--r--Tests/RunCMake/try_run/BadLinkLibraries-stderr.txt5
-rw-r--r--Tests/RunCMake/try_run/BadLinkLibraries.cmake4
-rw-r--r--Tests/RunCMake/try_run/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/try_run/LinkOptions.cmake44
-rw-r--r--Tests/RunCMake/try_run/RunCMakeTest.cmake12
-rw-r--r--Tests/RunCMake/try_run/WorkingDirArg.cmake9
-rw-r--r--Tests/RunCMake/try_run/lib.c4
-rw-r--r--Tests/RunCMake/try_run/main.c8
-rw-r--r--Tests/RunCMake/try_run/src.c4
-rw-r--r--Tests/RunCMake/variable_watch/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/variable_watch/ModifiedAccess-stderr.txt4
-rw-r--r--Tests/RunCMake/variable_watch/ModifiedAccess.cmake3
-rw-r--r--Tests/RunCMake/variable_watch/ModifyWatchInCallback.cmake17
-rw-r--r--Tests/RunCMake/variable_watch/NoWatcher-stderr.txt5
-rw-r--r--Tests/RunCMake/variable_watch/NoWatcher.cmake8
-rw-r--r--Tests/RunCMake/variable_watch/RaiseInParentScope-stderr.txt2
-rw-r--r--Tests/RunCMake/variable_watch/RaiseInParentScope.cmake15
-rw-r--r--Tests/RunCMake/variable_watch/RunCMakeTest.cmake7
-rw-r--r--Tests/RunCMake/variable_watch/WatchTwice-stderr.txt2
-rw-r--r--Tests/RunCMake/variable_watch/WatchTwice.cmake11
-rw-r--r--Tests/RunCMake/while/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/while/EndAlone-result.txt1
-rw-r--r--Tests/RunCMake/while/EndAlone-stderr.txt4
-rw-r--r--Tests/RunCMake/while/EndAlone.cmake1
-rw-r--r--Tests/RunCMake/while/EndAloneArgs-result.txt1
-rw-r--r--Tests/RunCMake/while/EndAloneArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/while/EndAloneArgs.cmake1
-rw-r--r--Tests/RunCMake/while/EndMismatch-stderr.txt13
-rw-r--r--Tests/RunCMake/while/EndMismatch.cmake2
-rw-r--r--Tests/RunCMake/while/EndMissing-result.txt1
-rw-r--r--Tests/RunCMake/while/EndMissing-stderr.txt4
-rw-r--r--Tests/RunCMake/while/EndMissing.cmake1
-rw-r--r--Tests/RunCMake/while/MissingArgument-result.txt1
-rw-r--r--Tests/RunCMake/while/MissingArgument-stderr.txt11
-rw-r--r--Tests/RunCMake/while/MissingArgument.cmake2
-rw-r--r--Tests/RunCMake/while/RunCMakeTest.cmake7
-rw-r--r--Tests/RuntimePath/CMakeLists.txt44
-rw-r--r--Tests/RuntimePath/bar1.c5
-rw-r--r--Tests/RuntimePath/bar2.c5
-rw-r--r--Tests/RuntimePath/foo1.c4
-rw-r--r--Tests/RuntimePath/foo2.c4
-rw-r--r--Tests/RuntimePath/main.c5
-rw-r--r--Tests/SBCS/CMakeLists.txt6
-rw-r--r--Tests/SBCS/SBCS.cxx23
-rw-r--r--Tests/SetLang/CMakeLists.txt25
-rw-r--r--Tests/SetLang/bar.c32
-rw-r--r--Tests/SetLang/foo.c7
-rw-r--r--Tests/SetLang/stay_c.c8
-rw-r--r--Tests/SetLang/stay_cxx.cxx8
-rw-r--r--Tests/SetLang/zoom.zzz7
-rw-r--r--Tests/Simple/CMakeLists.txt17
-rw-r--r--Tests/Simple/simple.cxx11
-rw-r--r--Tests/Simple/simpleCLib.c11
-rw-r--r--Tests/Simple/simpleLib.cxx3
-rw-r--r--Tests/Simple/simpleWe.cpp14
-rw-r--r--Tests/SimpleCOnly/CMakeLists.txt17
-rw-r--r--Tests/SimpleCOnly/bar.c4
-rw-r--r--Tests/SimpleCOnly/foo.c4
-rw-r--r--Tests/SimpleCOnly/main.c12
-rw-r--r--Tests/SourceFileIncludeDirProperty/CMakeLists.txt15
-rw-r--r--Tests/SourceFileIncludeDirProperty/main.c7
-rw-r--r--Tests/SourceFileIncludeDirProperty/source/header.h2
-rw-r--r--Tests/SourceFileIncludeDirProperty/target/header.h2
-rw-r--r--Tests/SourceFileProperty/CMakeLists.txt27
-rw-r--r--Tests/SourceFileProperty/ICaseTest.c7
-rw-r--r--Tests/SourceFileProperty/main.c13
-rw-r--r--Tests/SourceGroups/CMakeLists.txt65
-rw-r--r--Tests/SourceGroups/README.txt1
-rw-r--r--Tests/SourceGroups/bar.c4
-rw-r--r--Tests/SourceGroups/baz.c4
-rw-r--r--Tests/SourceGroups/foo.c4
-rw-r--r--Tests/SourceGroups/main.c31
-rw-r--r--Tests/SourceGroups/nested.c4
-rw-r--r--Tests/SourceGroups/sub1/foo.c4
-rw-r--r--Tests/SourceGroups/sub1/foobar.c4
-rw-r--r--Tests/SourceGroups/sub1/tree_bar.c4
-rw-r--r--Tests/SourceGroups/sub1/tree_baz.c4
-rw-r--r--Tests/SourceGroups/sub1/tree_subdir/tree_foobar.c4
-rw-r--r--Tests/SourceGroups/tree_empty_prefix_bar.c4
-rw-r--r--Tests/SourceGroups/tree_empty_prefix_foo.c4
-rw-r--r--Tests/SourceGroups/tree_prefix_bar.c4
-rw-r--r--Tests/SourceGroups/tree_prefix_foo.c4
-rw-r--r--Tests/SourcesProperty/CMakeLists.txt14
-rw-r--r--Tests/SourcesProperty/iface.cpp5
-rw-r--r--Tests/SourcesProperty/iface.h4
-rw-r--r--Tests/SourcesProperty/main.cpp7
-rw-r--r--Tests/SourcesProperty/prop.cpp5
-rw-r--r--Tests/StagingPrefix/CMakeLists.txt93
-rw-r--r--Tests/StagingPrefix/Consumer/CMakeLists.txt22
-rw-r--r--Tests/StagingPrefix/Consumer/cmake/FindBar.cmake6
-rw-r--r--Tests/StagingPrefix/Consumer/main.cpp10
-rw-r--r--Tests/StagingPrefix/Producer/CMakeLists.txt26
-rw-r--r--Tests/StagingPrefix/Producer/bar.cpp7
-rw-r--r--Tests/StagingPrefix/Producer/bar.h10
-rw-r--r--Tests/StagingPrefix/Producer/foo.cpp7
-rw-r--r--Tests/StagingPrefix/Producer/foo.h10
-rw-r--r--Tests/StagingPrefix/main.cpp5
-rw-r--r--Tests/StringFileTest/CMakeLists.txt291
-rw-r--r--Tests/StringFileTest/InputFile.h.in38
-rw-r--r--Tests/StringFileTest/StringFile.cxx32
-rw-r--r--Tests/StringFileTest/main.ihx21
-rw-r--r--Tests/StringFileTest/main.srec21
-rw-r--r--Tests/StringFileTest/test.binbin0 -> 5 bytes-rw-r--r--Tests/StringFileTest/test.utf83
-rw-r--r--Tests/SubDir/AnotherSubdir/pair+int.int.c6
-rw-r--r--Tests/SubDir/AnotherSubdir/pair_int.int.c6
-rw-r--r--Tests/SubDir/AnotherSubdir/secondone.c6
-rw-r--r--Tests/SubDir/AnotherSubdir/testfromsubdir.c14
-rw-r--r--Tests/SubDir/CMakeLists.txt50
-rw-r--r--Tests/SubDir/Examples/CMakeLists.txt3
-rw-r--r--Tests/SubDir/Examples/example1/CMakeLists.txt7
-rw-r--r--Tests/SubDir/Examples/example1/example1.cxx7
-rw-r--r--Tests/SubDir/Examples/example2/CMakeLists.txt2
-rw-r--r--Tests/SubDir/Examples/example2/example2.cxx7
-rw-r--r--Tests/SubDir/Executable/CMakeLists.txt13
-rw-r--r--Tests/SubDir/Executable/test.cxx42
-rw-r--r--Tests/SubDir/ThirdSubDir/pair+int.int1.c6
-rw-r--r--Tests/SubDir/ThirdSubDir/pair_int.int1.c6
-rw-r--r--Tests/SubDir/ThirdSubDir/pair_p_int.int1.c6
-rw-r--r--Tests/SubDir/ThirdSubDir/testfromauxsubdir.c16
-rw-r--r--Tests/SubDir/ThirdSubDir/thirdone.c6
-rw-r--r--Tests/SubDir/vcl_algorithm+vcl_pair+double.foo.c6
-rw-r--r--Tests/SubDir/vcl_algorithm_vcl_pair_double.foo.c6
-rw-r--r--Tests/SubDirSpaces/Another Subdir/pair+int.int.c6
-rw-r--r--Tests/SubDirSpaces/Another Subdir/pair_int.int.c6
-rw-r--r--Tests/SubDirSpaces/Another Subdir/secondone.c6
-rw-r--r--Tests/SubDirSpaces/Another Subdir/testfromsubdir.c14
-rw-r--r--Tests/SubDirSpaces/CMakeLists.txt77
-rw-r--r--Tests/SubDirSpaces/Executable Sources/CMakeLists.txt1
-rw-r--r--Tests/SubDirSpaces/Executable Sources/test.cxx42
-rw-r--r--Tests/SubDirSpaces/Executable/CMakeLists.txt1
-rw-r--r--Tests/SubDirSpaces/Executable/test.cxx42
-rw-r--r--Tests/SubDirSpaces/Some Examples/CMakeLists.txt3
-rw-r--r--Tests/SubDirSpaces/Some Examples/example1/CMakeLists.txt7
-rw-r--r--Tests/SubDirSpaces/Some Examples/example1/example1.cxx7
-rw-r--r--Tests/SubDirSpaces/Some Examples/example2/CMakeLists.txt2
-rw-r--r--Tests/SubDirSpaces/Some Examples/example2/example2.cxx7
-rw-r--r--Tests/SubDirSpaces/Some(x86) Sources/CMakeLists.txt1
-rw-r--r--Tests/SubDirSpaces/Some(x86) Sources/test.c3
-rw-r--r--Tests/SubDirSpaces/ThirdSubDir/pair+int.int1.c6
-rw-r--r--Tests/SubDirSpaces/ThirdSubDir/pair_int.int1.c6
-rw-r--r--Tests/SubDirSpaces/ThirdSubDir/pair_p_int.int1.c6
-rw-r--r--Tests/SubDirSpaces/ThirdSubDir/testfromauxsubdir.c21
-rw-r--r--Tests/SubDirSpaces/ThirdSubDir/thirdone.c6
-rw-r--r--Tests/SubDirSpaces/vcl_algorithm+vcl_pair+double.foo.c6
-rw-r--r--Tests/SubDirSpaces/vcl_algorithm_vcl_pair_double.foo.c6
-rw-r--r--Tests/SubProject/CMakeLists.txt15
-rw-r--r--Tests/SubProject/bar.cxx1
-rw-r--r--Tests/SubProject/car.cxx6
-rw-r--r--Tests/SubProject/foo/CMakeLists.txt3
-rw-r--r--Tests/SubProject/foo/foo.cxx14
-rw-r--r--Tests/SubProject/gen.cxx.in4
-rw-r--r--Tests/SwiftMix/CMain.c5
-rw-r--r--Tests/SwiftMix/CMakeLists.txt6
-rw-r--r--Tests/SwiftMix/ObjC-Swift.h0
-rw-r--r--Tests/SwiftMix/ObjCMain.m4
-rw-r--r--Tests/SwiftMix/SwiftMain.swift8
-rw-r--r--Tests/SwiftOnly/CMakeLists.txt38
-rw-r--r--Tests/SwiftOnly/L.swift1
-rw-r--r--Tests/SwiftOnly/M.swift2
-rw-r--r--Tests/SwiftOnly/N.swift2
-rw-r--r--Tests/SwiftOnly/main.swift1
-rw-r--r--Tests/SystemInformation/CMakeLists.txt59
-rw-r--r--Tests/SystemInformation/DumpInformation.cxx82
-rw-r--r--Tests/SystemInformation/DumpInformation.h.in6
-rw-r--r--Tests/SystemInformation/SystemInformation.in122
-rw-r--r--Tests/TargetName/CMakeLists.txt5
-rw-r--r--Tests/TargetName/executables/CMakeLists.txt1
-rw-r--r--Tests/TargetName/executables/hello_world.c5
-rw-r--r--Tests/TargetName/scripts/.gitattributes1
-rw-r--r--Tests/TargetName/scripts/CMakeLists.txt13
-rwxr-xr-xTests/TargetName/scripts/hello_world2
-rw-r--r--Tests/TestDriver/CMakeLists.txt15
-rw-r--r--Tests/TestDriver/subdir/test3.cxx8
-rw-r--r--Tests/TestDriver/test1.cxx22
-rw-r--r--Tests/TestDriver/test2.cxx8
-rw-r--r--Tests/TestDriver/testArgs.h16
-rw-r--r--Tests/TestDriver/testExtraStuff.cxx4
-rw-r--r--Tests/TestDriver/testExtraStuff2.cxx4
-rw-r--r--Tests/TestDriver/testExtraStuff3.cxx4
-rw-r--r--Tests/Testing/CMakeLists.txt59
-rw-r--r--Tests/Testing/DartConfig.cmake24
-rw-r--r--Tests/Testing/Sub/Sub2/CMakeLists.txt17
-rw-r--r--Tests/Testing/Sub/Sub2/testing2.cxx4
-rw-r--r--Tests/Testing/testing.cxx4
-rw-r--r--Tests/TestsWorkingDirectory/CMakeLists.txt42
-rw-r--r--Tests/TestsWorkingDirectory/main.c62
-rw-r--r--Tests/TestsWorkingDirectory/subdir/CMakeLists.txt31
-rw-r--r--Tests/TryCompile/CMakeLists.txt404
-rw-r--r--Tests/TryCompile/Inner/CMakeLists.txt15
-rw-r--r--Tests/TryCompile/Inner/innerexe.c5
-rw-r--r--Tests/TryCompile/Inner/innerlib.c4
-rw-r--r--Tests/TryCompile/check_a_b.c10
-rw-r--r--Tests/TryCompile/exit_success.c7
-rw-r--r--Tests/TryCompile/exit_with_error.c7
-rw-r--r--Tests/TryCompile/expect_arg.c18
-rw-r--r--Tests/TryCompile/fail.c1
-rw-r--r--Tests/TryCompile/fail.m1
-rw-r--r--Tests/TryCompile/fail2a.c4
-rw-r--r--Tests/TryCompile/fail2b.c1
-rw-r--r--Tests/TryCompile/pass.c4
-rw-r--r--Tests/TryCompile/pass.m4
-rw-r--r--Tests/TryCompile/pass2a.c5
-rw-r--r--Tests/TryCompile/pass2b.cxx4
-rw-r--r--Tests/TryCompile/testdef.c7
-rw-r--r--Tests/Unset/CMakeLists.txt91
-rw-r--r--Tests/Unset/unset.c4
-rw-r--r--Tests/UseSWIG/AlternateLibraryName/CMakeLists.txt35
-rw-r--r--Tests/UseSWIG/BasicConfiguration.cmake86
-rw-r--r--Tests/UseSWIG/BasicCsharp/CMakeLists.txt21
-rw-r--r--Tests/UseSWIG/BasicFortran/CMakeLists.txt23
-rw-r--r--Tests/UseSWIG/BasicPerl/CMakeLists.txt14
-rw-r--r--Tests/UseSWIG/BasicPython/CMakeLists.txt13
-rw-r--r--Tests/UseSWIG/CMakeLists.txt207
-rw-r--r--Tests/UseSWIG/LegacyConfiguration.cmake68
-rw-r--r--Tests/UseSWIG/LegacyPerl/CMakeLists.txt14
-rw-r--r--Tests/UseSWIG/LegacyPython/CMakeLists.txt13
-rw-r--r--Tests/UseSWIG/ModuleName/CMakeLists.txt42
-rw-r--r--Tests/UseSWIG/ModuleName/example.i9
-rw-r--r--Tests/UseSWIG/ModuleName/runme.py52
-rw-r--r--Tests/UseSWIG/ModuleVersion2/CMakeLists.txt56
-rw-r--r--Tests/UseSWIG/MultipleFiles/CMakeLists.txt30
-rw-r--r--Tests/UseSWIG/MultipleFiles/add.cxx6
-rw-r--r--Tests/UseSWIG/MultipleFiles/add.h1
-rw-r--r--Tests/UseSWIG/MultipleFiles/add.i4
-rw-r--r--Tests/UseSWIG/MultipleFiles/sub.cxx6
-rw-r--r--Tests/UseSWIG/MultipleFiles/sub.h1
-rw-r--r--Tests/UseSWIG/MultipleFiles/sub.i5
-rw-r--r--Tests/UseSWIG/MultipleModules/CMakeLists.txt68
-rw-r--r--Tests/UseSWIG/MultiplePython/CMakeLists.txt59
-rw-r--r--Tests/UseSWIG/NamespaceCsharp/CMakeLists.txt25
-rw-r--r--Tests/UseSWIG/NamespaceCsharp/ValidateSupportFiles.cmake8
-rw-r--r--Tests/UseSWIG/NamespaceCsharp/ns_example.cpp14
-rw-r--r--Tests/UseSWIG/NamespaceCsharp/ns_example.hpp19
-rw-r--r--Tests/UseSWIG/NamespaceCsharp/ns_example.i8
-rw-r--r--Tests/UseSWIG/SwigSrcFileExtension/CMakeLists.txt28
-rw-r--r--Tests/UseSWIG/SwigSrcFileExtension/my_add.i9
-rw-r--r--Tests/UseSWIG/SwigSrcFileExtension/my_sub.swg9
-rwxr-xr-xTests/UseSWIG/SwigSrcFileExtension/runme.py24
-rw-r--r--Tests/UseSWIG/SwigSrcOUTPUT_DIR/CMakeLists.txt61
-rw-r--r--Tests/UseSWIG/SwigSrcOUTPUT_DIR/ValidateSupportFiles.cmake17
-rw-r--r--Tests/UseSWIG/SwigSrcOUTPUT_DIR/bar.hpp15
-rw-r--r--Tests/UseSWIG/SwigSrcOUTPUT_DIR/bar.i8
-rw-r--r--Tests/UseSWIG/SwigSrcOUTPUT_DIR/cs.cpp29
-rw-r--r--Tests/UseSWIG/SwigSrcOUTPUT_DIR/foo.hpp15
-rw-r--r--Tests/UseSWIG/SwigSrcOUTPUT_DIR/foo.i8
-rw-r--r--Tests/UseSWIG/UseTargetINCLUDE_DIRECTORIES/CMakeLists.txt45
-rw-r--r--Tests/UseSWIG/UseTargetINCLUDE_DIRECTORIES/example.i9
-rw-r--r--Tests/UseSWIG/example.cxx33
-rw-r--r--Tests/UseSWIG/example.h37
-rw-r--r--Tests/UseSWIG/example.i9
-rw-r--r--Tests/UseSWIG/runme.cs54
-rw-r--r--Tests/UseSWIG/runme.f9077
-rw-r--r--Tests/UseSWIG/runme.php458
-rw-r--r--Tests/UseSWIG/runme.pike53
-rw-r--r--Tests/UseSWIG/runme.pl56
-rw-r--r--Tests/UseSWIG/runme.py52
-rw-r--r--Tests/UseSWIG/runme.rb49
-rw-r--r--Tests/UseSWIG/runme.tcl49
-rw-r--r--Tests/UseSWIG/runme2.tcl69
-rw-r--r--Tests/VSAndroid/AndroidManifest.xml16
-rw-r--r--Tests/VSAndroid/CMakeLists.txt57
-rw-r--r--Tests/VSAndroid/build.xml4
-rw-r--r--Tests/VSAndroid/jni/first.c22
-rw-r--r--Tests/VSAndroid/jni/first.h22
-rw-r--r--Tests/VSAndroid/jni/second.c25
-rw-r--r--Tests/VSAndroid/proguard-android.txt57
-rw-r--r--Tests/VSAndroid/res/values/strings.xml4
-rw-r--r--Tests/VSAndroid/src/com/example/twolibs/TwoLibs.java46
-rw-r--r--Tests/VSExcludeFromDefaultBuild/CMakeLists.txt36
-rw-r--r--Tests/VSExcludeFromDefaultBuild/ClearExes.cmake8
-rw-r--r--Tests/VSExcludeFromDefaultBuild/ResultTest.cmake29
-rw-r--r--Tests/VSExcludeFromDefaultBuild/main.c4
-rw-r--r--Tests/VSExternalInclude/CMakeLists.txt69
-rw-r--r--Tests/VSExternalInclude/Lib1/CMakeLists.txt6
-rw-r--r--Tests/VSExternalInclude/Lib1/lib1.cpp7
-rw-r--r--Tests/VSExternalInclude/Lib1/lib1.h7
-rw-r--r--Tests/VSExternalInclude/Lib2/CMakeLists.txt8
-rw-r--r--Tests/VSExternalInclude/Lib2/lib2.cpp10
-rw-r--r--Tests/VSExternalInclude/Lib2/lib2.h10
-rw-r--r--Tests/VSExternalInclude/main.cpp9
-rw-r--r--Tests/VSGNUFortran/CMakeLists.txt27
-rw-r--r--Tests/VSGNUFortran/c_code/CMakeLists.txt2
-rw-r--r--Tests/VSGNUFortran/c_code/main.c7
-rw-r--r--Tests/VSGNUFortran/runtest.cmake.in23
-rw-r--r--Tests/VSGNUFortran/subdir/CMakeLists.txt16
-rw-r--r--Tests/VSGNUFortran/subdir/fortran/CMakeLists.txt51
-rw-r--r--Tests/VSGNUFortran/subdir/fortran/hello.f7
-rw-r--r--Tests/VSGNUFortran/subdir/fortran/world.f6
-rw-r--r--Tests/VSMASM/CMakeLists.txt10
-rw-r--r--Tests/VSMASM/foo.asm7
-rw-r--r--Tests/VSMASM/include/foo-proc.asm4
-rw-r--r--Tests/VSMASM/main.c5
-rw-r--r--Tests/VSMidl/CMakeLists.txt81
-rw-r--r--Tests/VSMidl/src/CMakeLists.txt6
-rw-r--r--Tests/VSMidl/src/main.cpp18
-rw-r--r--Tests/VSMidl/src/test.idl30
-rw-r--r--Tests/VSNASM/CMakeLists.txt20
-rw-r--r--Tests/VSNASM/bar.asm13
-rw-r--r--Tests/VSNASM/foo.asm7
-rw-r--r--Tests/VSNASM/include/foo-proc.asm7
-rw-r--r--Tests/VSNASM/main.c6
-rw-r--r--Tests/VSProjectInSubdir/CMakeLists.txt3
-rw-r--r--Tests/VSProjectInSubdir/subdir/CMakeLists.txt1
-rw-r--r--Tests/VSResource/CMakeLists.txt65
-rw-r--r--Tests/VSResource/include.rc.in1
-rw-r--r--Tests/VSResource/lib.cpp4
-rw-r--r--Tests/VSResource/lib.rc4
-rw-r--r--Tests/VSResource/main.cpp76
-rw-r--r--Tests/VSResource/test.rc20
-rw-r--r--Tests/VSResource/test.txt1
-rw-r--r--Tests/VSResourceNinjaForceRSP/CMakeLists.txt7
-rw-r--r--Tests/VSResourceNinjaForceRSP/lib.cpp4
-rw-r--r--Tests/VSResourceNinjaForceRSP/main.cpp6
-rw-r--r--Tests/VSResourceNinjaForceRSP/test.rc4
-rw-r--r--Tests/VSWinStorePhone/CMakeLists.txt160
-rw-r--r--Tests/VSWinStorePhone/CxxDLL/CMakeLists.txt3
-rw-r--r--Tests/VSWinStorePhone/CxxDLL/cxxdll.cpp8
-rw-r--r--Tests/VSWinStorePhone/CxxDLL/cxxdll.h5
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/.gitattributes1
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Assets/ApplicationIcon.pngbin0 -> 2335 bytes-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Assets/Logo.pngbin0 -> 488 bytes-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Assets/SmallLogo.pngbin0 -> 167 bytes-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Assets/SmallLogo44x44.pngbin0 -> 265 bytes-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Assets/SplashScreen.pngbin0 -> 909 bytes-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Assets/StoreLogo.pngbin0 -> 227 bytes-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileLarge.pngbin0 -> 2953 bytes-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileMedium.pngbin0 -> 2767 bytes-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileSmall.pngbin0 -> 1397 bytes-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/IconicTileMediumLarge.pngbin0 -> 893 bytes-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/IconicTileSmall.pngbin0 -> 516 bytes-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/BasicTimer.h71
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.cpp186
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.h44
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1.cpp167
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1.h57
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1_TemporaryKey.pfxbin0 -> 2560 bytes-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Direct3DBase.cpp336
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Direct3DBase.h39
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/DirectXHelper.h44
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/SimplePixelShader.csobin0 -> 12796 bytes-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/SimplePixelShader.hlsl14
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/SimpleVertexShader.csobin0 -> 16336 bytes-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/SimpleVertexShader.hlsl39
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/Strings/en-US/Resources.resw123
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/pch.cpp1
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/pch.h8
-rw-r--r--Tests/VSWinStorePhone/EnsurePropertiesSet.cmake45
-rw-r--r--Tests/VSWinStorePhone/VerifyAppPackage.cmake34
-rw-r--r--Tests/VSWinStorePhone/WinRT/Batman.cpp14
-rw-r--r--Tests/VSWinStorePhone/WinRT/Batman.h12
-rw-r--r--Tests/VSWinStorePhone/WinRT/CMakeLists.txt13
-rw-r--r--Tests/VSWinStorePhone/cmake/Package_vc11.store.appxmanifest.in24
-rw-r--r--Tests/VSWinStorePhone/cmake/Package_vc11.wp.appxmanifest.in35
-rw-r--r--Tests/VSWinStorePhone/cmake/Package_vc12.store.appxmanifest.in34
-rw-r--r--Tests/VSWinStorePhone/cmake/Package_vc12.wp.appxmanifest.in36
-rw-r--r--Tests/VSWinStorePhone/cmake/Package_vc14.store.appxmanifest.in36
-rw-r--r--Tests/VSWindowsFormsResx/CMakeLists.txt45
-rw-r--r--Tests/VSWindowsFormsResx/WindowsFormsResx/Header.h0
-rw-r--r--Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.cpp1
-rw-r--r--Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.h79
-rw-r--r--Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.resx61
-rw-r--r--Tests/VSWindowsFormsResx/WindowsFormsResx/Source.cpp4
-rw-r--r--Tests/VSXaml/App.xaml7
-rw-r--r--Tests/VSXaml/App.xaml.cpp130
-rw-r--r--Tests/VSXaml/App.xaml.h31
-rw-r--r--Tests/VSXaml/Assets/Logo.scale-100.pngbin0 -> 488 bytes-rw-r--r--Tests/VSXaml/Assets/SmallLogo.scale-100.pngbin0 -> 167 bytes-rw-r--r--Tests/VSXaml/Assets/SplashScreen.scale-100.pngbin0 -> 909 bytes-rw-r--r--Tests/VSXaml/Assets/StoreLogo.scale-100.pngbin0 -> 227 bytes-rw-r--r--Tests/VSXaml/CMakeLists.txt52
-rw-r--r--Tests/VSXaml/MainPage.xaml14
-rw-r--r--Tests/VSXaml/MainPage.xaml.cpp29
-rw-r--r--Tests/VSXaml/MainPage.xaml.h20
-rw-r--r--Tests/VSXaml/Package.appxmanifest41
-rw-r--r--Tests/VSXaml/VSXaml_TemporaryKey.pfxbin0 -> 2560 bytes-rw-r--r--Tests/VSXaml/pch.cpp6
-rw-r--r--Tests/VSXaml/pch.h11
-rw-r--r--Tests/VariableUsage/CMakeLists.txt1
-rw-r--r--Tests/Visibility/CMakeLists.txt66
-rw-r--r--Tests/Visibility/bar.c3
-rw-r--r--Tests/Visibility/foo.cpp11
-rw-r--r--Tests/Visibility/hidden.c9
-rw-r--r--Tests/Visibility/shared.c6
-rw-r--r--Tests/Visibility/shared.cpp8
-rw-r--r--Tests/Visibility/verify.cmake14
-rw-r--r--Tests/WarnUnusedCliUnused/CMakeLists.txt9
-rw-r--r--Tests/WarnUnusedCliUnused/empty.cpp7
-rw-r--r--Tests/Wrapping/CMakeLists.txt108
-rw-r--r--Tests/Wrapping/Wrap.c19
-rw-r--r--Tests/Wrapping/dummy0
-rw-r--r--Tests/Wrapping/fakefluid.cxx17
-rw-r--r--Tests/Wrapping/fltk1.fl0
-rw-r--r--Tests/Wrapping/fltk2.fl0
-rw-r--r--Tests/Wrapping/foo.ui.in44
-rw-r--r--Tests/Wrapping/hints0
-rw-r--r--Tests/Wrapping/itkWrapperConfig.cxx0
-rw-r--r--Tests/Wrapping/qtnoqtmain.cxx4
-rw-r--r--Tests/Wrapping/qtwrapping.ui44
-rw-r--r--Tests/Wrapping/qtwrappingmain.cxx27
-rw-r--r--Tests/Wrapping/vtkExcluded.cxx0
-rw-r--r--Tests/Wrapping/vtkExcluded.h2
-rw-r--r--Tests/Wrapping/vtkIncluded.cxx0
-rw-r--r--Tests/Wrapping/vtkIncluded.h2
-rw-r--r--Tests/Wrapping/vtkTestMoc.h8
-rw-r--r--Tests/Wrapping/wrapFLTK.cxx4
-rw-r--r--Tests/Wrapping/wrapping.cxx4
-rw-r--r--Tests/X11/CMakeLists.txt40
-rw-r--r--Tests/X11/HelloWorldX11.cxx143
-rw-r--r--Tests/X11/X11.c21
-rw-r--r--Tests/XCTest/CMakeLists.txt77
-rw-r--r--Tests/XCTest/CocoaExample/AppDelegate.h5
-rw-r--r--Tests/XCTest/CocoaExample/AppDelegate.m18
-rw-r--r--Tests/XCTest/CocoaExample/Info.plist30
-rw-r--r--Tests/XCTest/CocoaExample/MainMenu.xib680
-rw-r--r--Tests/XCTest/CocoaExample/main.m5
-rw-r--r--Tests/XCTest/CocoaExampleTests/CocoaExampleTests.m13
-rw-r--r--Tests/XCTest/FrameworkExample/FrameworkExample.c6
-rw-r--r--Tests/XCTest/FrameworkExample/FrameworkExample.h1
-rw-r--r--Tests/XCTest/FrameworkExample/Info.plist28
-rw-r--r--Tests/XCTest/FrameworkExampleTests/FrameworkExampleTests.m16
-rw-r--r--Tests/XCTest/FrameworkExampleTests/Info.plist24
-rw-r--r--Tests/XCTest/StaticLibExample/StaticLibExample.c6
-rw-r--r--Tests/XCTest/StaticLibExample/StaticLibExample.h1
-rw-r--r--Tests/XCTest/StaticLibExampleTests/Info.plist24
-rw-r--r--Tests/XCTest/StaticLibExampleTests/StaticLibExampleTests.m16
-rw-r--r--Tests/bootstrap.bat.in2
-rw-r--r--Tests/iOSNavApp/CMakeLists.txt37
-rw-r--r--Tests/iOSNavApp/Classes/NavApp3AppDelegate.h21
-rw-r--r--Tests/iOSNavApp/Classes/NavApp3AppDelegate.m88
-rw-r--r--Tests/iOSNavApp/Classes/RootViewController.h14
-rw-r--r--Tests/iOSNavApp/Classes/RootViewController.m168
-rw-r--r--Tests/iOSNavApp/Info.plist.in32
-rw-r--r--Tests/iOSNavApp/MainWindow.xib542
-rw-r--r--Tests/iOSNavApp/NavApp3_Prefix.pch14
-rw-r--r--Tests/iOSNavApp/RootViewController.xib384
-rw-r--r--Tests/iOSNavApp/TotalFunction.c14
-rw-r--r--Tests/iOSNavApp/TotalFunction.h14
-rw-r--r--Tests/iOSNavApp/main.m17
-rw-r--r--Tests/test_clean.cmake.in2
-rw-r--r--Utilities/.NoDartCoverage1
-rw-r--r--Utilities/.clang-tidy6
-rw-r--r--Utilities/.gitattributes8
-rw-r--r--Utilities/CMakeLists.txt21
-rw-r--r--Utilities/Doxygen/CMakeLists.txt96
-rw-r--r--Utilities/Doxygen/DeveloperReference/mainpage.dox8
-rw-r--r--Utilities/Doxygen/doxyfile.in91
-rwxr-xr-xUtilities/Git/commit-msg14
-rwxr-xr-xUtilities/Git/pre-commit69
-rwxr-xr-xUtilities/Git/prepare-commit-msg6
-rw-r--r--Utilities/GitSetup/.gitattributes6
-rw-r--r--Utilities/GitSetup/LICENSE202
-rw-r--r--Utilities/GitSetup/NOTICE5
-rw-r--r--Utilities/GitSetup/README87
-rw-r--r--Utilities/GitSetup/config2
-rwxr-xr-xUtilities/GitSetup/setup-hooks64
-rwxr-xr-xUtilities/GitSetup/setup-user46
-rwxr-xr-xUtilities/GitSetup/tips55
-rw-r--r--Utilities/IWYU/mapping.imp134
-rw-r--r--Utilities/KWIML/.gitattributes1
-rw-r--r--Utilities/KWIML/CMakeLists.txt103
-rw-r--r--Utilities/KWIML/Copyright.txt30
-rw-r--r--Utilities/KWIML/README.md36
-rw-r--r--Utilities/KWIML/include/kwiml/abi.h583
-rw-r--r--Utilities/KWIML/include/kwiml/int.h1080
-rw-r--r--Utilities/KWIML/src/kwiml-config.cmake.in1
-rw-r--r--Utilities/KWIML/src/version.h.in59
-rw-r--r--Utilities/KWIML/test/CMakeLists.txt56
-rw-r--r--Utilities/KWIML/test/test.c33
-rw-r--r--Utilities/KWIML/test/test.cxx6
-rw-r--r--Utilities/KWIML/test/test.h16
-rw-r--r--Utilities/KWIML/test/test_abi_C.c19
-rw-r--r--Utilities/KWIML/test/test_abi_CXX.cxx19
-rw-r--r--Utilities/KWIML/test/test_abi_endian.h41
-rw-r--r--Utilities/KWIML/test/test_include_C.c16
-rw-r--r--Utilities/KWIML/test/test_include_CXX.cxx22
-rw-r--r--Utilities/KWIML/test/test_int_C.c19
-rw-r--r--Utilities/KWIML/test/test_int_CXX.cxx19
-rw-r--r--Utilities/KWIML/test/test_int_format.h210
-rw-r--r--Utilities/Release/.gitattributes1
-rw-r--r--Utilities/Release/CMakeInstall.bmpbin0 -> 25820 bytes-rw-r--r--Utilities/Release/CMakeLogo.icobin0 -> 17542 bytes-rw-r--r--Utilities/Release/README.rst93
-rw-r--r--Utilities/Release/WiX/CMakeLists.txt12
-rw-r--r--Utilities/Release/WiX/CustomAction/CMakeLists.txt19
-rw-r--r--Utilities/Release/WiX/CustomAction/detect_nsis_overwrite.cpp44
-rw-r--r--Utilities/Release/WiX/CustomAction/exports.def2
-rw-r--r--Utilities/Release/WiX/WIX.template.in59
-rw-r--r--Utilities/Release/WiX/cmake_extra_dialog.wxs36
-rw-r--r--Utilities/Release/WiX/cmake_nsis_overwrite_dialog.wxs21
-rw-r--r--Utilities/Release/WiX/custom_action_dll.wxs.in6
-rw-r--r--Utilities/Release/WiX/install_dir.wxs72
-rw-r--r--Utilities/Release/WiX/patch_desktop_shortcut.xml5
-rw-r--r--Utilities/Release/WiX/patch_path_env.xml26
-rw-r--r--Utilities/Release/WiX/ui_banner.jpgbin0 -> 2607 bytes-rw-r--r--Utilities/Release/WiX/ui_dialog.jpgbin0 -> 13369 bytes-rwxr-xr-xUtilities/Release/consolidate-relnotes.bash27
-rwxr-xr-xUtilities/Release/files-sign.bash5
-rw-r--r--Utilities/Release/files-v1.json.in106
-rw-r--r--Utilities/Release/files-v1.rst186
-rwxr-xr-xUtilities/Release/files.bash84
-rw-r--r--Utilities/Release/linux/aarch64/Dockerfile35
-rw-r--r--Utilities/Release/linux/aarch64/base/Dockerfile31
-rw-r--r--Utilities/Release/linux/aarch64/cache.txt44
-rw-r--r--Utilities/Release/linux/aarch64/deps/Dockerfile141
-rw-r--r--Utilities/Release/linux/aarch64/deps/openssl-source.patch12
-rw-r--r--Utilities/Release/linux/aarch64/deps/qt-install.patch24
-rw-r--r--Utilities/Release/linux/aarch64/test/Dockerfile26
-rw-r--r--Utilities/Release/linux/aarch64/test/test-make.bash17
-rw-r--r--Utilities/Release/linux/aarch64/test/test-ninja.bash17
-rw-r--r--Utilities/Release/linux/x86_64/Dockerfile36
-rw-r--r--Utilities/Release/linux/x86_64/base/Dockerfile30
-rw-r--r--Utilities/Release/linux/x86_64/cache.txt44
-rw-r--r--Utilities/Release/linux/x86_64/deps/Dockerfile142
-rw-r--r--Utilities/Release/linux/x86_64/deps/openssl-source.patch12
-rw-r--r--Utilities/Release/linux/x86_64/deps/qt-install.patch24
-rw-r--r--Utilities/Release/linux/x86_64/test/Dockerfile26
-rw-r--r--Utilities/Release/linux/x86_64/test/test-make.bash17
-rw-r--r--Utilities/Release/linux/x86_64/test/test-ninja.bash17
-rwxr-xr-xUtilities/Release/macos/qt-5.15.2-macosx10.13-x86_64-arm64.bash125
-rwxr-xr-xUtilities/Release/macos/qt-5.9.9-macosx10.10-x86_64-arm64.bash135
-rw-r--r--Utilities/Release/macos/qt-5.9.9.patch20
-rwxr-xr-xUtilities/Release/push.bash73
-rw-r--r--Utilities/Release/win/x86/Dockerfile23
-rw-r--r--Utilities/Release/win/x86/base/Dockerfile30
-rwxr-xr-xUtilities/Release/win/x86/base/msvc-i386.bat1
-rwxr-xr-xUtilities/Release/win/x86/base/msvc-x86_64.bat1
-rwxr-xr-xUtilities/Release/win/x86/build.bat19
-rw-r--r--Utilities/Release/win/x86/cache-i386.txt45
-rw-r--r--Utilities/Release/win/x86/cache-x86_64.txt45
-rw-r--r--Utilities/Release/win/x86/deps/Dockerfile127
-rwxr-xr-xUtilities/Release/win/x86/deps/qt-build.bat47
-rw-r--r--Utilities/Release/win/x86/deps/qt-install.patch26
-rwxr-xr-xUtilities/Release/win/x86/pack.bat12
-rw-r--r--Utilities/Release/win/x86/test/Dockerfile37
-rwxr-xr-xUtilities/Release/win/x86/test/test-ninja.bat19
-rwxr-xr-xUtilities/Release/win/x86/test/test-nmake.bat19
-rw-r--r--Utilities/Scripts/BoostScanDeps.cmake238
-rwxr-xr-xUtilities/Scripts/clang-format.bash124
-rwxr-xr-xUtilities/Scripts/regenerate-lexers.bash57
-rwxr-xr-xUtilities/Scripts/regenerate-parsers.bash32
-rwxr-xr-xUtilities/Scripts/update-bzip2.bash27
-rwxr-xr-xUtilities/Scripts/update-curl.bash51
-rwxr-xr-xUtilities/Scripts/update-expat.bash49
-rwxr-xr-xUtilities/Scripts/update-gitsetup.bash27
-rwxr-xr-xUtilities/Scripts/update-jsoncpp.bash33
-rwxr-xr-xUtilities/Scripts/update-kwiml.bash20
-rwxr-xr-xUtilities/Scripts/update-kwsys.bash24
-rwxr-xr-xUtilities/Scripts/update-libarchive.bash32
-rwxr-xr-xUtilities/Scripts/update-liblzma.bash34
-rwxr-xr-xUtilities/Scripts/update-librhash.bash44
-rwxr-xr-xUtilities/Scripts/update-libuv.bash28
-rwxr-xr-xUtilities/Scripts/update-nghttp2.bash30
-rw-r--r--Utilities/Scripts/update-third-party.bash193
-rwxr-xr-xUtilities/Scripts/update-vim-syntax.bash24
-rwxr-xr-xUtilities/Scripts/update-zstd.bash36
-rwxr-xr-xUtilities/SetupForDevelopment.sh14
-rw-r--r--Utilities/Sphinx/.gitignore1
-rw-r--r--Utilities/Sphinx/CMakeLists.txt252
-rw-r--r--Utilities/Sphinx/CTestConfig.cmake16
-rw-r--r--Utilities/Sphinx/apply_qthelp_css_workaround.cmake19
-rw-r--r--Utilities/Sphinx/cmake.py472
-rw-r--r--Utilities/Sphinx/colors.py29
-rw-r--r--Utilities/Sphinx/conf.py.in87
-rwxr-xr-xUtilities/Sphinx/create_identifiers.py51
-rw-r--r--Utilities/Sphinx/fixup_qthelp_names.cmake23
-rw-r--r--Utilities/Sphinx/static/cmake-favicon.icobin0 -> 1150 bytes-rw-r--r--Utilities/Sphinx/static/cmake-logo-16.pngbin0 -> 692 bytes-rw-r--r--Utilities/Sphinx/static/cmake.css24
-rw-r--r--Utilities/Sphinx/templates/layout.html31
-rwxr-xr-xUtilities/Sphinx/update_versions.py115
-rw-r--r--Utilities/cm3p/Setup.Configuration.h5
-rw-r--r--Utilities/cm3p/archive.h11
-rw-r--r--Utilities/cm3p/archive_entry.h11
-rw-r--r--Utilities/cm3p/bzlib.h11
-rw-r--r--Utilities/cm3p/curl/curl.h11
-rw-r--r--Utilities/cm3p/expat.h11
-rw-r--r--Utilities/cm3p/json/reader.h11
-rw-r--r--Utilities/cm3p/json/value.h11
-rw-r--r--Utilities/cm3p/json/writer.h11
-rw-r--r--Utilities/cm3p/kwiml/abi.h11
-rw-r--r--Utilities/cm3p/kwiml/int.h11
-rw-r--r--Utilities/cm3p/lzma.h11
-rw-r--r--Utilities/cm3p/rhash.h11
-rw-r--r--Utilities/cm3p/uv.h11
-rw-r--r--Utilities/cm3p/zlib.h11
-rw-r--r--Utilities/cm3p/zstd.h11
-rw-r--r--Utilities/cmThirdParty.h.in17
-rw-r--r--Utilities/cmThirdPartyChecks.cmake296
-rw-r--r--Utilities/cmbzip2/.gitattributes1
-rw-r--r--Utilities/cmbzip2/CMakeLists.txt13
-rw-r--r--Utilities/cmbzip2/LICENSE42
-rw-r--r--Utilities/cmbzip2/README196
-rw-r--r--Utilities/cmbzip2/blocksort.c1094
-rw-r--r--Utilities/cmbzip2/bzip2.c2036
-rw-r--r--Utilities/cmbzip2/bzip2recover.c516
-rw-r--r--Utilities/cmbzip2/bzlib.c1572
-rw-r--r--Utilities/cmbzip2/bzlib.h282
-rw-r--r--Utilities/cmbzip2/bzlib_private.h511
-rw-r--r--Utilities/cmbzip2/compress.c672
-rw-r--r--Utilities/cmbzip2/crctable.c104
-rw-r--r--Utilities/cmbzip2/decompress.c652
-rw-r--r--Utilities/cmbzip2/dlltest.c175
-rw-r--r--Utilities/cmbzip2/huffman.c205
-rw-r--r--Utilities/cmbzip2/mk251.c31
-rw-r--r--Utilities/cmbzip2/randtable.c84
-rw-r--r--Utilities/cmbzip2/spewG.c54
-rw-r--r--Utilities/cmbzip2/unzcrash.c141
-rw-r--r--Utilities/cmcurl/.gitattributes1
-rw-r--r--Utilities/cmcurl/CMake/CMakeConfigurableFile.in22
-rw-r--r--Utilities/cmcurl/CMake/CurlSymbolHiding.cmake76
-rw-r--r--Utilities/cmcurl/CMake/CurlTests.c617
-rw-r--r--Utilities/cmcurl/CMake/FindBearSSL.cmake30
-rw-r--r--Utilities/cmcurl/CMake/FindBrotli.cmake41
-rw-r--r--Utilities/cmcurl/CMake/FindCARES.cmake45
-rw-r--r--Utilities/cmcurl/CMake/FindGSS.cmake310
-rw-r--r--Utilities/cmcurl/CMake/FindLibSSH2.cmake43
-rw-r--r--Utilities/cmcurl/CMake/FindMbedTLS.cmake34
-rw-r--r--Utilities/cmcurl/CMake/FindNGHTTP2.cmake39
-rw-r--r--Utilities/cmcurl/CMake/FindNGHTTP3.cmake76
-rw-r--r--Utilities/cmcurl/CMake/FindNGTCP2.cmake113
-rw-r--r--Utilities/cmcurl/CMake/FindNSS.cmake38
-rw-r--r--Utilities/cmcurl/CMake/FindQUICHE.cmake68
-rw-r--r--Utilities/cmcurl/CMake/FindWolfSSL.cmake34
-rw-r--r--Utilities/cmcurl/CMake/FindZstd.cmake69
-rw-r--r--Utilities/cmcurl/CMake/Macros.cmake120
-rw-r--r--Utilities/cmcurl/CMake/OtherTests.cmake308
-rw-r--r--Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake141
-rw-r--r--Utilities/cmcurl/CMake/Utilities.cmake33
-rw-r--r--Utilities/cmcurl/CMake/cmake_uninstall.cmake.in47
-rw-r--r--Utilities/cmcurl/CMake/curl-config.cmake.in33
-rw-r--r--Utilities/cmcurl/CMakeLists.txt1710
-rw-r--r--Utilities/cmcurl/COPYING22
-rw-r--r--Utilities/cmcurl/curltest.c81
-rw-r--r--Utilities/cmcurl/include/curl/curl.h3039
-rw-r--r--Utilities/cmcurl/include/curl/curlver.h77
-rw-r--r--Utilities/cmcurl/include/curl/easy.h123
-rw-r--r--Utilities/cmcurl/include/curl/mprintf.h50
-rw-r--r--Utilities/cmcurl/include/curl/multi.h456
-rw-r--r--Utilities/cmcurl/include/curl/options.h68
-rw-r--r--Utilities/cmcurl/include/curl/stdcheaders.h33
-rw-r--r--Utilities/cmcurl/include/curl/system.h504
-rw-r--r--Utilities/cmcurl/include/curl/typecheck-gcc.h705
-rw-r--r--Utilities/cmcurl/include/curl/urlapi.h125
-rw-r--r--Utilities/cmcurl/lib/CMakeLists.txt169
-rw-r--r--Utilities/cmcurl/lib/Makefile.inc337
-rw-r--r--Utilities/cmcurl/lib/altsvc.c647
-rw-r--r--Utilities/cmcurl/lib/altsvc.h79
-rw-r--r--Utilities/cmcurl/lib/amigaos.c95
-rw-r--r--Utilities/cmcurl/lib/amigaos.h44
-rw-r--r--Utilities/cmcurl/lib/arpa_telnet.h108
-rw-r--r--Utilities/cmcurl/lib/asyn-ares.c815
-rw-r--r--Utilities/cmcurl/lib/asyn-thread.c805
-rw-r--r--Utilities/cmcurl/lib/asyn.h182
-rw-r--r--Utilities/cmcurl/lib/base64.c329
-rw-r--r--Utilities/cmcurl/lib/c-hyper.c908
-rw-r--r--Utilities/cmcurl/lib/c-hyper.h56
-rw-r--r--Utilities/cmcurl/lib/conncache.c608
-rw-r--r--Utilities/cmcurl/lib/conncache.h119
-rw-r--r--Utilities/cmcurl/lib/connect.c1654
-rw-r--r--Utilities/cmcurl/lib/connect.h156
-rw-r--r--Utilities/cmcurl/lib/content_encoding.c1110
-rw-r--r--Utilities/cmcurl/lib/content_encoding.h55
-rw-r--r--Utilities/cmcurl/lib/cookie.c1686
-rw-r--r--Utilities/cmcurl/lib/cookie.h120
-rw-r--r--Utilities/cmcurl/lib/curl_addrinfo.c595
-rw-r--r--Utilities/cmcurl/lib/curl_addrinfo.h106
-rw-r--r--Utilities/cmcurl/lib/curl_base64.h35
-rw-r--r--Utilities/cmcurl/lib/curl_config.h.cmake1091
-rw-r--r--Utilities/cmcurl/lib/curl_ctype.c133
-rw-r--r--Utilities/cmcurl/lib/curl_ctype.h81
-rw-r--r--Utilities/cmcurl/lib/curl_des.c63
-rw-r--r--Utilities/cmcurl/lib/curl_des.h34
-rw-r--r--Utilities/cmcurl/lib/curl_endian.c124
-rw-r--r--Utilities/cmcurl/lib/curl_endian.h43
-rw-r--r--Utilities/cmcurl/lib/curl_fnmatch.c389
-rw-r--r--Utilities/cmcurl/lib/curl_fnmatch.h44
-rw-r--r--Utilities/cmcurl/lib/curl_get_line.c60
-rw-r--r--Utilities/cmcurl/lib/curl_get_line.h29
-rw-r--r--Utilities/cmcurl/lib/curl_gethostname.c100
-rw-r--r--Utilities/cmcurl/lib/curl_gethostname.h31
-rw-r--r--Utilities/cmcurl/lib/curl_gssapi.c140
-rw-r--r--Utilities/cmcurl/lib/curl_gssapi.h61
-rw-r--r--Utilities/cmcurl/lib/curl_hmac.h72
-rw-r--r--Utilities/cmcurl/lib/curl_krb5.h51
-rw-r--r--Utilities/cmcurl/lib/curl_ldap.h34
-rw-r--r--Utilities/cmcurl/lib/curl_md4.h36
-rw-r--r--Utilities/cmcurl/lib/curl_md5.h63
-rw-r--r--Utilities/cmcurl/lib/curl_memory.h156
-rw-r--r--Utilities/cmcurl/lib/curl_memrchr.c62
-rw-r--r--Utilities/cmcurl/lib/curl_memrchr.h44
-rw-r--r--Utilities/cmcurl/lib/curl_multibyte.c153
-rw-r--r--Utilities/cmcurl/lib/curl_multibyte.h90
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_core.c741
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_core.h105
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_wb.c497
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_wb.h43
-rw-r--r--Utilities/cmcurl/lib/curl_path.c198
-rw-r--r--Utilities/cmcurl/lib/curl_path.h47
-rw-r--r--Utilities/cmcurl/lib/curl_printf.h48
-rw-r--r--Utilities/cmcurl/lib/curl_range.c94
-rw-r--r--Utilities/cmcurl/lib/curl_range.h29
-rw-r--r--Utilities/cmcurl/lib/curl_rtmp.c330
-rw-r--r--Utilities/cmcurl/lib/curl_rtmp.h33
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.c643
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.h147
-rw-r--r--Utilities/cmcurl/lib/curl_setup.h816
-rw-r--r--Utilities/cmcurl/lib/curl_setup_once.h499
-rw-r--r--Utilities/cmcurl/lib/curl_sha256.h38
-rw-r--r--Utilities/cmcurl/lib/curl_sspi.c237
-rw-r--r--Utilities/cmcurl/lib/curl_sspi.h350
-rw-r--r--Utilities/cmcurl/lib/curl_threads.c155
-rw-r--r--Utilities/cmcurl/lib/curl_threads.h64
-rw-r--r--Utilities/cmcurl/lib/curlx.h116
-rw-r--r--Utilities/cmcurl/lib/dict.c323
-rw-r--r--Utilities/cmcurl/lib/dict.h29
-rw-r--r--Utilities/cmcurl/lib/doh.c1005
-rw-r--r--Utilities/cmcurl/lib/doh.h109
-rw-r--r--Utilities/cmcurl/lib/dotdot.c182
-rw-r--r--Utilities/cmcurl/lib/dotdot.h25
-rw-r--r--Utilities/cmcurl/lib/dynbuf.c255
-rw-r--r--Utilities/cmcurl/lib/dynbuf.h88
-rw-r--r--Utilities/cmcurl/lib/easy.c1260
-rw-r--r--Utilities/cmcurl/lib/easygetopt.c96
-rw-r--r--Utilities/cmcurl/lib/easyif.h32
-rw-r--r--Utilities/cmcurl/lib/easyoptions.c354
-rw-r--r--Utilities/cmcurl/lib/easyoptions.h35
-rw-r--r--Utilities/cmcurl/lib/escape.c246
-rw-r--r--Utilities/cmcurl/lib/escape.h40
-rw-r--r--Utilities/cmcurl/lib/file.c539
-rw-r--r--Utilities/cmcurl/lib/file.h40
-rw-r--r--Utilities/cmcurl/lib/fileinfo.c44
-rw-r--r--Utilities/cmcurl/lib/fileinfo.h36
-rw-r--r--Utilities/cmcurl/lib/formdata.c946
-rw-r--r--Utilities/cmcurl/lib/formdata.h60
-rw-r--r--Utilities/cmcurl/lib/ftp.c4372
-rw-r--r--Utilities/cmcurl/lib/ftp.h156
-rw-r--r--Utilities/cmcurl/lib/ftplistparser.c1019
-rw-r--r--Utilities/cmcurl/lib/ftplistparser.h41
-rw-r--r--Utilities/cmcurl/lib/getenv.c77
-rw-r--r--Utilities/cmcurl/lib/getinfo.c602
-rw-r--r--Utilities/cmcurl/lib/getinfo.h27
-rw-r--r--Utilities/cmcurl/lib/gopher.c235
-rw-r--r--Utilities/cmcurl/lib/gopher.h32
-rw-r--r--Utilities/cmcurl/lib/hash.c351
-rw-r--r--Utilities/cmcurl/lib/hash.h100
-rw-r--r--Utilities/cmcurl/lib/hmac.c170
-rw-r--r--Utilities/cmcurl/lib/hostasyn.c126
-rw-r--r--Utilities/cmcurl/lib/hostcheck.c150
-rw-r--r--Utilities/cmcurl/lib/hostcheck.h31
-rw-r--r--Utilities/cmcurl/lib/hostip.c1118
-rw-r--r--Utilities/cmcurl/lib/hostip.h248
-rw-r--r--Utilities/cmcurl/lib/hostip4.c299
-rw-r--r--Utilities/cmcurl/lib/hostip6.c202
-rw-r--r--Utilities/cmcurl/lib/hostsyn.c107
-rw-r--r--Utilities/cmcurl/lib/hsts.c522
-rw-r--r--Utilities/cmcurl/lib/hsts.h65
-rw-r--r--Utilities/cmcurl/lib/http.c4268
-rw-r--r--Utilities/cmcurl/lib/http.h313
-rw-r--r--Utilities/cmcurl/lib/http2.c2451
-rw-r--r--Utilities/cmcurl/lib/http2.h83
-rw-r--r--Utilities/cmcurl/lib/http_aws_sigv4.c394
-rw-r--r--Utilities/cmcurl/lib/http_aws_sigv4.h29
-rw-r--r--Utilities/cmcurl/lib/http_chunks.c343
-rw-r--r--Utilities/cmcurl/lib/http_chunks.h98
-rw-r--r--Utilities/cmcurl/lib/http_digest.c183
-rw-r--r--Utilities/cmcurl/lib/http_digest.h43
-rw-r--r--Utilities/cmcurl/lib/http_negotiate.c222
-rw-r--r--Utilities/cmcurl/lib/http_negotiate.h41
-rw-r--r--Utilities/cmcurl/lib/http_ntlm.c258
-rw-r--r--Utilities/cmcurl/lib/http_ntlm.h42
-rw-r--r--Utilities/cmcurl/lib/http_proxy.c911
-rw-r--r--Utilities/cmcurl/lib/http_proxy.h52
-rw-r--r--Utilities/cmcurl/lib/idn_win32.c111
-rw-r--r--Utilities/cmcurl/lib/if2ip.c246
-rw-r--r--Utilities/cmcurl/lib/if2ip.h82
-rw-r--r--Utilities/cmcurl/lib/imap.c2121
-rw-r--r--Utilities/cmcurl/lib/imap.h99
-rw-r--r--Utilities/cmcurl/lib/inet_ntop.c197
-rw-r--r--Utilities/cmcurl/lib/inet_ntop.h37
-rw-r--r--Utilities/cmcurl/lib/inet_pton.c237
-rw-r--r--Utilities/cmcurl/lib/inet_pton.h39
-rw-r--r--Utilities/cmcurl/lib/krb5.c912
-rw-r--r--Utilities/cmcurl/lib/ldap.c1077
-rw-r--r--Utilities/cmcurl/lib/libcurl.rc63
-rw-r--r--Utilities/cmcurl/lib/llist.c146
-rw-r--r--Utilities/cmcurl/lib/llist.h50
-rw-r--r--Utilities/cmcurl/lib/md4.c529
-rw-r--r--Utilities/cmcurl/lib/md5.c623
-rw-r--r--Utilities/cmcurl/lib/memdebug.c462
-rw-r--r--Utilities/cmcurl/lib/memdebug.h177
-rw-r--r--Utilities/cmcurl/lib/mime.c2060
-rw-r--r--Utilities/cmcurl/lib/mime.h170
-rw-r--r--Utilities/cmcurl/lib/mprintf.c1157
-rw-r--r--Utilities/cmcurl/lib/mqtt.c637
-rw-r--r--Utilities/cmcurl/lib/mqtt.h59
-rw-r--r--Utilities/cmcurl/lib/multi.c3416
-rw-r--r--Utilities/cmcurl/lib/multihandle.h156
-rw-r--r--Utilities/cmcurl/lib/multiif.h98
-rw-r--r--Utilities/cmcurl/lib/netrc.c278
-rw-r--r--Utilities/cmcurl/lib/netrc.h45
-rw-r--r--Utilities/cmcurl/lib/non-ascii.c332
-rw-r--r--Utilities/cmcurl/lib/non-ascii.h61
-rw-r--r--Utilities/cmcurl/lib/nonblock.c91
-rw-r--r--Utilities/cmcurl/lib/nonblock.h30
-rw-r--r--Utilities/cmcurl/lib/nwlib.c327
-rw-r--r--Utilities/cmcurl/lib/nwos.c88
-rw-r--r--Utilities/cmcurl/lib/openldap.c766
-rw-r--r--Utilities/cmcurl/lib/parsedate.c601
-rw-r--r--Utilities/cmcurl/lib/parsedate.h36
-rw-r--r--Utilities/cmcurl/lib/pingpong.c510
-rw-r--r--Utilities/cmcurl/lib/pingpong.h163
-rw-r--r--Utilities/cmcurl/lib/pop3.c1554
-rw-r--r--Utilities/cmcurl/lib/pop3.h95
-rw-r--r--Utilities/cmcurl/lib/progress.c624
-rw-r--r--Utilities/cmcurl/lib/progress.h64
-rw-r--r--Utilities/cmcurl/lib/psl.c111
-rw-r--r--Utilities/cmcurl/lib/psl.h47
-rw-r--r--Utilities/cmcurl/lib/quic.h62
-rw-r--r--Utilities/cmcurl/lib/rand.c186
-rw-r--r--Utilities/cmcurl/lib/rand.h49
-rw-r--r--Utilities/cmcurl/lib/rename.c71
-rw-r--r--Utilities/cmcurl/lib/rename.h27
-rw-r--r--Utilities/cmcurl/lib/rtsp.c836
-rw-r--r--Utilities/cmcurl/lib/rtsp.h70
-rw-r--r--Utilities/cmcurl/lib/select.c472
-rw-r--r--Utilities/cmcurl/lib/select.h118
-rw-r--r--Utilities/cmcurl/lib/sendf.c782
-rw-r--r--Utilities/cmcurl/lib/sendf.h90
-rw-r--r--Utilities/cmcurl/lib/setopt.c2963
-rw-r--r--Utilities/cmcurl/lib/setopt.h30
-rw-r--r--Utilities/cmcurl/lib/setup-os400.h227
-rw-r--r--Utilities/cmcurl/lib/setup-vms.h443
-rw-r--r--Utilities/cmcurl/lib/setup-win32.h122
-rw-r--r--Utilities/cmcurl/lib/sha256.c517
-rw-r--r--Utilities/cmcurl/lib/share.c264
-rw-r--r--Utilities/cmcurl/lib/share.h70
-rw-r--r--Utilities/cmcurl/lib/sigpipe.h79
-rw-r--r--Utilities/cmcurl/lib/slist.c144
-rw-r--r--Utilities/cmcurl/lib/slist.h39
-rw-r--r--Utilities/cmcurl/lib/smb.c1025
-rw-r--r--Utilities/cmcurl/lib/smb.h255
-rw-r--r--Utilities/cmcurl/lib/smtp.c1897
-rw-r--r--Utilities/cmcurl/lib/smtp.h96
-rw-r--r--Utilities/cmcurl/lib/sockaddr.h42
-rw-r--r--Utilities/cmcurl/lib/socketpair.c121
-rw-r--r--Utilities/cmcurl/lib/socketpair.h36
-rw-r--r--Utilities/cmcurl/lib/socks.c1031
-rw-r--r--Utilities/cmcurl/lib/socks.h80
-rw-r--r--Utilities/cmcurl/lib/socks_gssapi.c532
-rw-r--r--Utilities/cmcurl/lib/socks_sspi.c609
-rw-r--r--Utilities/cmcurl/lib/speedcheck.c77
-rw-r--r--Utilities/cmcurl/lib/speedcheck.h33
-rw-r--r--Utilities/cmcurl/lib/splay.c276
-rw-r--r--Utilities/cmcurl/lib/splay.h56
-rw-r--r--Utilities/cmcurl/lib/strcase.c263
-rw-r--r--Utilities/cmcurl/lib/strcase.h51
-rw-r--r--Utilities/cmcurl/lib/strdup.c95
-rw-r--r--Utilities/cmcurl/lib/strdup.h32
-rw-r--r--Utilities/cmcurl/lib/strerror.c1007
-rw-r--r--Utilities/cmcurl/lib/strerror.h37
-rw-r--r--Utilities/cmcurl/lib/strtok.c66
-rw-r--r--Utilities/cmcurl/lib/strtok.h34
-rw-r--r--Utilities/cmcurl/lib/strtoofft.c242
-rw-r--r--Utilities/cmcurl/lib/strtoofft.h52
-rw-r--r--Utilities/cmcurl/lib/system_win32.c237
-rw-r--r--Utilities/cmcurl/lib/system_win32.h46
-rw-r--r--Utilities/cmcurl/lib/telnet.c1585
-rw-r--r--Utilities/cmcurl/lib/telnet.h28
-rw-r--r--Utilities/cmcurl/lib/tftp.c1437
-rw-r--r--Utilities/cmcurl/lib/tftp.h28
-rw-r--r--Utilities/cmcurl/lib/timeval.c206
-rw-r--r--Utilities/cmcurl/lib/timeval.h58
-rw-r--r--Utilities/cmcurl/lib/transfer.c1910
-rw-r--r--Utilities/cmcurl/lib/transfer.h71
-rw-r--r--Utilities/cmcurl/lib/url.c4101
-rw-r--r--Utilities/cmcurl/lib/url.h81
-rw-r--r--Utilities/cmcurl/lib/urlapi-int.h34
-rw-r--r--Utilities/cmcurl/lib/urlapi.c1484
-rw-r--r--Utilities/cmcurl/lib/urldata.h1957
-rw-r--r--Utilities/cmcurl/lib/vauth/cleartext.c170
-rw-r--r--Utilities/cmcurl/lib/vauth/cram.c138
-rw-r--r--Utilities/cmcurl/lib/vauth/digest.c999
-rw-r--r--Utilities/cmcurl/lib/vauth/digest.h47
-rw-r--r--Utilities/cmcurl/lib/vauth/digest_sspi.c694
-rw-r--r--Utilities/cmcurl/lib/vauth/krb5_gssapi.c401
-rw-r--r--Utilities/cmcurl/lib/vauth/krb5_sspi.c533
-rw-r--r--Utilities/cmcurl/lib/vauth/ntlm.c875
-rw-r--r--Utilities/cmcurl/lib/vauth/ntlm.h143
-rw-r--r--Utilities/cmcurl/lib/vauth/ntlm_sspi.c383
-rw-r--r--Utilities/cmcurl/lib/vauth/oauth2.c126
-rw-r--r--Utilities/cmcurl/lib/vauth/spnego_gssapi.c282
-rw-r--r--Utilities/cmcurl/lib/vauth/spnego_sspi.c371
-rw-r--r--Utilities/cmcurl/lib/vauth/vauth.c147
-rw-r--r--Utilities/cmcurl/lib/vauth/vauth.h215
-rw-r--r--Utilities/cmcurl/lib/version.c567
-rw-r--r--Utilities/cmcurl/lib/version_win32.c226
-rw-r--r--Utilities/cmcurl/lib/version_win32.h53
-rw-r--r--Utilities/cmcurl/lib/vquic/ngtcp2.c1929
-rw-r--r--Utilities/cmcurl/lib/vquic/ngtcp2.h74
-rw-r--r--Utilities/cmcurl/lib/vquic/quiche.c871
-rw-r--r--Utilities/cmcurl/lib/vquic/quiche.h50
-rw-r--r--Utilities/cmcurl/lib/vquic/vquic.c85
-rw-r--r--Utilities/cmcurl/lib/vquic/vquic.h34
-rw-r--r--Utilities/cmcurl/lib/vssh/libssh.c2923
-rw-r--r--Utilities/cmcurl/lib/vssh/libssh2.c3609
-rw-r--r--Utilities/cmcurl/lib/vssh/ssh.h271
-rw-r--r--Utilities/cmcurl/lib/vssh/wolfssh.c1167
-rw-r--r--Utilities/cmcurl/lib/vssh/wolfssh.h27
-rw-r--r--Utilities/cmcurl/lib/vtls/bearssl.c869
-rw-r--r--Utilities/cmcurl/lib/vtls/bearssl.h32
-rw-r--r--Utilities/cmcurl/lib/vtls/gskit.c1288
-rw-r--r--Utilities/cmcurl/lib/vtls/gskit.h38
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.c1685
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.h34
-rw-r--r--Utilities/cmcurl/lib/vtls/keylog.c156
-rw-r--r--Utilities/cmcurl/lib/vtls/keylog.h56
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls.c1114
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls.h32
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c144
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h48
-rw-r--r--Utilities/cmcurl/lib/vtls/mesalink.c668
-rw-r--r--Utilities/cmcurl/lib/vtls/mesalink.h32
-rw-r--r--Utilities/cmcurl/lib/vtls/nss.c2450
-rw-r--r--Utilities/cmcurl/lib/vtls/nssg.h39
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.c4495
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.h37
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.c2432
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.h109
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel_verify.c699
-rw-r--r--Utilities/cmcurl/lib/vtls/sectransp.c3319
-rw-r--r--Utilities/cmcurl/lib/vtls/sectransp.h32
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.c1397
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.h293
-rw-r--r--Utilities/cmcurl/lib/vtls/wolfssl.c1166
-rw-r--r--Utilities/cmcurl/lib/vtls/wolfssl.h31
-rw-r--r--Utilities/cmcurl/lib/warnless.c489
-rw-r--r--Utilities/cmcurl/lib/warnless.h97
-rw-r--r--Utilities/cmcurl/lib/wildcard.c73
-rw-r--r--Utilities/cmcurl/lib/wildcard.h67
-rw-r--r--Utilities/cmcurl/lib/x509asn1.c1280
-rw-r--r--Utilities/cmcurl/lib/x509asn1.h133
-rw-r--r--Utilities/cmexpat/.gitattributes1
-rw-r--r--Utilities/cmexpat/CMakeLists.txt25
-rw-r--r--Utilities/cmexpat/COPYING21
-rw-r--r--Utilities/cmexpat/ConfigureChecks.cmake55
-rw-r--r--Utilities/cmexpat/README.md194
-rw-r--r--Utilities/cmexpat/expat_config.h.cmake88
-rw-r--r--Utilities/cmexpat/lib/ascii.h120
-rw-r--r--Utilities/cmexpat/lib/asciitab.h64
-rw-r--r--Utilities/cmexpat/lib/expat.h1024
-rw-r--r--Utilities/cmexpat/lib/expat_external.h161
-rw-r--r--Utilities/cmexpat/lib/iasciitab.h65
-rw-r--r--Utilities/cmexpat/lib/internal.h123
-rw-r--r--Utilities/cmexpat/lib/latin1tab.h64
-rw-r--r--Utilities/cmexpat/lib/nametab.h136
-rw-r--r--Utilities/cmexpat/lib/siphash.h401
-rw-r--r--Utilities/cmexpat/lib/utf8tab.h64
-rw-r--r--Utilities/cmexpat/lib/winconfig.h61
-rw-r--r--Utilities/cmexpat/lib/xmlparse.c6914
-rw-r--r--Utilities/cmexpat/lib/xmlrole.c1249
-rw-r--r--Utilities/cmexpat/lib/xmlrole.h139
-rw-r--r--Utilities/cmexpat/lib/xmltok.c1672
-rw-r--r--Utilities/cmexpat/lib/xmltok.h315
-rw-r--r--Utilities/cmexpat/lib/xmltok_impl.c1805
-rw-r--r--Utilities/cmexpat/lib/xmltok_impl.h73
-rw-r--r--Utilities/cmexpat/lib/xmltok_ns.c118
-rw-r--r--Utilities/cmjsoncpp/.gitattributes1
-rw-r--r--Utilities/cmjsoncpp/CMakeLists.txt25
-rw-r--r--Utilities/cmjsoncpp/LICENSE55
-rw-r--r--Utilities/cmjsoncpp/README-CMake.txt66
-rw-r--r--Utilities/cmjsoncpp/include/json/allocator.h102
-rw-r--r--Utilities/cmjsoncpp/include/json/assertions.h54
-rw-r--r--Utilities/cmjsoncpp/include/json/config.h194
-rw-r--r--Utilities/cmjsoncpp/include/json/features.h65
-rw-r--r--Utilities/cmjsoncpp/include/json/forwards.h37
-rw-r--r--Utilities/cmjsoncpp/include/json/json.h14
-rw-r--r--Utilities/cmjsoncpp/include/json/reader.h415
-rw-r--r--Utilities/cmjsoncpp/include/json/value.h891
-rw-r--r--Utilities/cmjsoncpp/include/json/version.h20
-rw-r--r--Utilities/cmjsoncpp/include/json/writer.h342
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_reader.cpp2172
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_tool.h117
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_value.cpp1913
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_valueiterator.inl167
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_writer.cpp1372
-rw-r--r--Utilities/cmlibarchive/.gitattributes1
-rw-r--r--Utilities/cmlibarchive/CMakeLists.txt2028
-rw-r--r--Utilities/cmlibarchive/COPYING66
-rw-r--r--Utilities/cmlibarchive/CTestConfig.cmake11
-rw-r--r--Utilities/cmlibarchive/build/cmake/CheckFileOffsetBits.c14
-rw-r--r--Utilities/cmlibarchive/build/cmake/CheckFileOffsetBits.cmake44
-rw-r--r--Utilities/cmlibarchive/build/cmake/CheckFuncs.cmake49
-rw-r--r--Utilities/cmlibarchive/build/cmake/CheckFuncs_stub.c.in16
-rw-r--r--Utilities/cmlibarchive/build/cmake/CheckHeaderDirent.cmake32
-rw-r--r--Utilities/cmlibarchive/build/cmake/CheckTypeExists.cmake42
-rw-r--r--Utilities/cmlibarchive/build/cmake/CreatePkgConfigFile.cmake33
-rw-r--r--Utilities/cmlibarchive/build/cmake/FindLibGCC.cmake22
-rw-r--r--Utilities/cmlibarchive/build/cmake/FindMbedTLS.cmake13
-rw-r--r--Utilities/cmlibarchive/build/cmake/FindNettle.cmake23
-rw-r--r--Utilities/cmlibarchive/build/cmake/FindPCREPOSIX.cmake34
-rw-r--r--Utilities/cmlibarchive/build/cmake/LibarchiveCodeCoverage.cmake68
-rw-r--r--Utilities/cmlibarchive/build/cmake/config.h.in1159
-rw-r--r--Utilities/cmlibarchive/build/pkgconfig/libarchive.pc.in12
-rwxr-xr-xUtilities/cmlibarchive/build/utils/gen_archive_string_composition_h.sh455
-rw-r--r--Utilities/cmlibarchive/build/version1
-rw-r--r--Utilities/cmlibarchive/libarchive/CMakeLists.txt270
-rw-r--r--Utilities/cmlibarchive/libarchive/archive.h1194
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_acl.c2097
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_acl_private.h83
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_blake2.h195
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_blake2_impl.h161
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_blake2s_ref.c367
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_blake2sp_ref.c359
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_check_magic.c175
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_cmdline.c227
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_cmdline_private.h47
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_crc32.h83
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_cryptor.c519
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_cryptor_private.h179
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_digest.c1691
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_digest_private.h412
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_disk_acl_darwin.c559
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_disk_acl_freebsd.c702
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_disk_acl_linux.c743
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_disk_acl_sunos.c819
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_endian.h195
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry.3149
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry.c2066
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry.h705
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_acl.3458
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_copy_bhfi.c75
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_copy_stat.c83
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_link_resolver.c447
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_linkify.3224
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_locale.h92
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_misc.363
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_paths.3153
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_perms.3209
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_private.h184
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_sparse.c156
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_stat.3274
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_stat.c118
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_strmode.c87
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_time.3129
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_xattr.c156
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_getdate.c1167
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_getdate.h39
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_hmac.c305
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_hmac_private.h110
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_match.c1875
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h53
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h54
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_options.c218
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_options_private.h51
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_pack_dev.c336
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_pack_dev.h49
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_pathmatch.c459
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_pathmatch.h52
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_platform.h195
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_platform_acl.h55
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_platform_xattr.h47
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_ppmd7.c1168
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h119
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_ppmd8.c1287
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_ppmd8_private.h148
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_ppmd_private.h151
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_private.h176
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_random.c272
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_random_private.h36
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_rb.c709
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_rb.h113
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read.3252
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read.c1751
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.374
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.c186
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_append_filter.c204
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_data.3130
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_data_into_fd.c139
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk.3346
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c1044
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c2722
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk_private.h98
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk_set_standard_lookup.c313
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c2477
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_extract.3137
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_extract.c60
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_extract2.c155
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_filter.3154
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_format.3177
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_free.393
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_header.391
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_new.359
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_open.3233
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_open_fd.c211
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_open_file.c180
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_open_filename.c582
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_open_memory.c186
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_private.h266
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_set_format.c108
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_set_options.3262
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_set_options.c155
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_all.c85
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_bzip2.c371
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_compress.c465
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_grzip.c121
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_gzip.c535
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_lrzip.c132
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c742
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c494
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_none.c52
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c518
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_rpm.c289
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c685
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c796
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c292
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c3873
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_all.c89
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c638
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_by_code.c77
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c3227
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c1086
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_empty.c96
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c3278
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c2915
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c2025
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c2999
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_rar5.c4103
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_raw.c192
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c2904
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_warc.c832
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c3319
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c4044
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_string.c4224
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_string.h243
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_string_composition.h2292
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_string_sprintf.c192
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_util.3224
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_util.c649
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_version_details.c151
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_virtual.c163
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_windows.c909
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_windows.h321
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write.3268
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write.c789
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter.c72
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_b64encode.c304
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_by_name.c77
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_bzip2.c401
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_compress.c447
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_grzip.c135
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_gzip.c442
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_lrzip.c197
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_lz4.c700
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_lzop.c478
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_none.c43
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_program.c409
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_uuencode.c295
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c545
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c325
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_blocksize.3114
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_data.390
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_disk.3362
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c4536
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_disk_private.h45
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_disk_set_standard_lookup.c263
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c2825
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_filter.3134
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_finish_entry.379
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_format.3175
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_free.396
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_header.373
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_new.358
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_open.3246
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_open_fd.c144
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_open_file.c109
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_open_filename.c253
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_open_memory.c113
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_private.h164
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format.c123
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c2317
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c570
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c92
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c500
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_newc.c457
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_filter_by_ext.c142
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_gnutar.c755
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c8162
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c2228
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c2044
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_private.h42
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_raw.c125
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_shar.c641
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_ustar.c758
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_v7tar.c638
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_warc.c453
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c3258
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c1695
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_options.3707
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_options.c130
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_passphrase.374
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_passphrase.c95
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_xxhash.h48
-rw-r--r--Utilities/cmlibarchive/libarchive/config_freebsd.h260
-rw-r--r--Utilities/cmlibarchive/libarchive/cpio.5325
-rw-r--r--Utilities/cmlibarchive/libarchive/filter_fork.h41
-rw-r--r--Utilities/cmlibarchive/libarchive/filter_fork_posix.c238
-rw-r--r--Utilities/cmlibarchive/libarchive/filter_fork_windows.c190
-rw-r--r--Utilities/cmlibarchive/libarchive/libarchive-formats.5465
-rw-r--r--Utilities/cmlibarchive/libarchive/libarchive.3289
-rw-r--r--Utilities/cmlibarchive/libarchive/libarchive_changes.3341
-rw-r--r--Utilities/cmlibarchive/libarchive/libarchive_internals.3365
-rw-r--r--Utilities/cmlibarchive/libarchive/mtree.5324
-rw-r--r--Utilities/cmlibarchive/libarchive/tar.5949
-rw-r--r--Utilities/cmlibarchive/libarchive/xxhash.c521
-rw-r--r--Utilities/cmliblzma/.gitattributes1
-rw-r--r--Utilities/cmliblzma/CMakeLists.txt169
-rw-r--r--Utilities/cmliblzma/COPYING65
-rw-r--r--Utilities/cmliblzma/common/common_w32res.rc50
-rw-r--r--Utilities/cmliblzma/common/sysdefs.h213
-rw-r--r--Utilities/cmliblzma/common/tuklib_integer.h525
-rw-r--r--Utilities/cmliblzma/config.h.in120
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma.h325
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/base.h659
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/bcj.h90
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/block.h581
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/check.h150
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/container.h632
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/delta.h77
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/filter.h425
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/hardware.h64
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/index.h686
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/index_hash.h107
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/lzma12.h420
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/stream_flags.h223
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/version.h121
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/vli.h166
-rw-r--r--Utilities/cmliblzma/liblzma/check/check.c174
-rw-r--r--Utilities/cmliblzma/liblzma/check/check.h172
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc32_fast.c82
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc32_small.c61
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc32_table.c19
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc32_table_be.h525
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc32_table_le.h525
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc32_tablegen.c117
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc32_x86.S304
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc64_fast.c72
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc64_small.c53
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc64_table.c19
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc64_table_be.h521
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc64_table_le.h521
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc64_tablegen.c88
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc64_x86.S287
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc_macros.h30
-rw-r--r--Utilities/cmliblzma/liblzma/check/sha256.c196
-rw-r--r--Utilities/cmliblzma/liblzma/common/alone_decoder.c243
-rw-r--r--Utilities/cmliblzma/liblzma/common/alone_decoder.h23
-rw-r--r--Utilities/cmliblzma/liblzma/common/alone_encoder.c163
-rw-r--r--Utilities/cmliblzma/liblzma/common/auto_decoder.c195
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_buffer_decoder.c80
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_buffer_encoder.c337
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_buffer_encoder.h24
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_decoder.c257
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_decoder.h22
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_encoder.c223
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_encoder.h47
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_header_decoder.c124
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_header_encoder.c132
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_util.c90
-rw-r--r--Utilities/cmliblzma/liblzma/common/common.c445
-rw-r--r--Utilities/cmliblzma/liblzma/common/common.h313
-rw-r--r--Utilities/cmliblzma/liblzma/common/easy_buffer_encoder.c27
-rw-r--r--Utilities/cmliblzma/liblzma/common/easy_decoder_memusage.c24
-rw-r--r--Utilities/cmliblzma/liblzma/common/easy_encoder.c24
-rw-r--r--Utilities/cmliblzma/liblzma/common/easy_encoder_memusage.c24
-rw-r--r--Utilities/cmliblzma/liblzma/common/easy_preset.c27
-rw-r--r--Utilities/cmliblzma/liblzma/common/easy_preset.h32
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_buffer_decoder.c88
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_buffer_encoder.c55
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_common.c337
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_common.h48
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_decoder.c184
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_decoder.h23
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_encoder.c286
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_encoder.h27
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_flags_decoder.c46
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_flags_encoder.c56
-rw-r--r--Utilities/cmliblzma/liblzma/common/hardware_cputhreads.c22
-rw-r--r--Utilities/cmliblzma/liblzma/common/hardware_physmem.c25
-rw-r--r--Utilities/cmliblzma/liblzma/common/index.c1250
-rw-r--r--Utilities/cmliblzma/liblzma/common/index.h73
-rw-r--r--Utilities/cmliblzma/liblzma/common/index_decoder.c352
-rw-r--r--Utilities/cmliblzma/liblzma/common/index_encoder.c256
-rw-r--r--Utilities/cmliblzma/liblzma/common/index_encoder.h23
-rw-r--r--Utilities/cmliblzma/liblzma/common/index_hash.c334
-rw-r--r--Utilities/cmliblzma/liblzma/common/memcmplen.h175
-rw-r--r--Utilities/cmliblzma/liblzma/common/outqueue.c184
-rw-r--r--Utilities/cmliblzma/liblzma/common/outqueue.h156
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_buffer_decoder.c91
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_buffer_encoder.c141
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_decoder.c467
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_decoder.h22
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_encoder.c340
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_encoder_mt.c1143
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_flags_common.c47
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_flags_common.h33
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_flags_decoder.c82
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_flags_encoder.c86
-rw-r--r--Utilities/cmliblzma/liblzma/common/vli_decoder.c86
-rw-r--r--Utilities/cmliblzma/liblzma/common/vli_encoder.c69
-rw-r--r--Utilities/cmliblzma/liblzma/common/vli_size.c30
-rw-r--r--Utilities/cmliblzma/liblzma/delta/delta_common.c73
-rw-r--r--Utilities/cmliblzma/liblzma/delta/delta_common.h20
-rw-r--r--Utilities/cmliblzma/liblzma/delta/delta_decoder.c78
-rw-r--r--Utilities/cmliblzma/liblzma/delta/delta_decoder.h26
-rw-r--r--Utilities/cmliblzma/liblzma/delta/delta_encoder.c125
-rw-r--r--Utilities/cmliblzma/liblzma/delta/delta_encoder.h24
-rw-r--r--Utilities/cmliblzma/liblzma/delta/delta_private.h37
-rw-r--r--Utilities/cmliblzma/liblzma/liblzma.pc.in19
-rw-r--r--Utilities/cmliblzma/liblzma/liblzma_w32res.rc14
-rw-r--r--Utilities/cmliblzma/liblzma/lz/lz_decoder.c306
-rw-r--r--Utilities/cmliblzma/liblzma/lz/lz_decoder.h234
-rw-r--r--Utilities/cmliblzma/liblzma/lz/lz_encoder.c616
-rw-r--r--Utilities/cmliblzma/liblzma/lz/lz_encoder.h327
-rw-r--r--Utilities/cmliblzma/liblzma/lz/lz_encoder_hash.h108
-rw-r--r--Utilities/cmliblzma/liblzma/lz/lz_encoder_hash_table.h68
-rw-r--r--Utilities/cmliblzma/liblzma/lz/lz_encoder_mf.c744
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/fastpos.h141
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/fastpos_table.c519
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/fastpos_tablegen.c56
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma2_decoder.c310
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma2_decoder.h29
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma2_encoder.c410
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma2_encoder.h43
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_common.h224
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_decoder.c1064
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_decoder.h53
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_encoder.c677
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_encoder.h58
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_encoder_optimum_fast.c170
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_encoder_optimum_normal.c855
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_encoder_presets.c64
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_encoder_private.h148
-rw-r--r--Utilities/cmliblzma/liblzma/rangecoder/price.h92
-rw-r--r--Utilities/cmliblzma/liblzma/rangecoder/price_table.c22
-rw-r--r--Utilities/cmliblzma/liblzma/rangecoder/price_tablegen.c87
-rw-r--r--Utilities/cmliblzma/liblzma/rangecoder/range_common.h71
-rw-r--r--Utilities/cmliblzma/liblzma/rangecoder/range_decoder.h185
-rw-r--r--Utilities/cmliblzma/liblzma/rangecoder/range_encoder.h231
-rw-r--r--Utilities/cmliblzma/liblzma/simple/arm.c71
-rw-r--r--Utilities/cmliblzma/liblzma/simple/armthumb.c76
-rw-r--r--Utilities/cmliblzma/liblzma/simple/ia64.c112
-rw-r--r--Utilities/cmliblzma/liblzma/simple/powerpc.c75
-rw-r--r--Utilities/cmliblzma/liblzma/simple/simple_coder.c282
-rw-r--r--Utilities/cmliblzma/liblzma/simple/simple_coder.h72
-rw-r--r--Utilities/cmliblzma/liblzma/simple/simple_decoder.c40
-rw-r--r--Utilities/cmliblzma/liblzma/simple/simple_decoder.h22
-rw-r--r--Utilities/cmliblzma/liblzma/simple/simple_encoder.c38
-rw-r--r--Utilities/cmliblzma/liblzma/simple/simple_encoder.h23
-rw-r--r--Utilities/cmliblzma/liblzma/simple/simple_private.h74
-rw-r--r--Utilities/cmliblzma/liblzma/simple/sparc.c83
-rw-r--r--Utilities/cmliblzma/liblzma/simple/x86.c159
-rw-r--r--Utilities/cmlibrhash/.gitattributes1
-rw-r--r--Utilities/cmlibrhash/CMakeLists.txt40
-rw-r--r--Utilities/cmlibrhash/COPYING15
-rw-r--r--Utilities/cmlibrhash/librhash/algorithms.c282
-rw-r--r--Utilities/cmlibrhash/librhash/algorithms.h155
-rw-r--r--Utilities/cmlibrhash/librhash/byte_order.c173
-rw-r--r--Utilities/cmlibrhash/librhash/byte_order.h223
-rw-r--r--Utilities/cmlibrhash/librhash/hex.c210
-rw-r--r--Utilities/cmlibrhash/librhash/hex.h26
-rw-r--r--Utilities/cmlibrhash/librhash/md5.c236
-rw-r--r--Utilities/cmlibrhash/librhash/md5.h31
-rw-r--r--Utilities/cmlibrhash/librhash/rhash.c702
-rw-r--r--Utilities/cmlibrhash/librhash/rhash.h519
-rw-r--r--Utilities/cmlibrhash/librhash/sha1.c196
-rw-r--r--Utilities/cmlibrhash/librhash/sha1.h31
-rw-r--r--Utilities/cmlibrhash/librhash/sha256.c241
-rw-r--r--Utilities/cmlibrhash/librhash/sha256.h32
-rw-r--r--Utilities/cmlibrhash/librhash/sha3.c362
-rw-r--r--Utilities/cmlibrhash/librhash/sha3.h54
-rw-r--r--Utilities/cmlibrhash/librhash/sha512.c255
-rw-r--r--Utilities/cmlibrhash/librhash/sha512.h32
-rw-r--r--Utilities/cmlibrhash/librhash/ustd.h71
-rw-r--r--Utilities/cmlibrhash/librhash/util.h31
-rw-r--r--Utilities/cmlibuv/.gitattributes1
-rw-r--r--Utilities/cmlibuv/CMakeLists.txt365
-rw-r--r--Utilities/cmlibuv/LICENSE70
-rw-r--r--Utilities/cmlibuv/include/uv.h1842
-rw-r--r--Utilities/cmlibuv/include/uv/aix.h32
-rw-r--r--Utilities/cmlibuv/include/uv/android-ifaddrs.h54
-rw-r--r--Utilities/cmlibuv/include/uv/bsd.h34
-rw-r--r--Utilities/cmlibuv/include/uv/darwin.h61
-rw-r--r--Utilities/cmlibuv/include/uv/errno.h448
-rw-r--r--Utilities/cmlibuv/include/uv/linux.h34
-rw-r--r--Utilities/cmlibuv/include/uv/os390.h33
-rw-r--r--Utilities/cmlibuv/include/uv/posix.h31
-rw-r--r--Utilities/cmlibuv/include/uv/stdint-msvc2008.h247
-rw-r--r--Utilities/cmlibuv/include/uv/sunos.h44
-rw-r--r--Utilities/cmlibuv/include/uv/threadpool.h37
-rw-r--r--Utilities/cmlibuv/include/uv/tree.h768
-rw-r--r--Utilities/cmlibuv/include/uv/unix.h527
-rw-r--r--Utilities/cmlibuv/include/uv/version.h43
-rw-r--r--Utilities/cmlibuv/include/uv/win.h702
-rw-r--r--Utilities/cmlibuv/src/fs-poll.c287
-rw-r--r--Utilities/cmlibuv/src/heap-inl.h245
-rw-r--r--Utilities/cmlibuv/src/idna.c291
-rw-r--r--Utilities/cmlibuv/src/idna.h31
-rw-r--r--Utilities/cmlibuv/src/inet.c302
-rw-r--r--Utilities/cmlibuv/src/queue.h108
-rw-r--r--Utilities/cmlibuv/src/random.c123
-rw-r--r--Utilities/cmlibuv/src/strscpy.c38
-rw-r--r--Utilities/cmlibuv/src/strscpy.h39
-rw-r--r--Utilities/cmlibuv/src/threadpool.c388
-rw-r--r--Utilities/cmlibuv/src/timer.c184
-rw-r--r--Utilities/cmlibuv/src/unix/aix-common.c90
-rw-r--r--Utilities/cmlibuv/src/unix/aix.c1304
-rw-r--r--Utilities/cmlibuv/src/unix/android-ifaddrs.c713
-rw-r--r--Utilities/cmlibuv/src/unix/async.c253
-rw-r--r--Utilities/cmlibuv/src/unix/atomic-ops.h67
-rw-r--r--Utilities/cmlibuv/src/unix/bsd-ifaddrs.c163
-rw-r--r--Utilities/cmlibuv/src/unix/bsd-proctitle.c100
-rw-r--r--Utilities/cmlibuv/src/unix/cmake-bootstrap.c163
-rw-r--r--Utilities/cmlibuv/src/unix/core.c1625
-rw-r--r--Utilities/cmlibuv/src/unix/cygwin.c53
-rw-r--r--Utilities/cmlibuv/src/unix/darwin-proctitle.c192
-rw-r--r--Utilities/cmlibuv/src/unix/darwin-stub.h113
-rw-r--r--Utilities/cmlibuv/src/unix/darwin.c371
-rw-r--r--Utilities/cmlibuv/src/unix/dl.c80
-rw-r--r--Utilities/cmlibuv/src/unix/freebsd.c282
-rw-r--r--Utilities/cmlibuv/src/unix/fs.c2144
-rw-r--r--Utilities/cmlibuv/src/unix/fsevents.c923
-rw-r--r--Utilities/cmlibuv/src/unix/getaddrinfo.c255
-rw-r--r--Utilities/cmlibuv/src/unix/getnameinfo.c121
-rw-r--r--Utilities/cmlibuv/src/unix/haiku.c167
-rw-r--r--Utilities/cmlibuv/src/unix/hpux.c30
-rw-r--r--Utilities/cmlibuv/src/unix/ibmi.c501
-rw-r--r--Utilities/cmlibuv/src/unix/internal.h354
-rw-r--r--Utilities/cmlibuv/src/unix/kqueue.c585
-rw-r--r--Utilities/cmlibuv/src/unix/linux-core.c1146
-rw-r--r--Utilities/cmlibuv/src/unix/linux-inotify.c327
-rw-r--r--Utilities/cmlibuv/src/unix/linux-syscalls.c267
-rw-r--r--Utilities/cmlibuv/src/unix/linux-syscalls.h81
-rw-r--r--Utilities/cmlibuv/src/unix/loop-watcher.c68
-rw-r--r--Utilities/cmlibuv/src/unix/loop.c228
-rw-r--r--Utilities/cmlibuv/src/unix/netbsd.c259
-rw-r--r--Utilities/cmlibuv/src/unix/no-fsevents.c42
-rw-r--r--Utilities/cmlibuv/src/unix/no-proctitle.c45
-rw-r--r--Utilities/cmlibuv/src/unix/openbsd.c240
-rw-r--r--Utilities/cmlibuv/src/unix/os390-syscalls.c584
-rw-r--r--Utilities/cmlibuv/src/unix/os390-syscalls.h74
-rw-r--r--Utilities/cmlibuv/src/unix/os390.c975
-rw-r--r--Utilities/cmlibuv/src/unix/pipe.c379
-rw-r--r--Utilities/cmlibuv/src/unix/poll.c150
-rw-r--r--Utilities/cmlibuv/src/unix/posix-hrtime.c74
-rw-r--r--Utilities/cmlibuv/src/unix/posix-poll.c374
-rw-r--r--Utilities/cmlibuv/src/unix/process.c650
-rw-r--r--Utilities/cmlibuv/src/unix/procfs-exepath.c45
-rw-r--r--Utilities/cmlibuv/src/unix/proctitle.c159
-rw-r--r--Utilities/cmlibuv/src/unix/pthread-fixes.c58
-rw-r--r--Utilities/cmlibuv/src/unix/qnx.c137
-rw-r--r--Utilities/cmlibuv/src/unix/random-devurandom.c93
-rw-r--r--Utilities/cmlibuv/src/unix/random-getentropy.c57
-rw-r--r--Utilities/cmlibuv/src/unix/random-getrandom.c88
-rw-r--r--Utilities/cmlibuv/src/unix/random-sysctl-linux.c99
-rw-r--r--Utilities/cmlibuv/src/unix/signal.c558
-rw-r--r--Utilities/cmlibuv/src/unix/spinlock.h53
-rw-r--r--Utilities/cmlibuv/src/unix/stream.c1693
-rw-r--r--Utilities/cmlibuv/src/unix/sunos.c871
-rw-r--r--Utilities/cmlibuv/src/unix/sysinfo-loadavg.c36
-rw-r--r--Utilities/cmlibuv/src/unix/sysinfo-memory.c42
-rw-r--r--Utilities/cmlibuv/src/unix/tcp.c461
-rw-r--r--Utilities/cmlibuv/src/unix/thread.c844
-rw-r--r--Utilities/cmlibuv/src/unix/tty.c399
-rw-r--r--Utilities/cmlibuv/src/unix/udp.c1332
-rw-r--r--Utilities/cmlibuv/src/uv-common.c930
-rw-r--r--Utilities/cmlibuv/src/uv-common.h368
-rw-r--r--Utilities/cmlibuv/src/uv-data-getter-setters.c119
-rw-r--r--Utilities/cmlibuv/src/version.c45
-rw-r--r--Utilities/cmlibuv/src/win/async.c98
-rw-r--r--Utilities/cmlibuv/src/win/atomicops-inl.h57
-rw-r--r--Utilities/cmlibuv/src/win/core.c748
-rw-r--r--Utilities/cmlibuv/src/win/detect-wakeup.c56
-rw-r--r--Utilities/cmlibuv/src/win/dl.c136
-rw-r--r--Utilities/cmlibuv/src/win/error.c173
-rw-r--r--Utilities/cmlibuv/src/win/fs-event.c608
-rw-r--r--Utilities/cmlibuv/src/win/fs-fd-hash-inl.h200
-rw-r--r--Utilities/cmlibuv/src/win/fs.c3428
-rw-r--r--Utilities/cmlibuv/src/win/getaddrinfo.c463
-rw-r--r--Utilities/cmlibuv/src/win/getnameinfo.c157
-rw-r--r--Utilities/cmlibuv/src/win/handle-inl.h180
-rw-r--r--Utilities/cmlibuv/src/win/handle.c162
-rw-r--r--Utilities/cmlibuv/src/win/internal.h348
-rw-r--r--Utilities/cmlibuv/src/win/loop-watcher.c122
-rw-r--r--Utilities/cmlibuv/src/win/pipe.c2393
-rw-r--r--Utilities/cmlibuv/src/win/poll.c584
-rw-r--r--Utilities/cmlibuv/src/win/process-stdio.c512
-rw-r--r--Utilities/cmlibuv/src/win/process.c1337
-rw-r--r--Utilities/cmlibuv/src/win/req-inl.h221
-rw-r--r--Utilities/cmlibuv/src/win/signal.c282
-rw-r--r--Utilities/cmlibuv/src/win/snprintf.c42
-rw-r--r--Utilities/cmlibuv/src/win/stream-inl.h54
-rw-r--r--Utilities/cmlibuv/src/win/stream.c243
-rw-r--r--Utilities/cmlibuv/src/win/tcp.c1573
-rw-r--r--Utilities/cmlibuv/src/win/thread.c520
-rw-r--r--Utilities/cmlibuv/src/win/tty.c2452
-rw-r--r--Utilities/cmlibuv/src/win/udp.c1181
-rw-r--r--Utilities/cmlibuv/src/win/util.c1977
-rw-r--r--Utilities/cmlibuv/src/win/winapi.c137
-rw-r--r--Utilities/cmlibuv/src/win/winapi.h4771
-rw-r--r--Utilities/cmlibuv/src/win/winsock.c575
-rw-r--r--Utilities/cmlibuv/src/win/winsock.h202
-rw-r--r--Utilities/cmnghttp2/.gitattributes1
-rw-r--r--Utilities/cmnghttp2/CMakeLists.txt52
-rw-r--r--Utilities/cmnghttp2/COPYING23
-rw-r--r--Utilities/cmnghttp2/cmakeconfig.h.in18
-rw-r--r--Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h5487
-rw-r--r--Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2ver.h42
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_buf.c525
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_buf.h412
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_callbacks.c175
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_callbacks.h125
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_debug.c60
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_debug.h43
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_frame.c1134
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_frame.h624
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_hd.c2351
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_hd.h439
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_hd_huffman.c144
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_hd_huffman.h72
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_hd_huffman_data.c4980
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_helper.c629
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_helper.h122
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_http.c530
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_http.h97
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_int.h58
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_map.c189
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_map.h144
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_mem.c74
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_mem.h45
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_net.h91
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_npn.c57
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_npn.h34
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_option.c123
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_option.h131
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_outbound_item.c127
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_outbound_item.h166
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_pq.c184
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_pq.h130
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_priority_spec.c52
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_priority_spec.h42
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_queue.c85
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_queue.h51
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_rcbuf.c102
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_rcbuf.h80
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_session.c7780
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_session.h901
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_stream.c1001
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_stream.h437
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_submit.c814
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_submit.h34
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_version.c38
-rw-r--r--Utilities/cmvssetup/.gitattributes1
-rw-r--r--Utilities/cmvssetup/Setup.Configuration.h991
-rw-r--r--Utilities/cmzlib/.NoDartCoverage1
-rw-r--r--Utilities/cmzlib/CMakeLists.txt44
-rw-r--r--Utilities/cmzlib/ChangeLog855
-rw-r--r--Utilities/cmzlib/Copyright.txt23
-rw-r--r--Utilities/cmzlib/FAQ339
-rw-r--r--Utilities/cmzlib/INDEX51
-rw-r--r--Utilities/cmzlib/README125
-rw-r--r--Utilities/cmzlib/README.Kitware.txt40
-rw-r--r--Utilities/cmzlib/adler32.c149
-rw-r--r--Utilities/cmzlib/cm_zlib_mangle.h93
-rw-r--r--Utilities/cmzlib/compress.c79
-rw-r--r--Utilities/cmzlib/crc32.c423
-rw-r--r--Utilities/cmzlib/crc32.h441
-rw-r--r--Utilities/cmzlib/deflate.c1743
-rw-r--r--Utilities/cmzlib/deflate.h331
-rw-r--r--Utilities/cmzlib/gzio.c1026
-rw-r--r--Utilities/cmzlib/inffast.c318
-rw-r--r--Utilities/cmzlib/inffast.h11
-rw-r--r--Utilities/cmzlib/inffixed.h94
-rw-r--r--Utilities/cmzlib/inflate.c1368
-rw-r--r--Utilities/cmzlib/inflate.h115
-rw-r--r--Utilities/cmzlib/inftrees.c329
-rw-r--r--Utilities/cmzlib/inftrees.h55
-rw-r--r--Utilities/cmzlib/trees.c1219
-rw-r--r--Utilities/cmzlib/trees.h128
-rw-r--r--Utilities/cmzlib/uncompr.c61
-rw-r--r--Utilities/cmzlib/zconf.h351
-rw-r--r--Utilities/cmzlib/zlib.def47
-rw-r--r--Utilities/cmzlib/zlib.h1357
-rw-r--r--Utilities/cmzlib/zlib.rc32
-rw-r--r--Utilities/cmzlib/zlibDllConfig.h.in6
-rw-r--r--Utilities/cmzlib/zutil.c318
-rw-r--r--Utilities/cmzlib/zutil.h269
-rw-r--r--Utilities/cmzstd/.gitattributes1
-rw-r--r--Utilities/cmzstd/CMakeLists.txt50
-rw-r--r--Utilities/cmzstd/LICENSE30
-rw-r--r--Utilities/cmzstd/README.md193
-rw-r--r--Utilities/cmzstd/lib/common/bitstream.h454
-rw-r--r--Utilities/cmzstd/lib/common/compiler.h175
-rw-r--r--Utilities/cmzstd/lib/common/cpu.h215
-rw-r--r--Utilities/cmzstd/lib/common/debug.c24
-rw-r--r--Utilities/cmzstd/lib/common/debug.h114
-rw-r--r--Utilities/cmzstd/lib/common/entropy_common.c216
-rw-r--r--Utilities/cmzstd/lib/common/error_private.c55
-rw-r--r--Utilities/cmzstd/lib/common/error_private.h80
-rw-r--r--Utilities/cmzstd/lib/common/fse.h688
-rw-r--r--Utilities/cmzstd/lib/common/fse_decompress.c286
-rw-r--r--Utilities/cmzstd/lib/common/huf.h340
-rw-r--r--Utilities/cmzstd/lib/common/mem.h453
-rw-r--r--Utilities/cmzstd/lib/common/pool.c344
-rw-r--r--Utilities/cmzstd/lib/common/pool.h84
-rw-r--r--Utilities/cmzstd/lib/common/threading.c121
-rw-r--r--Utilities/cmzstd/lib/common/threading.h155
-rw-r--r--Utilities/cmzstd/lib/common/xxhash.c864
-rw-r--r--Utilities/cmzstd/lib/common/xxhash.h285
-rw-r--r--Utilities/cmzstd/lib/common/zstd_common.c83
-rw-r--r--Utilities/cmzstd/lib/common/zstd_errors.h94
-rw-r--r--Utilities/cmzstd/lib/common/zstd_internal.h447
-rw-r--r--Utilities/cmzstd/lib/compress/fse_compress.c698
-rw-r--r--Utilities/cmzstd/lib/compress/hist.c183
-rw-r--r--Utilities/cmzstd/lib/compress/hist.h75
-rw-r--r--Utilities/cmzstd/lib/compress/huf_compress.c798
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_compress.c4278
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_compress_internal.h1125
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_compress_literals.c158
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_compress_literals.h29
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_compress_sequences.c419
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_compress_sequences.h54
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_compress_superblock.c845
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_compress_superblock.h32
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_cwksp.h525
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_double_fast.c521
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_double_fast.h38
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_fast.c496
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_fast.h37
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_lazy.c1138
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_lazy.h67
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_ldm.c619
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_ldm.h110
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_opt.c1200
-rw-r--r--Utilities/cmzstd/lib/compress/zstd_opt.h56
-rw-r--r--Utilities/cmzstd/lib/compress/zstdmt_compress.c2143
-rw-r--r--Utilities/cmzstd/lib/compress/zstdmt_compress.h192
-rw-r--r--Utilities/cmzstd/lib/decompress/huf_decompress.c1248
-rw-r--r--Utilities/cmzstd/lib/decompress/zstd_ddict.c244
-rw-r--r--Utilities/cmzstd/lib/decompress/zstd_ddict.h44
-rw-r--r--Utilities/cmzstd/lib/decompress/zstd_decompress.c1885
-rw-r--r--Utilities/cmzstd/lib/decompress/zstd_decompress_block.c1432
-rw-r--r--Utilities/cmzstd/lib/decompress/zstd_decompress_block.h59
-rw-r--r--Utilities/cmzstd/lib/decompress/zstd_decompress_internal.h189
-rw-r--r--Utilities/cmzstd/lib/deprecated/zbuff.h214
-rw-r--r--Utilities/cmzstd/lib/deprecated/zbuff_common.c26
-rw-r--r--Utilities/cmzstd/lib/deprecated/zbuff_compress.c147
-rw-r--r--Utilities/cmzstd/lib/deprecated/zbuff_decompress.c75
-rw-r--r--Utilities/cmzstd/lib/dictBuilder/cover.c1236
-rw-r--r--Utilities/cmzstd/lib/dictBuilder/cover.h157
-rw-r--r--Utilities/cmzstd/lib/dictBuilder/divsufsort.c1913
-rw-r--r--Utilities/cmzstd/lib/dictBuilder/divsufsort.h67
-rw-r--r--Utilities/cmzstd/lib/dictBuilder/fastcover.c757
-rw-r--r--Utilities/cmzstd/lib/dictBuilder/zdict.c1135
-rw-r--r--Utilities/cmzstd/lib/dictBuilder/zdict.h305
-rw-r--r--Utilities/cmzstd/lib/zstd.h2090
-rw-r--r--Utilities/std/.gitattributes2
-rw-r--r--Utilities/std/CMakeLists.txt17
-rw-r--r--Utilities/std/cm/algorithm35
-rw-r--r--Utilities/std/cm/bits/erase_if.hxx26
-rw-r--r--Utilities/std/cm/bits/fs_path.cxx1030
-rw-r--r--Utilities/std/cm/bits/string_view.cxx301
-rw-r--r--Utilities/std/cm/deque37
-rw-r--r--Utilities/std/cm/filesystem1172
-rw-r--r--Utilities/std/cm/iomanip180
-rw-r--r--Utilities/std/cm/iterator213
-rw-r--r--Utilities/std/cm/list36
-rw-r--r--Utilities/std/cm/map41
-rw-r--r--Utilities/std/cm/memory67
-rw-r--r--Utilities/std/cm/optional567
-rw-r--r--Utilities/std/cm/set40
-rw-r--r--Utilities/std/cm/shared_mutex73
-rw-r--r--Utilities/std/cm/string39
-rw-r--r--Utilities/std/cm/string_view216
-rw-r--r--Utilities/std/cm/type_traits60
-rw-r--r--Utilities/std/cm/unordered_map42
-rw-r--r--Utilities/std/cm/unordered_set42
-rw-r--r--Utilities/std/cm/utility31
-rw-r--r--Utilities/std/cm/vector37
-rw-r--r--Utilities/std/cmSTL.hxx.in7
-rw-r--r--Utilities/std/cmext/algorithm248
-rw-r--r--Utilities/std/cmext/iterator48
-rw-r--r--Utilities/std/cmext/memory38
-rw-r--r--Utilities/std/cmext/string_view39
-rw-r--r--Utilities/std/cmext/type_traits85
-rwxr-xr-xbootstrap1993
-rw-r--r--cmake_uninstall.cmake.in22
-rwxr-xr-xconfigure3
-rw-r--r--doxygen.config697
19095 files changed, 1212028 insertions, 1110 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..cba23d6
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,51 @@
+---
+# This configuration requires clang-format version 6.0 exactly.
+BasedOnStyle: Mozilla
+AlignOperands: false
+AllowShortFunctionsOnASingleLine: InlineOnly
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: true
+ AfterEnum: true
+ AfterFunction: true
+ AfterStruct: true
+ AfterUnion: true
+BreakBeforeBraces: Custom
+ColumnLimit: 79
+IndentPPDirectives: AfterHash
+SortUsingDeclarations: false
+SpaceAfterTemplateKeyword: true
+IncludeBlocks: Regroup
+IncludeCategories:
+ - Regex: '^[<"]cmSTL\.hxx'
+ Priority: -2
+ - Regex: '^[<"]cmConfigure\.h'
+ Priority: -1
+ - Regex: '^<queue>'
+ Priority: 1
+ - Regex: '^(<|")cm(ext)?/'
+ Priority: 2
+ - Regex: '^(<|")windows\.h'
+ Priority: 3
+ - Regex: '^<sys/'
+ Priority: 5
+ - Regex: '^(<|")Qt?[A-Z]'
+ Priority: 6
+ - Regex: '^<cmtp/'
+ Priority: 7
+ - Regex: '^(<|")cmsys/'
+ Priority: 8
+ - Regex: '^(<|")cm_'
+ Priority: 9
+ - Regex: '^(<|")cm[A-Z][^.]+\.h'
+ Priority: 10
+ - Regex: '^<[^.]+\.h'
+ Priority: 4
+ - Regex: '^<'
+ Priority: 1
+ - Regex: '.*'
+ Priority: 11
+...
diff --git a/.clang-tidy b/.clang-tidy
new file mode 100644
index 0000000..5e513fb
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1,39 @@
+---
+Checks: "-*,\
+bugprone-*,\
+-bugprone-macro-parentheses,\
+-bugprone-misplaced-widening-cast,\
+-bugprone-narrowing-conversions,\
+-bugprone-too-small-loop-variable,\
+google-readability-casting,\
+misc-*,\
+-misc-no-recursion,\
+-misc-non-private-member-variables-in-classes,\
+-misc-static-assert,\
+modernize-*,\
+-modernize-avoid-c-arrays,\
+-modernize-use-nodiscard,\
+-modernize-use-noexcept,\
+-modernize-use-trailing-return-type,\
+-modernize-use-transparent-functors,\
+performance-*,\
+readability-*,\
+-readability-convert-member-functions-to-static,\
+-readability-function-size,\
+-readability-identifier-naming,\
+-readability-implicit-bool-conversion,\
+-readability-inconsistent-declaration-parameter-name,\
+-readability-magic-numbers,\
+-readability-named-parameter,\
+-readability-redundant-declaration,\
+-readability-uppercase-literal-suffix,\
+"
+HeaderFilterRegex: 'Source/cm[^/]*\.(h|hxx|cxx)$'
+CheckOptions:
+ - key: modernize-use-default-member-init.UseAssignment
+ value: '1'
+ - key: modernize-use-equals-default.IgnoreMacros
+ value: '0'
+ - key: modernize-use-auto.MinTypeNameLength
+ value: '80'
+...
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..e5e7e30
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,10 @@
+root = true
+
+[*]
+charset = utf-8
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[{CMakeLists.txt,*.cmake,*.rst}]
+indent_size = 2
+indent_style = space
diff --git a/.gitattributes b/.gitattributes
index 7065eb5..fac38df 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,12 +1,40 @@
.git* export-ignore
+.hooks* export-ignore
+.editorconfig export-ignore
-*.c kwsys-c-style
-*.c.in kwsys-c-style
-*.cxx kwsys-c-style
-*.h kwsys-c-style
-*.h.in kwsys-c-style
-*.hxx kwsys-c-style
-*.hxx.in kwsys-c-style
+# Custom attribute to mark sources as using our C code style.
+[attr]our-c-style whitespace=tab-in-indent format.clang-format-6.0
+
+# Custom attribute to mark sources as generated.
+# Do not perform whitespace checks. Do not format.
+[attr]generated whitespace=-tab-in-indent,-indent-with-non-tab -format.clang-format-6.0
+
+bootstrap eol=lf
+configure eol=lf
+*.[1-9] eol=lf
+*.bash eol=lf
+*.sh eol=lf
+*.sh.in eol=lf
+
+*.bat eol=crlf
+*.bat.in eol=crlf
+*.sln eol=crlf
+*.vcproj eol=crlf
+
+*.pfx -text
+*.png -text
+*.png.in -text
+
+*.c our-c-style
+*.cc our-c-style
+*.cpp our-c-style
+*.cu our-c-style
+*.cxx our-c-style
+*.h our-c-style
+*.hh our-c-style
+*.hpp our-c-style
+*.hxx our-c-style
+*.notcu our-c-style
*.cmake whitespace=tab-in-indent
*.rst whitespace=tab-in-indent conflict-marker-size=79
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..5281c92
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,7 @@
+Thanks for your interest in contributing to CMake! The GitHub repository
+is a mirror provided for convenience, but CMake does not use GitHub pull
+requests for contribution. Please see
+
+ https://gitlab.kitware.com/cmake/cmake/-/tree/master/CONTRIBUTING.rst
+
+for contribution instructions. GitHub OAuth may be used to sign in.
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2f35615
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+# Exclude MacOS Finder files.
+.DS_Store
+
+*.user*
+
+*.pyc
+Testing
+CMakeUserPresets.json
+
+# Visual Studio work directory
+.vs/
+
+# Visual Studio Code
+.vscode/
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..465dc2c
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,594 @@
+include:
+ # Metadata shared my many jobs
+ - local: .gitlab/rules.yml
+ - local: .gitlab/artifacts.yml
+
+ # OS builds.
+ - local: .gitlab/os-linux.yml
+ - local: .gitlab/os-macos.yml
+ - local: .gitlab/os-windows.yml
+
+ # Post-build steps
+ - local: .gitlab/upload.yml
+
+stages:
+ - prep
+ - build
+ - test
+ - test-ext
+ - upload
+
+################################################################################
+# Job declarations
+#
+# Each job must pull in each of the following keys:
+#
+# - a "base image"
+# - a build script
+# - tags for the jobs
+# - rules for when to run the job
+#
+# Additionally, jobs may also contain:
+#
+# - artifacts
+# - dependency/needs jobs for required jobs
+################################################################################
+
+# Prep jobs
+
+prep:source-package:
+ extends:
+ - .linux_prep_source
+ - .cmake_prep_source_linux
+ - .linux_builder_tags
+ - .cmake_release_artifacts
+ - .run_only_for_package
+
+prep:doc-package:
+ extends:
+ - .fedora33_sphinx_package
+ - .cmake_prep_doc_linux
+ - .linux_builder_tags_qt
+ - .cmake_doc_artifacts
+ - .run_only_for_package
+
+upload:source-package:
+ extends:
+ - .rsync_upload
+ - .run_only_for_package
+ dependencies:
+ - prep:source-package
+ needs:
+ - prep:source-package
+ variables:
+ RSYNC_DESTINATION: dev
+
+# Lint builds
+
+build:debian10-iwyu:
+ extends:
+ - .debian10_iwyu
+ - .cmake_build_linux
+ - .linux_builder_tags
+ - .run_automatically
+
+build:fedora33-tidy:
+ extends:
+ - .fedora33_tidy
+ - .cmake_build_linux
+ - .linux_builder_tags_qt
+ - .run_automatically
+
+build:fedora33-sphinx:
+ extends:
+ - .fedora33_sphinx
+ - .cmake_build_linux
+ - .linux_builder_tags_qt
+ - .run_automatically
+ variables:
+ CMAKE_CI_JOB_CONTINUOUS: "true"
+ CMAKE_CI_JOB_HELP: "true"
+
+# Linux builds
+
+build:centos6-x86_64:
+ extends:
+ - .linux_release_x86_64
+ - .cmake_build_linux_release
+ - .cmake_release_artifacts
+ - .linux_builder_tags
+ - .run_manually
+
+build:centos7-aarch64:
+ extends:
+ - .linux_release_aarch64
+ - .cmake_build_linux_release
+ - .cmake_release_artifacts
+ - .linux_builder_tags_aarch64
+ - .run_manually
+ variables:
+ CMAKE_CI_NO_MR: "true"
+
+test:debian10-ninja:
+ extends:
+ - .debian10_ninja
+ - .cmake_test_linux_release
+ - .linux_builder_tags_qt
+ - .run_dependent
+ - .needs_centos6_x86_64
+
+test:debian10-aarch64-ninja:
+ extends:
+ - .debian10_aarch64_ninja
+ - .cmake_test_linux_release
+ - .linux_builder_tags_aarch64_qt
+ - .run_dependent
+ - .needs_centos7_aarch64
+ variables:
+ CMAKE_CI_NO_MR: "true"
+
+test:fedora33-makefiles:
+ extends:
+ - .fedora33_makefiles
+ - .cmake_test_linux_release
+ - .linux_builder_tags_qt
+ - .run_dependent
+ - .needs_centos6_x86_64
+
+test:cuda10.2-nvidia:
+ extends:
+ - .cuda10.2_nvidia
+ - .cmake_test_linux_release
+ - .linux_builder_tags_cuda
+ - .run_dependent
+ - .needs_centos6_x86_64
+
+build:fedora33-ninja:
+ extends:
+ - .fedora33_ninja
+ - .cmake_build_linux
+ - .cmake_build_artifacts
+ - .linux_builder_tags_qt
+ - .run_manually
+
+test:fedora33-ninja:
+ extends:
+ - .fedora33_ninja
+ - .cmake_test_linux
+ - .linux_builder_tags_x11
+ - .cmake_test_artifacts
+ - .run_dependent
+ dependencies:
+ - build:fedora33-ninja
+ needs:
+ - build:fedora33-ninja
+
+test:fedora33-ninja-multi:
+ extends:
+ - .fedora33_ninja_multi
+ - .cmake_test_linux_external
+ - .linux_builder_tags_qt
+ - .run_dependent
+ dependencies:
+ - test:fedora33-ninja
+ needs:
+ - test:fedora33-ninja
+
+test:intel2016-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2016_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2016-el7
+
+test:intel2016u1-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2016u1_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2016u1-el7
+
+test:intel2016u2-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2016u2_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2016u2-el7
+
+test:intel2017-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2017_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017-el7
+
+test:intel2017u1-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2017u1_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u1-el7
+
+test:intel2017u2-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2017u2_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u2-el7
+
+test:intel2017u3-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2017u3_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u3-el7
+
+test:intel2017u4-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2017u4_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u4-el7
+
+test:intel2017u5-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2017u5_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u5-el7
+
+test:intel2017u6-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2017u6_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u6-el7
+
+test:intel2017u7-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2017u7_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u7-el7
+
+test:intel2017u8-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2017u8_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u8-el7
+
+test:intel2018-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2018_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2018-el7
+
+test:intel2018u1-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2018u1_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2018u1-el7
+
+test:intel2018u2-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2018u2_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2018u2-el7
+
+test:intel2018u3-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2018u3_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2018u3-el7
+
+test:intel2018u4-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2018u4_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2018u4-el7
+
+test:intel2019-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2019_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2019-el7
+
+test:intel2019u1-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2019u1_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2019u1-el7
+
+test:intel2019u2-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2019u2_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2019u2-el7
+
+test:intel2019u3-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2019u3_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2019u3-el7
+
+test:intel2019u4-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2019u4_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2019u4-el7
+
+test:intel2020-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2020_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2020-el8
+
+test:intel2020u2-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2020u2_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2020u2-el8
+
+test:intel2020u4-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2020u4_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2020u4-el8
+
+test:intel2021.1.1-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2021.1.1_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2021.1.1-el8
+
+test:intel2021.1.2-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2021.1.2_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2021.1.2-el8
+
+test:oneapi2021.1.1-makefiles:
+ extends:
+ - .cmake_test_linux_inteloneapi_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: oneapi2021.1.1_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2021.1.1-el8
+
+test:oneapi2021.1.2-makefiles:
+ extends:
+ - .cmake_test_linux_inteloneapi_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: oneapi2021.1.2_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2021.1.2-el8
+
+build:linux-x86_64-package:
+ extends:
+ - .linux_package
+ - .linux_release_x86_64
+ - .cmake_build_linux_release
+ - .cmake_release_artifacts
+ - .linux_builder_tags
+ - .run_only_for_package
+ dependencies:
+ - prep:doc-package
+ needs:
+ - prep:doc-package
+
+upload:linux-x86_64-package:
+ extends:
+ - .rsync_upload
+ - .run_only_for_package
+ dependencies:
+ - build:linux-x86_64-package
+ needs:
+ - build:linux-x86_64-package
+ variables:
+ RSYNC_DESTINATION: dev
+
+build:linux-aarch64-package:
+ extends:
+ - .linux_package
+ - .linux_release_aarch64
+ - .cmake_build_linux_release
+ - .cmake_release_artifacts
+ - .linux_builder_tags_aarch64
+ - .run_only_for_package
+ dependencies:
+ - prep:doc-package
+ needs:
+ - prep:doc-package
+
+upload:linux-aarch64-package:
+ extends:
+ - .rsync_upload
+ - .run_only_for_package
+ dependencies:
+ - build:linux-aarch64-package
+ needs:
+ - build:linux-aarch64-package
+ variables:
+ RSYNC_DESTINATION: dev
+
+# macOS builds
+
+build:macos-x86_64-ninja:
+ extends:
+ - .macos_x86_64_ninja
+ - .cmake_build_macos
+ - .cmake_build_artifacts
+ - .macos_x86_64_builder_tags
+ - .run_manually
+
+build:macos-arm64-ninja:
+ extends:
+ - .macos_arm64_ninja
+ - .cmake_build_macos
+ - .cmake_build_artifacts
+ - .macos_arm64_builder_tags
+ - .run_manually
+ variables:
+ CMAKE_CI_NO_MR: "true"
+
+test:macos-x86_64-ninja:
+ extends:
+ - .macos_x86_64_ninja
+ - .cmake_test_macos
+ - .cmake_test_artifacts
+ - .macos_x86_64_builder_tags
+ - .run_dependent
+ dependencies:
+ - build:macos-x86_64-ninja
+ needs:
+ - build:macos-x86_64-ninja
+
+test:macos-arm64-ninja:
+ extends:
+ - .macos_arm64_ninja
+ - .cmake_test_macos
+ - .cmake_test_artifacts
+ - .macos_arm64_builder_tags
+ - .run_dependent
+ dependencies:
+ - build:macos-arm64-ninja
+ needs:
+ - build:macos-arm64-ninja
+ variables:
+ CMAKE_CI_NO_MR: "true"
+
+build:macos-x86_64-makefiles:
+ extends:
+ - .macos_x86_64_makefiles
+ - .cmake_build_macos
+ - .cmake_build_artifacts
+ - .macos_x86_64_builder_tags
+ - .run_manually
+
+test:macos-x86_64-makefiles:
+ extends:
+ - .macos_x86_64_makefiles
+ - .cmake_test_macos
+ - .macos_x86_64_builder_tags
+ - .run_dependent
+ dependencies:
+ - build:macos-x86_64-makefiles
+ needs:
+ - build:macos-x86_64-makefiles
+
+test:macos-x86_64-xcode:
+ extends:
+ - .macos_x86_64_xcode
+ - .cmake_test_macos_external
+ - .macos_x86_64_builder_ext_tags
+ - .run_dependent
+ dependencies:
+ - test:macos-x86_64-ninja
+ needs:
+ - test:macos-x86_64-ninja
+
+test:macos-arm64-xcode:
+ extends:
+ - .macos_arm64_xcode
+ - .cmake_test_macos_external
+ - .macos_arm64_builder_ext_tags
+ - .run_dependent
+ dependencies:
+ - test:macos-arm64-ninja
+ needs:
+ - test:macos-arm64-ninja
+ variables:
+ CMAKE_CI_NO_MR: "true"
+
+build:macos-package:
+ extends:
+ - .macos_package
+ - .cmake_build_macos_package
+ - .cmake_release_artifacts
+ - .macos_x86_64_builder_tags_package
+ - .run_only_for_package
+ dependencies:
+ - prep:doc-package
+ needs:
+ - prep:doc-package
+
+upload:macos-package:
+ extends:
+ - .rsync_upload
+ - .run_only_for_package
+ dependencies:
+ - build:macos-package
+ needs:
+ - build:macos-package
+ variables:
+ RSYNC_DESTINATION: dev
+
+build:macos10.10-package:
+ extends:
+ - .macos10.10_package
+ - .cmake_build_macos_package
+ - .cmake_release_artifacts
+ - .macos_x86_64_builder_tags_package
+ - .run_only_for_package
+ dependencies:
+ - prep:doc-package
+ needs:
+ - prep:doc-package
+
+upload:macos10.10-package:
+ extends:
+ - .rsync_upload
+ - .run_only_for_package
+ dependencies:
+ - build:macos10.10-package
+ needs:
+ - build:macos10.10-package
+ variables:
+ RSYNC_DESTINATION: dev
+
+# Windows builds
+
+build:windows-vs2019-x64-ninja:
+ extends:
+ - .windows_vs2019_x64_ninja
+ - .cmake_build_windows
+ - .cmake_build_artifacts
+ - .windows_builder_tags
+ - .run_manually
+
+test:windows-vs2019-x64-ninja:
+ extends:
+ - .windows_vs2019_x64_ninja
+ - .cmake_test_windows
+ - .windows_builder_tags
+ - .cmake_test_artifacts
+ - .run_dependent
+ dependencies:
+ - build:windows-vs2019-x64-ninja
+ needs:
+ - build:windows-vs2019-x64-ninja
+
+test:windows-vs2019-x64:
+ extends:
+ - .windows_vs2019_x64
+ - .cmake_test_windows_external
+ - .windows_builder_ext_tags
+ - .run_dependent
+ dependencies:
+ - test:windows-vs2019-x64-ninja
+ needs:
+ - test:windows-vs2019-x64-ninja
diff --git a/.gitlab/artifacts.yml b/.gitlab/artifacts.yml
new file mode 100644
index 0000000..bf8e8b6
--- /dev/null
+++ b/.gitlab/artifacts.yml
@@ -0,0 +1,99 @@
+# Lists of paths for artifacts of various stages.
+
+.cmake_build_artifacts:
+ artifacts:
+ expire_in: 1d
+ paths:
+ # XXX(globbing): Can be simplified with support from
+ # https://gitlab.com/gitlab-org/gitlab-runner/issues/4840
+ - build/CTestTestfile.cmake
+ - build/*/CTestTestfile.cmake
+ - build/*/*/CTestTestfile.cmake
+ - build/*/*/*/CTestTestfile.cmake
+ - build/*/*/*/*/CTestTestfile.cmake
+
+ # Allow CMake to find CMAKE_ROOT.
+ - build/CMakeFiles/CMakeSourceDir.txt
+
+ # Take the install tree.
+ - build/install/
+
+ # We need the main binaries.
+ - build/bin/
+ # The cache is needed for the installation test.
+ - build/CMakeCache.txt
+ # Test binaries. Eventually these might be better under
+ # `Source/Tests` or the like.
+ - build/Tests/EnforceConfig.cmake
+ - build/Tests/CMakeBuildTest.cmake
+ - build/Tests/CMakeBuildDoubleProjectTest.cmake
+ - build/Tests/CMake*/runcompilecommands
+ - build/Tests/CMake*/runcompilecommands.exe
+ - build/Tests/CMake*/test*
+ - build/Tests/CMake*/PseudoMemcheck/valgrind
+ - build/Tests/CMake*/PseudoMemcheck/purify
+ - build/Tests/CMake*/PseudoMemcheck/memcheck_fail
+ - build/Tests/CMake*/PseudoMemcheck/BC
+ - build/Tests/CMake*/PseudoMemcheck/cuda-memcheck
+ - build/Tests/CMake*/PseudoMemcheck/valgrind.exe
+ - build/Tests/CMake*/PseudoMemcheck/purify.exe
+ - build/Tests/CMake*/PseudoMemcheck/memcheck_fail.exe
+ - build/Tests/CMake*/PseudoMemcheck/BC.exe
+ - build/Tests/CMake*/PseudoMemcheck/cuda-memcheck.exe
+ - build/Tests/CMake*/PseudoMemcheck/NoLog
+ - build/Tests/CMake*Lib/*LibTests
+ - build/Tests/CMake*Lib/*LibTests.exe
+ - build/Source/kwsys/cmsysTest*
+ - build/Source/kwsys/testConsoleBufChild.exe
+ - build/Utilities/cmcurl/curltest
+ - build/Utilities/cmcurl/curltest.exe
+ - build/Utilities/KWIML/test/kwiml_test
+ - build/Utilities/KWIML/test/kwiml_test.exe
+ - build/Source/kwsys/*cmsysTestDynload.*
+ - build/Source/kwsys/dynloaddir/cmsysTestDynloadImpl.dll
+ - build/Source/kwsys/dynloaddir/cmsysTestDynloadUse.dll
+
+ # Test directories.
+ - build/Tests/CTest*
+ - build/Tests/Find*
+ - build/Tests/Qt5*
+ - build/Tests/RunCMake/
+ - build/Tests/CMakeOnly/
+ - build/Tests/CMakeTests/
+ - build/Tests/CMakeGUI/
+ - build/Tests/FortranC/
+
+ # CTest/CDash information.
+ - build/Testing/
+ - build/DartConfiguation.tcl
+ - build/CTestCustom.cmake
+
+.cmake_release_artifacts:
+ artifacts:
+ expire_in: 5d
+ # Release artifacts are of interest even for failed jobs.
+ when: always
+ paths:
+ # Any packages made.
+ - build/cmake-*-linux-x86_64.*
+ - build/cmake-*-linux-aarch64.*
+ - build/cmake-*-macos*-universal.*
+ # Any source packages made.
+ - build/cmake-*.tar.gz
+ - build/cmake-*.zip
+
+.cmake_test_artifacts:
+ artifacts:
+ expire_in: 1d
+ # External testing can be useful even if test jobs fail.
+ when: always
+ paths:
+ # Take the install tree.
+ - build/install/
+
+.cmake_doc_artifacts:
+ artifacts:
+ expire_in: 1d
+ paths:
+ # Take the install tree.
+ - build/install-doc/
diff --git a/.gitlab/ci/cmake.ps1 b/.gitlab/ci/cmake.ps1
new file mode 100755
index 0000000..3d6fb81
--- /dev/null
+++ b/.gitlab/ci/cmake.ps1
@@ -0,0 +1,19 @@
+$erroractionpreference = "stop"
+
+$version = "3.19.7"
+$sha256sum = "E6788D6E23B3026C37FCFA7658075D6B5F9113F26FAE17FE372AD4A7EE62D5FD"
+$filename = "cmake-$version-win64-x64"
+$tarball = "$filename.zip"
+
+$outdir = $pwd.Path
+$outdir = "$outdir\.gitlab"
+$ProgressPreference = 'SilentlyContinue'
+Invoke-WebRequest -Uri "https://github.com/Kitware/CMake/releases/download/v$version/$tarball" -OutFile "$outdir\$tarball"
+$hash = Get-FileHash "$outdir\$tarball" -Algorithm SHA256
+if ($hash.Hash -ne $sha256sum) {
+ exit 1
+}
+
+Add-Type -AssemblyName System.IO.Compression.FileSystem
+[System.IO.Compression.ZipFile]::ExtractToDirectory("$outdir\$tarball", "$outdir")
+Move-Item -Path "$outdir\$filename" -Destination "$outdir\cmake"
diff --git a/.gitlab/ci/cmake.sh b/.gitlab/ci/cmake.sh
new file mode 100755
index 0000000..e02eb8a
--- /dev/null
+++ b/.gitlab/ci/cmake.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+set -e
+
+readonly version="3.19.3"
+
+case "$(uname -s)-$(uname -m)" in
+ Linux-x86_64)
+ shatool="sha256sum"
+ sha256sum="c18b65697e9679e5c88dccede08c323cd3d3730648e59048047bba82097e0ffc"
+ platform="Linux-x86_64"
+ ;;
+ Linux-aarch64)
+ shatool="sha256sum"
+ sha256sum="66e507c97ffb586d7ca6567890808b792c8eb004b645706df6fbf27826a395a2"
+ platform="Linux-aarch64"
+ ;;
+ Darwin-*)
+ shatool="shasum -a 256"
+ sha256sum="a6b79ad05f89241a05797510e650354d74ff72cc988981cdd1eb2b3b2bda66ac"
+ platform="macos-universal"
+ ;;
+ *)
+ echo "Unrecognized platform $(uname -s)-$(uname -m)"
+ exit 1
+ ;;
+esac
+readonly shatool
+readonly sha256sum
+readonly platform
+
+readonly filename="cmake-$version-$platform"
+readonly tarball="$filename.tar.gz"
+
+cd .gitlab
+
+echo "$sha256sum $tarball" > cmake.sha256sum
+curl -OL "https://github.com/Kitware/CMake/releases/download/v$version/$tarball"
+$shatool --check cmake.sha256sum
+tar xf "$tarball"
+mv "$filename" cmake
+
+if [ "$( uname -s )" = "Darwin" ]; then
+ ln -s CMake.app/Contents/bin cmake/bin
+fi
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_common.cmake b/.gitlab/ci/configure_common.cmake
new file mode 100644
index 0000000..436e582
--- /dev/null
+++ b/.gitlab/ci/configure_common.cmake
@@ -0,0 +1,15 @@
+set(CTEST_USE_LAUNCHERS "ON" CACHE BOOL "")
+
+# We run the install right after the build. Avoid rerunning it when installing.
+set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY "ON" CACHE BOOL "")
+# Install CMake under the build tree.
+set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "")
+set(CMake_TEST_INSTALL "OFF" CACHE BOOL "")
+
+if (NOT "$ENV{CMAKE_BUILD_TYPE}" STREQUAL "")
+ set(CMAKE_BUILD_TYPE "$ENV{CMAKE_BUILD_TYPE}" CACHE STRING "")
+endif ()
+
+if (NOT configure_no_sccache)
+ include("${CMAKE_CURRENT_LIST_DIR}/configure_sccache.cmake")
+endif()
diff --git a/.gitlab/ci/configure_cuda10.2_nvidia.cmake b/.gitlab/ci/configure_cuda10.2_nvidia.cmake
new file mode 100644
index 0000000..519699b
--- /dev/null
+++ b/.gitlab/ci/configure_cuda10.2_nvidia.cmake
@@ -0,0 +1,3 @@
+set(CMake_TEST_CUDA "NVIDIA" CACHE STRING "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_debian10_aarch64_ninja.cmake b/.gitlab/ci/configure_debian10_aarch64_ninja.cmake
new file mode 100644
index 0000000..1ad3ac4
--- /dev/null
+++ b/.gitlab/ci/configure_debian10_aarch64_ninja.cmake
@@ -0,0 +1,67 @@
+set(CMake_TEST_FindALSA "ON" CACHE BOOL "")
+set(CMake_TEST_FindBLAS "ON" CACHE BOOL "")
+set(CMake_TEST_FindBoost "ON" CACHE BOOL "")
+set(CMake_TEST_FindBoost_Python "ON" CACHE BOOL "")
+set(CMake_TEST_FindBZip2 "ON" CACHE BOOL "")
+set(CMake_TEST_FindCups "ON" CACHE BOOL "")
+set(CMake_TEST_FindCURL "ON" CACHE BOOL "")
+set(CMake_TEST_FindDevIL "ON" CACHE BOOL "")
+set(CMake_TEST_FindDoxygen_Dot "ON" CACHE BOOL "")
+set(CMake_TEST_FindDoxygen "ON" CACHE BOOL "")
+set(CMake_TEST_FindEXPAT "ON" CACHE BOOL "")
+set(CMake_TEST_FindFontconfig "ON" CACHE BOOL "")
+set(CMake_TEST_FindFreetype "ON" CACHE BOOL "")
+set(CMake_TEST_FindGDAL "ON" CACHE BOOL "")
+set(CMake_TEST_FindGIF "ON" CACHE BOOL "")
+set(CMake_TEST_FindGit "ON" CACHE BOOL "")
+set(CMake_TEST_FindGLEW "ON" CACHE BOOL "")
+set(CMake_TEST_FindGnuTLS "ON" CACHE BOOL "")
+set(CMake_TEST_FindGSL "ON" CACHE BOOL "")
+set(CMake_TEST_FindGTest "ON" CACHE BOOL "")
+set(CMake_TEST_FindGTK2 "ON" CACHE BOOL "")
+set(CMake_TEST_FindIconv "ON" CACHE BOOL "")
+set(CMake_TEST_FindIntl "ON" CACHE BOOL "")
+set(CMake_TEST_FindJPEG "ON" CACHE BOOL "")
+set(CMake_TEST_FindJsonCpp "ON" CACHE BOOL "")
+set(CMake_TEST_FindLAPACK "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibArchive "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibinput "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibLZMA "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibUV "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibXml2 "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibXslt "ON" CACHE BOOL "")
+set(CMake_TEST_FindMPI_C "ON" CACHE BOOL "")
+set(CMake_TEST_FindMPI_CXX "ON" CACHE BOOL "")
+set(CMake_TEST_FindMPI_Fortran "ON" CACHE BOOL "")
+set(CMake_TEST_FindMPI "ON" CACHE BOOL "")
+set(CMake_TEST_FindODBC "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenACC "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenGL "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_Fortran "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenSSL "ON" CACHE BOOL "")
+set(CMake_TEST_FindPatch "ON" CACHE BOOL "")
+set(CMake_TEST_FindPNG "ON" CACHE BOOL "")
+set(CMake_TEST_FindPostgreSQL "ON" CACHE BOOL "")
+set(CMake_TEST_FindProtobuf "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython_NumPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython_PyPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindRuby "ON" CACHE BOOL "")
+set(CMake_TEST_FindSDL "ON" CACHE BOOL "")
+set(CMake_TEST_FindSQLite3 "ON" CACHE BOOL "")
+set(CMake_TEST_FindTIFF "ON" CACHE BOOL "")
+set(CMake_TEST_FindX11 "ON" CACHE BOOL "")
+set(CMake_TEST_FindXalanC "ON" CACHE BOOL "")
+set(CMake_TEST_FindXercesC "ON" CACHE BOOL "")
+set(CMake_TEST_Fortran_SUBMODULES "ON" CACHE BOOL "")
+set(CMake_TEST_IPO_WORKS_C "ON" CACHE BOOL "")
+set(CMake_TEST_IPO_WORKS_CXX "ON" CACHE BOOL "")
+set(CMake_TEST_IPO_WORKS_Fortran "ON" CACHE BOOL "")
+set(CMake_TEST_JQ "/usr/bin/jq" CACHE PATH "")
+set(CMake_TEST_Qt5 "ON" CACHE BOOL "")
+set(CMake_TEST_UseSWIG "ON" CACHE BOOL "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_debian10_iwyu.cmake b/.gitlab/ci/configure_debian10_iwyu.cmake
new file mode 100644
index 0000000..1daa581
--- /dev/null
+++ b/.gitlab/ci/configure_debian10_iwyu.cmake
@@ -0,0 +1,4 @@
+set(CMake_RUN_IWYU ON CACHE BOOL "")
+set(IWYU_COMMAND "/usr/bin/include-what-you-use-6.0" CACHE FILEPATH "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_debian10_ninja.cmake b/.gitlab/ci/configure_debian10_ninja.cmake
new file mode 100644
index 0000000..d925387
--- /dev/null
+++ b/.gitlab/ci/configure_debian10_ninja.cmake
@@ -0,0 +1,69 @@
+set(CMake_TEST_FindALSA "ON" CACHE BOOL "")
+set(CMake_TEST_FindBLAS "ON" CACHE BOOL "")
+set(CMake_TEST_FindBoost "ON" CACHE BOOL "")
+set(CMake_TEST_FindBoost_Python "ON" CACHE BOOL "")
+set(CMake_TEST_FindBZip2 "ON" CACHE BOOL "")
+set(CMake_TEST_FindCups "ON" CACHE BOOL "")
+set(CMake_TEST_FindCURL "ON" CACHE BOOL "")
+set(CMake_TEST_FindDevIL "ON" CACHE BOOL "")
+set(CMake_TEST_FindDoxygen_Dot "ON" CACHE BOOL "")
+set(CMake_TEST_FindDoxygen "ON" CACHE BOOL "")
+set(CMake_TEST_FindEXPAT "ON" CACHE BOOL "")
+set(CMake_TEST_FindFontconfig "ON" CACHE BOOL "")
+set(CMake_TEST_FindFreetype "ON" CACHE BOOL "")
+set(CMake_TEST_FindGDAL "ON" CACHE BOOL "")
+set(CMake_TEST_FindGIF "ON" CACHE BOOL "")
+set(CMake_TEST_FindGit "ON" CACHE BOOL "")
+set(CMake_TEST_FindGLEW "ON" CACHE BOOL "")
+set(CMake_TEST_FindGnuTLS "ON" CACHE BOOL "")
+set(CMake_TEST_FindGSL "ON" CACHE BOOL "")
+set(CMake_TEST_FindGTest "ON" CACHE BOOL "")
+set(CMake_TEST_FindGTK2 "ON" CACHE BOOL "")
+set(CMake_TEST_FindIconv "ON" CACHE BOOL "")
+set(CMake_TEST_FindIntl "ON" CACHE BOOL "")
+set(CMake_TEST_FindJPEG "ON" CACHE BOOL "")
+set(CMake_TEST_FindJsonCpp "ON" CACHE BOOL "")
+set(CMake_TEST_FindLAPACK "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibArchive "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibinput "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibLZMA "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibUV "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibXml2 "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibXslt "ON" CACHE BOOL "")
+set(CMake_TEST_FindMPI_C "ON" CACHE BOOL "")
+set(CMake_TEST_FindMPI_CXX "ON" CACHE BOOL "")
+set(CMake_TEST_FindMPI_Fortran "ON" CACHE BOOL "")
+set(CMake_TEST_FindMPI "ON" CACHE BOOL "")
+set(CMake_TEST_FindODBC "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenACC "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenGL "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_Fortran "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenSSL "ON" CACHE BOOL "")
+set(CMake_TEST_FindPatch "ON" CACHE BOOL "")
+set(CMake_TEST_FindPNG "ON" CACHE BOOL "")
+set(CMake_TEST_FindPostgreSQL "ON" CACHE BOOL "")
+set(CMake_TEST_FindProtobuf "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython_IronPython "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython_NumPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython_PyPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindRuby "ON" CACHE BOOL "")
+set(CMake_TEST_FindRuby_RVM "ON" CACHE BOOL "")
+set(CMake_TEST_FindSDL "ON" CACHE BOOL "")
+set(CMake_TEST_FindSQLite3 "ON" CACHE BOOL "")
+set(CMake_TEST_FindTIFF "ON" CACHE BOOL "")
+set(CMake_TEST_FindX11 "ON" CACHE BOOL "")
+set(CMake_TEST_FindXalanC "ON" CACHE BOOL "")
+set(CMake_TEST_FindXercesC "ON" CACHE BOOL "")
+set(CMake_TEST_Fortran_SUBMODULES "ON" CACHE BOOL "")
+set(CMake_TEST_IPO_WORKS_C "ON" CACHE BOOL "")
+set(CMake_TEST_IPO_WORKS_CXX "ON" CACHE BOOL "")
+set(CMake_TEST_IPO_WORKS_Fortran "ON" CACHE BOOL "")
+set(CMake_TEST_JQ "/usr/bin/jq" CACHE PATH "")
+set(CMake_TEST_Qt5 "ON" CACHE BOOL "")
+set(CMake_TEST_UseSWIG "ON" CACHE BOOL "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_external_test.cmake b/.gitlab/ci/configure_external_test.cmake
new file mode 100644
index 0000000..71397d1
--- /dev/null
+++ b/.gitlab/ci/configure_external_test.cmake
@@ -0,0 +1,3 @@
+set(CMake_TEST_HOST_CMAKE "ON" CACHE BOOL "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_fedora33_common.cmake b/.gitlab/ci/configure_fedora33_common.cmake
new file mode 100644
index 0000000..dee78ab
--- /dev/null
+++ b/.gitlab/ci/configure_fedora33_common.cmake
@@ -0,0 +1,6 @@
+set(BUILD_CursesDialog ON CACHE BOOL "")
+set(BUILD_QtDialog ON CACHE BOOL "")
+set(CMake_TEST_JQ "/usr/bin/jq" CACHE PATH "")
+set(CMake_TEST_JSON_SCHEMA ON CACHE BOOL "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_fedora33_makefiles.cmake b/.gitlab/ci/configure_fedora33_makefiles.cmake
new file mode 100644
index 0000000..882ffcd
--- /dev/null
+++ b/.gitlab/ci/configure_fedora33_makefiles.cmake
@@ -0,0 +1,68 @@
+set(CMake_TEST_FindALSA "ON" CACHE BOOL "")
+set(CMake_TEST_FindBLAS "ON" CACHE BOOL "")
+set(CMake_TEST_FindBoost "ON" CACHE BOOL "")
+set(CMake_TEST_FindBoost_Python "ON" CACHE BOOL "")
+set(CMake_TEST_FindBZip2 "ON" CACHE BOOL "")
+set(CMake_TEST_FindCups "ON" CACHE BOOL "")
+set(CMake_TEST_FindCURL "ON" CACHE BOOL "")
+set(CMake_TEST_FindDevIL "ON" CACHE BOOL "")
+set(CMake_TEST_FindDoxygen_Dot "ON" CACHE BOOL "")
+set(CMake_TEST_FindDoxygen "ON" CACHE BOOL "")
+set(CMake_TEST_FindEXPAT "ON" CACHE BOOL "")
+set(CMake_TEST_FindFontconfig "ON" CACHE BOOL "")
+set(CMake_TEST_FindFreetype "ON" CACHE BOOL "")
+set(CMake_TEST_FindGDAL "ON" CACHE BOOL "")
+set(CMake_TEST_FindGIF "ON" CACHE BOOL "")
+set(CMake_TEST_FindGit "ON" CACHE BOOL "")
+set(CMake_TEST_FindGLEW "ON" CACHE BOOL "")
+set(CMake_TEST_FindGnuTLS "ON" CACHE BOOL "")
+set(CMake_TEST_FindGSL "ON" CACHE BOOL "")
+set(CMake_TEST_FindGTest "ON" CACHE BOOL "")
+set(CMake_TEST_FindGTK2 "ON" CACHE BOOL "")
+set(CMake_TEST_FindIconv "ON" CACHE BOOL "")
+set(CMake_TEST_FindIntl "ON" CACHE BOOL "")
+set(CMake_TEST_FindJPEG "ON" CACHE BOOL "")
+set(CMake_TEST_FindJsonCpp "ON" CACHE BOOL "")
+set(CMake_TEST_FindLAPACK "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibArchive "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibinput "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibLZMA "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibUV "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibXml2 "ON" CACHE BOOL "")
+set(CMake_TEST_FindLibXslt "ON" CACHE BOOL "")
+set(CMake_TEST_FindMPI_C "ON" CACHE BOOL "")
+set(CMake_TEST_FindMPI_CXX "ON" CACHE BOOL "")
+set(CMake_TEST_FindMPI_Fortran "ON" CACHE BOOL "")
+set(CMake_TEST_FindMPI "ON" CACHE BOOL "")
+set(CMake_TEST_FindODBC "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenACC "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenGL "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_Fortran "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenSSL "ON" CACHE BOOL "")
+set(CMake_TEST_FindPatch "ON" CACHE BOOL "")
+set(CMake_TEST_FindPNG "ON" CACHE BOOL "")
+set(CMake_TEST_FindPostgreSQL "ON" CACHE BOOL "")
+set(CMake_TEST_FindProtobuf "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython_NumPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython_PyPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindRuby "ON" CACHE BOOL "")
+set(CMake_TEST_FindRuby_RVM "ON" CACHE BOOL "")
+set(CMake_TEST_FindSDL "ON" CACHE BOOL "")
+set(CMake_TEST_FindSQLite3 "ON" CACHE BOOL "")
+set(CMake_TEST_FindTIFF "ON" CACHE BOOL "")
+set(CMake_TEST_FindX11 "ON" CACHE BOOL "")
+set(CMake_TEST_FindXalanC "ON" CACHE BOOL "")
+set(CMake_TEST_FindXercesC "ON" CACHE BOOL "")
+set(CMake_TEST_Fortran_SUBMODULES "ON" CACHE BOOL "")
+set(CMake_TEST_IPO_WORKS_C "ON" CACHE BOOL "")
+set(CMake_TEST_IPO_WORKS_CXX "ON" CACHE BOOL "")
+set(CMake_TEST_IPO_WORKS_Fortran "ON" CACHE BOOL "")
+set(CMake_TEST_ISPC "ON" CACHE STRING "")
+set(CMake_TEST_Qt5 "ON" CACHE BOOL "")
+set(CMake_TEST_UseSWIG "ON" CACHE BOOL "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_fedora33_ninja.cmake b/.gitlab/ci/configure_fedora33_ninja.cmake
new file mode 100644
index 0000000..883f425
--- /dev/null
+++ b/.gitlab/ci/configure_fedora33_ninja.cmake
@@ -0,0 +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_fedora33_common.cmake")
diff --git a/.gitlab/ci/configure_fedora33_ninja_multi.cmake b/.gitlab/ci/configure_fedora33_ninja_multi.cmake
new file mode 100644
index 0000000..efb4b84
--- /dev/null
+++ b/.gitlab/ci/configure_fedora33_ninja_multi.cmake
@@ -0,0 +1,2 @@
+set(CMake_TEST_ISPC "ON" CACHE STRING "")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_fedora33_sphinx.cmake b/.gitlab/ci/configure_fedora33_sphinx.cmake
new file mode 100644
index 0000000..90d159b
--- /dev/null
+++ b/.gitlab/ci/configure_fedora33_sphinx.cmake
@@ -0,0 +1,2 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_sphinx.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_fedora33_sphinx_package.cmake b/.gitlab/ci/configure_fedora33_sphinx_package.cmake
new file mode 100644
index 0000000..e839de8
--- /dev/null
+++ b/.gitlab/ci/configure_fedora33_sphinx_package.cmake
@@ -0,0 +1,13 @@
+# Disable formats not wanted in the package's documentation.
+set(SPHINX_INFO OFF CACHE BOOL "")
+set(SPHINX_SINGLEHTML OFF CACHE BOOL "")
+set(SPHINX_TEXT OFF CACHE BOOL "")
+
+# Set the destination directory for docs that packages expect.
+set(CMAKE_DOC_DIR "doc/cmake" CACHE STRING "")
+
+# Use a custom prefix to avoid conflicting with other builds.
+set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install-doc" CACHE PATH "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_sphinx.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_fedora33_tidy.cmake b/.gitlab/ci/configure_fedora33_tidy.cmake
new file mode 100644
index 0000000..9052fdc
--- /dev/null
+++ b/.gitlab/ci/configure_fedora33_tidy.cmake
@@ -0,0 +1,3 @@
+set(CMake_RUN_CLANG_TIDY ON CACHE BOOL "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora33_common.cmake")
diff --git a/.gitlab/ci/configure_intelclassic_makefiles.cmake b/.gitlab/ci/configure_intelclassic_makefiles.cmake
new file mode 100644
index 0000000..20863a2
--- /dev/null
+++ b/.gitlab/ci/configure_intelclassic_makefiles.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_inteloneapi_makefiles.cmake b/.gitlab/ci/configure_inteloneapi_makefiles.cmake
new file mode 100644
index 0000000..20863a2
--- /dev/null
+++ b/.gitlab/ci/configure_inteloneapi_makefiles.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_macos10.10_package.cmake b/.gitlab/ci/configure_macos10.10_package.cmake
new file mode 100644
index 0000000..f01e6c8
--- /dev/null
+++ b/.gitlab/ci/configure_macos10.10_package.cmake
@@ -0,0 +1,4 @@
+set(CPACK_SYSTEM_NAME "macos10.10-universal" CACHE STRING "")
+set(CMAKE_OSX_DEPLOYMENT_TARGET "10.10" CACHE STRING "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_package_common.cmake")
diff --git a/.gitlab/ci/configure_macos_arm64_ninja.cmake b/.gitlab/ci/configure_macos_arm64_ninja.cmake
new file mode 100644
index 0000000..f657d98
--- /dev/null
+++ b/.gitlab/ci/configure_macos_arm64_ninja.cmake
@@ -0,0 +1,3 @@
+set(CMake_TEST_GUI "ON" CACHE BOOL "")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_macos_arm64_xcode.cmake b/.gitlab/ci/configure_macos_arm64_xcode.cmake
new file mode 100644
index 0000000..1b976d2
--- /dev/null
+++ b/.gitlab/ci/configure_macos_arm64_xcode.cmake
@@ -0,0 +1,2 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_macos_common.cmake b/.gitlab/ci/configure_macos_common.cmake
new file mode 100644
index 0000000..37cd51c
--- /dev/null
+++ b/.gitlab/ci/configure_macos_common.cmake
@@ -0,0 +1,18 @@
+# Our CI machines do not consistently have Java installed, so a build may
+# detect that Java is available and working, but a test machine then not have a
+# working Java installed. To work around this, just act as if Java is not
+# available on any CI machine.
+set(CMake_TEST_Java 0 CACHE FILEPATH "")
+
+# Qt binaries get placed inside the source directory, which causes them to not
+# be included in the install-time rpath, but we still want them in the
+# build-time rpath. CMake sets CMAKE_BUILD_WITH_INSTALL_RPATH to ON by default,
+# so set it to OFF.
+set(CMAKE_BUILD_WITH_INSTALL_RPATH OFF CACHE BOOL "")
+
+set(BUILD_QtDialog ON CACHE BOOL "")
+
+# The "XCTest" test uses an explicit deployment target chosen
+# when CMake itself is configured. Use a version that is not
+# newer than the macOS version running on any CI host.
+set(CMake_TEST_XCTest_DEPLOYMENT_TARGET "10.15" CACHE STRING "")
diff --git a/.gitlab/ci/configure_macos_package.cmake b/.gitlab/ci/configure_macos_package.cmake
new file mode 100644
index 0000000..380e44c
--- /dev/null
+++ b/.gitlab/ci/configure_macos_package.cmake
@@ -0,0 +1,4 @@
+set(CPACK_SYSTEM_NAME "macos-universal" CACHE STRING "")
+set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_package_common.cmake")
diff --git a/.gitlab/ci/configure_macos_package_common.cmake b/.gitlab/ci/configure_macos_package_common.cmake
new file mode 100644
index 0000000..3aa8ae2
--- /dev/null
+++ b/.gitlab/ci/configure_macos_package_common.cmake
@@ -0,0 +1,26 @@
+set(CMake_DOC_ARTIFACT_PREFIX "$ENV{CI_PROJECT_DIR}/build/install-doc" CACHE PATH "")
+
+# Set up install destinations as expected by the packaging scripts.
+set(CMAKE_INSTALL_PREFIX "/" CACHE PATH "")
+set(CMAKE_DOC_DIR "doc/cmake" CACHE STRING "")
+
+# Settings for CMake packages for macOS.
+set(CPACK_DMG_FORMAT "UDBZ" CACHE STRING "")
+set(CMAKE_CXX_FLAGS "-stdlib=libc++" CACHE STRING "")
+set(CMAKE_C_STANDARD "11" CACHE STRING "")
+set(CMAKE_CXX_STANDARD "14" CACHE STRING "")
+set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "")
+set(CMAKE_SKIP_BOOTSTRAP_TEST "TRUE" CACHE STRING "")
+set(BUILD_CursesDialog "ON" CACHE BOOL "")
+set(BUILD_QtDialog "TRUE" CACHE BOOL "")
+set(CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL "3" CACHE STRING "")
+set(CMake_INSTALL_DEPENDENCIES "ON" CACHE BOOL "")
+set(CMAKE_SKIP_RPATH "TRUE" CACHE BOOL "")
+set(CMake_TEST_NO_FindPackageModeMakefileTest "TRUE" CACHE BOOL "")
+
+# XXX(sccache): restore sccache when it works for multiple architectures:
+# https://github.com/mozilla/sccache/issues/847
+set(configure_no_sccache 1)
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_macos_x86_64_makefiles.cmake b/.gitlab/ci/configure_macos_x86_64_makefiles.cmake
new file mode 100644
index 0000000..f657d98
--- /dev/null
+++ b/.gitlab/ci/configure_macos_x86_64_makefiles.cmake
@@ -0,0 +1,3 @@
+set(CMake_TEST_GUI "ON" CACHE BOOL "")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_macos_x86_64_ninja.cmake b/.gitlab/ci/configure_macos_x86_64_ninja.cmake
new file mode 100644
index 0000000..f657d98
--- /dev/null
+++ b/.gitlab/ci/configure_macos_x86_64_ninja.cmake
@@ -0,0 +1,3 @@
+set(CMake_TEST_GUI "ON" CACHE BOOL "")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_macos_x86_64_xcode.cmake b/.gitlab/ci/configure_macos_x86_64_xcode.cmake
new file mode 100644
index 0000000..1b976d2
--- /dev/null
+++ b/.gitlab/ci/configure_macos_x86_64_xcode.cmake
@@ -0,0 +1,2 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_sccache.cmake b/.gitlab/ci/configure_sccache.cmake
new file mode 100644
index 0000000..261bb28
--- /dev/null
+++ b/.gitlab/ci/configure_sccache.cmake
@@ -0,0 +1,2 @@
+set(CMAKE_C_COMPILER_LAUNCHER "sccache" CACHE STRING "")
+set(CMAKE_CXX_COMPILER_LAUNCHER "sccache" CACHE STRING "")
diff --git a/.gitlab/ci/configure_sphinx.cmake b/.gitlab/ci/configure_sphinx.cmake
new file mode 100644
index 0000000..3750309
--- /dev/null
+++ b/.gitlab/ci/configure_sphinx.cmake
@@ -0,0 +1,6 @@
+set(SPHINX_INFO ON CACHE BOOL "")
+set(SPHINX_MAN ON CACHE BOOL "")
+set(SPHINX_HTML ON CACHE BOOL "")
+set(SPHINX_SINGLEHTML ON CACHE BOOL "")
+set(SPHINX_QTHELP ON CACHE BOOL "")
+set(SPHINX_TEXT ON CACHE BOOL "")
diff --git a/.gitlab/ci/configure_windows_common.cmake b/.gitlab/ci/configure_windows_common.cmake
new file mode 100644
index 0000000..45250ac
--- /dev/null
+++ b/.gitlab/ci/configure_windows_common.cmake
@@ -0,0 +1,4 @@
+set(BUILD_QtDialog ON CACHE BOOL "")
+set(CMAKE_PREFIX_PATH "$ENV{CI_PROJECT_DIR}/.gitlab/qt" CACHE STRING "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_windows_vs2019_x64.cmake b/.gitlab/ci/configure_windows_vs2019_x64.cmake
new file mode 100644
index 0000000..f6ece57
--- /dev/null
+++ b/.gitlab/ci/configure_windows_vs2019_x64.cmake
@@ -0,0 +1,3 @@
+set(CMake_TEST_WIX_NO_VERIFY "ON" CACHE BOOL "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_windows_vs2019_x64_ninja.cmake b/.gitlab/ci/configure_windows_vs2019_x64_ninja.cmake
new file mode 100644
index 0000000..e1ae81e
--- /dev/null
+++ b/.gitlab/ci/configure_windows_vs2019_x64_ninja.cmake
@@ -0,0 +1,7 @@
+set(CMake_TEST_WIX_NO_VERIFY "ON" CACHE BOOL "")
+set(CMake_TEST_GUI "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenGL "ON" CACHE BOOL "")
+set(CMake_TEST_IPO_WORKS_C "ON" CACHE BOOL "")
+set(CMake_TEST_IPO_WORKS_CXX "ON" CACHE BOOL "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_common.cmake")
diff --git a/.gitlab/ci/ctest_build.cmake b/.gitlab/ci/ctest_build.cmake
new file mode 100644
index 0000000..e7a0985
--- /dev/null
+++ b/.gitlab/ci/ctest_build.cmake
@@ -0,0 +1,49 @@
+cmake_minimum_required(VERSION 3.8)
+
+include("${CMAKE_CURRENT_LIST_DIR}/gitlab_ci.cmake")
+
+# Read the files from the build directory.
+ctest_read_custom_files("${CTEST_BINARY_DIRECTORY}")
+
+# Pick up from where the configure left off.
+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 ()
+
+if (CTEST_CMAKE_GENERATOR STREQUAL "Unix Makefiles")
+ set(CTEST_BUILD_FLAGS "-j${nproc} -l${nproc}")
+elseif (CTEST_CMAKE_GENERATOR MATCHES "Ninja")
+ set(CTEST_BUILD_FLAGS "-l${nproc}")
+endif ()
+
+ctest_build(
+ NUMBER_WARNINGS num_warnings
+ RETURN_VALUE build_result)
+ctest_submit(PARTS Build)
+
+if (build_result)
+ message(FATAL_ERROR
+ "Failed to build")
+endif ()
+
+if ("$ENV{CTEST_NO_WARNINGS_ALLOWED}" AND num_warnings GREATER 0)
+ message(FATAL_ERROR
+ "Found ${num_warnings} warnings (treating as fatal).")
+endif ()
+
+if (NOT "$ENV{CMake_SKIP_INSTALL}")
+ ctest_build(APPEND
+ TARGET install
+ RETURN_VALUE install_result)
+
+ if (install_result)
+ message(FATAL_ERROR
+ "Failed to install")
+ endif ()
+endif ()
diff --git a/.gitlab/ci/ctest_configure.cmake b/.gitlab/ci/ctest_configure.cmake
new file mode 100644
index 0000000..2682055
--- /dev/null
+++ b/.gitlab/ci/ctest_configure.cmake
@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 3.8)
+
+include("${CMAKE_CURRENT_LIST_DIR}/gitlab_ci.cmake")
+
+set(cmake_args
+ -C "${CMAKE_CURRENT_LIST_DIR}/configure_$ENV{CMAKE_CONFIGURATION}.cmake")
+
+# Create an entry in CDash.
+ctest_start("${ctest_model}" GROUP "${ctest_group}")
+
+# Gather update information.
+find_package(Git)
+set(CTEST_UPDATE_VERSION_ONLY ON)
+set(CTEST_UPDATE_COMMAND "${GIT_EXECUTABLE}")
+ctest_update()
+
+# Configure the project.
+ctest_configure(
+ OPTIONS "${cmake_args}"
+ RETURN_VALUE configure_result)
+
+# Read the files from the build directory.
+ctest_read_custom_files("${CTEST_BINARY_DIRECTORY}")
+
+# We can now submit because we've configured. This is a cmb-superbuild-ism.
+ctest_submit(PARTS Update)
+ctest_submit(PARTS Configure)
+
+if (configure_result)
+ message(FATAL_ERROR
+ "Failed to configure")
+endif ()
diff --git a/.gitlab/ci/ctest_exclusions.cmake b/.gitlab/ci/ctest_exclusions.cmake
new file mode 100644
index 0000000..b885a6a
--- /dev/null
+++ b/.gitlab/ci/ctest_exclusions.cmake
@@ -0,0 +1,19 @@
+set(test_exclusions
+ # This test hits global resources and can be handled by nightly testing.
+ # https://gitlab.kitware.com/cmake/cmake/-/merge_requests/4769
+ "^BundleGeneratorTest$"
+)
+
+if (CTEST_CMAKE_GENERATOR MATCHES "Visual Studio")
+ list(APPEND test_exclusions
+ # This test takes around 5 minutes with Visual Studio.
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/20733
+ "^ExternalProjectUpdate$"
+ # This test is a dependency of the above and is only required for it.
+ "^ExternalProjectUpdateSetup$")
+endif ()
+
+string(REPLACE ";" "|" test_exclusions "${test_exclusions}")
+if (test_exclusions)
+ set(test_exclusions "(${test_exclusions})")
+endif ()
diff --git a/.gitlab/ci/ctest_test.cmake b/.gitlab/ci/ctest_test.cmake
new file mode 100644
index 0000000..facf9ba
--- /dev/null
+++ b/.gitlab/ci/ctest_test.cmake
@@ -0,0 +1,30 @@
+cmake_minimum_required(VERSION 3.8)
+
+include("${CMAKE_CURRENT_LIST_DIR}/gitlab_ci.cmake")
+
+# Read the files from the build directory.
+ctest_read_custom_files("${CTEST_BINARY_DIRECTORY}")
+
+# Pick up from where the configure left off.
+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(
+ PARALLEL_LEVEL "${nproc}"
+ TEST_LOAD "${nproc}"
+ RETURN_VALUE test_result
+ EXCLUDE "${test_exclusions}")
+ctest_submit(PARTS Test)
+
+if (test_result)
+ message(FATAL_ERROR
+ "Failed to test")
+endif ()
diff --git a/.gitlab/ci/ctest_test_external.cmake b/.gitlab/ci/ctest_test_external.cmake
new file mode 100644
index 0000000..6576c26
--- /dev/null
+++ b/.gitlab/ci/ctest_test_external.cmake
@@ -0,0 +1,88 @@
+cmake_minimum_required(VERSION 3.8)
+
+include("${CMAKE_CURRENT_LIST_DIR}/gitlab_ci.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/env_$ENV{CMAKE_CONFIGURATION}.cmake" OPTIONAL)
+
+set(cmake_args
+ -C "${CMAKE_CURRENT_LIST_DIR}/configure_$ENV{CMAKE_CONFIGURATION}.cmake")
+
+# Create an entry in CDash.
+ctest_start("${ctest_model}" GROUP "${ctest_group}")
+
+# Gather update information.
+find_package(Git)
+set(CTEST_UPDATE_VERSION_ONLY ON)
+set(CTEST_UPDATE_COMMAND "${GIT_EXECUTABLE}")
+ctest_update()
+
+# Configure the project.
+ctest_configure(
+ OPTIONS "${cmake_args}"
+ RETURN_VALUE configure_result)
+
+# Read the files from the build directory.
+ctest_read_custom_files("${CTEST_BINARY_DIRECTORY}")
+
+# We can now submit because we've configured. This is a cmb-superbuild-ism.
+ctest_submit(PARTS Update)
+ctest_submit(PARTS Configure)
+
+if (configure_result)
+ ctest_submit(PARTS Done)
+ message(FATAL_ERROR
+ "Failed to configure")
+endif ()
+
+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 ()
+
+if (CTEST_CMAKE_GENERATOR STREQUAL "Unix Makefiles")
+ set(CTEST_BUILD_FLAGS "-j${nproc} -l${nproc}")
+elseif (CTEST_CMAKE_GENERATOR MATCHES "Ninja")
+ set(CTEST_BUILD_FLAGS "-l${nproc}")
+endif ()
+
+ctest_build(
+ NUMBER_WARNINGS num_warnings
+ RETURN_VALUE build_result)
+ctest_submit(PARTS Build)
+
+if (build_result)
+ ctest_submit(PARTS Done)
+ message(FATAL_ERROR
+ "Failed to build")
+endif ()
+
+if ("$ENV{CTEST_NO_WARNINGS_ALLOWED}" AND num_warnings GREATER 0)
+ ctest_submit(PARTS Done)
+ message(FATAL_ERROR
+ "Found ${num_warnings} warnings (treating as fatal).")
+endif ()
+
+set(ctest_label_args)
+if (NOT "$ENV{CTEST_LABELS}" STREQUAL "")
+ list(APPEND ctest_label_args
+ INCLUDE_LABEL "$ENV{CTEST_LABELS}")
+endif ()
+
+include("${CMAKE_CURRENT_LIST_DIR}/ctest_exclusions.cmake")
+ctest_test(
+ PARALLEL_LEVEL "${nproc}"
+ TEST_LOAD "${nproc}"
+ RETURN_VALUE test_result
+ ${ctest_label_args}
+ EXCLUDE "${test_exclusions}")
+ctest_submit(PARTS Test)
+
+if (test_result)
+ ctest_submit(PARTS Done)
+ message(FATAL_ERROR
+ "Failed to test")
+endif ()
+
+ctest_submit(PARTS Done)
diff --git a/.gitlab/ci/docker/cuda10.2/Dockerfile b/.gitlab/ci/docker/cuda10.2/Dockerfile
new file mode 100644
index 0000000..e0ea0e7
--- /dev/null
+++ b/.gitlab/ci/docker/cuda10.2/Dockerfile
@@ -0,0 +1,5 @@
+FROM nvidia/cuda:10.2-devel-ubuntu18.04
+MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
+
+COPY install_deps.sh /root/install_deps.sh
+RUN sh /root/install_deps.sh
diff --git a/.gitlab/ci/docker/cuda10.2/install_deps.sh b/.gitlab/ci/docker/cuda10.2/install_deps.sh
new file mode 100755
index 0000000..0d57cd3
--- /dev/null
+++ b/.gitlab/ci/docker/cuda10.2/install_deps.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+set -e
+
+apt-get update
+
+# Install development tools.
+apt-get install -y \
+ g++ \
+ curl \
+ git
+
+apt-get clean
diff --git a/.gitlab/ci/docker/debian10-aarch64/Dockerfile b/.gitlab/ci/docker/debian10-aarch64/Dockerfile
new file mode 100644
index 0000000..2079795
--- /dev/null
+++ b/.gitlab/ci/docker/debian10-aarch64/Dockerfile
@@ -0,0 +1,5 @@
+FROM arm64v8/debian:10
+MAINTAINER Brad King <brad.king@kitware.com>
+
+COPY install_deps.sh /root/install_deps.sh
+RUN sh /root/install_deps.sh
diff --git a/.gitlab/ci/docker/debian10-aarch64/install_deps.sh b/.gitlab/ci/docker/debian10-aarch64/install_deps.sh
new file mode 100755
index 0000000..d84b3c8
--- /dev/null
+++ b/.gitlab/ci/docker/debian10-aarch64/install_deps.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+set -e
+
+apt-get update
+
+# Install build requirements.
+apt-get install -y \
+ libssl-dev
+
+# Install development tools.
+apt-get install -y \
+ g++ \
+ curl \
+ git
+
+# Install iwyu runtime deps.
+apt-get install -y \
+ clang-6.0 \
+ libncurses6
+
+# Tools needed for the test suite.
+apt-get install -y \
+ jq
+
+# Packages needed to test find modules.
+apt-get install -y \
+ alsa-utils \
+ doxygen graphviz \
+ gnutls-dev \
+ libarchive-dev \
+ libblas-dev \
+ libboost-dev \
+ libboost-filesystem-dev \
+ libboost-program-options-dev \
+ libboost-python-dev \
+ libboost-thread-dev \
+ libbz2-dev \
+ libcups2-dev \
+ libcurl4-gnutls-dev \
+ libdevil-dev \
+ libfontconfig1-dev \
+ libfreetype6-dev \
+ libgdal-dev \
+ libgif-dev \
+ libgl1-mesa-dev \
+ libglew-dev \
+ libgsl-dev \
+ libgtest-dev \
+ libgtk2.0-dev \
+ libinput-dev \
+ libjpeg-dev \
+ libjsoncpp-dev \
+ liblapack-dev \
+ liblzma-dev \
+ libopenmpi-dev openmpi-bin \
+ libpng-dev \
+ libpq-dev postgresql-server-dev-11 \
+ libprotobuf-dev libprotobuf-c-dev libprotoc-dev protobuf-compiler \
+ libsdl-dev \
+ libsqlite3-dev \
+ libtiff-dev \
+ libuv1-dev \
+ libx11-dev \
+ libxalan-c-dev \
+ libxerces-c-dev \
+ libxml2-dev libxml2-utils \
+ libxslt-dev xsltproc \
+ python2 python2-dev python-numpy pypy pypy-dev \
+ python3 python3-dev python3-numpy pypy3 pypy3-dev python3-venv \
+ qtbase5-dev qtbase5-dev-tools \
+ ruby ruby-dev \
+ swig \
+ unixodbc-dev
+
+apt-get clean
diff --git a/.gitlab/ci/docker/debian10/Dockerfile b/.gitlab/ci/docker/debian10/Dockerfile
new file mode 100644
index 0000000..34a4bf1
--- /dev/null
+++ b/.gitlab/ci/docker/debian10/Dockerfile
@@ -0,0 +1,25 @@
+FROM debian:10 as iwyu-build
+MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
+
+COPY install_iwyu.sh /root/install_iwyu.sh
+RUN sh /root/install_iwyu.sh
+
+FROM debian:10 as rvm-build
+MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
+
+COPY install_rvm.sh /root/install_rvm.sh
+RUN sh /root/install_rvm.sh
+
+FROM debian:10
+MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
+
+COPY install_deps.sh /root/install_deps.sh
+RUN sh /root/install_deps.sh
+
+COPY --from=iwyu-build /root/iwyu.tar.gz /root/iwyu.tar.gz
+RUN tar -C / -xf /root/iwyu.tar.gz
+RUN ln -s /usr/lib/llvm-6.0/bin/include-what-you-use /usr/bin/include-what-you-use-6.0
+
+COPY --from=rvm-build /root/rvm.tar /root/rvm.tar
+RUN tar -C /usr/local -xf /root/rvm.tar \
+ && rm /root/rvm.tar
diff --git a/.gitlab/ci/docker/debian10/install_deps.sh b/.gitlab/ci/docker/debian10/install_deps.sh
new file mode 100755
index 0000000..e6c9ba0
--- /dev/null
+++ b/.gitlab/ci/docker/debian10/install_deps.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+set -e
+
+apt-get update
+
+# Install build requirements.
+apt-get install -y \
+ libssl-dev
+
+# Install development tools.
+apt-get install -y \
+ g++ \
+ curl \
+ git
+
+# Install iwyu runtime deps.
+apt-get install -y \
+ clang-6.0 \
+ libncurses6
+
+# Tools needed for the test suite.
+apt-get install -y \
+ jq
+
+# Packages needed to test find modules.
+apt-get install -y \
+ alsa-utils \
+ doxygen graphviz \
+ gnutls-dev \
+ libarchive-dev \
+ libblas-dev \
+ libboost-dev \
+ libboost-filesystem-dev \
+ libboost-program-options-dev \
+ libboost-python-dev \
+ libboost-thread-dev \
+ libbz2-dev \
+ libcups2-dev \
+ libcurl4-gnutls-dev \
+ libdevil-dev \
+ libfontconfig1-dev \
+ libfreetype6-dev \
+ libgdal-dev \
+ libgif-dev \
+ libgl1-mesa-dev \
+ libglew-dev \
+ libgsl-dev \
+ libgtest-dev \
+ libgtk2.0-dev \
+ libinput-dev \
+ libjpeg-dev \
+ libjsoncpp-dev \
+ liblapack-dev \
+ liblzma-dev \
+ libopenmpi-dev openmpi-bin \
+ libpng-dev \
+ libpq-dev postgresql-server-dev-11 \
+ libprotobuf-dev libprotobuf-c-dev libprotoc-dev protobuf-compiler \
+ libsdl-dev \
+ libsqlite3-dev \
+ libtiff-dev \
+ libuv1-dev \
+ libx11-dev \
+ libxalan-c-dev \
+ libxerces-c-dev \
+ libxml2-dev libxml2-utils \
+ libxslt-dev xsltproc \
+ python2 python2-dev python-numpy pypy pypy-dev \
+ python3 python3-dev python3-numpy pypy3 pypy3-dev python3-venv \
+ qtbase5-dev qtbase5-dev-tools \
+ ruby ruby-dev \
+ swig \
+ unixodbc-dev
+
+# CMake_TEST_FindPython_IronPython
+apt-get install -y \
+ libmono-system-windows-forms4.0-cil
+curl -L -O https://github.com/IronLanguages/ironpython2/releases/download/ipy-2.7.10/ironpython_2.7.10.deb
+dpkg -i ironpython_2.7.10.deb
+rm ironpython_2.7.10.deb
+
+apt-get clean
diff --git a/.gitlab/ci/docker/debian10/install_iwyu.sh b/.gitlab/ci/docker/debian10/install_iwyu.sh
new file mode 100755
index 0000000..54d26ef
--- /dev/null
+++ b/.gitlab/ci/docker/debian10/install_iwyu.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+set -e
+
+# Install development tools.
+apt-get update
+apt-get install -y \
+ clang-6.0 \
+ libclang-6.0-dev \
+ llvm-6.0-dev \
+ libz-dev \
+ g++ \
+ cmake \
+ ninja-build \
+ git
+
+cd /root
+git clone "https://github.com/include-what-you-use/include-what-you-use.git"
+cd include-what-you-use
+readonly llvm_version="$( clang-6.0 --version | head -n1 | cut -d' ' -f3 | cut -d. -f-2 )"
+git checkout "clang_$llvm_version"
+mkdir build
+cd build
+
+cmake -GNinja \
+ -DCMAKE_BUILD_TYPE=Release \
+ "-DCMAKE_INSTALL_PREFIX=/usr/lib/llvm-$llvm_version" \
+ "-DIWYU_LLVM_ROOT_PATH=/usr/lib/llvm-$llvm_version" \
+ ..
+ninja
+DESTDIR=/root/iwyu-destdir ninja install
+tar -C /root/iwyu-destdir -cf /root/iwyu.tar.gz .
diff --git a/.gitlab/ci/docker/debian10/install_rvm.sh b/.gitlab/ci/docker/debian10/install_rvm.sh
new file mode 100755
index 0000000..2bea511
--- /dev/null
+++ b/.gitlab/ci/docker/debian10/install_rvm.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+set -e
+
+apt-get update
+apt-get install -y \
+ curl \
+ gnupg2 \
+ procps
+
+gpg2 --keyserver hkp://pool.sks-keyservers.net \
+ --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 \
+ 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
+
+curl -sSL https://get.rvm.io | bash -s stable
+
+/usr/local/rvm/bin/rvm install ruby-2.7.0
+
+tar -C /usr/local -cf /root/rvm.tar rvm
diff --git a/.gitlab/ci/docker/fedora33/Dockerfile b/.gitlab/ci/docker/fedora33/Dockerfile
new file mode 100644
index 0000000..8ebcb9e
--- /dev/null
+++ b/.gitlab/ci/docker/fedora33/Dockerfile
@@ -0,0 +1,18 @@
+FROM fedora:33 as rvm-build
+MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
+
+COPY install_rvm.sh /root/install_rvm.sh
+RUN sh /root/install_rvm.sh
+
+FROM fedora:33
+MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
+
+COPY install_deps.sh /root/install_deps.sh
+RUN sh /root/install_deps.sh
+
+COPY install_ispc.sh /root/install_ispc.sh
+RUN sh /root/install_ispc.sh
+
+COPY --from=rvm-build /root/rvm.tar /root/rvm.tar
+RUN tar -C /usr/local -xf /root/rvm.tar \
+ && rm /root/rvm.tar
diff --git a/.gitlab/ci/docker/fedora33/install_deps.sh b/.gitlab/ci/docker/fedora33/install_deps.sh
new file mode 100755
index 0000000..cdfe35e
--- /dev/null
+++ b/.gitlab/ci/docker/fedora33/install_deps.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+set -e
+
+# Install build requirements.
+dnf install --setopt=install_weak_deps=False -y \
+ ncurses-devel \
+ openssl-devel \
+ qt5-qtbase-devel
+
+# Install development tools.
+dnf install --setopt=install_weak_deps=False -y \
+ clang-tools-extra \
+ gcc-c++ \
+ git-core \
+ make
+
+# Install documentation tools.
+dnf install --setopt=install_weak_deps=False -y \
+ python3-sphinx \
+ texinfo \
+ qt5-qttools-devel
+
+# Tools needed for the test suite.
+dnf install --setopt=install_weak_deps=False -y \
+ findutils \
+ file \
+ jq \
+ which
+
+# Packages needed to test find modules.
+dnf install --setopt=install_weak_deps=False -y \
+ alsa-lib-devel \
+ blas-devel \
+ boost-devel boost-python3-devel \
+ bzip2-devel \
+ cups-devel \
+ DevIL-devel \
+ doxygen \
+ expat-devel \
+ fontconfig-devel \
+ freetype-devel \
+ gdal-devel \
+ gettext \
+ giflib-devel \
+ glew-devel \
+ gmock \
+ gnutls-devel \
+ gsl-devel \
+ gtest-devel \
+ gtk2-devel \
+ jsoncpp-devel \
+ lapack-devel \
+ libarchive-devel \
+ libcurl-devel \
+ libinput-devel systemd-devel \
+ libjpeg-turbo-devel \
+ libpng-devel \
+ libpq-devel postgresql-server-devel \
+ libtiff-devel \
+ libuv-devel \
+ libxml2-devel \
+ libxslt-devel \
+ openmpi-devel \
+ patch \
+ perl \
+ protobuf-devel protobuf-c-devel protobuf-lite-devel \
+ pypy2 pypy2-devel \
+ pypy3 pypy3-devel \
+ python2 python2-devel python2-numpy \
+ python3 python3-devel python3-numpy \
+ python3-jsmin python3-jsonschema \
+ ruby rubygems ruby-devel \
+ SDL-devel \
+ sqlite-devel \
+ swig \
+ unixODBC-devel \
+ xalan-c-devel \
+ xerces-c-devel \
+ xz-devel
+
+dnf clean all
diff --git a/.gitlab/ci/docker/fedora33/install_ispc.sh b/.gitlab/ci/docker/fedora33/install_ispc.sh
new file mode 100755
index 0000000..fdc14b5
--- /dev/null
+++ b/.gitlab/ci/docker/fedora33/install_ispc.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+set -e
+
+readonly version="1.13.0"
+readonly sha256sum="8ab1189bd5db596b3eee9d9465d3528b6626a7250675d67102761bb0d284cd21"
+
+readonly filename="ispc-v$version-linux"
+readonly tarball="$filename.tar.gz"
+
+echo "$sha256sum $tarball" > ispc.sha256sum
+curl -OL "https://github.com/ispc/ispc/releases/download/v$version/$tarball"
+sha256sum --check ispc.sha256sum
+tar --strip-components=1 -C /usr/local -xf "$tarball" "$filename/bin/ispc"
diff --git a/.gitlab/ci/docker/fedora33/install_rvm.sh b/.gitlab/ci/docker/fedora33/install_rvm.sh
new file mode 100755
index 0000000..6d4fa97
--- /dev/null
+++ b/.gitlab/ci/docker/fedora33/install_rvm.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+set -e
+
+gpg2 --keyserver hkp://pool.sks-keyservers.net \
+ --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 \
+ 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
+
+dnf install --setopt=install_weak_deps=False -y \
+ findutils \
+ procps \
+ which
+
+curl -sSL https://get.rvm.io | bash -s stable
+
+# This is intentionally an older version.
+# If updating, the associated `env_fedora*_makefiles.cmake` file needs updated
+# as well.
+/usr/local/rvm/bin/rvm install ruby-2.7.0
+
+tar -C /usr/local -cf /root/rvm.tar rvm
diff --git a/.gitlab/ci/docker/ninja/centos7-aarch64.bash b/.gitlab/ci/docker/ninja/centos7-aarch64.bash
new file mode 100755
index 0000000..d24967c
--- /dev/null
+++ b/.gitlab/ci/docker/ninja/centos7-aarch64.bash
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+
+cleanup() {
+ docker container rm -fv "$build_container" >/dev/null 2>&1 || true
+ docker image rm -f "$build_image" >/dev/null 2>&1 || true
+}
+
+readonly suffix="-$(date -u +%Y-%m-%d)-${RANDOM}"
+readonly build_container="ninja-build-linux-aarch64$suffix"
+readonly build_image="ninja:build-linux-aarch64$suffix"
+readonly git_tag="${1-v1.10.2}"
+
+trap "cleanup" EXIT INT TERM
+
+docker image build --build-arg GIT_TAG="$git_tag" --tag="$build_image" "${BASH_SOURCE%/*}/centos7-aarch64"
+docker container create --name "$build_container" "$build_image"
+docker cp "$build_container:/ninja/ninja" "ninja"
diff --git a/.gitlab/ci/docker/ninja/centos7-aarch64/Dockerfile b/.gitlab/ci/docker/ninja/centos7-aarch64/Dockerfile
new file mode 100644
index 0000000..d9e1cc6
--- /dev/null
+++ b/.gitlab/ci/docker/ninja/centos7-aarch64/Dockerfile
@@ -0,0 +1,7 @@
+FROM kitware/cmake:build-linux-aarch64-base-2020-12-21
+MAINTAINER Brad King <brad.king@kitware.com>
+
+ARG GIT_TAG=v1.10.2
+
+COPY build_ninja.sh /root/build_ninja.sh
+RUN scl enable devtoolset-7 -- sh /root/build_ninja.sh $GIT_TAG
diff --git a/.gitlab/ci/docker/ninja/centos7-aarch64/build_ninja.sh b/.gitlab/ci/docker/ninja/centos7-aarch64/build_ninja.sh
new file mode 100755
index 0000000..7e2602c
--- /dev/null
+++ b/.gitlab/ci/docker/ninja/centos7-aarch64/build_ninja.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+set -e
+
+git clone https://github.com/ninja-build/ninja.git
+cd ninja
+git checkout "${1-v1.10.2}"
+./configure.py --bootstrap
+./ninja all
+./ninja_test
+strip ninja
diff --git a/.gitlab/ci/download_python3.cmake b/.gitlab/ci/download_python3.cmake
new file mode 100644
index 0000000..0f5b18b
--- /dev/null
+++ b/.gitlab/ci/download_python3.cmake
@@ -0,0 +1,41 @@
+cmake_minimum_required(VERSION 3.17)
+
+set(version "3.8.6")
+set(sha256sum "376e18eef7e3ea467f0e3af041b01fc7e2f12855506c2ab2653ceb5e0951212e")
+set(dirname "python-${version}-embed-win-x86_64")
+set(tarball "${dirname}.tar.xz")
+
+# Download the file.
+file(DOWNLOAD
+ "https://cmake.org/files/dependencies/${tarball}"
+ ".gitlab/${tarball}"
+ STATUS download_status
+ EXPECTED_HASH "SHA256=${sha256sum}")
+
+# Check the download status.
+list(GET download_status 0 res)
+if (res)
+ list(GET download_status 1 err)
+ message(FATAL_ERROR
+ "Failed to download ${tarball}: ${err}")
+endif ()
+
+# Extract the file.
+execute_process(
+ COMMAND
+ "${CMAKE_COMMAND}"
+ -E tar
+ xzf "${tarball}"
+ WORKING_DIRECTORY ".gitlab"
+ RESULT_VARIABLE res
+ ERROR_VARIABLE err
+ ERROR_STRIP_TRAILING_WHITESPACE)
+if (res)
+ message(FATAL_ERROR
+ "Failed to extract ${tarball}: ${err}")
+endif ()
+
+# Move to a predictable directory.
+file(RENAME
+ ".gitlab/${dirname}"
+ ".gitlab/python3")
diff --git a/.gitlab/ci/download_qt.cmake b/.gitlab/ci/download_qt.cmake
new file mode 100644
index 0000000..3990430
--- /dev/null
+++ b/.gitlab/ci/download_qt.cmake
@@ -0,0 +1,135 @@
+cmake_minimum_required(VERSION 3.12)
+
+# Input variables.
+set(qt_version_major "5")
+set(qt_version_minor "15")
+set(qt_version_patch "1")
+
+# Combined version variables.
+set(qt_version "${qt_version_major}.${qt_version_minor}.${qt_version_patch}")
+set(qt_version_nodot "${qt_version_major}${qt_version_minor}${qt_version_patch}")
+
+# Files needed to download.
+set(qt_files)
+if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "windows")
+ # Determine the ABI to fetch for Qt.
+ if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "vs2015")
+ set(qt_platform "windows_x86")
+ set(msvc_year "2015")
+ set(qt_abi "win64_msvc${msvc_year}_64")
+ elseif ("$ENV{CMAKE_CONFIGURATION}" MATCHES "vs2017" OR
+ "$ENV{CMAKE_CONFIGURATION}" MATCHES "vs2019")
+ set(qt_platform "windows_x86")
+ set(msvc_year "2019")
+ set(qt_abi "win64_msvc${msvc_year}_64")
+ else ()
+ message(FATAL_ERROR "Unknown ABI to use for Qt")
+ endif ()
+
+ set(qt_build_stamp "202009071110")
+
+ set(qt_file_name_prefix "${qt_version}-0-${qt_build_stamp}")
+
+ foreach (qt_component IN ITEMS qtbase qtwinextras)
+ list(APPEND qt_files
+ "${qt_file_name_prefix}${qt_component}-Windows-Windows_10-MSVC${msvc_year}-Windows-Windows_10-X86_64.7z")
+ endforeach ()
+
+ set(qt_subdir "${qt_version}/msvc${msvc_year}_64")
+
+ # This URL is only visible inside of Kitware's network.
+ # Please use your own Qt Account to obtain these files.
+ set(qt_url_root "https://paraview.org/files/dependencies/internal/qt")
+ set(qt_url_path "${qt_platform}/desktop/qt5_${qt_version_nodot}/qt.qt5.${qt_version_nodot}.${qt_abi}")
+elseif ("$ENV{CMAKE_CONFIGURATION}" MATCHES "macos")
+ if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "macos10.10_package")
+ list(APPEND qt_files "qt-5.9.9-macosx10.10-x86_64-arm64.tar.xz")
+ set(qt_subdir "qt-5.9.9-macosx10.10-x86_64-arm64")
+ else ()
+ list(APPEND qt_files "qt-5.15.2-macosx10.13-x86_64-arm64.tar.xz")
+ set(qt_subdir "qt-5.15.2-macosx10.13-x86_64-arm64")
+ endif()
+ set(qt_url_root "https://cmake.org/files/dependencies")
+ set(qt_url_path "")
+else()
+ message(FATAL_ERROR "Unknown OS to use for Qt")
+endif ()
+
+# Verify that we know what directory will be extracted.
+if (NOT qt_subdir)
+ message(FATAL_ERROR
+ "The extracted subdirectory is not set")
+endif ()
+
+# Build up the path to the file to download.
+set(qt_url_prefix "${qt_url_root}/${qt_url_path}")
+
+# Include the file containing the hashes of the files that matter.
+include("${CMAKE_CURRENT_LIST_DIR}/download_qt_hashes.cmake")
+
+# Download and extract each file.
+foreach (qt_file IN LISTS qt_files)
+ # Ensure we have a hash to verify.
+ if (NOT DEFINED "${qt_file}_hash")
+ message(FATAL_ERROR
+ "Unknown hash for ${qt_file}")
+ endif ()
+
+ # Download the file.
+ file(DOWNLOAD
+ "${qt_url_prefix}/${qt_file}"
+ ".gitlab/${qt_file}"
+ STATUS download_status
+ EXPECTED_HASH "SHA256=${${qt_file}_hash}")
+
+ # Check the download status.
+ list(GET download_status 0 res)
+ if (res)
+ list(GET download_status 1 err)
+ message(FATAL_ERROR
+ "Failed to download ${qt_file}: ${err}")
+ endif ()
+
+ # Extract the file.
+ execute_process(
+ COMMAND
+ "${CMAKE_COMMAND}"
+ -E tar
+ xf "${qt_file}"
+ WORKING_DIRECTORY ".gitlab"
+ RESULT_VARIABLE res
+ ERROR_VARIABLE err
+ ERROR_STRIP_TRAILING_WHITESPACE)
+ if (res)
+ message(FATAL_ERROR
+ "Failed to extract ${qt_file}: ${err}")
+ endif ()
+endforeach ()
+
+# The Windows tarballs have some unfortunate permissions in them that prevent
+# deletion when `git clean -ffdx` tries to clean up the directory.
+if (qt_platform STREQUAL "windows_x86")
+ # Fix permissions.
+ file(TO_NATIVE_PATH ".gitlab/${qt_subdir}/*.*" native_qt_dir)
+ execute_process(
+ # Remove any read-only flags that aren't affected by `icacls`.
+ COMMAND
+ attrib
+ -r # Remove readonly flag
+ "${native_qt_dir}"
+ /d # Treat as a directory
+ /s # Recursive
+ /l # Don't dereference symlinks
+ RESULT_VARIABLE res
+ ERROR_VARIABLE err
+ ERROR_STRIP_TRAILING_WHITESPACE)
+ if (res)
+ message(FATAL_ERROR
+ "Failed to fix remove read-only flags in ${qt_file}: ${err}")
+ endif ()
+endif ()
+
+# Move to a predictable prefix.
+file(RENAME
+ ".gitlab/${qt_subdir}"
+ ".gitlab/qt")
diff --git a/.gitlab/ci/download_qt_hashes.cmake b/.gitlab/ci/download_qt_hashes.cmake
new file mode 100644
index 0000000..afbc081
--- /dev/null
+++ b/.gitlab/ci/download_qt_hashes.cmake
@@ -0,0 +1,14 @@
+# Lines can be generated by doing:
+#
+# sha256sum $files | awk '{ print "set(\"" $2 "_hash\" " $1 ")" }' >> $thisfile
+
+set("5.15.1-0-202009071110qtbase-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z_hash" a5635124a135f383d9fb92bf628b018cff9f781addfd388926a367cda5b7cd38)
+set("5.15.1-0-202009071110qtwinextras-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z_hash" 908947855b5d7a854886746365ac29e9296b5d64d4e18089641a6988167807d3)
+
+set("5.15.1-0-202009071110qtbase-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z_hash" 5d0d2e71e3b00cf88ac4c616b4b314a7e73871f325512821f53c464cdfee961f)
+set("5.15.1-0-202009071110qtwinextras-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z_hash" 803e0234169464babb5305dedc21382e90c3266c6f9414ff0cff04be578681e1)
+
+set("5.15.1-0-202009071110qtbase-MacOS-MacOS_10_13-Clang-MacOS-MacOS_10_13-X86_64.7z_hash" df2813ce7c6cb4287abd7956cd1cb9d08312e4ac1208b6cb57af4df11b8ebba1)
+
+set("qt-5.9.9-macosx10.10-x86_64-arm64.tar.xz_hash" d4449771afa0bc6a809c14f1e6d939e7732494cf059503ae451e2bfe8fc60cc1)
+set("qt-5.15.2-macosx10.13-x86_64-arm64.tar.xz_hash" 7b9463a01c8beeee5bf8d01c70deff2d08561cd20aaf6f7a2f41cf8b68ce8a6b)
diff --git a/.gitlab/ci/env.sh b/.gitlab/ci/env.sh
new file mode 100644
index 0000000..7634f5d
--- /dev/null
+++ b/.gitlab/ci/env.sh
@@ -0,0 +1,14 @@
+quietly() {
+ readonly log="/tmp/quietly-$RANDOM.log"
+ if ! "$@" >"$log" 2>&1; then
+ ret=$?
+ cat "$log"
+ rm -f "$log"
+ exit $ret
+ fi
+ rm -f "$log"
+}
+
+if test -r ".gitlab/ci/env_${CMAKE_CONFIGURATION}.sh"; then
+ source ".gitlab/ci/env_${CMAKE_CONFIGURATION}.sh"
+fi
diff --git a/.gitlab/ci/env_debian10_ninja.cmake b/.gitlab/ci/env_debian10_ninja.cmake
new file mode 100644
index 0000000..ec252b4
--- /dev/null
+++ b/.gitlab/ci/env_debian10_ninja.cmake
@@ -0,0 +1 @@
+set(ENV{MY_RUBY_HOME} "/usr/local/rvm/rubies/ruby-2.7.0")
diff --git a/.gitlab/ci/env_fedora33_makefiles.cmake b/.gitlab/ci/env_fedora33_makefiles.cmake
new file mode 100644
index 0000000..1d0efa7
--- /dev/null
+++ b/.gitlab/ci/env_fedora33_makefiles.cmake
@@ -0,0 +1,2 @@
+set(ENV{MY_RUBY_HOME} "/usr/local/rvm/rubies/ruby-2.7.0")
+set(ENV{PATH} "/usr/lib64/openmpi/bin:$ENV{PATH}")
diff --git a/.gitlab/ci/env_intelclassic_common.sh b/.gitlab/ci/env_intelclassic_common.sh
new file mode 100644
index 0000000..22b1d03
--- /dev/null
+++ b/.gitlab/ci/env_intelclassic_common.sh
@@ -0,0 +1,9 @@
+source .gitlab/ci/env_intelcompiler_license.sh
+
+if test -r /opt/intel/oneapi/setvars.sh; then
+ source /opt/intel/oneapi/setvars.sh
+elif test -r /opt/intel/bin/compilervars.sh; then
+ source /opt/intel/bin/compilervars.sh intel64
+fi
+
+export CC=icc CXX=icpc FC=ifort
diff --git a/.gitlab/ci/env_intelclassic_makefiles.sh b/.gitlab/ci/env_intelclassic_makefiles.sh
new file mode 100644
index 0000000..d1ff85e
--- /dev/null
+++ b/.gitlab/ci/env_intelclassic_makefiles.sh
@@ -0,0 +1 @@
+source .gitlab/ci/env_intelclassic_common.sh
diff --git a/.gitlab/ci/env_intelcompiler_license.sh b/.gitlab/ci/env_intelcompiler_license.sh
new file mode 100644
index 0000000..54743b2
--- /dev/null
+++ b/.gitlab/ci/env_intelcompiler_license.sh
@@ -0,0 +1,8 @@
+if test -n "$CMAKE_CI_INTELCOMPILER_LICENSE"; then
+ if test -d /opt/intel/licenses; then
+ mv "$CMAKE_CI_INTELCOMPILER_LICENSE" /opt/intel/licenses/ci.lic
+ else
+ rm "$CMAKE_CI_INTELCOMPILER_LICENSE"
+ fi
+ unset CMAKE_CI_INTELCOMPILER_LICENSE
+fi
diff --git a/.gitlab/ci/env_inteloneapi_common.sh b/.gitlab/ci/env_inteloneapi_common.sh
new file mode 100644
index 0000000..beaf3fe
--- /dev/null
+++ b/.gitlab/ci/env_inteloneapi_common.sh
@@ -0,0 +1,7 @@
+source .gitlab/ci/env_intelcompiler_license.sh
+
+if test -r /opt/intel/oneapi/setvars.sh; then
+ source /opt/intel/oneapi/setvars.sh
+fi
+
+export CC=icx CXX=icpx FC=ifx
diff --git a/.gitlab/ci/env_inteloneapi_makefiles.sh b/.gitlab/ci/env_inteloneapi_makefiles.sh
new file mode 100644
index 0000000..eefcdda
--- /dev/null
+++ b/.gitlab/ci/env_inteloneapi_makefiles.sh
@@ -0,0 +1 @@
+source .gitlab/ci/env_inteloneapi_common.sh
diff --git a/.gitlab/ci/gitlab_ci.cmake b/.gitlab/ci/gitlab_ci.cmake
new file mode 100644
index 0000000..f166215
--- /dev/null
+++ b/.gitlab/ci/gitlab_ci.cmake
@@ -0,0 +1,75 @@
+if (NOT DEFINED "ENV{GITLAB_CI}")
+ message(FATAL_ERROR
+ "This script assumes it is being run inside of GitLab-CI")
+endif ()
+
+# Set up the source and build paths.
+set(CTEST_SOURCE_DIRECTORY "$ENV{CI_PROJECT_DIR}")
+set(CTEST_BINARY_DIRECTORY "${CTEST_SOURCE_DIRECTORY}/build")
+if (NOT "$ENV{CTEST_SOURCE_SUBDIRECTORY}" STREQUAL "")
+ string(APPEND CTEST_SOURCE_DIRECTORY "/$ENV{CTEST_SOURCE_SUBDIRECTORY}")
+endif ()
+
+if ("$ENV{CMAKE_CONFIGURATION}" STREQUAL "")
+ message(FATAL_ERROR
+ "The CMAKE_CONFIGURATION environment variable is required to know what "
+ "cache initialization file to use.")
+endif ()
+
+# Set the build metadata.
+if(NOT "$ENV{CMAKE_CI_BUILD_NAME}" STREQUAL "")
+ set(CTEST_BUILD_NAME "$ENV{CI_PROJECT_NAME}-$ENV{CMAKE_CI_BUILD_NAME}")
+else()
+ set(CTEST_BUILD_NAME "$ENV{CI_PROJECT_NAME}-$ENV{CMAKE_CONFIGURATION}")
+endif()
+set(CTEST_SITE "gitlab-ci")
+set(ctest_model "Experimental")
+
+# Default to Release builds.
+if (NOT "$ENV{CMAKE_BUILD_TYPE}" STREQUAL "")
+ set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_BUILD_TYPE}")
+endif ()
+if (NOT CTEST_BUILD_CONFIGURATION)
+ set(CTEST_BUILD_CONFIGURATION "Release")
+endif ()
+set(CTEST_CONFIGURATION_TYPE "${CTEST_BUILD_CONFIGURATION}")
+
+# Default to using Ninja.
+if (NOT "$ENV{CMAKE_GENERATOR}" STREQUAL "")
+ set(CTEST_CMAKE_GENERATOR "$ENV{CMAKE_GENERATOR}")
+endif ()
+if (NOT CTEST_CMAKE_GENERATOR)
+ set(CTEST_CMAKE_GENERATOR "Ninja")
+endif ()
+
+# Set the toolset and platform if requested.
+if (NOT "$ENV{CMAKE_GENERATOR_PLATFORM}" STREQUAL "")
+ set(CTEST_CMAKE_GENERATOR_PLATFORM "$ENV{CMAKE_GENERATOR_PLATFORM}")
+endif ()
+if (NOT "$ENV{CMAKE_GENERATOR_TOOLSET}" STREQUAL "")
+ set(CTEST_CMAKE_GENERATOR_TOOLSET "$ENV{CMAKE_GENERATOR_TOOLSET}")
+endif ()
+
+# Determine the group to submit to.
+set(ctest_group "Experimental")
+if (NOT "$ENV{CI_MERGE_REQUEST_ID}" STREQUAL "")
+ set(ctest_group "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 "")
+ set(ctest_model "Continuous")
+ if (NOT "$ENV{CMAKE_CI_JOB_HELP}" STREQUAL "")
+ set(ctest_group "Continuous Help")
+ else()
+ set(ctest_group "Continuous")
+ endif()
+ string(PREPEND CTEST_BUILD_NAME "continuous-")
+elseif (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
+ set(ctest_model "Nightly")
+ set(ctest_group "Nightly Expected")
+ string(PREPEND CTEST_BUILD_NAME "nightly-")
+elseif ("$ENV{CI_PROJECT_PATH}" STREQUAL "cmake/cmake")
+ if ("$ENV{CI_COMMIT_REF_NAME}" STREQUAL "master")
+ set(ctest_group "master")
+ elseif ("$ENV{CI_COMMIT_REF_NAME}" STREQUAL "release")
+ set(ctest_group "release")
+ endif ()
+endif ()
diff --git a/.gitlab/ci/ninja.ps1 b/.gitlab/ci/ninja.ps1
new file mode 100755
index 0000000..4c5333a
--- /dev/null
+++ b/.gitlab/ci/ninja.ps1
@@ -0,0 +1,18 @@
+$erroractionpreference = "stop"
+
+$version = "1.10.2"
+$sha256sum = "BBDE850D247D2737C5764C927D1071CBB1F1957DCABDA4A130FA8547C12C695F"
+$filename = "ninja-win"
+$tarball = "$filename.zip"
+
+$outdir = $pwd.Path
+$outdir = "$outdir\.gitlab"
+$ProgressPreference = 'SilentlyContinue'
+Invoke-WebRequest -Uri "https://github.com/ninja-build/ninja/releases/download/v$version/$tarball" -OutFile "$outdir\$tarball"
+$hash = Get-FileHash "$outdir\$tarball" -Algorithm SHA256
+if ($hash.Hash -ne $sha256sum) {
+ exit 1
+}
+
+Add-Type -AssemblyName System.IO.Compression.FileSystem
+[System.IO.Compression.ZipFile]::ExtractToDirectory("$outdir\$tarball", "$outdir")
diff --git a/.gitlab/ci/ninja.sh b/.gitlab/ci/ninja.sh
new file mode 100755
index 0000000..8ead670
--- /dev/null
+++ b/.gitlab/ci/ninja.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+set -e
+
+readonly version="1.10.2"
+baseurl="https://github.com/ninja-build/ninja/releases/download/v$version"
+
+case "$(uname -s)-$(uname -m)" in
+ Linux-x86_64)
+ shatool="sha256sum"
+ sha256sum="763464859c7ef2ea3a0a10f4df40d2025d3bb9438fcb1228404640410c0ec22d"
+ filename="ninja-linux"
+ ;;
+ Linux-aarch64)
+ shatool="sha256sum"
+ sha256sum="c0c29925fd7f0f24981b3b9d18353c7111c9af59eb6e6b0ffc0c4914cdc7999c"
+ # Use binary built by adjacent 'docker/ninja/centos7-aarch64.bash' script.
+ baseurl="https://cmake.org/files/dependencies"
+ filename="ninja-$version-1-linux-aarch64"
+ ;;
+ Darwin-*)
+ shatool="shasum -a 256"
+ sha256sum="6fa359f491fac7e5185273c6421a000eea6a2f0febf0ac03ac900bd4d80ed2a5"
+ filename="ninja-mac"
+ ;;
+ *)
+ echo "Unrecognized platform $(uname -s)-$(uname -m)"
+ exit 1
+ ;;
+esac
+readonly shatool
+readonly sha256sum
+
+readonly tarball="$filename.zip"
+
+cd .gitlab
+
+echo "$sha256sum $tarball" > ninja.sha256sum
+curl -OL "$baseurl/$tarball"
+$shatool --check ninja.sha256sum
+./cmake/bin/cmake -E tar xf "$tarball"
diff --git a/.gitlab/ci/sccache.sh b/.gitlab/ci/sccache.sh
new file mode 100755
index 0000000..12b8f9d
--- /dev/null
+++ b/.gitlab/ci/sccache.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+set -e
+
+readonly kernel="$(uname -s)-$(uname -m)"
+case $kernel in
+ Linux-x86_64)
+ version="v0.2.15"
+ shatool="sha256sum"
+ sha256sum="e5d03a9aa3b9fac7e490391bbe22d4f42c840d31ef9eaf127a03101930cbb7ca"
+ platform="x86_64-unknown-linux-musl"
+ ;;
+ Linux-aarch64)
+ version="v0.2.15"
+ shatool="sha256sum"
+ sha256sum="90d91d21a767e3f558196dbd52395f6475c08de5c4951a4c8049575fa6894489"
+ platform="aarch64-unknown-linux-musl"
+ ;;
+ Darwin-x86_64)
+ version="gfe63078"
+ shatool="shasum -a 256"
+ sha256sum="60a0302b1d7227f7ef56abd82266353f570d27c6e850c56c6448bf62def38888"
+ platform="x86_64-apple-darwin"
+ url="https://paraview.org/files/dependencies"
+ ;;
+ Darwin-arm64)
+ version="0.2.15-1-disk_cache_init"
+ shatool="shasum -a 256"
+ sha256sum="f7c9ff78e701810b8b1dbc2a163c7fda1177fc3f69c71f46e7a38242657a99fd"
+ platform="aarch64-apple-darwin"
+ url="https://cmake.org/files/dependencies/sccache"
+ ;;
+ *)
+ echo "Unrecognized platform $kernel"
+ exit 1
+ ;;
+esac
+readonly version
+readonly shatool
+readonly sha256sum
+readonly platform
+
+readonly filename="sccache-$version-$platform"
+readonly tarball="$filename.tar.gz"
+
+if [ -z "$url" ]; then
+ url="https://github.com/mozilla/sccache/releases/download/$version"
+fi
+readonly url
+
+cd .gitlab
+
+echo "$sha256sum $tarball" > sccache.sha256sum
+curl -OL "$url/$tarball"
+$shatool --check sccache.sha256sum
+tar xf "$tarball"
+mv "$filename/sccache" .
+chmod +x sccache
diff --git a/.gitlab/ci/vcvarsall.ps1 b/.gitlab/ci/vcvarsall.ps1
new file mode 100755
index 0000000..57d3386
--- /dev/null
+++ b/.gitlab/ci/vcvarsall.ps1
@@ -0,0 +1,9 @@
+$erroractionpreference = "stop"
+
+cmd /c "`"$env:VCVARSALL`" $VCVARSPLATFORM -vcvars_ver=$VCVARSVERSION & set" |
+foreach {
+ if ($_ -match "=") {
+ $v = $_.split("=")
+ [Environment]::SetEnvironmentVariable($v[0], $v[1])
+ }
+}
diff --git a/.gitlab/ci/wix.ps1 b/.gitlab/ci/wix.ps1
new file mode 100755
index 0000000..a9322b6
--- /dev/null
+++ b/.gitlab/ci/wix.ps1
@@ -0,0 +1,18 @@
+$erroractionpreference = "stop"
+
+$release = "wix3112rtm"
+$sha256sum = "2C1888D5D1DBA377FC7FA14444CF556963747FF9A0A289A3599CF09DA03B9E2E"
+$filename = "wix311-binaries"
+$tarball = "$filename.zip"
+
+$outdir = $pwd.Path
+$outdir = "$outdir\.gitlab"
+$ProgressPreference = 'SilentlyContinue'
+Invoke-WebRequest -Uri "https://github.com/wixtoolset/wix3/releases/download/$release/$tarball" -OutFile "$outdir\$tarball"
+$hash = Get-FileHash "$outdir\$tarball" -Algorithm SHA256
+if ($hash.Hash -ne $sha256sum) {
+ exit 1
+}
+
+Add-Type -AssemblyName System.IO.Compression.FileSystem
+[System.IO.Compression.ZipFile]::ExtractToDirectory("$outdir\$tarball", "$outdir\wix\bin")
diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml
new file mode 100644
index 0000000..81c4d8d
--- /dev/null
+++ b/.gitlab/os-linux.yml
@@ -0,0 +1,370 @@
+# Linux-specific builder configurations and build commands
+
+## Base images
+
+### Release
+
+.linux_prep_source:
+ image: "fedora:33"
+
+ variables:
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+
+.linux_release_x86_64:
+ image: "kitware/cmake:build-linux-x86_64-deps-2020-04-02@sha256:77e9ab183f34680990db9da5945473e288f0d6556bce79ecc1589670d656e157"
+
+ variables:
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+ LAUNCHER: "scl enable devtoolset-6 rh-python36 --"
+ CMAKE_ARCH: x86_64
+
+.linux_release_aarch64:
+ image: "kitware/cmake:build-linux-aarch64-deps-2020-12-21@sha256:0bd7dfe4e45593b04e39cd21e44011034610cfd376900558c5ef959bb1af15af"
+
+ variables:
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+ LAUNCHER: "scl enable devtoolset-7 --"
+ CMAKE_ARCH: aarch64
+
+.linux_package:
+ variables:
+ BOOTSTRAP_ARGS: '-- "-DCMake_DOC_ARTIFACT_PREFIX=$CI_PROJECT_DIR/build/install-doc"'
+
+.needs_centos6_x86_64:
+ dependencies:
+ - build:centos6-x86_64
+ needs:
+ - build:centos6-x86_64
+
+.needs_centos7_aarch64:
+ dependencies:
+ - build:centos7-aarch64
+ needs:
+ - build:centos7-aarch64
+
+### Debian
+
+.debian10:
+ image: "kitware/cmake:ci-debian10-x86_64-2021-04-06"
+
+ variables:
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+ CMAKE_ARCH: x86_64
+
+.debian10_iwyu:
+ extends: .debian10
+
+ variables:
+ CMAKE_CONFIGURATION: debian10_iwyu
+ CTEST_NO_WARNINGS_ALLOWED: 1
+ CMake_SKIP_INSTALL: 1
+
+.debian10_aarch64:
+ image: "kitware/cmake:ci-debian10-aarch64-2021-04-06"
+
+ variables:
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+ CMAKE_ARCH: aarch64
+
+### Fedora
+
+.fedora33:
+ image: "kitware/cmake:ci-fedora33-x86_64-2021-04-06"
+
+ variables:
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci/long file name for testing purposes"
+ CMAKE_ARCH: x86_64
+
+#### Lint builds
+
+.fedora33_tidy:
+ extends: .fedora33
+
+ variables:
+ CMAKE_CONFIGURATION: fedora33_tidy
+ CTEST_NO_WARNINGS_ALLOWED: 1
+ CMake_SKIP_INSTALL: 1
+
+.fedora33_sphinx:
+ extends: .fedora33
+
+ variables:
+ CMAKE_CONFIGURATION: fedora33_sphinx
+ CTEST_NO_WARNINGS_ALLOWED: 1
+ CTEST_SOURCE_SUBDIRECTORY: "Utilities/Sphinx"
+ CMake_SKIP_INSTALL: 1
+
+.fedora33_sphinx_package:
+ extends: .fedora33
+
+ variables:
+ CMAKE_CONFIGURATION: fedora33_sphinx_package
+ CTEST_SOURCE_SUBDIRECTORY: "Utilities/Sphinx"
+
+#### Build and test
+
+.debian10_ninja:
+ extends: .debian10
+
+ variables:
+ CMAKE_CONFIGURATION: debian10_ninja
+ CTEST_NO_WARNINGS_ALLOWED: 1
+
+.debian10_aarch64_ninja:
+ extends: .debian10_aarch64
+
+ variables:
+ CMAKE_CONFIGURATION: debian10_aarch64_ninja
+ CTEST_NO_WARNINGS_ALLOWED: 1
+
+.fedora33_ninja:
+ extends: .fedora33
+
+ variables:
+ CMAKE_CONFIGURATION: fedora33_ninja
+ CTEST_NO_WARNINGS_ALLOWED: 1
+
+.fedora33_ninja_multi:
+ extends: .fedora33
+
+ variables:
+ CMAKE_CONFIGURATION: fedora33_ninja_multi
+ CTEST_NO_WARNINGS_ALLOWED: 1
+ CMAKE_GENERATOR: "Ninja Multi-Config"
+
+.fedora33_makefiles:
+ extends: .fedora33
+
+ variables:
+ CMAKE_CONFIGURATION: fedora33_makefiles
+ CTEST_NO_WARNINGS_ALLOWED: 1
+ CMAKE_GENERATOR: "Unix Makefiles"
+
+### Intel Compiler
+
+.intelcompiler:
+ image: "kitware/intelcompiler:$CMAKE_CI_INTELCOMPILER_IMAGE_TAG"
+ environment:
+ name: intel-compiler
+ variables:
+ CMAKE_ARCH: x86_64
+
+.intelclassic_makefiles:
+ extends: .intelcompiler
+ variables:
+ CMAKE_CONFIGURATION: intelclassic_makefiles
+ CMAKE_GENERATOR: "Unix Makefiles"
+
+.inteloneapi_makefiles:
+ extends: .intelcompiler
+ variables:
+ CMAKE_CONFIGURATION: inteloneapi_makefiles
+ CMAKE_GENERATOR: "Unix Makefiles"
+
+### CUDA builds
+
+.cuda10.2:
+ image: "kitware/cmake:ci-cuda10.2-x86_64-2020-06-11"
+
+ variables:
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+ CMAKE_ARCH: x86_64
+ CTEST_LABELS: "CUDA"
+
+.cuda10.2_nvidia:
+ extends: .cuda10.2
+
+ variables:
+ CMAKE_CONFIGURATION: cuda10.2_nvidia
+ CTEST_NO_WARNINGS_ALLOWED: 1
+
+## Tags
+
+.linux_builder_tags:
+ tags:
+ - cmake
+ - build
+ - docker
+ - linux
+
+.linux_builder_tags_qt:
+ tags:
+ - cmake
+ - build
+ - docker
+ - linux
+ - linux-3.17 # Needed to be able to load Fedora's Qt libraries.
+
+.linux_builder_tags_x11:
+ tags:
+ - cmake
+ - docker
+ - linux
+ - linux-3.17 # Needed to be able to load Fedora's Qt libraries.
+ - x11
+
+.linux_builder_tags_cuda:
+ tags:
+ - cmake
+ - cuda-rt
+ - docker
+ - linux
+
+.linux_builder_tags_aarch64:
+ tags:
+ - cmake
+ - build
+ - docker
+ - linux-aarch64
+
+.linux_builder_tags_aarch64_qt:
+ tags:
+ - cmake
+ - build
+ - docker
+ - linux-aarch64
+ - linux-3.17 # Needed to be able to load Fedora's Qt libraries.
+
+## Linux-specific scripts
+
+.before_script_linux: &before_script_linux
+ - source .gitlab/ci/env.sh
+ - .gitlab/ci/cmake.sh
+ - .gitlab/ci/ninja.sh
+ - export PATH=$PWD/.gitlab:$PWD/.gitlab/cmake/bin:$PATH
+ - 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
+
+ script:
+ - *before_script_linux
+ - .gitlab/ci/sccache.sh
+ - sccache --start-server
+ - sccache --show-stats
+ - "$LAUNCHER ctest -VV -S .gitlab/ci/ctest_configure.cmake"
+ - "$LAUNCHER ctest -VV -S .gitlab/ci/ctest_build.cmake"
+ - sccache --show-stats
+
+ interruptible: true
+
+.cmake_test_linux:
+ stage: test
+
+ script:
+ - *before_script_linux
+ - "$LAUNCHER ctest --output-on-failure -V -S .gitlab/ci/ctest_test.cmake"
+
+ interruptible: true
+
+.cmake_build_linux_release:
+ stage: build
+
+ script:
+ - source .gitlab/ci/env.sh
+ # Bootstrap.
+ - mkdir -p build/
+ # Exclude documentation. A job dependency provides it for packaging.
+ - sed '/^# Build doc/,/^$/d' Utilities/Release/linux/$CMAKE_ARCH/cache.txt > build/CMakeCache.txt
+ # Make sccache available.
+ - .gitlab/ci/sccache.sh
+ - export PATH=$PWD/.gitlab:$PATH
+ # Append sccache settings to the cache.
+ - echo "CMAKE_C_COMPILER_LAUNCHER:STRING=sccache" >> build/CMakeCache.txt
+ - echo "CMAKE_CXX_COMPILER_LAUNCHER:STRING=sccache" >> build/CMakeCache.txt
+ # CI settings.
+ - echo "CMake_TEST_INSTALL:BOOL=OFF" >> build/CMakeCache.txt
+ - echo "CMAKE_INSTALL_PREFIX:PATH=$PWD/build/install" >> build/CMakeCache.txt
+ - echo "CMAKE_SKIP_INSTALL_ALL_DEPENDENCY:BOOL=ON" >> build/CMakeCache.txt
+ # Appease Git. The Git in this container is old (1.7) and doesn't
+ # understand some things. But, it doesn't need to, so make it blind.
+ - mkdir -p .git/info
+ - echo "* -crlf" >> .git/info/attributes
+ - git reset --hard
+ # Bootstrap
+ - cd build/
+ - '$LAUNCHER ../bootstrap --parallel=$(nproc) --docdir=doc/cmake $BOOTSTRAP_ARGS'
+ # FIXME: When CTest can drive an external CMake for the build as well,
+ # use the scripts here.
+ - "$LAUNCHER make -j$(nproc)"
+ # NOTE: This regex matches that used in the release build.
+ - "$LAUNCHER bin/ctest --output-on-failure -j$(nproc) -R '^(CMake\\.|CMakeLib\\.|CMakeServerLib\\.|RunCMake\\.ctest_memcheck)'"
+ # Make a package.
+ - bin/cpack -G TGZ
+ - bin/cpack -G STGZ
+ - sccache --show-stats
+
+ interruptible: true
+
+.cmake_test_linux_release:
+ stage: test-ext
+
+ script:
+ - *before_script_linux
+ # Make the CMake package available.
+ - mkdir -p build/install
+ - tar -C build/install --strip-components=1 -xzf build/cmake-*-linux-$CMAKE_ARCH.tar.gz
+ - .gitlab/ci/sccache.sh
+ - sccache --start-server
+ - sccache --show-stats
+ - "$LAUNCHER build/install/bin/ctest --output-on-failure -V -S .gitlab/ci/ctest_test_external.cmake"
+ - sccache --show-stats
+
+ interruptible: true
+
+.cmake_test_linux_external:
+ stage: test-ext
+
+ script:
+ - *before_script_linux
+ - .gitlab/ci/sccache.sh
+ - sccache --start-server
+ - sccache --show-stats
+ - "$LAUNCHER build/install/bin/ctest --output-on-failure -V -S .gitlab/ci/ctest_test_external.cmake"
+ - sccache --show-stats
+
+ interruptible: true
+
+.cmake_test_linux_intelclassic_makefiles:
+ extends:
+ - .intelclassic_makefiles
+ - .cmake_test_linux_release
+ - .linux_builder_tags_qt
+ - .run_manually
+ - .needs_centos6_x86_64
+ variables:
+ CMAKE_CI_JOB_NIGHTLY: "true"
+
+.cmake_test_linux_inteloneapi_makefiles:
+ extends:
+ - .inteloneapi_makefiles
+ - .cmake_test_linux_release
+ - .linux_builder_tags_qt
+ - .run_manually
+ - .needs_centos6_x86_64
+ variables:
+ CMAKE_CI_JOB_NIGHTLY: "true"
diff --git a/.gitlab/os-macos.yml b/.gitlab/os-macos.yml
new file mode 100644
index 0000000..1ce96b3
--- /dev/null
+++ b/.gitlab/os-macos.yml
@@ -0,0 +1,187 @@
+# macOS-specific builder configurations and build commands
+
+## Base configurations
+
+.macos:
+ variables:
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci ext/$CI_CONCURRENT_ID"
+ # 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-12.4.app/Contents/Developer"
+ # Avoid conflicting with other projects running on the same machine.
+ SCCACHE_SERVER_PORT: 4227
+
+### Build and test
+
+.macos_build:
+ extends: .macos
+
+ variables:
+ # Note that shell runners only support runners with a single
+ # concurrency level. We can't use `$CI_CONCURRENCY_ID` because this may
+ # change between the build and test stages which CMake doesn't support.
+ # Even if we could, it could change if other runners on the machine
+ # could run at the same time, so we drop it.
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+
+.macos_x86_64_ninja:
+ extends: .macos_build
+
+ variables:
+ CMAKE_CONFIGURATION: macos_x86_64_ninja
+ CTEST_NO_WARNINGS_ALLOWED: 1
+
+.macos_arm64_ninja:
+ extends: .macos_build
+
+ variables:
+ CMAKE_CONFIGURATION: macos_arm64_ninja
+ CTEST_NO_WARNINGS_ALLOWED: 1
+
+.macos_x86_64_makefiles:
+ extends: .macos_build
+
+ variables:
+ CMAKE_CONFIGURATION: macos_x86_64_makefiles
+ CTEST_NO_WARNINGS_ALLOWED: 1
+ CMAKE_GENERATOR: "Unix Makefiles"
+
+.macos_package:
+ extends: .macos_build
+
+ variables:
+ CMAKE_CONFIGURATION: macos_package
+ CTEST_NO_WARNINGS_ALLOWED: 1
+ CMake_SKIP_INSTALL: 1
+
+.macos10.10_package:
+ extends: .macos_build
+
+ variables:
+ CMAKE_CONFIGURATION: macos10.10_package
+ CTEST_NO_WARNINGS_ALLOWED: 1
+ CMake_SKIP_INSTALL: 1
+
+### External testing
+
+.macos_x86_64_xcode:
+ extends: .macos
+
+ variables:
+ CMAKE_CONFIGURATION: macos_x86_64_xcode
+ CMAKE_GENERATOR: Xcode
+ CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+
+.macos_arm64_xcode:
+ extends: .macos
+
+ variables:
+ CMAKE_CONFIGURATION: macos_arm64_xcode
+ CMAKE_GENERATOR: Xcode
+ CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+
+## Tags
+
+.macos_x86_64_builder_tags:
+ tags:
+ - cmake # Since this is a bare runner, pin to a project.
+ - macos
+ - shell
+ - xcode-12.4
+ - nonconcurrent
+
+.macos_x86_64_builder_tags_package:
+ tags:
+ - cmake # Since this is a bare runner, pin to a project.
+ - macos
+ - shell
+ - xcode-12.4
+ - nonconcurrent
+ - finder
+
+.macos_x86_64_builder_ext_tags:
+ tags:
+ - cmake # Since this is a bare runner, pin to a project.
+ - macos
+ - shell
+ - xcode-12.4
+ - concurrent
+
+.macos_arm64_builder_tags:
+ tags:
+ - cmake # Since this is a bare runner, pin to a project.
+ - macos-arm64
+ - shell
+ - xcode-12.4
+ - nonconcurrent
+
+.macos_arm64_builder_ext_tags:
+ tags:
+ - cmake # Since this is a bare runner, pin to a project.
+ - macos-arm64
+ - shell
+ - xcode-12.4
+ - concurrent
+
+## macOS-specific scripts
+
+.before_script_macos: &before_script_macos
+ - .gitlab/ci/cmake.sh
+ - .gitlab/ci/ninja.sh
+ - export PATH=$PWD/.gitlab:$PWD/.gitlab/cmake/bin:$PATH
+ - cmake --version
+ - ninja --version
+ # Download Qt
+ - cmake -P .gitlab/ci/download_qt.cmake
+ - export CMAKE_PREFIX_PATH=$PWD/.gitlab/qt
+
+.cmake_build_macos:
+ stage: build
+
+ script:
+ - *before_script_macos
+ - .gitlab/ci/sccache.sh
+ # Allow the server to already be running.
+ - "sccache --start-server || :"
+ - sccache --show-stats
+ - ctest -VV -S .gitlab/ci/ctest_configure.cmake
+ - ctest -VV -S .gitlab/ci/ctest_build.cmake
+ - sccache --show-stats
+
+ interruptible: true
+
+.cmake_build_macos_package:
+ stage: build
+
+ script:
+ - *before_script_macos
+ - ctest -VV -S .gitlab/ci/ctest_configure.cmake
+ - ctest -VV -S .gitlab/ci/ctest_build.cmake
+ - cd build
+ - cpack -G TGZ
+ - cpack -G DragNDrop
+
+ interruptible: true
+
+.cmake_test_macos:
+ stage: test
+
+ script:
+ - *before_script_macos
+ - ctest --output-on-failure -V -S .gitlab/ci/ctest_test.cmake
+
+ interruptible: true
+
+.cmake_test_macos_external:
+ stage: test-ext
+
+ script:
+ - *before_script_macos
+ - .gitlab/ci/sccache.sh
+ # Allow the server to already be running.
+ - "sccache --start-server || :"
+ - sccache --show-stats
+ - "$LAUNCHER build/install/CMake.app/Contents/bin/ctest --output-on-failure -V -S .gitlab/ci/ctest_test_external.cmake"
+ - sccache --show-stats
+
+ interruptible: true
diff --git a/.gitlab/os-windows.yml b/.gitlab/os-windows.yml
new file mode 100644
index 0000000..cd2f168
--- /dev/null
+++ b/.gitlab/os-windows.yml
@@ -0,0 +1,125 @@
+# Windows-specific builder configurations and build commands
+
+## Base configurations
+
+.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
+
+.windows_build:
+ extends: .windows
+
+ variables:
+ # Note that shell runners only support runners with a single
+ # concurrency level. We can't use `$CI_CONCURRENCY_ID` because this may
+ # change between the build and test stages which CMake doesn't support.
+ # Even if we could, it could change if other runners on the machine
+ # could run at the same time, so we drop it.
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR\\cmake ci"
+
+.windows_ninja:
+ extends: .windows_build
+
+ variables:
+ # Debug and RelWithDebinfo build types use the `/Zi` which results in
+ # uncacheable compiations.
+ # https://github.com/mozilla/sccache/issues/242
+ CMAKE_BUILD_TYPE: Release
+ CTEST_NO_WARNINGS_ALLOWED: 1
+
+.windows_vs2019_x64_ninja:
+ extends: .windows_ninja
+
+ variables:
+ CMAKE_CONFIGURATION: windows_vs2019_x64_ninja
+ VCVARSALL: "${VS160COMNTOOLS}\\..\\..\\VC\\Auxiliary\\Build\\vcvarsall.bat"
+ VCVARSPLATFORM: "x64"
+ VCVARSVERSION: "14.28.29910"
+
+### External testing
+
+.windows_vs2019_x64:
+ extends: .windows
+
+ variables:
+ CMAKE_CONFIGURATION: windows_vs2019_x64
+ CMAKE_GENERATOR: "Visual Studio 16 2019"
+ CMAKE_GENERATOR_PLATFORM: "x64"
+ CMAKE_GENERATOR_TOOLSET: "v142,version=14.28.29910"
+ CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+
+## Tags
+
+.windows_builder_tags:
+ tags:
+ - cmake # Since this is a bare runner, pin to a project.
+ - windows
+ - shell
+ - vs2019
+ - msvc-19.28-16.9
+ - nonconcurrent
+
+.windows_builder_ext_tags:
+ tags:
+ - cmake # Since this is a bare runner, pin to a project.
+ - windows
+ - shell
+ - vs2019
+ - msvc-19.28-16.9
+ - concurrent
+
+## Windows-specific scripts
+
+.before_script_windows: &before_script_windows
+ - Invoke-Expression -Command .gitlab/ci/wix.ps1
+ - Invoke-Expression -Command .gitlab/ci/cmake.ps1
+ - Invoke-Expression -Command .gitlab/ci/ninja.ps1
+ - $pwdpath = $pwd.Path
+ - Set-Item -Force -Path "env:WIX" -Value "$pwdpath\.gitlab\wix"
+ - (& "$env:WIX\bin\light.exe" -help) | Select -First 1
+ - Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab;$pwdpath\.gitlab\cmake\bin;$env:PATH"
+ - cmake --version
+ - ninja --version
+ - cmake -P .gitlab/ci/download_qt.cmake
+ - Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\qt\bin;$env:PATH"
+ - cmake -P .gitlab/ci/download_python3.cmake
+ - Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\python3;$env:PATH"
+ - python --version
+
+.cmake_build_windows:
+ stage: build
+
+ script:
+ - *before_script_windows
+ - Set-Item -Force -Path "env:PATH" -Value "$env:PATH;$env:SCCACHE_PATH"
+ - Invoke-Expression -Command .gitlab/ci/vcvarsall.ps1
+ - sccache --start-server
+ - sccache --show-stats
+ - ctest -VV -S .gitlab/ci/ctest_configure.cmake
+ - ctest -VV -S .gitlab/ci/ctest_build.cmake
+ - sccache --show-stats
+ - sccache --stop-server
+
+ interruptible: true
+
+.cmake_test_windows:
+ stage: test
+
+ script:
+ - *before_script_windows
+ - Invoke-Expression -Command .gitlab/ci/vcvarsall.ps1
+ - ctest --output-on-failure -V -S .gitlab/ci/ctest_test.cmake
+
+ interruptible: true
+
+.cmake_test_windows_external:
+ stage: test-ext
+
+ script:
+ - build/install/bin/ctest --output-on-failure -V -S .gitlab/ci/ctest_test_external.cmake
+
+ interruptible: true
diff --git a/.gitlab/rules.yml b/.gitlab/rules.yml
new file mode 100644
index 0000000..5685463
--- /dev/null
+++ b/.gitlab/rules.yml
@@ -0,0 +1,63 @@
+# Rules for where jobs can run
+
+.run_manually:
+ rules:
+ - if: '$CMAKE_CI_PACKAGE == "true"'
+ when: never
+ - if: '$CMAKE_CI_NIGHTLY == "true"'
+ when: on_success
+ - if: '$CMAKE_CI_JOB_NIGHTLY == "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: '($CMAKE_CI_NO_MR == "true" && $CI_MERGE_REQUEST_ID)'
+ when: never
+ - if: '$CI_MERGE_REQUEST_ID'
+ when: manual
+ - if: '$CI_PROJECT_PATH == "cmake/cmake"'
+ when: delayed
+ start_in: 5 minutes
+ - when: never
+
+.run_automatically:
+ rules:
+ - if: '$CMAKE_CI_PACKAGE == "true"'
+ when: never
+ - if: '$CMAKE_CI_NIGHTLY == "true"'
+ when: on_success
+ - if: '$CMAKE_CI_JOB_NIGHTLY == "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: '($CMAKE_CI_NO_MR == "true" && $CI_MERGE_REQUEST_ID)'
+ when: never
+ - 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: '($CMAKE_CI_NIGHTLY == "true" && $CMAKE_CI_NIGHTLY_IGNORE_DEPS == "true")'
+ when: always
+ - if: '$CMAKE_CI_NIGHTLY == "true"'
+ when: on_success
+ - if: '$CMAKE_CI_JOB_NIGHTLY == "true"'
+ when: never
+ - if: '($CMAKE_CI_NO_MR == "true" && $CI_MERGE_REQUEST_ID)'
+ when: never
+ - if: '$CI_MERGE_REQUEST_ID'
+ when: on_success
+ - if: '$CI_PROJECT_PATH == "cmake/cmake"'
+ when: on_success
+ - when: never
+
+.run_only_for_package:
+ rules:
+ - if: '$CMAKE_CI_PACKAGE == "true"'
+ when: on_success
+ - when: never
diff --git a/.gitlab/upload.yml b/.gitlab/upload.yml
new file mode 100644
index 0000000..8b8daa1
--- /dev/null
+++ b/.gitlab/upload.yml
@@ -0,0 +1,18 @@
+# Steps for uploading artifacts
+
+.rsync_upload:
+ image: "fedora:32"
+ stage: upload
+ tags:
+ - docker
+ - linux
+ - build
+ environment:
+ name: rsync-upload
+
+ script:
+ - ls build/
+ - dnf install -y --setopt=install_weak_deps=False rsync openssh-clients
+ - chmod 400 $RSYNC_BINARY_KEY
+ - ssh-keygen -y -f $RSYNC_BINARY_KEY > $RSYNC_BINARY_KEY.pub
+ - rsync -tv --recursive -e "ssh -i $RSYNC_BINARY_KEY -o StrictHostKeyChecking=no -o LogLevel=ERROR" build/ kitware@cmake.org:$RSYNC_DESTINATION/
diff --git a/.hooks-config b/.hooks-config
new file mode 100644
index 0000000..064371c
--- /dev/null
+++ b/.hooks-config
@@ -0,0 +1,10 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# Loaded by .git/hooks/(pre-commit|commit-msg|prepare-commit-msg)
+# during git commit after local hooks have been installed.
+
+[hooks "chain"]
+ pre-commit = Utilities/Git/pre-commit
+ commit-msg = Utilities/Git/commit-msg
+ prepare-commit-msg = Utilities/Git/prepare-commit-msg
diff --git a/Auxiliary/CMakeLists.txt b/Auxiliary/CMakeLists.txt
new file mode 100644
index 0000000..c0aebef
--- /dev/null
+++ b/Auxiliary/CMakeLists.txt
@@ -0,0 +1,16 @@
+# Install Vim files to a typical system integration directory.
+# Packagers can set CMake_INSTALL_VIMFILES_DIR to control this.
+if(NOT CMake_INSTALL_VIMFILES_DIR)
+ set(CMake_INSTALL_VIMFILES_DIR ${CMAKE_XDGDATA_DIR}/vim/vimfiles)
+endif()
+install(DIRECTORY vim/indent vim/syntax DESTINATION ${CMake_INSTALL_VIMFILES_DIR})
+
+# Install Emacs files to a typical system integration directory.
+# Packagers can set CMake_INSTALL_EMACS_DIR to control this.
+if(NOT CMake_INSTALL_EMACS_DIR)
+ set(CMake_INSTALL_EMACS_DIR ${CMAKE_XDGDATA_DIR}/emacs/site-lisp)
+endif()
+install(FILES cmake-mode.el DESTINATION ${CMake_INSTALL_EMACS_DIR})
+
+install(FILES cmake.m4 DESTINATION ${CMAKE_XDGDATA_DIR}/aclocal)
+add_subdirectory (bash-completion)
diff --git a/Auxiliary/bash-completion/CMakeLists.txt b/Auxiliary/bash-completion/CMakeLists.txt
new file mode 100644
index 0000000..93b6ffd
--- /dev/null
+++ b/Auxiliary/bash-completion/CMakeLists.txt
@@ -0,0 +1,21 @@
+# We need to integrate into the system install, or this will silently fail to
+# accomplish anything at all, and packagers won't even know it exists. Use the
+# `<sharedir>/bash-completion/completions/` hierarchy by default, rooted in
+# CMake's XDGDATA_DIR definition of the sharedir. This works with installation
+# to `/usr` or `/usr/local` (or any prefix which bash-completion is configured
+# with) as well as a simple installation by a local user into their home
+# directory *if* the prefix is `$HOME/.local` since `.local/share/` is part of
+# the bash-completion search path too.
+# For more complex installations, packagers can set CMake_INSTALL_BASH_COMP_DIR
+# to another system location.
+
+if(NOT CMake_INSTALL_BASH_COMP_DIR)
+ if(CMAKE_BASH_COMP_DIR)
+ # Honor previous customization option.
+ set(CMake_INSTALL_BASH_COMP_DIR "${CMAKE_BASH_COMP_DIR}")
+ else()
+ # Default.
+ set(CMake_INSTALL_BASH_COMP_DIR ${CMAKE_XDGDATA_DIR}/bash-completion/completions)
+ endif()
+endif()
+install(FILES cmake cpack ctest DESTINATION ${CMake_INSTALL_BASH_COMP_DIR})
diff --git a/Auxiliary/bash-completion/cmake b/Auxiliary/bash-completion/cmake
new file mode 100644
index 0000000..d8d2c86
--- /dev/null
+++ b/Auxiliary/bash-completion/cmake
@@ -0,0 +1,166 @@
+# bash completion for cmake(1) -*- shell-script -*-
+
+_cmake()
+{
+ local cur prev words cword split=false
+ if type -t _init_completion >/dev/null; then
+ _init_completion -n = || return
+ else
+ # manual initialization for older bash completion versions
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+ fi
+
+ # Workaround for options like -DCMAKE_BUILD_TYPE=Release
+ local prefix=
+ if [[ $cur == -D* ]]; then
+ prev=-D
+ prefix=-D
+ cur="${cur#-D}"
+ elif [[ $cur == -U* ]]; then
+ prev=-U
+ prefix=-U
+ cur="${cur#-U}"
+ fi
+
+ case "$prev" in
+ -D)
+ if [[ $cur == *=* ]]; then
+ # complete values for variables
+ local var type value
+ var="${cur%%[:=]*}"
+ value="${cur#*=}"
+
+ if [[ $cur == CMAKE_BUILD_TYPE* ]]; then # most widely used case
+ COMPREPLY=( $( compgen -W 'Debug Release RelWithDebInfo
+ MinSizeRel' -- "$value" ) )
+ return
+ fi
+
+ if [[ $cur == *:* ]]; then
+ type="${cur#*:}"
+ type="${type%%=*}"
+ else # get type from cache if it's not set explicitly
+ type=$( cmake -LA -N 2>/dev/null | grep "$var:" \
+ 2>/dev/null )
+ type="${type#*:}"
+ type="${type%%=*}"
+ fi
+ case "$type" in
+ FILEPATH)
+ cur="$value"
+ _filedir
+ return
+ ;;
+ PATH)
+ cur="$value"
+ _filedir -d
+ return
+ ;;
+ BOOL)
+ COMPREPLY=( $( compgen -W 'ON OFF TRUE FALSE' -- \
+ "$value" ) )
+ return
+ ;;
+ STRING|INTERNAL)
+ # no completion available
+ return
+ ;;
+ esac
+ elif [[ $cur == *:* ]]; then
+ # complete types
+ local type="${cur#*:}"
+ COMPREPLY=( $( compgen -W 'FILEPATH PATH STRING BOOL INTERNAL'\
+ -S = -- "$type" ) )
+ compopt -o nospace
+ else
+ # complete variable names
+ COMPREPLY=( $( compgen -W '$( cmake -LA -N 2>/dev/null |
+ tail -n +2 | cut -f1 -d: )' -P "$prefix" -- "$cur" ) )
+ compopt -o nospace
+ fi
+ return
+ ;;
+ -U)
+ COMPREPLY=( $( compgen -W '$( cmake -LA -N | tail -n +2 |
+ cut -f1 -d: )' -P "$prefix" -- "$cur" ) )
+ return
+ ;;
+ esac
+
+ _split_longopt && split=true
+
+ case "$prev" in
+ -C|-P|--graphviz|--system-information)
+ _filedir
+ return
+ ;;
+ --build|--install|--open)
+ _filedir -d
+ return
+ ;;
+ -E)
+ COMPREPLY=( $( compgen -W "$( cmake -E help |& sed -n \
+ '/^ [^ ]/{s|^ \([^ ]\{1,\}\) .*$|\1|;p}' 2>/dev/null )" \
+ -- "$cur" ) )
+ return
+ ;;
+ -G)
+ local IFS=$'\n'
+ local quoted
+ printf -v quoted %q "$cur"
+ COMPREPLY=( $( compgen -W '$( cmake --help 2>/dev/null | sed -n \
+ -e "1,/^Generators/d" \
+ -e "/^ *[^ =]/{s|^ *\([^=]*[^ =]\).*$|\1|;s| |\\\\ |g;p}" \
+ 2>/dev/null )' -- "$quoted" ) )
+ return
+ ;;
+ --loglevel)
+ COMPREPLY=( $(compgen -W 'error warning notice status verbose debug trace' -- $cur ) )
+ ;;
+ --help-command)
+ COMPREPLY=( $( compgen -W '$( cmake --help-command-list 2>/dev/null|
+ grep -v "^cmake version " )' -- "$cur" ) )
+ return
+ ;;
+ --help-manual)
+ COMPREPLY=( $( compgen -W '$( cmake --help-manual-list 2>/dev/null|
+ grep -v "^cmake version " | sed -e "s/([0-9])$//" )' -- "$cur" ) )
+ return
+ ;;
+ --help-module)
+ COMPREPLY=( $( compgen -W '$( cmake --help-module-list 2>/dev/null|
+ grep -v "^cmake version " )' -- "$cur" ) )
+ return
+ ;;
+ --help-policy)
+ COMPREPLY=( $( compgen -W '$( cmake --help-policy-list 2>/dev/null |
+ grep -v "^cmake version " )' -- "$cur" ) )
+ return
+ ;;
+ --help-property)
+ COMPREPLY=( $( compgen -W '$( cmake --help-property-list \
+ 2>/dev/null | grep -v "^cmake version " )' -- "$cur" ) )
+ return
+ ;;
+ --help-variable)
+ COMPREPLY=( $( compgen -W '$( cmake --help-variable-list \
+ 2>/dev/null | grep -v "^cmake version " )' -- "$cur" ) )
+ return
+ ;;
+ esac
+
+ $split && return
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $(compgen -W '$( _parse_help "$1" --help )' -- ${cur}) )
+ [[ $COMPREPLY == *= ]] && compopt -o nospace
+ [[ $COMPREPLY ]] && return
+ fi
+
+ _filedir
+} &&
+complete -F _cmake cmake
+
+# ex: ts=4 sw=4 et filetype=sh
diff --git a/Auxiliary/bash-completion/cpack b/Auxiliary/bash-completion/cpack
new file mode 100644
index 0000000..cf5751f
--- /dev/null
+++ b/Auxiliary/bash-completion/cpack
@@ -0,0 +1,88 @@
+# bash completion for cpack(1) -*- shell-script -*-
+
+_cpack()
+{
+ local cur prev words cword
+ if type -t _init_completion >/dev/null; then
+ _init_completion -n = || return
+ else
+ # manual initialization for older bash completion versions
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+ fi
+
+ case "$prev" in
+ -G)
+ COMPREPLY=( $( compgen -W '$( cpack --help 2>/dev/null |
+ sed -e "1,/^Generators/d" -e "s|^ *\([^ ]*\) .*$|\1|" \
+ 2>/dev/null )' -- "$cur" ) )
+ return
+ ;;
+ -C)
+ COMPREPLY=( $( compgen -W 'Debug Release RelWithDebInfo
+ MinSizeRel' -- "$cur" ) )
+ return
+ ;;
+ -D)
+ [[ $cur == *=* ]] && return # no completion for values
+ COMPREPLY=( $( compgen -W '$( cpack --help-variable-list \
+ 2>/dev/null | grep -v "^cpack version " )' -S = -- "$cur" ) )
+ compopt -o nospace
+ return
+ ;;
+ -P|-R|--vendor)
+ # argument required but no completions available
+ return
+ ;;
+ -B)
+ _filedir -d
+ return
+ ;;
+ --config)
+ _filedir
+ return
+ ;;
+ --help-command)
+ COMPREPLY=( $( compgen -W '$( cpack --help-command-list 2>/dev/null|
+ grep -v "^cpack version " )' -- "$cur" ) )
+ return
+ ;;
+ --help-manual)
+ COMPREPLY=( $( compgen -W '$( cpack --help-manual-list 2>/dev/null|
+ grep -v "^cpack version " | sed -e "s/([0-9])$//" )' -- "$cur" ) )
+ return
+ ;;
+ --help-module)
+ COMPREPLY=( $( compgen -W '$( cpack --help-module-list 2>/dev/null|
+ grep -v "^cpack version " )' -- "$cur" ) )
+ return
+ ;;
+ --help-policy)
+ COMPREPLY=( $( compgen -W '$( cpack --help-policy-list 2>/dev/null |
+ grep -v "^cpack version " )' -- "$cur" ) )
+ return
+ ;;
+ --help-property)
+ COMPREPLY=( $( compgen -W '$( cpack --help-property-list \
+ 2>/dev/null | grep -v "^cpack version " )' -- "$cur" ) )
+ return
+ ;;
+ --help-variable)
+ COMPREPLY=( $( compgen -W '$( cpack --help-variable-list \
+ 2>/dev/null | grep -v "^cpack version " )' -- "$cur" ) )
+ return
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $(compgen -W '$( _parse_help "$1" --help )' -- ${cur}) )
+ [[ $COMPREPLY == *= ]] && compopt -o nospace
+ [[ $COMPREPLY ]] && return
+ fi
+
+ _filedir
+} &&
+complete -F _cpack cpack
+
+# ex: ts=4 sw=4 et filetype=sh
diff --git a/Auxiliary/bash-completion/ctest b/Auxiliary/bash-completion/ctest
new file mode 100644
index 0000000..49343bb
--- /dev/null
+++ b/Auxiliary/bash-completion/ctest
@@ -0,0 +1,118 @@
+# bash completion for ctest(1) -*- shell-script -*-
+
+_ctest()
+{
+ local cur prev words cword
+ if type -t _init_completion >/dev/null; then
+ _init_completion -n = || return
+ else
+ # manual initialization for older bash completion versions
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+ fi
+
+ case "$prev" in
+ -C|--build-config)
+ COMPREPLY=( $( compgen -W 'Debug Release RelWithDebInfo
+ MinSizeRel' -- "$cur" ) )
+ return
+ ;;
+ -j|--parallel)
+ COMPREPLY=( $( compgen -W "{1..$(( $(_ncpus)*2 ))}" -- "$cur" ) )
+ return
+ ;;
+ -O|--output-log|-A|--add-notes|--extra-submit)
+ _filedir
+ return
+ ;;
+ -L|--label-regex|-LE|--label-exclude)
+ COMPREPLY=( $( compgen -W '$( ctest --print-labels 2>/dev/null |
+ grep "^ " 2>/dev/null | cut -d" " -f 3 )' -- "$cur" ) )
+ return
+ ;;
+ --track|-I|--tests-information|--max-width|--timeout|--stop-time)
+ # argument required but no completions available
+ return
+ ;;
+ -R|--tests-regex|-E|--exclude-regex)
+ COMPREPLY=( $( compgen -W '$( ctest -N 2>/dev/null |
+ grep "^ Test" 2>/dev/null | cut -d: -f 2 )' -- "$cur" ) )
+ return
+ ;;
+ -D|--dashboard)
+ if [[ $cur == @(Experimental|Nightly|Continuous)* ]]; then
+ local model action
+ action=${cur#@(Experimental|Nightly|Continuous)}
+ model=${cur%"$action"}
+ COMPREPLY=( $( compgen -W 'Start Update Configure Build Test
+ Coverage Submit MemCheck' -P "$model" -- "$action" ) )
+ else
+ COMPREPLY=( $( compgen -W 'Experimental Nightly Continuous' \
+ -- "$cur" ) )
+ compopt -o nospace
+ fi
+ return
+ ;;
+ -M|--test-model)
+ COMPREPLY=( $( compgen -W 'Experimental Nightly Continuous' -- \
+ "$cur" ) )
+ return
+ ;;
+ -T|--test-action)
+ COMPREPLY=( $( compgen -W 'Start Update Configure Build Test
+ Coverage Submit MemCheck' -- "$cur" ) )
+ return
+ ;;
+ -S|--script|-SP|--script-new-process)
+ _filedir '@(cmake|ctest)'
+ return
+ ;;
+ --interactive-debug-mode)
+ COMPREPLY=( $( compgen -W '0 1' -- "$cur" ) )
+ return
+ ;;
+
+ --help-command)
+ COMPREPLY=( $( compgen -W '$( ctest --help-command-list 2>/dev/null|
+ grep -v "^ctest version " )' -- "$cur" ) )
+ return
+ ;;
+ --help-manual)
+ COMPREPLY=( $( compgen -W '$( ctest --help-manual-list 2>/dev/null|
+ grep -v "^ctest version " | sed -e "s/([0-9])$//" )' -- "$cur" ) )
+ return
+ ;;
+ --help-module)
+ COMPREPLY=( $( compgen -W '$( ctest --help-module-list 2>/dev/null|
+ grep -v "^ctest version " )' -- "$cur" ) )
+ return
+ ;;
+ --help-policy)
+ COMPREPLY=( $( compgen -W '$( ctest --help-policy-list 2>/dev/null |
+ grep -v "^ctest version " )' -- "$cur" ) )
+ return
+ ;;
+ --help-property)
+ COMPREPLY=( $( compgen -W '$( ctest --help-property-list \
+ 2>/dev/null | grep -v "^ctest version " )' -- "$cur" ) )
+ return
+ ;;
+ --help-variable)
+ COMPREPLY=( $( compgen -W '$( ctest --help-variable-list \
+ 2>/dev/null | grep -v "^ctest version " )' -- "$cur" ) )
+ return
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $(compgen -W '$( _parse_help "$1" --help )' -- ${cur}) )
+ [[ $COMPREPLY == *= ]] && compopt -o nospace
+ [[ $COMPREPLY ]] && return
+ fi
+
+ _filedir
+} &&
+complete -F _ctest ctest
+
+# ex: ts=4 sw=4 et filetype=sh
diff --git a/Auxiliary/cmake-mode.el b/Auxiliary/cmake-mode.el
new file mode 100644
index 0000000..ddc7b40
--- /dev/null
+++ b/Auxiliary/cmake-mode.el
@@ -0,0 +1,473 @@
+;;; cmake-mode.el --- major-mode for editing CMake sources
+
+;; Package-Requires: ((emacs "24.1"))
+
+; Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+; file Copyright.txt or https://cmake.org/licensing for details.
+
+;------------------------------------------------------------------------------
+
+;;; Commentary:
+
+;; Provides syntax highlighting and indentation for CMakeLists.txt and
+;; *.cmake source files.
+;;
+;; Add this code to your .emacs file to use the mode:
+;;
+;; (setq load-path (cons (expand-file-name "/dir/with/cmake-mode") load-path))
+;; (require 'cmake-mode)
+
+;------------------------------------------------------------------------------
+
+;;; Code:
+;;
+;; cmake executable variable used to run cmake --help-command
+;; on commands in cmake-mode
+;;
+;; cmake-command-help Written by James Bigler
+;;
+
+(require 'rst)
+(require 'rx)
+
+(defcustom cmake-mode-cmake-executable "cmake"
+ "*The name of the cmake executable.
+
+This can be either absolute or looked up in $PATH. You can also
+set the path with these commands:
+ (setenv \"PATH\" (concat (getenv \"PATH\") \";C:\\\\Program Files\\\\CMake 2.8\\\\bin\"))
+ (setenv \"PATH\" (concat (getenv \"PATH\") \":/usr/local/cmake/bin\"))"
+ :type 'file
+ :group 'cmake)
+
+;; Keywords
+(defconst cmake-keywords-block-open '("IF" "MACRO" "FOREACH" "ELSE" "ELSEIF" "WHILE" "FUNCTION"))
+(defconst cmake-keywords-block-close '("ENDIF" "ENDFOREACH" "ENDMACRO" "ELSE" "ELSEIF" "ENDWHILE" "ENDFUNCTION"))
+(defconst cmake-keywords
+ (let ((kwds (append cmake-keywords-block-open cmake-keywords-block-close nil)))
+ (delete-dups kwds)))
+
+;; Regular expressions used by line indentation function.
+;;
+(defconst cmake-regex-blank "^[ \t]*$")
+(defconst cmake-regex-comment "#.*")
+(defconst cmake-regex-paren-left "(")
+(defconst cmake-regex-paren-right ")")
+(defconst cmake-regex-argument-quoted
+ (rx ?\" (* (or (not (any ?\" ?\\)) (and ?\\ anything))) ?\"))
+(defconst cmake-regex-argument-unquoted
+ (rx (or (not (any space "()#\"\\\n")) (and ?\\ nonl))
+ (* (or (not (any space "()#\\\n")) (and ?\\ nonl)))))
+(defconst cmake-regex-token
+ (rx-to-string `(group (or (regexp ,cmake-regex-comment)
+ ?\( ?\)
+ (regexp ,cmake-regex-argument-unquoted)
+ (regexp ,cmake-regex-argument-quoted)))))
+(defconst cmake-regex-indented
+ (rx-to-string `(and bol (* (group (or (regexp ,cmake-regex-token) (any space ?\n)))))))
+(defconst cmake-regex-block-open
+ (rx-to-string `(and symbol-start (or ,@(append cmake-keywords-block-open
+ (mapcar 'downcase cmake-keywords-block-open))) symbol-end)))
+(defconst cmake-regex-block-close
+ (rx-to-string `(and symbol-start (or ,@(append cmake-keywords-block-close
+ (mapcar 'downcase cmake-keywords-block-close))) symbol-end)))
+(defconst cmake-regex-close
+ (rx-to-string `(and bol (* space) (regexp ,cmake-regex-block-close)
+ (* space) (regexp ,cmake-regex-paren-left))))
+
+;------------------------------------------------------------------------------
+
+;; Line indentation helper functions
+
+(defun cmake-line-starts-inside-string ()
+ "Determine whether the beginning of the current line is in a string."
+ (save-excursion
+ (beginning-of-line)
+ (let ((parse-end (point)))
+ (goto-char (point-min))
+ (nth 3 (parse-partial-sexp (point) parse-end))
+ )
+ )
+ )
+
+(defun cmake-find-last-indented-line ()
+ "Move to the beginning of the last line that has meaningful indentation."
+ (let ((point-start (point))
+ region)
+ (forward-line -1)
+ (setq region (buffer-substring-no-properties (point) point-start))
+ (while (and (not (bobp))
+ (or (looking-at cmake-regex-blank)
+ (cmake-line-starts-inside-string)
+ (not (and (string-match cmake-regex-indented region)
+ (= (length region) (match-end 0))))))
+ (forward-line -1)
+ (setq region (buffer-substring-no-properties (point) point-start))
+ )
+ )
+ )
+
+;------------------------------------------------------------------------------
+
+;;
+;; Indentation increment.
+;;
+(defcustom cmake-tab-width 2
+ "Number of columns to indent cmake blocks"
+ :type 'integer
+ :group 'cmake)
+
+;;
+;; Line indentation function.
+;;
+(defun cmake-indent ()
+ "Indent current line as CMake code."
+ (interactive)
+ (unless (cmake-line-starts-inside-string)
+ (if (bobp)
+ (cmake-indent-line-to 0)
+ (let (cur-indent)
+ (save-excursion
+ (beginning-of-line)
+ (let ((point-start (point))
+ (case-fold-search t) ;; case-insensitive
+ token)
+ ; Search back for the last indented line.
+ (cmake-find-last-indented-line)
+ ; Start with the indentation on this line.
+ (setq cur-indent (current-indentation))
+ ; Search forward counting tokens that adjust indentation.
+ (while (re-search-forward cmake-regex-token point-start t)
+ (setq token (match-string 0))
+ (when (or (string-match (concat "^" cmake-regex-paren-left "$") token)
+ (and (string-match cmake-regex-block-open token)
+ (looking-at (concat "[ \t]*" cmake-regex-paren-left))))
+ (setq cur-indent (+ cur-indent cmake-tab-width)))
+ (when (string-match (concat "^" cmake-regex-paren-right "$") token)
+ (setq cur-indent (- cur-indent cmake-tab-width)))
+ )
+ (goto-char point-start)
+ ;; If next token closes the block, decrease indentation
+ (when (looking-at cmake-regex-close)
+ (setq cur-indent (- cur-indent cmake-tab-width))
+ )
+ )
+ )
+ ; Indent this line by the amount selected.
+ (cmake-indent-line-to (max cur-indent 0))
+ )
+ )
+ )
+ )
+
+(defun cmake-point-in-indendation ()
+ (string-match "^[ \\t]*$" (buffer-substring (point-at-bol) (point))))
+
+(defun cmake-indent-line-to (column)
+ "Indent the current line to COLUMN.
+If point is within the existing indentation it is moved to the end of
+the indentation. Otherwise it retains the same position on the line"
+ (if (cmake-point-in-indendation)
+ (indent-line-to column)
+ (save-excursion (indent-line-to column))))
+
+;------------------------------------------------------------------------------
+
+;;
+;; Helper functions for buffer
+;;
+(defun cmake-unscreamify-buffer ()
+ "Convert all CMake commands to lowercase in buffer."
+ (interactive)
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "^\\([ \t]*\\)\\_<\\(\\(?:\\w\\|\\s_\\)+\\)\\_>\\([ \t]*(\\)" nil t)
+ (replace-match
+ (concat
+ (match-string 1)
+ (downcase (match-string 2))
+ (match-string 3))
+ t))
+ )
+ )
+
+
+;------------------------------------------------------------------------------
+
+;;
+;; Navigation / marking by function or macro
+;;
+
+(defconst cmake--regex-defun-start
+ (rx line-start
+ (zero-or-more space)
+ (or "function" "macro")
+ (zero-or-more space)
+ "("))
+
+(defconst cmake--regex-defun-end
+ (rx line-start
+ (zero-or-more space)
+ "end"
+ (or "function" "macro")
+ (zero-or-more space)
+ "(" (zero-or-more (not-char ")")) ")"))
+
+(defun cmake-beginning-of-defun ()
+ "Move backward to the beginning of a CMake function or macro.
+
+Return t unless search stops due to beginning of buffer."
+ (interactive)
+ (when (not (region-active-p))
+ (push-mark))
+ (let ((case-fold-search t))
+ (when (re-search-backward cmake--regex-defun-start nil 'move)
+ t)))
+
+(defun cmake-end-of-defun ()
+ "Move forward to the end of a CMake function or macro.
+
+Return t unless search stops due to end of buffer."
+ (interactive)
+ (when (not (region-active-p))
+ (push-mark))
+ (let ((case-fold-search t))
+ (when (re-search-forward cmake--regex-defun-end nil 'move)
+ (forward-line)
+ t)))
+
+(defun cmake-mark-defun ()
+ "Mark the current CMake function or macro.
+
+This puts the mark at the end, and point at the beginning."
+ (interactive)
+ (cmake-end-of-defun)
+ (push-mark nil :nomsg :activate)
+ (cmake-beginning-of-defun))
+
+
+;------------------------------------------------------------------------------
+
+;;
+;; Keyword highlighting regex-to-face map.
+;;
+(defconst cmake-font-lock-keywords
+ `((,(rx-to-string `(and symbol-start
+ (or ,@cmake-keywords
+ ,@(mapcar #'downcase cmake-keywords))
+ symbol-end))
+ . font-lock-keyword-face)
+ (,(rx symbol-start (group (+ (or word (syntax symbol)))) (* blank) ?\()
+ 1 font-lock-function-name-face)
+ (,(rx "${" (group (+(any alnum "-_+/."))) "}")
+ 1 font-lock-variable-name-face t)
+ )
+ "Highlighting expressions for CMake mode.")
+
+;------------------------------------------------------------------------------
+
+;; Syntax table for this mode.
+(defvar cmake-mode-syntax-table nil
+ "Syntax table for CMake mode.")
+(or cmake-mode-syntax-table
+ (setq cmake-mode-syntax-table
+ (let ((table (make-syntax-table)))
+ (modify-syntax-entry ?\( "()" table)
+ (modify-syntax-entry ?\) ")(" table)
+ (modify-syntax-entry ?# "<" table)
+ (modify-syntax-entry ?\n ">" table)
+ (modify-syntax-entry ?$ "'" table)
+ table)))
+
+;;
+;; User hook entry point.
+;;
+(defvar cmake-mode-hook nil)
+
+;;------------------------------------------------------------------------------
+;; Mode definition.
+;;
+;;;###autoload
+(define-derived-mode cmake-mode prog-mode "CMake"
+ "Major mode for editing CMake source files."
+
+ ; Setup font-lock mode.
+ (set (make-local-variable 'font-lock-defaults) '(cmake-font-lock-keywords))
+ ; Setup indentation function.
+ (set (make-local-variable 'indent-line-function) 'cmake-indent)
+ ; Setup comment syntax.
+ (set (make-local-variable 'comment-start) "#"))
+
+;; Default cmake-mode key bindings
+(define-key cmake-mode-map "\e\C-a" #'cmake-beginning-of-defun)
+(define-key cmake-mode-map "\e\C-e" #'cmake-end-of-defun)
+(define-key cmake-mode-map "\e\C-h" #'cmake-mark-defun)
+
+
+; Help mode starts here
+
+
+;;;###autoload
+(defun cmake-command-run (type &optional topic buffer)
+ "Runs the command cmake with the arguments specified. The
+optional argument topic will be appended to the argument list."
+ (interactive "s")
+ (let* ((bufname (if buffer buffer (concat "*CMake" type (if topic "-") topic "*")))
+ (buffer (if (get-buffer bufname) (get-buffer bufname) (generate-new-buffer bufname)))
+ (command (concat cmake-mode-cmake-executable " " type " " topic))
+ ;; Turn of resizing of mini-windows for shell-command.
+ (resize-mini-windows nil)
+ )
+ (shell-command command buffer)
+ (save-selected-window
+ (select-window (display-buffer buffer 'not-this-window))
+ (cmake-mode)
+ (read-only-mode 1)
+ (view-mode 1))
+ )
+ )
+
+;;;###autoload
+(defun cmake-command-run-help (type &optional topic buffer)
+ "`cmake-command-run' but rendered in `rst-mode'."
+ (interactive "s")
+ (let* ((bufname (if buffer buffer (concat "*CMake" type (if topic "-") topic "*")))
+ (buffer (if (get-buffer bufname) (get-buffer bufname) (generate-new-buffer bufname)))
+ (command (concat cmake-mode-cmake-executable " " type " " topic))
+ ;; Turn of resizing of mini-windows for shell-command.
+ (resize-mini-windows nil)
+ )
+ (shell-command command buffer)
+ (save-selected-window
+ (select-window (display-buffer buffer 'not-this-window))
+ (rst-mode)
+ (read-only-mode 1)
+ (view-mode 1))
+ )
+ )
+
+;;;###autoload
+(defun cmake-help-list-commands ()
+ "Prints out a list of the cmake commands."
+ (interactive)
+ (cmake-command-run-help "--help-command-list")
+ )
+
+(defvar cmake-commands '() "List of available topics for --help-command.")
+(defvar cmake-help-command-history nil "Command read history.")
+(defvar cmake-modules '() "List of available topics for --help-module.")
+(defvar cmake-help-module-history nil "Module read history.")
+(defvar cmake-variables '() "List of available topics for --help-variable.")
+(defvar cmake-help-variable-history nil "Variable read history.")
+(defvar cmake-properties '() "List of available topics for --help-property.")
+(defvar cmake-help-property-history nil "Property read history.")
+(defvar cmake-help-complete-history nil "Complete help read history.")
+(defvar cmake-string-to-list-symbol
+ '(("command" cmake-commands cmake-help-command-history)
+ ("module" cmake-modules cmake-help-module-history)
+ ("variable" cmake-variables cmake-help-variable-history)
+ ("property" cmake-properties cmake-help-property-history)
+ ))
+
+(defun cmake-get-list (listname)
+ "If the value of LISTVAR is nil, run cmake --help-LISTNAME-list
+and store the result as a list in LISTVAR."
+ (let ((listvar (car (cdr (assoc listname cmake-string-to-list-symbol)))))
+ (if (not (symbol-value listvar))
+ (let ((temp-buffer-name "*CMake Temporary*"))
+ (save-window-excursion
+ (cmake-command-run-help (concat "--help-" listname "-list") nil temp-buffer-name)
+ (with-current-buffer temp-buffer-name
+ ; FIXME: Ignore first line if it is "cmake version ..." from CMake < 3.0.
+ (set listvar (split-string (buffer-substring-no-properties (point-min) (point-max)) "\n" t)))))
+ (symbol-value listvar)
+ ))
+ )
+
+(require 'thingatpt)
+(defun cmake-symbol-at-point ()
+ (let ((symbol (symbol-at-point)))
+ (and (not (null symbol))
+ (symbol-name symbol))))
+
+(defun cmake-help-type (type)
+ (let* ((default-entry (cmake-symbol-at-point))
+ (history (car (cdr (cdr (assoc type cmake-string-to-list-symbol)))))
+ (input (completing-read
+ (format "CMake %s: " type) ; prompt
+ (cmake-get-list type) ; completions
+ nil ; predicate
+ t ; require-match
+ default-entry ; initial-input
+ history
+ )))
+ (if (string= input "")
+ (error "No argument given")
+ input))
+ )
+
+;;;###autoload
+(defun cmake-help-command ()
+ "Prints out the help message for the command the cursor is on."
+ (interactive)
+ (cmake-command-run-help "--help-command" (cmake-help-type "command") "*CMake Help*"))
+
+;;;###autoload
+(defun cmake-help-module ()
+ "Prints out the help message for the module the cursor is on."
+ (interactive)
+ (cmake-command-run-help "--help-module" (cmake-help-type "module") "*CMake Help*"))
+
+;;;###autoload
+(defun cmake-help-variable ()
+ "Prints out the help message for the variable the cursor is on."
+ (interactive)
+ (cmake-command-run-help "--help-variable" (cmake-help-type "variable") "*CMake Help*"))
+
+;;;###autoload
+(defun cmake-help-property ()
+ "Prints out the help message for the property the cursor is on."
+ (interactive)
+ (cmake-command-run-help "--help-property" (cmake-help-type "property") "*CMake Help*"))
+
+;;;###autoload
+(defun cmake-help ()
+ "Queries for any of the four available help topics and prints out the appropriate page."
+ (interactive)
+ (let* ((default-entry (cmake-symbol-at-point))
+ (command-list (cmake-get-list "command"))
+ (variable-list (cmake-get-list "variable"))
+ (module-list (cmake-get-list "module"))
+ (property-list (cmake-get-list "property"))
+ (all-words (append command-list variable-list module-list property-list))
+ (input (completing-read
+ "CMake command/module/variable/property: " ; prompt
+ all-words ; completions
+ nil ; predicate
+ t ; require-match
+ default-entry ; initial-input
+ 'cmake-help-complete-history
+ )))
+ (if (string= input "")
+ (error "No argument given")
+ (if (member input command-list)
+ (cmake-command-run-help "--help-command" input "*CMake Help*")
+ (if (member input variable-list)
+ (cmake-command-run-help "--help-variable" input "*CMake Help*")
+ (if (member input module-list)
+ (cmake-command-run-help "--help-module" input "*CMake Help*")
+ (if (member input property-list)
+ (cmake-command-run-help "--help-property" input "*CMake Help*")
+ (error "Not a know help topic.") ; this really should not happen
+ ))))))
+ )
+
+;;;###autoload
+(progn
+ (add-to-list 'auto-mode-alist '("CMakeLists\\.txt\\'" . cmake-mode))
+ (add-to-list 'auto-mode-alist '("\\.cmake\\'" . cmake-mode)))
+
+; This file provides cmake-mode.
+(provide 'cmake-mode)
+
+;;; cmake-mode.el ends here
diff --git a/Auxiliary/cmake.m4 b/Auxiliary/cmake.m4
new file mode 100644
index 0000000..a40c0ae
--- /dev/null
+++ b/Auxiliary/cmake.m4
@@ -0,0 +1,44 @@
+dnl Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+dnl file Copyright.txt or https://cmake.org/licensing for details.
+
+AC_DEFUN([CMAKE_FIND_BINARY],
+[AC_ARG_VAR([CMAKE_BINARY], [path to the cmake binary])dnl
+
+if test "x$ac_cv_env_CMAKE_BINARY_set" != "xset"; then
+ AC_PATH_TOOL([CMAKE_BINARY], [cmake])dnl
+fi
+])dnl
+
+# $1: package name
+# $2: language (e.g. C/CXX/Fortran)
+# $3: The compiler ID, defaults to GNU.
+# Possible values are: GNU, Intel, Clang, SunPro, HP, XL, VisualAge, PGI,
+# PathScale, Cray, SCO, MSVC
+# $4: optional extra arguments to cmake, e.g. "-DCMAKE_SIZEOF_VOID_P=8"
+# $5: optional path to cmake binary
+AC_DEFUN([CMAKE_FIND_PACKAGE], [
+AC_REQUIRE([CMAKE_FIND_BINARY])dnl
+
+AC_ARG_VAR([$1][_][$2][FLAGS], [$2 compiler flags for $1. This overrides the cmake output])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1. This overrides the cmake output])dnl
+
+failed=false
+AC_MSG_CHECKING([for $1])
+if test -z "${$1[]_$2[]FLAGS}"; then
+ $1[]_$2[]FLAGS=`$CMAKE_BINARY --find-package "-DNAME=$1" "-DCOMPILER_ID=m4_default([$3], [GNU])" "-DLANGUAGE=$2" -DMODE=COMPILE $4` || failed=true
+fi
+if test -z "${$1[]_LIBS}"; then
+ $1[]_LIBS=`$CMAKE_BINARY --find-package "-DNAME=$1" "-DCOMPILER_ID=m4_default([$3], [GNU])" "-DLANGUAGE=$2" -DMODE=LINK $4` || failed=true
+fi
+
+if $failed; then
+ unset $1[]_$2[]FLAGS
+ unset $1[]_LIBS
+
+ AC_MSG_RESULT([no])
+ $6
+else
+ AC_MSG_RESULT([yes])
+ $5
+fi[]dnl
+])
diff --git a/Auxiliary/vim/cmake.vim.in b/Auxiliary/vim/cmake.vim.in
new file mode 100644
index 0000000..3471b54
--- /dev/null
+++ b/Auxiliary/vim/cmake.vim.in
@@ -0,0 +1,130 @@
+" Vim syntax file
+" Program: CMake - Cross-Platform Makefile Generator
+" Version: @VERSION@
+" Language: CMake
+" Author: Andy Cedilnik <andy.cedilnik@kitware.com>,
+" Nicholas Hutchinson <nshutchinson@gmail.com>,
+" Patrick Boettcher <patrick.boettcher@posteo.de>
+" Maintainer: Dimitri Merejkowsky <d.merej@gmail.com>
+" Former Maintainer: Karthik Krishnan <karthik.krishnan@kitware.com>
+" Last Change: @DATE@
+"
+" Licence: The CMake license applies to this file. See
+" https://cmake.org/licensing
+" This implies that distribution with Vim is allowed
+
+if exists("b:current_syntax")
+ finish
+endif
+let s:keepcpo= &cpo
+set cpo&vim
+
+syn region cmakeBracketArgument start="\[\z(=\?\|=[0-9]*\)\[" end="\]\z1\]" contains=cmakeTodo,@Spell
+
+syn region cmakeComment start="#" end="$" contains=cmakeTodo,@Spell
+syn region cmakeBracketComment start="#\[\z(=\?\|=[0-9]*\)\[" end="\]\z1\]" contains=cmakeTodo,@Spell
+
+syn match cmakeEscaped /\(\\\\\|\\"\|\\n\|\\t\)/ contained
+syn region cmakeRegistry start="\[" end="]" contained oneline contains=cmakeTodo,cmakeEscaped
+
+syn region cmakeGeneratorExpression start="$<" end=">" contained oneline contains=cmakeVariableValue,cmakeProperty,cmakeGeneratorExpressions,cmakeTodo
+
+syn region cmakeString start='"' end='"' contained contains=cmakeTodo,cmakeVariableValue,cmakeEscaped
+
+syn region cmakeVariableValue start="${" end="}" contained oneline contains=cmakeVariable,cmakeTodo,cmakeVariableValue
+
+syn region cmakeEnvironment start="$ENV{" end="}" contained oneline contains=cmakeTodo
+
+syn region cmakeArguments start="(" end=")" contains=ALLBUT,cmakeGeneratorExpressions,cmakeCommand,cmakeCommandConditional,cmakeCommandRepeat,cmakeCommandDeprecated,cmakeCommandManuallyAdded,cmakeArguments,cmakeTodo
+
+syn case match
+
+syn keyword cmakeProperty contained
+@PROPERTIES@
+
+syn keyword cmakeVariable contained
+@VARIABLE_LIST@
+
+syn keyword cmakeModule contained
+@MODULES@
+
+@KEYWORDS@
+
+syn keyword cmakeGeneratorExpressions contained
+@GENERATOR_EXPRESSIONS@
+
+syn case ignore
+
+syn keyword cmakeCommand
+@COMMAND_LIST@
+ \ nextgroup=cmakeArguments
+
+syn keyword cmakeCommandConditional
+@CONDITIONALS@
+ \ nextgroup=cmakeArguments
+
+syn keyword cmakeCommandRepeat
+@LOOPS@
+ \ nextgroup=cmakeArguments
+
+syn keyword cmakeCommandDeprecated
+@DEPRECATED@
+ \ nextgroup=cmakeArguments
+
+syn case match
+
+syn keyword cmakeTodo
+ \ TODO FIXME XXX
+ \ contained
+
+hi def link cmakeBracketArgument String
+hi def link cmakeBracketComment Comment
+hi def link cmakeCommand Function
+hi def link cmakeCommandConditional Conditional
+hi def link cmakeCommandDeprecated WarningMsg
+hi def link cmakeCommandRepeat Repeat
+hi def link cmakeComment Comment
+hi def link cmakeEnvironment Special
+hi def link cmakeEscaped Special
+hi def link cmakeGeneratorExpression WarningMsg
+hi def link cmakeGeneratorExpressions Constant
+hi def link cmakeModule Include
+hi def link cmakeProperty Constant
+hi def link cmakeRegistry Underlined
+hi def link cmakeString String
+hi def link cmakeTodo TODO
+hi def link cmakeVariableValue Type
+hi def link cmakeVariable Identifier
+
+@KEYWORDS_HIGHLIGHT@
+
+" Manually added - difficult to parse out of documentation
+syn case ignore
+
+syn keyword cmakeCommandManuallyAdded
+ \ configure_package_config_file write_basic_package_version_file
+ \ nextgroup=cmakeArguments
+
+syn case match
+
+syn keyword cmakeKWconfigure_package_config_file contained
+ \ INSTALL_DESTINATION PATH_VARS NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO INSTALL_PREFIX
+
+syn keyword cmakeKWconfigure_package_config_file_constants contained
+ \ AnyNewerVersion SameMajorVersion SameMinorVersion ExactVersion
+
+syn keyword cmakeKWwrite_basic_package_version_file contained
+ \ VERSION COMPATIBILITY
+
+hi def link cmakeCommandManuallyAdded Function
+
+hi def link cmakeKWconfigure_package_config_file ModeMsg
+hi def link cmakeKWwrite_basic_package_version_file ModeMsg
+hi def link cmakeKWconfigure_package_config_file_constants Constant
+
+let b:current_syntax = "cmake"
+
+let &cpo = s:keepcpo
+unlet s:keepcpo
+
+" vim: set nowrap:
diff --git a/Auxiliary/vim/extract-upper-case.pl b/Auxiliary/vim/extract-upper-case.pl
new file mode 100755
index 0000000..1179199
--- /dev/null
+++ b/Auxiliary/vim/extract-upper-case.pl
@@ -0,0 +1,213 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use POSIX qw(strftime);
+use JSON;
+use File::Basename;
+
+#my $cmake = "/home/pboettch/devel/upstream/cmake/build/bin/cmake";
+my $cmake = "cmake";
+
+my @variables;
+my @commands;
+my @properties;
+my @modules;
+my %keywords; # command => keyword-list
+
+# find cmake/Modules/ | sed -rn 's/.*CMakeDetermine(.+)Compiler.cmake/\1/p' | sort
+my @languages = qw(ASM ASM_MASM ASM_NASM C CSharp CUDA CXX Fortran Java RC Swift);
+
+# unwanted upper-cases
+my %unwanted = map { $_ => 1 } qw(VS CXX IDE NOTFOUND NO_ DFOO DBAR NEW);
+ # cannot remove ALL - exists for add_custom_command
+
+# control-statements
+my %conditional = map { $_ => 1 } qw(if else elseif endif);
+my %loop = map { $_ => 1 } qw(foreach while endforeach endwhile);
+
+# decrecated
+my %deprecated = map { $_ => 1 } qw(build_name exec_program export_library_dependencies install_files install_programs install_targets link_libraries make_directory output_required_files remove subdir_depends subdirs use_mangled_mesa utility_source variable_requires write_file);
+
+# add some (popular) modules
+push @modules, "ExternalProject";
+
+# variables
+open(CMAKE, "$cmake --help-variable-list|") or die "could not run cmake";
+while (<CMAKE>) {
+ chomp;
+
+ if (/<(.*?)>/) {
+ if ($1 eq 'LANG') {
+ foreach my $lang (@languages) {
+ (my $V = $_) =~ s/<.*>/$lang/;
+ push @variables, $V;
+ }
+
+ next
+ } else {
+ next; # skip if containing < or >
+ }
+ }
+
+ push @variables, $_;
+}
+close(CMAKE);
+
+# transform all variables in a hash - to be able to use exists later on
+my %variables = map { $_ => 1 } @variables;
+
+# commands
+open(CMAKE, "$cmake --help-command-list|");
+while (my $cmd = <CMAKE>) {
+ chomp $cmd;
+ push @commands, $cmd;
+}
+close(CMAKE);
+
+# now generate a keyword-list per command
+foreach my $cmd (@commands) {
+ my @word = extract_upper("$cmake --help-command $cmd|");
+
+ next if scalar @word == 0;
+
+ $keywords{$cmd} = [ sort keys %{ { map { $_ => 1 } @word } } ];
+}
+
+# and now for modules
+foreach my $mod (@modules) {
+ my @word = extract_upper("$cmake --help-module $mod|");
+
+ next if scalar @word == 0;
+
+ $keywords{$mod} = [ sort keys %{ { map { $_ => 1 } @word } } ];
+}
+
+# and now for generator-expressions
+my @generator_expr = extract_upper("$cmake --help-manual cmake-generator-expressions |");
+
+# properties
+open(CMAKE, "$cmake --help-property-list|");
+while (<CMAKE>) {
+ next if /\</; # skip if containing < or >
+ chomp;
+ push @properties, $_;
+}
+close(CMAKE);
+
+# transform all properties in a hash
+my %properties = map { $_ => 1 } @properties;
+
+# read in manually written files
+my $modules_dir = dirname(__FILE__) . "/modules";
+opendir(DIR, $modules_dir) || die "can't opendir $modules_dir: $!";
+my @json_files = grep { /\.json$/ && -f "$modules_dir/$_" } readdir(DIR);
+closedir DIR;
+
+foreach my $file (@json_files) {
+ local $/; # Enable 'slurp' mode
+ open my $fh, "<", $modules_dir."/".$file;
+ my $json = <$fh>;
+ close $fh;
+
+ my $mod = decode_json($json);
+ foreach my $var (@{$mod->{variables}}) {
+ $variables{$var} = 1;
+ }
+
+ while (my ($cmd, $keywords) = each %{$mod->{commands}}) {
+ $keywords{$cmd} = [ sort @{$keywords} ];
+ }
+}
+
+# version
+open(CMAKE, "$cmake --version|");
+my $version = 'unknown';
+while (<CMAKE>) {
+ chomp;
+ $version = $_ if /cmake version/;
+}
+close(CMAKE);
+
+# generate cmake.vim
+open(IN, "<cmake.vim.in") or die "could not read cmake.vim.in";
+open(OUT, ">syntax/cmake.vim") or die "could not write to syntax/cmake.vim";
+
+my @keyword_hi;
+
+while(<IN>)
+{
+ if (m/\@([A-Z0-9_]+)\@/) { # match for @SOMETHING@
+ if ($1 eq "COMMAND_LIST") {
+ # do not include "special" commands in this list
+ my @tmp = grep { ! exists $conditional{$_} and
+ ! exists $loop{$_} and
+ ! exists $deprecated{$_} } @commands;
+ print_list(\*OUT, @tmp);
+ } elsif ($1 eq "VARIABLE_LIST") {
+ print_list(\*OUT, keys %variables);
+ } elsif ($1 eq "MODULES") {
+ print_list(\*OUT, @modules);
+ } elsif ($1 eq "GENERATOR_EXPRESSIONS") {
+ print_list(\*OUT, @generator_expr);
+ } elsif ($1 eq "CONDITIONALS") {
+ print_list(\*OUT, keys %conditional);
+ } elsif ($1 eq "LOOPS") {
+ print_list(\*OUT, keys %loop);
+ } elsif ($1 eq "DEPRECATED") {
+ print_list(\*OUT, keys %deprecated);
+ } elsif ($1 eq "PROPERTIES") {
+ print_list(\*OUT, keys %properties);
+ } elsif ($1 eq "KEYWORDS") {
+ foreach my $k (sort keys %keywords) {
+ print OUT "syn keyword cmakeKW$k contained\n";
+ print_list(\*OUT, @{$keywords{$k}});
+ print OUT "\n";
+ push @keyword_hi, "hi def link cmakeKW$k ModeMsg";
+ }
+ } elsif ($1 eq "KEYWORDS_HIGHLIGHT") {
+ print OUT join("\n", @keyword_hi), "\n";
+ } elsif ($1 eq "VERSION") {
+ $_ =~ s/\@VERSION\@/$version/;
+ print OUT $_;
+ } elsif ($1 eq "DATE") {
+ my $date = strftime "%Y %b %d", localtime;
+ $_ =~ s/\@DATE\@/$date/;
+ print OUT $_;
+ } else {
+ print "ERROR do not know how to replace $1\n";
+ }
+ } else {
+ print OUT $_;
+ }
+}
+close(IN);
+close(OUT);
+
+sub extract_upper
+{
+ my $input = shift;
+ my @word;
+
+ open(KW, $input);
+ while (<KW>) {
+ foreach my $w (m/\b([A-Z_]{2,})\b/g) {
+ next
+ if exists $variables{$w} or # skip if it is a variable
+ exists $unwanted{$w} or # skip if not wanted
+ grep(/$w/, @word); # skip if already in array
+
+ push @word, $w;
+ }
+ }
+ close(KW);
+
+ return @word;
+}
+
+sub print_list
+{
+ my $O = shift;
+ my $indent = " " x 12 . "\\ ";
+ print $O $indent, join("\n" . $indent, sort @_), "\n";
+}
diff --git a/Auxiliary/vim/indent/cmake.vim b/Auxiliary/vim/indent/cmake.vim
new file mode 100644
index 0000000..33e583d
--- /dev/null
+++ b/Auxiliary/vim/indent/cmake.vim
@@ -0,0 +1,89 @@
+" Vim indent file
+" Language: CMake (ft=cmake)
+" Author: Andy Cedilnik <andy.cedilnik@kitware.com>
+" Maintainer: Dimitri Merejkowsky <d.merej@gmail.com>
+" Former Maintainer: Karthik Krishnan <karthik.krishnan@kitware.com>
+" Last Change: 2017 Aug 30
+"
+" Licence: The CMake license applies to this file. See
+" https://cmake.org/licensing
+" This implies that distribution with Vim is allowed
+
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+let s:keepcpo= &cpo
+set cpo&vim
+
+setlocal indentexpr=CMakeGetIndent(v:lnum)
+setlocal indentkeys+==ENDIF(,ENDFOREACH(,ENDMACRO(,ELSE(,ELSEIF(,ENDWHILE(
+
+" Only define the function once.
+if exists("*CMakeGetIndent")
+ finish
+endif
+
+fun! CMakeGetIndent(lnum)
+ let this_line = getline(a:lnum)
+
+ " Find a non-blank line above the current line.
+ let lnum = a:lnum
+ let lnum = prevnonblank(lnum - 1)
+ let previous_line = getline(lnum)
+
+ " Hit the start of the file, use zero indent.
+ if lnum == 0
+ return 0
+ endif
+
+ let ind = indent(lnum)
+
+ let or = '\|'
+ " Regular expressions used by line indentation function.
+ let cmake_regex_comment = '#.*'
+ let cmake_regex_identifier = '[A-Za-z][A-Za-z0-9_]*'
+ let cmake_regex_quoted = '"\([^"\\]\|\\.\)*"'
+ let cmake_regex_arguments = '\(' . cmake_regex_quoted .
+ \ or . '\$(' . cmake_regex_identifier . ')' .
+ \ or . '[^()\\#"]' . or . '\\.' . '\)*'
+
+ let cmake_indent_comment_line = '^\s*' . cmake_regex_comment
+ let cmake_indent_blank_regex = '^\s*$'
+ let cmake_indent_open_regex = '^\s*' . cmake_regex_identifier .
+ \ '\s*(' . cmake_regex_arguments .
+ \ '\(' . cmake_regex_comment . '\)\?$'
+
+ let cmake_indent_close_regex = '^' . cmake_regex_arguments .
+ \ ')\s*' .
+ \ '\(' . cmake_regex_comment . '\)\?$'
+
+ let cmake_indent_begin_regex = '^\s*\(IF\|MACRO\|FOREACH\|ELSE\|ELSEIF\|WHILE\|FUNCTION\)\s*('
+ let cmake_indent_end_regex = '^\s*\(ENDIF\|ENDFOREACH\|ENDMACRO\|ELSE\|ELSEIF\|ENDWHILE\|ENDFUNCTION\)\s*('
+
+ " Add
+ if previous_line =~? cmake_indent_comment_line " Handle comments
+ let ind = ind
+ else
+ if previous_line =~? cmake_indent_begin_regex
+ let ind = ind + shiftwidth()
+ endif
+ if previous_line =~? cmake_indent_open_regex
+ let ind = ind + shiftwidth()
+ endif
+ endif
+
+ " Subtract
+ if this_line =~? cmake_indent_end_regex
+ let ind = ind - shiftwidth()
+ endif
+ if previous_line =~? cmake_indent_close_regex
+ let ind = ind - shiftwidth()
+ endif
+
+ return ind
+endfun
+
+let &cpo = s:keepcpo
+unlet s:keepcpo
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
new file mode 100644
index 0000000..067f80d
--- /dev/null
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -0,0 +1,4099 @@
+" Vim syntax file
+" Program: CMake - Cross-Platform Makefile Generator
+" Version: cmake version 3.19.20201028-gdab947f
+" Language: CMake
+" Author: Andy Cedilnik <andy.cedilnik@kitware.com>,
+" Nicholas Hutchinson <nshutchinson@gmail.com>,
+" Patrick Boettcher <patrick.boettcher@posteo.de>
+" Maintainer: Dimitri Merejkowsky <d.merej@gmail.com>
+" Former Maintainer: Karthik Krishnan <karthik.krishnan@kitware.com>
+" Last Change: 2020 oct. 28
+"
+" Licence: The CMake license applies to this file. See
+" https://cmake.org/licensing
+" This implies that distribution with Vim is allowed
+
+if exists("b:current_syntax")
+ finish
+endif
+let s:keepcpo= &cpo
+set cpo&vim
+
+syn region cmakeBracketArgument start="\[\z(=\?\|=[0-9]*\)\[" end="\]\z1\]" contains=cmakeTodo,@Spell
+
+syn region cmakeComment start="#" end="$" contains=cmakeTodo,@Spell
+syn region cmakeBracketComment start="#\[\z(=\?\|=[0-9]*\)\[" end="\]\z1\]" contains=cmakeTodo,@Spell
+
+syn match cmakeEscaped /\(\\\\\|\\"\|\\n\|\\t\)/ contained
+syn region cmakeRegistry start="\[" end="]" contained oneline contains=cmakeTodo,cmakeEscaped
+
+syn region cmakeGeneratorExpression start="$<" end=">" contained oneline contains=cmakeVariableValue,cmakeProperty,cmakeGeneratorExpressions,cmakeTodo
+
+syn region cmakeString start='"' end='"' contained contains=cmakeTodo,cmakeVariableValue,cmakeEscaped
+
+syn region cmakeVariableValue start="${" end="}" contained oneline contains=cmakeVariable,cmakeTodo,cmakeVariableValue
+
+syn region cmakeEnvironment start="$ENV{" end="}" contained oneline contains=cmakeTodo
+
+syn region cmakeArguments start="(" end=")" contains=ALLBUT,cmakeGeneratorExpressions,cmakeCommand,cmakeCommandConditional,cmakeCommandRepeat,cmakeCommandDeprecated,cmakeCommandManuallyAdded,cmakeArguments,cmakeTodo
+
+syn case match
+
+syn keyword cmakeProperty contained
+ \ ABSTRACT
+ \ ADDITIONAL_CLEAN_FILES
+ \ ADDITIONAL_MAKE_CLEAN_FILES
+ \ ADVANCED
+ \ AIX_EXPORT_ALL_SYMBOLS
+ \ ALIASED_TARGET
+ \ ALIAS_GLOBAL
+ \ ALLOW_DUPLICATE_CUSTOM_TARGETS
+ \ ANDROID_ANT_ADDITIONAL_OPTIONS
+ \ ANDROID_API
+ \ ANDROID_API_MIN
+ \ ANDROID_ARCH
+ \ ANDROID_ASSETS_DIRECTORIES
+ \ ANDROID_GUI
+ \ ANDROID_JAR_DEPENDENCIES
+ \ ANDROID_JAR_DIRECTORIES
+ \ ANDROID_JAVA_SOURCE_DIR
+ \ ANDROID_NATIVE_LIB_DEPENDENCIES
+ \ ANDROID_NATIVE_LIB_DIRECTORIES
+ \ ANDROID_PROCESS_MAX
+ \ ANDROID_PROGUARD
+ \ ANDROID_PROGUARD_CONFIG_PATH
+ \ ANDROID_SECURE_PROPS_PATH
+ \ ANDROID_SKIP_ANT_STEP
+ \ ANDROID_STL_TYPE
+ \ ARCHIVE_OUTPUT_DIRECTORY
+ \ ARCHIVE_OUTPUT_NAME
+ \ ATTACHED_FILES
+ \ ATTACHED_FILES_ON_FAIL
+ \ AUTOGEN_BUILD_DIR
+ \ AUTOGEN_ORIGIN_DEPENDS
+ \ AUTOGEN_PARALLEL
+ \ AUTOGEN_SOURCE_GROUP
+ \ AUTOGEN_TARGETS_FOLDER
+ \ AUTOGEN_TARGET_DEPENDS
+ \ AUTOMOC
+ \ AUTOMOC_COMPILER_PREDEFINES
+ \ AUTOMOC_DEPEND_FILTERS
+ \ AUTOMOC_EXECUTABLE
+ \ AUTOMOC_MACRO_NAMES
+ \ AUTOMOC_MOC_OPTIONS
+ \ AUTOMOC_PATH_PREFIX
+ \ AUTOMOC_SOURCE_GROUP
+ \ AUTOMOC_TARGETS_FOLDER
+ \ AUTORCC
+ \ AUTORCC_EXECUTABLE
+ \ AUTORCC_OPTIONS
+ \ AUTORCC_SOURCE_GROUP
+ \ AUTOUIC
+ \ AUTOUIC_EXECUTABLE
+ \ AUTOUIC_OPTIONS
+ \ AUTOUIC_SEARCH_PATHS
+ \ AUTOUIC_SOURCE_GROUP
+ \ BINARY_DIR
+ \ BUILDSYSTEM_TARGETS
+ \ BUILD_RPATH
+ \ BUILD_RPATH_USE_ORIGIN
+ \ BUILD_WITH_INSTALL_NAME_DIR
+ \ BUILD_WITH_INSTALL_RPATH
+ \ BUNDLE
+ \ BUNDLE_EXTENSION
+ \ CACHE_VARIABLES
+ \ CLEAN_NO_CUSTOM
+ \ CMAKE_CONFIGURE_DEPENDS
+ \ CMAKE_CUDA_KNOWN_FEATURES
+ \ CMAKE_CXX_KNOWN_FEATURES
+ \ CMAKE_C_KNOWN_FEATURES
+ \ CMAKE_ROLE
+ \ COMMON_LANGUAGE_RUNTIME
+ \ COMPATIBLE_INTERFACE_BOOL
+ \ COMPATIBLE_INTERFACE_NUMBER_MAX
+ \ COMPATIBLE_INTERFACE_NUMBER_MIN
+ \ COMPATIBLE_INTERFACE_STRING
+ \ COMPILE_DEFINITIONS
+ \ COMPILE_FEATURES
+ \ COMPILE_FLAGS
+ \ COMPILE_OPTIONS
+ \ COMPILE_PDB_NAME
+ \ COMPILE_PDB_OUTPUT_DIRECTORY
+ \ COST
+ \ CPACK_DESKTOP_SHORTCUTS
+ \ CPACK_NEVER_OVERWRITE
+ \ CPACK_PERMANENT
+ \ CPACK_STARTUP_SHORTCUTS
+ \ CPACK_START_MENU_SHORTCUTS
+ \ CPACK_WIX_ACL
+ \ CROSSCOMPILING_EMULATOR
+ \ CUDA_ARCHITECTURES
+ \ CUDA_EXTENSIONS
+ \ CUDA_PTX_COMPILATION
+ \ CUDA_RESOLVE_DEVICE_SYMBOLS
+ \ CUDA_RUNTIME_LIBRARY
+ \ CUDA_SEPARABLE_COMPILATION
+ \ CUDA_STANDARD
+ \ CUDA_STANDARD_REQUIRED
+ \ CXX_EXTENSIONS
+ \ CXX_STANDARD
+ \ CXX_STANDARD_REQUIRED
+ \ C_EXTENSIONS
+ \ C_STANDARD
+ \ C_STANDARD_REQUIRED
+ \ DEBUG_CONFIGURATIONS
+ \ DEBUG_POSTFIX
+ \ DEFINE_SYMBOL
+ \ DEFINITIONS
+ \ DEPENDS
+ \ DEPLOYMENT_ADDITIONAL_FILES
+ \ DEPLOYMENT_REMOTE_DIRECTORY
+ \ DEPRECATION
+ \ DISABLED
+ \ DISABLED_FEATURES
+ \ DISABLE_PRECOMPILE_HEADERS
+ \ DOTNET_TARGET_FRAMEWORK
+ \ DOTNET_TARGET_FRAMEWORK_VERSION
+ \ ECLIPSE_EXTRA_CPROJECT_CONTENTS
+ \ ECLIPSE_EXTRA_NATURES
+ \ ENABLED_FEATURES
+ \ ENABLED_LANGUAGES
+ \ ENABLE_EXPORTS
+ \ ENVIRONMENT
+ \ EXCLUDE_FROM_ALL
+ \ EXCLUDE_FROM_DEFAULT_BUILD
+ \ EXPORT_NAME
+ \ EXPORT_PROPERTIES
+ \ EXTERNAL_OBJECT
+ \ EchoString
+ \ FAIL_REGULAR_EXPRESSION
+ \ FIND_LIBRARY_USE_LIB32_PATHS
+ \ FIND_LIBRARY_USE_LIB64_PATHS
+ \ FIND_LIBRARY_USE_LIBX32_PATHS
+ \ FIND_LIBRARY_USE_OPENBSD_VERSIONING
+ \ FIXTURES_CLEANUP
+ \ FIXTURES_REQUIRED
+ \ FIXTURES_SETUP
+ \ FOLDER
+ \ FRAMEWORK
+ \ FRAMEWORK_VERSION
+ \ Fortran_FORMAT
+ \ Fortran_MODULE_DIRECTORY
+ \ Fortran_PREPROCESS
+ \ GENERATED
+ \ GENERATOR_FILE_NAME
+ \ GENERATOR_IS_MULTI_CONFIG
+ \ GHS_INTEGRITY_APP
+ \ GHS_NO_SOURCE_GROUP_FILE
+ \ GLOBAL_DEPENDS_DEBUG_MODE
+ \ GLOBAL_DEPENDS_NO_CYCLES
+ \ GNUtoMS
+ \ HAS_CXX
+ \ HEADER_FILE_ONLY
+ \ HELPSTRING
+ \ IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
+ \ IMPORTED
+ \ IMPORTED_COMMON_LANGUAGE_RUNTIME
+ \ IMPORTED_CONFIGURATIONS
+ \ IMPORTED_GLOBAL
+ \ IMPORTED_IMPLIB
+ \ IMPORTED_LIBNAME
+ \ IMPORTED_LINK_DEPENDENT_LIBRARIES
+ \ IMPORTED_LINK_INTERFACE_LANGUAGES
+ \ IMPORTED_LINK_INTERFACE_LIBRARIES
+ \ IMPORTED_LINK_INTERFACE_MULTIPLICITY
+ \ IMPORTED_LOCATION
+ \ IMPORTED_NO_SONAME
+ \ IMPORTED_OBJECTS
+ \ IMPORTED_SONAME
+ \ IMPORT_PREFIX
+ \ IMPORT_SUFFIX
+ \ INCLUDE_DIRECTORIES
+ \ INCLUDE_REGULAR_EXPRESSION
+ \ INSTALL_NAME_DIR
+ \ INSTALL_REMOVE_ENVIRONMENT_RPATH
+ \ INSTALL_RPATH
+ \ INSTALL_RPATH_USE_LINK_PATH
+ \ INTERFACE_AUTOUIC_OPTIONS
+ \ INTERFACE_COMPILE_DEFINITIONS
+ \ INTERFACE_COMPILE_FEATURES
+ \ INTERFACE_COMPILE_OPTIONS
+ \ INTERFACE_INCLUDE_DIRECTORIES
+ \ INTERFACE_LINK_DEPENDS
+ \ INTERFACE_LINK_DIRECTORIES
+ \ INTERFACE_LINK_LIBRARIES
+ \ INTERFACE_LINK_OPTIONS
+ \ INTERFACE_POSITION_INDEPENDENT_CODE
+ \ INTERFACE_PRECOMPILE_HEADERS
+ \ INTERFACE_SOURCES
+ \ INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
+ \ INTERPROCEDURAL_OPTIMIZATION
+ \ IN_TRY_COMPILE
+ \ IOS_INSTALL_COMBINED
+ \ ISPC_HEADER_DIRECTORY
+ \ ISPC_INSTRUCTION_SETS
+ \ JOB_POOLS
+ \ JOB_POOL_COMPILE
+ \ JOB_POOL_LINK
+ \ JOB_POOL_PRECOMPILE_HEADER
+ \ KEEP_EXTENSION
+ \ LABELS
+ \ LANGUAGE
+ \ LIBRARY_OUTPUT_DIRECTORY
+ \ LIBRARY_OUTPUT_NAME
+ \ LINKER_LANGUAGE
+ \ LINK_DEPENDS
+ \ LINK_DEPENDS_NO_SHARED
+ \ LINK_DIRECTORIES
+ \ LINK_FLAGS
+ \ LINK_INTERFACE_LIBRARIES
+ \ LINK_INTERFACE_MULTIPLICITY
+ \ LINK_LIBRARIES
+ \ LINK_OPTIONS
+ \ LINK_SEARCH_END_STATIC
+ \ LINK_SEARCH_START_STATIC
+ \ LINK_WHAT_YOU_USE
+ \ LISTFILE_STACK
+ \ LOCATION
+ \ MACHO_COMPATIBILITY_VERSION
+ \ MACHO_CURRENT_VERSION
+ \ MACOSX_BUNDLE
+ \ MACOSX_BUNDLE_INFO_PLIST
+ \ MACOSX_FRAMEWORK_INFO_PLIST
+ \ MACOSX_PACKAGE_LOCATION
+ \ MACOSX_RPATH
+ \ MACROS
+ \ MANUALLY_ADDED_DEPENDENCIES
+ \ MEASUREMENT
+ \ MODIFIED
+ \ MSVC_RUNTIME_LIBRARY
+ \ NAME
+ \ NO_SONAME
+ \ NO_SYSTEM_FROM_IMPORTED
+ \ OBJCXX_EXTENSIONS
+ \ OBJCXX_STANDARD
+ \ OBJCXX_STANDARD_REQUIRED
+ \ OBJC_EXTENSIONS
+ \ OBJC_STANDARD
+ \ OBJC_STANDARD_REQUIRED
+ \ OBJECT_DEPENDS
+ \ OBJECT_OUTPUTS
+ \ OPTIMIZE_DEPENDENCIES
+ \ OSX_ARCHITECTURES
+ \ OUTPUT_NAME
+ \ PACKAGES_FOUND
+ \ PACKAGES_NOT_FOUND
+ \ PARENT_DIRECTORY
+ \ PASS_REGULAR_EXPRESSION
+ \ PCH_INSTANTIATE_TEMPLATES
+ \ PCH_WARN_INVALID
+ \ PDB_NAME
+ \ PDB_OUTPUT_DIRECTORY
+ \ POSITION_INDEPENDENT_CODE
+ \ POST_INSTALL_SCRIPT
+ \ PRECOMPILE_HEADERS
+ \ PRECOMPILE_HEADERS_REUSE_FROM
+ \ PREDEFINED_TARGETS_FOLDER
+ \ PREFIX
+ \ PRE_INSTALL_SCRIPT
+ \ PRIVATE_HEADER
+ \ PROCESSORS
+ \ PROCESSOR_AFFINITY
+ \ PROJECT_LABEL
+ \ PUBLIC_HEADER
+ \ REPORT_UNDEFINED_PROPERTIES
+ \ REQUIRED_FILES
+ \ RESOURCE
+ \ RESOURCE_GROUPS
+ \ RESOURCE_LOCK
+ \ RULE_LAUNCH_COMPILE
+ \ RULE_LAUNCH_CUSTOM
+ \ RULE_LAUNCH_LINK
+ \ RULE_MESSAGES
+ \ RUNTIME_OUTPUT_DIRECTORY
+ \ RUNTIME_OUTPUT_NAME
+ \ RUN_SERIAL
+ \ SKIP_AUTOGEN
+ \ SKIP_AUTOMOC
+ \ SKIP_AUTORCC
+ \ SKIP_AUTOUIC
+ \ SKIP_BUILD_RPATH
+ \ SKIP_PRECOMPILE_HEADERS
+ \ SKIP_REGULAR_EXPRESSION
+ \ SKIP_RETURN_CODE
+ \ SKIP_UNITY_BUILD_INCLUSION
+ \ SOURCES
+ \ SOURCE_DIR
+ \ SOVERSION
+ \ STATIC_LIBRARY_FLAGS
+ \ STATIC_LIBRARY_OPTIONS
+ \ STRINGS
+ \ SUBDIRECTORIES
+ \ SUFFIX
+ \ SYMBOLIC
+ \ Swift_DEPENDENCIES_FILE
+ \ Swift_DIAGNOSTICS_FILE
+ \ Swift_LANGUAGE_VERSION
+ \ Swift_MODULE_DIRECTORY
+ \ Swift_MODULE_NAME
+ \ TARGET_ARCHIVES_MAY_BE_SHARED_LIBS
+ \ TARGET_MESSAGES
+ \ TARGET_SUPPORTS_SHARED_LIBS
+ \ TESTS
+ \ TEST_INCLUDE_FILE
+ \ TEST_INCLUDE_FILES
+ \ TIMEOUT
+ \ TIMEOUT_AFTER_MATCH
+ \ TYPE
+ \ UNITY_BUILD
+ \ UNITY_BUILD_BATCH_SIZE
+ \ UNITY_BUILD_CODE_AFTER_INCLUDE
+ \ UNITY_BUILD_CODE_BEFORE_INCLUDE
+ \ UNITY_BUILD_MODE
+ \ UNITY_GROUP
+ \ USE_FOLDERS
+ \ VALUE
+ \ VARIABLES
+ \ VERSION
+ \ VISIBILITY_INLINES_HIDDEN
+ \ VS_CONFIGURATION_TYPE
+ \ VS_COPY_TO_OUT_DIR
+ \ VS_DEBUGGER_COMMAND
+ \ VS_DEBUGGER_COMMAND_ARGUMENTS
+ \ VS_DEBUGGER_ENVIRONMENT
+ \ VS_DEBUGGER_WORKING_DIRECTORY
+ \ VS_DEPLOYMENT_CONTENT
+ \ VS_DEPLOYMENT_LOCATION
+ \ VS_DESKTOP_EXTENSIONS_VERSION
+ \ VS_DOTNET_DOCUMENTATION_FILE
+ \ VS_DOTNET_REFERENCES
+ \ VS_DOTNET_REFERENCES_COPY_LOCAL
+ \ VS_DOTNET_TARGET_FRAMEWORK_VERSION
+ \ VS_DPI_AWARE
+ \ VS_GLOBAL_KEYWORD
+ \ VS_GLOBAL_PROJECT_TYPES
+ \ VS_GLOBAL_ROOTNAMESPACE
+ \ VS_INCLUDE_IN_VSIX
+ \ VS_IOT_EXTENSIONS_VERSION
+ \ VS_IOT_STARTUP_TASK
+ \ VS_JUST_MY_CODE_DEBUGGING
+ \ VS_KEYWORD
+ \ VS_MOBILE_EXTENSIONS_VERSION
+ \ VS_NO_SOLUTION_DEPLOY
+ \ VS_PACKAGE_REFERENCES
+ \ VS_PLATFORM_TOOLSET
+ \ VS_PROJECT_IMPORT
+ \ VS_RESOURCE_GENERATOR
+ \ VS_SCC_AUXPATH
+ \ VS_SCC_LOCALPATH
+ \ VS_SCC_PROJECTNAME
+ \ VS_SCC_PROVIDER
+ \ VS_SDK_REFERENCES
+ \ VS_SETTINGS
+ \ VS_SHADER_DISABLE_OPTIMIZATIONS
+ \ VS_SHADER_ENABLE_DEBUG
+ \ VS_SHADER_ENTRYPOINT
+ \ VS_SHADER_FLAGS
+ \ VS_SHADER_MODEL
+ \ VS_SHADER_OBJECT_FILE_NAME
+ \ VS_SHADER_OUTPUT_HEADER_FILE
+ \ VS_SHADER_TYPE
+ \ VS_SHADER_VARIABLE_NAME
+ \ VS_SOLUTION_DEPLOY
+ \ VS_STARTUP_PROJECT
+ \ VS_TOOL_OVERRIDE
+ \ VS_USER_PROPS
+ \ VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION
+ \ VS_WINRT_COMPONENT
+ \ VS_WINRT_EXTENSIONS
+ \ VS_WINRT_REFERENCES
+ \ VS_XAML_TYPE
+ \ WILL_FAIL
+ \ WIN32_EXECUTABLE
+ \ WINDOWS_EXPORT_ALL_SYMBOLS
+ \ WORKING_DIRECTORY
+ \ WRAP_EXCLUDE
+ \ XCODE_EMIT_EFFECTIVE_PLATFORM_NAME
+ \ XCODE_EXPLICIT_FILE_TYPE
+ \ XCODE_FILE_ATTRIBUTES
+ \ XCODE_GENERATE_SCHEME
+ \ XCODE_LAST_KNOWN_FILE_TYPE
+ \ XCODE_LINK_BUILD_PHASE_MODE
+ \ XCODE_PRODUCT_TYPE
+ \ XCODE_SCHEME_ADDRESS_SANITIZER
+ \ XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN
+ \ XCODE_SCHEME_ARGUMENTS
+ \ XCODE_SCHEME_DEBUG_AS_ROOT
+ \ XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING
+ \ XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
+ \ XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
+ \ XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
+ \ XCODE_SCHEME_ENVIRONMENT
+ \ XCODE_SCHEME_EXECUTABLE
+ \ XCODE_SCHEME_GUARD_MALLOC
+ \ XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP
+ \ XCODE_SCHEME_MALLOC_GUARD_EDGES
+ \ XCODE_SCHEME_MALLOC_SCRIBBLE
+ \ XCODE_SCHEME_MALLOC_STACK
+ \ XCODE_SCHEME_THREAD_SANITIZER
+ \ XCODE_SCHEME_THREAD_SANITIZER_STOP
+ \ XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER
+ \ XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP
+ \ XCODE_SCHEME_WORKING_DIRECTORY
+ \ XCODE_SCHEME_ZOMBIE_OBJECTS
+ \ XCTEST
+
+syn keyword cmakeVariable contained
+ \ ANDROID
+ \ APPLE
+ \ BORLAND
+ \ BUILD_SHARED_LIBS
+ \ CACHE
+ \ CMAKE_ABSOLUTE_DESTINATION_FILES
+ \ CMAKE_AIX_EXPORT_ALL_SYMBOLS
+ \ CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS
+ \ CMAKE_ANDROID_API
+ \ CMAKE_ANDROID_API_MIN
+ \ CMAKE_ANDROID_ARCH
+ \ CMAKE_ANDROID_ARCH_ABI
+ \ CMAKE_ANDROID_ARM_MODE
+ \ CMAKE_ANDROID_ARM_NEON
+ \ CMAKE_ANDROID_ASSETS_DIRECTORIES
+ \ CMAKE_ANDROID_GUI
+ \ CMAKE_ANDROID_JAR_DEPENDENCIES
+ \ CMAKE_ANDROID_JAR_DIRECTORIES
+ \ CMAKE_ANDROID_JAVA_SOURCE_DIR
+ \ CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES
+ \ CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES
+ \ CMAKE_ANDROID_NDK
+ \ CMAKE_ANDROID_NDK_DEPRECATED_HEADERS
+ \ CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG
+ \ CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION
+ \ CMAKE_ANDROID_PROCESS_MAX
+ \ CMAKE_ANDROID_PROGUARD
+ \ CMAKE_ANDROID_PROGUARD_CONFIG_PATH
+ \ CMAKE_ANDROID_SECURE_PROPS_PATH
+ \ CMAKE_ANDROID_SKIP_ANT_STEP
+ \ CMAKE_ANDROID_STANDALONE_TOOLCHAIN
+ \ CMAKE_ANDROID_STL_TYPE
+ \ CMAKE_APPBUNDLE_PATH
+ \ CMAKE_AR
+ \ CMAKE_ARCHIVE_OUTPUT_DIRECTORY
+ \ CMAKE_ARGC
+ \ CMAKE_ARGV0
+ \ CMAKE_ASM
+ \ CMAKE_ASM_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_ASM_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_ASM_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_ASM_ARCHIVE_APPEND
+ \ CMAKE_ASM_ARCHIVE_CREATE
+ \ CMAKE_ASM_ARCHIVE_FINISH
+ \ CMAKE_ASM_CLANG_TIDY
+ \ CMAKE_ASM_COMPILER
+ \ CMAKE_ASM_COMPILER_ABI
+ \ CMAKE_ASM_COMPILER_AR
+ \ CMAKE_ASM_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_ASM_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_ASM_COMPILER_ID
+ \ CMAKE_ASM_COMPILER_LAUNCHER
+ \ CMAKE_ASM_COMPILER_LOADED
+ \ CMAKE_ASM_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_ASM_COMPILER_RANLIB
+ \ CMAKE_ASM_COMPILER_TARGET
+ \ CMAKE_ASM_COMPILER_VERSION
+ \ CMAKE_ASM_COMPILER_VERSION_INTERNAL
+ \ CMAKE_ASM_COMPILE_OBJECT
+ \ CMAKE_ASM_CPPCHECK
+ \ CMAKE_ASM_CPPLINT
+ \ CMAKE_ASM_CREATE_SHARED_LIBRARY
+ \ CMAKE_ASM_CREATE_SHARED_MODULE
+ \ CMAKE_ASM_CREATE_STATIC_LIBRARY
+ \ CMAKE_ASM_FLAGS
+ \ CMAKE_ASM_FLAGS_DEBUG
+ \ CMAKE_ASM_FLAGS_DEBUG_INIT
+ \ CMAKE_ASM_FLAGS_INIT
+ \ CMAKE_ASM_FLAGS_MINSIZEREL
+ \ CMAKE_ASM_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_ASM_FLAGS_RELEASE
+ \ CMAKE_ASM_FLAGS_RELEASE_INIT
+ \ CMAKE_ASM_FLAGS_RELWITHDEBINFO
+ \ CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_ASM_IGNORE_EXTENSIONS
+ \ CMAKE_ASM_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_ASM_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_ASM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_ASM_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_ASM_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_ASM_INIT
+ \ CMAKE_ASM_LIBRARY_ARCHITECTURE
+ \ CMAKE_ASM_LINKER_PREFERENCE
+ \ CMAKE_ASM_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_ASM_LINKER_WRAPPER_FLAG
+ \ CMAKE_ASM_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_ASM_LINK_EXECUTABLE
+ \ CMAKE_ASM_LINK_LIBRARY_FILE_FLAG
+ \ CMAKE_ASM_LINK_LIBRARY_FLAG
+ \ CMAKE_ASM_LINK_LIBRARY_SUFFIX
+ \ CMAKE_ASM_MASM
+ \ CMAKE_ASM_MASM_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_ASM_MASM_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_ASM_MASM_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_ASM_MASM_ARCHIVE_APPEND
+ \ CMAKE_ASM_MASM_ARCHIVE_CREATE
+ \ CMAKE_ASM_MASM_ARCHIVE_FINISH
+ \ CMAKE_ASM_MASM_CLANG_TIDY
+ \ CMAKE_ASM_MASM_COMPILER
+ \ CMAKE_ASM_MASM_COMPILER_ABI
+ \ CMAKE_ASM_MASM_COMPILER_AR
+ \ CMAKE_ASM_MASM_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_ASM_MASM_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_ASM_MASM_COMPILER_ID
+ \ CMAKE_ASM_MASM_COMPILER_LAUNCHER
+ \ CMAKE_ASM_MASM_COMPILER_LOADED
+ \ CMAKE_ASM_MASM_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_ASM_MASM_COMPILER_RANLIB
+ \ CMAKE_ASM_MASM_COMPILER_TARGET
+ \ CMAKE_ASM_MASM_COMPILER_VERSION
+ \ CMAKE_ASM_MASM_COMPILER_VERSION_INTERNAL
+ \ CMAKE_ASM_MASM_COMPILE_OBJECT
+ \ CMAKE_ASM_MASM_CPPCHECK
+ \ CMAKE_ASM_MASM_CPPLINT
+ \ CMAKE_ASM_MASM_CREATE_SHARED_LIBRARY
+ \ CMAKE_ASM_MASM_CREATE_SHARED_MODULE
+ \ CMAKE_ASM_MASM_CREATE_STATIC_LIBRARY
+ \ CMAKE_ASM_MASM_FLAGS
+ \ CMAKE_ASM_MASM_FLAGS_DEBUG
+ \ CMAKE_ASM_MASM_FLAGS_DEBUG_INIT
+ \ CMAKE_ASM_MASM_FLAGS_INIT
+ \ CMAKE_ASM_MASM_FLAGS_MINSIZEREL
+ \ CMAKE_ASM_MASM_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_ASM_MASM_FLAGS_RELEASE
+ \ CMAKE_ASM_MASM_FLAGS_RELEASE_INIT
+ \ CMAKE_ASM_MASM_FLAGS_RELWITHDEBINFO
+ \ CMAKE_ASM_MASM_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_ASM_MASM_IGNORE_EXTENSIONS
+ \ CMAKE_ASM_MASM_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_ASM_MASM_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_ASM_MASM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_ASM_MASM_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_ASM_MASM_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_ASM_MASM_INIT
+ \ CMAKE_ASM_MASM_LIBRARY_ARCHITECTURE
+ \ CMAKE_ASM_MASM_LINKER_PREFERENCE
+ \ CMAKE_ASM_MASM_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_ASM_MASM_LINKER_WRAPPER_FLAG
+ \ CMAKE_ASM_MASM_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_ASM_MASM_LINK_EXECUTABLE
+ \ CMAKE_ASM_MASM_LINK_LIBRARY_FILE_FLAG
+ \ CMAKE_ASM_MASM_LINK_LIBRARY_FLAG
+ \ CMAKE_ASM_MASM_LINK_LIBRARY_SUFFIX
+ \ CMAKE_ASM_MASM_OUTPUT_EXTENSION
+ \ CMAKE_ASM_MASM_PLATFORM_ID
+ \ CMAKE_ASM_MASM_SIMULATE_ID
+ \ CMAKE_ASM_MASM_SIMULATE_VERSION
+ \ CMAKE_ASM_MASM_SIZEOF_DATA_PTR
+ \ CMAKE_ASM_MASM_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_ASM_MASM_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_ASM_MASM_STANDARD_LIBRARIES
+ \ CMAKE_ASM_MASM_VISIBILITY_PRESET
+ \ CMAKE_ASM_NASM
+ \ CMAKE_ASM_NASM_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_ASM_NASM_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_ASM_NASM_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_ASM_NASM_ARCHIVE_APPEND
+ \ CMAKE_ASM_NASM_ARCHIVE_CREATE
+ \ CMAKE_ASM_NASM_ARCHIVE_FINISH
+ \ CMAKE_ASM_NASM_CLANG_TIDY
+ \ CMAKE_ASM_NASM_COMPILER
+ \ CMAKE_ASM_NASM_COMPILER_ABI
+ \ CMAKE_ASM_NASM_COMPILER_AR
+ \ CMAKE_ASM_NASM_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_ASM_NASM_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_ASM_NASM_COMPILER_ID
+ \ CMAKE_ASM_NASM_COMPILER_LAUNCHER
+ \ CMAKE_ASM_NASM_COMPILER_LOADED
+ \ CMAKE_ASM_NASM_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_ASM_NASM_COMPILER_RANLIB
+ \ CMAKE_ASM_NASM_COMPILER_TARGET
+ \ CMAKE_ASM_NASM_COMPILER_VERSION
+ \ CMAKE_ASM_NASM_COMPILER_VERSION_INTERNAL
+ \ CMAKE_ASM_NASM_COMPILE_OBJECT
+ \ CMAKE_ASM_NASM_CPPCHECK
+ \ CMAKE_ASM_NASM_CPPLINT
+ \ CMAKE_ASM_NASM_CREATE_SHARED_LIBRARY
+ \ CMAKE_ASM_NASM_CREATE_SHARED_MODULE
+ \ CMAKE_ASM_NASM_CREATE_STATIC_LIBRARY
+ \ CMAKE_ASM_NASM_FLAGS
+ \ CMAKE_ASM_NASM_FLAGS_DEBUG
+ \ CMAKE_ASM_NASM_FLAGS_DEBUG_INIT
+ \ CMAKE_ASM_NASM_FLAGS_INIT
+ \ CMAKE_ASM_NASM_FLAGS_MINSIZEREL
+ \ CMAKE_ASM_NASM_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_ASM_NASM_FLAGS_RELEASE
+ \ CMAKE_ASM_NASM_FLAGS_RELEASE_INIT
+ \ CMAKE_ASM_NASM_FLAGS_RELWITHDEBINFO
+ \ CMAKE_ASM_NASM_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_ASM_NASM_IGNORE_EXTENSIONS
+ \ CMAKE_ASM_NASM_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_ASM_NASM_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_ASM_NASM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_ASM_NASM_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_ASM_NASM_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_ASM_NASM_INIT
+ \ CMAKE_ASM_NASM_LIBRARY_ARCHITECTURE
+ \ CMAKE_ASM_NASM_LINKER_PREFERENCE
+ \ CMAKE_ASM_NASM_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_ASM_NASM_LINKER_WRAPPER_FLAG
+ \ CMAKE_ASM_NASM_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_ASM_NASM_LINK_EXECUTABLE
+ \ CMAKE_ASM_NASM_LINK_LIBRARY_FILE_FLAG
+ \ CMAKE_ASM_NASM_LINK_LIBRARY_FLAG
+ \ CMAKE_ASM_NASM_LINK_LIBRARY_SUFFIX
+ \ CMAKE_ASM_NASM_OUTPUT_EXTENSION
+ \ CMAKE_ASM_NASM_PLATFORM_ID
+ \ CMAKE_ASM_NASM_SIMULATE_ID
+ \ CMAKE_ASM_NASM_SIMULATE_VERSION
+ \ CMAKE_ASM_NASM_SIZEOF_DATA_PTR
+ \ CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_ASM_NASM_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_ASM_NASM_STANDARD_LIBRARIES
+ \ CMAKE_ASM_NASM_VISIBILITY_PRESET
+ \ CMAKE_ASM_OUTPUT_EXTENSION
+ \ CMAKE_ASM_PLATFORM_ID
+ \ CMAKE_ASM_SIMULATE_ID
+ \ CMAKE_ASM_SIMULATE_VERSION
+ \ CMAKE_ASM_SIZEOF_DATA_PTR
+ \ CMAKE_ASM_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_ASM_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_ASM_STANDARD_LIBRARIES
+ \ CMAKE_ASM_VISIBILITY_PRESET
+ \ CMAKE_AUTOGEN_ORIGIN_DEPENDS
+ \ CMAKE_AUTOGEN_PARALLEL
+ \ CMAKE_AUTOGEN_VERBOSE
+ \ CMAKE_AUTOMOC
+ \ CMAKE_AUTOMOC_COMPILER_PREDEFINES
+ \ CMAKE_AUTOMOC_DEPEND_FILTERS
+ \ CMAKE_AUTOMOC_MACRO_NAMES
+ \ CMAKE_AUTOMOC_MOC_OPTIONS
+ \ CMAKE_AUTOMOC_PATH_PREFIX
+ \ CMAKE_AUTOMOC_RELAXED_MODE
+ \ CMAKE_AUTORCC
+ \ CMAKE_AUTORCC_OPTIONS
+ \ CMAKE_AUTOUIC
+ \ CMAKE_AUTOUIC_OPTIONS
+ \ CMAKE_AUTOUIC_SEARCH_PATHS
+ \ CMAKE_BACKWARDS_COMPATIBILITY
+ \ CMAKE_BINARY_DIR
+ \ CMAKE_BUILD_RPATH
+ \ CMAKE_BUILD_RPATH_USE_ORIGIN
+ \ CMAKE_BUILD_TOOL
+ \ CMAKE_BUILD_TYPE
+ \ CMAKE_BUILD_WITH_INSTALL_NAME_DIR
+ \ CMAKE_BUILD_WITH_INSTALL_RPATH
+ \ CMAKE_C
+ \ CMAKE_CACHEFILE_DIR
+ \ CMAKE_CACHE_MAJOR_VERSION
+ \ CMAKE_CACHE_MINOR_VERSION
+ \ CMAKE_CACHE_PATCH_VERSION
+ \ CMAKE_CFG_INTDIR
+ \ CMAKE_CLANG_VFS_OVERLAY
+ \ CMAKE_CL_64
+ \ CMAKE_CODEBLOCKS_COMPILER_ID
+ \ CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES
+ \ CMAKE_CODELITE_USE_TARGETS
+ \ CMAKE_COLOR_MAKEFILE
+ \ CMAKE_COMMAND
+ \ CMAKE_COMPILER_2005
+ \ CMAKE_COMPILER_IS_GNUCC
+ \ CMAKE_COMPILER_IS_GNUCXX
+ \ CMAKE_COMPILER_IS_GNUG77
+ \ CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY
+ \ CMAKE_CONFIGURATION_TYPES
+ \ CMAKE_CPACK_COMMAND
+ \ CMAKE_CROSSCOMPILING
+ \ CMAKE_CROSSCOMPILING_EMULATOR
+ \ CMAKE_CROSS_CONFIGS
+ \ CMAKE_CSharp
+ \ CMAKE_CSharp_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_CSharp_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_CSharp_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_CSharp_ARCHIVE_APPEND
+ \ CMAKE_CSharp_ARCHIVE_CREATE
+ \ CMAKE_CSharp_ARCHIVE_FINISH
+ \ CMAKE_CSharp_CLANG_TIDY
+ \ CMAKE_CSharp_COMPILER
+ \ CMAKE_CSharp_COMPILER_ABI
+ \ CMAKE_CSharp_COMPILER_AR
+ \ CMAKE_CSharp_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_CSharp_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_CSharp_COMPILER_ID
+ \ CMAKE_CSharp_COMPILER_LAUNCHER
+ \ CMAKE_CSharp_COMPILER_LOADED
+ \ CMAKE_CSharp_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_CSharp_COMPILER_RANLIB
+ \ CMAKE_CSharp_COMPILER_TARGET
+ \ CMAKE_CSharp_COMPILER_VERSION
+ \ CMAKE_CSharp_COMPILER_VERSION_INTERNAL
+ \ CMAKE_CSharp_COMPILE_OBJECT
+ \ CMAKE_CSharp_CPPCHECK
+ \ CMAKE_CSharp_CPPLINT
+ \ CMAKE_CSharp_CREATE_SHARED_LIBRARY
+ \ CMAKE_CSharp_CREATE_SHARED_MODULE
+ \ CMAKE_CSharp_CREATE_STATIC_LIBRARY
+ \ CMAKE_CSharp_FLAGS
+ \ CMAKE_CSharp_FLAGS_DEBUG
+ \ CMAKE_CSharp_FLAGS_DEBUG_INIT
+ \ CMAKE_CSharp_FLAGS_INIT
+ \ CMAKE_CSharp_FLAGS_MINSIZEREL
+ \ CMAKE_CSharp_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_CSharp_FLAGS_RELEASE
+ \ CMAKE_CSharp_FLAGS_RELEASE_INIT
+ \ CMAKE_CSharp_FLAGS_RELWITHDEBINFO
+ \ CMAKE_CSharp_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_CSharp_IGNORE_EXTENSIONS
+ \ CMAKE_CSharp_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_CSharp_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_CSharp_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_CSharp_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_CSharp_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_CSharp_INIT
+ \ CMAKE_CSharp_LIBRARY_ARCHITECTURE
+ \ CMAKE_CSharp_LINKER_PREFERENCE
+ \ CMAKE_CSharp_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_CSharp_LINKER_WRAPPER_FLAG
+ \ CMAKE_CSharp_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_CSharp_LINK_EXECUTABLE
+ \ CMAKE_CSharp_LINK_LIBRARY_FILE_FLAG
+ \ CMAKE_CSharp_LINK_LIBRARY_FLAG
+ \ CMAKE_CSharp_LINK_LIBRARY_SUFFIX
+ \ CMAKE_CSharp_OUTPUT_EXTENSION
+ \ CMAKE_CSharp_PLATFORM_ID
+ \ CMAKE_CSharp_SIMULATE_ID
+ \ CMAKE_CSharp_SIMULATE_VERSION
+ \ CMAKE_CSharp_SIZEOF_DATA_PTR
+ \ CMAKE_CSharp_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_CSharp_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_CSharp_STANDARD_LIBRARIES
+ \ CMAKE_CSharp_VISIBILITY_PRESET
+ \ CMAKE_CTEST_ARGUMENTS
+ \ CMAKE_CTEST_COMMAND
+ \ CMAKE_CUDA
+ \ CMAKE_CUDA_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_CUDA_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_CUDA_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_CUDA_ARCHITECTURES
+ \ CMAKE_CUDA_ARCHIVE_APPEND
+ \ CMAKE_CUDA_ARCHIVE_CREATE
+ \ CMAKE_CUDA_ARCHIVE_FINISH
+ \ CMAKE_CUDA_CLANG_TIDY
+ \ CMAKE_CUDA_COMPILER
+ \ CMAKE_CUDA_COMPILER_ABI
+ \ CMAKE_CUDA_COMPILER_AR
+ \ CMAKE_CUDA_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_CUDA_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_CUDA_COMPILER_ID
+ \ CMAKE_CUDA_COMPILER_LAUNCHER
+ \ CMAKE_CUDA_COMPILER_LOADED
+ \ CMAKE_CUDA_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_CUDA_COMPILER_RANLIB
+ \ CMAKE_CUDA_COMPILER_TARGET
+ \ CMAKE_CUDA_COMPILER_VERSION
+ \ CMAKE_CUDA_COMPILER_VERSION_INTERNAL
+ \ CMAKE_CUDA_COMPILE_FEATURES
+ \ CMAKE_CUDA_COMPILE_OBJECT
+ \ CMAKE_CUDA_CPPCHECK
+ \ CMAKE_CUDA_CPPLINT
+ \ CMAKE_CUDA_CREATE_SHARED_LIBRARY
+ \ CMAKE_CUDA_CREATE_SHARED_MODULE
+ \ CMAKE_CUDA_CREATE_STATIC_LIBRARY
+ \ CMAKE_CUDA_EXTENSIONS
+ \ CMAKE_CUDA_FLAGS
+ \ CMAKE_CUDA_FLAGS_DEBUG
+ \ CMAKE_CUDA_FLAGS_DEBUG_INIT
+ \ CMAKE_CUDA_FLAGS_INIT
+ \ CMAKE_CUDA_FLAGS_MINSIZEREL
+ \ CMAKE_CUDA_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_CUDA_FLAGS_RELEASE
+ \ CMAKE_CUDA_FLAGS_RELEASE_INIT
+ \ CMAKE_CUDA_FLAGS_RELWITHDEBINFO
+ \ CMAKE_CUDA_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_CUDA_HOST_COMPILER
+ \ CMAKE_CUDA_IGNORE_EXTENSIONS
+ \ CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_CUDA_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_CUDA_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_CUDA_INIT
+ \ CMAKE_CUDA_LIBRARY_ARCHITECTURE
+ \ CMAKE_CUDA_LINKER_PREFERENCE
+ \ CMAKE_CUDA_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_CUDA_LINKER_WRAPPER_FLAG
+ \ CMAKE_CUDA_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_CUDA_LINK_EXECUTABLE
+ \ CMAKE_CUDA_LINK_LIBRARY_FILE_FLAG
+ \ CMAKE_CUDA_LINK_LIBRARY_FLAG
+ \ CMAKE_CUDA_LINK_LIBRARY_SUFFIX
+ \ CMAKE_CUDA_OUTPUT_EXTENSION
+ \ CMAKE_CUDA_PLATFORM_ID
+ \ CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS
+ \ CMAKE_CUDA_RUNTIME_LIBRARY
+ \ CMAKE_CUDA_SEPARABLE_COMPILATION
+ \ CMAKE_CUDA_SIMULATE_ID
+ \ CMAKE_CUDA_SIMULATE_VERSION
+ \ CMAKE_CUDA_SIZEOF_DATA_PTR
+ \ CMAKE_CUDA_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_CUDA_STANDARD
+ \ CMAKE_CUDA_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_CUDA_STANDARD_LIBRARIES
+ \ CMAKE_CUDA_STANDARD_REQUIRED
+ \ CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES
+ \ CMAKE_CUDA_VISIBILITY_PRESET
+ \ CMAKE_CURRENT_BINARY_DIR
+ \ CMAKE_CURRENT_FUNCTION
+ \ CMAKE_CURRENT_FUNCTION_LIST_DIR
+ \ CMAKE_CURRENT_FUNCTION_LIST_FILE
+ \ CMAKE_CURRENT_FUNCTION_LIST_LINE
+ \ CMAKE_CURRENT_LIST_DIR
+ \ CMAKE_CURRENT_LIST_FILE
+ \ CMAKE_CURRENT_LIST_LINE
+ \ CMAKE_CURRENT_SOURCE_DIR
+ \ CMAKE_CXX
+ \ CMAKE_CXX_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_CXX_ARCHIVE_APPEND
+ \ CMAKE_CXX_ARCHIVE_CREATE
+ \ CMAKE_CXX_ARCHIVE_FINISH
+ \ CMAKE_CXX_CLANG_TIDY
+ \ CMAKE_CXX_COMPILER
+ \ CMAKE_CXX_COMPILER_ABI
+ \ CMAKE_CXX_COMPILER_AR
+ \ CMAKE_CXX_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_CXX_COMPILER_ID
+ \ CMAKE_CXX_COMPILER_LAUNCHER
+ \ CMAKE_CXX_COMPILER_LOADED
+ \ CMAKE_CXX_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_CXX_COMPILER_RANLIB
+ \ CMAKE_CXX_COMPILER_TARGET
+ \ CMAKE_CXX_COMPILER_VERSION
+ \ CMAKE_CXX_COMPILER_VERSION_INTERNAL
+ \ CMAKE_CXX_COMPILE_FEATURES
+ \ CMAKE_CXX_COMPILE_OBJECT
+ \ CMAKE_CXX_CPPCHECK
+ \ CMAKE_CXX_CPPLINT
+ \ CMAKE_CXX_CREATE_SHARED_LIBRARY
+ \ CMAKE_CXX_CREATE_SHARED_MODULE
+ \ CMAKE_CXX_CREATE_STATIC_LIBRARY
+ \ CMAKE_CXX_EXTENSIONS
+ \ CMAKE_CXX_FLAGS
+ \ CMAKE_CXX_FLAGS_DEBUG
+ \ CMAKE_CXX_FLAGS_DEBUG_INIT
+ \ CMAKE_CXX_FLAGS_INIT
+ \ CMAKE_CXX_FLAGS_MINSIZEREL
+ \ CMAKE_CXX_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_CXX_FLAGS_RELEASE
+ \ CMAKE_CXX_FLAGS_RELEASE_INIT
+ \ CMAKE_CXX_FLAGS_RELWITHDEBINFO
+ \ CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_CXX_IGNORE_EXTENSIONS
+ \ CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_CXX_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_CXX_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_CXX_INIT
+ \ CMAKE_CXX_LIBRARY_ARCHITECTURE
+ \ CMAKE_CXX_LINKER_PREFERENCE
+ \ CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_CXX_LINKER_WRAPPER_FLAG
+ \ CMAKE_CXX_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_CXX_LINK_EXECUTABLE
+ \ CMAKE_CXX_LINK_LIBRARY_FILE_FLAG
+ \ CMAKE_CXX_LINK_LIBRARY_FLAG
+ \ CMAKE_CXX_LINK_LIBRARY_SUFFIX
+ \ CMAKE_CXX_OUTPUT_EXTENSION
+ \ CMAKE_CXX_PLATFORM_ID
+ \ CMAKE_CXX_SIMULATE_ID
+ \ CMAKE_CXX_SIMULATE_VERSION
+ \ CMAKE_CXX_SIZEOF_DATA_PTR
+ \ CMAKE_CXX_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_CXX_STANDARD
+ \ CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_CXX_STANDARD_LIBRARIES
+ \ CMAKE_CXX_STANDARD_REQUIRED
+ \ CMAKE_CXX_VISIBILITY_PRESET
+ \ CMAKE_C_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_C_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_C_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_C_ARCHIVE_APPEND
+ \ CMAKE_C_ARCHIVE_CREATE
+ \ CMAKE_C_ARCHIVE_FINISH
+ \ CMAKE_C_CLANG_TIDY
+ \ CMAKE_C_COMPILER
+ \ CMAKE_C_COMPILER_ABI
+ \ CMAKE_C_COMPILER_AR
+ \ CMAKE_C_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_C_COMPILER_ID
+ \ CMAKE_C_COMPILER_LAUNCHER
+ \ CMAKE_C_COMPILER_LOADED
+ \ CMAKE_C_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_C_COMPILER_RANLIB
+ \ CMAKE_C_COMPILER_TARGET
+ \ CMAKE_C_COMPILER_VERSION
+ \ CMAKE_C_COMPILER_VERSION_INTERNAL
+ \ CMAKE_C_COMPILE_FEATURES
+ \ CMAKE_C_COMPILE_OBJECT
+ \ CMAKE_C_CPPCHECK
+ \ CMAKE_C_CPPLINT
+ \ CMAKE_C_CREATE_SHARED_LIBRARY
+ \ CMAKE_C_CREATE_SHARED_MODULE
+ \ CMAKE_C_CREATE_STATIC_LIBRARY
+ \ CMAKE_C_EXTENSIONS
+ \ CMAKE_C_FLAGS
+ \ CMAKE_C_FLAGS_DEBUG
+ \ CMAKE_C_FLAGS_DEBUG_INIT
+ \ CMAKE_C_FLAGS_INIT
+ \ CMAKE_C_FLAGS_MINSIZEREL
+ \ CMAKE_C_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_C_FLAGS_RELEASE
+ \ CMAKE_C_FLAGS_RELEASE_INIT
+ \ CMAKE_C_FLAGS_RELWITHDEBINFO
+ \ CMAKE_C_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_C_IGNORE_EXTENSIONS
+ \ CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_C_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_C_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_C_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_C_INIT
+ \ CMAKE_C_LIBRARY_ARCHITECTURE
+ \ CMAKE_C_LINKER_PREFERENCE
+ \ CMAKE_C_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_C_LINKER_WRAPPER_FLAG
+ \ CMAKE_C_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_C_LINK_EXECUTABLE
+ \ CMAKE_C_LINK_LIBRARY_FILE_FLAG
+ \ CMAKE_C_LINK_LIBRARY_FLAG
+ \ CMAKE_C_LINK_LIBRARY_SUFFIX
+ \ CMAKE_C_OUTPUT_EXTENSION
+ \ CMAKE_C_PLATFORM_ID
+ \ CMAKE_C_SIMULATE_ID
+ \ CMAKE_C_SIMULATE_VERSION
+ \ CMAKE_C_SIZEOF_DATA_PTR
+ \ CMAKE_C_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_C_STANDARD
+ \ CMAKE_C_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_C_STANDARD_LIBRARIES
+ \ CMAKE_C_STANDARD_REQUIRED
+ \ CMAKE_C_VISIBILITY_PRESET
+ \ CMAKE_DEBUG_POSTFIX
+ \ CMAKE_DEBUG_TARGET_PROPERTIES
+ \ CMAKE_DEFAULT_BUILD_TYPE
+ \ CMAKE_DEFAULT_CONFIGS
+ \ CMAKE_DEPENDS_IN_PROJECT_ONLY
+ \ CMAKE_DIRECTORY_LABELS
+ \ CMAKE_DISABLE_PRECOMPILE_HEADERS
+ \ CMAKE_DL_LIBS
+ \ CMAKE_DOTNET_TARGET_FRAMEWORK
+ \ CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION
+ \ CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES
+ \ CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT
+ \ CMAKE_ECLIPSE_MAKE_ARGUMENTS
+ \ CMAKE_ECLIPSE_RESOURCE_ENCODING
+ \ CMAKE_ECLIPSE_VERSION
+ \ CMAKE_EDIT_COMMAND
+ \ CMAKE_ENABLE_EXPORTS
+ \ CMAKE_ERROR_DEPRECATED
+ \ CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
+ \ CMAKE_EXECUTABLE_SUFFIX
+ \ CMAKE_EXECUTE_PROCESS_COMMAND_ECHO
+ \ CMAKE_EXE_LINKER_FLAGS
+ \ CMAKE_EXE_LINKER_FLAGS_INIT
+ \ CMAKE_EXPORT_COMPILE_COMMANDS
+ \ CMAKE_EXPORT_NO_PACKAGE_REGISTRY
+ \ CMAKE_EXPORT_PACKAGE_REGISTRY
+ \ CMAKE_EXTRA_GENERATOR
+ \ CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES
+ \ CMAKE_FIND_APPBUNDLE
+ \ CMAKE_FIND_DEBUG_MODE
+ \ CMAKE_FIND_FRAMEWORK
+ \ CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX
+ \ CMAKE_FIND_LIBRARY_PREFIXES
+ \ CMAKE_FIND_LIBRARY_SUFFIXES
+ \ CMAKE_FIND_NO_INSTALL_PREFIX
+ \ CMAKE_FIND_PACKAGE_NAME
+ \ CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY
+ \ CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY
+ \ CMAKE_FIND_PACKAGE_PREFER_CONFIG
+ \ CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS
+ \ CMAKE_FIND_PACKAGE_SORT_DIRECTION
+ \ CMAKE_FIND_PACKAGE_SORT_ORDER
+ \ CMAKE_FIND_PACKAGE_WARN_NO_MODULE
+ \ CMAKE_FIND_ROOT_PATH
+ \ CMAKE_FIND_ROOT_PATH_MODE_INCLUDE
+ \ CMAKE_FIND_ROOT_PATH_MODE_LIBRARY
+ \ CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
+ \ CMAKE_FIND_ROOT_PATH_MODE_PROGRAM
+ \ CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH
+ \ CMAKE_FIND_USE_CMAKE_PATH
+ \ CMAKE_FIND_USE_CMAKE_SYSTEM_PATH
+ \ CMAKE_FIND_USE_PACKAGE_REGISTRY
+ \ CMAKE_FIND_USE_PACKAGE_ROOT_PATH
+ \ CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH
+ \ CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY
+ \ CMAKE_FOLDER
+ \ CMAKE_FRAMEWORK
+ \ CMAKE_FRAMEWORK_PATH
+ \ CMAKE_Fortran
+ \ CMAKE_Fortran_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_Fortran_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_Fortran_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_Fortran_ARCHIVE_APPEND
+ \ CMAKE_Fortran_ARCHIVE_CREATE
+ \ CMAKE_Fortran_ARCHIVE_FINISH
+ \ CMAKE_Fortran_CLANG_TIDY
+ \ CMAKE_Fortran_COMPILER
+ \ CMAKE_Fortran_COMPILER_ABI
+ \ CMAKE_Fortran_COMPILER_AR
+ \ CMAKE_Fortran_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_Fortran_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_Fortran_COMPILER_ID
+ \ CMAKE_Fortran_COMPILER_LAUNCHER
+ \ CMAKE_Fortran_COMPILER_LOADED
+ \ CMAKE_Fortran_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_Fortran_COMPILER_RANLIB
+ \ CMAKE_Fortran_COMPILER_TARGET
+ \ CMAKE_Fortran_COMPILER_VERSION
+ \ CMAKE_Fortran_COMPILER_VERSION_INTERNAL
+ \ CMAKE_Fortran_COMPILE_OBJECT
+ \ CMAKE_Fortran_CPPCHECK
+ \ CMAKE_Fortran_CPPLINT
+ \ CMAKE_Fortran_CREATE_SHARED_LIBRARY
+ \ CMAKE_Fortran_CREATE_SHARED_MODULE
+ \ CMAKE_Fortran_CREATE_STATIC_LIBRARY
+ \ CMAKE_Fortran_FLAGS
+ \ CMAKE_Fortran_FLAGS_DEBUG
+ \ CMAKE_Fortran_FLAGS_DEBUG_INIT
+ \ CMAKE_Fortran_FLAGS_INIT
+ \ CMAKE_Fortran_FLAGS_MINSIZEREL
+ \ CMAKE_Fortran_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_Fortran_FLAGS_RELEASE
+ \ CMAKE_Fortran_FLAGS_RELEASE_INIT
+ \ CMAKE_Fortran_FLAGS_RELWITHDEBINFO
+ \ CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_Fortran_FORMAT
+ \ CMAKE_Fortran_IGNORE_EXTENSIONS
+ \ CMAKE_Fortran_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_Fortran_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_Fortran_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_Fortran_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_Fortran_INIT
+ \ CMAKE_Fortran_LIBRARY_ARCHITECTURE
+ \ CMAKE_Fortran_LINKER_PREFERENCE
+ \ CMAKE_Fortran_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_Fortran_LINKER_WRAPPER_FLAG
+ \ CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_Fortran_LINK_EXECUTABLE
+ \ CMAKE_Fortran_LINK_LIBRARY_FILE_FLAG
+ \ CMAKE_Fortran_LINK_LIBRARY_FLAG
+ \ CMAKE_Fortran_LINK_LIBRARY_SUFFIX
+ \ CMAKE_Fortran_MODDIR_DEFAULT
+ \ CMAKE_Fortran_MODDIR_FLAG
+ \ CMAKE_Fortran_MODOUT_FLAG
+ \ CMAKE_Fortran_MODULE_DIRECTORY
+ \ CMAKE_Fortran_OUTPUT_EXTENSION
+ \ CMAKE_Fortran_PLATFORM_ID
+ \ CMAKE_Fortran_PREPROCESS
+ \ CMAKE_Fortran_SIMULATE_ID
+ \ CMAKE_Fortran_SIMULATE_VERSION
+ \ CMAKE_Fortran_SIZEOF_DATA_PTR
+ \ CMAKE_Fortran_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_Fortran_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_Fortran_STANDARD_LIBRARIES
+ \ CMAKE_Fortran_VISIBILITY_PRESET
+ \ CMAKE_GENERATOR
+ \ CMAKE_GENERATOR_INSTANCE
+ \ CMAKE_GENERATOR_PLATFORM
+ \ CMAKE_GENERATOR_TOOLSET
+ \ CMAKE_GHS_NO_SOURCE_GROUP_FILE
+ \ CMAKE_GLOBAL_AUTOGEN_TARGET
+ \ CMAKE_GLOBAL_AUTOGEN_TARGET_NAME
+ \ CMAKE_GLOBAL_AUTORCC_TARGET
+ \ CMAKE_GLOBAL_AUTORCC_TARGET_NAME
+ \ CMAKE_GNUtoMS
+ \ CMAKE_HOME_DIRECTORY
+ \ CMAKE_HOST_APPLE
+ \ CMAKE_HOST_SOLARIS
+ \ CMAKE_HOST_SYSTEM
+ \ CMAKE_HOST_SYSTEM_NAME
+ \ CMAKE_HOST_SYSTEM_PROCESSOR
+ \ CMAKE_HOST_SYSTEM_VERSION
+ \ CMAKE_HOST_UNIX
+ \ CMAKE_HOST_WIN32
+ \ CMAKE_IGNORE_PATH
+ \ CMAKE_IMPORT_LIBRARY_PREFIX
+ \ CMAKE_IMPORT_LIBRARY_SUFFIX
+ \ CMAKE_INCLUDE_CURRENT_DIR
+ \ CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE
+ \ CMAKE_INCLUDE_DIRECTORIES_BEFORE
+ \ CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE
+ \ CMAKE_INCLUDE_PATH
+ \ CMAKE_INSTALL_DEFAULT_COMPONENT_NAME
+ \ CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
+ \ CMAKE_INSTALL_MESSAGE
+ \ CMAKE_INSTALL_NAME_DIR
+ \ CMAKE_INSTALL_PREFIX
+ \ CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
+ \ CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH
+ \ CMAKE_INSTALL_RPATH
+ \ CMAKE_INSTALL_RPATH_USE_LINK_PATH
+ \ CMAKE_INTERNAL_PLATFORM_ABI
+ \ CMAKE_INTERPROCEDURAL_OPTIMIZATION
+ \ CMAKE_IOS_INSTALL_COMBINED
+ \ CMAKE_ISPC_HEADER_DIRECTORY
+ \ CMAKE_ISPC_INSTRUCTION_SETS
+ \ CMAKE_JOB_POOLS
+ \ CMAKE_JOB_POOL_COMPILE
+ \ CMAKE_JOB_POOL_LINK
+ \ CMAKE_JOB_POOL_PRECOMPILE_HEADER
+ \ CMAKE_Java
+ \ CMAKE_Java_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_Java_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_Java_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_Java_ARCHIVE_APPEND
+ \ CMAKE_Java_ARCHIVE_CREATE
+ \ CMAKE_Java_ARCHIVE_FINISH
+ \ CMAKE_Java_CLANG_TIDY
+ \ CMAKE_Java_COMPILER
+ \ CMAKE_Java_COMPILER_ABI
+ \ CMAKE_Java_COMPILER_AR
+ \ CMAKE_Java_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_Java_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_Java_COMPILER_ID
+ \ CMAKE_Java_COMPILER_LAUNCHER
+ \ CMAKE_Java_COMPILER_LOADED
+ \ CMAKE_Java_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_Java_COMPILER_RANLIB
+ \ CMAKE_Java_COMPILER_TARGET
+ \ CMAKE_Java_COMPILER_VERSION
+ \ CMAKE_Java_COMPILER_VERSION_INTERNAL
+ \ CMAKE_Java_COMPILE_OBJECT
+ \ CMAKE_Java_CPPCHECK
+ \ CMAKE_Java_CPPLINT
+ \ CMAKE_Java_CREATE_SHARED_LIBRARY
+ \ CMAKE_Java_CREATE_SHARED_MODULE
+ \ CMAKE_Java_CREATE_STATIC_LIBRARY
+ \ CMAKE_Java_FLAGS
+ \ CMAKE_Java_FLAGS_DEBUG
+ \ CMAKE_Java_FLAGS_DEBUG_INIT
+ \ CMAKE_Java_FLAGS_INIT
+ \ CMAKE_Java_FLAGS_MINSIZEREL
+ \ CMAKE_Java_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_Java_FLAGS_RELEASE
+ \ CMAKE_Java_FLAGS_RELEASE_INIT
+ \ CMAKE_Java_FLAGS_RELWITHDEBINFO
+ \ CMAKE_Java_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_Java_IGNORE_EXTENSIONS
+ \ CMAKE_Java_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_Java_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_Java_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_Java_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_Java_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_Java_INIT
+ \ CMAKE_Java_LIBRARY_ARCHITECTURE
+ \ CMAKE_Java_LINKER_PREFERENCE
+ \ CMAKE_Java_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_Java_LINKER_WRAPPER_FLAG
+ \ CMAKE_Java_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_Java_LINK_EXECUTABLE
+ \ CMAKE_Java_LINK_LIBRARY_FILE_FLAG
+ \ CMAKE_Java_LINK_LIBRARY_FLAG
+ \ CMAKE_Java_LINK_LIBRARY_SUFFIX
+ \ CMAKE_Java_OUTPUT_EXTENSION
+ \ CMAKE_Java_PLATFORM_ID
+ \ CMAKE_Java_SIMULATE_ID
+ \ CMAKE_Java_SIMULATE_VERSION
+ \ CMAKE_Java_SIZEOF_DATA_PTR
+ \ CMAKE_Java_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_Java_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_Java_STANDARD_LIBRARIES
+ \ CMAKE_Java_VISIBILITY_PRESET
+ \ CMAKE_LIBRARY_ARCHITECTURE
+ \ CMAKE_LIBRARY_ARCHITECTURE_REGEX
+ \ CMAKE_LIBRARY_OUTPUT_DIRECTORY
+ \ CMAKE_LIBRARY_PATH
+ \ CMAKE_LIBRARY_PATH_FLAG
+ \ CMAKE_LINK_DEF_FILE_FLAG
+ \ CMAKE_LINK_DEPENDS_NO_SHARED
+ \ CMAKE_LINK_DIRECTORIES_BEFORE
+ \ CMAKE_LINK_INTERFACE_LIBRARIES
+ \ CMAKE_LINK_LIBRARY_FILE_FLAG
+ \ CMAKE_LINK_LIBRARY_FLAG
+ \ CMAKE_LINK_LIBRARY_SUFFIX
+ \ CMAKE_LINK_SEARCH_END_STATIC
+ \ CMAKE_LINK_SEARCH_START_STATIC
+ \ CMAKE_LINK_WHAT_YOU_USE
+ \ CMAKE_MACOSX_BUNDLE
+ \ CMAKE_MACOSX_RPATH
+ \ CMAKE_MAJOR_VERSION
+ \ CMAKE_MAKE_PROGRAM
+ \ CMAKE_MATCH_COUNT
+ \ CMAKE_MAXIMUM_RECURSION_DEPTH
+ \ CMAKE_MESSAGE_CONTEXT
+ \ CMAKE_MESSAGE_CONTEXT_SHOW
+ \ CMAKE_MESSAGE_INDENT
+ \ CMAKE_MESSAGE_LOG_LEVEL
+ \ CMAKE_MFC_FLAG
+ \ CMAKE_MINIMUM_REQUIRED_VERSION
+ \ CMAKE_MINOR_VERSION
+ \ CMAKE_MODULE_LINKER_FLAGS
+ \ CMAKE_MODULE_LINKER_FLAGS_INIT
+ \ CMAKE_MODULE_PATH
+ \ CMAKE_MSVCIDE_RUN_PATH
+ \ CMAKE_MSVC_RUNTIME_LIBRARY
+ \ CMAKE_NETRC
+ \ CMAKE_NETRC_FILE
+ \ CMAKE_NINJA_OUTPUT_PATH_PREFIX
+ \ CMAKE_NOT_USING_CONFIG_FLAGS
+ \ CMAKE_NO_BUILTIN_CHRPATH
+ \ CMAKE_NO_SYSTEM_FROM_IMPORTED
+ \ CMAKE_OBJCXX_CLANG_TIDY
+ \ CMAKE_OBJCXX_EXTENSIONS
+ \ CMAKE_OBJCXX_STANDARD
+ \ CMAKE_OBJCXX_STANDARD_REQUIRED
+ \ CMAKE_OBJC_CLANG_TIDY
+ \ CMAKE_OBJC_EXTENSIONS
+ \ CMAKE_OBJC_STANDARD
+ \ CMAKE_OBJC_STANDARD_REQUIRED
+ \ CMAKE_OBJECT_PATH_MAX
+ \ CMAKE_OPTIMIZE_DEPENDENCIES
+ \ CMAKE_OSX_ARCHITECTURES
+ \ CMAKE_OSX_DEPLOYMENT_TARGET
+ \ CMAKE_OSX_SYSROOT
+ \ CMAKE_PARENT_LIST_FILE
+ \ CMAKE_PATCH_VERSION
+ \ CMAKE_PCH_INSTANTIATE_TEMPLATES
+ \ CMAKE_PCH_WARN_INVALID
+ \ CMAKE_PDB_OUTPUT_DIRECTORY
+ \ CMAKE_POSITION_INDEPENDENT_CODE
+ \ CMAKE_PREFIX_PATH
+ \ CMAKE_PROGRAM_PATH
+ \ CMAKE_PROJECT_DESCRIPTION
+ \ CMAKE_PROJECT_HOMEPAGE_URL
+ \ CMAKE_PROJECT_INCLUDE
+ \ CMAKE_PROJECT_INCLUDE_BEFORE
+ \ CMAKE_PROJECT_NAME
+ \ CMAKE_PROJECT_VERSION
+ \ CMAKE_PROJECT_VERSION_MAJOR
+ \ CMAKE_PROJECT_VERSION_MINOR
+ \ CMAKE_PROJECT_VERSION_PATCH
+ \ CMAKE_PROJECT_VERSION_TWEAK
+ \ CMAKE_RANLIB
+ \ CMAKE_RC
+ \ CMAKE_RC_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_RC_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_RC_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_RC_ARCHIVE_APPEND
+ \ CMAKE_RC_ARCHIVE_CREATE
+ \ CMAKE_RC_ARCHIVE_FINISH
+ \ CMAKE_RC_CLANG_TIDY
+ \ CMAKE_RC_COMPILER
+ \ CMAKE_RC_COMPILER_ABI
+ \ CMAKE_RC_COMPILER_AR
+ \ CMAKE_RC_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_RC_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_RC_COMPILER_ID
+ \ CMAKE_RC_COMPILER_LAUNCHER
+ \ CMAKE_RC_COMPILER_LOADED
+ \ CMAKE_RC_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_RC_COMPILER_RANLIB
+ \ CMAKE_RC_COMPILER_TARGET
+ \ CMAKE_RC_COMPILER_VERSION
+ \ CMAKE_RC_COMPILER_VERSION_INTERNAL
+ \ CMAKE_RC_COMPILE_OBJECT
+ \ CMAKE_RC_CPPCHECK
+ \ CMAKE_RC_CPPLINT
+ \ CMAKE_RC_CREATE_SHARED_LIBRARY
+ \ CMAKE_RC_CREATE_SHARED_MODULE
+ \ CMAKE_RC_CREATE_STATIC_LIBRARY
+ \ CMAKE_RC_FLAGS
+ \ CMAKE_RC_FLAGS_DEBUG
+ \ CMAKE_RC_FLAGS_DEBUG_INIT
+ \ CMAKE_RC_FLAGS_INIT
+ \ CMAKE_RC_FLAGS_MINSIZEREL
+ \ CMAKE_RC_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_RC_FLAGS_RELEASE
+ \ CMAKE_RC_FLAGS_RELEASE_INIT
+ \ CMAKE_RC_FLAGS_RELWITHDEBINFO
+ \ CMAKE_RC_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_RC_IGNORE_EXTENSIONS
+ \ CMAKE_RC_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_RC_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_RC_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_RC_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_RC_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_RC_INIT
+ \ CMAKE_RC_LIBRARY_ARCHITECTURE
+ \ CMAKE_RC_LINKER_PREFERENCE
+ \ CMAKE_RC_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_RC_LINKER_WRAPPER_FLAG
+ \ CMAKE_RC_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_RC_LINK_EXECUTABLE
+ \ CMAKE_RC_LINK_LIBRARY_FILE_FLAG
+ \ CMAKE_RC_LINK_LIBRARY_FLAG
+ \ CMAKE_RC_LINK_LIBRARY_SUFFIX
+ \ CMAKE_RC_OUTPUT_EXTENSION
+ \ CMAKE_RC_PLATFORM_ID
+ \ CMAKE_RC_SIMULATE_ID
+ \ CMAKE_RC_SIMULATE_VERSION
+ \ CMAKE_RC_SIZEOF_DATA_PTR
+ \ CMAKE_RC_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_RC_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_RC_STANDARD_LIBRARIES
+ \ CMAKE_RC_VISIBILITY_PRESET
+ \ CMAKE_ROOT
+ \ CMAKE_RULE_MESSAGES
+ \ CMAKE_RUNTIME_OUTPUT_DIRECTORY
+ \ CMAKE_SCRIPT_MODE_FILE
+ \ CMAKE_SHARED_LIBRARY_PREFIX
+ \ CMAKE_SHARED_LIBRARY_SUFFIX
+ \ CMAKE_SHARED_LINKER_FLAGS
+ \ CMAKE_SHARED_LINKER_FLAGS_INIT
+ \ CMAKE_SHARED_MODULE_PREFIX
+ \ CMAKE_SHARED_MODULE_SUFFIX
+ \ CMAKE_SIZEOF_VOID_P
+ \ CMAKE_SKIP_BUILD_RPATH
+ \ CMAKE_SKIP_INSTALL_ALL_DEPENDENCY
+ \ CMAKE_SKIP_INSTALL_RPATH
+ \ CMAKE_SKIP_INSTALL_RULES
+ \ CMAKE_SKIP_RPATH
+ \ CMAKE_SOURCE_DIR
+ \ CMAKE_STAGING_PREFIX
+ \ CMAKE_STATIC_LIBRARY_PREFIX
+ \ CMAKE_STATIC_LIBRARY_SUFFIX
+ \ CMAKE_STATIC_LINKER_FLAGS
+ \ CMAKE_STATIC_LINKER_FLAGS_INIT
+ \ CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS
+ \ CMAKE_SUBLIME_TEXT_2_EXCLUDE_BUILD_TREE
+ \ CMAKE_SUPPRESS_REGENERATION
+ \ CMAKE_SYSROOT
+ \ CMAKE_SYSROOT_COMPILE
+ \ CMAKE_SYSROOT_LINK
+ \ CMAKE_SYSTEM
+ \ CMAKE_SYSTEM_APPBUNDLE_PATH
+ \ CMAKE_SYSTEM_FRAMEWORK_PATH
+ \ CMAKE_SYSTEM_IGNORE_PATH
+ \ CMAKE_SYSTEM_INCLUDE_PATH
+ \ CMAKE_SYSTEM_LIBRARY_PATH
+ \ CMAKE_SYSTEM_NAME
+ \ CMAKE_SYSTEM_PREFIX_PATH
+ \ CMAKE_SYSTEM_PROCESSOR
+ \ CMAKE_SYSTEM_PROGRAM_PATH
+ \ CMAKE_SYSTEM_VERSION
+ \ CMAKE_Swift
+ \ CMAKE_Swift_ANDROID_TOOLCHAIN_MACHINE
+ \ CMAKE_Swift_ANDROID_TOOLCHAIN_PREFIX
+ \ CMAKE_Swift_ANDROID_TOOLCHAIN_SUFFIX
+ \ CMAKE_Swift_ARCHIVE_APPEND
+ \ CMAKE_Swift_ARCHIVE_CREATE
+ \ CMAKE_Swift_ARCHIVE_FINISH
+ \ CMAKE_Swift_CLANG_TIDY
+ \ CMAKE_Swift_COMPILER
+ \ CMAKE_Swift_COMPILER_ABI
+ \ CMAKE_Swift_COMPILER_AR
+ \ CMAKE_Swift_COMPILER_ARCHITECTURE_ID
+ \ CMAKE_Swift_COMPILER_EXTERNAL_TOOLCHAIN
+ \ CMAKE_Swift_COMPILER_ID
+ \ CMAKE_Swift_COMPILER_LAUNCHER
+ \ CMAKE_Swift_COMPILER_LOADED
+ \ CMAKE_Swift_COMPILER_PREDEFINES_COMMAND
+ \ CMAKE_Swift_COMPILER_RANLIB
+ \ CMAKE_Swift_COMPILER_TARGET
+ \ CMAKE_Swift_COMPILER_VERSION
+ \ CMAKE_Swift_COMPILER_VERSION_INTERNAL
+ \ CMAKE_Swift_COMPILE_OBJECT
+ \ CMAKE_Swift_CPPCHECK
+ \ CMAKE_Swift_CPPLINT
+ \ CMAKE_Swift_CREATE_SHARED_LIBRARY
+ \ CMAKE_Swift_CREATE_SHARED_MODULE
+ \ CMAKE_Swift_CREATE_STATIC_LIBRARY
+ \ CMAKE_Swift_FLAGS
+ \ CMAKE_Swift_FLAGS_DEBUG
+ \ CMAKE_Swift_FLAGS_DEBUG_INIT
+ \ CMAKE_Swift_FLAGS_INIT
+ \ CMAKE_Swift_FLAGS_MINSIZEREL
+ \ CMAKE_Swift_FLAGS_MINSIZEREL_INIT
+ \ CMAKE_Swift_FLAGS_RELEASE
+ \ CMAKE_Swift_FLAGS_RELEASE_INIT
+ \ CMAKE_Swift_FLAGS_RELWITHDEBINFO
+ \ CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT
+ \ CMAKE_Swift_IGNORE_EXTENSIONS
+ \ CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES
+ \ CMAKE_Swift_IMPLICIT_LINK_DIRECTORIES
+ \ CMAKE_Swift_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ \ CMAKE_Swift_IMPLICIT_LINK_LIBRARIES
+ \ CMAKE_Swift_INCLUDE_WHAT_YOU_USE
+ \ CMAKE_Swift_INIT
+ \ CMAKE_Swift_LANGUAGE_VERSION
+ \ CMAKE_Swift_LIBRARY_ARCHITECTURE
+ \ CMAKE_Swift_LINKER_PREFERENCE
+ \ CMAKE_Swift_LINKER_PREFERENCE_PROPAGATES
+ \ CMAKE_Swift_LINKER_WRAPPER_FLAG
+ \ CMAKE_Swift_LINKER_WRAPPER_FLAG_SEP
+ \ CMAKE_Swift_LINK_EXECUTABLE
+ \ CMAKE_Swift_LINK_LIBRARY_FILE_FLAG
+ \ CMAKE_Swift_LINK_LIBRARY_FLAG
+ \ CMAKE_Swift_LINK_LIBRARY_SUFFIX
+ \ CMAKE_Swift_MODULE_DIRECTORY
+ \ CMAKE_Swift_NUM_THREADS
+ \ CMAKE_Swift_OUTPUT_EXTENSION
+ \ CMAKE_Swift_PLATFORM_ID
+ \ CMAKE_Swift_SIMULATE_ID
+ \ CMAKE_Swift_SIMULATE_VERSION
+ \ CMAKE_Swift_SIZEOF_DATA_PTR
+ \ CMAKE_Swift_SOURCE_FILE_EXTENSIONS
+ \ CMAKE_Swift_STANDARD_INCLUDE_DIRECTORIES
+ \ CMAKE_Swift_STANDARD_LIBRARIES
+ \ CMAKE_Swift_VISIBILITY_PRESET
+ \ CMAKE_TOOLCHAIN_FILE
+ \ CMAKE_TRY_COMPILE_CONFIGURATION
+ \ CMAKE_TRY_COMPILE_PLATFORM_VARIABLES
+ \ CMAKE_TRY_COMPILE_TARGET_TYPE
+ \ CMAKE_TWEAK_VERSION
+ \ CMAKE_UNITY_BUILD
+ \ CMAKE_UNITY_BUILD_BATCH_SIZE
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_ASM
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_ASM_MASM
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_ASM_NASM
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_C
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_CSharp
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_CUDA
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_CXX
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_Fortran
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_Java
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_RC
+ \ CMAKE_USER_MAKE_RULES_OVERRIDE_Swift
+ \ CMAKE_USE_RELATIVE_PATHS
+ \ CMAKE_VERBOSE_MAKEFILE
+ \ CMAKE_VERSION
+ \ CMAKE_VISIBILITY_INLINES_HIDDEN
+ \ CMAKE_VS_DEVENV_COMMAND
+ \ CMAKE_VS_GLOBALS
+ \ CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD
+ \ CMAKE_VS_INCLUDE_PACKAGE_TO_DEFAULT_BUILD
+ \ CMAKE_VS_INTEL_Fortran_PROJECT_VERSION
+ \ CMAKE_VS_JUST_MY_CODE_DEBUGGING
+ \ CMAKE_VS_MSBUILD_COMMAND
+ \ CMAKE_VS_NsightTegra_VERSION
+ \ CMAKE_VS_PLATFORM_NAME
+ \ CMAKE_VS_PLATFORM_NAME_DEFAULT
+ \ CMAKE_VS_PLATFORM_TOOLSET
+ \ CMAKE_VS_PLATFORM_TOOLSET_CUDA
+ \ CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR
+ \ CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE
+ \ CMAKE_VS_PLATFORM_TOOLSET_VERSION
+ \ CMAKE_VS_SDK_EXCLUDE_DIRECTORIES
+ \ CMAKE_VS_SDK_EXECUTABLE_DIRECTORIES
+ \ CMAKE_VS_SDK_INCLUDE_DIRECTORIES
+ \ CMAKE_VS_SDK_LIBRARY_DIRECTORIES
+ \ CMAKE_VS_SDK_LIBRARY_WINRT_DIRECTORIES
+ \ CMAKE_VS_SDK_REFERENCE_DIRECTORIES
+ \ CMAKE_VS_SDK_SOURCE_DIRECTORIES
+ \ CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION
+ \ CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM
+ \ CMAKE_VS_WINRT_BY_DEFAULT
+ \ CMAKE_WARN_DEPRECATED
+ \ CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION
+ \ CMAKE_WIN32_EXECUTABLE
+ \ CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
+ \ CMAKE_XCODE_BUILD_SYSTEM
+ \ CMAKE_XCODE_GENERATE_SCHEME
+ \ CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY
+ \ CMAKE_XCODE_LINK_BUILD_PHASE_MODE
+ \ CMAKE_XCODE_PLATFORM_TOOLSET
+ \ CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER
+ \ CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN
+ \ CMAKE_XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING
+ \ CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
+ \ CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
+ \ CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
+ \ CMAKE_XCODE_SCHEME_ENVIRONMENT
+ \ CMAKE_XCODE_SCHEME_GUARD_MALLOC
+ \ CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP
+ \ CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES
+ \ CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE
+ \ CMAKE_XCODE_SCHEME_MALLOC_STACK
+ \ CMAKE_XCODE_SCHEME_THREAD_SANITIZER
+ \ CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP
+ \ CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER
+ \ CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP
+ \ CMAKE_XCODE_SCHEME_WORKING_DIRECTORY
+ \ CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS
+ \ CPACK_ABSOLUTE_DESTINATION_FILES
+ \ CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY
+ \ CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
+ \ CPACK_INCLUDE_TOPLEVEL_DIRECTORY
+ \ CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
+ \ CPACK_PACKAGING_INSTALL_PREFIX
+ \ CPACK_SET_DESTDIR
+ \ CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION
+ \ CTEST_BINARY_DIRECTORY
+ \ CTEST_BUILD_COMMAND
+ \ CTEST_BUILD_NAME
+ \ CTEST_BZR_COMMAND
+ \ CTEST_BZR_UPDATE_OPTIONS
+ \ CTEST_CHANGE_ID
+ \ CTEST_CHECKOUT_COMMAND
+ \ CTEST_CONFIGURATION_TYPE
+ \ CTEST_CONFIGURE_COMMAND
+ \ CTEST_COVERAGE_COMMAND
+ \ CTEST_COVERAGE_EXTRA_FLAGS
+ \ CTEST_CURL_OPTIONS
+ \ CTEST_CUSTOM_COVERAGE_EXCLUDE
+ \ CTEST_CUSTOM_ERROR_EXCEPTION
+ \ CTEST_CUSTOM_ERROR_MATCH
+ \ CTEST_CUSTOM_ERROR_POST_CONTEXT
+ \ CTEST_CUSTOM_ERROR_PRE_CONTEXT
+ \ CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE
+ \ CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS
+ \ CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS
+ \ CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE
+ \ CTEST_CUSTOM_MEMCHECK_IGNORE
+ \ CTEST_CUSTOM_POST_MEMCHECK
+ \ CTEST_CUSTOM_POST_TEST
+ \ CTEST_CUSTOM_PRE_MEMCHECK
+ \ CTEST_CUSTOM_PRE_TEST
+ \ CTEST_CUSTOM_TESTS_IGNORE
+ \ CTEST_CUSTOM_WARNING_EXCEPTION
+ \ CTEST_CUSTOM_WARNING_MATCH
+ \ CTEST_CVS_CHECKOUT
+ \ CTEST_CVS_COMMAND
+ \ CTEST_CVS_UPDATE_OPTIONS
+ \ CTEST_DROP_LOCATION
+ \ CTEST_DROP_METHOD
+ \ CTEST_DROP_SITE
+ \ CTEST_DROP_SITE_CDASH
+ \ CTEST_DROP_SITE_PASSWORD
+ \ CTEST_DROP_SITE_USER
+ \ CTEST_EXTRA_COVERAGE_GLOB
+ \ CTEST_GIT_COMMAND
+ \ CTEST_GIT_INIT_SUBMODULES
+ \ CTEST_GIT_UPDATE_CUSTOM
+ \ CTEST_GIT_UPDATE_OPTIONS
+ \ CTEST_HG_COMMAND
+ \ CTEST_HG_UPDATE_OPTIONS
+ \ CTEST_LABELS_FOR_SUBPROJECTS
+ \ CTEST_MEMORYCHECK_COMMAND
+ \ CTEST_MEMORYCHECK_COMMAND_OPTIONS
+ \ CTEST_MEMORYCHECK_SANITIZER_OPTIONS
+ \ CTEST_MEMORYCHECK_SUPPRESSIONS_FILE
+ \ CTEST_MEMORYCHECK_TYPE
+ \ CTEST_NIGHTLY_START_TIME
+ \ CTEST_P4_CLIENT
+ \ CTEST_P4_COMMAND
+ \ CTEST_P4_OPTIONS
+ \ CTEST_P4_UPDATE_OPTIONS
+ \ CTEST_RESOURCE_SPEC_FILE
+ \ CTEST_RUN_CURRENT_SCRIPT
+ \ CTEST_SCP_COMMAND
+ \ CTEST_SITE
+ \ CTEST_SOURCE_DIRECTORY
+ \ CTEST_SUBMIT_URL
+ \ CTEST_SVN_COMMAND
+ \ CTEST_SVN_OPTIONS
+ \ CTEST_SVN_UPDATE_OPTIONS
+ \ CTEST_TEST_LOAD
+ \ CTEST_TEST_TIMEOUT
+ \ CTEST_TRIGGER_SITE
+ \ CTEST_UPDATE_COMMAND
+ \ CTEST_UPDATE_OPTIONS
+ \ CTEST_UPDATE_VERSION_ONLY
+ \ CTEST_UPDATE_VERSION_OVERRIDE
+ \ CTEST_USE_LAUNCHERS
+ \ CYGWIN
+ \ DOXYGEN_ABBREVIATE_BRIEF
+ \ DOXYGEN_ALIASES
+ \ DOXYGEN_ALLEXTERNALS
+ \ DOXYGEN_ALLOW_UNICODE_NAMES
+ \ DOXYGEN_ALPHABETICAL_INDEX
+ \ DOXYGEN_ALWAYS_DETAILED_SEC
+ \ DOXYGEN_AUTOLINK_SUPPORT
+ \ DOXYGEN_BINARY_TOC
+ \ DOXYGEN_BRIEF_MEMBER_DESC
+ \ DOXYGEN_BUILTIN_STL_SUPPORT
+ \ DOXYGEN_CALLER_GRAPH
+ \ DOXYGEN_CALL_GRAPH
+ \ DOXYGEN_CASE_SENSE_NAMES
+ \ DOXYGEN_CHM_FILE
+ \ DOXYGEN_CHM_INDEX_ENCODING
+ \ DOXYGEN_CITE_BIB_FILES
+ \ DOXYGEN_CLANG_ASSISTED_PARSING
+ \ DOXYGEN_CLANG_DATABASE_PATH
+ \ DOXYGEN_CLANG_OPTIONS
+ \ DOXYGEN_CLASS_DIAGRAMS
+ \ DOXYGEN_CLASS_GRAPH
+ \ DOXYGEN_COLLABORATION_GRAPH
+ \ DOXYGEN_COLS_IN_ALPHA_INDEX
+ \ DOXYGEN_COMPACT_LATEX
+ \ DOXYGEN_COMPACT_RTF
+ \ DOXYGEN_CPP_CLI_SUPPORT
+ \ DOXYGEN_CREATE_SUBDIRS
+ \ DOXYGEN_DIAFILE_DIRS
+ \ DOXYGEN_DIA_PATH
+ \ DOXYGEN_DIRECTORY_GRAPH
+ \ DOXYGEN_DISABLE_INDEX
+ \ DOXYGEN_DISTRIBUTE_GROUP_DOC
+ \ DOXYGEN_DOCBOOK_OUTPUT
+ \ DOXYGEN_DOCBOOK_PROGRAMLISTING
+ \ DOXYGEN_DOCSET_BUNDLE_ID
+ \ DOXYGEN_DOCSET_FEEDNAME
+ \ DOXYGEN_DOCSET_PUBLISHER_ID
+ \ DOXYGEN_DOCSET_PUBLISHER_NAME
+ \ DOXYGEN_DOTFILE_DIRS
+ \ DOXYGEN_DOT_CLEANUP
+ \ DOXYGEN_DOT_FONTNAME
+ \ DOXYGEN_DOT_FONTPATH
+ \ DOXYGEN_DOT_FONTSIZE
+ \ DOXYGEN_DOT_GRAPH_MAX_NODES
+ \ DOXYGEN_DOT_IMAGE_FORMAT
+ \ DOXYGEN_DOT_MULTI_TARGETS
+ \ DOXYGEN_DOT_NUM_THREADS
+ \ DOXYGEN_DOT_PATH
+ \ DOXYGEN_DOT_TRANSPARENT
+ \ DOXYGEN_DOXYFILE_ENCODING
+ \ DOXYGEN_ECLIPSE_DOC_ID
+ \ DOXYGEN_ENABLED_SECTIONS
+ \ DOXYGEN_ENABLE_PREPROCESSING
+ \ DOXYGEN_ENUM_VALUES_PER_LINE
+ \ DOXYGEN_EXAMPLE_PATH
+ \ DOXYGEN_EXAMPLE_PATTERNS
+ \ DOXYGEN_EXAMPLE_RECURSIVE
+ \ DOXYGEN_EXCLUDE
+ \ DOXYGEN_EXCLUDE_PATTERNS
+ \ DOXYGEN_EXCLUDE_SYMBOLS
+ \ DOXYGEN_EXCLUDE_SYMLINKS
+ \ DOXYGEN_EXPAND_AS_DEFINED
+ \ DOXYGEN_EXPAND_ONLY_PREDEF
+ \ DOXYGEN_EXTENSION_MAPPING
+ \ DOXYGEN_EXTERNAL_GROUPS
+ \ DOXYGEN_EXTERNAL_PAGES
+ \ DOXYGEN_EXTERNAL_SEARCH
+ \ DOXYGEN_EXTERNAL_SEARCH_ID
+ \ DOXYGEN_EXTRACT_ALL
+ \ DOXYGEN_EXTRACT_ANON_NSPACES
+ \ DOXYGEN_EXTRACT_LOCAL_CLASSES
+ \ DOXYGEN_EXTRACT_LOCAL_METHODS
+ \ DOXYGEN_EXTRACT_PACKAGE
+ \ DOXYGEN_EXTRACT_PRIVATE
+ \ DOXYGEN_EXTRACT_PRIV_VIRTUAL
+ \ DOXYGEN_EXTRACT_STATIC
+ \ DOXYGEN_EXTRA_PACKAGES
+ \ DOXYGEN_EXTRA_SEARCH_MAPPINGS
+ \ DOXYGEN_EXT_LINKS_IN_WINDOW
+ \ DOXYGEN_FILE_PATTERNS
+ \ DOXYGEN_FILE_VERSION_FILTER
+ \ DOXYGEN_FILTER_PATTERNS
+ \ DOXYGEN_FILTER_SOURCE_FILES
+ \ DOXYGEN_FILTER_SOURCE_PATTERNS
+ \ DOXYGEN_FORCE_LOCAL_INCLUDES
+ \ DOXYGEN_FORMULA_FONTSIZE
+ \ DOXYGEN_FORMULA_TRANSPARENT
+ \ DOXYGEN_FULL_PATH_NAMES
+ \ DOXYGEN_GENERATE_AUTOGEN_DEF
+ \ DOXYGEN_GENERATE_BUGLIST
+ \ DOXYGEN_GENERATE_CHI
+ \ DOXYGEN_GENERATE_DEPRECATEDLIST
+ \ DOXYGEN_GENERATE_DOCBOOK
+ \ DOXYGEN_GENERATE_DOCSET
+ \ DOXYGEN_GENERATE_ECLIPSEHELP
+ \ DOXYGEN_GENERATE_HTML
+ \ DOXYGEN_GENERATE_HTMLHELP
+ \ DOXYGEN_GENERATE_LATEX
+ \ DOXYGEN_GENERATE_LEGEND
+ \ DOXYGEN_GENERATE_MAN
+ \ DOXYGEN_GENERATE_PERLMOD
+ \ DOXYGEN_GENERATE_QHP
+ \ DOXYGEN_GENERATE_RTF
+ \ DOXYGEN_GENERATE_TAGFILE
+ \ DOXYGEN_GENERATE_TESTLIST
+ \ DOXYGEN_GENERATE_TODOLIST
+ \ DOXYGEN_GENERATE_TREEVIEW
+ \ DOXYGEN_GENERATE_XML
+ \ DOXYGEN_GRAPHICAL_HIERARCHY
+ \ DOXYGEN_GROUP_GRAPHS
+ \ DOXYGEN_GROUP_NESTED_COMPOUNDS
+ \ DOXYGEN_HAVE_DOT
+ \ DOXYGEN_HHC_LOCATION
+ \ DOXYGEN_HIDE_COMPOUND_REFERENCE
+ \ DOXYGEN_HIDE_FRIEND_COMPOUNDS
+ \ DOXYGEN_HIDE_IN_BODY_DOCS
+ \ DOXYGEN_HIDE_SCOPE_NAMES
+ \ DOXYGEN_HIDE_UNDOC_CLASSES
+ \ DOXYGEN_HIDE_UNDOC_MEMBERS
+ \ DOXYGEN_HIDE_UNDOC_RELATIONS
+ \ DOXYGEN_HTML_COLORSTYLE_GAMMA
+ \ DOXYGEN_HTML_COLORSTYLE_HUE
+ \ DOXYGEN_HTML_COLORSTYLE_SAT
+ \ DOXYGEN_HTML_DYNAMIC_MENUS
+ \ DOXYGEN_HTML_DYNAMIC_SECTIONS
+ \ DOXYGEN_HTML_EXTRA_FILES
+ \ DOXYGEN_HTML_EXTRA_STYLESHEET
+ \ DOXYGEN_HTML_FILE_EXTENSION
+ \ DOXYGEN_HTML_FOOTER
+ \ DOXYGEN_HTML_HEADER
+ \ DOXYGEN_HTML_INDEX_NUM_ENTRIES
+ \ DOXYGEN_HTML_OUTPUT
+ \ DOXYGEN_HTML_STYLESHEET
+ \ DOXYGEN_HTML_TIMESTAMP
+ \ DOXYGEN_IDL_PROPERTY_SUPPORT
+ \ DOXYGEN_IGNORE_PREFIX
+ \ DOXYGEN_IMAGE_PATH
+ \ DOXYGEN_INCLUDED_BY_GRAPH
+ \ DOXYGEN_INCLUDE_FILE_PATTERNS
+ \ DOXYGEN_INCLUDE_GRAPH
+ \ DOXYGEN_INCLUDE_PATH
+ \ DOXYGEN_INHERIT_DOCS
+ \ DOXYGEN_INLINE_GROUPED_CLASSES
+ \ DOXYGEN_INLINE_INFO
+ \ DOXYGEN_INLINE_INHERITED_MEMB
+ \ DOXYGEN_INLINE_SIMPLE_STRUCTS
+ \ DOXYGEN_INLINE_SOURCES
+ \ DOXYGEN_INPUT
+ \ DOXYGEN_INPUT_ENCODING
+ \ DOXYGEN_INPUT_FILTER
+ \ DOXYGEN_INTERACTIVE_SVG
+ \ DOXYGEN_INTERNAL_DOCS
+ \ DOXYGEN_JAVADOC_AUTOBRIEF
+ \ DOXYGEN_JAVADOC_BANNER
+ \ DOXYGEN_LATEX_BATCHMODE
+ \ DOXYGEN_LATEX_BIB_STYLE
+ \ DOXYGEN_LATEX_CMD_NAME
+ \ DOXYGEN_LATEX_EMOJI_DIRECTORY
+ \ DOXYGEN_LATEX_EXTRA_FILES
+ \ DOXYGEN_LATEX_EXTRA_STYLESHEET
+ \ DOXYGEN_LATEX_FOOTER
+ \ DOXYGEN_LATEX_HEADER
+ \ DOXYGEN_LATEX_HIDE_INDICES
+ \ DOXYGEN_LATEX_MAKEINDEX_CMD
+ \ DOXYGEN_LATEX_OUTPUT
+ \ DOXYGEN_LATEX_SOURCE_CODE
+ \ DOXYGEN_LATEX_TIMESTAMP
+ \ DOXYGEN_LAYOUT_FILE
+ \ DOXYGEN_LOOKUP_CACHE_SIZE
+ \ DOXYGEN_MACRO_EXPANSION
+ \ DOXYGEN_MAKEINDEX_CMD_NAME
+ \ DOXYGEN_MAN_EXTENSION
+ \ DOXYGEN_MAN_LINKS
+ \ DOXYGEN_MAN_OUTPUT
+ \ DOXYGEN_MAN_SUBDIR
+ \ DOXYGEN_MARKDOWN_SUPPORT
+ \ DOXYGEN_MATHJAX_CODEFILE
+ \ DOXYGEN_MATHJAX_EXTENSIONS
+ \ DOXYGEN_MATHJAX_FORMAT
+ \ DOXYGEN_MATHJAX_RELPATH
+ \ DOXYGEN_MAX_DOT_GRAPH_DEPTH
+ \ DOXYGEN_MAX_INITIALIZER_LINES
+ \ DOXYGEN_MSCFILE_DIRS
+ \ DOXYGEN_MULTILINE_CPP_IS_BRIEF
+ \ DOXYGEN_OPTIMIZE_FOR_FORTRAN
+ \ DOXYGEN_OPTIMIZE_OUTPUT_FOR_C
+ \ DOXYGEN_OPTIMIZE_OUTPUT_JAVA
+ \ DOXYGEN_OPTIMIZE_OUTPUT_SLICE
+ \ DOXYGEN_OPTIMIZE_OUTPUT_VHDL
+ \ DOXYGEN_OUTPUT_DIRECTORY
+ \ DOXYGEN_OUTPUT_LANGUAGE
+ \ DOXYGEN_OUTPUT_TEXT_DIRECTION
+ \ DOXYGEN_PAPER_TYPE
+ \ DOXYGEN_PDF_HYPERLINKS
+ \ DOXYGEN_PERLMOD_LATEX
+ \ DOXYGEN_PERLMOD_MAKEVAR_PREFIX
+ \ DOXYGEN_PERLMOD_PRETTY
+ \ DOXYGEN_PLANTUML_CFG_FILE
+ \ DOXYGEN_PLANTUML_INCLUDE_PATH
+ \ DOXYGEN_PLANTUML_JAR_PATH
+ \ DOXYGEN_PREDEFINED
+ \ DOXYGEN_PROJECT_BRIEF
+ \ DOXYGEN_PROJECT_LOGO
+ \ DOXYGEN_PROJECT_NAME
+ \ DOXYGEN_PROJECT_NUMBER
+ \ DOXYGEN_QCH_FILE
+ \ DOXYGEN_QHG_LOCATION
+ \ DOXYGEN_QHP_CUST_FILTER_ATTRS
+ \ DOXYGEN_QHP_CUST_FILTER_NAME
+ \ DOXYGEN_QHP_NAMESPACE
+ \ DOXYGEN_QHP_SECT_FILTER_ATTRS
+ \ DOXYGEN_QHP_VIRTUAL_FOLDER
+ \ DOXYGEN_QT_AUTOBRIEF
+ \ DOXYGEN_QUIET
+ \ DOXYGEN_RECURSIVE
+ \ DOXYGEN_REFERENCED_BY_RELATION
+ \ DOXYGEN_REFERENCES_LINK_SOURCE
+ \ DOXYGEN_REFERENCES_RELATION
+ \ DOXYGEN_REPEAT_BRIEF
+ \ DOXYGEN_RTF_EXTENSIONS_FILE
+ \ DOXYGEN_RTF_HYPERLINKS
+ \ DOXYGEN_RTF_OUTPUT
+ \ DOXYGEN_RTF_SOURCE_CODE
+ \ DOXYGEN_RTF_STYLESHEET_FILE
+ \ DOXYGEN_SEARCHDATA_FILE
+ \ DOXYGEN_SEARCHENGINE
+ \ DOXYGEN_SEARCHENGINE_URL
+ \ DOXYGEN_SEARCH_INCLUDES
+ \ DOXYGEN_SEPARATE_MEMBER_PAGES
+ \ DOXYGEN_SERVER_BASED_SEARCH
+ \ DOXYGEN_SHORT_NAMES
+ \ DOXYGEN_SHOW_FILES
+ \ DOXYGEN_SHOW_GROUPED_MEMB_INC
+ \ DOXYGEN_SHOW_INCLUDE_FILES
+ \ DOXYGEN_SHOW_NAMESPACES
+ \ DOXYGEN_SHOW_USED_FILES
+ \ DOXYGEN_SIP_SUPPORT
+ \ DOXYGEN_SKIP_FUNCTION_MACROS
+ \ DOXYGEN_SORT_BRIEF_DOCS
+ \ DOXYGEN_SORT_BY_SCOPE_NAME
+ \ DOXYGEN_SORT_GROUP_NAMES
+ \ DOXYGEN_SORT_MEMBERS_CTORS_1ST
+ \ DOXYGEN_SORT_MEMBER_DOCS
+ \ DOXYGEN_SOURCE_BROWSER
+ \ DOXYGEN_SOURCE_TOOLTIPS
+ \ DOXYGEN_STRICT_PROTO_MATCHING
+ \ DOXYGEN_STRIP_CODE_COMMENTS
+ \ DOXYGEN_STRIP_FROM_INC_PATH
+ \ DOXYGEN_STRIP_FROM_PATH
+ \ DOXYGEN_SUBGROUPING
+ \ DOXYGEN_TAB_SIZE
+ \ DOXYGEN_TAGFILES
+ \ DOXYGEN_TCL_SUBST
+ \ DOXYGEN_TEMPLATE_RELATIONS
+ \ DOXYGEN_TOC_EXPAND
+ \ DOXYGEN_TOC_INCLUDE_HEADINGS
+ \ DOXYGEN_TREEVIEW_WIDTH
+ \ DOXYGEN_TYPEDEF_HIDES_STRUCT
+ \ DOXYGEN_UML_LIMIT_NUM_FIELDS
+ \ DOXYGEN_UML_LOOK
+ \ DOXYGEN_USE_HTAGS
+ \ DOXYGEN_USE_MATHJAX
+ \ DOXYGEN_USE_MDFILE_AS_MAINPAGE
+ \ DOXYGEN_USE_PDFLATEX
+ \ DOXYGEN_VERBATIM_HEADERS
+ \ DOXYGEN_VERBATIM_VARS
+ \ DOXYGEN_VERSION
+ \ DOXYGEN_WARNINGS
+ \ DOXYGEN_WARN_AS_ERROR
+ \ DOXYGEN_WARN_FORMAT
+ \ DOXYGEN_WARN_IF_DOC_ERROR
+ \ DOXYGEN_WARN_IF_UNDOCUMENTED
+ \ DOXYGEN_WARN_LOGFILE
+ \ DOXYGEN_WARN_NO_PARAMDOC
+ \ DOXYGEN_XML_NS_MEMB_FILE_SCOPE
+ \ DOXYGEN_XML_OUTPUT
+ \ DOXYGEN_XML_PROGRAMLISTING
+ \ ENV
+ \ EXECUTABLE_OUTPUT_PATH
+ \ GHS-MULTI
+ \ IOS
+ \ LIBRARY_OUTPUT_PATH
+ \ MINGW
+ \ MSVC
+ \ MSVC10
+ \ MSVC11
+ \ MSVC12
+ \ MSVC14
+ \ MSVC60
+ \ MSVC70
+ \ MSVC71
+ \ MSVC80
+ \ MSVC90
+ \ MSVC_IDE
+ \ MSVC_TOOLSET_VERSION
+ \ MSVC_VERSION
+ \ MSYS
+ \ PROJECT_BINARY_DIR
+ \ PROJECT_DESCRIPTION
+ \ PROJECT_HOMEPAGE_URL
+ \ PROJECT_NAME
+ \ PROJECT_SOURCE_DIR
+ \ PROJECT_VERSION
+ \ PROJECT_VERSION_MAJOR
+ \ PROJECT_VERSION_MINOR
+ \ PROJECT_VERSION_PATCH
+ \ PROJECT_VERSION_TWEAK
+ \ UNIX
+ \ WIN32
+ \ WINCE
+ \ WINDOWS_PHONE
+ \ WINDOWS_STORE
+ \ XCODE
+ \ XCODE_VERSION
+
+syn keyword cmakeModule contained
+ \ ExternalProject
+
+syn keyword cmakeKWExternalProject contained
+ \ AWS
+ \ BINARY_DIR
+ \ BUILD_ALWAYS
+ \ BUILD_BYPRODUCTS
+ \ BUILD_COMMAND
+ \ BUILD_IN_SOURCE
+ \ CHECKOUT
+ \ CMAKE_ARGS
+ \ CMAKE_CACHE_ARGS
+ \ CMAKE_CACHE_DEFAULT_ARGS
+ \ CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY
+ \ CMAKE_TLS_CAINFO
+ \ CMAKE_TLS_VERIFY
+ \ COMMENT
+ \ CONFIGURE_COMMAND
+ \ CVS
+ \ CVSROOT
+ \ CVS_MODULE
+ \ CVS_REPOSITORY
+ \ CVS_TAG
+ \ DEPENDEES
+ \ DEPENDERS
+ \ DEPENDS
+ \ DOWNLOADED_FILE
+ \ DOWNLOAD_COMMAND
+ \ DOWNLOAD_DIR
+ \ DOWNLOAD_NAME
+ \ DOWNLOAD_NO_EXTRACT
+ \ DOWNLOAD_NO_PROGRESS
+ \ EP_BASE
+ \ EP_INDEPENDENT_STEP_TARGETS
+ \ EP_PREFIX
+ \ EP_STEP_TARGETS
+ \ EP_UPDATE_DISCONNECTED
+ \ EXCLUDE_FROM_ALL
+ \ FALSE
+ \ FORCE
+ \ GHS
+ \ GIT_CONFIG
+ \ GIT_PROGRESS
+ \ GIT_REMOTE_NAME
+ \ GIT_REMOTE_UPDATE_STRATEGY
+ \ GIT_REPOSITORY
+ \ GIT_SHALLOW
+ \ GIT_SUBMODULES
+ \ GIT_SUBMODULES_RECURSE
+ \ GIT_TAG
+ \ HG_REPOSITORY
+ \ HG_TAG
+ \ HTTP_HEADER
+ \ HTTP_PASSWORD
+ \ HTTP_USERNAME
+ \ IGNORED
+ \ INACTIVITY_TIMEOUT
+ \ INDEPENDENT_STEP_TARGETS
+ \ INSTALL_COMMAND
+ \ INSTALL_DIR
+ \ JOB_POOLS
+ \ LIST_SEPARATOR
+ \ LOG_BUILD
+ \ LOG_CONFIGURE
+ \ LOG_DIR
+ \ LOG_DOWNLOAD
+ \ LOG_INSTALL
+ \ LOG_MERGED_STDOUTERR
+ \ LOG_OUTPUT_ON_FAILURE
+ \ LOG_PATCH
+ \ LOG_TEST
+ \ LOG_UPDATE
+ \ MAKE_EXE
+ \ MULTI
+ \ NAMES
+ \ NETRC
+ \ NETRC_FILE
+ \ NOTE
+ \ NO_DEPENDS
+ \ OPTIONAL
+ \ PATCH_COMMAND
+ \ PREFIX
+ \ PROPERTY
+ \ REBASE
+ \ REBASE_CHECKOUT
+ \ REQUIRED
+ \ SOURCE_DIR
+ \ SOURCE_SUBDIR
+ \ STAMP_DIR
+ \ STEP_TARGETS
+ \ STRING
+ \ SVN_PASSWORD
+ \ SVN_REPOSITORY
+ \ SVN_REVISION
+ \ SVN_TRUST_CERT
+ \ SVN_USERNAME
+ \ TEST_AFTER_INSTALL
+ \ TEST_BEFORE_INSTALL
+ \ TEST_COMMAND
+ \ TEST_EXCLUDE_FROM_MAIN
+ \ TIMEOUT
+ \ TLS_CAINFO
+ \ TLS_VERIFY
+ \ TMP_DIR
+ \ TRUE
+ \ UPDATE_COMMAND
+ \ UPDATE_DISCONNECTED
+ \ URL
+ \ URL_HASH
+ \ URL_MD5
+ \ USES_TERMINAL_BUILD
+ \ USES_TERMINAL_CONFIGURE
+ \ USES_TERMINAL_DOWNLOAD
+ \ USES_TERMINAL_INSTALL
+ \ USES_TERMINAL_TEST
+ \ USES_TERMINAL_UPDATE
+ \ WORKING_DIRECTORY
+
+syn keyword cmakeKWadd_compile_definitions contained
+ \ COMPILE_DEFINITIONS
+ \ VAR
+
+syn keyword cmakeKWadd_compile_options contained
+ \ COMPILE_OPTIONS
+ \ SHELL
+ \ UNIX_COMMAND
+ \ WX
+
+syn keyword cmakeKWadd_custom_command contained
+ \ APPEND
+ \ ARGS
+ \ BYPRODUCTS
+ \ CC
+ \ COMMAND
+ \ COMMAND_EXPAND_LISTS
+ \ COMMENT
+ \ CROSSCOMPILING_EMULATOR
+ \ DEPENDS
+ \ DEPFILE
+ \ GENERATED
+ \ IMPLICIT_DEPENDS
+ \ INCLUDE_DIRECTORIES
+ \ JOB_POOL
+ \ JOB_POOLS
+ \ JOIN
+ \ MAIN_DEPENDENCY
+ \ NOT
+ \ OUTPUT
+ \ PATH
+ \ POST_BUILD
+ \ PRE_BUILD
+ \ PRE_LINK
+ \ SYMBOLIC
+ \ TARGET_FILE
+ \ TARGET_LINKER_FILE
+ \ TARGET_PDB_FILE
+ \ TARGET_PROPERTY
+ \ TARGET_SONAME_FILE
+ \ USES_TERMINAL
+ \ VERBATIM
+ \ WORKING_DIRECTORY
+
+syn keyword cmakeKWadd_custom_target contained
+ \ ALL
+ \ BYPRODUCTS
+ \ CC
+ \ COMMAND
+ \ COMMAND_EXPAND_LISTS
+ \ COMMENT
+ \ CROSSCOMPILING_EMULATOR
+ \ DEPENDS
+ \ GENERATED
+ \ INCLUDE_DIRECTORIES
+ \ JOB_POOL
+ \ JOB_POOLS
+ \ JOIN
+ \ PATH
+ \ SOURCES
+ \ TARGET_FILE
+ \ TARGET_LINKER_FILE
+ \ TARGET_PDB_FILE
+ \ TARGET_PROPERTY
+ \ TARGET_SONAME_FILE
+ \ USES_TERMINAL
+ \ VERBATIM
+ \ WORKING_DIRECTORY
+
+syn keyword cmakeKWadd_definitions contained
+ \ COMPILE_DEFINITIONS
+
+syn keyword cmakeKWadd_dependencies contained
+ \ DEPENDS
+ \ OBJECT_DEPENDS
+
+syn keyword cmakeKWadd_executable contained
+ \ ALIAS
+ \ ALIAS_GLOBAL
+ \ CONFIG
+ \ EXCLUDE_FROM_ALL
+ \ GLOBAL
+ \ HEADER_FILE_ONLY
+ \ IMPORTED
+ \ IMPORTED_
+ \ IMPORTED_LOCATION
+ \ IMPORTED_LOCATION_
+ \ MACOSX_BUNDLE
+ \ OUTPUT_NAME
+ \ RUNTIME_OUTPUT_DIRECTORY
+ \ TARGET
+
+syn keyword cmakeKWadd_library contained
+ \ ALIAS
+ \ ALIAS_GLOBAL
+ \ ARCHIVE_OUTPUT_DIRECTORY
+ \ CLI
+ \ CONFIG
+ \ DLL
+ \ EXCLUDE_FROM_ALL
+ \ FRAMEWORK
+ \ GLOBAL
+ \ HEADER_FILE_ONLY
+ \ IMPORTED
+ \ IMPORTED_
+ \ IMPORTED_IMPLIB
+ \ IMPORTED_IMPLIB_
+ \ IMPORTED_LOCATION
+ \ IMPORTED_LOCATION_
+ \ IMPORTED_OBJECTS
+ \ IMPORTED_OBJECTS_
+ \ INTERFACE
+ \ INTERFACE_
+ \ INTERFACE_SOURCES
+ \ LIBRARY_OUTPUT_DIRECTORY
+ \ MODULE
+ \ OBJECT
+ \ ON
+ \ OUTPUT_NAME
+ \ POSITION_INDEPENDENT_CODE
+ \ POST_BUILD
+ \ PRE_BUILD
+ \ PRE_LINK
+ \ PRIVATE
+ \ PUBLIC
+ \ RUNTIME_OUTPUT_DIRECTORY
+ \ SHARED
+ \ SOURCES
+ \ STATIC
+ \ TARGET_OBJECTS
+ \ UNKNOWN
+
+syn keyword cmakeKWadd_link_options contained
+ \ CMAKE_
+ \ CUDA_RESOLVE_DEVICE_SYMBOLS
+ \ CUDA_SEPARABLE_COMPILATION
+ \ DEVICE_LINK
+ \ GCC
+ \ GNU
+ \ HOST_LINK
+ \ LANG
+ \ LINKER
+ \ LINK_OPTIONS
+ \ SHELL
+ \ STATIC_LIBRARY_OPTIONS
+ \ UNIX_COMMAND
+ \ _LINKER_WRAPPER_FLAG
+ \ _LINKER_WRAPPER_FLAG_SEP
+
+syn keyword cmakeKWadd_subdirectory contained
+ \ EXCLUDE_FROM_ALL
+
+syn keyword cmakeKWadd_test contained
+ \ BUILD_TESTING
+ \ COMMAND
+ \ COMMAND_EXPAND_LISTS
+ \ CONFIGURATIONS
+ \ FAIL_REGULAR_EXPRESSION
+ \ NAME
+ \ OFF
+ \ PASS_REGULAR_EXPRESSION
+ \ SKIP_REGULAR_EXPRESSION
+ \ TARGET_FILE
+ \ WILL_FAIL
+ \ WORKING_DIRECTORY
+
+syn keyword cmakeKWbuild_command contained
+ \ CONFIGURATION
+ \ TARGET
+
+syn keyword cmakeKWcmake_host_system_information contained
+ \ AVAILABLE_PHYSICAL_MEMORY
+ \ AVAILABLE_VIRTUAL_MEMORY
+ \ FQDN
+ \ HAS_FPU
+ \ HAS_MMX
+ \ HAS_MMX_PLUS
+ \ HAS_SERIAL_NUMBER
+ \ HAS_SSE
+ \ HAS_SSE_FP
+ \ HAS_SSE_MMX
+ \ HOSTNAME
+ \ ID
+ \ NUMBER_OF_LOGICAL_CORES
+ \ NUMBER_OF_PHYSICAL_CORES
+ \ OS_NAME
+ \ OS_PLATFORM
+ \ OS_RELEASE
+ \ OS_VERSION
+ \ PROCESSOR_DESCRIPTION
+ \ PROCESSOR_NAME
+ \ PROCESSOR_SERIAL_NUMBER
+ \ QUERY
+ \ RESULT
+ \ TOTAL_PHYSICAL_MEMORY
+ \ TOTAL_VIRTUAL_MEMORY
+
+syn keyword cmakeKWcmake_language contained
+ \ AND
+ \ CALL
+ \ CANCEL_CALL
+ \ CODE
+ \ DEFER
+ \ DIRECTORY
+ \ EVAL
+ \ FALSE
+ \ GET_CALL_IDS
+ \ ID
+ \ ID_VAR
+ \ OR
+ \ STATUS
+ \ TRUE
+ \ WRITE
+
+syn keyword cmakeKWcmake_minimum_required contained
+ \ FATAL_ERROR
+ \ VERSION
+
+syn keyword cmakeKWcmake_parse_arguments contained
+ \ ARGN
+ \ CONFIGURATIONS
+ \ DESTINATION
+ \ FALSE
+ \ FAST
+ \ FILES
+ \ MY_INSTALL
+ \ MY_INSTALL_CONFIGURATIONS
+ \ MY_INSTALL_DESTINATION
+ \ MY_INSTALL_FAST
+ \ MY_INSTALL_KEYWORDS_MISSING_VALUES
+ \ MY_INSTALL_OPTIONAL
+ \ MY_INSTALL_RENAME
+ \ MY_INSTALL_TARGETS
+ \ MY_INSTALL_UNPARSED_ARGUMENTS
+ \ OPTIONAL
+ \ PARSE_ARGV
+ \ RENAME
+ \ TARGETS
+ \ TRUE
+ \ UNDEFINED
+ \ _KEYWORDS_MISSING_VALUES
+ \ _UNPARSED_ARGUMENTS
+
+syn keyword cmakeKWcmake_path contained
+ \ ABSOLUTE_PATH
+ \ AND
+ \ APPEND
+ \ BASE_DIRECTORY
+ \ CMAKE_PATH
+ \ COMPARE
+ \ CONCAT
+ \ CONVERT
+ \ ELSEIF
+ \ ENDIF
+ \ EXTENSION
+ \ EXTENSION_DEF
+ \ FALSE
+ \ FILENAME_DEF
+ \ GET
+ \ GET_EXTENSION
+ \ GET_FILENAME
+ \ GET_PARENT_PATH
+ \ GET_RELATIVE_PATH
+ \ GET_ROOT_DIRECTORY
+ \ GET_ROOT_NAME
+ \ GET_ROOT_PATH
+ \ GET_STEM
+ \ HASH
+ \ HAS_EXTENSION
+ \ HAS_FILENAME
+ \ HAS_PARENT_PATH
+ \ HAS_RELATIVE_PATH
+ \ HAS_ROOT_DIRECTORY
+ \ HAS_ROOT_NAME
+ \ HAS_ROOT_PATH
+ \ HAS_STEM
+ \ IF
+ \ IS_ABSOLUTE
+ \ IS_PREFIX
+ \ IS_RELATIVE
+ \ LAST_ONLY
+ \ MATCHES
+ \ NATIVE_PATH
+ \ NORMALIZE
+ \ NORMAL_PATH
+ \ NOT
+ \ NOT_EQUAL
+ \ OP
+ \ OS
+ \ OUTPUT_VARIABLE
+ \ PARENT_PATH
+ \ PROXIMATE_PATH
+ \ REAL_PATH
+ \ RELATIVE_PATH
+ \ REMOVE_EXTENSION
+ \ REMOVE_FILENAME
+ \ REPLACE_EXTENSION
+ \ REPLACE_FILENAME
+ \ RETURN
+ \ ROOT_DIRECTORY
+ \ ROOT_NAME
+ \ ROOT_PATH
+ \ STEM
+ \ STREQUAL
+ \ TO_CMAKE_PATH_LIST
+ \ TO_NATIVE_PATH_LIST
+ \ TRUE
+ \ XOR
+
+syn keyword cmakeKWcmake_policy contained
+ \ CMAKE_POLICY_DEFAULT_CMP
+ \ CMP
+ \ GET
+ \ NNNN
+ \ NO_POLICY_SCOPE
+ \ OLD
+ \ POP
+ \ PUSH
+ \ SET
+ \ VERSION
+
+syn keyword cmakeKWconfigure_file contained
+ \ COPYONLY
+ \ CRLF
+ \ DOS
+ \ ESCAPE_QUOTES
+ \ FILE_PERMISSIONS
+ \ FOO_ENABLE
+ \ FOO_STRING
+ \ LF
+ \ NEWLINE_STYLE
+ \ NO_SOURCE_PERMISSIONS
+ \ USE_SOURCE_PERMISSIONS
+ \ VAR
+
+syn keyword cmakeKWcreate_test_sourcelist contained
+ \ CMAKE_TESTDRIVER_AFTER_TESTMAIN
+ \ CMAKE_TESTDRIVER_BEFORE_TESTMAIN
+ \ EXTRA_INCLUDE
+ \ FUNCTION
+
+syn keyword cmakeKWctest_build contained
+ \ ALL_BUILD
+ \ APPEND
+ \ BUILD
+ \ CAPTURE_CMAKE_ERROR
+ \ CONFIGURATION
+ \ CTEST_BUILD_CONFIGURATION
+ \ CTEST_BUILD_FLAGS
+ \ CTEST_BUILD_TARGET
+ \ FLAGS
+ \ NUMBER_ERRORS
+ \ NUMBER_WARNINGS
+ \ QUIET
+ \ RETURN_VALUE
+ \ TARGET
+
+syn keyword cmakeKWctest_configure contained
+ \ APPEND
+ \ BUILD
+ \ CAPTURE_CMAKE_ERROR
+ \ OPTIONS
+ \ QUIET
+ \ RETURN_VALUE
+ \ SOURCE
+
+syn keyword cmakeKWctest_coverage contained
+ \ APPEND
+ \ BUILD
+ \ CAPTURE_CMAKE_ERROR
+ \ LABELS
+ \ QUIET
+ \ RETURN_VALUE
+
+syn keyword cmakeKWctest_memcheck contained
+ \ APPEND
+ \ BUILD
+ \ DEFECT_COUNT
+ \ EXCLUDE
+ \ EXCLUDE_FIXTURE
+ \ EXCLUDE_FIXTURE_CLEANUP
+ \ EXCLUDE_FIXTURE_SETUP
+ \ EXCLUDE_LABEL
+ \ INCLUDE
+ \ INCLUDE_LABEL
+ \ OFF
+ \ ON
+ \ PARALLEL_LEVEL
+ \ QUIET
+ \ RETURN_VALUE
+ \ SCHEDULE_RANDOM
+ \ START
+ \ STOP_TIME
+ \ STRIDE
+ \ TEST_LOAD
+
+syn keyword cmakeKWctest_run_script contained
+ \ NEW_PROCESS
+ \ RETURN_VALUE
+
+syn keyword cmakeKWctest_start contained
+ \ APPEND
+ \ GROUP
+ \ QUIET
+ \ TAG
+ \ TRACK
+
+syn keyword cmakeKWctest_submit contained
+ \ API
+ \ BUILD_ID
+ \ CAPTURE_CMAKE_ERROR
+ \ CDASH_UPLOAD
+ \ CDASH_UPLOAD_TYPE
+ \ CTEST_EXTRA_SUBMIT_FILES
+ \ CTEST_NOTES_FILES
+ \ FILES
+ \ HTTPHEADER
+ \ PARTS
+ \ QUIET
+ \ RETRY_COUNT
+ \ RETRY_DELAY
+ \ RETURN_VALUE
+ \ SUBMIT_URL
+
+syn keyword cmakeKWctest_test contained
+ \ AFTER_TIMEOUT
+ \ APPEND
+ \ BUILD
+ \ CAPTURE_CMAKE_ERROR
+ \ CPU
+ \ EXCLUDE
+ \ EXCLUDE_FIXTURE
+ \ EXCLUDE_FIXTURE_CLEANUP
+ \ EXCLUDE_FIXTURE_SETUP
+ \ EXCLUDE_LABEL
+ \ INCLUDE
+ \ INCLUDE_LABEL
+ \ OFF
+ \ ON
+ \ PARALLEL_LEVEL
+ \ QUIET
+ \ REPEAT
+ \ RESOURCE_SPEC_FILE
+ \ RETURN_VALUE
+ \ SCHEDULE_RANDOM
+ \ START
+ \ STOP_ON_FAILURE
+ \ STOP_TIME
+ \ STRIDE
+ \ TEST_LOAD
+ \ UNTIL_FAIL
+ \ UNTIL_PASS
+
+syn keyword cmakeKWctest_update contained
+ \ CAPTURE_CMAKE_ERROR
+ \ QUIET
+ \ RETURN_VALUE
+ \ SOURCE
+
+syn keyword cmakeKWctest_upload contained
+ \ CAPTURE_CMAKE_ERROR
+ \ FILES
+ \ QUIET
+
+syn keyword cmakeKWdefine_property contained
+ \ APPEND
+ \ APPEND_STRING
+ \ BRIEF_DOCS
+ \ CACHED_VARIABLE
+ \ DIRECTORY
+ \ FULL_DOCS
+ \ GLOBAL
+ \ INHERITED
+ \ PROPERTY
+ \ SOURCE
+ \ TARGET
+ \ TEST
+ \ VARIABLE
+
+syn keyword cmakeKWdoxygen_add_docs contained
+ \ ALL
+ \ COMMENT
+ \ USE_STAMP_FILE
+ \ WORKING_DIRECTORY
+
+syn keyword cmakeKWenable_language contained
+ \ ASM
+ \ CUDA
+ \ ISPC
+ \ OBJC
+ \ OBJCXX
+ \ OPTIONAL
+
+syn keyword cmakeKWenable_testing contained
+ \ BUILD_TESTING
+
+syn keyword cmakeKWexec_program contained
+ \ ARGS
+ \ OUTPUT_VARIABLE
+ \ RETURN_VALUE
+
+syn keyword cmakeKWexecute_process contained
+ \ ANSI
+ \ ANY
+ \ AUTO
+ \ COMMAND
+ \ COMMAND_ECHO
+ \ COMMAND_ERROR_IS_FATAL
+ \ ECHO_ERROR_VARIABLE
+ \ ECHO_OUTPUT_VARIABLE
+ \ ENCODING
+ \ ERROR_FILE
+ \ ERROR_QUIET
+ \ ERROR_STRIP_TRAILING_WHITESPACE
+ \ ERROR_VARIABLE
+ \ INPUT_FILE
+ \ LAST
+ \ NONE
+ \ OEM
+ \ OUTPUT_FILE
+ \ OUTPUT_QUIET
+ \ OUTPUT_STRIP_TRAILING_WHITESPACE
+ \ OUTPUT_VARIABLE
+ \ RESULTS_VARIABLE
+ \ RESULT_VARIABLE
+ \ RFC
+ \ STDERR
+ \ STDOUT
+ \ TIMEOUT
+ \ UTF
+ \ VERBATIM
+ \ WORKING_DIRECTORY
+
+syn keyword cmakeKWexport contained
+ \ ANDROID_MK
+ \ APPEND
+ \ CONFIG
+ \ EXPORT
+ \ EXPORT_LINK_INTERFACE_LIBRARIES
+ \ FILE
+ \ IMPORTED
+ \ IMPORTED_
+ \ NAMESPACE
+ \ NDK
+ \ OLD
+ \ PACKAGE
+ \ TARGETS
+
+syn keyword cmakeKWexport_library_dependencies contained
+ \ APPEND
+ \ EXPORT
+ \ INCLUDE
+ \ LINK_INTERFACE_LIBRARIES
+ \ SET
+
+syn keyword cmakeKWfile contained
+ \ ALGO
+ \ APPEND
+ \ ARCHIVE_CREATE
+ \ ARCHIVE_EXTRACT
+ \ ASCII
+ \ BASE_DIRECTORY
+ \ BUNDLE_EXECUTABLE
+ \ CHMOD
+ \ CHMOD_RECURSE
+ \ CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND
+ \ CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM
+ \ CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL
+ \ CMAKE_OBJDUMP
+ \ CMAKE_TLS_CAINFO
+ \ CMAKE_TLS_VERIFY
+ \ CODE
+ \ COMPILE_FEATURES
+ \ COMPRESSION
+ \ COMPRESSION_LEVEL
+ \ CONDITION
+ \ CONFIGURE
+ \ CONFIGURE_DEPENDS
+ \ CONFLICTING_DEPENDENCIES_PREFIX
+ \ CONTENT
+ \ CONVERT
+ \ COPY
+ \ COPY_ON_ERROR
+ \ CREATE_LINK
+ \ CRLF
+ \ DESTINATION
+ \ DIRECTORIES
+ \ DIRECTORY_PERMISSIONS
+ \ DLL
+ \ DOS
+ \ DOWNLOAD
+ \ ENCODING
+ \ ESCAPE_QUOTES
+ \ EXECUTABLES
+ \ EXPECTED_HASH
+ \ FILES_MATCHING
+ \ FILE_PERMISSIONS
+ \ FOLLOW_SYMLINKS
+ \ FOLLOW_SYMLINK_CHAIN
+ \ FORMAT
+ \ FUNCTION
+ \ GENERATE
+ \ GET_RUNTIME_DEPENDENCIES
+ \ GLOB
+ \ GLOB_RECURSE
+ \ GROUP_EXECUTE
+ \ GROUP_READ
+ \ GROUP_WRITE
+ \ GUARD
+ \ HASH
+ \ HEX
+ \ HTTPHEADER
+ \ IGNORED
+ \ INACTIVITY_TIMEOUT
+ \ INPUT
+ \ INSTALL
+ \ IS_ABSOLUTE
+ \ LENGTH_MAXIMUM
+ \ LENGTH_MINIMUM
+ \ LF
+ \ LIBRARIES
+ \ LIMIT
+ \ LIMIT_COUNT
+ \ LIMIT_INPUT
+ \ LIMIT_OUTPUT
+ \ LIST_DIRECTORIES
+ \ LIST_ONLY
+ \ LOCK
+ \ LOG
+ \ MAKE_DIRECTORY
+ \ MODULES
+ \ MTIME
+ \ MYLIBRARY
+ \ NETRC
+ \ NETRC_FILE
+ \ NEWLINE_CONSUME
+ \ NEWLINE_STYLE
+ \ NOT
+ \ NO_HEX_CONVERSION
+ \ NO_SOURCE_PERMISSIONS
+ \ OFFSET
+ \ ONLY
+ \ OPTIONAL
+ \ OUTPUT
+ \ OWNER_EXECUTE
+ \ OWNER_READ
+ \ OWNER_WRITE
+ \ PATHS
+ \ PATTERN
+ \ PATTERNS
+ \ PERMISSIONS
+ \ POST_EXCLUDE_REGEXES
+ \ POST_INCLUDE_REGEXES
+ \ PRE_EXCLUDE_REGEXES
+ \ PRE_INCLUDE_REGEXES
+ \ PROCESS
+ \ READ
+ \ READ_SYMLINK
+ \ REAL_PATH
+ \ REGEX
+ \ RELATIVE_PATH
+ \ RELEASE
+ \ REMOVE
+ \ REMOVE_RECURSE
+ \ RENAME
+ \ REQUIRED
+ \ RESOLVED_DEPENDENCIES_VAR
+ \ RESULT
+ \ RESULT_VARIABLE
+ \ RPATH
+ \ RUNPATH
+ \ SCRIPT
+ \ SHARED
+ \ SHOW_PROGRESS
+ \ SIZE
+ \ SSL
+ \ STATIC
+ \ STATUS
+ \ STRINGS
+ \ SYMBOLIC
+ \ TARGET
+ \ TARGET_PROPERTY
+ \ TIMESTAMP
+ \ TLS_CAINFO
+ \ TLS_VERIFY
+ \ TOUCH
+ \ TOUCH_NOCREATE
+ \ TO_CMAKE_PATH
+ \ TO_CMAKE_PATH_LIST
+ \ TO_NATIVE_PATH
+ \ TO_NATIVE_PATH_LIST
+ \ UNRESOLVED_DEPENDENCIES_VAR
+ \ UPLOAD
+ \ URL
+ \ USERPWD
+ \ USE_SOURCE_PERMISSIONS
+ \ UTC
+ \ UTF
+ \ VERBOSE
+ \ WORLD_EXECUTE
+ \ WORLD_READ
+ \ WORLD_WRITE
+ \ WRITE
+ \ XZ
+ \ _FILENAMES
+
+syn keyword cmakeKWfind_file contained
+ \ CMAKE_FIND_ROOT_PATH_BOTH
+ \ DOC
+ \ DVAR
+ \ FALSE
+ \ HINTS
+ \ INCLUDE
+ \ NAMES
+ \ NO_CMAKE_ENVIRONMENT_PATH
+ \ NO_CMAKE_FIND_ROOT_PATH
+ \ NO_CMAKE_PATH
+ \ NO_CMAKE_SYSTEM_PATH
+ \ NO_DEFAULT_PATH
+ \ NO_PACKAGE_ROOT_PATH
+ \ NO_SYSTEM_ENVIRONMENT_PATH
+ \ ONLY_CMAKE_FIND_ROOT_PATH
+ \ PATHS
+ \ PATH_SUFFIXES
+ \ REQUIRED
+ \ VAR
+
+syn keyword cmakeKWfind_library contained
+ \ CMAKE_FIND_ROOT_PATH_BOTH
+ \ DOC
+ \ DVAR
+ \ FALSE
+ \ HINTS
+ \ INCLUDE
+ \ NAMES
+ \ NAMES_PER_DIR
+ \ NO_CMAKE_ENVIRONMENT_PATH
+ \ NO_CMAKE_FIND_ROOT_PATH
+ \ NO_CMAKE_PATH
+ \ NO_CMAKE_SYSTEM_PATH
+ \ NO_DEFAULT_PATH
+ \ NO_PACKAGE_ROOT_PATH
+ \ NO_SYSTEM_ENVIRONMENT_PATH
+ \ ONLY_CMAKE_FIND_ROOT_PATH
+ \ PATHS
+ \ PATH_SUFFIXES
+ \ REQUIRED
+ \ VAR
+
+syn keyword cmakeKWfind_package contained
+ \ ABI
+ \ BUNDLE
+ \ CMAKE_DISABLE_FIND_PACKAGE_
+ \ CMAKE_FIND_ROOT_PATH_BOTH
+ \ COMPONENTS
+ \ CONFIG
+ \ CONFIGS
+ \ DEC
+ \ DVAR
+ \ EXACT
+ \ EXCLUDE
+ \ FALSE
+ \ FIND_PACKAGE_VERSION_FORMAT
+ \ FRAMEWORK
+ \ HINTS
+ \ INCLUDE
+ \ MODULE
+ \ NAMES
+ \ NATURAL
+ \ NO_CMAKE_BUILDS_PATH
+ \ NO_CMAKE_ENVIRONMENT_PATH
+ \ NO_CMAKE_FIND_ROOT_PATH
+ \ NO_CMAKE_PACKAGE_REGISTRY
+ \ NO_CMAKE_PATH
+ \ NO_CMAKE_SYSTEM_PACKAGE_REGISTRY
+ \ NO_CMAKE_SYSTEM_PATH
+ \ NO_DEFAULT_PATH
+ \ NO_MODULE
+ \ NO_PACKAGE_ROOT_PATH
+ \ NO_POLICY_SCOPE
+ \ NO_SYSTEM_ENVIRONMENT_PATH
+ \ ONLY_CMAKE_FIND_ROOT_PATH
+ \ OPTIONAL_COMPONENTS
+ \ PACKAGE_FIND_NAME
+ \ PACKAGE_FIND_VERSION
+ \ PACKAGE_FIND_VERSION_COMPLETE
+ \ PACKAGE_FIND_VERSION_COUNT
+ \ PACKAGE_FIND_VERSION_MAJOR
+ \ PACKAGE_FIND_VERSION_MAX
+ \ PACKAGE_FIND_VERSION_MAX_COUNT
+ \ PACKAGE_FIND_VERSION_MAX_MAJOR
+ \ PACKAGE_FIND_VERSION_MAX_MINOR
+ \ PACKAGE_FIND_VERSION_MAX_PATCH
+ \ PACKAGE_FIND_VERSION_MAX_TWEAK
+ \ PACKAGE_FIND_VERSION_MINOR
+ \ PACKAGE_FIND_VERSION_MIN_COUNT
+ \ PACKAGE_FIND_VERSION_MIN_MAJOR
+ \ PACKAGE_FIND_VERSION_MIN_MINOR
+ \ PACKAGE_FIND_VERSION_MIN_PATCH
+ \ PACKAGE_FIND_VERSION_MIN_TWEAK
+ \ PACKAGE_FIND_VERSION_PATCH
+ \ PACKAGE_FIND_VERSION_RANGE
+ \ PACKAGE_FIND_VERSION_RANGE_MAX
+ \ PACKAGE_FIND_VERSION_RANGE_MIN
+ \ PACKAGE_FIND_VERSION_TWEAK
+ \ PACKAGE_VERSION_COMPATIBLE
+ \ PACKAGE_VERSION_EXACT
+ \ PACKAGE_VERSION_UNSUITABLE
+ \ PATHS
+ \ PATH_SUFFIXES
+ \ QUIET
+ \ REQUIRED
+ \ SET
+ \ TRUE
+ \ _CONFIG
+ \ _CONSIDERED_CONFIGS
+ \ _CONSIDERED_VERSIONS
+ \ _DIR
+ \ _FIND_COMPONENTS
+ \ _FIND_QUIETLY
+ \ _FIND_REQUIRED
+ \ _FIND_REQUIRED_
+ \ _FIND_VERSION_EXACT
+ \ _FOUND
+
+syn keyword cmakeKWfind_path contained
+ \ CMAKE_FIND_ROOT_PATH_BOTH
+ \ DOC
+ \ DVAR
+ \ FALSE
+ \ HINTS
+ \ INCLUDE
+ \ NAMES
+ \ NO_CMAKE_ENVIRONMENT_PATH
+ \ NO_CMAKE_FIND_ROOT_PATH
+ \ NO_CMAKE_PATH
+ \ NO_CMAKE_SYSTEM_PATH
+ \ NO_DEFAULT_PATH
+ \ NO_PACKAGE_ROOT_PATH
+ \ NO_SYSTEM_ENVIRONMENT_PATH
+ \ ONLY_CMAKE_FIND_ROOT_PATH
+ \ PATHS
+ \ PATH_SUFFIXES
+ \ REQUIRED
+ \ VAR
+
+syn keyword cmakeKWfind_program contained
+ \ CMAKE_FIND_ROOT_PATH_BOTH
+ \ DOC
+ \ DVAR
+ \ FALSE
+ \ HINTS
+ \ NAMES
+ \ NAMES_PER_DIR
+ \ NO_CMAKE_ENVIRONMENT_PATH
+ \ NO_CMAKE_FIND_ROOT_PATH
+ \ NO_CMAKE_PATH
+ \ NO_CMAKE_SYSTEM_PATH
+ \ NO_DEFAULT_PATH
+ \ NO_PACKAGE_ROOT_PATH
+ \ NO_SYSTEM_ENVIRONMENT_PATH
+ \ ONLY_CMAKE_FIND_ROOT_PATH
+ \ PATHS
+ \ PATH_SUFFIXES
+ \ REQUIRED
+ \ VAR
+
+syn keyword cmakeKWfltk_wrap_ui contained
+ \ FLTK
+
+syn keyword cmakeKWforeach contained
+ \ APPEND
+ \ IN
+ \ ITEMS
+ \ LISTS
+ \ RANGE
+ \ STATUS
+ \ ZIP_LISTS
+
+syn keyword cmakeKWfunction contained
+ \ ARGC
+ \ ARGN
+ \ ARGV
+ \ CALL
+ \ FOO
+ \ PARENT_SCOPE
+
+syn keyword cmakeKWget_cmake_property contained
+ \ COMPONENTS
+ \ GLOBAL
+ \ MACROS
+ \ VARIABLES
+
+syn keyword cmakeKWget_directory_property contained
+ \ DEFINITION
+ \ DIRECTORY
+ \ INHERITED
+
+syn keyword cmakeKWget_filename_component contained
+ \ ABSOLUTE
+ \ BASE_DIR
+ \ DIRECTORY
+ \ EXT
+ \ LAST_EXT
+ \ NAME
+ \ NAME_WE
+ \ NAME_WLE
+ \ PATH
+ \ PROGRAM
+ \ PROGRAM_ARGS
+ \ REALPATH
+ \ REAL_PATH
+
+syn keyword cmakeKWget_property contained
+ \ BRIEF_DOCS
+ \ DEFINED
+ \ DIRECTORY
+ \ FULL_DOCS
+ \ GLOBAL
+ \ INSTALL
+ \ PROPERTY
+ \ SET
+ \ SOURCE
+ \ TARGET
+ \ TARGET_DIRECTORY
+ \ TEST
+ \ VARIABLE
+
+syn keyword cmakeKWget_source_file_property contained
+ \ DIRECTORY
+ \ INHERITED
+ \ LOCATION
+ \ TARGET_DIRECTORY
+
+syn keyword cmakeKWget_target_property contained
+ \ INHERITED
+ \ VAR
+
+syn keyword cmakeKWget_test_property contained
+ \ INHERITED
+ \ VAR
+
+syn keyword cmakeKWif contained
+ \ CMAKE_MATCH_
+ \ CMP
+ \ COMMAND
+ \ DEFINED
+ \ EQUAL
+ \ EXISTS
+ \ FALSE
+ \ GREATER
+ \ GREATER_EQUAL
+ \ IGNORE
+ \ IN_LIST
+ \ IS_ABSOLUTE
+ \ IS_DIRECTORY
+ \ IS_NEWER_THAN
+ \ IS_SYMLINK
+ \ LESS
+ \ LESS_EQUAL
+ \ MATCHES
+ \ NNNN
+ \ NOT
+ \ OFF
+ \ OR
+ \ POLICY
+ \ STREQUAL
+ \ STRGREATER
+ \ STRGREATER_EQUAL
+ \ STRLESS
+ \ STRLESS_EQUAL
+ \ TARGET
+ \ TEST
+ \ TRUE
+ \ VERSION_EQUAL
+ \ VERSION_GREATER
+ \ VERSION_GREATER_EQUAL
+ \ VERSION_LESS
+ \ VERSION_LESS_EQUAL
+ \ YES
+
+syn keyword cmakeKWinclude contained
+ \ NO_POLICY_SCOPE
+ \ OPTIONAL
+ \ RESULT_VARIABLE
+
+syn keyword cmakeKWinclude_directories contained
+ \ AFTER
+ \ BEFORE
+ \ INCLUDE_DIRECTORIES
+ \ ON
+ \ SYSTEM
+
+syn keyword cmakeKWinclude_external_msproject contained
+ \ GUID
+ \ MAP_IMPORTED_CONFIG_
+ \ PLATFORM
+ \ TYPE
+ \ WIX
+
+syn keyword cmakeKWinclude_guard contained
+ \ DIRECTORY
+ \ GLOBAL
+ \ TRUE
+ \ __CURRENT_FILE_VAR__
+
+syn keyword cmakeKWinstall contained
+ \ AFTER
+ \ AIX
+ \ APT
+ \ ARCHIVE
+ \ BEFORE
+ \ BUILD_TYPE
+ \ BUNDLE
+ \ CMAKE_INSTALL_BINDIR
+ \ CMAKE_INSTALL_DATADIR
+ \ CMAKE_INSTALL_DATAROOTDIR
+ \ CMAKE_INSTALL_DOCDIR
+ \ CMAKE_INSTALL_INCLUDEDIR
+ \ CMAKE_INSTALL_INFODIR
+ \ CMAKE_INSTALL_LIBDIR
+ \ CMAKE_INSTALL_LOCALEDIR
+ \ CMAKE_INSTALL_LOCALSTATEDIR
+ \ CMAKE_INSTALL_MANDIR
+ \ CMAKE_INSTALL_RUNSTATEDIR
+ \ CMAKE_INSTALL_SBINDIR
+ \ CMAKE_INSTALL_SHARESTATEDIR
+ \ CMAKE_INSTALL_SYSCONFDIR
+ \ CODE
+ \ COMPONENT
+ \ CONFIGURATIONS
+ \ CVS
+ \ DATA
+ \ DATAROOT
+ \ DBUILD_TYPE
+ \ DCOMPONENT
+ \ DESTDIR
+ \ DESTINATION
+ \ DIRECTORY
+ \ DIRECTORY_PERMISSIONS
+ \ DLL
+ \ DOC
+ \ ENABLE_EXPORTS
+ \ EXCLUDE_FROM_ALL
+ \ EXPORT
+ \ EXPORT_ANDROID_MK
+ \ EXPORT_LINK_INTERFACE_LIBRARIES
+ \ EXPORT_NAME
+ \ FILES
+ \ FILES_MATCHING
+ \ FILE_PERMISSIONS
+ \ FRAMEWORK
+ \ GROUP_EXECUTE
+ \ GROUP_READ
+ \ GROUP_WRITE
+ \ IMPORTED_
+ \ INCLUDES
+ \ INFO
+ \ INSTALL_PREFIX
+ \ INTERFACE_INCLUDE_DIRECTORIES
+ \ LIBRARY
+ \ LOCALE
+ \ LOCALSTATE
+ \ MACOSX_BUNDLE
+ \ MAN
+ \ MESSAGE_NEVER
+ \ NAMELINK_COMPONENT
+ \ NAMELINK_ONLY
+ \ NAMELINK_SKIP
+ \ NAMESPACE
+ \ NDK
+ \ OBJECTS
+ \ OPTIONAL
+ \ OWNER_EXECUTE
+ \ OWNER_READ
+ \ OWNER_WRITE
+ \ PATTERN
+ \ PERMISSIONS
+ \ POST_INSTALL_SCRIPT
+ \ PRE_INSTALL_SCRIPT
+ \ PRIVATE_HEADER
+ \ PROGRAMS
+ \ PROPERTIES
+ \ PUBLIC_HEADER
+ \ REGEX
+ \ RENAME
+ \ RESOURCE
+ \ RPM
+ \ RUNSTATE
+ \ RUNTIME
+ \ SBIN
+ \ SCRIPT
+ \ SETGID
+ \ SETUID
+ \ SHAREDSTATE
+ \ SOVERSION
+ \ STATIC
+ \ SYSCONF
+ \ TARGETS
+ \ TRUE
+ \ TYPE
+ \ USE_SOURCE_PERMISSIONS
+ \ VERSION
+ \ WORLD_EXECUTE
+ \ WORLD_READ
+ \ WORLD_WRITE
+
+syn keyword cmakeKWinstall_files contained
+ \ FILES
+ \ GLOB
+
+syn keyword cmakeKWinstall_programs contained
+ \ FILES
+ \ GLOB
+ \ PROGRAMS
+ \ TARGETS
+
+syn keyword cmakeKWinstall_targets contained
+ \ DLL
+ \ RUNTIME_DIRECTORY
+
+syn keyword cmakeKWlink_directories contained
+ \ AFTER
+ \ BEFORE
+ \ LINK_DIRECTORIES
+ \ ON
+ \ ORIGIN
+ \ RPATH
+
+syn keyword cmakeKWlist contained
+ \ ACTION
+ \ APPEND
+ \ ASCENDING
+ \ CASE
+ \ COMPARE
+ \ DESCENDING
+ \ EXCLUDE
+ \ FILE_BASENAME
+ \ FILTER
+ \ FIND
+ \ GENEX_STRIP
+ \ GET
+ \ INCLUDE
+ \ INSENSITIVE
+ \ INSERT
+ \ INTERNAL
+ \ JOIN
+ \ LENGTH
+ \ NATURAL
+ \ ORDER
+ \ OUTPUT_VARIABLE
+ \ PARENT_SCOPE
+ \ POP_BACK
+ \ POP_FRONT
+ \ PREPEND
+ \ REGEX
+ \ REMOVE_AT
+ \ REMOVE_DUPLICATES
+ \ REMOVE_ITEM
+ \ REPLACE
+ \ REVERSE
+ \ SELECTOR
+ \ SENSITIVE
+ \ SORT
+ \ STRING
+ \ STRIP
+ \ SUBLIST
+ \ TOLOWER
+ \ TOUPPER
+ \ TRANSFORM
+
+syn keyword cmakeKWload_cache contained
+ \ EXCLUDE
+ \ INCLUDE_INTERNALS
+ \ READ_WITH_PREFIX
+
+syn keyword cmakeKWload_command contained
+ \ CMAKE_LOADED_COMMAND_
+ \ COMMAND_NAME
+
+syn keyword cmakeKWmacro contained
+ \ ARGC
+ \ ARGN
+ \ ARGV
+ \ CALL
+ \ DEFINED
+ \ FOO
+ \ GREATER
+ \ LISTS
+ \ NOT
+
+syn keyword cmakeKWmark_as_advanced contained
+ \ CLEAR
+ \ FORCE
+
+syn keyword cmakeKWmath contained
+ \ EXPR
+ \ HEXADECIMAL
+ \ OUTPUT_FORMAT
+
+syn keyword cmakeKWmessage contained
+ \ APPEND
+ \ AUTHOR_WARNING
+ \ CHECK_
+ \ CHECK_FAIL
+ \ CHECK_PASS
+ \ CHECK_START
+ \ DEBUG
+ \ DEPRECATION
+ \ FATAL_ERROR
+ \ GUI
+ \ NOTICE
+ \ POP_BACK
+ \ SEND_ERROR
+ \ STATUS
+ \ TRACE
+ \ VERBOSE
+ \ WARNING
+
+syn keyword cmakeKWoption contained
+ \ OFF
+ \ ON
+
+syn keyword cmakeKWproject contained
+ \ ASM
+ \ CMAKE_PROJECT_
+ \ CUDA
+ \ DESCRIPTION
+ \ HOMEPAGE_URL
+ \ ISPC
+ \ LANGUAGES
+ \ NAME
+ \ NONE
+ \ OBJC
+ \ OBJCXX
+ \ PROJECT
+ \ VERSION
+ \ _BINARY_DIR
+ \ _DESCRIPTION
+ \ _HOMEPAGE_URL
+ \ _INCLUDE_BEFORE
+ \ _SOURCE_DIR
+ \ _VERSION
+ \ _VERSION_MAJOR
+ \ _VERSION_MINOR
+ \ _VERSION_PATCH
+ \ _VERSION_TWEAK
+
+syn keyword cmakeKWqt_wrap_cpp contained
+ \ AUTOMOC
+
+syn keyword cmakeKWqt_wrap_ui contained
+ \ AUTOUIC
+
+syn keyword cmakeKWremove contained
+ \ VALUE
+ \ VAR
+
+syn keyword cmakeKWreturn contained
+ \ DEFER
+
+syn keyword cmakeKWseparate_arguments contained
+ \ MSDN
+ \ NATIVE_COMMAND
+ \ PROGRAM
+ \ SEPARATE_ARGS
+ \ UNIX_COMMAND
+ \ WINDOWS_COMMAND
+
+syn keyword cmakeKWset contained
+ \ BOOL
+ \ FILEPATH
+ \ FORCE
+ \ INTERNAL
+ \ OFF
+ \ ON
+ \ PARENT_SCOPE
+ \ STRING
+ \ STRINGS
+
+syn keyword cmakeKWset_directory_properties contained
+ \ DIRECTORY
+ \ PROPERTIES
+
+syn keyword cmakeKWset_property contained
+ \ APPEND
+ \ APPEND_STRING
+ \ DIRECTORY
+ \ GLOBAL
+ \ INHERITED
+ \ INSTALL
+ \ PROPERTY
+ \ SOURCE
+ \ TARGET
+ \ TARGET_DIRECTORY
+ \ TEST
+ \ WIX
+
+syn keyword cmakeKWset_source_files_properties contained
+ \ DIRECTORY
+ \ PROPERTIES
+ \ SOURCE
+ \ TARGET_DIRECTORY
+
+syn keyword cmakeKWset_target_properties contained
+ \ PROPERTIES
+ \ TARGET
+
+syn keyword cmakeKWset_tests_properties contained
+ \ PROPERTIES
+ \ TEST
+
+syn keyword cmakeKWsite_name contained
+ \ HOSTNAME
+
+syn keyword cmakeKWsource_group contained
+ \ FILES
+ \ PREFIX
+ \ REGULAR_EXPRESSION
+ \ TREE
+
+syn keyword cmakeKWstring contained
+ \ ALPHABET
+ \ APPEND
+ \ ARRAY
+ \ ASCII
+ \ BOOLEAN
+ \ CMAKE_MATCH_
+ \ COMPARE
+ \ CONCAT
+ \ CONFIGURE
+ \ EQUAL
+ \ ERROR_VARIABLE
+ \ ESCAPE_QUOTES
+ \ FIND
+ \ GENEX_STRIP
+ \ GET
+ \ GREATER
+ \ GREATER_EQUAL
+ \ GUID
+ \ HASH
+ \ HEX
+ \ JOIN
+ \ JSON
+ \ JSONLENGTH
+ \ LENGTH
+ \ LESS
+ \ LESS_EQUAL
+ \ MAKE_C_IDENTIFIER
+ \ MATCH
+ \ MATCHALL
+ \ MATCHES
+ \ MEMBER
+ \ NAMESPACE
+ \ NOTEQUAL
+ \ NULL
+ \ NUMBER
+ \ OBJECT
+ \ OFF
+ \ ONLY
+ \ PREPEND
+ \ RANDOM
+ \ RANDOM_SEED
+ \ REGEX
+ \ REMOVE
+ \ REPEAT
+ \ REPLACE
+ \ REVERSE
+ \ RFC
+ \ SET
+ \ SHA
+ \ SOURCE_DATE_EPOCH
+ \ STRIP
+ \ SUBSTRING
+ \ SZ
+ \ TIMESTAMP
+ \ TOLOWER
+ \ TOUPPER
+ \ TYPE
+ \ US
+ \ UTC
+ \ UUID
+
+syn keyword cmakeKWsubdirs contained
+ \ EXCLUDE_FROM_ALL
+ \ PREORDER
+
+syn keyword cmakeKWtarget_compile_definitions contained
+ \ ALIAS
+ \ COMPILE_DEFINITIONS
+ \ FOO
+ \ IMPORTED
+ \ INTERFACE
+ \ INTERFACE_COMPILE_DEFINITIONS
+ \ PRIVATE
+ \ PUBLIC
+
+syn keyword cmakeKWtarget_compile_features contained
+ \ ALIAS
+ \ COMPILE_FEATURES
+ \ IMPORTED
+ \ INTERFACE
+ \ INTERFACE_COMPILE_FEATURES
+ \ PRIVATE
+ \ PUBLIC
+
+syn keyword cmakeKWtarget_compile_options contained
+ \ ALIAS
+ \ BEFORE
+ \ COMPILE_OPTIONS
+ \ IMPORTED
+ \ INTERFACE
+ \ INTERFACE_COMPILE_OPTIONS
+ \ PRIVATE
+ \ PUBLIC
+ \ SHELL
+ \ UNIX_COMMAND
+
+syn keyword cmakeKWtarget_include_directories contained
+ \ ALIAS
+ \ BEFORE
+ \ BUILD_INTERFACE
+ \ IMPORTED
+ \ INCLUDE_DIRECTORIES
+ \ INSTALL_INTERFACE
+ \ INTERFACE
+ \ INTERFACE_INCLUDE_DIRECTORIES
+ \ INTERFACE_LINK_LIBRARIES
+ \ INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
+ \ PRIVATE
+ \ PUBLIC
+ \ SYSTEM
+
+syn keyword cmakeKWtarget_link_directories contained
+ \ ALIAS
+ \ BEFORE
+ \ IMPORTED
+ \ INTERFACE
+ \ INTERFACE_LINK_DIRECTORIES
+ \ LINK_DIRECTORIES
+ \ ORIGIN
+ \ PRIVATE
+ \ PUBLIC
+ \ RPATH
+
+syn keyword cmakeKWtarget_link_libraries contained
+ \ ALIAS
+ \ DA
+ \ DAG
+ \ DEBUG_CONFIGURATIONS
+ \ DOBJ
+ \ IMPORTED
+ \ IMPORTED_NO_SONAME
+ \ INTERFACE
+ \ INTERFACE_LINK_LIBRARIES
+ \ LINK_INTERFACE_LIBRARIES
+ \ LINK_INTERFACE_LIBRARIES_DEBUG
+ \ LINK_INTERFACE_MULTIPLICITY
+ \ LINK_OPTIONS
+ \ LINK_PRIVATE
+ \ LINK_PUBLIC
+ \ OBJECT
+ \ OLD
+ \ PRIVATE
+ \ PUBLIC
+ \ SHARED
+ \ STATIC
+
+syn keyword cmakeKWtarget_link_options contained
+ \ ALIAS
+ \ BEFORE
+ \ CMAKE_
+ \ CUDA_RESOLVE_DEVICE_SYMBOLS
+ \ CUDA_SEPARABLE_COMPILATION
+ \ DEVICE_LINK
+ \ GCC
+ \ GNU
+ \ HOST_LINK
+ \ IMPORTED
+ \ INTERFACE
+ \ INTERFACE_LINK_OPTIONS
+ \ LANG
+ \ LINKER
+ \ LINK_OPTIONS
+ \ PRIVATE
+ \ PUBLIC
+ \ SHELL
+ \ STATIC_LIBRARY_OPTIONS
+ \ UNIX_COMMAND
+ \ _LINKER_WRAPPER_FLAG
+ \ _LINKER_WRAPPER_FLAG_SEP
+
+syn keyword cmakeKWtarget_precompile_headers contained
+ \ ALIAS
+ \ ANGLE
+ \ BUILD_INTERFACE
+ \ COMPILE_LANGUAGE
+ \ DISABLE_PRECOMPILE_HEADERS
+ \ EXPORT
+ \ FI
+ \ GCC
+ \ IMPORTED
+ \ INTERFACE
+ \ INTERFACE_PRECOMPILE_HEADERS
+ \ PRECOMPILE_HEADERS
+ \ PRECOMPILE_HEADERS_REUSE_FROM
+ \ PRIVATE
+ \ PUBLIC
+ \ REUSE_FROM
+ \ SKIP_PRECOMPILE_HEADERS
+
+syn keyword cmakeKWtarget_sources contained
+ \ ALIAS
+ \ IMPORTED
+ \ INTERFACE
+ \ INTERFACE_SOURCES
+ \ PRIVATE
+ \ PUBLIC
+ \ SOURCES
+
+syn keyword cmakeKWtry_compile contained
+ \ ALL_BUILD
+ \ CMAKE_FLAGS
+ \ COMPILE_DEFINITIONS
+ \ COPY_FILE
+ \ COPY_FILE_ERROR
+ \ CUDA_EXTENSIONS
+ \ CUDA_STANDARD
+ \ CUDA_STANDARD_REQUIRED
+ \ CXX_EXTENSIONS
+ \ CXX_STANDARD
+ \ CXX_STANDARD_REQUIRED
+ \ C_EXTENSIONS
+ \ C_STANDARD
+ \ C_STANDARD_REQUIRED
+ \ DEFINED
+ \ DLINK_LIBRARIES
+ \ DVAR
+ \ EXECUTABLE
+ \ FALSE
+ \ GHS
+ \ INCLUDE_DIRECTORIES
+ \ LANG
+ \ LINK_DIRECTORIES
+ \ LINK_LIBRARIES
+ \ LINK_OPTIONS
+ \ MULTI
+ \ NOT
+ \ OBJCXX_EXTENSIONS
+ \ OBJCXX_STANDARD
+ \ OBJCXX_STANDARD_REQUIRED
+ \ OBJC_EXTENSIONS
+ \ OBJC_STANDARD
+ \ OBJC_STANDARD_REQUIRED
+ \ OUTPUT_VARIABLE
+ \ PRIVATE
+ \ SOURCES
+ \ STATIC_LIBRARY
+ \ STATIC_LIBRARY_OPTIONS
+ \ TRUE
+ \ TYPE
+ \ VALUE
+ \ _EXTENSIONS
+ \ _STANDARD
+ \ _STANDARD_REQUIRED
+
+syn keyword cmakeKWtry_run contained
+ \ ARGS
+ \ CMAKE_FLAGS
+ \ COMPILE_DEFINITIONS
+ \ COMPILE_OUTPUT_VARIABLE
+ \ DLINK_LIBRARIES
+ \ DVAR
+ \ FAILED_TO_RUN
+ \ FALSE
+ \ INCLUDE_DIRECTORIES
+ \ LINK_DIRECTORIES
+ \ LINK_LIBRARIES
+ \ LINK_OPTIONS
+ \ RUN_OUTPUT_VARIABLE
+ \ TRUE
+ \ TYPE
+ \ VALUE
+ \ __TRYRUN_OUTPUT
+
+syn keyword cmakeKWunset contained
+ \ PARENT_SCOPE
+ \ VAR
+
+syn keyword cmakeKWuse_mangled_mesa contained
+ \ GL
+ \ OUTPUT_DIRECTORY
+ \ PATH_TO_MESA
+
+syn keyword cmakeKWvariable_requires contained
+ \ RESULT_VARIABLE
+ \ TEST_VARIABLE
+
+syn keyword cmakeKWvariable_watch contained
+ \ APPEND
+ \ COMMAND
+ \ DEFINED
+ \ MODIFIED_ACCESS
+ \ READ_ACCESS
+ \ REMOVED_ACCESS
+ \ UNKNOWN_MODIFIED_ACCESS
+ \ UNKNOWN_READ_ACCESS
+
+syn keyword cmakeKWwrite_file contained
+ \ APPEND
+ \ CONFIGURE_FILE
+ \ NOTE
+ \ WRITE
+
+
+syn keyword cmakeGeneratorExpressions contained
+ \ AND
+ \ ANGLE
+ \ ARCHIVE_OUTPUT_NAME
+ \ ARCHIVE_OUTPUT_NAME_
+ \ BAR
+ \ BOOL
+ \ BUILD_INTERFACE
+ \ CMAKE_
+ \ COMMA
+ \ COMMAND
+ \ COMPILE_DEFINITIONS
+ \ COMPILE_FEATURES
+ \ COMPILE_LANGUAGE
+ \ COMPILE_LANG_AND_ID
+ \ COMPILING_CUDA
+ \ COMPILING_CXX_WITH_CLANG
+ \ COMPILING_CXX_WITH_INTEL
+ \ COMPILING_C_WITH_CLANG
+ \ CONFIG
+ \ CONFIGURATION
+ \ CUDA_COMPILER_ID
+ \ CUDA_COMPILER_VERSION
+ \ CUDA_RESOLVE_DEVICE_SYMBOLS
+ \ CUDA_SEPARABLE_COMPILATION
+ \ CUSTOM_KEYS
+ \ CXX_COMPILER_ID
+ \ CXX_COMPILER_VERSION
+ \ CXX_CONFIG
+ \ CXX_STANDARD
+ \ C_COMPILER_ID
+ \ C_COMPILER_VERSION
+ \ C_STANDARD
+ \ DEBUG_MODE
+ \ DEBUG_POSTFIX
+ \ DEVICE_LINK
+ \ DLL
+ \ EXCLUDE
+ \ EXPORT
+ \ FALSE
+ \ FILTER
+ \ FOO_EXTRA_THINGS
+ \ GENERATE
+ \ GENEX_EVAL
+ \ GNU
+ \ HOST_LINK
+ \ IF
+ \ IGNORE
+ \ IMPORT_PREFIX
+ \ IMPORT_SUFFIX
+ \ INCLUDE_DIRECTORIES
+ \ INSTALL_INTERFACE
+ \ INSTALL_NAME_DIR
+ \ INSTALL_PREFIX
+ \ INTERFACE
+ \ INTERFACE_LINK_LIBRARIES
+ \ IN_LIST
+ \ ISPC_COMPILER_ID
+ \ ISPC_COMPILER_VERSION
+ \ JOIN
+ \ LANG
+ \ LANG_COMPILER_ID
+ \ LIBRARY_OUTPUT_NAME
+ \ LIBRARY_OUTPUT_NAME_
+ \ LINK_LANGUAGE
+ \ LINK_LANG_AND_ID
+ \ LINK_LIBRARIES
+ \ LINK_ONLY
+ \ LOWER_CASE
+ \ MAKE_C_IDENTIFIER
+ \ MAP_IMPORTED_CONFIG_
+ \ NO
+ \ NOT
+ \ OBJCXX_COMPILER_ID
+ \ OBJCXX_COMPILER_VERSION
+ \ OBJC_COMPILER_ID
+ \ OBJC_COMPILER_VERSION
+ \ OFF
+ \ OLD_COMPILER
+ \ OUTPUT_NAME
+ \ OUTPUT_NAME_
+ \ PDB_NAME
+ \ PDB_NAME_
+ \ PDB_OUTPUT_DIRECTORY
+ \ PDB_OUTPUT_DIRECTORY_
+ \ PLATFORM_ID
+ \ POSIX
+ \ PRIVATE
+ \ PUBLIC
+ \ REMOVE_DUPLICATES
+ \ RUNTIME_OUTPUT_NAME
+ \ RUNTIME_OUTPUT_NAME_
+ \ SDK
+ \ SEMICOLON
+ \ SHELL_PATH
+ \ STATIC
+ \ STREQUAL
+ \ TARGET_BUNDLE_CONTENT_DIR
+ \ TARGET_BUNDLE_DIR
+ \ TARGET_EXISTS
+ \ TARGET_FILE
+ \ TARGET_FILE_BASE_NAME
+ \ TARGET_FILE_DIR
+ \ TARGET_FILE_NAME
+ \ TARGET_FILE_PREFIX
+ \ TARGET_FILE_SUFFIX
+ \ TARGET_GENEX_EVAL
+ \ TARGET_LINKER_FILE
+ \ TARGET_LINKER_FILE_BASE_NAME
+ \ TARGET_LINKER_FILE_DIR
+ \ TARGET_LINKER_FILE_NAME
+ \ TARGET_LINKER_FILE_PREFIX
+ \ TARGET_LINKER_FILE_SUFFIX
+ \ TARGET_NAME_IF_EXISTS
+ \ TARGET_OBJECTS
+ \ TARGET_PDB_FILE
+ \ TARGET_PDB_FILE_BASE_NAME
+ \ TARGET_PDB_FILE_DIR
+ \ TARGET_PDB_FILE_NAME
+ \ TARGET_POLICY
+ \ TARGET_PROPERTY
+ \ TARGET_SONAME_FILE
+ \ TARGET_SONAME_FILE_DIR
+ \ TARGET_SONAME_FILE_NAME
+ \ UPPER_CASE
+ \ VERSION_EQUAL
+ \ VERSION_GREATER
+ \ VERSION_GREATER_EQUAL
+ \ VERSION_LESS
+ \ VERSION_LESS_EQUAL
+ \ _POSTFIX
+
+syn case ignore
+
+syn keyword cmakeCommand
+ \ add_compile_definitions
+ \ add_compile_options
+ \ add_custom_command
+ \ add_custom_target
+ \ add_definitions
+ \ add_dependencies
+ \ add_executable
+ \ add_library
+ \ add_link_options
+ \ add_subdirectory
+ \ add_test
+ \ aux_source_directory
+ \ break
+ \ build_command
+ \ cmake_host_system_information
+ \ cmake_language
+ \ cmake_minimum_required
+ \ cmake_parse_arguments
+ \ cmake_path
+ \ cmake_policy
+ \ configure_file
+ \ continue
+ \ create_test_sourcelist
+ \ ctest_build
+ \ ctest_configure
+ \ ctest_coverage
+ \ ctest_empty_binary_directory
+ \ ctest_memcheck
+ \ ctest_read_custom_files
+ \ ctest_run_script
+ \ ctest_sleep
+ \ ctest_start
+ \ ctest_submit
+ \ ctest_test
+ \ ctest_update
+ \ ctest_upload
+ \ define_property
+ \ enable_language
+ \ enable_testing
+ \ endfunction
+ \ endmacro
+ \ execute_process
+ \ export
+ \ file
+ \ find_file
+ \ find_library
+ \ find_package
+ \ find_path
+ \ find_program
+ \ fltk_wrap_ui
+ \ function
+ \ get_cmake_property
+ \ get_directory_property
+ \ get_filename_component
+ \ get_property
+ \ get_source_file_property
+ \ get_target_property
+ \ get_test_property
+ \ include
+ \ include_directories
+ \ include_external_msproject
+ \ include_guard
+ \ include_regular_expression
+ \ install
+ \ link_directories
+ \ list
+ \ load_cache
+ \ load_command
+ \ macro
+ \ mark_as_advanced
+ \ math
+ \ message
+ \ option
+ \ project
+ \ qt_wrap_cpp
+ \ qt_wrap_ui
+ \ remove_definitions
+ \ return
+ \ separate_arguments
+ \ set
+ \ set_directory_properties
+ \ set_property
+ \ set_source_files_properties
+ \ set_target_properties
+ \ set_tests_properties
+ \ site_name
+ \ source_group
+ \ string
+ \ target_compile_definitions
+ \ target_compile_features
+ \ target_compile_options
+ \ target_include_directories
+ \ target_link_directories
+ \ target_link_libraries
+ \ target_link_options
+ \ target_precompile_headers
+ \ target_sources
+ \ try_compile
+ \ try_run
+ \ unset
+ \ variable_watch
+ \ nextgroup=cmakeArguments
+
+syn keyword cmakeCommandConditional
+ \ else
+ \ elseif
+ \ endif
+ \ if
+ \ nextgroup=cmakeArguments
+
+syn keyword cmakeCommandRepeat
+ \ endforeach
+ \ endwhile
+ \ foreach
+ \ while
+ \ nextgroup=cmakeArguments
+
+syn keyword cmakeCommandDeprecated
+ \ build_name
+ \ exec_program
+ \ export_library_dependencies
+ \ install_files
+ \ install_programs
+ \ install_targets
+ \ link_libraries
+ \ make_directory
+ \ output_required_files
+ \ remove
+ \ subdir_depends
+ \ subdirs
+ \ use_mangled_mesa
+ \ utility_source
+ \ variable_requires
+ \ write_file
+ \ nextgroup=cmakeArguments
+
+syn case match
+
+syn keyword cmakeTodo
+ \ TODO FIXME XXX
+ \ contained
+
+hi def link cmakeBracketArgument String
+hi def link cmakeBracketComment Comment
+hi def link cmakeCommand Function
+hi def link cmakeCommandConditional Conditional
+hi def link cmakeCommandDeprecated WarningMsg
+hi def link cmakeCommandRepeat Repeat
+hi def link cmakeComment Comment
+hi def link cmakeEnvironment Special
+hi def link cmakeEscaped Special
+hi def link cmakeGeneratorExpression WarningMsg
+hi def link cmakeGeneratorExpressions Constant
+hi def link cmakeModule Include
+hi def link cmakeProperty Constant
+hi def link cmakeRegistry Underlined
+hi def link cmakeString String
+hi def link cmakeTodo TODO
+hi def link cmakeVariableValue Type
+hi def link cmakeVariable Identifier
+
+hi def link cmakeKWExternalProject ModeMsg
+hi def link cmakeKWadd_compile_definitions ModeMsg
+hi def link cmakeKWadd_compile_options ModeMsg
+hi def link cmakeKWadd_custom_command ModeMsg
+hi def link cmakeKWadd_custom_target ModeMsg
+hi def link cmakeKWadd_definitions ModeMsg
+hi def link cmakeKWadd_dependencies ModeMsg
+hi def link cmakeKWadd_executable ModeMsg
+hi def link cmakeKWadd_library ModeMsg
+hi def link cmakeKWadd_link_options ModeMsg
+hi def link cmakeKWadd_subdirectory ModeMsg
+hi def link cmakeKWadd_test ModeMsg
+hi def link cmakeKWbuild_command ModeMsg
+hi def link cmakeKWcmake_host_system_information ModeMsg
+hi def link cmakeKWcmake_language ModeMsg
+hi def link cmakeKWcmake_minimum_required ModeMsg
+hi def link cmakeKWcmake_parse_arguments ModeMsg
+hi def link cmakeKWcmake_path ModeMsg
+hi def link cmakeKWcmake_policy ModeMsg
+hi def link cmakeKWconfigure_file ModeMsg
+hi def link cmakeKWcreate_test_sourcelist ModeMsg
+hi def link cmakeKWctest_build ModeMsg
+hi def link cmakeKWctest_configure ModeMsg
+hi def link cmakeKWctest_coverage ModeMsg
+hi def link cmakeKWctest_memcheck ModeMsg
+hi def link cmakeKWctest_run_script ModeMsg
+hi def link cmakeKWctest_start ModeMsg
+hi def link cmakeKWctest_submit ModeMsg
+hi def link cmakeKWctest_test ModeMsg
+hi def link cmakeKWctest_update ModeMsg
+hi def link cmakeKWctest_upload ModeMsg
+hi def link cmakeKWdefine_property ModeMsg
+hi def link cmakeKWdoxygen_add_docs ModeMsg
+hi def link cmakeKWenable_language ModeMsg
+hi def link cmakeKWenable_testing ModeMsg
+hi def link cmakeKWexec_program ModeMsg
+hi def link cmakeKWexecute_process ModeMsg
+hi def link cmakeKWexport ModeMsg
+hi def link cmakeKWexport_library_dependencies ModeMsg
+hi def link cmakeKWfile ModeMsg
+hi def link cmakeKWfind_file ModeMsg
+hi def link cmakeKWfind_library ModeMsg
+hi def link cmakeKWfind_package ModeMsg
+hi def link cmakeKWfind_path ModeMsg
+hi def link cmakeKWfind_program ModeMsg
+hi def link cmakeKWfltk_wrap_ui ModeMsg
+hi def link cmakeKWforeach ModeMsg
+hi def link cmakeKWfunction ModeMsg
+hi def link cmakeKWget_cmake_property ModeMsg
+hi def link cmakeKWget_directory_property ModeMsg
+hi def link cmakeKWget_filename_component ModeMsg
+hi def link cmakeKWget_property ModeMsg
+hi def link cmakeKWget_source_file_property ModeMsg
+hi def link cmakeKWget_target_property ModeMsg
+hi def link cmakeKWget_test_property ModeMsg
+hi def link cmakeKWif ModeMsg
+hi def link cmakeKWinclude ModeMsg
+hi def link cmakeKWinclude_directories ModeMsg
+hi def link cmakeKWinclude_external_msproject ModeMsg
+hi def link cmakeKWinclude_guard ModeMsg
+hi def link cmakeKWinstall ModeMsg
+hi def link cmakeKWinstall_files ModeMsg
+hi def link cmakeKWinstall_programs ModeMsg
+hi def link cmakeKWinstall_targets ModeMsg
+hi def link cmakeKWlink_directories ModeMsg
+hi def link cmakeKWlist ModeMsg
+hi def link cmakeKWload_cache ModeMsg
+hi def link cmakeKWload_command ModeMsg
+hi def link cmakeKWmacro ModeMsg
+hi def link cmakeKWmark_as_advanced ModeMsg
+hi def link cmakeKWmath ModeMsg
+hi def link cmakeKWmessage ModeMsg
+hi def link cmakeKWoption ModeMsg
+hi def link cmakeKWproject ModeMsg
+hi def link cmakeKWqt_wrap_cpp ModeMsg
+hi def link cmakeKWqt_wrap_ui ModeMsg
+hi def link cmakeKWremove ModeMsg
+hi def link cmakeKWreturn ModeMsg
+hi def link cmakeKWseparate_arguments ModeMsg
+hi def link cmakeKWset ModeMsg
+hi def link cmakeKWset_directory_properties ModeMsg
+hi def link cmakeKWset_property ModeMsg
+hi def link cmakeKWset_source_files_properties ModeMsg
+hi def link cmakeKWset_target_properties ModeMsg
+hi def link cmakeKWset_tests_properties ModeMsg
+hi def link cmakeKWsite_name ModeMsg
+hi def link cmakeKWsource_group ModeMsg
+hi def link cmakeKWstring ModeMsg
+hi def link cmakeKWsubdirs ModeMsg
+hi def link cmakeKWtarget_compile_definitions ModeMsg
+hi def link cmakeKWtarget_compile_features ModeMsg
+hi def link cmakeKWtarget_compile_options ModeMsg
+hi def link cmakeKWtarget_include_directories ModeMsg
+hi def link cmakeKWtarget_link_directories ModeMsg
+hi def link cmakeKWtarget_link_libraries ModeMsg
+hi def link cmakeKWtarget_link_options ModeMsg
+hi def link cmakeKWtarget_precompile_headers ModeMsg
+hi def link cmakeKWtarget_sources ModeMsg
+hi def link cmakeKWtry_compile ModeMsg
+hi def link cmakeKWtry_run ModeMsg
+hi def link cmakeKWunset ModeMsg
+hi def link cmakeKWuse_mangled_mesa ModeMsg
+hi def link cmakeKWvariable_requires ModeMsg
+hi def link cmakeKWvariable_watch ModeMsg
+hi def link cmakeKWwrite_file ModeMsg
+
+" Manually added - difficult to parse out of documentation
+syn case ignore
+
+syn keyword cmakeCommandManuallyAdded
+ \ configure_package_config_file write_basic_package_version_file
+ \ nextgroup=cmakeArguments
+
+syn case match
+
+syn keyword cmakeKWconfigure_package_config_file contained
+ \ INSTALL_DESTINATION PATH_VARS NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO INSTALL_PREFIX
+
+syn keyword cmakeKWconfigure_package_config_file_constants contained
+ \ AnyNewerVersion SameMajorVersion SameMinorVersion ExactVersion
+
+syn keyword cmakeKWwrite_basic_package_version_file contained
+ \ VERSION COMPATIBILITY
+
+hi def link cmakeCommandManuallyAdded Function
+
+hi def link cmakeKWconfigure_package_config_file ModeMsg
+hi def link cmakeKWwrite_basic_package_version_file ModeMsg
+hi def link cmakeKWconfigure_package_config_file_constants Constant
+
+let b:current_syntax = "cmake"
+
+let &cpo = s:keepcpo
+unlet s:keepcpo
+
+" vim: set nowrap:
diff --git a/CMakeCPack.cmake b/CMakeCPack.cmake
new file mode 100644
index 0000000..9357804
--- /dev/null
+++ b/CMakeCPack.cmake
@@ -0,0 +1,267 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+option(CMAKE_INSTALL_DEBUG_LIBRARIES
+ "Install Microsoft runtime debug libraries with CMake." FALSE)
+mark_as_advanced(CMAKE_INSTALL_DEBUG_LIBRARIES)
+
+# By default, do not warn when built on machines using only VS Express:
+if(NOT DEFINED CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
+ set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON)
+endif()
+
+if(CMake_INSTALL_DEPENDENCIES)
+ include(${CMake_SOURCE_DIR}/Modules/InstallRequiredSystemLibraries.cmake)
+endif()
+
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "CMake is a build tool")
+set(CPACK_PACKAGE_VENDOR "Kitware")
+set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/Copyright.txt")
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/Copyright.txt")
+set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
+set(CPACK_PACKAGE_VERSION "${CMake_VERSION}")
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}")
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "cmake-${CMake_VERSION}")
+
+# Installers for 32- vs. 64-bit CMake:
+# - Root install directory (displayed to end user at installer-run time)
+# - "NSIS package/display name" (text used in the installer GUI)
+# - Registry key used to store info about the installation
+if(CMAKE_CL_64)
+ set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
+ set(CPACK_NSIS_PACKAGE_NAME "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION} (Win64)")
+else()
+ set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES")
+ set(CPACK_NSIS_PACKAGE_NAME "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION}")
+endif()
+set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "${CPACK_NSIS_PACKAGE_NAME}")
+
+if(NOT DEFINED CPACK_SYSTEM_NAME)
+ # make sure package is not Cygwin-unknown, for Cygwin just
+ # cygwin is good for the system name
+ if("x${CMAKE_SYSTEM_NAME}" STREQUAL "xCYGWIN")
+ set(CPACK_SYSTEM_NAME Cygwin)
+ else()
+ set(CPACK_SYSTEM_NAME ${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR})
+ endif()
+endif()
+if(${CPACK_SYSTEM_NAME} MATCHES Windows)
+ if(CMAKE_CL_64)
+ set(CPACK_SYSTEM_NAME win64-x64)
+ set(CPACK_IFW_TARGET_DIRECTORY "@RootDir@/Program Files/${CMAKE_PROJECT_NAME}")
+ else()
+ set(CPACK_SYSTEM_NAME win32-x86)
+ endif()
+endif()
+
+# Command for configure IFW script templates
+include(${CMake_SOURCE_DIR}/Modules/CPackIFWConfigureFile.cmake)
+
+# Advanced IFW configuration
+set(_cpifwrc CPACK_IFW_COMPONENT_GROUP_CMAKE_)
+set(_cpifwrcconf _CPACK_IFW_COMPONENT_GROUP_CMAKE)
+set(${_cpifwrcconf} "# CMake IFW configuration\n")
+macro(_cmifwarg DESCRIPTION TYPE NAME DEFAULT)
+ set(_var CMake_IFW_ROOT_COMPONENT_${NAME})
+ if(DEFINED ${_var})
+ set(${_var} ${${_var}} CACHE ${TYPE} ${DESCRIPTION})
+ mark_as_advanced(${_var})
+ elseif(NOT "${DEFAULT}" STREQUAL "")
+ set(${_var} ${DEFAULT})
+ endif()
+ if(DEFINED ${_var})
+ set(${_cpifwrcconf}
+ "${${_cpifwrcconf}} set(${_cpifwrc}${NAME}\n \"${${_var}}\")\n")
+ endif()
+endmacro()
+
+_cmifwarg("Package <Name> tag (domen-like)"
+ STRING NAME "")
+_cmifwarg("Package <DisplayName> tag"
+ STRING DISPLAY_NAME "")
+_cmifwarg("Package <Description> tag"
+ STRING DESCRIPTION "")
+_cmifwarg("Package <ReleaseDate> tag (keep empty to auto generate)"
+ STRING RELEASE_DATE "")
+_cmifwarg("Package <Default> tag (values: TRUE, FALSE, SCRIPT)"
+ STRING DEFAULT "")
+_cmifwarg("Package <Version> tag"
+ STRING VERSION
+ "${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}.${CMake_VERSION_PATCH}")
+_cmifwarg("Package <SortingPriority> tag"
+ STRING PRIORITY "100")
+_cmifwarg("Package <ForsedInstallation> tag"
+ STRING FORCED_INSTALLATION "")
+
+set(${_cpifwrc}LICENSES_DEFAULT
+ "${CPACK_PACKAGE_NAME} Copyright;${CPACK_RESOURCE_FILE_LICENSE}")
+
+# Components
+if(CMake_INSTALL_COMPONENTS)
+ set(_CPACK_IFW_COMPONENTS_ALL cmake ctest cpack)
+ if(WIN32 AND NOT CYGWIN)
+ list(APPEND _CPACK_IFW_COMPONENTS_ALL cmcldeps)
+ endif()
+ if(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
+ set(_CPACK_IFW_COMPONENT_UNSPECIFIED_NAME
+ ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME})
+ else()
+ set(_CPACK_IFW_COMPONENT_UNSPECIFIED_NAME Unspecified)
+ endif()
+ list(APPEND _CPACK_IFW_COMPONENTS_ALL ${_CPACK_IFW_COMPONENT_UNSPECIFIED_NAME})
+ string(TOUPPER "${_CPACK_IFW_COMPONENT_UNSPECIFIED_NAME}"
+ _CPACK_IFW_COMPONENT_UNSPECIFIED_UNAME)
+ if(BUILD_CursesDialog)
+ list(APPEND _CPACK_IFW_COMPONENTS_ALL ccmake)
+ endif()
+ if(BUILD_QtDialog)
+ list(APPEND _CPACK_IFW_COMPONENTS_ALL cmake-gui)
+ if(USE_LGPL)
+ set(_CPACK_IFW_COMPONENT_CMAKE-GUI_LICENSES "set(CPACK_IFW_COMPONENT_CMAKE-GUI_LICENSES
+ \"LGPLv${USE_LGPL}\" \"${CMake_SOURCE_DIR}/Licenses/LGPLv${USE_LGPL}.txt\")")
+ endif()
+ endif()
+ if(SPHINX_MAN)
+ list(APPEND _CPACK_IFW_COMPONENTS_ALL sphinx-man)
+ endif()
+ if(SPHINX_HTML)
+ list(APPEND _CPACK_IFW_COMPONENTS_ALL sphinx-html)
+ endif()
+ if(SPHINX_SINGLEHTML)
+ list(APPEND _CPACK_IFW_COMPONENTS_ALL sphinx-singlehtml)
+ endif()
+ if(SPHINX_QTHELP)
+ list(APPEND _CPACK_IFW_COMPONENTS_ALL sphinx-qthelp)
+ endif()
+ if(SPHINX_LATEXPDF)
+ list(APPEND _CPACK_IFW_COMPONENTS_ALL sphinx-latexpdf)
+ endif()
+ if(CMake_BUILD_DEVELOPER_REFERENCE)
+ if(CMake_BUILD_DEVELOPER_REFERENCE_HTML)
+ list(APPEND _CPACK_IFW_COMPONENTS_ALL cmake-developer-reference-html)
+ endif()
+ if(CMake_BUILD_DEVELOPER_REFERENCE_QTHELP)
+ list(APPEND _CPACK_IFW_COMPONENTS_ALL cmake-developer-reference-qthelp)
+ endif()
+ endif()
+ set(_CPACK_IFW_COMPONENTS_CONFIGURATION "
+ # Components
+ set(CPACK_COMPONENTS_ALL \"${_CPACK_IFW_COMPONENTS_ALL}\")
+ set(CPACK_COMPONENTS_GROUPING IGNORE)
+ ")
+ _cmifwarg("Package <Script> template"
+ FILEPATH SCRIPT_TEMPLATE "${CMake_SOURCE_DIR}/Source/QtIFW/CMake.qs.in")
+else()
+ if(BUILD_QtDialog AND USE_LGPL)
+ set(${_cpifwrc}LICENSES_DEFAULT
+ "${${_cpifwrc}LICENSES_DEFAULT};LGPLv${USE_LGPL};${CMake_SOURCE_DIR}/Licenses/LGPLv${USE_LGPL}.txt")
+ endif()
+ _cmifwarg("Package <Script> template"
+ FILEPATH SCRIPT_TEMPLATE "${CMake_SOURCE_DIR}/Source/QtIFW/installscript.qs.in")
+endif()
+_cmifwarg("Package <Script> generated"
+ FILEPATH SCRIPT_GENERATED "${CMake_BINARY_DIR}/CMake.qs")
+
+_cmifwarg("Package <Licenses> tag (pairs of <display_name> <file_path>)"
+ STRING LICENSES "${${_cpifwrc}LICENSES_DEFAULT}")
+
+if(${CMAKE_SYSTEM_NAME} MATCHES Windows)
+ set(_CPACK_IFW_PACKAGE_ICON
+ "set(CPACK_IFW_PACKAGE_ICON \"${CMake_SOURCE_DIR}/Source/QtDialog/CMakeSetup.ico\")")
+ if(BUILD_QtDialog)
+ set(_CPACK_IFW_SHORTCUT_OPTIONAL "${_CPACK_IFW_SHORTCUT_OPTIONAL}component.addOperation(\"CreateShortcut\", \"@TargetDir@/bin/cmake-gui.exe\", \"@StartMenuDir@/CMake (cmake-gui).lnk\");\n")
+ endif()
+ if(SPHINX_HTML)
+ set(_CPACK_IFW_SHORTCUT_OPTIONAL "${_CPACK_IFW_SHORTCUT_OPTIONAL}component.addOperation(\"CreateShortcut\", \"@TargetDir@/doc/cmake-${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}/html/index.html\", \"@StartMenuDir@/CMake Documentation.lnk\");\n")
+ endif()
+ if(CMake_BUILD_DEVELOPER_REFERENCE)
+ if(CMake_BUILD_DEVELOPER_REFERENCE_HTML)
+ set(_CPACK_IFW_SHORTCUT_OPTIONAL "${_CPACK_IFW_SHORTCUT_OPTIONAL}component.addOperation(\"CreateShortcut\", \"@TargetDir@/doc/cmake-${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}/developer-reference/html/index.html\", \"@StartMenuDir@/CMake Developer Reference.lnk\");\n")
+ endif()
+ endif()
+ install(FILES "${CMake_SOURCE_DIR}/Source/QtIFW/cmake.org.html"
+ DESTINATION "${CMAKE_DOC_DIR}"
+ )
+endif()
+
+if(${CMAKE_SYSTEM_NAME} MATCHES Linux)
+ set(CPACK_IFW_TARGET_DIRECTORY "@HomeDir@/${CMAKE_PROJECT_NAME}")
+ set(CPACK_IFW_ADMIN_TARGET_DIRECTORY "@ApplicationsDir@/${CMAKE_PROJECT_NAME}")
+endif()
+
+# Components scripts configuration
+if((EXISTS "${CMake_IFW_ROOT_COMPONENT_SCRIPT_TEMPLATE}")
+ AND (NOT "${CMake_IFW_ROOT_COMPONENT_SCRIPT_GENERATED}" STREQUAL "")
+ AND (NOT "${CMake_IFW_ROOT_COMPONENT_SCRIPT}"))
+ cpack_ifw_configure_file("${CMake_IFW_ROOT_COMPONENT_SCRIPT_TEMPLATE}"
+ "${CMake_IFW_ROOT_COMPONENT_SCRIPT_GENERATED}")
+ _cmifwarg("Package <Script> tag"
+ FILEPATH SCRIPT "${CMake_IFW_ROOT_COMPONENT_SCRIPT_GENERATED}")
+endif()
+foreach(_script
+ CMake.Dialogs.QtGUI
+ CMake.Documentation.SphinxHTML
+ CMake.DeveloperReference.HTML)
+ cpack_ifw_configure_file("${CMake_SOURCE_DIR}/Source/QtIFW/${_script}.qs.in"
+ "${CMake_BINARY_DIR}/${_script}.qs")
+endforeach()
+
+if(NOT DEFINED CPACK_PACKAGE_FILE_NAME)
+ # if the CPACK_PACKAGE_FILE_NAME is not defined by the cache
+ # default to source package - system, on cygwin system is not
+ # needed
+ if(CYGWIN)
+ set(CPACK_PACKAGE_FILE_NAME "${CPACK_SOURCE_PACKAGE_FILE_NAME}")
+ else()
+ set(CPACK_PACKAGE_FILE_NAME
+ "${CPACK_SOURCE_PACKAGE_FILE_NAME}-${CPACK_SYSTEM_NAME}")
+ endif()
+endif()
+
+set(CPACK_PACKAGE_CONTACT "cmake+development@discourse.cmake.org")
+
+if(UNIX)
+ set(CPACK_STRIP_FILES "${CMAKE_BIN_DIR}/ccmake;${CMAKE_BIN_DIR}/cmake;${CMAKE_BIN_DIR}/cpack;${CMAKE_BIN_DIR}/ctest")
+ set(CPACK_SOURCE_STRIP_FILES "")
+ set(CPACK_PACKAGE_EXECUTABLES "ccmake" "CMake")
+endif()
+
+set(CPACK_WIX_UPGRADE_GUID "8ffd1d72-b7f1-11e2-8ee5-00238bca4991")
+
+if(MSVC AND NOT "$ENV{WIX}" STREQUAL "")
+ set(WIX_CUSTOM_ACTION_ENABLED TRUE)
+ if(CMAKE_CONFIGURATION_TYPES)
+ set(WIX_CUSTOM_ACTION_MULTI_CONFIG TRUE)
+ else()
+ set(WIX_CUSTOM_ACTION_MULTI_CONFIG FALSE)
+ endif()
+else()
+ set(WIX_CUSTOM_ACTION_ENABLED FALSE)
+endif()
+
+# Set the options file that needs to be included inside CMakeCPackOptions.cmake
+set(QT_DIALOG_CPACK_OPTIONS_FILE ${CMake_BINARY_DIR}/Source/QtDialog/QtDialogCPack.cmake)
+configure_file("${CMake_SOURCE_DIR}/CMakeCPackOptions.cmake.in"
+ "${CMake_BINARY_DIR}/CMakeCPackOptions.cmake" @ONLY)
+set(CPACK_PROJECT_CONFIG_FILE "${CMake_BINARY_DIR}/CMakeCPackOptions.cmake")
+
+set(CPACK_SOURCE_IGNORE_FILES
+ # Files specific to version control.
+ "/\\\\.git/"
+ "/\\\\.gitattributes$"
+ "/\\\\.github/"
+ "/\\\\.gitignore$"
+ "/\\\\.hooks-config$"
+
+ # Cygwin package build.
+ "/\\\\.build/"
+
+ # Temporary files.
+ "\\\\.swp$"
+ "\\\\.#"
+ "/#"
+ "~$"
+ )
+
+# include CPack model once all variables are set
+include(CPack)
diff --git a/CMakeCPackOptions.cmake.in b/CMakeCPackOptions.cmake.in
new file mode 100644
index 0000000..2a4bcc5
--- /dev/null
+++ b/CMakeCPackOptions.cmake.in
@@ -0,0 +1,313 @@
+# This file is configured at cmake time, and loaded at cpack time.
+# To pass variables to cpack from cmake, they must be configured
+# in this file.
+
+if(CPACK_GENERATOR MATCHES "NSIS")
+ set(CPACK_NSIS_INSTALL_ROOT "@CPACK_NSIS_INSTALL_ROOT@")
+
+ # set the install/unistall icon used for the installer itself
+ # There is a bug in NSI that does not handle full unix paths properly.
+ set(CPACK_NSIS_MUI_ICON "@CMake_SOURCE_DIR@/Utilities/Release\\CMakeLogo.ico")
+ set(CPACK_NSIS_MUI_UNIICON "@CMake_SOURCE_DIR@/Utilities/Release\\CMakeLogo.ico")
+ # set the package header icon for MUI
+ set(CPACK_PACKAGE_ICON "@CMake_SOURCE_DIR@/Utilities/Release\\CMakeInstall.bmp")
+ # tell cpack to create links to the doc files
+ set(CPACK_NSIS_MENU_LINKS
+ "@CMAKE_DOC_DIR@/html/index.html" "CMake Documentation"
+ "https://cmake.org" "CMake Web Site"
+ )
+ # Use the icon from cmake-gui for add-remove programs
+ set(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\cmake-gui.exe")
+
+ set(CPACK_NSIS_PACKAGE_NAME "@CPACK_NSIS_PACKAGE_NAME@")
+ set(CPACK_NSIS_DISPLAY_NAME "@CPACK_NSIS_PACKAGE_NAME@, a cross-platform, open-source build system")
+ set(CPACK_NSIS_HELP_LINK "https://cmake.org")
+ set(CPACK_NSIS_URL_INFO_ABOUT "http://www.kitware.com")
+ set(CPACK_NSIS_CONTACT @CPACK_PACKAGE_CONTACT@)
+ set(CPACK_NSIS_MODIFY_PATH ON)
+endif()
+
+# include the cpack options for qt dialog if they exist
+# they might not if qt was not enabled for the build
+include("@QT_DIALOG_CPACK_OPTIONS_FILE@" OPTIONAL)
+
+if(CPACK_GENERATOR MATCHES "IFW")
+
+ # Installer configuration
+ set(CPACK_IFW_PACKAGE_TITLE "CMake Build Tool")
+ set(CPACK_IFW_PRODUCT_URL "https://cmake.org")
+ @_CPACK_IFW_PACKAGE_ICON@
+ set(CPACK_IFW_PACKAGE_WINDOW_ICON
+ "@CMake_SOURCE_DIR@/Source/QtDialog/CMakeSetup128.png")
+ set(CPACK_IFW_PACKAGE_CONTROL_SCRIPT
+ "@CMake_SOURCE_DIR@/Source/QtIFW/controlscript.qs")
+
+ # Uninstaller configuration
+ set(CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_NAME "cmake-maintenance")
+ @_CPACK_IFW_COMPONENTS_CONFIGURATION@
+ # Unspecified
+ set(CPACK_IFW_COMPONENT_@_CPACK_IFW_COMPONENT_UNSPECIFIED_UNAME@_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ # Package configuration group
+ set(CPACK_IFW_PACKAGE_GROUP CMake)
+
+ # Group configuration
+
+ # CMake
+ set(CPACK_COMPONENT_GROUP_CMAKE_DISPLAY_NAME
+ "@CPACK_PACKAGE_NAME@")
+ set(CPACK_COMPONENT_GROUP_CMAKE_DESCRIPTION
+ "@CPACK_PACKAGE_DESCRIPTION_SUMMARY@")
+ @_CPACK_IFW_COMPONENT_GROUP_CMAKE@
+
+ # Tools
+ set(CPACK_COMPONENT_GROUP_TOOLS_DISPLAY_NAME "Command-Line Tools")
+ set(CPACK_COMPONENT_GROUP_TOOLS_DESCRIPTION
+ "Command-Line Tools: cmake, ctest and cpack")
+ set(CPACK_COMPONENT_GROUP_TOOLS_PARENT_GROUP CMake)
+ set(CPACK_IFW_COMPONENT_GROUP_TOOLS_PRIORITY 90)
+ set(CPACK_IFW_COMPONENT_GROUP_TOOLS_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ set(CPACK_COMPONENT_CMAKE_DISPLAY_NAME "cmake")
+ set(CPACK_COMPONENT_CMAKE_DESCRIPTION
+ "The \"cmake\" executable is the CMake command-line interface")
+ set(CPACK_COMPONENT_CMAKE_REQUIRED TRUE)
+ set(CPACK_COMPONENT_CMAKE_GROUP Tools)
+ set(CPACK_IFW_COMPONENT_CMAKE_NAME "CMake")
+ set(CPACK_IFW_COMPONENT_CMAKE_PRIORITY 89)
+ set(CPACK_IFW_COMPONENT_CMAKE_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ set(CPACK_COMPONENT_CTEST_DISPLAY_NAME "ctest")
+ set(CPACK_COMPONENT_CTEST_DESCRIPTION
+ "The \"ctest\" executable is the CMake test driver program")
+ set(CPACK_COMPONENT_CTEST_REQUIRED TRUE)
+ set(CPACK_COMPONENT_CTEST_GROUP Tools)
+ set(CPACK_IFW_COMPONENT_CTEST_NAME "CTest")
+ set(CPACK_IFW_COMPONENT_CTEST_PRIORITY 88)
+ set(CPACK_IFW_COMPONENT_CTEST_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ set(CPACK_COMPONENT_CPACK_DISPLAY_NAME "cpack")
+ set(CPACK_COMPONENT_CPACK_DESCRIPTION
+ "The \"cpack\" executable is the CMake packaging program")
+ set(CPACK_COMPONENT_CPACK_REQUIRED TRUE)
+ set(CPACK_COMPONENT_CPACK_GROUP Tools)
+ set(CPACK_IFW_COMPONENT_CPACK_NAME "CPack")
+ set(CPACK_IFW_COMPONENT_CPACK_PRIORITY 87)
+ set(CPACK_IFW_COMPONENT_CPACK_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ set(CPACK_COMPONENT_CMCLDEPS_DISPLAY_NAME "cmcldeps")
+ set(CPACK_COMPONENT_CMCLDEPS_DESCRIPTION
+ "The \"cmcldeps\" executable is wrapper around \"cl\" program")
+ set(CPACK_COMPONENT_CMCLDEPS_GROUP Tools)
+ set(CPACK_IFW_COMPONENT_CMCLDEPS_NAME "CMClDeps")
+ set(CPACK_IFW_COMPONENT_CMCLDEPS_PRIORITY 86)
+ set(CPACK_IFW_COMPONENT_CMCLDEPS_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ # Dialogs
+ set(CPACK_COMPONENT_GROUP_DIALOGS_DISPLAY_NAME "Interactive Dialogs")
+ set(CPACK_COMPONENT_GROUP_DIALOGS_DESCRIPTION
+ "Interactive Dialogs with Console and GUI interfaces")
+ set(CPACK_COMPONENT_GROUP_DIALOGS_PARENT_GROUP CMake)
+ set(CPACK_IFW_COMPONENT_GROUP_DIALOGS_PRIORITY 80)
+ set(CPACK_IFW_COMPONENT_GROUP_DIALOGS_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ set(CPACK_COMPONENT_CMAKE-GUI_DISPLAY_NAME "cmake-gui")
+ set(CPACK_COMPONENT_CMAKE-GUI_GROUP Dialogs)
+ set(CPACK_IFW_COMPONENT_CMAKE-GUI_NAME "QtGUI")
+ set(CPACK_IFW_COMPONENT_CMAKE-GUI_SCRIPT
+ "@CMake_BINARY_DIR@/CMake.Dialogs.QtGUI.qs")
+ set(CPACK_IFW_COMPONENT_CMAKE-GUI_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+ @_CPACK_IFW_COMPONENT_CMAKE-GUI_LICENSES@
+
+ set(CPACK_COMPONENT_CCMAKE_DISPLAY_NAME "ccmake")
+ set(CPACK_COMPONENT_CCMAKE_GROUP Dialogs)
+ set(CPACK_IFW_COMPONENT_CCMAKE_NAME "CursesGUI")
+ set(CPACK_IFW_COMPONENT_CCMAKE_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ # Documentation
+ set(CPACK_COMPONENT_GROUP_DOCUMENTATION_DISPLAY_NAME "Documentation")
+ set(CPACK_COMPONENT_GROUP_DOCUMENTATION_DESCRIPTION
+ "CMake Documentation in different formats (html, man, qch)")
+ set(CPACK_COMPONENT_GROUP_DOCUMENTATION_PARENT_GROUP CMake)
+ set(CPACK_IFW_COMPONENT_GROUP_DOCUMENTATION_PRIORITY 60)
+ set(CPACK_IFW_COMPONENT_GROUP_DOCUMENTATION_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ set(CPACK_COMPONENT_SPHINX-MAN_DISPLAY_NAME "man")
+ set(CPACK_COMPONENT_SPHINX-MAN_GROUP Documentation)
+ set(CPACK_COMPONENT_SPHINX-MAN_DISABLED TRUE)
+ set(CPACK_IFW_COMPONENT_SPHINX-MAN_NAME "SphinxMan")
+ set(CPACK_IFW_COMPONENT_SPHINX-MAN_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ set(CPACK_COMPONENT_SPHINX-HTML_DISPLAY_NAME "HTML")
+ set(CPACK_COMPONENT_SPHINX-HTML_GROUP Documentation)
+ set(CPACK_IFW_COMPONENT_SPHINX-HTML_NAME "SphinxHTML")
+ set(CPACK_IFW_COMPONENT_SPHINX-HTML_SCRIPT
+ "@CMake_BINARY_DIR@/CMake.Documentation.SphinxHTML.qs")
+ set(CPACK_IFW_COMPONENT_SPHINX-HTML_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ set(CPACK_COMPONENT_SPHINX-SINGLEHTML_DISPLAY_NAME "Single HTML")
+ set(CPACK_COMPONENT_SPHINX-SINGLEHTML_GROUP Documentation)
+ set(CPACK_COMPONENT_SPHINX-SINGLEHTML_DISABLED TRUE)
+ set(CPACK_IFW_COMPONENT_SPHINX-SINGLEHTML_NAME "SphinxSingleHTML")
+ set(CPACK_IFW_COMPONENT_SPHINX-SINGLEHTML_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ set(CPACK_COMPONENT_SPHINX-QTHELP_DISPLAY_NAME "Qt Compressed Help")
+ set(CPACK_COMPONENT_SPHINX-QTHELP_GROUP Documentation)
+ set(CPACK_COMPONENT_SPHINX-QTHELP_DISABLED TRUE)
+ set(CPACK_IFW_COMPONENT_SPHINX-QTHELP_NAME "SphinxQtHelp")
+ set(CPACK_IFW_COMPONENT_SPHINX-QTHELP_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ # Developer Reference
+ set(CPACK_COMPONENT_GROUP_DEVELOPERREFERENCE_DISPLAY_NAME "Developer Reference")
+ set(CPACK_COMPONENT_GROUP_DEVELOPERREFERENCE_DESCRIPTION
+ "CMake Reference in different formats (html, qch)")
+ set(CPACK_COMPONENT_GROUP_DEVELOPERREFERENCE_PARENT_GROUP CMake)
+ set(CPACK_IFW_COMPONENT_GROUP_DEVELOPERREFERENCE_PRIORITY 50)
+ set(CPACK_IFW_COMPONENT_GROUP_DEVELOPERREFERENCE_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ set(CPACK_COMPONENT_CMAKE-DEVELOPER-REFERENCE-HTML_DISPLAY_NAME "HTML")
+ set(CPACK_COMPONENT_CMAKE-DEVELOPER-REFERENCE-HTML_GROUP DeveloperReference)
+ set(CPACK_COMPONENT_CMAKE-DEVELOPER-REFERENCE-HTML_DISABLED TRUE)
+ set(CPACK_IFW_COMPONENT_CMAKE-DEVELOPER-REFERENCE-HTML_NAME "HTML")
+ set(CPACK_IFW_COMPONENT_CMAKE-DEVELOPER-REFERENCE-HTML_SCRIPT
+ "@CMake_BINARY_DIR@/CMake.DeveloperReference.HTML.qs")
+ set(CPACK_IFW_COMPONENT_CMAKE-DEVELOPER-REFERENCE-HTML_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+ set(CPACK_COMPONENT_CMAKE-DEVELOPER-REFERENCE-QTHELP_DISPLAY_NAME "Qt Compressed Help")
+ set(CPACK_COMPONENT_CMAKE-DEVELOPER-REFERENCE-QTHELP_GROUP DeveloperReference)
+ set(CPACK_COMPONENT_CMAKE-DEVELOPER-REFERENCE-QTHELP_DISABLED TRUE)
+ set(CPACK_IFW_COMPONENT_CMAKE-DEVELOPER-REFERENCE-QTHELP_NAME "QtHelp")
+ set(CPACK_IFW_COMPONENT_CMAKE-DEVELOPER-REFERENCE-QTHELP_VERSION
+ "@CMake_IFW_ROOT_COMPONENT_VERSION@")
+
+endif()
+
+if("${CPACK_GENERATOR}" STREQUAL "PackageMaker")
+ if(CMAKE_PACKAGE_QTGUI)
+ set(CPACK_PACKAGE_DEFAULT_LOCATION "/Applications")
+ else()
+ set(CPACK_PACKAGE_DEFAULT_LOCATION "/usr")
+ endif()
+endif()
+
+if("${CPACK_GENERATOR}" STREQUAL "DragNDrop")
+ set(CPACK_DMG_BACKGROUND_IMAGE
+ "@CMake_SOURCE_DIR@/Packaging/CMakeDMGBackground.tif")
+ set(CPACK_DMG_DS_STORE_SETUP_SCRIPT
+ "@CMake_SOURCE_DIR@/Packaging/CMakeDMGSetup.scpt")
+endif()
+
+if("${CPACK_GENERATOR}" STREQUAL "WIX")
+ # Reset CPACK_PACKAGE_VERSION to deal with WiX restriction.
+ # But the file names still use the full CMake_VERSION value:
+ set(CPACK_PACKAGE_FILE_NAME
+ "cmake-@CMake_VERSION@-${CPACK_SYSTEM_NAME}")
+ set(CPACK_SOURCE_PACKAGE_FILE_NAME
+ "cmake-@CMake_VERSION@")
+
+ if(NOT CPACK_WIX_SIZEOF_VOID_P)
+ set(CPACK_WIX_SIZEOF_VOID_P "@CMAKE_SIZEOF_VOID_P@")
+ endif()
+
+ set(CPACK_PACKAGE_VERSION
+ "@CMake_VERSION_MAJOR@.@CMake_VERSION_MINOR@")
+ # WIX installers require at most a 4 component version number, where
+ # each component is an integer between 0 and 65534 inclusive
+ set(patch "@CMake_VERSION_PATCH@")
+ if(patch MATCHES "^[0-9]+$" AND patch LESS 65535)
+ set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}.${patch}")
+ endif()
+
+ set(CPACK_WIX_PROPERTY_ARPURLINFOABOUT "https://cmake.org")
+
+ set(CPACK_WIX_PROPERTY_ARPCONTACT "@CPACK_PACKAGE_CONTACT@")
+
+ set(CPACK_WIX_PROPERTY_ARPCOMMENTS
+ "CMake is a cross-platform, open-source build system."
+ )
+
+ set(CPACK_WIX_PRODUCT_ICON
+ "@CMake_SOURCE_DIR@/Utilities/Release/CMakeLogo.ico"
+ )
+
+ set_property(INSTALL "@CMAKE_DOC_DIR@/html/index.html" PROPERTY
+ CPACK_START_MENU_SHORTCUTS "CMake Documentation"
+ )
+
+ set_property(INSTALL "cmake.org.html" PROPERTY
+ CPACK_START_MENU_SHORTCUTS "CMake Web Site"
+ )
+
+ set(CPACK_WIX_LIGHT_EXTRA_FLAGS "-dcl:high")
+
+ set(CPACK_WIX_UI_BANNER
+ "@CMake_SOURCE_DIR@/Utilities/Release/WiX/ui_banner.jpg"
+ )
+
+ set(CPACK_WIX_UI_DIALOG
+ "@CMake_SOURCE_DIR@/Utilities/Release/WiX/ui_dialog.jpg"
+ )
+
+ set(CPACK_WIX_EXTRA_SOURCES
+ "@CMake_SOURCE_DIR@/Utilities/Release/WiX/install_dir.wxs"
+ "@CMake_SOURCE_DIR@/Utilities/Release/WiX/cmake_extra_dialog.wxs"
+ )
+
+ set(_WIX_CUSTOM_ACTION_ENABLED "@WIX_CUSTOM_ACTION_ENABLED@")
+ if(_WIX_CUSTOM_ACTION_ENABLED)
+ list(APPEND CPACK_WIX_EXTRA_SOURCES
+ "@CMake_SOURCE_DIR@/Utilities/Release/WiX/cmake_nsis_overwrite_dialog.wxs"
+ )
+ list(APPEND CPACK_WIX_CANDLE_EXTRA_FLAGS -dCHECK_NSIS=1)
+
+ set(_WIX_CUSTOM_ACTION_MULTI_CONFIG "@WIX_CUSTOM_ACTION_MULTI_CONFIG@")
+ if(_WIX_CUSTOM_ACTION_MULTI_CONFIG)
+ if(CPACK_BUILD_CONFIG)
+ set(_WIX_CUSTOM_ACTION_CONFIG "${CPACK_BUILD_CONFIG}")
+ else()
+ set(_WIX_CUSTOM_ACTION_CONFIG "Release")
+ endif()
+
+ list(APPEND CPACK_WIX_EXTRA_SOURCES
+ "@CMake_BINARY_DIR@/Utilities/Release/WiX/custom_action_dll-${_WIX_CUSTOM_ACTION_CONFIG}.wxs")
+ else()
+ list(APPEND CPACK_WIX_EXTRA_SOURCES
+ "@CMake_BINARY_DIR@/Utilities/Release/WiX/custom_action_dll.wxs")
+ endif()
+ endif()
+
+ set(CPACK_WIX_UI_REF "CMakeUI_InstallDir")
+
+ set(CPACK_WIX_PATCH_FILE
+ "@CMake_SOURCE_DIR@/Utilities/Release/WiX/patch_path_env.xml"
+ )
+
+ set(CPACK_WIX_TEMPLATE
+ "@CMake_SOURCE_DIR@/Utilities/Release/WiX/WIX.template.in"
+ )
+
+ set(BUILD_QtDialog "@BUILD_QtDialog@")
+
+ if(BUILD_QtDialog)
+ list(APPEND CPACK_WIX_PATCH_FILE
+ "@CMake_SOURCE_DIR@/Utilities/Release/WiX/patch_desktop_shortcut.xml"
+ )
+ list(APPEND CPACK_WIX_CANDLE_EXTRA_FLAGS -dBUILD_QtDialog=1)
+ endif()
+endif()
diff --git a/CMakeGraphVizOptions.cmake b/CMakeGraphVizOptions.cmake
new file mode 100644
index 0000000..1add78c
--- /dev/null
+++ b/CMakeGraphVizOptions.cmake
@@ -0,0 +1 @@
+set(GRAPHVIZ_IGNORE_TARGETS "tartest;testSystemTools;testRegistry;testProcess;testIOS;testHashSTL;testFail;testCommandLineArguments;xrtest;LIBCURL;foo")
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bf8543e..045a283 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,1147 +1,887 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
-# file Copyright.txt or https://cmake.org/licensing#kwsys for details.
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.1...3.19 FATAL_ERROR)
+set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideC.cmake)
+set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideCXX.cmake)
+project(CMake)
+unset(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX)
+unset(CMAKE_USER_MAKE_RULES_OVERRIDE_C)
+
+# FIXME: This block should go away after a transition period.
+if(MSVC AND NOT CMAKE_VERSION VERSION_LESS 3.15)
+ # Filter out MSVC runtime library flags that may have come from
+ # the cache of an existing build tree or from scripts.
+ foreach(l C CXX)
+ foreach(c DEBUG MINSIZEREL RELEASE RELWITHDEBINFO)
+ string(REGEX REPLACE "[-/]M[DT]d?( |$)" "" "CMAKE_${l}_FLAGS_${c}" "${CMAKE_${l}_FLAGS_${c}}")
+ endforeach()
+ endforeach()
+endif()
-# The Kitware System Library is intended to be included in other
-# projects. It is completely configurable in that the library's
-# namespace can be configured and the components that are included can
-# be selected invididually.
+# Make sure we can find internal find_package modules only used for
+# building CMake and not for shipping externally
+list(INSERT CMAKE_MODULE_PATH 0 ${CMake_SOURCE_DIR}/Source/Modules)
-# Typical usage is to import the kwsys directory tree into a
-# subdirectory under a parent project and enable the classes that will
-# be used. All classes are disabled by default. The CMake listfile
-# above this one configures the library as follows:
-#
-# set(KWSYS_NAMESPACE foosys)
-# set(KWSYS_USE_Directory 1) # Enable Directory class.
-# add_subdirectory(kwsys)
-#
-# Optional settings are as follows:
-#
-# KWSYS_HEADER_ROOT = The directory into which to generate the kwsys headers.
-# A directory called "${KWSYS_NAMESPACE}" will be
-# created under this root directory to hold the files.
-# KWSYS_SPLIT_OBJECTS_FROM_INTERFACE
-# = Instead of creating a single ${KWSYS_NAMESPACE} library
-# target, create three separate targets:
-# ${KWSYS_NAMESPACE}
-# - An INTERFACE library only containing usage
-# requirements.
-# ${KWSYS_NAMESPACE}_objects
-# - An OBJECT library for the built kwsys objects.
-# Note: This is omitted from the install rules
-# ${KWSYS_NAMESPACE}_private
-# - An INTERFACE library combining both that is
-# appropriate for use with PRIVATE linking in
-# target_link_libraries. Because of how interface
-# properties propagate, this target is not suitable
-# for use with PUBLIC or INTERFACE linking.
-# KWSYS_ALIAS_TARGET = The name of an alias target to create to the actual target.
-#
-# Example:
-#
-# set(KWSYS_HEADER_ROOT ${PROJECT_BINARY_DIR})
-# include_directories(${PROJECT_BINARY_DIR})
-#
-# KWSYS_CXX_STANDARD = A value for CMAKE_CXX_STANDARD within KWSys.
-# Set to empty string to use no default value.
-# KWSYS_CXX_COMPILE_FEATURES = target_compile_features arguments for KWSys.
-#
-# Optional settings to setup install rules are as follows:
-#
-# KWSYS_INSTALL_BIN_DIR = The installation target directories into
-# KWSYS_INSTALL_LIB_DIR which the libraries and headers from
-# KWSYS_INSTALL_INCLUDE_DIR kwsys should be installed by a "make install".
-# The values should be specified relative to
-# the installation prefix and NOT start with '/'.
-# KWSYS_INSTALL_DOC_DIR = The installation target directory for documentation
-# such as copyright information.
-#
-# KWSYS_INSTALL_COMPONENT_NAME_RUNTIME = Name of runtime and development
-# KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT installation components.
-# If not given the install rules
-# will not be in any component.
-#
-# KWSYS_INSTALL_EXPORT_NAME = The EXPORT option value for install(TARGETS) calls.
-#
-# Example:
-#
-# set(KWSYS_INSTALL_BIN_DIR bin)
-# set(KWSYS_INSTALL_LIB_DIR lib)
-# set(KWSYS_INSTALL_INCLUDE_DIR include)
-# set(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME Runtime)
-# set(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT Development)
+if(CMAKE_BOOTSTRAP)
+ # Running from bootstrap script. Set local variable and remove from cache.
+ set(CMAKE_BOOTSTRAP 1)
+ unset(CMAKE_BOOTSTRAP CACHE)
+endif()
-# Once configured, kwsys should be used as follows from C or C++ code:
-#
-# #include <foosys/Directory.hxx>
-# ...
-# foosys::Directory directory;
-#
+if(CMake_TEST_HOST_CMAKE)
+ get_filename_component(CMake_TEST_EXTERNAL_CMAKE "${CMAKE_COMMAND}" DIRECTORY)
+endif()
-# NOTE: This library is intended for internal use by Kitware-driven
-# projects. In order to keep it simple no attempt will be made to
-# maintain backward compatibility when changes are made to KWSys.
-# When an incompatible change is made Kitware's projects that use
-# KWSys will be fixed, but no notification will necessarily be sent to
-# any outside mailing list and no documentation of the change will be
-# written.
-
-cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
-foreach(p
- CMP0056 # CMake 3.2, Honor link flags in try_compile() source-file signature.
- CMP0063 # CMake 3.3, Honor visibility properties for all target types.
- CMP0067 # CMake 3.8, Honor language standard in try_compile source-file signature.
- CMP0069 # CMake 3.9, INTERPROCEDURAL_OPTIMIZATION is enforced when enabled.
- )
- if(POLICY ${p})
- cmake_policy(SET ${p} NEW)
+if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ if(CMAKE_SYSTEM_NAME STREQUAL "HP-UX")
+ message(FATAL_ERROR
+ "CMake no longer compiles on HP-UX. See\n"
+ " https://gitlab.kitware.com/cmake/cmake/-/issues/17137\n"
+ "Use CMake 3.9 or lower instead."
+ )
endif()
-endforeach()
-
-#-----------------------------------------------------------------------------
-# If a namespace is not specified, use "kwsys" and enable testing.
-# This should be the case only when kwsys is not included inside
-# another project and is being tested.
-if(NOT KWSYS_NAMESPACE)
- set(KWSYS_NAMESPACE "kwsys")
- set(KWSYS_STANDALONE 1)
+
+ set(CMake_BIN_DIR ${CMake_BINARY_DIR}/bin)
endif()
-#-----------------------------------------------------------------------------
-# The project name is that of the specified namespace.
-project(${KWSYS_NAMESPACE})
-
-# Tell CMake how to follow dependencies of sources in this directory.
-set_property(DIRECTORY
- PROPERTY IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
- "KWSYS_HEADER(%)=<${KWSYS_NAMESPACE}/%>"
- )
-
-if(KWSYS_CXX_STANDARD)
- set(CMAKE_CXX_STANDARD "${KWSYS_CXX_STANDARD}")
-elseif(NOT DEFINED CMAKE_CXX_STANDARD AND NOT DEFINED KWSYS_CXX_STANDARD)
- if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
- AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC"
- AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU"
- )
- set(CMAKE_CXX_STANDARD 14)
+if(CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL)
+ if(CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL MATCHES "^3|2\\.1$")
+ set(USE_LGPL "${CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL}")
else()
- set(CMAKE_CXX_STANDARD 11)
+ set(USE_LGPL "2.1")
endif()
+else()
+ set(USE_LGPL "")
endif()
-# Select library components.
-if(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
- set(KWSYS_ENABLE_C 1)
- # Enable all components.
- set(KWSYS_USE_Base64 1)
- set(KWSYS_USE_Directory 1)
- set(KWSYS_USE_DynamicLoader 1)
- set(KWSYS_USE_Encoding 1)
- set(KWSYS_USE_Glob 1)
- set(KWSYS_USE_MD5 1)
- set(KWSYS_USE_Process 1)
- set(KWSYS_USE_RegularExpression 1)
- set(KWSYS_USE_Status 1)
- set(KWSYS_USE_System 1)
- set(KWSYS_USE_SystemTools 1)
- set(KWSYS_USE_CommandLineArguments 1)
- set(KWSYS_USE_Terminal 1)
- set(KWSYS_USE_FStream 1)
- set(KWSYS_USE_String 1)
- set(KWSYS_USE_SystemInformation 1)
- set(KWSYS_USE_ConsoleBuf 1)
+if("${CMake_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
+ # Disallow architecture-specific try_run. It may not run on the host.
+ macro(TRY_RUN)
+ if(CMAKE_TRY_COMPILE_OSX_ARCHITECTURES)
+ message(FATAL_ERROR "TRY_RUN not allowed with CMAKE_TRY_COMPILE_OSX_ARCHITECTURES=[${CMAKE_TRY_COMPILE_OSX_ARCHITECTURES}]")
+ else()
+ _TRY_RUN(${ARGV})
+ endif()
+ endmacro()
endif()
-# Enforce component dependencies.
-if(KWSYS_USE_SystemTools)
- set(KWSYS_USE_Directory 1)
- set(KWSYS_USE_FStream 1)
- set(KWSYS_USE_Encoding 1)
- set(KWSYS_USE_Status 1)
-endif()
-if(KWSYS_USE_Glob)
- set(KWSYS_USE_Directory 1)
- set(KWSYS_USE_SystemTools 1)
- set(KWSYS_USE_RegularExpression 1)
- set(KWSYS_USE_FStream 1)
- set(KWSYS_USE_Encoding 1)
-endif()
-if(KWSYS_USE_Process)
- set(KWSYS_USE_System 1)
- set(KWSYS_USE_Encoding 1)
-endif()
-if(KWSYS_USE_SystemInformation)
- set(KWSYS_USE_Process 1)
-endif()
-if(KWSYS_USE_System)
- set(KWSYS_USE_Encoding 1)
-endif()
-if(KWSYS_USE_Directory)
- set(KWSYS_USE_Encoding 1)
- set(KWSYS_USE_Status 1)
-endif()
-if(KWSYS_USE_DynamicLoader)
- set(KWSYS_USE_Encoding 1)
-endif()
-if(KWSYS_USE_FStream)
- set(KWSYS_USE_Encoding 1)
+# Use most-recent available language dialects with GNU and Clang
+if(NOT DEFINED CMAKE_C_STANDARD AND NOT CMake_NO_C_STANDARD)
+ include(${CMake_SOURCE_DIR}/Source/Checks/cm_c11_thread_local.cmake)
+ if(NOT CMake_C11_THREAD_LOCAL_BROKEN)
+ set(CMAKE_C_STANDARD 11)
+ else()
+ set(CMAKE_C_STANDARD 99)
+ endif()
endif()
-if(KWSYS_USE_ConsoleBuf)
- set(KWSYS_USE_Encoding 1)
+if(NOT DEFINED CMAKE_CXX_STANDARD AND NOT CMake_NO_CXX_STANDARD)
+ if (CMAKE_CXX_COMPILER_ID STREQUAL SunPro AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.14)
+ set(CMAKE_CXX_STANDARD 98)
+ else()
+ if(NOT CMAKE_VERSION VERSION_LESS 3.8)
+ include(${CMake_SOURCE_DIR}/Source/Checks/cm_cxx17_check.cmake)
+ else()
+ set(CMake_CXX17_BROKEN 1)
+ endif()
+ if(NOT CMake_CXX17_BROKEN)
+ set(CMAKE_CXX_STANDARD 17)
+ else()
+ include(${CMake_SOURCE_DIR}/Source/Checks/cm_cxx14_check.cmake)
+ if(NOT CMake_CXX14_BROKEN)
+ set(CMAKE_CXX_STANDARD 14)
+ else()
+ set(CMAKE_CXX_STANDARD 11)
+ endif()
+ endif()
+ endif()
endif()
+if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ # include special compile flags for some compilers
+ include(CompileFlags.cmake)
-# Specify default 8 bit encoding for Windows
-if(NOT KWSYS_ENCODING_DEFAULT_CODEPAGE)
- set(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_ACP)
-endif()
+ # check for available C++ features
+ include(${CMake_SOURCE_DIR}/Source/Checks/cm_cxx_features.cmake)
-# Enable testing if building standalone.
-if(KWSYS_STANDALONE)
- include(Dart)
- mark_as_advanced(BUILD_TESTING DART_ROOT TCL_TCLSH)
- if(BUILD_TESTING)
- enable_testing()
+ if(NOT CMake_HAVE_CXX_UNIQUE_PTR)
+ message(FATAL_ERROR "The C++ compiler does not support C++11 (e.g. std::unique_ptr).")
endif()
endif()
-# Choose default shared/static build if not specified.
-if(NOT DEFINED KWSYS_BUILD_SHARED)
- set(KWSYS_BUILD_SHARED ${BUILD_SHARED_LIBS})
-endif()
-
-# Include helper macros.
-include(${CMAKE_CURRENT_SOURCE_DIR}/kwsysPlatformTests.cmake)
-include(CheckTypeSize)
-
-# Do full dependency headers.
-include_regular_expression("^.*$")
+# Inform STL library header wrappers whether to use system versions.
+configure_file(${CMake_SOURCE_DIR}/Utilities/std/cmSTL.hxx.in
+ ${CMake_BINARY_DIR}/Utilities/cmSTL.hxx
+ @ONLY)
-# Use new KWSYS_INSTALL_*_DIR variable names to control installation.
-# Take defaults from the old names. Note that there was no old name
-# for the bin dir, so we take the old lib dir name so DLLs will be
-# installed in a compatible way for old code.
-if(NOT KWSYS_INSTALL_INCLUDE_DIR)
- string(REGEX REPLACE "^/" "" KWSYS_INSTALL_INCLUDE_DIR
- "${KWSYS_HEADER_INSTALL_DIR}")
-endif()
-if(NOT KWSYS_INSTALL_LIB_DIR)
- string(REGEX REPLACE "^/" "" KWSYS_INSTALL_LIB_DIR
- "${KWSYS_LIBRARY_INSTALL_DIR}")
-endif()
-if(NOT KWSYS_INSTALL_BIN_DIR)
- string(REGEX REPLACE "^/" "" KWSYS_INSTALL_BIN_DIR
- "${KWSYS_LIBRARY_INSTALL_DIR}")
-endif()
+# set the internal encoding of CMake to UTF-8
+set(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_UTF8)
-# Setup header install rules.
-set(KWSYS_INSTALL_INCLUDE_OPTIONS)
-if(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT)
- set(KWSYS_INSTALL_INCLUDE_OPTIONS ${KWSYS_INSTALL_INCLUDE_OPTIONS}
- COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT}
- )
-endif()
+# option to use COMPONENT with install command
+option(CMake_INSTALL_COMPONENTS "Using components when installing" OFF)
+mark_as_advanced(CMake_INSTALL_COMPONENTS)
+macro(CMake_OPTIONAL_COMPONENT NAME)
+ if(CMake_INSTALL_COMPONENTS)
+ set(COMPONENT COMPONENT ${NAME})
+ else()
+ set(COMPONENT)
+ endif()
+endmacro()
+
+# option to disable installing 3rd-party dependencies
+option(CMake_INSTALL_DEPENDENCIES
+ "Whether to install 3rd-party runtime dependencies" OFF)
+mark_as_advanced(CMake_INSTALL_DEPENDENCIES)
+
+# option to build reference for CMake developers
+option(CMake_BUILD_DEVELOPER_REFERENCE
+ "Build CMake Developer Reference" OFF)
+mark_as_advanced(CMake_BUILD_DEVELOPER_REFERENCE)
+
+# option to build using interprocedural optimizations (IPO/LTO)
+if (NOT CMAKE_VERSION VERSION_LESS 3.12.2)
+ option(CMake_BUILD_LTO "Compile CMake with link-time optimization if supported" OFF)
+ if(CMake_BUILD_LTO)
+ include(CheckIPOSupported)
+ check_ipo_supported(RESULT HAVE_IPO)
+ if(HAVE_IPO)
+ set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
+ endif()
+ endif()
+endif()
+
+#-----------------------------------------------------------------------
+# a macro to deal with system libraries, implemented as a macro
+# simply to improve readability of the main script
+#-----------------------------------------------------------------------
+macro(CMAKE_HANDLE_SYSTEM_LIBRARIES)
+ # Options have dependencies.
+ include(CMakeDependentOption)
+
+ # Allow the user to enable/disable all system utility library options by
+ # defining CMAKE_USE_SYSTEM_LIBRARIES or CMAKE_USE_SYSTEM_LIBRARY_${util}.
+ set(UTILITIES BZIP2 CURL EXPAT FORM JSONCPP LIBARCHIVE LIBLZMA LIBRHASH LIBUV NGHTTP2 ZLIB ZSTD)
+ foreach(util ${UTILITIES})
+ if(NOT DEFINED CMAKE_USE_SYSTEM_LIBRARY_${util}
+ AND DEFINED CMAKE_USE_SYSTEM_LIBRARIES)
+ set(CMAKE_USE_SYSTEM_LIBRARY_${util} "${CMAKE_USE_SYSTEM_LIBRARIES}")
+ endif()
+ if(DEFINED CMAKE_USE_SYSTEM_LIBRARY_${util})
+ if(CMAKE_USE_SYSTEM_LIBRARY_${util})
+ set(CMAKE_USE_SYSTEM_LIBRARY_${util} ON)
+ else()
+ set(CMAKE_USE_SYSTEM_LIBRARY_${util} OFF)
+ endif()
+ if(CMAKE_BOOTSTRAP)
+ unset(CMAKE_USE_SYSTEM_LIBRARY_${util} CACHE)
+ endif()
+ string(TOLOWER "${util}" lutil)
+ set(CMAKE_USE_SYSTEM_${util} "${CMAKE_USE_SYSTEM_LIBRARY_${util}}"
+ CACHE BOOL "Use system-installed ${lutil}" FORCE)
+ else()
+ set(CMAKE_USE_SYSTEM_LIBRARY_${util} OFF)
+ endif()
+ endforeach()
+ if(CMAKE_BOOTSTRAP)
+ unset(CMAKE_USE_SYSTEM_LIBRARIES CACHE)
+ endif()
+
+ # Optionally use system utility libraries.
+ option(CMAKE_USE_SYSTEM_LIBARCHIVE "Use system-installed libarchive" "${CMAKE_USE_SYSTEM_LIBRARY_LIBARCHIVE}")
+ option(CMAKE_USE_SYSTEM_CURL "Use system-installed curl" "${CMAKE_USE_SYSTEM_LIBRARY_CURL}")
+ option(CMAKE_USE_SYSTEM_EXPAT "Use system-installed expat" "${CMAKE_USE_SYSTEM_LIBRARY_EXPAT}")
+ CMAKE_DEPENDENT_OPTION(CMAKE_USE_SYSTEM_ZLIB "Use system-installed zlib"
+ "${CMAKE_USE_SYSTEM_LIBRARY_ZLIB}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE;NOT CMAKE_USE_SYSTEM_CURL" ON)
+ CMAKE_DEPENDENT_OPTION(CMAKE_USE_SYSTEM_BZIP2 "Use system-installed bzip2"
+ "${CMAKE_USE_SYSTEM_LIBRARY_BZIP2}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE" ON)
+ CMAKE_DEPENDENT_OPTION(CMAKE_USE_SYSTEM_ZSTD "Use system-installed zstd"
+ "${CMAKE_USE_SYSTEM_LIBRARY_ZSTD}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE" ON)
+ CMAKE_DEPENDENT_OPTION(CMAKE_USE_SYSTEM_LIBLZMA "Use system-installed liblzma"
+ "${CMAKE_USE_SYSTEM_LIBRARY_LIBLZMA}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE" ON)
+ CMAKE_DEPENDENT_OPTION(CMAKE_USE_SYSTEM_NGHTTP2 "Use system-installed nghttp2"
+ "${CMAKE_USE_SYSTEM_LIBRARY_NGHTTP2}" "NOT CMAKE_USE_SYSTEM_CURL" ON)
+ option(CMAKE_USE_SYSTEM_FORM "Use system-installed libform" "${CMAKE_USE_SYSTEM_LIBRARY_FORM}")
+ option(CMAKE_USE_SYSTEM_JSONCPP "Use system-installed jsoncpp" "${CMAKE_USE_SYSTEM_LIBRARY_JSONCPP}")
+ option(CMAKE_USE_SYSTEM_LIBRHASH "Use system-installed librhash" "${CMAKE_USE_SYSTEM_LIBRARY_LIBRHASH}")
+ option(CMAKE_USE_SYSTEM_LIBUV "Use system-installed libuv" "${CMAKE_USE_SYSTEM_LIBRARY_LIBUV}")
+
+ # For now use system KWIML only if explicitly requested rather
+ # than activating via the general system libs options.
+ option(CMAKE_USE_SYSTEM_KWIML "Use system-installed KWIML" OFF)
+ mark_as_advanced(CMAKE_USE_SYSTEM_KWIML)
+
+ # Mention to the user what system libraries are being used.
+ foreach(util ${UTILITIES} KWIML)
+ if(CMAKE_USE_SYSTEM_${util})
+ message(STATUS "Using system-installed ${util}")
+ endif()
+ endforeach()
+
+ # Inform utility library header wrappers whether to use system versions.
+ configure_file(${CMake_SOURCE_DIR}/Utilities/cmThirdParty.h.in
+ ${CMake_BINARY_DIR}/Utilities/cmThirdParty.h
+ @ONLY)
+
+endmacro()
+
+#-----------------------------------------------------------------------
+# a macro to determine the generator and ctest executable to use
+# for testing. Simply to improve readability of the main script.
+#-----------------------------------------------------------------------
+macro(CMAKE_SETUP_TESTING)
+ if(BUILD_TESTING)
+ set(CMAKE_TEST_SYSTEM_LIBRARIES 0)
+ foreach(util CURL EXPAT ZLIB)
+ if(CMAKE_USE_SYSTEM_${util})
+ set(CMAKE_TEST_SYSTEM_LIBRARIES 1)
+ endif()
+ endforeach()
-# Setup library install rules.
-set(KWSYS_INSTALL_LIBRARY_RULE)
-set(KWSYS_INSTALL_NAMELINK_RULE)
-if(KWSYS_INSTALL_LIB_DIR)
- if(KWSYS_INSTALL_EXPORT_NAME)
- list(APPEND KWSYS_INSTALL_LIBRARY_RULE EXPORT ${KWSYS_INSTALL_EXPORT_NAME})
- endif()
- # Install the shared library to the lib directory.
- set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
- LIBRARY DESTINATION ${KWSYS_INSTALL_LIB_DIR} NAMELINK_SKIP
- )
- # Assign the shared library to the runtime component.
- if(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME)
- set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
- COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME}
- )
- endif()
- if(KWSYS_BUILD_SHARED)
- set(KWSYS_INSTALL_NAMELINK_RULE ${KWSYS_INSTALL_NAMELINK_RULE}
- LIBRARY DESTINATION ${KWSYS_INSTALL_LIB_DIR} NAMELINK_ONLY
- )
- # Assign the namelink to the development component.
- if(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT)
- set(KWSYS_INSTALL_NAMELINK_RULE ${KWSYS_INSTALL_NAMELINK_RULE}
- COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT}
- )
+ # This variable is set by cmake, however to
+ # test cmake we want to make sure that
+ # the ctest from this cmake is used for testing
+ # and not the ctest from the cmake building and testing
+ # cmake.
+ if(CMake_TEST_EXTERNAL_CMAKE)
+ set(CMAKE_CTEST_COMMAND "${CMake_TEST_EXTERNAL_CMAKE}/ctest")
+ set(CMAKE_CMAKE_COMMAND "${CMake_TEST_EXTERNAL_CMAKE}/cmake")
+ set(CMAKE_CPACK_COMMAND "${CMake_TEST_EXTERNAL_CMAKE}/cpack")
+ foreach(exe cmake ctest cpack)
+ add_executable(${exe} IMPORTED)
+ set_property(TARGET ${exe} PROPERTY IMPORTED_LOCATION ${CMake_TEST_EXTERNAL_CMAKE}/${exe})
+ endforeach()
+ else()
+ set(CMAKE_CTEST_COMMAND "${CMake_BIN_DIR}/ctest")
+ set(CMAKE_CMAKE_COMMAND "${CMake_BIN_DIR}/cmake")
+ set(CMAKE_CPACK_COMMAND "${CMake_BIN_DIR}/cpack")
endif()
endif()
- # Install the archive to the lib directory.
- set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
- ARCHIVE DESTINATION ${KWSYS_INSTALL_LIB_DIR}
- )
- # Assign the archive to the development component.
- if(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT)
- set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
- COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT}
- )
- endif()
-endif()
-if(KWSYS_INSTALL_BIN_DIR)
- # Install the runtime library to the bin directory.
- set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
- RUNTIME DESTINATION ${KWSYS_INSTALL_BIN_DIR}
- )
- # Assign the runtime library to the runtime component.
- if(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME)
- set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
- COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME}
- )
+ # configure some files for testing
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Templates/CTestScript.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/CTestScript.cmake"
+ @ONLY)
+ configure_file(${CMake_SOURCE_DIR}/Tests/.NoDartCoverage
+ ${CMake_BINARY_DIR}/Tests/.NoDartCoverage)
+ configure_file(${CMake_SOURCE_DIR}/Tests/.NoDartCoverage
+ ${CMake_BINARY_DIR}/Modules/.NoDartCoverage)
+ configure_file(${CMake_SOURCE_DIR}/CTestCustom.cmake.in
+ ${CMake_BINARY_DIR}/CTestCustom.cmake @ONLY)
+ if(BUILD_TESTING AND DART_ROOT)
+ configure_file(${CMake_SOURCE_DIR}/CMakeLogo.gif
+ ${CMake_BINARY_DIR}/Testing/HTML/TestingResults/Icons/Logo.gif COPYONLY)
endif()
-endif()
-
-# Do not support old KWSYS_*a_INSTALL_DIR variable names.
-set(KWSYS_HEADER_INSTALL_DIR)
-set(KWSYS_LIBRARY_INSTALL_DIR)
+ mark_as_advanced(DART_ROOT)
+endmacro()
-# Generated source files will need this header.
-string(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}"
- KWSYS_IN_SOURCE_BUILD)
-if(NOT KWSYS_IN_SOURCE_BUILD)
- configure_file(${PROJECT_SOURCE_DIR}/kwsysPrivate.h
- ${PROJECT_BINARY_DIR}/kwsysPrivate.h COPYONLY IMMEDIATE)
-endif()
-# Select plugin module file name convention.
-if(NOT KWSYS_DynamicLoader_PREFIX)
- set(KWSYS_DynamicLoader_PREFIX ${CMAKE_SHARED_MODULE_PREFIX})
-endif()
-if(NOT KWSYS_DynamicLoader_SUFFIX)
- set(KWSYS_DynamicLoader_SUFFIX ${CMAKE_SHARED_MODULE_SUFFIX})
-endif()
+# Provide a way for Visual Studio Express users to turn OFF the new FOLDER
+# organization feature. Default to ON for non-Express users. Express users must
+# explicitly turn off this option to build CMake in the Express IDE...
+#
+option(CMAKE_USE_FOLDERS "Enable folder grouping of projects in IDEs." ON)
+mark_as_advanced(CMAKE_USE_FOLDERS)
-#-----------------------------------------------------------------------------
-# We require ANSI support from the C compiler. Add any needed flags.
-if(CMAKE_ANSI_CFLAGS)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ANSI_CFLAGS}")
-endif()
-#-----------------------------------------------------------------------------
-# Adjust compiler flags for some platforms.
-if(NOT CMAKE_COMPILER_IS_GNUCXX)
- if(CMAKE_SYSTEM MATCHES "OSF1-V.*")
- string(REGEX MATCH "-timplicit_local"
- KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL "${CMAKE_CXX_FLAGS}")
- string(REGEX MATCH "-no_implicit_include"
- KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE "${CMAKE_CXX_FLAGS}")
- if(NOT KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -timplicit_local")
- endif()
- if(NOT KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no_implicit_include")
- endif()
- endif()
- if(CMAKE_SYSTEM MATCHES "HP-UX")
- set(KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS "+p")
- if(CMAKE_CXX_COMPILER_ID MATCHES "HP")
- # it is known that version 3.85 fails and 6.25 works without these flags
- if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4)
- # use new C++ library and improved template support
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -AA +hpxstd98")
- endif()
- endif()
+option(CMake_RUN_CLANG_TIDY "Run clang-tidy with the compiler." OFF)
+if(CMake_RUN_CLANG_TIDY)
+ if(CMake_SOURCE_DIR STREQUAL CMake_BINARY_DIR)
+ message(FATAL_ERROR "CMake_RUN_CLANG_TIDY requires an out-of-source build!")
endif()
-endif()
-if(KWSYS_STANDALONE)
- if(CMAKE_CXX_COMPILER_ID STREQUAL SunPro)
- if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03")
- else()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=stlport4")
- endif()
+ find_program(CLANG_TIDY_COMMAND NAMES clang-tidy)
+ if(NOT CLANG_TIDY_COMMAND)
+ message(FATAL_ERROR "CMake_RUN_CLANG_TIDY is ON but clang-tidy is not found!")
endif()
-endif()
+ set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}")
-#-----------------------------------------------------------------------------
-# Configure the standard library header wrappers based on compiler's
-# capabilities and parent project's request. Enforce 0/1 as only
-# possible values for configuration into Configure.hxx.
+ # Create a preprocessor definition that depends on .clang-tidy content so
+ # the compile command will change when .clang-tidy changes. This ensures
+ # that a subsequent build re-runs clang-tidy on all sources even if they
+ # do not otherwise need to be recompiled. Nothing actually uses this
+ # definition. We add it to targets on which we run clang-tidy just to
+ # get the build dependency on the .clang-tidy file.
+ file(SHA1 ${CMAKE_CURRENT_SOURCE_DIR}/.clang-tidy clang_tidy_sha1)
+ set(CLANG_TIDY_DEFINITIONS "CLANG_TIDY_SHA1=${clang_tidy_sha1}")
+ unset(clang_tidy_sha1)
-if(KWSYS_USE_Encoding)
- # Look for type size helper macros.
- KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_WSTRING
- "Checking whether wstring is available" DIRECT)
endif()
+configure_file(.clang-tidy .clang-tidy COPYONLY)
-if(KWSYS_NAMESPACE MATCHES "^kwsys$")
- set(KWSYS_NAME_IS_KWSYS 1)
-else()
- set(KWSYS_NAME_IS_KWSYS 0)
-endif()
-if(KWSYS_BUILD_SHARED)
- set(KWSYS_BUILD_SHARED 1)
- set(KWSYS_LIBRARY_TYPE SHARED)
-else()
- set(KWSYS_BUILD_SHARED 0)
- set(KWSYS_LIBRARY_TYPE STATIC)
+option(CMake_RUN_IWYU "Run include-what-you-use with the compiler." OFF)
+if(CMake_RUN_IWYU)
+ find_program(IWYU_COMMAND NAMES include-what-you-use iwyu)
+ if(NOT IWYU_COMMAND)
+ message(FATAL_ERROR "CMake_RUN_IWYU is ON but include-what-you-use is not found!")
+ endif()
+ set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE
+ "${IWYU_COMMAND};-Xiwyu;--mapping_file=${CMake_SOURCE_DIR}/Utilities/IWYU/mapping.imp;-w")
+ list(APPEND CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${CMake_IWYU_OPTIONS})
endif()
-if(NOT DEFINED KWSYS_BUILD_PIC)
- set(KWSYS_BUILD_PIC 0)
-endif()
-#-----------------------------------------------------------------------------
-# Configure some implementation details.
+#-----------------------------------------------------------------------
+# a macro that only sets the FOLDER target property if it's
+# "appropriate"
+#-----------------------------------------------------------------------
+macro(CMAKE_SET_TARGET_FOLDER tgt folder)
+ if(CMAKE_USE_FOLDERS)
+ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+ if(MSVC AND TARGET ${tgt})
+ set_property(TARGET "${tgt}" PROPERTY FOLDER "${folder}")
+ endif()
+ else()
+ set_property(GLOBAL PROPERTY USE_FOLDERS OFF)
+ endif()
+endmacro()
-KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_PTRDIFF_T
- "Checking whether C compiler has ptrdiff_t in stddef.h" DIRECT)
-KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_SSIZE_T
- "Checking whether C compiler has ssize_t in unistd.h" DIRECT)
-if(KWSYS_USE_Process)
- KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC
- "Checking whether C compiler has clock_gettime" DIRECT)
-endif()
-set_source_files_properties(ProcessUNIX.c System.c PROPERTIES
- COMPILE_FLAGS "-DKWSYS_C_HAS_PTRDIFF_T=${KWSYS_C_HAS_PTRDIFF_T} -DKWSYS_C_HAS_SSIZE_T=${KWSYS_C_HAS_SSIZE_T} -DKWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC=${KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC}"
- )
+#-----------------------------------------------------------------------
+# a macro to build the utilities used by CMake
+# Simply to improve readability of the main script.
+#-----------------------------------------------------------------------
+macro (CMAKE_BUILD_UTILITIES)
+ find_package(Threads)
-if(DEFINED KWSYS_PROCESS_USE_SELECT)
- get_property(ProcessUNIX_FLAGS SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS)
- set_property(SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS "${ProcessUNIX_FLAGS} -DKWSYSPE_USE_SELECT=${KWSYSPE_USE_SELECT}")
-endif()
+ # Suppress unnecessary checks in third-party code.
+ include(Utilities/cmThirdPartyChecks.cmake)
-if(KWSYS_USE_DynamicLoader)
- get_property(KWSYS_SUPPORTS_SHARED_LIBS GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS)
- if(KWSYS_SUPPORTS_SHARED_LIBS)
- set(KWSYS_SUPPORTS_SHARED_LIBS 1)
+ #---------------------------------------------------------------------
+ # Create the kwsys library for CMake.
+ set(KWSYS_NAMESPACE cmsys)
+ set(KWSYS_USE_SystemTools 1)
+ set(KWSYS_USE_Directory 1)
+ set(KWSYS_USE_RegularExpression 1)
+ set(KWSYS_USE_Base64 1)
+ set(KWSYS_USE_MD5 1)
+ set(KWSYS_USE_Process 1)
+ set(KWSYS_USE_CommandLineArguments 1)
+ set(KWSYS_USE_ConsoleBuf 1)
+ set(KWSYS_HEADER_ROOT ${CMake_BINARY_DIR}/Source)
+ set(KWSYS_INSTALL_DOC_DIR "${CMAKE_DOC_DIR}")
+ if(CMake_NO_CXX_STANDARD)
+ set(KWSYS_CXX_STANDARD "")
+ endif()
+ if(WIN32)
+ # FIXME: Teach KWSys to hard-code these checks on Windows.
+ set(KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC_COMPILED 0)
+ set(KWSYS_C_HAS_PTRDIFF_T_COMPILED 1)
+ set(KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H_COMPILED 1)
+ set(KWSYS_CXX_HAS_RLIMIT64_COMPILED 0)
+ set(KWSYS_CXX_HAS_SETENV_COMPILED 0)
+ set(KWSYS_CXX_HAS_UNSETENV_COMPILED 0)
+ set(KWSYS_CXX_HAS_UTIMENSAT_COMPILED 0)
+ set(KWSYS_CXX_HAS_UTIMES_COMPILED 0)
+ set(KWSYS_CXX_STAT_HAS_ST_MTIM_COMPILED 0)
+ set(KWSYS_CXX_STAT_HAS_ST_MTIMESPEC_COMPILED 0)
+ set(KWSYS_STL_HAS_WSTRING_COMPILED 1)
+ set(KWSYS_SYS_HAS_IFADDRS_H 0)
+ endif()
+ add_subdirectory(Source/kwsys)
+ set(kwsys_folder "Utilities/KWSys")
+ CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE} "${kwsys_folder}")
+ CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}_c "${kwsys_folder}")
+ if(BUILD_TESTING)
+ CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestDynload "${kwsys_folder}")
+ CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestProcess "${kwsys_folder}")
+ CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestsC "${kwsys_folder}")
+ CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestsCxx "${kwsys_folder}")
+ CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestSharedForward "${kwsys_folder}")
+ endif()
+
+ #---------------------------------------------------------------------
+ # Setup third-party libraries.
+ # Everything in the tree should be able to include files from the
+ # Utilities directory.
+ if ((CMAKE_SYSTEM_NAME STREQUAL "AIX" OR CMAKE_SYSTEM_NAME STREQUAL "OS400") AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ # using -isystem option generate error "template with C linkage"
+ include_directories("${CMake_SOURCE_DIR}/Utilities/std")
else()
- set(KWSYS_SUPPORTS_SHARED_LIBS 0)
+ include_directories(SYSTEM "${CMake_SOURCE_DIR}/Utilities/std")
endif()
- set_property(SOURCE DynamicLoader.cxx APPEND PROPERTY COMPILE_DEFINITIONS
- KWSYS_SUPPORTS_SHARED_LIBS=${KWSYS_SUPPORTS_SHARED_LIBS})
-endif()
-if(KWSYS_USE_SystemTools)
- if (NOT DEFINED KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP)
- set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1)
- endif ()
- if (KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP)
- set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1)
- else ()
- set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 0)
- endif ()
- KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_SETENV
- "Checking whether CXX compiler has setenv" DIRECT)
- KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UNSETENV
- "Checking whether CXX compiler has unsetenv" DIRECT)
- KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
- "Checking whether CXX compiler has environ in stdlib.h" DIRECT)
- KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMES
- "Checking whether CXX compiler has utimes" DIRECT)
- KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMENSAT
- "Checking whether CXX compiler has utimensat" DIRECT)
- KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIM
- "Checking whether CXX compiler struct stat has st_mtim member" DIRECT)
- KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIMESPEC
- "Checking whether CXX compiler struct stat has st_mtimespec member" DIRECT)
- set_property(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS
- KWSYS_CXX_HAS_SETENV=${KWSYS_CXX_HAS_SETENV}
- KWSYS_CXX_HAS_UNSETENV=${KWSYS_CXX_HAS_UNSETENV}
- KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=${KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H}
- KWSYS_CXX_HAS_UTIMES=${KWSYS_CXX_HAS_UTIMES}
- KWSYS_CXX_HAS_UTIMENSAT=${KWSYS_CXX_HAS_UTIMENSAT}
- KWSYS_CXX_STAT_HAS_ST_MTIM=${KWSYS_CXX_STAT_HAS_ST_MTIM}
- KWSYS_CXX_STAT_HAS_ST_MTIMESPEC=${KWSYS_CXX_STAT_HAS_ST_MTIMESPEC}
- )
- if(NOT WIN32)
- if(KWSYS_STANDALONE)
- option(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES "If true, Windows paths will be supported on Unix as well" ON)
- endif()
- if(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES)
- set_property(SOURCE SystemTools.cxx testSystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS
- KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES
- )
- endif()
+ include_directories("${CMake_BINARY_DIR}/Utilities")
+ if ((CMAKE_SYSTEM_NAME STREQUAL "AIX" OR CMAKE_SYSTEM_NAME STREQUAL "OS400") AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ # using -isystem option generate error "template with C linkage"
+ include_directories("${CMake_SOURCE_DIR}/Utilities")
+ else()
+ include_directories(SYSTEM "${CMake_SOURCE_DIR}/Utilities")
endif()
- # Disable getpwnam for static linux builds since it depends on shared glibc
- get_property(SHARED_LIBS_SUPPORTED GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS)
- if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT SHARED_LIBS_SUPPORTED)
- set_property(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS
- HAVE_GETPWNAM=0
- )
- endif()
-endif()
+ #---------------------------------------------------------------------
+ # Build CMake std library for CMake and CTest.
+ set(CMAKE_STD_LIBRARY cmstd)
+ add_subdirectory(Utilities/std)
+ CMAKE_SET_TARGET_FOLDER(cmstd "Utilities/std")
-if(KWSYS_USE_SystemInformation)
- set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
- COMPILE_DEFINITIONS SIZEOF_VOID_P=${CMAKE_SIZEOF_VOID_P})
- if(NOT CYGWIN)
- include(CheckIncludeFiles)
- CHECK_INCLUDE_FILES("sys/types.h;ifaddrs.h" KWSYS_SYS_HAS_IFADDRS_H)
- if(KWSYS_SYS_HAS_IFADDRS_H)
- set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
- COMPILE_DEFINITIONS KWSYS_SYS_HAS_IFADDRS_H=1)
- endif()
- endif()
- if(WIN32)
- include(CheckSymbolExists)
- set(CMAKE_REQUIRED_LIBRARIES psapi)
- CHECK_SYMBOL_EXISTS(GetProcessMemoryInfo "windows.h;psapi.h" KWSYS_SYS_HAS_PSAPI)
- unset(CMAKE_REQUIRED_LIBRARIES)
- if(KWSYS_SYS_HAS_PSAPI)
- set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
- COMPILE_DEFINITIONS KWSYS_SYS_HAS_PSAPI=1)
- if(MSVC70 OR MSVC71)
- # Suppress LNK4089: all references to 'PSAPI.DLL' discarded by /OPT:REF
- set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /IGNORE:4089")
- endif()
+ # check for the use of system libraries versus builtin ones
+ # (a macro defined in this file)
+ CMAKE_HANDLE_SYSTEM_LIBRARIES()
+
+ if(CMAKE_USE_SYSTEM_KWIML)
+ find_package(KWIML 1.0)
+ if(NOT KWIML_FOUND)
+ message(FATAL_ERROR "CMAKE_USE_SYSTEM_KWIML is ON but KWIML is not found!")
endif()
- endif()
- if(CMAKE_SYSTEM MATCHES "HP-UX")
- CHECK_INCLUDE_FILES("sys/mpctl.h" KWSYS_SYS_HAS_MPCTL_H)
- if(KWSYS_SYS_HAS_MPCTL_H)
- set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
- COMPILE_DEFINITIONS KWSYS_SYS_HAS_MPCTL_H=1)
+ set(CMake_KWIML_LIBRARIES kwiml::kwiml)
+ else()
+ set(CMake_KWIML_LIBRARIES "")
+ if(BUILD_TESTING)
+ set(KWIML_TEST_ENABLE 1)
endif()
+ add_subdirectory(Utilities/KWIML)
endif()
- if(CMAKE_SYSTEM MATCHES "BSD")
- CHECK_INCLUDE_FILES("machine/cpu.h" KWSYS_SYS_HAS_MACHINE_CPU_H)
- if(KWSYS_SYS_HAS_MACHINE_CPU_H)
- set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
- COMPILE_DEFINITIONS KWSYS_SYS_HAS_MACHINE_CPU_H=1)
+
+ if(CMAKE_USE_SYSTEM_LIBRHASH)
+ find_package(LibRHash)
+ if(NOT LibRHash_FOUND)
+ message(FATAL_ERROR
+ "CMAKE_USE_SYSTEM_LIBRHASH is ON but LibRHash is not found!")
endif()
+ set(CMAKE_LIBRHASH_LIBRARIES LibRHash::LibRHash)
+ else()
+ set(CMAKE_LIBRHASH_LIBRARIES cmlibrhash)
+ add_subdirectory(Utilities/cmlibrhash)
+ CMAKE_SET_TARGET_FOLDER(cmlibrhash "Utilities/3rdParty")
+ endif()
+
+ #---------------------------------------------------------------------
+ # Build zlib library for Curl, CMake, and CTest.
+ set(CMAKE_ZLIB_HEADER "cm_zlib.h")
+ if(CMAKE_USE_SYSTEM_ZLIB)
+ find_package(ZLIB)
+ if(NOT ZLIB_FOUND)
+ message(FATAL_ERROR
+ "CMAKE_USE_SYSTEM_ZLIB is ON but a zlib is not found!")
+ endif()
+ set(CMAKE_ZLIB_INCLUDES ${ZLIB_INCLUDE_DIR})
+ set(CMAKE_ZLIB_LIBRARIES ${ZLIB_LIBRARIES})
+ else()
+ set(CMAKE_ZLIB_INCLUDES ${CMake_SOURCE_DIR}/Utilities)
+ set(CMAKE_ZLIB_LIBRARIES cmzlib)
+ set(WITHOUT_ZLIB_DLL "")
+ set(WITHOUT_ZLIB_DLL_WITH_LIB cmzlib)
+ set(ZLIB_DLL "")
+ set(ZLIB_DLL_WITH_LIB cmzlib)
+ set(ZLIB_WINAPI "")
+ set(ZLIB_WINAPI_COMPILED 0)
+ set(ZLIB_WINAPI_WITH_LIB cmzlib)
+ add_subdirectory(Utilities/cmzlib)
+ CMAKE_SET_TARGET_FOLDER(cmzlib "Utilities/3rdParty")
+ endif()
+
+ #---------------------------------------------------------------------
+ # Build Curl library for CTest.
+ if(CMAKE_USE_SYSTEM_CURL)
+ find_package(CURL)
+ if(NOT CURL_FOUND)
+ message(FATAL_ERROR
+ "CMAKE_USE_SYSTEM_CURL is ON but a curl is not found!")
+ endif()
+ set(CMAKE_CURL_INCLUDES ${CURL_INCLUDE_DIRS})
+ set(CMAKE_CURL_LIBRARIES ${CURL_LIBRARIES})
+ else()
+ set(CURL_SPECIAL_ZLIB_H ${CMAKE_ZLIB_HEADER})
+ set(CURL_SPECIAL_LIBZ_INCLUDES ${CMAKE_ZLIB_INCLUDES})
+ set(CURL_SPECIAL_LIBZ ${CMAKE_ZLIB_LIBRARIES})
+ set(CMAKE_CURL_INCLUDES)
+ set(CMAKE_CURL_LIBRARIES cmcurl)
+ if(CMAKE_TESTS_CDASH_SERVER)
+ set(CMAKE_CURL_TEST_URL "${CMAKE_TESTS_CDASH_SERVER}/user.php")
+ endif()
+ set(_CMAKE_USE_OPENSSL_DEFAULT OFF)
+ if(NOT DEFINED CMAKE_USE_OPENSSL AND NOT WIN32 AND NOT APPLE
+ AND CMAKE_SYSTEM_NAME MATCHES "(Linux|FreeBSD)")
+ set(_CMAKE_USE_OPENSSL_DEFAULT ON)
+ endif()
+ option(CMAKE_USE_OPENSSL "Use OpenSSL." ${_CMAKE_USE_OPENSSL_DEFAULT})
+ mark_as_advanced(CMAKE_USE_OPENSSL)
+ if(CMAKE_USE_OPENSSL)
+ set(CURL_CA_BUNDLE "" CACHE FILEPATH "Path to SSL CA Certificate Bundle")
+ set(CURL_CA_PATH "" CACHE PATH "Path to SSL CA Certificate Directory")
+ mark_as_advanced(CURL_CA_BUNDLE CURL_CA_PATH)
+ endif()
+ if(NOT CMAKE_USE_SYSTEM_NGHTTP2)
+ # Tell curl's FindNGHTTP2 module to use our library.
+ set(NGHTTP2_LIBRARY cmnghttp2)
+ set(NGHTTP2_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/cmnghttp2/lib/includes)
+ endif()
+ add_subdirectory(Utilities/cmcurl)
+ CMAKE_SET_TARGET_FOLDER(cmcurl "Utilities/3rdParty")
+ CMAKE_SET_TARGET_FOLDER(LIBCURL "Utilities/3rdParty")
+ if(NOT CMAKE_USE_SYSTEM_NGHTTP2)
+ # Configure after curl to re-use some check results.
+ add_subdirectory(Utilities/cmnghttp2)
+ CMAKE_SET_TARGET_FOLDER(cmnghttp2 "Utilities/3rdParty")
+ endif()
+ endif()
+
+ #---------------------------------------------------------------------
+ # Build expat library for CMake, CTest, and libarchive.
+ if(CMAKE_USE_SYSTEM_EXPAT)
+ find_package(EXPAT)
+ if(NOT EXPAT_FOUND)
+ message(FATAL_ERROR
+ "CMAKE_USE_SYSTEM_EXPAT is ON but a expat is not found!")
+ endif()
+ set(CMAKE_EXPAT_INCLUDES ${EXPAT_INCLUDE_DIRS})
+ set(CMAKE_EXPAT_LIBRARIES ${EXPAT_LIBRARIES})
+ else()
+ set(CMAKE_EXPAT_INCLUDES)
+ set(CMAKE_EXPAT_LIBRARIES cmexpat)
+ add_subdirectory(Utilities/cmexpat)
+ CMAKE_SET_TARGET_FOLDER(cmexpat "Utilities/3rdParty")
endif()
- KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_RLIMIT64
- "Checking whether CXX compiler has rlimit64" DIRECT)
- set(KWSYS_PLATFORM_CXX_TEST_DEFINES)
- if(KWSYS_CXX_HAS_RLIMIT64)
- set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
- COMPILE_DEFINITIONS KWSYS_CXX_HAS_RLIMIT64=1)
- endif()
- if(UNIX)
- include(CheckIncludeFileCXX)
- # check for simple stack trace
- # usually it's in libc but on FreeBSD
- # it's in libexecinfo
- find_library(EXECINFO_LIB "execinfo")
- mark_as_advanced(EXECINFO_LIB)
- if (NOT EXECINFO_LIB)
- set(EXECINFO_LIB "")
- endif()
- CHECK_INCLUDE_FILE_CXX("execinfo.h" KWSYS_CXX_HAS_EXECINFOH)
- if (KWSYS_CXX_HAS_EXECINFOH)
- # we have the backtrace header check if it
- # can be used with this compiler
- set(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${EXECINFO_LIB})
- KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BACKTRACE
- "Checking whether backtrace works with this C++ compiler" DIRECT)
- set(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES)
- if (KWSYS_CXX_HAS_BACKTRACE)
- # backtrace is supported by this system and compiler.
- # now check for the more advanced capabilities.
- set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
- COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE=1)
- # check for symbol lookup using dladdr
- CHECK_INCLUDE_FILE_CXX("dlfcn.h" KWSYS_CXX_HAS_DLFCNH)
- if (KWSYS_CXX_HAS_DLFCNH)
- # we have symbol lookup libraries and headers
- # check if they can be used with this compiler
- set(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${CMAKE_DL_LIBS})
- KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_DLADDR
- "Checking whether dladdr works with this C++ compiler" DIRECT)
- set(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES)
- if (KWSYS_CXX_HAS_DLADDR)
- # symbol lookup is supported by this system
- # and compiler.
- set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
- COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP=1)
- endif()
- endif()
- # c++ demangling support
- # check for cxxabi headers
- CHECK_INCLUDE_FILE_CXX("cxxabi.h" KWSYS_CXX_HAS_CXXABIH)
- if (KWSYS_CXX_HAS_CXXABIH)
- # check if cxxabi can be used with this
- # system and compiler.
- KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CXXABI
- "Checking whether cxxabi works with this C++ compiler" DIRECT)
- if (KWSYS_CXX_HAS_CXXABI)
- # c++ demangle using cxxabi is supported with
- # this system and compiler
- set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
- COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE=1)
- endif()
- endif()
- # basic backtrace works better with release build
- # don't bother with advanced features for release
- set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
- COMPILE_DEFINITIONS_DEBUG KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1)
- set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
- COMPILE_DEFINITIONS_RELWITHDEBINFO KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1)
+
+ #---------------------------------------------------------------------
+ # Build or use system libbz2 for libarchive.
+ if(NOT CMAKE_USE_SYSTEM_LIBARCHIVE)
+ if(CMAKE_USE_SYSTEM_BZIP2)
+ find_package(BZip2)
+ else()
+ set(BZIP2_INCLUDE_DIR
+ "${CMAKE_CURRENT_SOURCE_DIR}/Utilities/cmbzip2")
+ set(BZIP2_LIBRARIES cmbzip2)
+ set(BZIP2_NEED_PREFIX "")
+ set(USE_BZIP2_DLL "")
+ set(USE_BZIP2_DLL_WITH_LIB cmbzip2)
+ set(USE_BZIP2_STATIC "")
+ set(USE_BZIP2_STATIC_WITH_LIB cmbzip2)
+ add_subdirectory(Utilities/cmbzip2)
+ CMAKE_SET_TARGET_FOLDER(cmbzip2 "Utilities/3rdParty")
+ endif()
+ endif()
+
+ #---------------------------------------------------------------------
+ # Build or use system zstd for libarchive.
+ if(NOT CMAKE_USE_SYSTEM_LIBARCHIVE)
+ if(NOT CMAKE_USE_SYSTEM_ZSTD)
+ set(ZSTD_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Utilities/cmzstd")
+ set(ZSTD_LIBRARY cmzstd)
+ add_subdirectory(Utilities/cmzstd)
+ CMAKE_SET_TARGET_FOLDER(cmzstd "Utilities/3rdParty")
+ endif()
+ endif()
+
+ #---------------------------------------------------------------------
+ # Build or use system liblzma for libarchive.
+ if(NOT CMAKE_USE_SYSTEM_LIBARCHIVE)
+ if(CMAKE_USE_SYSTEM_LIBLZMA)
+ find_package(LibLZMA)
+ if(NOT LIBLZMA_FOUND)
+ message(FATAL_ERROR "CMAKE_USE_SYSTEM_LIBLZMA is ON but LibLZMA is not found!")
endif()
- endif()
- endif()
- if(KWSYS_BUILD_SHARED)
- set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
- COMPILE_DEFINITIONS KWSYS_BUILD_SHARED=1)
+ else()
+ add_subdirectory(Utilities/cmliblzma)
+ CMAKE_SET_TARGET_FOLDER(cmliblzma "Utilities/3rdParty")
+ set(LIBLZMA_HAS_AUTO_DECODER 1)
+ set(LIBLZMA_HAS_EASY_ENCODER 1)
+ set(LIBLZMA_HAS_LZMA_PRESET 1)
+ set(LIBLZMA_INCLUDE_DIR
+ "${CMAKE_CURRENT_SOURCE_DIR}/Utilities/cmliblzma/liblzma/api")
+ set(LIBLZMA_LIBRARY cmliblzma)
+ endif()
+ endif()
+
+ #---------------------------------------------------------------------
+ # Build or use system libarchive for CMake and CTest.
+ if(CMAKE_USE_SYSTEM_LIBARCHIVE)
+ find_package(LibArchive 3.3.3)
+ if(NOT LibArchive_FOUND)
+ message(FATAL_ERROR "CMAKE_USE_SYSTEM_LIBARCHIVE is ON but LibArchive is not found!")
+ endif()
+ set(CMAKE_TAR_INCLUDES ${LibArchive_INCLUDE_DIRS})
+ set(CMAKE_TAR_LIBRARIES ${LibArchive_LIBRARIES})
+ else()
+ set(EXPAT_INCLUDE_DIR ${CMAKE_EXPAT_INCLUDES})
+ set(EXPAT_LIBRARY ${CMAKE_EXPAT_LIBRARIES})
+ set(ZLIB_INCLUDE_DIR ${CMAKE_ZLIB_INCLUDES})
+ set(ZLIB_LIBRARY ${CMAKE_ZLIB_LIBRARIES})
+ add_definitions(-DLIBARCHIVE_STATIC)
+ set(ENABLE_MBEDTLS OFF CACHE INTERNAL "Enable use of mbed TLS")
+ set(ENABLE_NETTLE OFF CACHE INTERNAL "Enable use of Nettle")
+ set(ENABLE_OPENSSL ${CMAKE_USE_OPENSSL} CACHE INTERNAL "Enable use of OpenSSL")
+ set(ENABLE_LIBB2 OFF CACHE INTERNAL "Enable the use of the system LIBB2 library if found")
+ set(ENABLE_LZMA ON CACHE INTERNAL "Enable the use of the system LZMA library if found")
+ set(ENABLE_LZ4 OFF CACHE INTERNAL "Enable the use of the system LZ4 library if found")
+ set(ENABLE_LZO OFF CACHE INTERNAL "Enable the use of the system LZO library if found")
+ set(ENABLE_ZLIB ON CACHE INTERNAL "Enable the use of the system ZLIB library if found")
+ set(ENABLE_BZip2 ON CACHE INTERNAL "Enable the use of the system BZip2 library if found")
+ set(ENABLE_ZSTD ON CACHE INTERNAL "Enable the use of the system zstd library if found")
+ set(ENABLE_LIBXML2 OFF CACHE INTERNAL "Enable the use of the system libxml2 library if found")
+ set(ENABLE_EXPAT OFF CACHE INTERNAL "Enable the use of the system EXPAT library if found")
+ set(ENABLE_PCREPOSIX OFF CACHE INTERNAL "Enable the use of the system PCREPOSIX library if found")
+ set(ENABLE_LibGCC OFF CACHE INTERNAL "Enable the use of the system LibGCC library if found")
+ set(ENABLE_XATTR OFF CACHE INTERNAL "Enable extended attribute support")
+ set(ENABLE_ACL OFF CACHE INTERNAL "Enable ACL support")
+ set(ENABLE_ICONV OFF CACHE INTERNAL "Enable iconv support")
+ set(ENABLE_CNG OFF CACHE INTERNAL "Enable the use of CNG(Crypto Next Generation)")
+ SET(POSIX_REGEX_LIB "" CACHE INTERNAL "Choose what library should provide POSIX regular expression support")
+ add_subdirectory(Utilities/cmlibarchive)
+ CMAKE_SET_TARGET_FOLDER(cmlibarchive "Utilities/3rdParty")
+ set(CMAKE_TAR_LIBRARIES cmlibarchive ${BZIP2_LIBRARIES})
+ endif()
+
+ #---------------------------------------------------------------------
+ # Build jsoncpp library.
+ if(CMAKE_USE_SYSTEM_JSONCPP)
+ find_package(JsonCpp 1.4.1)
+ if(NOT JsonCpp_FOUND)
+ message(FATAL_ERROR
+ "CMAKE_USE_SYSTEM_JSONCPP is ON but a JsonCpp is not found!")
+ endif()
+ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+ set_property(TARGET JsonCpp::JsonCpp APPEND PROPERTY
+ INTERFACE_COMPILE_OPTIONS -Wno-deprecated-declarations)
+ endif()
+ set(CMAKE_JSONCPP_LIBRARIES JsonCpp::JsonCpp)
+ else()
+ set(CMAKE_JSONCPP_LIBRARIES cmjsoncpp)
+ add_subdirectory(Utilities/cmjsoncpp)
+ CMAKE_SET_TARGET_FOLDER(cmjsoncpp "Utilities/3rdParty")
endif()
- if(UNIX AND NOT CYGWIN)
- KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_GETLOADAVG
- "Checking whether CXX compiler has getloadavg" DIRECT)
- if(KWSYS_CXX_HAS_GETLOADAVG)
- set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
- COMPILE_DEFINITIONS KWSYS_CXX_HAS_GETLOADAVG=1)
+ #---------------------------------------------------------------------
+ # Build libuv library.
+ if(CMAKE_USE_SYSTEM_LIBUV)
+ find_package(LibUV 1.10.0)
+ if(NOT LIBUV_FOUND)
+ message(FATAL_ERROR
+ "CMAKE_USE_SYSTEM_LIBUV is ON but a libuv is not found!")
endif()
+ set(CMAKE_LIBUV_LIBRARIES LibUV::LibUV)
+ else()
+ set(CMAKE_LIBUV_LIBRARIES cmlibuv)
+ add_subdirectory(Utilities/cmlibuv)
+ CMAKE_SET_TARGET_FOLDER(cmlibuv "Utilities/3rdParty")
endif()
-endif()
-
-if(KWSYS_USE_FStream)
- KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H
- "Checking whether <ext/stdio_filebuf.h> is available" DIRECT)
-endif()
-#-----------------------------------------------------------------------------
-# Choose a directory for the generated headers.
-if(NOT KWSYS_HEADER_ROOT)
- set(KWSYS_HEADER_ROOT "${PROJECT_BINARY_DIR}")
-endif()
-set(KWSYS_HEADER_DIR "${KWSYS_HEADER_ROOT}/${KWSYS_NAMESPACE}")
-include_directories(${KWSYS_HEADER_ROOT})
-
-#-----------------------------------------------------------------------------
-if(KWSYS_INSTALL_DOC_DIR)
- # Assign the license to the runtime component since it must be
- # distributed with binary forms of this software.
- if(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME)
- set(KWSYS_INSTALL_LICENSE_OPTIONS ${KWSYS_INSTALL_LICENSE_OPTIONS}
- COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME}
- )
+ #---------------------------------------------------------------------
+ # Use curses?
+ if (UNIX)
+ if(NOT DEFINED BUILD_CursesDialog)
+ include(${CMake_SOURCE_DIR}/Source/Checks/Curses.cmake)
+ option(BUILD_CursesDialog "Build the CMake Curses Dialog ccmake" "${CMakeCheckCurses_COMPILED}")
+ endif()
+ else ()
+ set(BUILD_CursesDialog 0)
+ endif ()
+ if(BUILD_CursesDialog)
+ set(CURSES_NEED_NCURSES TRUE)
+ find_package(Curses)
+ if(NOT CURSES_FOUND)
+ message(WARNING
+ "'ccmake' will not be built because Curses was not found.\n"
+ "Turn off BUILD_CursesDialog to suppress this message."
+ )
+ set(BUILD_CursesDialog 0)
+ endif()
endif()
-
- # Install the license under the documentation directory.
- install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/Copyright.txt
- DESTINATION ${KWSYS_INSTALL_DOC_DIR}/${KWSYS_NAMESPACE}
- ${KWSYS_INSTALL_LICENSE_OPTIONS})
-endif()
-
-#-----------------------------------------------------------------------------
-# Build a list of classes and headers we need to implement the
-# selected components. Initialize with required components.
-set(KWSYS_CLASSES)
-set(KWSYS_H_FILES Configure SharedForward)
-set(KWSYS_HXX_FILES Configure String)
-
-# Add selected C++ classes.
-set(cppclasses
- Directory DynamicLoader Encoding Glob RegularExpression SystemTools
- CommandLineArguments FStream SystemInformation ConsoleBuf Status
- )
-foreach(cpp ${cppclasses})
- if(KWSYS_USE_${cpp})
- # Use the corresponding class.
- set(KWSYS_CLASSES ${KWSYS_CLASSES} ${cpp})
-
- # Load component-specific CMake code.
- if(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake)
- include(${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake)
+ if(BUILD_CursesDialog)
+ if(NOT CMAKE_USE_SYSTEM_FORM)
+ add_subdirectory(Source/CursesDialog/form)
+ elseif(NOT CURSES_FORM_LIBRARY)
+ message( FATAL_ERROR "CMAKE_USE_SYSTEM_FORM in ON but CURSES_FORM_LIBRARY is not set!" )
endif()
endif()
-endforeach()
+endmacro ()
-# Add selected C components.
-foreach(c
- Process Base64 Encoding MD5 Terminal System String
+#-----------------------------------------------------------------------
+if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ if(CMAKE_CXX_PLATFORM_ID MATCHES "OpenBSD")
+ execute_process(COMMAND ${CMAKE_CXX_COMPILER}
+ ${CMAKE_CXX_COMPILER_ARG1} -dumpversion
+ OUTPUT_VARIABLE _GXX_VERSION
)
- if(KWSYS_USE_${c})
- # Use the corresponding header file.
- set(KWSYS_H_FILES ${KWSYS_H_FILES} ${c})
-
- # Load component-specific CMake code.
- if(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${c}.cmake)
- include(${PROJECT_SOURCE_DIR}/kwsys${c}.cmake)
+ string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2"
+ _GXX_VERSION_SHORT ${_GXX_VERSION})
+ if(_GXX_VERSION_SHORT EQUAL 33)
+ message(FATAL_ERROR
+ "GXX 3.3 on OpenBSD is known to cause CPack to Crash.\n"
+ "Please use GXX 4.2 or greater to build CMake on OpenBSD\n"
+ "${CMAKE_CXX_COMPILER} version is: ${_GXX_VERSION}")
endif()
endif()
-endforeach()
-
-#-----------------------------------------------------------------------------
-# Build a list of sources for the library based on components that are
-# included.
-set(KWSYS_C_SRCS)
-set(KWSYS_CXX_SRCS)
-
-# Add the proper sources for this platform's Process implementation.
-if(KWSYS_USE_Process)
- if(NOT UNIX)
- # Use the Windows implementation.
- set(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessWin32.c)
- else()
- # Use the UNIX implementation.
- set(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessUNIX.c)
- endif()
endif()
-# Add selected C sources.
-foreach(c Base64 Encoding MD5 Terminal System String)
- if(KWSYS_USE_${c})
- if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}C.c)
- list(APPEND KWSYS_C_SRCS ${c}C.c)
- else()
- list(APPEND KWSYS_C_SRCS ${c}.c)
- endif()
- endif()
-endforeach()
-
-# Configure headers of C++ classes and construct the list of sources.
-foreach(c ${KWSYS_CLASSES})
- # Add this source to the list of source files for the library.
- if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}CXX.cxx)
- list(APPEND KWSYS_CXX_SRCS ${c}CXX.cxx)
- elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}.cxx)
- list(APPEND KWSYS_CXX_SRCS ${c}.cxx)
- endif()
+#-----------------------------------------------------------------------
+# The main section of the CMakeLists file
+#
+#-----------------------------------------------------------------------
+include(Source/CMakeVersion.cmake)
- # Configure the header for this class.
- configure_file(${PROJECT_SOURCE_DIR}/${c}.hxx.in ${KWSYS_HEADER_DIR}/${c}.hxx
- @ONLY IMMEDIATE)
- set(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${c}.hxx)
+# Include the standard Dart testing module
+enable_testing()
+include (${CMAKE_ROOT}/Modules/Dart.cmake)
- # Create an install target for the header.
- if(KWSYS_INSTALL_INCLUDE_DIR)
- install(FILES ${KWSYS_HEADER_DIR}/${c}.hxx
- DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
- ${KWSYS_INSTALL_INCLUDE_OPTIONS})
- endif()
-endforeach()
-
-# Configure C headers.
-foreach(h ${KWSYS_H_FILES})
- # Configure the header into the given directory.
- configure_file(${PROJECT_SOURCE_DIR}/${h}.h.in ${KWSYS_HEADER_DIR}/${h}.h
- @ONLY IMMEDIATE)
- set(KWSYS_C_SRCS ${KWSYS_C_SRCS} ${KWSYS_HEADER_DIR}/${h}.h)
-
- # Create an install target for the header.
- if(KWSYS_INSTALL_INCLUDE_DIR)
- install(FILES ${KWSYS_HEADER_DIR}/${h}.h
- DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
- ${KWSYS_INSTALL_INCLUDE_OPTIONS})
- endif()
-endforeach()
-
-# Configure other C++ headers.
-foreach(h ${KWSYS_HXX_FILES})
- # Configure the header into the given directory.
- configure_file(${PROJECT_SOURCE_DIR}/${h}.hxx.in ${KWSYS_HEADER_DIR}/${h}.hxx
- @ONLY IMMEDIATE)
- set(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${h}.hxx)
-
- # Create an install target for the header.
- if(KWSYS_INSTALL_INCLUDE_DIR)
- install(FILES ${KWSYS_HEADER_DIR}/${h}.hxx
- DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
- ${KWSYS_INSTALL_INCLUDE_OPTIONS})
- endif()
-endforeach()
-
-#-----------------------------------------------------------------------------
-# Add the library with the configured name and list of sources.
-if(KWSYS_C_SRCS OR KWSYS_CXX_SRCS)
- if(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE)
- set(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE})
- set(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE}_objects)
- set(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE}_private)
- set(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_INTERFACE} ${KWSYS_TARGET_LINK})
- set(KWSYS_LINK_DEPENDENCY INTERFACE)
- add_library(${KWSYS_TARGET_OBJECT} OBJECT
- ${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS})
- if(KWSYS_BUILD_SHARED OR KWSYS_BUILD_PIC)
- set_property(TARGET ${KWSYS_TARGET_OBJECT} PROPERTY
- POSITION_INDEPENDENT_CODE TRUE)
- endif()
- add_library(${KWSYS_TARGET_INTERFACE} INTERFACE)
- add_library(${KWSYS_TARGET_LINK} INTERFACE)
- target_link_libraries(${KWSYS_TARGET_LINK} INTERFACE
- ${KWSYS_TARGET_INTERFACE})
- target_sources(${KWSYS_TARGET_LINK} INTERFACE
- $<TARGET_OBJECTS:${KWSYS_TARGET_OBJECT}>)
- target_compile_features(${KWSYS_TARGET_OBJECT} PRIVATE ${KWSYS_CXX_COMPILE_FEATURES})
- target_compile_features(${KWSYS_TARGET_INTERFACE} INTERFACE ${KWSYS_CXX_COMPILE_FEATURES})
- else()
- set(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE})
- set(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE})
- set(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE})
- set(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_LINK})
- set(KWSYS_LINK_DEPENDENCY PUBLIC)
- add_library(${KWSYS_TARGET_INTERFACE} ${KWSYS_LIBRARY_TYPE}
- ${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS})
- target_compile_features(${KWSYS_TARGET_INTERFACE} PUBLIC ${KWSYS_CXX_COMPILE_FEATURES})
- endif()
- if (KWSYS_ALIAS_TARGET)
- add_library(${KWSYS_ALIAS_TARGET} ALIAS ${KWSYS_TARGET_INTERFACE})
- endif ()
- set_target_properties(${KWSYS_TARGET_OBJECT} PROPERTIES
- C_CLANG_TIDY ""
- CXX_CLANG_TIDY ""
- C_INCLUDE_WHAT_YOU_USE ""
- CXX_INCLUDE_WHAT_YOU_USE ""
- LABELS "${KWSYS_LABELS_LIB}")
- if(KWSYS_USE_DynamicLoader)
- if(UNIX)
- target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
- ${CMAKE_DL_LIBS})
- endif()
- endif()
+# Set up test-time configuration.
+set_directory_properties(PROPERTIES
+ TEST_INCLUDE_FILE "${CMake_BINARY_DIR}/Tests/EnforceConfig.cmake")
- if(KWSYS_USE_SystemInformation)
- if(WIN32)
- target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} ws2_32)
- # link in dbghelp.dll for symbol lookup if MSVC 1800 or later
- # Note that the dbghelp runtime is part of MS Windows OS
- if(MSVC_VERSION AND NOT MSVC_VERSION VERSION_LESS 1800)
- target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} dbghelp)
- endif()
- if(KWSYS_SYS_HAS_PSAPI)
- target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
- psapi)
- endif()
- elseif(UNIX)
- if (EXECINFO_LIB AND KWSYS_CXX_HAS_BACKTRACE)
- # backtrace on FreeBSD is not in libc
- target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
- ${EXECINFO_LIB})
- endif()
- if (KWSYS_CXX_HAS_DLADDR)
- # for symbol lookup using dladdr
- target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
- ${CMAKE_DL_LIBS})
- endif()
- if (CMAKE_SYSTEM_NAME STREQUAL "SunOS")
- target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
- socket)
- endif()
- endif()
- endif()
+if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ # where to write the resulting executables and libraries
+ set(BUILD_SHARED_LIBS OFF)
+ set(EXECUTABLE_OUTPUT_PATH "" CACHE INTERNAL "No configurable exe dir.")
+ set(LIBRARY_OUTPUT_PATH "" CACHE INTERNAL
+ "Where to put the libraries for CMake")
- # Apply user-defined target properties to the library.
- if(KWSYS_PROPERTIES_CXX)
- set_target_properties(${KWSYS_TARGET_INTERFACE} PROPERTIES
- ${KWSYS_PROPERTIES_CXX})
- endif()
+ # Load install destinations.
+ include(Source/CMakeInstallDestinations.cmake)
- # Set up include usage requirement
- if(COMMAND TARGET_INCLUDE_DIRECTORIES)
- target_include_directories(${KWSYS_TARGET_INTERFACE} INTERFACE
- $<BUILD_INTERFACE:${KWSYS_HEADER_ROOT}>)
- if(KWSYS_INSTALL_INCLUDE_DIR)
- target_include_directories(${KWSYS_TARGET_INTERFACE} INTERFACE
- $<INSTALL_INTERFACE:${KWSYS_INSTALL_INCLUDE_DIR}>)
- endif()
+ if(BUILD_TESTING)
+ include(${CMake_SOURCE_DIR}/Tests/CMakeInstall.cmake)
endif()
- # Create an install target for the library.
- if(KWSYS_INSTALL_LIBRARY_RULE)
- install(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_LIBRARY_RULE})
- endif()
- if(KWSYS_INSTALL_NAMELINK_RULE)
- install(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_NAMELINK_RULE})
+ # Checks for cmSystemTools.
+ if(WIN32)
+ set(HAVE_UNSETENV 0)
+ set(HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE 1)
+ else()
+ include(CheckSymbolExists)
+ CHECK_SYMBOL_EXISTS(unsetenv "stdlib.h" HAVE_UNSETENV)
+ CHECK_SYMBOL_EXISTS(environ "stdlib.h" HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE)
endif()
endif()
-# Add a C-only library if requested.
-if(KWSYS_ENABLE_C AND KWSYS_C_SRCS)
- if(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE)
- set(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c)
- set(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c_objects)
- set(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c_private)
- set(KWSYS_TARGET_C_INSTALL
- ${KWSYS_TARGET_C_INTERFACE} ${KWSYS_TARGET_C_LINK})
- set(KWSYS_LINK_DEPENDENCY INTERFACE)
- add_library(${KWSYS_TARGET_C_OBJECT} OBJECT ${KWSYS_C_SRCS})
- if(KWSYS_BUILD_SHARED OR KWSYS_BUILD_PIC)
- set_property(TARGET ${KWSYS_TARGET_C_OBJECT} PROPERTY
- POSITION_INDEPENDENT_CODE TRUE)
- endif()
- add_library(${KWSYS_TARGET_C_INTERFACE} INTERFACE)
- add_library(${KWSYS_TARGET_C_LINK} INTERFACE)
- target_link_libraries(${KWSYS_TARGET_C_LINK} INTERFACE
- ${KWSYS_TARGET_C_INTERFACE})
- target_sources(${KWSYS_TARGET_C_LINK} INTERFACE
- $<TARGET_OBJECTS:${KWSYS_TARGET_C_OBJECT}>)
- else()
- set(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c)
- set(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c)
- set(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c)
- set(KWSYS_TARGET_C_INSTALL ${KWSYS_TARGET_C_LINK})
- set(KWSYS_LINK_DEPENDENCY PUBLIC)
- add_library(${KWSYS_TARGET_C_INTERFACE} ${KWSYS_LIBRARY_TYPE}
- ${KWSYS_C_SRCS})
- endif()
- set_target_properties(${KWSYS_TARGET_C_OBJECT} PROPERTIES
- LABELS "${KWSYS_LABELS_LIB}")
+# CMAKE_TESTS_CDASH_SERVER: CDash server used by CMake/Tests.
+#
+# If not defined or "", this variable defaults to the server at
+# "http://open.cdash.org".
+#
+# If set explicitly to "NOTFOUND", curl tests and ctest tests that use
+# the network are skipped.
+#
+# If set to something starting with "http://localhost/", the CDash is
+# expected to be an instance of CDash used for CDash testing, pointing
+# to a cdash4simpletest database. In these cases, the CDash dashboards
+# should be run first.
+#
+if("x${CMAKE_TESTS_CDASH_SERVER}" STREQUAL "x" AND NOT CMake_TEST_NO_NETWORK)
+ set(CMAKE_TESTS_CDASH_SERVER "http://open.cdash.org")
+endif()
- # Apply user-defined target properties to the library.
- if(KWSYS_PROPERTIES_C)
- set_target_properties(${KWSYS_TARGET_C_INTERFACE} PROPERTIES
- ${KWSYS_PROPERTIES_C})
- endif()
+if(CMake_TEST_EXTERNAL_CMAKE)
+ set(KWIML_TEST_ENABLE 1)
+ add_subdirectory(Utilities/KWIML)
+endif()
+
+if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ # build the utilities (a macro defined in this file)
+ CMAKE_BUILD_UTILITIES()
- # Set up include usage requirement
- if(COMMAND TARGET_INCLUDE_DIRECTORIES)
- target_include_directories(${KWSYS_TARGET_C_INTERFACE} INTERFACE
- $<BUILD_INTERFACE:${KWSYS_HEADER_ROOT}>)
- if(KWSYS_INSTALL_INCLUDE_DIR)
- target_include_directories(${KWSYS_TARGET_C_INTERFACE} INTERFACE
- $<INSTALL_INTERFACE:${KWSYS_INSTALL_INCLUDE_DIR}>)
+ if(BUILD_QtDialog)
+ if(APPLE)
+ set(CMAKE_BUNDLE_VERSION
+ "${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}.${CMake_VERSION_PATCH}")
+ set(CMAKE_BUNDLE_LOCATION "${CMAKE_INSTALL_PREFIX}")
+ # make sure CMAKE_INSTALL_PREFIX ends in /
+ if(NOT CMAKE_INSTALL_PREFIX MATCHES "/$")
+ set(CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/")
+ endif()
+ set(CMAKE_INSTALL_PREFIX
+ "${CMAKE_INSTALL_PREFIX}CMake.app/Contents")
endif()
endif()
- # Create an install target for the library.
- if(KWSYS_INSTALL_LIBRARY_RULE)
- install(TARGETS ${KWSYS_TARGET_C_INSTALL})
+ if(UNIX)
+ # Install executables with the RPATH set for libraries outside the build tree.
+ # This is also suitable for binaries in the build tree. Avoid re-link on install.
+ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON CACHE BOOL "Install with RPATH set to find custom-built libraries.")
+ set(CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "Build with RPATH set to match install-tree RPATH.")
+ mark_as_advanced(CMAKE_INSTALL_RPATH_USE_LINK_PATH CMAKE_BUILD_WITH_INSTALL_RPATH)
endif()
-endif()
-
-# For building kwsys itself, we use a macro defined on the command
-# line to configure the namespace in the C and C++ source files.
-add_definitions("-DKWSYS_NAMESPACE=${KWSYS_NAMESPACE}")
-
-# Disable deprecation warnings for standard C functions.
-if(MSVC OR (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "Intel" OR
- (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC"))))
- add_definitions(
- -D_CRT_NONSTDC_NO_DEPRECATE
- -D_CRT_SECURE_NO_DEPRECATE
- -D_CRT_SECURE_NO_WARNINGS
- -D_SCL_SECURE_NO_DEPRECATE
- )
-endif()
-if(WIN32)
- # Help enforce the use of wide Windows apis.
- add_definitions(-DUNICODE -D_UNICODE)
-endif()
+ # add the uninstall support
+ configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
+ @ONLY)
+ add_custom_target(uninstall
+ "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
-if(KWSYS_USE_String)
- # Activate code in "String.c". See the comment in the source.
- set_source_files_properties(String.c PROPERTIES
- COMPILE_FLAGS "-DKWSYS_STRING_C")
-endif()
+ include (CMakeCPack.cmake)
-if(KWSYS_USE_Encoding)
- # Set default 8 bit encoding in "EndcodingC.c".
- set_property(SOURCE EncodingC.c EncodingCXX.cxx APPEND PROPERTY COMPILE_DEFINITIONS
- KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
endif()
-#-----------------------------------------------------------------------------
-# Setup testing if not being built as part of another project.
-if(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
- if(BUILD_TESTING)
- # Compute the location of executables.
- set(EXEC_DIR "${CMAKE_CURRENT_BINARY_DIR}")
- if(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
- set(EXEC_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
- endif()
+# setup some Testing support (a macro defined in this file)
+CMAKE_SETUP_TESTING()
- # C tests
- set(KWSYS_C_TESTS
- testEncode.c
- testTerminal.c
+if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ if(NOT CMake_VERSION_IS_RELEASE)
+ if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND
+ NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS 4.2)
+ set(C_FLAGS_LIST -Wcast-align -Werror-implicit-function-declaration -Wchar-subscripts
+ -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security
+ -Wmissing-format-attribute -fno-common -Wundef
)
- if(KWSYS_STANDALONE)
- set(KWSYS_C_TESTS ${KWSYS_C_TESTS} testFail.c)
- endif()
- create_test_sourcelist(
- KWSYS_C_TEST_SRCS ${KWSYS_NAMESPACE}TestsC.c
- ${KWSYS_C_TESTS}
+ set(CXX_FLAGS_LIST -Wnon-virtual-dtor -Wcast-align -Wchar-subscripts -Wall -W
+ -Wshadow -Wpointer-arith -Wformat-security -Wundef
)
- add_executable(${KWSYS_NAMESPACE}TestsC ${KWSYS_C_TEST_SRCS})
- set_property(TARGET ${KWSYS_NAMESPACE}TestsC PROPERTY LABELS ${KWSYS_LABELS_EXE})
- target_link_libraries(${KWSYS_NAMESPACE}TestsC ${KWSYS_TARGET_C_LINK})
- foreach(testfile ${KWSYS_C_TESTS})
- get_filename_component(test "${testfile}" NAME_WE)
- add_test(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsC ${test} ${KWSYS_TEST_ARGS_${test}})
- set_property(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST})
- endforeach()
- # C++ tests
- set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
- testConfigure.cxx
- testStatus.cxx
- testSystemTools.cxx
- testCommandLineArguments.cxx
- testCommandLineArguments1.cxx
- testDirectory.cxx
- )
- if(KWSYS_STL_HAS_WSTRING)
- set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
- testEncoding.cxx
- )
- endif()
- if(KWSYS_USE_FStream)
- set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
- testFStream.cxx
- )
- endif()
- if(KWSYS_USE_ConsoleBuf)
- add_executable(testConsoleBufChild testConsoleBufChild.cxx)
- set_property(TARGET testConsoleBufChild PROPERTY C_CLANG_TIDY "")
- set_property(TARGET testConsoleBufChild PROPERTY CXX_CLANG_TIDY "")
- set_property(TARGET testConsoleBufChild PROPERTY C_INCLUDE_WHAT_YOU_USE "")
- set_property(TARGET testConsoleBufChild PROPERTY CXX_INCLUDE_WHAT_YOU_USE "")
- set_property(TARGET testConsoleBufChild PROPERTY LABELS ${KWSYS_LABELS_EXE})
- target_link_libraries(testConsoleBufChild ${KWSYS_TARGET_LINK})
- set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
- testConsoleBuf.cxx
- )
- if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND
- CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "19.0.23506")
- set_property(SOURCE testConsoleBuf.cxx testConsoleBufChild.cxx PROPERTY COMPILE_FLAGS /utf-8)
- endif()
- set_property(SOURCE testConsoleBuf.cxx APPEND PROPERTY COMPILE_DEFINITIONS
- KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
- endif()
- if(KWSYS_USE_SystemInformation)
- set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation.cxx)
- endif()
- if(KWSYS_USE_DynamicLoader)
- set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testDynamicLoader.cxx)
- # If kwsys contains the DynamicLoader, need extra library
- add_library(${KWSYS_NAMESPACE}TestDynload MODULE testDynload.c)
- set_property(TARGET ${KWSYS_NAMESPACE}TestDynload PROPERTY LABELS ${KWSYS_LABELS_LIB})
- add_dependencies(${KWSYS_NAMESPACE}TestDynload ${KWSYS_TARGET_INTERFACE})
-
- if (WIN32)
- # Windows tests supported flags.
- add_library(${KWSYS_NAMESPACE}TestDynloadImpl SHARED testDynloadImpl.c)
- set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY LABELS ${KWSYS_LABELS_LIB})
- set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY DEFINE_SYMBOL BUILDING_TestDynloadImpl)
- set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir")
- add_dependencies(${KWSYS_NAMESPACE}TestDynloadImpl ${KWSYS_TARGET_INTERFACE})
- add_library(${KWSYS_NAMESPACE}TestDynloadUse MODULE testDynloadUse.c)
- set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LABELS ${KWSYS_LABELS_LIB})
- set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir")
- add_dependencies(${KWSYS_NAMESPACE}TestDynloadUse ${KWSYS_TARGET_INTERFACE})
- target_link_libraries(${KWSYS_NAMESPACE}TestDynloadUse PRIVATE ${KWSYS_NAMESPACE}TestDynloadImpl)
- endif ()
- endif()
- create_test_sourcelist(
- KWSYS_CXX_TEST_SRCS ${KWSYS_NAMESPACE}TestsCxx.cxx
- ${KWSYS_CXX_TESTS}
- )
- add_executable(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_CXX_TEST_SRCS})
- set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_CLANG_TIDY "")
- set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_CLANG_TIDY "")
- set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_INCLUDE_WHAT_YOU_USE "")
- set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_INCLUDE_WHAT_YOU_USE "")
- set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY LABELS ${KWSYS_LABELS_EXE})
- target_link_libraries(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_TARGET_LINK})
-
- set(TEST_SYSTEMTOOLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
- set(TEST_SYSTEMTOOLS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
- configure_file(
- ${PROJECT_SOURCE_DIR}/testSystemTools.h.in
- ${PROJECT_BINARY_DIR}/testSystemTools.h)
- include_directories(${PROJECT_BINARY_DIR})
-
- if(CTEST_TEST_KWSYS)
- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/ExtraTest.cmake.in"
- "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake")
- set_directory_properties(PROPERTIES TEST_INCLUDE_FILE "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake")
- endif()
+ foreach(FLAG_LANG C CXX)
+ foreach(FLAG ${${FLAG_LANG}_FLAGS_LIST})
+ if(NOT " ${CMAKE_${FLAG_LANG}_FLAGS} " MATCHES " ${FLAG} ")
+ set(CMAKE_${FLAG_LANG}_FLAGS "${CMAKE_${FLAG_LANG}_FLAGS} ${FLAG}")
+ endif()
+ endforeach()
+ endforeach()
- set(KWSYS_TEST_ARGS_testCommandLineArguments
- --another-bool-variable
- --long3=opt
- --set-bool-arg1
- -SSS ken brad bill andy
- --some-bool-variable=true
- --some-double-variable12.5
- --some-int-variable 14
- "--some-string-variable=test string with space"
- --some-multi-argument 5 1 8 3 7 1 3 9 7 1
- -N 12.5 -SS=andy -N 1.31 -N 22
- -SS=bill -BBtrue -SS=brad
- -BBtrue
- -BBfalse
- -SS=ken
- -A
- -C=test
- --long2 hello
- )
- set(KWSYS_TEST_ARGS_testCommandLineArguments1
- --ignored
- -n 24
- --second-ignored
- "-m=test value"
- third-ignored
- -p
- some junk at the end
- )
- foreach(testfile ${KWSYS_CXX_TESTS})
- get_filename_component(test "${testfile}" NAME_WE)
- add_test(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsCxx ${test} ${KWSYS_TEST_ARGS_${test}})
- set_property(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST})
- endforeach()
+ unset(C_FLAGS_LIST)
+ unset(CXX_FLAGS_LIST)
+ endif()
+ endif()
- # Process tests.
- add_executable(${KWSYS_NAMESPACE}TestProcess testProcess.c)
- set_property(TARGET ${KWSYS_NAMESPACE}TestProcess PROPERTY LABELS ${KWSYS_LABELS_EXE})
- target_link_libraries(${KWSYS_NAMESPACE}TestProcess ${KWSYS_TARGET_C_LINK})
- #set(KWSYS_TEST_PROCESS_7 7) # uncomment to run timing-sensitive test locally
- foreach(n 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7} 9 10)
- add_test(kwsys.testProcess-${n} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestProcess ${n})
- set_property(TEST kwsys.testProcess-${n} PROPERTY LABELS ${KWSYS_LABELS_TEST})
- set_tests_properties(kwsys.testProcess-${n} PROPERTIES TIMEOUT 120)
- endforeach()
+ # build the remaining subdirectories
+ add_subdirectory(Source)
+ add_subdirectory(Utilities)
+endif()
- set(testProcess_COMPILE_FLAGS "")
- # Some Apple compilers produce bad optimizations in this source.
- if(APPLE AND CMAKE_C_COMPILER_ID MATCHES "^(GNU|LLVM)$")
- set(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -O0")
- elseif(CMAKE_C_COMPILER_ID STREQUAL "XL")
- # Tell IBM XL not to warn about our test infinite loop
- if(CMAKE_SYSTEM MATCHES "Linux.*ppc64le"
- AND CMAKE_C_COMPILER_VERSION VERSION_LESS "16.1.0"
- AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS "13.1.1")
- # v13.1.[1-6] on Linux ppc64le is clang based and does not accept
- # the -qsuppress option, so just suppress all warnings.
- set(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -w")
- else()
- set(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -qsuppress=1500-010")
- endif()
- endif()
- if(CMAKE_C_FLAGS MATCHES "-fsanitize=")
- set(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -DCRASH_USING_ABORT")
- endif()
- set_property(SOURCE testProcess.c PROPERTY COMPILE_FLAGS "${testProcess_COMPILE_FLAGS}")
-
- # Test SharedForward
- configure_file(${PROJECT_SOURCE_DIR}/testSharedForward.c.in
- ${PROJECT_BINARY_DIR}/testSharedForward.c @ONLY IMMEDIATE)
- add_executable(${KWSYS_NAMESPACE}TestSharedForward
- ${PROJECT_BINARY_DIR}/testSharedForward.c)
- set_property(TARGET ${KWSYS_NAMESPACE}TestSharedForward PROPERTY LABELS ${KWSYS_LABELS_EXE})
- add_dependencies(${KWSYS_NAMESPACE}TestSharedForward ${KWSYS_TARGET_C_LINK})
- add_test(kwsys.testSharedForward ${EXEC_DIR}/${KWSYS_NAMESPACE}TestSharedForward 1)
- set_property(TEST kwsys.testSharedForward PROPERTY LABELS ${KWSYS_LABELS_TEST})
-
- # Configure some test properties.
- if(KWSYS_STANDALONE)
- # We expect test to fail
- set_tests_properties(kwsys.testFail PROPERTIES WILL_FAIL ON)
- get_test_property(kwsys.testFail WILL_FAIL wfv)
- set_tests_properties(kwsys.testFail PROPERTIES MEASUREMENT "Some Key=Some Value")
- message(STATUS "GET_TEST_PROPERTY returned: ${wfv}")
- endif()
+add_subdirectory(Tests)
- # Set up ctest custom configuration file.
- configure_file(${PROJECT_SOURCE_DIR}/CTestCustom.cmake.in
- ${PROJECT_BINARY_DIR}/CTestCustom.cmake @ONLY)
+if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ if(BUILD_TESTING)
+ CMAKE_SET_TARGET_FOLDER(CMakeLibTests "Tests")
+ IF(TARGET CMakeServerLibTests)
+ CMAKE_SET_TARGET_FOLDER(CMakeServerLibTests "Tests")
+ ENDIF()
+ endif()
+ if(TARGET documentation)
+ CMAKE_SET_TARGET_FOLDER(documentation "Documentation")
+ endif()
+endif()
+
+if(BUILD_TESTING)
+ add_test(SystemInformationNew "${CMAKE_CMAKE_COMMAND}"
+ --system-information -G "${CMAKE_GENERATOR}" )
+endif()
+
+if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ # Install license file as it requires.
+ install(FILES Copyright.txt DESTINATION ${CMAKE_DOC_DIR})
+
+ # Install script directories.
+ install(
+ DIRECTORY Help Modules Templates
+ DESTINATION ${CMAKE_DATA_DIR}
+ FILE_PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
+ DIRECTORY_PERMISSIONS OWNER_READ OWNER_EXECUTE OWNER_WRITE
+ GROUP_READ GROUP_EXECUTE
+ WORLD_READ WORLD_EXECUTE
+ PATTERN "*.sh*" PERMISSIONS OWNER_READ OWNER_EXECUTE OWNER_WRITE
+ GROUP_READ GROUP_EXECUTE
+ WORLD_READ WORLD_EXECUTE
+ REGEX "/(ExportImportList|cpp)$"
+ PERMISSIONS OWNER_READ OWNER_EXECUTE OWNER_WRITE
+ GROUP_READ GROUP_EXECUTE
+ WORLD_READ WORLD_EXECUTE
+ REGEX "Help/(dev|guide)($|/)" EXCLUDE
+ )
- # Suppress known consistent failures on buggy systems.
- if(KWSYS_TEST_BOGUS_FAILURES)
- set_tests_properties(${KWSYS_TEST_BOGUS_FAILURES} PROPERTIES WILL_FAIL ON)
- endif()
+ # Install auxiliary files integrating with other tools.
+ add_subdirectory(Auxiliary)
+ # Optionally sign installed binaries.
+ if(CMake_INSTALL_SIGNTOOL)
+ configure_file(Source/CMakeInstallSignTool.cmake.in Source/CMakeInstallSignTool.cmake @ONLY)
+ install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/Source/CMakeInstallSignTool.cmake)
endif()
endif()
diff --git a/CMakeLogo.gif b/CMakeLogo.gif
new file mode 100644
index 0000000..8426402
--- /dev/null
+++ b/CMakeLogo.gif
Binary files differ
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 32e7b83..3006214 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -1,42 +1,70 @@
-Contributing to KWSys
+Contributing to CMake
*********************
+The following summarizes the process for contributing changes.
+See documentation on `CMake Development`_ for more information.
+
+.. _`CMake Development`: Help/dev/README.rst
+
+Community
+=========
+
+CMake is maintained and supported by `Kitware`_ and developed in
+collaboration with a productive community of contributors.
+Please post to the ``Development`` category of the `CMake Forum`_ to raise
+discussion of development topics.
+
+.. _`Kitware`: http://www.kitware.com/cmake
+.. _`CMake Forum`: https://discourse.cmake.org
+
Patches
=======
-KWSys is kept in its own Git repository and shared by several projects
-via copies in their source trees. Changes to KWSys should not be made
-directly in a host project, except perhaps in maintenance branches.
-
-KWSys uses `Kitware's GitLab Instance`_ to manage development and code review.
+CMake uses `Kitware's GitLab Instance`_ to manage development and code review.
To contribute patches:
-#. Fork the upstream `KWSys Repository`_ into a personal account.
-#. Base all new work on the upstream ``master`` branch.
-#. Run ``./SetupForDevelopment.sh`` in new local work trees.
-#. Create commits making incremental, distinct, logically complete changes.
-#. Push a topic branch to a personal repository fork on GitLab.
-#. Create a GitLab Merge Request targeting the upstream ``master`` branch.
+#. Fork the upstream `CMake Repository`_ into a personal account.
+#. Run `Utilities/SetupForDevelopment.sh`_ for local git configuration.
+#. See `Building CMake`_ for building CMake locally.
+#. See the `CMake Source Code Guide`_ for coding guidelines.
+#. Create a topic branch named suitably for your work.
+ Base all new work on the upstream ``master`` branch.
+ Base work on the upstream ``release`` branch only if it fixes a
+ regression or bug in a feature new to that release.
+ If in doubt, prefer ``master``. Reviewers may simply ask for
+ a rebase if deemed appropriate in particular cases.
+#. Create commits making incremental, distinct, logically complete changes
+ with appropriate `commit messages`_.
+#. Push the topic branch to a personal repository fork on GitLab.
+#. Create a GitLab Merge Request targeting the upstream ``master`` branch
+ (even if the change is intended for merge to the ``release`` branch).
+ Check the box labelled "Allow commits from members who can merge to the
+ target branch". This will allow maintainers to make minor edits on your
+ behalf.
-Once changes are reviewed, tested, and integrated to KWSys upstream then
-copies of KWSys within dependent projects can be updated to get the changes.
+The merge request will enter the `CMake Review Process`_ for consideration.
.. _`Kitware's GitLab Instance`: https://gitlab.kitware.com
-.. _`KWSys Repository`: https://gitlab.kitware.com/utils/kwsys
+.. _`CMake Repository`: https://gitlab.kitware.com/cmake/cmake
+.. _`Utilities/SetupForDevelopment.sh`: Utilities/SetupForDevelopment.sh
+.. _`Building CMake`: README.rst#building-cmake
+.. _`CMake Source Code Guide`: Help/dev/source.rst
+.. _`commit messages`: Help/dev/review.rst#commit-messages
+.. _`CMake Review Process`: Help/dev/review.rst
+
+CMake Dashboard Client
+======================
-Code Style
-==========
+The *integration testing* step of the `CMake Review Process`_ uses a set of
+testing machines that follow an integration branch on their own schedule to
+drive testing and submit results to the `CMake CDash Page`_. Anyone is
+welcome to provide testing machines in order to help keep support for their
+platforms working.
-We use `clang-format`_ version **6.0** to define our style for C++ code in
-the KWSys source tree. See the `.clang-format`_ configuration file for
-our style settings. Use the `clang-format.bash`_ script to format source
-code. It automatically runs ``clang-format`` on the set of source files
-for which we enforce style. The script also has options to format only
-a subset of files, such as those that are locally modified.
+See documentation on `CMake Testing Process`_ for more information.
-.. _`clang-format`: http://clang.llvm.org/docs/ClangFormat.html
-.. _`.clang-format`: .clang-format
-.. _`clang-format.bash`: clang-format.bash
+.. _`CMake CDash Page`: https://open.cdash.org/index.php?project=CMake
+.. _`CMake Testing Process`: Help/dev/testing.rst
License
=======
diff --git a/CTestConfig.cmake b/CTestConfig.cmake
index 12347b6..476a1c6 100644
--- a/CTestConfig.cmake
+++ b/CTestConfig.cmake
@@ -1,11 +1,16 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
-# file Copyright.txt or https://cmake.org/licensing#kwsys for details.
+# file Copyright.txt or https://cmake.org/licensing for details.
-set(CTEST_PROJECT_NAME "KWSys")
-set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
-if (NOT CTEST_DROP_METHOD STREQUAL "https")
+# If changing this file, also update Utilities/Sphinx/CTestConfig.cmake
+
+set(CTEST_PROJECT_NAME "CMake")
+set(CTEST_NIGHTLY_START_TIME "1:00:00 UTC")
+
+if(NOT CTEST_DROP_METHOD STREQUAL "https")
set(CTEST_DROP_METHOD "http")
-endif ()
+endif()
set(CTEST_DROP_SITE "open.cdash.org")
-set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
+set(CTEST_DROP_LOCATION "/submit.php?project=CMake")
set(CTEST_DROP_SITE_CDASH TRUE)
+set(CTEST_CDASH_VERSION "1.6")
+set(CTEST_CDASH_QUERY_VERSION TRUE)
diff --git a/CTestCustom.cmake.in b/CTestCustom.cmake.in
index c07f0f3..4c8267d 100644
--- a/CTestCustom.cmake.in
+++ b/CTestCustom.cmake.in
@@ -1,18 +1,129 @@
-# kwsys.testProcess-10 involves sending SIGINT to a child process, which then
-# exits abnormally via a call to _exit(). (On Windows, a call to ExitProcess).
-# Naturally, this results in plenty of memory being "leaked" by this child
-# process - the memory check results are not meaningful in this case.
-#
-# kwsys.testProcess-9 also tests sending SIGINT to a child process. However,
-# normal operation of that test involves the child process timing out, and the
-# host process kills (SIGKILL) it as a result. Since it was SIGKILL'ed, the
-# resulting memory leaks are not logged by valgrind anyway. Therefore, we
-# don't have to exclude it.
+list(APPEND CTEST_CUSTOM_ERROR_MATCH
+ "ERROR:")
-list(APPEND CTEST_CUSTOM_MEMCHECK_IGNORE
- kwsys.testProcess-10
+list(APPEND CTEST_CUSTOM_WARNING_EXCEPTION
+ "warning: cast from 'char\\*' to 'cmCursesWidget\\*' increases required alignment of target type" # Occurs when using Solaris's system libform
+ "xtree.[0-9]+. : warning C4702: unreachable code"
+ "warning LNK4221"
+ "warning LNK4204" # Occurs by race condition with objects in small libs
+ "variable .var_args[2]*. is used before its value is set"
+ "jobserver unavailable"
+ "warning: \\(Long double usage is reported only once for each file"
+ "warning: To disable this warning use"
+ "could not be inlined"
+ "libcmexpat.*has no symbols"
+ "libcmcurl.*has no symbols"
+ "not sorted slower link editing will result"
+ "stl_deque.h:479"
+ "Utilities.cmzlib."
+ "Utilities.cmbzip2."
+ "Source.CTest.Curl"
+ "Source.CursesDialog.form"
+ "Utilities.cmcurl"
+ "Utilities.cmexpat."
+ "Utilities.cmlibarchive"
+ "warning: declaration of .single. shadows a global declaration"
+ "/usr/include.*(warning|note).*shadowed declaration is here"
+ "/usr/bin/ld.*warning.*-..*directory.name.*bin.*does not exist"
+ "Redeclaration of .send..... with a different storage class specifier"
+ "is not used for resolving any symbol"
+ "Clock skew detected"
+ "remark\\(1209"
+ "remark: .*LOOP WAS VECTORIZED"
+ "warning .980: wrong number of actual arguments to intrinsic function .std::basic_"
+ "LINK : warning LNK4089: all references to.*ADVAPI32.dll.*discarded by /OPT:REF"
+ "LINK : warning LNK4089: all references to.*CRYPT32.dll.*discarded by /OPT:REF"
+ "LINK : warning LNK4089: all references to.*PSAPI.DLL.*discarded by /OPT:REF"
+ "LINK : warning LNK4089: all references to.*RPCRT4.dll.*discarded by /OPT:REF"
+ "LINK : warning LNK4089: all references to.*SHELL32.dll.*discarded by /OPT:REF"
+ "LINK : warning LNK4089: all references to.*USER32.dll.*discarded by /OPT:REF"
+ "LINK : warning LNK4089: all references to.*ole32.dll.*discarded by /OPT:REF"
+ "Warning.*: .*/Utilities/KWIML/test/test_int_format.h.* # Redundant preprocessing concatenation"
+ "Warning: library was too large for page size.*"
+ "Warning: public.*_archive_.*in module.*archive_*clashes with prior module.*archive_.*"
+ "Warning: public.*BZ2_bz.*in module.*bzlib.*clashes with prior module.*bzlib.*"
+ "Warning: public.*_archive.*clashes with prior module.*"
+ "Warning: LINN32: Last line.*is less.*"
+ "Warning: Olimit was exceeded on function.*"
+ "Warning: To override Olimit for all functions in file.*"
+ "Warning: Function .* can throw only the exceptions thrown by the function .* it overrides\\."
+ "WarningMessagesDialog\\.cxx"
+ "warning.*directory name.*CMake-Xcode.*/bin/.*does not exist.*"
+ "stl_deque.h:1051"
+ "Tests/CMakeLib/testCTestResourceSpec.cxx:.*warning: missing initializer for member.*cmCTestResourceSpec::.*" # GCC 4.8 disagrees with later compilers on C++11 initializer list conversion
+ "(Lexer|Parser).*warning.*conversion.*may (alter its value|change the sign)"
+ "(Lexer|Parser).*warning.*(statement is unreachable|will never be executed)"
+ "(Lexer|Parser).*warning.*variable.*was set but never used"
+ "LexerParser.*warning.*empty expression statement has no effect; remove unnecessary"
+ "PGC-W-0095-Type cast required for this conversion.*ProcessUNIX.c"
+ "[Qq]t([Cc]ore|[Gg]ui|[Ww]idgets).*warning.*conversion.*may alter its value"
+ "warning:.*is.*very unsafe.*consider using.*"
+ "warning:.*is.*misused, please use.*"
+ "cmake.version.manifest.*manifest authoring warning.*Unrecognized Element"
+ "cc-3968 CC: WARNING File.*" # "implicit" truncation by static_cast
+ "ld: warning: directory not found for option .-(F|L)"
+ "ld: warning .*/libgcc.a archive's cputype"
+ "ld: warning: ignoring file .*/libgcc.a, file was built for archive which is not the architecture being linked"
+ "ld: warning: in .*/libgcc.a, file is not of required architecture"
+ "ld: warning: symbol .(deflate|inflate)_copyright. has differing sizes" # system libz and QtCore disagree
+ "warning.*This version of Mac OS X is unsupported"
+ "clang.*: warning: argument unused during compilation: .-g"
+ "note: in expansion of macro" # diagnostic context note
+ "note: expanded from macro" # diagnostic context note
+ "cm(StringCommand|CTestTestHandler)\\.cxx.*warning.*rand.*may return deterministic values"
+ "cm(StringCommand|CTestTestHandler)\\.cxx.*warning.*rand.*isn.*t random" # we do not do crypto
+ "cm(StringCommand|CTestTestHandler)\\.cxx.*warning.*srand.*seed choices are.*poor" # we do not do crypto
+ "IPA warning: function.*multiply defined in"
+ "LICENSE WARNING" # PGI license expiry. Not useful in nightly testing.
+
+ # Ignore compiler summary warning, assuming prior text has matched some
+ # other warning expression:
+ "[0-9,]+ warnings? generated." # Clang
+ "compilation completed with warnings" # PGI
+ "[0-9]+ Warning\\(s\\) detected" # SunPro
+
+ # scanbuild exceptions
+ "char_traits.h:.*: warning: Null pointer argument in call to string length function"
+ "stl_construct.h:.*: warning: Forming reference to null pointer"
+ ".*stl_uninitialized.h:75:19: warning: Forming reference to null pointer.*"
+ ".*stl_vector.h:.*: warning: Returning null reference.*"
+ "warning: Value stored to 'yymsg' is never read"
+ "warning: Value stored to 'yytoken' is never read"
+ "index_encoder.c.241.2. warning: Value stored to .out_start. is never read"
+ "index.c.*warning: Access to field.*results in a dereference of a null pointer.*loaded from variable.*"
+ "cmCommandArgumentLexer.cxx:[0-9]+:[0-9]+: warning: Call to 'realloc' has an allocation size of 0 bytes"
+ "cmDependsJavaLexer.cxx:[0-9]+:[0-9]+: warning: Call to 'realloc' has an allocation size of 0 bytes"
+ "cmExprLexer.cxx:[0-9]+:[0-9]+: warning: Call to 'realloc' has an allocation size of 0 bytes"
+ "cmListFileLexer.c:[0-9]+:[0-9]+: warning: Call to 'realloc' has an allocation size of 0 bytes"
+ "cmFortranLexer.cxx:[0-9]+:[0-9]+: warning: Call to 'realloc' has an allocation size of 0 bytes"
+ "testProcess.*warning: Dereference of null pointer .loaded from variable .invalidAddress.."
+ "liblzma/simple/x86.c:[0-9]+:[0-9]+: warning: The result of the '<<' expression is undefined"
+ "liblzma/common/index_encoder.c:[0-9]+:[0-9]+: warning: Value stored to .* during its initialization is never read"
+ "libuv/src/.*:[0-9]+:[0-9]+: warning: Dereference of null pointer"
+ "libuv/src/.*:[0-9]+:[0-9]+: warning: The left operand of '==' is a garbage value"
+ "libuv/src/.*:[0-9]+:[0-9]+: warning: 1st function call argument is an uninitialized value"
+ "nghttp2/lib/.*:[0-9]+:[0-9]+: warning: Dereference of null pointer"
+ "nghttp2/lib/.*:[0-9]+:[0-9]+: warning: Value stored to .* is never read"
)
-list(APPEND CTEST_CUSTOM_WARNING_EXCEPTION
- "LICENSE WARNING"
+if(NOT "@CMAKE_GENERATOR@" MATCHES "Xcode")
+ list(APPEND CTEST_CUSTOM_COVERAGE_EXCLUDE
+ "XCode"
+ )
+endif ()
+
+list(APPEND CTEST_CUSTOM_COVERAGE_EXCLUDE
+ # Exclude kwsys files from coverage results. They are reported
+ # (with better coverage results) on kwsys dashboards...
+ "/Source/(cm|kw)sys/"
+
+ # Exclude try_compile sources from coverage results:
+ "/CMakeFiles/CMakeTmp/"
+
+ # Exclude Qt source files from coverage results:
+ "[A-Za-z]./[Qq]t/qt-.+-opensource-src"
+ )
+
+list(APPEND CTEST_CUSTOM_MEMCHECK_IGNORE
+ kwsys.testProcess-10 # See Source/kwsys/CTestCustom.cmake.in
)
diff --git a/CompileFlags.cmake b/CompileFlags.cmake
new file mode 100644
index 0000000..e6fb20b
--- /dev/null
+++ b/CompileFlags.cmake
@@ -0,0 +1,138 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#-----------------------------------------------------------------------------
+# set some special flags for different compilers
+#
+if(WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "Intel")
+ set(_INTEL_WINDOWS 1)
+endif()
+
+if(WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "Clang"
+ AND "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ set(_CLANG_MSVC_WINDOWS 1)
+endif()
+
+# Disable deprecation warnings for standard C functions.
+# really only needed for newer versions of VS, but should
+# not hurt other versions, and this will work into the
+# future
+if(MSVC OR _INTEL_WINDOWS OR _CLANG_MSVC_WINDOWS)
+ add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE)
+else()
+endif()
+
+if(MSVC)
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stack:10000000")
+endif()
+
+# MSVC 14.28 enables C5105, but the Windows SDK 10.0.18362.0 triggers it.
+if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 19.28)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -wd5105")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd5105")
+endif()
+
+if(_CLANG_MSVC_WINDOWS AND "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Xlinker -stack:20000000")
+endif()
+
+#silence duplicate symbol warnings on AIX
+if(CMAKE_SYSTEM_NAME MATCHES "AIX")
+ if(NOT CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -bhalt:5 ")
+ endif()
+endif()
+
+if(CMAKE_SYSTEM MATCHES "OSF1-V")
+ if(NOT CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -timplicit_local -no_implicit_include ")
+ endif()
+endif()
+
+# Workaround for short jump tables on PA-RISC
+if(CMAKE_SYSTEM_PROCESSOR MATCHES "^parisc")
+ if(CMAKE_COMPILER_IS_GNUCC)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mlong-calls")
+ endif()
+ if(CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mlong-calls")
+ endif()
+endif()
+
+# Use 64-bit off_t on 32-bit Linux
+if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SIZEOF_VOID_P EQUAL 4)
+ # ensure 64bit offsets are used for filesystem accesses for 32bit compilation
+ add_definitions(-D_FILE_OFFSET_BITS=64)
+endif()
+
+# Workaround for TOC Overflow on ppc64
+set(bigTocFlag "")
+if(CMAKE_SYSTEM_NAME STREQUAL "AIX" AND
+ CMAKE_SYSTEM_PROCESSOR MATCHES "powerpc")
+ set(bigTocFlag "-Wl,-bbigtoc")
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND
+ CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64")
+ set(bigTocFlag "-Wl,--no-multi-toc")
+endif()
+if(bigTocFlag)
+ include(CheckCXXLinkerFlag)
+ check_cxx_linker_flag(${bigTocFlag} BIG_TOC_FLAG_SUPPORTED)
+ if(BIG_TOC_FLAG_SUPPORTED)
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${bigTocFlag}")
+ endif()
+endif()
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL SunPro AND
+ NOT DEFINED CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION)
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
+ if (NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD EQUAL 98)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03")
+ elseif(CMAKE_VERSION VERSION_LESS 3.8.20170502)
+ # CMake knows how to add this flag for compilation as C++11,
+ # but has not been taught that SunPro needs it for linking too.
+ # Add it in a place that will be used for both.
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ endif()
+ else()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=stlport4")
+ endif()
+endif()
+
+foreach(lang C CXX)
+ # Suppress warnings from PGI compiler.
+ if (CMAKE_${lang}_COMPILER_ID STREQUAL "PGI")
+ set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} -w")
+ endif()
+endforeach()
+
+# use the ansi CXX compile flag for building cmake
+if (CMAKE_ANSI_CXXFLAGS)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_ANSI_CXXFLAGS}")
+endif ()
+
+if (CMAKE_ANSI_CFLAGS)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ANSI_CFLAGS}")
+endif ()
+
+# Allow per-translation-unit parallel builds when using MSVC
+if(CMAKE_GENERATOR MATCHES "Visual Studio" AND
+ (CMAKE_C_COMPILER_ID MATCHES "MSVC|Intel" OR
+ CMAKE_CXX_COMPILER_ID MATCHES "MSVC|Intel"))
+
+ set(CMake_MSVC_PARALLEL ON CACHE STRING "\
+Enables /MP flag for parallel builds using MSVC. Specify an \
+integer value to control the number of threads used (Only \
+works on some older versions of Visual Studio). Setting to \
+ON lets the toolchain decide how many threads to use. Set to \
+OFF to disable /MP completely." )
+
+ if(CMake_MSVC_PARALLEL)
+ if(CMake_MSVC_PARALLEL GREATER 0)
+ string(APPEND CMAKE_C_FLAGS " /MP${CMake_MSVC_PARALLEL}")
+ string(APPEND CMAKE_CXX_FLAGS " /MP${CMake_MSVC_PARALLEL}")
+ else()
+ string(APPEND CMAKE_C_FLAGS " /MP")
+ string(APPEND CMAKE_CXX_FLAGS " /MP")
+ endif()
+ endif()
+endif()
diff --git a/Copyright.txt b/Copyright.txt
index 33d7fb4..7f51293 100644
--- a/Copyright.txt
+++ b/Copyright.txt
@@ -1,5 +1,5 @@
-KWSys - Kitware System Library
-Copyright 2000-2016 Kitware, Inc. and Contributors
+CMake - Cross Platform Makefile Generator
+Copyright 2000-2021 Kitware, Inc. and Contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,100 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The following individuals and institutions are among the Contributors:
+* Aaron C. Meadows <cmake@shadowguarddev.com>
+* Adriaan de Groot <groot@kde.org>
+* Aleksey Avdeev <solo@altlinux.ru>
+* Alexander Neundorf <neundorf@kde.org>
+* Alexander Smorkalov <alexander.smorkalov@itseez.com>
+* Alexey Sokolov <sokolov@google.com>
+* Alex Merry <alex.merry@kde.org>
+* Alex Turbov <i.zaufi@gmail.com>
+* Andreas Pakulat <apaku@gmx.de>
+* Andreas Schneider <asn@cryptomilk.org>
+* André Rigland Brodtkorb <Andre.Brodtkorb@ifi.uio.no>
+* Axel Huebl, Helmholtz-Zentrum Dresden - Rossendorf
+* Benjamin Eikel
+* Bjoern Ricks <bjoern.ricks@gmail.com>
+* Brad Hards <bradh@kde.org>
+* Christopher Harvey
+* Christoph Grüninger <foss@grueninger.de>
+* Clement Creusot <creusot@cs.york.ac.uk>
+* Daniel Blezek <blezek@gmail.com>
+* Daniel Pfeifer <daniel@pfeifer-mail.de>
+* Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+* Eran Ifrah <eran.ifrah@gmail.com>
+* Esben Mose Hansen, Ange Optimization ApS
+* Geoffrey Viola <geoffrey.viola@asirobots.com>
+* Google Inc
+* Gregor Jasny
+* Helio Chissini de Castro <helio@kde.org>
+* Ilya Lavrenov <ilya.lavrenov@itseez.com>
* Insight Software Consortium <insightsoftwareconsortium.org>
+* Jan Woetzel
+* Julien Schueller
+* Kelly Thompson <kgt@lanl.gov>
+* Konstantin Podsvirov <konstantin@podsvirov.pro>
+* Laurent Montel <montel@kde.org>
+* Mario Bensi <mbensi@ipsquad.net>
+* Martin Gräßlin <mgraesslin@kde.org>
+* Mathieu Malaterre <mathieu.malaterre@gmail.com>
+* Matthaeus G. Chajdas
+* Matthias Kretz <kretz@kde.org>
+* Matthias Maennich <matthias@maennich.net>
+* Michael Hirsch, Ph.D. <www.scivision.co>
+* Michael Stürmer
+* Miguel A. Figueroa-Villanueva
+* Mike Jackson
+* Mike McQuaid <mike@mikemcquaid.com>
+* Nicolas Bock <nicolasbock@gmail.com>
+* Nicolas Despres <nicolas.despres@gmail.com>
+* Nikita Krupen'ko <krnekit@gmail.com>
+* NVIDIA Corporation <www.nvidia.com>
+* OpenGamma Ltd. <opengamma.com>
+* Patrick Stotko <stotko@cs.uni-bonn.de>
+* Per Øyvind Karlsen <peroyvind@mandriva.org>
+* Peter Collingbourne <peter@pcc.me.uk>
+* Petr Gotthard <gotthard@honeywell.com>
+* Philip Lowman <philip@yhbt.com>
+* Philippe Proulx <pproulx@efficios.com>
+* Raffi Enficiaud, Max Planck Society
+* Raumfeld <raumfeld.com>
+* Roger Leigh <rleigh@codelibre.net>
+* Rolf Eike Beer <eike@sf-mail.de>
+* Roman Donchenko <roman.donchenko@itseez.com>
+* Roman Kharitonov <roman.kharitonov@itseez.com>
+* Ruslan Baratov
+* Sebastian Holtermann <sebholt@xwmw.org>
+* Stephen Kelly <steveire@gmail.com>
+* Sylvain Joubert <joubert.sy@gmail.com>
+* The Qt Company Ltd.
+* Thomas Sondergaard <ts@medical-insight.com>
+* Tobias Hunger <tobias.hunger@qt.io>
+* Todd Gamblin <tgamblin@llnl.gov>
+* Tristan Carel
+* University of Dundee
+* Vadim Zhukov
+* Will Dicharry <wdicharry@stellarscience.com>
See version control history for details of individual contributions.
+
+The above copyright and license notice applies to distributions of
+CMake in source and binary form. Third-party software packages supplied
+with CMake under compatible licenses provide their own copyright notices
+documented in corresponding subdirectories or source files.
+
+------------------------------------------------------------------------------
+
+CMake was initially developed by Kitware with the following sponsorship:
+
+ * National Library of Medicine at the National Institutes of Health
+ as part of the Insight Segmentation and Registration Toolkit (ITK).
+
+ * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
+ Visualization Initiative.
+
+ * National Alliance for Medical Image Computing (NAMIC) is funded by the
+ National Institutes of Health through the NIH Roadmap for Medical Research,
+ Grant U54 EB005149.
+
+ * Kitware, Inc.
diff --git a/DartConfig.cmake b/DartConfig.cmake
new file mode 100644
index 0000000..7d7c45b
--- /dev/null
+++ b/DartConfig.cmake
@@ -0,0 +1,10 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+set(CTEST_PROJECT_NAME "CMake")
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=CMake")
+set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/Help/command/DEVICE_LINK_OPTIONS.txt b/Help/command/DEVICE_LINK_OPTIONS.txt
new file mode 100644
index 0000000..1297cd0
--- /dev/null
+++ b/Help/command/DEVICE_LINK_OPTIONS.txt
@@ -0,0 +1,12 @@
+
+.. versionadded:: 3.18
+ When a device link step is involved, which is controlled by
+ :prop_tgt:`CUDA_SEPARABLE_COMPILATION` and
+ :prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` properties and policy :policy:`CMP0105`,
+ the raw options will be delivered to the host and device link steps (wrapped in
+ ``-Xcompiler`` or equivalent for device link). Options wrapped with
+ ``$<DEVICE_LINK:...>``
+ :manual:`generator expression <cmake-generator-expressions(7)>` will be used
+ only for the device link step. Options wrapped with ``$<HOST_LINK:...>``
+ :manual:`generator expression <cmake-generator-expressions(7)>` will be used
+ only for the host link step.
diff --git a/Help/command/FIND_XXX.txt b/Help/command/FIND_XXX.txt
new file mode 100644
index 0000000..aae1c38
--- /dev/null
+++ b/Help/command/FIND_XXX.txt
@@ -0,0 +1,167 @@
+A short-hand signature is:
+
+.. parsed-literal::
+
+ |FIND_XXX| (<VAR> name1 [path1 path2 ...])
+
+The general signature is:
+
+.. parsed-literal::
+
+ |FIND_XXX| (
+ <VAR>
+ name | |NAMES|
+ [HINTS [path | ENV var]... ]
+ [PATHS [path | ENV var]... ]
+ [PATH_SUFFIXES suffix1 [suffix2 ...]]
+ [DOC "cache documentation string"]
+ [REQUIRED]
+ [NO_DEFAULT_PATH]
+ [NO_PACKAGE_ROOT_PATH]
+ [NO_CMAKE_PATH]
+ [NO_CMAKE_ENVIRONMENT_PATH]
+ [NO_SYSTEM_ENVIRONMENT_PATH]
+ [NO_CMAKE_SYSTEM_PATH]
+ [CMAKE_FIND_ROOT_PATH_BOTH |
+ ONLY_CMAKE_FIND_ROOT_PATH |
+ NO_CMAKE_FIND_ROOT_PATH]
+ )
+
+This command is used to find a |SEARCH_XXX_DESC|.
+A cache entry named by ``<VAR>`` is created to store the result
+of this command.
+If the |SEARCH_XXX| is found the result is stored in the variable
+and the search will not be repeated unless the variable is cleared.
+If nothing is found, the result will be ``<VAR>-NOTFOUND``.
+
+Options include:
+
+``NAMES``
+ Specify one or more possible names for the |SEARCH_XXX|.
+
+ When using this to specify names with and without a version
+ suffix, we recommend specifying the unversioned name first
+ so that locally-built packages can be found before those
+ provided by distributions.
+
+``HINTS``, ``PATHS``
+ Specify directories to search in addition to the default locations.
+ The ``ENV var`` sub-option reads paths from a system environment
+ variable.
+
+``PATH_SUFFIXES``
+ Specify additional subdirectories to check below each directory
+ location otherwise considered.
+
+``DOC``
+ Specify the documentation string for the ``<VAR>`` cache entry.
+
+``REQUIRED``
+ .. versionadded:: 3.18
+
+ Stop processing with an error message if nothing is found, otherwise
+ the search will be attempted again the next time |FIND_XXX| is invoked
+ with the same variable.
+
+If ``NO_DEFAULT_PATH`` is specified, then no additional paths are
+added to the search.
+If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows:
+
+.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR| replace::
+ |prefix_XXX_SUBDIR| for each ``<prefix>`` in the
+ :variable:`<PackageName>_ROOT` CMake variable and the
+ :envvar:`<PackageName>_ROOT` environment variable if
+ called from within a find module loaded by
+ :command:`find_package(<PackageName>)`
+
+.. |CMAKE_PREFIX_PATH_XXX_SUBDIR| replace::
+ |prefix_XXX_SUBDIR| for each ``<prefix>`` in :variable:`CMAKE_PREFIX_PATH`
+
+.. |SYSTEM_ENVIRONMENT_PREFIX_PATH_XXX_SUBDIR| replace::
+ |prefix_XXX_SUBDIR| for each ``<prefix>/[s]bin`` in ``PATH``, and
+ |entry_XXX_SUBDIR| for other entries in ``PATH``
+
+.. |CMAKE_SYSTEM_PREFIX_PATH_XXX_SUBDIR| replace::
+ |prefix_XXX_SUBDIR| for each ``<prefix>`` in
+ :variable:`CMAKE_SYSTEM_PREFIX_PATH`
+
+1. .. versionadded:: 3.12
+ If called from within a find module or any other script loaded by a call to
+ :command:`find_package(<PackageName>)`, search prefixes unique to the
+ current package being found. Specifically, look in the
+ :variable:`<PackageName>_ROOT` CMake variable and the
+ :envvar:`<PackageName>_ROOT` environment variable.
+ The package root variables are maintained as a stack, so if called from
+ nested find modules or config packages, root paths from the parent's find
+ module or config package will be searched after paths from the current
+ module or package. In other words, the search order would be
+ ``<CurrentPackage>_ROOT``, ``ENV{<CurrentPackage>_ROOT}``,
+ ``<ParentPackage>_ROOT``, ``ENV{<ParentPackage>_ROOT}``, etc.
+ This can be skipped if ``NO_PACKAGE_ROOT_PATH`` is passed or by setting
+ the :variable:`CMAKE_FIND_USE_PACKAGE_ROOT_PATH` to ``FALSE``.
+ See policy :policy:`CMP0074`.
+
+ * |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX|
+
+2. Search paths specified in cmake-specific cache variables.
+ These are intended to be used on the command line with a ``-DVAR=value``.
+ The values are interpreted as :ref:`semicolon-separated lists <CMake Language Lists>`.
+ This can be skipped if ``NO_CMAKE_PATH`` is passed or by setting the
+ :variable:`CMAKE_FIND_USE_CMAKE_PATH` to ``FALSE``.
+
+ * |CMAKE_PREFIX_PATH_XXX|
+ * |CMAKE_XXX_PATH|
+ * |CMAKE_XXX_MAC_PATH|
+
+3. Search paths specified in cmake-specific environment variables.
+ These are intended to be set in the user's shell configuration,
+ and therefore use the host's native path separator
+ (``;`` on Windows and ``:`` on UNIX).
+ This can be skipped if ``NO_CMAKE_ENVIRONMENT_PATH`` is passed or
+ by setting the :variable:`CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH` to ``FALSE``.
+
+ * |CMAKE_PREFIX_PATH_XXX|
+ * |CMAKE_XXX_PATH|
+ * |CMAKE_XXX_MAC_PATH|
+
+4. Search the paths specified by the ``HINTS`` option.
+ These should be paths computed by system introspection, such as a
+ hint provided by the location of another item already found.
+ Hard-coded guesses should be specified with the ``PATHS`` option.
+
+5. Search the standard system environment variables.
+ This can be skipped if ``NO_SYSTEM_ENVIRONMENT_PATH`` is passed or by
+ setting the :variable:`CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH` to ``FALSE``.
+
+ * |SYSTEM_ENVIRONMENT_PATH_XXX|
+ * |SYSTEM_ENVIRONMENT_PATH_WINDOWS_XXX|
+
+6. Search cmake variables defined in the Platform files
+ for the current system. This can be skipped if ``NO_CMAKE_SYSTEM_PATH``
+ is passed or by setting the :variable:`CMAKE_FIND_USE_CMAKE_SYSTEM_PATH`
+ to ``FALSE``.
+
+ * |CMAKE_SYSTEM_PREFIX_PATH_XXX|
+ * |CMAKE_SYSTEM_XXX_PATH|
+ * |CMAKE_SYSTEM_XXX_MAC_PATH|
+
+ The platform paths that these variables contain are locations that
+ typically include installed software. An example being ``/usr/local`` for
+ UNIX based platforms.
+
+7. Search the paths specified by the PATHS option
+ or in the short-hand version of the command.
+ These are typically hard-coded guesses.
+
+.. versionadded:: 3.16
+ Added ``CMAKE_FIND_USE_<CATEGORY>_PATH`` variables to globally disable
+ various search locations.
+
+.. |FIND_ARGS_XXX| replace:: <VAR> NAMES name
+
+On macOS the :variable:`CMAKE_FIND_FRAMEWORK` and
+:variable:`CMAKE_FIND_APPBUNDLE` variables determine the order of
+preference between Apple-style and unix-style package components.
+
+.. include:: FIND_XXX_ROOT.txt
+.. include:: FIND_XXX_ORDER.txt
diff --git a/Help/command/FIND_XXX_ORDER.txt b/Help/command/FIND_XXX_ORDER.txt
new file mode 100644
index 0000000..bac2419
--- /dev/null
+++ b/Help/command/FIND_XXX_ORDER.txt
@@ -0,0 +1,12 @@
+The default search order is designed to be most-specific to
+least-specific for common use cases.
+Projects may override the order by simply calling the command
+multiple times and using the ``NO_*`` options:
+
+.. parsed-literal::
+
+ |FIND_XXX| (|FIND_ARGS_XXX| PATHS paths... NO_DEFAULT_PATH)
+ |FIND_XXX| (|FIND_ARGS_XXX|)
+
+Once one of the calls succeeds the result variable will be set
+and stored in the cache so that no call will search again.
diff --git a/Help/command/FIND_XXX_ROOT.txt b/Help/command/FIND_XXX_ROOT.txt
new file mode 100644
index 0000000..fab2303
--- /dev/null
+++ b/Help/command/FIND_XXX_ROOT.txt
@@ -0,0 +1,29 @@
+The CMake variable :variable:`CMAKE_FIND_ROOT_PATH` specifies one or more
+directories to be prepended to all other search directories. This
+effectively "re-roots" the entire search under given locations.
+Paths which are descendants of the :variable:`CMAKE_STAGING_PREFIX` are excluded
+from this re-rooting, because that variable is always a path on the host system.
+By default the :variable:`CMAKE_FIND_ROOT_PATH` is empty.
+
+The :variable:`CMAKE_SYSROOT` variable can also be used to specify exactly one
+directory to use as a prefix. Setting :variable:`CMAKE_SYSROOT` also has other
+effects. See the documentation for that variable for more.
+
+These variables are especially useful when cross-compiling to
+point to the root directory of the target environment and CMake will
+search there too. By default at first the directories listed in
+:variable:`CMAKE_FIND_ROOT_PATH` are searched, then the :variable:`CMAKE_SYSROOT`
+directory is searched, and then the non-rooted directories will be
+searched. The default behavior can be adjusted by setting
+|CMAKE_FIND_ROOT_PATH_MODE_XXX|. This behavior can be manually
+overridden on a per-call basis using options:
+
+``CMAKE_FIND_ROOT_PATH_BOTH``
+ Search in the order described above.
+
+``NO_CMAKE_FIND_ROOT_PATH``
+ Do not use the :variable:`CMAKE_FIND_ROOT_PATH` variable.
+
+``ONLY_CMAKE_FIND_ROOT_PATH``
+ Search only the re-rooted directories and directories below
+ :variable:`CMAKE_STAGING_PREFIX`.
diff --git a/Help/command/LINK_OPTIONS_LINKER.txt b/Help/command/LINK_OPTIONS_LINKER.txt
new file mode 100644
index 0000000..3f66181
--- /dev/null
+++ b/Help/command/LINK_OPTIONS_LINKER.txt
@@ -0,0 +1,22 @@
+To pass options to the linker tool, each compiler driver has its own syntax.
+The ``LINKER:`` prefix and ``,`` separator can be used to specify, in a portable
+way, options to pass to the linker tool. ``LINKER:`` is replaced by the
+appropriate driver option and ``,`` by the appropriate driver separator.
+The driver prefix and driver separator are given by the values of the
+:variable:`CMAKE_<LANG>_LINKER_WRAPPER_FLAG` and
+:variable:`CMAKE_<LANG>_LINKER_WRAPPER_FLAG_SEP` variables.
+
+For example, ``"LINKER:-z,defs"`` becomes ``-Xlinker -z -Xlinker defs`` for
+``Clang`` and ``-Wl,-z,defs`` for ``GNU GCC``.
+
+The ``LINKER:`` prefix can be specified as part of a ``SHELL:`` prefix
+expression.
+
+The ``LINKER:`` prefix supports, as an alternative syntax, specification of
+arguments using the ``SHELL:`` prefix and space as separator. The previous
+example then becomes ``"LINKER:SHELL:-z defs"``.
+
+.. note::
+
+ Specifying the ``SHELL:`` prefix anywhere other than at the beginning of the
+ ``LINKER:`` prefix is not supported.
diff --git a/Help/command/OPTIONS_SHELL.txt b/Help/command/OPTIONS_SHELL.txt
new file mode 100644
index 0000000..4051ffe
--- /dev/null
+++ b/Help/command/OPTIONS_SHELL.txt
@@ -0,0 +1,11 @@
+The final set of compile or link options used for a target is constructed by
+accumulating options from the current target and the usage requirements of
+its dependencies. The set of options is de-duplicated to avoid repetition.
+
+.. versionadded:: 3.12
+ While beneficial for individual options, the de-duplication step can break
+ up option groups. For example, ``-D A -D B`` becomes ``-D A B``. One may
+ specify a group of options using shell-like quoting along with a ``SHELL:``
+ prefix. The ``SHELL:`` prefix is dropped, and the rest of the option string
+ is parsed using the :command:`separate_arguments` ``UNIX_COMMAND`` mode.
+ For example, ``"SHELL:-D A" "SHELL:-D B"`` becomes ``-D A -D B``.
diff --git a/Help/command/add_compile_definitions.rst b/Help/command/add_compile_definitions.rst
new file mode 100644
index 0000000..48e33be
--- /dev/null
+++ b/Help/command/add_compile_definitions.rst
@@ -0,0 +1,27 @@
+add_compile_definitions
+-----------------------
+
+.. versionadded:: 3.12
+
+Add preprocessor definitions to the compilation of source files.
+
+.. code-block:: cmake
+
+ add_compile_definitions(<definition> ...)
+
+Adds preprocessor definitions to the compiler command line.
+
+The preprocessor definitions are added to the :prop_dir:`COMPILE_DEFINITIONS`
+directory property for the current ``CMakeLists`` file. They are also added to
+the :prop_tgt:`COMPILE_DEFINITIONS` target property for each target in the
+current ``CMakeLists`` file.
+
+Definitions are specified using the syntax ``VAR`` or ``VAR=value``.
+Function-style definitions are not supported. CMake will automatically
+escape the value correctly for the native build system (note that CMake
+language syntax may require escapes to specify some values).
+
+Arguments to ``add_compile_definitions`` may use "generator expressions" with
+the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
diff --git a/Help/command/add_compile_options.rst b/Help/command/add_compile_options.rst
new file mode 100644
index 0000000..36f403c
--- /dev/null
+++ b/Help/command/add_compile_options.rst
@@ -0,0 +1,51 @@
+add_compile_options
+-------------------
+
+Add options to the compilation of source files.
+
+.. code-block:: cmake
+
+ add_compile_options(<option> ...)
+
+Adds options to the :prop_dir:`COMPILE_OPTIONS` directory property.
+These options are used when compiling targets from the current
+directory and below.
+
+Arguments
+^^^^^^^^^
+
+Arguments to ``add_compile_options`` may use "generator expressions" with
+the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
+.. include:: OPTIONS_SHELL.txt
+
+Example
+^^^^^^^
+
+Since different compilers support different options, a typical use of
+this command is in a compiler-specific conditional clause:
+
+.. code-block:: cmake
+
+ if (MSVC)
+ # warning level 4 and all warnings as errors
+ add_compile_options(/W4 /WX)
+ else()
+ # lots of warnings and all warnings as errors
+ add_compile_options(-Wall -Wextra -pedantic -Werror)
+ endif()
+
+See Also
+^^^^^^^^
+
+This command can be used to add any options. However, for
+adding preprocessor definitions and include directories it is recommended
+to use the more specific commands :command:`add_compile_definitions`
+and :command:`include_directories`.
+
+The command :command:`target_compile_options` adds target-specific options.
+
+The source file property :prop_sf:`COMPILE_OPTIONS` adds options to one
+source file.
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
new file mode 100644
index 0000000..b6ff0ea
--- /dev/null
+++ b/Help/command/add_custom_command.rst
@@ -0,0 +1,433 @@
+add_custom_command
+------------------
+
+Add a custom build rule to the generated build system.
+
+There are two main signatures for ``add_custom_command``.
+
+Generating Files
+^^^^^^^^^^^^^^^^
+
+The first signature is for adding a custom command to produce an output:
+
+.. code-block:: cmake
+
+ add_custom_command(OUTPUT output1 [output2 ...]
+ COMMAND command1 [ARGS] [args1...]
+ [COMMAND command2 [ARGS] [args2...] ...]
+ [MAIN_DEPENDENCY depend]
+ [DEPENDS [depends...]]
+ [BYPRODUCTS [files...]]
+ [IMPLICIT_DEPENDS <lang1> depend1
+ [<lang2> depend2] ...]
+ [WORKING_DIRECTORY dir]
+ [COMMENT comment]
+ [DEPFILE depfile]
+ [JOB_POOL job_pool]
+ [VERBATIM] [APPEND] [USES_TERMINAL]
+ [COMMAND_EXPAND_LISTS])
+
+This defines a command to generate specified ``OUTPUT`` file(s).
+A target created in the same directory (``CMakeLists.txt`` file)
+that specifies any output of the custom command as a source file
+is given a rule to generate the file using the command at build time.
+Do not list the output in more than one independent target that
+may build in parallel or the two instances of the rule may conflict
+(instead use the :command:`add_custom_target` command to drive the
+command and make the other targets depend on that one).
+In makefile terms this creates a new target in the following form::
+
+ OUTPUT: MAIN_DEPENDENCY DEPENDS
+ COMMAND
+
+The options are:
+
+``APPEND``
+ Append the ``COMMAND`` and ``DEPENDS`` option values to the custom
+ command for the first output specified. There must have already
+ been a previous call to this command with the same output.
+
+ If the previous call specified the output via a generator expression,
+ the output specified by the current call must match in at least one
+ configuration after evaluating generator expressions. In this case,
+ the appended commands and dependencies apply to all configurations.
+
+ The ``COMMENT``, ``MAIN_DEPENDENCY``, and ``WORKING_DIRECTORY``
+ options are currently ignored when APPEND is given, but may be
+ used in the future.
+
+``BYPRODUCTS``
+ .. versionadded:: 3.2
+
+ Specify the files the command is expected to produce but whose
+ modification time may or may not be newer than the dependencies.
+ If a byproduct name is a relative path it will be interpreted
+ relative to the build tree directory corresponding to the
+ current source directory.
+ Each byproduct file will be marked with the :prop_sf:`GENERATED`
+ source file property automatically.
+
+ Explicit specification of byproducts is supported by the
+ :generator:`Ninja` generator to tell the ``ninja`` build tool
+ how to regenerate byproducts when they are missing. It is
+ also useful when other build rules (e.g. custom commands)
+ depend on the byproducts. Ninja requires a build rule for any
+ generated file on which another rule depends even if there are
+ order-only dependencies to ensure the byproducts will be
+ available before their dependents build.
+
+ The :ref:`Makefile Generators` will remove ``BYPRODUCTS`` and other
+ :prop_sf:`GENERATED` files during ``make clean``.
+
+ .. versionadded:: 3.20
+ Arguments to ``BYPRODUCTS`` may use a restricted set of
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+ :ref:`Target-dependent expressions <Target-Dependent Queries>` are not
+ permitted.
+
+``COMMAND``
+ Specify the command-line(s) to execute at build time.
+ If more than one ``COMMAND`` is specified they will be executed in order,
+ but *not* necessarily composed into a stateful shell or batch script.
+ (To run a full script, use the :command:`configure_file` command or the
+ :command:`file(GENERATE)` command to create it, and then specify
+ a ``COMMAND`` to launch it.)
+ The optional ``ARGS`` argument is for backward compatibility and
+ will be ignored.
+
+ If ``COMMAND`` specifies an executable target name (created by the
+ :command:`add_executable` command), it will automatically be replaced
+ by the location of the executable created at build time if either of
+ the following is true:
+
+ * The target is not being cross-compiled (i.e. the
+ :variable:`CMAKE_CROSSCOMPILING` variable is not set to true).
+ * .. versionadded:: 3.6
+ The target is being cross-compiled and an emulator is provided (i.e.
+ its :prop_tgt:`CROSSCOMPILING_EMULATOR` target property is set).
+ In this case, the contents of :prop_tgt:`CROSSCOMPILING_EMULATOR` will be
+ prepended to the command before the location of the target executable.
+
+ If neither of the above conditions are met, it is assumed that the
+ command name is a program to be found on the ``PATH`` at build time.
+
+ Arguments to ``COMMAND`` may use
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+ Use the :genex:`TARGET_FILE` generator expression to refer to the location
+ of a target later in the command line (i.e. as a command argument rather
+ than as the command to execute).
+
+ Whenever one of the following target based generator expressions are used as
+ a command to execute or is mentioned in a command argument, a target-level
+ dependency will be added automatically so that the mentioned target will be
+ built before any target using this custom command
+ (see policy :policy:`CMP0112`).
+
+ * ``TARGET_FILE``
+ * ``TARGET_LINKER_FILE``
+ * ``TARGET_SONAME_FILE``
+ * ``TARGET_PDB_FILE``
+
+ This target-level dependency does NOT add a file-level dependency that would
+ cause the custom command to re-run whenever the executable is recompiled.
+ List target names with the ``DEPENDS`` option to add such file-level
+ dependencies.
+
+
+``COMMENT``
+ Display the given message before the commands are executed at
+ build time.
+
+``DEPENDS``
+ Specify files on which the command depends. Each argument is converted
+ to a dependency as follows:
+
+ 1. If the argument is the name of a target (created by the
+ :command:`add_custom_target`, :command:`add_executable`, or
+ :command:`add_library` command) a target-level dependency is
+ created to make sure the target is built before any target
+ using this custom command. Additionally, if the target is an
+ executable or library, a file-level dependency is created to
+ cause the custom command to re-run whenever the target is
+ recompiled.
+
+ 2. If the argument is an absolute path, a file-level dependency
+ is created on that path.
+
+ 3. If the argument is the name of a source file that has been
+ added to a target or on which a source file property has been set,
+ a file-level dependency is created on that source file.
+
+ 4. If the argument is a relative path and it exists in the current
+ source directory, a file-level dependency is created on that
+ file in the current source directory.
+
+ 5. Otherwise, a file-level dependency is created on that path relative
+ to the current binary directory.
+
+ If any dependency is an ``OUTPUT`` of another custom command in the same
+ directory (``CMakeLists.txt`` file), CMake automatically brings the other
+ custom command into the target in which this command is built.
+
+ .. versionadded:: 3.16
+ A target-level dependency is added if any dependency is listed as
+ ``BYPRODUCTS`` of a target or any of its build events in the same
+ directory to ensure the byproducts will be available.
+
+ If ``DEPENDS`` is not specified, the command will run whenever
+ the ``OUTPUT`` is missing; if the command does not actually
+ create the ``OUTPUT``, the rule will always run.
+
+ .. versionadded:: 3.1
+ Arguments to ``DEPENDS`` may use
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+``COMMAND_EXPAND_LISTS``
+ .. versionadded:: 3.8
+
+ Lists in ``COMMAND`` arguments will be expanded, including those
+ created with
+ :manual:`generator expressions <cmake-generator-expressions(7)>`,
+ allowing ``COMMAND`` arguments such as
+ ``${CC} "-I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc``
+ to be properly expanded.
+
+``IMPLICIT_DEPENDS``
+ Request scanning of implicit dependencies of an input file.
+ The language given specifies the programming language whose
+ corresponding dependency scanner should be used.
+ Currently only ``C`` and ``CXX`` language scanners are supported.
+ The language has to be specified for every file in the
+ ``IMPLICIT_DEPENDS`` list. Dependencies discovered from the
+ scanning are added to those of the custom command at build time.
+ Note that the ``IMPLICIT_DEPENDS`` option is currently supported
+ only for Makefile generators and will be ignored by other generators.
+
+ .. note::
+
+ This option cannot be specified at the same time as ``DEPFILE`` option.
+
+``JOB_POOL``
+ .. versionadded:: 3.15
+
+ Specify a :prop_gbl:`pool <JOB_POOLS>` for the :generator:`Ninja`
+ generator. Incompatible with ``USES_TERMINAL``, which implies
+ the ``console`` pool.
+ Using a pool that is not defined by :prop_gbl:`JOB_POOLS` causes
+ an error by ninja at build time.
+
+``MAIN_DEPENDENCY``
+ Specify the primary input source file to the command. This is
+ treated just like any value given to the ``DEPENDS`` option
+ but also suggests to Visual Studio generators where to hang
+ the custom command. Each source file may have at most one command
+ specifying it as its main dependency. A compile command (i.e. for a
+ library or an executable) counts as an implicit main dependency which
+ gets silently overwritten by a custom command specification.
+
+``OUTPUT``
+ Specify the output files the command is expected to produce.
+ If an output name is a relative path it will be interpreted
+ relative to the build tree directory corresponding to the
+ current source directory.
+ Each output file will be marked with the :prop_sf:`GENERATED`
+ source file property automatically.
+ If the output of the custom command is not actually created
+ as a file on disk it should be marked with the :prop_sf:`SYMBOLIC`
+ source file property.
+
+ .. versionadded:: 3.20
+ Arguments to ``OUTPUT`` may use a restricted set of
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+ :ref:`Target-dependent expressions <Target-Dependent Queries>` are not
+ permitted.
+
+``USES_TERMINAL``
+ .. versionadded:: 3.2
+
+ The command will be given direct access to the terminal if possible.
+ With the :generator:`Ninja` generator, this places the command in
+ the ``console`` :prop_gbl:`pool <JOB_POOLS>`.
+
+``VERBATIM``
+ All arguments to the commands will be escaped properly for the
+ build tool so that the invoked command receives each argument
+ unchanged. Note that one level of escapes is still used by the
+ CMake language processor before add_custom_command even sees the
+ arguments. Use of ``VERBATIM`` is recommended as it enables
+ correct behavior. When ``VERBATIM`` is not given the behavior
+ is platform specific because there is no protection of
+ tool-specific special characters.
+
+``WORKING_DIRECTORY``
+ Execute the command with the given current working directory.
+ If it is a relative path it will be interpreted relative to the
+ build tree directory corresponding to the current source directory.
+
+ .. versionadded:: 3.13
+ Arguments to ``WORKING_DIRECTORY`` may use
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+``DEPFILE``
+ .. versionadded:: 3.7
+
+ Specify a ``.d`` depfile for the :generator:`Ninja` generator and
+ :ref:`Makefile Generators`. The depfile may use "generator expressions" with
+ the syntax ``$<...>``. See the :manual:`generator-expressions(7)
+ <cmake-generator-expressions(7)>` manual for available expressions.
+ A ``.d`` file holds dependencies usually emitted by the custom
+ command itself.
+ Using ``DEPFILE`` with other generators than :generator:`Ninja` or
+ :ref:`Makefile Generators` is an error.
+
+ .. versionadded:: 3.20
+ Added the support of :ref:`Makefile Generators`.
+
+ .. versionadded:: 3.21
+ Added the support of :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+ If the ``DEPFILE`` argument is relative, it should be relative to
+ :variable:`CMAKE_CURRENT_BINARY_DIR`, and any relative paths inside the
+ ``DEPFILE`` should also be relative to :variable:`CMAKE_CURRENT_BINARY_DIR`
+ (see policy :policy:`CMP0116`. This policy is always ``NEW`` for
+ :ref:`Makefile Generators`).
+
+ .. note::
+
+ For :ref:`Makefile Generators`, this option cannot be specified at the
+ same time as ``IMPLICIT_DEPENDS`` option.
+
+Examples: Generating Files
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Custom commands may be used to generate source files.
+For example, the code:
+
+.. code-block:: cmake
+
+ add_custom_command(
+ OUTPUT out.c
+ COMMAND someTool -i ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
+ -o out.c
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
+ VERBATIM)
+ add_library(myLib out.c)
+
+adds a custom command to run ``someTool`` to generate ``out.c`` and then
+compile the generated source as part of a library. The generation rule
+will re-run whenever ``in.txt`` changes.
+
+.. versionadded:: 3.20
+ One may use generator expressions to specify per-configuration outputs.
+ For example, the code:
+
+ .. code-block:: cmake
+
+ add_custom_command(
+ OUTPUT "out-$<CONFIG>.c"
+ COMMAND someTool -i ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
+ -o "out-$<CONFIG>.c"
+ -c "$<CONFIG>"
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
+ VERBATIM)
+ add_library(myLib "out-$<CONFIG>.c")
+
+ adds a custom command to run ``someTool`` to generate ``out-<config>.c``,
+ where ``<config>`` is the build configuration, and then compile the generated
+ source as part of a library.
+
+Build Events
+^^^^^^^^^^^^
+
+The second signature adds a custom command to a target such as a
+library or executable. This is useful for performing an operation
+before or after building the target. The command becomes part of the
+target and will only execute when the target itself is built. If the
+target is already built, the command will not execute.
+
+.. code-block:: cmake
+
+ add_custom_command(TARGET <target>
+ PRE_BUILD | PRE_LINK | POST_BUILD
+ COMMAND command1 [ARGS] [args1...]
+ [COMMAND command2 [ARGS] [args2...] ...]
+ [BYPRODUCTS [files...]]
+ [WORKING_DIRECTORY dir]
+ [COMMENT comment]
+ [VERBATIM] [USES_TERMINAL]
+ [COMMAND_EXPAND_LISTS])
+
+This defines a new command that will be associated with building the
+specified ``<target>``. The ``<target>`` must be defined in the current
+directory; targets defined in other directories may not be specified.
+
+When the command will happen is determined by which
+of the following is specified:
+
+``PRE_BUILD``
+ On :ref:`Visual Studio Generators`, run before any other rules are
+ executed within the target.
+ On other generators, run just before ``PRE_LINK`` commands.
+``PRE_LINK``
+ Run after sources have been compiled but before linking the binary
+ or running the librarian or archiver tool of a static library.
+ This is not defined for targets created by the
+ :command:`add_custom_target` command.
+``POST_BUILD``
+ Run after all other rules within the target have been executed.
+
+.. note::
+ Because generator expressions can be used in custom commands,
+ it is possible to define ``COMMAND`` lines or whole custom commands
+ which evaluate to empty strings for certain configurations.
+ For **Visual Studio 2010 (and newer)** generators these command
+ lines or custom commands will be omitted for the specific
+ configuration and no "empty-string-command" will be added.
+
+ This allows to add individual build events for every configuration.
+
+Examples: Build Events
+^^^^^^^^^^^^^^^^^^^^^^
+
+A ``POST_BUILD`` event may be used to post-process a binary after linking.
+For example, the code:
+
+.. code-block:: cmake
+
+ add_executable(myExe myExe.c)
+ add_custom_command(
+ TARGET myExe POST_BUILD
+ COMMAND someHasher -i "$<TARGET_FILE:myExe>"
+ -o "$<TARGET_FILE:myExe>.hash"
+ VERBATIM)
+
+will run ``someHasher`` to produce a ``.hash`` file next to the executable
+after linking.
+
+.. versionadded:: 3.20
+ One may use generator expressions to specify per-configuration byproducts.
+ For example, the code:
+
+ .. code-block:: cmake
+
+ add_library(myPlugin MODULE myPlugin.c)
+ add_custom_command(
+ TARGET myPlugin POST_BUILD
+ COMMAND someHasher -i "$<TARGET_FILE:myPlugin>"
+ --as-code "myPlugin-hash-$<CONFIG>.c"
+ BYPRODUCTS "myPlugin-hash-$<CONFIG>.c"
+ VERBATIM)
+ add_executable(myExe myExe.c "myPlugin-hash-$<CONFIG>.c")
+
+ will run ``someHasher`` after linking ``myPlugin``, e.g. to produce a ``.c``
+ file containing code to check the hash of ``myPlugin`` that the ``myExe``
+ executable can use to verify it before loading.
+
+Ninja Multi-Config
+^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.20
+
+ ``add_custom_command`` supports the :generator:`Ninja Multi-Config`
+ generator's cross-config capabilities. See the generator documentation
+ for more information.
diff --git a/Help/command/add_custom_target.rst b/Help/command/add_custom_target.rst
new file mode 100644
index 0000000..def23fa
--- /dev/null
+++ b/Help/command/add_custom_target.rst
@@ -0,0 +1,181 @@
+add_custom_target
+-----------------
+
+Add a target with no output so it will always be built.
+
+.. code-block:: cmake
+
+ add_custom_target(Name [ALL] [command1 [args1...]]
+ [COMMAND command2 [args2...] ...]
+ [DEPENDS depend depend depend ... ]
+ [BYPRODUCTS [files...]]
+ [WORKING_DIRECTORY dir]
+ [COMMENT comment]
+ [JOB_POOL job_pool]
+ [VERBATIM] [USES_TERMINAL]
+ [COMMAND_EXPAND_LISTS]
+ [SOURCES src1 [src2...]])
+
+Adds a target with the given name that executes the given commands.
+The target has no output file and is *always considered out of date*
+even if the commands try to create a file with the name of the target.
+Use the :command:`add_custom_command` command to generate a file with
+dependencies. By default nothing depends on the custom target. Use
+the :command:`add_dependencies` command to add dependencies to or
+from other targets.
+
+The options are:
+
+``ALL``
+ Indicate that this target should be added to the default build
+ target so that it will be run every time (the command cannot be
+ called ``ALL``).
+
+``BYPRODUCTS``
+ .. versionadded:: 3.2
+
+ Specify the files the command is expected to produce but whose
+ modification time may or may not be updated on subsequent builds.
+ If a byproduct name is a relative path it will be interpreted
+ relative to the build tree directory corresponding to the
+ current source directory.
+ Each byproduct file will be marked with the :prop_sf:`GENERATED`
+ source file property automatically.
+
+ Explicit specification of byproducts is supported by the
+ :generator:`Ninja` generator to tell the ``ninja`` build tool
+ how to regenerate byproducts when they are missing. It is
+ also useful when other build rules (e.g. custom commands)
+ depend on the byproducts. Ninja requires a build rule for any
+ generated file on which another rule depends even if there are
+ order-only dependencies to ensure the byproducts will be
+ available before their dependents build.
+
+ The :ref:`Makefile Generators` will remove ``BYPRODUCTS`` and other
+ :prop_sf:`GENERATED` files during ``make clean``.
+
+ .. versionadded:: 3.20
+ Arguments to ``BYPRODUCTS`` may use a restricted set of
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+ :ref:`Target-dependent expressions <Target-Dependent Queries>` are not
+ permitted.
+
+``COMMAND``
+ Specify the command-line(s) to execute at build time.
+ If more than one ``COMMAND`` is specified they will be executed in order,
+ but *not* necessarily composed into a stateful shell or batch script.
+ (To run a full script, use the :command:`configure_file` command or the
+ :command:`file(GENERATE)` command to create it, and then specify
+ a ``COMMAND`` to launch it.)
+
+ If ``COMMAND`` specifies an executable target name (created by the
+ :command:`add_executable` command), it will automatically be replaced
+ by the location of the executable created at build time if either of
+ the following is true:
+
+ * The target is not being cross-compiled (i.e. the
+ :variable:`CMAKE_CROSSCOMPILING` variable is not set to true).
+ * .. versionadded:: 3.6
+ The target is being cross-compiled and an emulator is provided (i.e.
+ its :prop_tgt:`CROSSCOMPILING_EMULATOR` target property is set).
+ In this case, the contents of :prop_tgt:`CROSSCOMPILING_EMULATOR` will be
+ prepended to the command before the location of the target executable.
+
+ If neither of the above conditions are met, it is assumed that the
+ command name is a program to be found on the ``PATH`` at build time.
+
+ Arguments to ``COMMAND`` may use
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+ Use the :genex:`TARGET_FILE` generator expression to refer to the location
+ of a target later in the command line (i.e. as a command argument rather
+ than as the command to execute).
+
+ Whenever one of the following target based generator expressions are used as
+ a command to execute or is mentioned in a command argument, a target-level
+ dependency will be added automatically so that the mentioned target will be
+ built before this custom target (see policy :policy:`CMP0112`).
+
+ * ``TARGET_FILE``
+ * ``TARGET_LINKER_FILE``
+ * ``TARGET_SONAME_FILE``
+ * ``TARGET_PDB_FILE``
+
+ The command and arguments are optional and if not specified an empty
+ target will be created.
+
+``COMMENT``
+ Display the given message before the commands are executed at
+ build time.
+
+``DEPENDS``
+ Reference files and outputs of custom commands created with
+ :command:`add_custom_command` command calls in the same directory
+ (``CMakeLists.txt`` file). They will be brought up to date when
+ the target is built.
+
+ .. versionchanged:: 3.16
+ A target-level dependency is added if any dependency is a byproduct
+ of a target or any of its build events in the same directory to ensure
+ the byproducts will be available before this target is built.
+
+ Use the :command:`add_dependencies` command to add dependencies
+ on other targets.
+
+``COMMAND_EXPAND_LISTS``
+ .. versionadded:: 3.8
+
+ Lists in ``COMMAND`` arguments will be expanded, including those
+ created with
+ :manual:`generator expressions <cmake-generator-expressions(7)>`,
+ allowing ``COMMAND`` arguments such as
+ ``${CC} "-I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc``
+ to be properly expanded.
+
+``JOB_POOL``
+ .. versionadded:: 3.15
+
+ Specify a :prop_gbl:`pool <JOB_POOLS>` for the :generator:`Ninja`
+ generator. Incompatible with ``USES_TERMINAL``, which implies
+ the ``console`` pool.
+ Using a pool that is not defined by :prop_gbl:`JOB_POOLS` causes
+ an error by ninja at build time.
+
+``SOURCES``
+ Specify additional source files to be included in the custom target.
+ Specified source files will be added to IDE project files for
+ convenience in editing even if they have no build rules.
+
+``VERBATIM``
+ All arguments to the commands will be escaped properly for the
+ build tool so that the invoked command receives each argument
+ unchanged. Note that one level of escapes is still used by the
+ CMake language processor before ``add_custom_target`` even sees
+ the arguments. Use of ``VERBATIM`` is recommended as it enables
+ correct behavior. When ``VERBATIM`` is not given the behavior
+ is platform specific because there is no protection of
+ tool-specific special characters.
+
+``USES_TERMINAL``
+ .. versionadded:: 3.2
+
+ The command will be given direct access to the terminal if possible.
+ With the :generator:`Ninja` generator, this places the command in
+ the ``console`` :prop_gbl:`pool <JOB_POOLS>`.
+
+``WORKING_DIRECTORY``
+ Execute the command with the given current working directory.
+ If it is a relative path it will be interpreted relative to the
+ build tree directory corresponding to the current source directory.
+
+ .. versionadded:: 3.13
+ Arguments to ``WORKING_DIRECTORY`` may use
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+Ninja Multi-Config
+^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.20
+
+ ``add_custom_target`` supports the :generator:`Ninja Multi-Config`
+ generator's cross-config capabilities. See the generator documentation
+ for more information.
diff --git a/Help/command/add_definitions.rst b/Help/command/add_definitions.rst
new file mode 100644
index 0000000..fe69188
--- /dev/null
+++ b/Help/command/add_definitions.rst
@@ -0,0 +1,35 @@
+add_definitions
+---------------
+
+Add -D define flags to the compilation of source files.
+
+.. code-block:: cmake
+
+ add_definitions(-DFOO -DBAR ...)
+
+Adds definitions to the compiler command line for targets in the current
+directory, whether added before or after this command is invoked, and for
+the ones in sub-directories added after. This command can be used to add any
+flags, but it is intended to add preprocessor definitions.
+
+.. note::
+
+ This command has been superseded by alternatives:
+
+ * Use :command:`add_compile_definitions` to add preprocessor definitions.
+ * Use :command:`include_directories` to add include directories.
+ * Use :command:`add_compile_options` to add other options.
+
+Flags beginning in ``-D`` or ``/D`` that look like preprocessor definitions are
+automatically added to the :prop_dir:`COMPILE_DEFINITIONS` directory
+property for the current directory. Definitions with non-trivial values
+may be left in the set of flags instead of being converted for reasons of
+backwards compatibility. See documentation of the
+:prop_dir:`directory <COMPILE_DEFINITIONS>`,
+:prop_tgt:`target <COMPILE_DEFINITIONS>`,
+:prop_sf:`source file <COMPILE_DEFINITIONS>` ``COMPILE_DEFINITIONS``
+properties for details on adding preprocessor definitions to specific
+scopes and configurations.
+
+See the :manual:`cmake-buildsystem(7)` manual for more on defining
+buildsystem properties.
diff --git a/Help/command/add_dependencies.rst b/Help/command/add_dependencies.rst
new file mode 100644
index 0000000..14c0183
--- /dev/null
+++ b/Help/command/add_dependencies.rst
@@ -0,0 +1,26 @@
+add_dependencies
+----------------
+
+Add a dependency between top-level targets.
+
+.. code-block:: cmake
+
+ add_dependencies(<target> [<target-dependency>]...)
+
+Makes a top-level ``<target>`` depend on other top-level targets to
+ensure that they build before ``<target>`` does. A top-level target
+is one created by one of the :command:`add_executable`,
+:command:`add_library`, or :command:`add_custom_target` commands
+(but not targets generated by CMake like ``install``).
+
+Dependencies added to an :ref:`imported target <Imported Targets>`
+or an :ref:`interface library <Interface Libraries>` are followed
+transitively in its place since the target itself does not build.
+
+.. versionadded:: 3.3
+ Allow adding dependencies to interface libraries.
+
+See the ``DEPENDS`` option of :command:`add_custom_target` and
+:command:`add_custom_command` commands for adding file-level
+dependencies in custom rules. See the :prop_sf:`OBJECT_DEPENDS`
+source file property to add file-level dependencies to object files.
diff --git a/Help/command/add_executable.rst b/Help/command/add_executable.rst
new file mode 100644
index 0000000..dde9429
--- /dev/null
+++ b/Help/command/add_executable.rst
@@ -0,0 +1,109 @@
+add_executable
+--------------
+
+.. only:: html
+
+ .. contents::
+
+Add an executable to the project using the specified source files.
+
+Normal Executables
+^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ add_executable(<name> [WIN32] [MACOSX_BUNDLE]
+ [EXCLUDE_FROM_ALL]
+ [source1] [source2 ...])
+
+Adds an executable target called ``<name>`` to be built from the source
+files listed in the command invocation. The
+``<name>`` corresponds to the logical target name and must be globally
+unique within a project. The actual file name of the executable built is
+constructed based on conventions of the native platform (such as
+``<name>.exe`` or just ``<name>``).
+
+.. versionadded:: 3.1
+ Source arguments to ``add_executable`` may use "generator expressions" with
+ the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+ manual for available expressions.
+
+.. versionadded:: 3.11
+ The source files can be omitted if they are added later using
+ :command:`target_sources`.
+
+By default the executable file will be created in the build tree
+directory corresponding to the source tree directory in which the
+command was invoked. See documentation of the
+:prop_tgt:`RUNTIME_OUTPUT_DIRECTORY` target property to change this
+location. See documentation of the :prop_tgt:`OUTPUT_NAME` target property
+to change the ``<name>`` part of the final file name.
+
+If ``WIN32`` is given the property :prop_tgt:`WIN32_EXECUTABLE` will be
+set on the target created. See documentation of that target property for
+details.
+
+If ``MACOSX_BUNDLE`` is given the corresponding property will be set on
+the created target. See documentation of the :prop_tgt:`MACOSX_BUNDLE`
+target property for details.
+
+If ``EXCLUDE_FROM_ALL`` is given the corresponding property will be set on
+the created target. See documentation of the :prop_tgt:`EXCLUDE_FROM_ALL`
+target property for details.
+
+See the :manual:`cmake-buildsystem(7)` manual for more on defining
+buildsystem properties.
+
+See also :prop_sf:`HEADER_FILE_ONLY` on what to do if some sources are
+pre-processed, and you want to have the original sources reachable from
+within IDE.
+
+Imported Executables
+^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ add_executable(<name> IMPORTED [GLOBAL])
+
+An :ref:`IMPORTED executable target <Imported Targets>` references an
+executable file located outside the project. No rules are generated to
+build it, and the :prop_tgt:`IMPORTED` target property is ``True``. The
+target name has scope in the directory in which it is created and below, but
+the ``GLOBAL`` option extends visibility. It may be referenced like any
+target built within the project. ``IMPORTED`` executables are useful
+for convenient reference from commands like :command:`add_custom_command`.
+Details about the imported executable are specified by setting properties
+whose names begin in ``IMPORTED_``. The most important such property is
+:prop_tgt:`IMPORTED_LOCATION` (and its per-configuration version
+:prop_tgt:`IMPORTED_LOCATION_<CONFIG>`) which specifies the location of
+the main executable file on disk. See documentation of the ``IMPORTED_*``
+properties for more information.
+
+Alias Executables
+^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ add_executable(<name> ALIAS <target>)
+
+Creates an :ref:`Alias Target <Alias Targets>`, such that ``<name>`` can
+be used to refer to ``<target>`` in subsequent commands. The ``<name>``
+does not appear in the generated buildsystem as a make target. The
+``<target>`` may not be an ``ALIAS``.
+
+.. versionadded:: 3.11
+ An ``ALIAS`` can target a ``GLOBAL`` :ref:`Imported Target <Imported Targets>`
+
+.. versionadded:: 3.18
+ An ``ALIAS`` can target a non-``GLOBAL`` Imported Target. Such alias is
+ scoped to the directory in which it is created and subdirectories.
+ The :prop_tgt:`ALIAS_GLOBAL` target property can be used to check if the
+ alias is global or not.
+
+``ALIAS`` targets can be used as targets to read properties
+from, executables for custom commands and custom targets. They can also be
+tested for existence with the regular :command:`if(TARGET)` subcommand.
+The ``<name>`` may not be used to modify properties of ``<target>``, that
+is, it may not be used as the operand of :command:`set_property`,
+:command:`set_target_properties`, :command:`target_link_libraries` etc.
+An ``ALIAS`` target may not be installed or exported.
diff --git a/Help/command/add_library.rst b/Help/command/add_library.rst
new file mode 100644
index 0000000..dfc6500
--- /dev/null
+++ b/Help/command/add_library.rst
@@ -0,0 +1,259 @@
+add_library
+-----------
+
+.. only:: html
+
+ .. contents::
+
+Add a library to the project using the specified source files.
+
+Normal Libraries
+^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ add_library(<name> [STATIC | SHARED | MODULE]
+ [EXCLUDE_FROM_ALL]
+ [<source>...])
+
+Adds a library target called ``<name>`` to be built from the source files
+listed in the command invocation. The ``<name>``
+corresponds to the logical target name and must be globally unique within
+a project. The actual file name of the library built is constructed based
+on conventions of the native platform (such as ``lib<name>.a`` or
+``<name>.lib``).
+
+.. versionadded:: 3.1
+ Source arguments to ``add_library`` may use "generator expressions" with
+ the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+ manual for available expressions.
+
+.. versionadded:: 3.11
+ The source files can be omitted if they are added later using
+ :command:`target_sources`.
+
+``STATIC``, ``SHARED``, or ``MODULE`` may be given to specify the type of
+library to be created. ``STATIC`` libraries are archives of object files
+for use when linking other targets. ``SHARED`` libraries are linked
+dynamically and loaded at runtime. ``MODULE`` libraries are plugins that
+are not linked into other targets but may be loaded dynamically at runtime
+using dlopen-like functionality. If no type is given explicitly the
+type is ``STATIC`` or ``SHARED`` based on whether the current value of the
+variable :variable:`BUILD_SHARED_LIBS` is ``ON``. For ``SHARED`` and
+``MODULE`` libraries the :prop_tgt:`POSITION_INDEPENDENT_CODE` target
+property is set to ``ON`` automatically.
+A ``SHARED`` library may be marked with the :prop_tgt:`FRAMEWORK`
+target property to create an macOS Framework.
+
+.. versionadded:: 3.8
+ A ``STATIC`` library may be marked with the :prop_tgt:`FRAMEWORK`
+ target property to create a static Framework.
+
+If a library does not export any symbols, it must not be declared as a
+``SHARED`` library. For example, a Windows resource DLL or a managed C++/CLI
+DLL that exports no unmanaged symbols would need to be a ``MODULE`` library.
+This is because CMake expects a ``SHARED`` library to always have an
+associated import library on Windows.
+
+By default the library file will be created in the build tree directory
+corresponding to the source tree directory in which the command was
+invoked. See documentation of the :prop_tgt:`ARCHIVE_OUTPUT_DIRECTORY`,
+:prop_tgt:`LIBRARY_OUTPUT_DIRECTORY`, and
+:prop_tgt:`RUNTIME_OUTPUT_DIRECTORY` target properties to change this
+location. See documentation of the :prop_tgt:`OUTPUT_NAME` target
+property to change the ``<name>`` part of the final file name.
+
+If ``EXCLUDE_FROM_ALL`` is given the corresponding property will be set on
+the created target. See documentation of the :prop_tgt:`EXCLUDE_FROM_ALL`
+target property for details.
+
+See the :manual:`cmake-buildsystem(7)` manual for more on defining
+buildsystem properties.
+
+See also :prop_sf:`HEADER_FILE_ONLY` on what to do if some sources are
+pre-processed, and you want to have the original sources reachable from
+within IDE.
+
+Object Libraries
+^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ add_library(<name> OBJECT [<source>...])
+
+Creates an :ref:`Object Library <Object Libraries>`. An object library
+compiles source files but does not archive or link their object files into a
+library. Instead other targets created by :command:`add_library` or
+:command:`add_executable` may reference the objects using an expression of the
+form ``$<TARGET_OBJECTS:objlib>`` as a source, where ``objlib`` is the
+object library name. For example:
+
+.. code-block:: cmake
+
+ add_library(... $<TARGET_OBJECTS:objlib> ...)
+ add_executable(... $<TARGET_OBJECTS:objlib> ...)
+
+will include objlib's object files in a library and an executable
+along with those compiled from their own sources. Object libraries
+may contain only sources that compile, header files, and other files
+that would not affect linking of a normal library (e.g. ``.txt``).
+They may contain custom commands generating such sources, but not
+``PRE_BUILD``, ``PRE_LINK``, or ``POST_BUILD`` commands. Some native build
+systems (such as Xcode) may not like targets that have only object files, so
+consider adding at least one real source file to any target that references
+``$<TARGET_OBJECTS:objlib>``.
+
+.. versionadded:: 3.12
+ Object libraries can be linked to with :command:`target_link_libraries`.
+
+Interface Libraries
+^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ add_library(<name> INTERFACE)
+
+Creates an :ref:`Interface Library <Interface Libraries>`.
+An ``INTERFACE`` library target does not compile sources and does
+not produce a library artifact on disk. However, it may have
+properties set on it and it may be installed and exported.
+Typically, ``INTERFACE_*`` properties are populated on an interface
+target using the commands:
+
+* :command:`set_property`,
+* :command:`target_link_libraries(INTERFACE)`,
+* :command:`target_link_options(INTERFACE)`,
+* :command:`target_include_directories(INTERFACE)`,
+* :command:`target_compile_options(INTERFACE)`,
+* :command:`target_compile_definitions(INTERFACE)`, and
+* :command:`target_sources(INTERFACE)`,
+
+and then it is used as an argument to :command:`target_link_libraries`
+like any other target.
+
+An interface library created with the above signature has no source files
+itself and is not included as a target in the generated buildsystem.
+
+.. versionadded:: 3.15
+ An interface library can have :prop_tgt:`PUBLIC_HEADER` and
+ :prop_tgt:`PRIVATE_HEADER` properties. The headers specified by those
+ properties can be installed using the :command:`install(TARGETS)` command.
+
+.. versionadded:: 3.19
+ An interface library target may be created with source files:
+
+ .. code-block:: cmake
+
+ add_library(<name> INTERFACE [<source>...] [EXCLUDE_FROM_ALL])
+
+ Source files may be listed directly in the ``add_library`` call or added
+ later by calls to :command:`target_sources` with the ``PRIVATE`` or
+ ``PUBLIC`` keywords.
+
+ If an interface library has source files (i.e. the :prop_tgt:`SOURCES`
+ target property is set), it will appear in the generated buildsystem
+ as a build target much like a target defined by the
+ :command:`add_custom_target` command. It does not compile any sources,
+ but does contain build rules for custom commands created by the
+ :command:`add_custom_command` command.
+
+.. note::
+ In most command signatures where the ``INTERFACE`` keyword appears,
+ the items listed after it only become part of that target's usage
+ requirements and are not part of the target's own settings. However,
+ in this signature of ``add_library``, the ``INTERFACE`` keyword refers
+ to the library type only. Sources listed after it in the ``add_library``
+ call are ``PRIVATE`` to the interface library and do not appear in its
+ :prop_tgt:`INTERFACE_SOURCES` target property.
+
+Imported Libraries
+^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ add_library(<name> <type> IMPORTED [GLOBAL])
+
+Creates an :ref:`IMPORTED library target <Imported Targets>` called ``<name>``.
+No rules are generated to build it, and the :prop_tgt:`IMPORTED` target
+property is ``True``. The target name has scope in the directory in which
+it is created and below, but the ``GLOBAL`` option extends visibility.
+It may be referenced like any target built within the project.
+``IMPORTED`` libraries are useful for convenient reference from commands
+like :command:`target_link_libraries`. Details about the imported library
+are specified by setting properties whose names begin in ``IMPORTED_`` and
+``INTERFACE_``.
+
+The ``<type>`` must be one of:
+
+``STATIC``, ``SHARED``, ``MODULE``, ``UNKNOWN``
+ References a library file located outside the project. The
+ :prop_tgt:`IMPORTED_LOCATION` target property (or its per-configuration
+ variant :prop_tgt:`IMPORTED_LOCATION_<CONFIG>`) specifies the
+ location of the main library file on disk:
+
+ * For a ``SHARED`` library on most non-Windows platforms, the main library
+ file is the ``.so`` or ``.dylib`` file used by both linkers and dynamic
+ loaders. If the referenced library file has a ``SONAME`` (or on macOS,
+ has a ``LC_ID_DYLIB`` starting in ``@rpath/``), the value of that field
+ should be set in the :prop_tgt:`IMPORTED_SONAME` target property.
+ If the referenced library file does not have a ``SONAME``, but the
+ platform supports it, then the :prop_tgt:`IMPORTED_NO_SONAME` target
+ property should be set.
+
+ * For a ``SHARED`` library on Windows, the :prop_tgt:`IMPORTED_IMPLIB`
+ target property (or its per-configuration variant
+ :prop_tgt:`IMPORTED_IMPLIB_<CONFIG>`) specifies the location of the
+ DLL import library file (``.lib`` or ``.dll.a``) on disk, and the
+ ``IMPORTED_LOCATION`` is the location of the ``.dll`` runtime
+ library (and is optional).
+
+ Additional usage requirements may be specified in ``INTERFACE_*`` properties.
+
+ An ``UNKNOWN`` library type is typically only used in the implementation of
+ :ref:`Find Modules`. It allows the path to an imported library (often found
+ using the :command:`find_library` command) to be used without having to know
+ what type of library it is. This is especially useful on Windows where a
+ static library and a DLL's import library both have the same file extension.
+
+``OBJECT``
+ References a set of object files located outside the project.
+ The :prop_tgt:`IMPORTED_OBJECTS` target property (or its per-configuration
+ variant :prop_tgt:`IMPORTED_OBJECTS_<CONFIG>`) specifies the locations of
+ object files on disk.
+ Additional usage requirements may be specified in ``INTERFACE_*`` properties.
+
+``INTERFACE``
+ Does not reference any library or object files on disk, but may
+ specify usage requirements in ``INTERFACE_*`` properties.
+
+See documentation of the ``IMPORTED_*`` and ``INTERFACE_*`` properties
+for more information.
+
+Alias Libraries
+^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ add_library(<name> ALIAS <target>)
+
+Creates an :ref:`Alias Target <Alias Targets>`, such that ``<name>`` can be
+used to refer to ``<target>`` in subsequent commands. The ``<name>`` does
+not appear in the generated buildsystem as a make target. The ``<target>``
+may not be an ``ALIAS``.
+
+.. versionadded:: 3.11
+ An ``ALIAS`` can target a ``GLOBAL`` :ref:`Imported Target <Imported Targets>`
+
+.. versionadded:: 3.18
+ An ``ALIAS`` can target a non-``GLOBAL`` Imported Target. Such alias is
+ scoped to the directory in which it is created and below.
+ The :prop_tgt:`ALIAS_GLOBAL` target property can be used to check if the
+ alias is global or not.
+
+``ALIAS`` targets can be used as linkable targets and as targets to
+read properties from. They can also be tested for existence with the
+regular :command:`if(TARGET)` subcommand. The ``<name>`` may not be used
+to modify properties of ``<target>``, that is, it may not be used as the
+operand of :command:`set_property`, :command:`set_target_properties`,
+:command:`target_link_libraries` etc. An ``ALIAS`` target may not be
+installed or exported.
diff --git a/Help/command/add_link_options.rst b/Help/command/add_link_options.rst
new file mode 100644
index 0000000..f03e7c0
--- /dev/null
+++ b/Help/command/add_link_options.rst
@@ -0,0 +1,35 @@
+add_link_options
+----------------
+
+.. versionadded:: 3.13
+
+Add options to the link step for executable, shared library or module
+library targets in the current directory and below that are added after
+this command is invoked.
+
+.. code-block:: cmake
+
+ add_link_options(<option> ...)
+
+This command can be used to add any link options, but alternative commands
+exist to add libraries (:command:`target_link_libraries` or
+:command:`link_libraries`). See documentation of the
+:prop_dir:`directory <LINK_OPTIONS>` and
+:prop_tgt:`target <LINK_OPTIONS>` ``LINK_OPTIONS`` properties.
+
+.. note::
+
+ This command cannot be used to add options for static library targets,
+ since they do not use a linker. To add archiver or MSVC librarian flags,
+ see the :prop_tgt:`STATIC_LIBRARY_OPTIONS` target property.
+
+Arguments to ``add_link_options`` may use "generator expressions" with
+the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
+.. include:: DEVICE_LINK_OPTIONS.txt
+
+.. include:: OPTIONS_SHELL.txt
+
+.. include:: LINK_OPTIONS_LINKER.txt
diff --git a/Help/command/add_subdirectory.rst b/Help/command/add_subdirectory.rst
new file mode 100644
index 0000000..8dba986
--- /dev/null
+++ b/Help/command/add_subdirectory.rst
@@ -0,0 +1,35 @@
+add_subdirectory
+----------------
+
+Add a subdirectory to the build.
+
+.. code-block:: cmake
+
+ add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
+
+Adds a subdirectory to the build. The source_dir specifies the
+directory in which the source CMakeLists.txt and code files are
+located. If it is a relative path it will be evaluated with respect
+to the current directory (the typical usage), but it may also be an
+absolute path. The ``binary_dir`` specifies the directory in which to
+place the output files. If it is a relative path it will be evaluated
+with respect to the current output directory, but it may also be an
+absolute path. If ``binary_dir`` is not specified, the value of
+``source_dir``, before expanding any relative path, will be used (the
+typical usage). The CMakeLists.txt file in the specified source
+directory will be processed immediately by CMake before processing in
+the current input file continues beyond this command.
+
+If the ``EXCLUDE_FROM_ALL`` argument is provided then targets in the
+subdirectory will not be included in the ``ALL`` target of the parent
+directory by default, and will be excluded from IDE project files.
+Users must explicitly build targets in the subdirectory. This is
+meant for use when the subdirectory contains a separate part of the
+project that is useful but not necessary, such as a set of examples.
+Typically the subdirectory should contain its own :command:`project`
+command invocation so that a full build system will be generated in the
+subdirectory (such as a VS IDE solution file). Note that inter-target
+dependencies supersede this exclusion. If a target built by the
+parent project depends on a target in the subdirectory, the dependee
+target will be included in the parent project build system to satisfy
+the dependency.
diff --git a/Help/command/add_test.rst b/Help/command/add_test.rst
new file mode 100644
index 0000000..95cd037
--- /dev/null
+++ b/Help/command/add_test.rst
@@ -0,0 +1,82 @@
+add_test
+--------
+
+Add a test to the project to be run by :manual:`ctest(1)`.
+
+.. code-block:: cmake
+
+ add_test(NAME <name> COMMAND <command> [<arg>...]
+ [CONFIGURATIONS <config>...]
+ [WORKING_DIRECTORY <dir>]
+ [COMMAND_EXPAND_LISTS])
+
+Adds a test called ``<name>``. The test name may contain arbitrary
+characters, expressed as a :ref:`Quoted Argument` or :ref:`Bracket Argument`
+if necessary. See policy :policy:`CMP0110`. The options are:
+
+``COMMAND``
+ Specify the test command-line. If ``<command>`` specifies an
+ executable target (created by :command:`add_executable`) it will
+ automatically be replaced by the location of the executable created
+ at build time.
+
+``CONFIGURATIONS``
+ Restrict execution of the test only to the named configurations.
+
+``WORKING_DIRECTORY``
+ Set the :prop_test:`WORKING_DIRECTORY` test property to
+ specify the working directory in which to execute the test.
+ If not specified the test will be run with the current working
+ directory set to the build directory corresponding to the
+ current source directory.
+
+``COMMAND_EXPAND_LISTS``
+ .. versionadded:: 3.16
+
+ Lists in ``COMMAND`` arguments will be expanded, including those
+ created with
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+The given test command is expected to exit with code ``0`` to pass and
+non-zero to fail, or vice-versa if the :prop_test:`WILL_FAIL` test
+property is set. Any output written to stdout or stderr will be
+captured by :manual:`ctest(1)` but does not affect the pass/fail status
+unless the :prop_test:`PASS_REGULAR_EXPRESSION`,
+:prop_test:`FAIL_REGULAR_EXPRESSION` or
+:prop_test:`SKIP_REGULAR_EXPRESSION` test property is used.
+
+.. versionadded:: 3.16
+ Added :prop_test:`SKIP_REGULAR_EXPRESSION` property.
+
+The ``COMMAND`` and ``WORKING_DIRECTORY`` options may use "generator
+expressions" with the syntax ``$<...>``. See the
+:manual:`cmake-generator-expressions(7)` manual for available expressions.
+
+Example usage:
+
+.. code-block:: cmake
+
+ add_test(NAME mytest
+ COMMAND testDriver --config $<CONFIG>
+ --exe $<TARGET_FILE:myexe>)
+
+This creates a test ``mytest`` whose command runs a ``testDriver`` tool
+passing the configuration name and the full path to the executable
+file produced by target ``myexe``.
+
+.. note::
+
+ CMake will generate tests only if the :command:`enable_testing`
+ command has been invoked. The :module:`CTest` module invokes the
+ command automatically unless the ``BUILD_TESTING`` option is turned
+ ``OFF``.
+
+---------------------------------------------------------------------
+
+.. code-block:: cmake
+
+ add_test(<name> <command> [<arg>...])
+
+Add a test called ``<name>`` with the given command-line. Unlike
+the above ``NAME`` signature no transformation is performed on the
+command-line to support target names or generator expressions.
diff --git a/Help/command/aux_source_directory.rst b/Help/command/aux_source_directory.rst
new file mode 100644
index 0000000..9619f35
--- /dev/null
+++ b/Help/command/aux_source_directory.rst
@@ -0,0 +1,24 @@
+aux_source_directory
+--------------------
+
+Find all source files in a directory.
+
+.. code-block:: cmake
+
+ aux_source_directory(<dir> <variable>)
+
+Collects the names of all the source files in the specified directory
+and stores the list in the ``<variable>`` provided. This command is
+intended to be used by projects that use explicit template
+instantiation. Template instantiation files can be stored in a
+``Templates`` subdirectory and collected automatically using this
+command to avoid manually listing all instantiations.
+
+It is tempting to use this command to avoid writing the list of source
+files for a library or executable target. While this seems to work,
+there is no way for CMake to generate a build system that knows when a
+new source file has been added. Normally the generated build system
+knows when it needs to rerun CMake because the ``CMakeLists.txt`` file is
+modified to add a new source. When the source is just added to the
+directory without modifying this file, one would have to manually
+rerun CMake to generate a build system incorporating the new file.
diff --git a/Help/command/break.rst b/Help/command/break.rst
new file mode 100644
index 0000000..4875a2b
--- /dev/null
+++ b/Help/command/break.rst
@@ -0,0 +1,12 @@
+break
+-----
+
+Break from an enclosing foreach or while loop.
+
+.. code-block:: cmake
+
+ break()
+
+Breaks from an enclosing :command:`foreach` or :command:`while` loop.
+
+See also the :command:`continue` command.
diff --git a/Help/command/build_command.rst b/Help/command/build_command.rst
new file mode 100644
index 0000000..6659005
--- /dev/null
+++ b/Help/command/build_command.rst
@@ -0,0 +1,45 @@
+build_command
+-------------
+
+Get a command line to build the current project.
+This is mainly intended for internal use by the :module:`CTest` module.
+
+.. code-block:: cmake
+
+ build_command(<variable>
+ [CONFIGURATION <config>]
+ [TARGET <target>]
+ [PROJECT_NAME <projname>] # legacy, causes warning
+ )
+
+Sets the given ``<variable>`` to a command-line string of the form::
+
+ <cmake> --build . [--config <config>] [--target <target>...] [-- -i]
+
+where ``<cmake>`` is the location of the :manual:`cmake(1)` command-line
+tool, and ``<config>`` and ``<target>`` are the values provided to the
+``CONFIGURATION`` and ``TARGET`` options, if any. The trailing ``-- -i``
+option is added for :ref:`Makefile Generators` if policy :policy:`CMP0061`
+is not set to ``NEW``.
+
+When invoked, this ``cmake --build`` command line will launch the
+underlying build system tool.
+
+.. code-block:: cmake
+
+ build_command(<cachevariable> <makecommand>)
+
+This second signature is deprecated, but still available for backwards
+compatibility. Use the first signature instead.
+
+It sets the given ``<cachevariable>`` to a command-line string as
+above but without the ``--target`` option.
+The ``<makecommand>`` is ignored but should be the full path to
+devenv, nmake, make or one of the end user build tools
+for legacy invocations.
+
+.. note::
+ In CMake versions prior to 3.0 this command returned a command
+ line that directly invokes the native build tool for the current
+ generator. Their implementation of the ``PROJECT_NAME`` option
+ had no useful effects, so CMake now warns on use of the option.
diff --git a/Help/command/build_name.rst b/Help/command/build_name.rst
new file mode 100644
index 0000000..2a1fbae
--- /dev/null
+++ b/Help/command/build_name.rst
@@ -0,0 +1,15 @@
+build_name
+----------
+
+Disallowed since version 3.0. See CMake Policy :policy:`CMP0036`.
+
+Use ``${CMAKE_SYSTEM}`` and ``${CMAKE_CXX_COMPILER}`` instead.
+
+::
+
+ build_name(variable)
+
+Sets the specified variable to a string representing the platform and
+compiler settings. These values are now available through the
+:variable:`CMAKE_SYSTEM` and
+:variable:`CMAKE_CXX_COMPILER <CMAKE_<LANG>_COMPILER>` variables.
diff --git a/Help/command/cmake_host_system_information.rst b/Help/command/cmake_host_system_information.rst
new file mode 100644
index 0000000..2b902a9
--- /dev/null
+++ b/Help/command/cmake_host_system_information.rst
@@ -0,0 +1,58 @@
+cmake_host_system_information
+-----------------------------
+
+Query host system specific information.
+
+.. code-block:: cmake
+
+ cmake_host_system_information(RESULT <variable> QUERY <key> ...)
+
+Queries system information of the host system on which cmake runs.
+One or more ``<key>`` can be provided to select the information to be
+queried. The list of queried values is stored in ``<variable>``.
+
+``<key>`` can be one of the following values:
+
+============================= ================================================
+Key Description
+============================= ================================================
+``NUMBER_OF_LOGICAL_CORES`` Number of logical cores
+``NUMBER_OF_PHYSICAL_CORES`` Number of physical cores
+``HOSTNAME`` Hostname
+``FQDN`` Fully qualified domain name
+``TOTAL_VIRTUAL_MEMORY`` Total virtual memory in MiB [#mebibytes]_
+``AVAILABLE_VIRTUAL_MEMORY`` Available virtual memory in MiB [#mebibytes]_
+``TOTAL_PHYSICAL_MEMORY`` Total physical memory in MiB [#mebibytes]_
+``AVAILABLE_PHYSICAL_MEMORY`` Available physical memory in MiB [#mebibytes]_
+============================= ================================================
+
+.. versionadded:: 3.10
+ Additional ``<key>`` values are available:
+
+============================= ================================================
+Key Description
+============================= ================================================
+``IS_64BIT`` One if processor is 64Bit
+``HAS_FPU`` One if processor has floating point unit
+``HAS_MMX`` One if processor supports MMX instructions
+``HAS_MMX_PLUS`` One if processor supports Ext. MMX instructions
+``HAS_SSE`` One if processor supports SSE instructions
+``HAS_SSE2`` One if processor supports SSE2 instructions
+``HAS_SSE_FP`` One if processor supports SSE FP instructions
+``HAS_SSE_MMX`` One if processor supports SSE MMX instructions
+``HAS_AMD_3DNOW`` One if processor supports 3DNow instructions
+``HAS_AMD_3DNOW_PLUS`` One if processor supports 3DNow+ instructions
+``HAS_IA64`` One if IA64 processor emulating x86
+``HAS_SERIAL_NUMBER`` One if processor has serial number
+``PROCESSOR_SERIAL_NUMBER`` Processor serial number
+``PROCESSOR_NAME`` Human readable processor name
+``PROCESSOR_DESCRIPTION`` Human readable full processor description
+``OS_NAME`` See :variable:`CMAKE_HOST_SYSTEM_NAME`
+``OS_RELEASE`` The OS sub-type e.g. on Windows ``Professional``
+``OS_VERSION`` The OS build ID
+``OS_PLATFORM`` See :variable:`CMAKE_HOST_SYSTEM_PROCESSOR`
+============================= ================================================
+
+.. rubric:: Footnotes
+
+.. [#mebibytes] One MiB (mebibyte) is equal to 1024x1024 bytes.
diff --git a/Help/command/cmake_language.rst b/Help/command/cmake_language.rst
new file mode 100644
index 0000000..99f874b
--- /dev/null
+++ b/Help/command/cmake_language.rst
@@ -0,0 +1,227 @@
+cmake_language
+--------------
+
+.. versionadded:: 3.18
+
+Call meta-operations on CMake commands.
+
+Synopsis
+^^^^^^^^
+
+.. parsed-literal::
+
+ cmake_language(`CALL`_ <command> [<arg>...])
+ cmake_language(`EVAL`_ CODE <code>...)
+ cmake_language(`DEFER`_ <options>... CALL <command> [<arg>...])
+
+Introduction
+^^^^^^^^^^^^
+
+This command will call meta-operations on built-in CMake commands or
+those created via the :command:`macro` or :command:`function` commands.
+
+``cmake_language`` does not introduce a new variable or policy scope.
+
+Calling Commands
+^^^^^^^^^^^^^^^^
+
+.. _CALL:
+
+.. code-block:: cmake
+
+ cmake_language(CALL <command> [<arg>...])
+
+Calls the named ``<command>`` with the given arguments (if any).
+For example, the code:
+
+.. code-block:: cmake
+
+ set(message_command "message")
+ cmake_language(CALL ${message_command} STATUS "Hello World!")
+
+is equivalent to
+
+.. code-block:: cmake
+
+ message(STATUS "Hello World!")
+
+.. note::
+ To ensure consistency of the code, the following commands are not allowed:
+
+ * ``if`` / ``elseif`` / ``else`` / ``endif``
+ * ``while`` / ``endwhile``
+ * ``foreach`` / ``endforeach``
+ * ``function`` / ``endfunction``
+ * ``macro`` / ``endmacro``
+
+Evaluating Code
+^^^^^^^^^^^^^^^
+
+.. _EVAL:
+
+.. code-block:: cmake
+
+ cmake_language(EVAL CODE <code>...)
+
+Evaluates the ``<code>...`` as CMake code.
+
+For example, the code:
+
+.. code-block:: cmake
+
+ set(A TRUE)
+ set(B TRUE)
+ set(C TRUE)
+ set(condition "(A AND B) OR C")
+
+ cmake_language(EVAL CODE "
+ if (${condition})
+ message(STATUS TRUE)
+ else()
+ message(STATUS FALSE)
+ endif()"
+ )
+
+is equivalent to
+
+.. code-block:: cmake
+
+ set(A TRUE)
+ set(B TRUE)
+ set(C TRUE)
+ set(condition "(A AND B) OR C")
+
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/eval.cmake "
+ if (${condition})
+ message(STATUS TRUE)
+ else()
+ message(STATUS FALSE)
+ endif()"
+ )
+
+ 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 with a capital letter ``A-Z``.
+ The ``<id>`` may begin with an underscore (``_``) only if it was generated
+ automatically by an earlier call that used ``ID_VAR`` to get the id.
+
+``ID_VAR <var>``
+ Specify a variable in which to store the identification for the
+ deferred call. If ``ID <id>`` is not given, a new identification
+ will be generated and the generated id will start with an underscore (``_``).
+
+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. The ids are for the directory scope in which
+the calls have been deferred to (i.e. where they will be executed), which can
+be different to the scope in which they were created. The ``DIRECTORY``
+option can be used to specify the scope for which to retrieve the call ids.
+If that option is not given, the call ids for the current directory scope will
+be returned.
+
+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 in
+the specified ``DIRECTORY`` scope (or the current directory scope if no
+``DIRECTORY`` option is given), 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 in the specified
+``DIRECTORY`` scope (or the current directory scope if no ``DIRECTORY`` option
+is given). 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/cmake_minimum_required.rst b/Help/command/cmake_minimum_required.rst
new file mode 100644
index 0000000..c3b3e73
--- /dev/null
+++ b/Help/command/cmake_minimum_required.rst
@@ -0,0 +1,74 @@
+cmake_minimum_required
+----------------------
+
+Require a minimum version of cmake.
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION <min>[...<max>] [FATAL_ERROR])
+
+.. versionadded:: 3.12
+ The optional ``<max>`` version.
+
+Sets the minimum required version of cmake for a project.
+Also updates the policy settings as explained below.
+
+``<min>`` and the optional ``<max>`` are each CMake versions of the form
+``major.minor[.patch[.tweak]]``, and the ``...`` is literal.
+
+If the running version of CMake is lower than the ``<min>`` required
+version it will stop processing the project and report an error.
+The optional ``<max>`` version, if specified, must be at least the
+``<min>`` version and affects policy settings as described below.
+If the running version of CMake is older than 3.12, the extra ``...``
+dots will be seen as version component separators, resulting in the
+``...<max>`` part being ignored and preserving the pre-3.12 behavior
+of basing policies on ``<min>``.
+
+This command will set the value of the
+:variable:`CMAKE_MINIMUM_REQUIRED_VERSION` variable to ``<min>``.
+
+The ``FATAL_ERROR`` option is accepted but ignored by CMake 2.6 and
+higher. It should be specified so CMake versions 2.4 and lower fail
+with an error instead of just a warning.
+
+.. note::
+ Call the ``cmake_minimum_required()`` command at the beginning of
+ the top-level ``CMakeLists.txt`` file even before calling the
+ :command:`project` command. It is important to establish version
+ and policy settings before invoking other commands whose behavior
+ they may affect. See also policy :policy:`CMP0000`.
+
+ Calling ``cmake_minimum_required()`` inside a :command:`function`
+ limits some effects to the function scope when invoked. Such calls
+ should not be made with the intention of having global effects.
+
+Policy Settings
+^^^^^^^^^^^^^^^
+
+The ``cmake_minimum_required(VERSION)`` command implicitly invokes the
+:command:`cmake_policy(VERSION)` command to specify that the current
+project code is written for the given range of CMake versions.
+All policies known to the running version of CMake and introduced
+in the ``<min>`` (or ``<max>``, if specified) version or earlier will
+be set to use ``NEW`` behavior. All policies introduced in later
+versions will be unset. This effectively requests behavior preferred
+as of a given CMake version and tells newer CMake versions to warn
+about their new policies.
+
+When a ``<min>`` version higher than 2.4 is specified the command
+implicitly invokes
+
+.. code-block:: cmake
+
+ cmake_policy(VERSION <min>[...<max>])
+
+which sets CMake policies based on the range of versions specified.
+When a ``<min>`` version 2.4 or lower is given the command implicitly
+invokes
+
+.. code-block:: cmake
+
+ cmake_policy(VERSION 2.4[...<max>])
+
+which enables compatibility features for CMake 2.4 and lower.
diff --git a/Help/command/cmake_parse_arguments.rst b/Help/command/cmake_parse_arguments.rst
new file mode 100644
index 0000000..7c85da6
--- /dev/null
+++ b/Help/command/cmake_parse_arguments.rst
@@ -0,0 +1,115 @@
+cmake_parse_arguments
+---------------------
+
+Parse function or macro arguments.
+
+.. code-block:: cmake
+
+ cmake_parse_arguments(<prefix> <options> <one_value_keywords>
+ <multi_value_keywords> <args>...)
+
+ cmake_parse_arguments(PARSE_ARGV <N> <prefix> <options>
+ <one_value_keywords> <multi_value_keywords>)
+
+.. versionadded:: 3.5
+ This command is implemented natively. Previously, it has been defined in the
+ module :module:`CMakeParseArguments`.
+
+This command is for use in macros or functions.
+It processes the arguments given to that macro or function,
+and defines a set of variables which hold the values of the
+respective options.
+
+The first signature reads processes arguments passed in the ``<args>...``.
+This may be used in either a :command:`macro` or a :command:`function`.
+
+.. versionadded:: 3.7
+ The ``PARSE_ARGV`` signature is only for use in a :command:`function`
+ body. In this case the arguments that are parsed come from the
+ ``ARGV#`` variables of the calling function. The parsing starts with
+ the ``<N>``-th argument, where ``<N>`` is an unsigned integer.
+ This allows for the values to have special characters like ``;`` in them.
+
+The ``<options>`` argument contains all options for the respective macro,
+i.e. keywords which can be used when calling the macro without any value
+following, like e.g. the ``OPTIONAL`` keyword of the :command:`install`
+command.
+
+The ``<one_value_keywords>`` argument contains all keywords for this macro
+which are followed by one value, like e.g. ``DESTINATION`` keyword of the
+:command:`install` command.
+
+The ``<multi_value_keywords>`` argument contains all keywords for this
+macro which can be followed by more than one value, like e.g. the
+``TARGETS`` or ``FILES`` keywords of the :command:`install` command.
+
+.. versionchanged:: 3.5
+ All keywords shall be unique. I.e. every keyword shall only be specified
+ once in either ``<options>``, ``<one_value_keywords>`` or
+ ``<multi_value_keywords>``. A warning will be emitted if uniqueness is
+ violated.
+
+When done, ``cmake_parse_arguments`` will consider for each of the
+keywords listed in ``<options>``, ``<one_value_keywords>`` and
+``<multi_value_keywords>`` a variable composed of the given ``<prefix>``
+followed by ``"_"`` and the name of the respective keyword. These
+variables will then hold the respective value from the argument list
+or be undefined if the associated option could not be found.
+For the ``<options>`` keywords, these will always be defined,
+to ``TRUE`` or ``FALSE``, whether the option is in the argument list or not.
+
+All remaining arguments are collected in a variable
+``<prefix>_UNPARSED_ARGUMENTS`` that will be undefined if all arguments
+were recognized. This can be checked afterwards to see
+whether your macro was called with unrecognized parameters.
+
+.. versionadded:: 3.15
+ ``<one_value_keywords>`` and ``<multi_value_keywords>`` that were given no
+ values at all are collected in a variable
+ ``<prefix>_KEYWORDS_MISSING_VALUES`` that will be undefined if all keywords
+ received values. This can be checked to see if there were keywords without
+ any values given.
+
+Consider the following example macro, ``my_install()``, which takes similar
+arguments to the real :command:`install` command:
+
+.. code-block:: cmake
+
+ macro(my_install)
+ set(options OPTIONAL FAST)
+ set(oneValueArgs DESTINATION RENAME)
+ set(multiValueArgs TARGETS CONFIGURATIONS)
+ cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}"
+ "${multiValueArgs}" ${ARGN} )
+
+ # ...
+
+Assume ``my_install()`` has been called like this:
+
+.. code-block:: cmake
+
+ my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub CONFIGURATIONS)
+
+After the ``cmake_parse_arguments`` call the macro will have set or undefined
+the following variables::
+
+ MY_INSTALL_OPTIONAL = TRUE
+ MY_INSTALL_FAST = FALSE # was not used in call to my_install
+ MY_INSTALL_DESTINATION = "bin"
+ MY_INSTALL_RENAME <UNDEFINED> # was not used
+ MY_INSTALL_TARGETS = "foo;bar"
+ MY_INSTALL_CONFIGURATIONS <UNDEFINED> # was not used
+ MY_INSTALL_UNPARSED_ARGUMENTS = "blub" # nothing expected after "OPTIONAL"
+ MY_INSTALL_KEYWORDS_MISSING_VALUES = "CONFIGURATIONS"
+ # No value for "CONFIGURATIONS" given
+
+You can then continue and process these variables.
+
+Keywords terminate lists of values, e.g. if directly after a
+``one_value_keyword`` another recognized keyword follows, this is
+interpreted as the beginning of the new option. E.g.
+``my_install(TARGETS foo DESTINATION OPTIONAL)`` would result in
+``MY_INSTALL_DESTINATION`` set to ``"OPTIONAL"``, but as ``OPTIONAL``
+is a keyword itself ``MY_INSTALL_DESTINATION`` will be empty (but added
+to ``MY_INSTALL_KEYWORDS_MISSING_VALUES``) and ``MY_INSTALL_OPTIONAL`` will
+therefore be set to ``TRUE``.
diff --git a/Help/command/cmake_path.rst b/Help/command/cmake_path.rst
new file mode 100644
index 0000000..a8999f3
--- /dev/null
+++ b/Help/command/cmake_path.rst
@@ -0,0 +1,784 @@
+cmake_path
+----------
+
+.. versionadded:: 3.20
+
+This command is for the manipulation of paths. Only syntactic aspects of
+paths are handled, there is no interaction of any kind with any underlying
+file system. The path may represent a non-existing path or even one that
+is not allowed to exist on the current file system or platform.
+For operations that do interact with the filesystem, see the :command:`file`
+command.
+
+.. note::
+
+ The ``cmake_path`` command handles paths in the format of the build system
+ (i.e. the host platform), not the target system. When cross-compiling,
+ if the path contains elements that are not representable on the host
+ platform (e.g. a drive letter when the host is not Windows), the results
+ will be unpredictable.
+
+Synopsis
+^^^^^^^^
+
+.. parsed-literal::
+
+ `Conventions`_
+
+ `Path Structure And Terminology`_
+
+ `Normalization`_
+
+ `Decomposition`_
+ cmake_path(`GET`_ <path-var> :ref:`ROOT_NAME <GET_ROOT_NAME>` <out-var>)
+ cmake_path(`GET`_ <path-var> :ref:`ROOT_DIRECTORY <GET_ROOT_DIRECTORY>` <out-var>)
+ cmake_path(`GET`_ <path-var> :ref:`ROOT_PATH <GET_ROOT_PATH>` <out-var>)
+ cmake_path(`GET`_ <path-var> :ref:`FILENAME <GET_FILENAME>` <out-var>)
+ cmake_path(`GET`_ <path-var> :ref:`EXTENSION <GET_EXTENSION>` [LAST_ONLY] <out-var>)
+ cmake_path(`GET`_ <path-var> :ref:`STEM <GET_STEM>` [LAST_ONLY] <out-var>)
+ cmake_path(`GET`_ <path-var> :ref:`RELATIVE_PART <GET_RELATIVE_PART>` <out-var>)
+ cmake_path(`GET`_ <path-var> :ref:`PARENT_PATH <GET_PARENT_PATH>` <out-var>)
+
+ `Query`_
+ cmake_path(`HAS_ROOT_NAME`_ <path-var> <out-var>)
+ cmake_path(`HAS_ROOT_DIRECTORY`_ <path-var> <out-var>)
+ cmake_path(`HAS_ROOT_PATH`_ <path-var> <out-var>)
+ cmake_path(`HAS_FILENAME`_ <path-var> <out-var>)
+ cmake_path(`HAS_EXTENSION`_ <path-var> <out-var>)
+ cmake_path(`HAS_STEM`_ <path-var> <out-var>)
+ cmake_path(`HAS_RELATIVE_PART`_ <path-var> <out-var>)
+ cmake_path(`HAS_PARENT_PATH`_ <path-var> <out-var>)
+ cmake_path(`IS_ABSOLUTE`_ <path-var> <out-var>)
+ cmake_path(`IS_RELATIVE`_ <path-var> <out-var>)
+ cmake_path(`IS_PREFIX`_ <path-var> <input> [NORMALIZE] <out-var>)
+ cmake_path(`COMPARE`_ <input1> <OP> <input2> <out-var>)
+
+ `Modification`_
+ cmake_path(:ref:`SET <cmake_path-SET>` <path-var> [NORMALIZE] <input>)
+ cmake_path(`APPEND`_ <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
+ cmake_path(`APPEND_STRING`_ <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
+ cmake_path(`REMOVE_FILENAME`_ <path-var> [OUTPUT_VARIABLE <out-var>])
+ cmake_path(`REPLACE_FILENAME`_ <path-var> <input> [OUTPUT_VARIABLE <out-var>])
+ cmake_path(`REMOVE_EXTENSION`_ <path-var> [LAST_ONLY] [OUTPUT_VARIABLE <out-var>])
+ cmake_path(`REPLACE_EXTENSION`_ <path-var> [LAST_ONLY] <input> [OUTPUT_VARIABLE <out-var>])
+
+ `Generation`_
+ cmake_path(`NORMAL_PATH`_ <path-var> [OUTPUT_VARIABLE <out-var>])
+ cmake_path(`RELATIVE_PATH`_ <path-var> [BASE_DIRECTORY <input>] [OUTPUT_VARIABLE <out-var>])
+ cmake_path(`ABSOLUTE_PATH`_ <path-var> [BASE_DIRECTORY <input>] [NORMALIZE] [OUTPUT_VARIABLE <out-var>])
+
+ `Native Conversion`_
+ cmake_path(`NATIVE_PATH`_ <path-var> [NORMALIZE] <out-var>)
+ cmake_path(`CONVERT`_ <input> `TO_CMAKE_PATH_LIST`_ <out-var>)
+ cmake_path(`CONVERT`_ <input> `TO_NATIVE_PATH_LIST`_ <out-var>)
+
+ `Hashing`_
+ cmake_path(`HASH`_ <path-var> <out-var>)
+
+Conventions
+^^^^^^^^^^^
+
+The following conventions are used in this command's documentation:
+
+``<path-var>``
+ Always the name of a variable. For commands that expect a ``<path-var>``
+ as input, the variable must exist and it is expected to hold a single path.
+
+``<input>``
+ A string literal which may contain a path, path fragment, or multiple paths
+ with a special separator depending on the command. See the description of
+ each command to see how this is interpreted.
+
+``<input>...``
+ Zero or more string literal arguments.
+
+``<out-var>``
+ The name of a variable into which the result of a command will be written.
+
+
+Path Structure And Terminology
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A path has the following structure (all components are optional, with some
+constraints):
+
+::
+
+ root-name root-directory-separator (item-name directory-separator)* filename
+
+``root-name``
+ Identifies the root on a filesystem with multiple roots (such as ``"C:"``
+ or ``"//myserver"``). It is optional.
+
+``root-directory-separator``
+ A directory separator that, if present, indicates that this path is
+ absolute. If it is missing and the first element other than the
+ ``root-name`` is an ``item-name``, then the path is relative.
+
+``item-name``
+ A sequence of characters that aren't directory separators. This name may
+ identify a file, a hard link, a symbolic link, or a directory. Two special
+ cases are recognized:
+
+ * The item name consisting of a single dot character ``.`` is a
+ directory name that refers to the current directory.
+
+ * The item name consisting of two dot characters ``..`` is a
+ directory name that refers to the parent directory.
+
+ The ``(...)*`` pattern shown above is to indicate that there can be zero
+ or more item names, with multiple items separated by a
+ ``directory-separator``. The ``()*`` characters are not part of the path.
+
+``directory-separator``
+ The only recognized directory separator is a forward slash character ``/``.
+ If this character is repeated, it is treated as a single directory
+ separator. In other words, ``/usr///////lib`` is the same as ``/usr/lib``.
+
+.. _FILENAME_DEF:
+.. _EXTENSION_DEF:
+.. _STEM_DEF:
+
+``filename``
+ A path has a ``filename`` if it does not end with a ``directory-separator``.
+ The ``filename`` is effectively the last ``item-name`` of the path, so it
+ can also be a hard link, symbolic link or a directory.
+
+ A ``filename`` can have an *extension*. By default, the extension is
+ defined as the sub-string beginning at the left-most period (including
+ the period) and until the end of the ``filename``. In commands that
+ accept a ``LAST_ONLY`` keyword, ``LAST_ONLY`` changes the interpretation
+ to the sub-string beginning at the right-most period.
+
+ The following exceptions apply to the above interpretation:
+
+ * If the first character in the ``filename`` is a period, that period is
+ ignored (i.e. a ``filename`` like ``".profile"`` is treated as having
+ no extension).
+
+ * If the ``filename`` is either ``.`` or ``..``, it has no extension.
+
+ The *stem* is the part of the ``filename`` before the extension.
+
+Some commands refer to a ``root-path``. This is the concatenation of
+``root-name`` and ``root-directory-separator``, either or both of which can
+be empty. A ``relative-part`` refers to the full path with any ``root-path``
+removed.
+
+
+Creating A Path Variable
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+While a path can be created with care using an ordinary :command:`set`
+command, it is recommended to use :ref:`cmake_path(SET) <cmake_path-SET>`
+instead, as it automatically converts the path to the required form where
+required. The :ref:`cmake_path(APPEND) <APPEND>` subcommand may
+be another suitable alternative where a path needs to be constructed by
+joining fragments. The following example compares the three methods for
+constructing the same path:
+
+.. code-block:: cmake
+
+ set(path1 "${CMAKE_CURRENT_SOURCE_DIR}/data")
+
+ cmake_path(SET path2 "${CMAKE_CURRENT_SOURCE_DIR}/data")
+
+ cmake_path(APPEND path3 "${CMAKE_CURRENT_SOURCE_DIR}" "data")
+
+`Modification`_ and `Generation`_ sub-commands can either store the result
+in-place, or in a separate variable named after an ``OUTPUT_VARIABLE``
+keyword. All other sub-commands store the result in a mandatory ``<out-var>``
+variable.
+
+.. _Normalization:
+
+Normalization
+^^^^^^^^^^^^^
+
+Some sub-commands support *normalizing* a path. The algorithm used to
+normalize a path is as follows:
+
+1. If the path is empty, stop (the normalized form of an empty path is
+ also an empty path).
+2. Replace each ``directory-separator``, which may consist of multiple
+ separators, with a single ``/`` (``/a///b --> /a/b``).
+3. Remove each solitary period (``.``) and any immediately following
+ ``directory-separator`` (``/a/./b/. --> /a/b``).
+4. Remove each ``item-name`` (other than ``..``) that is immediately
+ followed by a ``directory-separator`` and a ``..``, along with any
+ immediately following ``directory-separator`` (``/a/b/../c --> a/c``).
+5. If there is a ``root-directory``, remove any ``..`` and any
+ ``directory-separators`` immediately following them. The parent of the
+ root directory is treated as still the root directory (``/../a --> /a``).
+6. If the last ``item-name`` is ``..``, remove any trailing
+ ``directory-separator`` (``../ --> ..``).
+7. If the path is empty by this stage, add a ``dot`` (normal form of ``./``
+ is ``.``).
+
+
+Decomposition
+^^^^^^^^^^^^^
+
+.. _GET:
+.. _GET_ROOT_NAME:
+.. _GET_ROOT_DIRECTORY:
+.. _GET_ROOT_PATH:
+.. _GET_FILENAME:
+.. _GET_EXTENSION:
+.. _GET_STEM:
+.. _GET_RELATIVE_PART:
+.. _GET_PARENT_PATH:
+
+The following forms of the ``GET`` subcommand each retrieve a different
+component or group of components from a path. See
+`Path Structure And Terminology`_ for the meaning of each path component.
+
+::
+
+ cmake_path(GET <path-var> ROOT_NAME <out-var>)
+ cmake_path(GET <path-var> ROOT_DIRECTORY <out-var>)
+ cmake_path(GET <path-var> ROOT_PATH <out-var>)
+ cmake_path(GET <path-var> FILENAME <out-var>)
+ cmake_path(GET <path-var> EXTENSION [LAST_ONLY] <out-var>)
+ cmake_path(GET <path-var> STEM [LAST_ONLY] <out-var>)
+ cmake_path(GET <path-var> RELATIVE_PART <out-var>)
+ cmake_path(GET <path-var> PARENT_PATH <out-var>)
+
+If a requested component is not present in the path, an empty string will be
+stored in ``<out-var>``. For example, only Windows systems have the concept
+of a ``root-name``, so when the host machine is non-Windows, the ``ROOT_NAME``
+subcommand will always return an empty string.
+
+For ``PARENT_PATH``, if the `HAS_RELATIVE_PART`_ subcommand returns false,
+the result is a copy of ``<path-var>``. Note that this implies that a root
+directory is considered to have a parent, with that parent being itself.
+Where `HAS_RELATIVE_PART`_ returns true, the result will essentially be
+``<path-var>`` with one less element.
+
+Root examples
+"""""""""""""
+
+.. code-block:: cmake
+
+ set(path "c:/a")
+
+ cmake_path(GET path ROOT_NAME rootName)
+ cmake_path(GET path ROOT_DIRECTORY rootDir)
+ cmake_path(GET path ROOT_PATH rootPath)
+
+ message("Root name is \"${rootName}\"")
+ message("Root directory is \"${rootDir}\"")
+ message("Root path is \"${rootPath}\"")
+
+::
+
+ Root name is "c:"
+ Root directory is "/"
+ Root path is "c:/"
+
+Filename examples
+"""""""""""""""""
+
+.. code-block:: cmake
+
+ set(path "/a/b")
+ cmake_path(GET path FILENAME filename)
+ message("First filename is \"${filename}\"")
+
+ # Trailing slash means filename is empty
+ set(path "/a/b/")
+ cmake_path(GET path FILENAME filename)
+ message("Second filename is \"${filename}\"")
+
+::
+
+ First filename is "b"
+ Second filename is ""
+
+Extension and stem examples
+"""""""""""""""""""""""""""
+
+.. code-block:: cmake
+
+ set(path "name.ext1.ext2")
+
+ cmake_path(GET path EXTENSION fullExt)
+ cmake_path(GET path STEM fullStem)
+ message("Full extension is \"${fullExt}\"")
+ message("Full stem is \"${fullStem}\"")
+
+ # Effect of LAST_ONLY
+ cmake_path(GET path EXTENSION LAST_ONLY lastExt)
+ cmake_path(GET path STEM LAST_ONLY lastStem)
+ message("Last extension is \"${lastExt}\"")
+ message("Last stem is \"${lastStem}\"")
+
+ # Special cases
+ set(dotPath "/a/.")
+ set(dotDotPath "/a/..")
+ set(someMorePath "/a/.some.more")
+ cmake_path(GET dotPath EXTENSION dotExt)
+ cmake_path(GET dotPath STEM dotStem)
+ cmake_path(GET dotDotPath EXTENSION dotDotExt)
+ cmake_path(GET dotDotPath STEM dotDotStem)
+ cmake_path(GET dotMorePath EXTENSION someMoreExt)
+ cmake_path(GET dotMorePath STEM someMoreStem)
+ message("Dot extension is \"${dotExt}\"")
+ message("Dot stem is \"${dotStem}\"")
+ message("Dot-dot extension is \"${dotDotExt}\"")
+ message("Dot-dot stem is \"${dotDotStem}\"")
+ message(".some.more extension is \"${someMoreExt}\"")
+ message(".some.more stem is \"${someMoreStem}\"")
+
+::
+
+ Full extension is ".ext1.ext2"
+ Full stem is "name"
+ Last extension is ".ext2"
+ Last stem is "name.ext1"
+ Dot extension is ""
+ Dot stem is "."
+ Dot-dot extension is ""
+ Dot-dot stem is ".."
+ .some.more extension is ".more"
+ .some.more stem is ".some"
+
+Relative part examples
+""""""""""""""""""""""
+
+.. code-block:: cmake
+
+ set(path "c:/a/b")
+ cmake_path(GET path RELATIVE_PART result)
+ message("Relative part is \"${result}\"")
+
+ set(path "c/d")
+ cmake_path(GET path RELATIVE_PART result)
+ message("Relative part is \"${result}\"")
+
+ set(path "/")
+ cmake_path(GET path RELATIVE_PART result)
+ message("Relative part is \"${result}\"")
+
+::
+
+ Relative part is "a/b"
+ Relative part is "c/d"
+ Relative part is ""
+
+Path traversal examples
+"""""""""""""""""""""""
+
+.. code-block:: cmake
+
+ set(path "c:/a/b")
+ cmake_path(GET path PARENT_PATH result)
+ message("Parent path is \"${result}\"")
+
+ set(path "c:/")
+ cmake_path(GET path PARENT_PATH result)
+ message("Parent path is \"${result}\"")
+
+::
+
+ Parent path is "c:/a"
+ Parent path is "c:/"
+
+
+Query
+^^^^^
+
+Each of the ``GET`` subcommands has a corresponding ``HAS_...``
+subcommand which can be used to discover whether a particular path
+component is present. See `Path Structure And Terminology`_ for the
+meaning of each path component.
+
+.. _HAS_ROOT_NAME:
+.. _HAS_ROOT_DIRECTORY:
+.. _HAS_ROOT_PATH:
+.. _HAS_FILENAME:
+.. _HAS_EXTENSION:
+.. _HAS_STEM:
+.. _HAS_RELATIVE_PART:
+.. _HAS_PARENT_PATH:
+
+::
+
+ cmake_path(HAS_ROOT_NAME <path-var> <out-var>)
+ cmake_path(HAS_ROOT_DIRECTORY <path-var> <out-var>)
+ cmake_path(HAS_ROOT_PATH <path-var> <out-var>)
+ cmake_path(HAS_FILENAME <path-var> <out-var>)
+ cmake_path(HAS_EXTENSION <path-var> <out-var>)
+ cmake_path(HAS_STEM <path-var> <out-var>)
+ cmake_path(HAS_RELATIVE_PART <path-var> <out-var>)
+ cmake_path(HAS_PARENT_PATH <path-var> <out-var>)
+
+Each of the above follows the predictable pattern of setting ``<out-var>``
+to true if the path has the associated component, or false otherwise.
+Note the following special cases:
+
+* For ``HAS_ROOT_PATH``, a true result will only be returned if at least one
+ of ``root-name`` or ``root-directory`` is non-empty.
+
+* For ``HAS_PARENT_PATH``, the root directory is also considered to have a
+ parent, which will be itself. The result is true except if the path
+ consists of just a :ref:`filename <FILENAME_DEF>`.
+
+.. _IS_ABSOLUTE:
+
+::
+
+ cmake_path(IS_ABSOLUTE <path-var> <out-var>)
+
+Sets ``<out-var>`` to true if ``<path-var>`` is absolute. An absolute path
+is a path that unambiguously identifies the location of a file without
+reference to an additional starting location. On Windows, this means the
+path must have both a ``root-name`` and a ``root-directory-separator`` to be
+considered absolute. On other platforms, just a ``root-directory-separator``
+is sufficient. Note that this means on Windows, ``IS_ABSOLUTE`` can be
+false while ``HAS_ROOT_DIRECTORY`` can be true.
+
+.. _IS_RELATIVE:
+
+::
+
+ cmake_path(IS_RELATIVE <path-var> <out-var>)
+
+This will store the opposite of ``IS_ABSOLUTE`` in ``<out-var>``.
+
+.. _IS_PREFIX:
+
+::
+
+ cmake_path(IS_PREFIX <path-var> <input> [NORMALIZE] <out-var>)
+
+Checks if ``<path-var>`` is the prefix of ``<input>``.
+
+When the ``NORMALIZE`` option is specified, ``<path-var>`` and ``<input>``
+are :ref:`normalized <Normalization>` before the check.
+
+.. code-block:: cmake
+
+ set(path "/a/b/c/d")
+ cmake_path(IS_PREFIX path "/a/b" result) # result = true
+ cmake_path(IS_PREFIX path "/x/y/z" result) # result = false
+
+ set(path "/a/b")
+ cmake_path(IS_PREFIX path "/a/c/../b" NORMALIZE result) # result = true
+
+.. _COMPARE:
+
+::
+
+ cmake_path(COMPARE <input1> EQUAL <input2> <out-var>)
+ cmake_path(COMPARE <input1> NOT_EQUAL <input2> <out-var>)
+
+Compares the lexical representations of two paths provided as string literals.
+No normalization is performed on either path. Equality is determined
+according to the following pseudo-code logic:
+
+::
+
+ if(NOT <input1>.root_name() STREQUAL <input2>.root_name())
+ return FALSE
+
+ if(<input1>.has_root_directory() XOR <input2>.has_root_directory())
+ return FALSE
+
+ Return FALSE if a relative portion of <input1> is not lexicographically
+ equal to the relative portion of <input2>. This comparison is performed path
+ component-wise. If all of the components compare equal, then return TRUE.
+
+.. note::
+ Unlike most other ``cmake_path()`` subcommands, the ``COMPARE`` subcommand
+ takes literal strings as input, not the names of variables.
+
+
+Modification
+^^^^^^^^^^^^
+
+.. _cmake_path-SET:
+
+::
+
+ cmake_path(SET <path-var> [NORMALIZE] <input>)
+
+Assign the ``<input>`` path to ``<path-var>``. If ``<input>`` is a native
+path, it is converted into a cmake-style path with forward-slashes
+(``/``). On Windows, the long filename marker is taken into account.
+
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` before the conversion.
+
+For example:
+
+.. code-block:: cmake
+
+ set(native_path "c:\\a\\b/..\\c")
+ cmake_path(SET path "${native_path}")
+ message("CMake path is \"${path}\"")
+
+ cmake_path(SET path NORMALIZE "${native_path}")
+ message("Normalized CMake path is \"${path}\"")
+
+Output::
+
+ CMake path is "c:/a/b/../c"
+ Normalized CMake path is "c:/a/c"
+
+.. _APPEND:
+
+::
+
+ cmake_path(APPEND <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
+
+Append all the ``<input>`` arguments to the ``<path-var>`` using ``/`` as
+the ``directory-separator``. Depending on the ``<input>``, the previous
+contents of ``<path-var>`` may be discarded. For each ``<input>`` argument,
+the following algorithm (pseudo-code) applies:
+
+::
+
+ # <path> is the contents of <path-var>
+
+ if(<input>.is_absolute() OR
+ (<input>.has_root_name() AND
+ NOT <input>.root_name() STREQUAL <path>.root_name()))
+ replace <path> with <input>
+ return()
+ endif()
+
+ if(<input>.has_root_directory())
+ remove any root-directory and the entire relative path from <path>
+ elseif(<path>.has_filename() OR
+ (NOT <path-var>.has_root_directory() OR <path>.is_absolute()))
+ append directory-separator to <path>
+ endif()
+
+ append <input> omitting any root-name to <path>
+
+.. _APPEND_STRING:
+
+::
+
+ cmake_path(APPEND_STRING <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
+
+Append all the ``<input>`` arguments to the ``<path-var>`` without adding any
+``directory-separator``.
+
+.. _REMOVE_FILENAME:
+
+::
+
+ cmake_path(REMOVE_FILENAME <path-var> [OUTPUT_VARIABLE <out-var>])
+
+Removes the :ref:`filename <FILENAME_DEF>` component (as returned by
+:ref:`GET ... FILENAME <GET_FILENAME>`) from ``<path-var>``. After removal,
+any trailing ``directory-separator`` is left alone, if present.
+
+If ``OUTPUT_VARIABLE`` is not given, then after this function returns,
+`HAS_FILENAME`_ returns false for ``<path-var>``.
+
+For example:
+
+.. code-block:: cmake
+
+ set(path "/a/b")
+ cmake_path(REMOVE_FILENAME path)
+ message("First path is \"${path}\"")
+
+ # filename is now already empty, the following removes nothing
+ cmake_path(REMOVE_FILENAME path)
+ message("Second path is \"${result}\"")
+
+Output::
+
+ First path is "/a/"
+ Second path is "/a/"
+
+.. _REPLACE_FILENAME:
+
+::
+
+ cmake_path(REPLACE_FILENAME <path-var> <input> [OUTPUT_VARIABLE <out-var>])
+
+Replaces the :ref:`filename <FILENAME_DEF>` component from ``<path-var>``
+with ``<input>``. If ``<path-var>`` has no filename component (i.e.
+`HAS_FILENAME`_ returns false), the path is unchanged. The operation is
+equivalent to the following:
+
+.. code-block:: cmake
+
+ cmake_path(HAS_FILENAME path has_filename)
+ if(has_filename)
+ cmake_path(REMOVE_FILENAME path)
+ cmake_path(APPEND path input);
+ endif()
+
+.. _REMOVE_EXTENSION:
+
+::
+
+ cmake_path(REMOVE_EXTENSION <path-var> [LAST_ONLY]
+ [OUTPUT_VARIABLE <out-var>])
+
+Removes the :ref:`extension <EXTENSION_DEF>`, if any, from ``<path-var>``.
+
+.. _REPLACE_EXTENSION:
+
+::
+
+ cmake_path(REPLACE_EXTENSION <path-var> [LAST_ONLY] <input>
+ [OUTPUT_VARIABLE <out-var>])
+
+Replaces the :ref:`extension <EXTENSION_DEF>` with ``<input>``. Its effect
+is equivalent to the following:
+
+.. code-block:: cmake
+
+ cmake_path(REMOVE_EXTENSION path)
+ if(NOT "input" MATCHES "^\\.")
+ cmake_path(APPEND_STRING path ".")
+ endif()
+ cmake_path(APPEND_STRING path "input")
+
+
+Generation
+^^^^^^^^^^
+
+.. _NORMAL_PATH:
+
+::
+
+ cmake_path(NORMAL_PATH <path-var> [OUTPUT_VARIABLE <out-var>])
+
+Normalize ``<path-var>`` according the steps described in :ref:`Normalization`.
+
+.. _cmake_path-RELATIVE_PATH:
+.. _RELATIVE_PATH:
+
+::
+
+ cmake_path(RELATIVE_PATH <path-var> [BASE_DIRECTORY <input>]
+ [OUTPUT_VARIABLE <out-var>])
+
+Modifies ``<path-var>`` to make it relative to the ``BASE_DIRECTORY`` argument.
+If ``BASE_DIRECTORY`` is not specified, the default base directory will be
+:variable:`CMAKE_CURRENT_SOURCE_DIR`.
+
+For reference, the algorithm used to compute the relative path is the same
+as that used by C++
+`std::filesystem::path::lexically_relative
+<https://en.cppreference.com/w/cpp/filesystem/path/lexically_normal>`_.
+
+.. _ABSOLUTE_PATH:
+
+::
+
+ cmake_path(ABSOLUTE_PATH <path-var> [BASE_DIRECTORY <input>] [NORMALIZE]
+ [OUTPUT_VARIABLE <out-var>])
+
+If ``<path-var>`` is a relative path (`IS_RELATIVE`_ is true), it is evaluated
+relative to the given base directory specified by ``BASE_DIRECTORY`` option.
+If ``BASE_DIRECTORY`` is not specified, the default base directory will be
+:variable:`CMAKE_CURRENT_SOURCE_DIR`.
+
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` after the path computation.
+
+Because ``cmake_path()`` does not access the filesystem, symbolic links are
+not resolved. To compute a real path with symbolic links resolved, use the
+:command:`file(REAL_PATH)` command instead.
+
+Native Conversion
+^^^^^^^^^^^^^^^^^
+
+For commands in this section, *native* refers to the host platform, not the
+target platform when cross-compiling.
+
+.. _cmake_path-NATIVE_PATH:
+.. _NATIVE_PATH:
+
+::
+
+ cmake_path(NATIVE_PATH <path-var> [NORMALIZE] <out-var>)
+
+Converts a cmake-style ``<path-var>`` into a native path with
+platform-specific slashes (``\`` on Windows hosts and ``/`` elsewhere).
+
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` before the conversion.
+
+.. _CONVERT:
+.. _cmake_path-TO_CMAKE_PATH_LIST:
+.. _TO_CMAKE_PATH_LIST:
+
+::
+
+ cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <out-var> [NORMALIZE])
+
+Converts a native ``<input>`` path into a cmake-style path with forward
+slashes (``/``). On Windows hosts, the long filename marker is taken into
+account. The input can be a single path or a system search path like
+``$ENV{PATH}``. A search path will be converted to a cmake-style list
+separated by ``;`` characters (on non-Windows platforms, this essentially
+means ``:`` separators are replaced with ``;``). The result of the
+conversion is stored in the ``<out-var>`` variable.
+
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` before the conversion.
+
+.. note::
+ Unlike most other ``cmake_path()`` subcommands, the ``CONVERT`` subcommand
+ takes a literal string as input, not the name of a variable.
+
+.. _cmake_path-TO_NATIVE_PATH_LIST:
+.. _TO_NATIVE_PATH_LIST:
+
+::
+
+ cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <out-var> [NORMALIZE])
+
+Converts a cmake-style ``<input>`` path into a native path with
+platform-specific slashes (``\`` on Windows hosts and ``/`` elsewhere).
+The input can be a single path or a cmake-style list. A list will be
+converted into a native search path (``;``-separated on Windows,
+``:``-separated on other platforms). The result of the conversion is
+stored in the ``<out-var>`` variable.
+
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` before the conversion.
+
+.. note::
+ Unlike most other ``cmake_path()`` subcommands, the ``CONVERT`` subcommand
+ takes a literal string as input, not the name of a variable.
+
+For example:
+
+.. code-block:: cmake
+
+ set(paths "/a/b/c" "/x/y/z")
+ cmake_path(CONVERT "${paths}" TO_NATIVE_PATH_LIST native_paths)
+ message("Native path list is \"${native_paths}\"")
+
+Output on Windows::
+
+ Native path list is "\a\b\c;\x\y\z"
+
+Output on all other platforms::
+
+ Native path list is "/a/b/c:/x/y/z"
+
+Hashing
+^^^^^^^
+
+.. _HASH:
+
+::
+
+ cmake_path(HASH <path-var> <out-var>)
+
+Compute a hash value of ``<path-var>`` such that for two paths ``p1`` and
+``p2`` that compare equal (:ref:`COMPARE ... EQUAL <COMPARE>`), the hash
+value of ``p1`` is equal to the hash value of ``p2``. The path is always
+:ref:`normalized <Normalization>` before the hash is computed.
diff --git a/Help/command/cmake_policy.rst b/Help/command/cmake_policy.rst
new file mode 100644
index 0000000..94060d9
--- /dev/null
+++ b/Help/command/cmake_policy.rst
@@ -0,0 +1,111 @@
+cmake_policy
+------------
+
+Manage CMake Policy settings. See the :manual:`cmake-policies(7)`
+manual for defined policies.
+
+As CMake evolves it is sometimes necessary to change existing behavior
+in order to fix bugs or improve implementations of existing features.
+The CMake Policy mechanism is designed to help keep existing projects
+building as new versions of CMake introduce changes in behavior. Each
+new policy (behavioral change) is given an identifier of the form
+``CMP<NNNN>`` where ``<NNNN>`` is an integer index. Documentation
+associated with each policy describes the ``OLD`` and ``NEW`` behavior
+and the reason the policy was introduced. Projects may set each policy
+to select the desired behavior. When CMake needs to know which behavior
+to use it checks for a setting specified by the project. If no
+setting is available the ``OLD`` behavior is assumed and a warning is
+produced requesting that the policy be set.
+
+Setting Policies by CMake Version
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``cmake_policy`` command is used to set policies to ``OLD`` or ``NEW``
+behavior. While setting policies individually is supported, we
+encourage projects to set policies based on CMake versions:
+
+.. code-block:: cmake
+
+ cmake_policy(VERSION <min>[...<max>])
+
+.. versionadded:: 3.12
+ The optional ``<max>`` version.
+
+``<min>`` and the optional ``<max>`` are each CMake versions of the form
+``major.minor[.patch[.tweak]]``, and the ``...`` is literal. The ``<min>``
+version must be at least ``2.4`` and at most the running version of CMake.
+The ``<max>`` version, if specified, must be at least the ``<min>`` version
+but may exceed the running version of CMake. If the running version of
+CMake is older than 3.12, the extra ``...`` dots will be seen as version
+component separators, resulting in the ``...<max>`` part being ignored and
+preserving the pre-3.12 behavior of basing policies on ``<min>``.
+
+This specifies that the current CMake code is written for the given
+range of CMake versions. All policies known to the running version of CMake
+and introduced in the ``<min>`` (or ``<max>``, if specified) version
+or earlier will be set to use ``NEW`` behavior. All policies
+introduced in later versions will be unset (unless the
+:variable:`CMAKE_POLICY_DEFAULT_CMP<NNNN>` variable sets a default).
+This effectively requests behavior preferred as of a given CMake
+version and tells newer CMake versions to warn about their new policies.
+
+Note that the :command:`cmake_minimum_required(VERSION)`
+command implicitly calls ``cmake_policy(VERSION)`` too.
+
+Setting Policies Explicitly
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ cmake_policy(SET CMP<NNNN> NEW)
+ cmake_policy(SET CMP<NNNN> OLD)
+
+Tell CMake to use the ``OLD`` or ``NEW`` behavior for a given policy.
+Projects depending on the old behavior of a given policy may silence a
+policy warning by setting the policy state to ``OLD``. Alternatively
+one may fix the project to work with the new behavior and set the
+policy state to ``NEW``.
+
+.. include:: ../policy/DEPRECATED.txt
+
+Checking Policy Settings
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ cmake_policy(GET CMP<NNNN> <variable>)
+
+Check whether a given policy is set to ``OLD`` or ``NEW`` behavior.
+The output ``<variable>`` value will be ``OLD`` or ``NEW`` if the
+policy is set, and empty otherwise.
+
+CMake Policy Stack
+^^^^^^^^^^^^^^^^^^
+
+CMake keeps policy settings on a stack, so changes made by the
+``cmake_policy`` command affect only the top of the stack. A new entry on
+the policy stack is managed automatically for each subdirectory to
+protect its parents and siblings. CMake also manages a new entry for
+scripts loaded by :command:`include` and :command:`find_package` commands
+except when invoked with the ``NO_POLICY_SCOPE`` option
+(see also policy :policy:`CMP0011`).
+The ``cmake_policy`` command provides an interface to manage custom
+entries on the policy stack:
+
+.. code-block:: cmake
+
+ cmake_policy(PUSH)
+ cmake_policy(POP)
+
+Each ``PUSH`` must have a matching ``POP`` to erase any changes.
+This is useful to make temporary changes to policy settings.
+Calls to the :command:`cmake_minimum_required(VERSION)`,
+``cmake_policy(VERSION)``, or ``cmake_policy(SET)`` commands
+influence only the current top of the policy stack.
+
+Commands created by the :command:`function` and :command:`macro`
+commands record policy settings when they are created and
+use the pre-record policies when they are invoked. If the function or
+macro implementation sets policies, the changes automatically
+propagate up through callers until they reach the closest nested
+policy stack entry.
diff --git a/Help/command/configure_file.rst b/Help/command/configure_file.rst
new file mode 100644
index 0000000..086668c
--- /dev/null
+++ b/Help/command/configure_file.rst
@@ -0,0 +1,183 @@
+configure_file
+--------------
+
+Copy a file to another location and modify its contents.
+
+.. code-block:: cmake
+
+ configure_file(<input> <output>
+ [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS |
+ FILE_PERMISSIONS <permissions>...]
+ [COPYONLY] [ESCAPE_QUOTES] [@ONLY]
+ [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
+
+Copies an ``<input>`` file to an ``<output>`` file and substitutes
+variable values referenced as ``@VAR@`` or ``${VAR}`` in the input
+file content. Each variable reference will be replaced with the
+current value of the variable, or the empty string if the variable
+is not defined. Furthermore, input lines of the form
+
+.. code-block:: c
+
+ #cmakedefine VAR ...
+
+will be replaced with either
+
+.. code-block:: c
+
+ #define VAR ...
+
+or
+
+.. code-block:: c
+
+ /* #undef VAR */
+
+depending on whether ``VAR`` is set in CMake to any value not considered
+a false constant by the :command:`if` command. The "..." content on the
+line after the variable name, if any, is processed as above.
+
+Unlike lines of the form ``#cmakedefine VAR ...``, in lines of the form
+``#cmakedefine01 VAR``, ``VAR`` itself will expand to ``VAR 0`` or ``VAR 1``
+rather than being assigned the value ``...``. Therefore, input lines of the form
+
+.. code-block:: c
+
+ #cmakedefine01 VAR
+
+will be replaced with either
+
+.. code-block:: c
+
+ #define VAR 0
+
+or
+
+.. code-block:: c
+
+ #define VAR 1
+
+Input lines of the form ``#cmakedefine01 VAR ...`` will expand
+as ``#cmakedefine01 VAR ... 0`` or ``#cmakedefine01 VAR ... 0``,
+which may lead to undefined behavior.
+
+.. versionadded:: 3.10
+ The result lines (with the exception of the ``#undef`` comments) can be
+ indented using spaces and/or tabs between the ``#`` character
+ and the ``cmakedefine`` or ``cmakedefine01`` words. This whitespace
+ indentation will be preserved in the output lines:
+
+ .. code-block:: c
+
+ # cmakedefine VAR
+ # cmakedefine01 VAR
+
+ will be replaced, if ``VAR`` is defined, with
+
+ .. code-block:: c
+
+ # define VAR
+ # define VAR 1
+
+If the input file is modified the build system will re-run CMake to
+re-configure the file and generate the build system again.
+The generated file is modified and its timestamp updated on subsequent
+cmake runs only if its content is changed.
+
+The arguments are:
+
+``<input>``
+ Path to the input file. A relative path is treated with respect to
+ the value of :variable:`CMAKE_CURRENT_SOURCE_DIR`. The input path
+ must be a file, not a directory.
+
+``<output>``
+ Path to the output file or directory. A relative path is treated
+ with respect to the value of :variable:`CMAKE_CURRENT_BINARY_DIR`.
+ If the path names an existing directory the output file is placed
+ in that directory with the same file name as the input file.
+
+``NO_SOURCE_PERMISSIONS``
+ .. versionadded:: 3.19
+
+ Do not transfer the permissions of the input file to the output file.
+ The copied file permissions default to the standard 644 value
+ (-rw-r--r--).
+
+``USE_SOURCE_PERMISSIONS``
+ .. versionadded:: 3.20
+
+ Transfer the permissions of the input file to the output file.
+ This is already the default behavior if none of the three permissions-related
+ keywords are given (``NO_SOURCE_PERMISSIONS``, ``USE_SOURCE_PERMISSIONS``
+ or ``FILE_PERMISSIONS``). The ``USE_SOURCE_PERMISSIONS`` keyword mostly
+ serves as a way of making the intended behavior clearer at the call site.
+
+``FILE_PERMISSIONS <permissions>...``
+ .. versionadded:: 3.20
+
+ Ignore the input file's permissions and use the specified ``<permissions>``
+ for the output file instead.
+
+``COPYONLY``
+ Copy the file without replacing any variable references or other
+ content. This option may not be used with ``NEWLINE_STYLE``.
+
+``ESCAPE_QUOTES``
+ Escape any substituted quotes with backslashes (C-style).
+
+``@ONLY``
+ Restrict variable replacement to references of the form ``@VAR@``.
+ This is useful for configuring scripts that use ``${VAR}`` syntax.
+
+``NEWLINE_STYLE <style>``
+ Specify the newline style for the output file. Specify
+ ``UNIX`` or ``LF`` for ``\n`` newlines, or specify
+ ``DOS``, ``WIN32``, or ``CRLF`` for ``\r\n`` newlines.
+ This option may not be used with ``COPYONLY``.
+
+Example
+^^^^^^^
+
+Consider a source tree containing a ``foo.h.in`` file:
+
+.. code-block:: c
+
+ #cmakedefine FOO_ENABLE
+ #cmakedefine FOO_STRING "@FOO_STRING@"
+
+An adjacent ``CMakeLists.txt`` may use ``configure_file`` to
+configure the header:
+
+.. code-block:: cmake
+
+ option(FOO_ENABLE "Enable Foo" ON)
+ if(FOO_ENABLE)
+ set(FOO_STRING "foo")
+ endif()
+ configure_file(foo.h.in foo.h @ONLY)
+
+This creates a ``foo.h`` in the build directory corresponding to
+this source directory. If the ``FOO_ENABLE`` option is on, the
+configured file will contain:
+
+.. code-block:: c
+
+ #define FOO_ENABLE
+ #define FOO_STRING "foo"
+
+Otherwise it will contain:
+
+.. code-block:: c
+
+ /* #undef FOO_ENABLE */
+ /* #undef FOO_STRING */
+
+One may then use the :command:`include_directories` command to
+specify the output directory as an include directory:
+
+.. code-block:: cmake
+
+ include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+so that sources may include the header as ``#include <foo.h>``.
diff --git a/Help/command/continue.rst b/Help/command/continue.rst
new file mode 100644
index 0000000..f62802e
--- /dev/null
+++ b/Help/command/continue.rst
@@ -0,0 +1,16 @@
+continue
+--------
+
+.. versionadded:: 3.2
+
+Continue to the top of enclosing foreach or while loop.
+
+.. code-block:: cmake
+
+ continue()
+
+The ``continue`` command allows a cmake script to abort the rest of a block
+in a :command:`foreach` or :command:`while` loop, and start at the top of
+the next iteration.
+
+See also the :command:`break` command.
diff --git a/Help/command/create_test_sourcelist.rst b/Help/command/create_test_sourcelist.rst
new file mode 100644
index 0000000..77e37c5
--- /dev/null
+++ b/Help/command/create_test_sourcelist.rst
@@ -0,0 +1,30 @@
+create_test_sourcelist
+----------------------
+
+Create a test driver and source list for building test programs.
+
+.. code-block:: cmake
+
+ create_test_sourcelist(sourceListName driverName
+ test1 test2 test3
+ EXTRA_INCLUDE include.h
+ FUNCTION function)
+
+A test driver is a program that links together many small tests into a
+single executable. This is useful when building static executables
+with large libraries to shrink the total required size. The list of
+source files needed to build the test driver will be in
+``sourceListName``. ``driverName`` is the name of the test driver program.
+The rest of the arguments consist of a list of test source files, can
+be semicolon separated. Each test source file should have a function
+in it that is the same name as the file with no extension (foo.cxx
+should have int foo(int, char*[]);) ``driverName`` will be able to call
+each of the tests by name on the command line. If ``EXTRA_INCLUDE`` is
+specified, then the next argument is included into the generated file.
+If ``FUNCTION`` is specified, then the next argument is taken as a
+function name that is passed a pointer to ac and av. This can be used
+to add extra command line processing to each test. The
+``CMAKE_TESTDRIVER_BEFORE_TESTMAIN`` cmake variable can be set to
+have code that will be placed directly before calling the test main function.
+``CMAKE_TESTDRIVER_AFTER_TESTMAIN`` can be set to have code that
+will be placed directly after the call to the test main function.
diff --git a/Help/command/ctest_build.rst b/Help/command/ctest_build.rst
new file mode 100644
index 0000000..4d6dc5a
--- /dev/null
+++ b/Help/command/ctest_build.rst
@@ -0,0 +1,85 @@
+ctest_build
+-----------
+
+Perform the :ref:`CTest Build Step` as a :ref:`Dashboard Client`.
+
+::
+
+ ctest_build([BUILD <build-dir>] [APPEND]
+ [CONFIGURATION <config>]
+ [FLAGS <flags>]
+ [PROJECT_NAME <project-name>]
+ [TARGET <target-name>]
+ [NUMBER_ERRORS <num-err-var>]
+ [NUMBER_WARNINGS <num-warn-var>]
+ [RETURN_VALUE <result-var>]
+ [CAPTURE_CMAKE_ERROR <result-var>]
+ )
+
+Build the project and store results in ``Build.xml``
+for submission with the :command:`ctest_submit` command.
+
+The :variable:`CTEST_BUILD_COMMAND` variable may be set to explicitly
+specify the build command line. Otherwise the build command line is
+computed automatically based on the options given.
+
+The options are:
+
+``BUILD <build-dir>``
+ Specify the top-level build directory. If not given, the
+ :variable:`CTEST_BINARY_DIRECTORY` variable is used.
+
+``APPEND``
+ Mark ``Build.xml`` for append to results previously submitted to a
+ dashboard server since the last :command:`ctest_start` call.
+ Append semantics are defined by the dashboard server in use.
+ This does *not* cause results to be appended to a ``.xml`` file
+ produced by a previous call to this command.
+
+``CONFIGURATION <config>``
+ Specify the build configuration (e.g. ``Debug``). If not
+ specified the ``CTEST_BUILD_CONFIGURATION`` variable will be checked.
+ Otherwise the ``-C <cfg>`` option given to the :manual:`ctest(1)`
+ command will be used, if any.
+
+``FLAGS <flags>``
+ Pass additional arguments to the underlying build command.
+ If not specified the ``CTEST_BUILD_FLAGS`` variable will be checked.
+ This can, e.g., be used to trigger a parallel build using the
+ ``-j`` option of make. See the :module:`ProcessorCount` module
+ for an example.
+
+``PROJECT_NAME <project-name>``
+ Ignored since CMake 3.0.
+
+ .. versionchanged:: 3.14
+ This value is no longer required.
+
+``TARGET <target-name>``
+ Specify the name of a target to build. If not specified the
+ ``CTEST_BUILD_TARGET`` variable will be checked. Otherwise the
+ default target will be built. This is the "all" target
+ (called ``ALL_BUILD`` in :ref:`Visual Studio Generators`).
+
+``NUMBER_ERRORS <num-err-var>``
+ Store the number of build errors detected in the given variable.
+
+``NUMBER_WARNINGS <num-warn-var>``
+ Store the number of build warnings detected in the given variable.
+
+``RETURN_VALUE <result-var>``
+ Store the return value of the native build tool in the given variable.
+
+``CAPTURE_CMAKE_ERROR <result-var>``
+ .. versionadded:: 3.7
+
+ Store in the ``<result-var>`` variable -1 if there are any errors running
+ the command and prevent ctest from returning non-zero if an error occurs.
+
+``QUIET``
+ .. versionadded:: 3.3
+
+ Suppress any CTest-specific non-error output that would have been
+ printed to the console otherwise. The summary of warnings / errors,
+ as well as the output from the native build tool is unaffected by
+ this option.
diff --git a/Help/command/ctest_configure.rst b/Help/command/ctest_configure.rst
new file mode 100644
index 0000000..95712aa
--- /dev/null
+++ b/Help/command/ctest_configure.rst
@@ -0,0 +1,50 @@
+ctest_configure
+---------------
+
+Perform the :ref:`CTest Configure Step` as a :ref:`Dashboard Client`.
+
+::
+
+ ctest_configure([BUILD <build-dir>] [SOURCE <source-dir>] [APPEND]
+ [OPTIONS <options>] [RETURN_VALUE <result-var>] [QUIET]
+ [CAPTURE_CMAKE_ERROR <result-var>])
+
+Configure the project build tree and record results in ``Configure.xml``
+for submission with the :command:`ctest_submit` command.
+
+The options are:
+
+``BUILD <build-dir>``
+ Specify the top-level build directory. If not given, the
+ :variable:`CTEST_BINARY_DIRECTORY` variable is used.
+
+``SOURCE <source-dir>``
+ Specify the source directory. If not given, the
+ :variable:`CTEST_SOURCE_DIRECTORY` variable is used.
+
+``APPEND``
+ Mark ``Configure.xml`` for append to results previously submitted to a
+ dashboard server since the last :command:`ctest_start` call.
+ Append semantics are defined by the dashboard server in use.
+ This does *not* cause results to be appended to a ``.xml`` file
+ produced by a previous call to this command.
+
+``OPTIONS <options>``
+ Specify command-line arguments to pass to the configuration tool.
+
+``RETURN_VALUE <result-var>``
+ Store in the ``<result-var>`` variable the return value of the native
+ configuration tool.
+
+``CAPTURE_CMAKE_ERROR <result-var>``
+ .. versionadded:: 3.7
+
+ Store in the ``<result-var>`` variable -1 if there are any errors running
+ the command and prevent ctest from returning non-zero if an error occurs.
+
+``QUIET``
+ .. versionadded:: 3.3
+
+ Suppress any CTest-specific non-error messages that would have
+ otherwise been printed to the console. Output from the underlying
+ configure command is not affected.
diff --git a/Help/command/ctest_coverage.rst b/Help/command/ctest_coverage.rst
new file mode 100644
index 0000000..a6c643b
--- /dev/null
+++ b/Help/command/ctest_coverage.rst
@@ -0,0 +1,50 @@
+ctest_coverage
+--------------
+
+Perform the :ref:`CTest Coverage Step` as a :ref:`Dashboard Client`.
+
+::
+
+ ctest_coverage([BUILD <build-dir>] [APPEND]
+ [LABELS <label>...]
+ [RETURN_VALUE <result-var>]
+ [CAPTURE_CMAKE_ERROR <result-var>]
+ [QUIET]
+ )
+
+Collect coverage tool results and stores them in ``Coverage.xml``
+for submission with the :command:`ctest_submit` command.
+
+The options are:
+
+``BUILD <build-dir>``
+ Specify the top-level build directory. If not given, the
+ :variable:`CTEST_BINARY_DIRECTORY` variable is used.
+
+``APPEND``
+ Mark ``Coverage.xml`` for append to results previously submitted to a
+ dashboard server since the last :command:`ctest_start` call.
+ Append semantics are defined by the dashboard server in use.
+ This does *not* cause results to be appended to a ``.xml`` file
+ produced by a previous call to this command.
+
+``LABELS``
+ Filter the coverage report to include only source files labeled
+ with at least one of the labels specified.
+
+``RETURN_VALUE <result-var>``
+ Store in the ``<result-var>`` variable ``0`` if coverage tools
+ ran without error and non-zero otherwise.
+
+``CAPTURE_CMAKE_ERROR <result-var>``
+ .. versionadded:: 3.7
+
+ Store in the ``<result-var>`` variable -1 if there are any errors running
+ the command and prevent ctest from returning non-zero if an error occurs.
+
+``QUIET``
+ .. versionadded:: 3.3
+
+ Suppress any CTest-specific non-error output that would have been
+ printed to the console otherwise. The summary indicating how many
+ lines of code were covered is unaffected by this option.
diff --git a/Help/command/ctest_empty_binary_directory.rst b/Help/command/ctest_empty_binary_directory.rst
new file mode 100644
index 0000000..7753667
--- /dev/null
+++ b/Help/command/ctest_empty_binary_directory.rst
@@ -0,0 +1,12 @@
+ctest_empty_binary_directory
+----------------------------
+
+empties the binary directory
+
+::
+
+ ctest_empty_binary_directory( directory )
+
+Removes a binary directory. This command will perform some checks
+prior to deleting the directory in an attempt to avoid malicious or
+accidental directory deletion.
diff --git a/Help/command/ctest_memcheck.rst b/Help/command/ctest_memcheck.rst
new file mode 100644
index 0000000..f655c2e
--- /dev/null
+++ b/Help/command/ctest_memcheck.rst
@@ -0,0 +1,40 @@
+ctest_memcheck
+--------------
+
+Perform the :ref:`CTest MemCheck Step` as a :ref:`Dashboard Client`.
+
+::
+
+ ctest_memcheck([BUILD <build-dir>] [APPEND]
+ [START <start-number>]
+ [END <end-number>]
+ [STRIDE <stride-number>]
+ [EXCLUDE <exclude-regex>]
+ [INCLUDE <include-regex>]
+ [EXCLUDE_LABEL <label-exclude-regex>]
+ [INCLUDE_LABEL <label-include-regex>]
+ [EXCLUDE_FIXTURE <regex>]
+ [EXCLUDE_FIXTURE_SETUP <regex>]
+ [EXCLUDE_FIXTURE_CLEANUP <regex>]
+ [PARALLEL_LEVEL <level>]
+ [TEST_LOAD <threshold>]
+ [SCHEDULE_RANDOM <ON|OFF>]
+ [STOP_TIME <time-of-day>]
+ [RETURN_VALUE <result-var>]
+ [DEFECT_COUNT <defect-count-var>]
+ [QUIET]
+ )
+
+
+Run tests with a dynamic analysis tool and store results in
+``MemCheck.xml`` for submission with the :command:`ctest_submit`
+command.
+
+Most options are the same as those for the :command:`ctest_test` command.
+
+The options unique to this command are:
+
+``DEFECT_COUNT <defect-count-var>``
+ .. versionadded:: 3.8
+
+ Store in the ``<defect-count-var>`` the number of defects found.
diff --git a/Help/command/ctest_read_custom_files.rst b/Help/command/ctest_read_custom_files.rst
new file mode 100644
index 0000000..cf8e17a
--- /dev/null
+++ b/Help/command/ctest_read_custom_files.rst
@@ -0,0 +1,14 @@
+ctest_read_custom_files
+-----------------------
+
+read CTestCustom files.
+
+::
+
+ ctest_read_custom_files( directory ... )
+
+Read all the CTestCustom.ctest or CTestCustom.cmake files from the
+given directory.
+
+By default, invoking :manual:`ctest(1)` without a script will read custom
+files from the binary directory.
diff --git a/Help/command/ctest_run_script.rst b/Help/command/ctest_run_script.rst
new file mode 100644
index 0000000..5ec543e
--- /dev/null
+++ b/Help/command/ctest_run_script.rst
@@ -0,0 +1,15 @@
+ctest_run_script
+----------------
+
+runs a ctest -S script
+
+::
+
+ ctest_run_script([NEW_PROCESS] script_file_name script_file_name1
+ script_file_name2 ... [RETURN_VALUE var])
+
+Runs a script or scripts much like if it was run from ctest -S. If no
+argument is provided then the current script is run using the current
+settings of the variables. If ``NEW_PROCESS`` is specified then each
+script will be run in a separate process.If ``RETURN_VALUE`` is specified
+the return value of the last script run will be put into ``var``.
diff --git a/Help/command/ctest_sleep.rst b/Help/command/ctest_sleep.rst
new file mode 100644
index 0000000..16a914c
--- /dev/null
+++ b/Help/command/ctest_sleep.rst
@@ -0,0 +1,16 @@
+ctest_sleep
+-----------
+
+sleeps for some amount of time
+
+::
+
+ ctest_sleep(<seconds>)
+
+Sleep for given number of seconds.
+
+::
+
+ ctest_sleep(<time1> <duration> <time2>)
+
+Sleep for t=(time1 + duration - time2) seconds if t > 0.
diff --git a/Help/command/ctest_start.rst b/Help/command/ctest_start.rst
new file mode 100644
index 0000000..c0f3c6d
--- /dev/null
+++ b/Help/command/ctest_start.rst
@@ -0,0 +1,88 @@
+ctest_start
+-----------
+
+Starts the testing for a given model
+
+::
+
+ ctest_start(<model> [<source> [<binary>]] [GROUP <group>] [QUIET])
+
+ ctest_start([<model> [<source> [<binary>]]] [GROUP <group>] APPEND [QUIET])
+
+Starts the testing for a given model. The command should be called
+after the binary directory is initialized.
+
+The parameters are as follows:
+
+``<model>``
+ Set the dashboard model. Must be one of ``Experimental``, ``Continuous``, or
+ ``Nightly``. This parameter is required unless ``APPEND`` is specified.
+
+``<source>``
+ Set the source directory. If not specified, the value of
+ :variable:`CTEST_SOURCE_DIRECTORY` is used instead.
+
+``<binary>``
+ Set the binary directory. If not specified, the value of
+ :variable:`CTEST_BINARY_DIRECTORY` is used instead.
+
+``GROUP <group>``
+ If ``GROUP`` is used, the submissions will go to the specified group on the
+ CDash server. If no ``GROUP`` is specified, the name of the model is used by
+ default.
+
+ .. versionchanged:: 3.16
+ This replaces the deprecated option ``TRACK``. Despite the name
+ change its behavior is unchanged.
+
+``APPEND``
+ If ``APPEND`` is used, the existing ``TAG`` is used rather than creating a new
+ one based on the current time stamp. If you use ``APPEND``, you can omit the
+ ``<model>`` and ``GROUP <group>`` parameters, because they will be read from
+ the generated ``TAG`` file. For example:
+
+ .. code-block:: cmake
+
+ ctest_start(Experimental GROUP GroupExperimental)
+
+ Later, in another ``ctest -S`` script:
+
+ .. code-block:: cmake
+
+ ctest_start(APPEND)
+
+ When the second script runs ``ctest_start(APPEND)``, it will read the
+ ``Experimental`` model and ``GroupExperimental`` group from the ``TAG`` file
+ generated by the first ``ctest_start()`` command. Please note that if you
+ call ``ctest_start(APPEND)`` and specify a different model or group than
+ in the first ``ctest_start()`` command, a warning will be issued, and the
+ new model and group will be used.
+
+``QUIET``
+ .. versionadded:: 3.3
+
+ If ``QUIET`` is used, CTest will suppress any non-error messages that it
+ otherwise would have printed to the console.
+
+The parameters for ``ctest_start()`` can be issued in any order, with the
+exception that ``<model>``, ``<source>``, and ``<binary>`` have to appear
+in that order with respect to each other. The following are all valid and
+equivalent:
+
+.. code-block:: cmake
+
+ ctest_start(Experimental path/to/source path/to/binary GROUP SomeGroup QUIET APPEND)
+
+ ctest_start(GROUP SomeGroup Experimental QUIET path/to/source APPEND path/to/binary)
+
+ ctest_start(APPEND QUIET Experimental path/to/source GROUP SomeGroup path/to/binary)
+
+However, for the sake of readability, it is recommended that you order your
+parameters in the order listed at the top of this page.
+
+If the :variable:`CTEST_CHECKOUT_COMMAND` variable (or the
+:variable:`CTEST_CVS_CHECKOUT` variable) is set, its content is treated as
+command-line. The command is invoked with the current working directory set
+to the parent of the source directory, even if the source directory already
+exists. This can be used to create the source tree from a version control
+repository.
diff --git a/Help/command/ctest_submit.rst b/Help/command/ctest_submit.rst
new file mode 100644
index 0000000..e6d277f
--- /dev/null
+++ b/Help/command/ctest_submit.rst
@@ -0,0 +1,130 @@
+ctest_submit
+------------
+
+Perform the :ref:`CTest Submit Step` as a :ref:`Dashboard Client`.
+
+::
+
+ ctest_submit([PARTS <part>...] [FILES <file>...]
+ [SUBMIT_URL <url>]
+ [BUILD_ID <result-var>]
+ [HTTPHEADER <header>]
+ [RETRY_COUNT <count>]
+ [RETRY_DELAY <delay>]
+ [RETURN_VALUE <result-var>]
+ [CAPTURE_CMAKE_ERROR <result-var>]
+ [QUIET]
+ )
+
+Submit results to a dashboard server.
+By default all available parts are submitted.
+
+The options are:
+
+``PARTS <part>...``
+ Specify a subset of parts to submit. Valid part names are::
+
+ Start = nothing
+ Update = ctest_update results, in Update.xml
+ Configure = ctest_configure results, in Configure.xml
+ Build = ctest_build results, in Build.xml
+ Test = ctest_test results, in Test.xml
+ Coverage = ctest_coverage results, in Coverage.xml
+ MemCheck = ctest_memcheck results, in DynamicAnalysis.xml
+ Notes = Files listed by CTEST_NOTES_FILES, in Notes.xml
+ ExtraFiles = Files listed by CTEST_EXTRA_SUBMIT_FILES
+ Upload = Files prepared for upload by ctest_upload(), in Upload.xml
+ Submit = nothing
+ Done = Build is complete, in Done.xml
+
+``FILES <file>...``
+ Specify an explicit list of specific files to be submitted.
+ Each individual file must exist at the time of the call.
+
+``SUBMIT_URL <url>``
+ .. versionadded:: 3.14
+
+ The ``http`` or ``https`` URL of the dashboard server to send the submission
+ to. If not given, the :variable:`CTEST_SUBMIT_URL` variable is used.
+
+``BUILD_ID <result-var>``
+ .. versionadded:: 3.15
+
+ Store in the ``<result-var>`` variable the ID assigned to this build by
+ CDash.
+
+``HTTPHEADER <HTTP-header>``
+ .. versionadded:: 3.9
+
+ Specify HTTP header to be included in the request to CDash during submission.
+ For example, CDash can be configured to only accept submissions from
+ authenticated clients. In this case, you should provide a bearer token in your
+ header:
+
+ .. code-block:: cmake
+
+ ctest_submit(HTTPHEADER "Authorization: Bearer <auth-token>")
+
+ This suboption can be repeated several times for multiple headers.
+
+``RETRY_COUNT <count>``
+ Specify how many times to retry a timed-out submission.
+
+``RETRY_DELAY <delay>``
+ Specify how long (in seconds) to wait after a timed-out submission
+ before attempting to re-submit.
+
+``RETURN_VALUE <result-var>``
+ Store in the ``<result-var>`` variable ``0`` for success and
+ non-zero on failure.
+
+``CAPTURE_CMAKE_ERROR <result-var>``
+ .. versionadded:: 3.13
+
+ Store in the ``<result-var>`` variable -1 if there are any errors running
+ the command and prevent ctest from returning non-zero if an error occurs.
+
+``QUIET``
+ .. versionadded:: 3.3
+
+ Suppress all non-error messages that would have otherwise been
+ printed to the console.
+
+Submit to CDash Upload API
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.2
+
+::
+
+ ctest_submit(CDASH_UPLOAD <file> [CDASH_UPLOAD_TYPE <type>]
+ [SUBMIT_URL <url>]
+ [BUILD_ID <result-var>]
+ [HTTPHEADER <header>]
+ [RETRY_COUNT <count>]
+ [RETRY_DELAY <delay>]
+ [RETURN_VALUE <result-var>]
+ [QUIET])
+
+This second signature is used to upload files to CDash via the CDash
+file upload API. The API first sends a request to upload to CDash along
+with a content hash of the file. If CDash does not already have the file,
+then it is uploaded. Along with the file, a CDash type string is specified
+to tell CDash which handler to use to process the data.
+
+This signature interprets options in the same way as the first one.
+
+.. versionadded:: 3.8
+ Added the ``RETRY_COUNT``, ``RETRY_DELAY``, ``QUIET`` options.
+
+.. versionadded:: 3.9
+ Added the ``HTTPHEADER`` option.
+
+.. versionadded:: 3.13
+ Added the ``RETURN_VALUE`` option.
+
+.. versionadded:: 3.14
+ Added the ``SUBMIT_URL`` option.
+
+.. versionadded:: 3.15
+ Added the ``BUILD_ID`` option.
diff --git a/Help/command/ctest_test.rst b/Help/command/ctest_test.rst
new file mode 100644
index 0000000..b4493a0
--- /dev/null
+++ b/Help/command/ctest_test.rst
@@ -0,0 +1,162 @@
+ctest_test
+----------
+
+Perform the :ref:`CTest Test Step` as a :ref:`Dashboard Client`.
+
+::
+
+ ctest_test([BUILD <build-dir>] [APPEND]
+ [START <start-number>]
+ [END <end-number>]
+ [STRIDE <stride-number>]
+ [EXCLUDE <exclude-regex>]
+ [INCLUDE <include-regex>]
+ [EXCLUDE_LABEL <label-exclude-regex>]
+ [INCLUDE_LABEL <label-include-regex>]
+ [EXCLUDE_FIXTURE <regex>]
+ [EXCLUDE_FIXTURE_SETUP <regex>]
+ [EXCLUDE_FIXTURE_CLEANUP <regex>]
+ [PARALLEL_LEVEL <level>]
+ [RESOURCE_SPEC_FILE <file>]
+ [TEST_LOAD <threshold>]
+ [SCHEDULE_RANDOM <ON|OFF>]
+ [STOP_ON_FAILURE]
+ [STOP_TIME <time-of-day>]
+ [RETURN_VALUE <result-var>]
+ [CAPTURE_CMAKE_ERROR <result-var>]
+ [REPEAT <mode>:<n>]
+ [QUIET]
+ )
+
+Run tests in the project build tree and store results in
+``Test.xml`` for submission with the :command:`ctest_submit` command.
+
+The options are:
+
+``BUILD <build-dir>``
+ Specify the top-level build directory. If not given, the
+ :variable:`CTEST_BINARY_DIRECTORY` variable is used.
+
+``APPEND``
+ Mark ``Test.xml`` for append to results previously submitted to a
+ dashboard server since the last :command:`ctest_start` call.
+ Append semantics are defined by the dashboard server in use.
+ This does *not* cause results to be appended to a ``.xml`` file
+ produced by a previous call to this command.
+
+``START <start-number>``
+ Specify the beginning of a range of test numbers.
+
+``END <end-number>``
+ Specify the end of a range of test numbers.
+
+``STRIDE <stride-number>``
+ Specify the stride by which to step across a range of test numbers.
+
+``EXCLUDE <exclude-regex>``
+ Specify a regular expression matching test names to exclude.
+
+``INCLUDE <include-regex>``
+ Specify a regular expression matching test names to include.
+ Tests not matching this expression are excluded.
+
+``EXCLUDE_LABEL <label-exclude-regex>``
+ Specify a regular expression matching test labels to exclude.
+
+``INCLUDE_LABEL <label-include-regex>``
+ Specify a regular expression matching test labels to include.
+ Tests not matching this expression are excluded.
+
+``EXCLUDE_FIXTURE <regex>``
+ .. versionadded:: 3.7
+
+ If a test in the set of tests to be executed requires a particular fixture,
+ that fixture's setup and cleanup tests would normally be added to the test
+ set automatically. This option prevents adding setup or cleanup tests for
+ fixtures matching the ``<regex>``. Note that all other fixture behavior is
+ retained, including test dependencies and skipping tests that have fixture
+ setup tests that fail.
+
+``EXCLUDE_FIXTURE_SETUP <regex>``
+ .. versionadded:: 3.7
+
+ Same as ``EXCLUDE_FIXTURE`` except only matching setup tests are excluded.
+
+``EXCLUDE_FIXTURE_CLEANUP <regex>``
+ .. versionadded:: 3.7
+
+ Same as ``EXCLUDE_FIXTURE`` except only matching cleanup tests are excluded.
+
+``PARALLEL_LEVEL <level>``
+ Specify a positive number representing the number of tests to
+ be run in parallel.
+
+``RESOURCE_SPEC_FILE <file>``
+ .. versionadded:: 3.16
+
+ Specify a
+ :ref:`resource specification file <ctest-resource-specification-file>`. See
+ :ref:`ctest-resource-allocation` for more information.
+
+``TEST_LOAD <threshold>``
+ .. versionadded:: 3.4
+
+ While running tests in parallel, try not to start tests when they
+ may cause the CPU load to pass above a given threshold. If not
+ specified the :variable:`CTEST_TEST_LOAD` variable will be checked,
+ and then the ``--test-load`` command-line argument to :manual:`ctest(1)`.
+ See also the ``TestLoad`` setting in the :ref:`CTest Test Step`.
+
+``REPEAT <mode>:<n>``
+ .. versionadded:: 3.17
+
+ Run tests repeatedly based on the given ``<mode>`` up to ``<n>`` times.
+ The modes are:
+
+ ``UNTIL_FAIL``
+ Require each test to run ``<n>`` times without failing in order to pass.
+ This is useful in finding sporadic failures in test cases.
+
+ ``UNTIL_PASS``
+ Allow each test to run up to ``<n>`` times in order to pass.
+ Repeats tests if they fail for any reason.
+ This is useful in tolerating sporadic failures in test cases.
+
+ ``AFTER_TIMEOUT``
+ Allow each test to run up to ``<n>`` times in order to pass.
+ Repeats tests only if they timeout.
+ This is useful in tolerating sporadic timeouts in test cases
+ on busy machines.
+
+``SCHEDULE_RANDOM <ON|OFF>``
+ Launch tests in a random order. This may be useful for detecting
+ implicit test dependencies.
+
+``STOP_ON_FAILURE``
+ .. versionadded:: 3.18
+
+ Stop the execution of the tests once one has failed.
+
+``STOP_TIME <time-of-day>``
+ Specify a time of day at which the tests should all stop running.
+
+``RETURN_VALUE <result-var>``
+ Store in the ``<result-var>`` variable ``0`` if all tests passed.
+ Store non-zero if anything went wrong.
+
+``CAPTURE_CMAKE_ERROR <result-var>``
+ .. versionadded:: 3.7
+
+ Store in the ``<result-var>`` variable -1 if there are any errors running
+ the command and prevent ctest from returning non-zero if an error occurs.
+
+``QUIET``
+ .. versionadded:: 3.3
+
+ Suppress any CTest-specific non-error messages that would have otherwise
+ been printed to the console. Output from the underlying test command is not
+ affected. Summary info detailing the percentage of passing tests is also
+ unaffected by the ``QUIET`` option.
+
+See also the :variable:`CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE`
+and :variable:`CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE` variables.
diff --git a/Help/command/ctest_update.rst b/Help/command/ctest_update.rst
new file mode 100644
index 0000000..63f991b
--- /dev/null
+++ b/Help/command/ctest_update.rst
@@ -0,0 +1,43 @@
+ctest_update
+------------
+
+Perform the :ref:`CTest Update Step` as a :ref:`Dashboard Client`.
+
+::
+
+ ctest_update([SOURCE <source-dir>]
+ [RETURN_VALUE <result-var>]
+ [CAPTURE_CMAKE_ERROR <result-var>]
+ [QUIET])
+
+Update the source tree from version control and record results in
+``Update.xml`` for submission with the :command:`ctest_submit` command.
+
+The options are:
+
+``SOURCE <source-dir>``
+ Specify the source directory. If not given, the
+ :variable:`CTEST_SOURCE_DIRECTORY` variable is used.
+
+``RETURN_VALUE <result-var>``
+ Store in the ``<result-var>`` variable the number of files
+ updated or ``-1`` on error.
+
+``CAPTURE_CMAKE_ERROR <result-var>``
+ .. versionadded:: 3.13
+
+ Store in the ``<result-var>`` variable -1 if there are any errors running
+ the command and prevent ctest from returning non-zero if an error occurs.
+
+``QUIET``
+ .. versionadded:: 3.3
+
+ Tell CTest to suppress most non-error messages that it would
+ have otherwise printed to the console. CTest will still report
+ the new revision of the repository and any conflicting files
+ that were found.
+
+The update always follows the version control branch currently checked
+out in the source directory. See the :ref:`CTest Update Step`
+documentation for information about variables that change the behavior
+of ``ctest_update()``.
diff --git a/Help/command/ctest_upload.rst b/Help/command/ctest_upload.rst
new file mode 100644
index 0000000..ffddd0a
--- /dev/null
+++ b/Help/command/ctest_upload.rst
@@ -0,0 +1,26 @@
+ctest_upload
+------------
+
+Upload files to a dashboard server as a :ref:`Dashboard Client`.
+
+::
+
+ ctest_upload(FILES <file>... [QUIET] [CAPTURE_CMAKE_ERROR <result-var>])
+
+The options are:
+
+``FILES <file>...``
+ Specify a list of files to be sent along with the build results to the
+ dashboard server.
+
+``QUIET``
+ .. versionadded:: 3.3
+
+ Suppress any CTest-specific non-error output that would have been
+ printed to the console otherwise.
+
+``CAPTURE_CMAKE_ERROR <result-var>``
+ .. versionadded:: 3.7
+
+ Store in the ``<result-var>`` variable -1 if there are any errors running
+ the command and prevent ctest from returning non-zero if an error occurs.
diff --git a/Help/command/define_property.rst b/Help/command/define_property.rst
new file mode 100644
index 0000000..8f7439b
--- /dev/null
+++ b/Help/command/define_property.rst
@@ -0,0 +1,59 @@
+define_property
+---------------
+
+Define and document custom properties.
+
+.. code-block:: cmake
+
+ define_property(<GLOBAL | DIRECTORY | TARGET | SOURCE |
+ TEST | VARIABLE | CACHED_VARIABLE>
+ PROPERTY <name> [INHERITED]
+ BRIEF_DOCS <brief-doc> [docs...]
+ FULL_DOCS <full-doc> [docs...])
+
+Defines one property in a scope for use with the :command:`set_property` and
+:command:`get_property` commands. This is primarily useful to associate
+documentation with property names that may be retrieved with the
+:command:`get_property` command. The first argument determines the kind of
+scope in which the property should be used. It must be one of the
+following:
+
+::
+
+ GLOBAL = associated with the global namespace
+ DIRECTORY = associated with one directory
+ TARGET = associated with one target
+ SOURCE = associated with one source file
+ TEST = associated with a test named with add_test
+ VARIABLE = documents a CMake language variable
+ CACHED_VARIABLE = documents a CMake cache variable
+
+Note that unlike :command:`set_property` and :command:`get_property` no
+actual scope needs to be given; only the kind of scope is important.
+
+The required ``PROPERTY`` option is immediately followed by the name of
+the property being defined.
+
+If the ``INHERITED`` option is given, then the :command:`get_property` command
+will chain up to the next higher scope when the requested property is not set
+in the scope given to the command.
+
+* ``DIRECTORY`` scope chains to its parent directory's scope, continuing the
+ walk up parent directories until a directory has the property set or there
+ are no more parents. If still not found at the top level directory, it
+ chains to the ``GLOBAL`` scope.
+* ``TARGET``, ``SOURCE`` and ``TEST`` properties chain to ``DIRECTORY`` scope,
+ including further chaining up the directories, etc. as needed.
+
+Note that this scope chaining behavior only applies to calls to
+:command:`get_property`, :command:`get_directory_property`,
+:command:`get_target_property`, :command:`get_source_file_property` and
+:command:`get_test_property`. There is no inheriting behavior when *setting*
+properties, so using ``APPEND`` or ``APPEND_STRING`` with the
+:command:`set_property` command will not consider inherited values when working
+out the contents to append to.
+
+The ``BRIEF_DOCS`` and ``FULL_DOCS`` options are followed by strings to be
+associated with the property as its brief and full documentation.
+Corresponding options to the :command:`get_property` command will retrieve
+the documentation.
diff --git a/Help/command/else.rst b/Help/command/else.rst
new file mode 100644
index 0000000..a98fcd8
--- /dev/null
+++ b/Help/command/else.rst
@@ -0,0 +1,10 @@
+else
+----
+
+Starts the else portion of an if block.
+
+.. code-block:: cmake
+
+ else([<condition>])
+
+See the :command:`if` command.
diff --git a/Help/command/elseif.rst b/Help/command/elseif.rst
new file mode 100644
index 0000000..6bf8646
--- /dev/null
+++ b/Help/command/elseif.rst
@@ -0,0 +1,11 @@
+elseif
+------
+
+Starts an elseif portion of an if block.
+
+.. code-block:: cmake
+
+ elseif(<condition>)
+
+See the :command:`if` command, especially for the syntax and logic
+of the ``<condition>``.
diff --git a/Help/command/enable_language.rst b/Help/command/enable_language.rst
new file mode 100644
index 0000000..ce765de
--- /dev/null
+++ b/Help/command/enable_language.rst
@@ -0,0 +1,35 @@
+enable_language
+---------------
+Enable a language (CXX/C/OBJC/OBJCXX/Fortran/etc)
+
+.. code-block:: cmake
+
+ enable_language(<lang> [OPTIONAL] )
+
+Enables support for the named language in CMake. This is
+the same as the :command:`project` command but does not create any of the extra
+variables that are created by the project command. Example languages
+are ``CXX``, ``C``, ``CUDA``, ``OBJC``, ``OBJCXX``, ``Fortran``,
+``ISPC``, and ``ASM``.
+
+.. versionadded:: 3.8
+ Added ``CUDA`` support.
+
+.. versionadded:: 3.16
+ Added ``OBJC`` and ``OBJCXX`` support.
+
+.. versionadded:: 3.18
+ Added ``ISPC`` support.
+
+If enabling ``ASM``, enable it last so that CMake can check whether
+compilers for other languages like ``C`` work for assembly too.
+
+This command must be called in file scope, not in a function call.
+Furthermore, it must be called in the highest directory common to all
+targets using the named language directly for compiling sources or
+indirectly through link dependencies. It is simplest to enable all
+needed languages in the top-level directory of a project.
+
+The ``OPTIONAL`` keyword is a placeholder for future implementation and
+does not currently work. Instead you can use the :module:`CheckLanguage`
+module to verify support before enabling.
diff --git a/Help/command/enable_testing.rst b/Help/command/enable_testing.rst
new file mode 100644
index 0000000..3ac1a19
--- /dev/null
+++ b/Help/command/enable_testing.rst
@@ -0,0 +1,20 @@
+enable_testing
+--------------
+
+Enable testing for current directory and below.
+
+.. code-block:: cmake
+
+ enable_testing()
+
+Enables testing for this directory and below.
+
+This command should be in the source directory root
+because ctest expects to find a test file in the build
+directory root.
+
+This command is automatically invoked when the :module:`CTest`
+module is included, except if the ``BUILD_TESTING`` option is
+turned off.
+
+See also the :command:`add_test` command.
diff --git a/Help/command/endforeach.rst b/Help/command/endforeach.rst
new file mode 100644
index 0000000..fd923d5
--- /dev/null
+++ b/Help/command/endforeach.rst
@@ -0,0 +1,14 @@
+endforeach
+----------
+
+Ends a list of commands in a foreach block.
+
+.. code-block:: cmake
+
+ endforeach([<loop_var>])
+
+See the :command:`foreach` command.
+
+The optional ``<loop_var>`` argument is supported for backward compatibility
+only. If used it must be a verbatim repeat of the ``<loop_var>`` argument of
+the opening ``foreach`` clause.
diff --git a/Help/command/endfunction.rst b/Help/command/endfunction.rst
new file mode 100644
index 0000000..e27129d
--- /dev/null
+++ b/Help/command/endfunction.rst
@@ -0,0 +1,14 @@
+endfunction
+-----------
+
+Ends a list of commands in a function block.
+
+.. code-block:: cmake
+
+ endfunction([<name>])
+
+See the :command:`function` command.
+
+The optional ``<name>`` argument is supported for backward compatibility
+only. If used it must be a verbatim repeat of the ``<name>`` argument
+of the opening ``function`` command.
diff --git a/Help/command/endif.rst b/Help/command/endif.rst
new file mode 100644
index 0000000..fc4f038
--- /dev/null
+++ b/Help/command/endif.rst
@@ -0,0 +1,14 @@
+endif
+-----
+
+Ends a list of commands in an if block.
+
+.. code-block:: cmake
+
+ endif([<condition>])
+
+See the :command:`if` command.
+
+The optional ``<condition>`` argument is supported for backward compatibility
+only. If used it must be a verbatim repeat of the argument of the opening
+``if`` clause.
diff --git a/Help/command/endmacro.rst b/Help/command/endmacro.rst
new file mode 100644
index 0000000..4290ba7
--- /dev/null
+++ b/Help/command/endmacro.rst
@@ -0,0 +1,14 @@
+endmacro
+--------
+
+Ends a list of commands in a macro block.
+
+.. code-block:: cmake
+
+ endmacro([<name>])
+
+See the :command:`macro` command.
+
+The optional ``<name>`` argument is supported for backward compatibility
+only. If used it must be a verbatim repeat of the ``<name>`` argument
+of the opening ``macro`` command.
diff --git a/Help/command/endwhile.rst b/Help/command/endwhile.rst
new file mode 100644
index 0000000..5ef585b
--- /dev/null
+++ b/Help/command/endwhile.rst
@@ -0,0 +1,14 @@
+endwhile
+--------
+
+Ends a list of commands in a while block.
+
+.. code-block:: cmake
+
+ endwhile([<condition>])
+
+See the :command:`while` command.
+
+The optional ``<condition>`` argument is supported for backward compatibility
+only. If used it must be a verbatim repeat of the argument of the opening
+``while`` clause.
diff --git a/Help/command/exec_program.rst b/Help/command/exec_program.rst
new file mode 100644
index 0000000..bc9b069
--- /dev/null
+++ b/Help/command/exec_program.rst
@@ -0,0 +1,26 @@
+exec_program
+------------
+
+.. deprecated:: 3.0
+
+ Use the :command:`execute_process` command instead.
+
+Run an executable program during the processing of the CMakeList.txt
+file.
+
+::
+
+ exec_program(Executable [directory in which to run]
+ [ARGS <arguments to executable>]
+ [OUTPUT_VARIABLE <var>]
+ [RETURN_VALUE <var>])
+
+The executable is run in the optionally specified directory. The
+executable can include arguments if it is double quoted, but it is
+better to use the optional ``ARGS`` argument to specify arguments to the
+program. This is because cmake will then be able to escape spaces in
+the executable path. An optional argument ``OUTPUT_VARIABLE`` specifies a
+variable in which to store the output. To capture the return value of
+the execution, provide a ``RETURN_VALUE``. If ``OUTPUT_VARIABLE`` is
+specified, then no output will go to the stdout/stderr of the console
+running cmake.
diff --git a/Help/command/execute_process.rst b/Help/command/execute_process.rst
new file mode 100644
index 0000000..82fcd46
--- /dev/null
+++ b/Help/command/execute_process.rst
@@ -0,0 +1,158 @@
+execute_process
+---------------
+
+Execute one or more child processes.
+
+.. code-block:: cmake
+
+ execute_process(COMMAND <cmd1> [<arguments>]
+ [COMMAND <cmd2> [<arguments>]]...
+ [WORKING_DIRECTORY <directory>]
+ [TIMEOUT <seconds>]
+ [RESULT_VARIABLE <variable>]
+ [RESULTS_VARIABLE <variable>]
+ [OUTPUT_VARIABLE <variable>]
+ [ERROR_VARIABLE <variable>]
+ [INPUT_FILE <file>]
+ [OUTPUT_FILE <file>]
+ [ERROR_FILE <file>]
+ [OUTPUT_QUIET]
+ [ERROR_QUIET]
+ [COMMAND_ECHO <where>]
+ [OUTPUT_STRIP_TRAILING_WHITESPACE]
+ [ERROR_STRIP_TRAILING_WHITESPACE]
+ [ENCODING <name>]
+ [ECHO_OUTPUT_VARIABLE]
+ [ECHO_ERROR_VARIABLE]
+ [COMMAND_ERROR_IS_FATAL <ANY|LAST>])
+
+Runs the given sequence of one or more commands.
+
+Commands are executed concurrently as a pipeline, with the standard
+output of each process piped to the standard input of the next.
+A single standard error pipe is used for all processes.
+
+Options:
+
+``COMMAND``
+ A child process command line.
+
+ CMake executes the child process using operating system APIs directly.
+ All arguments are passed VERBATIM to the child process.
+ No intermediate shell is used, so shell operators such as ``>``
+ are treated as normal arguments.
+ (Use the ``INPUT_*``, ``OUTPUT_*``, and ``ERROR_*`` options to
+ redirect stdin, stdout, and stderr.)
+
+ If a sequential execution of multiple commands is required, use multiple
+ :command:`execute_process` calls with a single ``COMMAND`` argument.
+
+``WORKING_DIRECTORY``
+ The named directory will be set as the current working directory of
+ the child processes.
+
+``TIMEOUT``
+ After the specified number of seconds (fractions allowed), all unfinished
+ child processes will be terminated, and the ``RESULT_VARIABLE`` will be
+ set to a string mentioning the "timeout".
+
+``RESULT_VARIABLE``
+ The variable will be set to contain the result of last child process.
+ This will be an integer return code from the last child or a string
+ describing an error condition.
+
+``RESULTS_VARIABLE <variable>``
+ .. versionadded:: 3.10
+
+ The variable will be set to contain the result of all processes as a
+ :ref:`semicolon-separated list <CMake Language Lists>`, in order of the
+ given ``COMMAND`` arguments. Each entry will be an integer return code
+ from the corresponding child or a string describing an error condition.
+
+``OUTPUT_VARIABLE``, ``ERROR_VARIABLE``
+ The variable named will be set with the contents of the standard output
+ and standard error pipes, respectively. If the same variable is named
+ for both pipes their output will be merged in the order produced.
+
+``INPUT_FILE, OUTPUT_FILE``, ``ERROR_FILE``
+ The file named will be attached to the standard input of the first
+ process, standard output of the last process, or standard error of
+ all processes, respectively.
+
+ .. versionadded:: 3.3
+ If the same file is named for both output and error then it will be used
+ for both.
+
+``OUTPUT_QUIET``, ``ERROR_QUIET``
+ The standard output or standard error results will be quietly ignored.
+
+``COMMAND_ECHO <where>``
+ .. versionadded:: 3.15
+
+ The command being run will be echo'ed to ``<where>`` with ``<where>``
+ being set to one of ``STDERR``, ``STDOUT`` or ``NONE``.
+ See the :variable:`CMAKE_EXECUTE_PROCESS_COMMAND_ECHO` variable for a way
+ to control the default behavior when this option is not present.
+
+``ENCODING <name>``
+ .. versionadded:: 3.8
+
+ On Windows, the encoding that is used to decode output from the process.
+ Ignored on other platforms.
+ Valid encoding names are:
+
+ ``NONE``
+ Perform no decoding. This assumes that the process output is encoded
+ in the same way as CMake's internal encoding (UTF-8).
+ This is the default.
+ ``AUTO``
+ Use the current active console's codepage or if that isn't
+ available then use ANSI.
+ ``ANSI``
+ Use the ANSI codepage.
+ ``OEM``
+ Use the original equipment manufacturer (OEM) code page.
+ ``UTF8`` or ``UTF-8``
+ Use the UTF-8 codepage.
+
+ .. versionadded:: 3.11
+ Accept ``UTF-8`` spelling for consistency with the
+ `UTF-8 RFC <https://www.ietf.org/rfc/rfc3629>`_ naming convention.
+
+``ECHO_OUTPUT_VARIABLE``, ``ECHO_ERROR_VARIABLE``
+ .. versionadded:: 3.18
+
+ The standard output or standard error will not be exclusively redirected to
+ the configured variables.
+
+ The output will be duplicated, it will be sent into the configured variables
+ and also on standard output or standard error.
+
+ This is analogous to the ``tee`` Unix command.
+
+``COMMAND_ERROR_IS_FATAL <ANY|LAST>``
+ .. versionadded:: 3.19
+
+ The option following ``COMMAND_ERROR_IS_FATAL`` determines the behavior when
+ an error is encountered:
+
+ ``ANY``
+ If any of the commands in the list of commands fail, the
+ ``execute_process()`` command halts with an error.
+
+ ``LAST``
+ If the last command in the list of commands fails, the
+ ``execute_process()`` command halts with an error. Commands earlier in the
+ list will not cause a fatal error.
+
+If more than one ``OUTPUT_*`` or ``ERROR_*`` option is given for the
+same pipe the precedence is not specified.
+If no ``OUTPUT_*`` or ``ERROR_*`` options are given the output will
+be shared with the corresponding pipes of the CMake process itself.
+
+The :command:`execute_process` command is a newer more powerful version of
+:command:`exec_program`, but the old command has been kept for compatibility.
+Both commands run while CMake is processing the project prior to build
+system generation. Use :command:`add_custom_target` and
+:command:`add_custom_command` to create custom commands that run at
+build time.
diff --git a/Help/command/export.rst b/Help/command/export.rst
new file mode 100644
index 0000000..e8a1fa7
--- /dev/null
+++ b/Help/command/export.rst
@@ -0,0 +1,93 @@
+export
+------
+
+Export targets from the build tree for use by outside projects.
+
+.. code-block:: cmake
+
+ export(EXPORT <export-name> [NAMESPACE <namespace>] [FILE <filename>])
+
+Creates a file ``<filename>`` that may be included by outside projects to
+import targets from the current project's build tree. This is useful
+during cross-compiling to build utility executables that can run on
+the host platform in one project and then import them into another
+project being compiled for the target platform. If the ``NAMESPACE``
+option is given the ``<namespace>`` string will be prepended to all target
+names written to the file.
+
+Target installations are associated with the export ``<export-name>``
+using the ``EXPORT`` option of the :command:`install(TARGETS)` command.
+
+The file created by this command is specific to the build tree and
+should never be installed. See the :command:`install(EXPORT)` command to
+export targets from an installation tree.
+
+The properties set on the generated IMPORTED targets will have the
+same values as the final values of the input TARGETS.
+
+.. code-block:: cmake
+
+ export(TARGETS [target1 [target2 [...]]] [NAMESPACE <namespace>]
+ [APPEND] FILE <filename> [EXPORT_LINK_INTERFACE_LIBRARIES])
+
+This signature is similar to the ``EXPORT`` signature, but targets are listed
+explicitly rather than specified as an export-name. If the APPEND option is
+given the generated code will be appended to the file instead of overwriting it.
+The EXPORT_LINK_INTERFACE_LIBRARIES keyword, if present, causes the
+contents of the properties matching
+``(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)?`` to be exported, when
+policy CMP0022 is NEW. If a library target is included in the export
+but a target to which it links is not included the behavior is
+unspecified.
+
+.. note::
+
+ :ref:`Object Libraries` under :generator:`Xcode` have special handling if
+ multiple architectures are listed in :variable:`CMAKE_OSX_ARCHITECTURES`.
+ In this case they will be exported as :ref:`Interface Libraries` with
+ no object files available to clients. This is sufficient to satisfy
+ transitive usage requirements of other targets that link to the
+ object libraries in their implementation.
+
+.. code-block:: cmake
+
+ export(PACKAGE <PackageName>)
+
+Store the current build directory in the CMake user package registry
+for package ``<PackageName>``. The :command:`find_package` command may consider the
+directory while searching for package ``<PackageName>``. This helps dependent
+projects find and use a package from the current project's build tree
+without help from the user. Note that the entry in the package
+registry that this command creates works only in conjunction with a
+package configuration file (``<PackageName>Config.cmake``) that works with the
+build tree. In some cases, for example for packaging and for system
+wide installations, it is not desirable to write the user package
+registry.
+
+.. versionchanged:: 3.1
+ If the :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable
+ is enabled, the ``export(PACKAGE)`` command will do nothing.
+
+.. versionchanged:: 3.15
+ By default the ``export(PACKAGE)`` command does nothing (see policy
+ :policy:`CMP0090`) because populating the user package registry has effects
+ outside the source and build trees. Set the
+ :variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` variable to add build directories
+ to the CMake user package registry.
+
+.. code-block:: cmake
+
+ export(TARGETS [target1 [target2 [...]]] [ANDROID_MK <filename>])
+
+.. versionadded:: 3.7
+
+This signature exports cmake built targets to the android ndk build system
+by creating an Android.mk file that references the prebuilt targets. The
+Android NDK supports the use of prebuilt libraries, both static and shared.
+This allows cmake to build the libraries of a project and make them available
+to an ndk build system complete with transitive dependencies, include flags
+and defines required to use the libraries. The signature takes a list of
+targets and puts them in the Android.mk file specified by the ``<filename>``
+given. This signature can only be used if policy CMP0022 is NEW for all
+targets given. A error will be issued if that policy is set to OLD for one
+of the targets.
diff --git a/Help/command/export_library_dependencies.rst b/Help/command/export_library_dependencies.rst
new file mode 100644
index 0000000..9753abf
--- /dev/null
+++ b/Help/command/export_library_dependencies.rst
@@ -0,0 +1,28 @@
+export_library_dependencies
+---------------------------
+
+Disallowed since version 3.0. See CMake Policy :policy:`CMP0033`.
+
+Use :command:`install(EXPORT)` or :command:`export` command.
+
+This command generates an old-style library dependencies file.
+Projects requiring CMake 2.6 or later should not use the command. Use
+instead the :command:`install(EXPORT)` command to help export targets from an
+installation tree and the :command:`export` command to export targets from a
+build tree.
+
+The old-style library dependencies file does not take into account
+per-configuration names of libraries or the
+:prop_tgt:`LINK_INTERFACE_LIBRARIES` target property.
+
+::
+
+ export_library_dependencies(<file> [APPEND])
+
+Create a file named ``<file>`` that can be included into a CMake listfile
+with the INCLUDE command. The file will contain a number of SET
+commands that will set all the variables needed for library dependency
+information. This should be the last command in the top level
+CMakeLists.txt file of the project. If the ``APPEND`` option is
+specified, the SET commands will be appended to the given file instead
+of replacing it.
diff --git a/Help/command/file.rst b/Help/command/file.rst
new file mode 100644
index 0000000..2b445c5
--- /dev/null
+++ b/Help/command/file.rst
@@ -0,0 +1,1182 @@
+file
+----
+
+File manipulation command.
+
+This command is dedicated to file and path manipulation requiring access to the
+filesystem.
+
+For other path manipulation, handling only syntactic aspects, have a look at
+:command:`cmake_path` command.
+
+.. note::
+
+ The sub-commands `RELATIVE_PATH`_, `TO_CMAKE_PATH`_ and `TO_NATIVE_PATH`_ has
+ been superseded, respectively, by sub-commands
+ :ref:`RELATIVE_PATH <cmake_path-RELATIVE_PATH>`,
+ :ref:`CONVERT ... TO_CMAKE_PATH_LIST <cmake_path-TO_CMAKE_PATH_LIST>` and
+ :ref:`CONVERT ... TO_NATIVE_PATH_LIST <cmake_path-TO_NATIVE_PATH_LIST>` of
+ :command:`cmake_path` command.
+
+Synopsis
+^^^^^^^^
+
+.. parsed-literal::
+
+ `Reading`_
+ file(`READ`_ <filename> <out-var> [...])
+ file(`STRINGS`_ <filename> <out-var> [...])
+ file(`\<HASH\> <HASH_>`_ <filename> <out-var>)
+ file(`TIMESTAMP`_ <filename> <out-var> [...])
+ file(`GET_RUNTIME_DEPENDENCIES`_ [...])
+
+ `Writing`_
+ file({`WRITE`_ | `APPEND`_} <filename> <content>...)
+ file({`TOUCH`_ | `TOUCH_NOCREATE`_} [<file>...])
+ file(`GENERATE`_ OUTPUT <output-file> [...])
+ file(`CONFIGURE`_ OUTPUT <output-file> CONTENT <content> [...])
+
+ `Filesystem`_
+ file({`GLOB`_ | `GLOB_RECURSE`_} <out-var> [...] [<globbing-expr>...])
+ file(`RENAME`_ <oldname> <newname> [...])
+ file(`COPY_FILE`_ <oldname> <newname> [...])
+ file({`REMOVE`_ | `REMOVE_RECURSE`_ } [<files>...])
+ file(`MAKE_DIRECTORY`_ [<dir>...])
+ file({`COPY`_ | `INSTALL`_} <file>... DESTINATION <dir> [...])
+ file(`SIZE`_ <filename> <out-var>)
+ file(`READ_SYMLINK`_ <linkname> <out-var>)
+ file(`CREATE_LINK`_ <original> <linkname> [...])
+ file(`CHMOD`_ <files>... <directories>... PERMISSIONS <permissions>... [...])
+ file(`CHMOD_RECURSE`_ <files>... <directories>... PERMISSIONS <permissions>... [...])
+
+ `Path Conversion`_
+ file(`REAL_PATH`_ <path> <out-var> [BASE_DIRECTORY <dir>])
+ file(`RELATIVE_PATH`_ <out-var> <directory> <file>)
+ file({`TO_CMAKE_PATH`_ | `TO_NATIVE_PATH`_} <path> <out-var>)
+
+ `Transfer`_
+ file(`DOWNLOAD`_ <url> [<file>] [...])
+ file(`UPLOAD`_ <file> <url> [...])
+
+ `Locking`_
+ file(`LOCK`_ <path> [...])
+
+ `Archiving`_
+ file(`ARCHIVE_CREATE`_ OUTPUT <archive> PATHS <paths>... [...])
+ file(`ARCHIVE_EXTRACT`_ INPUT <archive> [...])
+
+Reading
+^^^^^^^
+
+.. _READ:
+
+.. code-block:: cmake
+
+ file(READ <filename> <variable>
+ [OFFSET <offset>] [LIMIT <max-in>] [HEX])
+
+Read content from a file called ``<filename>`` and store it in a
+``<variable>``. Optionally start from the given ``<offset>`` and
+read at most ``<max-in>`` bytes. The ``HEX`` option causes data to
+be converted to a hexadecimal representation (useful for binary data). If the
+``HEX`` option is specified, letters in the output (``a`` through ``f``) are in
+lowercase.
+
+.. _STRINGS:
+
+.. code-block:: cmake
+
+ file(STRINGS <filename> <variable> [<options>...])
+
+Parse a list of ASCII strings from ``<filename>`` and store it in
+``<variable>``. Binary data in the file are ignored. Carriage return
+(``\r``, CR) characters are ignored. The options are:
+
+``LENGTH_MAXIMUM <max-len>``
+ Consider only strings of at most a given length.
+
+``LENGTH_MINIMUM <min-len>``
+ Consider only strings of at least a given length.
+
+``LIMIT_COUNT <max-num>``
+ Limit the number of distinct strings to be extracted.
+
+``LIMIT_INPUT <max-in>``
+ Limit the number of input bytes to read from the file.
+
+``LIMIT_OUTPUT <max-out>``
+ Limit the number of total bytes to store in the ``<variable>``.
+
+``NEWLINE_CONSUME``
+ Treat newline characters (``\n``, LF) as part of string content
+ instead of terminating at them.
+
+``NO_HEX_CONVERSION``
+ Intel Hex and Motorola S-record files are automatically converted to
+ binary while reading unless this option is given.
+
+``REGEX <regex>``
+ Consider only strings that match the given regular expression.
+
+``ENCODING <encoding-type>``
+ .. versionadded:: 3.1
+
+ Consider strings of a given encoding. Currently supported encodings are:
+ ``UTF-8``, ``UTF-16LE``, ``UTF-16BE``, ``UTF-32LE``, ``UTF-32BE``.
+ If the ``ENCODING`` option is not provided and the file has a Byte Order Mark,
+ the ``ENCODING`` option will be defaulted to respect the Byte Order Mark.
+
+ .. versionadded:: 3.2
+ Added the ``UTF-16LE``, ``UTF-16BE``, ``UTF-32LE``, ``UTF-32BE`` encodings.
+
+For example, the code
+
+.. code-block:: cmake
+
+ file(STRINGS myfile.txt myfile)
+
+stores a list in the variable ``myfile`` in which each item is a line
+from the input file.
+
+.. _HASH:
+
+.. code-block:: cmake
+
+ file(<HASH> <filename> <variable>)
+
+Compute a cryptographic hash of the content of ``<filename>`` and
+store it in a ``<variable>``. The supported ``<HASH>`` algorithm names
+are those listed by the :ref:`string(\<HASH\>) <Supported Hash Algorithms>`
+command.
+
+.. _TIMESTAMP:
+
+.. code-block:: cmake
+
+ file(TIMESTAMP <filename> <variable> [<format>] [UTC])
+
+Compute a string representation of the modification time of ``<filename>``
+and store it in ``<variable>``. Should the command be unable to obtain a
+timestamp variable will be set to the empty string ("").
+
+See the :command:`string(TIMESTAMP)` command for documentation of
+the ``<format>`` and ``UTC`` options.
+
+.. _GET_RUNTIME_DEPENDENCIES:
+
+.. code-block:: cmake
+
+ file(GET_RUNTIME_DEPENDENCIES
+ [RESOLVED_DEPENDENCIES_VAR <deps_var>]
+ [UNRESOLVED_DEPENDENCIES_VAR <unresolved_deps_var>]
+ [CONFLICTING_DEPENDENCIES_PREFIX <conflicting_deps_prefix>]
+ [EXECUTABLES [<executable_files>...]]
+ [LIBRARIES [<library_files>...]]
+ [MODULES [<module_files>...]]
+ [DIRECTORIES [<directories>...]]
+ [BUNDLE_EXECUTABLE <bundle_executable_file>]
+ [PRE_INCLUDE_REGEXES [<regexes>...]]
+ [PRE_EXCLUDE_REGEXES [<regexes>...]]
+ [POST_INCLUDE_REGEXES [<regexes>...]]
+ [POST_EXCLUDE_REGEXES [<regexes>...]]
+ )
+
+.. versionadded:: 3.16
+
+Recursively get the list of libraries depended on by the given files.
+
+Please note that this sub-command is not intended to be used in project mode.
+Instead, use it in an :command:`install(CODE)` or :command:`install(SCRIPT)`
+block. For example:
+
+.. code-block:: cmake
+
+ install(CODE [[
+ file(GET_RUNTIME_DEPENDENCIES
+ # ...
+ )
+ ]])
+
+The arguments are as follows:
+
+``RESOLVED_DEPENDENCIES_VAR <deps_var>``
+ Name of the variable in which to store the list of resolved dependencies.
+
+``UNRESOLVED_DEPENDENCIES_VAR <unresolved_deps_var>``
+ Name of the variable in which to store the list of unresolved dependencies.
+ If this variable is not specified, and there are any unresolved dependencies,
+ an error is issued.
+
+``CONFLICTING_DEPENDENCIES_PREFIX <conflicting_deps_prefix>``
+ Variable prefix in which to store conflicting dependency information.
+ Dependencies are conflicting if two files with the same name are found in
+ two different directories. The list of filenames that conflict are stored in
+ ``<conflicting_deps_prefix>_FILENAMES``. For each filename, the list of paths
+ that were found for that filename are stored in
+ ``<conflicting_deps_prefix>_<filename>``.
+
+``EXECUTABLES <executable_files>``
+ List of executable files to read for dependencies. These are executables that
+ are typically created with :command:`add_executable`, but they do not have to
+ be created by CMake. On Apple platforms, the paths to these files determine
+ the value of ``@executable_path`` when recursively resolving the libraries.
+ Specifying any kind of library (``STATIC``, ``MODULE``, or ``SHARED``) here
+ will result in undefined behavior.
+
+``LIBRARIES <library_files>``
+ List of library files to read for dependencies. These are libraries that are
+ typically created with :command:`add_library(SHARED)`, but they do not have
+ to be created by CMake. Specifying ``STATIC`` libraries, ``MODULE``
+ libraries, or executables here will result in undefined behavior.
+
+``MODULES <module_files>``
+ List of loadable module files to read for dependencies. These are modules
+ that are typically created with :command:`add_library(MODULE)`, but they do
+ not have to be created by CMake. They are typically used by calling
+ ``dlopen()`` at runtime rather than linked at link time with ``ld -l``.
+ Specifying ``STATIC`` libraries, ``SHARED`` libraries, or executables here
+ will result in undefined behavior.
+
+``DIRECTORIES <directories>``
+ List of additional directories to search for dependencies. On Linux
+ platforms, these directories are searched if the dependency is not found in
+ any of the other usual paths. If it is found in such a directory, a warning
+ is issued, because it means that the file is incomplete (it does not list all
+ of the directories that contain its dependencies). On Windows platforms,
+ these directories are searched if the dependency is not found in any of the
+ other search paths, but no warning is issued, because searching other paths
+ is a normal part of Windows dependency resolution. On Apple platforms, this
+ argument has no effect.
+
+``BUNDLE_EXECUTABLE <bundle_executable_file>``
+ Executable to treat as the "bundle executable" when resolving libraries. On
+ Apple platforms, this argument determines the value of ``@executable_path``
+ when recursively resolving libraries for ``LIBRARIES`` and ``MODULES`` files.
+ It has no effect on ``EXECUTABLES`` files. On other platforms, it has no
+ effect. This is typically (but not always) one of the executables in the
+ ``EXECUTABLES`` argument which designates the "main" executable of the
+ package.
+
+The following arguments specify filters for including or excluding libraries to
+be resolved. See below for a full description of how they work.
+
+``PRE_INCLUDE_REGEXES <regexes>``
+ List of pre-include regexes through which to filter the names of
+ not-yet-resolved dependencies.
+
+``PRE_EXCLUDE_REGEXES <regexes>``
+ List of pre-exclude regexes through which to filter the names of
+ not-yet-resolved dependencies.
+
+``POST_INCLUDE_REGEXES <regexes>``
+ List of post-include regexes through which to filter the names of resolved
+ dependencies.
+
+``POST_EXCLUDE_REGEXES <regexes>``
+ List of post-exclude regexes through which to filter the names of resolved
+ dependencies.
+
+These arguments can be used to exclude unwanted system libraries when
+resolving the dependencies, or to include libraries from a specific
+directory. The filtering works as follows:
+
+1. If the not-yet-resolved dependency matches any of the
+ ``PRE_INCLUDE_REGEXES``, steps 2 and 3 are skipped, and the dependency
+ resolution proceeds to step 4.
+2. If the not-yet-resolved dependency matches any of the
+ ``PRE_EXCLUDE_REGEXES``, dependency resolution stops for that dependency.
+3. Otherwise, dependency resolution proceeds.
+4. ``file(GET_RUNTIME_DEPENDENCIES)`` searches for the dependency according to
+ the linking rules of the platform (see below).
+5. If the dependency is found, and its full path matches one of the
+ ``POST_INCLUDE_REGEXES``, the full path is added to the resolved
+ dependencies, and ``file(GET_RUNTIME_DEPENDENCIES)`` recursively resolves
+ that library's own dependencies. Otherwise, resolution proceeds to step 6.
+6. If the dependency is found, but its full path matches one of the
+ ``POST_EXCLUDE_REGEXES``, it is not added to the resolved dependencies, and
+ dependency resolution stops for that dependency.
+7. If the dependency is found, and its full path does not match either
+ ``POST_INCLUDE_REGEXES`` or ``POST_EXCLUDE_REGEXES``, the full path is added
+ to the resolved dependencies, and ``file(GET_RUNTIME_DEPENDENCIES)``
+ recursively resolves that library's own dependencies.
+
+Different platforms have different rules for how dependencies are resolved.
+These specifics are described here.
+
+On Linux platforms, library resolution works as follows:
+
+1. If the depending file does not have any ``RUNPATH`` entries, and the library
+ exists in one of the depending file's ``RPATH`` entries, or its parents', in
+ that order, the dependency is resolved to that file.
+2. Otherwise, if the depending file has any ``RUNPATH`` entries, and the
+ library exists in one of those entries, the dependency is resolved to that
+ file.
+3. Otherwise, if the library exists in one of the directories listed by
+ ``ldconfig``, the dependency is resolved to that file.
+4. Otherwise, if the library exists in one of the ``DIRECTORIES`` entries, the
+ dependency is resolved to that file. In this case, a warning is issued,
+ because finding a file in one of the ``DIRECTORIES`` means that the
+ depending file is not complete (it does not list all the directories from
+ which it pulls dependencies).
+5. Otherwise, the dependency is unresolved.
+
+On Windows platforms, library resolution works as follows:
+
+1. The dependent DLL name is converted to lowercase. Windows DLL names are
+ case-insensitive, and some linkers mangle the case of the DLL dependency
+ names. However, this makes it more difficult for ``PRE_INCLUDE_REGEXES``,
+ ``PRE_EXCLUDE_REGEXES``, ``POST_INCLUDE_REGEXES``, and
+ ``POST_EXCLUDE_REGEXES`` to properly filter DLL names - every regex would
+ have to check for both uppercase and lowercase letters. For example:
+
+ .. code-block:: cmake
+
+ file(GET_RUNTIME_DEPENDENCIES
+ # ...
+ PRE_INCLUDE_REGEXES "^[Mm][Yy][Ll][Ii][Bb][Rr][Aa][Rr][Yy]\\.[Dd][Ll][Ll]$"
+ )
+
+ Converting the DLL name to lowercase allows the regexes to only match
+ lowercase names, thus simplifying the regex. For example:
+
+ .. code-block:: cmake
+
+ file(GET_RUNTIME_DEPENDENCIES
+ # ...
+ PRE_INCLUDE_REGEXES "^mylibrary\\.dll$"
+ )
+
+ This regex will match ``mylibrary.dll`` regardless of how it is cased,
+ either on disk or in the depending file. (For example, it will match
+ ``mylibrary.dll``, ``MyLibrary.dll``, and ``MYLIBRARY.DLL``.)
+
+ Please note that the directory portion of any resolved DLLs retains its
+ casing and is not converted to lowercase. Only the filename portion is
+ converted.
+
+2. (**Not yet implemented**) If the depending file is a Windows Store app, and
+ the dependency is listed as a dependency in the application's package
+ manifest, the dependency is resolved to that file.
+3. Otherwise, if the library exists in the same directory as the depending
+ file, the dependency is resolved to that file.
+4. Otherwise, if the library exists in either the operating system's
+ ``system32`` directory or the ``Windows`` directory, in that order, the
+ dependency is resolved to that file.
+5. Otherwise, if the library exists in one of the directories specified by
+ ``DIRECTORIES``, in the order they are listed, the dependency is resolved to
+ that file. In this case, a warning is not issued, because searching other
+ directories is a normal part of Windows library resolution.
+6. Otherwise, the dependency is unresolved.
+
+On Apple platforms, library resolution works as follows:
+
+1. If the dependency starts with ``@executable_path/``, and an ``EXECUTABLES``
+ argument is in the process of being resolved, and replacing
+ ``@executable_path/`` with the directory of the executable yields an
+ existing file, the dependency is resolved to that file.
+2. Otherwise, if the dependency starts with ``@executable_path/``, and there is
+ a ``BUNDLE_EXECUTABLE`` argument, and replacing ``@executable_path/`` with
+ the directory of the bundle executable yields an existing file, the
+ dependency is resolved to that file.
+3. Otherwise, if the dependency starts with ``@loader_path/``, and replacing
+ ``@loader_path/`` with the directory of the depending file yields an
+ existing file, the dependency is resolved to that file.
+4. Otherwise, if the dependency starts with ``@rpath/``, and replacing
+ ``@rpath/`` with one of the ``RPATH`` entries of the depending file yields
+ an existing file, the dependency is resolved to that file. Note that
+ ``RPATH`` entries that start with ``@executable_path/`` or ``@loader_path/``
+ also have these items replaced with the appropriate path.
+5. Otherwise, if the dependency is an absolute file that exists, the dependency
+ is resolved to that file.
+6. Otherwise, the dependency is unresolved.
+
+This function accepts several variables that determine which tool is used for
+dependency resolution:
+
+.. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM
+
+ Determines which operating system and executable format the files are built
+ for. This could be one of several values:
+
+ * ``linux+elf``
+ * ``windows+pe``
+ * ``macos+macho``
+
+ If this variable is not specified, it is determined automatically by system
+ introspection.
+
+.. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL
+
+ Determines the tool to use for dependency resolution. It could be one of
+ several values, depending on the value of
+ :variable:`CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM`:
+
+ ================================================= =============================================
+ ``CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM`` ``CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL``
+ ================================================= =============================================
+ ``linux+elf`` ``objdump``
+ ``windows+pe`` ``dumpbin``
+ ``windows+pe`` ``objdump``
+ ``macos+macho`` ``otool``
+ ================================================= =============================================
+
+ If this variable is not specified, it is determined automatically by system
+ introspection.
+
+.. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND
+
+ Determines the path to the tool to use for dependency resolution. This is the
+ actual path to ``objdump``, ``dumpbin``, or ``otool``.
+
+ If this variable is not specified, it is determined by the value of
+ ``CMAKE_OBJDUMP`` if set, else by system introspection.
+
+ .. versionadded:: 3.18
+ Use ``CMAKE_OBJDUMP`` if set.
+
+Writing
+^^^^^^^
+
+.. _WRITE:
+.. _APPEND:
+
+.. code-block:: cmake
+
+ file(WRITE <filename> <content>...)
+ file(APPEND <filename> <content>...)
+
+Write ``<content>`` into a file called ``<filename>``. If the file does
+not exist, it will be created. If the file already exists, ``WRITE``
+mode will overwrite it and ``APPEND`` mode will append to the end.
+Any directories in the path specified by ``<filename>`` that do not
+exist will be created.
+
+If the file is a build input, use the :command:`configure_file` command
+to update the file only when its content changes.
+
+.. _TOUCH:
+.. _TOUCH_NOCREATE:
+
+.. code-block:: cmake
+
+ file(TOUCH [<files>...])
+ file(TOUCH_NOCREATE [<files>...])
+
+.. versionadded:: 3.12
+
+Create a file with no content if it does not yet exist. If the file already
+exists, its access and/or modification will be updated to the time when the
+function call is executed.
+
+Use TOUCH_NOCREATE to touch a file if it exists but not create it. If a file
+does not exist it will be silently ignored.
+
+With TOUCH and TOUCH_NOCREATE the contents of an existing file will not be
+modified.
+
+.. _GENERATE:
+
+.. code-block:: cmake
+
+ file(GENERATE OUTPUT output-file
+ <INPUT input-file|CONTENT content>
+ [CONDITION expression] [TARGET target]
+ [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS |
+ FILE_PERMISSIONS <permissions>...]
+ [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
+
+Generate an output file for each build configuration supported by the current
+:manual:`CMake Generator <cmake-generators(7)>`. Evaluate
+:manual:`generator expressions <cmake-generator-expressions(7)>`
+from the input content to produce the output content. The options are:
+
+``CONDITION <condition>``
+ Generate the output file for a particular configuration only if
+ the condition is true. The condition must be either ``0`` or ``1``
+ after evaluating generator expressions.
+
+``CONTENT <content>``
+ Use the content given explicitly as input.
+
+``INPUT <input-file>``
+ Use the content from a given file as input.
+
+ .. versionchanged:: 3.10
+ A relative path is treated with respect to the value of
+ :variable:`CMAKE_CURRENT_SOURCE_DIR`. See policy :policy:`CMP0070`.
+
+``OUTPUT <output-file>``
+ Specify the output file name to generate. Use generator expressions
+ such as ``$<CONFIG>`` to specify a configuration-specific output file
+ name. Multiple configurations may generate the same output file only
+ if the generated content is identical. Otherwise, the ``<output-file>``
+ must evaluate to an unique name for each configuration.
+
+ .. versionchanged:: 3.10
+ A relative path (after evaluating generator expressions) is treated
+ with respect to the value of :variable:`CMAKE_CURRENT_BINARY_DIR`.
+ See policy :policy:`CMP0070`.
+
+``TARGET <target>``
+ .. versionadded:: 3.19
+
+ Specify which target to use when evaluating generator expressions that
+ require a target for evaluation (e.g. ``$<COMPILE_FEATURES:...>``,
+ ``$<TARGET_PROPERTY:prop>``).
+
+``NO_SOURCE_PERMISSIONS``
+ .. versionadded:: 3.20
+
+ The generated file permissions default to the standard 644 value
+ (-rw-r--r--).
+
+``USE_SOURCE_PERMISSIONS``
+ .. versionadded:: 3.20
+
+ Transfer the file permissions of the ``INPUT`` file to the generated file.
+ This is already the default behavior if none of the three permissions-related
+ keywords are given (``NO_SOURCE_PERMISSIONS``, ``USE_SOURCE_PERMISSIONS``
+ or ``FILE_PERMISSIONS``). The ``USE_SOURCE_PERMISSIONS`` keyword mostly
+ serves as a way of making the intended behavior clearer at the call site.
+ It is an error to specify this option without ``INPUT``.
+
+``FILE_PERMISSIONS <permissions>...``
+ .. versionadded:: 3.20
+
+ Use the specified permissions for the generated file.
+
+``NEWLINE_STYLE <style>``
+ .. versionadded:: 3.20
+
+ Specify the newline style for the generated file. Specify
+ ``UNIX`` or ``LF`` for ``\n`` newlines, or specify
+ ``DOS``, ``WIN32``, or ``CRLF`` for ``\r\n`` newlines.
+
+Exactly one ``CONTENT`` or ``INPUT`` option must be given. A specific
+``OUTPUT`` file may be named by at most one invocation of ``file(GENERATE)``.
+Generated files are modified and their timestamp updated on subsequent cmake
+runs only if their content is changed.
+
+Note also that ``file(GENERATE)`` does not create the output file until the
+generation phase. The output file will not yet have been written when the
+``file(GENERATE)`` command returns, it is written only after processing all
+of a project's ``CMakeLists.txt`` files.
+
+.. _CONFIGURE:
+
+.. code-block:: cmake
+
+ file(CONFIGURE OUTPUT output-file
+ CONTENT content
+ [ESCAPE_QUOTES] [@ONLY]
+ [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
+
+.. versionadded:: 3.18
+
+Generate an output file using the input given by ``CONTENT`` and substitute
+variable values referenced as ``@VAR@`` or ``${VAR}`` contained therein. The
+substitution rules behave the same as the :command:`configure_file` command.
+In order to match :command:`configure_file`'s behavior, generator expressions
+are not supported for both ``OUTPUT`` and ``CONTENT``.
+
+The arguments are:
+
+``OUTPUT <output-file>``
+ Specify the output file name to generate. A relative path is treated with
+ respect to the value of :variable:`CMAKE_CURRENT_BINARY_DIR`.
+ ``<output-file>`` does not support generator expressions.
+
+``CONTENT <content>``
+ Use the content given explicitly as input.
+ ``<content>`` does not support generator expressions.
+
+``ESCAPE_QUOTES``
+ Escape any substituted quotes with backslashes (C-style).
+
+``@ONLY``
+ Restrict variable replacement to references of the form ``@VAR@``.
+ This is useful for configuring scripts that use ``${VAR}`` syntax.
+
+``NEWLINE_STYLE <style>``
+ Specify the newline style for the output file. Specify
+ ``UNIX`` or ``LF`` for ``\n`` newlines, or specify
+ ``DOS``, ``WIN32``, or ``CRLF`` for ``\r\n`` newlines.
+
+Filesystem
+^^^^^^^^^^
+
+.. _GLOB:
+.. _GLOB_RECURSE:
+
+.. code-block:: cmake
+
+ file(GLOB <variable>
+ [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS]
+ [<globbing-expressions>...])
+ file(GLOB_RECURSE <variable> [FOLLOW_SYMLINKS]
+ [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS]
+ [<globbing-expressions>...])
+
+Generate a list of files that match the ``<globbing-expressions>`` and
+store it into the ``<variable>``. Globbing expressions are similar to
+regular expressions, but much simpler. If ``RELATIVE`` flag is
+specified, the results will be returned as relative paths to the given
+path.
+
+.. versionchanged:: 3.6
+ The results will be ordered lexicographically.
+
+On Windows and macOS, globbing is case-insensitive even if the underlying
+filesystem is case-sensitive (both filenames and globbing expressions are
+converted to lowercase before matching). On other platforms, globbing is
+case-sensitive.
+
+.. versionadded:: 3.3
+ By default ``GLOB`` lists directories - directories are omitted in result if
+ ``LIST_DIRECTORIES`` is set to false.
+
+.. versionadded:: 3.12
+ If the ``CONFIGURE_DEPENDS`` flag is specified, CMake will add logic
+ to the main build system check target to rerun the flagged ``GLOB`` commands
+ at build time. If any of the outputs change, CMake will regenerate the build
+ system.
+
+.. note::
+ We do not recommend using GLOB to collect a list of source files from
+ your source tree. If no CMakeLists.txt file changes when a source is
+ added or removed then the generated build system cannot know when to
+ ask CMake to regenerate.
+ The ``CONFIGURE_DEPENDS`` flag may not work reliably on all generators, or if
+ a new generator is added in the future that cannot support it, projects using
+ it will be stuck. Even if ``CONFIGURE_DEPENDS`` works reliably, there is
+ still a cost to perform the check on every rebuild.
+
+Examples of globbing expressions include::
+
+ *.cxx - match all files with extension cxx
+ *.vt? - match all files with extension vta,...,vtz
+ f[3-5].txt - match files f3.txt, f4.txt, f5.txt
+
+The ``GLOB_RECURSE`` mode will traverse all the subdirectories of the
+matched directory and match the files. Subdirectories that are symlinks
+are only traversed if ``FOLLOW_SYMLINKS`` is given or policy
+:policy:`CMP0009` is not set to ``NEW``.
+
+.. versionadded:: 3.3
+ By default ``GLOB_RECURSE`` omits directories from result list - setting
+ ``LIST_DIRECTORIES`` to true adds directories to result list.
+ If ``FOLLOW_SYMLINKS`` is given or policy :policy:`CMP0009` is not set to
+ ``NEW`` then ``LIST_DIRECTORIES`` treats symlinks as directories.
+
+Examples of recursive globbing include::
+
+ /dir/*.py - match all python files in /dir and subdirectories
+
+.. _RENAME:
+
+.. code-block:: cmake
+
+ file(RENAME <oldname> <newname>
+ [RESULT <result>]
+ [NO_REPLACE])
+
+Move a file or directory within a filesystem from ``<oldname>`` to
+``<newname>``, replacing the destination atomically.
+
+The options are:
+
+``RESULT <result>``
+ Set ``<result>`` variable to ``0`` on success or an error message otherwise.
+ If ``RESULT`` is not specified and the operation fails, an error is emitted.
+
+``NO_REPLACE``
+ If the ``<newname>`` path already exists, do not replace it.
+ If ``RESULT <result>`` is used, the result variable will be
+ set to ``NO_REPLACE``. Otherwise, an error is emitted.
+
+.. _COPY_FILE:
+
+.. code-block:: cmake
+
+ file(COPY_FILE <oldname> <newname>
+ [RESULT <result>]
+ [ONLY_IF_DIFFERENT])
+
+Copy a file from ``<oldname>`` to ``<newname>``. Directories are not
+supported. Symlinks are ignored and ``<oldfile>``'s content is read and
+written to ``<newname>`` as a new file.
+
+The options are:
+
+``RESULT <result>``
+ Set ``<result>`` variable to ``0`` on success or an error message otherwise.
+ If ``RESULT`` is not specified and the operation fails, an error is emitted.
+
+``ONLY_IF_DIFFERENT``
+ If the ``<newname>`` path already exists, do not replace it if it is the
+ same as ``<oldname>``. Otherwise, an error is emitted.
+
+.. _REMOVE:
+.. _REMOVE_RECURSE:
+
+.. code-block:: cmake
+
+ file(REMOVE [<files>...])
+ file(REMOVE_RECURSE [<files>...])
+
+Remove the given files. The ``REMOVE_RECURSE`` mode will remove the given
+files and directories, also non-empty directories. No error is emitted if a
+given file does not exist. Relative input paths are evaluated with respect
+to the current source directory.
+
+.. versionchanged:: 3.15
+ Empty input paths are ignored with a warning. Previous versions of CMake
+ interpreted empty string as a relative path with respect to the current
+ directory and removed its contents.
+
+.. _MAKE_DIRECTORY:
+
+.. code-block:: cmake
+
+ file(MAKE_DIRECTORY [<directories>...])
+
+Create the given directories and their parents as needed.
+
+.. _COPY:
+.. _INSTALL:
+
+.. code-block:: cmake
+
+ file(<COPY|INSTALL> <files>... DESTINATION <dir>
+ [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS]
+ [FILE_PERMISSIONS <permissions>...]
+ [DIRECTORY_PERMISSIONS <permissions>...]
+ [FOLLOW_SYMLINK_CHAIN]
+ [FILES_MATCHING]
+ [[PATTERN <pattern> | REGEX <regex>]
+ [EXCLUDE] [PERMISSIONS <permissions>...]] [...])
+
+The ``COPY`` signature copies files, directories, and symlinks to a
+destination folder. Relative input paths are evaluated with respect
+to the current source directory, and a relative destination is
+evaluated with respect to the current build directory. Copying
+preserves input file timestamps, and optimizes out a file if it exists
+at the destination with the same timestamp. Copying preserves input
+permissions unless explicit permissions or ``NO_SOURCE_PERMISSIONS``
+are given (default is ``USE_SOURCE_PERMISSIONS``).
+
+.. versionadded:: 3.15
+ If ``FOLLOW_SYMLINK_CHAIN`` is specified, ``COPY`` will recursively resolve
+ the symlinks at the paths given until a real file is found, and install
+ a corresponding symlink in the destination for each symlink encountered. For
+ each symlink that is installed, the resolution is stripped of the directory,
+ leaving only the filename, meaning that the new symlink points to a file in
+ the same directory as the symlink. This feature is useful on some Unix systems,
+ where libraries are installed as a chain of symlinks with version numbers, with
+ less specific versions pointing to more specific versions.
+ ``FOLLOW_SYMLINK_CHAIN`` will install all of these symlinks and the library
+ itself into the destination directory. For example, if you have the following
+ directory structure:
+
+* ``/opt/foo/lib/libfoo.so.1.2.3``
+* ``/opt/foo/lib/libfoo.so.1.2 -> libfoo.so.1.2.3``
+* ``/opt/foo/lib/libfoo.so.1 -> libfoo.so.1.2``
+* ``/opt/foo/lib/libfoo.so -> libfoo.so.1``
+
+and you do:
+
+.. code-block:: cmake
+
+ file(COPY /opt/foo/lib/libfoo.so DESTINATION lib FOLLOW_SYMLINK_CHAIN)
+
+This will install all of the symlinks and ``libfoo.so.1.2.3`` itself into
+``lib``.
+
+See the :command:`install(DIRECTORY)` command for documentation of
+permissions, ``FILES_MATCHING``, ``PATTERN``, ``REGEX``, and
+``EXCLUDE`` options. Copying directories preserves the structure
+of their content even if options are used to select a subset of
+files.
+
+The ``INSTALL`` signature differs slightly from ``COPY``: it prints
+status messages (subject to the :variable:`CMAKE_INSTALL_MESSAGE` variable),
+and ``NO_SOURCE_PERMISSIONS`` is default.
+Installation scripts generated by the :command:`install` command
+use this signature (with some undocumented options for internal use).
+
+.. _SIZE:
+
+.. code-block:: cmake
+
+ file(SIZE <filename> <variable>)
+
+.. versionadded:: 3.14
+
+Determine the file size of the ``<filename>`` and put the result in
+``<variable>`` variable. Requires that ``<filename>`` is a valid path
+pointing to a file and is readable.
+
+.. _READ_SYMLINK:
+
+.. code-block:: cmake
+
+ file(READ_SYMLINK <linkname> <variable>)
+
+.. versionadded:: 3.14
+
+This subcommand queries the symlink ``<linkname>`` and stores the path it
+points to in the result ``<variable>``. If ``<linkname>`` does not exist or
+is not a symlink, CMake issues a fatal error.
+
+Note that this command returns the raw symlink path and does not resolve
+a relative path. The following is an example of how to ensure that an
+absolute path is obtained:
+
+.. code-block:: cmake
+
+ set(linkname "/path/to/foo.sym")
+ file(READ_SYMLINK "${linkname}" result)
+ if(NOT IS_ABSOLUTE "${result}")
+ get_filename_component(dir "${linkname}" DIRECTORY)
+ set(result "${dir}/${result}")
+ endif()
+
+.. _CREATE_LINK:
+
+.. code-block:: cmake
+
+ file(CREATE_LINK <original> <linkname>
+ [RESULT <result>] [COPY_ON_ERROR] [SYMBOLIC])
+
+.. versionadded:: 3.14
+
+Create a link ``<linkname>`` that points to ``<original>``.
+It will be a hard link by default, but providing the ``SYMBOLIC`` option
+results in a symbolic link instead. Hard links require that ``original``
+exists and is a file, not a directory. If ``<linkname>`` already exists,
+it will be overwritten.
+
+The ``<result>`` variable, if specified, receives the status of the operation.
+It is set to ``0`` upon success or an error message otherwise. If ``RESULT``
+is not specified and the operation fails, a fatal error is emitted.
+
+Specifying ``COPY_ON_ERROR`` enables copying the file as a fallback if
+creating the link fails. It can be useful for handling situations such as
+``<original>`` and ``<linkname>`` being on different drives or mount points,
+which would make them unable to support a hard link.
+
+.. _CHMOD:
+
+.. code-block:: cmake
+
+ file(CHMOD <files>... <directories>...
+ [PERMISSIONS <permissions>...]
+ [FILE_PERMISSIONS <permissions>...]
+ [DIRECTORY_PERMISSIONS <permissions>...])
+
+.. versionadded:: 3.19
+
+Set the permissions for the ``<files>...`` and ``<directories>...`` specified.
+Valid permissions are ``OWNER_READ``, ``OWNER_WRITE``, ``OWNER_EXECUTE``,
+``GROUP_READ``, ``GROUP_WRITE``, ``GROUP_EXECUTE``, ``WORLD_READ``,
+``WORLD_WRITE``, ``WORLD_EXECUTE``, ``SETUID``, ``SETGID``.
+
+Valid combination of keywords are:
+
+``PERMISSIONS``
+ All items are changed.
+
+``FILE_PERMISSIONS``
+ Only files are changed.
+
+``DIRECTORY_PERMISSIONS``
+ Only directories are changed.
+
+``PERMISSIONS`` and ``FILE_PERMISSIONS``
+ ``FILE_PERMISSIONS`` overrides ``PERMISSIONS`` for files.
+
+``PERMISSIONS`` and ``DIRECTORY_PERMISSIONS``
+ ``DIRECTORY_PERMISSIONS`` overrides ``PERMISSIONS`` for directories.
+
+``FILE_PERMISSIONS`` and ``DIRECTORY_PERMISSIONS``
+ Use ``FILE_PERMISSIONS`` for files and ``DIRECTORY_PERMISSIONS`` for
+ directories.
+
+
+.. _CHMOD_RECURSE:
+
+.. code-block:: cmake
+
+ file(CHMOD_RECURSE <files>... <directories>...
+ [PERMISSIONS <permissions>...]
+ [FILE_PERMISSIONS <permissions>...]
+ [DIRECTORY_PERMISSIONS <permissions>...])
+
+.. versionadded:: 3.19
+
+Same as `CHMOD`_, but change the permissions of files and directories present in
+the ``<directories>...`` recursively.
+
+Path Conversion
+^^^^^^^^^^^^^^^
+
+.. _REAL_PATH:
+
+.. code-block:: cmake
+
+ file(REAL_PATH <path> <out-var> [BASE_DIRECTORY <dir>])
+
+.. versionadded:: 3.19
+
+Compute the absolute path to an existing file or directory with symlinks
+resolved.
+
+If the provided ``<path>`` is a relative path, it is evaluated relative to the
+given base directory ``<dir>``. If no base directory is provided, the default
+base directory will be :variable:`CMAKE_CURRENT_SOURCE_DIR`.
+
+.. _RELATIVE_PATH:
+
+.. code-block:: cmake
+
+ file(RELATIVE_PATH <variable> <directory> <file>)
+
+Compute the relative path from a ``<directory>`` to a ``<file>`` and
+store it in the ``<variable>``.
+
+.. _TO_CMAKE_PATH:
+.. _TO_NATIVE_PATH:
+
+.. code-block:: cmake
+
+ file(TO_CMAKE_PATH "<path>" <variable>)
+ file(TO_NATIVE_PATH "<path>" <variable>)
+
+The ``TO_CMAKE_PATH`` mode converts a native ``<path>`` into a cmake-style
+path with forward-slashes (``/``). The input can be a single path or a
+system search path like ``$ENV{PATH}``. A search path will be converted
+to a cmake-style list separated by ``;`` characters.
+
+The ``TO_NATIVE_PATH`` mode converts a cmake-style ``<path>`` into a native
+path with platform-specific slashes (``\`` on Windows and ``/`` elsewhere).
+
+Always use double quotes around the ``<path>`` to be sure it is treated
+as a single argument to this command.
+
+Transfer
+^^^^^^^^
+
+.. _DOWNLOAD:
+.. _UPLOAD:
+
+.. code-block:: cmake
+
+ file(DOWNLOAD <url> [<file>] [<options>...])
+ file(UPLOAD <file> <url> [<options>...])
+
+The ``DOWNLOAD`` subcommand downloads the given ``<url>`` to a local ``<file>``.
+The ``UPLOAD`` mode uploads a local ``<file>`` to a given ``<url>``.
+
+.. versionadded:: 3.19
+ If ``<file>`` is not specified for ``file(DOWNLOAD)``, the file is not saved.
+ This can be useful if you want to know if a file can be downloaded (for example,
+ to check that it exists) without actually saving it anywhere.
+
+Options to both ``DOWNLOAD`` and ``UPLOAD`` are:
+
+``INACTIVITY_TIMEOUT <seconds>``
+ Terminate the operation after a period of inactivity.
+
+``LOG <variable>``
+ Store a human-readable log of the operation in a variable.
+
+``SHOW_PROGRESS``
+ Print progress information as status messages until the operation is
+ complete.
+
+``STATUS <variable>``
+ Store the resulting status of the operation in a variable.
+ The status is a ``;`` separated list of length 2.
+ The first element is the numeric return value for the operation,
+ and the second element is a string value for the error.
+ A ``0`` numeric error means no error in the operation.
+
+``TIMEOUT <seconds>``
+ Terminate the operation after a given total time has elapsed.
+
+``USERPWD <username>:<password>``
+ .. versionadded:: 3.7
+
+ Set username and password for operation.
+
+``HTTPHEADER <HTTP-header>``
+ .. versionadded:: 3.7
+
+ HTTP header for operation. Suboption can be repeated several times.
+
+``NETRC <level>``
+ .. versionadded:: 3.11
+
+ Specify whether the .netrc file is to be used for operation. If this
+ option is not specified, the value of the ``CMAKE_NETRC`` variable
+ will be used instead.
+ Valid levels are:
+
+ ``IGNORED``
+ The .netrc file is ignored.
+ This is the default.
+ ``OPTIONAL``
+ The .netrc file is optional, and information in the URL is preferred.
+ The file will be scanned to find which ever information is not specified
+ in the URL.
+ ``REQUIRED``
+ The .netrc file is required, and information in the URL is ignored.
+
+``NETRC_FILE <file>``
+ .. versionadded:: 3.11
+
+ Specify an alternative .netrc file to the one in your home directory,
+ if the ``NETRC`` level is ``OPTIONAL`` or ``REQUIRED``. If this option
+ is not specified, the value of the ``CMAKE_NETRC_FILE`` variable will
+ be used instead.
+
+If neither ``NETRC`` option is given CMake will check variables
+``CMAKE_NETRC`` and ``CMAKE_NETRC_FILE``, respectively.
+
+``TLS_VERIFY <ON|OFF>``
+ Specify whether to verify the server certificate for ``https://`` URLs.
+ The default is to *not* verify.
+
+ .. versionadded:: 3.18
+ Added support to ``file(UPLOAD)``.
+
+``TLS_CAINFO <file>``
+ Specify a custom Certificate Authority file for ``https://`` URLs.
+
+ .. versionadded:: 3.18
+ Added support to ``file(UPLOAD)``.
+
+For ``https://`` URLs CMake must be built with OpenSSL support. ``TLS/SSL``
+certificates are not checked by default. Set ``TLS_VERIFY`` to ``ON`` to
+check certificates. If neither ``TLS`` option is given CMake will check
+variables ``CMAKE_TLS_VERIFY`` and ``CMAKE_TLS_CAINFO``, respectively.
+
+Additional options to ``DOWNLOAD`` are:
+
+``EXPECTED_HASH ALGO=<value>``
+
+ Verify that the downloaded content hash matches the expected value, where
+ ``ALGO`` is one of the algorithms supported by ``file(<HASH>)``.
+ If it does not match, the operation fails with an error. It is an error to
+ specify this if ``DOWNLOAD`` is not given a ``<file>``.
+
+``EXPECTED_MD5 <value>``
+ Historical short-hand for ``EXPECTED_HASH MD5=<value>``. It is an error to
+ specify this if ``DOWNLOAD`` is not given a ``<file>``.
+
+Locking
+^^^^^^^
+
+.. _LOCK:
+
+.. code-block:: cmake
+
+ file(LOCK <path> [DIRECTORY] [RELEASE]
+ [GUARD <FUNCTION|FILE|PROCESS>]
+ [RESULT_VARIABLE <variable>]
+ [TIMEOUT <seconds>])
+
+.. versionadded:: 3.2
+
+Lock a file specified by ``<path>`` if no ``DIRECTORY`` option present and file
+``<path>/cmake.lock`` otherwise. File will be locked for scope defined by
+``GUARD`` option (default value is ``PROCESS``). ``RELEASE`` option can be used
+to unlock file explicitly. If option ``TIMEOUT`` is not specified CMake will
+wait until lock succeed or until fatal error occurs. If ``TIMEOUT`` is set to
+``0`` lock will be tried once and result will be reported immediately. If
+``TIMEOUT`` is not ``0`` CMake will try to lock file for the period specified
+by ``<seconds>`` value. Any errors will be interpreted as fatal if there is no
+``RESULT_VARIABLE`` option. Otherwise result will be stored in ``<variable>``
+and will be ``0`` on success or error message on failure.
+
+Note that lock is advisory - there is no guarantee that other processes will
+respect this lock, i.e. lock synchronize two or more CMake instances sharing
+some modifiable resources. Similar logic applied to ``DIRECTORY`` option -
+locking parent directory doesn't prevent other ``LOCK`` commands to lock any
+child directory or file.
+
+Trying to lock file twice is not allowed. Any intermediate directories and
+file itself will be created if they not exist. ``GUARD`` and ``TIMEOUT``
+options ignored on ``RELEASE`` operation.
+
+Archiving
+^^^^^^^^^
+
+.. _ARCHIVE_CREATE:
+
+.. code-block:: cmake
+
+ file(ARCHIVE_CREATE OUTPUT <archive>
+ PATHS <paths>...
+ [FORMAT <format>]
+ [COMPRESSION <compression> [COMPRESSION_LEVEL <compression-level>]]
+ [MTIME <mtime>]
+ [VERBOSE])
+
+.. versionadded:: 3.18
+
+Creates the specified ``<archive>`` file with the files and directories
+listed in ``<paths>``. Note that ``<paths>`` must list actual files or
+directories, wildcards are not supported.
+
+Use the ``FORMAT`` option to specify the archive format. Supported values
+for ``<format>`` are ``7zip``, ``gnutar``, ``pax``, ``paxr``, ``raw`` and
+``zip``. If ``FORMAT`` is not given, the default format is ``paxr``.
+
+Some archive formats allow the type of compression to be specified.
+The ``7zip`` and ``zip`` archive formats already imply a specific type of
+compression. The other formats use no compression by default, but can be
+directed to do so with the ``COMPRESSION`` option. Valid values for
+``<compression>`` are ``None``, ``BZip2``, ``GZip``, ``XZ``, and ``Zstd``.
+
+.. versionadded:: 3.19
+ The compression level can be specified with the ``COMPRESSION_LEVEL`` option.
+ The ``<compression-level>`` should be between 0-9, with the default being 0.
+ The ``COMPRESSION`` option must be present when ``COMPRESSION_LEVEL`` is given.
+
+.. note::
+ With ``FORMAT`` set to ``raw`` only one file will be compressed with the
+ compression type specified by ``COMPRESSION``.
+
+The ``VERBOSE`` option enables verbose output for the archive operation.
+
+To specify the modification time recorded in tarball entries, use
+the ``MTIME`` option.
+
+.. _ARCHIVE_EXTRACT:
+
+.. code-block:: cmake
+
+ file(ARCHIVE_EXTRACT INPUT <archive>
+ [DESTINATION <dir>]
+ [PATTERNS <patterns>...]
+ [LIST_ONLY]
+ [VERBOSE])
+
+.. versionadded:: 3.18
+
+Extracts or lists the content of the specified ``<archive>``.
+
+The directory where the content of the archive will be extracted to can
+be specified using the ``DESTINATION`` option. If the directory does not
+exist, it will be created. If ``DESTINATION`` is not given, the current
+binary directory will be used.
+
+If required, you may select which files and directories to list or extract
+from the archive using the specified ``<patterns>``. Wildcards are supported.
+If the ``PATTERNS`` option is not given, the entire archive will be listed or
+extracted.
+
+``LIST_ONLY`` will list the files in the archive rather than extract them.
+
+With ``VERBOSE``, the command will produce verbose output.
diff --git a/Help/command/find_file.rst b/Help/command/find_file.rst
new file mode 100644
index 0000000..39dfb85
--- /dev/null
+++ b/Help/command/find_file.rst
@@ -0,0 +1,37 @@
+find_file
+---------
+
+.. |FIND_XXX| replace:: find_file
+.. |NAMES| replace:: NAMES name1 [name2 ...]
+.. |SEARCH_XXX| replace:: full path to a file
+.. |SEARCH_XXX_DESC| replace:: full path to named file
+.. |prefix_XXX_SUBDIR| replace:: ``<prefix>/include``
+.. |entry_XXX_SUBDIR| replace:: ``<entry>/include``
+
+.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX| replace::
+ ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE`
+ is set, and |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR|
+.. |CMAKE_PREFIX_PATH_XXX| replace::
+ ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE`
+ is set, and |CMAKE_PREFIX_PATH_XXX_SUBDIR|
+.. |CMAKE_XXX_PATH| replace:: :variable:`CMAKE_INCLUDE_PATH`
+.. |CMAKE_XXX_MAC_PATH| replace:: :variable:`CMAKE_FRAMEWORK_PATH`
+
+.. |SYSTEM_ENVIRONMENT_PATH_XXX| replace:: The directories in ``INCLUDE``
+ and ``PATH``.
+.. |SYSTEM_ENVIRONMENT_PATH_WINDOWS_XXX| replace:: On Windows hosts:
+ ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE`
+ is set, and |SYSTEM_ENVIRONMENT_PREFIX_PATH_XXX_SUBDIR|.
+
+.. |CMAKE_SYSTEM_PREFIX_PATH_XXX| replace::
+ ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE`
+ is set, and |CMAKE_SYSTEM_PREFIX_PATH_XXX_SUBDIR|
+.. |CMAKE_SYSTEM_XXX_PATH| replace::
+ :variable:`CMAKE_SYSTEM_INCLUDE_PATH`
+.. |CMAKE_SYSTEM_XXX_MAC_PATH| replace::
+ :variable:`CMAKE_SYSTEM_FRAMEWORK_PATH`
+
+.. |CMAKE_FIND_ROOT_PATH_MODE_XXX| replace::
+ :variable:`CMAKE_FIND_ROOT_PATH_MODE_INCLUDE`
+
+.. include:: FIND_XXX.txt
diff --git a/Help/command/find_library.rst b/Help/command/find_library.rst
new file mode 100644
index 0000000..ab957ce
--- /dev/null
+++ b/Help/command/find_library.rst
@@ -0,0 +1,82 @@
+find_library
+------------
+
+.. |FIND_XXX| replace:: find_library
+.. |NAMES| replace:: NAMES name1 [name2 ...] [NAMES_PER_DIR]
+.. |SEARCH_XXX| replace:: library
+.. |SEARCH_XXX_DESC| replace:: library
+.. |prefix_XXX_SUBDIR| replace:: ``<prefix>/lib``
+.. |entry_XXX_SUBDIR| replace:: ``<entry>/lib``
+
+.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX| replace::
+ ``<prefix>/lib/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE` is set,
+ and |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR|
+.. |CMAKE_PREFIX_PATH_XXX| replace::
+ ``<prefix>/lib/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE` is set,
+ and |CMAKE_PREFIX_PATH_XXX_SUBDIR|
+.. |CMAKE_XXX_PATH| replace:: :variable:`CMAKE_LIBRARY_PATH`
+.. |CMAKE_XXX_MAC_PATH| replace:: :variable:`CMAKE_FRAMEWORK_PATH`
+
+.. |SYSTEM_ENVIRONMENT_PATH_XXX| replace:: The directories in ``LIB``
+ and ``PATH``.
+.. |SYSTEM_ENVIRONMENT_PATH_WINDOWS_XXX| replace:: On Windows hosts:
+ ``<prefix>/lib/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE`
+ is set, and |SYSTEM_ENVIRONMENT_PREFIX_PATH_XXX_SUBDIR|.
+
+.. |CMAKE_SYSTEM_PREFIX_PATH_XXX| replace::
+ ``<prefix>/lib/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE` is set,
+ and |CMAKE_SYSTEM_PREFIX_PATH_XXX_SUBDIR|
+.. |CMAKE_SYSTEM_XXX_PATH| replace::
+ :variable:`CMAKE_SYSTEM_LIBRARY_PATH`
+.. |CMAKE_SYSTEM_XXX_MAC_PATH| replace::
+ :variable:`CMAKE_SYSTEM_FRAMEWORK_PATH`
+
+.. |CMAKE_FIND_ROOT_PATH_MODE_XXX| replace::
+ :variable:`CMAKE_FIND_ROOT_PATH_MODE_LIBRARY`
+
+.. include:: FIND_XXX.txt
+
+When more than one value is given to the ``NAMES`` option this command by
+default will consider one name at a time and search every directory
+for it. The ``NAMES_PER_DIR`` option tells this command to consider one
+directory at a time and search for all names in it.
+
+Each library name given to the ``NAMES`` option is first considered
+as a library file name and then considered with platform-specific
+prefixes (e.g. ``lib``) and suffixes (e.g. ``.so``). Therefore one
+may specify library file names such as ``libfoo.a`` directly.
+This can be used to locate static libraries on UNIX-like systems.
+
+If the library found is a framework, then ``<VAR>`` will be set to the full
+path to the framework ``<fullPath>/A.framework``. When a full path to a
+framework is used as a library, CMake will use a ``-framework A``, and a
+``-F<fullPath>`` to link the framework to the target.
+
+If the :variable:`CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX` variable is set all
+search paths will be tested as normal, with the suffix appended, and with
+all matches of ``lib/`` replaced with
+``lib${CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX}/``. This variable overrides
+the :prop_gbl:`FIND_LIBRARY_USE_LIB32_PATHS`,
+:prop_gbl:`FIND_LIBRARY_USE_LIBX32_PATHS`,
+and :prop_gbl:`FIND_LIBRARY_USE_LIB64_PATHS` global properties.
+
+If the :prop_gbl:`FIND_LIBRARY_USE_LIB32_PATHS` global property is set
+all search paths will be tested as normal, with ``32/`` appended, and
+with all matches of ``lib/`` replaced with ``lib32/``. This property is
+automatically set for the platforms that are known to need it if at
+least one of the languages supported by the :command:`project` command
+is enabled.
+
+If the :prop_gbl:`FIND_LIBRARY_USE_LIBX32_PATHS` global property is set
+all search paths will be tested as normal, with ``x32/`` appended, and
+with all matches of ``lib/`` replaced with ``libx32/``. This property is
+automatically set for the platforms that are known to need it if at
+least one of the languages supported by the :command:`project` command
+is enabled.
+
+If the :prop_gbl:`FIND_LIBRARY_USE_LIB64_PATHS` global property is set
+all search paths will be tested as normal, with ``64/`` appended, and
+with all matches of ``lib/`` replaced with ``lib64/``. This property is
+automatically set for the platforms that are known to need it if at
+least one of the languages supported by the :command:`project` command
+is enabled.
diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst
new file mode 100644
index 0000000..3dfd62f
--- /dev/null
+++ b/Help/command/find_package.rst
@@ -0,0 +1,540 @@
+find_package
+------------
+
+.. only:: html
+
+ .. contents::
+
+Find an external project, and load its settings.
+
+.. _`basic signature`:
+
+Basic Signature and Module Mode
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
+ [REQUIRED] [[COMPONENTS] [components...]]
+ [OPTIONAL_COMPONENTS components...]
+ [NO_POLICY_SCOPE])
+
+Finds and loads settings from an external project. ``<PackageName>_FOUND``
+will be set to indicate whether the package was found. When the
+package is found package-specific information is provided through
+variables and :ref:`Imported Targets` documented by the package itself. The
+``QUIET`` option disables informational messages, including those indicating
+that the package cannot be found if it is not ``REQUIRED``. The ``REQUIRED``
+option stops processing with an error message if the package cannot be found.
+
+A package-specific list of required components may be listed after the
+``COMPONENTS`` option (or after the ``REQUIRED`` option if present).
+Additional optional components may be listed after
+``OPTIONAL_COMPONENTS``. Available components and their influence on
+whether a package is considered to be found are defined by the target
+package.
+
+.. _FIND_PACKAGE_VERSION_FORMAT:
+
+The ``[version]`` argument requests a version with which the package found
+should be compatible. There are two possible forms in which it may be
+specified:
+
+ * A single version with the format ``major[.minor[.patch[.tweak]]]``.
+ * A version range with the format ``versionMin...[<]versionMax`` where
+ ``versionMin`` and ``versionMax`` have the same format as the single
+ version. By default, both end points are included. By specifying ``<``,
+ the upper end point will be excluded. Version ranges are only supported
+ with CMake 3.19 or later.
+
+The ``EXACT`` option requests that the version be matched exactly. This option
+is incompatible with the specification of a version range.
+
+If no ``[version]`` and/or component list is given to a recursive invocation
+inside a find-module, the corresponding arguments are forwarded
+automatically from the outer call (including the ``EXACT`` flag for
+``[version]``). Version support is currently provided only on a
+package-by-package basis (see the `Version Selection`_ section below).
+When a version range is specified but the package is only designed to expect
+a single version, the package will ignore the upper end point of the range and
+only take the single version at the lower end of the range into account.
+
+See the :command:`cmake_policy` command documentation for discussion
+of the ``NO_POLICY_SCOPE`` option.
+
+The command has two modes by which it searches for packages: "Module"
+mode and "Config" mode. The above signature selects Module mode.
+If no module is found the command falls back to Config mode, described
+below. This fall back is disabled if the ``MODULE`` option is given.
+
+In Module mode, CMake searches for a file called ``Find<PackageName>.cmake``.
+The file is first searched in the :variable:`CMAKE_MODULE_PATH`,
+then among the :ref:`Find Modules` provided by the CMake installation.
+If the file is found, it is read and processed by CMake. It is responsible
+for finding the package, checking the version, and producing any needed
+messages. Some find-modules provide limited or no support for versioning;
+check the module documentation.
+
+If the ``MODULE`` option is not specified in the above signature,
+CMake first searches for the package using Module mode. Then, if the
+package is not found, it searches again using Config mode. A user
+may set the variable :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG` to
+``TRUE`` to direct CMake first search using Config mode before falling
+back to Module mode.
+
+Full Signature and Config Mode
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+User code should generally look for packages using the above `basic
+signature`_. The remainder of this command documentation specifies the
+full command signature and details of the search process. Project
+maintainers wishing to provide a package to be found by this command
+are encouraged to read on.
+
+The complete Config mode command signature is
+
+.. code-block:: cmake
+
+ find_package(<PackageName> [version] [EXACT] [QUIET]
+ [REQUIRED] [[COMPONENTS] [components...]]
+ [OPTIONAL_COMPONENTS components...]
+ [CONFIG|NO_MODULE]
+ [NO_POLICY_SCOPE]
+ [NAMES name1 [name2 ...]]
+ [CONFIGS config1 [config2 ...]]
+ [HINTS path1 [path2 ... ]]
+ [PATHS path1 [path2 ... ]]
+ [PATH_SUFFIXES suffix1 [suffix2 ...]]
+ [NO_DEFAULT_PATH]
+ [NO_PACKAGE_ROOT_PATH]
+ [NO_CMAKE_PATH]
+ [NO_CMAKE_ENVIRONMENT_PATH]
+ [NO_SYSTEM_ENVIRONMENT_PATH]
+ [NO_CMAKE_PACKAGE_REGISTRY]
+ [NO_CMAKE_BUILDS_PATH] # Deprecated; does nothing.
+ [NO_CMAKE_SYSTEM_PATH]
+ [NO_CMAKE_SYSTEM_PACKAGE_REGISTRY]
+ [CMAKE_FIND_ROOT_PATH_BOTH |
+ ONLY_CMAKE_FIND_ROOT_PATH |
+ NO_CMAKE_FIND_ROOT_PATH])
+
+The ``CONFIG`` option, the synonymous ``NO_MODULE`` option, or the use
+of options not specified in the `basic signature`_ all enforce pure Config
+mode. In pure Config mode, the command skips Module mode search and
+proceeds at once with Config mode search.
+
+Config mode search attempts to locate a configuration file provided by the
+package to be found. A cache entry called ``<PackageName>_DIR`` is created to
+hold the directory containing the file. By default the command
+searches for a package with the name ``<PackageName>``. If the ``NAMES`` option
+is given the names following it are used instead of ``<PackageName>``.
+The command searches for a file called ``<PackageName>Config.cmake`` or
+``<lower-case-package-name>-config.cmake`` for each name specified.
+A replacement set of possible configuration file names may be given
+using the ``CONFIGS`` option. The search procedure is specified below.
+Once found, the configuration file is read and processed by CMake.
+Since the file is provided by the package it already knows the
+location of package contents. The full path to the configuration file
+is stored in the cmake variable ``<PackageName>_CONFIG``.
+
+All configuration files which have been considered by CMake while
+searching for an installation of the package with an appropriate
+version are stored in the cmake variable ``<PackageName>_CONSIDERED_CONFIGS``,
+the associated versions in ``<PackageName>_CONSIDERED_VERSIONS``.
+
+If the package configuration file cannot be found CMake will generate
+an error describing the problem unless the ``QUIET`` argument is
+specified. If ``REQUIRED`` is specified and the package is not found a
+fatal error is generated and the configure step stops executing. If
+``<PackageName>_DIR`` has been set to a directory not containing a
+configuration file CMake will ignore it and search from scratch.
+
+Package maintainers providing CMake package configuration files are
+encouraged to name and install them such that the `Search Procedure`_
+outlined below will find them without requiring use of additional options.
+
+Version Selection
+^^^^^^^^^^^^^^^^^
+
+When the ``[version]`` argument is given, Config mode will only find a
+version of the package that claims compatibility with the requested
+version (see :ref:`format specification <FIND_PACKAGE_VERSION_FORMAT>`). If the
+``EXACT`` option is given, only a version of the package claiming an exact match
+of the requested version may be found. CMake does not establish any
+convention for the meaning of version numbers. Package version
+numbers are checked by "version" files provided by the packages
+themselves. For a candidate package configuration file
+``<config-file>.cmake`` the corresponding version file is located next
+to it and named either ``<config-file>-version.cmake`` or
+``<config-file>Version.cmake``. If no such version file is available
+then the configuration file is assumed to not be compatible with any
+requested version. A basic version file containing generic version
+matching code can be created using the
+:module:`CMakePackageConfigHelpers` module. When a version file
+is found it is loaded to check the requested version number. The
+version file is loaded in a nested scope in which the following
+variables have been defined:
+
+``PACKAGE_FIND_NAME``
+ The ``<PackageName>``
+``PACKAGE_FIND_VERSION``
+ Full requested version string
+``PACKAGE_FIND_VERSION_MAJOR``
+ Major version if requested, else 0
+``PACKAGE_FIND_VERSION_MINOR``
+ Minor version if requested, else 0
+``PACKAGE_FIND_VERSION_PATCH``
+ Patch version if requested, else 0
+``PACKAGE_FIND_VERSION_TWEAK``
+ Tweak version if requested, else 0
+``PACKAGE_FIND_VERSION_COUNT``
+ Number of version components, 0 to 4
+
+When a version range is specified, the above version variables will hold
+values based on the lower end of the version range. This is to preserve
+compatibility with packages that have not been implemented to expect version
+ranges. In addition, the version range will be described by the following
+variables:
+
+``PACKAGE_FIND_VERSION_RANGE``
+ Full requested version range string
+``PACKAGE_FIND_VERSION_RANGE_MIN``
+ This specifies whether the lower end point of the version range should be
+ included or excluded. Currently, the only supported value for this variable
+ is ``INCLUDE``.
+``PACKAGE_FIND_VERSION_RANGE_MAX``
+ This specifies whether the upper end point of the version range should be
+ included or excluded. The supported values for this variable are
+ ``INCLUDE`` and ``EXCLUDE``.
+
+``PACKAGE_FIND_VERSION_MIN``
+ Full requested version string of the lower end point of the range
+``PACKAGE_FIND_VERSION_MIN_MAJOR``
+ Major version of the lower end point if requested, else 0
+``PACKAGE_FIND_VERSION_MIN_MINOR``
+ Minor version of the lower end point if requested, else 0
+``PACKAGE_FIND_VERSION_MIN_PATCH``
+ Patch version of the lower end point if requested, else 0
+``PACKAGE_FIND_VERSION_MIN_TWEAK``
+ Tweak version of the lower end point if requested, else 0
+``PACKAGE_FIND_VERSION_MIN_COUNT``
+ Number of version components of the lower end point, 0 to 4
+
+``PACKAGE_FIND_VERSION_MAX``
+ Full requested version string of the upper end point of the range
+``PACKAGE_FIND_VERSION_MAX_MAJOR``
+ Major version of the upper end point if requested, else 0
+``PACKAGE_FIND_VERSION_MAX_MINOR``
+ Minor version of the upper end point if requested, else 0
+``PACKAGE_FIND_VERSION_MAX_PATCH``
+ Patch version of the upper end point if requested, else 0
+``PACKAGE_FIND_VERSION_MAX_TWEAK``
+ Tweak version of the upper end point if requested, else 0
+``PACKAGE_FIND_VERSION_MAX_COUNT``
+ Number of version components of the upper end point, 0 to 4
+
+Regardless of whether a single version or a version range is specified, the
+variable ``PACKAGE_FIND_VERSION_COMPLETE`` will be defined and will hold
+the full requested version string as specified.
+
+The version file checks whether it satisfies the requested version and
+sets these variables:
+
+``PACKAGE_VERSION``
+ Full provided version string
+``PACKAGE_VERSION_EXACT``
+ True if version is exact match
+``PACKAGE_VERSION_COMPATIBLE``
+ True if version is compatible
+``PACKAGE_VERSION_UNSUITABLE``
+ True if unsuitable as any version
+
+These variables are checked by the ``find_package`` command to determine
+whether the configuration file provides an acceptable version. They
+are not available after the ``find_package`` call returns. If the version
+is acceptable the following variables are set:
+
+``<PackageName>_VERSION``
+ Full provided version string
+``<PackageName>_VERSION_MAJOR``
+ Major version if provided, else 0
+``<PackageName>_VERSION_MINOR``
+ Minor version if provided, else 0
+``<PackageName>_VERSION_PATCH``
+ Patch version if provided, else 0
+``<PackageName>_VERSION_TWEAK``
+ Tweak version if provided, else 0
+``<PackageName>_VERSION_COUNT``
+ Number of version components, 0 to 4
+
+and the corresponding package configuration file is loaded.
+When multiple package configuration files are available whose version files
+claim compatibility with the version requested it is unspecified which
+one is chosen: unless the variable :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER`
+is set no attempt is made to choose a highest or closest version number.
+
+To control the order in which ``find_package`` checks for compatibility use
+the two variables :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` and
+:variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION`.
+For instance in order to select the highest version one can set
+
+.. code-block:: cmake
+
+ SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
+ SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
+
+before calling ``find_package``.
+
+Search Procedure
+^^^^^^^^^^^^^^^^
+
+CMake constructs a set of possible installation prefixes for the
+package. Under each prefix several directories are searched for a
+configuration file. The tables below show the directories searched.
+Each entry is meant for installation trees following Windows (``W``), UNIX
+(``U``), or Apple (``A``) conventions::
+
+ <prefix>/ (W)
+ <prefix>/(cmake|CMake)/ (W)
+ <prefix>/<name>*/ (W)
+ <prefix>/<name>*/(cmake|CMake)/ (W)
+ <prefix>/(lib/<arch>|lib*|share)/cmake/<name>*/ (U)
+ <prefix>/(lib/<arch>|lib*|share)/<name>*/ (U)
+ <prefix>/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/ (U)
+ <prefix>/<name>*/(lib/<arch>|lib*|share)/cmake/<name>*/ (W/U)
+ <prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/ (W/U)
+ <prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/ (W/U)
+
+On systems supporting macOS :prop_tgt:`FRAMEWORK` and :prop_tgt:`BUNDLE`, the
+following directories are searched for Frameworks or Application Bundles
+containing a configuration file::
+
+ <prefix>/<name>.framework/Resources/ (A)
+ <prefix>/<name>.framework/Resources/CMake/ (A)
+ <prefix>/<name>.framework/Versions/*/Resources/ (A)
+ <prefix>/<name>.framework/Versions/*/Resources/CMake/ (A)
+ <prefix>/<name>.app/Contents/Resources/ (A)
+ <prefix>/<name>.app/Contents/Resources/CMake/ (A)
+
+In all cases the ``<name>`` is treated as case-insensitive and corresponds
+to any of the names specified (``<PackageName>`` or names given by ``NAMES``).
+
+Paths with ``lib/<arch>`` are enabled if the
+:variable:`CMAKE_LIBRARY_ARCHITECTURE` variable is set. ``lib*`` includes one
+or more of the values ``lib64``, ``lib32``, ``libx32`` or ``lib`` (searched in
+that order).
+
+* Paths with ``lib64`` are searched on 64 bit platforms if the
+ :prop_gbl:`FIND_LIBRARY_USE_LIB64_PATHS` property is set to ``TRUE``.
+* Paths with ``lib32`` are searched on 32 bit platforms if the
+ :prop_gbl:`FIND_LIBRARY_USE_LIB32_PATHS` property is set to ``TRUE``.
+* Paths with ``libx32`` are searched on platforms using the x32 ABI
+ if the :prop_gbl:`FIND_LIBRARY_USE_LIBX32_PATHS` property is set to ``TRUE``.
+* The ``lib`` path is always searched.
+
+If ``PATH_SUFFIXES`` is specified, the suffixes are appended to each
+(``W``) or (``U``) directory entry one-by-one.
+
+This set of directories is intended to work in cooperation with
+projects that provide configuration files in their installation trees.
+Directories above marked with (``W``) are intended for installations on
+Windows where the prefix may point at the top of an application's
+installation directory. Those marked with (``U``) are intended for
+installations on UNIX platforms where the prefix is shared by multiple
+packages. This is merely a convention, so all (``W``) and (``U``) directories
+are still searched on all platforms. Directories marked with (``A``) are
+intended for installations on Apple platforms. The
+:variable:`CMAKE_FIND_FRAMEWORK` and :variable:`CMAKE_FIND_APPBUNDLE`
+variables determine the order of preference.
+
+The set of installation prefixes is constructed using the following
+steps. If ``NO_DEFAULT_PATH`` is specified all ``NO_*`` options are
+enabled.
+
+1. .. versionadded:: 3.12
+ Search paths specified in the :variable:`<PackageName>_ROOT` CMake
+ variable and the :envvar:`<PackageName>_ROOT` environment variable,
+ where ``<PackageName>`` is the package to be found.
+ The package root variables are maintained as a stack so if
+ called from within a find module, root paths from the parent's find
+ module will also be searched after paths for the current package.
+ This can be skipped if ``NO_PACKAGE_ROOT_PATH`` is passed or by setting
+ the :variable:`CMAKE_FIND_USE_PACKAGE_ROOT_PATH` to ``FALSE``.
+ See policy :policy:`CMP0074`.
+
+2. Search paths specified in cmake-specific cache variables. These
+ are intended to be used on the command line with a ``-DVAR=value``.
+ The values are interpreted as :ref:`semicolon-separated lists <CMake Language Lists>`.
+ This can be skipped if ``NO_CMAKE_PATH`` is passed or by setting the
+ :variable:`CMAKE_FIND_USE_CMAKE_PATH` to ``FALSE``:
+
+ * :variable:`CMAKE_PREFIX_PATH`
+ * :variable:`CMAKE_FRAMEWORK_PATH`
+ * :variable:`CMAKE_APPBUNDLE_PATH`
+
+3. Search paths specified in cmake-specific environment variables.
+ These are intended to be set in the user's shell configuration,
+ and therefore use the host's native path separator
+ (``;`` on Windows and ``:`` on UNIX).
+ This can be skipped if ``NO_CMAKE_ENVIRONMENT_PATH`` is passed or by setting
+ the :variable:`CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH` to ``FALSE``:
+
+ * ``<PackageName>_DIR``
+ * :envvar:`CMAKE_PREFIX_PATH`
+ * ``CMAKE_FRAMEWORK_PATH``
+ * ``CMAKE_APPBUNDLE_PATH``
+
+4. Search paths specified by the ``HINTS`` option. These should be paths
+ computed by system introspection, such as a hint provided by the
+ location of another item already found. Hard-coded guesses should
+ be specified with the ``PATHS`` option.
+
+5. Search the standard system environment variables. This can be
+ skipped if ``NO_SYSTEM_ENVIRONMENT_PATH`` is passed or by setting the
+ :variable:`CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH` to ``FALSE``. Path entries
+ ending in ``/bin`` or ``/sbin`` are automatically converted to their
+ parent directories:
+
+ * ``PATH``
+
+6. Search paths stored in the CMake :ref:`User Package Registry`.
+ This can be skipped if ``NO_CMAKE_PACKAGE_REGISTRY`` is passed or by
+ setting the variable :variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY`
+ to ``FALSE`` or the deprecated variable
+ :variable:`CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY` to ``TRUE``.
+
+ See the :manual:`cmake-packages(7)` manual for details on the user
+ package registry.
+
+7. Search cmake variables defined in the Platform files for the
+ current system. This can be skipped if ``NO_CMAKE_SYSTEM_PATH`` is
+ passed or by setting the :variable:`CMAKE_FIND_USE_CMAKE_SYSTEM_PATH`
+ to ``FALSE``:
+
+ * :variable:`CMAKE_SYSTEM_PREFIX_PATH`
+ * :variable:`CMAKE_SYSTEM_FRAMEWORK_PATH`
+ * :variable:`CMAKE_SYSTEM_APPBUNDLE_PATH`
+
+ The platform paths that these variables contain are locations that
+ typically include installed software. An example being ``/usr/local`` for
+ UNIX based platforms.
+
+8. Search paths stored in the CMake :ref:`System Package Registry`.
+ This can be skipped if ``NO_CMAKE_SYSTEM_PACKAGE_REGISTRY`` is passed
+ or by setting the :variable:`CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY`
+ variable to ``FALSE`` or the deprecated variable
+ :variable:`CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY` to ``TRUE``.
+
+ See the :manual:`cmake-packages(7)` manual for details on the system
+ package registry.
+
+9. Search paths specified by the ``PATHS`` option. These are typically
+ hard-coded guesses.
+
+.. versionadded:: 3.16
+ Added the ``CMAKE_FIND_USE_<CATEGORY>_PATH`` variables to globally disable
+ various search locations.
+
+.. |FIND_XXX| replace:: find_package
+.. |FIND_ARGS_XXX| replace:: <PackageName>
+.. |CMAKE_FIND_ROOT_PATH_MODE_XXX| replace::
+ :variable:`CMAKE_FIND_ROOT_PATH_MODE_PACKAGE`
+
+.. include:: FIND_XXX_ROOT.txt
+.. include:: FIND_XXX_ORDER.txt
+
+By default the value stored in the result variable will be the path at
+which the file is found. The :variable:`CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS`
+variable may be set to ``TRUE`` before calling ``find_package`` in order
+to resolve symbolic links and store the real path to the file.
+
+Every non-REQUIRED ``find_package`` call can be disabled by setting the
+:variable:`CMAKE_DISABLE_FIND_PACKAGE_<PackageName>` variable to ``TRUE``.
+
+Package File Interface Variables
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When loading a find module or package configuration file ``find_package``
+defines variables to provide information about the call arguments (and
+restores their original state before returning):
+
+``CMAKE_FIND_PACKAGE_NAME``
+ The ``<PackageName>`` which is searched for
+``<PackageName>_FIND_REQUIRED``
+ True if ``REQUIRED`` option was given
+``<PackageName>_FIND_QUIETLY``
+ True if ``QUIET`` option was given
+``<PackageName>_FIND_VERSION``
+ Full requested version string
+``<PackageName>_FIND_VERSION_MAJOR``
+ Major version if requested, else 0
+``<PackageName>_FIND_VERSION_MINOR``
+ Minor version if requested, else 0
+``<PackageName>_FIND_VERSION_PATCH``
+ Patch version if requested, else 0
+``<PackageName>_FIND_VERSION_TWEAK``
+ Tweak version if requested, else 0
+``<PackageName>_FIND_VERSION_COUNT``
+ Number of version components, 0 to 4
+``<PackageName>_FIND_VERSION_EXACT``
+ True if ``EXACT`` option was given
+``<PackageName>_FIND_COMPONENTS``
+ List of requested components
+``<PackageName>_FIND_REQUIRED_<c>``
+ True if component ``<c>`` is required,
+ false if component ``<c>`` is optional
+
+When a version range is specified, the above version variables will hold
+values based on the lower end of the version range. This is to preserve
+compatibility with packages that have not been implemented to expect version
+ranges. In addition, the version range will be described by the following
+variables:
+
+``<PackageName>_FIND_VERSION_RANGE``
+ Full requested version range string
+``<PackageName>_FIND_VERSION_RANGE_MIN``
+ This specifies whether the lower end point of the version range is
+ included or excluded. Currently, ``INCLUDE`` is the only supported value.
+``<PackageName>_FIND_VERSION_RANGE_MAX``
+ This specifies whether the upper end point of the version range is
+ included or excluded. The possible values for this variable are
+ ``INCLUDE`` or ``EXCLUDE``.
+
+``<PackageName>_FIND_VERSION_MIN``
+ Full requested version string of the lower end point of the range
+``<PackageName>_FIND_VERSION_MIN_MAJOR``
+ Major version of the lower end point if requested, else 0
+``<PackageName>_FIND_VERSION_MIN_MINOR``
+ Minor version of the lower end point if requested, else 0
+``<PackageName>_FIND_VERSION_MIN_PATCH``
+ Patch version of the lower end point if requested, else 0
+``<PackageName>_FIND_VERSION_MIN_TWEAK``
+ Tweak version of the lower end point if requested, else 0
+``<PackageName>_FIND_VERSION_MIN_COUNT``
+ Number of version components of the lower end point, 0 to 4
+
+``<PackageName>_FIND_VERSION_MAX``
+ Full requested version string of the upper end point of the range
+``<PackageName>_FIND_VERSION_MAX_MAJOR``
+ Major version of the upper end point if requested, else 0
+``<PackageName>_FIND_VERSION_MAX_MINOR``
+ Minor version of the upper end point if requested, else 0
+``<PackageName>_FIND_VERSION_MAX_PATCH``
+ Patch version of the upper end point if requested, else 0
+``<PackageName>_FIND_VERSION_MAX_TWEAK``
+ Tweak version of the upper end point if requested, else 0
+``<PackageName>_FIND_VERSION_MAX_COUNT``
+ Number of version components of the upper end point, 0 to 4
+
+Regardless of whether a single version or a version range is specified, the
+variable ``<PackageName>_FIND_VERSION_COMPLETE`` will be defined and will hold
+the full requested version string as specified.
+
+In Module mode the loaded find module is responsible to honor the
+request detailed by these variables; see the find module for details.
+In Config mode ``find_package`` handles ``REQUIRED``, ``QUIET``, and
+``[version]`` options automatically but leaves it to the package
+configuration file to handle components in a way that makes sense
+for the package. The package configuration file may set
+``<PackageName>_FOUND`` to false to tell ``find_package`` that component
+requirements are not satisfied.
diff --git a/Help/command/find_path.rst b/Help/command/find_path.rst
new file mode 100644
index 0000000..ec66771
--- /dev/null
+++ b/Help/command/find_path.rst
@@ -0,0 +1,42 @@
+find_path
+---------
+
+.. |FIND_XXX| replace:: find_path
+.. |NAMES| replace:: NAMES name1 [name2 ...]
+.. |SEARCH_XXX| replace:: file in a directory
+.. |SEARCH_XXX_DESC| replace:: directory containing the named file
+.. |prefix_XXX_SUBDIR| replace:: ``<prefix>/include``
+.. |entry_XXX_SUBDIR| replace:: ``<entry>/include``
+
+.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX| replace::
+ ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE`
+ is set, and |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR|
+.. |CMAKE_PREFIX_PATH_XXX| replace::
+ ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE`
+ is set, and |CMAKE_PREFIX_PATH_XXX_SUBDIR|
+.. |CMAKE_XXX_PATH| replace:: :variable:`CMAKE_INCLUDE_PATH`
+.. |CMAKE_XXX_MAC_PATH| replace:: :variable:`CMAKE_FRAMEWORK_PATH`
+
+.. |SYSTEM_ENVIRONMENT_PATH_XXX| replace:: The directories in ``INCLUDE``
+ and ``PATH``.
+.. |SYSTEM_ENVIRONMENT_PATH_WINDOWS_XXX| replace:: On Windows hosts:
+ ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE`
+ is set, and |SYSTEM_ENVIRONMENT_PREFIX_PATH_XXX_SUBDIR|.
+
+.. |CMAKE_SYSTEM_PREFIX_PATH_XXX| replace::
+ ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE`
+ is set, and |CMAKE_SYSTEM_PREFIX_PATH_XXX_SUBDIR|
+.. |CMAKE_SYSTEM_XXX_PATH| replace::
+ :variable:`CMAKE_SYSTEM_INCLUDE_PATH`
+.. |CMAKE_SYSTEM_XXX_MAC_PATH| replace::
+ :variable:`CMAKE_SYSTEM_FRAMEWORK_PATH`
+
+.. |CMAKE_FIND_ROOT_PATH_MODE_XXX| replace::
+ :variable:`CMAKE_FIND_ROOT_PATH_MODE_INCLUDE`
+
+.. include:: FIND_XXX.txt
+
+When searching for frameworks, if the file is specified as ``A/b.h``, then
+the framework search will look for ``A.framework/Headers/b.h``. If that
+is found the path will be set to the path to the framework. CMake
+will convert this to the correct ``-F`` option to include the file.
diff --git a/Help/command/find_program.rst b/Help/command/find_program.rst
new file mode 100644
index 0000000..e2ff693
--- /dev/null
+++ b/Help/command/find_program.rst
@@ -0,0 +1,36 @@
+find_program
+------------
+
+.. |FIND_XXX| replace:: find_program
+.. |NAMES| replace:: NAMES name1 [name2 ...] [NAMES_PER_DIR]
+.. |SEARCH_XXX| replace:: program
+.. |SEARCH_XXX_DESC| replace:: program
+.. |prefix_XXX_SUBDIR| replace:: ``<prefix>/[s]bin``
+.. |entry_XXX_SUBDIR| replace:: ``<entry>/[s]bin``
+
+.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX| replace::
+ |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR|
+.. |CMAKE_PREFIX_PATH_XXX| replace::
+ |CMAKE_PREFIX_PATH_XXX_SUBDIR|
+.. |CMAKE_XXX_PATH| replace:: :variable:`CMAKE_PROGRAM_PATH`
+.. |CMAKE_XXX_MAC_PATH| replace:: :variable:`CMAKE_APPBUNDLE_PATH`
+
+.. |SYSTEM_ENVIRONMENT_PATH_XXX| replace:: The directories in ``PATH`` itself.
+.. |SYSTEM_ENVIRONMENT_PATH_WINDOWS_XXX| replace:: On Windows hosts no extra search paths are included
+
+.. |CMAKE_SYSTEM_PREFIX_PATH_XXX| replace::
+ |CMAKE_SYSTEM_PREFIX_PATH_XXX_SUBDIR|
+.. |CMAKE_SYSTEM_XXX_PATH| replace::
+ :variable:`CMAKE_SYSTEM_PROGRAM_PATH`
+.. |CMAKE_SYSTEM_XXX_MAC_PATH| replace::
+ :variable:`CMAKE_SYSTEM_APPBUNDLE_PATH`
+
+.. |CMAKE_FIND_ROOT_PATH_MODE_XXX| replace::
+ :variable:`CMAKE_FIND_ROOT_PATH_MODE_PROGRAM`
+
+.. include:: FIND_XXX.txt
+
+When more than one value is given to the ``NAMES`` option this command by
+default will consider one name at a time and search every directory
+for it. The ``NAMES_PER_DIR`` option tells this command to consider one
+directory at a time and search for all names in it.
diff --git a/Help/command/fltk_wrap_ui.rst b/Help/command/fltk_wrap_ui.rst
new file mode 100644
index 0000000..6675272
--- /dev/null
+++ b/Help/command/fltk_wrap_ui.rst
@@ -0,0 +1,14 @@
+fltk_wrap_ui
+------------
+
+Create FLTK user interfaces Wrappers.
+
+.. code-block:: cmake
+
+ fltk_wrap_ui(resultingLibraryName source1
+ source2 ... sourceN )
+
+Produce .h and .cxx files for all the .fl and .fld files listed. The
+resulting .h and .cxx files will be added to a variable named
+``resultingLibraryName_FLTK_UI_SRCS`` which should be added to your
+library.
diff --git a/Help/command/foreach.rst b/Help/command/foreach.rst
new file mode 100644
index 0000000..8de6deb
--- /dev/null
+++ b/Help/command/foreach.rst
@@ -0,0 +1,129 @@
+foreach
+-------
+
+Evaluate a group of commands for each value in a list.
+
+.. code-block:: cmake
+
+ foreach(<loop_var> <items>)
+ <commands>
+ endforeach()
+
+where ``<items>`` is a list of items that are separated by
+semicolon or whitespace.
+All commands between ``foreach`` and the matching ``endforeach`` are recorded
+without being invoked. Once the ``endforeach`` is evaluated, the recorded
+list of commands is invoked once for each item in ``<items>``.
+At the beginning of each iteration the variable ``loop_var`` will be set
+to the value of the current item.
+
+The commands :command:`break` and :command:`continue` provide means to
+escape from the normal control flow.
+
+Per legacy, the :command:`endforeach` command admits
+an optional ``<loop_var>`` argument.
+If used, it must be a verbatim
+repeat of the argument of the opening
+``foreach`` command.
+
+.. code-block:: cmake
+
+ foreach(<loop_var> RANGE <stop>)
+
+In this variant, ``foreach`` iterates over the numbers
+0, 1, ... up to (and including) the nonnegative integer ``<stop>``.
+
+.. code-block:: cmake
+
+ foreach(<loop_var> RANGE <start> <stop> [<step>])
+
+In this variant, ``foreach`` iterates over the numbers from
+``<start>`` up to at most ``<stop>`` in steps of ``<step>``.
+If ``<step>`` is not specified, then the step size is 1.
+The three arguments ``<start>`` ``<stop>`` ``<step>`` must
+all be nonnegative integers, and ``<stop>`` must not be
+smaller than ``<start>``; otherwise you enter the danger zone
+of undocumented behavior that may change in future releases.
+
+.. code-block:: cmake
+
+ foreach(<loop_var> IN [LISTS [<lists>]] [ITEMS [<items>]])
+
+In this variant, ``<lists>`` is a whitespace or semicolon
+separated list of list-valued variables. The ``foreach``
+command iterates over each item in each given list.
+The ``<items>`` following the ``ITEMS`` keyword are processed
+as in the first variant of the ``foreach`` command.
+The forms ``LISTS A`` and ``ITEMS ${A}`` are
+equivalent.
+
+The following example shows how the ``LISTS`` option is
+processed:
+
+.. code-block:: cmake
+
+ set(A 0;1)
+ set(B 2 3)
+ set(C "4 5")
+ set(D 6;7 8)
+ set(E "")
+ foreach(X IN LISTS A B C D E)
+ message(STATUS "X=${X}")
+ endforeach()
+
+yields
+::
+
+ -- X=0
+ -- X=1
+ -- X=2
+ -- X=3
+ -- X=4 5
+ -- X=6
+ -- X=7
+ -- X=8
+
+
+.. code-block:: cmake
+
+ foreach(<loop_var>... IN ZIP_LISTS <lists>)
+
+.. versionadded:: 3.17
+
+In this variant, ``<lists>`` is a whitespace or semicolon
+separated list of list-valued variables. The ``foreach``
+command iterates over each list simultaneously setting the
+iteration variables as follows:
+
+- if the only ``loop_var`` given, then it sets a series of
+ ``loop_var_N`` variables to the current item from the
+ corresponding list;
+- if multiple variable names passed, their count should match
+ the lists variables count;
+- if any of the lists are shorter, the corresponding iteration
+ variable is not defined for the current iteration.
+
+.. code-block:: cmake
+
+ list(APPEND English one two three four)
+ list(APPEND Bahasa satu dua tiga)
+
+ foreach(num IN ZIP_LISTS English Bahasa)
+ message(STATUS "num_0=${num_0}, num_1=${num_1}")
+ endforeach()
+
+ foreach(en ba IN ZIP_LISTS English Bahasa)
+ message(STATUS "en=${en}, ba=${ba}")
+ endforeach()
+
+yields
+::
+
+ -- num_0=one, num_1=satu
+ -- num_0=two, num_1=dua
+ -- num_0=three, num_1=tiga
+ -- num_0=four, num_1=
+ -- en=one, ba=satu
+ -- en=two, ba=dua
+ -- en=three, ba=tiga
+ -- en=four, ba=
diff --git a/Help/command/function.rst b/Help/command/function.rst
new file mode 100644
index 0000000..3d25aa4
--- /dev/null
+++ b/Help/command/function.rst
@@ -0,0 +1,75 @@
+function
+--------
+
+Start recording a function for later invocation as a command.
+
+.. code-block:: cmake
+
+ function(<name> [<arg1> ...])
+ <commands>
+ endfunction()
+
+Defines a function named ``<name>`` that takes arguments named
+``<arg1>``, ... The ``<commands>`` in the function definition
+are recorded; they are not executed until the function is invoked.
+
+Per legacy, the :command:`endfunction` command admits an optional
+``<name>`` argument. If used, it must be a verbatim repeat of the
+argument of the opening ``function`` command.
+
+A function opens a new scope: see :command:`set(var PARENT_SCOPE)` for
+details.
+
+See the :command:`cmake_policy()` command documentation for the behavior
+of policies inside functions.
+
+See the :command:`macro()` command documentation for differences
+between CMake functions and macros.
+
+Invocation
+^^^^^^^^^^
+
+The function invocation is case-insensitive. A function defined as
+
+.. code-block:: cmake
+
+ function(foo)
+ <commands>
+ endfunction()
+
+can be invoked through any of
+
+.. code-block:: cmake
+
+ foo()
+ Foo()
+ FOO()
+ cmake_language(CALL foo)
+
+and so on. However, it is strongly recommended to stay with the
+case chosen in the function definition. Typically functions use
+all-lowercase names.
+
+.. versionadded:: 3.18
+ The :command:`cmake_language(CALL ...)` command can also be used to
+ invoke the function.
+
+Arguments
+^^^^^^^^^
+
+When the function is invoked, the recorded ``<commands>`` are first
+modified by replacing formal parameters (``${arg1}``, ...) with the
+arguments passed, and then invoked as normal commands.
+
+In addition to referencing the formal parameters you can reference the
+``ARGC`` variable which will be set to the number of arguments passed
+into the function as well as ``ARGV0``, ``ARGV1``, ``ARGV2``, ... which
+will have the actual values of the arguments passed in. This facilitates
+creating functions with optional arguments.
+
+Furthermore, ``ARGV`` holds the list of all arguments given to the
+function and ``ARGN`` holds the list of arguments past the last expected
+argument. Referencing to ``ARGV#`` arguments beyond ``ARGC`` have
+undefined behavior. Checking that ``ARGC`` is greater than ``#`` is
+the only way to ensure that ``ARGV#`` was passed to the function as an
+extra argument.
diff --git a/Help/command/get_cmake_property.rst b/Help/command/get_cmake_property.rst
new file mode 100644
index 0000000..96764a3
--- /dev/null
+++ b/Help/command/get_cmake_property.rst
@@ -0,0 +1,20 @@
+get_cmake_property
+------------------
+
+Get a global property of the CMake instance.
+
+.. code-block:: cmake
+
+ get_cmake_property(<var> <property>)
+
+Gets a global property from the CMake instance. The value of
+the ``<property>`` is stored in the variable ``<var>``.
+If the property is not found, ``<var>`` will be set to ``NOTFOUND``.
+See the :manual:`cmake-properties(7)` manual for available properties.
+
+See also the :command:`get_property` command ``GLOBAL`` option.
+
+In addition to global properties, this command (for historical reasons)
+also supports the :prop_dir:`VARIABLES` and :prop_dir:`MACROS` directory
+properties. It also supports a special ``COMPONENTS`` global property that
+lists the components given to the :command:`install` command.
diff --git a/Help/command/get_directory_property.rst b/Help/command/get_directory_property.rst
new file mode 100644
index 0000000..0ccbfb0
--- /dev/null
+++ b/Help/command/get_directory_property.rst
@@ -0,0 +1,36 @@
+get_directory_property
+----------------------
+
+Get a property of ``DIRECTORY`` scope.
+
+.. code-block:: cmake
+
+ get_directory_property(<variable> [DIRECTORY <dir>] <prop-name>)
+
+Stores a property of directory scope in the named ``<variable>``.
+
+The ``DIRECTORY`` argument specifies another directory from which
+to retrieve the property value instead of the current directory.
+Relative paths are treated as relative to the
+current source directory. CMake must already know about the directory,
+either by having added it through a call to :command:`add_subdirectory`
+or being the top level directory.
+
+.. versionadded:: 3.19
+ ``<dir>`` may reference a binary directory.
+
+If the property is not defined for the nominated directory scope,
+an empty string is returned. In the case of ``INHERITED`` properties,
+if the property is not found for the nominated directory scope,
+the search will chain to a parent scope as described for the
+:command:`define_property` command.
+
+.. code-block:: cmake
+
+ get_directory_property(<variable> [DIRECTORY <dir>]
+ DEFINITION <var-name>)
+
+Get a variable definition from a directory. This form is useful to
+get a variable definition from another directory.
+
+See also the more general :command:`get_property` command.
diff --git a/Help/command/get_filename_component.rst b/Help/command/get_filename_component.rst
new file mode 100644
index 0000000..be9d00a
--- /dev/null
+++ b/Help/command/get_filename_component.rst
@@ -0,0 +1,65 @@
+get_filename_component
+----------------------
+
+Get a specific component of a full filename.
+
+.. versionchanged:: 3.19
+ This command been superseded by :command:`cmake_path` command, except
+ ``REALPATH`` now offered by :ref:`file(REAL_PATH) <REAL_PATH>` command and
+ ``PROGRAM`` now available in :command:`separate_arguments(PROGRAM)` command.
+
+.. code-block:: cmake
+
+ get_filename_component(<var> <FileName> <mode> [CACHE])
+
+Sets ``<var>`` to a component of ``<FileName>``, where ``<mode>`` is one of:
+
+::
+
+ DIRECTORY = Directory without file name
+ NAME = File name without directory
+ EXT = File name longest extension (.b.c from d/a.b.c)
+ NAME_WE = File name with neither the directory nor the longest extension
+ LAST_EXT = File name last extension (.c from d/a.b.c)
+ NAME_WLE = File name with neither the directory nor the last extension
+ PATH = Legacy alias for DIRECTORY (use for CMake <= 2.8.11)
+
+.. versionadded:: 3.14
+ Added the ``LAST_EXT`` and ``NAME_WLE`` modes.
+
+Paths are returned with forward slashes and have no trailing slashes.
+If the optional ``CACHE`` argument is specified, the result variable is
+added to the cache.
+
+.. code-block:: cmake
+
+ get_filename_component(<var> <FileName> <mode> [BASE_DIR <dir>] [CACHE])
+
+.. versionadded:: 3.4
+
+Sets ``<var>`` to the absolute path of ``<FileName>``, where ``<mode>`` is one
+of:
+
+::
+
+ ABSOLUTE = Full path to file
+ REALPATH = Full path to existing file with symlinks resolved
+
+If the provided ``<FileName>`` is a relative path, it is evaluated relative
+to the given base directory ``<dir>``. If no base directory is
+provided, the default base directory will be
+:variable:`CMAKE_CURRENT_SOURCE_DIR`.
+
+Paths are returned with forward slashes and have no trailing slashes. If the
+optional ``CACHE`` argument is specified, the result variable is added to the
+cache.
+
+.. code-block:: cmake
+
+ get_filename_component(<var> <FileName> PROGRAM [PROGRAM_ARGS <arg_var>] [CACHE])
+
+The program in ``<FileName>`` will be found in the system search path or
+left as a full path. If ``PROGRAM_ARGS`` is present with ``PROGRAM``, then
+any command-line arguments present in the ``<FileName>`` string are split
+from the program name and stored in ``<arg_var>``. This is used to
+separate a program name from its arguments in a command line string.
diff --git a/Help/command/get_property.rst b/Help/command/get_property.rst
new file mode 100644
index 0000000..f77d8af
--- /dev/null
+++ b/Help/command/get_property.rst
@@ -0,0 +1,101 @@
+get_property
+------------
+
+Get a property.
+
+.. code-block:: cmake
+
+ get_property(<variable>
+ <GLOBAL |
+ DIRECTORY [<dir>] |
+ TARGET <target> |
+ SOURCE <source> |
+ [DIRECTORY <dir> | TARGET_DIRECTORY <target>] |
+ INSTALL <file> |
+ TEST <test> |
+ CACHE <entry> |
+ VARIABLE >
+ PROPERTY <name>
+ [SET | DEFINED | BRIEF_DOCS | FULL_DOCS])
+
+Gets one property from one object in a scope.
+
+The first argument specifies the variable in which to store the result.
+The second argument determines the scope from which to get the property.
+It must be one of the following:
+
+``GLOBAL``
+ Scope is unique and does not accept a name.
+
+``DIRECTORY``
+ Scope defaults to the current directory but another
+ directory (already processed by CMake) may be named by the
+ full or relative path ``<dir>``.
+ Relative paths are treated as relative to the current source directory.
+ See also the :command:`get_directory_property` command.
+
+ .. versionadded:: 3.19
+ ``<dir>`` may reference a binary directory.
+
+``TARGET``
+ Scope must name one existing target.
+ See also the :command:`get_target_property` command.
+
+``SOURCE``
+ Scope must name one source file. By default, the source file's property
+ will be read from the current source directory's scope.
+
+ .. versionadded:: 3.18
+ Directory scope can be overridden with one of the following sub-options:
+
+ ``DIRECTORY <dir>``
+ The source file property will be read from the ``<dir>`` directory's
+ scope. CMake must already know about
+ the directory, either by having added it through a call
+ to :command:`add_subdirectory` or ``<dir>`` being the top level directory.
+ Relative paths are treated as relative to the current source directory.
+
+ .. versionadded:: 3.19
+ ``<dir>`` may reference a binary directory.
+
+ ``TARGET_DIRECTORY <target>``
+ The source file property will be read from the directory scope in which
+ ``<target>`` was created (``<target>`` must therefore already exist).
+
+ See also the :command:`get_source_file_property` command.
+
+``INSTALL``
+ .. versionadded:: 3.1
+
+ Scope must name one installed file path.
+
+``TEST``
+ Scope must name one existing test.
+ See also the :command:`get_test_property` command.
+
+``CACHE``
+ Scope must name one cache entry.
+
+``VARIABLE``
+ Scope is unique and does not accept a name.
+
+The required ``PROPERTY`` option is immediately followed by the name of
+the property to get. If the property is not set an empty value is
+returned, although some properties support inheriting from a parent scope
+if defined to behave that way (see :command:`define_property`).
+
+If the ``SET`` option is given the variable is set to a boolean
+value indicating whether the property has been set. If the ``DEFINED``
+option is given the variable is set to a boolean value indicating
+whether the property has been defined such as with the
+:command:`define_property` command.
+
+If ``BRIEF_DOCS`` or ``FULL_DOCS`` is given then the variable is set to a
+string containing documentation for the requested property. If
+documentation is requested for a property that has not been defined
+``NOTFOUND`` is returned.
+
+.. note::
+
+ The :prop_sf:`GENERATED` source file property may be globally visible.
+ See its documentation for details.
diff --git a/Help/command/get_source_file_property.rst b/Help/command/get_source_file_property.rst
new file mode 100644
index 0000000..ae41565
--- /dev/null
+++ b/Help/command/get_source_file_property.rst
@@ -0,0 +1,47 @@
+get_source_file_property
+------------------------
+
+Get a property for a source file.
+
+.. code-block:: cmake
+
+ get_source_file_property(<variable> <file>
+ [DIRECTORY <dir> | TARGET_DIRECTORY <target>]
+ <property>)
+
+Gets a property from a source file. The value of the property is
+stored in the specified ``<variable>``. If the source property is not found,
+the behavior depends on whether it has been defined to be an ``INHERITED``
+property or not (see :command:`define_property`). Non-inherited properties
+will set ``variable`` to ``NOTFOUND``, whereas inherited properties will search
+the relevant parent scope as described for the :command:`define_property`
+command and if still unable to find the property, ``variable`` will be set to
+an empty string.
+
+By default, the source file's property will be read from the current source
+directory's scope.
+
+.. versionadded:: 3.18
+ Directory scope can be overridden with one of the following sub-options:
+
+ ``DIRECTORY <dir>``
+ The source file property will be read from the ``<dir>`` directory's
+ scope. CMake must already know about that source directory, either by
+ having added it through a call to :command:`add_subdirectory` or ``<dir>``
+ being the top level source directory. Relative paths are treated as
+ relative to the current source directory.
+
+ ``TARGET_DIRECTORY <target>``
+ The source file property will be read from the directory scope in which
+ ``<target>`` was created (``<target>`` must therefore already exist).
+
+Use :command:`set_source_files_properties` to set property values. Source
+file properties usually control how the file is built. One property that is
+always there is :prop_sf:`LOCATION`.
+
+See also the more general :command:`get_property` command.
+
+.. note::
+
+ The :prop_sf:`GENERATED` source file property may be globally visible.
+ See its documentation for details.
diff --git a/Help/command/get_target_property.rst b/Help/command/get_target_property.rst
new file mode 100644
index 0000000..985b1ff
--- /dev/null
+++ b/Help/command/get_target_property.rst
@@ -0,0 +1,27 @@
+get_target_property
+-------------------
+
+Get a property from a target.
+
+.. code-block:: cmake
+
+ get_target_property(<VAR> target property)
+
+Get a property from a target. The value of the property is stored in
+the variable ``<VAR>``. If the target property is not found, the behavior
+depends on whether it has been defined to be an ``INHERITED`` property
+or not (see :command:`define_property`). Non-inherited properties will
+set ``<VAR>`` to ``<VAR>-NOTFOUND``, whereas inherited properties will search
+the relevant parent scope as described for the :command:`define_property`
+command and if still unable to find the property, ``<VAR>`` will be set to
+an empty string.
+
+Use :command:`set_target_properties` to set target property values.
+Properties are usually used to control how a target is built, but some
+query the target instead. This command can get properties for any
+target so far created. The targets do not need to be in the current
+``CMakeLists.txt`` file.
+
+See also the more general :command:`get_property` command.
+
+See :ref:`Target Properties` for the list of properties known to CMake.
diff --git a/Help/command/get_test_property.rst b/Help/command/get_test_property.rst
new file mode 100644
index 0000000..e02b9bc
--- /dev/null
+++ b/Help/command/get_test_property.rst
@@ -0,0 +1,21 @@
+get_test_property
+-----------------
+
+Get a property of the test.
+
+.. code-block:: cmake
+
+ get_test_property(test property VAR)
+
+Get a property from the test. The value of the property is stored in
+the variable ``VAR``. If the test property is not found, the behavior
+depends on whether it has been defined to be an ``INHERITED`` property
+or not (see :command:`define_property`). Non-inherited properties will
+set ``VAR`` to "NOTFOUND", whereas inherited properties will search the
+relevant parent scope as described for the :command:`define_property`
+command and if still unable to find the property, ``VAR`` will be set to
+an empty string.
+
+For a list of standard properties you can type ``cmake --help-property-list``.
+
+See also the more general :command:`get_property` command.
diff --git a/Help/command/if.rst b/Help/command/if.rst
new file mode 100644
index 0000000..f327ca9
--- /dev/null
+++ b/Help/command/if.rst
@@ -0,0 +1,355 @@
+if
+--
+
+Conditionally execute a group of commands.
+
+Synopsis
+^^^^^^^^
+
+.. code-block:: cmake
+
+ if(<condition>)
+ <commands>
+ elseif(<condition>) # optional block, can be repeated
+ <commands>
+ else() # optional block
+ <commands>
+ endif()
+
+Evaluates the ``condition`` argument of the ``if`` clause according to the
+`Condition syntax`_ described below. If the result is true, then the
+``commands`` in the ``if`` block are executed.
+Otherwise, optional ``elseif`` blocks are processed in the same way.
+Finally, if no ``condition`` is true, ``commands`` in the optional ``else``
+block are executed.
+
+Per legacy, the :command:`else` and :command:`endif` commands admit
+an optional ``<condition>`` argument.
+If used, it must be a verbatim
+repeat of the argument of the opening
+``if`` command.
+
+.. _`Condition Syntax`:
+
+Condition Syntax
+^^^^^^^^^^^^^^^^
+
+The following syntax applies to the ``condition`` argument of
+the ``if``, ``elseif`` and :command:`while` clauses.
+
+Compound conditions are evaluated in the following order of precedence:
+Innermost parentheses are evaluated first. Next come unary tests such
+as `EXISTS`_, `COMMAND`_, and `DEFINED`_. Then binary tests such as
+`EQUAL`_, `LESS`_, `LESS_EQUAL`_, `GREATER`_, `GREATER_EQUAL`_,
+`STREQUAL`_, `STRLESS`_, `STRLESS_EQUAL`_, `STRGREATER`_,
+`STRGREATER_EQUAL`_, `VERSION_EQUAL`_, `VERSION_LESS`_,
+`VERSION_LESS_EQUAL`_, `VERSION_GREATER`_, `VERSION_GREATER_EQUAL`_,
+and `MATCHES`_. Then the boolean operators in the order `NOT`_, `AND`_,
+and finally `OR`_.
+
+Basic Expressions
+"""""""""""""""""
+
+``if(<constant>)``
+ True if the constant is ``1``, ``ON``, ``YES``, ``TRUE``, ``Y``,
+ or a non-zero number. False if the constant is ``0``, ``OFF``,
+ ``NO``, ``FALSE``, ``N``, ``IGNORE``, ``NOTFOUND``, the empty string,
+ or ends in the suffix ``-NOTFOUND``. Named boolean constants are
+ case-insensitive. If the argument is not one of these specific
+ constants, it is treated as a variable or string and the following
+ signature is used.
+
+``if(<variable|string>)``
+ True if given a variable that is defined to a value that is not a false
+ constant. False otherwise. (Note macro arguments are not variables.)
+
+Logic Operators
+"""""""""""""""
+
+.. _NOT:
+
+``if(NOT <condition>)``
+ True if the condition is not true.
+
+.. _AND:
+
+``if(<cond1> AND <cond2>)``
+ True if both conditions would be considered true individually.
+
+.. _OR:
+
+``if(<cond1> OR <cond2>)``
+ True if either condition would be considered true individually.
+
+``if((condition) AND (condition OR (condition)))``
+ The conditions inside the parenthesis are evaluated first and then
+ the remaining condition is evaluated as in the other examples.
+ Where there are nested parenthesis the innermost are evaluated as part
+ of evaluating the condition that contains them.
+
+Existence Checks
+""""""""""""""""
+
+.. _COMMAND:
+
+``if(COMMAND command-name)``
+ True if the given name is a command, macro or function that can be
+ invoked.
+
+``if(POLICY policy-id)``
+ True if the given name is an existing policy (of the form ``CMP<NNNN>``).
+
+``if(TARGET target-name)``
+ True if the given name is an existing logical target name created
+ by a call to the :command:`add_executable`, :command:`add_library`,
+ or :command:`add_custom_target` command that has already been invoked
+ (in any directory).
+
+``if(TEST test-name)``
+ .. versionadded:: 3.3
+ True if the given name is an existing test name created by the
+ :command:`add_test` command.
+
+.. _DEFINED:
+
+``if(DEFINED <name>|CACHE{<name>}|ENV{<name>})``
+ True if a variable, cache variable or environment variable
+ with given ``<name>`` is defined. The value of the variable
+ does not matter. Note that macro arguments are not variables.
+
+ .. versionadded:: 3.14
+ Added support for ``CACHE{<name>}`` variables.
+
+``if(<variable|string> IN_LIST <variable>)``
+ .. versionadded:: 3.3
+ True if the given element is contained in the named list variable.
+
+File Operations
+"""""""""""""""
+
+.. _EXISTS:
+
+``if(EXISTS path-to-file-or-directory)``
+ True if the named file or directory exists. Behavior is well-defined
+ only for explicit full paths (a leading ``~/`` is not expanded as
+ a home directory and is considered a relative path).
+ Resolves symbolic links, i.e. if the named file or directory is a
+ symbolic link, returns true if the target of the symbolic link exists.
+
+``if(file1 IS_NEWER_THAN file2)``
+ True if ``file1`` is newer than ``file2`` or if one of the two files doesn't
+ exist. Behavior is well-defined only for full paths. If the file
+ time stamps are exactly the same, an ``IS_NEWER_THAN`` comparison returns
+ true, so that any dependent build operations will occur in the event
+ of a tie. This includes the case of passing the same file name for
+ both file1 and file2.
+
+``if(IS_DIRECTORY path-to-directory)``
+ True if the given name is a directory. Behavior is well-defined only
+ for full paths.
+
+``if(IS_SYMLINK file-name)``
+ True if the given name is a symbolic link. Behavior is well-defined
+ only for full paths.
+
+``if(IS_ABSOLUTE path)``
+ True if the given path is an absolute path.
+
+Comparisons
+"""""""""""
+
+.. _MATCHES:
+
+``if(<variable|string> MATCHES regex)``
+ True if the given string or variable's value matches the given regular
+ condition. See :ref:`Regex Specification` for regex format.
+
+ .. versionadded:: 3.9
+ ``()`` groups are captured in :variable:`CMAKE_MATCH_<n>` variables.
+
+.. _LESS:
+
+``if(<variable|string> LESS <variable|string>)``
+ True if the given string or variable's value is a valid number and less
+ than that on the right.
+
+.. _GREATER:
+
+``if(<variable|string> GREATER <variable|string>)``
+ True if the given string or variable's value is a valid number and greater
+ than that on the right.
+
+.. _EQUAL:
+
+``if(<variable|string> EQUAL <variable|string>)``
+ True if the given string or variable's value is a valid number and equal
+ to that on the right.
+
+.. _LESS_EQUAL:
+
+``if(<variable|string> LESS_EQUAL <variable|string>)``
+ .. versionadded:: 3.7
+ True if the given string or variable's value is a valid number and less
+ than or equal to that on the right.
+
+.. _GREATER_EQUAL:
+
+``if(<variable|string> GREATER_EQUAL <variable|string>)``
+ .. versionadded:: 3.7
+ True if the given string or variable's value is a valid number and greater
+ than or equal to that on the right.
+
+.. _STRLESS:
+
+``if(<variable|string> STRLESS <variable|string>)``
+ True if the given string or variable's value is lexicographically less
+ than the string or variable on the right.
+
+.. _STRGREATER:
+
+``if(<variable|string> STRGREATER <variable|string>)``
+ True if the given string or variable's value is lexicographically greater
+ than the string or variable on the right.
+
+.. _STREQUAL:
+
+``if(<variable|string> STREQUAL <variable|string>)``
+ True if the given string or variable's value is lexicographically equal
+ to the string or variable on the right.
+
+.. _STRLESS_EQUAL:
+
+``if(<variable|string> STRLESS_EQUAL <variable|string>)``
+ .. versionadded:: 3.7
+ True if the given string or variable's value is lexicographically less
+ than or equal to the string or variable on the right.
+
+.. _STRGREATER_EQUAL:
+
+``if(<variable|string> STRGREATER_EQUAL <variable|string>)``
+ .. versionadded:: 3.7
+ True if the given string or variable's value is lexicographically greater
+ than or equal to the string or variable on the right.
+
+Version Comparisons
+"""""""""""""""""""
+
+.. _VERSION_LESS:
+
+``if(<variable|string> VERSION_LESS <variable|string>)``
+ Component-wise integer version number comparison (version format is
+ ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero).
+ Any non-integer version component or non-integer trailing part of a version
+ component effectively truncates the string at that point.
+
+.. _VERSION_GREATER:
+
+``if(<variable|string> VERSION_GREATER <variable|string>)``
+ Component-wise integer version number comparison (version format is
+ ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero).
+ Any non-integer version component or non-integer trailing part of a version
+ component effectively truncates the string at that point.
+
+.. _VERSION_EQUAL:
+
+``if(<variable|string> VERSION_EQUAL <variable|string>)``
+ Component-wise integer version number comparison (version format is
+ ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero).
+ Any non-integer version component or non-integer trailing part of a version
+ component effectively truncates the string at that point.
+
+.. _VERSION_LESS_EQUAL:
+
+``if(<variable|string> VERSION_LESS_EQUAL <variable|string>)``
+ .. versionadded:: 3.7
+ Component-wise integer version number comparison (version format is
+ ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero).
+ Any non-integer version component or non-integer trailing part of a version
+ component effectively truncates the string at that point.
+
+.. _VERSION_GREATER_EQUAL:
+
+``if(<variable|string> VERSION_GREATER_EQUAL <variable|string>)``
+ .. versionadded:: 3.7
+ Component-wise integer version number comparison (version format is
+ ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero).
+ Any non-integer version component or non-integer trailing part of a version
+ component effectively truncates the string at that point.
+
+Variable Expansion
+^^^^^^^^^^^^^^^^^^
+
+The if command was written very early in CMake's history, predating
+the ``${}`` variable evaluation syntax, and for convenience evaluates
+variables named by its arguments as shown in the above signatures.
+Note that normal variable evaluation with ``${}`` applies before the if
+command even receives the arguments. Therefore code like
+
+.. code-block:: cmake
+
+ set(var1 OFF)
+ set(var2 "var1")
+ if(${var2})
+
+appears to the if command as
+
+.. code-block:: cmake
+
+ if(var1)
+
+and is evaluated according to the ``if(<variable>)`` case documented
+above. The result is ``OFF`` which is false. However, if we remove the
+``${}`` from the example then the command sees
+
+.. code-block:: cmake
+
+ if(var2)
+
+which is true because ``var2`` is defined to ``var1`` which is not a false
+constant.
+
+Automatic evaluation applies in the other cases whenever the
+above-documented condition syntax accepts ``<variable|string>``:
+
+* The left hand argument to ``MATCHES`` is first checked to see if it is
+ a defined variable, if so the variable's value is used, otherwise the
+ original value is used.
+
+* If the left hand argument to ``MATCHES`` is missing it returns false
+ without error
+
+* Both left and right hand arguments to ``LESS``, ``GREATER``, ``EQUAL``,
+ ``LESS_EQUAL``, and ``GREATER_EQUAL``, are independently tested to see if
+ they are defined variables, if so their defined values are used otherwise
+ the original value is used.
+
+* Both left and right hand arguments to ``STRLESS``, ``STRGREATER``,
+ ``STREQUAL``, ``STRLESS_EQUAL``, and ``STRGREATER_EQUAL`` are independently
+ tested to see if they are defined variables, if so their defined values are
+ used otherwise the original value is used.
+
+* Both left and right hand arguments to ``VERSION_LESS``,
+ ``VERSION_GREATER``, ``VERSION_EQUAL``, ``VERSION_LESS_EQUAL``, and
+ ``VERSION_GREATER_EQUAL`` are independently tested to see if they are defined
+ variables, if so their defined values are used otherwise the original value
+ is used.
+
+* The right hand argument to ``NOT`` is tested to see if it is a boolean
+ constant, if so the value is used, otherwise it is assumed to be a
+ variable and it is dereferenced.
+
+* The left and right hand arguments to ``AND`` and ``OR`` are independently
+ tested to see if they are boolean constants, if so they are used as
+ such, otherwise they are assumed to be variables and are dereferenced.
+
+.. versionchanged:: 3.1
+ To prevent ambiguity, potential variable or keyword names can be
+ specified in a :ref:`Quoted Argument` or a :ref:`Bracket Argument`.
+ A quoted or bracketed variable or keyword will be interpreted as a
+ string and not dereferenced or interpreted.
+ See policy :policy:`CMP0054`.
+
+There is no automatic evaluation for environment or cache
+:ref:`Variable References`. Their values must be referenced as
+``$ENV{<name>}`` or ``$CACHE{<name>}`` wherever the above-documented
+condition syntax accepts ``<variable|string>``.
diff --git a/Help/command/include.rst b/Help/command/include.rst
new file mode 100644
index 0000000..80968da
--- /dev/null
+++ b/Help/command/include.rst
@@ -0,0 +1,25 @@
+include
+-------
+
+Load and run CMake code from a file or module.
+
+.. code-block:: cmake
+
+ include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>]
+ [NO_POLICY_SCOPE])
+
+Loads and runs CMake code from the file given. Variable reads and
+writes access the scope of the caller (dynamic scoping). If ``OPTIONAL``
+is present, then no error is raised if the file does not exist. If
+``RESULT_VARIABLE`` is given the variable ``<var>`` will be set to the
+full filename which has been included or ``NOTFOUND`` if it failed.
+
+If a module is specified instead of a file, the file with name
+``<modulename>.cmake`` is searched first in :variable:`CMAKE_MODULE_PATH`,
+then in the CMake module directory. There is one exception to this: if
+the file which calls ``include()`` is located itself in the CMake builtin
+module directory, then first the CMake builtin module directory is searched and
+:variable:`CMAKE_MODULE_PATH` afterwards. See also policy :policy:`CMP0017`.
+
+See the :command:`cmake_policy` command documentation for discussion of the
+``NO_POLICY_SCOPE`` option.
diff --git a/Help/command/include_directories.rst b/Help/command/include_directories.rst
new file mode 100644
index 0000000..fe281c3
--- /dev/null
+++ b/Help/command/include_directories.rst
@@ -0,0 +1,41 @@
+include_directories
+-------------------
+
+Add include directories to the build.
+
+.. code-block:: cmake
+
+ include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
+
+Add the given directories to those the compiler uses to search for
+include files. Relative paths are interpreted as relative to the
+current source directory.
+
+The include directories are added to the :prop_dir:`INCLUDE_DIRECTORIES`
+directory property for the current ``CMakeLists`` file. They are also
+added to the :prop_tgt:`INCLUDE_DIRECTORIES` target property for each
+target in the current ``CMakeLists`` file. The target property values
+are the ones used by the generators.
+
+By default the directories specified are appended onto the current list of
+directories. This default behavior can be changed by setting
+:variable:`CMAKE_INCLUDE_DIRECTORIES_BEFORE` to ``ON``. By using
+``AFTER`` or ``BEFORE`` explicitly, you can select between appending and
+prepending, independent of the default.
+
+If the ``SYSTEM`` option is given, the compiler will be told the
+directories are meant as system include directories on some platforms.
+Signalling this setting might achieve effects such as the compiler
+skipping warnings, or these fixed-install system files not being
+considered in dependency calculations - see compiler docs.
+
+Arguments to ``include_directories`` may use "generator expressions" with
+the syntax "$<...>". See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
+.. note::
+
+ Prefer the :command:`target_include_directories` command to add include
+ directories to individual targets and optionally propagate/export them
+ to dependents.
diff --git a/Help/command/include_external_msproject.rst b/Help/command/include_external_msproject.rst
new file mode 100644
index 0000000..4354654
--- /dev/null
+++ b/Help/command/include_external_msproject.rst
@@ -0,0 +1,27 @@
+include_external_msproject
+--------------------------
+
+Include an external Microsoft project file in a workspace.
+
+.. code-block:: cmake
+
+ include_external_msproject(projectname location
+ [TYPE projectTypeGUID]
+ [GUID projectGUID]
+ [PLATFORM platformName]
+ dep1 dep2 ...)
+
+Includes an external Microsoft project in the generated workspace
+file. Currently does nothing on UNIX. This will create a target
+named ``[projectname]``. This can be used in the :command:`add_dependencies`
+command to make things depend on the external project.
+
+``TYPE``, ``GUID`` and ``PLATFORM`` are optional parameters that allow one to
+specify the type of project, id (``GUID``) of the project and the name of
+the target platform. This is useful for projects requiring values
+other than the default (e.g. WIX projects).
+
+.. versionadded:: 3.9
+ If the imported project has different configuration names than the
+ current project, set the :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>`
+ target property to specify the mapping.
diff --git a/Help/command/include_guard.rst b/Help/command/include_guard.rst
new file mode 100644
index 0000000..dca3b6f
--- /dev/null
+++ b/Help/command/include_guard.rst
@@ -0,0 +1,48 @@
+include_guard
+-------------
+
+.. versionadded:: 3.10
+
+Provides an include guard for the file currently being processed by CMake.
+
+.. code-block:: cmake
+
+ include_guard([DIRECTORY|GLOBAL])
+
+Sets up an include guard for the current CMake file (see the
+:variable:`CMAKE_CURRENT_LIST_FILE` variable documentation).
+
+CMake will end its processing of the current file at the location of the
+:command:`include_guard` command if the current file has already been
+processed for the applicable scope (see below). This provides functionality
+similar to the include guards commonly used in source headers or to the
+``#pragma once`` directive. If the current file has been processed previously
+for the applicable scope, the effect is as though :command:`return` had been
+called. Do not call this command from inside a function being defined within
+the current file.
+
+An optional argument specifying the scope of the guard may be provided.
+Possible values for the option are:
+
+``DIRECTORY``
+ The include guard applies within the current directory and below. The file
+ will only be included once within this directory scope, but may be included
+ again by other files outside of this directory (i.e. a parent directory or
+ another directory not pulled in by :command:`add_subdirectory` or
+ :command:`include` from the current file or its children).
+
+``GLOBAL``
+ The include guard applies globally to the whole build. The current file
+ will only be included once regardless of the scope.
+
+If no arguments given, ``include_guard`` has the same scope as a variable,
+meaning that the include guard effect is isolated by the most recent
+function scope or current directory if no inner function scopes exist.
+In this case the command behavior is the same as:
+
+.. code-block:: cmake
+
+ if(__CURRENT_FILE_VAR__)
+ return()
+ endif()
+ set(__CURRENT_FILE_VAR__ TRUE)
diff --git a/Help/command/include_regular_expression.rst b/Help/command/include_regular_expression.rst
new file mode 100644
index 0000000..dde8378
--- /dev/null
+++ b/Help/command/include_regular_expression.rst
@@ -0,0 +1,18 @@
+include_regular_expression
+--------------------------
+
+Set the regular expression used for dependency checking.
+
+.. code-block:: cmake
+
+ include_regular_expression(regex_match [regex_complain])
+
+Sets the regular expressions used in dependency checking. Only files
+matching ``regex_match`` will be traced as dependencies. Only files
+matching ``regex_complain`` will generate warnings if they cannot be found
+(standard header paths are not searched). The defaults are:
+
+::
+
+ regex_match = "^.*$" (match everything)
+ regex_complain = "^$" (match empty string only)
diff --git a/Help/command/install.rst b/Help/command/install.rst
new file mode 100644
index 0000000..35207f4
--- /dev/null
+++ b/Help/command/install.rst
@@ -0,0 +1,762 @@
+install
+-------
+
+Specify rules to run at install time.
+
+Synopsis
+^^^^^^^^
+
+.. parsed-literal::
+
+ install(`TARGETS`_ <target>... [...])
+ install({`FILES`_ | `PROGRAMS`_} <file>... [...])
+ install(`DIRECTORY`_ <dir>... [...])
+ install(`SCRIPT`_ <file> [...])
+ install(`CODE`_ <code> [...])
+ install(`EXPORT`_ <export-name> [...])
+
+Introduction
+^^^^^^^^^^^^
+
+This command generates installation rules for a project. Install rules
+specified by calls to the ``install()`` command within a source directory
+are executed in order during installation.
+
+.. versionchanged:: 3.14
+ Install rules in subdirectories
+ added by calls to the :command:`add_subdirectory` command are interleaved
+ with those in the parent directory to run in the order declared (see
+ policy :policy:`CMP0082`).
+
+There are multiple signatures for this command. Some of them define
+installation options for files and targets. Options common to
+multiple signatures are covered here but they are valid only for
+signatures that specify them. The common options are:
+
+``DESTINATION``
+ Specify the directory on disk to which a file will be installed.
+ Arguments can be relative or absolute paths.
+
+ If a relative path is given it is interpreted relative to the value
+ of the :variable:`CMAKE_INSTALL_PREFIX` variable.
+ The prefix can be relocated at install time using the ``DESTDIR``
+ mechanism explained in the :variable:`CMAKE_INSTALL_PREFIX` variable
+ documentation.
+
+ If an absolute path (with a leading slash or drive letter) is given
+ it is used verbatim.
+
+ As absolute paths are not supported by :manual:`cpack <cpack(1)>` installer
+ generators, it is preferable to use relative paths throughout.
+ In particular, there is no need to make paths absolute by prepending
+ :variable:`CMAKE_INSTALL_PREFIX`; this prefix is used by default if
+ the DESTINATION is a relative path.
+
+``PERMISSIONS``
+ Specify permissions for installed files. Valid permissions are
+ ``OWNER_READ``, ``OWNER_WRITE``, ``OWNER_EXECUTE``, ``GROUP_READ``,
+ ``GROUP_WRITE``, ``GROUP_EXECUTE``, ``WORLD_READ``, ``WORLD_WRITE``,
+ ``WORLD_EXECUTE``, ``SETUID``, and ``SETGID``. Permissions that do
+ not make sense on certain platforms are ignored on those platforms.
+
+``CONFIGURATIONS``
+ Specify a list of build configurations for which the install rule
+ applies (Debug, Release, etc.). Note that the values specified for
+ this option only apply to options listed AFTER the ``CONFIGURATIONS``
+ option. For example, to set separate install paths for the Debug and
+ Release configurations, do the following:
+
+ .. code-block:: cmake
+
+ install(TARGETS target
+ CONFIGURATIONS Debug
+ RUNTIME DESTINATION Debug/bin)
+ install(TARGETS target
+ CONFIGURATIONS Release
+ RUNTIME DESTINATION Release/bin)
+
+ Note that ``CONFIGURATIONS`` appears BEFORE ``RUNTIME DESTINATION``.
+
+``COMPONENT``
+ Specify an installation component name with which the install rule
+ is associated, such as "runtime" or "development". During
+ component-specific installation only install rules associated with
+ the given component name will be executed. During a full installation
+ all components are installed unless marked with ``EXCLUDE_FROM_ALL``.
+ If ``COMPONENT`` is not provided a default component "Unspecified" is
+ created. The default component name may be controlled with the
+ :variable:`CMAKE_INSTALL_DEFAULT_COMPONENT_NAME` variable.
+
+``EXCLUDE_FROM_ALL``
+ .. versionadded:: 3.6
+
+ Specify that the file is excluded from a full installation and only
+ installed as part of a component-specific installation
+
+``RENAME``
+ Specify a name for an installed file that may be different from the
+ original file. Renaming is allowed only when a single file is
+ installed by the command.
+
+``OPTIONAL``
+ Specify that it is not an error if the file to be installed does
+ not exist.
+
+.. versionadded:: 3.1
+ Command signatures that install files may print messages during
+ installation. Use the :variable:`CMAKE_INSTALL_MESSAGE` variable
+ to control which messages are printed.
+
+.. versionadded:: 3.11
+ Many of the ``install()`` variants implicitly create the directories
+ containing the installed files. If
+ :variable:`CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS` is set, these
+ directories will be created with the permissions specified. Otherwise,
+ they will be created according to the uname rules on Unix-like platforms.
+ Windows platforms are unaffected.
+
+Installing Targets
+^^^^^^^^^^^^^^^^^^
+
+.. _`install(TARGETS)`:
+.. _TARGETS:
+
+.. code-block:: cmake
+
+ install(TARGETS targets... [EXPORT <export-name>]
+ [[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDLE|
+ PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
+ [DESTINATION <dir>]
+ [PERMISSIONS permissions...]
+ [CONFIGURATIONS [Debug|Release|...]]
+ [COMPONENT <component>]
+ [NAMELINK_COMPONENT <component>]
+ [OPTIONAL] [EXCLUDE_FROM_ALL]
+ [NAMELINK_ONLY|NAMELINK_SKIP]
+ ] [...]
+ [INCLUDES DESTINATION [<dir> ...]]
+ )
+
+The ``TARGETS`` form specifies rules for installing targets from a
+project. There are several kinds of target :ref:`Output Artifacts`
+that may be installed:
+
+``ARCHIVE``
+ Target artifacts of this kind include:
+
+ * *Static libraries*
+ (except on macOS when marked as ``FRAMEWORK``, see below);
+ * *DLL import libraries*
+ (on all Windows-based systems including Cygwin; they have extension
+ ``.lib``, in contrast to the ``.dll`` libraries that go to ``RUNTIME``);
+ * On AIX, the *linker import file* created for executables with
+ :prop_tgt:`ENABLE_EXPORTS` enabled.
+
+``LIBRARY``
+ Target artifacts of this kind include:
+
+ * *Shared libraries*, except
+
+ - DLLs (these go to ``RUNTIME``, see below),
+ - on macOS when marked as ``FRAMEWORK`` (see below).
+
+``RUNTIME``
+ Target artifacts of this kind include:
+
+ * *Executables*
+ (except on macOS when marked as ``MACOSX_BUNDLE``, see ``BUNDLE`` below);
+ * DLLs (on all Windows-based systems including Cygwin; note that the
+ accompanying import libraries are of kind ``ARCHIVE``).
+
+``OBJECTS``
+ .. versionadded:: 3.9
+
+ Object files associated with *object libraries*.
+
+``FRAMEWORK``
+ Both static and shared libraries marked with the ``FRAMEWORK``
+ property are treated as ``FRAMEWORK`` targets on macOS.
+
+``BUNDLE``
+ Executables marked with the :prop_tgt:`MACOSX_BUNDLE` property are treated as
+ ``BUNDLE`` targets on macOS.
+
+``PUBLIC_HEADER``
+ Any :prop_tgt:`PUBLIC_HEADER` files associated with a library are installed in
+ the destination specified by the ``PUBLIC_HEADER`` argument on non-Apple
+ platforms. Rules defined by this argument are ignored for :prop_tgt:`FRAMEWORK`
+ libraries on Apple platforms because the associated files are installed
+ into the appropriate locations inside the framework folder. See
+ :prop_tgt:`PUBLIC_HEADER` for details.
+
+``PRIVATE_HEADER``
+ Similar to ``PUBLIC_HEADER``, but for ``PRIVATE_HEADER`` files. See
+ :prop_tgt:`PRIVATE_HEADER` for details.
+
+``RESOURCE``
+ Similar to ``PUBLIC_HEADER`` and ``PRIVATE_HEADER``, but for
+ ``RESOURCE`` files. See :prop_tgt:`RESOURCE` for details.
+
+For each of these arguments given, the arguments following them only apply
+to the target or file type specified in the argument. If none is given, the
+installation properties apply to all target types. If only one is given then
+only targets of that type will be installed (which can be used to install
+just a DLL or just an import library.)
+
+For regular executables, static libraries and shared libraries, the
+``DESTINATION`` argument is not required. For these target types, when
+``DESTINATION`` is omitted, a default destination will be taken from the
+appropriate variable from :module:`GNUInstallDirs`, or set to a built-in
+default value if that variable is not defined. The same is true for the
+public and private headers associated with the installed targets through the
+:prop_tgt:`PUBLIC_HEADER` and :prop_tgt:`PRIVATE_HEADER` target properties.
+A destination must always be provided for module libraries, Apple bundles and
+frameworks. A destination can be omitted for interface and object libraries,
+but they are handled differently (see the discussion of this topic toward the
+end of this section).
+
+The following table shows the target types with their associated variables and
+built-in defaults that apply when no destination is given:
+
+================== =============================== ======================
+ Target Type GNUInstallDirs Variable Built-In Default
+================== =============================== ======================
+``RUNTIME`` ``${CMAKE_INSTALL_BINDIR}`` ``bin``
+``LIBRARY`` ``${CMAKE_INSTALL_LIBDIR}`` ``lib``
+``ARCHIVE`` ``${CMAKE_INSTALL_LIBDIR}`` ``lib``
+``PRIVATE_HEADER`` ``${CMAKE_INSTALL_INCLUDEDIR}`` ``include``
+``PUBLIC_HEADER`` ``${CMAKE_INSTALL_INCLUDEDIR}`` ``include``
+================== =============================== ======================
+
+Projects wishing to follow the common practice of installing headers into a
+project-specific subdirectory will need to provide a destination rather than
+rely on the above.
+
+To make packages compliant with distribution filesystem layout policies, if
+projects must specify a ``DESTINATION``, it is recommended that they use a
+path that begins with the appropriate :module:`GNUInstallDirs` variable.
+This allows package maintainers to control the install destination by setting
+the appropriate cache variables. The following example shows a static library
+being installed to the default destination provided by
+:module:`GNUInstallDirs`, but with its headers installed to a project-specific
+subdirectory that follows the above recommendation:
+
+.. code-block:: cmake
+
+ add_library(mylib STATIC ...)
+ set_target_properties(mylib PROPERTIES PUBLIC_HEADER mylib.h)
+ include(GNUInstallDirs)
+ install(TARGETS mylib
+ PUBLIC_HEADER
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/myproj
+ )
+
+In addition to the common options listed above, each target can accept
+the following additional arguments:
+
+``NAMELINK_COMPONENT``
+ .. versionadded:: 3.12
+
+ On some platforms a versioned shared library has a symbolic link such
+ as::
+
+ lib<name>.so -> lib<name>.so.1
+
+ where ``lib<name>.so.1`` is the soname of the library and ``lib<name>.so``
+ is a "namelink" allowing linkers to find the library when given
+ ``-l<name>``. The ``NAMELINK_COMPONENT`` option is similar to the
+ ``COMPONENT`` option, but it changes the installation component of a shared
+ library namelink if one is generated. If not specified, this defaults to the
+ value of ``COMPONENT``. It is an error to use this parameter outside of a
+ ``LIBRARY`` block.
+
+ Consider the following example:
+
+ .. code-block:: cmake
+
+ install(TARGETS mylib
+ LIBRARY
+ COMPONENT Libraries
+ NAMELINK_COMPONENT Development
+ PUBLIC_HEADER
+ COMPONENT Development
+ )
+
+ In this scenario, if you choose to install only the ``Development``
+ component, both the headers and namelink will be installed without the
+ library. (If you don't also install the ``Libraries`` component, the
+ namelink will be a dangling symlink, and projects that link to the library
+ will have build errors.) If you install only the ``Libraries`` component,
+ only the library will be installed, without the headers and namelink.
+
+ This option is typically used for package managers that have separate
+ runtime and development packages. For example, on Debian systems, the
+ library is expected to be in the runtime package, and the headers and
+ namelink are expected to be in the development package.
+
+ See the :prop_tgt:`VERSION` and :prop_tgt:`SOVERSION` target properties for
+ details on creating versioned shared libraries.
+
+``NAMELINK_ONLY``
+ This option causes the installation of only the namelink when a library
+ target is installed. On platforms where versioned shared libraries do not
+ have namelinks or when a library is not versioned, the ``NAMELINK_ONLY``
+ option installs nothing. It is an error to use this parameter outside of a
+ ``LIBRARY`` block.
+
+ When ``NAMELINK_ONLY`` is given, either ``NAMELINK_COMPONENT`` or
+ ``COMPONENT`` may be used to specify the installation component of the
+ namelink, but ``COMPONENT`` should generally be preferred.
+
+``NAMELINK_SKIP``
+ Similar to ``NAMELINK_ONLY``, but it has the opposite effect: it causes the
+ installation of library files other than the namelink when a library target
+ is installed. When neither ``NAMELINK_ONLY`` or ``NAMELINK_SKIP`` are given,
+ both portions are installed. On platforms where versioned shared libraries
+ do not have symlinks or when a library is not versioned, ``NAMELINK_SKIP``
+ installs the library. It is an error to use this parameter outside of a
+ ``LIBRARY`` block.
+
+ If ``NAMELINK_SKIP`` is specified, ``NAMELINK_COMPONENT`` has no effect. It
+ is not recommended to use ``NAMELINK_SKIP`` in conjunction with
+ ``NAMELINK_COMPONENT``.
+
+The `install(TARGETS)`_ command can also accept the following options at the
+top level:
+
+``EXPORT``
+ This option associates the installed target files with an export called
+ ``<export-name>``. It must appear before any target options. To actually
+ install the export file itself, call `install(EXPORT)`_, documented below.
+ See documentation of the :prop_tgt:`EXPORT_NAME` target property to change
+ the name of the exported target.
+
+``INCLUDES DESTINATION``
+ This option specifies a list of directories which will be added to the
+ :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target property of the
+ ``<targets>`` when exported by the `install(EXPORT)`_ command. If a
+ relative path is specified, it is treated as relative to the
+ ``$<INSTALL_PREFIX>``.
+
+One or more groups of properties may be specified in a single call to
+the ``TARGETS`` form of this command. A target may be installed more than
+once to different locations. Consider hypothetical targets ``myExe``,
+``mySharedLib``, and ``myStaticLib``. The code:
+
+.. code-block:: cmake
+
+ install(TARGETS myExe mySharedLib myStaticLib
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib/static)
+ install(TARGETS mySharedLib DESTINATION /some/full/path)
+
+will install ``myExe`` to ``<prefix>/bin`` and ``myStaticLib`` to
+``<prefix>/lib/static``. On non-DLL platforms ``mySharedLib`` will be
+installed to ``<prefix>/lib`` and ``/some/full/path``. On DLL platforms
+the ``mySharedLib`` DLL will be installed to ``<prefix>/bin`` and
+``/some/full/path`` and its import library will be installed to
+``<prefix>/lib/static`` and ``/some/full/path``.
+
+:ref:`Interface Libraries` may be listed among the targets to install.
+They install no artifacts but will be included in an associated ``EXPORT``.
+If :ref:`Object Libraries` are listed but given no destination for their
+object files, they will be exported as :ref:`Interface Libraries`.
+This is sufficient to satisfy transitive usage requirements of other
+targets that link to the object libraries in their implementation.
+
+Installing a target with the :prop_tgt:`EXCLUDE_FROM_ALL` target property
+set to ``TRUE`` has undefined behavior.
+
+.. versionadded:: 3.3
+ An install destination given as a ``DESTINATION`` argument may
+ use "generator expressions" with the syntax ``$<...>``. See the
+ :manual:`cmake-generator-expressions(7)` manual for available expressions.
+
+.. versionadded:: 3.13
+ `install(TARGETS)`_ can install targets that were created in
+ other directories. When using such cross-directory install rules, running
+ ``make install`` (or similar) from a subdirectory will not guarantee that
+ targets from other directories are up-to-date. You can use
+ :command:`target_link_libraries` or :command:`add_dependencies`
+ to ensure that such out-of-directory targets are built before the
+ subdirectory-specific install rules are run.
+
+Installing Files
+^^^^^^^^^^^^^^^^
+
+.. _`install(FILES)`:
+.. _`install(PROGRAMS)`:
+.. _FILES:
+.. _PROGRAMS:
+
+.. code-block:: cmake
+
+ install(<FILES|PROGRAMS> files...
+ TYPE <type> | DESTINATION <dir>
+ [PERMISSIONS permissions...]
+ [CONFIGURATIONS [Debug|Release|...]]
+ [COMPONENT <component>]
+ [RENAME <name>] [OPTIONAL] [EXCLUDE_FROM_ALL])
+
+The ``FILES`` form specifies rules for installing files for a project.
+File names given as relative paths are interpreted with respect to the
+current source directory. Files installed by this form are by default
+given permissions ``OWNER_WRITE``, ``OWNER_READ``, ``GROUP_READ``, and
+``WORLD_READ`` if no ``PERMISSIONS`` argument is given.
+
+The ``PROGRAMS`` form is identical to the ``FILES`` form except that the
+default permissions for the installed file also include ``OWNER_EXECUTE``,
+``GROUP_EXECUTE``, and ``WORLD_EXECUTE``. This form is intended to install
+programs that are not targets, such as shell scripts. Use the ``TARGETS``
+form to install targets built within the project.
+
+The list of ``files...`` given to ``FILES`` or ``PROGRAMS`` may use
+"generator expressions" with the syntax ``$<...>``. See the
+:manual:`cmake-generator-expressions(7)` manual for available expressions.
+However, if any item begins in a generator expression it must evaluate
+to a full path.
+
+Either a ``TYPE`` or a ``DESTINATION`` must be provided, but not both.
+A ``TYPE`` argument specifies the generic file type of the files being
+installed. A destination will then be set automatically by taking the
+corresponding variable from :module:`GNUInstallDirs`, or by using a
+built-in default if that variable is not defined. See the table below for
+the supported file types and their corresponding variables and built-in
+defaults. Projects can provide a ``DESTINATION`` argument instead of a
+file type if they wish to explicitly define the install destination.
+
+======================= ================================== =========================
+ ``TYPE`` Argument GNUInstallDirs Variable Built-In Default
+======================= ================================== =========================
+``BIN`` ``${CMAKE_INSTALL_BINDIR}`` ``bin``
+``SBIN`` ``${CMAKE_INSTALL_SBINDIR}`` ``sbin``
+``LIB`` ``${CMAKE_INSTALL_LIBDIR}`` ``lib``
+``INCLUDE`` ``${CMAKE_INSTALL_INCLUDEDIR}`` ``include``
+``SYSCONF`` ``${CMAKE_INSTALL_SYSCONFDIR}`` ``etc``
+``SHAREDSTATE`` ``${CMAKE_INSTALL_SHARESTATEDIR}`` ``com``
+``LOCALSTATE`` ``${CMAKE_INSTALL_LOCALSTATEDIR}`` ``var``
+``RUNSTATE`` ``${CMAKE_INSTALL_RUNSTATEDIR}`` ``<LOCALSTATE dir>/run``
+``DATA`` ``${CMAKE_INSTALL_DATADIR}`` ``<DATAROOT dir>``
+``INFO`` ``${CMAKE_INSTALL_INFODIR}`` ``<DATAROOT dir>/info``
+``LOCALE`` ``${CMAKE_INSTALL_LOCALEDIR}`` ``<DATAROOT dir>/locale``
+``MAN`` ``${CMAKE_INSTALL_MANDIR}`` ``<DATAROOT dir>/man``
+``DOC`` ``${CMAKE_INSTALL_DOCDIR}`` ``<DATAROOT dir>/doc``
+======================= ================================== =========================
+
+Projects wishing to follow the common practice of installing headers into a
+project-specific subdirectory will need to provide a destination rather than
+rely on the above.
+
+Note that some of the types' built-in defaults use the ``DATAROOT`` directory as
+a prefix. The ``DATAROOT`` prefix is calculated similarly to the types, with
+``CMAKE_INSTALL_DATAROOTDIR`` as the variable and ``share`` as the built-in
+default. You cannot use ``DATAROOT`` as a ``TYPE`` parameter; please use
+``DATA`` instead.
+
+To make packages compliant with distribution filesystem layout policies, if
+projects must specify a ``DESTINATION``, it is recommended that they use a
+path that begins with the appropriate :module:`GNUInstallDirs` variable.
+This allows package maintainers to control the install destination by setting
+the appropriate cache variables. The following example shows how to follow
+this advice while installing headers to a project-specific subdirectory:
+
+.. code-block:: cmake
+
+ include(GNUInstallDirs)
+ install(FILES mylib.h
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/myproj
+ )
+
+.. versionadded:: 3.4
+ An install destination given as a ``DESTINATION`` argument may
+ use "generator expressions" with the syntax ``$<...>``. See the
+ :manual:`cmake-generator-expressions(7)` manual for available expressions.
+
+.. versionadded:: 3.20
+ An install rename given as a ``RENAME`` argument may
+ use "generator expressions" with the syntax ``$<...>``. See the
+ :manual:`cmake-generator-expressions(7)` manual for available expressions.
+
+Installing Directories
+^^^^^^^^^^^^^^^^^^^^^^
+
+.. _`install(DIRECTORY)`:
+.. _DIRECTORY:
+
+.. code-block:: cmake
+
+ install(DIRECTORY dirs...
+ TYPE <type> | DESTINATION <dir>
+ [FILE_PERMISSIONS permissions...]
+ [DIRECTORY_PERMISSIONS permissions...]
+ [USE_SOURCE_PERMISSIONS] [OPTIONAL] [MESSAGE_NEVER]
+ [CONFIGURATIONS [Debug|Release|...]]
+ [COMPONENT <component>] [EXCLUDE_FROM_ALL]
+ [FILES_MATCHING]
+ [[PATTERN <pattern> | REGEX <regex>]
+ [EXCLUDE] [PERMISSIONS permissions...]] [...])
+
+The ``DIRECTORY`` form installs contents of one or more directories to a
+given destination. The directory structure is copied verbatim to the
+destination. The last component of each directory name is appended to
+the destination directory but a trailing slash may be used to avoid
+this because it leaves the last component empty. Directory names
+given as relative paths are interpreted with respect to the current
+source directory. If no input directory names are given the
+destination directory will be created but nothing will be installed
+into it. The ``FILE_PERMISSIONS`` and ``DIRECTORY_PERMISSIONS`` options
+specify permissions given to files and directories in the destination.
+If ``USE_SOURCE_PERMISSIONS`` is specified and ``FILE_PERMISSIONS`` is not,
+file permissions will be copied from the source directory structure.
+If no permissions are specified files will be given the default
+permissions specified in the ``FILES`` form of the command, and the
+directories will be given the default permissions specified in the
+``PROGRAMS`` form of the command.
+
+.. versionadded:: 3.1
+ The ``MESSAGE_NEVER`` option disables file installation status output.
+
+Installation of directories may be controlled with fine granularity
+using the ``PATTERN`` or ``REGEX`` options. These "match" options specify a
+globbing pattern or regular expression to match directories or files
+encountered within input directories. They may be used to apply
+certain options (see below) to a subset of the files and directories
+encountered. The full path to each input file or directory (with
+forward slashes) is matched against the expression. A ``PATTERN`` will
+match only complete file names: the portion of the full path matching
+the pattern must occur at the end of the file name and be preceded by
+a slash. A ``REGEX`` will match any portion of the full path but it may
+use ``/`` and ``$`` to simulate the ``PATTERN`` behavior. By default all
+files and directories are installed whether or not they are matched.
+The ``FILES_MATCHING`` option may be given before the first match option
+to disable installation of files (but not directories) not matched by
+any expression. For example, the code
+
+.. code-block:: cmake
+
+ install(DIRECTORY src/ DESTINATION include/myproj
+ FILES_MATCHING PATTERN "*.h")
+
+will extract and install header files from a source tree.
+
+Some options may follow a ``PATTERN`` or ``REGEX`` expression and are applied
+only to files or directories matching them. The ``EXCLUDE`` option will
+skip the matched file or directory. The ``PERMISSIONS`` option overrides
+the permissions setting for the matched file or directory. For
+example the code
+
+.. code-block:: cmake
+
+ install(DIRECTORY icons scripts/ DESTINATION share/myproj
+ PATTERN "CVS" EXCLUDE
+ PATTERN "scripts/*"
+ PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
+ GROUP_EXECUTE GROUP_READ)
+
+will install the ``icons`` directory to ``share/myproj/icons`` and the
+``scripts`` directory to ``share/myproj``. The icons will get default
+file permissions, the scripts will be given specific permissions, and any
+``CVS`` directories will be excluded.
+
+Either a ``TYPE`` or a ``DESTINATION`` must be provided, but not both.
+A ``TYPE`` argument specifies the generic file type of the files within the
+listed directories being installed. A destination will then be set
+automatically by taking the corresponding variable from
+:module:`GNUInstallDirs`, or by using a built-in default if that variable
+is not defined. See the table below for the supported file types and their
+corresponding variables and built-in defaults. Projects can provide a
+``DESTINATION`` argument instead of a file type if they wish to explicitly
+define the install destination.
+
+======================= ================================== =========================
+ ``TYPE`` Argument GNUInstallDirs Variable Built-In Default
+======================= ================================== =========================
+``BIN`` ``${CMAKE_INSTALL_BINDIR}`` ``bin``
+``SBIN`` ``${CMAKE_INSTALL_SBINDIR}`` ``sbin``
+``LIB`` ``${CMAKE_INSTALL_LIBDIR}`` ``lib``
+``INCLUDE`` ``${CMAKE_INSTALL_INCLUDEDIR}`` ``include``
+``SYSCONF`` ``${CMAKE_INSTALL_SYSCONFDIR}`` ``etc``
+``SHAREDSTATE`` ``${CMAKE_INSTALL_SHARESTATEDIR}`` ``com``
+``LOCALSTATE`` ``${CMAKE_INSTALL_LOCALSTATEDIR}`` ``var``
+``RUNSTATE`` ``${CMAKE_INSTALL_RUNSTATEDIR}`` ``<LOCALSTATE dir>/run``
+``DATA`` ``${CMAKE_INSTALL_DATADIR}`` ``<DATAROOT dir>``
+``INFO`` ``${CMAKE_INSTALL_INFODIR}`` ``<DATAROOT dir>/info``
+``LOCALE`` ``${CMAKE_INSTALL_LOCALEDIR}`` ``<DATAROOT dir>/locale``
+``MAN`` ``${CMAKE_INSTALL_MANDIR}`` ``<DATAROOT dir>/man``
+``DOC`` ``${CMAKE_INSTALL_DOCDIR}`` ``<DATAROOT dir>/doc``
+======================= ================================== =========================
+
+Note that some of the types' built-in defaults use the ``DATAROOT`` directory as
+a prefix. The ``DATAROOT`` prefix is calculated similarly to the types, with
+``CMAKE_INSTALL_DATAROOTDIR`` as the variable and ``share`` as the built-in
+default. You cannot use ``DATAROOT`` as a ``TYPE`` parameter; please use
+``DATA`` instead.
+
+To make packages compliant with distribution filesystem layout policies, if
+projects must specify a ``DESTINATION``, it is recommended that they use a
+path that begins with the appropriate :module:`GNUInstallDirs` variable.
+This allows package maintainers to control the install destination by setting
+the appropriate cache variables.
+
+.. versionadded:: 3.4
+ An install destination given as a ``DESTINATION`` argument may
+ use "generator expressions" with the syntax ``$<...>``. See the
+ :manual:`cmake-generator-expressions(7)` manual for available expressions.
+
+.. versionadded:: 3.5
+ The list of ``dirs...`` given to ``DIRECTORY`` may use
+ "generator expressions" too.
+
+Custom Installation Logic
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. _`install(CODE)`:
+.. _`install(SCRIPT)`:
+.. _CODE:
+.. _SCRIPT:
+
+.. code-block:: cmake
+
+ install([[SCRIPT <file>] [CODE <code>]]
+ [COMPONENT <component>] [EXCLUDE_FROM_ALL] [...])
+
+The ``SCRIPT`` form will invoke the given CMake script files during
+installation. If the script file name is a relative path it will be
+interpreted with respect to the current source directory. The ``CODE``
+form will invoke the given CMake code during installation. Code is
+specified as a single argument inside a double-quoted string. For
+example, the code
+
+.. code-block:: cmake
+
+ install(CODE "MESSAGE(\"Sample install message.\")")
+
+will print a message during installation.
+
+.. versionadded:: 3.14
+ ``<file>`` or ``<code>`` may use "generator expressions" with the syntax
+ ``$<...>`` (in the case of ``<file>``, this refers to their use in the file
+ name, not the file's contents). See the
+ :manual:`cmake-generator-expressions(7)` manual for available expressions.
+
+Installing Exports
+^^^^^^^^^^^^^^^^^^
+
+.. _`install(EXPORT)`:
+.. _EXPORT:
+
+.. code-block:: cmake
+
+ install(EXPORT <export-name> DESTINATION <dir>
+ [NAMESPACE <namespace>] [[FILE <name>.cmake]|
+ [PERMISSIONS permissions...]
+ [CONFIGURATIONS [Debug|Release|...]]
+ [EXPORT_LINK_INTERFACE_LIBRARIES]
+ [COMPONENT <component>]
+ [EXCLUDE_FROM_ALL])
+ install(EXPORT_ANDROID_MK <export-name> DESTINATION <dir> [...])
+
+The ``EXPORT`` form generates and installs a CMake file containing code to
+import targets from the installation tree into another project.
+Target installations are associated with the export ``<export-name>``
+using the ``EXPORT`` option of the `install(TARGETS)`_ signature
+documented above. The ``NAMESPACE`` option will prepend ``<namespace>`` to
+the target names as they are written to the import file. By default
+the generated file will be called ``<export-name>.cmake`` but the ``FILE``
+option may be used to specify a different name. The value given to
+the ``FILE`` option must be a file name with the ``.cmake`` extension.
+If a ``CONFIGURATIONS`` option is given then the file will only be installed
+when one of the named configurations is installed. Additionally, the
+generated import file will reference only the matching target
+configurations. The ``EXPORT_LINK_INTERFACE_LIBRARIES`` keyword, if
+present, causes the contents of the properties matching
+``(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)?`` to be exported, when
+policy :policy:`CMP0022` is ``NEW``.
+
+.. note::
+ The installed ``<export-name>.cmake`` file may come with additional
+ per-configuration ``<export-name>-*.cmake`` files to be loaded by
+ globbing. Do not use an export name that is the same as the package
+ name in combination with installing a ``<package-name>-config.cmake``
+ file or the latter may be incorrectly matched by the glob and loaded.
+
+When a ``COMPONENT`` option is given, the listed ``<component>`` implicitly
+depends on all components mentioned in the export set. The exported
+``<name>.cmake`` file will require each of the exported components to be
+present in order for dependent projects to build properly. For example, a
+project may define components ``Runtime`` and ``Development``, with shared
+libraries going into the ``Runtime`` component and static libraries and
+headers going into the ``Development`` component. The export set would also
+typically be part of the ``Development`` component, but it would export
+targets from both the ``Runtime`` and ``Development`` components. Therefore,
+the ``Runtime`` component would need to be installed if the ``Development``
+component was installed, but not vice versa. If the ``Development`` component
+was installed without the ``Runtime`` component, dependent projects that try
+to link against it would have build errors. Package managers, such as APT and
+RPM, typically handle this by listing the ``Runtime`` component as a dependency
+of the ``Development`` component in the package metadata, ensuring that the
+library is always installed if the headers and CMake export file are present.
+
+.. versionadded:: 3.7
+ In addition to cmake language files, the ``EXPORT_ANDROID_MK`` mode maybe
+ used to specify an export to the android ndk build system. This mode
+ accepts the same options as the normal export mode. The Android
+ NDK supports the use of prebuilt libraries, both static and shared. This
+ allows cmake to build the libraries of a project and make them available
+ to an ndk build system complete with transitive dependencies, include flags
+ and defines required to use the libraries.
+
+The ``EXPORT`` form is useful to help outside projects use targets built
+and installed by the current project. For example, the code
+
+.. code-block:: cmake
+
+ install(TARGETS myexe EXPORT myproj DESTINATION bin)
+ install(EXPORT myproj NAMESPACE mp_ DESTINATION lib/myproj)
+ install(EXPORT_ANDROID_MK myproj DESTINATION share/ndk-modules)
+
+will install the executable ``myexe`` to ``<prefix>/bin`` and code to import
+it in the file ``<prefix>/lib/myproj/myproj.cmake`` and
+``<prefix>/share/ndk-modules/Android.mk``. An outside project
+may load this file with the include command and reference the ``myexe``
+executable from the installation tree using the imported target name
+``mp_myexe`` as if the target were built in its own tree.
+
+.. note::
+ This command supercedes the :command:`install_targets` command and
+ the :prop_tgt:`PRE_INSTALL_SCRIPT` and :prop_tgt:`POST_INSTALL_SCRIPT`
+ target properties. It also replaces the ``FILES`` forms of the
+ :command:`install_files` and :command:`install_programs` commands.
+ The processing order of these install rules relative to
+ those generated by :command:`install_targets`,
+ :command:`install_files`, and :command:`install_programs` commands
+ is not defined.
+
+Generated Installation Script
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. note::
+
+ Use of this feature is not recommended. Please consider using the
+ ``--install`` argument of :manual:`cmake(1)` instead.
+
+The ``install()`` command generates a file, ``cmake_install.cmake``, inside
+the build directory, which is used internally by the generated install target
+and by CPack. You can also invoke this script manually with ``cmake -P``. This
+script accepts several variables:
+
+``COMPONENT``
+ Set this variable to install only a single CPack component as opposed to all
+ of them. For example, if you only want to install the ``Development``
+ component, run ``cmake -DCOMPONENT=Development -P cmake_install.cmake``.
+
+``BUILD_TYPE``
+ Set this variable to change the build type if you are using a multi-config
+ generator. For example, to install with the ``Debug`` configuration, run
+ ``cmake -DBUILD_TYPE=Debug -P cmake_install.cmake``.
+
+``DESTDIR``
+ This is an environment variable rather than a CMake variable. It allows you
+ to change the installation prefix on UNIX systems. See :envvar:`DESTDIR` for
+ details.
diff --git a/Help/command/install_files.rst b/Help/command/install_files.rst
new file mode 100644
index 0000000..ff074a8
--- /dev/null
+++ b/Help/command/install_files.rst
@@ -0,0 +1,41 @@
+install_files
+-------------
+
+.. deprecated:: 3.0
+
+ Use the :command:`install(FILES)` command instead.
+
+This command has been superceded by the :command:`install` command. It is
+provided for compatibility with older CMake code. The ``FILES`` form is
+directly replaced by the ``FILES`` form of the :command:`install`
+command. The regexp form can be expressed more clearly using the ``GLOB``
+form of the :command:`file` command.
+
+::
+
+ install_files(<dir> extension file file ...)
+
+Create rules to install the listed files with the given extension into
+the given directory. Only files existing in the current source tree
+or its corresponding location in the binary tree may be listed. If a
+file specified already has an extension, that extension will be
+removed first. This is useful for providing lists of source files
+such as foo.cxx when you want the corresponding foo.h to be installed.
+A typical extension is ``.h``.
+
+::
+
+ install_files(<dir> regexp)
+
+Any files in the current source directory that match the regular
+expression will be installed.
+
+::
+
+ install_files(<dir> FILES file file ...)
+
+Any files listed after the ``FILES`` keyword will be installed explicitly
+from the names given. Full paths are allowed in this form.
+
+The directory ``<dir>`` is relative to the installation prefix, which is
+stored in the variable :variable:`CMAKE_INSTALL_PREFIX`.
diff --git a/Help/command/install_programs.rst b/Help/command/install_programs.rst
new file mode 100644
index 0000000..fab6482
--- /dev/null
+++ b/Help/command/install_programs.rst
@@ -0,0 +1,36 @@
+install_programs
+----------------
+
+.. deprecated:: 3.0
+
+ Use the :command:`install(PROGRAMS)` command instead.
+
+This command has been superceded by the :command:`install` command. It is
+provided for compatibility with older CMake code. The ``FILES`` form is
+directly replaced by the ``PROGRAMS`` form of the :command:`install`
+command. The regexp form can be expressed more clearly using the ``GLOB``
+form of the :command:`file` command.
+
+::
+
+ install_programs(<dir> file1 file2 [file3 ...])
+ install_programs(<dir> FILES file1 [file2 ...])
+
+Create rules to install the listed programs into the given directory.
+Use the ``FILES`` argument to guarantee that the file list version of the
+command will be used even when there is only one argument.
+
+::
+
+ install_programs(<dir> regexp)
+
+In the second form any program in the current source directory that
+matches the regular expression will be installed.
+
+This command is intended to install programs that are not built by
+cmake, such as shell scripts. See the ``TARGETS`` form of the
+:command:`install` command to create installation rules for targets built
+by cmake.
+
+The directory ``<dir>`` is relative to the installation prefix, which is
+stored in the variable :variable:`CMAKE_INSTALL_PREFIX`.
diff --git a/Help/command/install_targets.rst b/Help/command/install_targets.rst
new file mode 100644
index 0000000..c9efdce
--- /dev/null
+++ b/Help/command/install_targets.rst
@@ -0,0 +1,19 @@
+install_targets
+---------------
+
+.. deprecated:: 3.0
+
+ Use the :command:`install(TARGETS)` command instead.
+
+This command has been superceded by the :command:`install` command. It is
+provided for compatibility with older CMake code.
+
+::
+
+ install_targets(<dir> [RUNTIME_DIRECTORY dir] target target)
+
+Create rules to install the listed targets into the given directory.
+The directory ``<dir>`` is relative to the installation prefix, which is
+stored in the variable :variable:`CMAKE_INSTALL_PREFIX`. If
+``RUNTIME_DIRECTORY`` is specified, then on systems with special runtime
+files (Windows DLL), the files will be copied to that directory.
diff --git a/Help/command/link_directories.rst b/Help/command/link_directories.rst
new file mode 100644
index 0000000..6732402
--- /dev/null
+++ b/Help/command/link_directories.rst
@@ -0,0 +1,55 @@
+link_directories
+----------------
+
+Add directories in which the linker will look for libraries.
+
+.. code-block:: cmake
+
+ link_directories([AFTER|BEFORE] directory1 [directory2 ...])
+
+Adds the paths in which the linker should search for libraries.
+Relative paths given to this command are interpreted as relative to
+the current source directory, see :policy:`CMP0015`.
+
+The command will apply only to targets created after it is called.
+
+.. versionadded:: 3.13
+ The directories are added to the :prop_dir:`LINK_DIRECTORIES` directory
+ property for the current ``CMakeLists.txt`` file, converting relative
+ paths to absolute as needed. See the :manual:`cmake-buildsystem(7)`
+ manual for more on defining buildsystem properties.
+
+.. versionadded:: 3.13
+ By default the directories specified are appended onto the current list of
+ directories. This default behavior can be changed by setting
+ :variable:`CMAKE_LINK_DIRECTORIES_BEFORE` to ``ON``. By using
+ ``AFTER`` or ``BEFORE`` explicitly, you can select between appending and
+ prepending, independent of the default.
+
+.. versionadded:: 3.13
+ Arguments to ``link_directories`` may use "generator expressions" with
+ the syntax "$<...>". See the :manual:`cmake-generator-expressions(7)`
+ manual for available expressions.
+
+.. note::
+
+ This command is rarely necessary and should be avoided where there are
+ other choices. Prefer to pass full absolute paths to libraries where
+ possible, since this ensures the correct library will always be linked.
+ The :command:`find_library` command provides the full path, which can
+ generally be used directly in calls to :command:`target_link_libraries`.
+ Situations where a library search path may be needed include:
+
+ - Project generators like Xcode where the user can switch target
+ architecture at build time, but a full path to a library cannot
+ be used because it only provides one architecture (i.e. it is not
+ a universal binary).
+ - Libraries may themselves have other private library dependencies
+ that expect to be found via ``RPATH`` mechanisms, but some linkers
+ are not able to fully decode those paths (e.g. due to the presence
+ of things like ``$ORIGIN``).
+
+ If a library search path must be provided, prefer to localize the effect
+ where possible by using the :command:`target_link_directories` command
+ rather than ``link_directories()``. The target-specific command can also
+ control how the search directories propagate to other dependent targets.
diff --git a/Help/command/link_libraries.rst b/Help/command/link_libraries.rst
new file mode 100644
index 0000000..8665cb7
--- /dev/null
+++ b/Help/command/link_libraries.rst
@@ -0,0 +1,19 @@
+link_libraries
+--------------
+
+Link libraries to all targets added later.
+
+.. code-block:: cmake
+
+ link_libraries([item1 [item2 [...]]]
+ [[debug|optimized|general] <item>] ...)
+
+Specify libraries or flags to use when linking any targets created later in
+the current directory or below by commands such as :command:`add_executable`
+or :command:`add_library`. See the :command:`target_link_libraries` command
+for meaning of arguments.
+
+.. note::
+ The :command:`target_link_libraries` command should be preferred whenever
+ possible. Library dependencies are chained automatically, so directory-wide
+ specification of link libraries is rarely needed.
diff --git a/Help/command/list.rst b/Help/command/list.rst
new file mode 100644
index 0000000..7accc5a
--- /dev/null
+++ b/Help/command/list.rst
@@ -0,0 +1,353 @@
+list
+----
+
+List operations.
+
+Synopsis
+^^^^^^^^
+
+.. parsed-literal::
+
+ `Reading`_
+ list(`LENGTH`_ <list> <out-var>)
+ list(`GET`_ <list> <element index> [<index> ...] <out-var>)
+ list(`JOIN`_ <list> <glue> <out-var>)
+ list(`SUBLIST`_ <list> <begin> <length> <out-var>)
+
+ `Search`_
+ list(`FIND`_ <list> <value> <out-var>)
+
+ `Modification`_
+ list(`APPEND`_ <list> [<element>...])
+ list(`FILTER`_ <list> {INCLUDE | EXCLUDE} REGEX <regex>)
+ list(`INSERT`_ <list> <index> [<element>...])
+ list(`POP_BACK`_ <list> [<out-var>...])
+ list(`POP_FRONT`_ <list> [<out-var>...])
+ list(`PREPEND`_ <list> [<element>...])
+ list(`REMOVE_ITEM`_ <list> <value>...)
+ list(`REMOVE_AT`_ <list> <index>...)
+ list(`REMOVE_DUPLICATES`_ <list>)
+ list(`TRANSFORM`_ <list> <ACTION> [...])
+
+ `Ordering`_
+ list(`REVERSE`_ <list>)
+ list(`SORT`_ <list> [...])
+
+Introduction
+^^^^^^^^^^^^
+
+The list subcommands ``APPEND``, ``INSERT``, ``FILTER``, ``PREPEND``,
+``POP_BACK``, ``POP_FRONT``, ``REMOVE_AT``, ``REMOVE_ITEM``,
+``REMOVE_DUPLICATES``, ``REVERSE`` and ``SORT`` may create
+new values for the list within the current CMake variable scope. Similar to
+the :command:`set` command, the LIST command creates new variable values in
+the current scope, even if the list itself is actually defined in a parent
+scope. To propagate the results of these operations upwards, use
+:command:`set` with ``PARENT_SCOPE``, :command:`set` with
+``CACHE INTERNAL``, or some other means of value propagation.
+
+.. note::
+
+ A list in cmake is a ``;`` separated group of strings. To create a
+ list the set command can be used. For example, ``set(var a b c d e)``
+ creates a list with ``a;b;c;d;e``, and ``set(var "a b c d e")`` creates a
+ string or a list with one item in it. (Note macro arguments are not
+ variables, and therefore cannot be used in LIST commands.)
+
+.. note::
+
+ When specifying index values, if ``<element index>`` is 0 or greater, it
+ is indexed from the beginning of the list, with 0 representing the
+ first list element. If ``<element index>`` is -1 or lesser, it is indexed
+ from the end of the list, with -1 representing the last list element.
+ Be careful when counting with negative indices: they do not start from
+ 0. -0 is equivalent to 0, the first list element.
+
+Reading
+^^^^^^^
+
+.. _LENGTH:
+
+.. code-block:: cmake
+
+ list(LENGTH <list> <output variable>)
+
+Returns the list's length.
+
+.. _GET:
+
+.. code-block:: cmake
+
+ list(GET <list> <element index> [<element index> ...] <output variable>)
+
+Returns the list of elements specified by indices from the list.
+
+.. _JOIN:
+
+.. code-block:: cmake
+
+ list(JOIN <list> <glue> <output variable>)
+
+.. versionadded:: 3.12
+
+Returns a string joining all list's elements using the glue string.
+To join multiple strings, which are not part of a list, use ``JOIN`` operator
+from :command:`string` command.
+
+.. _SUBLIST:
+
+.. code-block:: cmake
+
+ list(SUBLIST <list> <begin> <length> <output variable>)
+
+.. versionadded:: 3.12
+
+Returns a sublist of the given list.
+If ``<length>`` is 0, an empty list will be returned.
+If ``<length>`` is -1 or the list is smaller than ``<begin>+<length>`` then
+the remaining elements of the list starting at ``<begin>`` will be returned.
+
+Search
+^^^^^^
+
+.. _FIND:
+
+.. code-block:: cmake
+
+ list(FIND <list> <value> <output variable>)
+
+Returns the index of the element specified in the list or -1
+if it wasn't found.
+
+Modification
+^^^^^^^^^^^^
+
+.. _APPEND:
+
+.. code-block:: cmake
+
+ list(APPEND <list> [<element> ...])
+
+Appends elements to the list.
+
+.. _FILTER:
+
+.. code-block:: cmake
+
+ list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regular_expression>)
+
+.. versionadded:: 3.6
+
+Includes or removes items from the list that match the mode's pattern.
+In ``REGEX`` mode, items will be matched against the given regular expression.
+
+For more information on regular expressions see also the
+:command:`string` command.
+
+.. _INSERT:
+
+.. code-block:: cmake
+
+ list(INSERT <list> <element_index> <element> [<element> ...])
+
+Inserts elements to the list to the specified location.
+
+.. _POP_BACK:
+
+.. code-block:: cmake
+
+ list(POP_BACK <list> [<out-var>...])
+
+.. versionadded:: 3.15
+
+If no variable name is given, removes exactly one element. Otherwise,
+assign the last element's value to the given variable and removes it,
+up to the last variable name given.
+
+.. _POP_FRONT:
+
+.. code-block:: cmake
+
+ list(POP_FRONT <list> [<out-var>...])
+
+.. versionadded:: 3.15
+
+If no variable name is given, removes exactly one element. Otherwise,
+assign the first element's value to the given variable and removes it,
+up to the last variable name given.
+
+.. _PREPEND:
+
+.. code-block:: cmake
+
+ list(PREPEND <list> [<element> ...])
+
+.. versionadded:: 3.15
+
+Insert elements to the 0th position in the list.
+
+.. _REMOVE_ITEM:
+
+.. code-block:: cmake
+
+ list(REMOVE_ITEM <list> <value> [<value> ...])
+
+Removes all instances of the given items from the list.
+
+.. _REMOVE_AT:
+
+.. code-block:: cmake
+
+ list(REMOVE_AT <list> <index> [<index> ...])
+
+Removes items at given indices from the list.
+
+.. _REMOVE_DUPLICATES:
+
+.. code-block:: cmake
+
+ list(REMOVE_DUPLICATES <list>)
+
+Removes duplicated items in the list. The relative order of items is preserved,
+but if duplicates are encountered, only the first instance is preserved.
+
+.. _TRANSFORM:
+
+.. code-block:: cmake
+
+ list(TRANSFORM <list> <ACTION> [<SELECTOR>]
+ [OUTPUT_VARIABLE <output variable>])
+
+.. versionadded:: 3.12
+
+Transforms the list by applying an action to all or, by specifying a
+``<SELECTOR>``, to the selected elements of the list, storing the result
+in-place or in the specified output variable.
+
+.. note::
+
+ The ``TRANSFORM`` sub-command does not change the number of elements in the
+ list. If a ``<SELECTOR>`` is specified, only some elements will be changed,
+ the other ones will remain the same as before the transformation.
+
+``<ACTION>`` specifies the action to apply to the elements of the list.
+The actions have exactly the same semantics as sub-commands of the
+:command:`string` command. ``<ACTION>`` must be one of the following:
+
+``APPEND``, ``PREPEND``: Append, prepend specified value to each element of
+the list.
+
+ .. code-block:: cmake
+
+ list(TRANSFORM <list> <APPEND|PREPEND> <value> ...)
+
+``TOUPPER``, ``TOLOWER``: Convert each element of the list to upper, lower
+characters.
+
+ .. code-block:: cmake
+
+ list(TRANSFORM <list> <TOLOWER|TOUPPER> ...)
+
+``STRIP``: Remove leading and trailing spaces from each element of the
+list.
+
+ .. code-block:: cmake
+
+ list(TRANSFORM <list> STRIP ...)
+
+``GENEX_STRIP``: Strip any
+:manual:`generator expressions <cmake-generator-expressions(7)>` from each
+element of the list.
+
+ .. code-block:: cmake
+
+ list(TRANSFORM <list> GENEX_STRIP ...)
+
+``REPLACE``: Match the regular expression as many times as possible and
+substitute the replacement expression for the match for each element
+of the list
+(Same semantic as ``REGEX REPLACE`` from :command:`string` command).
+
+ .. code-block:: cmake
+
+ list(TRANSFORM <list> REPLACE <regular_expression>
+ <replace_expression> ...)
+
+``<SELECTOR>`` determines which elements of the list will be transformed.
+Only one type of selector can be specified at a time. When given,
+``<SELECTOR>`` must be one of the following:
+
+``AT``: Specify a list of indexes.
+
+ .. code-block:: cmake
+
+ list(TRANSFORM <list> <ACTION> AT <index> [<index> ...] ...)
+
+``FOR``: Specify a range with, optionally, an increment used to iterate over
+the range.
+
+ .. code-block:: cmake
+
+ list(TRANSFORM <list> <ACTION> FOR <start> <stop> [<step>] ...)
+
+``REGEX``: Specify a regular expression. Only elements matching the regular
+expression will be transformed.
+
+ .. code-block:: cmake
+
+ list(TRANSFORM <list> <ACTION> REGEX <regular_expression> ...)
+
+
+Ordering
+^^^^^^^^
+
+.. _REVERSE:
+
+.. code-block:: cmake
+
+ list(REVERSE <list>)
+
+Reverses the contents of the list in-place.
+
+.. _SORT:
+
+.. code-block:: cmake
+
+ list(SORT <list> [COMPARE <compare>] [CASE <case>] [ORDER <order>])
+
+Sorts the list in-place alphabetically.
+
+.. versionadded:: 3.13
+ Added the ``COMPARE``, ``CASE``, and ``ORDER`` options.
+
+.. versionadded:: 3.18
+ Added the ``COMPARE NATURAL`` option.
+
+Use the ``COMPARE`` keyword to select the comparison method for sorting.
+The ``<compare>`` option should be one of:
+
+* ``STRING``: Sorts a list of strings alphabetically. This is the
+ default behavior if the ``COMPARE`` option is not given.
+* ``FILE_BASENAME``: Sorts a list of pathnames of files by their basenames.
+* ``NATURAL``: Sorts a list of strings using natural order
+ (see ``strverscmp(3)`` manual), i.e. such that contiguous digits
+ are compared as whole numbers.
+ For example: the following list `10.0 1.1 2.1 8.0 2.0 3.1`
+ will be sorted as `1.1 2.0 2.1 3.1 8.0 10.0` if the ``NATURAL``
+ comparison is selected where it will be sorted as
+ `1.1 10.0 2.0 2.1 3.1 8.0` with the ``STRING`` comparison.
+
+Use the ``CASE`` keyword to select a case sensitive or case insensitive
+sort mode. The ``<case>`` option should be one of:
+
+* ``SENSITIVE``: List items are sorted in a case-sensitive manner. This is
+ the default behavior if the ``CASE`` option is not given.
+* ``INSENSITIVE``: List items are sorted case insensitively. The order of
+ items which differ only by upper/lowercase is not specified.
+
+To control the sort order, the ``ORDER`` keyword can be given.
+The ``<order>`` option should be one of:
+
+* ``ASCENDING``: Sorts the list in ascending order. This is the default
+ behavior when the ``ORDER`` option is not given.
+* ``DESCENDING``: Sorts the list in descending order.
diff --git a/Help/command/load_cache.rst b/Help/command/load_cache.rst
new file mode 100644
index 0000000..b89eb61
--- /dev/null
+++ b/Help/command/load_cache.rst
@@ -0,0 +1,26 @@
+load_cache
+----------
+
+Load in the values from another project's CMake cache.
+
+.. code-block:: cmake
+
+ load_cache(pathToBuildDirectory READ_WITH_PREFIX prefix entry1...)
+
+Reads the cache and store the requested entries in variables with their
+name prefixed with the given prefix. This only reads the values, and
+does not create entries in the local project's cache.
+
+.. code-block:: cmake
+
+ load_cache(pathToBuildDirectory [EXCLUDE entry1...]
+ [INCLUDE_INTERNALS entry1...])
+
+Loads in the values from another cache and store them in the local
+project's cache as internal entries. This is useful for a project
+that depends on another project built in a different tree. ``EXCLUDE``
+option can be used to provide a list of entries to be excluded.
+``INCLUDE_INTERNALS`` can be used to provide a list of internal entries to
+be included. Normally, no internal entries are brought in. Use of
+this form of the command is strongly discouraged, but it is provided
+for backward compatibility.
diff --git a/Help/command/load_command.rst b/Help/command/load_command.rst
new file mode 100644
index 0000000..dc23599
--- /dev/null
+++ b/Help/command/load_command.rst
@@ -0,0 +1,23 @@
+load_command
+------------
+
+Disallowed since version 3.0. See CMake Policy :policy:`CMP0031`.
+
+Load a command into a running CMake.
+
+::
+
+ load_command(COMMAND_NAME <loc1> [loc2 ...])
+
+The given locations are searched for a library whose name is
+cmCOMMAND_NAME. If found, it is loaded as a module and the command is
+added to the set of available CMake commands. Usually,
+:command:`try_compile` is used before this command to compile the
+module. If the command is successfully loaded a variable named
+
+::
+
+ CMAKE_LOADED_COMMAND_<COMMAND_NAME>
+
+will be set to the full path of the module that was loaded. Otherwise
+the variable will not be set.
diff --git a/Help/command/macro.rst b/Help/command/macro.rst
new file mode 100644
index 0000000..5fe4c00
--- /dev/null
+++ b/Help/command/macro.rst
@@ -0,0 +1,151 @@
+macro
+-----
+
+Start recording a macro for later invocation as a command
+
+.. code-block:: cmake
+
+ macro(<name> [<arg1> ...])
+ <commands>
+ endmacro()
+
+Defines a macro named ``<name>`` that takes arguments named
+``<arg1>``, ... Commands listed after macro, but before the
+matching :command:`endmacro()`, are not executed until the macro
+is invoked.
+
+Per legacy, the :command:`endmacro` command admits an optional
+``<name>`` argument. If used, it must be a verbatim repeat of the
+argument of the opening ``macro`` command.
+
+See the :command:`cmake_policy()` command documentation for the behavior
+of policies inside macros.
+
+See the :ref:`Macro vs Function` section below for differences
+between CMake macros and :command:`functions <function>`.
+
+Invocation
+^^^^^^^^^^
+
+The macro invocation is case-insensitive. A macro defined as
+
+.. code-block:: cmake
+
+ macro(foo)
+ <commands>
+ endmacro()
+
+can be invoked through any of
+
+.. code-block:: cmake
+
+ foo()
+ Foo()
+ FOO()
+ cmake_language(CALL foo)
+
+and so on. However, it is strongly recommended to stay with the
+case chosen in the macro definition. Typically macros use
+all-lowercase names.
+
+.. versionadded:: 3.18
+ The :command:`cmake_language(CALL ...)` command can also be used to
+ invoke the macro.
+
+Arguments
+^^^^^^^^^
+
+When a macro is invoked, the commands recorded in the macro are
+first modified by replacing formal parameters (``${arg1}``, ...)
+with the arguments passed, and then invoked as normal commands.
+
+In addition to referencing the formal parameters you can reference the
+values ``${ARGC}`` which will be set to the number of arguments passed
+into the function as well as ``${ARGV0}``, ``${ARGV1}``, ``${ARGV2}``,
+... which will have the actual values of the arguments passed in.
+This facilitates creating macros with optional arguments.
+
+Furthermore, ``${ARGV}`` holds the list of all arguments given to the
+macro and ``${ARGN}`` holds the list of arguments past the last expected
+argument.
+Referencing to ``${ARGV#}`` arguments beyond ``${ARGC}`` have undefined
+behavior. Checking that ``${ARGC}`` is greater than ``#`` is the only
+way to ensure that ``${ARGV#}`` was passed to the function as an extra
+argument.
+
+.. _`Macro vs Function`:
+
+Macro vs Function
+^^^^^^^^^^^^^^^^^
+
+The ``macro`` command is very similar to the :command:`function` command.
+Nonetheless, there are a few important differences.
+
+In a function, ``ARGN``, ``ARGC``, ``ARGV`` and ``ARGV0``, ``ARGV1``, ...
+are true variables in the usual CMake sense. In a macro, they are not,
+they are string replacements much like the C preprocessor would do
+with a macro. This has a number of consequences, as explained in
+the :ref:`Argument Caveats` section below.
+
+Another difference between macros and functions is the control flow.
+A function is executed by transferring control from the calling
+statement to the function body. A macro is executed as if the macro
+body were pasted in place of the calling statement. This has the
+consequence that a :command:`return()` in a macro body does not
+just terminate execution of the macro; rather, control is returned
+from the scope of the macro call. To avoid confusion, it is recommended
+to avoid :command:`return()` in macros altogether.
+
+Unlike a function, the :variable:`CMAKE_CURRENT_FUNCTION`,
+:variable:`CMAKE_CURRENT_FUNCTION_LIST_DIR`,
+:variable:`CMAKE_CURRENT_FUNCTION_LIST_FILE`,
+:variable:`CMAKE_CURRENT_FUNCTION_LIST_LINE` variables are not
+set for a macro.
+
+.. _`Argument Caveats`:
+
+Argument Caveats
+^^^^^^^^^^^^^^^^
+
+Since ``ARGN``, ``ARGC``, ``ARGV``, ``ARGV0`` etc. are not variables,
+you will NOT be able to use commands like
+
+.. code-block:: cmake
+
+ if(ARGV1) # ARGV1 is not a variable
+ if(DEFINED ARGV2) # ARGV2 is not a variable
+ if(ARGC GREATER 2) # ARGC is not a variable
+ foreach(loop_var IN LISTS ARGN) # ARGN is not a variable
+
+In the first case, you can use ``if(${ARGV1})``. In the second and
+third case, the proper way to check if an optional variable was
+passed to the macro is to use ``if(${ARGC} GREATER 2)``. In the
+last case, you can use ``foreach(loop_var ${ARGN})`` but this will
+skip empty arguments. If you need to include them, you can use
+
+.. code-block:: cmake
+
+ set(list_var "${ARGN}")
+ foreach(loop_var IN LISTS list_var)
+
+Note that if you have a variable with the same name in the scope from
+which the macro is called, using unreferenced names will use the
+existing variable instead of the arguments. For example:
+
+.. code-block:: cmake
+
+ macro(bar)
+ foreach(arg IN LISTS ARGN)
+ <commands>
+ endforeach()
+ endmacro()
+
+ function(foo)
+ bar(x y z)
+ endfunction()
+
+ foo(a b c)
+
+Will loop over ``a;b;c`` and not over ``x;y;z`` as one might have expected.
+If you want true CMake variables and/or better CMake scope control you
+should look at the function command.
diff --git a/Help/command/make_directory.rst b/Help/command/make_directory.rst
new file mode 100644
index 0000000..8469b0a
--- /dev/null
+++ b/Help/command/make_directory.rst
@@ -0,0 +1,14 @@
+make_directory
+--------------
+
+.. deprecated:: 3.0
+
+ Use the :command:`file(MAKE_DIRECTORY)` command instead.
+
+::
+
+ make_directory(directory)
+
+Creates the specified directory. Full paths should be given. Any
+parent directories that do not exist will also be created. Use with
+care.
diff --git a/Help/command/mark_as_advanced.rst b/Help/command/mark_as_advanced.rst
new file mode 100644
index 0000000..201363f
--- /dev/null
+++ b/Help/command/mark_as_advanced.rst
@@ -0,0 +1,28 @@
+mark_as_advanced
+----------------
+
+Mark cmake cached variables as advanced.
+
+.. code-block:: cmake
+
+ mark_as_advanced([CLEAR|FORCE] <var1> ...)
+
+Sets the advanced/non-advanced state of the named
+cached variables.
+
+An advanced variable will not be displayed in any
+of the cmake GUIs unless the ``show advanced`` option is on.
+In script mode, the advanced/non-advanced state has no effect.
+
+If the keyword ``CLEAR`` is given
+then advanced variables are changed back to unadvanced.
+If the keyword ``FORCE`` is given
+then the variables are made advanced.
+If neither ``FORCE`` nor ``CLEAR`` is specified,
+new values will be marked as advanced, but if a
+variable already has an advanced/non-advanced state,
+it will not be changed.
+
+.. versionchanged:: 3.17
+ Variables passed to this command which are not already in the cache
+ are ignored. See policy :policy:`CMP0102`.
diff --git a/Help/command/math.rst b/Help/command/math.rst
new file mode 100644
index 0000000..8386aab
--- /dev/null
+++ b/Help/command/math.rst
@@ -0,0 +1,38 @@
+math
+----
+
+Evaluate a mathematical expression.
+
+.. code-block:: cmake
+
+ math(EXPR <variable> "<expression>" [OUTPUT_FORMAT <format>])
+
+Evaluates a mathematical ``<expression>`` and sets ``<variable>`` to the
+resulting value. The result of the expression must be representable as a
+64-bit signed integer.
+
+The mathematical expression must be given as a string (i.e. enclosed in
+double quotation marks). An example is ``"5 * (10 + 13)"``.
+Supported operators are ``+``, ``-``, ``*``, ``/``, ``%``, ``|``, ``&``,
+``^``, ``~``, ``<<``, ``>>``, and ``(...)``; they have the same meaning
+as in C code.
+
+.. versionadded:: 3.13
+ Hexadecimal numbers are recognized when prefixed with ``0x``, as in C code.
+
+.. versionadded:: 3.13
+ The result is formatted according to the option ``OUTPUT_FORMAT``,
+ where ``<format>`` is one of
+
+ ``HEXADECIMAL``
+ Hexadecimal notation as in C code, i. e. starting with "0x".
+ ``DECIMAL``
+ Decimal notation. Which is also used if no ``OUTPUT_FORMAT`` option
+ is specified.
+
+For example
+
+.. code-block:: cmake
+
+ math(EXPR value "100 * 0xA" OUTPUT_FORMAT DECIMAL) # value is set to "1000"
+ math(EXPR value "100 * 0xA" OUTPUT_FORMAT HEXADECIMAL) # value is set to "0x3e8"
diff --git a/Help/command/message.rst b/Help/command/message.rst
new file mode 100644
index 0000000..e44803e
--- /dev/null
+++ b/Help/command/message.rst
@@ -0,0 +1,191 @@
+message
+-------
+
+Log a message.
+
+Synopsis
+^^^^^^^^
+
+.. parsed-literal::
+
+ `General messages`_
+ message([<mode>] "message text" ...)
+
+ `Reporting checks`_
+ message(<checkState> "message text" ...)
+
+
+General messages
+^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ message([<mode>] "message text" ...)
+
+Record the specified message text in the log. If more than one message
+string is given, they are concatenated into a single message with no
+separator between the strings.
+
+The optional ``<mode>`` keyword determines the type of message, which
+influences the way the message is handled:
+
+``FATAL_ERROR``
+ CMake Error, stop processing and generation.
+
+``SEND_ERROR``
+ CMake Error, continue processing, but skip generation.
+
+``WARNING``
+ CMake Warning, continue processing.
+
+``AUTHOR_WARNING``
+ CMake Warning (dev), continue processing.
+
+``DEPRECATION``
+ CMake Deprecation Error or Warning if variable
+ :variable:`CMAKE_ERROR_DEPRECATED` or :variable:`CMAKE_WARN_DEPRECATED`
+ is enabled, respectively, else no message.
+
+(none) or ``NOTICE``
+ Important message printed to stderr to attract user's attention.
+
+``STATUS``
+ The main interesting messages that project users might be interested in.
+ Ideally these should be concise, no more than a single line, but still
+ informative.
+
+``VERBOSE``
+ Detailed informational messages intended for project users. These messages
+ should provide additional details that won't be of interest in most cases,
+ but which may be useful to those building the project when they want deeper
+ insight into what's happening.
+
+``DEBUG``
+ Detailed informational messages intended for developers working on the
+ project itself as opposed to users who just want to build it. These messages
+ will not typically be of interest to other users building the project and
+ will often be closely related to internal implementation details.
+
+``TRACE``
+ Fine-grained messages with very low-level implementation details. Messages
+ using this log level would normally only be temporary and would expect to be
+ removed before releasing the project, packaging up the files, etc.
+
+.. versionadded:: 3.15
+ Added the ``NOTICE``, ``VERBOSE``, ``DEBUG``, and ``TRACE`` levels.
+
+The CMake command-line tool displays ``STATUS`` to ``TRACE`` messages on stdout
+with the message preceded by two hyphens and a space. All other message types
+are sent to stderr and are not prefixed with hyphens. The
+:manual:`CMake GUI <cmake-gui(1)>` displays all messages in its log area.
+The :manual:`curses interface <ccmake(1)>` shows ``STATUS`` to ``TRACE``
+messages one at a time on a status line and other messages in an
+interactive pop-up box. The ``--log-level`` command-line option to each of
+these tools can be used to control which messages will be shown.
+
+.. versionadded:: 3.17
+ To make a log level persist between CMake runs, the
+ :variable:`CMAKE_MESSAGE_LOG_LEVEL` variable can be set instead.
+ Note that the command line option takes precedence over the cache variable.
+
+.. versionadded:: 3.16
+ Messages of log levels ``NOTICE`` and below will have each line preceded
+ by the content of the :variable:`CMAKE_MESSAGE_INDENT` variable (converted to
+ a single string by concatenating its list items). For ``STATUS`` to ``TRACE``
+ messages, this indenting content will be inserted after the hyphens.
+
+.. versionadded:: 3.17
+ Messages of log levels ``NOTICE`` and below can also have each line preceded
+ with context of the form ``[some.context.example]``. The content between the
+ square brackets is obtained by converting the :variable:`CMAKE_MESSAGE_CONTEXT`
+ list variable to a dot-separated string. The message context will always
+ appear before any indenting content but after any automatically added leading
+ hyphens. By default, message context is not shown, it has to be explicitly
+ enabled by giving the :manual:`cmake <cmake(1)>` ``--log-context``
+ command-line option or by setting the :variable:`CMAKE_MESSAGE_CONTEXT_SHOW`
+ variable to true. See the :variable:`CMAKE_MESSAGE_CONTEXT` documentation for
+ usage examples.
+
+CMake Warning and Error message text displays using a simple markup
+language. Non-indented text is formatted in line-wrapped paragraphs
+delimited by newlines. Indented text is considered pre-formatted.
+
+
+Reporting checks
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.17
+
+A common pattern in CMake output is a message indicating the start of some
+sort of check, followed by another message reporting the result of that check.
+For example:
+
+.. code-block:: cmake
+
+ message(STATUS "Looking for someheader.h")
+ #... do the checks, set checkSuccess with the result
+ if(checkSuccess)
+ message(STATUS "Looking for someheader.h - found")
+ else()
+ message(STATUS "Looking for someheader.h - not found")
+ endif()
+
+This can be more robustly and conveniently expressed using the ``CHECK_...``
+keyword form of the ``message()`` command:
+
+.. code-block:: cmake
+
+ message(<checkState> "message" ...)
+
+where ``<checkState>`` must be one of the following:
+
+ ``CHECK_START``
+ Record a concise message about the check about to be performed.
+
+ ``CHECK_PASS``
+ Record a successful result for a check.
+
+ ``CHECK_FAIL``
+ Record an unsuccessful result for a check.
+
+When recording a check result, the command repeats the message from the most
+recently started check for which no result has yet been reported, then some
+separator characters and then the message text provided after the
+``CHECK_PASS`` or ``CHECK_FAIL`` keyword. Check messages are always reported
+at ``STATUS`` log level.
+
+Checks may be nested and every ``CHECK_START`` should have exactly one
+matching ``CHECK_PASS`` or ``CHECK_FAIL``.
+The :variable:`CMAKE_MESSAGE_INDENT` variable can also be used to add
+indenting to nested checks if desired. For example:
+
+.. code-block:: cmake
+
+ message(CHECK_START "Finding my things")
+ list(APPEND CMAKE_MESSAGE_INDENT " ")
+ unset(missingComponents)
+
+ message(CHECK_START "Finding partA")
+ # ... do check, assume we find A
+ message(CHECK_PASS "found")
+
+ message(CHECK_START "Finding partB")
+ # ... do check, assume we don't find B
+ list(APPEND missingComponents B)
+ message(CHECK_FAIL "not found")
+
+ list(POP_BACK CMAKE_MESSAGE_INDENT)
+ if(missingComponents)
+ message(CHECK_FAIL "missing components: ${missingComponents}")
+ else()
+ message(CHECK_PASS "all components found")
+ endif()
+
+Output from the above would appear something like the following::
+
+ -- Finding my things
+ -- Finding partA
+ -- Finding partA - found
+ -- Finding partB
+ -- Finding partB - not found
+ -- Finding my things - missing components: B
diff --git a/Help/command/option.rst b/Help/command/option.rst
new file mode 100644
index 0000000..02b8dac
--- /dev/null
+++ b/Help/command/option.rst
@@ -0,0 +1,16 @@
+option
+------
+
+Provide an option that the user can optionally select.
+
+.. code-block:: cmake
+
+ option(<variable> "<help_text>" [value])
+
+Provides an option for the user to select as ``ON`` or ``OFF``.
+If no initial ``<value>`` is provided, ``OFF`` is used.
+If ``<variable>`` is already set as a normal or cache variable,
+then the command does nothing (see policy :policy:`CMP0077`).
+
+If you have options that depend on the values of other options, see
+the module help for :module:`CMakeDependentOption`.
diff --git a/Help/command/output_required_files.rst b/Help/command/output_required_files.rst
new file mode 100644
index 0000000..b3a6e86
--- /dev/null
+++ b/Help/command/output_required_files.rst
@@ -0,0 +1,19 @@
+output_required_files
+---------------------
+
+Disallowed since version 3.0. See CMake Policy :policy:`CMP0032`.
+
+Approximate C preprocessor dependency scanning.
+
+This command exists only because ancient CMake versions provided it.
+CMake handles preprocessor dependency scanning automatically using a
+more advanced scanner.
+
+::
+
+ output_required_files(srcfile outputfile)
+
+Outputs a list of all the source files that are required by the
+specified ``srcfile``. This list is written into ``outputfile``. This is
+similar to writing out the dependencies for ``srcfile`` except that it
+jumps from ``.h`` files into ``.cxx``, ``.c`` and ``.cpp`` files if possible.
diff --git a/Help/command/project.rst b/Help/command/project.rst
new file mode 100644
index 0000000..8a6bc1e
--- /dev/null
+++ b/Help/command/project.rst
@@ -0,0 +1,164 @@
+project
+-------
+
+Set the name of the project.
+
+Synopsis
+^^^^^^^^
+
+.. code-block:: cmake
+
+ project(<PROJECT-NAME> [<language-name>...])
+ project(<PROJECT-NAME>
+ [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
+ [DESCRIPTION <project-description-string>]
+ [HOMEPAGE_URL <url-string>]
+ [LANGUAGES <language-name>...])
+
+Sets the name of the project, and stores it in the variable
+:variable:`PROJECT_NAME`. When called from the top-level
+``CMakeLists.txt`` also stores the project name in the
+variable :variable:`CMAKE_PROJECT_NAME`.
+
+Also sets the variables:
+
+:variable:`PROJECT_SOURCE_DIR`, :variable:`<PROJECT-NAME>_SOURCE_DIR`
+ Absolute path to the source directory for the project.
+
+:variable:`PROJECT_BINARY_DIR`, :variable:`<PROJECT-NAME>_BINARY_DIR`
+ Absolute path to the binary directory for the project.
+
+:variable:`PROJECT_IS_TOP_LEVEL`, :variable:`<PROJECT-NAME>_IS_TOP_LEVEL`
+ .. versionadded:: 3.21
+
+ Boolean value indicating whether the project is top-level.
+
+Further variables are set by the optional arguments described in the following.
+If any of these arguments is not used, then the corresponding variables are
+set to the empty string.
+
+Options
+^^^^^^^
+
+The options are:
+
+``VERSION <version>``
+ Optional; may not be used unless policy :policy:`CMP0048` is
+ set to ``NEW``.
+
+ Takes a ``<version>`` argument composed of non-negative integer components,
+ i.e. ``<major>[.<minor>[.<patch>[.<tweak>]]]``,
+ and sets the variables
+
+ * :variable:`PROJECT_VERSION`,
+ :variable:`<PROJECT-NAME>_VERSION`
+ * :variable:`PROJECT_VERSION_MAJOR`,
+ :variable:`<PROJECT-NAME>_VERSION_MAJOR`
+ * :variable:`PROJECT_VERSION_MINOR`,
+ :variable:`<PROJECT-NAME>_VERSION_MINOR`
+ * :variable:`PROJECT_VERSION_PATCH`,
+ :variable:`<PROJECT-NAME>_VERSION_PATCH`
+ * :variable:`PROJECT_VERSION_TWEAK`,
+ :variable:`<PROJECT-NAME>_VERSION_TWEAK`.
+
+ .. versionadded:: 3.12
+ When the ``project()`` command is called from the top-level
+ ``CMakeLists.txt``, then the version is also stored in the variable
+ :variable:`CMAKE_PROJECT_VERSION`.
+
+``DESCRIPTION <project-description-string>``
+ .. versionadded:: 3.9
+
+ Optional.
+ Sets the variables
+
+ * :variable:`PROJECT_DESCRIPTION`, :variable:`<PROJECT-NAME>_DESCRIPTION`
+
+ to ``<project-description-string>``.
+ It is recommended that this description is a relatively short string,
+ usually no more than a few words.
+
+ When the ``project()`` command is called from the top-level ``CMakeLists.txt``,
+ then the description is also stored in the variable :variable:`CMAKE_PROJECT_DESCRIPTION`.
+
+ .. versionadded:: 3.12
+ Added the ``<PROJECT-NAME>_DESCRIPTION`` variable.
+
+``HOMEPAGE_URL <url-string>``
+ .. versionadded:: 3.12
+
+ Optional.
+ Sets the variables
+
+ * :variable:`PROJECT_HOMEPAGE_URL`, :variable:`<PROJECT-NAME>_HOMEPAGE_URL`
+
+ to ``<url-string>``, which should be the canonical home URL for the project.
+
+ When the ``project()`` command is called from the top-level ``CMakeLists.txt``,
+ then the URL also is stored in the variable :variable:`CMAKE_PROJECT_HOMEPAGE_URL`.
+
+``LANGUAGES <language-name>...``
+ Optional.
+ Can also be specified without ``LANGUAGES`` keyword per the first, short signature.
+
+ Selects which programming languages are needed to build the project.
+ Supported languages include ``C``, ``CXX`` (i.e. C++), ``CUDA``,
+ ``OBJC`` (i.e. Objective-C), ``OBJCXX``, ``Fortran``, ``ISPC``, and ``ASM``.
+ By default ``C`` and ``CXX`` are enabled if no language options are given.
+ Specify language ``NONE``, or use the ``LANGUAGES`` keyword and list no languages,
+ to skip enabling any languages.
+
+ .. versionadded:: 3.8
+ Added ``CUDA`` support.
+
+ .. versionadded:: 3.16
+ Added ``OBJC`` and ``OBJCXX`` support.
+
+ .. versionadded:: 3.18
+ Added ``ISPC`` support.
+
+ If enabling ``ASM``, list it last so that CMake can check whether
+ compilers for other languages like ``C`` work for assembly too.
+
+The variables set through the ``VERSION``, ``DESCRIPTION`` and ``HOMEPAGE_URL``
+options are intended for use as default values in package metadata and documentation.
+
+Code Injection
+^^^^^^^^^^^^^^
+
+If the :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` or
+:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE` variables are set,
+the files they point to will be included as the first step of the
+``project()`` command.
+If both are set, then :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` will be
+included before :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`.
+
+If the :variable:`CMAKE_PROJECT_INCLUDE` or
+:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE` variables are set, the files
+they point to will be included as the last step of the ``project()`` command.
+If both are set, then :variable:`CMAKE_PROJECT_INCLUDE` will be included before
+:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`.
+
+.. versionadded:: 3.15
+ Added the ``CMAKE_PROJECT_INCLUDE`` and ``CMAKE_PROJECT_INCLUDE_BEFORE``
+ variables.
+
+.. versionadded:: 3.17
+ Added the ``CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`` variable.
+
+Usage
+^^^^^
+
+The top-level ``CMakeLists.txt`` file for a project must contain a
+literal, direct call to the ``project()`` command; loading one
+through the :command:`include` command is not sufficient. If no such
+call exists, CMake will issue a warning and pretend there is a
+``project(Project)`` at the top to enable the default languages
+(``C`` and ``CXX``).
+
+.. note::
+ Call the ``project()`` command near the top of the top-level
+ ``CMakeLists.txt``, but *after* calling :command:`cmake_minimum_required`.
+ It is important to establish version and policy settings before invoking
+ other commands whose behavior they may affect.
+ See also policy :policy:`CMP0000`.
diff --git a/Help/command/qt_wrap_cpp.rst b/Help/command/qt_wrap_cpp.rst
new file mode 100644
index 0000000..ce11c2d
--- /dev/null
+++ b/Help/command/qt_wrap_cpp.rst
@@ -0,0 +1,23 @@
+qt_wrap_cpp
+-----------
+
+.. deprecated:: 3.14
+
+ This command was originally added to support Qt 3 before the
+ :command:`add_custom_command()` command was sufficiently mature. The
+ :module:`FindQt4` module provides the ``qt4_wrap_cpp()`` macro, which
+ should be used instead for Qt 4 projects. For projects using Qt 5 or
+ later, use the equivalent macro provided by Qt itself (e.g. Qt 5 provides
+ ``qt5_wrap_cpp()``).
+
+Manually create Qt Wrappers.
+
+.. code-block:: cmake
+
+ qt_wrap_cpp(resultingLibraryName DestName SourceLists ...)
+
+Produces moc files for all the .h files listed in the SourceLists. The
+moc files will be added to the library using the ``DestName`` source list.
+
+Consider updating the project to use the :prop_tgt:`AUTOMOC` target property
+instead for a more automated way of invoking the ``moc`` tool.
diff --git a/Help/command/qt_wrap_ui.rst b/Help/command/qt_wrap_ui.rst
new file mode 100644
index 0000000..efbbc54
--- /dev/null
+++ b/Help/command/qt_wrap_ui.rst
@@ -0,0 +1,26 @@
+qt_wrap_ui
+----------
+
+.. deprecated:: 3.14
+
+ This command was originally added to support Qt 3 before the
+ :command:`add_custom_command()` command was sufficiently mature. The
+ :module:`FindQt4` module provides the ``qt4_wrap_ui()`` macro, which
+ should be used instead for Qt 4 projects. For projects using Qt 5 or
+ later, use the equivalent macro provided by Qt itself (e.g. Qt 5 provides
+ ``qt5_wrap_ui()``).
+
+Manually create Qt user interfaces Wrappers.
+
+.. code-block:: cmake
+
+ qt_wrap_ui(resultingLibraryName HeadersDestName
+ SourcesDestName SourceLists ...)
+
+Produces .h and .cxx files for all the .ui files listed in the
+``SourceLists``. The .h files will be added to the library using the
+``HeadersDestNamesource`` list. The .cxx files will be added to the
+library using the ``SourcesDestNamesource`` list.
+
+Consider updating the project to use the :prop_tgt:`AUTOUIC` target property
+instead for a more automated way of invoking the ``uic`` tool.
diff --git a/Help/command/remove.rst b/Help/command/remove.rst
new file mode 100644
index 0000000..543d016
--- /dev/null
+++ b/Help/command/remove.rst
@@ -0,0 +1,14 @@
+remove
+------
+
+.. deprecated:: 3.0
+
+ Use the :command:`list(REMOVE_ITEM)` command instead.
+
+::
+
+ remove(VAR VALUE VALUE ...)
+
+Removes ``VALUE`` from the variable ``VAR``. This is typically used to
+remove entries from a vector (e.g. semicolon separated list). ``VALUE``
+is expanded.
diff --git a/Help/command/remove_definitions.rst b/Help/command/remove_definitions.rst
new file mode 100644
index 0000000..faad16d
--- /dev/null
+++ b/Help/command/remove_definitions.rst
@@ -0,0 +1,11 @@
+remove_definitions
+------------------
+
+Remove -D define flags added by :command:`add_definitions`.
+
+.. code-block:: cmake
+
+ remove_definitions(-DFOO -DBAR ...)
+
+Removes flags (added by :command:`add_definitions`) from the compiler
+command line for sources in the current directory and below.
diff --git a/Help/command/return.rst b/Help/command/return.rst
new file mode 100644
index 0000000..ec009d8
--- /dev/null
+++ b/Help/command/return.rst
@@ -0,0 +1,20 @@
+return
+------
+
+Return from a file, directory or function.
+
+.. code-block:: cmake
+
+ return()
+
+Returns from a file, directory or function. When this command is
+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.
+
+Note that a :command:`macro <macro>`, unlike a :command:`function <function>`,
+is expanded in place and therefore cannot handle ``return()``.
diff --git a/Help/command/separate_arguments.rst b/Help/command/separate_arguments.rst
new file mode 100644
index 0000000..f66af35
--- /dev/null
+++ b/Help/command/separate_arguments.rst
@@ -0,0 +1,80 @@
+separate_arguments
+------------------
+
+Parse command-line arguments into a semicolon-separated list.
+
+.. code-block:: cmake
+
+ separate_arguments(<variable> <mode> [PROGRAM [SEPARATE_ARGS]] <args>)
+
+Parses a space-separated string ``<args>`` into a list of items,
+and stores this list in semicolon-separated standard form in ``<variable>``.
+
+This function is intended for parsing command-line arguments.
+The entire command line must be passed as one string in the
+argument ``<args>``.
+
+The exact parsing rules depend on the operating system.
+They are specified by the ``<mode>`` argument which must
+be one of the following keywords:
+
+``UNIX_COMMAND``
+ Arguments are separated by unquoted whitespace.
+ Both single-quote and double-quote pairs are respected.
+ A backslash escapes the next literal character (``\"`` is ``"``);
+ there are no special escapes (``\n`` is just ``n``).
+
+``WINDOWS_COMMAND``
+ A Windows command-line is parsed using the same
+ syntax the runtime library uses to construct argv at startup. It
+ separates arguments by whitespace that is not double-quoted.
+ Backslashes are literal unless they precede double-quotes. See the
+ MSDN article `Parsing C Command-Line Arguments`_ for details.
+
+``NATIVE_COMMAND``
+ .. versionadded:: 3.9
+
+ Proceeds as in ``WINDOWS_COMMAND`` mode if the host system is Windows.
+ Otherwise proceeds as in ``UNIX_COMMAND`` mode.
+
+``PROGRAM``
+ .. versionadded:: 3.19
+
+ The first item in ``<args>`` is assumed to be an executable and will be
+ searched in the system search path or left as a full path. If not found,
+ ``<variable>`` will be empty. Otherwise, ``<variable>`` is a list of 2
+ elements:
+
+ 0. Absolute path of the program
+ 1. Any command-line arguments present in ``<args>`` as a string
+
+ For example:
+
+ .. code-block:: cmake
+
+ separate_arguments (out UNIX_COMMAND PROGRAM "cc -c main.c")
+
+ * First element of the list: ``/path/to/cc``
+ * Second element of the list: ``" -c main.c"``
+
+``SEPARATE_ARGS``
+ When this sub-option of ``PROGRAM`` option is specified, command-line
+ arguments will be split as well and stored in ``<variable>``.
+
+ For example:
+
+ .. code-block:: cmake
+
+ separate_arguments (out UNIX_COMMAND PROGRAM SEPARATE_ARGS "cc -c main.c")
+
+ The contents of ``out`` will be: ``/path/to/cc;-c;main.c``
+
+.. _`Parsing C Command-Line Arguments`: https://msdn.microsoft.com/library/a1y7w461.aspx
+
+.. code-block:: cmake
+
+ separate_arguments(<var>)
+
+Convert the value of ``<var>`` to a semi-colon separated list. All
+spaces are replaced with ';'. This helps with generating command
+lines.
diff --git a/Help/command/set.rst b/Help/command/set.rst
new file mode 100644
index 0000000..c0e02e2
--- /dev/null
+++ b/Help/command/set.rst
@@ -0,0 +1,104 @@
+set
+---
+
+Set a normal, cache, or environment variable to a given value.
+See the :ref:`cmake-language(7) variables <CMake Language Variables>`
+documentation for the scopes and interaction of normal variables
+and cache entries.
+
+Signatures of this command that specify a ``<value>...`` placeholder
+expect zero or more arguments. Multiple arguments will be joined as
+a :ref:`semicolon-separated list <CMake Language Lists>` to form the actual variable
+value to be set. Zero arguments will cause normal variables to be
+unset. See the :command:`unset` command to unset variables explicitly.
+
+Set Normal Variable
+^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ set(<variable> <value>... [PARENT_SCOPE])
+
+Sets the given ``<variable>`` in the current function or directory scope.
+
+If the ``PARENT_SCOPE`` option is given the variable will be set in
+the scope above the current scope. Each new directory or function
+creates a new scope. This command will set the value of a variable
+into the parent directory or calling function (whichever is applicable
+to the case at hand). The previous state of the variable's value stays the
+same in the current scope (e.g., if it was undefined before, it is still
+undefined and if it had a value, it is still that value).
+
+Set Cache Entry
+^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ set(<variable> <value>... CACHE <type> <docstring> [FORCE])
+
+Sets the given cache ``<variable>`` (cache entry). Since cache entries
+are meant to provide user-settable values this does not overwrite
+existing cache entries by default. Use the ``FORCE`` option to
+overwrite existing entries.
+
+The ``<type>`` must be specified as one of:
+
+``BOOL``
+ Boolean ``ON/OFF`` value. :manual:`cmake-gui(1)` offers a checkbox.
+
+``FILEPATH``
+ Path to a file on disk. :manual:`cmake-gui(1)` offers a file dialog.
+
+``PATH``
+ Path to a directory on disk. :manual:`cmake-gui(1)` offers a file dialog.
+
+``STRING``
+ A line of text. :manual:`cmake-gui(1)` offers a text field or a
+ drop-down selection if the :prop_cache:`STRINGS` cache entry
+ property is set.
+
+``INTERNAL``
+ A line of text. :manual:`cmake-gui(1)` does not show internal entries.
+ They may be used to store variables persistently across runs.
+ Use of this type implies ``FORCE``.
+
+The ``<docstring>`` must be specified as a line of text providing
+a quick summary of the option for presentation to :manual:`cmake-gui(1)`
+users.
+
+If the cache entry does not exist prior to the call or the ``FORCE``
+option is given then the cache entry will be set to the given value.
+Furthermore, any normal variable binding in the current scope will
+be removed to expose the newly cached value to any immediately
+following evaluation.
+
+It is possible for the cache entry to exist prior to the call but
+have no type set if it was created on the :manual:`cmake(1)` command
+line by a user through the ``-D<var>=<value>`` option without
+specifying a type. In this case the ``set`` command will add the
+type. Furthermore, if the ``<type>`` is ``PATH`` or ``FILEPATH``
+and the ``<value>`` provided on the command line is a relative path,
+then the ``set`` command will treat the path as relative to the
+current working directory and convert it to an absolute path.
+
+Set Environment Variable
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ set(ENV{<variable>} [<value>])
+
+Sets an :manual:`Environment Variable <cmake-env-variables(7)>`
+to the given value.
+Subsequent calls of ``$ENV{<variable>}`` will return this new value.
+
+This command affects only the current CMake process, not the process
+from which CMake was called, nor the system environment at large,
+nor the environment of subsequent build or test processes.
+
+If no argument is given after ``ENV{<variable>}`` or if ``<value>`` is
+an empty string, then this command will clear any existing value of the
+environment variable.
+
+Arguments after ``<value>`` are ignored. If extra arguments are found,
+then an author warning is issued.
diff --git a/Help/command/set_directory_properties.rst b/Help/command/set_directory_properties.rst
new file mode 100644
index 0000000..f02a8e6
--- /dev/null
+++ b/Help/command/set_directory_properties.rst
@@ -0,0 +1,15 @@
+set_directory_properties
+------------------------
+
+Set properties of the current directory and subdirectories.
+
+.. code-block:: cmake
+
+ set_directory_properties(PROPERTIES prop1 value1 [prop2 value2] ...)
+
+Sets properties of the current directory and its subdirectories in key-value pairs.
+
+See also the :command:`set_property(DIRECTORY)` command.
+
+See :ref:`Directory Properties` for the list of properties known to CMake
+and their individual documentation for the behavior of each property.
diff --git a/Help/command/set_property.rst b/Help/command/set_property.rst
new file mode 100644
index 0000000..bf437b4
--- /dev/null
+++ b/Help/command/set_property.rst
@@ -0,0 +1,112 @@
+set_property
+------------
+
+Set a named property in a given scope.
+
+.. code-block:: cmake
+
+ set_property(<GLOBAL |
+ DIRECTORY [<dir>] |
+ TARGET [<target1> ...] |
+ SOURCE [<src1> ...]
+ [DIRECTORY <dirs> ...] |
+ [TARGET_DIRECTORY <targets> ...]
+ INSTALL [<file1> ...] |
+ TEST [<test1> ...] |
+ CACHE [<entry1> ...] >
+ [APPEND] [APPEND_STRING]
+ PROPERTY <name> [<value1> ...])
+
+Sets one property on zero or more objects of a scope.
+
+The first argument determines the scope in which the property is set.
+It must be one of the following:
+
+``GLOBAL``
+ Scope is unique and does not accept a name.
+
+``DIRECTORY``
+ Scope defaults to the current directory but other directories
+ (already processed by CMake) may be named by full or relative path.
+ Relative paths are treated as relative to the current source directory.
+ See also the :command:`set_directory_properties` command.
+
+ .. versionadded:: 3.19
+ ``<dir>`` may reference a binary directory.
+
+``TARGET``
+ Scope may name zero or more existing targets.
+ See also the :command:`set_target_properties` command.
+
+``SOURCE``
+ Scope may name zero or more source files. By default, source file properties
+ are only visible to targets added in the same directory (``CMakeLists.txt``).
+
+ .. versionadded:: 3.18
+ Visibility can be set in other directory scopes using one or both of the
+ following sub-options:
+
+ ``DIRECTORY <dirs>...``
+ The source file property will be set in each of the ``<dirs>``
+ directories' scopes. CMake must already know about
+ each of these directories, either by having added them through a call to
+ :command:`add_subdirectory` or it being the top level source directory.
+ Relative paths are treated as relative to the current source directory.
+
+ .. versionadded:: 3.19
+ ``<dirs>`` may reference a binary directory.
+
+ ``TARGET_DIRECTORY <targets>...``
+ The source file property will be set in each of the directory scopes
+ where any of the specified ``<targets>`` were created (the ``<targets>``
+ must therefore already exist).
+
+ See also the :command:`set_source_files_properties` command.
+
+``INSTALL``
+ .. versionadded:: 3.1
+
+ Scope may name zero or more installed file paths.
+ These are made available to CPack to influence deployment.
+
+ Both the property key and value may use generator expressions.
+ Specific properties may apply to installed files and/or directories.
+
+ Path components have to be separated by forward slashes,
+ must be normalized and are case sensitive.
+
+ To reference the installation prefix itself with a relative path use ``.``.
+
+ Currently installed file properties are only defined for
+ the WIX generator where the given paths are relative
+ to the installation prefix.
+
+``TEST``
+ Scope may name zero or more existing tests.
+ See also the :command:`set_tests_properties` command.
+
+``CACHE``
+ Scope must name zero or more cache existing entries.
+
+The required ``PROPERTY`` option is immediately followed by the name of
+the property to set. Remaining arguments are used to compose the
+property value in the form of a semicolon-separated list.
+
+If the ``APPEND`` option is given the list is appended to any existing
+property value (except that empty values are ignored and not appended).
+If the ``APPEND_STRING`` option is given the string is
+appended to any existing property value as string, i.e. it results in a
+longer string and not a list of strings. When using ``APPEND`` or
+``APPEND_STRING`` with a property defined to support ``INHERITED``
+behavior (see :command:`define_property`), no inheriting occurs when
+finding the initial value to append to. If the property is not already
+directly set in the nominated scope, the command will behave as though
+``APPEND`` or ``APPEND_STRING`` had not been given.
+
+See the :manual:`cmake-properties(7)` manual for a list of properties
+in each scope.
+
+.. note::
+
+ The :prop_sf:`GENERATED` source file property may be globally visible.
+ See its documentation for details.
diff --git a/Help/command/set_source_files_properties.rst b/Help/command/set_source_files_properties.rst
new file mode 100644
index 0000000..61c69a2
--- /dev/null
+++ b/Help/command/set_source_files_properties.rst
@@ -0,0 +1,43 @@
+set_source_files_properties
+---------------------------
+
+Source files can have properties that affect how they are built.
+
+.. code-block:: cmake
+
+ set_source_files_properties(<files> ...
+ [DIRECTORY <dirs> ...]
+ [TARGET_DIRECTORY <targets> ...]
+ PROPERTIES <prop1> <value1>
+ [<prop2> <value2>] ...)
+
+Sets properties associated with source files using a key/value paired
+list.
+
+.. versionadded:: 3.18
+ By default, source file properties are only visible to targets added in the
+ same directory (``CMakeLists.txt``). Visibility can be set in other directory
+ scopes using one or both of the following options:
+
+``DIRECTORY <dirs>...``
+ The source file properties will be set in each of the ``<dirs>``
+ directories' scopes. CMake must already know about each of these
+ source directories, either by having added them through a call to
+ :command:`add_subdirectory` or it being the top level source directory.
+ Relative paths are treated as relative to the current source directory.
+
+``TARGET_DIRECTORY <targets>...``
+ The source file properties will be set in each of the directory scopes
+ where any of the specified ``<targets>`` were created (the ``<targets>``
+ must therefore already exist).
+
+Use :command:`get_source_file_property` to get property values.
+See also the :command:`set_property(SOURCE)` command.
+
+See :ref:`Source File Properties` for the list of properties known
+to CMake.
+
+.. note::
+
+ The :prop_sf:`GENERATED` source file property may be globally visible.
+ See its documentation for details.
diff --git a/Help/command/set_target_properties.rst b/Help/command/set_target_properties.rst
new file mode 100644
index 0000000..597be23
--- /dev/null
+++ b/Help/command/set_target_properties.rst
@@ -0,0 +1,20 @@
+set_target_properties
+---------------------
+
+Targets can have properties that affect how they are built.
+
+.. code-block:: cmake
+
+ set_target_properties(target1 target2 ...
+ PROPERTIES prop1 value1
+ prop2 value2 ...)
+
+Sets properties on targets. The syntax for the command is to list all
+the targets you want to change, and then provide the values you want to
+set next. You can use any prop value pair you want and extract it
+later with the :command:`get_property` or :command:`get_target_property`
+command.
+
+See also the :command:`set_property(TARGET)` command.
+
+See :ref:`Target Properties` for the list of properties known to CMake.
diff --git a/Help/command/set_tests_properties.rst b/Help/command/set_tests_properties.rst
new file mode 100644
index 0000000..9bc94ae
--- /dev/null
+++ b/Help/command/set_tests_properties.rst
@@ -0,0 +1,17 @@
+set_tests_properties
+--------------------
+
+Set a property of the tests.
+
+.. code-block:: cmake
+
+ set_tests_properties(test1 [test2...] PROPERTIES prop1 value1 prop2 value2)
+
+Sets a property for the tests. If the test is not found, CMake
+will report an error.
+:manual:`Generator expressions <cmake-generator-expressions(7)>` will be
+expanded the same as supported by the test's :command:`add_test` call.
+
+See also the :command:`set_property(TEST)` command.
+
+See :ref:`Test Properties` for the list of properties known to CMake.
diff --git a/Help/command/site_name.rst b/Help/command/site_name.rst
new file mode 100644
index 0000000..09b5a9f
--- /dev/null
+++ b/Help/command/site_name.rst
@@ -0,0 +1,12 @@
+site_name
+---------
+
+Set the given variable to the name of the computer.
+
+.. code-block:: cmake
+
+ site_name(variable)
+
+On UNIX-like platforms, if the variable ``HOSTNAME`` is set, its value
+will be executed as a command expected to print out the host name,
+much like the ``hostname`` command-line tool.
diff --git a/Help/command/source_group.rst b/Help/command/source_group.rst
new file mode 100644
index 0000000..5db1ec8
--- /dev/null
+++ b/Help/command/source_group.rst
@@ -0,0 +1,67 @@
+source_group
+------------
+
+Define a grouping for source files in IDE project generation.
+There are two different signatures to create source groups.
+
+.. code-block:: cmake
+
+ source_group(<name> [FILES <src>...] [REGULAR_EXPRESSION <regex>])
+ source_group(TREE <root> [PREFIX <prefix>] [FILES <src>...])
+
+Defines a group into which sources will be placed in project files.
+This is intended to set up file tabs in Visual Studio.
+The options are:
+
+``TREE``
+ .. versionadded:: 3.8
+
+ CMake will automatically detect, from ``<src>`` files paths, source groups
+ it needs to create, to keep structure of source groups analogically to the
+ actual files and directories structure in the project. Paths of ``<src>``
+ files will be cut to be relative to ``<root>``.
+
+``PREFIX``
+ .. versionadded:: 3.8
+
+ Source group and files located directly in ``<root>`` path, will be placed
+ in ``<prefix>`` source groups.
+
+``FILES``
+ Any source file specified explicitly will be placed in group
+ ``<name>``. Relative paths are interpreted with respect to the
+ current source directory.
+
+``REGULAR_EXPRESSION``
+ Any source file whose name matches the regular expression will
+ be placed in group ``<name>``.
+
+If a source file matches multiple groups, the *last* group that
+explicitly lists the file with ``FILES`` will be favored, if any.
+If no group explicitly lists the file, the *last* group whose
+regular expression matches the file will be favored.
+
+The ``<name>`` of the group and ``<prefix>`` argument may contain forward
+slashes or backslashes to specify subgroups. Backslashes need to be escaped
+appropriately:
+
+.. code-block:: cmake
+
+ source_group(base/subdir ...)
+ source_group(outer\\inner ...)
+ source_group(TREE <root> PREFIX sources\\inc ...)
+
+.. versionadded:: 3.18
+ Allow using forward slashes (``/``) to specify subgroups.
+
+For backwards compatibility, the short-hand signature
+
+.. code-block:: cmake
+
+ source_group(<name> <regex>)
+
+is equivalent to
+
+.. code-block:: cmake
+
+ source_group(<name> REGULAR_EXPRESSION <regex>)
diff --git a/Help/command/string.rst b/Help/command/string.rst
new file mode 100644
index 0000000..8ad0089
--- /dev/null
+++ b/Help/command/string.rst
@@ -0,0 +1,612 @@
+string
+------
+
+String operations.
+
+Synopsis
+^^^^^^^^
+
+.. parsed-literal::
+
+ `Search and Replace`_
+ string(`FIND`_ <string> <substring> <out-var> [...])
+ string(`REPLACE`_ <match-string> <replace-string> <out-var> <input>...)
+ string(`REGEX MATCH`_ <match-regex> <out-var> <input>...)
+ string(`REGEX MATCHALL`_ <match-regex> <out-var> <input>...)
+ string(`REGEX REPLACE`_ <match-regex> <replace-expr> <out-var> <input>...)
+
+ `Manipulation`_
+ string(`APPEND`_ <string-var> [<input>...])
+ string(`PREPEND`_ <string-var> [<input>...])
+ string(`CONCAT`_ <out-var> [<input>...])
+ string(`JOIN`_ <glue> <out-var> [<input>...])
+ string(`TOLOWER`_ <string> <out-var>)
+ string(`TOUPPER`_ <string> <out-var>)
+ string(`LENGTH`_ <string> <out-var>)
+ string(`SUBSTRING`_ <string> <begin> <length> <out-var>)
+ string(`STRIP`_ <string> <out-var>)
+ string(`GENEX_STRIP`_ <string> <out-var>)
+ string(`REPEAT`_ <string> <count> <out-var>)
+
+ `Comparison`_
+ string(`COMPARE`_ <op> <string1> <string2> <out-var>)
+
+ `Hashing`_
+ string(`\<HASH\> <HASH_>`_ <out-var> <input>)
+
+ `Generation`_
+ string(`ASCII`_ <number>... <out-var>)
+ string(`HEX`_ <string> <out-var>)
+ string(`CONFIGURE`_ <string> <out-var> [...])
+ string(`MAKE_C_IDENTIFIER`_ <string> <out-var>)
+ string(`RANDOM`_ [<option>...] <out-var>)
+ string(`TIMESTAMP`_ <out-var> [<format string>] [UTC])
+ string(`UUID`_ <out-var> ...)
+
+ `JSON`_
+ string(JSON <out-var> [ERROR_VARIABLE <error-var>]
+ {`GET`_ | `TYPE`_ | :ref:`LENGTH <JSONLENGTH>` | `REMOVE`_}
+ <json-string> <member|index> [<member|index> ...])
+ string(JSON <out-var> [ERROR_VARIABLE <error-var>]
+ `MEMBER`_ <json-string>
+ [<member|index> ...] <index>)
+ string(JSON <out-var> [ERROR_VARIABLE <error-var>]
+ `SET`_ <json-string>
+ <member|index> [<member|index> ...] <value>)
+ string(JSON <out-var> [ERROR_VARIABLE <error-var>]
+ `EQUAL`_ <json-string1> <json-string2>)
+
+Search and Replace
+^^^^^^^^^^^^^^^^^^
+
+Search and Replace With Plain Strings
+"""""""""""""""""""""""""""""""""""""
+
+.. _FIND:
+
+.. code-block:: cmake
+
+ string(FIND <string> <substring> <output_variable> [REVERSE])
+
+Return the position where the given ``<substring>`` was found in
+the supplied ``<string>``. If the ``REVERSE`` flag was used, the command will
+search for the position of the last occurrence of the specified
+``<substring>``. If the ``<substring>`` is not found, a position of -1 is
+returned.
+
+The ``string(FIND)`` subcommand treats all strings as ASCII-only characters.
+The index stored in ``<output_variable>`` will also be counted in bytes,
+so strings containing multi-byte characters may lead to unexpected results.
+
+.. _REPLACE:
+
+.. code-block:: cmake
+
+ string(REPLACE <match_string>
+ <replace_string> <output_variable>
+ <input> [<input>...])
+
+Replace all occurrences of ``<match_string>`` in the ``<input>``
+with ``<replace_string>`` and store the result in the ``<output_variable>``.
+
+Search and Replace With Regular Expressions
+"""""""""""""""""""""""""""""""""""""""""""
+
+.. _`REGEX MATCH`:
+
+.. code-block:: cmake
+
+ string(REGEX MATCH <regular_expression>
+ <output_variable> <input> [<input>...])
+
+Match the ``<regular_expression>`` once and store the match in the
+``<output_variable>``.
+All ``<input>`` arguments are concatenated before matching.
+Regular expressions are specified in the subsection just below.
+
+.. _`REGEX MATCHALL`:
+
+.. code-block:: cmake
+
+ string(REGEX MATCHALL <regular_expression>
+ <output_variable> <input> [<input>...])
+
+Match the ``<regular_expression>`` as many times as possible and store the
+matches in the ``<output_variable>`` as a list.
+All ``<input>`` arguments are concatenated before matching.
+
+.. _`REGEX REPLACE`:
+
+.. code-block:: cmake
+
+ string(REGEX REPLACE <regular_expression>
+ <replacement_expression> <output_variable>
+ <input> [<input>...])
+
+Match the ``<regular_expression>`` as many times as possible and substitute
+the ``<replacement_expression>`` for the match in the output.
+All ``<input>`` arguments are concatenated before matching.
+
+The ``<replacement_expression>`` may refer to parenthesis-delimited
+subexpressions of the match using ``\1``, ``\2``, ..., ``\9``. Note that
+two backslashes (``\\1``) are required in CMake code to get a backslash
+through argument parsing.
+
+.. _`Regex Specification`:
+
+Regex Specification
+"""""""""""""""""""
+
+The following characters have special meaning in regular expressions:
+
+``^``
+ Matches at beginning of input
+``$``
+ Matches at end of input
+``.``
+ Matches any single character
+``\<char>``
+ Matches the single character specified by ``<char>``. Use this to
+ match special regex characters, e.g. ``\.`` for a literal ``.``
+ or ``\\`` for a literal backslash ``\``. Escaping a non-special
+ character is unnecessary but allowed, e.g. ``\a`` matches ``a``.
+``[ ]``
+ Matches any character(s) inside the brackets
+``[^ ]``
+ Matches any character(s) not inside the brackets
+``-``
+ Inside brackets, specifies an inclusive range between
+ characters on either side e.g. ``[a-f]`` is ``[abcdef]``
+ To match a literal ``-`` using brackets, make it the first
+ or the last character e.g. ``[+*/-]`` matches basic
+ mathematical operators.
+``*``
+ Matches preceding pattern zero or more times
+``+``
+ Matches preceding pattern one or more times
+``?``
+ Matches preceding pattern zero or once only
+``|``
+ Matches a pattern on either side of the ``|``
+``()``
+ Saves a matched subexpression, which can be referenced
+ in the ``REGEX REPLACE`` operation.
+
+ .. versionadded:: 3.9
+ All regular expression-related commands, including e.g.
+ :command:`if(MATCHES)`, save subgroup matches in the variables
+ :variable:`CMAKE_MATCH_<n>` for ``<n>`` 0..9.
+
+``*``, ``+`` and ``?`` have higher precedence than concatenation. ``|``
+has lower precedence than concatenation. This means that the regular
+expression ``^ab+d$`` matches ``abbd`` but not ``ababd``, and the regular
+expression ``^(ab|cd)$`` matches ``ab`` but not ``abd``.
+
+CMake language :ref:`Escape Sequences` such as ``\t``, ``\r``, ``\n``,
+and ``\\`` may be used to construct literal tabs, carriage returns,
+newlines, and backslashes (respectively) to pass in a regex. For example:
+
+* The quoted argument ``"[ \t\r\n]"`` specifies a regex that matches
+ any single whitespace character.
+* The quoted argument ``"[/\\]"`` specifies a regex that matches
+ a single forward slash ``/`` or backslash ``\``.
+* The quoted argument ``"[A-Za-z0-9_]"`` specifies a regex that matches
+ any single "word" character in the C locale.
+* The quoted argument ``"\\(\\a\\+b\\)"`` specifies a regex that matches
+ the exact string ``(a+b)``. Each ``\\`` is parsed in a quoted argument
+ as just ``\``, so the regex itself is actually ``\(\a\+\b\)``. This
+ can alternatively be specified in a :ref:`bracket argument` without
+ having to escape the backslashes, e.g. ``[[\(\a\+\b\)]]``.
+
+Manipulation
+^^^^^^^^^^^^
+
+.. _APPEND:
+
+.. code-block:: cmake
+
+ string(APPEND <string_variable> [<input>...])
+
+.. versionadded:: 3.4
+
+Append all the ``<input>`` arguments to the string.
+
+.. _PREPEND:
+
+.. code-block:: cmake
+
+ string(PREPEND <string_variable> [<input>...])
+
+.. versionadded:: 3.10
+
+Prepend all the ``<input>`` arguments to the string.
+
+.. _CONCAT:
+
+.. code-block:: cmake
+
+ string(CONCAT <output_variable> [<input>...])
+
+Concatenate all the ``<input>`` arguments together and store
+the result in the named ``<output_variable>``.
+
+.. _JOIN:
+
+.. code-block:: cmake
+
+ string(JOIN <glue> <output_variable> [<input>...])
+
+.. versionadded:: 3.12
+
+Join all the ``<input>`` arguments together using the ``<glue>``
+string and store the result in the named ``<output_variable>``.
+
+To join a list's elements, prefer to use the ``JOIN`` operator
+from the :command:`list` command. This allows for the elements to have
+special characters like ``;`` in them.
+
+.. _TOLOWER:
+
+.. code-block:: cmake
+
+ string(TOLOWER <string> <output_variable>)
+
+Convert ``<string>`` to lower characters.
+
+.. _TOUPPER:
+
+.. code-block:: cmake
+
+ string(TOUPPER <string> <output_variable>)
+
+Convert ``<string>`` to upper characters.
+
+.. _LENGTH:
+
+.. code-block:: cmake
+
+ string(LENGTH <string> <output_variable>)
+
+Store in an ``<output_variable>`` a given string's length in bytes.
+Note that this means if ``<string>`` contains multi-byte characters, the
+result stored in ``<output_variable>`` will *not* be the number of characters.
+
+.. _SUBSTRING:
+
+.. code-block:: cmake
+
+ string(SUBSTRING <string> <begin> <length> <output_variable>)
+
+Store in an ``<output_variable>`` a substring of a given ``<string>``. If
+``<length>`` is ``-1`` the remainder of the string starting at ``<begin>``
+will be returned.
+
+.. versionchanged:: 3.2
+ If ``<string>`` is shorter than ``<length>`` then the end of the string
+ is used instead. Previous versions of CMake reported an error in this case.
+
+Both ``<begin>`` and ``<length>`` are counted in bytes, so care must
+be exercised if ``<string>`` could contain multi-byte characters.
+
+.. _STRIP:
+
+.. code-block:: cmake
+
+ string(STRIP <string> <output_variable>)
+
+Store in an ``<output_variable>`` a substring of a given ``<string>`` with
+leading and trailing spaces removed.
+
+.. _GENEX_STRIP:
+
+.. code-block:: cmake
+
+ string(GENEX_STRIP <string> <output_variable>)
+
+.. versionadded:: 3.1
+
+Strip any :manual:`generator expressions <cmake-generator-expressions(7)>`
+from the input ``<string>`` and store the result in the ``<output_variable>``.
+
+.. _REPEAT:
+
+.. code-block:: cmake
+
+ string(REPEAT <string> <count> <output_variable>)
+
+.. versionadded:: 3.15
+
+Produce the output string as the input ``<string>`` repeated ``<count>`` times.
+
+Comparison
+^^^^^^^^^^
+
+.. _COMPARE:
+
+.. code-block:: cmake
+
+ string(COMPARE LESS <string1> <string2> <output_variable>)
+ string(COMPARE GREATER <string1> <string2> <output_variable>)
+ string(COMPARE EQUAL <string1> <string2> <output_variable>)
+ string(COMPARE NOTEQUAL <string1> <string2> <output_variable>)
+ string(COMPARE LESS_EQUAL <string1> <string2> <output_variable>)
+ string(COMPARE GREATER_EQUAL <string1> <string2> <output_variable>)
+
+Compare the strings and store true or false in the ``<output_variable>``.
+
+.. versionadded:: 3.7
+ Added the ``LESS_EQUAL`` and ``GREATER_EQUAL`` options.
+
+.. _`Supported Hash Algorithms`:
+
+Hashing
+^^^^^^^
+
+.. _`HASH`:
+
+.. code-block:: cmake
+
+ string(<HASH> <output_variable> <input>)
+
+Compute a cryptographic hash of the ``<input>`` string.
+The supported ``<HASH>`` algorithm names are:
+
+``MD5``
+ Message-Digest Algorithm 5, RFC 1321.
+``SHA1``
+ US Secure Hash Algorithm 1, RFC 3174.
+``SHA224``
+ US Secure Hash Algorithms, RFC 4634.
+``SHA256``
+ US Secure Hash Algorithms, RFC 4634.
+``SHA384``
+ US Secure Hash Algorithms, RFC 4634.
+``SHA512``
+ US Secure Hash Algorithms, RFC 4634.
+``SHA3_224``
+ Keccak SHA-3.
+``SHA3_256``
+ Keccak SHA-3.
+``SHA3_384``
+ Keccak SHA-3.
+``SHA3_512``
+ Keccak SHA-3.
+
+.. versionadded:: 3.8
+ Added the ``SHA3_*`` hash algorithms.
+
+Generation
+^^^^^^^^^^
+
+.. _ASCII:
+
+.. code-block:: cmake
+
+ string(ASCII <number> [<number> ...] <output_variable>)
+
+Convert all numbers into corresponding ASCII characters.
+
+.. _HEX:
+
+.. code-block:: cmake
+
+ string(HEX <string> <output_variable>)
+
+.. versionadded:: 3.18
+
+Convert each byte in the input ``<string>`` to its hexadecimal representation
+and store the concatenated hex digits in the ``<output_variable>``. Letters in
+the output (``a`` through ``f``) are in lowercase.
+
+.. _CONFIGURE:
+
+.. code-block:: cmake
+
+ string(CONFIGURE <string> <output_variable>
+ [@ONLY] [ESCAPE_QUOTES])
+
+Transform a ``<string>`` like :command:`configure_file` transforms a file.
+
+.. _MAKE_C_IDENTIFIER:
+
+.. code-block:: cmake
+
+ string(MAKE_C_IDENTIFIER <string> <output_variable>)
+
+Convert each non-alphanumeric character in the input ``<string>`` to an
+underscore and store the result in the ``<output_variable>``. If the first
+character of the ``<string>`` is a digit, an underscore will also be prepended
+to the result.
+
+.. _RANDOM:
+
+.. code-block:: cmake
+
+ string(RANDOM [LENGTH <length>] [ALPHABET <alphabet>]
+ [RANDOM_SEED <seed>] <output_variable>)
+
+Return a random string of given ``<length>`` consisting of
+characters from the given ``<alphabet>``. Default length is 5 characters
+and default alphabet is all numbers and upper and lower case letters.
+If an integer ``RANDOM_SEED`` is given, its value will be used to seed the
+random number generator.
+
+.. _TIMESTAMP:
+
+.. code-block:: cmake
+
+ string(TIMESTAMP <output_variable> [<format_string>] [UTC])
+
+Write a string representation of the current date
+and/or time to the ``<output_variable>``.
+
+If the command is unable to obtain a timestamp, the ``<output_variable>``
+will be set to the empty string ``""``.
+
+The optional ``UTC`` flag requests the current date/time representation to
+be in Coordinated Universal Time (UTC) rather than local time.
+
+The optional ``<format_string>`` may contain the following format
+specifiers:
+
+::
+
+ %% A literal percent sign (%).
+ %d The day of the current month (01-31).
+ %H The hour on a 24-hour clock (00-23).
+ %I The hour on a 12-hour clock (01-12).
+ %j The day of the current year (001-366).
+ %m The month of the current year (01-12).
+ %b Abbreviated month name (e.g. Oct).
+ %B Full month name (e.g. October).
+ %M The minute of the current hour (00-59).
+ %s Seconds since midnight (UTC) 1-Jan-1970 (UNIX time).
+ %S The second of the current minute.
+ 60 represents a leap second. (00-60)
+ %U The week number of the current year (00-53).
+ %w The day of the current week. 0 is Sunday. (0-6)
+ %a Abbreviated weekday name (e.g. Fri).
+ %A Full weekday name (e.g. Friday).
+ %y The last two digits of the current year (00-99)
+ %Y The current year.
+
+.. versionadded:: 3.6
+ ``%s`` format specifier (UNIX time).
+
+.. versionadded:: 3.7
+ ``%a`` and ``%b`` format specifiers (abbreviated month and weekday names).
+
+.. versionadded:: 3.8
+ ``%%`` specifier (literal ``%``).
+
+.. versionadded:: 3.7
+ ``%A`` and ``%B`` format specifiers (full month and weekday names).
+
+Unknown format specifiers will be ignored and copied to the output
+as-is.
+
+If no explicit ``<format_string>`` is given, it will default to:
+
+::
+
+ %Y-%m-%dT%H:%M:%S for local time.
+ %Y-%m-%dT%H:%M:%SZ for UTC.
+
+.. versionadded:: 3.8
+ If the ``SOURCE_DATE_EPOCH`` environment variable is set,
+ its value will be used instead of the current time.
+ See https://reproducible-builds.org/specs/source-date-epoch/ for details.
+
+.. _UUID:
+
+.. code-block:: cmake
+
+ string(UUID <output_variable> NAMESPACE <namespace> NAME <name>
+ TYPE <MD5|SHA1> [UPPER])
+
+.. versionadded:: 3.1
+
+Create a universally unique identifier (aka GUID) as per RFC4122
+based on the hash of the combined values of ``<namespace>``
+(which itself has to be a valid UUID) and ``<name>``.
+The hash algorithm can be either ``MD5`` (Version 3 UUID) or
+``SHA1`` (Version 5 UUID).
+A UUID has the format ``xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx``
+where each ``x`` represents a lower case hexadecimal character.
+Where required, an uppercase representation can be requested
+with the optional ``UPPER`` flag.
+
+.. _JSON:
+
+JSON
+^^^^
+
+.. versionadded:: 3.19
+
+Functionality for querying a JSON string.
+
+.. note::
+ In each of the following JSON-related subcommands, if the optional
+ ``ERROR_VARIABLE`` argument is given, errors will be reported in
+ ``<error-variable>`` and the ``<out-var>`` will be set to
+ ``<member|index>-[<member|index>...]-NOTFOUND`` with the path elements
+ up to the point where the error occurred, or just ``NOTFOUND`` if there
+ is no relevant path. If an error occurs but the ``ERROR_VARIABLE``
+ option is not present, a fatal error message is generated. If no error
+ occurs, the ``<error-variable>`` will be set to ``NOTFOUND``.
+
+.. _GET:
+.. code-block:: cmake
+
+ string(JSON <out-var> [ERROR_VARIABLE <error-variable>]
+ GET <json-string> <member|index> [<member|index> ...])
+
+Get an element from ``<json-string>`` at the location given
+by the list of ``<member|index>`` arguments.
+Array and object elements will be returned as a JSON string.
+Boolean elements will be returned as ``ON`` or ``OFF``.
+Null elements will be returned as an empty string.
+Number and string types will be returned as strings.
+
+.. _TYPE:
+.. code-block:: cmake
+
+ string(JSON <out-var> [ERROR_VARIABLE <error-variable>]
+ TYPE <json-string> <member|index> [<member|index> ...])
+
+Get the type of an element in ``<json-string>`` at the location
+given by the list of ``<member|index>`` arguments. The ``<out-var>``
+will be set to one of ``NULL``, ``NUMBER``, ``STRING``, ``BOOLEAN``,
+``ARRAY``, or ``OBJECT``.
+
+.. _MEMBER:
+.. code-block:: cmake
+
+ string(JSON <out-var> [ERROR_VARIABLE <error-var>]
+ MEMBER <json-string>
+ [<member|index> ...] <index>)
+
+Get the name of the ``<index>``-th member in ``<json-string>`` at the location
+given by the list of ``<member|index>`` arguments.
+Requires an element of object type.
+
+.. _JSONLENGTH:
+.. code-block:: cmake
+
+ string(JSON <out-var> [ERROR_VARIABLE <error-variable>]
+ LENGTH <json-string> <member|index> [<member|index> ...])
+
+Get the length of an element in ``<json-string>`` at the location
+given by the list of ``<member|index>`` arguments.
+Requires an element of array or object type.
+
+.. _REMOVE:
+.. code-block:: cmake
+
+ string(JSON <out-var> [ERROR_VARIABLE <error-variable>]
+ REMOVE <json-string> <member|index> [<member|index> ...])
+
+Remove an element from ``<json-string>`` at the location
+given by the list of ``<member|index>`` arguments. The JSON string
+without the removed element will be stored in ``<out-var>``.
+
+.. _SET:
+.. code-block:: cmake
+
+ string(JSON <out-var> [ERROR_VARIABLE <error-variable>]
+ SET <json-string> <member|index> [<member|index> ...] <value>)
+
+Set an element in ``<json-string>`` at the location
+given by the list of ``<member|index>`` arguments to ``<value>``.
+The contents of ``<value>`` should be valid JSON.
+
+.. _EQUAL:
+.. code-block:: cmake
+
+ string(JSON <out-var> [ERROR_VARIABLE <error-var>]
+ EQUAL <json-string1> <json-string2>)
+
+Compare the two JSON objects given by ``<json-string1>`` and ``<json-string2>``
+for equality. The contents of ``<json-string1>`` and ``<json-string2>``
+should be valid JSON. The ``<out-var>`` will be set to a true value if the
+JSON objects are considered equal, or a false value otherwise.
diff --git a/Help/command/subdir_depends.rst b/Help/command/subdir_depends.rst
new file mode 100644
index 0000000..0c1b3c1
--- /dev/null
+++ b/Help/command/subdir_depends.rst
@@ -0,0 +1,13 @@
+subdir_depends
+--------------
+
+Disallowed since version 3.0. See CMake Policy :policy:`CMP0029`.
+
+Does nothing.
+
+::
+
+ subdir_depends(subdir dep1 dep2 ...)
+
+Does not do anything. This command used to help projects order
+parallel builds correctly. This functionality is now automatic.
diff --git a/Help/command/subdirs.rst b/Help/command/subdirs.rst
new file mode 100644
index 0000000..530951b
--- /dev/null
+++ b/Help/command/subdirs.rst
@@ -0,0 +1,26 @@
+subdirs
+-------
+
+.. deprecated:: 3.0
+
+ Use the :command:`add_subdirectory` command instead.
+
+Add a list of subdirectories to the build.
+
+::
+
+ subdirs(dir1 dir2 ...[EXCLUDE_FROM_ALL exclude_dir1 exclude_dir2 ...]
+ [PREORDER] )
+
+Add a list of subdirectories to the build. The :command:`add_subdirectory`
+command should be used instead of ``subdirs`` although ``subdirs`` will still
+work. This will cause any CMakeLists.txt files in the sub directories
+to be processed by CMake. Any directories after the ``PREORDER`` flag are
+traversed first by makefile builds, the ``PREORDER`` flag has no effect on
+IDE projects. Any directories after the ``EXCLUDE_FROM_ALL`` marker will
+not be included in the top level makefile or project file. This is
+useful for having CMake create makefiles or projects for a set of
+examples in a project. You would want CMake to generate makefiles or
+project files for all the examples at the same time, but you would not
+want them to show up in the top level project or be built each time
+make is run from the top.
diff --git a/Help/command/target_compile_definitions.rst b/Help/command/target_compile_definitions.rst
new file mode 100644
index 0000000..3fb113a
--- /dev/null
+++ b/Help/command/target_compile_definitions.rst
@@ -0,0 +1,50 @@
+target_compile_definitions
+--------------------------
+
+Add compile definitions to a target.
+
+.. code-block:: cmake
+
+ target_compile_definitions(<target>
+ <INTERFACE|PUBLIC|PRIVATE> [items1...]
+ [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
+
+Specifies compile definitions to use when compiling a given ``<target>``. The
+named ``<target>`` must have been created by a command such as
+:command:`add_executable` or :command:`add_library` and must not be an
+:ref:`ALIAS target <Alias Targets>`.
+
+The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
+specify the scope of the following arguments. ``PRIVATE`` and ``PUBLIC``
+items will populate the :prop_tgt:`COMPILE_DEFINITIONS` property of
+``<target>``. ``PUBLIC`` and ``INTERFACE`` items will populate the
+:prop_tgt:`INTERFACE_COMPILE_DEFINITIONS` property of ``<target>``.
+The following arguments specify compile definitions. Repeated calls for the
+same ``<target>`` append items in the order called.
+
+.. versionadded:: 3.11
+ Allow setting ``INTERFACE`` items on :ref:`IMPORTED targets <Imported Targets>`.
+
+Arguments to ``target_compile_definitions`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
+Any leading ``-D`` on an item will be removed. Empty items are ignored.
+For example, the following are all equivalent:
+
+.. code-block:: cmake
+
+ target_compile_definitions(foo PUBLIC FOO)
+ target_compile_definitions(foo PUBLIC -DFOO) # -D removed
+ target_compile_definitions(foo PUBLIC "" FOO) # "" ignored
+ target_compile_definitions(foo PUBLIC -D FOO) # -D becomes "", then ignored
+
+Definitions may optionally have values:
+
+.. code-block:: cmake
+
+ target_compile_definitions(foo PUBLIC FOO=1)
+
+Note that many compilers treat ``-DFOO`` as equivalent to ``-DFOO=1``, but
+other tools may not recognize this in all circumstances (e.g. IntelliSense).
diff --git a/Help/command/target_compile_features.rst b/Help/command/target_compile_features.rst
new file mode 100644
index 0000000..58502bf
--- /dev/null
+++ b/Help/command/target_compile_features.rst
@@ -0,0 +1,37 @@
+target_compile_features
+-----------------------
+
+.. versionadded:: 3.1
+
+Add expected compiler features to a target.
+
+.. code-block:: cmake
+
+ target_compile_features(<target> <PRIVATE|PUBLIC|INTERFACE> <feature> [...])
+
+Specifies compiler features required when compiling a given target. If the
+feature is not listed in the :variable:`CMAKE_C_COMPILE_FEATURES`,
+:variable:`CMAKE_CUDA_COMPILE_FEATURES`, or :variable:`CMAKE_CXX_COMPILE_FEATURES`
+variables, then an error will be reported by CMake. If the use of the feature requires
+an additional compiler flag, such as ``-std=gnu++11``, the flag will be added
+automatically.
+
+The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
+specify the scope of the features. ``PRIVATE`` and ``PUBLIC`` items will
+populate the :prop_tgt:`COMPILE_FEATURES` property of ``<target>``.
+``PUBLIC`` and ``INTERFACE`` items will populate the
+:prop_tgt:`INTERFACE_COMPILE_FEATURES` property of ``<target>``.
+Repeated calls for the same ``<target>`` append items.
+
+.. versionadded:: 3.11
+ Allow setting ``INTERFACE`` items on :ref:`IMPORTED targets <Imported Targets>`.
+
+The named ``<target>`` must have been created by a command such as
+:command:`add_executable` or :command:`add_library` and must not be an
+:ref:`ALIAS target <Alias Targets>`.
+
+Arguments to ``target_compile_features`` may use "generator expressions"
+with the syntax ``$<...>``.
+See the :manual:`cmake-generator-expressions(7)` manual for available
+expressions. See the :manual:`cmake-compile-features(7)` manual for
+information on compile features and a list of supported compilers.
diff --git a/Help/command/target_compile_options.rst b/Help/command/target_compile_options.rst
new file mode 100644
index 0000000..e45b209
--- /dev/null
+++ b/Help/command/target_compile_options.rst
@@ -0,0 +1,52 @@
+target_compile_options
+----------------------
+
+Add compile options to a target.
+
+.. code-block:: cmake
+
+ target_compile_options(<target> [BEFORE]
+ <INTERFACE|PUBLIC|PRIVATE> [items1...]
+ [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
+
+Adds options to the :prop_tgt:`COMPILE_OPTIONS` or
+:prop_tgt:`INTERFACE_COMPILE_OPTIONS` target properties. These options
+are used when compiling the given ``<target>``, which must have been
+created by a command such as :command:`add_executable` or
+:command:`add_library` and must not be an :ref:`ALIAS target <Alias Targets>`.
+
+Arguments
+^^^^^^^^^
+
+If ``BEFORE`` is specified, the content will be prepended to the property
+instead of being appended.
+
+The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
+specify the scope of the following arguments. ``PRIVATE`` and ``PUBLIC``
+items will populate the :prop_tgt:`COMPILE_OPTIONS` property of
+``<target>``. ``PUBLIC`` and ``INTERFACE`` items will populate the
+:prop_tgt:`INTERFACE_COMPILE_OPTIONS` property of ``<target>``.
+The following arguments specify compile options. Repeated calls for the same
+``<target>`` append items in the order called.
+
+.. versionadded:: 3.11
+ Allow setting ``INTERFACE`` items on :ref:`IMPORTED targets <Imported Targets>`.
+
+Arguments to ``target_compile_options`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
+.. include:: OPTIONS_SHELL.txt
+
+See Also
+^^^^^^^^
+
+This command can be used to add any options. However, for adding
+preprocessor definitions and include directories it is recommended
+to use the more specific commands :command:`target_compile_definitions`
+and :command:`target_include_directories`.
+
+For directory-wide settings, there is the command :command:`add_compile_options`.
+
+For file-specific settings, there is the source file property :prop_sf:`COMPILE_OPTIONS`.
diff --git a/Help/command/target_include_directories.rst b/Help/command/target_include_directories.rst
new file mode 100644
index 0000000..3e53b2e
--- /dev/null
+++ b/Help/command/target_include_directories.rst
@@ -0,0 +1,64 @@
+target_include_directories
+--------------------------
+
+Add include directories to a target.
+
+.. code-block:: cmake
+
+ target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
+ <INTERFACE|PUBLIC|PRIVATE> [items1...]
+ [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
+
+Specifies include directories to use when compiling a given target.
+The named ``<target>`` must have been created by a command such
+as :command:`add_executable` or :command:`add_library` and must not be an
+:ref:`ALIAS target <Alias Targets>`.
+
+By using ``AFTER`` or ``BEFORE`` explicitly, you can select between appending
+and prepending, independent of the default.
+
+The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to specify
+the scope of the following arguments. ``PRIVATE`` and ``PUBLIC`` items will
+populate the :prop_tgt:`INCLUDE_DIRECTORIES` property of ``<target>``.
+``PUBLIC`` and ``INTERFACE`` items will populate the
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` property of ``<target>``.
+The following arguments specify include directories.
+
+.. versionadded:: 3.11
+ Allow setting ``INTERFACE`` items on :ref:`IMPORTED targets <Imported Targets>`.
+
+Specified include directories may be absolute paths or relative paths.
+Repeated calls for the same <target> append items in the order called. If
+``SYSTEM`` is specified, the compiler will be told the
+directories are meant as system include directories on some platforms
+(signalling this setting might achieve effects such as the compiler
+skipping warnings, or these fixed-install system files not being
+considered in dependency calculations - see compiler docs). If ``SYSTEM``
+is used together with ``PUBLIC`` or ``INTERFACE``, the
+:prop_tgt:`INTERFACE_SYSTEM_INCLUDE_DIRECTORIES` target property will be
+populated with the specified directories.
+
+Arguments to ``target_include_directories`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
+Include directories usage requirements commonly differ between the build-tree
+and the install-tree. The ``BUILD_INTERFACE`` and ``INSTALL_INTERFACE``
+generator expressions can be used to describe separate usage requirements
+based on the usage location. Relative paths are allowed within the
+``INSTALL_INTERFACE`` expression and are interpreted relative to the
+installation prefix. For example:
+
+.. code-block:: cmake
+
+ target_include_directories(mylib PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/mylib>
+ $<INSTALL_INTERFACE:include/mylib> # <prefix>/include/mylib
+ )
+
+Creating Relocatable Packages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. |INTERFACE_PROPERTY_LINK| replace:: :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`
+.. include:: /include/INTERFACE_INCLUDE_DIRECTORIES_WARNING.txt
diff --git a/Help/command/target_link_directories.rst b/Help/command/target_link_directories.rst
new file mode 100644
index 0000000..bb75a3d
--- /dev/null
+++ b/Help/command/target_link_directories.rst
@@ -0,0 +1,57 @@
+target_link_directories
+-----------------------
+
+.. versionadded:: 3.13
+
+Add link directories to a target.
+
+.. code-block:: cmake
+
+ target_link_directories(<target> [BEFORE]
+ <INTERFACE|PUBLIC|PRIVATE> [items1...]
+ [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
+
+Specifies the paths in which the linker should search for libraries when
+linking a given target. Each item can be an absolute or relative path,
+with the latter being interpreted as relative to the current source
+directory. These items will be added to the link command.
+
+The named ``<target>`` must have been created by a command such as
+:command:`add_executable` or :command:`add_library` and must not be an
+:ref:`ALIAS target <Alias Targets>`.
+
+The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
+specify the scope of the items that follow them. ``PRIVATE`` and
+``PUBLIC`` items will populate the :prop_tgt:`LINK_DIRECTORIES` property
+of ``<target>``. ``PUBLIC`` and ``INTERFACE`` items will populate the
+:prop_tgt:`INTERFACE_LINK_DIRECTORIES` property of ``<target>``
+(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items).
+Each item specifies a link directory and will be converted to an absolute
+path if necessary before adding it to the relevant property. Repeated
+calls for the same ``<target>`` append items in the order called.
+
+If ``BEFORE`` is specified, the content will be prepended to the relevant
+property instead of being appended.
+
+Arguments to ``target_link_directories`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
+.. note::
+
+ This command is rarely necessary and should be avoided where there are
+ other choices. Prefer to pass full absolute paths to libraries where
+ possible, since this ensures the correct library will always be linked.
+ The :command:`find_library` command provides the full path, which can
+ generally be used directly in calls to :command:`target_link_libraries`.
+ Situations where a library search path may be needed include:
+
+ - Project generators like Xcode where the user can switch target
+ architecture at build time, but a full path to a library cannot
+ be used because it only provides one architecture (i.e. it is not
+ a universal binary).
+ - Libraries may themselves have other private library dependencies
+ that expect to be found via ``RPATH`` mechanisms, but some linkers
+ are not able to fully decode those paths (e.g. due to the presence
+ of things like ``$ORIGIN``).
diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst
new file mode 100644
index 0000000..872e264
--- /dev/null
+++ b/Help/command/target_link_libraries.rst
@@ -0,0 +1,322 @@
+target_link_libraries
+---------------------
+
+.. only:: html
+
+ .. contents::
+
+Specify libraries or flags to use when linking a given target and/or
+its dependents. :ref:`Usage requirements <Target Usage Requirements>`
+from linked library targets will be propagated. Usage requirements
+of a target's dependencies affect compilation of its own sources.
+
+Overview
+^^^^^^^^
+
+This command has several signatures as detailed in subsections below.
+All of them have the general form
+
+.. code-block:: cmake
+
+ target_link_libraries(<target> ... <item>... ...)
+
+The named ``<target>`` must have been created by a command such as
+:command:`add_executable` or :command:`add_library` and must not be an
+:ref:`ALIAS target <Alias Targets>`. If policy :policy:`CMP0079` is not
+set to ``NEW`` then the target must have been created in the current
+directory. Repeated calls for the same ``<target>`` append items in
+the order called.
+
+.. versionadded:: 3.13
+ The ``<target>`` doesn't have to be defined in the same directory as the
+ ``target_link_libraries`` call.
+
+Each ``<item>`` may be:
+
+* **A library target name**: The generated link line will have the
+ full path to the linkable library file associated with the target.
+ The buildsystem will have a dependency to re-link ``<target>`` if
+ the library file changes.
+
+ The named target must be created by :command:`add_library` within
+ the project or as an :ref:`IMPORTED library <Imported Targets>`.
+ If it is created within the project an ordering dependency will
+ automatically be added in the build system to make sure the named
+ library target is up-to-date before the ``<target>`` links.
+
+ If an imported library has the :prop_tgt:`IMPORTED_NO_SONAME`
+ target property set, CMake may ask the linker to search for
+ the library instead of using the full path
+ (e.g. ``/usr/lib/libfoo.so`` becomes ``-lfoo``).
+
+ The full path to the target's artifact will be quoted/escaped for
+ the shell automatically.
+
+* **A full path to a library file**: The generated link line will
+ normally preserve the full path to the file. The buildsystem will
+ have a dependency to re-link ``<target>`` if the library file changes.
+
+ There are some cases where CMake may ask the linker to search for
+ the library (e.g. ``/usr/lib/libfoo.so`` becomes ``-lfoo``), such
+ as when a shared library is detected to have no ``SONAME`` field.
+ See policy :policy:`CMP0060` for discussion of another case.
+
+ If the library file is in a macOS framework, the ``Headers`` directory
+ of the framework will also be processed as a
+ :ref:`usage requirement <Target Usage Requirements>`. This has the same
+ effect as passing the framework directory as an include directory.
+
+ .. versionadded:: 3.8
+ On :ref:`Visual Studio Generators` for VS 2010 and above, library files
+ ending in ``.targets`` will be treated as MSBuild targets files and
+ imported into generated project files. This is not supported by other
+ generators.
+
+ The full path to the library file will be quoted/escaped for
+ the shell automatically.
+
+* **A plain library name**: The generated link line will ask the linker
+ to search for the library (e.g. ``foo`` becomes ``-lfoo`` or ``foo.lib``).
+
+ The library name/flag is treated as a command-line string fragment and
+ will be used with no extra quoting or escaping.
+
+* **A link flag**: Item names starting with ``-``, but not ``-l`` or
+ ``-framework``, are treated as linker flags. Note that such flags will
+ be treated like any other library link item for purposes of transitive
+ dependencies, so they are generally safe to specify only as private link
+ items that will not propagate to dependents.
+
+ Link flags specified here are inserted into the link command in the same
+ place as the link libraries. This might not be correct, depending on
+ the linker. Use the :prop_tgt:`LINK_OPTIONS` target property or
+ :command:`target_link_options` command to add link
+ flags explicitly. The flags will then be placed at the toolchain-defined
+ flag position in the link command.
+
+ .. versionadded:: 3.13
+ :prop_tgt:`LINK_OPTIONS` target property and :command:`target_link_options`
+ command. For earlier versions of CMake, use :prop_tgt:`LINK_FLAGS`
+ property instead.
+
+ The link flag is treated as a command-line string fragment and
+ will be used with no extra quoting or escaping.
+
+* **A generator expression**: A ``$<...>`` :manual:`generator expression
+ <cmake-generator-expressions(7)>` may evaluate to any of the above
+ items or to a :ref:`semicolon-separated list <CMake Language Lists>` of them.
+ If the ``...`` contains any ``;`` characters, e.g. after evaluation
+ of a ``${list}`` variable, be sure to use an explicitly quoted
+ argument ``"$<...>"`` so that this command receives it as a
+ single ``<item>``.
+
+ Additionally, a generator expression may be used as a fragment of
+ any of the above items, e.g. ``foo$<1:_d>``.
+
+ Note that generator expressions will not be used in OLD handling of
+ policy :policy:`CMP0003` or policy :policy:`CMP0004`.
+
+* A ``debug``, ``optimized``, or ``general`` keyword immediately followed
+ by another ``<item>``. The item following such a keyword will be used
+ only for the corresponding build configuration. The ``debug`` keyword
+ corresponds to the ``Debug`` configuration (or to configurations named
+ in the :prop_gbl:`DEBUG_CONFIGURATIONS` global property if it is set).
+ The ``optimized`` keyword corresponds to all other configurations. The
+ ``general`` keyword corresponds to all configurations, and is purely
+ optional. Higher granularity may be achieved for per-configuration
+ rules by creating and linking to
+ :ref:`IMPORTED library targets <Imported Targets>`.
+ These keywords are interpreted immediately by this command and therefore
+ have no special meaning when produced by a generator expression.
+
+Items containing ``::``, such as ``Foo::Bar``, are assumed to be
+:ref:`IMPORTED <Imported Targets>` or :ref:`ALIAS <Alias Targets>` library
+target names and will cause an error if no such target exists.
+See policy :policy:`CMP0028`.
+
+See the :manual:`cmake-buildsystem(7)` manual for more on defining
+buildsystem properties.
+
+Libraries for a Target and/or its Dependents
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ target_link_libraries(<target>
+ <PRIVATE|PUBLIC|INTERFACE> <item>...
+ [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
+
+The ``PUBLIC``, ``PRIVATE`` and ``INTERFACE`` keywords can be used to
+specify both the link dependencies and the link interface in one command.
+Libraries and targets following ``PUBLIC`` are linked to, and are made
+part of the link interface. Libraries and targets following ``PRIVATE``
+are linked to, but are not made part of the link interface. Libraries
+following ``INTERFACE`` are appended to the link interface and are not
+used for linking ``<target>``.
+
+Libraries for both a Target and its Dependents
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ target_link_libraries(<target> <item>...)
+
+Library dependencies are transitive by default with this signature.
+When this target is linked into another target then the libraries
+linked to this target will appear on the link line for the other
+target too. This transitive "link interface" is stored in the
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` target property and may be overridden
+by setting the property directly. When :policy:`CMP0022` is not set to
+``NEW``, transitive linking is built in but may be overridden by the
+:prop_tgt:`LINK_INTERFACE_LIBRARIES` property. Calls to other signatures
+of this command may set the property making any libraries linked
+exclusively by this signature private.
+
+Libraries for a Target and/or its Dependents (Legacy)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ target_link_libraries(<target>
+ <LINK_PRIVATE|LINK_PUBLIC> <lib>...
+ [<LINK_PRIVATE|LINK_PUBLIC> <lib>...]...)
+
+The ``LINK_PUBLIC`` and ``LINK_PRIVATE`` modes can be used to specify both
+the link dependencies and the link interface in one command.
+
+This signature is for compatibility only. Prefer the ``PUBLIC`` or
+``PRIVATE`` keywords instead.
+
+Libraries and targets following ``LINK_PUBLIC`` are linked to, and are
+made part of the :prop_tgt:`INTERFACE_LINK_LIBRARIES`. If policy
+:policy:`CMP0022` is not ``NEW``, they are also made part of the
+:prop_tgt:`LINK_INTERFACE_LIBRARIES`. Libraries and targets following
+``LINK_PRIVATE`` are linked to, but are not made part of the
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` (or :prop_tgt:`LINK_INTERFACE_LIBRARIES`).
+
+Libraries for Dependents Only (Legacy)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ target_link_libraries(<target> LINK_INTERFACE_LIBRARIES <item>...)
+
+The ``LINK_INTERFACE_LIBRARIES`` mode appends the libraries to the
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` target property instead of using them
+for linking. If policy :policy:`CMP0022` is not ``NEW``, then this mode
+also appends libraries to the :prop_tgt:`LINK_INTERFACE_LIBRARIES` and its
+per-configuration equivalent.
+
+This signature is for compatibility only. Prefer the ``INTERFACE`` mode
+instead.
+
+Libraries specified as ``debug`` are wrapped in a generator expression to
+correspond to debug builds. If policy :policy:`CMP0022` is
+not ``NEW``, the libraries are also appended to the
+:prop_tgt:`LINK_INTERFACE_LIBRARIES_DEBUG <LINK_INTERFACE_LIBRARIES_<CONFIG>>`
+property (or to the properties corresponding to configurations listed in
+the :prop_gbl:`DEBUG_CONFIGURATIONS` global property if it is set).
+Libraries specified as ``optimized`` are appended to the
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` property. If policy :policy:`CMP0022`
+is not ``NEW``, they are also appended to the
+:prop_tgt:`LINK_INTERFACE_LIBRARIES` property. Libraries specified as
+``general`` (or without any keyword) are treated as if specified for both
+``debug`` and ``optimized``.
+
+Linking Object Libraries
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.12
+
+:ref:`Object Libraries` may be used as the ``<target>`` (first) argument
+of ``target_link_libraries`` to specify dependencies of their sources
+on other libraries. For example, the code
+
+.. code-block:: cmake
+
+ add_library(A SHARED a.c)
+ target_compile_definitions(A PUBLIC A)
+
+ add_library(obj OBJECT obj.c)
+ target_compile_definitions(obj PUBLIC OBJ)
+ target_link_libraries(obj PUBLIC A)
+
+compiles ``obj.c`` with ``-DA -DOBJ`` and establishes usage requirements
+for ``obj`` that propagate to its dependents.
+
+Normal libraries and executables may link to :ref:`Object Libraries`
+to get their objects and usage requirements. Continuing the above
+example, the code
+
+.. code-block:: cmake
+
+ add_library(B SHARED b.c)
+ target_link_libraries(B PUBLIC obj)
+
+compiles ``b.c`` with ``-DA -DOBJ``, creates shared library ``B``
+with object files from ``b.c`` and ``obj.c``, and links ``B`` to ``A``.
+Furthermore, the code
+
+.. code-block:: cmake
+
+ add_executable(main main.c)
+ target_link_libraries(main B)
+
+compiles ``main.c`` with ``-DA -DOBJ`` and links executable ``main``
+to ``B`` and ``A``. The object library's usage requirements are
+propagated transitively through ``B``, but its object files are not.
+
+:ref:`Object Libraries` may "link" to other object libraries to get
+usage requirements, but since they do not have a link step nothing
+is done with their object files. Continuing from the above example,
+the code:
+
+.. code-block:: cmake
+
+ add_library(obj2 OBJECT obj2.c)
+ target_link_libraries(obj2 PUBLIC obj)
+
+ add_executable(main2 main2.c)
+ target_link_libraries(main2 obj2)
+
+compiles ``obj2.c`` with ``-DA -DOBJ``, creates executable ``main2``
+with object files from ``main2.c`` and ``obj2.c``, and links ``main2``
+to ``A``.
+
+In other words, when :ref:`Object Libraries` appear in a target's
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` property they will be
+treated as :ref:`Interface Libraries`, but when they appear in
+a target's :prop_tgt:`LINK_LIBRARIES` property their object files
+will be included in the link too.
+
+Cyclic Dependencies of Static Libraries
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The library dependency graph is normally acyclic (a DAG), but in the case
+of mutually-dependent ``STATIC`` libraries CMake allows the graph to
+contain cycles (strongly connected components). When another target links
+to one of the libraries, CMake repeats the entire connected component.
+For example, the code
+
+.. code-block:: cmake
+
+ add_library(A STATIC a.c)
+ add_library(B STATIC b.c)
+ target_link_libraries(A B)
+ target_link_libraries(B A)
+ add_executable(main main.c)
+ target_link_libraries(main A)
+
+links ``main`` to ``A B A B``. While one repetition is usually
+sufficient, pathological object file and symbol arrangements can require
+more. One may handle such cases by using the
+:prop_tgt:`LINK_INTERFACE_MULTIPLICITY` target property or by manually
+repeating the component in the last ``target_link_libraries`` call.
+However, if two archives are really so interdependent they should probably
+be combined into a single archive, perhaps by using :ref:`Object Libraries`.
+
+Creating Relocatable Packages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. |INTERFACE_PROPERTY_LINK| replace:: :prop_tgt:`INTERFACE_LINK_LIBRARIES`
+.. include:: /include/INTERFACE_LINK_LIBRARIES_WARNING.txt
diff --git a/Help/command/target_link_options.rst b/Help/command/target_link_options.rst
new file mode 100644
index 0000000..87dff39
--- /dev/null
+++ b/Help/command/target_link_options.rst
@@ -0,0 +1,54 @@
+target_link_options
+-------------------
+
+.. versionadded:: 3.13
+
+Add options to the link step for an executable, shared library or module
+library target.
+
+.. code-block:: cmake
+
+ target_link_options(<target> [BEFORE]
+ <INTERFACE|PUBLIC|PRIVATE> [items1...]
+ [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
+
+The named ``<target>`` must have been created by a command such as
+:command:`add_executable` or :command:`add_library` and must not be an
+:ref:`ALIAS target <Alias Targets>`.
+
+This command can be used to add any link options, but alternative commands
+exist to add libraries (:command:`target_link_libraries` or
+:command:`link_libraries`). See documentation of the
+:prop_dir:`directory <LINK_OPTIONS>` and
+:prop_tgt:`target <LINK_OPTIONS>` ``LINK_OPTIONS`` properties.
+
+.. note::
+
+ This command cannot be used to add options for static library targets,
+ since they do not use a linker. To add archiver or MSVC librarian flags,
+ see the :prop_tgt:`STATIC_LIBRARY_OPTIONS` target property.
+
+If ``BEFORE`` is specified, the content will be prepended to the property
+instead of being appended.
+
+The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
+specify the scope of the following arguments. ``PRIVATE`` and ``PUBLIC``
+items will populate the :prop_tgt:`LINK_OPTIONS` property of
+``<target>``. ``PUBLIC`` and ``INTERFACE`` items will populate the
+:prop_tgt:`INTERFACE_LINK_OPTIONS` property of ``<target>``.
+The following arguments specify link options. Repeated calls for the same
+``<target>`` append items in the order called.
+
+.. note::
+ :ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items.
+
+Arguments to ``target_link_options`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
+.. include:: DEVICE_LINK_OPTIONS.txt
+
+.. include:: OPTIONS_SHELL.txt
+
+.. include:: LINK_OPTIONS_LINKER.txt
diff --git a/Help/command/target_precompile_headers.rst b/Help/command/target_precompile_headers.rst
new file mode 100644
index 0000000..9f7dabb
--- /dev/null
+++ b/Help/command/target_precompile_headers.rst
@@ -0,0 +1,125 @@
+target_precompile_headers
+-------------------------
+
+.. versionadded:: 3.16
+
+Add a list of header files to precompile.
+
+Precompiling header files can speed up compilation by creating a partially
+processed version of some header files, and then using that version during
+compilations rather than repeatedly parsing the original headers.
+
+Main Form
+^^^^^^^^^
+
+.. code-block:: cmake
+
+ target_precompile_headers(<target>
+ <INTERFACE|PUBLIC|PRIVATE> [header1...]
+ [<INTERFACE|PUBLIC|PRIVATE> [header2...] ...])
+
+The command adds header files to the :prop_tgt:`PRECOMPILE_HEADERS` and/or
+:prop_tgt:`INTERFACE_PRECOMPILE_HEADERS` target properties of ``<target>``.
+The named ``<target>`` must have been created by a command such as
+:command:`add_executable` or :command:`add_library` and must not be an
+:ref:`ALIAS target <Alias Targets>`.
+
+The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
+specify the scope of the following arguments. ``PRIVATE`` and ``PUBLIC``
+items will populate the :prop_tgt:`PRECOMPILE_HEADERS` property of
+``<target>``. ``PUBLIC`` and ``INTERFACE`` items will populate the
+:prop_tgt:`INTERFACE_PRECOMPILE_HEADERS` property of ``<target>``
+(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items).
+Repeated calls for the same ``<target>`` will append items in the order called.
+
+Projects should generally avoid using ``PUBLIC`` or ``INTERFACE`` for targets
+that will be :ref:`exported <install(EXPORT)>`, or they should at least use
+the :genex:`$<BUILD_INTERFACE:...>` generator expression to prevent precompile
+headers from appearing in an installed exported target. Consumers of a target
+should typically be in control of what precompile headers they use, not have
+precompile headers forced on them by the targets being consumed (since
+precompile headers are not typically usage requirements). A notable exception
+to this is where an :ref:`interface library <Interface Libraries>` is created
+to define a commonly used set of precompile headers in one place and then other
+targets link to that interface library privately. In this case, the interface
+library exists specifically to propagate the precompile headers to its
+consumers and the consumer is effectively still in control, since it decides
+whether to link to the interface library or not.
+
+The list of header files is used to generate a header file named
+``cmake_pch.h|xx`` which is used to generate the precompiled header file
+(``.pch``, ``.gch``, ``.pchi``) artifact. The ``cmake_pch.h|xx`` header
+file will be force included (``-include`` for GCC, ``/FI`` for MSVC) to
+all source files, so sources do not need to have ``#include "pch.h"``.
+
+Header file names specified with angle brackets (e.g. ``<unordered_map>``) or
+explicit double quotes (escaped for the :manual:`cmake-language(7)`,
+e.g. ``[["other_header.h"]]``) will be treated as is, and include directories
+must be available for the compiler to find them. Other header file names
+(e.g. ``project_header.h``) are interpreted as being relative to the current
+source directory (e.g. :variable:`CMAKE_CURRENT_SOURCE_DIR`) and will be
+included by absolute path. For example:
+
+.. code-block:: cmake
+
+ target_precompile_headers(myTarget
+ PUBLIC
+ project_header.h
+ PRIVATE
+ [["other_header.h"]]
+ <unordered_map>
+ )
+
+Arguments to ``target_precompile_headers()`` may use "generator expressions"
+with the syntax ``$<...>``.
+See the :manual:`cmake-generator-expressions(7)` manual for available
+expressions.
+The :genex:`$<COMPILE_LANGUAGE:...>` generator expression is particularly
+useful for specifying a language-specific header to precompile for
+only one language (e.g. ``CXX`` and not ``C``). In this case, header
+file names that are not explicitly in double quotes or angle brackets
+must be specified by absolute path. Also, when specifying angle brackets
+inside a generator expression, be sure to encode the closing ``>`` as
+``$<ANGLE-R>``. For example:
+
+.. code-block:: cmake
+
+ target_precompile_headers(mylib PRIVATE
+ "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_only.h>"
+ "$<$<COMPILE_LANGUAGE:C>:<stddef.h$<ANGLE-R>>"
+ "$<$<COMPILE_LANGUAGE:CXX>:<cstddef$<ANGLE-R>>"
+ )
+
+
+Reusing Precompile Headers
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The command also supports a second signature which can be used to specify that
+one target re-uses a precompiled header file artifact from another target
+instead of generating its own:
+
+.. code-block:: cmake
+
+ target_precompile_headers(<target> REUSE_FROM <other_target>)
+
+This form sets the :prop_tgt:`PRECOMPILE_HEADERS_REUSE_FROM` property to
+``<other_target>`` and adds a dependency such that ``<target>`` will depend
+on ``<other_target>``. CMake will halt with an error if the
+:prop_tgt:`PRECOMPILE_HEADERS` property of ``<target>`` is already set when
+the ``REUSE_FROM`` form is used.
+
+.. note::
+
+ The ``REUSE_FROM`` form requires the same set of compiler options,
+ compiler flags and compiler definitions for both ``<target>`` and
+ ``<other_target>``. Some compilers (e.g. GCC) may issue a warning if the
+ precompiled header file cannot be used (``-Winvalid-pch``).
+
+See Also
+^^^^^^^^
+
+To disable precompile headers for specific targets, see the
+:prop_tgt:`DISABLE_PRECOMPILE_HEADERS` target property.
+
+To prevent precompile headers from being used when compiling a specific
+source file, see the :prop_sf:`SKIP_PRECOMPILE_HEADERS` source file property.
diff --git a/Help/command/target_sources.rst b/Help/command/target_sources.rst
new file mode 100644
index 0000000..520614a
--- /dev/null
+++ b/Help/command/target_sources.rst
@@ -0,0 +1,48 @@
+target_sources
+--------------
+
+.. versionadded:: 3.1
+
+Add sources to a target.
+
+.. code-block:: cmake
+
+ target_sources(<target>
+ <INTERFACE|PUBLIC|PRIVATE> [items1...]
+ [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
+
+Specifies sources to use when building a target and/or its dependents.
+The named ``<target>`` must have been created by a command such as
+:command:`add_executable` or :command:`add_library` or
+:command:`add_custom_target` and must not be an
+:ref:`ALIAS target <Alias Targets>`.
+
+.. versionchanged:: 3.13
+ Relative source file paths are interpreted as being relative to the current
+ source directory (i.e. :variable:`CMAKE_CURRENT_SOURCE_DIR`).
+ See policy :policy:`CMP0076`.
+
+.. versionadded:: 3.20
+ ``<target>`` can be a custom target.
+
+The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
+specify the scope of the items following them. ``PRIVATE`` and ``PUBLIC``
+items will populate the :prop_tgt:`SOURCES` property of
+``<target>``, which are used when building the target itself.
+``PUBLIC`` and ``INTERFACE`` items will populate the
+:prop_tgt:`INTERFACE_SOURCES` property of ``<target>``, which are used
+when building dependents.
+The following arguments specify sources. Repeated calls for the same
+``<target>`` append items in the order called. The targets created by
+:command:`add_custom_target` can only have ``PRIVATE`` scope.
+
+.. versionadded:: 3.3
+ Allow exporting targets with :prop_tgt:`INTERFACE_SOURCES`.
+
+.. versionadded:: 3.11
+ Allow setting ``INTERFACE`` items on :ref:`IMPORTED targets <Imported Targets>`.
+
+Arguments to ``target_sources`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
diff --git a/Help/command/try_compile.rst b/Help/command/try_compile.rst
new file mode 100644
index 0000000..06da910
--- /dev/null
+++ b/Help/command/try_compile.rst
@@ -0,0 +1,214 @@
+try_compile
+-----------
+
+.. only:: html
+
+ .. contents::
+
+Try building some code.
+
+Try Compiling Whole Projects
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ try_compile(<resultVar> <bindir> <srcdir>
+ <projectName> [<targetName>] [CMAKE_FLAGS <flags>...]
+ [OUTPUT_VARIABLE <var>])
+
+Try building a project. The success or failure of the ``try_compile``,
+i.e. ``TRUE`` or ``FALSE`` respectively, is returned in ``<resultVar>``.
+
+.. versionadded:: 3.14
+ The name of the ``<resultVar>`` is defined by the user. Previously, it had
+ a fixed name ``RESULT_VAR``.
+
+In this form, ``<srcdir>`` should contain a complete CMake project with a
+``CMakeLists.txt`` file and all sources. The ``<bindir>`` and ``<srcdir>``
+will not be deleted after this command is run. Specify ``<targetName>`` to
+build a specific target instead of the ``all`` or ``ALL_BUILD`` target. See
+below for the meaning of other options.
+
+Try Compiling Source Files
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ try_compile(<resultVar> <bindir> <srcfile|SOURCES srcfile...>
+ [CMAKE_FLAGS <flags>...]
+ [COMPILE_DEFINITIONS <defs>...]
+ [LINK_OPTIONS <options>...]
+ [LINK_LIBRARIES <libs>...]
+ [OUTPUT_VARIABLE <var>]
+ [COPY_FILE <fileName> [COPY_FILE_ERROR <var>]]
+ [<LANG>_STANDARD <std>]
+ [<LANG>_STANDARD_REQUIRED <bool>]
+ [<LANG>_EXTENSIONS <bool>]
+ )
+
+Try building an executable or static library from one or more source files
+(which one is determined by the :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE`
+variable). The success or failure of the ``try_compile``, i.e. ``TRUE`` or
+``FALSE`` respectively, is returned in ``<resultVar>``.
+
+.. versionadded:: 3.14
+ The name of the ``<resultVar>`` is defined by the user. Previously, it had
+ a fixed name ``RESULT_VAR``.
+
+In this form, one or more source files must be provided. If
+:variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` is unset or is set to ``EXECUTABLE``,
+the sources must include a definition for ``main`` and CMake will create a
+``CMakeLists.txt`` file to build the source(s) as an executable.
+If :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` is set to ``STATIC_LIBRARY``,
+a static library will be built instead and no definition for ``main`` is
+required. For an executable, the generated ``CMakeLists.txt`` file would
+contain something like the following:
+
+.. code-block:: cmake
+
+ add_definitions(<expanded COMPILE_DEFINITIONS from caller>)
+ include_directories(${INCLUDE_DIRECTORIES})
+ link_directories(${LINK_DIRECTORIES})
+ add_executable(cmTryCompileExec <srcfile>...)
+ target_link_options(cmTryCompileExec PRIVATE <LINK_OPTIONS from caller>)
+ target_link_libraries(cmTryCompileExec ${LINK_LIBRARIES})
+
+The options are:
+
+``CMAKE_FLAGS <flags>...``
+ Specify flags of the form ``-DVAR:TYPE=VALUE`` to be passed to
+ the ``cmake`` command-line used to drive the test build.
+ The above example shows how values for variables
+ ``INCLUDE_DIRECTORIES``, ``LINK_DIRECTORIES``, and ``LINK_LIBRARIES``
+ are used.
+
+``COMPILE_DEFINITIONS <defs>...``
+ Specify ``-Ddefinition`` arguments to pass to :command:`add_definitions`
+ in the generated test project.
+
+``COPY_FILE <fileName>``
+ Copy the built executable or static library to the given ``<fileName>``.
+
+``COPY_FILE_ERROR <var>``
+ Use after ``COPY_FILE`` to capture into variable ``<var>`` any error
+ message encountered while trying to copy the file.
+
+``LINK_LIBRARIES <libs>...``
+ Specify libraries to be linked in the generated project.
+ The list of libraries may refer to system libraries and to
+ :ref:`Imported Targets <Imported Targets>` from the calling project.
+
+ If this option is specified, any ``-DLINK_LIBRARIES=...`` value
+ given to the ``CMAKE_FLAGS`` option will be ignored.
+
+``LINK_OPTIONS <options>...``
+ .. versionadded:: 3.14
+
+ Specify link step options to pass to :command:`target_link_options` or to
+ set the :prop_tgt:`STATIC_LIBRARY_OPTIONS` target property in the generated
+ project, depending on the :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable.
+
+``OUTPUT_VARIABLE <var>``
+ Store the output from the build process in the given variable.
+
+``<LANG>_STANDARD <std>``
+ .. versionadded:: 3.8
+
+ Specify the :prop_tgt:`C_STANDARD`, :prop_tgt:`CXX_STANDARD`,
+ :prop_tgt:`OBJC_STANDARD`, :prop_tgt:`OBJCXX_STANDARD`,
+ or :prop_tgt:`CUDA_STANDARD` target property of the generated project.
+
+``<LANG>_STANDARD_REQUIRED <bool>``
+ .. versionadded:: 3.8
+
+ Specify the :prop_tgt:`C_STANDARD_REQUIRED`,
+ :prop_tgt:`CXX_STANDARD_REQUIRED`, :prop_tgt:`OBJC_STANDARD_REQUIRED`,
+ :prop_tgt:`OBJCXX_STANDARD_REQUIRED`,or :prop_tgt:`CUDA_STANDARD_REQUIRED`
+ target property of the generated project.
+
+``<LANG>_EXTENSIONS <bool>``
+ .. versionadded:: 3.8
+
+ Specify the :prop_tgt:`C_EXTENSIONS`, :prop_tgt:`CXX_EXTENSIONS`,
+ :prop_tgt:`OBJC_EXTENSIONS`, :prop_tgt:`OBJCXX_EXTENSIONS`,
+ or :prop_tgt:`CUDA_EXTENSIONS` target property of the generated project.
+
+In this version all files in ``<bindir>/CMakeFiles/CMakeTmp`` will be
+cleaned automatically. For debugging, ``--debug-trycompile`` can be
+passed to ``cmake`` to avoid this clean. However, multiple sequential
+``try_compile`` operations reuse this single output directory. If you use
+``--debug-trycompile``, you can only debug one ``try_compile`` call at a time.
+The recommended procedure is to protect all ``try_compile`` calls in your
+project by ``if(NOT DEFINED <resultVar>)`` logic, configure with cmake
+all the way through once, then delete the cache entry associated with
+the try_compile call of interest, and then re-run cmake again with
+``--debug-trycompile``.
+
+Other Behavior Settings
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.4
+ If set, the following variables are passed in to the generated
+ try_compile CMakeLists.txt to initialize compile target properties with
+ default values:
+
+ * :variable:`CMAKE_CUDA_RUNTIME_LIBRARY`
+ * :variable:`CMAKE_ENABLE_EXPORTS`
+ * :variable:`CMAKE_LINK_SEARCH_START_STATIC`
+ * :variable:`CMAKE_LINK_SEARCH_END_STATIC`
+ * :variable:`CMAKE_MSVC_RUNTIME_LIBRARY`
+ * :variable:`CMAKE_POSITION_INDEPENDENT_CODE`
+
+ If :policy:`CMP0056` is set to ``NEW``, then
+ :variable:`CMAKE_EXE_LINKER_FLAGS` is passed in as well.
+
+.. versionchanged:: 3.14
+ If :policy:`CMP0083` is set to ``NEW``, then in order to obtain correct
+ behavior at link time, the ``check_pie_supported()`` command from the
+ :module:`CheckPIESupported` module must be called before using the
+ :command:`try_compile` command.
+
+The current settings of :policy:`CMP0065` and :policy:`CMP0083` are propagated
+through to the generated test project.
+
+Set the :variable:`CMAKE_TRY_COMPILE_CONFIGURATION` variable to choose
+a build configuration.
+
+.. versionadded:: 3.6
+ Set the :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable to specify
+ the type of target used for the source file signature.
+
+.. versionadded:: 3.6
+ Set the :variable:`CMAKE_TRY_COMPILE_PLATFORM_VARIABLES` variable to specify
+ variables that must be propagated into the test project. This variable is
+ meant for use only in toolchain files and is only honored by the
+ ``try_compile()`` command for the source files form, not when given a whole
+ project.
+
+.. versionchanged:: 3.8
+ If :policy:`CMP0067` is set to ``NEW``, or any of the ``<LANG>_STANDARD``,
+ ``<LANG>_STANDARD_REQUIRED``, or ``<LANG>_EXTENSIONS`` options are used,
+ then the language standard variables are honored:
+
+ * :variable:`CMAKE_C_STANDARD`
+ * :variable:`CMAKE_C_STANDARD_REQUIRED`
+ * :variable:`CMAKE_C_EXTENSIONS`
+ * :variable:`CMAKE_CXX_STANDARD`
+ * :variable:`CMAKE_CXX_STANDARD_REQUIRED`
+ * :variable:`CMAKE_CXX_EXTENSIONS`
+ * :variable:`CMAKE_OBJC_STANDARD`
+ * :variable:`CMAKE_OBJC_STANDARD_REQUIRED`
+ * :variable:`CMAKE_OBJC_EXTENSIONS`
+ * :variable:`CMAKE_OBJCXX_STANDARD`
+ * :variable:`CMAKE_OBJCXX_STANDARD_REQUIRED`
+ * :variable:`CMAKE_OBJCXX_EXTENSIONS`
+ * :variable:`CMAKE_CUDA_STANDARD`
+ * :variable:`CMAKE_CUDA_STANDARD_REQUIRED`
+ * :variable:`CMAKE_CUDA_EXTENSIONS`
+
+ Their values are used to set the corresponding target properties in
+ the generated project (unless overridden by an explicit option).
+
+.. versionchanged:: 3.14
+ For the :generator:`Green Hills MULTI` generator the GHS toolset and target
+ system customization cache variables are also propagated into the test project.
diff --git a/Help/command/try_run.rst b/Help/command/try_run.rst
new file mode 100644
index 0000000..404de98
--- /dev/null
+++ b/Help/command/try_run.rst
@@ -0,0 +1,123 @@
+try_run
+-------
+
+.. only:: html
+
+ .. contents::
+
+Try compiling and then running some code.
+
+Try Compiling and Running Source Files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ try_run(<runResultVar> <compileResultVar>
+ <bindir> <srcfile> [CMAKE_FLAGS <flags>...]
+ [COMPILE_DEFINITIONS <defs>...]
+ [LINK_OPTIONS <options>...]
+ [LINK_LIBRARIES <libs>...]
+ [COMPILE_OUTPUT_VARIABLE <var>]
+ [RUN_OUTPUT_VARIABLE <var>]
+ [OUTPUT_VARIABLE <var>]
+ [WORKING_DIRECTORY <var>]
+ [ARGS <args>...])
+
+Try compiling a ``<srcfile>``. Returns ``TRUE`` or ``FALSE`` for success
+or failure in ``<compileResultVar>``. If the compile succeeded, runs the
+executable and returns its exit code in ``<runResultVar>``. If the
+executable was built, but failed to run, then ``<runResultVar>`` will be
+set to ``FAILED_TO_RUN``. See the :command:`try_compile` command for
+information on how the test project is constructed to build the source file.
+
+.. versionadded:: 3.14
+ The names of the result variables ``<runResultVar>`` and
+ ``<compileResultVar>`` are defined by the user. Previously, they had
+ fixed names ``RUN_RESULT_VAR`` and ``COMPILE_RESULT_VAR``.
+
+The options are:
+
+``CMAKE_FLAGS <flags>...``
+ Specify flags of the form ``-DVAR:TYPE=VALUE`` to be passed to
+ the ``cmake`` command-line used to drive the test build.
+ The example in :command:`try_compile` shows how values for variables
+ ``INCLUDE_DIRECTORIES``, ``LINK_DIRECTORIES``, and ``LINK_LIBRARIES``
+ are used.
+
+``COMPILE_DEFINITIONS <defs>...``
+ Specify ``-Ddefinition`` arguments to pass to :command:`add_definitions`
+ in the generated test project.
+
+``COMPILE_OUTPUT_VARIABLE <var>``
+ Report the compile step build output in a given variable.
+
+``LINK_LIBRARIES <libs>...``
+ .. versionadded:: 3.2
+
+ Specify libraries to be linked in the generated project.
+ The list of libraries may refer to system libraries and to
+ :ref:`Imported Targets <Imported Targets>` from the calling project.
+
+ If this option is specified, any ``-DLINK_LIBRARIES=...`` value
+ given to the ``CMAKE_FLAGS`` option will be ignored.
+
+``LINK_OPTIONS <options>...``
+ .. versionadded:: 3.14
+
+ Specify link step options to pass to :command:`target_link_options` in the
+ generated project.
+
+``OUTPUT_VARIABLE <var>``
+ Report the compile build output and the output from running the executable
+ in the given variable. This option exists for legacy reasons. Prefer
+ ``COMPILE_OUTPUT_VARIABLE`` and ``RUN_OUTPUT_VARIABLE`` instead.
+
+``RUN_OUTPUT_VARIABLE <var>``
+ Report the output from running the executable in a given variable.
+
+``WORKING_DIRECTORY <var>``
+ .. versionadded:: 3.20
+
+ Run the executable in the given directory. If no ``WORKING_DIRECTORY`` is
+ specified, the executable will run in ``<bindir>``.
+
+Other Behavior Settings
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Set the :variable:`CMAKE_TRY_COMPILE_CONFIGURATION` variable to choose
+a build configuration.
+
+Behavior when Cross Compiling
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.3
+ Use ``CMAKE_CROSSCOMPILING_EMULATOR`` when running cross-compiled
+ binaries.
+
+When cross compiling, the executable compiled in the first step
+usually cannot be run on the build host. The ``try_run`` command checks
+the :variable:`CMAKE_CROSSCOMPILING` variable to detect whether CMake is in
+cross-compiling mode. If that is the case, it will still try to compile
+the executable, but it will not try to run the executable unless the
+:variable:`CMAKE_CROSSCOMPILING_EMULATOR` variable is set. Instead it
+will create cache variables which must be filled by the user or by
+presetting them in some CMake script file to the values the executable
+would have produced if it had been run on its actual target platform.
+These cache entries are:
+
+``<runResultVar>``
+ Exit code if the executable were to be run on the target platform.
+
+``<runResultVar>__TRYRUN_OUTPUT``
+ Output from stdout and stderr if the executable were to be run on
+ the target platform. This is created only if the
+ ``RUN_OUTPUT_VARIABLE`` or ``OUTPUT_VARIABLE`` option was used.
+
+In order to make cross compiling your project easier, use ``try_run``
+only if really required. If you use ``try_run``, use the
+``RUN_OUTPUT_VARIABLE`` or ``OUTPUT_VARIABLE`` options only if really
+required. Using them will require that when cross-compiling, the cache
+variables will have to be set manually to the output of the executable.
+You can also "guard" the calls to ``try_run`` with an :command:`if`
+block checking the :variable:`CMAKE_CROSSCOMPILING` variable and
+provide an easy-to-preset alternative for this case.
diff --git a/Help/command/unset.rst b/Help/command/unset.rst
new file mode 100644
index 0000000..7521052
--- /dev/null
+++ b/Help/command/unset.rst
@@ -0,0 +1,41 @@
+unset
+-----
+
+Unset a variable, cache variable, or environment variable.
+
+Unset Normal Variable or Cache Entry
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ unset(<variable> [CACHE | PARENT_SCOPE])
+
+Removes a normal variable from the current scope, causing it
+to become undefined. If ``CACHE`` is present, then a cache variable
+is removed instead of a normal variable. Note that when evaluating
+:ref:`Variable References` of the form ``${VAR}``, CMake first searches
+for a normal variable with that name. If no such normal variable exists,
+CMake will then search for a cache entry with that name. Because of this
+unsetting a normal variable can expose a cache variable that was previously
+hidden. To force a variable reference of the form ``${VAR}`` to return an
+empty string, use ``set(<variable> "")``, which clears the normal variable
+but leaves it defined.
+
+If ``PARENT_SCOPE`` is present then the variable is removed from the scope
+above the current scope. See the same option in the :command:`set` command
+for further details.
+
+Unset Environment Variable
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ unset(ENV{<variable>})
+
+Removes ``<variable>`` from the currently available
+:manual:`Environment Variables <cmake-env-variables(7)>`.
+Subsequent calls of ``$ENV{<variable>}`` will return the empty string.
+
+This command affects only the current CMake process, not the process
+from which CMake was called, nor the system environment at large,
+nor the environment of subsequent build or test processes.
diff --git a/Help/command/use_mangled_mesa.rst b/Help/command/use_mangled_mesa.rst
new file mode 100644
index 0000000..5b0e2ee
--- /dev/null
+++ b/Help/command/use_mangled_mesa.rst
@@ -0,0 +1,15 @@
+use_mangled_mesa
+----------------
+
+Disallowed since version 3.0. See CMake Policy :policy:`CMP0030`.
+
+Copy mesa headers for use in combination with system GL.
+
+::
+
+ use_mangled_mesa(PATH_TO_MESA OUTPUT_DIRECTORY)
+
+The path to mesa includes, should contain ``gl_mangle.h``. The mesa
+headers are copied to the specified output directory. This allows
+mangled mesa headers to override other GL headers by being added to
+the include directory path earlier.
diff --git a/Help/command/utility_source.rst b/Help/command/utility_source.rst
new file mode 100644
index 0000000..94d6a4e
--- /dev/null
+++ b/Help/command/utility_source.rst
@@ -0,0 +1,24 @@
+utility_source
+--------------
+
+Disallowed since version 3.0. See CMake Policy :policy:`CMP0034`.
+
+Specify the source tree of a third-party utility.
+
+::
+
+ utility_source(cache_entry executable_name
+ path_to_source [file1 file2 ...])
+
+When a third-party utility's source is included in the distribution,
+this command specifies its location and name. The cache entry will
+not be set unless the ``path_to_source`` and all listed files exist. It
+is assumed that the source tree of the utility will have been built
+before it is needed.
+
+When cross compiling CMake will print a warning if a ``utility_source()``
+command is executed, because in many cases it is used to build an
+executable which is executed later on. This doesn't work when cross
+compiling, since the executable can run only on their target platform.
+So in this case the cache entry has to be adjusted manually so it
+points to an executable which is runnable on the build host.
diff --git a/Help/command/variable_requires.rst b/Help/command/variable_requires.rst
new file mode 100644
index 0000000..322b154
--- /dev/null
+++ b/Help/command/variable_requires.rst
@@ -0,0 +1,22 @@
+variable_requires
+-----------------
+
+Disallowed since version 3.0. See CMake Policy :policy:`CMP0035`.
+
+Use the :command:`if` command instead.
+
+Assert satisfaction of an option's required variables.
+
+::
+
+ variable_requires(TEST_VARIABLE RESULT_VARIABLE
+ REQUIRED_VARIABLE1
+ REQUIRED_VARIABLE2 ...)
+
+The first argument (``TEST_VARIABLE``) is the name of the variable to be
+tested, if that variable is false nothing else is done. If
+``TEST_VARIABLE`` is true, then the next argument (``RESULT_VARIABLE``)
+is a variable that is set to true if all the required variables are set.
+The rest of the arguments are variables that must be true or not set
+to ``NOTFOUND`` to avoid an error. If any are not true, an error is
+reported.
diff --git a/Help/command/variable_watch.rst b/Help/command/variable_watch.rst
new file mode 100644
index 0000000..8293f5a
--- /dev/null
+++ b/Help/command/variable_watch.rst
@@ -0,0 +1,48 @@
+variable_watch
+--------------
+
+Watch the CMake variable for change.
+
+.. code-block:: cmake
+
+ variable_watch(<variable> [<command>])
+
+If the specified ``<variable>`` changes and no ``<command>`` is given,
+a message will be printed to inform about the change.
+
+If ``<command>`` is given, this command will be executed instead.
+The command will receive the following arguments:
+``COMMAND(<variable> <access> <value> <current_list_file> <stack>)``
+
+``<variable>``
+ Name of the variable being accessed.
+
+``<access>``
+ One of ``READ_ACCESS``, ``UNKNOWN_READ_ACCESS``, ``MODIFIED_ACCESS``,
+ ``UNKNOWN_MODIFIED_ACCESS``, or ``REMOVED_ACCESS``. The ``UNKNOWN_``
+ values are only used when the variable has never been set. Once set,
+ they are never used again during the same CMake run, even if the
+ variable is later unset.
+
+``<value>``
+ The value of the variable. On a modification, this is the new
+ (modified) value of the variable. On removal, the value is empty.
+
+``<current_list_file>``
+ Full path to the file doing the access.
+
+``<stack>``
+ List of absolute paths of all files currently on the stack of file
+ inclusion, with the bottom-most file first and the currently
+ processed file (that is, ``current_list_file``) last.
+
+Note that for some accesses such as :command:`list(APPEND)`, the watcher
+is executed twice, first with a read access and then with a write one.
+Also note that an :command:`if(DEFINED)` query on the variable does not
+register as an access and the watcher is not executed.
+
+Only non-cache variables can be watched using this command. Access to
+cache variables is never watched. However, the existence of a cache
+variable ``var`` causes accesses to the non-cache variable ``var`` to
+not use the ``UNKNOWN_`` prefix, even if a non-cache variable ``var``
+has never existed.
diff --git a/Help/command/while.rst b/Help/command/while.rst
new file mode 100644
index 0000000..a4957c1
--- /dev/null
+++ b/Help/command/while.rst
@@ -0,0 +1,25 @@
+while
+-----
+
+Evaluate a group of commands while a condition is true
+
+.. code-block:: cmake
+
+ while(<condition>)
+ <commands>
+ endwhile()
+
+All commands between while and the matching :command:`endwhile` are recorded
+without being invoked. Once the :command:`endwhile` is evaluated, the
+recorded list of commands is invoked as long as the ``<condition>`` is true.
+
+The ``<condition>`` has the same syntax and is evaluated using the same logic
+as described at length for the :command:`if` command.
+
+The commands :command:`break` and :command:`continue` provide means to
+escape from the normal control flow.
+
+Per legacy, the :command:`endwhile` command admits
+an optional ``<condition>`` argument.
+If used, it must be a verbatim repeat of the argument of the opening
+``while`` command.
diff --git a/Help/command/write_file.rst b/Help/command/write_file.rst
new file mode 100644
index 0000000..4d476bd
--- /dev/null
+++ b/Help/command/write_file.rst
@@ -0,0 +1,22 @@
+write_file
+----------
+
+.. deprecated:: 3.0
+
+ Use the :command:`file(WRITE)` command instead.
+
+::
+
+ write_file(filename "message to write"... [APPEND])
+
+The first argument is the file name, the rest of the arguments are
+messages to write. If the argument ``APPEND`` is specified, then the
+message will be appended.
+
+NOTE 1: :command:`file(WRITE)` and :command:`file(APPEND)` do exactly
+the same as this one but add some more functionality.
+
+NOTE 2: When using ``write_file`` the produced file cannot be used as an
+input to CMake (CONFIGURE_FILE, source file ...) because it will lead
+to an infinite loop. Use :command:`configure_file` if you want to
+generate input files to CMake.
diff --git a/Help/cpack_gen/archive.rst b/Help/cpack_gen/archive.rst
new file mode 100644
index 0000000..b941812
--- /dev/null
+++ b/Help/cpack_gen/archive.rst
@@ -0,0 +1,88 @@
+CPack Archive Generator
+-----------------------
+
+CPack generator for packaging files into an archive, which can have
+any of the following formats:
+
+ - 7Z - 7zip - (.7z)
+ - TBZ2 (.tar.bz2)
+ - TGZ (.tar.gz)
+ - TXZ (.tar.xz)
+ - TZ (.tar.Z)
+ - TZST (.tar.zst)
+ - ZIP (.zip)
+
+.. versionadded:: 3.1
+ ``7Z`` and ``TXZ`` formats support.
+
+.. versionadded:: 3.16
+ ``TZST`` format support.
+
+When this generator is called from ``CPackSourceConfig.cmake`` (or through
+the ``package_source`` target), then the generated archive will contain all
+files in the project directory, except those specified in
+:variable:`CPACK_SOURCE_IGNORE_FILES`. The following is one example of
+packaging all source files of a project:
+
+.. code-block:: cmake
+
+ set(CPACK_SOURCE_GENERATOR "TGZ")
+ set(CPACK_SOURCE_IGNORE_FILES
+ \\.git/
+ build/
+ ".*~$"
+ )
+ set(CPACK_VERBATIM_VARIABLES YES)
+ include(CPack)
+
+When this generator is called from ``CPackConfig.cmake`` (or through the
+``package`` target), then the generated archive will contain all files
+that have been installed via CMake's :command:`install` command (and the
+deprecated commands :command:`install_files`, :command:`install_programs`,
+and :command:`install_targets`).
+
+Variables specific to CPack Archive generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. variable:: CPACK_ARCHIVE_FILE_NAME
+ CPACK_ARCHIVE_<component>_FILE_NAME
+
+ Package file name without extension. The extension is determined from the
+ archive format (see list above) and automatically appended to the file name.
+ The default is ``<CPACK_PACKAGE_FILE_NAME>[-<component>]``, with spaces
+ replaced by '-'.
+
+ .. versionadded:: 3.9
+ Per-component ``CPACK_ARCHIVE_<component>_FILE_NAME`` variables.
+
+.. variable:: CPACK_ARCHIVE_COMPONENT_INSTALL
+
+ Enable component packaging. If enabled (ON), then the archive generator
+ creates multiple packages. The default is OFF, which means that a single
+ package containing files of all components is generated.
+
+Variables used by CPack Archive generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+These variables are used by the Archive generator, but are also available to
+CPack generators which are essentially archives at their core. These include:
+
+ - :cpack_gen:`CPack Cygwin Generator`
+ - :cpack_gen:`CPack FreeBSD Generator`
+
+.. variable:: CPACK_ARCHIVE_THREADS
+
+ .. versionadded:: 3.18
+
+ The number of threads to use when performing the compression. If set to
+ ``0``, the number of available cores on the machine will be used instead.
+ The default is ``1`` which limits compression to a single thread. Note that
+ not all compression modes support threading in all environments. Currently,
+ only the XZ compression may support it.
+
+ See also the :variable:`CPACK_THREADS` variable.
+
+.. note::
+
+ Official CMake binaries available on ``cmake.org`` ship with a ``liblzma``
+ that does not support parallel compression.
diff --git a/Help/cpack_gen/bundle.rst b/Help/cpack_gen/bundle.rst
new file mode 100644
index 0000000..5e335c0
--- /dev/null
+++ b/Help/cpack_gen/bundle.rst
@@ -0,0 +1,76 @@
+CPack Bundle Generator
+----------------------
+
+CPack Bundle generator (macOS) specific options
+
+Variables specific to CPack Bundle generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Installers built on macOS using the Bundle generator use the
+aforementioned DragNDrop (``CPACK_DMG_xxx``) variables, plus the following
+Bundle-specific parameters (``CPACK_BUNDLE_xxx``).
+
+.. variable:: CPACK_BUNDLE_NAME
+
+ The name of the generated bundle. This appears in the macOS Finder as the
+ bundle name. Required.
+
+.. variable:: CPACK_BUNDLE_PLIST
+
+ Path to an macOS Property List (``.plist``) file that will be used
+ for the generated bundle. This
+ assumes that the caller has generated or specified their own ``Info.plist``
+ file. Required.
+
+.. variable:: CPACK_BUNDLE_ICON
+
+ Path to an macOS icon file that will be used as the icon for the generated
+ bundle. This is the icon that appears in the macOS Finder for the bundle, and
+ in the macOS dock when the bundle is opened. Required.
+
+.. variable:: CPACK_BUNDLE_STARTUP_COMMAND
+
+ Path to a startup script. This is a path to an executable or script that
+ will be run whenever an end-user double-clicks the generated bundle in the
+ macOS Finder. Optional.
+
+.. variable:: CPACK_BUNDLE_APPLE_CERT_APP
+
+ .. versionadded:: 3.2
+
+ The name of your Apple supplied code signing certificate for the application.
+ The name usually takes the form ``Developer ID Application: [Name]`` or
+ ``3rd Party Mac Developer Application: [Name]``. If this variable is not set
+ the application will not be signed.
+
+.. variable:: CPACK_BUNDLE_APPLE_ENTITLEMENTS
+
+ .. versionadded:: 3.2
+
+ The name of the Property List (``.plist``) file that contains your Apple
+ entitlements for sandboxing your application. This file is required
+ for submission to the macOS App Store.
+
+.. variable:: CPACK_BUNDLE_APPLE_CODESIGN_FILES
+
+ .. versionadded:: 3.2
+
+ A list of additional files that you wish to be signed. You do not need to
+ list the main application folder, or the main executable. You should
+ list any frameworks and plugins that are included in your app bundle.
+
+.. variable:: CPACK_BUNDLE_APPLE_CODESIGN_PARAMETER
+
+ .. versionadded:: 3.3
+
+ Additional parameter that will passed to ``codesign``.
+ Default value: ``--deep -f``
+
+.. variable:: CPACK_COMMAND_CODESIGN
+
+ .. versionadded:: 3.2
+
+ Path to the ``codesign(1)`` command used to sign applications with an
+ Apple cert. This variable can be used to override the automatically
+ detected command (or specify its location if the auto-detection fails
+ to find it).
diff --git a/Help/cpack_gen/cygwin.rst b/Help/cpack_gen/cygwin.rst
new file mode 100644
index 0000000..c537a79
--- /dev/null
+++ b/Help/cpack_gen/cygwin.rst
@@ -0,0 +1,30 @@
+CPack Cygwin Generator
+----------------------
+
+Cygwin CPack generator (Cygwin).
+
+Variables affecting the CPack Cygwin generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- .. versionadded:: 3.18
+ :variable:`CPACK_ARCHIVE_THREADS`
+
+
+Variables specific to CPack Cygwin generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The
+following variable is specific to installers build on and/or for
+Cygwin:
+
+.. variable:: CPACK_CYGWIN_PATCH_NUMBER
+
+ The Cygwin patch number. FIXME: This documentation is incomplete.
+
+.. variable:: CPACK_CYGWIN_PATCH_FILE
+
+ The Cygwin patch file. FIXME: This documentation is incomplete.
+
+.. variable:: CPACK_CYGWIN_BUILD_SCRIPT
+
+ The Cygwin build script. FIXME: This documentation is incomplete.
diff --git a/Help/cpack_gen/deb.rst b/Help/cpack_gen/deb.rst
new file mode 100644
index 0000000..03c4ea8
--- /dev/null
+++ b/Help/cpack_gen/deb.rst
@@ -0,0 +1,678 @@
+CPack DEB Generator
+-------------------
+
+The built in (binary) CPack DEB generator (Unix only)
+
+Variables specific to CPack Debian (DEB) generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The CPack DEB generator may be used to create DEB package using :module:`CPack`.
+The CPack DEB generator is a :module:`CPack` generator thus it uses the
+``CPACK_XXX`` variables used by :module:`CPack`.
+
+The CPack DEB generator should work on any Linux host but it will produce
+better deb package when Debian specific tools ``dpkg-xxx`` are usable on
+the build system.
+
+The CPack DEB generator has specific features which are controlled by the
+specifics ``CPACK_DEBIAN_XXX`` variables.
+
+``CPACK_DEBIAN_<COMPONENT>_XXXX`` variables may be used in order to have
+**component** specific values. Note however that ``<COMPONENT>`` refers to
+the **grouping name** written in upper case. It may be either a component name
+or a component GROUP name.
+
+Here are some CPack DEB generator wiki resources that are here for historic
+reasons and are no longer maintained but may still prove useful:
+
+ - https://gitlab.kitware.com/cmake/community/-/wikis/doc/cpack/Configuration
+ - https://gitlab.kitware.com/cmake/community/-/wikis/doc/cpack/PackageGenerators#deb-unix-only
+
+List of CPack DEB generator specific variables:
+
+.. variable:: CPACK_DEB_COMPONENT_INSTALL
+
+ Enable component packaging for CPackDEB
+
+ * Mandatory : NO
+ * Default : OFF
+
+ If enabled (ON) multiple packages are generated. By default a single package
+ containing files of all components is generated.
+
+.. variable:: CPACK_DEBIAN_PACKAGE_NAME
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_NAME
+
+ Set Package control field (variable is automatically transformed to lower
+ case).
+
+ * Mandatory : YES
+ * Default :
+
+ - :variable:`CPACK_PACKAGE_NAME` for non-component based
+ installations
+ - :variable:`CPACK_DEBIAN_PACKAGE_NAME` suffixed with -<COMPONENT>
+ for component-based installations.
+
+ .. versionadded:: 3.5
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_NAME`` variables.
+
+ See https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Source
+
+.. variable:: CPACK_DEBIAN_FILE_NAME
+ CPACK_DEBIAN_<COMPONENT>_FILE_NAME
+
+ .. versionadded:: 3.6
+
+ Package file name.
+
+ * Mandatory : YES
+ * Default : ``<CPACK_PACKAGE_FILE_NAME>[-<component>].deb``
+
+ This may be set to ``DEB-DEFAULT`` to allow the CPack DEB generator to generate
+ package file name by itself in deb format::
+
+ <PackageName>_<VersionNumber>-<DebianRevisionNumber>_<DebianArchitecture>.deb
+
+ Alternatively provided package file name must end
+ with either ``.deb`` or ``.ipk`` suffix.
+
+ .. versionadded:: 3.10
+ ``.ipk`` suffix used by OPKG packaging system.
+
+ .. note::
+
+ Preferred setting of this variable is ``DEB-DEFAULT`` but for backward
+ compatibility with the CPack DEB generator in CMake prior to version 3.6 this
+ feature is disabled by default.
+
+ .. note::
+
+ By using non default filenames duplicate names may occur. Duplicate files
+ get overwritten and it is up to the packager to set the variables in a
+ manner that will prevent such errors.
+
+.. variable:: CPACK_DEBIAN_PACKAGE_EPOCH
+
+ .. versionadded:: 3.10
+
+ The Debian package epoch
+
+ * Mandatory : No
+ * Default : -
+
+ Optional number that should be incremented when changing versioning schemas
+ or fixing mistakes in the version numbers of older packages.
+
+.. variable:: CPACK_DEBIAN_PACKAGE_VERSION
+
+ The Debian package version
+
+ * Mandatory : YES
+ * Default : :variable:`CPACK_PACKAGE_VERSION`
+
+ This variable may contain only alphanumerics (A-Za-z0-9) and the characters
+ . + - ~ (full stop, plus, hyphen, tilde) and should start with a digit. If
+ :variable:`CPACK_DEBIAN_PACKAGE_RELEASE` is not set then hyphens are not
+ allowed.
+
+ .. note::
+
+ For backward compatibility with CMake 3.9 and lower a failed test of this
+ variable's content is not a hard error when both
+ :variable:`CPACK_DEBIAN_PACKAGE_RELEASE` and
+ :variable:`CPACK_DEBIAN_PACKAGE_EPOCH` variables are not set. An author
+ warning is reported instead.
+
+.. variable:: CPACK_DEBIAN_PACKAGE_RELEASE
+
+ .. versionadded:: 3.6
+
+ The Debian package release - Debian revision number.
+
+ * Mandatory : No
+ * Default : -
+
+ This is the numbering of the DEB package itself, i.e. the version of the
+ packaging and not the version of the content (see
+ :variable:`CPACK_DEBIAN_PACKAGE_VERSION`). One may change the default value
+ if the previous packaging was buggy and/or you want to put here a fancy Linux
+ distro specific numbering.
+
+.. variable:: CPACK_DEBIAN_PACKAGE_ARCHITECTURE
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_ARCHITECTURE
+
+ The Debian package architecture
+
+ * Mandatory : YES
+ * Default : Output of ``dpkg --print-architecture`` (or ``i386``
+ if ``dpkg`` is not found)
+
+ .. versionadded:: 3.6
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_ARCHITECTURE`` variables.
+
+.. variable:: CPACK_DEBIAN_PACKAGE_DEPENDS
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_DEPENDS
+
+ Sets the Debian dependencies of this package.
+
+ * Mandatory : NO
+ * Default :
+
+ - An empty string for non-component based installations
+ - :variable:`CPACK_DEBIAN_PACKAGE_DEPENDS` for component-based
+ installations.
+
+
+ .. versionadded:: 3.3
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_DEPENDS`` variables.
+
+ .. note::
+
+ If :variable:`CPACK_DEBIAN_PACKAGE_SHLIBDEPS` or
+ more specifically :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_SHLIBDEPS`
+ is set for this component, the discovered dependencies will be appended
+ to :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_DEPENDS` instead of
+ :variable:`CPACK_DEBIAN_PACKAGE_DEPENDS`. If
+ :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_DEPENDS` is an empty string,
+ only the automatically discovered dependencies will be set for this
+ component.
+
+ Example::
+
+ set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.3.1-6), libc6 (< 2.4)")
+
+.. variable:: CPACK_DEBIAN_ENABLE_COMPONENT_DEPENDS
+
+ .. versionadded:: 3.6
+
+ Sets inter-component dependencies if listed with
+ :variable:`CPACK_COMPONENT_<compName>_DEPENDS` variables.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_DEBIAN_PACKAGE_MAINTAINER
+
+ The Debian package maintainer
+
+ * Mandatory : YES
+ * Default : ``CPACK_PACKAGE_CONTACT``
+
+.. variable:: CPACK_DEBIAN_PACKAGE_DESCRIPTION
+ CPACK_DEBIAN_<COMPONENT>_DESCRIPTION
+
+ The Debian package description
+
+ * Mandatory : YES
+ * Default :
+
+ - :variable:`CPACK_DEBIAN_<COMPONENT>_DESCRIPTION` (component
+ based installers only) if set, or :variable:`CPACK_DEBIAN_PACKAGE_DESCRIPTION` if set, or
+ - :variable:`CPACK_COMPONENT_<compName>_DESCRIPTION` (component
+ based installers only) if set, or :variable:`CPACK_PACKAGE_DESCRIPTION` if set, or
+ - content of the file specified in :variable:`CPACK_PACKAGE_DESCRIPTION_FILE` if set
+
+ If after that description is not set, :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY` going to be
+ used if set. Otherwise, :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY` will be added as the first
+ line of description as defined in `Debian Policy Manual`_.
+
+ .. versionadded:: 3.3
+ Per-component ``CPACK_COMPONENT_<compName>_DESCRIPTION`` variables.
+
+ .. versionadded:: 3.16
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_DESCRIPTION`` variables.
+
+ .. versionadded:: 3.16
+ The ``CPACK_PACKAGE_DESCRIPTION_FILE`` variable.
+
+.. _Debian Policy Manual: https://www.debian.org/doc/debian-policy/ch-controlfields.html#description
+
+.. variable:: CPACK_DEBIAN_PACKAGE_SECTION
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_SECTION
+
+ Set Section control field e.g. admin, devel, doc, ...
+
+ * Mandatory : YES
+ * Default : "devel"
+
+ .. versionadded:: 3.5
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_SECTION`` variables.
+
+ See https://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections
+
+.. variable:: CPACK_DEBIAN_ARCHIVE_TYPE
+
+ .. versionadded:: 3.7
+
+ .. deprecated:: 3.14
+
+ The archive format used for creating the Debian package.
+
+ * Mandatory : YES
+ * Default : "gnutar"
+
+ Possible value is:
+
+ - gnutar
+
+ .. note::
+
+ This variable previously defaulted to the ``paxr`` value, but ``dpkg``
+ has never supported that tar format. For backwards compatibility the
+ ``paxr`` value will be mapped to ``gnutar`` and a deprecation message
+ will be emitted.
+
+.. variable:: CPACK_DEBIAN_COMPRESSION_TYPE
+
+ .. versionadded:: 3.1
+
+ The compression used for creating the Debian package.
+
+ * Mandatory : YES
+ * Default : "gzip"
+
+ Possible values are:
+
+ - lzma
+ - xz
+ - bzip2
+ - gzip
+
+.. variable:: CPACK_DEBIAN_PACKAGE_PRIORITY
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_PRIORITY
+
+ Set Priority control field e.g. required, important, standard, optional,
+ extra
+
+ * Mandatory : YES
+ * Default : "optional"
+
+ .. versionadded:: 3.5
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_PRIORITY`` varables.
+
+ See https://www.debian.org/doc/debian-policy/ch-archive.html#s-priorities
+
+.. variable:: CPACK_DEBIAN_PACKAGE_HOMEPAGE
+
+ The URL of the web site for this package, preferably (when applicable) the
+ site from which the original source can be obtained and any additional
+ upstream documentation or information may be found.
+
+ * Mandatory : NO
+ * Default : :variable:`CMAKE_PROJECT_HOMEPAGE_URL`
+
+ .. versionadded:: 3.12
+ The ``CMAKE_PROJECT_HOMEPAGE_URL`` variable.
+
+ .. note::
+
+ The content of this field is a simple URL without any surrounding
+ characters such as <>.
+
+.. variable:: CPACK_DEBIAN_PACKAGE_SHLIBDEPS
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_SHLIBDEPS
+
+ May be set to ON in order to use ``dpkg-shlibdeps`` to generate
+ better package dependency list.
+
+ * Mandatory : NO
+ * Default :
+
+ - :variable:`CPACK_DEBIAN_PACKAGE_SHLIBDEPS` if set or
+ - OFF
+
+ .. note::
+
+ You may need set :variable:`CMAKE_INSTALL_RPATH` to an appropriate value
+ if you use this feature, because if you don't ``dpkg-shlibdeps``
+ may fail to find your own shared libs.
+ See https://gitlab.kitware.com/cmake/community/-/wikis/doc/cmake/RPATH-handling
+
+ .. note::
+
+ You can also set :variable:`CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS`
+ to an appropriate value if you use this feature, in order to please
+ ``dpkg-shlibdeps``. However, you should only do this for private
+ shared libraries that could not get resolved otherwise.
+
+ .. versionadded:: 3.3
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_SHLIBDEPS`` variables.
+
+ .. versionadded:: 3.6
+ Correct handling of ``$ORIGIN`` in :variable:`CMAKE_INSTALL_RPATH`.
+
+.. variable:: CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS
+
+ .. versionadded:: 3.20
+
+ May be set to a list of directories that will be given to ``dpkg-shlibdeps``
+ via its ``-l`` option. These will be searched by ``dpkg-shlibdeps`` in order
+ to find private shared library dependencies.
+
+ * Mandatory : NO
+ * Default :
+
+ .. note::
+
+ You should prefer to set :variable:`CMAKE_INSTALL_RPATH` to an appropriate
+ value if you use ``dpkg-shlibdeps``. The current option is really only
+ needed for private shared library dependencies.
+
+.. variable:: CPACK_DEBIAN_PACKAGE_DEBUG
+
+ May be set when invoking cpack in order to trace debug information
+ during the CPack DEB generator run.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_DEBIAN_PACKAGE_PREDEPENDS
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_PREDEPENDS
+
+ Sets the `Pre-Depends` field of the Debian package.
+ Like :variable:`Depends <CPACK_DEBIAN_PACKAGE_DEPENDS>`, except that it
+ also forces ``dpkg`` to complete installation of the packages named
+ before even starting the installation of the package which declares the
+ pre-dependency.
+
+ * Mandatory : NO
+ * Default :
+
+ - An empty string for non-component based installations
+ - :variable:`CPACK_DEBIAN_PACKAGE_PREDEPENDS` for component-based
+ installations.
+
+ .. versionadded:: 3.4
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_PREDEPENDS`` variables.
+
+ See http://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
+
+.. variable:: CPACK_DEBIAN_PACKAGE_ENHANCES
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_ENHANCES
+
+ Sets the `Enhances` field of the Debian package.
+ Similar to :variable:`Suggests <CPACK_DEBIAN_PACKAGE_SUGGESTS>` but works
+ in the opposite direction: declares that a package can enhance the
+ functionality of another package.
+
+ * Mandatory : NO
+ * Default :
+
+ - An empty string for non-component based installations
+ - :variable:`CPACK_DEBIAN_PACKAGE_ENHANCES` for component-based
+ installations.
+
+ .. versionadded:: 3.4
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_ENHANCES`` variables.
+
+ See http://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
+
+.. variable:: CPACK_DEBIAN_PACKAGE_BREAKS
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_BREAKS
+
+ Sets the `Breaks` field of the Debian package.
+ When a binary package (P) declares that it breaks other packages (B),
+ ``dpkg`` will not allow the package (P) which declares `Breaks` be
+ **unpacked** unless the packages that will be broken (B) are deconfigured
+ first.
+ As long as the package (P) is configured, the previously deconfigured
+ packages (B) cannot be reconfigured again.
+
+ * Mandatory : NO
+ * Default :
+
+ - An empty string for non-component based installations
+ - :variable:`CPACK_DEBIAN_PACKAGE_BREAKS` for component-based
+ installations.
+
+ .. versionadded:: 3.4
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_BREAKS`` variables.
+
+ See https://www.debian.org/doc/debian-policy/ch-relationships.html#s-breaks
+
+.. variable:: CPACK_DEBIAN_PACKAGE_CONFLICTS
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_CONFLICTS
+
+ Sets the `Conflicts` field of the Debian package.
+ When one binary package declares a conflict with another using a `Conflicts`
+ field, ``dpkg`` will not allow them to be unpacked on the system at
+ the same time.
+
+ * Mandatory : NO
+ * Default :
+
+ - An empty string for non-component based installations
+ - :variable:`CPACK_DEBIAN_PACKAGE_CONFLICTS` for component-based
+ installations.
+
+ .. versionadded:: 3.4
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_CONFLICTS`` variables.
+
+ See https://www.debian.org/doc/debian-policy/ch-relationships.html#s-conflicts
+
+ .. note::
+
+ This is a stronger restriction than
+ :variable:`Breaks <CPACK_DEBIAN_PACKAGE_BREAKS>`, which prevents the
+ broken package from being configured while the breaking package is in
+ the "Unpacked" state but allows both packages to be unpacked at the same
+ time.
+
+.. variable:: CPACK_DEBIAN_PACKAGE_PROVIDES
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_PROVIDES
+
+ Sets the `Provides` field of the Debian package.
+ A virtual package is one which appears in the `Provides` control field of
+ another package.
+
+ * Mandatory : NO
+ * Default :
+
+ - An empty string for non-component based installations
+ - :variable:`CPACK_DEBIAN_PACKAGE_PROVIDES` for component-based
+ installations.
+
+ .. versionadded:: 3.4
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_PROVIDES`` variables.
+
+ See https://www.debian.org/doc/debian-policy/ch-relationships.html#s-virtual
+
+.. variable:: CPACK_DEBIAN_PACKAGE_REPLACES
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_REPLACES
+
+ Sets the `Replaces` field of the Debian package.
+ Packages can declare in their control file that they should overwrite
+ files in certain other packages, or completely replace other packages.
+
+ * Mandatory : NO
+ * Default :
+
+ - An empty string for non-component based installations
+ - :variable:`CPACK_DEBIAN_PACKAGE_REPLACES` for component-based
+ installations.
+
+ .. versionadded:: 3.4
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_REPLACES`` variables.
+
+ See http://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
+
+.. variable:: CPACK_DEBIAN_PACKAGE_RECOMMENDS
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_RECOMMENDS
+
+ Sets the `Recommends` field of the Debian package.
+ Allows packages to declare a strong, but not absolute, dependency on other
+ packages.
+
+ * Mandatory : NO
+ * Default :
+
+ - An empty string for non-component based installations
+ - :variable:`CPACK_DEBIAN_PACKAGE_RECOMMENDS` for component-based
+ installations.
+
+ .. versionadded:: 3.4
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_RECOMMENDS`` variables.
+
+ See http://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
+
+.. variable:: CPACK_DEBIAN_PACKAGE_SUGGESTS
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_SUGGESTS
+
+ Sets the `Suggests` field of the Debian package.
+ Allows packages to declare a suggested package install grouping.
+
+ * Mandatory : NO
+ * Default :
+
+ - An empty string for non-component based installations
+ - :variable:`CPACK_DEBIAN_PACKAGE_SUGGESTS` for component-based
+ installations.
+
+ .. versionadded:: 3.4
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_SUGGESTS`` variables.
+
+ See http://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
+
+.. variable:: CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS
+
+ .. versionadded:: 3.6
+
+ * Mandatory : NO
+ * Default : OFF
+
+ Allows to generate shlibs control file automatically. Compatibility is defined by
+ :variable:`CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY` variable value.
+
+ .. note::
+
+ Libraries are only considered if they have both library name and version
+ set. This can be done by setting SOVERSION property with
+ :command:`set_target_properties` command.
+
+.. variable:: CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY
+
+ .. versionadded:: 3.6
+
+ Compatibility policy for auto-generated shlibs control file.
+
+ * Mandatory : NO
+ * Default : "="
+
+ Defines compatibility policy for auto-generated shlibs control file.
+ Possible values: "=", ">="
+
+ See https://www.debian.org/doc/debian-policy/ch-sharedlibs.html#s-sharedlibs-shlibdeps
+
+.. variable:: CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_CONTROL_EXTRA
+
+ This variable allow advanced user to add custom script to the
+ control.tar.gz.
+ Typical usage is for conffiles, postinst, postrm, prerm.
+
+ * Mandatory : NO
+ * Default : -
+
+ Usage::
+
+ set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
+ "${CMAKE_CURRENT_SOURCE_DIR}/prerm;${CMAKE_CURRENT_SOURCE_DIR}/postrm")
+
+ .. versionadded:: 3.4
+ Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_CONTROL_EXTRA`` variables.
+
+.. variable:: CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_CONTROL_STRICT_PERMISSION
+
+ .. versionadded:: 3.4
+
+ This variable indicates if the Debian policy on control files should be
+ strictly followed.
+
+ * Mandatory : NO
+ * Default : FALSE
+
+ Usage::
+
+ set(CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION TRUE)
+
+ This overrides the permissions on the original files, following the rules
+ set by Debian policy
+ https://www.debian.org/doc/debian-policy/ch-files.html#s-permissions-owners
+
+ .. note::
+
+ The original permissions of the files will be used in the final
+ package unless this variable is set to ``TRUE``.
+ In particular, the scripts should have the proper executable
+ flag prior to the generation of the package.
+
+.. variable:: CPACK_DEBIAN_PACKAGE_SOURCE
+ CPACK_DEBIAN_<COMPONENT>_PACKAGE_SOURCE
+
+ .. versionadded:: 3.5
+
+ Sets the ``Source`` field of the binary Debian package.
+ When the binary package name is not the same as the source package name
+ (in particular when several components/binaries are generated from one
+ source) the source from which the binary has been generated should be
+ indicated with the field ``Source``.
+
+ * Mandatory : NO
+ * Default :
+
+ - An empty string for non-component based installations
+ - :variable:`CPACK_DEBIAN_PACKAGE_SOURCE` for component-based
+ installations.
+
+ See https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Source
+
+ .. note::
+
+ This value is not interpreted. It is possible to pass an optional
+ revision number of the referenced source package as well.
+
+Packaging of debug information
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.13
+
+Dbgsym packages contain debug symbols for debugging packaged binaries.
+
+Dbgsym packaging has its own set of variables:
+
+.. variable:: CPACK_DEBIAN_DEBUGINFO_PACKAGE
+ CPACK_DEBIAN_<component>_DEBUGINFO_PACKAGE
+
+ Enable generation of dbgsym .ddeb package(s).
+
+ * Mandatory : NO
+ * Default : OFF
+
+.. note::
+
+ Binaries must contain debug symbols before packaging so use either ``Debug``
+ or ``RelWithDebInfo`` for :variable:`CMAKE_BUILD_TYPE` variable value.
+
+Building Debian packages on Windows
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.10
+
+To communicate UNIX file permissions from the install stage
+to the CPack DEB generator the "cmake_mode_t" NTFS
+alternate data stream (ADT) is used.
+
+When a filesystem without ADT support is used only owner read/write
+permissions can be preserved.
+
+Reproducible packages
+^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.13
+
+The environment variable ``SOURCE_DATE_EPOCH`` may be set to a UNIX
+timestamp, defined as the number of seconds, excluding leap seconds,
+since 01 Jan 1970 00:00:00 UTC. If set, the CPack DEB generator will
+use its value for timestamps in the package.
diff --git a/Help/cpack_gen/dmg.rst b/Help/cpack_gen/dmg.rst
new file mode 100644
index 0000000..ec2cf1e
--- /dev/null
+++ b/Help/cpack_gen/dmg.rst
@@ -0,0 +1,129 @@
+CPack DragNDrop Generator
+-------------------------
+
+The DragNDrop CPack generator (macOS) creates a DMG image.
+
+Variables specific to CPack DragNDrop generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following variables are specific to the DragNDrop installers built
+on macOS:
+
+.. variable:: CPACK_DMG_VOLUME_NAME
+
+ The volume name of the generated disk image. Defaults to
+ CPACK_PACKAGE_FILE_NAME.
+
+.. variable:: CPACK_DMG_FORMAT
+
+ The disk image format. Common values are ``UDRO`` (UDIF read-only), ``UDZO`` (UDIF
+ zlib-compressed) or ``UDBZ`` (UDIF bzip2-compressed). Refer to ``hdiutil(1)`` for
+ more information on other available formats. Defaults to ``UDZO``.
+
+.. variable:: CPACK_DMG_DS_STORE
+
+ Path to a custom ``.DS_Store`` file. This ``.DS_Store`` file can be used to
+ specify the Finder window position/geometry and layout (such as hidden
+ toolbars, placement of the icons etc.). This file has to be generated by
+ the Finder (either manually or through AppleScript) using a normal folder
+ from which the ``.DS_Store`` file can then be extracted.
+
+.. variable:: CPACK_DMG_DS_STORE_SETUP_SCRIPT
+
+ .. versionadded:: 3.5
+
+ Path to a custom AppleScript file. This AppleScript is used to generate
+ a ``.DS_Store`` file which specifies the Finder window position/geometry and
+ layout (such as hidden toolbars, placement of the icons etc.).
+ By specifying a custom AppleScript there is no need to use
+ ``CPACK_DMG_DS_STORE``, as the ``.DS_Store`` that is generated by the AppleScript
+ will be packaged.
+
+.. variable:: CPACK_DMG_BACKGROUND_IMAGE
+
+ Path to an image file to be used as the background. This file will be
+ copied to ``.background``/``background.<ext>``, where ``<ext>`` is the original image file
+ extension. The background image is installed into the image before
+ ``CPACK_DMG_DS_STORE_SETUP_SCRIPT`` is executed or ``CPACK_DMG_DS_STORE`` is
+ installed. By default no background image is set.
+
+.. variable:: CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK
+
+ .. versionadded:: 3.6
+
+ Default behaviour is to include a symlink to ``/Applications`` in the DMG.
+ Set this option to ``ON`` to avoid adding the symlink.
+
+.. variable:: CPACK_DMG_SLA_DIR
+
+ .. versionadded:: 3.5
+
+ Directory where license and menu files for different languages are stored.
+ Setting this causes CPack to look for a ``<language>.menu.txt`` and
+ ``<language>.license.txt`` or ``<language>.license.rtf`` file for every
+ language defined in ``CPACK_DMG_SLA_LANGUAGES``. If both this variable and
+ ``CPACK_RESOURCE_FILE_LICENSE`` are set, CPack will only look for the menu
+ files and use the same license file for all languages. If both
+ ``<language>.license.txt`` and ``<language>.license.rtf`` exist, the ``.txt``
+ file will be used.
+
+ .. versionadded:: 3.17
+ RTF support.
+
+.. variable:: CPACK_DMG_SLA_LANGUAGES
+
+ .. versionadded:: 3.5
+
+ Languages for which a license agreement is provided when mounting the
+ generated DMG. A menu file consists of 9 lines of text. The first line is
+ is the name of the language itself, uppercase, in English (e.g. German).
+ The other lines are translations of the following strings:
+
+ - Agree
+ - Disagree
+ - Print
+ - Save...
+ - You agree to the terms of the License Agreement when you click the
+ "Agree" button.
+ - Software License Agreement
+ - This text cannot be saved. The disk may be full or locked, or the file
+ may be locked.
+ - Unable to print. Make sure you have selected a printer.
+
+ For every language in this list, CPack will try to find files
+ ``<language>.menu.txt`` and ``<language>.license.txt`` in the directory
+ specified by the :variable:`CPACK_DMG_SLA_DIR` variable.
+
+.. variable:: CPACK_DMG_<component>_FILE_NAME
+
+ .. versionadded:: 3.17
+
+ File name when packaging ``<component>`` as its own DMG
+ (``CPACK_COMPONENTS_GROUPING`` set to IGNORE).
+
+ - Default: ``CPACK_PACKAGE_FILE_NAME-<component>``
+
+.. variable:: CPACK_DMG_FILESYSTEM
+
+ The filesystem format. Common values are ``APFS`` and ``HFS+``.
+ See ``man hdiutil`` for a full list of supported formats.
+ Defaults to ``HFS+``.
+
+.. variable:: CPACK_COMMAND_HDIUTIL
+
+ Path to the ``hdiutil(1)`` command used to operate on disk image files on
+ macOS. This variable can be used to override the automatically detected
+ command (or specify its location if the auto-detection fails to find it).
+
+.. variable:: CPACK_COMMAND_SETFILE
+
+ Path to the ``SetFile(1)`` command used to set extended attributes on files and
+ directories on macOS. This variable can be used to override the
+ automatically detected command (or specify its location if the
+ auto-detection fails to find it).
+
+.. variable:: CPACK_COMMAND_REZ
+
+ Path to the ``Rez(1)`` command used to compile resources on macOS. This
+ variable can be used to override the automatically detected command (or
+ specify its location if the auto-detection fails to find it).
diff --git a/Help/cpack_gen/external.rst b/Help/cpack_gen/external.rst
new file mode 100644
index 0000000..4c083f0
--- /dev/null
+++ b/Help/cpack_gen/external.rst
@@ -0,0 +1,294 @@
+CPack External Generator
+------------------------
+
+.. versionadded:: 3.13
+
+CPack provides many generators to create packages for a variety of platforms
+and packaging systems. The intention is for CMake/CPack to be a complete
+end-to-end solution for building and packaging a software project. However, it
+may not always be possible to use CPack for the entire packaging process, due
+to either technical limitations or policies that require the use of certain
+tools. For this reason, CPack provides the "External" generator, which allows
+external packaging software to take advantage of some of the functionality
+provided by CPack, such as component installation and the dependency graph.
+
+Integration with External Packaging Tools
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The CPack External generator generates a ``.json`` file containing the
+CPack internal metadata, which gives external software information
+on how to package the software. External packaging software may itself
+invoke CPack, consume the generated metadata,
+install and package files as required.
+
+Alternatively CPack can invoke an external packaging software
+through an optional custom CMake script in
+:variable:`CPACK_EXTERNAL_PACKAGE_SCRIPT` instead.
+
+Staging of installation files may also optionally be
+taken care of by the generator when enabled through the
+:variable:`CPACK_EXTERNAL_ENABLE_STAGING` variable.
+
+JSON Format
+^^^^^^^^^^^
+
+The JSON metadata file contains a list of CPack components and component groups,
+the various options passed to :command:`cpack_add_component` and
+:command:`cpack_add_component_group`, the dependencies between the components
+and component groups, and various other options passed to CPack.
+
+The JSON's root object will always provide two fields:
+``formatVersionMajor`` and ``formatVersionMinor``, which are always integers
+that describe the output format of the generator. Backwards-compatible changes
+to the output format (for example, adding a new field that didn't exist before)
+cause the minor version to be incremented, and backwards-incompatible changes
+(for example, deleting a field or changing its meaning) cause the major version
+to be incremented and the minor version reset to 0. The format version is
+always of the format ``major.minor``. In other words, it always has exactly two
+parts, separated by a period.
+
+You can request one or more specific versions of the output format as described
+below with :variable:`CPACK_EXTERNAL_REQUESTED_VERSIONS`. The output format will
+have a major version that exactly matches the requested major version, and a
+minor version that is greater than or equal to the requested minor version. If
+no version is requested with :variable:`CPACK_EXTERNAL_REQUESTED_VERSIONS`, the
+latest known major version is used by default. Currently, the only supported
+format is 1.0, which is described below.
+
+Version 1.0
+***********
+
+In addition to the standard format fields, format version 1.0 provides the
+following fields in the root:
+
+``components``
+ The ``components`` field is an object with component names as the keys and
+ objects describing the components as the values. The component objects have
+ the following fields:
+
+ ``name``
+ The name of the component. This is always the same as the key in the
+ ``components`` object.
+
+ ``displayName``
+ The value of the ``DISPLAY_NAME`` field passed to
+ :command:`cpack_add_component`.
+
+ ``description``
+ The value of the ``DESCRIPTION`` field passed to
+ :command:`cpack_add_component`.
+
+ ``isHidden``
+ True if ``HIDDEN`` was passed to :command:`cpack_add_component`, false if
+ it was not.
+
+ ``isRequired``
+ True if ``REQUIRED`` was passed to :command:`cpack_add_component`, false if
+ it was not.
+
+ ``isDisabledByDefault``
+ True if ``DISABLED`` was passed to :command:`cpack_add_component`, false if
+ it was not.
+
+ ``group``
+ Only present if ``GROUP`` was passed to :command:`cpack_add_component`. If
+ so, this field is a string value containing the component's group.
+
+ ``dependencies``
+ An array of components the component depends on. This contains the values
+ in the ``DEPENDS`` argument passed to :command:`cpack_add_component`. If no
+ ``DEPENDS`` argument was passed, this is an empty list.
+
+ ``installationTypes``
+ An array of installation types the component is part of. This contains the
+ values in the ``INSTALL_TYPES`` argument passed to
+ :command:`cpack_add_component`. If no ``INSTALL_TYPES`` argument was
+ passed, this is an empty list.
+
+ ``isDownloaded``
+ True if ``DOWNLOADED`` was passed to :command:`cpack_add_component`, false
+ if it was not.
+
+ ``archiveFile``
+ The name of the archive file passed with the ``ARCHIVE_FILE`` argument to
+ :command:`cpack_add_component`. If no ``ARCHIVE_FILE`` argument was passed,
+ this is an empty string.
+
+``componentGroups``
+ The ``componentGroups`` field is an object with component group names as the
+ keys and objects describing the component groups as the values. The component
+ group objects have the following fields:
+
+ ``name``
+ The name of the component group. This is always the same as the key in the
+ ``componentGroups`` object.
+
+ ``displayName``
+ The value of the ``DISPLAY_NAME`` field passed to
+ :command:`cpack_add_component_group`.
+
+ ``description``
+ The value of the ``DESCRIPTION`` field passed to
+ :command:`cpack_add_component_group`.
+
+ ``parentGroup``
+ Only present if ``PARENT_GROUP`` was passed to
+ :command:`cpack_add_component_group`. If so, this field is a string value
+ containing the component group's parent group.
+
+ ``isExpandedByDefault``
+ True if ``EXPANDED`` was passed to :command:`cpack_add_component_group`,
+ false if it was not.
+
+ ``isBold``
+ True if ``BOLD_TITLE`` was passed to :command:`cpack_add_component_group`,
+ false if it was not.
+
+ ``components``
+ An array of names of components that are direct members of the group
+ (components that have this group as their ``GROUP``). Components of
+ subgroups are not included.
+
+ ``subgroups``
+ An array of names of component groups that are subgroups of the group
+ (groups that have this group as their ``PARENT_GROUP``).
+
+``installationTypes``
+ The ``installationTypes`` field is an object with installation type names as
+ the keys and objects describing the installation types as the values. The
+ installation type objects have the following fields:
+
+ ``name``
+ The name of the installation type. This is always the same as the key in
+ the ``installationTypes`` object.
+
+ ``displayName``
+ The value of the ``DISPLAY_NAME`` field passed to
+ :command:`cpack_add_install_type`.
+
+ ``index``
+ The integer index of the installation type in the list.
+
+``projects``
+ The ``projects`` field is an array of objects describing CMake projects which
+ comprise the CPack project. The values in this field are derived from
+ :variable:`CPACK_INSTALL_CMAKE_PROJECTS`. In most cases, this will be only a
+ single project. The project objects have the following fields:
+
+ ``projectName``
+ The project name passed to :variable:`CPACK_INSTALL_CMAKE_PROJECTS`.
+
+ ``component``
+ The name of the component or component set which comprises the project.
+
+ ``directory``
+ The build directory of the CMake project. This is the directory which
+ contains the ``cmake_install.cmake`` script.
+
+ ``subDirectory``
+ The subdirectory to install the project into inside the CPack package.
+
+``packageName``
+ The package name given in :variable:`CPACK_PACKAGE_NAME`. Only present if
+ this option is set.
+
+``packageVersion``
+ The package version given in :variable:`CPACK_PACKAGE_VERSION`. Only present
+ if this option is set.
+
+``packageDescriptionFile``
+ The package description file given in
+ :variable:`CPACK_PACKAGE_DESCRIPTION_FILE`. Only present if this option is
+ set.
+
+``packageDescriptionSummary``
+ The package description summary given in
+ :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY`. Only present if this option is
+ set.
+
+``buildConfig``
+ The build configuration given to CPack with the ``-C`` option. Only present
+ if this option is set.
+
+``defaultDirectoryPermissions``
+ The default directory permissions given in
+ :variable:`CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS`. Only present if this
+ option is set.
+
+``setDestdir``
+ True if :variable:`CPACK_SET_DESTDIR` is true, false if it is not.
+
+``packagingInstallPrefix``
+ The install prefix given in :variable:`CPACK_PACKAGING_INSTALL_PREFIX`. Only
+ present if :variable:`CPACK_SET_DESTDIR` is true.
+
+``stripFiles``
+ True if :variable:`CPACK_STRIP_FILES` is true, false if it is not.
+
+``warnOnAbsoluteInstallDestination``
+ True if :variable:`CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION` is true, false
+ if it is not.
+
+``errorOnAbsoluteInstallDestination``
+ True if :variable:`CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION` is true,
+ false if it is not.
+
+Variables specific to CPack External generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. variable:: CPACK_EXTERNAL_REQUESTED_VERSIONS
+
+ This variable is used to request a specific version of the CPack External
+ generator. It is a list of ``major.minor`` values, separated by semicolons.
+
+ If this variable is set to a non-empty value, the CPack External generator
+ will iterate through each item in the list to search for a version that it
+ knows how to generate. Requested versions should be listed in order of
+ descending preference by the client software, as the first matching version
+ in the list will be generated.
+
+ The generator knows how to generate the version if it has a versioned
+ generator whose major version exactly matches the requested major version,
+ and whose minor version is greater than or equal to the requested minor
+ version. For example, if ``CPACK_EXTERNAL_REQUESTED_VERSIONS`` contains 1.0, and
+ the CPack External generator knows how to generate 1.1, it will generate 1.1.
+ If the generator doesn't know how to generate a version in the list, it skips
+ the version and looks at the next one. If it doesn't know how to generate any
+ of the requested versions, an error is thrown.
+
+ If this variable is not set, or is empty, the CPack External generator will
+ generate the highest major and minor version that it knows how to generate.
+
+ If an invalid version is encountered in ``CPACK_EXTERNAL_REQUESTED_VERSIONS`` (one
+ that doesn't match ``major.minor``, where ``major`` and ``minor`` are
+ integers), it is ignored.
+
+.. variable:: CPACK_EXTERNAL_ENABLE_STAGING
+
+ This variable can be set to true to enable optional installation
+ into a temporary staging area which can then be picked up
+ and packaged by an external packaging tool.
+ The top level directory used by CPack for the current packaging
+ task is contained in ``CPACK_TOPLEVEL_DIRECTORY``.
+ It is automatically cleaned up on each run before packaging is initiated
+ and can be used for custom temporary files required by
+ the external packaging tool.
+ It also contains the staging area ``CPACK_TEMPORARY_DIRECTORY``
+ into which CPack performs the installation when staging is enabled.
+
+.. variable:: CPACK_EXTERNAL_PACKAGE_SCRIPT
+
+ This variable can optionally specify the full path to
+ a CMake script file to be run as part of the CPack invocation.
+ It is invoked after (optional) staging took place and may
+ run an external packaging tool. The script has access to
+ the variables defined by the CPack config file.
+
+.. variable:: CPACK_EXTERNAL_BUILT_PACKAGES
+
+ .. versionadded:: 3.19
+
+ The ``CPACK_EXTERNAL_PACKAGE_SCRIPT`` script may set this list variable to the
+ full paths of generated package files. CPack will copy these files from the
+ staging directory back to the top build directory and possibly produce
+ checksum files if the :variable:`CPACK_PACKAGE_CHECKSUM` is set.
diff --git a/Help/cpack_gen/freebsd.rst b/Help/cpack_gen/freebsd.rst
new file mode 100644
index 0000000..2c93569
--- /dev/null
+++ b/Help/cpack_gen/freebsd.rst
@@ -0,0 +1,149 @@
+CPack FreeBSD Generator
+-----------------------
+
+.. versionadded:: 3.10
+
+The built in (binary) CPack FreeBSD (pkg) generator (Unix only)
+
+Variables affecting the CPack FreeBSD (pkg) generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- .. versionadded:: 3.18
+ :variable:`CPACK_ARCHIVE_THREADS`
+
+Variables specific to CPack FreeBSD (pkg) generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The CPack FreeBSD generator may be used to create pkg(8) packages -- these may
+be used on FreeBSD, DragonflyBSD, NetBSD, OpenBSD, but also on Linux or OSX,
+depending on the installed package-management tools -- using :module:`CPack`.
+
+The CPack FreeBSD generator is a :module:`CPack` generator and uses the
+``CPACK_XXX`` variables used by :module:`CPack`. It tries to re-use packaging
+information that may already be specified for Debian packages for the
+:cpack_gen:`CPack DEB Generator`. It also tries to re-use RPM packaging
+information when Debian does not specify.
+
+The CPack FreeBSD generator should work on any host with libpkg installed. The
+packages it produces are specific to the host architecture and ABI.
+
+The CPack FreeBSD generator sets package-metadata through
+``CPACK_FREEBSD_XXX`` variables. The CPack FreeBSD generator, unlike the
+CPack Deb generator, does not specially support componentized packages; a
+single package is created from all the software artifacts created through
+CMake.
+
+All of the variables can be set specifically for FreeBSD packaging in
+the CPackConfig file or in CMakeLists.txt, but most of them have defaults
+that use general settings (e.g. CMAKE_PROJECT_NAME) or Debian-specific
+variables when those make sense (e.g. the homepage of an upstream project
+is usually unchanged by the flavor of packaging). When there is no Debian
+information to fall back on, but the RPM packaging has it, fall back to
+the RPM information (e.g. package license).
+
+.. variable:: CPACK_FREEBSD_PACKAGE_NAME
+
+ Sets the package name (in the package manifest, but also affects the
+ output filename).
+
+ * Mandatory: YES
+ * Default:
+
+ - :variable:`CPACK_PACKAGE_NAME` (this is always set by CPack itself,
+ based on CMAKE_PROJECT_NAME).
+
+.. variable:: CPACK_FREEBSD_PACKAGE_COMMENT
+
+ Sets the package comment. This is the short description displayed by
+ pkg(8) in standard "pkg info" output.
+
+ * Mandatory: YES
+ * Default:
+
+ - :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY` (this is always set
+ by CPack itself, if nothing else sets it explicitly).
+ - :variable:`PROJECT_DESCRIPTION` (this can be set with the DESCRIPTION
+ parameter for :command:`project`).
+
+.. variable:: CPACK_FREEBSD_PACKAGE_DESCRIPTION
+
+ Sets the package description. This is the long description of the package,
+ given by "pkg info" with a specific package as argument.
+
+ * Mandatory: YES
+ * Default:
+
+ - :variable:`CPACK_DEBIAN_PACKAGE_DESCRIPTION` (this may be set already
+ for Debian packaging, so we may as well re-use it).
+
+.. variable:: CPACK_FREEBSD_PACKAGE_WWW
+
+ The URL of the web site for this package, preferably (when applicable) the
+ site from which the original source can be obtained and any additional
+ upstream documentation or information may be found.
+
+ * Mandatory: YES
+ * Default:
+
+ - :variable:`CMAKE_PROJECT_HOMEPAGE_URL`, or if that is not set,
+ :variable:`CPACK_DEBIAN_PACKAGE_HOMEPAGE` (this may be set already
+ for Debian packaging, so we may as well re-use it).
+
+ .. versionadded:: 3.12
+ The ``CMAKE_PROJECT_HOMEPAGE_URL`` variable.
+
+.. variable:: CPACK_FREEBSD_PACKAGE_LICENSE
+
+ The license, or licenses, which apply to this software package. This must
+ be one or more license-identifiers that pkg recognizes as acceptable license
+ identifiers (e.g. "GPLv2").
+
+ * Mandatory: YES
+ * Default:
+
+ - :variable:`CPACK_RPM_PACKAGE_LICENSE`
+
+.. variable:: CPACK_FREEBSD_PACKAGE_LICENSE_LOGIC
+
+ This variable is only of importance if there is more than one license.
+ The default is "single", which is only applicable to a single license.
+ Other acceptable values are determined by pkg -- those are "dual" or "multi" --
+ meaning choice (OR) or simultaneous (AND) application of the licenses.
+
+ * Mandatory: NO
+ * Default: single
+
+.. variable:: CPACK_FREEBSD_PACKAGE_MAINTAINER
+
+ The FreeBSD maintainer (e.g. kde@freebsd.org) of this package.
+
+ * Mandatory: YES
+ * Default: none
+
+.. variable:: CPACK_FREEBSD_PACKAGE_ORIGIN
+
+ The origin (ports label) of this package; for packages built by CPack
+ outside of the ports system this is of less importance. The default
+ puts the package somewhere under misc/, as a stopgap.
+
+ * Mandatory: YES
+ * Default: misc/<package name>
+
+.. variable:: CPACK_FREEBSD_PACKAGE_CATEGORIES
+
+ The ports categories where this package lives (if it were to be built
+ from ports). If none is set a single category is determined based on
+ the package origin.
+
+ * Mandatory: YES
+ * Default: derived from ORIGIN
+
+.. variable:: CPACK_FREEBSD_PACKAGE_DEPS
+
+ A list of package origins that should be added as package dependencies.
+ These are in the form <category>/<packagename>, e.g. x11/libkonq.
+ No version information needs to be provided (this is not included
+ in the manifest).
+
+ * Mandatory: NO
+ * Default: empty
diff --git a/Help/cpack_gen/ifw.rst b/Help/cpack_gen/ifw.rst
new file mode 100644
index 0000000..6817eac
--- /dev/null
+++ b/Help/cpack_gen/ifw.rst
@@ -0,0 +1,407 @@
+CPack IFW Generator
+-------------------
+
+.. versionadded:: 3.1
+
+Configure and run the Qt Installer Framework to generate a Qt installer.
+
+.. only:: html
+
+ .. contents::
+
+Overview
+^^^^^^^^
+
+This :manual:`cpack generator <cpack-generators(7)>` generates
+configuration and meta information for the `Qt Installer Framework
+<http://doc.qt.io/qtinstallerframework/index.html>`_ (QtIFW),
+and runs QtIFW tools to generate a Qt installer.
+
+QtIFW provides tools and utilities to create installers for
+the platforms supported by `Qt <https://www.qt.io>`_: Linux,
+Microsoft Windows, and macOS.
+
+To make use of this generator, QtIFW needs to be installed.
+The :module:`CPackIFW` module looks for the location of the
+QtIFW command-line utilities, and defines several commands to
+control the behavior of this generator.
+
+Variables
+^^^^^^^^^
+
+You can use the following variables to change behavior of CPack ``IFW``
+generator.
+
+Debug
+"""""
+
+.. variable:: CPACK_IFW_VERBOSE
+
+ .. versionadded:: 3.3
+
+ Set to ``ON`` to enable addition debug output.
+ By default is ``OFF``.
+
+Package
+"""""""
+
+.. variable:: CPACK_IFW_PACKAGE_TITLE
+
+ Name of the installer as displayed on the title bar.
+ By default used :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY`.
+
+.. variable:: CPACK_IFW_PACKAGE_PUBLISHER
+
+ Publisher of the software (as shown in the Windows Control Panel).
+ By default used :variable:`CPACK_PACKAGE_VENDOR`.
+
+.. variable:: CPACK_IFW_PRODUCT_URL
+
+ URL to a page that contains product information on your web site.
+
+.. variable:: CPACK_IFW_PACKAGE_ICON
+
+ Filename for a custom installer icon. The actual file is '.icns' (macOS),
+ '.ico' (Windows). No functionality on Unix.
+
+.. variable:: CPACK_IFW_PACKAGE_WINDOW_ICON
+
+ Filename for a custom window icon in PNG format for the Installer
+ application.
+
+.. variable:: CPACK_IFW_PACKAGE_LOGO
+
+ Filename for a logo is used as QWizard::LogoPixmap.
+
+.. variable:: CPACK_IFW_PACKAGE_WATERMARK
+
+ .. versionadded:: 3.8
+
+ Filename for a watermark is used as QWizard::WatermarkPixmap.
+
+.. variable:: CPACK_IFW_PACKAGE_BANNER
+
+ .. versionadded:: 3.8
+
+ Filename for a banner is used as QWizard::BannerPixmap.
+
+.. variable:: CPACK_IFW_PACKAGE_BACKGROUND
+
+ .. versionadded:: 3.8
+
+ Filename for an image used as QWizard::BackgroundPixmap (only used by MacStyle).
+
+.. variable:: CPACK_IFW_PACKAGE_WIZARD_STYLE
+
+ .. versionadded:: 3.8
+
+ Wizard style to be used ("Modern", "Mac", "Aero" or "Classic").
+
+.. variable:: CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH
+
+ .. versionadded:: 3.8
+
+ Default width of the wizard in pixels. Setting a banner image will override this.
+
+.. variable:: CPACK_IFW_PACKAGE_WIZARD_DEFAULT_HEIGHT
+
+ .. versionadded:: 3.8
+
+ Default height of the wizard in pixels. Setting a watermark image will override this.
+
+.. variable:: CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST
+
+ .. versionadded:: 3.20
+
+ Set to ``OFF`` if the widget listing installer pages on the left side of the wizard should not be shown.
+
+ It is ``ON`` by default, but will only have an effect if using QtIFW 4.0 or later.
+
+.. variable:: CPACK_IFW_PACKAGE_TITLE_COLOR
+
+ .. versionadded:: 3.8
+
+ Color of the titles and subtitles (takes an HTML color code, such as "#88FF33").
+
+.. variable:: CPACK_IFW_PACKAGE_STYLE_SHEET
+
+ .. versionadded:: 3.15
+
+ Filename for a stylesheet.
+
+.. variable:: CPACK_IFW_TARGET_DIRECTORY
+
+ Default target directory for installation.
+ By default used
+ "@ApplicationsDir@/:variable:`CPACK_PACKAGE_INSTALL_DIRECTORY`"
+ (variables embedded in '@' are expanded by the
+ `QtIFW scripting engine <https://doc.qt.io/qtinstallerframework/scripting.html>`_).
+
+ You can use predefined variables.
+
+.. variable:: CPACK_IFW_ADMIN_TARGET_DIRECTORY
+
+ Default target directory for installation with administrator rights.
+
+ You can use predefined variables.
+
+.. variable:: CPACK_IFW_PACKAGE_REMOVE_TARGET_DIR
+
+ .. versionadded:: 3.11
+
+ Set to ``OFF`` if the target directory should not be deleted when uninstalling.
+
+ Is ``ON`` by default
+
+.. variable:: CPACK_IFW_PACKAGE_GROUP
+
+ The group, which will be used to configure the root package
+
+.. variable:: CPACK_IFW_PACKAGE_NAME
+
+ The root package name, which will be used if configuration group is not
+ specified
+
+.. variable:: CPACK_IFW_PACKAGE_START_MENU_DIRECTORY
+
+ .. versionadded:: 3.3
+
+ Name of the default program group for the product in the Windows Start menu.
+
+ By default used :variable:`CPACK_IFW_PACKAGE_NAME`.
+
+.. variable:: CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_NAME
+
+ .. versionadded:: 3.3
+
+ Filename of the generated maintenance tool.
+ The platform-specific executable file extension is appended.
+
+ By default used QtIFW defaults (``maintenancetool``).
+
+.. variable:: CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_INI_FILE
+
+ .. versionadded:: 3.3
+
+ Filename for the configuration of the generated maintenance tool.
+
+ By default used QtIFW defaults (``maintenancetool.ini``).
+
+.. variable:: CPACK_IFW_PACKAGE_ALLOW_NON_ASCII_CHARACTERS
+
+ .. versionadded:: 3.3
+
+ Set to ``ON`` if the installation path can contain non-ASCII characters.
+
+ Is ``ON`` for QtIFW less 2.0 tools.
+
+.. variable:: CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH
+
+ .. versionadded:: 3.3
+
+ Set to ``OFF`` if the installation path cannot contain space characters.
+
+ Is ``ON`` for QtIFW less 2.0 tools.
+
+.. variable:: CPACK_IFW_PACKAGE_CONTROL_SCRIPT
+
+ .. versionadded:: 3.3
+
+ Filename for a custom installer control script.
+
+.. variable:: CPACK_IFW_PACKAGE_RESOURCES
+
+ .. versionadded:: 3.7
+
+ List of additional resources ('.qrc' files) to include in the installer
+ binary.
+
+ You can use :command:`cpack_ifw_add_package_resources` command to resolve
+ relative paths.
+
+.. variable:: CPACK_IFW_PACKAGE_FILE_EXTENSION
+
+ .. versionadded:: 3.10
+
+ The target binary extension.
+
+ On Linux, the name of the target binary is automatically extended with
+ '.run', if you do not specify the extension.
+
+ On Windows, the target is created as an application with the extension
+ '.exe', which is automatically added, if not supplied.
+
+ On Mac, the target is created as an DMG disk image with the extension
+ '.dmg', which is automatically added, if not supplied.
+
+.. variable:: CPACK_IFW_REPOSITORIES_ALL
+
+ The list of remote repositories.
+
+ The default value of this variable is computed by CPack and contains
+ all repositories added with command :command:`cpack_ifw_add_repository`
+ or updated with command :command:`cpack_ifw_update_repository`.
+
+.. variable:: CPACK_IFW_DOWNLOAD_ALL
+
+ If this is ``ON`` all components will be downloaded.
+ By default is ``OFF`` or used value
+ from ``CPACK_DOWNLOAD_ALL`` if set
+
+Components
+""""""""""
+
+.. variable:: CPACK_IFW_RESOLVE_DUPLICATE_NAMES
+
+ Resolve duplicate names when installing components with groups.
+
+.. variable:: CPACK_IFW_PACKAGES_DIRECTORIES
+
+ Additional prepared packages dirs that will be used to resolve
+ dependent components.
+
+.. variable:: CPACK_IFW_REPOSITORIES_DIRECTORIES
+
+ .. versionadded:: 3.10
+
+ Additional prepared repository dirs that will be used to resolve and
+ repack dependent components. This feature available only
+ since QtIFW 3.1.
+
+QtIFW Tools
+"""""""""""
+
+.. variable:: CPACK_IFW_FRAMEWORK_VERSION
+
+ .. versionadded:: 3.3
+
+ The version of used QtIFW tools.
+
+The following variables provide the locations of the QtIFW
+command-line tools as discovered by the module :module:`CPackIFW`.
+These variables are cached, and may be configured if needed.
+
+.. variable:: CPACK_IFW_ARCHIVEGEN_EXECUTABLE
+
+ .. versionadded:: 3.19
+
+ The path to ``archivegen``.
+
+.. variable:: CPACK_IFW_BINARYCREATOR_EXECUTABLE
+
+ The path to ``binarycreator``.
+
+.. variable:: CPACK_IFW_REPOGEN_EXECUTABLE
+
+ The path to ``repogen``.
+
+.. variable:: CPACK_IFW_INSTALLERBASE_EXECUTABLE
+
+ The path to ``installerbase``.
+
+.. variable:: CPACK_IFW_DEVTOOL_EXECUTABLE
+
+ The path to ``devtool``.
+
+Hints for Finding QtIFW
+"""""""""""""""""""""""
+
+Generally, the CPack ``IFW`` generator automatically finds QtIFW tools,
+but if you don't use a default path for installation of the QtIFW tools,
+the path may be specified in either a CMake or an environment variable:
+
+.. variable:: CPACK_IFW_ROOT
+
+ .. versionadded:: 3.9
+
+ An CMake variable which specifies the location of the QtIFW tool suite.
+
+ The variable will be cached in the ``CPackConfig.cmake`` file and used at
+ CPack runtime.
+
+.. variable:: QTIFWDIR
+
+ An environment variable which specifies the location of the QtIFW tool
+ suite.
+
+.. note::
+ The specified path should not contain "bin" at the end
+ (for example: "D:\\DevTools\\QtIFW2.0.5").
+
+The :variable:`CPACK_IFW_ROOT` variable has a higher priority and overrides
+the value of the :variable:`QTIFWDIR` variable.
+
+Other Settings
+^^^^^^^^^^^^^^
+
+Online installer
+""""""""""""""""
+
+By default, this generator generates an *offline installer*. This means that
+that all packaged files are fully contained in the installer executable.
+
+In contrast, an *online installer* will download some or all components from
+a remote server.
+
+The ``DOWNLOADED`` option in the :command:`cpack_add_component` command
+specifies that a component is to be downloaded. Alternatively, the ``ALL``
+option in the :command:`cpack_configure_downloads` command specifies that
+`all` components are to be be downloaded.
+
+The :command:`cpack_ifw_add_repository` command and the
+:variable:`CPACK_IFW_DOWNLOAD_ALL` variable allow for more specific
+configuration.
+
+When there are online components, CPack will write them to archive files.
+The help page of the :module:`CPackComponent` module, especially the section
+on the :command:`cpack_configure_downloads` function, explains how to make
+these files accessible from a download URL.
+
+Internationalization
+""""""""""""""""""""
+
+.. versionadded:: 3.9
+
+Some variables and command arguments support internationalization via
+CMake script. This is an optional feature.
+
+Installers created by QtIFW tools have built-in support for
+internationalization and many phrases are localized to many languages,
+but this does not apply to the description of the your components and groups
+that will be distributed.
+
+Localization of the description of your components and groups is useful for
+users of your installers.
+
+A localized variable or argument can contain a single default value, and a
+set of pairs the name of the locale and the localized value.
+
+For example:
+
+.. code-block:: cmake
+
+ set(LOCALIZABLE_VARIABLE "Default value"
+ en "English value"
+ en_US "American value"
+ en_GB "Great Britain value"
+ )
+
+See Also
+^^^^^^^^
+
+Qt Installer Framework Manual:
+
+* Index page:
+ http://doc.qt.io/qtinstallerframework/index.html
+
+* Component Scripting:
+ http://doc.qt.io/qtinstallerframework/scripting.html
+
+* Predefined Variables:
+ http://doc.qt.io/qtinstallerframework/scripting.html#predefined-variables
+
+* Promoting Updates:
+ http://doc.qt.io/qtinstallerframework/ifw-updates.html
+
+Download Qt Installer Framework for your platform from Qt site:
+ http://download.qt.io/official_releases/qt-installer-framework
diff --git a/Help/cpack_gen/nsis.rst b/Help/cpack_gen/nsis.rst
new file mode 100644
index 0000000..02e33ba
--- /dev/null
+++ b/Help/cpack_gen/nsis.rst
@@ -0,0 +1,203 @@
+CPack NSIS Generator
+--------------------
+
+CPack Nullsoft Scriptable Install System (NSIS) generator specific options.
+
+.. versionchanged:: 3.17
+ The NSIS generator requires NSIS 3.0 or newer.
+
+Variables specific to CPack NSIS generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following variables are specific to the graphical installers built
+on Windows Nullsoft Scriptable Install System.
+
+.. variable:: CPACK_NSIS_INSTALL_ROOT
+
+ The default installation directory presented to the end user by the NSIS
+ installer is under this root dir. The full directory presented to the end
+ user is: ``${CPACK_NSIS_INSTALL_ROOT}/${CPACK_PACKAGE_INSTALL_DIRECTORY}``
+
+.. variable:: CPACK_NSIS_MUI_ICON
+
+ An icon filename. The name of a ``*.ico`` file used as the main icon for the
+ generated install program.
+
+.. variable:: CPACK_NSIS_MUI_UNIICON
+
+ An icon filename. The name of a ``*.ico`` file used as the main icon for the
+ generated uninstall program.
+
+.. variable:: CPACK_NSIS_INSTALLER_MUI_ICON_CODE
+
+ undocumented.
+
+.. variable:: CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP
+
+ .. versionadded:: 3.5
+
+ The filename of a bitmap to use as the NSIS ``MUI_WELCOMEFINISHPAGE_BITMAP``.
+
+.. variable:: CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP
+
+ .. versionadded:: 3.5
+
+ The filename of a bitmap to use as the NSIS ``MUI_UNWELCOMEFINISHPAGE_BITMAP``.
+
+.. variable:: CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS
+
+ Extra NSIS commands that will be added to the beginning of the install
+ Section, before your install tree is available on the target system.
+
+.. variable:: CPACK_NSIS_EXTRA_INSTALL_COMMANDS
+
+ Extra NSIS commands that will be added to the end of the install Section,
+ after your install tree is available on the target system.
+
+.. variable:: CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS
+
+ Extra NSIS commands that will be added to the uninstall Section, before
+ your install tree is removed from the target system.
+
+.. variable:: CPACK_NSIS_COMPRESSOR
+
+ The arguments that will be passed to the NSIS `SetCompressor` command.
+
+.. variable:: CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL
+
+ Ask about uninstalling previous versions first. If this is set to ``ON``,
+ then an installer will look for previous installed versions and if one is
+ found, ask the user whether to uninstall it before proceeding with the
+ install.
+
+.. variable:: CPACK_NSIS_MODIFY_PATH
+
+ Modify ``PATH`` toggle. If this is set to ``ON``, then an extra page will appear
+ in the installer that will allow the user to choose whether the program
+ directory should be added to the system ``PATH`` variable.
+
+.. variable:: CPACK_NSIS_DISPLAY_NAME
+
+ The display name string that appears in the Windows `Apps & features`
+ in `Control Panel`
+
+.. variable:: CPACK_NSIS_PACKAGE_NAME
+
+ The title displayed at the top of the installer.
+
+.. variable:: CPACK_NSIS_INSTALLED_ICON_NAME
+
+ A path to the executable that contains the installer icon.
+
+.. variable:: CPACK_NSIS_HELP_LINK
+
+ URL to a web site providing assistance in installing your application.
+
+.. variable:: CPACK_NSIS_URL_INFO_ABOUT
+
+ URL to a web site providing more information about your application.
+
+.. variable:: CPACK_NSIS_CONTACT
+
+ Contact information for questions and comments about the installation
+ process.
+
+.. variable:: CPACK_NSIS_<compName>_INSTALL_DIRECTORY
+
+ .. versionadded:: 3.7
+
+ Custom install directory for the specified component ``<compName>`` instead
+ of ``$INSTDIR``.
+
+.. variable:: CPACK_NSIS_CREATE_ICONS_EXTRA
+
+ Additional NSIS commands for creating `Start Menu` shortcuts.
+
+.. variable:: CPACK_NSIS_DELETE_ICONS_EXTRA
+
+ Additional NSIS commands to uninstall `Start Menu` shortcuts.
+
+.. variable:: CPACK_NSIS_EXECUTABLES_DIRECTORY
+
+ Creating NSIS `Start Menu` links assumes that they are in ``bin`` unless this
+ variable is set. For example, you would set this to ``exec`` if your
+ executables are in an exec directory.
+
+.. variable:: CPACK_NSIS_MUI_FINISHPAGE_RUN
+
+ Specify an executable to add an option to run on the finish page of the
+ NSIS installer.
+
+.. variable:: CPACK_NSIS_MENU_LINKS
+
+ Specify links in ``[application]`` menu. This should contain a list of pair
+ ``link`` ``link name``. The link may be a URL or a path relative to
+ installation prefix. Like::
+
+ set(CPACK_NSIS_MENU_LINKS
+ "doc/cmake-@CMake_VERSION_MAJOR@.@CMake_VERSION_MINOR@/cmake.html"
+ "CMake Help" "https://cmake.org" "CMake Web Site")
+
+.. variable:: CPACK_NSIS_UNINSTALL_NAME
+
+ .. versionadded:: 3.17
+
+ Specify the name of the program to uninstall the version.
+ Default is ``Uninstall``.
+
+.. variable:: CPACK_NSIS_WELCOME_TITLE
+
+ .. versionadded:: 3.17
+
+ The title to display on the top of the page for the welcome page.
+
+.. variable:: CPACK_NSIS_WELCOME_TITLE_3LINES
+
+ .. versionadded:: 3.17
+
+ Display the title in the welcome page on 3 lines instead of 2.
+
+.. variable:: CPACK_NSIS_FINISH_TITLE
+
+ .. versionadded:: 3.17
+
+ The title to display on the top of the page for the finish page.
+
+.. variable:: CPACK_NSIS_FINISH_TITLE_3LINES
+
+ .. versionadded:: 3.17
+
+ Display the title in the finish page on 3 lines instead of 2.
+
+.. variable:: CPACK_NSIS_MUI_HEADERIMAGE
+
+ .. versionadded:: 3.17
+
+ The image to display on the header of installers pages.
+
+.. variable:: CPACK_NSIS_MANIFEST_DPI_AWARE
+
+ .. versionadded:: 3.18
+
+ If set, declares that the installer is DPI-aware.
+
+.. variable:: CPACK_NSIS_BRANDING_TEXT
+
+ .. versionadded:: 3.20
+
+ If set, updates the text at the bottom of the install window.
+ To set the string to blank, use a space (" ").
+
+.. variable:: CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION
+
+ .. versionadded:: 3.20
+
+ If set, trim down the size of the control to the size of the branding text string.
+ Allowed values for this variable are ``LEFT``, ``CENTER`` or ``RIGHT``.
+ If not specified, the default behavior is ``LEFT``.
+
+.. variable:: CPACK_NSIS_EXECUTABLE
+
+ .. versionadded:: 3.21
+
+ If set, specify the name of the NSIS executable. Default is ``makensis``.
diff --git a/Help/cpack_gen/nuget.rst b/Help/cpack_gen/nuget.rst
new file mode 100644
index 0000000..c980dd6
--- /dev/null
+++ b/Help/cpack_gen/nuget.rst
@@ -0,0 +1,255 @@
+CPack NuGet Generator
+---------------------
+
+.. versionadded:: 3.12
+
+When build a NuGet package there is no direct way to control an output
+filename due a lack of the corresponding CLI option of NuGet, so there
+is no ``CPACK_NUGET_PACKAGE_FILE_NAME`` variable. To form the output filename
+NuGet uses the package name and the version according to its built-in rules.
+
+Also, be aware that including a top level directory
+(``CPACK_INCLUDE_TOPLEVEL_DIRECTORY``) is ignored by this generator.
+
+
+Variables specific to CPack NuGet generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The CPack NuGet generator may be used to create NuGet packages using
+:module:`CPack`. The CPack NuGet generator is a :module:`CPack` generator thus
+it uses the ``CPACK_XXX`` variables used by :module:`CPack`.
+
+The CPack NuGet generator has specific features which are controlled by the
+specifics ``CPACK_NUGET_XXX`` variables. In the "one per group" mode
+(see :variable:`CPACK_COMPONENTS_GROUPING`), ``<compName>`` placeholder
+in the variables below would contain a group name (uppercased and turned into
+a "C" identifier).
+
+List of CPack NuGet generator specific variables:
+
+.. variable:: CPACK_NUGET_COMPONENT_INSTALL
+
+ Enable component packaging for CPack NuGet generator
+
+ * Mandatory : NO
+ * Default : OFF
+
+.. variable:: CPACK_NUGET_PACKAGE_NAME
+ CPACK_NUGET_<compName>_PACKAGE_NAME
+
+ The NUGET package name. ``CPACK_NUGET_PACKAGE_NAME`` is used as the
+ package ``id`` on nuget.org_
+
+ * Mandatory : YES
+ * Default : :variable:`CPACK_PACKAGE_NAME`
+
+.. variable:: CPACK_NUGET_PACKAGE_VERSION
+ CPACK_NUGET_<compName>_PACKAGE_VERSION
+
+ The NuGet package version.
+
+ * Mandatory : YES
+ * Default : :variable:`CPACK_PACKAGE_VERSION`
+
+.. variable:: CPACK_NUGET_PACKAGE_DESCRIPTION
+ CPACK_NUGET_<compName>_PACKAGE_DESCRIPTION
+
+ A long description of the package for UI display.
+
+ * Mandatory : YES
+ * Default :
+ - :variable:`CPACK_COMPONENT_<compName>_DESCRIPTION`,
+ - ``CPACK_COMPONENT_GROUP_<groupName>_DESCRIPTION``,
+ - :variable:`CPACK_PACKAGE_DESCRIPTION`
+
+.. variable:: CPACK_NUGET_PACKAGE_AUTHORS
+ CPACK_NUGET_<compName>_PACKAGE_AUTHORS
+
+ A comma-separated list of packages authors, matching the profile names
+ on nuget.org_. These are displayed in the NuGet Gallery on
+ nuget.org_ and are used to cross-reference packages by the same
+ authors.
+
+ * Mandatory : YES
+ * Default : :variable:`CPACK_PACKAGE_VENDOR`
+
+.. variable:: CPACK_NUGET_PACKAGE_TITLE
+ CPACK_NUGET_<compName>_PACKAGE_TITLE
+
+ A human-friendly title of the package, typically used in UI displays
+ as on nuget.org_ and the Package Manager in Visual Studio. If not
+ specified, the package ID is used.
+
+ * Mandatory : NO
+ * Default :
+ - :variable:`CPACK_COMPONENT_<compName>_DISPLAY_NAME`,
+ - ``CPACK_COMPONENT_GROUP_<groupName>_DISPLAY_NAME``
+
+.. variable:: CPACK_NUGET_PACKAGE_OWNERS
+ CPACK_NUGET_<compName>_PACKAGE_OWNERS
+
+ A comma-separated list of the package creators using profile names
+ on nuget.org_. This is often the same list as in authors,
+ and is ignored when uploading the package to nuget.org_.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_NUGET_PACKAGE_HOMEPAGE_URL
+ CPACK_NUGET_<compName>_PACKAGE_HOMEPAGE_URL
+
+ An URL for the package's home page, often shown in UI displays as well
+ as nuget.org_.
+
+ * Mandatory : NO
+ * Default : :variable:`CPACK_PACKAGE_HOMEPAGE_URL`
+
+.. variable:: CPACK_NUGET_PACKAGE_LICENSEURL
+ CPACK_NUGET_<compName>_PACKAGE_LICENSEURL
+
+ .. deprecated:: 3.20
+ Use a local license file
+ (:variable:`CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME`)
+ or a `(SPDX) license identifier`_
+ (:variable:`CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION`) instead.
+
+ An URL for the package's license, often shown in UI displays as well
+ as on nuget.org_.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION
+ CPACK_NUGET_<compName>_PACKAGE_LICENSE_EXPRESSION
+
+ .. versionadded:: 3.20
+
+ A Software Package Data Exchange `(SPDX) license identifier`_ such as
+ ``MIT``, ``BSD-3-Clause``, or ``LGPL-3.0-or-later``. In the case of a
+ choice of licenses or more complex restrictions, compound license
+ expressions may be formed using boolean operators, for example
+ ``MIT OR BSD-3-Clause``. See the `SPDX specification`_ for guidance
+ on forming complex license expressions.
+
+ If ``CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME`` is specified,
+ ``CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION`` is ignored.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME
+ CPACK_NUGET_<compName>_PACKAGE_LICENSE_FILE_NAME
+
+ The package's license file in :file:`.txt` or :file:`.md` format.
+
+ If ``CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME`` is specified,
+ ``CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION`` is ignored.
+
+ .. versionadded:: 3.20
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_NUGET_PACKAGE_ICONURL
+ CPACK_NUGET_<compName>_PACKAGE_ICONURL
+
+ .. deprecated:: 3.20
+ Use a local icon file (:variable:`CPACK_NUGET_PACKAGE_ICON`) instead.
+
+ An URL for a 64x64 image with transparency background to use as the
+ icon for the package in UI display.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_NUGET_PACKAGE_ICON
+ CPACK_NUGET_<compName>_PACKAGE_ICON
+
+ .. versionadded:: 3.20
+
+ The filename of a 64x64 image with transparency background to use as the
+ icon for the package in UI display.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_NUGET_PACKAGE_DESCRIPTION_SUMMARY
+ CPACK_NUGET_<compName>_PACKAGE_DESCRIPTION_SUMMARY
+
+ A short description of the package for UI display. If omitted, a
+ truncated version of description is used.
+
+ * Mandatory : NO
+ * Default : :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY`
+
+.. variable:: CPACK_NUGET_PACKAGE_RELEASE_NOTES
+ CPACK_NUGET_<compName>_PACKAGE_RELEASE_NOTES
+
+ A description of the changes made in this release of the package,
+ often used in UI like the Updates tab of the Visual Studio Package
+ Manager in place of the package description.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_NUGET_PACKAGE_COPYRIGHT
+ CPACK_NUGET_<compName>_PACKAGE_COPYRIGHT
+
+ Copyright details for the package.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_NUGET_PACKAGE_LANGUAGE
+ CPACK_NUGET_<compName>_PACKAGE_LANGUAGE
+
+ .. versionadded:: 3.20
+
+ Locale specifier for the package, for example ``en_CA``.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_NUGET_PACKAGE_TAGS
+ CPACK_NUGET_<compName>_PACKAGE_TAGS
+
+ A space-delimited list of tags and keywords that describe the
+ package and aid discoverability of packages through search and
+ filtering.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_NUGET_PACKAGE_DEPENDENCIES
+ CPACK_NUGET_<compName>_PACKAGE_DEPENDENCIES
+
+ A list of package dependencies.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_NUGET_PACKAGE_DEPENDENCIES_<dependency>_VERSION
+ CPACK_NUGET_<compName>_PACKAGE_DEPENDENCIES_<dependency>_VERSION
+
+ A `version specification`_ for the particular dependency, where
+ ``<dependency>`` is an item of the dependency list (see above)
+ transformed with ``MAKE_C_IDENTIFIER`` function of :command:`string`
+ command.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_NUGET_PACKAGE_DEBUG
+
+ Enable debug messages while executing CPack NuGet generator.
+
+ * Mandatory : NO
+ * Default : OFF
+
+
+.. _nuget.org: http://nuget.org
+.. _version specification: https://docs.microsoft.com/en-us/nuget/reference/package-versioning#version-ranges-and-wildcards
+.. _(SPDX) license identifier: https://spdx.org/licenses/
+.. _SPDX specification: https://spdx.github.io/spdx-spec/appendix-IV-SPDX-license-expressions/
+
+.. NuGet spec docs https://docs.microsoft.com/en-us/nuget/reference/nuspec
diff --git a/Help/cpack_gen/packagemaker.rst b/Help/cpack_gen/packagemaker.rst
new file mode 100644
index 0000000..256446d
--- /dev/null
+++ b/Help/cpack_gen/packagemaker.rst
@@ -0,0 +1,87 @@
+CPack PackageMaker Generator
+----------------------------
+
+PackageMaker CPack generator (macOS).
+
+.. deprecated:: 3.17
+
+ Xcode no longer distributes the PackageMaker tools.
+ This CPack generator will be removed in a future version of CPack.
+
+Variables specific to CPack PackageMaker generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following variable is specific to installers built on Mac
+macOS using PackageMaker:
+
+.. variable:: CPACK_OSX_PACKAGE_VERSION
+
+ The version of macOS that the resulting PackageMaker archive should be
+ compatible with. Different versions of macOS support different
+ features. For example, CPack can only build component-based installers for
+ macOS 10.4 or newer, and can only build installers that download
+ components on-the-fly for macOS 10.5 or newer. If left blank, this value
+ will be set to the minimum version of macOS that supports the requested
+ features. Set this variable to some value (e.g., 10.4) only if you want to
+ guarantee that your installer will work on that version of macOS, and
+ don't mind missing extra features available in the installer shipping with
+ later versions of macOS.
+
+Background Image
+""""""""""""""""
+
+.. versionadded:: 3.17
+
+This group of variables controls the background image of the generated
+installer.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND
+
+ Adds a background to Distribution XML if specified. The value contains the
+ path to image in ``Resources`` directory.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_ALIGNMENT
+
+ Adds an ``alignment`` attribute to the background in Distribution XML.
+ Refer to Apple documentation for valid values.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_SCALING
+
+ Adds a ``scaling`` attribute to the background in Distribution XML.
+ Refer to Apple documentation for valid values.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_MIME_TYPE
+
+ Adds a ``mime-type`` attribute to the background in Distribution XML.
+ The option contains MIME type of an image.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_UTI
+
+ Adds an ``uti`` attribute to the background in Distribution XML.
+ The option contains UTI type of an image.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_DARKAQUA
+
+ Adds a background for the Dark Aqua theme to Distribution XML if
+ specified. The value contains the path to image in ``Resources``
+ directory.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_DARKAQUA_ALIGNMENT
+
+ Does the same as :variable:`CPACK_PACKAGEMAKER_BACKGROUND_ALIGNMENT` option,
+ but for the dark theme.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_DARKAQUA_SCALING
+
+ Does the same as :variable:`CPACK_PACKAGEMAKER_BACKGROUND_SCALING` option,
+ but for the dark theme.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_DARKAQUA_MIME_TYPE
+
+ Does the same as :variable:`CPACK_PACKAGEMAKER_BACKGROUND_MIME_TYPE` option,
+ but for the dark theme.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_DARKAQUA_UTI
+
+ Does the same as :variable:`CPACK_PACKAGEMAKER_BACKGROUND_UTI` option,
+ but for the dark theme.
diff --git a/Help/cpack_gen/productbuild.rst b/Help/cpack_gen/productbuild.rst
new file mode 100644
index 0000000..cf3041f
--- /dev/null
+++ b/Help/cpack_gen/productbuild.rst
@@ -0,0 +1,138 @@
+CPack productbuild Generator
+----------------------------
+
+.. versionadded:: 3.7
+
+productbuild CPack generator (macOS).
+
+Variables specific to CPack productbuild generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following variable is specific to installers built on Mac
+macOS using ProductBuild:
+
+.. variable:: CPACK_COMMAND_PRODUCTBUILD
+
+ Path to the ``productbuild(1)`` command used to generate a product archive for
+ the macOS Installer or Mac App Store. This variable can be used to override
+ the automatically detected command (or specify its location if the
+ auto-detection fails to find it).
+
+.. variable:: CPACK_PRODUCTBUILD_IDENTITY_NAME
+
+ .. versionadded:: 3.8
+
+ Adds a digital signature to the resulting package.
+
+
+.. variable:: CPACK_PRODUCTBUILD_KEYCHAIN_PATH
+
+ .. versionadded:: 3.8
+
+ Specify a specific keychain to search for the signing identity.
+
+
+.. variable:: CPACK_COMMAND_PKGBUILD
+
+ Path to the ``pkgbuild(1)`` command used to generate an macOS component package
+ on macOS. This variable can be used to override the automatically detected
+ command (or specify its location if the auto-detection fails to find it).
+
+
+.. variable:: CPACK_PKGBUILD_IDENTITY_NAME
+
+ .. versionadded:: 3.8
+
+ Adds a digital signature to the resulting package.
+
+
+.. variable:: CPACK_PKGBUILD_KEYCHAIN_PATH
+
+ .. versionadded:: 3.8
+
+ Specify a specific keychain to search for the signing identity.
+
+
+.. variable:: CPACK_PREFLIGHT_<COMP>_SCRIPT
+
+ Full path to a file that will be used as the ``preinstall`` script for the
+ named ``<COMP>`` component's package, where ``<COMP>`` is the uppercased
+ component name. No ``preinstall`` script is added if this variable is not
+ defined for a given component.
+
+
+.. variable:: CPACK_POSTFLIGHT_<COMP>_SCRIPT
+
+ Full path to a file that will be used as the ``postinstall`` script for the
+ named ``<COMP>`` component's package, where ``<COMP>`` is the uppercased
+ component name. No ``postinstall`` script is added if this variable is not
+ defined for a given component.
+
+.. variable:: CPACK_PRODUCTBUILD_RESOURCES_DIR
+
+ .. versionadded:: 3.9
+
+ If specified the productbuild generator copies files from this directory
+ (including subdirectories) to the ``Resources`` directory. This is done
+ before the :variable:`CPACK_RESOURCE_FILE_WELCOME`,
+ :variable:`CPACK_RESOURCE_FILE_README`, and
+ :variable:`CPACK_RESOURCE_FILE_LICENSE` files are copied.
+
+Background Image
+""""""""""""""""
+
+.. versionadded:: 3.17
+
+This group of variables controls the background image of the generated
+installer.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND
+
+ Adds a background to Distribution XML if specified. The value contains the
+ path to image in ``Resources`` directory.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_ALIGNMENT
+
+ Adds an ``alignment`` attribute to the background in Distribution XML.
+ Refer to Apple documentation for valid values.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_SCALING
+
+ Adds a ``scaling`` attribute to the background in Distribution XML.
+ Refer to Apple documentation for valid values.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_MIME_TYPE
+
+ Adds a ``mime-type`` attribute to the background in Distribution XML.
+ The option contains MIME type of an image.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_UTI
+
+ Adds an ``uti`` attribute to the background in Distribution XML.
+ The option contains UTI type of an image.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA
+
+ Adds a background for the Dark Aqua theme to Distribution XML if
+ specified. The value contains the path to image in ``Resources``
+ directory.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_ALIGNMENT
+
+ Does the same as :variable:`CPACK_PRODUCTBUILD_BACKGROUND_ALIGNMENT` option,
+ but for the dark theme.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_SCALING
+
+ Does the same as :variable:`CPACK_PRODUCTBUILD_BACKGROUND_SCALING` option,
+ but for the dark theme.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_MIME_TYPE
+
+ Does the same as :variable:`CPACK_PRODUCTBUILD_BACKGROUND_MIME_TYPE` option,
+ but for the dark theme.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_UTI
+
+ Does the same as :variable:`CPACK_PRODUCTBUILD_BACKGROUND_UTI` option,
+ but for the dark theme.
diff --git a/Help/cpack_gen/rpm.rst b/Help/cpack_gen/rpm.rst
new file mode 100644
index 0000000..5260a1d
--- /dev/null
+++ b/Help/cpack_gen/rpm.rst
@@ -0,0 +1,1035 @@
+CPack RPM Generator
+-------------------
+
+The built in (binary) CPack RPM generator (Unix only)
+
+Variables specific to CPack RPM generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The CPack RPM generator may be used to create RPM packages using :module:`CPack`.
+The CPack RPM generator is a :module:`CPack` generator thus it uses the
+``CPACK_XXX`` variables used by :module:`CPack`.
+
+The CPack RPM generator has specific features which are controlled by the specifics
+``CPACK_RPM_XXX`` variables.
+
+``CPACK_RPM_<COMPONENT>_XXXX`` variables may be used in order to have
+**component** specific values. Note however that ``<COMPONENT>`` refers to the
+**grouping name** written in upper case. It may be either a component name or
+a component GROUP name. Usually those variables correspond to RPM spec file
+entities. One may find information about spec files here
+http://www.rpm.org/wiki/Docs
+
+.. versionchanged:: 3.6
+
+ `<COMPONENT>` part of variables is preferred to be in upper case (e.g. if
+ component is named ``foo`` then use ``CPACK_RPM_FOO_XXXX`` variable name format)
+ as is with other ``CPACK_<COMPONENT>_XXXX`` variables.
+ For the purposes of back compatibility (CMake/CPack version 3.5 and lower)
+ support for same cased component (e.g. ``fOo`` would be used as
+ ``CPACK_RPM_fOo_XXXX``) is still supported for variables defined in older
+ versions of CMake/CPack but is not guaranteed for variables that
+ will be added in the future. For the sake of back compatibility same cased
+ component variables also override upper cased versions where both are
+ present.
+
+Here are some CPack RPM generator wiki resources that are here for historic
+reasons and are no longer maintained but may still prove useful:
+
+ - https://gitlab.kitware.com/cmake/community/-/wikis/doc/cpack/Configuration
+ - https://gitlab.kitware.com/cmake/community/-/wikis/doc/cpack/PackageGenerators#rpm-unix-only
+
+List of CPack RPM generator specific variables:
+
+.. variable:: CPACK_RPM_COMPONENT_INSTALL
+
+ Enable component packaging for CPack RPM generator
+
+ * Mandatory : NO
+ * Default : OFF
+
+ If enabled (``ON``) multiple packages are generated. By default
+ a single package containing files of all components is generated.
+
+.. variable:: CPACK_RPM_PACKAGE_SUMMARY
+ CPACK_RPM_<component>_PACKAGE_SUMMARY
+
+ The RPM package summary.
+
+ * Mandatory : YES
+ * Default : :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY`
+
+ .. versionadded:: 3.2
+ Per-component ``CPACK_RPM_<component>_PACKAGE_SUMMARY`` variables.
+
+.. variable:: CPACK_RPM_PACKAGE_NAME
+ CPACK_RPM_<component>_PACKAGE_NAME
+
+ The RPM package name.
+
+ * Mandatory : YES
+ * Default : :variable:`CPACK_PACKAGE_NAME`
+
+ .. versionadded:: 3.5
+ Per-component ``CPACK_RPM_<component>_PACKAGE_NAME`` variables.
+
+.. variable:: CPACK_RPM_FILE_NAME
+ CPACK_RPM_<component>_FILE_NAME
+
+ .. versionadded:: 3.6
+
+ Package file name.
+
+ * Mandatory : YES
+ * Default : ``<CPACK_PACKAGE_FILE_NAME>[-<component>].rpm`` with spaces
+ replaced by '-'
+
+ This may be set to ``RPM-DEFAULT`` to allow ``rpmbuild`` tool to generate package
+ file name by itself.
+ Alternatively provided package file name must end with ``.rpm`` suffix.
+
+ .. note::
+
+ By using user provided spec file, rpm macro extensions such as for
+ generating ``debuginfo`` packages or by simply using multiple components more
+ than one rpm file may be generated, either from a single spec file or from
+ multiple spec files (each component execution produces its own spec file).
+ In such cases duplicate file names may occur as a result of this variable
+ setting or spec file content structure. Duplicate files get overwritten
+ and it is up to the packager to set the variables in a manner that will
+ prevent such errors.
+
+.. variable:: CPACK_RPM_MAIN_COMPONENT
+
+ .. versionadded:: 3.8
+
+ Main component that is packaged without component suffix.
+
+ * Mandatory : NO
+ * Default : -
+
+ This variable can be set to any component or group name so that component or
+ group rpm package is generated without component suffix in filename and
+ package name.
+
+.. variable:: CPACK_RPM_PACKAGE_EPOCH
+
+ .. versionadded:: 3.10
+
+ The RPM package epoch
+
+ * Mandatory : No
+ * Default : -
+
+ Optional number that should be incremented when changing versioning schemas
+ or fixing mistakes in the version numbers of older packages.
+
+.. variable:: CPACK_RPM_PACKAGE_VERSION
+
+ The RPM package version.
+
+ * Mandatory : YES
+ * Default : :variable:`CPACK_PACKAGE_VERSION`
+
+.. variable:: CPACK_RPM_PACKAGE_ARCHITECTURE
+ CPACK_RPM_<component>_PACKAGE_ARCHITECTURE
+
+ The RPM package architecture.
+
+ * Mandatory : YES
+ * Default : Native architecture output by ``uname -m``
+
+ This may be set to ``noarch`` if you know you are building a ``noarch`` package.
+
+ .. versionadded:: 3.3
+ Per-component ``CPACK_RPM_<component>_PACKAGE_ARCHITECTURE`` variables.
+
+.. variable:: CPACK_RPM_PACKAGE_RELEASE
+
+ The RPM package release.
+
+ * Mandatory : YES
+ * Default : 1
+
+ This is the numbering of the RPM package itself, i.e. the version of the
+ packaging and not the version of the content (see
+ :variable:`CPACK_RPM_PACKAGE_VERSION`). One may change the default value if
+ the previous packaging was buggy and/or you want to put here a fancy Linux
+ distro specific numbering.
+
+.. note::
+
+ This is the string that goes into the RPM ``Release:`` field. Some distros
+ (e.g. Fedora, CentOS) require ``1%{?dist}`` format and not just a number.
+ ``%{?dist}`` part can be added by setting :variable:`CPACK_RPM_PACKAGE_RELEASE_DIST`.
+
+.. variable:: CPACK_RPM_PACKAGE_RELEASE_DIST
+
+ .. versionadded:: 3.6
+
+ The dist tag that is added RPM ``Release:`` field.
+
+ * Mandatory : NO
+ * Default : OFF
+
+ This is the reported ``%{dist}`` tag from the current distribution or empty
+ ``%{dist}`` if RPM macro is not set. If this variable is set then RPM
+ ``Release:`` field value is set to ``${CPACK_RPM_PACKAGE_RELEASE}%{?dist}``.
+
+.. variable:: CPACK_RPM_PACKAGE_LICENSE
+
+ The RPM package license policy.
+
+ * Mandatory : YES
+ * Default : "unknown"
+
+.. variable:: CPACK_RPM_PACKAGE_GROUP
+ CPACK_RPM_<component>_PACKAGE_GROUP
+
+ The RPM package group.
+
+ * Mandatory : YES
+ * Default : "unknown"
+
+ .. versionadded:: 3.5
+ Per-component ``CPACK_RPM_<component>_PACKAGE_GROUP`` variables.
+
+.. variable:: CPACK_RPM_PACKAGE_VENDOR
+
+ The RPM package vendor.
+
+ * Mandatory : YES
+ * Default : CPACK_PACKAGE_VENDOR if set or "unknown"
+
+.. variable:: CPACK_RPM_PACKAGE_URL
+ CPACK_RPM_<component>_PACKAGE_URL
+
+ The projects URL.
+
+ * Mandatory : NO
+ * Default : :variable:`CMAKE_PROJECT_HOMEPAGE_URL`
+
+ .. versionadded:: 3.12
+ The ``CMAKE_PROJECT_HOMEPAGE_URL`` variable.
+
+.. variable:: CPACK_RPM_PACKAGE_DESCRIPTION
+ CPACK_RPM_<component>_PACKAGE_DESCRIPTION
+
+ RPM package description.
+
+ * Mandatory : YES
+ * Default : :variable:`CPACK_COMPONENT_<compName>_DESCRIPTION` (component
+ based installers only) if set, :variable:`CPACK_PACKAGE_DESCRIPTION_FILE`
+ if set or "no package description available"
+
+ .. versionadded:: 3.2
+ Per-component ``CPACK_RPM_<component>_PACKAGE_DESCRIPTION`` variables.
+
+.. variable:: CPACK_RPM_COMPRESSION_TYPE
+
+ RPM compression type.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to override RPM compression type to be used to build the
+ RPM. For example some Linux distribution now default to ``lzma`` or ``xz``
+ compression whereas older cannot use such RPM. Using this one can enforce
+ compression type to be used.
+
+ Possible values are:
+
+ - lzma
+ - xz
+ - bzip2
+ - gzip
+
+.. variable:: CPACK_RPM_PACKAGE_AUTOREQ
+ CPACK_RPM_<component>_PACKAGE_AUTOREQ
+
+ RPM spec autoreq field.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to enable (``1``, ``yes``) or disable (``0``, ``no``) automatic
+ shared libraries dependency detection. Dependencies are added to requires list.
+
+ .. note::
+
+ By default automatic dependency detection is enabled by rpm generator.
+
+.. variable:: CPACK_RPM_PACKAGE_AUTOPROV
+ CPACK_RPM_<component>_PACKAGE_AUTOPROV
+
+ RPM spec autoprov field.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to enable (``1``, ``yes``) or disable (``0``, ``no``)
+ automatic listing of shared libraries that are provided by the package.
+ Shared libraries are added to provides list.
+
+ .. note::
+
+ By default automatic provides detection is enabled by rpm generator.
+
+.. variable:: CPACK_RPM_PACKAGE_AUTOREQPROV
+ CPACK_RPM_<component>_PACKAGE_AUTOREQPROV
+
+ RPM spec autoreqprov field.
+
+ * Mandatory : NO
+ * Default : -
+
+ Variable enables/disables autoreq and autoprov at the same time.
+ See :variable:`CPACK_RPM_PACKAGE_AUTOREQ` and
+ :variable:`CPACK_RPM_PACKAGE_AUTOPROV` for more details.
+
+ .. note::
+
+ By default automatic detection feature is enabled by rpm.
+
+.. variable:: CPACK_RPM_PACKAGE_REQUIRES
+ CPACK_RPM_<component>_PACKAGE_REQUIRES
+
+ RPM spec requires field.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to set RPM dependencies (requires). Note that you must enclose
+ the complete requires string between quotes, for example::
+
+ set(CPACK_RPM_PACKAGE_REQUIRES "python >= 2.5.0, cmake >= 2.8")
+
+ The required package list of an RPM file could be printed with::
+
+ rpm -qp --requires file.rpm
+
+.. variable:: CPACK_RPM_PACKAGE_CONFLICTS
+ CPACK_RPM_<component>_PACKAGE_CONFLICTS
+
+ RPM spec conflicts field.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to set negative RPM dependencies (conflicts). Note that you must
+ enclose the complete requires string between quotes, for example::
+
+ set(CPACK_RPM_PACKAGE_CONFLICTS "libxml2")
+
+ The conflicting package list of an RPM file could be printed with::
+
+ rpm -qp --conflicts file.rpm
+
+.. variable:: CPACK_RPM_PACKAGE_REQUIRES_PRE
+ CPACK_RPM_<component>_PACKAGE_REQUIRES_PRE
+
+ .. versionadded:: 3.2
+
+ RPM spec requires(pre) field.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to set RPM preinstall dependencies (requires(pre)). Note that
+ you must enclose the complete requires string between quotes, for example::
+
+ set(CPACK_RPM_PACKAGE_REQUIRES_PRE "shadow-utils, initscripts")
+
+.. variable:: CPACK_RPM_PACKAGE_REQUIRES_POST
+ CPACK_RPM_<component>_PACKAGE_REQUIRES_POST
+
+ .. versionadded:: 3.2
+
+ RPM spec requires(post) field.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to set RPM postinstall dependencies (requires(post)). Note that
+ you must enclose the complete requires string between quotes, for example::
+
+ set(CPACK_RPM_PACKAGE_REQUIRES_POST "shadow-utils, initscripts")
+
+.. variable:: CPACK_RPM_PACKAGE_REQUIRES_POSTUN
+ CPACK_RPM_<component>_PACKAGE_REQUIRES_POSTUN
+
+ .. versionadded:: 3.2
+
+ RPM spec requires(postun) field.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to set RPM postuninstall dependencies (requires(postun)). Note
+ that you must enclose the complete requires string between quotes, for
+ example::
+
+ set(CPACK_RPM_PACKAGE_REQUIRES_POSTUN "shadow-utils, initscripts")
+
+.. variable:: CPACK_RPM_PACKAGE_REQUIRES_PREUN
+ CPACK_RPM_<component>_PACKAGE_REQUIRES_PREUN
+
+ .. versionadded:: 3.2
+
+ RPM spec requires(preun) field.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to set RPM preuninstall dependencies (requires(preun)). Note that
+ you must enclose the complete requires string between quotes, for example::
+
+ set(CPACK_RPM_PACKAGE_REQUIRES_PREUN "shadow-utils, initscripts")
+
+.. variable:: CPACK_RPM_PACKAGE_SUGGESTS
+ CPACK_RPM_<component>_PACKAGE_SUGGESTS
+
+ RPM spec suggest field.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to set weak RPM dependencies (suggests). Note that you must
+ enclose the complete requires string between quotes.
+
+.. variable:: CPACK_RPM_PACKAGE_PROVIDES
+ CPACK_RPM_<component>_PACKAGE_PROVIDES
+
+ RPM spec provides field.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to set RPM dependencies (provides). The provided package list
+ of an RPM file could be printed with::
+
+ rpm -qp --provides file.rpm
+
+.. variable:: CPACK_RPM_PACKAGE_OBSOLETES
+ CPACK_RPM_<component>_PACKAGE_OBSOLETES
+
+ RPM spec obsoletes field.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to set RPM packages that are obsoleted by this one.
+
+.. variable:: CPACK_RPM_PACKAGE_RELOCATABLE
+
+ build a relocatable RPM.
+
+ * Mandatory : NO
+ * Default : CPACK_PACKAGE_RELOCATABLE
+
+ If this variable is set to TRUE or ON, the CPack RPM generator will try
+ to build a relocatable RPM package. A relocatable RPM may
+ be installed using::
+
+ rpm --prefix or --relocate
+
+ in order to install it at an alternate place see rpm(8). Note that
+ currently this may fail if :variable:`CPACK_SET_DESTDIR` is set to ``ON``. If
+ :variable:`CPACK_SET_DESTDIR` is set then you will get a warning message but
+ if there is file installed with absolute path you'll get unexpected behavior.
+
+.. variable:: CPACK_RPM_SPEC_INSTALL_POST
+
+ Deprecated - use :variable:`CPACK_RPM_SPEC_MORE_DEFINE` instead.
+
+ * Mandatory : NO
+ * Default : -
+ * Deprecated: YES
+
+ May be used to override the ``__spec_install_post`` section within the
+ generated spec file. This affects the install step during package creation,
+ not during package installation. For adding operations to be performed
+ during package installation, use
+ :variable:`CPACK_RPM_POST_INSTALL_SCRIPT_FILE` instead.
+
+.. variable:: CPACK_RPM_SPEC_MORE_DEFINE
+
+ RPM extended spec definitions lines.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to add any ``%define`` lines to the generated spec file. An
+ example of its use is to prevent stripping of executables (but note that
+ this may also disable other default post install processing)::
+
+ set(CPACK_RPM_SPEC_MORE_DEFINE "%define __spec_install_post /bin/true")
+
+.. variable:: CPACK_RPM_PACKAGE_DEBUG
+
+ Toggle CPack RPM generator debug output.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be set when invoking cpack in order to trace debug information
+ during CPack RPM run. For example you may launch CPack like this::
+
+ cpack -D CPACK_RPM_PACKAGE_DEBUG=1 -G RPM
+
+.. variable:: CPACK_RPM_USER_BINARY_SPECFILE
+ CPACK_RPM_<componentName>_USER_BINARY_SPECFILE
+
+ A user provided spec file.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be set by the user in order to specify a USER binary spec file
+ to be used by the CPack RPM generator instead of generating the file.
+ The specified file will be processed by configure_file( @ONLY).
+
+.. variable:: CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE
+
+ Spec file template.
+
+ * Mandatory : NO
+ * Default : -
+
+ If set CPack will generate a template for USER specified binary
+ spec file and stop with an error. For example launch CPack like this::
+
+ cpack -D CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE=1 -G RPM
+
+ The user may then use this file in order to hand-craft is own
+ binary spec file which may be used with
+ :variable:`CPACK_RPM_USER_BINARY_SPECFILE`.
+
+.. variable:: CPACK_RPM_PRE_INSTALL_SCRIPT_FILE
+ CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE
+ CPACK_RPM_PRE_TRANS_SCRIPT_FILE
+
+ Path to file containing pre install/uninstall/transaction script.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to embed a pre installation/uninstallation/transaction script in the spec file.
+ The referred script file (or both) will be read and directly
+ put after the ``%pre`` or ``%preun`` section
+ If :variable:`CPACK_RPM_COMPONENT_INSTALL` is set to ON the install/uninstall/transaction
+ script for each component can be overridden with
+ ``CPACK_RPM_<COMPONENT>_PRE_INSTALL_SCRIPT_FILE``,
+ ``CPACK_RPM_<COMPONENT>_PRE_UNINSTALL_SCRIPT_FILE``, and
+ ``CPACK_RPM_<COMPONENT>_PRE_TRANS_SCRIPT_FILE``
+ One may verify which scriptlet has been included with::
+
+ rpm -qp --scripts package.rpm
+
+ .. versionadded:: 3.18
+ The ``CPACK_RPM_PRE_TRANS_SCRIPT_FILE`` variable.
+
+.. variable:: CPACK_RPM_POST_INSTALL_SCRIPT_FILE
+ CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE
+ CPACK_RPM_POST_TRANS_SCRIPT_FILE
+
+ Path to file containing post install/uninstall/transaction script.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to embed a post installation/uninstallation/transaction script in the spec file.
+ The referred script file (or both) will be read and directly
+ put after the ``%post`` or ``%postun`` section.
+ If :variable:`CPACK_RPM_COMPONENT_INSTALL` is set to ON the install/uninstall/transaction
+ script for each component can be overridden with
+ ``CPACK_RPM_<COMPONENT>_POST_INSTALL_SCRIPT_FILE``,
+ ``CPACK_RPM_<COMPONENT>_POST_UNINSTALL_SCRIPT_FILE``, and
+ ``CPACK_RPM_<COMPONENT>_POST_TRANS_SCRIPT_FILE``
+ One may verify which scriptlet has been included with::
+
+ rpm -qp --scripts package.rpm
+
+ .. versionadded:: 3.18
+ The ``CPACK_RPM_POST_TRANS_SCRIPT_FILE`` variable.
+
+.. variable:: CPACK_RPM_USER_FILELIST
+ CPACK_RPM_<COMPONENT>_USER_FILELIST
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to explicitly specify ``%(<directive>)`` file line
+ in the spec file. Like ``%config(noreplace)`` or any other directive
+ that be found in the ``%files`` section. Since
+ the CPack RPM generator is generating the list of files (and directories) the
+ user specified files of the ``CPACK_RPM_<COMPONENT>_USER_FILELIST`` list will
+ be removed from the generated list. If referring to directories do
+ not add a trailing slash.
+
+ .. versionadded:: 3.8
+ You can have multiple directives per line, as in
+ ``%attr(600,root,root) %config(noreplace)``.
+
+.. variable:: CPACK_RPM_CHANGELOG_FILE
+
+ RPM changelog file.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to embed a changelog in the spec file.
+ The referred file will be read and directly put after the ``%changelog``
+ section.
+
+.. variable:: CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST
+
+ list of path to be excluded.
+
+ * Mandatory : NO
+ * Default : /etc /etc/init.d /usr /usr/bin /usr/include /usr/lib
+ /usr/libx32 /usr/lib64 /usr/share /usr/share/aclocal
+ /usr/share/doc
+
+ May be used to exclude path (directories or files) from the auto-generated
+ list of paths discovered by CPack RPM. The default value contains a
+ reasonable set of values if the variable is not defined by the user. If the
+ variable is defined by the user then the CPack RPM generator will NOT any of
+ the default path. If you want to add some path to the default list then you
+ can use :variable:`CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION` variable.
+
+ .. versionadded:: 3.10
+ Added ``/usr/share/aclocal`` to the default list of excludes.
+
+.. variable:: CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
+
+ additional list of path to be excluded.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to add more exclude path (directories or files) from the initial
+ default list of excluded paths. See
+ :variable:`CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST`.
+
+.. variable:: CPACK_RPM_RELOCATION_PATHS
+
+ .. versionadded:: 3.2
+
+ Packages relocation paths list.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to specify more than one relocation path per relocatable RPM.
+ Variable contains a list of relocation paths that if relative are prefixed
+ by the value of :variable:`CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX` or by the
+ value of :variable:`CPACK_PACKAGING_INSTALL_PREFIX` if the component version
+ is not provided.
+ Variable is not component based as its content can be used to set a different
+ path prefix for e.g. binary dir and documentation dir at the same time.
+ Only prefixes that are required by a certain component are added to that
+ component - component must contain at least one file/directory/symbolic link
+ with :variable:`CPACK_RPM_RELOCATION_PATHS` prefix for a certain relocation
+ path to be added. Package will not contain any relocation paths if there are
+ no files/directories/symbolic links on any of the provided prefix locations.
+ Packages that either do not contain any relocation paths or contain
+ files/directories/symbolic links that are outside relocation paths print
+ out an ``AUTHOR_WARNING`` that RPM will be partially relocatable.
+
+.. variable:: CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX
+
+ .. versionadded:: 3.2
+
+ Per component relocation path install prefix.
+
+ * Mandatory : NO
+ * Default : CPACK_PACKAGING_INSTALL_PREFIX
+
+ May be used to set per component :variable:`CPACK_PACKAGING_INSTALL_PREFIX`
+ for relocatable RPM packages.
+
+.. variable:: CPACK_RPM_NO_INSTALL_PREFIX_RELOCATION
+ CPACK_RPM_NO_<COMPONENT>_INSTALL_PREFIX_RELOCATION
+
+ .. versionadded:: 3.3
+
+ Removal of default install prefix from relocation paths list.
+
+ * Mandatory : NO
+ * Default : CPACK_PACKAGING_INSTALL_PREFIX or CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX
+ are treated as one of relocation paths
+
+ May be used to remove CPACK_PACKAGING_INSTALL_PREFIX and CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX
+ from relocatable RPM prefix paths.
+
+.. variable:: CPACK_RPM_ADDITIONAL_MAN_DIRS
+
+ .. versionadded:: 3.3
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to set additional man dirs that could potentially be compressed
+ by brp-compress RPM macro. Variable content must be a list of regular
+ expressions that point to directories containing man files or to man files
+ directly. Note that in order to compress man pages a path must also be
+ present in brp-compress RPM script and that brp-compress script must be
+ added to RPM configuration by the operating system.
+
+ Regular expressions that are added by default were taken from brp-compress
+ RPM macro:
+
+ - /usr/man/man.*
+ - /usr/man/.*/man.*
+ - /usr/info.*
+ - /usr/share/man/man.*
+ - /usr/share/man/.*/man.*
+ - /usr/share/info.*
+ - /usr/kerberos/man.*
+ - /usr/X11R6/man/man.*
+ - /usr/lib/perl5/man/man.*
+ - /usr/share/doc/.*/man/man.*
+ - /usr/lib/.*/man/man.*
+
+.. variable:: CPACK_RPM_DEFAULT_USER
+ CPACK_RPM_<compName>_DEFAULT_USER
+
+ .. versionadded:: 3.6
+
+ default user ownership of RPM content
+
+ * Mandatory : NO
+ * Default : root
+
+ Value should be user name and not UID.
+ Note that <compName> must be in upper-case.
+
+.. variable:: CPACK_RPM_DEFAULT_GROUP
+ CPACK_RPM_<compName>_DEFAULT_GROUP
+
+ .. versionadded:: 3.6
+
+ default group ownership of RPM content
+
+ * Mandatory : NO
+ * Default : root
+
+ Value should be group name and not GID.
+ Note that <compName> must be in upper-case.
+
+.. variable:: CPACK_RPM_DEFAULT_FILE_PERMISSIONS
+ CPACK_RPM_<compName>_DEFAULT_FILE_PERMISSIONS
+
+ .. versionadded:: 3.6
+
+ default permissions used for packaged files
+
+ * Mandatory : NO
+ * Default : - (system default)
+
+ Accepted values are lists with ``PERMISSIONS``. Valid permissions
+ are:
+
+ - OWNER_READ
+ - OWNER_WRITE
+ - OWNER_EXECUTE
+ - GROUP_READ
+ - GROUP_WRITE
+ - GROUP_EXECUTE
+ - WORLD_READ
+ - WORLD_WRITE
+ - WORLD_EXECUTE
+
+ Note that <compName> must be in upper-case.
+
+.. variable:: CPACK_RPM_DEFAULT_DIR_PERMISSIONS
+ CPACK_RPM_<compName>_DEFAULT_DIR_PERMISSIONS
+
+ .. versionadded:: 3.6
+
+ default permissions used for packaged directories
+
+ * Mandatory : NO
+ * Default : - (system default)
+
+ Accepted values are lists with PERMISSIONS. Valid permissions
+ are the same as for :variable:`CPACK_RPM_DEFAULT_FILE_PERMISSIONS`.
+ Note that <compName> must be in upper-case.
+
+.. variable:: CPACK_RPM_INSTALL_WITH_EXEC
+
+ .. versionadded:: 3.11
+
+ force execute permissions on programs and shared libraries
+
+ * Mandatory : NO
+ * Default : - (system default)
+
+ Force set owner, group and world execute permissions on programs and shared
+ libraries. This can be used for creating valid rpm packages on systems such
+ as Debian where shared libraries do not have execute permissions set.
+
+.. note::
+
+ Programs and shared libraries without execute permissions are ignored during
+ separation of debug symbols from the binary for debuginfo packages.
+
+Packaging of Symbolic Links
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.3
+
+The CPack RPM generator supports packaging of symbolic links::
+
+ execute_process(COMMAND ${CMAKE_COMMAND}
+ -E create_symlink <relative_path_location> <symlink_name>)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/<symlink_name>
+ DESTINATION <symlink_location> COMPONENT libraries)
+
+Symbolic links will be optimized (paths will be shortened if possible)
+before being added to the package or if multiple relocation paths are
+detected, a post install symlink relocation script will be generated.
+
+Symbolic links may point to locations that are not packaged by the same
+package (either a different component or even not packaged at all) but
+those locations will be treated as if they were a part of the package
+while determining if symlink should be either created or present in a
+post install script - depending on relocation paths.
+
+.. versionchanged:: 3.6
+ Symbolic links that point to locations outside packaging path produce a
+ warning and are treated as non relocatable permanent symbolic links.
+ Previous versions of CMake produced an error in this case.
+
+Currently there are a few limitations though:
+
+* For component based packaging component interdependency is not checked
+ when processing symbolic links. Symbolic links pointing to content of
+ a different component are treated the same way as if pointing to location
+ that will not be packaged.
+
+* Symbolic links pointing to a location through one or more intermediate
+ symbolic links will not be handled differently - if the intermediate
+ symbolic link(s) is also on a relocatable path, relocating it during
+ package installation may cause initial symbolic link to point to an
+ invalid location.
+
+Packaging of debug information
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.7
+
+Debuginfo packages contain debug symbols and sources for debugging packaged
+binaries.
+
+Debuginfo RPM packaging has its own set of variables:
+
+.. variable:: CPACK_RPM_DEBUGINFO_PACKAGE
+ CPACK_RPM_<component>_DEBUGINFO_PACKAGE
+
+ Enable generation of debuginfo RPM package(s).
+
+ * Mandatory : NO
+ * Default : OFF
+
+.. note::
+
+ Binaries must contain debug symbols before packaging so use either ``Debug``
+ or ``RelWithDebInfo`` for :variable:`CMAKE_BUILD_TYPE` variable value.
+
+.. note::
+
+ Packages generated from packages without binary files, with binary files but
+ without execute permissions or without debug symbols will cause packaging
+ termination.
+
+.. variable:: CPACK_BUILD_SOURCE_DIRS
+
+ Provides locations of root directories of source files from which binaries
+ were built.
+
+ * Mandatory : YES if :variable:`CPACK_RPM_DEBUGINFO_PACKAGE` is set
+ * Default : -
+
+.. note::
+
+ For CMake project :variable:`CPACK_BUILD_SOURCE_DIRS` is set by default to
+ point to :variable:`CMAKE_SOURCE_DIR` and :variable:`CMAKE_BINARY_DIR` paths.
+
+.. note::
+
+ Sources with path prefixes that do not fall under any location provided with
+ :variable:`CPACK_BUILD_SOURCE_DIRS` will not be present in debuginfo package.
+
+.. variable:: CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX
+ CPACK_RPM_<component>_BUILD_SOURCE_DIRS_PREFIX
+
+ Prefix of location where sources will be placed during package installation.
+
+ * Mandatory : YES if :variable:`CPACK_RPM_DEBUGINFO_PACKAGE` is set
+ * Default : "/usr/src/debug/<CPACK_PACKAGE_FILE_NAME>" and
+ for component packaging "/usr/src/debug/<CPACK_PACKAGE_FILE_NAME>-<component>"
+
+.. note::
+
+ Each source path prefix is additionally suffixed by ``src_<index>`` where
+ index is index of the path used from :variable:`CPACK_BUILD_SOURCE_DIRS`
+ variable. This produces ``<CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX>/src_<index>``
+ replacement path.
+ Limitation is that replaced path part must be shorter or of equal
+ length than the length of its replacement. If that is not the case either
+ :variable:`CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX` variable has to be set to
+ a shorter path or source directories must be placed on a longer path.
+
+.. variable:: CPACK_RPM_DEBUGINFO_EXCLUDE_DIRS
+
+ Directories containing sources that should be excluded from debuginfo packages.
+
+ * Mandatory : NO
+ * Default : "/usr /usr/src /usr/src/debug"
+
+ Listed paths are owned by other RPM packages and should therefore not be
+ deleted on debuginfo package uninstallation.
+
+.. variable:: CPACK_RPM_DEBUGINFO_EXCLUDE_DIRS_ADDITION
+
+ Paths that should be appended to :variable:`CPACK_RPM_DEBUGINFO_EXCLUDE_DIRS`
+ for exclusion.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE
+
+ .. versionadded:: 3.8
+
+ Create a single debuginfo package even if components packaging is set.
+
+ * Mandatory : NO
+ * Default : OFF
+
+ When this variable is enabled it produces a single debuginfo package even if
+ component packaging is enabled.
+
+ When using this feature in combination with components packaging and there is
+ more than one component this variable requires :variable:`CPACK_RPM_MAIN_COMPONENT`
+ to be set.
+
+.. note::
+
+ If none of the :variable:`CPACK_RPM_<component>_DEBUGINFO_PACKAGE` variables
+ is set then :variable:`CPACK_RPM_DEBUGINFO_PACKAGE` is automatically set to
+ ``ON`` when :variable:`CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE` is set.
+
+.. variable:: CPACK_RPM_DEBUGINFO_FILE_NAME
+ CPACK_RPM_<component>_DEBUGINFO_FILE_NAME
+
+ .. versionadded:: 3.9
+
+ Debuginfo package file name.
+
+ * Mandatory : NO
+ * Default : rpmbuild tool generated package file name
+
+ Alternatively provided debuginfo package file name must end with ``.rpm``
+ suffix and should differ from file names of other generated packages.
+
+ Variable may contain ``@cpack_component@`` placeholder which will be
+ replaced by component name if component packaging is enabled otherwise it
+ deletes the placeholder.
+
+ Setting the variable to ``RPM-DEFAULT`` may be used to explicitly set
+ filename generation to default.
+
+.. note::
+
+ :variable:`CPACK_RPM_FILE_NAME` also supports rpmbuild tool generated package
+ file name - disabled by default but can be enabled by setting the variable to
+ ``RPM-DEFAULT``.
+
+Packaging of sources (SRPM)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.7
+
+SRPM packaging is enabled by setting :variable:`CPACK_RPM_PACKAGE_SOURCES`
+variable while usually using :variable:`CPACK_INSTALLED_DIRECTORIES` variable
+to provide directory containing CMakeLists.txt and source files.
+
+For CMake projects SRPM package would be produced by executing::
+
+ cpack -G RPM --config ./CPackSourceConfig.cmake
+
+.. note::
+
+ Produced SRPM package is expected to be built with :manual:`cmake(1)` executable
+ and packaged with :manual:`cpack(1)` executable so CMakeLists.txt has to be
+ located in root source directory and must be able to generate binary rpm
+ packages by executing ``cpack -G`` command. The two executables as well as
+ rpmbuild must also be present when generating binary rpm packages from the
+ produced SRPM package.
+
+Once the SRPM package is generated it can be used to generate binary packages
+by creating a directory structure for rpm generation and executing rpmbuild
+tool::
+
+ mkdir -p build_dir/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
+ rpmbuild --define "_topdir <path_to_build_dir>" --rebuild <SRPM_file_name>
+
+Generated packages will be located in build_dir/RPMS directory or its sub
+directories.
+
+.. note::
+
+ SRPM package internally uses CPack/RPM generator to generate binary packages
+ so CMakeScripts.txt can decide during the SRPM to binary rpm generation step
+ what content the package(s) should have as well as how they should be packaged
+ (monolithic or components). CMake can decide this for e.g. by reading environment
+ variables set by the package manager before starting the process of generating
+ binary rpm packages. This way a single SRPM package can be used to produce
+ different binary rpm packages on different platforms depending on the platform's
+ packaging rules.
+
+Source RPM packaging has its own set of variables:
+
+.. variable:: CPACK_RPM_PACKAGE_SOURCES
+
+ Should the content be packaged as a source rpm (default is binary rpm).
+
+ * Mandatory : NO
+ * Default : OFF
+
+.. note::
+
+ For cmake projects :variable:`CPACK_RPM_PACKAGE_SOURCES` variable is set
+ to ``OFF`` in CPackConfig.cmake and ``ON`` in CPackSourceConfig.cmake
+ generated files.
+
+.. variable:: CPACK_RPM_SOURCE_PKG_BUILD_PARAMS
+
+ Additional command-line parameters provided to :manual:`cmake(1)` executable.
+
+ * Mandatory : NO
+ * Default : -
+
+.. variable:: CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX
+
+ Packaging install prefix that would be provided in :variable:`CPACK_PACKAGING_INSTALL_PREFIX`
+ variable for producing binary RPM packages.
+
+ * Mandatory : YES
+ * Default : "/"
+
+.. VARIABLE:: CPACK_RPM_BUILDREQUIRES
+
+ List of source rpm build dependencies.
+
+ * Mandatory : NO
+ * Default : -
+
+ May be used to set source RPM build dependencies (BuildRequires). Note that
+ you must enclose the complete build requirements string between quotes, for
+ example::
+
+ set(CPACK_RPM_BUILDREQUIRES "python >= 2.5.0, cmake >= 2.8")
diff --git a/Help/cpack_gen/wix.rst b/Help/cpack_gen/wix.rst
new file mode 100644
index 0000000..79f835e
--- /dev/null
+++ b/Help/cpack_gen/wix.rst
@@ -0,0 +1,322 @@
+CPack WIX Generator
+-------------------
+
+CPack WIX generator specific options
+
+.. versionadded:: 3.7
+ Support :variable:`CPACK_COMPONENT_<compName>_DISABLED` variable.
+
+Variables specific to CPack WIX generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following variables are specific to the installers built on
+Windows using WiX.
+
+.. variable:: CPACK_WIX_UPGRADE_GUID
+
+ Upgrade GUID (``Product/@UpgradeCode``)
+
+ Will be automatically generated unless explicitly provided.
+
+ It should be explicitly set to a constant generated globally unique
+ identifier (GUID) to allow your installers to replace existing
+ installations that use the same GUID.
+
+ You may for example explicitly set this variable in your
+ CMakeLists.txt to the value that has been generated per default. You
+ should not use GUIDs that you did not generate yourself or which may
+ belong to other projects.
+
+ A GUID shall have the following fixed length syntax::
+
+ XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
+
+ (each X represents an uppercase hexadecimal digit)
+
+.. variable:: CPACK_WIX_PRODUCT_GUID
+
+ Product GUID (``Product/@Id``)
+
+ Will be automatically generated unless explicitly provided.
+
+ If explicitly provided this will set the Product Id of your installer.
+
+ The installer will abort if it detects a pre-existing installation that
+ uses the same GUID.
+
+ The GUID shall use the syntax described for CPACK_WIX_UPGRADE_GUID.
+
+.. variable:: CPACK_WIX_LICENSE_RTF
+
+ RTF License File
+
+ If CPACK_RESOURCE_FILE_LICENSE has an .rtf extension it is used as-is.
+
+ If CPACK_RESOURCE_FILE_LICENSE has an .txt extension it is implicitly
+ converted to RTF by the WIX Generator.
+ The expected encoding of the .txt file is UTF-8.
+
+ With CPACK_WIX_LICENSE_RTF you can override the license file used by the
+ WIX Generator in case CPACK_RESOURCE_FILE_LICENSE is in an unsupported
+ format or the .txt -> .rtf conversion does not work as expected.
+
+.. variable:: CPACK_WIX_PRODUCT_ICON
+
+ The Icon shown next to the program name in Add/Remove programs.
+
+ If set, this icon is used in place of the default icon.
+
+.. variable:: CPACK_WIX_UI_REF
+
+ This variable allows you to override the Id of the ``<UIRef>`` element
+ in the WiX template.
+
+ The default is ``WixUI_InstallDir`` in case no CPack components have
+ been defined and ``WixUI_FeatureTree`` otherwise.
+
+.. variable:: CPACK_WIX_UI_BANNER
+
+ The bitmap will appear at the top of all installer pages other than the
+ welcome and completion dialogs.
+
+ If set, this image will replace the default banner image.
+
+ This image must be 493 by 58 pixels.
+
+.. variable:: CPACK_WIX_UI_DIALOG
+
+ Background bitmap used on the welcome and completion dialogs.
+
+ If this variable is set, the installer will replace the default dialog
+ image.
+
+ This image must be 493 by 312 pixels.
+
+.. variable:: CPACK_WIX_PROGRAM_MENU_FOLDER
+
+ Start menu folder name for launcher.
+
+ If this variable is not set, it will be initialized with CPACK_PACKAGE_NAME
+
+ .. versionadded:: 3.16
+ If this variable is set to ``.``, then application shortcuts will be
+ created directly in the start menu and the uninstaller shortcut will be
+ omitted.
+
+.. variable:: CPACK_WIX_CULTURES
+
+ Language(s) of the installer
+
+ Languages are compiled into the WixUI extension library. To use them,
+ simply provide the name of the culture. If you specify more than one
+ culture identifier in a comma or semicolon delimited list, the first one
+ that is found will be used. You can find a list of supported languages at:
+ http://wix.sourceforge.net/manual-wix3/WixUI_localization.htm
+
+.. variable:: CPACK_WIX_TEMPLATE
+
+ Template file for WiX generation
+
+ If this variable is set, the specified template will be used to generate
+ the WiX wxs file. This should be used if further customization of the
+ output is required.
+
+ If this variable is not set, the default MSI template included with CMake
+ will be used.
+
+.. variable:: CPACK_WIX_PATCH_FILE
+
+ Optional list of XML files with fragments to be inserted into
+ generated WiX sources.
+
+ .. versionadded:: 3.5
+ Support listing multiple patch files.
+
+ This optional variable can be used to specify an XML file that the
+ WIX generator will use to inject fragments into its generated
+ source files.
+
+ Patch files understood by the CPack WIX generator
+ roughly follow this RELAX NG compact schema:
+
+ .. code-block:: none
+
+ start = CPackWiXPatch
+
+ CPackWiXPatch = element CPackWiXPatch { CPackWiXFragment* }
+
+ CPackWiXFragment = element CPackWiXFragment
+ {
+ attribute Id { string },
+ fragmentContent*
+ }
+
+ fragmentContent = element * - CPackWiXFragment
+ {
+ (attribute * { text } | text | fragmentContent)*
+ }
+
+ Currently fragments can be injected into most
+ Component, File, Directory and Feature elements.
+
+ .. versionadded:: 3.3
+ The following additional special Ids can be used:
+
+ * ``#PRODUCT`` for the ``<Product>`` element.
+ * ``#PRODUCTFEATURE`` for the root ``<Feature>`` element.
+
+ .. versionadded:: 3.7
+ Support patching arbitrary ``<Feature>`` elements.
+
+ .. versionadded:: 3.9
+ Allow setting additional attributes.
+
+ The following example illustrates how this works.
+
+ Given that the WIX generator creates the following XML element:
+
+ .. code-block:: xml
+
+ <Component Id="CM_CP_applications.bin.my_libapp.exe" Guid="*"/>
+
+ The following XML patch file may be used to inject an Environment element
+ into it:
+
+ .. code-block:: xml
+
+ <CPackWiXPatch>
+ <CPackWiXFragment Id="CM_CP_applications.bin.my_libapp.exe">
+ <Environment Id="MyEnvironment" Action="set"
+ Name="MyVariableName" Value="MyVariableValue"/>
+ </CPackWiXFragment>
+ </CPackWiXPatch>
+
+.. variable:: CPACK_WIX_EXTRA_SOURCES
+
+ Extra WiX source files
+
+ This variable provides an optional list of extra WiX source files (.wxs)
+ that should be compiled and linked. The full path to source files is
+ required.
+
+.. variable:: CPACK_WIX_EXTRA_OBJECTS
+
+ Extra WiX object files or libraries
+
+ This variable provides an optional list of extra WiX object (.wixobj)
+ and/or WiX library (.wixlib) files. The full path to objects and libraries
+ is required.
+
+.. variable:: CPACK_WIX_EXTENSIONS
+
+ This variable provides a list of additional extensions for the WiX
+ tools light and candle.
+
+.. variable:: CPACK_WIX_<TOOL>_EXTENSIONS
+
+ This is the tool specific version of CPACK_WIX_EXTENSIONS.
+ ``<TOOL>`` can be either LIGHT or CANDLE.
+
+.. variable:: CPACK_WIX_<TOOL>_EXTRA_FLAGS
+
+ This list variable allows you to pass additional
+ flags to the WiX tool ``<TOOL>``.
+
+ Use it at your own risk.
+ Future versions of CPack may generate flags which may be in conflict
+ with your own flags.
+
+ ``<TOOL>`` can be either LIGHT or CANDLE.
+
+.. variable:: CPACK_WIX_CMAKE_PACKAGE_REGISTRY
+
+ If this variable is set the generated installer will create
+ an entry in the windows registry key
+ ``HKEY_LOCAL_MACHINE\Software\Kitware\CMake\Packages\<PackageName>``
+ The value for ``<PackageName>`` is provided by this variable.
+
+ Assuming you also install a CMake configuration file this will
+ allow other CMake projects to find your package with
+ the :command:`find_package` command.
+
+.. variable:: CPACK_WIX_PROPERTY_<PROPERTY>
+
+ .. versionadded:: 3.1
+
+ This variable can be used to provide a value for
+ the Windows Installer property ``<PROPERTY>``
+
+ The following list contains some example properties that can be used to
+ customize information under
+ "Programs and Features" (also known as "Add or Remove Programs")
+
+ * ARPCOMMENTS - Comments
+ * ARPHELPLINK - Help and support information URL
+ * ARPURLINFOABOUT - General information URL
+ * ARPURLUPDATEINFO - Update information URL
+ * ARPHELPTELEPHONE - Help and support telephone number
+ * ARPSIZE - Size (in kilobytes) of the application
+
+.. variable:: CPACK_WIX_ROOT_FEATURE_TITLE
+
+ .. versionadded:: 3.7
+
+ Sets the name of the root install feature in the WIX installer. Same as
+ CPACK_COMPONENT_<compName>_DISPLAY_NAME for components.
+
+.. variable:: CPACK_WIX_ROOT_FEATURE_DESCRIPTION
+
+ .. versionadded:: 3.7
+
+ Sets the description of the root install feature in the WIX installer. Same as
+ CPACK_COMPONENT_<compName>_DESCRIPTION for components.
+
+.. variable:: CPACK_WIX_SKIP_PROGRAM_FOLDER
+
+ .. versionadded:: 3.7
+
+ If this variable is set to true, the default install location
+ of the generated package will be CPACK_PACKAGE_INSTALL_DIRECTORY directly.
+ The install location will not be located relatively below
+ ProgramFiles or ProgramFiles64.
+
+ .. note::
+ Installers created with this feature do not take differences
+ between the system on which the installer is created
+ and the system on which the installer might be used into account.
+
+ It is therefore possible that the installer e.g. might try to install
+ onto a drive that is unavailable or unintended or a path that does not
+ follow the localization or convention of the system on which the
+ installation is performed.
+
+.. variable:: CPACK_WIX_ROOT_FOLDER_ID
+
+ .. versionadded:: 3.9
+
+ This variable allows specification of a custom root folder ID.
+ The generator specific ``<64>`` token can be used for
+ folder IDs that come in 32-bit and 64-bit variants.
+ In 32-bit builds the token will expand empty while in 64-bit builds
+ it will expand to ``64``.
+
+ When unset generated installers will default installing to
+ ``ProgramFiles<64>Folder``.
+
+.. variable:: CPACK_WIX_ROOT
+
+ This variable can optionally be set to the root directory
+ of a custom WiX Toolset installation.
+
+ When unspecified CPack will try to locate a WiX Toolset
+ installation via the ``WIX`` environment variable instead.
+
+.. variable:: CPACK_WIX_CUSTOM_XMLNS
+
+ .. versionadded:: 3.19
+
+ This variable provides a list of custom namespace declarations that are necessary
+ for using WiX extensions. Each declaration should be in the form name=url, where
+ name is the plain namespace without the usual xmlns: prefix and url is an unquoted
+ namespace url. A list of commonly known WiX schemata can be found here:
+ https://wixtoolset.org/documentation/manual/v3/xsd/
diff --git a/Help/dev/README.rst b/Help/dev/README.rst
new file mode 100644
index 0000000..9c3878b
--- /dev/null
+++ b/Help/dev/README.rst
@@ -0,0 +1,53 @@
+CMake Development
+*****************
+
+This directory contains documentation about development of CMake itself.
+It is not part of the user documentation distributed with CMake.
+
+Contributor Instructions
+========================
+
+See `CONTRIBUTING.rst`_ for instructions to contribute changes.
+
+The process for contributing changes is the same whether or not one
+has been invited to participate directly in upstream development.
+
+.. _`CONTRIBUTING.rst`: ../../CONTRIBUTING.rst
+
+Upstream Development
+====================
+
+CMake uses `Kitware's GitLab Instance`_ to manage development, review, and
+integration of changes. The `CMake Repository`_ holds the integration
+branches and tags. Upstream development processes are covered by the
+following documents:
+
+* The `CMake Review Process`_ manages integration of changes.
+* The `CMake Testing Process`_ drives integration testing.
+
+.. _`Kitware's GitLab Instance`: https://gitlab.kitware.com
+.. _`CMake Repository`: https://gitlab.kitware.com/cmake/cmake
+.. _`CMake Review Process`: review.rst
+.. _`CMake Testing Process`: testing.rst
+
+Developer Documentation
+=======================
+
+CMake developer documentation is provided by the following documents:
+
+* The `CMake Source Code Guide`_.
+* The `CMake Documentation Guide`_.
+* The `CMake Experimental Features Guide`_.
+
+.. _`CMake Source Code Guide`: source.rst
+.. _`CMake Documentation Guide`: documentation.rst
+.. _`CMake Experimental Features Guide`: experimental.rst
+
+Maintainer Documentation
+========================
+
+CMake maintainer documentation is provided by the following documents:
+
+* The `CMake Maintainer Guide`_.
+
+.. _`CMake Maintainer Guide`: maint.rst
diff --git a/Help/dev/documentation.rst b/Help/dev/documentation.rst
new file mode 100644
index 0000000..29fc880
--- /dev/null
+++ b/Help/dev/documentation.rst
@@ -0,0 +1,556 @@
+CMake Documentation Guide
+*************************
+
+The following is a guide to the CMake documentation source for developers.
+See documentation on `CMake Development`_ for more information.
+
+.. _`CMake Development`: README.rst
+
+Help
+====
+
+The ``Help`` directory contains CMake help manual source files.
+They are written using the `reStructuredText`_ markup syntax and
+processed by `Sphinx`_ to generate the CMake help manuals.
+
+.. _`reStructuredText`: http://docutils.sourceforge.net/docs/ref/rst/introduction.html
+.. _`Sphinx`: http://sphinx-doc.org
+
+Markup Constructs
+-----------------
+
+In addition to using Sphinx to generate the CMake help manuals, we
+also use a C++-implemented document processor to print documents for
+the ``--help-*`` command-line help options. It supports a subset of
+reStructuredText markup. When authoring or modifying documents,
+please verify that the command-line help looks good in addition to the
+Sphinx-generated html and man pages.
+
+The command-line help processor supports the following constructs
+defined by reStructuredText, Sphinx, and a CMake extension to Sphinx.
+
+..
+ Note: This list must be kept consistent with the cmRST implementation.
+
+CMake Domain directives
+ Directives defined in the `CMake Domain`_ for defining CMake
+ documentation objects are printed in command-line help output as
+ if the lines were normal paragraph text with interpretation.
+
+CMake Domain interpreted text roles
+ Interpreted text roles defined in the `CMake Domain`_ for
+ cross-referencing CMake documentation objects are replaced by their
+ link text in command-line help output. Other roles are printed
+ literally and not processed.
+
+``code-block`` directive
+ Add a literal code block without interpretation. The command-line
+ help processor prints the block content without the leading directive
+ line and with common indentation replaced by one space.
+
+``include`` directive
+ Include another document source file. The command-line help
+ processor prints the included document inline with the referencing
+ document.
+
+literal block after ``::``
+ A paragraph ending in ``::`` followed by a blank line treats
+ the following indented block as literal text without interpretation.
+ The command-line help processor prints the ``::`` literally and
+ prints the block content with common indentation replaced by one
+ space.
+
+``note`` directive
+ Call out a side note. The command-line help processor prints the
+ block content as if the lines were normal paragraph text with
+ interpretation.
+
+``parsed-literal`` directive
+ Add a literal block with markup interpretation. The command-line
+ help processor prints the block content without the leading
+ directive line and with common indentation replaced by one space.
+
+``productionlist`` directive
+ Render context-free grammar productions. The command-line help
+ processor prints the block content as if the lines were normal
+ paragraph text with interpretation.
+
+``replace`` directive
+ Define a ``|substitution|`` replacement.
+ The command-line help processor requires a substitution replacement
+ to be defined before it is referenced.
+
+``|substitution|`` reference
+ Reference a substitution replacement previously defined by
+ the ``replace`` directive. The command-line help processor
+ performs the substitution and replaces all newlines in the
+ replacement text with spaces.
+
+``toctree`` directive
+ Include other document sources in the Table-of-Contents
+ document tree. The command-line help processor prints
+ the referenced documents inline as part of the referencing
+ document.
+
+Inline markup constructs not listed above are printed literally in the
+command-line help output. We prefer to use inline markup constructs that
+look correct in source form, so avoid use of \\-escapes in favor of inline
+literals when possible.
+
+Explicit markup blocks not matching directives listed above are removed from
+command-line help output. Do not use them, except for plain ``..`` comments
+that are removed by Sphinx too.
+
+Note that nested indentation of blocks is not recognized by the
+command-line help processor. Therefore:
+
+* Explicit markup blocks are recognized only when not indented
+ inside other blocks.
+
+* Literal blocks after paragraphs ending in ``::`` but not
+ at the top indentation level may consume all indented lines
+ following them.
+
+Try to avoid these cases in practice.
+
+CMake Domain
+------------
+
+CMake adds a `Sphinx Domain`_ called ``cmake``, also called the
+"CMake Domain". It defines several "object" types for CMake
+documentation:
+
+``command``
+ A CMake language command.
+
+``cpack_gen``
+ A CPack package generator.
+ See the `cpack(1)`_ command-line tool's ``-G`` option.
+
+``envvar``
+ An environment variable.
+ See the `cmake-env-variables(7)`_ manual
+ and the `set()`_ command.
+
+``generator``
+ A CMake native build system generator.
+ See the `cmake(1)`_ command-line tool's ``-G`` option.
+
+``genex``
+ A CMake generator expression.
+ See the `cmake-generator-expressions(7)`_ manual.
+
+``manual``
+ A CMake manual page, like the `cmake(1)`_ manual.
+
+``module``
+ A CMake module.
+ See the `cmake-modules(7)`_ manual
+ and the `include()`_ command.
+
+``policy``
+ A CMake policy.
+ See the `cmake-policies(7)`_ manual
+ and the `cmake_policy()`_ command.
+
+``prop_cache, prop_dir, prop_gbl, prop_sf, prop_inst, prop_test, prop_tgt``
+ A CMake cache, directory, global, source file, installed file, test,
+ or target property, respectively. See the `cmake-properties(7)`_
+ manual and the `set_property()`_ command.
+
+``variable``
+ A CMake language variable.
+ See the `cmake-variables(7)`_ manual
+ and the `set()`_ command.
+
+Documentation objects in the CMake Domain come from two sources.
+First, the CMake extension to Sphinx transforms every document named
+with the form ``Help/<type>/<file-name>.rst`` to a domain object with
+type ``<type>``. The object name is extracted from the document title,
+which is expected to be of the form::
+
+ <object-name>
+ -------------
+
+and to appear at or near the top of the ``.rst`` file before any other
+lines starting in a letter, digit, ``<``, or ``$``. If no such title appears
+literally in the ``.rst`` file, the object name is the ``<file-name>``.
+If a title does appear, it is expected that ``<file-name>`` is equal
+to ``<object-name>`` with any ``<`` and ``>`` characters removed,
+or in the case of a ``$<genex-name>`` or ``$<genex-name:...>``, the
+``genex-name``.
+
+Second, the CMake Domain provides directives to define objects inside
+other documents:
+
+.. code-block:: rst
+
+ .. command:: <command-name>
+
+ This indented block documents <command-name>.
+
+ .. envvar:: <envvar-name>
+
+ This indented block documents <envvar-name>.
+
+ .. genex:: <genex-name>
+
+ This indented block documents <genex-name>.
+
+ .. variable:: <variable-name>
+
+ This indented block documents <variable-name>.
+
+Object types for which no directive is available must be defined using
+the first approach above.
+
+.. _`Sphinx Domain`: http://sphinx-doc.org/domains.html
+.. _`cmake(1)`: https://cmake.org/cmake/help/latest/manual/cmake.1.html
+.. _`cmake-env-variables(7)`: https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html
+.. _`cmake-generator-expressions(7)`: https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html
+.. _`cmake-modules(7)`: https://cmake.org/cmake/help/latest/manual/cmake-modules.7.html
+.. _`cmake-policies(7)`: https://cmake.org/cmake/help/latest/manual/cmake-policies.7.html
+.. _`cmake-properties(7)`: https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html
+.. _`cmake-variables(7)`: https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html
+.. _`cmake_policy()`: https://cmake.org/cmake/help/latest/command/cmake_policy.html
+.. _`cpack(1)`: https://cmake.org/cmake/help/latest/manual/cpack.1.html
+.. _`include()`: https://cmake.org/cmake/help/latest/command/include.html
+.. _`set()`: https://cmake.org/cmake/help/latest/command/set.html
+.. _`set_property()`: https://cmake.org/cmake/help/latest/command/set_property.html
+
+Cross-References
+----------------
+
+Sphinx uses reStructuredText interpreted text roles to provide
+cross-reference syntax. The `CMake Domain`_ provides for each
+domain object type a role of the same name to cross-reference it.
+CMake Domain roles are inline markup of the forms::
+
+ :type:`name`
+ :type:`text <name>`
+
+where ``type`` is the domain object type and ``name`` is the
+domain object name. In the first form the link text will be
+``name`` (or ``name()`` if the type is ``command``) and in
+the second form the link text will be the explicit ``text``.
+For example, the code:
+
+.. code-block:: rst
+
+ * The :command:`list` command.
+ * The :command:`list(APPEND)` sub-command.
+ * The :command:`list() command <list>`.
+ * The :command:`list(APPEND) sub-command <list>`.
+ * The :variable:`CMAKE_VERSION` variable.
+ * The :prop_tgt:`OUTPUT_NAME_<CONFIG>` target property.
+
+produces:
+
+* The `list()`_ command.
+* The `list(APPEND)`_ sub-command.
+* The `list() command`_.
+* The `list(APPEND) sub-command`_.
+* The `CMAKE_VERSION`_ variable.
+* The `OUTPUT_NAME_<CONFIG>`_ target property.
+
+Note that CMake Domain roles differ from Sphinx and reStructuredText
+convention in that the form ``a<b>``, without a space preceding ``<``,
+is interpreted as a name instead of link text with an explicit target.
+This is necessary because we use ``<placeholders>`` frequently in
+object names like ``OUTPUT_NAME_<CONFIG>``. The form ``a <b>``,
+with a space preceding ``<``, is still interpreted as a link text
+with an explicit target.
+
+.. _`list()`: https://cmake.org/cmake/help/latest/command/list.html
+.. _`list(APPEND)`: https://cmake.org/cmake/help/latest/command/list.html
+.. _`list(APPEND) sub-command`: https://cmake.org/cmake/help/latest/command/list.html
+.. _`list() command`: https://cmake.org/cmake/help/latest/command/list.html
+.. _`CMAKE_VERSION`: https://cmake.org/cmake/help/latest/variable/CMAKE_VERSION.html
+.. _`OUTPUT_NAME_<CONFIG>`: https://cmake.org/cmake/help/latest/prop_tgt/OUTPUT_NAME_CONFIG.html
+
+Style
+-----
+
+Style: Section Headers
+^^^^^^^^^^^^^^^^^^^^^^
+
+When marking section titles, make the section decoration line as long as
+the title text. Use only a line below the title, not above. For
+example:
+
+.. code-block:: rst
+
+ Title Text
+ ----------
+
+Capitalize the first letter of each non-minor word in the title.
+
+The section header underline character hierarchy is
+
+* ``#``: Manual group (part) in the master document
+* ``*``: Manual (chapter) title
+* ``=``: Section within a manual
+* ``-``: Subsection or `CMake Domain`_ object document title
+* ``^``: Subsubsection or `CMake Domain`_ object document section
+* ``"``: Paragraph or `CMake Domain`_ object document subsection
+
+Style: Whitespace
+^^^^^^^^^^^^^^^^^
+
+Use two spaces for indentation. Use two spaces between sentences in
+prose.
+
+Style: Line Length
+^^^^^^^^^^^^^^^^^^
+
+Prefer to restrict the width of lines to 75-80 columns. This is not a
+hard restriction, but writing new paragraphs wrapped at 75 columns
+allows space for adding minor content without significant re-wrapping of
+content.
+
+Style: Prose
+^^^^^^^^^^^^
+
+Use American English spellings in prose.
+
+Style: Starting Literal Blocks
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Prefer to mark the start of literal blocks with ``::`` at the end of
+the preceding paragraph. In cases where the following block gets
+a ``code-block`` marker, put a single ``:`` at the end of the preceding
+paragraph.
+
+Style: CMake Command Signatures
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Command signatures should be marked up as plain literal blocks, not as
+cmake ``code-blocks``.
+
+Signatures are separated from preceding content by a section header.
+That is, use:
+
+.. code-block:: rst
+
+ ... preceding paragraph.
+
+ Normal Libraries
+ ^^^^^^^^^^^^^^^^
+
+ ::
+
+ add_library(<lib> ...)
+
+ This signature is used for ...
+
+Signatures of commands should wrap optional parts with square brackets,
+and should mark list of optional arguments with an ellipsis (``...``).
+Elements of the signature which are specified by the user should be
+specified with angle brackets, and may be referred to in prose using
+``inline-literal`` syntax.
+
+Style: Boolean Constants
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use "``OFF``" and "``ON``" for boolean values which can be modified by
+the user, such as ``POSITION_INDEPENDENT_CODE``. Such properties
+may be "enabled" and "disabled". Use "``True``" and "``False``" for
+inherent values which can't be modified after being set, such as the
+``IMPORTED`` property of a build target.
+
+Style: Inline Literals
+^^^^^^^^^^^^^^^^^^^^^^
+
+Mark up references to keywords in signatures, file names, and other
+technical terms with ``inline-literal`` syntax, for example:
+
+.. code-block:: rst
+
+ If ``WIN32`` is used with :command:`add_executable`, the
+ :prop_tgt:`WIN32_EXECUTABLE` target property is enabled. That command
+ creates the file ``<name>.exe`` on Windows.
+
+Style: Cross-References
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Mark up linkable references as links, including repeats.
+An alternative, which is used by wikipedia
+(`<http://en.wikipedia.org/wiki/WP:REPEATLINK>`_),
+is to link to a reference only once per article. That style is not used
+in CMake documentation.
+
+Style: Referencing CMake Concepts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If referring to a concept which corresponds to a property, and that
+concept is described in a high-level manual, prefer to link to the
+manual section instead of the property. For example:
+
+.. code-block:: rst
+
+ This command creates an :ref:`Imported Target <Imported Targets>`.
+
+instead of:
+
+.. code-block:: rst
+
+ This command creates an :prop_tgt:`IMPORTED` target.
+
+The latter should be used only when referring specifically to the
+property.
+
+References to manual sections are not automatically created by creating
+a section, but code such as:
+
+.. code-block:: rst
+
+ .. _`Imported Targets`:
+
+creates a suitable anchor. Use an anchor name which matches the name
+of the corresponding section. Refer to the anchor using a
+cross-reference with specified text.
+
+Imported Targets need the ``IMPORTED`` term marked up with care in
+particular because the term may refer to a command keyword, a target
+property, or a concept.
+
+Where a property, command or variable is related conceptually to others,
+by for example, being related to the buildsystem description, generator
+expressions or Qt, each relevant property, command or variable should
+link to the primary manual, which provides high-level information. Only
+particular information relating to the command should be in the
+documentation of the command.
+
+Style: Referencing CMake Domain Objects
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When referring to `CMake Domain`_ objects such as properties, variables,
+commands etc, prefer to link to the target object and follow that with
+the type of object it is. For example:
+
+.. code-block:: rst
+
+ Set the :prop_tgt:`AUTOMOC` target property to ``ON``.
+
+Instead of
+
+.. code-block:: rst
+
+ Set the target property :prop_tgt:`AUTOMOC` to ``ON``.
+
+The ``policy`` directive is an exception, and the type us usually
+referred to before the link:
+
+.. code-block:: rst
+
+ If policy :policy:`CMP0022` is set to ``NEW`` the behavior is ...
+
+However, markup self-references with ``inline-literal`` syntax.
+For example, within the ``add_executable`` command documentation, use
+
+.. code-block:: rst
+
+ ``add_executable``
+
+not
+
+.. code-block:: rst
+
+ :command:`add_executable`
+
+which is used elsewhere.
+
+Modules
+=======
+
+The ``Modules`` directory contains CMake-language ``.cmake`` module files.
+
+Module Documentation
+--------------------
+
+To document CMake module ``Modules/<module-name>.cmake``, modify
+``Help/manual/cmake-modules.7.rst`` to reference the module in the
+``toctree`` directive, in sorted order, as::
+
+ /module/<module-name>
+
+Then add the module document file ``Help/module/<module-name>.rst``
+containing just the line::
+
+ .. cmake-module:: ../../Modules/<module-name>.cmake
+
+The ``cmake-module`` directive will scan the module file to extract
+reStructuredText markup from comment blocks that start in ``.rst:``.
+At the top of ``Modules/<module-name>.cmake``, begin with the following
+license notice:
+
+::
+
+ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ # file Copyright.txt or https://cmake.org/licensing for details.
+
+After this notice, add a *BLANK* line. Then, add documentation using
+a `Bracket Comment`_ of the form:
+
+::
+
+ #[=======================================================================[.rst:
+ <module-name>
+ -------------
+
+ <reStructuredText documentation of module>
+ #]=======================================================================]
+
+Any number of ``=`` may be used in the opening and closing brackets
+as long as they match. Content on the line containing the closing
+bracket is excluded if and only if the line starts in ``#``.
+
+Additional such ``.rst:`` comments may appear anywhere in the module file.
+All such comments must start with ``#`` in the first column.
+
+For example, a ``Findxxx.cmake`` module may contain:
+
+::
+
+ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ # file Copyright.txt or https://cmake.org/licensing for details.
+
+ #[=======================================================================[.rst:
+ FindXxx
+ -------
+
+ This is a cool module.
+ This module does really cool stuff.
+ It can do even more than you think.
+
+ It even needs two paragraphs to tell you about it.
+ And it defines the following variables:
+
+ ``VAR_COOL``
+ this is great isn't it?
+ ``VAR_REALLY_COOL``
+ cool right?
+ #]=======================================================================]
+
+ <code>
+
+ #[=======================================================================[.rst:
+ .. command:: xxx_do_something
+
+ This command does something for Xxx::
+
+ xxx_do_something(some arguments)
+ #]=======================================================================]
+ macro(xxx_do_something)
+ <code>
+ endmacro()
+
+Test the documentation formatting by running
+``cmake --help-module <module-name>``, and also by enabling the
+``SPHINX_HTML`` and ``SPHINX_MAN`` options to build the documentation.
+Edit the comments until generated documentation looks satisfactory. To
+have a .cmake file in this directory NOT show up in the modules
+documentation, simply leave out the ``Help/module/<module-name>.rst``
+file and the ``Help/manual/cmake-modules.7.rst`` toctree entry.
+
+.. _`Bracket Comment`: https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#bracket-comment
diff --git a/Help/dev/experimental.rst b/Help/dev/experimental.rst
new file mode 100644
index 0000000..d019161
--- /dev/null
+++ b/Help/dev/experimental.rst
@@ -0,0 +1,70 @@
+CMake Experimental Features Guide
+*********************************
+
+The following is a guide to CMake experimental features that are
+under development and not yet included in official documentation.
+See documentation on `CMake Development`_ for more information.
+
+.. _`CMake Development`: README.rst
+
+C++20 Module Dependencies
+=========================
+
+The Ninja generator has experimental infrastructure supporting C++20 module
+dependency scanning. This is similar to the Fortran modules support, but
+relies on external tools to scan C++20 translation units for module
+dependencies. The approach is described by Kitware's `D1483r1`_ paper.
+
+The ``CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP`` variable can be set to ``1``
+in order to activate this undocumented experimental infrastructure. This
+is **intended to make the functionality available to compiler writers** so
+they can use it to develop and test their dependency scanning tool.
+The ``CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE`` variable must also be set
+to tell CMake how to invoke the C++20 module dependency scanning tool.
+
+For example, add code like the following to a test project:
+
+.. code-block:: cmake
+
+ set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
+ string(CONCAT CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE
+ "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> <SOURCE>"
+ " -MT <DYNDEP_FILE> -MD -MF <DEP_FILE>"
+ " ${flags_to_scan_deps} -fdep-file=<DYNDEP_FILE> -fdep-output=<OBJECT>"
+ )
+
+The tool specified by ``CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE`` is
+expected to process the translation unit, write preprocessor dependencies
+to the file specified by the ``<DEP_FILE>`` placeholder, and write module
+dependencies to the file specified by the ``<DYNDEP_FILE>`` placeholder.
+
+The module dependencies should be written in the format described
+by the `P1689r3`_ paper.
+
+Compiler writers may try out their scanning functionality using
+the `cxx-modules-sandbox`_ test project, modified to set variables
+as above for their compiler.
+
+For compilers that generate module maps, tell CMake as follows:
+
+.. code-block:: cmake
+
+ set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "gcc")
+ set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG
+ "${compiler_flags_for_module_map} -fmodule-mapper=<MODULE_MAP_FILE>")
+
+Currently, the only supported format is ``gcc``. The format is described in
+the GCC documentation, but the relevant section for the purposes of CMake is:
+
+ A mapping file consisting of space-separated module-name, filename
+ pairs, one per line. Only the mappings for the direct imports and any
+ module export name need be provided. If other mappings are provided,
+ they override those stored in any imported CMI files. A repository
+ root may be specified in the mapping file by using ``$root`` as the
+ module name in the first active line.
+
+ -- GCC module mapper documentation
+
+.. _`D1483r1`: https://mathstuf.fedorapeople.org/fortran-modules/fortran-modules.html
+.. _`P1689r3`: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1689r3.html
+.. _`cxx-modules-sandbox`: https://github.com/mathstuf/cxx-modules-sandbox
diff --git a/Help/dev/maint.rst b/Help/dev/maint.rst
new file mode 100644
index 0000000..664b7a4
--- /dev/null
+++ b/Help/dev/maint.rst
@@ -0,0 +1,369 @@
+CMake Maintainer Guide
+**********************
+
+The following is a guide to CMake maintenance processes.
+See documentation on `CMake Development`_ for more information.
+
+.. _`CMake Development`: README.rst
+
+.. contents:: Maintainer Processes:
+
+Review a Merge Request
+======================
+
+The `CMake Review Process`_ requires a maintainer to issue the ``Do: merge``
+command to integrate a merge request. Please check at least the following:
+
+* If the MR source branch (or part of it) should be backported
+ to the ``release`` branch (and is already based on a commit
+ contained in the ``release`` branch), add a ``Backport: release`` or
+ ``Backport: release:<commit-ish>`` trailing line to the MR description.
+
+* If the MR source branch is not named well for the change it makes
+ (e.g. it is just ``master`` or the patch changed during review),
+ add a ``Topic-rename: <topic>`` trailing line to the MR description
+ to provide a better topic name.
+
+* If the MR introduces a new feature or a user-facing behavior change,
+ such as a policy, ensure that a ``Help/release/dev/$topic.rst`` file
+ is added with a release note.
+
+* If a commit changes a specific area, such as a module, its commit
+ message should have an ``area:`` prefix on its first line.
+
+* If a commit fixes a tracked issue, its commit message should have
+ a trailing line such as ``Fixes: #00000``.
+
+* Ensure that the MR adds sufficient documentation and test cases.
+
+* Ensure that the MR has been tested sufficiently. Typically it should
+ be staged for nightly testing with ``Do: stage``. Then manually
+ review the `CMake CDash Page`_ to verify that no regressions were
+ introduced. (Learn to tolerate spurious failures due to idiosyncrasies
+ of various nightly builders.)
+
+* Ensure that the MR targets the ``master`` branch. A MR intended for
+ the ``release`` branch should be based on ``release`` but still target
+ ``master``. Use the above-mentioned ``Backport: release`` line to tell
+ ``Do: merge`` to merge to both. If a MR is merged without the backport
+ line, a maintainer may still merge the MR topic to ``release`` manually.
+
+Maintain Current Release
+========================
+
+The ``release`` branch is used to maintain the current release or release
+candidate. The branch is published with no version number but maintained
+using a local branch named ``release-$ver``, where ``$ver`` is the version
+number of the current release in the form ``$major.$minor``. It is always
+merged into ``master`` before publishing.
+
+To merge an open MR to the ``release`` branch, edit its description to
+use the ``Backport: release`` line mentioned above and then ``Do: merge``
+normally. To update the ``release`` branch manually (e.g. to merge a
+``$topic`` branch that was merged without the backport line), use the
+following procedure.
+
+Before merging a ``$topic`` branch into ``release``, verify that the
+``$topic`` branch has already been merged to ``master`` via the usual
+``Do: merge`` process. Then, to merge the ``$topic`` branch into
+``release``, start by creating the local branch:
+
+.. code-block:: shell
+
+ git fetch origin
+ git checkout -b release-$ver origin/release
+
+Merge the ``$topic`` branch into the local ``release-$ver`` branch, making
+sure to include a ``Merge-request: !xxxx`` footer in the commit message:
+
+.. code-block:: shell
+
+ git merge --no-ff $topic
+
+Merge the ``release-$ver`` branch to ``master``:
+
+.. code-block:: shell
+
+ git checkout master
+ git pull
+ git merge --no-ff release-$ver
+
+Review new ancestry to ensure nothing unexpected was merged to either branch:
+
+.. code-block:: shell
+
+ git log --graph --boundary origin/master..master
+ git log --graph --boundary origin/release..release-$ver
+
+Publish both ``master`` and ``release`` simultaneously:
+
+.. code-block:: shell
+
+ git push --atomic origin master release-$ver:release
+
+.. _`CMake Review Process`: review.rst
+.. _`CMake CDash Page`: https://open.cdash.org/index.php?project=CMake
+
+Create Release Version
+======================
+
+When the ``release`` branch is ready to create a new release, follow the
+steps in the above `Maintain Current Release`_ section to checkout a local
+``release-$ver`` branch, where ``$ver`` is the version number of the
+current release in the form ``$major.$minor``.
+
+Edit ``Source/CMakeVersion.cmake`` to set the full version:
+
+.. code-block:: cmake
+
+ # CMake version number components.
+ set(CMake_VERSION_MAJOR $major)
+ set(CMake_VERSION_MINOR $minor)
+ set(CMake_VERSION_PATCH $patch)
+ #set(CMake_VERSION_RC $rc) # uncomment for release candidates
+
+In the following we use the placeholder ``$fullver`` for the full version
+number of the new release with the form ``$major.$minor.$patch[-rc$rc]``.
+If the version is not a release candidate, comment out the RC version
+component above and leave off the ``-rc$rc`` suffix from ``$fullver``.
+
+Commit the release version with the **exact** message ``CMake $fullver``:
+
+.. code-block:: shell
+
+ git commit -m "CMake $fullver"
+
+Tag the release using an annotated tag with the same message as the
+commit and named with the **exact** form ``v$fullver``:
+
+.. code-block:: shell
+
+ git tag -s -m "CMake $fullver" "v$fullver"
+
+Follow the steps in the above `Maintain Current Release`_ section to
+merge the ``release-$ver`` branch into ``master`` and publish both.
+
+Branch a New Release
+====================
+
+This section covers how to start a new ``release`` branch for a major or
+minor version bump (patch releases remain on their existing branch).
+
+In the following we use the placeholder ``$ver`` to represent the
+version number of the new release with the form ``$major.$minor``,
+and ``$prev`` to represent the version number of the prior release.
+
+Review Prior Release
+--------------------
+
+Review the history around the prior release branch:
+
+.. code-block:: shell
+
+ git log --graph --boundary \
+ ^$(git rev-list --grep="Merge topic 'doc-.*-relnotes'" -n 1 master)~1 \
+ $(git rev-list --grep="Begin post-.* development" -n 1 master) \
+ $(git tag --list *-rc1| tail -1)
+
+Consolidate Release Notes
+-------------------------
+
+Starting from a clean work tree on ``master``, create a topic branch to
+use for consolidating the release notes:
+
+.. code-block:: shell
+
+ git checkout -b doc-$ver-relnotes
+
+Run the `consolidate-relnotes.bash`_ script:
+
+.. code-block:: shell
+
+ Utilities/Release/consolidate-relnotes.bash $ver $prev
+
+.. _`consolidate-relnotes.bash`: ../../Utilities/Release/consolidate-relnotes.bash
+
+This moves notes from the ``Help/release/dev/*.rst`` files into a versioned
+``Help/release/$ver.rst`` file and updates ``Help/release/index.rst`` to
+link to the new document. Commit the changes with a message such as::
+
+ Help: Consolidate $ver release notes
+
+ Run the `Utilities/Release/consolidate-relnotes.bash` script to move
+ notes from `Help/release/dev/*` into `Help/release/$ver.rst`.
+
+Manually edit ``Help/release/$ver.rst`` to add section headers, organize
+the notes, and revise wording. Then commit with a message such as::
+
+ Help: Organize and revise $ver release notes
+
+ Add section headers similar to the $prev release notes and move each
+ individual bullet into an appropriate section. Revise a few bullets.
+
+Update Sphinx ``versionadded`` directives in documents added since
+the previous release by running the `update_versions.py`_ script:
+
+.. code-block:: shell
+
+ Utilities/Sphinx/update_versions.py --since v$prev.0 --overwrite
+
+.. _`update_versions.py`: ../../Utilities/Sphinx/update_versions.py
+
+Commit the changes with a message such as::
+
+ Help: Update Sphinx versionadded directives for $ver release
+
+ Run the script:
+
+ Utilities/Sphinx/update_versions.py --since v$prev.0 --overwrite
+
+Open a merge request with the ``doc-$ver-relnotes`` branch for review
+and integration. Further steps may proceed after this has been merged
+to ``master``.
+
+Update 'release' Branch
+-----------------------
+
+Starting from a clean work tree on ``master``, create a new ``release-$ver``
+branch locally:
+
+.. code-block:: shell
+
+ git checkout -b release-$ver origin/master
+
+Remove the development branch release note infrastructure:
+
+.. code-block:: shell
+
+ git rm Help/release/dev/0-sample-topic.rst
+ sed -i '/^\.\. include:: dev.txt/ {N;d}' Help/release/index.rst
+
+Commit with a message such as::
+
+ Help: Drop development topic notes to prepare release
+
+ Release versions do not have the development topic section of
+ the CMake Release Notes index page.
+
+Update ``.gitlab-ci.yml`` to drop the ``upload:`` jobs from the
+packaging pipeline by renaming them to start in ``.``:
+
+.. code-block:: shell
+
+ sed -i 's/^upload:/.upload:/' .gitlab-ci.yml
+
+Commit with a message such as::
+
+ gitlab-ci: Drop package pipeline upload jobs for release branch
+
+ The package pipeline for release versions should not upload packages
+ automatically to our archive of nightly development versions.
+
+Update ``Source/CMakeVersion.cmake`` to set the version to
+``$major.$minor.0-rc0``:
+
+.. code-block:: cmake
+
+ # CMake version number components.
+ set(CMake_VERSION_MAJOR $major)
+ set(CMake_VERSION_MINOR $minor)
+ set(CMake_VERSION_PATCH 0)
+ set(CMake_VERSION_RC 0)
+
+Update uses of ``DEVEL_CMAKE_VERSION`` in the source tree to mention the
+actual version number:
+
+.. code-block:: shell
+
+ $EDITOR $(git grep -l DEVEL_CMAKE_VERSION)
+
+Commit with a message such as::
+
+ Begin $ver release versioning
+
+Merge the ``release-$ver`` branch to ``master``:
+
+.. code-block:: shell
+
+ git checkout master
+ git pull
+ git merge --no-ff release-$ver
+
+Begin post-release development by restoring the development branch release
+note infrastructure, the nightly package pipeline upload jobs, and
+the version date from ``origin/master``:
+
+.. code-block:: shell
+
+ git checkout origin/master -- \
+ Source/CMakeVersion.cmake Help/release/dev/0-sample-topic.rst
+ sed -i $'/^Releases/ i\\\n.. include:: dev.txt\\\n' Help/release/index.rst
+ sed -i 's/^\.upload:/upload:/' .gitlab-ci.yml
+
+Update ``Source/CMakeVersion.cmake`` to set the version to
+``$major.$minor.$date``:
+
+.. code-block:: cmake
+
+ # CMake version number components.
+ set(CMake_VERSION_MAJOR $major)
+ set(CMake_VERSION_MINOR $minor)
+ set(CMake_VERSION_PATCH $date)
+ #set(CMake_VERSION_RC 0)
+
+Commit with a message such as::
+
+ Begin post-$ver development
+
+Push the update to the ``master`` and ``release`` branches:
+
+.. code-block:: shell
+
+ git push --atomic origin master release-$ver:release
+
+Announce 'release' Branch
+-------------------------
+
+Post a topic to the `CMake Discourse Forum Development Category`_
+announcing that post-release development is open::
+
+ I've branched `release` for $ver. The repository is now open for
+ post-$ver development. Please rebase open merge requests on `master`
+ before staging or merging.
+
+.. _`CMake Discourse Forum Development Category`: https://discourse.cmake.org/c/development
+
+Initial Post-Release Development
+--------------------------------
+
+Deprecate policies more than 8 release series old by updating the
+policy range check in ``cmMakefile::SetPolicy``.
+Commit with a message such as::
+
+ Add deprecation warnings for policies CMP#### and below
+
+ The OLD behaviors of all policies are deprecated, but only by
+ documentation. Add an explicit deprecation diagnostic for policies
+ introduced in CMake $OLDVER and below to encourage projects to port
+ away from setting policies to OLD.
+
+Update the ``cmake_policy`` version range generated by ``install(EXPORT)``
+in ``cmExportFileGenerator::GeneratePolicyHeaderCode`` to end at the
+previous release. We use one release back since we now know all the
+policies added for that version. Commit with a message such as::
+
+ export: Increase maximum policy version in exported files to $prev
+
+ The files generatd by `install(EXPORT)` and `export()` commands
+ are known to work with policies as of CMake $prev, so enable them
+ in sufficiently new CMake versions.
+
+Update the ``cmake_minimum_required`` version range in CMake itself:
+
+* ``CMakeLists.txt``
+* ``Utilities/Doxygen/CMakeLists.txt``
+* ``Utilities/Sphinx/CMakeLists.txt``
+
+to end in the previous release. Commit with a message such as::
+
+ Configure CMake itself with policies through CMake $prev
diff --git a/Help/dev/review.rst b/Help/dev/review.rst
new file mode 100644
index 0000000..10ff87b
--- /dev/null
+++ b/Help/dev/review.rst
@@ -0,0 +1,541 @@
+CMake Review Process
+********************
+
+The following documents the process for reviewing and integrating changes.
+See `CONTRIBUTING.rst`_ for instructions to contribute changes.
+See documentation on `CMake Development`_ for more information.
+
+.. _`CONTRIBUTING.rst`: ../../CONTRIBUTING.rst
+.. _`CMake Development`: README.rst
+
+.. contents:: The review process consists of the following steps:
+
+Merge Request
+=============
+
+A user initiates the review process for a change by pushing a *topic
+branch* to his or her own fork of the `CMake Repository`_ on GitLab and
+creating a *merge request* ("MR"). The new MR will appear on the
+`CMake Merge Requests Page`_. The rest of the review and integration
+process is managed by the merge request page for the change.
+
+During the review process, the MR submitter should address review comments
+or test failures by updating the MR with a (force-)push of the topic
+branch. The update initiates a new round of review.
+
+We recommend that users enable the "Remove source branch when merge
+request is accepted" option when creating the MR or by editing it.
+This will cause the MR topic branch to be automatically removed from
+the user's fork during the `Merge`_ step.
+
+.. _`CMake Merge Requests Page`: https://gitlab.kitware.com/cmake/cmake/-/merge_requests
+.. _`CMake Repository`: https://gitlab.kitware.com/cmake/cmake
+
+Workflow Status
+---------------
+
+`CMake GitLab Project Developers`_ may set one of the following labels
+in GitLab to track the state of a MR:
+
+* ``workflow:wip`` indicates that the MR needs additional updates from
+ the MR submitter before further review. Use this label after making
+ comments that require such updates.
+
+* ``workflow:in-review`` indicates that the MR awaits feedback from a
+ human reviewer or from `Topic Testing`_. Use this label after making
+ comments requesting such feedback.
+
+* ``workflow:nightly-testing`` indicates that the MR awaits results
+ of `Integration Testing`_. Use this label after making comments
+ requesting such staging.
+
+* ``workflow:expired`` indicates that the MR has been closed due
+ to a period of inactivity. See the `Expire`_ step. Use this label
+ after closing a MR for this reason.
+
+* ``workflow:external-discussion`` indicates that the MR has been closed
+ pending discussion elsewhere. See the `External Discussion`_ step.
+ Use this label after closing a MR for this reason.
+
+The workflow status labels are intended to be mutually exclusive,
+so please remove any existing workflow label when adding one.
+
+.. _`CMake GitLab Project Developers`: https://gitlab.kitware.com/cmake/cmake/-/settings/members
+
+Robot Review
+============
+
+The "Kitware Robot" (``@kwrobot``) automatically performs basic checks on
+the commits proposed in a MR. If all is well the robot silently reports
+a successful "build" status to GitLab. Otherwise the robot posts a comment
+with its diagnostics. **A topic may not be merged until the automatic
+review succeeds.**
+
+Note that the MR submitter is expected to address the robot's comments by
+*rewriting* the commits named by the robot's diagnostics (e.g., via
+``git rebase -i``). This is because the robot checks each commit individually,
+not the topic as a whole. This is done in order to ensure that commits in the
+middle of a topic do not, for example, add a giant file which is then later
+removed in the topic.
+
+Automatic Check
+---------------
+
+The automatic check is repeated whenever the topic branch is updated.
+One may explicitly request a re-check by adding a comment with the
+following command among the `comment trailing lines`_::
+
+ Do: check
+
+``@kwrobot`` will add an award emoji to the comment to indicate that it
+was processed and also run its checks again.
+
+Automatic Format
+----------------
+
+The automatic check will reject commits introducing source code not
+formatted according to ``clang-format``. One may ask the robot to
+automatically rewrite the MR topic branch with expected formatting
+by adding a comment with the following command among the
+`comment trailing lines`_::
+
+ Do: reformat
+
+``@kwrobot`` will add an award emoji to the comment to indicate that it
+was processed and also rewrite the MR topic branch and force-push an
+updated version with every commit formatted as expected by the check.
+
+Human Review
+============
+
+Anyone is welcome to review merge requests and make comments!
+
+Please make comments directly on the MR page Discussion and Changes tabs
+and not on individual commits. Comments on a commit may disappear
+from the MR page if the commit is rewritten in response.
+
+Reviewers may add comments providing feedback or to acknowledge their
+approval. Lines of specific forms will be extracted during the `merge`_
+step and included as trailing lines of the generated merge commit message.
+Each review comment consists of up to two parts which must be specified
+in the following order: `comment body`_, then `comment trailing lines`_.
+Each part is optional, but they must be specified in this order.
+
+Comment Body
+------------
+
+The body of a comment may be free-form `GitLab Flavored Markdown`_.
+See GitLab documentation on `Special GitLab References`_ to add links to
+things like issues, commits, or other merge requests (even across projects).
+
+Additionally, a line in the comment body may start with one of the
+following votes:
+
+* ``-1`` or ``:-1:`` indicates "the change is not ready for integration".
+
+* ``+1`` or ``:+1:`` indicates "I like the change".
+ This adds an ``Acked-by:`` trailer to the `merge`_ commit message.
+
+* ``+2`` indicates "the change is ready for integration".
+ This adds a ``Reviewed-by:`` trailer to the `merge`_ commit message.
+
+* ``+3`` indicates "I have tested the change and verified it works".
+ This adds a ``Tested-by:`` trailer to the `merge`_ commit message.
+
+.. _`GitLab Flavored Markdown`: https://gitlab.kitware.com/help/user/markdown.md
+.. _`Special GitLab References`: https://gitlab.kitware.com/help/user/markdown.md#special-gitlab-references
+
+Comment Trailing Lines
+----------------------
+
+Zero or more *trailing* lines in the last section of a comment may appear
+with the form ``Key: Value``. The first such line should be separated
+from a preceding `comment body`_ by a blank line. Any key-value pair(s)
+may be specified for human reference. A few specific keys have meaning to
+``@kwrobot`` as follows.
+
+Comment Trailer Votes
+^^^^^^^^^^^^^^^^^^^^^
+
+Among the `comment trailing lines`_ one may cast a vote using one of the
+following pairs followed by nothing but whitespace before the end of the line:
+
+* ``Rejected-by: me`` indicates "the change is not ready for integration".
+* ``Acked-by: me`` indicates "I like the change".
+ This adds an ``Acked-by:`` trailer to the `merge`_ commit message.
+* ``Reviewed-by: me`` indicates "the change is ready for integration".
+ This adds a ``Reviewed-by:`` trailer to the `merge`_ commit message.
+* ``Tested-by: me`` indicates "I have tested the change and verified it works".
+ This adds a ``Tested-by:`` trailer to the `merge`_ commit message.
+
+Each ``me`` reference may instead be an ``@username`` reference or a full
+``Real Name <user@domain>`` reference to credit someone else for performing
+the review. References to ``me`` and ``@username`` will automatically be
+transformed into a real name and email address according to the user's
+GitLab account profile.
+
+Comment Trailer Commands
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Among the `comment trailing lines`_ authorized users may issue special
+commands to ``@kwrobot`` using the form ``Do: ...``:
+
+* ``Do: check`` explicitly re-runs the robot `Automatic Check`_.
+* ``Do: reformat`` rewrites the MR topic for `Automatic Format`_.
+* ``Do: test`` submits the MR for `Topic Testing`_.
+* ``Do: stage`` submits the MR for `Integration Testing`_.
+* ``Do: merge`` submits the MR for `Merge`_.
+
+See the corresponding sections for details on permissions and options
+for each command.
+
+Commit Messages
+---------------
+
+Part of the human review is to check that each commit message is appropriate.
+The first line of the message should begin with one or two words indicating the
+area the commit applies to, followed by a colon and then a brief summary.
+Committers should aim to keep this first line short. Any subsequent lines
+should be separated from the first by a blank line and provide relevant, useful
+information.
+
+Area Prefix on Commit Messages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The appropriateness of the initial word describing the area the commit applies
+to is not something the automatic robot review can judge, so it is up to the
+human reviewer to confirm that the area is specified and that it is
+appropriate. Good area words include the module name the commit is primarily
+fixing, the main C++ source file being edited, ``Help`` for generic
+documentation changes or a feature or functionality theme the changes apply to
+(e.g. ``server`` or ``Autogen``). Examples of suitable first lines of a commit
+message include:
+
+* ``Help: Fix example in cmake-buildsystem(7) manual``
+* ``FindBoost: Add support for 1.64``
+* ``Autogen: Extended mocInclude tests``
+* ``cmLocalGenerator: Explain standard flag selection logic in comments``
+
+Referencing Issues in Commit Messages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If the commit fixes a particular reported issue, this information should
+ideally also be part of the commit message. The recommended way to do this is
+to place a line at the end of the message in the form ``Fixes: #xxxxx`` where
+``xxxxx`` is the GitLab issue number and to separate it from the rest of the
+text by a blank line. For example::
+
+ Help: Fix FooBar example robustness issue
+
+ FooBar supports option X, but the example provided
+ would not work if Y was also specified.
+
+ Fixes: #12345
+
+GitLab will automatically create relevant links to the merge request and will
+close the issue when the commit is merged into master. GitLab understands a few
+other synonyms for ``Fixes`` and allows much more flexible forms than the
+above, but committers should aim for this format for consistency. Note that
+such details can alternatively be specified in the merge request description.
+
+Referencing Commits in Commit Messages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The preferred form for references to other commits is
+``commit <shorthash> (<subject>, <date>)``, where:
+
+* ``<shorthash>``:
+ The abbreviated hash of the commit.
+
+* ``<subject>``:
+ The first line of the commit message.
+
+* ``<date>``:
+ The author date of the commit, in its original time zone, formatted as
+ ``CCYY-MM-DD``. ``git-log(1)`` shows the original time zone by default.
+
+This may be generated with ``git show -s --pretty=reference <commit>`` with
+Git 2.25 and newer. Older versions of Git can generate the same format via
+``git show -s --date=short --pretty="format:%h (%s, %ad)" <commit>``.
+
+If the commit is a fix for the mentioned commit, consider using a ``Fixes:``
+trailer in the commit message with the specified format. This trailer should
+not be word-wrapped. Note that if there is also an issue for what is being
+fixed, it is preferable to link to the issue instead.
+
+If relevant, add the first release tag of CMake containing the commit after
+the ``<date>``, i.e., ``commit <shorthash> (<subject>, <date>, <tag>)``.
+Or, use the output of ``git describe --contains <commit>`` as the ``<tag>``.
+
+Alternatively, the full commit ``<hash>`` may be used.
+
+Revising Commit Messages
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Reviewers are encouraged to ask the committer to amend commit messages to
+follow these guidelines, but prefer to focus on the changes themselves as a
+first priority. Maintainers will also make a check of commit messages before
+merging.
+
+Topic Testing
+=============
+
+CMake uses `GitLab CI`_ to test merge requests, configured by the top-level
+``.gitlab-ci.yml`` file. Results may be seen both on the merge request's
+pipeline page and on the `CMake CDash Page`_. Filtered CDash results
+showing just the pipeline's jobs can be reached by selecting the ``cdash``
+job in the ``External`` stage of the pipeline.
+
+Lint and documentation build jobs run automatically after every push.
+Heavier jobs require a manual trigger to run:
+
+* Merge request authors may visit their merge request's pipeline and click the
+ "Play" button on one or more jobs manually. If the merge request has the
+ "Allow commits from members who can merge to the target branch" check box
+ enabled, CMake maintainers may use the "Play" button too.
+
+* `CMake GitLab Project Developers`_ may trigger CI on a merge request by
+ adding a comment with a command among the `comment trailing lines`_::
+
+ Do: test
+
+ ``@kwrobot`` will add an award emoji to the comment to indicate that it
+ was processed and also trigger all manual jobs in the merge request's
+ pipeline.
+
+ The ``Do: test`` command accepts the following arguments:
+
+ * ``--named <regex>``, ``-n <regex>``: Trigger jobs matching ``<regex>``
+ anywhere in their name. Job names may be seen on the merge request's
+ pipeline page.
+ * ``--stage <stage>``, ``-s <stage>``: Only affect jobs in a given stage.
+ Stage names may be seen on the merge request's pipeline page. Note that
+ the names are determined by what is in the ``.gitlab-ci.yml`` file and may
+ be capitalized in the web page, so lowercasing the webpage's display name
+ for stages may be required.
+ * ``--action <action>``, ``-a <action>``: The action to perform on the jobs.
+ Possible actions:
+
+ * ``manual`` (the default): Start jobs awaiting manual interaction.
+ * ``unsuccessful``: Start or restart jobs which have not completed
+ successfully.
+ * ``failed``: Restart jobs which have completed, but without success.
+ * ``completed``: Restart all completed jobs.
+
+If the merge request topic branch is updated by a push, a new manual trigger
+using one of the above methods is needed to start CI again.
+
+.. _`GitLab CI`: https://gitlab.kitware.com/help/ci/README.md
+.. _`CMake CDash Page`: https://open.cdash.org/index.php?project=CMake
+
+Integration Testing
+===================
+
+The above `topic testing`_ tests the MR topic independent of other
+merge requests and on only a few key platforms and configurations.
+The `CMake Testing Process`_ also has a large number of machines
+provided by Kitware and generous volunteers that cover nearly all
+supported platforms, generators, and configurations. In order to
+avoid overwhelming these resources, they do not test every MR
+individually. Instead, these machines follow an *integration branch*,
+run tests on a nightly basis (or continuously during the day), and
+post to the `CMake CDash Page`_. Some follow ``master``. Most follow
+a special integration branch, the *topic stage*.
+
+The topic stage is a special branch maintained by the "Kitware Robot"
+(``@kwrobot``). It consists of the head of the MR target integration
+branch (e.g. ``master``) branch followed by a sequence of merges each
+integrating changes from an open MR that has been staged for integration
+testing. Each time the target integration branch is updated the stage
+is rebuilt automatically by merging the staged MR topics again.
+The branch is stored in the upstream repository by special refs:
+
+* ``refs/stage/master/head``: The current topic stage branch.
+ This is used by continuous builds that report to CDash.
+* ``refs/stage/master/nightly/latest``: Topic stage as of 1am UTC each night.
+ This is used by most nightly builds that report to CDash.
+* ``refs/stage/master/nightly/<yyyy>/<mm>/<dd>``: Topic stage as of 1am UTC
+ on the date specified. This is used for historical reference.
+
+`CMake GitLab Project Developers`_ may stage a MR for integration testing
+by adding a comment with a command among the `comment trailing lines`_::
+
+ Do: stage
+
+``@kwrobot`` will add an award emoji to the comment to indicate that it
+was processed and also attempt to add the MR topic branch to the topic
+stage. If the MR cannot be added (e.g. due to conflicts) the robot will
+post a comment explaining what went wrong.
+
+Once a MR has been added to the topic stage it will remain on the stage
+until one of the following occurs:
+
+* The MR topic branch is updated by a push.
+
+* The MR target integration branch (e.g. ``master``) branch is updated
+ and the MR cannot be merged into the topic stage again due to conflicts.
+
+* A developer or the submitter posts an explicit ``Do: unstage`` command.
+ This is useful to remove a MR from the topic stage when one is not ready
+ to push an update to the MR topic branch. It is unnecessary to explicitly
+ unstage just before or after pushing an update because the push will cause
+ the MR to be unstaged automatically.
+
+* The MR is closed.
+
+* The MR is merged.
+
+Once a MR has been removed from the topic stage a new ``Do: stage``
+command is needed to stage it again.
+
+.. _`CMake Testing Process`: testing.rst
+
+Resolve
+=======
+
+The workflow used by the CMake project supports a number of different
+ways in which a MR can be moved to a resolved state. In addition to
+the conventional practices of merging or closing a MR without merging it,
+a MR can also be moved to a quasi-resolved state pending some action.
+This may involve moving discussion to an issue or it may be the result of
+an extended period of inactivity. These quasi-resolved states are used
+to help manage the relatively large number of MRs the project receives
+and are not an indication of the changes being rejected. The following
+sections explain the different resolutions a MR may be given.
+
+Merge
+-----
+
+Once review has concluded that the MR topic is ready for integration,
+`CMake GitLab Project Masters`_ may merge the topic by adding a comment
+with a command among the `comment trailing lines`_::
+
+ Do: merge
+
+``@kwrobot`` will add an award emoji to the comment to indicate that it
+was processed and also attempt to merge the MR topic branch to the MR
+target integration branch (e.g. ``master``). If the MR cannot be merged
+(e.g. due to conflicts) the robot will post a comment explaining what
+went wrong. If the MR is merged the robot will also remove the source
+branch from the user's fork if the corresponding MR option was checked.
+
+The robot automatically constructs a merge commit message of the following
+form::
+
+ Merge topic 'mr-topic-branch-name'
+
+ 00000000 commit message subject line (one line per commit)
+
+ Acked-by: Kitware Robot <kwrobot@kitware.com>
+ Merge-request: !0000
+
+Mention of the commit short sha1s and MR number helps GitLab link the
+commits back to the merge request and indicates when they were merged.
+The ``Acked-by:`` trailer shown indicates that `Robot Review`_ passed.
+Additional ``Acked-by:``, ``Reviewed-by:``, and similar trailers may be
+collected from `Human Review`_ comments that have been made since the
+last time the MR topic branch was updated with a push.
+
+The ``Do: merge`` command accepts the following arguments:
+
+* ``-t <topic>``: substitute ``<topic>`` for the name of the MR topic
+ branch in the constructed merge commit message.
+
+Additionally, ``Do: merge`` extracts configuration from trailing lines
+in the MR description (the following have no effect if used in a MR
+comment instead):
+
+* ``Backport: release[:<commit-ish>]``: merge the topic branch into
+ the ``release`` branch to backport the change. This is allowed
+ only if the topic branch is based on a commit in ``release`` already.
+ If only part of the topic branch should be backported, specify it as
+ ``:<commit-ish>``. The ``<commit-ish>`` may use `git rev-parse`_
+ syntax to reference commits relative to the topic ``HEAD``.
+ See additional `backport instructions`_ for details.
+ For example:
+
+ ``Backport: release``
+ Merge the topic branch head into both ``release`` and ``master``.
+ ``Backport: release:HEAD~1^2``
+ Merge the topic branch head's parent's second parent commit into
+ the ``release`` branch. Merge the topic branch head to ``master``.
+
+* ``Topic-rename: <topic>``: substitute ``<topic>`` for the name of
+ the MR topic branch in the constructed merge commit message.
+ It is also used in merge commits constructed by ``Do: stage``.
+ The ``-t`` option to a ``Do: merge`` command overrides any topic
+ rename set in the MR description.
+
+.. _`CMake GitLab Project Masters`: https://gitlab.kitware.com/cmake/cmake/-/settings/members
+.. _`backport instructions`: https://gitlab.kitware.com/utils/git-workflow/-/wikis/Backport-topics
+.. _`git rev-parse`: https://git-scm.com/docs/git-rev-parse
+
+Close
+-----
+
+If review has concluded that the MR should not be integrated then it
+may be closed through GitLab. This would normally be a final state
+with no expectation that the MR would be re-opened in the future.
+It is also used when a MR is being superseded by another separate one,
+in which case a reference to the new MR should be added to the MR being
+closed.
+
+Expire
+------
+
+If progress on a MR has stalled for a while, it may be closed with a
+``workflow:expired`` label and a comment indicating that the MR has
+been closed due to inactivity (it may also be done where the MR is blocked
+for an extended period by work in a different MR). This is not an
+indication that there is a problem with the MR's content, it is only a
+practical measure to allow the reviewers to focus attention on MRs that
+are actively being worked on. As a guide, the average period of inactivity
+before transitioning a MR to the expired state would be around 2 weeks,
+but this may decrease to 1 week or less when there is a high number of
+open merge requests.
+
+Reviewers would usually provide a message similar to the following when
+resolving a MR as expired::
+
+ Closing for now. @<MR-author> please re-open when ready to continue work.
+
+This is to make it clear to contributors that they are welcome to re-open
+the expired MR when they are ready to return to working on it and moving
+it forward. In the meantime, the MR will appear as ``Closed`` in GitLab,
+but it can be differentiated from permanently closed MRs by the presence
+of the ``workflow:expired`` label.
+
+**NOTE:** Please re-open *before* pushing an update to the MR topic branch
+to ensure GitLab will still act on the association. If changes are pushed
+before re-opening the MR, the reviewer should initiate a ``Do: check`` to
+force GitLab to act on the updates.
+
+External Discussion
+-------------------
+
+In some situations, a series of comments on a MR may develop into a more
+involved discussion, or it may become apparent that there are broader
+discussions that need to take place before the MR can move forward in an
+agreed direction. Such discussions are better suited to GitLab issues
+rather than in a MR because MRs may be superseded by a different MR, or
+the set of changes may evolve to look quite different to the context in
+which the discussions began. When this occurs, reviewers may ask the
+MR author to open an issue to discuss things there and they will transition
+the MR to a resolved state with the label ``workflow:external-discussion``.
+The MR will appear in GitLab as closed, but it can be differentiated from
+permanently closed MRs by the presence of the ``workflow:external-discussion``
+label. Reviewers should leave a message clearly explaining the action
+so that the MR author understands that the MR closure is temporary and
+it is clear what actions need to happen next. The following is an example
+of such a message, but it will usually be necessary to tailor the message
+to the individual situation::
+
+ The desired behavior here looks to be more involved than first thought.
+ Please open an issue so we can discuss the relevant details there.
+ Once the path forward is clear, we can re-open this MR and continue work.
+
+When the discussion in the associated issue runs its course and the way
+forward is clear, the MR can be re-opened again and the
+``workflow:external-discussion`` label removed. Reviewers should ensure
+that the issue created contains a reference to the MR so that GitLab
+provides a cross-reference to link the two.
diff --git a/Help/dev/source.rst b/Help/dev/source.rst
new file mode 100644
index 0000000..9be4451
--- /dev/null
+++ b/Help/dev/source.rst
@@ -0,0 +1,244 @@
+CMake Source Code Guide
+***********************
+
+The following is a guide to the CMake source code for developers.
+See documentation on `CMake Development`_ for more information.
+
+.. _`CMake Development`: README.rst
+
+C++ Code Style
+==============
+
+We use `clang-format`_ version **6.0** to define our style for C++ code in
+the CMake source tree. See the `.clang-format`_ configuration file for our
+style settings. Use the `Utilities/Scripts/clang-format.bash`_ script to
+format source code. It automatically runs ``clang-format`` on the set of
+source files for which we enforce style. The script also has options to
+format only a subset of files, such as those that are locally modified.
+
+.. _`clang-format`: http://clang.llvm.org/docs/ClangFormat.html
+.. _`.clang-format`: ../../.clang-format
+.. _`Utilities/Scripts/clang-format.bash`: ../../Utilities/Scripts/clang-format.bash
+
+C++ Subset Permitted
+====================
+
+CMake requires compiling as C++11 in order to support building on older
+toolchains. However, to facilitate development, some standard library
+features from more recent C++ standards are supported through a compatibility
+layer. These features are defined under the namespace ``cm`` and headers
+are accessible under the ``cm/`` directory. The headers under ``cm/`` can
+be used in place of the standard ones when extended features are needed.
+For example ``<cm/memory>`` can be used in place of ``<memory>``.
+
+Available features are:
+
+* From ``C++14``:
+
+ * ``<cm/iomanip>``:
+ ``cm::quoted``
+
+ * ``<cm/iterator>``:
+ ``cm::make_reverse_iterator``, ``cm::cbegin``, ``cm::cend``,
+ ``cm::rbegin``, ``cm::rend``, ``cm::crbegin``, ``cm::crend``
+
+ * ``<cm/memory>``:
+ ``cm::make_unique``
+
+ * ``<cm/shared_mutex>``:
+ ``cm::shared_lock``
+
+ * ``<cm/type_traits>``:
+ ``cm::enable_if_t``
+
+* From ``C++17``:
+
+ * ``<cm/algorithm>``:
+ ``cm::clamp``
+
+ * ``cm/filesystem>``:
+ ``cm::filesystem::path``
+
+ * ``<cm/iterator>``:
+ ``cm::size``, ``cm::empty``, ``cm::data``
+
+ * ``<cm/optional>``:
+ ``cm::nullopt_t``, ``cm::nullopt``, ``cm::optional``,
+ ``cm::make_optional``, ``cm::bad_optional_access``
+
+ * ``<cm/shared_mutex>``:
+ ``cm::shared_mutex``
+
+ * ``<cm/string_view>``:
+ ``cm::string_view``
+
+ * ``<cm/type_traits>``:
+ ``cm::bool_constant``, ``cm::invoke_result_t``, ``cm::invoke_result``,
+ ``cm::void_t``
+
+ * ``<cm/utility>``:
+ ``cm::in_place_t``, ``cm::in_place``
+
+* From ``C++20``:
+
+ * ``<cm/deque>``:
+ ``cm::erase``, ``cm::erase_if``
+
+ * ``<cm/list>``:
+ ``cm::erase``, ``cm::erase_if``
+
+ * ``<cm/map>`` :
+ ``cm::erase_if``
+
+ * ``<cm/set>`` :
+ ``cm::erase_if``
+
+ * ``<cm/string>``:
+ ``cm::erase``, ``cm::erase_if``
+
+ * ``<cm/unordered_map>``:
+ ``cm::erase_if``
+
+ * ``<cm/unordered_set>``:
+ ``cm::erase_if``
+
+ * ``<cm/vector>``:
+ ``cm::erase``, ``cm::erase_if``
+
+Additionally, some useful non-standard extensions to the C++ standard library
+are available in headers under the directory ``cmext/`` in namespace ``cm``.
+These are:
+
+* ``<cmext/algorithm>``:
+
+ * ``cm::append``:
+ Append elements to a sequential container.
+
+ * ``cm::contains``:
+ Checks if element or key is contained in container.
+
+* ``<cmext/iterator>``:
+
+ * ``cm::is_terator``:
+ Checks if a type is an iterator type.
+
+ * ``cm::is_input_iterator``:
+ Checks if a type is an input iterator type.
+
+ * ``cm::is_range``:
+ Checks if a type is a range type: functions ``std::begin()`` and
+ ``std::end()`` apply.
+
+ * ``cm::is_input_range``:
+ Checks if a type is an input range type: functions ``std::begin()`` and
+ ``std::end()`` apply and return an input iterator.
+
+* ``<cmext/memory>``:
+
+ * ``cm::static_reference_cast``:
+ Apply a ``static_cast`` to a smart pointer.
+
+ * ``cm::dynamic_reference_cast``:
+ Apply a ``dynamic_cast`` to a smart pointer.
+
+* ``<cmext/type_traits>``:
+
+ * ``cm::is_container``:
+ Checks if a type is a container type.
+
+ * ``cm::is_associative_container``:
+ Checks if a type is an associative container type.
+
+ * ``cm::is_unordered_associative_container``:
+ Checks if a type is an unordered associative container type.
+
+ * ``cm::is_sequence_container``:
+ Checks if a type is a sequence container type.
+
+ * ``cm::is_unique_ptr``:
+ Checks if a type is a ``std::unique_ptr`` type.
+
+CMake assumes the compiler supports ``#pragma once``. Use this for all
+hand-written header files.
+
+Dynamic Memory Management
+=========================
+
+To ensure efficient memory management, i.e. no memory leaks, it is required
+to use smart pointers. Any dynamic memory allocation must be handled by a
+smart pointer such as ``std::unique_ptr`` or ``std::shared_ptr``.
+
+It is allowed to pass raw pointers between objects to enable objects sharing.
+A raw pointer **must** not be deleted. Only the object(s) owning the smart
+pointer are allowed to delete dynamically allocated memory.
+
+Third Parties
+=============
+
+To build CMake, some third parties are needed. Under ``Utilities``
+directory, are versions of these third parties which can be used as an
+alternate to the ones provided by the system.
+
+To enable the selection of the third parties between the system and CMake ones,
+in CMake sources, third parties headers must be prefixed by ``cm3p/``
+(for example: ``<cm3p/json/reader.h>``). These wrappers are located under
+``Utilities/cm3p`` directory.
+
+Source Tree Layout
+==================
+
+The CMake source tree is organized as follows.
+
+* ``Auxiliary/``:
+ Shell and editor integration files.
+
+* ``Help/``:
+ Documentation. See the `CMake Documentation Guide`_.
+
+ * ``Help/dev/``:
+ Developer documentation.
+
+ * ``Help/release/dev/``:
+ Release note snippets for development since last release.
+
+* ``Licenses/``:
+ License files for third-party libraries in binary distributions.
+
+* ``Modules/``:
+ CMake language modules installed with CMake.
+
+* ``Packaging/``:
+ Files used for packaging CMake itself for distribution.
+
+* ``Source/``:
+ Source code of CMake itself.
+
+* ``Templates/``:
+ Files distributed with CMake as implementation details for generators,
+ packagers, etc.
+
+* ``Tests/``:
+ The test suite. See `Tests/README.rst`_.
+
+* ``Utilities/``:
+ Scripts, third-party source code.
+
+ * ``Utilities/std/cm``:
+ Support files for various C++ standards.
+
+ * ``Utilities/std/cmext``:
+ Extensions to the C++ STL.
+
+ * ``Utilities/cm3p``:
+ Public headers for third parties needed to build CMake.
+
+ * ``Utilities/Sphinx/``:
+ Sphinx configuration to build CMake user documentation.
+
+ * ``Utilities/Release/``:
+ Scripts used to package CMake itself for distribution on ``cmake.org``.
+ See `Utilities/Release/README.rst`_.
+
+.. _`CMake Documentation Guide`: documentation.rst
+.. _`Tests/README.rst`: ../../Tests/README.rst
+.. _`Utilities/Release/README.rst`: ../../Utilities/Release/README.rst
diff --git a/Help/dev/testing.rst b/Help/dev/testing.rst
new file mode 100644
index 0000000..279e4b2
--- /dev/null
+++ b/Help/dev/testing.rst
@@ -0,0 +1,43 @@
+CMake Testing Process
+*********************
+
+The following documents the process for running integration testing builds.
+See documentation on `CMake Development`_ for more information.
+
+.. _`CMake Development`: README.rst
+
+CMake Dashboard Scripts
+=======================
+
+The *integration testing* step of the `CMake Review Process`_ uses a set of
+testing machines that follow an integration branch on their own schedule to
+drive testing and submit results to the `CMake CDash Page`_. Anyone is
+welcome to provide testing machines in order to help keep support for their
+platforms working.
+
+The `CMake Dashboard Scripts Repository`_ provides CTest scripts to drive
+nightly, continuous, and experimental testing of CMake. Use the following
+commands to set up a new integration testing client:
+
+.. code-block:: console
+
+ $ mkdir -p ~/Dashboards
+ $ cd ~/Dashboards
+ $ git clone https://gitlab.kitware.com/cmake/dashboard-scripts.git CMakeScripts
+ $ cd CMakeScripts
+
+The `cmake_common.cmake`_ script contains comments at the top with
+instructions to set up a testing client. As it instructs, create a
+CTest script with local settings and include ``cmake_common.cmake``.
+
+.. _`CMake Review Process`: review.rst
+.. _`CMake CDash Page`: https://open.cdash.org/index.php?project=CMake
+.. _`CMake Dashboard Scripts Repository`: https://gitlab.kitware.com/cmake/dashboard-scripts
+.. _`cmake_common.cmake`: https://gitlab.kitware.com/cmake/dashboard-scripts/-/blob/master/cmake_common.cmake
+
+Nightly Start Time
+------------------
+
+The ``cmake_common.cmake`` script expects its includer to be run from a
+nightly scheduled task (cron job). Schedule such tasks for sometime after
+``1:00am UTC``, the time at which our nightly testing branches fast-forward.
diff --git a/Help/envvar/ASM_DIALECT.rst b/Help/envvar/ASM_DIALECT.rst
new file mode 100644
index 0000000..c89515e
--- /dev/null
+++ b/Help/envvar/ASM_DIALECT.rst
@@ -0,0 +1,22 @@
+ASM<DIALECT>
+------------
+
+.. include:: ENV_VAR.txt
+
+Preferred executable for compiling a specific dialect of assembly language
+files. ``ASM<DIALECT>`` can be ``ASM``, ``ASM_NASM`` (Netwide Assembler),
+``ASM_MASM`` (Microsoft Assembler) or ``ASM-ATT`` (Assembler AT&T).
+Will only be used by CMake on the first configuration to determine
+``ASM<DIALECT>`` compiler, after which the value for ``ASM<DIALECT>`` is stored
+in the cache as
+:variable:`CMAKE_ASM<DIALECT>_COMPILER <CMAKE_<LANG>_COMPILER>`. For subsequent
+configuration runs, the environment variable will be ignored in favor of
+:variable:`CMAKE_ASM<DIALECT>_COMPILER <CMAKE_<LANG>_COMPILER>`.
+
+.. note::
+ Options that are required to make the compiler work correctly can be included;
+ they can not be changed.
+
+.. code-block:: console
+
+ $ export ASM="custom-compiler --arg1 --arg2"
diff --git a/Help/envvar/ASM_DIALECTFLAGS.rst b/Help/envvar/ASM_DIALECTFLAGS.rst
new file mode 100644
index 0000000..2e1c6d2
--- /dev/null
+++ b/Help/envvar/ASM_DIALECTFLAGS.rst
@@ -0,0 +1,15 @@
+ASM<DIALECT>FLAGS
+-----------------
+
+.. include:: ENV_VAR.txt
+
+Default compilation flags to be used when compiling a specific dialect of an
+assembly language. ``ASM<DIALECT>FLAGS`` can be ``ASMFLAGS``, ``ASM_NASMFLAGS``,
+``ASM_MASMFLAGS`` or ``ASM-ATTFLAGS``. Will only be used by CMake on the
+first configuration to determine ``ASM_<DIALECT>`` default compilation
+flags, after which the value for ``ASM<DIALECT>FLAGS`` is stored in the cache
+as ``CMAKE_ASM<DIALECT>_FLAGS <CMAKE_<LANG>_FLAGS>``. For any configuration
+run (including the first), the environment variable will be ignored, if the
+``CMAKE_ASM<DIALECT>_FLAGS <CMAKE_<LANG>_FLAGS>`` variable is defined.
+
+See also :variable:`CMAKE_ASM<DIALECT>_FLAGS_INIT <CMAKE_<LANG>_FLAGS_INIT>`.
diff --git a/Help/envvar/CC.rst b/Help/envvar/CC.rst
new file mode 100644
index 0000000..1bb8d51
--- /dev/null
+++ b/Help/envvar/CC.rst
@@ -0,0 +1,19 @@
+CC
+--
+
+.. include:: ENV_VAR.txt
+
+Preferred executable for compiling ``C`` language files. Will only be used by
+CMake on the first configuration to determine ``C`` compiler, after which the
+value for ``CC`` is stored in the cache as
+:variable:`CMAKE_C_COMPILER <CMAKE_<LANG>_COMPILER>`. For any configuration run
+(including the first), the environment variable will be ignored if the
+:variable:`CMAKE_C_COMPILER <CMAKE_<LANG>_COMPILER>` variable is defined.
+
+.. note::
+ Options that are required to make the compiler work correctly can be included;
+ they can not be changed.
+
+.. code-block:: console
+
+ $ export CC="custom-compiler --arg1 --arg2"
diff --git a/Help/envvar/CCMAKE_COLORS.rst b/Help/envvar/CCMAKE_COLORS.rst
new file mode 100644
index 0000000..4e76bf8
--- /dev/null
+++ b/Help/envvar/CCMAKE_COLORS.rst
@@ -0,0 +1,36 @@
+CCMAKE_COLORS
+-------------
+
+.. versionadded:: 3.18
+
+Determines what colors are used by the CMake curses interface,
+when run on a terminal that supports colors.
+The syntax follows the same conventions as ``LS_COLORS``;
+that is, a list of key/value pairs separated by ``:``.
+
+Keys are a single letter corresponding to a CMake cache variable type:
+
+- ``s``: A ``STRING``.
+- ``p``: A ``FILEPATH``.
+- ``c``: A value which has an associated list of choices.
+- ``y``: A ``BOOL`` which has a true-like value (e.g. ``ON``, ``YES``).
+- ``n``: A ``BOOL`` which has a false-like value (e.g. ``OFF``, ``NO``).
+
+Values are an integer number that specifies what color to use.
+``0`` is black (you probably don't want to use that).
+Others are determined by your terminal's color support.
+Most (color) terminals will support at least 8 or 16 colors.
+Some will support up to 256 colors. The colors will likely match
+`this chart <https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg>`_,
+although the first 16 colors may match the original
+`CGA color palette <https://en.wikipedia.org/wiki/Color_Graphics_Adapter#Color_palette>`_.
+(Many modern terminal emulators also allow their color palette,
+at least for the first 16 colors, to be configured by the user.)
+
+Note that fairly minimal checking is done for bad colors
+(although a value higher than what curses believes your terminal supports
+will be silently ignored) or bad syntax.
+
+For example::
+
+ CCMAKE_COLORS='s=39:p=220:c=207:n=196:y=46'
diff --git a/Help/envvar/CFLAGS.rst b/Help/envvar/CFLAGS.rst
new file mode 100644
index 0000000..190b4f4
--- /dev/null
+++ b/Help/envvar/CFLAGS.rst
@@ -0,0 +1,13 @@
+CFLAGS
+------
+
+.. include:: ENV_VAR.txt
+
+Default compilation flags to be used when compiling ``C`` files. Will only be
+used by CMake on the first configuration to determine ``CC`` default compilation
+flags, after which the value for ``CFLAGS`` is stored in the cache
+as :variable:`CMAKE_C_FLAGS <CMAKE_<LANG>_FLAGS>`. For any configuration run
+(including the first), the environment variable will be ignored if the
+:variable:`CMAKE_C_FLAGS <CMAKE_<LANG>_FLAGS>` variable is defined.
+
+See also :variable:`CMAKE_C_FLAGS_INIT <CMAKE_<LANG>_FLAGS_INIT>`.
diff --git a/Help/envvar/CMAKE_APPLE_SILICON_PROCESSOR.rst b/Help/envvar/CMAKE_APPLE_SILICON_PROCESSOR.rst
new file mode 100644
index 0000000..adecb72
--- /dev/null
+++ b/Help/envvar/CMAKE_APPLE_SILICON_PROCESSOR.rst
@@ -0,0 +1,13 @@
+CMAKE_APPLE_SILICON_PROCESSOR
+-----------------------------
+
+.. versionadded:: 3.19.2
+
+.. include:: ENV_VAR.txt
+
+On Apple Silicon hosts running macOS, set this environment variable to tell
+CMake what architecture to use for :variable:`CMAKE_HOST_SYSTEM_PROCESSOR`.
+The value must be either ``arm64`` or ``x86_64``.
+
+The :variable:`CMAKE_APPLE_SILICON_PROCESSOR` normal variable, if set,
+overrides this environment variable.
diff --git a/Help/envvar/CMAKE_BUILD_PARALLEL_LEVEL.rst b/Help/envvar/CMAKE_BUILD_PARALLEL_LEVEL.rst
new file mode 100644
index 0000000..dbc589a
--- /dev/null
+++ b/Help/envvar/CMAKE_BUILD_PARALLEL_LEVEL.rst
@@ -0,0 +1,13 @@
+CMAKE_BUILD_PARALLEL_LEVEL
+--------------------------
+
+.. versionadded:: 3.12
+
+.. include:: ENV_VAR.txt
+
+Specifies the maximum number of concurrent processes to use when building
+using the ``cmake --build`` command line
+:ref:`Build Tool Mode <Build Tool Mode>`.
+
+If this variable is defined empty the native build tool's default number is
+used.
diff --git a/Help/envvar/CMAKE_CONFIG_TYPE.rst b/Help/envvar/CMAKE_CONFIG_TYPE.rst
new file mode 100644
index 0000000..168593d
--- /dev/null
+++ b/Help/envvar/CMAKE_CONFIG_TYPE.rst
@@ -0,0 +1,7 @@
+CMAKE_CONFIG_TYPE
+-----------------
+
+.. include:: ENV_VAR.txt
+
+The default build configuration for :ref:`Build Tool Mode` and
+``ctest`` build handler when there is no explicit configuration given.
diff --git a/Help/envvar/CMAKE_EXPORT_COMPILE_COMMANDS.rst b/Help/envvar/CMAKE_EXPORT_COMPILE_COMMANDS.rst
new file mode 100644
index 0000000..9e678be
--- /dev/null
+++ b/Help/envvar/CMAKE_EXPORT_COMPILE_COMMANDS.rst
@@ -0,0 +1,11 @@
+CMAKE_EXPORT_COMPILE_COMMANDS
+-----------------------------
+
+.. versionadded:: 3.17
+
+.. include:: ENV_VAR.txt
+
+The default value for :variable:`CMAKE_EXPORT_COMPILE_COMMANDS` when there
+is no explicit configuration given on the first run while creating a new
+build tree. On later runs in an existing build tree the value persists in
+the cache as :variable:`CMAKE_EXPORT_COMPILE_COMMANDS`.
diff --git a/Help/envvar/CMAKE_GENERATOR.rst b/Help/envvar/CMAKE_GENERATOR.rst
new file mode 100644
index 0000000..3488b04
--- /dev/null
+++ b/Help/envvar/CMAKE_GENERATOR.rst
@@ -0,0 +1,18 @@
+CMAKE_GENERATOR
+---------------
+
+.. versionadded:: 3.15
+
+.. include:: ENV_VAR.txt
+
+Specifies the CMake default generator to use when no generator is supplied
+with ``-G``. If the provided value doesn't name a generator known by CMake,
+the internal default is used. Either way the resulting generator selection
+is stored in the :variable:`CMAKE_GENERATOR` variable.
+
+Some generators may be additionally configured using the environment
+variables:
+
+* :envvar:`CMAKE_GENERATOR_PLATFORM`
+* :envvar:`CMAKE_GENERATOR_TOOLSET`
+* :envvar:`CMAKE_GENERATOR_INSTANCE`
diff --git a/Help/envvar/CMAKE_GENERATOR_INSTANCE.rst b/Help/envvar/CMAKE_GENERATOR_INSTANCE.rst
new file mode 100644
index 0000000..8ca7d80
--- /dev/null
+++ b/Help/envvar/CMAKE_GENERATOR_INSTANCE.rst
@@ -0,0 +1,9 @@
+CMAKE_GENERATOR_INSTANCE
+------------------------
+
+.. versionadded:: 3.15
+
+.. include:: ENV_VAR.txt
+
+Default value for :variable:`CMAKE_GENERATOR_INSTANCE` if no Cache entry is
+present. This value is only applied if :envvar:`CMAKE_GENERATOR` is set.
diff --git a/Help/envvar/CMAKE_GENERATOR_PLATFORM.rst b/Help/envvar/CMAKE_GENERATOR_PLATFORM.rst
new file mode 100644
index 0000000..b039845
--- /dev/null
+++ b/Help/envvar/CMAKE_GENERATOR_PLATFORM.rst
@@ -0,0 +1,10 @@
+CMAKE_GENERATOR_PLATFORM
+------------------------
+
+.. versionadded:: 3.15
+
+.. include:: ENV_VAR.txt
+
+Default value for :variable:`CMAKE_GENERATOR_PLATFORM` if no Cache entry
+is present and no value is specified by :manual:`cmake(1)` ``-A`` option.
+This value is only applied if :envvar:`CMAKE_GENERATOR` is set.
diff --git a/Help/envvar/CMAKE_GENERATOR_TOOLSET.rst b/Help/envvar/CMAKE_GENERATOR_TOOLSET.rst
new file mode 100644
index 0000000..394dd88
--- /dev/null
+++ b/Help/envvar/CMAKE_GENERATOR_TOOLSET.rst
@@ -0,0 +1,10 @@
+CMAKE_GENERATOR_TOOLSET
+-----------------------
+
+.. versionadded:: 3.15
+
+.. include:: ENV_VAR.txt
+
+Default value for :variable:`CMAKE_GENERATOR_TOOLSET` if no Cache entry
+is present and no value is specified by :manual:`cmake(1)` ``-T`` option.
+This value is only applied if :envvar:`CMAKE_GENERATOR` is set.
diff --git a/Help/envvar/CMAKE_LANG_COMPILER_LAUNCHER.rst b/Help/envvar/CMAKE_LANG_COMPILER_LAUNCHER.rst
new file mode 100644
index 0000000..c384fa1
--- /dev/null
+++ b/Help/envvar/CMAKE_LANG_COMPILER_LAUNCHER.rst
@@ -0,0 +1,12 @@
+CMAKE_<LANG>_COMPILER_LAUNCHER
+------------------------------
+
+.. versionadded:: 3.17
+
+.. include:: ENV_VAR.txt
+
+Default compiler launcher to use for the specified language. Will only be used
+by CMake to initialize the variable on the first configuration. Afterwards, it
+is available through the cache setting of the variable of the same name. For
+any configuration run (including the first), the environment variable will be
+ignored if the :variable:`CMAKE_<LANG>_COMPILER_LAUNCHER` variable is defined.
diff --git a/Help/envvar/CMAKE_MSVCIDE_RUN_PATH.rst b/Help/envvar/CMAKE_MSVCIDE_RUN_PATH.rst
new file mode 100644
index 0000000..77ead4d
--- /dev/null
+++ b/Help/envvar/CMAKE_MSVCIDE_RUN_PATH.rst
@@ -0,0 +1,10 @@
+CMAKE_MSVCIDE_RUN_PATH
+----------------------
+
+.. include:: ENV_VAR.txt
+
+Extra PATH locations for custom commands when using
+:generator:`Visual Studio 9 2008` (or above) generators.
+
+The ``CMAKE_MSVCIDE_RUN_PATH`` environment variable sets the default value for
+the :variable:`CMAKE_MSVCIDE_RUN_PATH` variable if not already explicitly set.
diff --git a/Help/envvar/CMAKE_NO_VERBOSE.rst b/Help/envvar/CMAKE_NO_VERBOSE.rst
new file mode 100644
index 0000000..fe733f8
--- /dev/null
+++ b/Help/envvar/CMAKE_NO_VERBOSE.rst
@@ -0,0 +1,10 @@
+CMAKE_NO_VERBOSE
+----------------
+
+.. versionadded:: 3.14
+
+Disables verbose output from CMake when :envvar:`VERBOSE` environment variable
+is set.
+
+Only your build tool of choice will still print verbose output when you start
+to actually build your project.
diff --git a/Help/envvar/CMAKE_OSX_ARCHITECTURES.rst b/Help/envvar/CMAKE_OSX_ARCHITECTURES.rst
new file mode 100644
index 0000000..ef7d547
--- /dev/null
+++ b/Help/envvar/CMAKE_OSX_ARCHITECTURES.rst
@@ -0,0 +1,10 @@
+CMAKE_OSX_ARCHITECTURES
+-----------------------
+
+.. include:: ENV_VAR.txt
+
+Target specific architectures for macOS.
+
+The ``CMAKE_OSX_ARCHITECTURES`` environment variable sets the default value for
+the :variable:`CMAKE_OSX_ARCHITECTURES` variable. See
+:prop_tgt:`OSX_ARCHITECTURES` for more information.
diff --git a/Help/envvar/CMAKE_PREFIX_PATH.rst b/Help/envvar/CMAKE_PREFIX_PATH.rst
new file mode 100644
index 0000000..276fdd6
--- /dev/null
+++ b/Help/envvar/CMAKE_PREFIX_PATH.rst
@@ -0,0 +1,17 @@
+CMAKE_PREFIX_PATH
+-----------------
+
+.. include:: ENV_VAR.txt
+
+The ``CMAKE_PREFIX_PATH`` environment variable may be set to a list of
+directories specifying installation *prefixes* to be searched by the
+:command:`find_package`, :command:`find_program`, :command:`find_library`,
+:command:`find_file`, and :command:`find_path` commands. Each command will
+add appropriate subdirectories (like ``bin``, ``lib``, or ``include``)
+as specified in its own documentation.
+
+This variable may hold a single prefix or a list of prefixes separated
+by ``:`` on UNIX or ``;`` on Windows (the same as the ``PATH`` environment
+variable convention on those platforms).
+
+See also the :variable:`CMAKE_PREFIX_PATH` CMake variable.
diff --git a/Help/envvar/CSFLAGS.rst b/Help/envvar/CSFLAGS.rst
new file mode 100644
index 0000000..784328a
--- /dev/null
+++ b/Help/envvar/CSFLAGS.rst
@@ -0,0 +1,15 @@
+CSFLAGS
+-------
+
+.. versionadded:: 3.9.2
+
+.. include:: ENV_VAR.txt
+
+Default compilation flags to be used when compiling ``CSharp`` files. Will only be
+used by CMake on the first configuration to determine ``CSharp`` default
+compilation flags, after which the value for ``CSFLAGS`` is stored in the cache
+as :variable:`CMAKE_CSharp_FLAGS <CMAKE_<LANG>_FLAGS>`. For any configuration
+run (including the first), the environment variable will be ignored if the
+:variable:`CMAKE_CSharp_FLAGS <CMAKE_<LANG>_FLAGS>` variable is defined.
+
+See also :variable:`CMAKE_CSharp_FLAGS_INIT <CMAKE_<LANG>_FLAGS_INIT>`.
diff --git a/Help/envvar/CTEST_INTERACTIVE_DEBUG_MODE.rst b/Help/envvar/CTEST_INTERACTIVE_DEBUG_MODE.rst
new file mode 100644
index 0000000..e1991b2
--- /dev/null
+++ b/Help/envvar/CTEST_INTERACTIVE_DEBUG_MODE.rst
@@ -0,0 +1,7 @@
+CTEST_INTERACTIVE_DEBUG_MODE
+----------------------------
+
+.. include:: ENV_VAR.txt
+
+Environment variable that will exist and be set to ``1`` when a test executed
+by :manual:`ctest(1)` is run in interactive mode.
diff --git a/Help/envvar/CTEST_OUTPUT_ON_FAILURE.rst b/Help/envvar/CTEST_OUTPUT_ON_FAILURE.rst
new file mode 100644
index 0000000..d8b4262
--- /dev/null
+++ b/Help/envvar/CTEST_OUTPUT_ON_FAILURE.rst
@@ -0,0 +1,9 @@
+CTEST_OUTPUT_ON_FAILURE
+-----------------------
+
+.. include:: ENV_VAR.txt
+
+Boolean environment variable that controls if the output should be logged for
+failed tests. Set the value to ``1``, ``True``, or ``ON`` to enable output on failure.
+See :manual:`ctest(1)` for more information on controlling output of failed
+tests.
diff --git a/Help/envvar/CTEST_PARALLEL_LEVEL.rst b/Help/envvar/CTEST_PARALLEL_LEVEL.rst
new file mode 100644
index 0000000..fd4936e
--- /dev/null
+++ b/Help/envvar/CTEST_PARALLEL_LEVEL.rst
@@ -0,0 +1,7 @@
+CTEST_PARALLEL_LEVEL
+--------------------
+
+.. include:: ENV_VAR.txt
+
+Specify the number of tests for CTest to run in parallel. See :manual:`ctest(1)`
+for more information on parallel test execution.
diff --git a/Help/envvar/CTEST_PROGRESS_OUTPUT.rst b/Help/envvar/CTEST_PROGRESS_OUTPUT.rst
new file mode 100644
index 0000000..8c29d7d
--- /dev/null
+++ b/Help/envvar/CTEST_PROGRESS_OUTPUT.rst
@@ -0,0 +1,18 @@
+CTEST_PROGRESS_OUTPUT
+---------------------
+
+.. versionadded:: 3.13
+
+.. include:: ENV_VAR.txt
+
+Boolean environment variable that affects how :manual:`ctest <ctest(1)>`
+command output reports overall progress. When set to ``1``, ``TRUE``, ``ON`` or anything
+else that evaluates to boolean true, progress is reported by repeatedly
+updating the same line. This greatly reduces the overall verbosity, but is
+only supported when output is sent directly to a terminal. If the environment
+variable is not set or has a value that evaluates to false, output is reported
+normally with each test having its own start and end lines logged to the
+output.
+
+The ``--progress`` option to :manual:`ctest <ctest(1)>` overrides this
+environment variable if both are given.
diff --git a/Help/envvar/CTEST_USE_LAUNCHERS_DEFAULT.rst b/Help/envvar/CTEST_USE_LAUNCHERS_DEFAULT.rst
new file mode 100644
index 0000000..79dbb79
--- /dev/null
+++ b/Help/envvar/CTEST_USE_LAUNCHERS_DEFAULT.rst
@@ -0,0 +1,6 @@
+CTEST_USE_LAUNCHERS_DEFAULT
+---------------------------
+
+.. include:: ENV_VAR.txt
+
+Initializes the :variable:`CTEST_USE_LAUNCHERS` variable if not already defined.
diff --git a/Help/envvar/CUDAARCHS.rst b/Help/envvar/CUDAARCHS.rst
new file mode 100644
index 0000000..82369cd
--- /dev/null
+++ b/Help/envvar/CUDAARCHS.rst
@@ -0,0 +1,13 @@
+CUDAARCHS
+---------
+
+.. versionadded:: 3.20
+
+.. include:: ENV_VAR.txt
+
+Value used to initialize :variable:`CMAKE_CUDA_ARCHITECTURES` on the first
+configuration if it's not already defined. Subsequent runs will use the value
+stored in the cache.
+
+This is a semicolon-separated list of architectures as described in
+:prop_tgt:`CUDA_ARCHITECTURES`.
diff --git a/Help/envvar/CUDACXX.rst b/Help/envvar/CUDACXX.rst
new file mode 100644
index 0000000..1722128
--- /dev/null
+++ b/Help/envvar/CUDACXX.rst
@@ -0,0 +1,21 @@
+CUDACXX
+-------
+
+.. versionadded:: 3.8
+
+.. include:: ENV_VAR.txt
+
+Preferred executable for compiling ``CUDA`` language files. Will only be used by
+CMake on the first configuration to determine ``CUDA`` compiler, after which the
+value for ``CUDA`` is stored in the cache as
+:variable:`CMAKE_CUDA_COMPILER <CMAKE_<LANG>_COMPILER>`. For any configuration
+run (including the first), the environment variable will be ignored if the
+:variable:`CMAKE_CUDA_COMPILER <CMAKE_<LANG>_COMPILER>` variable is defined.
+
+.. note::
+ Options that are required to make the compiler work correctly can be included;
+ they can not be changed.
+
+.. code-block:: console
+
+ $ export CUDACXX="custom-compiler --arg1 --arg2"
diff --git a/Help/envvar/CUDAFLAGS.rst b/Help/envvar/CUDAFLAGS.rst
new file mode 100644
index 0000000..af577a0
--- /dev/null
+++ b/Help/envvar/CUDAFLAGS.rst
@@ -0,0 +1,15 @@
+CUDAFLAGS
+---------
+
+.. versionadded:: 3.8
+
+.. include:: ENV_VAR.txt
+
+Default compilation flags to be used when compiling ``CUDA`` files. Will only be
+used by CMake on the first configuration to determine ``CUDA`` default
+compilation flags, after which the value for ``CUDAFLAGS`` is stored in the
+cache as :variable:`CMAKE_CUDA_FLAGS <CMAKE_<LANG>_FLAGS>`. For any configuration
+run (including the first), the environment variable will be ignored if
+the :variable:`CMAKE_CUDA_FLAGS <CMAKE_<LANG>_FLAGS>` variable is defined.
+
+See also :variable:`CMAKE_CUDA_FLAGS_INIT <CMAKE_<LANG>_FLAGS_INIT>`.
diff --git a/Help/envvar/CUDAHOSTCXX.rst b/Help/envvar/CUDAHOSTCXX.rst
new file mode 100644
index 0000000..963f9d1
--- /dev/null
+++ b/Help/envvar/CUDAHOSTCXX.rst
@@ -0,0 +1,20 @@
+CUDAHOSTCXX
+-----------
+
+.. versionadded:: 3.8
+
+.. include:: ENV_VAR.txt
+
+Preferred executable for compiling host code when compiling ``CUDA``
+language files. Will only be used by CMake on the first configuration to
+determine ``CUDA`` host compiler, after which the value for ``CUDAHOSTCXX`` is
+stored in the cache as :variable:`CMAKE_CUDA_HOST_COMPILER`. For any
+configuration run (including the first), the environment variable will be
+ignored if the :variable:`CMAKE_CUDA_HOST_COMPILER` variable is defined.
+
+This environment variable is primarily meant for use with projects that
+enable ``CUDA`` as a first-class language.
+
+.. versionadded:: 3.13
+ The :module:`FindCUDA`
+ module will use this variable to initialize its ``CUDA_HOST_COMPILER`` setting.
diff --git a/Help/envvar/CXX.rst b/Help/envvar/CXX.rst
new file mode 100644
index 0000000..61ba5b8
--- /dev/null
+++ b/Help/envvar/CXX.rst
@@ -0,0 +1,19 @@
+CXX
+---
+
+.. include:: ENV_VAR.txt
+
+Preferred executable for compiling ``CXX`` language files. Will only be used by
+CMake on the first configuration to determine ``CXX`` compiler, after which the
+value for ``CXX`` is stored in the cache as
+:variable:`CMAKE_CXX_COMPILER <CMAKE_<LANG>_COMPILER>`. For any configuration
+run (including the first), the environment variable will be ignored if the
+:variable:`CMAKE_CXX_COMPILER <CMAKE_<LANG>_COMPILER>` variable is defined.
+
+.. note::
+ Options that are required to make the compiler work correctly can be included;
+ they can not be changed.
+
+.. code-block:: console
+
+ $ export CXX="custom-compiler --arg1 --arg2"
diff --git a/Help/envvar/CXXFLAGS.rst b/Help/envvar/CXXFLAGS.rst
new file mode 100644
index 0000000..460a347
--- /dev/null
+++ b/Help/envvar/CXXFLAGS.rst
@@ -0,0 +1,13 @@
+CXXFLAGS
+--------
+
+.. include:: ENV_VAR.txt
+
+Default compilation flags to be used when compiling ``CXX`` (C++) files. Will
+only be used by CMake on the first configuration to determine ``CXX`` default
+compilation flags, after which the value for ``CXXFLAGS`` is stored in the cache
+as :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>`. For any configuration run (
+including the first), the environment variable will be ignored if
+the :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` variable is defined.
+
+See also :variable:`CMAKE_CXX_FLAGS_INIT <CMAKE_<LANG>_FLAGS_INIT>`.
diff --git a/Help/envvar/DASHBOARD_TEST_FROM_CTEST.rst b/Help/envvar/DASHBOARD_TEST_FROM_CTEST.rst
new file mode 100644
index 0000000..6a52d64
--- /dev/null
+++ b/Help/envvar/DASHBOARD_TEST_FROM_CTEST.rst
@@ -0,0 +1,8 @@
+DASHBOARD_TEST_FROM_CTEST
+-------------------------
+
+.. include:: ENV_VAR.txt
+
+Environment variable that will exist when a test executed by :manual:`ctest(1)`
+is run in non-interactive mode. The value will be equal to
+:variable:`CMAKE_VERSION`.
diff --git a/Help/envvar/DESTDIR.rst b/Help/envvar/DESTDIR.rst
new file mode 100644
index 0000000..d2144ae
--- /dev/null
+++ b/Help/envvar/DESTDIR.rst
@@ -0,0 +1,21 @@
+DESTDIR
+-------
+
+.. include:: ENV_VAR.txt
+
+On UNIX one can use the ``DESTDIR`` mechanism in order to relocate the
+whole installation. ``DESTDIR`` means DESTination DIRectory. It is
+commonly used by makefile users in order to install software at
+non-default location. It is usually invoked like this:
+
+::
+
+ make DESTDIR=/home/john install
+
+which will install the concerned software using the installation
+prefix, e.g. ``/usr/local`` prepended with the ``DESTDIR`` value which
+finally gives ``/home/john/usr/local``.
+
+WARNING: ``DESTDIR`` may not be used on Windows because installation
+prefix usually contains a drive letter like in ``C:/Program Files``
+which cannot be prepended with some other prefix.
diff --git a/Help/envvar/ENV_VAR.txt b/Help/envvar/ENV_VAR.txt
new file mode 100644
index 0000000..e1e70cd
--- /dev/null
+++ b/Help/envvar/ENV_VAR.txt
@@ -0,0 +1,3 @@
+This is a CMake :ref:`Environment Variable <CMake Language
+Environment Variables>`. Its initial value is taken from
+the calling process environment.
diff --git a/Help/envvar/FC.rst b/Help/envvar/FC.rst
new file mode 100644
index 0000000..70e1475
--- /dev/null
+++ b/Help/envvar/FC.rst
@@ -0,0 +1,20 @@
+FC
+--
+
+.. include:: ENV_VAR.txt
+
+Preferred executable for compiling ``Fortran`` language files. Will only be used
+by CMake on the first configuration to determine ``Fortran`` compiler, after
+which the value for ``Fortran`` is stored in the cache as
+:variable:`CMAKE_Fortran_COMPILER <CMAKE_<LANG>_COMPILER>`. For any
+configuration run (including the first), the environment variable will be
+ignored if the :variable:`CMAKE_Fortran_COMPILER <CMAKE_<LANG>_COMPILER>`
+variable is defined.
+
+.. note::
+ Options that are required to make the compiler work correctly can be included;
+ they can not be changed.
+
+.. code-block:: console
+
+ $ export FC="custom-compiler --arg1 --arg2"
diff --git a/Help/envvar/FFLAGS.rst b/Help/envvar/FFLAGS.rst
new file mode 100644
index 0000000..53bffb6
--- /dev/null
+++ b/Help/envvar/FFLAGS.rst
@@ -0,0 +1,13 @@
+FFLAGS
+------
+
+.. include:: ENV_VAR.txt
+
+Default compilation flags to be used when compiling ``Fortran`` files. Will only
+be used by CMake on the first configuration to determine ``Fortran`` default
+compilation flags, after which the value for ``FFLAGS`` is stored in the cache
+as :variable:`CMAKE_Fortran_FLAGS <CMAKE_<LANG>_FLAGS>`. For any configuration
+run (including the first), the environment variable will be ignored if
+the :variable:`CMAKE_Fortran_FLAGS <CMAKE_<LANG>_FLAGS>` variable is defined.
+
+See also :variable:`CMAKE_Fortran_FLAGS_INIT <CMAKE_<LANG>_FLAGS_INIT>`.
diff --git a/Help/envvar/ISPC.rst b/Help/envvar/ISPC.rst
new file mode 100644
index 0000000..bcd6260
--- /dev/null
+++ b/Help/envvar/ISPC.rst
@@ -0,0 +1,13 @@
+ISPC
+-------
+
+.. versionadded:: 3.19
+
+.. include:: ENV_VAR.txt
+
+Preferred executable for compiling ``ISPC`` language files. Will only be used by
+CMake on the first configuration to determine ``ISPC`` compiler, after which the
+value for ``ISPC`` is stored in the cache as
+:variable:`CMAKE_ISPC_COMPILER <CMAKE_<LANG>_COMPILER>`. For any configuration
+run (including the first), the environment variable will be ignored if the
+:variable:`CMAKE_ISPC_COMPILER <CMAKE_<LANG>_COMPILER>` variable is defined.
diff --git a/Help/envvar/ISPCFLAGS.rst b/Help/envvar/ISPCFLAGS.rst
new file mode 100644
index 0000000..21df037
--- /dev/null
+++ b/Help/envvar/ISPCFLAGS.rst
@@ -0,0 +1,15 @@
+ISPCFLAGS
+---------
+
+.. versionadded:: 3.19
+
+.. include:: ENV_VAR.txt
+
+Default compilation flags to be used when compiling ``ISPC`` files. Will only be
+used by CMake on the first configuration to determine ``ISPC`` default
+compilation flags, after which the value for ``ISPCFLAGS`` is stored in the
+cache as :variable:`CMAKE_ISPC_FLAGS <CMAKE_<LANG>_FLAGS>`. For any configuration
+run (including the first), the environment variable will be ignored if
+the :variable:`CMAKE_ISPC_FLAGS <CMAKE_<LANG>_FLAGS>` variable is defined.
+
+See also :variable:`CMAKE_ISPC_FLAGS_INIT <CMAKE_<LANG>_FLAGS_INIT>`.
diff --git a/Help/envvar/LDFLAGS.rst b/Help/envvar/LDFLAGS.rst
new file mode 100644
index 0000000..816d6ef
--- /dev/null
+++ b/Help/envvar/LDFLAGS.rst
@@ -0,0 +1,12 @@
+LDFLAGS
+-------
+
+.. include:: ENV_VAR.txt
+
+Will only be used by CMake on the first configuration to determine the default
+linker flags, after which the value for ``LDFLAGS`` is stored in the cache
+as :variable:`CMAKE_EXE_LINKER_FLAGS_INIT`,
+:variable:`CMAKE_SHARED_LINKER_FLAGS_INIT`, and
+:variable:`CMAKE_MODULE_LINKER_FLAGS_INIT`. For any configuration run
+(including the first), the environment variable will be ignored if the
+equivalent ``CMAKE_<TYPE>_LINKER_FLAGS_INIT`` variable is defined.
diff --git a/Help/envvar/MACOSX_DEPLOYMENT_TARGET.rst b/Help/envvar/MACOSX_DEPLOYMENT_TARGET.rst
new file mode 100644
index 0000000..662bd03
--- /dev/null
+++ b/Help/envvar/MACOSX_DEPLOYMENT_TARGET.rst
@@ -0,0 +1,10 @@
+MACOSX_DEPLOYMENT_TARGET
+------------------------
+
+.. include:: ENV_VAR.txt
+
+Specify the minimum version of macOS on which the target binaries are
+to be deployed.
+
+The ``MACOSX_DEPLOYMENT_TARGET`` environment variable sets the default value for
+the :variable:`CMAKE_OSX_DEPLOYMENT_TARGET` variable.
diff --git a/Help/envvar/OBJC.rst b/Help/envvar/OBJC.rst
new file mode 100644
index 0000000..2d95806
--- /dev/null
+++ b/Help/envvar/OBJC.rst
@@ -0,0 +1,16 @@
+OBJC
+----
+
+.. versionadded:: 3.16.7
+
+.. include:: ENV_VAR.txt
+
+Preferred executable for compiling ``OBJC`` language files. Will only be used
+by CMake on the first configuration to determine ``OBJC`` compiler, after
+which the value for ``OBJC`` is stored in the cache as
+:variable:`CMAKE_OBJC_COMPILER <CMAKE_<LANG>_COMPILER>`. For any configuration
+run (including the first), the environment variable will be ignored if the
+:variable:`CMAKE_OBJC_COMPILER <CMAKE_<LANG>_COMPILER>` variable is defined.
+
+If ``OBJC`` is not defined, the :envvar:`CC` environment variable will
+be checked instead.
diff --git a/Help/envvar/OBJCXX.rst b/Help/envvar/OBJCXX.rst
new file mode 100644
index 0000000..71286d9
--- /dev/null
+++ b/Help/envvar/OBJCXX.rst
@@ -0,0 +1,16 @@
+OBJCXX
+------
+
+.. versionadded:: 3.16.7
+
+.. include:: ENV_VAR.txt
+
+Preferred executable for compiling ``OBJCXX`` language files. Will only be used
+by CMake on the first configuration to determine ``OBJCXX`` compiler, after
+which the value for ``OBJCXX`` is stored in the cache as
+:variable:`CMAKE_OBJCXX_COMPILER <CMAKE_<LANG>_COMPILER>`. For any configuration
+run (including the first), the environment variable will be ignored if the
+:variable:`CMAKE_OBJCXX_COMPILER <CMAKE_<LANG>_COMPILER>` variable is defined.
+
+If ``OBJCXX`` is not defined, the :envvar:`CXX` environment variable will
+be checked instead.
diff --git a/Help/envvar/PackageName_ROOT.rst b/Help/envvar/PackageName_ROOT.rst
new file mode 100644
index 0000000..0cdd384
--- /dev/null
+++ b/Help/envvar/PackageName_ROOT.rst
@@ -0,0 +1,19 @@
+<PackageName>_ROOT
+------------------
+
+.. versionadded:: 3.12
+
+.. include:: ENV_VAR.txt
+
+Calls to :command:`find_package(<PackageName>)` will search in prefixes
+specified by the ``<PackageName>_ROOT`` environment variable, where
+``<PackageName>`` is the name given to the :command:`find_package` call
+and ``_ROOT`` is literal. For example, ``find_package(Foo)`` will search
+prefixes specified in the ``Foo_ROOT`` environment variable (if set).
+See policy :policy:`CMP0074`.
+
+This variable may hold a single prefix or a list of prefixes separated
+by ``:`` on UNIX or ``;`` on Windows (the same as the ``PATH`` environment
+variable convention on those platforms).
+
+See also the :variable:`<PackageName>_ROOT` CMake variable.
diff --git a/Help/envvar/RC.rst b/Help/envvar/RC.rst
new file mode 100644
index 0000000..8a9324d
--- /dev/null
+++ b/Help/envvar/RC.rst
@@ -0,0 +1,19 @@
+RC
+--
+
+.. include:: ENV_VAR.txt
+
+Preferred executable for compiling ``resource`` files. Will only be used by CMake
+on the first configuration to determine ``resource`` compiler, after which the
+value for ``RC`` is stored in the cache as
+:variable:`CMAKE_RC_COMPILER <CMAKE_<LANG>_COMPILER>`. For any configuration run
+(including the first), the environment variable will be ignored if the
+:variable:`CMAKE_RC_COMPILER <CMAKE_<LANG>_COMPILER>` variable is defined.
+
+.. note::
+ Options that are required to make the compiler work correctly can be included;
+ they can not be changed.
+
+.. code-block:: console
+
+ $ export RC="custom-compiler --arg1 --arg2"
diff --git a/Help/envvar/RCFLAGS.rst b/Help/envvar/RCFLAGS.rst
new file mode 100644
index 0000000..bc43cb2
--- /dev/null
+++ b/Help/envvar/RCFLAGS.rst
@@ -0,0 +1,13 @@
+RCFLAGS
+-------
+
+.. include:: ENV_VAR.txt
+
+Default compilation flags to be used when compiling ``resource`` files. Will
+only be used by CMake on the first configuration to determine ``resource``
+default compilation flags, after which the value for ``RCFLAGS`` is stored in
+the cache as :variable:`CMAKE_RC_FLAGS <CMAKE_<LANG>_FLAGS>`. For any
+configuration run (including the first), the environment variable will be ignored
+if the :variable:`CMAKE_RC_FLAGS <CMAKE_<LANG>_FLAGS>` variable is defined.
+
+See also :variable:`CMAKE_RC_FLAGS_INIT <CMAKE_<LANG>_FLAGS_INIT>`.
diff --git a/Help/envvar/SWIFTC.rst b/Help/envvar/SWIFTC.rst
new file mode 100644
index 0000000..896e156
--- /dev/null
+++ b/Help/envvar/SWIFTC.rst
@@ -0,0 +1,21 @@
+SWIFTC
+------
+
+.. versionadded:: 3.15
+
+.. include:: ENV_VAR.txt
+
+Preferred executable for compiling ``Swift`` language files. Will only be used by
+CMake on the first configuration to determine ``Swift`` compiler, after which the
+value for ``SWIFTC`` is stored in the cache as
+:variable:`CMAKE_Swift_COMPILER <CMAKE_<LANG>_COMPILER>`. For any configuration run
+(including the first), the environment variable will be ignored if the
+:variable:`CMAKE_Swift_COMPILER <CMAKE_<LANG>_COMPILER>` variable is defined.
+
+.. note::
+ Options that are required to make the compiler work correctly can be included;
+ they can not be changed.
+
+.. code-block:: console
+
+ $ export SWIFTC="custom-compiler --arg1 --arg2"
diff --git a/Help/envvar/VERBOSE.rst b/Help/envvar/VERBOSE.rst
new file mode 100644
index 0000000..5911951
--- /dev/null
+++ b/Help/envvar/VERBOSE.rst
@@ -0,0 +1,12 @@
+VERBOSE
+-------
+
+.. versionadded:: 3.14
+
+Activates verbose output from CMake and your build tools of choice when
+you start to actually build your project.
+
+Note that any given value is ignored. It's just checked for existence.
+
+See also :ref:`Build Tool Mode <Build Tool Mode>` and
+:envvar:`CMAKE_NO_VERBOSE` environment variable
diff --git a/Help/generator/Borland Makefiles.rst b/Help/generator/Borland Makefiles.rst
new file mode 100644
index 0000000..c00d00a
--- /dev/null
+++ b/Help/generator/Borland Makefiles.rst
@@ -0,0 +1,4 @@
+Borland Makefiles
+-----------------
+
+Generates Borland makefiles.
diff --git a/Help/generator/CodeBlocks.rst b/Help/generator/CodeBlocks.rst
new file mode 100644
index 0000000..85da715
--- /dev/null
+++ b/Help/generator/CodeBlocks.rst
@@ -0,0 +1,35 @@
+CodeBlocks
+----------
+
+Generates CodeBlocks project files.
+
+Project files for CodeBlocks will be created in the top directory and
+in every subdirectory which features a ``CMakeLists.txt`` file containing
+a :command:`project` call. Additionally a hierarchy of makefiles is generated
+into the build tree.
+The appropriate make program can build the
+project through the default ``all`` target. An ``install`` target is
+also provided.
+
+.. versionadded:: 3.10
+ The :variable:`CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES` variable may
+ be set to ``ON`` to exclude any files which are located outside of
+ the project root directory.
+
+This "extra" generator may be specified as:
+
+``CodeBlocks - MinGW Makefiles``
+ Generate with :generator:`MinGW Makefiles`.
+
+``CodeBlocks - NMake Makefiles``
+ Generate with :generator:`NMake Makefiles`.
+
+``CodeBlocks - NMake Makefiles JOM``
+ .. versionadded:: 3.8
+ Generate with :generator:`NMake Makefiles JOM`.
+
+``CodeBlocks - Ninja``
+ Generate with :generator:`Ninja`.
+
+``CodeBlocks - Unix Makefiles``
+ Generate with :generator:`Unix Makefiles`.
diff --git a/Help/generator/CodeLite.rst b/Help/generator/CodeLite.rst
new file mode 100644
index 0000000..4f276df
--- /dev/null
+++ b/Help/generator/CodeLite.rst
@@ -0,0 +1,30 @@
+CodeLite
+----------
+
+Generates CodeLite project files.
+
+Project files for CodeLite will be created in the top directory and
+in every subdirectory which features a CMakeLists.txt file containing
+a :command:`project` call.
+The appropriate make program can build the
+project through the default ``all`` target. An ``install`` target
+is also provided.
+
+.. versionadded:: 3.7
+ The :variable:`CMAKE_CODELITE_USE_TARGETS` variable may be set to ``ON``
+ to change the default behavior from projects to targets as the basis
+ for project files.
+
+This "extra" generator may be specified as:
+
+``CodeLite - MinGW Makefiles``
+ Generate with :generator:`MinGW Makefiles`.
+
+``CodeLite - NMake Makefiles``
+ Generate with :generator:`NMake Makefiles`.
+
+``CodeLite - Ninja``
+ Generate with :generator:`Ninja`.
+
+``CodeLite - Unix Makefiles``
+ Generate with :generator:`Unix Makefiles`.
diff --git a/Help/generator/Eclipse CDT4.rst b/Help/generator/Eclipse CDT4.rst
new file mode 100644
index 0000000..634e2b6
--- /dev/null
+++ b/Help/generator/Eclipse CDT4.rst
@@ -0,0 +1,25 @@
+Eclipse CDT4
+------------
+
+Generates Eclipse CDT 4.0 project files.
+
+Project files for Eclipse will be created in the top directory. In
+out of source builds, a linked resource to the top level source
+directory will be created. Additionally a hierarchy of makefiles is
+generated into the build tree. The appropriate make program can build
+the project through the default ``all`` target. An ``install`` target
+is also provided.
+
+This "extra" generator may be specified as:
+
+``Eclipse CDT4 - MinGW Makefiles``
+ Generate with :generator:`MinGW Makefiles`.
+
+``Eclipse CDT4 - NMake Makefiles``
+ Generate with :generator:`NMake Makefiles`.
+
+``Eclipse CDT4 - Ninja``
+ Generate with :generator:`Ninja`.
+
+``Eclipse CDT4 - Unix Makefiles``
+ Generate with :generator:`Unix Makefiles`.
diff --git a/Help/generator/Green Hills MULTI.rst b/Help/generator/Green Hills MULTI.rst
new file mode 100644
index 0000000..5d2b1cd
--- /dev/null
+++ b/Help/generator/Green Hills MULTI.rst
@@ -0,0 +1,88 @@
+Green Hills MULTI
+-----------------
+
+.. versionadded:: 3.3
+
+.. versionadded:: 3.15
+ Linux support.
+
+Generates Green Hills MULTI project files (experimental, work-in-progress).
+
+Customizations are available through the following cache variables:
+
+* ``GHS_CUSTOMIZATION``
+* ``GHS_GPJ_MACROS``
+
+.. versionadded:: 3.14
+ The buildsystem has predetermined build-configuration settings that can be controlled
+ via the :variable:`CMAKE_BUILD_TYPE` variable.
+
+Toolset and Platform Selection
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.13
+
+Customizations that are used to pick toolset and target system:
+
+* The ``-A <arch>`` can be supplied for setting the target architecture.
+ ``<arch>`` usually is one of ``arm``, ``ppc``, ``86``, etcetera.
+ If the target architecture is not specified then
+ the default architecture of ``arm`` will be used.
+
+* The ``-T <toolset>`` option can be used to set the directory location of the toolset.
+ Both absolute and relative paths are valid. Relative paths use ``GHS_TOOLSET_ROOT``
+ as the root. If the toolset is not specified then the latest toolset found in
+ ``GHS_TOOLSET_ROOT`` will be used.
+
+Cache variables that are used for toolset and target system customization:
+
+* ``GHS_TARGET_PLATFORM``
+
+ | Defaults to ``integrity``.
+ | Usual values are ``integrity``, ``threadx``, ``uvelosity``, ``velosity``,
+ ``vxworks``, ``standalone``.
+
+* ``GHS_PRIMARY_TARGET``
+
+ | Sets ``primaryTarget`` entry in project file.
+ | Defaults to ``<arch>_<GHS_TARGET_PLATFORM>.tgt``.
+
+* ``GHS_TOOLSET_ROOT``
+
+ | Root path for ``toolset`` searches.
+ | Defaults to ``C:/ghs`` in Windows or ``/usr/ghs`` in Linux.
+
+* ``GHS_OS_ROOT``
+
+ | Root path for RTOS searches.
+ | Defaults to ``C:/ghs`` in Windows or ``/usr/ghs`` in Linux.
+
+* ``GHS_OS_DIR`` and ``GHS_OS_DIR_OPTION``
+
+ | Sets ``-os_dir`` entry in project file.
+ | Defaults to latest platform OS installation at ``GHS_OS_ROOT``. Set this value if
+ a specific RTOS is to be used.
+ | ``GHS_OS_DIR_OPTION`` default value is ``-os_dir``.
+
+ .. versionadded:: 3.15
+ The ``GHS_OS_DIR_OPTION`` variable.
+
+* ``GHS_BSP_NAME``
+
+ | Sets ``-bsp`` entry in project file.
+ | Defaults to ``sim<arch>`` for ``integrity`` platforms.
+
+Target Properties
+^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.14
+
+The following properties are available:
+
+* :prop_tgt:`GHS_INTEGRITY_APP`
+* :prop_tgt:`GHS_NO_SOURCE_GROUP_FILE`
+
+.. note::
+ This generator is deemed experimental as of CMake |release|
+ and is still a work in progress. Future versions of CMake
+ may make breaking changes as the generator matures.
diff --git a/Help/generator/Kate.rst b/Help/generator/Kate.rst
new file mode 100644
index 0000000..129bf63
--- /dev/null
+++ b/Help/generator/Kate.rst
@@ -0,0 +1,26 @@
+Kate
+----
+
+Generates Kate project files.
+
+A project file for Kate will be created in the top directory in the top level
+build directory.
+To use it in Kate, the Project plugin must be enabled.
+The project file is loaded in Kate by opening the
+``ProjectName.kateproject`` file in the editor.
+If the Kate Build-plugin is enabled, all targets generated by CMake are
+available for building.
+
+This "extra" generator may be specified as:
+
+``Kate - MinGW Makefiles``
+ Generate with :generator:`MinGW Makefiles`.
+
+``Kate - NMake Makefiles``
+ Generate with :generator:`NMake Makefiles`.
+
+``Kate - Ninja``
+ Generate with :generator:`Ninja`.
+
+``Kate - Unix Makefiles``
+ Generate with :generator:`Unix Makefiles`.
diff --git a/Help/generator/MSYS Makefiles.rst b/Help/generator/MSYS Makefiles.rst
new file mode 100644
index 0000000..75b9fe5
--- /dev/null
+++ b/Help/generator/MSYS Makefiles.rst
@@ -0,0 +1,12 @@
+MSYS Makefiles
+--------------
+
+Generates makefiles for use with MSYS (Minimal SYStem)
+``make`` under the MSYS shell.
+
+Use this generator in a MSYS shell prompt and using ``make`` as the build
+tool. The generated makefiles use ``/bin/sh`` as the shell to launch build
+rules. They are not compatible with a Windows command prompt.
+
+To build under a Windows command prompt, use the
+:generator:`MinGW Makefiles` generator.
diff --git a/Help/generator/MinGW Makefiles.rst b/Help/generator/MinGW Makefiles.rst
new file mode 100644
index 0000000..134ea70
--- /dev/null
+++ b/Help/generator/MinGW Makefiles.rst
@@ -0,0 +1,13 @@
+MinGW Makefiles
+---------------
+
+Generates makefiles for use with ``mingw32-make`` under a Windows command
+prompt.
+
+Use this generator under a Windows command prompt with
+MinGW (Minimalist GNU for Windows) in the ``PATH``
+and using ``mingw32-make`` as the build tool. The generated makefiles use
+``cmd.exe`` as the shell to launch build rules. They are not compatible with
+MSYS or a unix shell.
+
+To build under the MSYS shell, use the :generator:`MSYS Makefiles` generator.
diff --git a/Help/generator/NMake Makefiles JOM.rst b/Help/generator/NMake Makefiles JOM.rst
new file mode 100644
index 0000000..e0f4c90
--- /dev/null
+++ b/Help/generator/NMake Makefiles JOM.rst
@@ -0,0 +1,7 @@
+NMake Makefiles JOM
+-------------------
+
+Generates JOM makefiles.
+
+.. versionadded:: 3.8
+ :generator:`CodeBlocks` generator can be used as an extra generator.
diff --git a/Help/generator/NMake Makefiles.rst b/Help/generator/NMake Makefiles.rst
new file mode 100644
index 0000000..89f2479
--- /dev/null
+++ b/Help/generator/NMake Makefiles.rst
@@ -0,0 +1,4 @@
+NMake Makefiles
+---------------
+
+Generates NMake makefiles.
diff --git a/Help/generator/Ninja Multi-Config.rst b/Help/generator/Ninja Multi-Config.rst
new file mode 100644
index 0000000..8901192
--- /dev/null
+++ b/Help/generator/Ninja Multi-Config.rst
@@ -0,0 +1,163 @@
+Ninja Multi-Config
+------------------
+
+.. versionadded:: 3.17
+
+Generates multiple ``build-<Config>.ninja`` files.
+
+This generator is very much like the :generator:`Ninja` generator, but with
+some key differences. Only these differences will be discussed in this
+document.
+
+Unlike the :generator:`Ninja` generator, ``Ninja Multi-Config`` generates
+multiple configurations at once with :variable:`CMAKE_CONFIGURATION_TYPES`
+instead of only one configuration with :variable:`CMAKE_BUILD_TYPE`. One
+``build-<Config>.ninja`` file will be generated for each of these
+configurations (with ``<Config>`` being the configuration name.) These files
+are intended to be run with ``ninja -f build-<Config>.ninja``. A
+``build.ninja`` file is also generated, using the configuration from either
+:variable:`CMAKE_DEFAULT_BUILD_TYPE` or the first item from
+:variable:`CMAKE_CONFIGURATION_TYPES`.
+
+``cmake --build . --config <Config>`` will always use ``build-<Config>.ninja``
+to build. If no ``--config`` argument is specified, ``cmake --build .`` will
+use ``build.ninja``.
+
+Each ``build-<Config>.ninja`` file contains ``<target>`` targets as well as
+``<target>:<Config>`` targets, where ``<Config>`` is the same as the
+configuration specified in ``build-<Config>.ninja`` Additionally, if
+cross-config mode is enabled, ``build-<Config>.ninja`` may contain
+``<target>:<OtherConfig>`` targets, where ``<OtherConfig>`` is a cross-config,
+as well as ``<target>:all``, which builds the target in all cross-configs. See
+below for how to enable cross-config mode.
+
+The ``Ninja Multi-Config`` generator recognizes the following variables:
+
+:variable:`CMAKE_CONFIGURATION_TYPES`
+ Specifies the total set of configurations to build.
+
+:variable:`CMAKE_CROSS_CONFIGS`
+ Specifies a :ref:`semicolon-separated list <CMake Language Lists>` of
+ configurations available from all ``build-<Config>.ninja`` files.
+
+:variable:`CMAKE_DEFAULT_BUILD_TYPE`
+ Specifies the configuration to use by default in a ``build.ninja`` file.
+
+:variable:`CMAKE_DEFAULT_CONFIGS`
+ Specifies a :ref:`semicolon-separated list <CMake Language Lists>` of
+ configurations to build for a target in ``build.ninja``
+ if no ``:<Config>`` suffix is specified.
+
+Consider the following example:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.16)
+ project(MultiConfigNinja C)
+
+ add_executable(generator generator.c)
+ add_custom_command(OUTPUT generated.c COMMAND generator generated.c)
+ add_library(generated ${CMAKE_BINARY_DIR}/generated.c)
+
+Now assume you configure the project with ``Ninja Multi-Config`` and run one of
+the following commands:
+
+.. code-block:: shell
+
+ ninja -f build-Debug.ninja generated
+ # OR
+ cmake --build . --config Debug --target generated
+
+This would build the ``Debug`` configuration of ``generator``, which would be
+used to generate ``generated.c``, which would be used to build the ``Debug``
+configuration of ``generated``.
+
+But if :variable:`CMAKE_CROSS_CONFIGS` is set to ``all``, and you run the
+following instead:
+
+.. code-block:: shell
+
+ ninja -f build-Release.ninja generated:Debug
+ # OR
+ cmake --build . --config Release --target generated:Debug
+
+This would build the ``Release`` configuration of ``generator``, which would be
+used to generate ``generated.c``, which would be used to build the ``Debug``
+configuration of ``generated``. This is useful for running a release-optimized
+version of a generator utility while still building the debug version of the
+targets built with the generated code.
+
+Custom Commands
+^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.20
+
+The ``Ninja Multi-Config`` generator adds extra capabilities to
+:command:`add_custom_command` and :command:`add_custom_target` through its
+cross-config mode. The ``COMMAND``, ``DEPENDS``, and ``WORKING_DIRECTORY``
+arguments can be evaluated in the context of either the "command config" (the
+"native" configuration of the ``build-<Config>.ninja`` file in use) or the
+"output config" (the configuration used to evaluate the ``OUTPUT`` and
+``BYPRODUCTS``).
+
+If either ``OUTPUT`` or ``BYPRODUCTS`` names a path that is common to
+more than one configuration (e.g. it does not use any generator expressions),
+all arguments are evaluated in the command config by default.
+If all ``OUTPUT`` and ``BYPRODUCTS`` paths are unique to each configuration
+(e.g. by using the ``$<CONFIG>`` generator expression), the first argument of
+``COMMAND`` is still evaluated in the command config by default, while all
+subsequent arguments, as well as the arguments to ``DEPENDS`` and
+``WORKING_DIRECTORY``, are evaluated in the output config. These defaults can
+be overridden with the ``$<OUTPUT_CONFIG:...>`` and ``$<COMMAND_CONFIG:...>``
+generator-expressions. Note that if a target is specified by its name in
+``DEPENDS``, or as the first argument of ``COMMAND``, it is always evaluated
+in the command config, even if it is wrapped in ``$<OUTPUT_CONFIG:...>``
+(because its plain name is not a generator expression).
+
+As an example, consider the following:
+
+.. code-block:: cmake
+
+ add_custom_command(
+ OUTPUT "$<CONFIG>.txt"
+ COMMAND generator "$<CONFIG>.txt" "$<OUTPUT_CONFIG:$<CONFIG>>" "$<COMMAND_CONFIG:$<CONFIG>>"
+ DEPENDS tgt1 "$<TARGET_FILE:tgt2>" "$<OUTPUT_CONFIG:$<TARGET_FILE:tgt3>>" "$<COMMAND_CONFIG:$<TARGET_FILE:tgt4>>"
+ )
+
+Assume that ``generator``, ``tgt1``, ``tgt2``, ``tgt3``, and ``tgt4`` are all
+executable targets, and assume that ``$<CONFIG>.txt`` is built in the ``Debug``
+output config using the ``Release`` command config. The ``Release`` build of
+the ``generator`` target is called with ``Debug.txt Debug Release`` as
+arguments. The command depends on the ``Release`` builds of ``tgt1`` and
+``tgt4``, and the ``Debug`` builds of ``tgt2`` and ``tgt3``.
+
+``PRE_BUILD``, ``PRE_LINK``, and ``POST_BUILD`` custom commands for targets
+only get run in their "native" configuration (the ``Release`` configuration in
+the ``build-Release.ninja`` file) unless they have no ``BYPRODUCTS`` or their
+``BYPRODUCTS`` are unique per config. Consider the following example:
+
+.. code-block:: cmake
+
+ add_executable(exe main.c)
+ add_custom_command(
+ TARGET exe
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "Running no-byproduct command"
+ )
+ add_custom_command(
+ TARGET exe
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "Running separate-byproduct command for $<CONFIG>"
+ BYPRODUCTS $<CONFIG>.txt
+ )
+ add_custom_command(
+ TARGET exe
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "Running common-byproduct command for $<CONFIG>"
+ BYPRODUCTS exe.txt
+ )
+
+In this example, if you build ``exe:Debug`` in ``build-Release.ninja``, the
+first and second custom commands get run, since their byproducts are unique
+per-config, but the last custom command does not. However, if you build
+``exe:Release`` in ``build-Release.ninja``, all three custom commands get run.
diff --git a/Help/generator/Ninja.rst b/Help/generator/Ninja.rst
new file mode 100644
index 0000000..f3ba222
--- /dev/null
+++ b/Help/generator/Ninja.rst
@@ -0,0 +1,67 @@
+Ninja
+-----
+
+Generates ``build.ninja`` files.
+
+A ``build.ninja`` file is generated into the build tree. Use the ninja
+program to build the project through the ``all`` target and install the
+project through the ``install`` (or ``install/strip``) target.
+
+For each subdirectory ``sub/dir`` of the project, additional targets
+are generated:
+
+``sub/dir/all``
+
+ .. versionadded:: 3.6
+
+ Depends on all targets required by the subdirectory.
+
+``sub/dir/install``
+
+ .. versionadded:: 3.7
+
+ Runs the install step in the subdirectory, if any.
+
+``sub/dir/install/strip``
+
+ .. versionadded:: 3.7
+ Runs the install step in the subdirectory followed by a ``CMAKE_STRIP`` command,
+ if any.
+
+ The ``CMAKE_STRIP`` variable will contain the platform's ``strip`` utility, which
+ removes symbols information from generated binaries.
+
+``sub/dir/test``
+
+ .. versionadded:: 3.7
+
+ Runs the test step in the subdirectory, if any.
+
+``sub/dir/package``
+
+ .. versionadded:: 3.7
+
+ Runs the package step in the subdirectory, if any.
+
+Fortran Support
+^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.7
+
+The ``Ninja`` generator conditionally supports Fortran when the ``ninja``
+tool is at least version 1.10 (which has the required features).
+
+Swift Support
+^^^^^^^^^^^^^
+
+.. versionadded:: 3.15
+
+The Swift support is experimental, not considered stable, and may change
+in future releases of CMake.
+
+See Also
+^^^^^^^^
+
+.. versionadded:: 3.17
+ The :generator:`Ninja Multi-Config` generator is similar to the ``Ninja``
+ generator, but generates multiple configurations at once.
diff --git a/Help/generator/Sublime Text 2.rst b/Help/generator/Sublime Text 2.rst
new file mode 100644
index 0000000..0a07ea9
--- /dev/null
+++ b/Help/generator/Sublime Text 2.rst
@@ -0,0 +1,25 @@
+Sublime Text 2
+--------------
+
+Generates Sublime Text 2 project files.
+
+Project files for Sublime Text 2 will be created in the top directory
+and in every subdirectory which features a ``CMakeLists.txt`` file
+containing a :command:`project` call. Additionally ``Makefiles``
+(or ``build.ninja`` files) are generated into the build tree.
+The appropriate make program can build the project through the default ``all``
+target. An ``install`` target is also provided.
+
+This "extra" generator may be specified as:
+
+``Sublime Text 2 - MinGW Makefiles``
+ Generate with :generator:`MinGW Makefiles`.
+
+``Sublime Text 2 - NMake Makefiles``
+ Generate with :generator:`NMake Makefiles`.
+
+``Sublime Text 2 - Ninja``
+ Generate with :generator:`Ninja`.
+
+``Sublime Text 2 - Unix Makefiles``
+ Generate with :generator:`Unix Makefiles`.
diff --git a/Help/generator/Unix Makefiles.rst b/Help/generator/Unix Makefiles.rst
new file mode 100644
index 0000000..dfe4ecb
--- /dev/null
+++ b/Help/generator/Unix Makefiles.rst
@@ -0,0 +1,31 @@
+Unix Makefiles
+--------------
+
+Generates standard UNIX makefiles.
+
+A hierarchy of UNIX makefiles is generated into the build tree. Use
+any standard UNIX-style make program to build the project through
+the ``all`` target and install the project through the ``install``
+(or ``install/strip``) target.
+
+For each subdirectory ``sub/dir`` of the project a UNIX makefile will
+be created, containing the following targets:
+
+``all``
+ Depends on all targets required by the subdirectory.
+
+``install``
+ Runs the install step in the subdirectory, if any.
+
+``install/strip``
+ Runs the install step in the subdirectory followed by a ``CMAKE_STRIP`` command,
+ if any.
+
+ The ``CMAKE_STRIP`` variable will contain the platform's ``strip`` utility, which
+ removes symbols information from generated binaries.
+
+``test``
+ Runs the test step in the subdirectory, if any.
+
+``package``
+ Runs the package step in the subdirectory, if any.
diff --git a/Help/generator/VS_TOOLSET_HOST_ARCH.txt b/Help/generator/VS_TOOLSET_HOST_ARCH.txt
new file mode 100644
index 0000000..e361719
--- /dev/null
+++ b/Help/generator/VS_TOOLSET_HOST_ARCH.txt
@@ -0,0 +1,11 @@
+.. versionadded:: 3.8
+ For each toolset that comes with this version of Visual Studio, there are
+ variants that are themselves compiled for 32-bit (``x86``) and
+ 64-bit (``x64``) hosts (independent of the architecture they target).
+ |VS_TOOLSET_HOST_ARCH_DEFAULT|
+ One may explicitly request use of either the 32-bit or 64-bit host tools
+ by adding either ``host=x86`` or ``host=x64`` to the toolset specification.
+ See the :variable:`CMAKE_GENERATOR_TOOLSET` variable for details.
+
+.. versionadded:: 3.14
+ Added suport for ``host=x86`` option.
diff --git a/Help/generator/Visual Studio 10 2010.rst b/Help/generator/Visual Studio 10 2010.rst
new file mode 100644
index 0000000..b4376d8
--- /dev/null
+++ b/Help/generator/Visual Studio 10 2010.rst
@@ -0,0 +1,44 @@
+Visual Studio 10 2010
+---------------------
+
+Generates Visual Studio 10 (VS 2010) project files.
+
+For compatibility with CMake versions prior to 3.0, one may specify this
+generator using the name ``Visual Studio 10`` without the year component.
+
+Project Types
+^^^^^^^^^^^^^
+
+Only Visual C++ and C# projects may be generated. Other types of
+projects (Database, Website, etc.) are not supported.
+
+Platform Selection
+^^^^^^^^^^^^^^^^^^
+
+The default target platform name (architecture) is ``Win32``.
+
+.. versionadded:: 3.1
+ The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+ via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+ name (architecture). For example:
+
+ * ``cmake -G "Visual Studio 10 2010" -A Win32``
+ * ``cmake -G "Visual Studio 10 2010" -A x64``
+ * ``cmake -G "Visual Studio 10 2010" -A Itanium``
+
+For compatibility with CMake versions prior to 3.1, one may specify
+a target platform name optionally at the end of the generator name.
+This is supported only for:
+
+``Visual Studio 10 2010 Win64``
+ Specify target platform ``x64``.
+
+``Visual Studio 10 2010 IA64``
+ Specify target platform ``Itanium``.
+
+Toolset Selection
+^^^^^^^^^^^^^^^^^
+
+The ``v100`` toolset that comes with Visual Studio 10 2010 is selected by
+default. The :variable:`CMAKE_GENERATOR_TOOLSET` option may be set, perhaps
+via the :manual:`cmake(1)` ``-T`` option, to specify another toolset.
diff --git a/Help/generator/Visual Studio 11 2012.rst b/Help/generator/Visual Studio 11 2012.rst
new file mode 100644
index 0000000..932548b
--- /dev/null
+++ b/Help/generator/Visual Studio 11 2012.rst
@@ -0,0 +1,49 @@
+Visual Studio 11 2012
+---------------------
+
+Generates Visual Studio 11 (VS 2012) project files.
+
+For compatibility with CMake versions prior to 3.0, one may specify this
+generator using the name "Visual Studio 11" without the year component.
+
+Project Types
+^^^^^^^^^^^^^
+
+Only Visual C++ and C# projects may be generated. Other types of
+projects (JavaScript, Database, Website, etc.) are not supported.
+
+Platform Selection
+^^^^^^^^^^^^^^^^^^
+
+The default target platform name (architecture) is ``Win32``.
+
+.. versionadded:: 3.1
+ The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+ via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+ name (architecture). For example:
+
+ * ``cmake -G "Visual Studio 11 2012" -A Win32``
+ * ``cmake -G "Visual Studio 11 2012" -A x64``
+ * ``cmake -G "Visual Studio 11 2012" -A ARM``
+ * ``cmake -G "Visual Studio 11 2012" -A <WinCE-SDK>``
+ (Specify a target platform matching a Windows CE SDK name.)
+
+For compatibility with CMake versions prior to 3.1, one may specify
+a target platform name optionally at the end of the generator name.
+This is supported only for:
+
+``Visual Studio 11 2012 Win64``
+ Specify target platform ``x64``.
+
+``Visual Studio 11 2012 ARM``
+ Specify target platform ``ARM``.
+
+``Visual Studio 11 2012 <WinCE-SDK>``
+ Specify target platform matching a Windows CE SDK name.
+
+Toolset Selection
+^^^^^^^^^^^^^^^^^
+
+The ``v110`` toolset that comes with Visual Studio 11 2012 is selected by
+default. The :variable:`CMAKE_GENERATOR_TOOLSET` option may be set, perhaps
+via the :manual:`cmake(1)` ``-T`` option, to specify another toolset.
diff --git a/Help/generator/Visual Studio 12 2013.rst b/Help/generator/Visual Studio 12 2013.rst
new file mode 100644
index 0000000..b5fa1bf
--- /dev/null
+++ b/Help/generator/Visual Studio 12 2013.rst
@@ -0,0 +1,49 @@
+Visual Studio 12 2013
+---------------------
+
+Generates Visual Studio 12 (VS 2013) project files.
+
+For compatibility with CMake versions prior to 3.0, one may specify this
+generator using the name "Visual Studio 12" without the year component.
+
+Project Types
+^^^^^^^^^^^^^
+
+Only Visual C++ and C# projects may be generated. Other types of
+projects (JavaScript, Powershell, Python, etc.) are not supported.
+
+Platform Selection
+^^^^^^^^^^^^^^^^^^
+
+The default target platform name (architecture) is ``Win32``.
+
+.. versionadded:: 3.1
+ The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+ via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+ name (architecture). For example:
+
+ * ``cmake -G "Visual Studio 12 2013" -A Win32``
+ * ``cmake -G "Visual Studio 12 2013" -A x64``
+ * ``cmake -G "Visual Studio 12 2013" -A ARM``
+
+For compatibility with CMake versions prior to 3.1, one may specify
+a target platform name optionally at the end of the generator name.
+This is supported only for:
+
+``Visual Studio 12 2013 Win64``
+ Specify target platform ``x64``.
+
+``Visual Studio 12 2013 ARM``
+ Specify target platform ``ARM``.
+
+Toolset Selection
+^^^^^^^^^^^^^^^^^
+
+The ``v120`` toolset that comes with Visual Studio 12 2013 is selected by
+default. The :variable:`CMAKE_GENERATOR_TOOLSET` option may be set, perhaps
+via the :manual:`cmake(1)` ``-T`` option, to specify another toolset.
+
+.. |VS_TOOLSET_HOST_ARCH_DEFAULT| replace::
+ By default this generator uses the 32-bit variant even on a 64-bit host.
+
+.. include:: VS_TOOLSET_HOST_ARCH.txt
diff --git a/Help/generator/Visual Studio 14 2015.rst b/Help/generator/Visual Studio 14 2015.rst
new file mode 100644
index 0000000..9c61641
--- /dev/null
+++ b/Help/generator/Visual Studio 14 2015.rst
@@ -0,0 +1,65 @@
+Visual Studio 14 2015
+---------------------
+
+.. versionadded:: 3.1
+
+Generates Visual Studio 14 (VS 2015) project files.
+
+Project Types
+^^^^^^^^^^^^^
+
+Only Visual C++ and C# projects may be generated. Other types of
+projects (JavaScript, Powershell, Python, etc.) are not supported.
+
+Platform Selection
+^^^^^^^^^^^^^^^^^^
+
+The default target platform name (architecture) is ``Win32``.
+
+The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+name (architecture). For example:
+
+* ``cmake -G "Visual Studio 14 2015" -A Win32``
+* ``cmake -G "Visual Studio 14 2015" -A x64``
+* ``cmake -G "Visual Studio 14 2015" -A ARM``
+
+For compatibility with CMake versions prior to 3.1, one may specify
+a target platform name optionally at the end of the generator name.
+This is supported only for:
+
+``Visual Studio 14 2015 Win64``
+ Specify target platform ``x64``.
+
+``Visual Studio 14 2015 ARM``
+ Specify target platform ``ARM``.
+
+Toolset Selection
+^^^^^^^^^^^^^^^^^
+
+The ``v140`` toolset that comes with Visual Studio 14 2015 is selected by
+default. The :variable:`CMAKE_GENERATOR_TOOLSET` option may be set, perhaps
+via the :manual:`cmake(1)` ``-T`` option, to specify another toolset.
+
+.. |VS_TOOLSET_HOST_ARCH_DEFAULT| replace::
+ By default this generator uses the 32-bit variant even on a 64-bit host.
+
+.. include:: VS_TOOLSET_HOST_ARCH.txt
+
+.. _`Windows 10 SDK Maximum Version for VS 2015`:
+
+Windows 10 SDK Maximum Version for VS 2015
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.19
+
+Microsoft stated in a "Windows 10 October 2018 Update" blog post that Windows
+10 SDK versions (15063, 16299, 17134, 17763) are not supported by VS 2015 and
+are only supported by VS 2017 and later. Therefore by default CMake
+automatically ignores Windows 10 SDKs beyond ``10.0.14393.0``.
+
+However, there are other recommendations for certain driver/Win32 builds that
+indicate otherwise. A user can override this behavior by either setting the
+:variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM` to a false value
+or setting the :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM` to
+the string value of the required maximum (e.g. ``10.0.15063.0``).
diff --git a/Help/generator/Visual Studio 15 2017.rst b/Help/generator/Visual Studio 15 2017.rst
new file mode 100644
index 0000000..a002f2f
--- /dev/null
+++ b/Help/generator/Visual Studio 15 2017.rst
@@ -0,0 +1,66 @@
+Visual Studio 15 2017
+---------------------
+
+.. versionadded:: 3.7.1
+
+Generates Visual Studio 15 (VS 2017) project files.
+
+Project Types
+^^^^^^^^^^^^^
+
+Only Visual C++ and C# projects may be generated. Other types of
+projects (JavaScript, Powershell, Python, etc.) are not supported.
+
+Instance Selection
+^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.9
+ VS 2017 supports multiple installations on the same machine.
+ The :variable:`CMAKE_GENERATOR_INSTANCE` variable may be set as a
+ cache entry containing the absolute path to a Visual Studio instance.
+ If the value is not specified explicitly by the user or a toolchain file,
+ CMake queries the Visual Studio Installer to locate VS instances, chooses
+ one, and sets the variable as a cache entry to hold the value persistently.
+
+.. versionadded:: 3.11
+ When CMake first chooses an instance, if the ``VS150COMNTOOLS`` environment
+ variable is set and points to the ``Common7/Tools`` directory within
+ one of the instances, that instance will be used. Otherwise, if more
+ than one instance is installed we do not define which one is chosen
+ by default.
+
+Platform Selection
+^^^^^^^^^^^^^^^^^^
+
+The default target platform name (architecture) is ``Win32``.
+
+The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+name (architecture). For example:
+
+* ``cmake -G "Visual Studio 15 2017" -A Win32``
+* ``cmake -G "Visual Studio 15 2017" -A x64``
+* ``cmake -G "Visual Studio 15 2017" -A ARM``
+* ``cmake -G "Visual Studio 15 2017" -A ARM64``
+
+For compatibility with CMake versions prior to 3.1, one may specify
+a target platform name optionally at the end of the generator name.
+This is supported only for:
+
+``Visual Studio 15 2017 Win64``
+ Specify target platform ``x64``.
+
+``Visual Studio 15 2017 ARM``
+ Specify target platform ``ARM``.
+
+Toolset Selection
+^^^^^^^^^^^^^^^^^
+
+The ``v141`` toolset that comes with Visual Studio 15 2017 is selected by
+default. The :variable:`CMAKE_GENERATOR_TOOLSET` option may be set, perhaps
+via the :manual:`cmake(1)` ``-T`` option, to specify another toolset.
+
+.. |VS_TOOLSET_HOST_ARCH_DEFAULT| replace::
+ By default this generator uses the 32-bit variant even on a 64-bit host.
+
+.. include:: VS_TOOLSET_HOST_ARCH.txt
diff --git a/Help/generator/Visual Studio 16 2019.rst b/Help/generator/Visual Studio 16 2019.rst
new file mode 100644
index 0000000..3da8091
--- /dev/null
+++ b/Help/generator/Visual Studio 16 2019.rst
@@ -0,0 +1,56 @@
+Visual Studio 16 2019
+---------------------
+
+.. versionadded:: 3.14
+
+Generates Visual Studio 16 (VS 2019) project files.
+
+Project Types
+^^^^^^^^^^^^^
+
+Only Visual C++ and C# projects may be generated. Other types of
+projects (JavaScript, Powershell, Python, etc.) are not supported.
+
+Instance Selection
+^^^^^^^^^^^^^^^^^^
+
+VS 2019 supports multiple installations on the same machine.
+The :variable:`CMAKE_GENERATOR_INSTANCE` variable may be set as a
+cache entry containing the absolute path to a Visual Studio instance.
+If the value is not specified explicitly by the user or a toolchain file,
+CMake queries the Visual Studio Installer to locate VS instances, chooses
+one, and sets the variable as a cache entry to hold the value persistently.
+
+When CMake first chooses an instance, if the ``VS160COMNTOOLS`` environment
+variable is set and points to the ``Common7/Tools`` directory within
+one of the instances, that instance will be used. Otherwise, if more
+than one instance is installed we do not define which one is chosen
+by default.
+
+Platform Selection
+^^^^^^^^^^^^^^^^^^
+
+The default target platform name (architecture) is that of the host
+and is provided in the :variable:`CMAKE_VS_PLATFORM_NAME_DEFAULT` variable.
+
+The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+name (architecture). For example:
+
+* ``cmake -G "Visual Studio 16 2019" -A Win32``
+* ``cmake -G "Visual Studio 16 2019" -A x64``
+* ``cmake -G "Visual Studio 16 2019" -A ARM``
+* ``cmake -G "Visual Studio 16 2019" -A ARM64``
+
+Toolset Selection
+^^^^^^^^^^^^^^^^^
+
+The ``v142`` toolset that comes with Visual Studio 16 2019 is selected by
+default. The :variable:`CMAKE_GENERATOR_TOOLSET` option may be set, perhaps
+via the :manual:`cmake(1)` ``-T`` option, to specify another toolset.
+
+.. |VS_TOOLSET_HOST_ARCH_DEFAULT| replace::
+ By default this generator uses the 64-bit variant on x64 hosts and
+ the 32-bit variant otherwise.
+
+.. include:: VS_TOOLSET_HOST_ARCH.txt
diff --git a/Help/generator/Visual Studio 6.rst b/Help/generator/Visual Studio 6.rst
new file mode 100644
index 0000000..2dd07e0
--- /dev/null
+++ b/Help/generator/Visual Studio 6.rst
@@ -0,0 +1,6 @@
+Visual Studio 6
+---------------
+
+Removed. This once generated Visual Studio 6 project files, but the
+generator has been removed since CMake 3.6. It is still possible to
+build with VS 6 tools using the :generator:`NMake Makefiles` generator.
diff --git a/Help/generator/Visual Studio 7 .NET 2003.rst b/Help/generator/Visual Studio 7 .NET 2003.rst
new file mode 100644
index 0000000..d4c7869
--- /dev/null
+++ b/Help/generator/Visual Studio 7 .NET 2003.rst
@@ -0,0 +1,6 @@
+Visual Studio 7 .NET 2003
+-------------------------
+
+Removed. This once generated Visual Studio .NET 2003 project files, but
+the generator has been removed since CMake 3.9. It is still possible to
+build with VS 7.1 tools using the :generator:`NMake Makefiles` generator.
diff --git a/Help/generator/Visual Studio 7.rst b/Help/generator/Visual Studio 7.rst
new file mode 100644
index 0000000..54d29df
--- /dev/null
+++ b/Help/generator/Visual Studio 7.rst
@@ -0,0 +1,6 @@
+Visual Studio 7
+---------------
+
+Removed. This once generated Visual Studio .NET 2002 project files, but
+the generator has been removed since CMake 3.6. It is still possible to
+build with VS 7.0 tools using the :generator:`NMake Makefiles` generator.
diff --git a/Help/generator/Visual Studio 8 2005.rst b/Help/generator/Visual Studio 8 2005.rst
new file mode 100644
index 0000000..947e7a5
--- /dev/null
+++ b/Help/generator/Visual Studio 8 2005.rst
@@ -0,0 +1,6 @@
+Visual Studio 8 2005
+--------------------
+
+Removed. This once generated Visual Studio 8 2005 project files, but
+the generator has been removed since CMake 3.12. It is still possible to
+build with VS 2005 tools using the :generator:`NMake Makefiles` generator.
diff --git a/Help/generator/Visual Studio 9 2008.rst b/Help/generator/Visual Studio 9 2008.rst
new file mode 100644
index 0000000..644f936
--- /dev/null
+++ b/Help/generator/Visual Studio 9 2008.rst
@@ -0,0 +1,33 @@
+Visual Studio 9 2008
+--------------------
+
+Generates Visual Studio 9 2008 project files.
+
+Platform Selection
+^^^^^^^^^^^^^^^^^^
+
+The default target platform name (architecture) is ``Win32``.
+
+.. versionadded:: 3.1
+ The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+ via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+ name (architecture). For example:
+
+ * ``cmake -G "Visual Studio 9 2008" -A Win32``
+ * ``cmake -G "Visual Studio 9 2008" -A x64``
+ * ``cmake -G "Visual Studio 9 2008" -A Itanium``
+ * ``cmake -G "Visual Studio 9 2008" -A <WinCE-SDK>``
+ (Specify a target platform matching a Windows CE SDK name.)
+
+For compatibility with CMake versions prior to 3.1, one may specify
+a target platform name optionally at the end of the generator name.
+This is supported only for:
+
+``Visual Studio 9 2008 Win64``
+ Specify target platform ``x64``.
+
+``Visual Studio 9 2008 IA64``
+ Specify target platform ``Itanium``.
+
+``Visual Studio 9 2008 <WinCE-SDK>``
+ Specify target platform matching a Windows CE SDK name.
diff --git a/Help/generator/Watcom WMake.rst b/Help/generator/Watcom WMake.rst
new file mode 100644
index 0000000..09bdc3d
--- /dev/null
+++ b/Help/generator/Watcom WMake.rst
@@ -0,0 +1,4 @@
+Watcom WMake
+------------
+
+Generates Watcom WMake makefiles.
diff --git a/Help/generator/Xcode.rst b/Help/generator/Xcode.rst
new file mode 100644
index 0000000..e4900a1
--- /dev/null
+++ b/Help/generator/Xcode.rst
@@ -0,0 +1,46 @@
+Xcode
+-----
+
+Generate Xcode project files.
+
+.. versionchanged:: 3.15
+ This generator supports Xcode 5.0 and above.
+
+.. _`Xcode Build System Selection`:
+
+Toolset and Build System Selection
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+By default Xcode is allowed to select its own default toolchain.
+The :variable:`CMAKE_GENERATOR_TOOLSET` option may be set, perhaps
+via the :manual:`cmake(1)` ``-T`` option, to specify another toolset.
+
+.. versionadded:: 3.19
+ This generator supports toolset specification using one of these forms:
+
+* ``toolset``
+* ``toolset[,key=value]*``
+* ``key=value[,key=value]*``
+
+The ``toolset`` specifies the toolset name. The selected toolset name
+is provided in the :variable:`CMAKE_XCODE_PLATFORM_TOOLSET` variable.
+
+The ``key=value`` pairs form a comma-separated list of options to
+specify generator-specific details of the toolset selection.
+Supported pairs are:
+
+``buildsystem=<variant>``
+ Specify the buildsystem variant to use.
+ See the :variable:`CMAKE_XCODE_BUILD_SYSTEM` variable for allowed values.
+
+ For example, to select the original build system under Xcode 12,
+ run :manual:`cmake(1)` with the option ``-T buildsystem=1``.
+
+Swift Support
+^^^^^^^^^^^^^
+
+.. versionadded:: 3.4
+
+When using the :generator:`Xcode` generator with Xcode 6.1 or higher,
+one may enable the ``Swift`` language with the :command:`enable_language`
+command or the :command:`project`.
diff --git a/Help/guide/ide-integration/index.rst b/Help/guide/ide-integration/index.rst
new file mode 100644
index 0000000..addf932
--- /dev/null
+++ b/Help/guide/ide-integration/index.rst
@@ -0,0 +1,126 @@
+IDE Integration Guide
+*********************
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+Integrated development environments (IDEs) may want to integrate with CMake to
+improve the development experience for CMake users. This document lays out the
+recommended best practices for such integration.
+
+Bundling
+========
+
+Many IDE vendors will want to bundle a copy of CMake with their IDE. IDEs that
+bundle CMake should present the user with the option of using an external CMake
+installation instead of the bundled one, in case the bundled copy becomes
+outdated and the user wants to use a newer version.
+
+While IDE vendors may be tempted to bundle different versions of CMake with
+their application, such practice is not recommended. CMake has strong
+guarantees of backwards compatibility, and there is no reason not to use a
+newer version of CMake than what a project requires, or indeed, the very latest
+version. Therefore, it is recommended that IDE vendors that bundle CMake with
+their application always include the very latest patch version of CMake
+available at the time of release.
+
+As a suggestion, IDEs may also ship a copy of the Ninja buildsystem alongside
+CMake. Ninja is highly performant and well-supported on all platforms that
+support CMake. IDEs that bundle Ninja should use Ninja 1.10 or later, which
+contains features needed to support Fortran builds.
+
+Presets
+=======
+
+CMake supports a file format called ``CMakePresets.json``, and its
+user-specific counterpart, ``CMakeUserPresets.json``. This file contains
+information on the various configure presets that a user may want. Each preset
+may have a different compiler, build flags, etc. The details of this format are
+explained in the :manual:`cmake(1)` manual.
+
+IDE vendors are encouraged to read and evaluate this file the same way CMake
+does, and present the user with the presets listed in the file. Users should be
+able to see (and possibly edit) the CMake cache variables, environment
+variables, and command line options that are defined for a given preset. The
+IDE should then construct the list of appropriate :manual:`cmake(1)` command
+line arguments based on these settings, rather than using the ``--preset=``
+option directly. The ``--preset=`` option is intended only as a convenient
+frontend for command line users, and should not be used by the IDE.
+
+For example, if a preset named ``ninja`` specifies ``Ninja`` as the generator
+and ``${sourceDir}/build`` as the build directory, instead of running:
+
+.. code-block:: console
+
+ cmake -S /path/to/source --preset=ninja
+
+the IDE should instead calculate the settings of the ``ninja`` preset, and then
+run:
+
+.. code-block:: console
+
+ cmake -S /path/to/source -B /path/to/source/build -G Ninja
+
+While reading, parsing, and evaluating the contents of ``CMakePresets.json`` is
+straightforward, it is not trivial. In addition to the documentation, IDE
+vendors may also wish to refer to the CMake source code and test cases for a
+better understanding of how to implement the format.
+:download:`This file </manual/presets/schema.json>` provides a machine-readable
+JSON schema for the ``CMakePresets.json`` format that IDE vendors may find
+useful for validation and providing editing assistance.
+
+Configuring
+===========
+
+IDEs that invoke :manual:`cmake(1)` to run the configure step may wish to
+receive information about the artifacts that the build will produce, as well
+as the include directories, compile definitions, etc. used to build the
+artifacts. Such information can be obtained by using the
+:manual:`File API <cmake-file-api(7)>`. The manual page for the File API
+contains more information about the API and how to invoke it.
+:manual:`Server mode <cmake-server(7)>` was removed as of CMake 3.20 and
+should not be used on CMake 3.14 or later.
+
+IDEs should avoid creating more build trees than necessary, and only create
+multiple build trees if the user wishes to switch to a different compiler,
+use different compile flags, etc. In particular, IDEs should NOT create
+multiple single-config build trees which all have the same properties except
+for a differing :variable:`CMAKE_BUILD_TYPE`, effectively creating a
+multi-config environment. Instead, the :generator:`Ninja Multi-Config`
+generator, in conjunction with the :manual:`File API <cmake-file-api(7)>` to
+get the list of build configurations, should be used for this purpose.
+
+IDEs should not use the "extra generators" with Makefile or Ninja generators,
+which generate IDE project files in addition to the Makefile or Ninja files.
+Instead the :manual:`File API <cmake-file-api(7)>` should be used to get the
+list of build artifacts.
+
+Building
+========
+
+If a Makefile or Ninja generator is used to generate the build tree, it is not
+recommended to invoke ``make`` or ``ninja`` directly. Instead, it is
+recommended that the IDE invoke :manual:`cmake(1)` with the ``--build``
+argument, which will in turn invoke the appropriate build tool.
+
+If an IDE project generator is used, such as :generator:`Xcode` or one of the
+Visual Studio generators, and the IDE understands the project format used, the
+IDE should read the project file and build it the same way it would otherwise.
+
+The :manual:`File API <cmake-file-api(7)>` can be used to obtain a list of
+build configurations from the build tree, and the IDE should present this list
+to the user to select a build configuration.
+
+Testing
+=======
+
+:manual:`ctest(1)` supports outputting a JSON format with information about the
+available tests and test configurations. IDEs which want to run CTest should
+obtain this information and use it to present the user with a list of tests.
+
+IDEs should not invoke the ``test`` target of the generated buildsystem.
+Instead, they should invoke :manual:`ctest(1)` directly.
diff --git a/Help/guide/importing-exporting/Downstream/CMakeLists.txt b/Help/guide/importing-exporting/Downstream/CMakeLists.txt
new file mode 100644
index 0000000..381c875
--- /dev/null
+++ b/Help/guide/importing-exporting/Downstream/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.15)
+project(Downstream)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# find MathFunctions
+find_package(MathFunctions 3.4.1 EXACT)
+
+# create executable
+add_executable(myexe main.cc)
+
+# use MathFunctions library
+target_link_libraries(myexe PRIVATE MathFunctions::MathFunctions)
diff --git a/Help/guide/importing-exporting/Downstream/main.cc b/Help/guide/importing-exporting/Downstream/main.cc
new file mode 100644
index 0000000..8574373
--- /dev/null
+++ b/Help/guide/importing-exporting/Downstream/main.cc
@@ -0,0 +1,23 @@
+// A simple program that outputs the square root of a number
+#include <iostream>
+#include <string>
+
+#include "MathFunctions.h"
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = std::stod(argv[1]);
+
+ // calculate square root
+ const double sqrt = MathFunctions::sqrt(inputValue);
+ std::cout << "The square root of " << inputValue << " is " << sqrt
+ << std::endl;
+
+ return 0;
+}
diff --git a/Help/guide/importing-exporting/DownstreamComponents/CMakeLists.txt b/Help/guide/importing-exporting/DownstreamComponents/CMakeLists.txt
new file mode 100644
index 0000000..88b46c8
--- /dev/null
+++ b/Help/guide/importing-exporting/DownstreamComponents/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.15)
+project(DownstreamComponents)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# find MathFunctions
+find_package(MathFunctions 3.4 COMPONENTS Addition SquareRoot)
+
+# create executable
+add_executable(myexe main.cc)
+
+# use MathFunctions library
+target_link_libraries(myexe PRIVATE MathFunctions::Addition MathFunctions::SquareRoot)
+
+# Workaround for GCC on AIX to avoid -isystem, not needed in general.
+set_property(TARGET myexe PROPERTY NO_SYSTEM_FROM_IMPORTED 1)
diff --git a/Help/guide/importing-exporting/DownstreamComponents/main.cc b/Help/guide/importing-exporting/DownstreamComponents/main.cc
new file mode 100644
index 0000000..f5e8fa6
--- /dev/null
+++ b/Help/guide/importing-exporting/DownstreamComponents/main.cc
@@ -0,0 +1,28 @@
+// A simple program that outputs the square root of a number
+#include <iostream>
+#include <string>
+
+#include "Addition.h"
+#include "SquareRoot.h"
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = std::stod(argv[1]);
+
+ // calculate square root
+ const double sqrt = MathFunctions::sqrt(inputValue);
+ std::cout << "The square root of " << inputValue << " is " << sqrt
+ << std::endl;
+
+ // calculate sum
+ const double sum = MathFunctions::add(inputValue, inputValue);
+ std::cout << inputValue << " + " << inputValue << " = " << sum << std::endl;
+
+ return 0;
+}
diff --git a/Help/guide/importing-exporting/Importing/CMakeLists.txt b/Help/guide/importing-exporting/Importing/CMakeLists.txt
new file mode 100644
index 0000000..fe7d704
--- /dev/null
+++ b/Help/guide/importing-exporting/Importing/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.15)
+project(Importing)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# Add executable
+add_executable(myexe IMPORTED)
+
+# Set imported location
+set_property(TARGET myexe PROPERTY
+ IMPORTED_LOCATION "../InstallMyExe/bin/myexe")
+
+# Add custom command to create source file
+add_custom_command(OUTPUT main.cc COMMAND myexe)
+
+# Use source file
+add_executable(mynewexe main.cc)
diff --git a/Help/guide/importing-exporting/MathFunctions/CMakeLists.txt b/Help/guide/importing-exporting/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..d277b54
--- /dev/null
+++ b/Help/guide/importing-exporting/MathFunctions/CMakeLists.txt
@@ -0,0 +1,78 @@
+cmake_minimum_required(VERSION 3.15)
+project(MathFunctions)
+
+# make cache variables for install destinations
+include(GNUInstallDirs)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# create library
+add_library(MathFunctions STATIC MathFunctions.cxx)
+
+# add include directories
+target_include_directories(MathFunctions
+ PUBLIC
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
+ "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
+)
+
+# install the target and create export-set
+install(TARGETS MathFunctions
+ EXPORT MathFunctionsTargets
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+)
+
+# install header file
+install(FILES MathFunctions.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+# generate and install export file
+install(EXPORT MathFunctionsTargets
+ FILE MathFunctionsTargets.cmake
+ NAMESPACE MathFunctions::
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
+)
+
+# include CMakePackageConfigHelpers macro
+include(CMakePackageConfigHelpers)
+
+# set version
+set(version 3.4.1)
+
+set_property(TARGET MathFunctions PROPERTY VERSION ${version})
+set_property(TARGET MathFunctions PROPERTY SOVERSION 3)
+set_property(TARGET MathFunctions PROPERTY
+ INTERFACE_MathFunctions_MAJOR_VERSION 3)
+set_property(TARGET MathFunctions APPEND PROPERTY
+ COMPATIBLE_INTERFACE_STRING MathFunctions_MAJOR_VERSION
+)
+
+# generate the version file for the config file
+write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
+ VERSION "${version}"
+ COMPATIBILITY AnyNewerVersion
+)
+
+# create config file
+configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
+ "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
+ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
+)
+
+# install config files
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
+)
+
+# generate the export targets for the build tree
+export(EXPORT MathFunctionsTargets
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/MathFunctionsTargets.cmake"
+ NAMESPACE MathFunctions::
+)
diff --git a/Help/guide/importing-exporting/MathFunctions/Config.cmake.in b/Help/guide/importing-exporting/MathFunctions/Config.cmake.in
new file mode 100644
index 0000000..eba1ff6
--- /dev/null
+++ b/Help/guide/importing-exporting/MathFunctions/Config.cmake.in
@@ -0,0 +1,5 @@
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake")
+
+check_required_components(MathFunctions)
diff --git a/Help/guide/importing-exporting/MathFunctions/MathFunctions.cxx b/Help/guide/importing-exporting/MathFunctions/MathFunctions.cxx
new file mode 100644
index 0000000..e75fe74
--- /dev/null
+++ b/Help/guide/importing-exporting/MathFunctions/MathFunctions.cxx
@@ -0,0 +1,10 @@
+#include "MathFunctions.h"
+
+#include <cmath>
+
+namespace MathFunctions {
+double sqrt(double x)
+{
+ return std::sqrt(x);
+}
+}
diff --git a/Help/guide/importing-exporting/MathFunctions/MathFunctions.h b/Help/guide/importing-exporting/MathFunctions/MathFunctions.h
new file mode 100644
index 0000000..b38596d
--- /dev/null
+++ b/Help/guide/importing-exporting/MathFunctions/MathFunctions.h
@@ -0,0 +1,5 @@
+#pragma once
+
+namespace MathFunctions {
+double sqrt(double x);
+}
diff --git a/Help/guide/importing-exporting/MathFunctionsComponents/Addition/Addition.cxx b/Help/guide/importing-exporting/MathFunctionsComponents/Addition/Addition.cxx
new file mode 100644
index 0000000..0a6b98b
--- /dev/null
+++ b/Help/guide/importing-exporting/MathFunctionsComponents/Addition/Addition.cxx
@@ -0,0 +1,8 @@
+#include "Addition.h"
+
+namespace MathFunctions {
+double add(double x, double y)
+{
+ return x + y;
+}
+}
diff --git a/Help/guide/importing-exporting/MathFunctionsComponents/Addition/Addition.h b/Help/guide/importing-exporting/MathFunctionsComponents/Addition/Addition.h
new file mode 100644
index 0000000..b061d5e
--- /dev/null
+++ b/Help/guide/importing-exporting/MathFunctionsComponents/Addition/Addition.h
@@ -0,0 +1,5 @@
+#pragma once
+
+namespace MathFunctions {
+double add(double x, double y);
+}
diff --git a/Help/guide/importing-exporting/MathFunctionsComponents/Addition/CMakeLists.txt b/Help/guide/importing-exporting/MathFunctionsComponents/Addition/CMakeLists.txt
new file mode 100644
index 0000000..9de935e
--- /dev/null
+++ b/Help/guide/importing-exporting/MathFunctionsComponents/Addition/CMakeLists.txt
@@ -0,0 +1,30 @@
+# create library
+add_library(Addition STATIC Addition.cxx)
+
+add_library(MathFunctions::Addition ALIAS Addition)
+
+# add include directories
+target_include_directories(Addition
+ PUBLIC
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+# install the target and create export-set
+install(TARGETS Addition
+ EXPORT AdditionTargets
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+)
+
+# install header file
+install(FILES Addition.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+# generate and install export file
+install(EXPORT AdditionTargets
+ FILE MathFunctionsAdditionTargets.cmake
+ NAMESPACE MathFunctions::
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
+)
diff --git a/Help/guide/importing-exporting/MathFunctionsComponents/CMakeLists.txt b/Help/guide/importing-exporting/MathFunctionsComponents/CMakeLists.txt
new file mode 100644
index 0000000..90ee89f
--- /dev/null
+++ b/Help/guide/importing-exporting/MathFunctionsComponents/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 3.15)
+project(MathFunctionsComponents)
+
+# make cache variables for install destinations
+include(GNUInstallDirs)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+add_subdirectory(Addition)
+add_subdirectory(SquareRoot)
+
+# include CMakePackageConfigHelpers macro
+include(CMakePackageConfigHelpers)
+
+# set version
+set(version 3.4.1)
+
+# generate the version file for the config file
+write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
+ VERSION "${version}"
+ COMPATIBILITY AnyNewerVersion
+)
+
+# create config file
+configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
+ "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
+ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
+ NO_CHECK_REQUIRED_COMPONENTS_MACRO
+)
+
+# install config files
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
+)
diff --git a/Help/guide/importing-exporting/MathFunctionsComponents/Config.cmake.in b/Help/guide/importing-exporting/MathFunctionsComponents/Config.cmake.in
new file mode 100644
index 0000000..09f6c35
--- /dev/null
+++ b/Help/guide/importing-exporting/MathFunctionsComponents/Config.cmake.in
@@ -0,0 +1,11 @@
+@PACKAGE_INIT@
+
+set(_supported_components Addition SquareRoot)
+
+foreach(_comp ${MathFunctions_FIND_COMPONENTS})
+ if (NOT _comp IN_LIST _supported_components)
+ set(MathFunctions_FOUND False)
+ set(MathFunctions_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}")
+ endif()
+ include("${CMAKE_CURRENT_LIST_DIR}/MathFunctions${_comp}Targets.cmake")
+endforeach()
diff --git a/Help/guide/importing-exporting/MathFunctionsComponents/MathFunctions.cxx b/Help/guide/importing-exporting/MathFunctionsComponents/MathFunctions.cxx
new file mode 100644
index 0000000..e75fe74
--- /dev/null
+++ b/Help/guide/importing-exporting/MathFunctionsComponents/MathFunctions.cxx
@@ -0,0 +1,10 @@
+#include "MathFunctions.h"
+
+#include <cmath>
+
+namespace MathFunctions {
+double sqrt(double x)
+{
+ return std::sqrt(x);
+}
+}
diff --git a/Help/guide/importing-exporting/MathFunctionsComponents/MathFunctions.h b/Help/guide/importing-exporting/MathFunctionsComponents/MathFunctions.h
new file mode 100644
index 0000000..b38596d
--- /dev/null
+++ b/Help/guide/importing-exporting/MathFunctionsComponents/MathFunctions.h
@@ -0,0 +1,5 @@
+#pragma once
+
+namespace MathFunctions {
+double sqrt(double x);
+}
diff --git a/Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/CMakeLists.txt b/Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/CMakeLists.txt
new file mode 100644
index 0000000..517c5e2
--- /dev/null
+++ b/Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/CMakeLists.txt
@@ -0,0 +1,30 @@
+# create library
+add_library(SquareRoot STATIC SquareRoot.cxx)
+
+add_library(MathFunctions::SquareRoot ALIAS SquareRoot)
+
+# add include directories
+target_include_directories(SquareRoot
+ PUBLIC
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
+ "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
+)
+
+# install the target and create export-set
+install(TARGETS SquareRoot
+ EXPORT SquareRootTargets
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+)
+
+# install header file
+install(FILES SquareRoot.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+# generate and install export file
+install(EXPORT SquareRootTargets
+ FILE MathFunctionsSquareRootTargets.cmake
+ NAMESPACE MathFunctions::
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
+)
diff --git a/Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/SquareRoot.cxx b/Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/SquareRoot.cxx
new file mode 100644
index 0000000..29c0c4a
--- /dev/null
+++ b/Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/SquareRoot.cxx
@@ -0,0 +1,10 @@
+#include "SquareRoot.h"
+
+#include <cmath>
+
+namespace MathFunctions {
+double sqrt(double x)
+{
+ return std::sqrt(x);
+}
+}
diff --git a/Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/SquareRoot.h b/Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/SquareRoot.h
new file mode 100644
index 0000000..b38596d
--- /dev/null
+++ b/Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/SquareRoot.h
@@ -0,0 +1,5 @@
+#pragma once
+
+namespace MathFunctions {
+double sqrt(double x);
+}
diff --git a/Help/guide/importing-exporting/MyExe/CMakeLists.txt b/Help/guide/importing-exporting/MyExe/CMakeLists.txt
new file mode 100644
index 0000000..34e37a4
--- /dev/null
+++ b/Help/guide/importing-exporting/MyExe/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.15)
+project(MyExe)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# Add executable
+add_executable(myexe main.cxx)
+
+# install executable
+install(TARGETS myexe)
diff --git a/Help/guide/importing-exporting/MyExe/main.cxx b/Help/guide/importing-exporting/MyExe/main.cxx
new file mode 100644
index 0000000..35ab2a7
--- /dev/null
+++ b/Help/guide/importing-exporting/MyExe/main.cxx
@@ -0,0 +1,16 @@
+// A simple program that outputs a file with the given name
+#include <fstream>
+#include <iostream>
+
+int main(int argc, char* argv[])
+{
+ std::ofstream outfile("main.cc");
+ outfile << "int main(int argc, char* argv[])" << std::endl;
+ outfile << "{" << std::endl;
+ outfile << " // Your code here" << std::endl;
+ outfile << " return 0;" << std::endl;
+ outfile << "}" << std::endl;
+ outfile.close();
+
+ return 0;
+}
diff --git a/Help/guide/importing-exporting/index.rst b/Help/guide/importing-exporting/index.rst
new file mode 100644
index 0000000..3e60250
--- /dev/null
+++ b/Help/guide/importing-exporting/index.rst
@@ -0,0 +1,772 @@
+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
+from one CMake-based project and importing them into another. Finally, we
+will demonstrate how to package a project with a configuration file to allow
+for easy integration into other CMake projects. This guide and the complete
+example source code can be found in the ``Help/guide/importing-exporting``
+directory of the CMake source code tree.
+
+
+Importing Targets
+=================
+
+:prop_tgt:`IMPORTED` targets are used to convert files outside of a CMake
+project into logical targets inside of the project. :prop_tgt:`IMPORTED`
+targets are created using the ``IMPORTED`` option of the
+:command:`add_executable` and :command:`add_library` commands. No build
+files are generated for :prop_tgt:`IMPORTED` targets. Once imported,
+:prop_tgt:`IMPORTED` targets may be referenced like any other target within
+the project and provide a convenient, flexible reference to outside
+executables and libraries.
+
+By default, the :prop_tgt:`IMPORTED` target name has scope in the directory in
+which it is created and below. We can use the ``GLOBAL`` option to extended
+visibility so that the target is accessible globally in the build system.
+
+Details about the :prop_tgt:`IMPORTED` target are specified by setting
+properties whose names begin in ``IMPORTED_`` and ``INTERFACE_``. For example,
+:prop_tgt:`IMPORTED_LOCATION` contains the full path to the target on
+disk.
+
+Importing Executables
+---------------------
+
+To start, we will walk through a simple example that creates an
+:prop_tgt:`IMPORTED` executable target and then references it from the
+:command:`add_custom_command` command.
+
+We'll need to do some setup to get started. We want to create an executable
+that when run creates a basic ``main.cc`` file in the current directory. The
+details of this project are not important. Navigate to
+``Help/guide/importing-exporting/MyExe``, create a build directory, run
+:manual:`cmake <cmake(1)>` and build and install the project.
+
+.. code-block:: console
+
+ $ cd Help/guide/importing-exporting/MyExe
+ $ mkdir build
+ $ cd build
+ $ cmake ..
+ $ cmake --build .
+ $ cmake --install . --prefix <install location>
+ $ <install location>/myexe
+ $ ls
+ [...] main.cc [...]
+
+Now we can import this executable into another CMake project. The source code
+for this section is available in ``Help/guide/importing-exporting/Importing``.
+In the CMakeLists file, use the :command:`add_executable` command to create a
+new target called ``myexe``. Use the ``IMPORTED`` option to tell CMake that
+this target references an executable file located outside of the project. No
+rules will be generated to build it and the :prop_tgt:`IMPORTED` target
+property will be set to ``true``.
+
+.. literalinclude:: Importing/CMakeLists.txt
+ :language: cmake
+ :start-after: # Add executable
+ :end-before: # Set imported location
+
+Next, set the :prop_tgt:`IMPORTED_LOCATION` property of the target using
+the :command:`set_property` command. This will tell CMake the location of the
+target on disk. The location may need to be adjusted to the
+``<install location>`` specified in the previous step.
+
+.. literalinclude:: Importing/CMakeLists.txt
+ :language: cmake
+ :start-after: # Set imported location
+ :end-before: # Add custom command
+
+We can now reference this :prop_tgt:`IMPORTED` target just like any target
+built within the project. In this instance, let's imagine that we want to use
+the generated source file in our project. Use the :prop_tgt:`IMPORTED`
+target in the :command:`add_custom_command` command:
+
+.. literalinclude:: Importing/CMakeLists.txt
+ :language: cmake
+ :start-after: # Add custom command
+ :end-before: # Use source file
+
+As ``COMMAND`` specifies an executable target name, it will automatically be
+replaced by the location of the executable given by the
+:prop_tgt:`IMPORTED_LOCATION` property above.
+
+Finally, use the output from :command:`add_custom_command`:
+
+.. literalinclude:: Importing/CMakeLists.txt
+ :language: cmake
+ :start-after: # Use source file
+
+Importing Libraries
+-------------------
+
+In a similar manner, libraries from other projects may be accessed through
+:prop_tgt:`IMPORTED` targets.
+
+Note: The full source code for the examples in this section is not provided
+and is left as an exercise for the reader.
+
+In the CMakeLists file, add an :prop_tgt:`IMPORTED` library and specify its
+location on disk:
+
+.. code-block:: cmake
+
+ add_library(foo STATIC IMPORTED)
+ set_property(TARGET foo PROPERTY
+ IMPORTED_LOCATION "/path/to/libfoo.a")
+
+Then use the :prop_tgt:`IMPORTED` library inside of our project:
+
+.. code-block:: cmake
+
+ add_executable(myexe src1.c src2.c)
+ target_link_libraries(myexe PRIVATE foo)
+
+
+On Windows, a .dll and its .lib import library may be imported together:
+
+.. code-block:: cmake
+
+ add_library(bar SHARED IMPORTED)
+ set_property(TARGET bar PROPERTY
+ IMPORTED_LOCATION "c:/path/to/bar.dll")
+ set_property(TARGET bar PROPERTY
+ IMPORTED_IMPLIB "c:/path/to/bar.lib")
+ add_executable(myexe src1.c src2.c)
+ target_link_libraries(myexe PRIVATE bar)
+
+A library with multiple configurations may be imported with a single target:
+
+.. code-block:: cmake
+
+ find_library(math_REL NAMES m)
+ find_library(math_DBG NAMES md)
+ add_library(math STATIC IMPORTED GLOBAL)
+ set_target_properties(math PROPERTIES
+ IMPORTED_LOCATION "${math_REL}"
+ IMPORTED_LOCATION_DEBUG "${math_DBG}"
+ IMPORTED_CONFIGURATIONS "RELEASE;DEBUG"
+ )
+ add_executable(myexe src1.c src2.c)
+ target_link_libraries(myexe PRIVATE math)
+
+The generated build system will link ``myexe`` to ``m.lib`` when built in the
+release configuration, and ``md.lib`` when built in the debug configuration.
+
+Exporting Targets
+=================
+
+While :prop_tgt:`IMPORTED` targets on their own are useful, they still
+require that the project that imports them knows the locations of the target
+files on disk. The real power of :prop_tgt:`IMPORTED` targets is when the
+project providing the target files also provides a CMake file to help import
+them. A project can be setup to produce the necessary information so that it
+can easily be used by other CMake projects be it from a build directory, a
+local install or when packaged.
+
+In the remaining sections, we will walk through a set of example projects
+step-by-step. The first project will create and install a library and
+corresponding CMake configuration and package files. The second project will
+use the generated package.
+
+Let's start by looking at the ``MathFunctions`` project in the
+``Help/guide/importing-exporting/MathFunctions`` directory. Here we have a
+header file ``MathFunctions.h`` that declares a ``sqrt`` function:
+
+.. literalinclude:: MathFunctions/MathFunctions.h
+ :language: c++
+
+And a corresponding source file ``MathFunctions.cxx``:
+
+.. literalinclude:: MathFunctions/MathFunctions.cxx
+ :language: c++
+
+Don't worry too much about the specifics of the C++ files, they are just meant
+to be a simple example that will compile and run on many build systems.
+
+Now we can create a ``CMakeLists.txt`` file for the ``MathFunctions``
+project. Start by specifying the :command:`cmake_minimum_required` version and
+:command:`project` name:
+
+.. literalinclude:: MathFunctions/CMakeLists.txt
+ :language: cmake
+ :end-before: # create library
+
+The :module:`GNUInstallDirs` module is included in order to provide the
+project with the flexibility to install into different platform layouts by
+making the directories available as cache variables.
+
+Create a library called ``MathFunctions`` with the :command:`add_library`
+command:
+
+.. literalinclude:: MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # create library
+ :end-before: # add include directories
+
+And then use the :command:`target_include_directories` command to specify the
+include directories for the target:
+
+.. literalinclude:: MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # add include directories
+ :end-before: # install the target and create export-set
+
+We need to tell CMake that we want to use different include directories
+depending on if we're building the library or using it from an installed
+location. If we don't do this, when CMake creates the export information it
+will export a path that is specific to the current build directory
+and will not be valid for other projects. We can use
+:manual:`generator expressions <cmake-generator-expressions(7)>` to specify
+that if we're building the library include the current source directory.
+Otherwise, when installed, include the ``include`` directory. See the `Creating
+Relocatable Packages`_ section for more details.
+
+The :command:`install(TARGETS)` and :command:`install(EXPORT)` commands
+work together to install both targets (a library in our case) and a CMake
+file designed to make it easy to import the targets into another CMake project.
+
+First, in the :command:`install(TARGETS)` command we will specify the target,
+the ``EXPORT`` name and the destinations that tell CMake where to install the
+targets.
+
+.. literalinclude:: MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # install the target and create export-set
+ :end-before: # install header file
+
+Here, the ``EXPORT`` option tells CMake to create an export called
+``MathFunctionsTargets``. The generated :prop_tgt:`IMPORTED` targets have
+appropriate properties set to define their
+:ref:`usage requirements <Target Usage Requirements>`, such as
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`,
+:prop_tgt:`INTERFACE_COMPILE_DEFINITIONS` and other relevant built-in
+``INTERFACE_`` properties. The ``INTERFACE`` variant of user-defined
+properties listed in :prop_tgt:`COMPATIBLE_INTERFACE_STRING` and other
+:ref:`Compatible Interface Properties` are also propagated to the
+generated :prop_tgt:`IMPORTED` targets. For example, in this case, the
+:prop_tgt:`IMPORTED` target will have its
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` property populated with
+the directory specified by the ``INCLUDES DESTINATION`` property. As a
+relative path was given, it is treated as relative to the
+:variable:`CMAKE_INSTALL_PREFIX`.
+
+Note, we have *not* asked CMake to install the export yet.
+
+We don't want to forget to install the ``MathFunctions.h`` header file with the
+:command:`install(FILES)` command. The header file should be installed to the
+``include`` directory, as specified by the
+:command:`target_include_directories` command above.
+
+.. literalinclude:: MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # install header file
+ :end-before: # generate and install export file
+
+Now that the ``MathFunctions`` library and header file are installed, we also
+need to explicitly install the ``MathFunctionsTargets`` export details. Use
+the :command:`install(EXPORT)` command to export the targets in
+``MathFunctionsTargets``, as defined by the :command:`install(TARGETS)`
+command.
+
+.. literalinclude:: MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # generate and install export file
+ :end-before: # include CMakePackageConfigHelpers macro
+
+This command generates the ``MathFunctionsTargets.cmake`` file and arranges
+to install it to ``lib/cmake``. The file contains code suitable for
+use by downstreams to import all targets listed in the install command from
+the installation tree.
+
+The ``NAMESPACE`` option will prepend ``MathFunctions::`` to the target names
+as they are written to the export file. This convention of double-colons
+gives CMake a hint that the name is an :prop_tgt:`IMPORTED` target when it
+is used by downstream projects. This way, CMake can issue a diagnostic
+message if the package providing it was not found.
+
+The generated export file contains code that creates an :prop_tgt:`IMPORTED` library.
+
+.. code-block:: cmake
+
+ # Create imported target MathFunctions::MathFunctions
+ add_library(MathFunctions::MathFunctions STATIC IMPORTED)
+
+ set_target_properties(MathFunctions::MathFunctions PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
+ )
+
+This code is very similar to the example we created by hand in the
+`Importing Libraries`_ section. Note that ``${_IMPORT_PREFIX}`` is computed
+relative to the file location.
+
+An outside project may load this file with the :command:`include` command and
+reference the ``MathFunctions`` library from the installation tree as if it
+were built in its own tree. For example:
+
+.. code-block:: cmake
+ :linenos:
+
+ include(${INSTALL_PREFIX}/lib/cmake/MathFunctionTargets.cmake)
+ add_executable(myexe src1.c src2.c )
+ target_link_libraries(myexe PRIVATE MathFunctions::MathFunctions)
+
+Line 1 loads the target CMake file. Although we only exported a single
+target, this file may import any number of targets. Their locations are
+computed relative to the file location so that the install tree may be
+easily moved. Line 3 references the imported ``MathFunctions`` library. The
+resulting build system will link to the library from its installed location.
+
+Executables may also be exported and imported using the same process.
+
+Any number of target installations may be associated with the same
+export name. Export names are considered global so any directory may
+contribute a target installation. The :command:`install(EXPORT)` command only
+needs to be called once to install a file that references all targets. Below
+is an example of how multiple exports may be combined into a single
+export file, even if they are in different subdirectories of the project.
+
+.. code-block:: cmake
+
+ # A/CMakeLists.txt
+ add_executable(myexe src1.c)
+ install(TARGETS myexe DESTINATION lib/myproj
+ EXPORT myproj-targets)
+
+ # B/CMakeLists.txt
+ add_library(foo STATIC foo1.c)
+ install(TARGETS foo DESTINATION lib EXPORTS myproj-targets)
+
+ # Top CMakeLists.txt
+ add_subdirectory (A)
+ add_subdirectory (B)
+ install(EXPORT myproj-targets DESTINATION lib/myproj)
+
+Creating Packages
+-----------------
+
+At this point, the ``MathFunctions`` project is exporting the target
+information required to be used by other projects. We can make this project
+even easier for other projects to use by generating a configuration file so
+that the CMake :command:`find_package` command can find our project.
+
+To start, we will need to make a few additions to the ``CMakeLists.txt``
+file. First, include the :module:`CMakePackageConfigHelpers` module to get
+access to some helper functions for creating config files.
+
+.. literalinclude:: MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # include CMakePackageConfigHelpers macro
+ :end-before: # set version
+
+Then we will create a package configuration file and a package version file.
+
+Creating a Package Configuration File
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use the :command:`configure_package_config_file` command provided by the
+:module:`CMakePackageConfigHelpers` to generate the package configuration
+file. Note that this command should be used instead of the plain
+:command:`configure_file` command. It helps to ensure that the resulting
+package is relocatable by avoiding hardcoded paths in the installed
+configuration file. The path given to ``INSTALL_DESTINATION`` must be the
+destination where the ``MathFunctionsConfig.cmake`` file will be installed.
+We will examine the contents of the package configuration file in the next
+section.
+
+.. literalinclude:: MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # create config file
+ :end-before: # install config files
+
+Install the generated configuration files with the :command:`INSTALL(files)`
+command. Both ``MathFunctionsConfigVersion.cmake`` and
+``MathFunctionsConfig.cmake`` are installed to the same location, completing
+the package.
+
+.. literalinclude:: MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # install config files
+ :end-before: # generate the export targets for the build tree
+
+Now we need to create the package configuration file itself. In this case, the
+``Config.cmake.in`` file is very simple but sufficient to allow downstreams
+to use the :prop_tgt:`IMPORTED` targets.
+
+.. literalinclude:: MathFunctions/Config.cmake.in
+
+The first line of the file contains only the string ``@PACKAGE_INIT@``. This
+expands when the file is configured and allows the use of relocatable paths
+prefixed with ``PACKAGE_``. It also provides the ``set_and_check()`` and
+``check_required_components()`` macros.
+
+The ``check_required_components`` helper macro ensures that all requested,
+non-optional components have been found by checking the
+``<Package>_<Component>_FOUND`` variables for all required components. This
+macro should be called at the end of the package configuration file even if the
+package does not have any components. This way, CMake can make sure that the
+downstream project hasn't specified any non-existent components. If
+``check_required_components`` fails, the ``<Package>_FOUND`` variable is set to
+FALSE, and the package is considered to be not found.
+
+The ``set_and_check()`` macro should be used in configuration files instead
+of the normal ``set()`` command for setting directories and file locations.
+If a referenced file or directory does not exist, the macro will fail.
+
+If any macros should be provided by the ``MathFunctions`` package, they should
+be in a separate file which is installed to the same location as the
+``MathFunctionsConfig.cmake`` file, and included from there.
+
+**All required dependencies of a package must also be found in the package
+configuration file.** Let's imagine that we require the ``Stats`` library in
+our project. In the CMakeLists file, we would add:
+
+.. code-block:: cmake
+
+ find_package(Stats 2.6.4 REQUIRED)
+ target_link_libraries(MathFunctions PUBLIC Stats::Types)
+
+As the ``Stats::Types`` target is a ``PUBLIC`` dependency of ``MathFunctions``,
+downstreams must also find the ``Stats`` package and link to the
+``Stats::Types`` library. The ``Stats`` package should be found in the
+configuration file to ensure this.
+
+.. code-block:: cmake
+
+ include(CMakeFindDependencyMacro)
+ find_dependency(Stats 2.6.4)
+
+The ``find_dependency`` macro from the :module:`CMakeFindDependencyMacro`
+module helps by propagating whether the package is ``REQUIRED``, or
+``QUIET``, etc. The ``find_dependency`` macro also sets
+``MathFunctions_FOUND`` to ``False`` if the dependency is not found, along
+with a diagnostic that the ``MathFunctions`` package cannot be used without
+the ``Stats`` package.
+
+**Exercise:** Add a required library to the ``MathFunctions`` project.
+
+Creating a Package Version File
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The :module:`CMakePackageConfigHelpers` module provides the
+:command:`write_basic_package_version_file` command for creating a simple
+package version file. This file is read by CMake when :command:`find_package`
+is called to determine the compatibility with the requested version, and to set
+some version-specific variables such as ``<PackageName>_VERSION``,
+``<PackageName>_VERSION_MAJOR``, ``<PackageName>_VERSION_MINOR``, etc. See
+:manual:`cmake-packages <cmake-packages(7)>` documentation for more details.
+
+.. literalinclude:: MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # set version
+ :end-before: # create config file
+
+In our example, ``MathFunctions_MAJOR_VERSION`` is defined as a
+:prop_tgt:`COMPATIBLE_INTERFACE_STRING` which means that it must be
+compatible among the dependencies of any depender. By setting this
+custom defined user property in this version and in the next version of
+``MathFunctions``, :manual:`cmake <cmake(1)>` will issue a diagnostic if
+there is an attempt to use version 3 together with version 4. Packages can
+choose to employ such a pattern if different major versions of the package
+are designed to be incompatible.
+
+
+Exporting Targets from the Build Tree
+-------------------------------------
+
+Typically, projects are built and installed before being used by an outside
+project. However, in some cases, it is desirable to export targets directly
+from a build tree. The targets may then be used by an outside project that
+references the build tree with no installation involved. The :command:`export`
+command is used to generate a file exporting targets from a project build tree.
+
+If we want our example project to also be used from a build directory we only
+have to add the following to ``CMakeLists.txt``:
+
+.. literalinclude:: MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # generate the export targets for the build tree
+
+Here we use the :command:`export` command to generate the export targets for
+the build tree. In this case, we'll create a file called
+``MathFunctionsTargets.cmake`` in the ``cmake`` subdirectory of the build
+directory. The generated file contains the required code to import the target
+and may be loaded by an outside project that is aware of the project build
+tree. This file is specific to the build-tree, and **is not relocatable**.
+
+It is possible to create a suitable package configuration file and package
+version file to define a package for the build tree which may be used without
+installation. Consumers of the build tree can simply ensure that the
+:variable:`CMAKE_PREFIX_PATH` contains the build directory, or set the
+``MathFunctions_DIR`` to ``<build_dir>/MathFunctions`` in the cache.
+
+An example application of this feature is for building an executable on a host
+platform when cross-compiling. The project containing the executable may be
+built on the host platform and then the project that is being cross-compiled
+for another platform may load it.
+
+Building and Installing a Package
+---------------------------------
+
+At this point, we have generated a relocatable CMake configuration for our
+project that can be used after the project has been installed. Let's try to
+build the ``MathFunctions`` project:
+
+.. code-block:: console
+
+ mkdir MathFunctions_build
+ cd MathFunctions_build
+ cmake ../MathFunctions
+ cmake --build .
+
+In the build directory, notice that the file ``MathFunctionsTargets.cmake``
+has been created in the ``cmake`` subdirectory.
+
+Now install the project:
+
+.. code-block:: console
+
+ $ cmake --install . --prefix "/home/myuser/installdir"
+
+Creating Relocatable Packages
+=============================
+
+Packages created by :command:`install(EXPORT)` are designed to be relocatable,
+using paths relative to the location of the package itself. They must not
+reference absolute paths of files on the machine where the package is built
+that will not exist on the machines where the package may be installed.
+
+When defining the interface of a target for ``EXPORT``, keep in mind that the
+include directories should be specified as relative paths to the
+:variable:`CMAKE_INSTALL_PREFIX` but should not explicitly include the
+:variable:`CMAKE_INSTALL_PREFIX`:
+
+.. code-block:: cmake
+
+ target_include_directories(tgt INTERFACE
+ # Wrong, not relocatable:
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include/TgtName>
+ )
+
+ target_include_directories(tgt INTERFACE
+ # Ok, relocatable:
+ $<INSTALL_INTERFACE:include/TgtName>
+ )
+
+The ``$<INSTALL_PREFIX>``
+:manual:`generator expression <cmake-generator-expressions(7)>` may be used as
+a placeholder for the install prefix without resulting in a non-relocatable
+package. This is necessary if complex generator expressions are used:
+
+.. code-block:: cmake
+
+ target_include_directories(tgt INTERFACE
+ # Ok, relocatable:
+ $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include/TgtName>
+ )
+
+This also applies to paths referencing external dependencies.
+It is not advisable to populate any properties which may contain
+paths, such as :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` or
+:prop_tgt:`INTERFACE_LINK_LIBRARIES`, with paths relevant to dependencies.
+For example, this code may not work well for a relocatable package:
+
+.. code-block:: cmake
+
+ target_link_libraries(MathFunctions INTERFACE
+ ${Foo_LIBRARIES} ${Bar_LIBRARIES}
+ )
+ target_include_directories(MathFunctions INTERFACE
+ "$<INSTALL_INTERFACE:${Foo_INCLUDE_DIRS};${Bar_INCLUDE_DIRS}>"
+ )
+
+The referenced variables may contain the absolute paths to libraries
+and include directories **as found on the machine the package was made on**.
+This would create a package with hard-coded paths to dependencies not
+suitable for relocation.
+
+Ideally such dependencies should be used through their own
+:ref:`IMPORTED targets <Imported Targets>` that have their own
+:prop_tgt:`IMPORTED_LOCATION` and usage requirement properties
+such as :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` populated
+appropriately. Those imported targets may then be used with
+the :command:`target_link_libraries` command for ``MathFunctions``:
+
+.. code-block:: cmake
+
+ target_link_libraries(MathFunctions INTERFACE Foo::Foo Bar::Bar)
+
+With this approach the package references its external dependencies
+only through the names of :ref:`IMPORTED targets <Imported Targets>`.
+When a consumer uses the installed package, the consumer will run the
+appropriate :command:`find_package` commands (via the ``find_dependency``
+macro described above) to find the dependencies and populate the
+imported targets with appropriate paths on their own machine.
+
+Using the Package Configuration File
+====================================
+
+Now we're ready to create a project to use the installed ``MathFunctions``
+library. In this section we will be using source code from
+``Help\guide\importing-exporting\Downstream``. In this directory, there is a
+source file called ``main.cc`` that uses the ``MathFunctions`` library to
+calculate the square root of a given number and then prints the results:
+
+.. literalinclude:: Downstream/main.cc
+ :language: c++
+
+As before, we'll start with the :command:`cmake_minimum_required` and
+:command:`project` commands in the ``CMakeLists.txt`` file. For this project,
+we'll also specify the C++ standard.
+
+.. literalinclude:: Downstream/CMakeLists.txt
+ :language: cmake
+ :end-before: # find MathFunctions
+
+We can use the :command:`find_package` command:
+
+.. literalinclude:: Downstream/CMakeLists.txt
+ :language: cmake
+ :start-after: # find MathFunctions
+ :end-before: # create executable
+
+Create an exectuable:
+
+.. literalinclude:: Downstream/CMakeLists.txt
+ :language: cmake
+ :start-after: # create executable
+ :end-before: # use MathFunctions library
+
+And link to the ``MathFunctions`` library:
+
+.. literalinclude:: Downstream/CMakeLists.txt
+ :language: cmake
+ :start-after: # use MathFunctions library
+
+That's it! Now let's try to build the ``Downstream`` project.
+
+.. code-block:: console
+
+ mkdir Downstream_build
+ cd Downstream_build
+ cmake ../Downstream
+ cmake --build .
+
+A warning may have appeared during CMake configuration:
+
+.. code-block:: console
+
+ CMake Warning at CMakeLists.txt:4 (find_package):
+ By not providing "FindMathFunctions.cmake" in CMAKE_MODULE_PATH this
+ project has asked CMake to find a package configuration file provided by
+ "MathFunctions", but CMake did not find one.
+
+ Could not find a package configuration file provided by "MathFunctions"
+ with any of the following names:
+
+ MathFunctionsConfig.cmake
+ mathfunctions-config.cmake
+
+ Add the installation prefix of "MathFunctions" to CMAKE_PREFIX_PATH or set
+ "MathFunctions_DIR" to a directory containing one of the above files. If
+ "MathFunctions" provides a separate development package or SDK, be sure it
+ has been installed.
+
+Set the ``CMAKE_PREFIX_PATH`` to where MathFunctions was installed previously
+and try again. Ensure that the newly created executable runs as expected.
+
+Adding Components
+=================
+
+Let's edit the ``MathFunctions`` project to use components. The source code for
+this section can be found in
+``Help\guide\importing-exporting\MathFunctionsComponents``. The CMakeLists file
+for this project adds two subdirectories: ``Addition`` and ``SquareRoot``.
+
+.. literalinclude:: MathFunctionsComponents/CMakeLists.txt
+ :language: cmake
+ :end-before: # include CMakePackageConfigHelpers macro
+
+Generate and install the package configuration and package version files:
+
+.. literalinclude:: MathFunctionsComponents/CMakeLists.txt
+ :language: cmake
+ :start-after: # include CMakePackageConfigHelpers macro
+
+If ``COMPONENTS`` are specified when the downstream uses
+:command:`find_package`, they are listed in the
+``<PackageName>_FIND_COMPONENTS`` variable. We can use this variable to verify
+that all necessary component targets are included in ``Config.cmake.in``. At
+the same time, this function will act as a custom ``check_required_components``
+macro to ensure that the downstream only attempts to use supported components.
+
+.. literalinclude:: MathFunctionsComponents/Config.cmake.in
+
+Here, the ``MathFunctions_NOT_FOUND_MESSAGE`` is set to a diagnosis that the
+package could not be found because an invalid component was specified. This
+message variable can be set for any case where the ``_FOUND`` variable is set
+to ``False``, and will be displayed to the user.
+
+The ``Addition`` and ``SquareRoot`` directories are similar. Let's look at one
+of the CMakeLists files:
+
+.. literalinclude:: MathFunctionsComponents/SquareRoot/CMakeLists.txt
+ :language: cmake
+
+Now we can build the project as described in earlier sections. To test using
+this package, we can use the project in
+``Help\guide\importing-exporting\DownstreamComponents``. There's two
+differences from the previous ``Downstream`` project. First, we need to find
+the package components. Change the ``find_package`` line from:
+
+.. literalinclude:: Downstream/CMakeLists.txt
+ :language: cmake
+ :start-after: # find MathFunctions
+ :end-before: # create executable
+
+To:
+
+.. literalinclude:: DownstreamComponents/CMakeLists.txt
+ :language: cmake
+ :start-after: # find MathFunctions
+ :end-before: # create executable
+
+and the ``target_link_libraries`` line from:
+
+.. literalinclude:: Downstream/CMakeLists.txt
+ :language: cmake
+ :start-after: # use MathFunctions library
+
+To:
+
+.. literalinclude:: DownstreamComponents/CMakeLists.txt
+ :language: cmake
+ :start-after: # use MathFunctions library
+ :end-before: # Workaround for GCC on AIX to avoid -isystem
+
+In ``main.cc``, replace ``#include MathFunctions.h`` with:
+
+.. literalinclude:: DownstreamComponents/main.cc
+ :language: c
+ :start-after: #include <string>
+ :end-before: int main
+
+Finally, use the ``Addition`` library:
+
+.. literalinclude:: DownstreamComponents/main.cc
+ :language: c
+ :start-after: // calculate sum
+ :end-before: return 0;
+
+Build the ``Downstream`` project and confirm that it can find and use the
+package components.
diff --git a/Help/guide/tutorial/Complete/CMakeLists.txt b/Help/guide/tutorial/Complete/CMakeLists.txt
new file mode 100644
index 0000000..4d8a3ad
--- /dev/null
+++ b/Help/guide/tutorial/Complete/CMakeLists.txt
@@ -0,0 +1,124 @@
+cmake_minimum_required(VERSION 3.15)
+
+# set the project name and version
+project(Tutorial VERSION 1.0)
+
+set(CMAKE_DEBUG_POSTFIX d)
+
+add_library(tutorial_compiler_flags INTERFACE)
+target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
+
+# add compiler warning flags just when building this project via
+# the BUILD_INTERFACE genex
+set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU>")
+set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
+target_compile_options(tutorial_compiler_flags INTERFACE
+ "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>"
+ "$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
+)
+
+# control where the static and shared libraries are built so that on windows
+# we don't need to tinker with the path to run the executable
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+
+option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
+
+if(APPLE)
+ set(CMAKE_INSTALL_RPATH "@executable_path/../lib")
+elseif(UNIX)
+ set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
+endif()
+
+# configure a header file to pass the version number only
+configure_file(TutorialConfig.h.in TutorialConfig.h)
+
+# add the MathFunctions library
+add_subdirectory(MathFunctions)
+
+# add the executable
+add_executable(Tutorial tutorial.cxx)
+set_target_properties(Tutorial PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
+
+target_link_libraries(Tutorial PUBLIC MathFunctions)
+
+# add the binary tree to the search path for include files
+# so that we will find TutorialConfig.h
+target_include_directories(Tutorial PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ )
+
+# add the install targets
+install(TARGETS Tutorial DESTINATION bin)
+install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
+ DESTINATION include
+ )
+
+# enable testing
+enable_testing()
+
+# does the application run
+add_test(NAME Runs COMMAND Tutorial 25)
+
+# does the usage message work?
+add_test(NAME Usage COMMAND Tutorial)
+set_tests_properties(Usage
+ PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
+ )
+
+# define a function to simplify adding tests
+function(do_test target arg result)
+ add_test(NAME Comp${arg} COMMAND ${target} ${arg})
+ set_tests_properties(Comp${arg}
+ PROPERTIES PASS_REGULAR_EXPRESSION ${result}
+ )
+endfunction(do_test)
+
+# do a bunch of result based tests
+do_test(Tutorial 4 "4 is 2")
+do_test(Tutorial 9 "9 is 3")
+do_test(Tutorial 5 "5 is 2.236")
+do_test(Tutorial 7 "7 is 2.645")
+do_test(Tutorial 25 "25 is 5")
+do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial 0.0001 "0.0001 is 0.01")
+
+include(InstallRequiredSystemLibraries)
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
+set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
+set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
+include(CPack)
+
+# install the configuration targets
+install(EXPORT MathFunctionsTargets
+ FILE MathFunctionsTargets.cmake
+ DESTINATION lib/cmake/MathFunctions
+)
+
+include(CMakePackageConfigHelpers)
+# generate the config file that is includes the exports
+configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
+ "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
+ INSTALL_DESTINATION "lib/cmake/example"
+ NO_SET_AND_CHECK_MACRO
+ NO_CHECK_REQUIRED_COMPONENTS_MACRO
+ )
+# generate the version file for the config file
+write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
+ VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}"
+ COMPATIBILITY AnyNewerVersion
+)
+
+# install the configuration file
+install(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
+ DESTINATION lib/cmake/MathFunctions
+ )
+
+# generate the export targets for the build tree
+# needs to be after the install(TARGETS ) command
+export(EXPORT MathFunctionsTargets
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake"
+)
diff --git a/Help/guide/tutorial/Complete/CTestConfig.cmake b/Help/guide/tutorial/Complete/CTestConfig.cmake
new file mode 100644
index 0000000..73efdb1
--- /dev/null
+++ b/Help/guide/tutorial/Complete/CTestConfig.cmake
@@ -0,0 +1,7 @@
+set(CTEST_PROJECT_NAME "CMakeTutorial")
+set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
+
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "my.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial")
+set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/Help/guide/tutorial/Complete/Config.cmake.in b/Help/guide/tutorial/Complete/Config.cmake.in
new file mode 100644
index 0000000..17cbabd
--- /dev/null
+++ b/Help/guide/tutorial/Complete/Config.cmake.in
@@ -0,0 +1,4 @@
+
+@PACKAGE_INIT@
+
+include ( "${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )
diff --git a/Help/guide/tutorial/Complete/License.txt b/Help/guide/tutorial/Complete/License.txt
new file mode 100644
index 0000000..c62d00b
--- /dev/null
+++ b/Help/guide/tutorial/Complete/License.txt
@@ -0,0 +1,2 @@
+This is the open source License.txt file introduced in
+CMake/Tutorial/Step7...
diff --git a/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..a47d5e0
--- /dev/null
+++ b/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt
@@ -0,0 +1,67 @@
+# add the library that runs
+add_library(MathFunctions MathFunctions.cxx)
+
+# state that anybody linking to us needs to include the current source dir
+# to find MathFunctions.h, while we don't.
+target_include_directories(MathFunctions
+ INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ $<INSTALL_INTERFACE:include>
+ )
+
+# should we use our own math functions
+option(USE_MYMATH "Use tutorial provided math implementation" ON)
+if(USE_MYMATH)
+
+ target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
+
+ # first we add the executable that generates the table
+ add_executable(MakeTable MakeTable.cxx)
+ target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags)
+
+ # add the command to generate the source code
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ DEPENDS MakeTable
+ )
+
+ # library that just does sqrt
+ add_library(SqrtLibrary STATIC
+ mysqrt.cxx
+ ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ )
+
+ # state that we depend on our binary dir to find Table.h
+ target_include_directories(SqrtLibrary PRIVATE
+ ${CMAKE_CURRENT_BINARY_DIR}
+ )
+
+ # state that SqrtLibrary need PIC when the default is shared libraries
+ set_target_properties(SqrtLibrary PROPERTIES
+ POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
+ )
+
+ target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
+ target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
+endif()
+
+target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
+
+# define the symbol stating we are using the declspec(dllexport) when
+# building on windows
+target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
+
+# setup the version numbering
+set_property(TARGET MathFunctions PROPERTY VERSION "1.0.0")
+set_property(TARGET MathFunctions PROPERTY SOVERSION "1")
+
+# install rules
+set(installable_libs MathFunctions tutorial_compiler_flags)
+if(TARGET SqrtLibrary)
+ list(APPEND installable_libs SqrtLibrary)
+endif()
+install(TARGETS ${installable_libs}
+ DESTINATION lib
+ EXPORT MathFunctionsTargets)
+install(FILES MathFunctions.h DESTINATION include)
diff --git a/Help/guide/tutorial/Complete/MathFunctions/MakeTable.cxx b/Help/guide/tutorial/Complete/MathFunctions/MakeTable.cxx
new file mode 100644
index 0000000..ee58556
--- /dev/null
+++ b/Help/guide/tutorial/Complete/MathFunctions/MakeTable.cxx
@@ -0,0 +1,25 @@
+// A simple program that builds a sqrt table
+#include <cmath>
+#include <fstream>
+#include <iostream>
+
+int main(int argc, char* argv[])
+{
+ // make sure we have enough arguments
+ if (argc < 2) {
+ return 1;
+ }
+
+ std::ofstream fout(argv[1], std::ios_base::out);
+ const bool fileOpen = fout.is_open();
+ if (fileOpen) {
+ fout << "double sqrtTable[] = {" << std::endl;
+ for (int i = 0; i < 10; ++i) {
+ fout << sqrt(static_cast<double>(i)) << "," << std::endl;
+ }
+ // close the table with a zero
+ fout << "0};" << std::endl;
+ fout.close();
+ }
+ return fileOpen ? 0 : 1; // return 0 if wrote the file
+}
diff --git a/Help/guide/tutorial/Complete/MathFunctions/MathFunctions.cxx b/Help/guide/tutorial/Complete/MathFunctions/MathFunctions.cxx
new file mode 100644
index 0000000..0145300
--- /dev/null
+++ b/Help/guide/tutorial/Complete/MathFunctions/MathFunctions.cxx
@@ -0,0 +1,19 @@
+
+#include "MathFunctions.h"
+
+#include <cmath>
+
+#ifdef USE_MYMATH
+# include "mysqrt.h"
+#endif
+
+namespace mathfunctions {
+double sqrt(double x)
+{
+#ifdef USE_MYMATH
+ return detail::mysqrt(x);
+#else
+ return std::sqrt(x);
+#endif
+}
+}
diff --git a/Help/guide/tutorial/Complete/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Complete/MathFunctions/MathFunctions.h
new file mode 100644
index 0000000..3fb547b
--- /dev/null
+++ b/Help/guide/tutorial/Complete/MathFunctions/MathFunctions.h
@@ -0,0 +1,14 @@
+
+#if defined(_WIN32)
+# if defined(EXPORTING_MYMATH)
+# define DECLSPEC __declspec(dllexport)
+# else
+# define DECLSPEC __declspec(dllimport)
+# endif
+#else // non windows
+# define DECLSPEC
+#endif
+
+namespace mathfunctions {
+double DECLSPEC sqrt(double x);
+}
diff --git a/Help/guide/tutorial/Complete/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Complete/MathFunctions/mysqrt.cxx
new file mode 100644
index 0000000..8153f18
--- /dev/null
+++ b/Help/guide/tutorial/Complete/MathFunctions/mysqrt.cxx
@@ -0,0 +1,37 @@
+#include <iostream>
+
+#include "MathFunctions.h"
+
+// include the generated table
+#include "Table.h"
+
+namespace mathfunctions {
+namespace detail {
+// a hack square root calculation using simple operations
+double mysqrt(double x)
+{
+ if (x <= 0) {
+ return 0;
+ }
+
+ // use the table to help find an initial value
+ double result = x;
+ if (x >= 1 && x < 10) {
+ std::cout << "Use the table to help find an initial value " << std::endl;
+ result = sqrtTable[static_cast<int>(x)];
+ }
+
+ // do ten iterations
+ for (int i = 0; i < 10; ++i) {
+ if (result <= 0) {
+ result = 0.1;
+ }
+ double delta = x - (result * result);
+ result = result + 0.5 * delta / result;
+ std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
+ }
+
+ return result;
+}
+}
+}
diff --git a/Help/guide/tutorial/Complete/MathFunctions/mysqrt.h b/Help/guide/tutorial/Complete/MathFunctions/mysqrt.h
new file mode 100644
index 0000000..e1c42ef
--- /dev/null
+++ b/Help/guide/tutorial/Complete/MathFunctions/mysqrt.h
@@ -0,0 +1,6 @@
+
+namespace mathfunctions {
+namespace detail {
+double mysqrt(double x);
+}
+}
diff --git a/Help/guide/tutorial/Complete/MultiCPackConfig.cmake b/Help/guide/tutorial/Complete/MultiCPackConfig.cmake
new file mode 100644
index 0000000..c2583df
--- /dev/null
+++ b/Help/guide/tutorial/Complete/MultiCPackConfig.cmake
@@ -0,0 +1,6 @@
+include("release/CPackConfig.cmake")
+
+set(CPACK_INSTALL_CMAKE_PROJECTS
+ "debug;Tutorial;ALL;/"
+ "release;Tutorial;ALL;/"
+ )
diff --git a/Help/guide/tutorial/Complete/TutorialConfig.h.in b/Help/guide/tutorial/Complete/TutorialConfig.h.in
new file mode 100644
index 0000000..7e4d7fa
--- /dev/null
+++ b/Help/guide/tutorial/Complete/TutorialConfig.h.in
@@ -0,0 +1,3 @@
+// the configured options and settings for Tutorial
+#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
+#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
diff --git a/Help/guide/tutorial/Complete/tutorial.cxx b/Help/guide/tutorial/Complete/tutorial.cxx
new file mode 100644
index 0000000..a4f44d5
--- /dev/null
+++ b/Help/guide/tutorial/Complete/tutorial.cxx
@@ -0,0 +1,26 @@
+// A simple program that computes the square root of a number
+#include <iostream>
+#include <string>
+
+#include "MathFunctions.h"
+#include "TutorialConfig.h"
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ // report version
+ std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
+ << Tutorial_VERSION_MINOR << std::endl;
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = std::stod(argv[1]);
+
+ const double outputValue = mathfunctions::sqrt(inputValue);
+
+ std::cout << "The square root of " << inputValue << " is " << outputValue
+ << std::endl;
+ return 0;
+}
diff --git a/Help/guide/tutorial/Step1/tutorial.cxx b/Help/guide/tutorial/Step1/tutorial.cxx
new file mode 100644
index 0000000..08323bf
--- /dev/null
+++ b/Help/guide/tutorial/Step1/tutorial.cxx
@@ -0,0 +1,22 @@
+// A simple program that computes the square root of a number
+#include <cmath>
+#include <cstdlib>
+#include <iostream>
+#include <string>
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = atof(argv[1]);
+
+ // calculate square root
+ const double outputValue = sqrt(inputValue);
+ std::cout << "The square root of " << inputValue << " is " << outputValue
+ << std::endl;
+ return 0;
+}
diff --git a/Help/guide/tutorial/Step10/CMakeLists.txt b/Help/guide/tutorial/Step10/CMakeLists.txt
new file mode 100644
index 0000000..34ae70c
--- /dev/null
+++ b/Help/guide/tutorial/Step10/CMakeLists.txt
@@ -0,0 +1,73 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name and version
+project(Tutorial VERSION 1.0)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# control where the static and shared libraries are built so that on windows
+# we don't need to tinker with the path to run the executable
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+
+option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
+
+# configure a header file to pass the version number only
+configure_file(TutorialConfig.h.in TutorialConfig.h)
+
+# add the MathFunctions library
+add_subdirectory(MathFunctions)
+
+# add the executable
+add_executable(Tutorial tutorial.cxx)
+target_link_libraries(Tutorial PUBLIC MathFunctions)
+
+# add the binary tree to the search path for include files
+# so that we will find TutorialConfig.h
+target_include_directories(Tutorial PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ )
+
+# add the install targets
+install(TARGETS Tutorial DESTINATION bin)
+install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
+ DESTINATION include
+ )
+
+# enable testing
+include(CTest)
+
+# does the application run
+add_test(NAME Runs COMMAND Tutorial 25)
+
+# does the usage message work?
+add_test(NAME Usage COMMAND Tutorial)
+set_tests_properties(Usage
+ PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
+ )
+
+# define a function to simplify adding tests
+function(do_test target arg result)
+ add_test(NAME Comp${arg} COMMAND ${target} ${arg})
+ set_tests_properties(Comp${arg}
+ PROPERTIES PASS_REGULAR_EXPRESSION ${result}
+ )
+endfunction(do_test)
+
+# do a bunch of result based tests
+do_test(Tutorial 4 "4 is 2")
+do_test(Tutorial 9 "9 is 3")
+do_test(Tutorial 5 "5 is 2.236")
+do_test(Tutorial 7 "7 is 2.645")
+do_test(Tutorial 25 "25 is 5")
+do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial 0.0001 "0.0001 is 0.01")
+
+include(InstallRequiredSystemLibraries)
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
+set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
+set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
+include(CPack)
diff --git a/Help/guide/tutorial/Step10/CTestConfig.cmake b/Help/guide/tutorial/Step10/CTestConfig.cmake
new file mode 100644
index 0000000..73efdb1
--- /dev/null
+++ b/Help/guide/tutorial/Step10/CTestConfig.cmake
@@ -0,0 +1,7 @@
+set(CTEST_PROJECT_NAME "CMakeTutorial")
+set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
+
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "my.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial")
+set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/Help/guide/tutorial/Step10/License.txt b/Help/guide/tutorial/Step10/License.txt
new file mode 100644
index 0000000..c62d00b
--- /dev/null
+++ b/Help/guide/tutorial/Step10/License.txt
@@ -0,0 +1,2 @@
+This is the open source License.txt file introduced in
+CMake/Tutorial/Step7...
diff --git a/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..0bfe20c
--- /dev/null
+++ b/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt
@@ -0,0 +1,55 @@
+# add the library that runs
+add_library(MathFunctions MathFunctions.cxx)
+
+# state that anybody linking to us needs to include the current source dir
+# to find MathFunctions.h, while we don't.
+target_include_directories(MathFunctions
+ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+
+# should we use our own math functions
+option(USE_MYMATH "Use tutorial provided math implementation" ON)
+if(USE_MYMATH)
+
+ target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
+
+ # first we add the executable that generates the table
+ add_executable(MakeTable MakeTable.cxx)
+
+ # add the command to generate the source code
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ DEPENDS MakeTable
+ )
+
+ # library that just does sqrt
+ add_library(SqrtLibrary STATIC
+ mysqrt.cxx
+ ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ )
+
+ # state that we depend on our binary dir to find Table.h
+ target_include_directories(SqrtLibrary PRIVATE
+ ${CMAKE_CURRENT_BINARY_DIR}
+ )
+
+ # state that SqrtLibrary need PIC when the default is shared libraries
+ set_target_properties(SqrtLibrary PROPERTIES
+ POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
+ )
+
+ target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
+endif()
+
+# define the symbol stating we are using the declspec(dllexport) when
+# building on windows
+target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
+
+# install rules
+set(installable_libs MathFunctions)
+if(TARGET SqrtLibrary)
+ list(APPEND installable_libs SqrtLibrary)
+endif()
+install(TARGETS ${installable_libs} DESTINATION lib)
+install(FILES MathFunctions.h DESTINATION include)
diff --git a/Help/guide/tutorial/Step10/MathFunctions/MakeTable.cxx b/Help/guide/tutorial/Step10/MathFunctions/MakeTable.cxx
new file mode 100644
index 0000000..ee58556
--- /dev/null
+++ b/Help/guide/tutorial/Step10/MathFunctions/MakeTable.cxx
@@ -0,0 +1,25 @@
+// A simple program that builds a sqrt table
+#include <cmath>
+#include <fstream>
+#include <iostream>
+
+int main(int argc, char* argv[])
+{
+ // make sure we have enough arguments
+ if (argc < 2) {
+ return 1;
+ }
+
+ std::ofstream fout(argv[1], std::ios_base::out);
+ const bool fileOpen = fout.is_open();
+ if (fileOpen) {
+ fout << "double sqrtTable[] = {" << std::endl;
+ for (int i = 0; i < 10; ++i) {
+ fout << sqrt(static_cast<double>(i)) << "," << std::endl;
+ }
+ // close the table with a zero
+ fout << "0};" << std::endl;
+ fout.close();
+ }
+ return fileOpen ? 0 : 1; // return 0 if wrote the file
+}
diff --git a/Help/guide/tutorial/Step10/MathFunctions/MathFunctions.cxx b/Help/guide/tutorial/Step10/MathFunctions/MathFunctions.cxx
new file mode 100644
index 0000000..0145300
--- /dev/null
+++ b/Help/guide/tutorial/Step10/MathFunctions/MathFunctions.cxx
@@ -0,0 +1,19 @@
+
+#include "MathFunctions.h"
+
+#include <cmath>
+
+#ifdef USE_MYMATH
+# include "mysqrt.h"
+#endif
+
+namespace mathfunctions {
+double sqrt(double x)
+{
+#ifdef USE_MYMATH
+ return detail::mysqrt(x);
+#else
+ return std::sqrt(x);
+#endif
+}
+}
diff --git a/Help/guide/tutorial/Step10/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Step10/MathFunctions/MathFunctions.h
new file mode 100644
index 0000000..3fb547b
--- /dev/null
+++ b/Help/guide/tutorial/Step10/MathFunctions/MathFunctions.h
@@ -0,0 +1,14 @@
+
+#if defined(_WIN32)
+# if defined(EXPORTING_MYMATH)
+# define DECLSPEC __declspec(dllexport)
+# else
+# define DECLSPEC __declspec(dllimport)
+# endif
+#else // non windows
+# define DECLSPEC
+#endif
+
+namespace mathfunctions {
+double DECLSPEC sqrt(double x);
+}
diff --git a/Help/guide/tutorial/Step10/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step10/MathFunctions/mysqrt.cxx
new file mode 100644
index 0000000..8153f18
--- /dev/null
+++ b/Help/guide/tutorial/Step10/MathFunctions/mysqrt.cxx
@@ -0,0 +1,37 @@
+#include <iostream>
+
+#include "MathFunctions.h"
+
+// include the generated table
+#include "Table.h"
+
+namespace mathfunctions {
+namespace detail {
+// a hack square root calculation using simple operations
+double mysqrt(double x)
+{
+ if (x <= 0) {
+ return 0;
+ }
+
+ // use the table to help find an initial value
+ double result = x;
+ if (x >= 1 && x < 10) {
+ std::cout << "Use the table to help find an initial value " << std::endl;
+ result = sqrtTable[static_cast<int>(x)];
+ }
+
+ // do ten iterations
+ for (int i = 0; i < 10; ++i) {
+ if (result <= 0) {
+ result = 0.1;
+ }
+ double delta = x - (result * result);
+ result = result + 0.5 * delta / result;
+ std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
+ }
+
+ return result;
+}
+}
+}
diff --git a/Help/guide/tutorial/Step10/MathFunctions/mysqrt.h b/Help/guide/tutorial/Step10/MathFunctions/mysqrt.h
new file mode 100644
index 0000000..e1c42ef
--- /dev/null
+++ b/Help/guide/tutorial/Step10/MathFunctions/mysqrt.h
@@ -0,0 +1,6 @@
+
+namespace mathfunctions {
+namespace detail {
+double mysqrt(double x);
+}
+}
diff --git a/Help/guide/tutorial/Step10/TutorialConfig.h.in b/Help/guide/tutorial/Step10/TutorialConfig.h.in
new file mode 100644
index 0000000..7e4d7fa
--- /dev/null
+++ b/Help/guide/tutorial/Step10/TutorialConfig.h.in
@@ -0,0 +1,3 @@
+// the configured options and settings for Tutorial
+#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
+#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
diff --git a/Help/guide/tutorial/Step10/tutorial.cxx b/Help/guide/tutorial/Step10/tutorial.cxx
new file mode 100644
index 0000000..37a0333
--- /dev/null
+++ b/Help/guide/tutorial/Step10/tutorial.cxx
@@ -0,0 +1,27 @@
+// A simple program that computes the square root of a number
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include "MathFunctions.h"
+#include "TutorialConfig.h"
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ // report version
+ std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
+ << Tutorial_VERSION_MINOR << std::endl;
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = std::stod(argv[1]);
+
+ const double outputValue = mathfunctions::sqrt(inputValue);
+
+ std::cout << "The square root of " << inputValue << " is " << outputValue
+ << std::endl;
+ return 0;
+}
diff --git a/Help/guide/tutorial/Step11/CMakeLists.txt b/Help/guide/tutorial/Step11/CMakeLists.txt
new file mode 100644
index 0000000..4763951
--- /dev/null
+++ b/Help/guide/tutorial/Step11/CMakeLists.txt
@@ -0,0 +1,81 @@
+cmake_minimum_required(VERSION 3.15)
+
+# set the project name and version
+project(Tutorial VERSION 1.0)
+
+add_library(tutorial_compiler_flags INTERFACE)
+target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
+
+# add compiler warning flags just when building this project via
+# the BUILD_INTERFACE genex
+set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU>")
+set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
+target_compile_options(tutorial_compiler_flags INTERFACE
+ "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>"
+ "$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
+)
+
+# control where the static and shared libraries are built so that on windows
+# we don't need to tinker with the path to run the executable
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+
+option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
+
+# configure a header file to pass the version number only
+configure_file(TutorialConfig.h.in TutorialConfig.h)
+
+# add the MathFunctions library
+add_subdirectory(MathFunctions)
+
+# add the executable
+add_executable(Tutorial tutorial.cxx)
+target_link_libraries(Tutorial PUBLIC MathFunctions)
+
+# add the binary tree to the search path for include files
+# so that we will find TutorialConfig.h
+target_include_directories(Tutorial PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ )
+
+# add the install targets
+install(TARGETS Tutorial DESTINATION bin)
+install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
+ DESTINATION include
+ )
+
+# enable testing
+enable_testing()
+
+# does the application run
+add_test(NAME Runs COMMAND Tutorial 25)
+
+# does the usage message work?
+add_test(NAME Usage COMMAND Tutorial)
+set_tests_properties(Usage
+ PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
+ )
+
+# define a function to simplify adding tests
+function(do_test target arg result)
+ add_test(NAME Comp${arg} COMMAND ${target} ${arg})
+ set_tests_properties(Comp${arg}
+ PROPERTIES PASS_REGULAR_EXPRESSION ${result}
+ )
+endfunction(do_test)
+
+# do a bunch of result based tests
+do_test(Tutorial 4 "4 is 2")
+do_test(Tutorial 9 "9 is 3")
+do_test(Tutorial 5 "5 is 2.236")
+do_test(Tutorial 7 "7 is 2.645")
+do_test(Tutorial 25 "25 is 5")
+do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial 0.0001 "0.0001 is 0.01")
+
+include(InstallRequiredSystemLibraries)
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
+set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
+set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
+include(CPack)
diff --git a/Help/guide/tutorial/Step11/CTestConfig.cmake b/Help/guide/tutorial/Step11/CTestConfig.cmake
new file mode 100644
index 0000000..73efdb1
--- /dev/null
+++ b/Help/guide/tutorial/Step11/CTestConfig.cmake
@@ -0,0 +1,7 @@
+set(CTEST_PROJECT_NAME "CMakeTutorial")
+set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
+
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "my.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial")
+set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/Help/guide/tutorial/Step11/License.txt b/Help/guide/tutorial/Step11/License.txt
new file mode 100644
index 0000000..c62d00b
--- /dev/null
+++ b/Help/guide/tutorial/Step11/License.txt
@@ -0,0 +1,2 @@
+This is the open source License.txt file introduced in
+CMake/Tutorial/Step7...
diff --git a/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..0d287ca
--- /dev/null
+++ b/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt
@@ -0,0 +1,59 @@
+# add the library that runs
+add_library(MathFunctions MathFunctions.cxx)
+
+# state that anybody linking to us needs to include the current source dir
+# to find MathFunctions.h, while we don't.
+target_include_directories(MathFunctions
+ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+
+# should we use our own math functions
+option(USE_MYMATH "Use tutorial provided math implementation" ON)
+if(USE_MYMATH)
+
+ target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
+
+ # first we add the executable that generates the table
+ add_executable(MakeTable MakeTable.cxx)
+ target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags)
+
+ # add the command to generate the source code
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ DEPENDS MakeTable
+ )
+
+ # library that just does sqrt
+ add_library(SqrtLibrary STATIC
+ mysqrt.cxx
+ ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ )
+
+ # state that we depend on our binary dir to find Table.h
+ target_include_directories(SqrtLibrary PRIVATE
+ ${CMAKE_CURRENT_BINARY_DIR}
+ )
+
+ # state that SqrtLibrary need PIC when the default is shared libraries
+ set_target_properties(SqrtLibrary PROPERTIES
+ POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
+ )
+
+ target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
+ target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
+endif()
+
+target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
+
+# define the symbol stating we are using the declspec(dllexport) when
+#building on windows
+target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
+
+# install rules
+set(installable_libs MathFunctions tutorial_compiler_flags)
+if(TARGET SqrtLibrary)
+ list(APPEND installable_libs SqrtLibrary)
+endif()
+install(TARGETS ${installable_libs} DESTINATION lib)
+install(FILES MathFunctions.h DESTINATION include)
diff --git a/Help/guide/tutorial/Step11/MathFunctions/MakeTable.cxx b/Help/guide/tutorial/Step11/MathFunctions/MakeTable.cxx
new file mode 100644
index 0000000..ee58556
--- /dev/null
+++ b/Help/guide/tutorial/Step11/MathFunctions/MakeTable.cxx
@@ -0,0 +1,25 @@
+// A simple program that builds a sqrt table
+#include <cmath>
+#include <fstream>
+#include <iostream>
+
+int main(int argc, char* argv[])
+{
+ // make sure we have enough arguments
+ if (argc < 2) {
+ return 1;
+ }
+
+ std::ofstream fout(argv[1], std::ios_base::out);
+ const bool fileOpen = fout.is_open();
+ if (fileOpen) {
+ fout << "double sqrtTable[] = {" << std::endl;
+ for (int i = 0; i < 10; ++i) {
+ fout << sqrt(static_cast<double>(i)) << "," << std::endl;
+ }
+ // close the table with a zero
+ fout << "0};" << std::endl;
+ fout.close();
+ }
+ return fileOpen ? 0 : 1; // return 0 if wrote the file
+}
diff --git a/Help/guide/tutorial/Step11/MathFunctions/MathFunctions.cxx b/Help/guide/tutorial/Step11/MathFunctions/MathFunctions.cxx
new file mode 100644
index 0000000..0145300
--- /dev/null
+++ b/Help/guide/tutorial/Step11/MathFunctions/MathFunctions.cxx
@@ -0,0 +1,19 @@
+
+#include "MathFunctions.h"
+
+#include <cmath>
+
+#ifdef USE_MYMATH
+# include "mysqrt.h"
+#endif
+
+namespace mathfunctions {
+double sqrt(double x)
+{
+#ifdef USE_MYMATH
+ return detail::mysqrt(x);
+#else
+ return std::sqrt(x);
+#endif
+}
+}
diff --git a/Help/guide/tutorial/Step11/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Step11/MathFunctions/MathFunctions.h
new file mode 100644
index 0000000..3fb547b
--- /dev/null
+++ b/Help/guide/tutorial/Step11/MathFunctions/MathFunctions.h
@@ -0,0 +1,14 @@
+
+#if defined(_WIN32)
+# if defined(EXPORTING_MYMATH)
+# define DECLSPEC __declspec(dllexport)
+# else
+# define DECLSPEC __declspec(dllimport)
+# endif
+#else // non windows
+# define DECLSPEC
+#endif
+
+namespace mathfunctions {
+double DECLSPEC sqrt(double x);
+}
diff --git a/Help/guide/tutorial/Step11/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step11/MathFunctions/mysqrt.cxx
new file mode 100644
index 0000000..8153f18
--- /dev/null
+++ b/Help/guide/tutorial/Step11/MathFunctions/mysqrt.cxx
@@ -0,0 +1,37 @@
+#include <iostream>
+
+#include "MathFunctions.h"
+
+// include the generated table
+#include "Table.h"
+
+namespace mathfunctions {
+namespace detail {
+// a hack square root calculation using simple operations
+double mysqrt(double x)
+{
+ if (x <= 0) {
+ return 0;
+ }
+
+ // use the table to help find an initial value
+ double result = x;
+ if (x >= 1 && x < 10) {
+ std::cout << "Use the table to help find an initial value " << std::endl;
+ result = sqrtTable[static_cast<int>(x)];
+ }
+
+ // do ten iterations
+ for (int i = 0; i < 10; ++i) {
+ if (result <= 0) {
+ result = 0.1;
+ }
+ double delta = x - (result * result);
+ result = result + 0.5 * delta / result;
+ std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
+ }
+
+ return result;
+}
+}
+}
diff --git a/Help/guide/tutorial/Step11/MathFunctions/mysqrt.h b/Help/guide/tutorial/Step11/MathFunctions/mysqrt.h
new file mode 100644
index 0000000..e1c42ef
--- /dev/null
+++ b/Help/guide/tutorial/Step11/MathFunctions/mysqrt.h
@@ -0,0 +1,6 @@
+
+namespace mathfunctions {
+namespace detail {
+double mysqrt(double x);
+}
+}
diff --git a/Help/guide/tutorial/Step11/TutorialConfig.h.in b/Help/guide/tutorial/Step11/TutorialConfig.h.in
new file mode 100644
index 0000000..7e4d7fa
--- /dev/null
+++ b/Help/guide/tutorial/Step11/TutorialConfig.h.in
@@ -0,0 +1,3 @@
+// the configured options and settings for Tutorial
+#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
+#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
diff --git a/Help/guide/tutorial/Step11/tutorial.cxx b/Help/guide/tutorial/Step11/tutorial.cxx
new file mode 100644
index 0000000..a4f44d5
--- /dev/null
+++ b/Help/guide/tutorial/Step11/tutorial.cxx
@@ -0,0 +1,26 @@
+// A simple program that computes the square root of a number
+#include <iostream>
+#include <string>
+
+#include "MathFunctions.h"
+#include "TutorialConfig.h"
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ // report version
+ std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
+ << Tutorial_VERSION_MINOR << std::endl;
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = std::stod(argv[1]);
+
+ const double outputValue = mathfunctions::sqrt(inputValue);
+
+ std::cout << "The square root of " << inputValue << " is " << outputValue
+ << std::endl;
+ return 0;
+}
diff --git a/Help/guide/tutorial/Step12/CMakeLists.txt b/Help/guide/tutorial/Step12/CMakeLists.txt
new file mode 100644
index 0000000..eca79d9
--- /dev/null
+++ b/Help/guide/tutorial/Step12/CMakeLists.txt
@@ -0,0 +1,120 @@
+cmake_minimum_required(VERSION 3.15)
+
+# set the project name and version
+project(Tutorial VERSION 1.0)
+
+add_library(tutorial_compiler_flags INTERFACE)
+target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
+
+# add compiler warning flags just when building this project via
+# the BUILD_INTERFACE genex
+set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU>")
+set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
+target_compile_options(tutorial_compiler_flags INTERFACE
+ "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>"
+ "$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
+)
+
+# control where the static and shared libraries are built so that on windows
+# we don't need to tinker with the path to run the executable
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+
+option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
+
+if(APPLE)
+ set(CMAKE_INSTALL_RPATH "@executable_path/../lib")
+elseif(UNIX)
+ set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
+endif()
+
+# configure a header file to pass the version number only
+configure_file(TutorialConfig.h.in TutorialConfig.h)
+
+# add the MathFunctions library
+add_subdirectory(MathFunctions)
+
+# add the executable
+add_executable(Tutorial tutorial.cxx)
+target_link_libraries(Tutorial PUBLIC MathFunctions)
+
+# add the binary tree to the search path for include files
+# so that we will find TutorialConfig.h
+target_include_directories(Tutorial PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ )
+
+# add the install targets
+install(TARGETS Tutorial DESTINATION bin)
+install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
+ DESTINATION include
+ )
+
+# enable testing
+enable_testing()
+
+# does the application run
+add_test(NAME Runs COMMAND Tutorial 25)
+
+# does the usage message work?
+add_test(NAME Usage COMMAND Tutorial)
+set_tests_properties(Usage
+ PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
+ )
+
+# define a function to simplify adding tests
+function(do_test target arg result)
+ add_test(NAME Comp${arg} COMMAND ${target} ${arg})
+ set_tests_properties(Comp${arg}
+ PROPERTIES PASS_REGULAR_EXPRESSION ${result}
+ )
+endfunction(do_test)
+
+# do a bunch of result based tests
+do_test(Tutorial 4 "4 is 2")
+do_test(Tutorial 9 "9 is 3")
+do_test(Tutorial 5 "5 is 2.236")
+do_test(Tutorial 7 "7 is 2.645")
+do_test(Tutorial 25 "25 is 5")
+do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial 0.0001 "0.0001 is 0.01")
+
+include(InstallRequiredSystemLibraries)
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
+set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
+set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
+include(CPack)
+
+# install the configuration targets
+install(EXPORT MathFunctionsTargets
+ FILE MathFunctionsTargets.cmake
+ DESTINATION lib/cmake/MathFunctions
+)
+
+include(CMakePackageConfigHelpers)
+# generate the config file that is includes the exports
+configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
+ "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
+ INSTALL_DESTINATION "lib/cmake/example"
+ NO_SET_AND_CHECK_MACRO
+ NO_CHECK_REQUIRED_COMPONENTS_MACRO
+ )
+# generate the version file for the config file
+write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
+ VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}"
+ COMPATIBILITY AnyNewerVersion
+)
+
+# install the configuration file
+install(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
+ DESTINATION lib/cmake/MathFunctions
+ )
+
+# generate the export targets for the build tree
+# needs to be after the install(TARGETS ) command
+export(EXPORT MathFunctionsTargets
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake"
+)
diff --git a/Help/guide/tutorial/Step12/CTestConfig.cmake b/Help/guide/tutorial/Step12/CTestConfig.cmake
new file mode 100644
index 0000000..73efdb1
--- /dev/null
+++ b/Help/guide/tutorial/Step12/CTestConfig.cmake
@@ -0,0 +1,7 @@
+set(CTEST_PROJECT_NAME "CMakeTutorial")
+set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
+
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "my.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial")
+set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/Help/guide/tutorial/Step12/Config.cmake.in b/Help/guide/tutorial/Step12/Config.cmake.in
new file mode 100644
index 0000000..17cbabd
--- /dev/null
+++ b/Help/guide/tutorial/Step12/Config.cmake.in
@@ -0,0 +1,4 @@
+
+@PACKAGE_INIT@
+
+include ( "${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )
diff --git a/Help/guide/tutorial/Step12/License.txt b/Help/guide/tutorial/Step12/License.txt
new file mode 100644
index 0000000..c62d00b
--- /dev/null
+++ b/Help/guide/tutorial/Step12/License.txt
@@ -0,0 +1,2 @@
+This is the open source License.txt file introduced in
+CMake/Tutorial/Step7...
diff --git a/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..ea3861c
--- /dev/null
+++ b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt
@@ -0,0 +1,63 @@
+# add the library that runs
+add_library(MathFunctions MathFunctions.cxx)
+
+# state that anybody linking to us needs to include the current source dir
+# to find MathFunctions.h, while we don't.
+target_include_directories(MathFunctions
+ INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ $<INSTALL_INTERFACE:include>
+ )
+
+# should we use our own math functions
+option(USE_MYMATH "Use tutorial provided math implementation" ON)
+if(USE_MYMATH)
+
+ target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
+
+ # first we add the executable that generates the table
+ add_executable(MakeTable MakeTable.cxx)
+ target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags)
+
+ # add the command to generate the source code
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ DEPENDS MakeTable
+ )
+
+ # library that just does sqrt
+ add_library(SqrtLibrary STATIC
+ mysqrt.cxx
+ ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ )
+
+ # state that we depend on our binary dir to find Table.h
+ target_include_directories(SqrtLibrary PRIVATE
+ ${CMAKE_CURRENT_BINARY_DIR}
+ )
+
+ # state that SqrtLibrary need PIC when the default is shared libraries
+ set_target_properties(SqrtLibrary PROPERTIES
+ POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
+ )
+
+ target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
+ target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
+endif()
+
+target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
+
+# define the symbol stating we are using the declspec(dllexport) when
+# building on windows
+target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
+
+# install rules
+set(installable_libs MathFunctions tutorial_compiler_flags)
+if(TARGET SqrtLibrary)
+ list(APPEND installable_libs SqrtLibrary)
+endif()
+install(TARGETS ${installable_libs}
+ DESTINATION lib
+ EXPORT MathFunctionsTargets)
+install(FILES MathFunctions.h DESTINATION include)
diff --git a/Help/guide/tutorial/Step12/MathFunctions/MakeTable.cxx b/Help/guide/tutorial/Step12/MathFunctions/MakeTable.cxx
new file mode 100644
index 0000000..ee58556
--- /dev/null
+++ b/Help/guide/tutorial/Step12/MathFunctions/MakeTable.cxx
@@ -0,0 +1,25 @@
+// A simple program that builds a sqrt table
+#include <cmath>
+#include <fstream>
+#include <iostream>
+
+int main(int argc, char* argv[])
+{
+ // make sure we have enough arguments
+ if (argc < 2) {
+ return 1;
+ }
+
+ std::ofstream fout(argv[1], std::ios_base::out);
+ const bool fileOpen = fout.is_open();
+ if (fileOpen) {
+ fout << "double sqrtTable[] = {" << std::endl;
+ for (int i = 0; i < 10; ++i) {
+ fout << sqrt(static_cast<double>(i)) << "," << std::endl;
+ }
+ // close the table with a zero
+ fout << "0};" << std::endl;
+ fout.close();
+ }
+ return fileOpen ? 0 : 1; // return 0 if wrote the file
+}
diff --git a/Help/guide/tutorial/Step12/MathFunctions/MathFunctions.cxx b/Help/guide/tutorial/Step12/MathFunctions/MathFunctions.cxx
new file mode 100644
index 0000000..0145300
--- /dev/null
+++ b/Help/guide/tutorial/Step12/MathFunctions/MathFunctions.cxx
@@ -0,0 +1,19 @@
+
+#include "MathFunctions.h"
+
+#include <cmath>
+
+#ifdef USE_MYMATH
+# include "mysqrt.h"
+#endif
+
+namespace mathfunctions {
+double sqrt(double x)
+{
+#ifdef USE_MYMATH
+ return detail::mysqrt(x);
+#else
+ return std::sqrt(x);
+#endif
+}
+}
diff --git a/Help/guide/tutorial/Step12/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Step12/MathFunctions/MathFunctions.h
new file mode 100644
index 0000000..3fb547b
--- /dev/null
+++ b/Help/guide/tutorial/Step12/MathFunctions/MathFunctions.h
@@ -0,0 +1,14 @@
+
+#if defined(_WIN32)
+# if defined(EXPORTING_MYMATH)
+# define DECLSPEC __declspec(dllexport)
+# else
+# define DECLSPEC __declspec(dllimport)
+# endif
+#else // non windows
+# define DECLSPEC
+#endif
+
+namespace mathfunctions {
+double DECLSPEC sqrt(double x);
+}
diff --git a/Help/guide/tutorial/Step12/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step12/MathFunctions/mysqrt.cxx
new file mode 100644
index 0000000..8153f18
--- /dev/null
+++ b/Help/guide/tutorial/Step12/MathFunctions/mysqrt.cxx
@@ -0,0 +1,37 @@
+#include <iostream>
+
+#include "MathFunctions.h"
+
+// include the generated table
+#include "Table.h"
+
+namespace mathfunctions {
+namespace detail {
+// a hack square root calculation using simple operations
+double mysqrt(double x)
+{
+ if (x <= 0) {
+ return 0;
+ }
+
+ // use the table to help find an initial value
+ double result = x;
+ if (x >= 1 && x < 10) {
+ std::cout << "Use the table to help find an initial value " << std::endl;
+ result = sqrtTable[static_cast<int>(x)];
+ }
+
+ // do ten iterations
+ for (int i = 0; i < 10; ++i) {
+ if (result <= 0) {
+ result = 0.1;
+ }
+ double delta = x - (result * result);
+ result = result + 0.5 * delta / result;
+ std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
+ }
+
+ return result;
+}
+}
+}
diff --git a/Help/guide/tutorial/Step12/MathFunctions/mysqrt.h b/Help/guide/tutorial/Step12/MathFunctions/mysqrt.h
new file mode 100644
index 0000000..e1c42ef
--- /dev/null
+++ b/Help/guide/tutorial/Step12/MathFunctions/mysqrt.h
@@ -0,0 +1,6 @@
+
+namespace mathfunctions {
+namespace detail {
+double mysqrt(double x);
+}
+}
diff --git a/Help/guide/tutorial/Step12/TutorialConfig.h.in b/Help/guide/tutorial/Step12/TutorialConfig.h.in
new file mode 100644
index 0000000..7e4d7fa
--- /dev/null
+++ b/Help/guide/tutorial/Step12/TutorialConfig.h.in
@@ -0,0 +1,3 @@
+// the configured options and settings for Tutorial
+#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
+#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
diff --git a/Help/guide/tutorial/Step12/tutorial.cxx b/Help/guide/tutorial/Step12/tutorial.cxx
new file mode 100644
index 0000000..a4f44d5
--- /dev/null
+++ b/Help/guide/tutorial/Step12/tutorial.cxx
@@ -0,0 +1,26 @@
+// A simple program that computes the square root of a number
+#include <iostream>
+#include <string>
+
+#include "MathFunctions.h"
+#include "TutorialConfig.h"
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ // report version
+ std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
+ << Tutorial_VERSION_MINOR << std::endl;
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = std::stod(argv[1]);
+
+ const double outputValue = mathfunctions::sqrt(inputValue);
+
+ std::cout << "The square root of " << inputValue << " is " << outputValue
+ << std::endl;
+ return 0;
+}
diff --git a/Help/guide/tutorial/Step2/CMakeLists.txt b/Help/guide/tutorial/Step2/CMakeLists.txt
new file mode 100644
index 0000000..7aa59e9
--- /dev/null
+++ b/Help/guide/tutorial/Step2/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name and version
+project(Tutorial VERSION 1.0)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# configure a header file to pass some of the CMake settings
+# to the source code
+configure_file(TutorialConfig.h.in TutorialConfig.h)
+
+# add the executable
+add_executable(Tutorial tutorial.cxx)
+
+# add the binary tree to the search path for include files
+# so that we will find TutorialConfig.h
+target_include_directories(Tutorial PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ )
diff --git a/Help/guide/tutorial/Step2/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Step2/MathFunctions/MathFunctions.h
new file mode 100644
index 0000000..cd36bcc
--- /dev/null
+++ b/Help/guide/tutorial/Step2/MathFunctions/MathFunctions.h
@@ -0,0 +1 @@
+double mysqrt(double x);
diff --git a/Help/guide/tutorial/Step2/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step2/MathFunctions/mysqrt.cxx
new file mode 100644
index 0000000..1e4d97a
--- /dev/null
+++ b/Help/guide/tutorial/Step2/MathFunctions/mysqrt.cxx
@@ -0,0 +1,22 @@
+#include <iostream>
+
+// a hack square root calculation using simple operations
+double mysqrt(double x)
+{
+ if (x <= 0) {
+ return 0;
+ }
+
+ double result = x;
+
+ // do ten iterations
+ for (int i = 0; i < 10; ++i) {
+ if (result <= 0) {
+ result = 0.1;
+ }
+ double delta = x - (result * result);
+ result = result + 0.5 * delta / result;
+ std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
+ }
+ return result;
+}
diff --git a/Help/guide/tutorial/Step2/TutorialConfig.h.in b/Help/guide/tutorial/Step2/TutorialConfig.h.in
new file mode 100644
index 0000000..7e4d7fa
--- /dev/null
+++ b/Help/guide/tutorial/Step2/TutorialConfig.h.in
@@ -0,0 +1,3 @@
+// the configured options and settings for Tutorial
+#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
+#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
diff --git a/Help/guide/tutorial/Step2/tutorial.cxx b/Help/guide/tutorial/Step2/tutorial.cxx
new file mode 100644
index 0000000..53b0810
--- /dev/null
+++ b/Help/guide/tutorial/Step2/tutorial.cxx
@@ -0,0 +1,26 @@
+// A simple program that computes the square root of a number
+#include <cmath>
+#include <iostream>
+#include <string>
+
+#include "TutorialConfig.h"
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ // report version
+ std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
+ << Tutorial_VERSION_MINOR << std::endl;
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = std::stod(argv[1]);
+
+ // calculate square root
+ const double outputValue = sqrt(inputValue);
+ std::cout << "The square root of " << inputValue << " is " << outputValue
+ << std::endl;
+ return 0;
+}
diff --git a/Help/guide/tutorial/Step3/CMakeLists.txt b/Help/guide/tutorial/Step3/CMakeLists.txt
new file mode 100644
index 0000000..1c12816
--- /dev/null
+++ b/Help/guide/tutorial/Step3/CMakeLists.txt
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name and version
+project(Tutorial VERSION 1.0)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# should we use our own math functions
+option(USE_MYMATH "Use tutorial provided math implementation" ON)
+
+# configure a header file to pass some of the CMake settings
+# to the source code
+configure_file(TutorialConfig.h.in TutorialConfig.h)
+
+# add the MathFunctions library
+if(USE_MYMATH)
+ add_subdirectory(MathFunctions)
+ list(APPEND EXTRA_LIBS MathFunctions)
+ list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
+endif()
+
+# add the executable
+add_executable(Tutorial tutorial.cxx)
+
+target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
+
+# add the binary tree to the search path for include files
+# so that we will find TutorialConfig.h
+target_include_directories(Tutorial PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ ${EXTRA_INCLUDES}
+ )
diff --git a/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..8b443a6
--- /dev/null
+++ b/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(MathFunctions mysqrt.cxx)
diff --git a/Help/guide/tutorial/Step3/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Step3/MathFunctions/MathFunctions.h
new file mode 100644
index 0000000..cd36bcc
--- /dev/null
+++ b/Help/guide/tutorial/Step3/MathFunctions/MathFunctions.h
@@ -0,0 +1 @@
+double mysqrt(double x);
diff --git a/Help/guide/tutorial/Step3/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step3/MathFunctions/mysqrt.cxx
new file mode 100644
index 0000000..abe767d
--- /dev/null
+++ b/Help/guide/tutorial/Step3/MathFunctions/mysqrt.cxx
@@ -0,0 +1,24 @@
+#include <iostream>
+
+#include "MathFunctions.h"
+
+// a hack square root calculation using simple operations
+double mysqrt(double x)
+{
+ if (x <= 0) {
+ return 0;
+ }
+
+ double result = x;
+
+ // do ten iterations
+ for (int i = 0; i < 10; ++i) {
+ if (result <= 0) {
+ result = 0.1;
+ }
+ double delta = x - (result * result);
+ result = result + 0.5 * delta / result;
+ std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
+ }
+ return result;
+}
diff --git a/Help/guide/tutorial/Step3/TutorialConfig.h.in b/Help/guide/tutorial/Step3/TutorialConfig.h.in
new file mode 100644
index 0000000..e23f521
--- /dev/null
+++ b/Help/guide/tutorial/Step3/TutorialConfig.h.in
@@ -0,0 +1,4 @@
+// the configured options and settings for Tutorial
+#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
+#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
+#cmakedefine USE_MYMATH
diff --git a/Help/guide/tutorial/Step3/tutorial.cxx b/Help/guide/tutorial/Step3/tutorial.cxx
new file mode 100644
index 0000000..b3c6a4f
--- /dev/null
+++ b/Help/guide/tutorial/Step3/tutorial.cxx
@@ -0,0 +1,36 @@
+// A simple program that computes the square root of a number
+#include <cmath>
+#include <iostream>
+#include <string>
+
+#include "TutorialConfig.h"
+
+// should we include the MathFunctions header?
+#ifdef USE_MYMATH
+# include "MathFunctions.h"
+#endif
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ // report version
+ std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
+ << Tutorial_VERSION_MINOR << std::endl;
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = std::stod(argv[1]);
+
+ // which square root function should we use?
+#ifdef USE_MYMATH
+ const double outputValue = mysqrt(inputValue);
+#else
+ const double outputValue = sqrt(inputValue);
+#endif
+
+ std::cout << "The square root of " << inputValue << " is " << outputValue
+ << std::endl;
+ return 0;
+}
diff --git a/Help/guide/tutorial/Step4/CMakeLists.txt b/Help/guide/tutorial/Step4/CMakeLists.txt
new file mode 100644
index 0000000..38e9b1f
--- /dev/null
+++ b/Help/guide/tutorial/Step4/CMakeLists.txt
@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name and version
+project(Tutorial VERSION 1.0)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# should we use our own math functions
+option(USE_MYMATH "Use tutorial provided math implementation" ON)
+
+# configure a header file to pass some of the CMake settings
+# to the source code
+configure_file(TutorialConfig.h.in TutorialConfig.h)
+
+# add the MathFunctions library
+if(USE_MYMATH)
+ add_subdirectory(MathFunctions)
+ list(APPEND EXTRA_LIBS MathFunctions)
+endif()
+
+# add the executable
+add_executable(Tutorial tutorial.cxx)
+
+target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
+
+# add the binary tree to the search path for include files
+# so that we will find TutorialConfig.h
+target_include_directories(Tutorial PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ )
diff --git a/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..0515852
--- /dev/null
+++ b/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_library(MathFunctions mysqrt.cxx)
+
+# state that anybody linking to us needs to include the current source dir
+# to find MathFunctions.h, while we don't.
+target_include_directories(MathFunctions
+ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
+ )
diff --git a/Help/guide/tutorial/Step4/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Step4/MathFunctions/MathFunctions.h
new file mode 100644
index 0000000..cd36bcc
--- /dev/null
+++ b/Help/guide/tutorial/Step4/MathFunctions/MathFunctions.h
@@ -0,0 +1 @@
+double mysqrt(double x);
diff --git a/Help/guide/tutorial/Step4/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step4/MathFunctions/mysqrt.cxx
new file mode 100644
index 0000000..abe767d
--- /dev/null
+++ b/Help/guide/tutorial/Step4/MathFunctions/mysqrt.cxx
@@ -0,0 +1,24 @@
+#include <iostream>
+
+#include "MathFunctions.h"
+
+// a hack square root calculation using simple operations
+double mysqrt(double x)
+{
+ if (x <= 0) {
+ return 0;
+ }
+
+ double result = x;
+
+ // do ten iterations
+ for (int i = 0; i < 10; ++i) {
+ if (result <= 0) {
+ result = 0.1;
+ }
+ double delta = x - (result * result);
+ result = result + 0.5 * delta / result;
+ std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
+ }
+ return result;
+}
diff --git a/Help/guide/tutorial/Step4/TutorialConfig.h.in b/Help/guide/tutorial/Step4/TutorialConfig.h.in
new file mode 100644
index 0000000..e23f521
--- /dev/null
+++ b/Help/guide/tutorial/Step4/TutorialConfig.h.in
@@ -0,0 +1,4 @@
+// the configured options and settings for Tutorial
+#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
+#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
+#cmakedefine USE_MYMATH
diff --git a/Help/guide/tutorial/Step4/tutorial.cxx b/Help/guide/tutorial/Step4/tutorial.cxx
new file mode 100644
index 0000000..b3c6a4f
--- /dev/null
+++ b/Help/guide/tutorial/Step4/tutorial.cxx
@@ -0,0 +1,36 @@
+// A simple program that computes the square root of a number
+#include <cmath>
+#include <iostream>
+#include <string>
+
+#include "TutorialConfig.h"
+
+// should we include the MathFunctions header?
+#ifdef USE_MYMATH
+# include "MathFunctions.h"
+#endif
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ // report version
+ std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
+ << Tutorial_VERSION_MINOR << std::endl;
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = std::stod(argv[1]);
+
+ // which square root function should we use?
+#ifdef USE_MYMATH
+ const double outputValue = mysqrt(inputValue);
+#else
+ const double outputValue = sqrt(inputValue);
+#endif
+
+ std::cout << "The square root of " << inputValue << " is " << outputValue
+ << std::endl;
+ return 0;
+}
diff --git a/Help/guide/tutorial/Step5/CMakeLists.txt b/Help/guide/tutorial/Step5/CMakeLists.txt
new file mode 100644
index 0000000..c3b375a
--- /dev/null
+++ b/Help/guide/tutorial/Step5/CMakeLists.txt
@@ -0,0 +1,66 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name and version
+project(Tutorial VERSION 1.0)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# should we use our own math functions
+option(USE_MYMATH "Use tutorial provided math implementation" ON)
+
+# configure a header file to pass some of the CMake settings
+# to the source code
+configure_file(TutorialConfig.h.in TutorialConfig.h)
+
+# add the MathFunctions library
+if(USE_MYMATH)
+ add_subdirectory(MathFunctions)
+ list(APPEND EXTRA_LIBS MathFunctions)
+endif()
+
+# add the executable
+add_executable(Tutorial tutorial.cxx)
+target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
+
+# add the binary tree to the search path for include files
+# so that we will find TutorialConfig.h
+target_include_directories(Tutorial PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ )
+
+# add the install targets
+install(TARGETS Tutorial DESTINATION bin)
+install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
+ DESTINATION include
+ )
+
+# enable testing
+enable_testing()
+
+# does the application run
+add_test(NAME Runs COMMAND Tutorial 25)
+
+# does the usage message work?
+add_test(NAME Usage COMMAND Tutorial)
+set_tests_properties(Usage
+ PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
+ )
+
+# define a function to simplify adding tests
+function(do_test target arg result)
+ add_test(NAME Comp${arg} COMMAND ${target} ${arg})
+ set_tests_properties(Comp${arg}
+ PROPERTIES PASS_REGULAR_EXPRESSION ${result}
+ )
+endfunction(do_test)
+
+# do a bunch of result based tests
+do_test(Tutorial 4 "4 is 2")
+do_test(Tutorial 9 "9 is 3")
+do_test(Tutorial 5 "5 is 2.236")
+do_test(Tutorial 7 "7 is 2.645")
+do_test(Tutorial 25 "25 is 5")
+do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial 0.0001 "0.0001 is 0.01")
diff --git a/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..b12f27d
--- /dev/null
+++ b/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_library(MathFunctions mysqrt.cxx)
+
+# state that anybody linking to us needs to include the current source dir
+# to find MathFunctions.h, while we don't.
+target_include_directories(MathFunctions
+ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+
+# install rules
+install(TARGETS MathFunctions DESTINATION lib)
+install(FILES MathFunctions.h DESTINATION include)
diff --git a/Help/guide/tutorial/Step5/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Step5/MathFunctions/MathFunctions.h
new file mode 100644
index 0000000..cd36bcc
--- /dev/null
+++ b/Help/guide/tutorial/Step5/MathFunctions/MathFunctions.h
@@ -0,0 +1 @@
+double mysqrt(double x);
diff --git a/Help/guide/tutorial/Step5/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step5/MathFunctions/mysqrt.cxx
new file mode 100644
index 0000000..abe767d
--- /dev/null
+++ b/Help/guide/tutorial/Step5/MathFunctions/mysqrt.cxx
@@ -0,0 +1,24 @@
+#include <iostream>
+
+#include "MathFunctions.h"
+
+// a hack square root calculation using simple operations
+double mysqrt(double x)
+{
+ if (x <= 0) {
+ return 0;
+ }
+
+ double result = x;
+
+ // do ten iterations
+ for (int i = 0; i < 10; ++i) {
+ if (result <= 0) {
+ result = 0.1;
+ }
+ double delta = x - (result * result);
+ result = result + 0.5 * delta / result;
+ std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
+ }
+ return result;
+}
diff --git a/Help/guide/tutorial/Step5/TutorialConfig.h.in b/Help/guide/tutorial/Step5/TutorialConfig.h.in
new file mode 100644
index 0000000..e23f521
--- /dev/null
+++ b/Help/guide/tutorial/Step5/TutorialConfig.h.in
@@ -0,0 +1,4 @@
+// the configured options and settings for Tutorial
+#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
+#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
+#cmakedefine USE_MYMATH
diff --git a/Help/guide/tutorial/Step5/tutorial.cxx b/Help/guide/tutorial/Step5/tutorial.cxx
new file mode 100644
index 0000000..b3c6a4f
--- /dev/null
+++ b/Help/guide/tutorial/Step5/tutorial.cxx
@@ -0,0 +1,36 @@
+// A simple program that computes the square root of a number
+#include <cmath>
+#include <iostream>
+#include <string>
+
+#include "TutorialConfig.h"
+
+// should we include the MathFunctions header?
+#ifdef USE_MYMATH
+# include "MathFunctions.h"
+#endif
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ // report version
+ std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
+ << Tutorial_VERSION_MINOR << std::endl;
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = std::stod(argv[1]);
+
+ // which square root function should we use?
+#ifdef USE_MYMATH
+ const double outputValue = mysqrt(inputValue);
+#else
+ const double outputValue = sqrt(inputValue);
+#endif
+
+ std::cout << "The square root of " << inputValue << " is " << outputValue
+ << std::endl;
+ return 0;
+}
diff --git a/Help/guide/tutorial/Step6/CMakeLists.txt b/Help/guide/tutorial/Step6/CMakeLists.txt
new file mode 100644
index 0000000..c3b375a
--- /dev/null
+++ b/Help/guide/tutorial/Step6/CMakeLists.txt
@@ -0,0 +1,66 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name and version
+project(Tutorial VERSION 1.0)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# should we use our own math functions
+option(USE_MYMATH "Use tutorial provided math implementation" ON)
+
+# configure a header file to pass some of the CMake settings
+# to the source code
+configure_file(TutorialConfig.h.in TutorialConfig.h)
+
+# add the MathFunctions library
+if(USE_MYMATH)
+ add_subdirectory(MathFunctions)
+ list(APPEND EXTRA_LIBS MathFunctions)
+endif()
+
+# add the executable
+add_executable(Tutorial tutorial.cxx)
+target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
+
+# add the binary tree to the search path for include files
+# so that we will find TutorialConfig.h
+target_include_directories(Tutorial PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ )
+
+# add the install targets
+install(TARGETS Tutorial DESTINATION bin)
+install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
+ DESTINATION include
+ )
+
+# enable testing
+enable_testing()
+
+# does the application run
+add_test(NAME Runs COMMAND Tutorial 25)
+
+# does the usage message work?
+add_test(NAME Usage COMMAND Tutorial)
+set_tests_properties(Usage
+ PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
+ )
+
+# define a function to simplify adding tests
+function(do_test target arg result)
+ add_test(NAME Comp${arg} COMMAND ${target} ${arg})
+ set_tests_properties(Comp${arg}
+ PROPERTIES PASS_REGULAR_EXPRESSION ${result}
+ )
+endfunction(do_test)
+
+# do a bunch of result based tests
+do_test(Tutorial 4 "4 is 2")
+do_test(Tutorial 9 "9 is 3")
+do_test(Tutorial 5 "5 is 2.236")
+do_test(Tutorial 7 "7 is 2.645")
+do_test(Tutorial 25 "25 is 5")
+do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial 0.0001 "0.0001 is 0.01")
diff --git a/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..f64c6ac
--- /dev/null
+++ b/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt
@@ -0,0 +1,32 @@
+add_library(MathFunctions mysqrt.cxx)
+
+# state that anybody linking to us needs to include the current source dir
+# to find MathFunctions.h, while we don't.
+target_include_directories(MathFunctions
+ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+
+# does this system provide the log and exp functions?
+include(CheckSymbolExists)
+check_symbol_exists(log "math.h" HAVE_LOG)
+check_symbol_exists(exp "math.h" HAVE_EXP)
+if(NOT (HAVE_LOG AND HAVE_EXP))
+ unset(HAVE_LOG CACHE)
+ unset(HAVE_EXP CACHE)
+ set(CMAKE_REQUIRED_LIBRARIES "m")
+ check_symbol_exists(log "math.h" HAVE_LOG)
+ check_symbol_exists(exp "math.h" HAVE_EXP)
+ if(HAVE_LOG AND HAVE_EXP)
+ target_link_libraries(MathFunctions PRIVATE m)
+ endif()
+endif()
+
+# add compile definitions
+if(HAVE_LOG AND HAVE_EXP)
+ target_compile_definitions(MathFunctions
+ PRIVATE "HAVE_LOG" "HAVE_EXP")
+endif()
+
+# install rules
+install(TARGETS MathFunctions DESTINATION lib)
+install(FILES MathFunctions.h DESTINATION include)
diff --git a/Help/guide/tutorial/Step6/MathFunctions/MakeTable.cxx b/Help/guide/tutorial/Step6/MathFunctions/MakeTable.cxx
new file mode 100644
index 0000000..ee58556
--- /dev/null
+++ b/Help/guide/tutorial/Step6/MathFunctions/MakeTable.cxx
@@ -0,0 +1,25 @@
+// A simple program that builds a sqrt table
+#include <cmath>
+#include <fstream>
+#include <iostream>
+
+int main(int argc, char* argv[])
+{
+ // make sure we have enough arguments
+ if (argc < 2) {
+ return 1;
+ }
+
+ std::ofstream fout(argv[1], std::ios_base::out);
+ const bool fileOpen = fout.is_open();
+ if (fileOpen) {
+ fout << "double sqrtTable[] = {" << std::endl;
+ for (int i = 0; i < 10; ++i) {
+ fout << sqrt(static_cast<double>(i)) << "," << std::endl;
+ }
+ // close the table with a zero
+ fout << "0};" << std::endl;
+ fout.close();
+ }
+ return fileOpen ? 0 : 1; // return 0 if wrote the file
+}
diff --git a/Help/guide/tutorial/Step6/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Step6/MathFunctions/MathFunctions.h
new file mode 100644
index 0000000..cd36bcc
--- /dev/null
+++ b/Help/guide/tutorial/Step6/MathFunctions/MathFunctions.h
@@ -0,0 +1 @@
+double mysqrt(double x);
diff --git a/Help/guide/tutorial/Step6/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step6/MathFunctions/mysqrt.cxx
new file mode 100644
index 0000000..0637063
--- /dev/null
+++ b/Help/guide/tutorial/Step6/MathFunctions/mysqrt.cxx
@@ -0,0 +1,32 @@
+#include <cmath>
+#include <iostream>
+
+#include "MathFunctions.h"
+
+// a hack square root calculation using simple operations
+double mysqrt(double x)
+{
+ if (x <= 0) {
+ return 0;
+ }
+
+ // if we have both log and exp then use them
+#if defined(HAVE_LOG) && defined(HAVE_EXP)
+ double result = exp(log(x) * 0.5);
+ std::cout << "Computing sqrt of " << x << " to be " << result
+ << " using log and exp" << std::endl;
+#else
+ double result = x;
+
+ // do ten iterations
+ for (int i = 0; i < 10; ++i) {
+ if (result <= 0) {
+ result = 0.1;
+ }
+ double delta = x - (result * result);
+ result = result + 0.5 * delta / result;
+ std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
+ }
+#endif
+ return result;
+}
diff --git a/Help/guide/tutorial/Step6/TutorialConfig.h.in b/Help/guide/tutorial/Step6/TutorialConfig.h.in
new file mode 100644
index 0000000..e23f521
--- /dev/null
+++ b/Help/guide/tutorial/Step6/TutorialConfig.h.in
@@ -0,0 +1,4 @@
+// the configured options and settings for Tutorial
+#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
+#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
+#cmakedefine USE_MYMATH
diff --git a/Help/guide/tutorial/Step6/tutorial.cxx b/Help/guide/tutorial/Step6/tutorial.cxx
new file mode 100644
index 0000000..b3c6a4f
--- /dev/null
+++ b/Help/guide/tutorial/Step6/tutorial.cxx
@@ -0,0 +1,36 @@
+// A simple program that computes the square root of a number
+#include <cmath>
+#include <iostream>
+#include <string>
+
+#include "TutorialConfig.h"
+
+// should we include the MathFunctions header?
+#ifdef USE_MYMATH
+# include "MathFunctions.h"
+#endif
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ // report version
+ std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
+ << Tutorial_VERSION_MINOR << std::endl;
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = std::stod(argv[1]);
+
+ // which square root function should we use?
+#ifdef USE_MYMATH
+ const double outputValue = mysqrt(inputValue);
+#else
+ const double outputValue = sqrt(inputValue);
+#endif
+
+ std::cout << "The square root of " << inputValue << " is " << outputValue
+ << std::endl;
+ return 0;
+}
diff --git a/Help/guide/tutorial/Step7/CMakeLists.txt b/Help/guide/tutorial/Step7/CMakeLists.txt
new file mode 100644
index 0000000..c3b375a
--- /dev/null
+++ b/Help/guide/tutorial/Step7/CMakeLists.txt
@@ -0,0 +1,66 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name and version
+project(Tutorial VERSION 1.0)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# should we use our own math functions
+option(USE_MYMATH "Use tutorial provided math implementation" ON)
+
+# configure a header file to pass some of the CMake settings
+# to the source code
+configure_file(TutorialConfig.h.in TutorialConfig.h)
+
+# add the MathFunctions library
+if(USE_MYMATH)
+ add_subdirectory(MathFunctions)
+ list(APPEND EXTRA_LIBS MathFunctions)
+endif()
+
+# add the executable
+add_executable(Tutorial tutorial.cxx)
+target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
+
+# add the binary tree to the search path for include files
+# so that we will find TutorialConfig.h
+target_include_directories(Tutorial PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ )
+
+# add the install targets
+install(TARGETS Tutorial DESTINATION bin)
+install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
+ DESTINATION include
+ )
+
+# enable testing
+enable_testing()
+
+# does the application run
+add_test(NAME Runs COMMAND Tutorial 25)
+
+# does the usage message work?
+add_test(NAME Usage COMMAND Tutorial)
+set_tests_properties(Usage
+ PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
+ )
+
+# define a function to simplify adding tests
+function(do_test target arg result)
+ add_test(NAME Comp${arg} COMMAND ${target} ${arg})
+ set_tests_properties(Comp${arg}
+ PROPERTIES PASS_REGULAR_EXPRESSION ${result}
+ )
+endfunction(do_test)
+
+# do a bunch of result based tests
+do_test(Tutorial 4 "4 is 2")
+do_test(Tutorial 9 "9 is 3")
+do_test(Tutorial 5 "5 is 2.236")
+do_test(Tutorial 7 "7 is 2.645")
+do_test(Tutorial 25 "25 is 5")
+do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial 0.0001 "0.0001 is 0.01")
diff --git a/Help/guide/tutorial/Step7/License.txt b/Help/guide/tutorial/Step7/License.txt
new file mode 100644
index 0000000..c62d00b
--- /dev/null
+++ b/Help/guide/tutorial/Step7/License.txt
@@ -0,0 +1,2 @@
+This is the open source License.txt file introduced in
+CMake/Tutorial/Step7...
diff --git a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..9ede4b3
--- /dev/null
+++ b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt
@@ -0,0 +1,29 @@
+# first we add the executable that generates the table
+add_executable(MakeTable MakeTable.cxx)
+
+# add the command to generate the source code
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ DEPENDS MakeTable
+ )
+
+# add the main library
+add_library(MathFunctions
+ mysqrt.cxx
+ ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ )
+
+# state that anybody linking to us needs to include the current source dir
+# to find MathFunctions.h, while we don't.
+# state that we depend on Tutorial_BINARY_DIR but consumers don't, as the
+# TutorialConfig.h include is an implementation detail
+# state that we depend on our binary dir to find Table.h
+target_include_directories(MathFunctions
+ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
+ )
+
+# install rules
+install(TARGETS MathFunctions DESTINATION lib)
+install(FILES MathFunctions.h DESTINATION include)
diff --git a/Help/guide/tutorial/Step7/MathFunctions/MakeTable.cxx b/Help/guide/tutorial/Step7/MathFunctions/MakeTable.cxx
new file mode 100644
index 0000000..ee58556
--- /dev/null
+++ b/Help/guide/tutorial/Step7/MathFunctions/MakeTable.cxx
@@ -0,0 +1,25 @@
+// A simple program that builds a sqrt table
+#include <cmath>
+#include <fstream>
+#include <iostream>
+
+int main(int argc, char* argv[])
+{
+ // make sure we have enough arguments
+ if (argc < 2) {
+ return 1;
+ }
+
+ std::ofstream fout(argv[1], std::ios_base::out);
+ const bool fileOpen = fout.is_open();
+ if (fileOpen) {
+ fout << "double sqrtTable[] = {" << std::endl;
+ for (int i = 0; i < 10; ++i) {
+ fout << sqrt(static_cast<double>(i)) << "," << std::endl;
+ }
+ // close the table with a zero
+ fout << "0};" << std::endl;
+ fout.close();
+ }
+ return fileOpen ? 0 : 1; // return 0 if wrote the file
+}
diff --git a/Help/guide/tutorial/Step7/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Step7/MathFunctions/MathFunctions.h
new file mode 100644
index 0000000..cd36bcc
--- /dev/null
+++ b/Help/guide/tutorial/Step7/MathFunctions/MathFunctions.h
@@ -0,0 +1 @@
+double mysqrt(double x);
diff --git a/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx
new file mode 100644
index 0000000..7d80ee9
--- /dev/null
+++ b/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx
@@ -0,0 +1,33 @@
+#include <iostream>
+
+#include "MathFunctions.h"
+
+// include the generated table
+#include "Table.h"
+
+// a hack square root calculation using simple operations
+double mysqrt(double x)
+{
+ if (x <= 0) {
+ return 0;
+ }
+
+ // use the table to help find an initial value
+ double result = x;
+ if (x >= 1 && x < 10) {
+ std::cout << "Use the table to help find an initial value " << std::endl;
+ result = sqrtTable[static_cast<int>(x)];
+ }
+
+ // do ten iterations
+ for (int i = 0; i < 10; ++i) {
+ if (result <= 0) {
+ result = 0.1;
+ }
+ double delta = x - (result * result);
+ result = result + 0.5 * delta / result;
+ std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
+ }
+
+ return result;
+}
diff --git a/Help/guide/tutorial/Step7/TutorialConfig.h.in b/Help/guide/tutorial/Step7/TutorialConfig.h.in
new file mode 100644
index 0000000..e23f521
--- /dev/null
+++ b/Help/guide/tutorial/Step7/TutorialConfig.h.in
@@ -0,0 +1,4 @@
+// the configured options and settings for Tutorial
+#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
+#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
+#cmakedefine USE_MYMATH
diff --git a/Help/guide/tutorial/Step7/tutorial.cxx b/Help/guide/tutorial/Step7/tutorial.cxx
new file mode 100644
index 0000000..b3c6a4f
--- /dev/null
+++ b/Help/guide/tutorial/Step7/tutorial.cxx
@@ -0,0 +1,36 @@
+// A simple program that computes the square root of a number
+#include <cmath>
+#include <iostream>
+#include <string>
+
+#include "TutorialConfig.h"
+
+// should we include the MathFunctions header?
+#ifdef USE_MYMATH
+# include "MathFunctions.h"
+#endif
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ // report version
+ std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
+ << Tutorial_VERSION_MINOR << std::endl;
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = std::stod(argv[1]);
+
+ // which square root function should we use?
+#ifdef USE_MYMATH
+ const double outputValue = mysqrt(inputValue);
+#else
+ const double outputValue = sqrt(inputValue);
+#endif
+
+ std::cout << "The square root of " << inputValue << " is " << outputValue
+ << std::endl;
+ return 0;
+}
diff --git a/Help/guide/tutorial/Step8/CMakeLists.txt b/Help/guide/tutorial/Step8/CMakeLists.txt
new file mode 100644
index 0000000..19b9913
--- /dev/null
+++ b/Help/guide/tutorial/Step8/CMakeLists.txt
@@ -0,0 +1,73 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name and version
+project(Tutorial VERSION 1.0)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# should we use our own math functions
+option(USE_MYMATH "Use tutorial provided math implementation" ON)
+
+# configure a header file to pass some of the CMake settings
+# to the source code
+configure_file(TutorialConfig.h.in TutorialConfig.h)
+
+# add the MathFunctions library
+if(USE_MYMATH)
+ add_subdirectory(MathFunctions)
+ list(APPEND EXTRA_LIBS MathFunctions)
+endif()
+
+# add the executable
+add_executable(Tutorial tutorial.cxx)
+target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
+
+# add the binary tree to the search path for include files
+# so that we will find TutorialConfig.h
+target_include_directories(Tutorial PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ )
+
+# add the install targets
+install(TARGETS Tutorial DESTINATION bin)
+install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
+ DESTINATION include
+ )
+
+# enable testing
+enable_testing()
+
+# does the application run
+add_test(NAME Runs COMMAND Tutorial 25)
+
+# does the usage message work?
+add_test(NAME Usage COMMAND Tutorial)
+set_tests_properties(Usage
+ PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
+ )
+
+# define a function to simplify adding tests
+function(do_test target arg result)
+ add_test(NAME Comp${arg} COMMAND ${target} ${arg})
+ set_tests_properties(Comp${arg}
+ PROPERTIES PASS_REGULAR_EXPRESSION ${result}
+ )
+endfunction(do_test)
+
+# do a bunch of result based tests
+do_test(Tutorial 4 "4 is 2")
+do_test(Tutorial 9 "9 is 3")
+do_test(Tutorial 5 "5 is 2.236")
+do_test(Tutorial 7 "7 is 2.645")
+do_test(Tutorial 25 "25 is 5")
+do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial 0.0001 "0.0001 is 0.01")
+
+# setup installer
+include(InstallRequiredSystemLibraries)
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
+set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
+set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
+include(CPack)
diff --git a/Help/guide/tutorial/Step8/License.txt b/Help/guide/tutorial/Step8/License.txt
new file mode 100644
index 0000000..c62d00b
--- /dev/null
+++ b/Help/guide/tutorial/Step8/License.txt
@@ -0,0 +1,2 @@
+This is the open source License.txt file introduced in
+CMake/Tutorial/Step7...
diff --git a/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..9ede4b3
--- /dev/null
+++ b/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt
@@ -0,0 +1,29 @@
+# first we add the executable that generates the table
+add_executable(MakeTable MakeTable.cxx)
+
+# add the command to generate the source code
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ DEPENDS MakeTable
+ )
+
+# add the main library
+add_library(MathFunctions
+ mysqrt.cxx
+ ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ )
+
+# state that anybody linking to us needs to include the current source dir
+# to find MathFunctions.h, while we don't.
+# state that we depend on Tutorial_BINARY_DIR but consumers don't, as the
+# TutorialConfig.h include is an implementation detail
+# state that we depend on our binary dir to find Table.h
+target_include_directories(MathFunctions
+ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
+ )
+
+# install rules
+install(TARGETS MathFunctions DESTINATION lib)
+install(FILES MathFunctions.h DESTINATION include)
diff --git a/Help/guide/tutorial/Step8/MathFunctions/MakeTable.cxx b/Help/guide/tutorial/Step8/MathFunctions/MakeTable.cxx
new file mode 100644
index 0000000..ee58556
--- /dev/null
+++ b/Help/guide/tutorial/Step8/MathFunctions/MakeTable.cxx
@@ -0,0 +1,25 @@
+// A simple program that builds a sqrt table
+#include <cmath>
+#include <fstream>
+#include <iostream>
+
+int main(int argc, char* argv[])
+{
+ // make sure we have enough arguments
+ if (argc < 2) {
+ return 1;
+ }
+
+ std::ofstream fout(argv[1], std::ios_base::out);
+ const bool fileOpen = fout.is_open();
+ if (fileOpen) {
+ fout << "double sqrtTable[] = {" << std::endl;
+ for (int i = 0; i < 10; ++i) {
+ fout << sqrt(static_cast<double>(i)) << "," << std::endl;
+ }
+ // close the table with a zero
+ fout << "0};" << std::endl;
+ fout.close();
+ }
+ return fileOpen ? 0 : 1; // return 0 if wrote the file
+}
diff --git a/Help/guide/tutorial/Step8/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Step8/MathFunctions/MathFunctions.h
new file mode 100644
index 0000000..cd36bcc
--- /dev/null
+++ b/Help/guide/tutorial/Step8/MathFunctions/MathFunctions.h
@@ -0,0 +1 @@
+double mysqrt(double x);
diff --git a/Help/guide/tutorial/Step8/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step8/MathFunctions/mysqrt.cxx
new file mode 100644
index 0000000..7d80ee9
--- /dev/null
+++ b/Help/guide/tutorial/Step8/MathFunctions/mysqrt.cxx
@@ -0,0 +1,33 @@
+#include <iostream>
+
+#include "MathFunctions.h"
+
+// include the generated table
+#include "Table.h"
+
+// a hack square root calculation using simple operations
+double mysqrt(double x)
+{
+ if (x <= 0) {
+ return 0;
+ }
+
+ // use the table to help find an initial value
+ double result = x;
+ if (x >= 1 && x < 10) {
+ std::cout << "Use the table to help find an initial value " << std::endl;
+ result = sqrtTable[static_cast<int>(x)];
+ }
+
+ // do ten iterations
+ for (int i = 0; i < 10; ++i) {
+ if (result <= 0) {
+ result = 0.1;
+ }
+ double delta = x - (result * result);
+ result = result + 0.5 * delta / result;
+ std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
+ }
+
+ return result;
+}
diff --git a/Help/guide/tutorial/Step8/TutorialConfig.h.in b/Help/guide/tutorial/Step8/TutorialConfig.h.in
new file mode 100644
index 0000000..e23f521
--- /dev/null
+++ b/Help/guide/tutorial/Step8/TutorialConfig.h.in
@@ -0,0 +1,4 @@
+// the configured options and settings for Tutorial
+#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
+#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
+#cmakedefine USE_MYMATH
diff --git a/Help/guide/tutorial/Step8/tutorial.cxx b/Help/guide/tutorial/Step8/tutorial.cxx
new file mode 100644
index 0000000..b3c6a4f
--- /dev/null
+++ b/Help/guide/tutorial/Step8/tutorial.cxx
@@ -0,0 +1,36 @@
+// A simple program that computes the square root of a number
+#include <cmath>
+#include <iostream>
+#include <string>
+
+#include "TutorialConfig.h"
+
+// should we include the MathFunctions header?
+#ifdef USE_MYMATH
+# include "MathFunctions.h"
+#endif
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ // report version
+ std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
+ << Tutorial_VERSION_MINOR << std::endl;
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = std::stod(argv[1]);
+
+ // which square root function should we use?
+#ifdef USE_MYMATH
+ const double outputValue = mysqrt(inputValue);
+#else
+ const double outputValue = sqrt(inputValue);
+#endif
+
+ std::cout << "The square root of " << inputValue << " is " << outputValue
+ << std::endl;
+ return 0;
+}
diff --git a/Help/guide/tutorial/Step9/CMakeLists.txt b/Help/guide/tutorial/Step9/CMakeLists.txt
new file mode 100644
index 0000000..d5f1cc8
--- /dev/null
+++ b/Help/guide/tutorial/Step9/CMakeLists.txt
@@ -0,0 +1,72 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name and version
+project(Tutorial VERSION 1.0)
+
+# specify the C++ standard
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+# should we use our own math functions
+option(USE_MYMATH "Use tutorial provided math implementation" ON)
+
+# configure a header file to pass some of the CMake settings
+# to the source code
+configure_file(TutorialConfig.h.in TutorialConfig.h)
+
+# add the MathFunctions library
+if(USE_MYMATH)
+ add_subdirectory(MathFunctions)
+ list(APPEND EXTRA_LIBS MathFunctions)
+endif()
+
+# add the executable
+add_executable(Tutorial tutorial.cxx)
+target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
+
+# add the binary tree to the search path for include files
+# so that we will find TutorialConfig.h
+target_include_directories(Tutorial PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ )
+
+# add the install targets
+install(TARGETS Tutorial DESTINATION bin)
+install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
+ DESTINATION include
+ )
+
+# enable testing
+include(CTest)
+
+# does the application run
+add_test(NAME Runs COMMAND Tutorial 25)
+
+# does the usage message work?
+add_test(NAME Usage COMMAND Tutorial)
+set_tests_properties(Usage
+ PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
+ )
+
+# define a function to simplify adding tests
+function(do_test target arg result)
+ add_test(NAME Comp${arg} COMMAND ${target} ${arg})
+ set_tests_properties(Comp${arg}
+ PROPERTIES PASS_REGULAR_EXPRESSION ${result}
+ )
+endfunction(do_test)
+
+# do a bunch of result based tests
+do_test(Tutorial 4 "4 is 2")
+do_test(Tutorial 9 "9 is 3")
+do_test(Tutorial 5 "5 is 2.236")
+do_test(Tutorial 7 "7 is 2.645")
+do_test(Tutorial 25 "25 is 5")
+do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial 0.0001 "0.0001 is 0.01")
+
+include(InstallRequiredSystemLibraries)
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
+set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
+set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
+include(CPack)
diff --git a/Help/guide/tutorial/Step9/CTestConfig.cmake b/Help/guide/tutorial/Step9/CTestConfig.cmake
new file mode 100644
index 0000000..73efdb1
--- /dev/null
+++ b/Help/guide/tutorial/Step9/CTestConfig.cmake
@@ -0,0 +1,7 @@
+set(CTEST_PROJECT_NAME "CMakeTutorial")
+set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
+
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "my.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial")
+set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/Help/guide/tutorial/Step9/License.txt b/Help/guide/tutorial/Step9/License.txt
new file mode 100644
index 0000000..c62d00b
--- /dev/null
+++ b/Help/guide/tutorial/Step9/License.txt
@@ -0,0 +1,2 @@
+This is the open source License.txt file introduced in
+CMake/Tutorial/Step7...
diff --git a/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..50f0701
--- /dev/null
+++ b/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt
@@ -0,0 +1,27 @@
+# first we add the executable that generates the table
+add_executable(MakeTable MakeTable.cxx)
+
+# add the command to generate the source code
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ DEPENDS MakeTable
+ )
+
+# add the main library
+add_library(MathFunctions
+ mysqrt.cxx
+ ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ )
+
+# state that anybody linking to us needs to include the current source dir
+# to find MathFunctions.h, while we don't.
+# state that we depend on our binary dir to find Table.h
+target_include_directories(MathFunctions
+ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
+ )
+
+# install rules
+install(TARGETS MathFunctions DESTINATION lib)
+install(FILES MathFunctions.h DESTINATION include)
diff --git a/Help/guide/tutorial/Step9/MathFunctions/MakeTable.cxx b/Help/guide/tutorial/Step9/MathFunctions/MakeTable.cxx
new file mode 100644
index 0000000..ee58556
--- /dev/null
+++ b/Help/guide/tutorial/Step9/MathFunctions/MakeTable.cxx
@@ -0,0 +1,25 @@
+// A simple program that builds a sqrt table
+#include <cmath>
+#include <fstream>
+#include <iostream>
+
+int main(int argc, char* argv[])
+{
+ // make sure we have enough arguments
+ if (argc < 2) {
+ return 1;
+ }
+
+ std::ofstream fout(argv[1], std::ios_base::out);
+ const bool fileOpen = fout.is_open();
+ if (fileOpen) {
+ fout << "double sqrtTable[] = {" << std::endl;
+ for (int i = 0; i < 10; ++i) {
+ fout << sqrt(static_cast<double>(i)) << "," << std::endl;
+ }
+ // close the table with a zero
+ fout << "0};" << std::endl;
+ fout.close();
+ }
+ return fileOpen ? 0 : 1; // return 0 if wrote the file
+}
diff --git a/Help/guide/tutorial/Step9/MathFunctions/MathFunctions.cxx b/Help/guide/tutorial/Step9/MathFunctions/MathFunctions.cxx
new file mode 100644
index 0000000..0145300
--- /dev/null
+++ b/Help/guide/tutorial/Step9/MathFunctions/MathFunctions.cxx
@@ -0,0 +1,19 @@
+
+#include "MathFunctions.h"
+
+#include <cmath>
+
+#ifdef USE_MYMATH
+# include "mysqrt.h"
+#endif
+
+namespace mathfunctions {
+double sqrt(double x)
+{
+#ifdef USE_MYMATH
+ return detail::mysqrt(x);
+#else
+ return std::sqrt(x);
+#endif
+}
+}
diff --git a/Help/guide/tutorial/Step9/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Step9/MathFunctions/MathFunctions.h
new file mode 100644
index 0000000..cd36bcc
--- /dev/null
+++ b/Help/guide/tutorial/Step9/MathFunctions/MathFunctions.h
@@ -0,0 +1 @@
+double mysqrt(double x);
diff --git a/Help/guide/tutorial/Step9/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step9/MathFunctions/mysqrt.cxx
new file mode 100644
index 0000000..7d80ee9
--- /dev/null
+++ b/Help/guide/tutorial/Step9/MathFunctions/mysqrt.cxx
@@ -0,0 +1,33 @@
+#include <iostream>
+
+#include "MathFunctions.h"
+
+// include the generated table
+#include "Table.h"
+
+// a hack square root calculation using simple operations
+double mysqrt(double x)
+{
+ if (x <= 0) {
+ return 0;
+ }
+
+ // use the table to help find an initial value
+ double result = x;
+ if (x >= 1 && x < 10) {
+ std::cout << "Use the table to help find an initial value " << std::endl;
+ result = sqrtTable[static_cast<int>(x)];
+ }
+
+ // do ten iterations
+ for (int i = 0; i < 10; ++i) {
+ if (result <= 0) {
+ result = 0.1;
+ }
+ double delta = x - (result * result);
+ result = result + 0.5 * delta / result;
+ std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
+ }
+
+ return result;
+}
diff --git a/Help/guide/tutorial/Step9/MathFunctions/mysqrt.h b/Help/guide/tutorial/Step9/MathFunctions/mysqrt.h
new file mode 100644
index 0000000..e1c42ef
--- /dev/null
+++ b/Help/guide/tutorial/Step9/MathFunctions/mysqrt.h
@@ -0,0 +1,6 @@
+
+namespace mathfunctions {
+namespace detail {
+double mysqrt(double x);
+}
+}
diff --git a/Help/guide/tutorial/Step9/TutorialConfig.h.in b/Help/guide/tutorial/Step9/TutorialConfig.h.in
new file mode 100644
index 0000000..e23f521
--- /dev/null
+++ b/Help/guide/tutorial/Step9/TutorialConfig.h.in
@@ -0,0 +1,4 @@
+// the configured options and settings for Tutorial
+#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
+#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
+#cmakedefine USE_MYMATH
diff --git a/Help/guide/tutorial/Step9/tutorial.cxx b/Help/guide/tutorial/Step9/tutorial.cxx
new file mode 100644
index 0000000..b3c6a4f
--- /dev/null
+++ b/Help/guide/tutorial/Step9/tutorial.cxx
@@ -0,0 +1,36 @@
+// A simple program that computes the square root of a number
+#include <cmath>
+#include <iostream>
+#include <string>
+
+#include "TutorialConfig.h"
+
+// should we include the MathFunctions header?
+#ifdef USE_MYMATH
+# include "MathFunctions.h"
+#endif
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ // report version
+ std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
+ << Tutorial_VERSION_MINOR << std::endl;
+ std::cout << "Usage: " << argv[0] << " number" << std::endl;
+ return 1;
+ }
+
+ // convert input to double
+ const double inputValue = std::stod(argv[1]);
+
+ // which square root function should we use?
+#ifdef USE_MYMATH
+ const double outputValue = mysqrt(inputValue);
+#else
+ const double outputValue = sqrt(inputValue);
+#endif
+
+ std::cout << "The square root of " << inputValue << " is " << outputValue
+ << std::endl;
+ return 0;
+}
diff --git a/Help/guide/tutorial/index.rst b/Help/guide/tutorial/index.rst
new file mode 100644
index 0000000..94753d5
--- /dev/null
+++ b/Help/guide/tutorial/index.rst
@@ -0,0 +1,946 @@
+CMake Tutorial
+**************
+
+.. only:: html
+
+ .. 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
+documentation and source code for examples can be found in the
+``Help/guide/tutorial`` directory of the CMake source code tree. Each step has
+its own subdirectory containing code that may be used as a starting point. The
+tutorial examples are progressive so that each step provides the complete
+solution for the previous step.
+
+A Basic Starting Point (Step 1)
+===============================
+
+The most basic project is an executable built from source code files.
+For simple projects, a three line ``CMakeLists.txt`` file is all that is
+required. This will be the starting point for our tutorial. Create a
+``CMakeLists.txt`` file in the ``Step1`` directory that looks like:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.10)
+
+ # set the project name
+ project(Tutorial)
+
+ # add the executable
+ add_executable(Tutorial tutorial.cxx)
+
+
+Note that this example uses lower case commands in the ``CMakeLists.txt`` file.
+Upper, lower, and mixed case commands are supported by CMake. The source
+code for ``tutorial.cxx`` is provided in the ``Step1`` directory and can be
+used to compute the square root of a number.
+
+Adding a Version Number and Configured Header File
+--------------------------------------------------
+
+The first feature we will add is to provide our executable and project with a
+version number. While we could do this exclusively in the source code, using
+``CMakeLists.txt`` provides more flexibility.
+
+First, modify the ``CMakeLists.txt`` file to use the :command:`project` command
+to set the project name and version number.
+
+.. literalinclude:: Step2/CMakeLists.txt
+ :language: cmake
+ :end-before: # specify the C++ standard
+
+Then, configure a header file to pass the version number to the source
+code:
+
+.. literalinclude:: Step2/CMakeLists.txt
+ :language: cmake
+ :start-after: # to the source code
+ :end-before: # add the executable
+
+Since the configured file will be written into the binary tree, we
+must add that directory to the list of paths to search for include
+files. Add the following lines to the end of the ``CMakeLists.txt`` file:
+
+.. literalinclude:: Step2/CMakeLists.txt
+ :language: cmake
+ :start-after: # so that we will find TutorialConfig.h
+
+Using your favorite editor, create ``TutorialConfig.h.in`` in the source
+directory with the following contents:
+
+.. literalinclude:: Step2/TutorialConfig.h.in
+ :language: cmake
+
+When CMake configures this header file the values for
+``@Tutorial_VERSION_MAJOR@`` and ``@Tutorial_VERSION_MINOR@`` will be
+replaced.
+
+Next modify ``tutorial.cxx`` to include the configured header file,
+``TutorialConfig.h``.
+
+Finally, let's print out the executable name and version number by updating
+``tutorial.cxx`` as follows:
+
+.. literalinclude:: Step2/tutorial.cxx
+ :language: c++
+ :start-after: {
+ :end-before: // convert input to double
+
+Specify the C++ Standard
+-------------------------
+
+Next let's add some C++11 features to our project by replacing ``atof`` with
+``std::stod`` in ``tutorial.cxx``. At the same time, remove
+``#include <cstdlib>``.
+
+.. literalinclude:: Step2/tutorial.cxx
+ :language: c++
+ :start-after: // convert input to double
+ :end-before: // calculate square root
+
+We will need to explicitly state in the CMake code that it should use the
+correct flags. The easiest way to enable support for a specific C++ standard
+in CMake is by using the :variable:`CMAKE_CXX_STANDARD` variable. For this
+tutorial, set the :variable:`CMAKE_CXX_STANDARD` variable in the
+``CMakeLists.txt`` file to 11 and :variable:`CMAKE_CXX_STANDARD_REQUIRED` to
+True. Make sure to add the ``CMAKE_CXX_STANDARD`` declarations above the call
+to ``add_executable``.
+
+.. literalinclude:: Step2/CMakeLists.txt
+ :language: cmake
+ :end-before: # configure a header file to pass some of the CMake settings
+
+Build and Test
+--------------
+
+Run the :manual:`cmake <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
+with your chosen build tool.
+
+For example, from the command line we could navigate to the
+``Help/guide/tutorial`` directory of the CMake source code tree and create a
+build directory:
+
+.. code-block:: console
+
+ mkdir Step1_build
+
+Next, navigate to the build directory and run CMake to configure the project
+and generate a native build system:
+
+.. code-block:: console
+
+ cd Step1_build
+ cmake ../Step1
+
+Then call that build system to actually compile/link the project:
+
+.. code-block:: console
+
+ cmake --build .
+
+Finally, try to use the newly built ``Tutorial`` with these commands:
+
+.. code-block:: console
+
+ Tutorial 4294967296
+ Tutorial 10
+ Tutorial
+
+Adding a Library (Step 2)
+=========================
+
+Now we will add a library to our project. This library will contain our own
+implementation for computing the square root of a number. The executable can
+then use this library instead of the standard square root function provided by
+the compiler.
+
+For this tutorial we will put the library into a subdirectory
+called ``MathFunctions``. This directory already contains a header file,
+``MathFunctions.h``, and a source file ``mysqrt.cxx``. The source file has one
+function called ``mysqrt`` that provides similar functionality to the
+compiler's ``sqrt`` function.
+
+Add the following one line ``CMakeLists.txt`` file to the ``MathFunctions``
+directory:
+
+.. literalinclude:: Step3/MathFunctions/CMakeLists.txt
+ :language: cmake
+
+To make use of the new library we will add an :command:`add_subdirectory`
+call in the top-level ``CMakeLists.txt`` file so that the library will get
+built. We add the new library to the executable, and add ``MathFunctions`` as
+an include directory so that the ``mysqrt.h`` header file can be found. The
+last few lines of the top-level ``CMakeLists.txt`` file should now look like:
+
+.. code-block:: cmake
+
+ # add the MathFunctions library
+ add_subdirectory(MathFunctions)
+
+ # add the executable
+ add_executable(Tutorial tutorial.cxx)
+
+ target_link_libraries(Tutorial PUBLIC MathFunctions)
+
+ # add the binary tree to the search path for include files
+ # so that we will find TutorialConfig.h
+ target_include_directories(Tutorial PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ "${PROJECT_SOURCE_DIR}/MathFunctions"
+ )
+
+Now let us make the MathFunctions library optional. While for the tutorial
+there really isn't any need to do so, for larger projects this is a common
+occurrence. The first step is to add an option to the top-level
+``CMakeLists.txt`` file.
+
+.. literalinclude:: Step3/CMakeLists.txt
+ :language: cmake
+ :start-after: # should we use our own math functions
+ :end-before: # add the MathFunctions library
+
+This option will be displayed in the :manual:`cmake-gui <cmake-gui(1)>` and
+:manual:`ccmake <ccmake(1)>`
+with a default value of ON that can be changed by the user. This setting will
+be stored in the cache so that the user does not need to set the value each
+time they run CMake on a build directory.
+
+The next change is to make building and linking the MathFunctions library
+conditional. To do this we change the end of the top-level ``CMakeLists.txt``
+file to look like the following:
+
+.. literalinclude:: Step3/CMakeLists.txt
+ :language: cmake
+ :start-after: # add the MathFunctions library
+
+Note the use of the variable ``EXTRA_LIBS`` to collect up any optional
+libraries to later be linked into the executable. The variable
+``EXTRA_INCLUDES`` is used similarly for optional header files. This is a
+classic approach when dealing with many optional components, we will cover
+the modern approach in the next step.
+
+The corresponding changes to the source code are fairly straightforward.
+First, in ``tutorial.cxx``, include the ``MathFunctions.h`` header if we
+need it:
+
+.. literalinclude:: Step3/tutorial.cxx
+ :language: c++
+ :start-after: // should we include the MathFunctions header
+ :end-before: int main
+
+Then, in the same file, make ``USE_MYMATH`` control which square root
+function is used:
+
+.. literalinclude:: Step3/tutorial.cxx
+ :language: c++
+ :start-after: // which square root function should we use?
+ :end-before: std::cout << "The square root of
+
+Since the source code now requires ``USE_MYMATH`` we can add it to
+``TutorialConfig.h.in`` with the following line:
+
+.. literalinclude:: Step3/TutorialConfig.h.in
+ :language: c
+ :lines: 4
+
+**Exercise**: Why is it important that we configure ``TutorialConfig.h.in``
+after the option for ``USE_MYMATH``? What would happen if we inverted the two?
+
+Run the :manual:`cmake <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
+with your chosen build tool. Then run the built Tutorial executable.
+
+Now let's update the value of ``USE_MYMATH``. The easiest way is to use the
+:manual:`cmake-gui <cmake-gui(1)>` or :manual:`ccmake <ccmake(1)>` if you're
+in the terminal. Or, alternatively, if you want to change the option from the
+command-line, try:
+
+.. code-block:: console
+
+ cmake ../Step2 -DUSE_MYMATH=OFF
+
+Rebuild and run the tutorial again.
+
+Which function gives better results, sqrt or mysqrt?
+
+Adding Usage Requirements for Library (Step 3)
+==============================================
+
+Usage requirements allow for far better control over a library or executable's
+link and include line while also giving more control over the transitive
+property of targets inside CMake. The primary commands that leverage usage
+requirements are:
+
+ - :command:`target_compile_definitions`
+ - :command:`target_compile_options`
+ - :command:`target_include_directories`
+ - :command:`target_link_libraries`
+
+Let's refactor our code from `Adding a Library (Step 2)`_ to use the modern
+CMake approach of usage requirements. We first state that anybody linking to
+MathFunctions needs to include the current source directory, while
+MathFunctions itself doesn't. So this can become an ``INTERFACE`` usage
+requirement.
+
+Remember ``INTERFACE`` means things that consumers require but the producer
+doesn't. Add the following lines to the end of
+``MathFunctions/CMakeLists.txt``:
+
+.. literalinclude:: Step4/MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # to find MathFunctions.h
+
+Now that we've specified usage requirements for MathFunctions we can safely
+remove our uses of the ``EXTRA_INCLUDES`` variable from the top-level
+``CMakeLists.txt``, here:
+
+.. literalinclude:: Step4/CMakeLists.txt
+ :language: cmake
+ :start-after: # add the MathFunctions library
+ :end-before: # add the executable
+
+And here:
+
+.. literalinclude:: Step4/CMakeLists.txt
+ :language: cmake
+ :start-after: # so that we will find TutorialConfig.h
+
+Once this is done, run the :manual:`cmake <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
+with your chosen build tool or by using ``cmake --build .`` from the build
+directory.
+
+Installing and Testing (Step 4)
+===============================
+
+Now we can start adding install rules and testing support to our project.
+
+Install Rules
+-------------
+
+The install rules are fairly simple: for MathFunctions we want to install the
+library and header file and for the application we want to install the
+executable and configured header.
+
+So to the end of ``MathFunctions/CMakeLists.txt`` we add:
+
+.. literalinclude:: Step5/MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # install rules
+
+And to the end of the top-level ``CMakeLists.txt`` we add:
+
+.. literalinclude:: Step5/CMakeLists.txt
+ :language: cmake
+ :start-after: # add the install targets
+ :end-before: # enable testing
+
+That is all that is needed to create a basic local install of the tutorial.
+
+Now run the :manual:`cmake <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
+with your chosen build tool.
+
+Then run the install step by using the ``install`` option of the
+:manual:`cmake <cmake(1)>` command (introduced in 3.15, older versions of
+CMake must use ``make install``) from the command line. For
+multi-configuration tools, don't forget to use the ``--config`` argument to
+specify the configuration. If using an IDE, simply build the ``INSTALL``
+target. This step will install the appropriate header files, libraries, and
+executables. For example:
+
+.. code-block:: console
+
+ cmake --install .
+
+The CMake variable :variable:`CMAKE_INSTALL_PREFIX` is used to determine the
+root of where the files will be installed. If using the ``cmake --install``
+command, the installation prefix can be overridden via the ``--prefix``
+argument. For example:
+
+.. code-block:: console
+
+ cmake --install . --prefix "/home/myuser/installdir"
+
+Navigate to the install directory and verify that the installed Tutorial runs.
+
+Testing Support
+---------------
+
+Next let's test our application. At the end of the top-level ``CMakeLists.txt``
+file we can enable testing and then add a number of basic tests to verify that
+the application is working correctly.
+
+.. literalinclude:: Step5/CMakeLists.txt
+ :language: cmake
+ :start-after: # enable testing
+
+The first test simply verifies that the application runs, does not segfault or
+otherwise crash, and has a zero return value. This is the basic form of a
+CTest test.
+
+The next test makes use of the :prop_test:`PASS_REGULAR_EXPRESSION` test
+property to verify that the output of the test contains certain strings. In
+this case, verifying that the usage message is printed when an incorrect number
+of arguments are provided.
+
+Lastly, we have a function called ``do_test`` that runs the application and
+verifies that the computed square root is correct for given input. For each
+invocation of ``do_test``, another test is added to the project with a name,
+input, and expected results based on the passed arguments.
+
+Rebuild the application and then cd to the binary directory and run the
+:manual:`ctest <ctest(1)>` executable: ``ctest -N`` and ``ctest -VV``. For
+multi-config generators (e.g. Visual Studio), the configuration type must be
+specified. To run tests in Debug mode, for example, use ``ctest -C Debug -VV``
+from the build directory (not the Debug subdirectory!). Alternatively, build
+the ``RUN_TESTS`` target from the IDE.
+
+Adding System Introspection (Step 5)
+====================================
+
+Let us consider adding some code to our project that depends on features the
+target platform may not have. For this example, we will add some code that
+depends on whether or not the target platform has the ``log`` and ``exp``
+functions. Of course almost every platform has these functions but for this
+tutorial assume that they are not common.
+
+If the platform has ``log`` and ``exp`` then we will use them to compute the
+square root in the ``mysqrt`` function. We first test for the availability of
+these functions using the :module:`CheckSymbolExists` module in
+``MathFunctions/CMakeLists.txt``. On some platforms, we will need to link to
+the m library. If ``log`` and ``exp`` are not initially found, require the m
+library and try again.
+
+.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # does this system provide the log and exp functions?
+ :end-before: # add compile definitions
+
+If available, use :command:`target_compile_definitions` to specify
+``HAVE_LOG`` and ``HAVE_EXP`` as ``PRIVATE`` compile definitions.
+
+.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # add compile definitions
+ :end-before: # install rules
+
+If ``log`` and ``exp`` are available on the system, then we will use them to
+compute the square root in the ``mysqrt`` function. Add the following code to
+the ``mysqrt`` function in ``MathFunctions/mysqrt.cxx`` (don't forget the
+``#endif`` before returning the result!):
+
+.. literalinclude:: Step6/MathFunctions/mysqrt.cxx
+ :language: c++
+ :start-after: // if we have both log and exp then use them
+ :end-before: // do ten iterations
+
+We will also need to modify ``mysqrt.cxx`` to include ``cmath``.
+
+.. literalinclude:: Step6/MathFunctions/mysqrt.cxx
+ :language: c++
+ :end-before: #include <iostream>
+
+Run the :manual:`cmake <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
+with your chosen build tool and run the Tutorial executable.
+
+Which function gives better results now, sqrt or mysqrt?
+
+Adding a Custom Command and Generated File (Step 6)
+===================================================
+
+Suppose, for the purpose of this tutorial, we decide that we never want to use
+the platform ``log`` and ``exp`` functions and instead would like to
+generate a table of precomputed values to use in the ``mysqrt`` function.
+In this section, we will create the table as part of the build process,
+and then compile that table into our application.
+
+First, let's remove the check for the ``log`` and ``exp`` functions in
+``MathFunctions/CMakeLists.txt``. Then remove the check for ``HAVE_LOG`` and
+``HAVE_EXP`` from ``mysqrt.cxx``. At the same time, we can remove
+:code:`#include <cmath>`.
+
+In the ``MathFunctions`` subdirectory, a new source file named
+``MakeTable.cxx`` has been provided to generate the table.
+
+After reviewing the file, we can see that the table is produced as valid C++
+code and that the output filename is passed in as an argument.
+
+The next step is to add the appropriate commands to the
+``MathFunctions/CMakeLists.txt`` file to build the MakeTable executable and
+then run it as part of the build process. A few commands are needed to
+accomplish this.
+
+First, at the top of ``MathFunctions/CMakeLists.txt``, the executable for
+``MakeTable`` is added as any other executable would be added.
+
+.. literalinclude:: Step7/MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # first we add the executable that generates the table
+ :end-before: # add the command to generate the source code
+
+Then we add a custom command that specifies how to produce ``Table.h``
+by running MakeTable.
+
+.. literalinclude:: Step7/MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # add the command to generate the source code
+ :end-before: # add the main library
+
+Next we have to let CMake know that ``mysqrt.cxx`` depends on the generated
+file ``Table.h``. This is done by adding the generated ``Table.h`` to the list
+of sources for the library MathFunctions.
+
+.. literalinclude:: Step7/MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # add the main library
+ :end-before: # state that anybody linking
+
+We also have to add the current binary directory to the list of include
+directories so that ``Table.h`` can be found and included by ``mysqrt.cxx``.
+
+.. literalinclude:: Step7/MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # state that we depend on our bin
+ :end-before: # install rules
+
+Now let's use the generated table. First, modify ``mysqrt.cxx`` to include
+``Table.h``. Next, we can rewrite the mysqrt function to use the table:
+
+.. literalinclude:: Step7/MathFunctions/mysqrt.cxx
+ :language: c++
+ :start-after: // a hack square root calculation using simple operations
+
+Run the :manual:`cmake <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
+with your chosen build tool.
+
+When this project is built it will first build the ``MakeTable`` executable.
+It will then run ``MakeTable`` to produce ``Table.h``. Finally, it will
+compile ``mysqrt.cxx`` which includes ``Table.h`` to produce the MathFunctions
+library.
+
+Run the Tutorial executable and verify that it is using the table.
+
+Building an Installer (Step 7)
+==============================
+
+Next suppose that we want to distribute our project to other people so that
+they can use it. We want to provide both binary and source distributions on a
+variety of platforms. This is a little different from the install we did
+previously in `Installing and Testing (Step 4)`_ , where we were
+installing the binaries that we had built from the source code. In this
+example we will be building installation packages that support binary
+installations and package management features. To accomplish this we will use
+CPack to create platform specific installers. Specifically we need to add a
+few lines to the bottom of our top-level ``CMakeLists.txt`` file.
+
+.. literalinclude:: Step8/CMakeLists.txt
+ :language: cmake
+ :start-after: # setup installer
+
+That is all there is to it. We start by including
+:module:`InstallRequiredSystemLibraries`. This module will include any runtime
+libraries that are needed by the project for the current platform. Next we set
+some CPack variables to where we have stored the license and version
+information for this project. The version information was set earlier in this
+tutorial and the ``license.txt`` has been included in the top-level source
+directory for this step.
+
+Finally we include the :module:`CPack module <CPack>` which will use these
+variables and some other properties of the current system to setup an
+installer.
+
+The next step is to build the project in the usual manner and then run the
+:manual:`cpack <cpack(1)>` executable. To build a binary distribution, from the
+binary directory run:
+
+.. code-block:: console
+
+ cpack
+
+To specify the generator, use the ``-G`` option. For multi-config builds, use
+``-C`` to specify the configuration. For example:
+
+.. code-block:: console
+
+ cpack -G ZIP -C Debug
+
+To create a source distribution you would type:
+
+.. code-block:: console
+
+ cpack --config CPackSourceConfig.cmake
+
+Alternatively, run ``make package`` or right click the ``Package`` target and
+``Build Project`` from an IDE.
+
+Run the installer found in the binary directory. Then run the installed
+executable and verify that it works.
+
+Adding Support for a Dashboard (Step 8)
+=======================================
+
+Adding support for submitting our test results to a dashboard is simple. We
+already defined a number of tests for our project in `Testing Support`_. Now we
+just have to run those tests and submit them to a dashboard. To include support
+for dashboards we include the :module:`CTest` module in our top-level
+``CMakeLists.txt``.
+
+Replace:
+
+.. code-block:: cmake
+
+ # enable testing
+ enable_testing()
+
+With:
+
+.. code-block:: cmake
+
+ # enable dashboard scripting
+ include(CTest)
+
+The :module:`CTest` module will automatically call ``enable_testing()``, so we
+can remove it from our CMake files.
+
+We will also need to create a ``CTestConfig.cmake`` file in the top-level
+directory where we can specify the name of the project and where to submit the
+dashboard.
+
+.. literalinclude:: Step9/CTestConfig.cmake
+ :language: cmake
+
+The :manual:`ctest <ctest(1)>` executable will read in this file when it runs.
+To create a simple dashboard you can run the :manual:`cmake <cmake(1)>`
+executable or the :manual:`cmake-gui <cmake-gui(1)>` to configure the project,
+but do not build it yet. Instead, change directory to the binary tree, and then
+run:
+
+ ctest [-VV] -D Experimental
+
+Remember, for multi-config generators (e.g. Visual Studio), the configuration
+type must be specified::
+
+ ctest [-VV] -C Debug -D Experimental
+
+Or, from an IDE, build the ``Experimental`` target.
+
+The :manual:`ctest <ctest(1)>` executable will build and test the project and
+submit the results to Kitware's public dashboard:
+https://my.cdash.org/index.php?project=CMakeTutorial.
+
+Mixing Static and Shared (Step 9)
+=================================
+
+In this section we will show how the :variable:`BUILD_SHARED_LIBS` variable can
+be used to control the default behavior of :command:`add_library`,
+and allow control over how libraries without an explicit type (``STATIC``,
+``SHARED``, ``MODULE`` or ``OBJECT``) are built.
+
+To accomplish this we need to add :variable:`BUILD_SHARED_LIBS` to the
+top-level ``CMakeLists.txt``. We use the :command:`option` command as it allows
+users to optionally select if the value should be ON or OFF.
+
+Next we are going to refactor MathFunctions to become a real library that
+encapsulates using ``mysqrt`` or ``sqrt``, instead of requiring the calling
+code to do this logic. This will also mean that ``USE_MYMATH`` will not control
+building MathFunctions, but instead will control the behavior of this library.
+
+The first step is to update the starting section of the top-level
+``CMakeLists.txt`` to look like:
+
+.. literalinclude:: Step10/CMakeLists.txt
+ :language: cmake
+ :end-before: # add the binary tree
+
+Now that we have made MathFunctions always be used, we will need to update
+the logic of that library. So, in ``MathFunctions/CMakeLists.txt`` we need to
+create a SqrtLibrary that will conditionally be built and installed when
+``USE_MYMATH`` is enabled. Now, since this is a tutorial, we are going to
+explicitly require that SqrtLibrary is built statically.
+
+The end result is that ``MathFunctions/CMakeLists.txt`` should look like:
+
+.. literalinclude:: Step10/MathFunctions/CMakeLists.txt
+ :language: cmake
+ :lines: 1-36,42-
+
+Next, update ``MathFunctions/mysqrt.cxx`` to use the ``mathfunctions`` and
+``detail`` namespaces:
+
+.. literalinclude:: Step10/MathFunctions/mysqrt.cxx
+ :language: c++
+
+We also need to make some changes in ``tutorial.cxx``, so that it no longer
+uses ``USE_MYMATH``:
+
+#. Always include ``MathFunctions.h``
+#. Always use ``mathfunctions::sqrt``
+#. Don't include cmath
+
+Finally, update ``MathFunctions/MathFunctions.h`` to use dll export defines:
+
+.. literalinclude:: Step10/MathFunctions/MathFunctions.h
+ :language: c++
+
+At this point, if you build everything, you may notice that linking fails
+as we are combining a static library without position independent code with a
+library that has position independent code. The solution to this is to
+explicitly set the :prop_tgt:`POSITION_INDEPENDENT_CODE` target property of
+SqrtLibrary to be True no matter the build type.
+
+.. literalinclude:: Step10/MathFunctions/CMakeLists.txt
+ :language: cmake
+ :lines: 37-42
+
+**Exercise**: We modified ``MathFunctions.h`` to use dll export defines.
+Using CMake documentation can you find a helper module to simplify this?
+
+
+Adding Generator Expressions (Step 10)
+======================================
+
+:manual:`Generator expressions <cmake-generator-expressions(7)>` are evaluated
+during build system generation to produce information specific to each build
+configuration.
+
+:manual:`Generator expressions <cmake-generator-expressions(7)>` are allowed in
+the context of many target properties, such as :prop_tgt:`LINK_LIBRARIES`,
+:prop_tgt:`INCLUDE_DIRECTORIES`, :prop_tgt:`COMPILE_DEFINITIONS` and others.
+They may also be used when using commands to populate those properties, such as
+:command:`target_link_libraries`, :command:`target_include_directories`,
+:command:`target_compile_definitions` and others.
+
+:manual:`Generator expressions <cmake-generator-expressions(7)>` may be used
+to enable conditional linking, conditional definitions used when compiling,
+conditional include directories and more. The conditions may be based on the
+build configuration, target properties, platform information or any other
+queryable information.
+
+There are different types of
+:manual:`generator expressions <cmake-generator-expressions(7)>` including
+Logical, Informational, and Output expressions.
+
+Logical expressions are used to create conditional output. The basic
+expressions are the 0 and 1 expressions. A ``$<0:...>`` results in the empty
+string, and ``<1:...>`` results in the content of "...". They can also be
+nested.
+
+A common usage of
+:manual:`generator expressions <cmake-generator-expressions(7)>` is to
+conditionally add compiler flags, such as those for language levels or
+warnings. A nice pattern is to associate this information to an ``INTERFACE``
+target allowing this information to propagate. Let's start by constructing an
+``INTERFACE`` target and specifying the required C++ standard level of ``11``
+instead of using :variable:`CMAKE_CXX_STANDARD`.
+
+So the following code:
+
+.. literalinclude:: Step10/CMakeLists.txt
+ :language: cmake
+ :start-after: project(Tutorial VERSION 1.0)
+ :end-before: # control where the static and shared libraries are built so that on windows
+
+Would be replaced with:
+
+.. literalinclude:: Step11/CMakeLists.txt
+ :language: cmake
+ :start-after: project(Tutorial VERSION 1.0)
+ :end-before: # add compiler warning flags just when building this project via
+
+
+Next we add the desired compiler warning flags that we want for our project. As
+warning flags vary based on the compiler we use the ``COMPILE_LANG_AND_ID``
+generator expression to control which flags to apply given a language and a set
+of compiler ids as seen below:
+
+.. literalinclude:: Step11/CMakeLists.txt
+ :language: cmake
+ :start-after: # the BUILD_INTERFACE genex
+ :end-before: # control where the static and shared libraries are built so that on windows
+
+Looking at this we see that the warning flags are encapsulated inside a
+``BUILD_INTERFACE`` condition. This is done so that consumers of our installed
+project will not inherit our warning flags.
+
+
+**Exercise**: Modify ``MathFunctions/CMakeLists.txt`` so that all targets have
+a :command:`target_link_libraries` call to ``tutorial_compiler_flags``.
+
+
+Adding Export Configuration (Step 11)
+=====================================
+
+During `Installing and Testing (Step 4)`_ of the tutorial we added the ability
+for CMake to install the library and headers of the project. During
+`Building an Installer (Step 7)`_ we added the ability to package up this
+information so it could be distributed to other people.
+
+The next step is to add the necessary information so that other CMake projects
+can use our project, be it from a build directory, a local install or when
+packaged.
+
+The first step is to update our :command:`install(TARGETS)` commands to not
+only specify a ``DESTINATION`` but also an ``EXPORT``. The ``EXPORT`` keyword
+generates and installs a CMake file containing code to import all targets
+listed in the install command from the installation tree. So let's go ahead and
+explicitly ``EXPORT`` the MathFunctions library by updating the ``install``
+command in ``MathFunctions/CMakeLists.txt`` to look like:
+
+.. literalinclude:: Complete/MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # install rules
+
+Now that we have MathFunctions being exported, we also need to explicitly
+install the generated ``MathFunctionsTargets.cmake`` file. This is done by
+adding the following to the bottom of the top-level ``CMakeLists.txt``:
+
+.. literalinclude:: Complete/CMakeLists.txt
+ :language: cmake
+ :start-after: # install the configuration targets
+ :end-before: include(CMakePackageConfigHelpers)
+
+At this point you should try and run CMake. If everything is setup properly
+you will see that CMake will generate an error that looks like:
+
+.. code-block:: console
+
+ Target "MathFunctions" INTERFACE_INCLUDE_DIRECTORIES property contains
+ path:
+
+ "/Users/robert/Documents/CMakeClass/Tutorial/Step11/MathFunctions"
+
+ which is prefixed in the source directory.
+
+What CMake is trying to say is that during generating the export information
+it will export a path that is intrinsically tied to the current machine and
+will not be valid on other machines. The solution to this is to update the
+MathFunctions :command:`target_include_directories` to understand that it needs
+different ``INTERFACE`` locations when being used from within the build
+directory and from an install / package. This means converting the
+:command:`target_include_directories` call for MathFunctions to look like:
+
+.. literalinclude:: Step12/MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # to find MathFunctions.h, while we don't.
+ :end-before: # should we use our own math functions
+
+Once this has been updated, we can re-run CMake and verify that it doesn't
+warn anymore.
+
+At this point, we have CMake properly packaging the target information that is
+required but we will still need to generate a ``MathFunctionsConfig.cmake`` so
+that the CMake :command:`find_package` command can find our project. So let's go
+ahead and add a new file to the top-level of the project called
+``Config.cmake.in`` with the following contents:
+
+.. literalinclude:: Step12/Config.cmake.in
+
+Then, to properly configure and install that file, add the following to the
+bottom of the top-level ``CMakeLists.txt``:
+
+.. literalinclude:: Step12/CMakeLists.txt
+ :language: cmake
+ :start-after: # install the configuration targets
+ :end-before: # generate the export
+
+At this point, we have generated a relocatable CMake Configuration for our
+project that can be used after the project has been installed or packaged. If
+we want our project to also be used from a build directory we only have to add
+the following to the bottom of the top level ``CMakeLists.txt``:
+
+.. literalinclude:: Step12/CMakeLists.txt
+ :language: cmake
+ :start-after: # needs to be after the install(TARGETS ) command
+
+With this export call we now generate a ``Targets.cmake``, allowing the
+configured ``MathFunctionsConfig.cmake`` in the build directory to be used by
+other projects, without needing it to be installed.
+
+Packaging Debug and Release (Step 12)
+=====================================
+
+**Note:** This example is valid for single-configuration generators and will
+not work for multi-configuration generators (e.g. Visual Studio).
+
+By default, CMake's model is that a build directory only contains a single
+configuration, be it Debug, Release, MinSizeRel, or RelWithDebInfo. It is
+possible, however, to setup CPack to bundle multiple build directories and
+construct a package that contains multiple configurations of the same project.
+
+First, we want to ensure that the debug and release builds use different names
+for the executables and libraries that will be installed. Let's use `d` as the
+postfix for the debug executable and libraries.
+
+Set :variable:`CMAKE_DEBUG_POSTFIX` near the beginning of the top-level
+``CMakeLists.txt`` file:
+
+.. literalinclude:: Complete/CMakeLists.txt
+ :language: cmake
+ :start-after: project(Tutorial VERSION 1.0)
+ :end-before: target_compile_features(tutorial_compiler_flags
+
+And the :prop_tgt:`DEBUG_POSTFIX` property on the tutorial executable:
+
+.. literalinclude:: Complete/CMakeLists.txt
+ :language: cmake
+ :start-after: # add the executable
+ :end-before: # add the binary tree to the search path for include files
+
+Let's also add version numbering to the MathFunctions library. In
+``MathFunctions/CMakeLists.txt``, set the :prop_tgt:`VERSION` and
+:prop_tgt:`SOVERSION` properties:
+
+.. literalinclude:: Complete/MathFunctions/CMakeLists.txt
+ :language: cmake
+ :start-after: # setup the version numbering
+ :end-before: # install rules
+
+From the ``Step12`` directory, create ``debug`` and ``release``
+subbdirectories. The layout will look like:
+
+.. code-block:: none
+
+ - Step12
+ - debug
+ - release
+
+Now we need to setup debug and release builds. We can use
+:variable:`CMAKE_BUILD_TYPE` to set the configuration type:
+
+.. code-block:: console
+
+ cd debug
+ cmake -DCMAKE_BUILD_TYPE=Debug ..
+ cmake --build .
+ cd ../release
+ cmake -DCMAKE_BUILD_TYPE=Release ..
+ cmake --build .
+
+Now that both the debug and release builds are complete, we can use a custom
+configuration file to package both builds into a single release. In the
+``Step12`` directory, create a file called ``MultiCPackConfig.cmake``. In this
+file, first include the default configuration file that was created by the
+:manual:`cmake <cmake(1)>` executable.
+
+Next, use the ``CPACK_INSTALL_CMAKE_PROJECTS`` variable to specify which
+projects to install. In this case, we want to install both debug and release.
+
+.. literalinclude:: Complete/MultiCPackConfig.cmake
+ :language: cmake
+
+From the ``Step12`` directory, run :manual:`cpack <cpack(1)>` specifying our
+custom configuration file with the ``config`` option:
+
+.. code-block:: console
+
+ cpack --config MultiCPackConfig.cmake
diff --git a/Help/guide/user-interaction/GUI-Add-Entry.png b/Help/guide/user-interaction/GUI-Add-Entry.png
new file mode 100644
index 0000000..1e9be7e
--- /dev/null
+++ b/Help/guide/user-interaction/GUI-Add-Entry.png
Binary files differ
diff --git a/Help/guide/user-interaction/GUI-Choose-Generator.png b/Help/guide/user-interaction/GUI-Choose-Generator.png
new file mode 100644
index 0000000..19ad2c0
--- /dev/null
+++ b/Help/guide/user-interaction/GUI-Choose-Generator.png
Binary files differ
diff --git a/Help/guide/user-interaction/GUI-Configure-Dialog.png b/Help/guide/user-interaction/GUI-Configure-Dialog.png
new file mode 100644
index 0000000..9839cac
--- /dev/null
+++ b/Help/guide/user-interaction/GUI-Configure-Dialog.png
Binary files differ
diff --git a/Help/guide/user-interaction/GUI-Source-Binary.png b/Help/guide/user-interaction/GUI-Source-Binary.png
new file mode 100644
index 0000000..e338354
--- /dev/null
+++ b/Help/guide/user-interaction/GUI-Source-Binary.png
Binary files differ
diff --git a/Help/guide/user-interaction/VS-Choose-Arch.png b/Help/guide/user-interaction/VS-Choose-Arch.png
new file mode 100644
index 0000000..816b0f4
--- /dev/null
+++ 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
new file mode 100644
index 0000000..ba8196b
--- /dev/null
+++ b/Help/guide/user-interaction/index.rst
@@ -0,0 +1,767 @@
+User Interaction Guide
+**********************
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+Where a software package supplies a CMake-based buildsystem
+with the source of their software, the consumer of the
+software is required to run a CMake user interaction tool
+in order to build it.
+
+Well-behaved CMake-based buildsystems do not create any
+output in the source directory, so typically, the user
+performs an out-of-source build and performs the build
+there. First, CMake must be instructed to generate a
+suitable buildsystem, then the user invokes a build tool
+to process that generated buildsystem. The generated
+buildsystem is specific to the machine used to generate
+it and is not redistributable. Each consumer of a provided
+source software package is required to use CMake to
+generate a buildsystem specific to their system.
+
+Generated buildsystems should generally be treated as
+read-only. The CMake files as a primary artifact should
+completely specify the buildsystem and there should be no
+reason to populate properties manually in an IDE for
+example after generating the buildsystem. CMake will
+periodically rewrite the generated buildsystem, so
+modifications by users will be overwritten.
+
+The features and user interfaces described in this manual
+are available for all CMake-based build systems by virtue
+of providing CMake files.
+
+The CMake tooling may report errors to the user when
+processing provided CMake files, such as reporting that
+the compiler is not supported, or the compiler does not
+support a required compile option, or a dependency can
+not be found. These errors must be resolved by the user
+by choosing a different compiler,
+:guide:`installing dependencies <Using Dependencies Guide>`,
+or instructing CMake where to find them, etc.
+
+Command Line cmake tool
+-----------------------
+
+A simple but typical use of :manual:`cmake(1)` with a fresh
+copy of software source code is to create a build directory
+and invoke cmake there:
+
+.. code-block:: console
+
+ $ cd some_software-1.4.2
+ $ mkdir build
+ $ cd build
+ $ cmake .. -DCMAKE_INSTALL_PREFIX=/opt/the/prefix
+ $ cmake --build .
+ $ cmake --build . --target install
+
+It is recommended to build in a separate directory to the
+source because that keeps the source directory pristine,
+allows for building a single source with multiple
+toolchains, and allows easy clearing of build artifacts by
+simply deleting the build directory.
+
+The CMake tooling may report warnings which are intended
+for the provider of the software, not intended for the
+consumer of the software. Such warnings end with "This
+warning is for project developers". Users may disable
+such warnings by passing the ``-Wno-dev`` flag to
+:manual:`cmake(1)`.
+
+cmake-gui tool
+--------------
+
+Users more accustomed to GUI interfaces may use the
+:manual:`cmake-gui(1)` tool to invoke CMake and generate
+a buildsystem.
+
+The source and binary directories must first be
+populated. It is always advised to use different
+directories for the source and the build.
+
+.. image:: GUI-Source-Binary.png
+ :alt: Choosing source and binary directories
+
+Generating a Buildsystem
+========================
+
+There are several user interface tools which may be used
+to generate a buildsystem from CMake files. The
+:manual:`ccmake(1)` and :manual:`cmake-gui(1)` tools guide
+the user through setting the various necessary options.
+The :manual:`cmake(1)` tool can be invoked to specify
+options on the command line. This manual describes options
+which may be set using any of the user interface tools,
+though the mode of setting an option is different for each
+tool.
+
+Command line environment
+------------------------
+
+When invoking :manual:`cmake(1)` with a command line
+buildsystem such as ``Makefiles`` or ``Ninja``, it is
+necessary to use the correct build environment to
+ensure that build tools are available. CMake must be
+able to find the appropriate
+:variable:`build tool <CMAKE_MAKE_PROGRAM>`,
+compiler, linker and other tools as needed.
+
+On Linux systems, the appropriate tools are often
+provided in system-wide locations and may be readily
+installed through the system package manager. Other
+toolchains provided by the user or installed in
+non-default locations can also be used.
+
+When cross-compiling, some platforms may require
+environment variables to be set or may provide
+scripts to set the environment.
+
+Visual Studio ships multiple command prompts and
+``vcvarsall.bat`` scripts for setting up the
+correct environments for command line buildsystems. While
+not strictly necessary to use a corresponding
+command line environment when using a Visual Studio
+generator, doing so has no disadvantages.
+
+When using Xcode, there can be more than one Xcode
+version installed. Which one to use can be selected
+in a number of different ways, but the most common
+methods are:
+
+* Setting the default version in the preferences
+ of the Xcode IDE.
+* Setting the default version via the ``xcode-select``
+ command line tool.
+* Overriding the default version by setting the
+ ``DEVELOPER_DIR`` environment variable when running
+ CMake and the build tool.
+
+For convenience, :manual:`cmake-gui(1)` provides an
+environment variable editor.
+
+Command line ``-G`` option
+--------------------------
+
+CMake chooses a generator by default based on the
+platform. Usually, the default generator is sufficient
+to allow the user to proceed to build the software.
+
+The user may override the default generator with
+the ``-G`` option:
+
+.. code-block:: console
+
+ $ cmake .. -G Ninja
+
+The output of ``cmake --help`` includes a list of
+:manual:`generators <cmake-generators(7)>` available
+for the user to choose from. Note that generator
+names are case sensitive.
+
+On Unix-like systems (including Mac OS X), the
+:generator:`Unix Makefiles` generator is used by
+default. A variant of that generator can also be used
+on Windows in various environments, such as the
+:generator:`NMake Makefiles` and
+:generator:`MinGW Makefiles` generator. These generators
+generate a ``Makefile`` variant which can be executed
+with ``make``, ``gmake``, ``nmake`` or similar tools.
+See the individual generator documentation for more
+information on targeted environments and tools.
+
+The :generator:`Ninja` generator is available on all
+major platforms. ``ninja`` is a build tool similar
+in use-cases to ``make``, but with a focus on
+performance and efficiency.
+
+On Windows, :manual:`cmake(1)` can be used to generate
+solutions for the Visual Studio IDE. Visual Studio
+versions may be specified by the product name of the
+IDE, which includes a four-digit year. Aliases are
+provided for other means by which Visual Studio
+versions are sometimes referred to, such as two
+digits which correspond to the product version of the
+VisualC++ compiler, or a combination of the two:
+
+.. code-block:: console
+
+ $ cmake .. -G "Visual Studio 2019"
+ $ cmake .. -G "Visual Studio 16"
+ $ cmake .. -G "Visual Studio 16 2019"
+
+Visual Studio generators can target different architectures.
+One can specify the target architecture using the `-A` option:
+
+.. code-block:: console
+
+ cmake .. -G "Visual Studio 2019" -A x64
+ cmake .. -G "Visual Studio 16" -A ARM
+ cmake .. -G "Visual Studio 16 2019" -A ARM64
+
+On Apple, the :generator:`Xcode` generator may be used to
+generate project files for the Xcode IDE.
+
+Some IDEs such as KDevelop4, QtCreator and CLion have
+native support for CMake-based buildsystems. Those IDEs
+provide user interface for selecting an underlying
+generator to use, typically a choice between a ``Makefile``
+or a ``Ninja`` based generator.
+
+Note that it is not possible to change the generator
+with ``-G`` after the first invocation of CMake. To
+change the generator, the build directory must be
+deleted and the build must be started from scratch.
+
+When generating Visual Studio project and solutions
+files several other options are available to use when
+initially running :manual:`cmake(1)`.
+
+The Visual Studio toolset can be specified with the
+``-T`` option:
+
+.. code-block:: console
+
+ $ # Build with the clang-cl toolset
+ $ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T ClangCL
+ $ # Build targeting Windows XP
+ $ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T v120_xp
+
+Whereas the ``-A`` option specifies the _target_
+architecture, the ``-T`` option can be used to specify
+details of the toolchain used. For example, `-Thost=x64`
+can be given to select the 64-bit version of the host
+tools. The following demonstrates how to use 64-bit
+tools and also build for a 64-bit target architecture:
+
+.. code-block:: console
+
+ $ cmake .. -G "Visual Studio 16 2019" -A x64 -Thost=x64
+
+Choosing a generator in cmake-gui
+---------------------------------
+
+The "Configure" button triggers a new dialog to
+select the CMake generator to use.
+
+.. 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:: 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:: VS-Choose-Arch.png
+ :alt: Choosing an architecture for Visual Studio generators
+
+.. _`Setting Build Variables`:
+
+Setting Build Variables
+=======================
+
+Software projects often require variables to be
+set on the command line when invoking CMake. Some of
+the most commonly used CMake variables are listed in
+the table below:
+
+========================================== ============================================================
+ Variable Meaning
+========================================== ============================================================
+ :variable:`CMAKE_PREFIX_PATH` Path to search for
+ :guide:`dependent packages <Using Dependencies Guide>`
+ :variable:`CMAKE_MODULE_PATH` Path to search for additional CMake modules
+ :variable:`CMAKE_BUILD_TYPE` Build configuration, such as
+ ``Debug`` or ``Release``, determining
+ debug/optimization flags. This is only
+ relevant for single-configuration buildsystems such
+ as ``Makefile`` and ``Ninja``. Multi-configuration
+ buildsystems such as those for Visual Studio and Xcode
+ ignore this setting.
+ :variable:`CMAKE_INSTALL_PREFIX` Location to install the
+ software to with the
+ ``install`` build target
+ :variable:`CMAKE_TOOLCHAIN_FILE` File containing cross-compiling
+ data such as
+ :manual:`toolchains and sysroots <cmake-toolchains(7)>`.
+ :variable:`BUILD_SHARED_LIBS` Whether to build shared
+ instead of static libraries
+ for :command:`add_library`
+ commands used without a type
+ :variable:`CMAKE_EXPORT_COMPILE_COMMANDS` Generate a ``compile_commands.json``
+ file for use with clang-based tools
+========================================== ============================================================
+
+Other project-specific variables may be available
+to control builds, such as enabling or disabling
+components of the project.
+
+There is no convention provided by CMake for how
+such variables are named between different
+provided buildsystems, except that variables with
+the prefix ``CMAKE_`` usually refer to options
+provided by CMake itself and should not be used
+in third-party options, which should use
+their own prefix instead. The
+:manual:`cmake-gui(1)` tool can display options
+in groups defined by their prefix, so it makes
+sense for third parties to ensure that they use a
+self-consistent prefix.
+
+Setting variables on the command line
+-------------------------------------
+
+CMake variables can be set on the command line either
+when creating the initial build:
+
+.. code-block:: console
+
+ $ mkdir build
+ $ cd build
+ $ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug
+
+or later on a subsequent invocation of
+:manual:`cmake(1)`:
+
+.. code-block:: console
+
+ $ cd build
+ $ cmake . -DCMAKE_BUILD_TYPE=Debug
+
+The ``-U`` flag may be used to unset variables
+on the :manual:`cmake(1)` command line:
+
+.. code-block:: console
+
+ $ cd build
+ $ cmake . -UMyPackage_DIR
+
+A CMake buildsystem which was initially created
+on the command line can be modified using the
+:manual:`cmake-gui(1)` and vice-versa.
+
+The :manual:`cmake(1)` tool allows specifying a
+file to use to populate the initial cache using
+the ``-C`` option. This can be useful to simplify
+commands and scripts which repeatedly require the
+same cache entries.
+
+Setting variables with cmake-gui
+--------------------------------
+
+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:: GUI-Add-Entry.png
+ :alt: Editing a cache entry
+
+The main view of the :manual:`cmake-gui(1)` user interface
+can be used to edit existing variables.
+
+The CMake Cache
+---------------
+
+When CMake is executed, it needs to find the locations of
+compilers, tools and dependencies. It also needs to be
+able to consistently re-generate a buildsystem to use the
+same compile/link flags and paths to dependencies. Such
+parameters are also required to be configurable by the
+user because they are paths and options specific to the
+users system.
+
+When it is first executed, CMake generates a
+``CMakeCache.txt`` file in the build directory containing
+key-value pairs for such artifacts. The cache file can be
+viewed or edited by the user by running the
+:manual:`cmake-gui(1)` or :manual:`ccmake(1)` tool. The
+tools provide an interactive interface for re-configuring
+the provided software and re-generating the buildsystem,
+as is needed after editing cached values. Each cache
+entry may have an associated short help text which is
+displayed in the user interface tools.
+
+The cache entries may also have a type to signify how it
+should be presented in the user interface. For example,
+a cache entry of type ``BOOL`` can be edited by a
+checkbox in a user interface, a ``STRING`` can be edited
+in a text field, and a ``FILEPATH`` while similar to a
+``STRING`` should also provide a way to locate filesystem
+paths using a file dialog. An entry of type ``STRING``
+may provide a restricted list of allowed values which are
+then provided in a drop-down menu in the
+:manual:`cmake-gui(1)` user interface (see the
+:prop_cache:`STRINGS` cache property).
+
+The CMake files shipped with a software package may also
+define boolean toggle options using the :command:`option`
+command. The command creates a cache entry which has a
+help text and a default value. Such cache entries are
+typically specific to the provided software and affect
+the configuration of the build, such as whether tests
+and examples are built, whether to build with exceptions
+enabled etc.
+
+Presets
+=======
+
+CMake understands a file, ``CMakePresets.json``, and its
+user-specific counterpart, ``CMakeUserPresets.json``, for
+saving presets for commonly-used configure settings. These
+presets can set the build directory, generator, cache
+variables, environment variables, and other command-line
+options. All of these options can be overridden by the
+user. The full details of the ``CMakePresets.json`` format
+are listed in the :manual:`cmake-presets(7)` manual.
+
+Using presets on the command-line
+---------------------------------
+
+When using the :manual:`cmake(1)` command line tool, a
+preset can be invoked by using the ``--preset`` option. If
+``--preset`` is specified, the generator and build
+directory are not required, but can be specified to
+override them. For example, if you have the following
+``CMakePresets.json`` file:
+
+.. code-block:: json
+
+ {
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "ninja-release",
+ "binaryDir": "${sourceDir}/build/${presetName}",
+ "generator": "Ninja",
+ "cacheVariables": {
+ "CMAKE_BUILD_TYPE": "Release"
+ }
+ }
+ ]
+ }
+
+and you run the following:
+
+.. code-block:: console
+
+ cmake -S /path/to/source --preset=ninja-release
+
+This will generate a build directory in
+``/path/to/source/build/ninja-release`` with the
+:generator:`Ninja` generator, and with
+:variable:`CMAKE_BUILD_TYPE` set to ``Release``.
+
+If you want to see the list of available presets, you can
+run:
+
+.. code-block:: console
+
+ cmake -S /path/to/source --list-presets
+
+This will list the presets available in
+``/path/to/source/CMakePresets.json`` and
+``/path/to/source/CMakeUsersPresets.json`` without
+generating a build tree.
+
+Using presets in cmake-gui
+--------------------------
+
+If a project has presets available, either through
+``CMakePresets.json`` or ``CMakeUserPresets.json``, the
+list of presets will appear in a drop-down menu in
+:manual:`cmake-gui(1)` between the source directory and
+the binary directory. Choosing a preset sets the binary
+directory, generator, environment variables, and cache
+variables, but all of these options can be overridden after
+a preset is selected.
+
+Invoking the Buildsystem
+========================
+
+After generating the buildsystem, the software can be
+built by invoking the particular build tool. In the
+case of the IDE generators, this can involve loading
+the generated project file into the IDE to invoke the
+build.
+
+CMake is aware of the specific build tool needed to invoke
+a build so in general, to build a buildsystem or project
+from the command line after generating, the following
+command may be invoked in the build directory:
+
+.. code-block:: console
+
+ $ cmake --build .
+
+The ``--build`` flag enables a particular mode of
+operation for the :manual:`cmake(1)` tool. It invokes
+the :variable:`CMAKE_MAKE_PROGRAM` command associated
+with the :manual:`generator <cmake-generators(7)>`, or
+the build tool configured by the user.
+
+The ``--build`` mode also accepts the parameter
+``--target`` to specify a particular target to build,
+for example a particular library, executable or
+custom target, or a particular special target like
+``install``:
+
+.. code-block:: console
+
+ $ cmake --build . --target myexe
+
+The ``--build`` mode also accepts a ``--config`` parameter
+in the case of multi-config generators to specify which
+particular configuration to build:
+
+.. code-block:: console
+
+ $ cmake --build . --target myexe --config Release
+
+The ``--config`` option has no effect if the generator
+generates a buildsystem specific to a configuration which
+is chosen when invoking cmake with the
+:variable:`CMAKE_BUILD_TYPE` variable.
+
+Some buildsystems omit details of command lines invoked
+during the build. The ``--verbose`` flag can be used to
+cause those command lines to be shown:
+
+.. code-block:: console
+
+ $ cmake --build . --target myexe --verbose
+
+The ``--build`` mode can also pass particular command
+line options to the underlying build tool by listing
+them after ``--``. This can be useful to specify
+options to the build tool, such as to continue the
+build after a failed job, where CMake does not
+provide a high-level user interface.
+
+For all generators, it is possible to run the underlying
+build tool after invoking CMake. For example, ``make``
+may be executed after generating with the
+:generator:`Unix Makefiles` generator to invoke the build,
+or ``ninja`` after generating with the :generator:`Ninja`
+generator etc. The IDE buildsystems usually provide
+command line tooling for building a project which can
+also be invoked.
+
+Selecting a Target
+------------------
+
+Each executable and library described in the CMake files
+is a build target, and the buildsystem may describe
+custom targets, either for internal use, or for user
+consumption, for example to create documentation.
+
+CMake provides some built-in targets for all buildsystems
+providing CMake files.
+
+``all``
+ The default target used by ``Makefile`` and ``Ninja``
+ generators. Builds all targets in the buildsystem,
+ except those which are excluded by their
+ :prop_tgt:`EXCLUDE_FROM_ALL` target property or
+ :prop_dir:`EXCLUDE_FROM_ALL` directory property. The
+ name ``ALL_BUILD`` is used for this purpose for the
+ Xcode and Visual Studio generators.
+``help``
+ Lists the targets available for build. This target is
+ available when using the :generator:`Unix Makefiles` or
+ :generator:`Ninja` generator, and the exact output is
+ tool-specific.
+``clean``
+ Delete built object files and other output files. The
+ ``Makefile`` based generators create a ``clean`` target
+ per directory, so that an individual directory can be
+ cleaned. The ``Ninja`` tool provides its own granular
+ ``-t clean`` system.
+``test``
+ Runs tests. This target is only automatically available
+ if the CMake files provide CTest-based tests. See also
+ `Running Tests`_.
+``install``
+ Installs the software. This target is only automatically
+ available if the software defines install rules with the
+ :command:`install` command. See also
+ `Software Installation`_.
+``package``
+ Creates a binary package. This target is only
+ automatically available if the CMake files provide
+ CPack-based packages.
+``package_source``
+ Creates a source package. This target is only
+ automatically available if the CMake files provide
+ CPack-based packages.
+
+For ``Makefile`` based systems, ``/fast`` variants of binary
+build targets are provided. The ``/fast`` variants are used
+to build the specified target without regard for its
+dependencies. The dependencies are not checked and
+are not rebuilt if out of date. The :generator:`Ninja`
+generator is sufficiently fast at dependency checking that
+such targets are not provided for that generator.
+
+``Makefile`` based systems also provide build-targets to
+preprocess, assemble and compile individual files in a
+particular directory.
+
+.. code-block:: console
+
+ $ make foo.cpp.i
+ $ make foo.cpp.s
+ $ make foo.cpp.o
+
+The file extension is built into the name of the target
+because another file with the same name but a different
+extension may exist. However, build-targets without the
+file extension are also provided.
+
+.. code-block:: console
+
+ $ make foo.i
+ $ make foo.s
+ $ make foo.o
+
+In buildsystems which contain ``foo.c`` and ``foo.cpp``,
+building the ``foo.i`` target will preprocess both files.
+
+Specifying a Build Program
+--------------------------
+
+The program invoked by the ``--build`` mode is determined
+by the :variable:`CMAKE_MAKE_PROGRAM` variable. For most
+generators, the particular program does not need to be
+configured.
+
+===================== =========================== ===========================
+ Generator Default make program Alternatives
+===================== =========================== ===========================
+ XCode ``xcodebuild``
+ Unix Makefiles ``make``
+ NMake Makefiles ``nmake`` ``jom``
+ NMake Makefiles JOM ``jom`` ``nmake``
+ MinGW Makefiles ``mingw32-make``
+ MSYS Makefiles ``make``
+ Ninja ``ninja``
+ Visual Studio ``msbuild``
+ Watcom WMake ``wmake``
+===================== =========================== ===========================
+
+The ``jom`` tool is capable of reading makefiles of the
+``NMake`` flavor and building in parallel, while the
+``nmake`` tool always builds serially. After generating
+with the :generator:`NMake Makefiles` generator a user
+can run ``jom`` instead of ``nmake``. The ``--build``
+mode would also use ``jom`` if the
+:variable:`CMAKE_MAKE_PROGRAM` was set to ``jom`` while
+using the :generator:`NMake Makefiles` generator, and
+as a convenience, the :generator:`NMake Makefiles JOM`
+generator is provided to find ``jom`` in the normal way
+and use it as the :variable:`CMAKE_MAKE_PROGRAM`. For
+completeness, ``nmake`` is an alternative tool which
+can process the output of the
+:generator:`NMake Makefiles JOM` generator, but doing
+so would be a pessimisation.
+
+Software Installation
+=====================
+
+The :variable:`CMAKE_INSTALL_PREFIX` variable can be
+set in the CMake cache to specify where to install the
+provided software. If the provided software has install
+rules, specified using the :command:`install` command,
+they will install artifacts into that prefix. On Windows,
+the default installation location corresponds to the
+``ProgramFiles`` system directory which may be
+architecture specific. On Unix hosts, ``/usr/local`` is
+the default installation location.
+
+The :variable:`CMAKE_INSTALL_PREFIX` variable always
+refers to the installation prefix on the target
+filesystem.
+
+In cross-compiling or packaging scenarios where the
+sysroot is read-only or where the sysroot should otherwise
+remain pristine, the :variable:`CMAKE_STAGING_PREFIX`
+variable can be set to a location to actually install
+the files.
+
+The commands:
+
+.. code-block:: console
+
+ $ cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local \
+ -DCMAKE_SYSROOT=$HOME/root \
+ -DCMAKE_STAGING_PREFIX=/tmp/package
+ $ cmake --build .
+ $ cmake --build . --target install
+
+result in files being installed to paths such
+as ``/tmp/package/lib/libfoo.so`` on the host machine.
+The ``/usr/local`` location on the host machine is
+not affected.
+
+Some provided software may specify ``uninstall`` rules,
+but CMake does not generate such rules by default itself.
+
+Running Tests
+=============
+
+The :manual:`ctest(1)` tool is shipped with the CMake
+distribution to execute provided tests and report
+results. The ``test`` build-target is provided to run
+all available tests, but the :manual:`ctest(1)` tool
+allows granular control over which tests to run, how to
+run them, and how to report results. Executing
+:manual:`ctest(1)` in the build directory is equivalent
+to running the ``test`` target:
+
+.. code-block:: console
+
+ $ ctest
+
+A regular expression can be passed to run only tests
+which match the expression. To run only tests with
+``Qt`` in their name:
+
+.. code-block:: console
+
+ $ ctest -R Qt
+
+Tests can be excluded by regular expression too. To
+run only tests without ``Qt`` in their name:
+
+.. code-block:: console
+
+ $ ctest -E Qt
+
+Tests can be run in parallel by passing ``-j`` arguments
+to :manual:`ctest(1)`:
+
+.. code-block:: console
+
+ $ ctest -R Qt -j8
+
+The environment variable :envvar:`CTEST_PARALLEL_LEVEL`
+can alternatively be set to avoid the need to pass
+``-j``.
+
+By default :manual:`ctest(1)` does not print the output
+from the tests. The command line argument ``-V`` (or
+``--verbose``) enables verbose mode to print the
+output from all tests.
+The ``--output-on-failure`` option prints the test
+output for failing tests only. The environment variable
+:envvar:`CTEST_OUTPUT_ON_FAILURE`
+can be set to ``1`` as an alternative to passing the
+``--output-on-failure`` option to :manual:`ctest(1)`.
diff --git a/Help/guide/using-dependencies/index.rst b/Help/guide/using-dependencies/index.rst
new file mode 100644
index 0000000..f4d7845
--- /dev/null
+++ b/Help/guide/using-dependencies/index.rst
@@ -0,0 +1,200 @@
+Using Dependencies Guide
+************************
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+For developers wishing to use CMake to consume a third
+party binary package, there are multiple possibilities
+regarding how to optimally do so, depending on how
+CMake-aware the third-party library is.
+
+CMake files provided with a software package contain
+instructions for finding each build dependency. Some
+build dependencies are optional in that the build may
+succeed with a different feature set if the dependency
+is missing, and some dependencies are required. CMake
+searches well-known locations for each dependency, and
+the provided software may supply additional hints or
+locations to CMake to find each dependency.
+
+If a required dependency is not found by
+:manual:`cmake(1)`, the cache is populated with an entry
+which contains a ``NOTFOUND`` value. This value can be
+replaced by specifying it on the command line, or in
+the :manual:`ccmake(1)` or :manual:`cmake-gui(1)` tool.
+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
+:ref:`Config File Packages`. These packages are text files
+shipped with the library which instruct CMake how to use the
+library binaries and associated headers, helper tools and
+CMake macros provided by the library.
+
+The config files can usually be found in a directory whose
+name matches the pattern ``lib/cmake/<PackageName>``, though
+they may be in other locations instead. The
+``<PackageName>`` corresponds to use in CMake code with the
+:command:`find_package` command such as
+``find_package(PackageName REQUIRED)``.
+
+The ``lib/cmake/<PackageName>`` directory will contain a
+file which is either named ``<PackageName>Config.cmake``
+or ``<PackageName>-config.cmake``. This is the entry point
+to the package for CMake. A separate optional file named
+``<PackageName>ConfigVersion.cmake`` may also exist in the
+directory. This file is used by CMake to determine whether
+the version of the third party package satisfies uses of the
+:command:`find_package` command which specify version
+constraints. It is optional to specify a version when using
+:command:`find_package`, even if a ``ConfigVersion`` file is
+present.
+
+If the ``Config.cmake`` file is found and the
+optionally-specified version is satisfied, then the CMake
+:command:`find_package` command considers the package to be
+found and the entire library package is assumed to be
+complete as designed.
+
+There may be additional files providing CMake macros or
+:ref:`imported targets` for you to use. CMake does not
+enforce any naming convention for these
+files. They are related to the primary ``Config`` file by
+use of the CMake :command:`include` command.
+
+:guide:`Invoking CMake <User Interaction Guide>` with the
+intent of using a package of third party binaries requires
+that cmake :command:`find_package` commands succeed in finding
+the package. If the location of the package is in a directory
+known to CMake, the :command:`find_package` call should
+succeed. The directories known to cmake are platform-specific.
+For example, packages installed on Linux with a standard
+system package manager will be found in the ``/usr`` prefix
+automatically. Packages installed in ``Program Files`` on
+Windows will similarly be found automatically.
+
+Packages which are not found automatically are in locations
+not predictable to CMake such as ``/opt/mylib`` or
+``$HOME/dev/prefix``. This is a normal situation and CMake
+provides several ways for users to specify where to find
+such libraries.
+
+The :variable:`CMAKE_PREFIX_PATH` variable may be
+:ref:`set when invoking CMake <Setting Build Variables>`.
+It is treated as a list of paths to search for
+:ref:`Config File Packages`. A package installed in
+``/opt/somepackage`` will typically install config files
+such as
+``/opt/somepackage/lib/cmake/somePackage/SomePackageConfig.cmake``.
+In that case, ``/opt/somepackage`` should be added to
+:variable:`CMAKE_PREFIX_PATH`.
+
+The environment variable ``CMAKE_PREFIX_PATH`` may also be
+populated with prefixes to search for packages. Like the
+``PATH`` environment variable, this is a list and needs to use
+the platform-specific environment variable list item separator
+(``:`` on Unix and ``;`` on Windows).
+
+The :variable:`CMAKE_PREFIX_PATH` variable provides convenience
+in cases where multiple prefixes need to be specified, or when
+multiple different package binaries are available in the same
+prefix. Paths to packages may also be specified by setting
+variables matching ``<PackageName>_DIR``, such as
+``SomePackage_DIR``. Note that this is not a prefix but should
+be a full path to a directory containing a config-style package
+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
+specified in files containing configuration-specific file
+paths relevant to the package, such as debug and release
+versions of libraries.
+
+Often the third-party package documentation will point out the
+names of imported targets available after a successful
+``find_package`` for a library. Those imported target names
+can be used with the :command:`target_link_libraries` command.
+
+A complete example which makes a simple use of a third party
+library might look like:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.10)
+ project(MyExeProject VERSION 1.0.0)
+
+ find_package(SomePackage REQUIRED)
+ add_executable(MyExe main.cpp)
+ target_link_libraries(MyExe PRIVATE SomePrefix::LibName)
+
+See :manual:`cmake-buildsystem(7)` for further information
+about developing a CMake buildsystem.
+
+Libraries not Providing Config-file Packages
+--------------------------------------------
+
+Third-party libraries which do not provide config-file packages
+can still be found with the :command:`find_package` command, if
+a ``FindSomePackage.cmake`` file is available.
+
+These module-file packages are different to config-file packages
+in that:
+
+#. They should not be provided by the third party, except
+ perhaps in the form of documentation
+#. The availability of a ``Find<PackageName>.cmake`` file does
+ not indicate the availability of the binaries themselves.
+#. CMake does not search the :variable:`CMAKE_PREFIX_PATH` for
+ ``Find<PackageName>.cmake`` files. Instead CMake searches
+ for such files in the :variable:`CMAKE_MODULE_PATH`
+ variable. It is common for users to set the
+ :variable:`CMAKE_MODULE_PATH` when running CMake, and it is
+ common for CMake projects to append to
+ :variable:`CMAKE_MODULE_PATH` to allow use of local
+ module-file packages.
+#. CMake ships ``Find<PackageName>.cmake`` files for some
+ :manual:`third party packages <cmake-modules(7)>`
+ for convenience in cases where the third party does
+ not provide config-file packages directly. These files are
+ a maintenance burden for CMake, so new Find modules are
+ generally not added to CMake anymore. Third-parties should
+ provide config file packages instead of relying on a Find
+ module to be provided by CMake.
+
+Module-file packages may also provide :ref:`Imported targets`.
+A complete example which finds such a package might look
+like:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.10)
+ project(MyExeProject VERSION 1.0.0)
+
+ find_package(PNG REQUIRED)
+
+ # Add path to a FindSomePackage.cmake file
+ list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+ find_package(SomePackage REQUIRED)
+
+ add_executable(MyExe main.cpp)
+ target_link_libraries(MyExe PRIVATE
+ PNG::PNG
+ SomePrefix::LibName
+ )
+
+The :variable:`<PackageName>_ROOT` variable is also
+searched as a prefix for :command:`find_package` calls using
+module-file packages such as ``FindSomePackage``.
diff --git a/Help/include/COMPILE_DEFINITIONS_DISCLAIMER.txt b/Help/include/COMPILE_DEFINITIONS_DISCLAIMER.txt
new file mode 100644
index 0000000..6797d0e
--- /dev/null
+++ b/Help/include/COMPILE_DEFINITIONS_DISCLAIMER.txt
@@ -0,0 +1,18 @@
+Disclaimer: Most native build tools have poor support for escaping
+certain values. CMake has work-arounds for many cases but some values
+may just not be possible to pass correctly. If a value does not seem
+to be escaped correctly, do not attempt to work-around the problem by
+adding escape sequences to the value. Your work-around may break in a
+future version of CMake that has improved escape support. Instead
+consider defining the macro in a (configured) header file. Then
+report the limitation. Known limitations include::
+
+ # - broken almost everywhere
+ ; - broken in VS IDE 7.0 and Borland Makefiles
+ , - broken in VS IDE
+ % - broken in some cases in NMake
+ & | - broken in some cases on MinGW
+ ^ < > \" - broken in most Make tools on Windows
+
+CMake does not reject these values outright because they do work in
+some cases. Use with caution.
diff --git a/Help/include/INTERFACE_INCLUDE_DIRECTORIES_WARNING.txt b/Help/include/INTERFACE_INCLUDE_DIRECTORIES_WARNING.txt
new file mode 100644
index 0000000..a54d728
--- /dev/null
+++ b/Help/include/INTERFACE_INCLUDE_DIRECTORIES_WARNING.txt
@@ -0,0 +1,18 @@
+
+Note that it is not advisable to populate the ``INSTALL_INTERFACE`` of the
+|INTERFACE_PROPERTY_LINK| of a target with absolute paths to the include
+directories of dependencies. That would hard-code into installed packages
+the include directory paths for dependencies
+**as found on the machine the package was made on**.
+
+The ``INSTALL_INTERFACE`` of the |INTERFACE_PROPERTY_LINK| is only
+suitable for specifying the required include directories for headers
+provided with the target itself, not those provided by the transitive
+dependencies listed in its :prop_tgt:`INTERFACE_LINK_LIBRARIES` target
+property. Those dependencies should themselves be targets that specify
+their own header locations in |INTERFACE_PROPERTY_LINK|.
+
+See the :ref:`Creating Relocatable Packages` section of the
+:manual:`cmake-packages(7)` manual for discussion of additional care
+that must be taken when specifying usage requirements while creating
+packages for redistribution.
diff --git a/Help/include/INTERFACE_LINK_LIBRARIES_WARNING.txt b/Help/include/INTERFACE_LINK_LIBRARIES_WARNING.txt
new file mode 100644
index 0000000..46e84ac
--- /dev/null
+++ b/Help/include/INTERFACE_LINK_LIBRARIES_WARNING.txt
@@ -0,0 +1,10 @@
+
+Note that it is not advisable to populate the
+|INTERFACE_PROPERTY_LINK| of a target with absolute paths to dependencies.
+That would hard-code into installed packages the library file paths
+for dependencies **as found on the machine the package was made on**.
+
+See the :ref:`Creating Relocatable Packages` section of the
+:manual:`cmake-packages(7)` manual for discussion of additional care
+that must be taken when specifying usage requirements while creating
+packages for redistribution.
diff --git a/Help/index.rst b/Help/index.rst
new file mode 100644
index 0000000..fdbf847
--- /dev/null
+++ b/Help/index.rst
@@ -0,0 +1,107 @@
+.. title:: CMake Reference Documentation
+
+Introduction
+############
+
+CMake is a tool to manage building of source code. Originally, CMake was
+designed as a generator for various dialects of ``Makefile``, today
+CMake generates modern buildsystems such as ``Ninja`` as well as project
+files for IDEs such as Visual Studio and Xcode.
+
+CMake is widely used for the C and C++ languages, but it may be used to
+build source code of other languages too.
+
+People encountering CMake for the first time may have different initial
+goals. To learn how to build a source code package downloaded from the
+internet, start with the :guide:`User Interaction Guide`.
+This will detail the steps needed to run the :manual:`cmake(1)` or
+:manual:`cmake-gui(1)` executable and how to choose a generator, and
+how to complete the build.
+
+The :guide:`Using Dependencies Guide` is aimed at developers
+wishing to get started using a third-party library.
+
+For developers starting a project using CMake, the :guide:`CMake Tutorial`
+is a suitable starting point. The :manual:`cmake-buildsystem(7)`
+manual is aimed at developers expanding their knowledge of maintaining
+a buildsystem and becoming familiar with the build targets that
+can be represented in CMake. The :manual:`cmake-packages(7)` manual
+explains how to create packages which can easily be consumed by
+third-party CMake-based buildsystems.
+
+Command-Line Tools
+##################
+
+.. toctree::
+ :maxdepth: 1
+
+ /manual/cmake.1
+ /manual/ctest.1
+ /manual/cpack.1
+
+Interactive Dialogs
+###################
+
+.. toctree::
+ :maxdepth: 1
+
+ /manual/cmake-gui.1
+ /manual/ccmake.1
+
+Reference Manuals
+#################
+
+.. toctree::
+ :maxdepth: 1
+
+ /manual/cmake-buildsystem.7
+ /manual/cmake-commands.7
+ /manual/cmake-compile-features.7
+ /manual/cmake-developer.7
+ /manual/cmake-env-variables.7
+ /manual/cmake-file-api.7
+ /manual/cmake-generator-expressions.7
+ /manual/cmake-generators.7
+ /manual/cmake-language.7
+ /manual/cmake-modules.7
+ /manual/cmake-packages.7
+ /manual/cmake-policies.7
+ /manual/cmake-presets.7
+ /manual/cmake-properties.7
+ /manual/cmake-qt.7
+ /manual/cmake-server.7
+ /manual/cmake-toolchains.7
+ /manual/cmake-variables.7
+ /manual/cpack-generators.7
+
+.. only:: not man
+
+ Guides
+ ######
+
+ .. toctree::
+ :maxdepth: 1
+
+ /guide/tutorial/index
+ /guide/user-interaction/index
+ /guide/using-dependencies/index
+ /guide/importing-exporting/index
+ /guide/ide-integration/index
+
+.. only:: html or text
+
+ Release Notes
+ #############
+
+ .. toctree::
+ :maxdepth: 1
+
+ /release/index
+
+.. only:: html
+
+ Index and Search
+ ################
+
+ * :ref:`genindex`
+ * :ref:`search`
diff --git a/Help/manual/ID_RESERVE.txt b/Help/manual/ID_RESERVE.txt
new file mode 100644
index 0000000..be2b163
--- /dev/null
+++ b/Help/manual/ID_RESERVE.txt
@@ -0,0 +1,7 @@
+.. note::
+
+ CMake reserves identifiers that:
+
+ * begin with ``CMAKE_`` (upper-, lower-, or mixed-case), or
+ * begin with ``_CMAKE_`` (upper-, lower-, or mixed-case), or
+ * begin with ``_`` followed by the name of any :manual:`CMake Command <cmake-commands(7)>`.
diff --git a/Help/manual/LINKS.txt b/Help/manual/LINKS.txt
new file mode 100644
index 0000000..810fa0b
--- /dev/null
+++ b/Help/manual/LINKS.txt
@@ -0,0 +1,17 @@
+The following resources are available to get help using CMake:
+
+Home Page
+ https://cmake.org
+
+ The primary starting point for learning about CMake.
+
+Online Documentation and Community Resources
+ https://cmake.org/documentation
+
+ Links to available documentation and community resources may be
+ found on this web page.
+
+Discourse Forum
+ https://discourse.cmake.org
+
+ The Discourse Forum hosts discussion and questions about CMake.
diff --git a/Help/manual/OPTIONS_BUILD.txt b/Help/manual/OPTIONS_BUILD.txt
new file mode 100644
index 0000000..c4f9be8
--- /dev/null
+++ b/Help/manual/OPTIONS_BUILD.txt
@@ -0,0 +1,130 @@
+``-S <path-to-source>``
+ Path to root directory of the CMake project to build.
+
+``-B <path-to-build>``
+ Path to directory which CMake will use as the root of build directory.
+
+ If the directory doesn't already exist CMake will make it.
+
+``-C <initial-cache>``
+ Pre-load a script to populate the cache.
+
+ When CMake is first run in an empty build tree, it creates a
+ ``CMakeCache.txt`` file and populates it with customizable settings for
+ the project. This option may be used to specify a file from which
+ to load cache entries before the first pass through the project's
+ CMake listfiles. The loaded entries take priority over the
+ project's default values. The given file should be a CMake script
+ containing :command:`set` commands that use the ``CACHE`` option, not a
+ cache-format file.
+
+ References to :variable:`CMAKE_SOURCE_DIR` and :variable:`CMAKE_BINARY_DIR`
+ within the script evaluate to the top-level source and build tree.
+
+``-D <var>:<type>=<value>, -D <var>=<value>``
+ Create or update a CMake ``CACHE`` entry.
+
+ When CMake is first run in an empty build tree, it creates a
+ ``CMakeCache.txt`` file and populates it with customizable settings for
+ the project. This option may be used to specify a setting that
+ takes priority over the project's default value. The option may be
+ repeated for as many ``CACHE`` entries as desired.
+
+ If the ``:<type>`` portion is given it must be one of the types
+ specified by the :command:`set` command documentation for its
+ ``CACHE`` signature.
+ If the ``:<type>`` portion is omitted the entry will be created
+ with no type if it does not exist with a type already. If a
+ command in the project sets the type to ``PATH`` or ``FILEPATH``
+ then the ``<value>`` will be converted to an absolute path.
+
+ This option may also be given as a single argument:
+ ``-D<var>:<type>=<value>`` or ``-D<var>=<value>``.
+
+``-U <globbing_expr>``
+ Remove matching entries from CMake ``CACHE``.
+
+ This option may be used to remove one or more variables from the
+ ``CMakeCache.txt`` file, globbing expressions using ``*`` and ``?`` are
+ supported. The option may be repeated for as many ``CACHE`` entries as
+ desired.
+
+ Use with care, you can make your ``CMakeCache.txt`` non-working.
+
+``-G <generator-name>``
+ Specify a build system generator.
+
+ CMake may support multiple native build systems on certain
+ platforms. A generator is responsible for generating a particular
+ build system. Possible generator names are specified in the
+ :manual:`cmake-generators(7)` manual.
+
+ If not specified, CMake checks the :envvar:`CMAKE_GENERATOR` environment
+ variable and otherwise falls back to a builtin default selection.
+
+``-T <toolset-spec>``
+ Toolset specification for the generator, if supported.
+
+ Some CMake generators support a toolset specification to tell
+ the native build system how to choose a compiler. See the
+ :variable:`CMAKE_GENERATOR_TOOLSET` variable for details.
+
+``-A <platform-name>``
+ Specify platform name if supported by generator.
+
+ Some CMake generators support a platform name to be given to the
+ native build system to choose a compiler or SDK. See the
+ :variable:`CMAKE_GENERATOR_PLATFORM` variable for details.
+
+``--install-prefix <directory>``
+ Specify the installation directory, used by the
+ :variable:`CMAKE_INSTALL_PREFIX` variable. Must be an absolute path.
+
+``-Wno-dev``
+ Suppress developer warnings.
+
+ Suppress warnings that are meant for the author of the
+ ``CMakeLists.txt`` files. By default this will also turn off
+ deprecation warnings.
+
+``-Wdev``
+ Enable developer warnings.
+
+ Enable warnings that are meant for the author of the ``CMakeLists.txt``
+ files. By default this will also turn on deprecation warnings.
+
+``-Werror=dev``
+ Make developer warnings errors.
+
+ Make warnings that are meant for the author of the ``CMakeLists.txt`` files
+ errors. By default this will also turn on deprecated warnings as errors.
+
+``-Wno-error=dev``
+ Make developer warnings not errors.
+
+ Make warnings that are meant for the author of the ``CMakeLists.txt`` files not
+ errors. By default this will also turn off deprecated warnings as errors.
+
+``-Wdeprecated``
+ Enable deprecated functionality warnings.
+
+ Enable warnings for usage of deprecated functionality, that are meant
+ for the author of the ``CMakeLists.txt`` files.
+
+``-Wno-deprecated``
+ Suppress deprecated functionality warnings.
+
+ Suppress warnings for usage of deprecated functionality, that are meant
+ for the author of the ``CMakeLists.txt`` files.
+
+``-Werror=deprecated``
+ Make deprecated macro and function warnings errors.
+
+ Make warnings for usage of deprecated macros and functions, that are meant
+ for the author of the ``CMakeLists.txt`` files, errors.
+
+``-Wno-error=deprecated``
+ Make deprecated macro and function warnings not errors.
+
+ Make warnings for usage of deprecated macros and functions, that are meant
+ for the author of the ``CMakeLists.txt`` files, not errors.
diff --git a/Help/manual/OPTIONS_HELP.txt b/Help/manual/OPTIONS_HELP.txt
new file mode 100644
index 0000000..feeca7d
--- /dev/null
+++ b/Help/manual/OPTIONS_HELP.txt
@@ -0,0 +1,136 @@
+.. |file| replace:: The help is printed to a named <f>ile if given.
+
+``--help,-help,-usage,-h,-H,/?``
+ Print usage information and exit.
+
+ Usage describes the basic command line interface and its options.
+
+``--version,-version,/V [<f>]``
+ Show program name/version banner and exit.
+
+ If a file is specified, the version is written into it.
+ |file|
+
+``--help-full [<f>]``
+ Print all help manuals and exit.
+
+ All manuals are printed in a human-readable text format.
+ |file|
+
+``--help-manual <man> [<f>]``
+ Print one help manual and exit.
+
+ The specified manual is printed in a human-readable text format.
+ |file|
+
+``--help-manual-list [<f>]``
+ List help manuals available and exit.
+
+ The list contains all manuals for which help may be obtained by
+ using the ``--help-manual`` option followed by a manual name.
+ |file|
+
+``--help-command <cmd> [<f>]``
+ Print help for one command and exit.
+
+ The :manual:`cmake-commands(7)` manual entry for ``<cmd>`` is
+ printed in a human-readable text format.
+ |file|
+
+``--help-command-list [<f>]``
+ List commands with help available and exit.
+
+ The list contains all commands for which help may be obtained by
+ using the ``--help-command`` option followed by a command name.
+ |file|
+
+``--help-commands [<f>]``
+ Print cmake-commands manual and exit.
+
+ The :manual:`cmake-commands(7)` manual is printed in a
+ human-readable text format.
+ |file|
+
+``--help-module <mod> [<f>]``
+ Print help for one module and exit.
+
+ The :manual:`cmake-modules(7)` manual entry for ``<mod>`` is printed
+ in a human-readable text format.
+ |file|
+
+``--help-module-list [<f>]``
+ List modules with help available and exit.
+
+ The list contains all modules for which help may be obtained by
+ using the ``--help-module`` option followed by a module name.
+ |file|
+
+``--help-modules [<f>]``
+ Print cmake-modules manual and exit.
+
+ The :manual:`cmake-modules(7)` manual is printed in a human-readable
+ text format.
+ |file|
+
+``--help-policy <cmp> [<f>]``
+ Print help for one policy and exit.
+
+ The :manual:`cmake-policies(7)` manual entry for ``<cmp>`` is
+ printed in a human-readable text format.
+ |file|
+
+``--help-policy-list [<f>]``
+ List policies with help available and exit.
+
+ The list contains all policies for which help may be obtained by
+ using the ``--help-policy`` option followed by a policy name.
+ |file|
+
+``--help-policies [<f>]``
+ Print cmake-policies manual and exit.
+
+ The :manual:`cmake-policies(7)` manual is printed in a
+ human-readable text format.
+ |file|
+
+``--help-property <prop> [<f>]``
+ Print help for one property and exit.
+
+ The :manual:`cmake-properties(7)` manual entries for ``<prop>`` are
+ printed in a human-readable text format.
+ |file|
+
+``--help-property-list [<f>]``
+ List properties with help available and exit.
+
+ The list contains all properties for which help may be obtained by
+ using the ``--help-property`` option followed by a property name.
+ |file|
+
+``--help-properties [<f>]``
+ Print cmake-properties manual and exit.
+
+ The :manual:`cmake-properties(7)` manual is printed in a
+ human-readable text format.
+ |file|
+
+``--help-variable <var> [<f>]``
+ Print help for one variable and exit.
+
+ The :manual:`cmake-variables(7)` manual entry for ``<var>`` is
+ printed in a human-readable text format.
+ |file|
+
+``--help-variable-list [<f>]``
+ List variables with help available and exit.
+
+ The list contains all variables for which help may be obtained by
+ using the ``--help-variable`` option followed by a variable name.
+ |file|
+
+``--help-variables [<f>]``
+ Print cmake-variables manual and exit.
+
+ The :manual:`cmake-variables(7)` manual is printed in a
+ human-readable text format.
+ |file|
diff --git a/Help/manual/ccmake.1.rst b/Help/manual/ccmake.1.rst
new file mode 100644
index 0000000..60d45a3
--- /dev/null
+++ b/Help/manual/ccmake.1.rst
@@ -0,0 +1,37 @@
+.. cmake-manual-description: CMake Curses Dialog Command-Line Reference
+
+ccmake(1)
+*********
+
+Synopsis
+========
+
+.. parsed-literal::
+
+ ccmake [<options>] {<path-to-source> | <path-to-existing-build>}
+
+Description
+===========
+
+The **ccmake** executable is the CMake curses interface. Project
+configuration settings may be specified interactively through this
+GUI. Brief instructions are provided at the bottom of the terminal
+when the program is running.
+
+CMake is a cross-platform build system generator. Projects specify
+their build process with platform-independent CMake listfiles included
+in each directory of a source tree with the name ``CMakeLists.txt``.
+Users build a project by using CMake to generate a build system for a
+native tool on their platform.
+
+Options
+=======
+
+.. include:: OPTIONS_BUILD.txt
+
+.. include:: OPTIONS_HELP.txt
+
+See Also
+========
+
+.. include:: LINKS.txt
diff --git a/Help/manual/cmake-buildsystem.7.rst b/Help/manual/cmake-buildsystem.7.rst
new file mode 100644
index 0000000..7008383
--- /dev/null
+++ b/Help/manual/cmake-buildsystem.7.rst
@@ -0,0 +1,1021 @@
+.. cmake-manual-description: CMake Buildsystem Reference
+
+cmake-buildsystem(7)
+********************
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+A CMake-based buildsystem is organized as a set of high-level logical
+targets. Each target corresponds to an executable or library, or
+is a custom target containing custom commands. Dependencies between the
+targets are expressed in the buildsystem to determine the build order
+and the rules for regeneration in response to change.
+
+Binary Targets
+==============
+
+Executables and libraries are defined using the :command:`add_executable`
+and :command:`add_library` commands. The resulting binary files have
+appropriate :prop_tgt:`PREFIX`, :prop_tgt:`SUFFIX` and extensions for the platform targeted.
+Dependencies between binary targets are expressed using the
+:command:`target_link_libraries` command:
+
+.. code-block:: cmake
+
+ add_library(archive archive.cpp zip.cpp lzma.cpp)
+ add_executable(zipapp zipapp.cpp)
+ target_link_libraries(zipapp archive)
+
+``archive`` is defined as a ``STATIC`` library -- an archive containing objects
+compiled from ``archive.cpp``, ``zip.cpp``, and ``lzma.cpp``. ``zipapp``
+is defined as an executable formed by compiling and linking ``zipapp.cpp``.
+When linking the ``zipapp`` executable, the ``archive`` static library is
+linked in.
+
+Binary Executables
+------------------
+
+The :command:`add_executable` command defines an executable target:
+
+.. code-block:: cmake
+
+ add_executable(mytool mytool.cpp)
+
+Commands such as :command:`add_custom_command`, which generates rules to be
+run at build time can transparently use an :prop_tgt:`EXECUTABLE <TYPE>`
+target as a ``COMMAND`` executable. The buildsystem rules will ensure that
+the executable is built before attempting to run the command.
+
+Binary Library Types
+--------------------
+
+.. _`Normal Libraries`:
+
+Normal Libraries
+^^^^^^^^^^^^^^^^
+
+By default, the :command:`add_library` command defines a ``STATIC`` library,
+unless a type is specified. A type may be specified when using the command:
+
+.. code-block:: cmake
+
+ add_library(archive SHARED archive.cpp zip.cpp lzma.cpp)
+
+.. code-block:: cmake
+
+ add_library(archive STATIC archive.cpp zip.cpp lzma.cpp)
+
+The :variable:`BUILD_SHARED_LIBS` variable may be enabled to change the
+behavior of :command:`add_library` to build shared libraries by default.
+
+In the context of the buildsystem definition as a whole, it is largely
+irrelevant whether particular libraries are ``SHARED`` or ``STATIC`` --
+the commands, dependency specifications and other APIs work similarly
+regardless of the library type. The ``MODULE`` library type is
+dissimilar in that it is generally not linked to -- it is not used in
+the right-hand-side of the :command:`target_link_libraries` command.
+It is a type which is loaded as a plugin using runtime techniques.
+If the library does not export any unmanaged symbols (e.g. Windows
+resource DLL, C++/CLI DLL), it is required that the library not be a
+``SHARED`` library because CMake expects ``SHARED`` libraries to export
+at least one symbol.
+
+.. code-block:: cmake
+
+ add_library(archive MODULE 7z.cpp)
+
+.. _`Apple Frameworks`:
+
+Apple Frameworks
+""""""""""""""""
+
+A ``SHARED`` library may be marked with the :prop_tgt:`FRAMEWORK`
+target property to create an macOS or iOS Framework Bundle.
+A library with the ``FRAMEWORK`` target property should also set the
+:prop_tgt:`FRAMEWORK_VERSION` target property. This property is typically
+set to the value of "A" by macOS conventions.
+The ``MACOSX_FRAMEWORK_IDENTIFIER`` sets ``CFBundleIdentifier`` key
+and it uniquely identifies the bundle.
+
+.. code-block:: cmake
+
+ add_library(MyFramework SHARED MyFramework.cpp)
+ set_target_properties(MyFramework PROPERTIES
+ FRAMEWORK TRUE
+ FRAMEWORK_VERSION A # Version "A" is macOS convention
+ MACOSX_FRAMEWORK_IDENTIFIER org.cmake.MyFramework
+ )
+
+.. _`Object Libraries`:
+
+Object Libraries
+^^^^^^^^^^^^^^^^
+
+The ``OBJECT`` library type defines a non-archival collection of object files
+resulting from compiling the given source files. The object files collection
+may be used as source inputs to other targets by using the syntax
+``$<TARGET_OBJECTS:name>``. This is a
+:manual:`generator expression <cmake-generator-expressions(7)>` that can be
+used to supply the ``OBJECT`` library content to other targets:
+
+.. code-block:: cmake
+
+ add_library(archive OBJECT archive.cpp zip.cpp lzma.cpp)
+
+ add_library(archiveExtras STATIC $<TARGET_OBJECTS:archive> extras.cpp)
+
+ add_executable(test_exe $<TARGET_OBJECTS:archive> test.cpp)
+
+The link (or archiving) step of those other targets will use the object
+files collection in addition to those from their own sources.
+
+Alternatively, object libraries may be linked into other targets:
+
+.. code-block:: cmake
+
+ add_library(archive OBJECT archive.cpp zip.cpp lzma.cpp)
+
+ add_library(archiveExtras STATIC extras.cpp)
+ target_link_libraries(archiveExtras PUBLIC archive)
+
+ add_executable(test_exe test.cpp)
+ target_link_libraries(test_exe archive)
+
+The link (or archiving) step of those other targets will use the object
+files from ``OBJECT`` libraries that are *directly* linked. Additionally,
+usage requirements of the ``OBJECT`` libraries will be honored when compiling
+sources in those other targets. Furthermore, those usage requirements
+will propagate transitively to dependents of those other targets.
+
+Object libraries may not be used as the ``TARGET`` in a use of the
+:command:`add_custom_command(TARGET)` command signature. However,
+the list of objects can be used by :command:`add_custom_command(OUTPUT)`
+or :command:`file(GENERATE)` by using ``$<TARGET_OBJECTS:objlib>``.
+
+Build Specification and Usage Requirements
+==========================================
+
+The :command:`target_include_directories`, :command:`target_compile_definitions`
+and :command:`target_compile_options` commands specify the build specifications
+and the usage requirements of binary targets. The commands populate the
+:prop_tgt:`INCLUDE_DIRECTORIES`, :prop_tgt:`COMPILE_DEFINITIONS` and
+:prop_tgt:`COMPILE_OPTIONS` target properties respectively, and/or the
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`, :prop_tgt:`INTERFACE_COMPILE_DEFINITIONS`
+and :prop_tgt:`INTERFACE_COMPILE_OPTIONS` target properties.
+
+Each of the commands has a ``PRIVATE``, ``PUBLIC`` and ``INTERFACE`` mode. The
+``PRIVATE`` mode populates only the non-``INTERFACE_`` variant of the target
+property and the ``INTERFACE`` mode populates only the ``INTERFACE_`` variants.
+The ``PUBLIC`` mode populates both variants of the respective target property.
+Each command may be invoked with multiple uses of each keyword:
+
+.. code-block:: cmake
+
+ target_compile_definitions(archive
+ PRIVATE BUILDING_WITH_LZMA
+ INTERFACE USING_ARCHIVE_LIB
+ )
+
+Note that usage requirements are not designed as a way to make downstreams
+use particular :prop_tgt:`COMPILE_OPTIONS` or
+:prop_tgt:`COMPILE_DEFINITIONS` etc for convenience only. The contents of
+the properties must be **requirements**, not merely recommendations or
+convenience.
+
+See the :ref:`Creating Relocatable Packages` section of the
+:manual:`cmake-packages(7)` manual for discussion of additional care
+that must be taken when specifying usage requirements while creating
+packages for redistribution.
+
+Target Properties
+-----------------
+
+The contents of the :prop_tgt:`INCLUDE_DIRECTORIES`,
+:prop_tgt:`COMPILE_DEFINITIONS` and :prop_tgt:`COMPILE_OPTIONS` target
+properties are used appropriately when compiling the source files of a
+binary target.
+
+Entries in the :prop_tgt:`INCLUDE_DIRECTORIES` are added to the compile line
+with ``-I`` or ``-isystem`` prefixes and in the order of appearance in the
+property value.
+
+Entries in the :prop_tgt:`COMPILE_DEFINITIONS` are prefixed with ``-D`` or
+``/D`` and added to the compile line in an unspecified order. The
+:prop_tgt:`DEFINE_SYMBOL` target property is also added as a compile
+definition as a special convenience case for ``SHARED`` and ``MODULE``
+library targets.
+
+Entries in the :prop_tgt:`COMPILE_OPTIONS` are escaped for the shell and added
+in the order of appearance in the property value. Several compile options have
+special separate handling, such as :prop_tgt:`POSITION_INDEPENDENT_CODE`.
+
+The contents of the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`,
+:prop_tgt:`INTERFACE_COMPILE_DEFINITIONS` and
+:prop_tgt:`INTERFACE_COMPILE_OPTIONS` target properties are
+*Usage Requirements* -- they specify content which consumers
+must use to correctly compile and link with the target they appear on.
+For any binary target, the contents of each ``INTERFACE_`` property on
+each target specified in a :command:`target_link_libraries` command is
+consumed:
+
+.. code-block:: cmake
+
+ set(srcs archive.cpp zip.cpp)
+ if (LZMA_FOUND)
+ list(APPEND srcs lzma.cpp)
+ endif()
+ add_library(archive SHARED ${srcs})
+ if (LZMA_FOUND)
+ # The archive library sources are compiled with -DBUILDING_WITH_LZMA
+ target_compile_definitions(archive PRIVATE BUILDING_WITH_LZMA)
+ endif()
+ target_compile_definitions(archive INTERFACE USING_ARCHIVE_LIB)
+
+ add_executable(consumer)
+ # Link consumer to archive and consume its usage requirements. The consumer
+ # executable sources are compiled with -DUSING_ARCHIVE_LIB.
+ target_link_libraries(consumer archive)
+
+Because it is common to require that the source directory and corresponding
+build directory are added to the :prop_tgt:`INCLUDE_DIRECTORIES`, the
+:variable:`CMAKE_INCLUDE_CURRENT_DIR` variable can be enabled to conveniently
+add the corresponding directories to the :prop_tgt:`INCLUDE_DIRECTORIES` of
+all targets. The variable :variable:`CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE`
+can be enabled to add the corresponding directories to the
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of all targets. This makes use of
+targets in multiple different directories convenient through use of the
+:command:`target_link_libraries` command.
+
+
+.. _`Target Usage Requirements`:
+
+Transitive Usage Requirements
+-----------------------------
+
+The usage requirements of a target can transitively propagate to dependents.
+The :command:`target_link_libraries` command has ``PRIVATE``,
+``INTERFACE`` and ``PUBLIC`` keywords to control the propagation.
+
+.. code-block:: cmake
+
+ add_library(archive archive.cpp)
+ target_compile_definitions(archive INTERFACE USING_ARCHIVE_LIB)
+
+ add_library(serialization serialization.cpp)
+ target_compile_definitions(serialization INTERFACE USING_SERIALIZATION_LIB)
+
+ add_library(archiveExtras extras.cpp)
+ target_link_libraries(archiveExtras PUBLIC archive)
+ target_link_libraries(archiveExtras PRIVATE serialization)
+ # archiveExtras is compiled with -DUSING_ARCHIVE_LIB
+ # and -DUSING_SERIALIZATION_LIB
+
+ add_executable(consumer consumer.cpp)
+ # consumer is compiled with -DUSING_ARCHIVE_LIB
+ target_link_libraries(consumer archiveExtras)
+
+Because ``archive`` is a ``PUBLIC`` dependency of ``archiveExtras``, the
+usage requirements of it are propagated to ``consumer`` too. Because
+``serialization`` is a ``PRIVATE`` dependency of ``archiveExtras``, the usage
+requirements of it are not propagated to ``consumer``.
+
+Generally, a dependency should be specified in a use of
+:command:`target_link_libraries` with the ``PRIVATE`` keyword if it is used by
+only the implementation of a library, and not in the header files. If a
+dependency is additionally used in the header files of a library (e.g. for
+class inheritance), then it should be specified as a ``PUBLIC`` dependency.
+A dependency which is not used by the implementation of a library, but only by
+its headers should be specified as an ``INTERFACE`` dependency. The
+:command:`target_link_libraries` command may be invoked with multiple uses of
+each keyword:
+
+.. code-block:: cmake
+
+ target_link_libraries(archiveExtras
+ PUBLIC archive
+ PRIVATE serialization
+ )
+
+Usage requirements are propagated by reading the ``INTERFACE_`` variants
+of target properties from dependencies and appending the values to the
+non-``INTERFACE_`` variants of the operand. For example, the
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of dependencies is read and
+appended to the :prop_tgt:`INCLUDE_DIRECTORIES` of the operand. In cases
+where order is relevant and maintained, and the order resulting from the
+:command:`target_link_libraries` calls does not allow correct compilation,
+use of an appropriate command to set the property directly may update the
+order.
+
+For example, if the linked libraries for a target must be specified
+in the order ``lib1`` ``lib2`` ``lib3`` , but the include directories must
+be specified in the order ``lib3`` ``lib1`` ``lib2``:
+
+.. code-block:: cmake
+
+ target_link_libraries(myExe lib1 lib2 lib3)
+ target_include_directories(myExe
+ PRIVATE $<TARGET_PROPERTY:lib3,INTERFACE_INCLUDE_DIRECTORIES>)
+
+Note that care must be taken when specifying usage requirements for targets
+which will be exported for installation using the :command:`install(EXPORT)`
+command. See :ref:`Creating Packages` for more.
+
+.. _`Compatible Interface Properties`:
+
+Compatible Interface Properties
+-------------------------------
+
+Some target properties are required to be compatible between a target and
+the interface of each dependency. For example, the
+:prop_tgt:`POSITION_INDEPENDENT_CODE` target property may specify a
+boolean value of whether a target should be compiled as
+position-independent-code, which has platform-specific consequences.
+A target may also specify the usage requirement
+:prop_tgt:`INTERFACE_POSITION_INDEPENDENT_CODE` to communicate that
+consumers must be compiled as position-independent-code.
+
+.. code-block:: cmake
+
+ add_executable(exe1 exe1.cpp)
+ set_property(TARGET exe1 PROPERTY POSITION_INDEPENDENT_CODE ON)
+
+ add_library(lib1 SHARED lib1.cpp)
+ set_property(TARGET lib1 PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON)
+
+ add_executable(exe2 exe2.cpp)
+ target_link_libraries(exe2 lib1)
+
+Here, both ``exe1`` and ``exe2`` will be compiled as position-independent-code.
+``lib1`` will also be compiled as position-independent-code because that is the
+default setting for ``SHARED`` libraries. If dependencies have conflicting,
+non-compatible requirements :manual:`cmake(1)` issues a diagnostic:
+
+.. code-block:: cmake
+
+ add_library(lib1 SHARED lib1.cpp)
+ set_property(TARGET lib1 PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON)
+
+ add_library(lib2 SHARED lib2.cpp)
+ set_property(TARGET lib2 PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE OFF)
+
+ add_executable(exe1 exe1.cpp)
+ target_link_libraries(exe1 lib1)
+ set_property(TARGET exe1 PROPERTY POSITION_INDEPENDENT_CODE OFF)
+
+ add_executable(exe2 exe2.cpp)
+ target_link_libraries(exe2 lib1 lib2)
+
+The ``lib1`` requirement ``INTERFACE_POSITION_INDEPENDENT_CODE`` is not
+"compatible" with the :prop_tgt:`POSITION_INDEPENDENT_CODE` property of
+the ``exe1`` target. The library requires that consumers are built as
+position-independent-code, while the executable specifies to not built as
+position-independent-code, so a diagnostic is issued.
+
+The ``lib1`` and ``lib2`` requirements are not "compatible". One of them
+requires that consumers are built as position-independent-code, while
+the other requires that consumers are not built as position-independent-code.
+Because ``exe2`` links to both and they are in conflict, a CMake error message
+is issued::
+
+ CMake Error: The INTERFACE_POSITION_INDEPENDENT_CODE property of "lib2" does
+ not agree with the value of POSITION_INDEPENDENT_CODE already determined
+ for "exe2".
+
+To be "compatible", the :prop_tgt:`POSITION_INDEPENDENT_CODE` property,
+if set must be either the same, in a boolean sense, as the
+:prop_tgt:`INTERFACE_POSITION_INDEPENDENT_CODE` property of all transitively
+specified dependencies on which that property is set.
+
+This property of "compatible interface requirement" may be extended to other
+properties by specifying the property in the content of the
+:prop_tgt:`COMPATIBLE_INTERFACE_BOOL` target property. Each specified property
+must be compatible between the consuming target and the corresponding property
+with an ``INTERFACE_`` prefix from each dependency:
+
+.. code-block:: cmake
+
+ add_library(lib1Version2 SHARED lib1_v2.cpp)
+ set_property(TARGET lib1Version2 PROPERTY INTERFACE_CUSTOM_PROP ON)
+ set_property(TARGET lib1Version2 APPEND PROPERTY
+ COMPATIBLE_INTERFACE_BOOL CUSTOM_PROP
+ )
+
+ add_library(lib1Version3 SHARED lib1_v3.cpp)
+ set_property(TARGET lib1Version3 PROPERTY INTERFACE_CUSTOM_PROP OFF)
+
+ add_executable(exe1 exe1.cpp)
+ target_link_libraries(exe1 lib1Version2) # CUSTOM_PROP will be ON
+
+ add_executable(exe2 exe2.cpp)
+ target_link_libraries(exe2 lib1Version2 lib1Version3) # Diagnostic
+
+Non-boolean properties may also participate in "compatible interface"
+computations. Properties specified in the
+:prop_tgt:`COMPATIBLE_INTERFACE_STRING`
+property must be either unspecified or compare to the same string among
+all transitively specified dependencies. This can be useful to ensure
+that multiple incompatible versions of a library are not linked together
+through transitive requirements of a target:
+
+.. code-block:: cmake
+
+ add_library(lib1Version2 SHARED lib1_v2.cpp)
+ set_property(TARGET lib1Version2 PROPERTY INTERFACE_LIB_VERSION 2)
+ set_property(TARGET lib1Version2 APPEND PROPERTY
+ COMPATIBLE_INTERFACE_STRING LIB_VERSION
+ )
+
+ add_library(lib1Version3 SHARED lib1_v3.cpp)
+ set_property(TARGET lib1Version3 PROPERTY INTERFACE_LIB_VERSION 3)
+
+ add_executable(exe1 exe1.cpp)
+ target_link_libraries(exe1 lib1Version2) # LIB_VERSION will be "2"
+
+ add_executable(exe2 exe2.cpp)
+ target_link_libraries(exe2 lib1Version2 lib1Version3) # Diagnostic
+
+The :prop_tgt:`COMPATIBLE_INTERFACE_NUMBER_MAX` target property specifies
+that content will be evaluated numerically and the maximum number among all
+specified will be calculated:
+
+.. code-block:: cmake
+
+ add_library(lib1Version2 SHARED lib1_v2.cpp)
+ set_property(TARGET lib1Version2 PROPERTY INTERFACE_CONTAINER_SIZE_REQUIRED 200)
+ set_property(TARGET lib1Version2 APPEND PROPERTY
+ COMPATIBLE_INTERFACE_NUMBER_MAX CONTAINER_SIZE_REQUIRED
+ )
+
+ add_library(lib1Version3 SHARED lib1_v3.cpp)
+ set_property(TARGET lib1Version3 PROPERTY INTERFACE_CONTAINER_SIZE_REQUIRED 1000)
+
+ add_executable(exe1 exe1.cpp)
+ # CONTAINER_SIZE_REQUIRED will be "200"
+ target_link_libraries(exe1 lib1Version2)
+
+ add_executable(exe2 exe2.cpp)
+ # CONTAINER_SIZE_REQUIRED will be "1000"
+ target_link_libraries(exe2 lib1Version2 lib1Version3)
+
+Similarly, the :prop_tgt:`COMPATIBLE_INTERFACE_NUMBER_MIN` may be used to
+calculate the numeric minimum value for a property from dependencies.
+
+Each calculated "compatible" property value may be read in the consumer at
+generate-time using generator expressions.
+
+Note that for each dependee, the set of properties specified in each
+compatible interface property must not intersect with the set specified in
+any of the other properties.
+
+Property Origin Debugging
+-------------------------
+
+Because build specifications can be determined by dependencies, the lack of
+locality of code which creates a target and code which is responsible for
+setting build specifications may make the code more difficult to reason about.
+:manual:`cmake(1)` provides a debugging facility to print the origin of the
+contents of properties which may be determined by dependencies. The properties
+which can be debugged are listed in the
+:variable:`CMAKE_DEBUG_TARGET_PROPERTIES` variable documentation:
+
+.. code-block:: cmake
+
+ set(CMAKE_DEBUG_TARGET_PROPERTIES
+ INCLUDE_DIRECTORIES
+ COMPILE_DEFINITIONS
+ POSITION_INDEPENDENT_CODE
+ CONTAINER_SIZE_REQUIRED
+ LIB_VERSION
+ )
+ add_executable(exe1 exe1.cpp)
+
+In the case of properties listed in :prop_tgt:`COMPATIBLE_INTERFACE_BOOL` or
+:prop_tgt:`COMPATIBLE_INTERFACE_STRING`, the debug output shows which target
+was responsible for setting the property, and which other dependencies also
+defined the property. In the case of
+:prop_tgt:`COMPATIBLE_INTERFACE_NUMBER_MAX` and
+:prop_tgt:`COMPATIBLE_INTERFACE_NUMBER_MIN`, the debug output shows the
+value of the property from each dependency, and whether the value determines
+the new extreme.
+
+Build Specification with Generator Expressions
+----------------------------------------------
+
+Build specifications may use
+:manual:`generator expressions <cmake-generator-expressions(7)>` containing
+content which may be conditional or known only at generate-time. For example,
+the calculated "compatible" value of a property may be read with the
+``TARGET_PROPERTY`` expression:
+
+.. code-block:: cmake
+
+ add_library(lib1Version2 SHARED lib1_v2.cpp)
+ set_property(TARGET lib1Version2 PROPERTY
+ INTERFACE_CONTAINER_SIZE_REQUIRED 200)
+ set_property(TARGET lib1Version2 APPEND PROPERTY
+ COMPATIBLE_INTERFACE_NUMBER_MAX CONTAINER_SIZE_REQUIRED
+ )
+
+ add_executable(exe1 exe1.cpp)
+ target_link_libraries(exe1 lib1Version2)
+ target_compile_definitions(exe1 PRIVATE
+ CONTAINER_SIZE=$<TARGET_PROPERTY:CONTAINER_SIZE_REQUIRED>
+ )
+
+In this case, the ``exe1`` source files will be compiled with
+``-DCONTAINER_SIZE=200``.
+
+Configuration determined build specifications may be conveniently set using
+the ``CONFIG`` generator expression.
+
+.. code-block:: cmake
+
+ target_compile_definitions(exe1 PRIVATE
+ $<$<CONFIG:Debug>:DEBUG_BUILD>
+ )
+
+The ``CONFIG`` parameter is compared case-insensitively with the configuration
+being built. In the presence of :prop_tgt:`IMPORTED` targets, the content of
+:prop_tgt:`MAP_IMPORTED_CONFIG_DEBUG <MAP_IMPORTED_CONFIG_<CONFIG>>` is also
+accounted for by this expression.
+
+Some buildsystems generated by :manual:`cmake(1)` have a predetermined
+build-configuration set in the :variable:`CMAKE_BUILD_TYPE` variable. The
+buildsystem for the IDEs such as Visual Studio and Xcode are generated
+independent of the build-configuration, and the actual build configuration
+is not known until build-time. Therefore, code such as
+
+.. code-block:: cmake
+
+ string(TOLOWER ${CMAKE_BUILD_TYPE} _type)
+ if (_type STREQUAL debug)
+ target_compile_definitions(exe1 PRIVATE DEBUG_BUILD)
+ endif()
+
+may appear to work for :ref:`Makefile Generators` and :generator:`Ninja`
+generators, but is not portable to IDE generators. Additionally,
+the :prop_tgt:`IMPORTED` configuration-mappings are not accounted for
+with code like this, so it should be avoided.
+
+The unary ``TARGET_PROPERTY`` generator expression and the ``TARGET_POLICY``
+generator expression are evaluated with the consuming target context. This
+means that a usage requirement specification may be evaluated differently based
+on the consumer:
+
+.. code-block:: cmake
+
+ add_library(lib1 lib1.cpp)
+ target_compile_definitions(lib1 INTERFACE
+ $<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:LIB1_WITH_EXE>
+ $<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>:LIB1_WITH_SHARED_LIB>
+ $<$<TARGET_POLICY:CMP0041>:CONSUMER_CMP0041_NEW>
+ )
+
+ add_executable(exe1 exe1.cpp)
+ target_link_libraries(exe1 lib1)
+
+ cmake_policy(SET CMP0041 NEW)
+
+ add_library(shared_lib shared_lib.cpp)
+ target_link_libraries(shared_lib lib1)
+
+The ``exe1`` executable will be compiled with ``-DLIB1_WITH_EXE``, while the
+``shared_lib`` shared library will be compiled with ``-DLIB1_WITH_SHARED_LIB``
+and ``-DCONSUMER_CMP0041_NEW``, because policy :policy:`CMP0041` is
+``NEW`` at the point where the ``shared_lib`` target is created.
+
+The ``BUILD_INTERFACE`` expression wraps requirements which are only used when
+consumed from a target in the same buildsystem, or when consumed from a target
+exported to the build directory using the :command:`export` command. The
+``INSTALL_INTERFACE`` expression wraps requirements which are only used when
+consumed from a target which has been installed and exported with the
+:command:`install(EXPORT)` command:
+
+.. code-block:: cmake
+
+ add_library(ClimbingStats climbingstats.cpp)
+ target_compile_definitions(ClimbingStats INTERFACE
+ $<BUILD_INTERFACE:ClimbingStats_FROM_BUILD_LOCATION>
+ $<INSTALL_INTERFACE:ClimbingStats_FROM_INSTALLED_LOCATION>
+ )
+ install(TARGETS ClimbingStats EXPORT libExport ${InstallArgs})
+ install(EXPORT libExport NAMESPACE Upstream::
+ DESTINATION lib/cmake/ClimbingStats)
+ export(EXPORT libExport NAMESPACE Upstream::)
+
+ add_executable(exe1 exe1.cpp)
+ target_link_libraries(exe1 ClimbingStats)
+
+In this case, the ``exe1`` executable will be compiled with
+``-DClimbingStats_FROM_BUILD_LOCATION``. The exporting commands generate
+:prop_tgt:`IMPORTED` targets with either the ``INSTALL_INTERFACE`` or the
+``BUILD_INTERFACE`` omitted, and the ``*_INTERFACE`` marker stripped away.
+A separate project consuming the ``ClimbingStats`` package would contain:
+
+.. code-block:: cmake
+
+ find_package(ClimbingStats REQUIRED)
+
+ add_executable(Downstream main.cpp)
+ target_link_libraries(Downstream Upstream::ClimbingStats)
+
+Depending on whether the ``ClimbingStats`` package was used from the build
+location or the install location, the ``Downstream`` target would be compiled
+with either ``-DClimbingStats_FROM_BUILD_LOCATION`` or
+``-DClimbingStats_FROM_INSTALL_LOCATION``. For more about packages and
+exporting see the :manual:`cmake-packages(7)` manual.
+
+.. _`Include Directories and Usage Requirements`:
+
+Include Directories and Usage Requirements
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Include directories require some special consideration when specified as usage
+requirements and when used with generator expressions. The
+:command:`target_include_directories` command accepts both relative and
+absolute include directories:
+
+.. code-block:: cmake
+
+ add_library(lib1 lib1.cpp)
+ target_include_directories(lib1 PRIVATE
+ /absolute/path
+ relative/path
+ )
+
+Relative paths are interpreted relative to the source directory where the
+command appears. Relative paths are not allowed in the
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of :prop_tgt:`IMPORTED` targets.
+
+In cases where a non-trivial generator expression is used, the
+``INSTALL_PREFIX`` expression may be used within the argument of an
+``INSTALL_INTERFACE`` expression. It is a replacement marker which
+expands to the installation prefix when imported by a consuming project.
+
+Include directories usage requirements commonly differ between the build-tree
+and the install-tree. The ``BUILD_INTERFACE`` and ``INSTALL_INTERFACE``
+generator expressions can be used to describe separate usage requirements
+based on the usage location. Relative paths are allowed within the
+``INSTALL_INTERFACE`` expression and are interpreted relative to the
+installation prefix. For example:
+
+.. code-block:: cmake
+
+ add_library(ClimbingStats climbingstats.cpp)
+ target_include_directories(ClimbingStats INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/generated>
+ $<INSTALL_INTERFACE:/absolute/path>
+ $<INSTALL_INTERFACE:relative/path>
+ $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/$<CONFIG>/generated>
+ )
+
+Two convenience APIs are provided relating to include directories usage
+requirements. The :variable:`CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE` variable
+may be enabled, with an equivalent effect to:
+
+.. code-block:: cmake
+
+ set_property(TARGET tgt APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR}>
+ )
+
+for each target affected. The convenience for installed targets is
+an ``INCLUDES DESTINATION`` component with the :command:`install(TARGETS)`
+command:
+
+.. code-block:: cmake
+
+ install(TARGETS foo bar bat EXPORT tgts ${dest_args}
+ INCLUDES DESTINATION include
+ )
+ install(EXPORT tgts ${other_args})
+ install(FILES ${headers} DESTINATION include)
+
+This is equivalent to appending ``${CMAKE_INSTALL_PREFIX}/include`` to the
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of each of the installed
+:prop_tgt:`IMPORTED` targets when generated by :command:`install(EXPORT)`.
+
+When the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of an
+:ref:`imported target <Imported targets>` is consumed, the entries in the
+property are treated as ``SYSTEM`` include directories, as if they were
+listed in the :prop_tgt:`INTERFACE_SYSTEM_INCLUDE_DIRECTORIES` of the
+dependency. This can result in omission of compiler warnings for headers
+found in those directories. This behavior for :ref:`imported targets` may
+be controlled by setting the :prop_tgt:`NO_SYSTEM_FROM_IMPORTED` target
+property on the *consumers* of imported targets.
+
+If a binary target is linked transitively to a macOS :prop_tgt:`FRAMEWORK`, the
+``Headers`` directory of the framework is also treated as a usage requirement.
+This has the same effect as passing the framework directory as an include
+directory.
+
+Link Libraries and Generator Expressions
+----------------------------------------
+
+Like build specifications, :prop_tgt:`link libraries <LINK_LIBRARIES>` may be
+specified with generator expression conditions. However, as consumption of
+usage requirements is based on collection from linked dependencies, there is
+an additional limitation that the link dependencies must form a "directed
+acyclic graph". That is, if linking to a target is dependent on the value of
+a target property, that target property may not be dependent on the linked
+dependencies:
+
+.. code-block:: cmake
+
+ add_library(lib1 lib1.cpp)
+ add_library(lib2 lib2.cpp)
+ target_link_libraries(lib1 PUBLIC
+ $<$<TARGET_PROPERTY:POSITION_INDEPENDENT_CODE>:lib2>
+ )
+ add_library(lib3 lib3.cpp)
+ set_property(TARGET lib3 PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON)
+
+ add_executable(exe1 exe1.cpp)
+ target_link_libraries(exe1 lib1 lib3)
+
+As the value of the :prop_tgt:`POSITION_INDEPENDENT_CODE` property of
+the ``exe1`` target is dependent on the linked libraries (``lib3``), and the
+edge of linking ``exe1`` is determined by the same
+:prop_tgt:`POSITION_INDEPENDENT_CODE` property, the dependency graph above
+contains a cycle. :manual:`cmake(1)` issues an error message.
+
+.. _`Output Artifacts`:
+
+Output Artifacts
+----------------
+
+The buildsystem targets created by the :command:`add_library` and
+:command:`add_executable` commands create rules to create binary outputs.
+The exact output location of the binaries can only be determined at
+generate-time because it can depend on the build-configuration and the
+link-language of linked dependencies etc. ``TARGET_FILE``,
+``TARGET_LINKER_FILE`` and related expressions can be used to access the
+name and location of generated binaries. These expressions do not work
+for ``OBJECT`` libraries however, as there is no single file generated
+by such libraries which is relevant to the expressions.
+
+There are three kinds of output artifacts that may be build by targets
+as detailed in the following sections. Their classification differs
+between DLL platforms and non-DLL platforms. All Windows-based
+systems including Cygwin are DLL platforms.
+
+.. _`Runtime Output Artifacts`:
+
+Runtime Output Artifacts
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+A *runtime* output artifact of a buildsystem target may be:
+
+* The executable file (e.g. ``.exe``) of an executable target
+ created by the :command:`add_executable` command.
+
+* On DLL platforms: the executable file (e.g. ``.dll``) of a shared
+ library target created by the :command:`add_library` command
+ with the ``SHARED`` option.
+
+The :prop_tgt:`RUNTIME_OUTPUT_DIRECTORY` and :prop_tgt:`RUNTIME_OUTPUT_NAME`
+target properties may be used to control runtime output artifact locations
+and names in the build tree.
+
+.. _`Library Output Artifacts`:
+
+Library Output Artifacts
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+A *library* output artifact of a buildsystem target may be:
+
+* The loadable module file (e.g. ``.dll`` or ``.so``) of a module
+ library target created by the :command:`add_library` command
+ with the ``MODULE`` option.
+
+* On non-DLL platforms: the shared library file (e.g. ``.so`` or ``.dylib``)
+ of a shared library target created by the :command:`add_library`
+ command with the ``SHARED`` option.
+
+The :prop_tgt:`LIBRARY_OUTPUT_DIRECTORY` and :prop_tgt:`LIBRARY_OUTPUT_NAME`
+target properties may be used to control library output artifact locations
+and names in the build tree.
+
+.. _`Archive Output Artifacts`:
+
+Archive Output Artifacts
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+An *archive* output artifact of a buildsystem target may be:
+
+* The static library file (e.g. ``.lib`` or ``.a``) of a static
+ library target created by the :command:`add_library` command
+ with the ``STATIC`` option.
+
+* On DLL platforms: the import library file (e.g. ``.lib``) of a shared
+ library target created by the :command:`add_library` command
+ with the ``SHARED`` option. This file is only guaranteed to exist if
+ the library exports at least one unmanaged symbol.
+
+* On DLL platforms: the import library file (e.g. ``.lib``) of an
+ executable target created by the :command:`add_executable` command
+ when its :prop_tgt:`ENABLE_EXPORTS` target property is set.
+
+* On AIX: the linker import file (e.g. ``.imp``) of an executable target
+ created by the :command:`add_executable` command when its
+ :prop_tgt:`ENABLE_EXPORTS` target property is set.
+
+The :prop_tgt:`ARCHIVE_OUTPUT_DIRECTORY` and :prop_tgt:`ARCHIVE_OUTPUT_NAME`
+target properties may be used to control archive output artifact locations
+and names in the build tree.
+
+Directory-Scoped Commands
+-------------------------
+
+The :command:`target_include_directories`,
+:command:`target_compile_definitions` and
+:command:`target_compile_options` commands have an effect on only one
+target at a time. The commands :command:`add_compile_definitions`,
+:command:`add_compile_options` and :command:`include_directories` have
+a similar function, but operate at directory scope instead of target
+scope for convenience.
+
+Pseudo Targets
+==============
+
+Some target types do not represent outputs of the buildsystem, but only inputs
+such as external dependencies, aliases or other non-build artifacts. Pseudo
+targets are not represented in the generated buildsystem.
+
+.. _`Imported Targets`:
+
+Imported Targets
+----------------
+
+An :prop_tgt:`IMPORTED` target represents a pre-existing dependency. Usually
+such targets are defined by an upstream package and should be treated as
+immutable. After declaring an :prop_tgt:`IMPORTED` target one can adjust its
+target properties by using the customary commands such as
+:command:`target_compile_definitions`, :command:`target_include_directories`,
+:command:`target_compile_options` or :command:`target_link_libraries` just like
+with any other regular target.
+
+:prop_tgt:`IMPORTED` targets may have the same usage requirement properties
+populated as binary targets, such as
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`,
+:prop_tgt:`INTERFACE_COMPILE_DEFINITIONS`,
+:prop_tgt:`INTERFACE_COMPILE_OPTIONS`,
+:prop_tgt:`INTERFACE_LINK_LIBRARIES`, and
+:prop_tgt:`INTERFACE_POSITION_INDEPENDENT_CODE`.
+
+The :prop_tgt:`LOCATION` may also be read from an IMPORTED target, though there
+is rarely reason to do so. Commands such as :command:`add_custom_command` can
+transparently use an :prop_tgt:`IMPORTED` :prop_tgt:`EXECUTABLE <TYPE>` target
+as a ``COMMAND`` executable.
+
+The scope of the definition of an :prop_tgt:`IMPORTED` target is the directory
+where it was defined. It may be accessed and used from subdirectories, but
+not from parent directories or sibling directories. The scope is similar to
+the scope of a cmake variable.
+
+It is also possible to define a ``GLOBAL`` :prop_tgt:`IMPORTED` target which is
+accessible globally in the buildsystem.
+
+See the :manual:`cmake-packages(7)` manual for more on creating packages
+with :prop_tgt:`IMPORTED` targets.
+
+.. _`Alias Targets`:
+
+Alias Targets
+-------------
+
+An ``ALIAS`` target is a name which may be used interchangeably with
+a binary target name in read-only contexts. A primary use-case for ``ALIAS``
+targets is for example or unit test executables accompanying a library, which
+may be part of the same buildsystem or built separately based on user
+configuration.
+
+.. code-block:: cmake
+
+ add_library(lib1 lib1.cpp)
+ install(TARGETS lib1 EXPORT lib1Export ${dest_args})
+ install(EXPORT lib1Export NAMESPACE Upstream:: ${other_args})
+
+ add_library(Upstream::lib1 ALIAS lib1)
+
+In another directory, we can link unconditionally to the ``Upstream::lib1``
+target, which may be an :prop_tgt:`IMPORTED` target from a package, or an
+``ALIAS`` target if built as part of the same buildsystem.
+
+.. code-block:: cmake
+
+ if (NOT TARGET Upstream::lib1)
+ find_package(lib1 REQUIRED)
+ endif()
+ add_executable(exe1 exe1.cpp)
+ target_link_libraries(exe1 Upstream::lib1)
+
+``ALIAS`` targets are not mutable, installable or exportable. They are
+entirely local to the buildsystem description. A name can be tested for
+whether it is an ``ALIAS`` name by reading the :prop_tgt:`ALIASED_TARGET`
+property from it:
+
+.. code-block:: cmake
+
+ get_target_property(_aliased Upstream::lib1 ALIASED_TARGET)
+ if(_aliased)
+ message(STATUS "The name Upstream::lib1 is an ALIAS for ${_aliased}.")
+ endif()
+
+.. _`Interface Libraries`:
+
+Interface Libraries
+-------------------
+
+An ``INTERFACE`` library target does not compile sources and does not
+produce a library artifact on disk, so it has no :prop_tgt:`LOCATION`.
+
+It may specify usage requirements such as
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`,
+:prop_tgt:`INTERFACE_COMPILE_DEFINITIONS`,
+:prop_tgt:`INTERFACE_COMPILE_OPTIONS`,
+:prop_tgt:`INTERFACE_LINK_LIBRARIES`,
+:prop_tgt:`INTERFACE_SOURCES`,
+and :prop_tgt:`INTERFACE_POSITION_INDEPENDENT_CODE`.
+Only the ``INTERFACE`` modes of the :command:`target_include_directories`,
+:command:`target_compile_definitions`, :command:`target_compile_options`,
+:command:`target_sources`, and :command:`target_link_libraries` commands
+may be used with ``INTERFACE`` libraries.
+
+Since CMake 3.19, an ``INTERFACE`` library target may optionally contain
+source files. An interface library that contains source files will be
+included as a build target in the generated buildsystem. It does not
+compile sources, but may contain custom commands to generate other sources.
+Additionally, IDEs will show the source files as part of the target for
+interactive reading and editing.
+
+A primary use-case for ``INTERFACE`` libraries is header-only libraries.
+
+.. code-block:: cmake
+
+ add_library(Eigen INTERFACE
+ src/eigen.h
+ src/vector.h
+ src/matrix.h
+ )
+ target_include_directories(Eigen INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
+ $<INSTALL_INTERFACE:include/Eigen>
+ )
+
+ add_executable(exe1 exe1.cpp)
+ target_link_libraries(exe1 Eigen)
+
+Here, the usage requirements from the ``Eigen`` target are consumed and used
+when compiling, but it has no effect on linking.
+
+Another use-case is to employ an entirely target-focussed design for usage
+requirements:
+
+.. code-block:: cmake
+
+ add_library(pic_on INTERFACE)
+ set_property(TARGET pic_on PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON)
+ add_library(pic_off INTERFACE)
+ set_property(TARGET pic_off PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE OFF)
+
+ add_library(enable_rtti INTERFACE)
+ target_compile_options(enable_rtti INTERFACE
+ $<$<OR:$<COMPILER_ID:GNU>,$<COMPILER_ID:Clang>>:-rtti>
+ )
+
+ add_executable(exe1 exe1.cpp)
+ target_link_libraries(exe1 pic_on enable_rtti)
+
+This way, the build specification of ``exe1`` is expressed entirely as linked
+targets, and the complexity of compiler-specific flags is encapsulated in an
+``INTERFACE`` library target.
+
+``INTERFACE`` libraries may be installed and exported. Any content they refer
+to must be installed separately:
+
+.. code-block:: cmake
+
+ set(Eigen_headers
+ src/eigen.h
+ src/vector.h
+ src/matrix.h
+ )
+ add_library(Eigen INTERFACE ${Eigen_headers})
+ target_include_directories(Eigen INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
+ $<INSTALL_INTERFACE:include/Eigen>
+ )
+
+ install(TARGETS Eigen EXPORT eigenExport)
+ install(EXPORT eigenExport NAMESPACE Upstream::
+ DESTINATION lib/cmake/Eigen
+ )
+ install(FILES ${Eigen_headers}
+ DESTINATION include/Eigen
+ )
diff --git a/Help/manual/cmake-commands.7.rst b/Help/manual/cmake-commands.7.rst
new file mode 100644
index 0000000..036fa8f
--- /dev/null
+++ b/Help/manual/cmake-commands.7.rst
@@ -0,0 +1,174 @@
+.. cmake-manual-description: CMake Language Command Reference
+
+cmake-commands(7)
+*****************
+
+.. only:: html
+
+ .. contents::
+
+Scripting Commands
+==================
+
+These commands are always available.
+
+.. toctree::
+ :maxdepth: 1
+
+ /command/break
+ /command/cmake_host_system_information
+ /command/cmake_language
+ /command/cmake_minimum_required
+ /command/cmake_parse_arguments
+ /command/cmake_path
+ /command/cmake_policy
+ /command/configure_file
+ /command/continue
+ /command/else
+ /command/elseif
+ /command/endforeach
+ /command/endfunction
+ /command/endif
+ /command/endmacro
+ /command/endwhile
+ /command/execute_process
+ /command/file
+ /command/find_file
+ /command/find_library
+ /command/find_package
+ /command/find_path
+ /command/find_program
+ /command/foreach
+ /command/function
+ /command/get_cmake_property
+ /command/get_directory_property
+ /command/get_filename_component
+ /command/get_property
+ /command/if
+ /command/include
+ /command/include_guard
+ /command/list
+ /command/macro
+ /command/mark_as_advanced
+ /command/math
+ /command/message
+ /command/option
+ /command/return
+ /command/separate_arguments
+ /command/set
+ /command/set_directory_properties
+ /command/set_property
+ /command/site_name
+ /command/string
+ /command/unset
+ /command/variable_watch
+ /command/while
+
+Project Commands
+================
+
+These commands are available only in CMake projects.
+
+.. toctree::
+ :maxdepth: 1
+
+ /command/add_compile_definitions
+ /command/add_compile_options
+ /command/add_custom_command
+ /command/add_custom_target
+ /command/add_definitions
+ /command/add_dependencies
+ /command/add_executable
+ /command/add_library
+ /command/add_link_options
+ /command/add_subdirectory
+ /command/add_test
+ /command/aux_source_directory
+ /command/build_command
+ /command/create_test_sourcelist
+ /command/define_property
+ /command/enable_language
+ /command/enable_testing
+ /command/export
+ /command/fltk_wrap_ui
+ /command/get_source_file_property
+ /command/get_target_property
+ /command/get_test_property
+ /command/include_directories
+ /command/include_external_msproject
+ /command/include_regular_expression
+ /command/install
+ /command/link_directories
+ /command/link_libraries
+ /command/load_cache
+ /command/project
+ /command/remove_definitions
+ /command/set_source_files_properties
+ /command/set_target_properties
+ /command/set_tests_properties
+ /command/source_group
+ /command/target_compile_definitions
+ /command/target_compile_features
+ /command/target_compile_options
+ /command/target_include_directories
+ /command/target_link_directories
+ /command/target_link_libraries
+ /command/target_link_options
+ /command/target_precompile_headers
+ /command/target_sources
+ /command/try_compile
+ /command/try_run
+
+.. _`CTest Commands`:
+
+CTest Commands
+==============
+
+These commands are available only in CTest scripts.
+
+.. toctree::
+ :maxdepth: 1
+
+ /command/ctest_build
+ /command/ctest_configure
+ /command/ctest_coverage
+ /command/ctest_empty_binary_directory
+ /command/ctest_memcheck
+ /command/ctest_read_custom_files
+ /command/ctest_run_script
+ /command/ctest_sleep
+ /command/ctest_start
+ /command/ctest_submit
+ /command/ctest_test
+ /command/ctest_update
+ /command/ctest_upload
+
+Deprecated Commands
+===================
+
+These commands are deprecated and are only made available to maintain
+backward compatibility. The documentation of each command states the
+CMake version in which it was deprecated. Do not use these commands
+in new code.
+
+.. toctree::
+ :maxdepth: 1
+
+ /command/build_name
+ /command/exec_program
+ /command/export_library_dependencies
+ /command/install_files
+ /command/install_programs
+ /command/install_targets
+ /command/load_command
+ /command/make_directory
+ /command/output_required_files
+ /command/qt_wrap_cpp
+ /command/qt_wrap_ui
+ /command/remove
+ /command/subdir_depends
+ /command/subdirs
+ /command/use_mangled_mesa
+ /command/utility_source
+ /command/variable_requires
+ /command/write_file
diff --git a/Help/manual/cmake-compile-features.7.rst b/Help/manual/cmake-compile-features.7.rst
new file mode 100644
index 0000000..56d16c0
--- /dev/null
+++ b/Help/manual/cmake-compile-features.7.rst
@@ -0,0 +1,381 @@
+.. cmake-manual-description: CMake Compile Features Reference
+
+cmake-compile-features(7)
+*************************
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+Project source code may depend on, or be conditional on, the availability
+of certain features of the compiler. There are three use-cases which arise:
+`Compile Feature Requirements`_, `Optional Compile Features`_
+and `Conditional Compilation Options`_.
+
+While features are typically specified in programming language standards,
+CMake provides a primary user interface based on granular handling of
+the features, not the language standard that introduced the feature.
+
+The :prop_gbl:`CMAKE_C_KNOWN_FEATURES`, :prop_gbl:`CMAKE_CUDA_KNOWN_FEATURES`,
+and :prop_gbl:`CMAKE_CXX_KNOWN_FEATURES` global properties contain all the
+features known to CMake, regardless of compiler support for the feature.
+The :variable:`CMAKE_C_COMPILE_FEATURES`, :variable:`CMAKE_CUDA_COMPILE_FEATURES`
+, and :variable:`CMAKE_CXX_COMPILE_FEATURES` variables contain all features
+CMake knows are known to the compiler, regardless of language standard
+or compile flags needed to use them.
+
+Features known to CMake are named mostly following the same convention
+as the Clang feature test macros. There are some exceptions, such as
+CMake using ``cxx_final`` and ``cxx_override`` instead of the single
+``cxx_override_control`` used by Clang.
+
+Note that there are no separate compile features properties or variables for
+the ``OBJC`` or ``OBJCXX`` languages. These are based off ``C`` or ``C++``
+respectively, so the properties and variables for their corresponding base
+language should be used instead.
+
+Compile Feature Requirements
+============================
+
+Compile feature requirements may be specified with the
+:command:`target_compile_features` command. For example, if a target must
+be compiled with compiler support for the
+:prop_gbl:`cxx_constexpr <CMAKE_CXX_KNOWN_FEATURES>` feature:
+
+.. code-block:: cmake
+
+ add_library(mylib requires_constexpr.cpp)
+ target_compile_features(mylib PRIVATE cxx_constexpr)
+
+In processing the requirement for the ``cxx_constexpr`` feature,
+:manual:`cmake(1)` will ensure that the in-use C++ compiler is capable
+of the feature, and will add any necessary flags such as ``-std=gnu++11``
+to the compile lines of C++ files in the ``mylib`` target. A
+``FATAL_ERROR`` is issued if the compiler is not capable of the
+feature.
+
+The exact compile flags and language standard are deliberately not part
+of the user interface for this use-case. CMake will compute the
+appropriate compile flags to use by considering the features specified
+for each target.
+
+Such compile flags are added even if the compiler supports the
+particular feature without the flag. For example, the GNU compiler
+supports variadic templates (with a warning) even if ``-std=gnu++98`` is
+used. CMake adds the ``-std=gnu++11`` flag if ``cxx_variadic_templates``
+is specified as a requirement.
+
+In the above example, ``mylib`` requires ``cxx_constexpr`` when it
+is built itself, but consumers of ``mylib`` are not required to use a
+compiler which supports ``cxx_constexpr``. If the interface of
+``mylib`` does require the ``cxx_constexpr`` feature (or any other
+known feature), that may be specified with the ``PUBLIC`` or
+``INTERFACE`` signatures of :command:`target_compile_features`:
+
+.. code-block:: cmake
+
+ add_library(mylib requires_constexpr.cpp)
+ # cxx_constexpr is a usage-requirement
+ target_compile_features(mylib PUBLIC cxx_constexpr)
+
+ # main.cpp will be compiled with -std=gnu++11 on GNU for cxx_constexpr.
+ add_executable(myexe main.cpp)
+ target_link_libraries(myexe mylib)
+
+Feature requirements are evaluated transitively by consuming the link
+implementation. See :manual:`cmake-buildsystem(7)` for more on
+transitive behavior of build properties and usage requirements.
+
+.. _`Requiring Language Standards`:
+
+Requiring Language Standards
+----------------------------
+
+In projects that use a large number of commonly available features from
+a particular language standard (e.g. C++ 11) one may specify a
+meta-feature (e.g. ``cxx_std_11``) that requires use of a compiler mode
+that is at minimum aware of that standard, but could be greater.
+This is simpler than specifying all the features individually, but does
+not guarantee the existence of any particular feature.
+Diagnosis of use of unsupported features will be delayed until compile time.
+
+For example, if C++ 11 features are used extensively in a project's
+header files, then clients must use a compiler mode that is no less
+than C++ 11. This can be requested with the code:
+
+.. code-block:: cmake
+
+ target_compile_features(mylib PUBLIC cxx_std_11)
+
+In this example, CMake will ensure the compiler is invoked in a mode
+of at-least C++ 11 (or C++ 14, C++ 17, ...), adding flags such as
+``-std=gnu++11`` if necessary. This applies to sources within ``mylib``
+as well as any dependents (that may include headers from ``mylib``).
+
+Availability of Compiler Extensions
+-----------------------------------
+
+Because the :prop_tgt:`CXX_EXTENSIONS` target property is ``ON`` by default,
+CMake uses extended variants of language dialects by default, such as
+``-std=gnu++11`` instead of ``-std=c++11``. That target property may be
+set to ``OFF`` to use the non-extended variant of the dialect flag. Note
+that because most compilers enable extensions by default, this could
+expose cross-platform bugs in user code or in the headers of third-party
+dependencies.
+
+Optional Compile Features
+=========================
+
+Compile features may be preferred if available, without creating a hard
+requirement. For example, a library may provides alternative
+implementations depending on whether the ``cxx_variadic_templates``
+feature is available:
+
+.. code-block:: c++
+
+ #if Foo_COMPILER_CXX_VARIADIC_TEMPLATES
+ template<int I, int... Is>
+ struct Interface;
+
+ template<int I>
+ struct Interface<I>
+ {
+ static int accumulate()
+ {
+ return I;
+ }
+ };
+
+ template<int I, int... Is>
+ struct Interface
+ {
+ static int accumulate()
+ {
+ return I + Interface<Is...>::accumulate();
+ }
+ };
+ #else
+ template<int I1, int I2 = 0, int I3 = 0, int I4 = 0>
+ struct Interface
+ {
+ static int accumulate() { return I1 + I2 + I3 + I4; }
+ };
+ #endif
+
+Such an interface depends on using the correct preprocessor defines for the
+compiler features. CMake can generate a header file containing such
+defines using the :module:`WriteCompilerDetectionHeader` module. The
+module contains the ``write_compiler_detection_header`` function which
+accepts parameters to control the content of the generated header file:
+
+.. code-block:: cmake
+
+ write_compiler_detection_header(
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/foo_compiler_detection.h"
+ PREFIX Foo
+ COMPILERS GNU
+ FEATURES
+ cxx_variadic_templates
+ )
+
+Such a header file may be used internally in the source code of a project,
+and it may be installed and used in the interface of library code.
+
+For each feature listed in ``FEATURES``, a preprocessor definition
+is created in the header file, and defined to either ``1`` or ``0``.
+
+Additionally, some features call for additional defines, such as the
+``cxx_final`` and ``cxx_override`` features. Rather than being used in
+``#ifdef`` code, the ``final`` keyword is abstracted by a symbol
+which is defined to either ``final``, a compiler-specific equivalent, or
+to empty. That way, C++ code can be written to unconditionally use the
+symbol, and compiler support determines what it is expanded to:
+
+.. code-block:: c++
+
+ struct Interface {
+ virtual void Execute() = 0;
+ };
+
+ struct Concrete Foo_FINAL {
+ void Execute() Foo_OVERRIDE;
+ };
+
+In this case, ``Foo_FINAL`` will expand to ``final`` if the
+compiler supports the keyword, or to empty otherwise.
+
+In this use-case, the CMake code will wish to enable a particular language
+standard if available from the compiler. The :prop_tgt:`CXX_STANDARD`
+target property variable may be set to the desired language standard
+for a particular target, and the :variable:`CMAKE_CXX_STANDARD` may be
+set to influence all following targets:
+
+.. code-block:: cmake
+
+ write_compiler_detection_header(
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/foo_compiler_detection.h"
+ PREFIX Foo
+ COMPILERS GNU
+ FEATURES
+ cxx_final cxx_override
+ )
+
+ # Includes foo_compiler_detection.h and uses the Foo_FINAL symbol
+ # which will expand to 'final' if the compiler supports the requested
+ # CXX_STANDARD.
+ add_library(foo foo.cpp)
+ set_property(TARGET foo PROPERTY CXX_STANDARD 11)
+
+ # Includes foo_compiler_detection.h and uses the Foo_FINAL symbol
+ # which will expand to 'final' if the compiler supports the feature,
+ # even though CXX_STANDARD is not set explicitly. The requirement of
+ # cxx_constexpr causes CMake to set CXX_STANDARD internally, which
+ # affects the compile flags.
+ add_library(foo_impl foo_impl.cpp)
+ target_compile_features(foo_impl PRIVATE cxx_constexpr)
+
+The ``write_compiler_detection_header`` function also creates compatibility
+code for other features which have standard equivalents. For example, the
+``cxx_static_assert`` feature is emulated with a template and abstracted
+via the ``<PREFIX>_STATIC_ASSERT`` and ``<PREFIX>_STATIC_ASSERT_MSG``
+function-macros.
+
+Conditional Compilation Options
+===============================
+
+Libraries may provide entirely different header files depending on
+requested compiler features.
+
+For example, a header at ``with_variadics/interface.h`` may contain:
+
+.. code-block:: c++
+
+ template<int I, int... Is>
+ struct Interface;
+
+ template<int I>
+ struct Interface<I>
+ {
+ static int accumulate()
+ {
+ return I;
+ }
+ };
+
+ template<int I, int... Is>
+ struct Interface
+ {
+ static int accumulate()
+ {
+ return I + Interface<Is...>::accumulate();
+ }
+ };
+
+while a header at ``no_variadics/interface.h`` may contain:
+
+.. code-block:: c++
+
+ template<int I1, int I2 = 0, int I3 = 0, int I4 = 0>
+ struct Interface
+ {
+ static int accumulate() { return I1 + I2 + I3 + I4; }
+ };
+
+It would be possible to write a abstraction ``interface.h`` header
+containing something like:
+
+.. code-block:: c++
+
+ #include "foo_compiler_detection.h"
+ #if Foo_COMPILER_CXX_VARIADIC_TEMPLATES
+ #include "with_variadics/interface.h"
+ #else
+ #include "no_variadics/interface.h"
+ #endif
+
+However this could be unmaintainable if there are many files to
+abstract. What is needed is to use alternative include directories
+depending on the compiler capabilities.
+
+CMake provides a ``COMPILE_FEATURES``
+:manual:`generator expression <cmake-generator-expressions(7)>` to implement
+such conditions. This may be used with the build-property commands such as
+:command:`target_include_directories` and :command:`target_link_libraries`
+to set the appropriate :manual:`buildsystem <cmake-buildsystem(7)>`
+properties:
+
+.. code-block:: cmake
+
+ add_library(foo INTERFACE)
+ set(with_variadics ${CMAKE_CURRENT_SOURCE_DIR}/with_variadics)
+ set(no_variadics ${CMAKE_CURRENT_SOURCE_DIR}/no_variadics)
+ target_include_directories(foo
+ INTERFACE
+ "$<$<COMPILE_FEATURES:cxx_variadic_templates>:${with_variadics}>"
+ "$<$<NOT:$<COMPILE_FEATURES:cxx_variadic_templates>>:${no_variadics}>"
+ )
+
+Consuming code then simply links to the ``foo`` target as usual and uses
+the feature-appropriate include directory
+
+.. code-block:: cmake
+
+ add_executable(consumer_with consumer_with.cpp)
+ target_link_libraries(consumer_with foo)
+ set_property(TARGET consumer_with CXX_STANDARD 11)
+
+ add_executable(consumer_no consumer_no.cpp)
+ target_link_libraries(consumer_no foo)
+
+Supported Compilers
+===================
+
+CMake is currently aware of the :prop_tgt:`C++ standards <CXX_STANDARD>`
+and :prop_gbl:`compile features <CMAKE_CXX_KNOWN_FEATURES>` available from
+the following :variable:`compiler ids <CMAKE_<LANG>_COMPILER_ID>` as of the
+versions specified for each:
+
+* ``AppleClang``: Apple Clang for Xcode versions 4.4+.
+* ``Clang``: Clang compiler versions 2.9+.
+* ``GNU``: GNU compiler versions 4.4+.
+* ``MSVC``: Microsoft Visual Studio versions 2010+.
+* ``SunPro``: Oracle SolarisStudio versions 12.4+.
+* ``Intel``: Intel compiler versions 12.1+.
+
+CMake is currently aware of the :prop_tgt:`C standards <C_STANDARD>`
+and :prop_gbl:`compile features <CMAKE_C_KNOWN_FEATURES>` available from
+the following :variable:`compiler ids <CMAKE_<LANG>_COMPILER_ID>` as of the
+versions specified for each:
+
+* all compilers and versions listed above for C++.
+* ``GNU``: GNU compiler versions 3.4+
+
+CMake is currently aware of the :prop_tgt:`C++ standards <CXX_STANDARD>` and
+their associated meta-features (e.g. ``cxx_std_11``) available from the
+following :variable:`compiler ids <CMAKE_<LANG>_COMPILER_ID>` as of the
+versions specified for each:
+
+* ``Cray``: Cray Compiler Environment version 8.1+.
+* ``Fujitsu``: Fujitsu HPC compiler 4.0+.
+* ``PGI``: PGI version 12.10+.
+* ``NVHPC``: NVIDIA HPC compilers version 11.0+.
+* ``TI``: Texas Instruments compiler.
+* ``XL``: IBM XL version 10.1+.
+
+CMake is currently aware of the :prop_tgt:`C standards <C_STANDARD>` and
+their associated meta-features (e.g. ``c_std_99``) available from the
+following :variable:`compiler ids <CMAKE_<LANG>_COMPILER_ID>` as of the
+versions specified for each:
+
+* all compilers and versions listed above with only meta-features for C++.
+
+CMake is currently aware of the :prop_tgt:`CUDA standards <CUDA_STANDARD>` and
+their associated meta-features (e.g. ``cuda_std_11``) available from the
+following :variable:`compiler ids <CMAKE_<LANG>_COMPILER_ID>` as of the
+versions specified for each:
+
+* ``Clang``: Clang compiler 5.0+.
+* ``NVIDIA``: NVIDIA nvcc compiler 7.5+.
diff --git a/Help/manual/cmake-developer.7.rst b/Help/manual/cmake-developer.7.rst
new file mode 100644
index 0000000..fe146de
--- /dev/null
+++ b/Help/manual/cmake-developer.7.rst
@@ -0,0 +1,501 @@
+.. cmake-manual-description: CMake Developer Reference
+
+cmake-developer(7)
+******************
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+This manual is intended for reference by developers working with
+:manual:`cmake-language(7)` code, whether writing their own modules,
+authoring their own build systems, or working on CMake itself.
+
+See https://cmake.org/get-involved/ to get involved in development of
+CMake upstream. It includes links to contribution instructions, which
+in turn link to developer guides for CMake itself.
+
+.. _`Find Modules`:
+
+Find Modules
+============
+
+A "find module" is a ``Find<PackageName>.cmake`` file to be loaded by the
+:command:`find_package` command when invoked for ``<PackageName>``.
+
+The primary task of a find module is to determine whether a package is
+available, set the ``<PackageName>_FOUND`` variable to reflect this and
+provide any variables, macros and imported targets required to use the
+package. A find module is useful in cases where an upstream library does
+not provide a :ref:`config file package <Config File Packages>`.
+
+The traditional approach is to use variables for everything, including
+libraries and executables: see the `Standard Variable Names`_ section
+below. This is what most of the existing find modules provided by CMake
+do.
+
+The more modern approach is to behave as much like
+:ref:`config file packages <Config File Packages>` files as possible, by
+providing :ref:`imported target <Imported targets>`. This has the advantage
+of propagating :ref:`Target Usage Requirements` to consumers.
+
+In either case (or even when providing both variables and imported
+targets), find modules should provide backwards compatibility with old
+versions that had the same name.
+
+A FindFoo.cmake module will typically be loaded by the command::
+
+ find_package(Foo [major[.minor[.patch[.tweak]]]]
+ [EXACT] [QUIET] [REQUIRED]
+ [[COMPONENTS] [components...]]
+ [OPTIONAL_COMPONENTS components...]
+ [NO_POLICY_SCOPE])
+
+See the :command:`find_package` documentation for details on what
+variables are set for the find module. Most of these are dealt with by
+using :module:`FindPackageHandleStandardArgs`.
+
+Briefly, the module should only locate versions of the package
+compatible with the requested version, as described by the
+``Foo_FIND_VERSION`` family of variables. If ``Foo_FIND_QUIETLY`` is
+set to true, it should avoid printing messages, including anything
+complaining about the package not being found. If ``Foo_FIND_REQUIRED``
+is set to true, the module should issue a ``FATAL_ERROR`` if the package
+cannot be found. If neither are set to true, it should print a
+non-fatal message if it cannot find the package.
+
+Packages that find multiple semi-independent parts (like bundles of
+libraries) should search for the components listed in
+``Foo_FIND_COMPONENTS`` if it is set , and only set ``Foo_FOUND`` to
+true if for each searched-for component ``<c>`` that was not found,
+``Foo_FIND_REQUIRED_<c>`` is not set to true. The ``HANDLE_COMPONENTS``
+argument of ``find_package_handle_standard_args()`` can be used to
+implement this.
+
+If ``Foo_FIND_COMPONENTS`` is not set, which modules are searched for
+and required is up to the find module, but should be documented.
+
+For internal implementation, it is a generally accepted convention that
+variables starting with underscore are for temporary use only.
+
+
+.. _`CMake Developer Standard Variable Names`:
+
+Standard Variable Names
+-----------------------
+
+For a ``FindXxx.cmake`` module that takes the approach of setting
+variables (either instead of or in addition to creating imported
+targets), the following variable names should be used to keep things
+consistent between Find modules. Note that all variables start with
+``Xxx_``, which (unless otherwise noted) must match exactly the name
+of the ``FindXxx.cmake`` file, including upper/lowercase.
+This prefix on the variable names ensures that they do not conflict with
+variables of other Find modules. The same pattern should also be followed
+for any macros, functions and imported targets defined by the Find module.
+
+``Xxx_INCLUDE_DIRS``
+ The final set of include directories listed in one variable for use by
+ client code. This should not be a cache entry (note that this also means
+ this variable should not be used as the result variable of a
+ :command:`find_path` command - see ``Xxx_INCLUDE_DIR`` below for that).
+
+``Xxx_LIBRARIES``
+ The libraries to use with the module. These may be CMake targets, full
+ absolute paths to a library binary or the name of a library that the
+ linker must find in its search path. This should not be a cache entry
+ (note that this also means this variable should not be used as the
+ result variable of a :command:`find_library` command - see
+ ``Xxx_LIBRARY`` below for that).
+
+``Xxx_DEFINITIONS``
+ The compile definitions to use when compiling code that uses the module.
+ This really shouldn't include options such as ``-DHAS_JPEG`` that a client
+ source-code file uses to decide whether to ``#include <jpeg.h>``
+
+``Xxx_EXECUTABLE``
+ The full absolute path to an executable. In this case, ``Xxx`` might not
+ be the name of the module, it might be the name of the tool (usually
+ converted to all uppercase), assuming that tool has such a well-known name
+ that it is unlikely that another tool with the same name exists. It would
+ be appropriate to use this as the result variable of a
+ :command:`find_program` command.
+
+``Xxx_YYY_EXECUTABLE``
+ Similar to ``Xxx_EXECUTABLE`` except here the ``Xxx`` is always the module
+ name and ``YYY`` is the tool name (again, usually fully uppercase).
+ Prefer this form if the tool name is not very widely known or has the
+ potential to clash with another tool. For greater consistency, also
+ prefer this form if the module provides more than one executable.
+
+``Xxx_LIBRARY_DIRS``
+ Optionally, the final set of library directories listed in one
+ variable for use by client code. This should not be a cache entry.
+
+``Xxx_ROOT_DIR``
+ Where to find the base directory of the module.
+
+``Xxx_VERSION_VV``
+ Variables of this form specify whether the ``Xxx`` module being provided
+ is version ``VV`` of the module. There should not be more than one
+ variable of this form set to true for a given module. For example, a
+ module ``Barry`` might have evolved over many years and gone through a
+ number of different major versions. Version 3 of the ``Barry`` module
+ might set the variable ``Barry_VERSION_3`` to true, whereas an older
+ version of the module might set ``Barry_VERSION_2`` to true instead.
+ It would be an error for both ``Barry_VERSION_3`` and ``Barry_VERSION_2``
+ to both be set to true.
+
+``Xxx_WRAP_YY``
+ When a variable of this form is set to false, it indicates that the
+ relevant wrapping command should not be used. The wrapping command
+ depends on the module, it may be implied by the module name or it might
+ be specified by the ``YY`` part of the variable.
+
+``Xxx_Yy_FOUND``
+ For variables of this form, ``Yy`` is the name of a component for the
+ module. It should match exactly one of the valid component names that
+ may be passed to the :command:`find_package` command for the module.
+ If a variable of this form is set to false, it means that the ``Yy``
+ component of module ``Xxx`` was not found or is not available.
+ Variables of this form would typically be used for optional components
+ so that the caller can check whether an optional component is available.
+
+``Xxx_FOUND``
+ When the :command:`find_package` command returns to the caller, this
+ variable will be set to true if the module was deemed to have been found
+ successfully.
+
+``Xxx_NOT_FOUND_MESSAGE``
+ Should be set by config-files in the case that it has set
+ ``Xxx_FOUND`` to FALSE. The contained message will be printed by the
+ :command:`find_package` command and by
+ :command:`find_package_handle_standard_args` to inform the user about the
+ problem. Use this instead of calling :command:`message` directly to
+ report a reason for failing to find the module or package.
+
+``Xxx_RUNTIME_LIBRARY_DIRS``
+ Optionally, the runtime library search path for use when running an
+ executable linked to shared libraries. The list should be used by
+ user code to create the ``PATH`` on windows or ``LD_LIBRARY_PATH`` on
+ UNIX. This should not be a cache entry.
+
+``Xxx_VERSION``
+ The full version string of the package found, if any. Note that many
+ existing modules provide ``Xxx_VERSION_STRING`` instead.
+
+``Xxx_VERSION_MAJOR``
+ The major version of the package found, if any.
+
+``Xxx_VERSION_MINOR``
+ The minor version of the package found, if any.
+
+``Xxx_VERSION_PATCH``
+ The patch version of the package found, if any.
+
+The following names should not usually be used in ``CMakeLists.txt`` files.
+They are intended for use by Find modules to specify and cache the locations
+of specific files or directories. Users are typically able to set and edit
+these variables to control the behavior of Find modules (like entering the
+path to a library manually):
+
+``Xxx_LIBRARY``
+ The path of the library. Use this form only when the module provides a
+ single library. It is appropriate to use this as the result variable
+ in a :command:`find_library` command.
+
+``Xxx_Yy_LIBRARY``
+ The path of library ``Yy`` provided by the module ``Xxx``. Use this form
+ when the module provides more than one library or where other modules may
+ also provide a library of the same name. It is also appropriate to use
+ this form as the result variable in a :command:`find_library` command.
+
+``Xxx_INCLUDE_DIR``
+ When the module provides only a single library, this variable can be used
+ to specify where to find headers for using the library (or more accurately,
+ the path that consumers of the library should add to their header search
+ path). It would be appropriate to use this as the result variable in a
+ :command:`find_path` command.
+
+``Xxx_Yy_INCLUDE_DIR``
+ If the module provides more than one library or where other modules may
+ also provide a library of the same name, this form is recommended for
+ specifying where to find headers for using library ``Yy`` provided by
+ the module. Again, it would be appropriate to use this as the result
+ variable in a :command:`find_path` command.
+
+To prevent users being overwhelmed with settings to configure, try to
+keep as many options as possible out of the cache, leaving at least one
+option which can be used to disable use of the module, or locate a
+not-found library (e.g. ``Xxx_ROOT_DIR``). For the same reason, mark
+most cache options as advanced. For packages which provide both debug
+and release binaries, it is common to create cache variables with a
+``_LIBRARY_<CONFIG>`` suffix, such as ``Foo_LIBRARY_RELEASE`` and
+``Foo_LIBRARY_DEBUG``. The :module:`SelectLibraryConfigurations` module
+can be helpful for such cases.
+
+While these are the standard variable names, you should provide
+backwards compatibility for any old names that were actually in use.
+Make sure you comment them as deprecated, so that no-one starts using
+them.
+
+
+A Sample Find Module
+--------------------
+
+We will describe how to create a simple find module for a library ``Foo``.
+
+The top of the module should begin with a license notice, followed by
+a blank line, and then followed by a :ref:`Bracket Comment`. The comment
+should begin with ``.rst:`` to indicate that the rest of its content is
+reStructuredText-format documentation. For example:
+
+::
+
+ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ # file Copyright.txt or https://cmake.org/licensing for details.
+
+ #[=======================================================================[.rst:
+ FindFoo
+ -------
+
+ Finds the Foo library.
+
+ Imported Targets
+ ^^^^^^^^^^^^^^^^
+
+ This module provides the following imported targets, if found:
+
+ ``Foo::Foo``
+ The Foo library
+
+ Result Variables
+ ^^^^^^^^^^^^^^^^
+
+ This will define the following variables:
+
+ ``Foo_FOUND``
+ True if the system has the Foo library.
+ ``Foo_VERSION``
+ The version of the Foo library which was found.
+ ``Foo_INCLUDE_DIRS``
+ Include directories needed to use Foo.
+ ``Foo_LIBRARIES``
+ Libraries needed to link to Foo.
+
+ Cache Variables
+ ^^^^^^^^^^^^^^^
+
+ The following cache variables may also be set:
+
+ ``Foo_INCLUDE_DIR``
+ The directory containing ``foo.h``.
+ ``Foo_LIBRARY``
+ The path to the Foo library.
+
+ #]=======================================================================]
+
+The module documentation consists of:
+
+* An underlined heading specifying the module name.
+
+* A simple description of what the module finds.
+ More description may be required for some packages. If there are
+ caveats or other details users of the module should be aware of,
+ specify them here.
+
+* A section listing imported targets provided by the module, if any.
+
+* A section listing result variables provided by the module.
+
+* Optionally a section listing cache variables used by the module, if any.
+
+If the package provides any macros or functions, they should be listed in
+an additional section, but can be documented by additional ``.rst:``
+comment blocks immediately above where those macros or functions are defined.
+
+The find module implementation may begin below the documentation block.
+Now the actual libraries and so on have to be found. The code here will
+obviously vary from module to module (dealing with that, after all, is the
+point of find modules), but there tends to be a common pattern for libraries.
+
+First, we try to use ``pkg-config`` to find the library. Note that we
+cannot rely on this, as it may not be available, but it provides a good
+starting point.
+
+.. code-block:: cmake
+
+ find_package(PkgConfig)
+ pkg_check_modules(PC_Foo QUIET Foo)
+
+This should define some variables starting ``PC_Foo_`` that contain the
+information from the ``Foo.pc`` file.
+
+Now we need to find the libraries and include files; we use the
+information from ``pkg-config`` to provide hints to CMake about where to
+look.
+
+.. code-block:: cmake
+
+ find_path(Foo_INCLUDE_DIR
+ NAMES foo.h
+ PATHS ${PC_Foo_INCLUDE_DIRS}
+ PATH_SUFFIXES Foo
+ )
+ find_library(Foo_LIBRARY
+ NAMES foo
+ PATHS ${PC_Foo_LIBRARY_DIRS}
+ )
+
+Alternatively, if the library is available with multiple configurations, you can
+use :module:`SelectLibraryConfigurations` to automatically set the
+``Foo_LIBRARY`` variable instead:
+
+.. code-block:: cmake
+
+ find_library(Foo_LIBRARY_RELEASE
+ NAMES foo
+ PATHS ${PC_Foo_LIBRARY_DIRS}/Release
+ )
+ find_library(Foo_LIBRARY_DEBUG
+ NAMES foo
+ PATHS ${PC_Foo_LIBRARY_DIRS}/Debug
+ )
+
+ include(SelectLibraryConfigurations)
+ select_library_configurations(Foo)
+
+If you have a good way of getting the version (from a header file, for
+example), you can use that information to set ``Foo_VERSION`` (although
+note that find modules have traditionally used ``Foo_VERSION_STRING``,
+so you may want to set both). Otherwise, attempt to use the information
+from ``pkg-config``
+
+.. code-block:: cmake
+
+ set(Foo_VERSION ${PC_Foo_VERSION})
+
+Now we can use :module:`FindPackageHandleStandardArgs` to do most of the
+rest of the work for us
+
+.. code-block:: cmake
+
+ include(FindPackageHandleStandardArgs)
+ find_package_handle_standard_args(Foo
+ FOUND_VAR Foo_FOUND
+ REQUIRED_VARS
+ Foo_LIBRARY
+ Foo_INCLUDE_DIR
+ VERSION_VAR Foo_VERSION
+ )
+
+This will check that the ``REQUIRED_VARS`` contain values (that do not
+end in ``-NOTFOUND``) and set ``Foo_FOUND`` appropriately. It will also
+cache those values. If ``Foo_VERSION`` is set, and a required version
+was passed to :command:`find_package`, it will check the requested version
+against the one in ``Foo_VERSION``. It will also print messages as
+appropriate; note that if the package was found, it will print the
+contents of the first required variable to indicate where it was found.
+
+At this point, we have to provide a way for users of the find module to
+link to the library or libraries that were found. There are two
+approaches, as discussed in the `Find Modules`_ section above. The
+traditional variable approach looks like
+
+.. code-block:: cmake
+
+ if(Foo_FOUND)
+ set(Foo_LIBRARIES ${Foo_LIBRARY})
+ set(Foo_INCLUDE_DIRS ${Foo_INCLUDE_DIR})
+ set(Foo_DEFINITIONS ${PC_Foo_CFLAGS_OTHER})
+ endif()
+
+If more than one library was found, all of them should be included in
+these variables (see the `Standard Variable Names`_ section for more
+information).
+
+When providing imported targets, these should be namespaced (hence the
+``Foo::`` prefix); CMake will recognize that values passed to
+:command:`target_link_libraries` that contain ``::`` in their name are
+supposed to be imported targets (rather than just library names), and
+will produce appropriate diagnostic messages if that target does not
+exist (see policy :policy:`CMP0028`).
+
+.. code-block:: cmake
+
+ if(Foo_FOUND AND NOT TARGET Foo::Foo)
+ add_library(Foo::Foo UNKNOWN IMPORTED)
+ set_target_properties(Foo::Foo PROPERTIES
+ IMPORTED_LOCATION "${Foo_LIBRARY}"
+ INTERFACE_COMPILE_OPTIONS "${PC_Foo_CFLAGS_OTHER}"
+ INTERFACE_INCLUDE_DIRECTORIES "${Foo_INCLUDE_DIR}"
+ )
+ endif()
+
+One thing to note about this is that the ``INTERFACE_INCLUDE_DIRECTORIES`` and
+similar properties should only contain information about the target itself, and
+not any of its dependencies. Instead, those dependencies should also be
+targets, and CMake should be told that they are dependencies of this target.
+CMake will then combine all the necessary information automatically.
+
+The type of the :prop_tgt:`IMPORTED` target created in the
+:command:`add_library` command can always be specified as ``UNKNOWN``
+type. This simplifies the code in cases where static or shared variants may
+be found, and CMake will determine the type by inspecting the files.
+
+If the library is available with multiple configurations, the
+:prop_tgt:`IMPORTED_CONFIGURATIONS` target property should also be
+populated:
+
+.. code-block:: cmake
+
+ if(Foo_FOUND)
+ if (NOT TARGET Foo::Foo)
+ add_library(Foo::Foo UNKNOWN IMPORTED)
+ endif()
+ if (Foo_LIBRARY_RELEASE)
+ set_property(TARGET Foo::Foo APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE
+ )
+ set_target_properties(Foo::Foo PROPERTIES
+ IMPORTED_LOCATION_RELEASE "${Foo_LIBRARY_RELEASE}"
+ )
+ endif()
+ if (Foo_LIBRARY_DEBUG)
+ set_property(TARGET Foo::Foo APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG
+ )
+ set_target_properties(Foo::Foo PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${Foo_LIBRARY_DEBUG}"
+ )
+ endif()
+ set_target_properties(Foo::Foo PROPERTIES
+ INTERFACE_COMPILE_OPTIONS "${PC_Foo_CFLAGS_OTHER}"
+ INTERFACE_INCLUDE_DIRECTORIES "${Foo_INCLUDE_DIR}"
+ )
+ endif()
+
+The ``RELEASE`` variant should be listed first in the property
+so that the variant is chosen if the user uses a configuration which is
+not an exact match for any listed ``IMPORTED_CONFIGURATIONS``.
+
+Most of the cache variables should be hidden in the ``ccmake`` interface unless
+the user explicitly asks to edit them.
+
+.. code-block:: cmake
+
+ mark_as_advanced(
+ Foo_INCLUDE_DIR
+ Foo_LIBRARY
+ )
+
+If this module replaces an older version, you should set compatibility variables
+to cause the least disruption possible.
+
+.. code-block:: cmake
+
+ # compatibility variables
+ set(Foo_VERSION_STRING ${Foo_VERSION})
diff --git a/Help/manual/cmake-env-variables.7.rst b/Help/manual/cmake-env-variables.7.rst
new file mode 100644
index 0000000..bc1fa1d
--- /dev/null
+++ b/Help/manual/cmake-env-variables.7.rst
@@ -0,0 +1,96 @@
+.. cmake-manual-description: CMake Environment Variables Reference
+
+cmake-env-variables(7)
+**********************
+
+.. only:: html
+
+ .. contents::
+
+This page lists environment variables that have special
+meaning to CMake.
+
+For general information on environment variables, see the
+:ref:`Environment Variables <CMake Language Environment Variables>`
+section in the cmake-language manual.
+
+Environment Variables that Change Behavior
+==========================================
+
+.. toctree::
+ :maxdepth: 1
+
+ /envvar/CMAKE_PREFIX_PATH
+
+Environment Variables that Control the Build
+============================================
+
+.. toctree::
+ :maxdepth: 1
+
+ /envvar/CMAKE_APPLE_SILICON_PROCESSOR
+ /envvar/CMAKE_BUILD_PARALLEL_LEVEL
+ /envvar/CMAKE_CONFIG_TYPE
+ /envvar/CMAKE_EXPORT_COMPILE_COMMANDS
+ /envvar/CMAKE_GENERATOR
+ /envvar/CMAKE_GENERATOR_INSTANCE
+ /envvar/CMAKE_GENERATOR_PLATFORM
+ /envvar/CMAKE_GENERATOR_TOOLSET
+ /envvar/CMAKE_LANG_COMPILER_LAUNCHER
+ /envvar/CMAKE_MSVCIDE_RUN_PATH
+ /envvar/CMAKE_NO_VERBOSE
+ /envvar/CMAKE_OSX_ARCHITECTURES
+ /envvar/DESTDIR
+ /envvar/LDFLAGS
+ /envvar/MACOSX_DEPLOYMENT_TARGET
+ /envvar/PackageName_ROOT
+ /envvar/VERBOSE
+
+Environment Variables for Languages
+===================================
+
+.. toctree::
+ :maxdepth: 1
+
+ /envvar/ASM_DIALECT
+ /envvar/ASM_DIALECTFLAGS
+ /envvar/CC
+ /envvar/CFLAGS
+ /envvar/CSFLAGS
+ /envvar/CUDAARCHS
+ /envvar/CUDACXX
+ /envvar/CUDAFLAGS
+ /envvar/CUDAHOSTCXX
+ /envvar/CXX
+ /envvar/CXXFLAGS
+ /envvar/FC
+ /envvar/FFLAGS
+ /envvar/ISPC
+ /envvar/ISPCFLAGS
+ /envvar/OBJC
+ /envvar/OBJCXX
+ /envvar/RC
+ /envvar/RCFLAGS
+ /envvar/SWIFTC
+
+Environment Variables for CTest
+===============================
+
+.. toctree::
+ :maxdepth: 1
+
+ /envvar/CMAKE_CONFIG_TYPE
+ /envvar/CTEST_INTERACTIVE_DEBUG_MODE
+ /envvar/CTEST_OUTPUT_ON_FAILURE
+ /envvar/CTEST_PARALLEL_LEVEL
+ /envvar/CTEST_PROGRESS_OUTPUT
+ /envvar/CTEST_USE_LAUNCHERS_DEFAULT
+ /envvar/DASHBOARD_TEST_FROM_CTEST
+
+Environment Variables for the CMake curses interface
+====================================================
+
+.. toctree::
+ :maxdepth: 1
+
+ /envvar/CCMAKE_COLORS
diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
new file mode 100644
index 0000000..cbc3d6d
--- /dev/null
+++ b/Help/manual/cmake-file-api.7.rst
@@ -0,0 +1,1506 @@
+.. cmake-manual-description: CMake File-Based API
+
+cmake-file-api(7)
+*****************
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+CMake provides a file-based API that clients may use to get semantic
+information about the buildsystems CMake generates. Clients may use
+the API by writing query files to a specific location in a build tree
+to request zero or more `Object Kinds`_. When CMake generates the
+buildsystem in that build tree it will read the query files and write
+reply files for the client to read.
+
+The file-based API uses a ``<build>/.cmake/api/`` directory at the top
+of a build tree. The API is versioned to support changes to the layout
+of files within the API directory. API file layout versioning is
+orthogonal to the versioning of `Object Kinds`_ used in replies.
+This version of CMake supports only one API version, `API v1`_.
+
+API v1
+======
+
+API v1 is housed in the ``<build>/.cmake/api/v1/`` directory.
+It has the following subdirectories:
+
+``query/``
+ Holds query files written by clients.
+ These may be `v1 Shared Stateless Query Files`_,
+ `v1 Client Stateless Query Files`_, or `v1 Client Stateful Query Files`_.
+
+``reply/``
+ Holds reply files written by CMake whenever it runs to generate a build
+ system. These are indexed by a `v1 Reply Index File`_ file that may
+ reference additional `v1 Reply Files`_. CMake owns all reply files.
+ Clients must never remove them.
+
+ Clients may look for and read a reply index file at any time.
+ Clients may optionally create the ``reply/`` directory at any time
+ and monitor it for the appearance of a new reply index file.
+
+v1 Shared Stateless Query Files
+-------------------------------
+
+Shared stateless query files allow clients to share requests for
+major versions of the `Object Kinds`_ and get all requested versions
+recognized by the CMake that runs.
+
+Clients may create shared requests by creating empty files in the
+``v1/query/`` directory. The form is::
+
+ <build>/.cmake/api/v1/query/<kind>-v<major>
+
+where ``<kind>`` is one of the `Object Kinds`_, ``-v`` is literal,
+and ``<major>`` is the major version number.
+
+Files of this form are stateless shared queries not owned by any specific
+client. Once created they should not be removed without external client
+coordination or human intervention.
+
+v1 Client Stateless Query Files
+-------------------------------
+
+Client stateless query files allow clients to create owned requests for
+major versions of the `Object Kinds`_ and get all requested versions
+recognized by the CMake that runs.
+
+Clients may create owned requests by creating empty files in
+client-specific query subdirectories. The form is::
+
+ <build>/.cmake/api/v1/query/client-<client>/<kind>-v<major>
+
+where ``client-`` is literal, ``<client>`` is a string uniquely
+identifying the client, ``<kind>`` is one of the `Object Kinds`_,
+``-v`` is literal, and ``<major>`` is the major version number.
+Each client must choose a unique ``<client>`` identifier via its
+own means.
+
+Files of this form are stateless queries owned by the client ``<client>``.
+The owning client may remove them at any time.
+
+v1 Client Stateful Query Files
+------------------------------
+
+Stateful query files allow clients to request a list of versions of
+each of the `Object Kinds`_ and get only the most recent version
+recognized by the CMake that runs.
+
+Clients may create owned stateful queries by creating ``query.json``
+files in client-specific query subdirectories. The form is::
+
+ <build>/.cmake/api/v1/query/client-<client>/query.json
+
+where ``client-`` is literal, ``<client>`` is a string uniquely
+identifying the client, and ``query.json`` is literal. Each client
+must choose a unique ``<client>`` identifier via its own means.
+
+``query.json`` files are stateful queries owned by the client ``<client>``.
+The owning client may update or remove them at any time. When a
+given client installation is updated it may then update the stateful
+query it writes to build trees to request newer object versions.
+This can be used to avoid asking CMake to generate multiple object
+versions unnecessarily.
+
+A ``query.json`` file must contain a JSON object:
+
+.. code-block:: json
+
+ {
+ "requests": [
+ { "kind": "<kind>" , "version": 1 },
+ { "kind": "<kind>" , "version": { "major": 1, "minor": 2 } },
+ { "kind": "<kind>" , "version": [2, 1] },
+ { "kind": "<kind>" , "version": [2, { "major": 1, "minor": 2 }] },
+ { "kind": "<kind>" , "version": 1, "client": {} },
+ { "kind": "..." }
+ ],
+ "client": {}
+ }
+
+The members are:
+
+``requests``
+ A JSON array containing zero or more requests. Each request is
+ a JSON object with members:
+
+ ``kind``
+ Specifies one of the `Object Kinds`_ to be included in the reply.
+
+ ``version``
+ Indicates the version(s) of the object kind that the client
+ understands. Versions have major and minor components following
+ semantic version conventions. The value must be
+
+ * a JSON integer specifying a (non-negative) major version number, or
+ * a JSON object containing ``major`` and (optionally) ``minor``
+ members specifying non-negative integer version components, or
+ * a JSON array whose elements are each one of the above.
+
+ ``client``
+ Optional member reserved for use by the client. This value is
+ preserved in the reply written for the client in the
+ `v1 Reply Index File`_ but is otherwise ignored. Clients may use
+ this to pass custom information with a request through to its reply.
+
+ For each requested object kind CMake will choose the *first* version
+ that it recognizes for that kind among those listed in the request.
+ The response will use the selected *major* version with the highest
+ *minor* version known to the running CMake for that major version.
+ Therefore clients should list all supported major versions in
+ preferred order along with the minimal minor version required
+ for each major version.
+
+``client``
+ Optional member reserved for use by the client. This value is
+ preserved in the reply written for the client in the
+ `v1 Reply Index File`_ but is otherwise ignored. Clients may use
+ this to pass custom information with a query through to its reply.
+
+Other ``query.json`` top-level members are reserved for future use.
+If present they are ignored for forward compatibility.
+
+v1 Reply Index File
+-------------------
+
+CMake writes an ``index-*.json`` file to the ``v1/reply/`` directory
+whenever it runs to generate a build system. Clients must read the
+reply index file first and may read other `v1 Reply Files`_ only by
+following references. The form of the reply index file name is::
+
+ <build>/.cmake/api/v1/reply/index-<unspecified>.json
+
+where ``index-`` is literal and ``<unspecified>`` is an unspecified
+name selected by CMake. Whenever a new index file is generated it
+is given a new name and any old one is deleted. During the short
+time between these steps there may be multiple index files present;
+the one with the largest name in lexicographic order is the current
+index file.
+
+The reply index file contains a JSON object:
+
+.. code-block:: json
+
+ {
+ "cmake": {
+ "version": {
+ "major": 3, "minor": 14, "patch": 0, "suffix": "",
+ "string": "3.14.0", "isDirty": false
+ },
+ "paths": {
+ "cmake": "/prefix/bin/cmake",
+ "ctest": "/prefix/bin/ctest",
+ "cpack": "/prefix/bin/cpack",
+ "root": "/prefix/share/cmake-3.14"
+ },
+ "generator": {
+ "multiConfig": false,
+ "name": "Unix Makefiles"
+ }
+ },
+ "objects": [
+ { "kind": "<kind>",
+ "version": { "major": 1, "minor": 0 },
+ "jsonFile": "<file>" },
+ { "...": "..." }
+ ],
+ "reply": {
+ "<kind>-v<major>": { "kind": "<kind>",
+ "version": { "major": 1, "minor": 0 },
+ "jsonFile": "<file>" },
+ "<unknown>": { "error": "unknown query file" },
+ "...": {},
+ "client-<client>": {
+ "<kind>-v<major>": { "kind": "<kind>",
+ "version": { "major": 1, "minor": 0 },
+ "jsonFile": "<file>" },
+ "<unknown>": { "error": "unknown query file" },
+ "...": {},
+ "query.json": {
+ "requests": [ {}, {}, {} ],
+ "responses": [
+ { "kind": "<kind>",
+ "version": { "major": 1, "minor": 0 },
+ "jsonFile": "<file>" },
+ { "error": "unknown query file" },
+ { "...": {} }
+ ],
+ "client": {}
+ }
+ }
+ }
+ }
+
+The members are:
+
+``cmake``
+ A JSON object containing information about the instance of CMake that
+ generated the reply. It contains members:
+
+ ``version``
+ A JSON object specifying the version of CMake with members:
+
+ ``major``, ``minor``, ``patch``
+ Integer values specifying the major, minor, and patch version components.
+ ``suffix``
+ A string specifying the version suffix, if any, e.g. ``g0abc3``.
+ ``string``
+ A string specifying the full version in the format
+ ``<major>.<minor>.<patch>[-<suffix>]``.
+ ``isDirty``
+ A boolean indicating whether the version was built from a version
+ controlled source tree with local modifications.
+
+ ``paths``
+ A JSON object specifying paths to things that come with CMake.
+ It has members for ``cmake``, ``ctest``, and ``cpack`` whose values
+ are JSON strings specifying the absolute path to each tool,
+ represented with forward slashes. It also has a ``root`` member for
+ the absolute path to the directory containing CMake resources like the
+ ``Modules/`` directory (see :variable:`CMAKE_ROOT`).
+
+ ``generator``
+ A JSON object describing the CMake generator used for the build.
+ It has members:
+
+ ``multiConfig``
+ A boolean specifying whether the generator supports multiple output
+ configurations.
+ ``name``
+ A string specifying the name of the generator.
+ ``platform``
+ If the generator supports :variable:`CMAKE_GENERATOR_PLATFORM`,
+ this is a string specifying the generator platform name.
+
+``objects``
+ A JSON array listing all versions of all `Object Kinds`_ generated
+ as part of the reply. Each array entry is a
+ `v1 Reply File Reference`_.
+
+``reply``
+ A JSON object mirroring the content of the ``query/`` directory
+ that CMake loaded to produce the reply. The members are of the form
+
+ ``<kind>-v<major>``
+ A member of this form appears for each of the
+ `v1 Shared Stateless Query Files`_ that CMake recognized as a
+ request for object kind ``<kind>`` with major version ``<major>``.
+ The value is a `v1 Reply File Reference`_ to the corresponding
+ reply file for that object kind and version.
+
+ ``<unknown>``
+ A member of this form appears for each of the
+ `v1 Shared Stateless Query Files`_ that CMake did not recognize.
+ The value is a JSON object with a single ``error`` member
+ containing a string with an error message indicating that the
+ query file is unknown.
+
+ ``client-<client>``
+ A member of this form appears for each client-owned directory
+ holding `v1 Client Stateless Query Files`_.
+ The value is a JSON object mirroring the content of the
+ ``query/client-<client>/`` directory. The members are of the form:
+
+ ``<kind>-v<major>``
+ A member of this form appears for each of the
+ `v1 Client Stateless Query Files`_ that CMake recognized as a
+ request for object kind ``<kind>`` with major version ``<major>``.
+ The value is a `v1 Reply File Reference`_ to the corresponding
+ reply file for that object kind and version.
+
+ ``<unknown>``
+ A member of this form appears for each of the
+ `v1 Client Stateless Query Files`_ that CMake did not recognize.
+ The value is a JSON object with a single ``error`` member
+ containing a string with an error message indicating that the
+ query file is unknown.
+
+ ``query.json``
+ This member appears for clients using
+ `v1 Client Stateful Query Files`_.
+ If the ``query.json`` file failed to read or parse as a JSON object,
+ this member is a JSON object with a single ``error`` member
+ containing a string with an error message. Otherwise, this member
+ is a JSON object mirroring the content of the ``query.json`` file.
+ The members are:
+
+ ``client``
+ A copy of the ``query.json`` file ``client`` member, if it exists.
+
+ ``requests``
+ A copy of the ``query.json`` file ``requests`` member, if it exists.
+
+ ``responses``
+ If the ``query.json`` file ``requests`` member is missing or invalid,
+ this member is a JSON object with a single ``error`` member
+ containing a string with an error message. Otherwise, this member
+ contains a JSON array with a response for each entry of the
+ ``requests`` array, in the same order. Each response is
+
+ * a JSON object with a single ``error`` member containing a string
+ with an error message, or
+ * a `v1 Reply File Reference`_ to the corresponding reply file for
+ the requested object kind and selected version.
+
+After reading the reply index file, clients may read the other
+`v1 Reply Files`_ it references.
+
+v1 Reply File Reference
+^^^^^^^^^^^^^^^^^^^^^^^
+
+The reply index file represents each reference to another reply file
+using a JSON object with members:
+
+``kind``
+ A string specifying one of the `Object Kinds`_.
+``version``
+ A JSON object with members ``major`` and ``minor`` specifying
+ integer version components of the object kind.
+``jsonFile``
+ A JSON string specifying a path relative to the reply index file
+ to another JSON file containing the object.
+
+v1 Reply Files
+--------------
+
+Reply files containing specific `Object Kinds`_ are written by CMake.
+The names of these files are unspecified and must not be interpreted
+by clients. Clients must first read the `v1 Reply Index File`_ and
+and follow references to the names of the desired response objects.
+
+Reply files (including the index file) will never be replaced by
+files of the same name but different content. This allows a client
+to read the files concurrently with a running CMake that may generate
+a new reply. However, after generating a new reply CMake will attempt
+to remove reply files from previous runs that it did not just write.
+If a client attempts to read a reply file referenced by the index but
+finds the file missing, that means a concurrent CMake has generated
+a new reply. The client may simply start again by reading the new
+reply index file.
+
+.. _`file-api object kinds`:
+
+Object Kinds
+============
+
+The CMake file-based API reports semantic information about the build
+system using the following kinds of JSON objects. Each kind of object
+is versioned independently using semantic versioning with major and
+minor components. Every kind of object has the form:
+
+.. code-block:: json
+
+ {
+ "kind": "<kind>",
+ "version": { "major": 1, "minor": 0 },
+ "...": {}
+ }
+
+The ``kind`` member is a string specifying the object kind name.
+The ``version`` member is a JSON object with ``major`` and ``minor``
+members specifying integer components of the object kind's version.
+Additional top-level members are specific to each object kind.
+
+Object Kind "codemodel"
+-----------------------
+
+The ``codemodel`` object kind describes the build system structure as
+modeled by CMake.
+
+There is only one ``codemodel`` object major version, version 2.
+Version 1 does not exist to avoid confusion with that from
+:manual:`cmake-server(7)` mode.
+
+"codemodel" version 2
+^^^^^^^^^^^^^^^^^^^^^
+
+``codemodel`` object version 2 is a JSON object:
+
+.. code-block:: json
+
+ {
+ "kind": "codemodel",
+ "version": { "major": 2, "minor": 2 },
+ "paths": {
+ "source": "/path/to/top-level-source-dir",
+ "build": "/path/to/top-level-build-dir"
+ },
+ "configurations": [
+ {
+ "name": "Debug",
+ "directories": [
+ {
+ "source": ".",
+ "build": ".",
+ "childIndexes": [ 1 ],
+ "projectIndex": 0,
+ "targetIndexes": [ 0 ],
+ "hasInstallRule": true,
+ "minimumCMakeVersion": {
+ "string": "3.14"
+ },
+ "jsonFile": "<file>"
+ },
+ {
+ "source": "sub",
+ "build": "sub",
+ "parentIndex": 0,
+ "projectIndex": 0,
+ "targetIndexes": [ 1 ],
+ "minimumCMakeVersion": {
+ "string": "3.14"
+ },
+ "jsonFile": "<file>"
+ }
+ ],
+ "projects": [
+ {
+ "name": "MyProject",
+ "directoryIndexes": [ 0, 1 ],
+ "targetIndexes": [ 0, 1 ]
+ }
+ ],
+ "targets": [
+ {
+ "name": "MyExecutable",
+ "directoryIndex": 0,
+ "projectIndex": 0,
+ "jsonFile": "<file>"
+ },
+ {
+ "name": "MyLibrary",
+ "directoryIndex": 1,
+ "projectIndex": 0,
+ "jsonFile": "<file>"
+ }
+ ]
+ }
+ ]
+ }
+
+The members specific to ``codemodel`` objects are:
+
+``paths``
+ A JSON object containing members:
+
+ ``source``
+ A string specifying the absolute path to the top-level source directory,
+ represented with forward slashes.
+
+ ``build``
+ A string specifying the absolute path to the top-level build directory,
+ represented with forward slashes.
+
+``configurations``
+ A JSON array of entries corresponding to available build configurations.
+ On single-configuration generators there is one entry for the value
+ of the :variable:`CMAKE_BUILD_TYPE` variable. For multi-configuration
+ generators there is an entry for each configuration listed in the
+ :variable:`CMAKE_CONFIGURATION_TYPES` variable.
+ Each entry is a JSON object containing members:
+
+ ``name``
+ A string specifying the name of the configuration, e.g. ``Debug``.
+
+ ``directories``
+ A JSON array of entries each corresponding to a build system directory
+ whose source directory contains a ``CMakeLists.txt`` file. The first
+ entry corresponds to the top-level directory. Each entry is a
+ JSON object containing members:
+
+ ``source``
+ A string specifying the path to the source directory, represented
+ with forward slashes. If the directory is inside the top-level
+ source directory then the path is specified relative to that
+ directory (with ``.`` for the top-level source directory itself).
+ Otherwise the path is absolute.
+
+ ``build``
+ A string specifying the path to the build directory, represented
+ with forward slashes. If the directory is inside the top-level
+ build directory then the path is specified relative to that
+ directory (with ``.`` for the top-level build directory itself).
+ Otherwise the path is absolute.
+
+ ``parentIndex``
+ Optional member that is present when the directory is not top-level.
+ The value is an unsigned integer 0-based index of another entry in
+ the main ``directories`` array that corresponds to the parent
+ directory that added this directory as a subdirectory.
+
+ ``childIndexes``
+ Optional member that is present when the directory has subdirectories.
+ The value is a JSON array of entries corresponding to child directories
+ created by the :command:`add_subdirectory` or :command:`subdirs`
+ command. Each entry is an unsigned integer 0-based index of another
+ entry in the main ``directories`` array.
+
+ ``projectIndex``
+ An unsigned integer 0-based index into the main ``projects`` array
+ indicating the build system project to which the this directory belongs.
+
+ ``targetIndexes``
+ Optional member that is present when the directory itself has targets,
+ excluding those belonging to subdirectories. The value is a JSON
+ array of entries corresponding to the targets. Each entry is an
+ unsigned integer 0-based index into the main ``targets`` array.
+
+ ``minimumCMakeVersion``
+ Optional member present when a minimum required version of CMake is
+ known for the directory. This is the ``<min>`` version given to the
+ most local call to the :command:`cmake_minimum_required(VERSION)`
+ command in the directory itself or one of its ancestors.
+ The value is a JSON object with one member:
+
+ ``string``
+ A string specifying the minimum required version in the format::
+
+ <major>.<minor>[.<patch>[.<tweak>]][<suffix>]
+
+ Each component is an unsigned integer and the suffix may be an
+ arbitrary string.
+
+ ``hasInstallRule``
+ Optional member that is present with boolean value ``true`` when
+ the directory or one of its subdirectories contains any
+ :command:`install` rules, i.e. whether a ``make install``
+ or equivalent rule is available.
+
+ ``jsonFile``
+ A JSON string specifying a path relative to the codemodel file
+ to another JSON file containing a
+ `"codemodel" version 2 "directory" object`_.
+
+ This field was added in codemodel version 2.3.
+
+ ``projects``
+ A JSON array of entries corresponding to the top-level project
+ and sub-projects defined in the build system. Each (sub-)project
+ corresponds to a source directory whose ``CMakeLists.txt`` file
+ calls the :command:`project` command with a project name different
+ from its parent directory. The first entry corresponds to the
+ top-level project.
+
+ Each entry is a JSON object containing members:
+
+ ``name``
+ A string specifying the name given to the :command:`project` command.
+
+ ``parentIndex``
+ Optional member that is present when the project is not top-level.
+ The value is an unsigned integer 0-based index of another entry in
+ the main ``projects`` array that corresponds to the parent project
+ that added this project as a sub-project.
+
+ ``childIndexes``
+ Optional member that is present when the project has sub-projects.
+ The value is a JSON array of entries corresponding to the sub-projects.
+ Each entry is an unsigned integer 0-based index of another
+ entry in the main ``projects`` array.
+
+ ``directoryIndexes``
+ A JSON array of entries corresponding to build system directories
+ that are part of the project. The first entry corresponds to the
+ top-level directory of the project. Each entry is an unsigned
+ integer 0-based index into the main ``directories`` array.
+
+ ``targetIndexes``
+ Optional member that is present when the project itself has targets,
+ excluding those belonging to sub-projects. The value is a JSON
+ array of entries corresponding to the targets. Each entry is an
+ unsigned integer 0-based index into the main ``targets`` array.
+
+ ``targets``
+ A JSON array of entries corresponding to the build system targets.
+ Such targets are created by calls to :command:`add_executable`,
+ :command:`add_library`, and :command:`add_custom_target`, excluding
+ imported targets and interface libraries (which do not generate any
+ build rules). Each entry is a JSON object containing members:
+
+ ``name``
+ A string specifying the target name.
+
+ ``id``
+ A string uniquely identifying the target. This matches the ``id``
+ field in the file referenced by ``jsonFile``.
+
+ ``directoryIndex``
+ An unsigned integer 0-based index into the main ``directories`` array
+ indicating the build system directory in which the target is defined.
+
+ ``projectIndex``
+ An unsigned integer 0-based index into the main ``projects`` array
+ indicating the build system project in which the target is defined.
+
+ ``jsonFile``
+ A JSON string specifying a path relative to the codemodel file
+ to another JSON file containing a
+ `"codemodel" version 2 "target" object`_.
+
+"codemodel" version 2 "directory" object
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A codemodel "directory" object is referenced by a `"codemodel" version 2`_
+object's ``directories`` array. Each "directory" object is a JSON object
+with members:
+
+``paths``
+ A JSON object containing members:
+
+ ``source``
+ A string specifying the path to the source directory, represented
+ with forward slashes. If the directory is inside the top-level
+ source directory then the path is specified relative to that
+ directory (with ``.`` for the top-level source directory itself).
+ Otherwise the path is absolute.
+
+ ``build``
+ A string specifying the path to the build directory, represented
+ with forward slashes. If the directory is inside the top-level
+ build directory then the path is specified relative to that
+ directory (with ``.`` for the top-level build directory itself).
+ Otherwise the path is absolute.
+
+``installers``
+ A JSON array of entries corresponding to :command:`install` rules.
+ Each entry is a JSON object containing members:
+
+ ``component``
+ A string specifying the component selected by the corresponding
+ :command:`install` command invocation.
+
+ ``destination``
+ Optional member that is present for specific ``type`` values below.
+ The value is a string specifying the install destination path.
+ The path may be absolute or relative to the install prefix.
+
+ ``paths``
+ Optional member that is present for specific ``type`` values below.
+ The value is a JSON array of entries corresponding to the paths
+ (files or directories) to be installed. Each entry is one of:
+
+ * A string specifying the path from which a file or directory
+ is to be installed. The portion of the path not preceded by
+ a ``/`` also specifies the path (name) to which the file
+ or directory is to be installed under the destination.
+
+ * A JSON object with members:
+
+ ``from``
+ A string specifying the path from which a file or directory
+ is to be installed.
+
+ ``to``
+ A string specifying the path to which the file or directory
+ is to be installed under the destination.
+
+ In both cases the paths are represented with forward slashes. If
+ the "from" path is inside the top-level directory documented by the
+ corresponding ``type`` value, then the path is specified relative
+ to that directory. Otherwise the path is absolute.
+
+ ``type``
+ A string specifying the type of installation rule. The value is one
+ of the following, with some variants providing additional members:
+
+ ``file``
+ An :command:`install(FILES)` or :command:`install(PROGRAMS)` call.
+ The ``destination`` and ``paths`` members are populated, with paths
+ under the top-level *source* directory expressed relative to it.
+ The ``isOptional`` member may exist.
+ This type has no additional members.
+
+ ``directory``
+ An :command:`install(DIRECTORY)` call.
+ The ``destination`` and ``paths`` members are populated, with paths
+ under the top-level *source* directory expressed relative to it.
+ The ``isOptional`` member may exist.
+ This type has no additional members.
+
+ ``target``
+ An :command:`install(TARGETS)` call.
+ The ``destination`` and ``paths`` members are populated, with paths
+ under the top-level *build* directory expressed relative to it.
+ The ``isOptional`` member may exist.
+ This type has additional members ``targetId``, ``targetIndex``,
+ ``targetIsImportLibrary``, and ``targetInstallNamelink``.
+
+ ``export``
+ An :command:`install(EXPORT)` call.
+ The ``destination`` and ``paths`` members are populated, with paths
+ under the top-level *build* directory expressed relative to it.
+ The ``paths`` entries refer to files generated automatically by
+ CMake for installation, and their actual values are considered
+ private implementation details.
+ This type has additional members ``exportName`` and ``exportTargets``.
+
+ ``script``
+ An :command:`install(SCRIPT)` call.
+ This type has additional member ``scriptFile``.
+
+ ``code``
+ An :command:`install(CODE)` call.
+ This type has no additional members.
+
+ ``isExcludeFromAll``
+ Optional member that is present with boolean value ``true`` when
+ :command:`install` is called with the ``EXCLUDE_FROM_ALL`` option.
+
+ ``isOptional``
+ Optional member that is present with boolean value ``true`` when
+ :command:`install` is called with the ``OPTIONAL`` option.
+ This is allowed when ``type`` is ``file``, ``directory``, or ``target``.
+
+ ``targetId``
+ Optional member that is present when ``type`` is ``target``.
+ The value is a string uniquely identifying the target to be installed.
+ This matches the ``id`` member of the target in the main
+ "codemodel" object's ``targets`` array.
+
+ ``targetIndex``
+ Optional member that is present when ``type`` is ``target``.
+ The value is an unsigned integer 0-based index into the main "codemodel"
+ object's ``targets`` array for the target to be installed.
+
+ ``targetIsImportLibrary``
+ Optional member that is present when ``type`` is ``target`` and
+ the installer is for a Windows DLL import library file or for an
+ AIX linker import file. If present, it has boolean value ``true``.
+
+ ``targetInstallNamelink``
+ Optional member that is present when ``type`` is ``target`` and
+ the installer corresponds to a target that may use symbolic links
+ to implement the :prop_tgt:`VERSION` and :prop_tgt:`SOVERSION`
+ target properties.
+ The value is a string indicating how the installer is supposed to
+ handle the symlinks: ``skip`` means the installer should skip the
+ symlinks and install only the real file, and ``only`` means the
+ installer should install only the symlinks and not the real file.
+ In all cases the ``paths`` member lists what it actually installs.
+
+ ``exportName``
+ Optional member that is present when ``type`` is ``export``.
+ The value is a string specifying the name of the export.
+
+ ``exportTargets``
+ Optional member that is present when ``type`` is ``export``.
+ The value is a JSON array of entries corresponding to the targets
+ included in the export. Each entry is a JSON object with members:
+
+ ``id``
+ A string uniquely identifying the target. This matches
+ the ``id`` member of the target in the main "codemodel"
+ object's ``targets`` array.
+
+ ``index``
+ An unsigned integer 0-based index into the main "codemodel"
+ object's ``targets`` array for the target.
+
+ ``scriptFile``
+ Optional member that is present when ``type`` is ``script``.
+ The value is a string specifying the path to the script file on disk,
+ represented with forward slashes. If the file is inside the top-level
+ source directory then the path is specified relative to that directory.
+ Otherwise the path is absolute.
+
+ ``backtrace``
+ Optional member that is present when a CMake language backtrace to
+ the :command:`install` or other command invocation that added this
+ installer is available. The value is an unsigned integer 0-based
+ index into the ``backtraceGraph`` member's ``nodes`` array.
+
+``backtraceGraph``
+ A `"codemodel" version 2 "backtrace graph"`_ whose nodes are referenced
+ from ``backtrace`` members elsewhere in this "directory" object.
+
+"codemodel" version 2 "target" object
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A codemodel "target" object is referenced by a `"codemodel" version 2`_
+object's ``targets`` array. Each "target" object is a JSON object
+with members:
+
+``name``
+ A string specifying the logical name of the target.
+
+``id``
+ A string uniquely identifying the target. The format is unspecified
+ and should not be interpreted by clients.
+
+``type``
+ A string specifying the type of the target. The value is one of
+ ``EXECUTABLE``, ``STATIC_LIBRARY``, ``SHARED_LIBRARY``,
+ ``MODULE_LIBRARY``, ``OBJECT_LIBRARY``, ``INTERFACE_LIBRARY``,
+ or ``UTILITY``.
+
+``backtrace``
+ Optional member that is present when a CMake language backtrace to
+ the command in the source code that created the target is available.
+ The value is an unsigned integer 0-based index into the
+ ``backtraceGraph`` member's ``nodes`` array.
+
+``folder``
+ Optional member that is present when the :prop_tgt:`FOLDER` target
+ property is set. The value is a JSON object with one member:
+
+ ``name``
+ A string specifying the name of the target folder.
+
+``paths``
+ A JSON object containing members:
+
+ ``source``
+ A string specifying the path to the target's source directory,
+ represented with forward slashes. If the directory is inside the
+ top-level source directory then the path is specified relative to
+ that directory (with ``.`` for the top-level source directory itself).
+ Otherwise the path is absolute.
+
+ ``build``
+ A string specifying the path to the target's build directory,
+ represented with forward slashes. If the directory is inside the
+ top-level build directory then the path is specified relative to
+ that directory (with ``.`` for the top-level build directory itself).
+ Otherwise the path is absolute.
+
+``nameOnDisk``
+ Optional member that is present for executable and library targets
+ that are linked or archived into a single primary artifact.
+ The value is a string specifying the file name of that artifact on disk.
+
+``artifacts``
+ Optional member that is present for executable and library targets
+ that produce artifacts on disk meant for consumption by dependents.
+ The value is a JSON array of entries corresponding to the artifacts.
+ Each entry is a JSON object containing one member:
+
+ ``path``
+ A string specifying the path to the file on disk, represented with
+ forward slashes. If the file is inside the top-level build directory
+ then the path is specified relative to that directory.
+ Otherwise the path is absolute.
+
+``isGeneratorProvided``
+ Optional member that is present with boolean value ``true`` if the
+ target is provided by CMake's build system generator rather than by
+ a command in the source code.
+
+``install``
+ Optional member that is present when the target has an :command:`install`
+ rule. The value is a JSON object with members:
+
+ ``prefix``
+ A JSON object specifying the installation prefix. It has one member:
+
+ ``path``
+ A string specifying the value of :variable:`CMAKE_INSTALL_PREFIX`.
+
+ ``destinations``
+ A JSON array of entries specifying an install destination path.
+ Each entry is a JSON object with members:
+
+ ``path``
+ A string specifying the install destination path. The path may
+ be absolute or relative to the install prefix.
+
+ ``backtrace``
+ Optional member that is present when a CMake language backtrace to
+ the :command:`install` command invocation that specified this
+ destination is available. The value is an unsigned integer 0-based
+ index into the ``backtraceGraph`` member's ``nodes`` array.
+
+``link``
+ Optional member that is present for executables and shared library
+ targets that link into a runtime binary. The value is a JSON object
+ with members describing the link step:
+
+ ``language``
+ A string specifying the language (e.g. ``C``, ``CXX``, ``Fortran``)
+ of the toolchain is used to invoke the linker.
+
+ ``commandFragments``
+ Optional member that is present when fragments of the link command
+ line invocation are available. The value is a JSON array of entries
+ specifying ordered fragments. Each entry is a JSON object with members:
+
+ ``fragment``
+ A string specifying a fragment of the link command line invocation.
+ The value is encoded in the build system's native shell format.
+
+ ``role``
+ A string specifying the role of the fragment's content:
+
+ * ``flags``: link flags.
+ * ``libraries``: link library file paths or flags.
+ * ``libraryPath``: library search path flags.
+ * ``frameworkPath``: macOS framework search path flags.
+
+ ``lto``
+ Optional member that is present with boolean value ``true``
+ when link-time optimization (a.k.a. interprocedural optimization
+ or link-time code generation) is enabled.
+
+ ``sysroot``
+ Optional member that is present when the :variable:`CMAKE_SYSROOT_LINK`
+ or :variable:`CMAKE_SYSROOT` variable is defined. The value is a
+ JSON object with one member:
+
+ ``path``
+ A string specifying the absolute path to the sysroot, represented
+ with forward slashes.
+
+``archive``
+ Optional member that is present for static library targets. The value
+ is a JSON object with members describing the archive step:
+
+ ``commandFragments``
+ Optional member that is present when fragments of the archiver command
+ line invocation are available. The value is a JSON array of entries
+ specifying the fragments. Each entry is a JSON object with members:
+
+ ``fragment``
+ A string specifying a fragment of the archiver command line invocation.
+ The value is encoded in the build system's native shell format.
+
+ ``role``
+ A string specifying the role of the fragment's content:
+
+ * ``flags``: archiver flags.
+
+ ``lto``
+ Optional member that is present with boolean value ``true``
+ when link-time optimization (a.k.a. interprocedural optimization
+ or link-time code generation) is enabled.
+
+``dependencies``
+ Optional member that is present when the target depends on other targets.
+ The value is a JSON array of entries corresponding to the dependencies.
+ Each entry is a JSON object with members:
+
+ ``id``
+ A string uniquely identifying the target on which this target depends.
+ This matches the main ``id`` member of the other target.
+
+ ``backtrace``
+ Optional member that is present when a CMake language backtrace to
+ the :command:`add_dependencies`, :command:`target_link_libraries`,
+ or other command invocation that created this dependency is
+ available. The value is an unsigned integer 0-based index into
+ the ``backtraceGraph`` member's ``nodes`` array.
+
+``sources``
+ A JSON array of entries corresponding to the target's source files.
+ Each entry is a JSON object with members:
+
+ ``path``
+ A string specifying the path to the source file on disk, represented
+ with forward slashes. If the file is inside the top-level source
+ directory then the path is specified relative to that directory.
+ Otherwise the path is absolute.
+
+ ``compileGroupIndex``
+ Optional member that is present when the source is compiled.
+ The value is an unsigned integer 0-based index into the
+ ``compileGroups`` array.
+
+ ``sourceGroupIndex``
+ Optional member that is present when the source is part of a source
+ group either via the :command:`source_group` command or by default.
+ The value is an unsigned integer 0-based index into the
+ ``sourceGroups`` array.
+
+ ``isGenerated``
+ Optional member that is present with boolean value ``true`` if
+ the source is :prop_sf:`GENERATED`.
+
+ ``backtrace``
+ Optional member that is present when a CMake language backtrace to
+ the :command:`target_sources`, :command:`add_executable`,
+ :command:`add_library`, :command:`add_custom_target`, or other
+ command invocation that added this source to the target is
+ available. The value is an unsigned integer 0-based index into
+ the ``backtraceGraph`` member's ``nodes`` array.
+
+``sourceGroups``
+ Optional member that is present when sources are grouped together by
+ the :command:`source_group` command or by default. The value is a
+ JSON array of entries corresponding to the groups. Each entry is
+ a JSON object with members:
+
+ ``name``
+ A string specifying the name of the source group.
+
+ ``sourceIndexes``
+ A JSON array listing the sources belonging to the group.
+ Each entry is an unsigned integer 0-based index into the
+ main ``sources`` array for the target.
+
+``compileGroups``
+ Optional member that is present when the target has sources that compile.
+ The value is a JSON array of entries corresponding to groups of sources
+ that all compile with the same settings. Each entry is a JSON object
+ with members:
+
+ ``sourceIndexes``
+ A JSON array listing the sources belonging to the group.
+ Each entry is an unsigned integer 0-based index into the
+ main ``sources`` array for the target.
+
+ ``language``
+ A string specifying the language (e.g. ``C``, ``CXX``, ``Fortran``)
+ of the toolchain is used to compile the source file.
+
+ ``languageStandard``
+ Optional member that is present when the language standard is set
+ explicitly (e.g. via :prop_tgt:`CXX_STANDARD`) or implicitly by
+ compile features. Each entry is a JSON object with two members:
+
+ ``backtraces``
+ Optional member that is present when a CMake language backtrace to
+ the ``<LANG>_STANDARD`` setting is available. If the language
+ standard was set implicitly by compile features those are used as
+ the backtrace(s). It's possible for multiple compile features to
+ require the same language standard so there could be multiple
+ backtraces. The value is a JSON array with each entry being an
+ unsigned integer 0-based index into the ``backtraceGraph``
+ member's ``nodes`` array.
+
+ ``standard``
+ String representing the language standard.
+
+ This field was added in codemodel version 2.2.
+
+ ``compileCommandFragments``
+ Optional member that is present when fragments of the compiler command
+ line invocation are available. The value is a JSON array of entries
+ specifying ordered fragments. Each entry is a JSON object with
+ one member:
+
+ ``fragment``
+ A string specifying a fragment of the compile command line invocation.
+ The value is encoded in the build system's native shell format.
+
+ ``includes``
+ Optional member that is present when there are include directories.
+ The value is a JSON array with an entry for each directory. Each
+ entry is a JSON object with members:
+
+ ``path``
+ A string specifying the path to the include directory,
+ represented with forward slashes.
+
+ ``isSystem``
+ Optional member that is present with boolean value ``true`` if
+ the include directory is marked as a system include directory.
+
+ ``backtrace``
+ Optional member that is present when a CMake language backtrace to
+ the :command:`target_include_directories` or other command invocation
+ that added this include directory is available. The value is
+ an unsigned integer 0-based index into the ``backtraceGraph``
+ member's ``nodes`` array.
+
+ ``precompileHeaders``
+ Optional member that is present when :command:`target_precompile_headers`
+ or other command invocations set :prop_tgt:`PRECOMPILE_HEADERS` on the
+ target. The value is a JSON array with an entry for each header. Each
+ entry is a JSON object with members:
+
+ ``header``
+ Full path to the precompile header file.
+
+ ``backtrace``
+ Optional member that is present when a CMake language backtrace to
+ the :command:`target_precompile_headers` or other command invocation
+ that added this precompiled header is available. The value is an
+ unsigned integer 0-based index into the ``backtraceGraph`` member's
+ ``nodes`` array.
+
+ This field was added in codemodel version 2.1.
+
+ ``defines``
+ Optional member that is present when there are preprocessor definitions.
+ The value is a JSON array with an entry for each definition. Each
+ entry is a JSON object with members:
+
+ ``define``
+ A string specifying the preprocessor definition in the format
+ ``<name>[=<value>]``, e.g. ``DEF`` or ``DEF=1``.
+
+ ``backtrace``
+ Optional member that is present when a CMake language backtrace to
+ the :command:`target_compile_definitions` or other command invocation
+ that added this preprocessor definition is available. The value is
+ an unsigned integer 0-based index into the ``backtraceGraph``
+ member's ``nodes`` array.
+
+ ``sysroot``
+ Optional member that is present when the
+ :variable:`CMAKE_SYSROOT_COMPILE` or :variable:`CMAKE_SYSROOT`
+ variable is defined. The value is a JSON object with one member:
+
+ ``path``
+ A string specifying the absolute path to the sysroot, represented
+ with forward slashes.
+
+``backtraceGraph``
+ A `"codemodel" version 2 "backtrace graph"`_ whose nodes are referenced
+ from ``backtrace`` members elsewhere in this "target" object.
+
+"codemodel" version 2 "backtrace graph"
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``backtraceGraph`` member of a `"codemodel" version 2 "directory" object`_,
+or `"codemodel" version 2 "target" object`_ is a JSON object describing a
+graph of backtraces. Its nodes are referenced from ``backtrace`` members
+elsewhere in the containing object. The backtrace graph object members are:
+
+``nodes``
+ A JSON array listing nodes in the backtrace graph. Each entry
+ is a JSON object with members:
+
+ ``file``
+ An unsigned integer 0-based index into the backtrace ``files`` array.
+
+ ``line``
+ An optional member present when the node represents a line within
+ the file. The value is an unsigned integer 1-based line number.
+
+ ``command``
+ An optional member present when the node represents a command
+ invocation within the file. The value is an unsigned integer
+ 0-based index into the backtrace ``commands`` array.
+
+ ``parent``
+ An optional member present when the node is not the bottom of
+ the call stack. The value is an unsigned integer 0-based index
+ of another entry in the backtrace ``nodes`` array.
+
+``commands``
+ A JSON array listing command names referenced by backtrace nodes.
+ Each entry is a string specifying a command name.
+
+``files``
+ A JSON array listing CMake language files referenced by backtrace nodes.
+ Each entry is a string specifying the path to a file, represented
+ with forward slashes. If the file is inside the top-level source
+ directory then the path is specified relative to that directory.
+ Otherwise the path is absolute.
+
+Object Kind "cache"
+-------------------
+
+The ``cache`` object kind lists cache entries. These are the
+:ref:`CMake Language Variables` stored in the persistent cache
+(``CMakeCache.txt``) for the build tree.
+
+There is only one ``cache`` object major version, version 2.
+Version 1 does not exist to avoid confusion with that from
+:manual:`cmake-server(7)` mode.
+
+"cache" version 2
+^^^^^^^^^^^^^^^^^
+
+``cache`` object version 2 is a JSON object:
+
+.. code-block:: json
+
+ {
+ "kind": "cache",
+ "version": { "major": 2, "minor": 0 },
+ "entries": [
+ {
+ "name": "BUILD_SHARED_LIBS",
+ "value": "ON",
+ "type": "BOOL",
+ "properties": [
+ {
+ "name": "HELPSTRING",
+ "value": "Build shared libraries"
+ }
+ ]
+ },
+ {
+ "name": "CMAKE_GENERATOR",
+ "value": "Unix Makefiles",
+ "type": "INTERNAL",
+ "properties": [
+ {
+ "name": "HELPSTRING",
+ "value": "Name of generator."
+ }
+ ]
+ }
+ ]
+ }
+
+The members specific to ``cache`` objects are:
+
+``entries``
+ A JSON array whose entries are each a JSON object specifying a
+ cache entry. The members of each entry are:
+
+ ``name``
+ A string specifying the name of the entry.
+
+ ``value``
+ A string specifying the value of the entry.
+
+ ``type``
+ A string specifying the type of the entry used by
+ :manual:`cmake-gui(1)` to choose a widget for editing.
+
+ ``properties``
+ A JSON array of entries specifying associated
+ :ref:`cache entry properties <Cache Entry Properties>`.
+ Each entry is a JSON object containing members:
+
+ ``name``
+ A string specifying the name of the cache entry property.
+
+ ``value``
+ A string specifying the value of the cache entry property.
+
+Object Kind "cmakeFiles"
+------------------------
+
+The ``cmakeFiles`` object kind lists files used by CMake while
+configuring and generating the build system. These include the
+``CMakeLists.txt`` files as well as included ``.cmake`` files.
+
+There is only one ``cmakeFiles`` object major version, version 1.
+
+"cmakeFiles" version 1
+^^^^^^^^^^^^^^^^^^^^^^
+
+``cmakeFiles`` object version 1 is a JSON object:
+
+.. code-block:: json
+
+ {
+ "kind": "cmakeFiles",
+ "version": { "major": 1, "minor": 0 },
+ "paths": {
+ "build": "/path/to/top-level-build-dir",
+ "source": "/path/to/top-level-source-dir"
+ },
+ "inputs": [
+ {
+ "path": "CMakeLists.txt"
+ },
+ {
+ "isGenerated": true,
+ "path": "/path/to/top-level-build-dir/.../CMakeSystem.cmake"
+ },
+ {
+ "isExternal": true,
+ "path": "/path/to/external/third-party/module.cmake"
+ },
+ {
+ "isCMake": true,
+ "isExternal": true,
+ "path": "/path/to/cmake/Modules/CMakeGenericSystem.cmake"
+ }
+ ]
+ }
+
+The members specific to ``cmakeFiles`` objects are:
+
+``paths``
+ A JSON object containing members:
+
+ ``source``
+ A string specifying the absolute path to the top-level source directory,
+ represented with forward slashes.
+
+ ``build``
+ A string specifying the absolute path to the top-level build directory,
+ represented with forward slashes.
+
+``inputs``
+ A JSON array whose entries are each a JSON object specifying an input
+ file used by CMake when configuring and generating the build system.
+ The members of each entry are:
+
+ ``path``
+ A string specifying the path to an input file to CMake, represented
+ with forward slashes. If the file is inside the top-level source
+ directory then the path is specified relative to that directory.
+ Otherwise the path is absolute.
+
+ ``isGenerated``
+ Optional member that is present with boolean value ``true``
+ if the path specifies a file that is under the top-level
+ build directory and the build is out-of-source.
+ This member is not available on in-source builds.
+
+ ``isExternal``
+ Optional member that is present with boolean value ``true``
+ if the path specifies a file that is not under the top-level
+ source or build directories.
+
+ ``isCMake``
+ Optional member that is present with boolean value ``true``
+ if the path specifies a file in the CMake installation.
+
+Object Kind "toolchains"
+------------------------
+
+The ``toolchains`` object kind lists properties of the toolchains used during
+the build. These include the language, compiler path, ID, and version.
+
+There is only one ``toolchains`` object major version, version 1.
+
+"toolchains" version 1
+^^^^^^^^^^^^^^^^^^^^^^
+
+``toolchains`` object version 1 is a JSON object:
+
+.. code-block:: json
+
+ {
+ "kind": "toolchains",
+ "version": { "major": 1, "minor": 0 },
+ "toolchains": [
+ {
+ "language": "C",
+ "compiler": {
+ "path": "/usr/bin/cc",
+ "id": "GNU",
+ "version": "9.3.0",
+ "implicit": {
+ "includeDirectories": [
+ "/usr/lib/gcc/x86_64-linux-gnu/9/include",
+ "/usr/local/include",
+ "/usr/include/x86_64-linux-gnu",
+ "/usr/include"
+ ],
+ "linkDirectories": [
+ "/usr/lib/gcc/x86_64-linux-gnu/9",
+ "/usr/lib/x86_64-linux-gnu",
+ "/usr/lib",
+ "/lib/x86_64-linux-gnu",
+ "/lib"
+ ],
+ "linkFrameworkDirectories": [],
+ "linkLibraries": [ "gcc", "gcc_s", "c", "gcc", "gcc_s" ]
+ }
+ },
+ "sourceFileExtensions": [ "c", "m" ]
+ },
+ {
+ "language": "CXX",
+ "compiler": {
+ "path": "/usr/bin/c++",
+ "id": "GNU",
+ "version": "9.3.0",
+ "implicit": {
+ "includeDirectories": [
+ "/usr/include/c++/9",
+ "/usr/include/x86_64-linux-gnu/c++/9",
+ "/usr/include/c++/9/backward",
+ "/usr/lib/gcc/x86_64-linux-gnu/9/include",
+ "/usr/local/include",
+ "/usr/include/x86_64-linux-gnu",
+ "/usr/include"
+ ],
+ "linkDirectories": [
+ "/usr/lib/gcc/x86_64-linux-gnu/9",
+ "/usr/lib/x86_64-linux-gnu",
+ "/usr/lib",
+ "/lib/x86_64-linux-gnu",
+ "/lib"
+ ],
+ "linkFrameworkDirectories": [],
+ "linkLibraries": [
+ "stdc++", "m", "gcc_s", "gcc", "c", "gcc_s", "gcc"
+ ]
+ }
+ },
+ "sourceFileExtensions": [
+ "C", "M", "c++", "cc", "cpp", "cxx", "mm", "CPP"
+ ]
+ }
+ ]
+ }
+
+The members specific to ``toolchains`` objects are:
+
+``toolchains``
+ A JSON array whose entries are each a JSON object specifying a toolchain
+ associated with a particular language. The members of each entry are:
+
+ ``language``
+ A JSON string specifying the toolchain language, like C or CXX. Language
+ names are the same as langauge names that can be passed to the
+ :command:`project` command. Because CMake only supports a single toolchain
+ per language, this field can be used as a key.
+
+ ``compiler``
+ A JSON object containing members:
+
+ ``path``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_COMPILER` variable is defined for the current
+ language. Its value is a JSON string holding the path to the compiler.
+
+ ``id``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_COMPILER_ID` variable is defined for the current
+ language. Its value is a JSON string holding the ID (GNU, MSVC, etc.) of
+ the compiler.
+
+ ``version``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable is defined for the
+ current language. Its value is a JSON string holding the version of the
+ compiler.
+
+ ``target``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_COMPILER_TARGET` variable is defined for the
+ current language. Its value is a JSON string holding the cross-compiling
+ target of the compiler.
+
+ ``implicit``
+ A JSON object containing members:
+
+ ``includeDirectories``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES` variable is
+ defined for the current language. Its value is a JSON array of JSON
+ strings where each string holds a path to an implicit include
+ directory for the compiler.
+
+ ``linkDirectories``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES` variable is
+ defined for the current language. Its value is a JSON array of JSON
+ strings where each string holds a path to an implicit link directory
+ for the compiler.
+
+ ``linkFrameworkDirectories``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES` variable
+ is defined for the current language. Its value is a JSON array of JSON
+ strings where each string holds a path to an implicit link framework
+ directory for the compiler.
+
+ ``linkLibraries``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES` variable is defined
+ for the current language. Its value is a JSON array of JSON strings
+ where each string holds a path to an implicit link library for the
+ compiler.
+
+ ``sourceFileExtensions``
+ Optional member that is present when the
+ :variable:`CMAKE_<LANG>_SOURCE_FILE_EXTENSIONS` variable is defined for
+ the current language. Its value is a JSON array of JSON strings where each
+ each string holds a file extension (without the leading dot) for the
+ language.
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
new file mode 100644
index 0000000..775067a
--- /dev/null
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -0,0 +1,1061 @@
+.. cmake-manual-description: CMake Generator Expressions
+
+cmake-generator-expressions(7)
+******************************
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+Generator expressions are evaluated during build system generation to produce
+information specific to each build configuration.
+
+Generator expressions are allowed in the context of many target properties,
+such as :prop_tgt:`LINK_LIBRARIES`, :prop_tgt:`INCLUDE_DIRECTORIES`,
+:prop_tgt:`COMPILE_DEFINITIONS` and others. They may also be used when using
+commands to populate those properties, such as :command:`target_link_libraries`,
+:command:`target_include_directories`, :command:`target_compile_definitions`
+and others.
+
+They enable conditional linking, conditional definitions used when compiling,
+conditional include directories, and more. The conditions may be based on
+the build configuration, target properties, platform information or any other
+queryable information.
+
+Generator expressions have the form ``$<...>``. To avoid confusion, this page
+deviates from most of the CMake documentation in that it omits angular brackets
+``<...>`` around placeholders like ``condition``, ``string``, ``target``,
+among others.
+
+Generator expressions can be nested, as shown in most of the examples below.
+
+.. _`Boolean Generator Expressions`:
+
+Boolean Generator Expressions
+=============================
+
+Boolean expressions evaluate to either ``0`` or ``1``.
+They are typically used to construct the condition in a :ref:`conditional
+generator expression<Conditional Generator Expressions>`.
+
+Available boolean expressions are:
+
+Logical Operators
+-----------------
+
+.. genex:: $<BOOL:string>
+
+ Converts ``string`` to ``0`` or ``1``. Evaluates to ``0`` if any of the
+ following is true:
+
+ * ``string`` is empty,
+ * ``string`` is a case-insensitive equal of
+ ``0``, ``FALSE``, ``OFF``, ``N``, ``NO``, ``IGNORE``, or ``NOTFOUND``, or
+ * ``string`` ends in the suffix ``-NOTFOUND`` (case-sensitive).
+
+ Otherwise evaluates to ``1``.
+
+.. genex:: $<AND:conditions>
+
+ where ``conditions`` is a comma-separated list of boolean expressions.
+ Evaluates to ``1`` if all conditions are ``1``.
+ Otherwise evaluates to ``0``.
+
+.. genex:: $<OR:conditions>
+
+ where ``conditions`` is a comma-separated list of boolean expressions.
+ Evaluates to ``1`` if at least one of the conditions is ``1``.
+ Otherwise evaluates to ``0``.
+
+.. genex:: $<NOT:condition>
+
+ ``0`` if ``condition`` is ``1``, else ``1``.
+
+String Comparisons
+------------------
+
+.. genex:: $<STREQUAL:string1,string2>
+
+ ``1`` if ``string1`` and ``string2`` are equal, else ``0``.
+ The comparison is case-sensitive. For a case-insensitive comparison,
+ combine with a :ref:`string transforming generator expression
+ <String Transforming Generator Expressions>`,
+
+ .. code-block:: cmake
+
+ $<STREQUAL:$<UPPER_CASE:${foo}>,"BAR"> # "1" if ${foo} is any of "BAR", "Bar", "bar", ...
+
+.. genex:: $<EQUAL:value1,value2>
+
+ ``1`` if ``value1`` and ``value2`` are numerically equal, else ``0``.
+
+.. genex:: $<IN_LIST:string,list>
+
+ ``1`` if ``string`` is member of the semicolon-separated ``list``, else ``0``.
+ Uses case-sensitive comparisons.
+
+.. genex:: $<VERSION_LESS:v1,v2>
+
+ ``1`` if ``v1`` is a version less than ``v2``, else ``0``.
+
+.. genex:: $<VERSION_GREATER:v1,v2>
+
+ ``1`` if ``v1`` is a version greater than ``v2``, else ``0``.
+
+.. genex:: $<VERSION_EQUAL:v1,v2>
+
+ ``1`` if ``v1`` is the same version as ``v2``, else ``0``.
+
+.. genex:: $<VERSION_LESS_EQUAL:v1,v2>
+
+ ``1`` if ``v1`` is a version less than or equal to ``v2``, else ``0``.
+
+.. genex:: $<VERSION_GREATER_EQUAL:v1,v2>
+
+ ``1`` if ``v1`` is a version greater than or equal to ``v2``, else ``0``.
+
+Variable Queries
+----------------
+
+.. genex:: $<TARGET_EXISTS:target>
+
+ ``1`` if ``target`` exists, else ``0``.
+
+.. genex:: $<CONFIG:cfgs>
+
+ ``1`` if config is any one of the entries in ``cfgs``, else ``0``. This is a
+ case-insensitive comparison. The mapping in
+ :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` is also considered by this
+ expression when it is evaluated on a property on an :prop_tgt:`IMPORTED`
+ target.
+
+.. genex:: $<PLATFORM_ID:platform_ids>
+
+ where ``platform_ids`` is a comma-separated list.
+ ``1`` if the CMake's platform id matches any one of the entries in
+ ``platform_ids``, otherwise ``0``.
+ See also the :variable:`CMAKE_SYSTEM_NAME` variable.
+
+.. genex:: $<C_COMPILER_ID:compiler_ids>
+
+ where ``compiler_ids`` is a comma-separated list.
+ ``1`` if the CMake's compiler id of the C compiler matches any one
+ of the entries in ``compiler_ids``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+
+.. genex:: $<CXX_COMPILER_ID:compiler_ids>
+
+ where ``compiler_ids`` is a comma-separated list.
+ ``1`` if the CMake's compiler id of the CXX compiler matches any one
+ of the entries in ``compiler_ids``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+
+.. genex:: $<CUDA_COMPILER_ID:compiler_ids>
+
+ where ``compiler_ids`` is a comma-separated list.
+ ``1`` if the CMake's compiler id of the CUDA compiler matches any one
+ of the entries in ``compiler_ids``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+
+.. genex:: $<OBJC_COMPILER_ID:compiler_ids>
+
+ where ``compiler_ids`` is a comma-separated list.
+ ``1`` if the CMake's compiler id of the Objective-C compiler matches any one
+ of the entries in ``compiler_ids``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+
+.. genex:: $<OBJCXX_COMPILER_ID:compiler_ids>
+
+ where ``compiler_ids`` is a comma-separated list.
+ ``1`` if the CMake's compiler id of the Objective-C++ compiler matches any one
+ of the entries in ``compiler_ids``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+
+.. genex:: $<Fortran_COMPILER_ID:compiler_ids>
+
+ where ``compiler_ids`` is a comma-separated list.
+ ``1`` if the CMake's compiler id of the Fortran compiler matches any one
+ of the entries in ``compiler_ids``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+
+.. genex:: $<ISPC_COMPILER_ID:compiler_ids>
+
+ where ``compiler_ids`` is a comma-separated list.
+ ``1`` if the CMake's compiler id of the ISPC compiler matches any one
+ of the entries in ``compiler_ids``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+
+.. genex:: $<C_COMPILER_VERSION:version>
+
+ ``1`` if the version of the C compiler matches ``version``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+
+.. genex:: $<CXX_COMPILER_VERSION:version>
+
+ ``1`` if the version of the CXX compiler matches ``version``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+
+.. genex:: $<CUDA_COMPILER_VERSION:version>
+
+ ``1`` if the version of the CXX compiler matches ``version``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+
+.. genex:: $<OBJC_COMPILER_VERSION:version>
+
+ ``1`` if the version of the OBJC compiler matches ``version``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+
+.. genex:: $<OBJCXX_COMPILER_VERSION:version>
+
+ ``1`` if the version of the OBJCXX compiler matches ``version``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+
+.. genex:: $<Fortran_COMPILER_VERSION:version>
+
+ ``1`` if the version of the Fortran compiler matches ``version``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+
+.. genex:: $<ISPC_COMPILER_VERSION:version>
+
+ ``1`` if the version of the ISPC compiler matches ``version``, otherwise ``0``.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+
+.. genex:: $<TARGET_POLICY:policy>
+
+ ``1`` if the ``policy`` was NEW when the 'head' target was created,
+ else ``0``. If the ``policy`` was not set, the warning message for the policy
+ will be emitted. This generator expression only works for a subset of
+ policies.
+
+.. genex:: $<COMPILE_FEATURES:features>
+
+ where ``features`` is a comma-spearated list.
+ Evaluates to ``1`` if all of the ``features`` are available for the 'head'
+ target, and ``0`` otherwise. If this expression is used while evaluating
+ the link implementation of a target and if any dependency transitively
+ increases the required :prop_tgt:`C_STANDARD` or :prop_tgt:`CXX_STANDARD`
+ for the 'head' target, an error is reported. See the
+ :manual:`cmake-compile-features(7)` manual for information on
+ compile features and a list of supported compilers.
+
+.. _`Boolean COMPILE_LANGUAGE Generator Expression`:
+
+.. genex:: $<COMPILE_LANG_AND_ID:language,compiler_ids>
+
+ ``1`` when the language used for compilation unit matches ``language`` and
+ the CMake's compiler id of the language compiler matches any one of the
+ entries in ``compiler_ids``, otherwise ``0``. This expression is a short form
+ for the combination of ``$<COMPILE_LANGUAGE:language>`` and
+ ``$<LANG_COMPILER_ID:compiler_ids>``. This expression may be used to specify
+ compile options, compile definitions, and include directories for source files of a
+ particular language and compiler combination in a target. For example:
+
+ .. code-block:: cmake
+
+ add_executable(myapp main.cpp foo.c bar.cpp zot.cu)
+ target_compile_definitions(myapp
+ PRIVATE $<$<COMPILE_LANG_AND_ID:CXX,AppleClang,Clang>:COMPILING_CXX_WITH_CLANG>
+ $<$<COMPILE_LANG_AND_ID:CXX,Intel>:COMPILING_CXX_WITH_INTEL>
+ $<$<COMPILE_LANG_AND_ID:C,Clang>:COMPILING_C_WITH_CLANG>
+ )
+
+ This specifies the use of different compile definitions based on both
+ the compiler id and compilation language. This example will have a
+ ``COMPILING_CXX_WITH_CLANG`` compile definition when Clang is the CXX
+ compiler, and ``COMPILING_CXX_WITH_INTEL`` when Intel is the CXX compiler.
+ Likewise when the C compiler is Clang it will only see the ``COMPILING_C_WITH_CLANG``
+ definition.
+
+ Without the ``COMPILE_LANG_AND_ID`` generator expression the same logic
+ would be expressed as:
+
+ .. code-block:: cmake
+
+ target_compile_definitions(myapp
+ PRIVATE $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:AppleClang,Clang>>:COMPILING_CXX_WITH_CLANG>
+ $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:Intel>>:COMPILING_CXX_WITH_INTEL>
+ $<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:Clang>>:COMPILING_C_WITH_CLANG>
+ )
+
+.. genex:: $<COMPILE_LANGUAGE:languages>
+
+ ``1`` when the language used for compilation unit matches any of the entries
+ in ``languages``, otherwise ``0``. This expression may be used to specify
+ compile options, compile definitions, and include directories for source files of a
+ particular language in a target. For example:
+
+ .. code-block:: cmake
+
+ add_executable(myapp main.cpp foo.c bar.cpp zot.cu)
+ target_compile_options(myapp
+ PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
+ )
+ target_compile_definitions(myapp
+ PRIVATE $<$<COMPILE_LANGUAGE:CXX>:COMPILING_CXX>
+ $<$<COMPILE_LANGUAGE:CUDA>:COMPILING_CUDA>
+ )
+ target_include_directories(myapp
+ PRIVATE $<$<COMPILE_LANGUAGE:CXX,CUDA>:/opt/foo/headers>
+ )
+
+ This specifies the use of the ``-fno-exceptions`` compile option,
+ ``COMPILING_CXX`` compile definition, and ``cxx_headers`` include
+ directory for C++ only (compiler id checks elided). It also specifies
+ a ``COMPILING_CUDA`` compile definition for CUDA.
+
+ Note that with :ref:`Visual Studio Generators` and :generator:`Xcode` there
+ is no way to represent target-wide compile definitions or include directories
+ separately for ``C`` and ``CXX`` languages.
+ Also, with :ref:`Visual Studio Generators` there is no way to represent
+ target-wide flags separately for ``C`` and ``CXX`` languages. Under these
+ generators, expressions for both C and C++ sources will be evaluated
+ using ``CXX`` if there are any C++ sources and otherwise using ``C``.
+ A workaround is to create separate libraries for each source file language
+ instead:
+
+ .. code-block:: cmake
+
+ add_library(myapp_c foo.c)
+ add_library(myapp_cxx bar.cpp)
+ target_compile_options(myapp_cxx PUBLIC -fno-exceptions)
+ add_executable(myapp main.cpp)
+ target_link_libraries(myapp myapp_c myapp_cxx)
+
+.. _`Boolean LINK_LANGUAGE Generator Expression`:
+
+.. genex:: $<LINK_LANG_AND_ID:language,compiler_ids>
+
+ ``1`` when the language used for link step matches ``language`` and the
+ CMake's compiler id of the language linker matches any one of the entries
+ in ``compiler_ids``, otherwise ``0``. This expression is a short form for the
+ combination of ``$<LINK_LANGUAGE:language>`` and
+ ``$<LANG_COMPILER_ID:compiler_ids>``. This expression may be used to specify
+ link libraries, link options, link directories and link dependencies of a
+ particular language and linker combination in a target. For example:
+
+ .. code-block:: cmake
+
+ add_library(libC_Clang ...)
+ add_library(libCXX_Clang ...)
+ add_library(libC_Intel ...)
+ add_library(libCXX_Intel ...)
+
+ add_executable(myapp main.c)
+ if (CXX_CONFIG)
+ target_sources(myapp PRIVATE file.cxx)
+ endif()
+ target_link_libraries(myapp
+ PRIVATE $<$<LINK_LANG_AND_ID:CXX,Clang,AppleClang>:libCXX_Clang>
+ $<$<LINK_LANG_AND_ID:C,Clang,AppleClang>:libC_Clang>
+ $<$<LINK_LANG_AND_ID:CXX,Intel>:libCXX_Intel>
+ $<$<LINK_LANG_AND_ID:C,Intel>:libC_Intel>)
+
+ This specifies the use of different link libraries based on both the
+ compiler id and link language. This example will have target ``libCXX_Clang``
+ as link dependency when ``Clang`` or ``AppleClang`` is the ``CXX``
+ linker, and ``libCXX_Intel`` when ``Intel`` is the ``CXX`` linker.
+ Likewise when the ``C`` linker is ``Clang`` or ``AppleClang``, target
+ ``libC_Clang`` will be added as link dependency and ``libC_Intel`` when
+ ``Intel`` is the ``C`` linker.
+
+ See :ref:`the note related to
+ <Constraints LINK_LANGUAGE Generator Expression>`
+ ``$<LINK_LANGUAGE:language>`` for constraints about the usage of this
+ generator expression.
+
+.. genex:: $<LINK_LANGUAGE:languages>
+
+ ``1`` when the language used for link step matches any of the entries
+ in ``languages``, otherwise ``0``. This expression may be used to specify
+ link libraries, link options, link directories and link dependencies of a
+ particular language in a target. For example:
+
+ .. code-block:: cmake
+
+ add_library(api_C ...)
+ add_library(api_CXX ...)
+ add_library(api INTERFACE)
+ target_link_options(api INTERFACE $<$<LINK_LANGUAGE:C>:-opt_c>
+ $<$<LINK_LANGUAGE:CXX>:-opt_cxx>)
+ target_link_libraries(api INTERFACE $<$<LINK_LANGUAGE:C>:api_C>
+ $<$<LINK_LANGUAGE:CXX>:api_CXX>)
+
+ add_executable(myapp1 main.c)
+ target_link_options(myapp1 PRIVATE api)
+
+ add_executable(myapp2 main.cpp)
+ target_link_options(myapp2 PRIVATE api)
+
+ This specifies to use the ``api`` target for linking targets ``myapp1`` and
+ ``myapp2``. In practice, ``myapp1`` will link with target ``api_C`` and
+ option ``-opt_c`` because it will use ``C`` as link language. And ``myapp2``
+ will link with ``api_CXX`` and option ``-opt_cxx`` because ``CXX`` will be
+ the link language.
+
+ .. _`Constraints LINK_LANGUAGE Generator Expression`:
+
+ .. note::
+
+ To determine the link language of a target, it is required to collect,
+ transitively, all the targets which will be linked to it. So, for link
+ libraries properties, a double evaluation will be done. During the first
+ evaluation, ``$<LINK_LANGUAGE:..>`` expressions will always return ``0``.
+ The link language computed after this first pass will be used to do the
+ second pass. To avoid inconsistency, it is required that the second pass
+ do not change the link language. Moreover, to avoid unexpected
+ side-effects, it is required to specify complete entities as part of the
+ ``$<LINK_LANGUAGE:..>`` expression. For example:
+
+ .. code-block:: cmake
+
+ add_library(lib STATIC file.cxx)
+ add_library(libother STATIC file.c)
+
+ # bad usage
+ add_executable(myapp1 main.c)
+ target_link_libraries(myapp1 PRIVATE lib$<$<LINK_LANGUAGE:C>:other>)
+
+ # correct usage
+ add_executable(myapp2 main.c)
+ target_link_libraries(myapp2 PRIVATE $<$<LINK_LANGUAGE:C>:libother>)
+
+ In this example, for ``myapp1``, the first pass will, unexpectedly,
+ determine that the link language is ``CXX`` because the evaluation of the
+ generator expression will be an empty string so ``myapp1`` will depends on
+ target ``lib`` which is ``C++``. On the contrary, for ``myapp2``, the first
+ evaluation will give ``C`` as link language, so the second pass will
+ correctly add target ``libother`` as link dependency.
+
+.. genex:: $<DEVICE_LINK:list>
+
+ Returns the list if it is the device link step, an empty list otherwise.
+ The device link step is controlled by :prop_tgt:`CUDA_SEPARABLE_COMPILATION`
+ and :prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` properties and
+ policy :policy:`CMP0105`. This expression can only be used to specify link
+ options.
+
+.. genex:: $<HOST_LINK:list>
+
+ Returns the list if it is the normal link step, an empty list otherwise.
+ This expression is mainly useful when a device link step is also involved
+ (see ``$<DEVICE_LINK:list>`` generator expression). This expression can only
+ be used to specify link options.
+
+String-Valued Generator Expressions
+===================================
+
+These expressions expand to some string.
+For example,
+
+.. code-block:: cmake
+
+ include_directories(/usr/include/$<CXX_COMPILER_ID>/)
+
+expands to ``/usr/include/GNU/`` or ``/usr/include/Clang/`` etc, depending on
+the compiler identifier.
+
+String-valued expressions may also be combined with other expressions.
+Here an example for a string-valued expression within a boolean expressions
+within a conditional expression:
+
+.. code-block:: cmake
+
+ $<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,4.2.0>:OLD_COMPILER>
+
+expands to ``OLD_COMPILER`` if the
+:variable:`CMAKE_CXX_COMPILER_VERSION <CMAKE_<LANG>_COMPILER_VERSION>` is less
+than 4.2.0.
+
+And here two nested string-valued expressions:
+
+.. code-block:: cmake
+
+ -I$<JOIN:$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>, -I>
+
+generates a string of the entries in the :prop_tgt:`INCLUDE_DIRECTORIES` target
+property with each entry preceded by ``-I``.
+
+Expanding on the previous example, if one first wants to check if the
+``INCLUDE_DIRECTORIES`` property is non-empty, then it is advisable to
+introduce a helper variable to keep the code readable:
+
+.. code-block:: cmake
+
+ set(prop "$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>") # helper variable
+ $<$<BOOL:${prop}>:-I$<JOIN:${prop}, -I>>
+
+The following string-valued generator expressions are available:
+
+Escaped Characters
+------------------
+
+String literals to escape the special meaning a character would otherwise have:
+
+.. genex:: $<ANGLE-R>
+
+ A literal ``>``. Used for example to compare strings that contain a ``>``.
+
+.. genex:: $<COMMA>
+
+ A literal ``,``. Used for example to compare strings which contain a ``,``.
+
+.. genex:: $<SEMICOLON>
+
+ A literal ``;``. Used to prevent list expansion on an argument with ``;``.
+
+.. _`Conditional Generator Expressions`:
+
+Conditional Expressions
+-----------------------
+
+Conditional generator expressions depend on a boolean condition
+that must be ``0`` or ``1``.
+
+.. genex:: $<condition:true_string>
+
+ Evaluates to ``true_string`` if ``condition`` is ``1``.
+ Otherwise evaluates to the empty string.
+
+.. genex:: $<IF:condition,true_string,false_string>
+
+ Evaluates to ``true_string`` if ``condition`` is ``1``.
+ Otherwise evaluates to ``false_string``.
+
+Typically, the ``condition`` is a :ref:`boolean generator expression
+<Boolean Generator Expressions>`. For instance,
+
+.. code-block:: cmake
+
+ $<$<CONFIG:Debug>:DEBUG_MODE>
+
+expands to ``DEBUG_MODE`` when the ``Debug`` configuration is used, and
+otherwise expands to the empty string.
+
+.. _`String Transforming Generator Expressions`:
+
+String Transformations
+----------------------
+
+.. genex:: $<JOIN:list,string>
+
+ Joins the list with the content of ``string``.
+
+.. genex:: $<REMOVE_DUPLICATES:list>
+
+ Removes duplicated items in the given ``list``.
+
+.. genex:: $<FILTER:list,INCLUDE|EXCLUDE,regex>
+
+ Includes or removes items from ``list`` that match the regular expression ``regex``.
+
+.. genex:: $<LOWER_CASE:string>
+
+ Content of ``string`` converted to lower case.
+
+.. genex:: $<UPPER_CASE:string>
+
+ Content of ``string`` converted to upper case.
+
+.. genex:: $<GENEX_EVAL:expr>
+
+ Content of ``expr`` evaluated as a generator expression in the current
+ context. This enables consumption of generator expressions whose
+ evaluation results itself in generator expressions.
+
+.. genex:: $<TARGET_GENEX_EVAL:tgt,expr>
+
+ Content of ``expr`` evaluated as a generator expression in the context of
+ ``tgt`` target. This enables consumption of custom target properties that
+ themselves contain generator expressions.
+
+ Having the capability to evaluate generator expressions is very useful when
+ you want to manage custom properties supporting generator expressions.
+ For example:
+
+ .. code-block:: cmake
+
+ add_library(foo ...)
+
+ set_property(TARGET foo PROPERTY
+ CUSTOM_KEYS $<$<CONFIG:DEBUG>:FOO_EXTRA_THINGS>
+ )
+
+ add_custom_target(printFooKeys
+ COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_PROPERTY:foo,CUSTOM_KEYS>
+ )
+
+ This naive implementation of the ``printFooKeys`` custom command is wrong
+ because ``CUSTOM_KEYS`` target property is not evaluated and the content
+ is passed as is (i.e. ``$<$<CONFIG:DEBUG>:FOO_EXTRA_THINGS>``).
+
+ To have the expected result (i.e. ``FOO_EXTRA_THINGS`` if config is
+ ``Debug``), it is required to evaluate the output of
+ ``$<TARGET_PROPERTY:foo,CUSTOM_KEYS>``:
+
+ .. code-block:: cmake
+
+ add_custom_target(printFooKeys
+ COMMAND ${CMAKE_COMMAND} -E
+ echo $<TARGET_GENEX_EVAL:foo,$<TARGET_PROPERTY:foo,CUSTOM_KEYS>>
+ )
+
+Variable Queries
+----------------
+
+.. genex:: $<CONFIG>
+
+ Configuration name.
+
+.. genex:: $<CONFIGURATION>
+
+ Configuration name. Deprecated since CMake 3.0. Use ``CONFIG`` instead.
+
+.. genex:: $<PLATFORM_ID>
+
+ The current system's CMake platform id.
+ See also the :variable:`CMAKE_SYSTEM_NAME` variable.
+
+.. genex:: $<C_COMPILER_ID>
+
+ The CMake's compiler id of the C compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+
+.. genex:: $<CXX_COMPILER_ID>
+
+ The CMake's compiler id of the CXX compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+
+.. genex:: $<CUDA_COMPILER_ID>
+
+ The CMake's compiler id of the CUDA compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+
+.. genex:: $<OBJC_COMPILER_ID>
+
+ The CMake's compiler id of the OBJC compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+
+.. genex:: $<OBJCXX_COMPILER_ID>
+
+ The CMake's compiler id of the OBJCXX compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+
+.. genex:: $<Fortran_COMPILER_ID>
+
+ The CMake's compiler id of the Fortran compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+
+.. genex:: $<ISPC_COMPILER_ID>
+
+ The CMake's compiler id of the ISPC compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+
+.. genex:: $<C_COMPILER_VERSION>
+
+ The version of the C compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+
+.. genex:: $<CXX_COMPILER_VERSION>
+
+ The version of the CXX compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+
+.. genex:: $<CUDA_COMPILER_VERSION>
+
+ The version of the CUDA compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+
+.. genex:: $<OBJC_COMPILER_VERSION>
+
+ The version of the OBJC compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+
+.. genex:: $<OBJCXX_COMPILER_VERSION>
+
+ The version of the OBJCXX compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+
+.. genex:: $<Fortran_COMPILER_VERSION>
+
+ The version of the Fortran compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+
+.. genex:: $<ISPC_COMPILER_VERSION>
+
+ The version of the ISPC compiler used.
+ See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+
+.. genex:: $<COMPILE_LANGUAGE>
+
+ The compile language of source files when evaluating compile options.
+ See :ref:`the related boolean expression
+ <Boolean COMPILE_LANGUAGE Generator Expression>`
+ ``$<COMPILE_LANGUAGE:language>``
+ for notes about the portability of this generator expression.
+
+.. genex:: $<LINK_LANGUAGE>
+
+ The link language of target when evaluating link options.
+ See :ref:`the related boolean expression
+ <Boolean LINK_LANGUAGE Generator Expression>` ``$<LINK_LANGUAGE:language>``
+ for notes about the portability of this generator expression.
+
+ .. note::
+
+ This generator expression is not supported by the link libraries
+ properties to avoid side-effects due to the double evaluation of
+ these properties.
+
+.. _`Target-Dependent Queries`:
+
+Target-Dependent Queries
+------------------------
+
+These queries refer to a target ``tgt``. This can be any runtime artifact,
+namely:
+
+* an executable target created by :command:`add_executable`
+* a shared library target (``.so``, ``.dll`` but not their ``.lib`` import library)
+ created by :command:`add_library`
+* a static library target created by :command:`add_library`
+
+In the following, "the ``tgt`` filename" means the name of the ``tgt``
+binary file. This has to be distinguished from "the target name",
+which is just the string ``tgt``.
+
+.. genex:: $<TARGET_NAME_IF_EXISTS:tgt>
+
+ The target name ``tgt`` if the target exists, an empty string otherwise.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_FILE:tgt>
+
+ Full path to the ``tgt`` binary file.
+
+.. genex:: $<TARGET_FILE_BASE_NAME:tgt>
+
+ Base name of ``tgt``, i.e. ``$<TARGET_FILE_NAME:tgt>`` without prefix and
+ suffix.
+ For example, if the ``tgt`` filename is ``libbase.so``, the base name is ``base``.
+
+ See also the :prop_tgt:`OUTPUT_NAME`, :prop_tgt:`ARCHIVE_OUTPUT_NAME`,
+ :prop_tgt:`LIBRARY_OUTPUT_NAME` and :prop_tgt:`RUNTIME_OUTPUT_NAME`
+ target properties and their configuration specific variants
+ :prop_tgt:`OUTPUT_NAME_<CONFIG>`, :prop_tgt:`ARCHIVE_OUTPUT_NAME_<CONFIG>`,
+ :prop_tgt:`LIBRARY_OUTPUT_NAME_<CONFIG>` and
+ :prop_tgt:`RUNTIME_OUTPUT_NAME_<CONFIG>`.
+
+ The :prop_tgt:`<CONFIG>_POSTFIX` and :prop_tgt:`DEBUG_POSTFIX` target
+ properties can also be considered.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_FILE_PREFIX:tgt>
+
+ Prefix of the ``tgt`` filename (such as ``lib``).
+
+ See also the :prop_tgt:`PREFIX` target property.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_FILE_SUFFIX:tgt>
+
+ Suffix of the ``tgt`` filename (extension such as ``.so`` or ``.exe``).
+
+ See also the :prop_tgt:`SUFFIX` target property.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_FILE_NAME:tgt>
+
+ The ``tgt`` filename.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on (see policy :policy:`CMP0112`).
+
+.. genex:: $<TARGET_FILE_DIR:tgt>
+
+ Directory of the ``tgt`` binary file.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on (see policy :policy:`CMP0112`).
+
+.. genex:: $<TARGET_LINKER_FILE:tgt>
+
+ File used when linking to the ``tgt`` target. This will usually
+ be the library that ``tgt`` represents (``.a``, ``.lib``, ``.so``),
+ but for a shared library on DLL platforms, it would be the ``.lib``
+ import library associated with the DLL.
+
+.. genex:: $<TARGET_LINKER_FILE_BASE_NAME:tgt>
+
+ Base name of file used to link the target ``tgt``, i.e.
+ ``$<TARGET_LINKER_FILE_NAME:tgt>`` without prefix and suffix. For example,
+ if target file name is ``libbase.a``, the base name is ``base``.
+
+ See also the :prop_tgt:`OUTPUT_NAME`, :prop_tgt:`ARCHIVE_OUTPUT_NAME`,
+ and :prop_tgt:`LIBRARY_OUTPUT_NAME` target properties and their configuration
+ specific variants :prop_tgt:`OUTPUT_NAME_<CONFIG>`,
+ :prop_tgt:`ARCHIVE_OUTPUT_NAME_<CONFIG>` and
+ :prop_tgt:`LIBRARY_OUTPUT_NAME_<CONFIG>`.
+
+ The :prop_tgt:`<CONFIG>_POSTFIX` and :prop_tgt:`DEBUG_POSTFIX` target
+ properties can also be considered.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_LINKER_FILE_PREFIX:tgt>
+
+ Prefix of file used to link target ``tgt``.
+
+ See also the :prop_tgt:`PREFIX` and :prop_tgt:`IMPORT_PREFIX` target
+ properties.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_LINKER_FILE_SUFFIX:tgt>
+
+ Suffix of file used to link where ``tgt`` is the name of a target.
+
+ The suffix corresponds to the file extension (such as ".so" or ".lib").
+
+ See also the :prop_tgt:`SUFFIX` and :prop_tgt:`IMPORT_SUFFIX` target
+ properties.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_LINKER_FILE_NAME:tgt>
+
+ Name of file used to link target ``tgt``.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on (see policy :policy:`CMP0112`).
+
+.. genex:: $<TARGET_LINKER_FILE_DIR:tgt>
+
+ Directory of file used to link target ``tgt``.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on (see policy :policy:`CMP0112`).
+
+.. genex:: $<TARGET_SONAME_FILE:tgt>
+
+ File with soname (``.so.3``) where ``tgt`` is the name of a target.
+.. genex:: $<TARGET_SONAME_FILE_NAME:tgt>
+
+ Name of file with soname (``.so.3``).
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on (see policy :policy:`CMP0112`).
+
+.. genex:: $<TARGET_SONAME_FILE_DIR:tgt>
+
+ Directory of with soname (``.so.3``).
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on (see policy :policy:`CMP0112`).
+
+.. genex:: $<TARGET_PDB_FILE:tgt>
+
+ Full path to the linker generated program database file (.pdb)
+ where ``tgt`` is the name of a target.
+
+ See also the :prop_tgt:`PDB_NAME` and :prop_tgt:`PDB_OUTPUT_DIRECTORY`
+ target properties and their configuration specific variants
+ :prop_tgt:`PDB_NAME_<CONFIG>` and :prop_tgt:`PDB_OUTPUT_DIRECTORY_<CONFIG>`.
+
+.. genex:: $<TARGET_PDB_FILE_BASE_NAME:tgt>
+
+ Base name of the linker generated program database file (.pdb)
+ where ``tgt`` is the name of a target.
+
+ The base name corresponds to the target PDB file name (see
+ ``$<TARGET_PDB_FILE_NAME:tgt>``) without prefix and suffix. For example,
+ if target file name is ``base.pdb``, the base name is ``base``.
+
+ See also the :prop_tgt:`PDB_NAME` target property and its configuration
+ specific variant :prop_tgt:`PDB_NAME_<CONFIG>`.
+
+ The :prop_tgt:`<CONFIG>_POSTFIX` and :prop_tgt:`DEBUG_POSTFIX` target
+ properties can also be considered.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_PDB_FILE_NAME:tgt>
+
+ Name of the linker generated program database file (.pdb).
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on (see policy :policy:`CMP0112`).
+
+.. genex:: $<TARGET_PDB_FILE_DIR:tgt>
+
+ Directory of the linker generated program database file (.pdb).
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on (see policy :policy:`CMP0112`).
+
+.. genex:: $<TARGET_BUNDLE_DIR:tgt>
+
+ Full path to the bundle directory (``my.app``, ``my.framework``, or
+ ``my.bundle``) where ``tgt`` is the name of a target.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on (see policy :policy:`CMP0112`).
+
+.. genex:: $<TARGET_BUNDLE_CONTENT_DIR:tgt>
+
+ Full path to the bundle content directory where ``tgt`` is the name of a
+ target. For the macOS SDK it leads to ``my.app/Contents``, ``my.framework``,
+ or ``my.bundle/Contents``. For all other SDKs (e.g. iOS) it leads to
+ ``my.app``, ``my.framework``, or ``my.bundle`` due to the flat bundle
+ structure.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on (see policy :policy:`CMP0112`).
+
+.. genex:: $<TARGET_PROPERTY:tgt,prop>
+
+ Value of the property ``prop`` on the target ``tgt``.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_PROPERTY:prop>
+
+ Value of the property ``prop`` on the target for which the expression
+ is being evaluated. Note that for generator expressions in
+ :ref:`Target Usage Requirements` this is the consuming target rather
+ than the target specifying the requirement.
+
+.. genex:: $<TARGET_RUNTIME_DLLS:tgt>
+
+ List of DLLs that the target depends on at runtime. This is determined by
+ the locations of all the ``SHARED`` and ``MODULE`` targets in the target's
+ transitive dependencies. Using this generator expression on targets other
+ than executables, ``SHARED`` libraries, and ``MODULE`` libraries is an error.
+ On non-DLL platforms, it evaluates to an empty string.
+
+ This generator expression can be used to copy all of the DLLs that a target
+ depends on into its output directory in a ``POST_BUILD`` custom command. For
+ example:
+
+ .. code-block:: cmake
+
+ find_package(foo REQUIRED)
+
+ add_executable(exe main.c)
+ target_link_libraries(exe PRIVATE foo::foo foo::bar)
+ add_custom_command(TARGET exe POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:exe> $<TARGET_FILE_DIR:exe>
+ COMMAND_EXPAND_LISTS
+ )
+
+.. genex:: $<INSTALL_PREFIX>
+
+ Content of the install prefix when the target is exported via
+ :command:`install(EXPORT)`, or when evaluated in
+ :prop_tgt:`INSTALL_NAME_DIR`, and empty otherwise.
+
+Output-Related Expressions
+--------------------------
+
+.. genex:: $<TARGET_NAME:...>
+
+ Marks ``...`` as being the name of a target. This is required if exporting
+ targets to multiple dependent export sets. The ``...`` must be a literal
+ name of a target- it may not contain generator expressions.
+
+.. genex:: $<LINK_ONLY:...>
+
+ Content of ``...`` except when evaluated in a link interface while
+ propagating :ref:`Target Usage Requirements`, in which case it is the
+ empty string.
+ Intended for use only in an :prop_tgt:`INTERFACE_LINK_LIBRARIES` target
+ property, perhaps via the :command:`target_link_libraries` command,
+ to specify private link dependencies without other usage requirements.
+
+.. genex:: $<INSTALL_INTERFACE:...>
+
+ Content of ``...`` when the property is exported using :command:`install(EXPORT)`,
+ and empty otherwise.
+
+.. genex:: $<BUILD_INTERFACE:...>
+
+ Content of ``...`` when the property is exported using :command:`export`, or
+ when the target is used by another target in the same buildsystem. Expands to
+ the empty string otherwise.
+
+.. genex:: $<MAKE_C_IDENTIFIER:...>
+
+ Content of ``...`` converted to a C identifier. The conversion follows the
+ same behavior as :command:`string(MAKE_C_IDENTIFIER)`.
+
+.. genex:: $<TARGET_OBJECTS:objLib>
+
+ List of objects resulting from build of ``objLib``.
+
+.. genex:: $<SHELL_PATH:...>
+
+ Content of ``...`` converted to shell path style. For example, slashes are
+ converted to backslashes in Windows shells and drive letters are converted
+ to posix paths in MSYS shells. The ``...`` must be an absolute path.
+ The ``...`` may be a :ref:`semicolon-separated list <CMake Language Lists>`
+ of paths, in which case each path is converted individually and a result
+ list is generated using the shell path separator (``:`` on POSIX and
+ ``;`` on Windows). Be sure to enclose the argument containing this genex
+ in double quotes in CMake source code so that ``;`` does not split arguments.
+
+.. genex:: $<OUTPUT_CONFIG:...>
+
+ .. versionadded:: 3.20
+
+ Only valid in :command:`add_custom_command` and :command:`add_custom_target`
+ as the outer-most generator expression in an argument.
+ With the :generator:`Ninja Multi-Config` generator, generator expressions
+ in ``...`` are evaluated using the custom command's "output config".
+ With other generators, the content of ``...`` is evaluated normally.
+
+.. genex:: $<COMMAND_CONFIG:...>
+
+ .. versionadded:: 3.20
+
+ Only valid in :command:`add_custom_command` and :command:`add_custom_target`
+ as the outer-most generator expression in an argument.
+ With the :generator:`Ninja Multi-Config` generator, generator expressions
+ in ``...`` are evaluated using the custom command's "command config".
+ With other generators, the content of ``...`` is evaluated normally.
+
+Debugging
+=========
+
+Since generator expressions are evaluated during generation of the buildsystem,
+and not during processing of ``CMakeLists.txt`` files, it is not possible to
+inspect their result with the :command:`message()` command.
+
+One possible way to generate debug messages is to add a custom target,
+
+.. code-block:: cmake
+
+ add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo "$<...>")
+
+The shell command ``make genexdebug`` (invoked after execution of ``cmake``)
+would then print the result of ``$<...>``.
+
+Another way is to write debug messages to a file:
+
+.. code-block:: cmake
+
+ file(GENERATE OUTPUT filename CONTENT "$<...>")
diff --git a/Help/manual/cmake-generators.7.rst b/Help/manual/cmake-generators.7.rst
new file mode 100644
index 0000000..8ca2bf6
--- /dev/null
+++ b/Help/manual/cmake-generators.7.rst
@@ -0,0 +1,120 @@
+.. cmake-manual-description: CMake Generators Reference
+
+cmake-generators(7)
+*******************
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+A *CMake Generator* is responsible for writing the input files for
+a native build system. Exactly one of the `CMake Generators`_ must be
+selected for a build tree to determine what native build system is to
+be used. Optionally one of the `Extra Generators`_ may be selected
+as a variant of some of the `Command-Line Build Tool Generators`_ to
+produce project files for an auxiliary IDE.
+
+CMake Generators are platform-specific so each may be available only
+on certain platforms. The :manual:`cmake(1)` command-line tool ``--help``
+output lists available generators on the current platform. Use its ``-G``
+option to specify the generator for a new build tree.
+The :manual:`cmake-gui(1)` offers interactive selection of a generator
+when creating a new build tree.
+
+CMake Generators
+================
+
+.. _`Command-Line Build Tool Generators`:
+
+Command-Line Build Tool Generators
+----------------------------------
+
+These generators support command-line build tools. In order to use them,
+one must launch CMake from a command-line prompt whose environment is
+already configured for the chosen compiler and build tool.
+
+.. _`Makefile Generators`:
+
+Makefile Generators
+^^^^^^^^^^^^^^^^^^^
+
+.. toctree::
+ :maxdepth: 1
+
+ /generator/Borland Makefiles
+ /generator/MSYS Makefiles
+ /generator/MinGW Makefiles
+ /generator/NMake Makefiles
+ /generator/NMake Makefiles JOM
+ /generator/Unix Makefiles
+ /generator/Watcom WMake
+
+.. _`Ninja Generators`:
+
+Ninja Generators
+^^^^^^^^^^^^^^^^
+
+.. toctree::
+ :maxdepth: 1
+
+ /generator/Ninja
+ /generator/Ninja Multi-Config
+
+.. _`IDE Build Tool Generators`:
+
+IDE Build Tool Generators
+-------------------------
+
+These generators support Integrated Development Environment (IDE)
+project files. Since the IDEs configure their own environment
+one may launch CMake from any environment.
+
+.. _`Visual Studio Generators`:
+
+Visual Studio Generators
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. toctree::
+ :maxdepth: 1
+
+ /generator/Visual Studio 6
+ /generator/Visual Studio 7
+ /generator/Visual Studio 7 .NET 2003
+ /generator/Visual Studio 8 2005
+ /generator/Visual Studio 9 2008
+ /generator/Visual Studio 10 2010
+ /generator/Visual Studio 11 2012
+ /generator/Visual Studio 12 2013
+ /generator/Visual Studio 14 2015
+ /generator/Visual Studio 15 2017
+ /generator/Visual Studio 16 2019
+
+Other Generators
+^^^^^^^^^^^^^^^^
+
+.. toctree::
+ :maxdepth: 1
+
+ /generator/Green Hills MULTI
+ /generator/Xcode
+
+Extra Generators
+================
+
+Some of the `CMake Generators`_ listed in the :manual:`cmake(1)`
+command-line tool ``--help`` output may have variants that specify
+an extra generator for an auxiliary IDE tool. Such generator
+names have the form ``<extra-generator> - <main-generator>``.
+The following extra generators are known to CMake.
+
+.. toctree::
+ :maxdepth: 1
+
+ /generator/CodeBlocks
+ /generator/CodeLite
+ /generator/Eclipse CDT4
+ /generator/Kate
+ /generator/Sublime Text 2
diff --git a/Help/manual/cmake-gui.1.rst b/Help/manual/cmake-gui.1.rst
new file mode 100644
index 0000000..281986f
--- /dev/null
+++ b/Help/manual/cmake-gui.1.rst
@@ -0,0 +1,52 @@
+.. cmake-manual-description: CMake GUI Command-Line Reference
+
+cmake-gui(1)
+************
+
+Synopsis
+========
+
+.. parsed-literal::
+
+ cmake-gui [<options>]
+ cmake-gui [<options>] {<path-to-source> | <path-to-existing-build>}
+ cmake-gui [<options>] -S <path-to-source> -B <path-to-build>
+ cmake-gui [<options>] --browse-manual
+
+Description
+===========
+
+The **cmake-gui** executable is the CMake GUI. Project configuration
+settings may be specified interactively. Brief instructions are
+provided at the bottom of the window when the program is running.
+
+CMake is a cross-platform build system generator. Projects specify
+their build process with platform-independent CMake listfiles included
+in each directory of a source tree with the name ``CMakeLists.txt``.
+Users build a project by using CMake to generate a build system for a
+native tool on their platform.
+
+Options
+=======
+
+``-S <path-to-source>``
+ Path to root directory of the CMake project to build.
+
+``-B <path-to-build>``
+ Path to directory which CMake will use as the root of build directory.
+
+ If the directory doesn't already exist CMake will make it.
+
+``--preset=<preset-name>``
+ Name of the preset to use from the project's
+ :manual:`presets <cmake-presets(7)>` files, if it has them.
+
+``--browse-manual``
+ Open the CMake reference manual in a browser and immediately exit.
+
+.. include:: OPTIONS_HELP.txt
+
+See Also
+========
+
+.. include:: LINKS.txt
diff --git a/Help/manual/cmake-language.7.rst b/Help/manual/cmake-language.7.rst
new file mode 100644
index 0000000..b7f0861
--- /dev/null
+++ b/Help/manual/cmake-language.7.rst
@@ -0,0 +1,629 @@
+.. cmake-manual-description: CMake Language Reference
+
+cmake-language(7)
+*****************
+
+.. only:: html
+
+ .. contents::
+
+Organization
+============
+
+CMake input files are written in the "CMake Language" in source files
+named ``CMakeLists.txt`` or ending in a ``.cmake`` file name extension.
+
+CMake Language source files in a project are organized into:
+
+* `Directories`_ (``CMakeLists.txt``),
+* `Scripts`_ (``<script>.cmake``), and
+* `Modules`_ (``<module>.cmake``).
+
+Directories
+-----------
+
+When CMake processes a project source tree, the entry point is
+a source file called ``CMakeLists.txt`` in the top-level source
+directory. This file may contain the entire build specification
+or use the :command:`add_subdirectory` command to add subdirectories
+to the build. Each subdirectory added by the command must also
+contain a ``CMakeLists.txt`` file as the entry point to that
+directory. For each source directory whose ``CMakeLists.txt`` file
+is processed CMake generates a corresponding directory in the build
+tree to act as the default working and output directory.
+
+Scripts
+-------
+
+An individual ``<script>.cmake`` source file may be processed
+in *script mode* by using the :manual:`cmake(1)` command-line tool
+with the ``-P`` option. Script mode simply runs the commands in
+the given CMake Language source file and does not generate a
+build system. It does not allow CMake commands that define build
+targets or actions.
+
+Modules
+-------
+
+CMake Language code in either `Directories`_ or `Scripts`_ may
+use the :command:`include` command to load a ``<module>.cmake``
+source file in the scope of the including context.
+See the :manual:`cmake-modules(7)` manual page for documentation
+of modules included with the CMake distribution.
+Project source trees may also provide their own modules and
+specify their location(s) in the :variable:`CMAKE_MODULE_PATH`
+variable.
+
+Syntax
+======
+
+.. _`CMake Language Encoding`:
+
+Encoding
+--------
+
+A CMake Language source file may be written in 7-bit ASCII text for
+maximum portability across all supported platforms. Newlines may be
+encoded as either ``\n`` or ``\r\n`` but will be converted to ``\n``
+as input files are read.
+
+Note that the implementation is 8-bit clean so source files may
+be encoded as UTF-8 on platforms with system APIs supporting this
+encoding. In addition, CMake 3.2 and above support source files
+encoded in UTF-8 on Windows (using UTF-16 to call system APIs).
+Furthermore, CMake 3.0 and above allow a leading UTF-8
+`Byte-Order Mark`_ in source files.
+
+.. _`Byte-Order Mark`: http://en.wikipedia.org/wiki/Byte_order_mark
+
+Source Files
+------------
+
+A CMake Language source file consists of zero or more
+`Command Invocations`_ separated by newlines and optionally
+spaces and `Comments`_:
+
+.. raw:: latex
+
+ \begin{small}
+
+.. productionlist::
+ file: `file_element`*
+ file_element: `command_invocation` `line_ending` |
+ : (`bracket_comment`|`space`)* `line_ending`
+ line_ending: `line_comment`? `newline`
+ space: <match '[ \t]+'>
+ newline: <match '\n'>
+
+.. raw:: latex
+
+ \end{small}
+
+Note that any source file line not inside `Command Arguments`_ or
+a `Bracket Comment`_ can end in a `Line Comment`_.
+
+.. _`Command Invocations`:
+
+Command Invocations
+-------------------
+
+A *command invocation* is a name followed by paren-enclosed arguments
+separated by whitespace:
+
+.. raw:: latex
+
+ \begin{small}
+
+.. productionlist::
+ command_invocation: `space`* `identifier` `space`* '(' `arguments` ')'
+ identifier: <match '[A-Za-z_][A-Za-z0-9_]*'>
+ arguments: `argument`? `separated_arguments`*
+ separated_arguments: `separation`+ `argument`? |
+ : `separation`* '(' `arguments` ')'
+ separation: `space` | `line_ending`
+
+.. raw:: latex
+
+ \end{small}
+
+For example:
+
+.. code-block:: cmake
+
+ add_executable(hello world.c)
+
+Command names are case-insensitive.
+Nested unquoted parentheses in the arguments must balance.
+Each ``(`` or ``)`` is given to the command invocation as
+a literal `Unquoted Argument`_. This may be used in calls
+to the :command:`if` command to enclose conditions.
+For example:
+
+.. code-block:: cmake
+
+ if(FALSE AND (FALSE OR TRUE)) # evaluates to FALSE
+
+.. note::
+ CMake versions prior to 3.0 require command name identifiers
+ to be at least 2 characters.
+
+ CMake versions prior to 2.8.12 silently accept an `Unquoted Argument`_
+ or a `Quoted Argument`_ immediately following a `Quoted Argument`_ and
+ not separated by any whitespace. For compatibility, CMake 2.8.12 and
+ higher accept such code but produce a warning.
+
+Command Arguments
+-----------------
+
+There are three types of arguments within `Command Invocations`_:
+
+.. raw:: latex
+
+ \begin{small}
+
+.. productionlist::
+ argument: `bracket_argument` | `quoted_argument` | `unquoted_argument`
+
+.. raw:: latex
+
+ \end{small}
+
+.. _`Bracket Argument`:
+
+Bracket Argument
+^^^^^^^^^^^^^^^^
+
+A *bracket argument*, inspired by `Lua`_ long bracket syntax,
+encloses content between opening and closing "brackets" of the
+same length:
+
+.. raw:: latex
+
+ \begin{small}
+
+.. productionlist::
+ bracket_argument: `bracket_open` `bracket_content` `bracket_close`
+ bracket_open: '[' '='* '['
+ bracket_content: <any text not containing a `bracket_close` with
+ : the same number of '=' as the `bracket_open`>
+ bracket_close: ']' '='* ']'
+
+.. raw:: latex
+
+ \end{small}
+
+An opening bracket is written ``[`` followed by zero or more ``=`` followed
+by ``[``. The corresponding closing bracket is written ``]`` followed
+by the same number of ``=`` followed by ``]``.
+Brackets do not nest. A unique length may always be chosen
+for the opening and closing brackets to contain closing brackets
+of other lengths.
+
+Bracket argument content consists of all text between the opening
+and closing brackets, except that one newline immediately following
+the opening bracket, if any, is ignored. No evaluation of the
+enclosed content, such as `Escape Sequences`_ or `Variable References`_,
+is performed. A bracket argument is always given to the command
+invocation as exactly one argument.
+
+.. No code-block syntax highlighting in the following example
+ (long string literal not supported by our cmake.py)
+
+For example::
+
+ message([=[
+ This is the first line in a bracket argument with bracket length 1.
+ No \-escape sequences or ${variable} references are evaluated.
+ This is always one argument even though it contains a ; character.
+ The text does not end on a closing bracket of length 0 like ]].
+ It does end in a closing bracket of length 1.
+ ]=])
+
+.. note::
+ CMake versions prior to 3.0 do not support bracket arguments.
+ They interpret the opening bracket as the start of an
+ `Unquoted Argument`_.
+
+.. _`Lua`: http://www.lua.org/
+
+.. _`Quoted Argument`:
+
+Quoted Argument
+^^^^^^^^^^^^^^^
+
+A *quoted argument* encloses content between opening and closing
+double-quote characters:
+
+.. raw:: latex
+
+ \begin{small}
+
+.. productionlist::
+ quoted_argument: '"' `quoted_element`* '"'
+ quoted_element: <any character except '\' or '"'> |
+ : `escape_sequence` |
+ : `quoted_continuation`
+ quoted_continuation: '\' `newline`
+
+.. raw:: latex
+
+ \end{small}
+
+Quoted argument content consists of all text between opening and
+closing quotes. Both `Escape Sequences`_ and `Variable References`_
+are evaluated. A quoted argument is always given to the command
+invocation as exactly one argument.
+
+.. No code-block syntax highlighting in the following example
+ (escape \" not supported by our cmake.py)
+
+For example:
+
+.. code-block:: cmake
+
+ message("This is a quoted argument containing multiple lines.
+ This is always one argument even though it contains a ; character.
+ Both \\-escape sequences and ${variable} references are evaluated.
+ The text does not end on an escaped double-quote like \".
+ It does end in an unescaped double quote.
+ ")
+
+.. No code-block syntax highlighting in the following example
+ (for conformity with the two above examples)
+
+The final ``\`` on any line ending in an odd number of backslashes
+is treated as a line continuation and ignored along with the
+immediately following newline character. For example:
+
+.. code-block:: cmake
+
+ message("\
+ This is the first line of a quoted argument. \
+ In fact it is the only line but since it is long \
+ the source code uses line continuation.\
+ ")
+
+.. note::
+ CMake versions prior to 3.0 do not support continuation with ``\``.
+ They report errors in quoted arguments containing lines ending in
+ an odd number of ``\`` characters.
+
+.. _`Unquoted Argument`:
+
+Unquoted Argument
+^^^^^^^^^^^^^^^^^
+
+An *unquoted argument* is not enclosed by any quoting syntax.
+It may not contain any whitespace, ``(``, ``)``, ``#``, ``"``, or ``\``
+except when escaped by a backslash:
+
+.. raw:: latex
+
+ \begin{small}
+
+.. productionlist::
+ unquoted_argument: `unquoted_element`+ | `unquoted_legacy`
+ unquoted_element: <any character except whitespace or one of '()#"\'> |
+ : `escape_sequence`
+ unquoted_legacy: <see note in text>
+
+.. raw:: latex
+
+ \end{small}
+
+Unquoted argument content consists of all text in a contiguous block
+of allowed or escaped characters. Both `Escape Sequences`_ and
+`Variable References`_ are evaluated. The resulting value is divided
+in the same way `Lists`_ divide into elements. Each non-empty element
+is given to the command invocation as an argument. Therefore an
+unquoted argument may be given to a command invocation as zero or
+more arguments.
+
+For example:
+
+.. code-block:: cmake
+
+ foreach(arg
+ NoSpace
+ Escaped\ Space
+ This;Divides;Into;Five;Arguments
+ Escaped\;Semicolon
+ )
+ message("${arg}")
+ endforeach()
+
+.. note::
+ To support legacy CMake code, unquoted arguments may also contain
+ double-quoted strings (``"..."``, possibly enclosing horizontal
+ whitespace), and make-style variable references (``$(MAKEVAR)``).
+
+ Unescaped double-quotes must balance, may not appear at the
+ beginning of an unquoted argument, and are treated as part of the
+ content. For example, the unquoted arguments ``-Da="b c"``,
+ ``-Da=$(v)``, and ``a" "b"c"d`` are each interpreted literally.
+ They may instead be written as quoted arguments ``"-Da=\"b c\""``,
+ ``"-Da=$(v)"``, and ``"a\" \"b\"c\"d"``, respectively.
+
+ Make-style references are treated literally as part of the content
+ and do not undergo variable expansion. They are treated as part
+ of a single argument (rather than as separate ``$``, ``(``,
+ ``MAKEVAR``, and ``)`` arguments).
+
+ The above "unquoted_legacy" production represents such arguments.
+ We do not recommend using legacy unquoted arguments in new code.
+ Instead use a `Quoted Argument`_ or a `Bracket Argument`_ to
+ represent the content.
+
+.. _`Escape Sequences`:
+
+Escape Sequences
+----------------
+
+An *escape sequence* is a ``\`` followed by one character:
+
+.. raw:: latex
+
+ \begin{small}
+
+.. productionlist::
+ escape_sequence: `escape_identity` | `escape_encoded` | `escape_semicolon`
+ escape_identity: '\' <match '[^A-Za-z0-9;]'>
+ escape_encoded: '\t' | '\r' | '\n'
+ escape_semicolon: '\;'
+
+.. raw:: latex
+
+ \end{small}
+
+A ``\`` followed by a non-alphanumeric character simply encodes the literal
+character without interpreting it as syntax. A ``\t``, ``\r``, or ``\n``
+encodes a tab, carriage return, or newline character, respectively. A ``\;``
+outside of any `Variable References`_ encodes itself but may be used in an
+`Unquoted Argument`_ to encode the ``;`` without dividing the argument
+value on it. A ``\;`` inside `Variable References`_ encodes the literal
+``;`` character. (See also policy :policy:`CMP0053` documentation for
+historical considerations.)
+
+.. _`Variable References`:
+
+Variable References
+-------------------
+
+A *variable reference* has the form ``${<variable>}`` and is
+evaluated inside a `Quoted Argument`_ or an `Unquoted Argument`_.
+A variable reference is replaced by the value of the variable,
+or by the empty string if the variable is not set.
+Variable references can nest and are evaluated from the
+inside out, e.g. ``${outer_${inner_variable}_variable}``.
+
+Literal variable references may consist of alphanumeric characters,
+the characters ``/_.+-``, and `Escape Sequences`_. Nested references
+may be used to evaluate variables of any name. See also policy
+:policy:`CMP0053` documentation for historical considerations and reasons why
+the ``$`` is also technically permitted but is discouraged.
+
+The `Variables`_ section documents the scope of variable names
+and how their values are set.
+
+An *environment variable reference* has the form ``$ENV{<variable>}``.
+See the `Environment Variables`_ section for more information.
+
+A *cache variable reference* has the form ``$CACHE{<variable>}``.
+See :variable:`CACHE` for more information.
+
+The :command:`if` command has a special condition syntax that
+allows for variable references in the short form ``<variable>``
+instead of ``${<variable>}``.
+However, environment and cache variables always need to be
+referenced as ``$ENV{<variable>}`` or ``$CACHE{<variable>}``.
+
+Comments
+--------
+
+A comment starts with a ``#`` character that is not inside a
+`Bracket Argument`_, `Quoted Argument`_, or escaped with ``\``
+as part of an `Unquoted Argument`_. There are two types of
+comments: a `Bracket Comment`_ and a `Line Comment`_.
+
+.. _`Bracket Comment`:
+
+Bracket Comment
+^^^^^^^^^^^^^^^
+
+A ``#`` immediately followed by a :token:`bracket_open` forms a
+*bracket comment* consisting of the entire bracket enclosure:
+
+.. raw:: latex
+
+ \begin{small}
+
+.. productionlist::
+ bracket_comment: '#' `bracket_argument`
+
+.. raw:: latex
+
+ \end{small}
+
+For example:
+
+::
+
+ #[[This is a bracket comment.
+ It runs until the close bracket.]]
+ message("First Argument\n" #[[Bracket Comment]] "Second Argument")
+
+.. note::
+ CMake versions prior to 3.0 do not support bracket comments.
+ They interpret the opening ``#`` as the start of a `Line Comment`_.
+
+.. _`Line Comment`:
+
+Line Comment
+^^^^^^^^^^^^
+
+A ``#`` not immediately followed by a :token:`bracket_open` forms a
+*line comment* that runs until the end of the line:
+
+.. raw:: latex
+
+ \begin{small}
+
+.. productionlist::
+ line_comment: '#' <any text not starting in a `bracket_open`
+ : and not containing a `newline`>
+
+.. raw:: latex
+
+ \end{small}
+
+For example:
+
+.. code-block:: cmake
+
+ # This is a line comment.
+ message("First Argument\n" # This is a line comment :)
+ "Second Argument") # This is a line comment.
+
+Control Structures
+==================
+
+Conditional Blocks
+------------------
+
+The :command:`if`/:command:`elseif`/:command:`else`/:command:`endif`
+commands delimit code blocks to be executed conditionally.
+
+Loops
+-----
+
+The :command:`foreach`/:command:`endforeach` and
+:command:`while`/:command:`endwhile` commands delimit code
+blocks to be executed in a loop. Inside such blocks the
+:command:`break` command may be used to terminate the loop
+early whereas the :command:`continue` command may be used
+to start with the next iteration immediately.
+
+Command Definitions
+-------------------
+
+The :command:`macro`/:command:`endmacro`, and
+:command:`function`/:command:`endfunction` commands delimit
+code blocks to be recorded for later invocation as commands.
+
+.. _`CMake Language Variables`:
+
+Variables
+=========
+
+Variables are the basic unit of storage in the CMake Language.
+Their values are always of string type, though some commands may
+interpret the strings as values of other types.
+The :command:`set` and :command:`unset` commands explicitly
+set or unset a variable, but other commands have semantics
+that modify variables as well.
+Variable names are case-sensitive and may consist of almost
+any text, but we recommend sticking to names consisting only
+of alphanumeric characters plus ``_`` and ``-``.
+
+Variables have dynamic scope. Each variable "set" or "unset"
+creates a binding in the current scope:
+
+Function Scope
+ `Command Definitions`_ created by the :command:`function` command
+ create commands that, when invoked, process the recorded commands
+ in a new variable binding scope. A variable "set" or "unset"
+ binds in this scope and is visible for the current function and
+ any nested calls within it, but not after the function returns.
+
+Directory Scope
+ Each of the `Directories`_ in a source tree has its own variable
+ bindings. Before processing the ``CMakeLists.txt`` file for a
+ directory, CMake copies all variable bindings currently defined
+ in the parent directory, if any, to initialize the new directory
+ scope. CMake `Scripts`_, when processed with ``cmake -P``, bind
+ variables in one "directory" scope.
+
+ A variable "set" or "unset" not inside a function call binds
+ to the current directory scope.
+
+Persistent Cache
+ CMake stores a separate set of "cache" variables, or "cache entries",
+ whose values persist across multiple runs within a project build
+ tree. Cache entries have an isolated binding scope modified only
+ by explicit request, such as by the ``CACHE`` option of the
+ :command:`set` and :command:`unset` commands.
+
+When evaluating `Variable References`_, CMake first searches the
+function call stack, if any, for a binding and then falls back
+to the binding in the current directory scope, if any. If a
+"set" binding is found, its value is used. If an "unset" binding
+is found, or no binding is found, CMake then searches for a
+cache entry. If a cache entry is found, its value is used.
+Otherwise, the variable reference evaluates to an empty string.
+The ``$CACHE{VAR}`` syntax can be used to do direct cache entry
+lookups.
+
+The :manual:`cmake-variables(7)` manual documents the many variables
+that are provided by CMake or have meaning to CMake when set
+by project code.
+
+.. include:: ID_RESERVE.txt
+
+.. _`CMake Language Environment Variables`:
+
+Environment Variables
+=====================
+
+Environment Variables are like ordinary `Variables`_, with the
+following differences:
+
+Scope
+ Environment variables have global scope in a CMake process.
+ They are never cached.
+
+References
+ `Variable References`_ have the form ``$ENV{<variable>}``.
+
+Initialization
+ Initial values of the CMake environment variables are those of
+ the calling process.
+ Values can be changed using the :command:`set` and :command:`unset`
+ commands.
+ These commands only affect the running CMake process,
+ not the system environment at large.
+ Changed values are not written back to the calling process,
+ and they are not seen by subsequent build or test processes.
+
+The :manual:`cmake-env-variables(7)` manual documents environment
+variables that have special meaning to CMake.
+
+.. _`CMake Language Lists`:
+
+Lists
+=====
+
+Although all values in CMake are stored as strings, a string
+may be treated as a list in certain contexts, such as during
+evaluation of an `Unquoted Argument`_. In such contexts, a string
+is divided into list elements by splitting on ``;`` characters not
+following an unequal number of ``[`` and ``]`` characters and not
+immediately preceded by a ``\``. The sequence ``\;`` does not
+divide a value but is replaced by ``;`` in the resulting element.
+
+A list of elements is represented as a string by concatenating
+the elements separated by ``;``. For example, the :command:`set`
+command stores multiple values into the destination variable
+as a list:
+
+.. code-block:: cmake
+
+ set(srcs a.c b.c c.c) # sets "srcs" to "a.c;b.c;c.c"
+
+Lists are meant for simple use cases such as a list of source
+files and should not be used for complex data processing tasks.
+Most commands that construct lists do not escape ``;`` characters
+in list elements, thus flattening nested lists:
+
+.. code-block:: cmake
+
+ set(x a "b;c") # sets "x" to "a;b;c", not "a;b\;c"
diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst
new file mode 100644
index 0000000..17c1a1e
--- /dev/null
+++ b/Help/manual/cmake-modules.7.rst
@@ -0,0 +1,322 @@
+.. cmake-manual-description: CMake Modules Reference
+
+cmake-modules(7)
+****************
+
+The modules listed here are part of the CMake distribution.
+Projects may provide further modules; their location(s)
+can be specified in the :variable:`CMAKE_MODULE_PATH` variable.
+
+Utility Modules
+^^^^^^^^^^^^^^^
+
+These modules are loaded using the :command:`include` command.
+
+.. toctree::
+ :maxdepth: 1
+
+ /module/AndroidTestUtilities
+ /module/BundleUtilities
+ /module/CheckCCompilerFlag
+ /module/CheckCompilerFlag
+ /module/CheckCSourceCompiles
+ /module/CheckCSourceRuns
+ /module/CheckCXXCompilerFlag
+ /module/CheckCXXSourceCompiles
+ /module/CheckCXXSourceRuns
+ /module/CheckCXXSymbolExists
+ /module/CheckFortranCompilerFlag
+ /module/CheckFortranFunctionExists
+ /module/CheckFortranSourceCompiles
+ /module/CheckFortranSourceRuns
+ /module/CheckFunctionExists
+ /module/CheckIncludeFileCXX
+ /module/CheckIncludeFile
+ /module/CheckIncludeFiles
+ /module/CheckIPOSupported
+ /module/CheckLanguage
+ /module/CheckLibraryExists
+ /module/CheckLinkerFlag
+ /module/CheckOBJCCompilerFlag
+ /module/CheckOBJCSourceCompiles
+ /module/CheckOBJCSourceRuns
+ /module/CheckOBJCXXCompilerFlag
+ /module/CheckOBJCXXSourceCompiles
+ /module/CheckOBJCXXSourceRuns
+ /module/CheckPIESupported
+ /module/CheckPrototypeDefinition
+ /module/CheckSourceCompiles
+ /module/CheckSourceRuns
+ /module/CheckStructHasMember
+ /module/CheckSymbolExists
+ /module/CheckTypeSize
+ /module/CheckVariableExists
+ /module/CMakeAddFortranSubdirectory
+ /module/CMakeBackwardCompatibilityCXX
+ /module/CMakeDependentOption
+ /module/CMakeFindDependencyMacro
+ /module/CMakeFindFrameworks
+ /module/CMakeFindPackageMode
+ /module/CMakeGraphVizOptions
+ /module/CMakePackageConfigHelpers
+ /module/CMakePrintHelpers
+ /module/CMakePrintSystemInformation
+ /module/CMakePushCheckState
+ /module/CMakeVerifyManifest
+ /module/CPack
+ /module/CPackComponent
+ /module/CPackIFW
+ /module/CPackIFWConfigureFile
+ /module/CSharpUtilities
+ /module/CTest
+ /module/CTestCoverageCollectGCOV
+ /module/CTestScriptMode
+ /module/CTestUseLaunchers
+ /module/Dart
+ /module/DeployQt4
+ /module/ExternalData
+ /module/ExternalProject
+ /module/FeatureSummary
+ /module/FetchContent
+ /module/FindPackageHandleStandardArgs
+ /module/FindPackageMessage
+ /module/FortranCInterface
+ /module/GenerateExportHeader
+ /module/GetPrerequisites
+ /module/GNUInstallDirs
+ /module/GoogleTest
+ /module/InstallRequiredSystemLibraries
+ /module/ProcessorCount
+ /module/SelectLibraryConfigurations
+ /module/SquishTestScript
+ /module/TestBigEndian
+ /module/TestForANSIForScope
+ /module/TestForANSIStreamHeaders
+ /module/TestForSSTREAM
+ /module/TestForSTDNamespace
+ /module/UseEcos
+ /module/UseJava
+ /module/UseSWIG
+ /module/UsewxWidgets
+
+Find Modules
+^^^^^^^^^^^^
+
+These modules search for third-party software.
+They are normally called through the :command:`find_package` command.
+
+.. toctree::
+ :maxdepth: 1
+
+ /module/FindALSA
+ /module/FindArmadillo
+ /module/FindASPELL
+ /module/FindAVIFile
+ /module/FindBacktrace
+ /module/FindBISON
+ /module/FindBLAS
+ /module/FindBoost
+ /module/FindBullet
+ /module/FindBZip2
+ /module/FindCABLE
+ /module/FindCoin3D
+ /module/FindCUDAToolkit
+ /module/FindCups
+ /module/FindCURL
+ /module/FindCurses
+ /module/FindCVS
+ /module/FindCxxTest
+ /module/FindCygwin
+ /module/FindDart
+ /module/FindDCMTK
+ /module/FindDevIL
+ /module/FindDoxygen
+ /module/FindEnvModules
+ /module/FindEXPAT
+ /module/FindFLEX
+ /module/FindFLTK
+ /module/FindFLTK2
+ /module/FindFontconfig
+ /module/FindFreetype
+ /module/FindGCCXML
+ /module/FindGDAL
+ /module/FindGettext
+ /module/FindGIF
+ /module/FindGit
+ /module/FindGLEW
+ /module/FindGLUT
+ /module/FindGnuplot
+ /module/FindGnuTLS
+ /module/FindGSL
+ /module/FindGTest
+ /module/FindGTK
+ /module/FindGTK2
+ /module/FindHDF5
+ /module/FindHg
+ /module/FindHSPELL
+ /module/FindHTMLHelp
+ /module/FindIce
+ /module/FindIconv
+ /module/FindIcotool
+ /module/FindICU
+ /module/FindImageMagick
+ /module/FindIntl
+ /module/FindITK
+ /module/FindJasper
+ /module/FindJava
+ /module/FindJNI
+ /module/FindJPEG
+ /module/FindKDE3
+ /module/FindKDE4
+ /module/FindLAPACK
+ /module/FindLATEX
+ /module/FindLibArchive
+ /module/FindLibinput
+ /module/FindLibLZMA
+ /module/FindLibXml2
+ /module/FindLibXslt
+ /module/FindLTTngUST
+ /module/FindLua
+ /module/FindLua50
+ /module/FindLua51
+ /module/FindMatlab
+ /module/FindMFC
+ /module/FindMotif
+ /module/FindMPEG
+ /module/FindMPEG2
+ /module/FindMPI
+ /module/FindODBC
+ /module/FindOpenACC
+ /module/FindOpenAL
+ /module/FindOpenCL
+ /module/FindOpenGL
+ /module/FindOpenMP
+ /module/FindOpenSceneGraph
+ /module/FindOpenSSL
+ /module/FindOpenThreads
+ /module/Findosg
+ /module/Findosg_functions
+ /module/FindosgAnimation
+ /module/FindosgDB
+ /module/FindosgFX
+ /module/FindosgGA
+ /module/FindosgIntrospection
+ /module/FindosgManipulator
+ /module/FindosgParticle
+ /module/FindosgPresentation
+ /module/FindosgProducer
+ /module/FindosgQt
+ /module/FindosgShadow
+ /module/FindosgSim
+ /module/FindosgTerrain
+ /module/FindosgText
+ /module/FindosgUtil
+ /module/FindosgViewer
+ /module/FindosgVolume
+ /module/FindosgWidget
+ /module/FindPatch
+ /module/FindPerl
+ /module/FindPerlLibs
+ /module/FindPHP4
+ /module/FindPhysFS
+ /module/FindPike
+ /module/FindPkgConfig
+ /module/FindPNG
+ /module/FindPostgreSQL
+ /module/FindProducer
+ /module/FindProtobuf
+ /module/FindPython
+ /module/FindPython2
+ /module/FindPython3
+ /module/FindQt3
+ /module/FindQt4
+ /module/FindQuickTime
+ /module/FindRTI
+ /module/FindRuby
+ /module/FindSDL
+ /module/FindSDL_image
+ /module/FindSDL_mixer
+ /module/FindSDL_net
+ /module/FindSDL_sound
+ /module/FindSDL_ttf
+ /module/FindSelfPackers
+ /module/FindSquish
+ /module/FindSQLite3
+ /module/FindSubversion
+ /module/FindSWIG
+ /module/FindTCL
+ /module/FindTclsh
+ /module/FindTclStub
+ /module/FindThreads
+ /module/FindTIFF
+ /module/FindUnixCommands
+ /module/FindVTK
+ /module/FindVulkan
+ /module/FindWget
+ /module/FindWish
+ /module/FindwxWidgets
+ /module/FindX11
+ /module/FindXalanC
+ /module/FindXCTest
+ /module/FindXercesC
+ /module/FindXMLRPC
+ /module/FindZLIB
+
+Deprecated Modules
+^^^^^^^^^^^^^^^^^^^
+
+Deprecated Utility Modules
+==========================
+
+.. toctree::
+ :maxdepth: 1
+
+ /module/AddFileDependencies
+ /module/CMakeDetermineVSServicePack
+ /module/CMakeExpandImportedTargets
+ /module/CMakeForceCompiler
+ /module/CMakeParseArguments
+ /module/Documentation
+ /module/MacroAddFileDependencies
+ /module/TestCXXAcceptsFlag
+ /module/UseJavaClassFilelist
+ /module/UseJavaSymlinks
+ /module/UsePkgConfig
+ /module/Use_wxWindows
+ /module/WriteBasicConfigVersionFile
+ /module/WriteCompilerDetectionHeader
+
+Deprecated Find Modules
+=======================
+
+.. toctree::
+ :maxdepth: 1
+
+ /module/FindCUDA
+ /module/FindPythonInterp
+ /module/FindPythonLibs
+ /module/FindQt
+ /module/FindwxWindows
+
+Legacy CPack Modules
+====================
+
+These modules used to be mistakenly exposed to the user, and have been moved
+out of user visibility. They are for CPack internal use, and should never be
+used directly.
+
+.. toctree::
+ :maxdepth: 1
+
+ /module/CPackArchive
+ /module/CPackBundle
+ /module/CPackCygwin
+ /module/CPackDeb
+ /module/CPackDMG
+ /module/CPackFreeBSD
+ /module/CPackNSIS
+ /module/CPackNuGet
+ /module/CPackPackageMaker
+ /module/CPackProductBuild
+ /module/CPackRPM
+ /module/CPackWIX
diff --git a/Help/manual/cmake-packages.7.rst b/Help/manual/cmake-packages.7.rst
new file mode 100644
index 0000000..4b2934a
--- /dev/null
+++ b/Help/manual/cmake-packages.7.rst
@@ -0,0 +1,719 @@
+.. cmake-manual-description: CMake Packages Reference
+
+cmake-packages(7)
+*****************
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+Packages provide dependency information to CMake based buildsystems. Packages
+are found with the :command:`find_package` command. The result of
+using :command:`find_package` is either a set of :prop_tgt:`IMPORTED` targets, or
+a set of variables corresponding to build-relevant information.
+
+Using Packages
+==============
+
+CMake provides direct support for two forms of packages,
+`Config-file Packages`_ and `Find-module Packages`_.
+Indirect support for ``pkg-config`` packages is also provided via
+the :module:`FindPkgConfig` module. In all cases, the basic form
+of :command:`find_package` calls is the same:
+
+.. code-block:: cmake
+
+ find_package(Qt4 4.7.0 REQUIRED) # CMake provides a Qt4 find-module
+ find_package(Qt5Core 5.1.0 REQUIRED) # Qt provides a Qt5 package config file.
+ find_package(LibXml2 REQUIRED) # Use pkg-config via the LibXml2 find-module
+
+In cases where it is known that a package configuration file is provided by
+upstream, and only that should be used, the ``CONFIG`` keyword may be passed
+to :command:`find_package`:
+
+.. code-block:: cmake
+
+ find_package(Qt5Core 5.1.0 CONFIG REQUIRED)
+ find_package(Qt5Gui 5.1.0 CONFIG)
+
+Similarly, the ``MODULE`` keyword says to use only a find-module:
+
+.. code-block:: cmake
+
+ find_package(Qt4 4.7.0 MODULE REQUIRED)
+
+Specifying the type of package explicitly improves the error message shown to
+the user if it is not found.
+
+Both types of packages also support specifying components of a package,
+either after the ``REQUIRED`` keyword:
+
+.. code-block:: cmake
+
+ find_package(Qt5 5.1.0 CONFIG REQUIRED Widgets Xml Sql)
+
+or as a separate ``COMPONENTS`` list:
+
+.. code-block:: cmake
+
+ find_package(Qt5 5.1.0 COMPONENTS Widgets Xml Sql)
+
+or as a separate ``OPTIONAL_COMPONENTS`` list:
+
+.. code-block:: cmake
+
+ find_package(Qt5 5.1.0 COMPONENTS Widgets
+ OPTIONAL_COMPONENTS Xml Sql
+ )
+
+Handling of ``COMPONENTS`` and ``OPTIONAL_COMPONENTS`` is defined by the
+package.
+
+By setting the :variable:`CMAKE_DISABLE_FIND_PACKAGE_<PackageName>` variable to
+``TRUE``, the ``<PackageName>`` package will not be searched, and will always
+be ``NOTFOUND``.
+
+.. _`Config File Packages`:
+
+Config-file Packages
+--------------------
+
+A config-file package is a set of files provided by upstreams for downstreams
+to use. CMake searches in a number of locations for package configuration files, as
+described in the :command:`find_package` documentation. The most simple way for
+a CMake user to tell :manual:`cmake(1)` to search in a non-standard prefix for
+a package is to set the ``CMAKE_PREFIX_PATH`` cache variable.
+
+Config-file packages are provided by upstream vendors as part of development
+packages, that is, they belong with the header files and any other files
+provided to assist downstreams in using the package.
+
+A set of variables which provide package status information are also set
+automatically when using a config-file package. The ``<PackageName>_FOUND``
+variable is set to true or false, depending on whether the package was
+found. The ``<PackageName>_DIR`` cache variable is set to the location of the
+package configuration file.
+
+Find-module Packages
+--------------------
+
+A find module is a file with a set of rules for finding the required pieces of
+a dependency, primarily header files and libraries. Typically, a find module
+is needed when the upstream is not built with CMake, or is not CMake-aware
+enough to otherwise provide a package configuration file. Unlike a package configuration
+file, it is not shipped with upstream, but is used by downstream to find the
+files by guessing locations of files with platform-specific hints.
+
+Unlike the case of an upstream-provided package configuration file, no single point
+of reference identifies the package as being found, so the ``<PackageName>_FOUND``
+variable is not automatically set by the :command:`find_package` command. It
+can still be expected to be set by convention however and should be set by
+the author of the Find-module. Similarly there is no ``<PackageName>_DIR`` variable,
+but each of the artifacts such as library locations and header file locations
+provide a separate cache variable.
+
+See the :manual:`cmake-developer(7)` manual for more information about creating
+Find-module files.
+
+Package Layout
+==============
+
+A config-file package consists of a `Package Configuration File`_ and
+optionally a `Package Version File`_ provided with the project distribution.
+
+Package Configuration File
+--------------------------
+
+Consider a project ``Foo`` that installs the following files::
+
+ <prefix>/include/foo-1.2/foo.h
+ <prefix>/lib/foo-1.2/libfoo.a
+
+It may also provide a CMake package configuration file::
+
+ <prefix>/lib/cmake/foo-1.2/FooConfig.cmake
+
+with content defining :prop_tgt:`IMPORTED` targets, or defining variables, such
+as:
+
+.. code-block:: cmake
+
+ # ...
+ # (compute PREFIX relative to file location)
+ # ...
+ set(Foo_INCLUDE_DIRS ${PREFIX}/include/foo-1.2)
+ set(Foo_LIBRARIES ${PREFIX}/lib/foo-1.2/libfoo.a)
+
+If another project wishes to use ``Foo`` it need only to locate the ``FooConfig.cmake``
+file and load it to get all the information it needs about package content
+locations. Since the package configuration file is provided by the package
+installation it already knows all the file locations.
+
+The :command:`find_package` command may be used to search for the package
+configuration file. This command constructs a set of installation prefixes
+and searches under each prefix in several locations. Given the name ``Foo``,
+it looks for a file called ``FooConfig.cmake`` or ``foo-config.cmake``.
+The full set of locations is specified in the :command:`find_package` command
+documentation. One place it looks is::
+
+ <prefix>/lib/cmake/Foo*/
+
+where ``Foo*`` is a case-insensitive globbing expression. In our example the
+globbing expression will match ``<prefix>/lib/cmake/foo-1.2`` and the package
+configuration file will be found.
+
+Once found, a package configuration file is immediately loaded. It, together
+with a package version file, contains all the information the project needs to
+use the package.
+
+Package Version File
+--------------------
+
+When the :command:`find_package` command finds a candidate package configuration
+file it looks next to it for a version file. The version file is loaded to test
+whether the package version is an acceptable match for the version requested.
+If the version file claims compatibility the configuration file is accepted.
+Otherwise it is ignored.
+
+The name of the package version file must match that of the package configuration
+file but has either ``-version`` or ``Version`` appended to the name before
+the ``.cmake`` extension. For example, the files::
+
+ <prefix>/lib/cmake/foo-1.3/foo-config.cmake
+ <prefix>/lib/cmake/foo-1.3/foo-config-version.cmake
+
+and::
+
+ <prefix>/lib/cmake/bar-4.2/BarConfig.cmake
+ <prefix>/lib/cmake/bar-4.2/BarConfigVersion.cmake
+
+are each pairs of package configuration files and corresponding package version
+files.
+
+When the :command:`find_package` command loads a version file it first sets the
+following variables:
+
+``PACKAGE_FIND_NAME``
+ The ``<PackageName>``
+
+``PACKAGE_FIND_VERSION``
+ Full requested version string
+
+``PACKAGE_FIND_VERSION_MAJOR``
+ Major version if requested, else 0
+
+``PACKAGE_FIND_VERSION_MINOR``
+ Minor version if requested, else 0
+
+``PACKAGE_FIND_VERSION_PATCH``
+ Patch version if requested, else 0
+
+``PACKAGE_FIND_VERSION_TWEAK``
+ Tweak version if requested, else 0
+
+``PACKAGE_FIND_VERSION_COUNT``
+ Number of version components, 0 to 4
+
+The version file must use these variables to check whether it is compatible or
+an exact match for the requested version and set the following variables with
+results:
+
+``PACKAGE_VERSION``
+ Full provided version string
+
+``PACKAGE_VERSION_EXACT``
+ True if version is exact match
+
+``PACKAGE_VERSION_COMPATIBLE``
+ True if version is compatible
+
+``PACKAGE_VERSION_UNSUITABLE``
+ True if unsuitable as any version
+
+Version files are loaded in a nested scope so they are free to set any variables
+they wish as part of their computation. The find_package command wipes out the
+scope when the version file has completed and it has checked the output
+variables. When the version file claims to be an acceptable match for the
+requested version the find_package command sets the following variables for
+use by the project:
+
+``<PackageName>_VERSION``
+ Full provided version string
+
+``<PackageName>_VERSION_MAJOR``
+ Major version if provided, else 0
+
+``<PackageName>_VERSION_MINOR``
+ Minor version if provided, else 0
+
+``<PackageName>_VERSION_PATCH``
+ Patch version if provided, else 0
+
+``<PackageName>_VERSION_TWEAK``
+ Tweak version if provided, else 0
+
+``<PackageName>_VERSION_COUNT``
+ Number of version components, 0 to 4
+
+The variables report the version of the package that was actually found.
+The ``<PackageName>`` part of their name matches the argument given to the
+:command:`find_package` command.
+
+.. _`Creating Packages`:
+
+Creating Packages
+=================
+
+Usually, the upstream depends on CMake itself and can use some CMake facilities
+for creating the package files. Consider an upstream which provides a single
+shared library:
+
+.. code-block:: cmake
+
+ project(UpstreamLib)
+
+ set(CMAKE_INCLUDE_CURRENT_DIR ON)
+ set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
+
+ set(Upstream_VERSION 3.4.1)
+
+ include(GenerateExportHeader)
+
+ add_library(ClimbingStats SHARED climbingstats.cpp)
+ generate_export_header(ClimbingStats)
+ set_property(TARGET ClimbingStats PROPERTY VERSION ${Upstream_VERSION})
+ set_property(TARGET ClimbingStats PROPERTY SOVERSION 3)
+ set_property(TARGET ClimbingStats PROPERTY
+ INTERFACE_ClimbingStats_MAJOR_VERSION 3)
+ set_property(TARGET ClimbingStats APPEND PROPERTY
+ COMPATIBLE_INTERFACE_STRING ClimbingStats_MAJOR_VERSION
+ )
+
+ install(TARGETS ClimbingStats EXPORT ClimbingStatsTargets
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib
+ RUNTIME DESTINATION bin
+ INCLUDES DESTINATION include
+ )
+ install(
+ FILES
+ climbingstats.h
+ "${CMAKE_CURRENT_BINARY_DIR}/climbingstats_export.h"
+ DESTINATION
+ include
+ COMPONENT
+ Devel
+ )
+
+ include(CMakePackageConfigHelpers)
+ write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/ClimbingStats/ClimbingStatsConfigVersion.cmake"
+ VERSION ${Upstream_VERSION}
+ COMPATIBILITY AnyNewerVersion
+ )
+
+ export(EXPORT ClimbingStatsTargets
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/ClimbingStats/ClimbingStatsTargets.cmake"
+ NAMESPACE Upstream::
+ )
+ configure_file(cmake/ClimbingStatsConfig.cmake
+ "${CMAKE_CURRENT_BINARY_DIR}/ClimbingStats/ClimbingStatsConfig.cmake"
+ COPYONLY
+ )
+
+ set(ConfigPackageLocation lib/cmake/ClimbingStats)
+ install(EXPORT ClimbingStatsTargets
+ FILE
+ ClimbingStatsTargets.cmake
+ NAMESPACE
+ Upstream::
+ DESTINATION
+ ${ConfigPackageLocation}
+ )
+ install(
+ FILES
+ cmake/ClimbingStatsConfig.cmake
+ "${CMAKE_CURRENT_BINARY_DIR}/ClimbingStats/ClimbingStatsConfigVersion.cmake"
+ DESTINATION
+ ${ConfigPackageLocation}
+ COMPONENT
+ Devel
+ )
+
+The :module:`CMakePackageConfigHelpers` module provides a macro for creating
+a simple ``ConfigVersion.cmake`` file. This file sets the version of the
+package. It is read by CMake when :command:`find_package` is called to
+determine the compatibility with the requested version, and to set some
+version-specific variables ``<PackageName>_VERSION``, ``<PackageName>_VERSION_MAJOR``,
+``<PackageName>_VERSION_MINOR`` etc. The :command:`install(EXPORT)` command is
+used to export the targets in the ``ClimbingStatsTargets`` export-set, defined
+previously by the :command:`install(TARGETS)` command. This command generates
+the ``ClimbingStatsTargets.cmake`` file to contain :prop_tgt:`IMPORTED`
+targets, suitable for use by downstreams and arranges to install it to
+``lib/cmake/ClimbingStats``. The generated ``ClimbingStatsConfigVersion.cmake``
+and a ``cmake/ClimbingStatsConfig.cmake`` are installed to the same location,
+completing the package.
+
+The generated :prop_tgt:`IMPORTED` targets have appropriate properties set
+to define their :ref:`usage requirements <Target Usage Requirements>`, such as
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`,
+:prop_tgt:`INTERFACE_COMPILE_DEFINITIONS` and other relevant built-in
+``INTERFACE_`` properties. The ``INTERFACE`` variant of user-defined
+properties listed in :prop_tgt:`COMPATIBLE_INTERFACE_STRING` and
+other :ref:`Compatible Interface Properties` are also propagated to the
+generated :prop_tgt:`IMPORTED` targets. In the above case,
+``ClimbingStats_MAJOR_VERSION`` is defined as a string which must be
+compatible among the dependencies of any depender. By setting this custom
+defined user property in this version and in the next version of
+``ClimbingStats``, :manual:`cmake(1)` will issue a diagnostic if there is an
+attempt to use version 3 together with version 4. Packages can choose to
+employ such a pattern if different major versions of the package are designed
+to be incompatible.
+
+A ``NAMESPACE`` with double-colons is specified when exporting the targets
+for installation. This convention of double-colons gives CMake a hint that
+the name is an :prop_tgt:`IMPORTED` target when it is used by downstreams
+with the :command:`target_link_libraries` command. This way, CMake can
+issue a diagnostic if the package providing it has not yet been found.
+
+In this case, when using :command:`install(TARGETS)` the ``INCLUDES DESTINATION``
+was specified. This causes the ``IMPORTED`` targets to have their
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` populated with the ``include``
+directory in the :variable:`CMAKE_INSTALL_PREFIX`. When the ``IMPORTED``
+target is used by downstream, it automatically consumes the entries from
+that property.
+
+Creating a Package Configuration File
+-------------------------------------
+
+In this case, the ``ClimbingStatsConfig.cmake`` file could be as simple as:
+
+.. code-block:: cmake
+
+ include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStatsTargets.cmake")
+
+As this allows downstreams to use the ``IMPORTED`` targets. If any macros
+should be provided by the ``ClimbingStats`` package, they should
+be in a separate file which is installed to the same location as the
+``ClimbingStatsConfig.cmake`` file, and included from there.
+
+This can also be extended to cover dependencies:
+
+.. code-block:: cmake
+
+ # ...
+ add_library(ClimbingStats SHARED climbingstats.cpp)
+ generate_export_header(ClimbingStats)
+
+ find_package(Stats 2.6.4 REQUIRED)
+ target_link_libraries(ClimbingStats PUBLIC Stats::Types)
+
+As the ``Stats::Types`` target is a ``PUBLIC`` dependency of ``ClimbingStats``,
+downstreams must also find the ``Stats`` package and link to the ``Stats::Types``
+library. The ``Stats`` package should be found in the ``ClimbingStatsConfig.cmake``
+file to ensure this. The ``find_dependency`` macro from the
+:module:`CMakeFindDependencyMacro` helps with this by propagating
+whether the package is ``REQUIRED``, or ``QUIET`` etc. All ``REQUIRED``
+dependencies of a package should be found in the ``Config.cmake`` file:
+
+.. code-block:: cmake
+
+ include(CMakeFindDependencyMacro)
+ find_dependency(Stats 2.6.4)
+
+ include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStatsTargets.cmake")
+ include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStatsMacros.cmake")
+
+The ``find_dependency`` macro also sets ``ClimbingStats_FOUND`` to ``False`` if
+the dependency is not found, along with a diagnostic that the ``ClimbingStats``
+package can not be used without the ``Stats`` package.
+
+If ``COMPONENTS`` are specified when the downstream uses :command:`find_package`,
+they are listed in the ``<PackageName>_FIND_COMPONENTS`` variable. If a particular
+component is non-optional, then the ``<PackageName>_FIND_REQUIRED_<comp>`` will
+be true. This can be tested with logic in the package configuration file:
+
+.. code-block:: cmake
+
+ include(CMakeFindDependencyMacro)
+ find_dependency(Stats 2.6.4)
+
+ include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStatsTargets.cmake")
+ include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStatsMacros.cmake")
+
+ set(_supported_components Plot Table)
+
+ foreach(_comp ${ClimbingStats_FIND_COMPONENTS})
+ if (NOT ";${_supported_components};" MATCHES _comp)
+ set(ClimbingStats_FOUND False)
+ set(ClimbingStats_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}")
+ endif()
+ include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStats${_comp}Targets.cmake")
+ endforeach()
+
+Here, the ``ClimbingStats_NOT_FOUND_MESSAGE`` is set to a diagnosis that the package
+could not be found because an invalid component was specified. This message
+variable can be set for any case where the ``_FOUND`` variable is set to ``False``,
+and will be displayed to the user.
+
+Creating a Package Configuration File for the Build Tree
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The :command:`export(EXPORT)` command creates an :prop_tgt:`IMPORTED` targets
+definition file which is specific to the build-tree, and is not relocatable.
+This can similarly be used with a suitable package configuration file and
+package version file to define a package for the build tree which may be used
+without installation. Consumers of the build tree can simply ensure that the
+:variable:`CMAKE_PREFIX_PATH` contains the build directory, or set the
+``ClimbingStats_DIR`` to ``<build_dir>/ClimbingStats`` in the cache.
+
+.. _`Creating Relocatable Packages`:
+
+Creating Relocatable Packages
+-----------------------------
+
+A relocatable package must not reference absolute paths of files on
+the machine where the package is built that will not exist on the
+machines where the package may be installed.
+
+Packages created by :command:`install(EXPORT)` are designed to be relocatable,
+using paths relative to the location of the package itself. When defining
+the interface of a target for ``EXPORT``, keep in mind that the include
+directories should be specified as relative paths which are relative to the
+:variable:`CMAKE_INSTALL_PREFIX`:
+
+.. code-block:: cmake
+
+ target_include_directories(tgt INTERFACE
+ # Wrong, not relocatable:
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include/TgtName>
+ )
+
+ target_include_directories(tgt INTERFACE
+ # Ok, relocatable:
+ $<INSTALL_INTERFACE:include/TgtName>
+ )
+
+The ``$<INSTALL_PREFIX>``
+:manual:`generator expression <cmake-generator-expressions(7)>` may be used as
+a placeholder for the install prefix without resulting in a non-relocatable
+package. This is necessary if complex generator expressions are used:
+
+.. code-block:: cmake
+
+ target_include_directories(tgt INTERFACE
+ # Ok, relocatable:
+ $<INSTALL_INTERFACE:$<$<CONFIG:Debug>:$<INSTALL_PREFIX>/include/TgtName>>
+ )
+
+This also applies to paths referencing external dependencies.
+It is not advisable to populate any properties which may contain
+paths, such as :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` and
+:prop_tgt:`INTERFACE_LINK_LIBRARIES`, with paths relevant to dependencies.
+For example, this code may not work well for a relocatable package:
+
+.. code-block:: cmake
+
+ target_link_libraries(ClimbingStats INTERFACE
+ ${Foo_LIBRARIES} ${Bar_LIBRARIES}
+ )
+ target_include_directories(ClimbingStats INTERFACE
+ "$<INSTALL_INTERFACE:${Foo_INCLUDE_DIRS};${Bar_INCLUDE_DIRS}>"
+ )
+
+The referenced variables may contain the absolute paths to libraries
+and include directories **as found on the machine the package was made on**.
+This would create a package with hard-coded paths to dependencies and not
+suitable for relocation.
+
+Ideally such dependencies should be used through their own
+:ref:`IMPORTED targets <Imported Targets>` that have their own
+:prop_tgt:`IMPORTED_LOCATION` and usage requirement properties
+such as :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` populated
+appropriately. Those imported targets may then be used with
+the :command:`target_link_libraries` command for ``ClimbingStats``:
+
+.. code-block:: cmake
+
+ target_link_libraries(ClimbingStats INTERFACE Foo::Foo Bar::Bar)
+
+With this approach the package references its external dependencies
+only through the names of :ref:`IMPORTED targets <Imported Targets>`.
+When a consumer uses the installed package, the consumer will run the
+appropriate :command:`find_package` commands (via the ``find_dependency``
+macro described above) to find the dependencies and populate the
+imported targets with appropriate paths on their own machine.
+
+Unfortunately many :manual:`modules <cmake-modules(7)>` shipped with
+CMake do not yet provide :ref:`IMPORTED targets <Imported Targets>`
+because their development pre-dated this approach. This may improve
+incrementally over time. Workarounds to create relocatable packages
+using such modules include:
+
+* When building the package, specify each ``Foo_LIBRARY`` cache
+ entry as just a library name, e.g. ``-DFoo_LIBRARY=foo``. This
+ tells the corresponding find module to populate the ``Foo_LIBRARIES``
+ with just ``foo`` to ask the linker to search for the library
+ instead of hard-coding a path.
+
+* Or, after installing the package content but before creating the
+ package installation binary for redistribution, manually replace
+ the absolute paths with placeholders for substitution by the
+ installation tool when the package is installed.
+
+.. _`Package Registry`:
+
+Package Registry
+================
+
+CMake provides two central locations to register packages that have
+been built or installed anywhere on a system:
+
+* `User Package Registry`_
+* `System Package Registry`_
+
+The registries are especially useful to help projects find packages in
+non-standard install locations or directly in their own build trees.
+A project may populate either the user or system registry (using its own
+means, see below) to refer to its location.
+In either case the package should store at the registered location a
+`Package Configuration File`_ (``<PackageName>Config.cmake``) and optionally a
+`Package Version File`_ (``<PackageName>ConfigVersion.cmake``).
+
+The :command:`find_package` command searches the two package registries
+as two of the search steps specified in its documentation. If it has
+sufficient permissions it also removes stale package registry entries
+that refer to directories that do not exist or do not contain a matching
+package configuration file.
+
+.. _`User Package Registry`:
+
+User Package Registry
+---------------------
+
+The User Package Registry is stored in a per-user location.
+The :command:`export(PACKAGE)` command may be used to register a project
+build tree in the user package registry. CMake currently provides no
+interface to add install trees to the user package registry. Installers
+must be manually taught to register their packages if desired.
+
+On Windows the user package registry is stored in the Windows registry
+under a key in ``HKEY_CURRENT_USER``.
+
+A ``<PackageName>`` may appear under registry key::
+
+ HKEY_CURRENT_USER\Software\Kitware\CMake\Packages\<PackageName>
+
+as a ``REG_SZ`` value, with arbitrary name, that specifies the directory
+containing the package configuration file.
+
+On UNIX platforms the user package registry is stored in the user home
+directory under ``~/.cmake/packages``. A ``<PackageName>`` may appear under
+the directory::
+
+ ~/.cmake/packages/<PackageName>
+
+as a file, with arbitrary name, whose content specifies the directory
+containing the package configuration file.
+
+.. _`System Package Registry`:
+
+System Package Registry
+-----------------------
+
+The System Package Registry is stored in a system-wide location.
+CMake currently provides no interface to add to the system package registry.
+Installers must be manually taught to register their packages if desired.
+
+On Windows the system package registry is stored in the Windows registry
+under a key in ``HKEY_LOCAL_MACHINE``. A ``<PackageName>`` may appear under
+registry key::
+
+ HKEY_LOCAL_MACHINE\Software\Kitware\CMake\Packages\<PackageName>
+
+as a ``REG_SZ`` value, with arbitrary name, that specifies the directory
+containing the package configuration file.
+
+There is no system package registry on non-Windows platforms.
+
+.. _`Disabling the Package Registry`:
+
+Disabling the Package Registry
+------------------------------
+
+In some cases using the Package Registries is not desirable. CMake
+allows one to disable them using the following variables:
+
+* The :command:`export(PACKAGE)` command does not populate the user
+ package registry when :policy:`CMP0090` is set to ``NEW`` unless the
+ :variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` variable explicitly enables it.
+ When :policy:`CMP0090` is *not* set to ``NEW`` then
+ :command:`export(PACKAGE)` populates the user package registry unless
+ the :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable explicitly
+ disables it.
+* :variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY` disables the
+ User Package Registry in all the :command:`find_package` calls when
+ set to ``FALSE``.
+* Deprecated :variable:`CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY` disables the
+ User Package Registry in all the :command:`find_package` calls when set
+ to ``TRUE``. This variable is ignored when
+ :variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY` has been set.
+* :variable:`CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY` disables
+ the System Package Registry in all the :command:`find_package` calls.
+
+Package Registry Example
+------------------------
+
+A simple convention for naming package registry entries is to use content
+hashes. They are deterministic and unlikely to collide
+(:command:`export(PACKAGE)` uses this approach).
+The name of an entry referencing a specific directory is simply the content
+hash of the directory path itself.
+
+If a project arranges for package registry entries to exist, such as::
+
+ > reg query HKCU\Software\Kitware\CMake\Packages\MyPackage
+ HKEY_CURRENT_USER\Software\Kitware\CMake\Packages\MyPackage
+ 45e7d55f13b87179bb12f907c8de6fc4 REG_SZ c:/Users/Me/Work/lib/cmake/MyPackage
+ 7b4a9844f681c80ce93190d4e3185db9 REG_SZ c:/Users/Me/Work/MyPackage-build
+
+or::
+
+ $ cat ~/.cmake/packages/MyPackage/7d1fb77e07ce59a81bed093bbee945bd
+ /home/me/work/lib/cmake/MyPackage
+ $ cat ~/.cmake/packages/MyPackage/f92c1db873a1937f3100706657c63e07
+ /home/me/work/MyPackage-build
+
+then the ``CMakeLists.txt`` code:
+
+.. code-block:: cmake
+
+ find_package(MyPackage)
+
+will search the registered locations for package configuration files
+(``MyPackageConfig.cmake``). The search order among package registry
+entries for a single package is unspecified and the entry names
+(hashes in this example) have no meaning. Registered locations may
+contain package version files (``MyPackageConfigVersion.cmake``) to
+tell :command:`find_package` whether a specific location is suitable
+for the version requested.
+
+Package Registry Ownership
+--------------------------
+
+Package registry entries are individually owned by the project installations
+that they reference. A package installer is responsible for adding its own
+entry and the corresponding uninstaller is responsible for removing it.
+
+The :command:`export(PACKAGE)` command populates the user package registry
+with the location of a project build tree. Build trees tend to be deleted by
+developers and have no "uninstall" event that could trigger removal of their
+entries. In order to keep the registries clean the :command:`find_package`
+command automatically removes stale entries it encounters if it has sufficient
+permissions. CMake provides no interface to remove an entry referencing an
+existing build tree once :command:`export(PACKAGE)` has been invoked.
+However, if the project removes its package configuration file from the build
+tree then the entry referencing the location will be considered stale.
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
new file mode 100644
index 0000000..5dfa894
--- /dev/null
+++ b/Help/manual/cmake-policies.7.rst
@@ -0,0 +1,330 @@
+.. cmake-manual-description: CMake Policies Reference
+
+cmake-policies(7)
+*****************
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+Policies in CMake are used to preserve backward compatible behavior
+across multiple releases. When a new policy is introduced, newer CMake
+versions will begin to warn about the backward compatible behavior. It
+is possible to disable the warning by explicitly requesting the OLD, or
+backward compatible behavior using the :command:`cmake_policy` command.
+It is also possible to request ``NEW``, or non-backward compatible behavior
+for a policy, also avoiding the warning. Each policy can also be set to
+either ``NEW`` or ``OLD`` behavior explicitly on the command line with the
+:variable:`CMAKE_POLICY_DEFAULT_CMP<NNNN>` variable.
+
+A policy is a deprecation mechanism and not a reliable feature toggle.
+A policy should almost never be set to ``OLD``, except to silence warnings
+in an otherwise frozen or stable codebase, or temporarily as part of a
+larger migration path. The ``OLD`` behavior of each policy is undesirable
+and will be replaced with an error condition in a future release.
+
+The :command:`cmake_minimum_required` command does more than report an
+error if a too-old version of CMake is used to build a project. It
+also sets all policies introduced in that CMake version or earlier to
+``NEW`` behavior. To manage policies without increasing the minimum required
+CMake version, the :command:`if(POLICY)` command may be used:
+
+.. code-block:: cmake
+
+ if(POLICY CMP0990)
+ cmake_policy(SET CMP0990 NEW)
+ endif()
+
+This has the effect of using the ``NEW`` behavior with newer CMake releases which
+users may be using and not issuing a compatibility warning.
+
+The setting of a policy is confined in some cases to not propagate to the
+parent scope. For example, if the files read by the :command:`include` command
+or the :command:`find_package` command contain a use of :command:`cmake_policy`,
+that policy setting will not affect the caller by default. Both commands accept
+an optional ``NO_POLICY_SCOPE`` keyword to control this behavior.
+
+The :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` variable may also be used
+to determine whether to report an error on use of deprecated macros or
+functions.
+
+Policies Introduced by CMake 3.21
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0122: UseSWIG use standard library name conventions for csharp language. </policy/CMP0122>
+ CMP0121: The list command detects invalid indicies. </policy/CMP0121>
+
+Policies Introduced by CMake 3.20
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0120: The WriteCompilerDetectionHeader module is removed. </policy/CMP0120>
+ CMP0119: LANGUAGE source file property explicitly compiles as language. </policy/CMP0119>
+ CMP0118: The GENERATED source file property is now visible in all directories. </policy/CMP0118>
+ CMP0117: MSVC RTTI flag /GR is not added to CMAKE_CXX_FLAGS by default. </policy/CMP0117>
+ CMP0116: Ninja generators transform DEPFILEs from add_custom_command(). </policy/CMP0116>
+ CMP0115: Source file extensions must be explicit. </policy/CMP0115>
+
+Policies Introduced by CMake 3.19
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0114: ExternalProject step targets fully adopt their steps. </policy/CMP0114>
+ CMP0113: Makefile generators do not repeat custom commands from target dependencies. </policy/CMP0113>
+ CMP0112: Target file component generator expressions do not add target dependencies. </policy/CMP0112>
+ CMP0111: An imported target missing its location property fails during generation. </policy/CMP0111>
+ CMP0110: add_test() supports arbitrary characters in test names. </policy/CMP0110>
+ CMP0109: find_program() requires permission to execute but not to read. </policy/CMP0109>
+
+Policies Introduced by CMake 3.18
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0108: A target cannot link to itself through an alias. </policy/CMP0108>
+ CMP0107: An ALIAS target cannot overwrite another target. </policy/CMP0107>
+ CMP0106: The Documentation module is removed. </policy/CMP0106>
+ CMP0105: Device link step uses the link options. </policy/CMP0105>
+ CMP0104: CMAKE_CUDA_ARCHITECTURES now detected for NVCC, empty CUDA_ARCHITECTURES not allowed. </policy/CMP0104>
+ CMP0103: Multiple export() with same FILE without APPEND is not allowed. </policy/CMP0103>
+
+Policies Introduced by CMake 3.17
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0102: mark_as_advanced() does nothing if a cache entry does not exist. </policy/CMP0102>
+ CMP0101: target_compile_options honors BEFORE keyword in all scopes. </policy/CMP0101>
+ CMP0100: Let AUTOMOC and AUTOUIC process .hh header files. </policy/CMP0100>
+ CMP0099: Link properties are transitive over private dependency on static libraries. </policy/CMP0099>
+ CMP0098: FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing. </policy/CMP0098>
+
+Policies Introduced by CMake 3.16
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0097: ExternalProject_Add with GIT_SUBMODULES "" initializes no submodules. </policy/CMP0097>
+ CMP0096: project() preserves leading zeros in version components. </policy/CMP0096>
+ CMP0095: RPATH entries are properly escaped in the intermediary CMake install script. </policy/CMP0095>
+
+Policies Introduced by CMake 3.15
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0094: FindPython3, FindPython2 and FindPython use LOCATION for lookup strategy. </policy/CMP0094>
+ CMP0093: FindBoost reports Boost_VERSION in x.y.z format. </policy/CMP0093>
+ CMP0092: MSVC warning flags are not in CMAKE_{C,CXX}_FLAGS by default. </policy/CMP0092>
+ CMP0091: MSVC runtime library flags are selected by an abstraction. </policy/CMP0091>
+ CMP0090: export(PACKAGE) does not populate package registry by default. </policy/CMP0090>
+ CMP0089: Compiler id for IBM Clang-based XL compilers is now XLClang. </policy/CMP0089>
+
+Policies Introduced by CMake 3.14
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0088: FindBISON runs bison in CMAKE_CURRENT_BINARY_DIR when executing. </policy/CMP0088>
+ CMP0087: install(SCRIPT | CODE) supports generator expressions. </policy/CMP0087>
+ CMP0086: UseSWIG honors SWIG_MODULE_NAME via -module flag. </policy/CMP0086>
+ CMP0085: IN_LIST generator expression handles empty list items. </policy/CMP0085>
+ CMP0084: The FindQt module does not exist for find_package(). </policy/CMP0084>
+ CMP0083: Add PIE options when linking executable. </policy/CMP0083>
+ CMP0082: Install rules from add_subdirectory() are interleaved with those in caller. </policy/CMP0082>
+
+
+Policies Introduced by CMake 3.13
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0081: Relative paths not allowed in LINK_DIRECTORIES target property. </policy/CMP0081>
+ CMP0080: BundleUtilities cannot be included at configure time. </policy/CMP0080>
+ CMP0079: target_link_libraries allows use with targets in other directories. </policy/CMP0079>
+ CMP0078: UseSWIG generates standard target names. </policy/CMP0078>
+ CMP0077: option() honors normal variables. </policy/CMP0077>
+ CMP0076: target_sources() command converts relative paths to absolute. </policy/CMP0076>
+
+Policies Introduced by CMake 3.12
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0075: Include file check macros honor CMAKE_REQUIRED_LIBRARIES. </policy/CMP0075>
+ CMP0074: find_package uses PackageName_ROOT variables. </policy/CMP0074>
+ CMP0073: Do not produce legacy _LIB_DEPENDS cache entries. </policy/CMP0073>
+
+Policies Introduced by CMake 3.11
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0072: FindOpenGL prefers GLVND by default when available. </policy/CMP0072>
+
+Policies Introduced by CMake 3.10
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0071: Let AUTOMOC and AUTOUIC process GENERATED files. </policy/CMP0071>
+ CMP0070: Define file(GENERATE) behavior for relative paths. </policy/CMP0070>
+
+Policies Introduced by CMake 3.9
+================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0069: INTERPROCEDURAL_OPTIMIZATION is enforced when enabled. </policy/CMP0069>
+ CMP0068: RPATH settings on macOS do not affect install_name. </policy/CMP0068>
+
+Policies Introduced by CMake 3.8
+================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0067: Honor language standard in try_compile() source-file signature. </policy/CMP0067>
+
+Policies Introduced by CMake 3.7
+================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0066: Honor per-config flags in try_compile() source-file signature. </policy/CMP0066>
+
+Policies Introduced by CMake 3.4
+================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0065: Do not add flags to export symbols from executables without the ENABLE_EXPORTS target property. </policy/CMP0065>
+ CMP0064: Support new TEST if() operator. </policy/CMP0064>
+
+Policies Introduced by CMake 3.3
+================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0063: Honor visibility properties for all target types. </policy/CMP0063>
+ CMP0062: Disallow install() of export() result. </policy/CMP0062>
+ CMP0061: CTest does not by default tell make to ignore errors (-i). </policy/CMP0061>
+ CMP0060: Link libraries by full path even in implicit directories. </policy/CMP0060>
+ CMP0059: Do not treat DEFINITIONS as a built-in directory property. </policy/CMP0059>
+ CMP0058: Ninja requires custom command byproducts to be explicit. </policy/CMP0058>
+ CMP0057: Support new IN_LIST if() operator. </policy/CMP0057>
+
+Policies Introduced by CMake 3.2
+================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0056: Honor link flags in try_compile() source-file signature. </policy/CMP0056>
+ CMP0055: Strict checking for break() command. </policy/CMP0055>
+
+Policies Introduced by CMake 3.1
+================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0054: Only interpret if() arguments as variables or keywords when unquoted. </policy/CMP0054>
+ CMP0053: Simplify variable reference and escape sequence evaluation. </policy/CMP0053>
+ CMP0052: Reject source and build dirs in installed INTERFACE_INCLUDE_DIRECTORIES. </policy/CMP0052>
+ CMP0051: List TARGET_OBJECTS in SOURCES target property. </policy/CMP0051>
+
+Policies Introduced by CMake 3.0
+================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0050: Disallow add_custom_command SOURCE signatures. </policy/CMP0050>
+ CMP0049: Do not expand variables in target source entries. </policy/CMP0049>
+ CMP0048: project() command manages VERSION variables. </policy/CMP0048>
+ CMP0047: Use QCC compiler id for the qcc drivers on QNX. </policy/CMP0047>
+ CMP0046: Error on non-existent dependency in add_dependencies. </policy/CMP0046>
+ CMP0045: Error on non-existent target in get_target_property. </policy/CMP0045>
+ CMP0044: Case sensitive Lang_COMPILER_ID generator expressions. </policy/CMP0044>
+ CMP0043: Ignore COMPILE_DEFINITIONS_Config properties. </policy/CMP0043>
+ CMP0042: MACOSX_RPATH is enabled by default. </policy/CMP0042>
+ CMP0041: Error on relative include with generator expression. </policy/CMP0041>
+ CMP0040: The target in the TARGET signature of add_custom_command() must exist. </policy/CMP0040>
+ CMP0039: Utility targets may not have link dependencies. </policy/CMP0039>
+ CMP0038: Targets may not link directly to themselves. </policy/CMP0038>
+ CMP0037: Target names should not be reserved and should match a validity pattern. </policy/CMP0037>
+ CMP0036: The build_name command should not be called. </policy/CMP0036>
+ CMP0035: The variable_requires command should not be called. </policy/CMP0035>
+ CMP0034: The utility_source command should not be called. </policy/CMP0034>
+ CMP0033: The export_library_dependencies command should not be called. </policy/CMP0033>
+ CMP0032: The output_required_files command should not be called. </policy/CMP0032>
+ CMP0031: The load_command command should not be called. </policy/CMP0031>
+ CMP0030: The use_mangled_mesa command should not be called. </policy/CMP0030>
+ CMP0029: The subdir_depends command should not be called. </policy/CMP0029>
+ CMP0028: Double colon in target name means ALIAS or IMPORTED target. </policy/CMP0028>
+ CMP0027: Conditionally linked imported targets with missing include directories. </policy/CMP0027>
+ CMP0026: Disallow use of the LOCATION target property. </policy/CMP0026>
+ CMP0025: Compiler id for Apple Clang is now AppleClang. </policy/CMP0025>
+ CMP0024: Disallow include export result. </policy/CMP0024>
+
+Policies Introduced by CMake 2.8
+================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0023: Plain and keyword target_link_libraries signatures cannot be mixed. </policy/CMP0023>
+ CMP0022: INTERFACE_LINK_LIBRARIES defines the link interface. </policy/CMP0022>
+ CMP0021: Fatal error on relative paths in INCLUDE_DIRECTORIES target property. </policy/CMP0021>
+ CMP0020: Automatically link Qt executables to qtmain target on Windows. </policy/CMP0020>
+ CMP0019: Do not re-expand variables in include and link information. </policy/CMP0019>
+ CMP0018: Ignore CMAKE_SHARED_LIBRARY_Lang_FLAGS variable. </policy/CMP0018>
+ CMP0017: Prefer files from the CMake module directory when including from there. </policy/CMP0017>
+ CMP0016: target_link_libraries() reports error if its only argument is not a target. </policy/CMP0016>
+ CMP0015: link_directories() treats paths relative to the source dir. </policy/CMP0015>
+ CMP0014: Input directories must have CMakeLists.txt. </policy/CMP0014>
+ CMP0013: Duplicate binary directories are not allowed. </policy/CMP0013>
+ CMP0012: if() recognizes numbers and boolean constants. </policy/CMP0012>
+
+Policies Introduced by CMake 2.6
+================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0011: Included scripts do automatic cmake_policy PUSH and POP. </policy/CMP0011>
+ CMP0010: Bad variable reference syntax is an error. </policy/CMP0010>
+ CMP0009: FILE GLOB_RECURSE calls should not follow symlinks by default. </policy/CMP0009>
+ CMP0008: Libraries linked by full-path must have a valid library file name. </policy/CMP0008>
+ CMP0007: list command no longer ignores empty elements. </policy/CMP0007>
+ CMP0006: Installing MACOSX_BUNDLE targets requires a BUNDLE DESTINATION. </policy/CMP0006>
+ CMP0005: Preprocessor definition values are now escaped automatically. </policy/CMP0005>
+ CMP0004: Libraries linked may not have leading or trailing whitespace. </policy/CMP0004>
+ CMP0003: Libraries linked via full path no longer produce linker search paths. </policy/CMP0003>
+ CMP0002: Logical target names must be globally unique. </policy/CMP0002>
+ CMP0001: CMAKE_BACKWARDS_COMPATIBILITY should no longer be used. </policy/CMP0001>
+ CMP0000: A minimum required CMake version must be specified. </policy/CMP0000>
diff --git a/Help/manual/cmake-presets.7.rst b/Help/manual/cmake-presets.7.rst
new file mode 100644
index 0000000..3714004
--- /dev/null
+++ b/Help/manual/cmake-presets.7.rst
@@ -0,0 +1,998 @@
+.. cmake-manual-description: CMakePresets.json
+
+cmake-presets(7)
+****************
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+One problem that CMake users often face is sharing settings with other people
+for common ways to configure a project. This may be done to support CI builds,
+or for users who frequently use the same build. CMake supports two files,
+``CMakePresets.json`` and ``CMakeUserPresets.json``, that allow users to
+specify common configure options and share them with others.
+
+``CMakePresets.json`` and ``CMakeUserPresets.json`` live in the project's root
+directory. They both have exactly the same format, and both are optional
+(though at least one must be present if ``--preset`` is specified.)
+``CMakePresets.json`` is meant to save project-wide builds, while
+``CMakeUserPresets.json`` is meant for developers to save their own local
+builds. ``CMakePresets.json`` may be checked into a version control system, and
+``CMakeUserPresets.json`` should NOT be checked in. For example, if a project
+is using Git, ``CMakePresets.json`` may be tracked, and
+``CMakeUserPresets.json`` should be added to the ``.gitignore``.
+
+Format
+======
+
+The files are a JSON document with an object as the root:
+
+.. literalinclude:: presets/example.json
+ :language: json
+
+The root object recognizes the following fields:
+
+``version``
+
+ A required integer representing the version of the JSON schema.
+ The supported versions are ``1``, ``2``, and ``3``.
+
+``cmakeMinimumRequired``
+
+ An optional object representing the minimum version of CMake needed to
+ build this project. This object consists of the following fields:
+
+ ``major``
+
+ An optional integer representing the major version.
+
+ ``minor``
+
+ An optional integer representing the minor version.
+
+ ``patch``
+
+ An optional integer representing the patch version.
+
+``vendor``
+
+ An optional map containing vendor-specific information. CMake does not
+ interpret the contents of this field except to verify that it is a map if
+ it does exist. However, the keys should be a vendor-specific domain name
+ followed by a ``/``-separated path. For example, the Example IDE 1.0 could
+ use ``example.com/ExampleIDE/1.0``. The value of each field can be anything
+ desired by the vendor, though will typically be a map.
+
+``configurePresets``
+
+ An optional array of `Configure Preset`_ objects.
+ This is allowed in preset files specifying version ``1`` or above.
+
+``buildPresets``
+
+ An optional array of `Build Preset`_ objects.
+ This is allowed in preset files specifying version ``2`` or above.
+
+``testPresets``
+
+ An optional array of `Test Preset`_ objects.
+ This is allowed in preset files specifying version ``2`` or above.
+
+Configure Preset
+^^^^^^^^^^^^^^^^
+
+Each entry of the ``configurePresets`` array is a JSON object
+that may contain the following fields:
+
+``name``
+
+ A required string representing the machine-friendly name of the preset.
+ This identifier is used in the :ref:`cmake --preset <CMake Options>` option.
+ There must not be two configure presets in the union of ``CMakePresets.json``
+ and ``CMakeUserPresets.json`` in the same directory with the same name.
+ However, a configure preset may have the same name as a build or test preset.
+
+``hidden``
+
+ An optional boolean specifying whether or not a preset should be hidden.
+ If a preset is hidden, it cannot be used in the ``--preset=`` argument,
+ will not show up in the :manual:`CMake GUI <cmake-gui(1)>`, and does not
+ have to have a valid ``generator`` or ``binaryDir``, even from
+ inheritance. ``hidden`` presets are intended to be used as a base for
+ other presets to inherit via the ``inherits`` field.
+
+``inherits``
+
+ An optional array of strings representing the names of presets to inherit
+ from. The preset will inherit all of the fields from the ``inherits``
+ presets by default (except ``name``, ``hidden``, ``inherits``,
+ ``description``, and ``displayName``), but can override them as
+ desired. If multiple ``inherits`` presets provide conflicting values for
+ the same field, the earlier preset in the ``inherits`` list will be
+ preferred. Presets in ``CMakePresets.json`` may not inherit from presets
+ in ``CMakeUserPresets.json``.
+
+ This field can also be a string, which is equivalent to an array
+ containing one string.
+
+``condition``
+
+ An optional `Condition`_ object. This is allowed in preset files specifying
+ version ``3`` or above.
+
+``vendor``
+
+ An optional map containing vendor-specific information. CMake does not
+ interpret the contents of this field except to verify that it is a map
+ if it does exist. However, it should follow the same conventions as the
+ root-level ``vendor`` field. If vendors use their own per-preset
+ ``vendor`` field, they should implement inheritance in a sensible manner
+ when appropriate.
+
+``displayName``
+
+ An optional string with a human-friendly name of the preset.
+
+``description``
+
+ An optional string with a human-friendly description of the preset.
+
+``generator``
+
+ An optional string representing the generator to use for the preset. If
+ ``generator`` is not specified, it must be inherited from the
+ ``inherits`` preset (unless this preset is ``hidden``). In version ``3``
+ or above, this field may be omitted to fall back to regular generator
+ discovery procedure.
+
+ Note that for Visual Studio generators, unlike in the command line ``-G``
+ argument, you cannot include the platform name in the generator name. Use
+ the ``architecture`` field instead.
+
+``architecture``, ``toolset``
+
+ Optional fields representing the platform and toolset, respectively, for
+ generators that support them. Each may be either a string or an object
+ with the following fields:
+
+ ``value``
+
+ An optional string representing the value.
+
+ ``strategy``
+
+ An optional string telling CMake how to handle the ``architecture`` or
+ ``toolset`` field. Valid values are:
+
+ ``"set"``
+
+ Set the respective value. This will result in an error for generators
+ that do not support the respective field.
+
+ ``"external"``
+
+ Do not set the value, even if the generator supports it. This is
+ useful if, for example, a preset uses the Ninja generator, and an IDE
+ knows how to set up the Visual C++ environment from the
+ ``architecture`` and ``toolset`` fields. In that case, CMake will
+ ignore the field, but the IDE can use them to set up the environment
+ before invoking CMake.
+
+``binaryDir``
+
+ An optional string representing the path to the output binary directory.
+ This field supports `macro expansion`_. If a relative path is specified,
+ it is calculated relative to the source directory. If ``binaryDir`` is not
+ specified, it must be inherited from the ``inherits`` preset (unless this
+ preset is ``hidden``). In version ``3`` or above, this field may be
+ omitted.
+
+``installDir``
+
+ An optional string representing the path to the installation directory.
+ This field supports `macro expansion`_. If a relative path is specified,
+ it is calculated relative to the source directory. This is allowed in
+ preset files specifying version ``3`` or above.
+
+``cmakeExecutable``
+
+ An optional string representing the path to the CMake executable to use
+ for this preset. This is reserved for use by IDEs, and is not used by
+ CMake itself. IDEs that use this field should expand any macros in it.
+
+``cacheVariables``
+
+ An optional map of cache variables. The key is the variable name (which
+ may not be an empty string), and the value is either ``null``, a boolean
+ (which is equivalent to a value of ``"TRUE"`` or ``"FALSE"`` and a type
+ of ``BOOL``), a string representing the value of the variable (which
+ supports `macro expansion`_), or an object with the following fields:
+
+ ``type``
+
+ An optional string representing the type of the variable.
+
+ ``value``
+
+ A required string or boolean representing the value of the variable.
+ A boolean is equivalent to ``"TRUE"`` or ``"FALSE"``. This field
+ supports `macro expansion`_.
+
+ Cache variables are inherited through the ``inherits`` field, and the
+ preset's variables will be the union of its own ``cacheVariables`` and
+ the ``cacheVariables`` from all its parents. If multiple presets in this
+ union define the same variable, the standard rules of ``inherits`` are
+ applied. Setting a variable to ``null`` causes it to not be set, even if
+ a value was inherited from another preset.
+
+``environment``
+
+ An optional map of environment variables. The key is the variable name
+ (which may not be an empty string), and the value is either ``null`` or
+ a string representing the value of the variable. Each variable is set
+ regardless of whether or not a value was given to it by the process's
+ environment. This field supports `macro expansion`_, and environment
+ variables in this map may reference each other, and may be listed in any
+ order, as long as such references do not cause a cycle (for example,
+ if ``ENV_1`` is ``$env{ENV_2}``, ``ENV_2`` may not be ``$env{ENV_1}``.)
+
+ Environment variables are inherited through the ``inherits`` field, and
+ the preset's environment will be the union of its own ``environment`` and
+ the ``environment`` from all its parents. If multiple presets in this
+ union define the same variable, the standard rules of ``inherits`` are
+ applied. Setting a variable to ``null`` causes it to not be set, even if
+ a value was inherited from another preset.
+
+``warnings``
+
+ An optional object specifying the warnings to enable. The object may
+ contain the following fields:
+
+ ``dev``
+
+ An optional boolean. Equivalent to passing ``-Wdev`` or ``-Wno-dev``
+ on the command line. This may not be set to ``false`` if ``errors.dev``
+ is set to ``true``.
+
+ ``deprecated``
+
+ An optional boolean. Equivalent to passing ``-Wdeprecated`` or
+ ``-Wno-deprecated`` on the command line. This may not be set to
+ ``false`` if ``errors.deprecated`` is set to ``true``.
+
+ ``uninitialized``
+
+ An optional boolean. Setting this to ``true`` is equivalent to passing
+ ``--warn-uninitialized`` on the command line.
+
+ ``unusedCli``
+
+ An optional boolean. Setting this to ``false`` is equivalent to passing
+ ``--no-warn-unused-cli`` on the command line.
+
+ ``systemVars``
+
+ An optional boolean. Setting this to ``true`` is equivalent to passing
+ ``--check-system-vars`` on the command line.
+
+``errors``
+
+ An optional object specifying the errors to enable. The object may
+ contain the following fields:
+
+ ``dev``
+
+ An optional boolean. Equivalent to passing ``-Werror=dev`` or
+ ``-Wno-error=dev`` on the command line. This may not be set to ``true``
+ if ``warnings.dev`` is set to ``false``.
+
+ ``deprecated``
+
+ An optional boolean. Equivalent to passing ``-Werror=deprecated`` or
+ ``-Wno-error=deprecated`` on the command line. This may not be set to
+ ``true`` if ``warnings.deprecated`` is set to ``false``.
+
+``debug``
+
+ An optional object specifying debug options. The object may contain the
+ following fields:
+
+ ``output``
+
+ An optional boolean. Setting this to ``true`` is equivalent to passing
+ ``--debug-output`` on the command line.
+
+ ``tryCompile``
+
+ An optional boolean. Setting this to ``true`` is equivalent to passing
+ ``--debug-trycompile`` on the command line.
+
+ ``find``
+
+ An optional boolean. Setting this to ``true`` is equivalent to passing
+ ``--debug-find`` on the command line.
+
+Build Preset
+^^^^^^^^^^^^
+
+Each entry of the ``buildPresets`` array is a JSON object
+that may contain the following fields:
+
+``name``
+
+ A required string representing the machine-friendly name of the preset.
+ This identifier is used in the
+ :ref:`cmake --build --preset <Build Tool Mode>` option.
+ There must not be two build presets in the union of ``CMakePresets.json``
+ and ``CMakeUserPresets.json`` in the same directory with the same name.
+ However, a build preset may have the same name as a configure or test preset.
+
+``hidden``
+
+ An optional boolean specifying whether or not a preset should be hidden.
+ If a preset is hidden, it cannot be used in the ``--preset`` argument
+ and does not have to have a valid ``configurePreset``, even from
+ inheritance. ``hidden`` presets are intended to be used as a base for
+ other presets to inherit via the ``inherits`` field.
+
+``inherits``
+
+ An optional array of strings representing the names of presets to
+ inherit from. The preset will inherit all of the fields from the
+ ``inherits`` presets by default (except ``name``, ``hidden``,
+ ``inherits``, ``description``, and ``displayName``), but can override
+ them as desired. If multiple ``inherits`` presets provide conflicting
+ values for the same field, the earlier preset in the ``inherits`` list
+ will be preferred. Presets in ``CMakePresets.json`` may not inherit from
+ presets in ``CMakeUserPresets.json``.
+
+ This field can also be a string, which is equivalent to an array
+ containing one string.
+
+``condition``
+
+ An optional `Condition`_ object. This is allowed in preset files specifying
+ version ``3`` or above.
+
+``vendor``
+
+ An optional map containing vendor-specific information. CMake does not
+ interpret the contents of this field except to verify that it is a map
+ if it does exist. However, it should follow the same conventions as the
+ root-level ``vendor`` field. If vendors use their own per-preset
+ ``vendor`` field, they should implement inheritance in a sensible manner
+ when appropriate.
+
+``displayName``
+
+ An optional string with a human-friendly name of the preset.
+
+``description``
+
+ An optional string with a human-friendly description of the preset.
+
+``environment``
+
+ An optional map of environment variables. The key is the variable name
+ (which may not be an empty string), and the value is either ``null`` or
+ a string representing the value of the variable. Each variable is set
+ regardless of whether or not a value was given to it by the process's
+ environment. This field supports macro expansion, and environment
+ variables in this map may reference each other, and may be listed in any
+ order, as long as such references do not cause a cycle (for example, if
+ ``ENV_1`` is ``$env{ENV_2}``, ``ENV_2`` may not be ``$env{ENV_1}``.)
+
+ Environment variables are inherited through the ``inherits`` field, and
+ the preset's environment will be the union of its own ``environment``
+ and the ``environment`` from all its parents. If multiple presets in
+ this union define the same variable, the standard rules of ``inherits``
+ are applied. Setting a variable to ``null`` causes it to not be set,
+ even if a value was inherited from another preset.
+
+``configurePreset``
+
+ An optional string specifying the name of a configure preset to
+ associate with this build preset. If ``configurePreset`` is not
+ specified, it must be inherited from the inherits preset (unless this
+ preset is hidden). The build directory is inferred from the configure
+ preset, so the build will take place in the same ``binaryDir`` that the
+ configuration did.
+
+``inheritConfigureEnvironment``
+
+ An optional boolean that defaults to true. If true, the environment
+ variables from the associated configure preset are inherited after all
+ inherited build preset environments, but before environment variables
+ explicitly specified in this build preset.
+
+``jobs``
+
+ An optional integer. Equivalent to passing ``--parallel`` or ``-j`` on
+ the command line.
+
+``targets``
+
+ An optional string or array of strings. Equivalent to passing
+ ``--target`` or ``-t`` on the command line. Vendors may ignore the
+ targets property or hide build presets that explicitly specify targets.
+ This field supports macro expansion.
+
+``configuration``
+
+ An optional string. Equivalent to passing ``--config`` on the command
+ line.
+
+``cleanFirst``
+
+ An optional bool. If true, equivalent to passing ``--clean-first`` on
+ the command line.
+
+``verbose``
+
+ An optional bool. If true, equivalent to passing ``--verbose`` on the
+ command line.
+
+``nativeToolOptions``
+
+ An optional array of strings. Equivalent to passing options after ``--``
+ on the command line. The array values support macro expansion.
+
+Test Preset
+^^^^^^^^^^^
+
+Each entry of the ``testPresets`` array is a JSON object
+that may contain the following fields:
+
+``name``
+
+ A required string representing the machine-friendly name of the preset.
+ This identifier is used in the :ref:`ctest --preset <CTest Options>` option.
+ There must not be two test presets in the union of ``CMakePresets.json``
+ and ``CMakeUserPresets.json`` in the same directory with the same name.
+ However, a test preset may have the same name as a configure or build preset.
+
+``hidden``
+
+ An optional boolean specifying whether or not a preset should be hidden.
+ If a preset is hidden, it cannot be used in the ``--preset`` argument
+ and does not have to have a valid ``configurePreset``, even from
+ inheritance. ``hidden`` presets are intended to be used as a base for
+ other presets to inherit via the ``inherits`` field.
+
+``inherits``
+
+ An optional array of strings representing the names of presets to
+ inherit from. The preset will inherit all of the fields from the
+ ``inherits`` presets by default (except ``name``, ``hidden``,
+ ``inherits``, ``description``, and ``displayName``), but can override
+ them as desired. If multiple ``inherits`` presets provide conflicting
+ values for the same field, the earlier preset in the ``inherits`` list
+ will be preferred. Presets in ``CMakePresets.json`` may not inherit from
+ presets in ``CMakeUserPresets.json``.
+
+ This field can also be a string, which is equivalent to an array
+ containing one string.
+
+``condition``
+
+ An optional `Condition`_ object. This is allowed in preset files specifying
+ version ``3`` or above.
+
+``vendor``
+
+ An optional map containing vendor-specific information. CMake does not
+ interpret the contents of this field except to verify that it is a map
+ if it does exist. However, it should follow the same conventions as the
+ root-level ``vendor`` field. If vendors use their own per-preset
+ ``vendor`` field, they should implement inheritance in a sensible manner
+ when appropriate.
+
+``displayName``
+
+ An optional string with a human-friendly name of the preset.
+
+``description``
+
+ An optional string with a human-friendly description of the preset.
+
+``environment``
+
+ An optional map of environment variables. The key is the variable name
+ (which may not be an empty string), and the value is either ``null`` or
+ a string representing the value of the variable. Each variable is set
+ regardless of whether or not a value was given to it by the process's
+ environment. This field supports macro expansion, and environment
+ variables in this map may reference each other, and may be listed in any
+ order, as long as such references do not cause a cycle (for example, if
+ ``ENV_1`` is ``$env{ENV_2}``, ``ENV_2`` may not be ``$env{ENV_1}``.)
+
+ Environment variables are inherited through the ``inherits`` field, and
+ the preset's environment will be the union of its own ``environment``
+ and the ``environment`` from all its parents. If multiple presets in
+ this union define the same variable, the standard rules of ``inherits``
+ are applied. Setting a variable to ``null`` causes it to not be set,
+ even if a value was inherited from another preset.
+
+``configurePreset``
+
+ An optional string specifying the name of a configure preset to
+ associate with this test preset. If ``configurePreset`` is not
+ specified, it must be inherited from the inherits preset (unless this
+ preset is hidden). The build directory is inferred from the configure
+ preset, so tests will run in the same ``binaryDir`` that the
+ configuration did and build did.
+
+``inheritConfigureEnvironment``
+
+ An optional boolean that defaults to true. If true, the environment
+ variables from the associated configure preset are inherited after all
+ inherited test preset environments, but before environment variables
+ explicitly specified in this test preset.
+
+``configuration``
+
+ An optional string. Equivalent to passing ``--build-config`` on the
+ command line.
+
+``overwriteConfigurationFile``
+
+ An optional array of configuration options to overwrite options
+ specified in the CTest configuration file. Equivalent to passing
+ ``--overwrite`` for each value in the array. The array values
+ support macro expansion.
+
+``output``
+
+ An optional object specifying output options. The object may contain the
+ following fields.
+
+ ``shortProgress``
+
+ An optional bool. If true, equivalent to passing ``--progress`` on the
+ command line.
+
+ ``verbosity``
+
+ An optional string specifying verbosity level. Must be one of the
+ following:
+
+ ``default``
+
+ Equivalent to passing no verbosity flags on the command line.
+
+ ``verbose``
+
+ Equivalent to passing ``--verbose`` on the command line.
+
+ ``extra``
+
+ Equivalent to passing ``--extra-verbose`` on the command line.
+
+ ``debug``
+
+ An optional bool. If true, equivalent to passing ``--debug`` on the
+ command line.
+
+ ``outputOnFailure``
+
+ An optional bool. If true, equivalent to passing
+ ``--output-on-failure`` on the command line.
+
+ ``quiet``
+
+ An optional bool. If true, equivalent to passing ``--quiet`` on the
+ command line.
+
+ ``outputLogFile``
+
+ An optional string specifying a path to a log file. Equivalent to
+ passing ``--output-log`` on the command line. This field supports
+ macro expansion.
+
+ ``labelSummary``
+
+ An optional bool. If false, equivalent to passing
+ ``--no-label-summary`` on the command line.
+
+ ``subprojectSummary``
+
+ An optional bool. If false, equivalent to passing
+ ``--no-subproject-summary`` on the command line.
+
+ ``maxPassedTestOutputSize``
+
+ An optional integer specifying the maximum output for passed tests in
+ bytes. Equivalent to passing ``--test-output-size-passed`` on the
+ command line.
+
+ ``maxFailedTestOutputSize``
+
+ An optional integer specifying the maximum output for failed tests in
+ bytes. Equivalent to passing ``--test-output-size-failed`` on the
+ command line.
+
+ ``maxTestNameWidth``
+
+ An optional integer specifying the maximum width of a test name to
+ output. Equivalent to passing ``--max-width`` on the command line.
+
+``filter``
+
+ An optional object specifying how to filter the tests to run. The object
+ may contain the following fields.
+
+ ``include``
+
+ An optional object specifying which tests to include. The object may
+ contain the following fields.
+
+ ``name``
+
+ An optional string specifying a regex for test names. Equivalent to
+ passing ``--tests-regex`` on the command line. This field supports
+ macro expansion.
+
+
+ ``label``
+
+ An optional string specifying a regex for test labels. Equivalent to
+ passing ``--label-regex`` on the command line. This field supports
+ macro expansion.
+
+ ``useUnion``
+
+ An optional bool. Equivalent to passing ``--union`` on the command
+ line.
+
+ ``index``
+
+ An optional object specifying tests to include by test index. The
+ object may contain the following fields. Can also be an optional
+ string specifying a file with the command line syntax for
+ ``--tests-information``. If specified as a string, this field
+ supports macro expansion.
+
+ ``start``
+
+ An optional integer specifying a test index to start testing at.
+
+ ``end``
+
+ An optional integer specifying a test index to stop testing at.
+
+ ``stride``
+
+ An optional integer specifying the increment.
+
+ ``specificTests``
+
+ An optional array of integers specifying specific test indices to
+ run.
+
+ ``exclude``
+
+ An optional object specifying which tests to exclude. The object may
+ contain the following fields.
+
+ ``name``
+
+ An optional string specifying a regex for test names. Equivalent to
+ passing ``--exclude-regex`` on the command line. This field supports
+ macro expansion.
+
+ ``label``
+
+ An optional string specifying a regex for test labels. Equivalent to
+ passing ``--label-exclude`` on the command line. This field supports
+ macro expansion.
+
+ ``fixtures``
+
+ An optional object specifying which fixtures to exclude from adding
+ tests. The object may contain the following fields.
+
+ ``any``
+
+ An optional string specifying a regex for text fixtures to exclude
+ from adding any tests. Equivalent to ``--fixture-exclude-any`` on
+ the command line. This field supports macro expansion.
+
+ ``setup``
+
+ An optional string specifying a regex for text fixtures to exclude
+ from adding setup tests. Equivalent to ``--fixture-exclude-setup``
+ on the command line. This field supports macro expansion.
+
+ ``cleanup``
+
+ An optional string specifying a regex for text fixtures to exclude
+ from adding cleanup tests. Equivalent to
+ ``--fixture-exclude-cleanup`` on the command line. This field
+ supports macro expansion.
+
+``execution``
+
+ An optional object specifying options for test execution. The object may
+ contain the following fields.
+
+ ``stopOnFailure``
+
+ An optional bool. If true, equivalent to passing ``--stop-on-failure``
+ on the command line.
+
+ ``enableFailover``
+
+ An optional bool. If true, equivalent to passing ``-F`` on the command
+ line.
+
+ ``jobs``
+
+ An optional integer. Equivalent to passing ``--parallel`` on the
+ command line.
+
+ ``resourceSpecFile``
+
+ An optional string. Equivalent to passing ``--resource-spec-file`` on
+ the command line. This field supports macro expansion.
+
+ ``testLoad``
+
+ An optional integer. Equivalent to passing ``--test-load`` on the
+ command line.
+
+ ``showOnly``
+
+ An optional string. Equivalent to passing ``--show-only`` on the
+ command line. The string must be one of the following values:
+
+ ``human``
+
+ ``json-v1``
+
+ ``repeat``
+
+ An optional object specifying how to repeat tests. Equivalent to
+ passing ``--repeat`` on the command line. The object must have the
+ following fields.
+
+ ``mode``
+
+ A required string. Must be one of the following values:
+
+ ``until-fail``
+
+ ``until-pass``
+
+ ``after-timeout``
+
+ ``count``
+
+ A required integer.
+
+ ``interactiveDebugging``
+
+ An optional bool. If true, equivalent to passing
+ ``--interactive-debug-mode 1`` on the command line. If false,
+ equivalent to passing ``--interactive-debug-mode 0`` on the command
+ line.
+
+ ``scheduleRandom``
+
+ An optional bool. If true, equivalent to passing ``--schedule-random``
+ on the command line.
+
+ ``timeout``
+
+ An optional integer. Equivalent to passing ``--timeout`` on the
+ command line.
+
+ ``noTestsAction``
+
+ An optional string specifying the behavior if no tests are found. Must
+ be one of the following values:
+
+ ``default``
+
+ Equivalent to not passing any value on the command line.
+
+ ``error``
+
+ Equivalent to passing ``--no-tests=error`` on the command line.
+
+ ``ignore``
+
+ Equivalent to passing ``--no-tests=ignore`` on the command line.
+
+Condition
+^^^^^^^^^
+
+The ``condition`` field of a preset, allowed in preset files specifying version
+``3`` or above, is used to determine whether or not the preset is enabled. For
+example, this can be used to disable a preset on platforms other than Windows.
+``condition`` may be either a boolean, ``null``, or an object. If it is a
+boolean, the boolean indicates whether the preset is enabled or disabled. If it
+is ``null``, the preset is enabled, but the ``null`` condition is not inherited
+by any presets that may inherit from the preset. Sub-conditions (for example in
+a ``not``, ``anyOf``, or ``allOf`` condition) may not be ``null``. If it is an
+object, it has the following fields:
+
+``type``
+
+ A required string with one of the following values:
+
+ ``"const"``
+
+ Indicates that the condition is constant. This is equivalent to using a
+ boolean in place of the object. The condition object will have the
+ following additional fields:
+
+ ``value``
+
+ A required boolean which provides a constant value for the condition's
+ evaluation.
+
+ ``"equals"``
+
+ ``"notEquals"``
+
+ Indicates that the condition compares two strings to see if they are equal
+ (or not equal). The condition object will have the following additional
+ fields:
+
+ ``lhs``
+
+ First string to compare. This field supports macro expansion.
+
+ ``rhs``
+
+ Second string to compare. This field supports macro expansion.
+
+ ``"inList"``
+
+ ``"notInList"``
+
+ Indicates that the condition searches for a string in a list of strings.
+ The condition object will have the following additional fields:
+
+ ``string``
+
+ A required string to search for. This field supports macro expansion.
+
+ ``list``
+
+ A required list of strings to search. This field supports macro
+ expansion, and uses short-circuit evaluation.
+
+ ``"matches"``
+
+ ``"notMatches"``
+
+ Indicates that the condition searches for a regular expression in a string.
+ The condition object will have the following additional fields:
+
+ ``string``
+
+ A required string to search. This field supports macro expansion.
+
+ ``regex``
+
+ A required regular expression to search for. This field supports macro
+ expansion.
+
+ ``"anyOf"``
+
+ ``"allOf"``
+
+ Indicates that the condition is an aggregation of zero or more nested
+ conditions. The condition object will have the following additional fields:
+
+ ``conditions``
+
+ A required array of condition objects. These conditions use short-circuit
+ evaluation.
+
+ ``"not"``
+
+ Indicates that the condition is an inversion of another condition. The
+ condition object will have the following additional fields:
+
+ ``condition``
+
+ A required condition object.
+
+Macro Expansion
+^^^^^^^^^^^^^^^
+
+As mentioned above, some fields support macro expansion. Macros are
+recognized in the form ``$<macro-namespace>{<macro-name>}``. All macros are
+evaluated in the context of the preset being used, even if the macro is in a
+field that was inherited from another preset. For example, if the ``Base``
+preset sets variable ``PRESET_NAME`` to ``${presetName}``, and the
+``Derived`` preset inherits from ``Base``, ``PRESET_NAME`` will be set to
+``Derived``.
+
+It is an error to not put a closing brace at the end of a macro name. For
+example, ``${sourceDir`` is invalid. A dollar sign (``$``) followed by
+anything other than a left curly brace (``{``) with a possible namespace is
+interpreted as a literal dollar sign.
+
+Recognized macros include:
+
+``${sourceDir}``
+
+ Path to the project source directory.
+
+``${sourceParentDir}``
+
+ Path to the project source directory's parent directory.
+
+``${sourceDirName}``
+
+ The last filename component of ``${sourceDir}``. For example, if
+ ``${sourceDir}`` is ``/path/to/source``, this would be ``source``.
+
+``${presetName}``
+
+ Name specified in the preset's ``name`` field.
+
+``${generator}``
+
+ Generator specified in the preset's ``generator`` field. For build and
+ test presets, this will evaluate to the generator specified by
+ ``configurePreset``.
+
+``${hostSystemName}``
+
+ The name of the host operating system. Contains the same value as
+ :variable:`CMAKE_HOST_SYSTEM_NAME`. This is allowed in preset files
+ specifying version ``3`` or above.
+
+``${dollar}``
+
+ A literal dollar sign (``$``).
+
+``$env{<variable-name>}``
+
+ Environment variable with name ``<variable-name>``. The variable name may
+ not be an empty string. If the variable is defined in the ``environment``
+ field, that value is used instead of the value from the parent environment.
+ If the environment variable is not defined, this evaluates as an empty
+ string.
+
+ Note that while Windows environment variable names are case-insensitive,
+ variable names within a preset are still case-sensitive. This may lead to
+ unexpected results when using inconsistent casing. For best results, keep
+ the casing of environment variable names consistent.
+
+``$penv{<variable-name>}``
+
+ Similar to ``$env{<variable-name>}``, except that the value only comes from
+ the parent environment, and never from the ``environment`` field. This
+ allows you to prepend or append values to existing environment variables.
+ For example, setting ``PATH`` to ``/path/to/ninja/bin:$penv{PATH}`` will
+ prepend ``/path/to/ninja/bin`` to the ``PATH`` environment variable. This
+ is needed because ``$env{<variable-name>}`` does not allow circular
+ references.
+
+``$vendor{<macro-name>}``
+
+ An extension point for vendors to insert their own macros. CMake will not
+ be able to use presets which have a ``$vendor{<macro-name>}`` macro, and
+ effectively ignores such presets. However, it will still be able to use
+ other presets from the same file.
+
+ CMake does not make any attempt to interpret ``$vendor{<macro-name>}``
+ macros. However, to avoid name collisions, IDE vendors should prefix
+ ``<macro-name>`` with a very short (preferably <= 4 characters) vendor
+ identifier prefix, followed by a ``.``, followed by the macro name. For
+ example, the Example IDE could have ``$vendor{xide.ideInstallDir}``.
+
+Schema
+======
+
+:download:`This file </manual/presets/schema.json>` provides a machine-readable
+JSON schema for the ``CMakePresets.json`` format.
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
new file mode 100644
index 0000000..60a4028
--- /dev/null
+++ b/Help/manual/cmake-properties.7.rst
@@ -0,0 +1,587 @@
+.. cmake-manual-description: CMake Properties Reference
+
+cmake-properties(7)
+*******************
+
+.. only:: html
+
+ .. contents::
+
+.. _`Global Properties`:
+
+Properties of Global Scope
+==========================
+
+.. toctree::
+ :maxdepth: 1
+
+ /prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS
+ /prop_gbl/AUTOGEN_SOURCE_GROUP
+ /prop_gbl/AUTOGEN_TARGETS_FOLDER
+ /prop_gbl/AUTOMOC_SOURCE_GROUP
+ /prop_gbl/AUTOMOC_TARGETS_FOLDER
+ /prop_gbl/AUTORCC_SOURCE_GROUP
+ /prop_gbl/AUTOUIC_SOURCE_GROUP
+ /prop_gbl/CMAKE_C_KNOWN_FEATURES
+ /prop_gbl/CMAKE_CUDA_KNOWN_FEATURES
+ /prop_gbl/CMAKE_CXX_KNOWN_FEATURES
+ /prop_gbl/CMAKE_ROLE
+ /prop_gbl/DEBUG_CONFIGURATIONS
+ /prop_gbl/DISABLED_FEATURES
+ /prop_gbl/ECLIPSE_EXTRA_CPROJECT_CONTENTS
+ /prop_gbl/ECLIPSE_EXTRA_NATURES
+ /prop_gbl/ENABLED_FEATURES
+ /prop_gbl/ENABLED_LANGUAGES
+ /prop_gbl/FIND_LIBRARY_USE_LIB32_PATHS
+ /prop_gbl/FIND_LIBRARY_USE_LIB64_PATHS
+ /prop_gbl/FIND_LIBRARY_USE_LIBX32_PATHS
+ /prop_gbl/FIND_LIBRARY_USE_OPENBSD_VERSIONING
+ /prop_gbl/GENERATOR_IS_MULTI_CONFIG
+ /prop_gbl/GLOBAL_DEPENDS_DEBUG_MODE
+ /prop_gbl/GLOBAL_DEPENDS_NO_CYCLES
+ /prop_gbl/IN_TRY_COMPILE
+ /prop_gbl/JOB_POOLS
+ /prop_gbl/PACKAGES_FOUND
+ /prop_gbl/PACKAGES_NOT_FOUND
+ /prop_gbl/PREDEFINED_TARGETS_FOLDER
+ /prop_gbl/REPORT_UNDEFINED_PROPERTIES
+ /prop_gbl/RULE_LAUNCH_COMPILE
+ /prop_gbl/RULE_LAUNCH_CUSTOM
+ /prop_gbl/RULE_LAUNCH_LINK
+ /prop_gbl/RULE_MESSAGES
+ /prop_gbl/TARGET_ARCHIVES_MAY_BE_SHARED_LIBS
+ /prop_gbl/TARGET_MESSAGES
+ /prop_gbl/TARGET_SUPPORTS_SHARED_LIBS
+ /prop_gbl/USE_FOLDERS
+ /prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME
+
+.. _`Directory Properties`:
+
+Properties on Directories
+=========================
+
+.. toctree::
+ :maxdepth: 1
+
+ /prop_dir/ADDITIONAL_CLEAN_FILES
+ /prop_dir/BINARY_DIR
+ /prop_dir/BUILDSYSTEM_TARGETS
+ /prop_dir/CACHE_VARIABLES
+ /prop_dir/CLEAN_NO_CUSTOM
+ /prop_dir/CMAKE_CONFIGURE_DEPENDS
+ /prop_dir/COMPILE_DEFINITIONS
+ /prop_dir/COMPILE_OPTIONS
+ /prop_dir/DEFINITIONS
+ /prop_dir/EXCLUDE_FROM_ALL
+ /prop_dir/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
+ /prop_dir/INCLUDE_DIRECTORIES
+ /prop_dir/INCLUDE_REGULAR_EXPRESSION
+ /prop_dir/INTERPROCEDURAL_OPTIMIZATION
+ /prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG
+ /prop_dir/LABELS
+ /prop_dir/LINK_DIRECTORIES
+ /prop_dir/LINK_OPTIONS
+ /prop_dir/LISTFILE_STACK
+ /prop_dir/MACROS
+ /prop_dir/PARENT_DIRECTORY
+ /prop_dir/RULE_LAUNCH_COMPILE
+ /prop_dir/RULE_LAUNCH_CUSTOM
+ /prop_dir/RULE_LAUNCH_LINK
+ /prop_dir/SOURCE_DIR
+ /prop_dir/SUBDIRECTORIES
+ /prop_dir/TESTS
+ /prop_dir/TEST_INCLUDE_FILES
+ /prop_dir/VARIABLES
+ /prop_dir/VS_GLOBAL_SECTION_POST_section
+ /prop_dir/VS_GLOBAL_SECTION_PRE_section
+ /prop_dir/VS_STARTUP_PROJECT
+
+.. _`Target Properties`:
+
+Properties on Targets
+=====================
+
+.. toctree::
+ :maxdepth: 1
+
+ /prop_tgt/ADDITIONAL_CLEAN_FILES
+ /prop_tgt/AIX_EXPORT_ALL_SYMBOLS
+ /prop_tgt/ALIAS_GLOBAL
+ /prop_tgt/ALIASED_TARGET
+ /prop_tgt/ANDROID_ANT_ADDITIONAL_OPTIONS
+ /prop_tgt/ANDROID_API
+ /prop_tgt/ANDROID_API_MIN
+ /prop_tgt/ANDROID_ARCH
+ /prop_tgt/ANDROID_ASSETS_DIRECTORIES
+ /prop_tgt/ANDROID_GUI
+ /prop_tgt/ANDROID_JAR_DEPENDENCIES
+ /prop_tgt/ANDROID_JAR_DIRECTORIES
+ /prop_tgt/ANDROID_JAVA_SOURCE_DIR
+ /prop_tgt/ANDROID_NATIVE_LIB_DEPENDENCIES
+ /prop_tgt/ANDROID_NATIVE_LIB_DIRECTORIES
+ /prop_tgt/ANDROID_PROCESS_MAX
+ /prop_tgt/ANDROID_PROGUARD
+ /prop_tgt/ANDROID_PROGUARD_CONFIG_PATH
+ /prop_tgt/ANDROID_SECURE_PROPS_PATH
+ /prop_tgt/ANDROID_SKIP_ANT_STEP
+ /prop_tgt/ANDROID_STL_TYPE
+ /prop_tgt/ARCHIVE_OUTPUT_DIRECTORY
+ /prop_tgt/ARCHIVE_OUTPUT_DIRECTORY_CONFIG
+ /prop_tgt/ARCHIVE_OUTPUT_NAME
+ /prop_tgt/ARCHIVE_OUTPUT_NAME_CONFIG
+ /prop_tgt/AUTOGEN_BUILD_DIR
+ /prop_tgt/AUTOGEN_ORIGIN_DEPENDS
+ /prop_tgt/AUTOGEN_PARALLEL
+ /prop_tgt/AUTOGEN_TARGET_DEPENDS
+ /prop_tgt/AUTOMOC
+ /prop_tgt/AUTOMOC_COMPILER_PREDEFINES
+ /prop_tgt/AUTOMOC_DEPEND_FILTERS
+ /prop_tgt/AUTOMOC_EXECUTABLE
+ /prop_tgt/AUTOMOC_MACRO_NAMES
+ /prop_tgt/AUTOMOC_MOC_OPTIONS
+ /prop_tgt/AUTOMOC_PATH_PREFIX
+ /prop_tgt/AUTORCC
+ /prop_tgt/AUTORCC_EXECUTABLE
+ /prop_tgt/AUTORCC_OPTIONS
+ /prop_tgt/AUTOUIC
+ /prop_tgt/AUTOUIC_EXECUTABLE
+ /prop_tgt/AUTOUIC_OPTIONS
+ /prop_tgt/AUTOUIC_SEARCH_PATHS
+ /prop_tgt/BINARY_DIR
+ /prop_tgt/BUILD_RPATH
+ /prop_tgt/BUILD_RPATH_USE_ORIGIN
+ /prop_tgt/BUILD_WITH_INSTALL_NAME_DIR
+ /prop_tgt/BUILD_WITH_INSTALL_RPATH
+ /prop_tgt/BUNDLE
+ /prop_tgt/BUNDLE_EXTENSION
+ /prop_tgt/C_EXTENSIONS
+ /prop_tgt/C_STANDARD
+ /prop_tgt/C_STANDARD_REQUIRED
+ /prop_tgt/COMMON_LANGUAGE_RUNTIME
+ /prop_tgt/COMPATIBLE_INTERFACE_BOOL
+ /prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MAX
+ /prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MIN
+ /prop_tgt/COMPATIBLE_INTERFACE_STRING
+ /prop_tgt/COMPILE_DEFINITIONS
+ /prop_tgt/COMPILE_FEATURES
+ /prop_tgt/COMPILE_FLAGS
+ /prop_tgt/COMPILE_OPTIONS
+ /prop_tgt/COMPILE_PDB_NAME
+ /prop_tgt/COMPILE_PDB_NAME_CONFIG
+ /prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY
+ /prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG
+ /prop_tgt/CONFIG_OUTPUT_NAME
+ /prop_tgt/CONFIG_POSTFIX
+ /prop_tgt/CROSSCOMPILING_EMULATOR
+ /prop_tgt/CUDA_ARCHITECTURES
+ /prop_tgt/CUDA_EXTENSIONS
+ /prop_tgt/CUDA_PTX_COMPILATION
+ /prop_tgt/CUDA_RESOLVE_DEVICE_SYMBOLS
+ /prop_tgt/CUDA_RUNTIME_LIBRARY
+ /prop_tgt/CUDA_SEPARABLE_COMPILATION
+ /prop_tgt/CUDA_STANDARD
+ /prop_tgt/CUDA_STANDARD_REQUIRED
+ /prop_tgt/CXX_EXTENSIONS
+ /prop_tgt/CXX_STANDARD
+ /prop_tgt/CXX_STANDARD_REQUIRED
+ /prop_tgt/DEBUG_POSTFIX
+ /prop_tgt/DEFINE_SYMBOL
+ /prop_tgt/DEPLOYMENT_ADDITIONAL_FILES
+ /prop_tgt/DEPLOYMENT_REMOTE_DIRECTORY
+ /prop_tgt/DEPRECATION
+ /prop_tgt/DISABLE_PRECOMPILE_HEADERS
+ /prop_tgt/DOTNET_TARGET_FRAMEWORK
+ /prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION
+ /prop_tgt/EchoString
+ /prop_tgt/ENABLE_EXPORTS
+ /prop_tgt/EXCLUDE_FROM_ALL
+ /prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD
+ /prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG
+ /prop_tgt/EXPORT_COMPILE_COMMANDS
+ /prop_tgt/EXPORT_NAME
+ /prop_tgt/EXPORT_PROPERTIES
+ /prop_tgt/FOLDER
+ /prop_tgt/Fortran_FORMAT
+ /prop_tgt/Fortran_MODULE_DIRECTORY
+ /prop_tgt/Fortran_PREPROCESS
+ /prop_tgt/FRAMEWORK
+ /prop_tgt/FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG
+ /prop_tgt/FRAMEWORK_VERSION
+ /prop_tgt/GENERATOR_FILE_NAME
+ /prop_tgt/GHS_INTEGRITY_APP
+ /prop_tgt/GHS_NO_SOURCE_GROUP_FILE
+ /prop_tgt/GNUtoMS
+ /prop_tgt/HAS_CXX
+ /prop_tgt/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
+ /prop_tgt/IMPORTED
+ /prop_tgt/IMPORTED_COMMON_LANGUAGE_RUNTIME
+ /prop_tgt/IMPORTED_CONFIGURATIONS
+ /prop_tgt/IMPORTED_GLOBAL
+ /prop_tgt/IMPORTED_IMPLIB
+ /prop_tgt/IMPORTED_IMPLIB_CONFIG
+ /prop_tgt/IMPORTED_LIBNAME
+ /prop_tgt/IMPORTED_LIBNAME_CONFIG
+ /prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES
+ /prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG
+ /prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES
+ /prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG
+ /prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES
+ /prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES_CONFIG
+ /prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY
+ /prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY_CONFIG
+ /prop_tgt/IMPORTED_LOCATION
+ /prop_tgt/IMPORTED_LOCATION_CONFIG
+ /prop_tgt/IMPORTED_NO_SONAME
+ /prop_tgt/IMPORTED_NO_SONAME_CONFIG
+ /prop_tgt/IMPORTED_OBJECTS
+ /prop_tgt/IMPORTED_OBJECTS_CONFIG
+ /prop_tgt/IMPORTED_SONAME
+ /prop_tgt/IMPORTED_SONAME_CONFIG
+ /prop_tgt/IMPORT_PREFIX
+ /prop_tgt/IMPORT_SUFFIX
+ /prop_tgt/INCLUDE_DIRECTORIES
+ /prop_tgt/INSTALL_NAME_DIR
+ /prop_tgt/INSTALL_REMOVE_ENVIRONMENT_RPATH
+ /prop_tgt/INSTALL_RPATH
+ /prop_tgt/INSTALL_RPATH_USE_LINK_PATH
+ /prop_tgt/INTERFACE_AUTOUIC_OPTIONS
+ /prop_tgt/INTERFACE_COMPILE_DEFINITIONS
+ /prop_tgt/INTERFACE_COMPILE_FEATURES
+ /prop_tgt/INTERFACE_COMPILE_OPTIONS
+ /prop_tgt/INTERFACE_INCLUDE_DIRECTORIES
+ /prop_tgt/INTERFACE_LINK_DEPENDS
+ /prop_tgt/INTERFACE_LINK_DIRECTORIES
+ /prop_tgt/INTERFACE_LINK_LIBRARIES
+ /prop_tgt/INTERFACE_LINK_OPTIONS
+ /prop_tgt/INTERFACE_POSITION_INDEPENDENT_CODE
+ /prop_tgt/INTERFACE_PRECOMPILE_HEADERS
+ /prop_tgt/INTERFACE_SOURCES
+ /prop_tgt/INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
+ /prop_tgt/INTERPROCEDURAL_OPTIMIZATION
+ /prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG
+ /prop_tgt/IOS_INSTALL_COMBINED
+ /prop_tgt/ISPC_HEADER_DIRECTORY
+ /prop_tgt/ISPC_HEADER_SUFFIX
+ /prop_tgt/ISPC_INSTRUCTION_SETS
+ /prop_tgt/JOB_POOL_COMPILE
+ /prop_tgt/JOB_POOL_LINK
+ /prop_tgt/JOB_POOL_PRECOMPILE_HEADER
+ /prop_tgt/LABELS
+ /prop_tgt/LANG_CLANG_TIDY
+ /prop_tgt/LANG_COMPILER_LAUNCHER
+ /prop_tgt/LANG_CPPCHECK
+ /prop_tgt/LANG_CPPLINT
+ /prop_tgt/LANG_INCLUDE_WHAT_YOU_USE
+ /prop_tgt/LANG_VISIBILITY_PRESET
+ /prop_tgt/LIBRARY_OUTPUT_DIRECTORY
+ /prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG
+ /prop_tgt/LIBRARY_OUTPUT_NAME
+ /prop_tgt/LIBRARY_OUTPUT_NAME_CONFIG
+ /prop_tgt/LINK_DEPENDS
+ /prop_tgt/LINK_DEPENDS_NO_SHARED
+ /prop_tgt/LINK_DIRECTORIES
+ /prop_tgt/LINK_FLAGS
+ /prop_tgt/LINK_FLAGS_CONFIG
+ /prop_tgt/LINK_INTERFACE_LIBRARIES
+ /prop_tgt/LINK_INTERFACE_LIBRARIES_CONFIG
+ /prop_tgt/LINK_INTERFACE_MULTIPLICITY
+ /prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG
+ /prop_tgt/LINK_LIBRARIES
+ /prop_tgt/LINK_OPTIONS
+ /prop_tgt/LINK_SEARCH_END_STATIC
+ /prop_tgt/LINK_SEARCH_START_STATIC
+ /prop_tgt/LINK_WHAT_YOU_USE
+ /prop_tgt/LINKER_LANGUAGE
+ /prop_tgt/LOCATION
+ /prop_tgt/LOCATION_CONFIG
+ /prop_tgt/MACHO_COMPATIBILITY_VERSION
+ /prop_tgt/MACHO_CURRENT_VERSION
+ /prop_tgt/MACOSX_BUNDLE
+ /prop_tgt/MACOSX_BUNDLE_INFO_PLIST
+ /prop_tgt/MACOSX_FRAMEWORK_INFO_PLIST
+ /prop_tgt/MACOSX_RPATH
+ /prop_tgt/MANUALLY_ADDED_DEPENDENCIES
+ /prop_tgt/MAP_IMPORTED_CONFIG_CONFIG
+ /prop_tgt/MSVC_RUNTIME_LIBRARY
+ /prop_tgt/NAME
+ /prop_tgt/NO_SONAME
+ /prop_tgt/NO_SYSTEM_FROM_IMPORTED
+ /prop_tgt/OBJC_EXTENSIONS
+ /prop_tgt/OBJC_STANDARD
+ /prop_tgt/OBJC_STANDARD_REQUIRED
+ /prop_tgt/OBJCXX_EXTENSIONS
+ /prop_tgt/OBJCXX_STANDARD
+ /prop_tgt/OBJCXX_STANDARD_REQUIRED
+ /prop_tgt/OPTIMIZE_DEPENDENCIES
+ /prop_tgt/OSX_ARCHITECTURES
+ /prop_tgt/OSX_ARCHITECTURES_CONFIG
+ /prop_tgt/OUTPUT_NAME
+ /prop_tgt/OUTPUT_NAME_CONFIG
+ /prop_tgt/PCH_WARN_INVALID
+ /prop_tgt/PCH_INSTANTIATE_TEMPLATES
+ /prop_tgt/PDB_NAME
+ /prop_tgt/PDB_NAME_CONFIG
+ /prop_tgt/PDB_OUTPUT_DIRECTORY
+ /prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG
+ /prop_tgt/POSITION_INDEPENDENT_CODE
+ /prop_tgt/PRECOMPILE_HEADERS
+ /prop_tgt/PRECOMPILE_HEADERS_REUSE_FROM
+ /prop_tgt/PREFIX
+ /prop_tgt/PRIVATE_HEADER
+ /prop_tgt/PROJECT_LABEL
+ /prop_tgt/PUBLIC_HEADER
+ /prop_tgt/RESOURCE
+ /prop_tgt/RULE_LAUNCH_COMPILE
+ /prop_tgt/RULE_LAUNCH_CUSTOM
+ /prop_tgt/RULE_LAUNCH_LINK
+ /prop_tgt/RUNTIME_OUTPUT_DIRECTORY
+ /prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG
+ /prop_tgt/RUNTIME_OUTPUT_NAME
+ /prop_tgt/RUNTIME_OUTPUT_NAME_CONFIG
+ /prop_tgt/SKIP_BUILD_RPATH
+ /prop_tgt/SOURCE_DIR
+ /prop_tgt/SOURCES
+ /prop_tgt/SOVERSION
+ /prop_tgt/STATIC_LIBRARY_FLAGS
+ /prop_tgt/STATIC_LIBRARY_FLAGS_CONFIG
+ /prop_tgt/STATIC_LIBRARY_OPTIONS
+ /prop_tgt/SUFFIX
+ /prop_tgt/Swift_DEPENDENCIES_FILE
+ /prop_tgt/Swift_LANGUAGE_VERSION
+ /prop_tgt/Swift_MODULE_DIRECTORY
+ /prop_tgt/Swift_MODULE_NAME
+ /prop_tgt/TYPE
+ /prop_tgt/UNITY_BUILD
+ /prop_tgt/UNITY_BUILD_BATCH_SIZE
+ /prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE
+ /prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE
+ /prop_tgt/UNITY_BUILD_MODE
+ /prop_tgt/UNITY_BUILD_UNIQUE_ID
+ /prop_tgt/VERSION
+ /prop_tgt/VISIBILITY_INLINES_HIDDEN
+ /prop_tgt/VS_CONFIGURATION_TYPE
+ /prop_tgt/VS_DEBUGGER_COMMAND
+ /prop_tgt/VS_DEBUGGER_COMMAND_ARGUMENTS
+ /prop_tgt/VS_DEBUGGER_ENVIRONMENT
+ /prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY
+ /prop_tgt/VS_DESKTOP_EXTENSIONS_VERSION
+ /prop_tgt/VS_DOTNET_DOCUMENTATION_FILE
+ /prop_tgt/VS_DOTNET_REFERENCE_refname
+ /prop_tgt/VS_DOTNET_REFERENCEPROP_refname_TAG_tagname
+ /prop_tgt/VS_DOTNET_REFERENCES
+ /prop_tgt/VS_DOTNET_REFERENCES_COPY_LOCAL
+ /prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION
+ /prop_tgt/VS_DPI_AWARE
+ /prop_tgt/VS_GLOBAL_KEYWORD
+ /prop_tgt/VS_GLOBAL_PROJECT_TYPES
+ /prop_tgt/VS_GLOBAL_ROOTNAMESPACE
+ /prop_tgt/VS_GLOBAL_variable
+ /prop_tgt/VS_IOT_EXTENSIONS_VERSION
+ /prop_tgt/VS_IOT_STARTUP_TASK
+ /prop_tgt/VS_JUST_MY_CODE_DEBUGGING
+ /prop_tgt/VS_KEYWORD
+ /prop_tgt/VS_MOBILE_EXTENSIONS_VERSION
+ /prop_tgt/VS_NO_SOLUTION_DEPLOY
+ /prop_tgt/VS_PACKAGE_REFERENCES
+ /prop_tgt/VS_PLATFORM_TOOLSET
+ /prop_tgt/VS_PROJECT_IMPORT
+ /prop_tgt/VS_SCC_AUXPATH
+ /prop_tgt/VS_SCC_LOCALPATH
+ /prop_tgt/VS_SCC_PROJECTNAME
+ /prop_tgt/VS_SCC_PROVIDER
+ /prop_tgt/VS_SDK_REFERENCES
+ /prop_tgt/VS_SOLUTION_DEPLOY
+ /prop_tgt/VS_SOURCE_SETTINGS_tool
+ /prop_tgt/VS_USER_PROPS
+ /prop_tgt/VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION
+ /prop_tgt/VS_WINRT_COMPONENT
+ /prop_tgt/VS_WINRT_EXTENSIONS
+ /prop_tgt/VS_WINRT_REFERENCES
+ /prop_tgt/WIN32_EXECUTABLE
+ /prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS
+ /prop_tgt/XCODE_ATTRIBUTE_an-attribute
+ /prop_tgt/XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY
+ /prop_tgt/XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY
+ /prop_tgt/XCODE_EMBED_type
+ /prop_tgt/XCODE_EMBED_type_PATH
+ /prop_tgt/XCODE_EXPLICIT_FILE_TYPE
+ /prop_tgt/XCODE_GENERATE_SCHEME
+ /prop_tgt/XCODE_LINK_BUILD_PHASE_MODE
+ /prop_tgt/XCODE_PRODUCT_TYPE
+ /prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER
+ /prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN
+ /prop_tgt/XCODE_SCHEME_ARGUMENTS
+ /prop_tgt/XCODE_SCHEME_DEBUG_AS_ROOT
+ /prop_tgt/XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING
+ /prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
+ /prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
+ /prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
+ /prop_tgt/XCODE_SCHEME_ENVIRONMENT
+ /prop_tgt/XCODE_SCHEME_EXECUTABLE
+ /prop_tgt/XCODE_SCHEME_GUARD_MALLOC
+ /prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP
+ /prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES
+ /prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE
+ /prop_tgt/XCODE_SCHEME_MALLOC_STACK
+ /prop_tgt/XCODE_SCHEME_THREAD_SANITIZER
+ /prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP
+ /prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER
+ /prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP
+ /prop_tgt/XCODE_SCHEME_WORKING_DIRECTORY
+ /prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS
+ /prop_tgt/XCTEST
+
+.. _`Test Properties`:
+
+Properties on Tests
+===================
+
+.. toctree::
+ :maxdepth: 1
+
+ /prop_test/ATTACHED_FILES
+ /prop_test/ATTACHED_FILES_ON_FAIL
+ /prop_test/COST
+ /prop_test/DEPENDS
+ /prop_test/DISABLED
+ /prop_test/ENVIRONMENT
+ /prop_test/FAIL_REGULAR_EXPRESSION
+ /prop_test/FIXTURES_CLEANUP
+ /prop_test/FIXTURES_REQUIRED
+ /prop_test/FIXTURES_SETUP
+ /prop_test/LABELS
+ /prop_test/MEASUREMENT
+ /prop_test/PASS_REGULAR_EXPRESSION
+ /prop_test/PROCESSOR_AFFINITY
+ /prop_test/PROCESSORS
+ /prop_test/REQUIRED_FILES
+ /prop_test/RESOURCE_GROUPS
+ /prop_test/RESOURCE_LOCK
+ /prop_test/RUN_SERIAL
+ /prop_test/SKIP_REGULAR_EXPRESSION
+ /prop_test/SKIP_RETURN_CODE
+ /prop_test/TIMEOUT
+ /prop_test/TIMEOUT_AFTER_MATCH
+ /prop_test/WILL_FAIL
+ /prop_test/WORKING_DIRECTORY
+
+.. _`Source File Properties`:
+
+Properties on Source Files
+==========================
+
+.. toctree::
+ :maxdepth: 1
+
+ /prop_sf/ABSTRACT
+ /prop_sf/AUTORCC_OPTIONS
+ /prop_sf/AUTOUIC_OPTIONS
+ /prop_sf/COMPILE_DEFINITIONS
+ /prop_sf/COMPILE_FLAGS
+ /prop_sf/COMPILE_OPTIONS
+ /prop_sf/EXTERNAL_OBJECT
+ /prop_sf/Fortran_FORMAT
+ /prop_sf/Fortran_PREPROCESS
+ /prop_sf/GENERATED
+ /prop_sf/HEADER_FILE_ONLY
+ /prop_sf/INCLUDE_DIRECTORIES
+ /prop_sf/KEEP_EXTENSION
+ /prop_sf/LABELS
+ /prop_sf/LANGUAGE
+ /prop_sf/LOCATION
+ /prop_sf/MACOSX_PACKAGE_LOCATION
+ /prop_sf/OBJECT_DEPENDS
+ /prop_sf/OBJECT_OUTPUTS
+ /prop_sf/SKIP_AUTOGEN
+ /prop_sf/SKIP_AUTOMOC
+ /prop_sf/SKIP_AUTORCC
+ /prop_sf/SKIP_AUTOUIC
+ /prop_sf/SKIP_PRECOMPILE_HEADERS
+ /prop_sf/SKIP_UNITY_BUILD_INCLUSION
+ /prop_sf/Swift_DEPENDENCIES_FILE
+ /prop_sf/Swift_DIAGNOSTICS_FILE
+ /prop_sf/SYMBOLIC
+ /prop_sf/UNITY_GROUP
+ /prop_sf/VS_COPY_TO_OUT_DIR
+ /prop_sf/VS_CSHARP_tagname
+ /prop_sf/VS_DEPLOYMENT_CONTENT
+ /prop_sf/VS_DEPLOYMENT_LOCATION
+ /prop_sf/VS_INCLUDE_IN_VSIX
+ /prop_sf/VS_RESOURCE_GENERATOR
+ /prop_sf/VS_SETTINGS
+ /prop_sf/VS_SHADER_DISABLE_OPTIMIZATIONS
+ /prop_sf/VS_SHADER_ENABLE_DEBUG
+ /prop_sf/VS_SHADER_ENTRYPOINT
+ /prop_sf/VS_SHADER_FLAGS
+ /prop_sf/VS_SHADER_MODEL
+ /prop_sf/VS_SHADER_OBJECT_FILE_NAME
+ /prop_sf/VS_SHADER_OUTPUT_HEADER_FILE
+ /prop_sf/VS_SHADER_TYPE
+ /prop_sf/VS_SHADER_VARIABLE_NAME
+ /prop_sf/VS_TOOL_OVERRIDE.rst
+ /prop_sf/VS_XAML_TYPE
+ /prop_sf/WRAP_EXCLUDE
+ /prop_sf/XCODE_EXPLICIT_FILE_TYPE
+ /prop_sf/XCODE_FILE_ATTRIBUTES
+ /prop_sf/XCODE_LAST_KNOWN_FILE_TYPE
+
+.. _`Cache Entry Properties`:
+
+Properties on Cache Entries
+===========================
+
+.. toctree::
+ :maxdepth: 1
+
+ /prop_cache/ADVANCED
+ /prop_cache/HELPSTRING
+ /prop_cache/MODIFIED
+ /prop_cache/STRINGS
+ /prop_cache/TYPE
+ /prop_cache/VALUE
+
+.. _`Installed File Properties`:
+
+Properties on Installed Files
+=============================
+
+.. toctree::
+ :maxdepth: 1
+
+ /prop_inst/CPACK_DESKTOP_SHORTCUTS.rst
+ /prop_inst/CPACK_NEVER_OVERWRITE.rst
+ /prop_inst/CPACK_PERMANENT.rst
+ /prop_inst/CPACK_START_MENU_SHORTCUTS.rst
+ /prop_inst/CPACK_STARTUP_SHORTCUTS.rst
+ /prop_inst/CPACK_WIX_ACL.rst
+
+
+Deprecated Properties on Directories
+====================================
+
+.. toctree::
+ :maxdepth: 1
+
+ /prop_dir/ADDITIONAL_MAKE_CLEAN_FILES
+ /prop_dir/COMPILE_DEFINITIONS_CONFIG
+ /prop_dir/TEST_INCLUDE_FILE
+
+
+Deprecated Properties on Targets
+================================
+
+.. toctree::
+ :maxdepth: 1
+
+ /prop_tgt/COMPILE_DEFINITIONS_CONFIG
+ /prop_tgt/POST_INSTALL_SCRIPT
+ /prop_tgt/PRE_INSTALL_SCRIPT
+
+
+Deprecated Properties on Source Files
+=====================================
+
+.. toctree::
+ :maxdepth: 1
+
+ /prop_sf/COMPILE_DEFINITIONS_CONFIG
diff --git a/Help/manual/cmake-qt.7.rst b/Help/manual/cmake-qt.7.rst
new file mode 100644
index 0000000..f156f95
--- /dev/null
+++ b/Help/manual/cmake-qt.7.rst
@@ -0,0 +1,262 @@
+.. cmake-manual-description: CMake Qt Features Reference
+
+cmake-qt(7)
+***********
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+CMake can find and use Qt 4 and Qt 5 libraries. The Qt 4 libraries are found
+by the :module:`FindQt4` find-module shipped with CMake, whereas the
+Qt 5 libraries are found using "Config-file Packages" shipped with Qt 5. See
+:manual:`cmake-packages(7)` for more information about CMake packages, and
+see `the Qt cmake manual <http://qt-project.org/doc/qt-5/cmake-manual.html>`_
+for your Qt version.
+
+Qt 4 and Qt 5 may be used together in the same
+:manual:`CMake buildsystem <cmake-buildsystem(7)>`:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR)
+
+ project(Qt4And5)
+
+ set(CMAKE_AUTOMOC ON)
+
+ find_package(Qt5 COMPONENTS Widgets DBus REQUIRED)
+ add_executable(publisher publisher.cpp)
+ target_link_libraries(publisher Qt5::Widgets Qt5::DBus)
+
+ find_package(Qt4 REQUIRED)
+ add_executable(subscriber subscriber.cpp)
+ target_link_libraries(subscriber Qt4::QtGui Qt4::QtDBus)
+
+A CMake target may not link to both Qt 4 and Qt 5. A diagnostic is issued if
+this is attempted or results from transitive target dependency evaluation.
+
+Qt Build Tools
+==============
+
+Qt relies on some bundled tools for code generation, such as ``moc`` for
+meta-object code generation, ``uic`` for widget layout and population,
+and ``rcc`` for virtual file system content generation. These tools may be
+automatically invoked by :manual:`cmake(1)` if the appropriate conditions
+are met. The automatic tool invocation may be used with both Qt 4 and Qt 5.
+
+.. _`Qt AUTOMOC`:
+
+AUTOMOC
+^^^^^^^
+
+The :prop_tgt:`AUTOMOC` target property controls whether :manual:`cmake(1)`
+inspects the C++ files in the target to determine if they require ``moc`` to
+be run, and to create rules to execute ``moc`` at the appropriate time.
+
+If a macro from :prop_tgt:`AUTOMOC_MACRO_NAMES` is found in a header file,
+``moc`` will be run on the file. The result will be put into a file named
+according to ``moc_<basename>.cpp``.
+If the macro is found in a C++ implementation
+file, the moc output will be put into a file named according to
+``<basename>.moc``, following the Qt conventions. The ``<basename>.moc`` must
+be included by the user in the C++ implementation file with a preprocessor
+``#include``.
+
+Included ``moc_*.cpp`` and ``*.moc`` files will be generated in the
+``<AUTOGEN_BUILD_DIR>/include`` directory which is
+automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`.
+
+* This differs from CMake 3.7 and below; see their documentation for details.
+
+* For :prop_gbl:`multi configuration generators <GENERATOR_IS_MULTI_CONFIG>`,
+ the include directory is ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>``.
+
+* See :prop_tgt:`AUTOGEN_BUILD_DIR`.
+
+Not included ``moc_<basename>.cpp`` files will be generated in custom
+folders to avoid name collisions and included in a separate
+file which is compiled into the target, named either
+``<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp`` or
+``<AUTOGEN_BUILD_DIR>/mocs_compilation_$<CONFIG>.cpp``.
+
+* See :prop_tgt:`AUTOGEN_BUILD_DIR`.
+
+The ``moc`` command line will consume the :prop_tgt:`COMPILE_DEFINITIONS` and
+:prop_tgt:`INCLUDE_DIRECTORIES` target properties from the target it is being
+invoked for, and for the appropriate build configuration.
+
+The :prop_tgt:`AUTOMOC` target property may be pre-set for all
+following targets by setting the :variable:`CMAKE_AUTOMOC` variable. The
+:prop_tgt:`AUTOMOC_MOC_OPTIONS` target property may be populated to set
+options to pass to ``moc``. The :variable:`CMAKE_AUTOMOC_MOC_OPTIONS`
+variable may be populated to pre-set the options for all following targets.
+
+Additional macro names to search for can be added to
+:prop_tgt:`AUTOMOC_MACRO_NAMES`.
+
+Additional ``moc`` dependency file names can be extracted from source code
+by using :prop_tgt:`AUTOMOC_DEPEND_FILTERS`.
+
+Source C++ files can be excluded from :prop_tgt:`AUTOMOC` processing by
+enabling :prop_sf:`SKIP_AUTOMOC` or the broader :prop_sf:`SKIP_AUTOGEN`.
+
+.. _`Qt AUTOUIC`:
+
+AUTOUIC
+^^^^^^^
+
+The :prop_tgt:`AUTOUIC` target property controls whether :manual:`cmake(1)`
+inspects the C++ files in the target to determine if they require ``uic`` to
+be run, and to create rules to execute ``uic`` at the appropriate time.
+
+If a preprocessor ``#include`` directive is found which matches
+``<path>ui_<basename>.h``, and a ``<basename>.ui`` file exists,
+then ``uic`` will be executed to generate the appropriate file.
+The ``<basename>.ui`` file is searched for in the following places
+
+1. ``<source_dir>/<basename>.ui``
+2. ``<source_dir>/<path><basename>.ui``
+3. ``<AUTOUIC_SEARCH_PATHS>/<basename>.ui``
+4. ``<AUTOUIC_SEARCH_PATHS>/<path><basename>.ui``
+
+where ``<source_dir>`` is the directory of the C++ file and
+:prop_tgt:`AUTOUIC_SEARCH_PATHS` is a list of additional search paths.
+
+The generated generated ``ui_*.h`` files are placed in the
+``<AUTOGEN_BUILD_DIR>/include`` directory which is
+automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`.
+
+* This differs from CMake 3.7 and below; see their documentation for details.
+
+* For :prop_gbl:`multi configuration generators <GENERATOR_IS_MULTI_CONFIG>`,
+ the include directory is ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>``.
+
+* See :prop_tgt:`AUTOGEN_BUILD_DIR`.
+
+The :prop_tgt:`AUTOUIC` target property may be pre-set for all following
+targets by setting the :variable:`CMAKE_AUTOUIC` variable. The
+:prop_tgt:`AUTOUIC_OPTIONS` target property may be populated to set options
+to pass to ``uic``. The :variable:`CMAKE_AUTOUIC_OPTIONS` variable may be
+populated to pre-set the options for all following targets. The
+:prop_sf:`AUTOUIC_OPTIONS` source file property may be set on the
+``<basename>.ui`` file to set particular options for the file. This
+overrides options from the :prop_tgt:`AUTOUIC_OPTIONS` target property.
+
+A target may populate the :prop_tgt:`INTERFACE_AUTOUIC_OPTIONS` target
+property with options that should be used when invoking ``uic``. This must be
+consistent with the :prop_tgt:`AUTOUIC_OPTIONS` target property content of the
+depender target. The :variable:`CMAKE_DEBUG_TARGET_PROPERTIES` variable may
+be used to track the origin target of such
+:prop_tgt:`INTERFACE_AUTOUIC_OPTIONS`. This means that a library which
+provides an alternative translation system for Qt may specify options which
+should be used when running ``uic``:
+
+.. code-block:: cmake
+
+ add_library(KI18n klocalizedstring.cpp)
+ target_link_libraries(KI18n Qt5::Core)
+
+ # KI18n uses the tr2i18n() function instead of tr(). That function is
+ # declared in the klocalizedstring.h header.
+ set(autouic_options
+ -tr tr2i18n
+ -include klocalizedstring.h
+ )
+
+ set_property(TARGET KI18n APPEND PROPERTY
+ INTERFACE_AUTOUIC_OPTIONS ${autouic_options}
+ )
+
+A consuming project linking to the target exported from upstream automatically
+uses appropriate options when ``uic`` is run by :prop_tgt:`AUTOUIC`, as a
+result of linking with the :prop_tgt:`IMPORTED` target:
+
+.. code-block:: cmake
+
+ set(CMAKE_AUTOUIC ON)
+ # Uses a libwidget.ui file:
+ add_library(LibWidget libwidget.cpp)
+ target_link_libraries(LibWidget
+ KF5::KI18n
+ Qt5::Widgets
+ )
+
+Source files can be excluded from :prop_tgt:`AUTOUIC` processing by
+enabling :prop_sf:`SKIP_AUTOUIC` or the broader :prop_sf:`SKIP_AUTOGEN`.
+
+.. _`Qt AUTORCC`:
+
+AUTORCC
+^^^^^^^
+
+The :prop_tgt:`AUTORCC` target property controls whether :manual:`cmake(1)`
+creates rules to execute ``rcc`` at the appropriate time on source files
+which have the suffix ``.qrc``.
+
+.. code-block:: cmake
+
+ add_executable(myexe main.cpp resource_file.qrc)
+
+The :prop_tgt:`AUTORCC` target property may be pre-set for all following targets
+by setting the :variable:`CMAKE_AUTORCC` variable. The
+:prop_tgt:`AUTORCC_OPTIONS` target property may be populated to set options
+to pass to ``rcc``. The :variable:`CMAKE_AUTORCC_OPTIONS` variable may be
+populated to pre-set the options for all following targets. The
+:prop_sf:`AUTORCC_OPTIONS` source file property may be set on the
+``<name>.qrc`` file to set particular options for the file. This
+overrides options from the :prop_tgt:`AUTORCC_OPTIONS` target property.
+
+Source files can be excluded from :prop_tgt:`AUTORCC` processing by
+enabling :prop_sf:`SKIP_AUTORCC` or the broader :prop_sf:`SKIP_AUTOGEN`.
+
+The ``<ORIGIN>_autogen`` target
+===============================
+
+The ``moc`` and ``uic`` tools are executed as part of a synthesized
+``<ORIGIN>_autogen`` :command:`custom target <add_custom_target>` generated by
+CMake. By default that ``<ORIGIN>_autogen`` target inherits the dependencies
+of the ``<ORIGIN>`` target (see :prop_tgt:`AUTOGEN_ORIGIN_DEPENDS`).
+Target dependencies may be added to the ``<ORIGIN>_autogen`` target by adding
+them to the :prop_tgt:`AUTOGEN_TARGET_DEPENDS` target property.
+
+Visual Studio Generators
+========================
+
+When using the :manual:`Visual Studio generators <cmake-generators(7)>`, CMake
+generates a ``PRE_BUILD`` :command:`custom command <add_custom_command>`
+instead of the ``<ORIGIN>_autogen`` :command:`custom target <add_custom_target>`
+(for :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`).
+This isn't always possible though and
+an ``<ORIGIN>_autogen`` :command:`custom target <add_custom_target>` is used,
+when either
+
+- the ``<ORIGIN>`` target depends on :prop_sf:`GENERATED` files which aren't
+ excluded from :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC` by
+ :prop_sf:`SKIP_AUTOMOC`, :prop_sf:`SKIP_AUTOUIC`, :prop_sf:`SKIP_AUTOGEN`
+ or :policy:`CMP0071`
+- :prop_tgt:`AUTOGEN_TARGET_DEPENDS` lists a source file
+- :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET` is enabled
+
+qtmain.lib on Windows
+=====================
+
+The Qt 4 and 5 :prop_tgt:`IMPORTED` targets for the QtGui libraries specify
+that the qtmain.lib static library shipped with Qt will be linked by all
+dependent executables which have the :prop_tgt:`WIN32_EXECUTABLE` enabled.
+
+To disable this behavior, enable the ``Qt5_NO_LINK_QTMAIN`` target property for
+Qt 5 based targets or ``QT4_NO_LINK_QTMAIN`` target property for Qt 4 based
+targets.
+
+.. code-block:: cmake
+
+ add_executable(myexe WIN32 main.cpp)
+ target_link_libraries(myexe Qt4::QtGui)
+
+ add_executable(myexe_no_qtmain WIN32 main_no_qtmain.cpp)
+ set_property(TARGET main_no_qtmain PROPERTY QT4_NO_LINK_QTMAIN ON)
+ target_link_libraries(main_no_qtmain Qt4::QtGui)
diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst
new file mode 100644
index 0000000..6c8d0f4
--- /dev/null
+++ b/Help/manual/cmake-server.7.rst
@@ -0,0 +1,7 @@
+.. cmake-manual-description: CMake Server
+
+cmake-server(7)
+***************
+
+The :manual:`cmake(1)` server mode has been removed since CMake 3.20.
+Clients should use the :manual:`cmake-file-api(7)` instead.
diff --git a/Help/manual/cmake-toolchains.7.rst b/Help/manual/cmake-toolchains.7.rst
new file mode 100644
index 0000000..1ededee
--- /dev/null
+++ b/Help/manual/cmake-toolchains.7.rst
@@ -0,0 +1,672 @@
+.. cmake-manual-description: CMake Toolchains Reference
+
+cmake-toolchains(7)
+*******************
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+CMake uses a toolchain of utilities to compile, link libraries and create
+archives, and other tasks to drive the build. The toolchain utilities available
+are determined by the languages enabled. In normal builds, CMake automatically
+determines the toolchain for host builds based on system introspection and
+defaults. In cross-compiling scenarios, a toolchain file may be specified
+with information about compiler and utility paths.
+
+Languages
+=========
+
+Languages are enabled by the :command:`project` command. Language-specific
+built-in variables, such as
+:variable:`CMAKE_CXX_COMPILER <CMAKE_<LANG>_COMPILER>`,
+:variable:`CMAKE_CXX_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` etc are set by
+invoking the :command:`project` command. If no project command
+is in the top-level CMakeLists file, one will be implicitly generated. By default
+the enabled languages are ``C`` and ``CXX``:
+
+.. code-block:: cmake
+
+ project(C_Only C)
+
+A special value of ``NONE`` can also be used with the :command:`project` command
+to enable no languages:
+
+.. code-block:: cmake
+
+ project(MyProject NONE)
+
+The :command:`enable_language` command can be used to enable languages after the
+:command:`project` command:
+
+.. code-block:: cmake
+
+ enable_language(CXX)
+
+When a language is enabled, CMake finds a compiler for that language, and
+determines some information, such as the vendor and version of the compiler,
+the target architecture and bitwidth, the location of corresponding utilities
+etc.
+
+The :prop_gbl:`ENABLED_LANGUAGES` global property contains the languages which
+are currently enabled.
+
+Variables and Properties
+========================
+
+Several variables relate to the language components of a toolchain which are
+enabled. :variable:`CMAKE_<LANG>_COMPILER` is the full path to the compiler used
+for ``<LANG>``. :variable:`CMAKE_<LANG>_COMPILER_ID` is the identifier used
+by CMake for the compiler and :variable:`CMAKE_<LANG>_COMPILER_VERSION` is the
+version of the compiler.
+
+The :variable:`CMAKE_<LANG>_FLAGS` variables and the configuration-specific
+equivalents contain flags that will be added to the compile command when
+compiling a file of a particular language.
+
+As the linker is invoked by the compiler driver, CMake needs a way to determine
+which compiler to use to invoke the linker. This is calculated by the
+:prop_sf:`LANGUAGE` of source files in the target, and in the case of static
+libraries, the language of the dependent libraries. The choice CMake makes may
+be overridden with the :prop_tgt:`LINKER_LANGUAGE` target property.
+
+Toolchain Features
+==================
+
+CMake provides the :command:`try_compile` command and wrapper macros such as
+:module:`CheckCXXSourceCompiles`, :module:`CheckCXXSymbolExists` and
+:module:`CheckIncludeFile` to test capability and availability of various
+toolchain features. These APIs test the toolchain in some way and cache the
+result so that the test does not have to be performed again the next time
+CMake runs.
+
+Some toolchain features have built-in handling in CMake, and do not require
+compile-tests. For example, :prop_tgt:`POSITION_INDEPENDENT_CODE` allows
+specifying that a target should be built as position-independent code, if
+the compiler supports that feature. The :prop_tgt:`<LANG>_VISIBILITY_PRESET`
+and :prop_tgt:`VISIBILITY_INLINES_HIDDEN` target properties add flags for
+hidden visibility, if supported by the compiler.
+
+.. _`Cross Compiling Toolchain`:
+
+Cross Compiling
+===============
+
+If :manual:`cmake(1)` is invoked with the command line parameter
+``-DCMAKE_TOOLCHAIN_FILE=path/to/file``, the file will be loaded early to set
+values for the compilers.
+The :variable:`CMAKE_CROSSCOMPILING` variable is set to true when CMake is
+cross-compiling.
+
+Note that using the :variable:`CMAKE_SOURCE_DIR` or :variable:`CMAKE_BINARY_DIR`
+variables inside a toolchain file is typically undesirable. The toolchain
+file is used in contexts where these variables have different values when used
+in different places (e.g. as part of a call to :command:`try_compile`). In most
+cases, where there is a need to evaluate paths inside a toolchain file, the more
+appropriate variable to use would be :variable:`CMAKE_CURRENT_LIST_DIR`, since
+it always has an unambiguous, predictable value.
+
+Cross Compiling for Linux
+-------------------------
+
+A typical cross-compiling toolchain for Linux has content such
+as:
+
+.. code-block:: cmake
+
+ set(CMAKE_SYSTEM_NAME Linux)
+ set(CMAKE_SYSTEM_PROCESSOR arm)
+
+ set(CMAKE_SYSROOT /home/devel/rasp-pi-rootfs)
+ set(CMAKE_STAGING_PREFIX /home/devel/stage)
+
+ set(tools /home/devel/gcc-4.7-linaro-rpi-gnueabihf)
+ set(CMAKE_C_COMPILER ${tools}/bin/arm-linux-gnueabihf-gcc)
+ set(CMAKE_CXX_COMPILER ${tools}/bin/arm-linux-gnueabihf-g++)
+
+ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+
+The :variable:`CMAKE_SYSTEM_NAME` is the CMake-identifier of the target platform
+to build for.
+
+The :variable:`CMAKE_SYSTEM_PROCESSOR` is the CMake-identifier of the target architecture
+to build for.
+
+The :variable:`CMAKE_SYSROOT` is optional, and may be specified if a sysroot
+is available.
+
+The :variable:`CMAKE_STAGING_PREFIX` is also optional. It may be used to specify
+a path on the host to install to. The :variable:`CMAKE_INSTALL_PREFIX` is always
+the runtime installation location, even when cross-compiling.
+
+The :variable:`CMAKE_<LANG>_COMPILER` variables may be set to full paths, or to
+names of compilers to search for in standard locations. For toolchains that
+do not support linking binaries without custom flags or scripts one may set
+the :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable to ``STATIC_LIBRARY``
+to tell CMake not to try to link executables during its checks.
+
+CMake ``find_*`` commands will look in the sysroot, and the :variable:`CMAKE_FIND_ROOT_PATH`
+entries by default in all cases, as well as looking in the host system root prefix.
+Although this can be controlled on a case-by-case basis, when cross-compiling, it
+can be useful to exclude looking in either the host or the target for particular
+artifacts. Generally, includes, libraries and packages should be found in the
+target system prefixes, whereas executables which must be run as part of the build
+should be found only on the host and not on the target. This is the purpose of
+the ``CMAKE_FIND_ROOT_PATH_MODE_*`` variables.
+
+.. _`Cray Cross-Compile`:
+
+Cross Compiling for the Cray Linux Environment
+----------------------------------------------
+
+Cross compiling for compute nodes in the Cray Linux Environment can be done
+without needing a separate toolchain file. Specifying
+``-DCMAKE_SYSTEM_NAME=CrayLinuxEnvironment`` on the CMake command line will
+ensure that the appropriate build settings and search paths are configured.
+The platform will pull its configuration from the current environment
+variables and will configure a project to use the compiler wrappers from the
+Cray Programming Environment's ``PrgEnv-*`` modules if present and loaded.
+
+The default configuration of the Cray Programming Environment is to only
+support static libraries. This can be overridden and shared libraries
+enabled by setting the ``CRAYPE_LINK_TYPE`` environment variable to
+``dynamic``.
+
+Running CMake without specifying :variable:`CMAKE_SYSTEM_NAME` will
+run the configure step in host mode assuming a standard Linux environment.
+If not overridden, the ``PrgEnv-*`` compiler wrappers will end up getting used,
+which if targeting the either the login node or compute node, is likely not the
+desired behavior. The exception to this would be if you are building directly
+on a NID instead of cross-compiling from a login node. If trying to build
+software for a login node, you will need to either first unload the
+currently loaded ``PrgEnv-*`` module or explicitly tell CMake to use the
+system compilers in ``/usr/bin`` instead of the Cray wrappers. If instead
+targeting a compute node is desired, just specify the
+:variable:`CMAKE_SYSTEM_NAME` as mentioned above.
+
+Cross Compiling using Clang
+---------------------------
+
+Some compilers such as Clang are inherently cross compilers.
+The :variable:`CMAKE_<LANG>_COMPILER_TARGET` can be set to pass a
+value to those supported compilers when compiling:
+
+.. code-block:: cmake
+
+ set(CMAKE_SYSTEM_NAME Linux)
+ set(CMAKE_SYSTEM_PROCESSOR arm)
+
+ set(triple arm-linux-gnueabihf)
+
+ set(CMAKE_C_COMPILER clang)
+ set(CMAKE_C_COMPILER_TARGET ${triple})
+ set(CMAKE_CXX_COMPILER clang++)
+ set(CMAKE_CXX_COMPILER_TARGET ${triple})
+
+Similarly, some compilers do not ship their own supplementary utilities
+such as linkers, but provide a way to specify the location of the external
+toolchain which will be used by the compiler driver. The
+:variable:`CMAKE_<LANG>_COMPILER_EXTERNAL_TOOLCHAIN` variable can be set in a
+toolchain file to pass the path to the compiler driver.
+
+Cross Compiling for QNX
+-----------------------
+
+As the Clang compiler the QNX QCC compile is inherently a cross compiler.
+And the :variable:`CMAKE_<LANG>_COMPILER_TARGET` can be set to pass a
+value to those supported compilers when compiling:
+
+.. code-block:: cmake
+
+ set(CMAKE_SYSTEM_NAME QNX)
+
+ set(arch gcc_ntoarmv7le)
+
+ set(CMAKE_C_COMPILER qcc)
+ set(CMAKE_C_COMPILER_TARGET ${arch})
+ set(CMAKE_CXX_COMPILER QCC)
+ set(CMAKE_CXX_COMPILER_TARGET ${arch})
+
+ set(CMAKE_SYSROOT $ENV{QNX_TARGET})
+
+
+Cross Compiling for Windows CE
+------------------------------
+
+Cross compiling for Windows CE requires the corresponding SDK being
+installed on your system. These SDKs are usually installed under
+``C:/Program Files (x86)/Windows CE Tools/SDKs``.
+
+A toolchain file to configure a Visual Studio generator for
+Windows CE may look like this:
+
+.. code-block:: cmake
+
+ set(CMAKE_SYSTEM_NAME WindowsCE)
+
+ set(CMAKE_SYSTEM_VERSION 8.0)
+ set(CMAKE_SYSTEM_PROCESSOR arm)
+
+ set(CMAKE_GENERATOR_TOOLSET CE800) # Can be omitted for 8.0
+ set(CMAKE_GENERATOR_PLATFORM SDK_AM335X_SK_WEC2013_V310)
+
+The :variable:`CMAKE_GENERATOR_PLATFORM` tells the generator which SDK to use.
+Further :variable:`CMAKE_SYSTEM_VERSION` tells the generator what version of
+Windows CE to use. Currently version 8.0 (Windows Embedded Compact 2013) is
+supported out of the box. Other versions may require one to set
+:variable:`CMAKE_GENERATOR_TOOLSET` to the correct value.
+
+Cross Compiling for Windows 10 Universal Applications
+-----------------------------------------------------
+
+A toolchain file to configure a Visual Studio generator for a
+Windows 10 Universal Application may look like this:
+
+.. code-block:: cmake
+
+ set(CMAKE_SYSTEM_NAME WindowsStore)
+ set(CMAKE_SYSTEM_VERSION 10.0)
+
+A Windows 10 Universal Application targets both Windows Store and
+Windows Phone. Specify the :variable:`CMAKE_SYSTEM_VERSION` variable
+to be ``10.0`` to build with the latest available Windows 10 SDK.
+Specify a more specific version (e.g. ``10.0.10240.0`` for RTM)
+to build with the corresponding SDK.
+
+Cross Compiling for Windows Phone
+---------------------------------
+
+A toolchain file to configure a Visual Studio generator for
+Windows Phone may look like this:
+
+.. code-block:: cmake
+
+ set(CMAKE_SYSTEM_NAME WindowsPhone)
+ set(CMAKE_SYSTEM_VERSION 8.1)
+
+Cross Compiling for Windows Store
+---------------------------------
+
+A toolchain file to configure a Visual Studio generator for
+Windows Store may look like this:
+
+.. code-block:: cmake
+
+ set(CMAKE_SYSTEM_NAME WindowsStore)
+ set(CMAKE_SYSTEM_VERSION 8.1)
+
+.. _`Cross Compiling for Android`:
+
+Cross Compiling for Android
+---------------------------
+
+A toolchain file may configure cross-compiling for Android by setting the
+:variable:`CMAKE_SYSTEM_NAME` variable to ``Android``. Further configuration
+is specific to the Android development environment to be used.
+
+For :ref:`Visual Studio Generators`, CMake expects :ref:`NVIDIA Nsight Tegra
+Visual Studio Edition <Cross Compiling for Android with NVIDIA Nsight Tegra
+Visual Studio Edition>` or the :ref:`Visual Studio tools for Android
+<Cross Compiling for Android with the NDK>` to be installed. See those sections
+for further configuration details.
+
+For :ref:`Makefile Generators` and the :generator:`Ninja` generator,
+CMake expects one of these environments:
+
+* :ref:`NDK <Cross Compiling for Android with the NDK>`
+* :ref:`Standalone Toolchain <Cross Compiling for Android with a Standalone Toolchain>`
+
+CMake uses the following steps to select one of the environments:
+
+* If the :variable:`CMAKE_ANDROID_NDK` variable is set, the NDK at the
+ specified location will be used.
+
+* Else, if the :variable:`CMAKE_ANDROID_STANDALONE_TOOLCHAIN` variable
+ is set, the Standalone Toolchain at the specified location will be used.
+
+* Else, if the :variable:`CMAKE_SYSROOT` variable is set to a directory
+ of the form ``<ndk>/platforms/android-<api>/arch-<arch>``, the ``<ndk>``
+ part will be used as the value of :variable:`CMAKE_ANDROID_NDK` and the
+ NDK will be used.
+
+* Else, if the :variable:`CMAKE_SYSROOT` variable is set to a directory of the
+ form ``<standalone-toolchain>/sysroot``, the ``<standalone-toolchain>`` part
+ will be used as the value of :variable:`CMAKE_ANDROID_STANDALONE_TOOLCHAIN`
+ and the Standalone Toolchain will be used.
+
+* Else, if a cmake variable ``ANDROID_NDK`` is set it will be used
+ as the value of :variable:`CMAKE_ANDROID_NDK`, and the NDK will be used.
+
+* Else, if a cmake variable ``ANDROID_STANDALONE_TOOLCHAIN`` is set, it will be
+ used as the value of :variable:`CMAKE_ANDROID_STANDALONE_TOOLCHAIN`, and the
+ Standalone Toolchain will be used.
+
+* Else, if an environment variable ``ANDROID_NDK_ROOT`` or
+ ``ANDROID_NDK`` is set, it will be used as the value of
+ :variable:`CMAKE_ANDROID_NDK`, and the NDK will be used.
+
+* Else, if an environment variable ``ANDROID_STANDALONE_TOOLCHAIN`` is
+ set then it will be used as the value of
+ :variable:`CMAKE_ANDROID_STANDALONE_TOOLCHAIN`, and the Standalone
+ Toolchain will be used.
+
+* Else, an error diagnostic will be issued that neither the NDK or
+ Standalone Toolchain can be found.
+
+.. versionadded:: 3.20
+ If an Android NDK is selected, its version number is reported
+ in the :variable:`CMAKE_ANDROID_NDK_VERSION` variable.
+
+.. _`Cross Compiling for Android with the NDK`:
+
+Cross Compiling for Android with the NDK
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A toolchain file may configure :ref:`Makefile Generators`,
+:ref:`Ninja Generators`, or :ref:`Visual Studio Generators` to target
+Android for cross-compiling.
+
+Configure use of an Android NDK with the following variables:
+
+:variable:`CMAKE_SYSTEM_NAME`
+ Set to ``Android``. Must be specified to enable cross compiling
+ for Android.
+
+:variable:`CMAKE_SYSTEM_VERSION`
+ Set to the Android API level. If not specified, the value is
+ determined as follows:
+
+ * If the :variable:`CMAKE_ANDROID_API` variable is set, its value
+ is used as the API level.
+ * If the :variable:`CMAKE_SYSROOT` variable is set, the API level is
+ detected from the NDK directory structure containing the sysroot.
+ * Otherwise, the latest API level available in the NDK is used.
+
+:variable:`CMAKE_ANDROID_ARCH_ABI`
+ Set to the Android ABI (architecture). If not specified, this
+ variable will default to the first supported ABI in the list of
+ ``armeabi``, ``armeabi-v7a`` and ``arm64-v8a``.
+ The :variable:`CMAKE_ANDROID_ARCH` variable will be computed
+ from ``CMAKE_ANDROID_ARCH_ABI`` automatically.
+ Also see the :variable:`CMAKE_ANDROID_ARM_MODE` and
+ :variable:`CMAKE_ANDROID_ARM_NEON` variables.
+
+:variable:`CMAKE_ANDROID_NDK`
+ Set to the absolute path to the Android NDK root directory.
+ If not specified, a default for this variable will be chosen
+ as specified :ref:`above <Cross Compiling for Android>`.
+
+:variable:`CMAKE_ANDROID_NDK_DEPRECATED_HEADERS`
+ Set to a true value to use the deprecated per-api-level headers
+ instead of the unified headers. If not specified, the default will
+ be false unless using a NDK that does not provide unified headers.
+
+:variable:`CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION`
+ On NDK r19 or above, this variable must be unset or set to ``clang``.
+ On NDK r18 or below, set this to the version of the NDK toolchain to
+ be selected as the compiler. If not specified, the default will be
+ the latest available GCC toolchain.
+
+:variable:`CMAKE_ANDROID_STL_TYPE`
+ Set to specify which C++ standard library to use. If not specified,
+ a default will be selected as described in the variable documentation.
+
+The following variables will be computed and provided automatically:
+
+:variable:`CMAKE_<LANG>_ANDROID_TOOLCHAIN_PREFIX`
+ The absolute path prefix to the binutils in the NDK toolchain.
+
+:variable:`CMAKE_<LANG>_ANDROID_TOOLCHAIN_SUFFIX`
+ The host platform suffix of the binutils in the NDK toolchain.
+
+
+For example, a toolchain file might contain:
+
+.. code-block:: cmake
+
+ set(CMAKE_SYSTEM_NAME Android)
+ set(CMAKE_SYSTEM_VERSION 21) # API level
+ set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)
+ set(CMAKE_ANDROID_NDK /path/to/android-ndk)
+ set(CMAKE_ANDROID_STL_TYPE gnustl_static)
+
+Alternatively one may specify the values without a toolchain file:
+
+.. code-block:: console
+
+ $ cmake ../src \
+ -DCMAKE_SYSTEM_NAME=Android \
+ -DCMAKE_SYSTEM_VERSION=21 \
+ -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \
+ -DCMAKE_ANDROID_NDK=/path/to/android-ndk \
+ -DCMAKE_ANDROID_STL_TYPE=gnustl_static
+
+.. _`Cross Compiling for Android with a Standalone Toolchain`:
+
+Cross Compiling for Android with a Standalone Toolchain
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A toolchain file may configure :ref:`Makefile Generators` or the
+:generator:`Ninja` generator to target Android for cross-compiling
+using a standalone toolchain.
+
+Configure use of an Android standalone toolchain with the following variables:
+
+:variable:`CMAKE_SYSTEM_NAME`
+ Set to ``Android``. Must be specified to enable cross compiling
+ for Android.
+
+:variable:`CMAKE_ANDROID_STANDALONE_TOOLCHAIN`
+ Set to the absolute path to the standalone toolchain root directory.
+ A ``${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/sysroot`` directory
+ must exist.
+ If not specified, a default for this variable will be chosen
+ as specified :ref:`above <Cross Compiling for Android>`.
+
+:variable:`CMAKE_ANDROID_ARM_MODE`
+ When the standalone toolchain targets ARM, optionally set this to ``ON``
+ to target 32-bit ARM instead of 16-bit Thumb.
+ See variable documentation for details.
+
+:variable:`CMAKE_ANDROID_ARM_NEON`
+ When the standalone toolchain targets ARM v7, optionally set thisto ``ON``
+ to target ARM NEON devices. See variable documentation for details.
+
+The following variables will be computed and provided automatically:
+
+:variable:`CMAKE_SYSTEM_VERSION`
+ The Android API level detected from the standalone toolchain.
+
+:variable:`CMAKE_ANDROID_ARCH_ABI`
+ The Android ABI detected from the standalone toolchain.
+
+:variable:`CMAKE_<LANG>_ANDROID_TOOLCHAIN_PREFIX`
+ The absolute path prefix to the ``binutils`` in the standalone toolchain.
+
+:variable:`CMAKE_<LANG>_ANDROID_TOOLCHAIN_SUFFIX`
+ The host platform suffix of the ``binutils`` in the standalone toolchain.
+
+For example, a toolchain file might contain:
+
+.. code-block:: cmake
+
+ set(CMAKE_SYSTEM_NAME Android)
+ set(CMAKE_ANDROID_STANDALONE_TOOLCHAIN /path/to/android-toolchain)
+
+Alternatively one may specify the values without a toolchain file:
+
+.. code-block:: console
+
+ $ cmake ../src \
+ -DCMAKE_SYSTEM_NAME=Android \
+ -DCMAKE_ANDROID_STANDALONE_TOOLCHAIN=/path/to/android-toolchain
+
+.. _`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio Edition`:
+
+Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio Edition
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A toolchain file to configure one of the :ref:`Visual Studio Generators`
+to build using NVIDIA Nsight Tegra targeting Android may look like this:
+
+.. code-block:: cmake
+
+ set(CMAKE_SYSTEM_NAME Android)
+
+The :variable:`CMAKE_GENERATOR_TOOLSET` may be set to select
+the Nsight Tegra "Toolchain Version" value.
+
+See also target properties:
+
+* :prop_tgt:`ANDROID_ANT_ADDITIONAL_OPTIONS`
+* :prop_tgt:`ANDROID_API_MIN`
+* :prop_tgt:`ANDROID_API`
+* :prop_tgt:`ANDROID_ARCH`
+* :prop_tgt:`ANDROID_ASSETS_DIRECTORIES`
+* :prop_tgt:`ANDROID_GUI`
+* :prop_tgt:`ANDROID_JAR_DEPENDENCIES`
+* :prop_tgt:`ANDROID_JAR_DIRECTORIES`
+* :prop_tgt:`ANDROID_JAVA_SOURCE_DIR`
+* :prop_tgt:`ANDROID_NATIVE_LIB_DEPENDENCIES`
+* :prop_tgt:`ANDROID_NATIVE_LIB_DIRECTORIES`
+* :prop_tgt:`ANDROID_PROCESS_MAX`
+* :prop_tgt:`ANDROID_PROGUARD_CONFIG_PATH`
+* :prop_tgt:`ANDROID_PROGUARD`
+* :prop_tgt:`ANDROID_SECURE_PROPS_PATH`
+* :prop_tgt:`ANDROID_SKIP_ANT_STEP`
+* :prop_tgt:`ANDROID_STL_TYPE`
+
+.. _`Cross Compiling for iOS, tvOS, or watchOS`:
+
+Cross Compiling for iOS, tvOS, or watchOS
+-----------------------------------------
+
+For cross-compiling to iOS, tvOS, or watchOS, the :generator:`Xcode`
+generator is recommended. The :generator:`Unix Makefiles` or
+:generator:`Ninja` generators can also be used, but they require the
+project to handle more areas like target CPU selection and code signing.
+
+Any of the three systems can be targeted by setting the
+:variable:`CMAKE_SYSTEM_NAME` variable to a value from the table below.
+By default, the latest Device SDK is chosen. As for all Apple platforms,
+a different SDK (e.g. a simulator) can be selected by setting the
+:variable:`CMAKE_OSX_SYSROOT` variable, although this should rarely be
+necessary (see :ref:`Switching Between Device and Simulator` below).
+A list of available SDKs can be obtained by running ``xcodebuild -showsdks``.
+
+======= ================= ==================== ================
+OS CMAKE_SYSTEM_NAME Device SDK (default) Simulator SDK
+======= ================= ==================== ================
+iOS iOS iphoneos iphonesimulator
+tvOS tvOS appletvos appletvsimulator
+watchOS watchOS watchos watchsimulator
+======= ================= ==================== ================
+
+For example, to create a CMake configuration for iOS, the following
+command is sufficient:
+
+.. code-block:: console
+
+ cmake .. -GXcode -DCMAKE_SYSTEM_NAME=iOS
+
+Variable :variable:`CMAKE_OSX_ARCHITECTURES` can be used to set architectures
+for both device and simulator. Variable :variable:`CMAKE_OSX_DEPLOYMENT_TARGET`
+can be used to set an iOS/tvOS/watchOS deployment target.
+
+Next configuration will install fat 5 architectures iOS library
+and add the ``-miphoneos-version-min=9.3``/``-mios-simulator-version-min=9.3``
+flags to the compiler:
+
+.. code-block:: console
+
+ $ cmake -S. -B_builds -GXcode \
+ -DCMAKE_SYSTEM_NAME=iOS \
+ "-DCMAKE_OSX_ARCHITECTURES=armv7;armv7s;arm64;i386;x86_64" \
+ -DCMAKE_OSX_DEPLOYMENT_TARGET=9.3 \
+ -DCMAKE_INSTALL_PREFIX=`pwd`/_install \
+ -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=NO \
+ -DCMAKE_IOS_INSTALL_COMBINED=YES
+
+Example:
+
+.. code-block:: cmake
+
+ # CMakeLists.txt
+ cmake_minimum_required(VERSION 3.14)
+ project(foo)
+ add_library(foo foo.cpp)
+ install(TARGETS foo DESTINATION lib)
+
+Install:
+
+.. code-block:: console
+
+ $ cmake --build _builds --config Release --target install
+
+Check library:
+
+.. code-block:: console
+
+ $ lipo -info _install/lib/libfoo.a
+ Architectures in the fat file: _install/lib/libfoo.a are: i386 armv7 armv7s x86_64 arm64
+
+.. code-block:: console
+
+ $ otool -l _install/lib/libfoo.a | grep -A2 LC_VERSION_MIN_IPHONEOS
+ cmd LC_VERSION_MIN_IPHONEOS
+ cmdsize 16
+ version 9.3
+
+Code Signing
+^^^^^^^^^^^^
+
+Some build artifacts for the embedded Apple platforms require mandatory
+code signing. If the :generator:`Xcode` generator is being used and
+code signing is required or desired, the development team ID can be
+specified via the ``CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM`` CMake variable.
+This team ID will then be included in the generated Xcode project.
+By default, CMake avoids the need for code signing during the internal
+configuration phase (i.e compiler ID and feature detection).
+
+.. _`Switching Between Device and Simulator`:
+
+Switching Between Device and Simulator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When configuring for any of the embedded platforms, one can target either
+real devices or the simulator. Both have their own separate SDK, but CMake
+only supports specifying a single SDK for the configuration phase. This
+means the developer must select one or the other at configuration time.
+When using the :generator:`Xcode` generator, this is less of a limitation
+because Xcode still allows you to build for either a device or a simulator,
+even though configuration was only performed for one of the two. From
+within the Xcode IDE, builds are performed for the selected "destination"
+platform. When building from the command line, the desired sdk can be
+specified directly by passing a ``-sdk`` option to the underlying build
+tool (``xcodebuild``). For example:
+
+.. code-block:: console
+
+ $ cmake --build ... -- -sdk iphonesimulator
+
+Please note that checks made during configuration were performed against
+the configure-time SDK and might not hold true for other SDKs. Commands
+like :command:`find_package`, :command:`find_library`, etc. store and use
+details only for the configured SDK/platform, so they can be problematic
+if wanting to switch between device and simulator builds. You can follow
+the next rules to make device + simulator configuration work:
+
+- Use explicit ``-l`` linker flag,
+ e.g. ``target_link_libraries(foo PUBLIC "-lz")``
+
+- Use explicit ``-framework`` linker flag,
+ e.g. ``target_link_libraries(foo PUBLIC "-framework CoreFoundation")``
+
+- Use :command:`find_package` only for libraries installed with
+ :variable:`CMAKE_IOS_INSTALL_COMBINED` feature
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
new file mode 100644
index 0000000..37ef053
--- /dev/null
+++ b/Help/manual/cmake-variables.7.rst
@@ -0,0 +1,706 @@
+.. cmake-manual-description: CMake Variables Reference
+
+cmake-variables(7)
+******************
+
+.. only:: html
+
+ .. contents::
+
+This page documents variables that are provided by CMake
+or have meaning to CMake when set by project code.
+
+For general information on variables, see the
+:ref:`Variables <CMake Language Variables>`
+section in the cmake-language manual.
+
+.. include:: ID_RESERVE.txt
+
+Variables that Provide Information
+==================================
+
+.. toctree::
+ :maxdepth: 1
+
+ /variable/CMAKE_AR
+ /variable/CMAKE_ARGC
+ /variable/CMAKE_ARGV0
+ /variable/CMAKE_BINARY_DIR
+ /variable/CMAKE_BUILD_TOOL
+ /variable/CMAKE_CACHE_MAJOR_VERSION
+ /variable/CMAKE_CACHE_MINOR_VERSION
+ /variable/CMAKE_CACHE_PATCH_VERSION
+ /variable/CMAKE_CACHEFILE_DIR
+ /variable/CMAKE_CFG_INTDIR
+ /variable/CMAKE_COMMAND
+ /variable/CMAKE_CPACK_COMMAND
+ /variable/CMAKE_CROSSCOMPILING
+ /variable/CMAKE_CROSSCOMPILING_EMULATOR
+ /variable/CMAKE_CTEST_COMMAND
+ /variable/CMAKE_CURRENT_BINARY_DIR
+ /variable/CMAKE_CURRENT_FUNCTION
+ /variable/CMAKE_CURRENT_FUNCTION_LIST_DIR
+ /variable/CMAKE_CURRENT_FUNCTION_LIST_FILE
+ /variable/CMAKE_CURRENT_FUNCTION_LIST_LINE
+ /variable/CMAKE_CURRENT_LIST_DIR
+ /variable/CMAKE_CURRENT_LIST_FILE
+ /variable/CMAKE_CURRENT_LIST_LINE
+ /variable/CMAKE_CURRENT_SOURCE_DIR
+ /variable/CMAKE_DEBUG_TARGET_PROPERTIES
+ /variable/CMAKE_DIRECTORY_LABELS
+ /variable/CMAKE_DL_LIBS
+ /variable/CMAKE_DOTNET_TARGET_FRAMEWORK
+ /variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION
+ /variable/CMAKE_EDIT_COMMAND
+ /variable/CMAKE_EXECUTABLE_SUFFIX
+ /variable/CMAKE_EXTRA_GENERATOR
+ /variable/CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES
+ /variable/CMAKE_FIND_DEBUG_MODE
+ /variable/CMAKE_FIND_PACKAGE_NAME
+ /variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION
+ /variable/CMAKE_FIND_PACKAGE_SORT_ORDER
+ /variable/CMAKE_GENERATOR
+ /variable/CMAKE_GENERATOR_INSTANCE
+ /variable/CMAKE_GENERATOR_PLATFORM
+ /variable/CMAKE_GENERATOR_TOOLSET
+ /variable/CMAKE_IMPORT_LIBRARY_PREFIX
+ /variable/CMAKE_IMPORT_LIBRARY_SUFFIX
+ /variable/CMAKE_JOB_POOL_COMPILE
+ /variable/CMAKE_JOB_POOL_LINK
+ /variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER
+ /variable/CMAKE_JOB_POOLS
+ /variable/CMAKE_LANG_COMPILER_AR
+ /variable/CMAKE_LANG_COMPILER_RANLIB
+ /variable/CMAKE_LANG_LINK_LIBRARY_SUFFIX
+ /variable/CMAKE_LINK_LIBRARY_SUFFIX
+ /variable/CMAKE_LINK_SEARCH_END_STATIC
+ /variable/CMAKE_LINK_SEARCH_START_STATIC
+ /variable/CMAKE_MAJOR_VERSION
+ /variable/CMAKE_MAKE_PROGRAM
+ /variable/CMAKE_MATCH_COUNT
+ /variable/CMAKE_MATCH_n
+ /variable/CMAKE_MINIMUM_REQUIRED_VERSION
+ /variable/CMAKE_MINOR_VERSION
+ /variable/CMAKE_NETRC
+ /variable/CMAKE_NETRC_FILE
+ /variable/CMAKE_PARENT_LIST_FILE
+ /variable/CMAKE_PATCH_VERSION
+ /variable/CMAKE_PROJECT_DESCRIPTION
+ /variable/CMAKE_PROJECT_HOMEPAGE_URL
+ /variable/CMAKE_PROJECT_NAME
+ /variable/CMAKE_PROJECT_VERSION
+ /variable/CMAKE_PROJECT_VERSION_MAJOR
+ /variable/CMAKE_PROJECT_VERSION_MINOR
+ /variable/CMAKE_PROJECT_VERSION_PATCH
+ /variable/CMAKE_PROJECT_VERSION_TWEAK
+ /variable/CMAKE_RANLIB
+ /variable/CMAKE_ROOT
+ /variable/CMAKE_RULE_MESSAGES
+ /variable/CMAKE_SCRIPT_MODE_FILE
+ /variable/CMAKE_SHARED_LIBRARY_PREFIX
+ /variable/CMAKE_SHARED_LIBRARY_SUFFIX
+ /variable/CMAKE_SHARED_MODULE_PREFIX
+ /variable/CMAKE_SHARED_MODULE_SUFFIX
+ /variable/CMAKE_SIZEOF_VOID_P
+ /variable/CMAKE_SKIP_INSTALL_RULES
+ /variable/CMAKE_SKIP_RPATH
+ /variable/CMAKE_SOURCE_DIR
+ /variable/CMAKE_STATIC_LIBRARY_PREFIX
+ /variable/CMAKE_STATIC_LIBRARY_SUFFIX
+ /variable/CMAKE_Swift_MODULE_DIRECTORY
+ /variable/CMAKE_Swift_NUM_THREADS
+ /variable/CMAKE_TOOLCHAIN_FILE
+ /variable/CMAKE_TWEAK_VERSION
+ /variable/CMAKE_VERBOSE_MAKEFILE
+ /variable/CMAKE_VERSION
+ /variable/CMAKE_VS_DEVENV_COMMAND
+ /variable/CMAKE_VS_MSBUILD_COMMAND
+ /variable/CMAKE_VS_NsightTegra_VERSION
+ /variable/CMAKE_VS_PLATFORM_NAME
+ /variable/CMAKE_VS_PLATFORM_NAME_DEFAULT
+ /variable/CMAKE_VS_PLATFORM_TOOLSET
+ /variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA
+ /variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR
+ /variable/CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE
+ /variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION
+ /variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION
+ /variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM
+ /variable/CMAKE_XCODE_BUILD_SYSTEM
+ /variable/CMAKE_XCODE_PLATFORM_TOOLSET
+ /variable/PROJECT-NAME_BINARY_DIR
+ /variable/PROJECT-NAME_DESCRIPTION
+ /variable/PROJECT-NAME_HOMEPAGE_URL
+ /variable/PROJECT-NAME_IS_TOP_LEVEL
+ /variable/PROJECT-NAME_SOURCE_DIR
+ /variable/PROJECT-NAME_VERSION
+ /variable/PROJECT-NAME_VERSION_MAJOR
+ /variable/PROJECT-NAME_VERSION_MINOR
+ /variable/PROJECT-NAME_VERSION_PATCH
+ /variable/PROJECT-NAME_VERSION_TWEAK
+ /variable/PROJECT_BINARY_DIR
+ /variable/PROJECT_DESCRIPTION
+ /variable/PROJECT_HOMEPAGE_URL
+ /variable/PROJECT_IS_TOP_LEVEL
+ /variable/PROJECT_NAME
+ /variable/PROJECT_SOURCE_DIR
+ /variable/PROJECT_VERSION
+ /variable/PROJECT_VERSION_MAJOR
+ /variable/PROJECT_VERSION_MINOR
+ /variable/PROJECT_VERSION_PATCH
+ /variable/PROJECT_VERSION_TWEAK
+
+Variables that Change Behavior
+==============================
+
+.. toctree::
+ :maxdepth: 1
+
+ /variable/BUILD_SHARED_LIBS
+ /variable/CMAKE_ABSOLUTE_DESTINATION_FILES
+ /variable/CMAKE_APPBUNDLE_PATH
+ /variable/CMAKE_AUTOMOC_RELAXED_MODE
+ /variable/CMAKE_BACKWARDS_COMPATIBILITY
+ /variable/CMAKE_BUILD_TYPE
+ /variable/CMAKE_CLANG_VFS_OVERLAY
+ /variable/CMAKE_CODEBLOCKS_COMPILER_ID
+ /variable/CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES
+ /variable/CMAKE_CODELITE_USE_TARGETS
+ /variable/CMAKE_COLOR_MAKEFILE
+ /variable/CMAKE_CONFIGURATION_TYPES
+ /variable/CMAKE_DEPENDS_IN_PROJECT_ONLY
+ /variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName
+ /variable/CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES
+ /variable/CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT
+ /variable/CMAKE_ECLIPSE_MAKE_ARGUMENTS
+ /variable/CMAKE_ECLIPSE_RESOURCE_ENCODING
+ /variable/CMAKE_ECLIPSE_VERSION
+ /variable/CMAKE_ERROR_DEPRECATED
+ /variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
+ /variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO
+ /variable/CMAKE_EXPORT_COMPILE_COMMANDS
+ /variable/CMAKE_EXPORT_PACKAGE_REGISTRY
+ /variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY
+ /variable/CMAKE_FIND_APPBUNDLE
+ /variable/CMAKE_FIND_FRAMEWORK
+ /variable/CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX
+ /variable/CMAKE_FIND_LIBRARY_PREFIXES
+ /variable/CMAKE_FIND_LIBRARY_SUFFIXES
+ /variable/CMAKE_FIND_NO_INSTALL_PREFIX
+ /variable/CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY
+ /variable/CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY
+ /variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG
+ /variable/CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS
+ /variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE
+ /variable/CMAKE_FIND_ROOT_PATH
+ /variable/CMAKE_FIND_ROOT_PATH_MODE_INCLUDE
+ /variable/CMAKE_FIND_ROOT_PATH_MODE_LIBRARY
+ /variable/CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
+ /variable/CMAKE_FIND_ROOT_PATH_MODE_PROGRAM
+ /variable/CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH
+ /variable/CMAKE_FIND_USE_CMAKE_PATH
+ /variable/CMAKE_FIND_USE_CMAKE_SYSTEM_PATH
+ /variable/CMAKE_FIND_USE_PACKAGE_REGISTRY
+ /variable/CMAKE_FIND_USE_PACKAGE_ROOT_PATH
+ /variable/CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH
+ /variable/CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY
+ /variable/CMAKE_FRAMEWORK_PATH
+ /variable/CMAKE_IGNORE_PATH
+ /variable/CMAKE_INCLUDE_DIRECTORIES_BEFORE
+ /variable/CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE
+ /variable/CMAKE_INCLUDE_PATH
+ /variable/CMAKE_INSTALL_DEFAULT_COMPONENT_NAME
+ /variable/CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
+ /variable/CMAKE_INSTALL_MESSAGE
+ /variable/CMAKE_INSTALL_PREFIX
+ /variable/CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
+ /variable/CMAKE_LIBRARY_PATH
+ /variable/CMAKE_LINK_DIRECTORIES_BEFORE
+ /variable/CMAKE_MFC_FLAG
+ /variable/CMAKE_MAXIMUM_RECURSION_DEPTH
+ /variable/CMAKE_MESSAGE_CONTEXT
+ /variable/CMAKE_MESSAGE_CONTEXT_SHOW
+ /variable/CMAKE_MESSAGE_INDENT
+ /variable/CMAKE_MESSAGE_LOG_LEVEL
+ /variable/CMAKE_MODULE_PATH
+ /variable/CMAKE_POLICY_DEFAULT_CMPNNNN
+ /variable/CMAKE_POLICY_WARNING_CMPNNNN
+ /variable/CMAKE_PREFIX_PATH
+ /variable/CMAKE_PROGRAM_PATH
+ /variable/CMAKE_PROJECT_INCLUDE
+ /variable/CMAKE_PROJECT_INCLUDE_BEFORE
+ /variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE
+ /variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE
+ /variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY
+ /variable/CMAKE_STAGING_PREFIX
+ /variable/CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS
+ /variable/CMAKE_SUBLIME_TEXT_2_EXCLUDE_BUILD_TREE
+ /variable/CMAKE_SUPPRESS_REGENERATION
+ /variable/CMAKE_SYSROOT
+ /variable/CMAKE_SYSROOT_COMPILE
+ /variable/CMAKE_SYSROOT_LINK
+ /variable/CMAKE_SYSTEM_APPBUNDLE_PATH
+ /variable/CMAKE_SYSTEM_FRAMEWORK_PATH
+ /variable/CMAKE_SYSTEM_IGNORE_PATH
+ /variable/CMAKE_SYSTEM_INCLUDE_PATH
+ /variable/CMAKE_SYSTEM_LIBRARY_PATH
+ /variable/CMAKE_SYSTEM_PREFIX_PATH
+ /variable/CMAKE_SYSTEM_PROGRAM_PATH
+ /variable/CMAKE_USER_MAKE_RULES_OVERRIDE
+ /variable/CMAKE_WARN_DEPRECATED
+ /variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION
+ /variable/CMAKE_XCODE_GENERATE_SCHEME
+ /variable/CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY
+ /variable/CMAKE_XCODE_LINK_BUILD_PHASE_MODE
+ /variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER
+ /variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN
+ /variable/CMAKE_XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING
+ /variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
+ /variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
+ /variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
+ /variable/CMAKE_XCODE_SCHEME_ENVIRONMENT
+ /variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC
+ /variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP
+ /variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES
+ /variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE
+ /variable/CMAKE_XCODE_SCHEME_MALLOC_STACK
+ /variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER
+ /variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP
+ /variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER
+ /variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP
+ /variable/CMAKE_XCODE_SCHEME_WORKING_DIRECTORY
+ /variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS
+ /variable/PackageName_ROOT
+
+Variables that Describe the System
+==================================
+
+.. toctree::
+ :maxdepth: 1
+
+ /variable/ANDROID
+ /variable/APPLE
+ /variable/BORLAND
+ /variable/CMAKE_ANDROID_NDK_VERSION
+ /variable/CMAKE_CL_64
+ /variable/CMAKE_COMPILER_2005
+ /variable/CMAKE_HOST_APPLE
+ /variable/CMAKE_HOST_SOLARIS
+ /variable/CMAKE_HOST_SYSTEM
+ /variable/CMAKE_HOST_SYSTEM_NAME
+ /variable/CMAKE_HOST_SYSTEM_PROCESSOR
+ /variable/CMAKE_HOST_SYSTEM_VERSION
+ /variable/CMAKE_HOST_UNIX
+ /variable/CMAKE_HOST_WIN32
+ /variable/CMAKE_LIBRARY_ARCHITECTURE
+ /variable/CMAKE_LIBRARY_ARCHITECTURE_REGEX
+ /variable/CMAKE_OBJECT_PATH_MAX
+ /variable/CMAKE_SYSTEM
+ /variable/CMAKE_SYSTEM_NAME
+ /variable/CMAKE_SYSTEM_PROCESSOR
+ /variable/CMAKE_SYSTEM_VERSION
+ /variable/CYGWIN
+ /variable/GHS-MULTI
+ /variable/IOS
+ /variable/MINGW
+ /variable/MSVC
+ /variable/MSVC10
+ /variable/MSVC11
+ /variable/MSVC12
+ /variable/MSVC14
+ /variable/MSVC60
+ /variable/MSVC70
+ /variable/MSVC71
+ /variable/MSVC80
+ /variable/MSVC90
+ /variable/MSVC_IDE
+ /variable/MSVC_TOOLSET_VERSION
+ /variable/MSVC_VERSION
+ /variable/MSYS
+ /variable/UNIX
+ /variable/WIN32
+ /variable/WINCE
+ /variable/WINDOWS_PHONE
+ /variable/WINDOWS_STORE
+ /variable/XCODE
+ /variable/XCODE_VERSION
+
+Variables that Control the Build
+================================
+
+.. toctree::
+ :maxdepth: 1
+
+ /variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS
+ /variable/CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS
+ /variable/CMAKE_ANDROID_API
+ /variable/CMAKE_ANDROID_API_MIN
+ /variable/CMAKE_ANDROID_ARCH
+ /variable/CMAKE_ANDROID_ARCH_ABI
+ /variable/CMAKE_ANDROID_ARM_MODE
+ /variable/CMAKE_ANDROID_ARM_NEON
+ /variable/CMAKE_ANDROID_ASSETS_DIRECTORIES
+ /variable/CMAKE_ANDROID_EXCEPTIONS
+ /variable/CMAKE_ANDROID_GUI
+ /variable/CMAKE_ANDROID_JAR_DEPENDENCIES
+ /variable/CMAKE_ANDROID_JAR_DIRECTORIES
+ /variable/CMAKE_ANDROID_JAVA_SOURCE_DIR
+ /variable/CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES
+ /variable/CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES
+ /variable/CMAKE_ANDROID_NDK
+ /variable/CMAKE_ANDROID_NDK_DEPRECATED_HEADERS
+ /variable/CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG
+ /variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION
+ /variable/CMAKE_ANDROID_PROCESS_MAX
+ /variable/CMAKE_ANDROID_PROGUARD
+ /variable/CMAKE_ANDROID_PROGUARD_CONFIG_PATH
+ /variable/CMAKE_ANDROID_RTTI
+ /variable/CMAKE_ANDROID_SECURE_PROPS_PATH
+ /variable/CMAKE_ANDROID_SKIP_ANT_STEP
+ /variable/CMAKE_ANDROID_STANDALONE_TOOLCHAIN
+ /variable/CMAKE_ANDROID_STL_TYPE
+ /variable/CMAKE_APPLE_SILICON_PROCESSOR
+ /variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY
+ /variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY_CONFIG
+ /variable/CMAKE_AUTOGEN_ORIGIN_DEPENDS
+ /variable/CMAKE_AUTOGEN_PARALLEL
+ /variable/CMAKE_AUTOGEN_VERBOSE
+ /variable/CMAKE_AUTOMOC
+ /variable/CMAKE_AUTOMOC_COMPILER_PREDEFINES
+ /variable/CMAKE_AUTOMOC_DEPEND_FILTERS
+ /variable/CMAKE_AUTOMOC_MACRO_NAMES
+ /variable/CMAKE_AUTOMOC_MOC_OPTIONS
+ /variable/CMAKE_AUTOMOC_PATH_PREFIX
+ /variable/CMAKE_AUTORCC
+ /variable/CMAKE_AUTORCC_OPTIONS
+ /variable/CMAKE_AUTOUIC
+ /variable/CMAKE_AUTOUIC_OPTIONS
+ /variable/CMAKE_AUTOUIC_SEARCH_PATHS
+ /variable/CMAKE_BUILD_RPATH
+ /variable/CMAKE_BUILD_RPATH_USE_ORIGIN
+ /variable/CMAKE_BUILD_WITH_INSTALL_NAME_DIR
+ /variable/CMAKE_BUILD_WITH_INSTALL_RPATH
+ /variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY
+ /variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG
+ /variable/CMAKE_CONFIG_POSTFIX
+ /variable/CMAKE_CROSS_CONFIGS
+ /variable/CMAKE_CTEST_ARGUMENTS
+ /variable/CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS
+ /variable/CMAKE_CUDA_RUNTIME_LIBRARY
+ /variable/CMAKE_CUDA_SEPARABLE_COMPILATION
+ /variable/CMAKE_DEBUG_POSTFIX
+ /variable/CMAKE_DEFAULT_BUILD_TYPE
+ /variable/CMAKE_DEFAULT_CONFIGS
+ /variable/CMAKE_DISABLE_PRECOMPILE_HEADERS
+ /variable/CMAKE_DEPENDS_USE_COMPILER
+ /variable/CMAKE_ENABLE_EXPORTS
+ /variable/CMAKE_EXE_LINKER_FLAGS
+ /variable/CMAKE_EXE_LINKER_FLAGS_CONFIG
+ /variable/CMAKE_EXE_LINKER_FLAGS_CONFIG_INIT
+ /variable/CMAKE_EXE_LINKER_FLAGS_INIT
+ /variable/CMAKE_FOLDER
+ /variable/CMAKE_FRAMEWORK
+ /variable/CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG
+ /variable/CMAKE_Fortran_FORMAT
+ /variable/CMAKE_Fortran_MODULE_DIRECTORY
+ /variable/CMAKE_Fortran_PREPROCESS
+ /variable/CMAKE_GHS_NO_SOURCE_GROUP_FILE
+ /variable/CMAKE_GLOBAL_AUTOGEN_TARGET
+ /variable/CMAKE_GLOBAL_AUTOGEN_TARGET_NAME
+ /variable/CMAKE_GLOBAL_AUTORCC_TARGET
+ /variable/CMAKE_GLOBAL_AUTORCC_TARGET_NAME
+ /variable/CMAKE_GNUtoMS
+ /variable/CMAKE_INCLUDE_CURRENT_DIR
+ /variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE
+ /variable/CMAKE_INSTALL_NAME_DIR
+ /variable/CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH
+ /variable/CMAKE_INSTALL_RPATH
+ /variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH
+ /variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION
+ /variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION_CONFIG
+ /variable/CMAKE_IOS_INSTALL_COMBINED
+ /variable/CMAKE_LANG_CLANG_TIDY
+ /variable/CMAKE_LANG_COMPILER_LAUNCHER
+ /variable/CMAKE_LANG_CPPCHECK
+ /variable/CMAKE_LANG_CPPLINT
+ /variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE
+ /variable/CMAKE_LANG_LINK_LIBRARY_FILE_FLAG
+ /variable/CMAKE_LANG_LINK_LIBRARY_FLAG
+ /variable/CMAKE_LANG_VISIBILITY_PRESET
+ /variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY
+ /variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY_CONFIG
+ /variable/CMAKE_LIBRARY_PATH_FLAG
+ /variable/CMAKE_LINK_DEF_FILE_FLAG
+ /variable/CMAKE_LINK_DEPENDS_NO_SHARED
+ /variable/CMAKE_LINK_INTERFACE_LIBRARIES
+ /variable/CMAKE_LINK_LIBRARY_FILE_FLAG
+ /variable/CMAKE_LINK_LIBRARY_FLAG
+ /variable/CMAKE_LINK_WHAT_YOU_USE
+ /variable/CMAKE_MACOSX_BUNDLE
+ /variable/CMAKE_MACOSX_RPATH
+ /variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG
+ /variable/CMAKE_MODULE_LINKER_FLAGS
+ /variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG
+ /variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG_INIT
+ /variable/CMAKE_MODULE_LINKER_FLAGS_INIT
+ /variable/CMAKE_MSVCIDE_RUN_PATH
+ /variable/CMAKE_MSVC_RUNTIME_LIBRARY
+ /variable/CMAKE_NINJA_OUTPUT_PATH_PREFIX
+ /variable/CMAKE_NO_BUILTIN_CHRPATH
+ /variable/CMAKE_NO_SYSTEM_FROM_IMPORTED
+ /variable/CMAKE_OPTIMIZE_DEPENDENCIES
+ /variable/CMAKE_OSX_ARCHITECTURES
+ /variable/CMAKE_OSX_DEPLOYMENT_TARGET
+ /variable/CMAKE_OSX_SYSROOT
+ /variable/CMAKE_PCH_WARN_INVALID
+ /variable/CMAKE_PCH_INSTANTIATE_TEMPLATES
+ /variable/CMAKE_PDB_OUTPUT_DIRECTORY
+ /variable/CMAKE_PDB_OUTPUT_DIRECTORY_CONFIG
+ /variable/CMAKE_POSITION_INDEPENDENT_CODE
+ /variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY
+ /variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY_CONFIG
+ /variable/CMAKE_SHARED_LINKER_FLAGS
+ /variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG
+ /variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG_INIT
+ /variable/CMAKE_SHARED_LINKER_FLAGS_INIT
+ /variable/CMAKE_SKIP_BUILD_RPATH
+ /variable/CMAKE_SKIP_INSTALL_RPATH
+ /variable/CMAKE_STATIC_LINKER_FLAGS
+ /variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG
+ /variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG_INIT
+ /variable/CMAKE_STATIC_LINKER_FLAGS_INIT
+ /variable/CMAKE_TRY_COMPILE_CONFIGURATION
+ /variable/CMAKE_TRY_COMPILE_PLATFORM_VARIABLES
+ /variable/CMAKE_TRY_COMPILE_TARGET_TYPE
+ /variable/CMAKE_UNITY_BUILD
+ /variable/CMAKE_UNITY_BUILD_BATCH_SIZE
+ /variable/CMAKE_UNITY_BUILD_UNIQUE_ID
+ /variable/CMAKE_USE_RELATIVE_PATHS
+ /variable/CMAKE_VISIBILITY_INLINES_HIDDEN
+ /variable/CMAKE_VS_GLOBALS
+ /variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD
+ /variable/CMAKE_VS_INCLUDE_PACKAGE_TO_DEFAULT_BUILD
+ /variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING
+ /variable/CMAKE_VS_SDK_EXCLUDE_DIRECTORIES
+ /variable/CMAKE_VS_SDK_EXECUTABLE_DIRECTORIES
+ /variable/CMAKE_VS_SDK_INCLUDE_DIRECTORIES
+ /variable/CMAKE_VS_SDK_LIBRARY_DIRECTORIES
+ /variable/CMAKE_VS_SDK_LIBRARY_WINRT_DIRECTORIES
+ /variable/CMAKE_VS_SDK_REFERENCE_DIRECTORIES
+ /variable/CMAKE_VS_SDK_SOURCE_DIRECTORIES
+ /variable/CMAKE_VS_WINRT_BY_DEFAULT
+ /variable/CMAKE_WIN32_EXECUTABLE
+ /variable/CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
+ /variable/CMAKE_XCODE_ATTRIBUTE_an-attribute
+ /variable/EXECUTABLE_OUTPUT_PATH
+ /variable/LIBRARY_OUTPUT_PATH
+
+Variables for Languages
+=======================
+
+.. toctree::
+ :maxdepth: 1
+
+ /variable/CMAKE_COMPILER_IS_GNUCC
+ /variable/CMAKE_COMPILER_IS_GNUCXX
+ /variable/CMAKE_COMPILER_IS_GNUG77
+ /variable/CMAKE_CUDA_ARCHITECTURES
+ /variable/CMAKE_CUDA_COMPILE_FEATURES
+ /variable/CMAKE_CUDA_EXTENSIONS
+ /variable/CMAKE_CUDA_HOST_COMPILER
+ /variable/CMAKE_CUDA_STANDARD
+ /variable/CMAKE_CUDA_STANDARD_REQUIRED
+ /variable/CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES
+ /variable/CMAKE_CXX_COMPILE_FEATURES
+ /variable/CMAKE_CXX_EXTENSIONS
+ /variable/CMAKE_CXX_STANDARD
+ /variable/CMAKE_CXX_STANDARD_REQUIRED
+ /variable/CMAKE_C_COMPILE_FEATURES
+ /variable/CMAKE_C_EXTENSIONS
+ /variable/CMAKE_C_STANDARD
+ /variable/CMAKE_C_STANDARD_REQUIRED
+ /variable/CMAKE_Fortran_MODDIR_DEFAULT
+ /variable/CMAKE_Fortran_MODDIR_FLAG
+ /variable/CMAKE_Fortran_MODOUT_FLAG
+ /variable/CMAKE_ISPC_HEADER_DIRECTORY
+ /variable/CMAKE_ISPC_HEADER_SUFFIX
+ /variable/CMAKE_ISPC_INSTRUCTION_SETS
+ /variable/CMAKE_LANG_ANDROID_TOOLCHAIN_MACHINE
+ /variable/CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX
+ /variable/CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX
+ /variable/CMAKE_LANG_ARCHIVE_APPEND
+ /variable/CMAKE_LANG_ARCHIVE_CREATE
+ /variable/CMAKE_LANG_ARCHIVE_FINISH
+ /variable/CMAKE_LANG_BYTE_ORDER
+ /variable/CMAKE_LANG_COMPILER
+ /variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN
+ /variable/CMAKE_LANG_COMPILER_ID
+ /variable/CMAKE_LANG_COMPILER_LOADED
+ /variable/CMAKE_LANG_COMPILER_PREDEFINES_COMMAND
+ /variable/CMAKE_LANG_COMPILER_TARGET
+ /variable/CMAKE_LANG_COMPILER_VERSION
+ /variable/CMAKE_LANG_COMPILE_OBJECT
+ /variable/CMAKE_LANG_CREATE_SHARED_LIBRARY
+ /variable/CMAKE_LANG_CREATE_SHARED_MODULE
+ /variable/CMAKE_LANG_CREATE_STATIC_LIBRARY
+ /variable/CMAKE_LANG_FLAGS
+ /variable/CMAKE_LANG_FLAGS_CONFIG
+ /variable/CMAKE_LANG_FLAGS_CONFIG_INIT
+ /variable/CMAKE_LANG_FLAGS_DEBUG
+ /variable/CMAKE_LANG_FLAGS_DEBUG_INIT
+ /variable/CMAKE_LANG_FLAGS_INIT
+ /variable/CMAKE_LANG_FLAGS_MINSIZEREL
+ /variable/CMAKE_LANG_FLAGS_MINSIZEREL_INIT
+ /variable/CMAKE_LANG_FLAGS_RELEASE
+ /variable/CMAKE_LANG_FLAGS_RELEASE_INIT
+ /variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO
+ /variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO_INIT
+ /variable/CMAKE_LANG_IGNORE_EXTENSIONS
+ /variable/CMAKE_LANG_IMPLICIT_INCLUDE_DIRECTORIES
+ /variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES
+ /variable/CMAKE_LANG_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ /variable/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES
+ /variable/CMAKE_LANG_LIBRARY_ARCHITECTURE
+ /variable/CMAKE_LANG_LINK_EXECUTABLE
+ /variable/CMAKE_LANG_LINKER_PREFERENCE
+ /variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES
+ /variable/CMAKE_LANG_LINKER_WRAPPER_FLAG
+ /variable/CMAKE_LANG_LINKER_WRAPPER_FLAG_SEP
+ /variable/CMAKE_LANG_OUTPUT_EXTENSION
+ /variable/CMAKE_LANG_SIMULATE_ID
+ /variable/CMAKE_LANG_SIMULATE_VERSION
+ /variable/CMAKE_LANG_SIZEOF_DATA_PTR
+ /variable/CMAKE_LANG_SOURCE_FILE_EXTENSIONS
+ /variable/CMAKE_LANG_STANDARD_INCLUDE_DIRECTORIES
+ /variable/CMAKE_LANG_STANDARD_LIBRARIES
+ /variable/CMAKE_OBJC_EXTENSIONS
+ /variable/CMAKE_OBJC_STANDARD
+ /variable/CMAKE_OBJC_STANDARD_REQUIRED
+ /variable/CMAKE_OBJCXX_EXTENSIONS
+ /variable/CMAKE_OBJCXX_STANDARD
+ /variable/CMAKE_OBJCXX_STANDARD_REQUIRED
+ /variable/CMAKE_Swift_LANGUAGE_VERSION
+ /variable/CMAKE_USER_MAKE_RULES_OVERRIDE_LANG
+
+Variables for CTest
+===================
+
+.. toctree::
+ :maxdepth: 1
+
+ /variable/CTEST_BINARY_DIRECTORY
+ /variable/CTEST_BUILD_COMMAND
+ /variable/CTEST_BUILD_NAME
+ /variable/CTEST_BZR_COMMAND
+ /variable/CTEST_BZR_UPDATE_OPTIONS
+ /variable/CTEST_CHANGE_ID
+ /variable/CTEST_CHECKOUT_COMMAND
+ /variable/CTEST_CONFIGURATION_TYPE
+ /variable/CTEST_CONFIGURE_COMMAND
+ /variable/CTEST_COVERAGE_COMMAND
+ /variable/CTEST_COVERAGE_EXTRA_FLAGS
+ /variable/CTEST_CURL_OPTIONS
+ /variable/CTEST_CUSTOM_COVERAGE_EXCLUDE
+ /variable/CTEST_CUSTOM_ERROR_EXCEPTION
+ /variable/CTEST_CUSTOM_ERROR_MATCH
+ /variable/CTEST_CUSTOM_ERROR_POST_CONTEXT
+ /variable/CTEST_CUSTOM_ERROR_PRE_CONTEXT
+ /variable/CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE
+ /variable/CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS
+ /variable/CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS
+ /variable/CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE
+ /variable/CTEST_CUSTOM_MEMCHECK_IGNORE
+ /variable/CTEST_CUSTOM_POST_MEMCHECK
+ /variable/CTEST_CUSTOM_POST_TEST
+ /variable/CTEST_CUSTOM_PRE_MEMCHECK
+ /variable/CTEST_CUSTOM_PRE_TEST
+ /variable/CTEST_CUSTOM_TESTS_IGNORE
+ /variable/CTEST_CUSTOM_WARNING_EXCEPTION
+ /variable/CTEST_CUSTOM_WARNING_MATCH
+ /variable/CTEST_CVS_CHECKOUT
+ /variable/CTEST_CVS_COMMAND
+ /variable/CTEST_CVS_UPDATE_OPTIONS
+ /variable/CTEST_DROP_LOCATION
+ /variable/CTEST_DROP_METHOD
+ /variable/CTEST_DROP_SITE
+ /variable/CTEST_DROP_SITE_CDASH
+ /variable/CTEST_DROP_SITE_PASSWORD
+ /variable/CTEST_DROP_SITE_USER
+ /variable/CTEST_EXTRA_COVERAGE_GLOB
+ /variable/CTEST_GIT_COMMAND
+ /variable/CTEST_GIT_INIT_SUBMODULES
+ /variable/CTEST_GIT_UPDATE_CUSTOM
+ /variable/CTEST_GIT_UPDATE_OPTIONS
+ /variable/CTEST_HG_COMMAND
+ /variable/CTEST_HG_UPDATE_OPTIONS
+ /variable/CTEST_LABELS_FOR_SUBPROJECTS
+ /variable/CTEST_MEMORYCHECK_COMMAND
+ /variable/CTEST_MEMORYCHECK_COMMAND_OPTIONS
+ /variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS
+ /variable/CTEST_MEMORYCHECK_SUPPRESSIONS_FILE
+ /variable/CTEST_MEMORYCHECK_TYPE
+ /variable/CTEST_NIGHTLY_START_TIME
+ /variable/CTEST_P4_CLIENT
+ /variable/CTEST_P4_COMMAND
+ /variable/CTEST_P4_OPTIONS
+ /variable/CTEST_P4_UPDATE_OPTIONS
+ /variable/CTEST_RESOURCE_SPEC_FILE
+ /variable/CTEST_RUN_CURRENT_SCRIPT
+ /variable/CTEST_SCP_COMMAND
+ /variable/CTEST_SITE
+ /variable/CTEST_SUBMIT_URL
+ /variable/CTEST_SOURCE_DIRECTORY
+ /variable/CTEST_SVN_COMMAND
+ /variable/CTEST_SVN_OPTIONS
+ /variable/CTEST_SVN_UPDATE_OPTIONS
+ /variable/CTEST_TEST_LOAD
+ /variable/CTEST_TEST_TIMEOUT
+ /variable/CTEST_TRIGGER_SITE
+ /variable/CTEST_UPDATE_COMMAND
+ /variable/CTEST_UPDATE_OPTIONS
+ /variable/CTEST_UPDATE_VERSION_ONLY
+ /variable/CTEST_UPDATE_VERSION_OVERRIDE
+ /variable/CTEST_USE_LAUNCHERS
+
+Variables for CPack
+===================
+
+.. toctree::
+ :maxdepth: 1
+
+ /variable/CPACK_ABSOLUTE_DESTINATION_FILES
+ /variable/CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY
+ /variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
+ /variable/CPACK_INCLUDE_TOPLEVEL_DIRECTORY
+ /variable/CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
+ /variable/CPACK_PACKAGING_INSTALL_PREFIX
+ /variable/CPACK_SET_DESTDIR
+ /variable/CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION
+
+Variable Expansion Operators
+============================
+
+.. toctree::
+ :maxdepth: 1
+
+ /variable/CACHE
+ /variable/ENV
+
+Internal Variables
+==================
+
+CMake has many internal variables. Most of them are undocumented.
+Some of them, however, were at some point described as normal
+variables, and therefore may be encountered in legacy code. They
+are subject to change, and not recommended for use in project code.
+
+.. toctree::
+ :maxdepth: 1
+
+ /variable/CMAKE_HOME_DIRECTORY
+ /variable/CMAKE_INTERNAL_PLATFORM_ABI
+ /variable/CMAKE_LANG_COMPILER_ABI
+ /variable/CMAKE_LANG_COMPILER_ARCHITECTURE_ID
+ /variable/CMAKE_LANG_COMPILER_VERSION_INTERNAL
+ /variable/CMAKE_LANG_PLATFORM_ID
+ /variable/CMAKE_NOT_USING_CONFIG_FLAGS
+ /variable/CMAKE_VS_INTEL_Fortran_PROJECT_VERSION
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
new file mode 100644
index 0000000..157ea5f
--- /dev/null
+++ b/Help/manual/cmake.1.rst
@@ -0,0 +1,857 @@
+.. cmake-manual-description: CMake Command-Line Reference
+
+cmake(1)
+********
+
+Synopsis
+========
+
+.. parsed-literal::
+
+ `Generate a Project Buildsystem`_
+ cmake [<options>] <path-to-source>
+ cmake [<options>] <path-to-existing-build>
+ cmake [<options>] -S <path-to-source> -B <path-to-build>
+
+ `Build a Project`_
+ cmake --build <dir> [<options>] [-- <build-tool-options>]
+
+ `Install a Project`_
+ cmake --install <dir> [<options>]
+
+ `Open a Project`_
+ cmake --open <dir>
+
+ `Run a Script`_
+ cmake [{-D <var>=<value>}...] -P <cmake-script-file>
+
+ `Run a Command-Line Tool`_
+ cmake -E <command> [<options>]
+
+ `Run the Find-Package Tool`_
+ cmake --find-package [<options>]
+
+ `View Help`_
+ cmake --help[-<topic>]
+
+Description
+===========
+
+The **cmake** executable is the command-line interface of the cross-platform
+buildsystem generator CMake. The above `Synopsis`_ lists various actions
+the tool can perform as described in sections below.
+
+To build a software project with CMake, `Generate a Project Buildsystem`_.
+Optionally use **cmake** to `Build a Project`_, `Install a Project`_ or just
+run the corresponding build tool (e.g. ``make``) directly. **cmake** can also
+be used to `View Help`_.
+
+The other actions are meant for use by software developers writing
+scripts in the :manual:`CMake language <cmake-language(7)>` to support
+their builds.
+
+For graphical user interfaces that may be used in place of **cmake**,
+see :manual:`ccmake <ccmake(1)>` and :manual:`cmake-gui <cmake-gui(1)>`.
+For command-line interfaces to the CMake testing and packaging facilities,
+see :manual:`ctest <ctest(1)>` and :manual:`cpack <cpack(1)>`.
+
+For more information on CMake at large, `see also`_ the links at the end
+of this manual.
+
+
+Introduction to CMake Buildsystems
+==================================
+
+A *buildsystem* describes how to build a project's executables and libraries
+from its source code using a *build tool* to automate the process. For
+example, a buildsystem may be a ``Makefile`` for use with a command-line
+``make`` tool or a project file for an Integrated Development Environment
+(IDE). In order to avoid maintaining multiple such buildsystems, a project
+may specify its buildsystem abstractly using files written in the
+:manual:`CMake language <cmake-language(7)>`. From these files CMake
+generates a preferred buildsystem locally for each user through a backend
+called a *generator*.
+
+To generate a buildsystem with CMake, the following must be selected:
+
+Source Tree
+ The top-level directory containing source files provided by the project.
+ The project specifies its buildsystem using files as described in the
+ :manual:`cmake-language(7)` manual, starting with a top-level file named
+ ``CMakeLists.txt``. These files specify build targets and their
+ dependencies as described in the :manual:`cmake-buildsystem(7)` manual.
+
+Build Tree
+ The top-level directory in which buildsystem files and build output
+ artifacts (e.g. executables and libraries) are to be stored.
+ CMake will write a ``CMakeCache.txt`` file to identify the directory
+ as a build tree and store persistent information such as buildsystem
+ configuration options.
+
+ To maintain a pristine source tree, perform an *out-of-source* build
+ by using a separate dedicated build tree. An *in-source* build in
+ which the build tree is placed in the same directory as the source
+ tree is also supported, but discouraged.
+
+Generator
+ This chooses the kind of buildsystem to generate. See the
+ :manual:`cmake-generators(7)` manual for documentation of all generators.
+ Run ``cmake --help`` to see a list of generators available locally.
+ Optionally use the ``-G`` option below to specify a generator, or simply
+ accept the default CMake chooses for the current platform.
+
+ When using one of the :ref:`Command-Line Build Tool Generators`
+ CMake expects that the environment needed by the compiler toolchain
+ is already configured in the shell. When using one of the
+ :ref:`IDE Build Tool Generators`, no particular environment is needed.
+
+
+Generate a Project Buildsystem
+==============================
+
+Run CMake with one of the following command signatures to specify the
+source and build trees and generate a buildsystem:
+
+``cmake [<options>] <path-to-source>``
+ Uses the current working directory as the build tree, and
+ ``<path-to-source>`` as the source tree. The specified path may
+ be absolute or relative to the current working directory.
+ The source tree must contain a ``CMakeLists.txt`` file and must
+ *not* contain a ``CMakeCache.txt`` file because the latter
+ identifies an existing build tree. For example:
+
+ .. code-block:: console
+
+ $ mkdir build ; cd build
+ $ cmake ../src
+
+``cmake [<options>] <path-to-existing-build>``
+ Uses ``<path-to-existing-build>`` as the build tree, and loads the
+ path to the source tree from its ``CMakeCache.txt`` file, which must
+ have already been generated by a previous run of CMake. The specified
+ path may be absolute or relative to the current working directory.
+ For example:
+
+ .. code-block:: console
+
+ $ cd build
+ $ cmake .
+
+``cmake [<options>] -S <path-to-source> -B <path-to-build>``
+ Uses ``<path-to-build>`` as the build tree and ``<path-to-source>``
+ as the source tree. The specified paths may be absolute or relative
+ to the current working directory. The source tree must contain a
+ ``CMakeLists.txt`` file. The build tree will be created automatically
+ if it does not already exist. For example:
+
+ .. code-block:: console
+
+ $ cmake -S src -B build
+
+In all cases the ``<options>`` may be zero or more of the `Options`_ below.
+
+After generating a buildsystem one may use the corresponding native
+build tool to build the project. For example, after using the
+:generator:`Unix Makefiles` generator one may run ``make`` directly:
+
+ .. code-block:: console
+
+ $ make
+ $ make install
+
+Alternatively, one may use **cmake** to `Build a Project`_ by
+automatically choosing and invoking the appropriate native build tool.
+
+.. _`CMake Options`:
+
+Options
+-------
+
+.. include:: OPTIONS_BUILD.txt
+
+``-L[A][H]``
+ List non-advanced cached variables.
+
+ List ``CACHE`` variables will run CMake and list all the variables from
+ the CMake ``CACHE`` that are not marked as ``INTERNAL`` or :prop_cache:`ADVANCED`.
+ This will effectively display current CMake settings, which can then be
+ changed with ``-D`` option. Changing some of the variables may result
+ in more variables being created. If ``A`` is specified, then it will
+ display also advanced variables. If ``H`` is specified, it will also
+ display help for each variable.
+
+``-N``
+ View mode only.
+
+ Only load the cache. Do not actually run configure and generate
+ steps.
+
+``--graphviz=[file]``
+ Generate graphviz of dependencies, see :module:`CMakeGraphVizOptions` for more.
+
+ Generate a graphviz input file that will contain all the library and
+ executable dependencies in the project. See the documentation for
+ :module:`CMakeGraphVizOptions` for more details.
+
+``--system-information [file]``
+ Dump information about this system.
+
+ Dump a wide range of information about the current system. If run
+ from the top of a binary tree for a CMake project it will dump
+ additional information such as the cache, log files etc.
+
+``--log-level=<ERROR|WARNING|NOTICE|STATUS|VERBOSE|DEBUG|TRACE>``
+ Set the log level.
+
+ The :command:`message` command will only output messages of the specified
+ log level or higher. The default log level is ``STATUS``.
+
+ To make a log level persist between CMake runs, set
+ :variable:`CMAKE_MESSAGE_LOG_LEVEL` as a cache variable instead.
+ If both the command line option and the variable are given, the command line
+ option takes precedence.
+
+ For backward compatibility reasons, ``--loglevel`` is also accepted as a
+ synonym for this option.
+
+``--log-context``
+ Enable the :command:`message` command outputting context attached to each
+ message.
+
+ This option turns on showing context for the current CMake run only.
+ To make showing the context persistent for all subsequent CMake runs, set
+ :variable:`CMAKE_MESSAGE_CONTEXT_SHOW` as a cache variable instead.
+ When this command line option is given, :variable:`CMAKE_MESSAGE_CONTEXT_SHOW`
+ is ignored.
+
+``--debug-trycompile``
+ Do not delete the :command:`try_compile` build tree.
+ Only useful on one :command:`try_compile` at a time.
+
+ Do not delete the files and directories created for :command:`try_compile`
+ calls. This is useful in debugging failed try_compiles. It may
+ however change the results of the try-compiles as old junk from a
+ previous try-compile may cause a different test to either pass or
+ fail incorrectly. This option is best used for one try-compile at a
+ time, and only when debugging.
+
+``--debug-output``
+ Put cmake in a debug mode.
+
+ Print extra information during the cmake run like stack traces with
+ :command:`message(SEND_ERROR)` calls.
+
+``--debug-find``
+ Put cmake find commands in a debug mode.
+
+ Print extra find call information during the cmake run to standard
+ error. Output is designed for human consumption and not for parsing.
+ See also the :variable:`CMAKE_FIND_DEBUG_MODE` variable for debugging
+ a more local part of the project.
+
+``--trace``
+ Put cmake in trace mode.
+
+ Print a trace of all calls made and from where.
+
+``--trace-expand``
+ Put cmake in trace mode.
+
+ Like ``--trace``, but with variables expanded.
+
+``--trace-format=<format>``
+ Put cmake in trace mode and sets the trace output format.
+
+ ``<format>`` can be one of the following values.
+
+ ``human``
+ Prints each trace line in a human-readable format. This is the
+ default format.
+
+ ``json-v1``
+ Prints each line as a separate JSON document. Each document is
+ separated by a newline ( ``\n`` ). It is guaranteed that no
+ newline characters will be present inside a JSON document.
+
+ JSON trace format:
+
+ .. code-block:: json
+
+ {
+ "file": "/full/path/to/the/CMake/file.txt",
+ "line": 0,
+ "cmd": "add_executable",
+ "args": ["foo", "bar"],
+ "time": 1579512535.9687231,
+ "frame": 2
+ }
+
+ The members are:
+
+ ``file``
+ The full path to the CMake source file where the function
+ was called.
+
+ ``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.
+
+ ``args``
+ A string list of all function parameters.
+
+ ``time``
+ Timestamp (seconds since epoch) of the function call.
+
+ ``frame``
+ Stack frame depth of the function that was called.
+
+ Additionally, the first JSON document outputted contains the
+ ``version`` key for the current major and minor version of the
+
+ JSON trace format:
+
+ .. code-block:: json
+
+ {
+ "version": {
+ "major": 1,
+ "minor": 1
+ }
+ }
+
+ The members are:
+
+ ``version``
+ Indicates the version of the JSON format. The version has a
+ major and minor components following semantic version conventions.
+
+``--trace-source=<file>``
+ Put cmake in trace mode, but output only lines of a specified file.
+
+ Multiple options are allowed.
+
+``--trace-redirect=<file>``
+ Put cmake in trace mode and redirect trace output to a file instead of stderr.
+
+``--warn-uninitialized``
+ Warn about uninitialized values.
+
+ Print a warning when an uninitialized variable is used.
+
+``--warn-unused-vars``
+ Does nothing. In CMake versions 3.2 and below this enabled warnings about
+ unused variables. In CMake versions 3.3 through 3.18 the option was broken.
+ In CMake 3.19 and above the option has been removed.
+
+``--no-warn-unused-cli``
+ Don't warn about command line options.
+
+ Don't find variables that are declared on the command line, but not
+ used.
+
+``--check-system-vars``
+ Find problems with variable usage in system files.
+
+ Normally, unused and uninitialized variables are searched for only
+ in :variable:`CMAKE_SOURCE_DIR` and :variable:`CMAKE_BINARY_DIR`.
+ This flag tells CMake to warn about other files as well.
+
+``--profiling-output=<path>``
+ Used in conjunction with ``--profiling-format`` to output to a given path.
+
+``--profiling-format=<file>``
+ Enable the output of profiling data of CMake script in the given format.
+
+ This can aid performance analysis of CMake scripts executed. Third party
+ applications should be used to process the output into human readable format.
+
+ Currently supported values are:
+ ``google-trace`` Outputs in Google Trace Format, which can be parsed by the
+ about:tracing tab of Google Chrome or using a plugin for a tool like Trace
+ Compass.
+
+``--preset <preset>``, ``--preset=<preset>``
+ Reads a :manual:`preset <cmake-presets(7)>` from
+ ``<path-to-source>/CMakePresets.json`` and
+ ``<path-to-source>/CMakeUserPresets.json``. The preset specifies the
+ generator and the build directory, and optionally a list of variables and
+ other arguments to pass to CMake. The current working directory must contain
+ CMake preset files. The :manual:`CMake GUI <cmake-gui(1)>` can
+ also recognize ``CMakePresets.json`` and ``CMakeUserPresets.json`` files. For
+ full details on these files, see :manual:`cmake-presets(7)`.
+
+ The presets are read before all other command line options. The options
+ specified by the preset (variables, generator, etc.) can all be overridden by
+ manually specifying them on the command line. For example, if the preset sets
+ a variable called ``MYVAR`` to ``1``, but the user sets it to ``2`` with a
+ ``-D`` argument, the value ``2`` is preferred.
+
+``--list-presets, --list-presets=<[configure | build | test | all]>``
+ Lists the available presets. If no option is specified only configure presets
+ will be listed. The current working directory must contain CMake preset files.
+
+.. _`Build Tool Mode`:
+
+Build a Project
+===============
+
+CMake provides a command-line signature to build an already-generated
+project binary tree:
+
+.. code-block:: shell
+
+ cmake --build [<dir> | --preset <preset>] [<options>] [-- <build-tool-options>]
+
+This abstracts a native build tool's command-line interface with the
+following options:
+
+``--build <dir>``
+ Project binary directory to be built. This is required (unless a preset
+ is specified) and must be first.
+
+``--preset <preset>``, ``--preset=<preset>``
+ Use a build preset to specify build options. The project binary directory
+ is inferred from the ``configurePreset`` key. The current working directory
+ must contain CMake preset files.
+ See :manual:`preset <cmake-presets(7)>` for more details.
+
+``--list-presets``
+ Lists the available build presets. The current working directory must
+ contain CMake preset files.
+
+``--parallel [<jobs>], -j [<jobs>]``
+ The maximum number of concurrent processes to use when building.
+ If ``<jobs>`` is omitted the native build tool's default number is used.
+
+ The :envvar:`CMAKE_BUILD_PARALLEL_LEVEL` environment variable, if set,
+ specifies a default parallel level when this option is not given.
+
+ Some native build tools always build in parallel. The use of ``<jobs>``
+ value of ``1`` can be used to limit to a single job.
+
+``--target <tgt>..., -t <tgt>...``
+ Build ``<tgt>`` instead of the default target. Multiple targets may be
+ given, separated by spaces.
+
+``--config <cfg>``
+ For multi-configuration tools, choose configuration ``<cfg>``.
+
+``--clean-first``
+ Build target ``clean`` first, then build.
+ (To clean only, use ``--target clean``.)
+
+``--use-stderr``
+ Ignored. Behavior is default in CMake >= 3.0.
+
+``--verbose, -v``
+ Enable verbose output - if supported - including the build commands to be
+ executed.
+
+ This option can be omitted if :envvar:`VERBOSE` environment variable or
+ :variable:`CMAKE_VERBOSE_MAKEFILE` cached variable is set.
+
+
+``--``
+ Pass remaining options to the native tool.
+
+Run ``cmake --build`` with no options for quick help.
+
+Install a Project
+=================
+
+CMake provides a command-line signature to install an already-generated
+project binary tree:
+
+.. code-block:: shell
+
+ cmake --install <dir> [<options>]
+
+This may be used after building a project to run installation without
+using the generated build system or the native build tool.
+The options are:
+
+``--install <dir>``
+ Project binary directory to install. This is required and must be first.
+
+``--config <cfg>``
+ For multi-configuration generators, choose configuration ``<cfg>``.
+
+``--component <comp>``
+ Component-based install. Only install component ``<comp>``.
+
+``--default-directory-permissions <permissions>``
+ Default directory install permissions. Permissions in format ``<u=rwx,g=rx,o=rx>``.
+
+``--prefix <prefix>``
+ Override the installation prefix, :variable:`CMAKE_INSTALL_PREFIX`.
+
+``--strip``
+ Strip before installing.
+
+``-v, --verbose``
+ Enable verbose output.
+
+ This option can be omitted if :envvar:`VERBOSE` environment variable is set.
+
+Run ``cmake --install`` with no options for quick help.
+
+Open a Project
+==============
+
+.. code-block:: shell
+
+ cmake --open <dir>
+
+Open the generated project in the associated application. This is only
+supported by some generators.
+
+
+.. _`Script Processing Mode`:
+
+Run a Script
+============
+
+.. code-block:: shell
+
+ cmake [{-D <var>=<value>}...] -P <cmake-script-file> [-- <unparsed-options>...]
+
+Process the given cmake file as a script written in the CMake
+language. No configure or generate step is performed and the cache
+is not modified. If variables are defined using ``-D``, this must be
+done before the ``-P`` argument.
+
+Any options after ``--`` are not parsed by CMake, but they are still included
+in the set of :variable:`CMAKE_ARGV<n> <CMAKE_ARGV0>` variables passed to the
+script (including the ``--`` itself).
+
+
+Run a Command-Line Tool
+=======================
+
+CMake provides builtin command-line tools through the signature
+
+.. code-block:: shell
+
+ cmake -E <command> [<options>]
+
+Run ``cmake -E`` or ``cmake -E help`` for a summary of commands.
+Available commands are:
+
+``capabilities``
+ Report cmake capabilities in JSON format. The output is a JSON object
+ with the following keys:
+
+ ``version``
+ A JSON object with version information. Keys are:
+
+ ``string``
+ The full version string as displayed by cmake ``--version``.
+ ``major``
+ The major version number in integer form.
+ ``minor``
+ The minor version number in integer form.
+ ``patch``
+ The patch level in integer form.
+ ``suffix``
+ The cmake version suffix string.
+ ``isDirty``
+ A bool that is set if the cmake build is from a dirty tree.
+
+ ``generators``
+ A list available generators. Each generator is a JSON object with the
+ following keys:
+
+ ``name``
+ A string containing the name of the generator.
+ ``toolsetSupport``
+ ``true`` if the generator supports toolsets and ``false`` otherwise.
+ ``platformSupport``
+ ``true`` if the generator supports platforms and ``false`` otherwise.
+ ``extraGenerators``
+ A list of strings with all the extra generators compatible with
+ the generator.
+
+ ``fileApi``
+ Optional member that is present when the :manual:`cmake-file-api(7)`
+ is available. The value is a JSON object with one member:
+
+ ``requests``
+ A JSON array containing zero or more supported file-api requests.
+ Each request is a JSON object with members:
+
+ ``kind``
+ Specifies one of the supported :ref:`file-api object kinds`.
+
+ ``version``
+ A JSON array whose elements are each a JSON object containing
+ ``major`` and ``minor`` members specifying non-negative integer
+ version components.
+
+ ``serverMode``
+ ``true`` if cmake supports server-mode and ``false`` otherwise.
+ Always false since CMake 3.20.
+
+``cat <files>...``
+ Concatenate files and print on the standard output.
+
+``chdir <dir> <cmd> [<arg>...]``
+ Change the current working directory and run a command.
+
+``compare_files [--ignore-eol] <file1> <file2>``
+ Check if ``<file1>`` is same as ``<file2>``. If files are the same,
+ then returns ``0``, if not it returns ``1``. In case of invalid
+ arguments, it returns 2. The ``--ignore-eol`` option
+ implies line-wise comparison and ignores LF/CRLF differences.
+
+``copy <file>... <destination>``
+ Copy files to ``<destination>`` (either file or directory).
+ If multiple files are specified, the ``<destination>`` must be
+ directory and it must exist. Wildcards are not supported.
+ ``copy`` does follow symlinks. That means it does not copy symlinks,
+ but the files or directories it point to.
+
+``copy_directory <dir>... <destination>``
+ Copy content of ``<dir>...`` directories to ``<destination>`` directory.
+ If ``<destination>`` directory does not exist it will be created.
+ ``copy_directory`` does follow symlinks.
+
+``copy_if_different <file>... <destination>``
+ Copy files to ``<destination>`` (either file or directory) if
+ they have changed.
+ If multiple files are specified, the ``<destination>`` must be
+ directory and it must exist.
+ ``copy_if_different`` does follow symlinks.
+
+``create_symlink <old> <new>``
+ Create a symbolic link ``<new>`` naming ``<old>``.
+
+ .. note::
+ Path to where ``<new>`` symbolic link will be created has to exist beforehand.
+
+``create_hardlink <old> <new>``
+ Create a hard link ``<new>`` naming ``<old>``.
+
+ .. note::
+ Path to where ``<new>`` hard link will be created has to exist beforehand.
+ ``<old>`` has to exist beforehand.
+
+``echo [<string>...]``
+ Displays arguments as text.
+
+``echo_append [<string>...]``
+ Displays arguments as text but no new line.
+
+``env [--unset=NAME]... [NAME=VALUE]... COMMAND [ARG]...``
+ Run command in a modified environment.
+
+``environment``
+ Display the current environment variables.
+
+``false``
+ Do nothing, with an exit code of 1.
+
+``make_directory <dir>...``
+ Create ``<dir>`` directories. If necessary, create parent
+ directories too. If a directory already exists it will be
+ silently ignored.
+
+``md5sum <file>...``
+ Create MD5 checksum of files in ``md5sum`` compatible format::
+
+ 351abe79cd3800b38cdfb25d45015a15 file1.txt
+ 052f86c15bbde68af55c7f7b340ab639 file2.txt
+
+``sha1sum <file>...``
+ Create SHA1 checksum of files in ``sha1sum`` compatible format::
+
+ 4bb7932a29e6f73c97bb9272f2bdc393122f86e0 file1.txt
+ 1df4c8f318665f9a5f2ed38f55adadb7ef9f559c file2.txt
+
+``sha224sum <file>...``
+ Create SHA224 checksum of files in ``sha224sum`` compatible format::
+
+ b9b9346bc8437bbda630b0b7ddfc5ea9ca157546dbbf4c613192f930 file1.txt
+ 6dfbe55f4d2edc5fe5c9197bca51ceaaf824e48eba0cc453088aee24 file2.txt
+
+``sha256sum <file>...``
+ Create SHA256 checksum of files in ``sha256sum`` compatible format::
+
+ 76713b23615d31680afeb0e9efe94d47d3d4229191198bb46d7485f9cb191acc file1.txt
+ 15b682ead6c12dedb1baf91231e1e89cfc7974b3787c1e2e01b986bffadae0ea file2.txt
+
+``sha384sum <file>...``
+ Create SHA384 checksum of files in ``sha384sum`` compatible format::
+
+ acc049fedc091a22f5f2ce39a43b9057fd93c910e9afd76a6411a28a8f2b8a12c73d7129e292f94fc0329c309df49434 file1.txt
+ 668ddeb108710d271ee21c0f3acbd6a7517e2b78f9181c6a2ff3b8943af92b0195dcb7cce48aa3e17893173c0a39e23d file2.txt
+
+``sha512sum <file>...``
+ Create SHA512 checksum of files in ``sha512sum`` compatible format::
+
+ 2a78d7a6c5328cfb1467c63beac8ff21794213901eaadafd48e7800289afbc08e5fb3e86aa31116c945ee3d7bf2a6194489ec6101051083d1108defc8e1dba89 file1.txt
+ 7a0b54896fe5e70cca6dd643ad6f672614b189bf26f8153061c4d219474b05dad08c4e729af9f4b009f1a1a280cb625454bf587c690f4617c27e3aebdf3b7a2d file2.txt
+
+``remove [-f] <file>...``
+ .. deprecated:: 3.17
+
+ Remove the file(s). The planned behaviour was that if any of the
+ listed files already do not exist, the command returns a non-zero exit code,
+ but no message is logged. The ``-f`` option changes the behavior to return a
+ zero exit code (i.e. success) in such situations instead.
+ ``remove`` does not follow symlinks. That means it remove only symlinks
+ and not files it point to.
+
+ The implementation was buggy and always returned 0. It cannot be fixed without
+ breaking backwards compatibility. Use ``rm`` instead.
+
+``remove_directory <dir>...``
+ .. deprecated:: 3.17
+
+ Remove ``<dir>`` directories and their contents. If a directory does
+ not exist it will be silently ignored. If ``<dir>`` is a symlink to
+ a directory, just the symlink will be removed.
+ Use ``rm`` instead.
+
+``rename <oldname> <newname>``
+ Rename a file or directory (on one volume). If file with the ``<newname>`` name
+ already exists, then it will be silently replaced.
+
+``rm [-rRf] <file> <dir>...``
+ Remove the files ``<file>`` or directories ``dir``.
+ Use ``-r`` or ``-R`` to remove directories and their contents recursively.
+ If any of the listed files/directories do not exist, the command returns a
+ non-zero exit code, but no message is logged. The ``-f`` option changes
+ the behavior to return a zero exit code (i.e. success) in such
+ situations instead.
+
+``server``
+ Launch :manual:`cmake-server(7)` mode.
+
+``sleep <number>...``
+ Sleep for given number of seconds.
+
+``tar [cxt][vf][zjJ] file.tar [<options>] [--] [<pathname>...]``
+ Create or extract a tar or zip archive. Options are:
+
+ ``c``
+ Create a new archive containing the specified files.
+ If used, the ``<pathname>...`` argument is mandatory.
+ ``x``
+ Extract to disk from the archive.
+ The ``<pathname>...`` argument could be used to extract only selected files
+ or directories.
+ When extracting selected files or directories, you must provide their exact
+ names including the path, as printed by list (``-t``).
+ ``t``
+ List archive contents.
+ The ``<pathname>...`` argument could be used to list only selected files
+ or directories.
+ ``v``
+ Produce verbose output.
+ ``z``
+ Compress the resulting archive with gzip.
+ ``j``
+ Compress the resulting archive with bzip2.
+ ``J``
+ Compress the resulting archive with XZ.
+ ``--zstd``
+ Compress the resulting archive with Zstandard.
+ ``--files-from=<file>``
+ Read file names from the given file, one per line.
+ Blank lines are ignored. Lines may not start in ``-``
+ except for ``--add-file=<name>`` to add files whose
+ names start in ``-``.
+ ``--format=<format>``
+ Specify the format of the archive to be created.
+ Supported formats are: ``7zip``, ``gnutar``, ``pax``,
+ ``paxr`` (restricted pax, default), and ``zip``.
+ ``--mtime=<date>``
+ Specify modification time recorded in tarball entries.
+ ``--``
+ Stop interpreting options and treat all remaining arguments
+ as file names, even if they start with ``-``.
+
+
+``time <command> [<args>...]``
+ Run command and display elapsed time.
+
+``touch <file>...``
+ Creates ``<file>`` if file do not exist.
+ If ``<file>`` exists, it is changing ``<file>`` access and modification times.
+
+``touch_nocreate <file>...``
+ Touch a file if it exists but do not create it. If a file does
+ not exist it will be silently ignored.
+
+``true``
+ Do nothing, with an exit code of 0.
+
+Windows-specific Command-Line Tools
+-----------------------------------
+
+The following ``cmake -E`` commands are available only on Windows:
+
+``delete_regv <key>``
+ Delete Windows registry value.
+
+``env_vs8_wince <sdkname>``
+ Displays a batch file which sets the environment for the provided
+ Windows CE SDK installed in VS2005.
+
+``env_vs9_wince <sdkname>``
+ Displays a batch file which sets the environment for the provided
+ Windows CE SDK installed in VS2008.
+
+``write_regv <key> <value>``
+ Write Windows registry value.
+
+
+Run the Find-Package Tool
+=========================
+
+CMake provides a pkg-config like helper for Makefile-based projects:
+
+.. code-block:: shell
+
+ cmake --find-package [<options>]
+
+It searches a package using :command:`find_package()` and prints the
+resulting flags to stdout. This can be used instead of pkg-config
+to find installed libraries in plain Makefile-based projects or in
+autoconf-based projects (via ``share/aclocal/cmake.m4``).
+
+.. note::
+ This mode is not well-supported due to some technical limitations.
+ It is kept for compatibility but should not be used in new projects.
+
+
+View Help
+=========
+
+To print selected pages from the CMake documentation, use
+
+.. code-block:: shell
+
+ cmake --help[-<topic>]
+
+with one of the following options:
+
+.. include:: OPTIONS_HELP.txt
+
+To view the presets available for a project, use
+
+.. code-block:: shell
+
+ cmake <source-dir> --list-presets
+
+See Also
+========
+
+.. include:: LINKS.txt
diff --git a/Help/manual/cpack-generators.7.rst b/Help/manual/cpack-generators.7.rst
new file mode 100644
index 0000000..ade9149
--- /dev/null
+++ b/Help/manual/cpack-generators.7.rst
@@ -0,0 +1,29 @@
+.. cmake-manual-description: CPack Generator Reference
+
+cpack-generators(7)
+*******************
+
+.. only:: html
+
+ .. contents::
+
+Generators
+==========
+
+.. toctree::
+ :maxdepth: 1
+
+ /cpack_gen/archive
+ /cpack_gen/bundle
+ /cpack_gen/cygwin
+ /cpack_gen/deb
+ /cpack_gen/dmg
+ /cpack_gen/external
+ /cpack_gen/freebsd
+ /cpack_gen/ifw
+ /cpack_gen/nsis
+ /cpack_gen/nuget
+ /cpack_gen/packagemaker
+ /cpack_gen/productbuild
+ /cpack_gen/rpm
+ /cpack_gen/wix
diff --git a/Help/manual/cpack.1.rst b/Help/manual/cpack.1.rst
new file mode 100644
index 0000000..395cd41
--- /dev/null
+++ b/Help/manual/cpack.1.rst
@@ -0,0 +1,113 @@
+.. cmake-manual-description: CPack Command-Line Reference
+
+cpack(1)
+********
+
+Synopsis
+========
+
+.. parsed-literal::
+
+ cpack [<options>]
+
+Description
+===========
+
+The **cpack** executable is the CMake packaging program. It generates
+installers and source packages in a variety of formats.
+
+For each installer or package format, **cpack** has a specific backend,
+called "generator". A generator is responsible for generating the required
+inputs and invoking the specific package creation tools. These installer
+or package generators are not to be confused with the makefile generators
+of the :manual:`cmake <cmake(1)>` command.
+
+All supported generators are specified in the :manual:`cpack-generators
+<cpack-generators(7)>` manual. The command ``cpack --help`` prints a
+list of generators supported for the target platform. Which of them are
+to be used can be selected through the :variable:`CPACK_GENERATOR` variable
+or through the command-line option ``-G``.
+
+The **cpack** program is steered by a configuration file written in the
+:manual:`CMake language <cmake-language(7)>`. Unless chosen differently
+through the command-line option ``--config``, the file ``CPackConfig.cmake``
+in the current directory is used.
+
+In the standard CMake workflow, the file ``CPackConfig.cmake`` is generated
+by the :manual:`cmake <cmake(1)>` executable, provided the :module:`CPack`
+module is included by the project's ``CMakeLists.txt`` file.
+
+Options
+=======
+
+``-G <generators>``
+ ``<generators>`` is a :ref:`semicolon-separated list <CMake Language Lists>`
+ of generator names. ``cpack`` will iterate through this list and produce
+ package(s) in that generator's format according to the details provided in
+ the ``CPackConfig.cmake`` configuration file. If this option is not given,
+ the :variable:`CPACK_GENERATOR` variable determines the default set of
+ generators that will be used.
+
+``-C <configs>``
+ Specify the project configuration(s) to be packaged (e.g. ``Debug``,
+ ``Release``, etc.), where ``<configs>`` is a
+ :ref:`semicolon-separated list <CMake Language Lists>`.
+ When the CMake project uses a multi-configuration
+ generator such as Xcode or Visual Studio, this option is needed to tell
+ ``cpack`` which built executables to include in the package.
+ The user is responsible for ensuring that the configuration(s) listed
+ have already been built before invoking ``cpack``.
+
+``-D <var>=<value>``
+ Set a CPack variable. This will override any value set for ``<var>`` in the
+ input file read by ``cpack``.
+
+``--config <configFile>``
+ Specify the configuration file read by ``cpack`` to provide the packaging
+ details. By default, ``CPackConfig.cmake`` in the current directory will
+ be used.
+
+``--verbose, -V``
+ Run ``cpack`` with verbose output. This can be used to show more details
+ from the package generation tools and is suitable for project developers.
+
+``--debug``
+ Run ``cpack`` with debug output. This option is intended mainly for the
+ developers of ``cpack`` itself and is not normally needed by project
+ developers.
+
+``--trace``
+ Put the underlying cmake scripts in trace mode.
+
+``--trace-expand``
+ Put the underlying cmake scripts in expanded trace mode.
+
+``-P <packageName>``
+ Override/define the value of the :variable:`CPACK_PACKAGE_NAME` variable used
+ for packaging. Any value set for this variable in the ``CPackConfig.cmake``
+ file will then be ignored.
+
+``-R <packageVersion>``
+ Override/define the value of the :variable:`CPACK_PACKAGE_VERSION`
+ variable used for packaging. It will override a value set in the
+ ``CPackConfig.cmake`` file or one automatically computed from
+ :variable:`CPACK_PACKAGE_VERSION_MAJOR`,
+ :variable:`CPACK_PACKAGE_VERSION_MINOR` and
+ :variable:`CPACK_PACKAGE_VERSION_PATCH`.
+
+``-B <packageDirectory>``
+ Override/define :variable:`CPACK_PACKAGE_DIRECTORY`, which controls the
+ directory where CPack will perform its packaging work. The resultant
+ package(s) will be created at this location by default and a
+ ``_CPack_Packages`` subdirectory will also be created below this directory to
+ use as a working area during package creation.
+
+``--vendor <vendorName>``
+ Override/define :variable:`CPACK_PACKAGE_VENDOR`.
+
+.. include:: OPTIONS_HELP.txt
+
+See Also
+========
+
+.. include:: LINKS.txt
diff --git a/Help/manual/ctest.1.rst b/Help/manual/ctest.1.rst
new file mode 100644
index 0000000..68409e1
--- /dev/null
+++ b/Help/manual/ctest.1.rst
@@ -0,0 +1,1668 @@
+.. cmake-manual-description: CTest Command-Line Reference
+
+ctest(1)
+********
+
+.. contents::
+
+Synopsis
+========
+
+.. parsed-literal::
+
+ ctest [<options>]
+ ctest --build-and-test <path-to-source> <path-to-build>
+ --build-generator <generator> [<options>...]
+ [--build-options <opts>...] [--test-command <command> [<args>...]]
+ ctest {-D <dashboard> | -M <model> -T <action> | -S <script> | -SP <script>}
+ [-- <dashboard-options>...]
+
+Description
+===========
+
+The **ctest** executable is the CMake test driver program.
+CMake-generated build trees created for projects that use the
+:command:`enable_testing` and :command:`add_test` commands have testing support.
+This program will run the tests and report results.
+
+.. _`CTest Options`:
+
+Options
+=======
+
+``--preset <preset>``, ``--preset=<preset>``
+ Use a test preset to specify test options. The project binary directory
+ is inferred from the ``configurePreset`` key. The current working directory
+ must contain CMake preset files.
+ See :manual:`preset <cmake-presets(7)>` for more details.
+
+``--list-presets``
+ Lists the available test presets. The current working directory must contain
+ CMake preset files.
+
+``-C <cfg>, --build-config <cfg>``
+ Choose configuration to test.
+
+ Some CMake-generated build trees can have multiple build
+ configurations in the same tree. This option can be used to specify
+ which one should be tested. Example configurations are ``Debug`` and
+ ``Release``.
+
+``--progress``
+ Enable short progress output from tests.
+
+ When the output of **ctest** is being sent directly to a terminal, the
+ progress through the set of tests is reported by updating the same line
+ rather than printing start and end messages for each test on new lines.
+ This can significantly reduce the verbosity of the test output.
+ Test completion messages are still output on their own line for failed
+ tests and the final test summary will also still be logged.
+
+ This option can also be enabled by setting the environment variable
+ :envvar:`CTEST_PROGRESS_OUTPUT`.
+
+``-V,--verbose``
+ Enable verbose output from tests.
+
+ Test output is normally suppressed and only summary information is
+ displayed. This option will show all test output.
+
+``-VV,--extra-verbose``
+ Enable more verbose output from tests.
+
+ Test output is normally suppressed and only summary information is
+ displayed. This option will show even more test output.
+
+``--debug``
+ Displaying more verbose internals of CTest.
+
+ This feature will result in a large number of output that is mostly
+ useful for debugging dashboard problems.
+
+``--output-on-failure``
+ Output anything outputted by the test program if the test should fail.
+ This option can also be enabled by setting the
+ :envvar:`CTEST_OUTPUT_ON_FAILURE` environment variable
+
+``--stop-on-failure``
+ Stop running the tests when the first failure happens.
+
+``-F``
+ Enable failover.
+
+ This option allows CTest to resume a test set execution that was
+ previously interrupted. If no interruption occurred, the ``-F`` option
+ will have no effect.
+
+``-j <jobs>, --parallel <jobs>``
+ Run the tests in parallel using the given number of jobs.
+
+ This option tells CTest to run the tests in parallel using given
+ number of jobs. This option can also be set by setting the
+ :envvar:`CTEST_PARALLEL_LEVEL` environment variable.
+
+ This option can be used with the :prop_test:`PROCESSORS` test property.
+
+ See `Label and Subproject Summary`_.
+
+``--resource-spec-file <file>``
+ Run CTest with :ref:`resource allocation <ctest-resource-allocation>` enabled,
+ using the
+ :ref:`resource specification file <ctest-resource-specification-file>`
+ specified in ``<file>``.
+
+ When ``ctest`` is run as a `Dashboard Client`_ this sets the
+ ``ResourceSpecFile`` option of the `CTest Test Step`_.
+
+``--test-load <level>``
+ While running tests in parallel (e.g. with ``-j``), try not to start
+ tests when they may cause the CPU load to pass above a given threshold.
+
+ When ``ctest`` is run as a `Dashboard Client`_ this sets the
+ ``TestLoad`` option of the `CTest Test Step`_.
+
+``-Q,--quiet``
+ Make CTest quiet.
+
+ This option will suppress all the output. The output log file will
+ still be generated if the ``--output-log`` is specified. Options such
+ as ``--verbose``, ``--extra-verbose``, and ``--debug`` are ignored
+ if ``--quiet`` is specified.
+
+``-O <file>, --output-log <file>``
+ Output to log file.
+
+ This option tells CTest to write all its output to a ``<file>`` log file.
+
+``-N,--show-only[=<format>]``
+ Disable actual execution of tests.
+
+ This option tells CTest to list the tests that would be run but not
+ actually run them. Useful in conjunction with the ``-R`` and ``-E``
+ options.
+
+ ``<format>`` can be one of the following values.
+
+ ``human``
+ Human-friendly output. This is not guaranteed to be stable.
+ This is the default.
+
+ ``json-v1``
+ Dump the test information in JSON format.
+ See `Show as JSON Object Model`_.
+
+``-L <regex>, --label-regex <regex>``
+ Run tests with labels matching regular expression.
+
+ This option tells CTest to run only the tests whose labels match the
+ given regular expression. When more than one ``-L`` option is given,
+ a test will only be run if each regular expression matches at least one
+ of the test's labels (i.e. the multiple ``-L`` labels form an ``AND``
+ relationship). See `Label Matching`_.
+
+``-R <regex>, --tests-regex <regex>``
+ Run tests matching regular expression.
+
+ This option tells CTest to run only the tests whose names match the
+ given regular expression.
+
+``-E <regex>, --exclude-regex <regex>``
+ Exclude tests matching regular expression.
+
+ This option tells CTest to NOT run the tests whose names match the
+ given regular expression.
+
+``-LE <regex>, --label-exclude <regex>``
+ Exclude tests with labels matching regular expression.
+
+ This option tells CTest to NOT run the tests whose labels match the
+ given regular expression. When more than one ``-LE`` option is given,
+ a test will only be excluded if each regular expression matches at least one
+ of the test's labels (i.e. the multiple ``-LE`` labels form an ``AND``
+ relationship). See `Label Matching`_.
+
+``-FA <regex>, --fixture-exclude-any <regex>``
+ Exclude fixtures matching ``<regex>`` from automatically adding any tests to
+ the test set.
+
+ If a test in the set of tests to be executed requires a particular fixture,
+ that fixture's setup and cleanup tests would normally be added to the test set
+ automatically. This option prevents adding setup or cleanup tests for fixtures
+ matching the ``<regex>``. Note that all other fixture behavior is retained,
+ including test dependencies and skipping tests that have fixture setup tests
+ that fail.
+
+``-FS <regex>, --fixture-exclude-setup <regex>``
+ Same as ``-FA`` except only matching setup tests are excluded.
+
+``-FC <regex>, --fixture-exclude-cleanup <regex>``
+ Same as ``-FA`` except only matching cleanup tests are excluded.
+
+``-D <dashboard>, --dashboard <dashboard>``
+ Execute dashboard test.
+
+ This option tells CTest to act as a CDash client and perform a
+ dashboard test. All tests are ``<Mode><Test>``, where ``<Mode>`` can be
+ ``Experimental``, ``Nightly``, and ``Continuous``, and ``<Test>`` can be
+ ``Start``, ``Update``, ``Configure``, ``Build``, ``Test``,
+ ``Coverage``, and ``Submit``.
+
+ See `Dashboard Client`_.
+
+``-D <var>:<type>=<value>``
+ Define a variable for script mode.
+
+ Pass in variable values on the command line. Use in conjunction
+ with ``-S`` to pass variable values to a dashboard script. Parsing ``-D``
+ arguments as variable values is only attempted if the value
+ following ``-D`` does not match any of the known dashboard types.
+
+``-M <model>, --test-model <model>``
+ Sets the model for a dashboard.
+
+ This option tells CTest to act as a CDash client where the ``<model>``
+ can be ``Experimental``, ``Nightly``, and ``Continuous``.
+ Combining ``-M`` and ``-T`` is similar to ``-D``.
+
+ See `Dashboard Client`_.
+
+``-T <action>, --test-action <action>``
+ Sets the dashboard action to perform.
+
+ This option tells CTest to act as a CDash client and perform some
+ action such as ``start``, ``build``, ``test`` etc. See
+ `Dashboard Client Steps`_ for the full list of actions.
+ Combining ``-M`` and ``-T`` is similar to ``-D``.
+
+ See `Dashboard Client`_.
+
+``-S <script>, --script <script>``
+ Execute a dashboard for a configuration.
+
+ This option tells CTest to load in a configuration script which sets
+ a number of parameters such as the binary and source directories.
+ Then CTest will do what is required to create and run a dashboard.
+ This option basically sets up a dashboard and then runs ``ctest -D``
+ with the appropriate options.
+
+ See `Dashboard Client`_.
+
+``-SP <script>, --script-new-process <script>``
+ Execute a dashboard for a configuration.
+
+ This option does the same operations as ``-S`` but it will do them in a
+ separate process. This is primarily useful in cases where the
+ script may modify the environment and you do not want the modified
+ environment to impact other ``-S`` scripts.
+
+ See `Dashboard Client`_.
+
+``-I [Start,End,Stride,test#,test#|Test file], --tests-information``
+ Run a specific number of tests by number.
+
+ This option causes CTest to run tests starting at number ``Start``,
+ ending at number ``End``, and incrementing by ``Stride``. Any additional
+ numbers after ``Stride`` are considered individual test numbers. ``Start``,
+ ``End``, or ``Stride`` can be empty. Optionally a file can be given that
+ contains the same syntax as the command line.
+
+``-U, --union``
+ Take the Union of ``-I`` and ``-R``.
+
+ When both ``-R`` and ``-I`` are specified by default the intersection of
+ tests are run. By specifying ``-U`` the union of tests is run instead.
+
+``--rerun-failed``
+ Run only the tests that failed previously.
+
+ This option tells CTest to perform only the tests that failed during
+ its previous run. When this option is specified, CTest ignores all
+ other options intended to modify the list of tests to run (``-L``, ``-R``,
+ ``-E``, ``-LE``, ``-I``, etc). In the event that CTest runs and no tests
+ fail, subsequent calls to CTest with the ``--rerun-failed`` option will run
+ the set of tests that most recently failed (if any).
+
+``--repeat <mode>:<n>``
+ Run tests repeatedly based on the given ``<mode>`` up to ``<n>`` times.
+ The modes are:
+
+ ``until-fail``
+ Require each test to run ``<n>`` times without failing in order to pass.
+ This is useful in finding sporadic failures in test cases.
+
+ ``until-pass``
+ Allow each test to run up to ``<n>`` times in order to pass.
+ Repeats tests if they fail for any reason.
+ This is useful in tolerating sporadic failures in test cases.
+
+ ``after-timeout``
+ Allow each test to run up to ``<n>`` times in order to pass.
+ Repeats tests only if they timeout.
+ This is useful in tolerating sporadic timeouts in test cases
+ on busy machines.
+
+``--repeat-until-fail <n>``
+ Equivalent to ``--repeat until-fail:<n>``.
+
+``--max-width <width>``
+ Set the max width for a test name to output.
+
+ Set the maximum width for each test name to show in the output.
+ This allows the user to widen the output to avoid clipping the test
+ name which can be very annoying.
+
+``--interactive-debug-mode [0|1]``
+ Set the interactive mode to ``0`` or ``1``.
+
+ This option causes CTest to run tests in either an interactive mode
+ or a non-interactive mode. On Windows this means that in
+ non-interactive mode, all system debug pop up windows are blocked.
+ In dashboard mode (``Experimental``, ``Nightly``, ``Continuous``), the default
+ is non-interactive. When just running tests not for a dashboard the
+ default is to allow popups and interactive debugging.
+
+``--no-label-summary``
+ Disable timing summary information for labels.
+
+ This option tells CTest not to print summary information for each
+ label associated with the tests run. If there are no labels on the
+ tests, nothing extra is printed.
+
+ See `Label and Subproject Summary`_.
+
+``--no-subproject-summary``
+ Disable timing summary information for subprojects.
+
+ This option tells CTest not to print summary information for each
+ subproject associated with the tests run. If there are no subprojects on the
+ tests, nothing extra is printed.
+
+ See `Label and Subproject Summary`_.
+
+``--build-and-test``
+See `Build and Test Mode`_.
+
+``--test-dir <dir>``
+Specify the directory in which to look for tests.
+
+``--test-output-size-passed <size>``
+ Limit the output for passed tests to ``<size>`` bytes.
+
+``--test-output-size-failed <size>``
+ Limit the output for failed tests to ``<size>`` bytes.
+
+``--overwrite``
+ Overwrite CTest configuration option.
+
+ By default CTest uses configuration options from configuration file.
+ This option will overwrite the configuration option.
+
+``--force-new-ctest-process``
+ Run child CTest instances as new processes.
+
+ By default CTest will run child CTest instances within the same
+ process. If this behavior is not desired, this argument will
+ enforce new processes for child CTest processes.
+
+``--schedule-random``
+ Use a random order for scheduling tests.
+
+ This option will run the tests in a random order. It is commonly
+ used to detect implicit dependencies in a test suite.
+
+``--submit-index``
+ Legacy option for old Dart2 dashboard server feature.
+ Do not use.
+
+``--timeout <seconds>``
+ Set the default test timeout.
+
+ This option effectively sets a timeout on all tests that do not
+ already have a timeout set on them via the :prop_test:`TIMEOUT`
+ property.
+
+``--stop-time <time>``
+ Set a time at which all tests should stop running.
+
+ Set a real time of day at which all tests should timeout. Example:
+ ``7:00:00 -0400``. Any time format understood by the curl date parser
+ is accepted. Local time is assumed if no timezone is specified.
+
+``--print-labels``
+ Print all available test labels.
+
+ This option will not run any tests, it will simply print the list of
+ all labels associated with the test set.
+
+``--no-tests=<[error|ignore]>``
+ Regard no tests found either as error or ignore it.
+
+ If no tests were found, the default behavior of CTest is to always log an
+ error message but to return an error code in script mode only. This option
+ unifies the behavior of CTest by either returning an error code if no tests
+ were found or by ignoring it.
+
+.. include:: OPTIONS_HELP.txt
+
+.. _`Label Matching`:
+
+Label Matching
+==============
+
+Tests may have labels attached to them. Tests may be included
+or excluded from a test run by filtering on the labels.
+Each individual filter is a regular expression applied to
+the labels attached to a test.
+
+When ``-L`` is used, in order for a test to be included in a
+test run, each regular expression must match at least one
+label. Using more than one ``-L`` option means "match **all**
+of these".
+
+The ``-LE`` option works just like ``-L``, but excludes tests
+rather than including them. A test is excluded if each regular
+expression matches at least one label.
+
+If a test has no labels attached to it, then ``-L`` will never
+include that test, and ``-LE`` will never exclude that test.
+As an example of tests with labels, consider five tests,
+with the following labels:
+
+* *test1* has labels *tuesday* and *production*
+* *test2* has labels *tuesday* and *test*
+* *test3* has labels *wednesday* and *production*
+* *test4* has label *wednesday*
+* *test5* has labels *friday* and *test*
+
+Running ``ctest`` with ``-L tuesday -L test`` will select *test2*, which has
+both labels. Running CTest with ``-L test`` will select *test2* and
+*test5*, because both of them have a label that matches that regular
+expression.
+
+Because the matching works with regular expressions, take note that
+running CTest with ``-L es`` will match all five tests.
+To select the *tuesday* and *wednesday* tests together, use a single
+regular expression that matches either of them, like ``-L "tue|wed"``.
+
+.. _`Label and Subproject Summary`:
+
+Label and Subproject Summary
+============================
+
+CTest prints timing summary information for each ``LABEL`` and subproject
+associated with the tests run. The label time summary will not include labels
+that are mapped to subprojects.
+
+When the :prop_test:`PROCESSORS` test property is set, CTest will display a
+weighted test timing result in label and subproject summaries. The time is
+reported with `sec*proc` instead of just `sec`.
+
+The weighted time summary reported for each label or subproject ``j``
+is computed as::
+
+ Weighted Time Summary for Label/Subproject j =
+ sum(raw_test_time[j,i] * num_processors[j,i], i=1...num_tests[j])
+
+ for labels/subprojects j=1...total
+
+where:
+
+* ``raw_test_time[j,i]``: Wall-clock time for the ``i`` test
+ for the ``j`` label or subproject
+* ``num_processors[j,i]``: Value of the CTest :prop_test:`PROCESSORS` property
+ for the ``i`` test for the ``j`` label or subproject
+* ``num_tests[j]``: Number of tests associated with the ``j`` label or subproject
+* ``total``: Total number of labels or subprojects that have at least one test run
+
+Therefore, the weighted time summary for each label or subproject represents
+the amount of time that CTest gave to run the tests for each label or
+subproject and gives a good representation of the total expense of the tests
+for each label or subproject when compared to other labels or subprojects.
+
+For example, if ``SubprojectA`` showed ``100 sec*proc`` and ``SubprojectB`` showed
+``10 sec*proc``, then CTest allocated approximately 10 times the CPU/core time
+to run the tests for ``SubprojectA`` than for ``SubprojectB`` (e.g. so if effort
+is going to be expended to reduce the cost of the test suite for the whole
+project, then reducing the cost of the test suite for ``SubprojectA`` would
+likely have a larger impact than effort to reduce the cost of the test suite
+for ``SubprojectB``).
+
+.. _`Build and Test Mode`:
+
+Build and Test Mode
+===================
+
+CTest provides a command-line signature to configure (i.e. run cmake on),
+build, and/or execute a test::
+
+ ctest --build-and-test <path-to-source> <path-to-build>
+ --build-generator <generator>
+ [<options>...]
+ [--build-options <opts>...]
+ [--test-command <command> [<args>...]]
+
+The configure and test steps are optional. The arguments to this command line
+are the source and binary directories. The ``--build-generator`` option *must*
+be provided to use ``--build-and-test``. If ``--test-command`` is specified
+then that will be run after the build is complete. Other options that affect
+this mode include:
+
+``--build-target``
+ Specify a specific target to build.
+
+ If left out the ``all`` target is built.
+
+``--build-nocmake``
+ Run the build without running cmake first.
+
+ Skip the cmake step.
+
+``--build-run-dir``
+ Specify directory to run programs from.
+
+ Directory where programs will be after it has been compiled.
+
+``--build-two-config``
+ Run CMake twice.
+
+``--build-exe-dir``
+ Specify the directory for the executable.
+
+``--build-generator``
+ Specify the generator to use. See the :manual:`cmake-generators(7)` manual.
+
+``--build-generator-platform``
+ Specify the generator-specific platform.
+
+``--build-generator-toolset``
+ Specify the generator-specific toolset.
+
+``--build-project``
+ Specify the name of the project to build.
+
+``--build-makeprogram``
+ Specify the explicit make program to be used by CMake when configuring and
+ building the project. Only applicable for Make and Ninja based generators.
+
+``--build-noclean``
+ Skip the make clean step.
+
+``--build-config-sample``
+ A sample executable to use to determine the configuration that
+ should be used. e.g. ``Debug``, ``Release`` etc.
+
+``--build-options``
+ Additional options for configuring the build (i.e. for CMake, not for
+ the build tool). Note that if this is specified, the ``--build-options``
+ keyword and its arguments must be the last option given on the command
+ line, with the possible exception of ``--test-command``.
+
+``--test-command``
+ The command to run as the test step with the ``--build-and-test`` option.
+ All arguments following this keyword will be assumed to be part of the
+ test command line, so it must be the last option given.
+
+``--test-timeout``
+ The time limit in seconds
+
+.. _`Dashboard Client`:
+
+Dashboard Client
+================
+
+CTest can operate as a client for the `CDash`_ software quality dashboard
+application. As a dashboard client, CTest performs a sequence of steps
+to configure, build, and test software, and then submits the results to
+a `CDash`_ server. The command-line signature used to submit to `CDash`_ is::
+
+ ctest (-D <dashboard> | -M <model> -T <action> | -S <script> | -SP <script>)
+ [-- <dashboard-options>...]
+
+Options for Dashboard Client include:
+
+``--group <group>``
+ Specify what group you'd like to submit results to
+
+ Submit dashboard to specified group instead of default one. By
+ default, the dashboard is submitted to Nightly, Experimental, or
+ Continuous group, but by specifying this option, the group can be
+ arbitrary.
+
+ This replaces the deprecated option ``--track``.
+ Despite the name change its behavior is unchanged.
+
+``-A <file>, --add-notes <file>``
+ Add a notes file with submission.
+
+ This option tells CTest to include a notes file when submitting
+ dashboard.
+
+``--tomorrow-tag``
+ ``Nightly`` or ``Experimental`` starts with next day tag.
+
+ This is useful if the build will not finish in one day.
+
+``--extra-submit <file>[;<file>]``
+ Submit extra files to the dashboard.
+
+ This option will submit extra files to the dashboard.
+
+``--http1.0``
+ Submit using `HTTP 1.0`.
+
+ This option will force CTest to use `HTTP 1.0` to submit files to the
+ dashboard, instead of `HTTP 1.1`.
+
+``--no-compress-output``
+ Do not compress test output when submitting.
+
+ This flag will turn off automatic compression of test output. Use
+ this to maintain compatibility with an older version of CDash which
+ doesn't support compressed test output.
+
+Dashboard Client Steps
+----------------------
+
+CTest defines an ordered list of testing steps of which some or all may
+be run as a dashboard client:
+
+``Start``
+ Start a new dashboard submission to be composed of results recorded
+ by the following steps.
+ See the `CTest Start Step`_ section below.
+
+``Update``
+ Update the source tree from its version control repository.
+ Record the old and new versions and the list of updated source files.
+ See the `CTest Update Step`_ section below.
+
+``Configure``
+ Configure the software by running a command in the build tree.
+ Record the configuration output log.
+ See the `CTest Configure Step`_ section below.
+
+``Build``
+ Build the software by running a command in the build tree.
+ Record the build output log and detect warnings and errors.
+ See the `CTest Build Step`_ section below.
+
+``Test``
+ Test the software by loading a ``CTestTestfile.cmake``
+ from the build tree and executing the defined tests.
+ Record the output and result of each test.
+ See the `CTest Test Step`_ section below.
+
+``Coverage``
+ Compute coverage of the source code by running a coverage
+ analysis tool and recording its output.
+ See the `CTest Coverage Step`_ section below.
+
+``MemCheck``
+ Run the software test suite through a memory check tool.
+ Record the test output, results, and issues reported by the tool.
+ See the `CTest MemCheck Step`_ section below.
+
+``Submit``
+ Submit results recorded from other testing steps to the
+ software quality dashboard server.
+ See the `CTest Submit Step`_ section below.
+
+Dashboard Client Modes
+----------------------
+
+CTest defines three modes of operation as a dashboard client:
+
+``Nightly``
+ This mode is intended to be invoked once per day, typically at night.
+ It enables the ``Start``, ``Update``, ``Configure``, ``Build``, ``Test``,
+ ``Coverage``, and ``Submit`` steps by default. Selected steps run even
+ if the ``Update`` step reports no changes to the source tree.
+
+``Continuous``
+ This mode is intended to be invoked repeatedly throughout the day.
+ It enables the ``Start``, ``Update``, ``Configure``, ``Build``, ``Test``,
+ ``Coverage``, and ``Submit`` steps by default, but exits after the
+ ``Update`` step if it reports no changes to the source tree.
+
+``Experimental``
+ This mode is intended to be invoked by a developer to test local changes.
+ It enables the ``Start``, ``Configure``, ``Build``, ``Test``, ``Coverage``,
+ and ``Submit`` steps by default.
+
+Dashboard Client via CTest Command-Line
+---------------------------------------
+
+CTest can perform testing on an already-generated build tree.
+Run the ``ctest`` command with the current working directory set
+to the build tree and use one of these signatures::
+
+ ctest -D <mode>[<step>]
+ ctest -M <mode> [ -T <step> ]...
+
+The ``<mode>`` must be one of the above `Dashboard Client Modes`_,
+and each ``<step>`` must be one of the above `Dashboard Client Steps`_.
+
+CTest reads the `Dashboard Client Configuration`_ settings from
+a file in the build tree called either ``CTestConfiguration.ini``
+or ``DartConfiguration.tcl`` (the names are historical). The format
+of the file is::
+
+ # Lines starting in '#' are comments.
+ # Other non-blank lines are key-value pairs.
+ <setting>: <value>
+
+where ``<setting>`` is the setting name and ``<value>`` is the
+setting value.
+
+In build trees generated by CMake, this configuration file is
+generated by the :module:`CTest` module if included by the project.
+The module uses variables to obtain a value for each setting
+as documented with the settings below.
+
+.. _`CTest Script`:
+
+Dashboard Client via CTest Script
+---------------------------------
+
+CTest can perform testing driven by a :manual:`cmake-language(7)`
+script that creates and maintains the source and build tree as
+well as performing the testing steps. Run the ``ctest`` command
+with the current working directory set outside of any build tree
+and use one of these signatures::
+
+ ctest -S <script>
+ ctest -SP <script>
+
+The ``<script>`` file must call :ref:`CTest Commands` commands
+to run testing steps explicitly as documented below. The commands
+obtain `Dashboard Client Configuration`_ settings from their
+arguments or from variables set in the script.
+
+Dashboard Client Configuration
+==============================
+
+The `Dashboard Client Steps`_ may be configured by named
+settings as documented in the following sections.
+
+.. _`CTest Start Step`:
+
+CTest Start Step
+----------------
+
+Start a new dashboard submission to be composed of results recorded
+by the following steps.
+
+In a `CTest Script`_, the :command:`ctest_start` command runs this step.
+Arguments to the command may specify some of the step settings.
+The command first runs the command-line specified by the
+``CTEST_CHECKOUT_COMMAND`` variable, if set, to initialize the source
+directory.
+
+Configuration settings include:
+
+``BuildDirectory``
+ The full path to the project build tree.
+
+ * `CTest Script`_ variable: :variable:`CTEST_BINARY_DIRECTORY`
+ * :module:`CTest` module variable: :variable:`PROJECT_BINARY_DIR`
+
+``SourceDirectory``
+ The full path to the project source tree.
+
+ * `CTest Script`_ variable: :variable:`CTEST_SOURCE_DIRECTORY`
+ * :module:`CTest` module variable: :variable:`PROJECT_SOURCE_DIR`
+
+.. _`CTest Update Step`:
+
+CTest Update Step
+-----------------
+
+In a `CTest Script`_, the :command:`ctest_update` command runs this step.
+Arguments to the command may specify some of the step settings.
+
+Configuration settings to specify the version control tool include:
+
+``BZRCommand``
+ ``bzr`` command-line tool to use if source tree is managed by Bazaar.
+
+ * `CTest Script`_ variable: :variable:`CTEST_BZR_COMMAND`
+ * :module:`CTest` module variable: none
+
+``BZRUpdateOptions``
+ Command-line options to the ``BZRCommand`` when updating the source.
+
+ * `CTest Script`_ variable: :variable:`CTEST_BZR_UPDATE_OPTIONS`
+ * :module:`CTest` module variable: none
+
+``CVSCommand``
+ ``cvs`` command-line tool to use if source tree is managed by CVS.
+
+ * `CTest Script`_ variable: :variable:`CTEST_CVS_COMMAND`
+ * :module:`CTest` module variable: ``CVSCOMMAND``
+
+``CVSUpdateOptions``
+ Command-line options to the ``CVSCommand`` when updating the source.
+
+ * `CTest Script`_ variable: :variable:`CTEST_CVS_UPDATE_OPTIONS`
+ * :module:`CTest` module variable: ``CVS_UPDATE_OPTIONS``
+
+``GITCommand``
+ ``git`` command-line tool to use if source tree is managed by Git.
+
+ * `CTest Script`_ variable: :variable:`CTEST_GIT_COMMAND`
+ * :module:`CTest` module variable: ``GITCOMMAND``
+
+ The source tree is updated by ``git fetch`` followed by
+ ``git reset --hard`` to the ``FETCH_HEAD``. The result is the same
+ as ``git pull`` except that any local modifications are overwritten.
+ Use ``GITUpdateCustom`` to specify a different approach.
+
+``GITInitSubmodules``
+ If set, CTest will update the repository's submodules before updating.
+
+ * `CTest Script`_ variable: :variable:`CTEST_GIT_INIT_SUBMODULES`
+ * :module:`CTest` module variable: ``CTEST_GIT_INIT_SUBMODULES``
+
+``GITUpdateCustom``
+ Specify a custom command line (as a semicolon-separated list) to run
+ in the source tree (Git work tree) to update it instead of running
+ the ``GITCommand``.
+
+ * `CTest Script`_ variable: :variable:`CTEST_GIT_UPDATE_CUSTOM`
+ * :module:`CTest` module variable: ``CTEST_GIT_UPDATE_CUSTOM``
+
+``GITUpdateOptions``
+ Command-line options to the ``GITCommand`` when updating the source.
+
+ * `CTest Script`_ variable: :variable:`CTEST_GIT_UPDATE_OPTIONS`
+ * :module:`CTest` module variable: ``GIT_UPDATE_OPTIONS``
+
+``HGCommand``
+ ``hg`` command-line tool to use if source tree is managed by Mercurial.
+
+ * `CTest Script`_ variable: :variable:`CTEST_HG_COMMAND`
+ * :module:`CTest` module variable: none
+
+``HGUpdateOptions``
+ Command-line options to the ``HGCommand`` when updating the source.
+
+ * `CTest Script`_ variable: :variable:`CTEST_HG_UPDATE_OPTIONS`
+ * :module:`CTest` module variable: none
+
+``P4Client``
+ Value of the ``-c`` option to the ``P4Command``.
+
+ * `CTest Script`_ variable: :variable:`CTEST_P4_CLIENT`
+ * :module:`CTest` module variable: ``CTEST_P4_CLIENT``
+
+``P4Command``
+ ``p4`` command-line tool to use if source tree is managed by Perforce.
+
+ * `CTest Script`_ variable: :variable:`CTEST_P4_COMMAND`
+ * :module:`CTest` module variable: ``P4COMMAND``
+
+``P4Options``
+ Command-line options to the ``P4Command`` for all invocations.
+
+ * `CTest Script`_ variable: :variable:`CTEST_P4_OPTIONS`
+ * :module:`CTest` module variable: ``CTEST_P4_OPTIONS``
+
+``P4UpdateCustom``
+ Specify a custom command line (as a semicolon-separated list) to run
+ in the source tree (Perforce tree) to update it instead of running
+ the ``P4Command``.
+
+ * `CTest Script`_ variable: none
+ * :module:`CTest` module variable: ``CTEST_P4_UPDATE_CUSTOM``
+
+``P4UpdateOptions``
+ Command-line options to the ``P4Command`` when updating the source.
+
+ * `CTest Script`_ variable: :variable:`CTEST_P4_UPDATE_OPTIONS`
+ * :module:`CTest` module variable: ``CTEST_P4_UPDATE_OPTIONS``
+
+``SVNCommand``
+ ``svn`` command-line tool to use if source tree is managed by Subversion.
+
+ * `CTest Script`_ variable: :variable:`CTEST_SVN_COMMAND`
+ * :module:`CTest` module variable: ``SVNCOMMAND``
+
+``SVNOptions``
+ Command-line options to the ``SVNCommand`` for all invocations.
+
+ * `CTest Script`_ variable: :variable:`CTEST_SVN_OPTIONS`
+ * :module:`CTest` module variable: ``CTEST_SVN_OPTIONS``
+
+``SVNUpdateOptions``
+ Command-line options to the ``SVNCommand`` when updating the source.
+
+ * `CTest Script`_ variable: :variable:`CTEST_SVN_UPDATE_OPTIONS`
+ * :module:`CTest` module variable: ``SVN_UPDATE_OPTIONS``
+
+``UpdateCommand``
+ Specify the version-control command-line tool to use without
+ detecting the VCS that manages the source tree.
+
+ * `CTest Script`_ variable: :variable:`CTEST_UPDATE_COMMAND`
+ * :module:`CTest` module variable: ``<VCS>COMMAND``
+ when ``UPDATE_TYPE`` is ``<vcs>``, else ``UPDATE_COMMAND``
+
+``UpdateOptions``
+ Command-line options to the ``UpdateCommand``.
+
+ * `CTest Script`_ variable: :variable:`CTEST_UPDATE_OPTIONS`
+ * :module:`CTest` module variable: ``<VCS>_UPDATE_OPTIONS``
+ when ``UPDATE_TYPE`` is ``<vcs>``, else ``UPDATE_OPTIONS``
+
+``UpdateType``
+ Specify the version-control system that manages the source
+ tree if it cannot be detected automatically.
+ The value may be ``bzr``, ``cvs``, ``git``, ``hg``,
+ ``p4``, or ``svn``.
+
+ * `CTest Script`_ variable: none, detected from source tree
+ * :module:`CTest` module variable: ``UPDATE_TYPE`` if set,
+ else ``CTEST_UPDATE_TYPE``
+
+.. _`UpdateVersionOnly`:
+
+``UpdateVersionOnly``
+ Specify that you want the version control update command to only
+ discover the current version that is checked out, and not to update
+ to a different version.
+
+ * `CTest Script`_ variable: :variable:`CTEST_UPDATE_VERSION_ONLY`
+
+.. _`UpdateVersionOverride`:
+
+``UpdateVersionOverride``
+ Specify the current version of your source tree.
+
+ When this variable is set to a non-empty string, CTest will report the value
+ you specified rather than using the update command to discover the current
+ version that is checked out. Use of this variable supersedes
+ ``UpdateVersionOnly``. Like ``UpdateVersionOnly``, using this variable tells
+ CTest not to update the source tree to a different version.
+
+ * `CTest Script`_ variable: :variable:`CTEST_UPDATE_VERSION_OVERRIDE`
+
+Additional configuration settings include:
+
+``NightlyStartTime``
+ In the ``Nightly`` dashboard mode, specify the "nightly start time".
+ With centralized version control systems (``cvs`` and ``svn``),
+ the ``Update`` step checks out the version of the software as of
+ this time so that multiple clients choose a common version to test.
+ This is not well-defined in distributed version-control systems so
+ the setting is ignored.
+
+ * `CTest Script`_ variable: :variable:`CTEST_NIGHTLY_START_TIME`
+ * :module:`CTest` module variable: ``NIGHTLY_START_TIME`` if set,
+ else ``CTEST_NIGHTLY_START_TIME``
+
+.. _`CTest Configure Step`:
+
+CTest Configure Step
+--------------------
+
+In a `CTest Script`_, the :command:`ctest_configure` command runs this step.
+Arguments to the command may specify some of the step settings.
+
+Configuration settings include:
+
+``ConfigureCommand``
+ Command-line to launch the software configuration process.
+ It will be executed in the location specified by the
+ ``BuildDirectory`` setting.
+
+ * `CTest Script`_ variable: :variable:`CTEST_CONFIGURE_COMMAND`
+ * :module:`CTest` module variable: :variable:`CMAKE_COMMAND`
+ followed by :variable:`PROJECT_SOURCE_DIR`
+
+``LabelsForSubprojects``
+ Specify a semicolon-separated list of labels that will be treated as
+ subprojects. This mapping will be passed on to CDash when configure, test or
+ build results are submitted.
+
+ * `CTest Script`_ variable: :variable:`CTEST_LABELS_FOR_SUBPROJECTS`
+ * :module:`CTest` module variable: ``CTEST_LABELS_FOR_SUBPROJECTS``
+
+ See `Label and Subproject Summary`_.
+
+.. _`CTest Build Step`:
+
+CTest Build Step
+----------------
+
+In a `CTest Script`_, the :command:`ctest_build` command runs this step.
+Arguments to the command may specify some of the step settings.
+
+Configuration settings include:
+
+``DefaultCTestConfigurationType``
+ When the build system to be launched allows build-time selection
+ of the configuration (e.g. ``Debug``, ``Release``), this specifies
+ the default configuration to be built when no ``-C`` option is
+ given to the ``ctest`` command. The value will be substituted into
+ the value of ``MakeCommand`` to replace the literal string
+ ``${CTEST_CONFIGURATION_TYPE}`` if it appears.
+
+ * `CTest Script`_ variable: :variable:`CTEST_CONFIGURATION_TYPE`
+ * :module:`CTest` module variable: ``DEFAULT_CTEST_CONFIGURATION_TYPE``,
+ initialized by the :envvar:`CMAKE_CONFIG_TYPE` environment variable
+
+``LabelsForSubprojects``
+ Specify a semicolon-separated list of labels that will be treated as
+ subprojects. This mapping will be passed on to CDash when configure, test or
+ build results are submitted.
+
+ * `CTest Script`_ variable: :variable:`CTEST_LABELS_FOR_SUBPROJECTS`
+ * :module:`CTest` module variable: ``CTEST_LABELS_FOR_SUBPROJECTS``
+
+ See `Label and Subproject Summary`_.
+
+``MakeCommand``
+ Command-line to launch the software build process.
+ It will be executed in the location specified by the
+ ``BuildDirectory`` setting.
+
+ * `CTest Script`_ variable: :variable:`CTEST_BUILD_COMMAND`
+ * :module:`CTest` module variable: ``MAKECOMMAND``,
+ initialized by the :command:`build_command` command
+
+``UseLaunchers``
+ For build trees generated by CMake using one of the
+ :ref:`Makefile Generators` or the :generator:`Ninja`
+ generator, specify whether the
+ ``CTEST_USE_LAUNCHERS`` feature is enabled by the
+ :module:`CTestUseLaunchers` module (also included by the
+ :module:`CTest` module). When enabled, the generated build
+ system wraps each invocation of the compiler, linker, or
+ custom command line with a "launcher" that communicates
+ with CTest via environment variables and files to report
+ granular build warning and error information. Otherwise,
+ CTest must "scrape" the build output log for diagnostics.
+
+ * `CTest Script`_ variable: :variable:`CTEST_USE_LAUNCHERS`
+ * :module:`CTest` module variable: ``CTEST_USE_LAUNCHERS``
+
+.. _`CTest Test Step`:
+
+CTest Test Step
+---------------
+
+In a `CTest Script`_, the :command:`ctest_test` command runs this step.
+Arguments to the command may specify some of the step settings.
+
+Configuration settings include:
+
+``ResourceSpecFile``
+ Specify a
+ :ref:`resource specification file <ctest-resource-specification-file>`.
+
+ * `CTest Script`_ variable: :variable:`CTEST_RESOURCE_SPEC_FILE`
+ * :module:`CTest` module variable: ``CTEST_RESOURCE_SPEC_FILE``
+
+ See :ref:`ctest-resource-allocation` for more information.
+
+``LabelsForSubprojects``
+ Specify a semicolon-separated list of labels that will be treated as
+ subprojects. This mapping will be passed on to CDash when configure, test or
+ build results are submitted.
+
+ * `CTest Script`_ variable: :variable:`CTEST_LABELS_FOR_SUBPROJECTS`
+ * :module:`CTest` module variable: ``CTEST_LABELS_FOR_SUBPROJECTS``
+
+ See `Label and Subproject Summary`_.
+
+``TestLoad``
+ While running tests in parallel (e.g. with ``-j``), try not to start
+ tests when they may cause the CPU load to pass above a given threshold.
+
+ * `CTest Script`_ variable: :variable:`CTEST_TEST_LOAD`
+ * :module:`CTest` module variable: ``CTEST_TEST_LOAD``
+
+``TimeOut``
+ The default timeout for each test if not specified by the
+ :prop_test:`TIMEOUT` test property.
+
+ * `CTest Script`_ variable: :variable:`CTEST_TEST_TIMEOUT`
+ * :module:`CTest` module variable: ``DART_TESTING_TIMEOUT``
+
+.. _`CTest Coverage Step`:
+
+CTest Coverage Step
+-------------------
+
+In a `CTest Script`_, the :command:`ctest_coverage` command runs this step.
+Arguments to the command may specify some of the step settings.
+
+Configuration settings include:
+
+``CoverageCommand``
+ Command-line tool to perform software coverage analysis.
+ It will be executed in the location specified by the
+ ``BuildDirectory`` setting.
+
+ * `CTest Script`_ variable: :variable:`CTEST_COVERAGE_COMMAND`
+ * :module:`CTest` module variable: ``COVERAGE_COMMAND``
+
+``CoverageExtraFlags``
+ Specify command-line options to the ``CoverageCommand`` tool.
+
+ * `CTest Script`_ variable: :variable:`CTEST_COVERAGE_EXTRA_FLAGS`
+ * :module:`CTest` module variable: ``COVERAGE_EXTRA_FLAGS``
+
+ These options are the first arguments passed to ``CoverageCommand``.
+
+.. _`CTest MemCheck Step`:
+
+CTest MemCheck Step
+-------------------
+
+In a `CTest Script`_, the :command:`ctest_memcheck` command runs this step.
+Arguments to the command may specify some of the step settings.
+
+Configuration settings include:
+
+``MemoryCheckCommand``
+ Command-line tool to perform dynamic analysis. Test command lines
+ will be launched through this tool.
+
+ * `CTest Script`_ variable: :variable:`CTEST_MEMORYCHECK_COMMAND`
+ * :module:`CTest` module variable: ``MEMORYCHECK_COMMAND``
+
+``MemoryCheckCommandOptions``
+ Specify command-line options to the ``MemoryCheckCommand`` tool.
+ They will be placed prior to the test command line.
+
+ * `CTest Script`_ variable: :variable:`CTEST_MEMORYCHECK_COMMAND_OPTIONS`
+ * :module:`CTest` module variable: ``MEMORYCHECK_COMMAND_OPTIONS``
+
+``MemoryCheckType``
+ Specify the type of memory checking to perform.
+
+ * `CTest Script`_ variable: :variable:`CTEST_MEMORYCHECK_TYPE`
+ * :module:`CTest` module variable: ``MEMORYCHECK_TYPE``
+
+``MemoryCheckSanitizerOptions``
+ Specify options to sanitizers when running with a sanitize-enabled build.
+
+ * `CTest Script`_ variable: :variable:`CTEST_MEMORYCHECK_SANITIZER_OPTIONS`
+ * :module:`CTest` module variable: ``MEMORYCHECK_SANITIZER_OPTIONS``
+
+``MemoryCheckSuppressionFile``
+ Specify a file containing suppression rules for the
+ ``MemoryCheckCommand`` tool. It will be passed with options
+ appropriate to the tool.
+
+ * `CTest Script`_ variable: :variable:`CTEST_MEMORYCHECK_SUPPRESSIONS_FILE`
+ * :module:`CTest` module variable: ``MEMORYCHECK_SUPPRESSIONS_FILE``
+
+Additional configuration settings include:
+
+``BoundsCheckerCommand``
+ Specify a ``MemoryCheckCommand`` that is known to be command-line
+ compatible with Bounds Checker.
+
+ * `CTest Script`_ variable: none
+ * :module:`CTest` module variable: none
+
+``PurifyCommand``
+ Specify a ``MemoryCheckCommand`` that is known to be command-line
+ compatible with Purify.
+
+ * `CTest Script`_ variable: none
+ * :module:`CTest` module variable: ``PURIFYCOMMAND``
+
+``ValgrindCommand``
+ Specify a ``MemoryCheckCommand`` that is known to be command-line
+ compatible with Valgrind.
+
+ * `CTest Script`_ variable: none
+ * :module:`CTest` module variable: ``VALGRIND_COMMAND``
+
+``ValgrindCommandOptions``
+ Specify command-line options to the ``ValgrindCommand`` tool.
+ They will be placed prior to the test command line.
+
+ * `CTest Script`_ variable: none
+ * :module:`CTest` module variable: ``VALGRIND_COMMAND_OPTIONS``
+
+``DrMemoryCommand``
+ Specify a ``MemoryCheckCommand`` that is known to be a command-line
+ compatible with DrMemory.
+
+ * `CTest Script`_ variable: none
+ * :module:`CTest` module variable: ``DRMEMORY_COMMAND``
+
+``DrMemoryCommandOptions``
+ Specify command-line options to the ``DrMemoryCommand`` tool.
+ They will be placed prior to the test command line.
+
+ * `CTest Script`_ variable: none
+ * :module:`CTest` module variable: ``DRMEMORY_COMMAND_OPTIONS``
+
+``CudaSanitizerCommand``
+ Specify a ``MemoryCheckCommand`` that is known to be a command-line
+ compatible with cuda-memcheck or compute-sanitizer.
+
+ * `CTest Script`_ variable: none
+ * :module:`CTest` module variable: ``CUDA_SANITIZER_COMMAND``
+
+``CudaSanitizerCommandOptions``
+ Specify command-line options to the ``CudaSanitizerCommand`` tool.
+ They will be placed prior to the test command line.
+
+ * `CTest Script`_ variable: none
+ * :module:`CTest` module variable: ``CUDA_SANITIZER_COMMAND_OPTIONS``
+
+.. _`CTest Submit Step`:
+
+CTest Submit Step
+-----------------
+
+In a `CTest Script`_, the :command:`ctest_submit` command runs this step.
+Arguments to the command may specify some of the step settings.
+
+Configuration settings include:
+
+``BuildName``
+ Describe the dashboard client platform with a short string.
+ (Operating system, compiler, etc.)
+
+ * `CTest Script`_ variable: :variable:`CTEST_BUILD_NAME`
+ * :module:`CTest` module variable: ``BUILDNAME``
+
+``CDashVersion``
+ Legacy option. Not used.
+
+ * `CTest Script`_ variable: none, detected from server
+ * :module:`CTest` module variable: ``CTEST_CDASH_VERSION``
+
+``CTestSubmitRetryCount``
+ Specify a number of attempts to retry submission on network failure.
+
+ * `CTest Script`_ variable: none,
+ use the :command:`ctest_submit` ``RETRY_COUNT`` option.
+ * :module:`CTest` module variable: ``CTEST_SUBMIT_RETRY_COUNT``
+
+``CTestSubmitRetryDelay``
+ Specify a delay before retrying submission on network failure.
+
+ * `CTest Script`_ variable: none,
+ use the :command:`ctest_submit` ``RETRY_DELAY`` option.
+ * :module:`CTest` module variable: ``CTEST_SUBMIT_RETRY_DELAY``
+
+``CurlOptions``
+ Specify a semicolon-separated list of options to control the
+ Curl library that CTest uses internally to connect to the
+ server. Possible options are ``CURLOPT_SSL_VERIFYPEER_OFF``
+ and ``CURLOPT_SSL_VERIFYHOST_OFF``.
+
+ * `CTest Script`_ variable: :variable:`CTEST_CURL_OPTIONS`
+ * :module:`CTest` module variable: ``CTEST_CURL_OPTIONS``
+
+``DropLocation``
+ Legacy option. When ``SubmitURL`` is not set, it is constructed from
+ ``DropMethod``, ``DropSiteUser``, ``DropSitePassword``, ``DropSite``, and
+ ``DropLocation``.
+
+ * `CTest Script`_ variable: :variable:`CTEST_DROP_LOCATION`
+ * :module:`CTest` module variable: ``DROP_LOCATION`` if set,
+ else ``CTEST_DROP_LOCATION``
+
+``DropMethod``
+ Legacy option. When ``SubmitURL`` is not set, it is constructed from
+ ``DropMethod``, ``DropSiteUser``, ``DropSitePassword``, ``DropSite``, and
+ ``DropLocation``.
+
+ * `CTest Script`_ variable: :variable:`CTEST_DROP_METHOD`
+ * :module:`CTest` module variable: ``DROP_METHOD`` if set,
+ else ``CTEST_DROP_METHOD``
+
+``DropSite``
+ Legacy option. When ``SubmitURL`` is not set, it is constructed from
+ ``DropMethod``, ``DropSiteUser``, ``DropSitePassword``, ``DropSite``, and
+ ``DropLocation``.
+
+ * `CTest Script`_ variable: :variable:`CTEST_DROP_SITE`
+ * :module:`CTest` module variable: ``DROP_SITE`` if set,
+ else ``CTEST_DROP_SITE``
+
+``DropSitePassword``
+ Legacy option. When ``SubmitURL`` is not set, it is constructed from
+ ``DropMethod``, ``DropSiteUser``, ``DropSitePassword``, ``DropSite``, and
+ ``DropLocation``.
+
+ * `CTest Script`_ variable: :variable:`CTEST_DROP_SITE_PASSWORD`
+ * :module:`CTest` module variable: ``DROP_SITE_PASSWORD`` if set,
+ else ``CTEST_DROP_SITE_PASWORD``
+
+``DropSiteUser``
+ Legacy option. When ``SubmitURL`` is not set, it is constructed from
+ ``DropMethod``, ``DropSiteUser``, ``DropSitePassword``, ``DropSite``, and
+ ``DropLocation``.
+
+ * `CTest Script`_ variable: :variable:`CTEST_DROP_SITE_USER`
+ * :module:`CTest` module variable: ``DROP_SITE_USER`` if set,
+ else ``CTEST_DROP_SITE_USER``
+
+``IsCDash``
+ Legacy option. Not used.
+
+ * `CTest Script`_ variable: :variable:`CTEST_DROP_SITE_CDASH`
+ * :module:`CTest` module variable: ``CTEST_DROP_SITE_CDASH``
+
+``ScpCommand``
+ Legacy option. Not used.
+
+ * `CTest Script`_ variable: :variable:`CTEST_SCP_COMMAND`
+ * :module:`CTest` module variable: ``SCPCOMMAND``
+
+``Site``
+ Describe the dashboard client host site with a short string.
+ (Hostname, domain, etc.)
+
+ * `CTest Script`_ variable: :variable:`CTEST_SITE`
+ * :module:`CTest` module variable: ``SITE``,
+ initialized by the :command:`site_name` command
+
+``SubmitURL``
+ The ``http`` or ``https`` URL of the dashboard server to send the submission
+ to.
+
+ * `CTest Script`_ variable: :variable:`CTEST_SUBMIT_URL`
+ * :module:`CTest` module variable: ``SUBMIT_URL`` if set,
+ else ``CTEST_SUBMIT_URL``
+
+``TriggerSite``
+ Legacy option. Not used.
+
+ * `CTest Script`_ variable: :variable:`CTEST_TRIGGER_SITE`
+ * :module:`CTest` module variable: ``TRIGGER_SITE`` if set,
+ else ``CTEST_TRIGGER_SITE``
+
+.. _`Show as JSON Object Model`:
+
+Show as JSON Object Model
+=========================
+
+When the ``--show-only=json-v1`` command line option is given, the test
+information is output in JSON format. Version 1.0 of the JSON object
+model is defined as follows:
+
+``kind``
+ The string "ctestInfo".
+
+``version``
+ A JSON object specifying the version components. Its members are
+
+ ``major``
+ A non-negative integer specifying the major version component.
+ ``minor``
+ A non-negative integer specifying the minor version component.
+
+``backtraceGraph``
+ JSON object representing backtrace information with the
+ following members:
+
+ ``commands``
+ List of command names.
+ ``files``
+ List of file names.
+ ``nodes``
+ List of node JSON objects with members:
+
+ ``command``
+ Index into the ``commands`` member of the ``backtraceGraph``.
+ ``file``
+ Index into the ``files`` member of the ``backtraceGraph``.
+ ``line``
+ Line number in the file where the backtrace was added.
+ ``parent``
+ Index into the ``nodes`` member of the ``backtraceGraph``
+ representing the parent in the graph.
+
+``tests``
+ A JSON array listing information about each test. Each entry
+ is a JSON object with members:
+
+ ``name``
+ Test name.
+ ``config``
+ Configuration that the test can run on.
+ Empty string means any config.
+ ``command``
+ List where the first element is the test command and the
+ remaining elements are the command arguments.
+ ``backtrace``
+ Index into the ``nodes`` member of the ``backtraceGraph``.
+ ``properties``
+ Test properties.
+ Can contain keys for each of the supported test properties.
+
+.. _`ctest-resource-allocation`:
+
+Resource Allocation
+===================
+
+CTest provides a mechanism for tests to specify the resources that they need
+in a fine-grained way, and for users to specify the resources available on
+the running machine. This allows CTest to internally keep track of which
+resources are in use and which are free, scheduling tests in a way that
+prevents them from trying to claim resources that are not available.
+
+When the resource allocation feature is used, CTest will not oversubscribe
+resources. For example, if a resource has 8 slots, CTest will not run tests
+that collectively use more than 8 slots at a time. This has the effect of
+limiting how many tests can run at any given time, even if a high ``-j``
+argument is used, if those tests all use some slots from the same resource.
+In addition, it means that a single test that uses more of a resource than is
+available on a machine will not run at all (and will be reported as
+``Not Run``).
+
+A common use case for this feature is for tests that require the use of a GPU.
+Multiple tests can simultaneously allocate memory from a GPU, but if too many
+tests try to do this at once, some of them will fail to allocate, resulting in
+a failed test, even though the test would have succeeded if it had the memory
+it needed. By using the resource allocation feature, each test can specify how
+much memory it requires from a GPU, allowing CTest to schedule tests in a way
+that running several of these tests at once does not exhaust the GPU's memory
+pool.
+
+Please note that CTest has no concept of what a GPU is or how much memory it
+has, nor does it have any way of communicating with a GPU to retrieve this
+information or perform any memory management. CTest simply keeps track of a
+list of abstract resource types, each of which has a certain number of slots
+available for tests to use. Each test specifies the number of slots that it
+requires from a certain resource, and CTest then schedules them in a way that
+prevents the total number of slots in use from exceeding the listed capacity.
+When a test is executed, and slots from a resource are allocated to that test,
+tests may assume that they have exclusive use of those slots for the duration
+of the test's process.
+
+The CTest resource allocation feature consists of two inputs:
+
+* The :ref:`resource specification file <ctest-resource-specification-file>`,
+ described below, which describes the resources available on the system.
+* The :prop_test:`RESOURCE_GROUPS` property of tests, which describes the
+ resources required by the test.
+
+When CTest runs a test, the resources allocated to that test are passed in the
+form of a set of
+:ref:`environment variables <ctest-resource-environment-variables>` as
+described below. Using this information to decide which resource to connect to
+is left to the test writer.
+
+The ``RESOURCE_GROUPS`` property tells CTest what resources a test expects
+to use grouped in a way meaningful to the test. The test itself must read
+the :ref:`environment variables <ctest-resource-environment-variables>` to
+determine which resources have been allocated to each group. For example,
+each group may correspond to a process the test will spawn when executed.
+
+Note that even if a test specifies a ``RESOURCE_GROUPS`` property, it is still
+possible for that to test to run without any resource allocation (and without
+the corresponding
+:ref:`environment variables <ctest-resource-environment-variables>`)
+if the user does not pass a resource specification file. Passing this file,
+either through the ``--resource-spec-file`` command-line argument or the
+``RESOURCE_SPEC_FILE`` argument to :command:`ctest_test`, is what activates the
+resource allocation feature. Tests should check the
+``CTEST_RESOURCE_GROUP_COUNT`` environment variable to find out whether or not
+resource allocation is activated. This variable will always (and only) be
+defined if resource allocation is activated. If resource allocation is not
+activated, then the ``CTEST_RESOURCE_GROUP_COUNT`` variable will not exist,
+even if it exists for the parent ``ctest`` process. If a test absolutely must
+have resource allocation, then it can return a failing exit code or use the
+:prop_test:`SKIP_RETURN_CODE` or :prop_test:`SKIP_REGULAR_EXPRESSION`
+properties to indicate a skipped test.
+
+.. _`ctest-resource-specification-file`:
+
+Resource Specification File
+---------------------------
+
+The resource specification file is a JSON file which is passed to CTest, either
+on the :manual:`ctest(1)` command line as ``--resource-spec-file``, or as the
+``RESOURCE_SPEC_FILE`` argument of :command:`ctest_test`. If a dashboard script
+is used and ``RESOURCE_SPEC_FILE`` is not specified, the value of
+:variable:`CTEST_RESOURCE_SPEC_FILE` in the dashboard script is used instead.
+If ``--resource-spec-file``, ``RESOURCE_SPEC_FILE``, and
+:variable:`CTEST_RESOURCE_SPEC_FILE` in the dashboard script are not specified,
+the value of :variable:`CTEST_RESOURCE_SPEC_FILE` in the CMake build is used
+instead. If none of these are specified, no resource spec file is used.
+
+The resource specification file must be a JSON object. All examples in this
+document assume the following resource specification file:
+
+.. code-block:: json
+
+ {
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ {
+ "gpus": [
+ {
+ "id": "0",
+ "slots": 2
+ },
+ {
+ "id": "1",
+ "slots": 4
+ },
+ {
+ "id": "2",
+ "slots": 2
+ },
+ {
+ "id": "3"
+ }
+ ],
+ "crypto_chips": [
+ {
+ "id": "card0",
+ "slots": 4
+ }
+ ]
+ }
+ ]
+ }
+
+The members are:
+
+``version``
+ An object containing a ``major`` integer field and a ``minor`` integer field.
+ Currently, the only supported version is major ``1``, minor ``0``. Any other
+ value is an error.
+
+``local``
+ A JSON array of resource sets present on the system. Currently, this array
+ is restricted to being of size 1.
+
+ Each array element is a JSON object with members whose names are equal to the
+ desired resource types, such as ``gpus``. These names must start with a
+ lowercase letter or an underscore, and subsequent characters can be a
+ lowercase letter, a digit, or an underscore. Uppercase letters are not
+ allowed, because certain platforms have case-insensitive environment
+ variables. See the `Environment Variables`_ section below for
+ more information. It is recommended that the resource type name be the plural
+ of a noun, such as ``gpus`` or ``crypto_chips`` (and not ``gpu`` or
+ ``crypto_chip``.)
+
+ Please note that the names ``gpus`` and ``crypto_chips`` are just examples,
+ and CTest does not interpret them in any way. You are free to make up any
+ resource type you want to meet your own requirements.
+
+ The value for each resource type is a JSON array consisting of JSON objects,
+ each of which describe a specific instance of the specified resource. These
+ objects have the following members:
+
+ ``id``
+ A string consisting of an identifier for the resource. Each character in
+ the identifier can be a lowercase letter, a digit, or an underscore.
+ Uppercase letters are not allowed.
+
+ Identifiers must be unique within a resource type. However, they do not
+ have to be unique across resource types. For example, it is valid to have a
+ ``gpus`` resource named ``0`` and a ``crypto_chips`` resource named ``0``,
+ but not two ``gpus`` resources both named ``0``.
+
+ Please note that the IDs ``0``, ``1``, ``2``, ``3``, and ``card0`` are just
+ examples, and CTest does not interpret them in any way. You are free to
+ make up any IDs you want to meet your own requirements.
+
+ ``slots``
+ An optional unsigned number specifying the number of slots available on the
+ resource. For example, this could be megabytes of RAM on a GPU, or
+ cryptography units available on a cryptography chip. If ``slots`` is not
+ specified, a default value of ``1`` is assumed.
+
+In the example file above, there are four GPUs with ID's 0 through 3. GPU 0 has
+2 slots, GPU 1 has 4, GPU 2 has 2, and GPU 3 has a default of 1 slot. There is
+also one cryptography chip with 4 slots.
+
+``RESOURCE_GROUPS`` Property
+----------------------------
+
+See :prop_test:`RESOURCE_GROUPS` for a description of this property.
+
+.. _`ctest-resource-environment-variables`:
+
+Environment Variables
+---------------------
+
+Once CTest has decided which resources to allocate to a test, it passes this
+information to the test executable as a series of environment variables. For
+each example below, we will assume that the test in question has a
+:prop_test:`RESOURCE_GROUPS` property of
+``2,gpus:2;gpus:4,gpus:1,crypto_chips:2``.
+
+The following variables are passed to the test process:
+
+.. envvar:: CTEST_RESOURCE_GROUP_COUNT
+
+ The total number of groups specified by the :prop_test:`RESOURCE_GROUPS`
+ property. For example:
+
+ * ``CTEST_RESOURCE_GROUP_COUNT=3``
+
+ This variable will only be defined if :manual:`ctest(1)` has been given a
+ ``--resource-spec-file``, or if :command:`ctest_test` has been given a
+ ``RESOURCE_SPEC_FILE``. If no resource specification file has been given,
+ this variable will not be defined.
+
+.. envvar:: CTEST_RESOURCE_GROUP_<num>
+
+ The list of resource types allocated to each group, with each item
+ separated by a comma. ``<num>`` is a number from zero to
+ ``CTEST_RESOURCE_GROUP_COUNT`` minus one. ``CTEST_RESOURCE_GROUP_<num>``
+ is defined for each ``<num>`` in this range. For example:
+
+ * ``CTEST_RESOURCE_GROUP_0=gpus``
+ * ``CTEST_RESOURCE_GROUP_1=gpus``
+ * ``CTEST_RESOURCE_GROUP_2=crypto_chips,gpus``
+
+.. envvar:: CTEST_RESOURCE_GROUP_<num>_<resource-type>
+
+ The list of resource IDs and number of slots from each ID allocated to each
+ group for a given resource type. This variable consists of a series of
+ pairs, each pair separated by a semicolon, and with the two items in the pair
+ separated by a comma. The first item in each pair is ``id:`` followed by the
+ ID of a resource of type ``<resource-type>``, and the second item is
+ ``slots:`` followed by the number of slots from that resource allocated to
+ the given group. For example:
+
+ * ``CTEST_RESOURCE_GROUP_0_GPUS=id:0,slots:2``
+ * ``CTEST_RESOURCE_GROUP_1_GPUS=id:2,slots:2``
+ * ``CTEST_RESOURCE_GROUP_2_GPUS=id:1,slots:4;id:3,slots:1``
+ * ``CTEST_RESOURCE_GROUP_2_CRYPTO_CHIPS=id:card0,slots:2``
+
+ In this example, group 0 gets 2 slots from GPU ``0``, group 1 gets 2 slots
+ from GPU ``2``, and group 2 gets 4 slots from GPU ``1``, 1 slot from GPU
+ ``3``, and 2 slots from cryptography chip ``card0``.
+
+ ``<num>`` is a number from zero to ``CTEST_RESOURCE_GROUP_COUNT`` minus one.
+ ``<resource-type>`` is the name of a resource type, converted to uppercase.
+ ``CTEST_RESOURCE_GROUP_<num>_<resource-type>`` is defined for the product
+ of each ``<num>`` in the range listed above and each resource type listed in
+ ``CTEST_RESOURCE_GROUP_<num>``.
+
+ Because some platforms have case-insensitive names for environment variables,
+ the names of resource types may not clash in a case-insensitive environment.
+ Because of this, for the sake of simplicity, all resource types must be
+ listed in all lowercase in the
+ :ref:`resource specification file <ctest-resource-specification-file>` and
+ in the :prop_test:`RESOURCE_GROUPS` property, and they are converted to all
+ uppercase in the ``CTEST_RESOURCE_GROUP_<num>_<resource-type>`` environment
+ variable.
+
+See Also
+========
+
+.. include:: LINKS.txt
+
+.. _`CDash`: http://cdash.org/
diff --git a/Help/manual/presets/example.json b/Help/manual/presets/example.json
new file mode 100644
index 0000000..346f342
--- /dev/null
+++ b/Help/manual/presets/example.json
@@ -0,0 +1,70 @@
+{
+ "version": 3,
+ "cmakeMinimumRequired": {
+ "major": 3,
+ "minor": 20,
+ "patch": 0
+ },
+ "configurePresets": [
+ {
+ "name": "default",
+ "displayName": "Default Config",
+ "description": "Default build using Ninja generator",
+ "generator": "Ninja",
+ "binaryDir": "${sourceDir}/build/default",
+ "cacheVariables": {
+ "FIRST_CACHE_VARIABLE": {
+ "type": "BOOL",
+ "value": "OFF"
+ },
+ "SECOND_CACHE_VARIABLE": "ON"
+ },
+ "environment": {
+ "MY_ENVIRONMENT_VARIABLE": "Test",
+ "PATH": "$env{HOME}/ninja/bin:$penv{PATH}"
+ },
+ "vendor": {
+ "example.com/ExampleIDE/1.0": {
+ "autoFormat": true
+ }
+ }
+ },
+ {
+ "name": "ninja-multi",
+ "inherits": "default",
+ "displayName": "Ninja Multi-Config",
+ "description": "Default build using Ninja Multi-Config generator",
+ "generator": "Ninja Multi-Config"
+ },
+ {
+ "name": "windows-only",
+ "inherits": "default",
+ "displayName": "Windows-only configuration",
+ "description": "This build is only available on Windows",
+ "condition": {
+ "type": "equals",
+ "lhs": "${hostSystemName}",
+ "rhs": "Windows"
+ }
+ }
+ ],
+ "buildPresets": [
+ {
+ "name": "default",
+ "configurePreset": "default"
+ }
+ ],
+ "testPresets": [
+ {
+ "name": "default",
+ "configurePreset": "default",
+ "output": {"outputOnFailure": true},
+ "execution": {"noTestsAction": "error", "stopOnFailure": true}
+ }
+ ],
+ "vendor": {
+ "example.com/ExampleIDE/1.0": {
+ "autoFormat": false
+ }
+ }
+}
diff --git a/Help/manual/presets/schema.json b/Help/manual/presets/schema.json
new file mode 100644
index 0000000..e066362
--- /dev/null
+++ b/Help/manual/presets/schema.json
@@ -0,0 +1,1235 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "description": "The presets specify the generator and the build directory, and optionally a list of variables and other arguments to pass to CMake.",
+ "oneOf": [
+ {
+ "properties": {
+ "version": {
+ "const": 1,
+ "description": "A required integer representing the version of the JSON schema."
+ },
+ "cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
+ "vendor": { "$ref": "#/definitions/vendor" },
+ "configurePresets": { "$ref": "#/definitions/configurePresetsV1"}
+ },
+ "additionalProperties": false
+ },
+ {
+ "properties": {
+ "version": {
+ "const": 2,
+ "description": "A required integer representing the version of the JSON schema."
+ },
+ "cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
+ "vendor": { "$ref": "#/definitions/vendor" },
+ "configurePresets": { "$ref": "#/definitions/configurePresetsV1"},
+ "buildPresets": { "$ref": "#/definitions/buildPresetsV2"},
+ "testPresets": { "$ref": "#/definitions/testPresetsV2"}
+ },
+ "additionalProperties": false
+ },
+ {
+ "properties": {
+ "version": {
+ "const": 3,
+ "description": "A required integer representing the version of the JSON schema."
+ },
+ "cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
+ "vendor": { "$ref": "#/definitions/vendor" },
+ "configurePresets": { "$ref": "#/definitions/configurePresetsV3"},
+ "buildPresets": { "$ref": "#/definitions/buildPresetsV3"},
+ "testPresets": { "$ref": "#/definitions/testPresetsV3"}
+ },
+ "additionalProperties": false
+ }
+ ],
+ "required": [
+ "version"
+ ],
+ "definitions": {
+ "cmakeMinimumRequired": {
+ "type": "object",
+ "description": "An optional object representing the minimum version of CMake needed to build this project.",
+ "properties": {
+ "major": {
+ "type": "integer",
+ "description": "An optional integer representing the major version."
+ },
+ "minor": {
+ "type": "integer",
+ "description": "An optional integer representing the minor version."
+ },
+ "patch": {
+ "type": "integer",
+ "description": "An optional integer representing the patch version."
+ }
+ },
+ "additionalProperties": false
+ },
+ "vendor": {
+ "type": "object",
+ "description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, the keys should be a vendor-specific domain name followed by a /-separated path. For example, the Example IDE 1.0 could use example.com/ExampleIDE/1.0. The value of each field can be anything desired by the vendor, though will typically be a map.",
+ "properties": {}
+ },
+ "configurePresetsItemsV3": {
+ "type": "array",
+ "description": "A configure preset object.",
+ "items": {
+ "type": "object",
+ "description": "A configure preset object.",
+ "properties": {
+ "binaryDir": {
+ "type": "string",
+ "description": "An optional string representing the path to the output binary directory. This field supports macro expansion. If a relative path is specified, it is calculated relative to the source directory. If binaryDir is not specified, the path is calculated using regular methods."
+ },
+ "generator": {
+ "type": "string",
+ "description": "An optional string representing the generator to use for the preset. If generator is not specified, the normal generator discovery procedure is used. Note that for Visual Studio generators, unlike in the command line -G argument, you cannot include the platform name in the generator name. Use the architecture field instead."
+ },
+ "installDir": {
+ "type": "string",
+ "description": "An optional string representing the path to the output binary directory. This field supports macro expansion. If a relative path is specified, it is calculated relative to the source directory. If binaryDir is not specified, it must be inherited from the inherits preset (unless this preset is hidden)."
+ },
+ "condition": { "$ref": "#/definitions/topCondition" }
+ }
+ }
+ },
+ "configurePresetsItemsV1": {
+ "type": "array",
+ "description": "An optional array of configure preset objects.",
+ "items": {
+ "type": "object",
+ "description": "A configure preset object.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
+ "minLength": 1
+ },
+ "hidden": {
+ "type": "boolean",
+ "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset= argument, will not show up in the CMake GUI, and does not have to have a valid generator or binaryDir, even from inheritance. Hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
+ },
+ "inherits": {
+ "anyOf": [
+ {
+ "type": "string",
+ "description": "An optional string representing the name of the preset to inherit from.",
+ "minLength": 1
+ },
+ {
+ "type": "array",
+ "description": "An optional array of strings representing the names of presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json may not inherit from presets in CMakeUserPresets.json.",
+ "items": {
+ "type": "string",
+ "description": "An optional string representing the name of the preset to inherit from.",
+ "minLength": 1
+ }
+ }
+ ]
+ },
+ "vendor": {
+ "type": "object",
+ "description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, it should follow the same conventions as the root-level vendor field. If vendors use their own per-preset vendor field, they should implement inheritance in a sensible manner when appropriate.",
+ "properties": {}
+ },
+ "displayName": {
+ "type": "string",
+ "description": "An optional string with a human-friendly name of the preset."
+ },
+ "description": {
+ "type": "string",
+ "description": "An optional string with a human-friendly description of the preset."
+ },
+ "generator": {
+ "type": "string",
+ "description": "An optional string representing the generator to use for the preset. If generator is not specified, it must be inherited from the inherits preset (unless this preset is hidden). Note that for Visual Studio generators, unlike in the command line -G argument, you cannot include the platform name in the generator name. Use the architecture field instead."
+ },
+ "architecture": {
+ "anyOf": [
+ {
+ "type": "string",
+ "description": "An optional string representing the platform for generators that support it."
+ },
+ {
+ "type": "object",
+ "description": "An optional object representing the platform for generators that support it.",
+ "properties": {
+ "value": {
+ "type": "string",
+ "description": "An optional string representing the value."
+ },
+ "strategy": {
+ "type": "string",
+ "description": "An optional string telling CMake how to handle the field. Valid values are: \"set\" Set the respective value. This will result in an error for generators that do not support the respective field. \"external\" Do not set the value, even if the generator supports it. This is useful if, for example, a preset uses the Ninja generator, and an IDE knows how to set up the Visual C++ environment from the architecture and toolset fields. In that case, CMake will ignore the field, but the IDE can use them to set up the environment before invoking CMake.",
+ "enum": [
+ "set",
+ "external"
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ ]
+ },
+ "toolset": {
+ "anyOf": [
+ {
+ "type": "string",
+ "description": "An optional string representing the toolset for generators that support it."
+ },
+ {
+ "type": "object",
+ "description": "An optional object representing the toolset for generators that support it.",
+ "properties": {
+ "value": {
+ "type": "string",
+ "description": "An optional string representing the value."
+ },
+ "strategy": {
+ "type": "string",
+ "description": "An optional string telling CMake how to handle the field. Valid values are: \"set\" Set the respective value. This will result in an error for generators that do not support the respective field. \"external\" Do not set the value, even if the generator supports it. This is useful if, for example, a preset uses the Ninja generator, and an IDE knows how to set up the Visual C++ environment from the architecture and toolset fields. In that case, CMake will ignore the field, but the IDE can use them to set up the environment before invoking CMake.",
+ "enum": [
+ "set",
+ "external"
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ ]
+ },
+ "binaryDir": {
+ "type": "string",
+ "description": "An optional string representing the path to the output binary directory. This field supports macro expansion. If a relative path is specified, it is calculated relative to the source directory. If binaryDir is not specified, it must be inherited from the inherits preset (unless this preset is hidden)."
+ },
+ "cmakeExecutable": {
+ "type": "string",
+ "description": "An optional string representing the path to the CMake executable to use for this preset. This is reserved for use by IDEs, and is not used by CMake itself. IDEs that use this field should expand any macros in it."
+ },
+ "cacheVariables": {
+ "type": "object",
+ "description": "An optional map of cache variables. The key is the variable name (which must not be an empty string). Cache variables are inherited through the inherits field, and the preset's variables will be the union of its own cacheVariables and the cacheVariables from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied.",
+ "properties": {},
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "type": "null",
+ "description": "Setting a variable to null causes it to not be set, even if a value was inherited from another preset."
+ },
+ {
+ "type": "boolean",
+ "description": "A boolean representing the value of the variable. Equivalent to \"TRUE\" or \"FALSE\"."
+ },
+ {
+ "type": "string",
+ "description": "A string representing the value of the variable (which supports macro expansion)."
+ },
+ {
+ "type": "object",
+ "description": "An object representing the type and value of the variable.",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "An optional string representing the type of the variable. It should be BOOL, FILEPATH, PATH, STRING, or INTERNAL."
+ },
+ "value": {
+ "anyOf": [
+ {
+ "type": "boolean",
+ "description": "A required boolean representing the value of the variable. Equivalent to \"TRUE\" or \"FALSE\"."
+ },
+ {
+ "type": "string",
+ "description": "A required string representing the value of the variable. This field supports macro expansion."
+ }
+ ]
+ }
+ },
+ "required": [
+ "value"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ },
+ "propertyNames": {
+ "pattern": "^.+$"
+ }
+ },
+ "environment": {
+ "type": "object",
+ "description": "An optional map of environment variables. The key is the variable name (which must not be an empty string). Each variable is set regardless of whether or not a value was given to it by the process's environment. This field supports macro expansion, and environment variables in this map may reference each other, and may be listed in any order, as long as such references do not cause a cycle (for example,if ENV_1 is $env{ENV_2}, ENV_2 may not be $env{ENV_1}.) Environment variables are inherited through the inherits field, and the preset's environment will be the union of its own environment and the environment from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied. Setting a variable to null causes it to not be set, even if a value was inherited from another preset.",
+ "properties": {},
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "type": "null",
+ "description": "Setting a variable to null causes it to not be set, even if a value was inherited from another preset."
+ },
+ {
+ "type": "string",
+ "description": "A string representing the value of the variable."
+ }
+ ]
+ },
+ "propertyNames": {
+ "pattern": "^.+$"
+ }
+ },
+ "warnings": {
+ "type": "object",
+ "description": "An optional object specifying warnings.",
+ "properties": {
+ "dev": {
+ "type": "boolean",
+ "description": "An optional boolean. Equivalent to passing -Wdev or -Wno-dev on the command line. This may not be set to false if errors.dev is set to true."
+ },
+ "deprecated": {
+ "type": "boolean",
+ "description": "An optional boolean. Equivalent to passing -Wdeprecated or -Wno-deprecated on the command line. This may not be set to false if errors.deprecated is set to true."
+ },
+ "uninitialized": {
+ "type": "boolean",
+ "description": "An optional boolean. Setting this to true is equivalent to passing --warn-uninitialized on the command line."
+ },
+ "unusedCli": {
+ "type": "boolean",
+ "description": "An optional boolean. Setting this to false is equivalent to passing --no-warn-unused-cli on the command line."
+ },
+ "systemVars": {
+ "type": "boolean",
+ "description": "An optional boolean. Setting this to true is equivalent to passing --check-system-vars on the command line."
+ }
+ },
+ "additionalProperties": false
+ },
+ "errors": {
+ "type": "object",
+ "description": "An optional object specifying errors.",
+ "properties": {
+ "dev": {
+ "type": "boolean",
+ "description": "An optional boolean. Equivalent to passing -Werror=dev or -Wno-error=dev on the command line. This may not be set to true if warnings.dev is set to false."
+ },
+ "deprecated": {
+ "type": "boolean",
+ "description": "An optional boolean. Equivalent to passing -Werror=deprecated or -Wno-error=deprecated on the command line. This may not be set to true if warnings.deprecated is set to false."
+ }
+ },
+ "additionalProperties": false
+ },
+ "debug": {
+ "type": "object",
+ "description": "An optional object specifying debug options.",
+ "properties": {
+ "output": {
+ "type": "boolean",
+ "description": "An optional boolean. Setting this to true is equivalent to passing --debug-output on the command line."
+ },
+ "tryCompile": {
+ "type": "boolean",
+ "description": "An optional boolean. Setting this to true is equivalent to passing --debug-trycompile on the command line."
+ },
+ "find": {
+ "type": "boolean",
+ "description": "An optional boolean. Setting this to true is equivalent to passing --debug-find on the command line."
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "configurePresetsV3": {
+ "type": "array",
+ "description": "An optional array of configure preset objects.",
+ "allOf": [
+ { "$ref": "#/definitions/configurePresetsItemsV1" },
+ { "$ref": "#/definitions/configurePresetsItemsV3" }
+ ],
+ "items": {
+ "properties": {
+ "name": {},
+ "hidden": {},
+ "inherits": {},
+ "vendor": {},
+ "displayName": {},
+ "description": {},
+ "generator": {},
+ "architecture": {},
+ "toolset": {},
+ "binaryDir": {},
+ "installDir": {},
+ "cmakeExecutable": {},
+ "cacheVariables": {},
+ "environment": {},
+ "warnings": {},
+ "errors": {},
+ "debug": {},
+ "condition": {}
+ },
+ "required": [
+ "name"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "configurePresetsV1": {
+ "type": "array",
+ "description": "An optional array of configure preset objects.",
+ "allOf": [
+ { "$ref": "#/definitions/configurePresetsItemsV1" }
+ ],
+ "items": {
+ "properties": {
+ "name": {},
+ "hidden": {},
+ "inherits": {},
+ "vendor": {},
+ "displayName": {},
+ "description": {},
+ "generator": {},
+ "architecture": {},
+ "toolset": {},
+ "binaryDir": {},
+ "cmakeExecutable": {},
+ "cacheVariables": {},
+ "environment": {},
+ "warnings": {},
+ "errors": {},
+ "debug": {}
+ },
+ "required": [
+ "name"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "buildPresetsItemsV3": {
+ "type": "array",
+ "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
+ "items": {
+ "type": "object",
+ "properties": {
+ "condition": { "$ref": "#/definitions/topCondition" }
+ }
+ }
+ },
+ "buildPresetsItemsV2": {
+ "type": "array",
+ "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, or test) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
+ "minLength": 1
+ },
+ "hidden": {
+ "type": "boolean",
+ "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset argument, will not show up in the CMake GUI, and does not have to have a valid configurePreset, even from inheritance. Hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
+ },
+ "inherits": {
+ "anyOf": [
+ {
+ "type": "string",
+ "description": "An optional string representing the name of the build preset to inherit from.",
+ "minLength": 1
+ },
+ {
+ "type": "array",
+ "description": "An optional array of strings representing the names of build presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json may not inherit from presets in CMakeUserPresets.json.",
+ "items": {
+ "type": "string",
+ "description": "An optional string representing the name of the preset to inherit from.",
+ "minLength": 1
+ }
+ }
+ ]
+ },
+ "configurePreset": {
+ "type": "string",
+ "description": "An optional string specifying the name of a configure preset to associate with this build preset. If configurePreset is not specified, it must be inherited from the inherits preset (unless this preset is hidden). The build tree directory is inferred from the configure preset.",
+ "minLength": 1
+ },
+ "vendor": {
+ "type": "object",
+ "description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, it should follow the same conventions as the root-level vendor field. If vendors use their own per-preset vendor field, they should implement inheritance in a sensible manner when appropriate.",
+ "properties": {}
+ },
+ "displayName": {
+ "type": "string",
+ "description": "An optional string with a human-friendly name of the preset."
+ },
+ "description": {
+ "type": "string",
+ "description": "An optional string with a human-friendly description of the preset."
+ },
+ "inheritConfigureEnvironment": {
+ "type": "boolean",
+ "description": "An optional boolean that defaults to true. If true, the environment variables from the associated configure preset are inherited after all inherited build preset environments, but before environment variables explicitly specified in this build preset."
+ },
+ "environment": {
+ "type": "object",
+ "description": "An optional map of environment variables. The key is the variable name (which must not be an empty string). Each variable is set regardless of whether or not a value was given to it by the process's environment. This field supports macro expansion, and environment variables in this map may reference each other, and may be listed in any order, as long as such references do not cause a cycle (for example,if ENV_1 is $env{ENV_2}, ENV_2 may not be $env{ENV_1}.) Environment variables are inherited through the inherits field, and the preset's environment will be the union of its own environment and the environment from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied. Setting a variable to null causes it to not be set, even if a value was inherited from another preset.",
+ "properties": {},
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "type": "null",
+ "description": "Setting a variable to null causes it to not be set, even if a value was inherited from another preset."
+ },
+ {
+ "type": "string",
+ "description": "A string representing the value of the variable."
+ }
+ ]
+ },
+ "propertyNames": {
+ "pattern": "^.+$"
+ }
+ },
+ "jobs": {
+ "type": "integer",
+ "description": "An optional integer. Equivalent to passing --parallel or -j on the command line."
+ },
+ "targets": {
+ "anyOf": [
+ {
+ "type": "string",
+ "description": "An optional string. Equivalent to passing --target or -t on the command line. Vendors may ignore the targets property or hide build presets that explicitly specify targets."
+ },
+ {
+ "type": "array",
+ "description": "An optional array of strings. Equivalent to passing --target or -t on the command line. Vendors may ignore the targets property or hide build presets that explicitly specify targets.",
+ "items": {
+ "type": "string",
+ "description": "An optional string. Equivalent to passing --target or -t on the command line. Vendors may ignore the targets property or hide build presets that explicitly specify targets."
+ }
+ }
+ ]
+ },
+ "configuration": {
+ "type": "string",
+ "description": "An optional string. Equivalent to passing --config on the command line."
+ },
+ "cleanFirst": {
+ "type": "boolean",
+ "description": "An optional boolean. If true, equivalent to passing --clean-first on the command line."
+ },
+ "verbose": {
+ "type": "boolean",
+ "description": "An optional boolean. If true, equivalent to passing --verbose on the command line."
+ },
+ "nativeToolOptions": {
+ "type": "array",
+ "description": "An optional array of strings. Equivalent to passing options after -- on the command line.",
+ "items": {
+ "type": "string",
+ "description": "An optional string representing an option to pass after -- on the command line."
+ }
+ }
+ },
+ "required": [
+ "name"
+ ]
+ }
+ },
+ "buildPresetsV3": {
+ "type": "array",
+ "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
+ "allOf": [
+ { "$ref": "#/definitions/buildPresetsItemsV3" },
+ { "$ref": "#/definitions/buildPresetsItemsV2" }
+ ],
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {},
+ "hidden": {},
+ "inherits": {},
+ "configurePreset": {},
+ "vendor": {},
+ "displayName": {},
+ "description": {},
+ "inheritConfigureEnvironment": {},
+ "environment": {},
+ "jobs": {},
+ "targets": {},
+ "configuration": {},
+ "cleanFirst": {},
+ "verbose": {},
+ "nativeToolOptions": {},
+ "condition": {}
+ },
+ "required": [
+ "name"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "buildPresetsV2": {
+ "type": "array",
+ "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
+ "allOf": [
+ { "$ref": "#/definitions/buildPresetsItemsV2" }
+ ],
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {},
+ "hidden": {},
+ "inherits": {},
+ "configurePreset": {},
+ "vendor": {},
+ "displayName": {},
+ "description": {},
+ "inheritConfigureEnvironment": {},
+ "environment": {},
+ "jobs": {},
+ "targets": {},
+ "configuration": {},
+ "cleanFirst": {},
+ "verbose": {},
+ "nativeToolOptions": {}
+ },
+ "required": [
+ "name"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "testPresetsItemsV3": {
+ "type": "array",
+ "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
+ "items": {
+ "type": "object",
+ "properties": {
+ "condition": { "$ref": "#/definitions/topCondition" }
+ }
+ }
+ },
+ "testPresetsItemsV2": {
+ "type": "array",
+ "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, or test) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
+ "minLength": 1
+ },
+ "hidden": {
+ "type": "boolean",
+ "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset argument, will not show up in the CMake GUI, and does not have to have a valid configurePreset, even from inheritance. Hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
+ },
+ "inherits": {
+ "anyOf": [
+ {
+ "type": "string",
+ "description": "An optional string representing the name of the test preset to inherit from.",
+ "minLength": 1
+ },
+ {
+ "type": "array",
+ "description": "An optional array of strings representing the names of test presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json may not inherit from presets in CMakeUserPresets.json.",
+ "items": {
+ "type": "string",
+ "description": "An optional string representing the name of the preset to inherit from.",
+ "minLength": 1
+ }
+ }
+ ]
+ },
+ "configurePreset": {
+ "type": "string",
+ "description": "An optional string specifying the name of a configure preset to associate with this test preset. If configurePreset is not specified, it must be inherited from the inherits preset (unless this preset is hidden). The build tree directory is inferred from the configure preset.",
+ "minLength": 1
+ },
+ "vendor": {
+ "type": "object",
+ "description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, it should follow the same conventions as the root-level vendor field. If vendors use their own per-preset vendor field, they should implement inheritance in a sensible manner when appropriate.",
+ "properties": {}
+ },
+ "displayName": {
+ "type": "string",
+ "description": "An optional string with a human-friendly name of the preset."
+ },
+ "description": {
+ "type": "string",
+ "description": "An optional string with a human-friendly description of the preset."
+ },
+ "inheritConfigureEnvironment": {
+ "type": "boolean",
+ "description": "An optional boolean that defaults to true. If true, the environment variables from the associated configure preset are inherited after all inherited test preset environments, but before environment variables explicitly specified in this test preset."
+ },
+ "environment": {
+ "type": "object",
+ "description": "An optional map of environment variables. The key is the variable name (which must not be an empty string). Each variable is set regardless of whether or not a value was given to it by the process's environment. This field supports macro expansion, and environment variables in this map may reference each other, and may be listed in any order, as long as such references do not cause a cycle (for example,if ENV_1 is $env{ENV_2}, ENV_2 may not be $env{ENV_1}.) Environment variables are inherited through the inherits field, and the preset's environment will be the union of its own environment and the environment from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied. Setting a variable to null causes it to not be set, even if a value was inherited from another preset.",
+ "properties": {},
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "type": "null",
+ "description": "Setting a variable to null causes it to not be set, even if a value was inherited from another preset."
+ },
+ {
+ "type": "string",
+ "description": "A string representing the value of the variable."
+ }
+ ]
+ },
+ "propertyNames": {
+ "pattern": "^.+$"
+ }
+ },
+ "configuration": {
+ "type": "string",
+ "description": "An optional string. Equivalent to passing --build-config on the command line."
+ },
+ "overwriteConfigurationFile": {
+ "type": "array",
+ "description": "An optional array of configuration options to overwrite options specified in the CTest configuration file. Equivalent to passing ``--overwrite`` for each value in the array.",
+ "items": {
+ "type": "string",
+ "description": "An option written as a key-value pair in the form \"key=value\"."
+ }
+ },
+ "output": {
+ "type": "object",
+ "description": "An optional object specifying output options.",
+ "properties": {
+ "shortProgress": {
+ "type": "boolean",
+ "description": "An optional boolean. If true, equivalent to passing --progress on the command line."
+ },
+ "verbosity": {
+ "type": "string",
+ "description": "An optional string specifying verbosity level. Valid values are \"default\" (equivalent to passing no verbosity flags on the command line), \"verbose\" (equivalent to passing --verbose on the command line), and \"extra\" (equivalent to passing --extra-verbose on the command line).",
+ "enum": [
+ "default", "verbose", "extra"
+ ]
+ },
+ "debug": {
+ "type": "boolean",
+ "description": "An optional boolean. If true, equivalent to passing --debug on the command line."
+ },
+ "outputOnFailure": {
+ "type": "boolean",
+ "description": "An optional boolean. If true, equivalent to passing --output-on-failure on the command line."
+ },
+ "quiet": {
+ "type": "boolean",
+ "description": "An optional boolean. If true, equivalent to passing --quiet on the command line."
+ },
+ "outputLogFile": {
+ "type": "string",
+ "description": "An optional string specifying a path to a log file. Equivalent to passing --output-log on the command line."
+ },
+ "labelSummary": {
+ "type": "boolean",
+ "description": "An optional boolean. If false, equivalent to passing --no-label-summary on the command line."
+ },
+ "subprojectSummary": {
+ "type": "boolean",
+ "description": "An optional boolean. If false, equivalent to passing --no-subproject-summary on the command line."
+ },
+ "maxPassedTestOutputSize": {
+ "type": "integer",
+ "description": "An optional integer specifying the maximum output for passed tests in bytes. Equivalent to passing --test-output-size-passed on the command line."
+ },
+ "maxFailedTestOutputSize": {
+ "type": "integer",
+ "description": "An optional integer specifying the maximum output for failed tests in bytes. Equivalent to passing --test-output-size-failed on the command line."
+ },
+ "maxTestNameWidth": {
+ "type": "integer",
+ "description": "An optional integer specifying the maximum width of a test name to output. Equivalent to passing --max-width on the command line."
+ }
+ },
+ "additionalProperties": false
+ },
+ "filter": {
+ "type": "object",
+ "description": "An optional object specifying how to filter the tests to run.",
+ "properties": {
+ "include": {
+ "type": "object",
+ "description": "An optional object specifying which tests to include.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "An optional string specifying a regex for test names. Equivalent to passing --tests-regex on the command line."
+ },
+ "label": {
+ "type": "string",
+ "description": "An optional string specifying a regex for test labels. Equivalent to passing --label-regex on the command line."
+ },
+ "index": {
+ "anyOf": [
+ {
+ "type": "object",
+ "description": "An optional object specifying tests to include by test index.",
+ "properties": {
+ "start": {
+ "type": "integer",
+ "description": "An optional integer specifying a test index to start testing at."
+ },
+ "end": {
+ "type": "integer",
+ "description": "An optional integer specifying a test index to stop testing at."
+ },
+ "stride": {
+ "type": "integer",
+ "description": "An optional integer specifying the increment."
+ },
+ "specificTests": {
+ "type": "array",
+ "description": "An optional array of integers specifying specific test indices to run.",
+ "items": {
+ "type": "integer",
+ "description": "An integer specifying the test to run by index."
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "string",
+ "description": "An optional string specifying a file with the command line syntax for --tests-information."
+ }
+ ]
+ },
+ "useUnion": {
+ "type": "boolean",
+ "description": "An optional boolean. Equivalent to passing --union on the command line."
+ }
+ },
+ "additionalProperties": false
+ },
+ "exclude": {
+ "type": "object",
+ "description": "An optional object specifying which tests to exclude.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "An optional string specifying a regex for test names. Equivalent to passing --exclude-regex on the command line."
+ },
+ "label": {
+ "type": "string",
+ "description": "An optional string specifying a regex for test labels. Equivalent to passing --label-exclude on the command line."
+ },
+ "fixtures": {
+ "type": "object",
+ "description": "An optional object specifying which fixtures to exclude from adding tests.",
+ "properties": {
+ "any": {
+ "type": "string",
+ "description": "An optional string specifying a regex for text fixtures to exclude from adding any tests. Equivalent to --fixture-exclude-any on the command line."
+ },
+ "setup": {
+ "type": "string",
+ "description": "An optional string specifying a regex for text fixtures to exclude from adding setup tests. Equivalent to --fixture-exclude-setup on the command line."
+ },
+ "cleanup": {
+ "type": "string",
+ "description": "An optional string specifying a regex for text fixtures to exclude from adding cleanup tests. Equivalent to --fixture-exclude-cleanup on the command line."
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "execution": {
+ "type": "object",
+ "description": "An optional object specifying options for test execution.",
+ "properties": {
+ "stopOnFailure": {
+ "type": "boolean",
+ "description": "An optional boolean. If true, equivalent to passing --stop-on-failure on the command line."
+ },
+ "enableFailover": {
+ "type": "boolean",
+ "description": "An optional boolean. If true, equivalent to passing -F on the command line."
+ },
+ "jobs": {
+ "type": "integer",
+ "description": "An optional integer. Equivalent to passing --parallel on the command line."
+ },
+ "resourceSpecFile": {
+ "type": "string",
+ "description": "An optional string. Equivalent to passing --resource-spec-file on the command line."
+ },
+ "testLoad": {
+ "type": "integer",
+ "description": "An optional integer. Equivalent to passing --test-load on the command line."
+ },
+ "showOnly": {
+ "type": "string",
+ "description": "An optional string. Equivalent to passing --show-only on the command line. Value must be \"human\" or \"json-v1\".",
+ "enum": [
+ "human", "json-v1"
+ ]
+ },
+ "repeat": {
+ "type": "object",
+ "description": "An optional object specifying how to repeat tests. Equivalent to passing --repeat on the command line.",
+ "properties": {
+ "mode": {
+ "type": "string",
+ "description": "A required string. Must be one of the following values: \"until-fail\", \"until-pass\", or \"after-timeout\".",
+ "enum": [
+ "until-fail", "until-pass", "after-timeout"
+ ]
+ },
+ "count": {
+ "type": "integer",
+ "description": "A required integer."
+ }
+ },
+ "required": [
+ "mode", "count"
+ ],
+ "additionalProperties": false
+ },
+ "interactiveDebugging": {
+ "type": "boolean",
+ "description": "An optional boolean. If true, equivalent to passing --interactive-debug-mode 1 on the command line. If false, equivalent to passing --interactive-debug-mode 0 on the command line."
+ },
+ "scheduleRandom": {
+ "type": "boolean",
+ "description": "An optional boolean. If true, equivalent to passing --schedule-random on the command line."
+ },
+ "timeout": {
+ "type": "integer",
+ "description": "An optional integer. Equivalent to passing --timeout on the command line."
+ },
+ "noTestsAction": {
+ "type": "string",
+ "description": "An optional string specifying the behavior if no tests are found. Must be one of the following values: \"default\" (equivalent to not passing any value on the command line), \"error\" (equivalent to passing --no-tests=error on the command line), or \"ignore\" (equivalent to passing --no-tests-ignore on the command line).",
+ "enum": [
+ "default", "error", "ignore"
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "required": [
+ "name"
+ ]
+ }
+ },
+ "testPresetsV3": {
+ "type": "array",
+ "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
+ "allOf": [
+ { "$ref": "#/definitions/testPresetsItemsV2" },
+ { "$ref": "#/definitions/testPresetsItemsV3" }
+ ],
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {},
+ "hidden": {},
+ "inherits": {},
+ "configurePreset": {},
+ "vendor": {},
+ "displayName": {},
+ "description": {},
+ "inheritConfigureEnvironment": {},
+ "environment": {},
+ "configuration": {},
+ "overwriteConfigurationFile": {},
+ "output": {},
+ "filter": {},
+ "execution": {},
+ "condition": {}
+ },
+ "required": [
+ "name"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "testPresetsV2": {
+ "type": "array",
+ "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
+ "allOf": [
+ { "$ref": "#/definitions/testPresetsItemsV2" }
+ ],
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {},
+ "hidden": {},
+ "inherits": {},
+ "configurePreset": {},
+ "vendor": {},
+ "displayName": {},
+ "description": {},
+ "inheritConfigureEnvironment": {},
+ "environment": {},
+ "configuration": {},
+ "overwriteConfigurationFile": {},
+ "output": {},
+ "filter": {},
+ "execution": {}
+ },
+ "required": [
+ "name"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "condition": {
+ "anyOf": [
+ {
+ "type": "boolean",
+ "description": "A boolean which provides a constant value for the condition's evaluation."
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "A required string specifying the type of the condition.",
+ "const": "const"
+ },
+ "value": {
+ "type": "boolean",
+ "description": "A required boolean which provides a constant value for the condition's evaluation."
+ }
+ },
+ "required": [
+ "type",
+ "value"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "A required string specifying the type of the condition.",
+ "const": "equals"
+ },
+ "lhs": {
+ "type": "string",
+ "description": "First string to compare. This field supports macro expansion."
+ },
+ "rhs": {
+ "type": "string",
+ "description": "Second string to compare. This field supports macro expansion."
+ }
+ },
+ "required": [
+ "type",
+ "lhs",
+ "rhs"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "A required string specifying the type of the condition.",
+ "const": "notEquals"
+ },
+ "lhs": {
+ "type": "string",
+ "description": "First string to compare. This field supports macro expansion."
+ },
+ "rhs": {
+ "type": "string",
+ "description": "Second string to compare. This field supports macro expansion."
+ }
+ },
+ "required": [
+ "type",
+ "lhs",
+ "rhs"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "A required string specifying the type of the condition.",
+ "const": "inList"
+ },
+ "string": {
+ "type": "string",
+ "description": "A required string to search for. This field supports macro expansion."
+ },
+ "list": {
+ "type": "array",
+ "description": "A required list of strings to search. This field supports macro expansion, and uses short-circuit evaluation.",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": [
+ "type",
+ "string",
+ "list"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "A required string specifying the type of the condition.",
+ "const": "notInList"
+ },
+ "string": {
+ "type": "string",
+ "description": "A required string to search for. This field supports macro expansion."
+ },
+ "list": {
+ "type": "array",
+ "description": "A required list of strings to search. This field supports macro expansion, and uses short-circuit evaluation.",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": [
+ "type",
+ "string",
+ "list"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "A required string specifying the type of the condition.",
+ "const": "matches"
+ },
+ "string": {
+ "type": "string",
+ "description": "A required string to search. This field supports macro expansion."
+ },
+ "regex": {
+ "type": "string",
+ "description": "A required regular expression to search for. This field supports macro expansion."
+ }
+ },
+ "required": [
+ "type",
+ "string",
+ "regex"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "A required string specifying the type of the condition.",
+ "const": "notMatches"
+ },
+ "string": {
+ "type": "string",
+ "description": "A required string to search. This field supports macro expansion."
+ },
+ "regex": {
+ "type": "string",
+ "description": "A required regular expression to search for. This field supports macro expansion."
+ }
+ },
+ "required": [
+ "type",
+ "string",
+ "regex"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "A required string specifying the type of the condition.",
+ "const": "anyOf"
+ },
+ "conditions": {
+ "type": "array",
+ "description": "A required array of condition objects. These conditions use short-circuit evaluation.",
+ "items": { "$ref": "#/definitions/condition" }
+ }
+ },
+ "required": [
+ "type",
+ "conditions"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "A required string specifying the type of the condition.",
+ "const": "allOf"
+ },
+ "conditions": {
+ "type": "array",
+ "description": "A required array of condition objects. These conditions use short-circuit evaluation.",
+ "items": { "$ref": "#/definitions/condition" }
+ }
+ },
+ "required": [
+ "type",
+ "conditions"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "A required string specifying the type of the condition.",
+ "const": "not"
+ },
+ "condition": { "$ref": "#/definitions/condition" }
+ },
+ "required": [
+ "type",
+ "condition"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ },
+ "topCondition": {
+ "anyOf": [
+ { "$ref": "#/definitions/condition" },
+ {
+ "type": "null",
+ "description": "Null indicates that the condition always evaluates to true and is not inherited."
+ }
+ ]
+ }
+ }
+}
diff --git a/Help/module/AddFileDependencies.rst b/Help/module/AddFileDependencies.rst
new file mode 100644
index 0000000..3cbce33
--- /dev/null
+++ b/Help/module/AddFileDependencies.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/AddFileDependencies.cmake
diff --git a/Help/module/AndroidTestUtilities.rst b/Help/module/AndroidTestUtilities.rst
new file mode 100644
index 0000000..e7ec864
--- /dev/null
+++ b/Help/module/AndroidTestUtilities.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/AndroidTestUtilities.cmake
diff --git a/Help/module/BundleUtilities.rst b/Help/module/BundleUtilities.rst
new file mode 100644
index 0000000..5d9c840
--- /dev/null
+++ b/Help/module/BundleUtilities.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/BundleUtilities.cmake
diff --git a/Help/module/CMakeAddFortranSubdirectory.rst b/Help/module/CMakeAddFortranSubdirectory.rst
new file mode 100644
index 0000000..9abf571
--- /dev/null
+++ b/Help/module/CMakeAddFortranSubdirectory.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakeAddFortranSubdirectory.cmake
diff --git a/Help/module/CMakeBackwardCompatibilityCXX.rst b/Help/module/CMakeBackwardCompatibilityCXX.rst
new file mode 100644
index 0000000..05e5f4a
--- /dev/null
+++ b/Help/module/CMakeBackwardCompatibilityCXX.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakeBackwardCompatibilityCXX.cmake
diff --git a/Help/module/CMakeDependentOption.rst b/Help/module/CMakeDependentOption.rst
new file mode 100644
index 0000000..fd071b5
--- /dev/null
+++ b/Help/module/CMakeDependentOption.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakeDependentOption.cmake
diff --git a/Help/module/CMakeDetermineVSServicePack.rst b/Help/module/CMakeDetermineVSServicePack.rst
new file mode 100644
index 0000000..1768533
--- /dev/null
+++ b/Help/module/CMakeDetermineVSServicePack.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakeDetermineVSServicePack.cmake
diff --git a/Help/module/CMakeExpandImportedTargets.rst b/Help/module/CMakeExpandImportedTargets.rst
new file mode 100644
index 0000000..1084280
--- /dev/null
+++ b/Help/module/CMakeExpandImportedTargets.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakeExpandImportedTargets.cmake
diff --git a/Help/module/CMakeFindDependencyMacro.rst b/Help/module/CMakeFindDependencyMacro.rst
new file mode 100644
index 0000000..5b5b550
--- /dev/null
+++ b/Help/module/CMakeFindDependencyMacro.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakeFindDependencyMacro.cmake
diff --git a/Help/module/CMakeFindFrameworks.rst b/Help/module/CMakeFindFrameworks.rst
new file mode 100644
index 0000000..c2c219b
--- /dev/null
+++ b/Help/module/CMakeFindFrameworks.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakeFindFrameworks.cmake
diff --git a/Help/module/CMakeFindPackageMode.rst b/Help/module/CMakeFindPackageMode.rst
new file mode 100644
index 0000000..d099d19
--- /dev/null
+++ b/Help/module/CMakeFindPackageMode.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakeFindPackageMode.cmake
diff --git a/Help/module/CMakeForceCompiler.rst b/Help/module/CMakeForceCompiler.rst
new file mode 100644
index 0000000..3277426
--- /dev/null
+++ b/Help/module/CMakeForceCompiler.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakeForceCompiler.cmake
diff --git a/Help/module/CMakeGraphVizOptions.rst b/Help/module/CMakeGraphVizOptions.rst
new file mode 100644
index 0000000..2cd97b3
--- /dev/null
+++ b/Help/module/CMakeGraphVizOptions.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakeGraphVizOptions.cmake
diff --git a/Help/module/CMakePackageConfigHelpers.rst b/Help/module/CMakePackageConfigHelpers.rst
new file mode 100644
index 0000000..a291aff
--- /dev/null
+++ b/Help/module/CMakePackageConfigHelpers.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakePackageConfigHelpers.cmake
diff --git a/Help/module/CMakeParseArguments.rst b/Help/module/CMakeParseArguments.rst
new file mode 100644
index 0000000..810a9dd
--- /dev/null
+++ b/Help/module/CMakeParseArguments.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakeParseArguments.cmake
diff --git a/Help/module/CMakePrintHelpers.rst b/Help/module/CMakePrintHelpers.rst
new file mode 100644
index 0000000..a75a34f
--- /dev/null
+++ b/Help/module/CMakePrintHelpers.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakePrintHelpers.cmake
diff --git a/Help/module/CMakePrintSystemInformation.rst b/Help/module/CMakePrintSystemInformation.rst
new file mode 100644
index 0000000..0b5d848
--- /dev/null
+++ b/Help/module/CMakePrintSystemInformation.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakePrintSystemInformation.cmake
diff --git a/Help/module/CMakePushCheckState.rst b/Help/module/CMakePushCheckState.rst
new file mode 100644
index 0000000..e897929
--- /dev/null
+++ b/Help/module/CMakePushCheckState.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakePushCheckState.cmake
diff --git a/Help/module/CMakeVerifyManifest.rst b/Help/module/CMakeVerifyManifest.rst
new file mode 100644
index 0000000..eeff1bf
--- /dev/null
+++ b/Help/module/CMakeVerifyManifest.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CMakeVerifyManifest.cmake
diff --git a/Help/module/CPack.rst b/Help/module/CPack.rst
new file mode 100644
index 0000000..bfbda1f
--- /dev/null
+++ b/Help/module/CPack.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CPack.cmake
diff --git a/Help/module/CPackArchive.rst b/Help/module/CPackArchive.rst
new file mode 100644
index 0000000..f5d6da4
--- /dev/null
+++ b/Help/module/CPackArchive.rst
@@ -0,0 +1,6 @@
+CPackArchive
+------------
+
+.. versionadded:: 3.9
+
+The documentation for the CPack Archive generator has moved here: :cpack_gen:`CPack Archive Generator`
diff --git a/Help/module/CPackBundle.rst b/Help/module/CPackBundle.rst
new file mode 100644
index 0000000..5134884
--- /dev/null
+++ b/Help/module/CPackBundle.rst
@@ -0,0 +1,4 @@
+CPackBundle
+-----------
+
+The documentation for the CPack Bundle generator has moved here: :cpack_gen:`CPack Bundle Generator`
diff --git a/Help/module/CPackComponent.rst b/Help/module/CPackComponent.rst
new file mode 100644
index 0000000..df82836
--- /dev/null
+++ b/Help/module/CPackComponent.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CPackComponent.cmake
diff --git a/Help/module/CPackCygwin.rst b/Help/module/CPackCygwin.rst
new file mode 100644
index 0000000..719dfce
--- /dev/null
+++ b/Help/module/CPackCygwin.rst
@@ -0,0 +1,4 @@
+CPackCygwin
+-----------
+
+The documentation for the CPack Cygwin generator has moved here: :cpack_gen:`CPack Cygwin Generator`
diff --git a/Help/module/CPackDMG.rst b/Help/module/CPackDMG.rst
new file mode 100644
index 0000000..e59dcbb
--- /dev/null
+++ b/Help/module/CPackDMG.rst
@@ -0,0 +1,4 @@
+CPackDMG
+--------
+
+The documentation for the CPack DragNDrop generator has moved here: :cpack_gen:`CPack DragNDrop Generator`
diff --git a/Help/module/CPackDeb.rst b/Help/module/CPackDeb.rst
new file mode 100644
index 0000000..cd7e5f3
--- /dev/null
+++ b/Help/module/CPackDeb.rst
@@ -0,0 +1,4 @@
+CPackDeb
+--------
+
+The documentation for the CPack DEB generator has moved here: :cpack_gen:`CPack DEB Generator`
diff --git a/Help/module/CPackFreeBSD.rst b/Help/module/CPackFreeBSD.rst
new file mode 100644
index 0000000..7ae6164
--- /dev/null
+++ b/Help/module/CPackFreeBSD.rst
@@ -0,0 +1,6 @@
+CPackFreeBSD
+------------
+
+.. versionadded:: 3.10
+
+The documentation for the CPack FreeBSD generator has moved here: :cpack_gen:`CPack FreeBSD Generator`
diff --git a/Help/module/CPackIFW.rst b/Help/module/CPackIFW.rst
new file mode 100644
index 0000000..ea05796
--- /dev/null
+++ b/Help/module/CPackIFW.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CPackIFW.cmake
diff --git a/Help/module/CPackIFWConfigureFile.rst b/Help/module/CPackIFWConfigureFile.rst
new file mode 100644
index 0000000..e88517c
--- /dev/null
+++ b/Help/module/CPackIFWConfigureFile.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CPackIFWConfigureFile.cmake
diff --git a/Help/module/CPackNSIS.rst b/Help/module/CPackNSIS.rst
new file mode 100644
index 0000000..2cb407a
--- /dev/null
+++ b/Help/module/CPackNSIS.rst
@@ -0,0 +1,4 @@
+CPackNSIS
+---------
+
+The documentation for the CPack NSIS generator has moved here: :cpack_gen:`CPack NSIS Generator`
diff --git a/Help/module/CPackNuGet.rst b/Help/module/CPackNuGet.rst
new file mode 100644
index 0000000..bbed7f9
--- /dev/null
+++ b/Help/module/CPackNuGet.rst
@@ -0,0 +1,6 @@
+CPackNuGet
+----------
+
+.. versionadded:: 3.12
+
+The documentation for the CPack NuGet generator has moved here: :cpack_gen:`CPack NuGet Generator`
diff --git a/Help/module/CPackPackageMaker.rst b/Help/module/CPackPackageMaker.rst
new file mode 100644
index 0000000..226b6fd
--- /dev/null
+++ b/Help/module/CPackPackageMaker.rst
@@ -0,0 +1,4 @@
+CPackPackageMaker
+-----------------
+
+The documentation for the CPack PackageMaker generator has moved here: :cpack_gen:`CPack PackageMaker Generator`
diff --git a/Help/module/CPackProductBuild.rst b/Help/module/CPackProductBuild.rst
new file mode 100644
index 0000000..e12cd32
--- /dev/null
+++ b/Help/module/CPackProductBuild.rst
@@ -0,0 +1,6 @@
+CPackProductBuild
+-----------------
+
+.. versionadded:: 3.7
+
+The documentation for the CPack productbuild generator has moved here: :cpack_gen:`CPack productbuild Generator`
diff --git a/Help/module/CPackRPM.rst b/Help/module/CPackRPM.rst
new file mode 100644
index 0000000..00b7e0a
--- /dev/null
+++ b/Help/module/CPackRPM.rst
@@ -0,0 +1,4 @@
+CPackRPM
+--------
+
+The documentation for the CPack RPM generator has moved here: :cpack_gen:`CPack RPM Generator`
diff --git a/Help/module/CPackWIX.rst b/Help/module/CPackWIX.rst
new file mode 100644
index 0000000..fd378b8
--- /dev/null
+++ b/Help/module/CPackWIX.rst
@@ -0,0 +1,5 @@
+CPackWIX
+--------
+
+The documentation for the CPack WIX generator has moved here:
+:cpack_gen:`CPack WIX Generator`
diff --git a/Help/module/CSharpUtilities.rst b/Help/module/CSharpUtilities.rst
new file mode 100644
index 0000000..3621bbc
--- /dev/null
+++ b/Help/module/CSharpUtilities.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CSharpUtilities.cmake
diff --git a/Help/module/CTest.rst b/Help/module/CTest.rst
new file mode 100644
index 0000000..11a6af7
--- /dev/null
+++ b/Help/module/CTest.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CTest.cmake
diff --git a/Help/module/CTestCoverageCollectGCOV.rst b/Help/module/CTestCoverageCollectGCOV.rst
new file mode 100644
index 0000000..4c5deca
--- /dev/null
+++ b/Help/module/CTestCoverageCollectGCOV.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CTestCoverageCollectGCOV.cmake
diff --git a/Help/module/CTestScriptMode.rst b/Help/module/CTestScriptMode.rst
new file mode 100644
index 0000000..be1b044
--- /dev/null
+++ b/Help/module/CTestScriptMode.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CTestScriptMode.cmake
diff --git a/Help/module/CTestUseLaunchers.rst b/Help/module/CTestUseLaunchers.rst
new file mode 100644
index 0000000..688da08
--- /dev/null
+++ b/Help/module/CTestUseLaunchers.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CTestUseLaunchers.cmake
diff --git a/Help/module/CheckCCompilerFlag.rst b/Help/module/CheckCCompilerFlag.rst
new file mode 100644
index 0000000..1be1491
--- /dev/null
+++ b/Help/module/CheckCCompilerFlag.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckCCompilerFlag.cmake
diff --git a/Help/module/CheckCSourceCompiles.rst b/Help/module/CheckCSourceCompiles.rst
new file mode 100644
index 0000000..1fa02f9
--- /dev/null
+++ b/Help/module/CheckCSourceCompiles.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckCSourceCompiles.cmake
diff --git a/Help/module/CheckCSourceRuns.rst b/Help/module/CheckCSourceRuns.rst
new file mode 100644
index 0000000..16b47e6
--- /dev/null
+++ b/Help/module/CheckCSourceRuns.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckCSourceRuns.cmake
diff --git a/Help/module/CheckCXXCompilerFlag.rst b/Help/module/CheckCXXCompilerFlag.rst
new file mode 100644
index 0000000..cfd1f45
--- /dev/null
+++ b/Help/module/CheckCXXCompilerFlag.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckCXXCompilerFlag.cmake
diff --git a/Help/module/CheckCXXSourceCompiles.rst b/Help/module/CheckCXXSourceCompiles.rst
new file mode 100644
index 0000000..d701c4e
--- /dev/null
+++ b/Help/module/CheckCXXSourceCompiles.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckCXXSourceCompiles.cmake
diff --git a/Help/module/CheckCXXSourceRuns.rst b/Help/module/CheckCXXSourceRuns.rst
new file mode 100644
index 0000000..caab975
--- /dev/null
+++ b/Help/module/CheckCXXSourceRuns.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckCXXSourceRuns.cmake
diff --git a/Help/module/CheckCXXSymbolExists.rst b/Help/module/CheckCXXSymbolExists.rst
new file mode 100644
index 0000000..fc192e8
--- /dev/null
+++ b/Help/module/CheckCXXSymbolExists.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckCXXSymbolExists.cmake
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/module/CheckFortranCompilerFlag.rst b/Help/module/CheckFortranCompilerFlag.rst
new file mode 100644
index 0000000..58bf6ec
--- /dev/null
+++ b/Help/module/CheckFortranCompilerFlag.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckFortranCompilerFlag.cmake
diff --git a/Help/module/CheckFortranFunctionExists.rst b/Help/module/CheckFortranFunctionExists.rst
new file mode 100644
index 0000000..3395d05
--- /dev/null
+++ b/Help/module/CheckFortranFunctionExists.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckFortranFunctionExists.cmake
diff --git a/Help/module/CheckFortranSourceCompiles.rst b/Help/module/CheckFortranSourceCompiles.rst
new file mode 100644
index 0000000..b749a2a
--- /dev/null
+++ b/Help/module/CheckFortranSourceCompiles.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckFortranSourceCompiles.cmake
diff --git a/Help/module/CheckFortranSourceRuns.rst b/Help/module/CheckFortranSourceRuns.rst
new file mode 100644
index 0000000..a1bff70
--- /dev/null
+++ b/Help/module/CheckFortranSourceRuns.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckFortranSourceRuns.cmake
diff --git a/Help/module/CheckFunctionExists.rst b/Help/module/CheckFunctionExists.rst
new file mode 100644
index 0000000..ed89dc4
--- /dev/null
+++ b/Help/module/CheckFunctionExists.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckFunctionExists.cmake
diff --git a/Help/module/CheckIPOSupported.rst b/Help/module/CheckIPOSupported.rst
new file mode 100644
index 0000000..9c8a77b
--- /dev/null
+++ b/Help/module/CheckIPOSupported.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckIPOSupported.cmake
diff --git a/Help/module/CheckIncludeFile.rst b/Help/module/CheckIncludeFile.rst
new file mode 100644
index 0000000..6b83108
--- /dev/null
+++ b/Help/module/CheckIncludeFile.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckIncludeFile.cmake
diff --git a/Help/module/CheckIncludeFileCXX.rst b/Help/module/CheckIncludeFileCXX.rst
new file mode 100644
index 0000000..fdbf39f
--- /dev/null
+++ b/Help/module/CheckIncludeFileCXX.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckIncludeFileCXX.cmake
diff --git a/Help/module/CheckIncludeFiles.rst b/Help/module/CheckIncludeFiles.rst
new file mode 100644
index 0000000..b56f145
--- /dev/null
+++ b/Help/module/CheckIncludeFiles.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckIncludeFiles.cmake
diff --git a/Help/module/CheckLanguage.rst b/Help/module/CheckLanguage.rst
new file mode 100644
index 0000000..16f1a3f
--- /dev/null
+++ b/Help/module/CheckLanguage.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckLanguage.cmake
diff --git a/Help/module/CheckLibraryExists.rst b/Help/module/CheckLibraryExists.rst
new file mode 100644
index 0000000..7512f46
--- /dev/null
+++ b/Help/module/CheckLibraryExists.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckLibraryExists.cmake
diff --git a/Help/module/CheckLinkerFlag.rst b/Help/module/CheckLinkerFlag.rst
new file mode 100644
index 0000000..4005725
--- /dev/null
+++ b/Help/module/CheckLinkerFlag.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckLinkerFlag.cmake
diff --git a/Help/module/CheckOBJCCompilerFlag.rst b/Help/module/CheckOBJCCompilerFlag.rst
new file mode 100644
index 0000000..e4bd6fd
--- /dev/null
+++ b/Help/module/CheckOBJCCompilerFlag.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckOBJCCompilerFlag.cmake
diff --git a/Help/module/CheckOBJCSourceCompiles.rst b/Help/module/CheckOBJCSourceCompiles.rst
new file mode 100644
index 0000000..d4a1484
--- /dev/null
+++ b/Help/module/CheckOBJCSourceCompiles.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckOBJCSourceCompiles.cmake
diff --git a/Help/module/CheckOBJCSourceRuns.rst b/Help/module/CheckOBJCSourceRuns.rst
new file mode 100644
index 0000000..c72f0db
--- /dev/null
+++ b/Help/module/CheckOBJCSourceRuns.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckOBJCSourceRuns.cmake
diff --git a/Help/module/CheckOBJCXXCompilerFlag.rst b/Help/module/CheckOBJCXXCompilerFlag.rst
new file mode 100644
index 0000000..1518a48
--- /dev/null
+++ b/Help/module/CheckOBJCXXCompilerFlag.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckOBJCXXCompilerFlag.cmake
diff --git a/Help/module/CheckOBJCXXSourceCompiles.rst b/Help/module/CheckOBJCXXSourceCompiles.rst
new file mode 100644
index 0000000..a1c8ae9
--- /dev/null
+++ b/Help/module/CheckOBJCXXSourceCompiles.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckOBJCXXSourceCompiles.cmake
diff --git a/Help/module/CheckOBJCXXSourceRuns.rst b/Help/module/CheckOBJCXXSourceRuns.rst
new file mode 100644
index 0000000..5198e1b
--- /dev/null
+++ b/Help/module/CheckOBJCXXSourceRuns.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckOBJCXXSourceRuns.cmake
diff --git a/Help/module/CheckPIESupported.rst b/Help/module/CheckPIESupported.rst
new file mode 100644
index 0000000..02e7b43
--- /dev/null
+++ b/Help/module/CheckPIESupported.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckPIESupported.cmake
diff --git a/Help/module/CheckPrototypeDefinition.rst b/Help/module/CheckPrototypeDefinition.rst
new file mode 100644
index 0000000..073fcb5
--- /dev/null
+++ b/Help/module/CheckPrototypeDefinition.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckPrototypeDefinition.cmake
diff --git a/Help/module/CheckSourceCompiles.rst b/Help/module/CheckSourceCompiles.rst
new file mode 100644
index 0000000..906db0a
--- /dev/null
+++ b/Help/module/CheckSourceCompiles.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckSourceCompiles.cmake
diff --git a/Help/module/CheckSourceRuns.rst b/Help/module/CheckSourceRuns.rst
new file mode 100644
index 0000000..d469244
--- /dev/null
+++ b/Help/module/CheckSourceRuns.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckSourceRuns.cmake
diff --git a/Help/module/CheckStructHasMember.rst b/Help/module/CheckStructHasMember.rst
new file mode 100644
index 0000000..5277ad2
--- /dev/null
+++ b/Help/module/CheckStructHasMember.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckStructHasMember.cmake
diff --git a/Help/module/CheckSymbolExists.rst b/Help/module/CheckSymbolExists.rst
new file mode 100644
index 0000000..68ae700
--- /dev/null
+++ b/Help/module/CheckSymbolExists.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckSymbolExists.cmake
diff --git a/Help/module/CheckTypeSize.rst b/Help/module/CheckTypeSize.rst
new file mode 100644
index 0000000..6ad0345
--- /dev/null
+++ b/Help/module/CheckTypeSize.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckTypeSize.cmake
diff --git a/Help/module/CheckVariableExists.rst b/Help/module/CheckVariableExists.rst
new file mode 100644
index 0000000..07f0777
--- /dev/null
+++ b/Help/module/CheckVariableExists.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckVariableExists.cmake
diff --git a/Help/module/Dart.rst b/Help/module/Dart.rst
new file mode 100644
index 0000000..524ac33
--- /dev/null
+++ b/Help/module/Dart.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/Dart.cmake
diff --git a/Help/module/DeployQt4.rst b/Help/module/DeployQt4.rst
new file mode 100644
index 0000000..3c0ef44
--- /dev/null
+++ b/Help/module/DeployQt4.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/DeployQt4.cmake
diff --git a/Help/module/Documentation.rst b/Help/module/Documentation.rst
new file mode 100644
index 0000000..08e2ffb
--- /dev/null
+++ b/Help/module/Documentation.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/Documentation.cmake
diff --git a/Help/module/ExternalData.rst b/Help/module/ExternalData.rst
new file mode 100644
index 0000000..f0f8f1d
--- /dev/null
+++ b/Help/module/ExternalData.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/ExternalData.cmake
diff --git a/Help/module/ExternalProject.rst b/Help/module/ExternalProject.rst
new file mode 100644
index 0000000..fce7056
--- /dev/null
+++ b/Help/module/ExternalProject.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/ExternalProject.cmake
diff --git a/Help/module/FeatureSummary.rst b/Help/module/FeatureSummary.rst
new file mode 100644
index 0000000..6fd8f38
--- /dev/null
+++ b/Help/module/FeatureSummary.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FeatureSummary.cmake
diff --git a/Help/module/FetchContent.rst b/Help/module/FetchContent.rst
new file mode 100644
index 0000000..c130a6d
--- /dev/null
+++ b/Help/module/FetchContent.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FetchContent.cmake
diff --git a/Help/module/FindALSA.rst b/Help/module/FindALSA.rst
new file mode 100644
index 0000000..2a73786
--- /dev/null
+++ b/Help/module/FindALSA.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindALSA.cmake
diff --git a/Help/module/FindASPELL.rst b/Help/module/FindASPELL.rst
new file mode 100644
index 0000000..56dedc4
--- /dev/null
+++ b/Help/module/FindASPELL.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindASPELL.cmake
diff --git a/Help/module/FindAVIFile.rst b/Help/module/FindAVIFile.rst
new file mode 100644
index 0000000..71282a6
--- /dev/null
+++ b/Help/module/FindAVIFile.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindAVIFile.cmake
diff --git a/Help/module/FindArmadillo.rst b/Help/module/FindArmadillo.rst
new file mode 100644
index 0000000..f0ac933
--- /dev/null
+++ b/Help/module/FindArmadillo.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindArmadillo.cmake
diff --git a/Help/module/FindBISON.rst b/Help/module/FindBISON.rst
new file mode 100644
index 0000000..c6e5791
--- /dev/null
+++ b/Help/module/FindBISON.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindBISON.cmake
diff --git a/Help/module/FindBLAS.rst b/Help/module/FindBLAS.rst
new file mode 100644
index 0000000..41f6771
--- /dev/null
+++ b/Help/module/FindBLAS.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindBLAS.cmake
diff --git a/Help/module/FindBZip2.rst b/Help/module/FindBZip2.rst
new file mode 100644
index 0000000..281b1d1
--- /dev/null
+++ b/Help/module/FindBZip2.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindBZip2.cmake
diff --git a/Help/module/FindBacktrace.rst b/Help/module/FindBacktrace.rst
new file mode 100644
index 0000000..e1ca48c
--- /dev/null
+++ b/Help/module/FindBacktrace.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindBacktrace.cmake
diff --git a/Help/module/FindBoost.rst b/Help/module/FindBoost.rst
new file mode 100644
index 0000000..1392540
--- /dev/null
+++ b/Help/module/FindBoost.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindBoost.cmake
diff --git a/Help/module/FindBullet.rst b/Help/module/FindBullet.rst
new file mode 100644
index 0000000..4ed2b85
--- /dev/null
+++ b/Help/module/FindBullet.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindBullet.cmake
diff --git a/Help/module/FindCABLE.rst b/Help/module/FindCABLE.rst
new file mode 100644
index 0000000..716d5ab
--- /dev/null
+++ b/Help/module/FindCABLE.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindCABLE.cmake
diff --git a/Help/module/FindCUDA.rst b/Help/module/FindCUDA.rst
new file mode 100644
index 0000000..46ffa9f
--- /dev/null
+++ b/Help/module/FindCUDA.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindCUDA.cmake
diff --git a/Help/module/FindCUDAToolkit.rst b/Help/module/FindCUDAToolkit.rst
new file mode 100644
index 0000000..5f01d68
--- /dev/null
+++ b/Help/module/FindCUDAToolkit.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindCUDAToolkit.cmake
diff --git a/Help/module/FindCURL.rst b/Help/module/FindCURL.rst
new file mode 100644
index 0000000..e2acc49
--- /dev/null
+++ b/Help/module/FindCURL.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindCURL.cmake
diff --git a/Help/module/FindCVS.rst b/Help/module/FindCVS.rst
new file mode 100644
index 0000000..c891c07
--- /dev/null
+++ b/Help/module/FindCVS.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindCVS.cmake
diff --git a/Help/module/FindCoin3D.rst b/Help/module/FindCoin3D.rst
new file mode 100644
index 0000000..fc70a74
--- /dev/null
+++ b/Help/module/FindCoin3D.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindCoin3D.cmake
diff --git a/Help/module/FindCups.rst b/Help/module/FindCups.rst
new file mode 100644
index 0000000..10d0646
--- /dev/null
+++ b/Help/module/FindCups.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindCups.cmake
diff --git a/Help/module/FindCurses.rst b/Help/module/FindCurses.rst
new file mode 100644
index 0000000..73dd011
--- /dev/null
+++ b/Help/module/FindCurses.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindCurses.cmake
diff --git a/Help/module/FindCxxTest.rst b/Help/module/FindCxxTest.rst
new file mode 100644
index 0000000..4f17c39
--- /dev/null
+++ b/Help/module/FindCxxTest.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindCxxTest.cmake
diff --git a/Help/module/FindCygwin.rst b/Help/module/FindCygwin.rst
new file mode 100644
index 0000000..2e529dd
--- /dev/null
+++ b/Help/module/FindCygwin.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindCygwin.cmake
diff --git a/Help/module/FindDCMTK.rst b/Help/module/FindDCMTK.rst
new file mode 100644
index 0000000..8437d55
--- /dev/null
+++ b/Help/module/FindDCMTK.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindDCMTK.cmake
diff --git a/Help/module/FindDart.rst b/Help/module/FindDart.rst
new file mode 100644
index 0000000..6f21ad4
--- /dev/null
+++ b/Help/module/FindDart.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindDart.cmake
diff --git a/Help/module/FindDevIL.rst b/Help/module/FindDevIL.rst
new file mode 100644
index 0000000..91a28dd
--- /dev/null
+++ b/Help/module/FindDevIL.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindDevIL.cmake
diff --git a/Help/module/FindDoxygen.rst b/Help/module/FindDoxygen.rst
new file mode 100644
index 0000000..cffe734
--- /dev/null
+++ b/Help/module/FindDoxygen.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindDoxygen.cmake
diff --git a/Help/module/FindEXPAT.rst b/Help/module/FindEXPAT.rst
new file mode 100644
index 0000000..5063680
--- /dev/null
+++ b/Help/module/FindEXPAT.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindEXPAT.cmake
diff --git a/Help/module/FindEnvModules.rst b/Help/module/FindEnvModules.rst
new file mode 100644
index 0000000..72c120f
--- /dev/null
+++ b/Help/module/FindEnvModules.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindEnvModules.cmake
diff --git a/Help/module/FindFLEX.rst b/Help/module/FindFLEX.rst
new file mode 100644
index 0000000..cc90791
--- /dev/null
+++ b/Help/module/FindFLEX.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindFLEX.cmake
diff --git a/Help/module/FindFLTK.rst b/Help/module/FindFLTK.rst
new file mode 100644
index 0000000..cc1964c
--- /dev/null
+++ b/Help/module/FindFLTK.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindFLTK.cmake
diff --git a/Help/module/FindFLTK2.rst b/Help/module/FindFLTK2.rst
new file mode 100644
index 0000000..5c2acc4
--- /dev/null
+++ b/Help/module/FindFLTK2.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindFLTK2.cmake
diff --git a/Help/module/FindFontconfig.rst b/Help/module/FindFontconfig.rst
new file mode 100644
index 0000000..449fe09
--- /dev/null
+++ b/Help/module/FindFontconfig.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindFontconfig.cmake
diff --git a/Help/module/FindFreetype.rst b/Help/module/FindFreetype.rst
new file mode 100644
index 0000000..424c3fc
--- /dev/null
+++ b/Help/module/FindFreetype.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindFreetype.cmake
diff --git a/Help/module/FindGCCXML.rst b/Help/module/FindGCCXML.rst
new file mode 100644
index 0000000..15fd4d0
--- /dev/null
+++ b/Help/module/FindGCCXML.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindGCCXML.cmake
diff --git a/Help/module/FindGDAL.rst b/Help/module/FindGDAL.rst
new file mode 100644
index 0000000..81fcb3a
--- /dev/null
+++ b/Help/module/FindGDAL.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindGDAL.cmake
diff --git a/Help/module/FindGIF.rst b/Help/module/FindGIF.rst
new file mode 100644
index 0000000..03d3a75
--- /dev/null
+++ b/Help/module/FindGIF.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindGIF.cmake
diff --git a/Help/module/FindGLEW.rst b/Help/module/FindGLEW.rst
new file mode 100644
index 0000000..77755da
--- /dev/null
+++ b/Help/module/FindGLEW.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindGLEW.cmake
diff --git a/Help/module/FindGLUT.rst b/Help/module/FindGLUT.rst
new file mode 100644
index 0000000..40263ee
--- /dev/null
+++ b/Help/module/FindGLUT.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindGLUT.cmake
diff --git a/Help/module/FindGSL.rst b/Help/module/FindGSL.rst
new file mode 100644
index 0000000..baf2213
--- /dev/null
+++ b/Help/module/FindGSL.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindGSL.cmake
diff --git a/Help/module/FindGTK.rst b/Help/module/FindGTK.rst
new file mode 100644
index 0000000..1ce6a86
--- /dev/null
+++ b/Help/module/FindGTK.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindGTK.cmake
diff --git a/Help/module/FindGTK2.rst b/Help/module/FindGTK2.rst
new file mode 100644
index 0000000..67c1ba9
--- /dev/null
+++ b/Help/module/FindGTK2.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindGTK2.cmake
diff --git a/Help/module/FindGTest.rst b/Help/module/FindGTest.rst
new file mode 100644
index 0000000..0e3b4d7
--- /dev/null
+++ b/Help/module/FindGTest.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindGTest.cmake
diff --git a/Help/module/FindGettext.rst b/Help/module/FindGettext.rst
new file mode 100644
index 0000000..e880dc0
--- /dev/null
+++ b/Help/module/FindGettext.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindGettext.cmake
diff --git a/Help/module/FindGit.rst b/Help/module/FindGit.rst
new file mode 100644
index 0000000..dd540ef
--- /dev/null
+++ b/Help/module/FindGit.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindGit.cmake
diff --git a/Help/module/FindGnuTLS.rst b/Help/module/FindGnuTLS.rst
new file mode 100644
index 0000000..de0c1d4
--- /dev/null
+++ b/Help/module/FindGnuTLS.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindGnuTLS.cmake
diff --git a/Help/module/FindGnuplot.rst b/Help/module/FindGnuplot.rst
new file mode 100644
index 0000000..93a18b6
--- /dev/null
+++ b/Help/module/FindGnuplot.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindGnuplot.cmake
diff --git a/Help/module/FindHDF5.rst b/Help/module/FindHDF5.rst
new file mode 100644
index 0000000..8ac1b8b
--- /dev/null
+++ b/Help/module/FindHDF5.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindHDF5.cmake
diff --git a/Help/module/FindHSPELL.rst b/Help/module/FindHSPELL.rst
new file mode 100644
index 0000000..c1905a2
--- /dev/null
+++ b/Help/module/FindHSPELL.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindHSPELL.cmake
diff --git a/Help/module/FindHTMLHelp.rst b/Help/module/FindHTMLHelp.rst
new file mode 100644
index 0000000..47d9c8c
--- /dev/null
+++ b/Help/module/FindHTMLHelp.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindHTMLHelp.cmake
diff --git a/Help/module/FindHg.rst b/Help/module/FindHg.rst
new file mode 100644
index 0000000..94aba6f
--- /dev/null
+++ b/Help/module/FindHg.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindHg.cmake
diff --git a/Help/module/FindICU.rst b/Help/module/FindICU.rst
new file mode 100644
index 0000000..ee3f4a9
--- /dev/null
+++ b/Help/module/FindICU.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindICU.cmake
diff --git a/Help/module/FindITK.rst b/Help/module/FindITK.rst
new file mode 100644
index 0000000..21a922f
--- /dev/null
+++ b/Help/module/FindITK.rst
@@ -0,0 +1,10 @@
+FindITK
+-------
+
+This module no longer exists.
+
+This module existed in versions of CMake prior to 3.1, but became
+only a thin wrapper around ``find_package(ITK NO_MODULE)`` to
+provide compatibility for projects using long-outdated conventions.
+Now ``find_package(ITK)`` will search for ``ITKConfig.cmake``
+directly.
diff --git a/Help/module/FindIce.rst b/Help/module/FindIce.rst
new file mode 100644
index 0000000..3af9405
--- /dev/null
+++ b/Help/module/FindIce.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindIce.cmake
diff --git a/Help/module/FindIconv.rst b/Help/module/FindIconv.rst
new file mode 100644
index 0000000..c1f3ed0
--- /dev/null
+++ b/Help/module/FindIconv.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindIconv.cmake
diff --git a/Help/module/FindIcotool.rst b/Help/module/FindIcotool.rst
new file mode 100644
index 0000000..c139f58
--- /dev/null
+++ b/Help/module/FindIcotool.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindIcotool.cmake
diff --git a/Help/module/FindImageMagick.rst b/Help/module/FindImageMagick.rst
new file mode 100644
index 0000000..3a3596e
--- /dev/null
+++ b/Help/module/FindImageMagick.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindImageMagick.cmake
diff --git a/Help/module/FindIntl.rst b/Help/module/FindIntl.rst
new file mode 100644
index 0000000..813e2df
--- /dev/null
+++ b/Help/module/FindIntl.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindIntl.cmake
diff --git a/Help/module/FindJNI.rst b/Help/module/FindJNI.rst
new file mode 100644
index 0000000..b753cf8
--- /dev/null
+++ b/Help/module/FindJNI.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindJNI.cmake
diff --git a/Help/module/FindJPEG.rst b/Help/module/FindJPEG.rst
new file mode 100644
index 0000000..8036352
--- /dev/null
+++ b/Help/module/FindJPEG.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindJPEG.cmake
diff --git a/Help/module/FindJasper.rst b/Help/module/FindJasper.rst
new file mode 100644
index 0000000..725a87f
--- /dev/null
+++ b/Help/module/FindJasper.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindJasper.cmake
diff --git a/Help/module/FindJava.rst b/Help/module/FindJava.rst
new file mode 100644
index 0000000..39e6b6b
--- /dev/null
+++ b/Help/module/FindJava.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindJava.cmake
diff --git a/Help/module/FindKDE3.rst b/Help/module/FindKDE3.rst
new file mode 100644
index 0000000..13ac15c
--- /dev/null
+++ b/Help/module/FindKDE3.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindKDE3.cmake
diff --git a/Help/module/FindKDE4.rst b/Help/module/FindKDE4.rst
new file mode 100644
index 0000000..8b22f7f
--- /dev/null
+++ b/Help/module/FindKDE4.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindKDE4.cmake
diff --git a/Help/module/FindLAPACK.rst b/Help/module/FindLAPACK.rst
new file mode 100644
index 0000000..6e99090
--- /dev/null
+++ b/Help/module/FindLAPACK.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindLAPACK.cmake
diff --git a/Help/module/FindLATEX.rst b/Help/module/FindLATEX.rst
new file mode 100644
index 0000000..4b14c71
--- /dev/null
+++ b/Help/module/FindLATEX.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindLATEX.cmake
diff --git a/Help/module/FindLTTngUST.rst b/Help/module/FindLTTngUST.rst
new file mode 100644
index 0000000..a775462
--- /dev/null
+++ b/Help/module/FindLTTngUST.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindLTTngUST.cmake
diff --git a/Help/module/FindLibArchive.rst b/Help/module/FindLibArchive.rst
new file mode 100644
index 0000000..c46b1d0
--- /dev/null
+++ b/Help/module/FindLibArchive.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindLibArchive.cmake
diff --git a/Help/module/FindLibLZMA.rst b/Help/module/FindLibLZMA.rst
new file mode 100644
index 0000000..8880158
--- /dev/null
+++ b/Help/module/FindLibLZMA.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindLibLZMA.cmake
diff --git a/Help/module/FindLibXml2.rst b/Help/module/FindLibXml2.rst
new file mode 100644
index 0000000..bbb3225
--- /dev/null
+++ b/Help/module/FindLibXml2.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindLibXml2.cmake
diff --git a/Help/module/FindLibXslt.rst b/Help/module/FindLibXslt.rst
new file mode 100644
index 0000000..4107170
--- /dev/null
+++ b/Help/module/FindLibXslt.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindLibXslt.cmake
diff --git a/Help/module/FindLibinput.rst b/Help/module/FindLibinput.rst
new file mode 100644
index 0000000..a8ca0b0
--- /dev/null
+++ b/Help/module/FindLibinput.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindLibinput.cmake
diff --git a/Help/module/FindLua.rst b/Help/module/FindLua.rst
new file mode 100644
index 0000000..977e5bf
--- /dev/null
+++ b/Help/module/FindLua.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindLua.cmake
diff --git a/Help/module/FindLua50.rst b/Help/module/FindLua50.rst
new file mode 100644
index 0000000..0353fc3
--- /dev/null
+++ b/Help/module/FindLua50.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindLua50.cmake
diff --git a/Help/module/FindLua51.rst b/Help/module/FindLua51.rst
new file mode 100644
index 0000000..672ff35
--- /dev/null
+++ b/Help/module/FindLua51.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindLua51.cmake
diff --git a/Help/module/FindMFC.rst b/Help/module/FindMFC.rst
new file mode 100644
index 0000000..a3226a6
--- /dev/null
+++ b/Help/module/FindMFC.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindMFC.cmake
diff --git a/Help/module/FindMPEG.rst b/Help/module/FindMPEG.rst
new file mode 100644
index 0000000..c9ce481
--- /dev/null
+++ b/Help/module/FindMPEG.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindMPEG.cmake
diff --git a/Help/module/FindMPEG2.rst b/Help/module/FindMPEG2.rst
new file mode 100644
index 0000000..f843c89
--- /dev/null
+++ b/Help/module/FindMPEG2.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindMPEG2.cmake
diff --git a/Help/module/FindMPI.rst b/Help/module/FindMPI.rst
new file mode 100644
index 0000000..fad10c7
--- /dev/null
+++ b/Help/module/FindMPI.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindMPI.cmake
diff --git a/Help/module/FindMatlab.rst b/Help/module/FindMatlab.rst
new file mode 100644
index 0000000..43f861a
--- /dev/null
+++ b/Help/module/FindMatlab.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindMatlab.cmake
diff --git a/Help/module/FindMotif.rst b/Help/module/FindMotif.rst
new file mode 100644
index 0000000..e602a50
--- /dev/null
+++ b/Help/module/FindMotif.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindMotif.cmake
diff --git a/Help/module/FindODBC.rst b/Help/module/FindODBC.rst
new file mode 100644
index 0000000..8558334
--- /dev/null
+++ b/Help/module/FindODBC.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindODBC.cmake
diff --git a/Help/module/FindOpenACC.rst b/Help/module/FindOpenACC.rst
new file mode 100644
index 0000000..dda3308
--- /dev/null
+++ b/Help/module/FindOpenACC.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindOpenACC.cmake
diff --git a/Help/module/FindOpenAL.rst b/Help/module/FindOpenAL.rst
new file mode 100644
index 0000000..f086556
--- /dev/null
+++ b/Help/module/FindOpenAL.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindOpenAL.cmake
diff --git a/Help/module/FindOpenCL.rst b/Help/module/FindOpenCL.rst
new file mode 100644
index 0000000..e87e289
--- /dev/null
+++ b/Help/module/FindOpenCL.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindOpenCL.cmake
diff --git a/Help/module/FindOpenGL.rst b/Help/module/FindOpenGL.rst
new file mode 100644
index 0000000..85e89bc
--- /dev/null
+++ b/Help/module/FindOpenGL.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindOpenGL.cmake
diff --git a/Help/module/FindOpenMP.rst b/Help/module/FindOpenMP.rst
new file mode 100644
index 0000000..01362ab
--- /dev/null
+++ b/Help/module/FindOpenMP.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindOpenMP.cmake
diff --git a/Help/module/FindOpenSSL.rst b/Help/module/FindOpenSSL.rst
new file mode 100644
index 0000000..f622bb1
--- /dev/null
+++ b/Help/module/FindOpenSSL.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindOpenSSL.cmake
diff --git a/Help/module/FindOpenSceneGraph.rst b/Help/module/FindOpenSceneGraph.rst
new file mode 100644
index 0000000..4346492
--- /dev/null
+++ b/Help/module/FindOpenSceneGraph.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindOpenSceneGraph.cmake
diff --git a/Help/module/FindOpenThreads.rst b/Help/module/FindOpenThreads.rst
new file mode 100644
index 0000000..bb3f0f9
--- /dev/null
+++ b/Help/module/FindOpenThreads.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindOpenThreads.cmake
diff --git a/Help/module/FindPHP4.rst b/Help/module/FindPHP4.rst
new file mode 100644
index 0000000..1de62e8
--- /dev/null
+++ b/Help/module/FindPHP4.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPHP4.cmake
diff --git a/Help/module/FindPNG.rst b/Help/module/FindPNG.rst
new file mode 100644
index 0000000..e6d1618
--- /dev/null
+++ b/Help/module/FindPNG.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPNG.cmake
diff --git a/Help/module/FindPackageHandleStandardArgs.rst b/Help/module/FindPackageHandleStandardArgs.rst
new file mode 100644
index 0000000..feda7ef
--- /dev/null
+++ b/Help/module/FindPackageHandleStandardArgs.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPackageHandleStandardArgs.cmake
diff --git a/Help/module/FindPackageMessage.rst b/Help/module/FindPackageMessage.rst
new file mode 100644
index 0000000..b682d8c
--- /dev/null
+++ b/Help/module/FindPackageMessage.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPackageMessage.cmake
diff --git a/Help/module/FindPatch.rst b/Help/module/FindPatch.rst
new file mode 100644
index 0000000..ba5e910
--- /dev/null
+++ b/Help/module/FindPatch.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPatch.cmake
diff --git a/Help/module/FindPerl.rst b/Help/module/FindPerl.rst
new file mode 100644
index 0000000..098f4b5
--- /dev/null
+++ b/Help/module/FindPerl.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPerl.cmake
diff --git a/Help/module/FindPerlLibs.rst b/Help/module/FindPerlLibs.rst
new file mode 100644
index 0000000..8d8bbab
--- /dev/null
+++ b/Help/module/FindPerlLibs.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPerlLibs.cmake
diff --git a/Help/module/FindPhysFS.rst b/Help/module/FindPhysFS.rst
new file mode 100644
index 0000000..21d928b
--- /dev/null
+++ b/Help/module/FindPhysFS.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPhysFS.cmake
diff --git a/Help/module/FindPike.rst b/Help/module/FindPike.rst
new file mode 100644
index 0000000..b096ca4
--- /dev/null
+++ b/Help/module/FindPike.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPike.cmake
diff --git a/Help/module/FindPkgConfig.rst b/Help/module/FindPkgConfig.rst
new file mode 100644
index 0000000..b8caf74
--- /dev/null
+++ b/Help/module/FindPkgConfig.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPkgConfig.cmake
diff --git a/Help/module/FindPostgreSQL.rst b/Help/module/FindPostgreSQL.rst
new file mode 100644
index 0000000..b45c07e
--- /dev/null
+++ b/Help/module/FindPostgreSQL.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPostgreSQL.cmake
diff --git a/Help/module/FindProducer.rst b/Help/module/FindProducer.rst
new file mode 100644
index 0000000..1c0c575
--- /dev/null
+++ b/Help/module/FindProducer.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindProducer.cmake
diff --git a/Help/module/FindProtobuf.rst b/Help/module/FindProtobuf.rst
new file mode 100644
index 0000000..b978e01
--- /dev/null
+++ b/Help/module/FindProtobuf.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindProtobuf.cmake
diff --git a/Help/module/FindPython.rst b/Help/module/FindPython.rst
new file mode 100644
index 0000000..057a350
--- /dev/null
+++ b/Help/module/FindPython.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPython.cmake
diff --git a/Help/module/FindPython2.rst b/Help/module/FindPython2.rst
new file mode 100644
index 0000000..1696bed
--- /dev/null
+++ b/Help/module/FindPython2.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPython2.cmake
diff --git a/Help/module/FindPython3.rst b/Help/module/FindPython3.rst
new file mode 100644
index 0000000..e530ab8
--- /dev/null
+++ b/Help/module/FindPython3.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPython3.cmake
diff --git a/Help/module/FindPythonInterp.rst b/Help/module/FindPythonInterp.rst
new file mode 100644
index 0000000..3be2306
--- /dev/null
+++ b/Help/module/FindPythonInterp.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPythonInterp.cmake
diff --git a/Help/module/FindPythonLibs.rst b/Help/module/FindPythonLibs.rst
new file mode 100644
index 0000000..8f0015d
--- /dev/null
+++ b/Help/module/FindPythonLibs.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindPythonLibs.cmake
diff --git a/Help/module/FindQt.rst b/Help/module/FindQt.rst
new file mode 100644
index 0000000..3aa8a26
--- /dev/null
+++ b/Help/module/FindQt.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindQt.cmake
diff --git a/Help/module/FindQt3.rst b/Help/module/FindQt3.rst
new file mode 100644
index 0000000..b933059
--- /dev/null
+++ b/Help/module/FindQt3.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindQt3.cmake
diff --git a/Help/module/FindQt4.rst b/Help/module/FindQt4.rst
new file mode 100644
index 0000000..28036b2
--- /dev/null
+++ b/Help/module/FindQt4.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindQt4.cmake
diff --git a/Help/module/FindQuickTime.rst b/Help/module/FindQuickTime.rst
new file mode 100644
index 0000000..735f7d2
--- /dev/null
+++ b/Help/module/FindQuickTime.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindQuickTime.cmake
diff --git a/Help/module/FindRTI.rst b/Help/module/FindRTI.rst
new file mode 100644
index 0000000..a93ad16
--- /dev/null
+++ b/Help/module/FindRTI.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindRTI.cmake
diff --git a/Help/module/FindRuby.rst b/Help/module/FindRuby.rst
new file mode 100644
index 0000000..a1e7922
--- /dev/null
+++ b/Help/module/FindRuby.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindRuby.cmake
diff --git a/Help/module/FindSDL.rst b/Help/module/FindSDL.rst
new file mode 100644
index 0000000..79893c0
--- /dev/null
+++ b/Help/module/FindSDL.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindSDL.cmake
diff --git a/Help/module/FindSDL_image.rst b/Help/module/FindSDL_image.rst
new file mode 100644
index 0000000..dc69d70
--- /dev/null
+++ b/Help/module/FindSDL_image.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindSDL_image.cmake
diff --git a/Help/module/FindSDL_mixer.rst b/Help/module/FindSDL_mixer.rst
new file mode 100644
index 0000000..1c9c446
--- /dev/null
+++ b/Help/module/FindSDL_mixer.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindSDL_mixer.cmake
diff --git a/Help/module/FindSDL_net.rst b/Help/module/FindSDL_net.rst
new file mode 100644
index 0000000..079d0bb
--- /dev/null
+++ b/Help/module/FindSDL_net.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindSDL_net.cmake
diff --git a/Help/module/FindSDL_sound.rst b/Help/module/FindSDL_sound.rst
new file mode 100644
index 0000000..077edf7
--- /dev/null
+++ b/Help/module/FindSDL_sound.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindSDL_sound.cmake
diff --git a/Help/module/FindSDL_ttf.rst b/Help/module/FindSDL_ttf.rst
new file mode 100644
index 0000000..40c5ec4
--- /dev/null
+++ b/Help/module/FindSDL_ttf.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindSDL_ttf.cmake
diff --git a/Help/module/FindSQLite3.rst b/Help/module/FindSQLite3.rst
new file mode 100644
index 0000000..d1910e5
--- /dev/null
+++ b/Help/module/FindSQLite3.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindSQLite3.cmake
diff --git a/Help/module/FindSWIG.rst b/Help/module/FindSWIG.rst
new file mode 100644
index 0000000..9b25b94
--- /dev/null
+++ b/Help/module/FindSWIG.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindSWIG.cmake
diff --git a/Help/module/FindSelfPackers.rst b/Help/module/FindSelfPackers.rst
new file mode 100644
index 0000000..5f2c689
--- /dev/null
+++ b/Help/module/FindSelfPackers.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindSelfPackers.cmake
diff --git a/Help/module/FindSquish.rst b/Help/module/FindSquish.rst
new file mode 100644
index 0000000..dc2c86d
--- /dev/null
+++ b/Help/module/FindSquish.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindSquish.cmake
diff --git a/Help/module/FindSubversion.rst b/Help/module/FindSubversion.rst
new file mode 100644
index 0000000..aa15857
--- /dev/null
+++ b/Help/module/FindSubversion.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindSubversion.cmake
diff --git a/Help/module/FindTCL.rst b/Help/module/FindTCL.rst
new file mode 100644
index 0000000..cbd2035
--- /dev/null
+++ b/Help/module/FindTCL.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindTCL.cmake
diff --git a/Help/module/FindTIFF.rst b/Help/module/FindTIFF.rst
new file mode 100644
index 0000000..69f8ca5
--- /dev/null
+++ b/Help/module/FindTIFF.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindTIFF.cmake
diff --git a/Help/module/FindTclStub.rst b/Help/module/FindTclStub.rst
new file mode 100644
index 0000000..6cc5b2d
--- /dev/null
+++ b/Help/module/FindTclStub.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindTclStub.cmake
diff --git a/Help/module/FindTclsh.rst b/Help/module/FindTclsh.rst
new file mode 100644
index 0000000..23e7d6b
--- /dev/null
+++ b/Help/module/FindTclsh.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindTclsh.cmake
diff --git a/Help/module/FindThreads.rst b/Help/module/FindThreads.rst
new file mode 100644
index 0000000..91967a7
--- /dev/null
+++ b/Help/module/FindThreads.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindThreads.cmake
diff --git a/Help/module/FindUnixCommands.rst b/Help/module/FindUnixCommands.rst
new file mode 100644
index 0000000..9ad05ad
--- /dev/null
+++ b/Help/module/FindUnixCommands.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindUnixCommands.cmake
diff --git a/Help/module/FindVTK.rst b/Help/module/FindVTK.rst
new file mode 100644
index 0000000..3bc67c5
--- /dev/null
+++ b/Help/module/FindVTK.rst
@@ -0,0 +1,10 @@
+FindVTK
+-------
+
+This module no longer exists.
+
+This module existed in versions of CMake prior to 3.1, but became
+only a thin wrapper around ``find_package(VTK NO_MODULE)`` to
+provide compatibility for projects using long-outdated conventions.
+Now ``find_package(VTK)`` will search for ``VTKConfig.cmake``
+directly.
diff --git a/Help/module/FindVulkan.rst b/Help/module/FindVulkan.rst
new file mode 100644
index 0000000..adf824e
--- /dev/null
+++ b/Help/module/FindVulkan.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindVulkan.cmake
diff --git a/Help/module/FindWget.rst b/Help/module/FindWget.rst
new file mode 100644
index 0000000..06affd4
--- /dev/null
+++ b/Help/module/FindWget.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindWget.cmake
diff --git a/Help/module/FindWish.rst b/Help/module/FindWish.rst
new file mode 100644
index 0000000..76be4cf
--- /dev/null
+++ b/Help/module/FindWish.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindWish.cmake
diff --git a/Help/module/FindX11.rst b/Help/module/FindX11.rst
new file mode 100644
index 0000000..906efd7
--- /dev/null
+++ b/Help/module/FindX11.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindX11.cmake
diff --git a/Help/module/FindXCTest.rst b/Help/module/FindXCTest.rst
new file mode 100644
index 0000000..ff6273c
--- /dev/null
+++ b/Help/module/FindXCTest.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindXCTest.cmake
diff --git a/Help/module/FindXMLRPC.rst b/Help/module/FindXMLRPC.rst
new file mode 100644
index 0000000..5d11a0c
--- /dev/null
+++ b/Help/module/FindXMLRPC.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindXMLRPC.cmake
diff --git a/Help/module/FindXalanC.rst b/Help/module/FindXalanC.rst
new file mode 100644
index 0000000..b99d212
--- /dev/null
+++ b/Help/module/FindXalanC.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindXalanC.cmake
diff --git a/Help/module/FindXercesC.rst b/Help/module/FindXercesC.rst
new file mode 100644
index 0000000..4818071
--- /dev/null
+++ b/Help/module/FindXercesC.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindXercesC.cmake
diff --git a/Help/module/FindZLIB.rst b/Help/module/FindZLIB.rst
new file mode 100644
index 0000000..ded8634
--- /dev/null
+++ b/Help/module/FindZLIB.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindZLIB.cmake
diff --git a/Help/module/Findosg.rst b/Help/module/Findosg.rst
new file mode 100644
index 0000000..6b407ac
--- /dev/null
+++ b/Help/module/Findosg.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/Findosg.cmake
diff --git a/Help/module/FindosgAnimation.rst b/Help/module/FindosgAnimation.rst
new file mode 100644
index 0000000..f14a1e7
--- /dev/null
+++ b/Help/module/FindosgAnimation.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgAnimation.cmake
diff --git a/Help/module/FindosgDB.rst b/Help/module/FindosgDB.rst
new file mode 100644
index 0000000..9f72bc7
--- /dev/null
+++ b/Help/module/FindosgDB.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgDB.cmake
diff --git a/Help/module/FindosgFX.rst b/Help/module/FindosgFX.rst
new file mode 100644
index 0000000..0e1edfb
--- /dev/null
+++ b/Help/module/FindosgFX.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgFX.cmake
diff --git a/Help/module/FindosgGA.rst b/Help/module/FindosgGA.rst
new file mode 100644
index 0000000..562d73f
--- /dev/null
+++ b/Help/module/FindosgGA.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgGA.cmake
diff --git a/Help/module/FindosgIntrospection.rst b/Help/module/FindosgIntrospection.rst
new file mode 100644
index 0000000..53621a7
--- /dev/null
+++ b/Help/module/FindosgIntrospection.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgIntrospection.cmake
diff --git a/Help/module/FindosgManipulator.rst b/Help/module/FindosgManipulator.rst
new file mode 100644
index 0000000..b9d615d
--- /dev/null
+++ b/Help/module/FindosgManipulator.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgManipulator.cmake
diff --git a/Help/module/FindosgParticle.rst b/Help/module/FindosgParticle.rst
new file mode 100644
index 0000000..9cf191c
--- /dev/null
+++ b/Help/module/FindosgParticle.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgParticle.cmake
diff --git a/Help/module/FindosgPresentation.rst b/Help/module/FindosgPresentation.rst
new file mode 100644
index 0000000..cb47841
--- /dev/null
+++ b/Help/module/FindosgPresentation.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgPresentation.cmake
diff --git a/Help/module/FindosgProducer.rst b/Help/module/FindosgProducer.rst
new file mode 100644
index 0000000..c502851
--- /dev/null
+++ b/Help/module/FindosgProducer.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgProducer.cmake
diff --git a/Help/module/FindosgQt.rst b/Help/module/FindosgQt.rst
new file mode 100644
index 0000000..08c8704
--- /dev/null
+++ b/Help/module/FindosgQt.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgQt.cmake
diff --git a/Help/module/FindosgShadow.rst b/Help/module/FindosgShadow.rst
new file mode 100644
index 0000000..fbb22e1
--- /dev/null
+++ b/Help/module/FindosgShadow.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgShadow.cmake
diff --git a/Help/module/FindosgSim.rst b/Help/module/FindosgSim.rst
new file mode 100644
index 0000000..9e47b65
--- /dev/null
+++ b/Help/module/FindosgSim.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgSim.cmake
diff --git a/Help/module/FindosgTerrain.rst b/Help/module/FindosgTerrain.rst
new file mode 100644
index 0000000..dd401d8
--- /dev/null
+++ b/Help/module/FindosgTerrain.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgTerrain.cmake
diff --git a/Help/module/FindosgText.rst b/Help/module/FindosgText.rst
new file mode 100644
index 0000000..bb028fb
--- /dev/null
+++ b/Help/module/FindosgText.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgText.cmake
diff --git a/Help/module/FindosgUtil.rst b/Help/module/FindosgUtil.rst
new file mode 100644
index 0000000..bb11bdf
--- /dev/null
+++ b/Help/module/FindosgUtil.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgUtil.cmake
diff --git a/Help/module/FindosgViewer.rst b/Help/module/FindosgViewer.rst
new file mode 100644
index 0000000..5def375
--- /dev/null
+++ b/Help/module/FindosgViewer.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgViewer.cmake
diff --git a/Help/module/FindosgVolume.rst b/Help/module/FindosgVolume.rst
new file mode 100644
index 0000000..d836906
--- /dev/null
+++ b/Help/module/FindosgVolume.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgVolume.cmake
diff --git a/Help/module/FindosgWidget.rst b/Help/module/FindosgWidget.rst
new file mode 100644
index 0000000..bdd1135
--- /dev/null
+++ b/Help/module/FindosgWidget.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindosgWidget.cmake
diff --git a/Help/module/Findosg_functions.rst b/Help/module/Findosg_functions.rst
new file mode 100644
index 0000000..522e1ac
--- /dev/null
+++ b/Help/module/Findosg_functions.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/Findosg_functions.cmake
diff --git a/Help/module/FindwxWidgets.rst b/Help/module/FindwxWidgets.rst
new file mode 100644
index 0000000..519beb7
--- /dev/null
+++ b/Help/module/FindwxWidgets.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindwxWidgets.cmake
diff --git a/Help/module/FindwxWindows.rst b/Help/module/FindwxWindows.rst
new file mode 100644
index 0000000..35c9728
--- /dev/null
+++ b/Help/module/FindwxWindows.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindwxWindows.cmake
diff --git a/Help/module/FortranCInterface.rst b/Help/module/FortranCInterface.rst
new file mode 100644
index 0000000..7afcf15
--- /dev/null
+++ b/Help/module/FortranCInterface.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FortranCInterface.cmake
diff --git a/Help/module/GNUInstallDirs.rst b/Help/module/GNUInstallDirs.rst
new file mode 100644
index 0000000..79d3570
--- /dev/null
+++ b/Help/module/GNUInstallDirs.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/GNUInstallDirs.cmake
diff --git a/Help/module/GenerateExportHeader.rst b/Help/module/GenerateExportHeader.rst
new file mode 100644
index 0000000..115713e
--- /dev/null
+++ b/Help/module/GenerateExportHeader.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/GenerateExportHeader.cmake
diff --git a/Help/module/GetPrerequisites.rst b/Help/module/GetPrerequisites.rst
new file mode 100644
index 0000000..84b20c8
--- /dev/null
+++ b/Help/module/GetPrerequisites.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/GetPrerequisites.cmake
diff --git a/Help/module/GoogleTest.rst b/Help/module/GoogleTest.rst
new file mode 100644
index 0000000..3d4cc97
--- /dev/null
+++ b/Help/module/GoogleTest.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/GoogleTest.cmake
diff --git a/Help/module/InstallRequiredSystemLibraries.rst b/Help/module/InstallRequiredSystemLibraries.rst
new file mode 100644
index 0000000..5ea9af3
--- /dev/null
+++ b/Help/module/InstallRequiredSystemLibraries.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/InstallRequiredSystemLibraries.cmake
diff --git a/Help/module/MacroAddFileDependencies.rst b/Help/module/MacroAddFileDependencies.rst
new file mode 100644
index 0000000..5f0bf6b
--- /dev/null
+++ b/Help/module/MacroAddFileDependencies.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/MacroAddFileDependencies.cmake
diff --git a/Help/module/ProcessorCount.rst b/Help/module/ProcessorCount.rst
new file mode 100644
index 0000000..0149d09
--- /dev/null
+++ b/Help/module/ProcessorCount.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/ProcessorCount.cmake
diff --git a/Help/module/SelectLibraryConfigurations.rst b/Help/module/SelectLibraryConfigurations.rst
new file mode 100644
index 0000000..14fd6f8
--- /dev/null
+++ b/Help/module/SelectLibraryConfigurations.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/SelectLibraryConfigurations.cmake
diff --git a/Help/module/SquishTestScript.rst b/Help/module/SquishTestScript.rst
new file mode 100644
index 0000000..47da404
--- /dev/null
+++ b/Help/module/SquishTestScript.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/SquishTestScript.cmake
diff --git a/Help/module/TestBigEndian.rst b/Help/module/TestBigEndian.rst
new file mode 100644
index 0000000..f9e4d2f
--- /dev/null
+++ b/Help/module/TestBigEndian.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/TestBigEndian.cmake
diff --git a/Help/module/TestCXXAcceptsFlag.rst b/Help/module/TestCXXAcceptsFlag.rst
new file mode 100644
index 0000000..ee3d70a
--- /dev/null
+++ b/Help/module/TestCXXAcceptsFlag.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/TestCXXAcceptsFlag.cmake
diff --git a/Help/module/TestForANSIForScope.rst b/Help/module/TestForANSIForScope.rst
new file mode 100644
index 0000000..00d9238
--- /dev/null
+++ b/Help/module/TestForANSIForScope.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/TestForANSIForScope.cmake
diff --git a/Help/module/TestForANSIStreamHeaders.rst b/Help/module/TestForANSIStreamHeaders.rst
new file mode 100644
index 0000000..212a30b
--- /dev/null
+++ b/Help/module/TestForANSIStreamHeaders.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/TestForANSIStreamHeaders.cmake
diff --git a/Help/module/TestForSSTREAM.rst b/Help/module/TestForSSTREAM.rst
new file mode 100644
index 0000000..d154751
--- /dev/null
+++ b/Help/module/TestForSSTREAM.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/TestForSSTREAM.cmake
diff --git a/Help/module/TestForSTDNamespace.rst b/Help/module/TestForSTDNamespace.rst
new file mode 100644
index 0000000..ad989e3
--- /dev/null
+++ b/Help/module/TestForSTDNamespace.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/TestForSTDNamespace.cmake
diff --git a/Help/module/UseEcos.rst b/Help/module/UseEcos.rst
new file mode 100644
index 0000000..0e57868
--- /dev/null
+++ b/Help/module/UseEcos.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/UseEcos.cmake
diff --git a/Help/module/UseJava.rst b/Help/module/UseJava.rst
new file mode 100644
index 0000000..fa2f1bd
--- /dev/null
+++ b/Help/module/UseJava.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/UseJava.cmake
diff --git a/Help/module/UseJavaClassFilelist.rst b/Help/module/UseJavaClassFilelist.rst
new file mode 100644
index 0000000..29949be
--- /dev/null
+++ b/Help/module/UseJavaClassFilelist.rst
@@ -0,0 +1,6 @@
+UseJavaClassFilelist
+--------------------
+
+.. versionchanged:: 3.20
+ This module was previously documented by mistake and was never meant for
+ direct inclusion by project code. See the :module:`UseJava` module.
diff --git a/Help/module/UseJavaSymlinks.rst b/Help/module/UseJavaSymlinks.rst
new file mode 100644
index 0000000..1058a68
--- /dev/null
+++ b/Help/module/UseJavaSymlinks.rst
@@ -0,0 +1,6 @@
+UseJavaSymlinks
+---------------
+
+.. versionchanged:: 3.20
+ This module was previously documented by mistake and was never meant for
+ direct inclusion by project code. See the :module:`UseJava` module.
diff --git a/Help/module/UsePkgConfig.rst b/Help/module/UsePkgConfig.rst
new file mode 100644
index 0000000..668f766
--- /dev/null
+++ b/Help/module/UsePkgConfig.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/UsePkgConfig.cmake
diff --git a/Help/module/UseSWIG.rst b/Help/module/UseSWIG.rst
new file mode 100644
index 0000000..0007c35
--- /dev/null
+++ b/Help/module/UseSWIG.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/UseSWIG.cmake
diff --git a/Help/module/Use_wxWindows.rst b/Help/module/Use_wxWindows.rst
new file mode 100644
index 0000000..a489e98
--- /dev/null
+++ b/Help/module/Use_wxWindows.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/Use_wxWindows.cmake
diff --git a/Help/module/UsewxWidgets.rst b/Help/module/UsewxWidgets.rst
new file mode 100644
index 0000000..6829c2d
--- /dev/null
+++ b/Help/module/UsewxWidgets.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/UsewxWidgets.cmake
diff --git a/Help/module/WriteBasicConfigVersionFile.rst b/Help/module/WriteBasicConfigVersionFile.rst
new file mode 100644
index 0000000..c637d5d
--- /dev/null
+++ b/Help/module/WriteBasicConfigVersionFile.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/WriteBasicConfigVersionFile.cmake
diff --git a/Help/module/WriteCompilerDetectionHeader.rst b/Help/module/WriteCompilerDetectionHeader.rst
new file mode 100644
index 0000000..4c81b48
--- /dev/null
+++ b/Help/module/WriteCompilerDetectionHeader.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/WriteCompilerDetectionHeader.cmake
diff --git a/Help/policy/CMP0000.rst b/Help/policy/CMP0000.rst
new file mode 100644
index 0000000..aecfa71
--- /dev/null
+++ b/Help/policy/CMP0000.rst
@@ -0,0 +1,34 @@
+CMP0000
+-------
+
+A minimum required CMake version must be specified.
+
+CMake requires that projects specify the version of CMake to which
+they have been written. This policy has been put in place so users
+trying to build the project may be told when they need to update their
+CMake. Specifying a version also helps the project build with CMake
+versions newer than that specified. Use the :command:`cmake_minimum_required`
+command at the top of your main ``CMakeLists.txt`` file:
+
+::
+
+ cmake_minimum_required(VERSION <major>.<minor>)
+
+where ``<major>.<minor>`` is the version of CMake you want to support
+(such as ``3.14``). The command will ensure that at least the given
+version of CMake is running and help newer versions be compatible with
+the project. See documentation of :command:`cmake_minimum_required` for
+details.
+
+Note that the command invocation must appear in the ``CMakeLists.txt``
+file itself; a call in an included file is not sufficient. However,
+the :command:`cmake_policy` command may be called to set policy ``CMP0000``
+to ``OLD`` or ``NEW`` behavior explicitly. The ``OLD`` behavior is to
+silently ignore the missing invocation. The ``NEW`` behavior is to issue
+an error instead of a warning. An included file may set ``CMP0000``
+explicitly to affect how this policy is enforced for the main
+``CMakeLists.txt`` file.
+
+This policy was introduced in CMake version 2.6.0.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0001.rst b/Help/policy/CMP0001.rst
new file mode 100644
index 0000000..6fa64d9
--- /dev/null
+++ b/Help/policy/CMP0001.rst
@@ -0,0 +1,21 @@
+CMP0001
+-------
+
+``CMAKE_BACKWARDS_COMPATIBILITY`` should no longer be used.
+
+The behavior is to check ``CMAKE_BACKWARDS_COMPATIBILITY`` and present
+it to the user. The ``NEW`` behavior is to ignore
+CMAKE_BACKWARDS_COMPATIBILITY completely.
+
+In CMake 2.4 and below the variable ``CMAKE_BACKWARDS_COMPATIBILITY`` was
+used to request compatibility with earlier versions of CMake. In
+CMake 2.6 and above all compatibility issues are handled by policies
+and the :command:`cmake_policy` command. However, CMake must still check
+``CMAKE_BACKWARDS_COMPATIBILITY`` for projects written for CMake 2.4 and
+below.
+
+This policy was introduced in CMake version 2.6.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0002.rst b/Help/policy/CMP0002.rst
new file mode 100644
index 0000000..dc68d51
--- /dev/null
+++ b/Help/policy/CMP0002.rst
@@ -0,0 +1,28 @@
+CMP0002
+-------
+
+Logical target names must be globally unique.
+
+Targets names created with :command:`add_executable`, :command:`add_library`, or
+:command:`add_custom_target` are logical build target names. Logical target
+names must be globally unique because:
+
+::
+
+ - Unique names may be referenced unambiguously both in CMake
+ code and on make tool command lines.
+ - Logical names are used by Xcode and VS IDE generators
+ to produce meaningful project names for the targets.
+
+The logical name of executable and library targets does not have to
+correspond to the physical file names built. Consider using the
+:prop_tgt:`OUTPUT_NAME` target property to create two targets with the same
+physical name while keeping logical names distinct. Custom targets
+must simply have globally unique names (unless one uses the global
+property :prop_gbl:`ALLOW_DUPLICATE_CUSTOM_TARGETS` with a Makefiles generator).
+
+This policy was introduced in CMake version 2.6.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0003.rst b/Help/policy/CMP0003.rst
new file mode 100644
index 0000000..dd90883
--- /dev/null
+++ b/Help/policy/CMP0003.rst
@@ -0,0 +1,104 @@
+CMP0003
+-------
+
+Libraries linked via full path no longer produce linker search paths.
+
+This policy affects how libraries whose full paths are NOT known are
+found at link time, but was created due to a change in how CMake deals
+with libraries whose full paths are known. Consider the code
+
+::
+
+ target_link_libraries(myexe /path/to/libA.so)
+
+CMake 2.4 and below implemented linking to libraries whose full paths
+are known by splitting them on the link line into separate components
+consisting of the linker search path and the library name. The
+example code might have produced something like
+
+::
+
+ ... -L/path/to -lA ...
+
+in order to link to library A. An analysis was performed to order
+multiple link directories such that the linker would find library A in
+the desired location, but there are cases in which this does not work.
+CMake versions 2.6 and above use the more reliable approach of passing
+the full path to libraries directly to the linker in most cases. The
+example code now produces something like
+
+::
+
+ ... /path/to/libA.so ....
+
+Unfortunately this change can break code like
+
+::
+
+ target_link_libraries(myexe /path/to/libA.so B)
+
+where ``B`` is meant to find ``/path/to/libB.so``. This code is wrong
+because the user is asking the linker to find library B but has not
+provided a linker search path (which may be added with the
+link_directories command). However, with the old linking
+implementation the code would work accidentally because the linker
+search path added for library A allowed library B to be found.
+
+In order to support projects depending on linker search paths added by
+linking to libraries with known full paths, the ``OLD`` behavior for this
+policy will add the linker search paths even though they are not
+needed for their own libraries. When this policy is set to ``OLD``, CMake
+will produce a link line such as
+
+::
+
+ ... -L/path/to /path/to/libA.so -lB ...
+
+which will allow library B to be found as it was previously. When
+this policy is set to NEW, CMake will produce a link line such as
+
+::
+
+ ... /path/to/libA.so -lB ...
+
+which more accurately matches what the project specified.
+
+The setting for this policy used when generating the link line is that
+in effect when the target is created by an add_executable or
+add_library command. For the example described above, the code
+
+::
+
+ cmake_policy(SET CMP0003 OLD) # or cmake_policy(VERSION 2.4)
+ add_executable(myexe myexe.c)
+ target_link_libraries(myexe /path/to/libA.so B)
+
+will work and suppress the warning for this policy. It may also be
+updated to work with the corrected linking approach:
+
+::
+
+ cmake_policy(SET CMP0003 NEW) # or cmake_policy(VERSION 2.6)
+ link_directories(/path/to) # needed to find library B
+ add_executable(myexe myexe.c)
+ target_link_libraries(myexe /path/to/libA.so B)
+
+Even better, library B may be specified with a full path:
+
+::
+
+ add_executable(myexe myexe.c)
+ target_link_libraries(myexe /path/to/libA.so /path/to/libB.so)
+
+When all items on the link line have known paths CMake does not check
+this policy so it has no effect.
+
+Note that the warning for this policy will be issued for at most one
+target. This avoids flooding users with messages for every target
+when setting the policy once will probably fix all targets.
+
+This policy was introduced in CMake version 2.6.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0004.rst b/Help/policy/CMP0004.rst
new file mode 100644
index 0000000..be6d307
--- /dev/null
+++ b/Help/policy/CMP0004.rst
@@ -0,0 +1,26 @@
+CMP0004
+-------
+
+Libraries linked may not have leading or trailing whitespace.
+
+CMake versions 2.4 and below silently removed leading and trailing
+whitespace from libraries linked with code like
+
+::
+
+ target_link_libraries(myexe " A ")
+
+This could lead to subtle errors in user projects.
+
+The ``OLD`` behavior for this policy is to silently remove leading and
+trailing whitespace. The ``NEW`` behavior for this policy is to diagnose
+the existence of such whitespace as an error. The setting for this
+policy used when checking the library names is that in effect when the
+target is created by an :command:`add_executable` or :command:`add_library`
+command.
+
+This policy was introduced in CMake version 2.6.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0005.rst b/Help/policy/CMP0005.rst
new file mode 100644
index 0000000..59567d5
--- /dev/null
+++ b/Help/policy/CMP0005.rst
@@ -0,0 +1,26 @@
+CMP0005
+-------
+
+Preprocessor definition values are now escaped automatically.
+
+This policy determines whether or not CMake should generate escaped
+preprocessor definition values added via add_definitions. CMake
+versions 2.4 and below assumed that only trivial values would be given
+for macros in add_definitions calls. It did not attempt to escape
+non-trivial values such as string literals in generated build rules.
+CMake versions 2.6 and above support escaping of most values, but
+cannot assume the user has not added escapes already in an attempt to
+work around limitations in earlier versions.
+
+The ``OLD`` behavior for this policy is to place definition values given
+to add_definitions directly in the generated build rules without
+attempting to escape anything. The ``NEW`` behavior for this policy is to
+generate correct escapes for all native build tools automatically.
+See documentation of the ``COMPILE_DEFINITIONS`` target property for
+limitations of the escaping implementation.
+
+This policy was introduced in CMake version 2.6.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0006.rst b/Help/policy/CMP0006.rst
new file mode 100644
index 0000000..181958b
--- /dev/null
+++ b/Help/policy/CMP0006.rst
@@ -0,0 +1,24 @@
+CMP0006
+-------
+
+Installing :prop_tgt:`MACOSX_BUNDLE` targets requires a ``BUNDLE DESTINATION``.
+
+This policy determines whether the :command:`install(TARGETS)` command must be
+given a ``BUNDLE DESTINATION`` when asked to install a target with the
+:prop_tgt:`MACOSX_BUNDLE` property set. CMake 2.4 and below did not distinguish
+application bundles from normal executables when installing targets.
+CMake 2.6 provides a ``BUNDLE`` option to the :command:`install(TARGETS)`
+command that specifies rules specific to application bundles on the Mac.
+Projects should use this option when installing a target with the
+:prop_tgt:`MACOSX_BUNDLE` property set.
+
+The ``OLD`` behavior for this policy is to fall back to the
+``RUNTIME DESTINATION`` if a ``BUNDLE DESTINATION`` is not given. The ``NEW``
+behavior for this policy is to produce an error if a bundle target is installed
+without a ``BUNDLE DESTINATION``.
+
+This policy was introduced in CMake version 2.6.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0007.rst b/Help/policy/CMP0007.rst
new file mode 100644
index 0000000..1006ed3
--- /dev/null
+++ b/Help/policy/CMP0007.rst
@@ -0,0 +1,17 @@
+CMP0007
+-------
+
+list command no longer ignores empty elements.
+
+This policy determines whether the list command will ignore empty
+elements in the list. CMake 2.4 and below list commands ignored all
+empty elements in the list. For example, ``a;b;;c`` would have length 3
+and not 4. The ``OLD`` behavior for this policy is to ignore empty list
+elements. The ``NEW`` behavior for this policy is to correctly count
+empty elements in a list.
+
+This policy was introduced in CMake version 2.6.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0008.rst b/Help/policy/CMP0008.rst
new file mode 100644
index 0000000..18ede82
--- /dev/null
+++ b/Help/policy/CMP0008.rst
@@ -0,0 +1,35 @@
+CMP0008
+-------
+
+Libraries linked by full-path must have a valid library file name.
+
+In CMake 2.4 and below it is possible to write code like
+
+::
+
+ target_link_libraries(myexe /full/path/to/somelib)
+
+where ``somelib`` is supposed to be a valid library file name such as
+``libsomelib.a`` or ``somelib.lib``. For Makefile generators this
+produces an error at build time because the dependency on the full
+path cannot be found. For :ref:`Visual Studio Generators` IDE
+and :generator:`Xcode` generators this used to
+work by accident because CMake would always split off the library
+directory and ask the linker to search for the library by name
+(``-lsomelib`` or ``somelib.lib``). Despite the failure with Makefiles, some
+projects have code like this and build only with Visual Studio and/or Xcode.
+This version of CMake prefers to pass the full path directly to the
+native build tool, which will fail in this case because it does not
+name a valid library file.
+
+This policy determines what to do with full paths that do not appear
+to name a valid library file. The ``OLD`` behavior for this policy is to
+split the library name from the path and ask the linker to search for
+it. The ``NEW`` behavior for this policy is to trust the given path and
+pass it directly to the native build tool unchanged.
+
+This policy was introduced in CMake version 2.6.1. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0009.rst b/Help/policy/CMP0009.rst
new file mode 100644
index 0000000..27cfde0
--- /dev/null
+++ b/Help/policy/CMP0009.rst
@@ -0,0 +1,21 @@
+CMP0009
+-------
+
+FILE GLOB_RECURSE calls should not follow symlinks by default.
+
+In CMake 2.6.1 and below, :command:`file(GLOB_RECURSE)` calls would follow
+through symlinks, sometimes coming up with unexpectedly large result sets
+because of symlinks to top level directories that contain hundreds of
+thousands of files.
+
+This policy determines whether or not to follow symlinks encountered
+during a :command:`file(GLOB_RECURSE)` call. The ``OLD`` behavior for this
+policy is to follow the symlinks. The ``NEW`` behavior for this policy is not
+to follow the symlinks by default, but only if ``FOLLOW_SYMLINKS`` is given
+as an additional argument to the ``FILE`` command.
+
+This policy was introduced in CMake version 2.6.2. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0010.rst b/Help/policy/CMP0010.rst
new file mode 100644
index 0000000..cfae498
--- /dev/null
+++ b/Help/policy/CMP0010.rst
@@ -0,0 +1,20 @@
+CMP0010
+-------
+
+Bad variable reference syntax is an error.
+
+In CMake 2.6.2 and below, incorrect variable reference syntax such as
+a missing close-brace (``${FOO``) was reported but did not stop
+processing of CMake code. This policy determines whether a bad
+variable reference is an error. The ``OLD`` behavior for this policy is
+to warn about the error, leave the string untouched, and continue.
+The ``NEW`` behavior for this policy is to report an error.
+
+If :policy:`CMP0053` is set to ``NEW``, this policy has no effect
+and is treated as always being ``NEW``.
+
+This policy was introduced in CMake version 2.6.3. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0011.rst b/Help/policy/CMP0011.rst
new file mode 100644
index 0000000..257415c
--- /dev/null
+++ b/Help/policy/CMP0011.rst
@@ -0,0 +1,25 @@
+CMP0011
+-------
+
+Included scripts do automatic :command:`cmake_policy` PUSH and POP.
+
+In CMake 2.6.2 and below, CMake Policy settings in scripts loaded by
+the :command:`include` and :command:`find_package` commands would affect
+the includer. Explicit invocations of ``cmake_policy(PUSH)`` and
+``cmake_policy(POP)`` were required to isolate policy changes and protect
+the includer. While some scripts intend to affect the policies of their
+includer, most do not. In CMake 2.6.3 and above, :command:`include` and
+:command:`find_package` by default ``PUSH`` and ``POP`` an entry on
+the policy stack around an included
+script, but provide a ``NO_POLICY_SCOPE`` option to disable it. This
+policy determines whether or not to imply ``NO_POLICY_SCOPE`` for
+compatibility. The ``OLD`` behavior for this policy is to imply
+``NO_POLICY_SCOPE`` for :command:`include` and :command:`find_package` commands.
+The ``NEW`` behavior for this policy is to allow the commands to do
+their default cmake_policy ``PUSH`` and ``POP``.
+
+This policy was introduced in CMake version 2.6.3. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0012.rst b/Help/policy/CMP0012.rst
new file mode 100644
index 0000000..17ec8d3
--- /dev/null
+++ b/Help/policy/CMP0012.rst
@@ -0,0 +1,28 @@
+CMP0012
+-------
+
+:command:`if` recognizes numbers and boolean constants.
+
+In CMake versions 2.6.4 and lower the :command:`if` command implicitly
+dereferenced arguments corresponding to variables, even those named
+like numbers or boolean constants, except for ``0`` and ``1``. Numbers and
+boolean constants such as ``true``, ``false``, ``yes``, ``no``, ``on``,
+``off``, ``y``, ``n``, ``notfound``, ``ignore`` (all case insensitive)
+were recognized in some cases but not all. For example, the code ``if(TRUE)``
+might have evaluated as ``false``.
+Numbers such as 2 were recognized only in boolean expressions
+like ``if(NOT 2)`` (leading to ``false``) but not as a single-argument like
+``if(2)`` (also leading to ``false``). Later versions of CMake prefer to
+treat numbers and boolean constants literally, so they should not be
+used as variable names.
+
+The ``OLD`` behavior for this policy is to implicitly dereference
+variables named like numbers and boolean constants. The ``NEW`` behavior
+for this policy is to recognize numbers and boolean constants without
+dereferencing variables with such names.
+
+This policy was introduced in CMake version 2.8.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0013.rst b/Help/policy/CMP0013.rst
new file mode 100644
index 0000000..dbd67a1
--- /dev/null
+++ b/Help/policy/CMP0013.rst
@@ -0,0 +1,21 @@
+CMP0013
+-------
+
+Duplicate binary directories are not allowed.
+
+CMake 2.6.3 and below silently permitted add_subdirectory() calls to
+create the same binary directory multiple times. During build system
+generation files would be written and then overwritten in the build
+tree and could lead to strange behavior. CMake 2.6.4 and above
+explicitly detect duplicate binary directories. CMake 2.6.4 always
+considers this case an error. In CMake 2.8.0 and above this policy
+determines whether or not the case is an error. The ``OLD`` behavior for
+this policy is to allow duplicate binary directories. The NEW
+behavior for this policy is to disallow duplicate binary directories
+with an error.
+
+This policy was introduced in CMake version 2.8.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0014.rst b/Help/policy/CMP0014.rst
new file mode 100644
index 0000000..331dde5
--- /dev/null
+++ b/Help/policy/CMP0014.rst
@@ -0,0 +1,17 @@
+CMP0014
+-------
+
+Input directories must have ``CMakeLists.txt``.
+
+CMake versions before 2.8 silently ignored missing ``CMakeLists.txt``
+files in directories referenced by :command:`add_subdirectory` or :command:`subdirs`,
+treating them as if present but empty. In CMake 2.8.0 and above this
+:command:`cmake_policy` determines whether or not the case is an error.
+The ``OLD`` behavior for this policy is to silently ignore the problem.
+The ``NEW`` behavior for this policy is to report an error.
+
+This policy was introduced in CMake version 2.8.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0015.rst b/Help/policy/CMP0015.rst
new file mode 100644
index 0000000..90d5203
--- /dev/null
+++ b/Help/policy/CMP0015.rst
@@ -0,0 +1,19 @@
+CMP0015
+-------
+
+ :command:`link_directories` treats paths relative to the source dir.
+
+In CMake 2.8.0 and lower the :command:`link_directories` command passed
+relative paths unchanged to the linker. In CMake 2.8.1 and above the
+:command:`link_directories` command prefers to interpret relative paths with
+respect to ``CMAKE_CURRENT_SOURCE_DIR``, which is consistent with
+:command:`include_directories` and other commands. The ``OLD`` behavior for
+this policy is to use relative paths verbatim in the linker command. The
+``NEW`` behavior for this policy is to convert relative paths to absolute
+paths by appending the relative path to ``CMAKE_CURRENT_SOURCE_DIR``.
+
+This policy was introduced in CMake version 2.8.1. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0016.rst b/Help/policy/CMP0016.rst
new file mode 100644
index 0000000..026d02a
--- /dev/null
+++ b/Help/policy/CMP0016.rst
@@ -0,0 +1,16 @@
+CMP0016
+-------
+
+:command:`target_link_libraries` reports error if its only argument
+is not a target.
+
+In CMake 2.8.2 and lower the :command:`target_link_libraries` command silently
+ignored if it was called with only one argument, and this argument
+wasn't a valid target. In CMake 2.8.3 and above it reports an error
+in this case.
+
+This policy was introduced in CMake version 2.8.3. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0017.rst b/Help/policy/CMP0017.rst
new file mode 100644
index 0000000..ca4664e
--- /dev/null
+++ b/Help/policy/CMP0017.rst
@@ -0,0 +1,21 @@
+CMP0017
+-------
+
+Prefer files from the CMake module directory when including from there.
+
+Starting with CMake 2.8.4, if a cmake-module shipped with CMake (i.e.
+located in the CMake module directory) calls :command:`include` or
+:command:`find_package`, the files located in the CMake module directory are
+preferred over the files in :variable:`CMAKE_MODULE_PATH`. This makes sure
+that the modules belonging to CMake always get those files included which
+they expect, and against which they were developed and tested. In all
+other cases, the files found in :variable:`CMAKE_MODULE_PATH` still take
+precedence over the ones in the CMake module directory. The ``OLD``
+behavior is to always prefer files from CMAKE_MODULE_PATH over files
+from the CMake modules directory.
+
+This policy was introduced in CMake version 2.8.4. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0018.rst b/Help/policy/CMP0018.rst
new file mode 100644
index 0000000..6248406
--- /dev/null
+++ b/Help/policy/CMP0018.rst
@@ -0,0 +1,35 @@
+CMP0018
+-------
+
+Ignore ``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` variable.
+
+CMake 2.8.8 and lower compiled sources in ``SHARED`` and ``MODULE`` libraries
+using the value of the undocumented ``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS``
+platform variable. The variable contained platform-specific flags
+needed to compile objects for shared libraries. Typically it included
+a flag such as ``-fPIC`` for position independent code but also included
+other flags needed on certain platforms. CMake 2.8.9 and higher
+prefer instead to use the :prop_tgt:`POSITION_INDEPENDENT_CODE` target
+property to determine what targets should be position independent, and new
+undocumented platform variables to select flags while ignoring
+``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` completely.
+
+The default for either approach produces identical compilation flags,
+but if a project modifies ``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` from its
+original value this policy determines which approach to use.
+
+The ``OLD`` behavior for this policy is to ignore the
+:prop_tgt:`POSITION_INDEPENDENT_CODE` property for all targets and use the
+modified value of ``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` for ``SHARED`` and
+``MODULE`` libraries.
+
+The ``NEW`` behavior for this policy is to ignore
+``CMAKE_SHARED_LIBRARY_<Lang>_FLAGS`` whether it is modified or not and
+honor the :prop_tgt:`POSITION_INDEPENDENT_CODE` target property.
+
+This policy was introduced in CMake version 2.8.9. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0019.rst b/Help/policy/CMP0019.rst
new file mode 100644
index 0000000..682dcdf
--- /dev/null
+++ b/Help/policy/CMP0019.rst
@@ -0,0 +1,22 @@
+CMP0019
+-------
+
+Do not re-expand variables in include and link information.
+
+CMake 2.8.10 and lower re-evaluated values given to the
+include_directories, link_directories, and link_libraries commands to
+expand any leftover variable references at the end of the
+configuration step. This was for strict compatibility with VERY early
+CMake versions because all variable references are now normally
+evaluated during CMake language processing. CMake 2.8.11 and higher
+prefer to skip the extra evaluation.
+
+The ``OLD`` behavior for this policy is to re-evaluate the values for
+strict compatibility. The ``NEW`` behavior for this policy is to leave
+the values untouched.
+
+This policy was introduced in CMake version 2.8.11. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0020.rst b/Help/policy/CMP0020.rst
new file mode 100644
index 0000000..6d27684
--- /dev/null
+++ b/Help/policy/CMP0020.rst
@@ -0,0 +1,27 @@
+CMP0020
+-------
+
+Automatically link Qt executables to ``qtmain`` target on Windows.
+
+CMake 2.8.10 and lower required users of Qt to always specify a link
+dependency to the ``qtmain.lib`` static library manually on Windows.
+CMake 2.8.11 gained the ability to evaluate generator expressions
+while determining the link dependencies from ``IMPORTED`` targets. This
+allows CMake itself to automatically link executables which link to Qt
+to the ``qtmain.lib`` library when using ``IMPORTED`` Qt targets. For
+applications already linking to ``qtmain.lib``, this should have little
+impact. For applications which supply their own alternative WinMain
+implementation and for applications which use the QAxServer library,
+this automatic linking will need to be disabled as per the
+documentation.
+
+The ``OLD`` behavior for this policy is not to link executables to
+``qtmain.lib`` automatically when they link to the QtCore ``IMPORTED`` target.
+The ``NEW`` behavior for this policy is to link executables to ``qtmain.lib``
+automatically when they link to QtCore ``IMPORTED`` target.
+
+This policy was introduced in CMake version 2.8.11. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0021.rst b/Help/policy/CMP0021.rst
new file mode 100644
index 0000000..937b106
--- /dev/null
+++ b/Help/policy/CMP0021.rst
@@ -0,0 +1,21 @@
+CMP0021
+-------
+
+Fatal error on relative paths in :prop_tgt:`INCLUDE_DIRECTORIES` target
+property.
+
+CMake 2.8.10.2 and lower allowed the :prop_tgt:`INCLUDE_DIRECTORIES` target
+property to contain relative paths. The base path for such relative
+entries is not well defined. CMake 2.8.12 issues a ``FATAL_ERROR`` if the
+:prop_tgt:`INCLUDE_DIRECTORIES` property contains a relative path.
+
+The ``OLD`` behavior for this policy is not to warn about relative paths
+in the ``INCLUDE_DIRECTORIES`` target property. The ``NEW`` behavior for this
+policy is to issue a ``FATAL_ERROR`` if ``INCLUDE_DIRECTORIES`` contains a
+relative path.
+
+This policy was introduced in CMake version 2.8.12. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0022.rst b/Help/policy/CMP0022.rst
new file mode 100644
index 0000000..be60e37
--- /dev/null
+++ b/Help/policy/CMP0022.rst
@@ -0,0 +1,39 @@
+CMP0022
+-------
+
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` defines the link interface.
+
+CMake 2.8.11 constructed the 'link interface' of a target from
+properties matching ``(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)?``.
+The modern way to specify config-sensitive content is to use generator
+expressions and the ``IMPORTED_`` prefix makes uniform processing of the
+link interface with generator expressions impossible. The
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` target property was introduced as a
+replacement in CMake 2.8.12. This new property is named consistently
+with the ``INTERFACE_COMPILE_DEFINITIONS``, ``INTERFACE_INCLUDE_DIRECTORIES``
+and ``INTERFACE_COMPILE_OPTIONS`` properties. For in-build targets, CMake
+will use the INTERFACE_LINK_LIBRARIES property as the source of the
+link interface only if policy ``CMP0022`` is ``NEW``. When exporting a target
+which has this policy set to ``NEW``, only the :prop_tgt:`INTERFACE_LINK_LIBRARIES`
+property will be processed and generated for the ``IMPORTED`` target by
+default. A new option to the :command:`install(EXPORT)` and export commands
+allows export of the old-style properties for compatibility with
+downstream users of CMake versions older than 2.8.12. The
+:command:`target_link_libraries` command will no longer populate the properties
+matching ``LINK_INTERFACE_LIBRARIES(_<CONFIG>)?`` if this policy is ``NEW``.
+
+Warning-free future-compatible code which works with CMake 2.8.7 onwards
+can be written by using the ``LINK_PRIVATE`` and ``LINK_PUBLIC`` keywords
+of :command:`target_link_libraries`.
+
+The ``OLD`` behavior for this policy is to ignore the
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` property for in-build targets.
+The ``NEW`` behavior for this policy is to use the ``INTERFACE_LINK_LIBRARIES``
+property for in-build targets, and ignore the old properties matching
+``(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)?``.
+
+This policy was introduced in CMake version 2.8.12. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0023.rst b/Help/policy/CMP0023.rst
new file mode 100644
index 0000000..3c72c81
--- /dev/null
+++ b/Help/policy/CMP0023.rst
@@ -0,0 +1,35 @@
+CMP0023
+-------
+
+Plain and keyword :command:`target_link_libraries` signatures cannot be mixed.
+
+CMake 2.8.12 introduced the :command:`target_link_libraries` signature using
+the ``PUBLIC``, ``PRIVATE``, and ``INTERFACE`` keywords to generalize the
+``LINK_PUBLIC`` and ``LINK_PRIVATE`` keywords introduced in CMake 2.8.7.
+Use of signatures with any of these keywords sets the link interface of a
+target explicitly, even if empty. This produces confusing behavior
+when used in combination with the historical behavior of the plain
+:command:`target_link_libraries` signature. For example, consider the code:
+
+::
+
+ target_link_libraries(mylib A)
+ target_link_libraries(mylib PRIVATE B)
+
+After the first line the link interface has not been set explicitly so
+CMake would use the link implementation, A, as the link interface.
+However, the second line sets the link interface to empty. In order
+to avoid this subtle behavior CMake now prefers to disallow mixing the
+plain and keyword signatures of :command:`target_link_libraries` for a single
+target.
+
+The ``OLD`` behavior for this policy is to allow keyword and plain
+:command:`target_link_libraries` signatures to be mixed. The ``NEW`` behavior for
+this policy is to not to allow mixing of the keyword and plain
+signatures.
+
+This policy was introduced in CMake version 2.8.12. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0024.rst b/Help/policy/CMP0024.rst
new file mode 100644
index 0000000..6e24b04
--- /dev/null
+++ b/Help/policy/CMP0024.rst
@@ -0,0 +1,25 @@
+CMP0024
+-------
+
+Disallow include export result.
+
+CMake 2.8.12 and lower allowed use of the :command:`include` command with the
+result of the :command:`export` command. This relies on the assumption that
+the :command:`export` command has an immediate effect at configure-time during
+a cmake run. Certain properties of targets are not fully determined
+until later at generate-time, such as the link language and complete
+list of link libraries. Future refactoring will change the effect of
+the :command:`export` command to be executed at generate-time. Use ``ALIAS``
+targets instead in cases where the goal is to refer to targets by
+another name.
+
+The ``OLD`` behavior for this policy is to allow including the result of
+an :command:`export` command. The ``NEW`` behavior for this policy is not to
+allow including the result of an :command:`export` command.
+
+This policy was introduced in CMake version 3.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0025.rst b/Help/policy/CMP0025.rst
new file mode 100644
index 0000000..ba5e1e9
--- /dev/null
+++ b/Help/policy/CMP0025.rst
@@ -0,0 +1,29 @@
+CMP0025
+-------
+
+Compiler id for Apple Clang is now ``AppleClang``.
+
+CMake 3.0 and above recognize that Apple Clang is a different compiler
+than upstream Clang and that they have different version numbers.
+CMake now prefers to present this to projects by setting the
+:variable:`CMAKE_<LANG>_COMPILER_ID` variable to ``AppleClang`` instead
+of ``Clang``. However, existing projects may assume the compiler id for
+Apple Clang is just ``Clang`` as it was in CMake versions prior to 3.0.
+Therefore this policy determines for Apple Clang which compiler id to
+report in the :variable:`CMAKE_<LANG>_COMPILER_ID` variable after
+language ``<LANG>`` is enabled by the :command:`project` or
+:command:`enable_language` command. The policy must be set prior
+to the invocation of either command.
+
+The ``OLD`` behavior for this policy is to use compiler id ``Clang``. The
+``NEW`` behavior for this policy is to use compiler id ``AppleClang``.
+
+This policy was introduced in CMake version 3.0. Use the
+:command:`cmake_policy` command to set this policy to ``OLD`` or ``NEW``
+explicitly. Unlike most policies, CMake version |release| does *not* warn
+by default when this policy is not set and simply uses ``OLD`` behavior.
+See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0025 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0026.rst b/Help/policy/CMP0026.rst
new file mode 100644
index 0000000..e08fd54
--- /dev/null
+++ b/Help/policy/CMP0026.rst
@@ -0,0 +1,29 @@
+CMP0026
+-------
+
+Disallow use of the LOCATION property for build targets.
+
+CMake 2.8.12 and lower allowed reading the :prop_tgt:`LOCATION` target
+property (and configuration-specific variants) to
+determine the eventual location of build targets. This relies on the
+assumption that all necessary information is available at
+configure-time to determine the final location and filename of the
+target. However, this property is not fully determined until later at
+generate-time. At generate time, the :genex:`$<TARGET_FILE>` generator
+expression can be used to determine the eventual :prop_tgt:`LOCATION` of a target
+output.
+
+Code which reads the :prop_tgt:`LOCATION` target property can be ported to
+use the :genex:`$<TARGET_FILE>` generator expression together with the
+:command:`file(GENERATE)` subcommand to generate a file containing
+the target location.
+
+The ``OLD`` behavior for this policy is to allow reading the :prop_tgt:`LOCATION`
+properties from build-targets. The ``NEW`` behavior for this policy is to
+not to allow reading the :prop_tgt:`LOCATION` properties from build-targets.
+
+This policy was introduced in CMake version 3.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0027.rst b/Help/policy/CMP0027.rst
new file mode 100644
index 0000000..bf7b6a9
--- /dev/null
+++ b/Help/policy/CMP0027.rst
@@ -0,0 +1,27 @@
+CMP0027
+-------
+
+Conditionally linked imported targets with missing include directories.
+
+CMake 2.8.11 introduced introduced the concept of
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`, and a check at cmake time that the
+entries in the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of an ``IMPORTED``
+target actually exist. CMake 2.8.11 also introduced generator expression
+support in the :command:`target_link_libraries` command. However, if an
+imported target is linked as a result of a generator expression evaluation, the
+entries in the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of that target were not
+checked for existence as they should be.
+
+The ``OLD`` behavior of this policy is to report a warning if an entry in
+the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of a generator-expression
+conditionally linked ``IMPORTED`` target does not exist.
+
+The ``NEW`` behavior of this policy is to report an error if an entry in
+the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of a generator-expression
+conditionally linked ``IMPORTED`` target does not exist.
+
+This policy was introduced in CMake version 3.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0028.rst b/Help/policy/CMP0028.rst
new file mode 100644
index 0000000..ab38229
--- /dev/null
+++ b/Help/policy/CMP0028.rst
@@ -0,0 +1,25 @@
+CMP0028
+-------
+
+Double colon in target name means ``ALIAS`` or ``IMPORTED`` target.
+
+CMake 2.8.12 and lower allowed the use of targets and files with double
+colons in :command:`target_link_libraries`, with some buildsystem generators.
+
+The use of double-colons is a common pattern used to namespace ``IMPORTED``
+targets and ``ALIAS`` targets. When computing the link dependencies of
+a target, the name of each dependency could either be a target, or a file
+on disk. Previously, if a target was not found with a matching name, the name
+was considered to refer to a file on disk. This can lead to confusing error
+messages if there is a typo in what should be a target name.
+
+The ``OLD`` behavior for this policy is to search for targets, then files on
+disk, even if the search term contains double-colons. The ``NEW`` behavior
+for this policy is to issue a ``FATAL_ERROR`` if a link dependency contains
+double-colons but is not an ``IMPORTED`` target or an ``ALIAS`` target.
+
+This policy was introduced in CMake version 3.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0029.rst b/Help/policy/CMP0029.rst
new file mode 100644
index 0000000..aa10b97
--- /dev/null
+++ b/Help/policy/CMP0029.rst
@@ -0,0 +1,12 @@
+CMP0029
+-------
+
+The :command:`subdir_depends` command should not be called.
+
+The implementation of this command has been empty since December 2001
+but was kept in CMake for compatibility for a long time.
+
+.. |disallowed_version| replace:: 3.0
+.. include:: DISALLOWED_COMMAND.txt
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0030.rst b/Help/policy/CMP0030.rst
new file mode 100644
index 0000000..81bbb84
--- /dev/null
+++ b/Help/policy/CMP0030.rst
@@ -0,0 +1,13 @@
+CMP0030
+-------
+
+The :command:`use_mangled_mesa` command should not be called.
+
+This command was created in September 2001 to support VTK before
+modern CMake language and custom command capabilities. VTK has
+not used it in years.
+
+.. |disallowed_version| replace:: 3.0
+.. include:: DISALLOWED_COMMAND.txt
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0031.rst b/Help/policy/CMP0031.rst
new file mode 100644
index 0000000..8c3eef6
--- /dev/null
+++ b/Help/policy/CMP0031.rst
@@ -0,0 +1,15 @@
+CMP0031
+-------
+
+The :command:`load_command` command should not be called.
+
+This command was added in August 2002 to allow projects to add
+arbitrary commands implemented in C or C++. However, it does
+not work when the toolchain in use does not match the ABI of
+the CMake process. It has been mostly superseded by the
+:command:`macro` and :command:`function` commands.
+
+.. |disallowed_version| replace:: 3.0
+.. include:: DISALLOWED_COMMAND.txt
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0032.rst b/Help/policy/CMP0032.rst
new file mode 100644
index 0000000..5c1fa4b
--- /dev/null
+++ b/Help/policy/CMP0032.rst
@@ -0,0 +1,15 @@
+CMP0032
+-------
+
+The :command:`output_required_files` command should not be called.
+
+This command was added in June 2001 to expose the then-current CMake
+implicit dependency scanner. CMake's real implicit dependency scanner
+has evolved since then but is not exposed through this command. The
+scanning capabilities of this command are very limited and this
+functionality is better achieved through dedicated outside tools.
+
+.. |disallowed_version| replace:: 3.0
+.. include:: DISALLOWED_COMMAND.txt
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0033.rst b/Help/policy/CMP0033.rst
new file mode 100644
index 0000000..4a6cc59
--- /dev/null
+++ b/Help/policy/CMP0033.rst
@@ -0,0 +1,16 @@
+CMP0033
+-------
+
+The :command:`export_library_dependencies` command should not be called.
+
+This command was added in January 2003 to export ``<tgt>_LIB_DEPENDS``
+internal CMake cache entries to a file for installation with a project.
+This was used at the time to allow transitive link dependencies to
+work for applications outside of the original build tree of a project.
+The functionality has been superseded by the :command:`export` and
+:command:`install(EXPORT)` commands.
+
+.. |disallowed_version| replace:: 3.0
+.. include:: DISALLOWED_COMMAND.txt
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0034.rst b/Help/policy/CMP0034.rst
new file mode 100644
index 0000000..0f3934a
--- /dev/null
+++ b/Help/policy/CMP0034.rst
@@ -0,0 +1,13 @@
+CMP0034
+-------
+
+The :command:`utility_source` command should not be called.
+
+This command was introduced in March 2001 to help build executables used to
+generate other files. This approach has long been replaced by
+:command:`add_executable` combined with :command:`add_custom_command`.
+
+.. |disallowed_version| replace:: 3.0
+.. include:: DISALLOWED_COMMAND.txt
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0035.rst b/Help/policy/CMP0035.rst
new file mode 100644
index 0000000..58199a4
--- /dev/null
+++ b/Help/policy/CMP0035.rst
@@ -0,0 +1,12 @@
+CMP0035
+-------
+
+The :command:`variable_requires` command should not be called.
+
+This command was introduced in November 2001 to perform some conditional
+logic. It has long been replaced by the :command:`if` command.
+
+.. |disallowed_version| replace:: 3.0
+.. include:: DISALLOWED_COMMAND.txt
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0036.rst b/Help/policy/CMP0036.rst
new file mode 100644
index 0000000..4bcfc54
--- /dev/null
+++ b/Help/policy/CMP0036.rst
@@ -0,0 +1,14 @@
+CMP0036
+-------
+
+The :command:`build_name` command should not be called.
+
+This command was added in May 2001 to compute a name for the current
+operating system and compiler combination. The command has long been
+documented as discouraged and replaced by the :variable:`CMAKE_SYSTEM`
+and :variable:`CMAKE_<LANG>_COMPILER` variables.
+
+.. |disallowed_version| replace:: 3.0
+.. include:: DISALLOWED_COMMAND.txt
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0037.rst b/Help/policy/CMP0037.rst
new file mode 100644
index 0000000..9895fb0
--- /dev/null
+++ b/Help/policy/CMP0037.rst
@@ -0,0 +1,34 @@
+CMP0037
+-------
+
+Target names should not be reserved and should match a validity pattern.
+
+CMake 2.8.12 and lower allowed creating targets using :command:`add_library`,
+:command:`add_executable` and :command:`add_custom_target` with unrestricted
+choice for the target name. Newer cmake features such
+as :manual:`cmake-generator-expressions(7)` and some
+diagnostics expect target names to match a restricted pattern.
+
+Target names may contain upper and lower case letters, numbers, the underscore
+character (``_``), dot(``.``), plus(``+``) and minus(``-``).
+As a special case, ``ALIAS`` and ``IMPORTED`` targets may contain
+two consecutive colons.
+
+Target names reserved by one or more CMake generators are not allowed.
+Among others these include ``all``, ``clean``, ``help``, and ``install``.
+
+Target names associated with optional features, such as ``test`` and
+``package``, may also be reserved. CMake 3.10 and below always reserve them.
+CMake 3.11 and above reserve them only when the corresponding feature is
+enabled (e.g. by including the :module:`CTest` or :module:`CPack` modules).
+
+The ``OLD`` behavior for this policy is to allow creating targets with
+reserved names or which do not match the validity pattern.
+The ``NEW`` behavior for this policy is to report an error
+if an add_* command is used with an invalid target name.
+
+This policy was introduced in CMake version 3.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0038.rst b/Help/policy/CMP0038.rst
new file mode 100644
index 0000000..7fb2209
--- /dev/null
+++ b/Help/policy/CMP0038.rst
@@ -0,0 +1,18 @@
+CMP0038
+-------
+
+Targets may not link directly to themselves.
+
+CMake 2.8.12 and lower allowed a build target to link to itself directly with
+a :command:`target_link_libraries` call. This is an indicator of a bug in
+user code.
+
+The ``OLD`` behavior for this policy is to ignore targets which list themselves
+in their own link implementation. The ``NEW`` behavior for this policy is to
+report an error if a target attempts to link to itself.
+
+This policy was introduced in CMake version 3.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0039.rst b/Help/policy/CMP0039.rst
new file mode 100644
index 0000000..4b14e21
--- /dev/null
+++ b/Help/policy/CMP0039.rst
@@ -0,0 +1,19 @@
+CMP0039
+-------
+
+Utility targets may not have link dependencies.
+
+CMake 2.8.12 and lower allowed using utility targets in the left hand side
+position of the :command:`target_link_libraries` command. This is an indicator
+of a bug in user code.
+
+The ``OLD`` behavior for this policy is to ignore attempts to set the link
+libraries of utility targets. The ``NEW`` behavior for this policy is to
+report an error if an attempt is made to set the link libraries of a
+utility target.
+
+This policy was introduced in CMake version 3.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0040.rst b/Help/policy/CMP0040.rst
new file mode 100644
index 0000000..0afe589
--- /dev/null
+++ b/Help/policy/CMP0040.rst
@@ -0,0 +1,21 @@
+CMP0040
+-------
+
+The target in the ``TARGET`` signature of :command:`add_custom_command`
+must exist and must be defined in the current directory.
+
+CMake 2.8.12 and lower silently ignored a custom command created with
+the ``TARGET`` signature of :command:`add_custom_command`
+if the target is unknown or was defined outside the current directory.
+
+The ``OLD`` behavior for this policy is to ignore custom commands
+for unknown targets. The ``NEW`` behavior for this policy is to report
+an error if the target referenced in :command:`add_custom_command` is
+unknown or was defined outside the current directory.
+
+This policy was introduced in CMake version 3.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or
+``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0041.rst b/Help/policy/CMP0041.rst
new file mode 100644
index 0000000..3b4df36
--- /dev/null
+++ b/Help/policy/CMP0041.rst
@@ -0,0 +1,27 @@
+CMP0041
+-------
+
+Error on relative include with generator expression.
+
+Diagnostics in CMake 2.8.12 and lower silently ignored an entry in the
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of a target if it contained a generator
+expression at any position.
+
+The path entries in that target property should not be relative. High-level
+API should ensure that by adding either a source directory or a install
+directory prefix, as appropriate.
+
+As an additional diagnostic, the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` generated
+on an :prop_tgt:`IMPORTED` target for the install location should not contain
+paths in the source directory or the build directory.
+
+The ``OLD`` behavior for this policy is to ignore relative path entries if they
+contain a generator expression. The ``NEW`` behavior for this policy is to report
+an error if a generator expression appears in another location and the path is
+relative.
+
+This policy was introduced in CMake version 3.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0042.rst b/Help/policy/CMP0042.rst
new file mode 100644
index 0000000..0877564
--- /dev/null
+++ b/Help/policy/CMP0042.rst
@@ -0,0 +1,21 @@
+CMP0042
+-------
+
+:prop_tgt:`MACOSX_RPATH` is enabled by default.
+
+CMake 2.8.12 and newer has support for using ``@rpath`` in a target's install
+name. This was enabled by setting the target property
+:prop_tgt:`MACOSX_RPATH`. The ``@rpath`` in an install name is a more
+flexible and powerful mechanism than ``@executable_path`` or ``@loader_path``
+for locating shared libraries.
+
+CMake 3.0 and later prefer this property to be ON by default. Projects
+wanting ``@rpath`` in a target's install name may remove any setting of
+the :prop_tgt:`INSTALL_NAME_DIR` and :variable:`CMAKE_INSTALL_NAME_DIR`
+variables.
+
+This policy was introduced in CMake version 3.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0043.rst b/Help/policy/CMP0043.rst
new file mode 100644
index 0000000..05210ac
--- /dev/null
+++ b/Help/policy/CMP0043.rst
@@ -0,0 +1,47 @@
+CMP0043
+-------
+
+Ignore COMPILE_DEFINITIONS_<Config> properties
+
+CMake 2.8.12 and lower allowed setting the
+:prop_tgt:`COMPILE_DEFINITIONS_<CONFIG>` target property and
+:prop_dir:`COMPILE_DEFINITIONS_<CONFIG>` directory property to apply
+configuration-specific compile definitions.
+
+Since CMake 2.8.10, the :prop_tgt:`COMPILE_DEFINITIONS` property has supported
+:manual:`generator expressions <cmake-generator-expressions(7)>` for setting
+configuration-dependent content. The continued existence of the suffixed
+variables is redundant, and causes a maintenance burden. Population of the
+:prop_tgt:`COMPILE_DEFINITIONS_DEBUG <COMPILE_DEFINITIONS_<CONFIG>>` property
+may be replaced with a population of :prop_tgt:`COMPILE_DEFINITIONS` directly
+or via :command:`target_compile_definitions`:
+
+.. code-block:: cmake
+
+ # Old Interfaces:
+ set_property(TARGET tgt APPEND PROPERTY
+ COMPILE_DEFINITIONS_DEBUG DEBUG_MODE
+ )
+ set_property(DIRECTORY APPEND PROPERTY
+ COMPILE_DEFINITIONS_DEBUG DIR_DEBUG_MODE
+ )
+
+ # New Interfaces:
+ set_property(TARGET tgt APPEND PROPERTY
+ COMPILE_DEFINITIONS $<$<CONFIG:Debug>:DEBUG_MODE>
+ )
+ target_compile_definitions(tgt PRIVATE $<$<CONFIG:Debug>:DEBUG_MODE>)
+ set_property(DIRECTORY APPEND PROPERTY
+ COMPILE_DEFINITIONS $<$<CONFIG:Debug>:DIR_DEBUG_MODE>
+ )
+
+The ``OLD`` behavior for this policy is to consume the content of the suffixed
+:prop_tgt:`COMPILE_DEFINITIONS_<CONFIG>` target property when generating the
+compilation command. The ``NEW`` behavior for this policy is to ignore the content
+of the :prop_tgt:`COMPILE_DEFINITIONS_<CONFIG>` target property .
+
+This policy was introduced in CMake version 3.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0044.rst b/Help/policy/CMP0044.rst
new file mode 100644
index 0000000..6a4d040
--- /dev/null
+++ b/Help/policy/CMP0044.rst
@@ -0,0 +1,21 @@
+CMP0044
+-------
+
+Case sensitive ``<LANG>_COMPILER_ID`` generator expressions
+
+CMake 2.8.12 introduced the ``<LANG>_COMPILER_ID``
+:manual:`generator expressions <cmake-generator-expressions(7)>` to allow
+comparison of the :variable:`CMAKE_<LANG>_COMPILER_ID` with a test value. The
+possible valid values are lowercase, but the comparison with the test value
+was performed case-insensitively.
+
+The ``OLD`` behavior for this policy is to perform a case-insensitive comparison
+with the value in the ``<LANG>_COMPILER_ID`` expression. The ``NEW`` behavior
+for this policy is to perform a case-sensitive comparison with the value in
+the ``<LANG>_COMPILER_ID`` expression.
+
+This policy was introduced in CMake version 3.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0045.rst b/Help/policy/CMP0045.rst
new file mode 100644
index 0000000..80e217b
--- /dev/null
+++ b/Help/policy/CMP0045.rst
@@ -0,0 +1,19 @@
+CMP0045
+-------
+
+Error on non-existent target in get_target_property.
+
+In CMake 2.8.12 and lower, the :command:`get_target_property` command accepted
+a non-existent target argument without issuing any error or warning. The
+result variable is set to a ``-NOTFOUND`` value.
+
+The ``OLD`` behavior for this policy is to issue no warning and set the result
+variable to a ``-NOTFOUND`` value. The ``NEW`` behavior
+for this policy is to issue a ``FATAL_ERROR`` if the command is called with a
+non-existent target.
+
+This policy was introduced in CMake version 3.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0046.rst b/Help/policy/CMP0046.rst
new file mode 100644
index 0000000..bf78584
--- /dev/null
+++ b/Help/policy/CMP0046.rst
@@ -0,0 +1,19 @@
+CMP0046
+-------
+
+Error on non-existent dependency in add_dependencies.
+
+CMake 2.8.12 and lower silently ignored non-existent dependencies
+listed in the :command:`add_dependencies` command.
+
+The ``OLD`` behavior for this policy is to silently ignore non-existent
+dependencies. The ``NEW`` behavior for this policy is to report an error
+if non-existent dependencies are listed in the :command:`add_dependencies`
+command.
+
+This policy was introduced in CMake version 3.0.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set it
+to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0047.rst b/Help/policy/CMP0047.rst
new file mode 100644
index 0000000..9588edd
--- /dev/null
+++ b/Help/policy/CMP0047.rst
@@ -0,0 +1,30 @@
+CMP0047
+-------
+
+Use ``QCC`` compiler id for the qcc drivers on QNX.
+
+CMake 3.0 and above recognize that the QNX qcc compiler driver is
+different from the GNU compiler.
+CMake now prefers to present this to projects by setting the
+:variable:`CMAKE_<LANG>_COMPILER_ID` variable to ``QCC`` instead
+of ``GNU``. However, existing projects may assume the compiler id for
+QNX qcc is just ``GNU`` as it was in CMake versions prior to 3.0.
+Therefore this policy determines for QNX qcc which compiler id to
+report in the :variable:`CMAKE_<LANG>_COMPILER_ID` variable after
+language ``<LANG>`` is enabled by the :command:`project` or
+:command:`enable_language` command. The policy must be set prior
+to the invocation of either command.
+
+The ``OLD`` behavior for this policy is to use the ``GNU`` compiler id
+for the qcc and QCC compiler drivers. The ``NEW`` behavior for this policy
+is to use the ``QCC`` compiler id for those drivers.
+
+This policy was introduced in CMake version 3.0. Use the
+:command:`cmake_policy` command to set this policy to ``OLD`` or ``NEW``
+explicitly. Unlike most policies, CMake version |release| does *not* warn
+by default when this policy is not set and simply uses ``OLD`` behavior.
+See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0047 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0048.rst b/Help/policy/CMP0048.rst
new file mode 100644
index 0000000..e63ec01
--- /dev/null
+++ b/Help/policy/CMP0048.rst
@@ -0,0 +1,24 @@
+CMP0048
+-------
+
+The :command:`project` command manages ``VERSION`` variables.
+
+CMake version 3.0 introduced the ``VERSION`` option of the :command:`project`
+command to specify a project version as well as the name. In order to keep
+:variable:`PROJECT_VERSION` and related variables consistent with variable
+:variable:`PROJECT_NAME` it is necessary to set the ``VERSION`` variables
+to the empty string when no ``VERSION`` is given to :command:`project`.
+However, this can change behavior for existing projects that set ``VERSION``
+variables themselves since :command:`project` may now clear them.
+This policy controls the behavior for compatibility with such projects.
+
+The ``OLD`` behavior for this policy is to leave ``VERSION`` variables untouched.
+The ``NEW`` behavior for this policy is to set ``VERSION`` as documented by the
+:command:`project` command.
+
+This policy was introduced in CMake version 3.0.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set
+it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0049.rst b/Help/policy/CMP0049.rst
new file mode 100644
index 0000000..49b20be
--- /dev/null
+++ b/Help/policy/CMP0049.rst
@@ -0,0 +1,25 @@
+CMP0049
+-------
+
+Do not expand variables in target source entries.
+
+CMake 2.8.12 and lower performed an extra layer of variable expansion
+when evaluating source file names::
+
+ set(a_source foo.c)
+ add_executable(foo \${a_source})
+
+.. note: no cmake highlighting since this syntax is deprecated
+
+This was undocumented behavior.
+
+The ``OLD`` behavior for this policy is to expand such variables when processing
+the target sources. The ``NEW`` behavior for this policy is to issue an error
+if such variables need to be expanded.
+
+This policy was introduced in CMake version 3.0.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set
+it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0050.rst b/Help/policy/CMP0050.rst
new file mode 100644
index 0000000..27e7b1d
--- /dev/null
+++ b/Help/policy/CMP0050.rst
@@ -0,0 +1,20 @@
+CMP0050
+-------
+
+Disallow add_custom_command SOURCE signatures.
+
+CMake 2.8.12 and lower allowed a signature for :command:`add_custom_command`
+which specified an input to a command. This was undocumented behavior.
+Modern use of CMake associates custom commands with their output, rather
+than their input.
+
+The ``OLD`` behavior for this policy is to allow the use of
+:command:`add_custom_command` SOURCE signatures. The ``NEW`` behavior for this
+policy is to issue an error if such a signature is used.
+
+This policy was introduced in CMake version 3.0.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set it to ``OLD`` or
+``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0051.rst b/Help/policy/CMP0051.rst
new file mode 100644
index 0000000..3558909
--- /dev/null
+++ b/Help/policy/CMP0051.rst
@@ -0,0 +1,28 @@
+CMP0051
+-------
+
+.. versionadded:: 3.1
+
+List :genex:`TARGET_OBJECTS` in SOURCES target property.
+
+CMake 3.0 and lower did not include the ``TARGET_OBJECTS``
+:manual:`generator expression <cmake-generator-expressions(7)>` when
+returning the :prop_tgt:`SOURCES` target property.
+
+Configure-time CMake code is not able to handle generator expressions. If
+using the :prop_tgt:`SOURCES` target property at configure time, it may be
+necessary to first remove generator expressions using the
+:command:`string(GENEX_STRIP)` command. Generate-time CMake code such as
+:command:`file(GENERATE)` can handle the content without stripping.
+
+The ``OLD`` behavior for this policy is to omit ``TARGET_OBJECTS``
+expressions from the :prop_tgt:`SOURCES` target property. The ``NEW``
+behavior for this policy is to include ``TARGET_OBJECTS`` expressions
+in the output.
+
+This policy was introduced in CMake version 3.1.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set it
+to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0052.rst b/Help/policy/CMP0052.rst
new file mode 100644
index 0000000..c75f9ab
--- /dev/null
+++ b/Help/policy/CMP0052.rst
@@ -0,0 +1,29 @@
+CMP0052
+-------
+
+.. versionadded:: 3.1
+
+Reject source and build dirs in installed
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`.
+
+CMake 3.0 and lower allowed subdirectories of the source directory or build
+directory to be in the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of
+installed and exported targets, if the directory was also a subdirectory of
+the installation prefix. This makes the installation depend on the
+existence of the source dir or binary dir, and the installation will be
+broken if either are removed after installation.
+
+See :ref:`Include Directories and Usage Requirements` for more on
+specifying include directories for targets.
+
+The ``OLD`` behavior for this policy is to export the content of the
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` with the source or binary
+directory. The ``NEW`` behavior for this
+policy is to issue an error if such a directory is used.
+
+This policy was introduced in CMake version 3.1.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set it
+to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0053.rst b/Help/policy/CMP0053.rst
new file mode 100644
index 0000000..9b18b2d
--- /dev/null
+++ b/Help/policy/CMP0053.rst
@@ -0,0 +1,52 @@
+CMP0053
+-------
+
+.. versionadded:: 3.1
+
+Simplify variable reference and escape sequence evaluation.
+
+CMake 3.1 introduced a much faster implementation of evaluation of the
+:ref:`Variable References` and :ref:`Escape Sequences` documented in the
+:manual:`cmake-language(7)` manual. While the behavior is identical
+to the legacy implementation in most cases, some corner cases were
+cleaned up to simplify the behavior. Specifically:
+
+* Expansion of ``@VAR@`` reference syntax defined by the
+ :command:`configure_file` and :command:`string(CONFIGURE)`
+ commands is no longer performed in other contexts.
+
+* Literal ``${VAR}`` reference syntax may contain only
+ alphanumeric characters (``A-Z``, ``a-z``, ``0-9``) and
+ the characters ``_``, ``.``, ``/``, ``-``, and ``+``.
+ Note that ``$`` is technically allowed in the ``NEW`` behavior, but is
+ invalid for ``OLD`` behavior. This is due to an oversight during the
+ implementation of :policy:`CMP0053` and its use as a literal variable
+ reference is discouraged for this reason.
+ Variables with other characters in their name may still
+ be referenced indirectly, e.g.
+
+ .. code-block:: cmake
+
+ set(varname "otherwise & disallowed $ characters")
+ message("${${varname}}")
+
+* The setting of policy :policy:`CMP0010` is not considered,
+ so improper variable reference syntax is always an error.
+
+* More characters are allowed to be escaped in variable names.
+ Previously, only ``()#" \@^`` were valid characters to
+ escape. Now any non-alphanumeric, non-semicolon, non-NUL
+ character may be escaped following the ``escape_identity``
+ production in the :ref:`Escape Sequences` section of the
+ :manual:`cmake-language(7)` manual.
+
+The ``OLD`` behavior for this policy is to honor the legacy behavior for
+variable references and escape sequences. The ``NEW`` behavior is to
+use the simpler variable expansion and escape sequence evaluation rules.
+
+This policy was introduced in CMake version 3.1.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set
+it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0054.rst b/Help/policy/CMP0054.rst
new file mode 100644
index 0000000..c7ae019
--- /dev/null
+++ b/Help/policy/CMP0054.rst
@@ -0,0 +1,54 @@
+CMP0054
+-------
+
+.. versionadded:: 3.1
+
+Only interpret :command:`if` arguments as variables or keywords when unquoted.
+
+CMake 3.1 and above no longer implicitly dereference variables or
+interpret keywords in an :command:`if` command argument when
+it is a :ref:`Quoted Argument` or a :ref:`Bracket Argument`.
+
+The ``OLD`` behavior for this policy is to dereference variables and
+interpret keywords even if they are quoted or bracketed.
+The ``NEW`` behavior is to not dereference variables or interpret keywords
+that have been quoted or bracketed.
+
+Given the following partial example:
+
+::
+
+ set(A E)
+ set(E "")
+
+ if("${A}" STREQUAL "")
+ message("Result is TRUE before CMake 3.1 or when CMP0054 is OLD")
+ else()
+ message("Result is FALSE in CMake 3.1 and above if CMP0054 is NEW")
+ endif()
+
+After explicit expansion of variables this gives:
+
+::
+
+ if("E" STREQUAL "")
+
+With the policy set to ``OLD`` implicit expansion reduces this semantically to:
+
+::
+
+ if("" STREQUAL "")
+
+With the policy set to ``NEW`` the quoted arguments will not be
+further dereferenced:
+
+::
+
+ if("E" STREQUAL "")
+
+This policy was introduced in CMake version 3.1.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set
+it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0055.rst b/Help/policy/CMP0055.rst
new file mode 100644
index 0000000..47cac8e
--- /dev/null
+++ b/Help/policy/CMP0055.rst
@@ -0,0 +1,21 @@
+CMP0055
+-------
+
+.. versionadded:: 3.2
+
+Strict checking for the :command:`break` command.
+
+CMake 3.1 and lower allowed calls to the :command:`break` command
+outside of a loop context and also ignored any given arguments.
+This was undefined behavior.
+
+The ``OLD`` behavior for this policy is to allow :command:`break` to be placed
+outside of loop contexts and ignores any arguments. The ``NEW`` behavior for this
+policy is to issue an error if a misplaced break or any arguments are found.
+
+This policy was introduced in CMake version 3.2.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set it to ``OLD`` or
+``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0056.rst b/Help/policy/CMP0056.rst
new file mode 100644
index 0000000..628a6a1
--- /dev/null
+++ b/Help/policy/CMP0056.rst
@@ -0,0 +1,36 @@
+CMP0056
+-------
+
+.. versionadded:: 3.2
+
+Honor link flags in :command:`try_compile` source-file signature.
+
+The :command:`try_compile` command source-file signature generates a
+``CMakeLists.txt`` file to build the source file into an executable.
+In order to compile the source the same way as it might be compiled
+by the calling project, the generated project sets the value of the
+:variable:`CMAKE_<LANG>_FLAGS` variable to that in the calling project.
+The value of the :variable:`CMAKE_EXE_LINKER_FLAGS` variable may be
+needed in some cases too, but CMake 3.1 and lower did not set it in
+the generated project. CMake 3.2 and above prefer to set it so that
+linker flags are honored as well as compiler flags. This policy
+provides compatibility with the pre-3.2 behavior.
+
+The ``OLD`` behavior for this policy is to not set the value of the
+:variable:`CMAKE_EXE_LINKER_FLAGS` variable in the generated test
+project. The ``NEW`` behavior for this policy is to set the value of
+the :variable:`CMAKE_EXE_LINKER_FLAGS` variable in the test project
+to the same as it is in the calling project.
+
+If the project code does not set the policy explicitly, users may
+set it on the command line by defining the
+:variable:`CMAKE_POLICY_DEFAULT_CMP0056 <CMAKE_POLICY_DEFAULT_CMP<NNNN>>`
+variable in the cache.
+
+This policy was introduced in CMake version 3.2. Unlike most policies,
+CMake version |release| does *not* warn by default when this policy
+is not set and simply uses ``OLD`` behavior. See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0056 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0057.rst b/Help/policy/CMP0057.rst
new file mode 100644
index 0000000..76aebfb
--- /dev/null
+++ b/Help/policy/CMP0057.rst
@@ -0,0 +1,18 @@
+CMP0057
+-------
+
+.. versionadded:: 3.3
+
+Support new :command:`if` IN_LIST operator.
+
+CMake 3.3 adds support for the new IN_LIST operator.
+
+The ``OLD`` behavior for this policy is to ignore the IN_LIST operator.
+The ``NEW`` behavior is to interpret the IN_LIST operator.
+
+This policy was introduced in CMake version 3.3.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set
+it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0058.rst b/Help/policy/CMP0058.rst
new file mode 100644
index 0000000..06cc74b
--- /dev/null
+++ b/Help/policy/CMP0058.rst
@@ -0,0 +1,112 @@
+CMP0058
+-------
+
+.. versionadded:: 3.3
+
+Ninja requires custom command byproducts to be explicit.
+
+When an intermediate file generated during the build is consumed
+by an expensive operation or a large tree of dependents, one may
+reduce the work needed for an incremental rebuild by updating the
+file timestamp only when its content changes. With this approach
+the generation rule must have a separate output file that is always
+updated with a new timestamp that is newer than any dependencies of
+the rule so that the build tool re-runs the rule only when the input
+changes. We refer to the separate output file as a rule's *witness*
+and the generated file as a rule's *byproduct*.
+
+Byproducts may not be listed as outputs because their timestamps are
+allowed to be older than the inputs. No build tools (like ``make``)
+that existed when CMake was designed have a way to express byproducts.
+Therefore CMake versions prior to 3.2 had no way to specify them.
+Projects typically left byproducts undeclared in the rules that
+generate them. For example:
+
+.. code-block:: cmake
+
+ add_custom_command(
+ OUTPUT witness.txt
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
+ byproduct.txt # timestamp may not change
+ COMMAND ${CMAKE_COMMAND} -E touch witness.txt
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
+ )
+ add_custom_target(Provider DEPENDS witness.txt)
+ add_custom_command(
+ OUTPUT generated.c
+ COMMAND expensive-task -i byproduct.txt -o generated.c
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/byproduct.txt
+ )
+ add_library(Consumer generated.c)
+ add_dependencies(Consumer Provider)
+
+This works well for all generators except :generator:`Ninja`.
+The Ninja build tool sees a rule listing ``byproduct.txt``
+as a dependency and no rule listing it as an output. Ninja then
+complains that there is no way to satisfy the dependency and
+stops building even though there are order-only dependencies
+that ensure ``byproduct.txt`` will exist before its consumers
+need it. See discussion of this problem in `Ninja Issue 760`_
+for further details on why Ninja works this way.
+
+.. _`Ninja Issue 760`: https://github.com/martine/ninja/issues/760
+
+Instead of leaving byproducts undeclared in the rules that generate
+them, Ninja expects byproducts to be listed along with other outputs.
+Such rules may be marked with a ``restat`` option that tells Ninja
+to check the timestamps of outputs after the rules run. This
+prevents byproducts whose timestamps do not change from causing
+their dependents to re-build unnecessarily.
+
+Since the above approach does not tell CMake what custom command
+generates ``byproduct.txt``, the Ninja generator does not have
+enough information to add the byproduct as an output of any rule.
+CMake 2.8.12 and above work around this problem and allow projects
+using the above approach to build by generating ``phony`` build
+rules to tell Ninja to tolerate such missing files. However, this
+workaround prevents Ninja from diagnosing a dependency that is
+really missing. It also works poorly in in-source builds where
+every custom command dependency, even on source files, needs to
+be treated this way because CMake does not have enough information
+to know which files are generated as byproducts of custom commands.
+
+CMake 3.2 introduced the ``BYPRODUCTS`` option to the
+:command:`add_custom_command` and :command:`add_custom_target`
+commands. This option allows byproducts to be specified explicitly:
+
+.. code-block:: cmake
+
+ add_custom_command(
+ OUTPUT witness.txt
+ BYPRODUCTS byproduct.txt # explicit byproduct specification
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
+ byproduct.txt # timestamp may not change
+ ...
+
+The ``BYPRODUCTS`` option is used by the :generator:`Ninja` generator
+to list byproducts among the outputs of the custom commands that
+generate them, and is ignored by other generators.
+
+CMake 3.3 and above prefer to require projects to specify custom
+command byproducts explicitly so that it can avoid using the
+``phony`` rule workaround altogether. Policy ``CMP0058`` was
+introduced to provide compatibility with existing projects that
+still need the workaround.
+
+This policy has no effect on generators other than :generator:`Ninja`.
+The ``OLD`` behavior for this policy is to generate Ninja ``phony``
+rules for unknown dependencies in the build tree. The ``NEW``
+behavior for this policy is to not generate these and instead
+require projects to specify custom command ``BYPRODUCTS`` explicitly.
+
+This policy was introduced in CMake version 3.3.
+CMake version |release| warns when it sees unknown dependencies in
+out-of-source build trees if the policy is not set and then uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set
+the policy to ``OLD`` or ``NEW`` explicitly. The policy setting
+must be in scope at the end of the top-level ``CMakeLists.txt``
+file of the project and has global effect.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0059.rst b/Help/policy/CMP0059.rst
new file mode 100644
index 0000000..6317d05
--- /dev/null
+++ b/Help/policy/CMP0059.rst
@@ -0,0 +1,21 @@
+CMP0059
+-------
+
+.. versionadded:: 3.3
+
+Do not treat ``DEFINITIONS`` as a built-in directory property.
+
+CMake 3.3 and above no longer make a list of definitions available through
+the :prop_dir:`DEFINITIONS` directory property. The
+:prop_dir:`COMPILE_DEFINITIONS` directory property may be used instead.
+
+The ``OLD`` behavior for this policy is to provide the list of flags given
+so far to the :command:`add_definitions` command. The ``NEW`` behavior is
+to behave as a normal user-defined directory property.
+
+This policy was introduced in CMake version 3.3.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set
+it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0060.rst b/Help/policy/CMP0060.rst
new file mode 100644
index 0000000..09257d1
--- /dev/null
+++ b/Help/policy/CMP0060.rst
@@ -0,0 +1,67 @@
+CMP0060
+-------
+
+.. versionadded:: 3.3
+
+Link libraries by full path even in implicit directories.
+
+Policy :policy:`CMP0003` was introduced with the intention of always
+linking library files by full path when a full path is given to the
+:command:`target_link_libraries` command. However, on some platforms
+(e.g. HP-UX) the compiler front-end adds alternative library search paths
+for the current architecture (e.g. ``/usr/lib/<arch>`` has alternatives
+to libraries in ``/usr/lib`` for the current architecture).
+On such platforms the :command:`find_library` may find a library such as
+``/usr/lib/libfoo.so`` that does not belong to the current architecture.
+
+Prior to policy :policy:`CMP0003` projects would still build in such
+cases because the incorrect library path would be converted to ``-lfoo``
+on the link line and the linker would find the proper library in the
+arch-specific search path provided by the compiler front-end implicitly.
+At the time we chose to remain compatible with such projects by always
+converting library files found in implicit link directories to ``-lfoo``
+flags to ask the linker to search for them. This approach allowed existing
+projects to continue to build while still linking to libraries outside
+implicit link directories via full path (such as those in the build tree).
+
+CMake does allow projects to override this behavior by using an
+:ref:`IMPORTED library target <Imported Targets>` with its
+:prop_tgt:`IMPORTED_LOCATION` property set to the desired full path to
+a library file. In fact, many :ref:`Find Modules` are learning to provide
+:ref:`Imported Targets` instead of just the traditional ``Foo_LIBRARIES``
+variable listing library files. However, this makes the link line
+generated for a library found by a Find Module depend on whether it
+is linked through an imported target or not, which is inconsistent.
+Furthermore, this behavior has been a source of confusion because the
+generated link line for a library file depends on its location. It is
+also problematic for projects trying to link statically because flags
+like ``-Wl,-Bstatic -lfoo -Wl,-Bdynamic`` may be used to help the linker
+select ``libfoo.a`` instead of ``libfoo.so`` but then leak dynamic linking
+to following libraries. (See the :prop_tgt:`LINK_SEARCH_END_STATIC`
+target property for a solution typically used for that problem.)
+
+When the special case for libraries in implicit link directories was first
+introduced the list of implicit link directories was simply hard-coded
+(e.g. ``/lib``, ``/usr/lib``, and a few others). Since that time, CMake
+has learned to detect the implicit link directories used by the compiler
+front-end. If necessary, the :command:`find_library` command could be
+taught to use this information to help find libraries of the proper
+architecture.
+
+For these reasons, CMake 3.3 and above prefer to drop the special case
+and link libraries by full path even when they are in implicit link
+directories. Policy ``CMP0060`` provides compatibility for existing
+projects.
+
+The ``OLD`` behavior for this policy is to ask the linker to search for
+libraries whose full paths are known to be in implicit link directories.
+The ``NEW`` behavior for this policy is to link libraries by full path even
+if they are in implicit link directories.
+
+This policy was introduced in CMake version 3.3. Unlike most policies,
+CMake version |release| does *not* warn by default when this policy
+is not set and simply uses ``OLD`` behavior. See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0060 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0061.rst b/Help/policy/CMP0061.rst
new file mode 100644
index 0000000..aca551d
--- /dev/null
+++ b/Help/policy/CMP0061.rst
@@ -0,0 +1,28 @@
+CMP0061
+-------
+
+.. versionadded:: 3.3
+
+CTest does not by default tell ``make`` to ignore errors (``-i``).
+
+The :command:`ctest_build` and :command:`build_command` commands no
+longer generate build commands for :ref:`Makefile Generators` with
+the ``-i`` option. Previously this was done to help build as much
+of tested projects as possible. However, this behavior is not
+consistent with other generators and also causes the return code
+of the ``make`` tool to be meaningless.
+
+Of course users may still add this option manually by setting
+:variable:`CTEST_BUILD_COMMAND` or the ``MAKECOMMAND`` cache entry.
+See the :ref:`CTest Build Step` ``MakeCommand`` setting documentation
+for their effects.
+
+The ``OLD`` behavior for this policy is to add ``-i`` to ``make``
+calls in CTest. The ``NEW`` behavior for this policy is to not
+add ``-i``.
+
+This policy was introduced in CMake version 3.3. Unlike most policies,
+CMake version |release| does *not* warn when this policy is not set and
+simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0062.rst b/Help/policy/CMP0062.rst
new file mode 100644
index 0000000..01e93f0
--- /dev/null
+++ b/Help/policy/CMP0062.rst
@@ -0,0 +1,31 @@
+CMP0062
+-------
+
+.. versionadded:: 3.3
+
+Disallow :command:`install` of :command:`export` result.
+
+The :command:`export()` command generates a file containing
+:ref:`Imported Targets`, which is suitable for use from the build
+directory. It is not suitable for installation because it contains absolute
+paths to buildsystem locations, and is particular to a single build
+configuration.
+
+The :command:`install(EXPORT)` generates and installs files which contain
+:ref:`Imported Targets`. These files are generated with relative paths
+(unless the user specifies absolute paths), and are designed for
+multi-configuration use. See :ref:`Creating Packages` for more.
+
+CMake 3.3 no longer allows the use of the :command:`install(FILES)` command
+with the result of the :command:`export()` command.
+
+The ``OLD`` behavior for this policy is to allow installing the result of
+an :command:`export()` command. The ``NEW`` behavior for this policy is
+not to allow installing the result of an :command:`export()` command.
+
+This policy was introduced in CMake version 3.3. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy()` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0063.rst b/Help/policy/CMP0063.rst
new file mode 100644
index 0000000..fec3ad8
--- /dev/null
+++ b/Help/policy/CMP0063.rst
@@ -0,0 +1,30 @@
+CMP0063
+-------
+
+.. versionadded:: 3.3
+
+Honor visibility properties for all target types.
+
+The :prop_tgt:`<LANG>_VISIBILITY_PRESET` and
+:prop_tgt:`VISIBILITY_INLINES_HIDDEN` target properties affect visibility
+of symbols during dynamic linking. When first introduced these properties
+affected compilation of sources only in shared libraries, module libraries,
+and executables with the :prop_tgt:`ENABLE_EXPORTS` property set. This
+was sufficient for the basic use cases of shared libraries and executables
+with plugins. However, some sources may be compiled as part of static
+libraries or object libraries and then linked into a shared library later.
+CMake 3.3 and above prefer to honor these properties for sources compiled
+in all target types. This policy preserves compatibility for projects
+expecting the properties to work only for some target types.
+
+The ``OLD`` behavior for this policy is to ignore the visibility properties
+for static libraries, object libraries, and executables without exports.
+The ``NEW`` behavior for this policy is to honor the visibility properties
+for all target types.
+
+This policy was introduced in CMake version 3.3. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy()` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0064.rst b/Help/policy/CMP0064.rst
new file mode 100644
index 0000000..0c20c13
--- /dev/null
+++ b/Help/policy/CMP0064.rst
@@ -0,0 +1,19 @@
+CMP0064
+-------
+
+.. versionadded:: 3.4
+
+Recognize ``TEST`` as a operator for the :command:`if` command.
+
+The ``TEST`` operator was added to the :command:`if` command to determine if a
+given test name was created by the :command:`add_test` command.
+
+The ``OLD`` behavior for this policy is to ignore the ``TEST`` operator.
+The ``NEW`` behavior is to interpret the ``TEST`` operator.
+
+This policy was introduced in CMake version 3.4. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy()` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0065.rst b/Help/policy/CMP0065.rst
new file mode 100644
index 0000000..8968b91
--- /dev/null
+++ b/Help/policy/CMP0065.rst
@@ -0,0 +1,29 @@
+CMP0065
+-------
+
+.. versionadded:: 3.4
+
+Do not add flags to export symbols from executables without
+the :prop_tgt:`ENABLE_EXPORTS` target property.
+
+CMake 3.3 and below, for historical reasons, always linked executables
+on some platforms with flags like ``-rdynamic`` to export symbols from
+the executables for use by any plugins they may load via ``dlopen``.
+CMake 3.4 and above prefer to do this only for executables that are
+explicitly marked with the :prop_tgt:`ENABLE_EXPORTS` target property.
+
+The ``OLD`` behavior of this policy is to always use the additional link
+flags when linking executables regardless of the value of the
+:prop_tgt:`ENABLE_EXPORTS` target property.
+
+The ``NEW`` behavior of this policy is to only use the additional link
+flags when linking executables if the :prop_tgt:`ENABLE_EXPORTS` target
+property is set to ``True``.
+
+This policy was introduced in CMake version 3.4. Unlike most policies,
+CMake version |release| does *not* warn by default when this policy
+is not set and simply uses ``OLD`` behavior. See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0065 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0066.rst b/Help/policy/CMP0066.rst
new file mode 100644
index 0000000..b08430f
--- /dev/null
+++ b/Help/policy/CMP0066.rst
@@ -0,0 +1,29 @@
+CMP0066
+-------
+
+.. versionadded:: 3.7
+
+Honor per-config flags in :command:`try_compile` source-file signature.
+
+The source file signature of the :command:`try_compile` command uses the value
+of the :variable:`CMAKE_<LANG>_FLAGS` variable in the test project so that the
+test compilation works as it would in the main project. However, CMake 3.6 and
+below do not also honor config-specific compiler flags such as those in the
+:variable:`CMAKE_<LANG>_FLAGS_DEBUG` variable. CMake 3.7 and above prefer to
+honor config-specific compiler flags too. This policy provides compatibility
+for projects that do not expect config-specific compiler flags to be used.
+
+The ``OLD`` behavior of this policy is to ignore config-specific flag
+variables like :variable:`CMAKE_<LANG>_FLAGS_DEBUG` and only use CMake's
+built-in defaults for the current compiler and platform.
+
+The ``NEW`` behavior of this policy is to honor config-specific flag
+variabldes like :variable:`CMAKE_<LANG>_FLAGS_DEBUG`.
+
+This policy was introduced in CMake version 3.7. Unlike most policies,
+CMake version |release| does *not* warn by default when this policy
+is not set and simply uses ``OLD`` behavior. See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0066 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0067.rst b/Help/policy/CMP0067.rst
new file mode 100644
index 0000000..8358bb2
--- /dev/null
+++ b/Help/policy/CMP0067.rst
@@ -0,0 +1,39 @@
+CMP0067
+-------
+
+.. versionadded:: 3.8
+
+Honor language standard in :command:`try_compile` source-file signature.
+
+The :command:`try_compile` source file signature is intended to allow
+callers to check whether they will be able to compile a given source file
+with the current toolchain. In order to match compiler behavior, any
+language standard mode should match. However, CMake 3.7 and below did not
+do this. CMake 3.8 and above prefer to honor the language standard settings
+for ``C``, ``CXX`` (C++), and ``CUDA`` using the values of the variables:
+
+* :variable:`CMAKE_C_STANDARD`
+* :variable:`CMAKE_C_STANDARD_REQUIRED`
+* :variable:`CMAKE_C_EXTENSIONS`
+* :variable:`CMAKE_CXX_STANDARD`
+* :variable:`CMAKE_CXX_STANDARD_REQUIRED`
+* :variable:`CMAKE_CXX_EXTENSIONS`
+* :variable:`CMAKE_CUDA_STANDARD`
+* :variable:`CMAKE_CUDA_STANDARD_REQUIRED`
+* :variable:`CMAKE_CUDA_EXTENSIONS`
+
+This policy provides compatibility for projects that do not expect
+the language standard settings to be used automatically.
+
+The ``OLD`` behavior of this policy is to ignore language standard
+setting variables when generating the ``try_compile`` test project.
+The ``NEW`` behavior of this policy is to honor language standard
+setting variables.
+
+This policy was introduced in CMake version 3.8. Unlike most policies,
+CMake version |release| does *not* warn by default when this policy
+is not set and simply uses ``OLD`` behavior. See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0067 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0068.rst b/Help/policy/CMP0068.rst
new file mode 100644
index 0000000..5d2a4b1
--- /dev/null
+++ b/Help/policy/CMP0068.rst
@@ -0,0 +1,37 @@
+CMP0068
+-------
+
+.. versionadded:: 3.9
+
+``RPATH`` settings on macOS do not affect ``install_name``.
+
+CMake 3.9 and newer remove any effect the following settings may have on the
+``install_name`` of a target on macOS:
+
+* :prop_tgt:`BUILD_WITH_INSTALL_RPATH` target property
+* :prop_tgt:`SKIP_BUILD_RPATH` target property
+* :variable:`CMAKE_SKIP_RPATH` variable
+* :variable:`CMAKE_SKIP_INSTALL_RPATH` variable
+
+Previously, setting :prop_tgt:`BUILD_WITH_INSTALL_RPATH` had the effect of
+setting both the ``install_name`` of a target to :prop_tgt:`INSTALL_NAME_DIR`
+and the ``RPATH`` to :prop_tgt:`INSTALL_RPATH`. In CMake 3.9, it only affects
+setting of ``RPATH``. However, if one wants :prop_tgt:`INSTALL_NAME_DIR` to
+apply to the target in the build tree, one may set
+:prop_tgt:`BUILD_WITH_INSTALL_NAME_DIR`.
+
+If :prop_tgt:`SKIP_BUILD_RPATH`, :variable:`CMAKE_SKIP_RPATH` or
+:variable:`CMAKE_SKIP_INSTALL_RPATH` were used to strip the directory portion
+of the ``install_name`` of a target, one may set ``INSTALL_NAME_DIR=""``
+instead.
+
+The ``OLD`` behavior of this policy is to use the ``RPATH`` settings for
+``install_name`` on macOS. The ``NEW`` behavior of this policy is to ignore
+the ``RPATH`` settings for ``install_name`` on macOS.
+
+This policy was introduced in CMake version 3.9. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0069.rst b/Help/policy/CMP0069.rst
new file mode 100644
index 0000000..eafac45
--- /dev/null
+++ b/Help/policy/CMP0069.rst
@@ -0,0 +1,94 @@
+CMP0069
+-------
+
+.. versionadded:: 3.9
+
+:prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` is enforced when enabled.
+
+CMake 3.9 and newer prefer to add IPO flags whenever the
+:prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` target property is enabled and
+produce an error if flags are not known to CMake for the current compiler.
+Since a given compiler may not support IPO flags in all environments in which
+it is used, it is now the project's responsibility to use the
+:module:`CheckIPOSupported` module to check for support before enabling the
+:prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` target property. This approach
+allows a project to conditionally activate IPO when supported. It also
+allows an end user to set the :variable:`CMAKE_INTERPROCEDURAL_OPTIMIZATION`
+variable in an environment known to support IPO even if the project does
+not enable the property.
+
+Since CMake 3.8 and lower only honored :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION`
+for the Intel compiler on Linux, some projects may unconditionally enable the
+target property. Policy ``CMP0069`` provides compatibility with such projects.
+
+This policy takes effect whenever the IPO property is enabled. The ``OLD``
+behavior for this policy is to add IPO flags only for Intel compiler on Linux.
+The ``NEW`` behavior for this policy is to add IPO flags for the current
+compiler or produce an error if CMake does not know the flags.
+
+This policy was introduced in CMake version 3.9. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
+
+Examples
+^^^^^^^^
+
+Behave like CMake 3.8 and do not apply any IPO flags except for Intel compiler
+on Linux:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.8)
+ project(foo)
+
+ # ...
+
+ set_property(TARGET ... PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
+
+Use the :module:`CheckIPOSupported` module to detect whether IPO is
+supported by the current compiler, environment, and CMake version.
+Produce a fatal error if support is not available:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.9) # CMP0069 NEW
+ project(foo)
+
+ include(CheckIPOSupported)
+ check_ipo_supported()
+
+ # ...
+
+ set_property(TARGET ... PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
+
+Apply IPO flags only if compiler supports it:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.9) # CMP0069 NEW
+ project(foo)
+
+ include(CheckIPOSupported)
+
+ # ...
+
+ check_ipo_supported(RESULT result)
+ if(result)
+ set_property(TARGET ... PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
+ endif()
+
+Apply IPO flags without any checks. This may lead to build errors if IPO
+is not supported by the compiler in the current environment. Produce an
+error if CMake does not know IPO flags for the current compiler:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.9) # CMP0069 NEW
+ project(foo)
+
+ # ...
+
+ set_property(TARGET ... PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
diff --git a/Help/policy/CMP0070.rst b/Help/policy/CMP0070.rst
new file mode 100644
index 0000000..c880d1f
--- /dev/null
+++ b/Help/policy/CMP0070.rst
@@ -0,0 +1,27 @@
+CMP0070
+-------
+
+.. versionadded:: 3.10
+
+Define :command:`file(GENERATE)` behavior for relative paths.
+
+CMake 3.10 and newer define that relative paths given to ``INPUT`` and
+``OUTPUT`` arguments of ``file(GENERATE)`` are interpreted relative to the
+current source and binary directories, respectively. CMake 3.9 and lower did
+not define any behavior for relative paths but did not diagnose them either
+and accidentally treated them relative to the process working directory.
+Policy ``CMP0070`` provides compatibility with projects that used the old
+undefined behavior.
+
+This policy affects behavior of relative paths given to ``file(GENERATE)``.
+The ``OLD`` behavior for this policy is to treat the paths relative to the
+working directory of CMake. The ``NEW`` behavior for this policy is to
+interpret relative paths with respect to the current source or binary
+directory of the caller.
+
+This policy was introduced in CMake version 3.10. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0071.rst b/Help/policy/CMP0071.rst
new file mode 100644
index 0000000..700d3b0
--- /dev/null
+++ b/Help/policy/CMP0071.rst
@@ -0,0 +1,44 @@
+CMP0071
+-------
+
+.. versionadded:: 3.10
+
+Let :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC` process
+:prop_sf:`GENERATED` files.
+
+Since version 3.10, CMake processes **regular** and :prop_sf:`GENERATED`
+source files in :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+In earlier CMake versions, only **regular** source files were processed.
+:prop_sf:`GENERATED` source files were ignored silently.
+
+This policy affects how source files that are :prop_sf:`GENERATED`
+get treated in :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+
+The ``OLD`` behavior for this policy is to ignore :prop_sf:`GENERATED`
+source files in :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+
+The ``NEW`` behavior for this policy is to process :prop_sf:`GENERATED`
+source files in :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC` just like regular
+source files.
+
+.. note::
+
+ To silence the ``CMP0071`` warning source files can be excluded from
+ :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC` processing by setting the
+ source file properties :prop_sf:`SKIP_AUTOMOC`, :prop_sf:`SKIP_AUTOUIC` or
+ :prop_sf:`SKIP_AUTOGEN`.
+
+Source skip example::
+
+ # ...
+ set_property(SOURCE /path/to/file1.h PROPERTY SKIP_AUTOMOC ON)
+ set_property(SOURCE /path/to/file2.h PROPERTY SKIP_AUTOUIC ON)
+ set_property(SOURCE /path/to/file3.h PROPERTY SKIP_AUTOGEN ON)
+ # ...
+
+This policy was introduced in CMake version 3.10. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0072.rst b/Help/policy/CMP0072.rst
new file mode 100644
index 0000000..1dcdfef
--- /dev/null
+++ b/Help/policy/CMP0072.rst
@@ -0,0 +1,28 @@
+CMP0072
+-------
+
+.. versionadded:: 3.11
+
+:module:`FindOpenGL` prefers GLVND by default when available.
+
+The :module:`FindOpenGL` module provides an ``OpenGL::GL`` target and an
+``OPENGL_LIBRARIES`` variable for projects to use for legacy GL interfaces.
+When both a legacy GL library (e.g. ``libGL.so``) and GLVND libraries
+for OpenGL and GLX (e.g. ``libOpenGL.so`` and ``libGLX.so``) are available,
+the module must choose between them. It documents an ``OpenGL_GL_PREFERENCE``
+variable that can be used to specify an explicit preference. When no such
+preference is set, the module must choose a default preference.
+
+CMake 3.11 and above prefer to choose GLVND libraries. This policy provides
+compatibility with projects that expect the legacy GL library to be used.
+
+The ``OLD`` behavior for this policy is to set ``OpenGL_GL_PREFERENCE`` to
+``LEGACY``. The ``NEW`` behavior for this policy is to set
+``OpenGL_GL_PREFERENCE`` to ``GLVND``.
+
+This policy was introduced in CMake version 3.11. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0073.rst b/Help/policy/CMP0073.rst
new file mode 100644
index 0000000..8f0345c
--- /dev/null
+++ b/Help/policy/CMP0073.rst
@@ -0,0 +1,27 @@
+CMP0073
+-------
+
+.. versionadded:: 3.12
+
+Do not produce legacy ``_LIB_DEPENDS`` cache entries.
+
+Ancient CMake versions once used ``<tgt>_LIB_DEPENDS`` cache entries to
+propagate library link dependencies. This has long been done by other
+means, leaving the :command:`export_library_dependencies` command as the
+only user of these values. That command has long been disallowed by
+policy :policy:`CMP0033`, but the ``<tgt>_LIB_DEPENDS`` cache entries
+were left for compatibility with possible non-standard uses by projects.
+
+CMake 3.12 and above now prefer to not produce these cache entries
+at all. This policy provides compatibility with projects that have
+not been updated to avoid using them.
+
+The ``OLD`` behavior for this policy is to set ``<tgt>_LIB_DEPENDS`` cache
+entries. The ``NEW`` behavior for this policy is to not set them.
+
+This policy was introduced in CMake version 3.12. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike most policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0074.rst b/Help/policy/CMP0074.rst
new file mode 100644
index 0000000..863bbb2
--- /dev/null
+++ b/Help/policy/CMP0074.rst
@@ -0,0 +1,25 @@
+CMP0074
+-------
+
+.. versionadded:: 3.12
+
+:command:`find_package` uses ``<PackageName>_ROOT`` variables.
+
+In CMake 3.12 and above the :command:`find_package(<PackageName>)` command now
+searches prefixes specified by the :variable:`<PackageName>_ROOT` CMake
+variable and the :envvar:`<PackageName>_ROOT` environment variable.
+Package roots are maintained as a stack so nested calls to all ``find_*``
+commands inside find modules and config packages also search the roots as
+prefixes. This policy provides compatibility with projects that have not been
+updated to avoid using ``<PackageName>_ROOT`` variables for other purposes.
+
+The ``OLD`` behavior for this policy is to ignore ``<PackageName>_ROOT``
+variables. The ``NEW`` behavior for this policy is to use
+``<PackageName>_ROOT`` variables.
+
+This policy was introduced in CMake version 3.12. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0075.rst b/Help/policy/CMP0075.rst
new file mode 100644
index 0000000..4213782
--- /dev/null
+++ b/Help/policy/CMP0075.rst
@@ -0,0 +1,28 @@
+CMP0075
+-------
+
+.. versionadded:: 3.12
+
+Include file check macros honor ``CMAKE_REQUIRED_LIBRARIES``.
+
+In CMake 3.12 and above, the
+
+* ``check_include_file`` macro in the :module:`CheckIncludeFile` module, the
+* ``check_include_file_cxx`` macro in the
+ :module:`CheckIncludeFileCXX` module, and the
+* ``check_include_files`` macro in the :module:`CheckIncludeFiles` module
+
+now prefer to link the check executable to the libraries listed in the
+``CMAKE_REQUIRED_LIBRARIES`` variable. This policy provides compatibility
+with projects that have not been updated to expect this behavior.
+
+The ``OLD`` behavior for this policy is to ignore ``CMAKE_REQUIRED_LIBRARIES``
+in the include file check macros. The ``NEW`` behavior of this policy is to
+honor ``CMAKE_REQUIRED_LIBRARIES`` in the include file check macros.
+
+This policy was introduced in CMake version 3.12. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0076.rst b/Help/policy/CMP0076.rst
new file mode 100644
index 0000000..edca742
--- /dev/null
+++ b/Help/policy/CMP0076.rst
@@ -0,0 +1,28 @@
+CMP0076
+-------
+
+.. versionadded:: 3.13
+
+The :command:`target_sources` command converts relative paths to absolute.
+
+In CMake 3.13 and above, the :command:`target_sources` command now converts
+relative source file paths to absolute paths in the following cases:
+
+* Source files are added to the target's :prop_tgt:`INTERFACE_SOURCES`
+ property.
+* The target's :prop_tgt:`SOURCE_DIR` property differs from
+ :variable:`CMAKE_CURRENT_SOURCE_DIR`.
+
+A path that begins with a generator expression is always left unmodified.
+
+This policy provides compatibility with projects that have not been updated
+to expect this behavior. The ``OLD`` behavior for this policy is to leave
+all relative source file paths unmodified. The ``NEW`` behavior of this
+policy is to convert relative paths to absolute according to above rules.
+
+This policy was introduced in CMake version 3.13. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0077.rst b/Help/policy/CMP0077.rst
new file mode 100644
index 0000000..174cde9
--- /dev/null
+++ b/Help/policy/CMP0077.rst
@@ -0,0 +1,54 @@
+CMP0077
+-------
+
+.. versionadded:: 3.13
+
+:command:`option` honors normal variables.
+
+The :command:`option` command is typically used to create a cache entry
+to allow users to set the option. However, there are cases in which a
+normal (non-cached) variable of the same name as the option may be
+defined by the project prior to calling the :command:`option` command.
+For example, a project that embeds another project as a subdirectory
+may want to hard-code options of the subproject to build the way it needs.
+
+For historical reasons in CMake 3.12 and below the :command:`option`
+command *removes* a normal (non-cached) variable of the same name when:
+
+* a cache entry of the specified name does not exist at all, or
+* a cache entry of the specified name exists but has not been given
+ a type (e.g. via ``-D<name>=ON`` on the command line).
+
+In both of these cases (typically on the first run in a new build tree),
+the :command:`option` command gives the cache entry type ``BOOL`` and
+removes any normal (non-cached) variable of the same name. In the
+remaining case that the cache entry of the specified name already
+exists and has a type (typically on later runs in a build tree), the
+:command:`option` command changes nothing and any normal variable of
+the same name remains set.
+
+In CMake 3.13 and above the :command:`option` command prefers to
+do nothing when a normal variable of the given name already exists.
+It does not create or update a cache entry or remove the normal variable.
+The new behavior is consistent between the first and later runs in a
+build tree. This policy provides compatibility with projects that have
+not been updated to expect the new behavior.
+
+When the :command:`option` command sees a normal variable of the given
+name:
+
+* The ``OLD`` behavior for this policy is to proceed even when a normal
+ variable of the same name exists. If the cache entry does not already
+ exist and have a type then it is created and/or given a type and the
+ normal variable is removed.
+
+* The ``NEW`` behavior for this policy is to do nothing when a normal
+ variable of the same name exists. The normal variable is not removed.
+ The cache entry is not created or updated and is ignored if it exists.
+
+This policy was introduced in CMake version 3.13. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0078.rst b/Help/policy/CMP0078.rst
new file mode 100644
index 0000000..89fdb0b
--- /dev/null
+++ b/Help/policy/CMP0078.rst
@@ -0,0 +1,26 @@
+CMP0078
+-------
+
+.. versionadded:: 3.13
+
+:module:`UseSWIG` generates standard target names.
+
+Starting with CMake 3.13, :module:`UseSWIG` generates now standard target
+names. This policy provides compatibility with projects that expect the legacy
+behavior.
+
+The ``OLD`` behavior for this policy relies on
+``UseSWIG_TARGET_NAME_PREFERENCE`` variable that can be used to specify an
+explicit preference. The value may be one of:
+
+* ``LEGACY``: legacy strategy is applied. Variable
+ ``SWIG_MODULE_<name>_REAL_NAME`` must be used to get real target name.
+ This is the default if not specified.
+* ``STANDARD``: target name matches specified name.
+
+This policy was introduced in CMake version 3.13. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0079.rst b/Help/policy/CMP0079.rst
new file mode 100644
index 0000000..01aa08d
--- /dev/null
+++ b/Help/policy/CMP0079.rst
@@ -0,0 +1,42 @@
+CMP0079
+-------
+
+.. versionadded:: 3.13
+
+:command:`target_link_libraries` allows use with targets in other directories.
+
+Prior to CMake 3.13 the :command:`target_link_libraries` command did not
+accept targets not created in the calling directory as its first argument
+for calls that update the :prop_tgt:`LINK_LIBRARIES` of the target itself.
+It did accidentally accept targets from other directories on calls that
+only update the :prop_tgt:`INTERFACE_LINK_LIBRARIES`, but would simply
+add entries to the property as if the call were made in the original
+directory. Thus link interface libraries specified this way were always
+looked up by generators in the scope of the original target rather than
+in the scope that called :command:`target_link_libraries`.
+
+CMake 3.13 now allows the :command:`target_link_libraries` command to
+be called from any directory to add link dependencies and link interface
+libraries to targets created in other directories. The entries are added
+to :prop_tgt:`LINK_LIBRARIES` and :prop_tgt:`INTERFACE_LINK_LIBRARIES`
+using a special (internal) suffix to tell the generators to look up the
+names in the calling scope rather than the scope that created the target.
+
+This policy provides compatibility with projects that already use
+:command:`target_link_libraries` with the ``INTERFACE`` keyword
+on a target in another directory to add :prop_tgt:`INTERFACE_LINK_LIBRARIES`
+entries to be looked up in the target's directory. Such projects should
+be updated to be aware of the new scoping rules in that case.
+
+The ``OLD`` behavior of this policy is to disallow
+:command:`target_link_libraries` calls naming targets from another directory
+except in the previously accidentally allowed case of using the ``INTERFACE``
+keyword only. The ``NEW`` behavior of this policy is to allow all such
+calls but use the new scoping rules.
+
+This policy was introduced in CMake version 3.13. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0080.rst b/Help/policy/CMP0080.rst
new file mode 100644
index 0000000..789efea
--- /dev/null
+++ b/Help/policy/CMP0080.rst
@@ -0,0 +1,27 @@
+CMP0080
+-------
+
+.. versionadded:: 3.13
+
+:module:`BundleUtilities` cannot be included at configure time.
+
+The macros provided by :module:`BundleUtilities` are intended to be invoked
+at install time rather than at configure time, because they depend on the
+listed targets already existing at the time they are invoked. If they are
+invoked at configure time, the targets haven't been built yet, and the
+commands will fail.
+
+This policy restricts the inclusion of :module:`BundleUtilities` to
+``cmake -P`` style scripts and install rules. Specifically, it looks for the
+presence of :variable:`CMAKE_GENERATOR` and throws a fatal error if it exists.
+
+The ``OLD`` behavior of this policy is to allow :module:`BundleUtilities` to
+be included at configure time. The ``NEW`` behavior of this policy is to
+disallow such inclusion.
+
+This policy was introduced in CMake version 3.13. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0081.rst b/Help/policy/CMP0081.rst
new file mode 100644
index 0000000..d1573dd
--- /dev/null
+++ b/Help/policy/CMP0081.rst
@@ -0,0 +1,24 @@
+CMP0081
+-------
+
+.. versionadded:: 3.13
+
+Relative paths not allowed in :prop_tgt:`LINK_DIRECTORIES` target property.
+
+CMake 3.12 and lower allowed the :prop_dir:`LINK_DIRECTORIES` directory
+property to contain relative paths. The base path for such relative
+entries is not well defined. CMake 3.13 and later will issue a
+``FATAL_ERROR`` if the :prop_tgt:`LINK_DIRECTORIES` target property
+(which is initialized by the :prop_dir:`LINK_DIRECTORIES` directory property)
+contains a relative path.
+
+The ``OLD`` behavior for this policy is not to warn about relative paths
+in the :prop_tgt:`LINK_DIRECTORIES` target property. The ``NEW`` behavior for
+this policy is to issue a ``FATAL_ERROR`` if :prop_tgt:`LINK_DIRECTORIES`
+contains a relative path.
+
+This policy was introduced in CMake version 3.13. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0082.rst b/Help/policy/CMP0082.rst
new file mode 100644
index 0000000..25c9580
--- /dev/null
+++ b/Help/policy/CMP0082.rst
@@ -0,0 +1,28 @@
+CMP0082
+-------
+
+.. versionadded:: 3.14
+
+Install rules from :command:`add_subdirectory` calls are interleaved with
+those in caller.
+
+CMake 3.13 and lower ran the install rules from :command:`add_subdirectory`
+after all other install rules, even if :command:`add_subdirectory` was called
+before the other install rules. CMake 3.14 and above prefer to interleave
+these :command:`add_subdirectory` install rules with the others so that
+they are run in the order they are declared. This policy provides
+compatibility for projects that have not been updated to expect the
+new behavior.
+
+The ``OLD`` behavior for this policy is to run the install rules from
+:command:`add_subdirectory` after the other install rules. The ``NEW``
+behavior for this policy is to run all install rules in the order they are
+declared.
+
+This policy was introduced in CMake version 3.14. Unlike most policies,
+CMake version |release| does *not* warn by default when this policy
+is not set and simply uses ``OLD`` behavior. See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0082 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0083.rst b/Help/policy/CMP0083.rst
new file mode 100644
index 0000000..7518ee3
--- /dev/null
+++ b/Help/policy/CMP0083.rst
@@ -0,0 +1,71 @@
+CMP0083
+-------
+
+.. versionadded:: 3.14
+
+To control generation of Position Independent Executable (``PIE``) or not, some
+flags are required at link time.
+
+CMake 3.13 and lower did not add these link flags when
+:prop_tgt:`POSITION_INDEPENDENT_CODE` is set.
+
+The ``OLD`` behavior for this policy is to not manage ``PIE`` link flags. The
+``NEW`` behavior is to add link flags if :prop_tgt:`POSITION_INDEPENDENT_CODE`
+is set:
+
+* Set to ``TRUE``: flags to produce a position independent executable are
+ passed to the linker step. For example ``-pie`` for ``GCC``.
+* Set to ``FALSE``: flags not to produce a position independent executable are
+ passed to the linker step. For example ``-no-pie`` for ``GCC``.
+* Not set: no flags are passed to the linker step.
+
+Since a given linker may not support ``PIE`` flags in all environments in
+which it is used, it is the project's responsibility to use the
+:module:`CheckPIESupported` module to check for support to ensure that the
+:prop_tgt:`POSITION_INDEPENDENT_CODE` target property for executables will be
+honored at link time.
+
+This policy was introduced in CMake version 3.14. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike most policies, CMake version |release| does not warn when this policy is
+not set and simply uses ``OLD`` behavior.
+
+.. Note::
+
+ Android platform has a special handling of ``PIE`` so it is not required
+ to use the :module:`CheckPIESupported` module to ensure flags are passed to
+ the linker.
+
+.. include:: DEPRECATED.txt
+
+Examples
+^^^^^^^^
+
+Behave like CMake 3.13 and do not apply any ``PIE`` flags at link stage.
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.13)
+ project(foo)
+
+ # ...
+
+ add_executable(foo ...)
+ set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE TRUE)
+
+Use the :module:`CheckPIESupported` module to detect whether ``PIE`` is
+supported by the current linker and environment. Apply ``PIE`` flags only
+if the linker supports them.
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.14) # CMP0083 NEW
+ project(foo)
+
+ include(CheckPIESupported)
+ check_pie_supported()
+
+ # ...
+
+ add_executable(foo ...)
+ set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE TRUE)
diff --git a/Help/policy/CMP0084.rst b/Help/policy/CMP0084.rst
new file mode 100644
index 0000000..9547701
--- /dev/null
+++ b/Help/policy/CMP0084.rst
@@ -0,0 +1,28 @@
+CMP0084
+-------
+
+.. versionadded:: 3.14
+
+The :module:`FindQt` module does not exist for :command:`find_package`.
+
+The existence of :module:`FindQt` means that for Qt upstream to provide
+package config files that can be found by ``find_package(Qt)``, the consuming
+project has to explicitly specify ``find_package(Qt CONFIG)``. Removing this
+module gives Qt a path forward for exporting its own config files which can
+easily be found by consuming projects.
+
+This policy pretends that CMake's internal :module:`FindQt` module does not
+exist for :command:`find_package`. If a project really wants to use Qt 3 or 4,
+it can call ``find_package(Qt[34])``, ``include(FindQt)``, or add
+:module:`FindQt` to their :variable:`CMAKE_MODULE_PATH`.
+
+The ``OLD`` behavior of this policy is for :module:`FindQt` to exist for
+:command:`find_package`. The ``NEW`` behavior is to pretend that it doesn't
+exist for :command:`find_package`.
+
+This policy was introduced in CMake version 3.14. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0085.rst b/Help/policy/CMP0085.rst
new file mode 100644
index 0000000..d90c72f
--- /dev/null
+++ b/Help/policy/CMP0085.rst
@@ -0,0 +1,23 @@
+CMP0085
+-------
+
+.. versionadded:: 3.14
+
+``$<IN_LIST:...>`` handles empty list items.
+
+In CMake 3.13 and lower, the ``$<IN_LIST:...>`` generator expression always
+returned ``0`` if the first argument was empty, even if the list contained an
+empty item. This behavior is inconsistent with the ``IN_LIST`` behavior of
+:command:`if`, which this generator expression is meant to emulate. CMake 3.14
+and later handles this case correctly.
+
+The ``OLD`` behavior of this policy is for ``$<IN_LIST:...>`` to always return
+``0`` if the first argument is empty. The ``NEW`` behavior is to return ``1``
+if the first argument is empty and the list contains an empty item.
+
+This policy was introduced in CMake version 3.14. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0086.rst b/Help/policy/CMP0086.rst
new file mode 100644
index 0000000..725b502
--- /dev/null
+++ b/Help/policy/CMP0086.rst
@@ -0,0 +1,22 @@
+CMP0086
+-------
+
+.. versionadded:: 3.14
+
+:module:`UseSWIG` honors ``SWIG_MODULE_NAME`` via ``-module`` flag.
+
+Starting with CMake 3.14, :module:`UseSWIG` passes option
+``-module <module_name>`` to ``SWIG`` compiler if the file property
+``SWIG_MODULE_NAME`` is specified. This policy provides compatibility with
+projects that expect the legacy behavior.
+
+The ``OLD`` behavior for this policy is to never pass ``-module`` option.
+The ``NEW`` behavior is to pass ``-module`` option to ``SWIG`` compiler if
+``SWIG_MODULE_NAME`` is specified.
+
+This policy was introduced in CMake version 3.14. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0087.rst b/Help/policy/CMP0087.rst
new file mode 100644
index 0000000..4a65506
--- /dev/null
+++ b/Help/policy/CMP0087.rst
@@ -0,0 +1,31 @@
+CMP0087
+-------
+
+.. versionadded:: 3.14
+
+:command:`install(CODE)` and :command:`install(SCRIPT)` support generator
+expressions.
+
+In CMake 3.13 and earlier, :command:`install(CODE)` and
+:command:`install(SCRIPT)` did not evaluate generator expressions. CMake 3.14
+and later will evaluate generator expressions for :command:`install(CODE)` and
+:command:`install(SCRIPT)`.
+
+The ``OLD`` behavior of this policy is for :command:`install(CODE)` and
+:command:`install(SCRIPT)` to not evaluate generator expressions. The ``NEW``
+behavior is to evaluate generator expressions for :command:`install(CODE)` and
+:command:`install(SCRIPT)`.
+
+Note that it is the value of this policy setting at the end of the directory
+scope that is important, not its setting at the time of the call to
+:command:`install(CODE)` or :command:`install(SCRIPT)`. This has implications
+for calling these commands from places that have their own policy scope but not
+their own directory scope (e.g. from files brought in via :command:`include()`
+rather than :command:`add_subdirectory()`).
+
+This policy was introduced in CMake version 3.14. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0088.rst b/Help/policy/CMP0088.rst
new file mode 100644
index 0000000..1840a58
--- /dev/null
+++ b/Help/policy/CMP0088.rst
@@ -0,0 +1,31 @@
+CMP0088
+-------
+
+.. versionadded:: 3.14
+
+:module:`FindBISON` runs bison in :variable:`CMAKE_CURRENT_BINARY_DIR`
+when executing.
+
+The module provides a ``BISON_TARGET`` macro which generates BISON output.
+In CMake 3.13 and below the macro would generate a custom command that runs
+``bison`` in the source directory. CMake 3.14 and later prefer to run it
+in the build directory and use :variable:`CMAKE_CURRENT_BINARY_DIR` as the
+``WORKING_DIRECTORY`` of its :command:`add_custom_command` invocation.
+This ensures that any implicitly generated file is written to the build
+tree rather than the source.
+
+This policy provides compatibility for projects that have not been updated
+to expect the new behavior.
+
+The ``OLD`` behavior for this policy is for ``BISON_TARGET`` to use
+the current source directory for the ``WORKING_DIRECTORY`` and where
+to generate implicit files. The ``NEW`` behavior of this policy is to
+use the current binary directory for the ``WORKING_DIRECTORY`` and where
+to generate implicit files.
+
+This policy was introduced in CMake version 3.14. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike most policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0089.rst b/Help/policy/CMP0089.rst
new file mode 100644
index 0000000..e3fc77a
--- /dev/null
+++ b/Help/policy/CMP0089.rst
@@ -0,0 +1,32 @@
+CMP0089
+-------
+
+.. versionadded:: 3.15
+
+Compiler id for IBM Clang-based XL compilers is now ``XLClang``.
+
+CMake 3.15 and above recognize that IBM's Clang-based XL compilers
+that define ``__ibmxl__`` are a new front-end distinct from ``xlc``
+with a different command line and set of capabilities.
+CMake now prefers to present this to projects by setting the
+:variable:`CMAKE_<LANG>_COMPILER_ID` variable to ``XLClang`` instead
+of ``XL``. However, existing projects may assume the compiler id for
+Clang-based XL is just ``XL`` as it was in CMake versions prior to 3.15.
+Therefore this policy determines for Clang-based XL compilers which
+compiler id to report in the :variable:`CMAKE_<LANG>_COMPILER_ID`
+variable after language ``<LANG>`` is enabled by the :command:`project`
+or :command:`enable_language` command. The policy must be set prior
+to the invocation of either command.
+
+The ``OLD`` behavior for this policy is to use compiler id ``XL``. The
+``NEW`` behavior for this policy is to use compiler id ``XLClang``.
+
+This policy was introduced in CMake version 3.15. Use the
+:command:`cmake_policy` command to set this policy to ``OLD`` or ``NEW`` explicitly.
+Unlike most policies, CMake version |release| does *not* warn
+by default when this policy is not set and simply uses ``OLD`` behavior.
+See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0089 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0090.rst b/Help/policy/CMP0090.rst
new file mode 100644
index 0000000..58dd999
--- /dev/null
+++ b/Help/policy/CMP0090.rst
@@ -0,0 +1,29 @@
+CMP0090
+-------
+
+.. versionadded:: 3.15
+
+:command:`export(PACKAGE)` does not populate package registry by default.
+
+In CMake 3.14 and below the :command:`export(PACKAGE)` command populated the
+user package registry by default and users needed to set the
+:variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` to disable it, e.g. in automated
+build and packaging environments. Since the user package registry is stored
+outside the build tree, this side effect should not be enabled by default.
+Therefore CMake 3.15 and above prefer that :command:`export(PACKAGE)` does
+nothing unless an explicit :variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` variable
+is set to enable it. This policy provides compatibility with projects that
+have not been updated.
+
+The ``OLD`` behavior for this policy is for :command:`export(PACKAGE)` command
+to populate the user package registry unless
+:variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` is enabled.
+The ``NEW`` behavior is for :command:`export(PACKAGE)` command to do nothing
+unless the :variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` is enabled.
+
+This policy was introduced in CMake version 3.15. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike most policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0091.rst b/Help/policy/CMP0091.rst
new file mode 100644
index 0000000..ffc0ade
--- /dev/null
+++ b/Help/policy/CMP0091.rst
@@ -0,0 +1,51 @@
+CMP0091
+-------
+
+.. versionadded:: 3.15
+
+MSVC runtime library flags are selected by an abstraction.
+
+Compilers targeting the MSVC ABI have flags to select the MSVC runtime library.
+Runtime library selection typically varies with build configuration because
+there is a separate runtime library for Debug builds.
+
+In CMake 3.14 and below, MSVC runtime library selection flags are added to
+the default :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` cache entries by CMake
+automatically. This allows users to edit their cache entries to adjust the
+flags. However, the presence of such default flags is problematic for
+projects that want to choose a different runtime library programmatically.
+In particular, it requires string editing of the
+:variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` variables with knowledge of the
+CMake builtin defaults so they can be replaced.
+
+CMake 3.15 and above prefer to leave the MSVC runtime library selection flags
+out of the default :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` values and instead
+offer a first-class abstraction. The :variable:`CMAKE_MSVC_RUNTIME_LIBRARY`
+variable and :prop_tgt:`MSVC_RUNTIME_LIBRARY` target property may be set to
+select the MSVC runtime library. If they are not set then CMake uses the
+default value ``MultiThreaded$<$<CONFIG:Debug>:Debug>DLL`` which is
+equivalent to the original flags.
+
+This policy provides compatibility with projects that have not been updated
+to be aware of the abstraction. The policy setting takes effect as of the
+first :command:`project` or :command:`enable_language` command that enables
+a language whose compiler targets the MSVC ABI.
+
+.. note::
+
+ Once the policy has taken effect at the top of a project, that choice
+ must be used throughout the tree. In projects that have nested projects
+ in subdirectories, be sure to convert everything together.
+
+The ``OLD`` behavior for this policy is to place MSVC runtime library
+flags in the default :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` cache
+entries and ignore the :variable:`CMAKE_MSVC_RUNTIME_LIBRARY` abstraction.
+The ``NEW`` behavior for this policy is to *not* place MSVC runtime
+library flags in the default cache entries and use the abstraction instead.
+
+This policy was introduced in CMake version 3.15. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0092.rst b/Help/policy/CMP0092.rst
new file mode 100644
index 0000000..2f39830
--- /dev/null
+++ b/Help/policy/CMP0092.rst
@@ -0,0 +1,40 @@
+CMP0092
+-------
+
+.. versionadded:: 3.15
+
+MSVC warning flags are not in :variable:`CMAKE_<LANG>_FLAGS` by default.
+
+When using MSVC-like compilers in CMake 3.14 and below, warning flags
+like ``/W3`` are added to :variable:`CMAKE_<LANG>_FLAGS` by default.
+This is problematic for projects that want to choose a different warning
+level programmatically. In particular, it requires string editing of the
+:variable:`CMAKE_<LANG>_FLAGS` variables with knowledge of the
+CMake builtin defaults so they can be replaced.
+
+CMake 3.15 and above prefer to leave out warning flags from the value of
+:variable:`CMAKE_<LANG>_FLAGS` by default.
+
+This policy provides compatibility with projects that have not been updated
+to expect the lack of warning flags. The policy setting takes effect as of
+the first :command:`project` or :command:`enable_language` command that
+initializes :variable:`CMAKE_<LANG>_FLAGS` for a given language ``<LANG>``.
+
+.. note::
+
+ Once the policy has taken effect at the top of a project for a given
+ language, that choice must be used throughout the tree for that language.
+ In projects that have nested projects in subdirectories, be sure to
+ convert everything together.
+
+The ``OLD`` behavior for this policy is to place MSVC warning flags in the
+default :variable:`CMAKE_<LANG>_FLAGS` cache entries. The ``NEW`` behavior
+for this policy is to *not* place MSVC warning flags in the default cache
+entries.
+
+This policy was introduced in CMake version 3.15. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0093.rst b/Help/policy/CMP0093.rst
new file mode 100644
index 0000000..4a9955f
--- /dev/null
+++ b/Help/policy/CMP0093.rst
@@ -0,0 +1,26 @@
+CMP0093
+-------
+
+.. versionadded:: 3.15
+
+:module:`FindBoost` reports ``Boost_VERSION`` in ``x.y.z`` format.
+
+In CMake 3.14 and below the module would report the Boost version
+number as specified in the preprocessor definition ``BOOST_VERSION`` in
+the ``boost/version.hpp`` file. In CMake 3.15 and later it is preferred
+that the reported version number matches the ``x.y.z`` format reported
+by the CMake package shipped with Boost ``1.70.0`` and later. The macro
+value is still reported in the ``Boost_VERSION_MACRO`` variable.
+
+The ``OLD`` behavior for this policy is for :module:`FindBoost` to report
+``Boost_VERSION`` as specified in the preprocessor definition
+``BOOST_VERSION`` in ``boost/version.hpp``. The ``NEW`` behavior for this
+policy is for :module:`FindBoost` to report ``Boost_VERSION`` in
+``x.y.z`` format.
+
+This policy was introduced in CMake version 3.15. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses the ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0094.rst b/Help/policy/CMP0094.rst
new file mode 100644
index 0000000..1b57658
--- /dev/null
+++ b/Help/policy/CMP0094.rst
@@ -0,0 +1,24 @@
+CMP0094
+-------
+
+.. versionadded:: 3.15
+
+Modules :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+use ``LOCATION`` for lookup strategy.
+
+Starting with CMake 3.15, Modules :module:`FindPython3`, :module:`FindPython2`
+and :module:`FindPython` set value ``LOCATION`` for, respectively, variables
+``Python3_FIND_STRATEGY``, ``Python2_FIND_STRATEGY`` and
+``Python_FIND_STRATEGY``. This policy provides compatibility with projects that
+expect the legacy behavior.
+
+The ``OLD`` behavior for this policy set value ``VERSION`` for variables
+``Python3_FIND_STRATEGY``, ``Python2_FIND_STRATEGY`` and
+``Python_FIND_STRATEGY``.
+
+This policy was introduced in CMake version 3.15. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses the ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0095.rst b/Help/policy/CMP0095.rst
new file mode 100644
index 0000000..ebdbab6
--- /dev/null
+++ b/Help/policy/CMP0095.rst
@@ -0,0 +1,32 @@
+CMP0095
+-------
+
+.. versionadded:: 3.16
+
+``RPATH`` entries are properly escaped in the intermediary CMake install script.
+
+In CMake 3.15 and earlier, ``RPATH`` entries set via
+:variable:`CMAKE_INSTALL_RPATH` or via :prop_tgt:`INSTALL_RPATH` have not been
+escaped before being inserted into the ``cmake_install.cmake`` script. Dynamic
+linkers on ELF-based systems (e.g. Linux and FreeBSD) allow certain keywords in
+``RPATH`` entries, such as ``${ORIGIN}`` (More details are available in the
+``ld.so`` man pages on those systems). The syntax of these keywords can match
+CMake's variable syntax. In order to not be substituted (usually to an empty
+string) already by the intermediary ``cmake_install.cmake`` script, the user had
+to double-escape such ``RPATH`` keywords, e.g.
+``set(CMAKE_INSTALL_RPATH "\\\${ORIGIN}/../lib")``. Since the intermediary
+``cmake_install.cmake`` script is an implementation detail of CMake, CMake 3.16
+and later will make sure ``RPATH`` entries are inserted literally by escaping
+any coincidental CMake syntax.
+
+The ``OLD`` behavior of this policy is to not escape ``RPATH`` entries in the
+intermediary ``cmake_install.cmake`` script. The ``NEW`` behavior is to properly
+escape coincidental CMake syntax in ``RPATH`` entries when generating the
+intermediary ``cmake_install.cmake`` script.
+
+This policy was introduced in CMake version 3.16. CMake version |release| warns
+when the policy is not set and detected usage of CMake-like syntax and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set it to ``OLD``
+or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0096.rst b/Help/policy/CMP0096.rst
new file mode 100644
index 0000000..8fd6f72
--- /dev/null
+++ b/Help/policy/CMP0096.rst
@@ -0,0 +1,27 @@
+CMP0096
+-------
+
+.. versionadded:: 3.16
+
+The :command:`project` command preserves leading zeros in version components.
+
+When a ``VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]`` argument is given
+to the :command:`project` command, it stores the version string in the
+``PROJECT_VERSION`` variable and stores individual integer version components
+in ``PROJECT_VERSION_{MAJOR,MINOR,PATCH,TWEAK}`` variables (see policy
+:policy:`CMP0048`). CMake 3.15 and below dropped leading zeros from each
+component. CMake 3.16 and higher prefer to preserve leading zeros. This
+policy provides compatibility for projects that have not been updated to
+expect the new behavior.
+
+The ``OLD`` behavior of this policy drops leading zeros in all components,
+e.g. such that version ``1.07.06`` becomes ``1.7.6``. The ``NEW`` behavior
+of this policy preserves the leading zeros in all components, such that
+version ``1.07.06`` remains unchanged.
+
+This policy was introduced in CMake version 3.16. Unlike many policies, CMake
+version |release| does *not* warn when this policy is not set and simply uses
+the ``OLD`` behavior. Use the :command:`cmake_policy` command to set it to
+``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0097.rst b/Help/policy/CMP0097.rst
new file mode 100644
index 0000000..2240874
--- /dev/null
+++ b/Help/policy/CMP0097.rst
@@ -0,0 +1,25 @@
+CMP0097
+-------
+
+.. versionadded:: 3.16
+
+:command:`ExternalProject_Add` with ``GIT_SUBMODULES ""`` initializes no
+submodules.
+
+The module provides a ``GIT_SUBMODULES`` option which controls what submodules
+to initialize and update. Starting with CMake 3.16, explicitly setting
+``GIT_SUBMODULES`` to an empty string means no submodules will be initialized
+or updated.
+
+This policy provides compatibility for projects that have not been updated
+to expect the new behavior.
+
+The ``OLD`` behavior for this policy is for ``GIT_SUBMODULES`` when set to
+an empty string to initialize and update all git submodules.
+The ``NEW`` behavior for this policy is for ``GIT_SUBMODULES`` when set to
+an empty string to initialize and update no git submodules.
+
+This policy was introduced in CMake version 3.16. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike most policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
diff --git a/Help/policy/CMP0098.rst b/Help/policy/CMP0098.rst
new file mode 100644
index 0000000..e793380
--- /dev/null
+++ b/Help/policy/CMP0098.rst
@@ -0,0 +1,32 @@
+CMP0098
+-------
+
+.. versionadded:: 3.17
+
+:module:`FindFLEX` runs ``flex`` in directory
+:variable:`CMAKE_CURRENT_BINARY_DIR` when executing.
+
+The module provides a ``FLEX_TARGET`` macro which generates FLEX output.
+In CMake 3.16 and below the macro would generate a custom command that runs
+``flex`` in the current source directory. CMake 3.17 and later prefer to
+run it in the build directory and use :variable:`CMAKE_CURRENT_BINARY_DIR`
+as the ``WORKING_DIRECTORY`` of its :command:`add_custom_command` invocation.
+This ensures that any implicitly generated file is written relative to the
+build tree rather than the source tree, unless the generated file is
+provided as absolute path.
+
+This policy provides compatibility for projects that have not been updated
+to expect the new behavior.
+
+The ``OLD`` behavior for this policy is for ``FLEX_TARGET`` to use
+the current source directory for the ``WORKING_DIRECTORY`` and where
+to generate implicit files. The ``NEW`` behavior of this policy is to
+use the current binary directory for the ``WORKING_DIRECTORY`` relative to
+which implicit files are generated unless provided as absolute path.
+
+This policy was introduced in CMake version 3.17. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0099.rst b/Help/policy/CMP0099.rst
new file mode 100644
index 0000000..0c64949
--- /dev/null
+++ b/Help/policy/CMP0099.rst
@@ -0,0 +1,26 @@
+CMP0099
+-------
+
+.. versionadded:: 3.17
+
+Target link properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
+:prop_tgt:`INTERFACE_LINK_DIRECTORIES` and :prop_tgt:`INTERFACE_LINK_DEPENDS`
+are now transitive over private dependencies of static libraries.
+
+In CMake 3.16 and below the interface link properties attached to libraries
+are not propagated for private dependencies of static libraries.
+Only the libraries themselves are propagated to link the dependent binary.
+CMake 3.17 and later prefer to propagate all interface link properties.
+This policy provides compatibility for projects that have not been updated
+to expect the new behavior.
+
+The ``OLD`` behavior for this policy is to not propagate interface link
+properties. The ``NEW`` behavior of this policy is to propagate interface link
+properties.
+
+This policy was introduced in CMake version 3.17. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0100.rst b/Help/policy/CMP0100.rst
new file mode 100644
index 0000000..730fa82
--- /dev/null
+++ b/Help/policy/CMP0100.rst
@@ -0,0 +1,42 @@
+CMP0100
+-------
+
+.. versionadded:: 3.17
+
+Let :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC` process
+header files that end with a ``.hh`` extension.
+
+Since version 3.17, CMake processes header files that end with a
+``.hh`` extension in :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+In earlier CMake versions, these header files were ignored by
+:prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+
+This policy affects how header files that end with a ``.hh`` extension
+get treated in :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+
+The ``OLD`` behavior for this policy is to ignore ``.hh`` header files
+in :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+
+The ``NEW`` behavior for this policy is to process ``.hh`` header files
+in :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC` just like other header files.
+
+.. note::
+
+ To silence the ``CMP0100`` warning source files can be excluded from
+ :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC` processing by setting the
+ source file properties :prop_sf:`SKIP_AUTOMOC`, :prop_sf:`SKIP_AUTOUIC` or
+ :prop_sf:`SKIP_AUTOGEN`.
+
+ .. code-block:: cmake
+
+ # Source skip example:
+ set_property(SOURCE /path/to/file1.hh PROPERTY SKIP_AUTOMOC ON)
+ set_property(SOURCE /path/to/file2.hh PROPERTY SKIP_AUTOUIC ON)
+ set_property(SOURCE /path/to/file3.hh PROPERTY SKIP_AUTOGEN ON)
+
+This policy was introduced in CMake version 3.17.0. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0101.rst b/Help/policy/CMP0101.rst
new file mode 100644
index 0000000..f02bccc
--- /dev/null
+++ b/Help/policy/CMP0101.rst
@@ -0,0 +1,22 @@
+CMP0101
+-------
+
+.. versionadded:: 3.17
+
+:command:`target_compile_options` now honors ``BEFORE`` keyword in all scopes.
+
+In CMake 3.16 and below the :command:`target_compile_options` ignores the
+``BEFORE`` keyword in private scope. CMake 3.17 and later honors
+``BEFORE`` keyword in all scopes. This policy provides compatibility for
+projects that have not been updated to expect the new behavior.
+
+The ``OLD`` behavior for this policy is to not honor ``BEFORE`` keyword in
+private scope. The ``NEW`` behavior of this policy is to honor
+``BEFORE`` keyword in all scopes.
+
+This policy was introduced in CMake version 3.17. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0102.rst b/Help/policy/CMP0102.rst
new file mode 100644
index 0000000..78b5584
--- /dev/null
+++ b/Help/policy/CMP0102.rst
@@ -0,0 +1,27 @@
+CMP0102
+-------
+
+.. versionadded:: 3.17
+
+The :command:`mark_as_advanced` command no longer creates a cache entry if one
+does not already exist.
+
+In CMake 3.16 and below, if a variable was not defined at all or just defined
+locally, the :command:`mark_as_advanced` command would create a new cache
+entry with an ``UNINITIALIZED`` type and no value. When a :command:`find_path`
+(or other similar ``find_`` command) would next run, it would find this
+undefined cache entry and set it up with an empty string value. This process
+would end up deleting the local variable in the process (due to the way the
+cache works), effectively clearing any stored ``find_`` results that were only
+available in the local scope.
+
+The ``OLD`` behavior for this policy is to create the empty cache definition.
+The ``NEW`` behavior of this policy is to ignore variables which do not
+already exist in the cache.
+
+This policy was introduced in CMake version 3.17. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0103.rst b/Help/policy/CMP0103.rst
new file mode 100644
index 0000000..b5f44d1
--- /dev/null
+++ b/Help/policy/CMP0103.rst
@@ -0,0 +1,24 @@
+CMP0103
+-------
+
+.. versionadded:: 3.18
+
+Multiple calls to :command:`export` command with same ``FILE`` without
+``APPEND`` is no longer allowed.
+
+In CMake 3.17 and below, multiple calls to :command:`export` command with the
+same ``FILE`` without ``APPEND`` are accepted silently but only the last
+occurrence is taken into account during the generation.
+
+The ``OLD`` behavior for this policy is to ignore the multiple occurrences of
+ :command:`export` command except the last one.
+
+The ``NEW`` behavior of this policy is to raise an error on second call to
+:command:`export` command with same ``FILE`` without ``APPEND``.
+
+This policy was introduced in CMake version 3.18. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0104.rst b/Help/policy/CMP0104.rst
new file mode 100644
index 0000000..7c7a16e
--- /dev/null
+++ b/Help/policy/CMP0104.rst
@@ -0,0 +1,58 @@
+CMP0104
+-------
+
+.. versionadded:: 3.18
+
+Initialize :variable:`CMAKE_CUDA_ARCHITECTURES` when
+:variable:`CMAKE_CUDA_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` is ``NVIDIA``.
+Raise an error if :prop_tgt:`CUDA_ARCHITECTURES` is empty.
+
+:variable:`CMAKE_CUDA_ARCHITECTURES` introduced in CMake 3.18 is used to
+initialize :prop_tgt:`CUDA_ARCHITECTURES`, which passes correct code generation
+flags to the CUDA compiler.
+
+Previous to this users had to manually specify the code generation flags. This
+policy is for backwards compatibility with manually specifying code generation
+flags.
+
+The ``OLD`` behavior for this policy is to not initialize
+:variable:`CMAKE_CUDA_ARCHITECTURES` when
+:variable:`CMAKE_CUDA_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` is ``NVIDIA``.
+Empty :prop_tgt:`CUDA_ARCHITECTURES` is allowed.
+
+The ``NEW`` behavior of this policy is to initialize
+:variable:`CMAKE_CUDA_ARCHITECTURES` when
+:variable:`CMAKE_CUDA_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` is ``NVIDIA``
+and raise an error if :prop_tgt:`CUDA_ARCHITECTURES` is empty during generation.
+
+If :prop_tgt:`CUDA_ARCHITECTURES` is set to a false value no architectures
+flags are passed to the compiler. This is intended to support packagers and
+the rare cases where full control over the passed flags is required.
+
+This policy was introduced in CMake version 3.18. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
+
+Examples
+^^^^^^^^
+
+.. code-block:: cmake
+
+ set_property(TARGET tgt PROPERTY CUDA_ARCHITECTURES 35 50 72)
+
+Generates code for real and virtual architectures ``30``, ``50`` and ``72``.
+
+.. code-block:: cmake
+
+ set_property(TARGET tgt PROPERTY CUDA_ARCHITECTURES 70-real 72-virtual)
+
+Generates code for real architecture ``70`` and virtual architecture ``72``.
+
+.. code-block:: cmake
+
+ set_property(TARGET tgt PROPERTY CUDA_ARCHITECTURES OFF)
+
+CMake will not pass any architecture flags to the compiler.
diff --git a/Help/policy/CMP0105.rst b/Help/policy/CMP0105.rst
new file mode 100644
index 0000000..097a59a
--- /dev/null
+++ b/Help/policy/CMP0105.rst
@@ -0,0 +1,21 @@
+CMP0105
+-------
+
+.. versionadded:: 3.18
+
+:prop_tgt:`LINK_OPTIONS` and :prop_tgt:`INTERFACE_LINK_OPTIONS` target
+properties are now used for the device link step.
+
+In CMake 3.17 and below, link options are not used by the device link step.
+
+The ``OLD`` behavior for this policy is to ignore the link options.
+
+The ``NEW`` behavior of this policy is to use the link options during the
+device link step.
+
+This policy was introduced in CMake version 3.17. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0106.rst b/Help/policy/CMP0106.rst
new file mode 100644
index 0000000..18a6635
--- /dev/null
+++ b/Help/policy/CMP0106.rst
@@ -0,0 +1,21 @@
+CMP0106
+-------
+
+.. versionadded:: 3.18
+
+The :module:`Documentation` module is removed.
+
+The :module:`Documentation` was added as a support mechanism for the VTK
+project and was tuned for that project. Instead of CMake providing this module
+with (now old) VTK patterns for cache variables and required packages, the
+module is now deprecated by CMake itself.
+
+The ``OLD`` behavior of this policy is for :module:`Documentation` to add
+cache variables and find VTK documentation dependent packages. The ``NEW``
+behavior is to act as an empty module.
+
+This policy was introduced in CMake version 3.18. CMake version |release|
+warns when the policy is not set and uses ``OLD`` behavior. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0107.rst b/Help/policy/CMP0107.rst
new file mode 100644
index 0000000..da5ae06
--- /dev/null
+++ b/Help/policy/CMP0107.rst
@@ -0,0 +1,21 @@
+CMP0107
+-------
+
+.. versionadded:: 3.18
+
+It is not allowed to create an ``ALIAS`` target with the same name as an
+another target.
+
+In CMake 3.17 and below, an ``ALIAS`` target can overwrite silently an existing
+target with the same name.
+
+The ``OLD`` behavior for this policy is to allow target overwrite.
+
+The ``NEW`` behavior of this policy is to prevent target overwriting.
+
+This policy was introduced in CMake version 3.17. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0108.rst b/Help/policy/CMP0108.rst
new file mode 100644
index 0000000..4d1091d
--- /dev/null
+++ b/Help/policy/CMP0108.rst
@@ -0,0 +1,21 @@
+CMP0108
+-------
+
+.. versionadded:: 3.18
+
+A target is not allowed to link to itself even through an ``ALIAS`` target.
+
+In CMake 3.17 and below, a target can link to a target aliased to itself.
+
+The ``OLD`` behavior for this policy is to allow a target to link to a target
+aliased to itself.
+
+The ``NEW`` behavior of this policy is to prevent a target to link to itself
+through an ``ALIAS`` target.
+
+This policy was introduced in CMake version 3.17. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0109.rst b/Help/policy/CMP0109.rst
new file mode 100644
index 0000000..f86287f
--- /dev/null
+++ b/Help/policy/CMP0109.rst
@@ -0,0 +1,24 @@
+CMP0109
+-------
+
+.. versionadded:: 3.19
+
+:command:`find_program` requires permission to execute but not to read.
+
+In CMake 3.18 and below, the :command:`find_program` command on UNIX
+would find files that are readable without requiring execute permission,
+and would not find files that are executable without read permission.
+In CMake 3.19 and above, ``find_program`` now prefers to require execute
+permission but not read permission. This policy provides compatibility
+with projects that have not been updated to expect the new behavior.
+
+The ``OLD`` behavior for this policy is for ``find_program`` to require
+read permission but not execute permission.
+The ``NEW`` behavior for this policy is for ``find_program`` to require
+execute permission but not read permission.
+
+This policy was introduced in CMake version 3.19. CMake version |release|
+warns when the policy is not set and uses ``OLD`` behavior. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0110.rst b/Help/policy/CMP0110.rst
new file mode 100644
index 0000000..25a0008
--- /dev/null
+++ b/Help/policy/CMP0110.rst
@@ -0,0 +1,26 @@
+CMP0110
+-------
+
+.. versionadded:: 3.19
+
+:command:`add_test` supports arbitrary characters in test names.
+
+:command:`add_test` can now (officially) create tests with whitespace and
+other special characters in its name. Before CMake version 3.19 that was not
+allowed, however, it was possible to work around this limitation by explicitly
+putting escaped quotes arount the test's name in the ``add_test`` command.
+
+Although never officially supported several projects in the wild found and
+implemented this workaround. However, the new change which officially allows
+the ``add_test`` command to support whitespace and other special characters in
+test names now breaks that workaround. In order for these projects to work
+smoothly with newer CMake versions, this policy was introduced.
+
+The ``OLD`` behavior of this policy is to still prevent ``add_test`` from
+handling whitespace and special characters properly (if not using the
+mentioned workaround). The ``NEW`` behavior on the other hand allows names
+with whitespace and special characters for tests created by ``add_test``.
+
+This policy was introduced in CMake version 3.19. CMake version |release|
+warns when the policy is not set and uses ``OLD`` behavior. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
diff --git a/Help/policy/CMP0111.rst b/Help/policy/CMP0111.rst
new file mode 100644
index 0000000..e327583
--- /dev/null
+++ b/Help/policy/CMP0111.rst
@@ -0,0 +1,27 @@
+CMP0111
+-------
+
+.. versionadded:: 3.19
+
+An imported target missing its location property fails during generation.
+
+:ref:`Imported Targets` for library files and executables require that
+their location on disk is specified in a target property such as
+:prop_tgt:`IMPORTED_LOCATION`, :prop_tgt:`IMPORTED_IMPLIB`, or a
+per-configuration equivalent. If a needed location property is not set,
+CMake 3.18 and below generate the string ``<TARGET_NAME>-NOTFOUND`` in
+its place, which results in failures of the corresponding rules at build
+time. CMake 3.19 and above prefer instead to raise an error during
+generation. This policy provides compatibility for projects that have
+not been updated to expect the new behavior.
+
+The ``OLD`` behavior of this policy is to generate the location of an imported
+unknown, static or shared library target as ``<TARGET_NAME>-NOTFOUND`` if not
+set.
+The ``NEW`` behavior is to raise an error.
+
+This policy was introduced in CMake version 3.19. CMake version |release|
+warns when the policy is not set and uses ``OLD`` behavior. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0112.rst b/Help/policy/CMP0112.rst
new file mode 100644
index 0000000..313a51e
--- /dev/null
+++ b/Help/policy/CMP0112.rst
@@ -0,0 +1,40 @@
+CMP0112
+-------
+
+.. versionadded:: 3.19
+
+Target file component generator expressions do not add target dependencies.
+
+The following target-based generator expressions that query for directory or
+file name components no longer add a dependency on the evaluated target.
+
+ - ``TARGET_FILE_NAME``
+ - ``TARGET_FILE_DIR``
+ - ``TARGET_LINKER_FILE_BASE_NAME``
+ - ``TARGET_LINKER_FILE_NAME``
+ - ``TARGET_LINKER_FILE_DIR``
+ - ``TARGET_SONAME_FILE_NAME``
+ - ``TARGET_SONAME_FILE_DIR``
+ - ``TARGET_PDB_FILE_NAME``
+ - ``TARGET_PDB_FILE_DIR``
+ - ``TARGET_BUNDLE_DIR``
+ - ``TARGET_BUNDLE_CONTENT_DIR``
+
+
+In CMake 3.18 and lower a dependency on the evaluated target of the above
+generator expressions would always be added. CMake 3.19 and above prefer
+to not add this dependency. This policy provides compatibility for projects
+that have not been updated to expect the new behavior.
+
+The ``OLD`` behavior for this policy is to add a dependency on the evaluated
+target for the above generator expressions. The ``NEW`` behavior of
+this policy is to not add a dependency on the evaluated target for the
+above generator expressions.
+
+This policy was introduced in CMake version 3.19. Unlike many policies,
+CMake version |release| does *not* warn by default when this policy
+is not set and simply uses ``OLD`` behavior. See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0112 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0113.rst b/Help/policy/CMP0113.rst
new file mode 100644
index 0000000..6f56902
--- /dev/null
+++ b/Help/policy/CMP0113.rst
@@ -0,0 +1,43 @@
+CMP0113
+-------
+
+.. versionadded:: 3.19
+
+:ref:`Makefile Generators` do not repeat custom commands from target
+dependencies.
+
+Consider a chain of custom commands split across two dependent targets:
+
+.. code-block:: cmake
+
+ add_custom_command(OUTPUT output-not-created
+ COMMAND ... DEPENDS ...)
+ set_property(SOURCE output-not-created PROPERTY SYMBOLIC 1)
+ add_custom_command(OUTPUT output-created
+ COMMAND ... DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/output-not-created)
+ add_custom_target(first DEPENDS output-not-created)
+ add_custom_target(second DEPENDS output-created)
+ add_dependencies(second first)
+
+In CMake 3.18 and lower, the Makefile generators put a copy of both custom
+commands in the Makefile for target ``second`` even though its dependency on
+target ``first`` ensures that the first custom command runs before the second.
+Running ``make second`` would cause the first custom command to run once in
+the ``first`` target and then again in the ``second`` target.
+
+CMake 3.19 and above prefer to not duplicate custom commands in a target that
+are already generated in other targets on which the target depends (directly or
+indirectly). This policy provides compatibility for projects that have not
+been updated to expect the new behavior. In particular, projects that relied
+on the duplicate execution or that did not properly set the :prop_sf:`SYMBOLIC`
+source file property may be affected.
+
+The ``OLD`` behavior for this policy is to duplicate custom commands in
+dependent targets. The ``NEW`` behavior of this policy is to not duplicate
+custom commands in dependent targets.
+
+This policy was introduced in CMake version 3.19. Unlike many policies,
+CMake version |release| does *not* warn when this policy is not set and
+simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0114.rst b/Help/policy/CMP0114.rst
new file mode 100644
index 0000000..ae48478
--- /dev/null
+++ b/Help/policy/CMP0114.rst
@@ -0,0 +1,85 @@
+CMP0114
+-------
+
+.. versionadded:: 3.19
+
+:module:`ExternalProject` step targets fully adopt their steps.
+
+The :command:`ExternalProject_Add` ``STEP_TARGETS`` option, and the
+:command:`ExternalProject_Add_StepTargets` function, can be used to
+create build targets for individual steps of an external project.
+
+In CMake 3.18 and below, step targets have some limitations:
+
+* Step targets always depend on targets named by the
+ :command:`ExternalProject_Add` ``DEPENDS`` option even though
+ not all steps need them. In order to allow step targets to be created
+ without those dependencies, the :command:`ExternalProject_Add`
+ ``INDEPENDENT_STEP_TARGETS`` option or the
+ :command:`ExternalProject_Add_StepTargets` ``NO_DEPENDS`` option may
+ be used. However, adding such "independent" step targets makes sense
+ only for specific steps such as ``download``, ``update``, and ``patch``
+ because they do not need any of the external project's build dependencies.
+ Furthermore, it does not make sense to create independent step targets
+ for steps that depend on non-independent steps. Such rules are not
+ enforced, and projects that do not follow them can generate build systems
+ with confusing and generator-specific behavior.
+
+* Step targets hold copies of the custom commands implementing their
+ steps that are separate from the copies in the primary target created
+ by :command:`ExternalProject_Add`, and the primary target does not
+ depend on the step targets. In parallel builds that drive the primary
+ target and step targets concurrently, multiple copies of the steps'
+ commands may run concurrently and race each other.
+
+ Also, prior to policy :policy:`CMP0113`, the step targets generated
+ by :ref:`Makefile Generators` also contain all the custom commands
+ on which their step depends. This can lead to repeated execution of
+ those steps even in serial builds.
+
+In CMake 3.19 and above, the :module:`ExternalProject` module prefers
+a revised design to address these problems:
+
+* Each step is classified as "independent" if it does not depend
+ on other targets named by the :command:`ExternalProject_Add` ``DEPENDS``.
+ The predefined steps are automatically classified by default:
+
+ * The ``download``, ``update``, and ``patch`` steps are independent.
+ * The ``configure``, ``build``, ``test``, and ``install`` steps are not.
+
+ For custom steps, the :command:`ExternalProject_Add_Step` command provides
+ an ``INDEPENDENT`` option to mark them as independent. It is an error to
+ mark a step as independent if it depends on other steps that are not. Note
+ that this use of the term "independent" refers only to independence from
+ external targets and is orthogonal to a step's dependencies on other steps.
+
+* Step targets created by the :command:`ExternalProject_Add` ``STEP_TARGETS``
+ option or the :command:`ExternalProject_Add_Step` function are now
+ independent if and only if their steps are marked as independent.
+ The :command:`ExternalProject_Add` ``INDEPENDENT_STEP_TARGETS`` option
+ and :command:`ExternalProject_Add_StepTargets` ``NO_DEPENDS`` option
+ are no longer allowed.
+
+* Step targets, when created, are fully responsible for holding the
+ custom commands implementing their steps. The primary target created
+ by :command:`ExternalProject_Add` depends on the step targets, and the
+ step targets depend on each other. The target-level dependencies match
+ the file-level dependencies used by the custom commands for each step.
+
+ When the :command:`ExternalProject_Add` ``UPDATE_DISCONNECTED`` or
+ ``TEST_EXCLUDE_FROM_MAIN`` option is used, or the
+ :command:`ExternalProject_Add_Step` ``EXCLUDE_FROM_MAIN`` option is used
+ for a custom step, some step targets may be created automatically.
+ These are needed to hold the steps commonly depended upon by the primary
+ target and the disconnected step targets.
+
+Policy ``CMP0114`` provides compatibility for projects that have not been
+updated to expect the new behavior. The ``OLD`` behavior for this policy
+is to use the above-documented behavior from 3.18 and below. The ``NEW``
+behavior for this policy is to use the above-documented behavior preferred
+by 3.19 and above.
+
+This policy was introduced in CMake version 3.19. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
diff --git a/Help/policy/CMP0115.rst b/Help/policy/CMP0115.rst
new file mode 100644
index 0000000..7f82c43
--- /dev/null
+++ b/Help/policy/CMP0115.rst
@@ -0,0 +1,34 @@
+CMP0115
+-------
+
+.. versionadded:: 3.20
+
+Source file extensions must be explicit.
+
+In CMake 3.19 and below, if a source file could not be found by the name
+specified, it would append a list of known extensions to the name to see if
+the file with the extension could be found. For example, this would allow the
+user to run:
+
+.. code-block:: cmake
+
+ add_executable(exe main)
+
+and put ``main.c`` in the executable without specifying the extension.
+
+Starting in CMake 3.20, CMake prefers all source files to have their extensions
+explicitly listed:
+
+.. code-block:: cmake
+
+ add_executable(exe main.c)
+
+The ``OLD`` behavior for this policy is to implicitly append known extensions
+to source files if they can't be found. The ``NEW`` behavior of this policy is
+to not append known extensions and require them to be explicit.
+
+This policy was introduced in CMake version 3.20. CMake version |release|
+warns when the policy is not set and uses ``OLD`` behavior. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0116.rst b/Help/policy/CMP0116.rst
new file mode 100644
index 0000000..18e5a96
--- /dev/null
+++ b/Help/policy/CMP0116.rst
@@ -0,0 +1,41 @@
+CMP0116
+-------
+
+.. versionadded:: 3.20
+
+Ninja generators transform ``DEPFILE`` s from :command:`add_custom_command`.
+
+In CMake 3.19 and below, files given to the ``DEPFILE`` argument of
+:command:`add_custom_command` were passed directly to Ninja's ``depfile``
+variable without any path resolution. This meant that if
+:command:`add_custom_command` was called from a subdirectory (created by
+:command:`add_subdirectory`), the ``DEPFILE`` argument would have to be either
+an absolute path or a path relative to :variable:`CMAKE_BINARY_DIR`, rather
+than :variable:`CMAKE_CURRENT_BINARY_DIR`. In addition, no transformation was
+done on the file listed in ``DEPFILE``, which meant that the paths within the
+``DEPFILE`` had the same restrictions.
+
+Starting with CMake 3.20, the ``DEPFILE`` argument is relative to
+:variable:`CMAKE_CURRENT_BINARY_DIR` (unless it is absolute), and the paths in
+the ``DEPFILE`` are also relative to :variable:`CMAKE_CURRENT_BINARY_DIR`.
+CMake automatically transforms the paths in the ``DEPFILE`` (unless they are
+absolute) after the custom command is run. The file listed in ``DEPFILE`` is
+not modified in any way. Instead, CMake writes the transformation to its own
+internal file, and passes this internal file to Ninja's ``depfile`` variable.
+This transformation happens regardless of whether or not ``DEPFILE`` is
+relative, and regardless of whether or not :command:`add_custom_command` is
+called from a subdirectory.
+
+The ``OLD`` behavior for this policy is to pass the ``DEPFILE`` to Ninja
+unaltered. The ``NEW`` behavior for this policy is to transform the ``DEPFILE``
+after running the custom command. The status of ``CMP0116`` is recorded at the
+time of the custom command's creation, and you can have custom commands in the
+same directory with different values for ``CMP0116`` by setting the policy
+before each custom command.
+
+This policy was introduced in CMake version 3.20. Unlike most policies,
+CMake version |release| does *not* warn by default when this policy is not set
+(unless ``DEPFILE`` is used in a subdirectory) and simply uses ``OLD``
+behavior. See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0116 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
diff --git a/Help/policy/CMP0117.rst b/Help/policy/CMP0117.rst
new file mode 100644
index 0000000..0c4dd30
--- /dev/null
+++ b/Help/policy/CMP0117.rst
@@ -0,0 +1,43 @@
+CMP0117
+-------
+
+.. versionadded:: 3.20
+
+MSVC RTTI flag ``/GR`` is not added to
+:variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` by default.
+
+When using MSVC-like compilers in CMake 3.19 and below, the RTTI flag
+``/GR`` is added to :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` by
+default. This behavior is left from support for MSVC versions from Visual
+Studio 2003 and below that did not enable RTTI by default. It is no longer
+necessary. Furthermore, it is problematic for projects that want to change
+to ``/GR-`` programmatically. In particular, it requires string editing of
+the :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` variable with knowledge
+of the CMake builtin default so it can be replaced.
+
+CMake 3.20 and above prefer to leave out ``/GR`` from the value of
+:variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` by default.
+
+This policy provides compatibility with projects that have not been updated
+to expect the lack of the ``/GR`` flag. The policy setting takes effect as
+of the first :command:`project` or :command:`enable_language` command that
+initializes :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>`.
+
+.. note::
+
+ Once the policy has taken effect at the top of a project for a given
+ language, that choice must be used throughout the tree for that language.
+ In projects that have nested projects in subdirectories, be sure to
+ convert everything together.
+
+The ``OLD`` behavior for this policy is to place the MSVC ``/GR`` flag in the
+default :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` cache entry. The
+``NEW`` behavior for this policy is to *not* place the MSVC ``/GR`` flag in
+the default cache entry.
+
+This policy was introduced in CMake version 3.20. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0118.rst b/Help/policy/CMP0118.rst
new file mode 100644
index 0000000..aa7e0f7
--- /dev/null
+++ b/Help/policy/CMP0118.rst
@@ -0,0 +1,25 @@
+CMP0118
+-------
+
+.. versionadded:: 3.20
+
+The :prop_sf:`GENERATED` source file property is now visible in all directories.
+
+Whether or not a source file is generated is an all-or-nothing global
+property of the source. Consequently, the associated ``GENERATED``
+property is now visible from any directory scope, not only from the scope
+for which it was set.
+
+Additionally, the ``GENERATED`` property may now be set only to boolean
+values, and may not be turned off once turned on.
+
+The ``OLD`` behavior of this policy is to only allow ``GENERATED`` to be
+visible from the directory scope for which it was set. The ``NEW``
+behavior on the other hand allows it to be visible from any scope.
+
+This policy was introduced in CMake version 3.20. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior with regard
+to visibility of the ``GENERATED`` property. However, CMake does warn
+about setting the ``GENERATED`` property to a non-boolean value.
diff --git a/Help/policy/CMP0119.rst b/Help/policy/CMP0119.rst
new file mode 100644
index 0000000..61c8bdc
--- /dev/null
+++ b/Help/policy/CMP0119.rst
@@ -0,0 +1,36 @@
+CMP0119
+-------
+
+.. versionadded:: 3.20
+
+:prop_sf:`LANGUAGE` source file property explicitly compiles as specified
+language.
+
+The :prop_sf:`LANGUAGE` source file property is documented to mean that the
+source file is written in the specified language. In CMake 3.19 and below,
+setting this property causes CMake to compile the source file using the
+compiler for the specified language. However, it only passes an explicit
+flag to tell the compiler to treat the source as the specified language
+for MSVC-like, XL, and Embarcadero compilers for the ``CXX`` language.
+CMake 3.20 and above prefer to also explicitly tell the compiler to use
+the specified language using a flag such as ``-x c`` on all compilers
+for which such flags are known.
+
+This policy provides compatibility for projects that have not been updated
+to expect this behavior. For example, some projects were setting the
+``LANGUAGE`` property to ``C`` on assembly-language ``.S`` source files
+in order to compile them using the C compiler. Such projects should be
+updated to use ``enable_language(ASM)``, for which CMake will often choose
+the C compiler as the assembler on relevant platforms anyway.
+
+The ``OLD`` behavior for this policy is to interpret the ``LANGUAGE <LANG>``
+property using its undocumented meaning to "use the ``<LANG>`` compiler".
+The ``NEW`` behavior for this policy is to interpret the ``LANGUAGE <LANG>``
+property using its documented meaning to "compile as a ``<LANG>`` source".
+
+This policy was introduced in CMake version 3.20. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0120.rst b/Help/policy/CMP0120.rst
new file mode 100644
index 0000000..9d2f6c9
--- /dev/null
+++ b/Help/policy/CMP0120.rst
@@ -0,0 +1,47 @@
+CMP0120
+-------
+
+.. versionadded:: 3.20
+
+The :module:`WriteCompilerDetectionHeader` module is removed.
+
+CMake versions 3.1 through 3.19 provide this module to generate a
+C++ compatibility layer by re-using information from CMake's table of
+preprocessor checks for :manual:`cmake-compile-features(7)`. However:
+
+* Those granular features have been superseded by meta-features for
+ :ref:`Requiring Language Standards` such as ``cxx_std_11``. Therefore
+ no new granular feature checks will be added and projects will need to
+ use other means to conditionally use new C++ features.
+
+* The module exposes some of CMake's implementation details directly
+ to C++ translation units.
+
+* The module's approach effectively provides a header file with CMake,
+ thus tying the version of the header to the version of CMake.
+ Many projects found that the :module:`WriteCompilerDetectionHeader` was
+ best used by manually generating its header locally with a recent version
+ of CMake and then bundling it with the project source so that it could
+ be used with older CMake versions.
+
+For reasons including the above, CMake 3.20 and above prefer to not
+provide the :module:`WriteCompilerDetectionHeader` module. This policy
+provides compatibility for projects that have not been ported away from
+it. Projects using the module should be updated to stop using it.
+Alternatives include:
+
+* Bundle a copy of the generated header in the project's source.
+* Use a third-party alternative, such as the CC0-licensed `Hedley`_.
+* Drop support for compilers too old to provide the features natively.
+
+The ``OLD`` behavior of this policy is for inclusion of the deprecated
+:module:`WriteCompilerDetectionHeader` module to work. The ``NEW``
+behavior is for inclusion of the module to fail as if it does not exist.
+
+This policy was introduced in CMake version 3.20. CMake version |release|
+warns when the policy is not set and uses ``OLD`` behavior. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
+
+.. _`Hedley`: https://nemequ.github.io/hedley/
diff --git a/Help/policy/CMP0121.rst b/Help/policy/CMP0121.rst
new file mode 100644
index 0000000..5ef2856
--- /dev/null
+++ b/Help/policy/CMP0121.rst
@@ -0,0 +1,21 @@
+CMP0121
+-------
+
+.. versionadded:: 3.21
+
+The :command:`list` command now detects invalid indicies.
+
+Prior to CMake version 3.21, the :command:`list` command's ``GET``,
+``INSERT``, ``SUBLIST``, and ``REMOVE_AT`` subcommands did not detect invalid
+index arguments.
+
+The ``OLD`` behavior of this policy is for invalid indicies to be treated as
+their integer value (if any) at the start of the string. For example,
+``2good4you`` is a ``2`` and ``not_an_integer`` is a ``0``. The ``NEW``
+behavior is for invalid indicies to trigger an error.
+
+This policy was introduced in CMake version 3.21. CMake version |release|
+warns when the policy is not set and uses ``OLD`` behavior. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0122.rst b/Help/policy/CMP0122.rst
new file mode 100644
index 0000000..1ff8c48
--- /dev/null
+++ b/Help/policy/CMP0122.rst
@@ -0,0 +1,17 @@
+CMP0122
+-------
+
+.. versionadded:: 3.21
+
+:module:`UseSWIG` use library name conventions for ``CSharp`` language.
+
+Starting with CMake 3.21, :module:`UseSWIG` generates now a library using
+default naming conventions. This policy provides compatibility with projects
+that expect the legacy behavior.
+
+This policy was introduced in CMake version 3.21. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/DEPRECATED.txt b/Help/policy/DEPRECATED.txt
new file mode 100644
index 0000000..f66de55
--- /dev/null
+++ b/Help/policy/DEPRECATED.txt
@@ -0,0 +1,4 @@
+.. note::
+ The ``OLD`` behavior of a policy is
+ :manual:`deprecated by definition <cmake-policies(7)>`
+ and may be removed in a future version of CMake.
diff --git a/Help/policy/DISALLOWED_COMMAND.txt b/Help/policy/DISALLOWED_COMMAND.txt
new file mode 100644
index 0000000..6500bb0
--- /dev/null
+++ b/Help/policy/DISALLOWED_COMMAND.txt
@@ -0,0 +1,9 @@
+CMake >= |disallowed_version| prefer that this command never be called.
+The ``OLD`` behavior for this policy is to allow the command to be called.
+The ``NEW`` behavior for this policy is to issue a ``FATAL_ERROR`` when the
+command is called.
+
+This policy was introduced in CMake version |disallowed_version|.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set it to ``OLD`` or
+``NEW`` explicitly.
diff --git a/Help/prop_cache/ADVANCED.rst b/Help/prop_cache/ADVANCED.rst
new file mode 100644
index 0000000..ec4de9d
--- /dev/null
+++ b/Help/prop_cache/ADVANCED.rst
@@ -0,0 +1,8 @@
+ADVANCED
+--------
+
+True if entry should be hidden by default in GUIs.
+
+This is a boolean value indicating whether the entry is considered
+interesting only for advanced configuration. The :command:`mark_as_advanced`
+command modifies this property.
diff --git a/Help/prop_cache/HELPSTRING.rst b/Help/prop_cache/HELPSTRING.rst
new file mode 100644
index 0000000..71a86d0
--- /dev/null
+++ b/Help/prop_cache/HELPSTRING.rst
@@ -0,0 +1,7 @@
+HELPSTRING
+----------
+
+Help associated with entry in GUIs.
+
+This string summarizes the purpose of an entry to help users set it
+through a CMake GUI.
diff --git a/Help/prop_cache/MODIFIED.rst b/Help/prop_cache/MODIFIED.rst
new file mode 100644
index 0000000..3ad7035
--- /dev/null
+++ b/Help/prop_cache/MODIFIED.rst
@@ -0,0 +1,7 @@
+MODIFIED
+--------
+
+Internal management property. Do not set or get.
+
+This is an internal cache entry property managed by CMake to track
+interactive user modification of entries. Ignore it.
diff --git a/Help/prop_cache/STRINGS.rst b/Help/prop_cache/STRINGS.rst
new file mode 100644
index 0000000..0e3c326
--- /dev/null
+++ b/Help/prop_cache/STRINGS.rst
@@ -0,0 +1,9 @@
+STRINGS
+-------
+
+Enumerate possible ``STRING`` entry values for GUI selection.
+
+For cache entries with type ``STRING``, this enumerates a set of values.
+CMake GUIs may use this to provide a selection widget instead of a
+generic string entry field. This is for convenience only. CMake does
+not enforce that the value matches one of those listed.
diff --git a/Help/prop_cache/TYPE.rst b/Help/prop_cache/TYPE.rst
new file mode 100644
index 0000000..7ca859f
--- /dev/null
+++ b/Help/prop_cache/TYPE.rst
@@ -0,0 +1,21 @@
+TYPE
+----
+
+Widget type for entry in GUIs.
+
+Cache entry values are always strings, but CMake GUIs present widgets
+to help users set values. The GUIs use this property as a hint to
+determine the widget type. Valid ``TYPE`` values are:
+
+::
+
+ BOOL = Boolean ON/OFF value.
+ PATH = Path to a directory.
+ FILEPATH = Path to a file.
+ STRING = Generic string value.
+ INTERNAL = Do not present in GUI at all.
+ STATIC = Value managed by CMake, do not change.
+ UNINITIALIZED = Type not yet specified.
+
+Generally the ``TYPE`` of a cache entry should be set by the command which
+creates it ( :command:`set`, :command:`option`, :command:`find_library`, etc.).
diff --git a/Help/prop_cache/VALUE.rst b/Help/prop_cache/VALUE.rst
new file mode 100644
index 0000000..59aabd4
--- /dev/null
+++ b/Help/prop_cache/VALUE.rst
@@ -0,0 +1,7 @@
+VALUE
+-----
+
+Value of a cache entry.
+
+This property maps to the actual value of a cache entry. Setting this
+property always sets the value without checking, so use with care.
diff --git a/Help/prop_dir/ADDITIONAL_CLEAN_FILES.rst b/Help/prop_dir/ADDITIONAL_CLEAN_FILES.rst
new file mode 100644
index 0000000..6097d14
--- /dev/null
+++ b/Help/prop_dir/ADDITIONAL_CLEAN_FILES.rst
@@ -0,0 +1,23 @@
+ADDITIONAL_CLEAN_FILES
+----------------------
+
+.. versionadded:: 3.15
+
+A :ref:`;-list <CMake Language Lists>` of files or directories that will be
+removed as a part of the global ``clean`` target. It is useful for
+specifying generated files or directories that are used by multiple targets
+or by CMake itself, or that are generated in ways which cannot be captured as
+outputs or byproducts of custom commands.
+
+If an additional clean file is specific to a single target only, then the
+:prop_tgt:`ADDITIONAL_CLEAN_FILES` target property would usually be a better
+choice than this directory property.
+
+Relative paths are allowed and are interpreted relative to the
+current binary directory.
+
+Contents of ``ADDITIONAL_CLEAN_FILES`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property only works for the :generator:`Ninja` and the Makefile
+generators. It is ignored by other generators.
diff --git a/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst b/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst
new file mode 100644
index 0000000..b6f6160
--- /dev/null
+++ b/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst
@@ -0,0 +1,17 @@
+ADDITIONAL_MAKE_CLEAN_FILES
+---------------------------
+
+.. deprecated:: 3.15
+
+ Use :prop_dir:`ADDITIONAL_CLEAN_FILES` instead.
+
+Additional files to remove during the clean stage.
+
+A :ref:`;-list <CMake Language Lists>` of files that will be removed as a
+part of the ``make clean`` target.
+
+Arguments to :prop_dir:`ADDITIONAL_MAKE_CLEAN_FILES` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property only works for the Makefile generators.
+It is ignored on other generators.
diff --git a/Help/prop_dir/BINARY_DIR.rst b/Help/prop_dir/BINARY_DIR.rst
new file mode 100644
index 0000000..fcf9d17
--- /dev/null
+++ b/Help/prop_dir/BINARY_DIR.rst
@@ -0,0 +1,7 @@
+BINARY_DIR
+----------
+
+.. versionadded:: 3.7
+
+This read-only directory property reports absolute path to the binary
+directory corresponding to the source on which it is read.
diff --git a/Help/prop_dir/BUILDSYSTEM_TARGETS.rst b/Help/prop_dir/BUILDSYSTEM_TARGETS.rst
new file mode 100644
index 0000000..5c5893d
--- /dev/null
+++ b/Help/prop_dir/BUILDSYSTEM_TARGETS.rst
@@ -0,0 +1,13 @@
+BUILDSYSTEM_TARGETS
+-------------------
+
+.. versionadded:: 3.7
+
+This read-only directory property contains a
+:ref:`semicolon-separated list <CMake Language Lists>` of buildsystem targets added in the
+directory by calls to the :command:`add_library`, :command:`add_executable`,
+and :command:`add_custom_target` commands. The list does not include any
+:ref:`Imported Targets` or :ref:`Alias Targets`, but does include
+:ref:`Interface Libraries`. Each entry in the list is the logical name
+of a target, suitable to pass to the :command:`get_property` command
+``TARGET`` option.
diff --git a/Help/prop_dir/CACHE_VARIABLES.rst b/Help/prop_dir/CACHE_VARIABLES.rst
new file mode 100644
index 0000000..2c66f93
--- /dev/null
+++ b/Help/prop_dir/CACHE_VARIABLES.rst
@@ -0,0 +1,7 @@
+CACHE_VARIABLES
+---------------
+
+List of cache variables available in the current directory.
+
+This read-only property specifies the list of CMake cache variables
+currently defined. It is intended for debugging purposes.
diff --git a/Help/prop_dir/CLEAN_NO_CUSTOM.rst b/Help/prop_dir/CLEAN_NO_CUSTOM.rst
new file mode 100644
index 0000000..5ae78bf
--- /dev/null
+++ b/Help/prop_dir/CLEAN_NO_CUSTOM.rst
@@ -0,0 +1,6 @@
+CLEAN_NO_CUSTOM
+---------------
+
+Set to true to tell :ref:`Makefile Generators` not to remove the outputs of
+custom commands for this directory during the ``make clean`` operation.
+This is ignored on other generators because it is not possible to implement.
diff --git a/Help/prop_dir/CMAKE_CONFIGURE_DEPENDS.rst b/Help/prop_dir/CMAKE_CONFIGURE_DEPENDS.rst
new file mode 100644
index 0000000..b1aef19
--- /dev/null
+++ b/Help/prop_dir/CMAKE_CONFIGURE_DEPENDS.rst
@@ -0,0 +1,9 @@
+CMAKE_CONFIGURE_DEPENDS
+-----------------------
+
+Tell CMake about additional input files to the configuration process.
+If any named file is modified the build system will re-run CMake to
+re-configure the file and generate the build system again.
+
+Specify files as a semicolon-separated list of paths. Relative paths
+are interpreted as relative to the current source directory.
diff --git a/Help/prop_dir/COMPILE_DEFINITIONS.rst b/Help/prop_dir/COMPILE_DEFINITIONS.rst
new file mode 100644
index 0000000..18f4567
--- /dev/null
+++ b/Help/prop_dir/COMPILE_DEFINITIONS.rst
@@ -0,0 +1,31 @@
+COMPILE_DEFINITIONS
+-------------------
+
+Preprocessor definitions for compiling a directory's sources.
+
+This property specifies the list of options given so far to the
+:command:`add_compile_definitions` (or :command:`add_definitions`) command.
+
+The ``COMPILE_DEFINITIONS`` property may be set to a semicolon-separated
+list of preprocessor definitions using the syntax ``VAR`` or ``VAR=value``.
+Function-style definitions are not supported. CMake will
+automatically escape the value correctly for the native build system
+(note that CMake language syntax may require escapes to specify some
+values).
+
+This property will be initialized in each directory by its value in the
+directory's parent.
+
+CMake will automatically drop some definitions that are not supported
+by the native build tool.
+
+.. include:: /include/COMPILE_DEFINITIONS_DISCLAIMER.txt
+
+Contents of ``COMPILE_DEFINITIONS`` may use "generator expressions" with
+the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
+The corresponding :prop_dir:`COMPILE_DEFINITIONS_<CONFIG>` property may
+be set to specify per-configuration definitions. Generator expressions
+should be preferred instead of setting the alternative property.
diff --git a/Help/prop_dir/COMPILE_DEFINITIONS_CONFIG.rst b/Help/prop_dir/COMPILE_DEFINITIONS_CONFIG.rst
new file mode 100644
index 0000000..a6af45f
--- /dev/null
+++ b/Help/prop_dir/COMPILE_DEFINITIONS_CONFIG.rst
@@ -0,0 +1,19 @@
+COMPILE_DEFINITIONS_<CONFIG>
+----------------------------
+
+Ignored. See CMake Policy :policy:`CMP0043`.
+
+Per-configuration preprocessor definitions in a directory.
+
+This is the configuration-specific version of :prop_dir:`COMPILE_DEFINITIONS`
+where ``<CONFIG>`` is an upper-case name (ex. ``COMPILE_DEFINITIONS_DEBUG``).
+
+This property will be initialized in each directory by its value in
+the directory's parent.
+
+Contents of ``COMPILE_DEFINITIONS_<CONFIG>`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
+Generator expressions should be preferred instead of setting this property.
diff --git a/Help/prop_dir/COMPILE_OPTIONS.rst b/Help/prop_dir/COMPILE_OPTIONS.rst
new file mode 100644
index 0000000..48e8b9b
--- /dev/null
+++ b/Help/prop_dir/COMPILE_OPTIONS.rst
@@ -0,0 +1,16 @@
+COMPILE_OPTIONS
+---------------
+
+List of options to pass to the compiler.
+
+This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of options
+given so far to the :command:`add_compile_options` command.
+
+This property is used to initialize the :prop_tgt:`COMPILE_OPTIONS` target
+property when a target is created, which is used by the generators to set
+the options for the compiler.
+
+Contents of ``COMPILE_OPTIONS`` may use "generator expressions" with the
+syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions. See the :manual:`cmake-buildsystem(7)` manual
+for more on defining buildsystem properties.
diff --git a/Help/prop_dir/DEFINITIONS.rst b/Help/prop_dir/DEFINITIONS.rst
new file mode 100644
index 0000000..79ac3f3
--- /dev/null
+++ b/Help/prop_dir/DEFINITIONS.rst
@@ -0,0 +1,13 @@
+DEFINITIONS
+-----------
+
+For CMake 2.4 compatibility only. Use :prop_dir:`COMPILE_DEFINITIONS`
+instead.
+
+This read-only property specifies the list of flags given so far to
+the :command:`add_definitions` command. It is intended for debugging
+purposes. Use the :prop_dir:`COMPILE_DEFINITIONS` directory property
+instead.
+
+This built-in read-only property does not exist if policy
+:policy:`CMP0059` is set to ``NEW``.
diff --git a/Help/prop_dir/EXCLUDE_FROM_ALL.rst b/Help/prop_dir/EXCLUDE_FROM_ALL.rst
new file mode 100644
index 0000000..8e3cca0
--- /dev/null
+++ b/Help/prop_dir/EXCLUDE_FROM_ALL.rst
@@ -0,0 +1,13 @@
+EXCLUDE_FROM_ALL
+----------------
+
+Set this directory property to a true value on a subdirectory to exclude
+its targets from the "all" target of its ancestors. If excluded, running
+e.g. ``make`` in the parent directory will not build targets the
+subdirectory by default. This does not affect the "all" target of the
+subdirectory itself. Running e.g. ``make`` inside the subdirectory will
+still build its targets.
+
+If the :prop_tgt:`EXCLUDE_FROM_ALL` target property is set on a target
+then its value determines whether the target is included in the "all"
+target of this directory and its ancestors.
diff --git a/Help/prop_dir/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst b/Help/prop_dir/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst
new file mode 100644
index 0000000..f534976
--- /dev/null
+++ b/Help/prop_dir/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst
@@ -0,0 +1,34 @@
+IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
+----------------------------------
+
+Specify ``#include`` line transforms for dependencies in a directory.
+
+This property specifies rules to transform macro-like ``#include`` lines
+during implicit dependency scanning of C and C++ source files. The
+list of rules must be semicolon-separated with each entry of the form
+``A_MACRO(%)=value-with-%`` (the ``%`` must be literal). During dependency
+scanning occurrences of ``A_MACRO(...)`` on ``#include`` lines will be
+replaced by the value given with the macro argument substituted for
+``%``. For example, the entry
+
+::
+
+ MYDIR(%)=<mydir/%>
+
+will convert lines of the form
+
+::
+
+ #include MYDIR(myheader.h)
+
+to
+
+::
+
+ #include <mydir/myheader.h>
+
+allowing the dependency to be followed.
+
+This property applies to sources in all targets within a directory.
+The property value is initialized in each directory by its value in
+the directory's parent.
diff --git a/Help/prop_dir/INCLUDE_DIRECTORIES.rst b/Help/prop_dir/INCLUDE_DIRECTORIES.rst
new file mode 100644
index 0000000..5d856b8
--- /dev/null
+++ b/Help/prop_dir/INCLUDE_DIRECTORIES.rst
@@ -0,0 +1,32 @@
+INCLUDE_DIRECTORIES
+-------------------
+
+List of preprocessor include file search directories.
+
+This property specifies the list of directories given so far to the
+:command:`include_directories` command.
+
+This property is used to populate the :prop_tgt:`INCLUDE_DIRECTORIES`
+target property, which is used by the generators to set the include
+directories for the compiler.
+
+In addition to accepting values from that command, values may be set
+directly on any directory using the :command:`set_property` command, and can be
+set on the current directory using the :command:`set_directory_properties`
+command. A directory gets its initial value from its parent directory if it has
+one. The initial value of the :prop_tgt:`INCLUDE_DIRECTORIES` target property
+comes from the value of this property. Both directory and target property
+values are adjusted by calls to the :command:`include_directories` command.
+Calls to :command:`set_property` or :command:`set_directory_properties`,
+however, will update the directory property value without updating target
+property values. Therefore direct property updates must be made before
+calls to :command:`add_executable` or :command:`add_library` for targets
+they are meant to affect.
+
+The target property values are used by the generators to set the
+include paths for the compiler.
+
+Contents of ``INCLUDE_DIRECTORIES`` may use "generator expressions" with
+the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
diff --git a/Help/prop_dir/INCLUDE_REGULAR_EXPRESSION.rst b/Help/prop_dir/INCLUDE_REGULAR_EXPRESSION.rst
new file mode 100644
index 0000000..bb90c61
--- /dev/null
+++ b/Help/prop_dir/INCLUDE_REGULAR_EXPRESSION.rst
@@ -0,0 +1,9 @@
+INCLUDE_REGULAR_EXPRESSION
+--------------------------
+
+Include file scanning regular expression.
+
+This property specifies the regular expression used during
+dependency scanning to match include files that should be followed.
+See the :command:`include_regular_expression` command for a high-level
+interface to set this property.
diff --git a/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION.rst b/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION.rst
new file mode 100644
index 0000000..0c78dfb
--- /dev/null
+++ b/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION.rst
@@ -0,0 +1,7 @@
+INTERPROCEDURAL_OPTIMIZATION
+----------------------------
+
+Enable interprocedural optimization for targets in a directory.
+
+If set to true, enables interprocedural optimizations if they are
+known to be supported by the compiler.
diff --git a/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst b/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
new file mode 100644
index 0000000..840a1db
--- /dev/null
+++ b/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
@@ -0,0 +1,8 @@
+INTERPROCEDURAL_OPTIMIZATION_<CONFIG>
+-------------------------------------
+
+Per-configuration interprocedural optimization for a directory.
+
+This is a per-configuration version of ``INTERPROCEDURAL_OPTIMIZATION``.
+If set, this property overrides the generic property for the named
+configuration.
diff --git a/Help/prop_dir/LABELS.rst b/Help/prop_dir/LABELS.rst
new file mode 100644
index 0000000..bf14368
--- /dev/null
+++ b/Help/prop_dir/LABELS.rst
@@ -0,0 +1,15 @@
+LABELS
+------
+
+.. versionadded:: 3.10
+
+Specify a list of text labels associated with a directory and all of its
+subdirectories. This is equivalent to setting the :prop_tgt:`LABELS` target
+property and the :prop_test:`LABELS` test property on all targets and tests in
+the current directory and subdirectories. Note: Launchers must enabled to
+propagate labels to targets.
+
+The :variable:`CMAKE_DIRECTORY_LABELS` variable can be used to initialize this
+property.
+
+The list is reported in dashboard submissions.
diff --git a/Help/prop_dir/LINK_DIRECTORIES.rst b/Help/prop_dir/LINK_DIRECTORIES.rst
new file mode 100644
index 0000000..44dc230
--- /dev/null
+++ b/Help/prop_dir/LINK_DIRECTORIES.rst
@@ -0,0 +1,17 @@
+LINK_DIRECTORIES
+----------------
+
+List of linker search directories.
+
+This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of directories
+and is typically populated using the :command:`link_directories` command.
+It gets its initial value from its parent directory, if it has one.
+
+The directory property is used to initialize the :prop_tgt:`LINK_DIRECTORIES`
+target property when a target is created. That target property is used
+by the generators to set the library search directories for the linker.
+
+Contents of ``LINK_DIRECTORIES`` may use "generator expressions" with
+the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
diff --git a/Help/prop_dir/LINK_OPTIONS.rst b/Help/prop_dir/LINK_OPTIONS.rst
new file mode 100644
index 0000000..3a5c72f
--- /dev/null
+++ b/Help/prop_dir/LINK_OPTIONS.rst
@@ -0,0 +1,19 @@
+LINK_OPTIONS
+------------
+
+.. versionadded:: 3.13
+
+List of options to use for the link step of shared library, module
+and executable targets as well as the device link step.
+
+This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of options
+given so far to the :command:`add_link_options` command.
+
+This property is used to initialize the :prop_tgt:`LINK_OPTIONS` target
+property when a target is created, which is used by the generators to set
+the options for the compiler.
+
+Contents of ``LINK_OPTIONS`` may use "generator expressions" with the
+syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions. See the :manual:`cmake-buildsystem(7)` manual
+for more on defining buildsystem properties.
diff --git a/Help/prop_dir/LISTFILE_STACK.rst b/Help/prop_dir/LISTFILE_STACK.rst
new file mode 100644
index 0000000..22ec4b6
--- /dev/null
+++ b/Help/prop_dir/LISTFILE_STACK.rst
@@ -0,0 +1,10 @@
+LISTFILE_STACK
+--------------
+
+The current stack of listfiles being processed.
+
+This property is mainly useful when trying to debug errors in your
+CMake scripts. It returns a list of what list files are currently
+being processed, in order. So if one listfile does an
+:command:`include` command then that is effectively pushing the
+included listfile onto the stack.
diff --git a/Help/prop_dir/MACROS.rst b/Help/prop_dir/MACROS.rst
new file mode 100644
index 0000000..245cc1b
--- /dev/null
+++ b/Help/prop_dir/MACROS.rst
@@ -0,0 +1,8 @@
+MACROS
+------
+
+List of macro commands available in the current directory.
+
+This read-only property specifies the list of CMake macros currently
+defined. It is intended for debugging purposes. See the :command:`macro`
+command.
diff --git a/Help/prop_dir/PARENT_DIRECTORY.rst b/Help/prop_dir/PARENT_DIRECTORY.rst
new file mode 100644
index 0000000..3bc5824
--- /dev/null
+++ b/Help/prop_dir/PARENT_DIRECTORY.rst
@@ -0,0 +1,8 @@
+PARENT_DIRECTORY
+----------------
+
+Source directory that added current subdirectory.
+
+This read-only property specifies the source directory that added the
+current source directory as a subdirectory of the build. In the
+top-level directory the value is the empty-string.
diff --git a/Help/prop_dir/RULE_LAUNCH_COMPILE.rst b/Help/prop_dir/RULE_LAUNCH_COMPILE.rst
new file mode 100644
index 0000000..342d0ae
--- /dev/null
+++ b/Help/prop_dir/RULE_LAUNCH_COMPILE.rst
@@ -0,0 +1,7 @@
+RULE_LAUNCH_COMPILE
+-------------------
+
+Specify a launcher for compile rules.
+
+See the global property of the same name for details. This overrides
+the global property for a directory.
diff --git a/Help/prop_dir/RULE_LAUNCH_CUSTOM.rst b/Help/prop_dir/RULE_LAUNCH_CUSTOM.rst
new file mode 100644
index 0000000..93d1e01
--- /dev/null
+++ b/Help/prop_dir/RULE_LAUNCH_CUSTOM.rst
@@ -0,0 +1,7 @@
+RULE_LAUNCH_CUSTOM
+------------------
+
+Specify a launcher for custom rules.
+
+See the global property of the same name for details. This overrides
+the global property for a directory.
diff --git a/Help/prop_dir/RULE_LAUNCH_LINK.rst b/Help/prop_dir/RULE_LAUNCH_LINK.rst
new file mode 100644
index 0000000..3cfb236
--- /dev/null
+++ b/Help/prop_dir/RULE_LAUNCH_LINK.rst
@@ -0,0 +1,7 @@
+RULE_LAUNCH_LINK
+----------------
+
+Specify a launcher for link rules.
+
+See the global property of the same name for details. This overrides
+the global property for a directory.
diff --git a/Help/prop_dir/SOURCE_DIR.rst b/Help/prop_dir/SOURCE_DIR.rst
new file mode 100644
index 0000000..d73707d
--- /dev/null
+++ b/Help/prop_dir/SOURCE_DIR.rst
@@ -0,0 +1,7 @@
+SOURCE_DIR
+----------
+
+.. versionadded:: 3.7
+
+This read-only directory property reports absolute path to the source
+directory on which it is read.
diff --git a/Help/prop_dir/SUBDIRECTORIES.rst b/Help/prop_dir/SUBDIRECTORIES.rst
new file mode 100644
index 0000000..71ea496
--- /dev/null
+++ b/Help/prop_dir/SUBDIRECTORIES.rst
@@ -0,0 +1,17 @@
+SUBDIRECTORIES
+--------------
+
+.. versionadded:: 3.7
+
+This read-only directory property contains a
+:ref:`semicolon-separated list <CMake Language Lists>` of subdirectories processed so far by
+the :command:`add_subdirectory` or :command:`subdirs` commands. Each entry is
+the absolute path to the source directory (containing the ``CMakeLists.txt``
+file). This is suitable to pass to the :command:`get_property` command
+``DIRECTORY`` option.
+
+.. note::
+
+ The :command:`subdirs` command does not process its arguments until
+ after the calling directory is fully processed. Therefore looking
+ up this property in the current directory will not see them.
diff --git a/Help/prop_dir/TESTS.rst b/Help/prop_dir/TESTS.rst
new file mode 100644
index 0000000..294be17
--- /dev/null
+++ b/Help/prop_dir/TESTS.rst
@@ -0,0 +1,10 @@
+TESTS
+-----
+
+.. versionadded:: 3.12
+
+List of tests.
+
+This read-only property holds a
+:ref:`semicolon-separated list <CMake Language Lists>` of tests
+defined so far, in the current directory, by the :command:`add_test` command.
diff --git a/Help/prop_dir/TEST_INCLUDE_FILE.rst b/Help/prop_dir/TEST_INCLUDE_FILE.rst
new file mode 100644
index 0000000..31b2382
--- /dev/null
+++ b/Help/prop_dir/TEST_INCLUDE_FILE.rst
@@ -0,0 +1,9 @@
+TEST_INCLUDE_FILE
+-----------------
+
+Deprecated. Use :prop_dir:`TEST_INCLUDE_FILES` instead.
+
+A cmake file that will be included when ctest is run.
+
+If you specify ``TEST_INCLUDE_FILE``, that file will be included and
+processed when ctest is run on the directory.
diff --git a/Help/prop_dir/TEST_INCLUDE_FILES.rst b/Help/prop_dir/TEST_INCLUDE_FILES.rst
new file mode 100644
index 0000000..f9a66f4
--- /dev/null
+++ b/Help/prop_dir/TEST_INCLUDE_FILES.rst
@@ -0,0 +1,9 @@
+TEST_INCLUDE_FILES
+------------------
+
+.. versionadded:: 3.10
+
+A list of cmake files that will be included when ctest is run.
+
+If you specify ``TEST_INCLUDE_FILES``, those files will be included and
+processed when ctest is run on the directory.
diff --git a/Help/prop_dir/VARIABLES.rst b/Help/prop_dir/VARIABLES.rst
new file mode 100644
index 0000000..0328295
--- /dev/null
+++ b/Help/prop_dir/VARIABLES.rst
@@ -0,0 +1,7 @@
+VARIABLES
+---------
+
+List of variables defined in the current directory.
+
+This read-only property specifies the list of CMake variables
+currently defined. It is intended for debugging purposes.
diff --git a/Help/prop_dir/VS_GLOBAL_SECTION_POST_section.rst b/Help/prop_dir/VS_GLOBAL_SECTION_POST_section.rst
new file mode 100644
index 0000000..b65db99
--- /dev/null
+++ b/Help/prop_dir/VS_GLOBAL_SECTION_POST_section.rst
@@ -0,0 +1,31 @@
+VS_GLOBAL_SECTION_POST_<section>
+--------------------------------
+
+Specify a postSolution global section in Visual Studio.
+
+Setting a property like this generates an entry of the following form
+in the solution file:
+
+::
+
+ GlobalSection(<section>) = postSolution
+ <contents based on property value>
+ EndGlobalSection
+
+The property must be set to a semicolon-separated list of ``key=value``
+pairs. Each such pair will be transformed into an entry in the
+solution global section. Whitespace around key and value is ignored.
+List elements which do not contain an equal sign are skipped.
+
+This property only works for Visual Studio 9 and above; it is ignored
+on other generators. The property only applies when set on a
+directory whose ``CMakeLists.txt`` contains a :command:`project` command.
+
+Note that CMake generates postSolution sections ``ExtensibilityGlobals``
+and ``ExtensibilityAddIns`` by default. If you set the corresponding
+property, it will override the default section. For example, setting
+``VS_GLOBAL_SECTION_POST_ExtensibilityGlobals`` will override the default
+contents of the ``ExtensibilityGlobals`` section, while keeping
+ExtensibilityAddIns on its default. However, CMake will always
+add a ``SolutionGuid`` to the ``ExtensibilityGlobals`` section
+if it is not specified explicitly.
diff --git a/Help/prop_dir/VS_GLOBAL_SECTION_PRE_section.rst b/Help/prop_dir/VS_GLOBAL_SECTION_PRE_section.rst
new file mode 100644
index 0000000..7f8bf61
--- /dev/null
+++ b/Help/prop_dir/VS_GLOBAL_SECTION_PRE_section.rst
@@ -0,0 +1,22 @@
+VS_GLOBAL_SECTION_PRE_<section>
+-------------------------------
+
+Specify a preSolution global section in Visual Studio.
+
+Setting a property like this generates an entry of the following form
+in the solution file:
+
+::
+
+ GlobalSection(<section>) = preSolution
+ <contents based on property value>
+ EndGlobalSection
+
+The property must be set to a semicolon-separated list of ``key=value``
+pairs. Each such pair will be transformed into an entry in the
+solution global section. Whitespace around key and value is ignored.
+List elements which do not contain an equal sign are skipped.
+
+This property only works for Visual Studio 9 and above; it is ignored
+on other generators. The property only applies when set on a
+directory whose ``CMakeLists.txt`` contains a :command:`project` command.
diff --git a/Help/prop_dir/VS_STARTUP_PROJECT.rst b/Help/prop_dir/VS_STARTUP_PROJECT.rst
new file mode 100644
index 0000000..8a0c3c8
--- /dev/null
+++ b/Help/prop_dir/VS_STARTUP_PROJECT.rst
@@ -0,0 +1,20 @@
+VS_STARTUP_PROJECT
+------------------
+
+.. versionadded:: 3.6
+
+Specify the default startup project in a Visual Studio solution.
+
+The :ref:`Visual Studio Generators` create a ``.sln`` file for each directory
+whose ``CMakeLists.txt`` file calls the :command:`project` command. Set this
+property in the same directory as a :command:`project` command call (e.g. in
+the top-level ``CMakeLists.txt`` file) to specify the default startup project
+for the corresponding solution file.
+
+The property must be set to the name of an existing target. This
+will cause that project to be listed first in the generated solution
+file causing Visual Studio to make it the startup project if the
+solution has never been opened before.
+
+If this property is not specified, then the ``ALL_BUILD`` project
+will be the default.
diff --git a/Help/prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS.rst b/Help/prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS.rst
new file mode 100644
index 0000000..19775ff
--- /dev/null
+++ b/Help/prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS.rst
@@ -0,0 +1,21 @@
+ALLOW_DUPLICATE_CUSTOM_TARGETS
+------------------------------
+
+Allow duplicate custom targets to be created.
+
+Normally CMake requires that all targets built in a project have
+globally unique logical names (see policy :policy:`CMP0002`).
+This is necessary to generate meaningful project file names in
+:generator:`Xcode` and :ref:`Visual Studio Generators` IDE
+generators. It also allows the target names to be referenced
+unambiguously.
+
+Makefile generators are capable of supporting duplicate :command:`add_custom_target`
+names. For projects that care only about :ref:`Makefile Generators` and do
+not wish to support :generator:`Xcode` or :ref:`Visual Studio Generators` IDE
+generators, one may set this property to ``True``
+to allow duplicate custom targets. The property
+allows multiple :command:`add_custom_target` command calls in different
+directories to specify the same target name. However, setting this
+property will cause non-Makefile generators to produce an error and
+refuse to generate the project.
diff --git a/Help/prop_gbl/AUTOGEN_SOURCE_GROUP.rst b/Help/prop_gbl/AUTOGEN_SOURCE_GROUP.rst
new file mode 100644
index 0000000..07c732b
--- /dev/null
+++ b/Help/prop_gbl/AUTOGEN_SOURCE_GROUP.rst
@@ -0,0 +1,18 @@
+AUTOGEN_SOURCE_GROUP
+--------------------
+
+.. versionadded:: 3.9
+
+Name of the :command:`source_group` for :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTORCC` and :prop_tgt:`AUTOUIC` generated files.
+
+Files generated by :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTORCC` and
+:prop_tgt:`AUTOUIC` are not always known at configure time and therefore can't
+be passed to :command:`source_group`.
+:prop_gbl:`AUTOGEN_SOURCE_GROUP` can be used instead to generate or select
+a source group for :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTORCC` and
+:prop_tgt:`AUTOUIC` generated files.
+
+For :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTORCC` and :prop_tgt:`AUTOUIC` specific
+overrides see :prop_gbl:`AUTOMOC_SOURCE_GROUP`, :prop_gbl:`AUTORCC_SOURCE_GROUP`
+and :prop_gbl:`AUTOUIC_SOURCE_GROUP` respectively.
diff --git a/Help/prop_gbl/AUTOGEN_TARGETS_FOLDER.rst b/Help/prop_gbl/AUTOGEN_TARGETS_FOLDER.rst
new file mode 100644
index 0000000..0b747b2
--- /dev/null
+++ b/Help/prop_gbl/AUTOGEN_TARGETS_FOLDER.rst
@@ -0,0 +1,9 @@
+AUTOGEN_TARGETS_FOLDER
+----------------------
+
+Name of :prop_tgt:`FOLDER` for ``*_autogen`` targets that are added
+automatically by CMake for targets for which :prop_tgt:`AUTOMOC` is enabled.
+
+If not set, CMake uses the :prop_tgt:`FOLDER` property of the parent target as a
+default value for this property. See also the documentation for the
+:prop_tgt:`FOLDER` target property and the :prop_tgt:`AUTOMOC` target property.
diff --git a/Help/prop_gbl/AUTOMOC_SOURCE_GROUP.rst b/Help/prop_gbl/AUTOMOC_SOURCE_GROUP.rst
new file mode 100644
index 0000000..a266fde
--- /dev/null
+++ b/Help/prop_gbl/AUTOMOC_SOURCE_GROUP.rst
@@ -0,0 +1,9 @@
+AUTOMOC_SOURCE_GROUP
+--------------------
+
+.. versionadded:: 3.9
+
+Name of the :command:`source_group` for :prop_tgt:`AUTOMOC` generated files.
+
+When set this is used instead of :prop_gbl:`AUTOGEN_SOURCE_GROUP` for
+files generated by :prop_tgt:`AUTOMOC`.
diff --git a/Help/prop_gbl/AUTOMOC_TARGETS_FOLDER.rst b/Help/prop_gbl/AUTOMOC_TARGETS_FOLDER.rst
new file mode 100644
index 0000000..17666e4
--- /dev/null
+++ b/Help/prop_gbl/AUTOMOC_TARGETS_FOLDER.rst
@@ -0,0 +1,11 @@
+AUTOMOC_TARGETS_FOLDER
+----------------------
+
+Name of :prop_tgt:`FOLDER` for ``*_autogen`` targets that are added automatically by
+CMake for targets for which :prop_tgt:`AUTOMOC` is enabled.
+
+This property is obsolete. Use :prop_gbl:`AUTOGEN_TARGETS_FOLDER` instead.
+
+If not set, CMake uses the :prop_tgt:`FOLDER` property of the parent target as a
+default value for this property. See also the documentation for the
+:prop_tgt:`FOLDER` target property and the :prop_tgt:`AUTOMOC` target property.
diff --git a/Help/prop_gbl/AUTORCC_SOURCE_GROUP.rst b/Help/prop_gbl/AUTORCC_SOURCE_GROUP.rst
new file mode 100644
index 0000000..54ebabb
--- /dev/null
+++ b/Help/prop_gbl/AUTORCC_SOURCE_GROUP.rst
@@ -0,0 +1,9 @@
+AUTORCC_SOURCE_GROUP
+--------------------
+
+.. versionadded:: 3.9
+
+Name of the :command:`source_group` for :prop_tgt:`AUTORCC` generated files.
+
+When set this is used instead of :prop_gbl:`AUTOGEN_SOURCE_GROUP` for
+files generated by :prop_tgt:`AUTORCC`.
diff --git a/Help/prop_gbl/AUTOUIC_SOURCE_GROUP.rst b/Help/prop_gbl/AUTOUIC_SOURCE_GROUP.rst
new file mode 100644
index 0000000..79ebfe0
--- /dev/null
+++ b/Help/prop_gbl/AUTOUIC_SOURCE_GROUP.rst
@@ -0,0 +1,9 @@
+AUTOUIC_SOURCE_GROUP
+--------------------
+
+.. versionadded:: 3.21
+
+Name of the :command:`source_group` for :prop_tgt:`AUTOUIC` generated files.
+
+When set this is used instead of :prop_gbl:`AUTOGEN_SOURCE_GROUP` for
+files generated by :prop_tgt:`AUTOUIC`.
diff --git a/Help/prop_gbl/CMAKE_CUDA_KNOWN_FEATURES.rst b/Help/prop_gbl/CMAKE_CUDA_KNOWN_FEATURES.rst
new file mode 100644
index 0000000..6bbb870
--- /dev/null
+++ b/Help/prop_gbl/CMAKE_CUDA_KNOWN_FEATURES.rst
@@ -0,0 +1,35 @@
+CMAKE_CUDA_KNOWN_FEATURES
+-------------------------
+
+.. versionadded:: 3.17
+
+List of CUDA features known to this version of CMake.
+
+The features listed in this global property may be known to be available to the
+CUDA compiler. If the feature is available with the C++ compiler, it will
+be listed in the :variable:`CMAKE_CUDA_COMPILE_FEATURES` variable.
+
+The features listed here may be used with the :command:`target_compile_features`
+command. See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+
+The features known to this version of CMake are:
+
+``cuda_std_03``
+ Compiler mode is at least CUDA/C++ 03.
+
+``cuda_std_11``
+ Compiler mode is at least CUDA/C++ 11.
+
+``cuda_std_14``
+ Compiler mode is at least CUDA/C++ 14.
+
+``cuda_std_17``
+ Compiler mode is at least CUDA/C++ 17.
+
+``cuda_std_20``
+ Compiler mode is at least CUDA/C++ 20.
+
+``cuda_std_23``
+ Compiler mode is at least CUDA/C++ 23.
diff --git a/Help/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.rst b/Help/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.rst
new file mode 100644
index 0000000..73c0b34
--- /dev/null
+++ b/Help/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.rst
@@ -0,0 +1,354 @@
+CMAKE_CXX_KNOWN_FEATURES
+------------------------
+
+.. versionadded:: 3.1
+
+List of C++ features known to this version of CMake.
+
+The features listed in this global property may be known to be available to the
+C++ compiler. If the feature is available with the C++ compiler, it will
+be listed in the :variable:`CMAKE_CXX_COMPILE_FEATURES` variable.
+
+The features listed here may be used with the :command:`target_compile_features`
+command. See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+The features known to this version of CMake are listed below.
+
+High level meta features indicating C++ standard support
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following meta features indicate general support for the associated
+language standard. It reflects the language support claimed by the compiler,
+but it does not necessarily imply complete conformance to that standard.
+
+``cxx_std_98``
+ Compiler mode is at least C++ 98.
+
+``cxx_std_11``
+ Compiler mode is at least C++ 11.
+
+``cxx_std_14``
+ Compiler mode is at least C++ 14.
+
+``cxx_std_17``
+ Compiler mode is at least C++ 17.
+
+``cxx_std_20``
+ Compiler mode is at least C++ 20.
+
+``cxx_std_23``
+ Compiler mode is at least C++ 23.
+
+Low level individual compile features
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For C++ 11 and C++ 14, compilers were sometimes slow to implement certain
+language features. CMake provided some individual compile features to help
+projects determine whether specific features were available. These individual
+features are now less relevant and projects should generally prefer to use the
+high level meta features instead. Individual compile features are not provided
+for C++ 17 or later.
+
+See the :manual:`cmake-compile-features(7)` manual for further discussion of
+the use of individual compile features.
+
+Individual features from C++ 98
+"""""""""""""""""""""""""""""""
+
+``cxx_template_template_parameters``
+ Template template parameters, as defined in ``ISO/IEC 14882:1998``.
+
+
+Individual features from C++ 11
+"""""""""""""""""""""""""""""""
+
+``cxx_alias_templates``
+ Template aliases, as defined in N2258_.
+
+ .. _N2258: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf
+
+``cxx_alignas``
+ Alignment control ``alignas``, as defined in N2341_.
+
+ .. _N2341: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf
+
+``cxx_alignof``
+ Alignment control ``alignof``, as defined in N2341_.
+
+ .. _N2341: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf
+
+``cxx_attributes``
+ Generic attributes, as defined in N2761_.
+
+ .. _N2761: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf
+
+``cxx_auto_type``
+ Automatic type deduction, as defined in N1984_.
+
+ .. _N1984: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf
+
+``cxx_constexpr``
+ Constant expressions, as defined in N2235_.
+
+ .. _N2235: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf
+
+
+``cxx_decltype_incomplete_return_types``
+ Decltype on incomplete return types, as defined in N3276_.
+
+ .. _N3276 : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3276.pdf
+
+``cxx_decltype``
+ Decltype, as defined in N2343_.
+
+ .. _N2343: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf
+
+``cxx_default_function_template_args``
+ Default template arguments for function templates, as defined in DR226_
+
+ .. _DR226: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#226
+
+``cxx_defaulted_functions``
+ Defaulted functions, as defined in N2346_.
+
+ .. _N2346: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm
+
+``cxx_defaulted_move_initializers``
+ Defaulted move initializers, as defined in N3053_.
+
+ .. _N3053: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3053.html
+
+``cxx_delegating_constructors``
+ Delegating constructors, as defined in N1986_.
+
+ .. _N1986: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf
+
+``cxx_deleted_functions``
+ Deleted functions, as defined in N2346_.
+
+ .. _N2346: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm
+
+``cxx_enum_forward_declarations``
+ Enum forward declarations, as defined in N2764_.
+
+ .. _N2764: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf
+
+``cxx_explicit_conversions``
+ Explicit conversion operators, as defined in N2437_.
+
+ .. _N2437: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf
+
+``cxx_extended_friend_declarations``
+ Extended friend declarations, as defined in N1791_.
+
+ .. _N1791: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf
+
+``cxx_extern_templates``
+ Extern templates, as defined in N1987_.
+
+ .. _N1987: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1987.htm
+
+``cxx_final``
+ Override control ``final`` keyword, as defined in N2928_, N3206_ and N3272_.
+
+ .. _N2928: http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2928.htm
+ .. _N3206: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm
+ .. _N3272: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm
+
+``cxx_func_identifier``
+ Predefined ``__func__`` identifier, as defined in N2340_.
+
+ .. _N2340: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2340.htm
+
+``cxx_generalized_initializers``
+ Initializer lists, as defined in N2672_.
+
+ .. _N2672: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm
+
+``cxx_inheriting_constructors``
+ Inheriting constructors, as defined in N2540_.
+
+ .. _N2540: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm
+
+``cxx_inline_namespaces``
+ Inline namespaces, as defined in N2535_.
+
+ .. _N2535: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2535.htm
+
+``cxx_lambdas``
+ Lambda functions, as defined in N2927_.
+
+ .. _N2927: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2927.pdf
+
+``cxx_local_type_template_args``
+ Local and unnamed types as template arguments, as defined in N2657_.
+
+ .. _N2657: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm
+
+``cxx_long_long_type``
+ ``long long`` type, as defined in N1811_.
+
+ .. _N1811: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1811.pdf
+
+``cxx_noexcept``
+ Exception specifications, as defined in N3050_.
+
+ .. _N3050: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3050.html
+
+``cxx_nonstatic_member_init``
+ Non-static data member initialization, as defined in N2756_.
+
+ .. _N2756: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2756.htm
+
+``cxx_nullptr``
+ Null pointer, as defined in N2431_.
+
+ .. _N2431: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf
+
+``cxx_override``
+ Override control ``override`` keyword, as defined in N2928_, N3206_
+ and N3272_.
+
+ .. _N2928: http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2928.htm
+ .. _N3206: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm
+ .. _N3272: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm
+
+``cxx_range_for``
+ Range-based for, as defined in N2930_.
+
+ .. _N2930: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2930.html
+
+``cxx_raw_string_literals``
+ Raw string literals, as defined in N2442_.
+
+ .. _N2442: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm
+
+``cxx_reference_qualified_functions``
+ Reference qualified functions, as defined in N2439_.
+
+ .. _N2439: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm
+
+``cxx_right_angle_brackets``
+ Right angle bracket parsing, as defined in N1757_.
+
+ .. _N1757: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html
+
+``cxx_rvalue_references``
+ R-value references, as defined in N2118_.
+
+ .. _N2118: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html
+
+``cxx_sizeof_member``
+ Size of non-static data members, as defined in N2253_.
+
+ .. _N2253: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2253.html
+
+``cxx_static_assert``
+ Static assert, as defined in N1720_.
+
+ .. _N1720: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html
+
+``cxx_strong_enums``
+ Strongly typed enums, as defined in N2347_.
+
+ .. _N2347: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf
+
+``cxx_thread_local``
+ Thread-local variables, as defined in N2659_.
+
+ .. _N2659: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm
+
+``cxx_trailing_return_types``
+ Automatic function return type, as defined in N2541_.
+
+ .. _N2541: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm
+
+``cxx_unicode_literals``
+ Unicode string literals, as defined in N2442_.
+
+ .. _N2442: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm
+
+``cxx_uniform_initialization``
+ Uniform initialization, as defined in N2640_.
+
+ .. _N2640: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2640.pdf
+
+``cxx_unrestricted_unions``
+ Unrestricted unions, as defined in N2544_.
+
+ .. _N2544: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+
+``cxx_user_literals``
+ User-defined literals, as defined in N2765_.
+
+ .. _N2765: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2765.pdf
+
+``cxx_variadic_macros``
+ Variadic macros, as defined in N1653_.
+
+ .. _N1653: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm
+
+``cxx_variadic_templates``
+ Variadic templates, as defined in N2242_.
+
+ .. _N2242: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf
+
+
+Individual features from C++ 14
+"""""""""""""""""""""""""""""""
+
+``cxx_aggregate_default_initializers``
+ Aggregate default initializers, as defined in N3605_.
+
+ .. _N3605: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3605.html
+
+``cxx_attribute_deprecated``
+ ``[[deprecated]]`` attribute, as defined in N3760_.
+
+ .. _N3760: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3760.html
+
+``cxx_binary_literals``
+ Binary literals, as defined in N3472_.
+
+ .. _N3472: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3472.pdf
+
+``cxx_contextual_conversions``
+ Contextual conversions, as defined in N3323_.
+
+ .. _N3323: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3323.pdf
+
+``cxx_decltype_auto``
+ ``decltype(auto)`` semantics, as defined in N3638_.
+
+ .. _N3638: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3638.html
+
+``cxx_digit_separators``
+ Digit separators, as defined in N3781_.
+
+ .. _N3781: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3781.pdf
+
+``cxx_generic_lambdas``
+ Generic lambdas, as defined in N3649_.
+
+ .. _N3649: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3649.html
+
+``cxx_lambda_init_captures``
+ Initialized lambda captures, as defined in N3648_.
+
+ .. _N3648: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3648.html
+
+``cxx_relaxed_constexpr``
+ Relaxed constexpr, as defined in N3652_.
+
+ .. _N3652: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3652.html
+
+``cxx_return_type_deduction``
+ Return type deduction on normal functions, as defined in N3386_.
+
+ .. _N3386: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3386.html
+
+``cxx_variable_templates``
+ Variable templates, as defined in N3651_.
+
+ .. _N3651: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3651.pdf
diff --git a/Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst b/Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst
new file mode 100644
index 0000000..2bd0feb
--- /dev/null
+++ b/Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst
@@ -0,0 +1,43 @@
+CMAKE_C_KNOWN_FEATURES
+----------------------
+
+.. versionadded:: 3.1
+
+List of C features known to this version of CMake.
+
+The features listed in this global property may be known to be available to the
+C compiler. If the feature is available with the C compiler, it will
+be listed in the :variable:`CMAKE_C_COMPILE_FEATURES` variable.
+
+The features listed here may be used with the :command:`target_compile_features`
+command. See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+The features known to this version of CMake are:
+
+``c_std_90``
+ Compiler mode is at least C 90.
+
+``c_std_99``
+ Compiler mode is at least C 99.
+
+``c_std_11``
+ Compiler mode is at least C 11.
+
+``c_std_17``
+ Compiler mode is at least C 17.
+
+``c_std_23``
+ Compiler mode is at least C 23.
+
+``c_function_prototypes``
+ Function prototypes, as defined in ``ISO/IEC 9899:1990``.
+
+``c_restrict``
+ ``restrict`` keyword, as defined in ``ISO/IEC 9899:1999``.
+
+``c_static_assert``
+ Static assert, as defined in ``ISO/IEC 9899:2011``.
+
+``c_variadic_macros``
+ Variadic macros, as defined in ``ISO/IEC 9899:1999``.
diff --git a/Help/prop_gbl/CMAKE_ROLE.rst b/Help/prop_gbl/CMAKE_ROLE.rst
new file mode 100644
index 0000000..3f4492f
--- /dev/null
+++ b/Help/prop_gbl/CMAKE_ROLE.rst
@@ -0,0 +1,22 @@
+CMAKE_ROLE
+----------
+
+.. versionadded:: 3.14
+
+Tells what mode the current running script is in. Could be one of several
+values:
+
+``PROJECT``
+ Running in project mode (processing a ``CMakeLists.txt`` file).
+
+``SCRIPT``
+ Running in ``-P`` script mode.
+
+``FIND_PACKAGE``
+ Running in ``--find-package`` mode.
+
+``CTEST``
+ Running in CTest script mode.
+
+``CPACK``
+ Running in CPack.
diff --git a/Help/prop_gbl/DEBUG_CONFIGURATIONS.rst b/Help/prop_gbl/DEBUG_CONFIGURATIONS.rst
new file mode 100644
index 0000000..fec6fda
--- /dev/null
+++ b/Help/prop_gbl/DEBUG_CONFIGURATIONS.rst
@@ -0,0 +1,13 @@
+DEBUG_CONFIGURATIONS
+--------------------
+
+Specify which configurations are for debugging.
+
+The value must be a semi-colon separated list of configuration names.
+Currently this property is used only by the :command:`target_link_libraries`
+command. Additional uses may be defined in the future.
+
+This property must be set at the top level of the project and before
+the first :command:`target_link_libraries` command invocation. If any entry in
+the list does not match a valid configuration for the project the
+behavior is undefined.
diff --git a/Help/prop_gbl/DISABLED_FEATURES.rst b/Help/prop_gbl/DISABLED_FEATURES.rst
new file mode 100644
index 0000000..882bbfa
--- /dev/null
+++ b/Help/prop_gbl/DISABLED_FEATURES.rst
@@ -0,0 +1,11 @@
+DISABLED_FEATURES
+-----------------
+
+List of features which are disabled during the CMake run.
+
+List of features which are disabled during the CMake run. By default
+it contains the names of all packages which were not found. This is
+determined using the ``<NAME>_FOUND`` variables. Packages which are
+searched ``QUIET`` are not listed. A project can add its own features to
+this list. This property is used by the macros in
+``FeatureSummary.cmake``.
diff --git a/Help/prop_gbl/ECLIPSE_EXTRA_CPROJECT_CONTENTS.rst b/Help/prop_gbl/ECLIPSE_EXTRA_CPROJECT_CONTENTS.rst
new file mode 100644
index 0000000..2f110a7
--- /dev/null
+++ b/Help/prop_gbl/ECLIPSE_EXTRA_CPROJECT_CONTENTS.rst
@@ -0,0 +1,14 @@
+ECLIPSE_EXTRA_CPROJECT_CONTENTS
+-------------------------------
+
+.. versionadded:: 3.12
+
+Additional contents to be inserted into the generated Eclipse cproject file.
+
+The cproject file defines the CDT specific information. Some third party IDE's
+are based on Eclipse with the addition of other information specific to that IDE.
+Through this property, it is possible to add this additional contents to
+the generated project.
+It is expected to contain valid XML.
+
+Also see the :prop_gbl:`ECLIPSE_EXTRA_NATURES` property.
diff --git a/Help/prop_gbl/ECLIPSE_EXTRA_NATURES.rst b/Help/prop_gbl/ECLIPSE_EXTRA_NATURES.rst
new file mode 100644
index 0000000..a46575f
--- /dev/null
+++ b/Help/prop_gbl/ECLIPSE_EXTRA_NATURES.rst
@@ -0,0 +1,10 @@
+ECLIPSE_EXTRA_NATURES
+---------------------
+
+List of natures to add to the generated Eclipse project file.
+
+Eclipse projects specify language plugins by using natures. This property
+should be set to the unique identifier for a nature (which looks like a Java
+package name).
+
+Also see the :prop_gbl:`ECLIPSE_EXTRA_CPROJECT_CONTENTS` property.
diff --git a/Help/prop_gbl/ENABLED_FEATURES.rst b/Help/prop_gbl/ENABLED_FEATURES.rst
new file mode 100644
index 0000000..acbb3d0
--- /dev/null
+++ b/Help/prop_gbl/ENABLED_FEATURES.rst
@@ -0,0 +1,11 @@
+ENABLED_FEATURES
+----------------
+
+List of features which are enabled during the CMake run.
+
+List of features which are enabled during the CMake run. By default
+it contains the names of all packages which were found. This is
+determined using the ``<NAME>_FOUND`` variables. Packages which are
+searched ``QUIET`` are not listed. A project can add its own features to
+this list. This property is used by the macros in
+``FeatureSummary.cmake``.
diff --git a/Help/prop_gbl/ENABLED_LANGUAGES.rst b/Help/prop_gbl/ENABLED_LANGUAGES.rst
new file mode 100644
index 0000000..43e3c09
--- /dev/null
+++ b/Help/prop_gbl/ENABLED_LANGUAGES.rst
@@ -0,0 +1,6 @@
+ENABLED_LANGUAGES
+-----------------
+
+Read-only property that contains the list of currently enabled languages
+
+Set to list of currently enabled languages.
diff --git a/Help/prop_gbl/FIND_LIBRARY_USE_LIB32_PATHS.rst b/Help/prop_gbl/FIND_LIBRARY_USE_LIB32_PATHS.rst
new file mode 100644
index 0000000..f6cad66
--- /dev/null
+++ b/Help/prop_gbl/FIND_LIBRARY_USE_LIB32_PATHS.rst
@@ -0,0 +1,14 @@
+FIND_LIBRARY_USE_LIB32_PATHS
+----------------------------
+
+.. versionadded:: 3.7
+
+Whether the :command:`find_library` command should automatically search
+``lib32`` directories.
+
+``FIND_LIBRARY_USE_LIB32_PATHS`` is a boolean specifying whether the
+:command:`find_library` command should automatically search the ``lib32``
+variant of directories called ``lib`` in the search path when building 32-bit
+binaries.
+
+See also the :variable:`CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX` variable.
diff --git a/Help/prop_gbl/FIND_LIBRARY_USE_LIB64_PATHS.rst b/Help/prop_gbl/FIND_LIBRARY_USE_LIB64_PATHS.rst
new file mode 100644
index 0000000..ed343ba
--- /dev/null
+++ b/Help/prop_gbl/FIND_LIBRARY_USE_LIB64_PATHS.rst
@@ -0,0 +1,12 @@
+FIND_LIBRARY_USE_LIB64_PATHS
+----------------------------
+
+Whether :command:`find_library` should automatically search lib64
+directories.
+
+FIND_LIBRARY_USE_LIB64_PATHS is a boolean specifying whether the
+:command:`find_library` command should automatically search the lib64
+variant of directories called lib in the search path when building
+64-bit binaries.
+
+See also the :variable:`CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX` variable.
diff --git a/Help/prop_gbl/FIND_LIBRARY_USE_LIBX32_PATHS.rst b/Help/prop_gbl/FIND_LIBRARY_USE_LIBX32_PATHS.rst
new file mode 100644
index 0000000..851f859
--- /dev/null
+++ b/Help/prop_gbl/FIND_LIBRARY_USE_LIBX32_PATHS.rst
@@ -0,0 +1,14 @@
+FIND_LIBRARY_USE_LIBX32_PATHS
+-----------------------------
+
+.. versionadded:: 3.9
+
+Whether the :command:`find_library` command should automatically search
+``libx32`` directories.
+
+``FIND_LIBRARY_USE_LIBX32_PATHS`` is a boolean specifying whether the
+:command:`find_library` command should automatically search the ``libx32``
+variant of directories called ``lib`` in the search path when building
+x32-abi binaries.
+
+See also the :variable:`CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX` variable.
diff --git a/Help/prop_gbl/FIND_LIBRARY_USE_OPENBSD_VERSIONING.rst b/Help/prop_gbl/FIND_LIBRARY_USE_OPENBSD_VERSIONING.rst
new file mode 100644
index 0000000..beb94ac
--- /dev/null
+++ b/Help/prop_gbl/FIND_LIBRARY_USE_OPENBSD_VERSIONING.rst
@@ -0,0 +1,10 @@
+FIND_LIBRARY_USE_OPENBSD_VERSIONING
+-----------------------------------
+
+Whether :command:`find_library` should find OpenBSD-style shared
+libraries.
+
+This property is a boolean specifying whether the
+:command:`find_library` command should find shared libraries with
+OpenBSD-style versioned extension: ".so.<major>.<minor>". The
+property is set to true on OpenBSD and false on other platforms.
diff --git a/Help/prop_gbl/GENERATOR_IS_MULTI_CONFIG.rst b/Help/prop_gbl/GENERATOR_IS_MULTI_CONFIG.rst
new file mode 100644
index 0000000..761a1dd
--- /dev/null
+++ b/Help/prop_gbl/GENERATOR_IS_MULTI_CONFIG.rst
@@ -0,0 +1,15 @@
+GENERATOR_IS_MULTI_CONFIG
+-------------------------
+
+.. versionadded:: 3.9
+
+Read-only property that is true on multi-configuration generators.
+
+True when using a multi-configuration generator such as:
+
+* :generator:`Ninja Multi-Config`
+* :ref:`Visual Studio Generators`
+* :generator:`Xcode`
+
+Multi-config generators use :variable:`CMAKE_CONFIGURATION_TYPES`
+as the set of configurations and ignore :variable:`CMAKE_BUILD_TYPE`.
diff --git a/Help/prop_gbl/GLOBAL_DEPENDS_DEBUG_MODE.rst b/Help/prop_gbl/GLOBAL_DEPENDS_DEBUG_MODE.rst
new file mode 100644
index 0000000..832503b
--- /dev/null
+++ b/Help/prop_gbl/GLOBAL_DEPENDS_DEBUG_MODE.rst
@@ -0,0 +1,8 @@
+GLOBAL_DEPENDS_DEBUG_MODE
+-------------------------
+
+Enable global target dependency graph debug mode.
+
+CMake automatically analyzes the global inter-target dependency graph
+at the beginning of native build system generation. This property
+causes it to display details of its analysis to stderr.
diff --git a/Help/prop_gbl/GLOBAL_DEPENDS_NO_CYCLES.rst b/Help/prop_gbl/GLOBAL_DEPENDS_NO_CYCLES.rst
new file mode 100644
index 0000000..d10661e
--- /dev/null
+++ b/Help/prop_gbl/GLOBAL_DEPENDS_NO_CYCLES.rst
@@ -0,0 +1,10 @@
+GLOBAL_DEPENDS_NO_CYCLES
+------------------------
+
+Disallow global target dependency graph cycles.
+
+CMake automatically analyzes the global inter-target dependency graph
+at the beginning of native build system generation. It reports an
+error if the dependency graph contains a cycle that does not consist
+of all STATIC library targets. This property tells CMake to disallow
+all cycles completely, even among static libraries.
diff --git a/Help/prop_gbl/IN_TRY_COMPILE.rst b/Help/prop_gbl/IN_TRY_COMPILE.rst
new file mode 100644
index 0000000..fd2d2e1
--- /dev/null
+++ b/Help/prop_gbl/IN_TRY_COMPILE.rst
@@ -0,0 +1,7 @@
+IN_TRY_COMPILE
+--------------
+
+Read-only property that is true during a try-compile configuration.
+
+True when building a project inside a :command:`try_compile` or
+:command:`try_run` command.
diff --git a/Help/prop_gbl/JOB_POOLS.rst b/Help/prop_gbl/JOB_POOLS.rst
new file mode 100644
index 0000000..21da4662
--- /dev/null
+++ b/Help/prop_gbl/JOB_POOLS.rst
@@ -0,0 +1,31 @@
+JOB_POOLS
+---------
+
+Ninja only: List of available pools.
+
+A pool is a named integer property and defines the maximum number
+of concurrent jobs which can be started by a rule assigned to the pool.
+The :prop_gbl:`JOB_POOLS` property is a semicolon-separated list of
+pairs using the syntax NAME=integer (without a space after the equality sign).
+
+For instance:
+
+.. code-block:: cmake
+
+ set_property(GLOBAL PROPERTY JOB_POOLS two_jobs=2 ten_jobs=10)
+
+Defined pools could be used globally by setting
+:variable:`CMAKE_JOB_POOL_COMPILE` and :variable:`CMAKE_JOB_POOL_LINK`
+or per target by setting the target properties
+:prop_tgt:`JOB_POOL_COMPILE` and :prop_tgt:`JOB_POOL_LINK`.
+:command:`Custom commands <add_custom_command>` and
+:command:`custom targets <add_custom_target>` can specify pools using the
+option ``JOB_POOL``.
+Using a pool that is not defined by :prop_gbl:`JOB_POOLS` causes
+an error by ninja at build time.
+
+If not set, this property uses the value of the :variable:`CMAKE_JOB_POOLS`
+variable.
+
+Build targets provided by CMake that are meant for individual interactive
+use, such as ``install``, are placed in the ``console`` pool automatically.
diff --git a/Help/prop_gbl/PACKAGES_FOUND.rst b/Help/prop_gbl/PACKAGES_FOUND.rst
new file mode 100644
index 0000000..61cce1f
--- /dev/null
+++ b/Help/prop_gbl/PACKAGES_FOUND.rst
@@ -0,0 +1,7 @@
+PACKAGES_FOUND
+--------------
+
+List of packages which were found during the CMake run.
+
+List of packages which were found during the CMake run. Whether a
+package has been found is determined using the <NAME>_FOUND variables.
diff --git a/Help/prop_gbl/PACKAGES_NOT_FOUND.rst b/Help/prop_gbl/PACKAGES_NOT_FOUND.rst
new file mode 100644
index 0000000..ca3c5ba
--- /dev/null
+++ b/Help/prop_gbl/PACKAGES_NOT_FOUND.rst
@@ -0,0 +1,7 @@
+PACKAGES_NOT_FOUND
+------------------
+
+List of packages which were not found during the CMake run.
+
+List of packages which were not found during the CMake run. Whether a
+package has been found is determined using the <NAME>_FOUND variables.
diff --git a/Help/prop_gbl/PREDEFINED_TARGETS_FOLDER.rst b/Help/prop_gbl/PREDEFINED_TARGETS_FOLDER.rst
new file mode 100644
index 0000000..bf8c9a3
--- /dev/null
+++ b/Help/prop_gbl/PREDEFINED_TARGETS_FOLDER.rst
@@ -0,0 +1,9 @@
+PREDEFINED_TARGETS_FOLDER
+-------------------------
+
+Name of FOLDER for targets that are added automatically by CMake.
+
+If not set, CMake uses "CMakePredefinedTargets" as a default value for
+this property. Targets such as INSTALL, PACKAGE and RUN_TESTS will be
+organized into this FOLDER. See also the documentation for the
+:prop_tgt:`FOLDER` target property.
diff --git a/Help/prop_gbl/REPORT_UNDEFINED_PROPERTIES.rst b/Help/prop_gbl/REPORT_UNDEFINED_PROPERTIES.rst
new file mode 100644
index 0000000..29ba365
--- /dev/null
+++ b/Help/prop_gbl/REPORT_UNDEFINED_PROPERTIES.rst
@@ -0,0 +1,8 @@
+REPORT_UNDEFINED_PROPERTIES
+---------------------------
+
+If set, report any undefined properties to this file.
+
+If this property is set to a filename then when CMake runs it will
+report any properties or variables that were accessed but not defined
+into the filename specified in this property.
diff --git a/Help/prop_gbl/RULE_LAUNCH_COMPILE.rst b/Help/prop_gbl/RULE_LAUNCH_COMPILE.rst
new file mode 100644
index 0000000..e0df878
--- /dev/null
+++ b/Help/prop_gbl/RULE_LAUNCH_COMPILE.rst
@@ -0,0 +1,11 @@
+RULE_LAUNCH_COMPILE
+-------------------
+
+Specify a launcher for compile rules.
+
+:ref:`Makefile Generators` and the :generator:`Ninja` generator prefix
+compiler commands with the given launcher command line.
+This is intended to allow launchers to intercept build problems
+with high granularity. Other generators ignore this property
+because their underlying build systems provide no hook to wrap
+individual commands with a launcher.
diff --git a/Help/prop_gbl/RULE_LAUNCH_CUSTOM.rst b/Help/prop_gbl/RULE_LAUNCH_CUSTOM.rst
new file mode 100644
index 0000000..b20c59b
--- /dev/null
+++ b/Help/prop_gbl/RULE_LAUNCH_CUSTOM.rst
@@ -0,0 +1,11 @@
+RULE_LAUNCH_CUSTOM
+------------------
+
+Specify a launcher for custom rules.
+
+:ref:`Makefile Generators` and the :generator:`Ninja` generator prefix
+custom commands with the given launcher command line.
+This is intended to allow launchers to intercept build problems
+with high granularity. Other generators ignore this property
+because their underlying build systems provide no hook to wrap
+individual commands with a launcher.
diff --git a/Help/prop_gbl/RULE_LAUNCH_LINK.rst b/Help/prop_gbl/RULE_LAUNCH_LINK.rst
new file mode 100644
index 0000000..567bb68
--- /dev/null
+++ b/Help/prop_gbl/RULE_LAUNCH_LINK.rst
@@ -0,0 +1,11 @@
+RULE_LAUNCH_LINK
+----------------
+
+Specify a launcher for link rules.
+
+:ref:`Makefile Generators` and the :generator:`Ninja` generator prefix
+link and archive commands with the given launcher command line.
+This is intended to allow launchers to intercept build problems
+with high granularity. Other generators ignore this property
+because their underlying build systems provide no hook to wrap
+individual commands with a launcher.
diff --git a/Help/prop_gbl/RULE_MESSAGES.rst b/Help/prop_gbl/RULE_MESSAGES.rst
new file mode 100644
index 0000000..a9734a7
--- /dev/null
+++ b/Help/prop_gbl/RULE_MESSAGES.rst
@@ -0,0 +1,13 @@
+RULE_MESSAGES
+-------------
+
+Specify whether to report a message for each make rule.
+
+This property specifies whether Makefile generators should add a
+progress message describing what each build rule does. If the
+property is not set the default is ON. Set the property to OFF to
+disable granular messages and report only as each target completes.
+This is intended to allow scripted builds to avoid the build time cost
+of detailed reports. If a :variable:`CMAKE_RULE_MESSAGES` cache entry exists
+its value initializes the value of this property. Non-Makefile
+generators currently ignore this property.
diff --git a/Help/prop_gbl/TARGET_ARCHIVES_MAY_BE_SHARED_LIBS.rst b/Help/prop_gbl/TARGET_ARCHIVES_MAY_BE_SHARED_LIBS.rst
new file mode 100644
index 0000000..930feba
--- /dev/null
+++ b/Help/prop_gbl/TARGET_ARCHIVES_MAY_BE_SHARED_LIBS.rst
@@ -0,0 +1,7 @@
+TARGET_ARCHIVES_MAY_BE_SHARED_LIBS
+----------------------------------
+
+Set if shared libraries may be named like archives.
+
+On AIX shared libraries may be named "lib<name>.a". This property is
+set to true on such platforms.
diff --git a/Help/prop_gbl/TARGET_MESSAGES.rst b/Help/prop_gbl/TARGET_MESSAGES.rst
new file mode 100644
index 0000000..bb91772
--- /dev/null
+++ b/Help/prop_gbl/TARGET_MESSAGES.rst
@@ -0,0 +1,22 @@
+TARGET_MESSAGES
+---------------
+
+.. versionadded:: 3.4
+
+Specify whether to report the completion of each target.
+
+This property specifies whether :ref:`Makefile Generators` should
+add a progress message describing that each target has been completed.
+If the property is not set the default is ``ON``. Set the property
+to ``OFF`` to disable target completion messages.
+
+This option is intended to reduce build output when little or no
+work needs to be done to bring the build tree up to date.
+
+If a ``CMAKE_TARGET_MESSAGES`` cache entry exists its value
+initializes the value of this property.
+
+Non-Makefile generators currently ignore this property.
+
+See the counterpart property :prop_gbl:`RULE_MESSAGES` to disable
+everything except for target completion messages.
diff --git a/Help/prop_gbl/TARGET_SUPPORTS_SHARED_LIBS.rst b/Help/prop_gbl/TARGET_SUPPORTS_SHARED_LIBS.rst
new file mode 100644
index 0000000..f6e89fb
--- /dev/null
+++ b/Help/prop_gbl/TARGET_SUPPORTS_SHARED_LIBS.rst
@@ -0,0 +1,9 @@
+TARGET_SUPPORTS_SHARED_LIBS
+---------------------------
+
+Does the target platform support shared libraries.
+
+TARGET_SUPPORTS_SHARED_LIBS is a boolean specifying whether the target
+platform supports shared libraries. Basically all current general
+general purpose OS do so, the exception are usually embedded systems
+with no or special OSs.
diff --git a/Help/prop_gbl/USE_FOLDERS.rst b/Help/prop_gbl/USE_FOLDERS.rst
new file mode 100644
index 0000000..5919723
--- /dev/null
+++ b/Help/prop_gbl/USE_FOLDERS.rst
@@ -0,0 +1,10 @@
+USE_FOLDERS
+-----------
+
+Use the :prop_tgt:`FOLDER` target property to organize targets into
+folders.
+
+If not set, CMake treats this property as ``OFF`` by default. CMake
+generators that are capable of organizing into a hierarchy of folders
+use the values of the :prop_tgt:`FOLDER` target property to name those
+folders. See also the documentation for the :prop_tgt:`FOLDER` target property.
diff --git a/Help/prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME.rst b/Help/prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME.rst
new file mode 100644
index 0000000..392b704
--- /dev/null
+++ b/Help/prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME.rst
@@ -0,0 +1,27 @@
+XCODE_EMIT_EFFECTIVE_PLATFORM_NAME
+----------------------------------
+
+.. versionadded:: 3.8
+
+Control emission of ``EFFECTIVE_PLATFORM_NAME`` by the :generator:`Xcode`
+generator.
+
+It is required for building the same target with multiple SDKs. A
+common use case is the parallel use of ``iphoneos`` and
+``iphonesimulator`` SDKs.
+
+Three different states possible that control when the :generator:`Xcode`
+generator emits the ``EFFECTIVE_PLATFORM_NAME`` variable:
+
+- If set to ``ON`` it will always be emitted
+- If set to ``OFF`` it will never be emitted
+- If unset (the default) it will only be emitted when the project was
+ configured for an embedded Xcode SDK like iOS, tvOS, watchOS or any
+ of the simulators.
+
+.. note::
+
+ When this behavior is enable for generated Xcode projects, the
+ ``EFFECTIVE_PLATFORM_NAME`` variable will leak into
+ :manual:`Generator expressions <cmake-generator-expressions(7)>`
+ like ``TARGET_FILE`` and will render those mostly unusable.
diff --git a/Help/prop_inst/CPACK_DESKTOP_SHORTCUTS.rst b/Help/prop_inst/CPACK_DESKTOP_SHORTCUTS.rst
new file mode 100644
index 0000000..55e9a20
--- /dev/null
+++ b/Help/prop_inst/CPACK_DESKTOP_SHORTCUTS.rst
@@ -0,0 +1,9 @@
+CPACK_DESKTOP_SHORTCUTS
+-----------------------
+
+.. versionadded:: 3.3
+
+Species a list of shortcut names that should be created on the `Desktop`
+for this file.
+
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_NEVER_OVERWRITE.rst b/Help/prop_inst/CPACK_NEVER_OVERWRITE.rst
new file mode 100644
index 0000000..12eef9e
--- /dev/null
+++ b/Help/prop_inst/CPACK_NEVER_OVERWRITE.rst
@@ -0,0 +1,8 @@
+CPACK_NEVER_OVERWRITE
+---------------------
+
+.. versionadded:: 3.1
+
+Request that this file not be overwritten on install or reinstall.
+
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_PERMANENT.rst b/Help/prop_inst/CPACK_PERMANENT.rst
new file mode 100644
index 0000000..e89c552
--- /dev/null
+++ b/Help/prop_inst/CPACK_PERMANENT.rst
@@ -0,0 +1,8 @@
+CPACK_PERMANENT
+---------------
+
+.. versionadded:: 3.1
+
+Request that this file not be removed on uninstall.
+
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_STARTUP_SHORTCUTS.rst b/Help/prop_inst/CPACK_STARTUP_SHORTCUTS.rst
new file mode 100644
index 0000000..e896acd
--- /dev/null
+++ b/Help/prop_inst/CPACK_STARTUP_SHORTCUTS.rst
@@ -0,0 +1,9 @@
+CPACK_STARTUP_SHORTCUTS
+-----------------------
+
+.. versionadded:: 3.3
+
+Species a list of shortcut names that should be created in the `Startup` folder
+for this file.
+
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_START_MENU_SHORTCUTS.rst b/Help/prop_inst/CPACK_START_MENU_SHORTCUTS.rst
new file mode 100644
index 0000000..fb8807f
--- /dev/null
+++ b/Help/prop_inst/CPACK_START_MENU_SHORTCUTS.rst
@@ -0,0 +1,9 @@
+CPACK_START_MENU_SHORTCUTS
+--------------------------
+
+.. versionadded:: 3.3
+
+Species a list of shortcut names that should be created in the `Start Menu`
+for this file.
+
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_inst/CPACK_WIX_ACL.rst b/Help/prop_inst/CPACK_WIX_ACL.rst
new file mode 100644
index 0000000..8b4fb5c
--- /dev/null
+++ b/Help/prop_inst/CPACK_WIX_ACL.rst
@@ -0,0 +1,23 @@
+CPACK_WIX_ACL
+-------------
+
+.. versionadded:: 3.1
+
+Specifies access permissions for files or directories
+installed by a WiX installer.
+
+The property can contain multiple list entries,
+each of which has to match the following format.
+
+::
+
+ <user>[@<domain>]=<permission>[,<permission>]
+
+``<user>`` and ``<domain>`` specify the windows user and domain for which the
+``<Permission>`` element should be generated.
+
+``<permission>`` is any of the YesNoType attributes listed here::
+
+ http://wixtoolset.org/documentation/manual/v3/xsd/wix/permission.html
+
+The property is currently only supported by the :cpack_gen:`CPack WIX Generator`.
diff --git a/Help/prop_sf/ABSTRACT.rst b/Help/prop_sf/ABSTRACT.rst
new file mode 100644
index 0000000..339d115
--- /dev/null
+++ b/Help/prop_sf/ABSTRACT.rst
@@ -0,0 +1,9 @@
+ABSTRACT
+--------
+
+Is this source file an abstract class.
+
+A property on a source file that indicates if the source file
+represents a class that is abstract. This only makes sense for
+languages that have a notion of an abstract class and it is only used
+by some tools that wrap classes into other languages.
diff --git a/Help/prop_sf/AUTORCC_OPTIONS.rst b/Help/prop_sf/AUTORCC_OPTIONS.rst
new file mode 100644
index 0000000..2bec033
--- /dev/null
+++ b/Help/prop_sf/AUTORCC_OPTIONS.rst
@@ -0,0 +1,22 @@
+AUTORCC_OPTIONS
+---------------
+
+Additional options for ``rcc`` when using :prop_tgt:`AUTORCC`
+
+This property holds additional command line options which will be used when
+``rcc`` is executed during the build via :prop_tgt:`AUTORCC`, i.e. it is equivalent to the
+optional ``OPTIONS`` argument of the :module:`qt4_add_resources() <FindQt4>` macro.
+
+By default it is empty.
+
+The options set on the ``.qrc`` source file may override
+:prop_tgt:`AUTORCC_OPTIONS` set on the target.
+
+EXAMPLE
+^^^^^^^
+
+.. code-block:: cmake
+
+ # ...
+ set_property(SOURCE resources.qrc PROPERTY AUTORCC_OPTIONS "--compress;9")
+ # ...
diff --git a/Help/prop_sf/AUTOUIC_OPTIONS.rst b/Help/prop_sf/AUTOUIC_OPTIONS.rst
new file mode 100644
index 0000000..e2f47ec
--- /dev/null
+++ b/Help/prop_sf/AUTOUIC_OPTIONS.rst
@@ -0,0 +1,23 @@
+AUTOUIC_OPTIONS
+---------------
+
+Additional options for ``uic`` when using :prop_tgt:`AUTOUIC`
+
+This property holds additional command line options
+which will be used when ``uic`` is executed during the build via
+:prop_tgt:`AUTOUIC`, i.e. it is equivalent to the optional ``OPTIONS``
+argument of the :module:`qt4_wrap_ui() <FindQt4>` macro.
+
+By default it is empty.
+
+The options set on the ``.ui`` source file may override
+:prop_tgt:`AUTOUIC_OPTIONS` set on the target.
+
+EXAMPLE
+^^^^^^^
+
+.. code-block:: cmake
+
+ # ...
+ set_property(SOURCE widget.ui PROPERTY AUTOUIC_OPTIONS "--no-protection")
+ # ...
diff --git a/Help/prop_sf/COMPILE_DEFINITIONS.rst b/Help/prop_sf/COMPILE_DEFINITIONS.rst
new file mode 100644
index 0000000..6317690
--- /dev/null
+++ b/Help/prop_sf/COMPILE_DEFINITIONS.rst
@@ -0,0 +1,29 @@
+COMPILE_DEFINITIONS
+-------------------
+
+Preprocessor definitions for compiling a source file.
+
+The ``COMPILE_DEFINITIONS`` property may be set to a semicolon-separated
+list of preprocessor definitions using the syntax ``VAR`` or ``VAR=value``.
+Function-style definitions are not supported. CMake will
+automatically escape the value correctly for the native build system
+(note that CMake language syntax may require escapes to specify some
+values). This property may be set on a per-configuration basis using
+the name ``COMPILE_DEFINITIONS_<CONFIG>`` where ``<CONFIG>`` is an upper-case
+name (ex. ``COMPILE_DEFINITIONS_DEBUG``).
+
+CMake will automatically drop some definitions that are not supported
+by the native build tool. Xcode does not support per-configuration
+definitions on source files.
+
+.. include:: /include/COMPILE_DEFINITIONS_DISCLAIMER.txt
+
+Contents of ``COMPILE_DEFINITIONS`` may use :manual:`cmake-generator-expressions(7)`
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. However, :generator:`Xcode`
+does not support per-config per-source settings, so expressions
+that depend on the build configuration are not allowed with that
+generator.
+
+Generator expressions should be preferred instead of setting the alternative per-configuration
+property.
diff --git a/Help/prop_sf/COMPILE_DEFINITIONS_CONFIG.rst b/Help/prop_sf/COMPILE_DEFINITIONS_CONFIG.rst
new file mode 100644
index 0000000..ec867b6
--- /dev/null
+++ b/Help/prop_sf/COMPILE_DEFINITIONS_CONFIG.rst
@@ -0,0 +1,10 @@
+COMPILE_DEFINITIONS_<CONFIG>
+----------------------------
+
+Ignored. See CMake Policy :policy:`CMP0043`.
+
+Per-configuration preprocessor definitions on a source file.
+
+This is the configuration-specific version of :prop_tgt:`COMPILE_DEFINITIONS`.
+Note that :generator:`Xcode` does not support per-configuration source
+file flags so this property will be ignored by the :generator:`Xcode` generator.
diff --git a/Help/prop_sf/COMPILE_FLAGS.rst b/Help/prop_sf/COMPILE_FLAGS.rst
new file mode 100644
index 0000000..c211b89
--- /dev/null
+++ b/Help/prop_sf/COMPILE_FLAGS.rst
@@ -0,0 +1,19 @@
+COMPILE_FLAGS
+-------------
+
+Additional flags to be added when compiling this source file.
+
+The ``COMPILE_FLAGS`` property, managed as a string, sets additional compiler
+flags used to build source files. Use :prop_sf:`COMPILE_DEFINITIONS` to pass
+additional preprocessor definitions.
+
+Contents of ``COMPILE_FLAGS`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. However, :generator:`Xcode`
+does not support per-config per-source settings, so expressions
+that depend on the build configuration are not allowed with that
+generator.
+
+.. note::
+
+ This property has been superseded by the :prop_sf:`COMPILE_OPTIONS` property.
diff --git a/Help/prop_sf/COMPILE_OPTIONS.rst b/Help/prop_sf/COMPILE_OPTIONS.rst
new file mode 100644
index 0000000..a694c3e
--- /dev/null
+++ b/Help/prop_sf/COMPILE_OPTIONS.rst
@@ -0,0 +1,34 @@
+COMPILE_OPTIONS
+---------------
+
+.. versionadded:: 3.11
+
+List of additional options to pass to the compiler.
+
+This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of options
+and will be added to the list of compile flags when this
+source file builds.
+
+Contents of ``COMPILE_OPTIONS`` may use "generator expressions" with the
+syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions. However, :generator:`Xcode`
+does not support per-config per-source settings, so expressions
+that depend on the build configuration are not allowed with that
+generator.
+
+Usage example:
+
+.. code-block:: cmake
+
+ set_source_files_properties(foo.cpp PROPERTIES COMPILE_OPTIONS "-Wno-unused-parameter;-Wno-missing-field-initializer")
+
+Related properties:
+
+* Prefer this property over :prop_sf:`COMPILE_FLAGS`.
+* Use :prop_sf:`COMPILE_DEFINITIONS` to pass additional preprocessor definitions.
+* Use :prop_sf:`INCLUDE_DIRECTORIES` to pass additional include directories.
+
+Related commands:
+
+* :command:`add_compile_options` for directory-wide settings
+* :command:`target_compile_options` for target-specific settings
diff --git a/Help/prop_sf/EXTERNAL_OBJECT.rst b/Help/prop_sf/EXTERNAL_OBJECT.rst
new file mode 100644
index 0000000..351c04d
--- /dev/null
+++ b/Help/prop_sf/EXTERNAL_OBJECT.rst
@@ -0,0 +1,8 @@
+EXTERNAL_OBJECT
+---------------
+
+If set to true then this is an object file.
+
+If this property is set to ``True`` then the source file is really an
+object file and should not be compiled. It will still be linked into
+the target though.
diff --git a/Help/prop_sf/Fortran_FORMAT.rst b/Help/prop_sf/Fortran_FORMAT.rst
new file mode 100644
index 0000000..ef33926
--- /dev/null
+++ b/Help/prop_sf/Fortran_FORMAT.rst
@@ -0,0 +1,12 @@
+Fortran_FORMAT
+--------------
+
+Set to ``FIXED`` or ``FREE`` to indicate the Fortran source layout.
+
+This property tells CMake whether a given Fortran source file uses
+fixed-format or free-format. CMake will pass the corresponding format flag
+to the compiler. Consider using the target-wide :prop_tgt:`Fortran_FORMAT`
+property if all source files in a target share the same format.
+
+.. note:: For some compilers, ``NAG``, ``PGI`` and ``Solaris Studio``,
+ setting this to ``OFF`` will have no effect.
diff --git a/Help/prop_sf/Fortran_PREPROCESS.rst b/Help/prop_sf/Fortran_PREPROCESS.rst
new file mode 100644
index 0000000..548a97b
--- /dev/null
+++ b/Help/prop_sf/Fortran_PREPROCESS.rst
@@ -0,0 +1,19 @@
+Fortran_PREPROCESS
+------------------
+
+.. versionadded:: 3.18
+
+Control whether the Fortran source file should be unconditionally preprocessed.
+
+If unset or empty, rely on the compiler to determine whether the file
+should be preprocessed. If explicitly set to ``OFF`` then the file
+does not need to be preprocessed. If explicitly set to ``ON``, then
+the file does need to be preprocessed as part of the compilation step.
+
+When using the :generator:`Ninja` generator, all source files are
+first preprocessed in order to generate module dependency
+information. Setting this property to ``OFF`` will make ``Ninja``
+skip this step.
+
+Consider using the target-wide :prop_tgt:`Fortran_PREPROCESS` property
+if all source files in a target need to be preprocessed.
diff --git a/Help/prop_sf/GENERATED.rst b/Help/prop_sf/GENERATED.rst
new file mode 100644
index 0000000..216dfe8
--- /dev/null
+++ b/Help/prop_sf/GENERATED.rst
@@ -0,0 +1,48 @@
+GENERATED
+---------
+
+Is this source file generated as part of the build or CMake process.
+
+.. versionchanged:: 3.20
+ The GENERATED source file property is now visible in all directories.
+
+Tells the internal CMake engine that a source file is generated by an outside
+process such as another build step, or the execution of CMake itself.
+This information is then used to exempt the file from any existence or
+validity checks.
+
+Any file that is
+
+- created by the execution of commands such as
+ :command:`add_custom_command` and :command:`file(GENERATE)`
+- listed as one of the ``BYPRODUCTS`` of an :command:`add_custom_command`
+ or :command:`add_custom_target` command, or
+- created by a CMake ``AUTOGEN`` operation such as :prop_tgt:`AUTOMOC`,
+ :prop_tgt:`AUTORCC`, or :prop_tgt:`AUTOUIC`
+
+will be marked with the ``GENERATED`` property.
+
+When a generated file created as the ``OUTPUT`` of an
+:command:`add_custom_command` command is explicitly listed as a source file
+for any target in the same directory scope (which usually means the same
+``CMakeLists.txt`` file), CMake will automatically create a dependency to
+make sure the file is generated before building that target.
+
+The :ref:`Makefile Generators` will remove ``GENERATED`` files during
+``make clean``.
+
+Generated sources may be hidden in some IDE tools, while in others they might
+be shown. For the special case of sources generated by CMake's :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTORCC` or :prop_tgt:`AUTOUIC` functionality, the
+:prop_gbl:`AUTOGEN_SOURCE_GROUP`, :prop_gbl:`AUTOMOC_SOURCE_GROUP`,
+:prop_gbl:`AUTORCC_SOURCE_GROUP` and :prop_gbl:`AUTOUIC_SOURCE_GROUP` target
+properties may influence where the generated sources are grouped in the project's
+file lists.
+
+.. note::
+
+ Starting with CMake 3.20 the ``GENERATED`` source file property can be set
+ and retrieved from any directory scope. It is an all-or-nothing property.
+ It also can no longer be removed or unset if it was set to ``TRUE``. Policy
+ :policy:`CMP0118` was introduced to allow supporting the ``OLD`` behavior
+ for some time.
diff --git a/Help/prop_sf/HEADER_FILE_ONLY.rst b/Help/prop_sf/HEADER_FILE_ONLY.rst
new file mode 100644
index 0000000..71d62ae
--- /dev/null
+++ b/Help/prop_sf/HEADER_FILE_ONLY.rst
@@ -0,0 +1,24 @@
+HEADER_FILE_ONLY
+----------------
+
+Is this source file only a header file.
+
+A property on a source file that indicates if the source file is a
+header file with no associated implementation. This is set
+automatically based on the file extension and is used by CMake to
+determine if certain dependency information should be computed.
+
+By setting this property to ``ON``, you can disable compilation of
+the given source file, even if it should be compiled because it is
+part of the library's/executable's sources.
+
+This is useful if you have some source files which you somehow
+pre-process, and then add these pre-processed sources via
+:command:`add_library` or :command:`add_executable`. Normally, in IDE,
+there would be no reference of the original sources, only of these
+pre-processed sources. So by setting this property for all the original
+source files to ``ON``, and then either calling :command:`add_library`
+or :command:`add_executable` while passing both the pre-processed
+sources and the original sources, or by using :command:`target_sources`
+to add original source files will do exactly what would one expect, i.e.
+the original source files would be visible in IDE, and will not be built.
diff --git a/Help/prop_sf/INCLUDE_DIRECTORIES.rst b/Help/prop_sf/INCLUDE_DIRECTORIES.rst
new file mode 100644
index 0000000..89ffd15
--- /dev/null
+++ b/Help/prop_sf/INCLUDE_DIRECTORIES.rst
@@ -0,0 +1,20 @@
+INCLUDE_DIRECTORIES
+-------------------
+
+.. versionadded:: 3.11
+
+List of preprocessor include file search directories.
+
+This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of paths
+and will be added to the list of include directories when this
+source file builds. These directories will take precedence over directories
+defined at target level except for :generator:`Xcode` generator due to technical
+limitations.
+
+Relative paths should not be added to this property directly.
+
+Contents of ``INCLUDE_DIRECTORIES`` may use "generator expressions" with
+the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions. However, :generator:`Xcode` does not support
+per-config per-source settings, so expressions that depend on the build
+configuration are not allowed with that generator.
diff --git a/Help/prop_sf/KEEP_EXTENSION.rst b/Help/prop_sf/KEEP_EXTENSION.rst
new file mode 100644
index 0000000..a32f968
--- /dev/null
+++ b/Help/prop_sf/KEEP_EXTENSION.rst
@@ -0,0 +1,9 @@
+KEEP_EXTENSION
+--------------
+
+Make the output file have the same extension as the source file.
+
+If this property is set then the file extension of the output file
+will be the same as that of the source file. Normally the output file
+extension is computed based on the language of the source file, for
+example ``.cxx`` will go to a ``.o`` extension.
diff --git a/Help/prop_sf/LABELS.rst b/Help/prop_sf/LABELS.rst
new file mode 100644
index 0000000..d0d2a0a
--- /dev/null
+++ b/Help/prop_sf/LABELS.rst
@@ -0,0 +1,8 @@
+LABELS
+------
+
+Specify a list of text labels associated with a source file.
+
+This property has meaning only when the source file is listed in a
+target whose ``LABELS`` property is also set. No other semantics are
+currently specified.
diff --git a/Help/prop_sf/LANGUAGE.rst b/Help/prop_sf/LANGUAGE.rst
new file mode 100644
index 0000000..f14c176
--- /dev/null
+++ b/Help/prop_sf/LANGUAGE.rst
@@ -0,0 +1,17 @@
+LANGUAGE
+--------
+
+Specify the programming language in which a source file is written.
+
+A property that can be set to indicate what programming language the
+source file is. If it is not set the language is determined based on
+the file extension. Typical values are ``CXX`` (i.e. C++), ``C``,
+``CSharp``, ``CUDA``, ``Fortran``, ``ISPC``, and ``ASM``. Setting this
+property for a file means this file will be compiled. Do not set this
+for headers or files that should not be compiled.
+
+.. versionchanged:: 3.20
+ Setting this property causes the source file to be compiled as the
+ specified language, using explicit flags if possible. Previously it
+ only caused the specified language's compiler to be used.
+ See policy :policy:`CMP0119`.
diff --git a/Help/prop_sf/LOCATION.rst b/Help/prop_sf/LOCATION.rst
new file mode 100644
index 0000000..252d680
--- /dev/null
+++ b/Help/prop_sf/LOCATION.rst
@@ -0,0 +1,7 @@
+LOCATION
+--------
+
+The full path to a source file.
+
+A read only property on a SOURCE FILE that contains the full path to
+the source file.
diff --git a/Help/prop_sf/MACOSX_PACKAGE_LOCATION.rst b/Help/prop_sf/MACOSX_PACKAGE_LOCATION.rst
new file mode 100644
index 0000000..d185d91
--- /dev/null
+++ b/Help/prop_sf/MACOSX_PACKAGE_LOCATION.rst
@@ -0,0 +1,30 @@
+MACOSX_PACKAGE_LOCATION
+-----------------------
+
+Place a source file inside a Application Bundle
+(:prop_tgt:`MACOSX_BUNDLE`), Core Foundation Bundle (:prop_tgt:`BUNDLE`),
+or Framework Bundle (:prop_tgt:`FRAMEWORK`). It is applicable for macOS
+and iOS.
+
+Executable targets with the :prop_tgt:`MACOSX_BUNDLE` property set are
+built as macOS or iOS application bundles on Apple platforms. Shared
+library targets with the :prop_tgt:`FRAMEWORK` property set are built as
+macOS or iOS frameworks on Apple platforms. Module library targets with
+the :prop_tgt:`BUNDLE` property set are built as macOS ``CFBundle`` bundles
+on Apple platforms. Source files listed in the target with this property
+set will be copied to a directory inside the bundle or framework content
+folder specified by the property value. For macOS Application Bundles the
+content folder is ``<name>.app/Contents``. For macOS Frameworks the
+content folder is ``<name>.framework/Versions/<version>``. For macOS
+CFBundles the content folder is ``<name>.bundle/Contents`` (unless the
+extension is changed). See the :prop_tgt:`PUBLIC_HEADER`,
+:prop_tgt:`PRIVATE_HEADER`, and :prop_tgt:`RESOURCE` target properties for
+specifying files meant for ``Headers``, ``PrivateHeaders``, or
+``Resources`` directories.
+
+If the specified location is equal to ``Resources``, the resulting location
+will be the same as if the :prop_tgt:`RESOURCE` property had been used. If
+the specified location is a sub-folder of ``Resources``, it will be placed
+into the respective sub-folder. Note: For iOS Apple uses a flat bundle layout
+where no ``Resources`` folder exist. Therefore CMake strips the ``Resources``
+folder name from the specified location.
diff --git a/Help/prop_sf/OBJECT_DEPENDS.rst b/Help/prop_sf/OBJECT_DEPENDS.rst
new file mode 100644
index 0000000..aaff956
--- /dev/null
+++ b/Help/prop_sf/OBJECT_DEPENDS.rst
@@ -0,0 +1,21 @@
+OBJECT_DEPENDS
+--------------
+
+Additional files on which a compiled object file depends.
+
+Specifies a :ref:`semicolon-separated list <CMake Language Lists>` of full-paths to
+files on which any object files compiled from this source file depend.
+On :ref:`Makefile Generators` and the :generator:`Ninja` generator an
+object file will be recompiled if any of the named files is newer than it.
+:ref:`Visual Studio Generators` and the :generator:`Xcode` generator
+cannot implement such compilation dependencies.
+
+This property need not be used to specify the dependency of a source
+file on a generated header file that it includes. Although the
+property was originally introduced for this purpose, it is no longer
+necessary. If the generated header file is created by a custom
+command in the same target as the source file, the automatic
+dependency scanning process will recognize the dependency. If the
+generated header file is created by another target, an inter-target
+dependency should be created with the :command:`add_dependencies`
+command (if one does not already exist due to linking relationships).
diff --git a/Help/prop_sf/OBJECT_OUTPUTS.rst b/Help/prop_sf/OBJECT_OUTPUTS.rst
new file mode 100644
index 0000000..3e799ed
--- /dev/null
+++ b/Help/prop_sf/OBJECT_OUTPUTS.rst
@@ -0,0 +1,12 @@
+OBJECT_OUTPUTS
+--------------
+
+Additional outputs for a :generator:`Ninja` or :ref:`Makefile Generators` rule.
+
+Additional outputs created by compilation of this source file. If any
+of these outputs is missing the object will be recompiled. This is
+supported only on the :generator:`Ninja` and :ref:`Makefile Generators`
+and will be ignored on other generators.
+
+This property supports
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/prop_sf/SKIP_AUTOGEN.rst b/Help/prop_sf/SKIP_AUTOGEN.rst
new file mode 100644
index 0000000..2173f59
--- /dev/null
+++ b/Help/prop_sf/SKIP_AUTOGEN.rst
@@ -0,0 +1,19 @@
+SKIP_AUTOGEN
+------------
+
+.. versionadded:: 3.8
+
+Exclude the source file from :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTOUIC` and
+:prop_tgt:`AUTORCC` processing (for Qt projects).
+
+For finer exclusion control see :prop_sf:`SKIP_AUTOMOC`,
+:prop_sf:`SKIP_AUTOUIC` and :prop_sf:`SKIP_AUTORCC`.
+
+EXAMPLE
+^^^^^^^
+
+.. code-block:: cmake
+
+ # ...
+ set_property(SOURCE file.h PROPERTY SKIP_AUTOGEN ON)
+ # ...
diff --git a/Help/prop_sf/SKIP_AUTOMOC.rst b/Help/prop_sf/SKIP_AUTOMOC.rst
new file mode 100644
index 0000000..e92cfe0
--- /dev/null
+++ b/Help/prop_sf/SKIP_AUTOMOC.rst
@@ -0,0 +1,17 @@
+SKIP_AUTOMOC
+------------
+
+.. versionadded:: 3.8
+
+Exclude the source file from :prop_tgt:`AUTOMOC` processing (for Qt projects).
+
+For broader exclusion control see :prop_sf:`SKIP_AUTOGEN`.
+
+EXAMPLE
+^^^^^^^
+
+.. code-block:: cmake
+
+ # ...
+ set_property(SOURCE file.h PROPERTY SKIP_AUTOMOC ON)
+ # ...
diff --git a/Help/prop_sf/SKIP_AUTORCC.rst b/Help/prop_sf/SKIP_AUTORCC.rst
new file mode 100644
index 0000000..2829c25
--- /dev/null
+++ b/Help/prop_sf/SKIP_AUTORCC.rst
@@ -0,0 +1,17 @@
+SKIP_AUTORCC
+------------
+
+.. versionadded:: 3.8
+
+Exclude the source file from :prop_tgt:`AUTORCC` processing (for Qt projects).
+
+For broader exclusion control see :prop_sf:`SKIP_AUTOGEN`.
+
+EXAMPLE
+^^^^^^^
+
+.. code-block:: cmake
+
+ # ...
+ set_property(SOURCE file.qrc PROPERTY SKIP_AUTORCC ON)
+ # ...
diff --git a/Help/prop_sf/SKIP_AUTOUIC.rst b/Help/prop_sf/SKIP_AUTOUIC.rst
new file mode 100644
index 0000000..ae9725a
--- /dev/null
+++ b/Help/prop_sf/SKIP_AUTOUIC.rst
@@ -0,0 +1,22 @@
+SKIP_AUTOUIC
+------------
+
+.. versionadded:: 3.8
+
+Exclude the source file from :prop_tgt:`AUTOUIC` processing (for Qt projects).
+
+:prop_sf:`SKIP_AUTOUIC` can be set on C++ header and source files and on
+``.ui`` files.
+
+For broader exclusion control see :prop_sf:`SKIP_AUTOGEN`.
+
+EXAMPLE
+^^^^^^^
+
+.. code-block:: cmake
+
+ # ...
+ set_property(SOURCE file.h PROPERTY SKIP_AUTOUIC ON)
+ set_property(SOURCE file.cpp PROPERTY SKIP_AUTOUIC ON)
+ set_property(SOURCE widget.ui PROPERTY SKIP_AUTOUIC ON)
+ # ...
diff --git a/Help/prop_sf/SKIP_PRECOMPILE_HEADERS.rst b/Help/prop_sf/SKIP_PRECOMPILE_HEADERS.rst
new file mode 100644
index 0000000..660de3f
--- /dev/null
+++ b/Help/prop_sf/SKIP_PRECOMPILE_HEADERS.rst
@@ -0,0 +1,15 @@
+SKIP_PRECOMPILE_HEADERS
+-----------------------
+
+.. versionadded:: 3.16
+
+Is this source file skipped by :prop_tgt:`PRECOMPILE_HEADERS` feature.
+
+This property helps with build problems that one would run into
+when using the :prop_tgt:`PRECOMPILE_HEADERS` feature.
+
+One example would be the usage of Objective-C (``*.m``) files, and
+Objective-C++ (``*.mm``) files, which lead to compilation failure
+because they are treated (in case of Ninja / Makefile generator)
+as C, and CXX respectively. The precompile headers are not
+compatible between languages.
diff --git a/Help/prop_sf/SKIP_UNITY_BUILD_INCLUSION.rst b/Help/prop_sf/SKIP_UNITY_BUILD_INCLUSION.rst
new file mode 100644
index 0000000..ae526ac
--- /dev/null
+++ b/Help/prop_sf/SKIP_UNITY_BUILD_INCLUSION.rst
@@ -0,0 +1,13 @@
+SKIP_UNITY_BUILD_INCLUSION
+--------------------------
+
+.. versionadded:: 3.16
+
+Setting this property to true ensures the source file will be skipped by
+unity builds when its associated target has its :prop_tgt:`UNITY_BUILD`
+property set to true. The source file will instead be compiled on its own
+in the same way as it would with unity builds disabled.
+
+This property helps with "ODR (One definition rule)" problems where combining
+a particular source file with others might lead to build errors or other
+unintended side effects.
diff --git a/Help/prop_sf/SYMBOLIC.rst b/Help/prop_sf/SYMBOLIC.rst
new file mode 100644
index 0000000..8bebe30
--- /dev/null
+++ b/Help/prop_sf/SYMBOLIC.rst
@@ -0,0 +1,8 @@
+SYMBOLIC
+--------
+
+Is this just a name for a rule.
+
+If ``SYMBOLIC`` (boolean) is set to ``True`` the build system will be informed
+that the source file is not actually created on disk but instead used
+as a symbolic name for a build rule.
diff --git a/Help/prop_sf/Swift_DEPENDENCIES_FILE.rst b/Help/prop_sf/Swift_DEPENDENCIES_FILE.rst
new file mode 100644
index 0000000..a90c7eb
--- /dev/null
+++ b/Help/prop_sf/Swift_DEPENDENCIES_FILE.rst
@@ -0,0 +1,7 @@
+Swift_DEPENDENCIES_FILE
+-----------------------
+
+.. versionadded:: 3.15
+
+This property sets the path for the Swift dependency file (swiftdeps) for the
+source. If one is not specified, it will default to ``<OBJECT>.swiftdeps``.
diff --git a/Help/prop_sf/Swift_DIAGNOSTICS_FILE.rst b/Help/prop_sf/Swift_DIAGNOSTICS_FILE.rst
new file mode 100644
index 0000000..47d5ac3
--- /dev/null
+++ b/Help/prop_sf/Swift_DIAGNOSTICS_FILE.rst
@@ -0,0 +1,6 @@
+Swift_DIAGNOSTICS_FILE
+----------------------
+
+.. versionadded:: 3.15
+
+This property controls where the Swift diagnostics are serialized.
diff --git a/Help/prop_sf/UNITY_GROUP.rst b/Help/prop_sf/UNITY_GROUP.rst
new file mode 100644
index 0000000..9c18b70
--- /dev/null
+++ b/Help/prop_sf/UNITY_GROUP.rst
@@ -0,0 +1,7 @@
+UNITY_GROUP
+-----------
+
+.. versionadded:: 3.18
+
+This property controls which *bucket* the source will be part of when
+the :prop_tgt:`UNITY_BUILD_MODE` is set to ``GROUP``.
diff --git a/Help/prop_sf/VS_COPY_TO_OUT_DIR.rst b/Help/prop_sf/VS_COPY_TO_OUT_DIR.rst
new file mode 100644
index 0000000..ebc3061
--- /dev/null
+++ b/Help/prop_sf/VS_COPY_TO_OUT_DIR.rst
@@ -0,0 +1,8 @@
+VS_COPY_TO_OUT_DIR
+------------------
+
+.. versionadded:: 3.8
+
+Sets the ``<CopyToOutputDirectory>`` tag for a source file in a
+Visual Studio project file. Valid values are ``Never``, ``Always``
+and ``PreserveNewest``.
diff --git a/Help/prop_sf/VS_CSHARP_tagname.rst b/Help/prop_sf/VS_CSHARP_tagname.rst
new file mode 100644
index 0000000..75720f8
--- /dev/null
+++ b/Help/prop_sf/VS_CSHARP_tagname.rst
@@ -0,0 +1,22 @@
+VS_CSHARP_<tagname>
+-------------------
+
+.. versionadded:: 3.8
+
+Visual Studio and CSharp source-file-specific configuration.
+
+Tell the :manual:`Visual Studio generators <cmake-generators(7)>`
+to set the source file tag ``<tagname>``
+to a given value in the generated Visual Studio CSharp
+project. Ignored on other generators and languages. This property
+can be used to define dependencies between source files or set any
+other Visual Studio specific parameters.
+
+Example usage:
+
+.. code-block:: cmake
+
+ set_source_files_property(<filename>
+ PROPERTIES
+ VS_CSHARP_DependentUpon <other file>
+ VS_CSHARP_SubType "Form")
diff --git a/Help/prop_sf/VS_DEPLOYMENT_CONTENT.rst b/Help/prop_sf/VS_DEPLOYMENT_CONTENT.rst
new file mode 100644
index 0000000..ee49b27
--- /dev/null
+++ b/Help/prop_sf/VS_DEPLOYMENT_CONTENT.rst
@@ -0,0 +1,14 @@
+VS_DEPLOYMENT_CONTENT
+---------------------
+
+.. versionadded:: 3.1
+
+Mark a source file as content for deployment with a Windows Phone or
+Windows Store application when built with a
+:manual:`Visual Studio generators <cmake-generators(7)>`.
+The value must evaluate to either ``1`` or ``0`` and may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`
+to make the choice based on the build configuration.
+The ``.vcxproj`` file entry for the source file will be
+marked either ``DeploymentContent`` or ``ExcludedFromBuild``
+for values ``1`` and ``0``, respectively.
diff --git a/Help/prop_sf/VS_DEPLOYMENT_LOCATION.rst b/Help/prop_sf/VS_DEPLOYMENT_LOCATION.rst
new file mode 100644
index 0000000..b170544
--- /dev/null
+++ b/Help/prop_sf/VS_DEPLOYMENT_LOCATION.rst
@@ -0,0 +1,11 @@
+VS_DEPLOYMENT_LOCATION
+----------------------
+
+.. versionadded:: 3.1
+
+Specifies the deployment location for a content source file with a Windows
+Phone or Windows Store application when built
+with a :manual:`Visual Studio generators <cmake-generators(7)>`.
+This property is only applicable when using :prop_sf:`VS_DEPLOYMENT_CONTENT`.
+The value represent the path relative to the app package and applies to all
+configurations.
diff --git a/Help/prop_sf/VS_INCLUDE_IN_VSIX.rst b/Help/prop_sf/VS_INCLUDE_IN_VSIX.rst
new file mode 100644
index 0000000..16c56bf
--- /dev/null
+++ b/Help/prop_sf/VS_INCLUDE_IN_VSIX.rst
@@ -0,0 +1,8 @@
+VS_INCLUDE_IN_VSIX
+------------------
+
+.. versionadded:: 3.8
+
+Boolean property to specify if the file should be included within a
+VSIX (Visual Studio Integration Extension) extension package.
+This is needed for development of Visual Studio extensions.
diff --git a/Help/prop_sf/VS_RESOURCE_GENERATOR.rst b/Help/prop_sf/VS_RESOURCE_GENERATOR.rst
new file mode 100644
index 0000000..c5bb4f6
--- /dev/null
+++ b/Help/prop_sf/VS_RESOURCE_GENERATOR.rst
@@ -0,0 +1,10 @@
+VS_RESOURCE_GENERATOR
+---------------------
+
+.. versionadded:: 3.8
+
+This property allows to specify the resource generator to be used
+on this file. It defaults to ``PublicResXFileCodeGenerator`` if
+not set.
+
+This property only applies to C# projects.
diff --git a/Help/prop_sf/VS_SETTINGS.rst b/Help/prop_sf/VS_SETTINGS.rst
new file mode 100644
index 0000000..322f5a6
--- /dev/null
+++ b/Help/prop_sf/VS_SETTINGS.rst
@@ -0,0 +1,20 @@
+VS_SETTINGS
+-----------
+
+.. versionadded:: 3.18
+
+Set any item metadata on a non-built file.
+
+Takes a list of ``Key=Value`` pairs. Tells the Visual Studio generator to set
+``Key`` to ``Value`` as item metadata on the file.
+
+For example:
+
+.. code-block:: cmake
+
+ set_property(SOURCE file.hlsl PROPERTY VS_SETTINGS "Key=Value" "Key2=Value2")
+
+will set ``Key`` to ``Value`` and ``Key2`` to ``Value2`` on the
+``file.hlsl`` item as metadata.
+
+:manual:`Generator expressions <cmake-generator-expressions(7)>` are supported.
diff --git a/Help/prop_sf/VS_SHADER_DISABLE_OPTIMIZATIONS.rst b/Help/prop_sf/VS_SHADER_DISABLE_OPTIMIZATIONS.rst
new file mode 100644
index 0000000..6fb6778
--- /dev/null
+++ b/Help/prop_sf/VS_SHADER_DISABLE_OPTIMIZATIONS.rst
@@ -0,0 +1,8 @@
+VS_SHADER_DISABLE_OPTIMIZATIONS
+-------------------------------
+
+.. versionadded:: 3.11
+
+Disable compiler optimizations for an ``.hlsl`` source file. This adds the
+``-Od`` flag to the command line for the FxCompiler tool. Specify the value
+``true`` for this property to disable compiler optimizations.
diff --git a/Help/prop_sf/VS_SHADER_ENABLE_DEBUG.rst b/Help/prop_sf/VS_SHADER_ENABLE_DEBUG.rst
new file mode 100644
index 0000000..9c8f9d7
--- /dev/null
+++ b/Help/prop_sf/VS_SHADER_ENABLE_DEBUG.rst
@@ -0,0 +1,8 @@
+VS_SHADER_ENABLE_DEBUG
+----------------------
+
+.. versionadded:: 3.11
+
+Enable debugging information for an ``.hlsl`` source file. This adds the
+``-Zi`` flag to the command line for the FxCompiler tool. Specify the value
+``true`` to generate debugging information for the compiled shader.
diff --git a/Help/prop_sf/VS_SHADER_ENTRYPOINT.rst b/Help/prop_sf/VS_SHADER_ENTRYPOINT.rst
new file mode 100644
index 0000000..4b311ba
--- /dev/null
+++ b/Help/prop_sf/VS_SHADER_ENTRYPOINT.rst
@@ -0,0 +1,7 @@
+VS_SHADER_ENTRYPOINT
+--------------------
+
+.. versionadded:: 3.1
+
+Specifies the name of the entry point for the shader of a ``.hlsl`` source
+file.
diff --git a/Help/prop_sf/VS_SHADER_FLAGS.rst b/Help/prop_sf/VS_SHADER_FLAGS.rst
new file mode 100644
index 0000000..07f8497
--- /dev/null
+++ b/Help/prop_sf/VS_SHADER_FLAGS.rst
@@ -0,0 +1,6 @@
+VS_SHADER_FLAGS
+---------------
+
+.. versionadded:: 3.2
+
+Set additional Visual Studio shader flags of a ``.hlsl`` source file.
diff --git a/Help/prop_sf/VS_SHADER_MODEL.rst b/Help/prop_sf/VS_SHADER_MODEL.rst
new file mode 100644
index 0000000..072df89
--- /dev/null
+++ b/Help/prop_sf/VS_SHADER_MODEL.rst
@@ -0,0 +1,7 @@
+VS_SHADER_MODEL
+---------------
+
+.. versionadded:: 3.1
+
+Specifies the shader model of a ``.hlsl`` source file. Some shader types can
+only be used with recent shader models
diff --git a/Help/prop_sf/VS_SHADER_OBJECT_FILE_NAME.rst b/Help/prop_sf/VS_SHADER_OBJECT_FILE_NAME.rst
new file mode 100644
index 0000000..3647a5e
--- /dev/null
+++ b/Help/prop_sf/VS_SHADER_OBJECT_FILE_NAME.rst
@@ -0,0 +1,8 @@
+VS_SHADER_OBJECT_FILE_NAME
+--------------------------
+
+.. versionadded:: 3.12
+
+Specifies a file name for the compiled shader object file for an ``.hlsl``
+source file. This adds the ``-Fo`` flag to the command line for the FxCompiler
+tool.
diff --git a/Help/prop_sf/VS_SHADER_OUTPUT_HEADER_FILE.rst b/Help/prop_sf/VS_SHADER_OUTPUT_HEADER_FILE.rst
new file mode 100644
index 0000000..4113a16
--- /dev/null
+++ b/Help/prop_sf/VS_SHADER_OUTPUT_HEADER_FILE.rst
@@ -0,0 +1,7 @@
+VS_SHADER_OUTPUT_HEADER_FILE
+----------------------------
+
+.. versionadded:: 3.10
+
+Set filename for output header file containing object code of a ``.hlsl``
+source file.
diff --git a/Help/prop_sf/VS_SHADER_TYPE.rst b/Help/prop_sf/VS_SHADER_TYPE.rst
new file mode 100644
index 0000000..3fb7e60
--- /dev/null
+++ b/Help/prop_sf/VS_SHADER_TYPE.rst
@@ -0,0 +1,6 @@
+VS_SHADER_TYPE
+--------------
+
+.. versionadded:: 3.1
+
+Set the Visual Studio shader type of a ``.hlsl`` source file.
diff --git a/Help/prop_sf/VS_SHADER_VARIABLE_NAME.rst b/Help/prop_sf/VS_SHADER_VARIABLE_NAME.rst
new file mode 100644
index 0000000..3361b40
--- /dev/null
+++ b/Help/prop_sf/VS_SHADER_VARIABLE_NAME.rst
@@ -0,0 +1,7 @@
+VS_SHADER_VARIABLE_NAME
+-----------------------
+
+.. versionadded:: 3.10
+
+Set name of variable in header file containing object code of a ``.hlsl``
+source file.
diff --git a/Help/prop_sf/VS_TOOL_OVERRIDE.rst b/Help/prop_sf/VS_TOOL_OVERRIDE.rst
new file mode 100644
index 0000000..b2f4112
--- /dev/null
+++ b/Help/prop_sf/VS_TOOL_OVERRIDE.rst
@@ -0,0 +1,7 @@
+VS_TOOL_OVERRIDE
+----------------
+
+.. versionadded:: 3.7
+
+Override the default Visual Studio tool that will be applied to the source file
+with a new tool not based on the extension of the file.
diff --git a/Help/prop_sf/VS_XAML_TYPE.rst b/Help/prop_sf/VS_XAML_TYPE.rst
new file mode 100644
index 0000000..612b07b
--- /dev/null
+++ b/Help/prop_sf/VS_XAML_TYPE.rst
@@ -0,0 +1,9 @@
+VS_XAML_TYPE
+------------
+
+.. versionadded:: 3.3
+
+Mark a Extensible Application Markup Language (XAML) source file
+as a different type than the default ``Page``.
+The most common usage would be to set the default ``App.xaml`` file as
+``ApplicationDefinition``.
diff --git a/Help/prop_sf/WRAP_EXCLUDE.rst b/Help/prop_sf/WRAP_EXCLUDE.rst
new file mode 100644
index 0000000..638ff03
--- /dev/null
+++ b/Help/prop_sf/WRAP_EXCLUDE.rst
@@ -0,0 +1,11 @@
+WRAP_EXCLUDE
+------------
+
+Exclude this source file from any code wrapping techniques.
+
+Some packages can wrap source files into alternate languages to
+provide additional functionality.
+
+For example, C++ code can be wrapped into Java or Python, using SWIG.
+If ``WRAP_EXCLUDE`` is set to ``True``, that indicates that this
+source file should not be wrapped.
diff --git a/Help/prop_sf/XCODE_EXPLICIT_FILE_TYPE.rst b/Help/prop_sf/XCODE_EXPLICIT_FILE_TYPE.rst
new file mode 100644
index 0000000..5a50d7d
--- /dev/null
+++ b/Help/prop_sf/XCODE_EXPLICIT_FILE_TYPE.rst
@@ -0,0 +1,10 @@
+XCODE_EXPLICIT_FILE_TYPE
+------------------------
+
+.. versionadded:: 3.1
+
+Set the :generator:`Xcode` ``explicitFileType`` attribute on its reference to a
+source file. CMake computes a default based on file extension but
+can be told explicitly with this property.
+
+See also :prop_sf:`XCODE_LAST_KNOWN_FILE_TYPE`.
diff --git a/Help/prop_sf/XCODE_FILE_ATTRIBUTES.rst b/Help/prop_sf/XCODE_FILE_ATTRIBUTES.rst
new file mode 100644
index 0000000..ba51e00
--- /dev/null
+++ b/Help/prop_sf/XCODE_FILE_ATTRIBUTES.rst
@@ -0,0 +1,13 @@
+XCODE_FILE_ATTRIBUTES
+---------------------
+
+.. versionadded:: 3.7
+
+Add values to the :generator:`Xcode` ``ATTRIBUTES`` setting on its reference to a
+source file. Among other things, this can be used to set the role on
+a ``.mig`` file::
+
+ set_source_files_properties(defs.mig
+ PROPERTIES
+ XCODE_FILE_ATTRIBUTES "Client;Server"
+ )
diff --git a/Help/prop_sf/XCODE_LAST_KNOWN_FILE_TYPE.rst b/Help/prop_sf/XCODE_LAST_KNOWN_FILE_TYPE.rst
new file mode 100644
index 0000000..0b84e31
--- /dev/null
+++ b/Help/prop_sf/XCODE_LAST_KNOWN_FILE_TYPE.rst
@@ -0,0 +1,11 @@
+XCODE_LAST_KNOWN_FILE_TYPE
+--------------------------
+
+.. versionadded:: 3.1
+
+Set the :generator:`Xcode` ``lastKnownFileType`` attribute on its reference to
+a source file. CMake computes a default based on file extension but
+can be told explicitly with this property.
+
+See also :prop_sf:`XCODE_EXPLICIT_FILE_TYPE`, which is preferred
+over this property if set.
diff --git a/Help/prop_test/ATTACHED_FILES.rst b/Help/prop_test/ATTACHED_FILES.rst
new file mode 100644
index 0000000..496d800
--- /dev/null
+++ b/Help/prop_test/ATTACHED_FILES.rst
@@ -0,0 +1,7 @@
+ATTACHED_FILES
+--------------
+
+Attach a list of files to a dashboard submission.
+
+Set this property to a list of files that will be encoded and
+submitted to the dashboard as an addition to the test result.
diff --git a/Help/prop_test/ATTACHED_FILES_ON_FAIL.rst b/Help/prop_test/ATTACHED_FILES_ON_FAIL.rst
new file mode 100644
index 0000000..add54b2
--- /dev/null
+++ b/Help/prop_test/ATTACHED_FILES_ON_FAIL.rst
@@ -0,0 +1,7 @@
+ATTACHED_FILES_ON_FAIL
+----------------------
+
+Attach a list of files to a dashboard submission if the test fails.
+
+Same as :prop_test:`ATTACHED_FILES`, but these files will only be
+included if the test does not pass.
diff --git a/Help/prop_test/COST.rst b/Help/prop_test/COST.rst
new file mode 100644
index 0000000..9300d7b
--- /dev/null
+++ b/Help/prop_test/COST.rst
@@ -0,0 +1,14 @@
+COST
+----
+
+This property describes the cost of a test. When parallel testing is
+enabled, tests in the test set will be run in descending order of cost.
+Projects can explicitly define the cost of a test by setting this property
+to a floating point value.
+
+When the cost of a test is not defined by the project,
+:manual:`ctest <ctest(1)>` will initially use a default cost of ``0``.
+It computes a weighted average of the cost each time a test is run and
+uses that as an improved estimate of the cost for the next run. The more
+a test is re-run in the same build directory, the more representative the
+cost should become.
diff --git a/Help/prop_test/DEPENDS.rst b/Help/prop_test/DEPENDS.rst
new file mode 100644
index 0000000..5aa36b4
--- /dev/null
+++ b/Help/prop_test/DEPENDS.rst
@@ -0,0 +1,22 @@
+DEPENDS
+-------
+
+Specifies that this test should only be run after the specified list of tests.
+
+Set this to a list of tests that must finish before this test is run. The
+results of those tests are not considered, the dependency relationship is
+purely for order of execution (i.e. it is really just a *run after*
+relationship). Consider using test fixtures with setup tests if a dependency
+with successful completion is required (see :prop_test:`FIXTURES_REQUIRED`).
+
+Examples
+~~~~~~~~
+
+.. code-block:: cmake
+
+ add_test(NAME baseTest1 ...)
+ add_test(NAME baseTest2 ...)
+ add_test(NAME dependsTest12 ...)
+
+ set_tests_properties(dependsTest12 PROPERTIES DEPENDS "baseTest1;baseTest2")
+ # dependsTest12 runs after baseTest1 and baseTest2, even if they fail
diff --git a/Help/prop_test/DISABLED.rst b/Help/prop_test/DISABLED.rst
new file mode 100644
index 0000000..cbf07a5
--- /dev/null
+++ b/Help/prop_test/DISABLED.rst
@@ -0,0 +1,17 @@
+DISABLED
+--------
+
+.. versionadded:: 3.9
+
+If set to ``True``, the test will be skipped and its status will be 'Not Run'. A
+``DISABLED`` test will not be counted in the total number of tests and its
+completion status will be reported to CDash as ``Disabled``.
+
+A ``DISABLED`` test does not participate in test fixture dependency resolution.
+If a ``DISABLED`` test has fixture requirements defined in its
+:prop_test:`FIXTURES_REQUIRED` property, it will not cause setup or cleanup
+tests for those fixtures to be added to the test set.
+
+If a test with the :prop_test:`FIXTURES_SETUP` property set is ``DISABLED``,
+the fixture behavior will be as though that setup test was passing and any test
+case requiring that fixture will still run.
diff --git a/Help/prop_test/ENVIRONMENT.rst b/Help/prop_test/ENVIRONMENT.rst
new file mode 100644
index 0000000..102c792
--- /dev/null
+++ b/Help/prop_test/ENVIRONMENT.rst
@@ -0,0 +1,9 @@
+ENVIRONMENT
+-----------
+
+Specify environment variables that should be defined for running a test.
+
+If set to a list of environment variables and values of the form
+``MYVAR=value`` those environment variables will be defined while running
+the test. The environment is restored to its previous state after the
+test is done.
diff --git a/Help/prop_test/FAIL_REGULAR_EXPRESSION.rst b/Help/prop_test/FAIL_REGULAR_EXPRESSION.rst
new file mode 100644
index 0000000..facf902
--- /dev/null
+++ b/Help/prop_test/FAIL_REGULAR_EXPRESSION.rst
@@ -0,0 +1,15 @@
+FAIL_REGULAR_EXPRESSION
+-----------------------
+
+If the output matches this regular expression the test will fail.
+
+If set, if the output matches one of specified regular expressions,
+the test will fail. Example:
+
+.. code-block:: cmake
+
+ set_tests_properties(mytest PROPERTIES
+ FAIL_REGULAR_EXPRESSION "[^a-z]Error;ERROR;Failed"
+ )
+
+``FAIL_REGULAR_EXPRESSION`` expects a list of regular expressions.
diff --git a/Help/prop_test/FIXTURES_CLEANUP.rst b/Help/prop_test/FIXTURES_CLEANUP.rst
new file mode 100644
index 0000000..aa043da
--- /dev/null
+++ b/Help/prop_test/FIXTURES_CLEANUP.rst
@@ -0,0 +1,49 @@
+FIXTURES_CLEANUP
+----------------
+
+.. versionadded:: 3.7
+
+Specifies a list of fixtures for which the test is to be treated as a cleanup
+test. These fixture names are distinct from test case names and are not
+required to have any similarity to the names of tests associated with them.
+
+Fixture cleanup tests are ordinary tests with all of the usual test
+functionality. Setting the ``FIXTURES_CLEANUP`` property for a test has two
+primary effects:
+
+- CTest will ensure the test executes after all other tests which list any of
+ the fixtures in its :prop_test:`FIXTURES_REQUIRED` property.
+
+- If CTest is asked to run only a subset of tests (e.g. using regular
+ expressions or the ``--rerun-failed`` option) and the cleanup test is not in
+ the set of tests to run, it will automatically be added if any tests in the
+ set require any fixture listed in ``FIXTURES_CLEANUP``.
+
+A cleanup test can have multiple fixtures listed in its ``FIXTURES_CLEANUP``
+property. It will execute only once for the whole CTest run, not once for each
+fixture. A fixture can also have more than one cleanup test defined. If there
+are multiple cleanup tests for a fixture, projects can control their order with
+the usual :prop_test:`DEPENDS` test property if necessary.
+
+A cleanup test is allowed to require other fixtures, but not any fixture listed
+in its ``FIXTURES_CLEANUP`` property. For example:
+
+.. code-block:: cmake
+
+ # Ok: Dependent fixture is different to cleanup
+ set_tests_properties(cleanupFoo PROPERTIES
+ FIXTURES_CLEANUP Foo
+ FIXTURES_REQUIRED Bar
+ )
+
+ # Error: cannot require same fixture as cleanup
+ set_tests_properties(cleanupFoo PROPERTIES
+ FIXTURES_CLEANUP Foo
+ FIXTURES_REQUIRED Foo
+ )
+
+Cleanup tests will execute even if setup or regular tests for that fixture fail
+or are skipped.
+
+See :prop_test:`FIXTURES_REQUIRED` for a more complete discussion of how to use
+test fixtures.
diff --git a/Help/prop_test/FIXTURES_REQUIRED.rst b/Help/prop_test/FIXTURES_REQUIRED.rst
new file mode 100644
index 0000000..d92808a
--- /dev/null
+++ b/Help/prop_test/FIXTURES_REQUIRED.rst
@@ -0,0 +1,98 @@
+FIXTURES_REQUIRED
+-----------------
+
+.. versionadded:: 3.7
+
+Specifies a list of fixtures the test requires. Fixture names are case
+sensitive and they are not required to have any similarity to test names.
+
+Fixtures are a way to attach setup and cleanup tasks to a set of tests. If a
+test requires a given fixture, then all tests marked as setup tasks for that
+fixture will be executed first (once for the whole set of tests, not once per
+test requiring the fixture). After all tests requiring a particular fixture
+have completed, CTest will ensure all tests marked as cleanup tasks for that
+fixture are then executed. Tests are marked as setup tasks with the
+:prop_test:`FIXTURES_SETUP` property and as cleanup tasks with the
+:prop_test:`FIXTURES_CLEANUP` property. If any of a fixture's setup tests fail,
+all tests listing that fixture in their ``FIXTURES_REQUIRED`` property will not
+be executed. The cleanup tests for the fixture will always be executed, even if
+some setup tests fail.
+
+When CTest is asked to execute only a subset of tests (e.g. by the use of
+regular expressions or when run with the ``--rerun-failed`` command line
+option), it will automatically add any setup or cleanup tests for fixtures
+required by any of the tests that are in the execution set. This behavior can
+be overridden with the ``-FS``, ``-FC`` and ``-FA`` command line options to
+:manual:`ctest(1)` if desired.
+
+Since setup and cleanup tasks are also tests, they can have an ordering
+specified by the :prop_test:`DEPENDS` test property just like any other tests.
+This can be exploited to implement setup or cleanup using multiple tests for a
+single fixture to modularise setup or cleanup logic.
+
+The concept of a fixture is different to that of a resource specified by
+:prop_test:`RESOURCE_LOCK`, but they may be used together. A fixture defines a
+set of tests which share setup and cleanup requirements, whereas a resource
+lock has the effect of ensuring a particular set of tests do not run in
+parallel. Some situations may need both, such as setting up a database,
+serialising test access to that database and deleting the database again at the
+end. For such cases, tests would populate both ``FIXTURES_REQUIRED`` and
+:prop_test:`RESOURCE_LOCK` to combine the two behaviours. Names used for
+:prop_test:`RESOURCE_LOCK` have no relationship with names of fixtures, so note
+that a resource lock does not imply a fixture and vice versa.
+
+Consider the following example which represents a database test scenario
+similar to that mentioned above:
+
+.. code-block:: cmake
+
+ add_test(NAME testsDone COMMAND emailResults)
+ add_test(NAME fooOnly COMMAND testFoo)
+ add_test(NAME dbOnly COMMAND testDb)
+ add_test(NAME dbWithFoo COMMAND testDbWithFoo)
+ add_test(NAME createDB COMMAND initDB)
+ add_test(NAME setupUsers COMMAND userCreation)
+ add_test(NAME cleanupDB COMMAND deleteDB)
+ add_test(NAME cleanupFoo COMMAND removeFoos)
+
+ set_tests_properties(setupUsers PROPERTIES DEPENDS createDB)
+
+ set_tests_properties(createDB PROPERTIES FIXTURES_SETUP DB)
+ set_tests_properties(setupUsers PROPERTIES FIXTURES_SETUP DB)
+ set_tests_properties(cleanupDB PROPERTIES FIXTURES_CLEANUP DB)
+ set_tests_properties(cleanupFoo PROPERTIES FIXTURES_CLEANUP Foo)
+ set_tests_properties(testsDone PROPERTIES FIXTURES_CLEANUP "DB;Foo")
+
+ set_tests_properties(fooOnly PROPERTIES FIXTURES_REQUIRED Foo)
+ set_tests_properties(dbOnly PROPERTIES FIXTURES_REQUIRED DB)
+ set_tests_properties(dbWithFoo PROPERTIES FIXTURES_REQUIRED "DB;Foo")
+
+ set_tests_properties(dbOnly dbWithFoo createDB setupUsers cleanupDB
+ PROPERTIES RESOURCE_LOCK DbAccess)
+
+Key points from this example:
+
+- Two fixtures are defined: ``DB`` and ``Foo``. Tests can require a single
+ fixture as ``fooOnly`` and ``dbOnly`` do, or they can depend on multiple
+ fixtures like ``dbWithFoo`` does.
+
+- A ``DEPENDS`` relationship is set up to ensure ``setupUsers`` happens after
+ ``createDB``, both of which are setup tests for the ``DB`` fixture and will
+ therefore be executed before the ``dbOnly`` and ``dbWithFoo`` tests
+ automatically.
+
+- No explicit ``DEPENDS`` relationships were needed to make the setup tests run
+ before or the cleanup tests run after the regular tests.
+
+- The ``Foo`` fixture has no setup tests defined, only a single cleanup test.
+
+- ``testsDone`` is a cleanup test for both the ``DB`` and ``Foo`` fixtures.
+ Therefore, it will only execute once regular tests for both fixtures have
+ finished (i.e. after ``fooOnly``, ``dbOnly`` and ``dbWithFoo``). No
+ ``DEPENDS`` relationship was specified for ``testsDone``, so it is free to
+ run before, after or concurrently with other cleanup tests for either
+ fixture.
+
+- The setup and cleanup tests never list the fixtures they are for in their own
+ ``FIXTURES_REQUIRED`` property, as that would result in a dependency on
+ themselves and be considered an error.
diff --git a/Help/prop_test/FIXTURES_SETUP.rst b/Help/prop_test/FIXTURES_SETUP.rst
new file mode 100644
index 0000000..04a09d8
--- /dev/null
+++ b/Help/prop_test/FIXTURES_SETUP.rst
@@ -0,0 +1,50 @@
+FIXTURES_SETUP
+--------------
+
+.. versionadded:: 3.7
+
+Specifies a list of fixtures for which the test is to be treated as a setup
+test. These fixture names are distinct from test case names and are not
+required to have any similarity to the names of tests associated with them.
+
+Fixture setup tests are ordinary tests with all of the usual test
+functionality. Setting the ``FIXTURES_SETUP`` property for a test has two
+primary effects:
+
+- CTest will ensure the test executes before any other test which lists the
+ fixture name(s) in its :prop_test:`FIXTURES_REQUIRED` property.
+
+- If CTest is asked to run only a subset of tests (e.g. using regular
+ expressions or the ``--rerun-failed`` option) and the setup test is not in
+ the set of tests to run, it will automatically be added if any tests in the
+ set require any fixture listed in ``FIXTURES_SETUP``.
+
+A setup test can have multiple fixtures listed in its ``FIXTURES_SETUP``
+property. It will execute only once for the whole CTest run, not once for each
+fixture. A fixture can also have more than one setup test defined. If there are
+multiple setup tests for a fixture, projects can control their order with the
+usual :prop_test:`DEPENDS` test property if necessary.
+
+A setup test is allowed to require other fixtures, but not any fixture listed
+in its ``FIXTURES_SETUP`` property. For example:
+
+.. code-block:: cmake
+
+ # Ok: dependent fixture is different to setup
+ set_tests_properties(setupFoo PROPERTIES
+ FIXTURES_SETUP Foo
+ FIXTURES_REQUIRED Bar
+ )
+
+ # Error: cannot require same fixture as setup
+ set_tests_properties(setupFoo PROPERTIES
+ FIXTURES_SETUP Foo
+ FIXTURES_REQUIRED Foo
+ )
+
+If any of a fixture's setup tests fail, none of the tests listing that fixture
+in its :prop_test:`FIXTURES_REQUIRED` property will be run. Cleanup tests will,
+however, still be executed.
+
+See :prop_test:`FIXTURES_REQUIRED` for a more complete discussion of how to use
+test fixtures.
diff --git a/Help/prop_test/LABELS.rst b/Help/prop_test/LABELS.rst
new file mode 100644
index 0000000..8d75570
--- /dev/null
+++ b/Help/prop_test/LABELS.rst
@@ -0,0 +1,6 @@
+LABELS
+------
+
+Specify a list of text labels associated with a test.
+
+The list is reported in dashboard submissions.
diff --git a/Help/prop_test/MEASUREMENT.rst b/Help/prop_test/MEASUREMENT.rst
new file mode 100644
index 0000000..de459ed
--- /dev/null
+++ b/Help/prop_test/MEASUREMENT.rst
@@ -0,0 +1,8 @@
+MEASUREMENT
+-----------
+
+Specify a ``CDASH`` measurement and value to be reported for a test.
+
+If set to a name then that name will be reported to ``CDASH`` as a named
+measurement with a value of ``1``. You may also specify a value by
+setting ``MEASUREMENT`` to ``measurement=value``.
diff --git a/Help/prop_test/PASS_REGULAR_EXPRESSION.rst b/Help/prop_test/PASS_REGULAR_EXPRESSION.rst
new file mode 100644
index 0000000..0cd6215
--- /dev/null
+++ b/Help/prop_test/PASS_REGULAR_EXPRESSION.rst
@@ -0,0 +1,16 @@
+PASS_REGULAR_EXPRESSION
+-----------------------
+
+The output must match this regular expression for the test to pass.
+
+If set, the test output will be checked against the specified regular
+expressions and at least one of the regular expressions has to match,
+otherwise the test will fail. Example:
+
+.. code-block:: cmake
+
+ set_tests_properties(mytest PROPERTIES
+ PASS_REGULAR_EXPRESSION "TestPassed;All ok"
+ )
+
+``PASS_REGULAR_EXPRESSION`` expects a list of regular expressions.
diff --git a/Help/prop_test/PROCESSORS.rst b/Help/prop_test/PROCESSORS.rst
new file mode 100644
index 0000000..a927c10
--- /dev/null
+++ b/Help/prop_test/PROCESSORS.rst
@@ -0,0 +1,16 @@
+PROCESSORS
+----------
+
+Set to specify how many process slots this test requires.
+If not set, the default is ``1`` processor.
+
+Denotes the number of processors that this test will require. This is
+typically used for MPI tests, and should be used in conjunction with
+the :command:`ctest_test` ``PARALLEL_LEVEL`` option.
+
+This will also be used to display a weighted test timing result in label and
+subproject summaries in the command line output of :manual:`ctest(1)`. The wall
+clock time for the test run will be multiplied by this property to give a
+better idea of how much cpu resource CTest allocated for the test.
+
+See also the :prop_test:`PROCESSOR_AFFINITY` test property.
diff --git a/Help/prop_test/PROCESSOR_AFFINITY.rst b/Help/prop_test/PROCESSOR_AFFINITY.rst
new file mode 100644
index 0000000..f48a69c
--- /dev/null
+++ b/Help/prop_test/PROCESSOR_AFFINITY.rst
@@ -0,0 +1,13 @@
+PROCESSOR_AFFINITY
+------------------
+
+.. versionadded:: 3.12
+
+Set to a true value to ask CTest to launch the test process with CPU affinity
+for a fixed set of processors. If enabled and supported for the current
+platform, CTest will choose a set of processors to place in the CPU affinity
+mask when launching the test process. The number of processors in the set is
+determined by the :prop_test:`PROCESSORS` test property or the number of
+processors available to CTest, whichever is smaller. The set of processors
+chosen will be disjoint from the processors assigned to other concurrently
+running tests that also have the ``PROCESSOR_AFFINITY`` property enabled.
diff --git a/Help/prop_test/REQUIRED_FILES.rst b/Help/prop_test/REQUIRED_FILES.rst
new file mode 100644
index 0000000..baf209c
--- /dev/null
+++ b/Help/prop_test/REQUIRED_FILES.rst
@@ -0,0 +1,38 @@
+REQUIRED_FILES
+--------------
+
+List of files required to run the test. The filenames are relative to the
+test :prop_test:`WORKING_DIRECTORY` unless an absolute path is specified.
+
+If set to a list of files, the test will not be run unless all of the
+files exist.
+
+Examples
+~~~~~~~~
+
+Suppose that ``test.txt`` is created by test ``baseTest`` and ``none.txt``
+does not exist:
+
+.. code-block:: cmake
+
+ add_test(NAME baseTest ...) # Assumed to create test.txt
+ add_test(NAME fileTest ...)
+
+ # The following ensures that if baseTest is successful, test.txt will
+ # have been created before fileTest is run
+ set_tests_properties(fileTest PROPERTIES
+ DEPENDS baseTest
+ REQUIRED_FILES test.txt
+ )
+
+ add_test(NAME notRunTest ...)
+
+ # The following makes notRunTest depend on two files. Nothing creates
+ # the none.txt file, so notRunTest will fail with status "Not Run".
+ set_tests_properties(notRunTest PROPERTIES
+ REQUIRED_FILES "test.txt;none.txt"
+ )
+
+The above example demonstrates how ``REQUIRED_FILES`` works, but it is not the
+most robust way to implement test ordering with failure detection. For that,
+test fixtures are a better alternative (see :prop_test:`FIXTURES_REQUIRED`).
diff --git a/Help/prop_test/RESOURCE_GROUPS.rst b/Help/prop_test/RESOURCE_GROUPS.rst
new file mode 100644
index 0000000..26c8fa2
--- /dev/null
+++ b/Help/prop_test/RESOURCE_GROUPS.rst
@@ -0,0 +1,72 @@
+RESOURCE_GROUPS
+---------------
+
+.. versionadded:: 3.16
+
+Specify resources required by a test, grouped in a way that is meaningful to
+the test. See :ref:`resource allocation <ctest-resource-allocation>`
+for more information on how this property integrates into the CTest resource
+allocation feature.
+
+The ``RESOURCE_GROUPS`` property is a :ref:`semicolon-separated list <CMake
+Language Lists>` of group descriptions. Each entry consists of an optional
+number of groups using the description followed by a series of resource
+requirements for those groups. These requirements (and the number of groups)
+are separated by commas. The resource requirements consist of the name of a
+resource type, followed by a colon, followed by an unsigned integer
+specifying the number of slots required on one resource of the given type.
+
+The ``RESOURCE_GROUPS`` property tells CTest what resources a test expects
+to use grouped in a way meaningful to the test. The test itself must read
+the :ref:`environment variables <ctest-resource-environment-variables>` to
+determine which resources have been allocated to each group. For example,
+each group may correspond to a process the test will spawn when executed.
+
+Consider the following example:
+
+.. code-block:: cmake
+
+ add_test(NAME MyTest COMMAND MyExe)
+ set_property(TEST MyTest PROPERTY RESOURCE_GROUPS
+ "2,gpus:2"
+ "gpus:4,crypto_chips:2")
+
+In this example, there are two group descriptions (implicitly separated by a
+semicolon.) The content of the first description is ``2,gpus:2``. This
+description specifies 2 groups, each of which requires 2 slots from a single
+GPU. The content of the second description is ``gpus:4,crypto_chips:2``. This
+description does not specify a group count, so a default of 1 is assumed.
+This single group requires 4 slots from a single GPU and 2 slots from a
+single cryptography chip. In total, 3 resource groups are specified for this
+test, each with its own unique requirements.
+
+Note that the number of slots following the resource type specifies slots from
+a *single* instance of the resource. If the resource group can tolerate
+receiving slots from different instances of the same resource, it can indicate
+this by splitting the specification into multiple requirements of one slot. For
+example:
+
+.. code-block:: cmake
+
+ add_test(NAME MyTest COMMAND MyExe)
+ set_property(TEST MyTest PROPERTY RESOURCE_GROUPS
+ "gpus:1,gpus:1,gpus:1,gpus:1")
+
+In this case, the single resource group indicates that it needs four GPU slots,
+all of which may come from separate GPUs (though they don't have to; CTest may
+still assign slots from the same GPU.)
+
+When CTest sets the :ref:`environment variables
+<ctest-resource-environment-variables>` for a test, it assigns a group number
+based on the group description, starting at 0 on the left and the number of
+groups minus 1 on the right. For example, in the example above, the two
+groups in the first description would have IDs of 0 and 1, and the single
+group in the second description would have an ID of 2.
+
+Both the ``RESOURCE_GROUPS`` and :prop_test:`RESOURCE_LOCK` properties serve
+similar purposes, but they are distinct and orthogonal. Resources specified by
+``RESOURCE_GROUPS`` do not affect :prop_test:`RESOURCE_LOCK`, and vice versa.
+Whereas :prop_test:`RESOURCE_LOCK` is a simpler property that is used for
+locking one global resource, ``RESOURCE_GROUPS`` is a more advanced property
+that allows multiple tests to simultaneously use multiple resources of the
+same type, specifying their requirements in a fine-grained manner.
diff --git a/Help/prop_test/RESOURCE_LOCK.rst b/Help/prop_test/RESOURCE_LOCK.rst
new file mode 100644
index 0000000..8b13a01
--- /dev/null
+++ b/Help/prop_test/RESOURCE_LOCK.rst
@@ -0,0 +1,18 @@
+RESOURCE_LOCK
+-------------
+
+Specify a list of resources that are locked by this test.
+
+If multiple tests specify the same resource lock, they are guaranteed
+not to run concurrently.
+
+See also :prop_test:`FIXTURES_REQUIRED` if the resource requires any setup or
+cleanup steps.
+
+Both the :prop_test:`RESOURCE_GROUPS` and ``RESOURCE_LOCK`` properties serve
+similar purposes, but they are distinct and orthogonal. Resources specified by
+:prop_test:`RESOURCE_GROUPS` do not affect ``RESOURCE_LOCK``, and vice versa.
+Whereas ``RESOURCE_LOCK`` is a simpler property that is used for locking one
+global resource, :prop_test:`RESOURCE_GROUPS` is a more advanced property
+that allows multiple tests to simultaneously use multiple resources of the
+same type, specifying their requirements in a fine-grained manner.
diff --git a/Help/prop_test/RUN_SERIAL.rst b/Help/prop_test/RUN_SERIAL.rst
new file mode 100644
index 0000000..ab4c542
--- /dev/null
+++ b/Help/prop_test/RUN_SERIAL.rst
@@ -0,0 +1,8 @@
+RUN_SERIAL
+----------
+
+Do not run this test in parallel with any other test.
+
+Use this option in conjunction with the ctest_test ``PARALLEL_LEVEL``
+option to specify that this test should not be run in parallel with
+any other tests.
diff --git a/Help/prop_test/SKIP_REGULAR_EXPRESSION.rst b/Help/prop_test/SKIP_REGULAR_EXPRESSION.rst
new file mode 100644
index 0000000..46c4363
--- /dev/null
+++ b/Help/prop_test/SKIP_REGULAR_EXPRESSION.rst
@@ -0,0 +1,19 @@
+SKIP_REGULAR_EXPRESSION
+-----------------------
+
+.. versionadded:: 3.16
+
+If the output matches this regular expression the test will be marked as skipped.
+
+If set, if the output matches one of specified regular expressions,
+the test will be marked as skipped. Example:
+
+.. code-block:: cmake
+
+ set_property(TEST mytest PROPERTY
+ SKIP_REGULAR_EXPRESSION "[^a-z]Skip" "SKIP" "Skipped"
+ )
+
+``SKIP_REGULAR_EXPRESSION`` expects a list of regular expressions.
+
+See also the :prop_test:`SKIP_RETURN_CODE` property.
diff --git a/Help/prop_test/SKIP_RETURN_CODE.rst b/Help/prop_test/SKIP_RETURN_CODE.rst
new file mode 100644
index 0000000..23c4c62
--- /dev/null
+++ b/Help/prop_test/SKIP_RETURN_CODE.rst
@@ -0,0 +1,12 @@
+SKIP_RETURN_CODE
+----------------
+
+Return code to mark a test as skipped.
+
+Sometimes only a test itself can determine if all requirements for the
+test are met. If such a situation should not be considered a hard failure
+a return code of the process can be specified that will mark the test as
+``Not Run`` if it is encountered. Valid values are in the range of
+0 to 255, inclusive.
+
+See also the :prop_test:`SKIP_REGULAR_EXPRESSION` property.
diff --git a/Help/prop_test/TIMEOUT.rst b/Help/prop_test/TIMEOUT.rst
new file mode 100644
index 0000000..d1cb90d
--- /dev/null
+++ b/Help/prop_test/TIMEOUT.rst
@@ -0,0 +1,9 @@
+TIMEOUT
+-------
+
+How many seconds to allow for this test.
+
+This property if set will limit a test to not take more than the
+specified number of seconds to run. If it exceeds that the test
+process will be killed and ctest will move to the next test. This
+setting takes precedence over :variable:`CTEST_TEST_TIMEOUT`.
diff --git a/Help/prop_test/TIMEOUT_AFTER_MATCH.rst b/Help/prop_test/TIMEOUT_AFTER_MATCH.rst
new file mode 100644
index 0000000..726dcab
--- /dev/null
+++ b/Help/prop_test/TIMEOUT_AFTER_MATCH.rst
@@ -0,0 +1,41 @@
+TIMEOUT_AFTER_MATCH
+-------------------
+
+.. versionadded:: 3.6
+
+Change a test's timeout duration after a matching line is encountered
+in its output.
+
+Usage
+^^^^^
+
+.. code-block:: cmake
+
+ add_test(mytest ...)
+ set_property(TEST mytest PROPERTY TIMEOUT_AFTER_MATCH "${seconds}" "${regex}")
+
+Description
+^^^^^^^^^^^
+
+Allow a test ``seconds`` to complete after ``regex`` is encountered in
+its output.
+
+When the test outputs a line that matches ``regex`` its start time is
+reset to the current time and its timeout duration is changed to
+``seconds``. Prior to this, the timeout duration is determined by the
+:prop_test:`TIMEOUT` property or the :variable:`CTEST_TEST_TIMEOUT`
+variable if either of these are set. Because the test's start time is
+reset, its execution time will not include any time that was spent
+waiting for the matching output.
+
+:prop_test:`TIMEOUT_AFTER_MATCH` is useful for avoiding spurious
+timeouts when your test must wait for some system resource to become
+available before it can execute. Set :prop_test:`TIMEOUT` to a longer
+duration that accounts for resource acquisition and use
+:prop_test:`TIMEOUT_AFTER_MATCH` to control how long the actual test
+is allowed to run.
+
+If the required resource can be controlled by CTest you should use
+:prop_test:`RESOURCE_LOCK` instead of :prop_test:`TIMEOUT_AFTER_MATCH`.
+This property should be used when only the test itself can determine
+when its required resources are available.
diff --git a/Help/prop_test/WILL_FAIL.rst b/Help/prop_test/WILL_FAIL.rst
new file mode 100644
index 0000000..f1f94a4
--- /dev/null
+++ b/Help/prop_test/WILL_FAIL.rst
@@ -0,0 +1,7 @@
+WILL_FAIL
+---------
+
+If set to true, this will invert the pass/fail flag of the test.
+
+This property can be used for tests that are expected to fail and
+return a non zero return code.
diff --git a/Help/prop_test/WORKING_DIRECTORY.rst b/Help/prop_test/WORKING_DIRECTORY.rst
new file mode 100644
index 0000000..92a0409
--- /dev/null
+++ b/Help/prop_test/WORKING_DIRECTORY.rst
@@ -0,0 +1,9 @@
+WORKING_DIRECTORY
+-----------------
+
+The directory from which the test executable will be called.
+
+If this is not set, the test will be run with the working directory set to the
+binary directory associated with where the test was created (i.e. the
+:variable:`CMAKE_CURRENT_BINARY_DIR` for where :command:`add_test` was
+called).
diff --git a/Help/prop_tgt/ADDITIONAL_CLEAN_FILES.rst b/Help/prop_tgt/ADDITIONAL_CLEAN_FILES.rst
new file mode 100644
index 0000000..dc87d23
--- /dev/null
+++ b/Help/prop_tgt/ADDITIONAL_CLEAN_FILES.rst
@@ -0,0 +1,25 @@
+ADDITIONAL_CLEAN_FILES
+----------------------
+
+.. versionadded:: 3.15
+
+A :ref:`;-list <CMake Language Lists>` of files or directories that will be
+removed as a part of the global ``clean`` target. It can be used to specify
+files and directories that are generated as part of building the target or
+that are directly associated with the target in some way (e.g. created as a
+result of running the target).
+
+For custom targets, if such files can be captured as outputs or byproducts
+instead, then that should be preferred over adding them to this property.
+If an additional clean file is used by multiple targets or isn't
+target-specific, then the :prop_dir:`ADDITIONAL_CLEAN_FILES` directory
+property may be the more appropriate property to use.
+
+Relative paths are allowed and are interpreted relative to the
+current binary directory.
+
+Contents of ``ADDITIONAL_CLEAN_FILES`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property only works for the :generator:`Ninja` and the Makefile
+generators. It is ignored by other generators.
diff --git a/Help/prop_tgt/AIX_EXPORT_ALL_SYMBOLS.rst b/Help/prop_tgt/AIX_EXPORT_ALL_SYMBOLS.rst
new file mode 100644
index 0000000..de98fdf
--- /dev/null
+++ b/Help/prop_tgt/AIX_EXPORT_ALL_SYMBOLS.rst
@@ -0,0 +1,14 @@
+AIX_EXPORT_ALL_SYMBOLS
+----------------------
+
+.. versionadded:: 3.17
+
+On AIX, CMake automatically exports all symbols from shared libraries, and
+from executables with the :prop_tgt:`ENABLE_EXPORTS` target property set.
+Explicitly disable this boolean property to suppress the behavior and
+export no symbols by default. In this case it is expected that the project
+will use other means to export some symbols.
+
+This property is initialized by the value of
+the :variable:`CMAKE_AIX_EXPORT_ALL_SYMBOLS` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/ALIASED_TARGET.rst b/Help/prop_tgt/ALIASED_TARGET.rst
new file mode 100644
index 0000000..f9e6034
--- /dev/null
+++ b/Help/prop_tgt/ALIASED_TARGET.rst
@@ -0,0 +1,7 @@
+ALIASED_TARGET
+--------------
+
+Name of target aliased by this target.
+
+If this is an :ref:`Alias Target <Alias Targets>`, this property contains
+the name of the target aliased.
diff --git a/Help/prop_tgt/ALIAS_GLOBAL.rst b/Help/prop_tgt/ALIAS_GLOBAL.rst
new file mode 100644
index 0000000..a8859c6
--- /dev/null
+++ b/Help/prop_tgt/ALIAS_GLOBAL.rst
@@ -0,0 +1,19 @@
+ALIAS_GLOBAL
+------------
+
+.. versionadded:: 3.18
+
+Read-only property indicating of whether an :ref:`ALIAS target <Alias Targets>`
+is globally visible.
+
+The boolean value of this property is ``TRUE`` for aliases to
+:ref:`IMPORTED targets <Imported Targets>` created
+with the ``GLOBAL`` options to :command:`add_executable()` or
+:command:`add_library()`, ``FALSE`` otherwise. It is undefined for
+targets built within the project.
+
+.. note::
+
+ Promoting an :ref:`IMPORTED target <Imported Targets>` from ``LOCAL``
+ to ``GLOBAL`` scope by changing the value or :prop_tgt:`IMPORTED_GLOBAL`
+ target property do not change the scope of local aliases.
diff --git a/Help/prop_tgt/ANDROID_ANT_ADDITIONAL_OPTIONS.rst b/Help/prop_tgt/ANDROID_ANT_ADDITIONAL_OPTIONS.rst
new file mode 100644
index 0000000..eceb17d
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_ANT_ADDITIONAL_OPTIONS.rst
@@ -0,0 +1,10 @@
+ANDROID_ANT_ADDITIONAL_OPTIONS
+------------------------------
+
+.. versionadded:: 3.4
+
+Set the additional options for Android Ant build system. This is
+a string value containing all command line options for the Ant build.
+This property is initialized by the value of the
+:variable:`CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS` variable if it is
+set when a target is created.
diff --git a/Help/prop_tgt/ANDROID_API.rst b/Help/prop_tgt/ANDROID_API.rst
new file mode 100644
index 0000000..7664f18
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_API.rst
@@ -0,0 +1,10 @@
+ANDROID_API
+-----------
+
+.. versionadded:: 3.1
+
+When :ref:`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio
+Edition`, this property sets the Android target API version (e.g. ``15``).
+The version number must be a positive decimal integer. This property is
+initialized by the value of the :variable:`CMAKE_ANDROID_API` variable if
+it is set when a target is created.
diff --git a/Help/prop_tgt/ANDROID_API_MIN.rst b/Help/prop_tgt/ANDROID_API_MIN.rst
new file mode 100644
index 0000000..7ca2455
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_API_MIN.rst
@@ -0,0 +1,9 @@
+ANDROID_API_MIN
+---------------
+
+.. versionadded:: 3.2
+
+Set the Android MIN API version (e.g. ``9``). The version number
+must be a positive decimal integer. This property is initialized by
+the value of the :variable:`CMAKE_ANDROID_API_MIN` variable if it is set
+when a target is created. Native code builds using this API version.
diff --git a/Help/prop_tgt/ANDROID_ARCH.rst b/Help/prop_tgt/ANDROID_ARCH.rst
new file mode 100644
index 0000000..94b76dd
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_ARCH.rst
@@ -0,0 +1,20 @@
+ANDROID_ARCH
+------------
+
+.. versionadded:: 3.4
+
+When :ref:`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio
+Edition`, this property sets the Android target architecture.
+
+This is a string property that could be set to the one of
+the following values:
+
+* ``armv7-a``: "ARMv7-A (armv7-a)"
+* ``armv7-a-hard``: "ARMv7-A, hard-float ABI (armv7-a)"
+* ``arm64-v8a``: "ARMv8-A, 64bit (arm64-v8a)"
+* ``x86``: "x86 (x86)"
+* ``x86_64``: "x86_64 (x86_64)"
+
+This property is initialized by the value of the
+:variable:`CMAKE_ANDROID_ARCH` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/ANDROID_ASSETS_DIRECTORIES.rst b/Help/prop_tgt/ANDROID_ASSETS_DIRECTORIES.rst
new file mode 100644
index 0000000..b09a8b7
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_ASSETS_DIRECTORIES.rst
@@ -0,0 +1,11 @@
+ANDROID_ASSETS_DIRECTORIES
+--------------------------
+
+.. versionadded:: 3.4
+
+Set the Android assets directories to copy into the main assets
+folder before build. This a string property that contains the
+directory paths separated by semicolon.
+This property is initialized by the value of the
+:variable:`CMAKE_ANDROID_ASSETS_DIRECTORIES` variable if it is set when
+a target is created.
diff --git a/Help/prop_tgt/ANDROID_GUI.rst b/Help/prop_tgt/ANDROID_GUI.rst
new file mode 100644
index 0000000..cc022db
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_GUI.rst
@@ -0,0 +1,17 @@
+ANDROID_GUI
+-----------
+
+.. versionadded:: 3.1
+
+When :ref:`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio
+Edition`, this property specifies whether to build an executable as an
+application package on Android.
+
+When this property is set to true the executable when built for Android
+will be created as an application package. This property is initialized
+by the value of the :variable:`CMAKE_ANDROID_GUI` variable if it is set
+when a target is created.
+
+Add the ``AndroidManifest.xml`` source file explicitly to the
+target :command:`add_executable` command invocation to specify the
+root directory of the application package source.
diff --git a/Help/prop_tgt/ANDROID_JAR_DEPENDENCIES.rst b/Help/prop_tgt/ANDROID_JAR_DEPENDENCIES.rst
new file mode 100644
index 0000000..9880daf
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_JAR_DEPENDENCIES.rst
@@ -0,0 +1,9 @@
+ANDROID_JAR_DEPENDENCIES
+------------------------
+
+.. versionadded:: 3.4
+
+Set the Android property that specifies JAR dependencies.
+This is a string value property. This property is initialized
+by the value of the :variable:`CMAKE_ANDROID_JAR_DEPENDENCIES`
+variable if it is set when a target is created.
diff --git a/Help/prop_tgt/ANDROID_JAR_DIRECTORIES.rst b/Help/prop_tgt/ANDROID_JAR_DIRECTORIES.rst
new file mode 100644
index 0000000..6fef50b
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_JAR_DIRECTORIES.rst
@@ -0,0 +1,16 @@
+ANDROID_JAR_DIRECTORIES
+-----------------------
+
+.. versionadded:: 3.4
+
+Set the Android property that specifies directories to search for
+the JAR libraries.
+
+This a string property that contains the directory paths separated by
+semicolons. This property is initialized by the value of the
+:variable:`CMAKE_ANDROID_JAR_DIRECTORIES` variable if it is set when
+a target is created.
+
+Contents of ``ANDROID_JAR_DIRECTORIES`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions.
diff --git a/Help/prop_tgt/ANDROID_JAVA_SOURCE_DIR.rst b/Help/prop_tgt/ANDROID_JAVA_SOURCE_DIR.rst
new file mode 100644
index 0000000..9ea9884
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_JAVA_SOURCE_DIR.rst
@@ -0,0 +1,10 @@
+ANDROID_JAVA_SOURCE_DIR
+-----------------------
+
+.. versionadded:: 3.4
+
+Set the Android property that defines the Java source code root directories.
+This a string property that contains the directory paths separated by semicolon.
+This property is initialized by the value of the
+:variable:`CMAKE_ANDROID_JAVA_SOURCE_DIR` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/ANDROID_NATIVE_LIB_DEPENDENCIES.rst b/Help/prop_tgt/ANDROID_NATIVE_LIB_DEPENDENCIES.rst
new file mode 100644
index 0000000..3aa741f
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_NATIVE_LIB_DEPENDENCIES.rst
@@ -0,0 +1,16 @@
+ANDROID_NATIVE_LIB_DEPENDENCIES
+-------------------------------
+
+.. versionadded:: 3.4
+
+Set the Android property that specifies the .so dependencies.
+This is a string property.
+
+This property is initialized by the value of the
+:variable:`CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES` variable if it is set
+when a target is created.
+
+Contents of ``ANDROID_NATIVE_LIB_DEPENDENCIES`` may use
+"generator expressions" with the syntax ``$<...>``. See the
+:manual:`cmake-generator-expressions(7)` manual for
+available expressions.
diff --git a/Help/prop_tgt/ANDROID_NATIVE_LIB_DIRECTORIES.rst b/Help/prop_tgt/ANDROID_NATIVE_LIB_DIRECTORIES.rst
new file mode 100644
index 0000000..98200d9
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_NATIVE_LIB_DIRECTORIES.rst
@@ -0,0 +1,18 @@
+ANDROID_NATIVE_LIB_DIRECTORIES
+------------------------------
+
+.. versionadded:: 3.4
+
+Set the Android property that specifies directories to search for the ``.so``
+libraries.
+
+This a string property that contains the directory paths separated
+by semicolons.
+
+This property is initialized by the value of the
+:variable:`CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES` variable if it is set when a
+target is created.
+
+Contents of ``ANDROID_NATIVE_LIB_DIRECTORIES`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions.
diff --git a/Help/prop_tgt/ANDROID_PROCESS_MAX.rst b/Help/prop_tgt/ANDROID_PROCESS_MAX.rst
new file mode 100644
index 0000000..0b6aba7
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_PROCESS_MAX.rst
@@ -0,0 +1,10 @@
+ANDROID_PROCESS_MAX
+-------------------
+
+.. versionadded:: 3.4
+
+Set the Android property that defines the maximum number of a
+parallel Android NDK compiler processes (e.g. ``4``).
+This property is initialized by the value of the
+:variable:`CMAKE_ANDROID_PROCESS_MAX` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/ANDROID_PROGUARD.rst b/Help/prop_tgt/ANDROID_PROGUARD.rst
new file mode 100644
index 0000000..b5ce166
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_PROGUARD.rst
@@ -0,0 +1,11 @@
+ANDROID_PROGUARD
+----------------
+
+.. versionadded:: 3.4
+
+When this property is set to true that enables the ProGuard tool to shrink,
+optimize, and obfuscate the code by removing unused code and renaming
+classes, fields, and methods with semantically obscure names.
+This property is initialized by the value of the
+:variable:`CMAKE_ANDROID_PROGUARD` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/ANDROID_PROGUARD_CONFIG_PATH.rst b/Help/prop_tgt/ANDROID_PROGUARD_CONFIG_PATH.rst
new file mode 100644
index 0000000..6ac59d8
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_PROGUARD_CONFIG_PATH.rst
@@ -0,0 +1,11 @@
+ANDROID_PROGUARD_CONFIG_PATH
+----------------------------
+
+.. versionadded:: 3.4
+
+Set the Android property that specifies the location of the ProGuard
+config file. Leave empty to use the default one.
+This a string property that contains the path to ProGuard config file.
+This property is initialized by the value of the
+:variable:`CMAKE_ANDROID_PROGUARD_CONFIG_PATH` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/ANDROID_SECURE_PROPS_PATH.rst b/Help/prop_tgt/ANDROID_SECURE_PROPS_PATH.rst
new file mode 100644
index 0000000..f2ffa2e
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_SECURE_PROPS_PATH.rst
@@ -0,0 +1,10 @@
+ANDROID_SECURE_PROPS_PATH
+-------------------------
+
+.. versionadded:: 3.4
+
+Set the Android property that states the location of the secure properties file.
+This is a string property that contains the file path.
+This property is initialized by the value of the
+:variable:`CMAKE_ANDROID_SECURE_PROPS_PATH` variable
+if it is set when a target is created.
diff --git a/Help/prop_tgt/ANDROID_SKIP_ANT_STEP.rst b/Help/prop_tgt/ANDROID_SKIP_ANT_STEP.rst
new file mode 100644
index 0000000..1a54bce
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_SKIP_ANT_STEP.rst
@@ -0,0 +1,8 @@
+ANDROID_SKIP_ANT_STEP
+---------------------
+
+.. versionadded:: 3.4
+
+Set the Android property that defines whether or not to skip the Ant build step.
+This is a boolean property initialized by the value of the
+:variable:`CMAKE_ANDROID_SKIP_ANT_STEP` variable if it is set when a target is created.
diff --git a/Help/prop_tgt/ANDROID_STL_TYPE.rst b/Help/prop_tgt/ANDROID_STL_TYPE.rst
new file mode 100644
index 0000000..c83712b
--- /dev/null
+++ b/Help/prop_tgt/ANDROID_STL_TYPE.rst
@@ -0,0 +1,29 @@
+ANDROID_STL_TYPE
+----------------
+
+.. versionadded:: 3.4
+
+When :ref:`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio
+Edition`, this property specifies the type of STL support for the project.
+This is a string property that could set to the one of the following values:
+
+``none``
+ No C++ Support
+``system``
+ Minimal C++ without STL
+``gabi++_static``
+ GAbi++ Static
+``gabi++_shared``
+ GAbi++ Shared
+``gnustl_static``
+ GNU libstdc++ Static
+``gnustl_shared``
+ GNU libstdc++ Shared
+``stlport_static``
+ STLport Static
+``stlport_shared``
+ STLport Shared
+
+This property is initialized by the value of the
+:variable:`CMAKE_ANDROID_STL_TYPE` variable if it is set when a target is
+created.
diff --git a/Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.rst b/Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.rst
new file mode 100644
index 0000000..677e06d
--- /dev/null
+++ b/Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.rst
@@ -0,0 +1,9 @@
+ARCHIVE_OUTPUT_DIRECTORY
+------------------------
+
+.. |XXX| replace:: :ref:`ARCHIVE <Archive Output Artifacts>`
+.. |xxx| replace:: archive
+.. |CMAKE_XXX_OUTPUT_DIRECTORY| replace:: :variable:`CMAKE_ARCHIVE_OUTPUT_DIRECTORY`
+.. include:: XXX_OUTPUT_DIRECTORY.txt
+
+See also the :prop_tgt:`ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>` target property.
diff --git a/Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY_CONFIG.rst
new file mode 100644
index 0000000..12f8bb7
--- /dev/null
+++ b/Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY_CONFIG.rst
@@ -0,0 +1,16 @@
+ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>
+---------------------------------
+
+Per-configuration output directory for
+:ref:`ARCHIVE <Archive Output Artifacts>` target files.
+
+This is a per-configuration version of the
+:prop_tgt:`ARCHIVE_OUTPUT_DIRECTORY` target property, but
+multi-configuration generators (VS, Xcode) do NOT append a
+per-configuration subdirectory to the specified directory. This
+property is initialized by the value of the
+:variable:`CMAKE_ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>` variable if
+it is set when a target is created.
+
+Contents of ``ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/prop_tgt/ARCHIVE_OUTPUT_NAME.rst b/Help/prop_tgt/ARCHIVE_OUTPUT_NAME.rst
new file mode 100644
index 0000000..6150193
--- /dev/null
+++ b/Help/prop_tgt/ARCHIVE_OUTPUT_NAME.rst
@@ -0,0 +1,8 @@
+ARCHIVE_OUTPUT_NAME
+-------------------
+
+.. |XXX| replace:: :ref:`ARCHIVE <Archive Output Artifacts>`
+.. |xxx| replace:: archive
+.. include:: XXX_OUTPUT_NAME.txt
+
+See also the :prop_tgt:`ARCHIVE_OUTPUT_NAME_<CONFIG>` target property.
diff --git a/Help/prop_tgt/ARCHIVE_OUTPUT_NAME_CONFIG.rst b/Help/prop_tgt/ARCHIVE_OUTPUT_NAME_CONFIG.rst
new file mode 100644
index 0000000..4f62eb9
--- /dev/null
+++ b/Help/prop_tgt/ARCHIVE_OUTPUT_NAME_CONFIG.rst
@@ -0,0 +1,8 @@
+ARCHIVE_OUTPUT_NAME_<CONFIG>
+----------------------------
+
+Per-configuration output name for
+:ref:`ARCHIVE <Archive Output Artifacts>` target files.
+
+This is the configuration-specific version of the
+:prop_tgt:`ARCHIVE_OUTPUT_NAME` target property.
diff --git a/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst b/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst
new file mode 100644
index 0000000..ff42ae8
--- /dev/null
+++ b/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst
@@ -0,0 +1,19 @@
+AUTOGEN_BUILD_DIR
+-----------------
+
+.. versionadded:: 3.9
+
+Directory where :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC`
+generate files for the target.
+
+The directory is created on demand and automatically added to the
+:prop_tgt:`ADDITIONAL_CLEAN_FILES` target property.
+
+When unset or empty the directory ``<dir>/<target-name>_autogen`` is used where
+``<dir>`` is :variable:`CMAKE_CURRENT_BINARY_DIR` and ``<target-name>``
+is :prop_tgt:`NAME`.
+
+By default :prop_tgt:`AUTOGEN_BUILD_DIR` is unset.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/prop_tgt/AUTOGEN_ORIGIN_DEPENDS.rst b/Help/prop_tgt/AUTOGEN_ORIGIN_DEPENDS.rst
new file mode 100644
index 0000000..563190a
--- /dev/null
+++ b/Help/prop_tgt/AUTOGEN_ORIGIN_DEPENDS.rst
@@ -0,0 +1,40 @@
+AUTOGEN_ORIGIN_DEPENDS
+----------------------
+
+.. versionadded:: 3.14
+
+Switch for forwarding origin target dependencies to the corresponding
+``_autogen`` target.
+
+Targets which have their :prop_tgt:`AUTOMOC` or :prop_tgt:`AUTOUIC` property
+``ON`` have a corresponding ``_autogen`` target which generates
+``moc`` and ``uic`` files. As this ``_autogen`` target is created at
+generate-time, it is not possible to define dependencies of it using
+e.g. :command:`add_dependencies`. Instead the
+:prop_tgt:`AUTOGEN_ORIGIN_DEPENDS` target property decides whether the origin
+target dependencies should be forwarded to the ``_autogen`` target or not.
+
+By default :prop_tgt:`AUTOGEN_ORIGIN_DEPENDS` is initialized from
+:variable:`CMAKE_AUTOGEN_ORIGIN_DEPENDS` which is ``ON`` by default.
+
+In total the dependencies of the ``_autogen`` target are composed from
+
+- forwarded origin target dependencies
+ (enabled by default via :prop_tgt:`AUTOGEN_ORIGIN_DEPENDS`)
+- additional user defined dependencies from :prop_tgt:`AUTOGEN_TARGET_DEPENDS`
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
+
+Note
+^^^^
+
+Disabling :prop_tgt:`AUTOGEN_ORIGIN_DEPENDS` is useful to avoid building of
+origin target dependencies when building the ``_autogen`` target only.
+This is especially interesting when a
+:variable:`global autogen target <CMAKE_GLOBAL_AUTOGEN_TARGET>` is enabled.
+
+When the ``_autogen`` target doesn't require all the origin target's
+dependencies, and :prop_tgt:`AUTOGEN_ORIGIN_DEPENDS` is disabled, it might be
+necessary to extend :prop_tgt:`AUTOGEN_TARGET_DEPENDS` to add missing
+dependencies.
diff --git a/Help/prop_tgt/AUTOGEN_PARALLEL.rst b/Help/prop_tgt/AUTOGEN_PARALLEL.rst
new file mode 100644
index 0000000..663b54e
--- /dev/null
+++ b/Help/prop_tgt/AUTOGEN_PARALLEL.rst
@@ -0,0 +1,23 @@
+AUTOGEN_PARALLEL
+----------------
+
+.. versionadded:: 3.11
+
+Number of parallel ``moc`` or ``uic`` processes to start when using
+:prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+
+The custom ``<origin>_autogen`` target starts a number of threads of which
+each one parses a source file and on demand starts a ``moc`` or ``uic``
+process. ``AUTOGEN_PARALLEL`` controls how many parallel threads
+(and therefore ``moc`` or ``uic`` processes) are started.
+
+- An empty (or unset) value or the string ``AUTO`` sets the number of
+ threads/processes to the number of physical CPUs on the host system.
+- A positive non zero integer value sets the exact thread/process count.
+- Otherwise a single thread/process is started.
+
+By default ``AUTOGEN_PARALLEL`` is initialized from
+:variable:`CMAKE_AUTOGEN_PARALLEL`.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst b/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst
new file mode 100644
index 0000000..92b52a3
--- /dev/null
+++ b/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst
@@ -0,0 +1,36 @@
+AUTOGEN_TARGET_DEPENDS
+----------------------
+
+Additional target dependencies of the corresponding ``_autogen`` target.
+
+Targets which have their :prop_tgt:`AUTOMOC` or :prop_tgt:`AUTOUIC` property
+``ON`` have a corresponding ``_autogen`` target which generates
+``moc`` and ``uic`` files. As this ``_autogen`` target is created at
+generate-time, it is not possible to define dependencies of it using
+e.g. :command:`add_dependencies`. Instead the
+:prop_tgt:`AUTOGEN_TARGET_DEPENDS` target property can be set to a
+:ref:`;-list <CMake Language Lists>` of additional dependencies for the
+``_autogen`` target. Dependencies can be target names or file names.
+
+In total the dependencies of the ``_autogen`` target are composed from
+
+- forwarded origin target dependencies
+ (enabled by default via :prop_tgt:`AUTOGEN_ORIGIN_DEPENDS`)
+- additional user defined dependencies from :prop_tgt:`AUTOGEN_TARGET_DEPENDS`
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
+
+Use cases
+^^^^^^^^^
+
+If :prop_tgt:`AUTOMOC` or :prop_tgt:`AUTOUIC` depends on a file that is either
+
+- a :prop_sf:`GENERATED` non C++ file (e.g. a :prop_sf:`GENERATED` ``.json``
+ or ``.ui`` file) or
+- a :prop_sf:`GENERATED` C++ file that isn't recognized by :prop_tgt:`AUTOMOC`
+ and :prop_tgt:`AUTOUIC` because it's skipped by :prop_sf:`SKIP_AUTOMOC`,
+ :prop_sf:`SKIP_AUTOUIC`, :prop_sf:`SKIP_AUTOGEN` or :policy:`CMP0071` or
+- a file that isn't in the origin target's sources
+
+it must be added to :prop_tgt:`AUTOGEN_TARGET_DEPENDS`.
diff --git a/Help/prop_tgt/AUTOMOC.rst b/Help/prop_tgt/AUTOMOC.rst
new file mode 100644
index 0000000..52d96e0
--- /dev/null
+++ b/Help/prop_tgt/AUTOMOC.rst
@@ -0,0 +1,248 @@
+AUTOMOC
+-------
+
+Should the target be processed with auto-moc (for Qt projects).
+
+:prop_tgt:`AUTOMOC` is a boolean specifying whether CMake will handle the Qt
+``moc`` preprocessor automatically, i.e. without having to use the
+:module:`QT4_WRAP_CPP() <FindQt4>` or ``QT5_WRAP_CPP()`` macro.
+Currently Qt4 and Qt5 are supported.
+
+This property is initialized by the value of the :variable:`CMAKE_AUTOMOC`
+variable if it is set when a target is created.
+
+When this property is set ``ON``, CMake will scan the header and
+source files at build time and invoke ``moc`` accordingly.
+
+
+Header file processing
+^^^^^^^^^^^^^^^^^^^^^^
+
+At configuration time, a list of header files that should be scanned by
+:prop_tgt:`AUTOMOC` is computed from the target's sources.
+
+- All header files in the target's sources are added to the scan list.
+- For all C++ source files ``<source_base>.<source_extension>`` in the
+ target's sources, CMake searches for
+
+ - a regular header with the same base name
+ (``<source_base>.<header_extention>``) and
+ - a private header with the same base name and a ``_p`` suffix
+ (``<source_base>_p.<header_extention>``)
+
+ and adds these to the scan list.
+
+At build time, CMake scans each unknown or modified header file from the
+list and searches for
+
+- a Qt macro from :prop_tgt:`AUTOMOC_MACRO_NAMES`,
+- additional file dependencies from the ``FILE`` argument of a
+ ``Q_PLUGIN_METADATA`` macro and
+- additional file dependencies detected by filters defined in
+ :prop_tgt:`AUTOMOC_DEPEND_FILTERS`.
+
+If a Qt macro is found, then the header will be compiled by the ``moc`` to the
+output file ``moc_<base_name>.cpp``. The complete output file path is
+described in the section `Output file location`_.
+
+The header will be ``moc`` compiled again if a file from the additional file
+dependencies changes.
+
+Header ``moc`` output files ``moc_<base_name>.cpp`` can be included in source
+files. In the section `Including header moc files in sources`_ there is more
+information on that topic.
+
+
+Source file processing
+^^^^^^^^^^^^^^^^^^^^^^
+
+At build time, CMake scans each unknown or modified C++ source file from the
+target's sources for
+
+- a Qt macro from :prop_tgt:`AUTOMOC_MACRO_NAMES`,
+- includes of header ``moc`` files
+ (see `Including header moc files in sources`_),
+- additional file dependencies from the ``FILE`` argument of a
+ ``Q_PLUGIN_METADATA`` macro and
+- additional file dependencies detected by filters defined in
+ :prop_tgt:`AUTOMOC_DEPEND_FILTERS`.
+
+If a Qt macro is found, then the C++ source file
+``<base>.<source_extension>`` is expected to as well contain an include
+statement
+
+.. code-block:: c++
+
+ #include <<base>.moc> // or
+ #include "<base>.moc"
+
+The source file then will be compiled by the ``moc`` to the output file
+``<base>.moc``. A description of the complete output file path is in section
+`Output file location`_.
+
+The source will be ``moc`` compiled again if a file from the additional file
+dependencies changes.
+
+Including header moc files in sources
+"""""""""""""""""""""""""""""""""""""
+
+A source file can include the ``moc`` output file of a header
+``<header_base>.<header_extension>`` by using an include statement of
+the form
+
+.. code-block:: c++
+
+ #include <moc_<header_base>.cpp> // or
+ #include "moc_<header_base>.cpp"
+
+If the ``moc`` output file of a header is included by a source, it will
+be generated in a different location than if it was not included. This is
+described in the section `Output file location`_.
+
+
+Output file location
+^^^^^^^^^^^^^^^^^^^^
+
+Included moc output files
+"""""""""""""""""""""""""
+
+``moc`` output files that are included by a source file will be generated in
+
+- ``<AUTOGEN_BUILD_DIR>/include``
+ for single configuration generators or in
+- ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>``
+ for :prop_gbl:`multi configuration <GENERATOR_IS_MULTI_CONFIG>` generators.
+
+Where ``<AUTOGEN_BUILD_DIR>`` is the value of the target property
+:prop_tgt:`AUTOGEN_BUILD_DIR`.
+
+The include directory is automatically added to the target's
+:prop_tgt:`INCLUDE_DIRECTORIES`.
+
+Not included moc output files
+"""""""""""""""""""""""""""""
+
+``moc`` output files that are not included in a source file will be generated
+in
+
+- ``<AUTOGEN_BUILD_DIR>/<SOURCE_DIR_CHECKSUM>``
+ for single configuration generators or in,
+- ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>/<SOURCE_DIR_CHECKSUM>``
+ for :prop_gbl:`multi configuration <GENERATOR_IS_MULTI_CONFIG>` generators.
+
+Where ``<SOURCE_DIR_CHECKSUM>`` is a checksum computed from the relative
+parent directory path of the ``moc`` input file. This scheme allows to have
+``moc`` input files with the same name in different directories.
+
+All not included ``moc`` output files will be included automatically by the
+CMake generated file
+
+- ``<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp``, or
+- ``<AUTOGEN_BUILD_DIR>/mocs_compilation_$<CONFIG>.cpp``,
+
+which is added to the target's sources.
+
+
+Qt version detection
+^^^^^^^^^^^^^^^^^^^^
+
+:prop_tgt:`AUTOMOC` enabled targets need to know the Qt major and minor
+version they're working with. The major version usually is provided by the
+``INTERFACE_QT_MAJOR_VERSION`` property of the ``Qt[45]Core`` library,
+that the target links to. To find the minor version, CMake builds a list of
+available Qt versions from
+
+- ``Qt5Core_VERSION_MAJOR`` and ``Qt5Core_VERSION_MINOR`` variables
+ (usually set by ``find_package(Qt5...)``)
+- ``Qt5Core_VERSION_MAJOR`` and ``Qt5Core_VERSION_MINOR`` directory properties
+- ``QT_VERSION_MAJOR`` and ``QT_VERSION_MINOR`` variables
+ (usually set by ``find_package(Qt4...)``)
+- ``QT_VERSION_MAJOR`` and ``QT_VERSION_MINOR`` directory properties
+
+in the context of the :command:`add_executable` or :command:`add_library` call.
+
+Assumed ``INTERFACE_QT_MAJOR_VERSION`` is a valid number, the first
+entry in the list with a matching major version is taken. If no matching major
+version was found, an error is generated.
+If ``INTERFACE_QT_MAJOR_VERSION`` is not a valid number, the first
+entry in the list is taken.
+
+A ``find_package(Qt[45]...)`` call sets the ``QT/Qt5Core_VERSION_MAJOR/MINOR``
+variables. If the call is in a different context than the
+:command:`add_executable` or :command:`add_library` call, e.g. in a function,
+then the version variables might not be available to the :prop_tgt:`AUTOMOC`
+enabled target.
+In that case the version variables can be forwarded from the
+``find_package(Qt[45]...)`` calling context to the :command:`add_executable`
+or :command:`add_library` calling context as directory properties.
+The following Qt5 example demonstrates the procedure.
+
+.. code-block:: cmake
+
+ function (add_qt5_client)
+ find_package(Qt5 REQUIRED QUIET COMPONENTS Core Widgets)
+ ...
+ set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ PROPERTY Qt5Core_VERSION_MAJOR "${Qt5Core_VERSION_MAJOR}")
+ set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ PROPERTY Qt5Core_VERSION_MINOR "${Qt5Core_VERSION_MAJOR}")
+ ...
+ endfunction ()
+ ...
+ add_qt5_client()
+ add_executable(myTarget main.cpp)
+ target_link_libraries(myTarget Qt5::QtWidgets)
+ set_property(TARGET myTarget PROPERTY AUTOMOC ON)
+
+
+Modifiers
+^^^^^^^^^
+
+:prop_tgt:`AUTOMOC_EXECUTABLE`:
+The ``moc`` executable will be detected automatically, but can be forced to
+a certain binary using this target property.
+
+:prop_tgt:`AUTOMOC_MOC_OPTIONS`:
+Additional command line options for ``moc`` can be set in this target property.
+
+:prop_tgt:`AUTOMOC_MACRO_NAMES`:
+This list of Qt macro names can be extended to search for additional macros in
+headers and sources.
+
+:prop_tgt:`AUTOMOC_DEPEND_FILTERS`:
+``moc`` dependency file names can be extracted from headers or sources by
+defining file name filters in this target property.
+
+:prop_tgt:`AUTOMOC_COMPILER_PREDEFINES`:
+Compiler pre definitions for ``moc`` are written to the ``moc_predefs.h`` file.
+The generation of this file can be enabled or disabled in this target property.
+
+:prop_sf:`SKIP_AUTOMOC`:
+Sources and headers can be excluded from :prop_tgt:`AUTOMOC` processing by
+setting this source file property.
+
+:prop_sf:`SKIP_AUTOGEN`:
+Source files can be excluded from :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC` processing by
+setting this source file property.
+
+:prop_gbl:`AUTOGEN_SOURCE_GROUP`:
+This global property can be used to group files generated by
+:prop_tgt:`AUTOMOC` or :prop_tgt:`AUTORCC` together in an IDE, e.g. in MSVS.
+
+:prop_gbl:`AUTOGEN_TARGETS_FOLDER`:
+This global property can be used to group :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC` targets together in an IDE,
+e.g. in MSVS.
+
+:variable:`CMAKE_GLOBAL_AUTOGEN_TARGET`:
+A global ``autogen`` target, that depends on all :prop_tgt:`AUTOMOC` or
+:prop_tgt:`AUTOUIC` generated ``<ORIGIN>_autogen`` targets in the project,
+will be generated when this variable is ``ON``.
+
+:prop_tgt:`AUTOGEN_PARALLEL`:
+This target property controls the number of ``moc`` or ``uic`` processes to
+start in parallel during builds.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/prop_tgt/AUTOMOC_COMPILER_PREDEFINES.rst b/Help/prop_tgt/AUTOMOC_COMPILER_PREDEFINES.rst
new file mode 100644
index 0000000..8998284
--- /dev/null
+++ b/Help/prop_tgt/AUTOMOC_COMPILER_PREDEFINES.rst
@@ -0,0 +1,26 @@
+AUTOMOC_COMPILER_PREDEFINES
+---------------------------
+
+.. versionadded:: 3.10
+
+Boolean value used by :prop_tgt:`AUTOMOC` to determine if the
+compiler pre definitions file ``moc_predefs.h`` should be generated.
+
+CMake generates a ``moc_predefs.h`` file with compiler pre definitions
+from the output of the command defined in
+:variable:`CMAKE_CXX_COMPILER_PREDEFINES_COMMAND <CMAKE_<LANG>_COMPILER_PREDEFINES_COMMAND>`
+when
+
+- :prop_tgt:`AUTOMOC` is enabled,
+- :prop_tgt:`AUTOMOC_COMPILER_PREDEFINES` is enabled,
+- :variable:`CMAKE_CXX_COMPILER_PREDEFINES_COMMAND <CMAKE_<LANG>_COMPILER_PREDEFINES_COMMAND>` isn't empty and
+- the Qt version is greater or equal 5.8.
+
+The ``moc_predefs.h`` file, which is generated in :prop_tgt:`AUTOGEN_BUILD_DIR`,
+is passed to ``moc`` as the argument to the ``--include`` option.
+
+By default :prop_tgt:`AUTOMOC_COMPILER_PREDEFINES` is initialized from
+:variable:`CMAKE_AUTOMOC_COMPILER_PREDEFINES`, which is ON by default.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/prop_tgt/AUTOMOC_DEPEND_FILTERS.rst b/Help/prop_tgt/AUTOMOC_DEPEND_FILTERS.rst
new file mode 100644
index 0000000..1f31700
--- /dev/null
+++ b/Help/prop_tgt/AUTOMOC_DEPEND_FILTERS.rst
@@ -0,0 +1,109 @@
+AUTOMOC_DEPEND_FILTERS
+----------------------
+
+.. versionadded:: 3.9
+
+Filter definitions used by :prop_tgt:`AUTOMOC` to extract file names from a
+source file that are registered as additional dependencies for the
+``moc`` file of the source file.
+
+Filters are defined as ``KEYWORD;REGULAR_EXPRESSION`` pairs. First the file
+content is searched for ``KEYWORD``. If it is found at least once, then file
+names are extracted by successively searching for ``REGULAR_EXPRESSION`` and
+taking the first match group.
+
+The file name found in the first match group is searched for
+
+- first in the vicinity of the source file
+- and afterwards in the target's :prop_tgt:`INCLUDE_DIRECTORIES`.
+
+If any of the extracted files changes, then the ``moc`` file for the source
+file gets rebuilt even when the source file itself doesn't change.
+
+If any of the extracted files is :prop_sf:`GENERATED` or if it is not in the
+target's sources, then it might be necessary to add it to the
+``_autogen`` target dependencies.
+See :prop_tgt:`AUTOGEN_TARGET_DEPENDS` for reference.
+
+By default :prop_tgt:`AUTOMOC_DEPEND_FILTERS` is initialized from
+:variable:`CMAKE_AUTOMOC_DEPEND_FILTERS`, which is empty by default.
+
+From Qt 5.15.0 on this variable is ignored as moc is able to output the correct
+dependencies.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
+
+
+Example 1
+^^^^^^^^^
+
+A header file ``my_class.hpp`` uses a custom macro ``JSON_FILE_MACRO`` which
+is defined in an other header ``macros.hpp``.
+We want the ``moc`` file of ``my_class.hpp`` to depend on the file name
+argument of ``JSON_FILE_MACRO``::
+
+ // my_class.hpp
+ class My_Class : public QObject
+ {
+ Q_OBJECT
+ JSON_FILE_MACRO ( "info.json" )
+ ...
+ };
+
+In ``CMakeLists.txt`` we add a filter to
+:variable:`CMAKE_AUTOMOC_DEPEND_FILTERS` like this::
+
+ list( APPEND CMAKE_AUTOMOC_DEPEND_FILTERS
+ "JSON_FILE_MACRO"
+ "[\n][ \t]*JSON_FILE_MACRO[ \t]*\\([ \t]*\"([^\"]+)\""
+ )
+
+We assume ``info.json`` is a plain (not :prop_sf:`GENERATED`) file that is
+listed in the target's source. Therefore we do not need to add it to
+:prop_tgt:`AUTOGEN_TARGET_DEPENDS`.
+
+Example 2
+^^^^^^^^^
+
+In the target ``my_target`` a header file ``complex_class.hpp`` uses a
+custom macro ``JSON_BASED_CLASS`` which is defined in an other header
+``macros.hpp``::
+
+ // macros.hpp
+ ...
+ #define JSON_BASED_CLASS(name, json) \
+ class name : public QObject \
+ { \
+ Q_OBJECT \
+ Q_PLUGIN_METADATA(IID "demo" FILE json) \
+ name() {} \
+ };
+ ...
+
+::
+
+ // complex_class.hpp
+ #pragma once
+ JSON_BASED_CLASS(Complex_Class, "meta.json")
+ // end of file
+
+Since ``complex_class.hpp`` doesn't contain a ``Q_OBJECT`` macro it would be
+ignored by :prop_tgt:`AUTOMOC`. We change this by adding ``JSON_BASED_CLASS``
+to :variable:`CMAKE_AUTOMOC_MACRO_NAMES`::
+
+ list(APPEND CMAKE_AUTOMOC_MACRO_NAMES "JSON_BASED_CLASS")
+
+We want the ``moc`` file of ``complex_class.hpp`` to depend on
+``meta.json``. So we add a filter to
+:variable:`CMAKE_AUTOMOC_DEPEND_FILTERS`::
+
+ list(APPEND CMAKE_AUTOMOC_DEPEND_FILTERS
+ "JSON_BASED_CLASS"
+ "[\n^][ \t]*JSON_BASED_CLASS[ \t]*\\([^,]*,[ \t]*\"([^\"]+)\""
+ )
+
+Additionally we assume ``meta.json`` is :prop_sf:`GENERATED` which is
+why we have to add it to :prop_tgt:`AUTOGEN_TARGET_DEPENDS`::
+
+ set_property(TARGET my_target APPEND PROPERTY AUTOGEN_TARGET_DEPENDS "meta.json")
diff --git a/Help/prop_tgt/AUTOMOC_EXECUTABLE.rst b/Help/prop_tgt/AUTOMOC_EXECUTABLE.rst
new file mode 100644
index 0000000..f4b8396
--- /dev/null
+++ b/Help/prop_tgt/AUTOMOC_EXECUTABLE.rst
@@ -0,0 +1,17 @@
+AUTOMOC_EXECUTABLE
+------------------
+
+.. versionadded:: 3.14
+
+:prop_tgt:`AUTOMOC_EXECUTABLE` is file path pointing to the ``moc``
+executable to use for :prop_tgt:`AUTOMOC` enabled files. Setting
+this property will make CMake skip the automatic detection of the
+``moc`` binary as well as the sanity-tests normally run to ensure
+that the binary is available and working as expected.
+
+Usually this property does not need to be set. Only consider this
+property if auto-detection of ``moc`` can not work -- e.g. because
+you are building the ``moc`` binary as part of your project.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/prop_tgt/AUTOMOC_MACRO_NAMES.rst b/Help/prop_tgt/AUTOMOC_MACRO_NAMES.rst
new file mode 100644
index 0000000..a53810d
--- /dev/null
+++ b/Help/prop_tgt/AUTOMOC_MACRO_NAMES.rst
@@ -0,0 +1,34 @@
+AUTOMOC_MACRO_NAMES
+-------------------
+
+.. versionadded:: 3.10
+
+A :ref:`semicolon-separated list <CMake Language Lists>` list of macro names used by
+:prop_tgt:`AUTOMOC` to determine if a C++ file needs to be processed by ``moc``.
+
+This property is only used if the :prop_tgt:`AUTOMOC` property is ``ON``
+for this target.
+
+When running :prop_tgt:`AUTOMOC`, CMake searches for the strings listed in
+:prop_tgt:`AUTOMOC_MACRO_NAMES` in C++ source and header files.
+If any of the strings is found
+
+- as the first non space string on a new line or
+- as the first non space string after a ``{`` on a new line,
+
+then the file will be processed by ``moc``.
+
+By default :prop_tgt:`AUTOMOC_MACRO_NAMES` is initialized from
+:variable:`CMAKE_AUTOMOC_MACRO_NAMES`.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
+
+Example
+^^^^^^^
+
+In this case the ``Q_OBJECT`` macro is hidden inside another macro
+called ``CUSTOM_MACRO``. To let CMake know that source files that contain
+``CUSTOM_MACRO`` need to be ``moc`` processed, we call::
+
+ set_property(TARGET tgt APPEND PROPERTY AUTOMOC_MACRO_NAMES "CUSTOM_MACRO")
diff --git a/Help/prop_tgt/AUTOMOC_MOC_OPTIONS.rst b/Help/prop_tgt/AUTOMOC_MOC_OPTIONS.rst
new file mode 100644
index 0000000..330849b
--- /dev/null
+++ b/Help/prop_tgt/AUTOMOC_MOC_OPTIONS.rst
@@ -0,0 +1,17 @@
+AUTOMOC_MOC_OPTIONS
+-------------------
+
+Additional options for ``moc`` when using :prop_tgt:`AUTOMOC`
+
+This property is only used if the :prop_tgt:`AUTOMOC` property is ``ON``
+for this target. In this case, it holds additional command line
+options which will be used when ``moc`` is executed during the build, i.e.
+it is equivalent to the optional ``OPTIONS`` argument of the
+:module:`qt4_wrap_cpp() <FindQt4>` macro.
+
+This property is initialized by the value of the
+:variable:`CMAKE_AUTOMOC_MOC_OPTIONS` variable if it is set when a target
+is created, or an empty string otherwise.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst b/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst
new file mode 100644
index 0000000..836d953
--- /dev/null
+++ b/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst
@@ -0,0 +1,33 @@
+AUTOMOC_PATH_PREFIX
+-------------------
+
+.. versionadded:: 3.16
+
+When this property is ``ON``, CMake will generate the ``-p`` path prefix
+option for ``moc`` on :prop_tgt:`AUTOMOC` enabled Qt targets.
+
+To generate the path prefix, CMake tests if the header compiled by ``moc``
+is in any of the target
+:command:`include directories <target_include_directories>`. If so, CMake will
+compute the relative path accordingly. If the header is not in the
+:command:`include directories <target_include_directories>`, CMake will omit
+the ``-p`` path prefix option. ``moc`` usually generates a
+relative include path in that case.
+
+:prop_tgt:`AUTOMOC_PATH_PREFIX` is initialized from the variable
+:variable:`CMAKE_AUTOMOC_PATH_PREFIX`, which is ``OFF`` by default.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
+
+Reproducible builds
+^^^^^^^^^^^^^^^^^^^
+
+For reproducible builds it is recommended to keep headers that are ``moc``
+compiled in one of the target
+:command:`include directories <target_include_directories>` and set
+:prop_tgt:`AUTOMOC_PATH_PREFIX` to ``ON``. This ensures that:
+
+- ``moc`` output files are identical on different build setups,
+- ``moc`` output files will compile correctly when the source and/or
+ build directory is a symbolic link.
diff --git a/Help/prop_tgt/AUTORCC.rst b/Help/prop_tgt/AUTORCC.rst
new file mode 100644
index 0000000..9a98f44
--- /dev/null
+++ b/Help/prop_tgt/AUTORCC.rst
@@ -0,0 +1,62 @@
+AUTORCC
+-------
+
+Should the target be processed with auto-rcc (for Qt projects).
+
+:prop_tgt:`AUTORCC` is a boolean specifying whether CMake will handle
+the Qt ``rcc`` code generator automatically, i.e. without having to use
+the :module:`QT4_ADD_RESOURCES() <FindQt4>` or ``QT5_ADD_RESOURCES()``
+macro. Currently Qt4 and Qt5 are supported.
+
+When this property is ``ON``, CMake will handle ``.qrc`` files added
+as target sources at build time and invoke ``rcc`` accordingly.
+This property is initialized by the value of the :variable:`CMAKE_AUTORCC`
+variable if it is set when a target is created.
+
+By default :prop_tgt:`AUTORCC` is processed by a
+:command:`custom command <add_custom_command>`.
+If the ``.qrc`` file is :prop_sf:`GENERATED`, a
+:command:`custom target <add_custom_target>` is used instead.
+
+When there are multiple ``.qrc`` files with the same name, CMake will
+generate unspecified unique output file names for ``rcc``. Therefore, if
+``Q_INIT_RESOURCE()`` or ``Q_CLEANUP_RESOURCE()`` need to be used, the
+``.qrc`` file name must be unique.
+
+
+Modifiers
+^^^^^^^^^
+
+:prop_tgt:`AUTORCC_EXECUTABLE`:
+The ``rcc`` executable will be detected automatically, but can be forced to
+a certain binary by setting this target property.
+
+:prop_tgt:`AUTORCC_OPTIONS`:
+Additional command line options for ``rcc`` can be set via this target
+property. The corresponding :prop_sf:`AUTORCC_OPTIONS` source file property
+can be used to specify options to be applied only to a specific ``.qrc`` file.
+
+:prop_sf:`SKIP_AUTORCC`:
+``.qrc`` files can be excluded from :prop_tgt:`AUTORCC` processing by
+setting this source file property.
+
+:prop_sf:`SKIP_AUTOGEN`:
+Source files can be excluded from :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC` processing by
+setting this source file property.
+
+:prop_gbl:`AUTOGEN_SOURCE_GROUP`:
+This global property can be used to group files generated by
+:prop_tgt:`AUTOMOC` or :prop_tgt:`AUTORCC` together in an IDE, e.g. in MSVS.
+
+:prop_gbl:`AUTOGEN_TARGETS_FOLDER`:
+This global property can be used to group :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC` targets together in an IDE,
+e.g. in MSVS.
+
+:variable:`CMAKE_GLOBAL_AUTORCC_TARGET`:
+A global ``autorcc`` target that depends on all :prop_tgt:`AUTORCC` targets
+in the project will be generated when this variable is ``ON``.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/prop_tgt/AUTORCC_EXECUTABLE.rst b/Help/prop_tgt/AUTORCC_EXECUTABLE.rst
new file mode 100644
index 0000000..4f85fba
--- /dev/null
+++ b/Help/prop_tgt/AUTORCC_EXECUTABLE.rst
@@ -0,0 +1,17 @@
+AUTORCC_EXECUTABLE
+------------------
+
+.. versionadded:: 3.14
+
+:prop_tgt:`AUTORCC_EXECUTABLE` is file path pointing to the ``rcc``
+executable to use for :prop_tgt:`AUTORCC` enabled files. Setting
+this property will make CMake skip the automatic detection of the
+``rcc`` binary as well as the sanity-tests normally run to ensure
+that the binary is available and working as expected.
+
+Usually this property does not need to be set. Only consider this
+property if auto-detection of ``rcc`` can not work -- e.g. because
+you are building the ``rcc`` binary as part of your project.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/prop_tgt/AUTORCC_OPTIONS.rst b/Help/prop_tgt/AUTORCC_OPTIONS.rst
new file mode 100644
index 0000000..5261aff
--- /dev/null
+++ b/Help/prop_tgt/AUTORCC_OPTIONS.rst
@@ -0,0 +1,28 @@
+AUTORCC_OPTIONS
+---------------
+
+Additional options for ``rcc`` when using :prop_tgt:`AUTORCC`
+
+This property holds additional command line options which will be used
+when ``rcc`` is executed during the build via :prop_tgt:`AUTORCC`,
+i.e. it is equivalent to the optional ``OPTIONS`` argument of the
+:module:`qt4_add_resources() <FindQt4>` macro.
+
+This property is initialized by the value of the
+:variable:`CMAKE_AUTORCC_OPTIONS` variable if it is set when a target is
+created, or an empty string otherwise.
+
+The options set on the target may be overridden by :prop_sf:`AUTORCC_OPTIONS`
+set on the ``.qrc`` source file.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
+
+EXAMPLE
+^^^^^^^
+
+.. code-block:: cmake
+
+ # ...
+ set_property(TARGET tgt PROPERTY AUTORCC_OPTIONS "--compress;9")
+ # ...
diff --git a/Help/prop_tgt/AUTOUIC.rst b/Help/prop_tgt/AUTOUIC.rst
new file mode 100644
index 0000000..cd24f5e
--- /dev/null
+++ b/Help/prop_tgt/AUTOUIC.rst
@@ -0,0 +1,85 @@
+AUTOUIC
+-------
+
+Should the target be processed with auto-uic (for Qt projects).
+
+:prop_tgt:`AUTOUIC` is a boolean specifying whether CMake will handle
+the Qt ``uic`` code generator automatically, i.e. without having to use
+the :module:`QT4_WRAP_UI() <FindQt4>` or ``QT5_WRAP_UI()`` macro. Currently
+Qt4 and Qt5 are supported.
+
+This property is initialized by the value of the :variable:`CMAKE_AUTOUIC`
+variable if it is set when a target is created.
+
+When this property is ``ON``, CMake will scan the header and source files at
+build time and invoke ``uic`` accordingly.
+
+
+Header and source file processing
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+At build time, CMake scans each header and source file from the
+target's sources for include statements of the form
+
+.. code-block:: c++
+
+ #include "ui_<ui_base>.h"
+
+Once such an include statement is found in a file, CMake searches for the
+``uic`` input file ``<ui_base>.ui``
+
+- in the vicinity of the file and
+- in the :prop_tgt:`AUTOUIC_SEARCH_PATHS` of the target.
+
+If the ``<ui_base>.ui`` file was found, ``uic`` is called on it to generate
+``ui_<ui_base>.h`` in the directory
+
+- ``<AUTOGEN_BUILD_DIR>/include`` for single configuration generators or in
+- ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>`` for
+ :prop_gbl:`multi configuration <GENERATOR_IS_MULTI_CONFIG>` generators.
+
+Where ``<AUTOGEN_BUILD_DIR>`` is the value of the target property
+:prop_tgt:`AUTOGEN_BUILD_DIR`.
+
+The include directory is automatically added to the target's
+:prop_tgt:`INCLUDE_DIRECTORIES`.
+
+
+Modifiers
+^^^^^^^^^
+
+:prop_tgt:`AUTOUIC_EXECUTABLE`:
+The ``uic`` executable will be detected automatically, but can be forced to
+a certain binary using this target property.
+
+:prop_tgt:`AUTOUIC_OPTIONS`:
+Additional command line options for ``uic`` can be set via this target
+property. The corresponding :prop_sf:`AUTOUIC_OPTIONS` source file property
+can be used to specify options to be applied only to a specific
+``<base_name>.ui`` file.
+
+:prop_sf:`SKIP_AUTOUIC`:
+Source files can be excluded from :prop_tgt:`AUTOUIC` processing by setting
+this source file property.
+
+:prop_sf:`SKIP_AUTOGEN`:
+Source files can be excluded from :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC` processing by
+setting this source file property.
+
+:prop_gbl:`AUTOGEN_TARGETS_FOLDER`:
+This global property can be used to group :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC` targets together in an IDE,
+e.g. in MSVS.
+
+:variable:`CMAKE_GLOBAL_AUTOGEN_TARGET`:
+A global ``autogen`` target, that depends on all :prop_tgt:`AUTOMOC` or
+:prop_tgt:`AUTOUIC` generated ``<ORIGIN>_autogen`` targets in the project,
+will be generated when this variable is ``ON``.
+
+:prop_tgt:`AUTOGEN_PARALLEL`:
+This target property controls the number of ``moc`` or ``uic`` processes to
+start in parallel during builds.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/prop_tgt/AUTOUIC_EXECUTABLE.rst b/Help/prop_tgt/AUTOUIC_EXECUTABLE.rst
new file mode 100644
index 0000000..5966326
--- /dev/null
+++ b/Help/prop_tgt/AUTOUIC_EXECUTABLE.rst
@@ -0,0 +1,17 @@
+AUTOUIC_EXECUTABLE
+------------------
+
+.. versionadded:: 3.14
+
+:prop_tgt:`AUTOUIC_EXECUTABLE` is file path pointing to the ``uic``
+executable to use for :prop_tgt:`AUTOUIC` enabled files. Setting
+this property will make CMake skip the automatic detection of the
+``uic`` binary as well as the sanity-tests normally run to ensure
+that the binary is available and working as expected.
+
+Usually this property does not need to be set. Only consider this
+property if auto-detection of ``uic`` can not work -- e.g. because
+you are building the ``uic`` binary as part of your project.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/prop_tgt/AUTOUIC_OPTIONS.rst b/Help/prop_tgt/AUTOUIC_OPTIONS.rst
new file mode 100644
index 0000000..425ea1c
--- /dev/null
+++ b/Help/prop_tgt/AUTOUIC_OPTIONS.rst
@@ -0,0 +1,32 @@
+AUTOUIC_OPTIONS
+---------------
+
+Additional options for ``uic`` when using :prop_tgt:`AUTOUIC`
+
+This property holds additional command line options which will be used when
+``uic`` is executed during the build via :prop_tgt:`AUTOUIC`, i.e. it is
+equivalent to the optional ``OPTIONS`` argument of the
+:module:`qt4_wrap_ui() <FindQt4>` macro.
+
+This property is initialized by the value of the
+:variable:`CMAKE_AUTOUIC_OPTIONS` variable if it is set when a target is
+created, or an empty string otherwise.
+
+The options set on the target may be overridden by :prop_sf:`AUTOUIC_OPTIONS`
+set on the ``.ui`` source file.
+
+This property may use "generator expressions" with the syntax ``$<...>``.
+See the :manual:`cmake-generator-expressions(7)` manual for available
+expressions.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
+
+EXAMPLE
+^^^^^^^
+
+.. code-block:: cmake
+
+ # ...
+ set_property(TARGET tgt PROPERTY AUTOUIC_OPTIONS "--no-protection")
+ # ...
diff --git a/Help/prop_tgt/AUTOUIC_SEARCH_PATHS.rst b/Help/prop_tgt/AUTOUIC_SEARCH_PATHS.rst
new file mode 100644
index 0000000..87fea48
--- /dev/null
+++ b/Help/prop_tgt/AUTOUIC_SEARCH_PATHS.rst
@@ -0,0 +1,14 @@
+AUTOUIC_SEARCH_PATHS
+--------------------
+
+.. versionadded:: 3.9
+
+Search path list used by :prop_tgt:`AUTOUIC` to find included
+``.ui`` files.
+
+This property is initialized by the value of the
+:variable:`CMAKE_AUTOUIC_SEARCH_PATHS` variable if it is set
+when a target is created. Otherwise it is empty.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/prop_tgt/BINARY_DIR.rst b/Help/prop_tgt/BINARY_DIR.rst
new file mode 100644
index 0000000..beab12c
--- /dev/null
+++ b/Help/prop_tgt/BINARY_DIR.rst
@@ -0,0 +1,8 @@
+BINARY_DIR
+----------
+
+.. versionadded:: 3.4
+
+This read-only property reports the value of the
+:variable:`CMAKE_CURRENT_BINARY_DIR` variable in the directory in which
+the target was defined.
diff --git a/Help/prop_tgt/BUILD_RPATH.rst b/Help/prop_tgt/BUILD_RPATH.rst
new file mode 100644
index 0000000..1f917a5
--- /dev/null
+++ b/Help/prop_tgt/BUILD_RPATH.rst
@@ -0,0 +1,15 @@
+BUILD_RPATH
+-----------
+
+.. versionadded:: 3.8
+
+A :ref:`semicolon-separated list <CMake Language Lists>` specifying runtime path (``RPATH``)
+entries to add to binaries linked in the build tree (for platforms that
+support it). The entries will *not* be used for binaries in the install
+tree. See also the :prop_tgt:`INSTALL_RPATH` target property.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_BUILD_RPATH` if it is set when a target is created.
+
+This property supports
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/prop_tgt/BUILD_RPATH_USE_ORIGIN.rst b/Help/prop_tgt/BUILD_RPATH_USE_ORIGIN.rst
new file mode 100644
index 0000000..2cdfa0d
--- /dev/null
+++ b/Help/prop_tgt/BUILD_RPATH_USE_ORIGIN.rst
@@ -0,0 +1,26 @@
+BUILD_RPATH_USE_ORIGIN
+----------------------
+
+.. versionadded:: 3.14
+
+Whether to use relative paths for the build ``RPATH``.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_BUILD_RPATH_USE_ORIGIN`.
+
+On platforms that support runtime paths (``RPATH``) with the
+``$ORIGIN`` token, setting this property to ``TRUE`` enables relative
+paths in the build ``RPATH`` for executables and shared libraries that
+point to shared libraries in the same build tree.
+
+Normally the build ``RPATH`` of a binary contains absolute paths
+to the directory of each shared library it links to. The ``RPATH``
+entries for directories contained within the build tree can be made
+relative to enable relocatable builds and to help achieve reproducible
+builds by omitting the build directory from the build environment.
+
+This property has no effect on platforms that do not support the
+``$ORIGIN`` token in ``RPATH``, or when the :variable:`CMAKE_SKIP_RPATH`
+variable is set. The runtime path set through the
+:prop_tgt:`BUILD_RPATH` target property is also unaffected by this
+property.
diff --git a/Help/prop_tgt/BUILD_WITH_INSTALL_NAME_DIR.rst b/Help/prop_tgt/BUILD_WITH_INSTALL_NAME_DIR.rst
new file mode 100644
index 0000000..073dce5
--- /dev/null
+++ b/Help/prop_tgt/BUILD_WITH_INSTALL_NAME_DIR.rst
@@ -0,0 +1,15 @@
+BUILD_WITH_INSTALL_NAME_DIR
+---------------------------
+
+.. versionadded:: 3.9
+
+``BUILD_WITH_INSTALL_NAME_DIR`` is a boolean specifying whether the macOS
+``install_name`` of a target in the build tree uses the directory given by
+:prop_tgt:`INSTALL_NAME_DIR`. This setting only applies to targets on macOS.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_BUILD_WITH_INSTALL_NAME_DIR` if it is set when a target is
+created.
+
+If this property is not set and policy :policy:`CMP0068` is not ``NEW``, the
+value of :prop_tgt:`BUILD_WITH_INSTALL_RPATH` is used in its place.
diff --git a/Help/prop_tgt/BUILD_WITH_INSTALL_RPATH.rst b/Help/prop_tgt/BUILD_WITH_INSTALL_RPATH.rst
new file mode 100644
index 0000000..0244351
--- /dev/null
+++ b/Help/prop_tgt/BUILD_WITH_INSTALL_RPATH.rst
@@ -0,0 +1,15 @@
+BUILD_WITH_INSTALL_RPATH
+------------------------
+
+``BUILD_WITH_INSTALL_RPATH`` is a boolean specifying whether to link the target
+in the build tree with the :prop_tgt:`INSTALL_RPATH`. This takes precedence
+over :prop_tgt:`SKIP_BUILD_RPATH` and avoids the need for relinking before
+installation.
+
+This property is initialized by the value of the
+:variable:`CMAKE_BUILD_WITH_INSTALL_RPATH` variable if it is set when a target
+is created.
+
+If policy :policy:`CMP0068` is not ``NEW``, this property also controls use of
+:prop_tgt:`INSTALL_NAME_DIR` in the build tree on macOS. Either way, the
+:prop_tgt:`BUILD_WITH_INSTALL_NAME_DIR` target property takes precedence.
diff --git a/Help/prop_tgt/BUNDLE.rst b/Help/prop_tgt/BUNDLE.rst
new file mode 100644
index 0000000..c556ac3
--- /dev/null
+++ b/Help/prop_tgt/BUNDLE.rst
@@ -0,0 +1,9 @@
+BUNDLE
+------
+
+This target is a ``CFBundle`` on the macOS.
+
+If a module library target has this property set to true it will be
+built as a ``CFBundle`` when built on the mac. It will have the directory
+structure required for a ``CFBundle`` and will be suitable to be used for
+creating Browser Plugins or other application resources.
diff --git a/Help/prop_tgt/BUNDLE_EXTENSION.rst b/Help/prop_tgt/BUNDLE_EXTENSION.rst
new file mode 100644
index 0000000..70de11c
--- /dev/null
+++ b/Help/prop_tgt/BUNDLE_EXTENSION.rst
@@ -0,0 +1,8 @@
+BUNDLE_EXTENSION
+----------------
+
+The file extension used to name a :prop_tgt:`BUNDLE`, a :prop_tgt:`FRAMEWORK`,
+or a :prop_tgt:`MACOSX_BUNDLE` target on the macOS and iOS.
+
+The default value is ``bundle``, ``framework``, or ``app`` for the respective
+target types.
diff --git a/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst b/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst
new file mode 100644
index 0000000..adfa6f7
--- /dev/null
+++ b/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst
@@ -0,0 +1,24 @@
+COMMON_LANGUAGE_RUNTIME
+-----------------------
+
+.. versionadded:: 3.12
+
+By setting this target property, the target is configured to build with
+``C++/CLI`` support.
+
+The Visual Studio generator defines the ``clr`` parameter depending on
+the value of ``COMMON_LANGUAGE_RUNTIME``:
+
+* property not set: native C++ (i.e. default)
+* property set but empty: mixed unmanaged/managed C++
+* property set to any non empty value: managed C++
+
+Supported values: ``""``, ``"pure"``, ``"safe"``
+
+This property is only evaluated :ref:`Visual Studio Generators` for
+VS 2010 and above.
+
+To be able to build managed C++ targets with VS 2017 and above the component
+``C++/CLI support`` must be installed, which may not be done by default.
+
+See also :prop_tgt:`IMPORTED_COMMON_LANGUAGE_RUNTIME`
diff --git a/Help/prop_tgt/COMPATIBLE_INTERFACE_BOOL.rst b/Help/prop_tgt/COMPATIBLE_INTERFACE_BOOL.rst
new file mode 100644
index 0000000..6910367
--- /dev/null
+++ b/Help/prop_tgt/COMPATIBLE_INTERFACE_BOOL.rst
@@ -0,0 +1,20 @@
+COMPATIBLE_INTERFACE_BOOL
+-------------------------
+
+Properties which must be compatible with their link interface
+
+The ``COMPATIBLE_INTERFACE_BOOL`` property may contain a list of
+properties for this target which must be consistent when evaluated as a
+boolean with the ``INTERFACE`` variant of the property in all linked
+dependees. For example, if a property ``FOO`` appears in the list, then
+for each dependee, the ``INTERFACE_FOO`` property content in all of its
+dependencies must be consistent with each other, and with the ``FOO``
+property in the depender.
+
+Consistency in this sense has the meaning that if the property is set,
+then it must have the same boolean value as all others, and if the
+property is not set, then it is ignored.
+
+Note that for each dependee, the set of properties specified in this
+property must not intersect with the set specified in any of the other
+:ref:`Compatible Interface Properties`.
diff --git a/Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MAX.rst b/Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MAX.rst
new file mode 100644
index 0000000..298acf1
--- /dev/null
+++ b/Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MAX.rst
@@ -0,0 +1,18 @@
+COMPATIBLE_INTERFACE_NUMBER_MAX
+-------------------------------
+
+Properties whose maximum value from the link interface will be used.
+
+The ``COMPATIBLE_INTERFACE_NUMBER_MAX`` property may contain a list of
+properties for this target whose maximum value may be read at generate
+time when evaluated in the ``INTERFACE`` variant of the property in all
+linked dependees. For example, if a property ``FOO`` appears in the list,
+then for each dependee, the ``INTERFACE_FOO`` property content in all of
+its dependencies will be compared with each other and with the ``FOO``
+property in the depender. When reading the ``FOO`` property at generate
+time, the maximum value will be returned. If the property is not set,
+then it is ignored.
+
+Note that for each dependee, the set of properties specified in this
+property must not intersect with the set specified in any of the other
+:ref:`Compatible Interface Properties`.
diff --git a/Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MIN.rst b/Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MIN.rst
new file mode 100644
index 0000000..d5fd825
--- /dev/null
+++ b/Help/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MIN.rst
@@ -0,0 +1,18 @@
+COMPATIBLE_INTERFACE_NUMBER_MIN
+-------------------------------
+
+Properties whose maximum value from the link interface will be used.
+
+The ``COMPATIBLE_INTERFACE_NUMBER_MIN`` property may contain a list of
+properties for this target whose minimum value may be read at generate
+time when evaluated in the ``INTERFACE`` variant of the property of all
+linked dependees. For example, if a
+property ``FOO`` appears in the list, then for each dependee, the
+``INTERFACE_FOO`` property content in all of its dependencies will be
+compared with each other and with the ``FOO`` property in the depender.
+When reading the ``FOO`` property at generate time, the minimum value
+will be returned. If the property is not set, then it is ignored.
+
+Note that for each dependee, the set of properties specified in this
+property must not intersect with the set specified in any of the other
+:ref:`Compatible Interface Properties`.
diff --git a/Help/prop_tgt/COMPATIBLE_INTERFACE_STRING.rst b/Help/prop_tgt/COMPATIBLE_INTERFACE_STRING.rst
new file mode 100644
index 0000000..a0050b9
--- /dev/null
+++ b/Help/prop_tgt/COMPATIBLE_INTERFACE_STRING.rst
@@ -0,0 +1,16 @@
+COMPATIBLE_INTERFACE_STRING
+---------------------------
+
+Properties which must be string-compatible with their link interface
+
+The ``COMPATIBLE_INTERFACE_STRING`` property may contain a list of
+properties for this target which must be the same when evaluated as a
+string in the ``INTERFACE`` variant of the property all linked dependees.
+For example, if a property ``FOO`` appears in the list, then for each
+dependee, the ``INTERFACE_FOO`` property content in all of its
+dependencies must be equal with each other, and with the ``FOO`` property
+in the depender. If the property is not set, then it is ignored.
+
+Note that for each dependee, the set of properties specified in this
+property must not intersect with the set specified in any of the other
+:ref:`Compatible Interface Properties`.
diff --git a/Help/prop_tgt/COMPILE_DEFINITIONS.rst b/Help/prop_tgt/COMPILE_DEFINITIONS.rst
new file mode 100644
index 0000000..059f913
--- /dev/null
+++ b/Help/prop_tgt/COMPILE_DEFINITIONS.rst
@@ -0,0 +1,25 @@
+COMPILE_DEFINITIONS
+-------------------
+
+Preprocessor definitions for compiling a target's sources.
+
+The ``COMPILE_DEFINITIONS`` property may be set to a semicolon-separated
+list of preprocessor definitions using the syntax ``VAR`` or ``VAR=value``.
+Function-style definitions are not supported. CMake will
+automatically escape the value correctly for the native build system
+(note that CMake language syntax may require escapes to specify some
+values).
+
+CMake will automatically drop some definitions that are not supported
+by the native build tool.
+
+.. include:: /include/COMPILE_DEFINITIONS_DISCLAIMER.txt
+
+Contents of ``COMPILE_DEFINITIONS`` may use "generator expressions" with the
+syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions. See the :manual:`cmake-buildsystem(7)` manual
+for more on defining buildsystem properties.
+
+The corresponding :prop_tgt:`COMPILE_DEFINITIONS_<CONFIG>` property may
+be set to specify per-configuration definitions. Generator expressions
+should be preferred instead of setting the alternative property.
diff --git a/Help/prop_tgt/COMPILE_DEFINITIONS_CONFIG.rst b/Help/prop_tgt/COMPILE_DEFINITIONS_CONFIG.rst
new file mode 100644
index 0000000..84bd5e4
--- /dev/null
+++ b/Help/prop_tgt/COMPILE_DEFINITIONS_CONFIG.rst
@@ -0,0 +1,16 @@
+COMPILE_DEFINITIONS_<CONFIG>
+----------------------------
+
+Ignored. See CMake Policy :policy:`CMP0043`.
+
+Per-configuration preprocessor definitions on a target.
+
+This is the configuration-specific version of :prop_tgt:`COMPILE_DEFINITIONS`
+where ``<CONFIG>`` is an upper-case name (ex. ``COMPILE_DEFINITIONS_DEBUG``).
+
+Contents of ``COMPILE_DEFINITIONS_<CONFIG>`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
+Generator expressions should be preferred instead of setting this property.
diff --git a/Help/prop_tgt/COMPILE_FEATURES.rst b/Help/prop_tgt/COMPILE_FEATURES.rst
new file mode 100644
index 0000000..9b937ed
--- /dev/null
+++ b/Help/prop_tgt/COMPILE_FEATURES.rst
@@ -0,0 +1,15 @@
+COMPILE_FEATURES
+----------------
+
+.. versionadded:: 3.1
+
+Compiler features enabled for this target.
+
+The list of features in this property are a subset of the features listed
+in the :variable:`CMAKE_C_COMPILE_FEATURES`, :variable:`CMAKE_CUDA_COMPILE_FEATURES`, and
+:variable:`CMAKE_CXX_COMPILE_FEATURES` variables.
+
+Contents of ``COMPILE_FEATURES`` may use "generator expressions" with the
+syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual for
+available expressions. See the :manual:`cmake-compile-features(7)` manual
+for information on compile features and a list of supported compilers.
diff --git a/Help/prop_tgt/COMPILE_FLAGS.rst b/Help/prop_tgt/COMPILE_FLAGS.rst
new file mode 100644
index 0000000..8fe651b
--- /dev/null
+++ b/Help/prop_tgt/COMPILE_FLAGS.rst
@@ -0,0 +1,11 @@
+COMPILE_FLAGS
+-------------
+
+Additional flags to use when compiling this target's sources.
+
+The ``COMPILE_FLAGS`` property sets additional compiler flags used to
+build sources within the target. Use :prop_tgt:`COMPILE_DEFINITIONS`
+to pass additional preprocessor definitions.
+
+This property is deprecated. Use the :prop_tgt:`COMPILE_OPTIONS`
+property or the :command:`target_compile_options` command instead.
diff --git a/Help/prop_tgt/COMPILE_OPTIONS.rst b/Help/prop_tgt/COMPILE_OPTIONS.rst
new file mode 100644
index 0000000..0cd6836
--- /dev/null
+++ b/Help/prop_tgt/COMPILE_OPTIONS.rst
@@ -0,0 +1,17 @@
+COMPILE_OPTIONS
+---------------
+
+List of options to pass to the compiler.
+
+This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of options
+specified so far for its target. Use the :command:`target_compile_options`
+command to append more options.
+
+This property is initialized by the :prop_dir:`COMPILE_OPTIONS` directory
+property when a target is created, and is used by the generators to set
+the options for the compiler.
+
+Contents of ``COMPILE_OPTIONS`` may use "generator expressions" with the
+syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions. See the :manual:`cmake-buildsystem(7)` manual
+for more on defining buildsystem properties.
diff --git a/Help/prop_tgt/COMPILE_PDB_NAME.rst b/Help/prop_tgt/COMPILE_PDB_NAME.rst
new file mode 100644
index 0000000..b76afeb
--- /dev/null
+++ b/Help/prop_tgt/COMPILE_PDB_NAME.rst
@@ -0,0 +1,13 @@
+COMPILE_PDB_NAME
+----------------
+
+.. versionadded:: 3.1
+
+Output name for the MS debug symbol ``.pdb`` file generated by the
+compiler while building source files.
+
+This property specifies the base name for the debug symbols file.
+If not set, the default is unspecified.
+
+.. |PDB_XXX| replace:: :prop_tgt:`PDB_NAME`
+.. include:: COMPILE_PDB_NOTE.txt
diff --git a/Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst b/Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst
new file mode 100644
index 0000000..4c9825d
--- /dev/null
+++ b/Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst
@@ -0,0 +1,12 @@
+COMPILE_PDB_NAME_<CONFIG>
+-------------------------
+
+.. versionadded:: 3.1
+
+Per-configuration output name for the MS debug symbol ``.pdb`` file
+generated by the compiler while building source files.
+
+This is the configuration-specific version of :prop_tgt:`COMPILE_PDB_NAME`.
+
+.. |PDB_XXX| replace:: :prop_tgt:`PDB_NAME_<CONFIG>`
+.. include:: COMPILE_PDB_NOTE.txt
diff --git a/Help/prop_tgt/COMPILE_PDB_NOTE.txt b/Help/prop_tgt/COMPILE_PDB_NOTE.txt
new file mode 100644
index 0000000..43003d9
--- /dev/null
+++ b/Help/prop_tgt/COMPILE_PDB_NOTE.txt
@@ -0,0 +1,5 @@
+.. note::
+ The compiler-generated program database files are specified by the
+ ``/Fd`` compiler flag and are not the same as linker-generated
+ program database files specified by the ``/pdb`` linker flag.
+ Use the |PDB_XXX| property to specify the latter.
diff --git a/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY.rst b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY.rst
new file mode 100644
index 0000000..3f3df66
--- /dev/null
+++ b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY.rst
@@ -0,0 +1,15 @@
+COMPILE_PDB_OUTPUT_DIRECTORY
+----------------------------
+
+.. versionadded:: 3.1
+
+Output directory for the MS debug symbol ``.pdb`` file
+generated by the compiler while building source files.
+
+This property specifies the directory into which the MS debug symbols
+will be placed by the compiler. This property is initialized by the
+value of the :variable:`CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY` variable
+if it is set when a target is created.
+
+.. |PDB_XXX| replace:: :prop_tgt:`PDB_OUTPUT_DIRECTORY`
+.. include:: COMPILE_PDB_NOTE.txt
diff --git a/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
new file mode 100644
index 0000000..c25c2fc
--- /dev/null
+++ b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
@@ -0,0 +1,18 @@
+COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG>
+-------------------------------------
+
+.. versionadded:: 3.1
+
+Per-configuration output directory for the MS debug symbol ``.pdb`` file
+generated by the compiler while building source files.
+
+This is a per-configuration version of
+:prop_tgt:`COMPILE_PDB_OUTPUT_DIRECTORY`,
+but multi-configuration generators (Visual Studio, Xcode) do NOT append a
+per-configuration subdirectory to the specified directory. This
+property is initialized by the value of the
+:variable:`CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG>` variable
+if it is set when a target is created.
+
+.. |PDB_XXX| replace:: :prop_tgt:`PDB_OUTPUT_DIRECTORY_<CONFIG>`
+.. include:: COMPILE_PDB_NOTE.txt
diff --git a/Help/prop_tgt/CONFIG_OUTPUT_NAME.rst b/Help/prop_tgt/CONFIG_OUTPUT_NAME.rst
new file mode 100644
index 0000000..a61c702
--- /dev/null
+++ b/Help/prop_tgt/CONFIG_OUTPUT_NAME.rst
@@ -0,0 +1,8 @@
+<CONFIG>_OUTPUT_NAME
+--------------------
+
+Old per-configuration target file base name.
+Use :prop_tgt:`OUTPUT_NAME_<CONFIG>` instead.
+
+This is a configuration-specific version of the :prop_tgt:`OUTPUT_NAME`
+target property.
diff --git a/Help/prop_tgt/CONFIG_POSTFIX.rst b/Help/prop_tgt/CONFIG_POSTFIX.rst
new file mode 100644
index 0000000..5c2fbd7
--- /dev/null
+++ b/Help/prop_tgt/CONFIG_POSTFIX.rst
@@ -0,0 +1,13 @@
+<CONFIG>_POSTFIX
+----------------
+
+Postfix to append to the target file name for configuration <CONFIG>.
+
+When building with configuration <CONFIG> the value of this property
+is appended to the target file name built on disk. For non-executable
+targets, this property is initialized by the value of the variable
+CMAKE_<CONFIG>_POSTFIX if it is set when a target is created. This
+property is ignored on the Mac for Frameworks and App Bundles.
+
+For macOS see also the :prop_tgt:`FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>`
+target property.
diff --git a/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst b/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst
new file mode 100644
index 0000000..d7fb9b1
--- /dev/null
+++ b/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst
@@ -0,0 +1,17 @@
+CROSSCOMPILING_EMULATOR
+-----------------------
+
+.. versionadded:: 3.3
+
+Use the given emulator to run executables created when crosscompiling.
+This command will be added as a prefix to :command:`add_test`,
+:command:`add_custom_command`, and :command:`add_custom_target` commands
+for built target system executables.
+
+If this property contains a :ref:`semicolon-separated list <CMake Language
+Lists>`, then the first value is the command and remaining values are its
+arguments.
+
+This property is initialized by the value of the
+:variable:`CMAKE_CROSSCOMPILING_EMULATOR` variable if it is set when a target
+is created.
diff --git a/Help/prop_tgt/CUDA_ARCHITECTURES.rst b/Help/prop_tgt/CUDA_ARCHITECTURES.rst
new file mode 100644
index 0000000..d56b769
--- /dev/null
+++ b/Help/prop_tgt/CUDA_ARCHITECTURES.rst
@@ -0,0 +1,42 @@
+CUDA_ARCHITECTURES
+------------------
+
+.. versionadded:: 3.18
+
+List of architectures to generate device code for.
+
+An architecture can be suffixed by either ``-real`` or ``-virtual`` to specify
+the kind of architecture to generate code for.
+If no suffix is given then code is generated for both real and virtual
+architectures.
+
+A non-empty false value (e.g. ``OFF``) disables adding architectures.
+This is intended to support packagers and rare cases where full control
+over the passed flags is required.
+
+This property is initialized by the value of the :variable:`CMAKE_CUDA_ARCHITECTURES`
+variable if it is set when a target is created.
+
+The ``CUDA_ARCHITECTURES`` target property must be set to a non-empty value on targets
+that compile CUDA sources, or it is an error. See policy :policy:`CMP0104`.
+
+Examples
+^^^^^^^^
+
+.. code-block:: cmake
+
+ set_property(TARGET tgt PROPERTY CUDA_ARCHITECTURES 35 50 72)
+
+Generates code for real and virtual architectures ``30``, ``50`` and ``72``.
+
+.. code-block:: cmake
+
+ set_property(TARGET tgt PROPERTY CUDA_ARCHITECTURES 70-real 72-virtual)
+
+Generates code for real architecture ``70`` and virtual architecture ``72``.
+
+.. code-block:: cmake
+
+ set_property(TARGET tgt PROPERTY CUDA_ARCHITECTURES OFF)
+
+CMake will not pass any architecture flags to the compiler.
diff --git a/Help/prop_tgt/CUDA_EXTENSIONS.rst b/Help/prop_tgt/CUDA_EXTENSIONS.rst
new file mode 100644
index 0000000..2ddba0b
--- /dev/null
+++ b/Help/prop_tgt/CUDA_EXTENSIONS.rst
@@ -0,0 +1,19 @@
+CUDA_EXTENSIONS
+---------------
+
+.. versionadded:: 3.8
+
+Boolean specifying whether compiler specific extensions are requested.
+
+This property specifies whether compiler specific extensions should be
+used. For some compilers, this results in adding a flag such
+as ``-std=gnu++11`` instead of ``-std=c++11`` to the compile line. This
+property is ``ON`` by default. The basic CUDA/C++ standard level is
+controlled by the :prop_tgt:`CUDA_STANDARD` target property.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_CUDA_EXTENSIONS` variable if it is set when a target
+is created.
diff --git a/Help/prop_tgt/CUDA_PTX_COMPILATION.rst b/Help/prop_tgt/CUDA_PTX_COMPILATION.rst
new file mode 100644
index 0000000..4e90afe
--- /dev/null
+++ b/Help/prop_tgt/CUDA_PTX_COMPILATION.rst
@@ -0,0 +1,14 @@
+CUDA_PTX_COMPILATION
+--------------------
+
+.. versionadded:: 3.9
+
+Compile CUDA sources to ``.ptx`` files instead of ``.obj`` files
+within :ref:`Object Libraries`.
+
+For example:
+
+.. code-block:: cmake
+
+ add_library(myptx OBJECT a.cu b.cu)
+ set_property(TARGET myptx PROPERTY CUDA_PTX_COMPILATION ON)
diff --git a/Help/prop_tgt/CUDA_RESOLVE_DEVICE_SYMBOLS.rst b/Help/prop_tgt/CUDA_RESOLVE_DEVICE_SYMBOLS.rst
new file mode 100644
index 0000000..819ce3e
--- /dev/null
+++ b/Help/prop_tgt/CUDA_RESOLVE_DEVICE_SYMBOLS.rst
@@ -0,0 +1,27 @@
+CUDA_RESOLVE_DEVICE_SYMBOLS
+---------------------------
+
+.. versionadded:: 3.9
+
+CUDA only: Enables device linking for the specific library target where
+required.
+
+If set, this will tell the required compilers to enable device linking
+on the library target. Device linking is an additional link step
+required by some CUDA compilers when :prop_tgt:`CUDA_SEPARABLE_COMPILATION` is
+enabled. Normally device linking is deferred until a shared library or
+executable is generated, allowing for multiple static libraries to resolve
+device symbols at the same time when they are used by a shared library or
+executable.
+
+By default static library targets have this property is disabled,
+while shared, module, and executable targets have this property enabled.
+
+Note that device linking is not supported for :ref:`Object Libraries`.
+
+
+For instance:
+
+.. code-block:: cmake
+
+ set_property(TARGET mystaticlib PROPERTY CUDA_RESOLVE_DEVICE_SYMBOLS ON)
diff --git a/Help/prop_tgt/CUDA_RUNTIME_LIBRARY-VALUES.txt b/Help/prop_tgt/CUDA_RUNTIME_LIBRARY-VALUES.txt
new file mode 100644
index 0000000..a6d7050
--- /dev/null
+++ b/Help/prop_tgt/CUDA_RUNTIME_LIBRARY-VALUES.txt
@@ -0,0 +1,9 @@
+``None``
+ Link with ``-cudart=none`` or equivalent flag(s) to use no CUDA
+ runtime library.
+``Shared``
+ Link with ``-cudart=shared`` or equivalent flag(s) to use a
+ dynamically-linked CUDA runtime library.
+``Static``
+ Link with ``-cudart=static`` or equivalent flag(s) to use a
+ statically-linked CUDA runtime library.
diff --git a/Help/prop_tgt/CUDA_RUNTIME_LIBRARY.rst b/Help/prop_tgt/CUDA_RUNTIME_LIBRARY.rst
new file mode 100644
index 0000000..e937fc6
--- /dev/null
+++ b/Help/prop_tgt/CUDA_RUNTIME_LIBRARY.rst
@@ -0,0 +1,23 @@
+CUDA_RUNTIME_LIBRARY
+--------------------
+
+.. versionadded:: 3.17
+
+Select the CUDA runtime library for use by compilers targeting the CUDA language.
+
+The allowed case insensitive values are:
+
+.. include:: CUDA_RUNTIME_LIBRARY-VALUES.txt
+
+Contents of ``CUDA_RUNTIME_LIBRARY`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+If that property is not set then CMake uses an appropriate default
+value based on the compiler to select the CUDA runtime library.
+
+.. note::
+
+ This property has effect only when the ``CUDA`` language is enabled. To
+ control the CUDA runtime linking when only using the CUDA SDK with the
+ ``C`` or ``C++`` language we recommend using the :module:`FindCUDAToolkit`
+ module.
diff --git a/Help/prop_tgt/CUDA_SEPARABLE_COMPILATION.rst b/Help/prop_tgt/CUDA_SEPARABLE_COMPILATION.rst
new file mode 100644
index 0000000..32222f9
--- /dev/null
+++ b/Help/prop_tgt/CUDA_SEPARABLE_COMPILATION.rst
@@ -0,0 +1,19 @@
+CUDA_SEPARABLE_COMPILATION
+--------------------------
+
+.. versionadded:: 3.8
+
+CUDA only: Enables separate compilation of device code
+
+If set this will enable separable compilation for all CUDA files for
+the given target.
+
+For instance:
+
+.. code-block:: cmake
+
+ set_property(TARGET myexe PROPERTY CUDA_SEPARABLE_COMPILATION ON)
+
+This property is initialized by the value of the
+:variable:`CMAKE_CUDA_SEPARABLE_COMPILATION` variable if it is set when a
+target is created.
diff --git a/Help/prop_tgt/CUDA_STANDARD.rst b/Help/prop_tgt/CUDA_STANDARD.rst
new file mode 100644
index 0000000..6517035
--- /dev/null
+++ b/Help/prop_tgt/CUDA_STANDARD.rst
@@ -0,0 +1,34 @@
+CUDA_STANDARD
+-------------
+
+.. versionadded:: 3.8
+
+The CUDA/C++ standard whose features are requested to build this target.
+
+This property specifies the CUDA/C++ standard whose features are requested
+to build this target. For some compilers, this results in adding a
+flag such as ``-std=gnu++11`` to the compile line.
+
+Supported values are ``98``, ``03``, ``11``, ``14``, ``17``, ``20``, ``23``.
+
+If the value requested does not result in a compile flag being added for
+the compiler in use, a previous standard flag will be added instead. This
+means that using:
+
+.. code-block:: cmake
+
+ set_property(TARGET tgt PROPERTY CUDA_STANDARD 11)
+
+with a compiler which does not support ``-std=gnu++11`` or an equivalent
+flag will not result in an error or warning, but will instead add the
+``-std=gnu++98`` flag if supported. This "decay" behavior may be controlled
+with the :prop_tgt:`CUDA_STANDARD_REQUIRED` target property.
+Additionally, the :prop_tgt:`CUDA_EXTENSIONS` target property may be used to
+control whether compiler-specific extensions are enabled on a per-target basis.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_CUDA_STANDARD` variable if it is set when a target
+is created.
diff --git a/Help/prop_tgt/CUDA_STANDARD_REQUIRED.rst b/Help/prop_tgt/CUDA_STANDARD_REQUIRED.rst
new file mode 100644
index 0000000..c9301b5
--- /dev/null
+++ b/Help/prop_tgt/CUDA_STANDARD_REQUIRED.rst
@@ -0,0 +1,20 @@
+CUDA_STANDARD_REQUIRED
+----------------------
+
+.. versionadded:: 3.8
+
+Boolean describing whether the value of :prop_tgt:`CUDA_STANDARD` is a requirement.
+
+If this property is set to ``ON``, then the value of the
+:prop_tgt:`CUDA_STANDARD` target property is treated as a requirement. If this
+property is ``OFF`` or unset, the :prop_tgt:`CUDA_STANDARD` target property is
+treated as optional and may "decay" to a previous standard if the requested is
+not available. For compilers that have no notion of a standard level, such as
+MSVC 1800 (Visual Studio 2013) and lower, this has no effect.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_CUDA_STANDARD_REQUIRED` variable if it is set when a
+target is created.
diff --git a/Help/prop_tgt/CXX_EXTENSIONS.rst b/Help/prop_tgt/CXX_EXTENSIONS.rst
new file mode 100644
index 0000000..bda531e
--- /dev/null
+++ b/Help/prop_tgt/CXX_EXTENSIONS.rst
@@ -0,0 +1,19 @@
+CXX_EXTENSIONS
+--------------
+
+.. versionadded:: 3.1
+
+Boolean specifying whether compiler specific extensions are requested.
+
+This property specifies whether compiler specific extensions should be
+used. For some compilers, this results in adding a flag such
+as ``-std=gnu++11`` instead of ``-std=c++11`` to the compile line. This
+property is ``ON`` by default. The basic C++ standard level is
+controlled by the :prop_tgt:`CXX_STANDARD` target property.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_CXX_EXTENSIONS` variable if it is set when a target
+is created.
diff --git a/Help/prop_tgt/CXX_STANDARD.rst b/Help/prop_tgt/CXX_STANDARD.rst
new file mode 100644
index 0000000..be0dab5
--- /dev/null
+++ b/Help/prop_tgt/CXX_STANDARD.rst
@@ -0,0 +1,36 @@
+CXX_STANDARD
+------------
+
+.. versionadded:: 3.1
+
+The C++ standard whose features are requested to build this target.
+
+This property specifies the C++ standard whose features are requested
+to build this target. For some compilers, this results in adding a
+flag such as ``-std=gnu++11`` to the compile line. For compilers that
+have no notion of a standard level, such as Microsoft Visual C++ before
+2015 Update 3, this has no effect.
+
+Supported values are ``98``, ``11``, ``14``, ``17``, ``20``, ``23``.
+
+If the value requested does not result in a compile flag being added for
+the compiler in use, a previous standard flag will be added instead. This
+means that using:
+
+.. code-block:: cmake
+
+ set_property(TARGET tgt PROPERTY CXX_STANDARD 11)
+
+with a compiler which does not support ``-std=gnu++11`` or an equivalent
+flag will not result in an error or warning, but will instead add the
+``-std=gnu++98`` flag if supported. This "decay" behavior may be controlled
+with the :prop_tgt:`CXX_STANDARD_REQUIRED` target property.
+Additionally, the :prop_tgt:`CXX_EXTENSIONS` target property may be used to
+control whether compiler-specific extensions are enabled on a per-target basis.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_CXX_STANDARD` variable if it is set when a target
+is created.
diff --git a/Help/prop_tgt/CXX_STANDARD_REQUIRED.rst b/Help/prop_tgt/CXX_STANDARD_REQUIRED.rst
new file mode 100644
index 0000000..8b17490
--- /dev/null
+++ b/Help/prop_tgt/CXX_STANDARD_REQUIRED.rst
@@ -0,0 +1,20 @@
+CXX_STANDARD_REQUIRED
+---------------------
+
+.. versionadded:: 3.1
+
+Boolean describing whether the value of :prop_tgt:`CXX_STANDARD` is a requirement.
+
+If this property is set to ``ON``, then the value of the
+:prop_tgt:`CXX_STANDARD` target property is treated as a requirement. If this
+property is ``OFF`` or unset, the :prop_tgt:`CXX_STANDARD` target property is
+treated as optional and may "decay" to a previous standard if the requested is
+not available. For compilers that have no notion of a standard level, such as
+MSVC 1800 (Visual Studio 2013) and lower, this has no effect.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_CXX_STANDARD_REQUIRED` variable if it is set when a
+target is created.
diff --git a/Help/prop_tgt/C_EXTENSIONS.rst b/Help/prop_tgt/C_EXTENSIONS.rst
new file mode 100644
index 0000000..b2abb46
--- /dev/null
+++ b/Help/prop_tgt/C_EXTENSIONS.rst
@@ -0,0 +1,19 @@
+C_EXTENSIONS
+------------
+
+.. versionadded:: 3.1
+
+Boolean specifying whether compiler specific extensions are requested.
+
+This property specifies whether compiler specific extensions should be
+used. For some compilers, this results in adding a flag such
+as ``-std=gnu11`` instead of ``-std=c11`` to the compile line. This
+property is ``ON`` by default. The basic C standard level is
+controlled by the :prop_tgt:`C_STANDARD` target property.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_C_EXTENSIONS` variable if it is set when a target
+is created.
diff --git a/Help/prop_tgt/C_STANDARD.rst b/Help/prop_tgt/C_STANDARD.rst
new file mode 100644
index 0000000..e22b775
--- /dev/null
+++ b/Help/prop_tgt/C_STANDARD.rst
@@ -0,0 +1,36 @@
+C_STANDARD
+----------
+
+.. versionadded:: 3.1
+
+The C standard whose features are requested to build this target.
+
+This property specifies the C standard whose features are requested
+to build this target. For some compilers, this results in adding a
+flag such as ``-std=gnu11`` to the compile line. For compilers that
+have no notion of a C standard level, such as Microsoft Visual C++ before
+VS 16.7, this property has no effect.
+
+Supported values are ``90``, ``99``, ``11``, ``17``, ``23``.
+
+If the value requested does not result in a compile flag being added for
+the compiler in use, a previous standard flag will be added instead. This
+means that using:
+
+.. code-block:: cmake
+
+ set_property(TARGET tgt PROPERTY C_STANDARD 11)
+
+with a compiler which does not support ``-std=gnu11`` or an equivalent
+flag will not result in an error or warning, but will instead add the
+``-std=gnu99`` or ``-std=gnu90`` flag if supported. This "decay" behavior may
+be controlled with the :prop_tgt:`C_STANDARD_REQUIRED` target property.
+Additionally, the :prop_tgt:`C_EXTENSIONS` target property may be used to
+control whether compiler-specific extensions are enabled on a per-target basis.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_C_STANDARD` variable if it is set when a target
+is created.
diff --git a/Help/prop_tgt/C_STANDARD_REQUIRED.rst b/Help/prop_tgt/C_STANDARD_REQUIRED.rst
new file mode 100644
index 0000000..8059e3a
--- /dev/null
+++ b/Help/prop_tgt/C_STANDARD_REQUIRED.rst
@@ -0,0 +1,20 @@
+C_STANDARD_REQUIRED
+-------------------
+
+.. versionadded:: 3.1
+
+Boolean describing whether the value of :prop_tgt:`C_STANDARD` is a requirement.
+
+If this property is set to ``ON``, then the value of the
+:prop_tgt:`C_STANDARD` target property is treated as a requirement. If this
+property is ``OFF`` or unset, the :prop_tgt:`C_STANDARD` target property is
+treated as optional and may "decay" to a previous standard if the requested is
+not available. For compilers that have no notion of a C standard level, such
+as Microsoft Visual C++ before VS 16.7, this property has no effect.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_C_STANDARD_REQUIRED` variable if it is set when a
+target is created.
diff --git a/Help/prop_tgt/DEBUG_POSTFIX.rst b/Help/prop_tgt/DEBUG_POSTFIX.rst
new file mode 100644
index 0000000..eca7cb0
--- /dev/null
+++ b/Help/prop_tgt/DEBUG_POSTFIX.rst
@@ -0,0 +1,7 @@
+DEBUG_POSTFIX
+-------------
+
+See target property :prop_tgt:`<CONFIG>_POSTFIX`.
+
+This property is a special case of the more-general :prop_tgt:`<CONFIG>_POSTFIX`
+property for the ``DEBUG`` configuration.
diff --git a/Help/prop_tgt/DEFINE_SYMBOL.rst b/Help/prop_tgt/DEFINE_SYMBOL.rst
new file mode 100644
index 0000000..eb7f937
--- /dev/null
+++ b/Help/prop_tgt/DEFINE_SYMBOL.rst
@@ -0,0 +1,11 @@
+DEFINE_SYMBOL
+-------------
+
+Define a symbol when compiling this target's sources.
+
+``DEFINE_SYMBOL`` sets the name of the preprocessor symbol defined when
+compiling sources in a shared library. If not set here then it is set
+to ``target_EXPORTS`` by default (with some substitutions if the target is
+not a valid C identifier). This is useful for headers to know whether
+they are being included from inside their library or outside to
+properly setup dllexport/dllimport decorations.
diff --git a/Help/prop_tgt/DEPLOYMENT_ADDITIONAL_FILES.rst b/Help/prop_tgt/DEPLOYMENT_ADDITIONAL_FILES.rst
new file mode 100644
index 0000000..f11fe7c
--- /dev/null
+++ b/Help/prop_tgt/DEPLOYMENT_ADDITIONAL_FILES.rst
@@ -0,0 +1,20 @@
+DEPLOYMENT_ADDITIONAL_FILES
+---------------------------
+
+.. versionadded:: 3.13
+
+Set the WinCE project ``AdditionalFiles`` in ``DeploymentTool`` in ``.vcproj``
+files generated by the :generator:`Visual Studio 9 2008` generator.
+This is useful when you want to debug on remote WinCE device.
+Specify additional files that will be copied to the device.
+For example:
+
+.. code-block:: cmake
+
+ set_property(TARGET ${TARGET} PROPERTY
+ DEPLOYMENT_ADDITIONAL_FILES "english.lng|local_folder|remote_folder|0"
+ "german.lng|local_folder|remote_folder|0")
+
+produces::
+
+ <DeploymentTool AdditionalFiles="english.lng|local_folder|remote_folder|0;german.lng|local_folder|remote_folder|0" ... />
diff --git a/Help/prop_tgt/DEPLOYMENT_REMOTE_DIRECTORY.rst b/Help/prop_tgt/DEPLOYMENT_REMOTE_DIRECTORY.rst
new file mode 100644
index 0000000..0680238
--- /dev/null
+++ b/Help/prop_tgt/DEPLOYMENT_REMOTE_DIRECTORY.rst
@@ -0,0 +1,20 @@
+DEPLOYMENT_REMOTE_DIRECTORY
+---------------------------
+
+.. versionadded:: 3.6
+
+Set the WinCE project ``RemoteDirectory`` in ``DeploymentTool`` and
+``RemoteExecutable`` in ``DebuggerTool`` in ``.vcproj`` files generated
+by the :generator:`Visual Studio 9 2008` generator.
+This is useful when you want to debug on remote WinCE device.
+For example:
+
+.. code-block:: cmake
+
+ set_property(TARGET ${TARGET} PROPERTY
+ DEPLOYMENT_REMOTE_DIRECTORY "\\FlashStorage")
+
+produces::
+
+ <DeploymentTool RemoteDirectory="\FlashStorage" ... />
+ <DebuggerTool RemoteExecutable="\FlashStorage\target_file" ... />
diff --git a/Help/prop_tgt/DEPRECATION.rst b/Help/prop_tgt/DEPRECATION.rst
new file mode 100644
index 0000000..45ca848
--- /dev/null
+++ b/Help/prop_tgt/DEPRECATION.rst
@@ -0,0 +1,9 @@
+DEPRECATION
+-----------
+
+.. versionadded:: 3.17
+
+Deprecation message from imported target's developer.
+
+``DEPRECATION`` is the message regarding a deprecation status to be displayed
+to downstream users of a target.
diff --git a/Help/prop_tgt/DISABLE_PRECOMPILE_HEADERS.rst b/Help/prop_tgt/DISABLE_PRECOMPILE_HEADERS.rst
new file mode 100644
index 0000000..7b3826b
--- /dev/null
+++ b/Help/prop_tgt/DISABLE_PRECOMPILE_HEADERS.rst
@@ -0,0 +1,10 @@
+DISABLE_PRECOMPILE_HEADERS
+--------------------------
+
+.. versionadded:: 3.16
+
+Disables the precompilation of header files specified by
+:prop_tgt:`PRECOMPILE_HEADERS` property.
+
+If the property is not set, CMake will use the value provided
+by :variable:`CMAKE_DISABLE_PRECOMPILE_HEADERS`.
diff --git a/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK.rst b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK.rst
new file mode 100644
index 0000000..3ba4e25
--- /dev/null
+++ b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK.rst
@@ -0,0 +1,15 @@
+DOTNET_TARGET_FRAMEWORK
+-----------------------
+
+.. versionadded:: 3.17
+
+Specify the .NET target framework.
+
+Used to specify the .NET target framework for C++/CLI and C#. For
+example: ``netcoreapp2.1``.
+
+This property is only evaluated for :ref:`Visual Studio Generators`
+VS 2010 and above.
+
+Can be initialized for all targets using the variable
+:variable:`CMAKE_DOTNET_TARGET_FRAMEWORK`.
diff --git a/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst
new file mode 100644
index 0000000..fbd1aab
--- /dev/null
+++ b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst
@@ -0,0 +1,17 @@
+DOTNET_TARGET_FRAMEWORK_VERSION
+-------------------------------
+
+.. versionadded:: 3.12
+
+Specify the .NET target framework version.
+
+Used to specify the .NET target framework version for C++/CLI and C#.
+For example: ``v4.5``.
+
+This property is only evaluated for :ref:`Visual Studio Generators`
+VS 2010 and above.
+
+To initialize this variable for all targets set
+:variable:`CMAKE_DOTNET_TARGET_FRAMEWORK` or
+:variable:`CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION`. If both are set,
+the latter is ignored.
diff --git a/Help/prop_tgt/ENABLE_EXPORTS.rst b/Help/prop_tgt/ENABLE_EXPORTS.rst
new file mode 100644
index 0000000..0b1064a
--- /dev/null
+++ b/Help/prop_tgt/ENABLE_EXPORTS.rst
@@ -0,0 +1,31 @@
+ENABLE_EXPORTS
+--------------
+
+Specify whether an executable exports symbols for loadable modules.
+
+Normally an executable does not export any symbols because it is the
+final program. It is possible for an executable to export symbols to
+be used by loadable modules. When this property is set to true CMake
+will allow other targets to "link" to the executable with the
+:command:`target_link_libraries` command. On all platforms a target-level
+dependency on the executable is created for targets that link to it.
+Handling of the executable on the link lines of the loadable modules
+varies by platform:
+
+* On Windows-based systems (including Cygwin) an "import library" is
+ created along with the executable to list the exported symbols.
+ Loadable modules link to the import library to get the symbols.
+
+* On macOS, loadable modules link to the executable itself using the
+ ``-bundle_loader`` flag.
+
+* On AIX, a linker "import file" is created along with the executable
+ to list the exported symbols for import when linking other targets.
+ Loadable modules link to the import file to get the symbols.
+
+* On other platforms, loadable modules are simply linked without
+ referencing the executable since the dynamic loader will
+ automatically bind symbols when the module is loaded.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_ENABLE_EXPORTS` if it is set when a target is created.
diff --git a/Help/prop_tgt/EXCLUDE_FROM_ALL.rst b/Help/prop_tgt/EXCLUDE_FROM_ALL.rst
new file mode 100644
index 0000000..f0200f3
--- /dev/null
+++ b/Help/prop_tgt/EXCLUDE_FROM_ALL.rst
@@ -0,0 +1,28 @@
+EXCLUDE_FROM_ALL
+----------------
+
+Set this target property to a true (or false) value to exclude (or include)
+the target from the "all" target of the containing directory and its
+ancestors. If excluded, running e.g. ``make`` in the containing directory
+or its ancestors will not build the target by default.
+
+If this target property is not set then the target will be included in
+the "all" target of the containing directory. Furthermore, it will be
+included in the "all" target of its ancestor directories unless the
+:prop_dir:`EXCLUDE_FROM_ALL` directory property is set.
+
+With ``EXCLUDE_FROM_ALL`` set to false or not set at all, the target
+will be brought up to date as part of doing a ``make install`` or its
+equivalent for the CMake generator being used.
+
+If a target has ``EXCLUDE_FROM_ALL`` set to true, it may still be listed
+in an :command:`install(TARGETS)` command, but the user is responsible for
+ensuring that the target's build artifacts are not missing or outdated when
+an install is performed.
+
+This property may use "generator expressions" with the syntax ``$<...>``. See
+the :manual:`cmake-generator-expressions(7)` manual for available expressions.
+
+Only the "Ninja Multi-Config" generator supports a property value that varies by
+configuration. For all other generators the value of this property must be the
+same for all configurations.
diff --git a/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD.rst b/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD.rst
new file mode 100644
index 0000000..664704b
--- /dev/null
+++ b/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD.rst
@@ -0,0 +1,8 @@
+EXCLUDE_FROM_DEFAULT_BUILD
+--------------------------
+
+Exclude target from ``Build Solution``.
+
+This property is only used by Visual Studio generators.
+When set to ``TRUE``, the target will not be built when you press
+``Build Solution``.
diff --git a/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG.rst b/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG.rst
new file mode 100644
index 0000000..ad1021a
--- /dev/null
+++ b/Help/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG.rst
@@ -0,0 +1,10 @@
+EXCLUDE_FROM_DEFAULT_BUILD_<CONFIG>
+-----------------------------------
+
+Per-configuration version of target exclusion from ``Build Solution``.
+
+This is the configuration-specific version of
+:prop_tgt:`EXCLUDE_FROM_DEFAULT_BUILD`. If the generic
+:prop_tgt:`EXCLUDE_FROM_DEFAULT_BUILD` is also set on a target,
+``EXCLUDE_FROM_DEFAULT_BUILD_<CONFIG>`` takes
+precedence in configurations for which it has a value.
diff --git a/Help/prop_tgt/EXPORT_COMPILE_COMMANDS.rst b/Help/prop_tgt/EXPORT_COMPILE_COMMANDS.rst
new file mode 100644
index 0000000..0b1145c
--- /dev/null
+++ b/Help/prop_tgt/EXPORT_COMPILE_COMMANDS.rst
@@ -0,0 +1,9 @@
+EXPORT_COMPILE_COMMANDS
+-----------------------
+
+.. versionadded:: 3.20
+
+Enable/Disable output of compile commands during generation for a target.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_EXPORT_COMPILE_COMMANDS` if it is set when a target is created.
diff --git a/Help/prop_tgt/EXPORT_NAME.rst b/Help/prop_tgt/EXPORT_NAME.rst
new file mode 100644
index 0000000..0e021d0
--- /dev/null
+++ b/Help/prop_tgt/EXPORT_NAME.rst
@@ -0,0 +1,8 @@
+EXPORT_NAME
+-----------
+
+Exported name for target files.
+
+This sets the name for the ``IMPORTED`` target generated by the
+:command:`install(EXPORT)` and :command:`export` commands.
+If not set, the logical target name is used by default.
diff --git a/Help/prop_tgt/EXPORT_PROPERTIES.rst b/Help/prop_tgt/EXPORT_PROPERTIES.rst
new file mode 100644
index 0000000..2d54f8b
--- /dev/null
+++ b/Help/prop_tgt/EXPORT_PROPERTIES.rst
@@ -0,0 +1,24 @@
+EXPORT_PROPERTIES
+-----------------
+
+.. versionadded:: 3.12
+
+List additional properties to export for a target.
+
+This property contains a list of property names that should be exported by
+the :command:`install(EXPORT)` and :command:`export` commands. By default
+only a limited number of properties are exported. This property can be used
+to additionally export other properties as well.
+
+Properties starting with ``INTERFACE_`` or ``IMPORTED_`` are not allowed as
+they are reserved for internal CMake use.
+
+Properties containing generator expressions are also not allowed.
+
+.. note::
+
+ Since CMake 3.19, :ref:`Interface Libraries` may have arbitrary
+ target properties. If a project exports an interface library
+ with custom properties, the resulting package may not work with
+ dependents configured by older versions of CMake that reject the
+ custom properties.
diff --git a/Help/prop_tgt/EchoString.rst b/Help/prop_tgt/EchoString.rst
new file mode 100644
index 0000000..352d062
--- /dev/null
+++ b/Help/prop_tgt/EchoString.rst
@@ -0,0 +1,7 @@
+EchoString
+----------
+
+A message to be displayed when the target is built.
+
+A message to display on some generators (such as :ref:`Makefile Generators`)
+when the target is built.
diff --git a/Help/prop_tgt/FOLDER.rst b/Help/prop_tgt/FOLDER.rst
new file mode 100644
index 0000000..f6be9e6
--- /dev/null
+++ b/Help/prop_tgt/FOLDER.rst
@@ -0,0 +1,13 @@
+FOLDER
+------
+
+Set the folder name. Use to organize targets in an IDE.
+
+Targets with no ``FOLDER`` property will appear as top level entities in
+IDEs like Visual Studio. Targets with the same ``FOLDER`` property value
+will appear next to each other in a folder of that name. To nest
+folders, use ``FOLDER`` values such as 'GUI/Dialogs' with '/' characters
+separating folder levels.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_FOLDER` if it is set when a target is created.
diff --git a/Help/prop_tgt/FRAMEWORK.rst b/Help/prop_tgt/FRAMEWORK.rst
new file mode 100644
index 0000000..3dff1be
--- /dev/null
+++ b/Help/prop_tgt/FRAMEWORK.rst
@@ -0,0 +1,37 @@
+FRAMEWORK
+---------
+
+Build ``SHARED`` or ``STATIC`` library as Framework Bundle on the macOS and iOS.
+
+If such a library target has this property set to ``TRUE`` it will be
+built as a framework when built on the macOS and iOS. It will have the
+directory structure required for a framework and will be suitable to
+be used with the ``-framework`` option. This property is initialized by the
+value of the :variable:`CMAKE_FRAMEWORK` variable if it is set when a target is
+created.
+
+To customize ``Info.plist`` file in the framework, use
+:prop_tgt:`MACOSX_FRAMEWORK_INFO_PLIST` target property.
+
+For macOS see also the :prop_tgt:`FRAMEWORK_VERSION` target property.
+
+Example of creation ``dynamicFramework``:
+
+.. code-block:: cmake
+
+ add_library(dynamicFramework SHARED
+ dynamicFramework.c
+ dynamicFramework.h
+ )
+ set_target_properties(dynamicFramework PROPERTIES
+ FRAMEWORK TRUE
+ FRAMEWORK_VERSION C
+ MACOSX_FRAMEWORK_IDENTIFIER com.cmake.dynamicFramework
+ MACOSX_FRAMEWORK_INFO_PLIST Info.plist
+ # "current version" in semantic format in Mach-O binary file
+ VERSION 16.4.0
+ # "compatibility version" in semantic format in Mach-O binary file
+ SOVERSION 1.0.0
+ PUBLIC_HEADER dynamicFramework.h
+ XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer"
+ )
diff --git a/Help/prop_tgt/FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst b/Help/prop_tgt/FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst
new file mode 100644
index 0000000..84d0c1e
--- /dev/null
+++ b/Help/prop_tgt/FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst
@@ -0,0 +1,28 @@
+FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>
+---------------------------------------
+
+.. versionadded:: 3.18
+
+Postfix to append to the framework file name for configuration ``<CONFIG>``,
+when using a multi-config generator (like Xcode and Ninja Multi-Config).
+
+When building with configuration ``<CONFIG>`` the value of this property
+is appended to the framework file name built on disk.
+
+For example, given a framework called ``my_fw``, a value of ``_debug``
+for the ``FRAMEWORK_MULTI_CONFIG_POSTFIX_DEBUG`` property, and
+``Debug;Release`` in :variable:`CMAKE_CONFIGURATION_TYPES`, the following
+relevant files would be created for the ``Debug`` and ``Release``
+configurations:
+
+- ``Release/my_fw.framework/my_fw``
+- ``Release/my_fw.framework/Versions/A/my_fw``
+- ``Debug/my_fw.framework/my_fw_debug``
+- ``Debug/my_fw.framework/Versions/A/my_fw_debug``
+
+For framework targets, this property is initialized by the value of the
+:variable:`CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>` variable if it
+is set when a target is created.
+
+This property is ignored for non-framework targets, and when using single
+config generators.
diff --git a/Help/prop_tgt/FRAMEWORK_VERSION.rst b/Help/prop_tgt/FRAMEWORK_VERSION.rst
new file mode 100644
index 0000000..38b8137
--- /dev/null
+++ b/Help/prop_tgt/FRAMEWORK_VERSION.rst
@@ -0,0 +1,10 @@
+FRAMEWORK_VERSION
+-----------------
+
+.. versionadded:: 3.4
+
+Version of a framework created using the :prop_tgt:`FRAMEWORK` target
+property (e.g. ``A``).
+
+This property only affects macOS, as iOS doesn't have versioned
+directory structure.
diff --git a/Help/prop_tgt/Fortran_FORMAT.rst b/Help/prop_tgt/Fortran_FORMAT.rst
new file mode 100644
index 0000000..8704e5f
--- /dev/null
+++ b/Help/prop_tgt/Fortran_FORMAT.rst
@@ -0,0 +1,11 @@
+Fortran_FORMAT
+--------------
+
+Set to ``FIXED`` or ``FREE`` to indicate the Fortran source layout.
+
+This property tells CMake whether the Fortran source files in a target
+use fixed-format or free-format. CMake will pass the corresponding
+format flag to the compiler. Use the source-specific ``Fortran_FORMAT``
+property to change the format of a specific source file. If the
+variable :variable:`CMAKE_Fortran_FORMAT` is set when a target is created its
+value is used to initialize this property.
diff --git a/Help/prop_tgt/Fortran_MODULE_DIRECTORY.rst b/Help/prop_tgt/Fortran_MODULE_DIRECTORY.rst
new file mode 100644
index 0000000..84029e4
--- /dev/null
+++ b/Help/prop_tgt/Fortran_MODULE_DIRECTORY.rst
@@ -0,0 +1,25 @@
+Fortran_MODULE_DIRECTORY
+------------------------
+
+Specify output directory for Fortran modules provided by the target.
+
+If the target contains Fortran source files that provide modules and
+the compiler supports a module output directory this specifies the
+directory in which the modules will be placed. When this property is
+not set the modules will be placed in the build directory
+corresponding to the target's source directory. If the variable
+:variable:`CMAKE_Fortran_MODULE_DIRECTORY` is set when a target is created its
+value is used to initialize this property.
+
+When using one of the :ref:`Visual Studio Generators` with the Intel Fortran
+plugin installed in Visual Studio, a subdirectory named after the
+configuration will be appended to the path where modules are created.
+For example, if ``Fortran_MODULE_DIRECTORY`` is set to ``C:/some/path``,
+modules will end up in ``C:/some/path/Debug`` (or
+``C:/some/path/Release`` etc.) when an Intel Fortran ``.vfproj`` file is
+generated, and in ``C:/some/path`` when any other generator is used.
+
+Note that some compilers will automatically search the module output
+directory for modules USEd during compilation but others will not. If
+your sources USE modules their location must be specified by
+:prop_tgt:`INCLUDE_DIRECTORIES` regardless of this property.
diff --git a/Help/prop_tgt/Fortran_PREPROCESS.rst b/Help/prop_tgt/Fortran_PREPROCESS.rst
new file mode 100644
index 0000000..e7e2fba
--- /dev/null
+++ b/Help/prop_tgt/Fortran_PREPROCESS.rst
@@ -0,0 +1,25 @@
+Fortran_PREPROCESS
+------------------
+
+.. versionadded:: 3.18
+
+Control whether the Fortran source file should be unconditionally
+preprocessed.
+
+If unset or empty, rely on the compiler to determine whether the file
+should be preprocessed. If explicitly set to ``OFF`` then the file does not
+need to be preprocessed. If explicitly set to ``ON``, then the file does
+need to be preprocessed as part of the compilation step.
+
+When using the :generator:`Ninja` generator, all source files are
+first preprocessed in order to generate module dependency
+information. Setting this property to ``OFF`` will make ``Ninja``
+skip this step.
+
+Use the source-specific :prop_sf:`Fortran_PREPROCESS` property if a single
+file needs to be preprocessed. If the variable
+:variable:`CMAKE_Fortran_PREPROCESS` is set when a target is created its
+value is used to initialize this property.
+
+.. note:: For some compilers, ``NAG``, ``PGI`` and ``Solaris Studio``,
+ setting this to ``OFF`` will have no effect.
diff --git a/Help/prop_tgt/GENERATOR_FILE_NAME.rst b/Help/prop_tgt/GENERATOR_FILE_NAME.rst
new file mode 100644
index 0000000..a486105
--- /dev/null
+++ b/Help/prop_tgt/GENERATOR_FILE_NAME.rst
@@ -0,0 +1,9 @@
+GENERATOR_FILE_NAME
+-------------------
+
+Generator's file for this target.
+
+An internal property used by some generators to record the name of the
+project or dsp file associated with this target. Note that at
+configure time, this property is only set for targets created by
+:command:`include_external_msproject`.
diff --git a/Help/prop_tgt/GHS_INTEGRITY_APP.rst b/Help/prop_tgt/GHS_INTEGRITY_APP.rst
new file mode 100644
index 0000000..cccd087
--- /dev/null
+++ b/Help/prop_tgt/GHS_INTEGRITY_APP.rst
@@ -0,0 +1,12 @@
+GHS_INTEGRITY_APP
+-----------------
+
+.. versionadded:: 3.14
+
+``ON`` / ``OFF`` boolean to determine if an executable target should
+be treated as an `Integrity Application`.
+
+If no value is set and if a ``.int`` file is added as a source file to the
+executable target it will be treated as an `Integrity Application`.
+
+Supported on :generator:`Green Hills MULTI`.
diff --git a/Help/prop_tgt/GHS_NO_SOURCE_GROUP_FILE.rst b/Help/prop_tgt/GHS_NO_SOURCE_GROUP_FILE.rst
new file mode 100644
index 0000000..fe6b8e6
--- /dev/null
+++ b/Help/prop_tgt/GHS_NO_SOURCE_GROUP_FILE.rst
@@ -0,0 +1,15 @@
+GHS_NO_SOURCE_GROUP_FILE
+------------------------
+
+.. versionadded:: 3.14
+
+``ON`` / ``OFF`` boolean to control if the project file for a target should
+be one single file or multiple files.
+
+The default behavior or when the property is ``OFF`` is to generate a project
+file for the target and then a sub-project file for each source group.
+
+When this property is ``ON`` or if :variable:`CMAKE_GHS_NO_SOURCE_GROUP_FILE`
+is ``ON`` then only a single project file is generated for the target.
+
+Supported on :generator:`Green Hills MULTI`.
diff --git a/Help/prop_tgt/GNUtoMS.rst b/Help/prop_tgt/GNUtoMS.rst
new file mode 100644
index 0000000..a09ebbf
--- /dev/null
+++ b/Help/prop_tgt/GNUtoMS.rst
@@ -0,0 +1,17 @@
+GNUtoMS
+-------
+
+Convert GNU import library (``.dll.a``) to MS format (``.lib``).
+
+When linking a shared library or executable that exports symbols using
+GNU tools on Windows (MinGW/MSYS) with Visual Studio installed convert
+the import library (``.dll.a``) from GNU to MS format (``.lib``). Both import
+libraries will be installed by :command:`install(TARGETS)` and exported by
+:command:`install(EXPORT)` and :command:`export` to be linked
+by applications with either GNU- or MS-compatible tools.
+
+If the variable ``CMAKE_GNUtoMS`` is set when a target is created its
+value is used to initialize this property. The variable must be set
+prior to the first command that enables a language such as :command:`project`
+or :command:`enable_language`. CMake provides the variable as an option to the
+user automatically when configuring on Windows with GNU tools.
diff --git a/Help/prop_tgt/HAS_CXX.rst b/Help/prop_tgt/HAS_CXX.rst
new file mode 100644
index 0000000..15199b1
--- /dev/null
+++ b/Help/prop_tgt/HAS_CXX.rst
@@ -0,0 +1,7 @@
+HAS_CXX
+-------
+
+Link the target using the C++ linker tool (obsolete).
+
+This is equivalent to setting the :prop_tgt:`LINKER_LANGUAGE`
+property to ``CXX``.
diff --git a/Help/prop_tgt/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst b/Help/prop_tgt/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst
new file mode 100644
index 0000000..f7e366a
--- /dev/null
+++ b/Help/prop_tgt/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM.rst
@@ -0,0 +1,32 @@
+IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
+----------------------------------
+
+Specify ``#include`` line transforms for dependencies in a target.
+
+This property specifies rules to transform macro-like ``#include`` lines
+during implicit dependency scanning of C and C++ source files. The
+list of rules must be semicolon-separated with each entry of the form
+``A_MACRO(%)=value-with-%`` (the ``%`` must be literal). During dependency
+scanning occurrences of ``A_MACRO(...)`` on ``#include`` lines will be
+replaced by the value given with the macro argument substituted for
+``%``. For example, the entry
+
+::
+
+ MYDIR(%)=<mydir/%>
+
+will convert lines of the form
+
+::
+
+ #include MYDIR(myheader.h)
+
+to
+
+::
+
+ #include <mydir/myheader.h>
+
+allowing the dependency to be followed.
+
+This property applies to sources in the target on which it is set.
diff --git a/Help/prop_tgt/IMPORTED.rst b/Help/prop_tgt/IMPORTED.rst
new file mode 100644
index 0000000..22d28aa
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED.rst
@@ -0,0 +1,8 @@
+IMPORTED
+--------
+
+Read-only indication of whether a target is ``IMPORTED``.
+
+The boolean value of this property is ``True`` for targets created with
+the ``IMPORTED`` option to :command:`add_executable` or :command:`add_library`.
+It is ``False`` for targets built within the project.
diff --git a/Help/prop_tgt/IMPORTED_COMMON_LANGUAGE_RUNTIME.rst b/Help/prop_tgt/IMPORTED_COMMON_LANGUAGE_RUNTIME.rst
new file mode 100644
index 0000000..8c20e07
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_COMMON_LANGUAGE_RUNTIME.rst
@@ -0,0 +1,10 @@
+IMPORTED_COMMON_LANGUAGE_RUNTIME
+--------------------------------
+
+.. versionadded:: 3.12
+
+Property to define if the target uses ``C++/CLI``.
+
+Ignored for non-imported targets.
+
+See also the :prop_tgt:`COMMON_LANGUAGE_RUNTIME` target property.
diff --git a/Help/prop_tgt/IMPORTED_CONFIGURATIONS.rst b/Help/prop_tgt/IMPORTED_CONFIGURATIONS.rst
new file mode 100644
index 0000000..6de1baa
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_CONFIGURATIONS.rst
@@ -0,0 +1,11 @@
+IMPORTED_CONFIGURATIONS
+-----------------------
+
+Configurations provided for an IMPORTED target.
+
+Set this to the list of configuration names available for an IMPORTED
+target. The names correspond to configurations defined in the project
+from which the target is imported. If the importing project uses a
+different set of configurations the names may be mapped using the
+MAP_IMPORTED_CONFIG_<CONFIG> property. Ignored for non-imported
+targets.
diff --git a/Help/prop_tgt/IMPORTED_GLOBAL.rst b/Help/prop_tgt/IMPORTED_GLOBAL.rst
new file mode 100644
index 0000000..176127f
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_GLOBAL.rst
@@ -0,0 +1,32 @@
+IMPORTED_GLOBAL
+---------------
+
+.. versionadded:: 3.11
+
+Indication of whether an :ref:`IMPORTED target <Imported Targets>` is
+globally visible.
+
+The boolean value of this property is True for targets created with the
+``IMPORTED`` ``GLOBAL`` options to :command:`add_executable()` or
+:command:`add_library()`. It is always False for targets built within the
+project.
+
+For targets created with the ``IMPORTED`` option to
+:command:`add_executable()` or :command:`add_library()` but without the
+additional option ``GLOBAL`` this is False, too. However, setting this
+property for such a locally ``IMPORTED`` target to True promotes that
+target to global scope. This promotion can only be done in the same
+directory where that ``IMPORTED`` target was created in the first place.
+
+.. note::
+
+ Once an imported target has been made global, it cannot be changed back to
+ non-global. Therefore, if a project sets this property, it may only
+ provide a value of True. CMake will issue an error if the project tries to
+ set the property to a non-True value, even if the value was already False.
+
+.. note::
+
+ Local :ref:`ALIAS targets <Alias Targets>` created before promoting an
+ :ref:`IMPORTED target <Imported Targets>` from ``LOCAL`` to ``GLOBAL``, keep
+ their initial scope (see :prop_tgt:`ALIAS_GLOBAL` target property).
diff --git a/Help/prop_tgt/IMPORTED_IMPLIB.rst b/Help/prop_tgt/IMPORTED_IMPLIB.rst
new file mode 100644
index 0000000..c8b6fde
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_IMPLIB.rst
@@ -0,0 +1,9 @@
+IMPORTED_IMPLIB
+---------------
+
+Full path to the import library for an ``IMPORTED`` target.
+
+Set this to the location of the ``.lib`` part of a Windows DLL, or on
+AIX set it to an import file created for executables that export symbols
+(see the :prop_tgt:`ENABLE_EXPORTS` target property).
+Ignored for non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_IMPLIB_CONFIG.rst b/Help/prop_tgt/IMPORTED_IMPLIB_CONFIG.rst
new file mode 100644
index 0000000..5debabc
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_IMPLIB_CONFIG.rst
@@ -0,0 +1,7 @@
+IMPORTED_IMPLIB_<CONFIG>
+------------------------
+
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_IMPLIB` property.
+
+Configuration names correspond to those provided by the project from
+which the target is imported.
diff --git a/Help/prop_tgt/IMPORTED_LIBNAME.rst b/Help/prop_tgt/IMPORTED_LIBNAME.rst
new file mode 100644
index 0000000..7a83906
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_LIBNAME.rst
@@ -0,0 +1,25 @@
+IMPORTED_LIBNAME
+----------------
+
+.. versionadded:: 3.8
+
+Specify the link library name for an :ref:`imported <Imported Targets>`
+:ref:`Interface Library <Interface Libraries>`.
+
+An interface library builds no library file itself but does specify
+usage requirements for its consumers. The ``IMPORTED_LIBNAME``
+property may be set to specify a single library name to be placed
+on the link line in place of the interface library target name as
+a requirement for using the interface.
+
+This property is intended for use in naming libraries provided by
+a platform SDK for which the full path to a library file may not
+be known. The value may be a plain library name such as ``foo``
+but may *not* be a path (e.g. ``/usr/lib/libfoo.so``) or a flag
+(e.g. ``-Wl,...``). The name is never treated as a library target
+name even if it happens to name one.
+
+The ``IMPORTED_LIBNAME`` property is allowed only on
+:ref:`imported <Imported Targets>` :ref:`Interface Libraries`
+and is rejected on targets of other types (for which
+the :prop_tgt:`IMPORTED_LOCATION` target property may be used).
diff --git a/Help/prop_tgt/IMPORTED_LIBNAME_CONFIG.rst b/Help/prop_tgt/IMPORTED_LIBNAME_CONFIG.rst
new file mode 100644
index 0000000..df64769
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_LIBNAME_CONFIG.rst
@@ -0,0 +1,9 @@
+IMPORTED_LIBNAME_<CONFIG>
+-------------------------
+
+.. versionadded:: 3.8
+
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LIBNAME` property.
+
+Configuration names correspond to those provided by the project from
+which the target is imported.
diff --git a/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES.rst b/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES.rst
new file mode 100644
index 0000000..f7e2165
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES.rst
@@ -0,0 +1,14 @@
+IMPORTED_LINK_DEPENDENT_LIBRARIES
+---------------------------------
+
+Dependent shared libraries of an imported shared library.
+
+Shared libraries may be linked to other shared libraries as part of
+their implementation. On some platforms the linker searches for the
+dependent libraries of shared libraries they are including in the
+link. Set this property to the list of dependent shared libraries of
+an imported library. The list should be disjoint from the list of
+interface libraries in the :prop_tgt:`INTERFACE_LINK_LIBRARIES` property. On
+platforms requiring dependent shared libraries to be found at link
+time CMake uses this list to add appropriate files or paths to the
+link command line. Ignored for non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG.rst b/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG.rst
new file mode 100644
index 0000000..5b9c513
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG.rst
@@ -0,0 +1,8 @@
+IMPORTED_LINK_DEPENDENT_LIBRARIES_<CONFIG>
+------------------------------------------
+
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LINK_DEPENDENT_LIBRARIES`.
+
+Configuration names correspond to those provided by the project from
+which the target is imported. If set, this property completely
+overrides the generic property for the named configuration.
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES.rst
new file mode 100644
index 0000000..4ed4281
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES.rst
@@ -0,0 +1,14 @@
+IMPORTED_LINK_INTERFACE_LANGUAGES
+---------------------------------
+
+Languages compiled into an ``IMPORTED`` static library.
+
+Set this to the list of languages of source files compiled to produce
+a ``STATIC IMPORTED`` library (such as ``C`` or ``CXX``). CMake accounts for
+these languages when computing how to link a target to the imported
+library. For example, when a C executable links to an imported C++
+static library CMake chooses the C++ linker to satisfy language
+runtime dependencies of the static library.
+
+This property is ignored for targets that are not ``STATIC`` libraries.
+This property is ignored for non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG.rst
new file mode 100644
index 0000000..40fcf7f
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG.rst
@@ -0,0 +1,8 @@
+IMPORTED_LINK_INTERFACE_LANGUAGES_<CONFIG>
+------------------------------------------
+
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LINK_INTERFACE_LANGUAGES`.
+
+Configuration names correspond to those provided by the project from
+which the target is imported. If set, this property completely
+overrides the generic property for the named configuration.
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES.rst
new file mode 100644
index 0000000..527cf2e
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES.rst
@@ -0,0 +1,16 @@
+IMPORTED_LINK_INTERFACE_LIBRARIES
+---------------------------------
+
+Transitive link interface of an ``IMPORTED`` target.
+
+Set this to the list of libraries whose interface is included when an
+``IMPORTED`` library target is linked to another target. The libraries
+will be included on the link line for the target. Unlike the
+:prop_tgt:`LINK_INTERFACE_LIBRARIES` property, this property applies to all
+imported target types, including ``STATIC`` libraries. This property is
+ignored for non-imported targets.
+
+This property is ignored if the target also has a non-empty
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` property.
+
+This property is deprecated. Use :prop_tgt:`INTERFACE_LINK_LIBRARIES` instead.
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES_CONFIG.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES_CONFIG.rst
new file mode 100644
index 0000000..050fb1d
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_LIBRARIES_CONFIG.rst
@@ -0,0 +1,13 @@
+IMPORTED_LINK_INTERFACE_LIBRARIES_<CONFIG>
+------------------------------------------
+
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LINK_INTERFACE_LIBRARIES`.
+
+Configuration names correspond to those provided by the project from
+which the target is imported. If set, this property completely
+overrides the generic property for the named configuration.
+
+This property is ignored if the target also has a non-empty
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` property.
+
+This property is deprecated. Use :prop_tgt:`INTERFACE_LINK_LIBRARIES` instead.
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY.rst
new file mode 100644
index 0000000..7a92d96
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY.rst
@@ -0,0 +1,6 @@
+IMPORTED_LINK_INTERFACE_MULTIPLICITY
+------------------------------------
+
+Repetition count for cycles of ``IMPORTED`` static libraries.
+
+This is :prop_tgt:`LINK_INTERFACE_MULTIPLICITY` for ``IMPORTED`` targets.
diff --git a/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY_CONFIG.rst b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
new file mode 100644
index 0000000..758237b
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
@@ -0,0 +1,7 @@
+IMPORTED_LINK_INTERFACE_MULTIPLICITY_<CONFIG>
+---------------------------------------------
+
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LINK_INTERFACE_MULTIPLICITY`.
+
+If set, this property completely overrides the generic property for
+the named configuration.
diff --git a/Help/prop_tgt/IMPORTED_LOCATION.rst b/Help/prop_tgt/IMPORTED_LOCATION.rst
new file mode 100644
index 0000000..ddd910a
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_LOCATION.rst
@@ -0,0 +1,31 @@
+IMPORTED_LOCATION
+-----------------
+
+Full path to the main file on disk for an ``IMPORTED`` target.
+
+Set this to the location of an ``IMPORTED`` target file on disk. For
+executables this is the location of the executable file. For ``STATIC``
+libraries and modules this is the location of the library or module.
+For ``SHARED`` libraries on non-DLL platforms this is the location of the
+shared library. For application bundles on macOS this is the location of
+the executable file inside ``Contents/MacOS`` within the bundle folder.
+For frameworks on macOS this is the location of the
+library file symlink just inside the framework folder. For DLLs this
+is the location of the ``.dll`` part of the library. For ``UNKNOWN``
+libraries this is the location of the file to be linked. Ignored for
+non-imported targets.
+
+The ``IMPORTED_LOCATION`` target property may be overridden for a
+given configuration ``<CONFIG>`` by the configuration-specific
+:prop_tgt:`IMPORTED_LOCATION_<CONFIG>` target property. Furthermore,
+the :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` target property may be
+used to map between a project's configurations and those of an imported
+target. If none of these is set then the name of any other configuration
+listed in the :prop_tgt:`IMPORTED_CONFIGURATIONS` target property may be
+selected and its :prop_tgt:`IMPORTED_LOCATION_<CONFIG>` value used.
+
+To get the location of an imported target read one of the :prop_tgt:`LOCATION`
+or ``LOCATION_<CONFIG>`` properties.
+
+For platforms with import libraries (e.g. Windows) see also
+:prop_tgt:`IMPORTED_IMPLIB`.
diff --git a/Help/prop_tgt/IMPORTED_LOCATION_CONFIG.rst b/Help/prop_tgt/IMPORTED_LOCATION_CONFIG.rst
new file mode 100644
index 0000000..c5f5f04
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_LOCATION_CONFIG.rst
@@ -0,0 +1,7 @@
+IMPORTED_LOCATION_<CONFIG>
+--------------------------
+
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_LOCATION` property.
+
+Configuration names correspond to those provided by the project from
+which the target is imported.
diff --git a/Help/prop_tgt/IMPORTED_NO_SONAME.rst b/Help/prop_tgt/IMPORTED_NO_SONAME.rst
new file mode 100644
index 0000000..cbb7642
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_NO_SONAME.rst
@@ -0,0 +1,9 @@
+IMPORTED_NO_SONAME
+------------------
+
+Specifies that an ``IMPORTED`` shared library target has no ``soname``.
+
+Set this property to true for an imported shared library file that has
+no ``soname`` field. CMake may adjust generated link commands for some
+platforms to prevent the linker from using the path to the library in
+place of its missing ``soname``. Ignored for non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_NO_SONAME_CONFIG.rst b/Help/prop_tgt/IMPORTED_NO_SONAME_CONFIG.rst
new file mode 100644
index 0000000..76fe471
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_NO_SONAME_CONFIG.rst
@@ -0,0 +1,7 @@
+IMPORTED_NO_SONAME_<CONFIG>
+---------------------------
+
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_NO_SONAME` property.
+
+Configuration names correspond to those provided by the project from
+which the target is imported.
diff --git a/Help/prop_tgt/IMPORTED_OBJECTS.rst b/Help/prop_tgt/IMPORTED_OBJECTS.rst
new file mode 100644
index 0000000..f3577eb
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_OBJECTS.rst
@@ -0,0 +1,93 @@
+IMPORTED_OBJECTS
+----------------
+
+.. versionadded:: 3.9
+
+A :ref:`semicolon-separated list <CMake Language Lists>` of absolute paths
+to the object files on disk for an :ref:`imported <Imported targets>`
+:ref:`object library <object libraries>`.
+
+Ignored for non-imported targets.
+
+Projects may skip ``IMPORTED_OBJECTS`` if the configuration-specific
+property :prop_tgt:`IMPORTED_OBJECTS_<CONFIG>` is set instead, except in
+situations as noted in the section below.
+
+
+Xcode Generator Considerations
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.20
+
+For Apple platforms, a project may be built for more than one architecture.
+This is controlled by the :variable:`CMAKE_OSX_ARCHITECTURES` variable.
+For all but the :generator:`Xcode` generator, CMake invokes compilers once
+per source file and passes multiple ``-arch`` flags, leading to a single
+object file which will be a universal binary. Such object files work well
+when listed in the ``IMPORTED_OBJECTS`` of a separate CMake build, even for
+the :generator:`Xcode` generator. But producing such object files with the
+:generator:`Xcode` generator is more difficult, since it invokes the compiler
+once per architecture for each source file. Unlike the other generators,
+it does not generate universal object file binaries.
+
+A further complication with the :generator:`Xcode` generator is that when
+targeting device platforms (iOS, tvOS or watchOS), the :generator:`Xcode`
+generator has the ability to use either the device or simulator SDK without
+needing CMake to be re-run. The SDK can be selected at build time.
+But since some architectures can be supported by both the device and the
+simulator SDKs (e.g. ``arm64`` with Xcode 12 or later), not all combinations
+can be represented in a single universal binary. The only solution in this
+case is to have multiple object files.
+
+``IMPORTED_OBJECTS`` doesn't support generator expressions, so every file
+it lists needs to be valid for every architecture and SDK. If incorporating
+object files that are not universal binaries, the path and/or file name of
+each object file has to somehow encapsulate the different architectures and
+SDKs. With the :generator:`Xcode` generator, Xcode variables of the form
+``$(...)`` can be used to represent these aspects and Xcode will substitute
+the appropriate values at build time. CMake doesn't interpret these
+variables and embeds them unchanged in the Xcode project file.
+``$(CURRENT_ARCH)`` can be used to represent the architecture, while
+``$(EFFECTIVE_PLATFORM_NAME)`` can be used to differentiate between SDKs.
+
+The following shows one example of how these two variables can be used to
+refer to an object file whose location depends on both the SDK and the
+architecture:
+
+.. code-block:: cmake
+
+ add_library(someObjs OBJECT IMPORTED)
+
+ set_property(TARGET someObjs PROPERTY IMPORTED_OBJECTS
+ # Quotes are required because of the ()
+ "/path/to/somewhere/objects$(EFFECTIVE_PLATFORM_NAME)/$(CURRENT_ARCH)/func.o"
+ )
+
+ # Example paths:
+ # /path/to/somewhere/objects-iphoneos/arm64/func.o
+ # /path/to/somewhere/objects-iphonesimulator/x86_64/func.o
+
+In some cases, you may want to have configuration-specific object files
+as well. The :variable:`CMAKE_CFG_INTDIR` variable can be a convenient
+way of capturing this in combination with the SDK:
+
+.. code-block:: cmake
+
+ add_library(someObjs OBJECT IMPORTED)
+ set_property(TARGET someObjs PROPERTY IMPORTED_OBJECTS
+ "/path/to/somewhere/${CMAKE_CFG_INTDIR}/$(CURRENT_ARCH)/func.o"
+ )
+
+ # Example paths:
+ # /path/to/somewhere/Release-iphoneos/arm64/func.o
+ # /path/to/somewhere/Debug-iphonesimulator/x86_64/func.o
+
+When any Xcode variable or :variable:`CMAKE_CFG_INTDIR` is used, CMake is
+not able to fully evaluate the path(s) at configure time. One consequence
+of this is that the configuration-specific
+:prop_tgt:`IMPORTED_OBJECTS_<CONFIG>` properties cannot be used, since
+CMake cannot determine whether an object file exists at a particular
+``<CONFIG>`` location. The ``IMPORTED_OBJECTS`` property must be used for
+these situations and the configuration-specific aspects of the path must be
+handled by using :variable:`CMAKE_CFG_INTDIR` or with another Xcode variable
+``$(CONFIGURATION)``.
diff --git a/Help/prop_tgt/IMPORTED_OBJECTS_CONFIG.rst b/Help/prop_tgt/IMPORTED_OBJECTS_CONFIG.rst
new file mode 100644
index 0000000..238395a
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_OBJECTS_CONFIG.rst
@@ -0,0 +1,20 @@
+IMPORTED_OBJECTS_<CONFIG>
+-------------------------
+
+.. versionadded:: 3.9
+
+``<CONFIG>``-specific version of :prop_tgt:`IMPORTED_OBJECTS` property.
+
+Configuration names correspond to those provided by the project from
+which the target is imported.
+
+
+Xcode Generator Considerations
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Do not use this ``<CONFIG>``-specific property if you need to use Xcode
+variables like ``$(CURRENT_ARCH)`` or ``$(EFFECTIVE_PLATFORM_NAME)`` in
+the value. The ``<CONFIG>``-specific properties will be ignored in such
+cases because CMake cannot determine whether a file exists at the
+configuration-specific path at configuration time. For such cases, use
+:prop_tgt:`IMPORTED_OBJECTS` instead.
diff --git a/Help/prop_tgt/IMPORTED_SONAME.rst b/Help/prop_tgt/IMPORTED_SONAME.rst
new file mode 100644
index 0000000..bf0c3cb
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_SONAME.rst
@@ -0,0 +1,8 @@
+IMPORTED_SONAME
+---------------
+
+The ``soname`` of an ``IMPORTED`` target of shared library type.
+
+Set this to the ``soname`` embedded in an imported shared library. This
+is meaningful only on platforms supporting the feature. Ignored for
+non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_SONAME_CONFIG.rst b/Help/prop_tgt/IMPORTED_SONAME_CONFIG.rst
new file mode 100644
index 0000000..59a9d1a
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_SONAME_CONFIG.rst
@@ -0,0 +1,7 @@
+IMPORTED_SONAME_<CONFIG>
+------------------------
+
+<CONFIG>-specific version of :prop_tgt:`IMPORTED_SONAME` property.
+
+Configuration names correspond to those provided by the project from
+which the target is imported.
diff --git a/Help/prop_tgt/IMPORT_PREFIX.rst b/Help/prop_tgt/IMPORT_PREFIX.rst
new file mode 100644
index 0000000..17e381b
--- /dev/null
+++ b/Help/prop_tgt/IMPORT_PREFIX.rst
@@ -0,0 +1,9 @@
+IMPORT_PREFIX
+-------------
+
+What comes before the import library name.
+
+Similar to the target property :prop_tgt:`PREFIX`, but used for import libraries
+(typically corresponding to a ``DLL``) instead of regular libraries. A
+target property that can be set to override the prefix (such as ``lib``)
+on an import library name.
diff --git a/Help/prop_tgt/IMPORT_SUFFIX.rst b/Help/prop_tgt/IMPORT_SUFFIX.rst
new file mode 100644
index 0000000..9307115
--- /dev/null
+++ b/Help/prop_tgt/IMPORT_SUFFIX.rst
@@ -0,0 +1,9 @@
+IMPORT_SUFFIX
+-------------
+
+What comes after the import library name.
+
+Similar to the target property :prop_tgt:`SUFFIX`, but used
+for import libraries (typically corresponding to a ``DLL``) instead of
+regular libraries. A target property that can be set to override
+the suffix (such as ``.lib``) on an import library name.
diff --git a/Help/prop_tgt/INCLUDE_DIRECTORIES.rst b/Help/prop_tgt/INCLUDE_DIRECTORIES.rst
new file mode 100644
index 0000000..b381d1d
--- /dev/null
+++ b/Help/prop_tgt/INCLUDE_DIRECTORIES.rst
@@ -0,0 +1,24 @@
+INCLUDE_DIRECTORIES
+-------------------
+
+List of preprocessor include file search directories.
+
+This property specifies the list of directories given so far to the
+:command:`target_include_directories` command. In addition to accepting
+values from that command, values may be set directly on any
+target using the :command:`set_property` command. A target gets its
+initial value for this property from the value of the
+:prop_dir:`INCLUDE_DIRECTORIES` directory property. Both directory and
+target property values are adjusted by calls to the
+:command:`include_directories` command.
+
+The value of this property is used by the generators to set the include
+paths for the compiler.
+
+Relative paths should not be added to this property directly. Use one of
+the commands above instead to handle relative paths.
+
+Contents of ``INCLUDE_DIRECTORIES`` may use :manual:`cmake-generator-expressions(7)` with
+the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
diff --git a/Help/prop_tgt/INSTALL_NAME_DIR.rst b/Help/prop_tgt/INSTALL_NAME_DIR.rst
new file mode 100644
index 0000000..47a0037
--- /dev/null
+++ b/Help/prop_tgt/INSTALL_NAME_DIR.rst
@@ -0,0 +1,18 @@
+INSTALL_NAME_DIR
+----------------
+
+Directory name for installed targets on Apple platforms.
+
+``INSTALL_NAME_DIR`` is a string specifying the directory portion of the
+"install_name" field of shared libraries on Apple platforms for
+installed targets. When not set, the default directory used is determined
+by :prop_tgt:`MACOSX_RPATH`. Policies :policy:`CMP0068` and :policy:`CMP0042`
+are also relevant.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_INSTALL_NAME_DIR` if it is set when a target is
+created.
+
+This property supports :manual:`generator expressions <cmake-generator-expressions(7)>`.
+In particular, the :genex:`$<INSTALL_PREFIX>` generator expression can be
+used to set the directory relative to the install-time prefix.
diff --git a/Help/prop_tgt/INSTALL_REMOVE_ENVIRONMENT_RPATH.rst b/Help/prop_tgt/INSTALL_REMOVE_ENVIRONMENT_RPATH.rst
new file mode 100644
index 0000000..f41e41c
--- /dev/null
+++ b/Help/prop_tgt/INSTALL_REMOVE_ENVIRONMENT_RPATH.rst
@@ -0,0 +1,18 @@
+INSTALL_REMOVE_ENVIRONMENT_RPATH
+--------------------------------
+
+.. versionadded:: 3.16
+
+Controls whether toolchain-defined rpaths should be removed during installation.
+
+When a target is being installed, CMake may need to rewrite its rpath
+information. This occurs when the install rpath (as specified by the
+:prop_tgt:`INSTALL_RPATH` target property) has different contents to the rpath
+that the target was built with. Some toolchains insert their own rpath
+contents into the binary as part of the build. By default, CMake will
+preserve those extra inserted contents in the install rpath. For those
+scenarios where such toolchain-inserted entries need to be discarded during
+install, set the ``INSTALL_REMOVE_ENVIRONMENT_RPATH`` target property to true.
+
+This property is initialized by the value of
+:variable:`CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH` when the target is created.
diff --git a/Help/prop_tgt/INSTALL_RPATH.rst b/Help/prop_tgt/INSTALL_RPATH.rst
new file mode 100644
index 0000000..4549b92
--- /dev/null
+++ b/Help/prop_tgt/INSTALL_RPATH.rst
@@ -0,0 +1,16 @@
+INSTALL_RPATH
+-------------
+
+The rpath to use for installed targets.
+
+A semicolon-separated list specifying the rpath to use in installed
+targets (for platforms that support it). This property is initialized
+by the value of the variable :variable:`CMAKE_INSTALL_RPATH` if it is set when
+a target is created.
+
+Because the rpath may contain ``${ORIGIN}``, which coincides with CMake syntax,
+the contents of ``INSTALL_RPATH`` are properly escaped in the
+``cmake_install.cmake`` script (see policy :policy:`CMP0095`.)
+
+This property supports
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst b/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst
new file mode 100644
index 0000000..d16a7a1
--- /dev/null
+++ b/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst
@@ -0,0 +1,14 @@
+INSTALL_RPATH_USE_LINK_PATH
+---------------------------
+
+Add paths to linker search and installed rpath.
+
+``INSTALL_RPATH_USE_LINK_PATH`` is a boolean that if set to ``True``
+will append to the runtime search path (rpath) of installed binaries
+any directories outside the project that are in the linker search path or
+contain linked library files. The directories are appended after the
+value of the :prop_tgt:`INSTALL_RPATH` target property.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_INSTALL_RPATH_USE_LINK_PATH` if it is set when a target is
+created.
diff --git a/Help/prop_tgt/INTERFACE_AUTOUIC_OPTIONS.rst b/Help/prop_tgt/INTERFACE_AUTOUIC_OPTIONS.rst
new file mode 100644
index 0000000..e97d293
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_AUTOUIC_OPTIONS.rst
@@ -0,0 +1,14 @@
+INTERFACE_AUTOUIC_OPTIONS
+-------------------------
+
+List of interface options to pass to uic.
+
+Targets may populate this property to publish the options
+required to use when invoking ``uic``. Consuming targets can add entries to their
+own :prop_tgt:`AUTOUIC_OPTIONS` property such as
+``$<TARGET_PROPERTY:foo,INTERFACE_AUTOUIC_OPTIONS>`` to use the uic options
+specified in the interface of ``foo``. This is done automatically by
+the :command:`target_link_libraries` command.
+
+This property supports generator expressions. See the
+:manual:`cmake-generator-expressions(7)` manual for available expressions.
diff --git a/Help/prop_tgt/INTERFACE_BUILD_PROPERTY.txt b/Help/prop_tgt/INTERFACE_BUILD_PROPERTY.txt
new file mode 100644
index 0000000..4188b8d
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_BUILD_PROPERTY.txt
@@ -0,0 +1,16 @@
+
+List of public |property_name| requirements for a library.
+
+Targets may populate this property to publish the |property_name|
+required to compile against the headers for the target. The |command_name|
+command populates this property with values given to the ``PUBLIC`` and
+``INTERFACE`` keywords. Projects may also get and set the property directly.
+
+When target dependencies are specified using :command:`target_link_libraries`,
+CMake will read this property from all target dependencies to determine the
+build properties of the consumer.
+
+Contents of |PROPERTY_INTERFACE_NAME| may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+-manual for more on defining buildsystem properties.
diff --git a/Help/prop_tgt/INTERFACE_COMPILE_DEFINITIONS.rst b/Help/prop_tgt/INTERFACE_COMPILE_DEFINITIONS.rst
new file mode 100644
index 0000000..c74a319
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_COMPILE_DEFINITIONS.rst
@@ -0,0 +1,9 @@
+INTERFACE_COMPILE_DEFINITIONS
+-----------------------------
+
+.. |property_name| replace:: compile definitions
+.. |command_name| replace:: :command:`target_compile_definitions`
+.. |PROPERTY_INTERFACE_NAME| replace:: ``INTERFACE_COMPILE_DEFINITIONS``
+.. |PROPERTY_LINK| replace:: :prop_tgt:`COMPILE_DEFINITIONS`
+.. |PROPERTY_GENEX| replace:: ``$<TARGET_PROPERTY:foo,INTERFACE_COMPILE_DEFINITIONS>``
+.. include:: INTERFACE_BUILD_PROPERTY.txt
diff --git a/Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst b/Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst
new file mode 100644
index 0000000..0db3b0c
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst
@@ -0,0 +1,14 @@
+INTERFACE_COMPILE_FEATURES
+--------------------------
+
+.. versionadded:: 3.1
+
+.. |property_name| replace:: compile features
+.. |command_name| replace:: :command:`target_compile_features`
+.. |PROPERTY_INTERFACE_NAME| replace:: ``INTERFACE_COMPILE_FEATURES``
+.. |PROPERTY_LINK| replace:: :prop_tgt:`COMPILE_FEATURES`
+.. |PROPERTY_GENEX| replace:: ``$<TARGET_PROPERTY:foo,INTERFACE_COMPILE_FEATURES>``
+.. include:: INTERFACE_BUILD_PROPERTY.txt
+
+See the :manual:`cmake-compile-features(7)` manual for information on compile
+features and a list of supported compilers.
diff --git a/Help/prop_tgt/INTERFACE_COMPILE_OPTIONS.rst b/Help/prop_tgt/INTERFACE_COMPILE_OPTIONS.rst
new file mode 100644
index 0000000..7f0b385
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_COMPILE_OPTIONS.rst
@@ -0,0 +1,9 @@
+INTERFACE_COMPILE_OPTIONS
+-------------------------
+
+.. |property_name| replace:: compile options
+.. |command_name| replace:: :command:`target_compile_options`
+.. |PROPERTY_INTERFACE_NAME| replace:: ``INTERFACE_COMPILE_OPTIONS``
+.. |PROPERTY_LINK| replace:: :prop_tgt:`COMPILE_OPTIONS`
+.. |PROPERTY_GENEX| replace:: ``$<TARGET_PROPERTY:foo,INTERFACE_COMPILE_OPTIONS>``
+.. include:: INTERFACE_BUILD_PROPERTY.txt
diff --git a/Help/prop_tgt/INTERFACE_INCLUDE_DIRECTORIES.rst b/Help/prop_tgt/INTERFACE_INCLUDE_DIRECTORIES.rst
new file mode 100644
index 0000000..b1c40b2
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_INCLUDE_DIRECTORIES.rst
@@ -0,0 +1,29 @@
+INTERFACE_INCLUDE_DIRECTORIES
+-----------------------------
+
+.. |property_name| replace:: include directories
+.. |command_name| replace:: :command:`target_include_directories`
+.. |PROPERTY_INTERFACE_NAME| replace:: ``INTERFACE_INCLUDE_DIRECTORIES``
+.. |PROPERTY_LINK| replace:: :prop_tgt:`INCLUDE_DIRECTORIES`
+.. |PROPERTY_GENEX| replace:: ``$<TARGET_PROPERTY:foo,INTERFACE_INCLUDE_DIRECTORIES>``
+.. include:: INTERFACE_BUILD_PROPERTY.txt
+
+Include directories usage requirements commonly differ between the build-tree
+and the install-tree. The ``BUILD_INTERFACE`` and ``INSTALL_INTERFACE``
+generator expressions can be used to describe separate usage requirements
+based on the usage location. Relative paths are allowed within the
+``INSTALL_INTERFACE`` expression and are interpreted relative to the
+installation prefix. For example:
+
+.. code-block:: cmake
+
+ target_include_directories(mylib INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/mylib>
+ $<INSTALL_INTERFACE:include/mylib> # <prefix>/include/mylib
+ )
+
+Creating Relocatable Packages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. |INTERFACE_PROPERTY_LINK| replace:: ``INTERFACE_INCLUDE_DIRECTORIES``
+.. include:: /include/INTERFACE_INCLUDE_DIRECTORIES_WARNING.txt
diff --git a/Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst b/Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst
new file mode 100644
index 0000000..9c8275d
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst
@@ -0,0 +1,34 @@
+INTERFACE_LINK_DEPENDS
+----------------------
+
+.. versionadded:: 3.13
+
+Additional public interface files on which a target binary depends for linking.
+
+This property is supported only by :generator:`Ninja` and
+:ref:`Makefile Generators`.
+It is intended to specify dependencies on "linker scripts" for
+custom Makefile link rules.
+
+When target dependencies are specified using :command:`target_link_libraries`,
+CMake will read this property from all target dependencies to determine the
+build properties of the consumer.
+
+Contents of ``INTERFACE_LINK_DEPENDS`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+-manual for more on defining buildsystem properties.
+
+Link dependency files usage requirements commonly differ between the build-tree
+and the install-tree. The ``BUILD_INTERFACE`` and ``INSTALL_INTERFACE``
+generator expressions can be used to describe separate usage requirements
+based on the usage location. Relative paths are allowed within the
+``INSTALL_INTERFACE`` expression and are interpreted relative to the
+installation prefix. For example:
+
+.. code-block:: cmake
+
+ set_property(TARGET mylib PROPERTY INTERFACE_LINK_DEPENDS
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/mylinkscript>
+ $<INSTALL_INTERFACE:mylinkscript> # <prefix>/mylinkscript
+ )
diff --git a/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst b/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst
new file mode 100644
index 0000000..de1dabb
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst
@@ -0,0 +1,11 @@
+INTERFACE_LINK_DIRECTORIES
+--------------------------
+
+.. versionadded:: 3.13
+
+.. |property_name| replace:: link directories
+.. |command_name| replace:: :command:`target_link_directories`
+.. |PROPERTY_INTERFACE_NAME| replace:: ``INTERFACE_LINK_DIRECTORIES``
+.. |PROPERTY_LINK| replace:: :prop_tgt:`LINK_DIRECTORIES`
+.. |PROPERTY_GENEX| replace:: ``$<TARGET_PROPERTY:foo,INTERFACE_LINK_DIRECTORIES>``
+.. include:: INTERFACE_BUILD_PROPERTY.txt
diff --git a/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst b/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst
new file mode 100644
index 0000000..bf7f72f
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst
@@ -0,0 +1,26 @@
+INTERFACE_LINK_LIBRARIES
+------------------------
+
+List public interface libraries for a library.
+
+This property contains the list of transitive link dependencies. When
+the target is linked into another target using the
+:command:`target_link_libraries` command, the libraries listed (and
+recursively their link interface libraries) will be provided to the
+other target also. This property is overridden by the
+:prop_tgt:`LINK_INTERFACE_LIBRARIES` or
+:prop_tgt:`LINK_INTERFACE_LIBRARIES_<CONFIG>` property if policy
+:policy:`CMP0022` is ``OLD`` or unset.
+
+Contents of ``INTERFACE_LINK_LIBRARIES`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
+.. include:: LINK_LIBRARIES_INDIRECTION.txt
+
+Creating Relocatable Packages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. |INTERFACE_PROPERTY_LINK| replace:: ``INTERFACE_LINK_LIBRARIES``
+.. include:: /include/INTERFACE_LINK_LIBRARIES_WARNING.txt
diff --git a/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst b/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst
new file mode 100644
index 0000000..4245fe9
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst
@@ -0,0 +1,11 @@
+INTERFACE_LINK_OPTIONS
+----------------------
+
+.. versionadded:: 3.13
+
+.. |property_name| replace:: link options
+.. |command_name| replace:: :command:`target_link_options`
+.. |PROPERTY_INTERFACE_NAME| replace:: ``INTERFACE_LINK_OPTIONS``
+.. |PROPERTY_LINK| replace:: :prop_tgt:`LINK_OPTIONS`
+.. |PROPERTY_GENEX| replace:: ``$<TARGET_PROPERTY:foo,INTERFACE_LINK_OPTIONS>``
+.. include:: INTERFACE_BUILD_PROPERTY.txt
diff --git a/Help/prop_tgt/INTERFACE_POSITION_INDEPENDENT_CODE.rst b/Help/prop_tgt/INTERFACE_POSITION_INDEPENDENT_CODE.rst
new file mode 100644
index 0000000..4336d71
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_POSITION_INDEPENDENT_CODE.rst
@@ -0,0 +1,22 @@
+INTERFACE_POSITION_INDEPENDENT_CODE
+-----------------------------------
+
+Whether consumers need to create a position-independent target
+
+The ``INTERFACE_POSITION_INDEPENDENT_CODE`` property informs consumers of
+this target whether they must set their
+:prop_tgt:`POSITION_INDEPENDENT_CODE` property to ``ON``. If this
+property is set to ``ON``, then the :prop_tgt:`POSITION_INDEPENDENT_CODE`
+property on all consumers will be set to ``ON``. Similarly, if this
+property is set to ``OFF``, then the :prop_tgt:`POSITION_INDEPENDENT_CODE`
+property on all consumers will be set to ``OFF``. If this property is
+undefined, then consumers will determine their
+:prop_tgt:`POSITION_INDEPENDENT_CODE` property by other means. Consumers
+must ensure that the targets that they link to have a consistent
+requirement for their ``INTERFACE_POSITION_INDEPENDENT_CODE`` property.
+
+Contents of ``INTERFACE_POSITION_INDEPENDENT_CODE`` may use
+"generator expressions" with the syntax ``$<...>``. See the
+:manual:`cmake-generator-expressions(7)` manual for available expressions.
+See the :manual:`cmake-buildsystem(7)` manual for more on defining buildsystem
+properties.
diff --git a/Help/prop_tgt/INTERFACE_PRECOMPILE_HEADERS.rst b/Help/prop_tgt/INTERFACE_PRECOMPILE_HEADERS.rst
new file mode 100644
index 0000000..2299264
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_PRECOMPILE_HEADERS.rst
@@ -0,0 +1,18 @@
+INTERFACE_PRECOMPILE_HEADERS
+----------------------------
+
+.. versionadded:: 3.16
+
+List of interface header files to precompile into consuming targets.
+
+Targets may populate this property to publish the header files
+for consuming targets to precompile. The :command:`target_precompile_headers`
+command populates this property with values given to the ``PUBLIC`` and
+``INTERFACE`` keywords. Projects may also get and set the property directly.
+See the discussion in :command:`target_precompile_headers` for guidance on
+appropriate use of this property for installed or exported targets.
+
+Contents of ``INTERFACE_PRECOMPILE_HEADERS`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
diff --git a/Help/prop_tgt/INTERFACE_SOURCES.rst b/Help/prop_tgt/INTERFACE_SOURCES.rst
new file mode 100644
index 0000000..759c482
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_SOURCES.rst
@@ -0,0 +1,20 @@
+INTERFACE_SOURCES
+-----------------
+
+.. versionadded:: 3.1
+
+List of interface sources to compile into consuming targets.
+
+Targets may populate this property to publish the sources
+for consuming targets to compile. The :command:`target_sources` command
+populates this property with values given to the ``PUBLIC`` and
+``INTERFACE`` keywords. Projects may also get and set the property directly.
+
+When target dependencies are specified using :command:`target_link_libraries`,
+CMake will read this property from all target dependencies to determine the
+sources of the consumer.
+
+Contents of ``INTERFACE_SOURCES`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
diff --git a/Help/prop_tgt/INTERFACE_SYSTEM_INCLUDE_DIRECTORIES.rst b/Help/prop_tgt/INTERFACE_SYSTEM_INCLUDE_DIRECTORIES.rst
new file mode 100644
index 0000000..a0a97ad
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_SYSTEM_INCLUDE_DIRECTORIES.rst
@@ -0,0 +1,28 @@
+INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
+------------------------------------
+
+List of public system include directories for a library.
+
+Targets may populate this property to publish the include directories
+which contain system headers, and therefore should not result in
+compiler warnings. The :command:`target_include_directories(SYSTEM)`
+command signature populates this property with values given to the
+``PUBLIC`` and ``INTERFACE`` keywords.
+
+Projects may also get and set the property directly, but must be aware that
+adding directories to this property does not make those directories used
+during compilation. Adding directories to this property marks directories
+as ``SYSTEM`` which otherwise would be used in a non-``SYSTEM`` manner. This
+can appear similar to 'duplication', so prefer the
+high-level :command:`target_include_directories(SYSTEM)` command and avoid
+setting the property by low-level means.
+
+When target dependencies are specified using :command:`target_link_libraries`,
+CMake will read this property from all target dependencies to mark the
+same include directories as containing system headers.
+
+Contents of ``INTERFACE_SYSTEM_INCLUDE_DIRECTORIES`` may use "generator
+expressions" with the syntax ``$<...>``. See the
+:manual:`cmake-generator-expressions(7)` manual for available expressions.
+See the :manual:`cmake-buildsystem(7)` manual for more on defining
+buildsystem properties.
diff --git a/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst
new file mode 100644
index 0000000..d3a5e94
--- /dev/null
+++ b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst
@@ -0,0 +1,13 @@
+INTERPROCEDURAL_OPTIMIZATION
+----------------------------
+
+Enable interprocedural optimization for a target.
+
+If set to true, enables interprocedural optimizations if they are
+known :module:`to be supported <CheckIPOSupported>` by the compiler. Depending
+on value of policy :policy:`CMP0069`, the error will be reported or ignored,
+if interprocedural optimization is enabled but not supported.
+
+This property is initialized by the
+:variable:`CMAKE_INTERPROCEDURAL_OPTIMIZATION` variable if it is set when a
+target is created.
diff --git a/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
new file mode 100644
index 0000000..79d4604
--- /dev/null
+++ b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
@@ -0,0 +1,12 @@
+INTERPROCEDURAL_OPTIMIZATION_<CONFIG>
+-------------------------------------
+
+Per-configuration interprocedural optimization for a target.
+
+This is a per-configuration version of :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION`.
+If set, this property overrides the generic property for the named
+configuration.
+
+This property is initialized by the
+:variable:`CMAKE_INTERPROCEDURAL_OPTIMIZATION_<CONFIG>` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/IOS_INSTALL_COMBINED.rst b/Help/prop_tgt/IOS_INSTALL_COMBINED.rst
new file mode 100644
index 0000000..92d60dc
--- /dev/null
+++ b/Help/prop_tgt/IOS_INSTALL_COMBINED.rst
@@ -0,0 +1,19 @@
+IOS_INSTALL_COMBINED
+--------------------
+
+.. versionadded:: 3.5
+
+Build a combined (device and simulator) target when installing.
+
+When this property is set to set to false (which is the default) then it will
+either be built with the device SDK or the simulator SDK depending on the SDK
+set. But if this property is set to true then the target will at install time
+also be built for the corresponding SDK and combined into one library.
+
+.. note::
+
+ If a selected architecture is available for both: device SDK and simulator
+ SDK it will be built for the SDK selected by :variable:`CMAKE_OSX_SYSROOT`
+ and removed from the corresponding SDK.
+
+This feature requires at least Xcode version 6.
diff --git a/Help/prop_tgt/ISPC_HEADER_DIRECTORY.rst b/Help/prop_tgt/ISPC_HEADER_DIRECTORY.rst
new file mode 100644
index 0000000..2a3a8bc
--- /dev/null
+++ b/Help/prop_tgt/ISPC_HEADER_DIRECTORY.rst
@@ -0,0 +1,13 @@
+ISPC_HEADER_DIRECTORY
+---------------------
+
+.. versionadded:: 3.19
+
+Specify relative output directory for ISPC headers provided by the target.
+
+If the target contains ISPC source files, this specifies the directory in which
+the generated headers will be placed. Relative paths are treated with respect to
+the value of :variable:`CMAKE_CURRENT_BINARY_DIR`. When this property is not set, the
+headers will be placed a generator defined build directory. If the variable
+:variable:`CMAKE_ISPC_HEADER_DIRECTORY` is set when a target is created
+its value is used to initialize this property.
diff --git a/Help/prop_tgt/ISPC_HEADER_SUFFIX.rst b/Help/prop_tgt/ISPC_HEADER_SUFFIX.rst
new file mode 100644
index 0000000..6397e55
--- /dev/null
+++ b/Help/prop_tgt/ISPC_HEADER_SUFFIX.rst
@@ -0,0 +1,14 @@
+ISPC_HEADER_SUFFIX
+------------------
+
+.. versionadded:: 3.19.2
+
+Specify output suffix to be used for ISPC generated headers provided by the target.
+
+This property is initialized by the value of the :variable:`CMAKE_ISPC_HEADER_SUFFIX`
+variable if it is set when a target is created.
+
+If the target contains ISPC source files, this specifies the header suffix to
+be used for the generated headers.
+
+The default value is ``_ispc.h``.
diff --git a/Help/prop_tgt/ISPC_INSTRUCTION_SETS.rst b/Help/prop_tgt/ISPC_INSTRUCTION_SETS.rst
new file mode 100644
index 0000000..cad116f
--- /dev/null
+++ b/Help/prop_tgt/ISPC_INSTRUCTION_SETS.rst
@@ -0,0 +1,21 @@
+ISPC_INSTRUCTION_SETS
+---------------------
+
+.. versionadded:: 3.19
+
+List of instruction set architectures to generate code for.
+
+This property is initialized by the value of the :variable:`CMAKE_ISPC_INSTRUCTION_SETS`
+variable if it is set when a target is created.
+
+The ``ISPC_INSTRUCTION_SETS`` target property must be used when generating for multiple
+instruction sets so that CMake can track what object files will be generated.
+
+Examples
+^^^^^^^^
+
+.. code-block:: cmake
+
+ set_property(TARGET tgt PROPERTY ISPC_INSTRUCTION_SETS avx2-i32x4 avx512skx-i32x835)
+
+Generates code for avx2 and avx512skx target architectures.
diff --git a/Help/prop_tgt/JOB_POOL_COMPILE.rst b/Help/prop_tgt/JOB_POOL_COMPILE.rst
new file mode 100644
index 0000000..5d8e940
--- /dev/null
+++ b/Help/prop_tgt/JOB_POOL_COMPILE.rst
@@ -0,0 +1,17 @@
+JOB_POOL_COMPILE
+----------------
+
+Ninja only: Pool used for compiling.
+
+The number of parallel compile processes could be limited by defining
+pools with the global :prop_gbl:`JOB_POOLS`
+property and then specifying here the pool name.
+
+For instance:
+
+.. code-block:: cmake
+
+ set_property(TARGET myexe PROPERTY JOB_POOL_COMPILE ten_jobs)
+
+This property is initialized by the value of
+:variable:`CMAKE_JOB_POOL_COMPILE`.
diff --git a/Help/prop_tgt/JOB_POOL_LINK.rst b/Help/prop_tgt/JOB_POOL_LINK.rst
new file mode 100644
index 0000000..6535333
--- /dev/null
+++ b/Help/prop_tgt/JOB_POOL_LINK.rst
@@ -0,0 +1,16 @@
+JOB_POOL_LINK
+-------------
+
+Ninja only: Pool used for linking.
+
+The number of parallel link processes could be limited by defining
+pools with the global :prop_gbl:`JOB_POOLS`
+property and then specifying here the pool name.
+
+For instance:
+
+.. code-block:: cmake
+
+ set_property(TARGET myexe PROPERTY JOB_POOL_LINK two_jobs)
+
+This property is initialized by the value of :variable:`CMAKE_JOB_POOL_LINK`.
diff --git a/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst b/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst
new file mode 100644
index 0000000..42cace0
--- /dev/null
+++ b/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst
@@ -0,0 +1,23 @@
+JOB_POOL_PRECOMPILE_HEADER
+--------------------------
+
+.. versionadded:: 3.17
+
+Ninja only: Pool used for generating pre-compiled headers.
+
+The number of parallel compile processes could be limited by defining
+pools with the global :prop_gbl:`JOB_POOLS`
+property and then specifying here the pool name.
+
+For instance:
+
+.. code-block:: cmake
+
+ set_property(TARGET myexe PROPERTY JOB_POOL_PRECOMPILE_HEADER two_jobs)
+
+This property is initialized by the value of
+:variable:`CMAKE_JOB_POOL_PRECOMPILE_HEADER`.
+
+If neither :prop_tgt:`JOB_POOL_PRECOMPILE_HEADER` nor
+:variable:`CMAKE_JOB_POOL_PRECOMPILE_HEADER` are set then
+:prop_tgt:`JOB_POOL_COMPILE` will be used for this task.
diff --git a/Help/prop_tgt/LABELS.rst b/Help/prop_tgt/LABELS.rst
new file mode 100644
index 0000000..5e46469
--- /dev/null
+++ b/Help/prop_tgt/LABELS.rst
@@ -0,0 +1,6 @@
+LABELS
+------
+
+Specify a list of text labels associated with a target.
+
+Target label semantics are currently unspecified.
diff --git a/Help/prop_tgt/LANG_CLANG_TIDY.rst b/Help/prop_tgt/LANG_CLANG_TIDY.rst
new file mode 100644
index 0000000..af16d3c
--- /dev/null
+++ b/Help/prop_tgt/LANG_CLANG_TIDY.rst
@@ -0,0 +1,15 @@
+<LANG>_CLANG_TIDY
+-----------------
+
+.. versionadded:: 3.6
+
+This property is implemented only when ``<LANG>`` is ``C``, ``CXX``, ``OBJC`` or ``OBJCXX``.
+
+Specify a :ref:`semicolon-separated list <CMake Language Lists>` containing a command
+line for the ``clang-tidy`` tool. The :ref:`Makefile Generators`
+and the :generator:`Ninja` generator will run this tool along with the
+compiler and report a warning if the tool reports any problems.
+
+This property is initialized by the value of
+the :variable:`CMAKE_<LANG>_CLANG_TIDY` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/LANG_COMPILER_LAUNCHER.rst b/Help/prop_tgt/LANG_COMPILER_LAUNCHER.rst
new file mode 100644
index 0000000..16be3cd
--- /dev/null
+++ b/Help/prop_tgt/LANG_COMPILER_LAUNCHER.rst
@@ -0,0 +1,16 @@
+<LANG>_COMPILER_LAUNCHER
+------------------------
+
+.. versionadded:: 3.4
+
+This property is implemented only when ``<LANG>`` is ``C``, ``CXX``,
+``Fortran``, ``ISPC``, ``OBJC``, ``OBJCXX``, or ``CUDA``.
+
+Specify a :ref:`semicolon-separated list <CMake Language Lists>` containing a command line
+for a compiler launching tool. The :ref:`Makefile Generators` and the
+:generator:`Ninja` generator will run this tool and pass the compiler and
+its arguments to the tool. Some example tools are distcc and ccache.
+
+This property is initialized by the value of
+the :variable:`CMAKE_<LANG>_COMPILER_LAUNCHER` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/LANG_CPPCHECK.rst b/Help/prop_tgt/LANG_CPPCHECK.rst
new file mode 100644
index 0000000..80acbc0
--- /dev/null
+++ b/Help/prop_tgt/LANG_CPPCHECK.rst
@@ -0,0 +1,17 @@
+<LANG>_CPPCHECK
+---------------
+
+.. versionadded:: 3.10
+
+This property is supported only when ``<LANG>`` is ``C`` or ``CXX``.
+
+Specify a :ref:`semicolon-separated list <CMake Language Lists>` containing a command line
+for the ``cppcheck`` static analysis tool. The :ref:`Makefile Generators`
+and the :generator:`Ninja` generator will run ``cppcheck`` along with the
+compiler and report any problems. If the command-line specifies the
+exit code options to ``cppcheck`` then the build will fail if the
+tool returns non-zero.
+
+This property is initialized by the value of the
+:variable:`CMAKE_<LANG>_CPPCHECK` variable if it is set when a target is
+created.
diff --git a/Help/prop_tgt/LANG_CPPLINT.rst b/Help/prop_tgt/LANG_CPPLINT.rst
new file mode 100644
index 0000000..be6db46
--- /dev/null
+++ b/Help/prop_tgt/LANG_CPPLINT.rst
@@ -0,0 +1,15 @@
+<LANG>_CPPLINT
+--------------
+
+.. versionadded:: 3.8
+
+This property is supported only when ``<LANG>`` is ``C`` or ``CXX``.
+
+Specify a :ref:`semicolon-separated list <CMake Language Lists>` containing a command line
+for the ``cpplint`` style checker. The :ref:`Makefile Generators` and the
+:generator:`Ninja` generator will run ``cpplint`` along with the compiler
+and report any problems.
+
+This property is initialized by the value of the
+:variable:`CMAKE_<LANG>_CPPLINT` variable if it is set when a target is
+created.
diff --git a/Help/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE.rst b/Help/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE.rst
new file mode 100644
index 0000000..eebef56
--- /dev/null
+++ b/Help/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE.rst
@@ -0,0 +1,15 @@
+<LANG>_INCLUDE_WHAT_YOU_USE
+---------------------------
+
+.. versionadded:: 3.3
+
+This property is implemented only when ``<LANG>`` is ``C`` or ``CXX``.
+
+Specify a :ref:`semicolon-separated list <CMake Language Lists>` containing a command
+line for the ``include-what-you-use`` tool. The :ref:`Makefile Generators`
+and the :generator:`Ninja` generator will run this tool along with the
+compiler and report a warning if the tool reports any problems.
+
+This property is initialized by the value of
+the :variable:`CMAKE_<LANG>_INCLUDE_WHAT_YOU_USE` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/LANG_VISIBILITY_PRESET.rst b/Help/prop_tgt/LANG_VISIBILITY_PRESET.rst
new file mode 100644
index 0000000..5d34e20
--- /dev/null
+++ b/Help/prop_tgt/LANG_VISIBILITY_PRESET.rst
@@ -0,0 +1,13 @@
+<LANG>_VISIBILITY_PRESET
+------------------------
+
+Value for symbol visibility compile flags
+
+The ``<LANG>_VISIBILITY_PRESET`` property determines the value passed in a
+visibility related compile option, such as ``-fvisibility=`` for ``<LANG>``.
+This property affects compilation in sources of all types of targets
+(subject to policy :policy:`CMP0063`).
+
+This property is initialized by the value of the
+:variable:`CMAKE_<LANG>_VISIBILITY_PRESET` variable if it is set when a
+target is created.
diff --git a/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY.rst b/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY.rst
new file mode 100644
index 0000000..9fbe904
--- /dev/null
+++ b/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY.rst
@@ -0,0 +1,9 @@
+LIBRARY_OUTPUT_DIRECTORY
+------------------------
+
+.. |XXX| replace:: :ref:`LIBRARY <Library Output Artifacts>`
+.. |xxx| replace:: library
+.. |CMAKE_XXX_OUTPUT_DIRECTORY| replace:: :variable:`CMAKE_LIBRARY_OUTPUT_DIRECTORY`
+.. include:: XXX_OUTPUT_DIRECTORY.txt
+
+See also the :prop_tgt:`LIBRARY_OUTPUT_DIRECTORY_<CONFIG>` target property.
diff --git a/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst
new file mode 100644
index 0000000..5cefc38
--- /dev/null
+++ b/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst
@@ -0,0 +1,17 @@
+LIBRARY_OUTPUT_DIRECTORY_<CONFIG>
+---------------------------------
+
+Per-configuration output directory for
+:ref:`LIBRARY <Library Output Artifacts>` target files.
+
+This is a per-configuration version of the
+:prop_tgt:`LIBRARY_OUTPUT_DIRECTORY` target property, but
+multi-configuration generators (:ref:`Visual Studio Generators`,
+:generator:`Xcode`) do NOT append a
+per-configuration subdirectory to the specified directory. This
+property is initialized by the value of the
+:variable:`CMAKE_LIBRARY_OUTPUT_DIRECTORY_<CONFIG>` variable if
+it is set when a target is created.
+
+Contents of ``LIBRARY_OUTPUT_DIRECTORY_<CONFIG>`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/prop_tgt/LIBRARY_OUTPUT_NAME.rst b/Help/prop_tgt/LIBRARY_OUTPUT_NAME.rst
new file mode 100644
index 0000000..6027f7f
--- /dev/null
+++ b/Help/prop_tgt/LIBRARY_OUTPUT_NAME.rst
@@ -0,0 +1,8 @@
+LIBRARY_OUTPUT_NAME
+-------------------
+
+.. |XXX| replace:: :ref:`LIBRARY <Library Output Artifacts>`
+.. |xxx| replace:: library
+.. include:: XXX_OUTPUT_NAME.txt
+
+See also the :prop_tgt:`LIBRARY_OUTPUT_NAME_<CONFIG>` target property.
diff --git a/Help/prop_tgt/LIBRARY_OUTPUT_NAME_CONFIG.rst b/Help/prop_tgt/LIBRARY_OUTPUT_NAME_CONFIG.rst
new file mode 100644
index 0000000..1994c7b
--- /dev/null
+++ b/Help/prop_tgt/LIBRARY_OUTPUT_NAME_CONFIG.rst
@@ -0,0 +1,8 @@
+LIBRARY_OUTPUT_NAME_<CONFIG>
+----------------------------
+
+Per-configuration output name for
+:ref:`LIBRARY <Library Output Artifacts>` target files.
+
+This is the configuration-specific version of the
+:prop_tgt:`LIBRARY_OUTPUT_NAME` target property.
diff --git a/Help/prop_tgt/LINKER_LANGUAGE.rst b/Help/prop_tgt/LINKER_LANGUAGE.rst
new file mode 100644
index 0000000..b0a572b
--- /dev/null
+++ b/Help/prop_tgt/LINKER_LANGUAGE.rst
@@ -0,0 +1,14 @@
+LINKER_LANGUAGE
+---------------
+
+Specifies language whose compiler will invoke the linker.
+
+For executables, shared libraries, and modules, this sets the language
+whose compiler is used to link the target (such as "C" or "CXX"). A
+typical value for an executable is the language of the source file
+providing the program entry point (main). If not set, the language
+with the highest linker preference value is the default. See
+documentation of :variable:`CMAKE_<LANG>_LINKER_PREFERENCE` variables.
+
+If this property is not set by the user, it will be calculated at
+generate-time by CMake.
diff --git a/Help/prop_tgt/LINK_DEPENDS.rst b/Help/prop_tgt/LINK_DEPENDS.rst
new file mode 100644
index 0000000..e59d4c0
--- /dev/null
+++ b/Help/prop_tgt/LINK_DEPENDS.rst
@@ -0,0 +1,18 @@
+LINK_DEPENDS
+------------
+
+Additional files on which a target binary depends for linking.
+
+Specifies a semicolon-separated list of full-paths to files on which
+the link rule for this target depends. The target binary will be
+linked if any of the named files is newer than it.
+
+This property is supported only by :generator:`Ninja` and
+:ref:`Makefile Generators`. It is
+intended to specify dependencies on "linker scripts" for custom Makefile link
+rules.
+
+Contents of ``LINK_DEPENDS`` may use "generator expressions" with
+the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
diff --git a/Help/prop_tgt/LINK_DEPENDS_NO_SHARED.rst b/Help/prop_tgt/LINK_DEPENDS_NO_SHARED.rst
new file mode 100644
index 0000000..5c6778d
--- /dev/null
+++ b/Help/prop_tgt/LINK_DEPENDS_NO_SHARED.rst
@@ -0,0 +1,14 @@
+LINK_DEPENDS_NO_SHARED
+----------------------
+
+Do not depend on linked shared library files.
+
+Set this property to true to tell CMake generators not to add
+file-level dependencies on the shared library files linked by this
+target. Modification to the shared libraries will not be sufficient
+to re-link this target. Logical target-level dependencies will not be
+affected so the linked shared libraries will still be brought up to
+date before this target is built.
+
+This property is initialized by the value of the variable
+CMAKE_LINK_DEPENDS_NO_SHARED if it is set when a target is created.
diff --git a/Help/prop_tgt/LINK_DIRECTORIES.rst b/Help/prop_tgt/LINK_DIRECTORIES.rst
new file mode 100644
index 0000000..67be494
--- /dev/null
+++ b/Help/prop_tgt/LINK_DIRECTORIES.rst
@@ -0,0 +1,20 @@
+LINK_DIRECTORIES
+----------------
+
+.. versionadded:: 3.13
+
+List of directories to use for the link step of shared library, module
+and executable targets.
+
+This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of directories
+specified so far for its target. Use the :command:`target_link_directories`
+command to append more search directories.
+
+This property is initialized by the :prop_dir:`LINK_DIRECTORIES` directory
+property when a target is created, and is used by the generators to set
+the search directories for the linker.
+
+Contents of ``LINK_DIRECTORIES`` may use "generator expressions" with the
+syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions. See the :manual:`cmake-buildsystem(7)` manual
+for more on defining buildsystem properties.
diff --git a/Help/prop_tgt/LINK_FLAGS.rst b/Help/prop_tgt/LINK_FLAGS.rst
new file mode 100644
index 0000000..92cd3c0
--- /dev/null
+++ b/Help/prop_tgt/LINK_FLAGS.rst
@@ -0,0 +1,16 @@
+LINK_FLAGS
+----------
+
+Additional flags to use when linking this target if it is a shared library,
+module library, or an executable. Static libraries need to use
+:prop_tgt:`STATIC_LIBRARY_OPTIONS` or :prop_tgt:`STATIC_LIBRARY_FLAGS`
+properties.
+
+The ``LINK_FLAGS`` property, managed as a string, can be used to add extra
+flags to the link step of a target. :prop_tgt:`LINK_FLAGS_<CONFIG>` will add
+to the configuration ``<CONFIG>``, for example, ``DEBUG``, ``RELEASE``,
+``MINSIZEREL``, ``RELWITHDEBINFO``, ...
+
+.. note::
+
+ This property has been superseded by :prop_tgt:`LINK_OPTIONS` property.
diff --git a/Help/prop_tgt/LINK_FLAGS_CONFIG.rst b/Help/prop_tgt/LINK_FLAGS_CONFIG.rst
new file mode 100644
index 0000000..68c3129
--- /dev/null
+++ b/Help/prop_tgt/LINK_FLAGS_CONFIG.rst
@@ -0,0 +1,11 @@
+LINK_FLAGS_<CONFIG>
+-------------------
+
+Per-configuration linker flags for a ``SHARED`` library, ``MODULE`` or
+``EXECUTABLE`` target.
+
+This is the configuration-specific version of :prop_tgt:`LINK_FLAGS`.
+
+.. note::
+
+ This property has been superseded by :prop_tgt:`LINK_OPTIONS` property.
diff --git a/Help/prop_tgt/LINK_INTERFACE_LIBRARIES.rst b/Help/prop_tgt/LINK_INTERFACE_LIBRARIES.rst
new file mode 100644
index 0000000..2dcf45c
--- /dev/null
+++ b/Help/prop_tgt/LINK_INTERFACE_LIBRARIES.rst
@@ -0,0 +1,31 @@
+LINK_INTERFACE_LIBRARIES
+------------------------
+
+List public interface libraries for a shared library or executable.
+
+By default linking to a shared library target transitively links to
+targets with which the library itself was linked. For an executable
+with exports (see the :prop_tgt:`ENABLE_EXPORTS` target property) no
+default transitive link dependencies are used. This property replaces the default
+transitive link dependencies with an explicit list. When the target
+is linked into another target using the :command:`target_link_libraries`
+command, the libraries listed (and recursively
+their link interface libraries) will be provided to the other target
+also. If the list is empty then no transitive link dependencies will
+be incorporated when this target is linked into another target even if
+the default set is non-empty. This property is initialized by the
+value of the :variable:`CMAKE_LINK_INTERFACE_LIBRARIES` variable if it is
+set when a target is created. This property is ignored for ``STATIC``
+libraries.
+
+This property is overridden by the :prop_tgt:`INTERFACE_LINK_LIBRARIES`
+property if policy :policy:`CMP0022` is ``NEW``.
+
+This property is deprecated. Use :prop_tgt:`INTERFACE_LINK_LIBRARIES`
+instead.
+
+Creating Relocatable Packages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. |INTERFACE_PROPERTY_LINK| replace:: ``LINK_INTERFACE_LIBRARIES``
+.. include:: /include/INTERFACE_LINK_LIBRARIES_WARNING.txt
diff --git a/Help/prop_tgt/LINK_INTERFACE_LIBRARIES_CONFIG.rst b/Help/prop_tgt/LINK_INTERFACE_LIBRARIES_CONFIG.rst
new file mode 100644
index 0000000..22ee5a6
--- /dev/null
+++ b/Help/prop_tgt/LINK_INTERFACE_LIBRARIES_CONFIG.rst
@@ -0,0 +1,20 @@
+LINK_INTERFACE_LIBRARIES_<CONFIG>
+---------------------------------
+
+Per-configuration list of public interface libraries for a target.
+
+This is the configuration-specific version of
+:prop_tgt:`LINK_INTERFACE_LIBRARIES`. If set, this property completely
+overrides the generic property for the named configuration.
+
+This property is overridden by the :prop_tgt:`INTERFACE_LINK_LIBRARIES`
+property if policy :policy:`CMP0022` is ``NEW``.
+
+This property is deprecated. Use :prop_tgt:`INTERFACE_LINK_LIBRARIES`
+instead.
+
+Creating Relocatable Packages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. |INTERFACE_PROPERTY_LINK| replace:: ``LINK_INTERFACE_LIBRARIES_<CONFIG>``
+.. include:: /include/INTERFACE_LINK_LIBRARIES_WARNING.txt
diff --git a/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY.rst b/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY.rst
new file mode 100644
index 0000000..b798af9
--- /dev/null
+++ b/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY.rst
@@ -0,0 +1,12 @@
+LINK_INTERFACE_MULTIPLICITY
+---------------------------
+
+Repetition count for ``STATIC`` libraries with cyclic dependencies.
+
+When linking to a ``STATIC`` library target with cyclic dependencies the
+linker may need to scan more than once through the archives in the
+strongly connected component of the dependency graph. CMake by
+default constructs the link line so that the linker will scan through
+the component at least twice. This property specifies the minimum
+number of scans if it is larger than the default. CMake uses the
+largest value specified by any target in a component.
diff --git a/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG.rst b/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
new file mode 100644
index 0000000..7c9461f
--- /dev/null
+++ b/Help/prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG.rst
@@ -0,0 +1,8 @@
+LINK_INTERFACE_MULTIPLICITY_<CONFIG>
+------------------------------------
+
+Per-configuration repetition count for cycles of ``STATIC`` libraries.
+
+This is the configuration-specific version of
+:prop_tgt:`LINK_INTERFACE_MULTIPLICITY`. If set, this property completely
+overrides the generic property for the named configuration.
diff --git a/Help/prop_tgt/LINK_LIBRARIES.rst b/Help/prop_tgt/LINK_LIBRARIES.rst
new file mode 100644
index 0000000..d88e798
--- /dev/null
+++ b/Help/prop_tgt/LINK_LIBRARIES.rst
@@ -0,0 +1,19 @@
+LINK_LIBRARIES
+--------------
+
+List of direct link dependencies.
+
+This property specifies the list of libraries or targets which will be
+used for linking. In addition to accepting values from the
+:command:`target_link_libraries` command, values may be set directly on
+any target using the :command:`set_property` command.
+
+The value of this property is used by the generators to set the link
+libraries for the compiler.
+
+Contents of ``LINK_LIBRARIES`` may use "generator expressions" with the
+syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions. See the :manual:`cmake-buildsystem(7)` manual
+for more on defining buildsystem properties.
+
+.. include:: LINK_LIBRARIES_INDIRECTION.txt
diff --git a/Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt b/Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt
new file mode 100644
index 0000000..476e4a6
--- /dev/null
+++ b/Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt
@@ -0,0 +1,10 @@
+.. note::
+ A call to :command:`target_link_libraries(<target> ...)` may update this
+ property on ``<target>``. If ``<target>`` was not created in the same
+ directory as the call then :command:`target_link_libraries` will wrap each
+ entry with the form ``::@(directory-id);...;::@``, where the ``::@`` is
+ literal and the ``(directory-id)`` is unspecified.
+ This tells the generators that the named libraries must be looked up in
+ the scope of the caller rather than in the scope in which the
+ ``<target>`` was created. Valid directory ids are stripped on export
+ by the :command:`install(EXPORT)` and :command:`export` commands.
diff --git a/Help/prop_tgt/LINK_OPTIONS.rst b/Help/prop_tgt/LINK_OPTIONS.rst
new file mode 100644
index 0000000..8c0dfc4
--- /dev/null
+++ b/Help/prop_tgt/LINK_OPTIONS.rst
@@ -0,0 +1,30 @@
+LINK_OPTIONS
+------------
+
+.. versionadded:: 3.13
+
+List of options to use for the link step of shared library, module
+and executable targets as well as the device link step. Targets that are static
+libraries need to use the :prop_tgt:`STATIC_LIBRARY_OPTIONS` target property.
+
+These options are used for both normal linking and device linking
+(see policy :policy:`CMP0105`). To control link options for normal and device
+link steps, ``$<HOST_LINK>`` and ``$<DEVICE_LINK>``
+:manual:`generator expressions <cmake-generator-expressions(7)>` can be used.
+
+This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of
+options specified so far for its target. Use the :command:`target_link_options`
+command to append more options.
+
+This property is initialized by the :prop_dir:`LINK_OPTIONS` directory
+property when a target is created, and is used by the generators to set
+the options for the compiler.
+
+Contents of ``LINK_OPTIONS`` may use "generator expressions" with the
+syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions. See the :manual:`cmake-buildsystem(7)` manual
+for more on defining buildsystem properties.
+
+.. note::
+
+ This property must be used in preference to :prop_tgt:`LINK_FLAGS` property.
diff --git a/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst b/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst
new file mode 100644
index 0000000..fecbb14
--- /dev/null
+++ b/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst
@@ -0,0 +1,19 @@
+LINK_SEARCH_END_STATIC
+----------------------
+
+End a link line such that static system libraries are used.
+
+Some linkers support switches such as ``-Bstatic`` and ``-Bdynamic`` to
+determine whether to use static or shared libraries for ``-lXXX`` options.
+CMake uses these options to set the link type for libraries whose full
+paths are not known or (in some cases) are in implicit link
+directories for the platform. By default CMake adds an option at the
+end of the library list (if necessary) to set the linker search type
+back to its starting type. This property switches the final linker
+search type to ``-Bstatic`` regardless of how it started.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_LINK_SEARCH_END_STATIC` if it is set
+when a target is created.
+
+See also :prop_tgt:`LINK_SEARCH_START_STATIC`.
diff --git a/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst b/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst
new file mode 100644
index 0000000..83cf231
--- /dev/null
+++ b/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst
@@ -0,0 +1,20 @@
+LINK_SEARCH_START_STATIC
+------------------------
+
+Assume the linker looks for static libraries by default.
+
+Some linkers support switches such as ``-Bstatic`` and ``-Bdynamic`` to
+determine whether to use static or shared libraries for ``-lXXX`` options.
+CMake uses these options to set the link type for libraries whose full
+paths are not known or (in some cases) are in implicit link
+directories for the platform. By default the linker search type is
+assumed to be ``-Bdynamic`` at the beginning of the library list. This
+property switches the assumption to ``-Bstatic``. It is intended for use
+when linking an executable statically (e.g. with the GNU ``-static``
+option).
+
+This property is initialized by the value of the variable
+ :variable:`CMAKE_LINK_SEARCH_START_STATIC` if it is set
+ when a target is created.
+
+See also :prop_tgt:`LINK_SEARCH_END_STATIC`.
diff --git a/Help/prop_tgt/LINK_WHAT_YOU_USE.rst b/Help/prop_tgt/LINK_WHAT_YOU_USE.rst
new file mode 100644
index 0000000..2ed93ad
--- /dev/null
+++ b/Help/prop_tgt/LINK_WHAT_YOU_USE.rst
@@ -0,0 +1,17 @@
+LINK_WHAT_YOU_USE
+---------------------------
+
+.. versionadded:: 3.7
+
+This is a boolean option that when set to ``TRUE`` will automatically run
+``ldd -r -u`` on the target after it is linked. In addition, the linker flag
+``-Wl,--no-as-needed`` will be passed to the target with the link command so
+that all libraries specified on the command line will be linked into the
+target. This will result in the link producing a list of libraries that
+provide no symbols used by this target but are being linked to it.
+This is only applicable to executable and shared library targets and
+will only work when ld and ldd accept the flags used.
+
+This property is initialized by the value of
+the :variable:`CMAKE_LINK_WHAT_YOU_USE` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/LOCATION.rst b/Help/prop_tgt/LOCATION.rst
new file mode 100644
index 0000000..d058064
--- /dev/null
+++ b/Help/prop_tgt/LOCATION.rst
@@ -0,0 +1,28 @@
+LOCATION
+--------
+
+Read-only location of a target on disk.
+
+For an imported target, this read-only property returns the value of
+the ``LOCATION_<CONFIG>`` property for an unspecified configuration
+``<CONFIG>`` provided by the target.
+
+For a non-imported target, this property is provided for compatibility
+with CMake 2.4 and below. It was meant to get the location of an
+executable target's output file for use in :command:`add_custom_command`. The
+path may contain a build-system-specific portion that is replaced at
+build time with the configuration getting built (such as
+``$(ConfigurationName)`` in VS). In CMake 2.6 and above
+:command:`add_custom_command` automatically recognizes a target name in its
+``COMMAND`` and ``DEPENDS`` options and computes the target location. In
+CMake 2.8.4 and above :command:`add_custom_command` recognizes
+:manual:`generator expressions <cmake-generator-expressions(7)>`
+to refer to target locations anywhere in the command.
+Therefore this property is not needed for creating custom commands.
+
+Do not set properties that affect the location of a target after
+reading this property. These include properties whose names match
+``(RUNTIME|LIBRARY|ARCHIVE)_OUTPUT_(NAME|DIRECTORY)(_<CONFIG>)?``,
+``(IMPLIB_)?(PREFIX|SUFFIX)``, or "LINKER_LANGUAGE". Failure to follow
+this rule is not diagnosed and leaves the location of the target
+undefined.
diff --git a/Help/prop_tgt/LOCATION_CONFIG.rst b/Help/prop_tgt/LOCATION_CONFIG.rst
new file mode 100644
index 0000000..67de8ed
--- /dev/null
+++ b/Help/prop_tgt/LOCATION_CONFIG.rst
@@ -0,0 +1,20 @@
+LOCATION_<CONFIG>
+-----------------
+
+Read-only property providing a target location on disk.
+
+A read-only property that indicates where a target's main file is
+located on disk for the configuration ``<CONFIG>``. The property is
+defined only for library and executable targets. An imported target
+may provide a set of configurations different from that of the
+importing project. By default CMake looks for an exact-match but
+otherwise uses an arbitrary available configuration. Use the
+:prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` property to map imported
+configurations explicitly.
+
+Do not set properties that affect the location of a target after
+reading this property. These include properties whose names match
+``(RUNTIME|LIBRARY|ARCHIVE)_OUTPUT_(NAME|DIRECTORY)(_<CONFIG>)?``,
+``(IMPLIB_)?(PREFIX|SUFFIX)``, or :prop_tgt:`LINKER_LANGUAGE`.
+Failure to follow this rule is not diagnosed and leaves
+the location of the target undefined.
diff --git a/Help/prop_tgt/MACHO_COMPATIBILITY_VERSION.rst b/Help/prop_tgt/MACHO_COMPATIBILITY_VERSION.rst
new file mode 100644
index 0000000..a24b255
--- /dev/null
+++ b/Help/prop_tgt/MACHO_COMPATIBILITY_VERSION.rst
@@ -0,0 +1,27 @@
+MACHO_COMPATIBILITY_VERSION
+---------------------------
+
+.. versionadded:: 3.17
+
+What compatibility version number is this target for Mach-O binaries.
+
+For shared libraries on Mach-O systems (e.g. macOS, iOS)
+the ``MACHO_COMPATIBILITY_VERSION`` property corresponds to the
+*compatibility version* and :prop_tgt:`MACHO_CURRENT_VERSION` corresponds to
+the *current version*. These are both embedded in the shared library binary
+and can be checked with the ``otool -L <binary>`` command.
+
+It should be noted that the :prop_tgt:`MACHO_CURRENT_VERSION` and
+``MACHO_COMPATIBILITY_VERSION`` properties do not affect the file
+names or version-related symlinks that CMake generates for the library.
+The :prop_tgt:`VERSION` and :prop_tgt:`SOVERSION` target properties still
+control the file and symlink names. The ``install_name`` is also still
+controlled by :prop_tgt:`SOVERSION`.
+
+When :prop_tgt:`MACHO_CURRENT_VERSION` and ``MACHO_COMPATIBILITY_VERSION``
+are not given, :prop_tgt:`VERSION` and :prop_tgt:`SOVERSION` are used for
+the version details to be embedded in the binaries respectively.
+The :prop_tgt:`MACHO_CURRENT_VERSION` and ``MACHO_COMPATIBILITY_VERSION``
+properties only need to be given if the project needs to decouple the file
+and symlink naming from the version details embedded in the binaries
+(e.g. to match libtool conventions).
diff --git a/Help/prop_tgt/MACHO_CURRENT_VERSION.rst b/Help/prop_tgt/MACHO_CURRENT_VERSION.rst
new file mode 100644
index 0000000..530f79b
--- /dev/null
+++ b/Help/prop_tgt/MACHO_CURRENT_VERSION.rst
@@ -0,0 +1,27 @@
+MACHO_CURRENT_VERSION
+---------------------
+
+.. versionadded:: 3.17
+
+What current version number is this target for Mach-O binaries.
+
+For shared libraries on Mach-O systems (e.g. macOS, iOS)
+the :prop_tgt:`MACHO_COMPATIBILITY_VERSION` property corresponds to the
+*compatibility version* and ``MACHO_CURRENT_VERSION`` corresponds to the
+*current version*. These are both embedded in the shared library binary
+and can be checked with the ``otool -L <binary>`` command.
+
+It should be noted that the ``MACHO_CURRENT_VERSION`` and
+:prop_tgt:`MACHO_COMPATIBILITY_VERSION` properties do not affect the file
+names or version-related symlinks that CMake generates for the library.
+The :prop_tgt:`VERSION` and :prop_tgt:`SOVERSION` target properties still
+control the file and symlink names. The ``install_name`` is also still
+controlled by :prop_tgt:`SOVERSION`.
+
+When ``MACHO_CURRENT_VERSION`` and :prop_tgt:`MACHO_COMPATIBILITY_VERSION`
+are not given, :prop_tgt:`VERSION` and :prop_tgt:`SOVERSION` are used for
+the version details to be embedded in the binaries respectively.
+The ``MACHO_CURRENT_VERSION`` and :prop_tgt:`MACHO_COMPATIBILITY_VERSION`
+properties only need to be given if the project needs to decouple the file
+and symlink naming from the version details embedded in the binaries
+(e.g. to match libtool conventions).
diff --git a/Help/prop_tgt/MACOSX_BUNDLE.rst b/Help/prop_tgt/MACOSX_BUNDLE.rst
new file mode 100644
index 0000000..92bce53
--- /dev/null
+++ b/Help/prop_tgt/MACOSX_BUNDLE.rst
@@ -0,0 +1,12 @@
+MACOSX_BUNDLE
+-------------
+
+Build an executable as an Application Bundle on macOS or iOS.
+
+When this property is set to ``TRUE`` the executable when built on macOS
+or iOS will be created as an application bundle. This makes it
+a GUI executable that can be launched from the Finder. See the
+:prop_tgt:`MACOSX_BUNDLE_INFO_PLIST` target property for information about
+creation of the ``Info.plist`` file for the application bundle.
+This property is initialized by the value of the variable
+:variable:`CMAKE_MACOSX_BUNDLE` if it is set when a target is created.
diff --git a/Help/prop_tgt/MACOSX_BUNDLE_INFO_PLIST.rst b/Help/prop_tgt/MACOSX_BUNDLE_INFO_PLIST.rst
new file mode 100644
index 0000000..443a645
--- /dev/null
+++ b/Help/prop_tgt/MACOSX_BUNDLE_INFO_PLIST.rst
@@ -0,0 +1,35 @@
+MACOSX_BUNDLE_INFO_PLIST
+------------------------
+
+Specify a custom ``Info.plist`` template for a macOS and iOS Application Bundle.
+
+An executable target with :prop_tgt:`MACOSX_BUNDLE` enabled will be built as an
+application bundle on macOS. By default its ``Info.plist`` file is created
+by configuring a template called ``MacOSXBundleInfo.plist.in`` located in the
+:variable:`CMAKE_MODULE_PATH`. This property specifies an alternative template
+file name which may be a full path.
+
+The following target properties may be set to specify content to be
+configured into the file:
+
+``MACOSX_BUNDLE_BUNDLE_NAME``
+ Sets ``CFBundleName``.
+``MACOSX_BUNDLE_BUNDLE_VERSION``
+ Sets ``CFBundleVersion``.
+``MACOSX_BUNDLE_COPYRIGHT``
+ Sets ``NSHumanReadableCopyright``.
+``MACOSX_BUNDLE_GUI_IDENTIFIER``
+ Sets ``CFBundleIdentifier``.
+``MACOSX_BUNDLE_ICON_FILE``
+ Sets ``CFBundleIconFile``.
+``MACOSX_BUNDLE_INFO_STRING``
+ Sets ``CFBundleGetInfoString``.
+``MACOSX_BUNDLE_LONG_VERSION_STRING``
+ Sets ``CFBundleLongVersionString``.
+``MACOSX_BUNDLE_SHORT_VERSION_STRING``
+ Sets ``CFBundleShortVersionString``.
+
+CMake variables of the same name may be set to affect all targets in a
+directory that do not have each specific property set. If a custom
+``Info.plist`` is specified by this property it may of course hard-code
+all the settings instead of using the target properties.
diff --git a/Help/prop_tgt/MACOSX_FRAMEWORK_INFO_PLIST.rst b/Help/prop_tgt/MACOSX_FRAMEWORK_INFO_PLIST.rst
new file mode 100644
index 0000000..82fdcc0
--- /dev/null
+++ b/Help/prop_tgt/MACOSX_FRAMEWORK_INFO_PLIST.rst
@@ -0,0 +1,27 @@
+MACOSX_FRAMEWORK_INFO_PLIST
+---------------------------
+
+Specify a custom ``Info.plist`` template for a macOS and iOS Framework.
+
+A library target with :prop_tgt:`FRAMEWORK` enabled will be built as a
+framework on macOS. By default its ``Info.plist`` file is created by
+configuring a template called ``MacOSXFrameworkInfo.plist.in`` located in the
+:variable:`CMAKE_MODULE_PATH`. This property specifies an alternative template
+file name which may be a full path.
+
+The following target properties may be set to specify content to be
+configured into the file:
+
+``MACOSX_FRAMEWORK_BUNDLE_VERSION``
+ Sets ``CFBundleVersion``.
+``MACOSX_FRAMEWORK_ICON_FILE``
+ Sets ``CFBundleIconFile``.
+``MACOSX_FRAMEWORK_IDENTIFIER``
+ Sets ``CFBundleIdentifier``.
+``MACOSX_FRAMEWORK_SHORT_VERSION_STRING``
+ Sets ``CFBundleShortVersionString``.
+
+CMake variables of the same name may be set to affect all targets in a
+directory that do not have each specific property set. If a custom
+``Info.plist`` is specified by this property it may of course hard-code
+all the settings instead of using the target properties.
diff --git a/Help/prop_tgt/MACOSX_RPATH.rst b/Help/prop_tgt/MACOSX_RPATH.rst
new file mode 100644
index 0000000..acd5a7a
--- /dev/null
+++ b/Help/prop_tgt/MACOSX_RPATH.rst
@@ -0,0 +1,23 @@
+MACOSX_RPATH
+------------
+
+Whether this target on macOS or iOS is located at runtime using rpaths.
+
+When this property is set to ``TRUE``, the directory portion of
+the ``install_name`` field of this shared library will be ``@rpath``
+unless overridden by :prop_tgt:`INSTALL_NAME_DIR`. This indicates
+the shared library is to be found at runtime using runtime
+paths (rpaths).
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_MACOSX_RPATH` if it is set when a target is
+created.
+
+Runtime paths will also be embedded in binaries using this target and
+can be controlled by the :prop_tgt:`INSTALL_RPATH` target property on
+the target linking to this target.
+
+Policy :policy:`CMP0042` was introduced to change the default value of
+``MACOSX_RPATH`` to ``TRUE``. This is because use of ``@rpath`` is a
+more flexible and powerful alternative to ``@executable_path`` and
+``@loader_path``.
diff --git a/Help/prop_tgt/MANUALLY_ADDED_DEPENDENCIES.rst b/Help/prop_tgt/MANUALLY_ADDED_DEPENDENCIES.rst
new file mode 100644
index 0000000..72871b3
--- /dev/null
+++ b/Help/prop_tgt/MANUALLY_ADDED_DEPENDENCIES.rst
@@ -0,0 +1,10 @@
+MANUALLY_ADDED_DEPENDENCIES
+---------------------------
+
+.. versionadded:: 3.8
+
+Get manually added dependencies to other top-level targets.
+
+This read-only property can be used to query all dependencies that
+were added for this target with the :command:`add_dependencies`
+command.
diff --git a/Help/prop_tgt/MAP_IMPORTED_CONFIG_CONFIG.rst b/Help/prop_tgt/MAP_IMPORTED_CONFIG_CONFIG.rst
new file mode 100644
index 0000000..266ccf0
--- /dev/null
+++ b/Help/prop_tgt/MAP_IMPORTED_CONFIG_CONFIG.rst
@@ -0,0 +1,70 @@
+MAP_IMPORTED_CONFIG_<CONFIG>
+----------------------------
+
+Map from project configuration to
+:ref:`imported target <IMPORTED targets>`'s configuration.
+
+Set this to the list of configurations of an imported target that may
+be used for the current project's ``<CONFIG>`` configuration. Targets
+imported from another project may not provide the same set of
+configuration names available in the current project. Setting this
+property tells CMake what imported configurations are suitable for use
+when building the ``<CONFIG>`` configuration. The first configuration in
+the list found to be provided by the imported target (i.e. via
+:prop_tgt:`IMPORTED_LOCATION_<CONFIG>` for the mapped-to ``<CONFIG>``)
+is selected. As a special case, an empty list element refers to the
+configuration-less imported target location
+(i.e. :prop_tgt:`IMPORTED_LOCATION`).
+
+If this property is set and no matching configurations are available,
+then the imported target is considered to be not found. This property
+is ignored for non-imported targets.
+
+This property is initialized by the value of the
+:variable:`CMAKE_MAP_IMPORTED_CONFIG_<CONFIG>` variable if it is set when a
+target is created.
+
+Example
+^^^^^^^
+
+For example creating imported C++ library ``foo``:
+
+.. code-block:: cmake
+
+ add_library(foo STATIC IMPORTED)
+
+Use ``foo_debug`` path for ``Debug`` build type:
+
+.. code-block:: cmake
+
+ set_property(
+ TARGET foo APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG
+ )
+
+ set_target_properties(foo PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
+ IMPORTED_LOCATION_DEBUG "${foo_debug}"
+ )
+
+Use ``foo_release`` path for ``Release`` build type:
+
+.. code-block:: cmake
+
+ set_property(
+ TARGET foo APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE
+ )
+
+ set_target_properties(foo PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
+ IMPORTED_LOCATION_RELEASE "${foo_release}"
+ )
+
+Use ``Release`` version of library for ``MinSizeRel`` and ``RelWithDebInfo``
+build types:
+
+.. code-block:: cmake
+
+ set_target_properties(foo PROPERTIES
+ MAP_IMPORTED_CONFIG_MINSIZEREL Release
+ MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release
+ )
diff --git a/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt
new file mode 100644
index 0000000..6c61341
--- /dev/null
+++ b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt
@@ -0,0 +1,20 @@
+``MultiThreaded``
+ Compile with ``-MT`` or equivalent flag(s) to use a multi-threaded
+ statically-linked runtime library.
+``MultiThreadedDLL``
+ Compile with ``-MD`` or equivalent flag(s) to use a multi-threaded
+ dynamically-linked runtime library.
+``MultiThreadedDebug``
+ Compile with ``-MTd`` or equivalent flag(s) to use a multi-threaded
+ statically-linked runtime library.
+``MultiThreadedDebugDLL``
+ Compile with ``-MDd`` or equivalent flag(s) to use a multi-threaded
+ dynamically-linked runtime library.
+
+The value is ignored on non-MSVC compilers but an unsupported value will
+be rejected as an error when using a compiler targeting the MSVC ABI.
+
+The value may also be the empty string (``""``) in which case no runtime
+library selection flag will be added explicitly by CMake. Note that with
+:ref:`Visual Studio Generators` the native build system may choose to
+add its own default runtime library selection flag.
diff --git a/Help/prop_tgt/MSVC_RUNTIME_LIBRARY.rst b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY.rst
new file mode 100644
index 0000000..9b978b2
--- /dev/null
+++ b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY.rst
@@ -0,0 +1,31 @@
+MSVC_RUNTIME_LIBRARY
+--------------------
+
+.. versionadded:: 3.15
+
+Select the MSVC runtime library for use by compilers targeting the MSVC ABI.
+
+The allowed values are:
+
+.. include:: MSVC_RUNTIME_LIBRARY-VALUES.txt
+
+Use :manual:`generator expressions <cmake-generator-expressions(7)>` to
+support per-configuration specification. For example, the code:
+
+.. code-block:: cmake
+
+ add_executable(foo foo.c)
+ set_property(TARGET foo PROPERTY
+ MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+
+selects for the target ``foo`` a multi-threaded statically-linked runtime
+library with or without debug information depending on the configuration.
+
+If this property is not set then CMake uses the default value
+``MultiThreaded$<$<CONFIG:Debug>:Debug>DLL`` to select a MSVC runtime library.
+
+.. note::
+
+ This property has effect only when policy :policy:`CMP0091` is set to ``NEW``
+ prior to the first :command:`project` or :command:`enable_language` command
+ that enables a language using a compiler targeting the MSVC ABI.
diff --git a/Help/prop_tgt/NAME.rst b/Help/prop_tgt/NAME.rst
new file mode 100644
index 0000000..ddd84f2
--- /dev/null
+++ b/Help/prop_tgt/NAME.rst
@@ -0,0 +1,6 @@
+NAME
+----
+
+Logical name for the target.
+
+Read-only logical name for the target as used by CMake.
diff --git a/Help/prop_tgt/NO_SONAME.rst b/Help/prop_tgt/NO_SONAME.rst
new file mode 100644
index 0000000..d381a9c
--- /dev/null
+++ b/Help/prop_tgt/NO_SONAME.rst
@@ -0,0 +1,14 @@
+NO_SONAME
+---------
+
+Whether to set ``soname`` when linking a shared library.
+
+Enable this boolean property if a generated ``SHARED`` library
+should not have ``soname`` set. Default is to set ``soname`` on all
+shared libraries as long as the platform supports it.
+Generally, use this property only for leaf private libraries or
+plugins. If you use it on normal shared libraries which other targets
+link against, on some platforms a linker will insert a full path to
+the library (as specified at link time) into the dynamic section of
+the dependent binary. Therefore, once installed, dynamic loader may
+eventually fail to locate the library for the binary.
diff --git a/Help/prop_tgt/NO_SYSTEM_FROM_IMPORTED.rst b/Help/prop_tgt/NO_SYSTEM_FROM_IMPORTED.rst
new file mode 100644
index 0000000..880343d
--- /dev/null
+++ b/Help/prop_tgt/NO_SYSTEM_FROM_IMPORTED.rst
@@ -0,0 +1,15 @@
+NO_SYSTEM_FROM_IMPORTED
+-----------------------
+
+Do not treat include directories from the interfaces of consumed
+:ref:`imported targets` as ``SYSTEM``.
+
+The contents of the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target property
+of imported targets are treated as ``SYSTEM`` includes by default. If this
+property is enabled on a target, compilation of sources in that target will
+not treat the contents of the ``INTERFACE_INCLUDE_DIRECTORIES`` of consumed
+imported targets as system includes.
+
+This property is initialized by the value of the
+:variable:`CMAKE_NO_SYSTEM_FROM_IMPORTED` variable if it is set when a target
+is created.
diff --git a/Help/prop_tgt/OBJCXX_EXTENSIONS.rst b/Help/prop_tgt/OBJCXX_EXTENSIONS.rst
new file mode 100644
index 0000000..8a254f2
--- /dev/null
+++ b/Help/prop_tgt/OBJCXX_EXTENSIONS.rst
@@ -0,0 +1,22 @@
+OBJCXX_EXTENSIONS
+-----------------
+
+.. versionadded:: 3.16
+
+Boolean specifying whether compiler specific extensions are requested.
+
+This property specifies whether compiler specific extensions should be
+used. For some compilers, this results in adding a flag such
+as ``-std=gnu++11`` instead of ``-std=c++11`` to the compile line. This
+property is ``ON`` by default. The basic ObjC++ standard level is
+controlled by the :prop_tgt:`OBJCXX_STANDARD` target property.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+If the property is not set, and the project has set the :prop_tgt:`CXX_EXTENSIONS`,
+the value of :prop_tgt:`CXX_EXTENSIONS` is set for :prop_tgt:`OBJCXX_EXTENSIONS`.
+
+This property is initialized by the value of
+the :variable:`CMAKE_OBJCXX_EXTENSIONS` variable if it is set when a target
+is created.
diff --git a/Help/prop_tgt/OBJCXX_STANDARD.rst b/Help/prop_tgt/OBJCXX_STANDARD.rst
new file mode 100644
index 0000000..96088af
--- /dev/null
+++ b/Help/prop_tgt/OBJCXX_STANDARD.rst
@@ -0,0 +1,37 @@
+OBJCXX_STANDARD
+---------------
+
+.. versionadded:: 3.16
+
+The ObjC++ standard whose features are requested to build this target.
+
+This property specifies the ObjC++ standard whose features are requested
+to build this target. For some compilers, this results in adding a
+flag such as ``-std=gnu++11`` to the compile line.
+
+Supported values are ``98``, ``11``, ``14``, ``17``, ``20``, ``23``.
+
+If the value requested does not result in a compile flag being added for
+the compiler in use, a previous standard flag will be added instead. This
+means that using:
+
+.. code-block:: cmake
+
+ set_property(TARGET tgt PROPERTY OBJCXX_STANDARD 11)
+
+with a compiler which does not support ``-std=gnu++11`` or an equivalent
+flag will not result in an error or warning, but will instead add the
+``-std=gnu++98`` flag if supported. This "decay" behavior may be controlled
+with the :prop_tgt:`OBJCXX_STANDARD_REQUIRED` target property.
+Additionally, the :prop_tgt:`OBJCXX_EXTENSIONS` target property may be used to
+control whether compiler-specific extensions are enabled on a per-target basis.
+
+If the property is not set, and the project has set the :prop_tgt:`CXX_STANDARD`,
+the value of :prop_tgt:`CXX_STANDARD` is set for :prop_tgt:`OBJCXX_STANDARD`.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_OBJCXX_STANDARD` variable if it is set when a target
+is created.
diff --git a/Help/prop_tgt/OBJCXX_STANDARD_REQUIRED.rst b/Help/prop_tgt/OBJCXX_STANDARD_REQUIRED.rst
new file mode 100644
index 0000000..3cee740
--- /dev/null
+++ b/Help/prop_tgt/OBJCXX_STANDARD_REQUIRED.rst
@@ -0,0 +1,22 @@
+OBJCXX_STANDARD_REQUIRED
+------------------------
+
+.. versionadded:: 3.16
+
+Boolean describing whether the value of :prop_tgt:`OBJCXX_STANDARD` is a requirement.
+
+If this property is set to ``ON``, then the value of the
+:prop_tgt:`OBJCXX_STANDARD` target property is treated as a requirement. If this
+property is ``OFF`` or unset, the :prop_tgt:`OBJCXX_STANDARD` target property is
+treated as optional and may "decay" to a previous standard if the requested is
+not available.
+
+If the property is not set, and the project has set the :prop_tgt:`CXX_STANDARD_REQUIRED`,
+the value of :prop_tgt:`CXX_STANDARD_REQUIRED` is set for :prop_tgt:`OBJCXX_STANDARD_REQUIRED`.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_OBJCXX_STANDARD_REQUIRED` variable if it is set when a
+target is created.
diff --git a/Help/prop_tgt/OBJC_EXTENSIONS.rst b/Help/prop_tgt/OBJC_EXTENSIONS.rst
new file mode 100644
index 0000000..ef1c754
--- /dev/null
+++ b/Help/prop_tgt/OBJC_EXTENSIONS.rst
@@ -0,0 +1,22 @@
+OBJC_EXTENSIONS
+---------------
+
+.. versionadded:: 3.16
+
+Boolean specifying whether compiler specific extensions are requested.
+
+This property specifies whether compiler specific extensions should be
+used. For some compilers, this results in adding a flag such
+as ``-std=gnu11`` instead of ``-std=c11`` to the compile line. This
+property is ``ON`` by default. The basic OBJC standard level is
+controlled by the :prop_tgt:`OBJC_STANDARD` target property.
+
+If the property is not set, and the project has set the :prop_tgt:`C_EXTENSIONS`,
+the value of :prop_tgt:`C_EXTENSIONS` is set for :prop_tgt:`OBJC_EXTENSIONS`.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_OBJC_EXTENSIONS` variable if it is set when a target
+is created.
diff --git a/Help/prop_tgt/OBJC_STANDARD.rst b/Help/prop_tgt/OBJC_STANDARD.rst
new file mode 100644
index 0000000..2143ff9
--- /dev/null
+++ b/Help/prop_tgt/OBJC_STANDARD.rst
@@ -0,0 +1,37 @@
+OBJC_STANDARD
+-------------
+
+.. versionadded:: 3.16
+
+The OBJC standard whose features are requested to build this target.
+
+This property specifies the OBJC standard whose features are requested
+to build this target. For some compilers, this results in adding a
+flag such as ``-std=gnu11`` to the compile line.
+
+Supported values are ``90``, ``99`` and ``11``.
+
+If the value requested does not result in a compile flag being added for
+the compiler in use, a previous standard flag will be added instead. This
+means that using:
+
+.. code-block:: cmake
+
+ set_property(TARGET tgt PROPERTY OBJC_STANDARD 11)
+
+with a compiler which does not support ``-std=gnu11`` or an equivalent
+flag will not result in an error or warning, but will instead add the
+``-std=gnu99`` or ``-std=gnu90`` flag if supported. This "decay" behavior may
+be controlled with the :prop_tgt:`OBJC_STANDARD_REQUIRED` target property.
+Additionally, the :prop_tgt:`OBJC_EXTENSIONS` target property may be used to
+control whether compiler-specific extensions are enabled on a per-target basis.
+
+If the property is not set, and the project has set the :prop_tgt:`C_STANDARD`,
+the value of :prop_tgt:`C_STANDARD` is set for :prop_tgt:`OBJC_STANDARD`.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_OBJC_STANDARD` variable if it is set when a target
+is created.
diff --git a/Help/prop_tgt/OBJC_STANDARD_REQUIRED.rst b/Help/prop_tgt/OBJC_STANDARD_REQUIRED.rst
new file mode 100644
index 0000000..11547c8
--- /dev/null
+++ b/Help/prop_tgt/OBJC_STANDARD_REQUIRED.rst
@@ -0,0 +1,22 @@
+OBJC_STANDARD_REQUIRED
+----------------------
+
+.. versionadded:: 3.16
+
+Boolean describing whether the value of :prop_tgt:`OBJC_STANDARD` is a requirement.
+
+If this property is set to ``ON``, then the value of the
+:prop_tgt:`OBJC_STANDARD` target property is treated as a requirement. If this
+property is ``OFF`` or unset, the :prop_tgt:`OBJC_STANDARD` target property is
+treated as optional and may "decay" to a previous standard if the requested is
+not available.
+
+If the property is not set, and the project has set the :prop_tgt:`C_STANDARD_REQUIRED`,
+the value of :prop_tgt:`C_STANDARD_REQUIRED` is set for :prop_tgt:`OBJC_STANDARD_REQUIRED`.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_OBJC_STANDARD_REQUIRED` variable if it is set when a
+target is created.
diff --git a/Help/prop_tgt/OPTIMIZE_DEPENDENCIES.rst b/Help/prop_tgt/OPTIMIZE_DEPENDENCIES.rst
new file mode 100644
index 0000000..d17251f
--- /dev/null
+++ b/Help/prop_tgt/OPTIMIZE_DEPENDENCIES.rst
@@ -0,0 +1,43 @@
+OPTIMIZE_DEPENDENCIES
+---------------------
+
+.. versionadded:: 3.19
+
+Activates dependency optimization of static and object libraries.
+
+When this property is set to true, some dependencies for a static or object
+library may be removed at generation time if they are not necessary to build
+the library, since static and object libraries don't actually link against
+anything.
+
+If a static or object library has dependency optimization enabled, it first
+discards all dependencies. Then, it looks through all of the direct and
+indirect dependencies that it initially had, and adds them back if they meet
+any of the following criteria:
+
+* The dependency was added to the library by :command:`add_dependencies`.
+* The dependency was added to the library through a source file in the library
+ generated by a custom command that uses the dependency.
+* The dependency has any ``PRE_BUILD``, ``PRE_LINK``, or ``POST_BUILD`` custom
+ commands associated with it.
+* The dependency contains any source files that were generated by a custom
+ command.
+* The dependency contains any languages which produce side effects that are
+ relevant to the library. Currently, all languages except C, C++, Objective-C,
+ Objective-C++, assembly, and CUDA are assumed to produce side effects.
+ However, side effects from one language are assumed not to be relevant to
+ another (for example, a Fortran library is assumed to not have any side
+ effects that are relevant for a Swift library.)
+
+As an example, assume you have a static Fortran library which depends on a
+static C library, which in turn depends on a static Fortran library. The
+top-level Fortran library has optimization enabled, but the middle C library
+does not. If you build the top Fortran library, the bottom Fortran library will
+also build, but not the middle C library, since the C library does not have any
+side effects that are relevant for the Fortran library. However, if you build
+the middle C library, the bottom Fortran library will also build, even though
+it does not have any side effects that are relevant to the C library, since the
+C library does not have optimization enabled.
+
+This property is initialized by the value of the
+:variable:`CMAKE_OPTIMIZE_DEPENDENCIES` variable when the target is created.
diff --git a/Help/prop_tgt/OSX_ARCHITECTURES.rst b/Help/prop_tgt/OSX_ARCHITECTURES.rst
new file mode 100644
index 0000000..996a4be
--- /dev/null
+++ b/Help/prop_tgt/OSX_ARCHITECTURES.rst
@@ -0,0 +1,11 @@
+OSX_ARCHITECTURES
+-----------------
+
+Target specific architectures for macOS.
+
+The ``OSX_ARCHITECTURES`` property sets the target binary architecture for
+targets on macOS (``-arch``). This property is initialized by the value of the
+variable :variable:`CMAKE_OSX_ARCHITECTURES` if it is set when a target is
+created. Use :prop_tgt:`OSX_ARCHITECTURES_<CONFIG>` to set the binary
+architectures on a per-configuration basis, where ``<CONFIG>`` is an
+upper-case name (e.g. ``OSX_ARCHITECTURES_DEBUG``).
diff --git a/Help/prop_tgt/OSX_ARCHITECTURES_CONFIG.rst b/Help/prop_tgt/OSX_ARCHITECTURES_CONFIG.rst
new file mode 100644
index 0000000..06da4fb
--- /dev/null
+++ b/Help/prop_tgt/OSX_ARCHITECTURES_CONFIG.rst
@@ -0,0 +1,7 @@
+OSX_ARCHITECTURES_<CONFIG>
+--------------------------
+
+Per-configuration macOS and iOS binary architectures for a target.
+
+This property is the configuration-specific version of
+:prop_tgt:`OSX_ARCHITECTURES`.
diff --git a/Help/prop_tgt/OUTPUT_NAME.rst b/Help/prop_tgt/OUTPUT_NAME.rst
new file mode 100644
index 0000000..4b33b38
--- /dev/null
+++ b/Help/prop_tgt/OUTPUT_NAME.rst
@@ -0,0 +1,22 @@
+OUTPUT_NAME
+-----------
+
+Output name for target files.
+
+This sets the base name for output files created for an executable or
+library target. If not set, the logical target name is used by
+default during generation. The value is not set by default during
+configuration.
+
+Contents of ``OUTPUT_NAME`` and the variants listed below may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+See also the variants:
+
+* :prop_tgt:`OUTPUT_NAME_<CONFIG>`
+* :prop_tgt:`ARCHIVE_OUTPUT_NAME_<CONFIG>`
+* :prop_tgt:`ARCHIVE_OUTPUT_NAME`
+* :prop_tgt:`LIBRARY_OUTPUT_NAME_<CONFIG>`
+* :prop_tgt:`LIBRARY_OUTPUT_NAME`
+* :prop_tgt:`RUNTIME_OUTPUT_NAME_<CONFIG>`
+* :prop_tgt:`RUNTIME_OUTPUT_NAME`
diff --git a/Help/prop_tgt/OUTPUT_NAME_CONFIG.rst b/Help/prop_tgt/OUTPUT_NAME_CONFIG.rst
new file mode 100644
index 0000000..41b782f
--- /dev/null
+++ b/Help/prop_tgt/OUTPUT_NAME_CONFIG.rst
@@ -0,0 +1,7 @@
+OUTPUT_NAME_<CONFIG>
+--------------------
+
+Per-configuration target file base name.
+
+This is the configuration-specific version of the :prop_tgt:`OUTPUT_NAME`
+target property.
diff --git a/Help/prop_tgt/PCH_INSTANTIATE_TEMPLATES.rst b/Help/prop_tgt/PCH_INSTANTIATE_TEMPLATES.rst
new file mode 100644
index 0000000..7c1af2a
--- /dev/null
+++ b/Help/prop_tgt/PCH_INSTANTIATE_TEMPLATES.rst
@@ -0,0 +1,13 @@
+PCH_INSTANTIATE_TEMPLATES
+-------------------------
+
+.. versionadded:: 3.19
+
+When this property is set to true, the precompiled header compiler options
+will contain a flag to instantiate templates during the generation of the PCH
+if supported. This can significantly improve compile times. Supported in Clang
+since version 11.
+
+This property is initialized by the value of the
+:variable:`CMAKE_PCH_INSTANTIATE_TEMPLATES` variable if it is set when a target
+is created. If that variable is not set, the property defaults to ``ON``.
diff --git a/Help/prop_tgt/PCH_WARN_INVALID.rst b/Help/prop_tgt/PCH_WARN_INVALID.rst
new file mode 100644
index 0000000..2d5ec55
--- /dev/null
+++ b/Help/prop_tgt/PCH_WARN_INVALID.rst
@@ -0,0 +1,12 @@
+PCH_WARN_INVALID
+----------------
+
+.. versionadded:: 3.18
+
+When this property is set to true, the precompile header compiler options
+will contain a compiler flag which should warn about invalid precompiled
+headers e.g. ``-Winvalid-pch`` for GNU compiler.
+
+This property is initialized by the value of the
+:variable:`CMAKE_PCH_WARN_INVALID` variable if it is set when a target is
+created. If that variable is not set, the property defaults to ``ON``.
diff --git a/Help/prop_tgt/PDB_NAME.rst b/Help/prop_tgt/PDB_NAME.rst
new file mode 100644
index 0000000..3a65796
--- /dev/null
+++ b/Help/prop_tgt/PDB_NAME.rst
@@ -0,0 +1,12 @@
+PDB_NAME
+--------
+
+Output name for the MS debug symbol ``.pdb`` file generated by the
+linker for an executable or shared library target.
+
+This property specifies the base name for the debug symbols file.
+If not set, the :prop_tgt:`OUTPUT_NAME` target property value or
+logical target name is used by default.
+
+.. |COMPILE_PDB_XXX| replace:: :prop_tgt:`COMPILE_PDB_NAME`
+.. include:: PDB_NOTE.txt
diff --git a/Help/prop_tgt/PDB_NAME_CONFIG.rst b/Help/prop_tgt/PDB_NAME_CONFIG.rst
new file mode 100644
index 0000000..cb3121c
--- /dev/null
+++ b/Help/prop_tgt/PDB_NAME_CONFIG.rst
@@ -0,0 +1,10 @@
+PDB_NAME_<CONFIG>
+-----------------
+
+Per-configuration output name for the MS debug symbol ``.pdb`` file
+generated by the linker for an executable or shared library target.
+
+This is the configuration-specific version of :prop_tgt:`PDB_NAME`.
+
+.. |COMPILE_PDB_XXX| replace:: :prop_tgt:`COMPILE_PDB_NAME_<CONFIG>`
+.. include:: PDB_NOTE.txt
diff --git a/Help/prop_tgt/PDB_NOTE.txt b/Help/prop_tgt/PDB_NOTE.txt
new file mode 100644
index 0000000..b5ada07
--- /dev/null
+++ b/Help/prop_tgt/PDB_NOTE.txt
@@ -0,0 +1,9 @@
+.. note::
+ This property does not apply to STATIC library targets because no linker
+ is invoked to produce them so they have no linker-generated ``.pdb`` file
+ containing debug symbols.
+
+ The linker-generated program database files are specified by the
+ ``/pdb`` linker flag and are not the same as compiler-generated
+ program database files specified by the ``/Fd`` compiler flag.
+ Use the |COMPILE_PDB_XXX| property to specify the latter.
diff --git a/Help/prop_tgt/PDB_OUTPUT_DIRECTORY.rst b/Help/prop_tgt/PDB_OUTPUT_DIRECTORY.rst
new file mode 100644
index 0000000..2f667f3
--- /dev/null
+++ b/Help/prop_tgt/PDB_OUTPUT_DIRECTORY.rst
@@ -0,0 +1,19 @@
+PDB_OUTPUT_DIRECTORY
+--------------------
+
+Output directory for the MS debug symbols ``.pdb`` file
+generated by the linker for an executable or shared library target.
+
+This property specifies the directory into which the MS debug symbols
+will be placed by the linker. The property value may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+Multi-configuration generators append a per-configuration
+subdirectory to the specified directory unless a generator expression
+is used.
+
+This property is initialized by the value of the
+:variable:`CMAKE_PDB_OUTPUT_DIRECTORY` variable if it is
+set when a target is created.
+
+.. |COMPILE_PDB_XXX| replace:: :prop_tgt:`COMPILE_PDB_OUTPUT_DIRECTORY`
+.. include:: PDB_NOTE.txt
diff --git a/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst
new file mode 100644
index 0000000..6c55083
--- /dev/null
+++ b/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst
@@ -0,0 +1,19 @@
+PDB_OUTPUT_DIRECTORY_<CONFIG>
+-----------------------------
+
+Per-configuration output directory for the MS debug symbol ``.pdb`` file
+generated by the linker for an executable or shared library target.
+
+This is a per-configuration version of :prop_tgt:`PDB_OUTPUT_DIRECTORY`,
+but multi-configuration generators (:ref:`Visual Studio Generators`,
+:generator:`Xcode`) do NOT append a
+per-configuration subdirectory to the specified directory. This
+property is initialized by the value of the
+:variable:`CMAKE_PDB_OUTPUT_DIRECTORY_<CONFIG>` variable if it is
+set when a target is created.
+
+Contents of ``PDB_OUTPUT_DIRECTORY_<CONFIG>`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+.. |COMPILE_PDB_XXX| replace:: :prop_tgt:`COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG>`
+.. include:: PDB_NOTE.txt
diff --git a/Help/prop_tgt/POSITION_INDEPENDENT_CODE.rst b/Help/prop_tgt/POSITION_INDEPENDENT_CODE.rst
new file mode 100644
index 0000000..0aaf66b
--- /dev/null
+++ b/Help/prop_tgt/POSITION_INDEPENDENT_CODE.rst
@@ -0,0 +1,16 @@
+POSITION_INDEPENDENT_CODE
+-------------------------
+
+Whether to create a position-independent target
+
+The ``POSITION_INDEPENDENT_CODE`` property determines whether position
+independent executables or shared libraries will be created. This
+property is ``True`` by default for ``SHARED`` and ``MODULE`` library
+targets and ``False`` otherwise. This property is initialized by the value
+of the :variable:`CMAKE_POSITION_INDEPENDENT_CODE` variable if it is set
+when a target is created.
+
+.. note::
+
+ For executable targets, the link step is controlled by the :policy:`CMP0083`
+ policy and the :module:`CheckPIESupported` module.
diff --git a/Help/prop_tgt/POST_INSTALL_SCRIPT.rst b/Help/prop_tgt/POST_INSTALL_SCRIPT.rst
new file mode 100644
index 0000000..23935bc
--- /dev/null
+++ b/Help/prop_tgt/POST_INSTALL_SCRIPT.rst
@@ -0,0 +1,9 @@
+POST_INSTALL_SCRIPT
+-------------------
+
+Deprecated install support.
+
+The :prop_tgt:`PRE_INSTALL_SCRIPT` and ``POST_INSTALL_SCRIPT`` properties are
+the old way to specify CMake scripts to run before and after installing a
+target. They are used only when the old ``INSTALL_TARGETS`` command is
+used to install the target. Use the :command:`install` command instead.
diff --git a/Help/prop_tgt/PRECOMPILE_HEADERS.rst b/Help/prop_tgt/PRECOMPILE_HEADERS.rst
new file mode 100644
index 0000000..af27947
--- /dev/null
+++ b/Help/prop_tgt/PRECOMPILE_HEADERS.rst
@@ -0,0 +1,14 @@
+PRECOMPILE_HEADERS
+------------------
+
+.. versionadded:: 3.16
+
+List of header files to precompile.
+
+This property holds a :ref:`semicolon-separated list <CMake Language Lists>`
+of header files to precompile specified so far for its target.
+Use the :command:`target_precompile_headers` command to append more header
+files.
+
+This property supports
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/prop_tgt/PRECOMPILE_HEADERS_REUSE_FROM.rst b/Help/prop_tgt/PRECOMPILE_HEADERS_REUSE_FROM.rst
new file mode 100644
index 0000000..6f5635b
--- /dev/null
+++ b/Help/prop_tgt/PRECOMPILE_HEADERS_REUSE_FROM.rst
@@ -0,0 +1,9 @@
+PRECOMPILE_HEADERS_REUSE_FROM
+-----------------------------
+
+.. versionadded:: 3.16
+
+Target from which to reuse the precompiled headers build artifact.
+
+See the second signature of :command:`target_precompile_headers` command
+for more detailed information.
diff --git a/Help/prop_tgt/PREFIX.rst b/Help/prop_tgt/PREFIX.rst
new file mode 100644
index 0000000..a401292
--- /dev/null
+++ b/Help/prop_tgt/PREFIX.rst
@@ -0,0 +1,7 @@
+PREFIX
+------
+
+What comes before the library name.
+
+A target property that can be set to override the prefix (such as
+``lib``) on a library name.
diff --git a/Help/prop_tgt/PRE_INSTALL_SCRIPT.rst b/Help/prop_tgt/PRE_INSTALL_SCRIPT.rst
new file mode 100644
index 0000000..43432f4
--- /dev/null
+++ b/Help/prop_tgt/PRE_INSTALL_SCRIPT.rst
@@ -0,0 +1,9 @@
+PRE_INSTALL_SCRIPT
+------------------
+
+Deprecated install support.
+
+The ``PRE_INSTALL_SCRIPT`` and :prop_tgt:`POST_INSTALL_SCRIPT` properties are
+the old way to specify CMake scripts to run before and after installing a
+target. They are used only when the old ``INSTALL_TARGETS`` command is
+used to install the target. Use the :command:`install` command instead.
diff --git a/Help/prop_tgt/PRIVATE_HEADER.rst b/Help/prop_tgt/PRIVATE_HEADER.rst
new file mode 100644
index 0000000..23e1f8e
--- /dev/null
+++ b/Help/prop_tgt/PRIVATE_HEADER.rst
@@ -0,0 +1,11 @@
+PRIVATE_HEADER
+--------------
+
+Specify private header files in a :prop_tgt:`FRAMEWORK` shared library target.
+
+Shared library targets marked with the :prop_tgt:`FRAMEWORK` property generate
+frameworks on macOS, iOS and normal shared libraries on other platforms.
+This property may be set to a list of header files to be placed in the
+PrivateHeaders directory inside the framework folder. On non-Apple
+platforms these headers may be installed using the ``PRIVATE_HEADER``
+option to the :command:`install(TARGETS)` command.
diff --git a/Help/prop_tgt/PROJECT_LABEL.rst b/Help/prop_tgt/PROJECT_LABEL.rst
new file mode 100644
index 0000000..a1491ee
--- /dev/null
+++ b/Help/prop_tgt/PROJECT_LABEL.rst
@@ -0,0 +1,7 @@
+PROJECT_LABEL
+-------------
+
+Change the name of a target in an IDE.
+
+Can be used to change the name of the target in an IDE like Visual
+Studio.
diff --git a/Help/prop_tgt/PUBLIC_HEADER.rst b/Help/prop_tgt/PUBLIC_HEADER.rst
new file mode 100644
index 0000000..915e39c
--- /dev/null
+++ b/Help/prop_tgt/PUBLIC_HEADER.rst
@@ -0,0 +1,11 @@
+PUBLIC_HEADER
+-------------
+
+Specify public header files in a :prop_tgt:`FRAMEWORK` shared library target.
+
+Shared library targets marked with the :prop_tgt:`FRAMEWORK` property generate
+frameworks on macOS, iOS and normal shared libraries on other platforms.
+This property may be set to a list of header files to be placed in the
+``Headers`` directory inside the framework folder. On non-Apple platforms
+these headers may be installed using the ``PUBLIC_HEADER`` option to the
+:command:`install(TARGETS)` command.
diff --git a/Help/prop_tgt/RESOURCE.rst b/Help/prop_tgt/RESOURCE.rst
new file mode 100644
index 0000000..e5a1cb6
--- /dev/null
+++ b/Help/prop_tgt/RESOURCE.rst
@@ -0,0 +1,58 @@
+RESOURCE
+--------
+
+Specify resource files in a :prop_tgt:`FRAMEWORK` or :prop_tgt:`BUNDLE`.
+
+Target marked with the :prop_tgt:`FRAMEWORK` or :prop_tgt:`BUNDLE` property
+generate framework or application bundle (both macOS and iOS is supported)
+or normal shared libraries on other platforms.
+This property may be set to a list of files to be placed in the corresponding
+directory (eg. ``Resources`` directory for macOS) inside the bundle.
+On non-Apple platforms these files may be installed using the ``RESOURCE``
+option to the :command:`install(TARGETS)` command.
+
+Following example of Application Bundle:
+
+.. code-block:: cmake
+
+ add_executable(ExecutableTarget
+ addDemo.c
+ resourcefile.txt
+ appresourcedir/appres.txt)
+
+ target_link_libraries(ExecutableTarget heymath mul)
+
+ set(RESOURCE_FILES
+ resourcefile.txt
+ appresourcedir/appres.txt)
+
+ set_target_properties(ExecutableTarget PROPERTIES
+ MACOSX_BUNDLE TRUE
+ MACOSX_FRAMEWORK_IDENTIFIER org.cmake.ExecutableTarget
+ RESOURCE "${RESOURCE_FILES}")
+
+will produce flat structure for iOS systems::
+
+ ExecutableTarget.app
+ appres.txt
+ ExecutableTarget
+ Info.plist
+ resourcefile.txt
+
+For macOS systems it will produce following directory structure::
+
+ ExecutableTarget.app/
+ Contents
+ Info.plist
+ MacOS
+ ExecutableTarget
+ Resources
+ appres.txt
+ resourcefile.txt
+
+For Linux, such CMake script produce following files::
+
+ ExecutableTarget
+ Resources
+ appres.txt
+ resourcefile.txt
diff --git a/Help/prop_tgt/RULE_LAUNCH_COMPILE.rst b/Help/prop_tgt/RULE_LAUNCH_COMPILE.rst
new file mode 100644
index 0000000..e92ab86
--- /dev/null
+++ b/Help/prop_tgt/RULE_LAUNCH_COMPILE.rst
@@ -0,0 +1,7 @@
+RULE_LAUNCH_COMPILE
+-------------------
+
+Specify a launcher for compile rules.
+
+See the global property of the same name for details. This overrides
+the global and directory property for a target.
diff --git a/Help/prop_tgt/RULE_LAUNCH_CUSTOM.rst b/Help/prop_tgt/RULE_LAUNCH_CUSTOM.rst
new file mode 100644
index 0000000..2db0317
--- /dev/null
+++ b/Help/prop_tgt/RULE_LAUNCH_CUSTOM.rst
@@ -0,0 +1,7 @@
+RULE_LAUNCH_CUSTOM
+------------------
+
+Specify a launcher for custom rules.
+
+See the global property of the same name for details. This overrides
+the global and directory property for a target.
diff --git a/Help/prop_tgt/RULE_LAUNCH_LINK.rst b/Help/prop_tgt/RULE_LAUNCH_LINK.rst
new file mode 100644
index 0000000..f330033
--- /dev/null
+++ b/Help/prop_tgt/RULE_LAUNCH_LINK.rst
@@ -0,0 +1,7 @@
+RULE_LAUNCH_LINK
+----------------
+
+Specify a launcher for link rules.
+
+See the global property of the same name for details. This overrides
+the global and directory property for a target.
diff --git a/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.rst b/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.rst
new file mode 100644
index 0000000..3c37546
--- /dev/null
+++ b/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.rst
@@ -0,0 +1,9 @@
+RUNTIME_OUTPUT_DIRECTORY
+------------------------
+
+.. |XXX| replace:: :ref:`RUNTIME <Runtime Output Artifacts>`
+.. |xxx| replace:: runtime
+.. |CMAKE_XXX_OUTPUT_DIRECTORY| replace:: :variable:`CMAKE_RUNTIME_OUTPUT_DIRECTORY`
+.. include:: XXX_OUTPUT_DIRECTORY.txt
+
+See also the :prop_tgt:`RUNTIME_OUTPUT_DIRECTORY_<CONFIG>` target property.
diff --git a/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
new file mode 100644
index 0000000..6727754
--- /dev/null
+++ b/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
@@ -0,0 +1,17 @@
+RUNTIME_OUTPUT_DIRECTORY_<CONFIG>
+---------------------------------
+
+Per-configuration output directory for
+:ref:`RUNTIME <Runtime Output Artifacts>` target files.
+
+This is a per-configuration version of the
+:prop_tgt:`RUNTIME_OUTPUT_DIRECTORY` target property, but
+multi-configuration generators (:ref:`Visual Studio Generators`,
+:generator:`Xcode`) do NOT append a
+per-configuration subdirectory to the specified directory. This
+property is initialized by the value of the
+:variable:`CMAKE_RUNTIME_OUTPUT_DIRECTORY_<CONFIG>` variable if
+it is set when a target is created.
+
+Contents of ``RUNTIME_OUTPUT_DIRECTORY_<CONFIG>`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/prop_tgt/RUNTIME_OUTPUT_NAME.rst b/Help/prop_tgt/RUNTIME_OUTPUT_NAME.rst
new file mode 100644
index 0000000..11729c3
--- /dev/null
+++ b/Help/prop_tgt/RUNTIME_OUTPUT_NAME.rst
@@ -0,0 +1,8 @@
+RUNTIME_OUTPUT_NAME
+-------------------
+
+.. |XXX| replace:: :ref:`RUNTIME <Runtime Output Artifacts>`
+.. |xxx| replace:: runtime
+.. include:: XXX_OUTPUT_NAME.txt
+
+See also the :prop_tgt:`RUNTIME_OUTPUT_NAME_<CONFIG>` target property.
diff --git a/Help/prop_tgt/RUNTIME_OUTPUT_NAME_CONFIG.rst b/Help/prop_tgt/RUNTIME_OUTPUT_NAME_CONFIG.rst
new file mode 100644
index 0000000..b6a31bf
--- /dev/null
+++ b/Help/prop_tgt/RUNTIME_OUTPUT_NAME_CONFIG.rst
@@ -0,0 +1,8 @@
+RUNTIME_OUTPUT_NAME_<CONFIG>
+----------------------------
+
+Per-configuration output name for
+:ref:`RUNTIME <Runtime Output Artifacts>` target files.
+
+This is the configuration-specific version of the
+:prop_tgt:`RUNTIME_OUTPUT_NAME` target property.
diff --git a/Help/prop_tgt/SKIP_BUILD_RPATH.rst b/Help/prop_tgt/SKIP_BUILD_RPATH.rst
new file mode 100644
index 0000000..7086b1b
--- /dev/null
+++ b/Help/prop_tgt/SKIP_BUILD_RPATH.rst
@@ -0,0 +1,9 @@
+SKIP_BUILD_RPATH
+----------------
+
+Should rpaths be used for the build tree.
+
+``SKIP_BUILD_RPATH`` is a boolean specifying whether to skip automatic
+generation of an rpath allowing the target to run from the build tree.
+This property is initialized by the value of the variable
+:variable:`CMAKE_SKIP_BUILD_RPATH` if it is set when a target is created.
diff --git a/Help/prop_tgt/SOURCES.rst b/Help/prop_tgt/SOURCES.rst
new file mode 100644
index 0000000..493643e
--- /dev/null
+++ b/Help/prop_tgt/SOURCES.rst
@@ -0,0 +1,6 @@
+SOURCES
+-------
+
+Source names specified for a target.
+
+List of sources specified for a target.
diff --git a/Help/prop_tgt/SOURCE_DIR.rst b/Help/prop_tgt/SOURCE_DIR.rst
new file mode 100644
index 0000000..78ce220
--- /dev/null
+++ b/Help/prop_tgt/SOURCE_DIR.rst
@@ -0,0 +1,8 @@
+SOURCE_DIR
+----------
+
+.. versionadded:: 3.4
+
+This read-only property reports the value of the
+:variable:`CMAKE_CURRENT_SOURCE_DIR` variable in the directory in which
+the target was defined.
diff --git a/Help/prop_tgt/SOVERSION.rst b/Help/prop_tgt/SOVERSION.rst
new file mode 100644
index 0000000..b377f22
--- /dev/null
+++ b/Help/prop_tgt/SOVERSION.rst
@@ -0,0 +1,37 @@
+SOVERSION
+---------
+
+What version number is this target.
+
+For shared libraries :prop_tgt:`VERSION` and ``SOVERSION`` can be used to
+specify the build version and API version respectively. When building or
+installing appropriate symlinks are created if the platform supports
+symlinks and the linker supports so-names. If only one of both is
+specified the missing is assumed to have the same version number.
+``SOVERSION`` is ignored if :prop_tgt:`NO_SONAME` property is set.
+
+Windows Versions
+^^^^^^^^^^^^^^^^
+
+For shared libraries and executables on Windows the :prop_tgt:`VERSION`
+attribute is parsed to extract a ``<major>.<minor>`` version number.
+These numbers are used as the image version of the binary.
+
+Mach-O Versions
+^^^^^^^^^^^^^^^
+
+For shared libraries and executables on Mach-O systems (e.g. macOS, iOS),
+the ``SOVERSION`` property corresponds to the *compatibility version* and
+:prop_tgt:`VERSION` corresponds to the *current version* (unless Mach-O
+specific overrides are provided, as discussed below).
+See the :prop_tgt:`FRAMEWORK` target property for an example.
+
+For shared libraries, the :prop_tgt:`MACHO_COMPATIBILITY_VERSION` and
+:prop_tgt:`MACHO_CURRENT_VERSION` properties can be used to
+override the *compatibility version* and *current version* respectively.
+Note that ``SOVERSION`` will still be used to form the ``install_name``
+and both ``SOVERSION`` and :prop_tgt:`VERSION` may also affect the file
+and symlink names.
+
+Versions of Mach-O binaries may be checked with the ``otool -L <binary>``
+command.
diff --git a/Help/prop_tgt/STATIC_LIBRARY_FLAGS.rst b/Help/prop_tgt/STATIC_LIBRARY_FLAGS.rst
new file mode 100644
index 0000000..66e0e8b
--- /dev/null
+++ b/Help/prop_tgt/STATIC_LIBRARY_FLAGS.rst
@@ -0,0 +1,17 @@
+STATIC_LIBRARY_FLAGS
+--------------------
+
+Archiver (or MSVC librarian) flags for a static library target.
+Targets that are shared libraries, modules, or executables need to use
+the :prop_tgt:`LINK_OPTIONS` or :prop_tgt:`LINK_FLAGS` target properties.
+
+The ``STATIC_LIBRARY_FLAGS`` property, managed as a string, can be used to add
+extra flags to the link step of a static library target.
+:prop_tgt:`STATIC_LIBRARY_FLAGS_<CONFIG>` will add to the configuration
+``<CONFIG>``, for example, ``DEBUG``, ``RELEASE``, ``MINSIZEREL``,
+``RELWITHDEBINFO``, ...
+
+.. note::
+
+ This property has been superseded by :prop_tgt:`STATIC_LIBRARY_OPTIONS`
+ property.
diff --git a/Help/prop_tgt/STATIC_LIBRARY_FLAGS_CONFIG.rst b/Help/prop_tgt/STATIC_LIBRARY_FLAGS_CONFIG.rst
new file mode 100644
index 0000000..5b97941
--- /dev/null
+++ b/Help/prop_tgt/STATIC_LIBRARY_FLAGS_CONFIG.rst
@@ -0,0 +1,12 @@
+STATIC_LIBRARY_FLAGS_<CONFIG>
+-----------------------------
+
+Per-configuration archiver (or MSVC librarian) flags for a static library
+target.
+
+This is the configuration-specific version of :prop_tgt:`STATIC_LIBRARY_FLAGS`.
+
+.. note::
+
+ This property has been superseded by :prop_tgt:`STATIC_LIBRARY_OPTIONS`
+ property.
diff --git a/Help/prop_tgt/STATIC_LIBRARY_OPTIONS.rst b/Help/prop_tgt/STATIC_LIBRARY_OPTIONS.rst
new file mode 100644
index 0000000..2f4a3ba
--- /dev/null
+++ b/Help/prop_tgt/STATIC_LIBRARY_OPTIONS.rst
@@ -0,0 +1,22 @@
+STATIC_LIBRARY_OPTIONS
+----------------------
+
+.. versionadded:: 3.13
+
+Archiver (or MSVC librarian) flags for a static library target.
+Targets that are shared libraries, modules, or executables need to use
+the :prop_tgt:`LINK_OPTIONS` target property.
+
+This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of options
+specified so far for its target. Use :command:`set_target_properties` or
+:command:`set_property` commands to set its content.
+
+Contents of ``STATIC_LIBRARY_OPTIONS`` may use "generator expressions" with the
+syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions. See the :manual:`cmake-buildsystem(7)` manual
+for more on defining buildsystem properties.
+
+.. note::
+
+ This property must be used in preference to :prop_tgt:`STATIC_LIBRARY_FLAGS`
+ property.
diff --git a/Help/prop_tgt/SUFFIX.rst b/Help/prop_tgt/SUFFIX.rst
new file mode 100644
index 0000000..32ec429
--- /dev/null
+++ b/Help/prop_tgt/SUFFIX.rst
@@ -0,0 +1,7 @@
+SUFFIX
+------
+
+What comes after the target name.
+
+A target property that can be set to override the suffix (such as
+``.so`` or ``.exe``) on the name of a library, module or executable.
diff --git a/Help/prop_tgt/Swift_DEPENDENCIES_FILE.rst b/Help/prop_tgt/Swift_DEPENDENCIES_FILE.rst
new file mode 100644
index 0000000..0f944b6
--- /dev/null
+++ b/Help/prop_tgt/Swift_DEPENDENCIES_FILE.rst
@@ -0,0 +1,7 @@
+Swift_DEPENDENCIES_FILE
+-----------------------
+
+.. versionadded:: 3.15
+
+This property sets the path for the Swift dependency file (swiftdep) for the
+target. If one is not specified, it will default to ``<TARGET>.swiftdeps``.
diff --git a/Help/prop_tgt/Swift_LANGUAGE_VERSION.rst b/Help/prop_tgt/Swift_LANGUAGE_VERSION.rst
new file mode 100644
index 0000000..afc6b31
--- /dev/null
+++ b/Help/prop_tgt/Swift_LANGUAGE_VERSION.rst
@@ -0,0 +1,8 @@
+Swift_LANGUAGE_VERSION
+----------------------
+
+.. versionadded:: 3.16
+
+This property sets the language version for the Swift sources in the target. If
+one is not specified, it will default to ``<CMAKE_Swift_LANGUAGE_VERSION>`` if
+specified, otherwise it is the latest version supported by the compiler.
diff --git a/Help/prop_tgt/Swift_MODULE_DIRECTORY.rst b/Help/prop_tgt/Swift_MODULE_DIRECTORY.rst
new file mode 100644
index 0000000..a6484f2
--- /dev/null
+++ b/Help/prop_tgt/Swift_MODULE_DIRECTORY.rst
@@ -0,0 +1,12 @@
+Swift_MODULE_DIRECTORY
+----------------------
+
+.. versionadded:: 3.15
+
+Specify output directory for Swift modules provided by the target.
+
+If the target contains Swift source files, this specifies the directory in which
+the modules will be placed. When this property is not set, the modules will be
+placed in the build directory corresponding to the target's source directory.
+If the variable :variable:`CMAKE_Swift_MODULE_DIRECTORY` is set when a target is
+created its value is used to initialise this property.
diff --git a/Help/prop_tgt/Swift_MODULE_NAME.rst b/Help/prop_tgt/Swift_MODULE_NAME.rst
new file mode 100644
index 0000000..d941b54
--- /dev/null
+++ b/Help/prop_tgt/Swift_MODULE_NAME.rst
@@ -0,0 +1,7 @@
+Swift_MODULE_NAME
+-----------------
+
+.. versionadded:: 3.15
+
+This property specifies the name of the Swift module. It is defaulted to the
+name of the target.
diff --git a/Help/prop_tgt/TYPE.rst b/Help/prop_tgt/TYPE.rst
new file mode 100644
index 0000000..3136d11
--- /dev/null
+++ b/Help/prop_tgt/TYPE.rst
@@ -0,0 +1,9 @@
+TYPE
+----
+
+The type of the target.
+
+This read-only property can be used to test the type of the given
+target. It will be one of ``STATIC_LIBRARY``, ``MODULE_LIBRARY``,
+``SHARED_LIBRARY``, ``OBJECT_LIBRARY``, ``INTERFACE_LIBRARY``, ``EXECUTABLE``
+or one of the internal target types.
diff --git a/Help/prop_tgt/UNITY_BUILD.rst b/Help/prop_tgt/UNITY_BUILD.rst
new file mode 100644
index 0000000..f827a20
--- /dev/null
+++ b/Help/prop_tgt/UNITY_BUILD.rst
@@ -0,0 +1,87 @@
+UNITY_BUILD
+-----------
+
+.. versionadded:: 3.16
+
+When this property is set to true, the target source files will be combined
+into batches for faster compilation. This is done by creating a (set of)
+unity sources which ``#include`` the original sources, then compiling these
+unity sources instead of the originals. This is known as a *Unity* or *Jumbo*
+build.
+
+CMake provides different algorithms for selecting which sources are grouped
+together into a *bucket*. Algorithm selection is decided by the
+:prop_tgt:`UNITY_BUILD_MODE` target property, which has the following acceptable
+values:
+
+* ``BATCH``
+ When in this mode CMake determines which files are grouped together.
+ The :prop_tgt:`UNITY_BUILD_BATCH_SIZE` property controls the upper limit on
+ how many sources can be combined per unity source file.
+
+* ``GROUP``
+ When in this mode each target explicitly specifies how to group
+ source files. Each source file that has the same
+ :prop_sf:`UNITY_GROUP` value will be grouped together. Any sources
+ that don't have this property will be compiled individually. The
+ :prop_tgt:`UNITY_BUILD_BATCH_SIZE` property is ignored when using
+ this mode.
+
+If no explicit :prop_tgt:`UNITY_BUILD_MODE` has been specified, CMake will
+default to ``BATCH``.
+
+Unity builds are not currently supported for all languages. CMake version
+|release| supports combining ``C`` and ``CXX`` source files. For targets that
+mix source files from more than one language, CMake will separate the languages
+such that each generated unity source file only contains sources for a single
+language.
+
+This property is initialized by the value of the :variable:`CMAKE_UNITY_BUILD`
+variable when a target is created.
+
+.. note::
+
+ Projects should not directly set the ``UNITY_BUILD`` property or its
+ associated :variable:`CMAKE_UNITY_BUILD` variable to true. Depending
+ on the capabilities of the build machine and compiler used, it might or
+ might not be appropriate to enable unity builds. Therefore, this feature
+ should be under developer control, which would normally be through the
+ developer choosing whether or not to set the :variable:`CMAKE_UNITY_BUILD`
+ variable on the :manual:`cmake(1)` command line or some other equivalent
+ method. However, it IS recommended to set the ``UNITY_BUILD`` target
+ property to false if it is known that enabling unity builds for the
+ target can lead to problems.
+
+ODR (One definition rule) errors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When multiple source files are included into one source file, as is done
+for unity builds, it can potentially lead to ODR errors. CMake provides
+a number of measures to help address such problems:
+
+* Any source file that has a non-empty :prop_sf:`COMPILE_OPTIONS`,
+ :prop_sf:`COMPILE_DEFINITIONS`, :prop_sf:`COMPILE_FLAGS`, or
+ :prop_sf:`INCLUDE_DIRECTORIES` source property will not be combined
+ into a unity source.
+
+* Projects can prevent an individual source file from being combined into
+ a unity source by setting its :prop_sf:`SKIP_UNITY_BUILD_INCLUSION`
+ source property to true. This can be a more effective way to prevent
+ problems with specific files than disabling unity builds for an entire
+ target.
+
+* Projects can set :prop_tgt:`UNITY_BUILD_UNIQUE_ID` to cause a valid
+ C-identifier to be generated which is unique per file in a unity
+ build. This can be used to avoid problems with anonymous namespaces
+ in unity builds.
+
+* The :prop_tgt:`UNITY_BUILD_CODE_BEFORE_INCLUDE` and
+ :prop_tgt:`UNITY_BUILD_CODE_AFTER_INCLUDE` target properties can be used
+ to inject code into the unity source files before and after every
+ ``#include`` statement.
+
+* The order of source files added to the target via commands like
+ :command:`add_library`, :command:`add_executable` or
+ :command:`target_sources` will be preserved in the generated unity source
+ files. This can be used to manually enforce a specific grouping based on
+ the :prop_tgt:`UNITY_BUILD_BATCH_SIZE` target property.
diff --git a/Help/prop_tgt/UNITY_BUILD_BATCH_SIZE.rst b/Help/prop_tgt/UNITY_BUILD_BATCH_SIZE.rst
new file mode 100644
index 0000000..3886ec9
--- /dev/null
+++ b/Help/prop_tgt/UNITY_BUILD_BATCH_SIZE.rst
@@ -0,0 +1,25 @@
+UNITY_BUILD_BATCH_SIZE
+----------------------
+
+.. versionadded:: 3.16
+
+Specifies the maximum number of source files that can be combined into any one
+unity source file when unity builds are enabled by the :prop_tgt:`UNITY_BUILD`
+target property. The original source files will be distributed across as many
+unity source files as necessary to honor this limit.
+
+The initial value for this property is taken from the
+:variable:`CMAKE_UNITY_BUILD_BATCH_SIZE` variable when the target is created.
+If that variable has not been set, the initial value will be 8.
+
+The batch size needs to be selected carefully. If set too high, the size of
+the combined source files could result in the compiler using excessive memory
+or hitting other similar limits. In extreme cases, this can even result in
+build failure. On the other hand, if the batch size is too low, there will be
+little gain in build performance.
+
+Although strongly discouraged, the batch size may be set to a value of 0 to
+combine all the sources for the target into a single unity file, regardless of
+how many sources are involved. This runs the risk of creating an excessively
+large unity source file and negatively impacting the build performance, so
+a value of 0 is not generally recommended.
diff --git a/Help/prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE.rst b/Help/prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE.rst
new file mode 100644
index 0000000..ac2b19c
--- /dev/null
+++ b/Help/prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE.rst
@@ -0,0 +1,21 @@
+UNITY_BUILD_CODE_AFTER_INCLUDE
+------------------------------
+
+.. versionadded:: 3.16
+
+Code snippet which is included verbatim by the :prop_tgt:`UNITY_BUILD`
+feature just after every ``#include`` statement in the generated unity
+source files. For example:
+
+.. code-block:: cmake
+
+ set(after [[
+ #if defined(NOMINMAX)
+ #undef NOMINMAX
+ #endif
+ ]])
+ set_target_properties(myTarget PROPERTIES
+ UNITY_BUILD_CODE_AFTER_INCLUDE "${after}"
+ )
+
+See also :prop_tgt:`UNITY_BUILD_CODE_BEFORE_INCLUDE`.
diff --git a/Help/prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE.rst b/Help/prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE.rst
new file mode 100644
index 0000000..6f0d56b
--- /dev/null
+++ b/Help/prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE.rst
@@ -0,0 +1,21 @@
+UNITY_BUILD_CODE_BEFORE_INCLUDE
+-------------------------------
+
+.. versionadded:: 3.16
+
+Code snippet which is included verbatim by the :prop_tgt:`UNITY_BUILD`
+feature just before every ``#include`` statement in the generated unity
+source files. For example:
+
+.. code-block:: cmake
+
+ set(before [[
+ #if !defined(NOMINMAX)
+ #define NOMINMAX
+ #endif
+ ]])
+ set_target_properties(myTarget PROPERTIES
+ UNITY_BUILD_CODE_BEFORE_INCLUDE "${before}"
+ )
+
+See also :prop_tgt:`UNITY_BUILD_CODE_AFTER_INCLUDE`.
diff --git a/Help/prop_tgt/UNITY_BUILD_MODE.rst b/Help/prop_tgt/UNITY_BUILD_MODE.rst
new file mode 100644
index 0000000..003451e
--- /dev/null
+++ b/Help/prop_tgt/UNITY_BUILD_MODE.rst
@@ -0,0 +1,60 @@
+UNITY_BUILD_MODE
+----------------
+
+.. versionadded:: 3.18
+
+CMake provides different algorithms for selecting which sources are grouped
+together into a *bucket*. Selection is decided by this property,
+which has the following acceptable values:
+
+``BATCH``
+ When in this mode CMake determines which files are grouped together.
+ The :prop_tgt:`UNITY_BUILD_BATCH_SIZE` property controls the upper limit on
+ how many sources can be combined per unity source file.
+
+ Example usage:
+
+ .. code-block:: cmake
+
+ add_library(example_library
+ source1.cxx
+ source2.cxx
+ source3.cxx
+ source4.cxx)
+
+ set_target_properties(example_library PROPERTIES
+ UNITY_BUILD_MODE BATCH
+ UNITY_BUILD_BATCH_SIZE 2
+ )
+
+``GROUP``
+ When in this mode each target explicitly specifies how to group
+ source files. Each source file that has the same
+ :prop_sf:`UNITY_GROUP` value will be grouped together. Any sources
+ that don't have this property will be compiled individually. The
+ :prop_tgt:`UNITY_BUILD_BATCH_SIZE` property is ignored when using
+ this mode.
+
+ Example usage:
+
+ .. code-block:: cmake
+
+ add_library(example_library
+ source1.cxx
+ source2.cxx
+ source3.cxx
+ source4.cxx)
+
+ set_target_properties(example_library PROPERTIES
+ UNITY_BUILD_MODE GROUP
+ )
+
+ set_source_files_properties(source1.cxx source2.cxx source3.cxx
+ PROPERTIES UNITY_GROUP "bucket1"
+ )
+ set_source_files_properties(source4.cxx
+ PROPERTIES UNITY_GROUP "bucket2"
+ )
+
+If no explicit :prop_tgt:`UNITY_BUILD_MODE` has been specified, CMake will
+default to ``BATCH``.
diff --git a/Help/prop_tgt/UNITY_BUILD_UNIQUE_ID.rst b/Help/prop_tgt/UNITY_BUILD_UNIQUE_ID.rst
new file mode 100644
index 0000000..2c95e02
--- /dev/null
+++ b/Help/prop_tgt/UNITY_BUILD_UNIQUE_ID.rst
@@ -0,0 +1,55 @@
+UNITY_BUILD_UNIQUE_ID
+---------------------
+
+.. versionadded:: 3.20
+
+The name of a valid C-identifier which is set to a unique per-file
+value during unity builds.
+
+When this property is populated and when :prop_tgt:`UNITY_BUILD`
+is true, the property value is used to define a compiler definition
+of the specified name. The value of the defined symbol is unspecified,
+but it is unique per file path.
+
+Given:
+
+.. code-block:: cmake
+
+ set_target_properties(myTarget PROPERTIES
+ UNITY_BUILD "ON"
+ UNITY_BUILD_UNIQUE_ID "MY_UNITY_ID"
+ )
+
+the ``MY_UNITY_ID`` symbol is defined to a unique per-file value.
+
+One known use case for this identifier is to disambiguate the
+variables in an anonymous namespace in a limited scope.
+Anonymous namespaces present a problem for unity builds because
+they are used to ensure that certain variables and declarations
+are scoped to a translation unit which is approximated by a
+single source file. When source files are combined in a unity
+build file, those variables in different files are combined in
+a single translation unit and the names clash. This property can
+be used to avoid that with code like the following:
+
+.. code-block:: cpp
+
+ // Needed for when unity builds are disabled
+ #ifndef MY_UNITY_ID
+ #define MY_UNITY_ID
+ #endif
+
+ namespace { namespace MY_UNITY_ID {
+ // The name 'i' clashes (or could clash) with other
+ // variables in other anonymous namespaces
+ int i = 42;
+ }}
+
+ int use_var()
+ {
+ return MY_UNITY_ID::i;
+ }
+
+The pseudononymous namespace is used within a truly anonymous namespace.
+On many platforms, this maintains the invariant that the symbols within
+do not get external linkage when performing a unity build.
diff --git a/Help/prop_tgt/VERSION.rst b/Help/prop_tgt/VERSION.rst
new file mode 100644
index 0000000..95db483
--- /dev/null
+++ b/Help/prop_tgt/VERSION.rst
@@ -0,0 +1,39 @@
+VERSION
+-------
+
+What version number is this target.
+
+For shared libraries ``VERSION`` and :prop_tgt:`SOVERSION` can be used
+to specify the build version and API version respectively. When building or
+installing appropriate symlinks are created if the platform supports
+symlinks and the linker supports so-names. If only one of both is
+specified the missing is assumed to have the same version number. For
+executables ``VERSION`` can be used to specify the build version. When
+building or installing appropriate symlinks are created if the
+platform supports symlinks.
+
+Windows Versions
+^^^^^^^^^^^^^^^^
+
+For shared libraries and executables on Windows the ``VERSION``
+attribute is parsed to extract a ``<major>.<minor>`` version number.
+These numbers are used as the image version of the binary.
+
+Mach-O Versions
+^^^^^^^^^^^^^^^
+
+For shared libraries and executables on Mach-O systems (e.g. macOS, iOS),
+the :prop_tgt:`SOVERSION` property corresponds to the *compatibility version*
+and ``VERSION`` corresponds to the *current version* (unless Mach-O specific
+overrides are provided, as discussed below).
+See the :prop_tgt:`FRAMEWORK` target property for an example.
+
+For shared libraries, the :prop_tgt:`MACHO_COMPATIBILITY_VERSION` and
+:prop_tgt:`MACHO_CURRENT_VERSION` properties can be used to
+override the *compatibility version* and *current version* respectively.
+Note that :prop_tgt:`SOVERSION` will still be used to form the
+``install_name`` and both :prop_tgt:`SOVERSION` and ``VERSION`` may also
+affect the file and symlink names.
+
+Versions of Mach-O binaries may be checked with the ``otool -L <binary>``
+command.
diff --git a/Help/prop_tgt/VISIBILITY_INLINES_HIDDEN.rst b/Help/prop_tgt/VISIBILITY_INLINES_HIDDEN.rst
new file mode 100644
index 0000000..adbbc71
--- /dev/null
+++ b/Help/prop_tgt/VISIBILITY_INLINES_HIDDEN.rst
@@ -0,0 +1,13 @@
+VISIBILITY_INLINES_HIDDEN
+-------------------------
+
+Whether to add a compile flag to hide symbols of inline functions
+
+The ``VISIBILITY_INLINES_HIDDEN`` property determines whether a flag for
+hiding symbols for inline functions, such as ``-fvisibility-inlines-hidden``,
+should be used when invoking the compiler. This property affects compilation
+in sources of all types of targets (subject to policy :policy:`CMP0063`).
+
+This property is initialized by
+the value of the :variable:`CMAKE_VISIBILITY_INLINES_HIDDEN` variable if it
+is set when a target is created.
diff --git a/Help/prop_tgt/VS_CONFIGURATION_TYPE.rst b/Help/prop_tgt/VS_CONFIGURATION_TYPE.rst
new file mode 100644
index 0000000..4adffd4
--- /dev/null
+++ b/Help/prop_tgt/VS_CONFIGURATION_TYPE.rst
@@ -0,0 +1,14 @@
+VS_CONFIGURATION_TYPE
+---------------------
+
+.. versionadded:: 3.6
+
+Visual Studio project configuration type.
+
+Sets the ``ConfigurationType`` attribute for a generated Visual Studio project.
+The property value may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+If this property is set, it overrides the default setting that is based on the
+target type (e.g. ``StaticLibrary``, ``Application``, ...).
+
+Supported on :ref:`Visual Studio Generators` for VS 2010 and higher.
diff --git a/Help/prop_tgt/VS_DEBUGGER_COMMAND.rst b/Help/prop_tgt/VS_DEBUGGER_COMMAND.rst
new file mode 100644
index 0000000..58476d6
--- /dev/null
+++ b/Help/prop_tgt/VS_DEBUGGER_COMMAND.rst
@@ -0,0 +1,13 @@
+VS_DEBUGGER_COMMAND
+-------------------
+
+.. versionadded:: 3.12
+
+Sets the local debugger command for Visual Studio C++ targets.
+The property value may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+This is defined in ``<LocalDebuggerCommand>`` in the Visual Studio
+project file.
+
+This property only works for Visual Studio 2010 and above;
+it is ignored on other generators.
diff --git a/Help/prop_tgt/VS_DEBUGGER_COMMAND_ARGUMENTS.rst b/Help/prop_tgt/VS_DEBUGGER_COMMAND_ARGUMENTS.rst
new file mode 100644
index 0000000..6c26601
--- /dev/null
+++ b/Help/prop_tgt/VS_DEBUGGER_COMMAND_ARGUMENTS.rst
@@ -0,0 +1,13 @@
+VS_DEBUGGER_COMMAND_ARGUMENTS
+-----------------------------
+
+.. versionadded:: 3.13
+
+Sets the local debugger command line arguments for Visual Studio C++ targets.
+The property value may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+This is defined in ``<LocalDebuggerCommandArguments>`` in the Visual Studio
+project file.
+
+This property only works for Visual Studio 2010 and above;
+it is ignored on other generators.
diff --git a/Help/prop_tgt/VS_DEBUGGER_ENVIRONMENT.rst b/Help/prop_tgt/VS_DEBUGGER_ENVIRONMENT.rst
new file mode 100644
index 0000000..2f59a82
--- /dev/null
+++ b/Help/prop_tgt/VS_DEBUGGER_ENVIRONMENT.rst
@@ -0,0 +1,13 @@
+VS_DEBUGGER_ENVIRONMENT
+-----------------------
+
+.. versionadded:: 3.13
+
+Sets the local debugger environment for Visual Studio C++ targets.
+The property value may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+This is defined in ``<LocalDebuggerEnvironment>`` in the Visual Studio
+project file.
+
+This property only works for Visual Studio 2010 and above;
+it is ignored on other generators.
diff --git a/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst b/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst
new file mode 100644
index 0000000..c163abf
--- /dev/null
+++ b/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst
@@ -0,0 +1,13 @@
+VS_DEBUGGER_WORKING_DIRECTORY
+-----------------------------
+
+.. versionadded:: 3.8
+
+Sets the local debugger working directory for Visual Studio C++ targets.
+The property value may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+This is defined in ``<LocalDebuggerWorkingDirectory>`` in the Visual Studio
+project file.
+
+This property only works for Visual Studio 2010 and above;
+it is ignored on other generators.
diff --git a/Help/prop_tgt/VS_DESKTOP_EXTENSIONS_VERSION.rst b/Help/prop_tgt/VS_DESKTOP_EXTENSIONS_VERSION.rst
new file mode 100644
index 0000000..5fd23e1
--- /dev/null
+++ b/Help/prop_tgt/VS_DESKTOP_EXTENSIONS_VERSION.rst
@@ -0,0 +1,12 @@
+VS_DESKTOP_EXTENSIONS_VERSION
+-----------------------------
+
+.. versionadded:: 3.4
+
+Visual Studio Windows 10 Desktop Extensions Version
+
+Specifies the version of the Desktop Extensions that should be included in the
+target. For example ``10.0.10240.0``. If the value is not specified, the Desktop
+Extensions will not be included. To use the same version of the extensions as
+the Windows 10 SDK that is being used, you can use the
+:variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION` variable.
diff --git a/Help/prop_tgt/VS_DOTNET_DOCUMENTATION_FILE.rst b/Help/prop_tgt/VS_DOTNET_DOCUMENTATION_FILE.rst
new file mode 100644
index 0000000..a388256
--- /dev/null
+++ b/Help/prop_tgt/VS_DOTNET_DOCUMENTATION_FILE.rst
@@ -0,0 +1,8 @@
+VS_DOTNET_DOCUMENTATION_FILE
+----------------------------
+
+.. versionadded:: 3.17
+
+Visual Studio managed project .NET documentation output
+
+Sets the target XML documentation file output.
diff --git a/Help/prop_tgt/VS_DOTNET_REFERENCEPROP_refname_TAG_tagname.rst b/Help/prop_tgt/VS_DOTNET_REFERENCEPROP_refname_TAG_tagname.rst
new file mode 100644
index 0000000..5b9caee
--- /dev/null
+++ b/Help/prop_tgt/VS_DOTNET_REFERENCEPROP_refname_TAG_tagname.rst
@@ -0,0 +1,16 @@
+VS_DOTNET_REFERENCEPROP_<refname>_TAG_<tagname>
+-----------------------------------------------
+
+.. versionadded:: 3.10
+
+Defines an XML property ``<tagname>`` for a .NET reference
+``<refname>``.
+
+Reference properties can be set for .NET references which are
+defined by the target properties :prop_tgt:`VS_DOTNET_REFERENCES`,
+:prop_tgt:`VS_DOTNET_REFERENCE_<refname>`
+and also for project references to other C# targets which are
+established by :command:`target_link_libraries()`.
+
+This property is only applicable to C# targets and Visual Studio
+generators 2010 and later.
diff --git a/Help/prop_tgt/VS_DOTNET_REFERENCES.rst b/Help/prop_tgt/VS_DOTNET_REFERENCES.rst
new file mode 100644
index 0000000..a661ad9
--- /dev/null
+++ b/Help/prop_tgt/VS_DOTNET_REFERENCES.rst
@@ -0,0 +1,7 @@
+VS_DOTNET_REFERENCES
+--------------------
+
+Visual Studio managed project .NET references
+
+Adds one or more semicolon-delimited .NET references to a generated
+Visual Studio project. For example, "System;System.Windows.Forms".
diff --git a/Help/prop_tgt/VS_DOTNET_REFERENCES_COPY_LOCAL.rst b/Help/prop_tgt/VS_DOTNET_REFERENCES_COPY_LOCAL.rst
new file mode 100644
index 0000000..556fa8a
--- /dev/null
+++ b/Help/prop_tgt/VS_DOTNET_REFERENCES_COPY_LOCAL.rst
@@ -0,0 +1,9 @@
+VS_DOTNET_REFERENCES_COPY_LOCAL
+-------------------------------
+
+.. versionadded:: 3.8
+
+Sets the **Copy Local** property for all .NET hint references in the target
+
+Boolean property to enable/disable copying of .NET hint references to
+output directory. The default is ``ON``.
diff --git a/Help/prop_tgt/VS_DOTNET_REFERENCE_refname.rst b/Help/prop_tgt/VS_DOTNET_REFERENCE_refname.rst
new file mode 100644
index 0000000..9c4d34a
--- /dev/null
+++ b/Help/prop_tgt/VS_DOTNET_REFERENCE_refname.rst
@@ -0,0 +1,14 @@
+VS_DOTNET_REFERENCE_<refname>
+-----------------------------
+
+.. versionadded:: 3.8
+
+Visual Studio managed project .NET reference with name ``<refname>``
+and hint path.
+
+Adds one .NET reference to generated Visual Studio project. The
+reference will have the name ``<refname>`` and will point to the
+assembly given as value of the property.
+
+See also :prop_tgt:`VS_DOTNET_REFERENCES` and
+:prop_tgt:`VS_DOTNET_REFERENCES_COPY_LOCAL`
diff --git a/Help/prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION.rst b/Help/prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION.rst
new file mode 100644
index 0000000..6cb8f86
--- /dev/null
+++ b/Help/prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION.rst
@@ -0,0 +1,11 @@
+VS_DOTNET_TARGET_FRAMEWORK_VERSION
+----------------------------------
+
+Specify the .NET target framework version.
+
+Used to specify the .NET target framework version for C++/CLI. For
+example, "v4.5".
+
+This property is deprecated and should not be used anymore. Use
+:prop_tgt:`DOTNET_TARGET_FRAMEWORK` or
+:prop_tgt:`DOTNET_TARGET_FRAMEWORK_VERSION` instead.
diff --git a/Help/prop_tgt/VS_DPI_AWARE.rst b/Help/prop_tgt/VS_DPI_AWARE.rst
new file mode 100644
index 0000000..47ce1ce
--- /dev/null
+++ b/Help/prop_tgt/VS_DPI_AWARE.rst
@@ -0,0 +1,16 @@
+VS_DPI_AWARE
+------------
+
+.. versionadded:: 3.16
+
+Set the Manifest Tool -> Input and Output -> DPI Awareness in the Visual Studio
+target project properties.
+
+Valid values are ``PerMonitor``, ``ON``, or ``OFF``.
+
+For example:
+
+.. code-block:: cmake
+
+ add_executable(myproject myproject.cpp)
+ set_property(TARGET myproject PROPERTY VS_DPI_AWARE "PerMonitor")
diff --git a/Help/prop_tgt/VS_GLOBAL_KEYWORD.rst b/Help/prop_tgt/VS_GLOBAL_KEYWORD.rst
new file mode 100644
index 0000000..ce49316
--- /dev/null
+++ b/Help/prop_tgt/VS_GLOBAL_KEYWORD.rst
@@ -0,0 +1,12 @@
+VS_GLOBAL_KEYWORD
+-----------------
+
+Visual Studio project keyword for VS 10 (2010) and newer.
+
+Sets the "keyword" attribute for a generated Visual Studio project.
+Defaults to "Win32Proj". You may wish to override this value with
+"ManagedCProj", for example, in a Visual Studio managed C++ unit test
+project.
+
+Use the :prop_tgt:`VS_KEYWORD` target property to set the
+keyword for Visual Studio 9 (2008) and older.
diff --git a/Help/prop_tgt/VS_GLOBAL_PROJECT_TYPES.rst b/Help/prop_tgt/VS_GLOBAL_PROJECT_TYPES.rst
new file mode 100644
index 0000000..f4d9efc
--- /dev/null
+++ b/Help/prop_tgt/VS_GLOBAL_PROJECT_TYPES.rst
@@ -0,0 +1,15 @@
+VS_GLOBAL_PROJECT_TYPES
+-----------------------
+
+Visual Studio project type(s).
+
+Can be set to one or more UUIDs recognized by Visual Studio to
+indicate the type of project. This value is copied verbatim into the
+generated project file. Example for a managed C++ unit testing
+project:
+
+::
+
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}
+
+UUIDs are semicolon-delimited.
diff --git a/Help/prop_tgt/VS_GLOBAL_ROOTNAMESPACE.rst b/Help/prop_tgt/VS_GLOBAL_ROOTNAMESPACE.rst
new file mode 100644
index 0000000..a23c540
--- /dev/null
+++ b/Help/prop_tgt/VS_GLOBAL_ROOTNAMESPACE.rst
@@ -0,0 +1,7 @@
+VS_GLOBAL_ROOTNAMESPACE
+-----------------------
+
+Visual Studio project root namespace.
+
+Sets the "RootNamespace" attribute for a generated Visual Studio
+project. The attribute will be generated only if this is set.
diff --git a/Help/prop_tgt/VS_GLOBAL_variable.rst b/Help/prop_tgt/VS_GLOBAL_variable.rst
new file mode 100644
index 0000000..56b8021
--- /dev/null
+++ b/Help/prop_tgt/VS_GLOBAL_variable.rst
@@ -0,0 +1,10 @@
+VS_GLOBAL_<variable>
+--------------------
+
+Visual Studio project-specific global variable.
+
+Tell the Visual Studio generator to set the global variable
+'<variable>' to a given value in the generated Visual Studio project.
+Ignored on other generators. Qt integration works better if
+VS_GLOBAL_QtVersion is set to the version FindQt4.cmake found. For
+example, "4.7.3"
diff --git a/Help/prop_tgt/VS_IOT_EXTENSIONS_VERSION.rst b/Help/prop_tgt/VS_IOT_EXTENSIONS_VERSION.rst
new file mode 100644
index 0000000..ca6a3ca
--- /dev/null
+++ b/Help/prop_tgt/VS_IOT_EXTENSIONS_VERSION.rst
@@ -0,0 +1,12 @@
+VS_IOT_EXTENSIONS_VERSION
+-------------------------
+
+.. versionadded:: 3.4
+
+Visual Studio Windows 10 IoT Extensions Version
+
+Specifies the version of the IoT Extensions that should be included in the
+target. For example ``10.0.10240.0``. If the value is not specified, the IoT
+Extensions will not be included. To use the same version of the extensions as
+the Windows 10 SDK that is being used, you can use the
+:variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION` variable.
diff --git a/Help/prop_tgt/VS_IOT_STARTUP_TASK.rst b/Help/prop_tgt/VS_IOT_STARTUP_TASK.rst
new file mode 100644
index 0000000..259055d
--- /dev/null
+++ b/Help/prop_tgt/VS_IOT_STARTUP_TASK.rst
@@ -0,0 +1,8 @@
+VS_IOT_STARTUP_TASK
+-------------------
+
+.. versionadded:: 3.4
+
+Visual Studio Windows 10 IoT Continuous Background Task
+
+Specifies that the target should be compiled as a Continuous Background Task library.
diff --git a/Help/prop_tgt/VS_JUST_MY_CODE_DEBUGGING.rst b/Help/prop_tgt/VS_JUST_MY_CODE_DEBUGGING.rst
new file mode 100644
index 0000000..724bd2f
--- /dev/null
+++ b/Help/prop_tgt/VS_JUST_MY_CODE_DEBUGGING.rst
@@ -0,0 +1,12 @@
+VS_JUST_MY_CODE_DEBUGGING
+-------------------------
+
+.. versionadded:: 3.15
+
+Enable Just My Code with Visual Studio debugger.
+
+Supported on :ref:`Visual Studio Generators` for VS 2010 and higher,
+:ref:`Makefile Generators` and the :generator:`Ninja` generators.
+
+This property is initialized by the :variable:`CMAKE_VS_JUST_MY_CODE_DEBUGGING`
+variable if it is set when a target is created.
diff --git a/Help/prop_tgt/VS_KEYWORD.rst b/Help/prop_tgt/VS_KEYWORD.rst
new file mode 100644
index 0000000..6c2e042
--- /dev/null
+++ b/Help/prop_tgt/VS_KEYWORD.rst
@@ -0,0 +1,10 @@
+VS_KEYWORD
+----------
+
+Visual Studio project keyword for VS 9 (2008) and older.
+
+Can be set to change the visual studio keyword, for example Qt
+integration works better if this is set to Qt4VSv1.0.
+
+Use the :prop_tgt:`VS_GLOBAL_KEYWORD` target property to set the
+keyword for Visual Studio 10 (2010) and newer.
diff --git a/Help/prop_tgt/VS_MOBILE_EXTENSIONS_VERSION.rst b/Help/prop_tgt/VS_MOBILE_EXTENSIONS_VERSION.rst
new file mode 100644
index 0000000..b307e84
--- /dev/null
+++ b/Help/prop_tgt/VS_MOBILE_EXTENSIONS_VERSION.rst
@@ -0,0 +1,12 @@
+VS_MOBILE_EXTENSIONS_VERSION
+----------------------------
+
+.. versionadded:: 3.4
+
+Visual Studio Windows 10 Mobile Extensions Version
+
+Specifies the version of the Mobile Extensions that should be included in the
+target. For example ``10.0.10240.0``. If the value is not specified, the Mobile
+Extensions will not be included. To use the same version of the extensions as
+the Windows 10 SDK that is being used, you can use the
+:variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION` variable.
diff --git a/Help/prop_tgt/VS_NO_SOLUTION_DEPLOY.rst b/Help/prop_tgt/VS_NO_SOLUTION_DEPLOY.rst
new file mode 100644
index 0000000..bf6ac10
--- /dev/null
+++ b/Help/prop_tgt/VS_NO_SOLUTION_DEPLOY.rst
@@ -0,0 +1,48 @@
+VS_NO_SOLUTION_DEPLOY
+---------------------
+
+.. versionadded:: 3.15
+
+Specify that the target should not be marked for deployment to a Windows CE
+or Windows Phone device in the generated Visual Studio solution.
+
+Be default, all EXE and shared library (DLL) targets are marked to deploy to
+the target device in the generated Visual Studio solution.
+
+Generator expressions are supported.
+
+There are reasons one might want to exclude a target / generated project from
+deployment:
+
+- The library or executable may not be necessary in the primary deploy/debug
+ scenario, and excluding from deployment saves time in the
+ develop/download/debug cycle.
+- There may be insufficient space on the target device to accommodate all of
+ the build products.
+- Visual Studio 2013 requires a target device IP address be entered for each
+ target marked for deployment. For large numbers of targets, this can be
+ tedious.
+ NOTE: Visual Studio *will* deploy all project dependencies of a project
+ tagged for deployment to the IP address configured for that project even
+ if those dependencies are not tagged for deployment.
+
+
+Example 1
+^^^^^^^^^
+
+This shows setting the variable for the target foo.
+
+.. code-block:: cmake
+
+ add_library(foo SHARED foo.cpp)
+ set_property(TARGET foo PROPERTY VS_NO_SOLUTION_DEPLOY ON)
+
+Example 2
+^^^^^^^^^
+
+This shows setting the variable for the Release configuration only.
+
+.. code-block:: cmake
+
+ add_library(foo SHARED foo.cpp)
+ set_property(TARGET foo PROPERTY VS_NO_SOLUTION_DEPLOY "$<CONFIG:Release>")
diff --git a/Help/prop_tgt/VS_PACKAGE_REFERENCES.rst b/Help/prop_tgt/VS_PACKAGE_REFERENCES.rst
new file mode 100644
index 0000000..ec17567
--- /dev/null
+++ b/Help/prop_tgt/VS_PACKAGE_REFERENCES.rst
@@ -0,0 +1,15 @@
+VS_PACKAGE_REFERENCES
+---------------------
+
+.. versionadded:: 3.15
+
+Visual Studio package references for nuget.
+
+Adds one or more semicolon-delimited package references to a generated
+Visual Studio project. The version of the package will be
+underscore delimited. For example, ``boost_1.7.0;nunit_3.12.*``.
+
+.. code-block:: cmake
+
+ set_property(TARGET ${TARGET_NAME} PROPERTY
+ VS_PACKAGE_REFERENCES "boost_1.7.0")
diff --git a/Help/prop_tgt/VS_PLATFORM_TOOLSET.rst b/Help/prop_tgt/VS_PLATFORM_TOOLSET.rst
new file mode 100644
index 0000000..27a92d6
--- /dev/null
+++ b/Help/prop_tgt/VS_PLATFORM_TOOLSET.rst
@@ -0,0 +1,12 @@
+VS_PLATFORM_TOOLSET
+-------------------
+
+.. versionadded:: 3.18
+
+Overrides the platform toolset used to build a target.
+
+Only supported when the compiler used by the given toolset is the
+same as the compiler used to build the whole source tree.
+
+This is especially useful to create driver projects with the toolsets
+"WindowsUserModeDriver10.0" or "WindowsKernelModeDriver10.0".
diff --git a/Help/prop_tgt/VS_PROJECT_IMPORT.rst b/Help/prop_tgt/VS_PROJECT_IMPORT.rst
new file mode 100644
index 0000000..f5e9698
--- /dev/null
+++ b/Help/prop_tgt/VS_PROJECT_IMPORT.rst
@@ -0,0 +1,10 @@
+VS_PROJECT_IMPORT
+-----------------
+
+.. versionadded:: 3.15
+
+Visual Studio managed project imports
+
+Adds to a generated Visual Studio project one or more semicolon-delimited paths
+to .props files needed when building projects from some NuGet packages.
+For example, ``my_packages_path/MyPackage.1.0.0/build/MyPackage.props``.
diff --git a/Help/prop_tgt/VS_SCC_AUXPATH.rst b/Help/prop_tgt/VS_SCC_AUXPATH.rst
new file mode 100644
index 0000000..054f59e
--- /dev/null
+++ b/Help/prop_tgt/VS_SCC_AUXPATH.rst
@@ -0,0 +1,7 @@
+VS_SCC_AUXPATH
+--------------
+
+Visual Studio Source Code Control Aux Path.
+
+Can be set to change the visual studio source code control auxpath
+property.
diff --git a/Help/prop_tgt/VS_SCC_LOCALPATH.rst b/Help/prop_tgt/VS_SCC_LOCALPATH.rst
new file mode 100644
index 0000000..b5b7721
--- /dev/null
+++ b/Help/prop_tgt/VS_SCC_LOCALPATH.rst
@@ -0,0 +1,7 @@
+VS_SCC_LOCALPATH
+----------------
+
+Visual Studio Source Code Control Local Path.
+
+Can be set to change the visual studio source code control local path
+property.
diff --git a/Help/prop_tgt/VS_SCC_PROJECTNAME.rst b/Help/prop_tgt/VS_SCC_PROJECTNAME.rst
new file mode 100644
index 0000000..6d7f628
--- /dev/null
+++ b/Help/prop_tgt/VS_SCC_PROJECTNAME.rst
@@ -0,0 +1,7 @@
+VS_SCC_PROJECTNAME
+------------------
+
+Visual Studio Source Code Control Project.
+
+Can be set to change the visual studio source code control project
+name property.
diff --git a/Help/prop_tgt/VS_SCC_PROVIDER.rst b/Help/prop_tgt/VS_SCC_PROVIDER.rst
new file mode 100644
index 0000000..80475af
--- /dev/null
+++ b/Help/prop_tgt/VS_SCC_PROVIDER.rst
@@ -0,0 +1,7 @@
+VS_SCC_PROVIDER
+---------------
+
+Visual Studio Source Code Control Provider.
+
+Can be set to change the visual studio source code control provider
+property.
diff --git a/Help/prop_tgt/VS_SDK_REFERENCES.rst b/Help/prop_tgt/VS_SDK_REFERENCES.rst
new file mode 100644
index 0000000..9a082e7
--- /dev/null
+++ b/Help/prop_tgt/VS_SDK_REFERENCES.rst
@@ -0,0 +1,9 @@
+VS_SDK_REFERENCES
+-----------------
+
+.. versionadded:: 3.7
+
+Visual Studio project SDK references.
+Specify a :ref:`semicolon-separated list <CMake Language Lists>` of SDK references
+to be added to a generated Visual Studio project, e.g.
+``Microsoft.AdMediatorWindows81, Version=1.0``.
diff --git a/Help/prop_tgt/VS_SOLUTION_DEPLOY.rst b/Help/prop_tgt/VS_SOLUTION_DEPLOY.rst
new file mode 100644
index 0000000..e56f411
--- /dev/null
+++ b/Help/prop_tgt/VS_SOLUTION_DEPLOY.rst
@@ -0,0 +1,29 @@
+VS_SOLUTION_DEPLOY
+------------------
+
+.. versionadded:: 3.18
+
+Specify that the target should be marked for deployment when not targeting
+Windows CE, Windows Phone or a Windows Store application.
+
+If the target platform doesn't support deployment, this property won't have
+any effect.
+
+:manual:`Generator expressions <cmake-generator-expressions(7)>` are supported.
+
+Examples
+^^^^^^^^
+
+Always deploy target ``foo``:
+
+.. code-block:: cmake
+
+ add_executable(foo SHARED foo.cpp)
+ set_property(TARGET foo PROPERTY VS_SOLUTION_DEPLOY ON)
+
+Deploy target ``foo`` for all configurations except ``Release``:
+
+.. code-block:: cmake
+
+ add_executable(foo SHARED foo.cpp)
+ set_property(TARGET foo PROPERTY VS_SOLUTION_DEPLOY "$<NOT:$<CONFIG:Release>>")
diff --git a/Help/prop_tgt/VS_SOURCE_SETTINGS_tool.rst b/Help/prop_tgt/VS_SOURCE_SETTINGS_tool.rst
new file mode 100644
index 0000000..b5a76fc
--- /dev/null
+++ b/Help/prop_tgt/VS_SOURCE_SETTINGS_tool.rst
@@ -0,0 +1,21 @@
+VS_SOURCE_SETTINGS_<tool>
+-------------------------
+
+.. versionadded:: 3.18
+
+Set any item metadata on all non-built files that use <tool>.
+
+Takes a list of ``Key=Value`` pairs. Tells the Visual Studio generator
+to set ``Key`` to ``Value`` as item metadata on all non-built files
+that use ``<tool>``.
+
+For example:
+
+.. code-block:: cmake
+
+ set_property(TARGET main PROPERTY VS_SOURCE_SETTINGS_FXCompile "Key=Value" "Key2=Value2")
+
+will set ``Key`` to ``Value`` and ``Key2`` to ``Value2`` for all
+non-built files that use ``FXCompile``.
+
+:manual:`Generator expressions <cmake-generator-expressions(7)>` are supported.
diff --git a/Help/prop_tgt/VS_USER_PROPS.rst b/Help/prop_tgt/VS_USER_PROPS.rst
new file mode 100644
index 0000000..8f2a105
--- /dev/null
+++ b/Help/prop_tgt/VS_USER_PROPS.rst
@@ -0,0 +1,14 @@
+VS_USER_PROPS
+-------------
+
+.. versionadded:: 3.8
+
+Sets the user props file to be included in the visual studio
+C++ project file. The standard path is
+``$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props``, which is
+in most cases the same as
+``%LOCALAPPDATA%\\Microsoft\\MSBuild\\v4.0\\Microsoft.Cpp.Win32.user.props``
+or ``%LOCALAPPDATA%\\Microsoft\\MSBuild\\v4.0\\Microsoft.Cpp.x64.user.props``.
+
+The ``*.user.props`` files can be used for Visual Studio wide
+configuration which is independent from cmake.
diff --git a/Help/prop_tgt/VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION.rst b/Help/prop_tgt/VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION.rst
new file mode 100644
index 0000000..50cf203
--- /dev/null
+++ b/Help/prop_tgt/VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION.rst
@@ -0,0 +1,12 @@
+VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION
+--------------------------------------
+
+.. versionadded:: 3.4
+
+Visual Studio Windows Target Platform Minimum Version
+
+For Windows 10. Specifies the minimum version of the OS that is being
+targeted. For example ``10.0.10240.0``. If the value is not specified, the
+value of :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION` will be used on
+WindowsStore projects otherwise the target platform minimum version will not
+be specified for the project.
diff --git a/Help/prop_tgt/VS_WINRT_COMPONENT.rst b/Help/prop_tgt/VS_WINRT_COMPONENT.rst
new file mode 100644
index 0000000..8b4aaf7
--- /dev/null
+++ b/Help/prop_tgt/VS_WINRT_COMPONENT.rst
@@ -0,0 +1,13 @@
+VS_WINRT_COMPONENT
+------------------
+
+.. versionadded:: 3.1
+
+Mark a target as a Windows Runtime component for the Visual Studio generator.
+Compile the target with ``C++/CX`` language extensions for Windows Runtime.
+For ``SHARED`` and ``MODULE`` libraries, this also defines the
+``_WINRT_DLL`` preprocessor macro.
+
+.. note::
+ Currently this is implemented only by Visual Studio generators.
+ Support may be added to other generators in the future.
diff --git a/Help/prop_tgt/VS_WINRT_EXTENSIONS.rst b/Help/prop_tgt/VS_WINRT_EXTENSIONS.rst
new file mode 100644
index 0000000..d1cba34
--- /dev/null
+++ b/Help/prop_tgt/VS_WINRT_EXTENSIONS.rst
@@ -0,0 +1,5 @@
+VS_WINRT_EXTENSIONS
+-------------------
+
+Deprecated. Use :prop_tgt:`VS_WINRT_COMPONENT` instead.
+This property was an experimental partial implementation of that one.
diff --git a/Help/prop_tgt/VS_WINRT_REFERENCES.rst b/Help/prop_tgt/VS_WINRT_REFERENCES.rst
new file mode 100644
index 0000000..af98b2f
--- /dev/null
+++ b/Help/prop_tgt/VS_WINRT_REFERENCES.rst
@@ -0,0 +1,7 @@
+VS_WINRT_REFERENCES
+-------------------
+
+Visual Studio project Windows Runtime Metadata references
+
+Adds one or more semicolon-delimited WinRT references to a generated
+Visual Studio project. For example, "Windows;Windows.UI.Core".
diff --git a/Help/prop_tgt/WIN32_EXECUTABLE.rst b/Help/prop_tgt/WIN32_EXECUTABLE.rst
new file mode 100644
index 0000000..eac28ae
--- /dev/null
+++ b/Help/prop_tgt/WIN32_EXECUTABLE.rst
@@ -0,0 +1,17 @@
+WIN32_EXECUTABLE
+----------------
+
+Build an executable with a WinMain entry point on windows.
+
+When this property is set to true the executable when linked on
+Windows will be created with a WinMain() entry point instead of just
+main(). This makes it a GUI executable instead of a console application.
+See the :variable:`CMAKE_MFC_FLAG` variable documentation to
+configure use of the Microsoft Foundation Classes (MFC) for WinMain
+executables. This property is initialized by the value of the
+:variable:`CMAKE_WIN32_EXECUTABLE` variable if it is set when
+a target is created.
+
+This property supports
+:manual:`generator expressions <cmake-generator-expressions(7)>`, except if the
+target is managed (contains C# code.)
diff --git a/Help/prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS.rst b/Help/prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS.rst
new file mode 100644
index 0000000..00f32f6
--- /dev/null
+++ b/Help/prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS.rst
@@ -0,0 +1,28 @@
+WINDOWS_EXPORT_ALL_SYMBOLS
+--------------------------
+
+.. versionadded:: 3.4
+
+This property is implemented only for MS-compatible tools on Windows.
+
+Enable this boolean property to automatically create a module definition
+(``.def``) file with all global symbols found in the input ``.obj`` files
+for a ``SHARED`` library (or executable with :prop_tgt:`ENABLE_EXPORTS`)
+on Windows. The module definition file will be passed to the linker
+causing all symbols to be exported from the ``.dll``.
+For global *data* symbols, ``__declspec(dllimport)`` must still be used when
+compiling against the code in the ``.dll``. All other function symbols will
+be automatically exported and imported by callers. This simplifies porting
+projects to Windows by reducing the need for explicit ``dllexport`` markup,
+even in ``C++`` classes.
+
+When this property is enabled, zero or more ``.def`` files may also be
+specified as source files of the target. The exports named by these files
+will be merged with those detected from the object files to generate a
+single module definition file to be passed to the linker. This can be
+used to export symbols from a ``.dll`` that are not in any of its object
+files but are added by the linker from dependencies (e.g. ``msvcrt.lib``).
+
+This property is initialized by the value of
+the :variable:`CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/XCODE_ATTRIBUTE_an-attribute.rst b/Help/prop_tgt/XCODE_ATTRIBUTE_an-attribute.rst
new file mode 100644
index 0000000..fbe7608
--- /dev/null
+++ b/Help/prop_tgt/XCODE_ATTRIBUTE_an-attribute.rst
@@ -0,0 +1,22 @@
+XCODE_ATTRIBUTE_<an-attribute>
+------------------------------
+
+Set Xcode target attributes directly.
+
+Tell the :generator:`Xcode` generator to set ``<an-attribute>`` to a given
+value in the generated Xcode project. Ignored on other generators.
+
+This offers low-level control over the generated Xcode project file.
+It is meant as a last resort for specifying settings that CMake does
+not otherwise have a way to control. Although this can override a
+setting CMake normally produces on its own, doing so bypasses CMake's
+model of the project and can break things.
+
+See the :variable:`CMAKE_XCODE_ATTRIBUTE_<an-attribute>` variable
+to set attributes on all targets in a directory tree.
+
+Contents of ``XCODE_ATTRIBUTE_<an-attribute>`` may use
+"generator expressions" with the syntax ``$<...>``. See the
+:manual:`cmake-generator-expressions(7)` manual for available
+expressions. See the :manual:`cmake-buildsystem(7)` manual
+for more on defining buildsystem properties.
diff --git a/Help/prop_tgt/XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY.rst b/Help/prop_tgt/XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY.rst
new file mode 100644
index 0000000..7b68126
--- /dev/null
+++ b/Help/prop_tgt/XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY.rst
@@ -0,0 +1,8 @@
+XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY
+----------------------------------------
+
+.. versionadded:: 3.20
+
+Tell the :generator:`Xcode` generator to perform code signing for all the
+frameworks and libraries that are embedded using the
+:prop_tgt:`XCODE_EMBED_FRAMEWORKS <XCODE_EMBED_<type>>` property.
diff --git a/Help/prop_tgt/XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY.rst b/Help/prop_tgt/XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY.rst
new file mode 100644
index 0000000..29f8c5c
--- /dev/null
+++ b/Help/prop_tgt/XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY.rst
@@ -0,0 +1,8 @@
+XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY
+---------------------------------------------
+
+.. versionadded:: 3.20
+
+Tell the :generator:`Xcode` generator to remove headers from all the
+frameworks that are embedded using the
+:prop_tgt:`XCODE_EMBED_FRAMEWORKS <XCODE_EMBED_<type>>` property.
diff --git a/Help/prop_tgt/XCODE_EMBED_type.rst b/Help/prop_tgt/XCODE_EMBED_type.rst
new file mode 100644
index 0000000..90c5bc7
--- /dev/null
+++ b/Help/prop_tgt/XCODE_EMBED_type.rst
@@ -0,0 +1,14 @@
+XCODE_EMBED_<type>
+------------------
+
+.. versionadded:: 3.20
+
+Tell the :generator:`Xcode` generator to embed the specified list of items into
+the target bundle. ``<type>`` specifies the embed build phase to use.
+
+Currently, the only supported value for ``<type>`` is ``FRAMEWORKS``.
+The specified items will be added to the ``Embed Frameworks`` build phase.
+The items can be CMake target names or paths to frameworks or libraries.
+See also :prop_tgt:`XCODE_EMBED_<type>_PATH`,
+:prop_tgt:`XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY` and
+:prop_tgt:`XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY`.
diff --git a/Help/prop_tgt/XCODE_EMBED_type_PATH.rst b/Help/prop_tgt/XCODE_EMBED_type_PATH.rst
new file mode 100644
index 0000000..887cf57
--- /dev/null
+++ b/Help/prop_tgt/XCODE_EMBED_type_PATH.rst
@@ -0,0 +1,9 @@
+XCODE_EMBED_<type>_PATH
+-----------------------
+
+.. versionadded:: 3.20
+
+Tell the :generator:`Xcode` generator the relative path to use when embedding
+the items specified by :prop_tgt:`XCODE_EMBED_<type>`. The path is relative
+to the base location of the ``Embed XXX`` build phase associated with
+``<type>``.
diff --git a/Help/prop_tgt/XCODE_EXPLICIT_FILE_TYPE.rst b/Help/prop_tgt/XCODE_EXPLICIT_FILE_TYPE.rst
new file mode 100644
index 0000000..e01a034
--- /dev/null
+++ b/Help/prop_tgt/XCODE_EXPLICIT_FILE_TYPE.rst
@@ -0,0 +1,10 @@
+XCODE_EXPLICIT_FILE_TYPE
+------------------------
+
+.. versionadded:: 3.8
+
+Set the Xcode ``explicitFileType`` attribute on its reference to a
+target. CMake computes a default based on target type but
+can be told explicitly with this property.
+
+See also :prop_tgt:`XCODE_PRODUCT_TYPE`.
diff --git a/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst b/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst
new file mode 100644
index 0000000..06a3cf9
--- /dev/null
+++ b/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst
@@ -0,0 +1,43 @@
+XCODE_GENERATE_SCHEME
+---------------------
+
+.. versionadded:: 3.15
+
+If enabled, the :generator:`Xcode` generator will generate schema files. These
+are useful to invoke analyze, archive, build-for-testing and test
+actions from the command line.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_GENERATE_SCHEME` if it is set when a target
+is created.
+
+The following target properties overwrite the default of the
+corresponding settings on the "Diagnostic" tab for each schema file.
+Each of those is initialized by the respective ``CMAKE_`` variable
+at target creation time.
+
+- :prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER`
+- :prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN`
+- :prop_tgt:`XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER`
+- :prop_tgt:`XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS`
+- :prop_tgt:`XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE`
+- :prop_tgt:`XCODE_SCHEME_GUARD_MALLOC`
+- :prop_tgt:`XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP`
+- :prop_tgt:`XCODE_SCHEME_MALLOC_GUARD_EDGES`
+- :prop_tgt:`XCODE_SCHEME_MALLOC_SCRIBBLE`
+- :prop_tgt:`XCODE_SCHEME_MALLOC_STACK`
+- :prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER`
+- :prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER_STOP`
+- :prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER`
+- :prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP`
+- :prop_tgt:`XCODE_SCHEME_ZOMBIE_OBJECTS`
+
+The following target properties will be applied on the
+"Info", "Arguments", and "Options" tab:
+
+- :prop_tgt:`XCODE_SCHEME_ARGUMENTS`
+- :prop_tgt:`XCODE_SCHEME_DEBUG_AS_ROOT`
+- :prop_tgt:`XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING`
+- :prop_tgt:`XCODE_SCHEME_ENVIRONMENT`
+- :prop_tgt:`XCODE_SCHEME_EXECUTABLE`
+- :prop_tgt:`XCODE_SCHEME_WORKING_DIRECTORY`
diff --git a/Help/prop_tgt/XCODE_LINK_BUILD_PHASE_MODE.rst b/Help/prop_tgt/XCODE_LINK_BUILD_PHASE_MODE.rst
new file mode 100644
index 0000000..836cc6b
--- /dev/null
+++ b/Help/prop_tgt/XCODE_LINK_BUILD_PHASE_MODE.rst
@@ -0,0 +1,55 @@
+XCODE_LINK_BUILD_PHASE_MODE
+---------------------------
+
+.. versionadded:: 3.19
+
+When using the :generator:`Xcode` generator, libraries to be linked will be
+specified in the Xcode project file using either the "Link Binary With
+Libraries" build phase or directly as linker flags. The former allows Xcode
+to manage build paths, which may be necessary when creating Xcode archives
+because it may use different build paths to a regular build.
+
+This property controls usage of "Link Binary With Libraries" build phase for
+a target that is an app bundle, executable, shared library, shared framework
+or a module library.
+
+Possible values are:
+
+* ``NONE``
+ The libraries will be linked by specifying the linker flags directly.
+
+* ``BUILT_ONLY``
+ The "Link Binary With Libraries" build phase will be used to link to another
+ target under the following conditions:
+
+ - The target to be linked to is a regular non-imported, non-interface library
+ target.
+ - The output directory of the target being built has not been changed from
+ its default (see :prop_tgt:`RUNTIME_OUTPUT_DIRECTORY` and
+ :prop_tgt:`LIBRARY_OUTPUT_DIRECTORY`).
+
+* ``KNOWN_LOCATION``
+ The "Link Binary With Libraries" build phase will be used to link to another
+ target under the same conditions as with ``BUILT_ONLY`` and also:
+
+ - Imported library targets except those of type ``UNKNOWN``.
+ - Any non-target library specified directly with a path.
+
+For all other cases, the libraries will be linked by specifying the linker
+flags directly.
+
+.. warning::
+ Libraries linked using "Link Binary With Libraries" are linked after the
+ ones linked through regular linker flags. This order should be taken into
+ account when different static libraries contain symbols with the same name,
+ as the former ones will take precedence over the latter.
+
+.. warning::
+ If two or more directories contain libraries with identical file names and
+ some libraries are linked from those directories, the library search path
+ lookup will end up linking libraries from the first directory. This is a
+ known limitation of Xcode.
+
+This property is initialized by the value of the
+:variable:`CMAKE_XCODE_LINK_BUILD_PHASE_MODE` variable if it is set when a
+target is created.
diff --git a/Help/prop_tgt/XCODE_PRODUCT_TYPE.rst b/Help/prop_tgt/XCODE_PRODUCT_TYPE.rst
new file mode 100644
index 0000000..17a9c3f
--- /dev/null
+++ b/Help/prop_tgt/XCODE_PRODUCT_TYPE.rst
@@ -0,0 +1,10 @@
+XCODE_PRODUCT_TYPE
+------------------
+
+.. versionadded:: 3.8
+
+Set the Xcode ``productType`` attribute on its reference to a
+target. CMake computes a default based on target type but
+can be told explicitly with this property.
+
+See also :prop_tgt:`XCODE_EXPLICIT_FILE_TYPE`.
diff --git a/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER.rst b/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER.rst
new file mode 100644
index 0000000..c72ec06
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER.rst
@@ -0,0 +1,14 @@
+XCODE_SCHEME_ADDRESS_SANITIZER
+------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Address Sanitizer`` in the Diagnostics
+section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER` if it is set
+when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst b/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
new file mode 100644
index 0000000..293b5d4
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
@@ -0,0 +1,14 @@
+XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN
+-----------------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Detect use of stack after return``
+in the Diagnostics section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN`
+if it is set when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_ARGUMENTS.rst b/Help/prop_tgt/XCODE_SCHEME_ARGUMENTS.rst
new file mode 100644
index 0000000..2bfcb41
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_ARGUMENTS.rst
@@ -0,0 +1,12 @@
+XCODE_SCHEME_ARGUMENTS
+----------------------
+
+.. versionadded:: 3.13
+
+Specify command line arguments that should be added to the Arguments
+section of the generated Xcode scheme.
+
+If set to a list of arguments those will be added to the scheme.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_DEBUG_AS_ROOT.rst b/Help/prop_tgt/XCODE_SCHEME_DEBUG_AS_ROOT.rst
new file mode 100644
index 0000000..2523deb
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_DEBUG_AS_ROOT.rst
@@ -0,0 +1,9 @@
+XCODE_SCHEME_DEBUG_AS_ROOT
+--------------------------
+
+.. versionadded:: 3.15
+
+Whether to debug the target as 'root'.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING.rst b/Help/prop_tgt/XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING.rst
new file mode 100644
index 0000000..bbcae35
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING.rst
@@ -0,0 +1,15 @@
+XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING
+--------------------------------------
+
+.. versionadded:: 3.16
+
+Whether to enable
+``Allow debugging when using document Versions Browser``
+in the Options section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING`
+if it is set when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst b/Help/prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
new file mode 100644
index 0000000..3d315a2
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
@@ -0,0 +1,14 @@
+XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
+----------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to disable the ``Main Thread Checker``
+in the Diagnostics section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER`
+if it is set when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst b/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
new file mode 100644
index 0000000..2ca20f7
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
@@ -0,0 +1,14 @@
+XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
+----------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Dynamic Library Loads``
+in the Diagnostics section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS` if it is set
+when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst b/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
new file mode 100644
index 0000000..278c9ef
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
@@ -0,0 +1,14 @@
+XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
+-------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Dynamic Linker API usage``
+in the Diagnostics section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE` if it is set
+when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_ENVIRONMENT.rst b/Help/prop_tgt/XCODE_SCHEME_ENVIRONMENT.rst
new file mode 100644
index 0000000..16542f8
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_ENVIRONMENT.rst
@@ -0,0 +1,14 @@
+XCODE_SCHEME_ENVIRONMENT
+------------------------
+
+.. versionadded:: 3.13
+
+Specify environment variables that should be added to the Arguments
+section of the generated Xcode scheme.
+
+If set to a list of environment variables and values of the form
+``MYVAR=value`` those environment variables will be added to the
+scheme.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_EXECUTABLE.rst b/Help/prop_tgt/XCODE_SCHEME_EXECUTABLE.rst
new file mode 100644
index 0000000..b453f10
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_EXECUTABLE.rst
@@ -0,0 +1,11 @@
+XCODE_SCHEME_EXECUTABLE
+-----------------------
+
+.. versionadded:: 3.13
+
+Specify path to executable in the Info section of the generated
+Xcode scheme. If not set the schema generator will select the
+current target if it is actually executable.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_GUARD_MALLOC.rst b/Help/prop_tgt/XCODE_SCHEME_GUARD_MALLOC.rst
new file mode 100644
index 0000000..4b242a2
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_GUARD_MALLOC.rst
@@ -0,0 +1,14 @@
+XCODE_SCHEME_GUARD_MALLOC
+------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Guard Malloc``
+in the Diagnostics section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_GUARD_MALLOC` if it is set
+when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst b/Help/prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
new file mode 100644
index 0000000..2a813aa
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
@@ -0,0 +1,15 @@
+XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP
+-------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable the ``Main Thread Checker`` option
+``Pause on issues``
+in the Diagnostics section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP` if it is set
+when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES.rst b/Help/prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
new file mode 100644
index 0000000..750da74
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
@@ -0,0 +1,14 @@
+XCODE_SCHEME_MALLOC_GUARD_EDGES
+-------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Malloc Guard Edges``
+in the Diagnostics section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES` if it is set
+when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE.rst b/Help/prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE.rst
new file mode 100644
index 0000000..4ebd21b
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE.rst
@@ -0,0 +1,14 @@
+XCODE_SCHEME_MALLOC_SCRIBBLE
+------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Malloc Scribble``
+in the Diagnostics section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE` if it is set
+when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_MALLOC_STACK.rst b/Help/prop_tgt/XCODE_SCHEME_MALLOC_STACK.rst
new file mode 100644
index 0000000..5afe34e
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_MALLOC_STACK.rst
@@ -0,0 +1,14 @@
+XCODE_SCHEME_MALLOC_STACK
+-------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Malloc Stack`` in the Diagnostics
+section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_MALLOC_STACK` if it is set
+when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER.rst b/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER.rst
new file mode 100644
index 0000000..cc774c4
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER.rst
@@ -0,0 +1,14 @@
+XCODE_SCHEME_THREAD_SANITIZER
+-----------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Thread Sanitizer`` in the Diagnostics
+section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_THREAD_SANITIZER` if it is set
+when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP.rst b/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
new file mode 100644
index 0000000..3bb2596
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
@@ -0,0 +1,14 @@
+XCODE_SCHEME_THREAD_SANITIZER_STOP
+----------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Thread Sanitizer - Pause on issues``
+in the Diagnostics section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP` if it is set
+when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst b/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
new file mode 100644
index 0000000..1146130
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
@@ -0,0 +1,14 @@
+XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER
+------------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Undefined Behavior Sanitizer``
+in the Diagnostics section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER`
+if it is set when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst b/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
new file mode 100644
index 0000000..358f298
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
@@ -0,0 +1,15 @@
+XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP
+-----------------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Undefined Behavior Sanitizer`` option
+``Pause on issues``
+in the Diagnostics section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP`
+if it is set when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_WORKING_DIRECTORY.rst b/Help/prop_tgt/XCODE_SCHEME_WORKING_DIRECTORY.rst
new file mode 100644
index 0000000..d8d56fc
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_WORKING_DIRECTORY.rst
@@ -0,0 +1,15 @@
+XCODE_SCHEME_WORKING_DIRECTORY
+------------------------------
+
+.. versionadded:: 3.17
+
+Specify the ``Working Directory`` of the *Run* and *Profile*
+actions in the generated Xcode scheme. In case the value contains
+generator expressions those are evaluated.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_WORKING_DIRECTORY` if it is set
+when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS.rst b/Help/prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS.rst
new file mode 100644
index 0000000..6030109
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS.rst
@@ -0,0 +1,14 @@
+XCODE_SCHEME_ZOMBIE_OBJECTS
+------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Zombie Objects``
+in the Diagnostics section of the generated Xcode scheme.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS` if it is set
+when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/prop_tgt/XCTEST.rst b/Help/prop_tgt/XCTEST.rst
new file mode 100644
index 0000000..67e9a70
--- /dev/null
+++ b/Help/prop_tgt/XCTEST.rst
@@ -0,0 +1,15 @@
+XCTEST
+------
+
+.. versionadded:: 3.3
+
+This target is a XCTest CFBundle on the Mac.
+
+This property will usually get set via the :command:`xctest_add_bundle`
+macro in :module:`FindXCTest` module.
+
+If a module library target has this property set to true it will be
+built as a CFBundle when built on the Mac. It will have the directory
+structure required for a CFBundle.
+
+This property depends on :prop_tgt:`BUNDLE` to be effective.
diff --git a/Help/prop_tgt/XXX_OUTPUT_DIRECTORY.txt b/Help/prop_tgt/XXX_OUTPUT_DIRECTORY.txt
new file mode 100644
index 0000000..d38a96e
--- /dev/null
+++ b/Help/prop_tgt/XXX_OUTPUT_DIRECTORY.txt
@@ -0,0 +1,12 @@
+Output directory in which to build |XXX| target files.
+
+This property specifies the directory into which |xxx| target files
+should be built. The property value may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+Multi-configuration generators (:ref:`Visual Studio <Visual Studio Generators>`,
+:generator:`Xcode`, :generator:`Ninja Multi-Config`) append a
+per-configuration subdirectory to the specified directory unless a generator
+expression is used.
+
+This property is initialized by the value of the
+|CMAKE_XXX_OUTPUT_DIRECTORY| variable if it is set when a target is created.
diff --git a/Help/prop_tgt/XXX_OUTPUT_NAME.txt b/Help/prop_tgt/XXX_OUTPUT_NAME.txt
new file mode 100644
index 0000000..126f391
--- /dev/null
+++ b/Help/prop_tgt/XXX_OUTPUT_NAME.txt
@@ -0,0 +1,5 @@
+Output name for |XXX| target files.
+
+This property specifies the base name for |xxx| target files. It
+overrides :prop_tgt:`OUTPUT_NAME` and :prop_tgt:`OUTPUT_NAME_<CONFIG>`
+properties.
diff --git a/Help/release/3.0.rst b/Help/release/3.0.rst
new file mode 100644
index 0000000..64491e3
--- /dev/null
+++ b/Help/release/3.0.rst
@@ -0,0 +1,473 @@
+CMake 3.0 Release Notes
+***********************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 2.8.12 include the following.
+
+Documentation Changes
+=====================
+
+* The CMake documentation has been converted to reStructuredText and
+ now transforms via Sphinx (`<http://sphinx-doc.org>`__) into man and
+ html pages. This allows the documentation to be properly indexed
+ and to contain cross-references.
+
+ Conversion from the old internal documentation format was done by
+ an automatic process so some documents may still contain artifacts.
+ They will be updated incrementally over time.
+
+ A basic reStructuredText processor has been implemented to support
+ ``cmake --help-command`` and similar command-line options.
+
+* New manuals were added:
+
+ - :manual:`cmake-buildsystem(7)`
+ - :manual:`cmake-commands(7)`, replacing ``cmakecommands(1)``
+ and ``cmakecompat(1)``
+ - :manual:`cmake-developer(7)`
+ - :manual:`cmake-generator-expressions(7)`
+ - :manual:`cmake-generators(7)`
+ - :manual:`cmake-language(7)`
+ - :manual:`cmake-modules(7)`, replacing ``cmakemodules(1)``
+ - :manual:`cmake-packages(7)`
+ - :manual:`cmake-policies(7)`, replacing ``cmakepolicies(1)``
+ - :manual:`cmake-properties(7)`, replacing ``cmakeprops(1)``
+ - :manual:`cmake-qt(7)`
+ - :manual:`cmake-toolchains(7)`
+ - :manual:`cmake-variables(7)`, replacing ``cmakevars(1)``
+
+* Release notes for CMake 3.0.0 and above will now be included with
+ the html documentation.
+
+New Features
+============
+
+Syntax
+------
+
+* The CMake language has been extended with
+ :ref:`Bracket Argument` and :ref:`Bracket Comment`
+ syntax inspired by Lua long brackets::
+
+ set(x [===[bracket argument]===] #[[bracket comment]])
+
+ Content between equal-length open- and close-brackets is taken
+ literally with no variable replacements.
+
+ .. warning::
+ This syntax change could not be made in a fully compatible
+ way. No policy is possible because syntax parsing occurs before
+ any chance to set a policy. Existing code using an unquoted
+ argument that starts with an open bracket will be interpreted
+ differently without any diagnostic. Fortunately the syntax is
+ obscure enough that this problem is unlikely in practice.
+
+Generators
+----------
+
+* A new :generator:`CodeLite` extra generator is available
+ for use with the Makefile or Ninja generators.
+
+* A new :generator:`Kate` extra generator is available
+ for use with the Makefile or Ninja generators.
+
+* The :generator:`Ninja` generator learned to use ``ninja`` job pools
+ when specified by a new :prop_gbl:`JOB_POOLS` global property.
+
+Commands
+--------
+
+* The :command:`add_library` command learned a new ``INTERFACE``
+ library type. Interface libraries have no build rules but may
+ have properties defining
+ :manual:`usage requirements <cmake-buildsystem(7)>`
+ and may be installed, exported, and imported. This is useful to
+ create header-only libraries that have concrete link dependencies
+ on other libraries.
+
+* The :command:`export()` command learned a new ``EXPORT`` mode that
+ retrieves the list of targets to export from an export set configured
+ by the :command:`install(TARGETS)` command ``EXPORT`` option. This
+ makes it easy to export from the build tree the same targets that
+ are exported from the install tree.
+
+* The :command:`export` command learned to work with multiple dependent
+ export sets, thus allowing multiple packages to be built and exported
+ from a single tree. The feature requires CMake to wait until the
+ generation step to write the output file. This means one should not
+ :command:`include` the generated targets file later during project
+ configuration because it will not be available.
+ Use :ref:`Alias Targets` instead. See policy :policy:`CMP0024`.
+
+* The :command:`install(FILES)` command learned to support
+ :manual:`generator expressions <cmake-generator-expressions(7)>`
+ in the list of files.
+
+* The :command:`project` command learned to set some version variables
+ to values specified by the new ``VERSION`` option or to empty strings.
+ See policy :policy:`CMP0048`.
+
+* The :command:`string` command learned a new ``CONCAT`` mode.
+ It is particularly useful in combination with the new
+ :ref:`Bracket Argument` syntax.
+
+* The :command:`unset` command learned a ``PARENT_SCOPE`` option
+ matching that of the :command:`set` command.
+
+* The :command:`include_external_msproject` command learned
+ to handle non-C++ projects like ``.vbproj`` or ``.csproj``.
+
+* The :command:`ctest_update` command learned to update work trees
+ managed by the Perforce (p4) version control tool.
+
+* The :command:`message` command learned a ``DEPRECATION`` mode. Such
+ messages are not issued by default, but may be issued as a warning if
+ :variable:`CMAKE_WARN_DEPRECATED` is enabled, or as an error if
+ :variable:`CMAKE_ERROR_DEPRECATED` is enabled.
+
+* The :command:`target_link_libraries` command now allows repeated use of
+ the ``LINK_PUBLIC`` and ``LINK_PRIVATE`` keywords.
+
+Variables
+---------
+
+* Variable :variable:`CMAKE_FIND_NO_INSTALL_PREFIX` has been
+ introduced to tell CMake not to add the value of
+ :variable:`CMAKE_INSTALL_PREFIX` to the
+ :variable:`CMAKE_SYSTEM_PREFIX_PATH` variable by default.
+ This is useful when building a project that installs some
+ of its own dependencies to avoid finding files it is about
+ to replace.
+
+* Variable :variable:`CMAKE_STAGING_PREFIX` was introduced for use
+ when cross-compiling to specify an installation prefix on the
+ host system that differs from a :variable:`CMAKE_INSTALL_PREFIX`
+ value meant for the target system.
+
+* Variable :variable:`CMAKE_SYSROOT` was introduced to specify the
+ toolchain SDK installation prefix, typically for cross-compiling.
+ This is used to pass a ``--sysroot`` option to the compiler and
+ as a prefix searched by ``find_*`` commands.
+
+* Variable :variable:`CMAKE_<LANG>_COMPILER_TARGET` was introduced
+ for use when cross-compiling to specify the target platform in the
+ :ref:`toolchain file <Cross Compiling Toolchain>` specified by the
+ :variable:`CMAKE_TOOLCHAIN_FILE` variable.
+ This is used to pass an option such as ``--target=<triple>`` to some
+ cross-compiling compiler drivers.
+
+* Variable :variable:`CMAKE_MAP_IMPORTED_CONFIG_<CONFIG>` has been
+ introduced to optionally initialize the
+ :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` target property.
+
+Properties
+----------
+
+* The :prop_dir:`ADDITIONAL_MAKE_CLEAN_FILES` directory property
+ learned to support
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* A new directory property :prop_dir:`CMAKE_CONFIGURE_DEPENDS`
+ was introduced to allow projects to specify additional
+ files on which the configuration process depends. CMake will
+ re-run at build time when one of these files is modified.
+ Previously this was only possible to achieve by specifying
+ such files as the input to a :command:`configure_file` command.
+
+* A new :ref:`Qt AUTORCC` feature replaces the need to
+ invoke ``qt4_add_resources()`` by allowing ``.qrc`` files to
+ be listed as target sources.
+
+* A new :ref:`Qt AUTOUIC` feature replaces the need to
+ invoke ``qt4_wrap_ui()``.
+
+* Test properties learned to support
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+ This is useful to specify per-configuration values for test
+ properties like :prop_test:`REQUIRED_FILES` and
+ :prop_test:`WORKING_DIRECTORY`.
+
+* A new :prop_test:`SKIP_RETURN_CODE` test property was introduced
+ to tell :manual:`ctest(1)` to treat a particular test return code as
+ if the test were not run. This is useful for test drivers to report
+ that certain test requirements were not available.
+
+* New types of :ref:`Compatible Interface Properties` were introduced,
+ namely the :prop_tgt:`COMPATIBLE_INTERFACE_NUMBER_MAX` and
+ :prop_tgt:`COMPATIBLE_INTERFACE_NUMBER_MIN` for calculating numeric
+ maximum and minimum values respectively.
+
+Modules
+-------
+
+* The :module:`CheckTypeSize` module ``check_type_size`` macro and
+ the :module:`CheckStructHasMember` module ``check_struct_has_member``
+ macro learned a new ``LANGUAGE`` option to optionally check C++ types.
+
+* The :module:`ExternalData` module learned to work with no
+ URL templates if a local store is available.
+
+* The :module:`ExternalProject` function ``ExternalProject_Add``
+ learned a new ``GIT_SUBMODULES`` option to specify a subset
+ of available submodules to checkout.
+
+* A new :module:`FindBacktrace` module has been added to support
+ :command:`find_package(Backtrace)` calls.
+
+* A new :module:`FindLua` module has been added to support
+ :command:`find_package(Lua)` calls.
+
+* The :module:`FindBoost` module learned a new ``Boost_NAMESPACE``
+ option to change the ``boost`` prefix on library names.
+
+* The :module:`FindBoost` module learned to control search
+ for libraries with the ``g`` tag (for MS debug runtime) with
+ a new ``Boost_USE_DEBUG_RUNTIME`` option. It is ``ON`` by
+ default to preserve existing behavior.
+
+* The :module:`FindJava` and :module:`FindJNI` modules learned
+ to use a ``JAVA_HOME`` CMake variable or environment variable,
+ and then try ``/usr/libexec/java_home`` on OS X.
+
+* The :module:`UseJava` module ``add_jar`` function learned a new
+ ``MANIFEST`` option to pass the ``-m`` option to ``jar``.
+
+* A new :module:`CMakeFindDependencyMacro` module was introduced with
+ a ``find_dependency`` macro to find transitive dependencies in
+ a :manual:`package configuration file <cmake-packages(7)>`. Such
+ dependencies are omitted by the listing of the :module:`FeatureSummary`
+ module.
+
+* The :module:`FindQt4` module learned to create :ref:`Imported Targets`
+ for Qt executables. This helps disambiguate when using multiple
+ :manual:`Qt versions <cmake-qt(7)>` in the same buildsystem.
+
+* The :module:`FindRuby` module learned to search for Ruby 2.0 and 2.1.
+
+Generator Expressions
+---------------------
+
+* New ``$<PLATFORM_ID>`` and ``$<PLATFORM_ID:...>``
+ :manual:`generator expressions <cmake-generator-expressions(7)>`
+ have been added.
+
+* The ``$<CONFIG>``
+ :manual:`generator expression <cmake-generator-expressions(7)>` now has
+ a variant which takes no argument. This is equivalent to the
+ ``$<CONFIGURATION>`` expression.
+
+* New ``$<UPPER_CASE:...>`` and ``$<LOWER_CASE:...>``
+ :manual:`generator expressions <cmake-generator-expressions(7)>`
+ generator expressions have been added.
+
+* A new ``$<MAKE_C_IDENTIFIER:...>``
+ :manual:`generator expression <cmake-generator-expressions(7)>` has
+ been added.
+
+Other
+-----
+
+* The :manual:`cmake(1)` ``-E`` option learned a new ``sleep`` command.
+
+* The :manual:`ccmake(1)` dialog learned to honor the
+ :prop_cache:`STRINGS` cache entry property to cycle through
+ the enumerated list of possible values.
+
+* The :manual:`cmake-gui(1)` dialog learned to remember window
+ settings between sessions.
+
+* The :manual:`cmake-gui(1)` dialog learned to remember the type
+ of a cache entry for completion in the ``Add Entry`` dialog.
+
+New Diagnostics
+===============
+
+* Directories named in the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`
+ target property of imported targets linked conditionally by a
+ :manual:`generator expression <cmake-generator-expressions(7)>`
+ were not checked for existence. Now they are checked.
+ See policy :policy:`CMP0027`.
+
+* Build target names must now match a validity pattern and may no longer
+ conflict with CMake-defined targets. See policy :policy:`CMP0037`.
+
+* Build targets that specify themselves as a link dependency were
+ silently accepted but are now diagnosed. See :policy:`CMP0038`.
+
+* The :command:`target_link_libraries` command used to silently ignore
+ calls specifying as their first argument build targets created by
+ :command:`add_custom_target` but now diagnoses this mistake.
+ See policy :policy:`CMP0039`.
+
+* The :command:`add_custom_command` command used to silently ignore
+ calls specifying the ``TARGET`` option with a non-existent target
+ but now diagnoses this mistake. See policy :policy:`CMP0040`.
+
+* Relative paths in the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`
+ target property used to be silently accepted if they contained a
+ :manual:`generator expression <cmake-generator-expressions(7)>`
+ but are now rejected. See policy :policy:`CMP0041`.
+
+* The :command:`get_target_property` command learned to reject calls
+ specifying a non-existent target. See policy :policy:`CMP0045`.
+
+* The :command:`add_dependencies` command learned to reject calls
+ specifying a dependency on a non-existent target.
+ See policy :policy:`CMP0046`.
+
+* Link dependency analysis learned to assume names containing ``::``
+ refer to :ref:`Alias Targets` or :ref:`Imported Targets`. It will
+ now produce an error if such a linked target is missing. Previously
+ in this case CMake generated a link line that failed at build time.
+ See policy :policy:`CMP0028`.
+
+* When the :command:`project` or :command:`enable_language` commands
+ initialize support for a language, it is now an error if the full
+ path to the compiler cannot be found and stored in the corresponding
+ :variable:`CMAKE_<LANG>_COMPILER` variable. This produces nicer error
+ messages up front and stops processing when no working compiler
+ is known to be available.
+
+* Target sources specified with the :command:`add_library` or
+ :command:`add_executable` command learned to reject items which
+ require an undocumented extra layer of variable expansion.
+ See policy :policy:`CMP0049`.
+
+* Use of :command:`add_custom_command` undocumented ``SOURCE``
+ signatures now results in an error. See policy :policy:`CMP0050`.
+
+Deprecated and Removed Features
+===============================
+
+* Compatibility options supporting code written for CMake versions
+ prior to 2.4 have been removed.
+
+* Several long-outdated commands that should no longer be called
+ have been disallowed in new code by policies:
+
+ - Policy :policy:`CMP0029` disallows :command:`subdir_depends`
+ - Policy :policy:`CMP0030` disallows :command:`use_mangled_mesa`
+ - Policy :policy:`CMP0031` disallows :command:`load_command`
+ - Policy :policy:`CMP0032` disallows :command:`output_required_files`
+ - Policy :policy:`CMP0033` disallows :command:`export_library_dependencies`
+ - Policy :policy:`CMP0034` disallows :command:`utility_source`
+ - Policy :policy:`CMP0035` disallows :command:`variable_requires`
+ - Policy :policy:`CMP0036` disallows :command:`build_name`
+
+* The :manual:`cmake(1)` ``-i`` wizard mode has been removed.
+ Instead use an interactive dialog such as :manual:`ccmake(1)`
+ or use the ``-D`` option to set cache values from the command line.
+
+* The builtin documentation formatters that supported command-line
+ options such as ``--help-man`` and ``--help-html`` have been removed
+ in favor of the above-mentioned new documentation system. These and
+ other command-line options that used to generate man- and html-
+ formatted pages no longer work. The :manual:`cmake(1)`
+ ``--help-custom-modules`` option now produces a warning at runtime
+ and generates a minimal document that reports the limitation.
+
+* The :prop_dir:`COMPILE_DEFINITIONS_<CONFIG>` directory properties and the
+ :prop_tgt:`COMPILE_DEFINITIONS_<CONFIG>` target properties have been
+ deprecated. Instead set the corresponding :prop_dir:`COMPILE_DEFINITIONS`
+ directory property or :prop_tgt:`COMPILE_DEFINITIONS` target property and
+ use :manual:`generator expressions <cmake-generator-expressions(7)>` like
+ ``$<CONFIG:...>`` to specify per-configuration definitions.
+ See policy :policy:`CMP0043`.
+
+* The :prop_tgt:`LOCATION` target property should no longer be read from
+ non-IMPORTED targets. It does not make sense in multi-configuration
+ generators since the build configuration is not known while configuring
+ the project. It has been superseded by the ``$<TARGET_FILE>`` generator
+ expression. See policy :policy:`CMP0026`.
+
+* The :prop_tgt:`COMPILE_FLAGS` target property is now documented
+ as deprecated, though no warning is issued. Use the
+ :prop_tgt:`COMPILE_OPTIONS` target property or the
+ :command:`target_compile_options` command instead.
+
+* The :module:`GenerateExportHeader` module ``add_compiler_export_flags``
+ function is now deprecated. It has been superseded by the
+ :prop_tgt:`<LANG>_VISIBILITY_PRESET` and
+ :prop_tgt:`VISIBILITY_INLINES_HIDDEN` target properties.
+
+Other Changes
+=============
+
+* The version scheme was changed to use only two components for
+ the feature level instead of three. The third component will
+ now be used for bug-fix releases or the date of development versions.
+ See the :variable:`CMAKE_VERSION` variable documentation for details.
+
+* The default install locations of CMake itself on Windows and
+ OS X no longer contain the CMake version number. This allows
+ for easy replacement without re-generating local build trees
+ manually.
+
+* Generators for Visual Studio 10 (2010) and later were renamed to
+ include the product year like generators for older VS versions:
+
+ - ``Visual Studio 10`` -> :generator:`Visual Studio 10 2010`
+ - ``Visual Studio 11`` -> :generator:`Visual Studio 11 2012`
+ - ``Visual Studio 12`` -> :generator:`Visual Studio 12 2013`
+
+ This clarifies which generator goes with each Visual Studio
+ version. The old names are recognized for compatibility.
+
+* The :variable:`CMAKE_<LANG>_COMPILER_ID` value for Apple-provided
+ Clang is now ``AppleClang``. It must be distinct from upstream
+ Clang because the version numbers differ.
+ See policy :policy:`CMP0025`.
+
+* The :variable:`CMAKE_<LANG>_COMPILER_ID` value for ``qcc`` on QNX
+ is now ``QCC``. It must be distinct from ``GNU`` because the
+ command-line options differ. See policy :policy:`CMP0047`.
+
+* On 64-bit OS X the :variable:`CMAKE_HOST_SYSTEM_PROCESSOR` value
+ is now correctly detected as ``x86_64`` instead of ``i386``.
+
+* On OS X, CMake learned to enable behavior specified by the
+ :prop_tgt:`MACOSX_RPATH` target property by default. This activates
+ use of ``@rpath`` for runtime shared library searches.
+ See policy :policy:`CMP0042`.
+
+* The :command:`build_command` command now returns a :manual:`cmake(1)`
+ ``--build`` command line instead of a direct invocation of the native
+ build tool. When using ``Visual Studio`` generators, CMake and CTest
+ no longer require :variable:`CMAKE_MAKE_PROGRAM` to be located up front.
+ Selection of the proper msbuild or devenv tool is now performed as
+ late as possible when the solution (``.sln``) file is available so
+ it can depend on project content.
+
+* The :manual:`cmake(1)` ``--build`` command now shares its own stdout
+ and stderr pipes with the native build tool by default.
+ The ``--use-stderr`` option that once activated this is now ignored.
+
+* The ``$<C_COMPILER_ID:...>`` and ``$<CXX_COMPILER_ID:...>``
+ :manual:`generator expressions <cmake-generator-expressions(7)>`
+ used to perform case-insensitive comparison but have now been
+ corrected to perform case-sensitive comparison.
+ See policy :policy:`CMP0044`.
+
+* The builtin ``edit_cache`` target will no longer select
+ :manual:`ccmake(1)` by default when no interactive terminal will
+ be available (e.g. with :generator:`Ninja` or an IDE generator).
+ Instead :manual:`cmake-gui(1)` will be preferred if available.
+
+* The :module:`ExternalProject` download step learned to
+ re-attempt download in certain cases to be more robust to
+ temporary network failure.
+
+* The :module:`FeatureSummary` no longer lists transitive
+ dependencies since they were not directly requested by the
+ current project.
+
+* The ``cmake-mode.el`` major Emacs editing mode has been cleaned
+ up and enhanced in several ways.
+
+* Include directories specified in the
+ :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of :ref:`Imported Targets`
+ are treated as ``SYSTEM`` includes by default when handled as
+ :ref:`usage requirements <Include Directories and Usage Requirements>`.
diff --git a/Help/release/3.1.rst b/Help/release/3.1.rst
new file mode 100644
index 0000000..3f4712b
--- /dev/null
+++ b/Help/release/3.1.rst
@@ -0,0 +1,425 @@
+CMake 3.1 Release Notes
+***********************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.0 include the following.
+
+Documentation Changes
+=====================
+
+* A new :manual:`cmake-compile-features(7)` manual was added.
+
+New Features
+============
+
+Generators
+----------
+
+* The :generator:`Visual Studio 14 2015` generator was added.
+
+Windows Phone and Windows Store
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* Generators for Visual Studio 11 (2012) and above learned to generate
+ projects for Windows Phone and Windows Store. One may set the
+ :variable:`CMAKE_SYSTEM_NAME` variable to ``WindowsPhone``
+ or ``WindowsStore`` on the :manual:`cmake(1)` command-line
+ or in a :variable:`CMAKE_TOOLCHAIN_FILE` to activate these platforms.
+ Also set :variable:`CMAKE_SYSTEM_VERSION` to ``8.0`` or ``8.1`` to
+ specify the version of Windows to be targeted.
+
+NVIDIA Nsight Tegra
+^^^^^^^^^^^^^^^^^^^
+
+* Generators for Visual Studio 10 (2010) and above learned to generate
+ projects for NVIDIA Nsight Tegra Visual Studio Edition. One may set
+ the :variable:`CMAKE_SYSTEM_NAME` variable to ``Android`` on the
+ :manual:`cmake(1)` command-line or in a :variable:`CMAKE_TOOLCHAIN_FILE`
+ to activate this platform.
+
+Syntax
+------
+
+* The :manual:`cmake-language(7)` syntax for :ref:`Variable References` and
+ :ref:`Escape Sequences` was simplified in order to allow a much faster
+ implementation. See policy :policy:`CMP0053`.
+
+* The :command:`if` command no longer automatically dereferences
+ variables named in quoted or bracket arguments. See policy
+ :policy:`CMP0054`.
+
+Commands
+--------
+
+* The :command:`add_custom_command` command learned to interpret
+ :manual:`cmake-generator-expressions(7)` in arguments to ``DEPENDS``.
+
+* The :command:`export(PACKAGE)` command learned to check the
+ :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable to skip
+ exporting the package.
+
+* The :command:`file(STRINGS)` command gained a new ``ENCODING``
+ option to enable extraction of ``UTF-8`` strings.
+
+* The :command:`find_package` command learned to check the
+ :variable:`CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY` and
+ :variable:`CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY`
+ variables to skip searching the package registries.
+
+* The :command:`get_property` command learned a new ``INSTALL`` scope
+ for properties.
+
+* The :command:`install` command learned a ``MESSAGE_NEVER`` option
+ to avoid output during installation.
+
+* The :command:`set_property` command learned a new ``INSTALL`` scope
+ for properties.
+
+* The :command:`string` command learned a new ``GENEX_STRIP`` subcommand
+ which removes
+ :manual:`generator expression <cmake-generator-expressions(7)>`.
+
+* The :command:`string` command learned a new ``UUID`` subcommand
+ to generate a universally unique identifier.
+
+* New :command:`target_compile_features` command allows populating the
+ :prop_tgt:`COMPILE_FEATURES` target property, just like any other
+ build variable.
+
+* The :command:`target_sources` command was added to add to the
+ :prop_tgt:`SOURCES` target property.
+
+Variables
+---------
+
+* The Visual Studio generators for versions 8 (2005) and above
+ learned to read the target platform name from a new
+ :variable:`CMAKE_GENERATOR_PLATFORM` variable when it is
+ not specified as part of the generator name. The platform
+ name may be specified on the :manual:`cmake(1)` command line
+ with the ``-A`` option, e.g. ``-G "Visual Studio 12 2013" -A x64``.
+
+* The :variable:`CMAKE_GENERATOR_TOOLSET` variable may now be
+ initialized in a toolchain file specified by the
+ :variable:`CMAKE_TOOLCHAIN_FILE` variable. This is useful
+ when cross-compiling with the Xcode or Visual Studio
+ generators.
+
+* The :variable:`CMAKE_INSTALL_MESSAGE` variable was introduced to
+ optionally reduce output installation.
+
+Properties
+----------
+
+* New :prop_tgt:`CXX_STANDARD` and :prop_tgt:`CXX_EXTENSIONS` target
+ properties may specify values which CMake uses to compute required
+ compile options such as ``-std=c++11`` or ``-std=gnu++11``. The
+ :variable:`CMAKE_CXX_STANDARD` and :variable:`CMAKE_CXX_EXTENSIONS`
+ variables may be set to initialize the target properties.
+
+* New :prop_tgt:`C_STANDARD` and :prop_tgt:`C_EXTENSIONS` target
+ properties may specify values which CMake uses to compute required
+ compile options such as ``-std=c11`` or ``-std=gnu11``. The
+ :variable:`CMAKE_C_STANDARD` and :variable:`CMAKE_C_EXTENSIONS`
+ variables may be set to initialize the target properties.
+
+* New :prop_tgt:`COMPILE_FEATURES` target property may contain a list
+ of features required to compile a target. CMake uses this
+ information to ensure that the compiler in use is capable of building
+ the target, and to add any necessary compile flags to support language
+ features.
+
+* New :prop_tgt:`COMPILE_PDB_NAME` and
+ :prop_tgt:`COMPILE_PDB_OUTPUT_DIRECTORY` target properties
+ were introduced to specify the MSVC compiler program database
+ file location (``cl /Fd``). This complements the existing
+ :prop_tgt:`PDB_NAME` and :prop_tgt:`PDB_OUTPUT_DIRECTORY`
+ target properties that specify the linker program database
+ file location (``link /pdb``).
+
+* The :prop_tgt:`INTERFACE_LINK_LIBRARIES` target property now supports
+ a ``$<LINK_ONLY:...>``
+ :manual:`generator expression <cmake-generator-expressions(7)>`.
+
+* A new :prop_tgt:`INTERFACE_SOURCES` target property was introduced. This is
+ consumed by dependent targets, which compile and link the listed sources.
+
+* The :prop_tgt:`SOURCES` target property now contains
+ :manual:`generator expression <cmake-generator-expressions(7)>`
+ such as ``TARGET_OBJECTS`` when read at configure time, if
+ policy :policy:`CMP0051` is ``NEW``.
+
+* The :prop_tgt:`SOURCES` target property now generally supports
+ :manual:`generator expression <cmake-generator-expressions(7)>`. The
+ generator expressions may be used in the :command:`add_library` and
+ :command:`add_executable` commands.
+
+* It is now possible to write and append to the :prop_tgt:`SOURCES` target
+ property. The :variable:`CMAKE_DEBUG_TARGET_PROPERTIES` variable may be
+ used to trace the origin of sources.
+
+* A :prop_sf:`VS_DEPLOYMENT_CONTENT` source file property was added
+ to tell the Visual Studio generators to mark content for deployment
+ in Windows Phone and Windows Store projects.
+
+* A :prop_sf:`VS_DEPLOYMENT_LOCATION` source file property was added
+ to tell the Visual Studio generators the relative location of content
+ marked for deployment in Windows Phone and Windows Store projects.
+
+* The :prop_tgt:`VS_WINRT_COMPONENT` target property was created to
+ tell Visual Studio generators to compile a shared library as a
+ Windows Runtime (WinRT) component.
+
+* The :generator:`Xcode` generator learned to check source
+ file properties :prop_sf:`XCODE_EXPLICIT_FILE_TYPE` and
+ :prop_sf:`XCODE_LAST_KNOWN_FILE_TYPE` for a custom Xcode
+ file reference type.
+
+Modules
+-------
+
+* The :module:`BundleUtilities` module learned to resolve and replace
+ ``@rpath`` placeholders on OS X to correctly bundle applications
+ using them.
+
+* The :module:`CMakePackageConfigHelpers` module
+ :command:`configure_package_config_file` command learned a new
+ ``INSTALL_PREFIX`` option to generate package configuration files
+ meant for a prefix other than :variable:`CMAKE_INSTALL_PREFIX`.
+
+* The :module:`CheckFortranSourceCompiles` module was added to
+ provide a ``CHECK_Fortran_SOURCE_COMPILES`` macro.
+
+* The :module:`ExternalData` module learned to tolerate a ``DATA{}``
+ reference to a missing source file with a warning instead of
+ rejecting it with an error. This helps developers write new
+ ``DATA{}`` references to test reference outputs that have not
+ yet been created.
+
+* The :module:`ExternalProject` module learned to support lzma-compressed
+ source tarballs with ``.7z``, ``.tar.xz``, and ``.txz`` extensions.
+
+* The :module:`ExternalProject` module ``ExternalProject_Add`` command
+ learned a new ``BUILD_ALWAYS`` option to cause the external project
+ build step to run every time the host project is built.
+
+* The :module:`ExternalProject` module ``ExternalProject_Add`` command
+ learned a new ``EXCLUDE_FROM_ALL`` option to cause the external
+ project target to have the :prop_tgt:`EXCLUDE_FROM_ALL` target
+ property set.
+
+* The :module:`ExternalProject` module ``ExternalProject_Add_Step`` command
+ learned a new ``EXCLUDE_FROM_MAIN`` option to cause the step to not be
+ a direct dependency of the main external project target.
+
+* The :module:`ExternalProject` module ``ExternalProject_Add`` command
+ learned a new ``DOWNLOAD_NO_PROGRESS`` option to disable progress
+ output while downloading the source tarball.
+
+* The :module:`FeatureSummary` module ``feature_summary`` API
+ learned to accept multiple values for the ``WHAT`` option and
+ combine them appropriately.
+
+* The :module:`FindCUDA` module learned to support ``fatbin`` and ``cubin``
+ modules.
+
+* The :module:`FindGTest` module ``gtest_add_tests`` macro learned
+ a new ``AUTO`` option to automatically read the :prop_tgt:`SOURCES`
+ target property of the test executable and scan the source files
+ for tests to be added.
+
+* The :module:`FindGLEW` module now provides imported targets.
+
+* The :module:`FindGLUT` module now provides imported targets.
+
+* The :module:`FindHg` module gained a new ``Hg_WC_INFO`` macro to
+ help run ``hg`` to extract information about a Mercurial work copy.
+
+* The :module:`FindOpenCL` module was introduced.
+
+* The :module:`FindOpenMP` module learned to support Fortran.
+
+* The :module:`FindPkgConfig` module learned to use the ``PKG_CONFIG``
+ environment variable value as the ``pkg-config`` executable, if set.
+
+* The :module:`FindXercesC` module was introduced.
+
+* The :module:`FindZLIB` module now provides imported targets.
+
+* The :module:`GenerateExportHeader` module ``generate_export_header``
+ function learned to allow use with :ref:`Object Libraries`.
+
+* The :module:`InstallRequiredSystemLibraries` module gained a new
+ ``CMAKE_INSTALL_OPENMP_LIBRARIES`` option to install MSVC OpenMP
+ runtime libraries.
+
+* The :module:`UseSWIG` module learned to detect the module name
+ from ``.i`` source files if possible to avoid the need to set
+ the ``SWIG_MODULE_NAME`` source file property explicitly.
+
+* The :module:`WriteCompilerDetectionHeader` module was added to allow
+ creation of a portable header file for compiler optional feature detection.
+
+Generator Expressions
+---------------------
+
+* New ``COMPILE_FEATURES``
+ :manual:`generator expression <cmake-generator-expressions(7)>` allows
+ setting build properties based on available compiler features.
+
+CTest
+-----
+
+* The :command:`ctest_coverage` command learned to read variable
+ ``CTEST_COVERAGE_EXTRA_FLAGS`` to set ``CoverageExtraFlags``.
+
+* The :command:`ctest_coverage` command learned to support
+ Intel coverage files with the ``codecov`` tool.
+
+* The :command:`ctest_memcheck` command learned to support sanitizer
+ modes, including ``AddressSanitizer``, ``MemorySanitizer``,
+ ``ThreadSanitizer``, and ``UndefinedBehaviorSanitizer``.
+ Options may be set using the new
+ :variable:`CTEST_MEMORYCHECK_SANITIZER_OPTIONS` variable.
+
+CPack
+-----
+
+* :manual:`cpack(1)` gained an ``IFW`` generator to package using
+ Qt Framework Installer tools. See the :cpack_gen:`CPack IFW Generator`.
+
+* :manual:`cpack(1)` gained ``7Z`` and ``TXZ`` generators supporting
+ lzma-compressed archives.
+
+* The :cpack_gen:`CPack DEB Generator` learned a new
+ :variable:`CPACK_DEBIAN_COMPRESSION_TYPE` variable to set the
+ tarball compression type.
+
+* The :cpack_gen:`CPack WIX Generator` learned to support
+ a :prop_inst:`CPACK_WIX_ACL` installed file property to
+ specify an Access Control List.
+
+Other
+-----
+
+* The :manual:`cmake(1)` ``-E`` option learned a new ``env`` command.
+
+* The :manual:`cmake(1)` ``-E tar`` command learned to support
+ lzma-compressed files.
+
+* :ref:`Object Libraries` may now have extra sources that do not
+ compile to object files so long as they would not affect linking
+ of a normal library (e.g. ``.dat`` is okay but not ``.def``).
+
+* Visual Studio generators for VS 8 and later learned to support
+ the ``ASM_MASM`` language.
+
+* The Visual Studio generators learned to treat ``.hlsl`` source
+ files as High Level Shading Language sources (using ``FXCompile``
+ in ``.vcxproj`` files). Source file properties
+ :prop_sf:`VS_SHADER_TYPE`, :prop_sf:`VS_SHADER_MODEL`, and
+ :prop_sf:`VS_SHADER_ENTRYPOINT` were added added to specify the
+ shader type, model, and entry point name.
+
+New Diagnostics
+===============
+
+* Policy :policy:`CMP0052` introduced to control directories in the
+ :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of exported targets.
+
+Deprecated and Removed Features
+===============================
+
+* In CMake 3.0 the :command:`target_link_libraries` command
+ accidentally began allowing unquoted arguments to use
+ :manual:`generator expressions <cmake-generator-expressions(7)>`
+ containing a (``;`` separated) list within them. For example::
+
+ set(libs B C)
+ target_link_libraries(A PUBLIC $<BUILD_INTERFACE:${libs}>)
+
+ This is equivalent to writing::
+
+ target_link_libraries(A PUBLIC $<BUILD_INTERFACE:B C>)
+
+ and was never intended to work. It did not work in CMake 2.8.12.
+ Such generator expressions should be in quoted arguments::
+
+ set(libs B C)
+ target_link_libraries(A PUBLIC "$<BUILD_INTERFACE:${libs}>")
+
+ CMake 3.1 again requires the quotes for this to work correctly.
+
+* Prior to CMake 3.1 the Makefile generators did not escape ``#``
+ correctly inside make variable assignments used in generated
+ makefiles, causing them to be treated as comments. This made
+ code like::
+
+ add_compile_options(-Wno-#pragma-messages)
+
+ not work in Makefile generators, but work in other generators.
+ Now it is escaped correctly, making the behavior consistent
+ across generators. However, some projects may have tried to
+ workaround the original bug with code like::
+
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-\\#pragma-messages")
+
+ This added the needed escape for Makefile generators but also
+ caused other generators to pass ``-Wno-\#pragma-messages`` to
+ the shell, which would work only in POSIX shells.
+ Unfortunately the escaping fix could not be made in a compatible
+ way so this platform- and generator-specific workaround no
+ longer works. Project code may test the :variable:`CMAKE_VERSION`
+ variable value to make the workaround version-specific too.
+
+* Callbacks established by the :command:`variable_watch` command will no
+ longer receive the ``ALLOWED_UNKNOWN_READ_ACCESS`` access type when
+ the undocumented ``CMAKE_ALLOW_UNKNOWN_VARIABLE_READ_ACCESS`` variable is
+ set. Uninitialized variable accesses will always be reported as
+ ``UNKNOWN_READ_ACCESS``.
+
+* The :module:`CMakeDetermineVSServicePack` module now warns that
+ it is deprecated and should not longer be used. Use the
+ :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable instead.
+
+* The :module:`FindITK` module has been removed altogether.
+ It was a thin-wrapper around ``find_package(ITK ... NO_MODULE)``.
+ This produces much clearer error messages when ITK is not found.
+
+* The :module:`FindVTK` module has been removed altogether.
+ It was a thin-wrapper around ``find_package(VTK ... NO_MODULE)``.
+ This produces much clearer error messages when VTK is not found.
+
+ The module also provided compatibility support for finding VTK 4.0.
+ This capability has been dropped.
+
+Other Changes
+=============
+
+* The :manual:`cmake-gui(1)` learned to capture output from child
+ processes started by the :command:`execute_process` command
+ and display it in the output window.
+
+* The :manual:`cmake-language(7)` internal implementation of generator
+ expression and list expansion parsers have been optimized and shows
+ non-trivial speedup on large projects.
+
+* The Makefile generators learned to use response files with GNU tools
+ on Windows to pass library directories and names to the linker.
+
+* When generating linker command-lines, CMake now avoids repeating
+ items corresponding to SHARED library targets.
+
+* Support for the Open Watcom compiler has been overhauled.
+ The :variable:`CMAKE_<LANG>_COMPILER_ID` is now ``OpenWatcom``,
+ and the :variable:`CMAKE_<LANG>_COMPILER_VERSION` now uses
+ the Open Watcom external version numbering. The external
+ version numbers are lower than the internal version number
+ by 11.
+
+* The ``cmake-mode.el`` major Emacs editing mode no longer
+ treats ``_`` as part of words, making it more consistent
+ with other major modes.
diff --git a/Help/release/3.10.rst b/Help/release/3.10.rst
new file mode 100644
index 0000000..117415b
--- /dev/null
+++ b/Help/release/3.10.rst
@@ -0,0 +1,282 @@
+CMake 3.10 Release Notes
+************************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.9 include the following.
+
+New Features
+============
+
+Platforms
+---------
+
+* The `flang`_ Fortran compiler is now supported, with compiler id ``Flang``.
+
+* A new minimal platform file for ``Midipix`` was added.
+
+* Support for the MSVC ARM64 architecture was added.
+ Visual Studio 2017 Update 4 and above offer an ARM64 toolchain.
+
+* Support for the IAR ARM Compiler was improved.
+
+.. _`flang`: https://github.com/flang-compiler/flang
+
+Generators
+----------
+
+* The :ref:`Makefile Generators` and the :generator:`Ninja` generator learned
+ to add compiler launcher tools like ccache along with the compiler for the
+ ``CUDA`` language (``C`` and ``CXX`` were supported previously). See the
+ :variable:`CMAKE_<LANG>_COMPILER_LAUNCHER` variable and
+ :prop_tgt:`<LANG>_COMPILER_LAUNCHER` target property for details.
+
+* The :generator:`CodeBlocks` extra generator learned to optionally exclude
+ files from outside the project root directory from the generated project.
+ See the :variable:`CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES` variable.
+
+Commands
+--------
+
+* The :command:`cmake_host_system_information` command learned more keys
+ to get information about the processor capabilities and the host OS
+ version.
+
+* The :command:`configure_file` command learned to support indented
+ ``# cmakedefine`` and ``# cmakedefine01``. Spaces and/or tabs between
+ the ``#`` character and the ``cmakedefine``/``cmakedefine01`` words
+ are now understood and preserved in the output.
+
+* The :command:`execute_process` command gained a ``RESULTS_VARIABLE``
+ option to collect a list of results from all children in a pipeline
+ of processes when multiple ``COMMAND`` arguments are given.
+
+* The :command:`include_guard` command was introduced to allow guarding
+ CMake scripts from being included more than once. The command supports
+ ``DIRECTORY`` and ``GLOBAL`` options to adjust the corresponding include guard
+ scope. If no options given, include guard is similar to basic variable-based
+ check.
+
+* The :command:`string` command learned a new ``PREPEND`` subcommand.
+
+* The :command:`string(TIMESTAMP)` command now supports ``%A``
+ for full weekday name and ``%B`` for full month name.
+
+Variables
+---------
+
+* A :variable:`CMAKE_DIRECTORY_LABELS` variable was added to specify
+ labels for all tests in a directory.
+
+Properties
+----------
+
+* A :prop_tgt:`<LANG>_CPPCHECK` target property and supporting
+ :variable:`CMAKE_<LANG>_CPPCHECK` variable were introduced to tell
+ the :ref:`Makefile Generators` and the :generator:`Ninja` generator to
+ run ``cppcheck`` with the compiler for ``C`` and ``CXX`` languages.
+
+* A :prop_dir:`LABELS` directory property was added to specify labels
+ for all targets and tests in a directory.
+
+* A :prop_dir:`TEST_INCLUDE_FILES` directory property was added to
+ list any number of files to be included when running tests with
+ :manual:`ctest(1)`. This generalizes the :prop_dir:`TEST_INCLUDE_FILE`
+ property.
+
+* The :prop_tgt:`VS_DOTNET_REFERENCEPROP_<refname>_TAG_<tagname>`
+ target property was added to support custom XML tags for reference
+ assemblies in C# targets.
+
+* Source file properties :prop_sf:`VS_SHADER_OUTPUT_HEADER_FILE` and
+ :prop_sf:`VS_SHADER_VARIABLE_NAME` have been added to specify more
+ details of ``.hlsl`` sources with :ref:`Visual Studio Generators`.
+
+Modules
+-------
+
+* The :module:`FindCurses` module gained a ``CURSES_NEED_WIDE`` option
+ to request the wide-character variant.
+
+* The :module:`FindEXPAT` module now provides imported targets.
+
+* The :module:`FindFreetype` module now provides imported targets.
+
+* :module:`FindMPI` gained a number of new features, including:
+
+ * Language-specific components have been added to the module.
+ * Many more MPI environments are now supported.
+ * The environmental support for Fortran has been improved.
+ * A user now has fine-grained control over the MPI selection process,
+ including passing custom parameters to the MPI compiler.
+ * The version of the implemented MPI standard is now being exposed.
+ * MPI-2 C++ bindings can now be detected and also suppressed if so desired.
+ * The available Fortran bindings are now being detected and verified.
+ * Various MPI-3 information can be requested, including the library version
+ and Fortran capabilities of the individual bindings.
+ * Statically linked MPI implementations are supported.
+
+* A :module:`FindOpenACC` module was added to detect compiler support
+ for OpenACC. Currently only supports PGI, GNU and Cray compilers.
+
+* The :module:`FindOpenGL` module gained support for GLVND on Linux.
+
+* The :module:`FindOpenMP` module gained support for
+ language-specific components.
+
+* A :module:`FindPatch` module was added to find the ``patch``
+ command-line executable.
+
+* The :module:`FindProtobuf` module :command:`protobuf_generate_cpp` command
+ gained a ``DESCRIPTORS`` option to generate descriptor files.
+
+* The :module:`GoogleTest` module gained a new command
+ :command:`gtest_discover_tests` implementing dynamic (build-time) test
+ discovery. Unlike the source parsing approach, dynamic discovery executes
+ the test (in 'list available tests' mode) at build time to discover tests.
+ This is robust against unusual ways of labeling tests, provides much better
+ support for advanced features such as parameterized tests, and does not
+ require re-running CMake to discover added or removed tests within a test
+ executable. Note that a breaking change was made in CMake 3.10.3 to address
+ an ambiguity of the ``TIMEOUT`` keyword (see :ref:`Release Notes 3.10.3`).
+
+* The :module:`InstallRequiredSystemLibraries` module gained support
+ for installing Intel compiler runtimes.
+
+Autogen
+-------
+
+* When using :prop_tgt:`AUTOMOC` or :prop_tgt:`AUTOUIC` with a
+ multi configuration generator (e.g. :generator:`Xcode`),
+ included ``*.moc``, ``moc_*.cpp`` and ``ui_*.h`` files are generated in
+ ``<AUTOGEN_BUILD_DIR>/include_<CONFIG>`` instead of
+ ``<AUTOGEN_BUILD_DIR>/include``.
+
+* When using :prop_tgt:`AUTOMOC` or :prop_tgt:`AUTOUIC`,
+ source files that are :prop_sf:`GENERATED` will be processed as well.
+ They were ignored by :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`
+ in earlier releases.
+ See policy :policy:`CMP0071`.
+
+* When using :prop_tgt:`AUTOMOC`, CMake searches for the strings ``Q_OBJECT``,
+ ``Q_GADGET`` or ``Q_NAMESPACE`` in a source file to determine if it needs
+ to be ``moc`` processed. The new :variable:`CMAKE_AUTOMOC_MACRO_NAMES`
+ variable and :prop_tgt:`AUTOMOC_MACRO_NAMES` target property may be set
+ to register additional strings (macro names) to search for.
+
+* When using :prop_tgt:`AUTOMOC`, the new
+ :variable:`CMAKE_AUTOMOC_COMPILER_PREDEFINES` variable and
+ :prop_tgt:`AUTOMOC_COMPILER_PREDEFINES` target property specify whether
+ to enable or disable the generation of the compiler pre definitions file
+ ``moc_predefs.h``.
+
+CTest
+-----
+
+* A :variable:`CTEST_LABELS_FOR_SUBPROJECTS` CTest module variable and CTest
+ script variable were added to specify a list of labels that should be
+ treated as subprojects by CDash. To use this value in both the CTest module
+ and the ctest command line :ref:`Dashboard Client` mode (e.g. ``ctest -S``)
+ set it in the ``CTestConfig.cmake`` config file.
+
+CPack
+-----
+
+* A :cpack_gen:`CPack FreeBSD Generator` was added for FreeBSD ``pkg(8)``.
+
+* The :cpack_gen:`CPack DEB Generator` was enabled on Windows. While not
+ fully featured (due to the lack of external UNIX tools) this will allow
+ building basic cross-platform Debian packages.
+
+* The :cpack_gen:`CPack DEB Generator` learned to set package release
+ version in ``Version`` info property.
+ See the :variable:`CPACK_DEBIAN_PACKAGE_RELEASE` variable.
+
+* The :cpack_gen:`CPack DEB Generator` learned more strict package
+ version checking that complies with Debian rules.
+
+* The :module:`CPackIFW` module :command:`cpack_ifw_configure_component` and
+ :command:`cpack_ifw_configure_component_group` commands gained a new
+ ``REPLACES`` and ``CHECKABLE`` options.
+
+* The :cpack_gen:`CPack IFW Generator` gained new
+ :variable:`CPACK_IFW_PACKAGE_FILE_EXTENSION` variable to customize
+ target binary format.
+
+* The :cpack_gen:`CPack IFW Generator` gained new
+ :variable:`CPACK_IFW_REPOSITORIES_DIRECTORIES` variable to specify
+ additional repositories dirs that will be used to resolve and
+ repack dependent components. This feature is only available when
+ using QtIFW 3.1 or later.
+
+* The :cpack_gen:`CPack RPM Generator` and :cpack_gen:`CPack DEB Generator`
+ learned to set the package epoch version.
+ See :variable:`CPACK_RPM_PACKAGE_EPOCH` and
+ :variable:`CPACK_DEBIAN_PACKAGE_EPOCH` variables.
+
+Other
+-----
+
+* The :manual:`cmake(1)` ``-E`` mode gained support for ``sha1sum``,
+ ``sha224sum``, ``sha256sum``, ``sha384sum``, and ``sha512sum``.
+
+* The graphviz output now distinguishes among the different dependency types
+ ``PUBLIC``, ``PRIVATE`` and ``INTERFACE`` and represents them in the output
+ graph as solid, dashed and dotted edges.
+
+Deprecated and Removed Features
+===============================
+
+* Support for building CMake itself with C++98 compilers was dropped.
+ CMake is now implemented using C++11.
+
+* Support for building CMake on HP-UX has been dropped pending better
+ support for C++11 and a port of libuv. See `CMake Issue 17137`_.
+ Use CMake 3.9 or lower instead for HP-UX support.
+
+.. _`CMake Issue 17137`: https://gitlab.kitware.com/cmake/cmake/-/issues/17137
+
+Other Changes
+=============
+
+* On FreeBSD the C++ compiler named ``c++`` is now the preferred default.
+
+* The :command:`file(GENERATE)` command now interprets relative paths
+ given to its ``OUTPUT`` and ``INPUT`` arguments with respect to the
+ caller's current binary and source directories, respectively.
+ See policy :policy:`CMP0070`.
+
+* The :command:`get_filename_component` ``PROGRAM`` mode semantics
+ have been revised to not tolerate unquoted spaces in the path
+ to the program while also accepting arguments. While technically
+ incompatible with the old behavior, it is expected that behavior
+ under typical use cases with properly-quoted command-lines has
+ not changed.
+
+Updates
+=======
+
+Changes made since CMake 3.10.0 include the following.
+
+3.10.1
+------
+
+* The :manual:`cmake-server(7)` ``codemodel`` response ``crossReferences``
+ field added by 3.10.0 has been dropped due to excessive memory usage.
+ Another approach will be needed to provide backtrace information.
+
+.. _`Release Notes 3.10.3`:
+
+3.10.3
+------
+
+* CMake 3.10.1 added a ``TIMEOUT`` option to :command:`gtest_discover_tests`
+ from the :module:`GoogleTest` module. That keyword clashed with the
+ ``TIMEOUT`` test property, which is one of the common properties that
+ would be set with the command's ``PROPERTIES`` keyword, usually leading
+ to legal but unintended behavior. The keyword was changed to
+ ``DISCOVERY_TIMEOUT`` in CMake 3.10.3 to address this problem. The
+ ambiguous behavior of the :command:`gtest_discover_tests` command's
+ ``TIMEOUT`` keyword in 3.10.1 and 3.10.2 has not been preserved.
diff --git a/Help/release/3.11.rst b/Help/release/3.11.rst
new file mode 100644
index 0000000..a80657d
--- /dev/null
+++ b/Help/release/3.11.rst
@@ -0,0 +1,307 @@
+CMake 3.11 Release Notes
+************************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.10 include the following.
+
+New Features
+============
+
+Platforms
+---------
+
+* TI C/C++ compilers are now supported by the :generator:`Ninja` generator.
+
+Generators
+----------
+
+* The :generator:`CodeBlocks` extra generator learned to check a
+ :variable:`CMAKE_CODEBLOCKS_COMPILER_ID` variable for a custom
+ compiler identification value to place in the project file.
+
+* The :ref:`Makefile Generators` and the :generator:`Ninja` generator learned
+ to add compiler launcher tools along with the compiler for the ``Fortran``
+ language (``C``, ``CXX``, and ``CUDA`` were supported previously).
+ See the :variable:`CMAKE_<LANG>_COMPILER_LAUNCHER` variable and
+ :prop_tgt:`<LANG>_COMPILER_LAUNCHER` target property for details.
+
+* :ref:`Visual Studio Generators` learned to support the ``COMPILE_LANGUAGE``
+ :manual:`generator expression <cmake-generator-expressions(7)>` in
+ target-wide :prop_tgt:`COMPILE_DEFINITIONS`,
+ :prop_tgt:`INCLUDE_DIRECTORIES`, :prop_tgt:`COMPILE_OPTIONS`, and
+ :command:`file(GENERATE)`. See generator expression documentation
+ for caveats.
+
+* The :generator:`Xcode` generator learned to support the ``COMPILE_LANGUAGE``
+ :manual:`generator expression <cmake-generator-expressions(7)>` in
+ target-wide :prop_tgt:`COMPILE_DEFINITIONS` and
+ :prop_tgt:`INCLUDE_DIRECTORIES`. It previously supported only
+ :prop_tgt:`COMPILE_OPTIONS` and :command:`file(GENERATE)`.
+ See generator expression documentation for caveats.
+
+Commands
+--------
+
+* :command:`add_library` and :command:`add_executable` commands can now be
+ called without any sources and will not complain as long as sources are
+ added later via the :command:`target_sources` command.
+
+* The :command:`file(DOWNLOAD)` and :command:`file(UPLOAD)` commands
+ gained ``NETRC`` and ``NETRC_FILE`` options to specify use of a
+ ``.netrc`` file.
+
+* The :command:`target_compile_definitions` command learned to set the
+ :prop_tgt:`INTERFACE_COMPILE_DEFINITIONS` property on
+ :ref:`Imported Targets`.
+
+* The :command:`target_compile_features` command learned to set the
+ :prop_tgt:`INTERFACE_COMPILE_FEATURES` property on :ref:`Imported Targets`.
+
+* The :command:`target_compile_options` command learned to set the
+ :prop_tgt:`INTERFACE_COMPILE_OPTIONS` property on :ref:`Imported Targets`.
+
+* The :command:`target_include_directories` command learned to set the
+ :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` property on
+ :ref:`Imported Targets`.
+
+* The :command:`target_sources` command learned to set the
+ :prop_tgt:`INTERFACE_SOURCES` property on :ref:`Imported Targets`.
+
+* The :command:`target_link_libraries` command learned to set the
+ :prop_tgt:`INTERFACE_LINK_LIBRARIES` property on :ref:`Imported Targets`.
+
+Variables
+---------
+
+* A :variable:`CMAKE_GENERATOR_INSTANCE` variable was introduced
+ to hold the selected instance of the generator's corresponding
+ native tools if multiple are available. This is used by the
+ :generator:`Visual Studio 15 2017` generator to hold the
+ selected instance of Visual Studio persistently.
+
+* A :variable:`CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS` variable was added
+ to enable setting of default permissions for directories created implicitly
+ during installation of files by :command:`install` and
+ :command:`file(INSTALL)`, e.g. during ``make install``.
+
+* A :variable:`CMAKE_JOB_POOLS` variable was added specify a value to use for
+ the :prop_gbl:`JOB_POOLS` property. This enables control over build
+ parallelism with command line configuration parameters when using the Ninja
+ generator.
+
+* The :variable:`CMAKE_NETRC` and :variable:`CMAKE_NETRC_FILE` variables
+ were added to specify use of a ``.netrc`` file by the
+ :command:`file(DOWNLOAD)` and :command:`file(UPLOAD)` commands and
+ the :module:`ExternalProject` module.
+
+* A :variable:`CMAKE_CUDA_SEPARABLE_COMPILATION` variable was added to
+ initialize the :prop_tgt:`CUDA_SEPARABLE_COMPILATION` target property
+ on targets when they are created.
+
+Properties
+----------
+
+* The :prop_sf:`COMPILE_DEFINITIONS` source file property learned to support
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* A :prop_sf:`COMPILE_OPTIONS` source file property was added to manage list
+ of options to pass to the compiler.
+
+* An :prop_tgt:`IMPORTED_GLOBAL` target property was added to indicate
+ whether an :ref:`IMPORTED target <Imported Targets>` is globally visible.
+ It is automatically set to a true value for targets created with the
+ ``GLOBAL`` option to :command:`add_library` or :command:`add_executable`.
+ Additionally, project code may now *promote* a local imported target
+ to be globally visible by setting this property to ``TRUE``.
+
+* An :prop_sf:`INCLUDE_DIRECTORIES` source file property was added to specify
+ list of preprocessor include file search directories.
+
+* Source file properties :prop_sf:`VS_SHADER_DISABLE_OPTIMIZATIONS` and
+ :prop_sf:`VS_SHADER_ENABLE_DEBUG` have been added to specify more
+ details of ``.hlsl`` sources with :ref:`Visual Studio Generators`.
+
+Modules
+-------
+
+* The :module:`CheckIncludeFiles` module :command:`CHECK_INCLUDE_FILES`
+ command gained a ``LANGUAGE`` option to specify whether to check using the
+ ``C`` or ``CXX`` compiler.
+
+* The :module:`CMakePackageConfigHelpers` module
+ :command:`write_basic_package_version_file` command learned a new
+ ``SameMinorVersion`` mode for the ``COMPATIBILITY`` argument.
+
+* The :module:`ExternalProject` module learned to substitute ``<DOWNLOAD_DIR>``
+ in comments, commands, working directory and byproducts.
+
+* The :module:`ExternalProject` module gained ``NETRC`` and ``NETRC_FILE``
+ options to specify use of a ``.netrc`` file.
+
+* A new :module:`FetchContent` module was added which supports populating
+ content at configure time using any of the download/update methods
+ supported by :command:`ExternalProject_Add`. This allows the content
+ to be used immediately during the configure stage, such as with
+ :command:`add_subdirectory`, etc. Hierarchical project structures are
+ well supported, allowing parent projects to override the content details
+ of child projects and ensuring content is not populated multiple times
+ throughout the whole project tree.
+
+* The :module:`FindBLAS` and :module:`FindLAPACK` modules learned to support
+ `FLAME`_ ``blis`` and ``libflame``.
+
+* The :module:`FindDoxygen` module :command:`doxygen_add_docs` function
+ now supports a new ``DOXYGEN_VERBATIM_VARS`` list variable. Any
+ ``DOXYGEN_...`` variable contained in that list will bypass the automatic
+ quoting logic, leaving its contents untouched when transferring them to the
+ output ``Doxyfile``.
+
+* A :module:`FindIconv` module was added to locate iconv support.
+
+* The :module:`GenerateExportHeader` module ``GENERATE_EXPORT_HEADER`` command
+ gained an ``INCLUDE_GUARD_NAME`` option to change the name of the include
+ guard symbol written to the generated export header.
+ Additionally, it now adds a comment after the closing ``#endif`` on the
+ generated export header's include guard.
+
+* The :module:`UseJava` module ``add_jar`` command gained a
+ ``GENERATE_NATIVE_HEADERS`` option to generate native header files
+ using ``javac -h`` for ``javac`` 1.8 or above. This supersedes
+ ``create_javah``, which no longer works with JDK 1.10 and above due
+ to removal of the ``javah`` tool by `JEP 313`_.
+
+.. _`FLAME`: https://github.com/flame
+.. _`JEP 313`: http://openjdk.java.net/jeps/313
+
+Autogen
+-------
+
+* When using :prop_tgt:`AUTOMOC` or :prop_tgt:`AUTOUIC`, CMake now starts
+ multiple parallel ``moc`` or ``uic`` processes to reduce the build time.
+ A new :variable:`CMAKE_AUTOGEN_PARALLEL` variable and
+ :prop_tgt:`AUTOGEN_PARALLEL` target property may be set to specify the
+ number of parallel ``moc`` or ``uic`` processes to start. The default
+ is derived from the number of CPUs on the host.
+
+CTest
+-----
+
+* The :command:`ctest_start` command no longer sets
+ :variable:`CTEST_RUN_CURRENT_SCRIPT` due to issues with scoping if it is
+ called from inside a function. Instead, it sets an internal variable in
+ CTest. However, setting :variable:`CTEST_RUN_CURRENT_SCRIPT` to 0 at the
+ global scope still prevents the script from being re-run at the end.
+
+CPack
+-----
+
+* :manual:`cpack(1)` gained ``--trace`` and ``--trace-expand`` options.
+
+* The :cpack_gen:`CPack IFW Generator` gained new
+ :variable:`CPACK_IFW_PACKAGE_REMOVE_TARGET_DIR` variable to control
+ if the target directory should not be deleted when uninstalling.
+
+* The :cpack_gen:`CPack RPM Generator` learned to enable enforcing of execute
+ privileges on programs and shared libraries.
+ See :variable:`CPACK_RPM_INSTALL_WITH_EXEC` variable.
+
+* A :variable:`CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS` variable was added
+ which serves the same purpose during packaging (e.g. ``make package``) as the
+ :variable:`CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS` variable serves during
+ installation (e.g. ``make install``).
+
+Other
+-----
+
+* :ref:`Alias Targets` may now alias :ref:`Imported Targets` that are
+ created with the ``GLOBAL`` option to :command:`add_library`.
+
+* :ref:`Interface Libraries` may now have custom properties set on them if
+ they start with either an underscore (``_``) or a lowercase ASCII character.
+ The original intention was to only allow properties which made sense for
+ ``INTERFACE`` libraries, but it also blocked usage of custom properties.
+
+* The :manual:`cmake(1)` ``--open <dir>`` command-line option was added
+ to open generated IDE projects like Visual Studio solutions or Xcode
+ projects.
+
+Deprecated and Removed Features
+===============================
+
+* An explicit deprecation diagnostic was added for policies ``CMP0037``
+ through ``CMP0054`` (``CMP0036`` and below were already deprecated).
+ The :manual:`cmake-policies(7)` manual explains that the OLD behaviors
+ of all policies are deprecated and that projects should port to the
+ NEW behaviors.
+
+* The ``KDevelop3`` generator has been removed.
+
+Other Changes
+=============
+
+* Policy :policy:`CMP0037` no longer reserves target names associated
+ with optional features, such as ``test`` and ``package``, unless
+ the corresponding feature is enabled.
+
+* The :module:`FindOpenGL` module now prefers GLVND libraries if available.
+ See policy :policy:`CMP0072`.
+
+* The minimum deployment target set in the
+ :variable:`CMAKE_OSX_DEPLOYMENT_TARGET` variable used to be only
+ applied for macOS regardless of the selected SDK. It is now properly
+ set for the target platform selected by :variable:`CMAKE_OSX_SYSROOT`.
+ For example, if the sysroot variable specifies an iOS SDK then the
+ value in ``CMAKE_OSX_DEPLOYMENT_TARGET`` is interpreted as minimum
+ iOS version.
+
+* The :generator:`Xcode` generator behavior of generating one project
+ file per :command:`project()` command may now be controlled with the
+ :variable:`CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY` variable.
+ This could be useful to speed up the CMake generation step for
+ large projects and to work-around a bug in the ``ZERO_CHECK`` logic.
+
+* Since the ``CMakeCache.txt`` format does not support newlines in values,
+ values containing newlines are now truncated before writing to the file.
+ In addition, a warning comment is written to the cache file, and a warning
+ message is displayed to the user on the console.
+
+Updates
+=======
+
+Changes made since CMake 3.11.0 include the following.
+
+3.11.1
+------
+
+* The :module:`CheckIncludeFile` module ``check_include_file`` macro,
+ :module:`CheckIncludeFileCXX` module ``check_include_file_cxx`` macro,
+ and :module:`CheckIncludeFiles` module ``check_include_files`` macro
+ were taught to honor the ``CMAKE_REQUIRED_LIBRARIES`` variable in
+ CMake 3.11.0. This has been reverted due to changing behavior of
+ checks for existing projects. It may be restored in the future
+ with a policy for compatibility.
+
+3.11.2
+------
+
+* Calling :command:`add_library` to create an alias of an imported
+ target that is not globally visible now causes an error again as
+ it did prior to 3.11.0. This diagnostic was accidentally dropped
+ from CMake 3.11.0 and 3.11.1 by the change to allow globally visible
+ imported targets to be aliased.
+
+* The :module:`FindQt4` module ``qt4_wrap_cpp``, ``qt4_wrap_ui`` and
+ ``qt4_add_resources`` macros now set :prop_sf:`SKIP_AUTOMOC` and
+ :prop_sf:`SKIP_AUTOUIC` on their generated files. These files never
+ need to be processed by moc or uic, and we must say so explicitly to
+ account for policy :policy:`CMP0071`.
+
+3.11.3
+------
+
+* CMake 3.11.0 introduced support for resolving symbolic links on
+ Windows in code paths that typically do so on UNIX. This has been
+ reverted due to breakage on ``subst`` drives.
diff --git a/Help/release/3.12.rst b/Help/release/3.12.rst
new file mode 100644
index 0000000..481027e
--- /dev/null
+++ b/Help/release/3.12.rst
@@ -0,0 +1,305 @@
+CMake 3.12 Release Notes
+************************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.11 include the following.
+
+New Features
+============
+
+Generators
+----------
+
+* The :ref:`Visual Studio Generators` for VS 2017 learned to support a
+ ``version=14.##`` option in the :variable:`CMAKE_GENERATOR_TOOLSET`
+ value (e.g. via the :manual:`cmake(1)` ``-T`` option) to specify a
+ toolset version number.
+
+Command-Line
+------------
+
+* The :manual:`cmake(1)` :ref:`Build Tool Mode` (``cmake --build``) gained
+ ``--parallel [<jobs>]`` and ``-j [<jobs>]`` options to specify a parallel
+ build level. They map to corresponding options of the native build tool.
+
+Commands
+--------
+
+* The :command:`add_compile_definitions` command was added to set preprocessor
+ definitions at directory level. This supersedes :command:`add_definitions`.
+
+* The :command:`cmake_minimum_required` and :command:`cmake_policy(VERSION)`
+ commands now accept a version range using the form ``<min>[...<max>]``.
+ The ``<min>`` version is required but policies are set based on the
+ older of the running CMake version and the version specified by
+ ``<max>``. This allows projects to specify a range of versions
+ for which they have been updated and avoid explicit policy settings.
+
+* The :command:`file(GLOB)` and :command:`file(GLOB_RECURSE)` commands
+ learned a new flag ``CONFIGURE_DEPENDS`` which enables expression of
+ build system dependency on globbed directory's contents.
+
+* The :command:`file(TOUCH)` and :command:`file(TOUCH_NOCREATE)` commands
+ were added to expose ``TOUCH`` functionality without having to use
+ CMake's command-line tool mode with :command:`execute_process`.
+
+* The :command:`find_package` command now searches prefixes specified by
+ the :variable:`<PackageName>_ROOT` CMake variable and the
+ :envvar:`<PackageName>_ROOT` environment variable. Package roots are
+ maintained as a stack so nested calls to all ``find_*`` commands inside
+ find modules also search the roots as prefixes.
+ See policy :policy:`CMP0074`.
+
+* The :command:`install` command learned an optional ``NAMELINK_COMPONENT``
+ parameter, which allows you to change the component for a shared library's
+ namelink. If none is specified, the value of ``COMPONENT`` is used by
+ default.
+
+* The :command:`list` command learned a ``JOIN`` sub-command
+ to concatenate list's elements separated by a glue string.
+
+* The :command:`list` command learned a ``SUBLIST`` sub-command
+ to get a sublist of the list.
+
+* The :command:`list` command learned a ``TRANSFORM`` sub-command
+ to apply various string transformation to list's elements.
+
+* The :command:`project` command learned an optional ``HOMEPAGE_URL``
+ parameter which has the effect of setting variables like
+ :variable:`PROJECT_HOMEPAGE_URL`, :variable:`<PROJECT-NAME>_HOMEPAGE_URL`
+ and :variable:`CMAKE_PROJECT_HOMEPAGE_URL`.
+
+* The :command:`string` command learned a ``JOIN`` sub-command
+ to concatenate input strings separated by a glue string.
+
+* :command:`target_compile_options` and :command:`add_compile_options`
+ commands gained a ``SHELL:`` prefix to specify a group of related
+ options using shell-like quoting.
+
+* The :command:`target_link_libraries` command now supports
+ :ref:`Object Libraries`. Linking to an object library uses its object
+ files in direct dependents and also propagates usage requirements.
+
+Variables
+---------
+
+* The :variable:`CMAKE_FOLDER` variable was added to initialize the
+ :prop_tgt:`FOLDER` property on all targets.
+
+* The :variable:`CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION` variable
+ was defined to initialize all
+ :prop_tgt:`DOTNET_TARGET_FRAMEWORK_VERSION` target properties.
+
+* ``CMAKE_PROJECT_VERSION*`` variables have been introduced:
+
+ - :variable:`CMAKE_PROJECT_VERSION`
+ - :variable:`CMAKE_PROJECT_VERSION_MAJOR`
+ - :variable:`CMAKE_PROJECT_VERSION_MINOR`
+ - :variable:`CMAKE_PROJECT_VERSION_PATCH`
+ - :variable:`CMAKE_PROJECT_VERSION_TWEAK`
+
+* The :variable:`CMAKE_SUPPRESS_REGENERATION` variable was extended to
+ support the :generator:`Ninja` and :ref:`Makefile Generators`.
+ It is also now documented.
+
+* ``CMAKE_VS_SDK_*_DIRECTORIES`` variables were defined to tell
+ :ref:`Visual Studio Generators` for VS 2010 and above how to populate
+ fields in ``.vcxproj`` files that specify SDK directories. The
+ variables are:
+
+ - :variable:`CMAKE_VS_SDK_EXCLUDE_DIRECTORIES`
+ - :variable:`CMAKE_VS_SDK_EXECUTABLE_DIRECTORIES`
+ - :variable:`CMAKE_VS_SDK_INCLUDE_DIRECTORIES`
+ - :variable:`CMAKE_VS_SDK_LIBRARY_DIRECTORIES`
+ - :variable:`CMAKE_VS_SDK_LIBRARY_WINRT_DIRECTORIES`
+ - :variable:`CMAKE_VS_SDK_REFERENCE_DIRECTORIES`
+ - :variable:`CMAKE_VS_SDK_SOURCE_DIRECTORIES`
+
+* A :variable:`MSVC_TOOLSET_VERSION` variable was added to provide the
+ MSVC toolset version associated with the current MSVC compiler version
+ in :variable:`MSVC_VERSION`.
+
+Properties
+----------
+
+* The :prop_tgt:`COMMON_LANGUAGE_RUNTIME` target property was introduced
+ to configure the use of managed C++ for :ref:`Visual Studio Generators`
+ for VS 2010 and above.
+ A corresponding :prop_tgt:`IMPORTED_COMMON_LANGUAGE_RUNTIME` target
+ property was added to support ``C++/CLI`` for imported targets.
+
+* The :prop_tgt:`DOTNET_TARGET_FRAMEWORK_VERSION` target property
+ was introduced as replacement for
+ :prop_tgt:`VS_DOTNET_TARGET_FRAMEWORK_VERSION`, which is considered
+ deprecated now.
+
+* An :prop_tgt:`EXPORT_PROPERTIES` target property was added to specify a
+ custom list of target properties to include in targets exported by the
+ :command:`install(EXPORT)` and :command:`export` commands.
+
+* The :prop_tgt:`PDB_OUTPUT_DIRECTORY` property learned to support
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* A :prop_dir:`TESTS` directory property was added to hold the list of
+ tests defined by the :command:`add_test` command.
+
+* A :prop_tgt:`VS_DEBUGGER_COMMAND` target property was created to set the
+ debugging command line with :ref:`Visual Studio Generators` for VS 2010
+ and above.
+
+* HLSL source file properties :prop_sf:`VS_SHADER_DISABLE_OPTIMIZATIONS`
+ and :prop_sf:`VS_SHADER_ENABLE_DEBUG` gained support for generator
+ expressions.
+
+* HLSL source file property :prop_sf:`VS_SHADER_OBJECT_FILE_NAME` has been
+ added to the :ref:`Visual Studio Generators` for VS 2010 and above.
+ The property specifies the file name of the compiled shader object.
+
+Modules
+-------
+
+* The :module:`FindALSA` module now provides imported targets.
+
+* The :module:`FindCURL` module now provides imported targets.
+
+* The :module:`FindJPEG` module now provides imported targets.
+
+* The :module:`FindLibXml2` module now provides imported targets.
+
+* The :module:`FindMatlab` module now supports the Matlab Runtime
+ Compiler (MCR) for compiling and linking matlab extensions.
+
+* A :module:`FindODBC` module was added to find an Open Database Connectivity
+ (ODBC) library.
+
+* The :module:`FindPkgConfig` module has learned to export the found
+ libraries with full path for direct consumption with the
+ :command:`target_link_libraries` command.
+
+* New :module:`FindPython3` and :module:`FindPython2` modules, as well as
+ a new :module:`FindPython` module, have been added to provide a new way
+ to locate python environments.
+
+* The :module:`UseSWIG` module gained a whole refresh and is now more
+ consistent with standard CMake commands to generate libraries and is
+ fully configurable through properties.
+
+* The :module:`UseSWIG` module learned to manage multiple behaviors through
+ ``UseSWIG_MODULE_VERSION`` variable to ensure legacy support as well as more
+ robust handling of ``SWIG`` advanced features (like ``%template``).
+
+* The :module:`UseSWIG` module learned to support CSHARP variant
+ wrapper files.
+
+* The :module:`WriteCompilerDetectionHeader` module gained a ``BARE_FEATURES``
+ option to add a compatibility define for the exact keyword of a new language
+ feature.
+
+Generator Expressions
+---------------------
+
+* A new ``$<GENEX_EVAL:...>`` and ``$<TARGET_GENEX_EVAL:target,...>``
+ :manual:`generator expression <cmake-generator-expressions(7)>`
+ has been added to enable consumption of generator expressions whose
+ evaluation results itself in generator expressions.
+
+* A new ``$<IN_LIST:...>``
+ :manual:`generator expression <cmake-generator-expressions(7)>`
+ has been added.
+
+* A new ``$<TARGET_EXISTS:...>``
+ :manual:`generator expression <cmake-generator-expressions(7)>`
+ has been added.
+
+* A new ``$<TARGET_NAME_IF_EXISTS:...>``
+ :manual:`generator expression <cmake-generator-expressions(7)>`
+ has been added.
+
+CTest
+-----
+
+* The :command:`ctest_start` command has been reworked so that you can simply
+ call ``ctest_start(APPEND)`` and it will read all the needed information from
+ the TAG file. The argument parsing has also been relaxed so that the order of
+ the arguments is less significant.
+
+* A :prop_test:`PROCESSOR_AFFINITY` test property was added to request
+ that CTest run a test with CPU affinity for a set of processors
+ disjoint from other concurrently running tests with the property set.
+
+CPack
+-----
+
+* The :module:`CPack` module now uses variables
+ :variable:`CMAKE_PROJECT_VERSION_MAJOR`,
+ :variable:`CMAKE_PROJECT_VERSION_MINOR` and
+ :variable:`CMAKE_PROJECT_VERSION_PATCH`
+ to initialize corresponding CPack variables.
+
+* A :cpack_gen:`CPack NuGet Generator` was was added with basic
+ support for `NuGet`_.
+
+.. _NuGet: https://docs.microsoft.com/en-us/nuget/what-is-nuget
+
+Other
+-----
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ is now aware of C++ 20. No specific features are yet enumerated besides
+ the ``cxx_std_20`` meta-feature.
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ is now aware of the availability of C features in MSVC since VS 2010.
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ is now aware of C language standards supported by Texas Instruments C
+ compilers.
+
+Deprecated and Removed Features
+===============================
+
+* The :generator:`Visual Studio 8 2005` generator has been removed.
+
+* CMake no longer produces ``<tgt>_LIB_DEPENDS`` cache entries
+ for library targets. See policy :policy:`CMP0073`.
+
+Other Changes
+=============
+
+* Include flags for directories marked as ``SYSTEM`` are now moved after
+ non-system directories. The ``-isystem`` flag does this automatically,
+ so moving them explicitly to the end makes the behavior consistent on
+ compilers that do not have any ``-isystem`` flag.
+
+* Fortran dependency scanning now supports dependencies implied by
+ `Fortran Submodules`_.
+
+* The existence and functionality of the file
+ ``${CMAKE_BINARY_DIR}/cmake_install.cmake`` has now been documented in the
+ :command:`install` documentation so that external packaging software can take
+ advantage of CPack-style component installs.
+
+* The :module:`CheckIncludeFile` module ``check_include_file`` macro
+ learned to honor the ``CMAKE_REQUIRED_LIBRARIES`` variable.
+ See policy :policy:`CMP0075`.
+
+* The :module:`CheckIncludeFileCXX` module ``check_include_file_cxx`` macro
+ learned to honor the ``CMAKE_REQUIRED_LIBRARIES`` variable.
+ See policy :policy:`CMP0075`.
+
+* The :module:`CheckIncludeFiles` module ``check_include_files`` macro
+ learned to honor the ``CMAKE_REQUIRED_LIBRARIES`` variable.
+ See policy :policy:`CMP0075`.
+
+* The :manual:`cmake(1)` ``-E copy_directory`` tool now fails when the
+ source directory does not exist. Previously it succeeded by creating
+ an empty destination directory.
+
+* The :module:`UseSWIG` module :command:`swig_add_library` command
+ (and legacy ``swig_add_module`` command) now set the prefix of
+ Java modules to ``""`` for MINGW, MSYS, and CYGWIN environments.
+
+.. _`Fortran Submodules`: http://fortranwiki.org/fortran/show/Submodules
diff --git a/Help/release/3.13.rst b/Help/release/3.13.rst
new file mode 100644
index 0000000..a8dd0ba
--- /dev/null
+++ b/Help/release/3.13.rst
@@ -0,0 +1,289 @@
+CMake 3.13 Release Notes
+************************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.12 include the following.
+
+New Features
+============
+
+Generators
+----------
+
+* The :ref:`Visual Studio Generators` for VS 2010 and above learned to
+ support the :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` target property
+ and supporting :module:`CheckIPOSupported` module.
+
+* The :generator:`Xcode` generator learned to configure more Xcode Scheme
+ fields. See the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable.
+
+* The :generator:`Green Hills MULTI` generator has been updated:
+
+ - Added support for architecture selection through
+ :variable:`CMAKE_GENERATOR_PLATFORM`:
+ e.g. ``arm``, ``ppc``, and ``86``.
+
+ - Added support for toolset selection through
+ :variable:`CMAKE_GENERATOR_TOOLSET`,
+ e.g. ``comp_201205``, ``comp_201510``, ``comp_201722_beta``.
+
+ - Added support for platform selection through ``GHS_TARGET_PLATFORM``,
+ e.g. ``integrity``, ``linux``, ``standalone``, etc.
+
+ - No longer checks that ``arm`` based compilers are installed but ensures
+ that the correct ``gbuild.exe`` exists.
+
+ - No longer hard-codes ARM files, BSP, toolset, or OS locations.
+
+Command-Line
+------------
+
+* The :manual:`cmake(1)` command gained the ``-S <source_dir>``
+ command line option to specify the location of the source directory.
+ This option can be used independently of ``-B``.
+
+* The :manual:`cmake(1)` command gained the ``-B <build_dir>``
+ command line option to specify the location of the build directory.
+ This option can be used independently of ``-S``.
+
+* The :manual:`cmake(1)` ``-E create_symlink`` command can now be used
+ on Windows.
+
+Commands
+--------
+
+* The :command:`add_custom_command` and :command:`add_custom_target` commands
+ learned to support generator expressions in ``WORKING_DIRECTORY`` options.
+
+* The :command:`add_link_options` command was created to add link
+ options in the current directory.
+
+* The :command:`install(TARGETS)` command learned to install targets
+ created outside the current directory.
+
+* The :command:`link_directories` command gained options to control
+ insertion position.
+
+* The :command:`list(SORT)` command gained options to control the
+ comparison operation used to order the entries.
+
+* The :command:`math` command gained options for hexadecimal.
+
+* The :command:`target_link_directories` command was created to
+ specify link directories for targets and their dependents.
+
+* The :command:`target_link_options` command was created to
+ specify link options for targets and their dependents.
+
+* The :command:`target_link_libraries` command may now be called
+ to modify targets created outside the current directory.
+ See policy :policy:`CMP0079`.
+
+Variables
+---------
+
+* A :variable:`CMAKE_AUTOGEN_VERBOSE` variable was added to optionally
+ increase the verbosity of :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTOUIC`
+ and :prop_tgt:`AUTORCC` from within CMake project code.
+
+* A :variable:`CMAKE_VS_GLOBALS` variable was added to initialize
+ :prop_tgt:`VS_GLOBAL_<variable>` target properties on targets as
+ they are created.
+
+Properties
+----------
+
+* The :prop_tgt:`DEPLOYMENT_ADDITIONAL_FILES` target property was
+ added to tell the :generator:`Visual Studio 9 2008` generator
+ to specify additional files for deployment to WinCE devices
+ for remote debugging.
+
+* The :prop_tgt:`INTERFACE_LINK_DEPENDS` target property was created
+ to specify transitive link dependencies on files.
+
+* The :prop_tgt:`LINK_DEPENDS` target property learned to support
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* :prop_tgt:`LINK_DIRECTORIES` and :prop_tgt:`INTERFACE_LINK_DIRECTORIES`
+ target properties were added to collect link directories for a target
+ and its dependents. Use the :command:`target_link_directories` command
+ to set them.
+
+* :prop_tgt:`LINK_OPTIONS` and :prop_tgt:`INTERFACE_LINK_OPTIONS` target
+ properties were added to collect link options for a target and its
+ dependents. Use the :command:`target_link_options` command to set them.
+
+* A :prop_dir:`LINK_OPTIONS` directory property was added to collect
+ link options for targets created under the current directory.
+ Use the :command:`add_link_options` command to set it.
+
+* A :prop_tgt:`STATIC_LIBRARY_OPTIONS` target property was created
+ to specify archiver options to use when creating static libraries.
+
+* A :prop_tgt:`VS_DEBUGGER_COMMAND_ARGUMENTS` target property was created to
+ set the debugging command line arguments with
+ :ref:`Visual Studio Generators` for VS 2010 and above.
+
+* A :prop_tgt:`VS_DEBUGGER_ENVIRONMENT` target property was created to
+ set the debugging environment with
+ :ref:`Visual Studio Generators` for VS 2010 and above.
+
+* The :prop_tgt:`VS_DEBUGGER_COMMAND` and
+ :prop_tgt:`VS_DEBUGGER_WORKING_DIRECTORY` target properties
+ now support generator expressions.
+
+Modules
+-------
+
+* The :module:`FindBoost` module gained a ``Boost_ARCHITECTURE`` option
+ to specify a Boost architecture-specific library filename fragment.
+
+* The :module:`FindCURL` module learned to find debug and release variants
+ separately.
+
+* The :module:`FindMatlab` module gained new components ``ENGINE_LIBRARY`` and
+ ``DATAARRAY_LIBRARY`` to request finding the Matlab C++ Engine and DataArray
+ libraries respectively.
+
+* The :module:`FindMatlab` module now explicitly exports mexFunction in Visual
+ Studio.
+
+* The :module:`FindMatlab` module gained a new ``MCC_COMPILER``
+ component to request finding the Matlab Compiler add-on.
+
+* The :module:`FindPkgConfig` module gained an option to create imported
+ targets in global scope.
+
+* The :module:`FindPkgConfig` module gained support for ``<`` and ``>``
+ operators for version checks in addition to the already supported
+ operators ``>=``, ``<=``, and ``=``.
+
+* Modules :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+ gain capability to control order of resource lookup on macOS (Framework) and
+ Windows (Registry).
+
+* The :module:`FindSubversion` module ``Subversion_WC_INFO`` command
+ gained an ``IGNORE_SVN_FAILURE`` option to suppress failures,
+ e.g. when the source tree is not under Subversion control.
+
+* The :module:`UseSWIG` module learned to manage target property
+ :prop_tgt:`INCLUDE_DIRECTORIES` for ``SWIG`` compilation.
+
+CTest
+-----
+
+* :manual:`ctest(1)` gained a ``--progress`` option to enable a live
+ test progress summary when output goes to a terminal.
+
+CPack
+-----
+
+* The :cpack_gen:`CPack DEB Generator` learned to split debug symbols into
+ a corresponding .ddeb package when ``CPACK_DEBIAN_DEBUGINFO_PACKAGE`` is
+ set.
+
+* The :cpack_gen:`CPack DEB Generator` learned to honor the ``SOURCE_DATE_EPOCH``
+ environment variable when packaging files. This is useful for generating
+ reproducible packages.
+
+* CPack gained a new :cpack_gen:`CPack External Generator` which is used to
+ export the CPack metadata in a format that other software can understand. The
+ intention of this generator is to allow external packaging software to take
+ advantage of CPack's features when it may not be possible to use CPack for
+ the entire packaging process.
+
+Deprecated and Removed Features
+===============================
+
+* An explicit deprecation diagnostic was added for policies ``CMP0055``
+ through ``CMP0063`` (``CMP0054`` and below were already deprecated).
+ The :manual:`cmake-policies(7)` manual explains that the OLD behaviors
+ of all policies are deprecated and that projects should port to the
+ NEW behaviors.
+
+Other Changes
+=============
+
+* The precompiled binaries provided on ``cmake.org`` now include
+ qthelp-format documentation.
+
+* The :command:`option` command now honors an existing normal variable
+ of the same name and does nothing instead of possibly creating a cache
+ entry (or setting its type) and removing the normal variable.
+ See policy :policy:`CMP0077`.
+
+* The :ref:`Makefile Generators` learned to remove custom command and
+ custom target byproducts during ``make clean``.
+
+* The :command:`target_sources` command now interprets relative source file
+ paths as relative to the current source directory. This simplifies
+ incrementally building up a target's sources from subdirectories. The
+ :policy:`CMP0076` policy was added to provide backward compatibility with
+ the old behavior where required.
+
+* The :module:`BundleUtilities` module may no longer be included at configure
+ time. This was always a bug anyway. See policy :policy:`CMP0080`.
+
+* The :module:`UseSWIG` module has changed strategy for target naming.
+ See policy :policy:`CMP0078`.
+
+* The :prop_tgt:`LINK_DIRECTORIES` target property now expects absolute paths.
+ See policy :policy:`CMP0081`.
+
+* The CPack generators have been moved into their own separate section
+ in the documentation, rather than having the documentation in their
+ internal implementation modules.
+ These internal implementation modules are also no longer available
+ to scripts that may have been incorrectly including them, because
+ they should never have been available in the first place.
+
+Updates
+=======
+
+Changes made since CMake 3.13.0 include the following.
+
+3.13.2
+------
+
+* CMake 3.13.0 included a change to pass compiler implicit include
+ directories to the ``moc`` tool for :prop_tgt:`AUTOMOC`. This has
+ been reverted due to regressing existing builds and will need
+ further investigation before being re-introduced in a later release.
+
+3.13.3
+------
+
+* The :generator:`Visual Studio 15 2017` generator has been fixed to work
+ when VS 2019 is installed.
+
+* CMake now checks that at least one of the source or binary directory
+ is specified when running CMake and issues an error if both are missing.
+ This has always been a documented requirement, but the implementation
+ previously accidentally accepted cases in which neither are specified
+ so long as some other argument is given, and silently used the current
+ working directory as the source and build tree.
+
+3.13.4
+------
+
+* The error added by 3.13.3 in cases that neither a source or binary
+ directory is specified has been downgraded to a warning. While this
+ was never intended, documented, nor supported behavior, some projects
+ relied on it. The error has been downgraded to a warning for the
+ remainder of the 3.13.x release series to allow a transition period,
+ but it may become a fatal error again in a later release. Scripts
+ relying on the old behavior can be trivially fixed by specifying
+ the path to the source tree (even if just ``.``) explicitly and
+ continue to work with all versions of CMake.
+
+3.13.5
+------
+
+* In CMake 3.13.0 through 3.13.4, calling :command:`target_link_libraries`
+ to add ``PRIVATE`` dependencies to a static library created in another
+ directory (under policy :policy:`CMP0079` ``NEW`` behavior) would
+ incorrectly propagate usage requirements of those dependencies to
+ dependents that link the static library. This has been fixed.
diff --git a/Help/release/3.14.rst b/Help/release/3.14.rst
new file mode 100644
index 0000000..8a9738c
--- /dev/null
+++ b/Help/release/3.14.rst
@@ -0,0 +1,438 @@
+CMake 3.14 Release Notes
+************************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.13 include the following.
+
+New Features
+============
+
+Generators
+----------
+
+* The :generator:`Visual Studio 16 2019` generator was added. This is
+ experimental and based on "Visual Studio 2019 Preview 4" because this
+ version of VS has not been released.
+
+ The VS 2019 generator differs from generators for earlier versions
+ in that it does not provide variants that specify the target platform
+ in the generator name. Instead :variable:`CMAKE_GENERATOR_PLATFORM`
+ must be used, e.g. through the ``-A`` command-line option. Furthermore,
+ the default target platform (architecture) is now based on the *host*
+ platform. The VS host toolset selection is now based on the host
+ architecture as well.
+
+* The :generator:`Green Hills MULTI` generator has been updated:
+
+ * Now supports :ref:`Object Libraries`.
+
+ * Now warns on unsupported project types such as shared libraries.
+
+ * Now generates a top-level ``<PROJECT-NAME>.top.gpj`` for each directory
+ calling the :command:`project` command. The top-level project file
+ ``default.gpj`` is no longer created.
+
+ * Now honors target renaming and destination output control properties
+ such as :prop_tgt:`RUNTIME_OUTPUT_DIRECTORY` and :prop_tgt:`OUTPUT_NAME`.
+ This also fixes support for installation rules generated by
+ :command:`install`.
+
+ * Now honors source file properties :prop_sf:`INCLUDE_DIRECTORIES`,
+ :prop_sf:`COMPILE_DEFINITIONS`, and :prop_sf:`COMPILE_OPTIONS`.
+
+ * Now supports Dynamic Download Integrity Applications which did not include
+ Integrate Files via :prop_tgt:`GHS_INTEGRITY_APP` and setting a target
+ link flag of ``-dynamic``.
+
+ * The contents of project files now sorts sources groups and files by name.
+ Set the :prop_tgt:`GHS_NO_SOURCE_GROUP_FILE` target property to ``ON`` to
+ generate a single project file for the target instead of a project file for
+ each source group. Set the :variable:`CMAKE_GHS_NO_SOURCE_GROUP_FILE`
+ variable to enable this for all targets.
+
+File-Based API
+--------------
+
+* A file-based api for clients to get semantic buildsystem information
+ has been added. See the :manual:`cmake-file-api(7)` manual.
+ This is intended to replace the :manual:`cmake-server(7)` mode for IDEs.
+
+Platforms
+---------
+
+* CMake now supports :ref:`Cross Compiling for iOS, tvOS, or watchOS`
+ using simple toolchain files.
+
+Command-Line
+------------
+
+* The :manual:`cmake(1)` :ref:`Build Tool Mode <Build Tool Mode>`
+ (``cmake --build``) gained ``--verbose`` and ``-v`` options to
+ specify verbose build output. Some generators such as Xcode don't
+ support this option currently.
+
+* The :manual:`cmake(1)` ``-E compare_files`` command learned a new
+ ``--ignore-eol`` option to specify that end-of-line differences
+ (e.g. LF vs CRLF) should be ignored when comparing files.
+
+* The :manual:`cmake-gui(1)` dialog gained new ``-S`` and ``-B`` arguments to
+ explicitly specify source and build directories.
+
+Commands
+--------
+
+* The :command:`file` command learned a new sub-command, ``CREATE_LINK``,
+ which can be used to create hard or symbolic links.
+
+* The :command:`file` command learned a new sub-command, ``READ_SYMLINK``,
+ which can be used to determine the path that a symlink points to.
+
+* The :command:`file` command gained a ``SIZE`` mode to get the size
+ of a file on disk.
+
+* The :command:`find_package` command learned to optionally resolve
+ symbolic links in the paths to package configuration files.
+ See the :variable:`CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS` variable.
+
+* The :command:`get_filename_component` command gained new
+ ``LAST_EXT`` and ``NAME_WLE`` variants to work with the
+ extension after the last ``.`` in the name.
+
+* The :command:`if` command gained support for checking if cache variables
+ are defined with the ``DEFINED CACHE{VAR}`` syntax.
+
+* The :command:`install(CODE)` and :command:`install(SCRIPT)` commands
+ learned to support generator expressions. See policy :policy:`CMP0087`.
+
+* The :command:`install(TARGETS)` command learned how to install to an
+ appropriate default directory for a given target type, based on
+ variables from the :module:`GNUInstallDirs` module and built-in defaults,
+ in lieu of a ``DESTINATION`` argument.
+
+* The :command:`install(FILES)` and :command:`install(DIRECTORY)` commands
+ learned a new set of parameters for installing files as a file type,
+ setting the destination based on the appropriate variables from
+ :module:`GNUInstallDirs` and built-in defaults, in lieu of a
+ ``DESTINATION`` argument.
+
+* The :command:`list` operations ``REMOVE_ITEM``, ``REMOVE_DUPLICATES``,
+ ``SORT``, ``REVERSE``, and ``FILTER`` all now accept a non-existent variable
+ as the list since these operations on empty lists is also the empty list.
+
+* The :command:`list` operation ``REMOVE_AT`` now indicates that the given
+ indices are invalid for a non-existent variable or empty list.
+
+* The :command:`try_compile` and :command:`try_run` commands gained a new
+ ``LINK_OPTIONS`` option.
+
+Variables
+---------
+
+* A :variable:`CMAKE_BUILD_RPATH_USE_ORIGIN` variable and corresponding
+ :prop_tgt:`BUILD_RPATH_USE_ORIGIN` target property were added to
+ enable use of relative runtime paths (RPATHs). This helps achieving
+ relocatable and reproducible builds that are invariant of the build
+ directory.
+
+* A :variable:`CMAKE_VS_PLATFORM_NAME_DEFAULT` variable was added for
+ :ref:`Visual Studio Generators` to report their default platform used
+ when :variable:`CMAKE_GENERATOR_PLATFORM` is not set explicitly.
+
+Properties
+----------
+
+* A :prop_gbl:`CMAKE_ROLE` global property was added to allow scripts to
+ determine whether they're running in project mode, script mode,
+ find-package mode, CTest, or CPack.
+
+* The :prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` target property is now supported
+ on shared library, module library, and executable targets. Previously it was
+ only honored on static libraries.
+
+* The :prop_tgt:`EXCLUDE_FROM_ALL` target property was created to override
+ the setting of its directory. A target will now be built as part of "all"
+ if its :prop_tgt:`EXCLUDE_FROM_ALL` property is set to ``OFF``, even if its
+ containing directory is marked as :prop_dir:`EXCLUDE_FROM_ALL`.
+
+* :prop_tgt:`INTERFACE_POSITION_INDEPENDENT_CODE` target property gains the
+ support of :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+Modules
+-------
+
+* The family of modules to check capabilities (like
+ :module:`CheckCSourceCompiles`) gain capability to manage ``LINK_OPTIONS``.
+
+* A :module:`CheckFortranSourceRuns` module was added to provide a
+ :command:`check_fortran_source_runs` command to check if a Fortran
+ source snippet compiles and runs.
+
+* The :module:`CMakePackageConfigHelpers` module's
+ :command:`write_basic_package_version_file` command gained a new
+ ``ARCH_INDEPENDENT`` option for supporting architecture-independent
+ packages.
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add` command
+ gained ``LOG_DIR`` and ``LOG_MERGED_STDOUTERR`` options to control logging.
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add` command
+ gained ``LOG_PATCH`` to optionally log the patch step.
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add` command
+ learned to apply ``SOURCE_SUBDIR`` when ``BUILD_IN_SOURCE`` is also used.
+ The ``BUILD_COMMAND`` is run in the given ``SOURCE_SUBDIR`` of the
+ ``SOURCE_DIR``.
+
+* The :module:`FetchContent` module gained a new
+ :command:`FetchContent_MakeAvailable` command. It accepts a list of
+ dependency names, which it then iterates over, populating and adding
+ each one to the main build using the canonical pattern. This
+ significantly reduces the amount of boilerplate needed in a project.
+
+* The :module:`FindBISON` module's ``BISON_TARGET`` command now runs ``bison``
+ with :variable:`CMAKE_CURRENT_BINARY_DIR` as the working directory.
+ See policy :policy:`CMP0088`.
+
+* The :module:`FindCURL` module gained support for requesting
+ protocols as package components.
+
+* The :module:`FindFontconfig` module was added to find `fontconfig`_.
+
+* The :module:`FindGDAL` module now provides imported targets.
+
+* The :module:`FindGIF` module now provides imported targets.
+
+* The :module:`FindGit` module now provides an imported target for the
+ Git executable.
+
+* The :module:`FindIce` module learned to find ``slice2confluence``
+ and ``slice2matlab``.
+
+* The :module:`FindLibinput` module was added to find `libinput`_.
+
+* The :module:`FindLibLZMA` module now provides imported targets.
+
+* The :module:`FindMatlab` module gained new options ``R2017b`` and
+ ``R2018a`` to specify the MEX API version to use; these options
+ mirror the new options to the ``mex`` command in MATLAB R2018a.
+ The option ``MX_LIBRARY`` is no longer needed.
+
+* The :module:`FindPostgreSQL` module now provides imported targets.
+
+* The :module:`FindPython`, :module:`FindPython2`, and :module:`FindPython3`
+ modules gained support for ``NumPy`` component.
+
+* The :module:`FindPython2`, :module:`FindPython3`, and :module:`FindPython`
+ modules now support running in script mode by skipping the creation of
+ imported targets and helper functions.
+
+* The :module:`FindSQLite3` module was added to find the SQLite v3.x library.
+
+* The :module:`FindX11` had the following variables renamed in order to match
+ their library names rather than header names. The old variables are provided
+ for compatibility:
+
+ - ``X11_Xxf86misc_INCLUDE_PATH`` instead of ``X11_xf86misc_INCLUDE_PATH``
+ - ``X11_Xxf86misc_LIB`` instead of ``X11_xf86misc_LIB``
+ - ``X11_Xxf86misc_FOUND`` instead of ``X11_xf86misc_FOUND``
+ - ``X11_Xxf86vm_INCLUDE_PATH`` instead of ``X11_xf86vmode_INCLUDE_PATH``
+ - ``X11_Xxf86vm_LIB`` instead of ``X11_xf86vmode_LIB``
+ - ``X11_Xxf86vm_FOUND`` instead of ``X11_xf86vmode_FOUND``
+ - ``X11_xkbfile_INCLUDE_PATH`` instead of ``X11_Xkbfile_INCLUDE_PATH``
+ - ``X11_xkbfile_LIB`` instead of ``X11_Xkbfile_LIB``
+ - ``X11_xkbfile_FOUND`` instead of ``X11_Xkbfile_FOUND``
+ - ``X11_Xtst_INCLUDE_PATH`` instead of ``X11_XTest_INCLUDE_PATH``
+ - ``X11_Xtst_LIB`` instead of ``X11_XTest_LIB``
+ - ``X11_Xtst_FOUND`` instead of ``X11_XTest_FOUND``
+ - ``X11_Xss_INCLUDE_PATH`` instead of ``X11_Xscreensaver_INCLUDE_PATH``
+ - ``X11_Xss_LIB`` instead of ``X11_Xscreensaver_LIB``
+ - ``X11_Xss_FOUND`` instead of ``X11_Xscreensaver_FOUND``
+
+ The following variables are deprecated completely since they were
+ essentially duplicates:
+
+ - ``X11_Xinput_INCLUDE_PATH`` (use ``X11_Xi_INCLUDE_PATH``)
+ - ``X11_Xinput_LIB`` (use ``X11_Xi_LIB``)
+ - ``X11_Xinput_FOUND`` (use ``X11_Xi_FOUND``)
+
+* The :module:`FindX11` now provides ``X11_Xext_INCLUDE_PATH``.
+
+* The :module:`FindX11` now provides imported targets.
+
+* The :module:`UseSWIG` module learned to pass ``-module <module_name>`` to
+ the ``SWIG`` compiler if the file property ``SWIG_MODULE_NAME`` is defined.
+ See policy :policy:`CMP0086`.
+
+* The :module:`UseSWIG` module gained an option to specify
+ ``SWIG`` source file extensions.
+
+.. _`fontconfig`: https://www.freedesktop.org/wiki/Software/fontconfig/
+.. _`libinput`: https://www.freedesktop.org/wiki/Software/libinput/
+
+Generator Expressions
+---------------------
+
+* The ``$<Fortran_COMPILER_ID:...>`` and ``$<Fortran_COMPILER_VERSION:...>``
+ :manual:`generator expressions <cmake-generator-expressions(7)>` were added.
+
+* The ``$<IN_LIST:...>`` generator expression now correctly handles an
+ empty argument. See :policy:`CMP0085` for details.
+
+Autogen
+-------
+
+* The :prop_tgt:`AUTOMOC_EXECUTABLE`, :prop_tgt:`AUTORCC_EXECUTABLE`, and
+ :prop_tgt:`AUTOUIC_EXECUTABLE` target properties were added. They all
+ take a path to an executable and force automoc/autorcc/autouic to use
+ this executable.
+
+ Setting these will also prevent the configure time testing for these
+ executables. This is mainly useful when you build these tools yourself.
+
+* The new variables :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET`,
+ :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME`,
+ :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` and
+ :variable:`CMAKE_GLOBAL_AUTORCC_TARGET_NAME` control the generation
+ of global ``autogen`` and ``autorcc`` targets.
+
+* A new :variable:`CMAKE_AUTOGEN_ORIGIN_DEPENDS` variable and
+ :prop_tgt:`AUTOGEN_ORIGIN_DEPENDS` target property may be set to enable or
+ disable forwarding of the origin target dependencies to the corresponding
+ ``_autogen`` target.
+
+CTest
+-----
+
+* :manual:`ctest(1)` gained a ``--show-only=json-v1`` option to show the
+ list of tests in a machine-readable JSON format.
+ See the :ref:`Show as JSON Object Model` section of the manual.
+
+* The :command:`ctest_submit` command learned a new ``Done`` part that can be used
+ to inform CDash that a build is complete and that no more parts will be uploaded.
+
+* CTest learned to accept the dashboard server submission URL from a single
+ variable. See the ``SubmitURL`` setting in :manual:`ctest(1)`,
+ the :variable:`CTEST_SUBMIT_URL` variable, and the ``SUBMIT_URL``
+ argument of the :command:`ctest_submit` command.
+
+Deprecated and Removed Features
+===============================
+
+* An explicit deprecation diagnostic was added for policies ``CMP0064``
+ and ``CMP0065`` (``CMP0063`` and below were already deprecated).
+ The :manual:`cmake-policies(7)` manual explains that the OLD behaviors
+ of all policies are deprecated and that projects should port to the
+ NEW behaviors.
+
+* The :generator:`Xcode` generator deprecated support for Xcode
+ versions prior to Xcode 5. Support for those will be dropped in a
+ future version of CMake.
+
+* The :module:`FindQt` module is no longer used by the :command:`find_package`
+ command as a find module. This allows the Qt Project upstream to optionally
+ provide its own ``QtConfig.cmake`` package configuration file and have
+ applications use it via ``find_package(Qt)`` rather than
+ ``find_package(Qt CONFIG)``. See policy :policy:`CMP0084`.
+
+* Support for running CMake on Windows XP and Windows Vista has been dropped.
+ The precompiled Windows binaries provided on ``cmake.org`` now require
+ Windows 7 or higher.
+
+* CTest no longer supports submissions via ``ftp``, ``scp``, ``cp``, and
+ ``xmlrpc``. CDash is the only maintained testing dashboard for CTest,
+ and it only supports submissions over ``http`` and ``https``.
+
+Other Changes
+=============
+
+* Object library linking has been fixed to propagate private link libraries
+ of object libraries to consuming targets.
+
+* Install rules under :command:`add_subdirectory` now interleave with those in
+ the calling directory. See policy :policy:`CMP0082` for details.
+
+* CMake now imposes a maximum recursion limit to prevent a stack overflow on
+ scripts that recurse infinitely. The limit can be adjusted at runtime with
+ :variable:`CMAKE_MAXIMUM_RECURSION_DEPTH`.
+
+* When using cppcheck via the :variable:`CMAKE_<LANG>_CPPCHECK` variable
+ or :prop_tgt:`<LANG>_CPPCHECK` property, the build will now fail if
+ ``cppcheck`` returns non-zero as configured by its command-line options.
+
+* Required link options to manage Position Independent Executable are now
+ added when :prop_tgt:`POSITION_INDEPENDENT_CODE` is set. The project is
+ responsible for using the :module:`CheckPIESupported` module to check for
+ ``PIE`` support to ensure that the :prop_tgt:`POSITION_INDEPENDENT_CODE`
+ target property will be honored at link time for executables. This behavior
+ is controlled by policy :policy:`CMP0083`.
+
+* :ref:`Visual Studio Generators` for VS 2010 and above learned
+ to support the ``VS_DEBUGGER_*`` properties on targets created
+ via :command:`add_custom_target`.
+
+* The :module:`CPack` module no longer defaults to the ``paxr`` value in the
+ :variable:`CPACK_DEBIAN_ARCHIVE_TYPE` variable, because ``dpkg`` has
+ never supported the PAX tar format. The ``paxr`` value will be mapped
+ to ``gnutar`` and a deprecation message emitted.
+
+* CMake no longer issues a warning if a target listed in an
+ :command:`install(TARGETS)` command has its :prop_tgt:`EXCLUDE_FROM_ALL`
+ property set to true.
+
+Updates
+=======
+
+Changes made since CMake 3.14.0 include the following.
+
+3.14.1
+------
+
+* The :module:`FindFontconfig` module added by 3.14.0 accidentally
+ used uppercase ``FONTCONFIG_*`` variable names that do not match
+ our conventions. 3.14.1 revises the module to use ``Fontconfig_*``
+ variable names. This is incompatible with 3.14.0 but since the
+ module is new in the 3.14 series usage should not yet be widespread.
+
+3.14.3
+------
+
+* The :variable:`CMAKE_VS_PLATFORM_NAME_DEFAULT` variable was added
+ to help toolchain files work with the :generator:`Visual Studio 16 2019`
+ generator where the default platform now depends on the host platform.
+
+3.14.4
+------
+
+* In CMake 3.14.0 through 3.14.3, calling :command:`target_link_libraries`
+ to add ``PRIVATE`` dependencies to a static library created in another
+ directory (under policy :policy:`CMP0079` ``NEW`` behavior) would
+ incorrectly propagate usage requirements of those dependencies to
+ dependents that link the static library. This has been fixed.
+ The bug also existed in 3.13.0 through 3.13.4 and is fixed in 3.13.5.
+
+3.14.5
+------
+
+* Entries of the ``CPATH`` environment variable are no longer excluded
+ from explicit use via :command:`include_directories` and
+ :command:`target_include_directories` as they were in CMake 3.14.0
+ through 3.14.4.
+
+3.14.6
+------
+
+* In CMake 3.14.0 through 3.14.5, the :module:`FindBISON` module
+ policy :policy:`CMP0088` ``NEW`` behavior accidentally interpreted
+ a relative path to the ``.y`` input as relative to the build tree
+ directory instead of the source tree directory. This has been fixed.
+
+3.14.7
+------
+
+* In CMake 3.14.0 through 3.14.6, the :prop_dir:`EXCLUDE_FROM_ALL`
+ directory property was regressed from pre-3.14 behavior and caused
+ targets within the directory to be excluded even from its own "all".
+ This has been fixed.
diff --git a/Help/release/3.15.rst b/Help/release/3.15.rst
new file mode 100644
index 0000000..e68e7d3
--- /dev/null
+++ b/Help/release/3.15.rst
@@ -0,0 +1,396 @@
+CMake 3.15 Release Notes
+************************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.14 include the following.
+
+New Features
+============
+
+Generators
+----------
+
+* The :generator:`Xcode` generator now supports per-target schemes.
+ See the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable and
+ :prop_tgt:`XCODE_GENERATE_SCHEME` target property.
+
+* The :generator:`Green Hills MULTI` generator has been updated:
+
+ * It now supports the :command:`add_custom_command` and
+ :command:`add_custom_target` commands.
+
+ * It is now available on Linux.
+
+Languages
+---------
+
+* Preliminary support for the ``Swift`` language was added to the
+ :generator:`Ninja` generator:
+
+ * Use the :envvar:`SWIFTC` environment variable to specify a compiler.
+
+ * The :prop_tgt:`Swift_DEPENDENCIES_FILE` target property and
+ :prop_sf:`Swift_DEPENDENCIES_FILE` source file property were added
+ to customize dependency files.
+
+ * The :prop_tgt:`Swift_MODULE_NAME` target property was added to
+ customize the Swift module name.
+
+ * The :prop_sf:`Swift_DIAGNOSTICS_FILE` source property was added to
+ indicate where to write the serialised Swift diagnostics.
+
+ The Swift support is experimental, not considered stable, and may change
+ in future releases of CMake.
+
+Compilers
+---------
+
+* The ``Clang`` compiler variant on Windows that targets the MSVC ABI
+ but has a GNU-like command line is now supported.
+
+* Support for the Clang-based ARM compiler was added with compiler id
+ ``ARMClang``.
+
+* Support was added for the IAR compiler architectures Renesas RX,
+ RL78, RH850 and Texas Instruments MSP430.
+
+* Support was added for the IAR compilers built for Linux (IAR BuildLx).
+
+Command-Line
+------------
+
+* The :envvar:`CMAKE_GENERATOR` environment variable was added
+ to specify a default generator to use when :manual:`cmake(1)` is
+ run without a ``-G`` option. Additionally, environment variables
+ :envvar:`CMAKE_GENERATOR_PLATFORM`, :envvar:`CMAKE_GENERATOR_TOOLSET`,
+ and :envvar:`CMAKE_GENERATOR_INSTANCE` were created to configure
+ the generator.
+
+* The :manual:`cmake(1)` ``--build`` tool ``--target`` parameter gained support
+ for multiple targets, e.g. ``cmake --build . --target Library1 Library2``.
+ It now also has a short form ``-t`` alias, e.g.
+ ``cmake --build . -t Library1 Library2``.
+
+* The :manual:`cmake(1)` command gained a new ``--install`` option.
+ This may be used after building a project to run installation without
+ using the generated build system or the native build tool.
+
+* The :manual:`cmake(1)` command learned a new CLI option ``--loglevel``.
+
+* The :manual:`cmake(1)` ``-E remove_directory`` command-line tool learned
+ to support removing multiple directories.
+
+* The :manual:`cmake(1)` ``-E tar`` tool has been improved:
+
+ * It now continues adding files to an archive even if some of the files
+ are not readable. This behavior is more consistent with the
+ classic ``tar`` tool.
+
+ * It now parses all flags, and if an invalid flag was provided, a
+ warning is issued.
+
+ * It now displays an error if no action flag was specified, along with a
+ list of possible actions: ``t`` (list), ``c`` (create) or ``x`` (extract).
+
+ * It now supports extracting (``-x``) or listing (``-t``) only specific
+ files or directories.
+
+ * It now supports Zstandard compression with a ``--zstd`` option.
+ Zstandard was designed to give a compression ratio comparable to that
+ of the DEFLATE (zip) algorithm, but faster, especially for decompression.
+
+Commands
+--------
+
+* The :command:`add_custom_command` and :command:`add_custom_target` commands
+ gained a new ``JOB_POOL`` option that works with the :generator:`Ninja`
+ generator to set the pool variable on the build statement.
+
+* The :command:`add_library` command ``ALIAS`` option learned to support
+ import libraries of the ``UNKNOWN`` type.
+
+* The :command:`cmake_parse_arguments` command gained an additional
+ ``<prefix>_KEYWORDS_MISSING_VALUES`` output variable to report
+ keyword arguments that were given by the caller with no values.
+
+* The :command:`execute_process` command gained a ``COMMAND_ECHO`` option
+ and supporting :variable:`CMAKE_EXECUTE_PROCESS_COMMAND_ECHO` variable
+ to enable echoing of the command-line string before execution.
+
+* The :command:`file(INSTALL)` command learned a new argument,
+ ``FOLLOW_SYMLINK_CHAIN``, which can be used to recursively resolve and
+ install symlinks.
+
+* :command:`list` learned new sub-commands:
+ ``PREPEND``, ``POP_FRONT`` and ``POP_BACK``.
+
+* The :command:`message` command learned new types:
+ ``NOTICE``, ``VERBOSE``, ``DEBUG`` and ``TRACE``.
+
+* The :command:`string` learned a new sub-command ``REPEAT``.
+
+Variables
+---------
+
+* The :variable:`CMAKE_CROSSCOMPILING_EMULATOR` variable and corresponding
+ :prop_tgt:`CROSSCOMPILING_EMULATOR` target property learned to support
+ arguments to the emulator.
+
+* The :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG` variable was added to tell
+ :command:`find_package` calls to look for a package configuration
+ file first even if a find module is available.
+
+* The :variable:`CMAKE_FRAMEWORK` variable was added to initialize the
+ :prop_tgt:`FRAMEWORK` property on all targets.
+
+* The :variable:`CMAKE_VS_JUST_MY_CODE_DEBUGGING` variable and
+ :prop_tgt:`VS_JUST_MY_CODE_DEBUGGING` target property were added to
+ enable the Just My Code feature of the Visual Studio Debugger when
+ compiling with MSVC cl 19.05 and higher.
+
+* The :variable:`CMAKE_MSVC_RUNTIME_LIBRARY` variable and
+ :prop_tgt:`MSVC_RUNTIME_LIBRARY` target property were introduced to
+ select the runtime library used by compilers targeting the MSVC ABI.
+ See policy :policy:`CMP0091`.
+
+* The :variable:`CMAKE_PROJECT_INCLUDE` and
+ :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables were added to allow
+ injection of custom code at the sites of :command:`project` calls
+ without knowing the project name a priori.
+
+Properties
+----------
+
+* The :prop_tgt:`ADDITIONAL_CLEAN_FILES` target property and
+ :prop_dir:`ADDITIONAL_CLEAN_FILES` directory property were added.
+ They allow to register additional files that should be removed during
+ the clean stage.
+
+* The :prop_tgt:`PUBLIC_HEADER` and :prop_tgt:`PRIVATE_HEADER` properties
+ may now be set on :ref:`Interface Libraries`. The headers specified by those
+ properties can be installed using the :command:`install(TARGETS)` command by
+ passing the ``PUBLIC_HEADER`` and ``PRIVATE_HEADER`` arguments respectively.
+
+* The :prop_tgt:`VS_PACKAGE_REFERENCES` target property was added to
+ tell :ref:`Visual Studio Generators` to add references to ``nuget``
+ packages.
+
+* The :prop_tgt:`VS_PROJECT_IMPORT` target property was added to allow
+ managed Visual Studio project files to import external ``.props`` files.
+
+* The :prop_tgt:`VS_NO_SOLUTION_DEPLOY` target property was added to
+ tell :ref:`Visual Studio Generators` whether to deploy an artifact
+ to the WinCE or Windows Phone target device.
+
+Modules
+-------
+
+* The :module:`FindBoost` module was reworked to expose a more consistent
+ user experience between its "Config" and "Module" modes and with other
+ find modules in general.
+
+ * A new imported target ``Boost::headers`` is now defined (same
+ as ``Boost::boost``).
+
+ * New output variables ``Boost_VERSION_MACRO``,
+ ``Boost_VERSION_MAJOR``, ``Boost_VERSION_MINOR``,
+ ``Boost_VERSION_PATCH``, and ``Boost_VERSION_COUNT``
+ were added.
+
+ * The ``QUIET`` argument passed to :command:`find_package` is no
+ longer ignored in config mode. Note that the CMake package shipped with
+ Boost ``1.70.0`` ignores the ``QUIET`` argument passed to
+ :command:`find_package`. This is fixed in the next Boost release.
+
+ * The input switch ``Boost_DETAILED_FAILURE_MSG`` was removed.
+
+ * ``Boost_VERSION`` now reports the version in ``x.y.z``
+ format in module mode. See policy :policy:`CMP0093`.
+
+* The :module:`FindCups` module now provides imported targets.
+
+* The :module:`FindEnvModules` module was added to use Lua- and TCL-based
+ environment modules in :ref:`CTest Scripts <CTest Script>`.
+
+* The :module:`FindGLEW` module now provides an interface more consistent
+ with what upstream GLEW provides in its own CMake package files.
+
+* The :module:`FindPkgConfig` now populates :prop_tgt:`INTERFACE_LINK_OPTIONS`
+ property of imported targets with other (non-library) linker flags.
+
+* The :module:`FindPostgreSQL` module learned to find debug and release
+ variants separately.
+
+* Modules :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+ gained additional lookup strategies and controls, and a new default.
+ See policy :policy:`CMP0094`.
+
+* Modules :module:`FindPython`, :module:`FindPython2` and :module:`FindPython3`
+ gain a new target (respectively ``Python::Module``, ``Python2::Module``
+ and ``Python3::Module``) which can be used to develop Python modules.
+
+* Modules :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+ gain capability to control how virtual environments are handled.
+
+* The :module:`UseSWIG` module learned to manage alternate library names
+ by passing ``-interface <library_name>`` for ``python`` language or
+ ``-dllimport <library_name>`` for ``CSharp`` language to the ``SWIG``
+ compiler.
+
+Generator Expressions
+---------------------
+
+* The :manual:`generator expressions <cmake-generator-expressions(7)>`
+ ``C_COMPILER_ID``, ``CXX_COMPILER_ID``, ``CUDA_COMPILER_ID``,
+ ``Fortran_COMPILER_ID``, ``COMPILE_LANGUAGE``, ``COMPILE_LANG_AND_ID``, and
+ ``PLATFORM_ID`` learned to support matching one value from a comma-separated
+ list.
+
+* The ``$<CUDA_COMPILER_ID:...>`` and ``$<CUDA_COMPILER_VERSION:...>``
+ :manual:`generator expressions <cmake-generator-expressions(7)>` were added.
+
+* The ``$<COMPILE_LANG_AND_ID:...>`` generator expression was introduced to
+ allow specification of compile options for target files based on the
+ :variable:`CMAKE_<LANG>_COMPILER_ID` and :prop_sf:`LANGUAGE` of
+ each source file.
+
+* A ``$<FILTER:list,INCLUDE|EXCLUDE,regex>``
+ :manual:`generator expression <cmake-generator-expressions(7)>`
+ has been added.
+
+* A ``$<REMOVE_DUPLICATES:list>``
+ :manual:`generator expression <cmake-generator-expressions(7)>`
+ has been added.
+
+* The ``$<SHELL_PATH:...>`` :manual:`generator expression
+ <cmake-generator-expressions(7)>` gained support for a list of paths.
+
+* New ``$<TARGET_FILE*>`` :manual:`generator expressions
+ <cmake-generator-expressions(7)>` were added to retrieve the prefix, base
+ name, and suffix of the file names of various artifacts:
+
+ * ``$<TARGET_FILE_PREFIX:...>``
+ * ``$<TARGET_FILE_BASE_NAME:...>``
+ * ``$<TARGET_FILE_SUFFIX:...>``
+ * ``$<TARGET_LINKER_FILE_PREFIX:...>``
+ * ``$<TARGET_LINKER_FILE_BASE_NAME:...>``
+ * ``$<TARGET_LINKER_FILE_SUFFIX:...>``
+ * ``$<TARGET_PDB_FILE_BASE_NAME:...>``
+
+* The ``$<TARGET_OBJECTS:...>`` :manual:`generator expression
+ <cmake-generator-expressions(7)>` is now supported on ``SHARED``,
+ ``STATIC``, ``MODULE`` libraries and executables.
+
+CTest
+-----
+
+* The :command:`ctest_submit` command learned a new option: ``BUILD_ID``.
+ This can be used to store the ID assigned to this build by CDash to a
+ variable.
+
+* The :command:`ctest_update` command learned to honor a new variable:
+ :variable:`CTEST_UPDATE_VERSION_OVERRIDE`. This can be used to specify
+ the current version of your source tree rather than using the update
+ command to discover the current version that is checked out.
+
+CPack
+-----
+
+* The :cpack_gen:`CPack IFW Generator` gained a new
+ :variable:`CPACK_IFW_PACKAGE_STYLE_SHEET` variable to customize the
+ installer stylesheet.
+
+Deprecated and Removed Features
+===============================
+
+* The :manual:`cmake-server(7)` mode has been deprecated and will be
+ removed from a future version of CMake. Please port clients to use
+ the :manual:`cmake-file-api(7)` instead.
+
+* The :prop_dir:`ADDITIONAL_MAKE_CLEAN_FILES` directory property is now
+ deprecated. Use the :prop_dir:`ADDITIONAL_CLEAN_FILES` directory property
+ instead.
+
+* The variable :variable:`CMAKE_AUTOMOC_RELAXED_MODE` is considered
+ deprecated. Support still exists but will be removed in future versions.
+
+* The :command:`export(PACKAGE)` command now does nothing unless
+ enabled via :variable:`CMAKE_EXPORT_PACKAGE_REGISTRY`.
+ See policy :policy:`CMP0090`.
+
+* The :generator:`Xcode` generator now requires at least Xcode 5.
+
+* An explicit deprecation diagnostic was added for policy ``CMP0066``
+ (``CMP0065`` and below were already deprecated).
+ The :manual:`cmake-policies(7)` manual explains that the OLD behaviors
+ of all policies are deprecated and that projects should port to the
+ NEW behaviors.
+
+Other Changes
+=============
+
+* If a feature specified by :command:`target_compile_features` is available
+ in the compiler's default standard level, CMake 3.14 and below incorrectly
+ added unnecessary ``-std=`` flags that could lower the standard level.
+ This bug has been fixed in CMake 3.15. This behavior change may expose
+ bugs in existing projects that were relying on undocumented implementation
+ details. Specifying compile features only ensures that the compiler runs
+ in a mode that has those features, not that any specific standard level is
+ used or explicit ``-std=`` flag passed.
+
+* CMake learned how to compile C++14 with the IBM AIX XL compiler
+ and the SunPro compiler and to compile C++20 with the AppleClang compiler.
+
+* With MSVC-like compilers the value of :variable:`CMAKE_<LANG>_FLAGS`
+ no longer contains warning flags like ``/W3`` by default.
+ See policy :policy:`CMP0092`.
+
+* IBM Clang-based XL compilers that define ``__ibmxl__`` now use the
+ compiler id ``XLClang`` instead of ``XL``. See policy :policy:`CMP0089`.
+
+* The :command:`file(REMOVE)` and :command:`file(REMOVE_RECURSE)` commands
+ were changed to ignore empty arguments with a warning instead of treating
+ them as a relative path and removing the contents of the current directory.
+
+Updates
+=======
+
+Changes made since CMake 3.15.0 include the following.
+
+3.15.1
+------
+
+* In CMake 3.15.0 support for the GNU-like ``Clang`` compiler targeting the
+ MSVC ABI implemented :variable:`CMAKE_CXX_STANDARD` values 98 and 11 using
+ the corresponding ``-std=`` flags. However, these modes do not work with
+ the MSVC standard library. Therefore CMake 3.15.1 passes C++14 standard
+ flags even for C++98 and C++11. This is consistent with MSVC itself which
+ always runs in a mode aware of C++14.
+
+* Preliminary Swift support added in 3.15.0 has been updated.
+
+3.15.2
+------
+
+* In CMake 3.15.0 and 3.15.1 the :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG`
+ variable caused the :command:`find_package` command to fail on a missing
+ package even without the ``REQUIRED`` option. This has been fixed.
+
+3.15.3
+------
+
+* ``CrayPrgEnv`` compiler wrapper support has been updated for the 19.06
+ release of the Cray Programming Environment for which the default linking
+ mode on XC Cray systems is now dynamic instead of static.
+
+3.15.4
+------
+
+* In CMake 3.15.0 through 3.15.3, the :prop_dir:`EXCLUDE_FROM_ALL`
+ directory property was regressed from pre-3.14 behavior and caused
+ targets within the directory to be excluded even from its own "all".
+ This has been fixed.
+ The bug also existed in 3.14.0 through 3.14.6 and is fixed in 3.14.7.
diff --git a/Help/release/3.16.rst b/Help/release/3.16.rst
new file mode 100644
index 0000000..84d96cd
--- /dev/null
+++ b/Help/release/3.16.rst
@@ -0,0 +1,324 @@
+CMake 3.16 Release Notes
+************************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.15 include the following.
+
+New Features
+============
+
+Languages
+---------
+
+* CMake learned to support the Objective C (``OBJC``) and Objective C++
+ (``OBJCXX``) languages. They may be enabled via the :command:`project`
+ and :command:`enable_language` commands. When ``OBJC`` or ``OBJCXX``
+ is enabled, source files with the ``.m`` or ``.mm``, respectively,
+ will be compiled as Objective C or C++. Otherwise they will be treated
+ as plain C++ sources as they were before.
+
+Compilers
+---------
+
+* The ``Clang`` compiler is now supported on ``Solaris``.
+
+Platforms
+---------
+
+* On AIX, executables using the :prop_tgt:`ENABLE_EXPORTS` target property
+ now produce a linker import file with a ``.imp`` extension in addition
+ to the executable file. Plugins (created via :command:`add_library` with
+ the ``MODULE`` option) that use :command:`target_link_libraries` to link
+ to the executable for its symbols are now linked using the import file.
+ The :command:`install(TARGETS)` command now installs the import file as
+ an ``ARCHIVE`` artifact.
+
+* On AIX, runtime linking is no longer enabled by default. CMake provides
+ the linker enough information to resolve all symbols up front.
+ One may manually enable runtime linking for shared libraries and/or
+ loadable modules by adding ``-Wl,-G`` to their link flags
+ (e.g. in the :variable:`CMAKE_SHARED_LINKER_FLAGS` or
+ :variable:`CMAKE_MODULE_LINKER_FLAGS` variable).
+ One may manually enable runtime linking for executables by adding
+ ``-Wl,-brtl`` to their link flags (e.g. in the
+ :variable:`CMAKE_EXE_LINKER_FLAGS` variable).
+
+Command-Line
+------------
+
+* :manual:`cmake(1)` ``-E`` now supports ``true`` and ``false`` commands,
+ which do nothing while returning exit codes of 0 and 1, respectively.
+
+* :manual:`cmake(1)` gained a ``--trace-redirect=<file>`` command line
+ option that can be used to redirect ``--trace`` output to a file instead
+ of ``stderr``.
+
+* The :manual:`cmake(1)` ``--loglevel`` command line option has been
+ renamed to ``--log-level`` to make it consistent with the naming of other
+ command line options. The ``--loglevel`` option is still supported to
+ preserve backward compatibility.
+
+Commands
+--------
+
+* The :command:`add_test` command learned the option ``COMMAND_EXPAND_LISTS``
+ which causes lists in the ``COMMAND`` argument to be expanded, including
+ lists created by generator expressions.
+
+* The :command:`file` command learned a new sub-command,
+ ``GET_RUNTIME_DEPENDENCIES``, which allows you to recursively get the list of
+ libraries linked by an executable or library. This sub-command is intended as
+ a replacement for :module:`GetPrerequisites`.
+
+* The :command:`find_file`, :command:`find_library`, :command:`find_path`,
+ :command:`find_package`, and :command:`find_program` commands have learned to
+ check the following variables to control the default behavior for groups of
+ search locations:
+
+ * :variable:`CMAKE_FIND_USE_PACKAGE_ROOT_PATH` - Controls the default
+ behavior of searching the :variable:`<PackageName>_ROOT` variables.
+
+ * :variable:`CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH` - Controls the default
+ behavior of searching the CMake-specific environment variables.
+
+ * :variable:`CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH` - Controls the default
+ behavior of searching the standard system environment variables.
+
+ * :variable:`CMAKE_FIND_USE_CMAKE_PATH` - Controls the default behavior of
+ searching the CMake-specific cache variables.
+
+ * :variable:`CMAKE_FIND_USE_CMAKE_SYSTEM_PATH` - Controls the default
+ behavior of searching the platform-specific CMake variables.
+
+* The :command:`find_package` command has learned to check the
+ :variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY` variable to control the default
+ behavior of searching the CMake user package registry and to check the
+ :variable:`CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY` variable to control
+ the default behavior of searching the CMake system package registry.
+
+* The :command:`message` command learned indentation control with the new
+ :variable:`CMAKE_MESSAGE_INDENT` variable.
+
+* The :command:`target_precompile_headers` command was added to specify
+ a list of headers to precompile for faster compilation times.
+
+Variables
+---------
+
+* The :variable:`CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS` variable has been
+ introduced to optionally initialize the
+ :prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` target property.
+
+* The :variable:`CMAKE_ECLIPSE_RESOURCE_ENCODING` variable was added to
+ specify the resource encoding for the the :generator:`Eclipse CDT4` extra
+ generator.
+
+* The :variable:`CMAKE_UNITY_BUILD` variable was added to initialize the
+ :prop_tgt:`UNITY_BUILD` target property to tell generators to batch
+ include source files for faster compilation times.
+
+Properties
+----------
+
+* The :prop_tgt:`BUILD_RPATH` and :prop_tgt:`INSTALL_RPATH` target properties
+ now support :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* The :prop_tgt:`INSTALL_REMOVE_ENVIRONMENT_RPATH` target property was
+ added to remove compiler-defined ``RPATH`` entries from a target.
+ This property is initialized by the
+ :variable:`CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH` variable.
+
+* The :prop_tgt:`PRECOMPILE_HEADERS` target property was added to specify
+ a list of headers to precompile for faster compilation times.
+ Set it using the :command:`target_precompile_headers` command.
+
+* The :prop_tgt:`UNITY_BUILD` target property was added to tell
+ generators to batch include source files for faster compilation
+ times.
+
+* The :prop_tgt:`VS_CONFIGURATION_TYPE` target property now supports
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* The :prop_tgt:`VS_DPI_AWARE` target property was added to tell
+ :ref:`Visual Studio Generators` to set the ``EnableDpiAwareness``
+ property in ``.vcxproj`` files.
+
+* The :prop_tgt:`XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING` target property was
+ added to tell the :generator:`Xcode` generator to set the value of the
+ ``Allow debugging when using document Versions Browser`` schema option.
+
+Modules
+-------
+
+* The :module:`FindDoxygen` module :command:`doxygen_add_docs` command
+ gained a new ``USE_STAMP_FILE`` option. When this option present,
+ the custom target created by the command will only re-run Doxygen if
+ any of the source files have changed since the last successful run.
+
+* The :module:`FindGnuTLS` module now provides an imported target.
+
+* The :module:`FindPackageHandleStandardArgs` module
+ :command:`find_package_handle_standard_args` command gained
+ a new ``REASON_FAILURE_MESSAGE`` option to specify a message
+ giving the reason for the failure.
+
+* The :module:`FindPkgConfig` module :command:`pkg_search_module` macro
+ now defines a ``<prefix>_MODULE_NAME`` result variable containing the
+ first matching module name.
+
+* The :module:`FindPython3` and :module:`FindPython` modules gained
+ options to control which ``ABIs`` will be searched.
+
+* The :module:`FindPython3`, :module:`FindPython2`, and :module:`FindPython`
+ modules now support direct specification of artifacts via cache entries.
+
+Autogen
+-------
+
+* When using :prop_tgt:`AUTOMOC`, the new :variable:`CMAKE_AUTOMOC_PATH_PREFIX`
+ variable or :prop_tgt:`AUTOMOC_PATH_PREFIX` target property may be enabled
+ to generate the ``-p`` path prefix
+ option for ``moc``. This ensures that ``moc`` output files are identical
+ on different build setups (given, that the headers compiled by ``moc`` are
+ in an :command:`include directory <target_include_directories>`).
+ Also it ensures that ``moc`` output files will compile correctly when the
+ source and/or build directory is a symbolic link.
+
+CTest
+-----
+
+* :manual:`ctest(1)` now has the ability to schedule tests based on resource
+ requirements for each test. See :ref:`ctest-resource-allocation` for
+ details.
+
+* A new test property, :prop_test:`SKIP_REGULAR_EXPRESSION`, has been added.
+ This property is similar to :prop_test:`FAIL_REGULAR_EXPRESSION` and
+ :prop_test:`PASS_REGULAR_EXPRESSION`, but with the same meaning as
+ :prop_test:`SKIP_RETURN_CODE`. This is useful, for example, in cases where
+ the user has no control over the return code of the test. For example, in
+ Catch2, the return value is the number of assertion failed, therefore it is
+ impossible to use it for :prop_test:`SKIP_RETURN_CODE`.
+
+CPack
+-----
+
+* :manual:`cpack(1)` learned support for multiple configurations for ``-C``
+ option.
+
+* The :cpack_gen:`CPack DEB Generator` is now able to format generic text
+ (usually used as the description for multiple CPack generators) according
+ to the `Debian Policy Manual`_. See the
+ :variable:`CPACK_PACKAGE_DESCRIPTION_FILE` and
+ :variable:`CPACK_DEBIAN_<COMPONENT>_DESCRIPTION` variables.
+
+* The :cpack_gen:`CPack Archive Generator` learned to generate ``.tar.zst``
+ packages with Zstandard compression.
+
+.. _`Debian Policy Manual`: https://www.debian.org/doc/debian-policy/ch-controlfields.html#description
+
+Deprecated and Removed Features
+===============================
+
+* An explicit deprecation diagnostic was added for policy ``CMP0067``
+ (``CMP0066`` and below were already deprecated).
+ The :manual:`cmake-policies(7)` manual explains that the OLD behaviors
+ of all policies are deprecated and that projects should port to the
+ NEW behaviors.
+
+* The :variable:`CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY` variable has been
+ deprecated. Use the :variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY` variable
+ instead.
+
+* The :module:`GetPrerequisites` module has been deprecated, as it has been
+ superceded by :command:`file(GET_RUNTIME_DEPENDENCIES)`.
+
+* The ``CPACK_INSTALL_SCRIPT`` variable has been deprecated in favor of the
+ new, more accurately named :variable:`CPACK_INSTALL_SCRIPTS` variable.
+
+Other Changes
+=============
+
+* The :manual:`cmake(1)` ``-C <initial-cache>`` option now evaluates the
+ initial cache script with :variable:`CMAKE_SOURCE_DIR` and
+ :variable:`CMAKE_BINARY_DIR` set to the top-level source and build trees.
+
+* The :manual:`cmake(1)` ``-E remove_directory`` command-line tool,
+ when given the path to a symlink to a directory, now removes just
+ the symlink. It no longer removes content of the linked directory.
+
+* The :manual:`ctest(1)` ``--build-makeprogram`` command-line option now
+ specifies the make program used when configuring a project with the
+ :generator:`Ninja` generator or the :ref:`Makefile Generators`.
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add` command
+ has been updated so that ``GIT_SUBMODULES ""`` initializes no submodules.
+ See policy :policy:`CMP0097`.
+
+* The :module:`FindGTest` module has been updated to recognize
+ MSVC build trees generated by GTest 1.8.1.
+
+* The :command:`project` command no longer strips leading zeros in version
+ components. See policy :policy:`CMP0096`.
+
+* The Qt Compressed Help file is now named ``CMake.qch``, which no longer
+ contains the release version in the file name. When CMake is upgraded
+ in-place, the name and location of this file will remain constant.
+ Tools such as IDEs, help viewers, etc. should now be able to refer to this
+ file at a fixed location that remains valid across CMake upgrades.
+
+* ``RPATH`` entries are properly escaped in the generated CMake scripts
+ used for installation. See policy :policy:`CMP0095`.
+
+* When using :variable:`CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS` on Windows the
+ auto-generated exports are now updated only when the object files
+ providing the symbols are updated.
+
+Updates
+=======
+
+Changes made since CMake 3.16.0 include the following.
+
+3.16.2
+------
+
+* CMake 3.16.0 and 3.16.1 processed ``.hh`` files with :prop_tgt:`AUTOMOC`.
+ This was a behavior change from CMake 3.15 and below that can break
+ existing projects, so it has been reverted as of 3.16.2.
+
+3.16.5
+------
+
+* The :module:`FindPython`, :module:`FindPython2`, and :module:`FindPython3`
+ modules no longer create cache entries for ``Python{,2,3}_LIBRARY_RELEASE``
+ and ``Python{,2,3}_LIBRARY_DEBUG``. Those values are always computed from
+ other results and so should not be cached. The entries were created by
+ CMake 3.16.0 through 3.16.4 but were always ``FORCE``-set and could not
+ be meaningfully edited by users.
+
+ Additionally, the modules no longer expose their internal ``_Python*``
+ cache entries publicly. CMake 3.16.0 through 3.16.4 accidentally
+ made them visible as advanced cache entries.
+
+3.16.7
+------
+
+* Selection of the Objective C or C++ compiler now considers the
+ :envvar:`CC` or :envvar:`CXX` environment variable if the
+ :envvar:`OBJC` or :envvar:`OBJCXX` environment variable is not set.
+
+* The :module:`FindPkgConfig` module now extracts include directories
+ prefixed with ``-isystem`` into the ``*_INCLUDE_DIRS`` variables and
+ :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target properties.
+ Previously they would be places in ``*_CFLAGS_OTHER`` variables and
+ :prop_tgt:`INTERFACE_COMPILE_OPTIONS` target properties.
+
+3.16.9
+------
+
+* The default value of :variable:`CMAKE_AUTOMOC_PATH_PREFIX` was changed to
+ ``OFF`` because this feature can break existing projects that have
+ identically named header files in different include directories.
+ This restores compatibility with behavior of CMake 3.15 and below.
diff --git a/Help/release/3.17.rst b/Help/release/3.17.rst
new file mode 100644
index 0000000..abd7463
--- /dev/null
+++ b/Help/release/3.17.rst
@@ -0,0 +1,357 @@
+CMake 3.17 Release Notes
+************************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.16 include the following.
+
+New Features
+============
+
+Generators
+----------
+
+* :manual:`cmake(1)` gained a :generator:`Ninja Multi-Config` generator,
+ which is similar to the :generator:`Ninja` generator but can be used to build
+ multiple configurations at once.
+
+* :ref:`Visual Studio Generators` learned to support per-config sources.
+ Previously only :ref:`Command-Line Build Tool Generators` supported them.
+
+* :ref:`Visual Studio Generators` for VS 2010 and above now support
+ specifying the ``VCTargetsPath`` value for project files in
+ :variable:`CMAKE_GENERATOR_TOOLSET` setting.
+
+* :ref:`Visual Studio Generators` for VS 2010 and above learned to
+ support .NET Standard and .NET Core. See the
+ :prop_tgt:`DOTNET_TARGET_FRAMEWORK` target property and
+ associated :variable:`CMAKE_DOTNET_TARGET_FRAMEWORK` variable.
+
+Languages
+---------
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ now offers meta-features for the CUDA language standard levels
+ (e.g. ``cuda_std_03``, ``cuda_std_14``). See
+ :prop_gbl:`CMAKE_CUDA_KNOWN_FEATURES`.
+
+Compilers
+---------
+
+* The IBM XL Fortran compiler is now supported by the :generator:`Ninja`
+ generator.
+
+Command-Line
+------------
+
+* :manual:`cmake(1)` gained a ``--debug-find`` command-line option to
+ enable additional human-readable output on where ``find_*`` commands search.
+
+* :manual:`cmake(1)` gained a ``--trace-format`` command-line option that
+ can be used to set the ``--trace`` output format. Currently, the old
+ human readable and the new JSON format are supported. The new JSON format
+ is easier to parse automatically than the existing format.
+
+* :manual:`cmake(1)` gained a ``-E rm`` command-line tool that can be
+ used to remove directories and files. This supersedes the existing
+ ``-E remove`` and ``-E remove_directory`` tools and has better semantics.
+
+Commands
+--------
+
+* The :command:`add_custom_command` command learned to interpret paths in
+ ``DEPENDS`` arguments that are specified relative to the current
+ binary directory.
+
+* The :command:`foreach` command learned a new ``ZIP_LISTS`` option to iterate
+ over multiple lists simultaneously.
+
+* The :command:`load_cache(READ_WITH_PREFIX)` command mode is now allowed
+ when using ``cmake -P`` to :ref:`Run a Script <Script Processing Mode>`.
+
+* The :command:`message` command learned to output context provided in
+ the :variable:`CMAKE_MESSAGE_CONTEXT` variable for log levels
+ ``NOTICE`` and below. Enable this output with the new ``--log-context``
+ command-line option or :variable:`CMAKE_MESSAGE_CONTEXT_SHOW` variable.
+
+* The :command:`message` command gained new keywords ``CHECK_START``,
+ ``CHECK_PASS`` and ``CHECK_FAIL``.
+
+* The :command:`target_compile_options` command now honors the ``BEFORE``
+ keyword more consistently. See policy :policy:`CMP0101`.
+
+Variables
+---------
+
+* A :variable:`CMAKE_CTEST_ARGUMENTS` variable was added to specify a list
+ of command-line arguments passed to CTest when running through the
+ ``test`` (or ``RUN_TESTS``) target of the generated build system.
+
+* The following variables are now defined inside a :command:`function`:
+
+ - :variable:`CMAKE_CURRENT_FUNCTION`
+ - :variable:`CMAKE_CURRENT_FUNCTION_LIST_DIR`
+ - :variable:`CMAKE_CURRENT_FUNCTION_LIST_FILE`
+ - :variable:`CMAKE_CURRENT_FUNCTION_LIST_LINE`
+
+* The :variable:`CMAKE_CUDA_RUNTIME_LIBRARY` variable and
+ :prop_tgt:`CUDA_RUNTIME_LIBRARY` target property were introduced to
+ select the CUDA runtime library used when linking targets that
+ use CUDA.
+
+* The :variable:`CMAKE_FIND_DEBUG_MODE` variable was introduced to
+ print extra ``find_*`` call information during the cmake run to standard
+ error. Output is designed for human consumption and not for parsing.
+
+* The :variable:`CMAKE_EXPORT_COMPILE_COMMANDS` variable now takes its
+ initial value from the :envvar:`CMAKE_EXPORT_COMPILE_COMMANDS` environment
+ variable if no explicit configuration is given.
+
+* The :variable:`CMAKE_<LANG>_COMPILER_LAUNCHER` variable, if not set
+ explicitly, now takes its initial value from the
+ :envvar:`CMAKE_<LANG>_COMPILER_LAUNCHER` environment variable.
+
+* The :variable:`CMAKE_MESSAGE_LOG_LEVEL` variable can now be used
+ to persist a log level between CMake runs, unlike the ``--log-level``
+ command line option which only applies to that particular run.
+
+* The :variable:`CMAKE_XCODE_SCHEME_ENVIRONMENT` variable was added
+ to initialize the :prop_tgt:`XCODE_SCHEME_ENVIRONMENT` target property.
+
+* The :variable:`CMAKE_XCODE_SCHEME_WORKING_DIRECTORY` variable and
+ associated :prop_tgt:`XCODE_SCHEME_WORKING_DIRECTORY` target property
+ were added to tell the :generator:`Xcode` generator to set the value of
+ the ``Custom Working Directory`` schema option.
+
+Properties
+----------
+
+* The :prop_tgt:`AIX_EXPORT_ALL_SYMBOLS` target property and associated
+ :variable:`CMAKE_AIX_EXPORT_ALL_SYMBOLS` variable were created to
+ optionally explicitly disable automatic export of symbols from shared
+ libraries on AIX.
+
+* The :prop_tgt:`DEPRECATION` target property was added to mark
+ a target as deprecated. If a linked target is marked as
+ deprecated, a warning with the deprecation message is issued
+ at generate time.
+
+* The :prop_tgt:`INSTALL_NAME_DIR` target property now supports
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+ In particular, the ``$<INSTALL_PREFIX>`` generator expression can
+ be used to set the directory relative to the install-time prefix.
+
+* Target properties :prop_tgt:`MACHO_COMPATIBILITY_VERSION` and
+ :prop_tgt:`MACHO_CURRENT_VERSION` were added to set the
+ ``compatibility_version`` and ``curent_version``, respectively,
+ for Mach-O binaries. For backwards compatibility, if these properties
+ are not set, :prop_tgt:`SOVERSION` and :prop_tgt:`VERSION`
+ are used respectively as fallbacks.
+
+* The :prop_tgt:`VS_DOTNET_DOCUMENTATION_FILE` target property was added
+ to tell :ref:`Visual Studio Generators` to generate a ``DocumentationFile``
+ reference in ``.csproj`` files.
+
+Modules
+-------
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add`
+ command gained a ``GIT_SUBMODULES_RECURSE`` option to specify whether
+ Git submodules should be updated recursively. The default is on to
+ preserve existing behavior.
+
+* The :module:`FindCUDAToolkit` module was added to find the
+ CUDA Toolkit without enabling CUDA as a language.
+
+* The :module:`FindCURL` module learned to find CURL using
+ the ``CURLConfig.cmake`` package configuration file generated by
+ CURL's cmake buildsystem. It also gained a new ``CURL_NO_CURL_CMAKE``
+ option to disable this behavior.
+
+* The :module:`FindFLEX` module's ``FLEX_TARGET`` command now runs ``flex``
+ with :variable:`CMAKE_CURRENT_BINARY_DIR` as the working directory.
+ See policy :policy:`CMP0098`.
+
+* The :module:`FindLibArchive` module now provides an imported target
+ for libarchive.
+
+* The :module:`FindPython` module has learned to find Python components
+ in active virtual environments managed by ``conda``.
+
+* The :module:`FindPython3` and :module:`FindPython` modules gained,
+ respectively, variable ``Python3_SOABI`` and ``Python_SOABI`` giving
+ the standard extension suffix for modules. Moreover, commands
+ ``Python3_add_library()`` and ``Python_add_library()`` gained the option
+ ``WITH_SOABI`` to prefix the library suffix with the value of ``SOABI``.
+
+* The :module:`FindLibXml2` module now provides an imported target for the
+ ``xmllint`` executable.
+
+Autogen
+-------
+
+* :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC` learned to process headers
+ with a ``.hh`` extension. See policy :policy:`CMP0100`.
+
+CTest
+-----
+
+* The :variable:`CTEST_CONFIGURATION_TYPE` variable is now set from the
+ command line when :manual:`ctest(1)` is invoked with ``-C <cfg>``.
+
+* The :manual:`ctest(1)` tool gained support for Dr. Memory to run
+ memcheck runs.
+
+* The :manual:`ctest(1)` tool gained a ``--no-tests=<[error|ignore]>`` option
+ to explicitly set and unify the behavior between direct invocation and
+ script mode if no tests were found.
+
+* The :manual:`ctest(1)` tool gained a ``--repeat <mode>:<n>`` option
+ to specify conditions in which to repeat tests. This generalizes
+ the existing ``--repeat-until-fail <n>`` option to add modes for
+ ``until-pass`` and ``after-timeout``.
+
+* The :command:`ctest_test` command gained a ``REPEAT <mode>:<n>`` option
+ to specify conditions in which to repeat tests.
+
+CPack
+-----
+
+* The :cpack_gen:`CPack DragNDrop Generator` learned to use
+ the :variable:`CPACK_DMG_<component>_FILE_NAME` variable
+ to set a custom filename when packaging components into
+ their own DMGs.
+
+* The :cpack_gen:`CPack DragNDrop Generator` learned to handle
+ RTF formatted license files. When :variable:`CPACK_DMG_SLA_DIR`
+ variable is set, ``<language>.license.rtf`` is considered, but
+ only as a fallback when the plaintext (``.txt``) file is not found
+ in order to maintain backwards compatibility.
+
+* The :cpack_gen:`CPack NSIS Generator` gained a new variable
+ :variable:`CPACK_NSIS_MUI_HEADERIMAGE` to set the header image.
+ To not break existing setups, it still defaults to
+ :variable:`CPACK_PACKAGE_ICON` if the new variable is not set.
+
+* The :cpack_gen:`CPack NSIS Generator` now supports
+ :variable:`CPACK_NSIS_UNINSTALL_NAME`.
+ This can be used to specify the name of the Uninstall program.
+
+* The :cpack_gen:`CPack NSIS Generator` now supports
+ :variable:`CPACK_NSIS_WELCOME_TITLE` and
+ :variable:`CPACK_NSIS_WELCOME_TITLE_3LINES`.
+ These can be used to specify the welcome page title and display it in 3 lines.
+
+* The :cpack_gen:`CPack NSIS Generator` now supports
+ :variable:`CPACK_NSIS_FINISH_TITLE` and
+ :variable:`CPACK_NSIS_FINISH_TITLE_3LINES`.
+ These can be used to specify the finish page title and display it in 3 lines.
+
+* The :cpack_gen:`CPack productbuild Generator` gained support for a
+ :variable:`CPACK_PRODUCTBUILD_BACKGROUND` variable to specify a background
+ image for the macOS installer.
+
+Other
+-----
+
+* :manual:`ccmake(1)` now displays cache values using colors
+ based on the entry type if the terminal supports color.
+
+* :manual:`ccmake(1)` now displays messages and a progress bar during
+ configure and generate. It will keep the output displayed if any
+ errors or warnings occurred.
+
+Deprecated and Removed Features
+===============================
+
+* An explicit deprecation diagnostic was added for policy ``CMP0068``
+ and policy ``CMP0069`` (``CMP0067`` and below were already deprecated).
+ The :manual:`cmake-policies(7)` manual explains that the OLD behaviors
+ of all policies are deprecated and that projects should port to the
+ NEW behaviors.
+
+* The :cpack_gen:`CPack PackageMaker Generator` generator has been
+ deprecated because Xcode no longer distributes the PackageMaker tools.
+ The undocumented ``OSXX11`` generator has also been deprecated.
+
+* The :manual:`cmake(1)` command-line ``-E remove`` and ``-E remove_directory``
+ tools are deprecated in favor of the new ``-E rm`` tool. The older tools
+ always returned 0 if a named path did not exist even without the force
+ option and cannot be fixed without breaking compatibility, and so have
+ been superseded.
+
+* The :cpack_gen:`CPack NSIS Generator` now requires NSIS 3.0 or later.
+
+Other Changes
+=============
+
+* The :manual:`file API <cmake-file-api(7)>` index file now emits a
+ ``multiConfig`` flag specifying whether or not the generator supports
+ multiple output configurations.
+
+* Target link properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
+ :prop_tgt:`INTERFACE_LINK_DIRECTORIES` and
+ :prop_tgt:`INTERFACE_LINK_DEPENDS` are now transitive over private
+ dependencies on static libraries.
+ See policy :policy:`CMP0099`.
+
+* When using MinGW tools, the :command:`find_library` command no longer
+ finds ``.dll`` files by default. Instead, it expects ``.dll.a`` import
+ libraries to be available.
+
+* The :generator:`MinGW Makefiles` generator no longer issues an error if
+ ``sh.exe`` is present in the environment's ``PATH``.
+
+* The :generator:`Ninja` generator now prefers the first ninja build
+ tool to appear in the ``PATH`` no matter whether it is called
+ ``ninja-build``, ``ninja``, or ``samu``. Previously the first
+ of those names to appear anywhere in the ``PATH`` would be preferred.
+
+* With SDCC the ``sdar`` tool is now preferred over ``sdcclib`` as librarian.
+ The latter was deprecated by SDCC 3.2.0 and removed in SDCC 3.8.6.
+
+* With SDCC the default flags no longer include any target-specific flags.
+ Previously the default flags were hard-coded for 8051.
+
+* The :variable:`CMAKE_VS_GLOBALS` variable value now applies during
+ compiler identification and in targets created by the
+ :command:`add_custom_target` command.
+
+* The :generator:`Xcode` generator no longer hard-codes ``-Wmost``,
+ ``-Wno-four-char-constants``, and ``-Wno-unknown-pragmas`` warning flags.
+
+Updates
+=======
+
+Changes made since CMake 3.17.0 include the following.
+
+3.17.1
+------
+
+* CMake 3.17.0 updated the :cpack_gen:`CPack NSIS Generator` with changes
+ that require NSIS 3.0 or later. CMake 3.17.1 now enforces the use
+ of a sufficiently new version.
+
+3.17.3
+------
+
+* Selection of the Objective C or C++ compiler now considers the
+ :envvar:`CC` or :envvar:`CXX` environment variable if the
+ :envvar:`OBJC` or :envvar:`OBJCXX` environment variable is not set.
+
+* The :module:`FindPkgConfig` module now extracts include directories
+ prefixed with ``-isystem`` into the ``*_INCLUDE_DIRS`` variables and
+ :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target properties.
+ Previously they would be places in ``*_CFLAGS_OTHER`` variables and
+ :prop_tgt:`INTERFACE_COMPILE_OPTIONS` target properties.
+
+3.17.5
+------
+
+* The default value of :variable:`CMAKE_AUTOMOC_PATH_PREFIX` was changed to
+ ``OFF`` because this feature can break existing projects that have
+ identically named header files in different include directories.
+ This restores compatibility with behavior of CMake 3.15 and below.
+ The default was also changed to ``OFF`` in 3.16.9.
diff --git a/Help/release/3.18.rst b/Help/release/3.18.rst
new file mode 100644
index 0000000..f97e4df
--- /dev/null
+++ b/Help/release/3.18.rst
@@ -0,0 +1,364 @@
+CMake 3.18 Release Notes
+************************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.17 include the following.
+
+New Features
+============
+
+Languages
+---------
+
+* The ``CUDA`` language can now be compiled using Clang on non-Windows
+ platforms. Separable compilation is not yet supported on any platform.
+
+Command-Line
+------------
+
+* :manual:`cmake(1)` gained support for profiling of CMake scripts through
+ the parameters ``--profiling-output`` and ``--profiling-format``.
+
+* :manual:`cmake(1)` gained a ``cat`` command line
+ option that can be used to concatenate files and print them
+ on standard output.
+
+Commands
+--------
+
+* The :command:`add_library` and :command:`add_executable` commands
+ learned to create :ref:`Alias Targets` referencing non-``GLOBAL``
+ :ref:`Imported Targets`.
+
+* The :command:`cmake_language()` command was added for meta-operations on
+ scripted or built-in commands, starting with a mode to ``CALL`` other
+ commands, and ``EVAL CODE`` to inplace evaluate a CMake script.
+
+* The :command:`execute_process` command gained the ``ECHO_OUTPUT_VARIABLE``
+ and ``ECHO_ERROR_VARIABLE`` options.
+
+* The :command:`export` command now raise an error if used multiple times with
+ same ``FILE`` without ``APPEND``. See policy :policy:`CMP0103`.
+
+* The :command:`file` command gained the ``ARCHIVE_CREATE`` and
+ ``ARCHIVE_EXTRACT`` subcommands to expose the :manual:`cmake(1)` ``-E tar``
+ functionality to CMake scripting code.
+
+* The :command:`file(CONFIGURE)` subcommand was created in order to replicate
+ the :command:`configure_file` functionality without resorting to a
+ pre-existing file on disk as input. The content is instead passed as a
+ string.
+
+* The :command:`file(UPLOAD)` command gained ``TLS_VERIFY`` and ``TLS_CAINFO``
+ options to control server certificate verification.
+
+* The :command:`find_program`, :command:`find_library`, :command:`find_path`
+ and :command:`find_file` commands gained a new ``REQUIRED`` option that will
+ stop processing with an error message if nothing is found.
+
+* The :command:`get_property` command with ``SOURCE`` scope gained the
+ ``DIRECTORY`` and ``TARGET_DIRECTORY`` options to get a property
+ from the provided directory scope.
+
+* The :command:`get_source_file_property` command gained the ``DIRECTORY``
+ and ``TARGET_DIRECTORY`` options to get a property from the
+ provided directory scope.
+
+* The :command:`list` operation ``SORT`` gained the ``NATURAL`` sort
+ option to sort using natural order (see ``strverscmp(3)`` manual).
+
+* The :command:`set_property` command with the ``SOURCE`` scope gained the
+ ``DIRECTORY`` and ``TARGET_DIRECTORY`` options to set properties
+ in the provided directory scopes.
+
+* The :command:`set_source_files_properties` command gained the ``DIRECTORY``
+ and ``TARGET_DIRECTORY`` options to set properties in the provided
+ directory scopes.
+
+* The :command:`string` command learned a new ``HEX`` sub-command, which
+ converts strings into their hexadecimal representation.
+
+Variables
+---------
+
+* A :variable:`CMAKE_CUDA_ARCHITECTURES` variable was added to specify
+ CUDA output architectures. Users are encouraged to use this instead of
+ specifying options manually, as this approach is compiler-agnostic.
+ The variable is initialized automatically when
+ :variable:`CMAKE_CUDA_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` is ``NVIDIA``.
+ The variable is used to initialize the new :prop_tgt:`CUDA_ARCHITECTURES`
+ target property. See policy :policy:`CMP0104`.
+
+* The :variable:`CMAKE_PCH_WARN_INVALID` variable was added to initialize the
+ :prop_tgt:`PCH_WARN_INVALID` target property to allow the removal of the
+ precompiled header invalid warning.
+
+Properties
+----------
+
+* The :prop_tgt:`CUDA_ARCHITECTURES` target property was added to specify
+ CUDA output architectures. Users are encouraged to use this instead of
+ specifying options manually, as this approach is compiler-agnostic.
+ The property is initialized by the new :variable:`CMAKE_CUDA_ARCHITECTURES`
+ variable. See policy :policy:`CMP0104`.
+
+* The :prop_tgt:`Fortran_PREPROCESS` target property and
+ :prop_sf:`Fortran_PREPROCESS` source-file property were added to
+ control preprocessing of Fortran source files.
+
+* The :prop_tgt:`FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>` target property
+ and associated :variable:`CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>`
+ variable were created to allow adding a postfix to the name of a
+ framework file name when using a multi-config generator.
+
+* The :prop_sf:`OBJECT_OUTPUTS` source file property now supports
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* The :prop_tgt:`PCH_WARN_INVALID` target property was added to allow the
+ removal of the precompiled header invalid warning.
+
+* The :prop_tgt:`UNITY_BUILD_MODE` target property was added to tell
+ generators which algorithm to use for grouping included source
+ files.
+
+* The :prop_tgt:`VS_SOURCE_SETTINGS_<tool>` target property was added
+ to tell :ref:`Visual Studio Generators` for VS 2010 and above to add
+ metadata to non-built source files using ``<tool>``.
+
+* The :prop_sf:`VS_SETTINGS` source file property was added to tell
+ :ref:`Visual Studio Generators` for VS 2010 and above to add
+ metadata to a non-built source file.
+
+* The :prop_tgt:`VS_PLATFORM_TOOLSET` target property was added to tell
+ :ref:`Visual Studio Generators` for VS 2010 and above to override
+ the platform toolset.
+
+* The :prop_tgt:`VS_SOLUTION_DEPLOY` target property was added to tell
+ :ref:`Visual Studio Generators` for VS 2010 and above to mark a
+ target for deployment even when not building for Windows Phone/Store/CE.
+
+Modules
+-------
+
+* The :module:`CheckLinkerFlag` module has been added to provide a
+ facility to check validity of link flags.
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add` command
+ gained a new ``GIT_REMOTE_UPDATE_STRATEGY`` keyword. This can be used to
+ specify how failed rebase operations during a git update should be handled.
+ The ``CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY`` variable was also added as a
+ global default and is honored by both the :module:`ExternalProject` and
+ :module:`FetchContent` modules.
+
+* The :module:`FetchContent` module :command:`FetchContent_Declare` command
+ now supports a ``SOURCE_SUBDIR`` option. It can be used to direct
+ :command:`FetchContent_MakeAvailable` to look in a different location
+ for the ``CMakeLists.txt`` file.
+
+* The :module:`FindBLAS` module now provides an imported target.
+
+* The :module:`FindCUDAToolkit` module:
+
+ * gained the variable
+ ``CUDAToolkit_LIBRARY_ROOT``, which is the directory containing the
+ ``nvvm`` directory and ``version.txt``.
+
+ * uses toolkit and library root found during ``CUDA`` compiler detection.
+
+* The :module:`FindLAPACK` module now provides an imported target.
+
+* The :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+ modules:
+
+ * gained the possibility to create per-artifact cache variables for
+ interactive editing in :manual:`cmake-gui(1)` and :manual:`ccmake(1)`.
+
+ * gained sub-components ``Development.Module`` and
+ ``Development.Embed`` under the ``Development`` component.
+
+ * gained the capability to specify which Python implementations to find,
+ including ``IronPython`` and ``PyPy``.
+
+* The :module:`FindRuby` module input and output variables were all renamed
+ from ``RUBY_`` to ``Ruby_`` for consistency with other find modules.
+ Input variables of the old case will be honored if provided, and output
+ variables of the old case are always provided.
+
+* The :module:`FindSWIG` module now accepts target languages as ``COMPONENTS``
+ and ``OPTIONAL_COMPONENTS`` arguments to ``find_package``.
+
+* The :module:`GoogleTest` module :command:`gtest_discover_tests` command:
+
+ * gained a new ``DISCOVERY_MODE`` option to control when the test
+ discovery step is run. It offers a new ``PRE_TEST`` setting to
+ run the discovery at test time instead of build time. A new
+ ``CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE`` variable can be used
+ to change the default globally.
+
+ * gained a new optional parameter ``XML_OUTPUT_DIR``. When set the
+ JUnit XML test results are stored in that directory.
+
+* The :module:`FindLibXslt` module now provides imported targets.
+
+* The :module:`UseSWIG` module now supports Fortran as a target language if
+ the ``SWIG_EXECUTABLE`` is SWIG-Fortran_.
+
+.. _`SWIG-Fortran`: https://github.com/swig-fortran/swig
+
+Generator Expressions
+---------------------
+
+* The ``$<DEVICE_LINK:...>`` and ``$<HOST_LINK:...>``
+ :manual:`generator expressions <cmake-generator-expressions(7)>` were added
+ to manage device and host link steps.
+
+* The ``$<LINK_LANGUAGE:...>`` and ``$<LINK_LANG_AND_ID:...>``
+ :manual:`generator expressions <cmake-generator-expressions(7)>` were added.
+
+CTest
+-----
+
+* :manual:`ctest(1)` gained a new :variable:`CTEST_RESOURCE_SPEC_FILE`
+ variable, which can be used to specify a
+ :ref:`resource specification file <ctest-resource-specification-file>`.
+
+* :manual:`ctest(1)` gained a ``--stop-on-failure`` option,
+ which can be used to stop running the tests once one has failed.
+
+* The :command:`ctest_test` command gained a ``STOP_ON_FAILURE`` option
+ which can be used to stop running the tests once one has failed.
+
+* The :module:`CTestCoverageCollectGCOV` module
+ :command:`ctest_coverage_collect_gcov` command gained a
+ ``TARBALL_COMPRESSION`` option to control compression of the
+ tarball of collected results.
+
+CPack
+-----
+
+* The :cpack_gen:`CPack Archive Generator`'s ``TXZ`` format learned the
+ :variable:`CPACK_ARCHIVE_THREADS` variable to enable parallel compression.
+ Requires support in the ``liblzma`` used by CMake.
+
+* The :cpack_gen:`CPack NSIS Generator` gained a new variable
+ :variable:`CPACK_NSIS_MANIFEST_DPI_AWARE` to declare that the
+ installer is DPI-aware.
+
+* The :cpack_gen:`CPack RPM Generator` gained
+ :variable:`CPACK_RPM_PRE_TRANS_SCRIPT_FILE` and
+ :variable:`CPACK_RPM_POST_TRANS_SCRIPT_FILE`
+ variables to specify pre- and post-transaction scripts.
+
+Other
+-----
+
+* :manual:`cmake-gui(1)` now populates its generator selection
+ widget default value from the :envvar:`CMAKE_GENERATOR` environment
+ variable. Additionally, environment variables
+ :envvar:`CMAKE_GENERATOR_PLATFORM` and :envvar:`CMAKE_GENERATOR_TOOLSET`
+ are used to populate their respective widget defaults.
+
+* :manual:`ccmake(1)` learned to read a :envvar:`CCMAKE_COLORS`
+ environment variable to customize colors.
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ is now aware of the availability of C11 features in MSVC 19.27 and 19.28,
+ including support for the ``c_restrict``, ``c_static_assert`` features and
+ the ``-std:c11`` flag.
+
+Deprecated and Removed Features
+===============================
+
+* The :module:`Documentation` module has been deprecated via
+ :policy:`CMP0106`. This module was essentially VTK code that CMake should
+ not be shipping anymore.
+
+* An explicit deprecation diagnostic was added for policy ``CMP0070``
+ and policy ``CMP0071`` (``CMP0069`` and below were already deprecated).
+ The :manual:`cmake-policies(7)` manual explains that the OLD behaviors
+ of all policies are deprecated and that projects should port to the
+ NEW behaviors.
+
+Other Changes
+=============
+
+* On Windows, the :generator:`Ninja` and :generator:`Ninja Multi-Config`
+ generators, when a compiler is not explicitly specified, now select
+ the first compiler (of any name) found in directories listed by the
+ ``PATH`` environment variable.
+
+* The :prop_tgt:`LINK_OPTIONS` and :prop_tgt:`INTERFACE_LINK_OPTIONS` target
+ properties are now used for the device link step.
+ See policy :policy:`CMP0105`.
+
+* Creation of an ``ALIAS`` target overwriting an existing target now raises an
+ error. See policy :policy:`CMP0107`.
+
+* Linking a target to itself through an alias now raises an error.
+ See policy :policy:`CMP0108`.
+
+* The :module:`FindPackageHandleStandardArgs` module option ``REQUIRED_VARS``
+ is now optional if ``HANDLE_COMPONENTS`` is specified.
+
+* The :command:`source_group` command now also recognizes forward slashes
+ as subgroup delimiters, not just backslashes.
+
+* :manual:`ctest(1)` now logs environment variables that it sets for each test,
+ either due to the :prop_test:`ENVIRONMENT` property or the
+ :ref:`resource allocation <ctest-resource-allocation>` feature, and submits
+ this log to CDash. It does not log environment variables that were set
+ outside of CTest.
+
+* When building CMake itself from source and not using a system-provided
+ libcurl, HTTP/2 support is now enabled for commands supporting
+ network communication via ``http(s)``, such as :command:`file(DOWNLOAD)`,
+ :command:`file(UPLOAD)`, and :command:`ctest_submit`.
+ The precompiled binaries provided on ``cmake.org`` now support HTTP/2.
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 ``version`` field has
+ been updated to 2.1.
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 "target" object gained
+ a new ``precompileHeaders`` field in the ``compileGroups`` objects.
+
+Updates
+=======
+
+Changes made since CMake 3.18.0 include the following.
+
+3.18.1
+------
+
+* The :generator:`Xcode` generator, when :variable:`CMAKE_OSX_ARCHITECTURES`
+ is not defined, now selects ``$(NATIVE_ARCH_ACTUAL)`` as the default
+ architecture (the Xcode ``ARCHS`` setting). This is needed for Xcode 12
+ to select the host's architecture, which older versions of Xcode did
+ by default.
+
+* In CMake 3.18.0 the :command:`add_test` command learned to support
+ special characters in test names. This was accidentally left out of
+ its release notes. Unfortunately the fix breaks existing projects
+ that were using manual quoting or escaping to work around the prior
+ limitation. This fix has been reverted in 3.18.1, but may be
+ re-introduced in future versions of CMake with a policy for compatibility.
+
+3.18.2
+------
+
+* The default value of :variable:`CMAKE_AUTOMOC_PATH_PREFIX` was changed to
+ ``OFF`` because this feature can break existing projects that have
+ identically named header files in different include directories.
+ This restores compatibility with behavior of CMake 3.15 and below.
+ The default was also changed to ``OFF`` in 3.16.9 and 3.17.5.
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ was updated for MSVC 19.27 as mentioned above (``c_restrict``).
+
+3.18.3
+------
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ was updated for MSVC 19.28 as mentioned above (``c_static_assert``).
diff --git a/Help/release/3.19.rst b/Help/release/3.19.rst
new file mode 100644
index 0000000..49c6793
--- /dev/null
+++ b/Help/release/3.19.rst
@@ -0,0 +1,442 @@
+CMake 3.19 Release Notes
+************************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.18 include the following.
+
+New Features
+============
+
+Presets
+-------
+
+* :manual:`cmake(1)` and :manual:`cmake-gui(1)` now recognize
+ ``CMakePresets.json`` and ``CMakeUserPresets.json`` files (see
+ :manual:`cmake-presets(7)`).
+
+Generators
+----------
+
+* The :generator:`Xcode` generator now uses the Xcode "new build system"
+ when generating for Xcode 12.0 or higher.
+ See the :variable:`CMAKE_XCODE_BUILD_SYSTEM` variable.
+ One may use ``-T buildsystem=1`` to switch to the legacy build system.
+
+* The :generator:`Xcode` generator gained support for linking libraries and
+ frameworks via the *Link Binaries With Libraries* build phase instead of
+ always by embedding linker flags directly. This behavior is controlled by
+ a new :prop_tgt:`XCODE_LINK_BUILD_PHASE_MODE` target property, which is
+ initialized by a new :variable:`CMAKE_XCODE_LINK_BUILD_PHASE_MODE`
+ variable.
+
+* The :ref:`Visual Studio Generators` for VS 2015 and above gained support
+ for the Visual Studio Tools for Android. One may now set
+ :variable:`CMAKE_SYSTEM_NAME` to ``Android`` to generate ``.vcxproj`` files
+ for the Android tools.
+
+Languages
+---------
+
+* CMake learned to support ``ISPC`` as a first-class language that can be
+ enabled via the :command:`project` and :command:`enable_language` commands.
+ ``ISPC`` is currently supported by the :ref:`Makefile Generators`
+ and the :generator:`Ninja` generator on Linux, macOS, and Windows
+ using the Intel ISPC compiler.
+
+* ``CUDA`` language support for Clang now includes:
+
+ - separable compilation (:prop_tgt:`CUDA_SEPARABLE_COMPILATION`), and
+ - finding scattered toolkit installations when cross-compiling.
+
+* ``CUDA`` language support now works on QNX.
+
+Platforms
+---------
+
+* Apple Silicon is now supported (since CMake 3.19.2):
+
+ * The :variable:`CMAKE_HOST_SYSTEM_PROCESSOR` is selected using ``uname -m``.
+ Since this may vary based on CMake's own architecture and that of
+ the invoking process tree, the :variable:`CMAKE_APPLE_SILICON_PROCESSOR`
+ variable or :envvar:`CMAKE_APPLE_SILICON_PROCESSOR` environment
+ variable may be set to specify a host architecture explicitly.
+
+ * If :variable:`CMAKE_OSX_ARCHITECTURES` is not set, CMake adds explicit
+ flags to tell the compiler to build for the
+ :variable:`CMAKE_HOST_SYSTEM_PROCESSOR` so the toolchain does not
+ have to guess based on the process tree's architecture.
+
+File-Based API
+--------------
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 ``version`` field has
+ been updated to 2.2.
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 "target" object
+ gained a new ``languageStandard`` field in the ``compileGroups`` objects.
+
+Command-Line
+------------
+
+* The :manual:`cmake(1)` command-line tool's ``--install`` mode gained a
+ ``--default-directory-permissions`` option.
+
+* :manual:`cmake(1)` gained a ``-E create_hardlink`` command-line tool
+ that can be used to create hardlinks between files.
+
+GUI
+---
+
+* The :manual:`CMake GUI <cmake-gui(1)>` now has an environment variable
+ editor.
+
+Commands
+--------
+
+* The :command:`add_test` command now (officially) supports whitespace and
+ other special characters in the name for the test it creates.
+ See policy :policy:`CMP0110`.
+
+* The :command:`cmake_language` command gained a ``DEFER`` mode to
+ schedule command calls to occur at the end of processing a directory.
+
+* The :command:`configure_file` command gained a ``NO_SOURCE_PERMISSIONS``
+ option to suppress copying the input file's permissions to the output file.
+
+* The :command:`execute_process` command gained a ``COMMAND_ERROR_IS_FATAL``
+ option to specify a fatal error.
+
+* The :command:`file(ARCHIVE_CREATE)` command gained a ``COMPRESSION_LEVEL``
+ option to specify the compression level.
+
+* The :command:`file(CHMOD)` and :command:`file(CHMOD_RECURSE)` subcommands
+ were added to set permissions of files and directories.
+
+* The :command:`file(DOWNLOAD)` command ``<file>`` argument is now
+ optional. If it is not specified, the file is not saved.
+
+* The :command:`file(GENERATE)` command gained a new ``TARGET`` keyword to
+ support resolving target-dependent generator expressions.
+
+* The :command:`file` command gained a new ``REAL_PATH`` sub-command to
+ compute a path with symlinks resolved.
+
+* The :command:`find_package` command learned to handle a version range.
+
+* The :command:`separate_arguments` command gained a new ``PROGRAM`` option.
+ It allows the arguments to be treated as a program invocation and will
+ resolve the executable to a full path if it can be found.
+
+* The ``DIRECTORY`` option of the :command:`set_property`,
+ :command:`get_property`, and :command:`get_directory_property` commands
+ now accepts references to binary directory paths, such as the value of
+ :variable:`CMAKE_CURRENT_BINARY_DIR`.
+
+* The :command:`string` command gained a set of new ``JSON`` sub commands
+ that provide JSON parsing capabilities.
+
+Variables
+---------
+
+* The :variable:`CMAKE_CLANG_VFS_OVERLAY` variable was added to tell
+ Clang to use a VFS overlay to support the Windows SDK when
+ cross-compiling from hosts with case-sensitive filesystems.
+
+* The :variable:`CMAKE_MFC_FLAG` variable now supports generator expressions.
+
+* The :variable:`CMAKE_OPTIMIZE_DEPENDENCIES` variable was added to
+ initialize the new :prop_tgt:`OPTIMIZE_DEPENDENCIES` target property and
+ avoid unnecessarily building dependencies for a static library.
+
+* The :variable:`CMAKE_PCH_INSTANTIATE_TEMPLATES` variable was added to
+ initialize the new :prop_tgt:`PCH_INSTANTIATE_TEMPLATES` target property.
+
+* The :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM` variable
+ was added to tell the :ref:`Visual Studio Generators` what maximum
+ version of the Windows SDK to choose.
+
+Properties
+----------
+
+* The :prop_tgt:`EXCLUDE_FROM_ALL` target property now supports
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* The :prop_tgt:`OPTIMIZE_DEPENDENCIES` target property was added to
+ avoid unnecessarily building dependencies for a static library.
+
+* The :prop_tgt:`PCH_INSTANTIATE_TEMPLATES` target property was added to enable
+ template instantiation in the precompiled header. This is enabled by default
+ and may significantly improve compile times. Currently only supported for
+ Clang (version 11 or later).
+
+* The :prop_tgt:`WIN32_EXECUTABLE` target property now supports
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+Modules
+-------
+
+* The :module:`CheckCompilerFlag` module has been added to
+ generalize :module:`CheckCCompilerFlag` and
+ :module:`CheckCXXCompilerFlag` to more languages.
+ It also supports the ``CUDA`` and ``ISPC`` languages.
+
+* The :module:`CheckLinkerFlag` module now supports the ``CUDA`` language.
+
+* The :module:`CheckSourceCompiles` module has been added to
+ generalize :module:`CheckCSourceCompiles` and
+ :module:`CheckCXXSourceCompiles` to more languages.
+ It also supports the ``CUDA`` and ``ISPC`` languages.
+
+* The :module:`CheckSourceRuns` module has been added to
+ generalize :module:`CheckCSourceRuns` and
+ :module:`CheckCXXSourceRuns` to more languages.
+ It also supports the ``CUDA`` language.
+
+* The :module:`CMakePackageConfigHelpers` module gained support for version
+ ranges.
+
+* The :module:`FindCUDAToolkit` module gained support for finding CUDA
+ toolkits that do not contain ``nvcc``, as well as for finding scattered
+ toolkit installations when cross-compiling.
+
+* The :module:`FindPackageHandleStandardArgs` module learned to handle
+ version ranges. It also gained the ``find_package_check_version()`` command
+ to check the validity of a version against version-related arguments of
+ :command:`find_package` command.
+
+* The :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+ modules gained the ability to handle a version range.
+
+* The :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+ modules provide, respectively, the variable ``Python3_LINK_OPTIONS``,
+ ``Python2_LINK_OPTIONS`` and ``Python_LINK_OPTIONS`` for link options.
+
+* The :module:`FindSDL` module now provides:
+
+ * An imported target ``SDL::SDL``.
+
+ * Result variables ``SDL_LIBRARIES`` and ``SDL_INCLUDE_DIRS``.
+
+ * Version variables ``SDL_VERSION``, ``SDL_VERSION_MAJOR``,
+ ``SDL_VERSION_MINOR``, and ``SDL_VERSION_PATCH``.
+
+* The :module:`FindSWIG` module gained the ability to handle a version range.
+
+* The :module:`FindTIFF` module gained a ``CXX`` component to
+ find the ``tiffxx`` library containing C++ bindings.
+
+* The :module:`FindVulkan` module now provides a ``Vulkan::glslc`` imported
+ target and associated ``Vulkan_GLSLC_EXECUTABLE`` variable which contain
+ the path to the GLSL SPIR-V compiler.
+
+* The :module:`UseSWIG` module gained support for new source file properties
+ ``OUTPUT_DIR`` and ``OUTFILE_DIR`` to manage output directories on a
+ per-source basis.
+
+CTest
+-----
+
+* :manual:`ctest(1)` now supports the CUDA ``compute-sanitizer`` checker
+ (previously known as ``cuda-memcheck``) as the ``CTEST_MEMORYCHECK_COMMAND``.
+ The different tools (``memcheck``, ``racecheck``, ``synccheck`` and
+ ``initcheck``) supported by ``compute-sanitizer`` can be selected by
+ adding appropriate flags to the ``CTEST_MEMORYCHECK_COMMAND_OPTIONS``
+ variable. The default flags are ``--tool memcheck --leak-check full``.
+
+CPack
+-----
+
+* CPack gained the :variable:`CPACK_PRE_BUILD_SCRIPTS`,
+ :variable:`CPACK_POST_BUILD_SCRIPTS`, and :variable:`CPACK_PACKAGE_FILES`
+ variables.
+
+* The :cpack_gen:`CPack External Generator` gained the
+ :variable:`CPACK_EXTERNAL_BUILT_PACKAGES` variable.
+
+* The :cpack_gen:`CPack WIX Generator` gained a
+ :variable:`CPACK_WIX_CUSTOM_XMLNS` option to specify custom XML namespaces.
+
+Other
+-----
+
+* :ref:`Interface Libraries` may now have source files added via
+ :command:`add_library` or :command:`target_sources`. Those
+ with sources will be generated as part of the build system.
+
+Deprecated and Removed Features
+===============================
+
+* Compatibility with versions of CMake older than 2.8.12 is now deprecated
+ and will be removed from a future version. Calls to
+ :command:`cmake_minimum_required` or :command:`cmake_policy` that set
+ the policy version to an older value now issue a deprecation diagnostic.
+
+* An explicit deprecation diagnostic was added for policy ``CMP0071``
+ (``CMP0071`` and below were already deprecated).
+ The :manual:`cmake-policies(7)` manual explains that the OLD behaviors
+ of all policies are deprecated and that projects should port to the
+ NEW behaviors.
+
+* macOS SDKs older than 10.5 are no longer supported.
+
+* :manual:`cmake-gui(1)` now requires Qt5.
+ Support for compiling with Qt4 has been removed.
+
+* The :manual:`cmake(1)` command-line option ``--warn-unused-vars`` has
+ been removed and is now silently ignored. The option has not worked
+ correctly since CMake 3.3.
+
+Documentation
+=============
+
+The following guides have been added:
+
+* :guide:`IDE Integration Guide`
+* :guide:`Importing and Exporting Guide`
+
+Other Changes
+=============
+
+* Building for macOS will now use the latest SDK available on the system,
+ unless the user has explicitly chosen a SDK using
+ :variable:`CMAKE_OSX_SYSROOT`. The deployment target or system macOS
+ version will not affect the choice of SDK.
+
+* The :variable:`CMAKE_<LANG>_COMPILER` variable may now be used to
+ store "mandatory" compiler flags like the :envvar:`CC` and other environment
+ variables.
+
+* The :variable:`CMAKE_<LANG>_FLAGS_INIT` variable will now be considered
+ during the compiler identification check if other sources like
+ :variable:`CMAKE_<LANG>_FLAGS` or :envvar:`CFLAGS` are not set.
+
+* The :command:`find_program` command now requires permission to execute
+ but not to read the file found. See policy :policy:`CMP0109`.
+
+* An imported target missing its location property fails during generation
+ if the location is used. See policy :policy:`CMP0111`.
+
+* The following target-based generator expressions that query for directory or
+ file name components no longer add a dependency on the evaluated target.
+ See policy :policy:`CMP0112`.
+
+ - ``TARGET_FILE_DIR``
+ - ``TARGET_LINKER_FILE_BASE_NAME``
+ - ``TARGET_LINKER_FILE_NAME``
+ - ``TARGET_LINKER_FILE_DIR``
+ - ``TARGET_SONAME_FILE_NAME``
+ - ``TARGET_SONAME_FILE_DIR``
+ - ``TARGET_PDB_FILE_NAME``
+ - ``TARGET_PDB_FILE_DIR``
+ - ``TARGET_BUNDLE_DIR``
+ - ``TARGET_BUNDLE_CONTENT_DIR``
+
+* :ref:`Makefile Generators` no longer repeat custom commands from target
+ dependencies. See policy :policy:`CMP0113`.
+
+* The :module:`ExternalProject` module handling of step target dependencies
+ has been revised. See policy :policy:`CMP0114`.
+
+* The :prop_tgt:`OSX_ARCHITECTURES` target property is now respected
+ for the ``ASM`` language.
+
+* If ``CUDA`` compiler detection fails with user-specified
+ :variable:`CMAKE_CUDA_ARCHITECTURES` or
+ :variable:`CMAKE_CUDA_HOST_COMPILER`, an error is raised.
+
+Updates
+=======
+
+Changes made since CMake 3.19.0 include the following.
+
+3.19.1
+------
+
+* CMake 3.19.0 compiles source files with the :prop_sf:`LANGUAGE`
+ property by passing an explicit language flag such as ``-x c``.
+ This is consistent with the property's documented meaning that
+ the source file is written in the specified language. However,
+ it can break projects that were using the property only to
+ cause the specified language's compiler to be used. This has
+ been reverted to restore behavior from CMake 3.18 and below.
+
+* CUDA 11.1 support for Clang.
+
+3.19.2
+------
+
+* The precompiled macOS binary provided on ``cmake.org`` is now a
+ universal binary with ``x86_64`` and ``arm64`` architectures.
+ It requires macOS 10.10 or newer.
+ The package file naming pattern has been changed from
+ ``cmake-$ver-Darwin-x86_64`` to ``cmake-$ver-macos-universal``.
+
+* Apple Silicon host architecture selection support was updated.
+ CMake 3.19.0 and 3.19.1 always chose ``arm64`` as the host architecture.
+ CMake 3.19.2 returns to using ``uname -m`` as CMake 3.18 and below did.
+ Since this may vary based on CMake's own architecture and that of
+ the invoking process tree, the :variable:`CMAKE_APPLE_SILICON_PROCESSOR`
+ variable or :envvar:`CMAKE_APPLE_SILICON_PROCESSOR` environment
+ variable may be set to specify a host architecture explicitly.
+
+* The :variable:`CMAKE_ISPC_HEADER_SUFFIX` variable and corresponding
+ :prop_tgt:`ISPC_HEADER_SUFFIX` target property were added to control
+ the header suffix used by ``ISPC`` compiler generated headers.
+
+3.19.3
+------
+
+* A precompiled Linux ``aarch64`` binary is now provided on ``cmake.org``.
+
+* Two precompiled macOS binaries are now provided on ``cmake.org``:
+
+ * The naming pattern ``cmake-$ver-macos-universal`` is a universal
+ binary with ``x86_64`` and ``arm64`` architectures. It requires
+ macOS 10.13 or newer.
+
+ * The naming pattern ``cmake-$ver-macos10.10-universal`` is a universal
+ binary with ``x86_64`` and ``arm64`` architectures. It requires
+ macOS 10.10 or newer.
+
+3.19.4
+------
+
+* The :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM`
+ variable introduced in 3.19.0 previously worked only with the
+ :generator:`Visual Studio 14 2015` generator. It has now been fixed to
+ work with :ref:`Visual Studio Generators` for later VS versions too.
+
+3.19.5
+------
+
+* When :prop_tgt:`IOS_INSTALL_COMBINED` is enabled and the :generator:`Xcode`
+ generator is used, it is now possible to initiate an install or package
+ creation by running ``cmake --install`` or ``cpack`` from the command line.
+ When using the Xcode new build system, these are the only supported methods
+ due to a limitation of Xcode. Initiating these operations by building the
+ ``install`` or ``package`` targets in Xcode is only supported when using
+ the legacy build system.
+
+* The framework handling introduced in 3.19.0 as part of supporting Xcode's
+ *Link Binaries With Libraries* build phase broke the ability to switch
+ between device and simulator builds without reconfiguring. That capability
+ has now been restored.
+
+3.19.6
+------
+
+* The :manual:`cmake-presets(7)` feature no longer allows comments in
+ ``CMakePresets.json`` or ``CMakeUserPresets.json`` files.
+ This was mistakenly allowed by the implementation in CMake 3.19.0 through
+ CMake 3.19.5, and was not documented.
+
+3.19.7
+------
+
+* With :ref:`Visual Studio Generators` for VS 2017 and higher, the
+ :variable:`CMAKE_GENERATOR_TOOLSET` field ``version=`` now accepts
+ three-component MSVC toolset versions such as ``14.28.29910``.
+ See the :variable:`CMAKE_VS_PLATFORM_TOOLSET_VERSION` variable.
diff --git a/Help/release/3.2.rst b/Help/release/3.2.rst
new file mode 100644
index 0000000..992d44b
--- /dev/null
+++ b/Help/release/3.2.rst
@@ -0,0 +1,277 @@
+CMake 3.2 Release Notes
+***********************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.1 include the following.
+
+New Features
+============
+
+Syntax
+------
+
+* CMake learned to support unicode characters
+ :ref:`encoded as UTF-8 <CMake Language Encoding>`
+ on Windows. This was already supported on platforms whose
+ system APIs accept UTF-8 encoded strings.
+ Unicode characters may now be used in CMake code, paths to
+ source files, configured files such as ``.h.in`` files, and
+ other files read and written by CMake. Note that because CMake
+ interoperates with many other tools, there may still be some
+ limitations when using certain unicode characters.
+
+Commands
+--------
+
+* The :command:`add_custom_command` and :command:`add_custom_target`
+ commands learned a new ``BYPRODUCTS`` option to specify files
+ produced as side effects of the custom commands. These are not
+ outputs because they do not always have to be newer than inputs.
+
+* The :command:`add_custom_command` and :command:`add_custom_target`
+ commands learned a new ``USES_TERMINAL`` option to request that
+ the command be given direct access to the terminal if possible.
+ The :generator:`Ninja` generator will places such commands in the
+ ``console`` :prop_gbl:`pool <JOB_POOLS>`. Build targets provided by CMake
+ that are meant for individual interactive use, such as ``install``, are now
+ placed in this pool.
+
+* A new :command:`continue` command was added that can be called inside loop
+ contexts to end the current iteration and start the next one at the top of
+ the loop block.
+
+* The :command:`file(LOCK)` subcommand was created to allow CMake
+ processes to synchronize through file and directory locks.
+
+* The :command:`file(STRINGS)` now supports UTF-16LE, UTF-16BE,
+ UTF-32LE, UTF-32BE as ``ENCODING`` options.
+
+* The :command:`install(EXPORT)` command now works with an absolute
+ ``DESTINATION`` even if targets in the export set are installed
+ with a destination or :ref:`usage requirements <Target Usage Requirements>`
+ specified relative to the install prefix. The value of the
+ :variable:`CMAKE_INSTALL_PREFIX` variable is hard-coded into the installed
+ export file as the base for relative references.
+
+* The :command:`try_compile` command source file signature now honors
+ link flags (e.g. :variable:`CMAKE_EXE_LINKER_FLAGS`) in the generated
+ test project. See policy :policy:`CMP0056`.
+
+* The :command:`try_run` command learned to honor the ``LINK_LIBRARIES``
+ option just as :command:`try_compile` already does.
+
+* The :command:`file(GENERATE)` command now generates the output file with
+ the same permissions as the input file if set.
+
+* The :command:`file(GENERATE)` command can now generate files which are
+ used as source files for buildsystem targets. Generated files
+ automatically get their :prop_sf:`GENERATED` property set to ``TRUE``.
+
+Variables
+---------
+
+* The :variable:`CMAKE_MATCH_COUNT` variable was introduced to record the
+ number of matches made in the last regular expression matched in an
+ :command:`if` command or a :command:`string` command.
+
+Properties
+----------
+
+* An :prop_tgt:`ANDROID_API_MIN` target property was introduced to
+ specify the minimum version to be targeted by the toolchain.
+
+* A :prop_sf:`VS_SHADER_FLAGS` source file property was added to specify
+ additional shader flags to ``.hlsl`` files, for the Visual Studio
+ generators.
+
+Modules
+-------
+
+* The :module:`ExternalData` module learned to support
+ :ref:`Custom Fetch Scripts <ExternalData Custom Fetch Scripts>`.
+ This allows projects to specify custom ``.cmake`` scripts for
+ fetching data objects during the build.
+
+* The :module:`ExternalProject` module learned options to create
+ independent external project step targets that do not depend
+ on the builtin steps.
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add`
+ command learned a new ``CMAKE_CACHE_DEFAULT_ARGS`` option to
+ initialize cache values in the external project without setting
+ them on future builds.
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add`
+ command learned a new ``TEST_EXCLUDE_FROM_MAIN`` option to exclude
+ tests from the main build.
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add`
+ command learned a new ``UPDATE_DISCONNECTED`` option to avoid
+ automatically updating the source tree checkout from version control.
+
+* The :module:`FindCUDA` module learned about the ``cusolver``
+ library in CUDA 7.0.
+
+* The :module:`FindGit` module learned to find the ``git`` command-line tool
+ that comes with GitHub for Windows installed in user home directories.
+
+* A :module:`FindGSL` module was introduced to find the
+ GNU Scientific Library.
+
+* A :module:`FindIntl` module was introduced to find the
+ Gettext ``libintl`` library.
+
+* The :module:`FindLATEX` module learned to support components.
+
+* The :module:`FindMPI` module learned to find MS-MPI on Windows.
+
+* The :module:`FindOpenSSL` module now reports ``crypto`` and ``ssl``
+ libraries separately in ``OPENSSL_CRYPTO_LIBRARY`` and
+ ``OPENSSL_SSL_LIBRARY``, respectively, to allow applications to
+ link to one without the other.
+
+* The :module:`WriteCompilerDetectionHeader` module learned to
+ create a define for portability of the ``cxx_thread_local`` feature.
+ The define expands to either the C++11 ``thread_local`` keyword, or a
+ pre-standardization compiler-specific equivalent, as appropriate.
+
+* The :module:`WriteCompilerDetectionHeader` module learned to create
+ multiple output files per compiler and per language, instead of creating
+ one large file.
+
+CTest
+-----
+
+* The :command:`ctest_coverage` command learned to support Delphi coverage.
+
+* The :command:`ctest_coverage` command learned to support Javascript coverage.
+
+* The :module:`CTestCoverageCollectGCOV` module was introduced as an
+ alternative to the :command:`ctest_coverage` command for collecting
+ ``gcov`` results for submission to CDash.
+
+CPack
+-----
+
+* The :cpack_gen:`CPack RPM Generator` learned options to set per-component
+ descriptions and summaries. See the
+ :variable:`CPACK_RPM_<component>_PACKAGE_DESCRIPTION` and
+ :variable:`CPACK_RPM_<component>_PACKAGE_SUMMARY` variables.
+
+* The :cpack_gen:`CPack RPM Generator` learned options to specify
+ requirements for pre- and post-install scripts. See the
+ :variable:`CPACK_RPM_PACKAGE_REQUIRES_PRE` and
+ :variable:`CPACK_RPM_PACKAGE_REQUIRES_POST` variables.
+
+* The :cpack_gen:`CPack RPM Generator` learned options to specify
+ requirements for pre- and post-uninstall scripts. See the
+ :variable:`CPACK_RPM_PACKAGE_REQUIRES_PREUN` and
+ :variable:`CPACK_RPM_PACKAGE_REQUIRES_POSTUN` variables.
+
+* The :cpack_gen:`CPack RPM Generator` learned a new
+ :variable:`CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX` variable to
+ specify a component-specific value to use instead of
+ :variable:`CPACK_PACKAGING_INSTALL_PREFIX`.
+
+* The :cpack_gen:`CPack RPM Generator` learned a new
+ :variable:`CPACK_RPM_RELOCATION_PATHS` variable to
+ specify multiple relocation prefixes for a single rpm package.
+
+Other
+-----
+
+* The :manual:`cmake(1)` ``-E tar`` command now supports creating
+ ``.xz``-compressed archives with the ``J`` flag.
+
+* The :manual:`cmake(1)` ``-E tar`` command learned a new
+ ``--files-from=<file>`` option to specify file names using
+ lines in a file to overcome command-line length limits.
+
+* The :manual:`cmake(1)` ``-E tar`` command learned a new
+ ``--mtime=<date>`` option to specify the modification time
+ recorded in tarball entries.
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ is now aware of features supported by more compilers, including:
+
+ * Apple Clang (``AppleClang``) for Xcode versions 4.4 though 6.1.
+ * GNU compiler versions 4.4 through 5.0 on UNIX and Apple (``GNU``).
+ * Microsoft Visual Studio (``MSVC``) for versions 2010 through 2015.
+ * Oracle SolarisStudio (``SunPro``) version 12.4.
+
+* The :ref:`Qt AUTORCC` feature now tracks files listed in ``.qrc`` files
+ as dependencies. If an input file to the ``rcc`` tool is changed, the tool
+ is automatically re-run.
+
+New Diagnostics
+===============
+
+* The :command:`break` command now rejects calls outside of a loop
+ context or that pass arguments to the command.
+ See policy :policy:`CMP0055`.
+
+Deprecated and Removed Features
+===============================
+
+* Files written in the :manual:`cmake-language(7)`, such as
+ ``CMakeLists.txt`` or ``*.cmake`` files, are now expected to be
+ encoded as UTF-8. If files are already ASCII, they will be
+ compatible. If files were in a different encoding, including
+ Latin 1, they will need to be converted.
+
+* The :module:`FindOpenGL` module no longer explicitly searches
+ for any dependency on X11 libraries with the :module:`FindX11`
+ module. Such dependencies should not need to be explicit.
+ Applications using X11 APIs themselves should find and link
+ to X11 libraries explicitly.
+
+* The implementation of CMake now relies on some C++ compiler features which
+ are not supported by some older compilers. As a result, those old compilers
+ can no longer be used to build CMake itself. CMake continues to be able to
+ generate Makefiles and project files for users of those old compilers
+ however. Compilers known to no longer be capable of building CMake are:
+
+ * Visual Studio 6 and 7.0 -- superseded by VisualStudio 7.1 and newer.
+ * GCC 2.95 -- superseded by GCC 3 and newer compilers.
+ * Borland compilers -- superseded by other Windows compilers.
+ * Compaq compilers -- superseded by other compilers.
+ * SGI compilers -- IRIX was dropped as a host platform.
+
+Other Changes
+=============
+
+* On Windows and OS X, commands supporting network communication
+ via ``https``, such as :command:`file(DOWNLOAD)`,
+ :command:`file(UPLOAD)`, and :command:`ctest_submit`, now support
+ SSL/TLS even when CMake is not built against OpenSSL.
+ The Windows or OS X native SSL/TLS implementation is used by default.
+ OS-configured certificate authorities will be trusted automatically.
+
+ On other platforms, when CMake is built with OpenSSL, these
+ commands now search for OS-configured certificate authorities
+ in a few ``/etc`` paths to be trusted automatically.
+
+* On OS X with Makefile and Ninja generators, when a compiler is found
+ in ``/usr/bin`` it is now mapped to the corresponding compiler inside
+ the Xcode application folder, if any. This allows such build
+ trees to continue to work with their original compiler even when
+ ``xcode-select`` switches to a different Xcode installation.
+
+* The Visual Studio generators now write solution and project
+ files in UTF-8 instead of Windows-1252. Windows-1252 supported
+ Latin 1 languages such as those found in North and South America
+ and Western Europe. With UTF-8, additional languages are now
+ supported.
+
+* The :generator:`Xcode` generator no longer requires a value for
+ the :variable:`CMAKE_MAKE_PROGRAM` variable to be located up front.
+ It now locates ``xcodebuild`` when needed at build time.
+
+* When building CMake itself using SolarisStudio 12, the default ``libCStd``
+ standard library is not sufficient to build CMake. The SolarisStudio
+ distribution supports compiler options to use ``STLPort4`` or ``libstdc++``.
+ An appropriate option to select the standard library is now added
+ automatically when building CMake with SolarisStudio compilers.
diff --git a/Help/release/3.20.rst b/Help/release/3.20.rst
new file mode 100644
index 0000000..e452926
--- /dev/null
+++ b/Help/release/3.20.rst
@@ -0,0 +1,349 @@
+CMake 3.20 Release Notes
+************************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.19 include the following.
+
+New Features
+============
+
+Presets
+-------
+
+* :manual:`cmake-presets(7)` gained support for build and test presets.
+
+Generators
+----------
+
+* :ref:`Makefile Generators`, for some toolchains, now use the compiler
+ to extract implicit dependencies while compiling source files.
+
+Languages
+---------
+
+* C++23 compiler modes may now be specified via the :prop_tgt:`CXX_STANDARD`,
+ :prop_tgt:`CUDA_STANDARD`, or :prop_tgt:`OBJCXX_STANDARD` target properties,
+ or via the :manual:`Compile Features <cmake-compile-features(7)>`
+ functionality's ``cxx_std_23`` meta-feature.
+
+* ``CUDA`` language support now works when ``nvcc`` is a symbolic link,
+ for example due to a ``ccache`` or ``colornvcc`` wrapper script.
+
+* The :envvar:`CUDAARCHS` environment variable was added for initializing
+ :variable:`CMAKE_CUDA_ARCHITECTURES`. Useful in cases where the compiler
+ default is unsuitable for the machine's GPU.
+
+Compilers
+---------
+
+* The NVIDIA HPC SDK compilers are now supported with compiler id ``NVHPC``.
+
+* The Intel oneAPI NextGen LLVM compilers are now supported with
+ compiler id ``IntelLLVM``:
+
+ * The ``icx``/``icpx`` C/C++ compilers on Linux, and the ``icx``
+ C/C++ compiler on Windows, are fully supported as of oneAPI 2021.1.
+
+ * The ``ifx`` Fortran compiler on Linux is partially supported.
+ As of oneAPI 2021.1, ``ifx`` does not define several identification
+ macros, so CMake identifies it as the classic ``Intel`` compiler.
+ This works in many cases because ``ifx`` accepts the same command line
+ parameters as ``ifort``. A future version of oneAPI may fix this.
+
+ * The ``ifx`` Fortran compiler on Windows is not yet supported.
+
+ The Intel oneAPI Classic compilers (``icc``, ``icpc``, and ``ifort``)
+ continue to be supported with compiler id ``Intel``.
+
+* Support was added for the IAR STM8 compiler.
+
+Platforms
+---------
+
+* CMake's support for :ref:`Cross Compiling for Android`
+ is now merged with the Android NDK's toolchain file.
+ They now have similar behavior, though some variable names differ.
+ User-facing changes include:
+
+ - ``find_*`` functions will search NDK ABI / API specific paths by default.
+
+ - The default :variable:`CMAKE_BUILD_TYPE` for Android is
+ now ``RelWithDebInfo``.
+
+ - The :variable:`CMAKE_ANDROID_NDK_VERSION` variable was added to
+ report the version of the NDK.
+
+File-Based API
+--------------
+
+* The :manual:`cmake-file-api(7)` gained a new "toolchains" object
+ kind that describes the compiler used for each enabled language.
+
+Commands
+--------
+
+* :command:`add_custom_command` and :command:`add_custom_target` now
+ support :manual:`generator expressions <cmake-generator-expressions(7)>`
+ in their ``OUTPUT`` and ``BYPRODUCTS`` options.
+
+ Their ``COMMAND``, ``WORKING_DIRECTORY``, and ``DEPENDS`` options gained
+ support for new generator expressions ``$<COMMAND_CONFIG:...>`` and
+ ``$<OUTPUT_CONFIG:...>`` that control cross-config handling when using
+ the :generator:`Ninja Multi-Config` generator.
+
+* The :command:`add_custom_command` command gained ``DEPFILE`` support on
+ :ref:`Makefile Generators`.
+
+* The :command:`add_library` command previously prohibited imported object
+ libraries when using potentially multi-architecture configurations.
+ This mostly affected the :generator:`Xcode` generator, e.g. when targeting
+ iOS or one of the other device platforms. This restriction has now been
+ removed.
+
+* The :command:`cmake_path` command was added for operations on
+ filesystem paths.
+
+* The :command:`configure_file` command gained ``USE_SOURCE_PERMISSIONS``
+ and ``FILE_PERMISSIONS`` options to support copying of permissions of the
+ source file and using specified permissions respectively.
+
+* The :command:`file(GENERATE)` command gained a ``NEWLINE_STYLE`` option to
+ specify how newlines are handled for the generated file.
+
+* The :command:`file(GENERATE)` command gained ``NO_SOURCE_PERMISSIONS``,
+ ``USE_SOURCE_PERMISSIONS``, and ``FILE_PERMISSIONS`` options for controlling
+ the permissions of the generated file.
+
+* The :command:`install(FILES)` command ``RENAME`` option learned to
+ support :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* The :command:`target_include_directories` command gained a new option
+ ``AFTER``.
+
+* The :command:`target_sources` command now supports targets created
+ by the :command:`add_custom_target` command.
+
+* The :command:`try_run` command gained a ``WORKING_DIRECTORY`` option to
+ set the working directory in which to run the compiled check executable.
+
+Variables
+---------
+
+* The :variable:`CMAKE_<LANG>_BYTE_ORDER` variable was added to provide the
+ target architecture byte order detected from the toolchain.
+
+* The :variable:`CMAKE_RUNTIME_OUTPUT_DIRECTORY`,
+ :variable:`CMAKE_LIBRARY_OUTPUT_DIRECTORY`, and
+ :variable:`CMAKE_ARCHIVE_OUTPUT_DIRECTORY` variables now support
+ target-dependent generator expressions.
+
+Properties
+----------
+
+* The :prop_tgt:`<LANG>_CLANG_TIDY` target property and the associated
+ :variable:`CMAKE_<LANG>_CLANG_TIDY` variable learned to support
+ the ``OBJC`` and ``OBJCXX`` languages.
+
+* The :prop_tgt:`EXPORT_COMPILE_COMMANDS` target property was added
+ for the associated :variable:`CMAKE_EXPORT_COMPILE_COMMANDS` variable
+ to allow for configuration of exporting compile commands per target.
+
+* The :prop_sf:`GENERATED` source-file property is now visible
+ from any directory scope, regardless of the scope in which it is set.
+ See policy :policy:`CMP0118`.
+
+* The :prop_tgt:`UNITY_BUILD_UNIQUE_ID` target property
+ was added to support generation of an identifier that is
+ unique per source file in unity builds. It can help to
+ resolve duplicate symbol problems with anonymous namespaces.
+
+* The :prop_tgt:`WIN32_EXECUTABLE` target property now works with Clang
+ on Windows.
+
+* The :prop_tgt:`XCODE_EMBED_FRAMEWORKS <XCODE_EMBED_<type>>` target property
+ was added to tell the :generator:`Xcode` generator to embed frameworks.
+ Aspects of the embedding can be customized with the
+ :prop_tgt:`XCODE_EMBED_FRAMEWORKS_PATH <XCODE_EMBED_<type>>`,
+ :prop_tgt:`XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY`, and
+ :prop_tgt:`XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY` target properties.
+
+Modules
+-------
+
+* The :module:`ExternalData` module :command:`ExternalData_Add_Target`
+ function gained a ``SHOW_PROGRESS <bool>`` option for controlling whether
+ or not to show progress output during the build.
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add` function
+ gained a ``CONFIGURE_HANDLED_BY_BUILD`` option. This can be used to make
+ subsequent runs of the configure step be triggered by the build step when
+ an external project dependency rebuilds instead of always re-running the
+ configure step in such cases.
+
+* The :module:`FindBoost` module gained a ``Boost_NO_WARN_NEW_VERSIONS``
+ option to silence the warning about unknown dependencies for new
+ Boost versions.
+
+* The :module:`FindCUDAToolkit` module gained support for finding CUDA
+ toolkits when ``nvcc`` is a symbolic link,
+ for example due to a ``ccache`` or ``colornvcc`` wrapper script.
+
+* The :module:`FindGDAL` module has been improved to document and mark as
+ advanced its cache variables. There is a new ``FindGDAL_SKIP_GDAL_CONFIG``
+ variable which may be used to skip over the ``gdal-config``-based search.
+ Users may also set ``GDAL_ADDITIONAL_LIBRARY_VERSIONS`` to add additional
+ versions to the library name search strategy.
+
+* The :module:`FindIntl` module now provides an imported target.
+
+* The :module:`FindOpenSSL` module learned to support a version range.
+
+* The :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+ modules gained options controlling how unversioned interpreter names are
+ searched.
+
+* The :module:`UseJava` module ``add_jar()`` command's
+ ``GENERATE_NATIVE_HEADERS`` feature gained options to export the
+ generated target.
+
+* The :module:`UseSWIG` module gained the capability, for
+ :ref:`Makefile <Makefile Generators>` and :ref:`Ninja <Ninja Generators>`
+ generators, to use the ``swig`` tool to generate implicit dependencies.
+
+Autogen
+-------
+
+* The :ref:`Qt AUTOMOC` feature now works with per-config sources.
+
+CTest
+-----
+
+* :manual:`ctest(1)` gained a ``--test-dir`` option to specify the directory
+ in which to look for tests.
+
+CPack
+-----
+
+* :module:`CPack` gained the :variable:`CPACK_THREADS` variable to
+ control the number of threads used for parallelized operations,
+ such as compressing the installer package.
+
+* The :cpack_gen:`CPack DEB Generator` learned a new
+ :variable:`CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS`
+ variable to specify additional search directories for
+ resolving private library dependencies when using
+ ``dpkg-shlibdeps``.
+
+* The :cpack_gen:`CPack IFW Generator` gained a new
+ :variable:`CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST` variable to
+ control visibility of the widget listing installer pages on the left side
+ of the wizard. This feature available only since QtIFW 4.0.
+
+* The :cpack_gen:`CPack NSIS Generator` gained new
+ :variable:`CPACK_NSIS_BRANDING_TEXT` and
+ :variable:`CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION` variables to change
+ the text at the bottom of the install window and change its trim position
+
+* The :cpack_gen:`CPack NSIS Generator` now correctly handles Unicode
+ characters. If you want to have a :variable:`CPACK_RESOURCE_FILE_LICENSE`
+ with UTF-8 characters, it needs to be encoded in UTF-8 BOM.
+
+* The :cpack_gen:`CPack NuGet Generator` gained options:
+
+ - :variable:`CPACK_NUGET_PACKAGE_ICON` and
+ :variable:`CPACK_NUGET_<compName>_PACKAGE_ICON`
+ allow package icons to be specified by local files.
+ - :variable:`CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION` and
+ :variable:`CPACK_NUGET_<compName>_PACKAGE_LICENSE_EXPRESSION` add
+ support for specifying licenses recognized by the
+ `Software Package Data Exchange`_ (SPDX).
+ - :variable:`CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME` and
+ :variable:`CPACK_NUGET_<compName>_PACKAGE_LICENSE_FILE_NAME` allow
+ licenses to be specified by local files.
+ - :variable:`CPACK_NUGET_PACKAGE_LANGUAGE` and
+ :variable:`CPACK_NUGET_<compName>_PACKAGE_LANGUAGE` allow the locale
+ for a package to be specified, for example ``en_CA``.
+
+.. _Software Package Data Exchange: https://spdx.org/
+
+Deprecated and Removed Features
+===============================
+
+* The :manual:`cmake-server(7)` mode has been removed.
+ Clients should use the :manual:`cmake-file-api(7)` instead.
+
+* The :module:`WriteCompilerDetectionHeader` module has been deprecated
+ via policy :policy:`CMP0120`. Projects should be ported away from it.
+
+* The :module:`TestBigEndian` module has been deprecated in favor
+ of the :variable:`CMAKE_<LANG>_BYTE_ORDER` variable.
+
+* The :module:`AddFileDependencies` module is deprecated.
+ Port projects to use :command:`set_property` directly.
+
+* The :cpack_gen:`CPack NuGet Generator` deprecated some variables to reflect
+ changes in the NuGet specification:
+
+ - :variable:`CPACK_NUGET_PACKAGE_ICONURL` and
+ :variable:`CPACK_NUGET_<compName>_PACKAGE_ICONURL` have been deprecated;
+ replace with a reference to a local icon file.
+ - :variable:`CPACK_NUGET_PACKAGE_LICENSEURL` and
+ :variable:`CPACK_NUGET_<compName>_PACKAGE_LICENSEURL` have been deprecated;
+ replace with a reference to the project's license file or SPDX
+ license expression.
+
+Other Changes
+=============
+
+* Source file extensions must now be explicit.
+ See policy :policy:`CMP0115` for details.
+
+* The :prop_sf:`LANGUAGE` source file property now forces compilation
+ as the specified language. See policy :policy:`CMP0119`.
+
+* On AIX, installation of XCOFF executables and shared libraries
+ no longer requires relinking to change the runtime search path
+ from the build-tree RPATH to the install-tree RPATH. CMake now
+ edits the XCOFF binaries directly during installation, as has
+ long been done on ELF platforms.
+
+* With MSVC-like compilers the value of
+ :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` no longer contains
+ the ``/GR`` flag for runtime type information by default.
+ See policy :policy:`CMP0117`.
+
+* Ninja generators now transform the ``DEPFILE`` generated by an
+ :command:`add_custom_command`. See policy :policy:`CMP0116` for details.
+
+* The precompiled Linux binaries provided on
+ `cmake.org <https://cmake.org/download/>`_ have changed their naming pattern
+ to ``cmake-$ver-linux-$arch``, where ``$arch`` is either ``x86_64`` or
+ ``aarch64``.
+
+* The precompiled Windows binaries provided on
+ `cmake.org <https://cmake.org/download/>`_ have changed their naming pattern
+ to ``cmake-$ver-windows-$arch``, where ``$arch`` is either ``x86_64`` or
+ ``i386``.
+
+Updates
+=======
+
+Changes made since CMake 3.20.0 include the following.
+
+3.20.1
+------
+
+* The :module:`FindIntl` module in CMake 3.20.0 added checks
+ ``Intl_HAVE_GETTEXT_BUILTIN``, ``Intl_HAVE_DCGETTEXT_BUILTIN``,
+ and ``Intl_IS_BUILTIN``, but they were not implemented correctly.
+ These have been removed and replaced with a single ``Intl_IS_BUILT_IN``
+ check, whose name is consistent with the :module:`FindIconv` module.
+
+* The ``-rpath`` linker flag is now specified as supported on all Apple
+ platforms, not just macOS. The ``install_name_dir`` used for
+ iOS, tvOS and watchOS should now default to ``@rpath`` instead of using
+ a full absolute path and failing at runtime when the library or framework
+ is embedded in an application bundle (see :prop_tgt:`XCODE_EMBED_<type>`).
diff --git a/Help/release/3.3.rst b/Help/release/3.3.rst
new file mode 100644
index 0000000..44f4e19
--- /dev/null
+++ b/Help/release/3.3.rst
@@ -0,0 +1,287 @@
+CMake 3.3 Release Notes
+***********************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.2 include the following.
+
+New Features
+============
+
+Generators
+----------
+
+* The :ref:`Makefile Generators` now add ``.DELETE_ON_ERROR`` to the
+ makefiles that contain the actual build rules for files on disk.
+ This tells GNU make to remove rule outputs when their recipe
+ modifies an output but fails.
+
+* The :ref:`Visual Studio Generators` learned to support ``.xaml``
+ source files and automatically associate them with corresponding
+ ``.h`` and ``.cpp`` sources.
+
+* A new experimental :generator:`Green Hills MULTI` generator was
+ added on Windows. `Green Hills MULTI`_ is an IDE for embedded
+ real-time systems.
+
+.. _`Green Hills MULTI`: http://www.ghs.com/products/MULTI_IDE.html
+
+Commands
+--------
+
+* The :command:`add_dependencies` command learned to allow dependencies
+ to be added to :ref:`interface libraries <Interface Libraries>`.
+ Dependencies added to an interface library are followed transitively
+ in its place since the target itself does not build.
+
+* The :command:`execute_process` command learned to support specifying
+ the same file for ``OUTPUT_FILE`` and ``ERROR_FILE``.
+
+* The :command:`file(GLOB)` and :command:`file(GLOB_RECURSE)` commands
+ learned a new ``LIST_DIRECTORIES <bool>`` option to specify whether
+ the glob result should include directories.
+
+* The :command:`find_library`, :command:`find_path`, and :command:`find_file`
+ commands now search in installation prefixes derived from the ``PATH``
+ environment variable.
+
+* The :command:`if` command learned a new ``IN_LIST`` operator that
+ evaluates to true if a given element is contained in a named list.
+
+* The :command:`install(EXPORT)` and :command:`export()` commands
+ learned to export targets that populate the :prop_tgt:`INTERFACE_SOURCES`
+ target property.
+
+* The :command:`install(TARGETS)` command learned to support
+ generator expressions in the ``DESTINATION`` value.
+
+Variables
+---------
+
+* The version of some Fortran compilers is now detected and stored in the
+ :variable:`CMAKE_Fortran_COMPILER_VERSION <CMAKE_<LANG>_COMPILER_VERSION>`
+ variable.
+
+* The :ref:`Visual Studio Generators` learned a new
+ :variable:`CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD` option
+ to put the ``INSTALL`` target in the default build of a
+ solution (``.sln``) file.
+
+Properties
+----------
+
+* A :prop_tgt:`CROSSCOMPILING_EMULATOR` target property and supporting
+ :variable:`CMAKE_CROSSCOMPILING_EMULATOR` variable were introduced
+ to allow target platform binaries to run on the host during cross
+ compiling.
+
+* A :prop_tgt:`<LANG>_INCLUDE_WHAT_YOU_USE` target property and supporting
+ :variable:`CMAKE_<LANG>_INCLUDE_WHAT_YOU_USE` variable were introduced
+ to tell the :ref:`Makefile Generators` and the :generator:`Ninja` generator
+ to run ``include-what-you-use`` along with the compiler for ``C`` and
+ ``CXX`` languages.
+
+* The :prop_tgt:`<LANG>_VISIBILITY_PRESET` and
+ :prop_tgt:`VISIBILITY_INLINES_HIDDEN` target properties now
+ affect compilation in sources of all target types. See
+ policy :policy:`CMP0063`.
+
+* The :prop_tgt:`XCODE_ATTRIBUTE_<an-attribute>` target property learned
+ to support generator expressions.
+
+Modules
+-------
+
+* The :module:`CheckFortranCompilerFlag` module was introduced
+ to check ``Fortran`` compiler flags, much like the
+ :module:`CheckCCompilerFlag` module already does for ``C``.
+
+* The :module:`ExternalData` module learned a new
+ :variable:`ExternalData_NO_SYMLINKS` option to disable use of
+ symbolic links to populate the real data files and use copies
+ instead.
+
+* The :module:`ExternalData` module learned a new ``RECURSE:``
+ option in ``DATA{}`` references specifying directories.
+ This allows an entire directory tree of associated files
+ to be matched.
+
+* The :module:`ExternalData` module learned a new URL template
+ placeholder ``%(algo:<key>)`` to allow custom mapping from
+ algorithm name to URL component through configuration of new
+ :variable:`ExternalData_URL_ALGO_<algo>_<key>` variables.
+ This allows more flexibility in remote URLs.
+
+* The :module:`ExternalProject` module learned to replace tokens
+ like ``<BINARY_DIR>`` in the ``BYPRODUCTS`` of each step.
+
+* The :module:`ExternalProject` module APIs learned to support
+ :manual:`generator expressions <cmake-generator-expressions(7)>`
+ when using ``LOG_*`` options and in CMake initial cache options.
+
+* The :module:`FindBoost` module now tracks the directories containing
+ libraries separately for RELEASE and DEBUG configurations.
+
+* The :module:`FindCUDA` module now defaults to using the static
+ CUDA runtime library if it is available. A new
+ ``CUDA_USE_STATIC_CUDA_RUNTIME`` option is offered to control
+ this behavior.
+
+* The :module:`FindMatlab` module was completely rewritten. It learned
+ about versions and components and to find Matlab in a more precise and
+ multiplatform way. The module now offers APIs to create mex extensions,
+ documentation, and unit tests.
+
+* The :module:`FindPackageHandleStandardArgs` module
+ ``FIND_PACKAGE_HANDLE_STANDARD_ARGS`` function now
+ always populates both the ``<PackageName>_FOUND``
+ and ``<UPPERCASE_NAME>_FOUND`` variables (the latter
+ for backwards compatibility). The ``FOUND_VAR``
+ option is now ignored except to enforce its allowed
+ values.
+
+* The :module:`InstallRequiredSystemLibraries` module learned a new
+ ``CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT`` option to specify the
+ installation component.
+
+Generator Expressions
+---------------------
+
+* A new ``COMPILE_LANGUAGE`` generator expression was introduced to
+ allow specification of compile options for target files based on the
+ :prop_sf:`LANGUAGE` of each source file. Due to limitations of the
+ underlying native build tools, this feature has varying support across
+ generators. See the :manual:`cmake-generator-expressions(7)` manual
+ for details.
+
+CTest
+-----
+
+* The :manual:`ctest(1)` tool learned a new ``--repeat-until-fail <n>``
+ option to help find sporadic test failures.
+
+* The :module:`CTestCoverageCollectGCOV` module learned to support
+ the same ``CTEST_CUSTOM_COVERAGE_EXCLUDE`` option as the
+ :command:`ctest_coverage` command.
+
+CPack
+-----
+
+* The :cpack_gen:`CPack IFW Generator` learned to support
+ Qt Framework Installer 2.0 tools.
+
+* The :cpack_gen:`CPack DEB Generator` learned a new
+ :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_SHLIBDEPS`
+ variable to specify per-component use of ``dpkg-shlibdeps``.
+
+* The :cpack_gen:`CPack DEB Generator` learned a new
+ :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_DEPENDS`
+ option to specify per-component dependencies.
+
+* The :cpack_gen:`CPack RPM Generator` learned to package symbolic links
+ more cleanly and now supports directory symlinks with recent
+ ``rpmbuild`` versions.
+
+* The :cpack_gen:`CPack RPM Generator` learned a new
+ :variable:`CPACK_RPM_ADDITIONAL_MAN_DIRS` variable to specify
+ directories containing man pages for the brp-compress RPM macro.
+
+* The :cpack_gen:`CPack RPM Generator` learned a new
+ :variable:`CPACK_RPM_<component>_PACKAGE_ARCHITECTURE` variable
+ to specify a component-specific package architecture.
+
+* The CPack WIX generator learned the new
+ :prop_inst:`CPACK_START_MENU_SHORTCUTS`,
+ :prop_inst:`CPACK_DESKTOP_SHORTCUTS` and
+ :prop_inst:`CPACK_STARTUP_SHORTCUTS` installed file properties which can
+ be used to install shortcuts in the Start Menu, on the Desktop and
+ in the Startup Folder respectively.
+
+Other
+-----
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ is now aware of features supported by GNU compilers on Windows, versions
+ 4.4 through 5.0.
+
+* The :manual:`cmake(1)` ``-E tar`` command learned a new
+ ``--format<format>`` option to specify the archive format to
+ be written.
+
+* On OS X, CMake learned to create XCTest bundles to test Frameworks
+ and App Bundles within Xcode. The :module:`FindXCTest` module
+ provides convenience functions to handle :prop_tgt:`XCTEST` bundles.
+
+Deprecated and Removed Features
+===============================
+
+* On OS X the :manual:`cmake-gui(1)` no longer has the
+ ``Install For Command Line Use`` menu item. Instead there
+ is a ``How to Install For Command Line Use`` menu item
+ that shows an informational dialog box explaining how to
+ make the command line tools available. For example::
+
+ /Applications/CMake.app/Contents/bin/cmake-gui --install
+
+* The :command:`ctest_build` and :command:`build_command` commands
+ no longer tell ``make`` tools to ignore errors with the ``-i`` option.
+ Previously this was done for :ref:`Makefile Generators` but not others.
+ See policy :policy:`CMP0061`.
+
+* The :generator:`Visual Studio 10 2010` generator no longer checks
+ for running VS IDEs with the project open or asks them to reload.
+ This was originally done for VS 10 because it had been done for
+ VS 7 through 9 to avoid prompting for every project in a solution.
+ Since VS >= 10 allow the whole solution to reload at once they
+ do not need CMake to help them.
+
+* The :generator:`Visual Studio 7` generator (.NET 2002) is now
+ deprecated and will be removed in a future version of CMake.
+
+* The :generator:`Visual Studio 6` generator is now deprecated
+ and will be removed in a future version of CMake.
+
+* The :command:`find_package` command no longer considers project
+ build trees recently configured in a :manual:`cmake-gui(1)`.
+ This was previously done only on Windows and is now never done.
+ The ``NO_CMAKE_BUILDS_PATH`` option is now ignored if given
+ and effectively always on.
+ Projects may populate the :ref:`User Package Registry` to aid
+ users building multiple dependent projects one after another.
+
+* The :command:`add_definitions()` command no longer causes a
+ :prop_dir:`DEFINITIONS` directory property to be populated. See policy
+ :policy:`CMP0059`.
+
+* With Visual Studio 7, 8, and 9 generators the value of the ``$(OutDir)``
+ placeholder no longer evaluates to the configuration name. Projects
+ should use ``$(ConfigurationName)`` for that instead.
+
+* Using the output of :command:`export()` with the :command:`install(FILES)`
+ command is no longer allowed. See policy :policy:`CMP0062` for details.
+
+Other Changes
+=============
+
+* The :generator:`Ninja` generator now requires that calls to the
+ :command:`add_custom_command` and :command:`add_custom_target`
+ commands use the ``BYPRODUCTS`` option to explicitly specify any
+ files generated by the custom commands that are not listed as
+ outputs (perhaps because their timestamps are allowed to be older
+ than the inputs). See policy :policy:`CMP0058`.
+
+* Build-time progress output of :ref:`Makefile Generators` has been improved.
+ It no longer mixes progress and build rule messages during parallel builds.
+ The link rule messages now have progress and are displayed as bold green
+ instead of bold red (since red is often associated with an error message).
+
+* The :variable:`CMAKE_CFG_INTDIR` variable value for Visual Studio
+ 7, 8, and 9 is now ``$(ConfigurationName)`` instead of ``$(OutDir)``.
+ This should have no effect on the intended use cases of the variable.
+
+* Linking to library files by a full path in an implicit linker search
+ directory (e.g. ``/usr/lib/libfoo.a``) no longer asks the linker to
+ search for the library (e.g. ``-lfoo``) and now links by full path.
+ See policy :policy:`CMP0060`.
diff --git a/Help/release/3.4.rst b/Help/release/3.4.rst
new file mode 100644
index 0000000..943d267
--- /dev/null
+++ b/Help/release/3.4.rst
@@ -0,0 +1,273 @@
+CMake 3.4 Release Notes
+***********************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.3 include the following.
+
+New Features
+============
+
+Generators
+----------
+
+* The :generator:`Visual Studio 14 2015` generator learned to select
+ a Windows 10 SDK based on the value of the :variable:`CMAKE_SYSTEM_VERSION`
+ variable and the SDKs available on the host.
+
+* CMake learned rudimentary support for the Apple Swift language. When using
+ the :generator:`Xcode` generator with Xcode 6.1 or higher, one may enable
+ the ``Swift`` language with the :command:`enable_language` command or the
+ :command:`project` command (this is an error with other generators or when
+ Xcode is too old). Then one may list ``.swift`` source files in targets
+ for compilation.
+
+Commands
+--------
+
+* The :command:`find_program` command learned a ``NAMES_PER_DIR``
+ option to consider all given ``NAMES`` in each directory before
+ moving on to the next directory.
+
+* The :command:`get_filename_component` command learned a new ``BASE_DIR``
+ subcommand. This is used to specify a base directory when calculating an
+ absolute path from a relative path.
+
+* The :command:`if` command learned a new ``TEST`` operator that evaluates
+ to true if a given test name has been defined by the :command:`add_test`
+ command. See policy :policy:`CMP0064`.
+
+* The :command:`install(DIRECTORY)` command ``DESTINATION`` option learned to
+ support :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* The :command:`install(FILES)` command ``DESTINATION`` option learned to
+ support :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* The :command:`string` command learned a new ``APPEND`` subcommand.
+
+Variables
+---------
+
+* The :ref:`Makefile Generators` and the :generator:`Ninja` generator
+ learned to add compiler launcher tools like distcc and ccache along
+ with the compiler for ``C`` and ``CXX`` languages. See the
+ :variable:`CMAKE_<LANG>_COMPILER_LAUNCHER` variable and
+ :prop_tgt:`<LANG>_COMPILER_LAUNCHER` target property for details.
+
+* New :variable:`CMAKE_LINK_SEARCH_START_STATIC` and
+ :variable:`CMAKE_LINK_SEARCH_END_STATIC` variables were
+ introduced to initialize the
+ :prop_tgt:`LINK_SEARCH_START_STATIC` and
+ :prop_tgt:`LINK_SEARCH_END_STATIC` target properties,
+ respectively.
+
+Properties
+----------
+
+* :ref:`Visual Studio Generators` learned to support additional
+ target properties to customize projects for NVIDIA Nsight
+ Tegra Visual Studio Edition:
+
+ * :prop_tgt:`ANDROID_ANT_ADDITIONAL_OPTIONS`
+ * :prop_tgt:`ANDROID_ARCH`
+ * :prop_tgt:`ANDROID_ASSETS_DIRECTORIES`
+ * :prop_tgt:`ANDROID_JAR_DEPENDENCIES`
+ * :prop_tgt:`ANDROID_JAR_DIRECTORIES`
+ * :prop_tgt:`ANDROID_JAVA_SOURCE_DIR`
+ * :prop_tgt:`ANDROID_NATIVE_LIB_DEPENDENCIES`
+ * :prop_tgt:`ANDROID_NATIVE_LIB_DIRECTORIES`
+ * :prop_tgt:`ANDROID_PROCESS_MAX`
+ * :prop_tgt:`ANDROID_PROGUARD`
+ * :prop_tgt:`ANDROID_PROGUARD_CONFIG_PATH`
+ * :prop_tgt:`ANDROID_SECURE_PROPS_PATH`
+ * :prop_tgt:`ANDROID_SKIP_ANT_STEP`
+ * :prop_tgt:`ANDROID_STL_TYPE`
+
+* The :prop_tgt:`ARCHIVE_OUTPUT_DIRECTORY`,
+ :prop_tgt:`LIBRARY_OUTPUT_DIRECTORY`, and
+ :prop_tgt:`RUNTIME_OUTPUT_DIRECTORY` target properties learned to
+ support :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* The :prop_tgt:`SOURCE_DIR` and :prop_tgt:`BINARY_DIR` target properties
+ were introduced to allow project code to query where a target is defined.
+
+* The :prop_tgt:`OUTPUT_NAME` target property and its variants learned to
+ support :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* A :prop_gbl:`TARGET_MESSAGES` global property was added to tell the
+ :ref:`Makefile Generators` whether to generate commands to print output
+ after each target is completed.
+
+* On Windows with MS-compatible tools, CMake learned to optionally
+ generate a module definition (``.def``) file for ``SHARED`` libraries.
+ See the :prop_tgt:`WINDOWS_EXPORT_ALL_SYMBOLS` target property.
+
+Modules
+-------
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add`
+ function ``GIT_SUBMODULES`` option now also limits the set of
+ submodules that are initialized in addition to the prior behavior
+ of limiting the set of submodules that are updated.
+
+* The :module:`ExternalProject` module learned new ``USES_TERMINAL``
+ arguments for giving steps exclusive terminal access. This is
+ useful with the :generator:`Ninja` generator to monitor CMake
+ superbuild progress and prevent CPU oversubscription.
+
+* The :module:`FindBISON` module ``BISON_TARGET`` macro learned a
+ new ``DEFINES_FILE`` option to specify a custom output header
+ to be generated.
+
+* The :module:`FindHDF5` module learend a new ``HDF5_PREFER_PARALLEL``
+ option allowing users to specify that a parallel HDF5 tool is
+ preferred if both are available.
+
+* The :module:`FindIce` module now provides imported targets.
+
+* The :module:`FindJava` module learned to optionally find
+ the ``idlj`` and ``jarsigner`` tools.
+
+* The :module:`FindOpenSSL` module now provides imported targets.
+
+* The :module:`FindOpenSSL` module learned a new ``OPENSSL_USE_STATIC_LIBS``
+ option to search only for static libraries.
+
+* The :module:`FindPkgConfig` learned a new :command:`pkg_get_variable`
+ command which may be used to query for arbitrary variables from a package
+ (such as for related tools or data and plugin install paths).
+
+* The :module:`FindProtobuf` module gained a new
+ :command:`protobuf_generate_python` function to generate python
+ sources from ``.proto`` files.
+
+* The :module:`FindTIFF` module learned to search separately for
+ debug and release variants.
+
+* The :module:`FindwxWidgets` module learned to support version requests.
+
+* The :module:`FindXercesC` module learned to search separately for
+ debug and release variants.
+
+* The :module:`FindZLIB` module learned to search separately for
+ debug and release variants.
+
+* The :module:`GNUInstallDirs` module learned special default values
+ for certain installation prefixes according to the `GNU Coding
+ Standards`_ and the `Filesystem Hierarchy Standard`_.
+
+* The :module:`UseJava` module ``add_jar`` function learned
+ to support response files (e.g. ``@srcs.txt``) for source
+ specification.
+
+* The :module:`UseJava` module ``install_jar`` function learned
+ new ``DESTINATION`` and ``COMPONENT`` options to specify
+ the corresponding :command:`install` command options.
+
+* The :module:`UseJava` module gained a new ``create_javah``
+ function to create C headers from Java classes.
+
+.. _`GNU Coding Standards`: https://www.gnu.org/prep/standards/html_node/Directory-Variables.html
+.. _`Filesystem Hierarchy Standard`: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html
+
+Generator Expressions
+---------------------
+
+* A new ``$<SHELL_PATH:...>``
+ :manual:`generator expression <cmake-generator-expressions(7)>`
+ has been added.
+
+CTest
+-----
+
+* CTest learned to optionally measure the CPU load during parallel
+ testing and avoid starting tests that may cause the load to exceed
+ a given threshold. See the :manual:`ctest(1)` command ``--test-load``
+ option, the ``TestLoad`` setting of the :ref:`CTest Test Step`,
+ the :variable:`CTEST_TEST_LOAD` variable, and the ``TEST_LOAD``
+ option of the :command:`ctest_test` command.
+
+* :manual:`ctest(1)` learned options
+ ``--test-output-size-passed`` and ``--test-output-size-failed``
+ to customize the limit on test output size submitted when
+ running as a :ref:`Dashboard Client`.
+
+CPack
+-----
+
+* The :cpack_gen:`CPack DEB Generator` learned to set package dependencies
+ per component. See variables:
+
+ * :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_BREAKS`
+ * :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_CONFLICTS`
+ * :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_ENHANCES`
+ * :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_PREDEPENDS`
+ * :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_PROVIDES`
+ * :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_RECOMMENDS`
+ * :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_REPLACES`
+ * :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_SUGGESTS`
+
+* The :module:`CPack` module learned to package empty directories.
+
+* The :module:`CPack` module gained a new setting, ``CPACK_VERBATIM_VARIABLES``,
+ which can be used to ensure the cpack program receives the settings' values
+ exactly as they were set, even if they contain CMake-special characters.
+ For compatibility, it's off by default.
+
+Other
+-----
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ is now aware of features supported by GNU C compilers on Windows.
+
+* CMake learned to honor ``*.manifest`` source files with MSVC tools.
+ Manifest files named as sources of ``.exe`` and ``.dll`` targets
+ will be merged with linker-generated manifests and embedded in the
+ binary.
+
+* The `Concurrent Fortran 77 <https://ccur.com>`__ compiler is now supported.
+ Its :variable:`compiler id <CMAKE_<LANG>_COMPILER_ID>` is ``CCur``.
+
+* :manual:`cmake(1)` gained a new ``--trace-expand`` command line option
+ that is like ``--trace`` but expands variable references in the output.
+
+Deprecated and Removed Features
+===============================
+
+* The :module:`CMakeExpandImportedTargets` module is now documented
+ as deprecated. See module documentation for an explanation.
+
+* The :variable:`CMAKE_USE_RELATIVE_PATHS` variable no longer has any
+ effect. Previously it was partially implemented and unreliable.
+
+Other Changes
+=============
+
+* The :module:`CheckFunctionExists`, :module:`CheckLibraryExists`,
+ :module:`CheckSymbolExists`, and :module:`FindThreads` modules learned to
+ work in environments where only CXX is enabled.
+
+* The :cpack_gen:`CPack DEB Generator` now correctly excludes symlinks
+ during package checksum calculation.
+
+* The :cpack_gen:`CPack DEB Generator` no longer uses fakeroot and
+ system tar program for packaging.
+
+* The :module:`CPack` module no longer mangles settings with CMake-special
+ characters when they're used as defaults for other settings. The macro
+ ``cpack_set_if_not_set``, which was responsible for this, is now deprecated.
+
+* CMake no longer links executables with flags to export symbols
+ unless the :prop_tgt:`ENABLE_EXPORTS` target property is set.
+ See policy :policy:`CMP0065`.
+
+* The ``SONAME`` field is no longer set for ``MODULE`` libraries
+ created with the :command:`add_library` command. ``MODULE``
+ libraries are meant for explicit dynamic loading at runtime.
+ They cannot be linked so ``SONAME`` is not useful.
+
+* The internal :variable:`CMAKE_<LANG>_COMPILE_OBJECT` rule variable now
+ substitutes compiler include flags in a separate ``<INCLUDES>`` placeholder
+ instead of the main ``<FLAGS>`` placeholder.
diff --git a/Help/release/3.5.rst b/Help/release/3.5.rst
new file mode 100644
index 0000000..58a5d4e
--- /dev/null
+++ b/Help/release/3.5.rst
@@ -0,0 +1,187 @@
+CMake 3.5 Release Notes
+***********************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.4 include the following.
+
+New Features
+============
+
+GUI
+---
+
+* The :manual:`cmake-gui(1)` gained options to control warnings about
+ deprecated functionality.
+
+* The :manual:`cmake-gui(1)` learned an option to set the toolset
+ to be used with VS IDE and Xcode generators, much like the
+ existing ``-T`` option to :manual:`cmake(1)`.
+
+* The :manual:`cmake-gui(1)` gained a Regular Expression Explorer which
+ may be used to create and evaluate regular expressions in real-time.
+ The explorer window is available via the ``Tools`` menu.
+
+Command-Line
+------------
+
+* The ``-Wdev`` and ``-Wno-dev`` :manual:`cmake(1)` options now also enable
+ and suppress the deprecated warnings output by default.
+
+* The suppression of developer warnings as errors can now be controlled with
+ the new ``-Werror=dev`` and ``-Wno-error=dev`` :manual:`cmake(1)` options.
+
+* The :manual:`cmake(1)` ``-E`` command-line tools ``copy``,
+ ``copy_if_different``, ``copy_directory``, and ``make_directory``
+ learned to support multiple input files or directories.
+
+Commands
+--------
+
+* The :command:`cmake_parse_arguments` command is now implemented natively.
+ The :module:`CMakeParseArguments` module remains as an empty placeholder
+ for compatibility.
+
+* The :command:`install(DIRECTORY)` command learned to support
+ :manual:`generator expressions <cmake-generator-expressions(7)>`
+ in the list of directories.
+
+Variables
+---------
+
+* The :variable:`CMAKE_ERROR_DEPRECATED` variable can now be set using the
+ ``-Werror=deprecated`` and ``-Wno-error=deprecated`` :manual:`cmake(1)`
+ options.
+
+* The :variable:`CMAKE_WARN_DEPRECATED` variable can now be set using the
+ ``-Wdeprecated`` and ``-Wno-deprecated`` :manual:`cmake(1)` options.
+
+Properties
+----------
+
+* The :prop_tgt:`VS_GLOBAL_<variable>` target property is now implemented
+ for VS 2010 and above. Previously it worked only in VS 2008 and below.
+
+Modules
+-------
+
+* The :module:`ExternalProject` module learned a new ``GIT_REMOTE_NAME``
+ option to control the ``git clone --origin`` value.
+
+* The :module:`FindBoost` module now provides imported targets
+ such as ``Boost::boost`` and ``Boost::filesystem``.
+
+* The :module:`FindFLEX` module ``FLEX_TARGET`` macro learned a
+ new ``DEFINES_FILE`` option to specify a custom output header
+ to be generated.
+
+* The :module:`FindGTest` module now provides imported targets.
+
+* The :module:`FindGTK2` module, when ``GTK2_USE_IMPORTED_TARGETS`` is
+ enabled, now sets ``GTK2_LIBRARIES`` to contain the list of imported
+ targets instead of the paths to the libraries. Moreover it now sets
+ a new ``GTK2_TARGETS`` variable containing all the targets imported.
+
+* The :module:`FindOpenMP` module learned to support Clang.
+
+* The :module:`FindOpenSSL` module gained a new
+ ``OPENSSL_MSVC_STATIC_RT`` option to search for libraries using
+ the MSVC static runtime.
+
+* The :module:`FindPNG` module now provides imported targets.
+
+* The :module:`FindTIFF` module now provides imported targets.
+
+* A :module:`FindXalanC` module was introduced to find the
+ Apache Xalan-C++ XSL transform processing library.
+
+* The :module:`FindXercesC` module now provides imported targets.
+
+Platforms
+---------
+
+* Support was added for the ARM Compiler (arm.com) with compiler id ``ARMCC``.
+
+* A new platform file for cross-compiling in the Cray Linux Environment to
+ target compute nodes was added. See
+ :ref:`Cross Compiling for the Cray Linux Environment <Cray Cross-Compile>`
+ for usage details.
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ is now aware of features supported by Clang compilers on Windows (MinGW).
+
+* When building for embedded Apple platforms like iOS CMake learned to build and
+ install combined targets which contain both a device and a simulator build.
+ This behavior can be enabled by setting the :prop_tgt:`IOS_INSTALL_COMBINED`
+ target property.
+
+CPack
+-----
+
+* The :cpack_gen:`CPack DragNDrop Generator` learned new variable to
+ specify AppleScript file run to customize appearance of ``DragNDrop``
+ installer folder, including background image setting using supplied
+ PNG or multi-resolution TIFF file.
+ See the :variable:`CPACK_DMG_DS_STORE_SETUP_SCRIPT` and
+ :variable:`CPACK_DMG_BACKGROUND_IMAGE` variables.
+
+* The :cpack_gen:`CPack DEB Generator` learned to set the optional config
+ file ``Source`` field using a monolithic or per-component variable.
+ See :variable:`CPACK_DEBIAN_PACKAGE_SOURCE`.
+
+* The :cpack_gen:`CPack DEB Generator` learned to set Package, Section
+ and Priority control fields per-component.
+ See variables :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_SECTION` and
+ :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_PRIORITY`.
+
+* The :cpack_gen:`CPack DragNDrop Generator` learned to add
+ multi-lingual SLAs to a DMG which is presented to the user when they try to
+ mount the DMG. See the :variable:`CPACK_DMG_SLA_LANGUAGES` and
+ :variable:`CPACK_DMG_SLA_DIR` variables for details.
+
+* The :cpack_gen:`CPack NSIS Generator` learned new variables to
+ add bitmaps to the installer.
+ See the :variable:`CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP`
+ and :variable:`CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP` variables.
+
+* The :cpack_gen:`CPack RPM Generator` learned to set Name and Group
+ control fields per-component.
+ See :variable:`CPACK_RPM_<component>_PACKAGE_NAME`
+ and :variable:`CPACK_RPM_<component>_PACKAGE_GROUP`.
+
+Other
+-----
+
+* Warnings about deprecated functionality are now enabled by default.
+ They may be suppressed with ``-Wno-deprecated`` or by setting the
+ :variable:`CMAKE_WARN_DEPRECATED` variable to false.
+
+Deprecated and Removed Features
+===============================
+
+* The :manual:`cmake(1)` ``-E time`` command now properly passes arguments
+ with spaces or special characters through to the child process. This
+ may break scripts that worked around the bug with their own extra
+ quoting or escaping.
+
+* The :generator:`Xcode` generator was fixed to escape backslashes in
+ strings consistently with other generators. Projects that previously
+ worked around the inconsistecy with an extra level of backslashes
+ conditioned on the Xcode generator must be updated to remove the
+ workaround for CMake 3.5 and greater.
+
+Other Changes
+=============
+
+* The :generator:`Visual Studio 14 2015` generator learned to map the
+ ``/debug:fastlink`` linker flag to the ``.vcxproj`` file property.
+
+* The :module:`FindGTK2` module now configures the ``GTK2::sigc++`` imported
+ target to enable c++11 on its dependents when using sigc++ 2.5.1 or higher.
+
+* The precompiled Windows binary provided on ``cmake.org`` is now a
+ ``.msi`` package instead of an installer executable. One may need
+ to manually uninstall CMake versions lower than 3.5 before installing
+ the new package.
diff --git a/Help/release/3.6.rst b/Help/release/3.6.rst
new file mode 100644
index 0000000..f0add07
--- /dev/null
+++ b/Help/release/3.6.rst
@@ -0,0 +1,318 @@
+CMake 3.6 Release Notes
+***********************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.5 include the following.
+
+New Features
+============
+
+Generators
+----------
+
+* The :generator:`Ninja` generator learned to produce phony targets
+ of the form ``sub/dir/all`` to drive the build of a subdirectory.
+ This is equivalent to ``cd sub/dir; make all`` with
+ :ref:`Makefile Generators`.
+
+* The :generator:`Ninja` generator now includes system header files in build
+ dependencies to ensure correct re-builds when system packages are updated.
+
+* The :generator:`Visual Studio 14 2015` generator learned to support the
+ Clang/C2 toolsets, e.g. with the ``-T v140_clang_3_7`` option.
+ This feature is experimental.
+
+Commands
+--------
+
+* The :command:`add_custom_command` and :command:`add_custom_target` commands
+ learned how to use the :prop_tgt:`CROSSCOMPILING_EMULATOR` executable
+ target property.
+
+* The :command:`install` command learned a new ``EXCLUDE_FROM_ALL`` option
+ to leave installation rules out of the default installation.
+
+* The :command:`list` command gained a ``FILTER`` sub-command to filter
+ list elements by regular expression.
+
+* The :command:`string(TIMESTAMP)` and :command:`file(TIMESTAMP)`
+ commands gained support for the ``%s`` placeholder. This is
+ the number of seconds since the UNIX Epoch.
+
+Variables
+---------
+
+* A :variable:`CMAKE_DEPENDS_IN_PROJECT_ONLY` variable was introduced
+ to tell :ref:`Makefile Generators` to limit dependency scanning only
+ to files in the project source and build trees.
+
+* A new :variable:`CMAKE_HOST_SOLARIS` variable was introduced to
+ indicate when CMake is running on an Oracle Solaris host.
+
+* A :variable:`CMAKE_<LANG>_STANDARD_INCLUDE_DIRECTORIES` variable was
+ added for use by toolchain files to specify system include directories
+ to be appended to all compiler command lines.
+
+* The :variable:`CMAKE_<LANG>_STANDARD_LIBRARIES` variable is now documented.
+ It is intended for use by toolchain files to specify system libraries to be
+ added to all linker command lines.
+
+* A :variable:`CMAKE_NINJA_OUTPUT_PATH_PREFIX` variable was introduced
+ to tell the :generator:`Ninja` generator to configure the generated
+ ``build.ninja`` file for use as a ``subninja``.
+
+* A :variable:`CMAKE_TRY_COMPILE_PLATFORM_VARIABLES` variable was
+ added for use by toolchain files to specify platform-specific
+ variables that must be propagated by the :command:`try_compile`
+ command into test projects.
+
+* A :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable was added
+ to optionally tell the :command:`try_compile` command to build
+ a static library instead of an executable. This is useful for
+ cross-compiling toolchains that cannot link binaries without
+ custom flags or scripts.
+
+Properties
+----------
+
+* A :prop_tgt:`DEPLOYMENT_REMOTE_DIRECTORY` target property was introduced
+ to tell the :generator:`Visual Studio 9 2008` and
+ :generator:`Visual Studio 8 2005` generators to generate the "remote
+ directory" for WinCE project deployment and debugger settings.
+
+* A :prop_tgt:`<LANG>_CLANG_TIDY` target property and supporting
+ :variable:`CMAKE_<LANG>_CLANG_TIDY` variable were introduced to tell the
+ :ref:`Makefile Generators` and the :generator:`Ninja` generator to run
+ ``clang-tidy`` along with the compiler for ``C`` and ``CXX`` languages.
+
+* A :prop_test:`TIMEOUT_AFTER_MATCH` test property was introduced to
+ optionally tell CTest to enforce a secondary timeout after matching
+ certain output from a test.
+
+* A :prop_tgt:`VS_CONFIGURATION_TYPE` target property was introduced
+ to specify a custom project file type for :ref:`Visual Studio Generators`
+ supporting VS 2010 and above.
+
+* A :prop_dir:`VS_STARTUP_PROJECT` directory property was introduced
+ to specify for :ref:`Visual Studio Generators` the default startup
+ project for generated solutions (``.sln`` files).
+
+Modules
+-------
+
+* The :module:`CMakePushCheckState` module now pushes/pops/resets the variable
+ ``CMAKE_EXTRA_INCLUDE_FILE`` used in :module:`CheckTypeSize`.
+
+* The :module:`ExternalProject` module leared the ``GIT_SHALLOW 1``
+ option to perform a shallow clone of a Git repository.
+
+* The :module:`ExternalProject` module learned to initialize Git submodules
+ recursively and also to initialize new submodules on updates. Use the
+ ``GIT_SUBMODULES`` option to restrict which submodules are initialized and
+ updated.
+
+* The :module:`ExternalProject` module leared the ``DOWNLOAD_NO_EXTRACT 1``
+ argument to skip extracting the file that is downloaded (e.g., for
+ self-extracting shell installers or ``.msi`` files).
+
+* The :module:`ExternalProject` module now uses ``TLS_VERIFY`` when fetching
+ from git repositories.
+
+* The :module:`FindBLAS` and :module:`FindLAPACK` modules learned to
+ support `OpenBLAS <http://www.openblas.net>`__.
+
+* The :module:`FindCUDA` module learned to find the ``cublas_device`` library.
+
+* The :module:`FindGTest` module ``gtest_add_tests`` function now causes
+ CMake to automatically re-run when test sources change so that they
+ can be re-scanned.
+
+* The :module:`FindLTTngUST` module was introduced to find the LTTng-UST
+ library.
+
+* The :module:`FindPkgConfig` module learned to optionally create imported
+ targets for the libraries it has found.
+
+* The :module:`FindProtobuf` module learned to provide a ``Protobuf_VERSION``
+ variable and check the version number requested in a :command:`find_package`
+ call.
+
+* The :module:`InstallRequiredSystemLibraries` module learned a new
+ ``CMAKE_INSTALL_UCRT_LIBRARIES`` option to enable app-local deployment
+ of the Windows Universal CRT libraries with Visual Studio 2015.
+
+Platforms
+---------
+
+* The Clang compiler is now supported on CYGWIN.
+
+* Support was added for the Bruce C Compiler with compiler id ``Bruce``.
+
+CTest
+-----
+
+* The :command:`ctest_update` command now looks at the
+ :variable:`CTEST_GIT_INIT_SUBMODULES` variable to determine whether
+ submodules should be updated or not before updating.
+
+* The :command:`ctest_update` command will now synchronize submodules on an
+ update. Updates which add submodules or change a submodule's URL will now be
+ pulled properly.
+
+CPack
+-----
+
+* The :cpack_gen:`CPack DEB Generator` learned how to handle ``$ORIGIN``
+ in ``CMAKE_INSTALL_RPATH`` when :variable:`CPACK_DEBIAN_PACKAGE_SHLIBDEPS`
+ is used for dependency auto detection.
+
+* The :cpack_gen:`CPack DEB Generator` learned how to generate
+ ``DEBIAN/shlibs`` contorl file when package contains shared libraries.
+
+* The :cpack_gen:`CPack DEB Generator` learned how to generate
+ ``DEBIAN/postinst`` and ``DEBIAN/postrm`` files if the package installs
+ libraries in ldconfig-controlled locations (e.g. ``/lib/``, ``/usr/lib/``).
+
+* The :cpack_gen:`CPack DEB Generator` learned how to generate dependencies
+ between Debian packages if multi-component setup is used and
+ :variable:`CPACK_COMPONENT_<compName>_DEPENDS` variables are set.
+ For backward compatibility this feature is disabled by default.
+ See :variable:`CPACK_DEBIAN_ENABLE_COMPONENT_DEPENDS`.
+
+* The :cpack_gen:`CPack DEB Generator` learned how to set custom package
+ file names including how to generate properly-named Debian packages::
+
+ <PackageName>_<VersionNumber>-<DebianRevisionNumber>_<DebianArchitecture>.deb
+
+ For backward compatibility this feature is disabled by default. See
+ :variable:`CPACK_DEBIAN_FILE_NAME` and
+ :variable:`CPACK_DEBIAN_<COMPONENT>_FILE_NAME`.
+
+* The :cpack_gen:`CPack DEB Generator` learned how to set the package
+ release number (``DebianRevisionNumber`` in package file name when
+ used in combination with ``DEB-DEFAULT`` value set by
+ :variable:`CPACK_DEBIAN_FILE_NAME`).
+ See :variable:`CPACK_DEBIAN_PACKAGE_RELEASE`.
+
+* The :cpack_gen:`CPack DEB Generator` learned how to set the package
+ architecture per-component.
+ See :variable:`CPACK_DEBIAN_<COMPONENT>_PACKAGE_ARCHITECTURE`.
+
+* The :cpack_gen:`CPack DragNDrop Generator` learned a new option to skip the
+ ``/Applications`` symlink.
+ See the :variable:`CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK` variable.
+
+* The :module:`CPackIFW` module gained a new
+ :command:`cpack_ifw_update_repository` command to update a QtIFW-specific
+ repository from a remote repository.
+
+* The :cpack_gen:`CPack RPM Generator` learned how to set RPM ``dist`` tag
+ as part of RPM ``Release:`` tag when enabled (mandatory on some Linux
+ distributions for e.g. on Fedora).
+ See :variable:`CPACK_RPM_PACKAGE_RELEASE_DIST`.
+
+* The :cpack_gen:`CPack RPM Generator` learned how to set default values
+ for owning user/group and file/directory permissions of package content.
+ See :variable:`CPACK_RPM_DEFAULT_USER`, :variable:`CPACK_RPM_DEFAULT_GROUP`,
+ :variable:`CPACK_RPM_DEFAULT_FILE_PERMISSIONS`,
+ :variable:`CPACK_RPM_DEFAULT_DIR_PERMISSIONS` and their per component
+ counterparts.
+
+* The :cpack_gen:`CPack RPM Generator` learned how to set user defined
+ package file names, how to specify that rpmbuild should decide on file
+ name format as well as handling of multiple rpm packages generated by a
+ single user defined spec file.
+ See :variable:`CPACK_RPM_PACKAGE_NAME` and
+ :variable:`CPACK_RPM_<component>_PACKAGE_NAME`.
+
+* The :cpack_gen:`CPack RPM Generator` learned how to correctly handle symlinks
+ that are pointing outside generated packages.
+
+Other
+-----
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ is now aware of features supported by Intel C++ compilers versions 12.1
+ through 16.0 on UNIX platforms.
+
+Deprecated and Removed Features
+===============================
+
+* The :module:`CMakeForceCompiler` module and its macros are now deprecated.
+ See module documentation for an explanation.
+
+* The :command:`find_library`, :command:`find_path`, and :command:`find_file`
+ commands no longer search in installation prefixes derived from the ``PATH``
+ environment variable on non-Windows platforms. This behavior was added in
+ CMake 3.3 to support Windows hosts but has proven problematic on UNIX hosts.
+ Users that keep some ``<prefix>/bin`` directories in the ``PATH`` just for
+ their tools do not necessarily want any supporting ``<prefix>/lib``
+ directories searched. One may set the ``CMAKE_PREFIX_PATH`` environment
+ variable with a :ref:`semicolon-separated list <CMake Language Lists>` of prefixes that are
+ to be searched.
+
+* The :generator:`Visual Studio 7 .NET 2003` generator is now
+ deprecated and will be removed in a future version of CMake.
+
+* The :generator:`Visual Studio 7` generator (for VS .NET 2002) has been
+ removed. It had been deprecated since CMake 3.3.
+
+* The :generator:`Visual Studio 6` generator has been removed.
+ It had been deprecated since CMake 3.3.
+
+Other Changes
+=============
+
+* The precompiled OS X binary provided on ``cmake.org`` now requires
+ OS X 10.7 or newer.
+
+* On Linux and FreeBSD platforms, when building CMake itself from source and
+ not using a system-provided libcurl, OpenSSL is now used by default if it is
+ found on the system. This enables SSL/TLS support for commands supporting
+ network communication via ``https``, such as :command:`file(DOWNLOAD)`,
+ :command:`file(UPLOAD)`, and :command:`ctest_submit`.
+
+* The :manual:`cmake(1)` ``--build`` command-line tool now rejects multiple
+ ``--target`` options with an error instead of silently ignoring all but the
+ last one.
+
+* :prop_tgt:`AUTOMOC` now diagnoses name collisions when multiple source
+ files in different directories use ``#include <moc_foo.cpp>`` with the
+ same name (because the generated ``moc_foo.cpp`` files would collide).
+
+* The :module:`FindBISON` module ``BISON_TARGET`` macro now supports
+ special characters by passing the ``VERBATIM`` option to internal
+ :command:`add_custom_command` calls. This may break clients that
+ added escaping manually to work around the bug.
+
+* The :module:`FindFLEX` module ``FLEX_TARGET`` macro now supports
+ special characters by passing the ``VERBATIM`` option to internal
+ :command:`add_custom_command` calls. This may break clients that
+ added escaping manually to work around the bug.
+
+* The :module:`FindProtobuf` module input and output variables were all renamed
+ from ``PROTOBUF_`` to ``Protobuf_`` for consistency with other find modules.
+ Input variables of the old case will be honored if provided, and output
+ variables of the old case are always provided.
+
+* The :cpack_gen:`CPack RPM Generator` now supports upper cased component
+ names in per component CPackRPM specific variables.
+ E.g. component named ``foo`` now expects component specific
+ variable to be ``CPACK_RPM_FOO_PACKAGE_NAME`` while before
+ it expected ``CPACK_RPM_foo_PACKAGE_NAME``.
+ Upper cased component name part in variables is compatible
+ with convention used for other CPack variables.
+ For back compatibility old format of variables is still valid
+ and preferred if both versions of variable are set, but the
+ preferred future use is upper cased component names in variables.
+ New variables that will be added to CPackRPM in later versions
+ will only support upper cased component variable format.
+
+* The CPack NSIS generator's configuration file template was fixed to
+ quote the path to the uninstaller tool used by the
+ :variable:`CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL` option.
+ This avoids depending on an insecure Windows feature to run an
+ uninstaller tool with a space in the path.
diff --git a/Help/release/3.7.rst b/Help/release/3.7.rst
new file mode 100644
index 0000000..345c056
--- /dev/null
+++ b/Help/release/3.7.rst
@@ -0,0 +1,319 @@
+CMake 3.7 Release Notes
+***********************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.6 include the following.
+
+New Features
+============
+
+Platforms
+---------
+
+* CMake now supports :ref:`Cross Compiling for Android` with simple
+ toolchain files.
+
+* The Clang compiler is now supported on AIX.
+
+Generators
+----------
+
+* The :generator:`Ninja` generator learned to conditionally support
+ Fortran when using a ``ninja`` tool that has the necessary features.
+ See generator documentation for details.
+
+* The :generator:`Ninja` generator learned to produce phony targets
+ of the form ``sub/dir/{test,install,package}`` to drive the build
+ of a subdirectory installation, test or packaging target.
+ This is equivalent to ``cd sub/dir; make {test,install,package}``
+ with :ref:`Makefile Generators`.
+
+* The :generator:`Visual Studio 15 2017` generator was added. This is
+ experimental and based on "Visual Studio 2017 RC" because this version
+ of VS has not been released.
+
+* :ref:`Visual Studio Generators` for VS 2010 and above learned to
+ place ``.natvis`` source files into VS project files properly.
+
+* The :generator:`Xcode` generator's rudimentary Swift language support
+ learned to honor a new :variable:`CMAKE_Swift_LANGUAGE_VERSION` variable
+ to tell Xcode what version of Swift is used by the source.
+
+* The :generator:`CodeLite` generator gained a new
+ :variable:`CMAKE_CODELITE_USE_TARGETS` option
+ to change project creation from projects to targets.
+
+Commands
+--------
+
+* The :command:`add_custom_command` command gained a new ``DEPFILE``
+ option that works with the :generator:`Ninja` generator to provide
+ implicit dependency information to the build tool.
+
+* The :command:`cmake_parse_arguments` command gained a new ``PARSE_ARGV``
+ mode to read arguments directly from ``ARGC`` and ``ARGV#``
+ variables inside a :command:`function` body.
+
+* The :command:`export` command gained an ``ANDROID_MK`` option
+ to generate ``Android.mk`` files referencing CMake-built
+ libraries as prebuilts for the Android NDK build system.
+
+* The :command:`file(DOWNLOAD)` and :command:`file(UPLOAD)` commands gained
+ ``HTTPHEADER <HTTP-header>`` and ``USERPWD <username>:<password>`` options.
+
+* The :command:`find_library` and :command:`find_package` commands learned
+ to search in ``lib32/`` directories when the build targets a 32-bit
+ architecture. See the :prop_gbl:`FIND_LIBRARY_USE_LIB32_PATHS` global
+ property.
+
+* The :command:`find_package` command gained the possibility of
+ sorting compatible libraries by ``NAME`` or by ``NATURAL`` sorting by
+ setting the two new variables :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER`
+ and :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION`.
+
+* The :command:`if` command gained new boolean comparison operations
+ ``LESS_EQUAL``, ``GREATER_EQUAL``, ``STRLESS_EQUAL``, ``STRGREATER_EQUAL``,
+ ``VERSION_LESS_EQUAL``, and ``VERSION_GREATER_EQUAL``.
+
+* The :command:`install` command gained an ``EXPORT_ANDROID_MK``
+ subcommand to install ``Android.mk`` files referencing installed
+ libraries as prebuilts for the Android NDK build system.
+
+* The :command:`string(TIMESTAMP)` and :command:`file(TIMESTAMP)`
+ commands gained support for the ``%a`` and ``%b`` placeholders.
+ These are the abbreviated weekday and month names.
+
+* The :command:`try_compile` command source file signature now honors
+ configuration-specific flags (e.g. :variable:`CMAKE_<LANG>_FLAGS_DEBUG`)
+ in the generated test project. Previously only the default such flags
+ for the current toolchain were used. See policy :policy:`CMP0066`.
+
+Variables
+---------
+
+* Variable :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` was added to control
+ the sorting mode of the :command:`find_package` command.
+
+* Variable :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` was added to control
+ the sorting direction the :command:`find_package` command.
+
+* :variable:`Toolchain files <CMAKE_TOOLCHAIN_FILE>` may now set a
+ :variable:`CMAKE_<LANG>_FLAGS_INIT` variable to initialize the
+ :variable:`CMAKE_<LANG>_FLAGS` cache entry the first time a language is
+ enabled in a build tree.
+
+* :variable:`Toolchain files <CMAKE_TOOLCHAIN_FILE>` may now set
+ :variable:`CMAKE_EXE_LINKER_FLAGS_INIT`,
+ :variable:`CMAKE_SHARED_LINKER_FLAGS_INIT`, and
+ :variable:`CMAKE_MODULE_LINKER_FLAGS_INIT` variables to initialize the
+ :variable:`CMAKE_EXE_LINKER_FLAGS`,
+ :variable:`CMAKE_SHARED_LINKER_FLAGS`, and
+ :variable:`CMAKE_MODULE_LINKER_FLAGS` cache entries the first time
+ a language is enabled in a build tree.
+
+Properties
+----------
+
+* On Apple platforms the :prop_tgt:`BUNDLE_EXTENSION` target property
+ now also applies to Frameworks and App Bundles.
+
+* A :prop_dir:`BINARY_DIR` directory property was added to get the
+ absolute path to the binary directory corresponding to the source
+ directory on which the property is read.
+
+* A :prop_dir:`BUILDSYSTEM_TARGETS` directory property was added to
+ get the list of logical buildsystem target names added by the
+ project in a directory.
+
+* A :prop_tgt:`LINK_WHAT_YOU_USE` target property and supporting
+ :variable:`CMAKE_LINK_WHAT_YOU_USE` variable were introduced
+ to detect (on UNIX) shared libraries that are linked but not
+ needed by running ``ldd -r -u``.
+
+* A :prop_dir:`SOURCE_DIR` directory property was added to get the
+ absolute path to the source directory associated with a directory.
+
+* A :prop_dir:`SUBDIRECTORIES` directory property was added to
+ get the list of subdirectories added by a project in a directory.
+
+* A :prop_tgt:`VS_SDK_REFERENCES` target property was added to tell
+ :ref:`Visual Studio Generators` to reference the named SDKs.
+
+* A :prop_sf:`VS_TOOL_OVERRIDE` source file property was created to tell
+ :ref:`Visual Studio Generators` what tool to use for a source file.
+
+* The :prop_tgt:`WINDOWS_EXPORT_ALL_SYMBOLS` target property now applies
+ to executable targets with the :prop_tgt:`ENABLE_EXPORTS` property set.
+
+* A :prop_sf:`XCODE_FILE_ATTRIBUTES` source file property was
+ added to tell the :generator:`Xcode` generator to generate
+ custom content in the Xcode project attributes for the file.
+
+Modules
+-------
+
+* An :module:`AndroidTestUtilities` module was added to manage transfer
+ of test data to an Android device.
+
+* The :module:`CheckFortranSourceCompiles` module macro
+ ``CHECK_Fortran_SOURCE_COMPILES`` gained a ``SRC_EXT`` option
+ to specify a custom test Fortran source file extension.
+
+* The :module:`ExternalProject` module gained ``HTTP_USERNAME`` and
+ ``HTTP_PASSWORD`` options to set http download credentials.
+
+* The :module:`ExternalProject` module gained a ``HTTP_HEADER``
+ option to add http download headers.
+
+* The :module:`FindBISON` module ``BISON_TARGET`` macro learned a new
+ ``REPORT_FILE`` option to specify the bison ``--report-file=`` option.
+
+* The :module:`FindBZip2` module now provides imported targets.
+
+* A :module:`FindICU` module was introduced to find the International
+ Components for Unicode (ICU) libraries and programs.
+
+* The :module:`FindMatlab` module learned to find the SIMULINK and MAT
+ components.
+
+* The :module:`FindMatlab` module :command:`matlab_add_mex` command learned
+ to add executables and modules.
+
+* The :module:`FindMatlab` module :command:`matlab_add_unit_test` command
+ learned to support inline Matlab test code.
+
+* The :module:`FindOpenCL` module now provides imported targets.
+
+* The :module:`FindOpenMP` module learned to detect the OpenMP
+ version (specification date) from the compiler.
+
+* A :module:`FindVulkan` module was added.
+
+* The :module:`GenerateExportHeader` module learned a new
+ ``CUSTOM_CONTENT_FROM_VARIABLE`` option to specify a variable
+ containing custom content for inclusion in the generated header.
+
+* The :module:`GNUInstallDirs` module gained a new
+ :command:`GNUInstallDirs_get_absolute_install_dir` command.
+
+* The :module:`UseJava` module gained APIs to "export" jar targets
+ for use by external CMake projects. See the ``install_jar_exports``
+ and ``export_jars`` functions.
+
+CTest
+-----
+
+* CTest now supports test fixtures through the new :prop_test:`FIXTURES_SETUP`,
+ :prop_test:`FIXTURES_CLEANUP` and :prop_test:`FIXTURES_REQUIRED` test
+ properties. When using regular expressions or ``--rerun-failed`` to limit
+ the tests to be run, a fixture's setup and cleanup tests will automatically
+ be added to the execution set if any test requires that fixture.
+
+* The :command:`ctest_configure`, :command:`ctest_build`,
+ :command:`ctest_test`, :command:`ctest_coverage`, and :command:`ctest_upload`
+ commands gained a new ``CAPTURE_CMAKE_ERROR`` option to capture any errors
+ that occur as the commands run into a variable and avoid affecting the return
+ code of the :manual:`ctest(1)` process.
+
+CPack
+-----
+
+* CPack gained a :cpack_gen:`CPack productbuild Generator` on OS X.
+
+* CPack gained a new :variable:`CPACK_PACKAGE_CHECKSUM` variable to
+ enable generation of a checksum file for each package file.
+
+* The :cpack_gen:`CPack DEB Generator` learned to support long file names
+ when archive format is set to GNU tar.
+ See :variable:`CPACK_DEBIAN_ARCHIVE_TYPE`
+
+* The :module:`CPackIFW` module gained a new
+ :command:`cpack_ifw_add_package_resources` command to include additional
+ resources in the installer binary.
+
+* The :module:`CPackIFW` module :command:`cpack_ifw_configure_component` and
+ :command:`cpack_ifw_configure_component_group` commands gained a new
+ ``USER_INTERFACES`` option to add a list of additional pages to the IFW
+ installer.
+
+* The :cpack_gen:`CPack RPM Generator` learned to generate debuginfo
+ packages on demand. See :variable:`CPACK_RPM_DEBUGINFO_PACKAGE`
+ and its per component version.
+
+* The :cpack_gen:`CPack RPM Generator` learned to generate source rpm
+ (SRPM) packages on demand. See :variable:`CPACK_RPM_PACKAGE_SOURCES`,
+ :variable:`CPACK_RPM_SOURCE_PKG_BUILD_PARAMS` and
+ :variable:`CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX`.
+
+* The :cpack_gen:`CPack NSIS Generator` now supports
+ :variable:`CPACK_NSIS_<compName>_INSTALL_DIRECTORY`.
+ This can be used to set component specific installation directories.
+
+* The :cpack_gen:`CPack WIX Generator` now supports
+ :variable:`CPACK_WIX_SKIP_PROGRAM_FOLDER` to allow specification
+ of a custom absolute installation prefix outside
+ of the ProgramFiles folders.
+
+* The :cpack_gen:`CPack WIX Generator` now supports
+ :variable:`CPACK_COMPONENT_<compName>_DISABLED`.
+ This can be used to deselect a component from being installed by default.
+
+* The :cpack_gen:`CPack WIX Generator` now supports
+ :variable:`CPACK_WIX_PATCH_FILE` fragments for Feature elements.
+
+* The :cpack_gen:`CPack WIX Generator` now supports
+ :variable:`CPACK_WIX_ROOT_FEATURE_TITLE` and
+ :variable:`CPACK_WIX_ROOT_FEATURE_DESCRIPTION` to allow the specification
+ of a custom title and description for the root feature element.
+
+Other
+-----
+
+* :manual:`cmake(1)` gained a ``-E capabilities`` option to provide a
+ machine-readable (JSON) description of the capabilities of the
+ cmake tool (available generators, etc.).
+
+* A new :manual:`cmake-server(7)` mode was added to provide semantic
+ information about a CMake-generated buildsystem to clients through
+ a JSON protocol. Currently all protocols are experimental and subject
+ to change.
+
+* The :manual:`cmake(1)` command learned a ``--trace-source=<file>`` option.
+
+* :manual:`ccmake(1)` learned to support vim-like navigation bindings.
+
+* :manual:`cmake-gui(1)` gained a button to open the generated project file
+ for :ref:`Visual Studio Generators` and the :generator:`Xcode` generator.
+
+Deprecated and Removed Features
+===============================
+
+* We no longer provide Linux i386 binaries for download from ``cmake.org``
+ for new versions of CMake.
+
+* Vim support files ``cmake-indent.vim``, ``cmake-syntax.vim``, and
+ ``cmake-help.vim`` have been removed in favor of the files now provided
+ from the `vim-cmake-syntax`_ project.
+
+* Support for building CMake itself with some compilers was dropped:
+
+ * Visual Studio 7.1 and 2005 -- superseded by VS 2008 and above
+ * MinGW.org mingw32 -- superseded by MSYS2 mingw32 and mingw64
+
+ CMake still supports generating build systems for other projects using
+ these compilers.
+
+Other Changes
+=============
+
+* The Fortran dependency scanner learned to support the syntax of
+ `Fortran Submodules`_.
+
+* Vim support files ``indent/cmake.vim`` and ``syntax/cmake.vim``
+ from the `vim-cmake-syntax`_ project are now distributed with CMake.
+
+.. _`Fortran Submodules`: http://fortranwiki.org/fortran/show/Submodules
+.. _`vim-cmake-syntax`: https://github.com/pboettch/vim-cmake-syntax
diff --git a/Help/release/3.8.rst b/Help/release/3.8.rst
new file mode 100644
index 0000000..de51a7b
--- /dev/null
+++ b/Help/release/3.8.rst
@@ -0,0 +1,417 @@
+CMake 3.8 Release Notes
+***********************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.7 include the following.
+
+New Features
+============
+
+Languages
+---------
+
+C#
+^^
+
+* CMake learned to support ``CSharp`` (C#) as a first-class language that
+ can be enabled via the :command:`project` and :command:`enable_language`
+ commands. It is currently supported by the :ref:`Visual Studio Generators`
+ for VS 2010 and above.
+
+ C# assemblies and programs can be added just like common C++ targets using
+ the :command:`add_library` and :command:`add_executable` commands.
+ References between C# targets in the same source tree may be specified by
+ :command:`target_link_libraries` like for C++. References to system or
+ 3rd-party assemblies may be specified by the target properties
+ :prop_tgt:`VS_DOTNET_REFERENCE_<refname>` and
+ :prop_tgt:`VS_DOTNET_REFERENCES`.
+
+* More fine tuning of C# targets may be done using target and source
+ file properties. Specifically the target properties related to
+ Visual Studio (``VS_*``) are worth a look (for setting toolset
+ versions, root namespaces, assembly icons, ...).
+
+CUDA
+^^^^
+
+* CMake learned to support ``CUDA`` as a first-class language that can be
+ enabled via the :command:`project` and :command:`enable_language` commands.
+
+* ``CUDA`` is currently supported by the :ref:`Makefile Generators`
+ and the :generator:`Ninja` generator on Linux, macOS, and Windows.
+ Support for the Visual Studio IDE is under development but not
+ included in this release.
+
+* The NVIDIA CUDA Toolkit compiler (``nvcc``) is supported.
+
+C & C++
+^^^^^^^
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ now offers meta-features that request compiler modes for specific language
+ standard levels (e.g. ``cxx_std_11``). See
+ :prop_gbl:`CMAKE_C_KNOWN_FEATURES` and :prop_gbl:`CMAKE_CXX_KNOWN_FEATURES`.
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ is now aware of C++ 17. No specific features are yet enumerated besides
+ the ``cxx_std_17`` meta-feature.
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ is now aware of the availability of C99 in gcc since version 3.4.
+
+Platforms
+---------
+
+* A new minimal platform file for ``Fuchsia`` was added.
+
+Generators
+----------
+
+* The :generator:`CodeBlocks` extra generator may now be used to
+ generate with :generator:`NMake Makefiles JOM`.
+
+* The :ref:`Visual Studio Generators` for VS 2013 and above learned to
+ support a ``host=x64`` option in the :variable:`CMAKE_GENERATOR_TOOLSET`
+ value (e.g. via the :manual:`cmake(1)` ``-T`` option) to request use
+ of a VS 64-bit toolchain on 64-bit hosts.
+
+* The :ref:`Visual Studio Generators` learned to treat files passed to
+ :command:`target_link_libraries` whose names end in ``.targets``
+ as MSBuild "targets" files to be imported into generated project files.
+
+Commands
+--------
+
+* The :command:`add_custom_command` and :command:`add_custom_target` commands
+ learned the option ``COMMAND_EXPAND_LISTS`` which causes lists in the
+ ``COMMAND`` argument to be expanded, including lists created by generator
+ expressions.
+
+* The :command:`execute_process` command gained an ``ENCODING`` option to
+ specify on Windows which encoding is used for output from child process.
+
+* The :command:`math(EXPR)` command gained support for unary
+ ``+`` and ``-`` operators.
+
+* The :command:`source_group` command gained ``TREE`` and ``PREFIX``
+ options to add groups following source tree directory structure.
+
+* The :command:`string(TIMESTAMP)` command learned to treat ``%%``
+ as a way to encode plain ``%``.
+
+* The :command:`string(TIMESTAMP)` command will now honor the
+ ``SOURCE_DATE_EPOCH`` environment variable and use its value
+ instead of the current time.
+
+* The :command:`try_compile` command source file signature gained new options
+ to specify the language standard to use in the generated test project.
+
+* The :command:`try_compile` command source file signature now honors
+ language standard variables like :variable:`CMAKE_CXX_STANDARD`.
+ See policy :policy:`CMP0067`.
+
+Variables
+---------
+
+* A :variable:`CMAKE_CODELITE_USE_TARGETS` variable was added to tell the
+ :generator:`CodeLite` extra generator to change the generated project
+ to have target-centric organization.
+ The ``build``, ``rebuild``, and ``clean`` operations within ``CodeLite``
+ then work on a selected target rather than the whole workspace.
+ (Note that the :generator:`Ninja` clean operation on a target
+ includes its dependencies, though.)
+
+* The :variable:`CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS` variable was added to
+ tell the :generator:`Sublime Text 2` extra generator to place specified
+ environment variables in the generated ``.sublime-project``.
+
+* The :variable:`CMAKE_SUBLIME_TEXT_2_EXCLUDE_BUILD_TREE` variable was added
+ to tell the :generator:`Sublime Text 2` extra generator whether to exclude
+ the build tree from the ``.sublime-project`` when it is inside the source
+ tree.
+
+* A :variable:`CMAKE_VS_INCLUDE_PACKAGE_TO_DEFAULT_BUILD` variable was
+ added to tell :ref:`Visual Studio Generators` for VS 2010 and above
+ to include the ``PACKAGE`` target in the default build, similar to
+ the existing :variable:`CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD`
+ variable for the ``INSTALL`` target.
+
+Properties
+----------
+
+* A :prop_tgt:`BUILD_RPATH` target property and corresponding
+ :variable:`CMAKE_BUILD_RPATH` variable were added to support custom
+ ``RPATH`` locations to be added to binaries in the build tree.
+
+* The :prop_sf:`COMPILE_FLAGS` source file property learned to support
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* The :prop_tgt:`FRAMEWORK` target property may now also be applied to
+ static libraries on Apple targets. It will result in a proper
+ Framework but with a static library inside.
+
+* :ref:`Imported <Imported Targets>` :ref:`Interface Libraries` learned new
+ :prop_tgt:`IMPORTED_LIBNAME` and :prop_tgt:`IMPORTED_LIBNAME_<CONFIG>`
+ target properties to specify a link library name since interface libraries
+ do not build their own library files.
+
+* A :prop_tgt:`<LANG>_CPPLINT` target property and supporting
+ :variable:`CMAKE_<LANG>_CPPLINT` variable were introduced to tell
+ the :ref:`Makefile Generators` and the :generator:`Ninja` generator to
+ run the ``cpplint`` style checker along with the compiler for ``C`` and
+ ``CXX`` languages.
+
+* A :prop_tgt:`MANUALLY_ADDED_DEPENDENCIES` target property has been added.
+ It provides a read-only list of dependencies that have been added with
+ the :command:`add_dependencies` command.
+
+* The :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` target property learned
+ to interpret empty list elements as referring to the configuration-less
+ imported location specified by :prop_tgt:`IMPORTED_LOCATION`.
+
+* The :prop_tgt:`NO_SYSTEM_FROM_IMPORTED` target property is now supported
+ on :ref:`Imported <Imported Targets>` :ref:`Interface Libraries`.
+
+* New source file properties :prop_sf:`SKIP_AUTOMOC`, :prop_sf:`SKIP_AUTOUIC`,
+ :prop_sf:`SKIP_AUTORCC`, and :prop_sf:`SKIP_AUTOGEN` were added to allow
+ source files to be excluded from processing by :prop_tgt:`AUTOMOC`,
+ :prop_tgt:`AUTOUIC`, and :prop_tgt:`AUTORCC` target properties.
+
+* A :prop_sf:`VS_COPY_TO_OUT_DIR` source file property was added to
+ tell :ref:`Visual Studio Generators` for VS 2010 and above whether
+ or not a file should e copied to the output directory.
+
+* A :prop_tgt:`VS_DEBUGGER_WORKING_DIRECTORY` target property was added
+ to tell :ref:`Visual Studio Generators` for VS 2010 and above what
+ debugger working directory should be set for the target.
+
+* A :prop_tgt:`VS_DOTNET_REFERENCES_COPY_LOCAL` target property was added
+ to specify whether to copy referenced assemblies to the output directory.
+
+* A :prop_tgt:`VS_DOTNET_REFERENCE_<refname>` target property was added
+ to tell :ref:`Visual Studio Generators` for VS 2010 and above to add
+ a .NET reference with a given hint path.
+
+* A :prop_sf:`VS_INCLUDE_IN_VSIX` source file property was added to
+ tell :ref:`Visual Studio Generators` for VS 2010 and above whether
+ to include the file in a Visual Studio extension package.
+
+* A :prop_sf:`VS_RESOURCE_GENERATOR` source file property was added to
+ give :ref:`Visual Studio Generators` for VS 2010 and above a setting
+ for the resource generator (``C#`` only).
+
+* A :prop_tgt:`VS_USER_PROPS` target property was added to tell
+ :ref:`Visual Studio Generators` for VS 2010 and above to use a
+ custom MSBuild user ``.props`` file.
+
+* A :prop_gbl:`XCODE_EMIT_EFFECTIVE_PLATFORM_NAME` global property was
+ added to tell the :generator:`Xcode` generator whether to emit the
+ ``EFFECTIVE_PLATFORM_NAME`` variable. This is useful when building
+ with multiple SDKs like ``macosx`` and ``iphoneos`` in parallel.
+
+* New :prop_tgt:`XCODE_PRODUCT_TYPE` and :prop_tgt:`XCODE_EXPLICIT_FILE_TYPE`
+ target properties were created to tell the :generator:`Xcode` generator
+ to use custom values of the corresponding attributes for a target in the
+ generated Xcode project.
+
+Modules
+-------
+
+* A :module:`CSharpUtilities` module was added to aid parameterization of
+ Visual Studio C# targets. It provides functions to allow automated
+ setting of source file properties to support Windows Forms, WPF/XAML or
+ other technologies as needed.
+
+* The :module:`ExternalData` module learned to support multiple
+ content links for one data file using different hashes, e.g.
+ ``img.png.sha256`` and ``img.png.sha1``. This allows objects
+ to be fetched from sources indexed by different hash algorithms.
+
+* The :module:`ExternalProject` module gained the ``GIT_PROGRESS`` option to
+ force Git to show progress when cloning repositories.
+
+* The :module:`ExternalProject` module gained a ``GIT_CONFIG`` option
+ to pass ``--config`` options to Git when cloning repositories.
+
+* The :module:`FeatureSummary` module :command:`feature_summary` command now
+ accepts a new ``QUIET_ON_EMPTY`` option that suppresses the output when
+ the list of packages that belong to the selected category is empty.
+
+* The :module:`FeatureSummary` module :command:`add_feature_info` command
+ now accepts lists of dependencies for deciding whether a feature is enabled
+ or not.
+
+* The package types accepted by the :module:`FeatureSummary` module can now
+ be tweaked by changing the :variable:`FeatureSummary_PKG_TYPES`,
+ :variable:`FeatureSummary_REQUIRED_PKG_TYPES` and
+ :variable:`FeatureSummary_DEFAULT_PKG_TYPE` global properties.
+
+* The :module:`FindOpenGL` module now provides imported targets
+ ``OpenGL::GL`` and ``OpenGL::GLU`` when the libraries are found.
+
+* The :module:`UseSWIG` module gained a ``swig_add_library`` command
+ to give more flexibility over the old ``swig_add_module`` command.
+
+* The :module:`UseSWIG` module ``swig_add_source_to_module`` command
+ learned a new ``SWIG_OUTFILE_DIR`` option to control the output
+ file location (``swig -o``).
+
+* The :module:`WriteCompilerDetectionHeader` module gained the
+ ``ALLOW_UNKNOWN_COMPILERS`` and ``ALLOW_UNKNOWN_COMPILER_VERSIONS`` options
+ that allow creation of headers that will work also with unknown or old
+ compilers by simply assuming they do not support any of the requested
+ features.
+
+CTest
+-----
+
+* The :command:`ctest_memcheck` command gained a ``DEFECT_COUNT <var>``
+ option to capture the number of memory defects detected.
+
+* The :command:`ctest_memcheck` command learned to read the location of
+ suppressions files for sanitizers from the
+ :variable:`CTEST_MEMORYCHECK_SUPPRESSIONS_FILE` variable.
+
+* The :command:`ctest_memcheck` command learned to support ``LeakSanitizer``
+ independently from ``AddressSanitizer``.
+
+* The :command:`ctest_update` command ``CDASH_UPLOAD`` signature was taught
+ to honor the ``RETRY_COUNT``, ``RETRY_DELAY``, and ``QUIET`` options.
+
+CPack
+-----
+
+* The :module:`CPackIFWConfigureFile` module was added to define a new
+ :command:`cpack_ifw_configure_file` command to configure file templates
+ prepared in QtIFW/SDK/Creator style.
+
+* The :module:`CPackIFW` module :command:`cpack_ifw_configure_component` and
+ :command:`cpack_ifw_configure_component_group` commands gained a new
+ ``DEFAULT``, ``VIRTUAL``, ``FORCED_INSTALLATION``, ``REQUIRES_ADMIN_RIGHTS``,
+ ``DISPLAY_NAME``, ``UPDATE_TEXT``, ``DESCRIPTION``, ``RELEASE_DATE``,
+ ``AUTO_DEPEND_ON`` and ``TRANSLATIONS`` options to more specific
+ configuration.
+
+* The :module:`CPackIFW` module :command:`cpack_ifw_configure_component`
+ command gained a new ``DEPENDENCIES`` alias for ``DEPENDS`` option.
+
+* The :module:`CPackIFW` module :command:`cpack_ifw_configure_component_group`
+ command gained a new ``DEPENDS`` option. The ``DEPENDENCIES`` alias also
+ added.
+
+* The :module:`CPackIFW` module :command:`cpack_ifw_configure_component` and
+ :command:`cpack_ifw_configure_component_group` commands ``PRIORITY``
+ option now is deprecated and will be removed in a future version of CMake.
+ Please use new ``SORTING_PRIORITY`` option instead.
+
+* The :cpack_gen:`CPack IFW Generator` gained new
+ :variable:`CPACK_IFW_PACKAGE_WATERMARK`,
+ :variable:`CPACK_IFW_PACKAGE_BANNER`,
+ :variable:`CPACK_IFW_PACKAGE_BACKGROUND`,
+ :variable:`CPACK_IFW_PACKAGE_WIZARD_STYLE`,
+ :variable:`CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH`,
+ :variable:`CPACK_IFW_PACKAGE_WIZARD_DEFAULT_HEIGHT`, and
+ :variable:`CPACK_IFW_PACKAGE_TITLE_COLOR`
+ variables to customize a QtIFW installer look.
+
+* The :cpack_gen:`CPack productbuild Generator` gained options to sign packages.
+ See the variables :variable:`CPACK_PRODUCTBUILD_IDENTITY_NAME`,
+ :variable:`CPACK_PRODUCTBUILD_KEYCHAIN_PATH`,
+ :variable:`CPACK_PKGBUILD_IDENTITY_NAME`, and
+ :variable:`CPACK_PKGBUILD_KEYCHAIN_PATH`.
+
+* The :cpack_gen:`CPack RPM Generator` learned to omit tags that are not
+ supported by provided ``rpmbuild`` tool. If unsupported tags are set they
+ are ignored and a developer warning is printed out.
+
+* The :cpack_gen:`CPack RPM Generator` learned to generate main component
+ package which forces generation of a rpm for defined component without
+ component suffix in filename and package name.
+ See :variable:`CPACK_RPM_MAIN_COMPONENT` variable.
+
+* The :cpack_gen:`CPack RPM Generator` learned to generate a single
+ ``debuginfo`` package on demand even if components packaging is used.
+ See :variable:`CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE` variable.
+
+* The :cpack_gen:`CPack RPM Generator` learned to support
+ multiple directives per file when using
+ :variable:`CPACK_RPM_USER_FILELIST` variable.
+
+Other
+-----
+
+* CMake functionality using cryptographic hashes now supports SHA-3 algorithms.
+
+* A new generator expression ``$<IF:cond,true-value,false-value>`` was added.
+ It resolves to the true-value if the condition is ``1`` and resolves to
+ the false-value if the condition is ``0``.
+
+Deprecated and Removed Features
+===============================
+
+* The :module:`FeatureSummary` module commands :command:`set_package_info`,
+ :command:`set_feature_info`, :command:`print_enabled_features`, and
+ :command:`print_disabled_features` are now deprecated.
+
+* The :module:`UseSWIG` module ``swig_add_module`` command is now
+ deprecated in favor of ``swig_add_library``.
+
+Other Changes
+=============
+
+* If a command specified by the :prop_tgt:`<LANG>_CLANG_TIDY` target property
+ returns non-zero at build time this is now treated as an error instead of
+ silently ignored.
+
+* The :command:`ctest_memcheck` command no longer automatically adds
+ ``leak_check=1`` to the options used by ``AddressSanitizer``. The default
+ behavior of ``AddressSanitizer`` is to run `LeakSanitizer` to check leaks
+ unless ``leak_check=0``.
+
+* The :command:`ctest_memcheck` command was fixed to correctly append extra
+ sanitizer options read from the
+ :variable:`CTEST_MEMORYCHECK_SANITIZER_OPTIONS` variable to the environment
+ variables used internally by the sanitizers.
+
+* The :module:`FeatureSummary` module :command:`set_package_properties`
+ command no longer forces the package type to ``OPTIONAL`` when the type
+ is not explicitly set.
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+ is now aware of features supported by Intel C++ compilers versions 12.1
+ through 17.0 on UNIX and Windows platforms.
+
+* Calls to the :module:`FindPkgConfig` module :command:`pkg_check_modules`
+ command following a successful call learned to re-evaluate the cached values
+ for a given prefix after changes to the parameters to the command for that
+ prefix.
+
+* When using :prop_tgt:`AUTOMOC` or :prop_tgt:`AUTOUIC`, generated
+ ``moc_*``, ``*.moc`` and ``ui_*`` are placed in the
+ ``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/include`` directory which
+ is automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`.
+ It is therefore not necessary anymore to have
+ :variable:`CMAKE_CURRENT_BINARY_DIR` in the target's
+ :prop_tgt:`INCLUDE_DIRECTORIES`.
+
+* The :generator:`Sublime Text 2` generator no longer runs the native
+ build command (e.g. ``ninja`` or ``make``) with verbose build output
+ enabled.
+
+* The :command:`try_compile` command source file signature now
+ honors the :variable:`CMAKE_WARN_DEPRECATED` variable value
+ in the generated test project.
+
+* The :ref:`Visual Studio Generators` for VS 2010 and above now place
+ per-source file flags after target-wide flags when they are classified
+ as raw flags with no project file setting (``AdditionalOptions``).
+ This behavior is more consistent with the ordering of flags produced
+ by other generators, and allows flags on more-specific properties
+ (per-source) to override those on more general ones (per-target).
+
+* The precompiled Windows binary MSI package provided on ``cmake.org`` now
+ records the installation directory in the Windows Registry under the key
+ ``HKLM\Software\Kitware\CMake`` with a value named ``InstallDir``.
diff --git a/Help/release/3.9.rst b/Help/release/3.9.rst
new file mode 100644
index 0000000..89da627
--- /dev/null
+++ b/Help/release/3.9.rst
@@ -0,0 +1,343 @@
+CMake 3.9 Release Notes
+***********************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.8 include the following.
+
+New Features
+============
+
+Languages
+---------
+
+* ``CUDA`` is now supported by the :ref:`Visual Studio Generators`
+ for VS 2010 and above. This complements the existing support by the
+ :ref:`Makefile Generators` and the :generator:`Ninja` generator.
+ CUDA 8.0.61 or higher is recommended due to known bugs in the VS
+ integration by earlier versions.
+
+* CMake is now aware of the :prop_tgt:`C++ standards <CXX_STANDARD>` and
+ :prop_tgt:`C standards <C_STANDARD>` and their associated meta-features for
+ the following :variable:`compiler ids <CMAKE_<LANG>_COMPILER_ID>`: ``Cray``,
+ ``PGI``, and ``XL``.
+
+Generators
+----------
+
+* :ref:`Visual Studio Generators` for VS 2010 and above learned to support
+ the ``ASM_NASM`` language when ``nasm`` is installed.
+
+* The :generator:`Xcode` generator learned to create Xcode schema files.
+ This is an experimental feature and can be activated by setting the
+ :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable to a ``TRUE`` value.
+
+Commands
+--------
+
+* The :command:`add_library` command ``IMPORTED`` option learned to support
+ :ref:`Object Libraries`.
+
+* The :command:`find_library` command learned to search ``libx32`` paths
+ when the build targets the ``x32`` ABI. See the
+ :prop_gbl:`FIND_LIBRARY_USE_LIBX32_PATHS` global property.
+
+* The :command:`include_external_msproject` command learned to use
+ the :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` target property
+ to map current configurations to the external configurations.
+
+* The :command:`install(TARGETS)` command learned a new ``OBJECTS`` option to
+ specify where to install :ref:`Object Libraries`.
+
+* The :command:`install(EXPORT)` command learned how to export
+ :ref:`Object Libraries`.
+
+* The :command:`project` command learned an optional ``DESCRIPTION``
+ parameter to set the :variable:`PROJECT_DESCRIPTION` variable.
+
+* The :command:`separate_arguments` command gained a ``NATIVE_COMMAND`` mode
+ that performs argument separation depending on the host operating system.
+
+Variables
+---------
+
+* A :variable:`CMAKE_ANDROID_NDK_DEPRECATED_HEADERS` variable was added
+ for use when :ref:`Cross Compiling for Android with the NDK` to request
+ use of the deprecated headers even when unified headers are available.
+ The default is now to use unified headers if available.
+
+* A :variable:`CMAKE_AUTOMOC_DEPEND_FILTERS` variable was introduced to
+ allow :variable:`CMAKE_AUTOMOC` to extract additional dependency file names
+ for ``moc`` from the contents of source files.
+
+* A :variable:`CMAKE_AUTOUIC_SEARCH_PATHS` variable was introduced to
+ allow :variable:`CMAKE_AUTOUIC` to search for ``foo.ui`` in more
+ places than the vicinity of the file including ``ui_foo.h``.
+
+* A :variable:`CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX` variable was added to
+ tell the :command:`find_library` command to search in a ``lib<suffix>``
+ directory before each ``lib`` directory that would normally be searched.
+
+* A :variable:`CMAKE_INTERPROCEDURAL_OPTIMIZATION` variable was added to
+ initialize the :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` property on all
+ targets.
+
+* A :variable:`CMAKE_<LANG>_COMPILER_AR` variable was added to hold
+ the path to the GCC/Clang wrapper of ``ar``.
+
+* A :variable:`CMAKE_<LANG>_COMPILER_RANLIB` variable was added to hold
+ the path to the GCC/Clang wrapper of ``ranlib``.
+
+* The :variable:`CMAKE_SYSROOT_COMPILE` and :variable:`CMAKE_SYSROOT_LINK`
+ variables were added to use separate sysroots for compiling and linking.
+
+Properties
+----------
+
+* A new :prop_tgt:`AUTOGEN_BUILD_DIR` target property was introduced to set
+ a custom output directory for :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTOUIC`,
+ and :prop_tgt:`AUTORCC`.
+
+* A new :prop_tgt:`AUTOMOC_DEPEND_FILTERS` target property was introduced to
+ allow :prop_tgt:`AUTOMOC` to extract additional dependency file names
+ for ``moc`` from the contents of source files.
+
+* A new :prop_tgt:`AUTOUIC_SEARCH_PATHS` target property was introduced to
+ allow :prop_tgt:`AUTOUIC` to search for ``foo.ui`` in more
+ places than the vicinity of the file including ``ui_foo.h``.
+
+* Global properties :prop_gbl:`AUTOGEN_SOURCE_GROUP`,
+ :prop_gbl:`AUTOMOC_SOURCE_GROUP` and
+ :prop_gbl:`AUTORCC_SOURCE_GROUP` were
+ introduced to allow files generated by :prop_tgt:`AUTOMOC` or
+ :prop_tgt:`AUTORCC` to be placed in a :command:`source_group`.
+
+* A :prop_tgt:`BUILD_WITH_INSTALL_NAME_DIR` target property and corresponding
+ :variable:`CMAKE_BUILD_WITH_INSTALL_NAME_DIR` variable were added to
+ control whether to use the :prop_tgt:`INSTALL_NAME_DIR` target property
+ value for binaries in the build tree. This is for macOS ``install_name``
+ as :prop_tgt:`BUILD_WITH_INSTALL_RPATH` is for ``RPATH``.
+
+* A :prop_tgt:`CUDA_PTX_COMPILATION` target property was added to
+ :ref:`Object Libraries` to support compiling to ``.ptx`` files
+ instead of host object files.
+
+* A :prop_gbl:`GENERATOR_IS_MULTI_CONFIG` global property was
+ added to determine whether the current generator is a multi-configuration
+ generator (such as :ref:`Visual Studio Generators` or :generator:`Xcode`).
+
+* The :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` target property is now enforced
+ when enabled. CMake will add IPO flags unconditionally or produce an error
+ if it does not know the flags for the current compiler. The project is now
+ responsible to use the :module:`CheckIPOSupported` module to check for IPO
+ support before enabling the target property. See policy :policy:`CMP0069`.
+
+* The :prop_tgt:`WINDOWS_EXPORT_ALL_SYMBOLS` target property may now
+ be used in combination with explicit ``.def`` files in order to
+ export all symbols from the object files within a target plus
+ an explicit list of symbols that the linker finds in dependencies
+ (e.g. ``msvcrt.lib``).
+
+Modules
+-------
+
+* A :module:`CheckIPOSupported` module was added to help projects
+ check whether interprocedural optimization (IPO) is supported by
+ the current toolchain and CMake version.
+
+* The :module:`CMakeFindDependencyMacro` module ``find_dependency`` macro
+ now forwards all arguments to the underlying :command:`find_package`
+ call. Existing uses will continue to function as before, but callers can
+ now access the full suite of arguments that :command:`find_package` accepts.
+
+* The :module:`FeatureSummary` module :command:`feature_summary` command now
+ accepts the new ``DEFAULT_DESCRIPTION`` option that will print the default
+ title for the selected package type.
+
+* The :module:`FeatureSummary` module gained a new
+ :variable:`FeatureSummary_<TYPE>_DESCRIPTION` variable that can be defined
+ for each ``<TYPE>`` to replace the type name with the specified string
+ whenever the package type is used in an output string by the module.
+
+* The :module:`FindDoxygen` module learned to control Doxygen behavior using
+ CMake variables and generate documentation via the newly added
+ :command:`doxygen_add_docs` function. The Doxygen input file (``Doxyfile``)
+ is automatically generated and doxygen is run as part of a custom target.
+ Additional components can be specified to find optional tools: ``dot``,
+ ``mscgen`` and ``dia``.
+
+* The :module:`FindMPI` module now provides imported targets.
+
+* The :module:`FindProtobuf` module :command:`protobuf_generate_cpp`
+ command gained an ``EXPORT_MACRO`` option to specify the name of
+ a DLL export markup macro.
+
+* The :module:`FindProtobuf` module now supports usage of static libraries
+ for Unix via a new ``Protobuf_USE_STATIC_LIBS`` input variable.
+
+* The :module:`FindProtobuf` module now provides imported targets
+ when the libraries are found.
+
+* A new :module:`GoogleTest` module was added to provide the
+ :command:`gtest_add_tests` function independently of the :module:`FindGTest`
+ module. The function was also updated to support keyword arguments, with
+ functionality expanded to allow a test name prefix and suffix to be
+ specified, the dependency on the source files to be optional and the list of
+ discovered test cases to be returned to the caller.
+
+CTest
+-----
+
+* The :command:`ctest_submit` command gained a ``HTTPHEADER`` option
+ to specify custom headers to send during submission.
+
+* The :manual:`ctest(1)` executable gained new options which allow the
+ developer to disable automatically adding tests to the test set to satisfy
+ fixture dependencies. ``-FS`` prevents adding setup tests for fixtures
+ matching the provided regular expression, ``-FC`` prevents adding cleanup
+ tests for matching fixtures and ``-FA`` prevents adding any test for matching
+ fixtures.
+
+* A :prop_test:`DISABLED` test property was added to mark tests that
+ are configured but explicitly disabled so they do not run.
+
+CPack
+-----
+
+* The :cpack_gen:`CPack Archive Generator` learned to modify the filename
+ per-component. See the :variable:`CPACK_ARCHIVE_FILE_NAME` variable and
+ its per-component version :variable:`CPACK_ARCHIVE_<component>_FILE_NAME`.
+
+* The :module:`CPackComponent` module :command:`cpack_add_component` command
+ gained a new ``PLIST <filename>`` option to specify the ``pkgbuild``
+ ``--component-plist`` argument when using the
+ :module:`productbuild <CPackProductBuild>` generator.
+
+* The :module:`CPackIFW` module :command:`cpack_ifw_configure_component` and
+ :command:`cpack_ifw_configure_component_group` commands gained
+ internationalization support for ``DISPLAY_NAME`` and ``DESCRIPTION``
+ options.
+
+* The :cpack_gen:`CPack IFW Generator` learned the new hint
+ :variable:`CPACK_IFW_ROOT` variable for finding the QtIFW tool suite
+ installed in a non-standard place.
+
+* The :cpack_gen:`CPack productbuild Generator` gained a new
+ :variable:`CPACK_PRODUCTBUILD_RESOURCES_DIR` variable to
+ specify resources to be copied into the ``Resources``
+ directory.
+
+* The :cpack_gen:`CPack RPM Generator` learned to modify the ``debuginfo``
+ package name. See the :variable:`CPACK_RPM_DEBUGINFO_FILE_NAME` variable.
+
+* The :cpack_gen:`CPack WIX Generator` patching system now has the
+ ability to set additional attributes. This can be done by specifying
+ attributes with the ``CPackWiXFragment`` XML tag after the ``Id`` attribute.
+ See the :variable:`CPACK_WIX_PATCH_FILE` variable.
+
+* The :cpack_gen:`CPack WIX Generator` implemented a new
+ :variable:`CPACK_WIX_ROOT_FOLDER_ID` variable which allows
+ using a custom root folder ID instead of the default
+ ``ProgramFilesFolder`` / ``ProgramFiles64Folder``.
+
+Other
+-----
+
+* Interprocedural optimization (IPO) is now supported for GNU and Clang
+ compilers using link time optimization (LTO) flags. See the
+ :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` target property and
+ :module:`CheckIPOSupported` module.
+
+* The ``TARGET_OBJECTS``
+ :manual:`generator expression <cmake-generator-expressions(7)>`
+ is now supported by the :command:`add_custom_command` and
+ :command:`file(GENERATE)` commands.
+
+* Two new informational generator expressions to retrieve Apple Bundle
+ directories have been added. The first one ``$<TARGET_BUNDLE_DIR:tgt>``
+ outputs the full path to the Bundle directory, the other one
+ ``$<TARGET_BUNDLE_CONTENT_DIR:tgt>`` outputs the full path to the
+ ``Contents`` directory of macOS Bundles and App Bundles. For all other
+ bundle types and SDKs it is identical with ``$<TARGET_BUNDLE_DIR:tgt>``.
+ The new expressions are helpful to query Bundle locations independent of
+ the different Bundle types and layouts on macOS and iOS.
+
+Deprecated and Removed Features
+===============================
+
+* An explicit deprecation diagnostic was added for policies ``CMP0036``
+ and below. The :manual:`cmake-policies(7)` manual explains that the
+ OLD behaviors of all policies are deprecated and that projects should
+ always port to the NEW behaviors as soon as possible.
+
+* The :generator:`Visual Studio 8 2005` generator is now deprecated
+ and will be removed in a future version of CMake.
+
+* The :generator:`Visual Studio 7 .NET 2003` generator has been removed.
+
+* The :generator:`Xcode` generator dropped support for Xcode versions
+ older than 3.
+
+* The :module:`FindDoxygen` module has deprecated several variables.
+
+* The version of curl bundled with CMake no longer accepts URLs of the form
+ ``file://c:/...`` on Windows due to a change in upstream curl 7.52. Use
+ the form ``file:///c:/...`` instead to work on all versions.
+
+Other Changes
+=============
+
+* When using :prop_tgt:`AUTOMOC`, CMake now scans for the presence of the
+ ``Q_PLUGIN_METADATA`` macro and reruns moc when the file from the
+ macro's ``FILE`` argument changes.
+
+* When :prop_tgt:`AUTOMOC` detects an include statement of the form
+ ``#include "moc_<basename>.cpp"`` the search for the respective header file
+ now looks in the :prop_tgt:`INCLUDE_DIRECTORIES` of the target as well.
+
+* When running tests, CTest learned to treat skipped tests (using the
+ :prop_test:`SKIP_RETURN_CODE` property) the same as tests with the new
+ :prop_test:`DISABLED` property. Due to this change, CTest will not indicate
+ failure when all tests are either skipped or pass.
+
+* The :generator:`Ninja` generator has loosened the dependencies of object
+ compilation. Object compilation now depends only on custom targets
+ and custom commands associated with libraries on which the object's target
+ depends and no longer depends on the libraries themselves. Source files
+ in dependent targets may now compile without waiting for their targets'
+ dependencies to link.
+
+* On macOS, ``RPATH`` settings such as :prop_tgt:`BUILD_WITH_INSTALL_RPATH`
+ no longer affect the ``install_name`` field. See policy :policy:`CMP0068`.
+
+* The :generator:`Visual Studio 14 2015` generator has been taught about
+ a change to the ``v140`` toolset made by a VS 2015 update. VS changed
+ the set of values it understands for the ``GenerateDebugInformation``
+ linker setting that produces the ``-DEBUG`` linker flag variants.
+
+Updates
+=======
+
+Changes made since CMake 3.9.0 include the following.
+
+3.9.1
+-----
+
+* The ``find_`` command ``PACKAGE_ROOT`` search path group added by
+ CMake 3.9.0 has been removed for the 3.9 series due to regressions
+ caused by new use of ``<PackageName>_ROOT`` variables. The behavior
+ may be re-introduced in the future in a more-compatible way.
+
+3.9.2
+-----
+
+* On macOS, the default application bundle ``Info.plist`` file no longer
+ enables Hi-DPI support as it did in 3.9.0 and 3.9.1. The change had
+ to be reverted because it broke iOS applications.
+
+* The Xcode generator no longer adds "outputPaths" to custom script
+ build phases as it did in 3.9.0 and 3.9.1. This was added in an
+ attempt to support Xcode 9's new build system, but broke incremental
+ rebuilds for both the old and new Xcode build systems.
diff --git a/Help/release/dev.txt b/Help/release/dev.txt
new file mode 100644
index 0000000..2cf9193
--- /dev/null
+++ b/Help/release/dev.txt
@@ -0,0 +1,16 @@
+..
+ This file should be included by the adjacent "index.rst"
+ in development versions but not in release versions.
+
+Changes Since Release
+=====================
+
+The following noteworthy changes have been made in this development
+version since the preceding release but have not yet been consolidated
+into notes for a specific release version:
+
+.. toctree::
+ :maxdepth: 1
+ :glob:
+
+ dev/*
diff --git a/Help/release/dev/0-sample-topic.rst b/Help/release/dev/0-sample-topic.rst
new file mode 100644
index 0000000..e4cc01e
--- /dev/null
+++ b/Help/release/dev/0-sample-topic.rst
@@ -0,0 +1,7 @@
+0-sample-topic
+--------------
+
+* This is a sample release note for the change in a topic.
+ Developers should add similar notes for each topic branch
+ making a noteworthy change. Each document should be named
+ and titled to match the topic name to avoid merge conflicts.
diff --git a/Help/release/dev/FindDevIL-imported-targets.rst b/Help/release/dev/FindDevIL-imported-targets.rst
new file mode 100644
index 0000000..aa0929e
--- /dev/null
+++ b/Help/release/dev/FindDevIL-imported-targets.rst
@@ -0,0 +1,4 @@
+FindDevIL
+---------
+
+* The :module:`FindDevIL` module now provides imported targets.
diff --git a/Help/release/dev/FindIconv-version.rst b/Help/release/dev/FindIconv-version.rst
new file mode 100644
index 0000000..3546d86
--- /dev/null
+++ b/Help/release/dev/FindIconv-version.rst
@@ -0,0 +1,4 @@
+FindIconv-version
+-----------------
+
+* The :module:`FindIconv` module now has version support.
diff --git a/Help/release/dev/FindIntl-version.rst b/Help/release/dev/FindIntl-version.rst
new file mode 100644
index 0000000..5365cf1
--- /dev/null
+++ b/Help/release/dev/FindIntl-version.rst
@@ -0,0 +1,4 @@
+FindIntl-version
+----------------
+
+* The :module:`FindIntl` module now has version support.
diff --git a/Help/release/dev/UseSWIG-csharp.rst b/Help/release/dev/UseSWIG-csharp.rst
new file mode 100644
index 0000000..dbbeaf1
--- /dev/null
+++ b/Help/release/dev/UseSWIG-csharp.rst
@@ -0,0 +1,5 @@
+UseSWIG-csharp
+--------------
+
+* The :module:`UseSWIG` module use now standard library name conventions for
+ ``CSharp`` language. See policy :policy:`CMP0122`.
diff --git a/Help/release/dev/add_custom_command-DEPFILE-genex.rst b/Help/release/dev/add_custom_command-DEPFILE-genex.rst
new file mode 100644
index 0000000..52e5e9f
--- /dev/null
+++ b/Help/release/dev/add_custom_command-DEPFILE-genex.rst
@@ -0,0 +1,5 @@
+add_custom_command-DEPFILE-genex
+--------------------------------
+
+* The :command:`add_custom_command` command ``DEPFILE`` option learned to
+ support :manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/release/dev/c-std.rst b/Help/release/dev/c-std.rst
new file mode 100644
index 0000000..44daa85
--- /dev/null
+++ b/Help/release/dev/c-std.rst
@@ -0,0 +1,6 @@
+c-std
+-----
+
+* :prop_tgt:`C_STANDARD` and the
+ :manual:`Compile Features <cmake-compile-features(7)>` functionality gained
+ support for C17 and C23.
diff --git a/Help/release/dev/cmake-install-prefix-command.rst b/Help/release/dev/cmake-install-prefix-command.rst
new file mode 100644
index 0000000..2de5d91
--- /dev/null
+++ b/Help/release/dev/cmake-install-prefix-command.rst
@@ -0,0 +1,8 @@
+cmake-install-prefix-command
+----------------------------
+
+* The :manual:`cmake(1)` command gained the ``--install-prefix <dir>``
+ command line option to specify the location of the install prefix.
+
+* :manual:`cmake-presets(7)` configure preset gained support for specifying
+ the install prefix.
diff --git a/Help/release/dev/cmake-presets-condition.rst b/Help/release/dev/cmake-presets-condition.rst
new file mode 100644
index 0000000..aa01bc1
--- /dev/null
+++ b/Help/release/dev/cmake-presets-condition.rst
@@ -0,0 +1,4 @@
+cmake-presets-condition
+-----------------------
+
+* :manual:`cmake-presets(7)` now support conditional enabling of presets.
diff --git a/Help/release/dev/cmake-presets-host-system-name.rst b/Help/release/dev/cmake-presets-host-system-name.rst
new file mode 100644
index 0000000..8036939
--- /dev/null
+++ b/Help/release/dev/cmake-presets-host-system-name.rst
@@ -0,0 +1,5 @@
+cmake-presets-host-system-name
+------------------------------
+
+* :manual:`cmake-presets(7)` gained support for a new ``${hostSystemName}``
+ macro.
diff --git a/Help/release/dev/cmake-presets-optional-generator-and-binarydir.rst b/Help/release/dev/cmake-presets-optional-generator-and-binarydir.rst
new file mode 100644
index 0000000..7973489
--- /dev/null
+++ b/Help/release/dev/cmake-presets-optional-generator-and-binarydir.rst
@@ -0,0 +1,5 @@
+cmake-presets-optional-generator-and-binarydir
+----------------------------------------------
+
+* :manual:`cmake-presets(7)` now support omitting the ``generator`` and
+ ``binaryDir`` fields.
diff --git a/Help/release/dev/cmake-system-name-version.rst b/Help/release/dev/cmake-system-name-version.rst
new file mode 100644
index 0000000..9cfe401
--- /dev/null
+++ b/Help/release/dev/cmake-system-name-version.rst
@@ -0,0 +1,10 @@
+cmake-system-name-version
+-------------------------
+
+* :variable:`CMAKE_HOST_SYSTEM_NAME`'s undocumented version-stripping behavior
+ has been moved earlier, before :command:`project` or
+ :command:`enable_language` is called.
+* :variable:`CMAKE_SYSTEM_NAME`'s undocumented version-stripping behavior has
+ been removed entirely. If it is set by a ``-D`` flag or by a
+ :manual:`toolchain file <cmake-toolchains(7)>`, it is left unaltered, even if
+ it still contains a version number.
diff --git a/Help/release/dev/cpack-dmg-filesystem.rst b/Help/release/dev/cpack-dmg-filesystem.rst
new file mode 100644
index 0000000..e2a4742
--- /dev/null
+++ b/Help/release/dev/cpack-dmg-filesystem.rst
@@ -0,0 +1,5 @@
+cpack-dmg-filesystem
+--------------------
+
+* The :cpack_gen:`CPack DragNDrop Generator` gained option
+ :variable:`CPACK_DMG_FILESYSTEM` to control the ``.dmg`` filesystem.
diff --git a/Help/release/dev/cpack-nsis-executable-name.rst b/Help/release/dev/cpack-nsis-executable-name.rst
new file mode 100644
index 0000000..a3818db
--- /dev/null
+++ b/Help/release/dev/cpack-nsis-executable-name.rst
@@ -0,0 +1,6 @@
+cpack-nsis-executable-name
+--------------------------
+
+* The :cpack_gen:`CPack NSIS Generator` gained a new variable
+ :variable:`CPACK_NSIS_EXECUTABLE` to specify the makensis
+ executable to use instead of the default one.
diff --git a/Help/release/dev/cxx-module-extensions.rst b/Help/release/dev/cxx-module-extensions.rst
new file mode 100644
index 0000000..b9d0a8a
--- /dev/null
+++ b/Help/release/dev/cxx-module-extensions.rst
@@ -0,0 +1,4 @@
+cxx-module-extensions
+---------------------
+
+* Source file extensions ``.ixx`` and ``.cppm`` are now treated as C++.
diff --git a/Help/release/dev/file-COPY_FILE.rst b/Help/release/dev/file-COPY_FILE.rst
new file mode 100644
index 0000000..2f0cdf0
--- /dev/null
+++ b/Help/release/dev/file-COPY_FILE.rst
@@ -0,0 +1,4 @@
+file-COPY_ONLY
+--------------
+
+* The :command:`file(COPY_FILE)` command was added to copy a file to another.
diff --git a/Help/release/dev/file-RENAME.rst b/Help/release/dev/file-RENAME.rst
new file mode 100644
index 0000000..6c1314d
--- /dev/null
+++ b/Help/release/dev/file-RENAME.rst
@@ -0,0 +1,6 @@
+file-RENAME
+-----------
+
+* The :command:`file(RENAME)` command learned to optionally capture
+ failure in a result variable. It also gained a ``NO_REPLACE``
+ option to fail if the destination exists.
diff --git a/Help/release/dev/fileapi-codemodel-directory.rst b/Help/release/dev/fileapi-codemodel-directory.rst
new file mode 100644
index 0000000..f6515fd
--- /dev/null
+++ b/Help/release/dev/fileapi-codemodel-directory.rst
@@ -0,0 +1,10 @@
+fileapi-codemodel-directory
+---------------------------
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 ``version`` field has
+ component been updated to 2.3.
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 gained a
+ new "directory" object containing directory-level information.
+ This includes a list of installers generated by the :command:`install`
+ command.
diff --git a/Help/release/dev/fujitsu-compiler-support.rst b/Help/release/dev/fujitsu-compiler-support.rst
new file mode 100644
index 0000000..c6f8cfb
--- /dev/null
+++ b/Help/release/dev/fujitsu-compiler-support.rst
@@ -0,0 +1,11 @@
+fujitsu-compiler-support
+------------------------
+
+* Addition of the ``Fujitsu`` compiler ID operating in traditional ``Trad``
+ mode and ``FujitsuClang`` operating in ``Clang`` mode.
+* The :module:`FindOpenMP` module learned to support ``Fujitsu`` and
+ ``FujitsuClang``.
+* The :module:`FindMPI` module learned to support ``Fujitsu`` and
+ ``FujitsuClang`` in both host and cross compiling modes.
+* The :module:`FindBLAS` and :module:`FindLAPACK` modules learned to support
+ the serial ``Fujitsu SSL2`` and parallel ``Fujitsu SSL2BLAMP`` libraries.
diff --git a/Help/release/dev/ifw-default-version-operator.rst b/Help/release/dev/ifw-default-version-operator.rst
new file mode 100644
index 0000000..4aeace2
--- /dev/null
+++ b/Help/release/dev/ifw-default-version-operator.rst
@@ -0,0 +1,7 @@
+ifw-default-version-operator
+----------------------------
+
+* Names given as ``DEPENDS`` or ``DEPENDENCIES`` arguments to
+ :command:`cpack_ifw_configure_component` or
+ :command:`cpack_ifw_configure_component_group` may now contain hyphens.
+ This requires QtIFW 3.1 or later.
diff --git a/Help/release/dev/list-index-arg-parsing.rst b/Help/release/dev/list-index-arg-parsing.rst
new file mode 100644
index 0000000..2ea525b
--- /dev/null
+++ b/Help/release/dev/list-index-arg-parsing.rst
@@ -0,0 +1,7 @@
+list-index-arg-parsing
+----------------------
+
+* The :command:`list` command's ``GET``, ``INSERT``, ``SUBLIST``, and
+ ``REMOVE_AT`` subcommands now error with invalid (i.e., non-integer) values
+ are given as any of their index arguments based on the setting of policy
+ :policy:`CMP0121`.
diff --git a/Help/release/dev/project-is-top-level.rst b/Help/release/dev/project-is-top-level.rst
new file mode 100644
index 0000000..568afe0
--- /dev/null
+++ b/Help/release/dev/project-is-top-level.rst
@@ -0,0 +1,6 @@
+project-is-top-level
+--------------------
+
+* :command:`project` now sets variables :variable:`PROJECT_IS_TOP_LEVEL` and
+ :variable:`<PROJECT-NAME>_IS_TOP_LEVEL` to indicate whether it was called
+ in a top level ``CMakeLists.txt`` file.
diff --git a/Help/release/dev/runtime-dll-deps.rst b/Help/release/dev/runtime-dll-deps.rst
new file mode 100644
index 0000000..831410f
--- /dev/null
+++ b/Help/release/dev/runtime-dll-deps.rst
@@ -0,0 +1,4 @@
+runtime-dll-deps
+----------------
+
+* A new :genex:`TARGET_RUNTIME_DLLS` generator expression was added.
diff --git a/Help/release/index.rst b/Help/release/index.rst
new file mode 100644
index 0000000..5dfca05
--- /dev/null
+++ b/Help/release/index.rst
@@ -0,0 +1,38 @@
+:orphan:
+
+CMake Release Notes
+*******************
+
+..
+ This file should include the adjacent "dev.txt" file
+ in development versions but not in release versions.
+
+.. include:: dev.txt
+
+Releases
+========
+
+.. toctree::
+ :maxdepth: 1
+
+ 3.20 <3.20>
+ 3.19 <3.19>
+ 3.18 <3.18>
+ 3.17 <3.17>
+ 3.16 <3.16>
+ 3.15 <3.15>
+ 3.14 <3.14>
+ 3.13 <3.13>
+ 3.12 <3.12>
+ 3.11 <3.11>
+ 3.10 <3.10>
+ 3.9 <3.9>
+ 3.8 <3.8>
+ 3.7 <3.7>
+ 3.6 <3.6>
+ 3.5 <3.5>
+ 3.4 <3.4>
+ 3.3 <3.3>
+ 3.2 <3.2>
+ 3.1 <3.1>
+ 3.0 <3.0>
diff --git a/Help/variable/ANDROID.rst b/Help/variable/ANDROID.rst
new file mode 100644
index 0000000..68dccf2
--- /dev/null
+++ b/Help/variable/ANDROID.rst
@@ -0,0 +1,7 @@
+ANDROID
+-------
+
+.. versionadded:: 3.7
+
+Set to ``1`` when the target system (:variable:`CMAKE_SYSTEM_NAME`) is
+``Android``.
diff --git a/Help/variable/APPLE.rst b/Help/variable/APPLE.rst
new file mode 100644
index 0000000..810d5fc
--- /dev/null
+++ b/Help/variable/APPLE.rst
@@ -0,0 +1,5 @@
+APPLE
+-----
+
+Set to ``True`` when the target system is an Apple platform
+(macOS, iOS, tvOS or watchOS).
diff --git a/Help/variable/BORLAND.rst b/Help/variable/BORLAND.rst
new file mode 100644
index 0000000..badb733
--- /dev/null
+++ b/Help/variable/BORLAND.rst
@@ -0,0 +1,6 @@
+BORLAND
+-------
+
+``True`` if the Borland compiler is being used.
+
+This is set to ``true`` if the Borland compiler is being used.
diff --git a/Help/variable/BUILD_SHARED_LIBS.rst b/Help/variable/BUILD_SHARED_LIBS.rst
new file mode 100644
index 0000000..53087b2
--- /dev/null
+++ b/Help/variable/BUILD_SHARED_LIBS.rst
@@ -0,0 +1,10 @@
+BUILD_SHARED_LIBS
+-----------------
+
+Global flag to cause :command:`add_library` to create shared libraries if on.
+
+If present and true, this will cause all libraries to be built shared
+unless the library was explicitly added as a static library. This
+variable is often added to projects as an :command:`option` so that each user
+of a project can decide if they want to build the project using shared or
+static libraries.
diff --git a/Help/variable/CACHE.rst b/Help/variable/CACHE.rst
new file mode 100644
index 0000000..d5489c8
--- /dev/null
+++ b/Help/variable/CACHE.rst
@@ -0,0 +1,20 @@
+CACHE
+-----
+
+.. versionadded:: 3.13
+
+Operator to read cache variables.
+
+Use the syntax ``$CACHE{VAR}`` to read cache entry ``VAR``.
+See the :ref:`cmake-language(7) variables <CMake Language Variables>`
+documentation for more complete documentation of the interaction of
+normal variables and cache entries.
+
+When evaluating :ref:`Variable References` of the form ``${VAR}``,
+CMake first searches for a normal variable with that name, and if not
+found CMake will search for a cache entry with that name.
+The ``$CACHE{VAR}`` syntax can be used to do direct cache lookup and
+ignore any existing normal variable.
+
+See the :command:`set` and :command:`unset` commands to see how to
+write or remove cache variables.
diff --git a/Help/variable/CMAKE_ABSOLUTE_DESTINATION_FILES.rst b/Help/variable/CMAKE_ABSOLUTE_DESTINATION_FILES.rst
new file mode 100644
index 0000000..b6d0054
--- /dev/null
+++ b/Help/variable/CMAKE_ABSOLUTE_DESTINATION_FILES.rst
@@ -0,0 +1,9 @@
+CMAKE_ABSOLUTE_DESTINATION_FILES
+--------------------------------
+
+List of files which have been installed using an ``ABSOLUTE DESTINATION`` path.
+
+This variable is defined by CMake-generated ``cmake_install.cmake``
+scripts. It can be used (read-only) by programs or scripts that
+source those install scripts. This is used by some CPack generators
+(e.g. RPM).
diff --git a/Help/variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS.rst b/Help/variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS.rst
new file mode 100644
index 0000000..699fe0f
--- /dev/null
+++ b/Help/variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS.rst
@@ -0,0 +1,8 @@
+CMAKE_AIX_EXPORT_ALL_SYMBOLS
+----------------------------
+
+.. versionadded:: 3.17
+
+Default value for :prop_tgt:`AIX_EXPORT_ALL_SYMBOLS` target property.
+This variable is used to initialize the property on each target as it is
+created.
diff --git a/Help/variable/CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS.rst b/Help/variable/CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS.rst
new file mode 100644
index 0000000..2d6b4b9
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS
+------------------------------------
+
+.. versionadded:: 3.4
+
+Default value for the :prop_tgt:`ANDROID_ANT_ADDITIONAL_OPTIONS` target property.
+See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_API.rst b/Help/variable/CMAKE_ANDROID_API.rst
new file mode 100644
index 0000000..4388bf2
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_API.rst
@@ -0,0 +1,13 @@
+CMAKE_ANDROID_API
+-----------------
+
+.. versionadded:: 3.1
+
+When :ref:`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio
+Edition`, this variable may be set to specify the default value for the
+:prop_tgt:`ANDROID_API` target property. See that target property for
+additional information.
+
+Otherwise, when :ref:`Cross Compiling for Android`, this variable provides
+the Android API version number targeted. This will be the same value as
+the :variable:`CMAKE_SYSTEM_VERSION` variable for ``Android`` platforms.
diff --git a/Help/variable/CMAKE_ANDROID_API_MIN.rst b/Help/variable/CMAKE_ANDROID_API_MIN.rst
new file mode 100644
index 0000000..a0d2ab4
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_API_MIN.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_API_MIN
+---------------------
+
+.. versionadded:: 3.2
+
+Default value for the :prop_tgt:`ANDROID_API_MIN` target property.
+See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_ARCH.rst b/Help/variable/CMAKE_ANDROID_ARCH.rst
new file mode 100644
index 0000000..9f12742
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_ARCH.rst
@@ -0,0 +1,21 @@
+CMAKE_ANDROID_ARCH
+------------------
+
+.. versionadded:: 3.4
+
+When :ref:`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio
+Edition`, this variable may be set to specify the default value for the
+:prop_tgt:`ANDROID_ARCH` target property. See that target property for
+additional information.
+
+Otherwise, when :ref:`Cross Compiling for Android`, this variable provides
+the name of the Android architecture corresponding to the value of the
+:variable:`CMAKE_ANDROID_ARCH_ABI` variable. The architecture name
+may be one of:
+
+* ``arm``
+* ``arm64``
+* ``mips``
+* ``mips64``
+* ``x86``
+* ``x86_64``
diff --git a/Help/variable/CMAKE_ANDROID_ARCH_ABI.rst b/Help/variable/CMAKE_ANDROID_ARCH_ABI.rst
new file mode 100644
index 0000000..5a2e3ec
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_ARCH_ABI.rst
@@ -0,0 +1,19 @@
+CMAKE_ANDROID_ARCH_ABI
+----------------------
+
+.. versionadded:: 3.7
+
+When :ref:`Cross Compiling for Android`, this variable specifies the
+target architecture and ABI to be used. Valid values are:
+
+* ``arm64-v8a``
+* ``armeabi-v7a``
+* ``armeabi-v6``
+* ``armeabi``
+* ``mips``
+* ``mips64``
+* ``x86``
+* ``x86_64``
+
+See also the :variable:`CMAKE_ANDROID_ARM_MODE` and
+:variable:`CMAKE_ANDROID_ARM_NEON` variables.
diff --git a/Help/variable/CMAKE_ANDROID_ARM_MODE.rst b/Help/variable/CMAKE_ANDROID_ARM_MODE.rst
new file mode 100644
index 0000000..973ff7e
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_ARM_MODE.rst
@@ -0,0 +1,9 @@
+CMAKE_ANDROID_ARM_MODE
+----------------------
+
+.. versionadded:: 3.7
+
+When :ref:`Cross Compiling for Android` and :variable:`CMAKE_ANDROID_ARCH_ABI`
+is set to one of the ``armeabi`` architectures, set ``CMAKE_ANDROID_ARM_MODE``
+to ``ON`` to target 32-bit ARM processors (``-marm``). Otherwise, the
+default is to target the 16-bit Thumb processors (``-mthumb``).
diff --git a/Help/variable/CMAKE_ANDROID_ARM_NEON.rst b/Help/variable/CMAKE_ANDROID_ARM_NEON.rst
new file mode 100644
index 0000000..6b9cf08
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_ARM_NEON.rst
@@ -0,0 +1,8 @@
+CMAKE_ANDROID_ARM_NEON
+----------------------
+
+.. versionadded:: 3.7
+
+When :ref:`Cross Compiling for Android` and :variable:`CMAKE_ANDROID_ARCH_ABI`
+is set to ``armeabi-v7a`` set ``CMAKE_ANDROID_ARM_NEON`` to ``ON`` to target
+ARM NEON devices.
diff --git a/Help/variable/CMAKE_ANDROID_ASSETS_DIRECTORIES.rst b/Help/variable/CMAKE_ANDROID_ASSETS_DIRECTORIES.rst
new file mode 100644
index 0000000..3de2be4
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_ASSETS_DIRECTORIES.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_ASSETS_DIRECTORIES
+--------------------------------
+
+.. versionadded:: 3.4
+
+Default value for the :prop_tgt:`ANDROID_ASSETS_DIRECTORIES` target property.
+See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_EXCEPTIONS.rst b/Help/variable/CMAKE_ANDROID_EXCEPTIONS.rst
new file mode 100644
index 0000000..6dd44f8
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_EXCEPTIONS.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_EXCEPTIONS
+------------------------
+
+.. versionadded:: 3.20
+
+When :ref:`Cross Compiling for Android with the NDK`, this variable may be set
+to specify whether exceptions are enabled.
diff --git a/Help/variable/CMAKE_ANDROID_GUI.rst b/Help/variable/CMAKE_ANDROID_GUI.rst
new file mode 100644
index 0000000..821bbee
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_GUI.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_GUI
+-----------------
+
+.. versionadded:: 3.1
+
+Default value for the :prop_tgt:`ANDROID_GUI` target property of
+executables. See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_JAR_DEPENDENCIES.rst b/Help/variable/CMAKE_ANDROID_JAR_DEPENDENCIES.rst
new file mode 100644
index 0000000..80ab842
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_JAR_DEPENDENCIES.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_JAR_DEPENDENCIES
+------------------------------
+
+.. versionadded:: 3.4
+
+Default value for the :prop_tgt:`ANDROID_JAR_DEPENDENCIES` target property.
+See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_JAR_DIRECTORIES.rst b/Help/variable/CMAKE_ANDROID_JAR_DIRECTORIES.rst
new file mode 100644
index 0000000..4d148d8
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_JAR_DIRECTORIES.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_JAR_DIRECTORIES
+-----------------------------
+
+.. versionadded:: 3.4
+
+Default value for the :prop_tgt:`ANDROID_JAR_DIRECTORIES` target property.
+See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_JAVA_SOURCE_DIR.rst b/Help/variable/CMAKE_ANDROID_JAVA_SOURCE_DIR.rst
new file mode 100644
index 0000000..021baa0
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_JAVA_SOURCE_DIR.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_JAVA_SOURCE_DIR
+-----------------------------
+
+.. versionadded:: 3.4
+
+Default value for the :prop_tgt:`ANDROID_JAVA_SOURCE_DIR` target property.
+See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES.rst b/Help/variable/CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES.rst
new file mode 100644
index 0000000..41d4cc3
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES
+-------------------------------------
+
+.. versionadded:: 3.4
+
+Default value for the :prop_tgt:`ANDROID_NATIVE_LIB_DEPENDENCIES` target
+property. See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES.rst b/Help/variable/CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES.rst
new file mode 100644
index 0000000..e87547d
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES
+------------------------------------
+
+.. versionadded:: 3.4
+
+Default value for the :prop_tgt:`ANDROID_NATIVE_LIB_DIRECTORIES` target
+property. See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_NDK.rst b/Help/variable/CMAKE_ANDROID_NDK.rst
new file mode 100644
index 0000000..72ac99e
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_NDK.rst
@@ -0,0 +1,9 @@
+CMAKE_ANDROID_NDK
+-----------------
+
+.. versionadded:: 3.7
+
+When :ref:`Cross Compiling for Android with the NDK`, this variable holds
+the absolute path to the root directory of the NDK. The directory must
+contain a ``platforms`` subdirectory holding the ``android-<api>``
+directories.
diff --git a/Help/variable/CMAKE_ANDROID_NDK_DEPRECATED_HEADERS.rst b/Help/variable/CMAKE_ANDROID_NDK_DEPRECATED_HEADERS.rst
new file mode 100644
index 0000000..40a5c1a
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_NDK_DEPRECATED_HEADERS.rst
@@ -0,0 +1,11 @@
+CMAKE_ANDROID_NDK_DEPRECATED_HEADERS
+------------------------------------
+
+.. versionadded:: 3.9
+
+When :ref:`Cross Compiling for Android with the NDK`, this variable
+may be set to specify whether to use the deprecated per-api-level
+headers instead of the unified headers.
+
+If not specified, the default will be *false* if using a NDK version
+that provides the unified headers and *true* otherwise.
diff --git a/Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG.rst b/Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG.rst
new file mode 100644
index 0000000..9d61fa4
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG.rst
@@ -0,0 +1,8 @@
+CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG
+------------------------------------
+
+.. versionadded:: 3.7.1
+
+When :ref:`Cross Compiling for Android with the NDK`, this variable
+provides the NDK's "host tag" used to construct the path to prebuilt
+toolchains that run on the host.
diff --git a/Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst b/Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst
new file mode 100644
index 0000000..15fe18f
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst
@@ -0,0 +1,22 @@
+CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION
+-----------------------------------
+
+.. versionadded:: 3.7
+
+When :ref:`Cross Compiling for Android with the NDK`, this variable
+may be set to specify the version of the toolchain to be used
+as the compiler.
+
+On NDK r19 or above, this variable must be unset or set to ``clang``.
+
+On NDK r18 or below, this variable must be set to one of these forms:
+
+* ``<major>.<minor>``: GCC of specified version
+* ``clang<major>.<minor>``: Clang of specified version
+* ``clang``: Clang of most recent available version
+
+A toolchain of the requested version will be selected automatically to
+match the ABI named in the :variable:`CMAKE_ANDROID_ARCH_ABI` variable.
+
+If not specified, the default will be a value that selects the latest
+available GCC toolchain.
diff --git a/Help/variable/CMAKE_ANDROID_NDK_VERSION.rst b/Help/variable/CMAKE_ANDROID_NDK_VERSION.rst
new file mode 100644
index 0000000..5428d52
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_NDK_VERSION.rst
@@ -0,0 +1,8 @@
+CMAKE_ANDROID_NDK_VERSION
+-------------------------
+
+.. versionadded:: 3.20
+
+When :ref:`Cross Compiling for Android with the NDK` and using an
+Android NDK version 11 or higher, this variable is provided by
+CMake to report the NDK version number.
diff --git a/Help/variable/CMAKE_ANDROID_PROCESS_MAX.rst b/Help/variable/CMAKE_ANDROID_PROCESS_MAX.rst
new file mode 100644
index 0000000..be241c2
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_PROCESS_MAX.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_PROCESS_MAX
+-------------------------
+
+.. versionadded:: 3.4
+
+Default value for the :prop_tgt:`ANDROID_PROCESS_MAX` target property.
+See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_PROGUARD.rst b/Help/variable/CMAKE_ANDROID_PROGUARD.rst
new file mode 100644
index 0000000..bb001d3
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_PROGUARD.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_PROGUARD
+----------------------
+
+.. versionadded:: 3.4
+
+Default value for the :prop_tgt:`ANDROID_PROGUARD` target property.
+See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_PROGUARD_CONFIG_PATH.rst b/Help/variable/CMAKE_ANDROID_PROGUARD_CONFIG_PATH.rst
new file mode 100644
index 0000000..6fd4067
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_PROGUARD_CONFIG_PATH.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_PROGUARD_CONFIG_PATH
+----------------------------------
+
+.. versionadded:: 3.4
+
+Default value for the :prop_tgt:`ANDROID_PROGUARD_CONFIG_PATH` target property.
+See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_RTTI.rst b/Help/variable/CMAKE_ANDROID_RTTI.rst
new file mode 100644
index 0000000..0e98206
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_RTTI.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_RTTI
+------------------
+
+.. versionadded:: 3.20
+
+When :ref:`Cross Compiling for Android with the NDK`, this variable may be set
+to specify whether RTTI is enabled.
diff --git a/Help/variable/CMAKE_ANDROID_SECURE_PROPS_PATH.rst b/Help/variable/CMAKE_ANDROID_SECURE_PROPS_PATH.rst
new file mode 100644
index 0000000..9f5743e
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_SECURE_PROPS_PATH.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_SECURE_PROPS_PATH
+-------------------------------
+
+.. versionadded:: 3.4
+
+Default value for the :prop_tgt:`ANDROID_SECURE_PROPS_PATH` target property.
+See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_SKIP_ANT_STEP.rst b/Help/variable/CMAKE_ANDROID_SKIP_ANT_STEP.rst
new file mode 100644
index 0000000..588769b
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_SKIP_ANT_STEP.rst
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_SKIP_ANT_STEP
+---------------------------
+
+.. versionadded:: 3.4
+
+Default value for the :prop_tgt:`ANDROID_SKIP_ANT_STEP` target property.
+See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_STANDALONE_TOOLCHAIN.rst b/Help/variable/CMAKE_ANDROID_STANDALONE_TOOLCHAIN.rst
new file mode 100644
index 0000000..3ca89f5
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_STANDALONE_TOOLCHAIN.rst
@@ -0,0 +1,8 @@
+CMAKE_ANDROID_STANDALONE_TOOLCHAIN
+----------------------------------
+
+.. versionadded:: 3.7
+
+When :ref:`Cross Compiling for Android with a Standalone Toolchain`, this
+variable holds the absolute path to the root directory of the toolchain.
+The specified directory must contain a ``sysroot`` subdirectory.
diff --git a/Help/variable/CMAKE_ANDROID_STL_TYPE.rst b/Help/variable/CMAKE_ANDROID_STL_TYPE.rst
new file mode 100644
index 0000000..3778181
--- /dev/null
+++ b/Help/variable/CMAKE_ANDROID_STL_TYPE.rst
@@ -0,0 +1,39 @@
+CMAKE_ANDROID_STL_TYPE
+----------------------
+
+.. versionadded:: 3.4
+
+When :ref:`Cross Compiling for Android with NVIDIA Nsight Tegra Visual Studio
+Edition`, this variable may be set to specify the default value for the
+:prop_tgt:`ANDROID_STL_TYPE` target property. See that target property
+for additional information.
+
+When :ref:`Cross Compiling for Android with the NDK`, this variable may be
+set to specify the STL variant to be used. The value may be one of:
+
+``none``
+ No C++ Support
+``system``
+ Minimal C++ without STL
+``gabi++_static``
+ GAbi++ Static
+``gabi++_shared``
+ GAbi++ Shared
+``gnustl_static``
+ GNU libstdc++ Static
+``gnustl_shared``
+ GNU libstdc++ Shared
+``c++_static``
+ LLVM libc++ Static
+``c++_shared``
+ LLVM libc++ Shared
+``stlport_static``
+ STLport Static
+``stlport_shared``
+ STLport Shared
+
+The default value is ``gnustl_static`` on NDK versions that provide it
+and otherwise ``c++_static``. Note that this default differs from
+the native NDK build system because CMake may be used to build projects for
+Android that are not natively implemented for it and use the C++ standard
+library.
diff --git a/Help/variable/CMAKE_APPBUNDLE_PATH.rst b/Help/variable/CMAKE_APPBUNDLE_PATH.rst
new file mode 100644
index 0000000..1c7ca51
--- /dev/null
+++ b/Help/variable/CMAKE_APPBUNDLE_PATH.rst
@@ -0,0 +1,6 @@
+CMAKE_APPBUNDLE_PATH
+--------------------
+
+:ref:`Semicolon-separated list <CMake Language Lists>` of directories specifying a search path
+for macOS application bundles used by the :command:`find_program`, and
+:command:`find_package` commands.
diff --git a/Help/variable/CMAKE_APPLE_SILICON_PROCESSOR.rst b/Help/variable/CMAKE_APPLE_SILICON_PROCESSOR.rst
new file mode 100644
index 0000000..0d5ccd1
--- /dev/null
+++ b/Help/variable/CMAKE_APPLE_SILICON_PROCESSOR.rst
@@ -0,0 +1,14 @@
+CMAKE_APPLE_SILICON_PROCESSOR
+-----------------------------
+
+.. versionadded:: 3.19.2
+
+On Apple Silicon hosts running macOS, set this variable to tell
+CMake what architecture to use for :variable:`CMAKE_HOST_SYSTEM_PROCESSOR`.
+The value must be either ``arm64`` or ``x86_64``.
+
+The value of this variable should never be modified by project code.
+It is meant to be set as a cache entry provided by the user,
+e.g. via ``-DCMAKE_APPLE_SILICON_PROCESSOR=...``.
+
+See also the :envvar:`CMAKE_APPLE_SILICON_PROCESSOR` environment variable.
diff --git a/Help/variable/CMAKE_AR.rst b/Help/variable/CMAKE_AR.rst
new file mode 100644
index 0000000..5893677
--- /dev/null
+++ b/Help/variable/CMAKE_AR.rst
@@ -0,0 +1,7 @@
+CMAKE_AR
+--------
+
+Name of archiving tool for static libraries.
+
+This specifies the name of the program that creates archive or static
+libraries.
diff --git a/Help/variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY.rst b/Help/variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY.rst
new file mode 100644
index 0000000..c889321
--- /dev/null
+++ b/Help/variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY.rst
@@ -0,0 +1,9 @@
+CMAKE_ARCHIVE_OUTPUT_DIRECTORY
+------------------------------
+
+Where to put all the :ref:`ARCHIVE <Archive Output Artifacts>`
+target files when built.
+
+This variable is used to initialize the :prop_tgt:`ARCHIVE_OUTPUT_DIRECTORY`
+property on all the targets. See that target property for additional
+information.
diff --git a/Help/variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY_CONFIG.rst b/Help/variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY_CONFIG.rst
new file mode 100644
index 0000000..d8bd82c
--- /dev/null
+++ b/Help/variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY_CONFIG.rst
@@ -0,0 +1,11 @@
+CMAKE_ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>
+---------------------------------------
+
+.. versionadded:: 3.3
+
+Where to put all the :ref:`ARCHIVE <Archive Output Artifacts>`
+target files when built for a specific configuration.
+
+This variable is used to initialize the
+:prop_tgt:`ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>` property on all the targets.
+See that target property for additional information.
diff --git a/Help/variable/CMAKE_ARGC.rst b/Help/variable/CMAKE_ARGC.rst
new file mode 100644
index 0000000..30db2a2
--- /dev/null
+++ b/Help/variable/CMAKE_ARGC.rst
@@ -0,0 +1,8 @@
+CMAKE_ARGC
+----------
+
+Number of command line arguments passed to CMake in script mode.
+
+When run in :ref:`-P <Script Processing Mode>` script mode, CMake sets this
+variable to the number of command line arguments. See also
+:variable:`CMAKE_ARGV0`, ``1``, ``2`` ...
diff --git a/Help/variable/CMAKE_ARGV0.rst b/Help/variable/CMAKE_ARGV0.rst
new file mode 100644
index 0000000..c4d1c21
--- /dev/null
+++ b/Help/variable/CMAKE_ARGV0.rst
@@ -0,0 +1,9 @@
+CMAKE_ARGV0
+-----------
+
+Command line argument passed to CMake in script mode.
+
+When run in :ref:`-P <Script Processing Mode>` script mode, CMake sets this
+variable to the first command line argument. It then also sets ``CMAKE_ARGV1``,
+``CMAKE_ARGV2``, ... and so on, up to the number of command line arguments
+given. See also :variable:`CMAKE_ARGC`.
diff --git a/Help/variable/CMAKE_AUTOGEN_ORIGIN_DEPENDS.rst b/Help/variable/CMAKE_AUTOGEN_ORIGIN_DEPENDS.rst
new file mode 100644
index 0000000..c24e462
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOGEN_ORIGIN_DEPENDS.rst
@@ -0,0 +1,13 @@
+CMAKE_AUTOGEN_ORIGIN_DEPENDS
+----------------------------
+
+.. versionadded:: 3.14
+
+Switch for forwarding origin target dependencies to the corresponding
+``_autogen`` targets.
+
+This variable is used to initialize the :prop_tgt:`AUTOGEN_ORIGIN_DEPENDS`
+property on all the targets. See that target property for additional
+information.
+
+By default :variable:`CMAKE_AUTOGEN_ORIGIN_DEPENDS` is ``ON``.
diff --git a/Help/variable/CMAKE_AUTOGEN_PARALLEL.rst b/Help/variable/CMAKE_AUTOGEN_PARALLEL.rst
new file mode 100644
index 0000000..2ada012
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOGEN_PARALLEL.rst
@@ -0,0 +1,12 @@
+CMAKE_AUTOGEN_PARALLEL
+----------------------
+
+.. versionadded:: 3.11
+
+Number of parallel ``moc`` or ``uic`` processes to start when using
+:prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+
+This variable is used to initialize the :prop_tgt:`AUTOGEN_PARALLEL` property
+on all the targets. See that target property for additional information.
+
+By default :variable:`CMAKE_AUTOGEN_PARALLEL` is unset.
diff --git a/Help/variable/CMAKE_AUTOGEN_VERBOSE.rst b/Help/variable/CMAKE_AUTOGEN_VERBOSE.rst
new file mode 100644
index 0000000..f77ed6a
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOGEN_VERBOSE.rst
@@ -0,0 +1,15 @@
+CMAKE_AUTOGEN_VERBOSE
+---------------------
+
+.. versionadded:: 3.13
+
+Sets the verbosity of :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTOUIC` and
+:prop_tgt:`AUTORCC`. A positive integer value or a true boolean value
+lets the ``AUTO*`` generators output additional processing information.
+
+Setting :variable:`CMAKE_AUTOGEN_VERBOSE` has the same effect
+as setting the ``VERBOSE`` environment variable during
+generation (e.g. by calling ``make VERBOSE=1``).
+The extra verbosity is limited to the ``AUTO*`` generators though.
+
+By default :variable:`CMAKE_AUTOGEN_VERBOSE` is unset.
diff --git a/Help/variable/CMAKE_AUTOMOC.rst b/Help/variable/CMAKE_AUTOMOC.rst
new file mode 100644
index 0000000..02e5eb5
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOMOC.rst
@@ -0,0 +1,7 @@
+CMAKE_AUTOMOC
+-------------
+
+Whether to handle ``moc`` automatically for Qt targets.
+
+This variable is used to initialize the :prop_tgt:`AUTOMOC` property on all the
+targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_AUTOMOC_COMPILER_PREDEFINES.rst b/Help/variable/CMAKE_AUTOMOC_COMPILER_PREDEFINES.rst
new file mode 100644
index 0000000..f1b03a0
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOMOC_COMPILER_PREDEFINES.rst
@@ -0,0 +1,10 @@
+CMAKE_AUTOMOC_COMPILER_PREDEFINES
+---------------------------------
+
+.. versionadded:: 3.10
+
+This variable is used to initialize the :prop_tgt:`AUTOMOC_COMPILER_PREDEFINES`
+property on all the targets. See that target property for additional
+information.
+
+By default it is ON.
diff --git a/Help/variable/CMAKE_AUTOMOC_DEPEND_FILTERS.rst b/Help/variable/CMAKE_AUTOMOC_DEPEND_FILTERS.rst
new file mode 100644
index 0000000..2c1551a
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOMOC_DEPEND_FILTERS.rst
@@ -0,0 +1,14 @@
+CMAKE_AUTOMOC_DEPEND_FILTERS
+----------------------------
+
+.. versionadded:: 3.9
+
+Filter definitions used by :variable:`CMAKE_AUTOMOC`
+to extract file names from source code as additional dependencies
+for the ``moc`` file.
+
+This variable is used to initialize the :prop_tgt:`AUTOMOC_DEPEND_FILTERS`
+property on all the targets. See that target property for additional
+information.
+
+By default it is empty.
diff --git a/Help/variable/CMAKE_AUTOMOC_MACRO_NAMES.rst b/Help/variable/CMAKE_AUTOMOC_MACRO_NAMES.rst
new file mode 100644
index 0000000..1153cb2
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOMOC_MACRO_NAMES.rst
@@ -0,0 +1,22 @@
+CMAKE_AUTOMOC_MACRO_NAMES
+----------------------------
+
+.. versionadded:: 3.10
+
+:ref:`Semicolon-separated list <CMake Language Lists>` list of macro names used by
+:variable:`CMAKE_AUTOMOC` to determine if a C++ file needs to be
+processed by ``moc``.
+
+This variable is used to initialize the :prop_tgt:`AUTOMOC_MACRO_NAMES`
+property on all the targets. See that target property for additional
+information.
+
+The default value is ``Q_OBJECT;Q_GADGET;Q_NAMESPACE;Q_NAMESPACE_EXPORT``.
+
+Example
+^^^^^^^
+Let CMake know that source files that contain ``CUSTOM_MACRO`` must be ``moc``
+processed as well::
+
+ set(CMAKE_AUTOMOC ON)
+ list(APPEND CMAKE_AUTOMOC_MACRO_NAMES "CUSTOM_MACRO")
diff --git a/Help/variable/CMAKE_AUTOMOC_MOC_OPTIONS.rst b/Help/variable/CMAKE_AUTOMOC_MOC_OPTIONS.rst
new file mode 100644
index 0000000..09bf5cd
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOMOC_MOC_OPTIONS.rst
@@ -0,0 +1,7 @@
+CMAKE_AUTOMOC_MOC_OPTIONS
+-------------------------
+
+Additional options for ``moc`` when using :variable:`CMAKE_AUTOMOC`.
+
+This variable is used to initialize the :prop_tgt:`AUTOMOC_MOC_OPTIONS` property
+on all the targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_AUTOMOC_PATH_PREFIX.rst b/Help/variable/CMAKE_AUTOMOC_PATH_PREFIX.rst
new file mode 100644
index 0000000..42f48b4
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOMOC_PATH_PREFIX.rst
@@ -0,0 +1,13 @@
+CMAKE_AUTOMOC_PATH_PREFIX
+-------------------------
+
+.. versionadded:: 3.16
+
+Whether to generate the ``-p`` path prefix option for ``moc`` on
+:prop_tgt:`AUTOMOC` enabled Qt targets.
+
+This variable is used to initialize the :prop_tgt:`AUTOMOC_PATH_PREFIX`
+property on all the targets. See that target property for additional
+information.
+
+The default value is ``OFF``.
diff --git a/Help/variable/CMAKE_AUTOMOC_RELAXED_MODE.rst b/Help/variable/CMAKE_AUTOMOC_RELAXED_MODE.rst
new file mode 100644
index 0000000..6c0c61b
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOMOC_RELAXED_MODE.rst
@@ -0,0 +1,15 @@
+CMAKE_AUTOMOC_RELAXED_MODE
+--------------------------
+
+.. deprecated:: 3.15
+
+Switch between strict and relaxed automoc mode.
+
+By default, :prop_tgt:`AUTOMOC` behaves exactly as described in the
+documentation of the :prop_tgt:`AUTOMOC` target property. When set to
+``TRUE``, it accepts more input and tries to find the correct input file for
+``moc`` even if it differs from the documented behaviour. In this mode it
+e.g. also checks whether a header file is intended to be processed by moc
+when a ``"foo.moc"`` file has been included.
+
+Relaxed mode has to be enabled for KDE4 compatibility.
diff --git a/Help/variable/CMAKE_AUTORCC.rst b/Help/variable/CMAKE_AUTORCC.rst
new file mode 100644
index 0000000..7426105
--- /dev/null
+++ b/Help/variable/CMAKE_AUTORCC.rst
@@ -0,0 +1,7 @@
+CMAKE_AUTORCC
+-------------
+
+Whether to handle ``rcc`` automatically for Qt targets.
+
+This variable is used to initialize the :prop_tgt:`AUTORCC` property on all
+the targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_AUTORCC_OPTIONS.rst b/Help/variable/CMAKE_AUTORCC_OPTIONS.rst
new file mode 100644
index 0000000..815d39d
--- /dev/null
+++ b/Help/variable/CMAKE_AUTORCC_OPTIONS.rst
@@ -0,0 +1,16 @@
+CMAKE_AUTORCC_OPTIONS
+---------------------
+
+Additional options for ``rcc`` when using :variable:`CMAKE_AUTORCC`.
+
+This variable is used to initialize the :prop_tgt:`AUTORCC_OPTIONS` property on
+all the targets. See that target property for additional information.
+
+EXAMPLE
+^^^^^^^
+
+.. code-block:: cmake
+
+ # ...
+ set(CMAKE_AUTORCC_OPTIONS "--compress;9")
+ # ...
diff --git a/Help/variable/CMAKE_AUTOUIC.rst b/Help/variable/CMAKE_AUTOUIC.rst
new file mode 100644
index 0000000..5abefaa
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOUIC.rst
@@ -0,0 +1,7 @@
+CMAKE_AUTOUIC
+-------------
+
+Whether to handle ``uic`` automatically for Qt targets.
+
+This variable is used to initialize the :prop_tgt:`AUTOUIC` property on all
+the targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_AUTOUIC_OPTIONS.rst b/Help/variable/CMAKE_AUTOUIC_OPTIONS.rst
new file mode 100644
index 0000000..28fa92f
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOUIC_OPTIONS.rst
@@ -0,0 +1,16 @@
+CMAKE_AUTOUIC_OPTIONS
+---------------------
+
+Additional options for ``uic`` when using :variable:`CMAKE_AUTOUIC`.
+
+This variable is used to initialize the :prop_tgt:`AUTOUIC_OPTIONS` property on
+all the targets. See that target property for additional information.
+
+EXAMPLE
+^^^^^^^
+
+.. code-block:: cmake
+
+ # ...
+ set_property(CMAKE_AUTOUIC_OPTIONS "--no-protection")
+ # ...
diff --git a/Help/variable/CMAKE_AUTOUIC_SEARCH_PATHS.rst b/Help/variable/CMAKE_AUTOUIC_SEARCH_PATHS.rst
new file mode 100644
index 0000000..0262368
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOUIC_SEARCH_PATHS.rst
@@ -0,0 +1,13 @@
+CMAKE_AUTOUIC_SEARCH_PATHS
+--------------------------
+
+.. versionadded:: 3.9
+
+Search path list used by :variable:`CMAKE_AUTOUIC` to find included
+``.ui`` files.
+
+This variable is used to initialize the :prop_tgt:`AUTOUIC_SEARCH_PATHS`
+property on all the targets. See that target property for additional
+information.
+
+By default it is empty.
diff --git a/Help/variable/CMAKE_BACKWARDS_COMPATIBILITY.rst b/Help/variable/CMAKE_BACKWARDS_COMPATIBILITY.rst
new file mode 100644
index 0000000..05c366a
--- /dev/null
+++ b/Help/variable/CMAKE_BACKWARDS_COMPATIBILITY.rst
@@ -0,0 +1,4 @@
+CMAKE_BACKWARDS_COMPATIBILITY
+-----------------------------
+
+Deprecated. See CMake Policy :policy:`CMP0001` documentation.
diff --git a/Help/variable/CMAKE_BINARY_DIR.rst b/Help/variable/CMAKE_BINARY_DIR.rst
new file mode 100644
index 0000000..3b323b7
--- /dev/null
+++ b/Help/variable/CMAKE_BINARY_DIR.rst
@@ -0,0 +1,13 @@
+CMAKE_BINARY_DIR
+----------------
+
+The path to the top level of the build tree.
+
+This is the full path to the top level of the current CMake build
+tree. For an in-source build, this would be the same as
+:variable:`CMAKE_SOURCE_DIR`.
+
+When run in -P script mode, CMake sets the variables
+:variable:`CMAKE_BINARY_DIR`, :variable:`CMAKE_SOURCE_DIR`,
+:variable:`CMAKE_CURRENT_BINARY_DIR` and
+:variable:`CMAKE_CURRENT_SOURCE_DIR` to the current working directory.
diff --git a/Help/variable/CMAKE_BUILD_RPATH.rst b/Help/variable/CMAKE_BUILD_RPATH.rst
new file mode 100644
index 0000000..7a8ace7
--- /dev/null
+++ b/Help/variable/CMAKE_BUILD_RPATH.rst
@@ -0,0 +1,12 @@
+CMAKE_BUILD_RPATH
+-----------------
+
+.. versionadded:: 3.8
+
+:ref:`Semicolon-separated list <CMake Language Lists>` specifying runtime path (``RPATH``)
+entries to add to binaries linked in the build tree (for platforms that
+support it). The entries will *not* be used for binaries in the install
+tree. See also the :variable:`CMAKE_INSTALL_RPATH` variable.
+
+This is used to initialize the :prop_tgt:`BUILD_RPATH` target property
+for all targets.
diff --git a/Help/variable/CMAKE_BUILD_RPATH_USE_ORIGIN.rst b/Help/variable/CMAKE_BUILD_RPATH_USE_ORIGIN.rst
new file mode 100644
index 0000000..ecd9278
--- /dev/null
+++ b/Help/variable/CMAKE_BUILD_RPATH_USE_ORIGIN.rst
@@ -0,0 +1,9 @@
+CMAKE_BUILD_RPATH_USE_ORIGIN
+----------------------------
+
+.. versionadded:: 3.14
+
+Whether to use relative paths for the build ``RPATH``.
+
+This is used to initialize the :prop_tgt:`BUILD_RPATH_USE_ORIGIN` target
+property for all targets, see that property for more details.
diff --git a/Help/variable/CMAKE_BUILD_TOOL.rst b/Help/variable/CMAKE_BUILD_TOOL.rst
new file mode 100644
index 0000000..6133491
--- /dev/null
+++ b/Help/variable/CMAKE_BUILD_TOOL.rst
@@ -0,0 +1,6 @@
+CMAKE_BUILD_TOOL
+----------------
+
+This variable exists only for backwards compatibility.
+It contains the same value as :variable:`CMAKE_MAKE_PROGRAM`.
+Use that variable instead.
diff --git a/Help/variable/CMAKE_BUILD_TYPE.rst b/Help/variable/CMAKE_BUILD_TYPE.rst
new file mode 100644
index 0000000..405f7d5
--- /dev/null
+++ b/Help/variable/CMAKE_BUILD_TYPE.rst
@@ -0,0 +1,25 @@
+CMAKE_BUILD_TYPE
+----------------
+
+Specifies the build type on single-configuration generators.
+
+This statically specifies what build type (configuration) will be
+built in this build tree. Possible values are empty, ``Debug``, ``Release``,
+``RelWithDebInfo``, ``MinSizeRel``, ... This variable is only meaningful to
+single-configuration generators (such as :ref:`Makefile Generators` and
+:generator:`Ninja`) i.e. those which choose a single configuration when CMake
+runs to generate a build tree as opposed to multi-configuration generators
+which offer selection of the build configuration within the generated build
+environment. There are many per-config properties and variables
+(usually following clean ``SOME_VAR_<CONFIG>`` order conventions), such as
+``CMAKE_C_FLAGS_<CONFIG>``, specified as uppercase:
+``CMAKE_C_FLAGS_[DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL|...]``. For example,
+in a build tree configured to build type ``Debug``, CMake will see to
+having :variable:`CMAKE_C_FLAGS_DEBUG <CMAKE_<LANG>_FLAGS_DEBUG>` settings get
+added to the :variable:`CMAKE_C_FLAGS <CMAKE_<LANG>_FLAGS>` settings. See
+also :variable:`CMAKE_CONFIGURATION_TYPES`.
+
+Note that configuration names are case-insensitive. The value of this
+variable will be the same as it is specified when invoking CMake.
+For instance, if ``-DCMAKE_BUILD_TYPE=ReLeAsE`` is specified, then the
+value of ``CMAKE_BUILD_TYPE`` will be ``ReLeAsE``.
diff --git a/Help/variable/CMAKE_BUILD_WITH_INSTALL_NAME_DIR.rst b/Help/variable/CMAKE_BUILD_WITH_INSTALL_NAME_DIR.rst
new file mode 100644
index 0000000..5ba775c
--- /dev/null
+++ b/Help/variable/CMAKE_BUILD_WITH_INSTALL_NAME_DIR.rst
@@ -0,0 +1,9 @@
+CMAKE_BUILD_WITH_INSTALL_NAME_DIR
+---------------------------------
+
+.. versionadded:: 3.9
+
+Whether to use :prop_tgt:`INSTALL_NAME_DIR` on targets in the build tree.
+
+This variable is used to initialize the :prop_tgt:`BUILD_WITH_INSTALL_NAME_DIR`
+property on all targets.
diff --git a/Help/variable/CMAKE_BUILD_WITH_INSTALL_RPATH.rst b/Help/variable/CMAKE_BUILD_WITH_INSTALL_RPATH.rst
new file mode 100644
index 0000000..5b59a6e
--- /dev/null
+++ b/Help/variable/CMAKE_BUILD_WITH_INSTALL_RPATH.rst
@@ -0,0 +1,11 @@
+CMAKE_BUILD_WITH_INSTALL_RPATH
+------------------------------
+
+Use the install path for the ``RPATH``.
+
+Normally CMake uses the build tree for the ``RPATH`` when building
+executables etc on systems that use ``RPATH``. When the software is
+installed the executables etc are relinked by CMake to have the
+install ``RPATH``. If this variable is set to true then the software is
+always built with the install path for the ``RPATH`` and does not need to
+be relinked when installed.
diff --git a/Help/variable/CMAKE_CACHEFILE_DIR.rst b/Help/variable/CMAKE_CACHEFILE_DIR.rst
new file mode 100644
index 0000000..8604d0e
--- /dev/null
+++ b/Help/variable/CMAKE_CACHEFILE_DIR.rst
@@ -0,0 +1,7 @@
+CMAKE_CACHEFILE_DIR
+-------------------
+
+The directory with the ``CMakeCache.txt`` file.
+
+This is the full path to the directory that has the ``CMakeCache.txt``
+file in it. This is the same as :variable:`CMAKE_BINARY_DIR`.
diff --git a/Help/variable/CMAKE_CACHE_MAJOR_VERSION.rst b/Help/variable/CMAKE_CACHE_MAJOR_VERSION.rst
new file mode 100644
index 0000000..1e53ed6
--- /dev/null
+++ b/Help/variable/CMAKE_CACHE_MAJOR_VERSION.rst
@@ -0,0 +1,8 @@
+CMAKE_CACHE_MAJOR_VERSION
+-------------------------
+
+Major version of CMake used to create the ``CMakeCache.txt`` file
+
+This stores the major version of CMake used to write a CMake cache
+file. It is only different when a different version of CMake is run
+on a previously created cache file.
diff --git a/Help/variable/CMAKE_CACHE_MINOR_VERSION.rst b/Help/variable/CMAKE_CACHE_MINOR_VERSION.rst
new file mode 100644
index 0000000..5d174a3
--- /dev/null
+++ b/Help/variable/CMAKE_CACHE_MINOR_VERSION.rst
@@ -0,0 +1,8 @@
+CMAKE_CACHE_MINOR_VERSION
+-------------------------
+
+Minor version of CMake used to create the ``CMakeCache.txt`` file
+
+This stores the minor version of CMake used to write a CMake cache
+file. It is only different when a different version of CMake is run
+on a previously created cache file.
diff --git a/Help/variable/CMAKE_CACHE_PATCH_VERSION.rst b/Help/variable/CMAKE_CACHE_PATCH_VERSION.rst
new file mode 100644
index 0000000..22d267c
--- /dev/null
+++ b/Help/variable/CMAKE_CACHE_PATCH_VERSION.rst
@@ -0,0 +1,8 @@
+CMAKE_CACHE_PATCH_VERSION
+-------------------------
+
+Patch version of CMake used to create the ``CMakeCache.txt`` file
+
+This stores the patch version of CMake used to write a CMake cache
+file. It is only different when a different version of CMake is run
+on a previously created cache file.
diff --git a/Help/variable/CMAKE_CFG_INTDIR.rst b/Help/variable/CMAKE_CFG_INTDIR.rst
new file mode 100644
index 0000000..842654e
--- /dev/null
+++ b/Help/variable/CMAKE_CFG_INTDIR.rst
@@ -0,0 +1,52 @@
+CMAKE_CFG_INTDIR
+----------------
+
+Build-time reference to per-configuration output subdirectory.
+
+For native build systems supporting multiple configurations in the
+build tree (such as :ref:`Visual Studio Generators` and :generator:`Xcode`),
+the value is a reference to a build-time variable specifying the name
+of the per-configuration output subdirectory. On :ref:`Makefile Generators`
+this evaluates to `.` because there is only one configuration in a build tree.
+Example values:
+
+::
+
+ $(ConfigurationName) = Visual Studio 9
+ $(Configuration) = Visual Studio 10
+ $(CONFIGURATION) = Xcode
+ . = Make-based tools
+ . = Ninja
+ ${CONFIGURATION} = Ninja Multi-Config
+
+Note that this variable only has limited support on
+:generator:`Ninja Multi-Config`. It is recommended that you use the
+``$<CONFIG>`` :manual:`generator expression <cmake-generator-expressions(7)>`
+instead.
+
+Since these values are evaluated by the native build system, this
+variable is suitable only for use in command lines that will be
+evaluated at build time. Example of intended usage:
+
+::
+
+ add_executable(mytool mytool.c)
+ add_custom_command(
+ OUTPUT out.txt
+ COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/mytool
+ ${CMAKE_CURRENT_SOURCE_DIR}/in.txt out.txt
+ DEPENDS mytool in.txt
+ )
+ add_custom_target(drive ALL DEPENDS out.txt)
+
+Note that ``CMAKE_CFG_INTDIR`` is no longer necessary for this purpose but
+has been left for compatibility with existing projects. Instead
+:command:`add_custom_command` recognizes executable target names in its
+``COMMAND`` option, so
+``${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/mytool`` can be replaced
+by just ``mytool``.
+
+This variable is read-only. Setting it is undefined behavior. In
+multi-configuration build systems the value of this variable is passed
+as the value of preprocessor symbol ``CMAKE_INTDIR`` to the compilation
+of all source files.
diff --git a/Help/variable/CMAKE_CLANG_VFS_OVERLAY.rst b/Help/variable/CMAKE_CLANG_VFS_OVERLAY.rst
new file mode 100644
index 0000000..56ac328
--- /dev/null
+++ b/Help/variable/CMAKE_CLANG_VFS_OVERLAY.rst
@@ -0,0 +1,9 @@
+CMAKE_CLANG_VFS_OVERLAY
+-----------------------
+
+.. versionadded:: 3.19
+
+When cross compiling for windows with clang-cl, this variable can be an
+absolute path pointing to a clang virtual file system yaml file, which
+will enable clang-cl to resolve windows header names on a case sensitive
+file system.
diff --git a/Help/variable/CMAKE_CL_64.rst b/Help/variable/CMAKE_CL_64.rst
new file mode 100644
index 0000000..4e80d1f
--- /dev/null
+++ b/Help/variable/CMAKE_CL_64.rst
@@ -0,0 +1,7 @@
+CMAKE_CL_64
+-----------
+
+Discouraged. Use :variable:`CMAKE_SIZEOF_VOID_P` instead.
+
+Set to a true value when using a Microsoft Visual Studio ``cl`` compiler that
+*targets* a 64-bit architecture.
diff --git a/Help/variable/CMAKE_CODEBLOCKS_COMPILER_ID.rst b/Help/variable/CMAKE_CODEBLOCKS_COMPILER_ID.rst
new file mode 100644
index 0000000..0b2b0a0
--- /dev/null
+++ b/Help/variable/CMAKE_CODEBLOCKS_COMPILER_ID.rst
@@ -0,0 +1,15 @@
+CMAKE_CODEBLOCKS_COMPILER_ID
+----------------------------
+
+.. versionadded:: 3.11
+
+Change the compiler id in the generated CodeBlocks project files.
+
+CodeBlocks uses its own compiler id string which differs from
+:variable:`CMAKE_<LANG>_COMPILER_ID`. If this variable is left empty,
+CMake tries to recognize the CodeBlocks compiler id automatically.
+Otherwise the specified string is used in the CodeBlocks project file.
+See the CodeBlocks documentation for valid compiler id strings.
+
+Other IDEs like QtCreator that also use the CodeBlocks generator may ignore
+this setting.
diff --git a/Help/variable/CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES.rst b/Help/variable/CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES.rst
new file mode 100644
index 0000000..dbb8606
--- /dev/null
+++ b/Help/variable/CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES.rst
@@ -0,0 +1,9 @@
+CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES
+---------------------------------------
+
+.. versionadded:: 3.10
+
+Change the way the CodeBlocks generator creates project files.
+
+If this variable evaluates to ``ON`` the generator excludes from
+the project file any files that are located outside the project root.
diff --git a/Help/variable/CMAKE_CODELITE_USE_TARGETS.rst b/Help/variable/CMAKE_CODELITE_USE_TARGETS.rst
new file mode 100644
index 0000000..21af5f7
--- /dev/null
+++ b/Help/variable/CMAKE_CODELITE_USE_TARGETS.rst
@@ -0,0 +1,10 @@
+CMAKE_CODELITE_USE_TARGETS
+--------------------------
+
+.. versionadded:: 3.7
+
+Change the way the CodeLite generator creates projectfiles.
+
+If this variable evaluates to ``ON`` at the end of the top-level
+``CMakeLists.txt`` file, the generator creates projectfiles based on targets
+rather than projects.
diff --git a/Help/variable/CMAKE_COLOR_MAKEFILE.rst b/Help/variable/CMAKE_COLOR_MAKEFILE.rst
new file mode 100644
index 0000000..bb86ecc
--- /dev/null
+++ b/Help/variable/CMAKE_COLOR_MAKEFILE.rst
@@ -0,0 +1,7 @@
+CMAKE_COLOR_MAKEFILE
+--------------------
+
+Enables color output when using the :ref:`Makefile Generators`.
+
+When enabled, the generated Makefiles will produce colored output.
+Default is ``ON``.
diff --git a/Help/variable/CMAKE_COMMAND.rst b/Help/variable/CMAKE_COMMAND.rst
new file mode 100644
index 0000000..f80b46c
--- /dev/null
+++ b/Help/variable/CMAKE_COMMAND.rst
@@ -0,0 +1,8 @@
+CMAKE_COMMAND
+-------------
+
+The full path to the :manual:`cmake(1)` executable.
+
+This is the full path to the CMake executable :manual:`cmake(1)` which is
+useful from custom commands that want to use the ``cmake -E`` option for
+portable system commands. (e.g. ``/usr/local/bin/cmake``)
diff --git a/Help/variable/CMAKE_COMPILER_2005.rst b/Help/variable/CMAKE_COMPILER_2005.rst
new file mode 100644
index 0000000..134559b
--- /dev/null
+++ b/Help/variable/CMAKE_COMPILER_2005.rst
@@ -0,0 +1,6 @@
+CMAKE_COMPILER_2005
+-------------------
+
+Using the Visual Studio 2005 compiler from Microsoft
+
+Set to true when using the Visual Studio 2005 compiler from Microsoft.
diff --git a/Help/variable/CMAKE_COMPILER_IS_GNUCC.rst b/Help/variable/CMAKE_COMPILER_IS_GNUCC.rst
new file mode 100644
index 0000000..91cf848
--- /dev/null
+++ b/Help/variable/CMAKE_COMPILER_IS_GNUCC.rst
@@ -0,0 +1,7 @@
+CMAKE_COMPILER_IS_GNUCC
+-----------------------
+
+.. versionadded:: 3.7
+
+True if the ``C`` compiler is GNU.
+Use :variable:`CMAKE_C_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` instead.
diff --git a/Help/variable/CMAKE_COMPILER_IS_GNUCXX.rst b/Help/variable/CMAKE_COMPILER_IS_GNUCXX.rst
new file mode 100644
index 0000000..e67718a
--- /dev/null
+++ b/Help/variable/CMAKE_COMPILER_IS_GNUCXX.rst
@@ -0,0 +1,7 @@
+CMAKE_COMPILER_IS_GNUCXX
+------------------------
+
+.. versionadded:: 3.7
+
+True if the C++ (``CXX``) compiler is GNU.
+Use :variable:`CMAKE_CXX_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` instead.
diff --git a/Help/variable/CMAKE_COMPILER_IS_GNUG77.rst b/Help/variable/CMAKE_COMPILER_IS_GNUG77.rst
new file mode 100644
index 0000000..f69c01a
--- /dev/null
+++ b/Help/variable/CMAKE_COMPILER_IS_GNUG77.rst
@@ -0,0 +1,7 @@
+CMAKE_COMPILER_IS_GNUG77
+------------------------
+
+.. versionadded:: 3.7
+
+True if the ``Fortran`` compiler is GNU.
+Use :variable:`CMAKE_Fortran_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` instead.
diff --git a/Help/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY.rst b/Help/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY.rst
new file mode 100644
index 0000000..11f52c7
--- /dev/null
+++ b/Help/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY.rst
@@ -0,0 +1,10 @@
+CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY
+----------------------------------
+
+.. versionadded:: 3.1
+
+Output directory for MS debug symbol ``.pdb`` files
+generated by the compiler while building source files.
+
+This variable is used to initialize the
+:prop_tgt:`COMPILE_PDB_OUTPUT_DIRECTORY` property on all the targets.
diff --git a/Help/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst b/Help/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
new file mode 100644
index 0000000..99d0bdc
--- /dev/null
+++ b/Help/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
@@ -0,0 +1,13 @@
+CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG>
+-------------------------------------------
+
+.. versionadded:: 3.1
+
+Per-configuration output directory for MS debug symbol ``.pdb`` files
+generated by the compiler while building source files.
+
+This is a per-configuration version of
+:variable:`CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY`.
+This variable is used to initialize the
+:prop_tgt:`COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG>`
+property on all the targets.
diff --git a/Help/variable/CMAKE_CONFIGURATION_TYPES.rst b/Help/variable/CMAKE_CONFIGURATION_TYPES.rst
new file mode 100644
index 0000000..34e99eb
--- /dev/null
+++ b/Help/variable/CMAKE_CONFIGURATION_TYPES.rst
@@ -0,0 +1,10 @@
+CMAKE_CONFIGURATION_TYPES
+-------------------------
+
+Specifies the available build types on multi-config generators.
+
+This specifies what build types (configurations) will be available
+such as ``Debug``, ``Release``, ``RelWithDebInfo`` etc. This has reasonable
+defaults on most platforms, but can be extended to provide other build
+types. See also :variable:`CMAKE_BUILD_TYPE` for details of managing
+configuration data, and :variable:`CMAKE_CFG_INTDIR`.
diff --git a/Help/variable/CMAKE_CONFIG_POSTFIX.rst b/Help/variable/CMAKE_CONFIG_POSTFIX.rst
new file mode 100644
index 0000000..e686a43
--- /dev/null
+++ b/Help/variable/CMAKE_CONFIG_POSTFIX.rst
@@ -0,0 +1,7 @@
+CMAKE_<CONFIG>_POSTFIX
+----------------------
+
+Default filename postfix for libraries under configuration ``<CONFIG>``.
+
+When a non-executable target is created its :prop_tgt:`<CONFIG>_POSTFIX`
+target property is initialized with the value of this variable if it is set.
diff --git a/Help/variable/CMAKE_CPACK_COMMAND.rst b/Help/variable/CMAKE_CPACK_COMMAND.rst
new file mode 100644
index 0000000..3a81d68
--- /dev/null
+++ b/Help/variable/CMAKE_CPACK_COMMAND.rst
@@ -0,0 +1,10 @@
+CMAKE_CPACK_COMMAND
+-------------------
+
+.. versionadded:: 3.13
+
+Full path to :manual:`cpack(1)` command installed with CMake.
+
+This is the full path to the CPack executable :manual:`cpack(1)` which is
+useful from custom commands that want to use the :manual:`cmake(1)` ``-E``
+option for portable system commands.
diff --git a/Help/variable/CMAKE_CROSSCOMPILING.rst b/Help/variable/CMAKE_CROSSCOMPILING.rst
new file mode 100644
index 0000000..7e6ec33
--- /dev/null
+++ b/Help/variable/CMAKE_CROSSCOMPILING.rst
@@ -0,0 +1,27 @@
+CMAKE_CROSSCOMPILING
+--------------------
+
+Intended to indicate whether CMake is cross compiling, but note limitations
+discussed below.
+
+This variable will be set to true by CMake if the :variable:`CMAKE_SYSTEM_NAME`
+variable has been set manually (i.e. in a toolchain file or as a cache entry
+from the :manual:`cmake <cmake(1)>` command line). In most cases, manually
+setting :variable:`CMAKE_SYSTEM_NAME` will only be done when cross compiling,
+since it will otherwise be given the same value as
+:variable:`CMAKE_HOST_SYSTEM_NAME` if not manually set, which is correct for
+the non-cross-compiling case. In the event that :variable:`CMAKE_SYSTEM_NAME`
+is manually set to the same value as :variable:`CMAKE_HOST_SYSTEM_NAME`, then
+``CMAKE_CROSSCOMPILING`` will still be set to true.
+
+Another case to be aware of is that builds targeting Apple platforms other than
+macOS are handled differently to other cross compiling scenarios. Rather than
+relying on :variable:`CMAKE_SYSTEM_NAME` to select the target platform, Apple
+device builds use :variable:`CMAKE_OSX_SYSROOT` to select the appropriate SDK,
+which indirectly determines the target platform. Furthermore, when using the
+:generator:`Xcode` generator, developers can switch between device and
+simulator builds at build time rather than having a single
+choice at configure time, so the concept
+of whether the build is cross compiling or not is more complex. Therefore, the
+use of ``CMAKE_CROSSCOMPILING`` is not recommended for projects targeting Apple
+devices.
diff --git a/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst b/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst
new file mode 100644
index 0000000..815da00
--- /dev/null
+++ b/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst
@@ -0,0 +1,18 @@
+CMAKE_CROSSCOMPILING_EMULATOR
+-----------------------------
+
+.. versionadded:: 3.3
+
+This variable is only used when :variable:`CMAKE_CROSSCOMPILING` is on. It
+should point to a command on the host system that can run executable built
+for the target system.
+
+If this variable contains a :ref:`semicolon-separated list <CMake Language
+Lists>`, then the first value is the command and remaining values are its
+arguments.
+
+The command will be used to run :command:`try_run` generated executables,
+which avoids manual population of the ``TryRunResults.cmake`` file.
+
+It is also used as the default value for the
+:prop_tgt:`CROSSCOMPILING_EMULATOR` target property of executables.
diff --git a/Help/variable/CMAKE_CROSS_CONFIGS.rst b/Help/variable/CMAKE_CROSS_CONFIGS.rst
new file mode 100644
index 0000000..be921d6
--- /dev/null
+++ b/Help/variable/CMAKE_CROSS_CONFIGS.rst
@@ -0,0 +1,17 @@
+CMAKE_CROSS_CONFIGS
+-------------------
+
+.. versionadded:: 3.17
+
+Specifies a :ref:`semicolon-separated list <CMake Language Lists>` of
+configurations available from all ``build-<Config>.ninja`` files in the
+:generator:`Ninja Multi-Config` generator. This variable activates
+cross-config mode. Targets from each config specified in this variable can be
+built from any ``build-<Config>.ninja`` file. Custom commands will use the
+configuration native to ``build-<Config>.ninja``. If it is set to ``all``, all
+configurations from :variable:`CMAKE_CONFIGURATION_TYPES` are cross-configs. If
+it is not specified, or empty, each ``build-<Config>.ninja`` file will only
+contain build rules for its own configuration.
+
+The value of this variable must be a subset of
+:variable:`CMAKE_CONFIGURATION_TYPES`.
diff --git a/Help/variable/CMAKE_CTEST_ARGUMENTS.rst b/Help/variable/CMAKE_CTEST_ARGUMENTS.rst
new file mode 100644
index 0000000..4dfc8fe
--- /dev/null
+++ b/Help/variable/CMAKE_CTEST_ARGUMENTS.rst
@@ -0,0 +1,8 @@
+CMAKE_CTEST_ARGUMENTS
+---------------------
+
+.. versionadded:: 3.17
+
+Set this to a :ref:`semicolon-separated list <CMake Language Lists>` of
+command-line arguments to pass to :manual:`ctest(1)` when running tests
+through the ``test`` (or ``RUN_TESTS``) target of the generated build system.
diff --git a/Help/variable/CMAKE_CTEST_COMMAND.rst b/Help/variable/CMAKE_CTEST_COMMAND.rst
new file mode 100644
index 0000000..b2942e2
--- /dev/null
+++ b/Help/variable/CMAKE_CTEST_COMMAND.rst
@@ -0,0 +1,8 @@
+CMAKE_CTEST_COMMAND
+-------------------
+
+Full path to :manual:`ctest(1)` command installed with CMake.
+
+This is the full path to the CTest executable :manual:`ctest(1)` which is
+useful from custom commands that want to use the :manual:`cmake(1)` ``-E``
+option for portable system commands.
diff --git a/Help/variable/CMAKE_CUDA_ARCHITECTURES.rst b/Help/variable/CMAKE_CUDA_ARCHITECTURES.rst
new file mode 100644
index 0000000..d885516
--- /dev/null
+++ b/Help/variable/CMAKE_CUDA_ARCHITECTURES.rst
@@ -0,0 +1,35 @@
+CMAKE_CUDA_ARCHITECTURES
+------------------------
+
+.. versionadded:: 3.18
+
+Default value for :prop_tgt:`CUDA_ARCHITECTURES` property of targets.
+
+Initialized by the :envvar:`CUDAARCHS` environment variable if set.
+Otherwise as follows depending on :variable:`CMAKE_CUDA_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>`:
+
+- For ``Clang``: the oldest architecture that works.
+
+- For ``NVIDIA``: the default architecture chosen by the compiler.
+ See policy :policy:`CMP0104`.
+
+Users are encouraged to override this, as the default varies across compilers
+and compiler versions.
+
+This variable is used to initialize the :prop_tgt:`CUDA_ARCHITECTURES` property
+on all targets. See the target property for additional information.
+
+Examples
+^^^^^^^^
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION)
+
+ if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
+ set(CMAKE_CUDA_ARCHITECTURES 75)
+ endif()
+
+ project(example LANGUAGES CUDA)
+
+``CMAKE_CUDA_ARCHITECTURES`` will default to ``75`` unless overridden by the user.
diff --git a/Help/variable/CMAKE_CUDA_COMPILE_FEATURES.rst b/Help/variable/CMAKE_CUDA_COMPILE_FEATURES.rst
new file mode 100644
index 0000000..c1c270c
--- /dev/null
+++ b/Help/variable/CMAKE_CUDA_COMPILE_FEATURES.rst
@@ -0,0 +1,13 @@
+CMAKE_CUDA_COMPILE_FEATURES
+---------------------------
+
+.. versionadded:: 3.17
+
+List of features known to the CUDA compiler
+
+These features are known to be available for use with the CUDA compiler. This
+list is a subset of the features listed in the
+:prop_gbl:`CMAKE_CUDA_KNOWN_FEATURES` global property.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_CUDA_EXTENSIONS.rst b/Help/variable/CMAKE_CUDA_EXTENSIONS.rst
new file mode 100644
index 0000000..b86c0ea
--- /dev/null
+++ b/Help/variable/CMAKE_CUDA_EXTENSIONS.rst
@@ -0,0 +1,13 @@
+CMAKE_CUDA_EXTENSIONS
+---------------------
+
+.. versionadded:: 3.8
+
+Default value for :prop_tgt:`CUDA_EXTENSIONS` property of targets.
+
+This variable is used to initialize the :prop_tgt:`CUDA_EXTENSIONS`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst b/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst
new file mode 100644
index 0000000..d5fcb7d
--- /dev/null
+++ b/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst
@@ -0,0 +1,25 @@
+CMAKE_CUDA_HOST_COMPILER
+------------------------
+
+.. versionadded:: 3.10
+
+When :variable:`CMAKE_CUDA_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` is
+``NVIDIA``, ``CMAKE_CUDA_HOST_COMPILER`` selects the compiler executable to use
+when compiling host code for ``CUDA`` language files.
+This maps to the ``nvcc -ccbin`` option.
+
+The ``CMAKE_CUDA_HOST_COMPILER`` variable may be set explicitly before CUDA is
+first enabled by a :command:`project` or :command:`enable_language` command.
+This can be done via ``-DCMAKE_CUDA_HOST_COMPILER=...`` on the command line
+or in a :ref:`toolchain file <Cross Compiling Toolchain>`. Or, one may set
+the :envvar:`CUDAHOSTCXX` environment variable to provide a default value.
+
+Once the CUDA language is enabled, the ``CMAKE_CUDA_HOST_COMPILER`` variable
+is read-only and changes to it are undefined behavior.
+
+.. note::
+
+ Since ``CMAKE_CUDA_HOST_COMPILER`` is meaningful only when the
+ :variable:`CMAKE_CUDA_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` is ``NVIDIA``,
+ it does not make sense to set ``CMAKE_CUDA_HOST_COMPILER`` without also
+ setting ``CMAKE_CUDA_COMPILER`` to NVCC.
diff --git a/Help/variable/CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS.rst b/Help/variable/CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS.rst
new file mode 100644
index 0000000..474baee
--- /dev/null
+++ b/Help/variable/CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS.rst
@@ -0,0 +1,8 @@
+CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS
+---------------------------------
+
+.. versionadded:: 3.16
+
+Default value for :prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` target
+property. This variable is used to initialize the property on each target as
+it is created.
diff --git a/Help/variable/CMAKE_CUDA_RUNTIME_LIBRARY.rst b/Help/variable/CMAKE_CUDA_RUNTIME_LIBRARY.rst
new file mode 100644
index 0000000..69b9d93
--- /dev/null
+++ b/Help/variable/CMAKE_CUDA_RUNTIME_LIBRARY.rst
@@ -0,0 +1,27 @@
+CMAKE_CUDA_RUNTIME_LIBRARY
+--------------------------
+
+.. versionadded:: 3.17
+
+Select the CUDA runtime library for use when compiling and linking CUDA.
+This variable is used to initialize the :prop_tgt:`CUDA_RUNTIME_LIBRARY`
+property on all targets as they are created.
+
+The allowed case insensitive values are:
+
+.. include:: ../prop_tgt/CUDA_RUNTIME_LIBRARY-VALUES.txt
+
+Contents of ``CMAKE_CUDA_RUNTIME_LIBRARY`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+If this variable is not set then the :prop_tgt:`CUDA_RUNTIME_LIBRARY` target
+property will not be set automatically. If that property is not set then
+CMake uses an appropriate default value based on the compiler to select the
+CUDA runtime library.
+
+.. note::
+
+ This property has effect only when the ``CUDA`` language is enabled. To
+ control the CUDA runtime linking when only using the CUDA SDK with the
+ ``C`` or ``C++`` language we recommend using the :module:`FindCUDAToolkit`
+ module.
diff --git a/Help/variable/CMAKE_CUDA_SEPARABLE_COMPILATION.rst b/Help/variable/CMAKE_CUDA_SEPARABLE_COMPILATION.rst
new file mode 100644
index 0000000..3dbaef9
--- /dev/null
+++ b/Help/variable/CMAKE_CUDA_SEPARABLE_COMPILATION.rst
@@ -0,0 +1,8 @@
+CMAKE_CUDA_SEPARABLE_COMPILATION
+--------------------------------
+
+.. versionadded:: 3.11
+
+Default value for :prop_tgt:`CUDA_SEPARABLE_COMPILATION` target property.
+This variable is used to initialize the property on each target as it is
+created.
diff --git a/Help/variable/CMAKE_CUDA_STANDARD.rst b/Help/variable/CMAKE_CUDA_STANDARD.rst
new file mode 100644
index 0000000..798ab1e
--- /dev/null
+++ b/Help/variable/CMAKE_CUDA_STANDARD.rst
@@ -0,0 +1,13 @@
+CMAKE_CUDA_STANDARD
+-------------------
+
+.. versionadded:: 3.8
+
+Default value for :prop_tgt:`CUDA_STANDARD` property of targets.
+
+This variable is used to initialize the :prop_tgt:`CUDA_STANDARD`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_CUDA_STANDARD_REQUIRED.rst b/Help/variable/CMAKE_CUDA_STANDARD_REQUIRED.rst
new file mode 100644
index 0000000..ae2f52f
--- /dev/null
+++ b/Help/variable/CMAKE_CUDA_STANDARD_REQUIRED.rst
@@ -0,0 +1,13 @@
+CMAKE_CUDA_STANDARD_REQUIRED
+----------------------------
+
+.. versionadded:: 3.8
+
+Default value for :prop_tgt:`CUDA_STANDARD_REQUIRED` property of targets.
+
+This variable is used to initialize the :prop_tgt:`CUDA_STANDARD_REQUIRED`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES.rst b/Help/variable/CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES.rst
new file mode 100644
index 0000000..e586dab
--- /dev/null
+++ b/Help/variable/CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES.rst
@@ -0,0 +1,9 @@
+CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES
+--------------------------------------
+
+.. versionadded:: 3.8
+
+When the ``CUDA`` language has been enabled, this provides a
+:ref:`semicolon-separated list <CMake Language Lists>` of include directories provided
+by the CUDA Toolkit. The value may be useful for C++ source files
+to include CUDA headers.
diff --git a/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst b/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst
new file mode 100644
index 0000000..40496b5
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst
@@ -0,0 +1,15 @@
+CMAKE_CURRENT_BINARY_DIR
+------------------------
+
+The path to the binary directory currently being processed.
+
+This the full path to the build directory that is currently being
+processed by cmake. Each directory added by :command:`add_subdirectory` will
+create a binary directory in the build tree, and as it is being
+processed this variable will be set. For in-source builds this is the
+current source directory being processed.
+
+When run in -P script mode, CMake sets the variables
+:variable:`CMAKE_BINARY_DIR`, :variable:`CMAKE_SOURCE_DIR`,
+:variable:`CMAKE_CURRENT_BINARY_DIR` and
+:variable:`CMAKE_CURRENT_SOURCE_DIR` to the current working directory.
diff --git a/Help/variable/CMAKE_CURRENT_FUNCTION.rst b/Help/variable/CMAKE_CURRENT_FUNCTION.rst
new file mode 100644
index 0000000..5d1a4e9
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_FUNCTION.rst
@@ -0,0 +1,12 @@
+CMAKE_CURRENT_FUNCTION
+----------------------
+
+.. versionadded:: 3.17
+
+When executing code inside a :command:`function`, this variable
+contains the name of the current function. It can be useful for
+diagnostic or debug messages.
+
+See also :variable:`CMAKE_CURRENT_FUNCTION_LIST_DIR`,
+:variable:`CMAKE_CURRENT_FUNCTION_LIST_FILE` and
+:variable:`CMAKE_CURRENT_FUNCTION_LIST_LINE`.
diff --git a/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_DIR.rst b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_DIR.rst
new file mode 100644
index 0000000..f8f553d
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_DIR.rst
@@ -0,0 +1,43 @@
+CMAKE_CURRENT_FUNCTION_LIST_DIR
+-------------------------------
+
+.. versionadded:: 3.17
+
+When executing code inside a :command:`function`, this variable
+contains the full directory of the listfile that defined the current function.
+
+It is quite common practice in CMake for modules to use some additional files,
+such as templates to be copied in after substituting CMake variables.
+In such cases, a function needs to know where to locate those files in a way
+that doesn't depend on where the function is called. Without
+``CMAKE_CURRENT_FUNCTION_LIST_DIR``, the code to do that would typically use
+the following pattern:
+
+.. code-block:: cmake
+
+ set(_THIS_MODULE_BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
+
+ function(foo)
+ configure_file(
+ "${_THIS_MODULE_BASE_DIR}/some.template.in"
+ some.output
+ )
+ endfunction()
+
+Using ``CMAKE_CURRENT_FUNCTION_LIST_DIR`` inside the function instead
+eliminates the need for the extra variable which would otherwise be visible
+outside the function's scope.
+The above example can be written in the more concise and more robust form:
+
+.. code-block:: cmake
+
+ function(foo)
+ configure_file(
+ "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/some.template.in"
+ some.output
+ )
+ endfunction()
+
+See also :variable:`CMAKE_CURRENT_FUNCTION`,
+:variable:`CMAKE_CURRENT_FUNCTION_LIST_FILE` and
+:variable:`CMAKE_CURRENT_FUNCTION_LIST_LINE`.
diff --git a/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_FILE.rst b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_FILE.rst
new file mode 100644
index 0000000..437dfec
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_FILE.rst
@@ -0,0 +1,11 @@
+CMAKE_CURRENT_FUNCTION_LIST_FILE
+--------------------------------
+
+.. versionadded:: 3.17
+
+When executing code inside a :command:`function`, this variable
+contains the full path to the listfile that defined the current function.
+
+See also :variable:`CMAKE_CURRENT_FUNCTION`,
+:variable:`CMAKE_CURRENT_FUNCTION_LIST_DIR` and
+:variable:`CMAKE_CURRENT_FUNCTION_LIST_LINE`.
diff --git a/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_LINE.rst b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_LINE.rst
new file mode 100644
index 0000000..2fc7012
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_LINE.rst
@@ -0,0 +1,12 @@
+CMAKE_CURRENT_FUNCTION_LIST_LINE
+--------------------------------
+
+.. versionadded:: 3.17
+
+When executing code inside a :command:`function`, this variable
+contains the line number in the listfile where the current function
+was defined.
+
+See also :variable:`CMAKE_CURRENT_FUNCTION`,
+:variable:`CMAKE_CURRENT_FUNCTION_LIST_DIR` and
+:variable:`CMAKE_CURRENT_FUNCTION_LIST_FILE`.
diff --git a/Help/variable/CMAKE_CURRENT_LIST_DIR.rst b/Help/variable/CMAKE_CURRENT_LIST_DIR.rst
new file mode 100644
index 0000000..ebc3ab9
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_LIST_DIR.rst
@@ -0,0 +1,17 @@
+CMAKE_CURRENT_LIST_DIR
+----------------------
+
+Full directory of the listfile currently being processed.
+
+As CMake processes the listfiles in your project this variable will
+always be set to the directory where the listfile which is currently
+being processed (:variable:`CMAKE_CURRENT_LIST_FILE`) is located. The value
+has dynamic scope. When CMake starts processing commands in a source file
+it sets this variable to the directory where this file is located.
+When CMake finishes processing commands from the file it restores the
+previous value. Therefore the value of the variable inside a macro or
+function is the directory of the file invoking the bottom-most entry
+on the call stack, not the directory of the file containing the macro
+or function definition.
+
+See also :variable:`CMAKE_CURRENT_LIST_FILE`.
diff --git a/Help/variable/CMAKE_CURRENT_LIST_FILE.rst b/Help/variable/CMAKE_CURRENT_LIST_FILE.rst
new file mode 100644
index 0000000..84b0eee
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_LIST_FILE.rst
@@ -0,0 +1,15 @@
+CMAKE_CURRENT_LIST_FILE
+-----------------------
+
+Full path to the listfile currently being processed.
+
+As CMake processes the listfiles in your project this variable will
+always be set to the one currently being processed. The value has
+dynamic scope. When CMake starts processing commands in a source file
+it sets this variable to the location of the file. When CMake
+finishes processing commands from the file it restores the previous
+value. Therefore the value of the variable inside a macro or function
+is the file invoking the bottom-most entry on the call stack, not the
+file containing the macro or function definition.
+
+See also :variable:`CMAKE_PARENT_LIST_FILE`.
diff --git a/Help/variable/CMAKE_CURRENT_LIST_LINE.rst b/Help/variable/CMAKE_CURRENT_LIST_LINE.rst
new file mode 100644
index 0000000..7f839c2
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_LIST_LINE.rst
@@ -0,0 +1,11 @@
+CMAKE_CURRENT_LIST_LINE
+-----------------------
+
+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_CURRENT_SOURCE_DIR.rst b/Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst
new file mode 100644
index 0000000..c1b755a
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst
@@ -0,0 +1,12 @@
+CMAKE_CURRENT_SOURCE_DIR
+------------------------
+
+The path to the source directory currently being processed.
+
+This the full path to the source directory that is currently being
+processed by cmake.
+
+When run in -P script mode, CMake sets the variables
+:variable:`CMAKE_BINARY_DIR`, :variable:`CMAKE_SOURCE_DIR`,
+:variable:`CMAKE_CURRENT_BINARY_DIR` and
+:variable:`CMAKE_CURRENT_SOURCE_DIR` to the current working directory.
diff --git a/Help/variable/CMAKE_CXX_COMPILE_FEATURES.rst b/Help/variable/CMAKE_CXX_COMPILE_FEATURES.rst
new file mode 100644
index 0000000..8fcfbae
--- /dev/null
+++ b/Help/variable/CMAKE_CXX_COMPILE_FEATURES.rst
@@ -0,0 +1,13 @@
+CMAKE_CXX_COMPILE_FEATURES
+--------------------------
+
+.. versionadded:: 3.1
+
+List of features known to the C++ compiler
+
+These features are known to be available for use with the C++ compiler. This
+list is a subset of the features listed in the
+:prop_gbl:`CMAKE_CXX_KNOWN_FEATURES` global property.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_CXX_EXTENSIONS.rst b/Help/variable/CMAKE_CXX_EXTENSIONS.rst
new file mode 100644
index 0000000..ea8c4be
--- /dev/null
+++ b/Help/variable/CMAKE_CXX_EXTENSIONS.rst
@@ -0,0 +1,13 @@
+CMAKE_CXX_EXTENSIONS
+--------------------
+
+.. versionadded:: 3.1
+
+Default value for :prop_tgt:`CXX_EXTENSIONS` property of targets.
+
+This variable is used to initialize the :prop_tgt:`CXX_EXTENSIONS`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_CXX_STANDARD.rst b/Help/variable/CMAKE_CXX_STANDARD.rst
new file mode 100644
index 0000000..8ef8c80
--- /dev/null
+++ b/Help/variable/CMAKE_CXX_STANDARD.rst
@@ -0,0 +1,13 @@
+CMAKE_CXX_STANDARD
+------------------
+
+.. versionadded:: 3.1
+
+Default value for :prop_tgt:`CXX_STANDARD` property of targets.
+
+This variable is used to initialize the :prop_tgt:`CXX_STANDARD`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_CXX_STANDARD_REQUIRED.rst b/Help/variable/CMAKE_CXX_STANDARD_REQUIRED.rst
new file mode 100644
index 0000000..f7b2ae9
--- /dev/null
+++ b/Help/variable/CMAKE_CXX_STANDARD_REQUIRED.rst
@@ -0,0 +1,13 @@
+CMAKE_CXX_STANDARD_REQUIRED
+---------------------------
+
+.. versionadded:: 3.1
+
+Default value for :prop_tgt:`CXX_STANDARD_REQUIRED` property of targets.
+
+This variable is used to initialize the :prop_tgt:`CXX_STANDARD_REQUIRED`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_C_COMPILE_FEATURES.rst b/Help/variable/CMAKE_C_COMPILE_FEATURES.rst
new file mode 100644
index 0000000..2b306a3
--- /dev/null
+++ b/Help/variable/CMAKE_C_COMPILE_FEATURES.rst
@@ -0,0 +1,13 @@
+CMAKE_C_COMPILE_FEATURES
+------------------------
+
+.. versionadded:: 3.1
+
+List of features known to the C compiler
+
+These features are known to be available for use with the C compiler. This
+list is a subset of the features listed in the
+:prop_gbl:`CMAKE_C_KNOWN_FEATURES` global property.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_C_EXTENSIONS.rst b/Help/variable/CMAKE_C_EXTENSIONS.rst
new file mode 100644
index 0000000..fce8fc7
--- /dev/null
+++ b/Help/variable/CMAKE_C_EXTENSIONS.rst
@@ -0,0 +1,13 @@
+CMAKE_C_EXTENSIONS
+------------------
+
+.. versionadded:: 3.1
+
+Default value for :prop_tgt:`C_EXTENSIONS` property of targets.
+
+This variable is used to initialize the :prop_tgt:`C_EXTENSIONS`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_C_STANDARD.rst b/Help/variable/CMAKE_C_STANDARD.rst
new file mode 100644
index 0000000..64ef8ce
--- /dev/null
+++ b/Help/variable/CMAKE_C_STANDARD.rst
@@ -0,0 +1,13 @@
+CMAKE_C_STANDARD
+----------------
+
+.. versionadded:: 3.1
+
+Default value for :prop_tgt:`C_STANDARD` property of targets.
+
+This variable is used to initialize the :prop_tgt:`C_STANDARD`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_C_STANDARD_REQUIRED.rst b/Help/variable/CMAKE_C_STANDARD_REQUIRED.rst
new file mode 100644
index 0000000..e70b6bd
--- /dev/null
+++ b/Help/variable/CMAKE_C_STANDARD_REQUIRED.rst
@@ -0,0 +1,13 @@
+CMAKE_C_STANDARD_REQUIRED
+-------------------------
+
+.. versionadded:: 3.1
+
+Default value for :prop_tgt:`C_STANDARD_REQUIRED` property of targets.
+
+This variable is used to initialize the :prop_tgt:`C_STANDARD_REQUIRED`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_DEBUG_POSTFIX.rst b/Help/variable/CMAKE_DEBUG_POSTFIX.rst
new file mode 100644
index 0000000..08577a5
--- /dev/null
+++ b/Help/variable/CMAKE_DEBUG_POSTFIX.rst
@@ -0,0 +1,7 @@
+CMAKE_DEBUG_POSTFIX
+-------------------
+
+See variable :variable:`CMAKE_<CONFIG>_POSTFIX`.
+
+This variable is a special case of the more-general
+:variable:`CMAKE_<CONFIG>_POSTFIX` variable for the `DEBUG` configuration.
diff --git a/Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst b/Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst
new file mode 100644
index 0000000..a1fa1ff
--- /dev/null
+++ b/Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst
@@ -0,0 +1,23 @@
+CMAKE_DEBUG_TARGET_PROPERTIES
+-----------------------------
+
+Enables tracing output for target properties.
+
+This variable can be populated with a list of properties to generate
+debug output for when evaluating target properties. Currently it can
+only be used when evaluating:
+
+* :prop_tgt:`AUTOUIC_OPTIONS`
+* :prop_tgt:`COMPILE_DEFINITIONS`
+* :prop_tgt:`COMPILE_FEATURES`
+* :prop_tgt:`COMPILE_OPTIONS`
+* :prop_tgt:`INCLUDE_DIRECTORIES`
+* :prop_tgt:`LINK_DIRECTORIES`
+* :prop_tgt:`LINK_OPTIONS`
+* :prop_tgt:`POSITION_INDEPENDENT_CODE`
+* :prop_tgt:`SOURCES`
+
+target properties and any other property listed in
+:prop_tgt:`COMPATIBLE_INTERFACE_STRING` and other
+``COMPATIBLE_INTERFACE_`` properties. It outputs an origin for each entry
+in the target property. Default is unset.
diff --git a/Help/variable/CMAKE_DEFAULT_BUILD_TYPE.rst b/Help/variable/CMAKE_DEFAULT_BUILD_TYPE.rst
new file mode 100644
index 0000000..cadbf3a
--- /dev/null
+++ b/Help/variable/CMAKE_DEFAULT_BUILD_TYPE.rst
@@ -0,0 +1,14 @@
+CMAKE_DEFAULT_BUILD_TYPE
+------------------------
+
+.. versionadded:: 3.17
+
+Specifies the configuration to use by default in a ``build.ninja`` file in the
+:generator:`Ninja Multi-Config` generator. If this variable is specified,
+``build.ninja`` uses build rules from ``build-<Config>.ninja`` by default. All
+custom commands are executed with this configuration. If the variable is not
+specified, the first item from :variable:`CMAKE_CONFIGURATION_TYPES` is used
+instead.
+
+The value of this variable must be one of the items from
+:variable:`CMAKE_CONFIGURATION_TYPES`.
diff --git a/Help/variable/CMAKE_DEFAULT_CONFIGS.rst b/Help/variable/CMAKE_DEFAULT_CONFIGS.rst
new file mode 100644
index 0000000..65a5f0d
--- /dev/null
+++ b/Help/variable/CMAKE_DEFAULT_CONFIGS.rst
@@ -0,0 +1,21 @@
+CMAKE_DEFAULT_CONFIGS
+---------------------
+
+.. versionadded:: 3.17
+
+Specifies a :ref:`semicolon-separated list <CMake Language Lists>` of configurations
+to build for a target in ``build.ninja`` if no ``:<Config>`` suffix is specified in
+the :generator:`Ninja Multi-Config` generator. If it is set to ``all``, all
+configurations from :variable:`CMAKE_CROSS_CONFIGS` are used. If it is not
+specified, it defaults to :variable:`CMAKE_DEFAULT_BUILD_TYPE`.
+
+For example, if you set :variable:`CMAKE_DEFAULT_BUILD_TYPE` to ``Release``,
+but set :variable:`CMAKE_DEFAULT_CONFIGS` to ``Debug`` or ``all``, all
+``<target>`` aliases in ``build.ninja`` will resolve to ``<target>:Debug`` or
+``<target>:all``, but custom commands will still use the ``Release``
+configuration.
+
+The value of this variable must be a subset of :variable:`CMAKE_CROSS_CONFIGS`
+or be the same as :variable:`CMAKE_DEFAULT_BUILD_TYPE`. It must not be
+specified if :variable:`CMAKE_DEFAULT_BUILD_TYPE` or
+:variable:`CMAKE_CROSS_CONFIGS` is not used.
diff --git a/Help/variable/CMAKE_DEPENDS_IN_PROJECT_ONLY.rst b/Help/variable/CMAKE_DEPENDS_IN_PROJECT_ONLY.rst
new file mode 100644
index 0000000..bfe9402
--- /dev/null
+++ b/Help/variable/CMAKE_DEPENDS_IN_PROJECT_ONLY.rst
@@ -0,0 +1,12 @@
+CMAKE_DEPENDS_IN_PROJECT_ONLY
+-----------------------------
+
+.. versionadded:: 3.6
+
+When set to ``TRUE`` in a directory, the build system produced by the
+:ref:`Makefile Generators` is set up to only consider dependencies on source
+files that appear either in the source or in the binary directories. Changes
+to source files outside of these directories will not cause rebuilds.
+
+This should be used carefully in cases where some source files are picked up
+through external headers during the build.
diff --git a/Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst b/Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst
new file mode 100644
index 0000000..bdad59e
--- /dev/null
+++ b/Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst
@@ -0,0 +1,9 @@
+CMAKE_DEPENDS_USE_COMPILER
+--------------------------
+
+.. versionadded:: 3.20
+
+For the :ref:`Makefile Generators`, source dependencies are now, for a
+selection of compilers, generated by the compiler itself. By defining this
+variable with value ``FALSE``, you can restore the legacy behavior (i.e. using
+``CMake`` for dependencies discovery).
diff --git a/Help/variable/CMAKE_DIRECTORY_LABELS.rst b/Help/variable/CMAKE_DIRECTORY_LABELS.rst
new file mode 100644
index 0000000..81d6dd1
--- /dev/null
+++ b/Help/variable/CMAKE_DIRECTORY_LABELS.rst
@@ -0,0 +1,8 @@
+CMAKE_DIRECTORY_LABELS
+-----------------------
+
+.. versionadded:: 3.10
+
+Specify labels for the current directory.
+
+This is used to initialize the :prop_dir:`LABELS` directory property.
diff --git a/Help/variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName.rst b/Help/variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName.rst
new file mode 100644
index 0000000..ed60020
--- /dev/null
+++ b/Help/variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName.rst
@@ -0,0 +1,16 @@
+CMAKE_DISABLE_FIND_PACKAGE_<PackageName>
+----------------------------------------
+
+Variable for disabling :command:`find_package` calls.
+
+Every non-``REQUIRED`` :command:`find_package` call in a project can be
+disabled by setting the variable
+``CMAKE_DISABLE_FIND_PACKAGE_<PackageName>`` to ``TRUE``.
+This can be used to build a project without an optional package,
+although that package is installed.
+
+This switch should be used during the initial CMake run. Otherwise if
+the package has already been found in a previous CMake run, the
+variables which have been stored in the cache will still be there. In
+that case it is recommended to remove the cache variables for this
+package from the cache using the cache editor or :manual:`cmake(1)` ``-U``
diff --git a/Help/variable/CMAKE_DISABLE_PRECOMPILE_HEADERS.rst b/Help/variable/CMAKE_DISABLE_PRECOMPILE_HEADERS.rst
new file mode 100644
index 0000000..cf52776
--- /dev/null
+++ b/Help/variable/CMAKE_DISABLE_PRECOMPILE_HEADERS.rst
@@ -0,0 +1,8 @@
+CMAKE_DISABLE_PRECOMPILE_HEADERS
+--------------------------------
+
+.. versionadded:: 3.16
+
+Default value for :prop_tgt:`DISABLE_PRECOMPILE_HEADERS` of targets.
+
+By default ``CMAKE_DISABLE_PRECOMPILE_HEADERS`` is ``OFF``.
diff --git a/Help/variable/CMAKE_DL_LIBS.rst b/Help/variable/CMAKE_DL_LIBS.rst
new file mode 100644
index 0000000..50d313d
--- /dev/null
+++ b/Help/variable/CMAKE_DL_LIBS.rst
@@ -0,0 +1,7 @@
+CMAKE_DL_LIBS
+-------------
+
+Name of library containing ``dlopen`` and ``dlclose``.
+
+The name of the library that has ``dlopen`` and ``dlclose`` in it, usually
+``-ldl`` on most UNIX machines.
diff --git a/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK.rst b/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK.rst
new file mode 100644
index 0000000..29249d6
--- /dev/null
+++ b/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK.rst
@@ -0,0 +1,18 @@
+CMAKE_DOTNET_TARGET_FRAMEWORK
+-----------------------------
+
+.. versionadded:: 3.17
+
+Default value for :prop_tgt:`DOTNET_TARGET_FRAMEWORK` property of
+targets.
+
+This variable is used to initialize the
+:prop_tgt:`DOTNET_TARGET_FRAMEWORK` property on all targets. See that
+target property for additional information.
+
+Setting ``CMAKE_DOTNET_TARGET_FRAMEWORK`` may be necessary
+when working with ``C#`` and newer .NET framework versions to
+avoid referencing errors with the ``ALL_BUILD`` CMake target.
+
+This variable is only evaluated for :ref:`Visual Studio Generators`
+VS 2010 and above.
diff --git a/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION.rst b/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION.rst
new file mode 100644
index 0000000..fc3c360
--- /dev/null
+++ b/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION.rst
@@ -0,0 +1,22 @@
+CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION
+-------------------------------------
+
+.. versionadded:: 3.12
+
+Default value for :prop_tgt:`DOTNET_TARGET_FRAMEWORK_VERSION`
+property of targets.
+
+This variable is used to initialize the
+:prop_tgt:`DOTNET_TARGET_FRAMEWORK_VERSION` property on all
+targets. See that target property for additional information. When set,
+:variable:`CMAKE_DOTNET_TARGET_FRAMEWORK` takes precednece over this
+variable. See that variable or the associated target property
+:prop_tgt:`DOTNET_TARGET_FRAMEWORK` for additional information.
+
+
+Setting ``CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION`` may be necessary
+when working with ``C#`` and newer .NET framework versions to
+avoid referencing errors with the ``ALL_BUILD`` CMake target.
+
+This variable is only evaluated for :ref:`Visual Studio Generators`
+VS 2010 and above.
diff --git a/Help/variable/CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES.rst b/Help/variable/CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES.rst
new file mode 100644
index 0000000..548c563
--- /dev/null
+++ b/Help/variable/CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES.rst
@@ -0,0 +1,12 @@
+CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES
+---------------------------------------
+
+.. versionadded:: 3.6
+
+This cache variable is used by the Eclipse project generator. See
+:manual:`cmake-generators(7)`.
+
+The Eclipse project generator generates so-called linked resources
+e.g. to the subproject root dirs in the source tree or to the source files
+of targets.
+This can be disabled by setting this variable to FALSE.
diff --git a/Help/variable/CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT.rst b/Help/variable/CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT.rst
new file mode 100644
index 0000000..fc28ebb
--- /dev/null
+++ b/Help/variable/CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT.rst
@@ -0,0 +1,13 @@
+CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT
+-------------------------------------
+
+.. versionadded:: 3.6
+
+This cache variable is used by the Eclipse project generator. See
+:manual:`cmake-generators(7)`.
+
+If this variable is set to TRUE, the Eclipse project generator will generate
+an Eclipse project in :variable:`CMAKE_SOURCE_DIR` . This project can then
+be used in Eclipse e.g. for the version control functionality.
+:variable:`CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT` defaults to FALSE; so
+nothing is written into the source directory.
diff --git a/Help/variable/CMAKE_ECLIPSE_MAKE_ARGUMENTS.rst b/Help/variable/CMAKE_ECLIPSE_MAKE_ARGUMENTS.rst
new file mode 100644
index 0000000..90e36f5
--- /dev/null
+++ b/Help/variable/CMAKE_ECLIPSE_MAKE_ARGUMENTS.rst
@@ -0,0 +1,11 @@
+CMAKE_ECLIPSE_MAKE_ARGUMENTS
+----------------------------
+
+.. versionadded:: 3.6
+
+This cache variable is used by the Eclipse project generator. See
+:manual:`cmake-generators(7)`.
+
+This variable holds arguments which are used when Eclipse invokes the make
+tool. By default it is initialized to hold flags to enable parallel builds
+(using -j typically).
diff --git a/Help/variable/CMAKE_ECLIPSE_RESOURCE_ENCODING.rst b/Help/variable/CMAKE_ECLIPSE_RESOURCE_ENCODING.rst
new file mode 100644
index 0000000..492acd8
--- /dev/null
+++ b/Help/variable/CMAKE_ECLIPSE_RESOURCE_ENCODING.rst
@@ -0,0 +1,8 @@
+CMAKE_ECLIPSE_RESOURCE_ENCODING
+-------------------------------
+
+.. versionadded:: 3.16
+
+This cache variable tells the :generator:`Eclipse CDT4` project generator
+to set the resource encoding to the given value in generated project files.
+If no value is given, no encoding will be set.
diff --git a/Help/variable/CMAKE_ECLIPSE_VERSION.rst b/Help/variable/CMAKE_ECLIPSE_VERSION.rst
new file mode 100644
index 0000000..db65d89
--- /dev/null
+++ b/Help/variable/CMAKE_ECLIPSE_VERSION.rst
@@ -0,0 +1,12 @@
+CMAKE_ECLIPSE_VERSION
+---------------------
+
+.. versionadded:: 3.6
+
+This cache variable is used by the Eclipse project generator. See
+:manual:`cmake-generators(7)`.
+
+When using the Eclipse project generator, CMake tries to find the Eclipse
+executable and detect the version of it. Depending on the version it finds,
+some features are enabled or disabled. If CMake doesn't find
+Eclipse, it assumes the oldest supported version, Eclipse Callisto (3.2).
diff --git a/Help/variable/CMAKE_EDIT_COMMAND.rst b/Help/variable/CMAKE_EDIT_COMMAND.rst
new file mode 100644
index 0000000..2f4ab1f
--- /dev/null
+++ b/Help/variable/CMAKE_EDIT_COMMAND.rst
@@ -0,0 +1,8 @@
+CMAKE_EDIT_COMMAND
+------------------
+
+Full path to :manual:`cmake-gui(1)` or :manual:`ccmake(1)`. Defined only for
+:ref:`Makefile Generators` when not using an "extra" generator for an IDE.
+
+This is the full path to the CMake executable that can graphically
+edit the cache. For example, :manual:`cmake-gui(1)` or :manual:`ccmake(1)`.
diff --git a/Help/variable/CMAKE_ENABLE_EXPORTS.rst b/Help/variable/CMAKE_ENABLE_EXPORTS.rst
new file mode 100644
index 0000000..9f43de3
--- /dev/null
+++ b/Help/variable/CMAKE_ENABLE_EXPORTS.rst
@@ -0,0 +1,10 @@
+CMAKE_ENABLE_EXPORTS
+--------------------
+
+.. versionadded:: 3.4
+
+Specify whether executables export symbols for loadable modules.
+
+This variable is used to initialize the :prop_tgt:`ENABLE_EXPORTS` target
+property for executable targets when they are created by calls to the
+:command:`add_executable` command. See the property documentation for details.
diff --git a/Help/variable/CMAKE_ERROR_DEPRECATED.rst b/Help/variable/CMAKE_ERROR_DEPRECATED.rst
new file mode 100644
index 0000000..f3a6738
--- /dev/null
+++ b/Help/variable/CMAKE_ERROR_DEPRECATED.rst
@@ -0,0 +1,7 @@
+CMAKE_ERROR_DEPRECATED
+----------------------
+
+Whether to issue errors for deprecated functionality.
+
+If ``TRUE``, use of deprecated functionality will issue fatal errors.
+If this variable is not set, CMake behaves as if it were set to ``FALSE``.
diff --git a/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst b/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
new file mode 100644
index 0000000..38e9b7b
--- /dev/null
+++ b/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
@@ -0,0 +1,10 @@
+CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
+-------------------------------------------
+
+Ask ``cmake_install.cmake`` script to error out as soon as a file with
+absolute ``INSTALL DESTINATION`` is encountered.
+
+The fatal error is emitted before the installation of the offending
+file takes place. This variable is used by CMake-generated
+``cmake_install.cmake`` scripts. If one sets this variable to ``ON`` while
+running the script, it may get fatal error messages from the script.
diff --git a/Help/variable/CMAKE_EXECUTABLE_SUFFIX.rst b/Help/variable/CMAKE_EXECUTABLE_SUFFIX.rst
new file mode 100644
index 0000000..356590f
--- /dev/null
+++ b/Help/variable/CMAKE_EXECUTABLE_SUFFIX.rst
@@ -0,0 +1,9 @@
+CMAKE_EXECUTABLE_SUFFIX
+-----------------------
+
+The suffix for executables on this platform.
+
+The suffix to use for the end of an executable filename if any, ``.exe``
+on Windows.
+
+``CMAKE_EXECUTABLE_SUFFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO.rst b/Help/variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO.rst
new file mode 100644
index 0000000..90a16c3
--- /dev/null
+++ b/Help/variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO.rst
@@ -0,0 +1,8 @@
+CMAKE_EXECUTE_PROCESS_COMMAND_ECHO
+----------------------------------
+
+.. versionadded:: 3.15
+
+If this variable is set to ``STDERR``, ``STDOUT`` or ``NONE`` then commands
+in :command:`execute_process` calls will be printed to either stderr or
+stdout or not at all.
diff --git a/Help/variable/CMAKE_EXE_LINKER_FLAGS.rst b/Help/variable/CMAKE_EXE_LINKER_FLAGS.rst
new file mode 100644
index 0000000..9e108f8
--- /dev/null
+++ b/Help/variable/CMAKE_EXE_LINKER_FLAGS.rst
@@ -0,0 +1,6 @@
+CMAKE_EXE_LINKER_FLAGS
+----------------------
+
+Linker flags to be used to create executables.
+
+These flags will be used by the linker when creating an executable.
diff --git a/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst b/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst
new file mode 100644
index 0000000..0cd8113
--- /dev/null
+++ b/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst
@@ -0,0 +1,7 @@
+CMAKE_EXE_LINKER_FLAGS_<CONFIG>
+-------------------------------
+
+Flags to be used when linking an executable.
+
+Same as ``CMAKE_C_FLAGS_*`` but used by the linker when creating
+executables.
diff --git a/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG_INIT.rst b/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG_INIT.rst
new file mode 100644
index 0000000..4d2718a
--- /dev/null
+++ b/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG_INIT.rst
@@ -0,0 +1,12 @@
+CMAKE_EXE_LINKER_FLAGS_<CONFIG>_INIT
+------------------------------------
+
+.. versionadded:: 3.7
+
+Value used to initialize the :variable:`CMAKE_EXE_LINKER_FLAGS_<CONFIG>`
+cache entry the first time a build tree is configured.
+This variable is meant to be set by a :variable:`toolchain file
+<CMAKE_TOOLCHAIN_FILE>`. CMake may prepend or append content to
+the value based on the environment and target platform.
+
+See also :variable:`CMAKE_EXE_LINKER_FLAGS_INIT`.
diff --git a/Help/variable/CMAKE_EXE_LINKER_FLAGS_INIT.rst b/Help/variable/CMAKE_EXE_LINKER_FLAGS_INIT.rst
new file mode 100644
index 0000000..6e3927c
--- /dev/null
+++ b/Help/variable/CMAKE_EXE_LINKER_FLAGS_INIT.rst
@@ -0,0 +1,13 @@
+CMAKE_EXE_LINKER_FLAGS_INIT
+---------------------------
+
+.. versionadded:: 3.7
+
+Value used to initialize the :variable:`CMAKE_EXE_LINKER_FLAGS`
+cache entry the first time a build tree is configured.
+This variable is meant to be set by a :variable:`toolchain file
+<CMAKE_TOOLCHAIN_FILE>`. CMake may prepend or append content to
+the value based on the environment and target platform.
+
+See also the configuration-specific variable
+:variable:`CMAKE_EXE_LINKER_FLAGS_<CONFIG>_INIT`.
diff --git a/Help/variable/CMAKE_EXPORT_COMPILE_COMMANDS.rst b/Help/variable/CMAKE_EXPORT_COMPILE_COMMANDS.rst
new file mode 100644
index 0000000..53a19dc
--- /dev/null
+++ b/Help/variable/CMAKE_EXPORT_COMPILE_COMMANDS.rst
@@ -0,0 +1,40 @@
+CMAKE_EXPORT_COMPILE_COMMANDS
+-----------------------------
+
+.. versionadded:: 3.5
+
+Enable/Disable output of compile commands during generation.
+
+If enabled, generates a ``compile_commands.json`` file containing the exact
+compiler calls for all translation units of the project in machine-readable
+form. The format of the JSON file looks like:
+
+.. code-block:: javascript
+
+ [
+ {
+ "directory": "/home/user/development/project",
+ "command": "/usr/bin/c++ ... -c ../foo/foo.cc",
+ "file": "../foo/foo.cc"
+ },
+
+ ...
+
+ {
+ "directory": "/home/user/development/project",
+ "command": "/usr/bin/c++ ... -c ../foo/bar.cc",
+ "file": "../foo/bar.cc"
+ }
+ ]
+
+This is initialized by the :envvar:`CMAKE_EXPORT_COMPILE_COMMANDS` environment
+variable, and initializes the :prop_tgt:`EXPORT_COMPILE_COMMANDS` target
+property for all targets.
+
+.. note::
+ This option is implemented only by :ref:`Makefile Generators`
+ and the :generator:`Ninja`. It is ignored on other generators.
+
+ This option currently does not work well in combination with
+ the :prop_tgt:`UNITY_BUILD` target property or the
+ :variable:`CMAKE_UNITY_BUILD` variable.
diff --git a/Help/variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY.rst b/Help/variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY.rst
new file mode 100644
index 0000000..5772490
--- /dev/null
+++ b/Help/variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY.rst
@@ -0,0 +1,18 @@
+CMAKE_EXPORT_NO_PACKAGE_REGISTRY
+--------------------------------
+
+.. versionadded:: 3.1
+
+Disable the :command:`export(PACKAGE)` command when :policy:`CMP0090`
+is not set to ``NEW``.
+
+In some cases, for example for packaging and for system wide
+installations, it is not desirable to write the user package registry.
+If the ``CMAKE_EXPORT_NO_PACKAGE_REGISTRY`` variable is enabled,
+the :command:`export(PACKAGE)` command will do nothing.
+
+If :policy:`CMP0090` is set to ``NEW`` this variable does nothing, and the
+:variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` variable controls the behavior
+instead.
+
+See also :ref:`Disabling the Package Registry`.
diff --git a/Help/variable/CMAKE_EXPORT_PACKAGE_REGISTRY.rst b/Help/variable/CMAKE_EXPORT_PACKAGE_REGISTRY.rst
new file mode 100644
index 0000000..663639b
--- /dev/null
+++ b/Help/variable/CMAKE_EXPORT_PACKAGE_REGISTRY.rst
@@ -0,0 +1,17 @@
+CMAKE_EXPORT_PACKAGE_REGISTRY
+-----------------------------
+
+.. versionadded:: 3.15
+
+Enables the :command:`export(PACKAGE)` command when :policy:`CMP0090`
+is set to ``NEW``.
+
+The :command:`export(PACKAGE)` command does nothing by default. In some cases
+it is desirable to write to the user package registry, so the
+``CMAKE_EXPORT_PACKAGE_REGISTRY`` variable may be set to enable it.
+
+If :policy:`CMP0090` is *not* set to ``NEW`` this variable does nothing, and
+the :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable controls the behavior
+instead.
+
+See also :ref:`Disabling the Package Registry`.
diff --git a/Help/variable/CMAKE_EXTRA_GENERATOR.rst b/Help/variable/CMAKE_EXTRA_GENERATOR.rst
new file mode 100644
index 0000000..2c92323
--- /dev/null
+++ b/Help/variable/CMAKE_EXTRA_GENERATOR.rst
@@ -0,0 +1,10 @@
+CMAKE_EXTRA_GENERATOR
+---------------------
+
+The extra generator used to build the project. See
+:manual:`cmake-generators(7)`.
+
+When using the Eclipse, CodeBlocks, CodeLite, Kate or Sublime generators, CMake
+generates Makefiles (:variable:`CMAKE_GENERATOR`) and additionally project
+files for the respective IDE. This IDE project file generator is stored in
+``CMAKE_EXTRA_GENERATOR`` (e.g. ``Eclipse CDT4``).
diff --git a/Help/variable/CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES.rst b/Help/variable/CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES.rst
new file mode 100644
index 0000000..a130adb
--- /dev/null
+++ b/Help/variable/CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES.rst
@@ -0,0 +1,9 @@
+CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES
+-----------------------------------
+
+Additional suffixes for shared libraries.
+
+Extensions for shared libraries other than that specified by
+:variable:`CMAKE_SHARED_LIBRARY_SUFFIX`, if any. CMake uses this to recognize
+external shared library files during analysis of libraries linked by a
+target.
diff --git a/Help/variable/CMAKE_FIND_APPBUNDLE.rst b/Help/variable/CMAKE_FIND_APPBUNDLE.rst
new file mode 100644
index 0000000..17563f3
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_APPBUNDLE.rst
@@ -0,0 +1,24 @@
+CMAKE_FIND_APPBUNDLE
+--------------------
+
+.. versionadded:: 3.4
+
+This variable affects how ``find_*`` commands choose between
+macOS Application Bundles and unix-style package components.
+
+On Darwin or systems supporting macOS Application Bundles, the
+``CMAKE_FIND_APPBUNDLE`` variable can be set to empty or
+one of the following:
+
+``FIRST``
+ Try to find application bundles before standard programs.
+ This is the default on Darwin.
+
+``LAST``
+ Try to find application bundles after standard programs.
+
+``ONLY``
+ Only try to find application bundles.
+
+``NEVER``
+ Never try to find application bundles.
diff --git a/Help/variable/CMAKE_FIND_DEBUG_MODE.rst b/Help/variable/CMAKE_FIND_DEBUG_MODE.rst
new file mode 100644
index 0000000..8f2a82f
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_DEBUG_MODE.rst
@@ -0,0 +1,25 @@
+CMAKE_FIND_DEBUG_MODE
+---------------------
+
+.. versionadded:: 3.17
+
+Print extra find call information for the following commands to standard
+error:
+
+* :command:`find_program`
+* :command:`find_library`
+* :command:`find_file`
+* :command:`find_path`
+* :command:`find_package`
+
+Output is designed for human consumption and not for parsing.
+Enabling this variable is equivalent to using :manual:`cmake <cmake(1)>` ``--debug-find``
+with the added ability to enable debugging for a subset of find calls.
+
+.. code-block:: cmake
+
+ set(CMAKE_FIND_DEBUG_MODE TRUE)
+ find_program(...)
+ set(CMAKE_FIND_DEBUG_MODE FALSE)
+
+Default is unset.
diff --git a/Help/variable/CMAKE_FIND_FRAMEWORK.rst b/Help/variable/CMAKE_FIND_FRAMEWORK.rst
new file mode 100644
index 0000000..3b62cda
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_FRAMEWORK.rst
@@ -0,0 +1,24 @@
+CMAKE_FIND_FRAMEWORK
+--------------------
+
+.. versionadded:: 3.4
+
+This variable affects how ``find_*`` commands choose between
+macOS Frameworks and unix-style package components.
+
+On Darwin or systems supporting macOS Frameworks, the
+``CMAKE_FIND_FRAMEWORK`` variable can be set to empty or
+one of the following:
+
+``FIRST``
+ Try to find frameworks before standard libraries or headers.
+ This is the default on Darwin.
+
+``LAST``
+ Try to find frameworks after standard libraries or headers.
+
+``ONLY``
+ Only try to find frameworks.
+
+``NEVER``
+ Never try to find frameworks.
diff --git a/Help/variable/CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX.rst b/Help/variable/CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX.rst
new file mode 100644
index 0000000..ca2ad7f
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX.rst
@@ -0,0 +1,14 @@
+CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX
+------------------------------------
+
+.. versionadded:: 3.9
+
+Specify a ``<suffix>`` to tell the :command:`find_library` command to
+search in a ``lib<suffix>`` directory before each ``lib`` directory that
+would normally be searched.
+
+This overrides the behavior of related global properties:
+
+* :prop_gbl:`FIND_LIBRARY_USE_LIB32_PATHS`
+* :prop_gbl:`FIND_LIBRARY_USE_LIB64_PATHS`
+* :prop_gbl:`FIND_LIBRARY_USE_LIBX32_PATHS`
diff --git a/Help/variable/CMAKE_FIND_LIBRARY_PREFIXES.rst b/Help/variable/CMAKE_FIND_LIBRARY_PREFIXES.rst
new file mode 100644
index 0000000..58354b2
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_LIBRARY_PREFIXES.rst
@@ -0,0 +1,9 @@
+CMAKE_FIND_LIBRARY_PREFIXES
+---------------------------
+
+Prefixes to prepend when looking for libraries.
+
+This specifies what prefixes to add to library names when the
+:command:`find_library` command looks for libraries. On UNIX systems this is
+typically ``lib``, meaning that when trying to find the ``foo`` library it
+will look for ``libfoo``.
diff --git a/Help/variable/CMAKE_FIND_LIBRARY_SUFFIXES.rst b/Help/variable/CMAKE_FIND_LIBRARY_SUFFIXES.rst
new file mode 100644
index 0000000..4a64e33
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_LIBRARY_SUFFIXES.rst
@@ -0,0 +1,9 @@
+CMAKE_FIND_LIBRARY_SUFFIXES
+---------------------------
+
+Suffixes to append when looking for libraries.
+
+This specifies what suffixes to add to library names when the
+:command:`find_library` command looks for libraries. On Windows systems this
+is typically ``.lib`` and ``.dll``, meaning that when trying to find the
+``foo`` library it will look for ``foo.dll`` etc.
diff --git a/Help/variable/CMAKE_FIND_NO_INSTALL_PREFIX.rst b/Help/variable/CMAKE_FIND_NO_INSTALL_PREFIX.rst
new file mode 100644
index 0000000..789dc99
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_NO_INSTALL_PREFIX.rst
@@ -0,0 +1,19 @@
+CMAKE_FIND_NO_INSTALL_PREFIX
+----------------------------
+
+Exclude the values of the :variable:`CMAKE_INSTALL_PREFIX` and
+:variable:`CMAKE_STAGING_PREFIX` variables from
+:variable:`CMAKE_SYSTEM_PREFIX_PATH`. CMake adds these project-destination
+prefixes to :variable:`CMAKE_SYSTEM_PREFIX_PATH` by default in order to
+support building a series of dependent packages and installing them into
+a common prefix. Set ``CMAKE_FIND_NO_INSTALL_PREFIX`` to ``TRUE``
+to suppress this behavior.
+
+The :variable:`CMAKE_SYSTEM_PREFIX_PATH` is initialized on the first call to a
+:command:`project` or :command:`enable_language` command. Therefore one must
+set ``CMAKE_FIND_NO_INSTALL_PREFIX`` before this in order to take effect. A
+user may set the variable as a cache entry on the command line to achieve this.
+
+Note that the prefix(es) may still be searched for other reasons, such as being
+the same prefix as the CMake installation, or for being a built-in system
+prefix.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_NAME.rst b/Help/variable/CMAKE_FIND_PACKAGE_NAME.rst
new file mode 100644
index 0000000..fc1fd43
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_PACKAGE_NAME.rst
@@ -0,0 +1,8 @@
+CMAKE_FIND_PACKAGE_NAME
+-----------------------
+
+.. versionadded:: 3.1.1
+
+Defined by the :command:`find_package` command while loading
+a find module to record the caller-specified package name.
+See command documentation for details.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY.rst b/Help/variable/CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY.rst
new file mode 100644
index 0000000..8d86a94
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY.rst
@@ -0,0 +1,26 @@
+CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY
+--------------------------------------
+
+.. versionadded:: 3.1
+
+.. deprecated:: 3.16
+
+ Use the :variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY` variable instead.
+
+By default this variable is not set. If neither
+:variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY` nor
+``CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY`` is set, then
+:command:`find_package()` will use the :ref:`User Package Registry`
+unless the ``NO_CMAKE_PACKAGE_REGISTRY`` option is provided.
+
+``CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY`` is ignored if
+:variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY` is set.
+
+In some cases, for example to locate only system wide installations, it
+is not desirable to use the :ref:`User Package Registry` when searching
+for packages. If the :variable:`CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY`
+variable is ``TRUE``, all the :command:`find_package` commands will skip
+the :ref:`User Package Registry` as if they were called with the
+``NO_CMAKE_PACKAGE_REGISTRY`` argument.
+
+See also :ref:`Disabling the Package Registry`.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY.rst b/Help/variable/CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY.rst
new file mode 100644
index 0000000..cc67f08
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY.rst
@@ -0,0 +1,26 @@
+CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY
+---------------------------------------------
+
+.. versionadded:: 3.1
+
+.. deprecated:: 3.16
+
+ Use the :variable:`CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY` variable instead.
+
+By default this variable is not set. If neither
+:variable:`CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY` nor
+``CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY`` is set, then
+:command:`find_package()` will use the :ref:`System Package Registry`
+unless the ``NO_CMAKE_SYSTEM_PACKAGE_REGISTRY`` option is provided.
+
+``CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY`` is ignored if
+:variable:`CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY` is set.
+
+In some cases, it is not desirable to use the
+:ref:`System Package Registry` when searching for packages. If the
+:variable:`CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY` variable is
+``TRUE``, all the :command:`find_package` commands will skip
+the :ref:`System Package Registry` as if they were called with the
+``NO_CMAKE_SYSTEM_PACKAGE_REGISTRY`` argument.
+
+See also :ref:`Disabling the Package Registry`.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.rst b/Help/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.rst
new file mode 100644
index 0000000..ba81529
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.rst
@@ -0,0 +1,29 @@
+CMAKE_FIND_PACKAGE_PREFER_CONFIG
+---------------------------------
+
+.. versionadded:: 3.15
+
+Tell :command:`find_package` to try "Config" mode before "Module" mode if no
+mode was specified.
+
+The command :command:`find_package` operates without an explicit mode when
+the reduced signature is used without the ``MODULE`` option. In this case,
+by default, CMake first tries Module mode by searching for a
+``Find<pkg>.cmake`` module. If it fails, CMake then searches for the package
+using Config mode.
+
+Set ``CMAKE_FIND_PACKAGE_PREFER_CONFIG`` to ``TRUE`` to tell
+:command:`find_package` to first search using Config mode before falling back
+to Module mode.
+
+This variable may be useful when a developer has compiled a custom version of
+a common library and wishes to link it to a dependent project. If this
+variable is set to ``TRUE``, it would prevent a dependent project's call
+to :command:`find_package` from selecting the default library located by the
+system's ``Find<pkg>.cmake`` module before finding the developer's custom
+built library.
+
+Once this variable is set, it is the responsibility of the exported
+``<pkg>Config.cmake`` files to provide the same result variables as the
+``Find<pkg>.cmake`` modules so that dependent projects can use them
+interchangeably.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS.rst b/Help/variable/CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS.rst
new file mode 100644
index 0000000..86d75e7
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS.rst
@@ -0,0 +1,12 @@
+CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS
+-----------------------------------
+
+.. versionadded:: 3.14
+
+Set to ``TRUE`` to tell :command:`find_package` calls to resolve symbolic
+links in the value of ``<PackageName>_DIR``.
+
+This is helpful in use cases where the package search path points at a
+proxy directory in which symlinks to the real package locations appear.
+This is not enabled by default because there are also common use cases
+in which the symlinks should be preserved.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst b/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst
new file mode 100644
index 0000000..98c2a8f
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst
@@ -0,0 +1,18 @@
+CMAKE_FIND_PACKAGE_SORT_DIRECTION
+---------------------------------
+
+.. versionadded:: 3.7
+
+The sorting direction used by :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER`.
+It can assume one of the following values:
+
+``DEC``
+ Default. Ordering is done in descending mode.
+ The highest folder found will be tested first.
+
+``ASC``
+ Ordering is done in ascending mode.
+ The lowest folder found will be tested first.
+
+If :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` is not set or is set to ``NONE``
+this variable has no effect.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst b/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst
new file mode 100644
index 0000000..1725ba1
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst
@@ -0,0 +1,38 @@
+CMAKE_FIND_PACKAGE_SORT_ORDER
+-----------------------------
+
+.. versionadded:: 3.7
+
+The default order for sorting packages found using :command:`find_package`.
+It can assume one of the following values:
+
+``NONE``
+ Default. No attempt is done to sort packages.
+ The first valid package found will be selected.
+
+``NAME``
+ Sort packages lexicographically before selecting one.
+
+``NATURAL``
+ Sort packages using natural order (see ``strverscmp(3)`` manual),
+ i.e. such that contiguous digits are compared as whole numbers.
+
+Natural sorting can be employed to return the highest version when multiple
+versions of the same library are found by :command:`find_package`. For
+example suppose that the following libraries have been found:
+
+* libX-1.1.0
+* libX-1.2.9
+* libX-1.2.10
+
+By setting ``NATURAL`` order we can select the one with the highest
+version number ``libX-1.2.10``.
+
+.. code-block:: cmake
+
+ set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
+ find_package(libX CONFIG)
+
+The sort direction can be controlled using the
+:variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` variable
+(by default decrescent, e.g. lib-B will be tested before lib-A).
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst b/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst
new file mode 100644
index 0000000..5c4f23a
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst
@@ -0,0 +1,22 @@
+CMAKE_FIND_PACKAGE_WARN_NO_MODULE
+---------------------------------
+
+Tell :command:`find_package` to warn if called without an explicit mode.
+
+If :command:`find_package` is called without an explicit mode option
+(``MODULE``, ``CONFIG``, or ``NO_MODULE``) and no ``Find<pkg>.cmake`` module
+is in :variable:`CMAKE_MODULE_PATH` then CMake implicitly assumes that the
+caller intends to search for a package configuration file. If no package
+configuration file is found then the wording of the failure message
+must account for both the case that the package is really missing and
+the case that the project has a bug and failed to provide the intended
+Find module. If instead the caller specifies an explicit mode option
+then the failure message can be more specific.
+
+Set ``CMAKE_FIND_PACKAGE_WARN_NO_MODULE`` to ``TRUE`` to tell
+:command:`find_package` to warn when it implicitly assumes Config mode. This
+helps developers enforce use of an explicit mode in all calls to
+:command:`find_package` within a project.
+
+This variable has no effect if :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG` is
+set to ``TRUE``.
diff --git a/Help/variable/CMAKE_FIND_ROOT_PATH.rst b/Help/variable/CMAKE_FIND_ROOT_PATH.rst
new file mode 100644
index 0000000..6172c56
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_ROOT_PATH.rst
@@ -0,0 +1,8 @@
+CMAKE_FIND_ROOT_PATH
+--------------------
+
+:ref:`Semicolon-separated list <CMake Language Lists>` of root paths to search on the filesystem.
+
+This variable is most useful when cross-compiling. CMake uses the paths in
+this list as alternative roots to find filesystem items with
+:command:`find_package`, :command:`find_library` etc.
diff --git a/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_INCLUDE.rst b/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_INCLUDE.rst
new file mode 100644
index 0000000..df1af5a
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_INCLUDE.rst
@@ -0,0 +1,6 @@
+CMAKE_FIND_ROOT_PATH_MODE_INCLUDE
+---------------------------------
+
+.. |FIND_XXX| replace:: :command:`find_file` and :command:`find_path`
+
+.. include:: CMAKE_FIND_ROOT_PATH_MODE_XXX.txt
diff --git a/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_LIBRARY.rst b/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_LIBRARY.rst
new file mode 100644
index 0000000..52ab89d
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_LIBRARY.rst
@@ -0,0 +1,6 @@
+CMAKE_FIND_ROOT_PATH_MODE_LIBRARY
+---------------------------------
+
+.. |FIND_XXX| replace:: :command:`find_library`
+
+.. include:: CMAKE_FIND_ROOT_PATH_MODE_XXX.txt
diff --git a/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_PACKAGE.rst b/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_PACKAGE.rst
new file mode 100644
index 0000000..3872947
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_PACKAGE.rst
@@ -0,0 +1,6 @@
+CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
+---------------------------------
+
+.. |FIND_XXX| replace:: :command:`find_package`
+
+.. include:: CMAKE_FIND_ROOT_PATH_MODE_XXX.txt
diff --git a/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_PROGRAM.rst b/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_PROGRAM.rst
new file mode 100644
index 0000000..d24a78a
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_PROGRAM.rst
@@ -0,0 +1,6 @@
+CMAKE_FIND_ROOT_PATH_MODE_PROGRAM
+---------------------------------
+
+.. |FIND_XXX| replace:: :command:`find_program`
+
+.. include:: CMAKE_FIND_ROOT_PATH_MODE_XXX.txt
diff --git a/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_XXX.txt b/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_XXX.txt
new file mode 100644
index 0000000..ab65e09
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_ROOT_PATH_MODE_XXX.txt
@@ -0,0 +1,8 @@
+This variable controls whether the :variable:`CMAKE_FIND_ROOT_PATH` and
+:variable:`CMAKE_SYSROOT` are used by |FIND_XXX|.
+
+If set to ``ONLY``, then only the roots in :variable:`CMAKE_FIND_ROOT_PATH`
+will be searched. If set to ``NEVER``, then the roots in
+:variable:`CMAKE_FIND_ROOT_PATH` will be ignored and only the host system
+root will be used. If set to ``BOTH``, then the host system paths and the
+paths in :variable:`CMAKE_FIND_ROOT_PATH` will be searched.
diff --git a/Help/variable/CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH.rst b/Help/variable/CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH.rst
new file mode 100644
index 0000000..de1bad7
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH.rst
@@ -0,0 +1,26 @@
+CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH
+-------------------------------------
+
+.. versionadded:: 3.16
+
+Controls the default behavior of the following commands for whether or not to
+search paths provided by cmake-specific environment variables:
+
+* :command:`find_program`
+* :command:`find_library`
+* :command:`find_file`
+* :command:`find_path`
+* :command:`find_package`
+
+This is useful in cross-compiling environments.
+
+By default this variable is not set, which is equivalent to it having
+a value of ``TRUE``. Explicit options given to the above commands
+take precedence over this variable.
+
+See also the :variable:`CMAKE_FIND_USE_CMAKE_PATH`,
+:variable:`CMAKE_FIND_USE_CMAKE_SYSTEM_PATH`,
+:variable:`CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH`,
+:variable:`CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY`,
+:variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY`,
+and :variable:`CMAKE_FIND_USE_PACKAGE_ROOT_PATH` variables.
diff --git a/Help/variable/CMAKE_FIND_USE_CMAKE_PATH.rst b/Help/variable/CMAKE_FIND_USE_CMAKE_PATH.rst
new file mode 100644
index 0000000..47ce3a3
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_USE_CMAKE_PATH.rst
@@ -0,0 +1,26 @@
+CMAKE_FIND_USE_CMAKE_PATH
+-------------------------
+
+.. versionadded:: 3.16
+
+Controls the default behavior of the following commands for whether or not to
+search paths provided by cmake-specific cache variables:
+
+* :command:`find_program`
+* :command:`find_library`
+* :command:`find_file`
+* :command:`find_path`
+* :command:`find_package`
+
+This is useful in cross-compiling environments.
+
+By default this variable is not set, which is equivalent to it having
+a value of ``TRUE``. Explicit options given to the above commands
+take precedence over this variable.
+
+See also the :variable:`CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH`,
+:variable:`CMAKE_FIND_USE_CMAKE_SYSTEM_PATH`,
+:variable:`CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH`,
+:variable:`CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY`,
+:variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY`,
+and :variable:`CMAKE_FIND_USE_PACKAGE_ROOT_PATH` variables.
diff --git a/Help/variable/CMAKE_FIND_USE_CMAKE_SYSTEM_PATH.rst b/Help/variable/CMAKE_FIND_USE_CMAKE_SYSTEM_PATH.rst
new file mode 100644
index 0000000..2fd00df
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_USE_CMAKE_SYSTEM_PATH.rst
@@ -0,0 +1,26 @@
+CMAKE_FIND_USE_CMAKE_SYSTEM_PATH
+--------------------------------
+
+.. versionadded:: 3.16
+
+Controls the default behavior of the following commands for whether or not to
+search paths provided by platform-specific cmake variables:
+
+* :command:`find_program`
+* :command:`find_library`
+* :command:`find_file`
+* :command:`find_path`
+* :command:`find_package`
+
+This is useful in cross-compiling environments.
+
+By default this variable is not set, which is equivalent to it having
+a value of ``TRUE``. Explicit options given to the above commands
+take precedence over this variable.
+
+See also the :variable:`CMAKE_FIND_USE_CMAKE_PATH`,
+:variable:`CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH`,
+:variable:`CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH`,
+:variable:`CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY`,
+:variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY`,
+and :variable:`CMAKE_FIND_USE_PACKAGE_ROOT_PATH` variables.
diff --git a/Help/variable/CMAKE_FIND_USE_PACKAGE_REGISTRY.rst b/Help/variable/CMAKE_FIND_USE_PACKAGE_REGISTRY.rst
new file mode 100644
index 0000000..3127206
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_USE_PACKAGE_REGISTRY.rst
@@ -0,0 +1,32 @@
+CMAKE_FIND_USE_PACKAGE_REGISTRY
+-------------------------------
+
+.. versionadded:: 3.16
+
+Controls the default behavior of the :command:`find_package` command for
+whether or not to search paths provided by the :ref:`User Package Registry`.
+
+By default this variable is not set and the behavior will fall back
+to that determined by the deprecated
+:variable:`CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY` variable. If that is
+also not set, then :command:`find_package` will use the
+:ref:`User Package Registry` unless the ``NO_CMAKE_PACKAGE_REGISTRY`` option
+is provided.
+
+This variable takes precedence over
+:variable:`CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY` when both are set.
+
+In some cases, for example to locate only system wide installations, it
+is not desirable to use the :ref:`User Package Registry` when searching
+for packages. If the :variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY`
+variable is ``FALSE``, all the :command:`find_package` commands will skip
+the :ref:`User Package Registry` as if they were called with the
+``NO_CMAKE_PACKAGE_REGISTRY`` argument.
+
+See also :ref:`Disabling the Package Registry` and the
+:variable:`CMAKE_FIND_USE_CMAKE_PATH`,
+:variable:`CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH`,
+:variable:`CMAKE_FIND_USE_CMAKE_SYSTEM_PATH`,
+:variable:`CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH`,
+:variable:`CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY`,
+and :variable:`CMAKE_FIND_USE_PACKAGE_ROOT_PATH` variables.
diff --git a/Help/variable/CMAKE_FIND_USE_PACKAGE_ROOT_PATH.rst b/Help/variable/CMAKE_FIND_USE_PACKAGE_ROOT_PATH.rst
new file mode 100644
index 0000000..64e5c6d
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_USE_PACKAGE_ROOT_PATH.rst
@@ -0,0 +1,24 @@
+CMAKE_FIND_USE_PACKAGE_ROOT_PATH
+--------------------------------
+
+.. versionadded:: 3.16
+
+Controls the default behavior of the following commands for whether or not to
+search paths provided by :variable:`<PackageName>_ROOT` variables:
+
+* :command:`find_program`
+* :command:`find_library`
+* :command:`find_file`
+* :command:`find_path`
+* :command:`find_package`
+
+By default this variable is not set, which is equivalent to it having
+a value of ``TRUE``. Explicit options given to the above commands
+take precedence over this variable.
+
+See also the :variable:`CMAKE_FIND_USE_CMAKE_PATH`,
+:variable:`CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH`,
+:variable:`CMAKE_FIND_USE_CMAKE_SYSTEM_PATH`,
+:variable:`CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH`,
+:variable:`CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY`,
+and :variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY` variables.
diff --git a/Help/variable/CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH.rst b/Help/variable/CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH.rst
new file mode 100644
index 0000000..a0a86e4
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH.rst
@@ -0,0 +1,26 @@
+CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH
+--------------------------------------
+
+.. versionadded:: 3.16
+
+Controls the default behavior of the following commands for whether or not to
+search paths provided by standard system environment variables:
+
+* :command:`find_program`
+* :command:`find_library`
+* :command:`find_file`
+* :command:`find_path`
+* :command:`find_package`
+
+This is useful in cross-compiling environments.
+
+By default this variable is not set, which is equivalent to it having
+a value of ``TRUE``. Explicit options given to the above commands
+take precedence over this variable.
+
+See also the :variable:`CMAKE_FIND_USE_CMAKE_PATH`,
+:variable:`CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH`,
+:variable:`CMAKE_FIND_USE_CMAKE_SYSTEM_PATH`,
+:variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY`,
+:variable:`CMAKE_FIND_USE_PACKAGE_ROOT_PATH`,
+and :variable:`CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY` variables.
diff --git a/Help/variable/CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY.rst b/Help/variable/CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY.rst
new file mode 100644
index 0000000..504b7e8
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY.rst
@@ -0,0 +1,33 @@
+CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY
+--------------------------------------
+
+.. versionadded:: 3.16
+
+Controls searching the :ref:`System Package Registry` by the
+:command:`find_package` command.
+
+By default this variable is not set and the behavior will fall back
+to that determined by the deprecated
+:variable:`CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY` variable.
+If that is also not set, then :command:`find_package()` will use the
+:ref:`System Package Registry` unless the ``NO_CMAKE_SYSTEM_PACKAGE_REGISTRY``
+option is provided.
+
+This variable takes precedence over
+:variable:`CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY` when both are set.
+
+In some cases, for example to locate only user specific installations, it
+is not desirable to use the :ref:`System Package Registry` when searching
+for packages. If the ``CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY``
+variable is ``FALSE``, all the :command:`find_package` commands will skip
+the :ref:`System Package Registry` as if they were called with the
+``NO_CMAKE_SYSTEM_PACKAGE_REGISTRY`` argument.
+
+See also :ref:`Disabling the Package Registry`.
+
+See also the :variable:`CMAKE_FIND_USE_CMAKE_PATH`,
+:variable:`CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH`,
+:variable:`CMAKE_FIND_USE_CMAKE_SYSTEM_PATH`,
+:variable:`CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH`,
+:variable:`CMAKE_FIND_USE_PACKAGE_REGISTRY`,
+and :variable:`CMAKE_FIND_USE_PACKAGE_ROOT_PATH` variables.
diff --git a/Help/variable/CMAKE_FOLDER.rst b/Help/variable/CMAKE_FOLDER.rst
new file mode 100644
index 0000000..37f137c
--- /dev/null
+++ b/Help/variable/CMAKE_FOLDER.rst
@@ -0,0 +1,9 @@
+CMAKE_FOLDER
+------------
+
+.. versionadded:: 3.12
+
+Set the folder name. Use to organize targets in an IDE.
+
+This variable is used to initialize the :prop_tgt:`FOLDER` property on all the
+targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_FRAMEWORK.rst b/Help/variable/CMAKE_FRAMEWORK.rst
new file mode 100644
index 0000000..37385bf
--- /dev/null
+++ b/Help/variable/CMAKE_FRAMEWORK.rst
@@ -0,0 +1,9 @@
+CMAKE_FRAMEWORK
+---------------
+
+.. versionadded:: 3.15
+
+Default value for :prop_tgt:`FRAMEWORK` of targets.
+
+This variable is used to initialize the :prop_tgt:`FRAMEWORK` property on
+all the targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst b/Help/variable/CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst
new file mode 100644
index 0000000..47fb66e
--- /dev/null
+++ b/Help/variable/CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst
@@ -0,0 +1,10 @@
+CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>
+---------------------------------------------
+
+.. versionadded:: 3.18
+
+Default framework filename postfix under configuration ``<CONFIG>`` when
+using a multi-config generator.
+
+When a framework target is created its :prop_tgt:`FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>`
+target property is initialized with the value of this variable if it is set.
diff --git a/Help/variable/CMAKE_FRAMEWORK_PATH.rst b/Help/variable/CMAKE_FRAMEWORK_PATH.rst
new file mode 100644
index 0000000..13ade4e
--- /dev/null
+++ b/Help/variable/CMAKE_FRAMEWORK_PATH.rst
@@ -0,0 +1,7 @@
+CMAKE_FRAMEWORK_PATH
+--------------------
+
+:ref:`Semicolon-separated list <CMake Language Lists>` of directories specifying a search path
+for macOS frameworks used by the :command:`find_library`,
+:command:`find_package`, :command:`find_path`, and :command:`find_file`
+commands.
diff --git a/Help/variable/CMAKE_Fortran_FORMAT.rst b/Help/variable/CMAKE_Fortran_FORMAT.rst
new file mode 100644
index 0000000..1406e59
--- /dev/null
+++ b/Help/variable/CMAKE_Fortran_FORMAT.rst
@@ -0,0 +1,7 @@
+CMAKE_Fortran_FORMAT
+--------------------
+
+Set to ``FIXED`` or ``FREE`` to indicate the Fortran source layout.
+
+This variable is used to initialize the :prop_tgt:`Fortran_FORMAT` property on
+all the targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_Fortran_MODDIR_DEFAULT.rst b/Help/variable/CMAKE_Fortran_MODDIR_DEFAULT.rst
new file mode 100644
index 0000000..5aeab07
--- /dev/null
+++ b/Help/variable/CMAKE_Fortran_MODDIR_DEFAULT.rst
@@ -0,0 +1,8 @@
+CMAKE_Fortran_MODDIR_DEFAULT
+----------------------------
+
+Fortran default module output directory.
+
+Most Fortran compilers write ``.mod`` files to the current working
+directory. For those that do not, this is set to ``.`` and used when
+the :prop_tgt:`Fortran_MODULE_DIRECTORY` target property is not set.
diff --git a/Help/variable/CMAKE_Fortran_MODDIR_FLAG.rst b/Help/variable/CMAKE_Fortran_MODDIR_FLAG.rst
new file mode 100644
index 0000000..1da55ca
--- /dev/null
+++ b/Help/variable/CMAKE_Fortran_MODDIR_FLAG.rst
@@ -0,0 +1,7 @@
+CMAKE_Fortran_MODDIR_FLAG
+-------------------------
+
+Fortran flag for module output directory.
+
+This stores the flag needed to pass the value of the
+:prop_tgt:`Fortran_MODULE_DIRECTORY` target property to the compiler.
diff --git a/Help/variable/CMAKE_Fortran_MODOUT_FLAG.rst b/Help/variable/CMAKE_Fortran_MODOUT_FLAG.rst
new file mode 100644
index 0000000..2f83880
--- /dev/null
+++ b/Help/variable/CMAKE_Fortran_MODOUT_FLAG.rst
@@ -0,0 +1,7 @@
+CMAKE_Fortran_MODOUT_FLAG
+-------------------------
+
+Fortran flag to enable module output.
+
+Most Fortran compilers write ``.mod`` files out by default. For others,
+this stores the flag needed to enable module output.
diff --git a/Help/variable/CMAKE_Fortran_MODULE_DIRECTORY.rst b/Help/variable/CMAKE_Fortran_MODULE_DIRECTORY.rst
new file mode 100644
index 0000000..3c7edc1
--- /dev/null
+++ b/Help/variable/CMAKE_Fortran_MODULE_DIRECTORY.rst
@@ -0,0 +1,8 @@
+CMAKE_Fortran_MODULE_DIRECTORY
+------------------------------
+
+Fortran module output directory.
+
+This variable is used to initialize the :prop_tgt:`Fortran_MODULE_DIRECTORY`
+property on all the targets. See that target property for additional
+information.
diff --git a/Help/variable/CMAKE_Fortran_PREPROCESS.rst b/Help/variable/CMAKE_Fortran_PREPROCESS.rst
new file mode 100644
index 0000000..7d405f3
--- /dev/null
+++ b/Help/variable/CMAKE_Fortran_PREPROCESS.rst
@@ -0,0 +1,10 @@
+CMAKE_Fortran_PREPROCESS
+------------------------
+
+.. versionadded:: 3.18
+
+Default value for :prop_tgt:`Fortran_PREPROCESS` of targets.
+
+This variable is used to initialize the :prop_tgt:`Fortran_PREPROCESS`
+property on all the targets. See that target property for additional
+information.
diff --git a/Help/variable/CMAKE_GENERATOR.rst b/Help/variable/CMAKE_GENERATOR.rst
new file mode 100644
index 0000000..ec52cd4
--- /dev/null
+++ b/Help/variable/CMAKE_GENERATOR.rst
@@ -0,0 +1,12 @@
+CMAKE_GENERATOR
+---------------
+
+The generator used to build the project. See :manual:`cmake-generators(7)`.
+
+The name of the generator that is being used to generate the build
+files. (e.g. ``Unix Makefiles``, ``Ninja``, etc.)
+
+The value of this variable should never be modified by project code.
+A generator may be selected via the :manual:`cmake(1)` ``-G`` option,
+interactively in :manual:`cmake-gui(1)`, or via the :envvar:`CMAKE_GENERATOR`
+environment variable.
diff --git a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst
new file mode 100644
index 0000000..5858d7a
--- /dev/null
+++ b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst
@@ -0,0 +1,27 @@
+CMAKE_GENERATOR_INSTANCE
+------------------------
+
+.. versionadded:: 3.11
+
+Generator-specific instance specification provided by user.
+
+Some CMake generators support selection of an instance of the native build
+system when multiple instances are available. If the user specifies an
+instance (e.g. by setting this cache entry or via the
+:envvar:`CMAKE_GENERATOR_INSTANCE` environment variable), or after a default
+instance is chosen when a build tree is first configured, the value will be
+available in this variable.
+
+The value of this variable should never be modified by project code.
+A toolchain file specified by the :variable:`CMAKE_TOOLCHAIN_FILE`
+variable may initialize ``CMAKE_GENERATOR_INSTANCE`` as a cache entry.
+Once a given build tree has been initialized with a particular value
+for this variable, changing the value has undefined behavior.
+
+Instance specification is supported only on specific generators:
+
+* For the :generator:`Visual Studio 15 2017` generator (and above)
+ this specifies the absolute path to the VS installation directory
+ of the selected VS instance.
+
+See native build system documentation for allowed instance values.
diff --git a/Help/variable/CMAKE_GENERATOR_PLATFORM.rst b/Help/variable/CMAKE_GENERATOR_PLATFORM.rst
new file mode 100644
index 0000000..b17d83a
--- /dev/null
+++ b/Help/variable/CMAKE_GENERATOR_PLATFORM.rst
@@ -0,0 +1,33 @@
+CMAKE_GENERATOR_PLATFORM
+------------------------
+
+.. versionadded:: 3.1
+
+Generator-specific target platform specification provided by user.
+
+Some CMake generators support a target platform name to be given
+to the native build system to choose a compiler toolchain.
+If the user specifies a platform name (e.g. via the :manual:`cmake(1)` ``-A``
+option or via the :envvar:`CMAKE_GENERATOR_PLATFORM` environment variable)
+the value will be available in this variable.
+
+The value of this variable should never be modified by project code.
+A toolchain file specified by the :variable:`CMAKE_TOOLCHAIN_FILE`
+variable may initialize ``CMAKE_GENERATOR_PLATFORM``. Once a given
+build tree has been initialized with a particular value for this
+variable, changing the value has undefined behavior.
+
+Platform specification is supported only on specific generators:
+
+* For :ref:`Visual Studio Generators` with VS 2005 and above this
+ specifies the target architecture.
+
+* For :generator:`Green Hills MULTI` this specifies the target architecture.
+
+See native build system documentation for allowed platform names.
+
+Visual Studio Platform Selection
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+On :ref:`Visual Studio Generators` the selected platform name
+is provided in the :variable:`CMAKE_VS_PLATFORM_NAME` variable.
diff --git a/Help/variable/CMAKE_GENERATOR_TOOLSET.rst b/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
new file mode 100644
index 0000000..45f2d32
--- /dev/null
+++ b/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
@@ -0,0 +1,89 @@
+CMAKE_GENERATOR_TOOLSET
+-----------------------
+
+Native build system toolset specification provided by user.
+
+Some CMake generators support a toolset specification to tell the
+native build system how to choose a compiler. If the user specifies
+a toolset (e.g. via the :manual:`cmake(1)` ``-T`` option or via
+the :envvar:`CMAKE_GENERATOR_TOOLSET` environment variable) the value
+will be available in this variable.
+
+The value of this variable should never be modified by project code.
+A toolchain file specified by the :variable:`CMAKE_TOOLCHAIN_FILE`
+variable may initialize ``CMAKE_GENERATOR_TOOLSET``. Once a given
+build tree has been initialized with a particular value for this
+variable, changing the value has undefined behavior.
+
+Toolset specification is supported only on specific generators:
+
+* :ref:`Visual Studio Generators` for VS 2010 and above
+* The :generator:`Xcode` generator for Xcode 3.0 and above
+* The :generator:`Green Hills MULTI` generator
+
+See native build system documentation for allowed toolset names.
+
+Visual Studio Toolset Selection
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The :ref:`Visual Studio Generators` support toolset specification
+using one of these forms:
+
+* ``toolset``
+* ``toolset[,key=value]*``
+* ``key=value[,key=value]*``
+
+The ``toolset`` specifies the toolset name. The selected toolset name
+is provided in the :variable:`CMAKE_VS_PLATFORM_TOOLSET` variable.
+
+The ``key=value`` pairs form a comma-separated list of options to
+specify generator-specific details of the toolset selection.
+Supported pairs are:
+
+``cuda=<version>|<path>``
+ Specify the CUDA toolkit version to use or the path to a
+ standalone CUDA toolkit directory. Supported by VS 2010
+ and above. The version can only be used with the CUDA
+ toolkit VS integration globally installed.
+ See the :variable:`CMAKE_VS_PLATFORM_TOOLSET_CUDA` and
+ :variable:`CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR` variables.
+
+``host=<arch>``
+ Specify the host tools architecture as ``x64`` or ``x86``.
+ Supported by VS 2013 and above.
+ See the :variable:`CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE`
+ variable.
+
+``version=<version>``
+ Specify the toolset version to use. Supported by VS 2017
+ and above with the specified toolset installed.
+ See the :variable:`CMAKE_VS_PLATFORM_TOOLSET_VERSION` variable.
+
+``VCTargetsPath=<path>``
+ Specify an alternative ``VCTargetsPath`` value for Visual Studio
+ project files. This allows use of VS platform extension configuration
+ files (``.props`` and ``.targets``) that are not installed with VS.
+
+Visual Studio Toolset Customization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+**These are unstable interfaces with no compatibility guarantees**
+because they hook into undocumented internal CMake implementation details.
+Institutions may use these to internally maintain support for non-public
+Visual Studio platforms and toolsets, but must accept responsibility to
+make updates as changes are made to CMake.
+
+Additional ``key=value`` pairs are available:
+
+``customFlagTableDir=<path>``
+ .. versionadded:: 3.21
+
+ Specify the absolute path to a directory from which to load custom
+ flag tables stored as JSON documents with file names of the form
+ ``<platform>_<toolset>_<tool>.json`` or ``<platform>_<tool>.json``,
+ where ``<platform>`` is the :variable:`CMAKE_VS_PLATFORM_NAME`,
+ ``<toolset>`` is the :variable:`CMAKE_VS_PLATFORM_TOOLSET`,
+ and ``<tool>`` is the tool for which the flag table is meant.
+ **This naming pattern is an internal CMake implementation detail.**
+ The ``<tool>`` names are undocumented. The format of the ``.json``
+ flag table files is undocumented.
diff --git a/Help/variable/CMAKE_GHS_NO_SOURCE_GROUP_FILE.rst b/Help/variable/CMAKE_GHS_NO_SOURCE_GROUP_FILE.rst
new file mode 100644
index 0000000..0e8ae5e
--- /dev/null
+++ b/Help/variable/CMAKE_GHS_NO_SOURCE_GROUP_FILE.rst
@@ -0,0 +1,8 @@
+CMAKE_GHS_NO_SOURCE_GROUP_FILE
+------------------------------
+
+.. versionadded:: 3.14
+
+``ON`` / ``OFF`` boolean to control if the project file for a target should
+be one single file or multiple files. Refer to
+:prop_tgt:`GHS_NO_SOURCE_GROUP_FILE` for further details.
diff --git a/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst b/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst
new file mode 100644
index 0000000..96e9907
--- /dev/null
+++ b/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst
@@ -0,0 +1,28 @@
+CMAKE_GLOBAL_AUTOGEN_TARGET
+---------------------------
+
+.. versionadded:: 3.14
+
+Switch to enable generation of a global ``autogen`` target.
+
+When :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET` is enabled, a custom target
+``autogen`` is generated. This target depends on all :prop_tgt:`AUTOMOC` and
+:prop_tgt:`AUTOUIC` generated ``<ORIGIN>_autogen`` targets in the project.
+By building the global ``autogen`` target, all :prop_tgt:`AUTOMOC` and
+:prop_tgt:`AUTOUIC` files in the project will be generated.
+
+The name of the global ``autogen`` target can be changed by setting
+:variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME`.
+
+By default :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET` is unset.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
+
+Note
+^^^^
+
+``<ORIGIN>_autogen`` targets by default inherit their origin target's
+dependencies. This might result in unintended dependency target
+builds when only ``<ORIGIN>_autogen`` targets are built. A solution is to
+disable :prop_tgt:`AUTOGEN_ORIGIN_DEPENDS` on the respective origin targets.
diff --git a/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET_NAME.rst b/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET_NAME.rst
new file mode 100644
index 0000000..4af4bc3
--- /dev/null
+++ b/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET_NAME.rst
@@ -0,0 +1,15 @@
+CMAKE_GLOBAL_AUTOGEN_TARGET_NAME
+--------------------------------
+
+.. versionadded:: 3.14
+
+Change the name of the global ``autogen`` target.
+
+When :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET` is enabled, a global custom target
+named ``autogen`` is created. :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME`
+allows to set a different name for that target.
+
+By default :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME` is unset.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET.rst b/Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET.rst
new file mode 100644
index 0000000..efea5be
--- /dev/null
+++ b/Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET.rst
@@ -0,0 +1,20 @@
+CMAKE_GLOBAL_AUTORCC_TARGET
+---------------------------
+
+.. versionadded:: 3.14
+
+Switch to enable generation of a global ``autorcc`` target.
+
+When :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` is enabled, a custom target
+``autorcc`` is generated. This target depends on all :prop_tgt:`AUTORCC`
+generated ``<ORIGIN>_arcc_<QRC>`` targets in the project.
+By building the global ``autorcc`` target, all :prop_tgt:`AUTORCC`
+files in the project will be generated.
+
+The name of the global ``autorcc`` target can be changed by setting
+:variable:`CMAKE_GLOBAL_AUTORCC_TARGET_NAME`.
+
+By default :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` is unset.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET_NAME.rst b/Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET_NAME.rst
new file mode 100644
index 0000000..4d2e313
--- /dev/null
+++ b/Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET_NAME.rst
@@ -0,0 +1,15 @@
+CMAKE_GLOBAL_AUTORCC_TARGET_NAME
+--------------------------------
+
+.. versionadded:: 3.14
+
+Change the name of the global ``autorcc`` target.
+
+When :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` is enabled, a global custom target
+named ``autorcc`` is created. :variable:`CMAKE_GLOBAL_AUTORCC_TARGET_NAME`
+allows to set a different name for that target.
+
+By default :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME` is unset.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/variable/CMAKE_GNUtoMS.rst b/Help/variable/CMAKE_GNUtoMS.rst
new file mode 100644
index 0000000..9c0f59e
--- /dev/null
+++ b/Help/variable/CMAKE_GNUtoMS.rst
@@ -0,0 +1,8 @@
+CMAKE_GNUtoMS
+-------------
+
+Convert GNU import libraries (``.dll.a``) to MS format (``.lib``).
+
+This variable is used to initialize the :prop_tgt:`GNUtoMS` property on
+targets when they are created. See that target property for additional
+information.
diff --git a/Help/variable/CMAKE_HOME_DIRECTORY.rst b/Help/variable/CMAKE_HOME_DIRECTORY.rst
new file mode 100644
index 0000000..b03d956
--- /dev/null
+++ b/Help/variable/CMAKE_HOME_DIRECTORY.rst
@@ -0,0 +1,9 @@
+CMAKE_HOME_DIRECTORY
+--------------------
+
+Path to top of source tree. Same as :variable:`CMAKE_SOURCE_DIR`.
+
+This is an internal cache entry used to locate the source directory
+when loading a ``CMakeCache.txt`` from a build tree. It should not
+be used in project code. The variable :variable:`CMAKE_SOURCE_DIR`
+has the same value and should be preferred.
diff --git a/Help/variable/CMAKE_HOST_APPLE.rst b/Help/variable/CMAKE_HOST_APPLE.rst
new file mode 100644
index 0000000..9c205ec
--- /dev/null
+++ b/Help/variable/CMAKE_HOST_APPLE.rst
@@ -0,0 +1,6 @@
+CMAKE_HOST_APPLE
+----------------
+
+``True`` for Apple macOS operating systems.
+
+Set to ``true`` when the host system is Apple macOS.
diff --git a/Help/variable/CMAKE_HOST_SOLARIS.rst b/Help/variable/CMAKE_HOST_SOLARIS.rst
new file mode 100644
index 0000000..7054acd
--- /dev/null
+++ b/Help/variable/CMAKE_HOST_SOLARIS.rst
@@ -0,0 +1,8 @@
+CMAKE_HOST_SOLARIS
+------------------
+
+.. versionadded:: 3.6
+
+``True`` for Oracle Solaris operating systems.
+
+Set to ``true`` when the host system is Oracle Solaris.
diff --git a/Help/variable/CMAKE_HOST_SYSTEM.rst b/Help/variable/CMAKE_HOST_SYSTEM.rst
new file mode 100644
index 0000000..12d11d1
--- /dev/null
+++ b/Help/variable/CMAKE_HOST_SYSTEM.rst
@@ -0,0 +1,10 @@
+CMAKE_HOST_SYSTEM
+-----------------
+
+Composite Name of OS CMake is being run on.
+
+This variable is the composite of :variable:`CMAKE_HOST_SYSTEM_NAME` and
+:variable:`CMAKE_HOST_SYSTEM_VERSION`, e.g.
+``${CMAKE_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_VERSION}``. If
+:variable:`CMAKE_HOST_SYSTEM_VERSION` is not set, then this variable is
+the same as :variable:`CMAKE_HOST_SYSTEM_NAME`.
diff --git a/Help/variable/CMAKE_HOST_SYSTEM_NAME.rst b/Help/variable/CMAKE_HOST_SYSTEM_NAME.rst
new file mode 100644
index 0000000..e892677
--- /dev/null
+++ b/Help/variable/CMAKE_HOST_SYSTEM_NAME.rst
@@ -0,0 +1,8 @@
+CMAKE_HOST_SYSTEM_NAME
+----------------------
+
+Name of the OS CMake is running on.
+
+On systems that have the uname command, this variable is set to the
+output of ``uname -s``. ``Linux``, ``Windows``, and ``Darwin`` for macOS
+are the values found on the big three operating systems.
diff --git a/Help/variable/CMAKE_HOST_SYSTEM_PROCESSOR.rst b/Help/variable/CMAKE_HOST_SYSTEM_PROCESSOR.rst
new file mode 100644
index 0000000..c305779
--- /dev/null
+++ b/Help/variable/CMAKE_HOST_SYSTEM_PROCESSOR.rst
@@ -0,0 +1,42 @@
+CMAKE_HOST_SYSTEM_PROCESSOR
+---------------------------
+
+The name of the CPU CMake is running on.
+
+Windows Platforms
+^^^^^^^^^^^^^^^^^
+
+On Windows, this variable is set to the value of the environment variable
+``PROCESSOR_ARCHITECTURE``.
+
+Unix Platforms
+^^^^^^^^^^^^^^
+
+On systems that support ``uname``, this variable is set to the output of:
+
+- ``uname -m`` on GNU, Linux, Cygwin, Android, or
+- ``arch`` on OpenBSD, or
+- on other systems,
+
+ * ``uname -p`` if its exit code is nonzero, or
+ * ``uname -m`` otherwise.
+
+macOS Platforms
+^^^^^^^^^^^^^^^
+
+The value of ``uname -m`` is used by default.
+
+On Apple Silicon hosts, the architecture printed by ``uname -m`` may vary
+based on CMake's own architecture and that of the invoking process tree.
+
+.. versionadded:: 3.19.2
+
+ On Apple Silicon hosts:
+
+ * The :variable:`CMAKE_APPLE_SILICON_PROCESSOR` variable or
+ the :envvar:`CMAKE_APPLE_SILICON_PROCESSOR` environment variable
+ may be set to specify the host architecture explicitly.
+
+ * If :variable:`CMAKE_OSX_ARCHITECTURES` is not set, CMake adds explicit
+ flags to tell the compiler to build for the host architecture so the
+ toolchain does not have to guess based on the process tree's architecture.
diff --git a/Help/variable/CMAKE_HOST_SYSTEM_VERSION.rst b/Help/variable/CMAKE_HOST_SYSTEM_VERSION.rst
new file mode 100644
index 0000000..ed23070
--- /dev/null
+++ b/Help/variable/CMAKE_HOST_SYSTEM_VERSION.rst
@@ -0,0 +1,8 @@
+CMAKE_HOST_SYSTEM_VERSION
+-------------------------
+
+The OS version CMake is running on.
+
+A numeric version string for the system. On systems that support
+``uname``, this variable is set to the output of ``uname -r``. On other
+systems this is set to major-minor version numbers.
diff --git a/Help/variable/CMAKE_HOST_UNIX.rst b/Help/variable/CMAKE_HOST_UNIX.rst
new file mode 100644
index 0000000..817a957
--- /dev/null
+++ b/Help/variable/CMAKE_HOST_UNIX.rst
@@ -0,0 +1,7 @@
+CMAKE_HOST_UNIX
+---------------
+
+``True`` for UNIX and UNIX like operating systems.
+
+Set to ``true`` when the host system is UNIX or UNIX like (i.e. APPLE and
+CYGWIN).
diff --git a/Help/variable/CMAKE_HOST_WIN32.rst b/Help/variable/CMAKE_HOST_WIN32.rst
new file mode 100644
index 0000000..876b34c
--- /dev/null
+++ b/Help/variable/CMAKE_HOST_WIN32.rst
@@ -0,0 +1,6 @@
+CMAKE_HOST_WIN32
+----------------
+
+``True`` if the host system is running Windows, including Windows 64-bit and MSYS.
+
+Set to ``false`` on Cygwin.
diff --git a/Help/variable/CMAKE_IGNORE_PATH.rst b/Help/variable/CMAKE_IGNORE_PATH.rst
new file mode 100644
index 0000000..4bca34b
--- /dev/null
+++ b/Help/variable/CMAKE_IGNORE_PATH.rst
@@ -0,0 +1,18 @@
+CMAKE_IGNORE_PATH
+-----------------
+
+:ref:`Semicolon-separated list <CMake Language Lists>` of directories to be *ignored* by
+the :command:`find_program`, :command:`find_library`, :command:`find_file`,
+and :command:`find_path` commands. This is useful in cross-compiling
+environments where some system directories contain incompatible but
+possibly linkable libraries. For example, on cross-compiled cluster
+environments, this allows a user to ignore directories containing
+libraries meant for the front-end machine.
+
+By default this is empty; it is intended to be set by the project.
+Note that ``CMAKE_IGNORE_PATH`` takes a list of directory names, *not*
+a list of prefixes. To ignore paths under prefixes (``bin``, ``include``,
+``lib``, etc.), specify them explicitly.
+
+See also the :variable:`CMAKE_PREFIX_PATH`, :variable:`CMAKE_LIBRARY_PATH`,
+:variable:`CMAKE_INCLUDE_PATH`, and :variable:`CMAKE_PROGRAM_PATH` variables.
diff --git a/Help/variable/CMAKE_IMPORT_LIBRARY_PREFIX.rst b/Help/variable/CMAKE_IMPORT_LIBRARY_PREFIX.rst
new file mode 100644
index 0000000..1561a1d
--- /dev/null
+++ b/Help/variable/CMAKE_IMPORT_LIBRARY_PREFIX.rst
@@ -0,0 +1,9 @@
+CMAKE_IMPORT_LIBRARY_PREFIX
+---------------------------
+
+The prefix for import libraries that you link to.
+
+The prefix to use for the name of an import library if used on this
+platform.
+
+``CMAKE_IMPORT_LIBRARY_PREFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_IMPORT_LIBRARY_SUFFIX.rst b/Help/variable/CMAKE_IMPORT_LIBRARY_SUFFIX.rst
new file mode 100644
index 0000000..11aeab7
--- /dev/null
+++ b/Help/variable/CMAKE_IMPORT_LIBRARY_SUFFIX.rst
@@ -0,0 +1,9 @@
+CMAKE_IMPORT_LIBRARY_SUFFIX
+---------------------------
+
+The suffix for import libraries that you link to.
+
+The suffix to use for the end of an import library filename if used on
+this platform.
+
+``CMAKE_IMPORT_LIBRARY_SUFFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_INCLUDE_CURRENT_DIR.rst b/Help/variable/CMAKE_INCLUDE_CURRENT_DIR.rst
new file mode 100644
index 0000000..98d99eb
--- /dev/null
+++ b/Help/variable/CMAKE_INCLUDE_CURRENT_DIR.rst
@@ -0,0 +1,13 @@
+CMAKE_INCLUDE_CURRENT_DIR
+-------------------------
+
+Automatically add the current source and build directories to the include path.
+
+If this variable is enabled, CMake automatically adds
+:variable:`CMAKE_CURRENT_SOURCE_DIR` and :variable:`CMAKE_CURRENT_BINARY_DIR`
+to the include path for each directory. These additional include
+directories do not propagate down to subdirectories. This is useful
+mainly for out-of-source builds, where files generated into the build
+tree are included by files located in the source tree.
+
+By default ``CMAKE_INCLUDE_CURRENT_DIR`` is ``OFF``.
diff --git a/Help/variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE.rst b/Help/variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE.rst
new file mode 100644
index 0000000..697682b
--- /dev/null
+++ b/Help/variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE.rst
@@ -0,0 +1,12 @@
+CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE
+--------------------------------------
+
+Automatically add the current source and build directories to the
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target property.
+
+If this variable is enabled, CMake automatically adds for each shared
+library target, static library target, module target and executable
+target, :variable:`CMAKE_CURRENT_SOURCE_DIR` and
+:variable:`CMAKE_CURRENT_BINARY_DIR` to
+the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target property. By default
+``CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE`` is ``OFF``.
diff --git a/Help/variable/CMAKE_INCLUDE_DIRECTORIES_BEFORE.rst b/Help/variable/CMAKE_INCLUDE_DIRECTORIES_BEFORE.rst
new file mode 100644
index 0000000..e0f2a2e
--- /dev/null
+++ b/Help/variable/CMAKE_INCLUDE_DIRECTORIES_BEFORE.rst
@@ -0,0 +1,9 @@
+CMAKE_INCLUDE_DIRECTORIES_BEFORE
+--------------------------------
+
+Whether to append or prepend directories by default in
+:command:`include_directories`.
+
+This variable affects the default behavior of the :command:`include_directories`
+command. Setting this variable to ``ON`` is equivalent to using the ``BEFORE``
+option in all uses of that command.
diff --git a/Help/variable/CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE.rst b/Help/variable/CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE.rst
new file mode 100644
index 0000000..37d0a3d
--- /dev/null
+++ b/Help/variable/CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE.rst
@@ -0,0 +1,8 @@
+CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE
+----------------------------------------
+
+Whether to force prepending of project include directories.
+
+This variable affects the order of include directories generated in compiler
+command lines. If set to ``ON``, it causes the :variable:`CMAKE_SOURCE_DIR`
+and the :variable:`CMAKE_BINARY_DIR` to appear first.
diff --git a/Help/variable/CMAKE_INCLUDE_PATH.rst b/Help/variable/CMAKE_INCLUDE_PATH.rst
new file mode 100644
index 0000000..4918e99
--- /dev/null
+++ b/Help/variable/CMAKE_INCLUDE_PATH.rst
@@ -0,0 +1,7 @@
+CMAKE_INCLUDE_PATH
+------------------
+
+:ref:`Semicolon-separated list <CMake Language Lists>` of directories specifying a search path
+for the :command:`find_file` and :command:`find_path` commands. By default it
+is empty, it is intended to be set by the project. See also
+:variable:`CMAKE_SYSTEM_INCLUDE_PATH` and :variable:`CMAKE_PREFIX_PATH`.
diff --git a/Help/variable/CMAKE_INSTALL_DEFAULT_COMPONENT_NAME.rst b/Help/variable/CMAKE_INSTALL_DEFAULT_COMPONENT_NAME.rst
new file mode 100644
index 0000000..57160f1
--- /dev/null
+++ b/Help/variable/CMAKE_INSTALL_DEFAULT_COMPONENT_NAME.rst
@@ -0,0 +1,9 @@
+CMAKE_INSTALL_DEFAULT_COMPONENT_NAME
+------------------------------------
+
+Default component used in :command:`install` commands.
+
+If an :command:`install` command is used without the ``COMPONENT`` argument,
+these files will be grouped into a default component. The name of this
+default install component will be taken from this variable. It
+defaults to ``Unspecified``.
diff --git a/Help/variable/CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS.rst b/Help/variable/CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS.rst
new file mode 100644
index 0000000..aad99e4
--- /dev/null
+++ b/Help/variable/CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS.rst
@@ -0,0 +1,31 @@
+CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
+-------------------------------------------
+
+.. versionadded:: 3.11
+
+Default permissions for directories created implicitly during installation
+of files by :command:`install` and :command:`file(INSTALL)`.
+
+If ``make install`` is invoked and directories are implicitly created they
+get permissions set by :variable:`CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS`
+variable or platform specific default permissions if the variable is not set.
+
+Implicitly created directories are created if they are not explicitly installed
+by :command:`install` command but are needed to install a file on a certain
+path. Example of such locations are directories created due to the setting of
+:variable:`CMAKE_INSTALL_PREFIX`.
+
+Expected content of the :variable:`CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS`
+variable is a list of permissions that can be used by :command:`install` command
+`PERMISSIONS` section.
+
+Example usage:
+
+::
+
+ set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
+ OWNER_READ
+ OWNER_WRITE
+ OWNER_EXECUTE
+ GROUP_READ
+ )
diff --git a/Help/variable/CMAKE_INSTALL_MESSAGE.rst b/Help/variable/CMAKE_INSTALL_MESSAGE.rst
new file mode 100644
index 0000000..4f39cfe
--- /dev/null
+++ b/Help/variable/CMAKE_INSTALL_MESSAGE.rst
@@ -0,0 +1,32 @@
+CMAKE_INSTALL_MESSAGE
+---------------------
+
+.. versionadded:: 3.1
+
+Specify verbosity of installation script code generated by the
+:command:`install` command (using the :command:`file(INSTALL)` command).
+For paths that are newly installed or updated, installation
+may print lines like::
+
+ -- Installing: /some/destination/path
+
+For paths that are already up to date, installation may print
+lines like::
+
+ -- Up-to-date: /some/destination/path
+
+The ``CMAKE_INSTALL_MESSAGE`` variable may be set to control
+which messages are printed:
+
+``ALWAYS``
+ Print both ``Installing`` and ``Up-to-date`` messages.
+
+``LAZY``
+ Print ``Installing`` but not ``Up-to-date`` messages.
+
+``NEVER``
+ Print neither ``Installing`` nor ``Up-to-date`` messages.
+
+Other values have undefined behavior and may not be diagnosed.
+
+If this variable is not set, the default behavior is ``ALWAYS``.
diff --git a/Help/variable/CMAKE_INSTALL_NAME_DIR.rst b/Help/variable/CMAKE_INSTALL_NAME_DIR.rst
new file mode 100644
index 0000000..b07d44f
--- /dev/null
+++ b/Help/variable/CMAKE_INSTALL_NAME_DIR.rst
@@ -0,0 +1,8 @@
+CMAKE_INSTALL_NAME_DIR
+----------------------
+
+Directory name for installed targets on Apple platforms.
+
+``CMAKE_INSTALL_NAME_DIR`` is used to initialize the
+:prop_tgt:`INSTALL_NAME_DIR` property on all targets. See that target
+property for more information.
diff --git a/Help/variable/CMAKE_INSTALL_PREFIX.rst b/Help/variable/CMAKE_INSTALL_PREFIX.rst
new file mode 100644
index 0000000..02ba645
--- /dev/null
+++ b/Help/variable/CMAKE_INSTALL_PREFIX.rst
@@ -0,0 +1,23 @@
+CMAKE_INSTALL_PREFIX
+--------------------
+
+Install directory used by :command:`install`.
+
+If ``make install`` is invoked or ``INSTALL`` is built, this directory is
+prepended onto all install directories. This variable defaults to
+``/usr/local`` on UNIX and ``c:/Program Files/${PROJECT_NAME}`` on Windows.
+See :variable:`CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT` for how a
+project might choose its own default.
+
+On UNIX one can use the ``DESTDIR`` mechanism in order to relocate the
+whole installation. See :envvar:`DESTDIR` for more information.
+
+The installation prefix is also added to :variable:`CMAKE_SYSTEM_PREFIX_PATH`
+so that :command:`find_package`, :command:`find_program`,
+:command:`find_library`, :command:`find_path`, and :command:`find_file`
+will search the prefix for other software.
+
+.. note::
+
+ Use the :module:`GNUInstallDirs` module to provide GNU-style
+ options for the layout of directories within the installation.
diff --git a/Help/variable/CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT.rst b/Help/variable/CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT.rst
new file mode 100644
index 0000000..93cc319
--- /dev/null
+++ b/Help/variable/CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT.rst
@@ -0,0 +1,16 @@
+CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
+-------------------------------------------
+
+.. versionadded:: 3.7.1
+
+CMake sets this variable to a ``TRUE`` value when the
+:variable:`CMAKE_INSTALL_PREFIX` has just been initialized to
+its default value, typically on the first run of CMake within
+a new build tree. This can be used by project code to change
+the default without overriding a user-provided value:
+
+.. code-block:: cmake
+
+ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX "/my/default" CACHE PATH "..." FORCE)
+ endif()
diff --git a/Help/variable/CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH.rst b/Help/variable/CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH.rst
new file mode 100644
index 0000000..c86e433
--- /dev/null
+++ b/Help/variable/CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH.rst
@@ -0,0 +1,11 @@
+CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH
+--------------------------------------
+
+.. versionadded:: 3.16
+
+Sets the default for whether toolchain-defined rpaths should be removed during
+installation.
+
+``CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH`` is a boolean that provides the
+default value for the :prop_tgt:`INSTALL_REMOVE_ENVIRONMENT_RPATH` property
+of all subsequently created targets.
diff --git a/Help/variable/CMAKE_INSTALL_RPATH.rst b/Help/variable/CMAKE_INSTALL_RPATH.rst
new file mode 100644
index 0000000..813d1e0
--- /dev/null
+++ b/Help/variable/CMAKE_INSTALL_RPATH.rst
@@ -0,0 +1,8 @@
+CMAKE_INSTALL_RPATH
+-------------------
+
+The rpath to use for installed targets.
+
+A semicolon-separated list specifying the rpath to use in installed
+targets (for platforms that support it). This is used to initialize
+the target property :prop_tgt:`INSTALL_RPATH` for all targets.
diff --git a/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst b/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst
new file mode 100644
index 0000000..34524d1
--- /dev/null
+++ b/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst
@@ -0,0 +1,13 @@
+CMAKE_INSTALL_RPATH_USE_LINK_PATH
+---------------------------------
+
+Add paths to linker search and installed rpath.
+
+``CMAKE_INSTALL_RPATH_USE_LINK_PATH`` is a boolean that if set to ``True``
+will append to the runtime search path (rpath) of installed binaries
+any directories outside the project that are in the linker search path or
+contain linked library files. The directories are appended after the
+value of the :prop_tgt:`INSTALL_RPATH` target property.
+
+This variable is used to initialize the target property
+:prop_tgt:`INSTALL_RPATH_USE_LINK_PATH` for all targets.
diff --git a/Help/variable/CMAKE_INTERNAL_PLATFORM_ABI.rst b/Help/variable/CMAKE_INTERNAL_PLATFORM_ABI.rst
new file mode 100644
index 0000000..9693bf6
--- /dev/null
+++ b/Help/variable/CMAKE_INTERNAL_PLATFORM_ABI.rst
@@ -0,0 +1,6 @@
+CMAKE_INTERNAL_PLATFORM_ABI
+---------------------------
+
+An internal variable subject to change.
+
+This is used in determining the compiler ABI and is subject to change.
diff --git a/Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION.rst b/Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION.rst
new file mode 100644
index 0000000..cf7da76
--- /dev/null
+++ b/Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION.rst
@@ -0,0 +1,10 @@
+CMAKE_INTERPROCEDURAL_OPTIMIZATION
+----------------------------------
+
+.. versionadded:: 3.9
+
+Default value for :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` of targets.
+
+This variable is used to initialize the :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION`
+property on all the targets. See that target property for additional
+information.
diff --git a/Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst b/Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
new file mode 100644
index 0000000..5b3ee77
--- /dev/null
+++ b/Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
@@ -0,0 +1,10 @@
+CMAKE_INTERPROCEDURAL_OPTIMIZATION_<CONFIG>
+-------------------------------------------
+
+.. versionadded:: 3.9
+
+Default value for :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION_<CONFIG>` of targets.
+
+This variable is used to initialize the :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION_<CONFIG>`
+property on all the targets. See that target property for additional
+information.
diff --git a/Help/variable/CMAKE_IOS_INSTALL_COMBINED.rst b/Help/variable/CMAKE_IOS_INSTALL_COMBINED.rst
new file mode 100644
index 0000000..cd7fd8d
--- /dev/null
+++ b/Help/variable/CMAKE_IOS_INSTALL_COMBINED.rst
@@ -0,0 +1,10 @@
+CMAKE_IOS_INSTALL_COMBINED
+--------------------------
+
+.. versionadded:: 3.5
+
+Default value for :prop_tgt:`IOS_INSTALL_COMBINED` of targets.
+
+This variable is used to initialize the :prop_tgt:`IOS_INSTALL_COMBINED`
+property on all the targets. See that target property for additional
+information.
diff --git a/Help/variable/CMAKE_ISPC_HEADER_DIRECTORY.rst b/Help/variable/CMAKE_ISPC_HEADER_DIRECTORY.rst
new file mode 100644
index 0000000..a7c9cf6
--- /dev/null
+++ b/Help/variable/CMAKE_ISPC_HEADER_DIRECTORY.rst
@@ -0,0 +1,10 @@
+CMAKE_ISPC_HEADER_DIRECTORY
+----------------------------
+
+.. versionadded:: 3.19
+
+ISPC generated header output directory.
+
+This variable is used to initialize the :prop_tgt:`ISPC_HEADER_DIRECTORY`
+property on all the targets. See the target property for additional
+information.
diff --git a/Help/variable/CMAKE_ISPC_HEADER_SUFFIX.rst b/Help/variable/CMAKE_ISPC_HEADER_SUFFIX.rst
new file mode 100644
index 0000000..c9fb709
--- /dev/null
+++ b/Help/variable/CMAKE_ISPC_HEADER_SUFFIX.rst
@@ -0,0 +1,10 @@
+CMAKE_ISPC_HEADER_SUFFIX
+------------------------
+
+.. versionadded:: 3.19.2
+
+Output suffix to be used for ISPC generated headers.
+
+This variable is used to initialize the :prop_tgt:`ISPC_HEADER_SUFFIX`
+property on all the targets. See the target property for additional
+information.
diff --git a/Help/variable/CMAKE_ISPC_INSTRUCTION_SETS.rst b/Help/variable/CMAKE_ISPC_INSTRUCTION_SETS.rst
new file mode 100644
index 0000000..8a6005e
--- /dev/null
+++ b/Help/variable/CMAKE_ISPC_INSTRUCTION_SETS.rst
@@ -0,0 +1,9 @@
+CMAKE_ISPC_INSTRUCTION_SETS
+---------------------------
+
+.. versionadded:: 3.19
+
+Default value for :prop_tgt:`ISPC_INSTRUCTION_SETS` property of targets.
+
+This variable is used to initialize the :prop_tgt:`ISPC_INSTRUCTION_SETS` property
+on all targets. See the target property for additional information.
diff --git a/Help/variable/CMAKE_JOB_POOLS.rst b/Help/variable/CMAKE_JOB_POOLS.rst
new file mode 100644
index 0000000..43d3c84
--- /dev/null
+++ b/Help/variable/CMAKE_JOB_POOLS.rst
@@ -0,0 +1,8 @@
+CMAKE_JOB_POOLS
+---------------
+
+.. versionadded:: 3.11
+
+If the :prop_gbl:`JOB_POOLS` global property is not set, the value
+of this variable is used in its place. See :prop_gbl:`JOB_POOLS`
+for additional information.
diff --git a/Help/variable/CMAKE_JOB_POOL_COMPILE.rst b/Help/variable/CMAKE_JOB_POOL_COMPILE.rst
new file mode 100644
index 0000000..e5c2d9a
--- /dev/null
+++ b/Help/variable/CMAKE_JOB_POOL_COMPILE.rst
@@ -0,0 +1,6 @@
+CMAKE_JOB_POOL_COMPILE
+----------------------
+
+This variable is used to initialize the :prop_tgt:`JOB_POOL_COMPILE`
+property on all the targets. See :prop_tgt:`JOB_POOL_COMPILE`
+for additional information.
diff --git a/Help/variable/CMAKE_JOB_POOL_LINK.rst b/Help/variable/CMAKE_JOB_POOL_LINK.rst
new file mode 100644
index 0000000..eeee6e0
--- /dev/null
+++ b/Help/variable/CMAKE_JOB_POOL_LINK.rst
@@ -0,0 +1,6 @@
+CMAKE_JOB_POOL_LINK
+-------------------
+
+This variable is used to initialize the :prop_tgt:`JOB_POOL_LINK`
+property on all the targets. See :prop_tgt:`JOB_POOL_LINK`
+for additional information.
diff --git a/Help/variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER.rst b/Help/variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER.rst
new file mode 100644
index 0000000..1a6f66a
--- /dev/null
+++ b/Help/variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER.rst
@@ -0,0 +1,8 @@
+CMAKE_JOB_POOL_PRECOMPILE_HEADER
+--------------------------------
+
+.. versionadded:: 3.17
+
+This variable is used to initialize the :prop_tgt:`JOB_POOL_PRECOMPILE_HEADER`
+property on all the targets. See :prop_tgt:`JOB_POOL_PRECOMPILE_HEADER`
+for additional information.
diff --git a/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_MACHINE.rst b/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_MACHINE.rst
new file mode 100644
index 0000000..f539277
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_MACHINE.rst
@@ -0,0 +1,11 @@
+CMAKE_<LANG>_ANDROID_TOOLCHAIN_MACHINE
+--------------------------------------
+
+.. versionadded:: 3.7.1
+
+When :ref:`Cross Compiling for Android` this variable contains the
+toolchain binutils machine name (e.g. ``gcc -dumpmachine``). The
+binutils typically have a ``<machine>-`` prefix on their name.
+
+See also :variable:`CMAKE_<LANG>_ANDROID_TOOLCHAIN_PREFIX`
+and :variable:`CMAKE_<LANG>_ANDROID_TOOLCHAIN_SUFFIX`.
diff --git a/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX.rst b/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX.rst
new file mode 100644
index 0000000..ff072ca
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX.rst
@@ -0,0 +1,14 @@
+CMAKE_<LANG>_ANDROID_TOOLCHAIN_PREFIX
+-------------------------------------
+
+.. versionadded:: 3.7
+
+When :ref:`Cross Compiling for Android` this variable contains the absolute
+path prefixing the toolchain GNU compiler and its binutils.
+
+See also :variable:`CMAKE_<LANG>_ANDROID_TOOLCHAIN_SUFFIX`
+and :variable:`CMAKE_<LANG>_ANDROID_TOOLCHAIN_MACHINE`.
+
+For example, the path to the linker is::
+
+ ${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}ld${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}
diff --git a/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX.rst b/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX.rst
new file mode 100644
index 0000000..d595280
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX.rst
@@ -0,0 +1,10 @@
+CMAKE_<LANG>_ANDROID_TOOLCHAIN_SUFFIX
+-------------------------------------
+
+.. versionadded:: 3.7
+
+When :ref:`Cross Compiling for Android` this variable contains the
+host platform suffix of the toolchain GNU compiler and its binutils.
+
+See also :variable:`CMAKE_<LANG>_ANDROID_TOOLCHAIN_PREFIX`
+and :variable:`CMAKE_<LANG>_ANDROID_TOOLCHAIN_MACHINE`.
diff --git a/Help/variable/CMAKE_LANG_ARCHIVE_APPEND.rst b/Help/variable/CMAKE_LANG_ARCHIVE_APPEND.rst
new file mode 100644
index 0000000..ab4ad71
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_ARCHIVE_APPEND.rst
@@ -0,0 +1,10 @@
+CMAKE_<LANG>_ARCHIVE_APPEND
+---------------------------
+
+Rule variable to append to a static archive.
+
+This is a rule variable that tells CMake how to append to a static
+archive. It is used in place of :variable:`CMAKE_<LANG>_CREATE_STATIC_LIBRARY`
+on some platforms in order to support large object counts. See also
+:variable:`CMAKE_<LANG>_ARCHIVE_CREATE` and
+:variable:`CMAKE_<LANG>_ARCHIVE_FINISH`.
diff --git a/Help/variable/CMAKE_LANG_ARCHIVE_CREATE.rst b/Help/variable/CMAKE_LANG_ARCHIVE_CREATE.rst
new file mode 100644
index 0000000..fc295af
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_ARCHIVE_CREATE.rst
@@ -0,0 +1,10 @@
+CMAKE_<LANG>_ARCHIVE_CREATE
+---------------------------
+
+Rule variable to create a new static archive.
+
+This is a rule variable that tells CMake how to create a static
+archive. It is used in place of :variable:`CMAKE_<LANG>_CREATE_STATIC_LIBRARY`
+on some platforms in order to support large object counts. See also
+:variable:`CMAKE_<LANG>_ARCHIVE_APPEND` and
+:variable:`CMAKE_<LANG>_ARCHIVE_FINISH`.
diff --git a/Help/variable/CMAKE_LANG_ARCHIVE_FINISH.rst b/Help/variable/CMAKE_LANG_ARCHIVE_FINISH.rst
new file mode 100644
index 0000000..1bb5d65
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_ARCHIVE_FINISH.rst
@@ -0,0 +1,10 @@
+CMAKE_<LANG>_ARCHIVE_FINISH
+---------------------------
+
+Rule variable to finish an existing static archive.
+
+This is a rule variable that tells CMake how to finish a static
+archive. It is used in place of :variable:`CMAKE_<LANG>_CREATE_STATIC_LIBRARY`
+on some platforms in order to support large object counts. See also
+:variable:`CMAKE_<LANG>_ARCHIVE_CREATE` and
+:variable:`CMAKE_<LANG>_ARCHIVE_APPEND`.
diff --git a/Help/variable/CMAKE_LANG_BYTE_ORDER.rst b/Help/variable/CMAKE_LANG_BYTE_ORDER.rst
new file mode 100644
index 0000000..78f0ae6
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_BYTE_ORDER.rst
@@ -0,0 +1,20 @@
+CMAKE_<LANG>_BYTE_ORDER
+-----------------------
+
+.. versionadded:: 3.20
+
+Byte order of ``<LANG>`` compiler target architecture, if known.
+If defined and not empty, the value is one of:
+
+``BIG_ENDIAN``
+ The target architecture is Big Endian.
+
+``LITTLE_ENDIAN``
+ The target architecture is Little Endian.
+
+This is defined for languages ``C``, ``CXX``, ``OBJC``, ``OBJCXX``,
+and ``CUDA``.
+
+If :variable:`CMAKE_OSX_ARCHITECTURES` specifies multiple architectures, the
+value of ``CMAKE_<LANG>_BYTE_ORDER`` is non-empty only if all architectures
+share the same byte order.
diff --git a/Help/variable/CMAKE_LANG_CLANG_TIDY.rst b/Help/variable/CMAKE_LANG_CLANG_TIDY.rst
new file mode 100644
index 0000000..32e27b0
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_CLANG_TIDY.rst
@@ -0,0 +1,15 @@
+CMAKE_<LANG>_CLANG_TIDY
+-----------------------
+
+.. versionadded:: 3.6
+
+Default value for :prop_tgt:`<LANG>_CLANG_TIDY` target property
+when ``<LANG>`` is ``C``, ``CXX``, ``OBJC`` or ``OBJCXX``.
+
+This variable is used to initialize the property on each target as it is
+created. For example:
+
+.. code-block:: cmake
+
+ set(CMAKE_CXX_CLANG_TIDY clang-tidy -checks=-*,readability-*)
+ add_executable(foo foo.cxx)
diff --git a/Help/variable/CMAKE_LANG_COMPILER.rst b/Help/variable/CMAKE_LANG_COMPILER.rst
new file mode 100644
index 0000000..e694b33
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_COMPILER.rst
@@ -0,0 +1,32 @@
+CMAKE_<LANG>_COMPILER
+---------------------
+
+The full path to the compiler for ``LANG``.
+
+This is the command that will be used as the ``<LANG>`` compiler. Once
+set, you can not change this variable.
+
+Usage
+^^^^^
+
+This variable can be set by the user during the first time a build tree is configured.
+
+If a non-full path value is supplied then CMake will resolve the full path of
+the compiler.
+
+The variable could be set in a user supplied toolchain file or via `-D` on the command line.
+
+.. note::
+ Options that are required to make the compiler work correctly can be included
+ as items in a list; they can not be changed.
+
+.. code-block:: cmake
+
+ #set within user supplied toolchain file
+ set(CMAKE_C_COMPILER /full/path/to/qcc --arg1 --arg2)
+
+or
+
+.. code-block:: console
+
+ $ cmake ... -DCMAKE_C_COMPILER='qcc;--arg1;--arg2'
diff --git a/Help/variable/CMAKE_LANG_COMPILER_ABI.rst b/Help/variable/CMAKE_LANG_COMPILER_ABI.rst
new file mode 100644
index 0000000..be946c0
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_COMPILER_ABI.rst
@@ -0,0 +1,6 @@
+CMAKE_<LANG>_COMPILER_ABI
+-------------------------
+
+An internal variable subject to change.
+
+This is used in determining the compiler ABI and is subject to change.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_AR.rst b/Help/variable/CMAKE_LANG_COMPILER_AR.rst
new file mode 100644
index 0000000..74f2758
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_COMPILER_AR.rst
@@ -0,0 +1,9 @@
+CMAKE_<LANG>_COMPILER_AR
+------------------------
+
+.. versionadded:: 3.9
+
+A wrapper around ``ar`` adding the appropriate ``--plugin`` option for the
+compiler.
+
+See also :variable:`CMAKE_AR`.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_ARCHITECTURE_ID.rst b/Help/variable/CMAKE_LANG_COMPILER_ARCHITECTURE_ID.rst
new file mode 100644
index 0000000..8057566
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_COMPILER_ARCHITECTURE_ID.rst
@@ -0,0 +1,10 @@
+CMAKE_<LANG>_COMPILER_ARCHITECTURE_ID
+-------------------------------------
+
+.. versionadded:: 3.10
+
+An internal variable subject to change.
+
+This is used to identify the variant of a compiler based on its target
+architecture. For some compilers this is needed to determine the correct
+usage.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN.rst b/Help/variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN.rst
new file mode 100644
index 0000000..cbe3544
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN.rst
@@ -0,0 +1,13 @@
+CMAKE_<LANG>_COMPILER_EXTERNAL_TOOLCHAIN
+----------------------------------------
+
+The external toolchain for cross-compiling, if supported.
+
+Some compiler toolchains do not ship their own auxiliary utilities such as
+archivers and linkers. The compiler driver may support a command-line argument
+to specify the location of such tools.
+``CMAKE_<LANG>_COMPILER_EXTERNAL_TOOLCHAIN`` may be set to a path to
+the external toolchain and will be passed to the compiler driver if supported.
+
+This variable may only be set in a toolchain file specified by
+the :variable:`CMAKE_TOOLCHAIN_FILE` variable.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_ID.rst b/Help/variable/CMAKE_LANG_COMPILER_ID.rst
new file mode 100644
index 0000000..0abedde
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_COMPILER_ID.rst
@@ -0,0 +1,45 @@
+CMAKE_<LANG>_COMPILER_ID
+------------------------
+
+Compiler identification string.
+
+A short string unique to the compiler vendor. Possible values
+include:
+
+::
+
+ Absoft = Absoft Fortran (absoft.com)
+ ADSP = Analog VisualDSP++ (analog.com)
+ AppleClang = Apple Clang (apple.com)
+ ARMCC = ARM Compiler (arm.com)
+ ARMClang = ARM Compiler based on Clang (arm.com)
+ Bruce = Bruce C Compiler
+ CCur = Concurrent Fortran (ccur.com)
+ Clang = LLVM Clang (clang.llvm.org)
+ Cray = Cray Compiler (cray.com)
+ Embarcadero, Borland = Embarcadero (embarcadero.com)
+ Flang = Flang LLVM Fortran Compiler
+ Fujitsu = Fujitsu HPC compiler (Trad mode)
+ FujitsuClang = Fujitsu HPC compiler (Clang mode)
+ G95 = G95 Fortran (g95.org)
+ GNU = GNU Compiler Collection (gcc.gnu.org)
+ GHS = Green Hills Software (www.ghs.com)
+ HP = Hewlett-Packard Compiler (hp.com)
+ IAR = IAR Systems (iar.com)
+ Intel = Intel Compiler (intel.com)
+ IntelLLVM = Intel LLVM-Based Compiler (intel.com)
+ MSVC = Microsoft Visual Studio (microsoft.com)
+ NVHPC = NVIDIA HPC SDK Compiler (nvidia.com)
+ NVIDIA = NVIDIA CUDA Compiler (nvidia.com)
+ OpenWatcom = Open Watcom (openwatcom.org)
+ PGI = The Portland Group (pgroup.com)
+ PathScale = PathScale (pathscale.com)
+ SDCC = Small Device C Compiler (sdcc.sourceforge.net)
+ SunPro = Oracle Solaris Studio (oracle.com)
+ TI = Texas Instruments (ti.com)
+ TinyCC = Tiny C Compiler (tinycc.org)
+ XL, VisualAge, zOS = IBM XL (ibm.com)
+ XLClang = IBM Clang-based XL (ibm.com)
+
+This variable is not guaranteed to be defined for all compilers or
+languages.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_LAUNCHER.rst b/Help/variable/CMAKE_LANG_COMPILER_LAUNCHER.rst
new file mode 100644
index 0000000..89fd7bc
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_COMPILER_LAUNCHER.rst
@@ -0,0 +1,12 @@
+CMAKE_<LANG>_COMPILER_LAUNCHER
+------------------------------
+
+.. versionadded:: 3.4
+
+Default value for :prop_tgt:`<LANG>_COMPILER_LAUNCHER` target property.
+This variable is used to initialize the property on each target as it is
+created. This is done only when ``<LANG>`` is ``C``, ``CXX``, ``Fortran``,
+``ISPC``, ``OBJC``, ``OBJCXX``, or ``CUDA``.
+
+This variable is initialized to the :envvar:`CMAKE_<LANG>_COMPILER_LAUNCHER`
+environment variable if it is set.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_LOADED.rst b/Help/variable/CMAKE_LANG_COMPILER_LOADED.rst
new file mode 100644
index 0000000..9308878
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_COMPILER_LOADED.rst
@@ -0,0 +1,7 @@
+CMAKE_<LANG>_COMPILER_LOADED
+----------------------------
+
+Defined to true if the language is enabled.
+
+When language ``<LANG>`` is enabled by :command:`project` or
+:command:`enable_language` this variable is defined to ``1``.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_PREDEFINES_COMMAND.rst b/Help/variable/CMAKE_LANG_COMPILER_PREDEFINES_COMMAND.rst
new file mode 100644
index 0000000..935329a
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_COMPILER_PREDEFINES_COMMAND.rst
@@ -0,0 +1,10 @@
+CMAKE_<LANG>_COMPILER_PREDEFINES_COMMAND
+----------------------------------------
+
+.. versionadded:: 3.10
+
+Command that outputs the compiler pre definitions.
+
+See :prop_tgt:`AUTOMOC` which uses
+:variable:`CMAKE_CXX_COMPILER_PREDEFINES_COMMAND <CMAKE_<LANG>_COMPILER_PREDEFINES_COMMAND>`
+to generate the :prop_tgt:`AUTOMOC_COMPILER_PREDEFINES`.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_RANLIB.rst b/Help/variable/CMAKE_LANG_COMPILER_RANLIB.rst
new file mode 100644
index 0000000..1d10b55
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_COMPILER_RANLIB.rst
@@ -0,0 +1,9 @@
+CMAKE_<LANG>_COMPILER_RANLIB
+----------------------------
+
+.. versionadded:: 3.9
+
+A wrapper around ``ranlib`` adding the appropriate ``--plugin`` option for the
+compiler.
+
+See also :variable:`CMAKE_RANLIB`.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_TARGET.rst b/Help/variable/CMAKE_LANG_COMPILER_TARGET.rst
new file mode 100644
index 0000000..656c57d
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_COMPILER_TARGET.rst
@@ -0,0 +1,11 @@
+CMAKE_<LANG>_COMPILER_TARGET
+----------------------------
+
+The target for cross-compiling, if supported.
+
+Some compiler drivers are inherently cross-compilers, such as clang and
+QNX qcc. These compiler drivers support a command-line argument to specify
+the target to cross-compile for.
+
+This variable may only be set in a toolchain file specified by
+the :variable:`CMAKE_TOOLCHAIN_FILE` variable.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_VERSION.rst b/Help/variable/CMAKE_LANG_COMPILER_VERSION.rst
new file mode 100644
index 0000000..27b0cad
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_COMPILER_VERSION.rst
@@ -0,0 +1,12 @@
+CMAKE_<LANG>_COMPILER_VERSION
+-----------------------------
+
+Compiler version string.
+
+Compiler version in major[.minor[.patch[.tweak]]] format. This
+variable is not guaranteed to be defined for all compilers or
+languages.
+
+For example ``CMAKE_C_COMPILER_VERSION`` and
+``CMAKE_CXX_COMPILER_VERSION`` might indicate the respective C and C++
+compiler version.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_VERSION_INTERNAL.rst b/Help/variable/CMAKE_LANG_COMPILER_VERSION_INTERNAL.rst
new file mode 100644
index 0000000..596a989
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_COMPILER_VERSION_INTERNAL.rst
@@ -0,0 +1,10 @@
+CMAKE_<LANG>_COMPILER_VERSION_INTERNAL
+--------------------------------------
+
+.. versionadded:: 3.10
+
+An internal variable subject to change.
+
+This is used to identify the variant of a compiler based on an internal
+version number. For some compilers this is needed to determine the
+correct usage.
diff --git a/Help/variable/CMAKE_LANG_COMPILE_OBJECT.rst b/Help/variable/CMAKE_LANG_COMPILE_OBJECT.rst
new file mode 100644
index 0000000..ba59cad
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_COMPILE_OBJECT.rst
@@ -0,0 +1,7 @@
+CMAKE_<LANG>_COMPILE_OBJECT
+---------------------------
+
+Rule variable to compile a single object file.
+
+This is a rule variable that tells CMake how to compile a single
+object file for the language ``<LANG>``.
diff --git a/Help/variable/CMAKE_LANG_CPPCHECK.rst b/Help/variable/CMAKE_LANG_CPPCHECK.rst
new file mode 100644
index 0000000..5ae5faf
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_CPPCHECK.rst
@@ -0,0 +1,8 @@
+CMAKE_<LANG>_CPPCHECK
+---------------------
+
+.. versionadded:: 3.10
+
+Default value for :prop_tgt:`<LANG>_CPPCHECK` target property. This variable
+is used to initialize the property on each target as it is created. This
+is done only when ``<LANG>`` is ``C`` or ``CXX``.
diff --git a/Help/variable/CMAKE_LANG_CPPLINT.rst b/Help/variable/CMAKE_LANG_CPPLINT.rst
new file mode 100644
index 0000000..ab7b0fc
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_CPPLINT.rst
@@ -0,0 +1,8 @@
+CMAKE_<LANG>_CPPLINT
+--------------------
+
+.. versionadded:: 3.8
+
+Default value for :prop_tgt:`<LANG>_CPPLINT` target property. This variable
+is used to initialize the property on each target as it is created. This
+is done only when ``<LANG>`` is ``C`` or ``CXX``.
diff --git a/Help/variable/CMAKE_LANG_CREATE_SHARED_LIBRARY.rst b/Help/variable/CMAKE_LANG_CREATE_SHARED_LIBRARY.rst
new file mode 100644
index 0000000..16fcc03
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_CREATE_SHARED_LIBRARY.rst
@@ -0,0 +1,8 @@
+CMAKE_<LANG>_CREATE_SHARED_LIBRARY
+----------------------------------
+
+Rule variable to create a shared library.
+
+This is a rule variable that tells CMake how to create a shared
+library for the language ``<LANG>``. This rule variable is a ``;`` delimited
+list of commands to run to perform the linking step.
diff --git a/Help/variable/CMAKE_LANG_CREATE_SHARED_MODULE.rst b/Help/variable/CMAKE_LANG_CREATE_SHARED_MODULE.rst
new file mode 100644
index 0000000..807229d
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_CREATE_SHARED_MODULE.rst
@@ -0,0 +1,8 @@
+CMAKE_<LANG>_CREATE_SHARED_MODULE
+---------------------------------
+
+Rule variable to create a shared module.
+
+This is a rule variable that tells CMake how to create a shared
+library for the language ``<LANG>``. This rule variable is a ``;`` delimited
+list of commands to run.
diff --git a/Help/variable/CMAKE_LANG_CREATE_STATIC_LIBRARY.rst b/Help/variable/CMAKE_LANG_CREATE_STATIC_LIBRARY.rst
new file mode 100644
index 0000000..0cff200
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_CREATE_STATIC_LIBRARY.rst
@@ -0,0 +1,7 @@
+CMAKE_<LANG>_CREATE_STATIC_LIBRARY
+----------------------------------
+
+Rule variable to create a static library.
+
+This is a rule variable that tells CMake how to create a static
+library for the language ``<LANG>``.
diff --git a/Help/variable/CMAKE_LANG_FLAGS.rst b/Help/variable/CMAKE_LANG_FLAGS.rst
new file mode 100644
index 0000000..11864f8
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_FLAGS.rst
@@ -0,0 +1,20 @@
+CMAKE_<LANG>_FLAGS
+------------------
+
+Flags for all build types.
+
+``<LANG>`` flags used regardless of the value of :variable:`CMAKE_BUILD_TYPE`.
+
+This is initialized for each language from environment variables:
+
+* ``CMAKE_C_FLAGS``:
+ Initialized by the :envvar:`CFLAGS` environment variable.
+* ``CMAKE_CXX_FLAGS``:
+ Initialized by the :envvar:`CXXFLAGS` environment variable.
+* ``CMAKE_CUDA_FLAGS``:
+ Initialized by the :envvar:`CUDAFLAGS` environment variable.
+* ``CMAKE_Fortran_FLAGS``:
+ Initialized by the :envvar:`FFLAGS` environment variable.
+
+This value is a command-line string fragment. Therefore, multiple options
+should be separated by spaces, and options with spaces should be quoted.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_CONFIG.rst b/Help/variable/CMAKE_LANG_FLAGS_CONFIG.rst
new file mode 100644
index 0000000..628b62b
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_FLAGS_CONFIG.rst
@@ -0,0 +1,6 @@
+CMAKE_<LANG>_FLAGS_<CONFIG>
+---------------------------
+
+.. versionadded:: 3.11
+
+Flags for language ``<LANG>`` when building for the ``<CONFIG>`` configuration.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_CONFIG_INIT.rst b/Help/variable/CMAKE_LANG_FLAGS_CONFIG_INIT.rst
new file mode 100644
index 0000000..17669a2
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_FLAGS_CONFIG_INIT.rst
@@ -0,0 +1,12 @@
+CMAKE_<LANG>_FLAGS_<CONFIG>_INIT
+--------------------------------
+
+.. versionadded:: 3.11
+
+Value used to initialize the :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` cache
+entry the first time a build tree is configured for language ``<LANG>``.
+This variable is meant to be set by a :variable:`toolchain file
+<CMAKE_TOOLCHAIN_FILE>`. CMake may prepend or append content to
+the value based on the environment and target platform.
+
+See also :variable:`CMAKE_<LANG>_FLAGS_INIT`.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_DEBUG.rst b/Help/variable/CMAKE_LANG_FLAGS_DEBUG.rst
new file mode 100644
index 0000000..6be424a
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_FLAGS_DEBUG.rst
@@ -0,0 +1,5 @@
+CMAKE_<LANG>_FLAGS_DEBUG
+------------------------
+
+This variable is the ``Debug`` variant of the
+:variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` variable.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_DEBUG_INIT.rst b/Help/variable/CMAKE_LANG_FLAGS_DEBUG_INIT.rst
new file mode 100644
index 0000000..49c9e99
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_FLAGS_DEBUG_INIT.rst
@@ -0,0 +1,7 @@
+CMAKE_<LANG>_FLAGS_DEBUG_INIT
+-----------------------------
+
+.. versionadded:: 3.7
+
+This variable is the ``Debug`` variant of the
+:variable:`CMAKE_<LANG>_FLAGS_<CONFIG>_INIT` variable.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_INIT.rst b/Help/variable/CMAKE_LANG_FLAGS_INIT.rst
new file mode 100644
index 0000000..ca13a29
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_FLAGS_INIT.rst
@@ -0,0 +1,19 @@
+CMAKE_<LANG>_FLAGS_INIT
+-----------------------
+
+.. versionadded:: 3.7
+
+Value used to initialize the :variable:`CMAKE_<LANG>_FLAGS` cache entry
+the first time a build tree is configured for language ``<LANG>``.
+This variable is meant to be set by a :variable:`toolchain file
+<CMAKE_TOOLCHAIN_FILE>`. CMake may prepend or append content to
+the value based on the environment and target platform. For example,
+the contents of a ``xxxFLAGS`` environment variable will be prepended,
+where ``xxx`` will be language-specific but not necessarily the same as
+``<LANG>`` (e.g. :envvar:`CXXFLAGS` for ``CXX``, :envvar:`FFLAGS` for
+``Fortran``, and so on).
+This value is a command-line string fragment. Therefore, multiple options
+should be separated by spaces, and options with spaces should be quoted.
+
+See also the configuration-specific
+:variable:`CMAKE_<LANG>_FLAGS_<CONFIG>_INIT` variable.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_MINSIZEREL.rst b/Help/variable/CMAKE_LANG_FLAGS_MINSIZEREL.rst
new file mode 100644
index 0000000..634fab9
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_FLAGS_MINSIZEREL.rst
@@ -0,0 +1,5 @@
+CMAKE_<LANG>_FLAGS_MINSIZEREL
+-----------------------------
+
+This variable is the ``MinSizeRel`` variant of the
+:variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` variable.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_MINSIZEREL_INIT.rst b/Help/variable/CMAKE_LANG_FLAGS_MINSIZEREL_INIT.rst
new file mode 100644
index 0000000..3600909
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_FLAGS_MINSIZEREL_INIT.rst
@@ -0,0 +1,7 @@
+CMAKE_<LANG>_FLAGS_MINSIZEREL_INIT
+----------------------------------
+
+.. versionadded:: 3.7
+
+This variable is the ``MinSizeRel`` variant of the
+:variable:`CMAKE_<LANG>_FLAGS_<CONFIG>_INIT` variable.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_RELEASE.rst b/Help/variable/CMAKE_LANG_FLAGS_RELEASE.rst
new file mode 100644
index 0000000..3baeab0
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_FLAGS_RELEASE.rst
@@ -0,0 +1,5 @@
+CMAKE_<LANG>_FLAGS_RELEASE
+--------------------------
+
+This variable is the ``Release`` variant of the
+:variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` variable.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_RELEASE_INIT.rst b/Help/variable/CMAKE_LANG_FLAGS_RELEASE_INIT.rst
new file mode 100644
index 0000000..e889852
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_FLAGS_RELEASE_INIT.rst
@@ -0,0 +1,7 @@
+CMAKE_<LANG>_FLAGS_RELEASE_INIT
+-------------------------------
+
+.. versionadded:: 3.7
+
+This variable is the ``Release`` variant of the
+:variable:`CMAKE_<LANG>_FLAGS_<CONFIG>_INIT` variable.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO.rst b/Help/variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO.rst
new file mode 100644
index 0000000..67a5073
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO.rst
@@ -0,0 +1,5 @@
+CMAKE_<LANG>_FLAGS_RELWITHDEBINFO
+---------------------------------
+
+This variable is the ``RelWithDebInfo`` variant of the
+:variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` variable.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO_INIT.rst b/Help/variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO_INIT.rst
new file mode 100644
index 0000000..b42caee
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO_INIT.rst
@@ -0,0 +1,7 @@
+CMAKE_<LANG>_FLAGS_RELWITHDEBINFO_INIT
+--------------------------------------
+
+.. versionadded:: 3.7
+
+This variable is the ``RelWithDebInfo`` variant of the
+:variable:`CMAKE_<LANG>_FLAGS_<CONFIG>_INIT` variable.
diff --git a/Help/variable/CMAKE_LANG_IGNORE_EXTENSIONS.rst b/Help/variable/CMAKE_LANG_IGNORE_EXTENSIONS.rst
new file mode 100644
index 0000000..3d07e91
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_IGNORE_EXTENSIONS.rst
@@ -0,0 +1,7 @@
+CMAKE_<LANG>_IGNORE_EXTENSIONS
+------------------------------
+
+File extensions that should be ignored by the build.
+
+This is a list of file extensions that may be part of a project for a
+given language but are not compiled.
diff --git a/Help/variable/CMAKE_LANG_IMPLICIT_INCLUDE_DIRECTORIES.rst b/Help/variable/CMAKE_LANG_IMPLICIT_INCLUDE_DIRECTORIES.rst
new file mode 100644
index 0000000..e361fd9
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_IMPLICIT_INCLUDE_DIRECTORIES.rst
@@ -0,0 +1,14 @@
+CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES
+-----------------------------------------
+
+Directories implicitly searched by the compiler for header files.
+
+CMake does not explicitly specify these directories on compiler
+command lines for language ``<LANG>``. This prevents system include
+directories from being treated as user include directories on some
+compilers, which is important for ``C``, ``CXX``, and ``CUDA`` to
+avoid overriding standard library headers.
+
+This value is not used for ``Fortran`` because it has no standard
+library headers and some compilers do not search their implicit
+include directories for module ``.mod`` files.
diff --git a/Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst b/Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst
new file mode 100644
index 0000000..e9e04be
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst
@@ -0,0 +1,20 @@
+CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES
+--------------------------------------
+
+Implicit linker search path detected for language ``<LANG>``.
+
+Compilers typically pass directories containing language runtime
+libraries and default library search paths when they invoke a linker.
+These paths are implicit linker search directories for the compiler's
+language. CMake automatically detects these directories for each
+language and reports the results in this variable.
+
+Some toolchains read implicit directories from an environment variable such as
+``LIBRARY_PATH``. If using such an environment variable, keep its value
+consistent when operating in a given build tree because CMake saves the value
+detected when first creating a build tree.
+
+If policy :policy:`CMP0060` is not set to ``NEW``, then when a library in one
+of these directories is given by full path to :command:`target_link_libraries`
+CMake will generate the ``-l<name>`` form on link lines for historical
+purposes.
diff --git a/Help/variable/CMAKE_LANG_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES.rst b/Help/variable/CMAKE_LANG_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES.rst
new file mode 100644
index 0000000..61ccc5a
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES.rst
@@ -0,0 +1,8 @@
+CMAKE_<LANG>_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+------------------------------------------------
+
+Implicit linker framework search path detected for language ``<LANG>``.
+
+These paths are implicit linker framework search directories for the
+compiler's language. CMake automatically detects these directories
+for each language and reports the results in this variable.
diff --git a/Help/variable/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES.rst b/Help/variable/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES.rst
new file mode 100644
index 0000000..ec16477
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES.rst
@@ -0,0 +1,10 @@
+CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES
+------------------------------------
+
+Implicit link libraries and flags detected for language ``<LANG>``.
+
+Compilers typically pass language runtime library names and other
+flags when they invoke a linker. These flags are implicit link
+options for the compiler's language. CMake automatically detects
+these libraries and flags for each language and reports the results in
+this variable.
diff --git a/Help/variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE.rst b/Help/variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE.rst
new file mode 100644
index 0000000..be6c210
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE.rst
@@ -0,0 +1,8 @@
+CMAKE_<LANG>_INCLUDE_WHAT_YOU_USE
+---------------------------------
+
+.. versionadded:: 3.3
+
+Default value for :prop_tgt:`<LANG>_INCLUDE_WHAT_YOU_USE` target property.
+This variable is used to initialize the property on each target as it is
+created. This is done only when ``<LANG>`` is ``C`` or ``CXX``.
diff --git a/Help/variable/CMAKE_LANG_LIBRARY_ARCHITECTURE.rst b/Help/variable/CMAKE_LANG_LIBRARY_ARCHITECTURE.rst
new file mode 100644
index 0000000..7f888ee
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_LIBRARY_ARCHITECTURE.rst
@@ -0,0 +1,8 @@
+CMAKE_<LANG>_LIBRARY_ARCHITECTURE
+---------------------------------
+
+Target architecture library directory name detected for ``<LANG>``.
+
+If the ``<LANG>`` compiler passes to the linker an architecture-specific
+system library search directory such as ``<prefix>/lib/<arch>`` this
+variable contains the ``<arch>`` name if/as detected by CMake.
diff --git a/Help/variable/CMAKE_LANG_LINKER_PREFERENCE.rst b/Help/variable/CMAKE_LANG_LINKER_PREFERENCE.rst
new file mode 100644
index 0000000..ff82f8b
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_LINKER_PREFERENCE.rst
@@ -0,0 +1,11 @@
+CMAKE_<LANG>_LINKER_PREFERENCE
+------------------------------
+
+Preference value for linker language selection.
+
+The "linker language" for executable, shared library, and module
+targets is the language whose compiler will invoke the linker. The
+:prop_tgt:`LINKER_LANGUAGE` target property sets the language explicitly.
+Otherwise, the linker language is that whose linker preference value
+is highest among languages compiled and linked into the target. See
+also the :variable:`CMAKE_<LANG>_LINKER_PREFERENCE_PROPAGATES` variable.
diff --git a/Help/variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES.rst b/Help/variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES.rst
new file mode 100644
index 0000000..dbbeb0a
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES.rst
@@ -0,0 +1,9 @@
+CMAKE_<LANG>_LINKER_PREFERENCE_PROPAGATES
+-----------------------------------------
+
+True if :variable:`CMAKE_<LANG>_LINKER_PREFERENCE` propagates across targets.
+
+This is used when CMake selects a linker language for a target.
+Languages compiled directly into the target are always considered. A
+language compiled into static libraries linked by the target is
+considered if this variable is true.
diff --git a/Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG.rst b/Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG.rst
new file mode 100644
index 0000000..471c351
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG.rst
@@ -0,0 +1,41 @@
+CMAKE_<LANG>_LINKER_WRAPPER_FLAG
+--------------------------------
+
+.. versionadded:: 3.13
+
+Defines the syntax of compiler driver option to pass options to the linker
+tool. It will be used to translate the ``LINKER:`` prefix in the link options
+(see :command:`add_link_options` and :command:`target_link_options`).
+
+This variable holds a :ref:`semicolon-separated list <CMake Language Lists>` of tokens.
+If a space (i.e. " ") is specified as last token, flag and ``LINKER:``
+arguments will be specified as separate arguments to the compiler driver.
+The :variable:`CMAKE_<LANG>_LINKER_WRAPPER_FLAG_SEP` variable can be specified
+to manage concatenation of arguments.
+
+For example, for ``Clang`` we have:
+
+.. code-block:: cmake
+
+ set (CMAKE_C_LINKER_WRAPPER_FLAG "-Xlinker" " ")
+
+Specifying ``"LINKER:-z,defs"`` will be transformed in
+``-Xlinker -z -Xlinker defs``.
+
+For ``GNU GCC``:
+
+.. code-block:: cmake
+
+ set (CMAKE_C_LINKER_WRAPPER_FLAG "-Wl,")
+ set (CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",")
+
+Specifying ``"LINKER:-z,defs"`` will be transformed in ``-Wl,-z,defs``.
+
+And for ``SunPro``:
+
+.. code-block:: cmake
+
+ set (CMAKE_C_LINKER_WRAPPER_FLAG "-Qoption" "ld" " ")
+ set (CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",")
+
+Specifying ``"LINKER:-z,defs"`` will be transformed in ``-Qoption ld -z,defs``.
diff --git a/Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG_SEP.rst b/Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG_SEP.rst
new file mode 100644
index 0000000..a3895af
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG_SEP.rst
@@ -0,0 +1,11 @@
+CMAKE_<LANG>_LINKER_WRAPPER_FLAG_SEP
+------------------------------------
+
+.. versionadded:: 3.13
+
+This variable is used with :variable:`CMAKE_<LANG>_LINKER_WRAPPER_FLAG`
+variable to format ``LINKER:`` prefix in the link options
+(see :command:`add_link_options` and :command:`target_link_options`).
+
+When specified, arguments of the ``LINKER:`` prefix will be concatenated using
+this value as separator.
diff --git a/Help/variable/CMAKE_LANG_LINK_EXECUTABLE.rst b/Help/variable/CMAKE_LANG_LINK_EXECUTABLE.rst
new file mode 100644
index 0000000..abd5891
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_LINK_EXECUTABLE.rst
@@ -0,0 +1,6 @@
+CMAKE_<LANG>_LINK_EXECUTABLE
+----------------------------
+
+Rule variable to link an executable.
+
+Rule variable to link an executable for the given language.
diff --git a/Help/variable/CMAKE_LANG_LINK_LIBRARY_FILE_FLAG.rst b/Help/variable/CMAKE_LANG_LINK_LIBRARY_FILE_FLAG.rst
new file mode 100644
index 0000000..23ece88
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_LINK_LIBRARY_FILE_FLAG.rst
@@ -0,0 +1,10 @@
+CMAKE_<LANG>_LINK_LIBRARY_FILE_FLAG
+-----------------------------------
+
+.. versionadded:: 3.16
+
+Language-specific flag to be used to link a library specified by
+a path to its file.
+
+The flag will be used before a library file path is given to the
+linker. This is needed only on very few platforms.
diff --git a/Help/variable/CMAKE_LANG_LINK_LIBRARY_FLAG.rst b/Help/variable/CMAKE_LANG_LINK_LIBRARY_FLAG.rst
new file mode 100644
index 0000000..0f528db
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_LINK_LIBRARY_FLAG.rst
@@ -0,0 +1,9 @@
+CMAKE_<LANG>_LINK_LIBRARY_FLAG
+------------------------------
+
+.. versionadded:: 3.16
+
+Flag to be used to link a library into a shared library or executable.
+
+This flag will be used to specify a library to link to a shared library or an
+executable for the specific language. On most compilers this is ``-l``.
diff --git a/Help/variable/CMAKE_LANG_LINK_LIBRARY_SUFFIX.rst b/Help/variable/CMAKE_LANG_LINK_LIBRARY_SUFFIX.rst
new file mode 100644
index 0000000..359e29f
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_LINK_LIBRARY_SUFFIX.rst
@@ -0,0 +1,8 @@
+CMAKE_<LANG>_LINK_LIBRARY_SUFFIX
+--------------------------------
+
+.. versionadded:: 3.16
+
+Language-specific suffix for libraries that you link to.
+
+The suffix to use for the end of a library filename, ``.lib`` on Windows.
diff --git a/Help/variable/CMAKE_LANG_OUTPUT_EXTENSION.rst b/Help/variable/CMAKE_LANG_OUTPUT_EXTENSION.rst
new file mode 100644
index 0000000..0fbc566
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_OUTPUT_EXTENSION.rst
@@ -0,0 +1,7 @@
+CMAKE_<LANG>_OUTPUT_EXTENSION
+-----------------------------
+
+Extension for the output of a compile for a single file.
+
+This is the extension for an object file for the given ``<LANG>``. For
+example ``.obj`` for C on Windows.
diff --git a/Help/variable/CMAKE_LANG_PLATFORM_ID.rst b/Help/variable/CMAKE_LANG_PLATFORM_ID.rst
new file mode 100644
index 0000000..1b243e3
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_PLATFORM_ID.rst
@@ -0,0 +1,6 @@
+CMAKE_<LANG>_PLATFORM_ID
+------------------------
+
+An internal variable subject to change.
+
+This is used in determining the platform and is subject to change.
diff --git a/Help/variable/CMAKE_LANG_SIMULATE_ID.rst b/Help/variable/CMAKE_LANG_SIMULATE_ID.rst
new file mode 100644
index 0000000..15c87a1
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_SIMULATE_ID.rst
@@ -0,0 +1,9 @@
+CMAKE_<LANG>_SIMULATE_ID
+------------------------
+
+Identification string of "simulated" compiler.
+
+Some compilers simulate other compilers to serve as drop-in
+replacements. When CMake detects such a compiler it sets this
+variable to what would have been the :variable:`CMAKE_<LANG>_COMPILER_ID` for
+the simulated compiler.
diff --git a/Help/variable/CMAKE_LANG_SIMULATE_VERSION.rst b/Help/variable/CMAKE_LANG_SIMULATE_VERSION.rst
new file mode 100644
index 0000000..d6325e0
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_SIMULATE_VERSION.rst
@@ -0,0 +1,9 @@
+CMAKE_<LANG>_SIMULATE_VERSION
+-----------------------------
+
+Version string of "simulated" compiler.
+
+Some compilers simulate other compilers to serve as drop-in
+replacements. When CMake detects such a compiler it sets this
+variable to what would have been the :variable:`CMAKE_<LANG>_COMPILER_VERSION`
+for the simulated compiler.
diff --git a/Help/variable/CMAKE_LANG_SIZEOF_DATA_PTR.rst b/Help/variable/CMAKE_LANG_SIZEOF_DATA_PTR.rst
new file mode 100644
index 0000000..7465923
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_SIZEOF_DATA_PTR.rst
@@ -0,0 +1,7 @@
+CMAKE_<LANG>_SIZEOF_DATA_PTR
+----------------------------
+
+Size of pointer-to-data types for language ``<LANG>``.
+
+This holds the size (in bytes) of pointer-to-data types in the target
+platform ABI. It is defined for languages ``C`` and ``CXX`` (C++).
diff --git a/Help/variable/CMAKE_LANG_SOURCE_FILE_EXTENSIONS.rst b/Help/variable/CMAKE_LANG_SOURCE_FILE_EXTENSIONS.rst
new file mode 100644
index 0000000..e085fee
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_SOURCE_FILE_EXTENSIONS.rst
@@ -0,0 +1,6 @@
+CMAKE_<LANG>_SOURCE_FILE_EXTENSIONS
+-----------------------------------
+
+Extensions of source files for the given language.
+
+This is the list of extensions for a given language's source files.
diff --git a/Help/variable/CMAKE_LANG_STANDARD_INCLUDE_DIRECTORIES.rst b/Help/variable/CMAKE_LANG_STANDARD_INCLUDE_DIRECTORIES.rst
new file mode 100644
index 0000000..24aca8b
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_STANDARD_INCLUDE_DIRECTORIES.rst
@@ -0,0 +1,16 @@
+CMAKE_<LANG>_STANDARD_INCLUDE_DIRECTORIES
+-----------------------------------------
+
+.. versionadded:: 3.6
+
+Include directories to be used for every source file compiled with
+the ``<LANG>`` compiler. This is meant for specification of system
+include directories needed by the language for the current platform.
+The directories always appear at the end of the include path passed
+to the compiler.
+
+This variable should not be set by project code. It is meant to be set by
+CMake's platform information modules for the current toolchain, or by a
+toolchain file when used with :variable:`CMAKE_TOOLCHAIN_FILE`.
+
+See also :variable:`CMAKE_<LANG>_STANDARD_LIBRARIES`.
diff --git a/Help/variable/CMAKE_LANG_STANDARD_LIBRARIES.rst b/Help/variable/CMAKE_LANG_STANDARD_LIBRARIES.rst
new file mode 100644
index 0000000..d5f3351
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_STANDARD_LIBRARIES.rst
@@ -0,0 +1,14 @@
+CMAKE_<LANG>_STANDARD_LIBRARIES
+-------------------------------
+
+.. versionadded:: 3.6
+
+Libraries linked into every executable and shared library linked
+for language ``<LANG>``. This is meant for specification of system
+libraries needed by the language for the current platform.
+
+This variable should not be set by project code. It is meant to be set by
+CMake's platform information modules for the current toolchain, or by a
+toolchain file when used with :variable:`CMAKE_TOOLCHAIN_FILE`.
+
+See also :variable:`CMAKE_<LANG>_STANDARD_INCLUDE_DIRECTORIES`.
diff --git a/Help/variable/CMAKE_LANG_VISIBILITY_PRESET.rst b/Help/variable/CMAKE_LANG_VISIBILITY_PRESET.rst
new file mode 100644
index 0000000..1961ea0
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_VISIBILITY_PRESET.rst
@@ -0,0 +1,5 @@
+CMAKE_<LANG>_VISIBILITY_PRESET
+------------------------------
+
+Default value for the :prop_tgt:`<LANG>_VISIBILITY_PRESET` target
+property when a target is created.
diff --git a/Help/variable/CMAKE_LIBRARY_ARCHITECTURE.rst b/Help/variable/CMAKE_LIBRARY_ARCHITECTURE.rst
new file mode 100644
index 0000000..8a7dcbd
--- /dev/null
+++ b/Help/variable/CMAKE_LIBRARY_ARCHITECTURE.rst
@@ -0,0 +1,7 @@
+CMAKE_LIBRARY_ARCHITECTURE
+--------------------------
+
+Target architecture library directory name, if detected.
+
+This is the value of :variable:`CMAKE_<LANG>_LIBRARY_ARCHITECTURE` as detected
+for one of the enabled languages.
diff --git a/Help/variable/CMAKE_LIBRARY_ARCHITECTURE_REGEX.rst b/Help/variable/CMAKE_LIBRARY_ARCHITECTURE_REGEX.rst
new file mode 100644
index 0000000..1eb2ac2
--- /dev/null
+++ b/Help/variable/CMAKE_LIBRARY_ARCHITECTURE_REGEX.rst
@@ -0,0 +1,7 @@
+CMAKE_LIBRARY_ARCHITECTURE_REGEX
+--------------------------------
+
+Regex matching possible target architecture library directory names.
+
+This is used to detect :variable:`CMAKE_<LANG>_LIBRARY_ARCHITECTURE` from the
+implicit linker search path by matching the ``<arch>`` name.
diff --git a/Help/variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY.rst b/Help/variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY.rst
new file mode 100644
index 0000000..e97296d
--- /dev/null
+++ b/Help/variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY.rst
@@ -0,0 +1,9 @@
+CMAKE_LIBRARY_OUTPUT_DIRECTORY
+------------------------------
+
+Where to put all the :ref:`LIBRARY <Library Output Artifacts>`
+target files when built.
+
+This variable is used to initialize the :prop_tgt:`LIBRARY_OUTPUT_DIRECTORY`
+property on all the targets. See that target property for additional
+information.
diff --git a/Help/variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst b/Help/variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst
new file mode 100644
index 0000000..08f95c4
--- /dev/null
+++ b/Help/variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst
@@ -0,0 +1,11 @@
+CMAKE_LIBRARY_OUTPUT_DIRECTORY_<CONFIG>
+---------------------------------------
+
+.. versionadded:: 3.3
+
+Where to put all the :ref:`LIBRARY <Library Output Artifacts>`
+target files when built for a specific configuration.
+
+This variable is used to initialize the
+:prop_tgt:`LIBRARY_OUTPUT_DIRECTORY_<CONFIG>` property on all the targets.
+See that target property for additional information.
diff --git a/Help/variable/CMAKE_LIBRARY_PATH.rst b/Help/variable/CMAKE_LIBRARY_PATH.rst
new file mode 100644
index 0000000..8135b65
--- /dev/null
+++ b/Help/variable/CMAKE_LIBRARY_PATH.rst
@@ -0,0 +1,7 @@
+CMAKE_LIBRARY_PATH
+------------------
+
+:ref:`Semicolon-separated list <CMake Language Lists>` of directories specifying a search path
+for the :command:`find_library` command. By default it is empty, it is
+intended to be set by the project. See also
+:variable:`CMAKE_SYSTEM_LIBRARY_PATH` and :variable:`CMAKE_PREFIX_PATH`.
diff --git a/Help/variable/CMAKE_LIBRARY_PATH_FLAG.rst b/Help/variable/CMAKE_LIBRARY_PATH_FLAG.rst
new file mode 100644
index 0000000..ebe5fda
--- /dev/null
+++ b/Help/variable/CMAKE_LIBRARY_PATH_FLAG.rst
@@ -0,0 +1,7 @@
+CMAKE_LIBRARY_PATH_FLAG
+-----------------------
+
+The flag to be used to add a library search path to a compiler.
+
+The flag will be used to specify a library directory to the compiler.
+On most compilers this is ``-L``.
diff --git a/Help/variable/CMAKE_LINK_DEF_FILE_FLAG.rst b/Help/variable/CMAKE_LINK_DEF_FILE_FLAG.rst
new file mode 100644
index 0000000..fa09f9f
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_DEF_FILE_FLAG.rst
@@ -0,0 +1,7 @@
+CMAKE_LINK_DEF_FILE_FLAG
+------------------------
+
+Linker flag to be used to specify a ``.def`` file for dll creation.
+
+The flag will be used to add a ``.def`` file when creating a dll on
+Windows; this is only defined on Windows.
diff --git a/Help/variable/CMAKE_LINK_DEPENDS_NO_SHARED.rst b/Help/variable/CMAKE_LINK_DEPENDS_NO_SHARED.rst
new file mode 100644
index 0000000..cec7906
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_DEPENDS_NO_SHARED.rst
@@ -0,0 +1,8 @@
+CMAKE_LINK_DEPENDS_NO_SHARED
+----------------------------
+
+Whether to skip link dependencies on shared library files.
+
+This variable initializes the :prop_tgt:`LINK_DEPENDS_NO_SHARED` property on
+targets when they are created. See that target property for
+additional information.
diff --git a/Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst b/Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst
new file mode 100644
index 0000000..f120866
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst
@@ -0,0 +1,11 @@
+CMAKE_LINK_DIRECTORIES_BEFORE
+-----------------------------
+
+.. versionadded:: 3.13
+
+Whether to append or prepend directories by default in
+:command:`link_directories`.
+
+This variable affects the default behavior of the :command:`link_directories`
+command. Setting this variable to ``ON`` is equivalent to using the ``BEFORE``
+option in all uses of that command.
diff --git a/Help/variable/CMAKE_LINK_INTERFACE_LIBRARIES.rst b/Help/variable/CMAKE_LINK_INTERFACE_LIBRARIES.rst
new file mode 100644
index 0000000..33865da
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_INTERFACE_LIBRARIES.rst
@@ -0,0 +1,8 @@
+CMAKE_LINK_INTERFACE_LIBRARIES
+------------------------------
+
+Default value for :prop_tgt:`LINK_INTERFACE_LIBRARIES` of targets.
+
+This variable is used to initialize the :prop_tgt:`LINK_INTERFACE_LIBRARIES`
+property on all the targets. See that target property for additional
+information.
diff --git a/Help/variable/CMAKE_LINK_LIBRARY_FILE_FLAG.rst b/Help/variable/CMAKE_LINK_LIBRARY_FILE_FLAG.rst
new file mode 100644
index 0000000..6858e2c
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_LIBRARY_FILE_FLAG.rst
@@ -0,0 +1,7 @@
+CMAKE_LINK_LIBRARY_FILE_FLAG
+----------------------------
+
+Flag to be used to link a library specified by a path to its file.
+
+The flag will be used before a library file path is given to the
+linker. This is needed only on very few platforms.
diff --git a/Help/variable/CMAKE_LINK_LIBRARY_FLAG.rst b/Help/variable/CMAKE_LINK_LIBRARY_FLAG.rst
new file mode 100644
index 0000000..b5197e4
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_LIBRARY_FLAG.rst
@@ -0,0 +1,7 @@
+CMAKE_LINK_LIBRARY_FLAG
+-----------------------
+
+Flag to be used to link a library into an executable.
+
+The flag will be used to specify a library to link to an executable.
+On most compilers this is ``-l``.
diff --git a/Help/variable/CMAKE_LINK_LIBRARY_SUFFIX.rst b/Help/variable/CMAKE_LINK_LIBRARY_SUFFIX.rst
new file mode 100644
index 0000000..0ddafe8
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_LIBRARY_SUFFIX.rst
@@ -0,0 +1,6 @@
+CMAKE_LINK_LIBRARY_SUFFIX
+-------------------------
+
+The suffix for libraries that you link to.
+
+The suffix to use for the end of a library filename, ``.lib`` on Windows.
diff --git a/Help/variable/CMAKE_LINK_SEARCH_END_STATIC.rst b/Help/variable/CMAKE_LINK_SEARCH_END_STATIC.rst
new file mode 100644
index 0000000..e86f639
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_SEARCH_END_STATIC.rst
@@ -0,0 +1,21 @@
+CMAKE_LINK_SEARCH_END_STATIC
+----------------------------
+
+.. versionadded:: 3.4
+
+End a link line such that static system libraries are used.
+
+Some linkers support switches such as ``-Bstatic`` and ``-Bdynamic`` to
+determine whether to use static or shared libraries for ``-lXXX`` options.
+CMake uses these options to set the link type for libraries whose full
+paths are not known or (in some cases) are in implicit link
+directories for the platform. By default CMake adds an option at the
+end of the library list (if necessary) to set the linker search type
+back to its starting type. This property switches the final linker
+search type to ``-Bstatic`` regardless of how it started.
+
+This variable is used to initialize the target property
+:prop_tgt:`LINK_SEARCH_END_STATIC` for all targets. If set, its
+value is also used by the :command:`try_compile` command.
+
+See also :variable:`CMAKE_LINK_SEARCH_START_STATIC`.
diff --git a/Help/variable/CMAKE_LINK_SEARCH_START_STATIC.rst b/Help/variable/CMAKE_LINK_SEARCH_START_STATIC.rst
new file mode 100644
index 0000000..ab1837c
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_SEARCH_START_STATIC.rst
@@ -0,0 +1,22 @@
+CMAKE_LINK_SEARCH_START_STATIC
+------------------------------
+
+.. versionadded:: 3.4
+
+Assume the linker looks for static libraries by default.
+
+Some linkers support switches such as ``-Bstatic`` and ``-Bdynamic`` to
+determine whether to use static or shared libraries for ``-lXXX`` options.
+CMake uses these options to set the link type for libraries whose full
+paths are not known or (in some cases) are in implicit link
+directories for the platform. By default the linker search type is
+assumed to be ``-Bdynamic`` at the beginning of the library list. This
+property switches the assumption to ``-Bstatic``. It is intended for use
+when linking an executable statically (e.g. with the GNU ``-static``
+option).
+
+This variable is used to initialize the target property
+:prop_tgt:`LINK_SEARCH_START_STATIC` for all targets. If set, its
+value is also used by the :command:`try_compile` command.
+
+See also :variable:`CMAKE_LINK_SEARCH_END_STATIC`.
diff --git a/Help/variable/CMAKE_LINK_WHAT_YOU_USE.rst b/Help/variable/CMAKE_LINK_WHAT_YOU_USE.rst
new file mode 100644
index 0000000..06b3aa8
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_WHAT_YOU_USE.rst
@@ -0,0 +1,8 @@
+CMAKE_LINK_WHAT_YOU_USE
+---------------------------------
+
+.. versionadded:: 3.7
+
+Default value for :prop_tgt:`LINK_WHAT_YOU_USE` target property.
+This variable is used to initialize the property on each target as it is
+created.
diff --git a/Help/variable/CMAKE_MACOSX_BUNDLE.rst b/Help/variable/CMAKE_MACOSX_BUNDLE.rst
new file mode 100644
index 0000000..43ddff5
--- /dev/null
+++ b/Help/variable/CMAKE_MACOSX_BUNDLE.rst
@@ -0,0 +1,10 @@
+CMAKE_MACOSX_BUNDLE
+-------------------
+
+Default value for :prop_tgt:`MACOSX_BUNDLE` of targets.
+
+This variable is used to initialize the :prop_tgt:`MACOSX_BUNDLE` property on
+all the targets. See that target property for additional information.
+
+This variable is set to ``ON`` by default if :variable:`CMAKE_SYSTEM_NAME`
+equals to :ref:`iOS, tvOS or watchOS <Cross Compiling for iOS, tvOS, or watchOS>`.
diff --git a/Help/variable/CMAKE_MACOSX_RPATH.rst b/Help/variable/CMAKE_MACOSX_RPATH.rst
new file mode 100644
index 0000000..2fc648d
--- /dev/null
+++ b/Help/variable/CMAKE_MACOSX_RPATH.rst
@@ -0,0 +1,7 @@
+CMAKE_MACOSX_RPATH
+-------------------
+
+Whether to use rpaths on macOS and iOS.
+
+This variable is used to initialize the :prop_tgt:`MACOSX_RPATH` property on
+all targets.
diff --git a/Help/variable/CMAKE_MAJOR_VERSION.rst b/Help/variable/CMAKE_MAJOR_VERSION.rst
new file mode 100644
index 0000000..079ad70
--- /dev/null
+++ b/Help/variable/CMAKE_MAJOR_VERSION.rst
@@ -0,0 +1,5 @@
+CMAKE_MAJOR_VERSION
+-------------------
+
+First version number component of the :variable:`CMAKE_VERSION`
+variable.
diff --git a/Help/variable/CMAKE_MAKE_PROGRAM.rst b/Help/variable/CMAKE_MAKE_PROGRAM.rst
new file mode 100644
index 0000000..a3c8b7c
--- /dev/null
+++ b/Help/variable/CMAKE_MAKE_PROGRAM.rst
@@ -0,0 +1,64 @@
+CMAKE_MAKE_PROGRAM
+------------------
+
+Tool that can launch the native build system.
+The value may be the full path to an executable or just the tool
+name if it is expected to be in the ``PATH``.
+
+The tool selected depends on the :variable:`CMAKE_GENERATOR` used
+to configure the project:
+
+* The :ref:`Makefile Generators` set this to ``make``, ``gmake``, or
+ a generator-specific tool (e.g. ``nmake`` for :generator:`NMake Makefiles`).
+
+ These generators store ``CMAKE_MAKE_PROGRAM`` in the CMake cache
+ so that it may be edited by the user.
+
+* The :generator:`Ninja` generator sets this to ``ninja``.
+
+ This generator stores ``CMAKE_MAKE_PROGRAM`` in the CMake cache
+ so that it may be edited by the user.
+
+* The :generator:`Xcode` generator sets this to ``xcodebuild``.
+
+ This generator prefers to lookup the build tool at build time
+ rather than to store ``CMAKE_MAKE_PROGRAM`` in the CMake cache
+ ahead of time. This is because ``xcodebuild`` is easy to find.
+
+ For compatibility with versions of CMake prior to 3.2, if
+ a user or project explicitly adds ``CMAKE_MAKE_PROGRAM`` to
+ the CMake cache then CMake will use the specified value.
+
+* The :ref:`Visual Studio Generators` set this to the full path to
+ ``MSBuild.exe`` (VS >= 10), ``devenv.com`` (VS 7,8,9), or
+ ``VCExpress.exe`` (VS Express 8,9).
+ (See also variables
+ :variable:`CMAKE_VS_MSBUILD_COMMAND` and
+ :variable:`CMAKE_VS_DEVENV_COMMAND`.
+
+ These generators prefer to lookup the build tool at build time
+ rather than to store ``CMAKE_MAKE_PROGRAM`` in the CMake cache
+ ahead of time. This is because the tools are version-specific
+ and can be located using the Windows Registry. It is also
+ necessary because the proper build tool may depend on the
+ project content (e.g. the Intel Fortran plugin to VS 10 and 11
+ requires ``devenv.com`` to build its ``.vfproj`` project files
+ even though ``MSBuild.exe`` is normally preferred to support
+ the :variable:`CMAKE_GENERATOR_TOOLSET`).
+
+ For compatibility with versions of CMake prior to 3.0, if
+ a user or project explicitly adds ``CMAKE_MAKE_PROGRAM`` to
+ the CMake cache then CMake will use the specified value if
+ possible.
+
+* The :generator:`Green Hills MULTI` generator sets this to the full
+ path to ``gbuild.exe(Windows)`` or ``gbuild(Linux)`` based upon
+ the toolset being used.
+
+ Once the generator has initialized a particular value for this
+ variable, changing the value has undefined behavior.
+
+The ``CMAKE_MAKE_PROGRAM`` variable is set for use by project code.
+The value is also used by the :manual:`cmake(1)` ``--build`` and
+:manual:`ctest(1)` ``--build-and-test`` tools to launch the native
+build process.
diff --git a/Help/variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG.rst b/Help/variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG.rst
new file mode 100644
index 0000000..ed29afe
--- /dev/null
+++ b/Help/variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG.rst
@@ -0,0 +1,8 @@
+CMAKE_MAP_IMPORTED_CONFIG_<CONFIG>
+----------------------------------
+
+Default value for :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` of targets.
+
+This variable is used to initialize the
+:prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` property on all the targets. See
+that target property for additional information.
diff --git a/Help/variable/CMAKE_MATCH_COUNT.rst b/Help/variable/CMAKE_MATCH_COUNT.rst
new file mode 100644
index 0000000..deeec8b
--- /dev/null
+++ b/Help/variable/CMAKE_MATCH_COUNT.rst
@@ -0,0 +1,11 @@
+CMAKE_MATCH_COUNT
+-----------------
+
+.. versionadded:: 3.2
+
+The number of matches with the last regular expression.
+
+When a regular expression match is used, CMake fills in
+:variable:`CMAKE_MATCH_<n>` variables with the match contents.
+The ``CMAKE_MATCH_COUNT`` variable holds the number of match
+expressions when these are filled.
diff --git a/Help/variable/CMAKE_MATCH_n.rst b/Help/variable/CMAKE_MATCH_n.rst
new file mode 100644
index 0000000..a92788e
--- /dev/null
+++ b/Help/variable/CMAKE_MATCH_n.rst
@@ -0,0 +1,12 @@
+CMAKE_MATCH_<n>
+---------------
+
+.. versionadded:: 3.9
+
+Capture group ``<n>`` matched by the last regular expression, for groups
+0 through 9. Group 0 is the entire match. Groups 1 through 9 are the
+subexpressions captured by ``()`` syntax.
+
+When a regular expression match is used, CMake fills in ``CMAKE_MATCH_<n>``
+variables with the match contents. The :variable:`CMAKE_MATCH_COUNT`
+variable holds the number of match expressions when these are filled.
diff --git a/Help/variable/CMAKE_MAXIMUM_RECURSION_DEPTH.rst b/Help/variable/CMAKE_MAXIMUM_RECURSION_DEPTH.rst
new file mode 100644
index 0000000..59c60d3
--- /dev/null
+++ b/Help/variable/CMAKE_MAXIMUM_RECURSION_DEPTH.rst
@@ -0,0 +1,35 @@
+CMAKE_MAXIMUM_RECURSION_DEPTH
+-----------------------------
+
+.. versionadded:: 3.14
+
+Maximum recursion depth for CMake scripts. It is intended to be set on the
+command line with ``-DCMAKE_MAXIMUM_RECURSION_DEPTH=<x>``, or within
+``CMakeLists.txt`` by projects that require a large recursion depth. Projects
+that set this variable should provide the user with a way to override it. For
+example:
+
+.. code-block:: cmake
+
+ # About to perform deeply recursive actions
+ if(NOT CMAKE_MAXIMUM_RECURSION_DEPTH)
+ set(CMAKE_MAXIMUM_RECURSION_DEPTH 2000)
+ endif()
+
+If it is not set, or is set to a non-integer value, a sensible default limit is
+used. If the recursion limit is reached, the script terminates immediately with
+a fatal error.
+
+Calling any of the following commands increases the recursion depth:
+
+* :command:`include`
+* :command:`find_package`
+* :command:`add_subdirectory`
+* :command:`try_compile`
+* :command:`ctest_read_custom_files`
+* :command:`ctest_run_script` (unless ``NEW_PROCESS`` is specified)
+* User-defined :command:`function`'s and :command:`macro`'s (note that
+ :command:`function` and :command:`macro` themselves don't increase recursion
+ depth)
+* Reading or writing variables that are being watched by a
+ :command:`variable_watch`
diff --git a/Help/variable/CMAKE_MESSAGE_CONTEXT.rst b/Help/variable/CMAKE_MESSAGE_CONTEXT.rst
new file mode 100644
index 0000000..41ace43
--- /dev/null
+++ b/Help/variable/CMAKE_MESSAGE_CONTEXT.rst
@@ -0,0 +1,64 @@
+CMAKE_MESSAGE_CONTEXT
+---------------------
+
+.. versionadded:: 3.17
+
+When enabled by the :manual:`cmake <cmake(1)>` ``--log-context`` command line
+option or the :variable:`CMAKE_MESSAGE_CONTEXT_SHOW` variable, the
+:command:`message` command converts the ``CMAKE_MESSAGE_CONTEXT`` list into a
+dot-separated string surrounded by square brackets and prepends it to each line
+for messages of log levels ``NOTICE`` and below.
+
+For logging contexts to work effectively, projects should generally
+``APPEND`` and ``POP_BACK`` an item to the current value of
+``CMAKE_MESSAGE_CONTEXT`` rather than replace it.
+Projects should not assume the message context at the top of the source tree
+is empty, as there are scenarios where the context might have already been set
+(e.g. hierarchical projects).
+
+.. warning::
+
+ Valid context names are restricted to anything that could be used
+ as a CMake variable name. All names that begin with an underscore
+ or the string ``cmake_`` are also reserved for use by CMake and
+ should not be used by projects.
+
+Example:
+
+.. code-block:: cmake
+
+ function(bar)
+ list(APPEND CMAKE_MESSAGE_CONTEXT "bar")
+ message(VERBOSE "bar VERBOSE message")
+ endfunction()
+
+ function(baz)
+ list(APPEND CMAKE_MESSAGE_CONTEXT "baz")
+ message(DEBUG "baz DEBUG message")
+ endfunction()
+
+ function(foo)
+ list(APPEND CMAKE_MESSAGE_CONTEXT "foo")
+ bar()
+ message(TRACE "foo TRACE message")
+ baz()
+ endfunction()
+
+ list(APPEND CMAKE_MESSAGE_CONTEXT "top")
+
+ message(VERBOSE "Before `foo`")
+ foo()
+ message(VERBOSE "After `foo`")
+
+ list(POP_BACK CMAKE_MESSAGE_CONTEXT)
+
+
+Which results in the following output:
+
+.. code-block:: none
+
+ -- [top] Before `foo`
+ -- [top.foo.bar] bar VERBOSE message
+ -- [top.foo] foo TRACE message
+ -- [top.foo.baz] baz DEBUG message
+ -- [top] After `foo`
diff --git a/Help/variable/CMAKE_MESSAGE_CONTEXT_SHOW.rst b/Help/variable/CMAKE_MESSAGE_CONTEXT_SHOW.rst
new file mode 100644
index 0000000..382e9ff
--- /dev/null
+++ b/Help/variable/CMAKE_MESSAGE_CONTEXT_SHOW.rst
@@ -0,0 +1,17 @@
+CMAKE_MESSAGE_CONTEXT_SHOW
+--------------------------
+
+.. versionadded:: 3.17
+
+Setting this variable to true enables showing a context with each line
+logged by the :command:`message` command (see :variable:`CMAKE_MESSAGE_CONTEXT`
+for how the context itself is specified).
+
+This variable is an alternative to providing the ``--log-context`` option
+on the :manual:`cmake <cmake(1)>` command line. Whereas the command line
+option will apply only to that one CMake run, setting
+``CMAKE_MESSAGE_CONTEXT_SHOW`` to true as a cache variable will ensure that
+subsequent CMake runs will continue to show the message context.
+
+Projects should not set ``CMAKE_MESSAGE_CONTEXT_SHOW``. It is intended for
+users so that they may control whether or not to include context with messages.
diff --git a/Help/variable/CMAKE_MESSAGE_INDENT.rst b/Help/variable/CMAKE_MESSAGE_INDENT.rst
new file mode 100644
index 0000000..c6263d2
--- /dev/null
+++ b/Help/variable/CMAKE_MESSAGE_INDENT.rst
@@ -0,0 +1,34 @@
+CMAKE_MESSAGE_INDENT
+--------------------
+
+.. versionadded:: 3.16
+
+The :command:`message` command joins the strings from this list and for
+log levels of ``NOTICE`` and below, it prepends the resultant string to
+each line of the message.
+
+Example:
+
+.. code-block:: cmake
+
+ list(APPEND listVar one two three)
+
+ message(VERBOSE [[Collected items in the "listVar":]])
+ list(APPEND CMAKE_MESSAGE_INDENT " ")
+
+ foreach(item IN LISTS listVar)
+ message(VERBOSE ${item})
+ endforeach()
+
+ list(POP_BACK CMAKE_MESSAGE_INDENT)
+ message(VERBOSE "No more indent")
+
+Which results in the following output:
+
+.. code-block:: none
+
+ -- Collected items in the "listVar":
+ -- one
+ -- two
+ -- three
+ -- No more indent
diff --git a/Help/variable/CMAKE_MESSAGE_LOG_LEVEL.rst b/Help/variable/CMAKE_MESSAGE_LOG_LEVEL.rst
new file mode 100644
index 0000000..3b45d1d
--- /dev/null
+++ b/Help/variable/CMAKE_MESSAGE_LOG_LEVEL.rst
@@ -0,0 +1,17 @@
+CMAKE_MESSAGE_LOG_LEVEL
+-----------------------
+
+.. versionadded:: 3.17
+
+When set, this variable specifies the logging level used by the
+:command:`message` command. Valid values are the same as those for the
+``--log-level`` command line option of the :manual:`cmake(1)` program.
+If this variable is set and the ``--log-level`` command line option is
+given, the command line option takes precedence.
+
+The main advantage to using this variable is to make a log level persist
+between CMake runs. Setting it as a cache variable will ensure that
+subsequent CMake runs will continue to use the chosen log level.
+
+Projects should not set this variable, it is intended for users so that
+they may control the log level according to their own needs.
diff --git a/Help/variable/CMAKE_MFC_FLAG.rst b/Help/variable/CMAKE_MFC_FLAG.rst
new file mode 100644
index 0000000..118e9c6
--- /dev/null
+++ b/Help/variable/CMAKE_MFC_FLAG.rst
@@ -0,0 +1,20 @@
+CMAKE_MFC_FLAG
+--------------
+
+Use the MFC library for an executable or dll.
+
+Enables the use of the Microsoft Foundation Classes (MFC).
+It should be set to ``1`` for the static MFC library, and
+``2`` for the shared MFC library. This is used in Visual Studio
+project files.
+
+Usage example:
+
+.. code-block:: cmake
+
+ add_definitions(-D_AFXDLL)
+ set(CMAKE_MFC_FLAG 2)
+ add_executable(CMakeSetup WIN32 ${SRCS})
+
+Contents of ``CMAKE_MFC_FLAG`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/variable/CMAKE_MINIMUM_REQUIRED_VERSION.rst b/Help/variable/CMAKE_MINIMUM_REQUIRED_VERSION.rst
new file mode 100644
index 0000000..f466468
--- /dev/null
+++ b/Help/variable/CMAKE_MINIMUM_REQUIRED_VERSION.rst
@@ -0,0 +1,5 @@
+CMAKE_MINIMUM_REQUIRED_VERSION
+------------------------------
+
+The ``<min>`` version of CMake given to the most recent call to the
+:command:`cmake_minimum_required(VERSION)` command.
diff --git a/Help/variable/CMAKE_MINOR_VERSION.rst b/Help/variable/CMAKE_MINOR_VERSION.rst
new file mode 100644
index 0000000..f67cfb9
--- /dev/null
+++ b/Help/variable/CMAKE_MINOR_VERSION.rst
@@ -0,0 +1,5 @@
+CMAKE_MINOR_VERSION
+-------------------
+
+Second version number component of the :variable:`CMAKE_VERSION`
+variable.
diff --git a/Help/variable/CMAKE_MODULE_LINKER_FLAGS.rst b/Help/variable/CMAKE_MODULE_LINKER_FLAGS.rst
new file mode 100644
index 0000000..6372bbd
--- /dev/null
+++ b/Help/variable/CMAKE_MODULE_LINKER_FLAGS.rst
@@ -0,0 +1,6 @@
+CMAKE_MODULE_LINKER_FLAGS
+-------------------------
+
+Linker flags to be used to create modules.
+
+These flags will be used by the linker when creating a module.
diff --git a/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst b/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst
new file mode 100644
index 0000000..393263e
--- /dev/null
+++ b/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst
@@ -0,0 +1,6 @@
+CMAKE_MODULE_LINKER_FLAGS_<CONFIG>
+----------------------------------
+
+Flags to be used when linking a module.
+
+Same as ``CMAKE_C_FLAGS_*`` but used by the linker when creating modules.
diff --git a/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG_INIT.rst b/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG_INIT.rst
new file mode 100644
index 0000000..e8a6401
--- /dev/null
+++ b/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG_INIT.rst
@@ -0,0 +1,12 @@
+CMAKE_MODULE_LINKER_FLAGS_<CONFIG>_INIT
+---------------------------------------
+
+.. versionadded:: 3.7
+
+Value used to initialize the :variable:`CMAKE_MODULE_LINKER_FLAGS_<CONFIG>`
+cache entry the first time a build tree is configured.
+This variable is meant to be set by a :variable:`toolchain file
+<CMAKE_TOOLCHAIN_FILE>`. CMake may prepend or append content to
+the value based on the environment and target platform.
+
+See also :variable:`CMAKE_MODULE_LINKER_FLAGS_INIT`.
diff --git a/Help/variable/CMAKE_MODULE_LINKER_FLAGS_INIT.rst b/Help/variable/CMAKE_MODULE_LINKER_FLAGS_INIT.rst
new file mode 100644
index 0000000..d59e9bf
--- /dev/null
+++ b/Help/variable/CMAKE_MODULE_LINKER_FLAGS_INIT.rst
@@ -0,0 +1,13 @@
+CMAKE_MODULE_LINKER_FLAGS_INIT
+------------------------------
+
+.. versionadded:: 3.7
+
+Value used to initialize the :variable:`CMAKE_MODULE_LINKER_FLAGS`
+cache entry the first time a build tree is configured.
+This variable is meant to be set by a :variable:`toolchain file
+<CMAKE_TOOLCHAIN_FILE>`. CMake may prepend or append content to
+the value based on the environment and target platform.
+
+See also the configuration-specific variable
+:variable:`CMAKE_MODULE_LINKER_FLAGS_<CONFIG>_INIT`.
diff --git a/Help/variable/CMAKE_MODULE_PATH.rst b/Help/variable/CMAKE_MODULE_PATH.rst
new file mode 100644
index 0000000..4dcf6b5
--- /dev/null
+++ b/Help/variable/CMAKE_MODULE_PATH.rst
@@ -0,0 +1,7 @@
+CMAKE_MODULE_PATH
+-----------------
+
+:ref:`Semicolon-separated list <CMake Language Lists>` of directories specifying a search path
+for CMake modules to be loaded by the :command:`include` or
+:command:`find_package` commands before checking the default modules that come
+with CMake. By default it is empty, it is intended to be set by the project.
diff --git a/Help/variable/CMAKE_MSVCIDE_RUN_PATH.rst b/Help/variable/CMAKE_MSVCIDE_RUN_PATH.rst
new file mode 100644
index 0000000..721ceaa
--- /dev/null
+++ b/Help/variable/CMAKE_MSVCIDE_RUN_PATH.rst
@@ -0,0 +1,12 @@
+CMAKE_MSVCIDE_RUN_PATH
+----------------------
+
+.. versionadded:: 3.10
+
+Extra PATH locations that should be used when executing
+:command:`add_custom_command` or :command:`add_custom_target` when using the
+:generator:`Visual Studio 9 2008` (or above) generator. This allows
+for running commands and using dll's that the IDE environment is not aware of.
+
+If not set explicitly the value is initialized by the ``CMAKE_MSVCIDE_RUN_PATH``
+environment variable, if set, and otherwise left empty.
diff --git a/Help/variable/CMAKE_MSVC_RUNTIME_LIBRARY.rst b/Help/variable/CMAKE_MSVC_RUNTIME_LIBRARY.rst
new file mode 100644
index 0000000..14806e6
--- /dev/null
+++ b/Help/variable/CMAKE_MSVC_RUNTIME_LIBRARY.rst
@@ -0,0 +1,34 @@
+CMAKE_MSVC_RUNTIME_LIBRARY
+--------------------------
+
+.. versionadded:: 3.15
+
+Select the MSVC runtime library for use by compilers targeting the MSVC ABI.
+This variable is used to initialize the :prop_tgt:`MSVC_RUNTIME_LIBRARY`
+property on all targets as they are created. It is also propagated by
+calls to the :command:`try_compile` command into the test project.
+
+The allowed values are:
+
+.. include:: ../prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt
+
+Use :manual:`generator expressions <cmake-generator-expressions(7)>` to
+support per-configuration specification. For example, the code:
+
+.. code-block:: cmake
+
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+
+selects for all following targets a multi-threaded statically-linked runtime
+library with or without debug information depending on the configuration.
+
+If this variable is not set then the :prop_tgt:`MSVC_RUNTIME_LIBRARY` target
+property will not be set automatically. If that property is not set then
+CMake uses the default value ``MultiThreaded$<$<CONFIG:Debug>:Debug>DLL``
+to select a MSVC runtime library.
+
+.. note::
+
+ This variable has effect only when policy :policy:`CMP0091` is set to ``NEW``
+ prior to the first :command:`project` or :command:`enable_language` command
+ that enables a language using a compiler targeting the MSVC ABI.
diff --git a/Help/variable/CMAKE_NETRC.rst b/Help/variable/CMAKE_NETRC.rst
new file mode 100644
index 0000000..2c64a81
--- /dev/null
+++ b/Help/variable/CMAKE_NETRC.rst
@@ -0,0 +1,11 @@
+CMAKE_NETRC
+-----------
+
+.. versionadded:: 3.11
+
+This variable is used to initialize the ``NETRC`` option for
+:command:`file(DOWNLOAD)` and :command:`file(UPLOAD)` commands and the
+module :module:`ExternalProject`. See those commands for additional
+information.
+
+The local option takes precedence over this variable.
diff --git a/Help/variable/CMAKE_NETRC_FILE.rst b/Help/variable/CMAKE_NETRC_FILE.rst
new file mode 100644
index 0000000..97a645e
--- /dev/null
+++ b/Help/variable/CMAKE_NETRC_FILE.rst
@@ -0,0 +1,11 @@
+CMAKE_NETRC_FILE
+----------------
+
+.. versionadded:: 3.11
+
+This variable is used to initialize the ``NETRC_FILE`` option for
+:command:`file(DOWNLOAD)` and :command:`file(UPLOAD)` commands and the
+module :module:`ExternalProject`. See those commands for additional
+information.
+
+The local option takes precedence over this variable.
diff --git a/Help/variable/CMAKE_NINJA_OUTPUT_PATH_PREFIX.rst b/Help/variable/CMAKE_NINJA_OUTPUT_PATH_PREFIX.rst
new file mode 100644
index 0000000..a8c4035
--- /dev/null
+++ b/Help/variable/CMAKE_NINJA_OUTPUT_PATH_PREFIX.rst
@@ -0,0 +1,29 @@
+CMAKE_NINJA_OUTPUT_PATH_PREFIX
+------------------------------
+
+.. versionadded:: 3.6
+
+Set output files path prefix for the :generator:`Ninja` generator.
+
+Every output files listed in the generated ``build.ninja`` will be
+prefixed by the contents of this variable (a trailing slash is
+appended if missing). This is useful when the generated ninja file is
+meant to be embedded as a ``subninja`` file into a *super* ninja
+project. For example, a ninja build file generated with a command
+like::
+
+ cd top-build-dir/sub &&
+ cmake -G Ninja -DCMAKE_NINJA_OUTPUT_PATH_PREFIX=sub/ path/to/source
+
+can be embedded in ``top-build-dir/build.ninja`` with a directive like
+this::
+
+ subninja sub/build.ninja
+
+The ``auto-regeneration`` rule in ``top-build-dir/build.ninja`` must have an
+order-only dependency on ``sub/build.ninja``.
+
+.. note::
+ When ``CMAKE_NINJA_OUTPUT_PATH_PREFIX`` is set, the project generated
+ by CMake cannot be used as a standalone project. No default targets
+ are specified.
diff --git a/Help/variable/CMAKE_NOT_USING_CONFIG_FLAGS.rst b/Help/variable/CMAKE_NOT_USING_CONFIG_FLAGS.rst
new file mode 100644
index 0000000..98960c5
--- /dev/null
+++ b/Help/variable/CMAKE_NOT_USING_CONFIG_FLAGS.rst
@@ -0,0 +1,7 @@
+CMAKE_NOT_USING_CONFIG_FLAGS
+----------------------------
+
+Skip ``_BUILD_TYPE`` flags if true.
+
+This is an internal flag used by the generators in CMake to tell CMake
+to skip the ``_BUILD_TYPE`` flags.
diff --git a/Help/variable/CMAKE_NO_BUILTIN_CHRPATH.rst b/Help/variable/CMAKE_NO_BUILTIN_CHRPATH.rst
new file mode 100644
index 0000000..b9b045e
--- /dev/null
+++ b/Help/variable/CMAKE_NO_BUILTIN_CHRPATH.rst
@@ -0,0 +1,17 @@
+CMAKE_NO_BUILTIN_CHRPATH
+------------------------
+
+Do not use the builtin binary editor to fix runtime library search
+paths on installation.
+
+When an ELF or XCOFF binary needs to have a different runtime library
+search path after installation than it does in the build tree, CMake uses
+a builtin editor to change the runtime search path in the installed copy.
+If this variable is set to true then CMake will relink the binary before
+installation instead of using its builtin editor.
+
+.. versionadded:: 3.20
+
+ This variable also applies to XCOFF binaries' LIBPATH. Prior to the
+ addition of the XCOFF editor in CMake 3.20, this variable applied only
+ to ELF binaries' RPATH/RUNPATH.
diff --git a/Help/variable/CMAKE_NO_SYSTEM_FROM_IMPORTED.rst b/Help/variable/CMAKE_NO_SYSTEM_FROM_IMPORTED.rst
new file mode 100644
index 0000000..61e04b4
--- /dev/null
+++ b/Help/variable/CMAKE_NO_SYSTEM_FROM_IMPORTED.rst
@@ -0,0 +1,8 @@
+CMAKE_NO_SYSTEM_FROM_IMPORTED
+-----------------------------
+
+Default value for :prop_tgt:`NO_SYSTEM_FROM_IMPORTED` of targets.
+
+This variable is used to initialize the :prop_tgt:`NO_SYSTEM_FROM_IMPORTED`
+property on all the targets. See that target property for additional
+information.
diff --git a/Help/variable/CMAKE_OBJCXX_EXTENSIONS.rst b/Help/variable/CMAKE_OBJCXX_EXTENSIONS.rst
new file mode 100644
index 0000000..b5225ea
--- /dev/null
+++ b/Help/variable/CMAKE_OBJCXX_EXTENSIONS.rst
@@ -0,0 +1,13 @@
+CMAKE_OBJCXX_EXTENSIONS
+-----------------------
+
+.. versionadded:: 3.16
+
+Default value for :prop_tgt:`OBJCXX_EXTENSIONS` property of targets.
+
+This variable is used to initialize the :prop_tgt:`OBJCXX_EXTENSIONS`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_OBJCXX_STANDARD.rst b/Help/variable/CMAKE_OBJCXX_STANDARD.rst
new file mode 100644
index 0000000..98e4624
--- /dev/null
+++ b/Help/variable/CMAKE_OBJCXX_STANDARD.rst
@@ -0,0 +1,13 @@
+CMAKE_OBJCXX_STANDARD
+---------------------
+
+.. versionadded:: 3.16
+
+Default value for :prop_tgt:`OBJCXX_STANDARD` property of targets.
+
+This variable is used to initialize the :prop_tgt:`OBJCXX_STANDARD`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_OBJCXX_STANDARD_REQUIRED.rst b/Help/variable/CMAKE_OBJCXX_STANDARD_REQUIRED.rst
new file mode 100644
index 0000000..4b5e77c
--- /dev/null
+++ b/Help/variable/CMAKE_OBJCXX_STANDARD_REQUIRED.rst
@@ -0,0 +1,13 @@
+CMAKE_OBJCXX_STANDARD_REQUIRED
+------------------------------
+
+.. versionadded:: 3.16
+
+Default value for :prop_tgt:`OBJCXX_STANDARD_REQUIRED` property of targets.
+
+This variable is used to initialize the :prop_tgt:`OBJCXX_STANDARD_REQUIRED`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_OBJC_EXTENSIONS.rst b/Help/variable/CMAKE_OBJC_EXTENSIONS.rst
new file mode 100644
index 0000000..d6e3c7d
--- /dev/null
+++ b/Help/variable/CMAKE_OBJC_EXTENSIONS.rst
@@ -0,0 +1,13 @@
+CMAKE_OBJC_EXTENSIONS
+---------------------
+
+.. versionadded:: 3.16
+
+Default value for :prop_tgt:`OBJC_EXTENSIONS` property of targets.
+
+This variable is used to initialize the :prop_tgt:`OBJC_EXTENSIONS`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_OBJC_STANDARD.rst b/Help/variable/CMAKE_OBJC_STANDARD.rst
new file mode 100644
index 0000000..fde367d
--- /dev/null
+++ b/Help/variable/CMAKE_OBJC_STANDARD.rst
@@ -0,0 +1,13 @@
+CMAKE_OBJC_STANDARD
+-------------------
+
+.. versionadded:: 3.16
+
+Default value for :prop_tgt:`OBJC_STANDARD` property of targets.
+
+This variable is used to initialize the :prop_tgt:`OBJC_STANDARD`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_OBJC_STANDARD_REQUIRED.rst b/Help/variable/CMAKE_OBJC_STANDARD_REQUIRED.rst
new file mode 100644
index 0000000..8d26d95
--- /dev/null
+++ b/Help/variable/CMAKE_OBJC_STANDARD_REQUIRED.rst
@@ -0,0 +1,13 @@
+CMAKE_OBJC_STANDARD_REQUIRED
+----------------------------
+
+.. versionadded:: 3.16
+
+Default value for :prop_tgt:`OBJC_STANDARD_REQUIRED` property of targets.
+
+This variable is used to initialize the :prop_tgt:`OBJC_STANDARD_REQUIRED`
+property on all targets. See that target property for additional
+information.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_OBJECT_PATH_MAX.rst b/Help/variable/CMAKE_OBJECT_PATH_MAX.rst
new file mode 100644
index 0000000..9e30cbb
--- /dev/null
+++ b/Help/variable/CMAKE_OBJECT_PATH_MAX.rst
@@ -0,0 +1,16 @@
+CMAKE_OBJECT_PATH_MAX
+---------------------
+
+Maximum object file full-path length allowed by native build tools.
+
+CMake computes for every source file an object file name that is
+unique to the source file and deterministic with respect to the full
+path to the source file. This allows multiple source files in a
+target to share the same name if they lie in different directories
+without rebuilding when one is added or removed. However, it can
+produce long full paths in a few cases, so CMake shortens the path
+using a hashing scheme when the full path to an object file exceeds a
+limit. CMake has a built-in limit for each platform that is
+sufficient for common tools, but some native tools may have a lower
+limit. This variable may be set to specify the limit explicitly. The
+value must be an integer no less than 128.
diff --git a/Help/variable/CMAKE_OPTIMIZE_DEPENDENCIES.rst b/Help/variable/CMAKE_OPTIMIZE_DEPENDENCIES.rst
new file mode 100644
index 0000000..0ffb902
--- /dev/null
+++ b/Help/variable/CMAKE_OPTIMIZE_DEPENDENCIES.rst
@@ -0,0 +1,6 @@
+CMAKE_OPTIMIZE_DEPENDENCIES
+---------------------------
+
+.. versionadded:: 3.19
+
+Initializes the :prop_tgt:`OPTIMIZE_DEPENDENCIES` target property.
diff --git a/Help/variable/CMAKE_OSX_ARCHITECTURES.rst b/Help/variable/CMAKE_OSX_ARCHITECTURES.rst
new file mode 100644
index 0000000..fdaca28
--- /dev/null
+++ b/Help/variable/CMAKE_OSX_ARCHITECTURES.rst
@@ -0,0 +1,10 @@
+CMAKE_OSX_ARCHITECTURES
+-----------------------
+
+Target specific architectures for macOS and iOS.
+
+This variable is used to initialize the :prop_tgt:`OSX_ARCHITECTURES`
+property on each target as it is created. See that target property
+for additional information.
+
+.. include:: CMAKE_OSX_VARIABLE.txt
diff --git a/Help/variable/CMAKE_OSX_DEPLOYMENT_TARGET.rst b/Help/variable/CMAKE_OSX_DEPLOYMENT_TARGET.rst
new file mode 100644
index 0000000..9df5edd
--- /dev/null
+++ b/Help/variable/CMAKE_OSX_DEPLOYMENT_TARGET.rst
@@ -0,0 +1,15 @@
+CMAKE_OSX_DEPLOYMENT_TARGET
+---------------------------
+
+Specify the minimum version of the target platform (e.g. macOS or iOS)
+on which the target binaries are to be deployed. CMake uses this
+variable value for the ``-mmacosx-version-min`` flag or their respective
+target platform equivalents. For older Xcode versions that shipped
+multiple macOS SDKs this variable also helps to choose the SDK in case
+:variable:`CMAKE_OSX_SYSROOT` is unset.
+
+If not set explicitly the value is initialized by the
+``MACOSX_DEPLOYMENT_TARGET`` environment variable, if set,
+and otherwise computed based on the host platform.
+
+.. include:: CMAKE_OSX_VARIABLE.txt
diff --git a/Help/variable/CMAKE_OSX_SYSROOT.rst b/Help/variable/CMAKE_OSX_SYSROOT.rst
new file mode 100644
index 0000000..db9fccd
--- /dev/null
+++ b/Help/variable/CMAKE_OSX_SYSROOT.rst
@@ -0,0 +1,13 @@
+CMAKE_OSX_SYSROOT
+-----------------
+
+Specify the location or name of the macOS platform SDK to be used.
+CMake uses this value to compute the value of the ``-isysroot`` flag
+or equivalent and to help the ``find_*`` commands locate files in
+the SDK.
+
+If not set explicitly the value is initialized by the ``SDKROOT``
+environment variable, if set, and otherwise computed based on the
+:variable:`CMAKE_OSX_DEPLOYMENT_TARGET` or the host platform.
+
+.. include:: CMAKE_OSX_VARIABLE.txt
diff --git a/Help/variable/CMAKE_OSX_VARIABLE.txt b/Help/variable/CMAKE_OSX_VARIABLE.txt
new file mode 100644
index 0000000..16f3c1a
--- /dev/null
+++ b/Help/variable/CMAKE_OSX_VARIABLE.txt
@@ -0,0 +1,11 @@
+The value of this variable should be set prior to the first
+:command:`project` or :command:`enable_language` command invocation
+because it may influence configuration of the toolchain and flags.
+It is intended to be set locally by the user creating a build tree.
+This variable should be set as a ``CACHE`` entry (or else CMake may
+remove it while initializing a cache entry of the same name).
+
+Despite the ``OSX`` part in the variable name(s) they apply also to
+other SDKs than macOS like iOS, tvOS, or watchOS.
+
+This variable is ignored on platforms other than Apple.
diff --git a/Help/variable/CMAKE_PARENT_LIST_FILE.rst b/Help/variable/CMAKE_PARENT_LIST_FILE.rst
new file mode 100644
index 0000000..cfd8608
--- /dev/null
+++ b/Help/variable/CMAKE_PARENT_LIST_FILE.rst
@@ -0,0 +1,9 @@
+CMAKE_PARENT_LIST_FILE
+----------------------
+
+Full path to the CMake file that included the current one.
+
+While processing a CMake file loaded by :command:`include` or
+:command:`find_package` this variable contains the full path to the file
+including it. The top of the include stack is always the ``CMakeLists.txt``
+for the current directory. See also :variable:`CMAKE_CURRENT_LIST_FILE`.
diff --git a/Help/variable/CMAKE_PATCH_VERSION.rst b/Help/variable/CMAKE_PATCH_VERSION.rst
new file mode 100644
index 0000000..991ae76
--- /dev/null
+++ b/Help/variable/CMAKE_PATCH_VERSION.rst
@@ -0,0 +1,5 @@
+CMAKE_PATCH_VERSION
+-------------------
+
+Third version number component of the :variable:`CMAKE_VERSION`
+variable.
diff --git a/Help/variable/CMAKE_PCH_INSTANTIATE_TEMPLATES.rst b/Help/variable/CMAKE_PCH_INSTANTIATE_TEMPLATES.rst
new file mode 100644
index 0000000..9867f17
--- /dev/null
+++ b/Help/variable/CMAKE_PCH_INSTANTIATE_TEMPLATES.rst
@@ -0,0 +1,7 @@
+CMAKE_PCH_INSTANTIATE_TEMPLATES
+-------------------------------
+
+.. versionadded:: 3.19
+
+This variable is used to initialize the :prop_tgt:`PCH_INSTANTIATE_TEMPLATES`
+property of targets when they are created.
diff --git a/Help/variable/CMAKE_PCH_WARN_INVALID.rst b/Help/variable/CMAKE_PCH_WARN_INVALID.rst
new file mode 100644
index 0000000..457a428
--- /dev/null
+++ b/Help/variable/CMAKE_PCH_WARN_INVALID.rst
@@ -0,0 +1,7 @@
+CMAKE_PCH_WARN_INVALID
+----------------------
+
+.. versionadded:: 3.18
+
+This variable is used to initialize the :prop_tgt:`PCH_WARN_INVALID`
+property of targets when they are created.
diff --git a/Help/variable/CMAKE_PDB_OUTPUT_DIRECTORY.rst b/Help/variable/CMAKE_PDB_OUTPUT_DIRECTORY.rst
new file mode 100644
index 0000000..763bcb3
--- /dev/null
+++ b/Help/variable/CMAKE_PDB_OUTPUT_DIRECTORY.rst
@@ -0,0 +1,9 @@
+CMAKE_PDB_OUTPUT_DIRECTORY
+--------------------------
+
+Output directory for MS debug symbol ``.pdb`` files generated by the
+linker for executable and shared library targets.
+
+This variable is used to initialize the :prop_tgt:`PDB_OUTPUT_DIRECTORY`
+property on all the targets. See that target property for additional
+information.
diff --git a/Help/variable/CMAKE_PDB_OUTPUT_DIRECTORY_CONFIG.rst b/Help/variable/CMAKE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
new file mode 100644
index 0000000..4d18eec
--- /dev/null
+++ b/Help/variable/CMAKE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
@@ -0,0 +1,11 @@
+CMAKE_PDB_OUTPUT_DIRECTORY_<CONFIG>
+-----------------------------------
+
+Per-configuration output directory for MS debug symbol ``.pdb`` files
+generated by the linker for executable and shared library targets.
+
+This is a per-configuration version of :variable:`CMAKE_PDB_OUTPUT_DIRECTORY`.
+This variable is used to initialize the
+:prop_tgt:`PDB_OUTPUT_DIRECTORY_<CONFIG>`
+property on all the targets. See that target property for additional
+information.
diff --git a/Help/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst b/Help/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst
new file mode 100644
index 0000000..43582be
--- /dev/null
+++ b/Help/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst
@@ -0,0 +1,17 @@
+CMAKE_POLICY_DEFAULT_CMP<NNNN>
+------------------------------
+
+Default for CMake Policy ``CMP<NNNN>`` when it is otherwise left unset.
+
+Commands :command:`cmake_minimum_required(VERSION)` and
+:command:`cmake_policy(VERSION)` by default leave policies introduced after
+the given version unset. Set ``CMAKE_POLICY_DEFAULT_CMP<NNNN>`` to ``OLD``
+or ``NEW`` to specify the default for policy ``CMP<NNNN>``, where ``<NNNN>``
+is the policy number.
+
+This variable should not be set by a project in CMake code; use
+:command:`cmake_policy(SET)` instead. Users running CMake may set this
+variable in the cache (e.g. ``-DCMAKE_POLICY_DEFAULT_CMP<NNNN>=<OLD|NEW>``)
+to set a policy not otherwise set by the project. Set to ``OLD`` to quiet a
+policy warning while using old behavior or to ``NEW`` to try building the
+project with new behavior.
diff --git a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
new file mode 100644
index 0000000..9f68741
--- /dev/null
+++ b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
@@ -0,0 +1,37 @@
+CMAKE_POLICY_WARNING_CMP<NNNN>
+------------------------------
+
+Explicitly enable or disable the warning when CMake Policy ``CMP<NNNN>``
+is not set. This is meaningful only for the few policies that do not
+warn by default:
+
+* ``CMAKE_POLICY_WARNING_CMP0025`` controls the warning for
+ policy :policy:`CMP0025`.
+* ``CMAKE_POLICY_WARNING_CMP0047`` controls the warning for
+ policy :policy:`CMP0047`.
+* ``CMAKE_POLICY_WARNING_CMP0056`` controls the warning for
+ policy :policy:`CMP0056`.
+* ``CMAKE_POLICY_WARNING_CMP0060`` controls the warning for
+ policy :policy:`CMP0060`.
+* ``CMAKE_POLICY_WARNING_CMP0065`` controls the warning for
+ policy :policy:`CMP0065`.
+* ``CMAKE_POLICY_WARNING_CMP0066`` controls the warning for
+ policy :policy:`CMP0066`.
+* ``CMAKE_POLICY_WARNING_CMP0067`` controls the warning for
+ policy :policy:`CMP0067`.
+* ``CMAKE_POLICY_WARNING_CMP0082`` controls the warning for
+ policy :policy:`CMP0082`.
+* ``CMAKE_POLICY_WARNING_CMP0089`` controls the warning for
+ policy :policy:`CMP0089`.
+* ``CMAKE_POLICY_WARNING_CMP0102`` controls the warning for
+ policy :policy:`CMP0102`.
+* ``CMAKE_POLICY_WARNING_CMP0112`` controls the warning for
+ policy :policy:`CMP0112`.
+* ``CMAKE_POLICY_WARNING_CMP0116`` controls the warning for
+ policy :policy:`CMP0116`.
+
+This variable should not be set by a project in CMake code. Project
+developers running CMake may set this variable in their cache to
+enable the warning (e.g. ``-DCMAKE_POLICY_WARNING_CMP<NNNN>=ON``).
+Alternatively, running :manual:`cmake(1)` with the ``--debug-output``,
+``--trace``, or ``--trace-expand`` option will also enable the warning.
diff --git a/Help/variable/CMAKE_POSITION_INDEPENDENT_CODE.rst b/Help/variable/CMAKE_POSITION_INDEPENDENT_CODE.rst
new file mode 100644
index 0000000..b010317
--- /dev/null
+++ b/Help/variable/CMAKE_POSITION_INDEPENDENT_CODE.rst
@@ -0,0 +1,9 @@
+CMAKE_POSITION_INDEPENDENT_CODE
+-------------------------------
+
+Default value for :prop_tgt:`POSITION_INDEPENDENT_CODE` of targets.
+
+This variable is used to initialize the
+:prop_tgt:`POSITION_INDEPENDENT_CODE` property on all the targets.
+See that target property for additional information. If set, its
+value is also used by the :command:`try_compile` command.
diff --git a/Help/variable/CMAKE_PREFIX_PATH.rst b/Help/variable/CMAKE_PREFIX_PATH.rst
new file mode 100644
index 0000000..1d4fd0b
--- /dev/null
+++ b/Help/variable/CMAKE_PREFIX_PATH.rst
@@ -0,0 +1,15 @@
+CMAKE_PREFIX_PATH
+-----------------
+
+:ref:`Semicolon-separated list <CMake Language Lists>` of directories specifying installation
+*prefixes* to be searched by the :command:`find_package`,
+:command:`find_program`, :command:`find_library`, :command:`find_file`, and
+:command:`find_path` commands. Each command will add appropriate
+subdirectories (like ``bin``, ``lib``, or ``include``) as specified in its own
+documentation.
+
+By default this is empty. It is intended to be set by the project.
+
+See also :variable:`CMAKE_SYSTEM_PREFIX_PATH`, :variable:`CMAKE_INCLUDE_PATH`,
+:variable:`CMAKE_LIBRARY_PATH`, :variable:`CMAKE_PROGRAM_PATH`, and
+:variable:`CMAKE_IGNORE_PATH`.
diff --git a/Help/variable/CMAKE_PROGRAM_PATH.rst b/Help/variable/CMAKE_PROGRAM_PATH.rst
new file mode 100644
index 0000000..2d0c090
--- /dev/null
+++ b/Help/variable/CMAKE_PROGRAM_PATH.rst
@@ -0,0 +1,7 @@
+CMAKE_PROGRAM_PATH
+------------------
+
+:ref:`Semicolon-separated list <CMake Language Lists>` of directories specifying a search path
+for the :command:`find_program` command. By default it is empty, it is
+intended to be set by the project. See also
+:variable:`CMAKE_SYSTEM_PROGRAM_PATH` and :variable:`CMAKE_PREFIX_PATH`.
diff --git a/Help/variable/CMAKE_PROJECT_DESCRIPTION.rst b/Help/variable/CMAKE_PROJECT_DESCRIPTION.rst
new file mode 100644
index 0000000..95cbe40
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_DESCRIPTION.rst
@@ -0,0 +1,37 @@
+CMAKE_PROJECT_DESCRIPTION
+-------------------------
+
+.. versionadded:: 3.9
+
+The description of the top level project.
+
+This variable holds the description of the project as specified in the top
+level CMakeLists.txt file by a :command:`project` command. In the event that
+the top level CMakeLists.txt contains multiple :command:`project` calls,
+the most recently called one from that top level CMakeLists.txt will determine
+the value that ``CMAKE_PROJECT_DESCRIPTION`` contains. For example, consider
+the following top level CMakeLists.txt:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.0)
+ project(First DESCRIPTION "I am First")
+ project(Second DESCRIPTION "I am Second")
+ add_subdirectory(sub)
+ project(Third DESCRIPTION "I am Third")
+
+And ``sub/CMakeLists.txt`` with the following contents:
+
+.. code-block:: cmake
+
+ project(SubProj DESCRIPTION "I am SubProj")
+ message("CMAKE_PROJECT_DESCRIPTION = ${CMAKE_PROJECT_DESCRIPTION}")
+
+The most recently seen :command:`project` command from the top level
+CMakeLists.txt would be ``project(Second ...)``, so this will print::
+
+ CMAKE_PROJECT_DESCRIPTION = I am Second
+
+To obtain the description from the most recent call to :command:`project` in
+the current directory scope or above, see the :variable:`PROJECT_DESCRIPTION`
+variable.
diff --git a/Help/variable/CMAKE_PROJECT_HOMEPAGE_URL.rst b/Help/variable/CMAKE_PROJECT_HOMEPAGE_URL.rst
new file mode 100644
index 0000000..4c5debe
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_HOMEPAGE_URL.rst
@@ -0,0 +1,37 @@
+CMAKE_PROJECT_HOMEPAGE_URL
+--------------------------
+
+.. versionadded:: 3.12
+
+The homepage URL of the top level project.
+
+This variable holds the homepage URL of the project as specified in the top
+level CMakeLists.txt file by a :command:`project` command. In the event that
+the top level CMakeLists.txt contains multiple :command:`project` calls,
+the most recently called one from that top level CMakeLists.txt will determine
+the value that ``CMAKE_PROJECT_HOMEPAGE_URL`` contains. For example, consider
+the following top level CMakeLists.txt:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.0)
+ project(First HOMEPAGE_URL "http://first.example.com")
+ project(Second HOMEPAGE_URL "http://second.example.com")
+ add_subdirectory(sub)
+ project(Third HOMEPAGE_URL "http://third.example.com")
+
+And ``sub/CMakeLists.txt`` with the following contents:
+
+.. code-block:: cmake
+
+ project(SubProj HOMEPAGE_URL "http://subproj.example.com")
+ message("CMAKE_PROJECT_HOMEPAGE_URL = ${CMAKE_PROJECT_HOMEPAGE_URL}")
+
+The most recently seen :command:`project` command from the top level
+CMakeLists.txt would be ``project(Second ...)``, so this will print::
+
+ CMAKE_PROJECT_HOMEPAGE_URL = http://second.example.com
+
+To obtain the homepage URL from the most recent call to :command:`project` in
+the current directory scope or above, see the :variable:`PROJECT_HOMEPAGE_URL`
+variable.
diff --git a/Help/variable/CMAKE_PROJECT_INCLUDE.rst b/Help/variable/CMAKE_PROJECT_INCLUDE.rst
new file mode 100644
index 0000000..41d9e5d
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_INCLUDE.rst
@@ -0,0 +1,12 @@
+CMAKE_PROJECT_INCLUDE
+---------------------
+
+.. versionadded:: 3.15
+
+A CMake language file or module to be included as the last step of all
+:command:`project` command calls. This is intended for injecting custom code
+into project builds without modifying their source.
+
+See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
+:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE` and
+:variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables.
diff --git a/Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst b/Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst
new file mode 100644
index 0000000..c2fd0f8
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst
@@ -0,0 +1,12 @@
+CMAKE_PROJECT_INCLUDE_BEFORE
+----------------------------
+
+.. versionadded:: 3.15
+
+A CMake language file or module to be included as the first step of all
+:command:`project` command calls. This is intended for injecting custom code
+into project builds without modifying their source.
+
+See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
+:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE` and
+:variable:`CMAKE_PROJECT_INCLUDE` variables.
diff --git a/Help/variable/CMAKE_PROJECT_NAME.rst b/Help/variable/CMAKE_PROJECT_NAME.rst
new file mode 100644
index 0000000..94b8dba
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_NAME.rst
@@ -0,0 +1,35 @@
+CMAKE_PROJECT_NAME
+------------------
+
+The name of the top level project.
+
+This variable holds the name of the project as specified in the top
+level CMakeLists.txt file by a :command:`project` command. In the event that
+the top level CMakeLists.txt contains multiple :command:`project` calls,
+the most recently called one from that top level CMakeLists.txt will determine
+the name that ``CMAKE_PROJECT_NAME`` contains. For example, consider
+the following top level CMakeLists.txt:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.0)
+ project(First)
+ project(Second)
+ add_subdirectory(sub)
+ project(Third)
+
+And ``sub/CMakeLists.txt`` with the following contents:
+
+.. code-block:: cmake
+
+ project(SubProj)
+ message("CMAKE_PROJECT_NAME = ${CMAKE_PROJECT_NAME}")
+
+The most recently seen :command:`project` command from the top level
+CMakeLists.txt would be ``project(Second)``, so this will print::
+
+ CMAKE_PROJECT_NAME = Second
+
+To obtain the name from the most recent call to :command:`project` in
+the current directory scope or above, see the :variable:`PROJECT_NAME`
+variable.
diff --git a/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst b/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst
new file mode 100644
index 0000000..74247f1
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst
@@ -0,0 +1,11 @@
+CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE
+------------------------------------
+
+A CMake language file or module to be included as the last step of any
+:command:`project` command calls that specify ``<PROJECT-NAME>`` as the project
+name. This is intended for injecting custom code into project builds without
+modifying their source.
+
+See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`,
+:variable:`CMAKE_PROJECT_INCLUDE` and
+:variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables.
diff --git a/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE.rst b/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE.rst
new file mode 100644
index 0000000..39abb12
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE.rst
@@ -0,0 +1,13 @@
+CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE
+-------------------------------------------
+
+.. versionadded:: 3.17
+
+A CMake language file or module to be included as the first step of any
+:command:`project` command calls that specify ``<PROJECT-NAME>`` as the project
+name. This is intended for injecting custom code into project builds without
+modifying their source.
+
+See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
+:variable:`CMAKE_PROJECT_INCLUDE` and
+:variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables.
diff --git a/Help/variable/CMAKE_PROJECT_VERSION.rst b/Help/variable/CMAKE_PROJECT_VERSION.rst
new file mode 100644
index 0000000..450c136
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_VERSION.rst
@@ -0,0 +1,37 @@
+CMAKE_PROJECT_VERSION
+---------------------
+
+.. versionadded:: 3.12
+
+The version of the top level project.
+
+This variable holds the version of the project as specified in the top
+level CMakeLists.txt file by a :command:`project` command. In the event that
+the top level CMakeLists.txt contains multiple :command:`project` calls,
+the most recently called one from that top level CMakeLists.txt will determine
+the value that ``CMAKE_PROJECT_VERSION`` contains. For example, consider
+the following top level CMakeLists.txt:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.0)
+ project(First VERSION 1.2.3)
+ project(Second VERSION 3.4.5)
+ add_subdirectory(sub)
+ project(Third VERSION 6.7.8)
+
+And ``sub/CMakeLists.txt`` with the following contents:
+
+.. code-block:: cmake
+
+ project(SubProj VERSION 1)
+ message("CMAKE_PROJECT_VERSION = ${CMAKE_PROJECT_VERSION}")
+
+The most recently seen :command:`project` command from the top level
+CMakeLists.txt would be ``project(Second ...)``, so this will print::
+
+ CMAKE_PROJECT_VERSION = 3.4.5
+
+To obtain the version from the most recent call to :command:`project` in
+the current directory scope or above, see the :variable:`PROJECT_VERSION`
+variable.
diff --git a/Help/variable/CMAKE_PROJECT_VERSION_MAJOR.rst b/Help/variable/CMAKE_PROJECT_VERSION_MAJOR.rst
new file mode 100644
index 0000000..c7511e7
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_VERSION_MAJOR.rst
@@ -0,0 +1,11 @@
+CMAKE_PROJECT_VERSION_MAJOR
+---------------------------
+
+.. versionadded:: 3.12
+
+The major version of the top level project.
+
+This variable holds the major version of the project as specified in the top
+level CMakeLists.txt file by a :command:`project` command. Please see
+:variable:`CMAKE_PROJECT_VERSION` documentation for the behavior when
+multiple :command:`project` commands are used in the sources.
diff --git a/Help/variable/CMAKE_PROJECT_VERSION_MINOR.rst b/Help/variable/CMAKE_PROJECT_VERSION_MINOR.rst
new file mode 100644
index 0000000..dd91dcf
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_VERSION_MINOR.rst
@@ -0,0 +1,11 @@
+CMAKE_PROJECT_VERSION_MINOR
+---------------------------
+
+.. versionadded:: 3.12
+
+The minor version of the top level project.
+
+This variable holds the minor version of the project as specified in the top
+level CMakeLists.txt file by a :command:`project` command. Please see
+:variable:`CMAKE_PROJECT_VERSION` documentation for the behavior when
+multiple :command:`project` commands are used in the sources.
diff --git a/Help/variable/CMAKE_PROJECT_VERSION_PATCH.rst b/Help/variable/CMAKE_PROJECT_VERSION_PATCH.rst
new file mode 100644
index 0000000..61fd1f3
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_VERSION_PATCH.rst
@@ -0,0 +1,11 @@
+CMAKE_PROJECT_VERSION_PATCH
+---------------------------
+
+.. versionadded:: 3.12
+
+The patch version of the top level project.
+
+This variable holds the patch version of the project as specified in the top
+level CMakeLists.txt file by a :command:`project` command. Please see
+:variable:`CMAKE_PROJECT_VERSION` documentation for the behavior when
+multiple :command:`project` commands are used in the sources.
diff --git a/Help/variable/CMAKE_PROJECT_VERSION_TWEAK.rst b/Help/variable/CMAKE_PROJECT_VERSION_TWEAK.rst
new file mode 100644
index 0000000..0deae8b
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_VERSION_TWEAK.rst
@@ -0,0 +1,11 @@
+CMAKE_PROJECT_VERSION_TWEAK
+---------------------------
+
+.. versionadded:: 3.12
+
+The tweak version of the top level project.
+
+This variable holds the tweak version of the project as specified in the top
+level CMakeLists.txt file by a :command:`project` command. Please see
+:variable:`CMAKE_PROJECT_VERSION` documentation for the behavior when
+multiple :command:`project` commands are used in the sources.
diff --git a/Help/variable/CMAKE_RANLIB.rst b/Help/variable/CMAKE_RANLIB.rst
new file mode 100644
index 0000000..82672e9
--- /dev/null
+++ b/Help/variable/CMAKE_RANLIB.rst
@@ -0,0 +1,7 @@
+CMAKE_RANLIB
+------------
+
+Name of randomizing tool for static libraries.
+
+This specifies name of the program that randomizes libraries on UNIX,
+not used on Windows, but may be present.
diff --git a/Help/variable/CMAKE_ROOT.rst b/Help/variable/CMAKE_ROOT.rst
new file mode 100644
index 0000000..1d0a8af
--- /dev/null
+++ b/Help/variable/CMAKE_ROOT.rst
@@ -0,0 +1,8 @@
+CMAKE_ROOT
+----------
+
+Install directory for running cmake.
+
+This is the install root for the running CMake and the ``Modules``
+directory can be found here. This is commonly used in this format:
+``${CMAKE_ROOT}/Modules``
diff --git a/Help/variable/CMAKE_RULE_MESSAGES.rst b/Help/variable/CMAKE_RULE_MESSAGES.rst
new file mode 100644
index 0000000..39be2e9
--- /dev/null
+++ b/Help/variable/CMAKE_RULE_MESSAGES.rst
@@ -0,0 +1,10 @@
+CMAKE_RULE_MESSAGES
+-------------------
+
+.. versionadded:: 3.13
+
+Specify whether to report a message for each make rule.
+
+If set in the cache it is used to initialize the value of the :prop_gbl:`RULE_MESSAGES` property.
+Users may disable the option in their local build tree to disable granular messages
+and report only as each target completes in Makefile builds.
diff --git a/Help/variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY.rst b/Help/variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY.rst
new file mode 100644
index 0000000..6253d4a
--- /dev/null
+++ b/Help/variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY.rst
@@ -0,0 +1,9 @@
+CMAKE_RUNTIME_OUTPUT_DIRECTORY
+------------------------------
+
+Where to put all the :ref:`RUNTIME <Runtime Output Artifacts>`
+target files when built.
+
+This variable is used to initialize the :prop_tgt:`RUNTIME_OUTPUT_DIRECTORY`
+property on all the targets. See that target property for additional
+information.
diff --git a/Help/variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst b/Help/variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
new file mode 100644
index 0000000..c9c55c5
--- /dev/null
+++ b/Help/variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
@@ -0,0 +1,11 @@
+CMAKE_RUNTIME_OUTPUT_DIRECTORY_<CONFIG>
+---------------------------------------
+
+.. versionadded:: 3.3
+
+Where to put all the :ref:`RUNTIME <Runtime Output Artifacts>`
+target files when built for a specific configuration.
+
+This variable is used to initialize the
+:prop_tgt:`RUNTIME_OUTPUT_DIRECTORY_<CONFIG>` property on all the targets.
+See that target property for additional information.
diff --git a/Help/variable/CMAKE_SCRIPT_MODE_FILE.rst b/Help/variable/CMAKE_SCRIPT_MODE_FILE.rst
new file mode 100644
index 0000000..981af60
--- /dev/null
+++ b/Help/variable/CMAKE_SCRIPT_MODE_FILE.rst
@@ -0,0 +1,9 @@
+CMAKE_SCRIPT_MODE_FILE
+----------------------
+
+Full path to the :manual:`cmake(1)` ``-P`` script file currently being
+processed.
+
+When run in :manual:`cmake(1)` ``-P`` script mode, CMake sets this variable to
+the full path of the script file. When run to configure a ``CMakeLists.txt``
+file, this variable is not set.
diff --git a/Help/variable/CMAKE_SHARED_LIBRARY_PREFIX.rst b/Help/variable/CMAKE_SHARED_LIBRARY_PREFIX.rst
new file mode 100644
index 0000000..8afabaf
--- /dev/null
+++ b/Help/variable/CMAKE_SHARED_LIBRARY_PREFIX.rst
@@ -0,0 +1,8 @@
+CMAKE_SHARED_LIBRARY_PREFIX
+---------------------------
+
+The prefix for shared libraries that you link to.
+
+The prefix to use for the name of a shared library, ``lib`` on UNIX.
+
+``CMAKE_SHARED_LIBRARY_PREFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_SHARED_LIBRARY_SUFFIX.rst b/Help/variable/CMAKE_SHARED_LIBRARY_SUFFIX.rst
new file mode 100644
index 0000000..1f96a32
--- /dev/null
+++ b/Help/variable/CMAKE_SHARED_LIBRARY_SUFFIX.rst
@@ -0,0 +1,9 @@
+CMAKE_SHARED_LIBRARY_SUFFIX
+---------------------------
+
+The suffix for shared libraries that you link to.
+
+The suffix to use for the end of a shared library filename, ``.dll`` on
+Windows.
+
+``CMAKE_SHARED_LIBRARY_SUFFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_SHARED_LINKER_FLAGS.rst b/Help/variable/CMAKE_SHARED_LINKER_FLAGS.rst
new file mode 100644
index 0000000..fce950c
--- /dev/null
+++ b/Help/variable/CMAKE_SHARED_LINKER_FLAGS.rst
@@ -0,0 +1,6 @@
+CMAKE_SHARED_LINKER_FLAGS
+-------------------------
+
+Linker flags to be used to create shared libraries.
+
+These flags will be used by the linker when creating a shared library.
diff --git a/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst b/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst
new file mode 100644
index 0000000..4bf87a0
--- /dev/null
+++ b/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst
@@ -0,0 +1,7 @@
+CMAKE_SHARED_LINKER_FLAGS_<CONFIG>
+----------------------------------
+
+Flags to be used when linking a shared library.
+
+Same as ``CMAKE_C_FLAGS_*`` but used by the linker when creating shared
+libraries.
diff --git a/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG_INIT.rst b/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG_INIT.rst
new file mode 100644
index 0000000..7f3dec7
--- /dev/null
+++ b/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG_INIT.rst
@@ -0,0 +1,12 @@
+CMAKE_SHARED_LINKER_FLAGS_<CONFIG>_INIT
+---------------------------------------
+
+.. versionadded:: 3.7
+
+Value used to initialize the :variable:`CMAKE_SHARED_LINKER_FLAGS_<CONFIG>`
+cache entry the first time a build tree is configured.
+This variable is meant to be set by a :variable:`toolchain file
+<CMAKE_TOOLCHAIN_FILE>`. CMake may prepend or append content to
+the value based on the environment and target platform.
+
+See also :variable:`CMAKE_SHARED_LINKER_FLAGS_INIT`.
diff --git a/Help/variable/CMAKE_SHARED_LINKER_FLAGS_INIT.rst b/Help/variable/CMAKE_SHARED_LINKER_FLAGS_INIT.rst
new file mode 100644
index 0000000..6d51afe
--- /dev/null
+++ b/Help/variable/CMAKE_SHARED_LINKER_FLAGS_INIT.rst
@@ -0,0 +1,13 @@
+CMAKE_SHARED_LINKER_FLAGS_INIT
+------------------------------
+
+.. versionadded:: 3.7
+
+Value used to initialize the :variable:`CMAKE_SHARED_LINKER_FLAGS`
+cache entry the first time a build tree is configured.
+This variable is meant to be set by a :variable:`toolchain file
+<CMAKE_TOOLCHAIN_FILE>`. CMake may prepend or append content to
+the value based on the environment and target platform.
+
+See also the configuration-specific variable
+:variable:`CMAKE_SHARED_LINKER_FLAGS_<CONFIG>_INIT`.
diff --git a/Help/variable/CMAKE_SHARED_MODULE_PREFIX.rst b/Help/variable/CMAKE_SHARED_MODULE_PREFIX.rst
new file mode 100644
index 0000000..d6eef98
--- /dev/null
+++ b/Help/variable/CMAKE_SHARED_MODULE_PREFIX.rst
@@ -0,0 +1,8 @@
+CMAKE_SHARED_MODULE_PREFIX
+--------------------------
+
+The prefix for loadable modules that you link to.
+
+The prefix to use for the name of a loadable module on this platform.
+
+``CMAKE_SHARED_MODULE_PREFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_SHARED_MODULE_SUFFIX.rst b/Help/variable/CMAKE_SHARED_MODULE_SUFFIX.rst
new file mode 100644
index 0000000..81515c3
--- /dev/null
+++ b/Help/variable/CMAKE_SHARED_MODULE_SUFFIX.rst
@@ -0,0 +1,9 @@
+CMAKE_SHARED_MODULE_SUFFIX
+--------------------------
+
+The suffix for shared libraries that you link to.
+
+The suffix to use for the end of a loadable module filename on this
+platform
+
+``CMAKE_SHARED_MODULE_SUFFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_SIZEOF_VOID_P.rst b/Help/variable/CMAKE_SIZEOF_VOID_P.rst
new file mode 100644
index 0000000..f5464d1
--- /dev/null
+++ b/Help/variable/CMAKE_SIZEOF_VOID_P.rst
@@ -0,0 +1,8 @@
+CMAKE_SIZEOF_VOID_P
+-------------------
+
+Size of a ``void`` pointer.
+
+This is set to the size of a pointer on the target machine, and is determined
+by a try compile. If a 64-bit size is found, then the library search
+path is modified to look for 64-bit libraries first.
diff --git a/Help/variable/CMAKE_SKIP_BUILD_RPATH.rst b/Help/variable/CMAKE_SKIP_BUILD_RPATH.rst
new file mode 100644
index 0000000..8da6100
--- /dev/null
+++ b/Help/variable/CMAKE_SKIP_BUILD_RPATH.rst
@@ -0,0 +1,10 @@
+CMAKE_SKIP_BUILD_RPATH
+----------------------
+
+Do not include RPATHs in the build tree.
+
+Normally CMake uses the build tree for the RPATH when building
+executables etc on systems that use RPATH. When the software is
+installed the executables etc are relinked by CMake to have the
+install RPATH. If this variable is set to true then the software is
+always built with no RPATH.
diff --git a/Help/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY.rst b/Help/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY.rst
new file mode 100644
index 0000000..80a68c9
--- /dev/null
+++ b/Help/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY.rst
@@ -0,0 +1,11 @@
+CMAKE_SKIP_INSTALL_ALL_DEPENDENCY
+---------------------------------
+
+Don't make the ``install`` target depend on the ``all`` target.
+
+By default, the ``install`` target depends on the ``all`` target. This
+has the effect, that when ``make install`` is invoked or ``INSTALL`` is
+built, first the ``all`` target is built, then the installation starts.
+If :variable:`CMAKE_SKIP_INSTALL_ALL_DEPENDENCY` is set to ``TRUE``, this
+dependency is not created, so the installation process will start immediately,
+independent from whether the project has been completely built or not.
diff --git a/Help/variable/CMAKE_SKIP_INSTALL_RPATH.rst b/Help/variable/CMAKE_SKIP_INSTALL_RPATH.rst
new file mode 100644
index 0000000..cc0ac21
--- /dev/null
+++ b/Help/variable/CMAKE_SKIP_INSTALL_RPATH.rst
@@ -0,0 +1,14 @@
+CMAKE_SKIP_INSTALL_RPATH
+------------------------
+
+Do not include RPATHs in the install tree.
+
+Normally CMake uses the build tree for the RPATH when building
+executables etc on systems that use RPATH. When the software is
+installed the executables etc are relinked by CMake to have the
+install RPATH. If this variable is set to true then the software is
+always installed without RPATH, even if RPATH is enabled when
+building. This can be useful for example to allow running tests from
+the build directory with RPATH enabled before the installation step.
+To omit RPATH in both the build and install steps, use
+:variable:`CMAKE_SKIP_RPATH` instead.
diff --git a/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst b/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst
new file mode 100644
index 0000000..b77bb68
--- /dev/null
+++ b/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst
@@ -0,0 +1,8 @@
+CMAKE_SKIP_INSTALL_RULES
+------------------------
+
+Whether to disable generation of installation rules.
+
+If ``TRUE``, CMake will neither generate installation rules nor
+will it generate ``cmake_install.cmake`` files. This variable is ``FALSE`` by
+default.
diff --git a/Help/variable/CMAKE_SKIP_RPATH.rst b/Help/variable/CMAKE_SKIP_RPATH.rst
new file mode 100644
index 0000000..d7ce8e4
--- /dev/null
+++ b/Help/variable/CMAKE_SKIP_RPATH.rst
@@ -0,0 +1,10 @@
+CMAKE_SKIP_RPATH
+----------------
+
+If true, do not add run time path information.
+
+If this is set to ``TRUE``, then the rpath information is not added to
+compiled executables. The default is to add rpath information if the
+platform supports it. This allows for easy running from the build
+tree. To omit RPATH in the install step, but not the build step, use
+:variable:`CMAKE_SKIP_INSTALL_RPATH` instead.
diff --git a/Help/variable/CMAKE_SOURCE_DIR.rst b/Help/variable/CMAKE_SOURCE_DIR.rst
new file mode 100644
index 0000000..d1f1798
--- /dev/null
+++ b/Help/variable/CMAKE_SOURCE_DIR.rst
@@ -0,0 +1,13 @@
+CMAKE_SOURCE_DIR
+----------------
+
+The path to the top level of the source tree.
+
+This is the full path to the top level of the current CMake source
+tree. For an in-source build, this would be the same as
+:variable:`CMAKE_BINARY_DIR`.
+
+When run in ``-P`` script mode, CMake sets the variables
+:variable:`CMAKE_BINARY_DIR`, :variable:`CMAKE_SOURCE_DIR`,
+:variable:`CMAKE_CURRENT_BINARY_DIR` and
+:variable:`CMAKE_CURRENT_SOURCE_DIR` to the current working directory.
diff --git a/Help/variable/CMAKE_STAGING_PREFIX.rst b/Help/variable/CMAKE_STAGING_PREFIX.rst
new file mode 100644
index 0000000..bdb97fa
--- /dev/null
+++ b/Help/variable/CMAKE_STAGING_PREFIX.rst
@@ -0,0 +1,14 @@
+CMAKE_STAGING_PREFIX
+--------------------
+
+This variable may be set to a path to install to when cross-compiling. This can
+be useful if the path in :variable:`CMAKE_SYSROOT` is read-only, or otherwise
+should remain pristine.
+
+The :variable:`CMAKE_STAGING_PREFIX` location is also used as a search prefix
+by the ``find_*`` commands. This can be controlled by setting the
+:variable:`CMAKE_FIND_NO_INSTALL_PREFIX` variable.
+
+If any ``RPATH``/``RUNPATH`` entries passed to the linker contain the
+:variable:`CMAKE_STAGING_PREFIX`, the matching path fragments are replaced
+with the :variable:`CMAKE_INSTALL_PREFIX`.
diff --git a/Help/variable/CMAKE_STATIC_LIBRARY_PREFIX.rst b/Help/variable/CMAKE_STATIC_LIBRARY_PREFIX.rst
new file mode 100644
index 0000000..714b5cc
--- /dev/null
+++ b/Help/variable/CMAKE_STATIC_LIBRARY_PREFIX.rst
@@ -0,0 +1,8 @@
+CMAKE_STATIC_LIBRARY_PREFIX
+---------------------------
+
+The prefix for static libraries that you link to.
+
+The prefix to use for the name of a static library, ``lib`` on UNIX.
+
+``CMAKE_STATIC_LIBRARY_PREFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_STATIC_LIBRARY_SUFFIX.rst b/Help/variable/CMAKE_STATIC_LIBRARY_SUFFIX.rst
new file mode 100644
index 0000000..28dc09d
--- /dev/null
+++ b/Help/variable/CMAKE_STATIC_LIBRARY_SUFFIX.rst
@@ -0,0 +1,9 @@
+CMAKE_STATIC_LIBRARY_SUFFIX
+---------------------------
+
+The suffix for static libraries that you link to.
+
+The suffix to use for the end of a static library filename, ``.lib`` on
+Windows.
+
+``CMAKE_STATIC_LIBRARY_SUFFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_STATIC_LINKER_FLAGS.rst b/Help/variable/CMAKE_STATIC_LINKER_FLAGS.rst
new file mode 100644
index 0000000..1a810ce
--- /dev/null
+++ b/Help/variable/CMAKE_STATIC_LINKER_FLAGS.rst
@@ -0,0 +1,12 @@
+CMAKE_STATIC_LINKER_FLAGS
+-------------------------
+
+Flags to be used to create static libraries. These flags will be passed
+to the archiver when creating a static library.
+
+See also :variable:`CMAKE_STATIC_LINKER_FLAGS_<CONFIG>`.
+
+.. note::
+ Static libraries do not actually link. They are essentially archives
+ of object files. The use of the name "linker" in the name of this
+ variable is kept for compatibility.
diff --git a/Help/variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG.rst b/Help/variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG.rst
new file mode 100644
index 0000000..e561dc6
--- /dev/null
+++ b/Help/variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG.rst
@@ -0,0 +1,13 @@
+CMAKE_STATIC_LINKER_FLAGS_<CONFIG>
+----------------------------------
+
+Flags to be used to create static libraries. These flags will be passed
+to the archiver when creating a static library in the ``<CONFIG>``
+configuration.
+
+See also :variable:`CMAKE_STATIC_LINKER_FLAGS`.
+
+.. note::
+ Static libraries do not actually link. They are essentially archives
+ of object files. The use of the name "linker" in the name of this
+ variable is kept for compatibility.
diff --git a/Help/variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG_INIT.rst b/Help/variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG_INIT.rst
new file mode 100644
index 0000000..5e65ef2
--- /dev/null
+++ b/Help/variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG_INIT.rst
@@ -0,0 +1,12 @@
+CMAKE_STATIC_LINKER_FLAGS_<CONFIG>_INIT
+---------------------------------------
+
+.. versionadded:: 3.7
+
+Value used to initialize the :variable:`CMAKE_STATIC_LINKER_FLAGS_<CONFIG>`
+cache entry the first time a build tree is configured.
+This variable is meant to be set by a :variable:`toolchain file
+<CMAKE_TOOLCHAIN_FILE>`. CMake may prepend or append content to
+the value based on the environment and target platform.
+
+See also :variable:`CMAKE_STATIC_LINKER_FLAGS_INIT`.
diff --git a/Help/variable/CMAKE_STATIC_LINKER_FLAGS_INIT.rst b/Help/variable/CMAKE_STATIC_LINKER_FLAGS_INIT.rst
new file mode 100644
index 0000000..cbf681c
--- /dev/null
+++ b/Help/variable/CMAKE_STATIC_LINKER_FLAGS_INIT.rst
@@ -0,0 +1,13 @@
+CMAKE_STATIC_LINKER_FLAGS_INIT
+------------------------------
+
+.. versionadded:: 3.7
+
+Value used to initialize the :variable:`CMAKE_STATIC_LINKER_FLAGS`
+cache entry the first time a build tree is configured.
+This variable is meant to be set by a :variable:`toolchain file
+<CMAKE_TOOLCHAIN_FILE>`. CMake may prepend or append content to
+the value based on the environment and target platform.
+
+See also the configuration-specific variable
+:variable:`CMAKE_STATIC_LINKER_FLAGS_<CONFIG>_INIT`.
diff --git a/Help/variable/CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS.rst b/Help/variable/CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS.rst
new file mode 100644
index 0000000..5c1c8d1
--- /dev/null
+++ b/Help/variable/CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS.rst
@@ -0,0 +1,27 @@
+CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS
+---------------------------------
+
+.. versionadded:: 3.8
+
+This variable contains a list of env vars as a list of tokens with the
+syntax ``var=value``.
+
+Example:
+
+.. code-block:: cmake
+
+ set(CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS
+ "FOO=FOO1\;FOO2\;FOON"
+ "BAR=BAR1\;BAR2\;BARN"
+ "BAZ=BAZ1\;BAZ2\;BAZN"
+ "FOOBAR=FOOBAR1\;FOOBAR2\;FOOBARN"
+ "VALID="
+ )
+
+In case of malformed variables CMake will fail:
+
+.. code-block:: cmake
+
+ set(CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS
+ "THIS_IS_NOT_VALID"
+ )
diff --git a/Help/variable/CMAKE_SUBLIME_TEXT_2_EXCLUDE_BUILD_TREE.rst b/Help/variable/CMAKE_SUBLIME_TEXT_2_EXCLUDE_BUILD_TREE.rst
new file mode 100644
index 0000000..28b0dbd
--- /dev/null
+++ b/Help/variable/CMAKE_SUBLIME_TEXT_2_EXCLUDE_BUILD_TREE.rst
@@ -0,0 +1,9 @@
+CMAKE_SUBLIME_TEXT_2_EXCLUDE_BUILD_TREE
+---------------------------------------
+
+.. versionadded:: 3.8
+
+If this variable evaluates to ``ON`` at the end of the top-level
+``CMakeLists.txt`` file, the :generator:`Sublime Text 2` extra generator
+excludes the build tree from the ``.sublime-project`` if it is inside the
+source tree.
diff --git a/Help/variable/CMAKE_SUPPRESS_REGENERATION.rst b/Help/variable/CMAKE_SUPPRESS_REGENERATION.rst
new file mode 100644
index 0000000..48490ff
--- /dev/null
+++ b/Help/variable/CMAKE_SUPPRESS_REGENERATION.rst
@@ -0,0 +1,13 @@
+CMAKE_SUPPRESS_REGENERATION
+---------------------------
+
+.. versionadded:: 3.12
+
+If ``CMAKE_SUPPRESS_REGENERATION`` is ``OFF``, which is default, then CMake
+adds a special target on which all other targets depend that checks the build
+system and optionally re-runs CMake to regenerate the build system when
+the target specification source changes.
+
+If this variable evaluates to ``ON`` at the end of the top-level
+``CMakeLists.txt`` file, CMake will not add the regeneration target to the
+build system or perform any build system checks.
diff --git a/Help/variable/CMAKE_SYSROOT.rst b/Help/variable/CMAKE_SYSROOT.rst
new file mode 100644
index 0000000..35b944f
--- /dev/null
+++ b/Help/variable/CMAKE_SYSROOT.rst
@@ -0,0 +1,15 @@
+CMAKE_SYSROOT
+-------------
+
+Path to pass to the compiler in the ``--sysroot`` flag.
+
+The ``CMAKE_SYSROOT`` content is passed to the compiler in the ``--sysroot``
+flag, if supported. The path is also stripped from the ``RPATH``/``RUNPATH``
+if necessary on installation. The ``CMAKE_SYSROOT`` is also used to prefix
+paths searched by the ``find_*`` commands.
+
+This variable may only be set in a toolchain file specified by
+the :variable:`CMAKE_TOOLCHAIN_FILE` variable.
+
+See also the :variable:`CMAKE_SYSROOT_COMPILE` and
+:variable:`CMAKE_SYSROOT_LINK` variables.
diff --git a/Help/variable/CMAKE_SYSROOT_COMPILE.rst b/Help/variable/CMAKE_SYSROOT_COMPILE.rst
new file mode 100644
index 0000000..4aea48e
--- /dev/null
+++ b/Help/variable/CMAKE_SYSROOT_COMPILE.rst
@@ -0,0 +1,11 @@
+CMAKE_SYSROOT_COMPILE
+---------------------
+
+.. versionadded:: 3.9
+
+Path to pass to the compiler in the ``--sysroot`` flag when compiling source
+files. This is the same as :variable:`CMAKE_SYSROOT` but is used only for
+compiling sources and not linking.
+
+This variable may only be set in a toolchain file specified by
+the :variable:`CMAKE_TOOLCHAIN_FILE` variable.
diff --git a/Help/variable/CMAKE_SYSROOT_LINK.rst b/Help/variable/CMAKE_SYSROOT_LINK.rst
new file mode 100644
index 0000000..9749b7b
--- /dev/null
+++ b/Help/variable/CMAKE_SYSROOT_LINK.rst
@@ -0,0 +1,11 @@
+CMAKE_SYSROOT_LINK
+------------------
+
+.. versionadded:: 3.9
+
+Path to pass to the compiler in the ``--sysroot`` flag when linking. This is
+the same as :variable:`CMAKE_SYSROOT` but is used only for linking and not
+compiling sources.
+
+This variable may only be set in a toolchain file specified by
+the :variable:`CMAKE_TOOLCHAIN_FILE` variable.
diff --git a/Help/variable/CMAKE_SYSTEM.rst b/Help/variable/CMAKE_SYSTEM.rst
new file mode 100644
index 0000000..c7d0d8a
--- /dev/null
+++ b/Help/variable/CMAKE_SYSTEM.rst
@@ -0,0 +1,10 @@
+CMAKE_SYSTEM
+------------
+
+Composite name of operating system CMake is compiling for.
+
+This variable is the composite of :variable:`CMAKE_SYSTEM_NAME` and
+:variable:`CMAKE_SYSTEM_VERSION`, e.g.
+``${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_VERSION}``. If
+:variable:`CMAKE_SYSTEM_VERSION` is not set, then this variable is
+the same as :variable:`CMAKE_SYSTEM_NAME`.
diff --git a/Help/variable/CMAKE_SYSTEM_APPBUNDLE_PATH.rst b/Help/variable/CMAKE_SYSTEM_APPBUNDLE_PATH.rst
new file mode 100644
index 0000000..06a99a8
--- /dev/null
+++ b/Help/variable/CMAKE_SYSTEM_APPBUNDLE_PATH.rst
@@ -0,0 +1,9 @@
+CMAKE_SYSTEM_APPBUNDLE_PATH
+---------------------------
+
+.. versionadded:: 3.4
+
+Search path for macOS application bundles used by the :command:`find_program`,
+and :command:`find_package` commands. By default it contains the standard
+directories for the current system. It is *not* intended to be modified by
+the project, use :variable:`CMAKE_APPBUNDLE_PATH` for this.
diff --git a/Help/variable/CMAKE_SYSTEM_FRAMEWORK_PATH.rst b/Help/variable/CMAKE_SYSTEM_FRAMEWORK_PATH.rst
new file mode 100644
index 0000000..1a402c1
--- /dev/null
+++ b/Help/variable/CMAKE_SYSTEM_FRAMEWORK_PATH.rst
@@ -0,0 +1,10 @@
+CMAKE_SYSTEM_FRAMEWORK_PATH
+---------------------------
+
+.. versionadded:: 3.4
+
+Search path for macOS frameworks used by the :command:`find_library`,
+:command:`find_package`, :command:`find_path`, and :command:`find_file`
+commands. By default it contains the standard directories for the
+current system. It is *not* intended to be modified by the project,
+use :variable:`CMAKE_FRAMEWORK_PATH` for this.
diff --git a/Help/variable/CMAKE_SYSTEM_IGNORE_PATH.rst b/Help/variable/CMAKE_SYSTEM_IGNORE_PATH.rst
new file mode 100644
index 0000000..6afbd33
--- /dev/null
+++ b/Help/variable/CMAKE_SYSTEM_IGNORE_PATH.rst
@@ -0,0 +1,18 @@
+CMAKE_SYSTEM_IGNORE_PATH
+------------------------
+
+:ref:`Semicolon-separated list <CMake Language Lists>` of directories to be *ignored* by
+the :command:`find_program`, :command:`find_library`, :command:`find_file`,
+and :command:`find_path` commands. This is useful in cross-compiling
+environments where some system directories contain incompatible but
+possibly linkable libraries. For example, on cross-compiled cluster
+environments, this allows a user to ignore directories containing
+libraries meant for the front-end machine.
+
+By default this contains a list of directories containing incompatible
+binaries for the host system. See the :variable:`CMAKE_IGNORE_PATH` variable
+that is intended to be set by the project.
+
+See also the :variable:`CMAKE_SYSTEM_PREFIX_PATH`,
+:variable:`CMAKE_SYSTEM_LIBRARY_PATH`, :variable:`CMAKE_SYSTEM_INCLUDE_PATH`,
+and :variable:`CMAKE_SYSTEM_PROGRAM_PATH` variables.
diff --git a/Help/variable/CMAKE_SYSTEM_INCLUDE_PATH.rst b/Help/variable/CMAKE_SYSTEM_INCLUDE_PATH.rst
new file mode 100644
index 0000000..680404e
--- /dev/null
+++ b/Help/variable/CMAKE_SYSTEM_INCLUDE_PATH.rst
@@ -0,0 +1,8 @@
+CMAKE_SYSTEM_INCLUDE_PATH
+-------------------------
+
+:ref:`Semicolon-separated list <CMake Language Lists>` of directories specifying a search path
+for the :command:`find_file` and :command:`find_path` commands. By default
+this contains the standard directories for the current system. It is *not*
+intended to be modified by the project; use :variable:`CMAKE_INCLUDE_PATH` for
+this. See also :variable:`CMAKE_SYSTEM_PREFIX_PATH`.
diff --git a/Help/variable/CMAKE_SYSTEM_LIBRARY_PATH.rst b/Help/variable/CMAKE_SYSTEM_LIBRARY_PATH.rst
new file mode 100644
index 0000000..116832b
--- /dev/null
+++ b/Help/variable/CMAKE_SYSTEM_LIBRARY_PATH.rst
@@ -0,0 +1,8 @@
+CMAKE_SYSTEM_LIBRARY_PATH
+-------------------------
+
+:ref:`Semicolon-separated list <CMake Language Lists>` of directories specifying a search path
+for the :command:`find_library` command. By default this contains the
+standard directories for the current system. It is *not* intended to be
+modified by the project; use :variable:`CMAKE_LIBRARY_PATH` for this.
+See also :variable:`CMAKE_SYSTEM_PREFIX_PATH`.
diff --git a/Help/variable/CMAKE_SYSTEM_NAME.rst b/Help/variable/CMAKE_SYSTEM_NAME.rst
new file mode 100644
index 0000000..fef53ee
--- /dev/null
+++ b/Help/variable/CMAKE_SYSTEM_NAME.rst
@@ -0,0 +1,23 @@
+CMAKE_SYSTEM_NAME
+-----------------
+
+The name of the operating system for which CMake is to build.
+See the :variable:`CMAKE_SYSTEM_VERSION` variable for the OS version.
+
+Note that ``CMAKE_SYSTEM_NAME`` is not set to anything by default when running
+in script mode, since it's not building anything.
+
+System Name for Host Builds
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``CMAKE_SYSTEM_NAME`` is by default set to the same value as the
+:variable:`CMAKE_HOST_SYSTEM_NAME` variable so that the build
+targets the host system.
+
+System Name for Cross Compiling
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``CMAKE_SYSTEM_NAME`` may be set explicitly when first configuring a new build
+tree in order to enable :ref:`cross compiling <Cross Compiling Toolchain>`.
+In this case the :variable:`CMAKE_SYSTEM_VERSION` variable must also be
+set explicitly.
diff --git a/Help/variable/CMAKE_SYSTEM_PREFIX_PATH.rst b/Help/variable/CMAKE_SYSTEM_PREFIX_PATH.rst
new file mode 100644
index 0000000..81a7a0b
--- /dev/null
+++ b/Help/variable/CMAKE_SYSTEM_PREFIX_PATH.rst
@@ -0,0 +1,53 @@
+CMAKE_SYSTEM_PREFIX_PATH
+------------------------
+
+:ref:`Semicolon-separated list <CMake Language Lists>` of directories specifying installation
+*prefixes* to be searched by the :command:`find_package`,
+:command:`find_program`, :command:`find_library`, :command:`find_file`, and
+:command:`find_path` commands. Each command will add appropriate
+subdirectories (like ``bin``, ``lib``, or ``include``) as specified in its own
+documentation.
+
+By default this contains the system directories for the current system, the
+:variable:`CMAKE_INSTALL_PREFIX`, and the :variable:`CMAKE_STAGING_PREFIX`.
+The installation and staging prefixes may be excluded by setting
+the :variable:`CMAKE_FIND_NO_INSTALL_PREFIX` variable.
+
+The system directories that are contained in ``CMAKE_SYSTEM_PREFIX_PATH`` are
+locations that typically include installed software. An example being
+``/usr/local`` for UNIX based platforms. In addition to standard platform
+locations, CMake will also add values to ``CMAKE_SYSTEM_PREFIX_PATH`` based on
+environment variables. The environment variables and search locations that
+CMake uses may evolve over time, as platforms and their conventions also
+evolve. The following provides an indicative list of environment variables
+and locations that CMake searches, but they are subject to change:
+
+
+CrayLinuxEnvironment:
+ * ``ENV{SYSROOT_DIR}/``
+ * ``ENV{SYSROOT_DIR}/usr``
+ * ``ENV{SYSROOT_DIR}/usr/local``
+
+Darwin:
+ * ``ENV{SDKROOT}/usr`` When ``CMAKE_OSX_SYSROOT`` is not explicitly specified.
+
+OpenBSD:
+ * ``ENV{LOCALBASE}``
+
+Unix:
+ * ``ENV{CONDA_PREFIX}`` when using a conda compiler
+
+Windows:
+ * ``ENV{ProgramW6432}``
+ * ``ENV{ProgramFiles}``
+ * ``ENV{ProgramFiles(x86)}``
+ * ``ENV{SystemDrive}/Program Files``
+ * ``ENV{SystemDrive}/Program Files (x86)``
+
+
+``CMAKE_SYSTEM_PREFIX_PATH`` is *not* intended to be modified by the project;
+use :variable:`CMAKE_PREFIX_PATH` for this.
+
+See also :variable:`CMAKE_SYSTEM_INCLUDE_PATH`,
+:variable:`CMAKE_SYSTEM_LIBRARY_PATH`, :variable:`CMAKE_SYSTEM_PROGRAM_PATH`,
+and :variable:`CMAKE_SYSTEM_IGNORE_PATH`.
diff --git a/Help/variable/CMAKE_SYSTEM_PROCESSOR.rst b/Help/variable/CMAKE_SYSTEM_PROCESSOR.rst
new file mode 100644
index 0000000..ce16215
--- /dev/null
+++ b/Help/variable/CMAKE_SYSTEM_PROCESSOR.rst
@@ -0,0 +1,13 @@
+CMAKE_SYSTEM_PROCESSOR
+----------------------
+
+When not cross-compiling, this variable has the same value as the
+:variable:`CMAKE_HOST_SYSTEM_PROCESSOR` variable. In many cases,
+this will correspond to the target architecture for the build, but
+this is not guaranteed. (E.g. on Windows, the host may be ``AMD64``
+even when using a MSVC ``cl`` compiler with a 32-bit target.)
+
+When cross-compiling, a :variable:`CMAKE_TOOLCHAIN_FILE` should set
+the ``CMAKE_SYSTEM_PROCESSOR`` variable to match target architecture
+that it specifies (via :variable:`CMAKE_<LANG>_COMPILER` and perhaps
+:variable:`CMAKE_<LANG>_COMPILER_TARGET`).
diff --git a/Help/variable/CMAKE_SYSTEM_PROGRAM_PATH.rst b/Help/variable/CMAKE_SYSTEM_PROGRAM_PATH.rst
new file mode 100644
index 0000000..9b70361
--- /dev/null
+++ b/Help/variable/CMAKE_SYSTEM_PROGRAM_PATH.rst
@@ -0,0 +1,8 @@
+CMAKE_SYSTEM_PROGRAM_PATH
+-------------------------
+
+:ref:`Semicolon-separated list <CMake Language Lists>` of directories specifying a search path
+for the :command:`find_program` command. By default this contains the
+standard directories for the current system. It is *not* intended to be
+modified by the project; use :variable:`CMAKE_PROGRAM_PATH` for this.
+See also :variable:`CMAKE_SYSTEM_PREFIX_PATH`.
diff --git a/Help/variable/CMAKE_SYSTEM_VERSION.rst b/Help/variable/CMAKE_SYSTEM_VERSION.rst
new file mode 100644
index 0000000..aba8ca3
--- /dev/null
+++ b/Help/variable/CMAKE_SYSTEM_VERSION.rst
@@ -0,0 +1,28 @@
+CMAKE_SYSTEM_VERSION
+--------------------
+
+The version of the operating system for which CMake is to build.
+See the :variable:`CMAKE_SYSTEM_NAME` variable for the OS name.
+
+System Version for Host Builds
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When the :variable:`CMAKE_SYSTEM_NAME` variable takes its default value
+then ``CMAKE_SYSTEM_VERSION`` is by default set to the same value as the
+:variable:`CMAKE_HOST_SYSTEM_VERSION` variable so that the build targets
+the host system version.
+
+In the case of a host build then ``CMAKE_SYSTEM_VERSION`` may be set
+explicitly when first configuring a new build tree in order to enable
+targeting the build for a different version of the host operating system
+than is actually running on the host. This is allowed and not considered
+cross compiling so long as the binaries built for the specified OS version
+can still run on the host.
+
+System Version for Cross Compiling
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When the :variable:`CMAKE_SYSTEM_NAME` variable is set explicitly to
+enable :ref:`cross compiling <Cross Compiling Toolchain>` then the
+value of ``CMAKE_SYSTEM_VERSION`` must also be set explicitly to specify
+the target system version.
diff --git a/Help/variable/CMAKE_Swift_LANGUAGE_VERSION.rst b/Help/variable/CMAKE_Swift_LANGUAGE_VERSION.rst
new file mode 100644
index 0000000..fce6fa7
--- /dev/null
+++ b/Help/variable/CMAKE_Swift_LANGUAGE_VERSION.rst
@@ -0,0 +1,11 @@
+CMAKE_Swift_LANGUAGE_VERSION
+----------------------------
+
+.. versionadded:: 3.7
+
+Set to the Swift language version number. If not set, the oldest legacy
+version known to be available in the host Xcode version is assumed:
+
+* Swift ``4.0`` for Xcode 10.2 and above.
+* Swift ``3.0`` for Xcode 8.3 and above.
+* Swift ``2.3`` for Xcode 8.2 and below.
diff --git a/Help/variable/CMAKE_Swift_MODULE_DIRECTORY.rst b/Help/variable/CMAKE_Swift_MODULE_DIRECTORY.rst
new file mode 100644
index 0000000..3694973
--- /dev/null
+++ b/Help/variable/CMAKE_Swift_MODULE_DIRECTORY.rst
@@ -0,0 +1,10 @@
+CMAKE_Swift_MODULE_DIRECTORY
+----------------------------
+
+.. versionadded:: 3.15
+
+Swift module output directory.
+
+This variable is used to initialise the :prop_tgt:`Swift_MODULE_DIRECTORY`
+property on all the targets. See the target property for additional
+information.
diff --git a/Help/variable/CMAKE_Swift_NUM_THREADS.rst b/Help/variable/CMAKE_Swift_NUM_THREADS.rst
new file mode 100644
index 0000000..e1dafb0
--- /dev/null
+++ b/Help/variable/CMAKE_Swift_NUM_THREADS.rst
@@ -0,0 +1,10 @@
+CMAKE_Swift_NUM_THREADS
+-----------------------
+
+.. versionadded:: 3.15.1
+
+Number of threads for parallel compilation for Swift targets.
+
+This variable controls the number of parallel jobs that the swift driver creates
+for building targets. If not specified, it will default to the number of
+logical CPUs on the host.
diff --git a/Help/variable/CMAKE_TOOLCHAIN_FILE.rst b/Help/variable/CMAKE_TOOLCHAIN_FILE.rst
new file mode 100644
index 0000000..168ee74
--- /dev/null
+++ b/Help/variable/CMAKE_TOOLCHAIN_FILE.rst
@@ -0,0 +1,9 @@
+CMAKE_TOOLCHAIN_FILE
+--------------------
+
+Path to toolchain file supplied to :manual:`cmake(1)`.
+
+This variable is specified on the command line when cross-compiling with CMake.
+It is the path to a file which is read early in the CMake run and which
+specifies locations for compilers and toolchain utilities, and other target
+platform and compiler related information.
diff --git a/Help/variable/CMAKE_TRY_COMPILE_CONFIGURATION.rst b/Help/variable/CMAKE_TRY_COMPILE_CONFIGURATION.rst
new file mode 100644
index 0000000..d731f02
--- /dev/null
+++ b/Help/variable/CMAKE_TRY_COMPILE_CONFIGURATION.rst
@@ -0,0 +1,10 @@
+CMAKE_TRY_COMPILE_CONFIGURATION
+-------------------------------
+
+Build configuration used for :command:`try_compile` and :command:`try_run`
+projects.
+
+Projects built by :command:`try_compile` and :command:`try_run` are built
+synchronously during the CMake configuration step. Therefore a specific build
+configuration must be chosen even if the generated build system
+supports multiple configurations.
diff --git a/Help/variable/CMAKE_TRY_COMPILE_PLATFORM_VARIABLES.rst b/Help/variable/CMAKE_TRY_COMPILE_PLATFORM_VARIABLES.rst
new file mode 100644
index 0000000..d178513
--- /dev/null
+++ b/Help/variable/CMAKE_TRY_COMPILE_PLATFORM_VARIABLES.rst
@@ -0,0 +1,28 @@
+CMAKE_TRY_COMPILE_PLATFORM_VARIABLES
+------------------------------------
+
+.. versionadded:: 3.6
+
+List of variables that the :command:`try_compile` command source file signature
+must propagate into the test project in order to target the same platform as
+the host project.
+
+This variable should not be set by project code. It is meant to be set by
+CMake's platform information modules for the current toolchain, or by a
+toolchain file when used with :variable:`CMAKE_TOOLCHAIN_FILE`.
+
+Variables meaningful to CMake, such as :variable:`CMAKE_<LANG>_FLAGS`, are
+propagated automatically. The ``CMAKE_TRY_COMPILE_PLATFORM_VARIABLES``
+variable may be set to pass custom variables meaningful to a toolchain file.
+For example, a toolchain file may contain:
+
+.. code-block:: cmake
+
+ set(CMAKE_SYSTEM_NAME ...)
+ set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES MY_CUSTOM_VARIABLE)
+ # ... use MY_CUSTOM_VARIABLE ...
+
+If a user passes ``-DMY_CUSTOM_VARIABLE=SomeValue`` to CMake then this
+setting will be made visible to the toolchain file both for the main
+project and for test projects generated by the :command:`try_compile`
+command source file signature.
diff --git a/Help/variable/CMAKE_TRY_COMPILE_TARGET_TYPE.rst b/Help/variable/CMAKE_TRY_COMPILE_TARGET_TYPE.rst
new file mode 100644
index 0000000..b60539f
--- /dev/null
+++ b/Help/variable/CMAKE_TRY_COMPILE_TARGET_TYPE.rst
@@ -0,0 +1,17 @@
+CMAKE_TRY_COMPILE_TARGET_TYPE
+-----------------------------
+
+.. versionadded:: 3.6
+
+Type of target generated for :command:`try_compile` calls using the
+source file signature. Valid values are:
+
+``EXECUTABLE``
+ Use :command:`add_executable` to name the source file in the
+ generated project. This is the default if no value is given.
+
+``STATIC_LIBRARY``
+ Use :command:`add_library` with the ``STATIC`` option to name the
+ source file in the generated project. This avoids running the
+ linker and is intended for use with cross-compiling toolchains
+ that cannot link without custom flags or linker scripts.
diff --git a/Help/variable/CMAKE_TWEAK_VERSION.rst b/Help/variable/CMAKE_TWEAK_VERSION.rst
new file mode 100644
index 0000000..be2e050
--- /dev/null
+++ b/Help/variable/CMAKE_TWEAK_VERSION.rst
@@ -0,0 +1,11 @@
+CMAKE_TWEAK_VERSION
+-------------------
+
+Defined to ``0`` for compatibility with code written for older
+CMake versions that may have defined higher values.
+
+.. note::
+
+ In CMake versions 2.8.2 through 2.8.12, this variable holds
+ the fourth version number component of the
+ :variable:`CMAKE_VERSION` variable.
diff --git a/Help/variable/CMAKE_UNITY_BUILD.rst b/Help/variable/CMAKE_UNITY_BUILD.rst
new file mode 100644
index 0000000..54a781a
--- /dev/null
+++ b/Help/variable/CMAKE_UNITY_BUILD.rst
@@ -0,0 +1,22 @@
+CMAKE_UNITY_BUILD
+-----------------
+
+.. versionadded:: 3.16
+
+This variable is used to initialize the :prop_tgt:`UNITY_BUILD`
+property of targets when they are created. Setting it to true
+enables batch compilation of multiple sources within each target.
+This feature is known as a *Unity* or *Jumbo* build.
+
+Projects should not set this variable, it is intended as a developer
+control to be set on the :manual:`cmake(1)` command line or other
+equivalent methods. The developer must have the ability to enable or
+disable unity builds according to the capabilities of their own machine
+and compiler.
+
+By default, this variable is not set, which will result in unity builds
+being disabled.
+
+.. note::
+ This option currently does not work well in combination with
+ the :variable:`CMAKE_EXPORT_COMPILE_COMMANDS` variable.
diff --git a/Help/variable/CMAKE_UNITY_BUILD_BATCH_SIZE.rst b/Help/variable/CMAKE_UNITY_BUILD_BATCH_SIZE.rst
new file mode 100644
index 0000000..7733fe8
--- /dev/null
+++ b/Help/variable/CMAKE_UNITY_BUILD_BATCH_SIZE.rst
@@ -0,0 +1,9 @@
+CMAKE_UNITY_BUILD_BATCH_SIZE
+----------------------------
+
+.. versionadded:: 3.16
+
+This variable is used to initialize the :prop_tgt:`UNITY_BUILD_BATCH_SIZE`
+property of targets when they are created. It specifies the default upper
+limit on the number of source files that may be combined in any one unity
+source file when unity builds are enabled for a target.
diff --git a/Help/variable/CMAKE_UNITY_BUILD_UNIQUE_ID.rst b/Help/variable/CMAKE_UNITY_BUILD_UNIQUE_ID.rst
new file mode 100644
index 0000000..64ef18a
--- /dev/null
+++ b/Help/variable/CMAKE_UNITY_BUILD_UNIQUE_ID.rst
@@ -0,0 +1,8 @@
+CMAKE_UNITY_BUILD_UNIQUE_ID
+---------------------------
+
+.. versionadded:: 3.20
+
+This variable is used to initialize the :prop_tgt:`UNITY_BUILD_UNIQUE_ID`
+property of targets when they are created. It specifies the name of the
+unique identifier generated per file in a unity build.
diff --git a/Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE.rst b/Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE.rst
new file mode 100644
index 0000000..622278e
--- /dev/null
+++ b/Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE.rst
@@ -0,0 +1,25 @@
+CMAKE_USER_MAKE_RULES_OVERRIDE
+------------------------------
+
+Specify a CMake file that overrides platform information.
+
+CMake loads the specified file while enabling support for each
+language from either the :command:`project` or :command:`enable_language`
+commands. It is loaded after CMake's builtin compiler and platform information
+modules have been loaded but before the information is used. The file
+may set platform information variables to override CMake's defaults.
+
+This feature is intended for use only in overriding information
+variables that must be set before CMake builds its first test project
+to check that the compiler for a language works. It should not be
+used to load a file in cases that a normal :command:`include` will work. Use
+it only as a last resort for behavior that cannot be achieved any
+other way. For example, one may set the
+:variable:`CMAKE_C_FLAGS_INIT <CMAKE_<LANG>_FLAGS_INIT>` variable
+to change the default value used to initialize the
+:variable:`CMAKE_C_FLAGS <CMAKE_<LANG>_FLAGS>` variable
+before it is cached. The override file should NOT be used to set anything
+that could be set after languages are enabled, such as variables like
+:variable:`CMAKE_RUNTIME_OUTPUT_DIRECTORY` that affect the placement of
+binaries. Information set in the file will be used for :command:`try_compile`
+and :command:`try_run` builds too.
diff --git a/Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE_LANG.rst b/Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE_LANG.rst
new file mode 100644
index 0000000..e7139ac
--- /dev/null
+++ b/Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE_LANG.rst
@@ -0,0 +1,8 @@
+CMAKE_USER_MAKE_RULES_OVERRIDE_<LANG>
+-------------------------------------
+
+Specify a CMake file that overrides platform information for ``<LANG>``.
+
+This is a language-specific version of
+:variable:`CMAKE_USER_MAKE_RULES_OVERRIDE` loaded only when enabling language
+``<LANG>``.
diff --git a/Help/variable/CMAKE_USE_RELATIVE_PATHS.rst b/Help/variable/CMAKE_USE_RELATIVE_PATHS.rst
new file mode 100644
index 0000000..06fe0fb
--- /dev/null
+++ b/Help/variable/CMAKE_USE_RELATIVE_PATHS.rst
@@ -0,0 +1,5 @@
+CMAKE_USE_RELATIVE_PATHS
+------------------------
+
+This variable has no effect. The partially implemented effect it
+had in previous releases was removed in CMake 3.4.
diff --git a/Help/variable/CMAKE_VERBOSE_MAKEFILE.rst b/Help/variable/CMAKE_VERBOSE_MAKEFILE.rst
new file mode 100644
index 0000000..232a2fd
--- /dev/null
+++ b/Help/variable/CMAKE_VERBOSE_MAKEFILE.rst
@@ -0,0 +1,9 @@
+CMAKE_VERBOSE_MAKEFILE
+----------------------
+
+Enable verbose output from Makefile builds.
+
+This variable is a cache entry initialized (to ``FALSE``) by
+the :command:`project` command. Users may enable the option
+in their local build tree to get more verbose output from
+Makefile builds and show each command line as it is launched.
diff --git a/Help/variable/CMAKE_VERSION.rst b/Help/variable/CMAKE_VERSION.rst
new file mode 100644
index 0000000..872e2fa
--- /dev/null
+++ b/Help/variable/CMAKE_VERSION.rst
@@ -0,0 +1,51 @@
+CMAKE_VERSION
+-------------
+
+The CMake version string as three non-negative integer components
+separated by ``.`` and possibly followed by ``-`` and other information.
+The first two components represent the feature level and the third
+component represents either a bug-fix level or development date.
+
+Release versions and release candidate versions of CMake use the format::
+
+ <major>.<minor>.<patch>[-rc<n>]
+
+where the ``<patch>`` component is less than ``20000000``. Development
+versions of CMake use the format::
+
+ <major>.<minor>.<date>[-<id>]
+
+where the ``<date>`` component is of format ``CCYYMMDD`` and ``<id>``
+may contain arbitrary text. This represents development as of a
+particular date following the ``<major>.<minor>`` feature release.
+
+Individual component values are also available in variables:
+
+* :variable:`CMAKE_MAJOR_VERSION`
+* :variable:`CMAKE_MINOR_VERSION`
+* :variable:`CMAKE_PATCH_VERSION`
+* :variable:`CMAKE_TWEAK_VERSION`
+
+Use the :command:`if` command ``VERSION_LESS``, ``VERSION_GREATER``,
+``VERSION_EQUAL``, ``VERSION_LESS_EQUAL``, or ``VERSION_GREATER_EQUAL``
+operators to compare version string values against ``CMAKE_VERSION`` using a
+component-wise test. Version component values may be 10 or larger so do not
+attempt to compare version strings as floating-point numbers.
+
+.. note::
+
+ CMake versions 2.8.2 through 2.8.12 used three components for the
+ feature level. Release versions represented the bug-fix level in a
+ fourth component, i.e. ``<major>.<minor>.<patch>[.<tweak>][-rc<n>]``.
+ Development versions represented the development date in the fourth
+ component, i.e. ``<major>.<minor>.<patch>.<date>[-<id>]``.
+
+ CMake versions prior to 2.8.2 used three components for the
+ feature level and had no bug-fix component. Release versions
+ used an even-valued second component, i.e.
+ ``<major>.<even-minor>.<patch>[-rc<n>]``. Development versions
+ used an odd-valued second component with the development date as
+ the third component, i.e. ``<major>.<odd-minor>.<date>``.
+
+ The ``CMAKE_VERSION`` variable is defined by CMake 2.6.3 and higher.
+ Earlier versions defined only the individual component variables.
diff --git a/Help/variable/CMAKE_VISIBILITY_INLINES_HIDDEN.rst b/Help/variable/CMAKE_VISIBILITY_INLINES_HIDDEN.rst
new file mode 100644
index 0000000..150bacc
--- /dev/null
+++ b/Help/variable/CMAKE_VISIBILITY_INLINES_HIDDEN.rst
@@ -0,0 +1,5 @@
+CMAKE_VISIBILITY_INLINES_HIDDEN
+-------------------------------
+
+Default value for the :prop_tgt:`VISIBILITY_INLINES_HIDDEN` target
+property when a target is created.
diff --git a/Help/variable/CMAKE_VS_DEVENV_COMMAND.rst b/Help/variable/CMAKE_VS_DEVENV_COMMAND.rst
new file mode 100644
index 0000000..f109a9e
--- /dev/null
+++ b/Help/variable/CMAKE_VS_DEVENV_COMMAND.rst
@@ -0,0 +1,14 @@
+CMAKE_VS_DEVENV_COMMAND
+-----------------------
+
+The generators for :generator:`Visual Studio 9 2008` and above set this
+variable to the ``devenv.com`` command installed with the corresponding
+Visual Studio version. Note that this variable may be empty on
+Visual Studio Express editions because they do not provide this tool.
+
+This variable is not defined by other generators even if ``devenv.com``
+is installed on the computer.
+
+The :variable:`CMAKE_VS_MSBUILD_COMMAND` is also provided for
+:generator:`Visual Studio 10 2010` and above.
+See also the :variable:`CMAKE_MAKE_PROGRAM` variable.
diff --git a/Help/variable/CMAKE_VS_GLOBALS.rst b/Help/variable/CMAKE_VS_GLOBALS.rst
new file mode 100644
index 0000000..d4514fe
--- /dev/null
+++ b/Help/variable/CMAKE_VS_GLOBALS.rst
@@ -0,0 +1,23 @@
+CMAKE_VS_GLOBALS
+----------------
+
+.. versionadded:: 3.13
+
+List of ``Key=Value`` records to be set per target as target properties
+:prop_tgt:`VS_GLOBAL_<variable>` with ``variable=Key`` and value ``Value``.
+
+For example:
+
+.. code-block:: cmake
+
+ set(CMAKE_VS_GLOBALS
+ "DefaultLanguage=en-US"
+ "MinimumVisualStudioVersion=14.0"
+ )
+
+will set properties ``VS_GLOBAL_DefaultLanguage`` to ``en-US`` and
+``VS_GLOBAL_MinimumVisualStudioVersion`` to ``14.0`` for all targets
+(except for ``INTERFACE`` libraries).
+
+This variable is meant to be set by a
+:variable:`toolchain file <CMAKE_TOOLCHAIN_FILE>`.
diff --git a/Help/variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD.rst b/Help/variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD.rst
new file mode 100644
index 0000000..ace94e4
--- /dev/null
+++ b/Help/variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD.rst
@@ -0,0 +1,10 @@
+CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD
+-----------------------------------------
+
+.. versionadded:: 3.3
+
+Include ``INSTALL`` target to default build.
+
+In Visual Studio solution, by default the ``INSTALL`` target will not be part
+of the default build. Setting this variable will enable the ``INSTALL`` target
+to be part of the default build.
diff --git a/Help/variable/CMAKE_VS_INCLUDE_PACKAGE_TO_DEFAULT_BUILD.rst b/Help/variable/CMAKE_VS_INCLUDE_PACKAGE_TO_DEFAULT_BUILD.rst
new file mode 100644
index 0000000..ab4d0fa
--- /dev/null
+++ b/Help/variable/CMAKE_VS_INCLUDE_PACKAGE_TO_DEFAULT_BUILD.rst
@@ -0,0 +1,10 @@
+CMAKE_VS_INCLUDE_PACKAGE_TO_DEFAULT_BUILD
+-----------------------------------------
+
+.. versionadded:: 3.8
+
+Include ``PACKAGE`` target to default build.
+
+In Visual Studio solution, by default the ``PACKAGE`` target will not be part
+of the default build. Setting this variable will enable the ``PACKAGE`` target
+to be part of the default build.
diff --git a/Help/variable/CMAKE_VS_INTEL_Fortran_PROJECT_VERSION.rst b/Help/variable/CMAKE_VS_INTEL_Fortran_PROJECT_VERSION.rst
new file mode 100644
index 0000000..ceedf28
--- /dev/null
+++ b/Help/variable/CMAKE_VS_INTEL_Fortran_PROJECT_VERSION.rst
@@ -0,0 +1,7 @@
+CMAKE_VS_INTEL_Fortran_PROJECT_VERSION
+--------------------------------------
+
+When generating for :generator:`Visual Studio 9 2008` or greater with the Intel
+Fortran plugin installed, this specifies the ``.vfproj`` project file format
+version. This is intended for internal use by CMake and should not be
+used by project code.
diff --git a/Help/variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING.rst b/Help/variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING.rst
new file mode 100644
index 0000000..0a02a32
--- /dev/null
+++ b/Help/variable/CMAKE_VS_JUST_MY_CODE_DEBUGGING.rst
@@ -0,0 +1,10 @@
+CMAKE_VS_JUST_MY_CODE_DEBUGGING
+-------------------------------
+
+.. versionadded:: 3.15
+
+Enable Just My Code with Visual Studio debugger.
+
+This variable is used to initialize the :prop_tgt:`VS_JUST_MY_CODE_DEBUGGING`
+property on all targets when they are created. See that target property for
+additional information.
diff --git a/Help/variable/CMAKE_VS_MSBUILD_COMMAND.rst b/Help/variable/CMAKE_VS_MSBUILD_COMMAND.rst
new file mode 100644
index 0000000..58f2bef
--- /dev/null
+++ b/Help/variable/CMAKE_VS_MSBUILD_COMMAND.rst
@@ -0,0 +1,13 @@
+CMAKE_VS_MSBUILD_COMMAND
+------------------------
+
+The generators for :generator:`Visual Studio 10 2010` and above set this
+variable to the ``MSBuild.exe`` command installed with the corresponding
+Visual Studio version.
+
+This variable is not defined by other generators even if ``MSBuild.exe``
+is installed on the computer.
+
+The :variable:`CMAKE_VS_DEVENV_COMMAND` is also provided for the
+non-Express editions of Visual Studio.
+See also the :variable:`CMAKE_MAKE_PROGRAM` variable.
diff --git a/Help/variable/CMAKE_VS_NsightTegra_VERSION.rst b/Help/variable/CMAKE_VS_NsightTegra_VERSION.rst
new file mode 100644
index 0000000..2982b39
--- /dev/null
+++ b/Help/variable/CMAKE_VS_NsightTegra_VERSION.rst
@@ -0,0 +1,9 @@
+CMAKE_VS_NsightTegra_VERSION
+----------------------------
+
+.. versionadded:: 3.1
+
+When using a Visual Studio generator with the
+:variable:`CMAKE_SYSTEM_NAME` variable set to ``Android``,
+this variable contains the version number of the
+installed NVIDIA Nsight Tegra Visual Studio Edition.
diff --git a/Help/variable/CMAKE_VS_PLATFORM_NAME.rst b/Help/variable/CMAKE_VS_PLATFORM_NAME.rst
new file mode 100644
index 0000000..7d08add
--- /dev/null
+++ b/Help/variable/CMAKE_VS_PLATFORM_NAME.rst
@@ -0,0 +1,12 @@
+CMAKE_VS_PLATFORM_NAME
+----------------------
+
+.. versionadded:: 3.1
+
+Visual Studio target platform name used by the current generator.
+
+VS 8 and above allow project files to specify a target platform.
+CMake provides the name of the chosen platform in this variable.
+See the :variable:`CMAKE_GENERATOR_PLATFORM` variable for details.
+
+See also the :variable:`CMAKE_VS_PLATFORM_NAME_DEFAULT` variable.
diff --git a/Help/variable/CMAKE_VS_PLATFORM_NAME_DEFAULT.rst b/Help/variable/CMAKE_VS_PLATFORM_NAME_DEFAULT.rst
new file mode 100644
index 0000000..6440174
--- /dev/null
+++ b/Help/variable/CMAKE_VS_PLATFORM_NAME_DEFAULT.rst
@@ -0,0 +1,11 @@
+CMAKE_VS_PLATFORM_NAME_DEFAULT
+------------------------------
+
+.. versionadded:: 3.14.3
+
+Default for the Visual Studio target platform name for the current generator
+without considering the value of the :variable:`CMAKE_GENERATOR_PLATFORM`
+variable. For :ref:`Visual Studio Generators` for VS 2017 and below this is
+always ``Win32``. For VS 2019 and above this is based on the host platform.
+
+See also the :variable:`CMAKE_VS_PLATFORM_NAME` variable.
diff --git a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET.rst b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET.rst
new file mode 100644
index 0000000..ed2d3f3
--- /dev/null
+++ b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET.rst
@@ -0,0 +1,12 @@
+CMAKE_VS_PLATFORM_TOOLSET
+-------------------------
+
+Visual Studio Platform Toolset name.
+
+VS 10 and above use MSBuild under the hood and support multiple
+compiler toolchains. CMake may specify a toolset explicitly, such as
+``v110`` for VS 11 or ``Windows7.1SDK`` for 64-bit support in VS 10
+Express. CMake provides the name of the chosen toolset in this
+variable.
+
+See the :variable:`CMAKE_GENERATOR_TOOLSET` variable for details.
diff --git a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst
new file mode 100644
index 0000000..e66378d
--- /dev/null
+++ b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst
@@ -0,0 +1,16 @@
+CMAKE_VS_PLATFORM_TOOLSET_CUDA
+------------------------------
+
+.. versionadded:: 3.9
+
+NVIDIA CUDA Toolkit version whose Visual Studio toolset to use.
+
+The :ref:`Visual Studio Generators` for VS 2010 and above support using
+a CUDA toolset provided by a CUDA Toolkit. The toolset version number
+may be specified by a field in :variable:`CMAKE_GENERATOR_TOOLSET` of
+the form ``cuda=8.0``. Or it is automatically detected if a path to
+a standalone CUDA directory is specified in the form ``cuda=C:\path\to\cuda``.
+If none is specified CMake will choose a default version.
+CMake provides the selected CUDA toolset version in this variable.
+The value may be empty if no CUDA Toolkit with Visual Studio integration
+is installed.
diff --git a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR.rst b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR.rst
new file mode 100644
index 0000000..a19e7e1
--- /dev/null
+++ b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR.rst
@@ -0,0 +1,17 @@
+CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR
+-----------------------------------------
+
+.. versionadded:: 3.16
+
+Path to standalone NVIDIA CUDA Toolkit (eg. extracted from installer).
+
+The :ref:`Visual Studio Generators` for VS 2010 and above support using
+a standalone (non-installed) NVIDIA CUDA toolkit. The path
+may be specified by a field in :variable:`CMAKE_GENERATOR_TOOLSET` of
+the form ``cuda=C:\path\to\cuda``. The given directory must at least
+contain the nvcc compiler in path ``.\bin`` and must provide Visual Studio
+integration files in path ``.\extras\visual_studio_integration\
+MSBuildExtensions\``. One can create a standalone CUDA toolkit directory by
+either opening a installer with 7zip or copying the files that are extracted
+by the running installer. The value may be empty if no path to a standalone
+CUDA Toolkit was specified.
diff --git a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE.rst b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE.rst
new file mode 100644
index 0000000..84d7212
--- /dev/null
+++ b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE.rst
@@ -0,0 +1,12 @@
+CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE
+-------------------------------------------
+
+.. versionadded:: 3.8
+
+Visual Studio preferred tool architecture.
+
+The :ref:`Visual Studio Generators` for VS 2013 and above support using
+either the 32-bit or 64-bit host toolchains by specifying a ``host=x86``
+or ``host=x64`` value in the :variable:`CMAKE_GENERATOR_TOOLSET` option.
+CMake provides the selected toolchain architecture preference in this
+variable (``x86``, ``x64``, or empty).
diff --git a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst
new file mode 100644
index 0000000..c4369ee
--- /dev/null
+++ b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst
@@ -0,0 +1,33 @@
+CMAKE_VS_PLATFORM_TOOLSET_VERSION
+---------------------------------
+
+.. versionadded:: 3.12
+
+Visual Studio Platform Toolset version.
+
+The :ref:`Visual Studio Generators` for VS 2017 and above allow to
+select minor versions of the same toolset. The toolset version number
+may be specified by a field in :variable:`CMAKE_GENERATOR_TOOLSET` of
+the form ``version=14.11``. If none is specified CMake will choose a default
+toolset. The value may be empty if no minor version was selected and the
+default is used.
+
+If the value is not empty, it is the version number that MSBuild uses in
+its ``Microsoft.VCToolsVersion.*.props`` file names.
+
+.. versionadded:: 3.19.7
+
+ VS 16.9's toolset may also be specified as ``14.28.16.9`` because
+ VS 16.10 uses the file name ``Microsoft.VCToolsVersion.14.28.16.9.props``.
+
+Three-Component MSVC Toolset Versions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.19.7
+
+The ``version=`` field may be given a three-component toolset version
+such as ``14.28.29910``, and CMake will convert it to the name used by
+MSBuild ``Microsoft.VCToolsVersion.*.props`` files. This is useful
+to distinguish between VS 16.8's ``14.28.29333`` toolset and VS 16.9's
+``14.28.29910`` toolset. It also matches ``vcvarsall``'s ``-vcvars_ver=``
+behavior.
diff --git a/Help/variable/CMAKE_VS_SDK_EXCLUDE_DIRECTORIES.rst b/Help/variable/CMAKE_VS_SDK_EXCLUDE_DIRECTORIES.rst
new file mode 100644
index 0000000..969f328
--- /dev/null
+++ b/Help/variable/CMAKE_VS_SDK_EXCLUDE_DIRECTORIES.rst
@@ -0,0 +1,6 @@
+CMAKE_VS_SDK_EXCLUDE_DIRECTORIES
+--------------------------------
+
+.. versionadded:: 3.12
+
+This variable allows to override Visual Studio default Exclude Directories.
diff --git a/Help/variable/CMAKE_VS_SDK_EXECUTABLE_DIRECTORIES.rst b/Help/variable/CMAKE_VS_SDK_EXECUTABLE_DIRECTORIES.rst
new file mode 100644
index 0000000..7455e10
--- /dev/null
+++ b/Help/variable/CMAKE_VS_SDK_EXECUTABLE_DIRECTORIES.rst
@@ -0,0 +1,6 @@
+CMAKE_VS_SDK_EXECUTABLE_DIRECTORIES
+-----------------------------------
+
+.. versionadded:: 3.12
+
+This variable allows to override Visual Studio default Executable Directories.
diff --git a/Help/variable/CMAKE_VS_SDK_INCLUDE_DIRECTORIES.rst b/Help/variable/CMAKE_VS_SDK_INCLUDE_DIRECTORIES.rst
new file mode 100644
index 0000000..3f27aea
--- /dev/null
+++ b/Help/variable/CMAKE_VS_SDK_INCLUDE_DIRECTORIES.rst
@@ -0,0 +1,6 @@
+CMAKE_VS_SDK_INCLUDE_DIRECTORIES
+--------------------------------
+
+.. versionadded:: 3.12
+
+This variable allows to override Visual Studio default Include Directories.
diff --git a/Help/variable/CMAKE_VS_SDK_LIBRARY_DIRECTORIES.rst b/Help/variable/CMAKE_VS_SDK_LIBRARY_DIRECTORIES.rst
new file mode 100644
index 0000000..35e45a3
--- /dev/null
+++ b/Help/variable/CMAKE_VS_SDK_LIBRARY_DIRECTORIES.rst
@@ -0,0 +1,6 @@
+CMAKE_VS_SDK_LIBRARY_DIRECTORIES
+--------------------------------
+
+.. versionadded:: 3.12
+
+This variable allows to override Visual Studio default Library Directories.
diff --git a/Help/variable/CMAKE_VS_SDK_LIBRARY_WINRT_DIRECTORIES.rst b/Help/variable/CMAKE_VS_SDK_LIBRARY_WINRT_DIRECTORIES.rst
new file mode 100644
index 0000000..24b90b6
--- /dev/null
+++ b/Help/variable/CMAKE_VS_SDK_LIBRARY_WINRT_DIRECTORIES.rst
@@ -0,0 +1,7 @@
+CMAKE_VS_SDK_LIBRARY_WINRT_DIRECTORIES
+--------------------------------------
+
+.. versionadded:: 3.12
+
+This variable allows to override Visual Studio default Library WinRT
+Directories.
diff --git a/Help/variable/CMAKE_VS_SDK_REFERENCE_DIRECTORIES.rst b/Help/variable/CMAKE_VS_SDK_REFERENCE_DIRECTORIES.rst
new file mode 100644
index 0000000..00382fe
--- /dev/null
+++ b/Help/variable/CMAKE_VS_SDK_REFERENCE_DIRECTORIES.rst
@@ -0,0 +1,6 @@
+CMAKE_VS_SDK_REFERENCE_DIRECTORIES
+----------------------------------
+
+.. versionadded:: 3.12
+
+This variable allows to override Visual Studio default Reference Directories.
diff --git a/Help/variable/CMAKE_VS_SDK_SOURCE_DIRECTORIES.rst b/Help/variable/CMAKE_VS_SDK_SOURCE_DIRECTORIES.rst
new file mode 100644
index 0000000..b98c999
--- /dev/null
+++ b/Help/variable/CMAKE_VS_SDK_SOURCE_DIRECTORIES.rst
@@ -0,0 +1,6 @@
+CMAKE_VS_SDK_SOURCE_DIRECTORIES
+-------------------------------
+
+.. versionadded:: 3.12
+
+This variable allows to override Visual Studio default Source Directories.
diff --git a/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.rst b/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.rst
new file mode 100644
index 0000000..eb71049
--- /dev/null
+++ b/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.rst
@@ -0,0 +1,21 @@
+CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION
+----------------------------------------
+
+.. versionadded:: 3.4
+
+Visual Studio Windows Target Platform Version.
+
+When targeting Windows 10 and above Visual Studio 2015 and above support
+specification of a target Windows version to select a corresponding SDK.
+The :variable:`CMAKE_SYSTEM_VERSION` variable may be set to specify a
+version. Otherwise CMake computes a default version based on the Windows
+SDK versions available. The chosen Windows target version number is provided
+in ``CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION``. If no Windows 10 SDK
+is available this value will be empty.
+
+One may set a ``CMAKE_WINDOWS_KITS_10_DIR`` *environment variable*
+to an absolute path to tell CMake to look for Windows 10 SDKs in
+a custom location. The specified directory is expected to contain
+``Include/10.0.*`` directories.
+
+See also :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM`.
diff --git a/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM.rst b/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM.rst
new file mode 100644
index 0000000..d9f136c
--- /dev/null
+++ b/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM.rst
@@ -0,0 +1,14 @@
+CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM
+------------------------------------------------
+
+.. versionadded:: 3.19
+
+Override the :ref:`Windows 10 SDK Maximum Version for VS 2015` and beyond.
+
+The :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM` variable may
+be set to a false value (e.g. ``OFF``, ``FALSE``, or ``0``) or the SDK version
+to use as the maximum (e.g. ``10.0.14393.0``). If unset, the default depends
+on which version of Visual Studio is targeted by the current generator.
+
+This can be used in conjunction with :variable:`CMAKE_SYSTEM_VERSION`, which
+CMake uses to select :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION`.
diff --git a/Help/variable/CMAKE_VS_WINRT_BY_DEFAULT.rst b/Help/variable/CMAKE_VS_WINRT_BY_DEFAULT.rst
new file mode 100644
index 0000000..9ded85f
--- /dev/null
+++ b/Help/variable/CMAKE_VS_WINRT_BY_DEFAULT.rst
@@ -0,0 +1,20 @@
+CMAKE_VS_WINRT_BY_DEFAULT
+-------------------------
+
+.. versionadded:: 3.13
+
+Inform :ref:`Visual Studio Generators` for VS 2010 and above that the
+target platform enables WinRT compilation by default and it needs to
+be explicitly disabled if ``/ZW`` or :prop_tgt:`VS_WINRT_COMPONENT` is
+omitted (as opposed to enabling it when either of those options is
+present)
+
+This makes cmake configuration consistent in terms of WinRT among
+platforms - if you did not enable the WinRT compilation explicitly, it
+will be disabled (by either not enabling it or explicitly disabling it)
+
+Note: WinRT compilation is always explicitly disabled for C language
+source files, even if it is expliclty enabled for a project
+
+This variable is meant to be set by a
+:variable:`toolchain file <CMAKE_TOOLCHAIN_FILE>` for such platforms.
diff --git a/Help/variable/CMAKE_WARN_DEPRECATED.rst b/Help/variable/CMAKE_WARN_DEPRECATED.rst
new file mode 100644
index 0000000..4a224fa
--- /dev/null
+++ b/Help/variable/CMAKE_WARN_DEPRECATED.rst
@@ -0,0 +1,10 @@
+CMAKE_WARN_DEPRECATED
+---------------------
+
+Whether to issue warnings for deprecated functionality.
+
+If not ``FALSE``, use of deprecated functionality will issue warnings.
+If this variable is not set, CMake behaves as if it were set to ``TRUE``.
+
+When running :manual:`cmake(1)`, this option can be enabled with the
+``-Wdeprecated`` option, or disabled with the ``-Wno-deprecated`` option.
diff --git a/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst b/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst
new file mode 100644
index 0000000..81c1158
--- /dev/null
+++ b/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst
@@ -0,0 +1,9 @@
+CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION
+------------------------------------------
+
+Ask ``cmake_install.cmake`` script to warn each time a file with absolute
+``INSTALL DESTINATION`` is encountered.
+
+This variable is used by CMake-generated ``cmake_install.cmake`` scripts.
+If one sets this variable to ``ON`` while running the script, it may get
+warning messages from the script.
diff --git a/Help/variable/CMAKE_WIN32_EXECUTABLE.rst b/Help/variable/CMAKE_WIN32_EXECUTABLE.rst
new file mode 100644
index 0000000..b96abba
--- /dev/null
+++ b/Help/variable/CMAKE_WIN32_EXECUTABLE.rst
@@ -0,0 +1,7 @@
+CMAKE_WIN32_EXECUTABLE
+----------------------
+
+Default value for :prop_tgt:`WIN32_EXECUTABLE` of targets.
+
+This variable is used to initialize the :prop_tgt:`WIN32_EXECUTABLE` property
+on all the targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS.rst b/Help/variable/CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS.rst
new file mode 100644
index 0000000..7b01185
--- /dev/null
+++ b/Help/variable/CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS.rst
@@ -0,0 +1,8 @@
+CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
+--------------------------------
+
+.. versionadded:: 3.4
+
+Default value for :prop_tgt:`WINDOWS_EXPORT_ALL_SYMBOLS` target property.
+This variable is used to initialize the property on each target as it is
+created.
diff --git a/Help/variable/CMAKE_XCODE_ATTRIBUTE_an-attribute.rst b/Help/variable/CMAKE_XCODE_ATTRIBUTE_an-attribute.rst
new file mode 100644
index 0000000..ffa0a4c
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_ATTRIBUTE_an-attribute.rst
@@ -0,0 +1,24 @@
+CMAKE_XCODE_ATTRIBUTE_<an-attribute>
+------------------------------------
+
+.. versionadded:: 3.1
+
+Set Xcode target attributes directly.
+
+Tell the :generator:`Xcode` generator to set ``<an-attribute>`` to a given
+value in the generated Xcode project. Ignored on other generators.
+
+This offers low-level control over the generated Xcode project file.
+It is meant as a last resort for specifying settings that CMake does
+not otherwise have a way to control. Although this can override a
+setting CMake normally produces on its own, doing so bypasses CMake's
+model of the project and can break things.
+
+See the :prop_tgt:`XCODE_ATTRIBUTE_<an-attribute>` target property
+to set attributes on a specific target.
+
+Contents of ``CMAKE_XCODE_ATTRIBUTE_<an-attribute>`` may use
+"generator expressions" with the syntax ``$<...>``. See the
+:manual:`cmake-generator-expressions(7)` manual for available
+expressions. See the :manual:`cmake-buildsystem(7)` manual
+for more on defining buildsystem properties.
diff --git a/Help/variable/CMAKE_XCODE_BUILD_SYSTEM.rst b/Help/variable/CMAKE_XCODE_BUILD_SYSTEM.rst
new file mode 100644
index 0000000..d153061
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_BUILD_SYSTEM.rst
@@ -0,0 +1,24 @@
+CMAKE_XCODE_BUILD_SYSTEM
+------------------------
+
+.. versionadded:: 3.19
+
+Xcode build system selection.
+
+The :generator:`Xcode` generator defines this variable to indicate which
+variant of the Xcode build system will be used. The value is the
+version of Xcode in which the corresponding build system first became
+mature enough for use by CMake. The possible values are:
+
+``1``
+ The original Xcode build system.
+ This is the default when using Xcode 11.x or below.
+
+``12``
+ The Xcode "new build system" introduced by Xcode 10.
+ It became mature enough for use by CMake in Xcode 12.
+ This is the default when using Xcode 12.x or above.
+
+The ``CMAKE_XCODE_BUILD_SYSTEM`` variable is informational and should not
+be modified by project code. See the :ref:`Xcode Build System Selection`
+documentation section to select the Xcode build system.
diff --git a/Help/variable/CMAKE_XCODE_GENERATE_SCHEME.rst b/Help/variable/CMAKE_XCODE_GENERATE_SCHEME.rst
new file mode 100644
index 0000000..40070e1
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_GENERATE_SCHEME.rst
@@ -0,0 +1,12 @@
+CMAKE_XCODE_GENERATE_SCHEME
+---------------------------
+
+.. versionadded:: 3.9
+
+If enabled, the :generator:`Xcode` generator will generate schema files. These
+are useful to invoke analyze, archive, build-for-testing and test
+actions from the command line.
+
+This variable initializes the
+:prop_tgt:`XCODE_GENERATE_SCHEME`
+target property on all targets.
diff --git a/Help/variable/CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY.rst b/Help/variable/CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY.rst
new file mode 100644
index 0000000..38d043c
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY.rst
@@ -0,0 +1,11 @@
+CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY
+-------------------------------------------
+
+.. versionadded:: 3.11
+
+If enabled, the :generator:`Xcode` generator will generate only a
+single Xcode project file for the topmost :command:`project()` command
+instead of generating one for every ``project()`` command.
+
+This could be useful to speed up the CMake generation step for
+large projects and to work-around a bug in the ``ZERO_CHECK`` logic.
diff --git a/Help/variable/CMAKE_XCODE_LINK_BUILD_PHASE_MODE.rst b/Help/variable/CMAKE_XCODE_LINK_BUILD_PHASE_MODE.rst
new file mode 100644
index 0000000..17189c0
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_LINK_BUILD_PHASE_MODE.rst
@@ -0,0 +1,9 @@
+CMAKE_XCODE_LINK_BUILD_PHASE_MODE
+---------------------------------
+
+.. versionadded:: 3.19
+
+This variable is used to initialize the
+:prop_tgt:`XCODE_LINK_BUILD_PHASE_MODE` property on targets.
+It affects the methods that the :generator:`Xcode` generator uses to link
+different kinds of libraries. Its default value is ``NONE``.
diff --git a/Help/variable/CMAKE_XCODE_PLATFORM_TOOLSET.rst b/Help/variable/CMAKE_XCODE_PLATFORM_TOOLSET.rst
new file mode 100644
index 0000000..210da52
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_PLATFORM_TOOLSET.rst
@@ -0,0 +1,9 @@
+CMAKE_XCODE_PLATFORM_TOOLSET
+----------------------------
+
+Xcode compiler selection.
+
+:generator:`Xcode` supports selection of a compiler from one of the installed
+toolsets. CMake provides the name of the chosen toolset in this
+variable, if any is explicitly selected (e.g. via the :manual:`cmake(1)`
+``-T`` option).
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER.rst b/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER.rst
new file mode 100644
index 0000000..b3fa93b
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER.rst
@@ -0,0 +1,14 @@
+CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER
+------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Address Sanitizer`` in the Diagnostics
+section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst b/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
new file mode 100644
index 0000000..1a0a17a
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN.rst
@@ -0,0 +1,14 @@
+CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN
+-----------------------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Detect use of stack after return``
+in the Diagnostics section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING.rst b/Help/variable/CMAKE_XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING.rst
new file mode 100644
index 0000000..917fc7f
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING.rst
@@ -0,0 +1,15 @@
+CMAKE_XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING
+--------------------------------------------
+
+.. versionadded:: 3.16
+
+Whether to enable
+``Allow debugging when using document Versions Browser``
+in the Options section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst b/Help/variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
new file mode 100644
index 0000000..b604598
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER.rst
@@ -0,0 +1,14 @@
+CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
+----------------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to disable the ``Main Thread Checker``
+in the Diagnostics section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst b/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
new file mode 100644
index 0000000..070ddfc
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS.rst
@@ -0,0 +1,14 @@
+CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
+----------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Dynamic Library Loads``
+in the Diagnostics section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst b/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
new file mode 100644
index 0000000..4291816
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE.rst
@@ -0,0 +1,14 @@
+CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
+-------------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Dynamic Linker API usage``
+in the Diagnostics section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_ENVIRONMENT.rst b/Help/variable/CMAKE_XCODE_SCHEME_ENVIRONMENT.rst
new file mode 100644
index 0000000..62b698d
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_ENVIRONMENT.rst
@@ -0,0 +1,17 @@
+CMAKE_XCODE_SCHEME_ENVIRONMENT
+------------------------------
+
+.. versionadded:: 3.17
+
+Specify environment variables that should be added to the Arguments
+section of the generated Xcode scheme.
+
+If set to a list of environment variables and values of the form
+``MYVAR=value`` those environment variables will be added to the
+scheme.
+
+This variable initializes the :prop_tgt:`XCODE_SCHEME_ENVIRONMENT`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC.rst b/Help/variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC.rst
new file mode 100644
index 0000000..48b481e
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC.rst
@@ -0,0 +1,14 @@
+CMAKE_XCODE_SCHEME_GUARD_MALLOC
+-------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Guard Malloc``
+in the Diagnostics section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_GUARD_MALLOC`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst b/Help/variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
new file mode 100644
index 0000000..ef8ed9b
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP.rst
@@ -0,0 +1,15 @@
+CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP
+-------------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable the ``Main Thread Checker`` option
+``Pause on issues``
+in the Diagnostics section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES.rst b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
new file mode 100644
index 0000000..d4ae9eb
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES.rst
@@ -0,0 +1,14 @@
+CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES
+-------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Malloc Guard Edges``
+in the Diagnostics section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_MALLOC_GUARD_EDGES`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE.rst b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE.rst
new file mode 100644
index 0000000..e28f6a1
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE.rst
@@ -0,0 +1,14 @@
+CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE
+----------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Malloc Scribble``
+in the Diagnostics section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_MALLOC_SCRIBBLE`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_STACK.rst b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_STACK.rst
new file mode 100644
index 0000000..59fcfd3
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_MALLOC_STACK.rst
@@ -0,0 +1,14 @@
+CMAKE_XCODE_SCHEME_MALLOC_STACK
+-------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Malloc Stack`` in the Diagnostics
+section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_MALLOC_STACK`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER.rst b/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER.rst
new file mode 100644
index 0000000..511eb04
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER.rst
@@ -0,0 +1,14 @@
+CMAKE_XCODE_SCHEME_THREAD_SANITIZER
+-----------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Thread Sanitizer`` in the Diagnostics
+section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP.rst b/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
new file mode 100644
index 0000000..6f3b8ce
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP.rst
@@ -0,0 +1,14 @@
+CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP
+----------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Thread Sanitizer - Pause on issues``
+in the Diagnostics section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_THREAD_SANITIZER_STOP`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst b/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
new file mode 100644
index 0000000..46d3ccf
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER.rst
@@ -0,0 +1,14 @@
+CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER
+------------------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Undefined Behavior Sanitizer``
+in the Diagnostics section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst b/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
new file mode 100644
index 0000000..8fa5ece
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP.rst
@@ -0,0 +1,15 @@
+CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP
+-----------------------------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Undefined Behavior Sanitizer`` option
+``Pause on issues``
+in the Diagnostics section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_WORKING_DIRECTORY.rst b/Help/variable/CMAKE_XCODE_SCHEME_WORKING_DIRECTORY.rst
new file mode 100644
index 0000000..4221e48
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_WORKING_DIRECTORY.rst
@@ -0,0 +1,14 @@
+CMAKE_XCODE_SCHEME_WORKING_DIRECTORY
+------------------------------------
+
+.. versionadded:: 3.17
+
+Specify the ``Working Directory`` of the *Run* and *Profile*
+actions in the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_WORKING_DIRECTORY`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS.rst b/Help/variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS.rst
new file mode 100644
index 0000000..fd9488e
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS.rst
@@ -0,0 +1,14 @@
+CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS
+---------------------------------
+
+.. versionadded:: 3.13
+
+Whether to enable ``Zombie Objects``
+in the Diagnostics section of the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_ZOMBIE_OBJECTS`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CPACK_ABSOLUTE_DESTINATION_FILES.rst b/Help/variable/CPACK_ABSOLUTE_DESTINATION_FILES.rst
new file mode 100644
index 0000000..928fe45
--- /dev/null
+++ b/Help/variable/CPACK_ABSOLUTE_DESTINATION_FILES.rst
@@ -0,0 +1,10 @@
+CPACK_ABSOLUTE_DESTINATION_FILES
+--------------------------------
+
+List of files which have been installed using an ``ABSOLUTE DESTINATION`` path.
+
+This variable is a Read-Only variable which is set internally by CPack
+during installation and before packaging using
+:variable:`CMAKE_ABSOLUTE_DESTINATION_FILES` defined in ``cmake_install.cmake``
+scripts. The value can be used within CPack project configuration
+file and/or ``CPack<GEN>.cmake`` file of ``<GEN>`` generator.
diff --git a/Help/variable/CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY.rst b/Help/variable/CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY.rst
new file mode 100644
index 0000000..6cf75e4
--- /dev/null
+++ b/Help/variable/CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY.rst
@@ -0,0 +1,8 @@
+CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY
+------------------------------------------
+
+Boolean toggle to include/exclude top level directory (component case).
+
+Similar usage as :variable:`CPACK_INCLUDE_TOPLEVEL_DIRECTORY` but for the
+component case. See :variable:`CPACK_INCLUDE_TOPLEVEL_DIRECTORY`
+documentation for the detail.
diff --git a/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst b/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
new file mode 100644
index 0000000..30ae236
--- /dev/null
+++ b/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
@@ -0,0 +1,11 @@
+CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
+-------------------------------------------
+
+Ask CPack to error out as soon as a file with absolute ``INSTALL DESTINATION``
+is encountered.
+
+The fatal error is emitted before the installation of the offending
+file takes place. Some CPack generators, like ``NSIS``, enforce this
+internally. This variable triggers the definition
+of :variable:`CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION` when CPack
+runs.
diff --git a/Help/variable/CPACK_INCLUDE_TOPLEVEL_DIRECTORY.rst b/Help/variable/CPACK_INCLUDE_TOPLEVEL_DIRECTORY.rst
new file mode 100644
index 0000000..b8e9105
--- /dev/null
+++ b/Help/variable/CPACK_INCLUDE_TOPLEVEL_DIRECTORY.rst
@@ -0,0 +1,20 @@
+CPACK_INCLUDE_TOPLEVEL_DIRECTORY
+--------------------------------
+
+Boolean toggle to include/exclude top level directory.
+
+When preparing a package CPack installs the item under the so-called
+top level directory. The purpose of is to include (set to ``1`` or ``ON`` or
+``TRUE``) the top level directory in the package or not (set to ``0`` or
+``OFF`` or ``FALSE``).
+
+Each CPack generator has a built-in default value for this variable.
+E.g. Archive generators (ZIP, TGZ, ...) includes the top level
+whereas RPM or DEB don't. The user may override the default value by
+setting this variable.
+
+There is a similar variable
+:variable:`CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY` which may be used
+to override the behavior for the component packaging
+case which may have different default value for historical (now
+backward compatibility) reason.
diff --git a/Help/variable/CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS.rst b/Help/variable/CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS.rst
new file mode 100644
index 0000000..01fb189
--- /dev/null
+++ b/Help/variable/CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS.rst
@@ -0,0 +1,13 @@
+CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
+-------------------------------------------
+
+.. versionadded:: 3.11
+
+Default permissions for implicitly created directories during packaging.
+
+This variable serves the same purpose during packaging as the
+:variable:`CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS` variable
+serves during installation (e.g. ``make install``).
+
+If `include(CPack)` is used then by default this variable is set to the content
+of :variable:`CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS`.
diff --git a/Help/variable/CPACK_PACKAGING_INSTALL_PREFIX.rst b/Help/variable/CPACK_PACKAGING_INSTALL_PREFIX.rst
new file mode 100644
index 0000000..f423e2e
--- /dev/null
+++ b/Help/variable/CPACK_PACKAGING_INSTALL_PREFIX.rst
@@ -0,0 +1,15 @@
+CPACK_PACKAGING_INSTALL_PREFIX
+------------------------------
+
+The prefix used in the built package.
+
+Each CPack generator has a default value (like ``/usr``). This default
+value may be overwritten from the ``CMakeLists.txt`` or the :manual:`cpack(1)`
+command line by setting an alternative value. Example:
+
+::
+
+ set(CPACK_PACKAGING_INSTALL_PREFIX "/opt")
+
+This is not the same purpose as :variable:`CMAKE_INSTALL_PREFIX` which is used
+when installing from the build tree without building a package.
diff --git a/Help/variable/CPACK_SET_DESTDIR.rst b/Help/variable/CPACK_SET_DESTDIR.rst
new file mode 100644
index 0000000..27fd355
--- /dev/null
+++ b/Help/variable/CPACK_SET_DESTDIR.rst
@@ -0,0 +1,31 @@
+CPACK_SET_DESTDIR
+-----------------
+
+Boolean toggle to make CPack use ``DESTDIR`` mechanism when packaging.
+
+``DESTDIR`` means DESTination DIRectory. It is commonly used by makefile
+users in order to install software at non-default location. It is a
+basic relocation mechanism that should not be used on Windows (see
+:variable:`CMAKE_INSTALL_PREFIX` documentation). It is usually invoked like
+this:
+
+::
+
+ make DESTDIR=/home/john install
+
+which will install the concerned software using the installation
+prefix, e.g. ``/usr/local`` prepended with the ``DESTDIR`` value which
+finally gives ``/home/john/usr/local``. When preparing a package, CPack
+first installs the items to be packaged in a local (to the build tree)
+directory by using the same ``DESTDIR`` mechanism. Nevertheless, if
+``CPACK_SET_DESTDIR`` is set then CPack will set ``DESTDIR`` before doing the
+local install. The most noticeable difference is that without
+``CPACK_SET_DESTDIR``, CPack uses :variable:`CPACK_PACKAGING_INSTALL_PREFIX`
+as a prefix whereas with ``CPACK_SET_DESTDIR`` set, CPack will use
+:variable:`CMAKE_INSTALL_PREFIX` as a prefix.
+
+Manually setting ``CPACK_SET_DESTDIR`` may help (or simply be necessary)
+if some install rules uses absolute ``DESTINATION`` (see CMake
+:command:`install` command). However, starting with CPack/CMake 2.8.3 RPM
+and DEB installers tries to handle ``DESTDIR`` automatically so that it is
+seldom necessary for the user to set it.
diff --git a/Help/variable/CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst b/Help/variable/CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst
new file mode 100644
index 0000000..3fc5cca
--- /dev/null
+++ b/Help/variable/CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst
@@ -0,0 +1,9 @@
+CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION
+------------------------------------------
+
+Ask CPack to warn each time a file with absolute ``INSTALL DESTINATION`` is
+encountered.
+
+This variable triggers the definition of
+:variable:`CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION` when CPack runs
+``cmake_install.cmake`` scripts.
diff --git a/Help/variable/CTEST_BINARY_DIRECTORY.rst b/Help/variable/CTEST_BINARY_DIRECTORY.rst
new file mode 100644
index 0000000..8413e37
--- /dev/null
+++ b/Help/variable/CTEST_BINARY_DIRECTORY.rst
@@ -0,0 +1,7 @@
+CTEST_BINARY_DIRECTORY
+----------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``BuildDirectory`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_BUILD_COMMAND.rst b/Help/variable/CTEST_BUILD_COMMAND.rst
new file mode 100644
index 0000000..31c44e2
--- /dev/null
+++ b/Help/variable/CTEST_BUILD_COMMAND.rst
@@ -0,0 +1,7 @@
+CTEST_BUILD_COMMAND
+-------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``MakeCommand`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_BUILD_NAME.rst b/Help/variable/CTEST_BUILD_NAME.rst
new file mode 100644
index 0000000..3d08397
--- /dev/null
+++ b/Help/variable/CTEST_BUILD_NAME.rst
@@ -0,0 +1,7 @@
+CTEST_BUILD_NAME
+----------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``BuildName`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_BZR_COMMAND.rst b/Help/variable/CTEST_BZR_COMMAND.rst
new file mode 100644
index 0000000..0c05d1a
--- /dev/null
+++ b/Help/variable/CTEST_BZR_COMMAND.rst
@@ -0,0 +1,7 @@
+CTEST_BZR_COMMAND
+-----------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``BZRCommand`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_BZR_UPDATE_OPTIONS.rst b/Help/variable/CTEST_BZR_UPDATE_OPTIONS.rst
new file mode 100644
index 0000000..4dd5e5b
--- /dev/null
+++ b/Help/variable/CTEST_BZR_UPDATE_OPTIONS.rst
@@ -0,0 +1,7 @@
+CTEST_BZR_UPDATE_OPTIONS
+------------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``BZRUpdateOptions`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_CHANGE_ID.rst b/Help/variable/CTEST_CHANGE_ID.rst
new file mode 100644
index 0000000..a6d15f7
--- /dev/null
+++ b/Help/variable/CTEST_CHANGE_ID.rst
@@ -0,0 +1,11 @@
+CTEST_CHANGE_ID
+---------------
+
+.. versionadded:: 3.4
+
+Specify the CTest ``ChangeId`` setting
+in a :manual:`ctest(1)` dashboard client script.
+
+This setting allows CTest to pass arbitrary information about this
+build up to CDash. One use of this feature is to allow CDash to
+post comments on your pull request if anything goes wrong with your build.
diff --git a/Help/variable/CTEST_CHECKOUT_COMMAND.rst b/Help/variable/CTEST_CHECKOUT_COMMAND.rst
new file mode 100644
index 0000000..852c28e
--- /dev/null
+++ b/Help/variable/CTEST_CHECKOUT_COMMAND.rst
@@ -0,0 +1,7 @@
+CTEST_CHECKOUT_COMMAND
+----------------------
+
+.. versionadded:: 3.1
+
+Tell the :command:`ctest_start` command how to checkout or initialize
+the source directory in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_CONFIGURATION_TYPE.rst b/Help/variable/CTEST_CONFIGURATION_TYPE.rst
new file mode 100644
index 0000000..392845e
--- /dev/null
+++ b/Help/variable/CTEST_CONFIGURATION_TYPE.rst
@@ -0,0 +1,10 @@
+CTEST_CONFIGURATION_TYPE
+------------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``DefaultCTestConfigurationType`` setting
+in a :manual:`ctest(1)` dashboard client script.
+
+If the configuration type is set via ``-C <cfg>`` from the command line
+then this variable is populated accordingly.
diff --git a/Help/variable/CTEST_CONFIGURE_COMMAND.rst b/Help/variable/CTEST_CONFIGURE_COMMAND.rst
new file mode 100644
index 0000000..992ef47
--- /dev/null
+++ b/Help/variable/CTEST_CONFIGURE_COMMAND.rst
@@ -0,0 +1,7 @@
+CTEST_CONFIGURE_COMMAND
+-----------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``ConfigureCommand`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_COVERAGE_COMMAND.rst b/Help/variable/CTEST_COVERAGE_COMMAND.rst
new file mode 100644
index 0000000..f5425cb
--- /dev/null
+++ b/Help/variable/CTEST_COVERAGE_COMMAND.rst
@@ -0,0 +1,62 @@
+CTEST_COVERAGE_COMMAND
+----------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``CoverageCommand`` setting
+in a :manual:`ctest(1)` dashboard client script.
+
+Cobertura
+'''''''''
+
+Using `Cobertura`_ as the coverage generation within your multi-module
+Java project can generate a series of XML files.
+
+The Cobertura Coverage parser expects to read the coverage data from a
+single XML file which contains the coverage data for all modules.
+Cobertura has a program with the ability to merge given ``cobertura.ser`` files
+and then another program to generate a combined XML file from the previous
+merged file. For command line testing, this can be done by hand prior to
+CTest looking for the coverage files. For script builds,
+set the ``CTEST_COVERAGE_COMMAND`` variable to point to a file which will
+perform these same steps, such as a ``.sh`` or ``.bat`` file.
+
+.. code-block:: cmake
+
+ set(CTEST_COVERAGE_COMMAND .../run-coverage-and-consolidate.sh)
+
+where the ``run-coverage-and-consolidate.sh`` script is perhaps created by
+the :command:`configure_file` command and might contain the following code:
+
+.. code-block:: bash
+
+ #!/usr/bin/env bash
+ CoberturaFiles="$(find "/path/to/source" -name "cobertura.ser")"
+ SourceDirs="$(find "/path/to/source" -name "java" -type d)"
+ cobertura-merge --datafile coberturamerge.ser $CoberturaFiles
+ cobertura-report --datafile coberturamerge.ser --destination . \
+ --format xml $SourceDirs
+
+The script uses ``find`` to capture the paths to all of the ``cobertura.ser``
+files found below the project's source directory. It keeps the list of files
+and supplies it as an argument to the ``cobertura-merge`` program. The
+``--datafile`` argument signifies where the result of the merge will be kept.
+
+The combined ``coberturamerge.ser`` file is then used to generate the XML report
+using the ``cobertura-report`` program. The call to the cobertura-report
+program requires some named arguments.
+
+``--datafila``
+ path to the merged ``.ser`` file
+
+``--destination``
+ path to put the output files(s)
+
+``--format``
+ file format to write output in: xml or html
+
+The rest of the supplied arguments consist of the full paths to the
+``/src/main/java`` directories of each module within the source tree. These
+directories are needed and should not be forgotten.
+
+.. _`Cobertura`: http://cobertura.github.io/cobertura/
diff --git a/Help/variable/CTEST_COVERAGE_EXTRA_FLAGS.rst b/Help/variable/CTEST_COVERAGE_EXTRA_FLAGS.rst
new file mode 100644
index 0000000..39d9b5d
--- /dev/null
+++ b/Help/variable/CTEST_COVERAGE_EXTRA_FLAGS.rst
@@ -0,0 +1,7 @@
+CTEST_COVERAGE_EXTRA_FLAGS
+--------------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``CoverageExtraFlags`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_CURL_OPTIONS.rst b/Help/variable/CTEST_CURL_OPTIONS.rst
new file mode 100644
index 0000000..14af4e4
--- /dev/null
+++ b/Help/variable/CTEST_CURL_OPTIONS.rst
@@ -0,0 +1,7 @@
+CTEST_CURL_OPTIONS
+------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``CurlOptions`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_CUSTOM_COVERAGE_EXCLUDE.rst b/Help/variable/CTEST_CUSTOM_COVERAGE_EXCLUDE.rst
new file mode 100644
index 0000000..d5893c9
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_COVERAGE_EXCLUDE.rst
@@ -0,0 +1,7 @@
+CTEST_CUSTOM_COVERAGE_EXCLUDE
+-----------------------------
+
+A list of regular expressions which will be used to exclude files by their
+path from coverage output by the :command:`ctest_coverage` command.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_ERROR_EXCEPTION.rst b/Help/variable/CTEST_CUSTOM_ERROR_EXCEPTION.rst
new file mode 100644
index 0000000..cd65ae3
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_ERROR_EXCEPTION.rst
@@ -0,0 +1,7 @@
+CTEST_CUSTOM_ERROR_EXCEPTION
+----------------------------
+
+A list of regular expressions which will be used to exclude when detecting
+error messages in build outputs by the :command:`ctest_test` command.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_ERROR_MATCH.rst b/Help/variable/CTEST_CUSTOM_ERROR_MATCH.rst
new file mode 100644
index 0000000..558f5e5
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_ERROR_MATCH.rst
@@ -0,0 +1,7 @@
+CTEST_CUSTOM_ERROR_MATCH
+------------------------
+
+A list of regular expressions which will be used to detect error messages in
+build outputs by the :command:`ctest_test` command.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_ERROR_POST_CONTEXT.rst b/Help/variable/CTEST_CUSTOM_ERROR_POST_CONTEXT.rst
new file mode 100644
index 0000000..614859b
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_ERROR_POST_CONTEXT.rst
@@ -0,0 +1,7 @@
+CTEST_CUSTOM_ERROR_POST_CONTEXT
+-------------------------------
+
+The number of lines to include as context which follow an error message by the
+:command:`ctest_test` command. The default is 10.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_ERROR_PRE_CONTEXT.rst b/Help/variable/CTEST_CUSTOM_ERROR_PRE_CONTEXT.rst
new file mode 100644
index 0000000..74dc47a
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_ERROR_PRE_CONTEXT.rst
@@ -0,0 +1,7 @@
+CTEST_CUSTOM_ERROR_PRE_CONTEXT
+------------------------------
+
+The number of lines to include as context which precede an error message by
+the :command:`ctest_test` command. The default is 10.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE.rst b/Help/variable/CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE.rst
new file mode 100644
index 0000000..5aeae88
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE.rst
@@ -0,0 +1,8 @@
+CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE
+--------------------------------------------
+
+When saving a failing test's output, this is the maximum size, in bytes, that
+will be collected by the :command:`ctest_test` command. Defaults to 307200
+(300 KiB).
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS.rst b/Help/variable/CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS.rst
new file mode 100644
index 0000000..920cb04
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS.rst
@@ -0,0 +1,8 @@
+CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS
+-------------------------------------
+
+The maximum number of errors in a single build step which will be detected.
+After this, the :command:`ctest_test` command will truncate the output.
+Defaults to 50.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS.rst b/Help/variable/CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS.rst
new file mode 100644
index 0000000..a1f1cc1
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS.rst
@@ -0,0 +1,8 @@
+CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS
+---------------------------------------
+
+The maximum number of warnings in a single build step which will be detected.
+After this, the :command:`ctest_test` command will truncate the output.
+Defaults to 50.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE.rst b/Help/variable/CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE.rst
new file mode 100644
index 0000000..1fbb8c5
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE.rst
@@ -0,0 +1,8 @@
+CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE
+--------------------------------------------
+
+When saving a passing test's output, this is the maximum size, in bytes, that
+will be collected by the :command:`ctest_test` command. Defaults to 1024
+(1 KiB).
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_MEMCHECK_IGNORE.rst b/Help/variable/CTEST_CUSTOM_MEMCHECK_IGNORE.rst
new file mode 100644
index 0000000..578576c
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_MEMCHECK_IGNORE.rst
@@ -0,0 +1,7 @@
+CTEST_CUSTOM_MEMCHECK_IGNORE
+----------------------------
+
+A list of regular expressions to use to exclude tests during the
+:command:`ctest_memcheck` command.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_POST_MEMCHECK.rst b/Help/variable/CTEST_CUSTOM_POST_MEMCHECK.rst
new file mode 100644
index 0000000..40291fe
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_POST_MEMCHECK.rst
@@ -0,0 +1,6 @@
+CTEST_CUSTOM_POST_MEMCHECK
+--------------------------
+
+A list of commands to run at the end of the :command:`ctest_memcheck` command.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_POST_TEST.rst b/Help/variable/CTEST_CUSTOM_POST_TEST.rst
new file mode 100644
index 0000000..791292c
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_POST_TEST.rst
@@ -0,0 +1,6 @@
+CTEST_CUSTOM_POST_TEST
+----------------------
+
+A list of commands to run at the end of the :command:`ctest_test` command.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_PRE_MEMCHECK.rst b/Help/variable/CTEST_CUSTOM_PRE_MEMCHECK.rst
new file mode 100644
index 0000000..00de8aa
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_PRE_MEMCHECK.rst
@@ -0,0 +1,7 @@
+CTEST_CUSTOM_PRE_MEMCHECK
+-------------------------
+
+A list of commands to run at the start of the :command:`ctest_memcheck`
+command.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_PRE_TEST.rst b/Help/variable/CTEST_CUSTOM_PRE_TEST.rst
new file mode 100644
index 0000000..6af7152
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_PRE_TEST.rst
@@ -0,0 +1,6 @@
+CTEST_CUSTOM_PRE_TEST
+----------------------
+
+A list of commands to run at the start of the :command:`ctest_test` command.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_TESTS_IGNORE.rst b/Help/variable/CTEST_CUSTOM_TESTS_IGNORE.rst
new file mode 100644
index 0000000..57222ca
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_TESTS_IGNORE.rst
@@ -0,0 +1,7 @@
+CTEST_CUSTOM_TESTS_IGNORE
+-------------------------
+
+A list of regular expressions to use to exclude tests during the
+:command:`ctest_test` command.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_WARNING_EXCEPTION.rst b/Help/variable/CTEST_CUSTOM_WARNING_EXCEPTION.rst
new file mode 100644
index 0000000..a03d473
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_WARNING_EXCEPTION.rst
@@ -0,0 +1,7 @@
+CTEST_CUSTOM_WARNING_EXCEPTION
+------------------------------
+
+A list of regular expressions which will be used to exclude when detecting
+warning messages in build outputs by the :command:`ctest_build` command.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_WARNING_MATCH.rst b/Help/variable/CTEST_CUSTOM_WARNING_MATCH.rst
new file mode 100644
index 0000000..18aa6b3
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_WARNING_MATCH.rst
@@ -0,0 +1,7 @@
+CTEST_CUSTOM_WARNING_MATCH
+--------------------------
+
+A list of regular expressions which will be used to detect warning messages in
+build outputs by the :command:`ctest_build` command.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_XXX.txt b/Help/variable/CTEST_CUSTOM_XXX.txt
new file mode 100644
index 0000000..02d1547
--- /dev/null
+++ b/Help/variable/CTEST_CUSTOM_XXX.txt
@@ -0,0 +1,2 @@
+It is initialized by :manual:`ctest(1)`, but may be edited in a ``CTestCustom``
+file. See :command:`ctest_read_custom_files` documentation.
diff --git a/Help/variable/CTEST_CVS_CHECKOUT.rst b/Help/variable/CTEST_CVS_CHECKOUT.rst
new file mode 100644
index 0000000..32cf9eb
--- /dev/null
+++ b/Help/variable/CTEST_CVS_CHECKOUT.rst
@@ -0,0 +1,6 @@
+CTEST_CVS_CHECKOUT
+------------------
+
+.. versionadded:: 3.1
+
+Deprecated. Use :variable:`CTEST_CHECKOUT_COMMAND` instead.
diff --git a/Help/variable/CTEST_CVS_COMMAND.rst b/Help/variable/CTEST_CVS_COMMAND.rst
new file mode 100644
index 0000000..7932070
--- /dev/null
+++ b/Help/variable/CTEST_CVS_COMMAND.rst
@@ -0,0 +1,7 @@
+CTEST_CVS_COMMAND
+-----------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``CVSCommand`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_CVS_UPDATE_OPTIONS.rst b/Help/variable/CTEST_CVS_UPDATE_OPTIONS.rst
new file mode 100644
index 0000000..359e708
--- /dev/null
+++ b/Help/variable/CTEST_CVS_UPDATE_OPTIONS.rst
@@ -0,0 +1,7 @@
+CTEST_CVS_UPDATE_OPTIONS
+------------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``CVSUpdateOptions`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_DROP_LOCATION.rst b/Help/variable/CTEST_DROP_LOCATION.rst
new file mode 100644
index 0000000..f66793b
--- /dev/null
+++ b/Help/variable/CTEST_DROP_LOCATION.rst
@@ -0,0 +1,7 @@
+CTEST_DROP_LOCATION
+-------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``DropLocation`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_DROP_METHOD.rst b/Help/variable/CTEST_DROP_METHOD.rst
new file mode 100644
index 0000000..3a84658
--- /dev/null
+++ b/Help/variable/CTEST_DROP_METHOD.rst
@@ -0,0 +1,7 @@
+CTEST_DROP_METHOD
+-----------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``DropMethod`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_DROP_SITE.rst b/Help/variable/CTEST_DROP_SITE.rst
new file mode 100644
index 0000000..9c871e3
--- /dev/null
+++ b/Help/variable/CTEST_DROP_SITE.rst
@@ -0,0 +1,7 @@
+CTEST_DROP_SITE
+---------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``DropSite`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_DROP_SITE_CDASH.rst b/Help/variable/CTEST_DROP_SITE_CDASH.rst
new file mode 100644
index 0000000..dcdb286
--- /dev/null
+++ b/Help/variable/CTEST_DROP_SITE_CDASH.rst
@@ -0,0 +1,7 @@
+CTEST_DROP_SITE_CDASH
+---------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``IsCDash`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_DROP_SITE_PASSWORD.rst b/Help/variable/CTEST_DROP_SITE_PASSWORD.rst
new file mode 100644
index 0000000..8259651
--- /dev/null
+++ b/Help/variable/CTEST_DROP_SITE_PASSWORD.rst
@@ -0,0 +1,7 @@
+CTEST_DROP_SITE_PASSWORD
+------------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``DropSitePassword`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_DROP_SITE_USER.rst b/Help/variable/CTEST_DROP_SITE_USER.rst
new file mode 100644
index 0000000..8d2e3a3
--- /dev/null
+++ b/Help/variable/CTEST_DROP_SITE_USER.rst
@@ -0,0 +1,7 @@
+CTEST_DROP_SITE_USER
+--------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``DropSiteUser`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_EXTRA_COVERAGE_GLOB.rst b/Help/variable/CTEST_EXTRA_COVERAGE_GLOB.rst
new file mode 100644
index 0000000..1d7e8d4
--- /dev/null
+++ b/Help/variable/CTEST_EXTRA_COVERAGE_GLOB.rst
@@ -0,0 +1,9 @@
+CTEST_EXTRA_COVERAGE_GLOB
+-------------------------
+
+.. versionadded:: 3.4
+
+A list of regular expressions which will be used to find files which should be
+covered by the :command:`ctest_coverage` command.
+
+.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_GIT_COMMAND.rst b/Help/variable/CTEST_GIT_COMMAND.rst
new file mode 100644
index 0000000..eb9b440
--- /dev/null
+++ b/Help/variable/CTEST_GIT_COMMAND.rst
@@ -0,0 +1,7 @@
+CTEST_GIT_COMMAND
+-----------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``GITCommand`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_GIT_INIT_SUBMODULES.rst b/Help/variable/CTEST_GIT_INIT_SUBMODULES.rst
new file mode 100644
index 0000000..529bfc7
--- /dev/null
+++ b/Help/variable/CTEST_GIT_INIT_SUBMODULES.rst
@@ -0,0 +1,7 @@
+CTEST_GIT_INIT_SUBMODULES
+-------------------------
+
+.. versionadded:: 3.6
+
+Specify the CTest ``GITInitSubmodules`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_GIT_UPDATE_CUSTOM.rst b/Help/variable/CTEST_GIT_UPDATE_CUSTOM.rst
new file mode 100644
index 0000000..82a8a6a
--- /dev/null
+++ b/Help/variable/CTEST_GIT_UPDATE_CUSTOM.rst
@@ -0,0 +1,7 @@
+CTEST_GIT_UPDATE_CUSTOM
+-----------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``GITUpdateCustom`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_GIT_UPDATE_OPTIONS.rst b/Help/variable/CTEST_GIT_UPDATE_OPTIONS.rst
new file mode 100644
index 0000000..1568239
--- /dev/null
+++ b/Help/variable/CTEST_GIT_UPDATE_OPTIONS.rst
@@ -0,0 +1,7 @@
+CTEST_GIT_UPDATE_OPTIONS
+------------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``GITUpdateOptions`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_HG_COMMAND.rst b/Help/variable/CTEST_HG_COMMAND.rst
new file mode 100644
index 0000000..3372fe4
--- /dev/null
+++ b/Help/variable/CTEST_HG_COMMAND.rst
@@ -0,0 +1,7 @@
+CTEST_HG_COMMAND
+----------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``HGCommand`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_HG_UPDATE_OPTIONS.rst b/Help/variable/CTEST_HG_UPDATE_OPTIONS.rst
new file mode 100644
index 0000000..85c6b03
--- /dev/null
+++ b/Help/variable/CTEST_HG_UPDATE_OPTIONS.rst
@@ -0,0 +1,7 @@
+CTEST_HG_UPDATE_OPTIONS
+-----------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``HGUpdateOptions`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_LABELS_FOR_SUBPROJECTS.rst b/Help/variable/CTEST_LABELS_FOR_SUBPROJECTS.rst
new file mode 100644
index 0000000..dd6d125
--- /dev/null
+++ b/Help/variable/CTEST_LABELS_FOR_SUBPROJECTS.rst
@@ -0,0 +1,7 @@
+CTEST_LABELS_FOR_SUBPROJECTS
+----------------------------
+
+.. versionadded:: 3.10
+
+Specify the CTest ``LabelsForSubprojects`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_MEMORYCHECK_COMMAND.rst b/Help/variable/CTEST_MEMORYCHECK_COMMAND.rst
new file mode 100644
index 0000000..25f1bd9
--- /dev/null
+++ b/Help/variable/CTEST_MEMORYCHECK_COMMAND.rst
@@ -0,0 +1,7 @@
+CTEST_MEMORYCHECK_COMMAND
+-------------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``MemoryCheckCommand`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_MEMORYCHECK_COMMAND_OPTIONS.rst b/Help/variable/CTEST_MEMORYCHECK_COMMAND_OPTIONS.rst
new file mode 100644
index 0000000..51830d5
--- /dev/null
+++ b/Help/variable/CTEST_MEMORYCHECK_COMMAND_OPTIONS.rst
@@ -0,0 +1,7 @@
+CTEST_MEMORYCHECK_COMMAND_OPTIONS
+---------------------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``MemoryCheckCommandOptions`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst b/Help/variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst
new file mode 100644
index 0000000..b6fee2e
--- /dev/null
+++ b/Help/variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst
@@ -0,0 +1,12 @@
+CTEST_MEMORYCHECK_SANITIZER_OPTIONS
+-----------------------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``MemoryCheckSanitizerOptions`` setting
+in a :manual:`ctest(1)` dashboard client script.
+
+CTest prepends correct sanitizer options ``*_OPTIONS``
+environment variable to executed command. CTests adds
+its own ``log_path`` to sanitizer options, don't provide your
+own ``log_path``.
diff --git a/Help/variable/CTEST_MEMORYCHECK_SUPPRESSIONS_FILE.rst b/Help/variable/CTEST_MEMORYCHECK_SUPPRESSIONS_FILE.rst
new file mode 100644
index 0000000..a61a3ef
--- /dev/null
+++ b/Help/variable/CTEST_MEMORYCHECK_SUPPRESSIONS_FILE.rst
@@ -0,0 +1,7 @@
+CTEST_MEMORYCHECK_SUPPRESSIONS_FILE
+-----------------------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``MemoryCheckSuppressionFile`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_MEMORYCHECK_TYPE.rst b/Help/variable/CTEST_MEMORYCHECK_TYPE.rst
new file mode 100644
index 0000000..80353a4
--- /dev/null
+++ b/Help/variable/CTEST_MEMORYCHECK_TYPE.rst
@@ -0,0 +1,10 @@
+CTEST_MEMORYCHECK_TYPE
+----------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``MemoryCheckType`` setting
+in a :manual:`ctest(1)` dashboard client script.
+Valid values are ``Valgrind``, ``Purify``, ``BoundsChecker``, ``DrMemory``,
+``CudaSanitizer``, ``ThreadSanitizer``, ``AddressSanitizer``, ``LeakSanitizer``,
+``MemorySanitizer`` and ``UndefinedBehaviorSanitizer``.
diff --git a/Help/variable/CTEST_NIGHTLY_START_TIME.rst b/Help/variable/CTEST_NIGHTLY_START_TIME.rst
new file mode 100644
index 0000000..2d707d5
--- /dev/null
+++ b/Help/variable/CTEST_NIGHTLY_START_TIME.rst
@@ -0,0 +1,11 @@
+CTEST_NIGHTLY_START_TIME
+------------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``NightlyStartTime`` setting in a :manual:`ctest(1)`
+dashboard client script.
+
+Note that this variable must always be set for a nightly build in a
+dashboard script. It is needed so that nightly builds can be properly grouped
+together in CDash.
diff --git a/Help/variable/CTEST_P4_CLIENT.rst b/Help/variable/CTEST_P4_CLIENT.rst
new file mode 100644
index 0000000..0778c5b
--- /dev/null
+++ b/Help/variable/CTEST_P4_CLIENT.rst
@@ -0,0 +1,7 @@
+CTEST_P4_CLIENT
+---------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``P4Client`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_P4_COMMAND.rst b/Help/variable/CTEST_P4_COMMAND.rst
new file mode 100644
index 0000000..5cc2a81
--- /dev/null
+++ b/Help/variable/CTEST_P4_COMMAND.rst
@@ -0,0 +1,7 @@
+CTEST_P4_COMMAND
+----------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``P4Command`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_P4_OPTIONS.rst b/Help/variable/CTEST_P4_OPTIONS.rst
new file mode 100644
index 0000000..01b6534
--- /dev/null
+++ b/Help/variable/CTEST_P4_OPTIONS.rst
@@ -0,0 +1,7 @@
+CTEST_P4_OPTIONS
+----------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``P4Options`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_P4_UPDATE_OPTIONS.rst b/Help/variable/CTEST_P4_UPDATE_OPTIONS.rst
new file mode 100644
index 0000000..365aa3f
--- /dev/null
+++ b/Help/variable/CTEST_P4_UPDATE_OPTIONS.rst
@@ -0,0 +1,7 @@
+CTEST_P4_UPDATE_OPTIONS
+-----------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``P4UpdateOptions`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_RESOURCE_SPEC_FILE.rst b/Help/variable/CTEST_RESOURCE_SPEC_FILE.rst
new file mode 100644
index 0000000..8e9bf01
--- /dev/null
+++ b/Help/variable/CTEST_RESOURCE_SPEC_FILE.rst
@@ -0,0 +1,12 @@
+CTEST_RESOURCE_SPEC_FILE
+------------------------
+
+.. versionadded:: 3.18
+
+Specify the CTest ``ResourceSpecFile`` setting in a :manual:`ctest(1)`
+dashboard client script.
+
+This can also be used to specify the resource spec file from a CMake build. If
+no ``RESOURCE_SPEC_FILE`` is passed to :command:`ctest_test`, and
+``CTEST_RESOURCE_SPEC_FILE`` is not specified in the dashboard script, the
+value of this variable from the build is used.
diff --git a/Help/variable/CTEST_RUN_CURRENT_SCRIPT.rst b/Help/variable/CTEST_RUN_CURRENT_SCRIPT.rst
new file mode 100644
index 0000000..32c85ad
--- /dev/null
+++ b/Help/variable/CTEST_RUN_CURRENT_SCRIPT.rst
@@ -0,0 +1,7 @@
+CTEST_RUN_CURRENT_SCRIPT
+------------------------
+
+.. versionadded:: 3.11
+
+Setting this to 0 prevents :manual:`ctest(1)` from being run again when it
+reaches the end of a script run by calling ``ctest -S``.
diff --git a/Help/variable/CTEST_SCP_COMMAND.rst b/Help/variable/CTEST_SCP_COMMAND.rst
new file mode 100644
index 0000000..155b058
--- /dev/null
+++ b/Help/variable/CTEST_SCP_COMMAND.rst
@@ -0,0 +1,6 @@
+CTEST_SCP_COMMAND
+-----------------
+
+.. versionadded:: 3.1
+
+Legacy option. Not used.
diff --git a/Help/variable/CTEST_SITE.rst b/Help/variable/CTEST_SITE.rst
new file mode 100644
index 0000000..526e6ed
--- /dev/null
+++ b/Help/variable/CTEST_SITE.rst
@@ -0,0 +1,7 @@
+CTEST_SITE
+----------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``Site`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_SOURCE_DIRECTORY.rst b/Help/variable/CTEST_SOURCE_DIRECTORY.rst
new file mode 100644
index 0000000..4c6ac54
--- /dev/null
+++ b/Help/variable/CTEST_SOURCE_DIRECTORY.rst
@@ -0,0 +1,7 @@
+CTEST_SOURCE_DIRECTORY
+----------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``SourceDirectory`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_SUBMIT_URL.rst b/Help/variable/CTEST_SUBMIT_URL.rst
new file mode 100644
index 0000000..b6e7f68
--- /dev/null
+++ b/Help/variable/CTEST_SUBMIT_URL.rst
@@ -0,0 +1,7 @@
+CTEST_SUBMIT_URL
+----------------
+
+.. versionadded:: 3.14
+
+Specify the CTest ``SubmitURL`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_SVN_COMMAND.rst b/Help/variable/CTEST_SVN_COMMAND.rst
new file mode 100644
index 0000000..e97acd0
--- /dev/null
+++ b/Help/variable/CTEST_SVN_COMMAND.rst
@@ -0,0 +1,7 @@
+CTEST_SVN_COMMAND
+-----------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``SVNCommand`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_SVN_OPTIONS.rst b/Help/variable/CTEST_SVN_OPTIONS.rst
new file mode 100644
index 0000000..5326e20
--- /dev/null
+++ b/Help/variable/CTEST_SVN_OPTIONS.rst
@@ -0,0 +1,7 @@
+CTEST_SVN_OPTIONS
+-----------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``SVNOptions`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_SVN_UPDATE_OPTIONS.rst b/Help/variable/CTEST_SVN_UPDATE_OPTIONS.rst
new file mode 100644
index 0000000..24e0bbf
--- /dev/null
+++ b/Help/variable/CTEST_SVN_UPDATE_OPTIONS.rst
@@ -0,0 +1,7 @@
+CTEST_SVN_UPDATE_OPTIONS
+------------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``SVNUpdateOptions`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_TEST_LOAD.rst b/Help/variable/CTEST_TEST_LOAD.rst
new file mode 100644
index 0000000..b6a9d62
--- /dev/null
+++ b/Help/variable/CTEST_TEST_LOAD.rst
@@ -0,0 +1,9 @@
+CTEST_TEST_LOAD
+---------------
+
+.. versionadded:: 3.4
+
+Specify the ``TestLoad`` setting in the :ref:`CTest Test Step`
+of a :manual:`ctest(1)` dashboard client script. This sets the
+default value for the ``TEST_LOAD`` option of the :command:`ctest_test`
+command.
diff --git a/Help/variable/CTEST_TEST_TIMEOUT.rst b/Help/variable/CTEST_TEST_TIMEOUT.rst
new file mode 100644
index 0000000..61d9191
--- /dev/null
+++ b/Help/variable/CTEST_TEST_TIMEOUT.rst
@@ -0,0 +1,7 @@
+CTEST_TEST_TIMEOUT
+------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``TimeOut`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_TRIGGER_SITE.rst b/Help/variable/CTEST_TRIGGER_SITE.rst
new file mode 100644
index 0000000..6abb852
--- /dev/null
+++ b/Help/variable/CTEST_TRIGGER_SITE.rst
@@ -0,0 +1,6 @@
+CTEST_TRIGGER_SITE
+------------------
+
+.. versionadded:: 3.1
+
+Legacy option. Not used.
diff --git a/Help/variable/CTEST_UPDATE_COMMAND.rst b/Help/variable/CTEST_UPDATE_COMMAND.rst
new file mode 100644
index 0000000..c4ed645
--- /dev/null
+++ b/Help/variable/CTEST_UPDATE_COMMAND.rst
@@ -0,0 +1,7 @@
+CTEST_UPDATE_COMMAND
+--------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``UpdateCommand`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_UPDATE_OPTIONS.rst b/Help/variable/CTEST_UPDATE_OPTIONS.rst
new file mode 100644
index 0000000..96c4b6c
--- /dev/null
+++ b/Help/variable/CTEST_UPDATE_OPTIONS.rst
@@ -0,0 +1,7 @@
+CTEST_UPDATE_OPTIONS
+--------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``UpdateOptions`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_UPDATE_VERSION_ONLY.rst b/Help/variable/CTEST_UPDATE_VERSION_ONLY.rst
new file mode 100644
index 0000000..f7c863c
--- /dev/null
+++ b/Help/variable/CTEST_UPDATE_VERSION_ONLY.rst
@@ -0,0 +1,7 @@
+CTEST_UPDATE_VERSION_ONLY
+-------------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest :ref:`UpdateVersionOnly <UpdateVersionOnly>` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_UPDATE_VERSION_OVERRIDE.rst b/Help/variable/CTEST_UPDATE_VERSION_OVERRIDE.rst
new file mode 100644
index 0000000..87918cb
--- /dev/null
+++ b/Help/variable/CTEST_UPDATE_VERSION_OVERRIDE.rst
@@ -0,0 +1,7 @@
+CTEST_UPDATE_VERSION_OVERRIDE
+-----------------------------
+
+.. versionadded:: 3.15
+
+Specify the CTest :ref:`UpdateVersionOverride <UpdateVersionOverride>` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CTEST_USE_LAUNCHERS.rst b/Help/variable/CTEST_USE_LAUNCHERS.rst
new file mode 100644
index 0000000..728cdc5
--- /dev/null
+++ b/Help/variable/CTEST_USE_LAUNCHERS.rst
@@ -0,0 +1,7 @@
+CTEST_USE_LAUNCHERS
+-------------------
+
+.. versionadded:: 3.1
+
+Specify the CTest ``UseLaunchers`` setting
+in a :manual:`ctest(1)` dashboard client script.
diff --git a/Help/variable/CYGWIN.rst b/Help/variable/CYGWIN.rst
new file mode 100644
index 0000000..0039e07
--- /dev/null
+++ b/Help/variable/CYGWIN.rst
@@ -0,0 +1,6 @@
+CYGWIN
+------
+
+``True`` for Cygwin.
+
+Set to ``true`` when using Cygwin.
diff --git a/Help/variable/ENV.rst b/Help/variable/ENV.rst
new file mode 100644
index 0000000..2b43934
--- /dev/null
+++ b/Help/variable/ENV.rst
@@ -0,0 +1,12 @@
+ENV
+---
+
+Operator to read environment variables.
+
+Use the syntax ``$ENV{VAR}`` to read environment variable ``VAR``.
+
+To test whether an environment variable is defined, use the signature
+``if(DEFINED ENV{<name>})`` of the :command:`if` command.
+
+See the :command:`set` and :command:`unset` commands to see how to
+write or remove environment variables.
diff --git a/Help/variable/EXECUTABLE_OUTPUT_PATH.rst b/Help/variable/EXECUTABLE_OUTPUT_PATH.rst
new file mode 100644
index 0000000..26d3e92
--- /dev/null
+++ b/Help/variable/EXECUTABLE_OUTPUT_PATH.rst
@@ -0,0 +1,8 @@
+EXECUTABLE_OUTPUT_PATH
+----------------------
+
+Old executable location variable.
+
+The target property :prop_tgt:`RUNTIME_OUTPUT_DIRECTORY` supercedes this
+variable for a target if it is set. Executable targets are otherwise placed in
+this directory.
diff --git a/Help/variable/GHS-MULTI.rst b/Help/variable/GHS-MULTI.rst
new file mode 100644
index 0000000..bb139af
--- /dev/null
+++ b/Help/variable/GHS-MULTI.rst
@@ -0,0 +1,6 @@
+GHS-MULTI
+---------
+
+.. versionadded:: 3.3
+
+``True`` when using :generator:`Green Hills MULTI` generator.
diff --git a/Help/variable/IOS.rst b/Help/variable/IOS.rst
new file mode 100644
index 0000000..b27be55
--- /dev/null
+++ b/Help/variable/IOS.rst
@@ -0,0 +1,6 @@
+IOS
+---
+
+.. versionadded:: 3.14
+
+Set to ``1`` when the target system (:variable:`CMAKE_SYSTEM_NAME`) is ``iOS``.
diff --git a/Help/variable/LIBRARY_OUTPUT_PATH.rst b/Help/variable/LIBRARY_OUTPUT_PATH.rst
new file mode 100644
index 0000000..bb4328f
--- /dev/null
+++ b/Help/variable/LIBRARY_OUTPUT_PATH.rst
@@ -0,0 +1,9 @@
+LIBRARY_OUTPUT_PATH
+-------------------
+
+Old library location variable.
+
+The target properties :prop_tgt:`ARCHIVE_OUTPUT_DIRECTORY`,
+:prop_tgt:`LIBRARY_OUTPUT_DIRECTORY`, and :prop_tgt:`RUNTIME_OUTPUT_DIRECTORY`
+supersede this variable for a target if they are set. Library targets are
+otherwise placed in this directory.
diff --git a/Help/variable/MINGW.rst b/Help/variable/MINGW.rst
new file mode 100644
index 0000000..27c56ea
--- /dev/null
+++ b/Help/variable/MINGW.rst
@@ -0,0 +1,8 @@
+MINGW
+-----
+
+.. versionadded:: 3.2
+
+``True`` when using MinGW
+
+Set to ``true`` when the compiler is some version of MinGW.
diff --git a/Help/variable/MSVC.rst b/Help/variable/MSVC.rst
new file mode 100644
index 0000000..a2dbc2e
--- /dev/null
+++ b/Help/variable/MSVC.rst
@@ -0,0 +1,7 @@
+MSVC
+----
+
+Set to ``true`` when the compiler is some version of Microsoft Visual C++
+or another compiler simulating the Visual C++ ``cl`` command-line syntax.
+
+See also the :variable:`MSVC_VERSION` variable.
diff --git a/Help/variable/MSVC10.rst b/Help/variable/MSVC10.rst
new file mode 100644
index 0000000..55c6337
--- /dev/null
+++ b/Help/variable/MSVC10.rst
@@ -0,0 +1,7 @@
+MSVC10
+------
+
+Discouraged. Use the :variable:`MSVC_VERSION` variable instead.
+
+``True`` when using the Microsoft Visual Studio ``v100`` toolset
+(``cl`` version 16) or another compiler that simulates it.
diff --git a/Help/variable/MSVC11.rst b/Help/variable/MSVC11.rst
new file mode 100644
index 0000000..17943dc
--- /dev/null
+++ b/Help/variable/MSVC11.rst
@@ -0,0 +1,7 @@
+MSVC11
+------
+
+Discouraged. Use the :variable:`MSVC_VERSION` variable instead.
+
+``True`` when using the Microsoft Visual Studio ``v110`` toolset
+(``cl`` version 17) or another compiler that simulates it.
diff --git a/Help/variable/MSVC12.rst b/Help/variable/MSVC12.rst
new file mode 100644
index 0000000..a524fab
--- /dev/null
+++ b/Help/variable/MSVC12.rst
@@ -0,0 +1,7 @@
+MSVC12
+------
+
+Discouraged. Use the :variable:`MSVC_VERSION` variable instead.
+
+``True`` when using the Microsoft Visual Studio ``v120`` toolset
+(``cl`` version 18) or another compiler that simulates it.
diff --git a/Help/variable/MSVC14.rst b/Help/variable/MSVC14.rst
new file mode 100644
index 0000000..1eb5183
--- /dev/null
+++ b/Help/variable/MSVC14.rst
@@ -0,0 +1,9 @@
+MSVC14
+------
+
+.. versionadded:: 3.1
+
+Discouraged. Use the :variable:`MSVC_VERSION` variable instead.
+
+``True`` when using the Microsoft Visual Studio ``v140`` or ``v141``
+toolset (``cl`` version 19) or another compiler that simulates it.
diff --git a/Help/variable/MSVC60.rst b/Help/variable/MSVC60.rst
new file mode 100644
index 0000000..14164bf
--- /dev/null
+++ b/Help/variable/MSVC60.rst
@@ -0,0 +1,8 @@
+MSVC60
+------
+
+Discouraged. Use the :variable:`MSVC_VERSION` variable instead.
+
+``True`` when using Microsoft Visual C++ 6.0.
+
+Set to ``true`` when the compiler is version 6.0 of Microsoft Visual C++.
diff --git a/Help/variable/MSVC70.rst b/Help/variable/MSVC70.rst
new file mode 100644
index 0000000..ed3b0bb
--- /dev/null
+++ b/Help/variable/MSVC70.rst
@@ -0,0 +1,8 @@
+MSVC70
+------
+
+Discouraged. Use the :variable:`MSVC_VERSION` variable instead.
+
+``True`` when using Microsoft Visual C++ 7.0.
+
+Set to ``true`` when the compiler is version 7.0 of Microsoft Visual C++.
diff --git a/Help/variable/MSVC71.rst b/Help/variable/MSVC71.rst
new file mode 100644
index 0000000..0237592
--- /dev/null
+++ b/Help/variable/MSVC71.rst
@@ -0,0 +1,8 @@
+MSVC71
+------
+
+Discouraged. Use the :variable:`MSVC_VERSION` variable instead.
+
+``True`` when using Microsoft Visual C++ 7.1.
+
+Set to ``true`` when the compiler is version 7.1 of Microsoft Visual C++.
diff --git a/Help/variable/MSVC80.rst b/Help/variable/MSVC80.rst
new file mode 100644
index 0000000..1533218
--- /dev/null
+++ b/Help/variable/MSVC80.rst
@@ -0,0 +1,7 @@
+MSVC80
+------
+
+Discouraged. Use the :variable:`MSVC_VERSION` variable instead.
+
+``True`` when using the Microsoft Visual Studio ``v80`` toolset
+(``cl`` version 14) or another compiler that simulates it.
diff --git a/Help/variable/MSVC90.rst b/Help/variable/MSVC90.rst
new file mode 100644
index 0000000..4981ecf
--- /dev/null
+++ b/Help/variable/MSVC90.rst
@@ -0,0 +1,7 @@
+MSVC90
+------
+
+Discouraged. Use the :variable:`MSVC_VERSION` variable instead.
+
+``True`` when using the Microsoft Visual Studio ``v90`` toolset
+(``cl`` version 15) or another compiler that simulates it.
diff --git a/Help/variable/MSVC_IDE.rst b/Help/variable/MSVC_IDE.rst
new file mode 100644
index 0000000..18e9983
--- /dev/null
+++ b/Help/variable/MSVC_IDE.rst
@@ -0,0 +1,14 @@
+MSVC_IDE
+--------
+
+``True`` when using the Microsoft Visual C++ IDE.
+
+Set to ``true`` when the target platform is the Microsoft Visual C++ IDE, as
+opposed to the command line compiler.
+
+.. note::
+
+ This variable is only available after compiler detection has been performed,
+ so it is not available to toolchain files or before the first
+ :command:`project` or :command:`enable_language` call which uses an
+ MSVC-like compiler.
diff --git a/Help/variable/MSVC_TOOLSET_VERSION.rst b/Help/variable/MSVC_TOOLSET_VERSION.rst
new file mode 100644
index 0000000..c642a9f
--- /dev/null
+++ b/Help/variable/MSVC_TOOLSET_VERSION.rst
@@ -0,0 +1,24 @@
+MSVC_TOOLSET_VERSION
+--------------------
+
+.. versionadded:: 3.12
+
+The toolset version of Microsoft Visual C/C++ being used if any.
+If MSVC-like is being used, this variable is set based on the version
+of the compiler as given by the :variable:`MSVC_VERSION` variable.
+
+Known toolset version numbers are::
+
+ 80 = VS 2005 (8.0)
+ 90 = VS 2008 (9.0)
+ 100 = VS 2010 (10.0)
+ 110 = VS 2012 (11.0)
+ 120 = VS 2013 (12.0)
+ 140 = VS 2015 (14.0)
+ 141 = VS 2017 (15.0)
+ 142 = VS 2019 (16.0)
+
+Compiler versions newer than those known to CMake will be reported
+as the latest known toolset version.
+
+See also the :variable:`MSVC_VERSION` variable.
diff --git a/Help/variable/MSVC_VERSION.rst b/Help/variable/MSVC_VERSION.rst
new file mode 100644
index 0000000..45df37f
--- /dev/null
+++ b/Help/variable/MSVC_VERSION.rst
@@ -0,0 +1,24 @@
+MSVC_VERSION
+------------
+
+The version of Microsoft Visual C/C++ being used if any.
+If a compiler simulating Visual C++ is being used, this variable is set
+to the toolset version simulated as given by the ``_MSC_VER``
+preprocessor definition.
+
+Known version numbers are::
+
+ 1200 = VS 6.0
+ 1300 = VS 7.0
+ 1310 = VS 7.1
+ 1400 = VS 8.0 (v80 toolset)
+ 1500 = VS 9.0 (v90 toolset)
+ 1600 = VS 10.0 (v100 toolset)
+ 1700 = VS 11.0 (v110 toolset)
+ 1800 = VS 12.0 (v120 toolset)
+ 1900 = VS 14.0 (v140 toolset)
+ 1910-1919 = VS 15.0 (v141 toolset)
+ 1920-1929 = VS 16.0 (v142 toolset)
+
+See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` and
+:variable:`MSVC_TOOLSET_VERSION` variable.
diff --git a/Help/variable/MSYS.rst b/Help/variable/MSYS.rst
new file mode 100644
index 0000000..6be7681
--- /dev/null
+++ b/Help/variable/MSYS.rst
@@ -0,0 +1,6 @@
+MSYS
+----
+
+.. versionadded:: 3.14
+
+``True`` when using the :generator:`MSYS Makefiles` generator.
diff --git a/Help/variable/PROJECT-NAME_BINARY_DIR.rst b/Help/variable/PROJECT-NAME_BINARY_DIR.rst
new file mode 100644
index 0000000..49bc558
--- /dev/null
+++ b/Help/variable/PROJECT-NAME_BINARY_DIR.rst
@@ -0,0 +1,8 @@
+<PROJECT-NAME>_BINARY_DIR
+-------------------------
+
+Top level binary directory for the named project.
+
+A variable is created with the name used in the :command:`project` command,
+and is the binary directory for the project. This can be useful when
+:command:`add_subdirectory` is used to connect several projects.
diff --git a/Help/variable/PROJECT-NAME_DESCRIPTION.rst b/Help/variable/PROJECT-NAME_DESCRIPTION.rst
new file mode 100644
index 0000000..f372f5c
--- /dev/null
+++ b/Help/variable/PROJECT-NAME_DESCRIPTION.rst
@@ -0,0 +1,7 @@
+<PROJECT-NAME>_DESCRIPTION
+--------------------------
+
+.. versionadded:: 3.12
+
+Value given to the ``DESCRIPTION`` option of the most recent call to the
+:command:`project` command with project name ``<PROJECT-NAME>``, if any.
diff --git a/Help/variable/PROJECT-NAME_HOMEPAGE_URL.rst b/Help/variable/PROJECT-NAME_HOMEPAGE_URL.rst
new file mode 100644
index 0000000..4800b13
--- /dev/null
+++ b/Help/variable/PROJECT-NAME_HOMEPAGE_URL.rst
@@ -0,0 +1,7 @@
+<PROJECT-NAME>_HOMEPAGE_URL
+---------------------------
+
+.. versionadded:: 3.12
+
+Value given to the ``HOMEPAGE_URL`` option of the most recent call to the
+:command:`project` command with project name ``<PROJECT-NAME>``, if any.
diff --git a/Help/variable/PROJECT-NAME_IS_TOP_LEVEL.rst b/Help/variable/PROJECT-NAME_IS_TOP_LEVEL.rst
new file mode 100644
index 0000000..953e978
--- /dev/null
+++ b/Help/variable/PROJECT-NAME_IS_TOP_LEVEL.rst
@@ -0,0 +1,11 @@
+<PROJECT-NAME>_IS_TOP_LEVEL
+---------------------------
+
+.. versionadded:: 3.21
+
+A boolean variable indicating whether the named project was called in a top
+level ``CMakeLists.txt`` file.
+
+To obtain the value from the most recent call to :command:`project` in
+the current directory scope or above, see the
+:variable:`PROJECT_IS_TOP_LEVEL` variable.
diff --git a/Help/variable/PROJECT-NAME_SOURCE_DIR.rst b/Help/variable/PROJECT-NAME_SOURCE_DIR.rst
new file mode 100644
index 0000000..4df3e22
--- /dev/null
+++ b/Help/variable/PROJECT-NAME_SOURCE_DIR.rst
@@ -0,0 +1,8 @@
+<PROJECT-NAME>_SOURCE_DIR
+-------------------------
+
+Top level source directory for the named project.
+
+A variable is created with the name used in the :command:`project` command,
+and is the source directory for the project. This can be useful when
+:command:`add_subdirectory` is used to connect several projects.
diff --git a/Help/variable/PROJECT-NAME_VERSION.rst b/Help/variable/PROJECT-NAME_VERSION.rst
new file mode 100644
index 0000000..0f6ed51
--- /dev/null
+++ b/Help/variable/PROJECT-NAME_VERSION.rst
@@ -0,0 +1,11 @@
+<PROJECT-NAME>_VERSION
+----------------------
+
+Value given to the ``VERSION`` option of the most recent call to the
+:command:`project` command with project name ``<PROJECT-NAME>``, if any.
+
+See also the component-wise version variables
+:variable:`<PROJECT-NAME>_VERSION_MAJOR`,
+:variable:`<PROJECT-NAME>_VERSION_MINOR`,
+:variable:`<PROJECT-NAME>_VERSION_PATCH`, and
+:variable:`<PROJECT-NAME>_VERSION_TWEAK`.
diff --git a/Help/variable/PROJECT-NAME_VERSION_MAJOR.rst b/Help/variable/PROJECT-NAME_VERSION_MAJOR.rst
new file mode 100644
index 0000000..9e2d755
--- /dev/null
+++ b/Help/variable/PROJECT-NAME_VERSION_MAJOR.rst
@@ -0,0 +1,5 @@
+<PROJECT-NAME>_VERSION_MAJOR
+----------------------------
+
+First version number component of the :variable:`<PROJECT-NAME>_VERSION`
+variable as set by the :command:`project` command.
diff --git a/Help/variable/PROJECT-NAME_VERSION_MINOR.rst b/Help/variable/PROJECT-NAME_VERSION_MINOR.rst
new file mode 100644
index 0000000..fa2cdab
--- /dev/null
+++ b/Help/variable/PROJECT-NAME_VERSION_MINOR.rst
@@ -0,0 +1,5 @@
+<PROJECT-NAME>_VERSION_MINOR
+----------------------------
+
+Second version number component of the :variable:`<PROJECT-NAME>_VERSION`
+variable as set by the :command:`project` command.
diff --git a/Help/variable/PROJECT-NAME_VERSION_PATCH.rst b/Help/variable/PROJECT-NAME_VERSION_PATCH.rst
new file mode 100644
index 0000000..85b5e6b
--- /dev/null
+++ b/Help/variable/PROJECT-NAME_VERSION_PATCH.rst
@@ -0,0 +1,5 @@
+<PROJECT-NAME>_VERSION_PATCH
+----------------------------
+
+Third version number component of the :variable:`<PROJECT-NAME>_VERSION`
+variable as set by the :command:`project` command.
diff --git a/Help/variable/PROJECT-NAME_VERSION_TWEAK.rst b/Help/variable/PROJECT-NAME_VERSION_TWEAK.rst
new file mode 100644
index 0000000..65c4044
--- /dev/null
+++ b/Help/variable/PROJECT-NAME_VERSION_TWEAK.rst
@@ -0,0 +1,5 @@
+<PROJECT-NAME>_VERSION_TWEAK
+----------------------------
+
+Fourth version number component of the :variable:`<PROJECT-NAME>_VERSION`
+variable as set by the :command:`project` command.
diff --git a/Help/variable/PROJECT_BINARY_DIR.rst b/Help/variable/PROJECT_BINARY_DIR.rst
new file mode 100644
index 0000000..09e9ef2
--- /dev/null
+++ b/Help/variable/PROJECT_BINARY_DIR.rst
@@ -0,0 +1,6 @@
+PROJECT_BINARY_DIR
+------------------
+
+Full path to build directory for project.
+
+This is the binary directory of the most recent :command:`project` command.
diff --git a/Help/variable/PROJECT_DESCRIPTION.rst b/Help/variable/PROJECT_DESCRIPTION.rst
new file mode 100644
index 0000000..1fefcdc
--- /dev/null
+++ b/Help/variable/PROJECT_DESCRIPTION.rst
@@ -0,0 +1,11 @@
+PROJECT_DESCRIPTION
+-------------------
+
+.. versionadded:: 3.9
+
+Short project description given to the project command.
+
+This is the description given to the most recently called :command:`project`
+command in the current directory scope or above. To obtain the description
+of the top level project, see the :variable:`CMAKE_PROJECT_DESCRIPTION`
+variable.
diff --git a/Help/variable/PROJECT_HOMEPAGE_URL.rst b/Help/variable/PROJECT_HOMEPAGE_URL.rst
new file mode 100644
index 0000000..0d2c937
--- /dev/null
+++ b/Help/variable/PROJECT_HOMEPAGE_URL.rst
@@ -0,0 +1,11 @@
+PROJECT_HOMEPAGE_URL
+--------------------
+
+.. versionadded:: 3.12
+
+The homepage URL of the project.
+
+This is the homepage URL given to the most recently called :command:`project`
+command in the current directory scope or above. To obtain the homepage URL
+of the top level project, see the :variable:`CMAKE_PROJECT_HOMEPAGE_URL`
+variable.
diff --git a/Help/variable/PROJECT_IS_TOP_LEVEL.rst b/Help/variable/PROJECT_IS_TOP_LEVEL.rst
new file mode 100644
index 0000000..e5eb6c1
--- /dev/null
+++ b/Help/variable/PROJECT_IS_TOP_LEVEL.rst
@@ -0,0 +1,21 @@
+PROJECT_IS_TOP_LEVEL
+--------------------
+
+.. versionadded:: 3.21
+
+A boolean variable indicating whether :command:`project` was called in a top
+level ``CMakeLists.txt`` file.
+
+Some modules should only be included as part of the top level
+``CMakeLists.txt`` file to not cause unintended side effects in the build
+tree, and this variable can be used to conditionally execute such code. For
+example, consider the :module:`CTest` module, which creates targets and
+options:
+
+.. code-block:: cmake
+
+ project(MyProject)
+ ...
+ if(PROJECT_IS_TOP_LEVEL)
+ include(CTest)
+ endif()
diff --git a/Help/variable/PROJECT_NAME.rst b/Help/variable/PROJECT_NAME.rst
new file mode 100644
index 0000000..672680a
--- /dev/null
+++ b/Help/variable/PROJECT_NAME.rst
@@ -0,0 +1,8 @@
+PROJECT_NAME
+------------
+
+Name of the project given to the project command.
+
+This is the name given to the most recently called :command:`project`
+command in the current directory scope or above. To obtain the name of
+the top level project, see the :variable:`CMAKE_PROJECT_NAME` variable.
diff --git a/Help/variable/PROJECT_SOURCE_DIR.rst b/Help/variable/PROJECT_SOURCE_DIR.rst
new file mode 100644
index 0000000..b4601c2
--- /dev/null
+++ b/Help/variable/PROJECT_SOURCE_DIR.rst
@@ -0,0 +1,8 @@
+PROJECT_SOURCE_DIR
+------------------
+
+This is the source directory of the last call to the
+:command:`project` command made in the current directory scope or one
+of its parents. Note, it is not affected by calls to
+:command:`project` made within a child directory scope (i.e. from
+within a call to :command:`add_subdirectory` from the current scope).
diff --git a/Help/variable/PROJECT_VERSION.rst b/Help/variable/PROJECT_VERSION.rst
new file mode 100644
index 0000000..234558d
--- /dev/null
+++ b/Help/variable/PROJECT_VERSION.rst
@@ -0,0 +1,11 @@
+PROJECT_VERSION
+---------------
+
+Value given to the ``VERSION`` option of the most recent call to the
+:command:`project` command, if any.
+
+See also the component-wise version variables
+:variable:`PROJECT_VERSION_MAJOR`,
+:variable:`PROJECT_VERSION_MINOR`,
+:variable:`PROJECT_VERSION_PATCH`, and
+:variable:`PROJECT_VERSION_TWEAK`.
diff --git a/Help/variable/PROJECT_VERSION_MAJOR.rst b/Help/variable/PROJECT_VERSION_MAJOR.rst
new file mode 100644
index 0000000..4b6072c
--- /dev/null
+++ b/Help/variable/PROJECT_VERSION_MAJOR.rst
@@ -0,0 +1,5 @@
+PROJECT_VERSION_MAJOR
+---------------------
+
+First version number component of the :variable:`PROJECT_VERSION`
+variable as set by the :command:`project` command.
diff --git a/Help/variable/PROJECT_VERSION_MINOR.rst b/Help/variable/PROJECT_VERSION_MINOR.rst
new file mode 100644
index 0000000..5f31220
--- /dev/null
+++ b/Help/variable/PROJECT_VERSION_MINOR.rst
@@ -0,0 +1,5 @@
+PROJECT_VERSION_MINOR
+---------------------
+
+Second version number component of the :variable:`PROJECT_VERSION`
+variable as set by the :command:`project` command.
diff --git a/Help/variable/PROJECT_VERSION_PATCH.rst b/Help/variable/PROJECT_VERSION_PATCH.rst
new file mode 100644
index 0000000..ac72ec0
--- /dev/null
+++ b/Help/variable/PROJECT_VERSION_PATCH.rst
@@ -0,0 +1,5 @@
+PROJECT_VERSION_PATCH
+---------------------
+
+Third version number component of the :variable:`PROJECT_VERSION`
+variable as set by the :command:`project` command.
diff --git a/Help/variable/PROJECT_VERSION_TWEAK.rst b/Help/variable/PROJECT_VERSION_TWEAK.rst
new file mode 100644
index 0000000..d7f96d6
--- /dev/null
+++ b/Help/variable/PROJECT_VERSION_TWEAK.rst
@@ -0,0 +1,5 @@
+PROJECT_VERSION_TWEAK
+---------------------
+
+Fourth version number component of the :variable:`PROJECT_VERSION`
+variable as set by the :command:`project` command.
diff --git a/Help/variable/PackageName_ROOT.rst b/Help/variable/PackageName_ROOT.rst
new file mode 100644
index 0000000..98ba20e
--- /dev/null
+++ b/Help/variable/PackageName_ROOT.rst
@@ -0,0 +1,16 @@
+<PackageName>_ROOT
+------------------
+
+.. versionadded:: 3.12
+
+Calls to :command:`find_package(<PackageName>)` will search in prefixes
+specified by the ``<PackageName>_ROOT`` CMake variable, where
+``<PackageName>`` is the name given to the :command:`find_package` call
+and ``_ROOT`` is literal. For example, ``find_package(Foo)`` will search
+prefixes specified in the ``Foo_ROOT`` CMake variable (if set).
+See policy :policy:`CMP0074`.
+
+This variable may hold a single prefix or a
+:ref:`semicolon-separated list <CMake Language Lists>` of multiple prefixes.
+
+See also the :envvar:`<PackageName>_ROOT` environment variable.
diff --git a/Help/variable/UNIX.rst b/Help/variable/UNIX.rst
new file mode 100644
index 0000000..49d8668
--- /dev/null
+++ b/Help/variable/UNIX.rst
@@ -0,0 +1,7 @@
+UNIX
+----
+
+Set to ``True`` when the target system is UNIX or UNIX-like
+(e.g. :variable:`APPLE` and :variable:`CYGWIN`). The
+:variable:`CMAKE_SYSTEM_NAME` variable should be queried if
+a more specific understanding of the target system is required.
diff --git a/Help/variable/WIN32.rst b/Help/variable/WIN32.rst
new file mode 100644
index 0000000..78ab772
--- /dev/null
+++ b/Help/variable/WIN32.rst
@@ -0,0 +1,4 @@
+WIN32
+-----
+
+Set to ``True`` when the target system is Windows, including Win64.
diff --git a/Help/variable/WINCE.rst b/Help/variable/WINCE.rst
new file mode 100644
index 0000000..4dca297
--- /dev/null
+++ b/Help/variable/WINCE.rst
@@ -0,0 +1,7 @@
+WINCE
+-----
+
+.. versionadded:: 3.1
+
+True when the :variable:`CMAKE_SYSTEM_NAME` variable is set
+to ``WindowsCE``.
diff --git a/Help/variable/WINDOWS_PHONE.rst b/Help/variable/WINDOWS_PHONE.rst
new file mode 100644
index 0000000..bf7099d
--- /dev/null
+++ b/Help/variable/WINDOWS_PHONE.rst
@@ -0,0 +1,7 @@
+WINDOWS_PHONE
+-------------
+
+.. versionadded:: 3.1
+
+True when the :variable:`CMAKE_SYSTEM_NAME` variable is set
+to ``WindowsPhone``.
diff --git a/Help/variable/WINDOWS_STORE.rst b/Help/variable/WINDOWS_STORE.rst
new file mode 100644
index 0000000..13831c2
--- /dev/null
+++ b/Help/variable/WINDOWS_STORE.rst
@@ -0,0 +1,7 @@
+WINDOWS_STORE
+-------------
+
+.. versionadded:: 3.1
+
+True when the :variable:`CMAKE_SYSTEM_NAME` variable is set
+to ``WindowsStore``.
diff --git a/Help/variable/XCODE.rst b/Help/variable/XCODE.rst
new file mode 100644
index 0000000..167ca86
--- /dev/null
+++ b/Help/variable/XCODE.rst
@@ -0,0 +1,6 @@
+XCODE
+-----
+
+.. versionadded:: 3.7
+
+``True`` when using :generator:`Xcode` generator.
diff --git a/Help/variable/XCODE_VERSION.rst b/Help/variable/XCODE_VERSION.rst
new file mode 100644
index 0000000..9caf19a
--- /dev/null
+++ b/Help/variable/XCODE_VERSION.rst
@@ -0,0 +1,7 @@
+XCODE_VERSION
+-------------
+
+Version of Xcode (:generator:`Xcode` generator only).
+
+Under the :generator:`Xcode` generator, this is the version of Xcode
+as specified in ``Xcode.app/Contents/version.plist`` (such as ``3.1.2``).
diff --git a/Licenses/LGPLv2.1.txt b/Licenses/LGPLv2.1.txt
new file mode 100644
index 0000000..4362b49
--- /dev/null
+++ b/Licenses/LGPLv2.1.txt
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/Licenses/LGPLv3.txt b/Licenses/LGPLv3.txt
new file mode 100644
index 0000000..65c5ca8
--- /dev/null
+++ b/Licenses/LGPLv3.txt
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/Licenses/README.rst b/Licenses/README.rst
new file mode 100644
index 0000000..e798f78
--- /dev/null
+++ b/Licenses/README.rst
@@ -0,0 +1,7 @@
+Licenses
+========
+
+The CMake source tree is distributed under terms of the BSD 3-Clause license.
+
+This directory contains other license files that need to be packaged with
+binary distributions when certain third-party libraries are included.
diff --git a/Modules/AddFileDependencies.cmake b/Modules/AddFileDependencies.cmake
new file mode 100644
index 0000000..13b2600
--- /dev/null
+++ b/Modules/AddFileDependencies.cmake
@@ -0,0 +1,33 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+AddFileDependencies
+-------------------
+
+.. deprecated:: 3.20
+
+Add dependencies to a source file.
+
+.. code-block:: cmake
+
+ add_file_dependencies(<source> <files>...)
+
+Adds the given ``<files>`` to the dependencies of file ``<source>``.
+
+Do not use this command in new code. It is just a wrapper around:
+
+.. code-block:: cmake
+
+ set_property(SOURCE <source> APPEND PROPERTY OBJECT_DEPENDS <files>...)
+
+Instead use the :command:`set_property` command to append to the
+:prop_sf:`OBJECT_DEPENDS` source file property directly.
+
+#]=======================================================================]
+
+function(add_file_dependencies _file)
+
+ set_property(SOURCE "${_file}" APPEND PROPERTY OBJECT_DEPENDS "${ARGN}")
+
+endfunction()
diff --git a/Modules/AndroidTestUtilities.cmake b/Modules/AndroidTestUtilities.cmake
new file mode 100644
index 0000000..ddccf58
--- /dev/null
+++ b/Modules/AndroidTestUtilities.cmake
@@ -0,0 +1,164 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[======================================================================[.rst:
+AndroidTestUtilities
+------------------------
+
+.. versionadded:: 3.7
+
+Create a test that automatically loads specified data onto an Android device.
+
+Introduction
+^^^^^^^^^^^^
+
+Use this module to push data needed for testing an Android device behavior
+onto a connected Android device. The module will accept files and libraries as
+well as separate destinations for each. It will create a test that loads the
+files into a device object store and link to them from the specified
+destination. The files are only uploaded if they are not already in the object
+store.
+
+For example:
+
+.. code-block:: cmake
+
+ include(AndroidTestUtilities)
+ android_add_test_data(
+ example_setup_test
+ FILES <files>...
+ LIBS <libs>...
+ DEVICE_TEST_DIR "/data/local/tests/example"
+ DEVICE_OBJECT_STORE "/sdcard/.ExternalData/SHA"
+ )
+
+
+At build time a test named "example_setup_test" will be created. Run this test
+on the command line with :manual:`ctest(1)` to load the data onto the Android
+device.
+
+Module Functions
+^^^^^^^^^^^^^^^^
+
+.. command:: android_add_test_data
+
+ .. code-block:: cmake
+
+ android_add_test_data(<test-name>
+ [FILES <files>...] [FILES_DEST <device-dir>]
+ [LIBS <libs>...] [LIBS_DEST <device-dir>]
+ [DEVICE_OBJECT_STORE <device-dir>]
+ [DEVICE_TEST_DIR <device-dir>]
+ [NO_LINK_REGEX <strings>...]
+ )
+
+ The ``android_add_test_data`` function is used to copy files and libraries
+ needed to run project-specific tests. On the host operating system, this is
+ done at build time. For on-device testing, the files are loaded onto the
+ device by the manufactured test at run time.
+
+ This function accepts the following named parameters:
+
+ ``FILES <files>...``
+ zero or more files needed for testing
+ ``LIBS <libs>...``
+ zero or more libraries needed for testing
+ ``FILES_DEST <device-dir>``
+ absolute path where the data files are expected to be
+ ``LIBS_DEST <device-dir>``
+ absolute path where the libraries are expected to be
+ ``DEVICE_OBJECT_STORE <device-dir>``
+ absolute path to the location where the data is stored on-device
+ ``DEVICE_TEST_DIR <device-dir>``
+ absolute path to the root directory of the on-device test location
+ ``NO_LINK_REGEX <strings>...``
+ list of regex strings matching the names of files that should be
+ copied from the object store to the testing directory
+#]======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/ExternalData.cmake)
+
+# The parameters to this function should be set to the list of directories,
+# files, and libraries that need to be installed prior to testing.
+function(android_add_test_data test_name)
+ # As the names suggest, oneValueArgs lists the arguments that specify a
+ # single value, while multiValueArgs can contain one or more values.
+ set(keywordArgs)
+ set(oneValueArgs FILES_DEST LIBS_DEST DEVICE_OBJECT_STORE DEVICE_TEST_DIR)
+ set(multiValueArgs FILES LIBS NO_LINK_REGEX)
+
+ # For example, if you called this function with FILES </path/to/file>
+ # then this path would be stored in the variable AST_FILES.
+ # The AST prefix stands for the name of this function (android_add_test_data).
+ cmake_parse_arguments(AST "${keywordArgs}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+ if(NOT AST_DEVICE_TEST_DIR)
+ message(FATAL_ERROR "-- You must specify the location of the on device test directory.")
+ endif()
+ if(NOT AST_DEVICE_OBJECT_STORE)
+ message(FATAL_ERROR "-- You must specify the location of the on device object store.")
+ endif()
+ if(${AST_DEVICE_TEST_DIR} STREQUAL "/")
+ message(FATAL_ERROR "-- The device test directory cannot be '/'")
+ endif()
+
+ # Copy all test data files into the binary directory, where tests are run.
+ # ExternalData will handle fetching DATA{...} references.
+ string(REPLACE "|" ";" hash_algs "${_ExternalData_REGEX_EXT}")
+ # Convert ExternalData placeholder file names to DATA{} syntax.
+ foreach(alg ${hash_algs})
+ string(REGEX REPLACE "([^ ;]+)\\.${alg}" "DATA{\\1}" AST_FILES "${AST_FILES}")
+ endforeach()
+
+ set(DATA_TARGET_NAME "${test_name}")
+ string(FIND "${AST_FILES}" "DATA{" data_files_found)
+ if(${data_files_found} GREATER "-1")
+ # Use ExternalData if any DATA{} files were found.
+ ExternalData_Expand_Arguments(
+ ${DATA_TARGET_NAME}
+ extern_data_output
+ ${AST_FILES})
+ ExternalData_Add_Target(${DATA_TARGET_NAME})
+ else()
+ add_custom_target(${DATA_TARGET_NAME} ALL)
+ set(extern_data_output ${AST_FILES})
+ endif()
+
+ # For regular files on Linux, just copy them directly.
+ foreach(path ${AST_FILES})
+ foreach(output ${extern_data_output})
+ if(${output} STREQUAL ${path})
+ # Check if a destination was specified. If not, we copy by default
+ # into this project's binary directory, preserving its relative path.
+ if(AST_${VAR}_DEST)
+ set(DEST ${CMAKE_BINARY_DIR}/${parent_dir}/${AST_${VAR}_DEST})
+ else()
+ get_filename_component(parent_dir ${path} DIRECTORY)
+ set(DEST "${CMAKE_BINARY_DIR}/${parent_dir}")
+ endif()
+ get_filename_component(extern_data_source ${output} REALPATH)
+ get_filename_component(extern_data_basename ${output} NAME)
+ add_custom_command(
+ TARGET ${DATA_TARGET_NAME} POST_BUILD
+ DEPENDS ${extern_data_source}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${extern_data_source} ${DEST}/${extern_data_basename}
+ )
+ endif()
+ endforeach()
+ endforeach()
+
+ if(ANDROID)
+ string(REGEX REPLACE "DATA{([^ ;]+)}" "\\1" processed_FILES "${AST_FILES}")
+ add_test(
+ NAME ${test_name}
+ COMMAND ${CMAKE_COMMAND}
+ "-Darg_files_dest=${AST_FILES_DEST}"
+ "-Darg_libs_dest=${AST_LIBS_DEST}"
+ "-Darg_dev_test_dir=${AST_DEVICE_TEST_DIR}"
+ "-Darg_dev_obj_store=${AST_DEVICE_OBJECT_STORE}"
+ "-Darg_no_link_regex=${AST_NO_LINK_REGEX}"
+ "-Darg_files=${processed_FILES}"
+ "-Darg_libs=${AST_LIBS}"
+ "-Darg_src_dir=${CMAKE_CURRENT_SOURCE_DIR}"
+ -P ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/AndroidTestUtilities/PushToAndroidDevice.cmake)
+ endif()
+endfunction()
diff --git a/Modules/AndroidTestUtilities/PushToAndroidDevice.cmake b/Modules/AndroidTestUtilities/PushToAndroidDevice.cmake
new file mode 100644
index 0000000..fccff67
--- /dev/null
+++ b/Modules/AndroidTestUtilities/PushToAndroidDevice.cmake
@@ -0,0 +1,176 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This function handles pushing all of the test files needed to the device.
+# It places the data files in the object store and makes links to them from
+# the appropriate directories.
+#
+# This function accepts the following named parameters:
+# DIRS : one or more directories needed for testing.
+# FILES : one or more files needed for testing.
+# LIBS : one or more libraries needed for testing.
+# DIRS_DEST : specify where the directories should be installed.
+# FILES_DEST : specify where the files should be installed.
+# LIBS_DEST : specify where the libraries should be installed.
+# DEV_OBJ_STORE : specify where the actual data files should be placed.
+# DEV_TEST_DIR : specify the root file for the module test directory.
+# The DEV_OBJ_STORE and DEV_TEST_DIR variables are required.
+
+# The parameters to this function should be set to the list of directories,
+# files, and libraries that need to be installed prior to testing.
+function(android_push_test_files_to_device)
+
+ # The functions in the module need the adb executable.
+ find_program(adb_executable adb)
+ if(NOT adb_executable)
+ message(FATAL_ERROR "could not find adb")
+ endif()
+
+ function(execute_adb_command)
+ execute_process(COMMAND ${adb_executable} ${ARGN} RESULT_VARIABLE res_var OUTPUT_VARIABLE out_var ERROR_VARIABLE err_var)
+ set(out_var ${out_var} PARENT_SCOPE)
+ if(res_var)
+ string(REGEX REPLACE ";" " " com "${ARGN}")
+ message(FATAL_ERROR "Error occurred during adb command: adb ${com}\nError: ${err_var}.")
+ endif()
+ endfunction()
+
+ # Checks to make sure that a given file exists on the device. If it does,
+ # if(file_exists) will return true.
+ macro(check_device_file_exists device_file file_exists)
+ set(${file_exists} "")
+ execute_process(
+ COMMAND ${adb_executable} shell ls ${device_file}
+ OUTPUT_VARIABLE out_var ERROR_VARIABLE out_var)
+ if(NOT out_var) # when a directory exists but is empty the output is empty
+ set(${file_exists} "YES")
+ else()
+ string(FIND ${out_var} "No such file or directory" no_file_exists)
+ if(${no_file_exists} STREQUAL "-1") # -1 means the file exists
+ set(${file_exists} "YES")
+ endif()
+ endif()
+ endmacro()
+
+ # Checks to see if a filename matches a regex.
+ function(filename_regex filename reg_ex)
+ string(REGEX MATCH ${reg_ex} filename_match ${filename})
+ set(filename_match ${filename_match} PARENT_SCOPE)
+ endfunction()
+
+ # If a file with given name exists in the CMAKE_BINARY_DIR then use that file.
+ # Otherwise use the file with root in CMAKE_CURRENT_SOURCE_DIR.
+ macro(set_absolute_path relative_path absolute_path)
+ set(${absolute_path} ${arg_src_dir}/${relative_path})
+ if(EXISTS ${CMAKE_BINARY_DIR}/${relative_path})
+ set(${absolute_path} ${CMAKE_BINARY_DIR}/${relative_path})
+ endif()
+ if(NOT EXISTS ${${absolute_path}})
+ if(EXISTS ${relative_path})
+ set(${absolute_path} ${relative_path})
+ else()
+ message(FATAL_ERROR "Cannot find file for specified path: ${relative_path}")
+ endif()
+ endif()
+ endmacro()
+
+ # This function pushes the data into the device object store and
+ # creates a link to that data file in a specified location.
+ #
+ # This function requires the following un-named parameters:
+ # data_path : absolute path to data to load into dev obj store.
+ # dev_object_store : absolute path to the device object store directory.
+ # link_origin : absolute path to the origin of the link to the dev obj store data file.
+ function(push_and_link data_path dev_object_store link_origin)
+ FILE(SHA1 ${data_path} hash_val)
+ set(obj_store_dst ${dev_object_store}/${hash_val})
+ check_device_file_exists(${obj_store_dst} obj_store_file_exists)
+ # TODO: Verify that the object store file is indeed hashed correctly. Could use md5.
+ if(NOT obj_store_file_exists)
+ execute_adb_command(push ${data_path} ${obj_store_dst})
+ endif()
+ check_device_file_exists(${link_origin} link_exists)
+ if(link_exists)
+ execute_adb_command(shell rm -f ${link_origin})
+ endif()
+ foreach(ex ${arg_no_link_regex})
+ filename_regex(${data_path} ${ex})
+ LIST(APPEND match_ex ${filename_match})
+ endforeach()
+ if(match_ex)
+ execute_adb_command(shell cp ${obj_store_dst} ${link_origin})
+ else()
+ execute_adb_command(shell ln -s ${obj_store_dst} ${link_origin})
+ endif()
+ endfunction()
+
+ #----------------------------------------------------------------------------
+ #--------------------Beginning of actual function----------------------------
+ #----------------------------------------------------------------------------
+ set(oneValueArgs FILES_DEST LIBS_DEST DEV_TEST_DIR DEV_OBJ_STORE)
+ set(multiValueArgs FILES LIBS)
+ cmake_parse_arguments(_ptd "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ # Setup of object store and test dir.
+ check_device_file_exists(${_ptd_DEV_OBJ_STORE} dev_obj_store_exists)
+ if(NOT dev_obj_store_exists)
+ execute_adb_command(shell mkdir -p ${_ptd_DEV_OBJ_STORE})
+ endif()
+ check_device_file_exists(${_ptd_DEV_TEST_DIR} test_dir_exists)
+ if(test_dir_exists)
+ # This is protected in the SetupProjectTests module.
+ execute_adb_command(shell rm -r ${_ptd_DEV_TEST_DIR})
+ endif()
+ execute_adb_command(shell mkdir -p ${_ptd_DEV_TEST_DIR})
+
+ # Looping over the various types of test data possible.
+ foreach(TYPE ${multiValueArgs})
+ if(_ptd_${TYPE})
+
+ # determine if the data type destination has been explicitly specified.
+ if(_ptd_${TYPE}_DEST)
+ set(dest ${_ptd_${TYPE}_DEST})
+ else()
+ if(${TYPE} STREQUAL LIBS)
+ set(dest ${_ptd_DEV_TEST_DIR}/lib)
+ else()
+ set(dest ${_ptd_DEV_TEST_DIR})
+ endif()
+ endif()
+ execute_adb_command(shell mkdir -p ${dest})
+
+ # Loop over the files passed in
+ foreach(relative_path ${_ptd_${TYPE}})
+ # The absolute path can be through the source directory or the build directory.
+ # If the file/dir exists in the build directory that version is chosen.
+ set_absolute_path(${relative_path} absolute_path)
+ # Need to transfer all data files in the data directories to the device
+ # except those explicitly ignored.
+ if(${TYPE} STREQUAL FILES)
+ get_filename_component(file_dir ${relative_path} DIRECTORY)
+ # dest was determined earlier, relative_path is a dir, file is path from relative path to a data
+ set(cur_dest ${dest}/${relative_path})
+ set(on_dev_dir ${dest}/${file_dir})
+ execute_adb_command(shell mkdir -p ${on_dev_dir})
+ if(IS_SYMLINK ${absolute_path})
+ get_filename_component(real_data_origin ${absolute_path} REALPATH)
+ push_and_link(${real_data_origin} ${_ptd_DEV_OBJ_STORE} ${cur_dest})
+ else()
+ push_and_link(${absolute_path} ${_ptd_DEV_OBJ_STORE} ${cur_dest})
+ endif()
+ else() # LIBS
+ execute_adb_command(push ${absolute_path} ${dest})
+ endif()
+ endforeach()
+ endif()
+ endforeach()
+endfunction()
+
+android_push_test_files_to_device(
+ FILES_DEST ${arg_files_dest}
+ LIBS_DEST ${arg_libs_dest}
+ DEV_TEST_DIR ${arg_dev_test_dir}
+ DEV_OBJ_STORE ${arg_dev_obj_store}
+ FILES ${arg_files}
+ LIBS ${arg_libs}
+ )
diff --git a/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in b/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in
new file mode 100644
index 0000000..46b8b2a
--- /dev/null
+++ b/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in
@@ -0,0 +1,48 @@
+# This is a basic version file for the Config-mode of find_package().
+# It is used by write_basic_package_version_file() as input file for configure_file()
+# to create a version-file which can be installed along a config.cmake file.
+#
+# The created file sets PACKAGE_VERSION_EXACT if the current version string and
+# the requested version string are exactly the same and it sets
+# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version.
+# The variable CVF_VERSION must be set before calling configure_file().
+
+set(PACKAGE_VERSION "@CVF_VERSION@")
+
+if (PACKAGE_FIND_VERSION_RANGE)
+ # Package version must be in the requested version range
+ if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
+ OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
+ OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+ else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ endif()
+else()
+ if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+ else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+ endif()
+endif()
+
+
+# if the installed project requested no architecture check, don't perform the check
+if("@CVF_ARCH_INDEPENDENT@")
+ return()
+endif()
+
+# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
+if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "@CMAKE_SIZEOF_VOID_P@" STREQUAL "")
+ return()
+endif()
+
+# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
+if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "@CMAKE_SIZEOF_VOID_P@")
+ math(EXPR installedBits "@CMAKE_SIZEOF_VOID_P@ * 8")
+ set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
+ set(PACKAGE_VERSION_UNSUITABLE TRUE)
+endif()
diff --git a/Modules/BasicConfigVersion-ExactVersion.cmake.in b/Modules/BasicConfigVersion-ExactVersion.cmake.in
new file mode 100644
index 0000000..3507a22
--- /dev/null
+++ b/Modules/BasicConfigVersion-ExactVersion.cmake.in
@@ -0,0 +1,59 @@
+# This is a basic version file for the Config-mode of find_package().
+# It is used by write_basic_package_version_file() as input file for configure_file()
+# to create a version-file which can be installed along a config.cmake file.
+#
+# The created file sets PACKAGE_VERSION_EXACT if the current version string and
+# the requested version string are exactly the same and it sets
+# PACKAGE_VERSION_COMPATIBLE if the current version is equal to the requested version.
+# The tweak version component is ignored.
+# The variable CVF_VERSION must be set before calling configure_file().
+
+
+if (PACKAGE_FIND_VERSION_RANGE)
+ message(AUTHOR_WARNING
+ "`find_package()` specify a version range but the version strategy "
+ "(ExactVersion) of the module `${PACKAGE_FIND_NAME}` is incompatible "
+ "with this request. Only the lower endpoint of the range will be used.")
+endif()
+
+set(PACKAGE_VERSION "@CVF_VERSION@")
+
+if("@CVF_VERSION@" MATCHES "^([0-9]+\\.[0-9]+\\.[0-9]+)\\.") # strip the tweak version
+ set(CVF_VERSION_NO_TWEAK "${CMAKE_MATCH_1}")
+else()
+ set(CVF_VERSION_NO_TWEAK "@CVF_VERSION@")
+endif()
+
+if(PACKAGE_FIND_VERSION MATCHES "^([0-9]+\\.[0-9]+\\.[0-9]+)\\.") # strip the tweak version
+ set(REQUESTED_VERSION_NO_TWEAK "${CMAKE_MATCH_1}")
+else()
+ set(REQUESTED_VERSION_NO_TWEAK "${PACKAGE_FIND_VERSION}")
+endif()
+
+if(REQUESTED_VERSION_NO_TWEAK STREQUAL CVF_VERSION_NO_TWEAK)
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+endif()
+
+if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+ set(PACKAGE_VERSION_EXACT TRUE)
+endif()
+
+
+# if the installed project requested no architecture check, don't perform the check
+if("@CVF_ARCH_INDEPENDENT@")
+ return()
+endif()
+
+# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
+if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "@CMAKE_SIZEOF_VOID_P@" STREQUAL "")
+ return()
+endif()
+
+# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
+if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "@CMAKE_SIZEOF_VOID_P@")
+ math(EXPR installedBits "@CMAKE_SIZEOF_VOID_P@ * 8")
+ set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
+ set(PACKAGE_VERSION_UNSUITABLE TRUE)
+endif()
diff --git a/Modules/BasicConfigVersion-SameMajorVersion.cmake.in b/Modules/BasicConfigVersion-SameMajorVersion.cmake.in
new file mode 100644
index 0000000..dc04e54
--- /dev/null
+++ b/Modules/BasicConfigVersion-SameMajorVersion.cmake.in
@@ -0,0 +1,67 @@
+# This is a basic version file for the Config-mode of find_package().
+# It is used by write_basic_package_version_file() as input file for configure_file()
+# to create a version-file which can be installed along a config.cmake file.
+#
+# The created file sets PACKAGE_VERSION_EXACT if the current version string and
+# the requested version string are exactly the same and it sets
+# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
+# but only if the requested major version is the same as the current one.
+# The variable CVF_VERSION must be set before calling configure_file().
+
+
+set(PACKAGE_VERSION "@CVF_VERSION@")
+
+if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+
+ if("@CVF_VERSION@" MATCHES "^([0-9]+)\\.")
+ set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
+ else()
+ set(CVF_VERSION_MAJOR "@CVF_VERSION@")
+ endif()
+
+ if(PACKAGE_FIND_VERSION_RANGE)
+ # both endpoints of the range must have the expected major version
+ math (EXPR CVF_VERSION_MAJOR_NEXT "${CVF_VERSION_MAJOR} + 1")
+ if (NOT PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
+ OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR)
+ OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL CVF_VERSION_MAJOR_NEXT)))
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+ elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
+ AND ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS_EQUAL PACKAGE_FIND_VERSION_MAX)
+ OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MAX)))
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ else()
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+ endif()
+ else()
+ if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR)
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ else()
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+ endif()
+
+ if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+ endif()
+endif()
+
+
+# if the installed project requested no architecture check, don't perform the check
+if("@CVF_ARCH_INDEPENDENT@")
+ return()
+endif()
+
+# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
+if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "@CMAKE_SIZEOF_VOID_P@" STREQUAL "")
+ return()
+endif()
+
+# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
+if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "@CMAKE_SIZEOF_VOID_P@")
+ math(EXPR installedBits "@CMAKE_SIZEOF_VOID_P@ * 8")
+ set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
+ set(PACKAGE_VERSION_UNSUITABLE TRUE)
+endif()
diff --git a/Modules/BasicConfigVersion-SameMinorVersion.cmake.in b/Modules/BasicConfigVersion-SameMinorVersion.cmake.in
new file mode 100644
index 0000000..9bb2efc
--- /dev/null
+++ b/Modules/BasicConfigVersion-SameMinorVersion.cmake.in
@@ -0,0 +1,76 @@
+# This is a basic version file for the Config-mode of find_package().
+# It is used by write_basic_package_version_file() as input file for configure_file()
+# to create a version-file which can be installed along a config.cmake file.
+#
+# The created file sets PACKAGE_VERSION_EXACT if the current version string and
+# the requested version string are exactly the same and it sets
+# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
+# but only if the requested major and minor versions are the same as the current
+# one.
+# The variable CVF_VERSION must be set before calling configure_file().
+
+
+set(PACKAGE_VERSION "@CVF_VERSION@")
+
+if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+
+ if("@CVF_VERSION@" MATCHES "^([0-9]+)\\.([0-9]+)")
+ set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
+ set(CVF_VERSION_MINOR "${CMAKE_MATCH_2}")
+ else()
+ set(CVF_VERSION_MAJOR "@CVF_VERSION@")
+ set(CVF_VERSION_MINOR "")
+ endif()
+
+ if(PACKAGE_FIND_VERSION_RANGE)
+ # both endpoints of the range must have the expected major and minor versions
+ math (EXPR CVF_VERSION_MINOR_NEXT "${CVF_VERSION_MINOR} + 1")
+ if (NOT (PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
+ AND PACKAGE_FIND_VERSION_MIN_MINOR STREQUAL CVF_VERSION_MINOR)
+ OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE"
+ AND NOT (PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR
+ AND PACKAGE_FIND_VERSION_MAX_MINOR STREQUAL CVF_VERSION_MINOR))
+ OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE"
+ AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL ${CVF_VERSION_MAJOR}.${CVF_VERSION_MINOR_NEXT})))
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+ elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
+ AND PACKAGE_FIND_VERSION_MIN_MINOR STREQUAL CVF_VERSION_MINOR
+ AND ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS_EQUAL PACKAGE_FIND_VERSION_MAX)
+ OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MAX)))
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ else()
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+ endif()
+ else()
+ if((PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR) AND
+ (PACKAGE_FIND_VERSION_MINOR STREQUAL CVF_VERSION_MINOR))
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ else()
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+ endif()
+
+ if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+ endif()
+endif()
+
+
+# if the installed project requested no architecture check, don't perform the check
+if("@CVF_ARCH_INDEPENDENT@")
+ return()
+endif()
+
+# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
+if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "@CMAKE_SIZEOF_VOID_P@" STREQUAL "")
+ return()
+endif()
+
+# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
+if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "@CMAKE_SIZEOF_VOID_P@")
+ math(EXPR installedBits "@CMAKE_SIZEOF_VOID_P@ * 8")
+ set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
+ set(PACKAGE_VERSION_UNSUITABLE TRUE)
+endif()
diff --git a/Modules/BundleUtilities.cmake b/Modules/BundleUtilities.cmake
new file mode 100644
index 0000000..0beff04
--- /dev/null
+++ b/Modules/BundleUtilities.cmake
@@ -0,0 +1,1132 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+BundleUtilities
+---------------
+
+Functions to help assemble a standalone bundle application.
+
+A collection of CMake utility functions useful for dealing with ``.app``
+bundles on the Mac and bundle-like directories on any OS.
+
+The following functions are provided by this module:
+
+.. code-block:: cmake
+
+ fixup_bundle
+ copy_and_fixup_bundle
+ verify_app
+ get_bundle_main_executable
+ get_dotapp_dir
+ get_bundle_and_executable
+ get_bundle_all_executables
+ get_item_key
+ get_item_rpaths
+ clear_bundle_keys
+ set_bundle_key_values
+ get_bundle_keys
+ copy_resolved_item_into_bundle
+ copy_resolved_framework_into_bundle
+ fixup_bundle_item
+ verify_bundle_prerequisites
+ verify_bundle_symlinks
+
+Requires CMake 2.6 or greater because it uses function, break and
+``PARENT_SCOPE``. Also depends on ``GetPrerequisites.cmake``.
+
+DO NOT USE THESE FUNCTIONS AT CONFIGURE TIME (from ``CMakeLists.txt``)!
+Instead, invoke them from an :command:`install(CODE)` or
+:command:`install(SCRIPT)` rule.
+
+.. code-block:: cmake
+
+ fixup_bundle(<app> <libs> <dirs>)
+
+Fix up ``<app>`` bundle in-place and make it standalone, such that it can be
+drag-n-drop copied to another machine and run on that machine as long
+as all of the system libraries are compatible.
+
+If you pass plugins to ``fixup_bundle`` as the libs parameter, you should
+install them or copy them into the bundle before calling ``fixup_bundle``.
+The ``<libs>`` parameter is a list of libraries that must be fixed up, but
+that cannot be determined by ``otool`` output analysis (i.e. ``plugins``).
+
+Gather all the keys for all the executables and libraries in a bundle,
+and then, for each key, copy each prerequisite into the bundle. Then
+fix each one up according to its own list of prerequisites.
+
+Then clear all the keys and call ``verify_app`` on the final bundle to
+ensure that it is truly standalone.
+
+.. versionadded:: 3.6
+ As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
+ which are then ignored
+ (e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``).
+
+.. code-block:: cmake
+
+ copy_and_fixup_bundle(<src> <dst> <libs> <dirs>)
+
+Makes a copy of the bundle ``<src>`` at location ``<dst>`` and then fixes up
+the new copied bundle in-place at ``<dst>``.
+
+.. code-block:: cmake
+
+ verify_app(<app>)
+
+Verifies that an application ``<app>`` appears valid based on running
+analysis tools on it. Calls :command:`message(FATAL_ERROR)` if the application
+is not verified.
+
+.. versionadded:: 3.6
+ As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
+ which are then ignored
+ (e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``)
+
+.. code-block:: cmake
+
+ get_bundle_main_executable(<bundle> <result_var>)
+
+The result will be the full path name of the bundle's main executable
+file or an ``error:`` prefixed string if it could not be determined.
+
+.. code-block:: cmake
+
+ get_dotapp_dir(<exe> <dotapp_dir_var>)
+
+Returns the nearest parent dir whose name ends with ``.app`` given the
+full path to an executable. If there is no such parent dir, then
+simply return the dir containing the executable.
+
+The returned directory may or may not exist.
+
+.. code-block:: cmake
+
+ get_bundle_and_executable(<app> <bundle_var> <executable_var> <valid_var>)
+
+Takes either a ``.app`` directory name or the name of an executable
+nested inside a ``.app`` directory and returns the path to the ``.app``
+directory in ``<bundle_var>`` and the path to its main executable in
+``<executable_var>``.
+
+.. code-block:: cmake
+
+ get_bundle_all_executables(<bundle> <exes_var>)
+
+Scans ``<bundle>`` bundle recursively for all ``<exes_var>`` executable
+files and accumulates them into a variable.
+
+.. code-block:: cmake
+
+ get_item_key(<item> <key_var>)
+
+Given ``<item>`` file name, generate ``<key_var>`` key that should be unique
+considering the set of libraries that need copying or fixing up to
+make a bundle standalone. This is essentially the file name including
+extension with ``.`` replaced by ``_``
+
+This key is used as a prefix for CMake variables so that we can
+associate a set of variables with a given item based on its key.
+
+.. code-block:: cmake
+
+ clear_bundle_keys(<keys_var>)
+
+Loop over the ``<keys_var>`` list of keys, clearing all the variables
+associated with each key. After the loop, clear the list of keys itself.
+
+Caller of ``get_bundle_keys`` should call ``clear_bundle_keys`` when done with
+list of keys.
+
+.. code-block:: cmake
+
+ set_bundle_key_values(<keys_var> <context> <item> <exepath> <dirs>
+ <copyflag> [<rpaths>])
+
+Add ``<keys_var>`` key to the list (if necessary) for the given item.
+If added, also set all the variables associated with that key.
+
+.. code-block:: cmake
+
+ get_bundle_keys(<app> <libs> <dirs> <keys_var>)
+
+Loop over all the executable and library files within ``<app>`` bundle (and
+given as extra ``<libs>``) and accumulate a list of keys representing
+them. Set values associated with each key such that we can loop over
+all of them and copy prerequisite libs into the bundle and then do
+appropriate ``install_name_tool`` fixups.
+
+.. versionadded:: 3.6
+ As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
+ which are then ignored
+ (e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``)
+
+.. code-block:: cmake
+
+ copy_resolved_item_into_bundle(<resolved_item> <resolved_embedded_item>)
+
+Copy a resolved item into the bundle if necessary.
+Copy is not necessary, if the ``<resolved_item>`` is "the same as" the
+``<resolved_embedded_item>``.
+
+.. code-block:: cmake
+
+ copy_resolved_framework_into_bundle(<resolved_item> <resolved_embedded_item>)
+
+Copy a resolved framework into the bundle if necessary.
+Copy is not necessary, if the ``<resolved_item>`` is "the same as" the
+``<resolved_embedded_item>``.
+
+By default, ``BU_COPY_FULL_FRAMEWORK_CONTENTS`` is not set. If you want
+full frameworks embedded in your bundles, set
+``BU_COPY_FULL_FRAMEWORK_CONTENTS`` to ``ON`` before calling fixup_bundle. By
+default, ``COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE`` copies the framework
+dylib itself plus the framework ``Resources`` directory.
+
+.. code-block:: cmake
+
+ fixup_bundle_item(<resolved_embedded_item> <exepath> <dirs>)
+
+Get the direct/non-system prerequisites of the ``<resolved_embedded_item>``.
+For each prerequisite, change the way it is referenced to the value of
+the ``_EMBEDDED_ITEM`` keyed variable for that prerequisite. (Most likely
+changing to an ``@executable_path`` style reference.)
+
+This function requires that the ``<resolved_embedded_item>`` be ``inside``
+the bundle already. In other words, if you pass plugins to ``fixup_bundle``
+as the libs parameter, you should install them or copy them into the
+bundle before calling ``fixup_bundle``. The ``libs`` parameter is a list of
+libraries that must be fixed up, but that cannot be determined by
+otool output analysis. (i.e., ``plugins``)
+
+Also, change the id of the item being fixed up to its own
+``_EMBEDDED_ITEM`` value.
+
+Accumulate changes in a local variable and make *one* call to
+``install_name_tool`` at the end of the function with all the changes at
+once.
+
+If the ``BU_CHMOD_BUNDLE_ITEMS`` variable is set then bundle items will be
+marked writable before ``install_name_tool`` tries to change them.
+
+.. code-block:: cmake
+
+ verify_bundle_prerequisites(<bundle> <result_var> <info_var>)
+
+Verifies that the sum of all prerequisites of all files inside the
+bundle are contained within the bundle or are ``system`` libraries,
+presumed to exist everywhere.
+
+.. versionadded:: 3.6
+ As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
+ which are then ignored
+ (e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``)
+
+.. code-block:: cmake
+
+ verify_bundle_symlinks(<bundle> <result_var> <info_var>)
+
+Verifies that any symlinks found in the ``<bundle>`` bundle point to other files
+that are already also in the bundle... Anything that points to an
+external file causes this function to fail the verification.
+#]=======================================================================]
+
+function(_warn_cmp0080)
+ cmake_policy(GET_WARNING CMP0080 _cmp0080_warning)
+ message(AUTHOR_WARNING "${_cmp0080_warning}\n")
+endfunction()
+
+# Do not include this module at configure time!
+if(DEFINED CMAKE_GENERATOR)
+ cmake_policy(GET CMP0080 _BundleUtilities_CMP0080)
+ if(_BundleUtilities_CMP0080 STREQUAL "NEW")
+ message(FATAL_ERROR "BundleUtilities cannot be included at configure time!")
+ elseif(NOT _BundleUtilities_CMP0080 STREQUAL "OLD" AND NOT _CMP0080_SUPPRESS_WARNING)
+ _warn_cmp0080()
+ endif()
+endif()
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+# The functions defined in this file depend on the get_prerequisites function
+# (and possibly others) found in:
+#
+include("${CMAKE_CURRENT_LIST_DIR}/GetPrerequisites.cmake")
+
+
+function(get_bundle_main_executable bundle result_var)
+ set(result "error: '${bundle}/Contents/Info.plist' file does not exist")
+
+ if(EXISTS "${bundle}/Contents/Info.plist")
+ set(result "error: no CFBundleExecutable in '${bundle}/Contents/Info.plist' file")
+ set(line_is_main_executable 0)
+ set(bundle_executable "")
+
+ # Read Info.plist as a list of lines:
+ #
+ set(eol_char "E")
+ file(READ "${bundle}/Contents/Info.plist" info_plist)
+ string(REPLACE ";" "\\;" info_plist "${info_plist}")
+ string(REPLACE "\n" "${eol_char};" info_plist "${info_plist}")
+ string(REPLACE "\r" "${eol_char};" info_plist "${info_plist}")
+
+ # Scan the lines for "<key>CFBundleExecutable</key>" - the line after that
+ # is the name of the main executable.
+ #
+ foreach(line ${info_plist})
+ if(line_is_main_executable)
+ string(REGEX REPLACE "^.*<string>(.*)</string>.*$" "\\1" bundle_executable "${line}")
+ break()
+ endif()
+
+ if(line MATCHES "<key>CFBundleExecutable</key>")
+ set(line_is_main_executable 1)
+ endif()
+ endforeach()
+
+ if(NOT bundle_executable STREQUAL "")
+ if(EXISTS "${bundle}/Contents/MacOS/${bundle_executable}")
+ set(result "${bundle}/Contents/MacOS/${bundle_executable}")
+ else()
+
+ # Ultimate goal:
+ # If not in "Contents/MacOS" then scan the bundle for matching files. If
+ # there is only one executable file that matches, then use it, otherwise
+ # it's an error...
+ #
+ #file(GLOB_RECURSE file_list "${bundle}/${bundle_executable}")
+
+ # But for now, pragmatically, it's an error. Expect the main executable
+ # for the bundle to be in Contents/MacOS, it's an error if it's not:
+ #
+ set(result "error: '${bundle}/Contents/MacOS/${bundle_executable}' does not exist")
+ endif()
+ endif()
+ else()
+ #
+ # More inclusive technique... (This one would work on Windows and Linux
+ # too, if a developer followed the typical Mac bundle naming convention...)
+ #
+ # If there is no Info.plist file, try to find an executable with the same
+ # base name as the .app directory:
+ #
+ endif()
+
+ set(${result_var} "${result}" PARENT_SCOPE)
+endfunction()
+
+
+function(get_dotapp_dir exe dotapp_dir_var)
+ set(s "${exe}")
+
+ if(s MATCHES "/.*\\.app/")
+ # If there is a ".app" parent directory,
+ # ascend until we hit it:
+ # (typical of a Mac bundle executable)
+ #
+ set(done 0)
+ while(NOT ${done})
+ get_filename_component(snamewe "${s}" NAME_WE)
+ get_filename_component(sname "${s}" NAME)
+ get_filename_component(sdir "${s}" PATH)
+ set(s "${sdir}")
+ if(sname MATCHES "\\.app$")
+ set(done 1)
+ set(dotapp_dir "${sdir}/${sname}")
+ endif()
+ endwhile()
+ else()
+ # Otherwise use a directory containing the exe
+ # (typical of a non-bundle executable on Mac, Windows or Linux)
+ #
+ is_file_executable("${s}" is_executable)
+ if(is_executable)
+ get_filename_component(sdir "${s}" PATH)
+ set(dotapp_dir "${sdir}")
+ else()
+ set(dotapp_dir "${s}")
+ endif()
+ endif()
+
+
+ set(${dotapp_dir_var} "${dotapp_dir}" PARENT_SCOPE)
+endfunction()
+
+
+function(get_bundle_and_executable app bundle_var executable_var valid_var)
+ set(valid 0)
+
+ if(EXISTS "${app}")
+ # Is it a directory ending in .app?
+ if(IS_DIRECTORY "${app}")
+ if(app MATCHES "\\.app$")
+ get_bundle_main_executable("${app}" executable)
+ if(EXISTS "${app}" AND EXISTS "${executable}")
+ set(${bundle_var} "${app}" PARENT_SCOPE)
+ set(${executable_var} "${executable}" PARENT_SCOPE)
+ set(valid 1)
+ #message(STATUS "info: handled .app directory case...")
+ else()
+ message(STATUS "warning: *NOT* handled - .app directory case...")
+ endif()
+ else()
+ message(STATUS "warning: *NOT* handled - directory but not .app case...")
+ endif()
+ else()
+ # Is it an executable file?
+ is_file_executable("${app}" is_executable)
+ if(is_executable)
+ get_dotapp_dir("${app}" dotapp_dir)
+ if(EXISTS "${dotapp_dir}")
+ set(${bundle_var} "${dotapp_dir}" PARENT_SCOPE)
+ set(${executable_var} "${app}" PARENT_SCOPE)
+ set(valid 1)
+ #message(STATUS "info: handled executable file in .app dir case...")
+ else()
+ get_filename_component(app_dir "${app}" PATH)
+ set(${bundle_var} "${app_dir}" PARENT_SCOPE)
+ set(${executable_var} "${app}" PARENT_SCOPE)
+ set(valid 1)
+ #message(STATUS "info: handled executable file in any dir case...")
+ endif()
+ else()
+ message(STATUS "warning: *NOT* handled - not .app dir, not executable file...")
+ endif()
+ endif()
+ else()
+ message(STATUS "warning: *NOT* handled - directory/file does not exist...")
+ endif()
+
+ if(NOT valid)
+ set(${bundle_var} "error: not a bundle" PARENT_SCOPE)
+ set(${executable_var} "error: not a bundle" PARENT_SCOPE)
+ endif()
+
+ set(${valid_var} ${valid} PARENT_SCOPE)
+endfunction()
+
+
+function(get_bundle_all_executables bundle exes_var)
+ set(exes "")
+
+ if(UNIX)
+ find_program(find_cmd "find")
+ mark_as_advanced(find_cmd)
+ endif()
+
+ # find command is much quicker than checking every file one by one on Unix
+ # which can take long time for large bundles, and since anyway we expect
+ # executable to have execute flag set we can narrow the list much quicker.
+ if(find_cmd)
+ execute_process(COMMAND "${find_cmd}" "${bundle}"
+ -type f \( -perm -0100 -o -perm -0010 -o -perm -0001 \)
+ OUTPUT_VARIABLE file_list
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ string(REPLACE "\n" ";" file_list "${file_list}")
+ else()
+ file(GLOB_RECURSE file_list "${bundle}/*")
+ endif()
+
+ foreach(f ${file_list})
+ is_file_executable("${f}" is_executable)
+ if(is_executable)
+ set(exes ${exes} "${f}")
+ endif()
+ endforeach()
+
+ set(${exes_var} "${exes}" PARENT_SCOPE)
+endfunction()
+
+
+function(get_item_rpaths item rpaths_var)
+ if(APPLE)
+ find_program(otool_cmd "otool")
+ mark_as_advanced(otool_cmd)
+ endif()
+
+ if(otool_cmd)
+ execute_process(
+ COMMAND "${otool_cmd}" -l "${item}"
+ OUTPUT_VARIABLE load_cmds_ov
+ RESULT_VARIABLE otool_rv
+ ERROR_VARIABLE otool_ev
+ )
+ if(NOT otool_rv STREQUAL "0")
+ message(FATAL_ERROR "otool -l failed: ${otool_rv}\n${otool_ev}")
+ endif()
+ string(REGEX REPLACE "[^\n]+cmd LC_RPATH\n[^\n]+\n[^\n]+path ([^\n]+) \\(offset[^\n]+\n" "rpath \\1\n" load_cmds_ov "${load_cmds_ov}")
+ string(REGEX MATCHALL "rpath [^\n]+" load_cmds_ov "${load_cmds_ov}")
+ string(REGEX REPLACE "rpath " "" load_cmds_ov "${load_cmds_ov}")
+ if(load_cmds_ov)
+ foreach(rpath ${load_cmds_ov})
+ gp_append_unique(${rpaths_var} "${rpath}")
+ endforeach()
+ endif()
+ endif()
+
+ if(UNIX AND NOT APPLE)
+ file(READ_ELF ${item} RPATH rpath_var RUNPATH runpath_var CAPTURE_ERROR error_var)
+ get_filename_component(item_dir ${item} DIRECTORY)
+ foreach(rpath ${rpath_var} ${runpath_var})
+ # Substitute $ORIGIN with the exepath and add to the found rpaths
+ string(REPLACE "$ORIGIN" "${item_dir}" rpath "${rpath}")
+ gp_append_unique(${rpaths_var} "${rpath}")
+ endforeach()
+ endif()
+
+ set(${rpaths_var} ${${rpaths_var}} PARENT_SCOPE)
+endfunction()
+
+
+function(get_item_key item key_var)
+ get_filename_component(item_name "${item}" NAME)
+ if(WIN32)
+ string(TOLOWER "${item_name}" item_name)
+ endif()
+ string(REPLACE "." "_" ${key_var} "${item_name}")
+ set(${key_var} ${${key_var}} PARENT_SCOPE)
+endfunction()
+
+
+function(clear_bundle_keys keys_var)
+ foreach(key ${${keys_var}})
+ set(${key}_ITEM PARENT_SCOPE)
+ set(${key}_RESOLVED_ITEM PARENT_SCOPE)
+ set(${key}_DEFAULT_EMBEDDED_PATH PARENT_SCOPE)
+ set(${key}_EMBEDDED_ITEM PARENT_SCOPE)
+ set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE)
+ set(${key}_COPYFLAG PARENT_SCOPE)
+ set(${key}_RPATHS PARENT_SCOPE)
+ endforeach()
+ set(${keys_var} PARENT_SCOPE)
+endfunction()
+
+
+function(set_bundle_key_values keys_var context item exepath dirs copyflag)
+ if(ARGC GREATER 6)
+ set(rpaths "${ARGV6}")
+ else()
+ set(rpaths "")
+ endif()
+ get_filename_component(item_name "${item}" NAME)
+
+ get_item_key("${item}" key)
+
+ list(LENGTH ${keys_var} length_before)
+ gp_append_unique(${keys_var} "${key}")
+ list(LENGTH ${keys_var} length_after)
+
+ if(NOT length_before EQUAL length_after)
+ gp_resolve_item("${context}" "${item}" "${exepath}" "${dirs}" resolved_item "${rpaths}")
+
+ gp_item_default_embedded_path("${item}" default_embedded_path)
+
+ get_item_rpaths("${resolved_item}" item_rpaths)
+
+ if((NOT item MATCHES "\\.dylib$") AND (item MATCHES "[^/]+\\.framework/"))
+ # For frameworks, construct the name under the embedded path from the
+ # opening "${item_name}.framework/" to the closing "/${item_name}":
+ #
+ string(REGEX REPLACE "^.*(${item_name}.framework/.*/?${item_name}).*$" "${default_embedded_path}/\\1" embedded_item "${item}")
+ else()
+ # For other items, just use the same name as the original, but in the
+ # embedded path:
+ #
+ set(embedded_item "${default_embedded_path}/${item_name}")
+ endif()
+
+ # Replace @executable_path and resolve ".." references:
+ #
+ string(REPLACE "@executable_path" "${exepath}" resolved_embedded_item "${embedded_item}")
+ get_filename_component(resolved_embedded_item "${resolved_embedded_item}" ABSOLUTE)
+
+ # *But* -- if we are not copying, then force resolved_embedded_item to be
+ # the same as resolved_item. In the case of multiple executables in the
+ # original bundle, using the default_embedded_path results in looking for
+ # the resolved executable next to the main bundle executable. This is here
+ # so that exes in the other sibling directories (like "bin") get fixed up
+ # properly...
+ #
+ if(NOT copyflag)
+ set(resolved_embedded_item "${resolved_item}")
+ endif()
+
+ set(${keys_var} ${${keys_var}} PARENT_SCOPE)
+ set(${key}_ITEM "${item}" PARENT_SCOPE)
+ set(${key}_RESOLVED_ITEM "${resolved_item}" PARENT_SCOPE)
+ set(${key}_DEFAULT_EMBEDDED_PATH "${default_embedded_path}" PARENT_SCOPE)
+ set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE)
+ set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE)
+ set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE)
+ set(${key}_RPATHS "${item_rpaths}" PARENT_SCOPE)
+ set(${key}_RDEP_RPATHS "${rpaths}" PARENT_SCOPE)
+ else()
+ #message("warning: item key '${key}' already in the list, subsequent references assumed identical to first")
+ endif()
+endfunction()
+
+
+function(get_bundle_keys app libs dirs keys_var)
+ set(${keys_var} PARENT_SCOPE)
+
+ set(options)
+ set(oneValueArgs)
+ set(multiValueArgs IGNORE_ITEM)
+ cmake_parse_arguments(CFG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+ get_bundle_and_executable("${app}" bundle executable valid)
+ if(valid)
+ # Always use the exepath of the main bundle executable for @executable_path
+ # replacements:
+ #
+ get_filename_component(exepath "${executable}" PATH)
+
+ # But do fixups on all executables in the bundle:
+ #
+ get_bundle_all_executables("${bundle}" exes)
+
+ # Set keys for main executable first:
+ #
+ set_bundle_key_values(${keys_var} "${executable}" "${executable}" "${exepath}" "${dirs}" 0)
+
+ # Get rpaths specified by main executable:
+ #
+ get_item_key("${executable}" executable_key)
+ set(main_rpaths "${${executable_key}_RPATHS}")
+
+ # For each extra lib, accumulate a key as well and then also accumulate
+ # any of its prerequisites. (Extra libs are typically dynamically loaded
+ # plugins: libraries that are prerequisites for full runtime functionality
+ # but that do not show up in otool -L output...)
+ #
+ foreach(lib ${libs})
+ set_bundle_key_values(${keys_var} "${lib}" "${lib}" "${exepath}" "${dirs}" 0 "${main_rpaths}")
+
+ set(prereqs "")
+ get_filename_component(prereq_filename ${lib} NAME)
+
+ if(NOT prereq_filename IN_LIST CFG_IGNORE_ITEM)
+ get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}" "${main_rpaths}")
+ foreach(pr ${prereqs})
+ set_bundle_key_values(${keys_var} "${lib}" "${pr}" "${exepath}" "${dirs}" 1 "${main_rpaths}")
+ endforeach()
+ else()
+ message(STATUS "Ignoring file: ${prereq_filename}")
+ endif()
+ endforeach()
+
+ # For each executable found in the bundle, accumulate keys as we go.
+ # The list of keys should be complete when all prerequisites of all
+ # binaries in the bundle have been analyzed.
+ #
+ foreach(exe ${exes})
+ # Main executable is scanned first above:
+ #
+ if(NOT exe STREQUAL executable)
+ # Add the exe itself to the keys:
+ #
+ set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0 "${main_rpaths}")
+
+ # Get rpaths specified by executable:
+ #
+ get_item_key("${exe}" exe_key)
+ set(exe_rpaths "${main_rpaths}" "${${exe_key}_RPATHS}")
+ else()
+ set(exe_rpaths "${main_rpaths}")
+ endif()
+
+ # Add each prerequisite to the keys:
+ #
+ set(prereqs "")
+ get_filename_component(prereq_filename ${exe} NAME)
+
+ if(NOT prereq_filename IN_LIST CFG_IGNORE_ITEM)
+ get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}" "${exe_rpaths}")
+ foreach(pr ${prereqs})
+ set_bundle_key_values(${keys_var} "${exe}" "${pr}" "${exepath}" "${dirs}" 1 "${exe_rpaths}")
+ endforeach()
+ else()
+ message(STATUS "Ignoring file: ${prereq_filename}")
+ endif()
+ endforeach()
+
+ # preserve library symlink structure
+ foreach(key ${${keys_var}})
+ if("${${key}_COPYFLAG}" STREQUAL "1")
+ if(IS_SYMLINK "${${key}_RESOLVED_ITEM}")
+ get_filename_component(target "${${key}_RESOLVED_ITEM}" REALPATH)
+ set_bundle_key_values(${keys_var} "${exe}" "${target}" "${exepath}" "${dirs}" 1 "${exe_rpaths}")
+ get_item_key("${target}" targetkey)
+
+ if(WIN32)
+ # ignore case on Windows
+ string(TOLOWER "${${key}_RESOLVED_ITEM}" resolved_item_compare)
+ string(TOLOWER "${${targetkey}_RESOLVED_EMBEDDED_ITEM}" resolved_embedded_item_compare)
+ else()
+ set(resolved_item_compare "${${key}_RESOLVED_ITEM}")
+ set(resolved_embedded_item_compare "${${targetkey}_RESOLVED_EMBEDDED_ITEM}")
+ endif()
+ get_filename_component(resolved_item_compare "${resolved_item_compare}" NAME)
+ get_filename_component(resolved_embedded_item_compare "${resolved_embedded_item_compare}" NAME)
+
+ if(NOT resolved_item_compare STREQUAL resolved_embedded_item_compare)
+ set(${key}_COPYFLAG "2")
+ set(${key}_RESOLVED_ITEM "${${targetkey}_RESOLVED_EMBEDDED_ITEM}")
+ endif()
+
+ endif()
+ endif()
+ endforeach()
+ # Propagate values to caller's scope:
+ #
+ set(${keys_var} ${${keys_var}} PARENT_SCOPE)
+ foreach(key ${${keys_var}})
+ set(${key}_ITEM "${${key}_ITEM}" PARENT_SCOPE)
+ set(${key}_RESOLVED_ITEM "${${key}_RESOLVED_ITEM}" PARENT_SCOPE)
+ set(${key}_DEFAULT_EMBEDDED_PATH "${${key}_DEFAULT_EMBEDDED_PATH}" PARENT_SCOPE)
+ set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE)
+ set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE)
+ set(${key}_COPYFLAG "${${key}_COPYFLAG}" PARENT_SCOPE)
+ set(${key}_RPATHS "${${key}_RPATHS}" PARENT_SCOPE)
+ set(${key}_RDEP_RPATHS "${${key}_RDEP_RPATHS}" PARENT_SCOPE)
+ endforeach()
+ endif()
+endfunction()
+
+function(link_resolved_item_into_bundle resolved_item resolved_embedded_item)
+ if(WIN32)
+ # ignore case on Windows
+ string(TOLOWER "${resolved_item}" resolved_item_compare)
+ string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
+ else()
+ set(resolved_item_compare "${resolved_item}")
+ set(resolved_embedded_item_compare "${resolved_embedded_item}")
+ endif()
+
+ if(resolved_item_compare STREQUAL resolved_embedded_item_compare)
+ message(STATUS "warning: resolved_item == resolved_embedded_item - not linking...")
+ else()
+ get_filename_component(target_dir "${resolved_embedded_item}" DIRECTORY)
+ file(RELATIVE_PATH symlink_target "${target_dir}" "${resolved_item}")
+ if (NOT EXISTS "${target_dir}")
+ file(MAKE_DIRECTORY "${target_dir}")
+ endif()
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${symlink_target}" "${resolved_embedded_item}")
+ endif()
+endfunction()
+
+function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item)
+ if(WIN32)
+ # ignore case on Windows
+ string(TOLOWER "${resolved_item}" resolved_item_compare)
+ string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
+ else()
+ set(resolved_item_compare "${resolved_item}")
+ set(resolved_embedded_item_compare "${resolved_embedded_item}")
+ endif()
+
+ if(resolved_item_compare STREQUAL resolved_embedded_item_compare)
+ message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...")
+ else()
+ #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
+ if(UNIX AND NOT APPLE)
+ file(RPATH_REMOVE FILE "${resolved_embedded_item}")
+ endif()
+ endif()
+
+endfunction()
+
+
+function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_item)
+ if(WIN32)
+ # ignore case on Windows
+ string(TOLOWER "${resolved_item}" resolved_item_compare)
+ string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
+ else()
+ set(resolved_item_compare "${resolved_item}")
+ set(resolved_embedded_item_compare "${resolved_embedded_item}")
+ endif()
+
+ if(resolved_item_compare STREQUAL resolved_embedded_item_compare)
+ message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...")
+ else()
+ if(BU_COPY_FULL_FRAMEWORK_CONTENTS)
+ # Full Framework (everything):
+ get_filename_component(resolved_dir "${resolved_item}" PATH)
+ get_filename_component(resolved_dir "${resolved_dir}/../.." ABSOLUTE)
+ get_filename_component(resolved_embedded_dir "${resolved_embedded_item}" PATH)
+ get_filename_component(resolved_embedded_dir "${resolved_embedded_dir}/../.." ABSOLUTE)
+ #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_dir}' '${resolved_embedded_dir}'")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_dir}" "${resolved_embedded_dir}")
+ else()
+ # Framework lib itself:
+ #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
+
+ # Plus Resources, if they exist:
+ string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}")
+ string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_embedded_resources "${resolved_embedded_item}")
+ if(EXISTS "${resolved_resources}")
+ #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_resources}' '${resolved_embedded_resources}'")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}")
+ endif()
+
+ # Some frameworks e.g. Qt put Info.plist in wrong place, so when it is
+ # missing in resources, copy it from other well known incorrect locations:
+ if(NOT EXISTS "${resolved_resources}/Info.plist")
+ # Check for Contents/Info.plist in framework root (older Qt SDK):
+ string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Contents/Info.plist" resolved_info_plist "${resolved_item}")
+ string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources/Info.plist" resolved_embedded_info_plist "${resolved_embedded_item}")
+ if(EXISTS "${resolved_info_plist}")
+ #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_info_plist}' '${resolved_embedded_info_plist}'")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_info_plist}" "${resolved_embedded_info_plist}")
+ endif()
+ endif()
+
+ # Check if framework is versioned and fix it layout
+ string(REGEX REPLACE "^.*/([^/]+)/[^/]+$" "\\1" resolved_embedded_version "${resolved_embedded_item}")
+ string(REGEX REPLACE "^(.*)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions "${resolved_embedded_item}")
+ string(REGEX REPLACE "^.*/([^/]+)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions_basename "${resolved_embedded_item}")
+ if(resolved_embedded_versions_basename STREQUAL "Versions")
+ # Ensure Current symlink points to the framework version
+ if(NOT EXISTS "${resolved_embedded_versions}/Current")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${resolved_embedded_version}" "${resolved_embedded_versions}/Current")
+ endif()
+ # Restore symlinks in framework root pointing to current framework
+ # binary and resources:
+ string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1" resolved_embedded_root "${resolved_embedded_item}")
+ string(REGEX REPLACE "^.*/([^/]+)$" "\\1" resolved_embedded_item_basename "${resolved_embedded_item}")
+ if(NOT EXISTS "${resolved_embedded_root}/${resolved_embedded_item_basename}")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/${resolved_embedded_item_basename}" "${resolved_embedded_root}/${resolved_embedded_item_basename}")
+ endif()
+ if(NOT EXISTS "${resolved_embedded_root}/Resources")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/Resources" "${resolved_embedded_root}/Resources")
+ endif()
+ endif()
+ endif()
+ if(UNIX AND NOT APPLE)
+ file(RPATH_REMOVE FILE "${resolved_embedded_item}")
+ endif()
+ endif()
+
+endfunction()
+
+
+function(fixup_bundle_item resolved_embedded_item exepath dirs)
+ # This item's key is "ikey":
+ #
+ get_item_key("${resolved_embedded_item}" ikey)
+
+ # Ensure the item is "inside the .app bundle" -- it should not be fixed up if
+ # it is not in the .app bundle... Otherwise, we'll modify files in the build
+ # tree, or in other varied locations around the file system, with our call to
+ # install_name_tool. Make sure that doesn't happen here:
+ #
+ get_dotapp_dir("${exepath}" exe_dotapp_dir)
+ string(LENGTH "${exe_dotapp_dir}/" exe_dotapp_dir_length)
+ string(LENGTH "${resolved_embedded_item}" resolved_embedded_item_length)
+ set(path_too_short 0)
+ set(is_embedded 0)
+ if(resolved_embedded_item_length LESS exe_dotapp_dir_length)
+ set(path_too_short 1)
+ endif()
+ if(NOT path_too_short)
+ string(SUBSTRING "${resolved_embedded_item}" 0 ${exe_dotapp_dir_length} item_substring)
+ if("${exe_dotapp_dir}/" STREQUAL item_substring)
+ set(is_embedded 1)
+ endif()
+ endif()
+ if(NOT is_embedded)
+ message(" exe_dotapp_dir/='${exe_dotapp_dir}/'")
+ message(" item_substring='${item_substring}'")
+ message(" resolved_embedded_item='${resolved_embedded_item}'")
+ message("")
+ message("Install or copy the item into the bundle before calling fixup_bundle.")
+ message("Or maybe there's a typo or incorrect path in one of the args to fixup_bundle?")
+ message("")
+ message(FATAL_ERROR "cannot fixup an item that is not in the bundle...")
+ endif()
+
+ set(rpaths "${${ikey}_RPATHS}" "${${ikey}_RDEP_RPATHS}")
+
+ set(prereqs "")
+ get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}" "${rpaths}")
+
+ set(changes "")
+
+ foreach(pr ${prereqs})
+ # Each referenced item's key is "rkey" in the loop:
+ #
+ get_item_key("${pr}" rkey)
+
+ if(NOT "${${rkey}_EMBEDDED_ITEM}" STREQUAL "")
+ set(changes ${changes} "-change" "${pr}" "${${rkey}_EMBEDDED_ITEM}")
+ else()
+ message("warning: unexpected reference to '${pr}'")
+ endif()
+ endforeach()
+
+ if(BU_CHMOD_BUNDLE_ITEMS)
+ execute_process(COMMAND chmod u+w "${resolved_embedded_item}")
+ endif()
+
+ # CMAKE_INSTALL_NAME_TOOL may not be set if executed in script mode
+ # Duplicated from CMakeFindBinUtils.cmake
+ find_program(CMAKE_INSTALL_NAME_TOOL NAMES install_name_tool HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
+
+ # Only if install_name_tool supports -delete_rpath:
+ #
+ execute_process(COMMAND ${CMAKE_INSTALL_NAME_TOOL}
+ OUTPUT_VARIABLE install_name_tool_usage
+ ERROR_VARIABLE install_name_tool_usage
+ )
+ if(install_name_tool_usage MATCHES ".*-delete_rpath.*")
+ foreach(rpath ${${ikey}_RPATHS})
+ set(changes ${changes} -delete_rpath "${rpath}")
+ endforeach()
+ endif()
+
+ if(${ikey}_EMBEDDED_ITEM)
+ set(changes ${changes} -id "${${ikey}_EMBEDDED_ITEM}")
+ endif()
+
+ # Change this item's id and all of its references in one call
+ # to install_name_tool:
+ #
+ if(changes)
+ # Check for a script by extension (.bat,.sh,...) or if the file starts with "#!" (shebang)
+ file(READ ${resolved_embedded_item} file_contents LIMIT 5)
+ if(NOT "${resolved_embedded_item}" MATCHES "\\.(bat|c?sh|bash|ksh|cmd)$" AND
+ NOT file_contents MATCHES "^#!")
+ set(cmd ${CMAKE_INSTALL_NAME_TOOL} ${changes} "${resolved_embedded_item}")
+ execute_process(COMMAND ${cmd} RESULT_VARIABLE install_name_tool_result)
+ if(NOT install_name_tool_result EQUAL 0)
+ string(REPLACE ";" "' '" msg "'${cmd}'")
+ message(FATAL_ERROR "Command failed:\n ${msg}")
+ endif()
+ endif()
+ endif()
+endfunction()
+
+
+function(fixup_bundle app libs dirs)
+ message(STATUS "fixup_bundle")
+ message(STATUS " app='${app}'")
+ message(STATUS " libs='${libs}'")
+ message(STATUS " dirs='${dirs}'")
+
+ set(options)
+ set(oneValueArgs)
+ set(multiValueArgs IGNORE_ITEM)
+ cmake_parse_arguments(CFG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+ message(STATUS " ignoreItems='${CFG_IGNORE_ITEM}'")
+
+ get_bundle_and_executable("${app}" bundle executable valid)
+ if(valid)
+ get_filename_component(exepath "${executable}" PATH)
+
+ message(STATUS "fixup_bundle: preparing...")
+ get_bundle_keys("${app}" "${libs}" "${dirs}" keys IGNORE_ITEM "${CFG_IGNORE_ITEM}")
+
+ message(STATUS "fixup_bundle: copying...")
+ list(LENGTH keys n)
+ math(EXPR n ${n}*2)
+
+ set(i 0)
+ foreach(key ${keys})
+ math(EXPR i ${i}+1)
+ if("${${key}_COPYFLAG}" STREQUAL "2")
+ message(STATUS "${i}/${n}: linking '${${key}_RESOLVED_ITEM}' -> '${${key}_RESOLVED_EMBEDDED_ITEM}'")
+ elseif(${${key}_COPYFLAG})
+ message(STATUS "${i}/${n}: copying '${${key}_RESOLVED_ITEM}'")
+ else()
+ message(STATUS "${i}/${n}: *NOT* copying '${${key}_RESOLVED_ITEM}'")
+ endif()
+
+ set(show_status 0)
+ if(show_status)
+ message(STATUS "key='${key}'")
+ message(STATUS "item='${${key}_ITEM}'")
+ message(STATUS "resolved_item='${${key}_RESOLVED_ITEM}'")
+ message(STATUS "default_embedded_path='${${key}_DEFAULT_EMBEDDED_PATH}'")
+ message(STATUS "embedded_item='${${key}_EMBEDDED_ITEM}'")
+ message(STATUS "resolved_embedded_item='${${key}_RESOLVED_EMBEDDED_ITEM}'")
+ message(STATUS "copyflag='${${key}_COPYFLAG}'")
+ message(STATUS "")
+ endif()
+
+ if("${${key}_COPYFLAG}" STREQUAL "2")
+ link_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}"
+ "${${key}_RESOLVED_EMBEDDED_ITEM}")
+ elseif(${${key}_COPYFLAG})
+ set(item "${${key}_ITEM}")
+ if(item MATCHES "[^/]+\\.framework/")
+ copy_resolved_framework_into_bundle("${${key}_RESOLVED_ITEM}"
+ "${${key}_RESOLVED_EMBEDDED_ITEM}")
+ else()
+ copy_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}"
+ "${${key}_RESOLVED_EMBEDDED_ITEM}")
+ endif()
+ endif()
+ endforeach()
+
+ message(STATUS "fixup_bundle: fixing...")
+ foreach(key ${keys})
+ math(EXPR i ${i}+1)
+ if(APPLE)
+ message(STATUS "${i}/${n}: fixing up '${${key}_RESOLVED_EMBEDDED_ITEM}'")
+ if(NOT "${${key}_COPYFLAG}" STREQUAL "2")
+ fixup_bundle_item("${${key}_RESOLVED_EMBEDDED_ITEM}" "${exepath}" "${dirs}")
+ endif()
+ else()
+ message(STATUS "${i}/${n}: fix-up not required on this platform '${${key}_RESOLVED_EMBEDDED_ITEM}'")
+ endif()
+ endforeach()
+
+ message(STATUS "fixup_bundle: cleaning up...")
+ clear_bundle_keys(keys)
+
+ message(STATUS "fixup_bundle: verifying...")
+ verify_app("${app}" IGNORE_ITEM "${CFG_IGNORE_ITEM}")
+ else()
+ message(SEND_ERROR "error: fixup_bundle: not a valid bundle")
+ endif()
+
+ message(STATUS "fixup_bundle: done")
+endfunction()
+
+
+function(copy_and_fixup_bundle src dst libs dirs)
+ execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${src}" "${dst}")
+ fixup_bundle("${dst}" "${libs}" "${dirs}")
+endfunction()
+
+
+function(verify_bundle_prerequisites bundle result_var info_var)
+ set(result 1)
+ set(info "")
+ set(count 0)
+
+ set(options)
+ set(oneValueArgs)
+ set(multiValueArgs IGNORE_ITEM)
+ cmake_parse_arguments(CFG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+ get_bundle_main_executable("${bundle}" main_bundle_exe)
+
+ get_bundle_all_executables("${bundle}" file_list)
+ foreach(f ${file_list})
+ get_filename_component(exepath "${f}" PATH)
+ math(EXPR count "${count} + 1")
+
+ message(STATUS "executable file ${count}: ${f}")
+
+ set(prereqs "")
+ get_filename_component(prereq_filename ${f} NAME)
+
+ if(NOT prereq_filename IN_LIST CFG_IGNORE_ITEM)
+ get_item_rpaths(${f} _main_exe_rpaths)
+ get_prerequisites("${f}" prereqs 1 1 "${exepath}" "${_main_exe_rpaths}")
+
+ # On the Mac,
+ # "embedded" and "system" prerequisites are fine... anything else means
+ # the bundle's prerequisites are not verified (i.e., the bundle is not
+ # really "standalone")
+ #
+ # On Windows (and others? Linux/Unix/...?)
+ # "local" and "system" prereqs are fine...
+ #
+
+ set(external_prereqs "")
+
+ foreach(p ${prereqs})
+ set(p_type "")
+ gp_file_type("${f}" "${p}" p_type)
+
+ if(APPLE)
+ if(NOT p_type STREQUAL "embedded" AND NOT p_type STREQUAL "system")
+ set(external_prereqs ${external_prereqs} "${p}")
+ endif()
+ else()
+ if(NOT p_type STREQUAL "local" AND NOT p_type STREQUAL "system")
+ set(external_prereqs ${external_prereqs} "${p}")
+ endif()
+ endif()
+ endforeach()
+
+ if(external_prereqs)
+ # Found non-system/somehow-unacceptable prerequisites:
+ set(result 0)
+ set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n")
+ endif()
+ else()
+ message(STATUS "Ignoring file: ${prereq_filename}")
+ endif()
+ endforeach()
+
+ if(result)
+ set(info "Verified ${count} executable files in '${bundle}'")
+ endif()
+
+ set(${result_var} "${result}" PARENT_SCOPE)
+ set(${info_var} "${info}" PARENT_SCOPE)
+endfunction()
+
+
+function(verify_bundle_symlinks bundle result_var info_var)
+ set(result 1)
+ set(info "")
+ set(count 0)
+
+ # TODO: implement this function for real...
+ # Right now, it is just a stub that verifies unconditionally...
+
+ set(${result_var} "${result}" PARENT_SCOPE)
+ set(${info_var} "${info}" PARENT_SCOPE)
+endfunction()
+
+
+function(verify_app app)
+ set(verified 0)
+ set(info "")
+
+ set(options)
+ set(oneValueArgs)
+ set(multiValueArgs IGNORE_ITEM)
+ cmake_parse_arguments(CFG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+ get_bundle_and_executable("${app}" bundle executable valid)
+
+ message(STATUS "===========================================================================")
+ message(STATUS "Analyzing app='${app}'")
+ message(STATUS "bundle='${bundle}'")
+ message(STATUS "executable='${executable}'")
+ message(STATUS "valid='${valid}'")
+
+ # Verify that the bundle does not have any "external" prerequisites:
+ #
+ verify_bundle_prerequisites("${bundle}" verified info IGNORE_ITEM "${CFG_IGNORE_ITEM}")
+ message(STATUS "verified='${verified}'")
+ message(STATUS "info='${info}'")
+ message(STATUS "")
+
+ if(verified)
+ # Verify that the bundle does not have any symlinks to external files:
+ #
+ verify_bundle_symlinks("${bundle}" verified info)
+ message(STATUS "verified='${verified}'")
+ message(STATUS "info='${info}'")
+ message(STATUS "")
+ endif()
+
+ if(NOT verified)
+ message(FATAL_ERROR "error: verify_app failed")
+ endif()
+endfunction()
+
+cmake_policy(POP)
diff --git a/Modules/CMake.cmake b/Modules/CMake.cmake
new file mode 100644
index 0000000..caa5479
--- /dev/null
+++ b/Modules/CMake.cmake
@@ -0,0 +1,7 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is used by cmake.cxx to compute the CMAKE_ROOT location.
+# Do not remove this file from cvs without updating cmake.cxx to look
+# for a different file.
diff --git a/Modules/CMakeASM-ATTInformation.cmake b/Modules/CMakeASM-ATTInformation.cmake
new file mode 100644
index 0000000..d1970a2
--- /dev/null
+++ b/Modules/CMakeASM-ATTInformation.cmake
@@ -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.
+
+
+# support for AT&T syntax assemblers, e.g. GNU as
+
+set(ASM_DIALECT "-ATT")
+# *.S files are supposed to be preprocessed, so they should not be passed to
+# assembler but should be processed by gcc
+set(CMAKE_ASM${ASM_DIALECT}_SOURCE_FILE_EXTENSIONS s;asm)
+
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <INCLUDES> <FLAGS> -o <OBJECT> <SOURCE>")
+
+include(CMakeASMInformation)
+set(ASM_DIALECT)
diff --git a/Modules/CMakeASMCompiler.cmake.in b/Modules/CMakeASMCompiler.cmake.in
new file mode 100644
index 0000000..3953b30
--- /dev/null
+++ b/Modules/CMakeASMCompiler.cmake.in
@@ -0,0 +1,20 @@
+set(CMAKE_ASM@ASM_DIALECT@_COMPILER "@_CMAKE_ASM_COMPILER@")
+set(CMAKE_ASM@ASM_DIALECT@_COMPILER_ARG1 "@_CMAKE_ASM_COMPILER_ARG1@")
+set(CMAKE_AR "@CMAKE_AR@")
+set(CMAKE_ASM@ASM_DIALECT@_COMPILER_AR "@_CMAKE_ASM_COMPILER_AR@")
+set(CMAKE_RANLIB "@CMAKE_RANLIB@")
+set(CMAKE_ASM@ASM_DIALECT@_COMPILER_RANLIB "@_CMAKE_ASM_COMPILER_RANLIB@")
+set(CMAKE_LINKER "@CMAKE_LINKER@")
+set(CMAKE_MT "@CMAKE_MT@")
+set(CMAKE_ASM@ASM_DIALECT@_COMPILER_LOADED 1)
+set(CMAKE_ASM@ASM_DIALECT@_COMPILER_ID "@_CMAKE_ASM_COMPILER_ID@")
+set(CMAKE_ASM@ASM_DIALECT@_COMPILER_VERSION "@_CMAKE_ASM_COMPILER_VERSION@")
+set(CMAKE_ASM@ASM_DIALECT@_COMPILER_ENV_VAR "@_CMAKE_ASM_COMPILER_ENV_VAR@")
+@_SET_CMAKE_ASM_COMPILER_ID_VENDOR_MATCH@
+@_SET_CMAKE_ASM_COMPILER_ARCHITECTURE_ID@
+@_SET_CMAKE_ASM_COMPILER_SYSROOT@
+
+set(CMAKE_ASM@ASM_DIALECT@_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC)
+set(CMAKE_ASM@ASM_DIALECT@_LINKER_PREFERENCE 0)
+
+@CMAKE_ASM_COMPILER_CUSTOM_CODE@
diff --git a/Modules/CMakeASMInformation.cmake b/Modules/CMakeASMInformation.cmake
new file mode 100644
index 0000000..2dc1585
--- /dev/null
+++ b/Modules/CMakeASMInformation.cmake
@@ -0,0 +1,100 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+if(UNIX)
+ set(CMAKE_ASM${ASM_DIALECT}_OUTPUT_EXTENSION .o)
+else()
+ set(CMAKE_ASM${ASM_DIALECT}_OUTPUT_EXTENSION .obj)
+endif()
+
+set(CMAKE_INCLUDE_FLAG_ASM${ASM_DIALECT} "-I") # -I
+set(CMAKE_BASE_NAME)
+get_filename_component(CMAKE_BASE_NAME "${CMAKE_ASM${ASM_DIALECT}_COMPILER}" NAME_WE)
+
+if("${CMAKE_BASE_NAME}" STREQUAL "as")
+ set(CMAKE_BASE_NAME gas)
+endif()
+
+# Load compiler-specific information.
+set(_INCLUDED_FILE "")
+if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
+ include(Compiler/${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}-ASM${ASM_DIALECT} OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
+endif()
+if(NOT _INCLUDED_FILE)
+ if("ASM${ASM_DIALECT}" STREQUAL "ASM")
+ message(STATUS "Warning: Did not find file Compiler/${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}-ASM${ASM_DIALECT}")
+ endif()
+ include(Platform/${CMAKE_BASE_NAME} OPTIONAL)
+endif()
+
+if(CMAKE_SYSTEM_PROCESSOR)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}-ASM${ASM_DIALECT}-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
+ if(NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME}-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL)
+ endif()
+endif()
+
+include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}-ASM${ASM_DIALECT} OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
+if(NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME} OPTIONAL)
+endif()
+
+# This should be included before the _INIT variables are
+# used to initialize the cache. Since the rule variables
+# have if blocks on them, users can still define them here.
+# But, it should still be after the platform file so changes can
+# be made to those values.
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE "${_override}")
+endif()
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE_ASM)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE_ASM} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE_ASM "${_override}")
+endif()
+
+# Set default assembler file extensions:
+if(NOT CMAKE_ASM${ASM_DIALECT}_SOURCE_FILE_EXTENSIONS)
+ set(CMAKE_ASM${ASM_DIALECT}_SOURCE_FILE_EXTENSIONS s;S;asm)
+endif()
+
+
+# Support for CMAKE_ASM${ASM_DIALECT}_FLAGS_INIT and friends:
+set(CMAKE_ASM${ASM_DIALECT}_FLAGS_INIT "$ENV{ASM${ASM_DIALECT}FLAGS} ${CMAKE_ASM${ASM_DIALECT}_FLAGS_INIT}")
+
+cmake_initialize_per_config_variable(CMAKE_ASM${ASM_DIALECT}_FLAGS "Flags used by the ASM${ASM_DIALECT} compiler")
+
+if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT)
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+endif()
+
+if(NOT CMAKE_ASM${ASM_DIALECT}_CREATE_STATIC_LIBRARY)
+ set(CMAKE_ASM${ASM_DIALECT}_CREATE_STATIC_LIBRARY
+ "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS> "
+ "<CMAKE_RANLIB> <TARGET>")
+endif()
+
+if(NOT CMAKE_ASM${ASM_DIALECT}_LINK_EXECUTABLE)
+ set(CMAKE_ASM${ASM_DIALECT}_LINK_EXECUTABLE
+ "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <FLAGS> <CMAKE_ASM${ASM_DIALECT}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RUNTIME_ASM${ASM_DIALECT}_FLAG)
+ set(CMAKE_EXECUTABLE_RUNTIME_ASM${ASM_DIALECT}_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_ASM${ASM_DIALECT}_FLAG})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RUNTIME_ASM${ASM_DIALECT}_FLAG_SEP)
+ set(CMAKE_EXECUTABLE_RUNTIME_ASM${ASM_DIALECT}_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_ASM${ASM_DIALECT}_FLAG_SEP})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RPATH_LINK_ASM${ASM_DIALECT}_FLAG)
+ set(CMAKE_EXECUTABLE_RPATH_LINK_ASM${ASM_DIALECT}_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_ASM${ASM_DIALECT}_FLAG})
+endif()
+
+
+set(CMAKE_ASM${ASM_DIALECT}_INFOMATION_LOADED 1)
diff --git a/Modules/CMakeASM_MASMInformation.cmake b/Modules/CMakeASM_MASMInformation.cmake
new file mode 100644
index 0000000..6d1e174
--- /dev/null
+++ b/Modules/CMakeASM_MASMInformation.cmake
@@ -0,0 +1,20 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# support for the MS assembler, masm and masm64
+
+set(ASM_DIALECT "_MASM")
+
+set(CMAKE_ASM${ASM_DIALECT}_SOURCE_FILE_EXTENSIONS asm)
+
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> /c /Fo <OBJECT> <SOURCE>")
+
+# The ASM_MASM compiler id for this compiler is "MSVC", so fill out the runtime library table.
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL "")
+
+include(CMakeASMInformation)
+set(ASM_DIALECT)
diff --git a/Modules/CMakeASM_NASMInformation.cmake b/Modules/CMakeASM_NASMInformation.cmake
new file mode 100644
index 0000000..27b93ec
--- /dev/null
+++ b/Modules/CMakeASM_NASMInformation.cmake
@@ -0,0 +1,53 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# support for the nasm assembler
+
+set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS nasm asm)
+
+if(NOT CMAKE_ASM_NASM_OBJECT_FORMAT)
+ if(WIN32)
+ if(DEFINED CMAKE_C_SIZEOF_DATA_PTR AND CMAKE_C_SIZEOF_DATA_PTR EQUAL 8)
+ set(CMAKE_ASM_NASM_OBJECT_FORMAT win64)
+ elseif(DEFINED CMAKE_CXX_SIZEOF_DATA_PTR AND CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8)
+ set(CMAKE_ASM_NASM_OBJECT_FORMAT win64)
+ else()
+ set(CMAKE_ASM_NASM_OBJECT_FORMAT win32)
+ endif()
+ elseif(APPLE)
+ if(DEFINED CMAKE_C_SIZEOF_DATA_PTR AND CMAKE_C_SIZEOF_DATA_PTR EQUAL 8)
+ set(CMAKE_ASM_NASM_OBJECT_FORMAT macho64)
+ elseif(DEFINED CMAKE_CXX_SIZEOF_DATA_PTR AND CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8)
+ set(CMAKE_ASM_NASM_OBJECT_FORMAT macho64)
+ else()
+ set(CMAKE_ASM_NASM_OBJECT_FORMAT macho)
+ endif()
+ else()
+ if(DEFINED CMAKE_C_SIZEOF_DATA_PTR AND CMAKE_C_SIZEOF_DATA_PTR EQUAL 8)
+ set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64)
+ elseif(DEFINED CMAKE_CXX_SIZEOF_DATA_PTR AND CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8)
+ set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64)
+ else()
+ set(CMAKE_ASM_NASM_OBJECT_FORMAT elf)
+ endif()
+ endif()
+endif()
+
+if(NOT CMAKE_ASM_NASM_COMPILE_OBJECT)
+ set(CMAKE_ASM_NASM_COMPILE_OBJECT "<CMAKE_ASM_NASM_COMPILER> <INCLUDES> <FLAGS> -f ${CMAKE_ASM_NASM_OBJECT_FORMAT} -o <OBJECT> <SOURCE>")
+endif()
+
+set(CMAKE_DEPFILE_FLAGS_ASM_NASM "-MD <DEP_FILE> -MT <DEP_TARGET>")
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ # dependencies are computed by the compiler itself
+ set(CMAKE_ASM_NASM_DEPFILE_FORMAT gcc)
+ set(CMAKE_ASM_NASM_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+# Load the generic ASMInformation file:
+set(ASM_DIALECT "_NASM")
+include(CMakeASMInformation)
+set(ASM_DIALECT)
diff --git a/Modules/CMakeAddFortranSubdirectory.cmake b/Modules/CMakeAddFortranSubdirectory.cmake
new file mode 100644
index 0000000..69a8417
--- /dev/null
+++ b/Modules/CMakeAddFortranSubdirectory.cmake
@@ -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.
+
+#[=======================================================================[.rst:
+CMakeAddFortranSubdirectory
+---------------------------
+
+Add a fortran-only subdirectory, find a fortran compiler, and build.
+
+The ``cmake_add_fortran_subdirectory`` function adds a subdirectory
+to a project that contains a fortran-only subproject. The module will
+check the current compiler and see if it can support fortran. If no
+fortran compiler is found and the compiler is MSVC, then this module
+will find the MinGW gfortran. It will then use an external project to
+build with the MinGW tools. It will also create imported targets for
+the libraries created. This will only work if the fortran code is
+built into a dll, so :variable:`BUILD_SHARED_LIBS` is turned on in
+the project. In addition the :variable:`CMAKE_GNUtoMS` option is set
+to on, so that Microsoft ``.lib`` files are created. Usage is as follows:
+
+::
+
+ cmake_add_fortran_subdirectory(
+ <subdir> # name of subdirectory
+ PROJECT <project_name> # project name in subdir top CMakeLists.txt
+ ARCHIVE_DIR <dir> # dir where project places .lib files
+ RUNTIME_DIR <dir> # dir where project places .dll files
+ LIBRARIES <lib>... # names of library targets to import
+ LINK_LIBRARIES # link interface libraries for LIBRARIES
+ [LINK_LIBS <lib> <dep>...]...
+ CMAKE_COMMAND_LINE ... # extra command line flags to pass to cmake
+ NO_EXTERNAL_INSTALL # skip installation of external project
+ )
+
+Relative paths in ``ARCHIVE_DIR`` and ``RUNTIME_DIR`` are interpreted with
+respect to the build directory corresponding to the source directory
+in which the function is invoked.
+
+Limitations:
+
+``NO_EXTERNAL_INSTALL`` is required for forward compatibility with a
+future version that supports installation of the external project
+binaries during ``make install``.
+#]=======================================================================]
+
+include(CheckLanguage)
+include(ExternalProject)
+
+function(_setup_mingw_config_and_build source_dir build_dir)
+ # Look for a MinGW gfortran.
+ find_program(MINGW_GFORTRAN
+ NAMES gfortran
+ PATHS
+ c:/MinGW/bin
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MinGW;InstallLocation]/bin"
+ )
+ if(NOT MINGW_GFORTRAN)
+ message(FATAL_ERROR
+ "gfortran not found, please install MinGW with the gfortran option."
+ "Or set the cache variable MINGW_GFORTRAN to the full path. "
+ " This is required to build")
+ endif()
+
+ # Validate the MinGW gfortran we found.
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(_mingw_target "Target:.*64.*mingw")
+ else()
+ set(_mingw_target "Target:.*mingw32")
+ endif()
+ execute_process(COMMAND "${MINGW_GFORTRAN}" -v
+ ERROR_VARIABLE out ERROR_STRIP_TRAILING_WHITESPACE)
+ if(NOT "${out}" MATCHES "${_mingw_target}")
+ string(REPLACE "\n" "\n " out " ${out}")
+ message(FATAL_ERROR
+ "MINGW_GFORTRAN is set to\n"
+ " ${MINGW_GFORTRAN}\n"
+ "which is not a MinGW gfortran for this architecture. "
+ "The output from -v does not match \"${_mingw_target}\":\n"
+ "${out}\n"
+ "Set MINGW_GFORTRAN to a proper MinGW gfortran for this architecture."
+ )
+ endif()
+
+ # Configure scripts to run MinGW tools with the proper PATH.
+ get_filename_component(MINGW_PATH ${MINGW_GFORTRAN} PATH)
+ file(TO_NATIVE_PATH "${MINGW_PATH}" MINGW_PATH)
+ string(REPLACE "\\" "\\\\" MINGW_PATH "${MINGW_PATH}")
+ configure_file(
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/CMakeAddFortranSubdirectory/config_mingw.cmake.in
+ ${build_dir}/config_mingw.cmake
+ @ONLY)
+ configure_file(
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/CMakeAddFortranSubdirectory/build_mingw.cmake.in
+ ${build_dir}/build_mingw.cmake
+ @ONLY)
+endfunction()
+
+function(_add_fortran_library_link_interface library depend_library)
+ set_target_properties(${library} PROPERTIES
+ IMPORTED_LINK_INTERFACE_LIBRARIES_NOCONFIG "${depend_library}")
+endfunction()
+
+
+function(cmake_add_fortran_subdirectory subdir)
+ # Parse arguments to function
+ set(options NO_EXTERNAL_INSTALL)
+ set(oneValueArgs PROJECT ARCHIVE_DIR RUNTIME_DIR)
+ set(multiValueArgs LIBRARIES LINK_LIBRARIES CMAKE_COMMAND_LINE)
+ cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+ if(NOT ARGS_NO_EXTERNAL_INSTALL)
+ message(FATAL_ERROR
+ "Option NO_EXTERNAL_INSTALL is required (for forward compatibility) "
+ "but was not given."
+ )
+ endif()
+
+ # if we are not using MSVC without fortran support
+ # then just use the usual add_subdirectory to build
+ # the fortran library
+ check_language(Fortran)
+ if(NOT (MSVC AND (NOT CMAKE_Fortran_COMPILER)))
+ add_subdirectory(${subdir})
+ return()
+ endif()
+
+ # if we have MSVC without Intel fortran then setup
+ # external projects to build with mingw fortran
+
+ set(source_dir "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}")
+ set(project_name "${ARGS_PROJECT}")
+ set(library_dir "${ARGS_ARCHIVE_DIR}")
+ set(binary_dir "${ARGS_RUNTIME_DIR}")
+ set(libraries ${ARGS_LIBRARIES})
+ # use the same directory that add_subdirectory would have used
+ set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/${subdir}")
+ foreach(dir_var library_dir binary_dir)
+ if(NOT IS_ABSOLUTE "${${dir_var}}")
+ get_filename_component(${dir_var}
+ "${CMAKE_CURRENT_BINARY_DIR}/${${dir_var}}" ABSOLUTE)
+ endif()
+ endforeach()
+ # create build and configure wrapper scripts
+ _setup_mingw_config_and_build("${source_dir}" "${build_dir}")
+ # create the external project
+ externalproject_add(${project_name}_build
+ SOURCE_DIR ${source_dir}
+ BINARY_DIR ${build_dir}
+ CONFIGURE_COMMAND ${CMAKE_COMMAND}
+ -P ${build_dir}/config_mingw.cmake
+ BUILD_COMMAND ${CMAKE_COMMAND}
+ -P ${build_dir}/build_mingw.cmake
+ BUILD_ALWAYS 1
+ INSTALL_COMMAND ""
+ )
+ # create imported targets for all libraries
+ foreach(lib ${libraries})
+ add_library(${lib} SHARED IMPORTED GLOBAL)
+ set_property(TARGET ${lib} APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG)
+ set_target_properties(${lib} PROPERTIES
+ IMPORTED_IMPLIB_NOCONFIG "${library_dir}/lib${lib}.lib"
+ IMPORTED_LOCATION_NOCONFIG "${binary_dir}/lib${lib}.dll"
+ )
+ add_dependencies(${lib} ${project_name}_build)
+ endforeach()
+
+ # now setup link libraries for targets
+ set(start FALSE)
+ set(target)
+ foreach(lib ${ARGS_LINK_LIBRARIES})
+ if("${lib}" STREQUAL "LINK_LIBS")
+ set(start TRUE)
+ else()
+ if(start)
+ if(DEFINED target)
+ # process current target and target_libs
+ _add_fortran_library_link_interface(${target} "${target_libs}")
+ # zero out target and target_libs
+ set(target)
+ set(target_libs)
+ endif()
+ # save the current target and set start to FALSE
+ set(target ${lib})
+ set(start FALSE)
+ else()
+ # append the lib to target_libs
+ list(APPEND target_libs "${lib}")
+ endif()
+ endif()
+ endforeach()
+ # process anything that is left in target and target_libs
+ if(DEFINED target)
+ _add_fortran_library_link_interface(${target} "${target_libs}")
+ endif()
+endfunction()
diff --git a/Modules/CMakeAddFortranSubdirectory/build_mingw.cmake.in b/Modules/CMakeAddFortranSubdirectory/build_mingw.cmake.in
new file mode 100644
index 0000000..55b271a
--- /dev/null
+++ b/Modules/CMakeAddFortranSubdirectory/build_mingw.cmake.in
@@ -0,0 +1,2 @@
+set(ENV{PATH} "@MINGW_PATH@\;$ENV{PATH}")
+execute_process(COMMAND "@CMAKE_COMMAND@" --build . )
diff --git a/Modules/CMakeAddFortranSubdirectory/config_mingw.cmake.in b/Modules/CMakeAddFortranSubdirectory/config_mingw.cmake.in
new file mode 100644
index 0000000..97f6769
--- /dev/null
+++ b/Modules/CMakeAddFortranSubdirectory/config_mingw.cmake.in
@@ -0,0 +1,9 @@
+set(ENV{PATH} "@MINGW_PATH@\;$ENV{PATH}")
+set(CMAKE_COMMAND_LINE "@ARGS_CMAKE_COMMAND_LINE@")
+execute_process(
+ COMMAND "@CMAKE_COMMAND@" "-GMinGW Makefiles"
+ -DCMAKE_Fortran_COMPILER:PATH=@MINGW_GFORTRAN@
+ -DBUILD_SHARED_LIBS=ON
+ -DCMAKE_GNUtoMS=ON
+ ${CMAKE_COMMAND_LINE}
+ "@source_dir@")
diff --git a/Modules/CMakeAddNewLanguage.txt b/Modules/CMakeAddNewLanguage.txt
new file mode 100644
index 0000000..b0be590
--- /dev/null
+++ b/Modules/CMakeAddNewLanguage.txt
@@ -0,0 +1,31 @@
+This file provides a few notes to CMake developers about how to add
+support for a new language to CMake. It is also possible to place
+these files in :variable:`CMAKE_MODULE_PATH` within an outside project
+to add languages not supported by upstream CMake. However, this is not
+a fully supported use case.
+
+The implementation behind the scenes of project/enable_language,
+including the compiler/platform modules, is an *internal* API that
+does not make any compatibility guarantees. It is not covered in the
+official reference documentation that is versioned with the source code.
+Maintainers of external language support are responsible for porting
+it to each version of CMake as upstream changes are made. Since
+the API is internal we will not necessarily include notice of any
+changes in release notes.
+
+
+CMakeDetermine(LANG)Compiler.cmake -> this should find the compiler for LANG and configure CMake(LANG)Compiler.cmake.in
+
+CMake(LANG)Compiler.cmake.in -> used by CMakeDetermine(LANG)Compiler.cmake
+ This file is used to store compiler information and is copied down into try
+ compile directories so that try compiles do not need to re-determine and test the LANG
+
+CMakeTest(LANG)Compiler.cmake -> test the compiler and set:
+ SET(CMAKE_(LANG)_COMPILER_WORKS 1 CACHE INTERNAL "")
+
+CMake(LANG)Information.cmake -> set up rule variables for LANG :
+ CMAKE_(LANG)_CREATE_SHARED_LIBRARY
+ CMAKE_(LANG)_CREATE_SHARED_MODULE
+ CMAKE_(LANG)_CREATE_STATIC_LIBRARY
+ CMAKE_(LANG)_COMPILE_OBJECT
+ CMAKE_(LANG)_LINK_EXECUTABLE
diff --git a/Modules/CMakeBackwardCompatibilityC.cmake b/Modules/CMakeBackwardCompatibilityC.cmake
new file mode 100644
index 0000000..775a513
--- /dev/null
+++ b/Modules/CMakeBackwardCompatibilityC.cmake
@@ -0,0 +1,76 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+if(NOT CMAKE_SKIP_COMPATIBILITY_TESTS)
+ # Old CMake versions did not support OS X universal binaries anyway,
+ # so just get through this with at least some size for the types.
+ list(LENGTH CMAKE_OSX_ARCHITECTURES NUM_ARCHS)
+ if(${NUM_ARCHS} GREATER 1)
+ if(NOT DEFINED CMAKE_TRY_COMPILE_OSX_ARCHITECTURES)
+ message(WARNING "This module does not work with OS X universal binaries.")
+ set(__ERASE_CMAKE_TRY_COMPILE_OSX_ARCHITECTURES 1)
+ list(GET CMAKE_OSX_ARCHITECTURES 0 CMAKE_TRY_COMPILE_OSX_ARCHITECTURES)
+ endif()
+ endif()
+
+ include (CheckTypeSize)
+ CHECK_TYPE_SIZE(int CMAKE_SIZEOF_INT)
+ CHECK_TYPE_SIZE(long CMAKE_SIZEOF_LONG)
+ CHECK_TYPE_SIZE("void*" CMAKE_SIZEOF_VOID_P)
+ CHECK_TYPE_SIZE(char CMAKE_SIZEOF_CHAR)
+ CHECK_TYPE_SIZE(short CMAKE_SIZEOF_SHORT)
+ CHECK_TYPE_SIZE(float CMAKE_SIZEOF_FLOAT)
+ CHECK_TYPE_SIZE(double CMAKE_SIZEOF_DOUBLE)
+
+ include (CheckIncludeFile)
+ CHECK_INCLUDE_FILE("limits.h" CMAKE_HAVE_LIMITS_H)
+ CHECK_INCLUDE_FILE("unistd.h" CMAKE_HAVE_UNISTD_H)
+ CHECK_INCLUDE_FILE("pthread.h" CMAKE_HAVE_PTHREAD_H)
+
+ include (CheckIncludeFiles)
+ CHECK_INCLUDE_FILES("sys/types.h;sys/prctl.h" CMAKE_HAVE_SYS_PRCTL_H)
+
+ include (TestBigEndian)
+ TEST_BIG_ENDIAN(CMAKE_WORDS_BIGENDIAN)
+ include (FindX11)
+
+ if("${X11_X11_INCLUDE_PATH}" STREQUAL "/usr/include")
+ set (CMAKE_X_CFLAGS "" CACHE STRING "X11 extra flags.")
+ else()
+ set (CMAKE_X_CFLAGS "-I${X11_X11_INCLUDE_PATH}" CACHE STRING
+ "X11 extra flags.")
+ endif()
+ set (CMAKE_X_LIBS "${X11_LIBRARIES}" CACHE STRING
+ "Libraries and options used in X11 programs.")
+ set (CMAKE_HAS_X "${X11_FOUND}" CACHE INTERNAL "Is X11 around.")
+
+ include (FindThreads)
+
+ set (CMAKE_THREAD_LIBS "${CMAKE_THREAD_LIBS_INIT}" CACHE STRING
+ "Thread library used.")
+
+ set (CMAKE_USE_PTHREADS "${CMAKE_USE_PTHREADS_INIT}" CACHE BOOL
+ "Use the pthreads library.")
+
+ set (CMAKE_USE_WIN32_THREADS "${CMAKE_USE_WIN32_THREADS_INIT}" CACHE BOOL
+ "Use the win32 thread library.")
+
+ set (CMAKE_HP_PTHREADS ${CMAKE_HP_PTHREADS_INIT} CACHE BOOL
+ "Use HP pthreads.")
+
+ if(__ERASE_CMAKE_TRY_COMPILE_OSX_ARCHITECTURES)
+ set(CMAKE_TRY_COMPILE_OSX_ARCHITECTURES)
+ set(__ERASE_CMAKE_TRY_COMPILE_OSX_ARCHITECTURES)
+ endif()
+endif()
+
+mark_as_advanced(
+CMAKE_HP_PTHREADS
+CMAKE_THREAD_LIBS
+CMAKE_USE_PTHREADS
+CMAKE_USE_WIN32_THREADS
+CMAKE_X_CFLAGS
+CMAKE_X_LIBS
+)
+
diff --git a/Modules/CMakeBackwardCompatibilityCXX.cmake b/Modules/CMakeBackwardCompatibilityCXX.cmake
new file mode 100644
index 0000000..02744a9
--- /dev/null
+++ b/Modules/CMakeBackwardCompatibilityCXX.cmake
@@ -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.
+
+#[=======================================================================[.rst:
+CMakeBackwardCompatibilityCXX
+-----------------------------
+
+define a bunch of backwards compatibility variables
+
+::
+
+ CMAKE_ANSI_CXXFLAGS - flag for ansi c++
+ CMAKE_HAS_ANSI_STRING_STREAM - has <strstream>
+ include(TestForANSIStreamHeaders)
+ include(CheckIncludeFileCXX)
+ include(TestForSTDNamespace)
+ include(TestForANSIForScope)
+#]=======================================================================]
+
+if(NOT CMAKE_SKIP_COMPATIBILITY_TESTS)
+ # check for some ANSI flags in the CXX compiler if it is not gnu
+ if(NOT CMAKE_COMPILER_IS_GNUCXX)
+ include(TestCXXAcceptsFlag)
+ set(CMAKE_TRY_ANSI_CXX_FLAGS "")
+ if(CMAKE_SYSTEM_NAME MATCHES "OSF")
+ set(CMAKE_TRY_ANSI_CXX_FLAGS "-std strict_ansi -nopure_cname")
+ endif()
+ # if CMAKE_TRY_ANSI_CXX_FLAGS has something in it, see
+ # if the compiler accepts it
+ if(NOT CMAKE_TRY_ANSI_CXX_FLAGS STREQUAL "")
+ CHECK_CXX_ACCEPTS_FLAG(${CMAKE_TRY_ANSI_CXX_FLAGS} CMAKE_CXX_ACCEPTS_FLAGS)
+ # if the compiler liked the flag then set CMAKE_ANSI_CXXFLAGS
+ # to the flag
+ if(CMAKE_CXX_ACCEPTS_FLAGS)
+ set(CMAKE_ANSI_CXXFLAGS ${CMAKE_TRY_ANSI_CXX_FLAGS} CACHE INTERNAL
+ "What flags are required by the c++ compiler to make it ansi." )
+ endif()
+ endif()
+ endif()
+ set(CMAKE_CXX_FLAGS_SAVE ${CMAKE_CXX_FLAGS})
+ string(APPEND CMAKE_CXX_FLAGS " ${CMAKE_ANSI_CXXFLAGS}")
+ include(TestForANSIStreamHeaders)
+ include(CheckIncludeFileCXX)
+ include(TestForSTDNamespace)
+ include(TestForANSIForScope)
+ include(TestForSSTREAM)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_SAVE}")
+endif()
+
diff --git a/Modules/CMakeBorlandFindMake.cmake b/Modules/CMakeBorlandFindMake.cmake
new file mode 100644
index 0000000..18b9962
--- /dev/null
+++ b/Modules/CMakeBorlandFindMake.cmake
@@ -0,0 +1,7 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+set (CMAKE_MAKE_PROGRAM "make" CACHE STRING
+ "Program used to build from makefiles.")
+mark_as_advanced(CMAKE_MAKE_PROGRAM)
diff --git a/Modules/CMakeBuildSettings.cmake.in b/Modules/CMakeBuildSettings.cmake.in
new file mode 100644
index 0000000..7c4aa14
--- /dev/null
+++ b/Modules/CMakeBuildSettings.cmake.in
@@ -0,0 +1,13 @@
+
+# The command CMAKE_EXPORT_BUILD_SETTINGS(...) was used by
+# @PROJECT_NAME@ to generate this file. As of CMake 2.8 the
+# functionality of this command has been dropped as it was deemed
+# harmful (confusing users by changing their compiler).
+
+# CMake 2.6 and below do not support loading their equivalent of this
+# file if it was produced by a newer version of CMake. CMake 2.8 and
+# above simply do not load this file. Therefore we simply error out.
+message(FATAL_ERROR
+ "This @PROJECT_NAME@ was built by CMake @CMAKE_VERSION@, but this is CMake "
+ "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}. "
+ "Please upgrade CMake to a more recent version.")
diff --git a/Modules/CMakeCCompiler.cmake.in b/Modules/CMakeCCompiler.cmake.in
new file mode 100644
index 0000000..754f235
--- /dev/null
+++ b/Modules/CMakeCCompiler.cmake.in
@@ -0,0 +1,80 @@
+set(CMAKE_C_COMPILER "@CMAKE_C_COMPILER@")
+set(CMAKE_C_COMPILER_ARG1 "@CMAKE_C_COMPILER_ARG1@")
+set(CMAKE_C_COMPILER_ID "@CMAKE_C_COMPILER_ID@")
+set(CMAKE_C_COMPILER_VERSION "@CMAKE_C_COMPILER_VERSION@")
+set(CMAKE_C_COMPILER_VERSION_INTERNAL "@CMAKE_C_COMPILER_VERSION_INTERNAL@")
+set(CMAKE_C_COMPILER_WRAPPER "@CMAKE_C_COMPILER_WRAPPER@")
+set(CMAKE_C_STANDARD_COMPUTED_DEFAULT "@CMAKE_C_STANDARD_COMPUTED_DEFAULT@")
+set(CMAKE_C_COMPILE_FEATURES "@CMAKE_C_COMPILE_FEATURES@")
+set(CMAKE_C90_COMPILE_FEATURES "@CMAKE_C90_COMPILE_FEATURES@")
+set(CMAKE_C99_COMPILE_FEATURES "@CMAKE_C99_COMPILE_FEATURES@")
+set(CMAKE_C11_COMPILE_FEATURES "@CMAKE_C11_COMPILE_FEATURES@")
+set(CMAKE_C17_COMPILE_FEATURES "@CMAKE_C17_COMPILE_FEATURES@")
+set(CMAKE_C23_COMPILE_FEATURES "@CMAKE_C23_COMPILE_FEATURES@")
+
+set(CMAKE_C_PLATFORM_ID "@CMAKE_C_PLATFORM_ID@")
+set(CMAKE_C_SIMULATE_ID "@CMAKE_C_SIMULATE_ID@")
+set(CMAKE_C_COMPILER_FRONTEND_VARIANT "@CMAKE_C_COMPILER_FRONTEND_VARIANT@")
+set(CMAKE_C_SIMULATE_VERSION "@CMAKE_C_SIMULATE_VERSION@")
+@_SET_CMAKE_C_COMPILER_ARCHITECTURE_ID@
+@_SET_CMAKE_C_COMPILER_SYSROOT@
+@SET_MSVC_C_ARCHITECTURE_ID@
+@SET_CMAKE_XCODE_ARCHS@
+set(CMAKE_AR "@CMAKE_AR@")
+set(CMAKE_C_COMPILER_AR "@CMAKE_C_COMPILER_AR@")
+set(CMAKE_RANLIB "@CMAKE_RANLIB@")
+set(CMAKE_C_COMPILER_RANLIB "@CMAKE_C_COMPILER_RANLIB@")
+set(CMAKE_LINKER "@CMAKE_LINKER@")
+set(CMAKE_MT "@CMAKE_MT@")
+set(CMAKE_COMPILER_IS_GNUCC @CMAKE_COMPILER_IS_GNUCC@)
+set(CMAKE_C_COMPILER_LOADED 1)
+set(CMAKE_C_COMPILER_WORKS @CMAKE_C_COMPILER_WORKS@)
+set(CMAKE_C_ABI_COMPILED @CMAKE_C_ABI_COMPILED@)
+set(CMAKE_COMPILER_IS_MINGW @CMAKE_COMPILER_IS_MINGW@)
+set(CMAKE_COMPILER_IS_CYGWIN @CMAKE_COMPILER_IS_CYGWIN@)
+if(CMAKE_COMPILER_IS_CYGWIN)
+ set(CYGWIN 1)
+ set(UNIX 1)
+endif()
+
+set(CMAKE_C_COMPILER_ENV_VAR "CC")
+
+if(CMAKE_COMPILER_IS_MINGW)
+ set(MINGW 1)
+endif()
+set(CMAKE_C_COMPILER_ID_RUN 1)
+set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m)
+set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC)
+set(CMAKE_C_LINKER_PREFERENCE 10)
+
+# Save compiler ABI information.
+set(CMAKE_C_SIZEOF_DATA_PTR "@CMAKE_C_SIZEOF_DATA_PTR@")
+set(CMAKE_C_COMPILER_ABI "@CMAKE_C_COMPILER_ABI@")
+set(CMAKE_C_BYTE_ORDER "@CMAKE_C_BYTE_ORDER@")
+set(CMAKE_C_LIBRARY_ARCHITECTURE "@CMAKE_C_LIBRARY_ARCHITECTURE@")
+
+if(CMAKE_C_SIZEOF_DATA_PTR)
+ set(CMAKE_SIZEOF_VOID_P "${CMAKE_C_SIZEOF_DATA_PTR}")
+endif()
+
+if(CMAKE_C_COMPILER_ABI)
+ set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_C_COMPILER_ABI}")
+endif()
+
+if(CMAKE_C_LIBRARY_ARCHITECTURE)
+ set(CMAKE_LIBRARY_ARCHITECTURE "@CMAKE_C_LIBRARY_ARCHITECTURE@")
+endif()
+
+set(CMAKE_C_CL_SHOWINCLUDES_PREFIX "@CMAKE_C_CL_SHOWINCLUDES_PREFIX@")
+if(CMAKE_C_CL_SHOWINCLUDES_PREFIX)
+ set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_C_CL_SHOWINCLUDES_PREFIX}")
+endif()
+
+@CMAKE_C_COMPILER_CUSTOM_CODE@
+@CMAKE_C_SYSROOT_FLAG_CODE@
+@CMAKE_C_OSX_DEPLOYMENT_TARGET_FLAG_CODE@
+
+set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES "@CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES@")
+set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "@CMAKE_C_IMPLICIT_LINK_LIBRARIES@")
+set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "@CMAKE_C_IMPLICIT_LINK_DIRECTORIES@")
+set(CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@")
diff --git a/Modules/CMakeCCompilerABI.c b/Modules/CMakeCCompilerABI.c
new file mode 100644
index 0000000..f0ee21a
--- /dev/null
+++ b/Modules/CMakeCCompilerABI.c
@@ -0,0 +1,27 @@
+#ifdef __cplusplus
+# error "A C++ compiler has been selected for C."
+#endif
+
+#ifdef __CLASSIC_C__
+# define const
+#endif
+
+#include "CMakeCompilerABI.h"
+
+#ifdef __CLASSIC_C__
+int main(argc, argv) int argc;
+char* argv[];
+#else
+int main(int argc, char* argv[])
+#endif
+{
+ int require = 0;
+ require += info_sizeof_dptr[argc];
+ require += info_byte_order_big_endian[argc];
+ require += info_byte_order_little_endian[argc];
+#if defined(ABI_ID)
+ require += info_abi[argc];
+#endif
+ (void)argv;
+ return require;
+}
diff --git a/Modules/CMakeCCompilerId.c.in b/Modules/CMakeCCompilerId.c.in
new file mode 100644
index 0000000..75e9d1a
--- /dev/null
+++ b/Modules/CMakeCCompilerId.c.in
@@ -0,0 +1,90 @@
+#ifdef __cplusplus
+# error "A C++ compiler has been selected for C."
+#endif
+
+#if defined(__18CXX)
+# define ID_VOID_MAIN
+#endif
+#if defined(__CLASSIC_C__)
+/* cv-qualifiers did not exist in K&R C */
+# define const
+# define volatile
+#endif
+
+@CMAKE_C_COMPILER_ID_CONTENT@
+
+/* Construct the string literal in pieces to prevent the source from
+ getting matched. Store it in a pointer rather than an array
+ because some compilers will just produce instructions to fill the
+ array rather than assigning a pointer to a static array. */
+char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
+#ifdef SIMULATE_ID
+char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
+#endif
+
+#ifdef __QNXNTO__
+char const* qnxnto = "INFO" ":" "qnxnto[]";
+#endif
+
+#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
+char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
+#endif
+
+@CMAKE_C_COMPILER_ID_PLATFORM_CONTENT@
+@CMAKE_C_COMPILER_ID_ERROR_FOR_TEST@
+
+#if !defined(__STDC__) && !defined(__clang__)
+# if defined(_MSC_VER) || defined(__ibmxl__) || defined(__IBMC__)
+# define C_DIALECT "90"
+# else
+# define C_DIALECT
+# endif
+#elif __STDC_VERSION__ > 201710L
+# define C_DIALECT "23"
+#elif __STDC_VERSION__ >= 201710L
+# define C_DIALECT "17"
+#elif __STDC_VERSION__ >= 201000L
+# define C_DIALECT "11"
+#elif __STDC_VERSION__ >= 199901L
+# define C_DIALECT "99"
+#else
+# define C_DIALECT "90"
+#endif
+const char* info_language_dialect_default =
+ "INFO" ":" "dialect_default[" C_DIALECT "]";
+
+/*--------------------------------------------------------------------------*/
+
+#ifdef ID_VOID_MAIN
+void main() {}
+#else
+# if defined(__CLASSIC_C__)
+int main(argc, argv) int argc; char *argv[];
+# else
+int main(int argc, char* argv[])
+# endif
+{
+ int require = 0;
+ require += info_compiler[argc];
+ require += info_platform[argc];
+ require += info_arch[argc];
+#ifdef COMPILER_VERSION_MAJOR
+ require += info_version[argc];
+#endif
+#ifdef COMPILER_VERSION_INTERNAL
+ require += info_version_internal[argc];
+#endif
+#ifdef SIMULATE_ID
+ require += info_simulate[argc];
+#endif
+#ifdef SIMULATE_VERSION_MAJOR
+ require += info_simulate_version[argc];
+#endif
+#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
+ require += info_cray[argc];
+#endif
+ require += info_language_dialect_default[argc];
+ (void)argv;
+ return require;
+}
+#endif
diff --git a/Modules/CMakeCInformation.cmake b/Modules/CMakeCInformation.cmake
new file mode 100644
index 0000000..f6d620f
--- /dev/null
+++ b/Modules/CMakeCInformation.cmake
@@ -0,0 +1,195 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file sets the basic flags for the C language in CMake.
+# It also loads the available platform file for the system-compiler
+# if it exists.
+# It also loads a system - compiler - processor (or target hardware)
+# specific file, which is mainly useful for crosscompiling and embedded systems.
+
+include(CMakeLanguageInformation)
+
+# some compilers use different extensions (e.g. sdcc uses .rel)
+# so set the extension here first so it can be overridden by the compiler specific file
+if(UNIX)
+ set(CMAKE_C_OUTPUT_EXTENSION .o)
+else()
+ set(CMAKE_C_OUTPUT_EXTENSION .obj)
+endif()
+
+set(_INCLUDED_FILE 0)
+
+# Load compiler-specific information.
+if(CMAKE_C_COMPILER_ID)
+ include(Compiler/${CMAKE_C_COMPILER_ID}-C OPTIONAL)
+endif()
+
+set(CMAKE_BASE_NAME)
+get_filename_component(CMAKE_BASE_NAME "${CMAKE_C_COMPILER}" NAME_WE)
+if(CMAKE_COMPILER_IS_GNUCC)
+ set(CMAKE_BASE_NAME gcc)
+endif()
+
+
+# load a hardware specific file, mostly useful for embedded compilers
+if(CMAKE_SYSTEM_PROCESSOR)
+ if(CMAKE_C_COMPILER_ID)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_C_COMPILER_ID}-C-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
+ endif()
+ if (NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME}-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL)
+ endif ()
+endif()
+
+
+# load the system- and compiler specific files
+if(CMAKE_C_COMPILER_ID)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_C_COMPILER_ID}-C
+ OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
+endif()
+if (NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME}
+ OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
+endif ()
+
+# load any compiler-wrapper specific information
+if (CMAKE_C_COMPILER_WRAPPER)
+ __cmake_include_compiler_wrapper(C)
+endif ()
+
+# We specify the compiler information in the system file for some
+# platforms, but this language may not have been enabled when the file
+# was first included. Include it again to get the language info.
+# Remove this when all compiler info is removed from system files.
+if (NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_SYSTEM_NAME} OPTIONAL)
+endif ()
+
+if(CMAKE_C_SIZEOF_DATA_PTR)
+ foreach(f ${CMAKE_C_ABI_FILES})
+ include(${f})
+ endforeach()
+ unset(CMAKE_C_ABI_FILES)
+endif()
+
+# This should be included before the _INIT variables are
+# used to initialize the cache. Since the rule variables
+# have if blocks on them, users can still define them here.
+# But, it should still be after the platform file so changes can
+# be made to those values.
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE "${_override}")
+endif()
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE_C)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE_C} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE_C "${_override}")
+endif()
+
+
+# for most systems a module is the same as a shared library
+# so unless the variable CMAKE_MODULE_EXISTS is set just
+# copy the values from the LIBRARY variables
+if(NOT CMAKE_MODULE_EXISTS)
+ set(CMAKE_SHARED_MODULE_C_FLAGS ${CMAKE_SHARED_LIBRARY_C_FLAGS})
+ set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS})
+endif()
+
+set(CMAKE_C_FLAGS_INIT "$ENV{CFLAGS} ${CMAKE_C_FLAGS_INIT}")
+
+cmake_initialize_per_config_variable(CMAKE_C_FLAGS "Flags used by the C compiler")
+
+if(CMAKE_C_STANDARD_LIBRARIES_INIT)
+ set(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES_INIT}"
+ CACHE STRING "Libraries linked by default with all C applications.")
+ mark_as_advanced(CMAKE_C_STANDARD_LIBRARIES)
+endif()
+
+if(NOT CMAKE_C_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_C_COMPILER_LAUNCHER})
+ set(CMAKE_C_COMPILER_LAUNCHER "$ENV{CMAKE_C_COMPILER_LAUNCHER}"
+ CACHE STRING "Compiler launcher for C.")
+endif()
+
+include(CMakeCommonLanguageInclude)
+
+# now define the following rule variables
+
+# CMAKE_C_CREATE_SHARED_LIBRARY
+# CMAKE_C_CREATE_SHARED_MODULE
+# CMAKE_C_COMPILE_OBJECT
+# CMAKE_C_LINK_EXECUTABLE
+
+# variables supplied by the generator at use time
+# <TARGET>
+# <TARGET_BASE> the target without the suffix
+# <OBJECTS>
+# <OBJECT>
+# <LINK_LIBRARIES>
+# <FLAGS>
+# <LINK_FLAGS>
+
+# C compiler information
+# <CMAKE_C_COMPILER>
+# <CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS>
+# <CMAKE_SHARED_MODULE_CREATE_C_FLAGS>
+# <CMAKE_C_LINK_FLAGS>
+
+# Static library tools
+# <CMAKE_AR>
+# <CMAKE_RANLIB>
+
+
+# create a C shared library
+if(NOT CMAKE_C_CREATE_SHARED_LIBRARY)
+ set(CMAKE_C_CREATE_SHARED_LIBRARY
+ "<CMAKE_C_COMPILER> <CMAKE_SHARED_LIBRARY_C_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
+endif()
+
+# create a C shared module just copy the shared library rule
+if(NOT CMAKE_C_CREATE_SHARED_MODULE)
+ set(CMAKE_C_CREATE_SHARED_MODULE ${CMAKE_C_CREATE_SHARED_LIBRARY})
+endif()
+
+# Create a static archive incrementally for large object file counts.
+# If CMAKE_C_CREATE_STATIC_LIBRARY is set it will override these.
+if(NOT DEFINED CMAKE_C_ARCHIVE_CREATE)
+ set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_C_ARCHIVE_APPEND)
+ set(CMAKE_C_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_C_ARCHIVE_FINISH)
+ set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
+endif()
+
+# compile a C file into an object file
+if(NOT CMAKE_C_COMPILE_OBJECT)
+ set(CMAKE_C_COMPILE_OBJECT
+ "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+endif()
+
+if(NOT CMAKE_C_LINK_EXECUTABLE)
+ set(CMAKE_C_LINK_EXECUTABLE
+ "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RUNTIME_C_FLAG)
+ set(CMAKE_EXECUTABLE_RUNTIME_C_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RUNTIME_C_FLAG_SEP)
+ set(CMAKE_EXECUTABLE_RUNTIME_C_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RPATH_LINK_C_FLAG)
+ set(CMAKE_EXECUTABLE_RPATH_LINK_C_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG})
+endif()
+
+set(CMAKE_C_INFORMATION_LOADED 1)
+
+
diff --git a/Modules/CMakeCSharpCompiler.cmake.in b/Modules/CMakeCSharpCompiler.cmake.in
new file mode 100644
index 0000000..3d49b6b
--- /dev/null
+++ b/Modules/CMakeCSharpCompiler.cmake.in
@@ -0,0 +1,10 @@
+set(CMAKE_CSharp_COMPILER "@CMAKE_CSharp_COMPILER@")
+set(CMAKE_CSharp_COMPILER_ID "@CMAKE_CSharp_COMPILER_ID@")
+set(CMAKE_CSharp_COMPILER_VERSION "@CMAKE_CSharp_COMPILER_VERSION@")
+
+set(CMAKE_CSharp_COMPILER_LOADED 1)
+set(CMAKE_CSharp_COMPILER_WORKS "@CMAKE_CSharp_COMPILER_WORKS@")
+
+set(CMAKE_CSharp_COMPILER_ID_RUN "@CMAKE_CSharp_COMPILER_ID_RUN@")
+set(CMAKE_CSharp_IGNORE_EXTENSIONS "inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC")
+set(CMAKE_CSharp_SOURCE_FILE_EXTENSIONS "cs")
diff --git a/Modules/CMakeCSharpCompilerId.cs.in b/Modules/CMakeCSharpCompilerId.cs.in
new file mode 100644
index 0000000..987f63a
--- /dev/null
+++ b/Modules/CMakeCSharpCompilerId.cs.in
@@ -0,0 +1,63 @@
+using System;
+
+namespace CSharp
+{
+ public class CSharpApp
+ {
+ const string InfoCompiler = "INFO:compiler[Microsoft "
+#if PlatformToolsetv100
+ + "Visual Studio"
+#elif PlatformToolsetv110
+ + "Visual Studio"
+#elif PlatformToolsetv120
+ + "Visual Studio"
+#elif PlatformToolsetv140
+ + "Visual Studio"
+#elif PlatformToolsetv141
+ + "Visual Studio"
+#else
+ + "unknown"
+#endif
+ + "]";
+
+ const string InfoPlatform = "INFO:platform[Windows]";
+
+ const string InfoArchitecture = "INFO:arch["
+#if Platformx64
+ + "x64"
+#elif Platformx86
+ + "x86"
+#elif PlatformxWin32
+ + "Win32]"
+#else
+ + "unknown"
+#endif
+ + "]";
+
+ const string InfoCompilerVersion = "INFO:compiler_version["
+#if PlatformToolsetv100
+ + "2010"
+#elif PlatformToolsetv110
+ + "2012"
+#elif PlatformToolsetv120
+ + "2013"
+#elif PlatformToolsetv140
+ + "2015"
+#elif PlatformToolsetv141
+ + "2017"
+#else
+ + "9999"
+#endif
+ + "]";
+
+ static void Main(string[] args)
+ {
+ // we have to print the lines to make sure
+ // the compiler does not optimize them away ...
+ System.Console.WriteLine(InfoCompiler);
+ System.Console.WriteLine(InfoPlatform);
+ System.Console.WriteLine(InfoArchitecture);
+ System.Console.WriteLine(InfoCompilerVersion);
+ }
+ }
+}
diff --git a/Modules/CMakeCSharpInformation.cmake b/Modules/CMakeCSharpInformation.cmake
new file mode 100644
index 0000000..41cd449
--- /dev/null
+++ b/Modules/CMakeCSharpInformation.cmake
@@ -0,0 +1,67 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This file sets the basic flags for the C# language in CMake.
+# It also loads the available platform file for the system-compiler
+# if it exists.
+
+set(CMAKE_BASE_NAME)
+get_filename_component(CMAKE_BASE_NAME "${CMAKE_CSharp_COMPILER}" NAME_WE)
+
+set(CMAKE_BUILD_TYPE_INIT Debug)
+
+set(CMAKE_CSharp_FLAGS_INIT "/define:TRACE")
+set(CMAKE_CSharp_FLAGS_DEBUG_INIT "/debug:full /optimize- /warn:3 /errorreport:prompt /define:DEBUG")
+set(CMAKE_CSharp_FLAGS_RELEASE_INIT "/debug:none /optimize /warn:1 /errorreport:queue")
+set(CMAKE_CSharp_FLAGS_RELWITHDEBINFO_INIT "/debug:full /optimize-")
+set(CMAKE_CSharp_FLAGS_MINSIZEREL_INIT "/debug:none /optimize")
+set(CMAKE_CSharp_LINKER_SUPPORTS_PDB ON)
+
+set(CMAKE_CSharp_STANDARD_LIBRARIES_INIT "System")
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(CMAKE_CSharp_FLAGS_INIT "/platform:x86 ${CMAKE_CSharp_FLAGS_INIT}")
+else()
+ set(CMAKE_CSharp_FLAGS_INIT "/platform:x64 ${CMAKE_CSharp_FLAGS_INIT}")
+endif()
+
+# This should be included before the _INIT variables are
+# used to initialize the cache. Since the rule variables
+# have if blocks on them, users can still define them here.
+# But, it should still be after the platform file so changes can
+# be made to those values.
+
+# for most systems a module is the same as a shared library
+# so unless the variable CMAKE_MODULE_EXISTS is set just
+# copy the values from the LIBRARY variables
+if(NOT CMAKE_MODULE_EXISTS)
+ set(CMAKE_SHARED_MODULE_CSharp_FLAGS ${CMAKE_SHARED_LIBRARY_CSharp_FLAGS})
+ set(CMAKE_SHARED_MODULE_CREATE_CSharp_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_CSharp_FLAGS})
+endif()
+
+# add the flags to the cache based
+# on the initial values computed in the platform/*.cmake files
+# use _INIT variables so that this only happens the first time
+# and you can set these flags in the cmake cache
+set(CMAKE_CSharp_FLAGS_INIT "$ENV{CSFLAGS} ${CMAKE_CSharp_FLAGS_INIT}")
+
+cmake_initialize_per_config_variable(CMAKE_CSharp_FLAGS "Flags used by the C# compiler")
+
+if(CMAKE_CSharp_STANDARD_LIBRARIES_INIT)
+ set(CMAKE_CSharp_STANDARD_LIBRARIES "${CMAKE_CSharp_STANDARD_LIBRARIES_INIT}"
+ CACHE STRING "Libraries linked by default with all C# applications.")
+ mark_as_advanced(CMAKE_CSharp_STANDARD_LIBRARIES)
+endif()
+
+# set missing flags (if they are not defined). This is needed in the
+# unlikely case that you have only C# and no C/C++ targets in your
+# project.
+cmake_initialize_per_config_variable(CMAKE_EXE_LINKER_FLAGS "Flags used by the linker")
+cmake_initialize_per_config_variable(CMAKE_SHARED_LINKER_FLAGS "Flags used by the linker during the creation of shared libraries")
+
+set(CMAKE_CSharp_CREATE_SHARED_LIBRARY "CSharp_NO_CREATE_SHARED_LIBRARY")
+set(CMAKE_CSharp_CREATE_SHARED_MODULE "CSharp_NO_CREATE_SHARED_MODULE")
+set(CMAKE_CSharp_LINK_EXECUTABLE "CSharp_NO_LINK_EXECUTABLE")
+
+set(CMAKE_CSharp_USE_RESPONSE_FILE_FOR_OBJECTS 1)
+set(CMAKE_CSharp_INFORMATION_LOADED 1)
diff --git a/Modules/CMakeCUDACompiler.cmake.in b/Modules/CMakeCUDACompiler.cmake.in
new file mode 100644
index 0000000..56ae732
--- /dev/null
+++ b/Modules/CMakeCUDACompiler.cmake.in
@@ -0,0 +1,69 @@
+set(CMAKE_CUDA_COMPILER "@CMAKE_CUDA_COMPILER@")
+set(CMAKE_CUDA_HOST_COMPILER "@CMAKE_CUDA_HOST_COMPILER@")
+set(CMAKE_CUDA_HOST_LINK_LAUNCHER "@CMAKE_CUDA_HOST_LINK_LAUNCHER@")
+set(CMAKE_CUDA_COMPILER_ID "@CMAKE_CUDA_COMPILER_ID@")
+set(CMAKE_CUDA_COMPILER_VERSION "@CMAKE_CUDA_COMPILER_VERSION@")
+set(CMAKE_CUDA_DEVICE_LINKER "@CMAKE_CUDA_DEVICE_LINKER@")
+set(CMAKE_CUDA_FATBINARY "@CMAKE_CUDA_FATBINARY@")
+set(CMAKE_CUDA_STANDARD_COMPUTED_DEFAULT "@CMAKE_CUDA_STANDARD_COMPUTED_DEFAULT@")
+set(CMAKE_CUDA_COMPILE_FEATURES "@CMAKE_CUDA_COMPILE_FEATURES@")
+set(CMAKE_CUDA03_COMPILE_FEATURES "@CMAKE_CUDA03_COMPILE_FEATURES@")
+set(CMAKE_CUDA11_COMPILE_FEATURES "@CMAKE_CUDA11_COMPILE_FEATURES@")
+set(CMAKE_CUDA14_COMPILE_FEATURES "@CMAKE_CUDA14_COMPILE_FEATURES@")
+set(CMAKE_CUDA17_COMPILE_FEATURES "@CMAKE_CUDA17_COMPILE_FEATURES@")
+set(CMAKE_CUDA20_COMPILE_FEATURES "@CMAKE_CUDA20_COMPILE_FEATURES@")
+set(CMAKE_CUDA23_COMPILE_FEATURES "@CMAKE_CUDA23_COMPILE_FEATURES@")
+
+set(CMAKE_CUDA_PLATFORM_ID "@CMAKE_CUDA_PLATFORM_ID@")
+set(CMAKE_CUDA_SIMULATE_ID "@CMAKE_CUDA_SIMULATE_ID@")
+set(CMAKE_CUDA_COMPILER_FRONTEND_VARIANT "@CMAKE_CUDA_COMPILER_FRONTEND_VARIANT@")
+set(CMAKE_CUDA_SIMULATE_VERSION "@CMAKE_CUDA_SIMULATE_VERSION@")
+@SET_MSVC_CUDA_ARCHITECTURE_ID@
+@_SET_CMAKE_CUDA_COMPILER_SYSROOT@
+
+set(CMAKE_CUDA_COMPILER_ENV_VAR "CUDACXX")
+set(CMAKE_CUDA_HOST_COMPILER_ENV_VAR "CUDAHOSTCXX")
+
+set(CMAKE_CUDA_COMPILER_LOADED 1)
+set(CMAKE_CUDA_COMPILER_ID_RUN 1)
+set(CMAKE_CUDA_SOURCE_FILE_EXTENSIONS cu)
+set(CMAKE_CUDA_LINKER_PREFERENCE 15)
+set(CMAKE_CUDA_LINKER_PREFERENCE_PROPAGATES 1)
+
+set(CMAKE_CUDA_SIZEOF_DATA_PTR "@CMAKE_CUDA_SIZEOF_DATA_PTR@")
+set(CMAKE_CUDA_COMPILER_ABI "@CMAKE_CUDA_COMPILER_ABI@")
+set(CMAKE_CUDA_BYTE_ORDER "@CMAKE_CUDA_BYTE_ORDER@")
+set(CMAKE_CUDA_LIBRARY_ARCHITECTURE "@CMAKE_CUDA_LIBRARY_ARCHITECTURE@")
+
+if(CMAKE_CUDA_SIZEOF_DATA_PTR)
+ set(CMAKE_SIZEOF_VOID_P "${CMAKE_CUDA_SIZEOF_DATA_PTR}")
+endif()
+
+if(CMAKE_CUDA_COMPILER_ABI)
+ set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_CUDA_COMPILER_ABI}")
+endif()
+
+if(CMAKE_CUDA_LIBRARY_ARCHITECTURE)
+ set(CMAKE_LIBRARY_ARCHITECTURE "@CMAKE_CUDA_LIBRARY_ARCHITECTURE@")
+endif()
+
+set(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "@CMAKE_CUDA_COMPILER_TOOLKIT_ROOT@")
+set(CMAKE_CUDA_COMPILER_TOOLKIT_LIBRARY_ROOT "@CMAKE_CUDA_COMPILER_TOOLKIT_LIBRARY_ROOT@")
+set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "@CMAKE_CUDA_COMPILER_LIBRARY_ROOT@")
+
+set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "@CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES@")
+
+set(CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES "@CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES@")
+set(CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES "@CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES@")
+set(CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@")
+
+set(CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES "@CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES@")
+set(CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES "@CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES@")
+set(CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES "@CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES@")
+set(CMAKE_CUDA_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_CUDA_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@")
+
+@_SET_CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT@
+
+set(CMAKE_LINKER "@CMAKE_LINKER@")
+set(CMAKE_AR "@CMAKE_AR@")
+set(CMAKE_MT "@CMAKE_MT@")
diff --git a/Modules/CMakeCUDACompilerABI.cu b/Modules/CMakeCUDACompilerABI.cu
new file mode 100644
index 0000000..449a079
--- /dev/null
+++ b/Modules/CMakeCUDACompilerABI.cu
@@ -0,0 +1,18 @@
+#ifndef __CUDACC__
+# error "A C or C++ compiler has been selected for CUDA"
+#endif
+
+#include "CMakeCompilerABI.h"
+
+int main(int argc, char* argv[])
+{
+ int require = 0;
+ require += info_sizeof_dptr[argc];
+ require += info_byte_order_big_endian[argc];
+ require += info_byte_order_little_endian[argc];
+#if defined(ABI_ID)
+ require += info_abi[argc];
+#endif
+ (void)argv;
+ return require;
+}
diff --git a/Modules/CMakeCUDACompilerId.cu.in b/Modules/CMakeCUDACompilerId.cu.in
new file mode 100644
index 0000000..91039e5
--- /dev/null
+++ b/Modules/CMakeCUDACompilerId.cu.in
@@ -0,0 +1,54 @@
+#ifndef __CUDACC__
+# error "A C or C++ compiler has been selected for CUDA"
+#endif
+
+@CMAKE_CUDA_COMPILER_ID_CONTENT@
+
+/* Construct the string literal in pieces to prevent the source from
+ getting matched. Store it in a pointer rather than an array
+ because some compilers will just produce instructions to fill the
+ array rather than assigning a pointer to a static array. */
+char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
+#ifdef SIMULATE_ID
+char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
+#endif
+
+@CMAKE_CUDA_COMPILER_ID_PLATFORM_CONTENT@
+@CMAKE_CUDA_COMPILER_ID_ERROR_FOR_TEST@
+
+const char* info_language_dialect_default = "INFO" ":" "dialect_default["
+#if __cplusplus > 202002L
+ "23"
+#elif __cplusplus > 201703L
+ "20"
+#elif __cplusplus >= 201703L
+ "17"
+#elif __cplusplus >= 201402L
+ "14"
+#elif __cplusplus >= 201103L
+ "11"
+#else
+ "03"
+#endif
+"]";
+
+/*--------------------------------------------------------------------------*/
+
+int main(int argc, char* argv[])
+{
+ int require = 0;
+ require += info_compiler[argc];
+ require += info_platform[argc];
+#ifdef COMPILER_VERSION_MAJOR
+ require += info_version[argc];
+#endif
+#ifdef SIMULATE_ID
+ require += info_simulate[argc];
+#endif
+#ifdef SIMULATE_VERSION_MAJOR
+ require += info_simulate_version[argc];
+#endif
+ require += info_language_dialect_default[argc];
+ (void)argv;
+ return require;
+}
diff --git a/Modules/CMakeCUDAInformation.cmake b/Modules/CMakeCUDAInformation.cmake
new file mode 100644
index 0000000..44e2c2c
--- /dev/null
+++ b/Modules/CMakeCUDAInformation.cmake
@@ -0,0 +1,198 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+if(UNIX)
+ set(CMAKE_CUDA_OUTPUT_EXTENSION .o)
+else()
+ set(CMAKE_CUDA_OUTPUT_EXTENSION .obj)
+endif()
+set(CMAKE_INCLUDE_FLAG_CUDA "-I")
+
+# Set implicit links early so compiler-specific modules can use them.
+set(__IMPLICIT_LINKS)
+foreach(dir ${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES})
+ string(APPEND __IMPLICIT_LINKS " -L\"${dir}\"")
+endforeach()
+foreach(lib ${CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES})
+ if(${lib} MATCHES "/")
+ string(APPEND __IMPLICIT_LINKS " \"${lib}\"")
+ else()
+ string(APPEND __IMPLICIT_LINKS " -l${lib}")
+ endif()
+endforeach()
+
+# Load compiler-specific information.
+if(CMAKE_CUDA_COMPILER_ID)
+ include(Compiler/${CMAKE_CUDA_COMPILER_ID}-CUDA OPTIONAL)
+endif()
+
+# load the system- and compiler specific files
+if(CMAKE_CUDA_COMPILER_ID)
+ # load a hardware specific file, mostly useful for embedded compilers
+ if(CMAKE_SYSTEM_PROCESSOR)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_CUDA_COMPILER_ID}-CUDA-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL)
+ endif()
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_CUDA_COMPILER_ID}-CUDA OPTIONAL)
+endif()
+
+
+if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_CUDA_FLAG)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_CUDA_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG})
+endif()
+
+if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_CUDA_FLAG_SEP)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_CUDA_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
+endif()
+
+if(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_CUDA_FLAG)
+ set(CMAKE_SHARED_LIBRARY_RPATH_LINK_CUDA_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG})
+endif()
+
+if(NOT DEFINED CMAKE_EXE_EXPORTS_CUDA_FLAG)
+ set(CMAKE_EXE_EXPORTS_CUDA_FLAG ${CMAKE_EXE_EXPORTS_C_FLAG})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_SONAME_CUDA_FLAG)
+ set(CMAKE_SHARED_LIBRARY_SONAME_CUDA_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_C_FLAG})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RUNTIME_CUDA_FLAG)
+ set(CMAKE_EXECUTABLE_RUNTIME_CUDA_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_CUDA_FLAG})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RUNTIME_CUDA_FLAG_SEP)
+ set(CMAKE_EXECUTABLE_RUNTIME_CUDA_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_CUDA_FLAG_SEP})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RPATH_LINK_CUDA_FLAG)
+ set(CMAKE_EXECUTABLE_RPATH_LINK_CUDA_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_CUDA_FLAG})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_CUDA_WITH_RUNTIME_PATH)
+ set(CMAKE_SHARED_LIBRARY_LINK_CUDA_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH})
+endif()
+
+
+# for most systems a module is the same as a shared library
+# so unless the variable CMAKE_MODULE_EXISTS is set just
+# copy the values from the LIBRARY variables
+if(NOT CMAKE_MODULE_EXISTS)
+ set(CMAKE_SHARED_MODULE_CUDA_FLAGS ${CMAKE_SHARED_LIBRARY_CUDA_FLAGS})
+ set(CMAKE_SHARED_MODULE_CREATE_CUDA_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS})
+endif()
+
+# add the flags to the cache based
+# on the initial values computed in the platform/*.cmake files
+# use _INIT variables so that this only happens the first time
+# and you can set these flags in the cmake cache
+set(CMAKE_CUDA_FLAGS_INIT "$ENV{CUDAFLAGS} ${CMAKE_CUDA_FLAGS_INIT}")
+
+cmake_initialize_per_config_variable(CMAKE_CUDA_FLAGS "Flags used by the CUDA compiler")
+
+if(CMAKE_CUDA_STANDARD_LIBRARIES_INIT)
+ set(CMAKE_CUDA_STANDARD_LIBRARIES "${CMAKE_CUDA_STANDARD_LIBRARIES_INIT}"
+ CACHE STRING "Libraries linked by default with all CUDA applications.")
+ mark_as_advanced(CMAKE_CUDA_STANDARD_LIBRARIES)
+endif()
+
+if(NOT CMAKE_CUDA_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_CUDA_COMPILER_LAUNCHER})
+ set(CMAKE_CUDA_COMPILER_LAUNCHER "$ENV{CMAKE_CUDA_COMPILER_LAUNCHER}"
+ CACHE STRING "Compiler launcher for CUDA.")
+endif()
+
+include(CMakeCommonLanguageInclude)
+
+# now define the following rules:
+# CMAKE_CUDA_CREATE_SHARED_LIBRARY
+# CMAKE_CUDA_CREATE_SHARED_MODULE
+# CMAKE_CUDA_COMPILE_WHOLE_COMPILATION
+# CMAKE_CUDA_COMPILE_PTX_COMPILATION
+# CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION
+# CMAKE_CUDA_LINK_EXECUTABLE
+
+if(CMAKE_CUDA_HOST_COMPILER AND CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
+ # FIXME: This is too late for the Platform/Windows-NVIDIA-CUDA module to
+ # see it, so we do not support CMAKE_CUDA_HOST_COMPILER on Windows.
+ # Move this to Compiler/NVIDIA-CUDA and update the VS generator too.
+ string(APPEND _CMAKE_CUDA_EXTRA_FLAGS " -ccbin=<CMAKE_CUDA_HOST_COMPILER>")
+endif()
+
+# create a shared library
+if(NOT CMAKE_CUDA_CREATE_SHARED_LIBRARY)
+ set(CMAKE_CUDA_CREATE_SHARED_LIBRARY
+ "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
+endif()
+
+# create a shared module copy the shared library rule by default
+if(NOT CMAKE_CUDA_CREATE_SHARED_MODULE)
+ set(CMAKE_CUDA_CREATE_SHARED_MODULE ${CMAKE_CUDA_CREATE_SHARED_LIBRARY})
+endif()
+
+# Create a static archive incrementally for large object file counts.
+if(NOT DEFINED CMAKE_CUDA_ARCHIVE_CREATE)
+ set(CMAKE_CUDA_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_CUDA_ARCHIVE_APPEND)
+ set(CMAKE_CUDA_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_CUDA_ARCHIVE_FINISH)
+ set(CMAKE_CUDA_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
+endif()
+
+#Specify how to compile when ptx has been requested
+if(NOT CMAKE_CUDA_COMPILE_PTX_COMPILATION)
+ set(CMAKE_CUDA_COMPILE_PTX_COMPILATION
+ "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> ${_CMAKE_COMPILE_AS_CUDA_FLAG} ${_CMAKE_CUDA_PTX_FLAG} <SOURCE> -o <OBJECT>")
+endif()
+
+#Specify how to compile when separable compilation has been requested
+if(NOT CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION)
+ set(CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION
+ "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> ${_CMAKE_COMPILE_AS_CUDA_FLAG} ${_CMAKE_CUDA_DEVICE_CODE} <SOURCE> -o <OBJECT>")
+endif()
+
+#Specify how to compile when whole compilation has been requested
+if(NOT CMAKE_CUDA_COMPILE_WHOLE_COMPILATION)
+ set(CMAKE_CUDA_COMPILE_WHOLE_COMPILATION
+ "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> ${_CMAKE_COMPILE_AS_CUDA_FLAG} -c <SOURCE> -o <OBJECT>")
+endif()
+
+# compile a cu file into an executable
+if(NOT CMAKE_CUDA_LINK_EXECUTABLE)
+ set(CMAKE_CUDA_LINK_EXECUTABLE
+ "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
+endif()
+
+# Add implicit host link directories that contain device libraries
+# to the device link line.
+set(__IMPLICIT_DLINK_DIRS ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+if(__IMPLICIT_DLINK_DIRS)
+ list(REMOVE_ITEM __IMPLICIT_DLINK_DIRS ${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES})
+endif()
+set(__IMPLICIT_DLINK_FLAGS)
+foreach(dir ${__IMPLICIT_DLINK_DIRS})
+ if(EXISTS "${dir}/libcurand_static.a")
+ string(APPEND __IMPLICIT_DLINK_FLAGS " -L\"${dir}\"")
+ endif()
+endforeach()
+unset(__IMPLICIT_DLINK_DIRS)
+
+
+#These are used when linking relocatable (dc) cuda code
+if(NOT CMAKE_CUDA_DEVICE_LINK_LIBRARY)
+ set(CMAKE_CUDA_DEVICE_LINK_LIBRARY
+ "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICIT_DLINK_FLAGS}")
+endif()
+if(NOT CMAKE_CUDA_DEVICE_LINK_EXECUTABLE)
+ set(CMAKE_CUDA_DEVICE_LINK_EXECUTABLE
+ "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICIT_DLINK_FLAGS}")
+endif()
+
+# Used when device linking is handled by CMake.
+if(NOT CMAKE_CUDA_DEVICE_LINK_COMPILE)
+ set(CMAKE_CUDA_DEVICE_LINK_COMPILE "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <FLAGS> -D__CUDA_INCLUDE_COMPILER_INTERNAL_HEADERS__ -D__NV_EXTRA_INITIALIZATION=\"\" -D__NV_EXTRA_FINALIZATION=\"\" -DREGISTERLINKBINARYFILE=\\\"<REGISTER_FILE>\\\" -DFATBINFILE=\\\"<FATBINARY>\\\" ${_CMAKE_COMPILE_AS_CUDA_FLAG} -c \"${CMAKE_CUDA_COMPILER_TOOLKIT_LIBRARY_ROOT}/bin/crt/link.stub\" -o <OBJECT>")
+endif()
+
+unset(__IMPLICIT_DLINK_FLAGS)
+
+set(CMAKE_CUDA_INFORMATION_LOADED 1)
diff --git a/Modules/CMakeCXXCompiler.cmake.in b/Modules/CMakeCXXCompiler.cmake.in
new file mode 100644
index 0000000..d0ce77a
--- /dev/null
+++ b/Modules/CMakeCXXCompiler.cmake.in
@@ -0,0 +1,91 @@
+set(CMAKE_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
+set(CMAKE_CXX_COMPILER_ARG1 "@CMAKE_CXX_COMPILER_ARG1@")
+set(CMAKE_CXX_COMPILER_ID "@CMAKE_CXX_COMPILER_ID@")
+set(CMAKE_CXX_COMPILER_VERSION "@CMAKE_CXX_COMPILER_VERSION@")
+set(CMAKE_CXX_COMPILER_VERSION_INTERNAL "@CMAKE_CXX_COMPILER_VERSION_INTERNAL@")
+set(CMAKE_CXX_COMPILER_WRAPPER "@CMAKE_CXX_COMPILER_WRAPPER@")
+set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT "@CMAKE_CXX_STANDARD_COMPUTED_DEFAULT@")
+set(CMAKE_CXX_COMPILE_FEATURES "@CMAKE_CXX_COMPILE_FEATURES@")
+set(CMAKE_CXX98_COMPILE_FEATURES "@CMAKE_CXX98_COMPILE_FEATURES@")
+set(CMAKE_CXX11_COMPILE_FEATURES "@CMAKE_CXX11_COMPILE_FEATURES@")
+set(CMAKE_CXX14_COMPILE_FEATURES "@CMAKE_CXX14_COMPILE_FEATURES@")
+set(CMAKE_CXX17_COMPILE_FEATURES "@CMAKE_CXX17_COMPILE_FEATURES@")
+set(CMAKE_CXX20_COMPILE_FEATURES "@CMAKE_CXX20_COMPILE_FEATURES@")
+set(CMAKE_CXX23_COMPILE_FEATURES "@CMAKE_CXX23_COMPILE_FEATURES@")
+
+set(CMAKE_CXX_PLATFORM_ID "@CMAKE_CXX_PLATFORM_ID@")
+set(CMAKE_CXX_SIMULATE_ID "@CMAKE_CXX_SIMULATE_ID@")
+set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "@CMAKE_CXX_COMPILER_FRONTEND_VARIANT@")
+set(CMAKE_CXX_SIMULATE_VERSION "@CMAKE_CXX_SIMULATE_VERSION@")
+@_SET_CMAKE_CXX_COMPILER_ARCHITECTURE_ID@
+@_SET_CMAKE_CXX_COMPILER_SYSROOT@
+@SET_MSVC_CXX_ARCHITECTURE_ID@
+@SET_CMAKE_XCODE_ARCHS@
+set(CMAKE_AR "@CMAKE_AR@")
+set(CMAKE_CXX_COMPILER_AR "@CMAKE_CXX_COMPILER_AR@")
+set(CMAKE_RANLIB "@CMAKE_RANLIB@")
+set(CMAKE_CXX_COMPILER_RANLIB "@CMAKE_CXX_COMPILER_RANLIB@")
+set(CMAKE_LINKER "@CMAKE_LINKER@")
+set(CMAKE_MT "@CMAKE_MT@")
+set(CMAKE_COMPILER_IS_GNUCXX @CMAKE_COMPILER_IS_GNUCXX@)
+set(CMAKE_CXX_COMPILER_LOADED 1)
+set(CMAKE_CXX_COMPILER_WORKS @CMAKE_CXX_COMPILER_WORKS@)
+set(CMAKE_CXX_ABI_COMPILED @CMAKE_CXX_ABI_COMPILED@)
+set(CMAKE_COMPILER_IS_MINGW @CMAKE_COMPILER_IS_MINGW@)
+set(CMAKE_COMPILER_IS_CYGWIN @CMAKE_COMPILER_IS_CYGWIN@)
+if(CMAKE_COMPILER_IS_CYGWIN)
+ set(CYGWIN 1)
+ set(UNIX 1)
+endif()
+
+set(CMAKE_CXX_COMPILER_ENV_VAR "CXX")
+
+if(CMAKE_COMPILER_IS_MINGW)
+ set(MINGW 1)
+endif()
+set(CMAKE_CXX_COMPILER_ID_RUN 1)
+set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;mpp;CPP;ixx;cppm)
+set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC)
+
+foreach (lang C OBJC OBJCXX)
+ if (CMAKE_${lang}_COMPILER_ID_RUN)
+ foreach(extension IN LISTS CMAKE_${lang}_SOURCE_FILE_EXTENSIONS)
+ list(REMOVE_ITEM CMAKE_CXX_SOURCE_FILE_EXTENSIONS ${extension})
+ endforeach()
+ endif()
+endforeach()
+
+set(CMAKE_CXX_LINKER_PREFERENCE 30)
+set(CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES 1)
+
+# Save compiler ABI information.
+set(CMAKE_CXX_SIZEOF_DATA_PTR "@CMAKE_CXX_SIZEOF_DATA_PTR@")
+set(CMAKE_CXX_COMPILER_ABI "@CMAKE_CXX_COMPILER_ABI@")
+set(CMAKE_CXX_BYTE_ORDER "@CMAKE_CXX_BYTE_ORDER@")
+set(CMAKE_CXX_LIBRARY_ARCHITECTURE "@CMAKE_CXX_LIBRARY_ARCHITECTURE@")
+
+if(CMAKE_CXX_SIZEOF_DATA_PTR)
+ set(CMAKE_SIZEOF_VOID_P "${CMAKE_CXX_SIZEOF_DATA_PTR}")
+endif()
+
+if(CMAKE_CXX_COMPILER_ABI)
+ set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_CXX_COMPILER_ABI}")
+endif()
+
+if(CMAKE_CXX_LIBRARY_ARCHITECTURE)
+ set(CMAKE_LIBRARY_ARCHITECTURE "@CMAKE_CXX_LIBRARY_ARCHITECTURE@")
+endif()
+
+set(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX "@CMAKE_CXX_CL_SHOWINCLUDES_PREFIX@")
+if(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX)
+ set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_CXX_CL_SHOWINCLUDES_PREFIX}")
+endif()
+
+@CMAKE_CXX_COMPILER_CUSTOM_CODE@
+@CMAKE_CXX_SYSROOT_FLAG_CODE@
+@CMAKE_CXX_OSX_DEPLOYMENT_TARGET_FLAG_CODE@
+
+set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "@CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES@")
+set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "@CMAKE_CXX_IMPLICIT_LINK_LIBRARIES@")
+set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "@CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES@")
+set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@")
diff --git a/Modules/CMakeCXXCompilerABI.cpp b/Modules/CMakeCXXCompilerABI.cpp
new file mode 100644
index 0000000..036b96e
--- /dev/null
+++ b/Modules/CMakeCXXCompilerABI.cpp
@@ -0,0 +1,18 @@
+#ifndef __cplusplus
+# error "A C compiler has been selected for C++."
+#endif
+
+#include "CMakeCompilerABI.h"
+
+int main(int argc, char* argv[])
+{
+ int require = 0;
+ require += info_sizeof_dptr[argc];
+ require += info_byte_order_big_endian[argc];
+ require += info_byte_order_little_endian[argc];
+#if defined(ABI_ID)
+ require += info_abi[argc];
+#endif
+ (void)argv;
+ return require;
+}
diff --git a/Modules/CMakeCXXCompilerId.cpp.in b/Modules/CMakeCXXCompilerId.cpp.in
new file mode 100644
index 0000000..a67caba
--- /dev/null
+++ b/Modules/CMakeCXXCompilerId.cpp.in
@@ -0,0 +1,87 @@
+/* This source file must have a .cpp extension so that all C++ compilers
+ recognize the extension without flags. Borland does not know .cxx for
+ example. */
+#ifndef __cplusplus
+# error "A C compiler has been selected for C++."
+#endif
+
+@CMAKE_CXX_COMPILER_ID_CONTENT@
+
+/* Construct the string literal in pieces to prevent the source from
+ getting matched. Store it in a pointer rather than an array
+ because some compilers will just produce instructions to fill the
+ array rather than assigning a pointer to a static array. */
+char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
+#ifdef SIMULATE_ID
+char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
+#endif
+
+#ifdef __QNXNTO__
+char const* qnxnto = "INFO" ":" "qnxnto[]";
+#endif
+
+#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
+char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
+#endif
+
+@CMAKE_CXX_COMPILER_ID_PLATFORM_CONTENT@
+@CMAKE_CXX_COMPILER_ID_ERROR_FOR_TEST@
+
+#if defined(__INTEL_COMPILER) && defined(_MSVC_LANG) && _MSVC_LANG < 201403L
+# if defined(__INTEL_CXX11_MODE__)
+# if defined(__cpp_aggregate_nsdmi)
+# define CXX_STD 201402L
+# else
+# define CXX_STD 201103L
+# endif
+# else
+# define CXX_STD 199711L
+# endif
+#elif defined(_MSC_VER) && defined(_MSVC_LANG)
+# define CXX_STD _MSVC_LANG
+#else
+# define CXX_STD __cplusplus
+#endif
+
+const char* info_language_dialect_default = "INFO" ":" "dialect_default["
+#if CXX_STD > 202002L
+ "23"
+#elif CXX_STD > 201703L
+ "20"
+#elif CXX_STD >= 201703L
+ "17"
+#elif CXX_STD >= 201402L
+ "14"
+#elif CXX_STD >= 201103L
+ "11"
+#else
+ "98"
+#endif
+"]";
+
+/*--------------------------------------------------------------------------*/
+
+int main(int argc, char* argv[])
+{
+ int require = 0;
+ require += info_compiler[argc];
+ require += info_platform[argc];
+#ifdef COMPILER_VERSION_MAJOR
+ require += info_version[argc];
+#endif
+#ifdef COMPILER_VERSION_INTERNAL
+ require += info_version_internal[argc];
+#endif
+#ifdef SIMULATE_ID
+ require += info_simulate[argc];
+#endif
+#ifdef SIMULATE_VERSION_MAJOR
+ require += info_simulate_version[argc];
+#endif
+#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
+ require += info_cray[argc];
+#endif
+ require += info_language_dialect_default[argc];
+ (void)argv;
+ return require;
+}
diff --git a/Modules/CMakeCXXInformation.cmake b/Modules/CMakeCXXInformation.cmake
new file mode 100644
index 0000000..dbb4366
--- /dev/null
+++ b/Modules/CMakeCXXInformation.cmake
@@ -0,0 +1,282 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file sets the basic flags for the C++ language in CMake.
+# It also loads the available platform file for the system-compiler
+# if it exists.
+# It also loads a system - compiler - processor (or target hardware)
+# specific file, which is mainly useful for crosscompiling and embedded systems.
+
+include(CMakeLanguageInformation)
+
+# some compilers use different extensions (e.g. sdcc uses .rel)
+# so set the extension here first so it can be overridden by the compiler specific file
+if(UNIX)
+ set(CMAKE_CXX_OUTPUT_EXTENSION .o)
+else()
+ set(CMAKE_CXX_OUTPUT_EXTENSION .obj)
+endif()
+
+set(_INCLUDED_FILE 0)
+
+# Load compiler-specific information.
+if(CMAKE_CXX_COMPILER_ID)
+ include(Compiler/${CMAKE_CXX_COMPILER_ID}-CXX OPTIONAL)
+endif()
+
+set(CMAKE_BASE_NAME)
+get_filename_component(CMAKE_BASE_NAME "${CMAKE_CXX_COMPILER}" NAME_WE)
+# since the gnu compiler has several names force g++
+if(CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_BASE_NAME g++)
+endif()
+
+
+# load a hardware specific file, mostly useful for embedded compilers
+if(CMAKE_SYSTEM_PROCESSOR)
+ if(CMAKE_CXX_COMPILER_ID)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_CXX_COMPILER_ID}-CXX-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
+ endif()
+ if (NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME}-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL)
+ endif ()
+endif()
+
+# load the system- and compiler specific files
+if(CMAKE_CXX_COMPILER_ID)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_CXX_COMPILER_ID}-CXX OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
+endif()
+if (NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME} OPTIONAL
+ RESULT_VARIABLE _INCLUDED_FILE)
+endif ()
+
+# load any compiler-wrapper specific information
+if (CMAKE_CXX_COMPILER_WRAPPER)
+ __cmake_include_compiler_wrapper(CXX)
+endif ()
+
+# We specify the compiler information in the system file for some
+# platforms, but this language may not have been enabled when the file
+# was first included. Include it again to get the language info.
+# Remove this when all compiler info is removed from system files.
+if (NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_SYSTEM_NAME} OPTIONAL)
+endif ()
+
+if(CMAKE_CXX_SIZEOF_DATA_PTR)
+ foreach(f ${CMAKE_CXX_ABI_FILES})
+ include(${f})
+ endforeach()
+ unset(CMAKE_CXX_ABI_FILES)
+endif()
+
+# This should be included before the _INIT variables are
+# used to initialize the cache. Since the rule variables
+# have if blocks on them, users can still define them here.
+# But, it should still be after the platform file so changes can
+# be made to those values.
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE "${_override}")
+endif()
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE_CXX} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX "${_override}")
+endif()
+
+
+# Create a set of shared library variable specific to C++
+# For 90% of the systems, these are the same flags as the C versions
+# so if these are not set just copy the flags from the c version
+if(NOT CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS)
+ set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS})
+endif()
+
+if(NOT CMAKE_CXX_COMPILE_OPTIONS_PIC)
+ set(CMAKE_CXX_COMPILE_OPTIONS_PIC ${CMAKE_C_COMPILE_OPTIONS_PIC})
+endif()
+
+if(NOT CMAKE_CXX_COMPILE_OPTIONS_PIE)
+ set(CMAKE_CXX_COMPILE_OPTIONS_PIE ${CMAKE_C_COMPILE_OPTIONS_PIE})
+endif()
+if(NOT CMAKE_CXX_LINK_OPTIONS_PIE)
+ set(CMAKE_CXX_LINK_OPTIONS_PIE ${CMAKE_C_LINK_OPTIONS_PIE})
+endif()
+if(NOT CMAKE_CXX_LINK_OPTIONS_NO_PIE)
+ set(CMAKE_CXX_LINK_OPTIONS_NO_PIE ${CMAKE_C_LINK_OPTIONS_NO_PIE})
+endif()
+
+if(NOT CMAKE_CXX_COMPILE_OPTIONS_DLL)
+ set(CMAKE_CXX_COMPILE_OPTIONS_DLL ${CMAKE_C_COMPILE_OPTIONS_DLL})
+endif()
+
+if(NOT CMAKE_SHARED_LIBRARY_CXX_FLAGS)
+ set(CMAKE_SHARED_LIBRARY_CXX_FLAGS ${CMAKE_SHARED_LIBRARY_C_FLAGS})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
+ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS ${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS})
+endif()
+
+if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG})
+endif()
+
+if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
+endif()
+
+if(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG)
+ set(CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG})
+endif()
+
+if(NOT DEFINED CMAKE_EXE_EXPORTS_CXX_FLAG)
+ set(CMAKE_EXE_EXPORTS_CXX_FLAG ${CMAKE_EXE_EXPORTS_C_FLAG})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG)
+ set(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_C_FLAG})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG)
+ set(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG_SEP)
+ set(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RPATH_LINK_CXX_FLAG)
+ set(CMAKE_EXECUTABLE_RPATH_LINK_CXX_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_CXX_WITH_RUNTIME_PATH)
+ set(CMAKE_SHARED_LIBRARY_LINK_CXX_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH})
+endif()
+
+if(NOT CMAKE_INCLUDE_FLAG_CXX)
+ set(CMAKE_INCLUDE_FLAG_CXX ${CMAKE_INCLUDE_FLAG_C})
+endif()
+
+# for most systems a module is the same as a shared library
+# so unless the variable CMAKE_MODULE_EXISTS is set just
+# copy the values from the LIBRARY variables
+if(NOT CMAKE_MODULE_EXISTS)
+ set(CMAKE_SHARED_MODULE_CXX_FLAGS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS})
+ set(CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS})
+endif()
+
+# repeat for modules
+if(NOT CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS)
+ set(CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS ${CMAKE_SHARED_MODULE_CREATE_C_FLAGS})
+endif()
+
+if(NOT CMAKE_SHARED_MODULE_CXX_FLAGS)
+ set(CMAKE_SHARED_MODULE_CXX_FLAGS ${CMAKE_SHARED_MODULE_C_FLAGS})
+endif()
+
+# Initialize CXX link type selection flags from C versions.
+foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+ if(NOT CMAKE_${type}_LINK_STATIC_CXX_FLAGS)
+ set(CMAKE_${type}_LINK_STATIC_CXX_FLAGS
+ ${CMAKE_${type}_LINK_STATIC_C_FLAGS})
+ endif()
+ if(NOT CMAKE_${type}_LINK_DYNAMIC_CXX_FLAGS)
+ set(CMAKE_${type}_LINK_DYNAMIC_CXX_FLAGS
+ ${CMAKE_${type}_LINK_DYNAMIC_C_FLAGS})
+ endif()
+endforeach()
+
+# add the flags to the cache based
+# on the initial values computed in the platform/*.cmake files
+# use _INIT variables so that this only happens the first time
+# and you can set these flags in the cmake cache
+set(CMAKE_CXX_FLAGS_INIT "$ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS_INIT}")
+
+cmake_initialize_per_config_variable(CMAKE_CXX_FLAGS "Flags used by the CXX compiler")
+
+if(CMAKE_CXX_STANDARD_LIBRARIES_INIT)
+ set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES_INIT}"
+ CACHE STRING "Libraries linked by default with all C++ applications.")
+ mark_as_advanced(CMAKE_CXX_STANDARD_LIBRARIES)
+endif()
+
+if(NOT CMAKE_CXX_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_CXX_COMPILER_LAUNCHER})
+ set(CMAKE_CXX_COMPILER_LAUNCHER "$ENV{CMAKE_CXX_COMPILER_LAUNCHER}"
+ CACHE STRING "Compiler launcher for CXX.")
+endif()
+
+include(CMakeCommonLanguageInclude)
+
+# now define the following rules:
+# CMAKE_CXX_CREATE_SHARED_LIBRARY
+# CMAKE_CXX_CREATE_SHARED_MODULE
+# CMAKE_CXX_COMPILE_OBJECT
+# CMAKE_CXX_LINK_EXECUTABLE
+
+# variables supplied by the generator at use time
+# <TARGET>
+# <TARGET_BASE> the target without the suffix
+# <OBJECTS>
+# <OBJECT>
+# <LINK_LIBRARIES>
+# <FLAGS>
+# <LINK_FLAGS>
+
+# CXX compiler information
+# <CMAKE_CXX_COMPILER>
+# <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS>
+# <CMAKE_CXX_SHARED_MODULE_CREATE_FLAGS>
+# <CMAKE_CXX_LINK_FLAGS>
+
+# Static library tools
+# <CMAKE_AR>
+# <CMAKE_RANLIB>
+
+
+# create a shared C++ library
+if(NOT CMAKE_CXX_CREATE_SHARED_LIBRARY)
+ set(CMAKE_CXX_CREATE_SHARED_LIBRARY
+ "<CMAKE_CXX_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
+endif()
+
+# create a c++ shared module copy the shared library rule by default
+if(NOT CMAKE_CXX_CREATE_SHARED_MODULE)
+ set(CMAKE_CXX_CREATE_SHARED_MODULE ${CMAKE_CXX_CREATE_SHARED_LIBRARY})
+endif()
+
+
+# Create a static archive incrementally for large object file counts.
+# If CMAKE_CXX_CREATE_STATIC_LIBRARY is set it will override these.
+if(NOT DEFINED CMAKE_CXX_ARCHIVE_CREATE)
+ set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_CXX_ARCHIVE_APPEND)
+ set(CMAKE_CXX_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_CXX_ARCHIVE_FINISH)
+ set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
+endif()
+
+# compile a C++ file into an object file
+if(NOT CMAKE_CXX_COMPILE_OBJECT)
+ set(CMAKE_CXX_COMPILE_OBJECT
+ "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+endif()
+
+if(NOT CMAKE_CXX_LINK_EXECUTABLE)
+ set(CMAKE_CXX_LINK_EXECUTABLE
+ "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+endif()
+
+mark_as_advanced(
+CMAKE_VERBOSE_MAKEFILE
+)
+
+set(CMAKE_CXX_INFORMATION_LOADED 1)
diff --git a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
new file mode 100644
index 0000000..05174de
--- /dev/null
+++ b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
@@ -0,0 +1,36 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# Do NOT include this module directly into any of your code. It is meant as
+# a library for Check*CompilerFlag.cmake modules. It's content may change in
+# any way between releases.
+
+macro (CHECK_COMPILER_FLAG_COMMON_PATTERNS _VAR)
+ set(${_VAR}
+ FAIL_REGEX "[Uu]nrecogni[sz]ed .*option" # GNU, NAG, Fujitsu
+ FAIL_REGEX "switch .* is no longer supported" # GNU
+ FAIL_REGEX "unknown .*option" # Clang
+ FAIL_REGEX "optimization flag .* not supported" # Clang
+ FAIL_REGEX "unknown argument ignored" # Clang (cl)
+ FAIL_REGEX "ignoring unknown option" # MSVC, Intel
+ FAIL_REGEX "warning D9002" # MSVC, any lang
+ FAIL_REGEX "option.*not supported" # Intel
+ FAIL_REGEX "invalid argument .*option" # Intel
+ FAIL_REGEX "ignoring option .*argument required" # Intel
+ FAIL_REGEX "ignoring option .*argument is of wrong type" # Intel
+ FAIL_REGEX "[Uu]nknown option" # HP
+ FAIL_REGEX "[Ww]arning: [Oo]ption" # SunPro
+ FAIL_REGEX "command option .* is not recognized" # XL
+ FAIL_REGEX "command option .* contains an incorrect subargument" # XL
+ FAIL_REGEX "Option .* is not recognized. Option will be ignored." # XL
+ FAIL_REGEX "not supported in this configuration. ignored" # AIX
+ FAIL_REGEX "File with unknown suffix passed to linker" # PGI
+ FAIL_REGEX "[Uu]nknown switch" # PGI
+ FAIL_REGEX "WARNING: unknown flag:" # Open64
+ FAIL_REGEX "Incorrect command line option:" # Borland
+ FAIL_REGEX "Warning: illegal option" # SunStudio 12
+ FAIL_REGEX "[Ww]arning: Invalid suboption" # Fujitsu
+ FAIL_REGEX "An invalid option .* appears on the command line" # Cray
+ )
+endmacro ()
diff --git a/Modules/CMakeCommonLanguageInclude.cmake b/Modules/CMakeCommonLanguageInclude.cmake
new file mode 100644
index 0000000..b043e18
--- /dev/null
+++ b/Modules/CMakeCommonLanguageInclude.cmake
@@ -0,0 +1,23 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# this file has flags that are shared across languages and sets
+# cache values that can be initialized in the platform-compiler.cmake file
+# it may be included by more than one language.
+
+string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " $ENV{LDFLAGS}")
+string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " $ENV{LDFLAGS}")
+string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " $ENV{LDFLAGS}")
+
+cmake_initialize_per_config_variable(CMAKE_EXE_LINKER_FLAGS "Flags used by the linker")
+cmake_initialize_per_config_variable(CMAKE_SHARED_LINKER_FLAGS "Flags used by the linker during the creation of shared libraries")
+cmake_initialize_per_config_variable(CMAKE_MODULE_LINKER_FLAGS "Flags used by the linker during the creation of modules")
+cmake_initialize_per_config_variable(CMAKE_STATIC_LINKER_FLAGS "Flags used by the linker during the creation of static libraries")
+
+# Alias the build tool variable for backward compatibility.
+set(CMAKE_BUILD_TOOL ${CMAKE_MAKE_PROGRAM})
+
+mark_as_advanced(
+CMAKE_VERBOSE_MAKEFILE
+)
diff --git a/Modules/CMakeCompilerABI.h b/Modules/CMakeCompilerABI.h
new file mode 100644
index 0000000..c5ce4dd
--- /dev/null
+++ b/Modules/CMakeCompilerABI.h
@@ -0,0 +1,45 @@
+
+/* Size of a pointer-to-data in bytes. */
+#define SIZEOF_DPTR (sizeof(void*))
+const char info_sizeof_dptr[] = {
+ /* clang-format off */
+ 'I', 'N', 'F', 'O', ':', 's', 'i', 'z', 'e', 'o', 'f', '_', 'd', 'p', 't',
+ 'r', '[', ('0' + ((SIZEOF_DPTR / 10) % 10)), ('0' + (SIZEOF_DPTR % 10)), ']',
+ '\0'
+ /* clang-format on */
+};
+
+/* Byte order. Only one of these will have bytes in the right order. */
+static unsigned short const info_byte_order_big_endian[] = {
+ /* INFO:byte_order string for BIG_ENDIAN */
+ 0x494E, 0x464F, 0x3A62, 0x7974, 0x655F, 0x6F72, 0x6465, 0x725B,
+ 0x4249, 0x475F, 0x454E, 0x4449, 0x414E, 0x5D00, 0x0000
+};
+static unsigned short const info_byte_order_little_endian[] = {
+ /* INFO:byte_order string for LITTLE_ENDIAN */
+ 0x4E49, 0x4F46, 0x623A, 0x7479, 0x5F65, 0x726F, 0x6564, 0x5B72,
+ 0x494C, 0x5454, 0x454C, 0x455F, 0x444E, 0x4149, 0x5D4E, 0x0000
+};
+
+/* Application Binary Interface. */
+
+/* Check for (some) ARM ABIs.
+ * See e.g. http://wiki.debian.org/ArmEabiPort for some information on this. */
+#if defined(__GNU__) && defined(__ELF__) && defined(__ARM_EABI__)
+# define ABI_ID "ELF ARMEABI"
+#elif defined(__GNU__) && defined(__ELF__) && defined(__ARMEB__)
+# define ABI_ID "ELF ARM"
+#elif defined(__GNU__) && defined(__ELF__) && defined(__ARMEL__)
+# define ABI_ID "ELF ARM"
+
+#elif defined(__linux__) && defined(__ELF__) && defined(__amd64__) && \
+ defined(__ILP32__)
+# define ABI_ID "ELF X32"
+
+#elif defined(__ELF__)
+# define ABI_ID "ELF"
+#endif
+
+#if defined(ABI_ID)
+static char const info_abi[] = "INFO:abi[" ABI_ID "]";
+#endif
diff --git a/Modules/CMakeCompilerIdDetection.cmake b/Modules/CMakeCompilerIdDetection.cmake
new file mode 100644
index 0000000..c79d423
--- /dev/null
+++ b/Modules/CMakeCompilerIdDetection.cmake
@@ -0,0 +1,155 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+function(_readFile file)
+ include(${file})
+ get_filename_component(name ${file} NAME_WE)
+ string(REGEX REPLACE "-.*" "" CompilerId ${name})
+ set(_compiler_id_version_compute_${CompilerId} ${_compiler_id_version_compute} PARENT_SCOPE)
+ set(_compiler_id_simulate_${CompilerId} ${_compiler_id_simulate} PARENT_SCOPE)
+ set(_compiler_id_pp_test_${CompilerId} ${_compiler_id_pp_test} PARENT_SCOPE)
+endfunction()
+
+function(compiler_id_detection outvar lang)
+
+ if (NOT lang STREQUAL Fortran AND NOT lang STREQUAL CSharp
+ AND NOT lang STREQUAL ISPC)
+ file(GLOB lang_files
+ "${CMAKE_ROOT}/Modules/Compiler/*-DetermineCompiler.cmake")
+ set(nonlang CXX)
+ if (lang STREQUAL CXX)
+ set(nonlang C)
+ endif()
+
+ file(GLOB nonlang_files
+ "${CMAKE_ROOT}/Modules/Compiler/*-${nonlang}-DetermineCompiler.cmake")
+ list(REMOVE_ITEM lang_files ${nonlang_files})
+ endif()
+
+ set(files ${lang_files})
+ if (files)
+ foreach(file ${files})
+ _readFile(${file})
+ endforeach()
+
+ set(options ID_STRING VERSION_STRINGS ID_DEFINE PLATFORM_DEFAULT_COMPILER)
+ set(oneValueArgs PREFIX)
+ cmake_parse_arguments(CID "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+ if (CID_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unrecognized arguments: \"${CID_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ # Order is relevant here. For example, compilers which pretend to be
+ # GCC must appear before the actual GCC.
+ if (lang STREQUAL CXX)
+ list(APPEND ordered_compilers
+ Comeau
+ )
+ endif()
+ list(APPEND ordered_compilers
+ Intel
+ IntelLLVM
+ PathScale
+ Embarcadero
+ Borland
+ Watcom
+ OpenWatcom
+ SunPro
+ HP
+ Compaq
+ zOS
+ XLClang
+ XL
+ VisualAge
+ NVHPC
+ PGI
+ Cray
+ TI
+ FujitsuClang
+ Fujitsu
+ GHS
+ )
+ if (lang STREQUAL C)
+ list(APPEND ordered_compilers
+ TinyCC
+ Bruce
+ )
+ endif()
+ list(APPEND ordered_compilers
+ SCO
+ ARMCC
+ AppleClang
+ ARMClang
+ Clang
+ GNU
+ MSVC
+ ADSP
+ IAR
+ )
+ if (lang STREQUAL C)
+ list(APPEND ordered_compilers
+ SDCC
+ )
+ endif()
+
+ if(lang STREQUAL CUDA)
+ set(ordered_compilers NVIDIA Clang)
+ endif()
+
+ if(CID_ID_DEFINE)
+ foreach(Id ${ordered_compilers})
+ string(APPEND CMAKE_${lang}_COMPILER_ID_CONTENT "# define ${CID_PREFIX}COMPILER_IS_${Id} 0\n")
+ endforeach()
+ # Hard-code definitions for compilers that are no longer supported.
+ string(APPEND CMAKE_${lang}_COMPILER_ID_CONTENT "# define ${CID_PREFIX}COMPILER_IS_MIPSpro 0\n")
+ endif()
+
+ set(pp_if "#if")
+ if (CID_VERSION_STRINGS)
+ string(APPEND CMAKE_${lang}_COMPILER_ID_CONTENT "\n/* Version number components: V=Version, R=Revision, P=Patch
+ Version date components: YYYY=Year, MM=Month, DD=Day */\n")
+ endif()
+
+ foreach(Id ${ordered_compilers})
+ if (NOT _compiler_id_pp_test_${Id})
+ message(FATAL_ERROR "No preprocessor test for \"${Id}\"")
+ endif()
+ set(id_content "${pp_if} ${_compiler_id_pp_test_${Id}}\n")
+ if (CID_ID_STRING)
+ set(PREFIX ${CID_PREFIX})
+ string(CONFIGURE "${_compiler_id_simulate_${Id}}" SIMULATE_BLOCK @ONLY)
+ string(APPEND id_content "# define ${CID_PREFIX}COMPILER_ID \"${Id}\"${SIMULATE_BLOCK}")
+ endif()
+ if (CID_ID_DEFINE)
+ string(APPEND id_content "# undef ${CID_PREFIX}COMPILER_IS_${Id}\n")
+ string(APPEND id_content "# define ${CID_PREFIX}COMPILER_IS_${Id} 1\n")
+ endif()
+ if (CID_VERSION_STRINGS)
+ set(PREFIX ${CID_PREFIX})
+ set(MACRO_DEC DEC)
+ set(MACRO_HEX HEX)
+ string(CONFIGURE "${_compiler_id_version_compute_${Id}}" VERSION_BLOCK @ONLY)
+ string(APPEND id_content "${VERSION_BLOCK}\n")
+ endif()
+ string(APPEND CMAKE_${lang}_COMPILER_ID_CONTENT "\n${id_content}")
+ set(pp_if "#elif")
+ endforeach()
+
+ if (CID_PLATFORM_DEFAULT_COMPILER)
+ set(platform_compiler_detection "
+/* These compilers are either not known or too old to define an
+ identification macro. Try to identify the platform and guess that
+ it is the native compiler. */
+#elif defined(__hpux) || defined(__hpua)
+# define ${CID_PREFIX}COMPILER_ID \"HP\"
+
+#else /* unknown compiler */
+# define ${CID_PREFIX}COMPILER_ID \"\"")
+ endif()
+
+ string(APPEND CMAKE_${lang}_COMPILER_ID_CONTENT "\n${platform_compiler_detection}\n#endif")
+ endif()
+
+ set(${outvar} ${CMAKE_${lang}_COMPILER_ID_CONTENT} PARENT_SCOPE)
+endfunction()
diff --git a/Modules/CMakeConfigurableFile.in b/Modules/CMakeConfigurableFile.in
new file mode 100644
index 0000000..df2c382
--- /dev/null
+++ b/Modules/CMakeConfigurableFile.in
@@ -0,0 +1 @@
+@CMAKE_CONFIGURABLE_FILE_CONTENT@
diff --git a/Modules/CMakeDependentOption.cmake b/Modules/CMakeDependentOption.cmake
new file mode 100644
index 0000000..96855d2
--- /dev/null
+++ b/Modules/CMakeDependentOption.cmake
@@ -0,0 +1,64 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CMakeDependentOption
+--------------------
+
+Macro to provide an option dependent on other options.
+
+This macro presents an option to the user only if a set of other
+conditions are true.
+
+Usage:
+
+.. code-block:: cmake
+
+ cmake_dependent_option(<option> "<help_text>" <value> <depends> <force>)
+
+Where ``<option>`` is available to the user if ``<depends>`` is true. When
+``<option>`` is available, the given ``<help_text>`` and initial ``<value>``
+are used. If the ``<depends>`` condition is not true, ``<option>`` will not be
+presented and will always have the value given by ``<force>``. Any value set by
+the user is preserved for when the option is presented again. Each element in
+the fourth parameter is evaluated as an if-condition, so
+:ref:`Condition Syntax` can be used.
+
+Example invocation:
+
+.. code-block:: cmake
+
+ cmake_dependent_option(USE_FOO "Use Foo" ON
+ "USE_BAR;NOT USE_ZOT" OFF)
+
+If ``USE_BAR`` is true and ``USE_ZOT`` is false, this provides an option called
+``USE_FOO`` that defaults to ON. Otherwise, it sets ``USE_FOO`` to OFF and
+hides the option from the user. If the status of ``USE_BAR`` or ``USE_ZOT``
+ever changes, any value for the ``USE_FOO`` option is saved so that when the
+option is re-enabled it retains its old value.
+#]=======================================================================]
+
+macro(CMAKE_DEPENDENT_OPTION option doc default depends force)
+ if(${option}_ISSET MATCHES "^${option}_ISSET$")
+ set(${option}_AVAILABLE 1)
+ foreach(d ${depends})
+ string(REGEX REPLACE " +" ";" CMAKE_DEPENDENT_OPTION_DEP "${d}")
+ if(${CMAKE_DEPENDENT_OPTION_DEP})
+ else()
+ set(${option}_AVAILABLE 0)
+ endif()
+ endforeach()
+ if(${option}_AVAILABLE)
+ option(${option} "${doc}" "${default}")
+ set(${option} "${${option}}" CACHE BOOL "${doc}" FORCE)
+ else()
+ if(${option} MATCHES "^${option}$")
+ else()
+ set(${option} "${${option}}" CACHE INTERNAL "${doc}")
+ endif()
+ set(${option} ${force})
+ endif()
+ else()
+ set(${option} "${${option}_ISSET}")
+ endif()
+endmacro()
diff --git a/Modules/CMakeDetermineASM-ATTCompiler.cmake b/Modules/CMakeDetermineASM-ATTCompiler.cmake
new file mode 100644
index 0000000..a2efb6a
--- /dev/null
+++ b/Modules/CMakeDetermineASM-ATTCompiler.cmake
@@ -0,0 +1,10 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# determine the compiler to use for ASM using AT&T syntax, e.g. GNU as
+
+set(ASM_DIALECT "-ATT")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILER_LIST ${_CMAKE_TOOLCHAIN_PREFIX}gas ${_CMAKE_TOOLCHAIN_PREFIX}as)
+include(CMakeDetermineASMCompiler)
+set(ASM_DIALECT)
diff --git a/Modules/CMakeDetermineASMCompiler.cmake b/Modules/CMakeDetermineASMCompiler.cmake
new file mode 100644
index 0000000..e8b9db7
--- /dev/null
+++ b/Modules/CMakeDetermineASMCompiler.cmake
@@ -0,0 +1,257 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# determine the compiler to use for ASM programs
+
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
+
+if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER)
+ # prefer the environment variable ASM
+ if(NOT $ENV{ASM${ASM_DIALECT}} STREQUAL "")
+ get_filename_component(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT $ENV{ASM${ASM_DIALECT}} PROGRAM PROGRAM_ARGS CMAKE_ASM${ASM_DIALECT}_FLAGS_ENV_INIT)
+ if(CMAKE_ASM${ASM_DIALECT}_FLAGS_ENV_INIT)
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ARG1 "${CMAKE_ASM${ASM_DIALECT}_FLAGS_ENV_INIT}" CACHE STRING "Arguments to ASM${ASM_DIALECT} compiler")
+ endif()
+ if(NOT EXISTS ${CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT})
+ message(FATAL_ERROR "Could not find compiler set in environment variable ASM${ASM_DIALECT}:\n$ENV{ASM${ASM_DIALECT}}.")
+ endif()
+ endif()
+
+ # finally list compilers to try
+ if("ASM${ASM_DIALECT}" STREQUAL "ASM") # the generic assembler support
+ if(NOT CMAKE_ASM_COMPILER_INIT)
+ if(CMAKE_C_COMPILER)
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_LIST ${CMAKE_C_COMPILER})
+ elseif(CMAKE_CXX_COMPILER)
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_LIST ${CMAKE_CXX_COMPILER})
+ else()
+ # List all default C and CXX compilers
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_LIST
+ ${_CMAKE_TOOLCHAIN_PREFIX}cc ${_CMAKE_TOOLCHAIN_PREFIX}gcc cl bcc xlc
+ CC ${_CMAKE_TOOLCHAIN_PREFIX}c++ ${_CMAKE_TOOLCHAIN_PREFIX}g++ aCC cl bcc xlC)
+ endif()
+ endif()
+ else() # some specific assembler "dialect"
+ if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT AND NOT CMAKE_ASM${ASM_DIALECT}_COMPILER_LIST)
+ message(FATAL_ERROR "CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT or CMAKE_ASM${ASM_DIALECT}_COMPILER_LIST must be preset !")
+ endif()
+ endif()
+
+ # Find the compiler.
+ _cmake_find_compiler(ASM${ASM_DIALECT})
+
+else()
+ _cmake_find_compiler_path(ASM${ASM_DIALECT})
+endif()
+mark_as_advanced(CMAKE_ASM${ASM_DIALECT}_COMPILER)
+
+if (NOT _CMAKE_TOOLCHAIN_LOCATION)
+ get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_ASM${ASM_DIALECT}_COMPILER}" PATH)
+endif ()
+
+
+if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
+
+ # Table of per-vendor compiler id flags with expected output.
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS GNU )
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_GNU "--version")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_GNU "(GNU assembler)|(GCC)|(Free Software Foundation)")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS Clang )
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_Clang "--version")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_Clang "(clang version)")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS AppleClang )
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_AppleClang "--version")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_AppleClang "(Apple LLVM version)")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS ARMClang )
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_ARMClang "--version")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_ARMClang "armclang")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS HP )
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_HP "-V")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_HP "HP C")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS Intel )
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_Intel "--version")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_Intel "(ICC)")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS IntelLLVM )
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_IntelLLVM "--version")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_IntelLLVM "(Intel[^\n]+oneAPI)")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS SunPro )
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_SunPro "-V")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_SunPro "Sun C")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS XL )
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_XL "-qversion")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_XL "XL C")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS MSVC )
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_MSVC "-?")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_MSVC "Microsoft")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS TI )
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_TI "-h")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_TI "Texas Instruments")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS IAR)
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_IAR )
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_IAR "IAR Assembler")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS ARMCC)
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_ARMCC )
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_ARMCC "(ARM Compiler)|(ARM Assembler)")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS NASM)
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_NASM "-v")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_NASM "(NASM version)")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS YASM)
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_YASM "--version")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_YASM "(yasm)")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS ADSP)
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_ADSP "-version")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_ADSP "Analog Devices")
+
+ list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS QCC)
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_QCC "-V")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_QCC "gcc_nto")
+
+ include(CMakeDetermineCompilerId)
+ set(userflags)
+ CMAKE_DETERMINE_COMPILER_ID_VENDOR(ASM${ASM_DIALECT} "${userflags}")
+ if("x${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}" STREQUAL "xIAR")
+ # primary necessary to detect architecture, so the right archiver and linker can be picked
+ # eg. "IAR Assembler V8.10.1.12857/W32 for ARM" or "IAR Assembler V4.11.1.4666 for Renesas RX"
+ # Cut out identification first, newline handling is a pain
+ string(REGEX MATCH "IAR Assembler[^\r\n]*" _compileid "${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_OUTPUT}")
+ if("${_compileid}" MATCHES "V([0-9]+\\.[0-9]+\\.[0-9]+)")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_VERSION ${CMAKE_MATCH_1})
+ endif()
+ string(REGEX MATCHALL "([A-Za-z0-9-]+)" _all_compileid_matches "${_compileid}")
+ if(_all_compileid_matches)
+ list(GET _all_compileid_matches "-1" CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID)
+ endif()
+ endif()
+
+ _cmake_find_compiler_sysroot(ASM${ASM_DIALECT})
+
+ unset(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_OUTPUT)
+ unset(_all_compileid_matches)
+ unset(_compileid)
+endif()
+
+if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
+ if(CMAKE_ASM${ASM_DIALECT}_COMPILER_VERSION)
+ set(_version " ${CMAKE_ASM${ASM_DIALECT}_COMPILER_VERSION}")
+ else()
+ set(_version "")
+ endif()
+ if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID AND "x${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}" STREQUAL "xIAR")
+ set(_archid " ${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}")
+ else()
+ set(_archid "")
+ endif()
+ message(STATUS "The ASM${ASM_DIALECT} compiler identification is ${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}${_archid}${_version}")
+ unset(_archid)
+ unset(_version)
+else()
+ message(STATUS "The ASM${ASM_DIALECT} compiler identification is unknown")
+endif()
+
+# If we have a gas/as cross compiler, they have usually some prefix, like
+# e.g. powerpc-linux-gas, arm-elf-gas or i586-mingw32msvc-gas , optionally
+# with a 3-component version number at the end
+# The other tools of the toolchain usually have the same prefix
+# NAME_WE cannot be used since then this test will fail for names like
+# "arm-unknown-nto-qnx6.3.0-gas.exe", where BASENAME would be
+# "arm-unknown-nto-qnx6" instead of the correct "arm-unknown-nto-qnx6.3.0-"
+if (NOT _CMAKE_TOOLCHAIN_PREFIX)
+ get_filename_component(COMPILER_BASENAME "${CMAKE_ASM${ASM_DIALECT}_COMPILER}" NAME)
+ if (COMPILER_BASENAME MATCHES "^(.+-)g?as(-[0-9]+\\.[0-9]+\\.[0-9]+)?(\\.exe)?$")
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ endif ()
+endif ()
+
+# Now try the C compiler regexp:
+if (NOT _CMAKE_TOOLCHAIN_PREFIX)
+ if (COMPILER_BASENAME MATCHES "^(.+-)g?cc(-[0-9]+\\.[0-9]+\\.[0-9]+)?(\\.exe)?$")
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ endif ()
+endif ()
+
+# Finally try the CXX compiler regexp:
+if (NOT _CMAKE_TOOLCHAIN_PREFIX)
+ if (COMPILER_BASENAME MATCHES "^(.+-)[gc]\\+\\+(-[0-9]+\\.[0-9]+\\.[0-9]+)?(\\.exe)?$")
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ endif ()
+endif ()
+
+
+set(_CMAKE_PROCESSING_LANGUAGE "ASM")
+include(CMakeFindBinUtils)
+include(Compiler/${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}-FindBinUtils OPTIONAL)
+unset(_CMAKE_PROCESSING_LANGUAGE)
+
+set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ENV_VAR "ASM${ASM_DIALECT}")
+
+if(CMAKE_ASM${ASM_DIALECT}_COMPILER)
+ message(STATUS "Found assembler: ${CMAKE_ASM${ASM_DIALECT}_COMPILER}")
+else()
+ message(STATUS "Didn't find assembler")
+endif()
+
+foreach(_var
+ COMPILER
+ COMPILER_ID
+ COMPILER_ARG1
+ COMPILER_ENV_VAR
+ COMPILER_AR
+ COMPILER_RANLIB
+ COMPILER_VERSION
+ )
+ set(_CMAKE_ASM_${_var} "${CMAKE_ASM${ASM_DIALECT}_${_var}}")
+endforeach()
+
+if(CMAKE_ASM${ASM_DIALECT}_COMPILER_SYSROOT)
+ string(CONCAT _SET_CMAKE_ASM_COMPILER_SYSROOT
+ "set(CMAKE_ASM${ASM_DIALECT}_COMPILER_SYSROOT \"${CMAKE_ASM${ASM_DIALECT}_COMPILER_SYSROOT}\")\n"
+ "set(CMAKE_COMPILER_SYSROOT \"${CMAKE_ASM${ASM_DIALECT}_COMPILER_SYSROOT}\")")
+else()
+ set(_SET_CMAKE_ASM_COMPILER_SYSROOT "")
+endif()
+
+if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_MATCH)
+ set(_SET_CMAKE_ASM_COMPILER_ID_VENDOR_MATCH
+ "set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_MATCH [==[${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_MATCH}]==])")
+else()
+ set(_SET_CMAKE_ASM_COMPILER_ID_VENDOR_MATCH "")
+endif()
+
+if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID)
+ set(_SET_CMAKE_ASM_COMPILER_ARCHITECTURE_ID
+ "set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID ${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID})")
+else()
+ set(_SET_CMAKE_ASM_COMPILER_ARCHITECTURE_ID "")
+endif()
+
+# configure variables set in this file for fast reload later on
+configure_file(${CMAKE_ROOT}/Modules/CMakeASMCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeASM${ASM_DIALECT}Compiler.cmake @ONLY)
+
+foreach(_var
+ COMPILER
+ COMPILER_ID
+ COMPILER_ARG1
+ COMPILER_ENV_VAR
+ COMPILER_AR
+ COMPILER_RANLIB
+ COMPILER_VERSION
+ )
+ unset(_CMAKE_ASM_${_var})
+endforeach()
diff --git a/Modules/CMakeDetermineASM_MASMCompiler.cmake b/Modules/CMakeDetermineASM_MASMCompiler.cmake
new file mode 100644
index 0000000..80188fb
--- /dev/null
+++ b/Modules/CMakeDetermineASM_MASMCompiler.cmake
@@ -0,0 +1,18 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# Find the MS assembler (masm or masm64)
+
+set(ASM_DIALECT "_MASM")
+
+# if we are using the 64bit cl compiler, assume we also want the 64bit assembler
+if(";${CMAKE_VS_PLATFORM_NAME};${MSVC_C_ARCHITECTURE_ID};${MSVC_CXX_ARCHITECTURE_ID};"
+ MATCHES ";(Win64|Itanium|x64|IA64);")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT ml64)
+else()
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT ml)
+endif()
+
+include(CMakeDetermineASMCompiler)
+set(ASM_DIALECT)
diff --git a/Modules/CMakeDetermineASM_NASMCompiler.cmake b/Modules/CMakeDetermineASM_NASMCompiler.cmake
new file mode 100644
index 0000000..dd75310
--- /dev/null
+++ b/Modules/CMakeDetermineASM_NASMCompiler.cmake
@@ -0,0 +1,30 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# Find the nasm assembler. yasm (http://www.tortall.net/projects/yasm/) is nasm compatible
+
+set(CMAKE_ASM_NASM_COMPILER_LIST nasm yasm)
+
+if(NOT CMAKE_ASM_NASM_COMPILER)
+ set(_CMAKE_ENV_VARX86 "ProgramFiles(x86)")
+ set(_CMAKE_ASM_NASM_COMPILER_PATHS
+ "[HKEY_CURRENT_USER\\SOFTWARE\\nasm]"
+ "$ENV{ProgramFiles}/NASM"
+ "$ENV{${ENV_VARX86}}/NASM"
+ "$ENV{LOCALAPPDATA}/NASM"
+ )
+ find_program(CMAKE_ASM_NASM_COMPILER
+ NAMES ${CMAKE_ASM_NASM_COMPILER_LIST}
+ PATHS ${_CMAKE_ASM_NASM_COMPILER_PATHS}
+ NO_DEFAULT_PATH
+ DOC "NASM compiler"
+ )
+ unset(_CMAKE_ENV_VARX86)
+ unset(_CMAKE_ASM_NASM_COMPILER_PATHS)
+endif()
+
+# Load the generic DetermineASM compiler file with the DIALECT set properly:
+set(ASM_DIALECT "_NASM")
+include(CMakeDetermineASMCompiler)
+set(ASM_DIALECT)
diff --git a/Modules/CMakeDetermineCCompiler.cmake b/Modules/CMakeDetermineCCompiler.cmake
new file mode 100644
index 0000000..cd07ba9
--- /dev/null
+++ b/Modules/CMakeDetermineCCompiler.cmake
@@ -0,0 +1,230 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# determine the compiler to use for C programs
+# NOTE, a generator may set CMAKE_C_COMPILER before
+# loading this file to force a compiler.
+# use environment variable CC first if defined by user, next use
+# the cmake variable CMAKE_GENERATOR_CC which can be defined by a generator
+# as a default compiler
+# If the internal cmake variable _CMAKE_TOOLCHAIN_PREFIX is set, this is used
+# as prefix for the tools (e.g. arm-elf-gcc, arm-elf-ar etc.). This works
+# currently with the GNU crosscompilers.
+#
+# Sets the following variables:
+# CMAKE_C_COMPILER
+# CMAKE_AR
+# CMAKE_RANLIB
+# CMAKE_COMPILER_IS_GNUCC
+#
+# If not already set before, it also sets
+# _CMAKE_TOOLCHAIN_PREFIX
+
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
+
+# Load system-specific compiler preferences for this language.
+include(Platform/${CMAKE_SYSTEM_NAME}-Determine-C OPTIONAL)
+include(Platform/${CMAKE_SYSTEM_NAME}-C OPTIONAL)
+if(NOT CMAKE_C_COMPILER_NAMES)
+ set(CMAKE_C_COMPILER_NAMES cc)
+endif()
+
+if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
+elseif("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
+elseif("${CMAKE_GENERATOR}" MATCHES "Xcode")
+ set(CMAKE_C_COMPILER_XCODE_TYPE sourcecode.c.c)
+ _cmake_find_compiler_path(C)
+else()
+ if(NOT CMAKE_C_COMPILER)
+ set(CMAKE_C_COMPILER_INIT NOTFOUND)
+
+ # prefer the environment variable CC
+ if(NOT $ENV{CC} STREQUAL "")
+ get_filename_component(CMAKE_C_COMPILER_INIT $ENV{CC} PROGRAM PROGRAM_ARGS CMAKE_C_FLAGS_ENV_INIT)
+ if(CMAKE_C_FLAGS_ENV_INIT)
+ set(CMAKE_C_COMPILER_ARG1 "${CMAKE_C_FLAGS_ENV_INIT}" CACHE STRING "Arguments to C compiler")
+ endif()
+ if(NOT EXISTS ${CMAKE_C_COMPILER_INIT})
+ message(FATAL_ERROR "Could not find compiler set in environment variable CC:\n$ENV{CC}.")
+ endif()
+ endif()
+
+ # next try prefer the compiler specified by the generator
+ if(CMAKE_GENERATOR_CC)
+ if(NOT CMAKE_C_COMPILER_INIT)
+ set(CMAKE_C_COMPILER_INIT ${CMAKE_GENERATOR_CC})
+ endif()
+ endif()
+
+ # finally list compilers to try
+ if(NOT CMAKE_C_COMPILER_INIT)
+ set(CMAKE_C_COMPILER_LIST ${_CMAKE_TOOLCHAIN_PREFIX}cc ${_CMAKE_TOOLCHAIN_PREFIX}gcc cl bcc xlc icx clang)
+ endif()
+
+ _cmake_find_compiler(C)
+
+ else()
+ _cmake_find_compiler_path(C)
+ endif()
+ mark_as_advanced(CMAKE_C_COMPILER)
+
+ # Each entry in this list is a set of extra flags to try
+ # adding to the compile line to see if it helps produce
+ # a valid identification file.
+ set(CMAKE_C_COMPILER_ID_TEST_FLAGS_FIRST)
+ set(CMAKE_C_COMPILER_ID_TEST_FLAGS
+ # Try compiling to an object file only.
+ "-c"
+
+ # Try enabling ANSI mode on HP.
+ "-Aa"
+
+ # Try compiling K&R-compatible code (needed by Bruce C Compiler).
+ "-D__CLASSIC_C__"
+
+ # ARMClang need target options
+ "--target=arm-arm-none-eabi -mcpu=cortex-m3"
+ )
+endif()
+if(CMAKE_C_COMPILER_TARGET)
+ set(CMAKE_C_COMPILER_ID_TEST_FLAGS_FIRST "-c --target=${CMAKE_C_COMPILER_TARGET}")
+endif()
+# Build a small source file to identify the compiler.
+if(NOT CMAKE_C_COMPILER_ID_RUN)
+ set(CMAKE_C_COMPILER_ID_RUN 1)
+
+ # Try to identify the compiler.
+ set(CMAKE_C_COMPILER_ID)
+ set(CMAKE_C_PLATFORM_ID)
+ file(READ ${CMAKE_ROOT}/Modules/CMakePlatformId.h.in
+ CMAKE_C_COMPILER_ID_PLATFORM_CONTENT)
+
+ # The IAR compiler produces weird output.
+ # See https://gitlab.kitware.com/cmake/cmake/-/issues/10176#note_153591
+ list(APPEND CMAKE_C_COMPILER_ID_VENDORS IAR)
+ set(CMAKE_C_COMPILER_ID_VENDOR_FLAGS_IAR )
+ set(CMAKE_C_COMPILER_ID_VENDOR_REGEX_IAR "IAR .+ Compiler")
+
+ # Match the link line from xcodebuild output of the form
+ # Ld ...
+ # ...
+ # /path/to/cc ...CompilerIdC/...
+ # to extract the compiler front-end for the language.
+ set(CMAKE_C_COMPILER_ID_TOOL_MATCH_REGEX "\nLd[^\n]*(\n[ \t]+[^\n]*)*\n[ \t]+([^ \t\r\n]+)[^\r\n]*-o[^\r\n]*CompilerIdC/(\\./)?(CompilerIdC.(framework|xctest|build/[^ \t\r\n]+)/)?CompilerIdC[ \t\n\\\"]")
+ set(CMAKE_C_COMPILER_ID_TOOL_MATCH_INDEX 2)
+
+ include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
+ CMAKE_DETERMINE_COMPILER_ID(C CFLAGS CMakeCCompilerId.c)
+
+ _cmake_find_compiler_sysroot(C)
+
+ # Set old compiler and platform id variables.
+ if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ set(CMAKE_COMPILER_IS_GNUCC 1)
+ endif()
+ if(CMAKE_C_PLATFORM_ID MATCHES "MinGW")
+ set(CMAKE_COMPILER_IS_MINGW 1)
+ elseif(CMAKE_C_PLATFORM_ID MATCHES "Cygwin")
+ set(CMAKE_COMPILER_IS_CYGWIN 1)
+ endif()
+else()
+ if(NOT DEFINED CMAKE_C_COMPILER_FRONTEND_VARIANT)
+ # Some toolchain files set our internal CMAKE_C_COMPILER_ID_RUN
+ # variable but are not aware of CMAKE_C_COMPILER_FRONTEND_VARIANT.
+ # They pre-date our support for the GNU-like variant targeting the
+ # MSVC ABI so we do not consider that here.
+ if(CMAKE_C_COMPILER_ID STREQUAL "Clang"
+ OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xIntelLLVM")
+ if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
+ set(CMAKE_C_COMPILER_FRONTEND_VARIANT "MSVC")
+ else()
+ set(CMAKE_C_COMPILER_FRONTEND_VARIANT "GNU")
+ endif()
+ else()
+ set(CMAKE_C_COMPILER_FRONTEND_VARIANT "")
+ endif()
+ endif()
+endif()
+
+if (NOT _CMAKE_TOOLCHAIN_LOCATION)
+ get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_C_COMPILER}" PATH)
+endif ()
+
+# If we have a gcc cross compiler, they have usually some prefix, like
+# e.g. powerpc-linux-gcc, arm-elf-gcc or i586-mingw32msvc-gcc, optionally
+# with a 3-component version number at the end (e.g. arm-eabi-gcc-4.5.2).
+# The other tools of the toolchain usually have the same prefix
+# NAME_WE cannot be used since then this test will fail for names like
+# "arm-unknown-nto-qnx6.3.0-gcc.exe", where BASENAME would be
+# "arm-unknown-nto-qnx6" instead of the correct "arm-unknown-nto-qnx6.3.0-"
+if (NOT _CMAKE_TOOLCHAIN_PREFIX)
+
+ if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|QCC")
+ get_filename_component(COMPILER_BASENAME "${CMAKE_C_COMPILER}" NAME)
+ if (COMPILER_BASENAME MATCHES "^(.+-)?(clang|g?cc)(-cl)?(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$")
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ set(_CMAKE_TOOLCHAIN_SUFFIX ${CMAKE_MATCH_4})
+ set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_6})
+ elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
+ if(CMAKE_C_COMPILER_TARGET)
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_C_COMPILER_TARGET}-)
+ endif()
+ elseif(COMPILER_BASENAME MATCHES "qcc(\\.exe)?$")
+ if(CMAKE_C_COMPILER_TARGET MATCHES "gcc_nto([a-z0-9]+_[0-9]+|[^_le]+)(le)?")
+ set(_CMAKE_TOOLCHAIN_PREFIX nto${CMAKE_MATCH_1}-)
+ endif()
+ endif ()
+
+ # if "llvm-" is part of the prefix, remove it, since llvm doesn't have its own binutils
+ # but uses the regular ar, objcopy, etc. (instead of llvm-objcopy etc.)
+ if ("${_CMAKE_TOOLCHAIN_PREFIX}" MATCHES "(.+-)?llvm-$")
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ endif ()
+ elseif(CMAKE_C_COMPILER_ID MATCHES "TI")
+ # TI compilers are named e.g. cl6x, cl470 or armcl.exe
+ get_filename_component(COMPILER_BASENAME "${CMAKE_C_COMPILER}" NAME)
+ if (COMPILER_BASENAME MATCHES "^(.+)?cl([^.]+)?(\\.exe)?$")
+ set(_CMAKE_TOOLCHAIN_PREFIX "${CMAKE_MATCH_1}")
+ set(_CMAKE_TOOLCHAIN_SUFFIX "${CMAKE_MATCH_2}")
+ endif ()
+ endif()
+
+endif ()
+
+set(_CMAKE_PROCESSING_LANGUAGE "C")
+include(CMakeFindBinUtils)
+include(Compiler/${CMAKE_C_COMPILER_ID}-FindBinUtils OPTIONAL)
+unset(_CMAKE_PROCESSING_LANGUAGE)
+
+if(CMAKE_C_COMPILER_SYSROOT)
+ string(CONCAT _SET_CMAKE_C_COMPILER_SYSROOT
+ "set(CMAKE_C_COMPILER_SYSROOT \"${CMAKE_C_COMPILER_SYSROOT}\")\n"
+ "set(CMAKE_COMPILER_SYSROOT \"${CMAKE_C_COMPILER_SYSROOT}\")")
+else()
+ set(_SET_CMAKE_C_COMPILER_SYSROOT "")
+endif()
+
+if(CMAKE_C_COMPILER_ARCHITECTURE_ID)
+ set(_SET_CMAKE_C_COMPILER_ARCHITECTURE_ID
+ "set(CMAKE_C_COMPILER_ARCHITECTURE_ID ${CMAKE_C_COMPILER_ARCHITECTURE_ID})")
+else()
+ set(_SET_CMAKE_C_COMPILER_ARCHITECTURE_ID "")
+endif()
+
+if(MSVC_C_ARCHITECTURE_ID)
+ set(SET_MSVC_C_ARCHITECTURE_ID
+ "set(MSVC_C_ARCHITECTURE_ID ${MSVC_C_ARCHITECTURE_ID})")
+endif()
+
+if(CMAKE_C_XCODE_ARCHS)
+ set(SET_CMAKE_XCODE_ARCHS
+ "set(CMAKE_XCODE_ARCHS \"${CMAKE_C_XCODE_ARCHS}\")")
+endif()
+
+# configure variables set in this file for fast reload later on
+configure_file(${CMAKE_ROOT}/Modules/CMakeCCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeCCompiler.cmake
+ @ONLY
+ )
+set(CMAKE_C_COMPILER_ENV_VAR "CC")
diff --git a/Modules/CMakeDetermineCSharpCompiler.cmake b/Modules/CMakeDetermineCSharpCompiler.cmake
new file mode 100644
index 0000000..da860a8
--- /dev/null
+++ b/Modules/CMakeDetermineCSharpCompiler.cmake
@@ -0,0 +1,42 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+if(NOT ${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|[9][0-9])")
+ message(FATAL_ERROR
+ "C# is currently only supported for Microsoft Visual Studio 2010 and later.")
+endif()
+
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
+#include(Platform/${CMAKE_SYSTEM_NAME}-Determine-CSharp OPTIONAL)
+#include(Platform/${CMAKE_SYSTEM_NAME}-CSharp OPTIONAL)
+if(NOT CMAKE_CSharp_COMPILER_NAMES)
+ set(CMAKE_CSharp_COMPILER_NAMES csc)
+endif()
+
+# Build a small source file to identify the compiler.
+if(NOT CMAKE_CSharp_COMPILER_ID_RUN)
+ set(CMAKE_CSharp_COMPILER_ID_RUN 1)
+
+ # Try to identify the compiler.
+ set(CMAKE_CSharp_COMPILER_ID)
+ include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
+ CMAKE_DETERMINE_COMPILER_ID(CSharp CSFLAGS CMakeCSharpCompilerId.cs)
+
+ execute_process(COMMAND "${CMAKE_CSharp_COMPILER}" "/help /preferreduilang:en-US" OUTPUT_VARIABLE output)
+ string(REPLACE "\n" ";" output "${output}")
+ foreach(line ${output})
+ string(TOUPPER ${line} line)
+ string(REGEX REPLACE "^.*COMPILER.*VERSION[^\\.0-9]*([\\.0-9]+).*$" "\\1" version "${line}")
+ if(version AND NOT "x${line}" STREQUAL "x${version}")
+ set(CMAKE_CSharp_COMPILER_VERSION ${version})
+ break()
+ endif()
+ endforeach()
+ message(STATUS "The CSharp compiler version is ${CMAKE_CSharp_COMPILER_VERSION}")
+endif()
+
+# configure variables set in this file for fast reload later on
+configure_file(${CMAKE_ROOT}/Modules/CMakeCSharpCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeCSharpCompiler.cmake
+ @ONLY
+ )
diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake
new file mode 100644
index 0000000..0f507ea
--- /dev/null
+++ b/Modules/CMakeDetermineCUDACompiler.cmake
@@ -0,0 +1,615 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
+include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake)
+
+if( NOT ( ("${CMAKE_GENERATOR}" MATCHES "Make") OR
+ ("${CMAKE_GENERATOR}" MATCHES "Ninja") OR
+ ("${CMAKE_GENERATOR}" MATCHES "Visual Studio (1|[9][0-9])") ) )
+ message(FATAL_ERROR "CUDA language not currently supported by \"${CMAKE_GENERATOR}\" generator")
+endif()
+
+if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
+else()
+ if(NOT CMAKE_CUDA_COMPILER)
+ set(CMAKE_CUDA_COMPILER_INIT NOTFOUND)
+
+ # prefer the environment variable CUDACXX
+ if(NOT $ENV{CUDACXX} STREQUAL "")
+ get_filename_component(CMAKE_CUDA_COMPILER_INIT $ENV{CUDACXX} PROGRAM PROGRAM_ARGS CMAKE_CUDA_FLAGS_ENV_INIT)
+ if(CMAKE_CUDA_FLAGS_ENV_INIT)
+ set(CMAKE_CUDA_COMPILER_ARG1 "${CMAKE_CUDA_FLAGS_ENV_INIT}" CACHE STRING "Arguments to CXX compiler")
+ endif()
+ if(NOT EXISTS ${CMAKE_CUDA_COMPILER_INIT})
+ message(FATAL_ERROR "Could not find compiler set in environment variable CUDACXX:\n$ENV{CUDACXX}.\n${CMAKE_CUDA_COMPILER_INIT}")
+ endif()
+ endif()
+
+ # finally list compilers to try
+ if(NOT CMAKE_CUDA_COMPILER_INIT)
+ set(CMAKE_CUDA_COMPILER_LIST nvcc)
+ endif()
+
+ set(_CMAKE_CUDA_COMPILER_PATHS "$ENV{CUDA_PATH}/bin")
+ _cmake_find_compiler(CUDA)
+ unset(_CMAKE_CUDA_COMPILER_PATHS)
+ else()
+ _cmake_find_compiler_path(CUDA)
+ endif()
+
+ mark_as_advanced(CMAKE_CUDA_COMPILER)
+endif()
+
+#Allow the user to specify a host compiler
+if(NOT $ENV{CUDAHOSTCXX} STREQUAL "")
+ get_filename_component(CMAKE_CUDA_HOST_COMPILER $ENV{CUDAHOSTCXX} PROGRAM)
+ if(NOT EXISTS ${CMAKE_CUDA_HOST_COMPILER})
+ message(FATAL_ERROR "Could not find compiler set in environment variable CUDAHOSTCXX:\n$ENV{CUDAHOSTCXX}.\n${CMAKE_CUDA_HOST_COMPILER}")
+ endif()
+endif()
+
+if(NOT "$ENV{CUDAARCHS}" STREQUAL "")
+ set(CMAKE_CUDA_ARCHITECTURES "$ENV{CUDAARCHS}" CACHE STRING "CUDA architectures")
+endif()
+
+# Build a small source file to identify the compiler.
+if(NOT CMAKE_CUDA_COMPILER_ID_RUN)
+ set(CMAKE_CUDA_COMPILER_ID_RUN 1)
+
+ include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
+
+ if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
+ # We will not know CMAKE_CUDA_COMPILER until the main compiler id step
+ # below extracts it, but we do know that the compiler id will be NVIDIA.
+ set(CMAKE_CUDA_COMPILER_ID "NVIDIA")
+ else()
+ # We determine the vendor to help with find the toolkit and use the right flags for detection right away.
+ # The main compiler identification is still needed below to extract other information.
+ list(APPEND CMAKE_CUDA_COMPILER_ID_VENDORS NVIDIA Clang)
+ set(CMAKE_CUDA_COMPILER_ID_VENDOR_REGEX_NVIDIA "nvcc: NVIDIA \\(R\\) Cuda compiler driver")
+ set(CMAKE_CUDA_COMPILER_ID_VENDOR_REGEX_Clang "(clang version)")
+ CMAKE_DETERMINE_COMPILER_ID_VENDOR(CUDA "--version")
+
+ if(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang" AND WIN32)
+ message(FATAL_ERROR "Clang with CUDA is not yet supported on Windows. See CMake issue #20776.")
+ endif()
+
+ # Find the CUDA toolkit. We store the CMAKE_CUDA_COMPILER_TOOLKIT_ROOT and CMAKE_CUDA_COMPILER_LIBRARY_ROOT
+ # in CMakeCUDACompiler.cmake, so FindCUDAToolkit can avoid searching on future runs and the toolkit stays the same.
+ # This is very similar to FindCUDAToolkit, but somewhat simplified since we can issue fatal errors
+ # if we fail to find things we need and we don't need to account for searching the libraries.
+
+ # For NVCC we can easily deduce the SDK binary directory from the compiler path.
+ if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
+ set(_CUDA_NVCC_EXECUTABLE "${CMAKE_CUDA_COMPILER}")
+ else()
+ # Search using CUDAToolkit_ROOT and then CUDA_PATH for equivalence with FindCUDAToolkit.
+ # In FindCUDAToolkit CUDAToolkit_ROOT is searched automatically due to being in a find_package().
+ # First we search candidate non-default paths to give them priority.
+ find_program(_CUDA_NVCC_EXECUTABLE
+ NAMES nvcc nvcc.exe
+ PATHS ${CUDAToolkit_ROOT}
+ ENV CUDAToolkit_ROOT
+ ENV CUDA_PATH
+ PATH_SUFFIXES bin
+ NO_DEFAULT_PATH
+ )
+
+ # If we didn't find NVCC, then try the default paths.
+ find_program(_CUDA_NVCC_EXECUTABLE
+ NAMES nvcc nvcc.exe
+ PATH_SUFFIXES bin
+ )
+
+ # If the user specified CUDAToolkit_ROOT but nvcc could not be found, this is an error.
+ if(NOT _CUDA_NVCC_EXECUTABLE AND (DEFINED CUDAToolkit_ROOT OR DEFINED ENV{CUDAToolkit_ROOT}))
+ set(fail_base "Could not find nvcc executable in path specified by")
+
+ if(DEFINED CUDAToolkit_ROOT)
+ message(FATAL_ERROR "${fail_base} CUDAToolkit_ROOT=${CUDAToolkit_ROOT}")
+ elseif(DEFINED ENV{CUDAToolkit_ROOT})
+ message(FATAL_ERROR "${fail_base} environment variable CUDAToolkit_ROOT=$ENV{CUDAToolkit_ROOT}")
+ endif()
+ endif()
+
+ # CUDAToolkit_ROOT cmake/env variable not specified, try platform defaults.
+ #
+ # - Linux: /usr/local/cuda-X.Y
+ # - macOS: /Developer/NVIDIA/CUDA-X.Y
+ # - Windows: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vX.Y
+ #
+ # We will also search the default symlink location /usr/local/cuda first since
+ # if CUDAToolkit_ROOT is not specified, it is assumed that the symlinked
+ # directory is the desired location.
+ if(NOT _CUDA_NVCC_EXECUTABLE)
+ if(UNIX)
+ if(NOT APPLE)
+ set(platform_base "/usr/local/cuda-")
+ else()
+ set(platform_base "/Developer/NVIDIA/CUDA-")
+ endif()
+ else()
+ set(platform_base "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v")
+ endif()
+
+ # Build out a descending list of possible cuda installations, e.g.
+ file(GLOB possible_paths "${platform_base}*")
+ # Iterate the glob results and create a descending list.
+ set(versions)
+ foreach(p ${possible_paths})
+ # Extract version number from end of string
+ string(REGEX MATCH "[0-9][0-9]?\\.[0-9]$" p_version ${p})
+ if(IS_DIRECTORY ${p} AND p_version)
+ list(APPEND versions ${p_version})
+ endif()
+ endforeach()
+
+ # Sort numerically in descending order, so we try the newest versions first.
+ list(SORT versions COMPARE NATURAL ORDER DESCENDING)
+
+ # With a descending list of versions, populate possible paths to search.
+ set(search_paths)
+ foreach(v ${versions})
+ list(APPEND search_paths "${platform_base}${v}")
+ endforeach()
+
+ # Force the global default /usr/local/cuda to the front on Unix.
+ if(UNIX)
+ list(INSERT search_paths 0 "/usr/local/cuda")
+ endif()
+
+ # Now search for nvcc again using the platform default search paths.
+ find_program(_CUDA_NVCC_EXECUTABLE
+ NAMES nvcc nvcc.exe
+ PATHS ${search_paths}
+ PATH_SUFFIXES bin
+ )
+
+ # We are done with these variables now, cleanup.
+ unset(platform_base)
+ unset(possible_paths)
+ unset(versions)
+ unset(search_paths)
+
+ if(NOT _CUDA_NVCC_EXECUTABLE)
+ message(FATAL_ERROR "Failed to find nvcc.\nCompiler ${CMAKE_CUDA_COMPILER_ID} requires the CUDA toolkit. Please set the CUDAToolkit_ROOT variable.")
+ endif()
+ endif()
+ endif()
+
+ # Given that NVCC can be provided by multiple different sources (NVIDIA HPC SDK, CUDA Toolkit, distro)
+ # each of which has a different layout, we need to extract the CUDA toolkit root from the compiler
+ # itself, allowing us to support numerous different scattered toolkit layouts
+ execute_process(COMMAND ${_CUDA_NVCC_EXECUTABLE} "-v" "__cmake_determine_cuda"
+ OUTPUT_VARIABLE _CUDA_NVCC_OUT ERROR_VARIABLE _CUDA_NVCC_OUT)
+ if(_CUDA_NVCC_OUT MATCHES "TOP=([^\r\n]*)")
+ get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_MATCH_1}" ABSOLUTE)
+ else()
+ get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${_CUDA_NVCC_EXECUTABLE}" DIRECTORY)
+ get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}" DIRECTORY)
+ endif()
+ unset(_CUDA_NVCC_OUT)
+
+ set(CMAKE_CUDA_DEVICE_LINKER "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/bin/nvlink${CMAKE_EXECUTABLE_SUFFIX}")
+ set(CMAKE_CUDA_FATBINARY "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/bin/fatbinary${CMAKE_EXECUTABLE_SUFFIX}")
+
+
+ # In a non-scattered installation the following are equivalent to CMAKE_CUDA_COMPILER_TOOLKIT_ROOT.
+ # We first check for a non-scattered installation to prefer it over a scattered installation.
+
+ # CMAKE_CUDA_COMPILER_LIBRARY_ROOT contains the device library.
+ if(EXISTS "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/nvvm/libdevice")
+ set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}")
+ elseif(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/cuda/nvvm/libdevice")
+ set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_SYSROOT_LINK}/usr/lib/cuda")
+ elseif(EXISTS "${CMAKE_SYSROOT}/usr/lib/cuda/nvvm/libdevice")
+ set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_SYSROOT}/usr/lib/cuda")
+ else()
+ message(FATAL_ERROR "Couldn't find CUDA library root.")
+ endif()
+
+ # CMAKE_CUDA_COMPILER_TOOLKIT_LIBRARY_ROOT contains the linking stubs necessary for device linking and other low-level library files.
+ if(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/nvidia-cuda-toolkit/bin/crt/link.stub")
+ set(CMAKE_CUDA_COMPILER_TOOLKIT_LIBRARY_ROOT "${CMAKE_SYSROOT_LINK}/usr/lib/nvidia-cuda-toolkit")
+ elseif(EXISTS "${CMAKE_SYSROOT}/usr/lib/nvidia-cuda-toolkit/bin/crt/link.stub")
+ set(CMAKE_CUDA_COMPILER_TOOLKIT_LIBRARY_ROOT "${CMAKE_SYSROOT}/usr/lib/nvidia-cuda-toolkit")
+ else()
+ set(CMAKE_CUDA_COMPILER_TOOLKIT_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}")
+ endif()
+ endif()
+
+ set(CMAKE_CUDA_COMPILER_ID_FLAGS_ALWAYS "-v")
+
+ if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
+ set(nvcc_test_flags "--keep --keep-dir tmp")
+ if(CMAKE_CUDA_HOST_COMPILER)
+ string(APPEND nvcc_test_flags " -ccbin=\"${CMAKE_CUDA_HOST_COMPILER}\"")
+
+ # If the user has specified a host compiler we should fail instead of trying without.
+ # Succeeding detection without may result in confusing errors later on, see #21076.
+ set(CMAKE_CUDA_COMPILER_ID_REQUIRE_SUCCESS ON)
+ endif()
+ elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang")
+ set(clang_test_flags "--cuda-path=\"${CMAKE_CUDA_COMPILER_LIBRARY_ROOT}\"")
+ if(CMAKE_CROSSCOMPILING)
+ # Need to pass the host target and include directories if we're crosscompiling.
+ string(APPEND clang_test_flags " --sysroot=\"${CMAKE_SYSROOT}\" --target=${CMAKE_CUDA_COMPILER_TARGET}")
+ endif()
+ endif()
+
+ # Append user-specified architectures.
+ if(CMAKE_CUDA_ARCHITECTURES)
+ foreach(arch ${CMAKE_CUDA_ARCHITECTURES})
+ # Strip specifiers as PTX vs binary doesn't matter.
+ string(REGEX MATCH "[0-9]+" arch_name "${arch}")
+ string(APPEND clang_test_flags " --cuda-gpu-arch=sm_${arch_name}")
+ string(APPEND nvcc_test_flags " -gencode=arch=compute_${arch_name},code=sm_${arch_name}")
+ list(APPEND tested_architectures "${arch_name}")
+ endforeach()
+
+ # If the user has specified architectures we'll want to fail during compiler detection if they don't work.
+ set(CMAKE_CUDA_COMPILER_ID_REQUIRE_SUCCESS ON)
+ endif()
+
+ if(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang")
+ if(NOT CMAKE_CUDA_ARCHITECTURES)
+ # Clang doesn't automatically select an architecture supported by the SDK.
+ # Try in reverse order of deprecation with the most recent at front (i.e. the most likely to work for new setups).
+ foreach(arch "20" "30" "52")
+ list(APPEND CMAKE_CUDA_COMPILER_ID_TEST_FLAGS_FIRST "${clang_test_flags} --cuda-gpu-arch=sm_${arch}")
+ endforeach()
+ endif()
+
+ # If the user specified CMAKE_CUDA_ARCHITECTURES this will include all the architecture flags.
+ # Otherwise this won't include any architecture flags and we'll fallback to Clang's defaults.
+ list(APPEND CMAKE_CUDA_COMPILER_ID_TEST_FLAGS_FIRST "${clang_test_flags}")
+ elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
+ list(APPEND CMAKE_CUDA_COMPILER_ID_TEST_FLAGS_FIRST "${nvcc_test_flags}")
+ endif()
+
+ # We perform compiler identification for a second time to extract implicit linking info and host compiler for NVCC.
+ # We also use it to verify that CMAKE_CUDA_ARCHITECTURES and additionally on Clang that CUDA toolkit path works.
+ # The latter could be done during compiler testing in the future to avoid doing this for Clang.
+ # We need to unset the compiler ID otherwise CMAKE_DETERMINE_COMPILER_ID() doesn't work.
+ set(CMAKE_CUDA_COMPILER_ID)
+ set(CMAKE_CUDA_PLATFORM_ID)
+ file(READ ${CMAKE_ROOT}/Modules/CMakePlatformId.h.in
+ CMAKE_CUDA_COMPILER_ID_PLATFORM_CONTENT)
+
+ CMAKE_DETERMINE_COMPILER_ID(CUDA CUDAFLAGS CMakeCUDACompilerId.cu)
+
+ if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
+ # Now that we have the path to nvcc, we can compute the toolkit root.
+ get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER}" DIRECTORY)
+ get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}" DIRECTORY)
+ set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}")
+ endif()
+
+ _cmake_find_compiler_sysroot(CUDA)
+endif()
+
+set(_CMAKE_PROCESSING_LANGUAGE "CUDA")
+include(CMakeFindBinUtils)
+include(Compiler/${CMAKE_CUDA_COMPILER_ID}-FindBinUtils OPTIONAL)
+unset(_CMAKE_PROCESSING_LANGUAGE)
+
+if(MSVC_CUDA_ARCHITECTURE_ID)
+ set(SET_MSVC_CUDA_ARCHITECTURE_ID
+ "set(MSVC_CUDA_ARCHITECTURE_ID ${MSVC_CUDA_ARCHITECTURE_ID})")
+endif()
+
+if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
+ set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${CMAKE_LINKER}")
+ set(CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES "")
+ set(CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES "")
+ set(CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")
+
+ # We do not currently detect CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES but we
+ # do need to detect CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT from the compiler by
+ # looking at which cudart library exists in the implicit link libraries passed
+ # to the host linker.
+ if(CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT MATCHES "link\\.exe [^\n]*cudart_static\\.lib")
+ set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "STATIC")
+ elseif(CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT MATCHES "link\\.exe [^\n]*cudart\\.lib")
+ set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "SHARED")
+ else()
+ set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "NONE")
+ endif()
+ set(_SET_CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT
+ "set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT \"${CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT}\")")
+elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang")
+ if(NOT CMAKE_CUDA_ARCHITECTURES)
+ # Find the architecture that we successfully compiled using and set it as the default.
+ string(REGEX MATCH "-target-cpu sm_([0-9]+)" dont_care "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}")
+ set(detected_architecture "${CMAKE_MATCH_1}")
+ else()
+ string(REGEX MATCHALL "-target-cpu sm_([0-9]+)" target_cpus "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}")
+
+ foreach(cpu ${target_cpus})
+ string(REGEX MATCH "-target-cpu sm_([0-9]+)" dont_care "${cpu}")
+ list(APPEND architectures "${CMAKE_MATCH_1}")
+ endforeach()
+ endif()
+
+ # Find target directory when crosscompiling.
+ if(CMAKE_CROSSCOMPILING)
+ if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7-a")
+ # Support for NVPACK
+ set(_CUDA_TARGET_NAME "armv7-linux-androideabi")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
+ set(_CUDA_TARGET_NAME "armv7-linux-gnueabihf")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
+ if(ANDROID_ARCH_NAME STREQUAL "arm64")
+ set(_CUDA_TARGET_NAME "aarch64-linux-androideabi")
+ else()
+ set(_CUDA_TARGET_NAME "aarch64-linux")
+ endif()
+ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
+ set(_CUDA_TARGET_NAME "x86_64-linux")
+ endif()
+
+ if(EXISTS "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/targets/${_CUDA_TARGET_NAME}")
+ set(_CUDA_TARGET_DIR "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/targets/${_CUDA_TARGET_NAME}")
+ endif()
+ endif()
+
+ # If not already set we can simply use the toolkit root or it's a scattered installation.
+ if(NOT _CUDA_TARGET_DIR)
+ set(_CUDA_TARGET_DIR "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}")
+ endif()
+
+ # We can't use find_library() yet at this point, so try a few guesses.
+ if(EXISTS "${_CUDA_TARGET_DIR}/lib64")
+ set(_CUDA_LIBRARY_DIR "${_CUDA_TARGET_DIR}/lib64")
+ elseif(EXISTS "${_CUDA_TARGET_DIR}/lib/x64")
+ set(_CUDA_LIBRARY_DIR "${_CUDA_TARGET_DIR}/lib/x64")
+ elseif(EXISTS "${_CUDA_TARGET_DIR}/lib")
+ set(_CUDA_LIBRARY_DIR "${_CUDA_TARGET_DIR}/lib")
+ else()
+ message(FATAL_ERROR "Unable to find _CUDA_LIBRARY_DIR based on _CUDA_TARGET_DIR=${_CUDA_TARGET_DIR}")
+ endif()
+
+ # _CUDA_TARGET_DIR always points to the directory containing the include directory.
+ # On a scattered installation /usr, on a non-scattered something like /usr/local/cuda or /usr/local/cuda-10.2/targets/aarch64-linux.
+ if(EXISTS "${_CUDA_TARGET_DIR}/include/cuda_runtime.h")
+ set(_CUDA_INCLUDE_DIR "${_CUDA_TARGET_DIR}/include")
+ else()
+ message(FATAL_ERROR "Unable to find cuda_runtime.h in \"${_CUDA_TARGET_DIR}/include\" for _CUDA_INCLUDE_DIR.")
+ endif()
+
+ # Clang does not add any CUDA SDK libraries or directories when invoking the host linker.
+ # Add the CUDA toolkit library directory ourselves so that linking works.
+ # The CUDA runtime libraries are handled elsewhere by CMAKE_CUDA_RUNTIME_LIBRARY.
+ set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "${_CUDA_INCLUDE_DIR}")
+ set(CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES "${_CUDA_LIBRARY_DIR}")
+ set(CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES "")
+ set(CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")
+elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
+ set(_nvcc_log "")
+ string(REPLACE "\r" "" _nvcc_output_orig "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}")
+ if(_nvcc_output_orig MATCHES "#\\\$ +PATH= *([^\n]*)\n")
+ set(_nvcc_path "${CMAKE_MATCH_1}")
+ string(APPEND _nvcc_log " found 'PATH=' string: [${_nvcc_path}]\n")
+ string(REPLACE ":" ";" _nvcc_path "${_nvcc_path}")
+ else()
+ set(_nvcc_path "")
+ string(REPLACE "\n" "\n " _nvcc_output_log "\n${_nvcc_output_orig}")
+ string(APPEND _nvcc_log " no 'PATH=' string found in nvcc output:${_nvcc_output_log}\n")
+ endif()
+ if(_nvcc_output_orig MATCHES "#\\\$ +LIBRARIES= *([^\n]*)\n")
+ set(_nvcc_libraries "${CMAKE_MATCH_1}")
+ string(APPEND _nvcc_log " found 'LIBRARIES=' string: [${_nvcc_libraries}]\n")
+ else()
+ set(_nvcc_libraries "")
+ string(REPLACE "\n" "\n " _nvcc_output_log "\n${_nvcc_output_orig}")
+ string(APPEND _nvcc_log " no 'LIBRARIES=' string found in nvcc output:${_nvcc_output_log}\n")
+ endif()
+
+ set(_nvcc_link_line "")
+ if(_nvcc_libraries)
+ # Remove variable assignments.
+ string(REGEX REPLACE "#\\\$ *[^= ]+=[^\n]*\n" "" _nvcc_output "${_nvcc_output_orig}")
+ # Encode [] characters that break list expansion.
+ string(REPLACE "[" "{==={" _nvcc_output "${_nvcc_output}")
+ string(REPLACE "]" "}===}" _nvcc_output "${_nvcc_output}")
+ # Split lines.
+ string(REGEX REPLACE "\n+(#\\\$ )?" ";" _nvcc_output "${_nvcc_output}")
+ foreach(line IN LISTS _nvcc_output)
+ set(_nvcc_output_line "${line}")
+ string(REPLACE "{==={" "[" _nvcc_output_line "${_nvcc_output_line}")
+ string(REPLACE "}===}" "]" _nvcc_output_line "${_nvcc_output_line}")
+ string(APPEND _nvcc_log " considering line: [${_nvcc_output_line}]\n")
+ if("${_nvcc_output_line}" MATCHES "^ *nvlink")
+ string(APPEND _nvcc_log " ignoring nvlink line\n")
+ elseif(_nvcc_libraries)
+ if("${_nvcc_output_line}" MATCHES "(@\"?tmp/a\\.exe\\.res\"?)")
+ set(_nvcc_link_res_arg "${CMAKE_MATCH_1}")
+ set(_nvcc_link_res "${CMAKE_PLATFORM_INFO_DIR}/CompilerIdCUDA/tmp/a.exe.res")
+ if(EXISTS "${_nvcc_link_res}")
+ file(READ "${_nvcc_link_res}" _nvcc_link_res_content)
+ string(REPLACE "${_nvcc_link_res_arg}" "${_nvcc_link_res_content}" _nvcc_output_line "${_nvcc_output_line}")
+ endif()
+ endif()
+ string(FIND "${_nvcc_output_line}" "${_nvcc_libraries}" _nvcc_libraries_pos)
+ if(NOT _nvcc_libraries_pos EQUAL -1)
+ set(_nvcc_link_line "${_nvcc_output_line}")
+ string(APPEND _nvcc_log " extracted link line: [${_nvcc_link_line}]\n")
+ endif()
+ endif()
+ endforeach()
+ endif()
+
+ if(_nvcc_link_line)
+ if("x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC")
+ set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${CMAKE_LINKER}")
+ else()
+ #extract the compiler that is being used for linking
+ separate_arguments(_nvcc_link_line_args UNIX_COMMAND "${_nvcc_link_line}")
+ list(GET _nvcc_link_line_args 0 _nvcc_host_link_launcher)
+ if(IS_ABSOLUTE "${_nvcc_host_link_launcher}")
+ string(APPEND _nvcc_log " extracted link launcher absolute path: [${_nvcc_host_link_launcher}]\n")
+ set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${_nvcc_host_link_launcher}")
+ else()
+ string(APPEND _nvcc_log " extracted link launcher name: [${_nvcc_host_link_launcher}]\n")
+ find_program(_nvcc_find_host_link_launcher
+ NAMES ${_nvcc_host_link_launcher}
+ PATHS ${_nvcc_path} NO_DEFAULT_PATH)
+ find_program(_nvcc_find_host_link_launcher
+ NAMES ${_nvcc_host_link_launcher})
+ if(_nvcc_find_host_link_launcher)
+ string(APPEND _nvcc_log " found link launcher absolute path: [${_nvcc_find_host_link_launcher}]\n")
+ set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${_nvcc_find_host_link_launcher}")
+ else()
+ string(APPEND _nvcc_log " could not find link launcher absolute path\n")
+ set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${_nvcc_host_link_launcher}")
+ endif()
+ unset(_nvcc_find_host_link_launcher CACHE)
+ endif()
+ endif()
+
+ #prefix the line with cuda-fake-ld so that implicit link info believes it is
+ #a link line
+ set(_nvcc_link_line "cuda-fake-ld ${_nvcc_link_line}")
+ CMAKE_PARSE_IMPLICIT_LINK_INFO("${_nvcc_link_line}"
+ CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES
+ CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES
+ CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ log
+ "${CMAKE_CUDA_IMPLICIT_OBJECT_REGEX}")
+
+ # Detect CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT from the compiler by looking at which
+ # cudart library exists in the implicit link libraries passed to the host linker.
+ # This is required when a project sets the cuda runtime library as part of the
+ # initial flags.
+ if(";${CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES};" MATCHES [[;cudart_static(\.lib)?;]])
+ set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "STATIC")
+ elseif(";${CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES};" MATCHES [[;cudart(\.lib)?;]])
+ set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "SHARED")
+ else()
+ set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "NONE")
+ endif()
+ set(_SET_CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT
+ "set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT \"${CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT}\")")
+
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Parsed CUDA nvcc implicit link information from above output:\n${_nvcc_log}\n${log}\n\n")
+ else()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Failed to parse CUDA nvcc implicit link information:\n${_nvcc_log}\n\n")
+ message(FATAL_ERROR "Failed to extract nvcc implicit link line.")
+ endif()
+endif()
+
+# CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES is detected above as the list of
+# libraries that the CUDA compiler implicitly passes to the host linker.
+# CMake invokes the host linker directly and so needs to pass these libraries.
+# We filter out those that should not be passed unconditionally both here
+# and from CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES in CMakeTestCUDACompiler.
+set(CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES_EXCLUDE
+ # The CUDA runtime libraries are controlled by CMAKE_CUDA_RUNTIME_LIBRARY.
+ cudart cudart.lib
+ cudart_static cudart_static.lib
+ cudadevrt cudadevrt.lib
+
+ # Dependencies of the CUDA static runtime library on Linux hosts.
+ rt
+ pthread
+ dl
+ )
+list(REMOVE_ITEM CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES ${CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES_EXCLUDE})
+
+if(CMAKE_CUDA_COMPILER_SYSROOT)
+ string(CONCAT _SET_CMAKE_CUDA_COMPILER_SYSROOT
+ "set(CMAKE_CUDA_COMPILER_SYSROOT \"${CMAKE_CUDA_COMPILER_SYSROOT}\")\n"
+ "set(CMAKE_COMPILER_SYSROOT \"${CMAKE_CUDA_COMPILER_SYSROOT}\")")
+else()
+ set(_SET_CMAKE_CUDA_COMPILER_SYSROOT "")
+endif()
+
+# Determine CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES
+if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
+ set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES)
+ string(REPLACE "\r" "" _nvcc_output_orig "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}")
+ if(_nvcc_output_orig MATCHES "#\\\$ +INCLUDES= *([^\n]*)\n")
+ set(_nvcc_includes "${CMAKE_MATCH_1}")
+ string(APPEND _nvcc_log " found 'INCLUDES=' string: [${_nvcc_includes}]\n")
+ else()
+ set(_nvcc_includes "")
+ string(REPLACE "\n" "\n " _nvcc_output_log "\n${_nvcc_output_orig}")
+ string(APPEND _nvcc_log " no 'INCLUDES=' string found in nvcc output:${_nvcc_output_log}\n")
+ endif()
+ if(_nvcc_includes)
+ # across all operating system each include directory is prefixed with -I
+ separate_arguments(_nvcc_output NATIVE_COMMAND "${_nvcc_includes}")
+ foreach(line IN LISTS _nvcc_output)
+ string(REGEX REPLACE "^-I" "" line "${line}")
+ get_filename_component(line "${line}" ABSOLUTE)
+ list(APPEND CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "${line}")
+ endforeach()
+
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Parsed CUDA nvcc include information from above output:\n${_nvcc_log}\n${log}\n\n")
+ else()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Failed to detect CUDA nvcc include information:\n${_nvcc_log}\n\n")
+ endif()
+
+ # Parse default CUDA architecture.
+ cmake_policy(GET CMP0104 _CUDA_CMP0104)
+ if(NOT CMAKE_CUDA_ARCHITECTURES AND _CUDA_CMP0104 STREQUAL "NEW")
+ string(REGEX MATCH "arch[ =]compute_([0-9]+)" dont_care "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}")
+ set(detected_architecture "${CMAKE_MATCH_1}")
+ elseif(CMAKE_CUDA_ARCHITECTURES)
+ string(REGEX MATCHALL "-arch compute_([0-9]+)" target_cpus "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}")
+
+ foreach(cpu ${target_cpus})
+ string(REGEX MATCH "-arch compute_([0-9]+)" dont_care "${cpu}")
+ list(APPEND architectures "${CMAKE_MATCH_1}")
+ endforeach()
+ endif()
+endif()
+
+# If the user didn't set the architectures, then set them to a default.
+# If the user did, then make sure those architectures worked.
+if(DEFINED detected_architecture AND "${CMAKE_CUDA_ARCHITECTURES}" STREQUAL "")
+ set(CMAKE_CUDA_ARCHITECTURES "${detected_architecture}" CACHE STRING "CUDA architectures")
+
+ if(NOT CMAKE_CUDA_ARCHITECTURES)
+ message(FATAL_ERROR "Failed to find a working CUDA architecture.")
+ endif()
+elseif(architectures)
+ # Sort since order mustn't matter.
+ list(SORT architectures)
+ list(SORT tested_architectures)
+
+ # We don't distinguish real/virtual architectures during testing.
+ # For "70-real;70-virtual" we detect "70" as working and tested_architectures is "70;70".
+ # Thus we need to remove duplicates before checking if they're equal.
+ list(REMOVE_DUPLICATES tested_architectures)
+
+ if(NOT "${architectures}" STREQUAL "${tested_architectures}")
+ message(FATAL_ERROR
+ "The CMAKE_CUDA_ARCHITECTURES:\n"
+ " ${CMAKE_CUDA_ARCHITECTURES}\n"
+ "do not all work with this compiler. Try:\n"
+ " ${architectures}\n"
+ "instead.")
+ endif()
+endif()
+
+# configure all variables set in this file
+configure_file(${CMAKE_ROOT}/Modules/CMakeCUDACompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeCUDACompiler.cmake
+ @ONLY
+)
+
+# Don't leak variables unnecessarily to user code.
+unset(_CUDA_INCLUDE_DIR CACHE)
+unset(_CUDA_NVCC_EXECUTABLE CACHE)
+unset(_CUDA_LIBRARY_DIR)
+unset(_CUDA_TARGET_DIR)
+unset(_CUDA_TARGET_NAME)
+
+set(CMAKE_CUDA_COMPILER_ENV_VAR "CUDACXX")
+set(CMAKE_CUDA_HOST_COMPILER_ENV_VAR "CUDAHOSTCXX")
diff --git a/Modules/CMakeDetermineCXXCompiler.cmake b/Modules/CMakeDetermineCXXCompiler.cmake
new file mode 100644
index 0000000..fd07a5c
--- /dev/null
+++ b/Modules/CMakeDetermineCXXCompiler.cmake
@@ -0,0 +1,231 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# determine the compiler to use for C++ programs
+# NOTE, a generator may set CMAKE_CXX_COMPILER before
+# loading this file to force a compiler.
+# use environment variable CXX first if defined by user, next use
+# the cmake variable CMAKE_GENERATOR_CXX which can be defined by a generator
+# as a default compiler
+# If the internal cmake variable _CMAKE_TOOLCHAIN_PREFIX is set, this is used
+# as prefix for the tools (e.g. arm-elf-g++, arm-elf-ar etc.)
+#
+# Sets the following variables:
+# CMAKE_CXX_COMPILER
+# CMAKE_COMPILER_IS_GNUCXX
+# CMAKE_AR
+# CMAKE_RANLIB
+#
+# If not already set before, it also sets
+# _CMAKE_TOOLCHAIN_PREFIX
+
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
+
+# Load system-specific compiler preferences for this language.
+include(Platform/${CMAKE_SYSTEM_NAME}-Determine-CXX OPTIONAL)
+include(Platform/${CMAKE_SYSTEM_NAME}-CXX OPTIONAL)
+if(NOT CMAKE_CXX_COMPILER_NAMES)
+ set(CMAKE_CXX_COMPILER_NAMES CC)
+endif()
+
+if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
+elseif("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
+elseif("${CMAKE_GENERATOR}" MATCHES "Xcode")
+ set(CMAKE_CXX_COMPILER_XCODE_TYPE sourcecode.cpp.cpp)
+ _cmake_find_compiler_path(CXX)
+else()
+ if(NOT CMAKE_CXX_COMPILER)
+ set(CMAKE_CXX_COMPILER_INIT NOTFOUND)
+
+ # prefer the environment variable CXX
+ if(NOT $ENV{CXX} STREQUAL "")
+ get_filename_component(CMAKE_CXX_COMPILER_INIT $ENV{CXX} PROGRAM PROGRAM_ARGS CMAKE_CXX_FLAGS_ENV_INIT)
+ if(CMAKE_CXX_FLAGS_ENV_INIT)
+ set(CMAKE_CXX_COMPILER_ARG1 "${CMAKE_CXX_FLAGS_ENV_INIT}" CACHE STRING "Arguments to CXX compiler")
+ endif()
+ if(NOT EXISTS ${CMAKE_CXX_COMPILER_INIT})
+ message(FATAL_ERROR "Could not find compiler set in environment variable CXX:\n$ENV{CXX}.\n${CMAKE_CXX_COMPILER_INIT}")
+ endif()
+ endif()
+
+ # next prefer the generator specified compiler
+ if(CMAKE_GENERATOR_CXX)
+ if(NOT CMAKE_CXX_COMPILER_INIT)
+ set(CMAKE_CXX_COMPILER_INIT ${CMAKE_GENERATOR_CXX})
+ endif()
+ endif()
+
+ # finally list compilers to try
+ if(NOT CMAKE_CXX_COMPILER_INIT)
+ set(CMAKE_CXX_COMPILER_LIST CC ${_CMAKE_TOOLCHAIN_PREFIX}c++ ${_CMAKE_TOOLCHAIN_PREFIX}g++ aCC cl bcc xlC icpx icx clang++)
+ endif()
+
+ _cmake_find_compiler(CXX)
+ else()
+ _cmake_find_compiler_path(CXX)
+ endif()
+ mark_as_advanced(CMAKE_CXX_COMPILER)
+
+ # Each entry in this list is a set of extra flags to try
+ # adding to the compile line to see if it helps produce
+ # a valid identification file.
+ set(CMAKE_CXX_COMPILER_ID_TEST_FLAGS_FIRST)
+ set(CMAKE_CXX_COMPILER_ID_TEST_FLAGS
+ # Try compiling to an object file only.
+ "-c"
+ # IAR does not detect language automatically
+ "--c++"
+ "--ec++"
+
+ # ARMClang need target options
+ "--target=arm-arm-none-eabi -mcpu=cortex-m3"
+ )
+endif()
+
+if(CMAKE_CXX_COMPILER_TARGET)
+ set(CMAKE_CXX_COMPILER_ID_TEST_FLAGS_FIRST "-c --target=${CMAKE_CXX_COMPILER_TARGET}")
+endif()
+
+# Build a small source file to identify the compiler.
+if(NOT CMAKE_CXX_COMPILER_ID_RUN)
+ set(CMAKE_CXX_COMPILER_ID_RUN 1)
+
+ # Try to identify the compiler.
+ set(CMAKE_CXX_COMPILER_ID)
+ set(CMAKE_CXX_PLATFORM_ID)
+ file(READ ${CMAKE_ROOT}/Modules/CMakePlatformId.h.in
+ CMAKE_CXX_COMPILER_ID_PLATFORM_CONTENT)
+
+ # The IAR compiler produces weird output.
+ # See https://gitlab.kitware.com/cmake/cmake/-/issues/10176#note_153591
+ list(APPEND CMAKE_CXX_COMPILER_ID_VENDORS IAR)
+ set(CMAKE_CXX_COMPILER_ID_VENDOR_FLAGS_IAR )
+ set(CMAKE_CXX_COMPILER_ID_VENDOR_REGEX_IAR "IAR .+ Compiler")
+
+ # Match the link line from xcodebuild output of the form
+ # Ld ...
+ # ...
+ # /path/to/cc ...CompilerIdCXX/...
+ # to extract the compiler front-end for the language.
+ set(CMAKE_CXX_COMPILER_ID_TOOL_MATCH_REGEX "\nLd[^\n]*(\n[ \t]+[^\n]*)*\n[ \t]+([^ \t\r\n]+)[^\r\n]*-o[^\r\n]*CompilerIdCXX/(\\./)?(CompilerIdCXX.(framework|xctest|build/[^ \t\r\n]+)/)?CompilerIdCXX[ \t\n\\\"]")
+ set(CMAKE_CXX_COMPILER_ID_TOOL_MATCH_INDEX 2)
+
+ include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
+ CMAKE_DETERMINE_COMPILER_ID(CXX CXXFLAGS CMakeCXXCompilerId.cpp)
+
+ _cmake_find_compiler_sysroot(CXX)
+
+ # Set old compiler and platform id variables.
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ set(CMAKE_COMPILER_IS_GNUCXX 1)
+ endif()
+ if(CMAKE_CXX_PLATFORM_ID MATCHES "MinGW")
+ set(CMAKE_COMPILER_IS_MINGW 1)
+ elseif(CMAKE_CXX_PLATFORM_ID MATCHES "Cygwin")
+ set(CMAKE_COMPILER_IS_CYGWIN 1)
+ endif()
+else()
+ if(NOT DEFINED CMAKE_CXX_COMPILER_FRONTEND_VARIANT)
+ # Some toolchain files set our internal CMAKE_CXX_COMPILER_ID_RUN
+ # variable but are not aware of CMAKE_CXX_COMPILER_FRONTEND_VARIANT.
+ # They pre-date our support for the GNU-like variant targeting the
+ # MSVC ABI so we do not consider that here.
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
+ OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntelLLVM")
+ if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "MSVC")
+ else()
+ set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "GNU")
+ endif()
+ else()
+ set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "")
+ endif()
+ endif()
+endif()
+
+if (NOT _CMAKE_TOOLCHAIN_LOCATION)
+ get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_CXX_COMPILER}" PATH)
+endif ()
+
+# if we have a g++ cross compiler, they have usually some prefix, like
+# e.g. powerpc-linux-g++, arm-elf-g++ or i586-mingw32msvc-g++ , optionally
+# with a 3-component version number at the end (e.g. arm-eabi-gcc-4.5.2).
+# The other tools of the toolchain usually have the same prefix
+# NAME_WE cannot be used since then this test will fail for names like
+# "arm-unknown-nto-qnx6.3.0-gcc.exe", where BASENAME would be
+# "arm-unknown-nto-qnx6" instead of the correct "arm-unknown-nto-qnx6.3.0-"
+
+
+if (NOT _CMAKE_TOOLCHAIN_PREFIX)
+
+ if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang|QCC")
+ get_filename_component(COMPILER_BASENAME "${CMAKE_CXX_COMPILER}" NAME)
+ if (COMPILER_BASENAME MATCHES "^(.+-)?(clang\\+\\+|g\\+\\+|clang-cl)(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$")
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ set(_CMAKE_TOOLCHAIN_SUFFIX ${CMAKE_MATCH_3})
+ set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_5})
+ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+ if(CMAKE_CXX_COMPILER_TARGET)
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_CXX_COMPILER_TARGET}-)
+ endif()
+ elseif(COMPILER_BASENAME MATCHES "QCC(\\.exe)?$")
+ if(CMAKE_CXX_COMPILER_TARGET MATCHES "gcc_nto([a-z0-9]+_[0-9]+|[^_le]+)(le)")
+ set(_CMAKE_TOOLCHAIN_PREFIX nto${CMAKE_MATCH_1}-)
+ endif()
+ endif ()
+
+ # if "llvm-" is part of the prefix, remove it, since llvm doesn't have its own binutils
+ # but uses the regular ar, objcopy, etc. (instead of llvm-objcopy etc.)
+ if ("${_CMAKE_TOOLCHAIN_PREFIX}" MATCHES "(.+-)?llvm-$")
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ endif ()
+ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "TI")
+ # TI compilers are named e.g. cl6x, cl470 or armcl.exe
+ get_filename_component(COMPILER_BASENAME "${CMAKE_CXX_COMPILER}" NAME)
+ if (COMPILER_BASENAME MATCHES "^(.+)?cl([^.]+)?(\\.exe)?$")
+ set(_CMAKE_TOOLCHAIN_PREFIX "${CMAKE_MATCH_1}")
+ set(_CMAKE_TOOLCHAIN_SUFFIX "${CMAKE_MATCH_2}")
+ endif ()
+
+ endif()
+
+endif ()
+
+set(_CMAKE_PROCESSING_LANGUAGE "CXX")
+include(CMakeFindBinUtils)
+include(Compiler/${CMAKE_CXX_COMPILER_ID}-FindBinUtils OPTIONAL)
+unset(_CMAKE_PROCESSING_LANGUAGE)
+
+if(CMAKE_CXX_COMPILER_SYSROOT)
+ string(CONCAT _SET_CMAKE_CXX_COMPILER_SYSROOT
+ "set(CMAKE_CXX_COMPILER_SYSROOT \"${CMAKE_CXX_COMPILER_SYSROOT}\")\n"
+ "set(CMAKE_COMPILER_SYSROOT \"${CMAKE_CXX_COMPILER_SYSROOT}\")")
+else()
+ set(_SET_CMAKE_CXX_COMPILER_SYSROOT "")
+endif()
+
+if(CMAKE_CXX_COMPILER_ARCHITECTURE_ID)
+ set(_SET_CMAKE_CXX_COMPILER_ARCHITECTURE_ID
+ "set(CMAKE_CXX_COMPILER_ARCHITECTURE_ID ${CMAKE_CXX_COMPILER_ARCHITECTURE_ID})")
+else()
+ set(_SET_CMAKE_CXX_COMPILER_ARCHITECTURE_ID "")
+endif()
+
+if(MSVC_CXX_ARCHITECTURE_ID)
+ set(SET_MSVC_CXX_ARCHITECTURE_ID
+ "set(MSVC_CXX_ARCHITECTURE_ID ${MSVC_CXX_ARCHITECTURE_ID})")
+endif()
+
+if(CMAKE_CXX_XCODE_ARCHS)
+ set(SET_CMAKE_XCODE_ARCHS
+ "set(CMAKE_XCODE_ARCHS \"${CMAKE_CXX_XCODE_ARCHS}\")")
+endif()
+
+# configure all variables set in this file
+configure_file(${CMAKE_ROOT}/Modules/CMakeCXXCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeCXXCompiler.cmake
+ @ONLY
+ )
+
+set(CMAKE_CXX_COMPILER_ENV_VAR "CXX")
diff --git a/Modules/CMakeDetermineCompileFeatures.cmake b/Modules/CMakeDetermineCompileFeatures.cmake
new file mode 100644
index 0000000..f767847
--- /dev/null
+++ b/Modules/CMakeDetermineCompileFeatures.cmake
@@ -0,0 +1,171 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+function(cmake_determine_compile_features lang)
+
+ if(lang STREQUAL C AND COMMAND cmake_record_c_compile_features)
+ message(CHECK_START "Detecting ${lang} compile features")
+
+ set(CMAKE_C90_COMPILE_FEATURES)
+ set(CMAKE_C99_COMPILE_FEATURES)
+ set(CMAKE_C11_COMPILE_FEATURES)
+ set(CMAKE_C17_COMPILE_FEATURES)
+ set(CMAKE_C23_COMPILE_FEATURES)
+
+ include("${CMAKE_ROOT}/Modules/Internal/FeatureTesting.cmake")
+
+ cmake_record_c_compile_features()
+
+ if(NOT _result EQUAL 0)
+ message(CHECK_FAIL "failed")
+ return()
+ endif()
+
+ if (CMAKE_C17_COMPILE_FEATURES AND CMAKE_C23_COMPILE_FEATURES)
+ list(REMOVE_ITEM CMAKE_C23_COMPILE_FEATURES ${CMAKE_C17_COMPILE_FEATURES})
+ endif()
+ if (CMAKE_C11_COMPILE_FEATURES AND CMAKE_C17_COMPILE_FEATURES)
+ list(REMOVE_ITEM CMAKE_C17_COMPILE_FEATURES ${CMAKE_C11_COMPILE_FEATURES})
+ endif()
+ if (CMAKE_C99_COMPILE_FEATURES AND CMAKE_C11_COMPILE_FEATURES)
+ list(REMOVE_ITEM CMAKE_C11_COMPILE_FEATURES ${CMAKE_C99_COMPILE_FEATURES})
+ endif()
+ if (CMAKE_C90_COMPILE_FEATURES AND CMAKE_C99_COMPILE_FEATURES)
+ list(REMOVE_ITEM CMAKE_C99_COMPILE_FEATURES ${CMAKE_C90_COMPILE_FEATURES})
+ endif()
+
+ if(NOT CMAKE_C_COMPILE_FEATURES)
+ set(CMAKE_C_COMPILE_FEATURES
+ ${CMAKE_C90_COMPILE_FEATURES}
+ ${CMAKE_C99_COMPILE_FEATURES}
+ ${CMAKE_C11_COMPILE_FEATURES}
+ ${CMAKE_C17_COMPILE_FEATURES}
+ ${CMAKE_C23_COMPILE_FEATURES}
+ )
+ endif()
+
+ set(CMAKE_C_COMPILE_FEATURES ${CMAKE_C_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_C90_COMPILE_FEATURES ${CMAKE_C90_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_C99_COMPILE_FEATURES ${CMAKE_C99_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_C11_COMPILE_FEATURES ${CMAKE_C11_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_C17_COMPILE_FEATURES ${CMAKE_C17_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_C23_COMPILE_FEATURES ${CMAKE_C23_COMPILE_FEATURES} PARENT_SCOPE)
+
+ message(CHECK_PASS "done")
+
+ elseif(lang STREQUAL CXX AND COMMAND cmake_record_cxx_compile_features)
+ message(CHECK_START "Detecting ${lang} compile features")
+
+ set(CMAKE_CXX98_COMPILE_FEATURES)
+ set(CMAKE_CXX11_COMPILE_FEATURES)
+ set(CMAKE_CXX14_COMPILE_FEATURES)
+ set(CMAKE_CXX17_COMPILE_FEATURES)
+ set(CMAKE_CXX20_COMPILE_FEATURES)
+ set(CMAKE_CXX23_COMPILE_FEATURES)
+
+ include("${CMAKE_ROOT}/Modules/Internal/FeatureTesting.cmake")
+
+ cmake_record_cxx_compile_features()
+
+ if(NOT _result EQUAL 0)
+ message(CHECK_FAIL "failed")
+ return()
+ endif()
+
+ if (CMAKE_CXX20_COMPILE_FEATURES AND CMAKE_CXX23_COMPILE_FEATURES)
+ list(REMOVE_ITEM CMAKE_CXX23_COMPILE_FEATURES ${CMAKE_CXX20_COMPILE_FEATURES})
+ endif()
+ if (CMAKE_CXX17_COMPILE_FEATURES AND CMAKE_CXX20_COMPILE_FEATURES)
+ list(REMOVE_ITEM CMAKE_CXX20_COMPILE_FEATURES ${CMAKE_CXX17_COMPILE_FEATURES})
+ endif()
+ if (CMAKE_CXX14_COMPILE_FEATURES AND CMAKE_CXX17_COMPILE_FEATURES)
+ list(REMOVE_ITEM CMAKE_CXX17_COMPILE_FEATURES ${CMAKE_CXX14_COMPILE_FEATURES})
+ endif()
+ if (CMAKE_CXX11_COMPILE_FEATURES AND CMAKE_CXX14_COMPILE_FEATURES)
+ list(REMOVE_ITEM CMAKE_CXX14_COMPILE_FEATURES ${CMAKE_CXX11_COMPILE_FEATURES})
+ endif()
+ if (CMAKE_CXX98_COMPILE_FEATURES AND CMAKE_CXX11_COMPILE_FEATURES)
+ list(REMOVE_ITEM CMAKE_CXX11_COMPILE_FEATURES ${CMAKE_CXX98_COMPILE_FEATURES})
+ endif()
+
+ if(NOT CMAKE_CXX_COMPILE_FEATURES)
+ set(CMAKE_CXX_COMPILE_FEATURES
+ ${CMAKE_CXX98_COMPILE_FEATURES}
+ ${CMAKE_CXX11_COMPILE_FEATURES}
+ ${CMAKE_CXX14_COMPILE_FEATURES}
+ ${CMAKE_CXX17_COMPILE_FEATURES}
+ ${CMAKE_CXX20_COMPILE_FEATURES}
+ ${CMAKE_CXX23_COMPILE_FEATURES}
+ )
+ endif()
+
+ set(CMAKE_CXX_COMPILE_FEATURES ${CMAKE_CXX_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_CXX98_COMPILE_FEATURES ${CMAKE_CXX98_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_CXX11_COMPILE_FEATURES ${CMAKE_CXX11_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_CXX14_COMPILE_FEATURES ${CMAKE_CXX14_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_CXX17_COMPILE_FEATURES ${CMAKE_CXX17_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_CXX20_COMPILE_FEATURES ${CMAKE_CXX20_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_CXX23_COMPILE_FEATURES ${CMAKE_CXX23_COMPILE_FEATURES} PARENT_SCOPE)
+
+ message(CHECK_PASS "done")
+
+ elseif(lang STREQUAL CUDA AND COMMAND cmake_record_cuda_compile_features)
+ message(CHECK_START "Detecting ${lang} compile features")
+
+ set(CMAKE_CUDA03_COMPILE_FEATURES)
+ set(CMAKE_CUDA11_COMPILE_FEATURES)
+ set(CMAKE_CUDA14_COMPILE_FEATURES)
+ set(CMAKE_CUDA17_COMPILE_FEATURES)
+ set(CMAKE_CUDA20_COMPILE_FEATURES)
+ set(CMAKE_CUDA23_COMPILE_FEATURES)
+
+ include("${CMAKE_ROOT}/Modules/Internal/FeatureTesting.cmake")
+
+ cmake_record_cuda_compile_features()
+
+ if(NOT _result EQUAL 0)
+ message(CHECK_FAIL "failed")
+ return()
+ endif()
+
+ if (CMAKE_CUDA20_COMPILE_FEATURES AND CMAKE_CUDA23_COMPILE_FEATURES)
+ list(REMOVE_ITEM CMAKE_CUDA23_COMPILE_FEATURES ${CMAKE_CUDA20_COMPILE_FEATURES})
+ endif()
+ if (CMAKE_CUDA17_COMPILE_FEATURES AND CMAKE_CUDA20_COMPILE_FEATURES)
+ list(REMOVE_ITEM CMAKE_CUDA20_COMPILE_FEATURES ${CMAKE_CUDA17_COMPILE_FEATURES})
+ endif()
+ if (CMAKE_CUDA14_COMPILE_FEATURES AND CMAKE_CUDA17_COMPILE_FEATURES)
+ list(REMOVE_ITEM CMAKE_CUDA17_COMPILE_FEATURES ${CMAKE_CUDA14_COMPILE_FEATURES})
+ endif()
+ if (CMAKE_CUDA11_COMPILE_FEATURES AND CMAKE_CUDA14_COMPILE_FEATURES)
+ list(REMOVE_ITEM CMAKE_CUDA14_COMPILE_FEATURES ${CMAKE_CUDA11_COMPILE_FEATURES})
+ endif()
+ if (CMAKE_CUDA03_COMPILE_FEATURES AND CMAKE_CUDA11_COMPILE_FEATURES)
+ list(REMOVE_ITEM CMAKE_CUDA11_COMPILE_FEATURES ${CMAKE_CUDA03_COMPILE_FEATURES})
+ endif()
+
+ if(NOT CMAKE_CUDA_COMPILE_FEATURES)
+ set(CMAKE_CUDA_COMPILE_FEATURES
+ ${CMAKE_CUDA03_COMPILE_FEATURES}
+ ${CMAKE_CUDA11_COMPILE_FEATURES}
+ ${CMAKE_CUDA14_COMPILE_FEATURES}
+ ${CMAKE_CUDA17_COMPILE_FEATURES}
+ ${CMAKE_CUDA20_COMPILE_FEATURES}
+ ${CMAKE_CUDA23_COMPILE_FEATURES}
+ )
+ endif()
+
+ set(CMAKE_CUDA_COMPILE_FEATURES ${CMAKE_CUDA_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_CUDA03_COMPILE_FEATURES ${CMAKE_CUDA03_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_CUDA11_COMPILE_FEATURES ${CMAKE_CUDA11_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_CUDA14_COMPILE_FEATURES ${CMAKE_CUDA14_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_CUDA17_COMPILE_FEATURES ${CMAKE_CUDA17_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_CUDA20_COMPILE_FEATURES ${CMAKE_CUDA20_COMPILE_FEATURES} PARENT_SCOPE)
+ set(CMAKE_CUDA23_COMPILE_FEATURES ${CMAKE_CUDA23_COMPILE_FEATURES} PARENT_SCOPE)
+
+ message(CHECK_PASS "done")
+
+ endif()
+
+endfunction()
diff --git a/Modules/CMakeDetermineCompiler.cmake b/Modules/CMakeDetermineCompiler.cmake
new file mode 100644
index 0000000..6430793
--- /dev/null
+++ b/Modules/CMakeDetermineCompiler.cmake
@@ -0,0 +1,166 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+macro(_cmake_find_compiler lang)
+ # Use already-enabled languages for reference.
+ get_property(_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
+ list(REMOVE_ITEM _languages "${lang}")
+
+ if(CMAKE_${lang}_COMPILER_INIT)
+ # Search only for the specified compiler.
+ set(CMAKE_${lang}_COMPILER_LIST "${CMAKE_${lang}_COMPILER_INIT}")
+ else()
+ # Re-order the compiler list with preferred vendors first.
+ set(_${lang}_COMPILER_LIST "${CMAKE_${lang}_COMPILER_LIST}")
+ set(CMAKE_${lang}_COMPILER_LIST "")
+ # Prefer vendors of compilers from reference languages.
+ foreach(l ${_languages})
+ list(APPEND CMAKE_${lang}_COMPILER_LIST
+ ${_${lang}_COMPILER_NAMES_${CMAKE_${l}_COMPILER_ID}})
+ endforeach()
+ # Prefer vendors based on the platform.
+ list(APPEND CMAKE_${lang}_COMPILER_LIST ${CMAKE_${lang}_COMPILER_NAMES})
+ # Append the rest of the list and remove duplicates.
+ list(APPEND CMAKE_${lang}_COMPILER_LIST ${_${lang}_COMPILER_LIST})
+ unset(_${lang}_COMPILER_LIST)
+ list(REMOVE_DUPLICATES CMAKE_${lang}_COMPILER_LIST)
+ if(CMAKE_${lang}_COMPILER_EXCLUDE)
+ list(REMOVE_ITEM CMAKE_${lang}_COMPILER_LIST
+ ${CMAKE_${lang}_COMPILER_EXCLUDE})
+ endif()
+ endif()
+
+ # Look for directories containing compilers of reference languages.
+ set(_${lang}_COMPILER_HINTS)
+ foreach(l ${_languages})
+ if(CMAKE_${l}_COMPILER AND IS_ABSOLUTE "${CMAKE_${l}_COMPILER}")
+ get_filename_component(_hint "${CMAKE_${l}_COMPILER}" PATH)
+ if(IS_DIRECTORY "${_hint}")
+ list(APPEND _${lang}_COMPILER_HINTS "${_hint}")
+ endif()
+ unset(_hint)
+ endif()
+ endforeach()
+
+ # Find the compiler.
+ if(_${lang}_COMPILER_HINTS)
+ # Prefer directories containing compilers of reference languages.
+ list(REMOVE_DUPLICATES _${lang}_COMPILER_HINTS)
+ find_program(CMAKE_${lang}_COMPILER
+ NAMES ${CMAKE_${lang}_COMPILER_LIST}
+ PATHS ${_${lang}_COMPILER_HINTS}
+ NO_DEFAULT_PATH
+ DOC "${lang} compiler")
+ endif()
+ if(CMAKE_HOST_WIN32 AND CMAKE_GENERATOR MATCHES "Ninja")
+ # On Windows command-line builds, the Makefile generators each imply
+ # a preferred compiler tool. The Ninja generator does not imply a
+ # compiler tool, so use the compiler that occurs first in PATH.
+ find_program(CMAKE_${lang}_COMPILER
+ NAMES ${CMAKE_${lang}_COMPILER_LIST}
+ NAMES_PER_DIR
+ DOC "${lang} compiler"
+ NO_PACKAGE_ROOT_PATH
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH
+ )
+ endif()
+ find_program(CMAKE_${lang}_COMPILER NAMES ${CMAKE_${lang}_COMPILER_LIST} DOC "${lang} compiler")
+ if(_CMAKE_${lang}_COMPILER_PATHS)
+ # As a last fall-back, search in language-specific paths
+ find_program(CMAKE_${lang}_COMPILER
+ NAMES ${CMAKE_${lang}_COMPILER_LIST}
+ NAMES_PER_DIR
+ PATHS ${_CMAKE_${lang}_COMPILER_PATHS}
+ DOC "${lang} compiler"
+ NO_DEFAULT_PATH
+ )
+ endif()
+ if(CMAKE_${lang}_COMPILER_INIT AND NOT CMAKE_${lang}_COMPILER)
+ set_property(CACHE CMAKE_${lang}_COMPILER PROPERTY VALUE "${CMAKE_${lang}_COMPILER_INIT}")
+ endif()
+ unset(_${lang}_COMPILER_HINTS)
+ unset(_languages)
+
+ # Look for a make tool provided by Xcode
+ if(CMAKE_HOST_APPLE)
+ macro(_query_xcrun compiler_name result_var_keyword result_var)
+ if(NOT "x${result_var_keyword}" STREQUAL "xRESULT_VAR")
+ message(FATAL_ERROR "Bad arguments to macro")
+ endif()
+ execute_process(COMMAND xcrun --find ${compiler_name}
+ OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE _xcrun_err)
+ set("${result_var}" "${_xcrun_out}")
+ endmacro()
+
+ set(xcrun_result)
+ if (CMAKE_${lang}_COMPILER MATCHES "^/usr/bin/(.+)$")
+ _query_xcrun("${CMAKE_MATCH_1}" RESULT_VAR xcrun_result)
+ elseif (CMAKE_${lang}_COMPILER STREQUAL "CMAKE_${lang}_COMPILER-NOTFOUND")
+ foreach(comp ${CMAKE_${lang}_COMPILER_LIST})
+ _query_xcrun("${comp}" RESULT_VAR xcrun_result)
+ if(xcrun_result)
+ break()
+ endif()
+ endforeach()
+ endif()
+ if (xcrun_result)
+ set_property(CACHE CMAKE_${lang}_COMPILER PROPERTY VALUE "${xcrun_result}")
+ endif()
+ endif()
+endmacro()
+
+macro(_cmake_find_compiler_path lang)
+ if(CMAKE_${lang}_COMPILER)
+ # we only get here if CMAKE_${lang}_COMPILER was specified using -D or a pre-made CMakeCache.txt
+ # (e.g. via ctest) or set in CMAKE_TOOLCHAIN_FILE
+ # if CMAKE_${lang}_COMPILER is a list, use the first item as
+ # CMAKE_${lang}_COMPILER and the rest as CMAKE_${lang}_COMPILER_ARG1
+ set(CMAKE_${lang}_COMPILER_ARG1 "${CMAKE_${lang}_COMPILER}")
+ list(POP_FRONT CMAKE_${lang}_COMPILER_ARG1 CMAKE_${lang}_COMPILER)
+ list(JOIN CMAKE_${lang}_COMPILER_ARG1 " " CMAKE_${lang}_COMPILER_ARG1)
+
+ # find the compiler in the PATH if necessary
+ # if compiler (and arguments) comes from cache then synchronize cache with updated CMAKE_<LANG>_COMPILER
+ get_filename_component(_CMAKE_USER_${lang}_COMPILER_PATH "${CMAKE_${lang}_COMPILER}" PATH)
+ if(NOT _CMAKE_USER_${lang}_COMPILER_PATH)
+ find_program(CMAKE_${lang}_COMPILER_WITH_PATH NAMES ${CMAKE_${lang}_COMPILER})
+ if(CMAKE_${lang}_COMPILER_WITH_PATH)
+ set(CMAKE_${lang}_COMPILER ${CMAKE_${lang}_COMPILER_WITH_PATH})
+ get_property(_CMAKE_${lang}_COMPILER_CACHED CACHE CMAKE_${lang}_COMPILER PROPERTY TYPE)
+ if(_CMAKE_${lang}_COMPILER_CACHED)
+ set(CMAKE_${lang}_COMPILER "${CMAKE_${lang}_COMPILER}" CACHE STRING "${lang} compiler" FORCE)
+ endif()
+ unset(_CMAKE_${lang}_COMPILER_CACHED)
+ endif()
+ unset(CMAKE_${lang}_COMPILER_WITH_PATH CACHE)
+ elseif (EXISTS ${CMAKE_${lang}_COMPILER})
+ get_property(_CMAKE_${lang}_COMPILER_CACHED CACHE CMAKE_${lang}_COMPILER PROPERTY TYPE)
+ if(_CMAKE_${lang}_COMPILER_CACHED)
+ set(CMAKE_${lang}_COMPILER "${CMAKE_${lang}_COMPILER}" CACHE STRING "${lang} compiler" FORCE)
+ endif()
+ unset(_CMAKE_${lang}_COMPILER_CACHED)
+ endif()
+ endif()
+endmacro()
+
+function(_cmake_find_compiler_sysroot lang)
+ if(CMAKE_${lang}_COMPILER_ID STREQUAL "GNU")
+ execute_process(COMMAND "${CMAKE_${lang}_COMPILER}" -print-sysroot
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ OUTPUT_VARIABLE _cmake_sysroot_run_out
+ ERROR_VARIABLE _cmake_sysroot_run_err)
+
+ if(_cmake_sysroot_run_out AND NOT _cmake_sysroot_run_err
+ AND NOT _cmake_sysroot_run_out STREQUAL "/"
+ AND IS_DIRECTORY "${_cmake_sysroot_run_out}/usr")
+ file(TO_CMAKE_PATH "${_cmake_sysroot_run_out}/usr" _cmake_sysroot_run_out_usr)
+ set(CMAKE_${lang}_COMPILER_SYSROOT "${_cmake_sysroot_run_out_usr}" PARENT_SCOPE)
+ else()
+ set(CMAKE_${lang}_COMPILER_SYSROOT "" PARENT_SCOPE)
+ endif()
+ endif()
+endfunction()
diff --git a/Modules/CMakeDetermineCompilerABI.cmake b/Modules/CMakeDetermineCompilerABI.cmake
new file mode 100644
index 0000000..8191d81
--- /dev/null
+++ b/Modules/CMakeDetermineCompilerABI.cmake
@@ -0,0 +1,192 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# Function to compile a source file to identify the compiler ABI.
+# This is used internally by CMake and should not be included by user
+# code.
+
+include(${CMAKE_ROOT}/Modules/CMakeParseImplicitIncludeInfo.cmake)
+include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake)
+include(${CMAKE_ROOT}/Modules/CMakeParseLibraryArchitecture.cmake)
+include(CMakeTestCompilerCommon)
+
+function(CMAKE_DETERMINE_COMPILER_ABI lang src)
+ if(NOT DEFINED CMAKE_${lang}_ABI_COMPILED)
+ message(CHECK_START "Detecting ${lang} compiler ABI info")
+
+ # Compile the ABI identification source.
+ set(BIN "${CMAKE_PLATFORM_INFO_DIR}/CMakeDetermineCompilerABI_${lang}.bin")
+ set(CMAKE_FLAGS )
+ set(COMPILE_DEFINITIONS )
+ if(DEFINED CMAKE_${lang}_VERBOSE_FLAG)
+ set(CMAKE_FLAGS "-DEXE_LINKER_FLAGS=${CMAKE_${lang}_VERBOSE_FLAG}")
+ set(COMPILE_DEFINITIONS "${CMAKE_${lang}_VERBOSE_FLAG}")
+ endif()
+ if(DEFINED CMAKE_${lang}_VERBOSE_COMPILE_FLAG)
+ set(COMPILE_DEFINITIONS "${CMAKE_${lang}_VERBOSE_COMPILE_FLAG}")
+ endif()
+ if(NOT "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xMSVC")
+ # Avoid adding our own platform standard libraries for compilers
+ # from which we might detect implicit link libraries.
+ list(APPEND CMAKE_FLAGS "-DCMAKE_${lang}_STANDARD_LIBRARIES=")
+ endif()
+ __TestCompiler_setTryCompileTargetType()
+
+ # Avoid failing ABI detection on warnings.
+ string(REGEX REPLACE "(^| )-Werror([= ][^ ]*)?( |$)" " " CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS}")
+
+ # Save the current LC_ALL, LC_MESSAGES, and LANG environment variables
+ # and set them to "C" that way GCC's "search starts here" text is in
+ # English and we can grok it.
+ set(_orig_lc_all $ENV{LC_ALL})
+ set(_orig_lc_messages $ENV{LC_MESSAGES})
+ set(_orig_lang $ENV{LANG})
+ set(ENV{LC_ALL} C)
+ set(ENV{LC_MESSAGES} C)
+ set(ENV{LANG} C)
+
+ try_compile(CMAKE_${lang}_ABI_COMPILED
+ ${CMAKE_BINARY_DIR} ${src}
+ CMAKE_FLAGS ${CMAKE_FLAGS}
+ # Ignore unused flags when we are just determining the ABI.
+ "--no-warn-unused-cli"
+ COMPILE_DEFINITIONS ${COMPILE_DEFINITIONS}
+ OUTPUT_VARIABLE OUTPUT
+ COPY_FILE "${BIN}"
+ COPY_FILE_ERROR _copy_error
+ __CMAKE_INTERNAL ABI
+ )
+
+ # Restore original LC_ALL, LC_MESSAGES, and LANG
+ set(ENV{LC_ALL} ${_orig_lc_all})
+ set(ENV{LC_MESSAGES} ${_orig_lc_messages})
+ set(ENV{LANG} ${_orig_lang})
+
+ # Move result from cache to normal variable.
+ set(CMAKE_${lang}_ABI_COMPILED ${CMAKE_${lang}_ABI_COMPILED})
+ unset(CMAKE_${lang}_ABI_COMPILED CACHE)
+ if(CMAKE_${lang}_ABI_COMPILED AND _copy_error)
+ set(CMAKE_${lang}_ABI_COMPILED 0)
+ endif()
+ set(CMAKE_${lang}_ABI_COMPILED ${CMAKE_${lang}_ABI_COMPILED} PARENT_SCOPE)
+
+ # Load the resulting information strings.
+ if(CMAKE_${lang}_ABI_COMPILED)
+ message(CHECK_PASS "done")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Detecting ${lang} compiler ABI info compiled with the following output:\n${OUTPUT}\n\n")
+ file(STRINGS "${BIN}" ABI_STRINGS LIMIT_COUNT 32 REGEX "INFO:[A-Za-z0-9_]+\\[[^]]*\\]")
+ set(ABI_SIZEOF_DPTR "NOTFOUND")
+ set(ABI_BYTE_ORDER "NOTFOUND")
+ set(ABI_NAME "NOTFOUND")
+ foreach(info ${ABI_STRINGS})
+ if("${info}" MATCHES "INFO:sizeof_dptr\\[0*([^]]*)\\]" AND NOT ABI_SIZEOF_DPTR)
+ set(ABI_SIZEOF_DPTR "${CMAKE_MATCH_1}")
+ endif()
+ if("${info}" MATCHES "INFO:byte_order\\[(BIG_ENDIAN|LITTLE_ENDIAN)\\]")
+ set(byte_order "${CMAKE_MATCH_1}")
+ if(ABI_BYTE_ORDER STREQUAL "NOTFOUND")
+ # Tentatively use the value because this is the first occurrence.
+ set(ABI_BYTE_ORDER "${byte_order}")
+ elseif(NOT ABI_BYTE_ORDER STREQUAL "${byte_order}")
+ # Drop value because multiple occurrences do not match.
+ set(ABI_BYTE_ORDER "")
+ endif()
+ endif()
+ if("${info}" MATCHES "INFO:abi\\[([^]]*)\\]" AND NOT ABI_NAME)
+ set(ABI_NAME "${CMAKE_MATCH_1}")
+ endif()
+ endforeach()
+
+ if(ABI_SIZEOF_DPTR)
+ set(CMAKE_${lang}_SIZEOF_DATA_PTR "${ABI_SIZEOF_DPTR}" PARENT_SCOPE)
+ elseif(CMAKE_${lang}_SIZEOF_DATA_PTR_DEFAULT)
+ set(CMAKE_${lang}_SIZEOF_DATA_PTR "${CMAKE_${lang}_SIZEOF_DATA_PTR_DEFAULT}" PARENT_SCOPE)
+ endif()
+
+ if(ABI_BYTE_ORDER)
+ set(CMAKE_${lang}_BYTE_ORDER "${ABI_BYTE_ORDER}" PARENT_SCOPE)
+ endif()
+
+ if(ABI_NAME)
+ set(CMAKE_${lang}_COMPILER_ABI "${ABI_NAME}" PARENT_SCOPE)
+ endif()
+
+ # Parse implicit include directory for this language, if available.
+ if(CMAKE_${lang}_VERBOSE_FLAG)
+ set (implicit_incdirs "")
+ cmake_parse_implicit_include_info("${OUTPUT}" "${lang}"
+ implicit_incdirs log rv)
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Parsed ${lang} implicit include dir info from above output: rv=${rv}\n${log}\n\n")
+ if("${rv}" STREQUAL "done")
+ # Entries that we have been told to explicitly pass as standard include
+ # directories will not be implicitly added by the compiler.
+ if(CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES)
+ list(REMOVE_ITEM implicit_incdirs ${CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES})
+ endif()
+
+ # We parsed implicit include directories, so override the default initializer.
+ set(_CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES_INIT "${implicit_incdirs}")
+ endif()
+ endif()
+ set(CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES "${_CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES_INIT}" PARENT_SCOPE)
+
+ # Parse implicit linker information for this language, if available.
+ set(implicit_dirs "")
+ set(implicit_objs "")
+ set(implicit_libs "")
+ set(implicit_fwks "")
+ if(CMAKE_${lang}_VERBOSE_FLAG)
+ CMAKE_PARSE_IMPLICIT_LINK_INFO("${OUTPUT}" implicit_libs implicit_dirs implicit_fwks log
+ "${CMAKE_${lang}_IMPLICIT_OBJECT_REGEX}"
+ COMPUTE_IMPLICIT_OBJECTS implicit_objs)
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Parsed ${lang} implicit link information from above output:\n${log}\n\n")
+ endif()
+ # for VS IDE Intel Fortran we have to figure out the
+ # implicit link path for the fortran run time using
+ # a try-compile
+ if("${lang}" MATCHES "Fortran"
+ AND "${CMAKE_GENERATOR}" MATCHES "Visual Studio")
+ message(CHECK_START "Determine Intel Fortran Compiler Implicit Link Path")
+ # Build a sample project which reports symbols.
+ try_compile(IFORT_LIB_PATH_COMPILED
+ ${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath
+ ${CMAKE_ROOT}/Modules/IntelVSImplicitPath
+ IntelFortranImplicit
+ CMAKE_FLAGS
+ "-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}"
+ OUTPUT_VARIABLE _output)
+ file(WRITE
+ "${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath/output.txt"
+ "${_output}")
+ include(${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath/output.cmake OPTIONAL)
+ message(CHECK_PASS "done")
+ endif()
+
+ # Implicit link libraries cannot be used explicitly for multiple
+ # OS X architectures, so we skip it.
+ if(DEFINED CMAKE_OSX_ARCHITECTURES)
+ if("${CMAKE_OSX_ARCHITECTURES}" MATCHES ";")
+ set(implicit_libs "")
+ endif()
+ endif()
+
+ set(CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES "${implicit_libs}" PARENT_SCOPE)
+ set(CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES "${implicit_dirs}" PARENT_SCOPE)
+ set(CMAKE_${lang}_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "${implicit_fwks}" PARENT_SCOPE)
+
+ cmake_parse_library_architecture(${lang} "${implicit_dirs}" "${implicit_objs}" architecture_flag)
+ if(architecture_flag)
+ set(CMAKE_${lang}_LIBRARY_ARCHITECTURE "${architecture_flag}" PARENT_SCOPE)
+ endif()
+
+ else()
+ message(CHECK_FAIL "failed")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Detecting ${lang} compiler ABI info failed to compile with the following output:\n${OUTPUT}\n${_copy_error}\n\n")
+ endif()
+ endif()
+endfunction()
diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake
new file mode 100644
index 0000000..d7b7f26
--- /dev/null
+++ b/Modules/CMakeDetermineCompilerId.cmake
@@ -0,0 +1,1090 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+macro(__determine_compiler_id_test testflags_var userflags_var)
+ separate_arguments(testflags UNIX_COMMAND "${${testflags_var}}")
+ CMAKE_DETERMINE_COMPILER_ID_BUILD("${lang}" "${testflags}" "${${userflags_var}}" "${src}")
+ CMAKE_DETERMINE_COMPILER_ID_MATCH_VENDOR("${lang}" "${COMPILER_${lang}_PRODUCED_OUTPUT}")
+
+ if(NOT CMAKE_${lang}_COMPILER_ID)
+ foreach(file ${COMPILER_${lang}_PRODUCED_FILES})
+ CMAKE_DETERMINE_COMPILER_ID_CHECK("${lang}" "${CMAKE_${lang}_COMPILER_ID_DIR}/${file}" "${src}")
+ endforeach()
+ endif()
+endmacro()
+
+# Function to compile a source file to identify the compiler. This is
+# used internally by CMake and should not be included by user code.
+# If successful, sets CMAKE_<lang>_COMPILER_ID and CMAKE_<lang>_PLATFORM_ID
+
+function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
+ # Make sure the compiler arguments are clean.
+ string(STRIP "${CMAKE_${lang}_COMPILER_ARG1}" CMAKE_${lang}_COMPILER_ID_ARG1)
+ string(REGEX REPLACE " +" ";" CMAKE_${lang}_COMPILER_ID_ARG1 "${CMAKE_${lang}_COMPILER_ID_ARG1}")
+
+ # Make sure user-specified compiler flags are used.
+ if(CMAKE_${lang}_FLAGS)
+ set(CMAKE_${lang}_COMPILER_ID_FLAGS ${CMAKE_${lang}_FLAGS})
+ elseif(DEFINED ENV{${flagvar}})
+ set(CMAKE_${lang}_COMPILER_ID_FLAGS $ENV{${flagvar}})
+ else(CMAKE_${lang}_FLAGS_INIT)
+ set(CMAKE_${lang}_COMPILER_ID_FLAGS ${CMAKE_${lang}_FLAGS_INIT})
+ endif()
+ string(REPLACE " " ";" CMAKE_${lang}_COMPILER_ID_FLAGS_LIST "${CMAKE_${lang}_COMPILER_ID_FLAGS}")
+
+ # Compute the directory in which to run the test.
+ set(CMAKE_${lang}_COMPILER_ID_DIR ${CMAKE_PLATFORM_INFO_DIR}/CompilerId${lang})
+
+ # If we REQUIRE_SUCCESS, i.e. TEST_FLAGS_FIRST has the correct flags, we still need to
+ # try two combinations: with COMPILER_ID_FLAGS (from user) and without (see issue #21869).
+ if(CMAKE_${lang}_COMPILER_ID_REQUIRE_SUCCESS)
+ # If there COMPILER_ID_FLAGS is empty we can error for the first invocation.
+ if("${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}" STREQUAL "")
+ set(__compiler_id_require_success TRUE)
+ endif()
+
+ foreach(userflags "${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}" "")
+ set(testflags "${CMAKE_${lang}_COMPILER_ID_TEST_FLAGS_FIRST}")
+ __determine_compiler_id_test(testflags userflags)
+ if(CMAKE_${lang}_COMPILER_ID)
+ break()
+ endif()
+ set(__compiler_id_require_success TRUE)
+ endforeach()
+ else()
+ # Try building with no extra flags and then try each set
+ # of helper flags. Stop when the compiler is identified.
+ foreach(userflags "${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}" "")
+ foreach(testflags ${CMAKE_${lang}_COMPILER_ID_TEST_FLAGS_FIRST} "" ${CMAKE_${lang}_COMPILER_ID_TEST_FLAGS})
+ __determine_compiler_id_test(testflags userflags)
+ if(CMAKE_${lang}_COMPILER_ID)
+ break()
+ endif()
+ endforeach()
+ if(CMAKE_${lang}_COMPILER_ID)
+ break()
+ endif()
+ endforeach()
+ endif()
+
+ # Check if compiler id detection gave us the compiler tool.
+ if(CMAKE_${lang}_COMPILER_ID_TOOL)
+ set(CMAKE_${lang}_COMPILER "${CMAKE_${lang}_COMPILER_ID_TOOL}")
+ set(CMAKE_${lang}_COMPILER "${CMAKE_${lang}_COMPILER_ID_TOOL}" PARENT_SCOPE)
+ elseif(NOT CMAKE_${lang}_COMPILER)
+ set(CMAKE_${lang}_COMPILER "CMAKE_${lang}_COMPILER-NOTFOUND" PARENT_SCOPE)
+ endif()
+
+ # If the compiler is still unknown, try to query its vendor.
+ if(CMAKE_${lang}_COMPILER AND NOT CMAKE_${lang}_COMPILER_ID)
+ foreach(userflags "${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}" "")
+ CMAKE_DETERMINE_COMPILER_ID_VENDOR(${lang} "${userflags}")
+ endforeach()
+ endif()
+
+ # If the compiler is still unknown, fallback to GHS
+ if(NOT CMAKE_${lang}_COMPILER_ID AND "${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
+ set(CMAKE_${lang}_COMPILER_ID GHS)
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "The ${lang} compiler identification is falling back to GHS.\n\n")
+ endif()
+
+ # CUDA < 7.5 is missing version macros
+ if(lang STREQUAL "CUDA"
+ AND CMAKE_${lang}_COMPILER_ID STREQUAL "NVIDIA"
+ AND NOT CMAKE_${lang}_COMPILER_VERSION)
+ execute_process(
+ COMMAND "${CMAKE_${lang}_COMPILER}"
+ --version
+ OUTPUT_VARIABLE output ERROR_VARIABLE output
+ RESULT_VARIABLE result
+ TIMEOUT 10
+ )
+ if(output MATCHES [=[ V([0-9]+)\.([0-9]+)\.([0-9]+)]=])
+ set(CMAKE_${lang}_COMPILER_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
+ endif()
+ endif()
+
+ # For Swift we need to explicitly query the version.
+ if(lang STREQUAL "Swift"
+ AND CMAKE_${lang}_COMPILER
+ AND NOT CMAKE_${lang}_COMPILER_VERSION)
+ execute_process(
+ COMMAND "${CMAKE_${lang}_COMPILER}"
+ -version
+ OUTPUT_VARIABLE output ERROR_VARIABLE output
+ RESULT_VARIABLE result
+ TIMEOUT 10
+ )
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Running the ${lang} compiler: \"${CMAKE_${lang}_COMPILER}\" -version\n"
+ "${output}\n"
+ )
+
+ if(output MATCHES [[Swift version ([0-9]+\.[0-9]+(\.[0-9]+)?)]])
+ set(CMAKE_${lang}_COMPILER_VERSION "${CMAKE_MATCH_1}")
+ if(NOT CMAKE_${lang}_COMPILER_ID)
+ set(CMAKE_Swift_COMPILER_ID "Apple")
+ endif()
+ endif()
+ endif()
+
+ # For ISPC we need to explicitly query the version.
+ if(lang STREQUAL "ISPC"
+ AND CMAKE_${lang}_COMPILER
+ AND NOT CMAKE_${lang}_COMPILER_VERSION)
+ execute_process(
+ COMMAND "${CMAKE_${lang}_COMPILER}"
+ --version
+ OUTPUT_VARIABLE output ERROR_VARIABLE output
+ RESULT_VARIABLE result
+ TIMEOUT 10
+ )
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Running the ${lang} compiler: \"${CMAKE_${lang}_COMPILER}\" -version\n"
+ "${output}\n"
+ )
+
+ if(output MATCHES [[ISPC\), ([0-9]+\.[0-9]+(\.[0-9]+)?)]])
+ set(CMAKE_${lang}_COMPILER_VERSION "${CMAKE_MATCH_1}")
+ endif()
+ endif()
+
+
+ if (COMPILER_QNXNTO AND CMAKE_${lang}_COMPILER_ID STREQUAL "GNU")
+ execute_process(
+ COMMAND "${CMAKE_${lang}_COMPILER}"
+ -V
+ OUTPUT_VARIABLE output ERROR_VARIABLE output
+ RESULT_VARIABLE result
+ TIMEOUT 10
+ )
+ if (output MATCHES "targets available")
+ set(CMAKE_${lang}_COMPILER_ID QCC)
+ # http://community.qnx.com/sf/discussion/do/listPosts/projects.community/discussion.qnx_momentics_community_support.topc3555?_pagenum=2
+ # The qcc driver does not itself have a version.
+ endif()
+ endif()
+
+ # The Fujitsu compiler does not always convey version information through
+ # preprocessor symbols so we extract through command line info
+ if (CMAKE_${lang}_COMPILER_ID STREQUAL "Fujitsu")
+ if(NOT CMAKE_${lang}_COMPILER_VERSION)
+ execute_process(
+ COMMAND "${CMAKE_${lang}_COMPILER}" -V
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE output
+ RESULT_VARIABLE result
+ TIMEOUT 10
+ )
+ if (result EQUAL 0)
+ if (output MATCHES [[Fujitsu [^ ]* Compiler ([0-9]+\.[0-9]+\.[0-9]+)]])
+ set(CMAKE_${lang}_COMPILER_VERSION "${CMAKE_MATCH_1}")
+ endif()
+ endif()
+ endif()
+ endif()
+
+ # if the format is unknown after all files have been checked, put "Unknown" in the cache
+ if(NOT CMAKE_EXECUTABLE_FORMAT)
+ set(CMAKE_EXECUTABLE_FORMAT "Unknown" CACHE INTERNAL "Executable file format")
+ endif()
+
+ if((CMAKE_GENERATOR MATCHES "^Ninja"
+ OR ((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"))
+ AND MSVC_${lang}_ARCHITECTURE_ID)
+ foreach(userflags "${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}" "")
+ CMAKE_DETERMINE_MSVC_SHOWINCLUDES_PREFIX(${lang} "${userflags}")
+ endforeach()
+ else()
+ set(CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX "")
+ endif()
+
+ set(_variant "")
+ if("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xClang"
+ OR "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xIntelLLVM")
+ if("x${CMAKE_${lang}_SIMULATE_ID}" STREQUAL "xMSVC")
+ if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "MSVC")
+ else()
+ # Test whether an MSVC-like command-line option works.
+ execute_process(COMMAND "${CMAKE_${lang}_COMPILER}" -?
+ RESULT_VARIABLE _clang_result
+ OUTPUT_VARIABLE _clang_stdout
+ ERROR_VARIABLE _clang_stderr)
+ if(_clang_result EQUAL 0)
+ set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "MSVC")
+ else()
+ set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "GNU")
+ endif()
+ endif()
+ set(_variant " with ${CMAKE_${lang}_COMPILER_FRONTEND_VARIANT}-like command-line")
+ else()
+ set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "GNU")
+ endif()
+ else()
+ set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "")
+ endif()
+
+ # Display the final identification result.
+ if(CMAKE_${lang}_COMPILER_ID)
+ if(CMAKE_${lang}_COMPILER_VERSION)
+ set(_version " ${CMAKE_${lang}_COMPILER_VERSION}")
+ else()
+ set(_version "")
+ endif()
+ if(CMAKE_${lang}_COMPILER_ARCHITECTURE_ID AND "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xIAR")
+ set(_archid " ${CMAKE_${lang}_COMPILER_ARCHITECTURE_ID}")
+ else()
+ set(_archid "")
+ endif()
+ message(STATUS "The ${lang} compiler identification is "
+ "${CMAKE_${lang}_COMPILER_ID}${_archid}${_version}${_variant}")
+ unset(_archid)
+ unset(_version)
+ unset(_variant)
+ else()
+ message(STATUS "The ${lang} compiler identification is unknown")
+ endif()
+
+ if(lang STREQUAL "Fortran" AND CMAKE_${lang}_COMPILER_ID STREQUAL "XL")
+ set(CMAKE_${lang}_XL_CPP "${CMAKE_${lang}_COMPILER_ID_CPP}" PARENT_SCOPE)
+ endif()
+
+ set(CMAKE_${lang}_COMPILER_ID "${CMAKE_${lang}_COMPILER_ID}" PARENT_SCOPE)
+ set(CMAKE_${lang}_PLATFORM_ID "${CMAKE_${lang}_PLATFORM_ID}" PARENT_SCOPE)
+ set(CMAKE_${lang}_COMPILER_ARCHITECTURE_ID "${CMAKE_${lang}_COMPILER_ARCHITECTURE_ID}" PARENT_SCOPE)
+ set(MSVC_${lang}_ARCHITECTURE_ID "${MSVC_${lang}_ARCHITECTURE_ID}"
+ PARENT_SCOPE)
+ set(CMAKE_${lang}_XCODE_ARCHS "${CMAKE_${lang}_XCODE_ARCHS}" PARENT_SCOPE)
+ set(CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX "${CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX}" PARENT_SCOPE)
+ set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "${CMAKE_${lang}_COMPILER_FRONTEND_VARIANT}" PARENT_SCOPE)
+ set(CMAKE_${lang}_COMPILER_VERSION "${CMAKE_${lang}_COMPILER_VERSION}" PARENT_SCOPE)
+ set(CMAKE_${lang}_COMPILER_VERSION_INTERNAL "${CMAKE_${lang}_COMPILER_VERSION_INTERNAL}" PARENT_SCOPE)
+ set(CMAKE_${lang}_COMPILER_WRAPPER "${CMAKE_${lang}_COMPILER_WRAPPER}" PARENT_SCOPE)
+ set(CMAKE_${lang}_SIMULATE_ID "${CMAKE_${lang}_SIMULATE_ID}" PARENT_SCOPE)
+ set(CMAKE_${lang}_SIMULATE_VERSION "${CMAKE_${lang}_SIMULATE_VERSION}" PARENT_SCOPE)
+ set(CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT "${CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT}" PARENT_SCOPE)
+ set(CMAKE_${lang}_COMPILER_PRODUCED_OUTPUT "${COMPILER_${lang}_PRODUCED_OUTPUT}" PARENT_SCOPE)
+ set(CMAKE_${lang}_COMPILER_PRODUCED_FILES "${COMPILER_${lang}_PRODUCED_FILES}" PARENT_SCOPE)
+endfunction()
+
+include(CMakeCompilerIdDetection)
+
+#-----------------------------------------------------------------------------
+# Function to write the compiler id source file.
+function(CMAKE_DETERMINE_COMPILER_ID_WRITE lang src)
+ find_file(src_in ${src}.in PATHS ${CMAKE_ROOT}/Modules ${CMAKE_MODULE_PATH} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+ file(READ ${src_in} ID_CONTENT_IN)
+
+ compiler_id_detection(CMAKE_${lang}_COMPILER_ID_CONTENT ${lang}
+ ID_STRING
+ VERSION_STRINGS
+ PLATFORM_DEFAULT_COMPILER
+ )
+
+ unset(src_in CACHE)
+ string(CONFIGURE "${ID_CONTENT_IN}" ID_CONTENT_OUT @ONLY)
+ file(WRITE ${CMAKE_${lang}_COMPILER_ID_DIR}/${src} "${ID_CONTENT_OUT}")
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to build the compiler id source file and look for output
+# files.
+function(CMAKE_DETERMINE_COMPILER_ID_BUILD lang testflags userflags src)
+ # Create a clean working directory.
+ file(REMOVE_RECURSE ${CMAKE_${lang}_COMPILER_ID_DIR})
+ file(MAKE_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR})
+ file(MAKE_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR}/tmp)
+ CMAKE_DETERMINE_COMPILER_ID_WRITE("${lang}" "${src}")
+
+ # Construct a description of this test case.
+ set(COMPILER_DESCRIPTION
+ "Compiler: ${CMAKE_${lang}_COMPILER} ${CMAKE_${lang}_COMPILER_ID_ARG1}
+Build flags: ${userflags}
+Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
+")
+
+ # Compile the compiler identification source.
+ if("${CMAKE_GENERATOR}" MATCHES "Visual Studio ([0-9]+)")
+ set(vs_version ${CMAKE_MATCH_1})
+ set(id_platform ${CMAKE_VS_PLATFORM_NAME})
+ set(id_lang "${lang}")
+ set(id_PostBuildEvent_Command "")
+ if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "^[Ll][Ll][Vv][Mm](_v[0-9]+(_xp)?)?$")
+ set(id_cl_var "ClangClExecutable")
+ elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "^[Cc][Ll][Aa][Nn][Gg]([Cc][Ll]$|_[0-9])")
+ set(id_cl "$(CLToolExe)")
+ elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
+ set(id_cl clang.exe)
+ # Executable names have choosen according documentation
+ # URL: (https://software.intel.com/content/www/us/en/develop/documentation/get-started-with-dpcpp-compiler/top.html#top_GUID-A9B4C91D-97AC-450D-9742-9D895BC8AEE1)
+ elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "Intel")
+ if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "DPC\\+\\+ Compiler")
+ set(id_cl dpcpp.exe)
+ elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "C\\+\\+ Compiler 2021")
+ set(id_cl icx.exe)
+ elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "C\\+\\+ Compiler")
+ set(id_cl icl.exe)
+ endif()
+ else()
+ set(id_cl cl.exe)
+ endif()
+ if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android")
+ set(v NsightTegra)
+ set(ext vcxproj)
+ if(lang STREQUAL CXX)
+ set(id_gcc g++)
+ set(id_clang clang++)
+ else()
+ set(id_gcc gcc)
+ set(id_clang clang)
+ endif()
+ elseif(lang STREQUAL Fortran)
+ set(v Intel)
+ set(ext vfproj)
+ set(id_cl ifort.exe)
+ elseif(lang STREQUAL CSharp)
+ set(v 10)
+ set(ext csproj)
+ set(id_cl csc.exe)
+ elseif(NOT "${vs_version}" VERSION_LESS 10)
+ set(v 10)
+ set(ext vcxproj)
+ else()
+ set(id_version ${vs_version}.00)
+ set(v 7)
+ set(ext vcproj)
+ endif()
+ if(CMAKE_VS_PLATFORM_TOOLSET)
+ if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android")
+ set(id_toolset "<NdkToolchainVersion>${CMAKE_VS_PLATFORM_TOOLSET}</NdkToolchainVersion>")
+ else()
+ set(id_toolset "<PlatformToolset>${CMAKE_VS_PLATFORM_TOOLSET}</PlatformToolset>")
+ if(CMAKE_VS_PLATFORM_TOOLSET_VERSION)
+ set(id_sep "\\")
+ if(CMAKE_VS_PLATFORM_TOOLSET_VERSION VERSION_GREATER_EQUAL "14.20")
+ if(EXISTS "${CMAKE_GENERATOR_INSTANCE}/VC/Auxiliary/Build.${CMAKE_VS_PLATFORM_TOOLSET_VERSION}/Microsoft.VCToolsVersion.${CMAKE_VS_PLATFORM_TOOLSET_VERSION}.props")
+ set(id_sep ".")
+ endif()
+ endif()
+ set(id_toolset_version_props "<Import Project=\"${CMAKE_GENERATOR_INSTANCE}\\VC\\Auxiliary\\Build${id_sep}${CMAKE_VS_PLATFORM_TOOLSET_VERSION}\\Microsoft.VCToolsVersion.${CMAKE_VS_PLATFORM_TOOLSET_VERSION}.props\" />")
+ unset(id_sep)
+ endif()
+ endif()
+ else()
+ set(id_toolset "")
+ set(id_toolset_version_props "")
+ endif()
+ if(CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE)
+ set(id_PreferredToolArchitecture "<PreferredToolArchitecture>${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}</PreferredToolArchitecture>")
+ else()
+ set(id_PreferredToolArchitecture "")
+ endif()
+ if(CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone")
+ set(id_keyword "Win32Proj")
+ set(id_system "<ApplicationType>Windows Phone</ApplicationType>")
+ elseif(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
+ set(id_keyword "Win32Proj")
+ set(id_system "<ApplicationType>Windows Store</ApplicationType>")
+ elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
+ set(id_keyword "Android")
+ set(id_system "<ApplicationType>Android</ApplicationType>")
+ else()
+ set(id_keyword "Win32Proj")
+ set(id_system "")
+ endif()
+ if(id_keyword STREQUAL "Android")
+ if(CMAKE_GENERATOR MATCHES "Visual Studio 14")
+ set(id_system_version "<ApplicationTypeRevision>2.0</ApplicationTypeRevision>")
+ elseif(CMAKE_GENERATOR MATCHES "Visual Studio 1[56]")
+ set(id_system_version "<ApplicationTypeRevision>3.0</ApplicationTypeRevision>")
+ else()
+ set(id_system_version "")
+ endif()
+ elseif(id_system AND CMAKE_SYSTEM_VERSION MATCHES "^([0-9]+\\.[0-9]+)")
+ set(id_system_version "<ApplicationTypeRevision>${CMAKE_MATCH_1}</ApplicationTypeRevision>")
+ else()
+ set(id_system_version "")
+ endif()
+ if(id_keyword STREQUAL "Android")
+ set(id_config_type "DynamicLibrary")
+ else()
+ set(id_config_type "Application")
+ endif()
+ if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION)
+ set(id_WindowsTargetPlatformVersion "<WindowsTargetPlatformVersion>${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}</WindowsTargetPlatformVersion>")
+ endif()
+ if(CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR)
+ set(id_ToolsetVCTargetsDir "<VCTargetsPath>${CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR}</VCTargetsPath>")
+ endif()
+ set(id_CustomGlobals "")
+ foreach(pair IN LISTS CMAKE_VS_GLOBALS)
+ if("${pair}" MATCHES "([^=]+)=(.*)$")
+ string(APPEND id_CustomGlobals "<${CMAKE_MATCH_1}>${CMAKE_MATCH_2}</${CMAKE_MATCH_1}>\n ")
+ endif()
+ endforeach()
+ if(id_keyword STREQUAL "Android")
+ set(id_WindowsSDKDesktopARMSupport "")
+ elseif(id_platform STREQUAL "ARM64")
+ set(id_WindowsSDKDesktopARMSupport "<WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support>")
+ elseif(id_platform STREQUAL "ARM")
+ set(id_WindowsSDKDesktopARMSupport "<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>")
+ else()
+ set(id_WindowsSDKDesktopARMSupport "")
+ endif()
+ if(CMAKE_VS_WINCE_VERSION)
+ set(id_entrypoint "mainACRTStartup")
+ if("${vs_version}" VERSION_LESS 9)
+ set(id_subsystem 9)
+ else()
+ set(id_subsystem 8)
+ endif()
+ else()
+ set(id_subsystem 1)
+ endif()
+ set(id_dir ${CMAKE_${lang}_COMPILER_ID_DIR})
+ set(id_src "${src}")
+ set(id_compile "ClCompile")
+ if(id_cl_var)
+ set(id_PostBuildEvent_Command "echo CMAKE_${lang}_COMPILER=$(${id_cl_var})")
+ else()
+ set(id_PostBuildEvent_Command "for %%i in (${id_cl}) do %40echo CMAKE_${lang}_COMPILER=%%~$PATH:i")
+ endif()
+ set(id_Import_props "")
+ set(id_Import_targets "")
+ set(id_ItemDefinitionGroup_entry "")
+ set(id_Link_AdditionalDependencies "")
+ if(lang STREQUAL CUDA)
+ if(NOT CMAKE_VS_PLATFORM_TOOLSET_CUDA)
+ message(FATAL_ERROR "No CUDA toolset found.")
+ endif()
+ set(cuda_tools "CUDA ${CMAKE_VS_PLATFORM_TOOLSET_CUDA}")
+ set(id_compile "CudaCompile")
+ if(CMAKE_VS_PLATFORM_NAME STREQUAL x64)
+ set(cuda_target "<TargetMachinePlatform>64</TargetMachinePlatform>")
+ endif()
+ foreach(arch ${CMAKE_CUDA_ARCHITECTURES})
+ string(REGEX MATCH "[0-9]+" arch_name "${arch}")
+ string(APPEND cuda_codegen "compute_${arch_name},sm_${arch_name};")
+ endforeach()
+ set(id_ItemDefinitionGroup_entry "<CudaCompile>${cuda_target}<AdditionalOptions>%(AdditionalOptions)-v</AdditionalOptions><CodeGeneration>${cuda_codegen}</CodeGeneration></CudaCompile>")
+ set(id_PostBuildEvent_Command [[echo CMAKE_CUDA_COMPILER=$(CudaToolkitBinDir)\nvcc.exe]])
+ if(CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR)
+ # check for legacy cuda custom toolkit folder structure
+ if(EXISTS ${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}nvcc)
+ set(id_CudaToolkitCustomDir "<CudaToolkitCustomDir>${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}nvcc</CudaToolkitCustomDir>")
+ else()
+ set(id_CudaToolkitCustomDir "<CudaToolkitCustomDir>${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}</CudaToolkitCustomDir>")
+ endif()
+ if(EXISTS ${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}CUDAVisualStudioIntegration)
+ string(CONCAT id_Import_props "<Import Project=\"${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}CUDAVisualStudioIntegration\\extras\\visual_studio_integration\\MSBuildExtensions\\${cuda_tools}.props\" />")
+ string(CONCAT id_Import_targets "<Import Project=\"${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}CUDAVisualStudioIntegration\\extras\\visual_studio_integration\\MSBuildExtensions\\${cuda_tools}.targets\" />")
+ else()
+ string(CONCAT id_Import_props "<Import Project=\"${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}\\extras\\visual_studio_integration\\MSBuildExtensions\\${cuda_tools}.props\" />")
+ string(CONCAT id_Import_targets "<Import Project=\"${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}\\extras\\visual_studio_integration\\MSBuildExtensions\\${cuda_tools}.targets\" />")
+ endif()
+ else()
+ string(CONCAT id_Import_props [[<Import Project="$(VCTargetsPath)\BuildCustomizations\]] "${cuda_tools}" [[.props" />]])
+ string(CONCAT id_Import_targets [[<Import Project="$(VCTargetsPath)\BuildCustomizations\]] "${cuda_tools}" [[.targets" />]])
+ endif()
+ if(CMAKE_CUDA_FLAGS MATCHES "(^| )-cudart +shared( |$)")
+ set(id_Link_AdditionalDependencies "<AdditionalDependencies>cudart.lib</AdditionalDependencies>")
+ else()
+ set(id_Link_AdditionalDependencies "<AdditionalDependencies>cudart_static.lib</AdditionalDependencies>")
+ endif()
+ endif()
+ configure_file(${CMAKE_ROOT}/Modules/CompilerId/VS-${v}.${ext}.in
+ ${id_dir}/CompilerId${lang}.${ext} @ONLY)
+ if(CMAKE_VS_MSBUILD_COMMAND AND NOT lang STREQUAL "Fortran")
+ set(command "${CMAKE_VS_MSBUILD_COMMAND}" "CompilerId${lang}.${ext}"
+ "/p:Configuration=Debug" "/p:Platform=${id_platform}" "/p:VisualStudioVersion=${vs_version}.0"
+ )
+ elseif(CMAKE_VS_DEVENV_COMMAND)
+ set(command "${CMAKE_VS_DEVENV_COMMAND}" "CompilerId${lang}.${ext}" "/build" "Debug")
+ else()
+ set(command "")
+ endif()
+ if(command)
+ execute_process(
+ COMMAND ${command}
+ WORKING_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR}
+ OUTPUT_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
+ ERROR_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
+ RESULT_VARIABLE CMAKE_${lang}_COMPILER_ID_RESULT
+ )
+ else()
+ set(CMAKE_${lang}_COMPILER_ID_RESULT 1)
+ set(CMAKE_${lang}_COMPILER_ID_OUTPUT "VS environment not known to support ${lang}")
+ endif()
+ # Match the compiler location line printed out.
+ if("${CMAKE_${lang}_COMPILER_ID_OUTPUT}" MATCHES "CMAKE_${lang}_COMPILER=([^%\r\n]+)[\r\n]")
+ # Strip VS diagnostic output from the end of the line.
+ string(REGEX REPLACE " \\(TaskId:[0-9]*\\)$" "" _comp "${CMAKE_MATCH_1}")
+ if(EXISTS "${_comp}")
+ file(TO_CMAKE_PATH "${_comp}" _comp)
+ set(CMAKE_${lang}_COMPILER_ID_TOOL "${_comp}" PARENT_SCOPE)
+ endif()
+ endif()
+ elseif("${CMAKE_GENERATOR}" MATCHES "Xcode")
+ set(id_lang "${lang}")
+ set(id_type ${CMAKE_${lang}_COMPILER_XCODE_TYPE})
+ set(id_dir ${CMAKE_${lang}_COMPILER_ID_DIR})
+ set(id_src "${src}")
+ if(CMAKE_XCODE_PLATFORM_TOOLSET)
+ set(id_toolset "GCC_VERSION = ${CMAKE_XCODE_PLATFORM_TOOLSET};")
+ else()
+ set(id_toolset "")
+ endif()
+ if("${lang}" STREQUAL "Swift")
+ if(CMAKE_Swift_LANGUAGE_VERSION)
+ set(id_lang_version "SWIFT_VERSION = ${CMAKE_Swift_LANGUAGE_VERSION};")
+ elseif(XCODE_VERSION VERSION_GREATER_EQUAL 10.2)
+ set(id_lang_version "SWIFT_VERSION = 4.0;")
+ elseif(XCODE_VERSION VERSION_GREATER_EQUAL 8.3)
+ set(id_lang_version "SWIFT_VERSION = 3.0;")
+ else()
+ set(id_lang_version "SWIFT_VERSION = 2.3;")
+ endif()
+ else()
+ set(id_lang_version "")
+ endif()
+ if(CMAKE_OSX_DEPLOYMENT_TARGET)
+ set(id_deployment_target
+ "MACOSX_DEPLOYMENT_TARGET = \"${CMAKE_OSX_DEPLOYMENT_TARGET}\";")
+ else()
+ set(id_deployment_target "")
+ endif()
+ set(id_product_type "com.apple.product-type.tool")
+ if(CMAKE_OSX_SYSROOT)
+ set(id_sdkroot "SDKROOT = \"${CMAKE_OSX_SYSROOT}\";")
+ if(CMAKE_OSX_SYSROOT MATCHES "(^|/)[Ii][Pp][Hh][Oo][Nn][Ee]" OR
+ CMAKE_OSX_SYSROOT MATCHES "(^|/)[Aa][Pp][Pp][Ll][Ee][Tt][Vv]")
+ set(id_product_type "com.apple.product-type.bundle.unit-test")
+ elseif(CMAKE_OSX_SYSROOT MATCHES "(^|/)[Ww][Aa][Tt][Cc][Hh]")
+ set(id_product_type "com.apple.product-type.framework")
+ endif()
+ else()
+ set(id_sdkroot "")
+ endif()
+ set(id_clang_cxx_library "")
+ set(stdlib_regex "(^| )(-stdlib=)([^ ]+)( |$)")
+ string(REGEX MATCHALL "${stdlib_regex}" all_stdlib_matches "${CMAKE_CXX_FLAGS}")
+ if(all_stdlib_matches)
+ list(GET all_stdlib_matches "-1" last_stdlib_match)
+ if(last_stdlib_match MATCHES "${stdlib_regex}")
+ set(id_clang_cxx_library "CLANG_CXX_LIBRARY = \"${CMAKE_MATCH_3}\";")
+ endif()
+ endif()
+ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_OSX_SYSROOT MATCHES "^$|[Mm][Aa][Cc][Oo][Ss]")
+ # When targeting macOS, use only the host architecture.
+ if (_CMAKE_APPLE_ARCHS_DEFAULT)
+ set(id_archs "ARCHS = \"${_CMAKE_APPLE_ARCHS_DEFAULT}\";")
+ set(id_arch_active "ONLY_ACTIVE_ARCH = NO;")
+ else()
+ set(id_archs [[ARCHS = "$(NATIVE_ARCH_ACTUAL)";]])
+ set(id_arch_active "ONLY_ACTIVE_ARCH = YES;")
+ endif()
+ else()
+ set(id_archs "")
+ set(id_arch_active "ONLY_ACTIVE_ARCH = YES;")
+ endif()
+ configure_file(${CMAKE_ROOT}/Modules/CompilerId/Xcode-3.pbxproj.in
+ ${id_dir}/CompilerId${lang}.xcodeproj/project.pbxproj @ONLY)
+ unset(_ENV_MACOSX_DEPLOYMENT_TARGET)
+ if(DEFINED ENV{MACOSX_DEPLOYMENT_TARGET})
+ set(_ENV_MACOSX_DEPLOYMENT_TARGET "$ENV{MACOSX_DEPLOYMENT_TARGET}")
+ set(ENV{MACOSX_DEPLOYMENT_TARGET} "")
+ endif()
+ execute_process(COMMAND xcodebuild
+ WORKING_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR}
+ OUTPUT_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
+ ERROR_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
+ RESULT_VARIABLE CMAKE_${lang}_COMPILER_ID_RESULT
+ )
+ if(DEFINED _ENV_MACOSX_DEPLOYMENT_TARGET)
+ set(ENV{MACOSX_DEPLOYMENT_TARGET} "${_ENV_MACOSX_DEPLOYMENT_TARGET}")
+ endif()
+
+ if(DEFINED CMAKE_${lang}_COMPILER_ID_TOOL_MATCH_REGEX)
+ if("${CMAKE_${lang}_COMPILER_ID_OUTPUT}" MATCHES "${CMAKE_${lang}_COMPILER_ID_TOOL_MATCH_REGEX}")
+ set(_comp "${CMAKE_MATCH_${CMAKE_${lang}_COMPILER_ID_TOOL_MATCH_INDEX}}")
+ if(EXISTS "${_comp}")
+ set(CMAKE_${lang}_COMPILER_ID_TOOL "${_comp}" PARENT_SCOPE)
+ endif()
+ endif()
+ endif()
+ if("${CMAKE_${lang}_COMPILER_ID_OUTPUT}" MATCHES "ARCHS=([^%\r\n]+)[\r\n]")
+ set(CMAKE_${lang}_XCODE_ARCHS "${CMAKE_MATCH_1}")
+ separate_arguments(CMAKE_${lang}_XCODE_ARCHS)
+ set(CMAKE_${lang}_XCODE_ARCHS "${CMAKE_${lang}_XCODE_ARCHS}" PARENT_SCOPE)
+ endif()
+ elseif("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
+ set(id_dir ${CMAKE_${lang}_COMPILER_ID_DIR})
+ set(id_src "${src}")
+ if (GHS_PRIMARY_TARGET)
+ set(ghs_primary_target "${GHS_PRIMARY_TARGET}")
+ else()
+ set(ghs_primary_target "${CMAKE_GENERATOR_PLATFORM}_${GHS_TARGET_PLATFORM}.tgt")
+ endif()
+ if ("${GHS_TARGET_PLATFORM}" MATCHES "integrity")
+ set(bsp_name "macro GHS_BSP=${GHS_BSP_NAME}")
+ set(os_dir "macro GHS_OS=${GHS_OS_DIR}")
+ endif()
+ set(command "${CMAKE_MAKE_PROGRAM}" "-commands" "-top" "GHS_default.gpj")
+ configure_file(${CMAKE_ROOT}/Modules/CompilerId/GHS_default.gpj.in
+ ${id_dir}/GHS_default.gpj @ONLY)
+ configure_file(${CMAKE_ROOT}/Modules/CompilerId/GHS_lib.gpj.in
+ ${id_dir}/GHS_lib.gpj @ONLY)
+ execute_process(COMMAND ${command}
+ WORKING_DIRECTORY ${id_dir}
+ OUTPUT_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
+ ERROR_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
+ RESULT_VARIABLE CMAKE_${lang}_COMPILER_ID_RESULT
+ )
+ # Match the compiler location line printed out.
+ set(ghs_toolpath "${CMAKE_MAKE_PROGRAM}")
+ if(CMAKE_HOST_UNIX)
+ string(REPLACE "/gbuild" "/" ghs_toolpath ${ghs_toolpath})
+ else()
+ string(REPLACE "/gbuild.exe" "/" ghs_toolpath ${ghs_toolpath})
+ string(REPLACE / "\\\\" ghs_toolpath ${ghs_toolpath})
+ endif()
+ if("${CMAKE_${lang}_COMPILER_ID_OUTPUT}" MATCHES "(${ghs_toolpath}[^ ]*)")
+ if(CMAKE_HOST_UNIX)
+ set(_comp "${CMAKE_MATCH_1}")
+ else()
+ set(_comp "${CMAKE_MATCH_1}.exe")
+ endif()
+ if(EXISTS "${_comp}")
+ file(TO_CMAKE_PATH "${_comp}" _comp)
+ set(CMAKE_${lang}_COMPILER_ID_TOOL "${_comp}" PARENT_SCOPE)
+ endif()
+ endif()
+ else()
+ execute_process(
+ COMMAND "${CMAKE_${lang}_COMPILER}"
+ ${CMAKE_${lang}_COMPILER_ID_ARG1}
+ ${userflags}
+ ${testflags}
+ ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
+ "${src}"
+ WORKING_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR}
+ OUTPUT_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
+ ERROR_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
+ RESULT_VARIABLE CMAKE_${lang}_COMPILER_ID_RESULT
+ )
+ if("${CMAKE_${lang}_COMPILER_ID_OUTPUT}" MATCHES "exec: [^\n]*\\((/[^,\n]*/cpp),CMakeFortranCompilerId.F")
+ set(_cpp "${CMAKE_MATCH_1}")
+ if(EXISTS "${_cpp}")
+ set(CMAKE_${lang}_COMPILER_ID_CPP "${_cpp}" PARENT_SCOPE)
+ endif()
+ endif()
+ endif()
+
+ # Check the result of compilation.
+ if(CMAKE_${lang}_COMPILER_ID_RESULT
+ # Intel Fortran warns and ignores preprocessor lines without /fpp
+ OR CMAKE_${lang}_COMPILER_ID_OUTPUT MATCHES "Bad # preprocessor line"
+ )
+ # Compilation failed.
+ set(MSG
+ "Compiling the ${lang} compiler identification source file \"${src}\" failed.
+${COMPILER_DESCRIPTION}
+The output was:
+${CMAKE_${lang}_COMPILER_ID_RESULT}
+${CMAKE_${lang}_COMPILER_ID_OUTPUT}
+
+")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "${MSG}")
+
+ # Some languages may know the correct/desired set of flags and want to fail right away if they don't work.
+ # This is currently only used by CUDA.
+ if(__compiler_id_require_success)
+ message(FATAL_ERROR "${MSG}")
+ endif()
+
+ # No output files should be inspected.
+ set(COMPILER_${lang}_PRODUCED_FILES)
+ set(COMPILER_${lang}_PRODUCED_OUTPUT)
+ else()
+ # Compilation succeeded.
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Compiling the ${lang} compiler identification source file \"${src}\" succeeded.
+${COMPILER_DESCRIPTION}
+The output was:
+${CMAKE_${lang}_COMPILER_ID_RESULT}
+${CMAKE_${lang}_COMPILER_ID_OUTPUT}
+
+")
+
+ # Find the executable produced by the compiler, try all files in the
+ # binary dir.
+ string(REGEX REPLACE "([][])" "[\\1]" _glob_id_dir "${CMAKE_${lang}_COMPILER_ID_DIR}")
+ file(GLOB files
+ RELATIVE ${CMAKE_${lang}_COMPILER_ID_DIR}
+
+ # normal case
+ ${_glob_id_dir}/*
+
+ # com.apple.package-type.bundle.unit-test
+ ${_glob_id_dir}/*.xctest/*
+
+ # com.apple.product-type.framework
+ ${_glob_id_dir}/*.framework/*
+ )
+ list(REMOVE_ITEM files "${src}")
+ set(COMPILER_${lang}_PRODUCED_FILES "")
+ foreach(file ${files})
+ if(NOT IS_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR}/${file})
+ list(APPEND COMPILER_${lang}_PRODUCED_FILES ${file})
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Compilation of the ${lang} compiler identification source \""
+ "${src}\" produced \"${file}\"\n\n")
+ endif()
+ endforeach()
+
+ if(NOT COMPILER_${lang}_PRODUCED_FILES)
+ # No executable was found.
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Compilation of the ${lang} compiler identification source \""
+ "${src}\" did not produce an executable in \""
+ "${CMAKE_${lang}_COMPILER_ID_DIR}\".\n\n")
+ endif()
+
+ set(COMPILER_${lang}_PRODUCED_OUTPUT "${CMAKE_${lang}_COMPILER_ID_OUTPUT}")
+ endif()
+
+ # Return the files produced by the compilation.
+ set(COMPILER_${lang}_PRODUCED_FILES "${COMPILER_${lang}_PRODUCED_FILES}" PARENT_SCOPE)
+ set(COMPILER_${lang}_PRODUCED_OUTPUT "${COMPILER_${lang}_PRODUCED_OUTPUT}" PARENT_SCOPE)
+
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to extract the compiler id from compiler output.
+function(CMAKE_DETERMINE_COMPILER_ID_MATCH_VENDOR lang output)
+ foreach(vendor ${CMAKE_${lang}_COMPILER_ID_MATCH_VENDORS})
+ if(output MATCHES "${CMAKE_${lang}_COMPILER_ID_MATCH_VENDOR_REGEX_${vendor}}")
+ set(CMAKE_${lang}_COMPILER_ID "${vendor}")
+ endif()
+ endforeach()
+ set(CMAKE_${lang}_COMPILER_ID "${CMAKE_${lang}_COMPILER_ID}" PARENT_SCOPE)
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to extract the compiler id from an executable.
+function(CMAKE_DETERMINE_COMPILER_ID_CHECK lang file)
+ # Look for a compiler id if not yet known.
+ if(NOT CMAKE_${lang}_COMPILER_ID)
+ # Read the compiler identification string from the executable file.
+ set(COMPILER_ID)
+ set(COMPILER_VERSION)
+ set(COMPILER_VERSION_MAJOR 0)
+ set(COMPILER_VERSION_MINOR 0)
+ set(COMPILER_VERSION_PATCH 0)
+ set(COMPILER_VERSION_TWEAK 0)
+ set(COMPILER_VERSION_INTERNAL "")
+ set(HAVE_COMPILER_VERSION_MAJOR 0)
+ set(HAVE_COMPILER_VERSION_MINOR 0)
+ set(HAVE_COMPILER_VERSION_PATCH 0)
+ set(HAVE_COMPILER_VERSION_TWEAK 0)
+ set(COMPILER_WRAPPER)
+ set(DIGIT_VALUE_1 1)
+ set(DIGIT_VALUE_2 10)
+ set(DIGIT_VALUE_3 100)
+ set(DIGIT_VALUE_4 1000)
+ set(DIGIT_VALUE_5 10000)
+ set(DIGIT_VALUE_6 100000)
+ set(DIGIT_VALUE_7 1000000)
+ set(DIGIT_VALUE_8 10000000)
+ set(PLATFORM_ID)
+ set(ARCHITECTURE_ID)
+ set(SIMULATE_ID)
+ set(SIMULATE_VERSION)
+ foreach(encoding "" "ENCODING;UTF-16LE" "ENCODING;UTF-16BE")
+ file(STRINGS "${file}" CMAKE_${lang}_COMPILER_ID_STRINGS
+ LIMIT_COUNT 38 ${encoding}
+ REGEX ".?I.?N.?F.?O.?:.?[A-Za-z0-9_]+\\[[^]]*\\]")
+ if(NOT CMAKE_${lang}_COMPILER_ID_STRINGS STREQUAL "")
+ break()
+ endif()
+ endforeach()
+
+ # With the IAR Compiler, some strings are found twice, first time as incomplete
+ # list like "?<Constant "INFO:compiler[IAR]">". Remove the incomplete copies.
+ list(FILTER CMAKE_${lang}_COMPILER_ID_STRINGS EXCLUDE REGEX "\\?<Constant \\\"")
+
+ # The IAR-AVR compiler uses a binary format that places a '6'
+ # character (0x34) before each character in the string. Strip
+ # out these characters without removing any legitimate characters.
+ if(CMAKE_${lang}_COMPILER_ID_STRINGS MATCHES "(.)I.N.F.O.:.")
+ string(REGEX REPLACE "${CMAKE_MATCH_1}([^;])" "\\1"
+ CMAKE_${lang}_COMPILER_ID_STRINGS "${CMAKE_${lang}_COMPILER_ID_STRINGS}")
+ endif()
+
+ # Remove arbitrary text that may appear before or after each INFO string.
+ string(REGEX MATCHALL "INFO:[A-Za-z0-9_]+\\[([^]\"]*)\\]"
+ CMAKE_${lang}_COMPILER_ID_STRINGS "${CMAKE_${lang}_COMPILER_ID_STRINGS}")
+
+ # In C# binaries, some strings are found more than once.
+ list(REMOVE_DUPLICATES CMAKE_${lang}_COMPILER_ID_STRINGS)
+
+ set(COMPILER_ID_TWICE)
+ foreach(info ${CMAKE_${lang}_COMPILER_ID_STRINGS})
+ if("${info}" MATCHES "INFO:compiler\\[([^]\"]*)\\]")
+ if(COMPILER_ID)
+ set(COMPILER_ID_TWICE 1)
+ endif()
+ set(COMPILER_ID "${CMAKE_MATCH_1}")
+ endif()
+ if("${info}" MATCHES "INFO:platform\\[([^]\"]*)\\]")
+ set(PLATFORM_ID "${CMAKE_MATCH_1}")
+ endif()
+ if("${info}" MATCHES "INFO:arch\\[([^]\"]*)\\]")
+ set(ARCHITECTURE_ID "${CMAKE_MATCH_1}")
+ endif()
+ if("${info}" MATCHES "INFO:compiler_version\\[([^]\"]*)\\]")
+ string(REGEX REPLACE "^0+([0-9]+)" "\\1" COMPILER_VERSION "${CMAKE_MATCH_1}")
+ string(REGEX REPLACE "\\.0+([0-9])" ".\\1" COMPILER_VERSION "${COMPILER_VERSION}")
+ endif()
+ if("${info}" MATCHES "INFO:compiler_version_internal\\[([^]\"]*)\\]")
+ set(COMPILER_VERSION_INTERNAL "${CMAKE_MATCH_1}")
+ string(REGEX REPLACE "^0+([0-9]+)" "\\1" COMPILER_VERSION_INTERNAL "${COMPILER_VERSION_INTERNAL}")
+ string(REGEX REPLACE "\\.0+([0-9]+)" ".\\1" COMPILER_VERSION_INTERNAL "${COMPILER_VERSION_INTERNAL}")
+ string(STRIP "${COMPILER_VERSION_INTERNAL}" COMPILER_VERSION_INTERNAL)
+ endif()
+ foreach(comp MAJOR MINOR PATCH TWEAK)
+ foreach(digit 1 2 3 4 5 6 7 8 9)
+ if("${info}" MATCHES "INFO:compiler_version_${comp}_digit_${digit}\\[([0-9])\\]")
+ set(value ${CMAKE_MATCH_1})
+ math(EXPR COMPILER_VERSION_${comp} "${COMPILER_VERSION_${comp}} + ${value} * ${DIGIT_VALUE_${digit}}")
+ set(HAVE_COMPILER_VERSION_${comp} 1)
+ endif()
+ endforeach()
+ endforeach()
+ if("${info}" MATCHES "INFO:compiler_wrapper\\[([^]\"]*)\\]")
+ set(COMPILER_WRAPPER "${CMAKE_MATCH_1}")
+ endif()
+ if("${info}" MATCHES "INFO:simulate\\[([^]\"]*)\\]")
+ set(SIMULATE_ID "${CMAKE_MATCH_1}")
+ endif()
+ if("${info}" MATCHES "INFO:simulate_version\\[([^]\"]*)\\]")
+ string(REGEX REPLACE "^0+([0-9])" "\\1" SIMULATE_VERSION "${CMAKE_MATCH_1}")
+ string(REGEX REPLACE "\\.0+([0-9])" ".\\1" SIMULATE_VERSION "${SIMULATE_VERSION}")
+ endif()
+ if("${info}" MATCHES "INFO:qnxnto\\[\\]")
+ set(COMPILER_QNXNTO 1)
+ endif()
+ if("${info}" MATCHES "INFO:dialect_default\\[([^]\"]*)\\]")
+ set(CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT "${CMAKE_MATCH_1}")
+ endif()
+ endforeach()
+
+ # Construct compiler version from components if needed.
+ if(NOT DEFINED COMPILER_VERSION AND HAVE_COMPILER_VERSION_MAJOR)
+ set(COMPILER_VERSION "${COMPILER_VERSION_MAJOR}")
+ if(HAVE_COMPILER_VERSION_MINOR)
+ string(APPEND COMPILER_VERSION ".${COMPILER_VERSION_MINOR}")
+ if(HAVE_COMPILER_VERSION_PATCH)
+ string(APPEND COMPILER_VERSION ".${COMPILER_VERSION_PATCH}")
+ if(HAVE_COMPILER_VERSION_TWEAK)
+ string(APPEND COMPILER_VERSION ".${COMPILER_VERSION_TWEAK}")
+ endif()
+ endif()
+ endif()
+ endif()
+
+ # Detect the exact architecture from the PE header.
+ if(WIN32)
+ # The offset to the PE signature is stored at 0x3c.
+ file(READ ${file} peoffsethex LIMIT 1 OFFSET 60 HEX)
+ if(NOT peoffsethex STREQUAL "")
+ string(SUBSTRING "${peoffsethex}" 0 1 peoffsethex1)
+ string(SUBSTRING "${peoffsethex}" 1 1 peoffsethex2)
+ set(peoffsetexpression "${peoffsethex1} * 16 + ${peoffsethex2}")
+ string(REPLACE "a" "10" peoffsetexpression "${peoffsetexpression}")
+ string(REPLACE "b" "11" peoffsetexpression "${peoffsetexpression}")
+ string(REPLACE "c" "12" peoffsetexpression "${peoffsetexpression}")
+ string(REPLACE "d" "13" peoffsetexpression "${peoffsetexpression}")
+ string(REPLACE "e" "14" peoffsetexpression "${peoffsetexpression}")
+ string(REPLACE "f" "15" peoffsetexpression "${peoffsetexpression}")
+ math(EXPR peoffset "${peoffsetexpression}")
+
+ file(READ ${file} peheader LIMIT 6 OFFSET ${peoffset} HEX)
+ if(peheader STREQUAL "50450000a201")
+ set(ARCHITECTURE_ID "SH3")
+ elseif(peheader STREQUAL "50450000a301")
+ set(ARCHITECTURE_ID "SH3DSP")
+ elseif(peheader STREQUAL "50450000a601")
+ set(ARCHITECTURE_ID "SH4")
+ elseif(peheader STREQUAL "50450000a801")
+ set(ARCHITECTURE_ID "SH5")
+ endif()
+ endif()
+ endif()
+
+ # Check if a valid compiler and platform were found.
+ if(COMPILER_ID AND NOT COMPILER_ID_TWICE)
+ set(CMAKE_${lang}_COMPILER_ID "${COMPILER_ID}")
+ set(CMAKE_${lang}_PLATFORM_ID "${PLATFORM_ID}")
+ set(CMAKE_${lang}_COMPILER_ARCHITECTURE_ID "${ARCHITECTURE_ID}")
+ set(MSVC_${lang}_ARCHITECTURE_ID "${ARCHITECTURE_ID}")
+ set(CMAKE_${lang}_COMPILER_VERSION "${COMPILER_VERSION}")
+ set(CMAKE_${lang}_COMPILER_VERSION_INTERNAL "${COMPILER_VERSION_INTERNAL}")
+ set(CMAKE_${lang}_SIMULATE_ID "${SIMULATE_ID}")
+ set(CMAKE_${lang}_SIMULATE_VERSION "${SIMULATE_VERSION}")
+ endif()
+
+ # Check the compiler identification string.
+ if(CMAKE_${lang}_COMPILER_ID)
+ # The compiler identification was found.
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "The ${lang} compiler identification is ${CMAKE_${lang}_COMPILER_ID}, found in \""
+ "${file}\"\n\n")
+ else()
+ # The compiler identification could not be found.
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "The ${lang} compiler identification could not be found in \""
+ "${file}\"\n\n")
+ endif()
+ endif()
+
+ # try to figure out the executable format: ELF, COFF, Mach-O
+ if(NOT CMAKE_EXECUTABLE_FORMAT)
+ file(READ ${file} CMAKE_EXECUTABLE_MAGIC LIMIT 4 HEX)
+
+ # ELF files start with 0x7f"ELF"
+ if("${CMAKE_EXECUTABLE_MAGIC}" STREQUAL "7f454c46")
+ set(CMAKE_EXECUTABLE_FORMAT "ELF" CACHE INTERNAL "Executable file format")
+ endif()
+
+# # COFF (.exe) files start with "MZ"
+# if("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "4d5a....")
+# set(CMAKE_EXECUTABLE_FORMAT "COFF" CACHE INTERNAL "Executable file format")
+# endif()
+#
+ # Mach-O files start with MH_MAGIC or MH_CIGAM
+ if("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "feedface|cefaedfe|feedfacf|cffaedfe")
+ set(CMAKE_EXECUTABLE_FORMAT "MACHO" CACHE INTERNAL "Executable file format")
+ endif()
+
+ # XCOFF files start with 0x01 followed by 0xDF (32-bit) or 0xF7 (64-bit).
+ if("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "^01(df|f7)")
+ set(CMAKE_EXECUTABLE_FORMAT "XCOFF" CACHE INTERNAL "Executable file format")
+ endif()
+
+ endif()
+ if(NOT DEFINED CMAKE_EXECUTABLE_FORMAT)
+ set(CMAKE_EXECUTABLE_FORMAT)
+ endif()
+ # Return the information extracted.
+ set(CMAKE_${lang}_COMPILER_ID "${CMAKE_${lang}_COMPILER_ID}" PARENT_SCOPE)
+ set(CMAKE_${lang}_PLATFORM_ID "${CMAKE_${lang}_PLATFORM_ID}" PARENT_SCOPE)
+ set(CMAKE_${lang}_COMPILER_ARCHITECTURE_ID "${CMAKE_${lang}_COMPILER_ARCHITECTURE_ID}" PARENT_SCOPE)
+ set(MSVC_${lang}_ARCHITECTURE_ID "${MSVC_${lang}_ARCHITECTURE_ID}"
+ PARENT_SCOPE)
+ set(CMAKE_${lang}_COMPILER_VERSION "${CMAKE_${lang}_COMPILER_VERSION}" PARENT_SCOPE)
+ set(CMAKE_${lang}_COMPILER_VERSION_INTERNAL "${CMAKE_${lang}_COMPILER_VERSION_INTERNAL}" PARENT_SCOPE)
+ set(CMAKE_${lang}_COMPILER_WRAPPER "${COMPILER_WRAPPER}" PARENT_SCOPE)
+ set(CMAKE_${lang}_SIMULATE_ID "${CMAKE_${lang}_SIMULATE_ID}" PARENT_SCOPE)
+ set(CMAKE_${lang}_SIMULATE_VERSION "${CMAKE_${lang}_SIMULATE_VERSION}" PARENT_SCOPE)
+ set(CMAKE_EXECUTABLE_FORMAT "${CMAKE_EXECUTABLE_FORMAT}" PARENT_SCOPE)
+ set(COMPILER_QNXNTO "${COMPILER_QNXNTO}" PARENT_SCOPE)
+ set(CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT "${CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT}" PARENT_SCOPE)
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to query the compiler vendor.
+# This uses a table with entries of the form
+# list(APPEND CMAKE_${lang}_COMPILER_ID_VENDORS ${vendor})
+# set(CMAKE_${lang}_COMPILER_ID_VENDOR_FLAGS_${vendor} -some-vendor-flag)
+# set(CMAKE_${lang}_COMPILER_ID_VENDOR_REGEX_${vendor} "Some Vendor Output")
+# We try running the compiler with the flag for each vendor and
+# matching its regular expression in the output.
+function(CMAKE_DETERMINE_COMPILER_ID_VENDOR lang userflags)
+
+ if(NOT CMAKE_${lang}_COMPILER_ID_DIR)
+ # We get here when this function is called not from within CMAKE_DETERMINE_COMPILER_ID()
+ # This is done e.g. for detecting the compiler ID for assemblers.
+ # Compute the directory in which to run the test and Create a clean working directory.
+ set(CMAKE_${lang}_COMPILER_ID_DIR ${CMAKE_PLATFORM_INFO_DIR}/CompilerId${lang})
+ file(REMOVE_RECURSE ${CMAKE_${lang}_COMPILER_ID_DIR})
+ file(MAKE_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR})
+ endif()
+
+ # Save the current LC_ALL, LC_MESSAGES, and LANG environment variables
+ # and set them to "C" so we get the expected output to match.
+ set(_orig_lc_all $ENV{LC_ALL})
+ set(_orig_lc_messages $ENV{LC_MESSAGES})
+ set(_orig_lang $ENV{LANG})
+ set(ENV{LC_ALL} C)
+ set(ENV{LC_MESSAGES} C)
+ set(ENV{LANG} C)
+
+ foreach(vendor ${CMAKE_${lang}_COMPILER_ID_VENDORS})
+ set(flags ${CMAKE_${lang}_COMPILER_ID_VENDOR_FLAGS_${vendor}})
+ set(regex ${CMAKE_${lang}_COMPILER_ID_VENDOR_REGEX_${vendor}})
+ execute_process(
+ COMMAND "${CMAKE_${lang}_COMPILER}"
+ ${CMAKE_${lang}_COMPILER_ID_ARG1}
+ ${userflags}
+ ${flags}
+ WORKING_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR}
+ OUTPUT_VARIABLE output ERROR_VARIABLE output
+ RESULT_VARIABLE result
+ TIMEOUT 10
+ )
+
+ if("${output}" MATCHES "${regex}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Checking whether the ${lang} compiler is ${vendor} using \"${flags}\" "
+ "matched \"${regex}\":\n${output}")
+ set(CMAKE_${lang}_COMPILER_ID "${vendor}" PARENT_SCOPE)
+ set(CMAKE_${lang}_COMPILER_ID_OUTPUT "${output}" PARENT_SCOPE)
+ set(CMAKE_${lang}_COMPILER_ID_VENDOR_MATCH "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ break()
+ else()
+ if("${result}" MATCHES "timeout")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Checking whether the ${lang} compiler is ${vendor} using \"${flags}\" "
+ "terminated after 10 s due to timeout.")
+ else()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Checking whether the ${lang} compiler is ${vendor} using \"${flags}\" "
+ "did not match \"${regex}\":\n${output}")
+ endif()
+ endif()
+ endforeach()
+
+ # Restore original LC_ALL, LC_MESSAGES, and LANG
+ set(ENV{LC_ALL} ${_orig_lc_all})
+ set(ENV{LC_MESSAGES} ${_orig_lc_messages})
+ set(ENV{LANG} ${_orig_lang})
+endfunction()
+
+function(CMAKE_DETERMINE_MSVC_SHOWINCLUDES_PREFIX lang userflags)
+ # Run this MSVC-compatible compiler to detect what the /showIncludes
+ # option displays. We can use a C source even with the C++ compiler
+ # because MSVC-compatible compilers handle both and show the same output.
+ set(showdir ${CMAKE_BINARY_DIR}/CMakeFiles/ShowIncludes)
+ file(WRITE ${showdir}/foo.h "\n")
+ file(WRITE ${showdir}/main.c "#include \"foo.h\" \nint main(){}\n")
+ execute_process(
+ COMMAND "${CMAKE_${lang}_COMPILER}"
+ ${CMAKE_${lang}_COMPILER_ID_ARG1}
+ ${userflags}
+ /nologo /showIncludes /c main.c
+ WORKING_DIRECTORY ${showdir}
+ OUTPUT_VARIABLE out
+ ERROR_VARIABLE err
+ RESULT_VARIABLE res
+ ENCODING AUTO # cl prints in current code page
+ )
+ if(res EQUAL 0 AND "${out}" MATCHES "(^|\n)([^:\n]*:[^:\n]*:[ \t]*)")
+ set(CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX "${CMAKE_MATCH_2}" PARENT_SCOPE)
+ else()
+ set(CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX "" PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/Modules/CMakeDetermineFortranCompiler.cmake b/Modules/CMakeDetermineFortranCompiler.cmake
new file mode 100644
index 0000000..d7d032c
--- /dev/null
+++ b/Modules/CMakeDetermineFortranCompiler.cmake
@@ -0,0 +1,307 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# determine the compiler to use for Fortran programs
+# NOTE, a generator may set CMAKE_Fortran_COMPILER before
+# loading this file to force a compiler.
+# use environment variable FC first if defined by user, next use
+# the cmake variable CMAKE_GENERATOR_FC which can be defined by a generator
+# as a default compiler
+
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
+include(Platform/${CMAKE_SYSTEM_NAME}-Determine-Fortran OPTIONAL)
+include(Platform/${CMAKE_SYSTEM_NAME}-Fortran OPTIONAL)
+if(NOT CMAKE_Fortran_COMPILER_NAMES)
+ set(CMAKE_Fortran_COMPILER_NAMES f95)
+endif()
+
+if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
+elseif("${CMAKE_GENERATOR}" MATCHES "Xcode")
+ set(CMAKE_Fortran_COMPILER_XCODE_TYPE sourcecode.fortran.f90)
+ _cmake_find_compiler_path(Fortran)
+else()
+ if(NOT CMAKE_Fortran_COMPILER)
+ # prefer the environment variable CC
+ if(NOT $ENV{FC} STREQUAL "")
+ get_filename_component(CMAKE_Fortran_COMPILER_INIT $ENV{FC} PROGRAM PROGRAM_ARGS CMAKE_Fortran_FLAGS_ENV_INIT)
+ if(CMAKE_Fortran_FLAGS_ENV_INIT)
+ set(CMAKE_Fortran_COMPILER_ARG1 "${CMAKE_Fortran_FLAGS_ENV_INIT}" CACHE STRING "Arguments to Fortran compiler")
+ endif()
+ if(EXISTS ${CMAKE_Fortran_COMPILER_INIT})
+ else()
+ message(FATAL_ERROR "Could not find compiler set in environment variable FC:\n$ENV{FC}.")
+ endif()
+ endif()
+
+ # next try prefer the compiler specified by the generator
+ if(CMAKE_GENERATOR_FC)
+ if(NOT CMAKE_Fortran_COMPILER_INIT)
+ set(CMAKE_Fortran_COMPILER_INIT ${CMAKE_GENERATOR_FC})
+ endif()
+ endif()
+
+ # finally list compilers to try
+ if(NOT CMAKE_Fortran_COMPILER_INIT)
+ # Known compilers:
+ # f77/f90/f95: generic compiler names
+ # ftn: Cray fortran compiler wrapper
+ # g77: GNU Fortran 77 compiler
+ # gfortran: putative GNU Fortran 95+ compiler (in progress)
+ # fort77: native F77 compiler under HP-UX (and some older Crays)
+ # frt: Fujitsu F77 compiler
+ # pathf90/pathf95/pathf2003: PathScale Fortran compiler
+ # pgf77/pgf90/pgf95/pgfortran: Portland Group F77/F90/F95 compilers
+ # flang: Flang Fortran compiler
+ # xlf/xlf90/xlf95: IBM (AIX) F77/F90/F95 compilers
+ # lf95: Lahey-Fujitsu F95 compiler
+ # fl32: Microsoft Fortran 77 "PowerStation" compiler
+ # af77: Apogee F77 compiler for Intergraph hardware running CLIX
+ # epcf90: "Edinburgh Portable Compiler" F90
+ # fort: Compaq (now HP) Fortran 90/95 compiler for Tru64 and Linux/Alpha
+ # ifx: Intel Fortran LLVM-based compiler
+ # ifort: Intel Classic Fortran compiler
+ # ifc: Intel Fortran 95 compiler for Linux/x86
+ # efc: Intel Fortran 95 compiler for IA64
+ # nagfor: NAG Fortran compiler
+ #
+ # The order is 95 or newer compilers first, then 90,
+ # then 77 or older compilers, gnu is always last in the group,
+ # so if you paid for a compiler it is picked by default.
+ if(CMAKE_HOST_WIN32)
+ set(CMAKE_Fortran_COMPILER_LIST
+ ifort ifx pgf95 pgfortran lf95 fort
+ flang gfortran gfortran-4 g95 f90 pgf90
+ pgf77 g77 f77 nag
+ )
+ else()
+ set(CMAKE_Fortran_COMPILER_LIST
+ ftn
+ ifort ifc ifx efc pgf95 pgfortran lf95 xlf95 fort
+ flang gfortran gfortran-4 g95 f90 pgf90
+ frt pgf77 xlf g77 f77 nag
+ )
+ endif()
+
+ # Vendor-specific compiler names.
+ set(_Fortran_COMPILER_NAMES_GNU gfortran gfortran-4 g95 g77)
+ set(_Fortran_COMPILER_NAMES_Intel ifort ifc efc ifx)
+ set(_Fortran_COMPILER_NAMES_Absoft af95 af90 af77)
+ set(_Fortran_COMPILER_NAMES_PGI pgf95 pgfortran pgf90 pgf77)
+ set(_Fortran_COMPILER_NAMES_Flang flang)
+ set(_Fortran_COMPILER_NAMES_PathScale pathf2003 pathf95 pathf90)
+ set(_Fortran_COMPILER_NAMES_XL xlf)
+ set(_Fortran_COMPILER_NAMES_VisualAge xlf95 xlf90 xlf)
+ set(_Fortran_COMPILER_NAMES_NAG nagfor)
+ endif()
+
+ _cmake_find_compiler(Fortran)
+
+ else()
+ _cmake_find_compiler_path(Fortran)
+ endif()
+ mark_as_advanced(CMAKE_Fortran_COMPILER)
+
+ # Each entry in this list is a set of extra flags to try
+ # adding to the compile line to see if it helps produce
+ # a valid identification executable.
+ set(CMAKE_Fortran_COMPILER_ID_TEST_FLAGS_FIRST
+ # Get verbose output to help distinguish compilers.
+ "-v"
+ )
+ set(CMAKE_Fortran_COMPILER_ID_TEST_FLAGS
+ # Try compiling to an object file only.
+ "-c"
+
+ # Intel on windows does not preprocess by default.
+ "-fpp"
+ )
+endif()
+
+# Build a small source file to identify the compiler.
+if(NOT CMAKE_Fortran_COMPILER_ID_RUN)
+ set(CMAKE_Fortran_COMPILER_ID_RUN 1)
+
+ # Table of per-vendor compiler output regular expressions.
+ list(APPEND CMAKE_Fortran_COMPILER_ID_MATCH_VENDORS CCur)
+ set(CMAKE_Fortran_COMPILER_ID_MATCH_VENDOR_REGEX_CCur "Concurrent Fortran [0-9]+ Compiler")
+
+ # Table of per-vendor compiler id flags with expected output.
+ list(APPEND CMAKE_Fortran_COMPILER_ID_VENDORS Compaq)
+ set(CMAKE_Fortran_COMPILER_ID_VENDOR_FLAGS_Compaq "-what")
+ set(CMAKE_Fortran_COMPILER_ID_VENDOR_REGEX_Compaq "Compaq Visual Fortran")
+ list(APPEND CMAKE_Fortran_COMPILER_ID_VENDORS NAG) # Numerical Algorithms Group
+ set(CMAKE_Fortran_COMPILER_ID_VENDOR_FLAGS_NAG "-V")
+ set(CMAKE_Fortran_COMPILER_ID_VENDOR_REGEX_NAG "NAG Fortran Compiler")
+
+ # Match the link line from xcodebuild output of the form
+ # Ld ...
+ # ...
+ # /path/to/cc ...CompilerIdFortran/...
+ # to extract the compiler front-end for the language.
+ set(CMAKE_Fortran_COMPILER_ID_TOOL_MATCH_REGEX "\nLd[^\n]*(\n[ \t]+[^\n]*)*\n[ \t]+([^ \t\r\n]+)[^\r\n]*-o[^\r\n]*CompilerIdFortran/(\\./)?(CompilerIdFortran.xctest/)?CompilerIdFortran[ \t\n\\\"]")
+ set(CMAKE_Fortran_COMPILER_ID_TOOL_MATCH_INDEX 2)
+
+ set(_version_info "")
+ foreach(m MAJOR MINOR PATCH TWEAK)
+ set(_COMP "_${m}")
+ string(APPEND _version_info "
+#if defined(COMPILER_VERSION${_COMP})")
+ foreach(d 1 2 3 4 5 6 7 8)
+ string(APPEND _version_info "
+# undef DEC
+# undef HEX
+# define DEC(n) DEC_${d}(n)
+# define HEX(n) HEX_${d}(n)
+# if COMPILER_VERSION${_COMP} == 0
+ PRINT *, 'INFO:compiler_version${_COMP}_digit_${d}[0]'
+# elif COMPILER_VERSION${_COMP} == 1
+ PRINT *, 'INFO:compiler_version${_COMP}_digit_${d}[1]'
+# elif COMPILER_VERSION${_COMP} == 2
+ PRINT *, 'INFO:compiler_version${_COMP}_digit_${d}[2]'
+# elif COMPILER_VERSION${_COMP} == 3
+ PRINT *, 'INFO:compiler_version${_COMP}_digit_${d}[3]'
+# elif COMPILER_VERSION${_COMP} == 4
+ PRINT *, 'INFO:compiler_version${_COMP}_digit_${d}[4]'
+# elif COMPILER_VERSION${_COMP} == 5
+ PRINT *, 'INFO:compiler_version${_COMP}_digit_${d}[5]'
+# elif COMPILER_VERSION${_COMP} == 6
+ PRINT *, 'INFO:compiler_version${_COMP}_digit_${d}[6]'
+# elif COMPILER_VERSION${_COMP} == 7
+ PRINT *, 'INFO:compiler_version${_COMP}_digit_${d}[7]'
+# elif COMPILER_VERSION${_COMP} == 8
+ PRINT *, 'INFO:compiler_version${_COMP}_digit_${d}[8]'
+# elif COMPILER_VERSION${_COMP} == 9
+ PRINT *, 'INFO:compiler_version${_COMP}_digit_${d}[9]'
+# endif
+")
+ endforeach()
+ string(APPEND _version_info "
+#endif")
+ endforeach()
+ set(CMAKE_Fortran_COMPILER_ID_VERSION_INFO "${_version_info}")
+ unset(_version_info)
+ unset(_COMP)
+
+ # Try to identify the compiler.
+ set(CMAKE_Fortran_COMPILER_ID)
+ include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
+ CMAKE_DETERMINE_COMPILER_ID(Fortran FFLAGS CMakeFortranCompilerId.F)
+
+ _cmake_find_compiler_sysroot(Fortran)
+
+ # Fall back to old is-GNU test.
+ if(NOT CMAKE_Fortran_COMPILER_ID)
+ execute_process(COMMAND ${CMAKE_Fortran_COMPILER} ${CMAKE_Fortran_COMPILER_ID_FLAGS_LIST} -E "${CMAKE_ROOT}/Modules/CMakeTestGNU.c"
+ OUTPUT_VARIABLE CMAKE_COMPILER_OUTPUT RESULT_VARIABLE CMAKE_COMPILER_RETURN)
+ if(NOT CMAKE_COMPILER_RETURN)
+ if(CMAKE_COMPILER_OUTPUT MATCHES "THIS_IS_GNU")
+ set(CMAKE_Fortran_COMPILER_ID "GNU")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the Fortran compiler is GNU succeeded with "
+ "the following output:\n${CMAKE_COMPILER_OUTPUT}\n\n")
+ else()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the Fortran compiler is GNU failed with "
+ "the following output:\n${CMAKE_COMPILER_OUTPUT}\n\n")
+ endif()
+ if(NOT CMAKE_Fortran_PLATFORM_ID)
+ if(CMAKE_COMPILER_OUTPUT MATCHES "THIS_IS_MINGW")
+ set(CMAKE_Fortran_PLATFORM_ID "MinGW")
+ endif()
+ if(CMAKE_COMPILER_OUTPUT MATCHES "THIS_IS_CYGWIN")
+ set(CMAKE_Fortran_PLATFORM_ID "Cygwin")
+ endif()
+ endif()
+ endif()
+ endif()
+
+ # Fall back for GNU MINGW, which is not always detected correctly
+ # (__MINGW32__ is defined for the C language, but perhaps not for Fortran!)
+ if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU" AND NOT CMAKE_Fortran_PLATFORM_ID)
+ execute_process(COMMAND ${CMAKE_Fortran_COMPILER} ${CMAKE_Fortran_COMPILER_ID_FLAGS_LIST} -E "${CMAKE_ROOT}/Modules/CMakeTestGNU.c"
+ OUTPUT_VARIABLE CMAKE_COMPILER_OUTPUT RESULT_VARIABLE CMAKE_COMPILER_RETURN)
+ if(NOT CMAKE_COMPILER_RETURN)
+ if(CMAKE_COMPILER_OUTPUT MATCHES "THIS_IS_MINGW")
+ set(CMAKE_Fortran_PLATFORM_ID "MinGW")
+ endif()
+ if(CMAKE_COMPILER_OUTPUT MATCHES "THIS_IS_CYGWIN")
+ set(CMAKE_Fortran_PLATFORM_ID "Cygwin")
+ endif()
+ endif()
+ endif()
+
+ # Set old compiler and platform id variables.
+ if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU")
+ set(CMAKE_COMPILER_IS_GNUG77 1)
+ endif()
+ if(CMAKE_Fortran_PLATFORM_ID MATCHES "MinGW")
+ set(CMAKE_COMPILER_IS_MINGW 1)
+ elseif(CMAKE_Fortran_PLATFORM_ID MATCHES "Cygwin")
+ set(CMAKE_COMPILER_IS_CYGWIN 1)
+ endif()
+endif()
+
+if (NOT _CMAKE_TOOLCHAIN_LOCATION)
+ get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_Fortran_COMPILER}" PATH)
+endif ()
+
+# if we have a fortran cross compiler, they have usually some prefix, like
+# e.g. powerpc-linux-gfortran, arm-elf-gfortran or i586-mingw32msvc-gfortran , optionally
+# with a 3-component version number at the end (e.g. arm-eabi-gcc-4.5.2).
+# The other tools of the toolchain usually have the same prefix
+# NAME_WE cannot be used since then this test will fail for names like
+# "arm-unknown-nto-qnx6.3.0-gcc.exe", where BASENAME would be
+# "arm-unknown-nto-qnx6" instead of the correct "arm-unknown-nto-qnx6.3.0-"
+if (NOT _CMAKE_TOOLCHAIN_PREFIX)
+
+ if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU")
+ get_filename_component(COMPILER_BASENAME "${CMAKE_Fortran_COMPILER}" NAME)
+ if (COMPILER_BASENAME MATCHES "^(.+-)g?fortran(-[0-9]+\\.[0-9]+\\.[0-9]+)?(\\.exe)?$")
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ endif ()
+
+ # if "llvm-" is part of the prefix, remove it, since llvm doesn't have its own binutils
+ # but uses the regular ar, objcopy, etc. (instead of llvm-objcopy etc.)
+ if ("${_CMAKE_TOOLCHAIN_PREFIX}" MATCHES "(.+-)?llvm-$")
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ endif ()
+ endif()
+
+endif ()
+
+set(_CMAKE_PROCESSING_LANGUAGE "Fortran")
+include(CMakeFindBinUtils)
+include(Compiler/${CMAKE_Fortran_COMPILER_ID}-FindBinUtils OPTIONAL)
+unset(_CMAKE_PROCESSING_LANGUAGE)
+
+if(CMAKE_Fortran_XL_CPP)
+ set(_SET_CMAKE_Fortran_XL_CPP
+ "set(CMAKE_Fortran_XL_CPP \"${CMAKE_Fortran_XL_CPP}\")")
+endif()
+
+if(CMAKE_Fortran_COMPILER_SYSROOT)
+ string(CONCAT _SET_CMAKE_Fortran_COMPILER_SYSROOT
+ "set(CMAKE_Fortran_COMPILER_SYSROOT \"${CMAKE_Fortran_COMPILER_SYSROOT}\")\n"
+ "set(CMAKE_COMPILER_SYSROOT \"${CMAKE_Fortran_COMPILER_SYSROOT}\")")
+else()
+ set(_SET_CMAKE_Fortran_COMPILER_SYSROOT "")
+endif()
+
+if(CMAKE_Fortran_COMPILER_ARCHITECTURE_ID)
+ set(_SET_CMAKE_Fortran_COMPILER_ARCHITECTURE_ID
+ "set(CMAKE_Fortran_COMPILER_ARCHITECTURE_ID ${CMAKE_Fortran_COMPILER_ARCHITECTURE_ID})")
+else()
+ set(_SET_CMAKE_Fortran_COMPILER_ARCHITECTURE_ID "")
+endif()
+
+if(MSVC_Fortran_ARCHITECTURE_ID)
+ set(SET_MSVC_Fortran_ARCHITECTURE_ID
+ "set(MSVC_Fortran_ARCHITECTURE_ID ${MSVC_Fortran_ARCHITECTURE_ID})")
+endif()
+# configure variables set in this file for fast reload later on
+configure_file(${CMAKE_ROOT}/Modules/CMakeFortranCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeFortranCompiler.cmake
+ @ONLY
+ )
+set(CMAKE_Fortran_COMPILER_ENV_VAR "FC")
diff --git a/Modules/CMakeDetermineISPCCompiler.cmake b/Modules/CMakeDetermineISPCCompiler.cmake
new file mode 100644
index 0000000..ff2bf20
--- /dev/null
+++ b/Modules/CMakeDetermineISPCCompiler.cmake
@@ -0,0 +1,96 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# determine the compiler to use for ISPC programs
+
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
+
+if( NOT (("${CMAKE_GENERATOR}" MATCHES "Make") OR ("${CMAKE_GENERATOR}" MATCHES "Ninja")) )
+ message(FATAL_ERROR "ISPC language not currently supported by \"${CMAKE_GENERATOR}\" generator")
+endif()
+
+# Load system-specific compiler preferences for this language.
+include(Platform/${CMAKE_SYSTEM_NAME}-Determine-ISPC OPTIONAL)
+include(Platform/${CMAKE_SYSTEM_NAME}-ISPC OPTIONAL)
+if(NOT CMAKE_ISPC_COMPILER_NAMES)
+ set(CMAKE_ISPC_COMPILER_NAMES ispc)
+endif()
+
+
+if(NOT CMAKE_ISPC_COMPILER)
+
+ set(CMAKE_ISPC_COMPILER_INIT NOTFOUND)
+
+ # prefer the environment variable CC
+ if(NOT $ENV{ISPC} STREQUAL "")
+ get_filename_component(CMAKE_ISPC_COMPILER_INIT $ENV{ISPC} PROGRAM PROGRAM_ARGS CMAKE_ISPC_FLAGS_ENV_INIT)
+ if(CMAKE_ISPC_FLAGS_ENV_INIT)
+ set(CMAKE_ISPC_COMPILER_ARG1 "${CMAKE_ISPC_FLAGS_ENV_INIT}" CACHE STRING "First argument to ISPC compiler")
+ endif()
+ if(NOT EXISTS ${CMAKE_ISPC_COMPILER_INIT})
+ message(FATAL_ERROR "Could not find compiler set in environment variable ISPC:\n$ENV{ISPC}.")
+ endif()
+ endif()
+
+ # next try prefer the compiler specified by the generator
+ if(CMAKE_GENERATOR_ISPC)
+ if(NOT CMAKE_ISPC_COMPILER_INIT)
+ set(CMAKE_ISPC_COMPILER_INIT ${CMAKE_GENERATOR_ISPC})
+ endif()
+ endif()
+
+ # finally list compilers to try
+ if(NOT CMAKE_ISPC_COMPILER_INIT)
+ set(CMAKE_ISPC_COMPILER_LIST ${_CMAKE_TOOLCHAIN_PREFIX}ispc ispc)
+ endif()
+
+ # Find the compiler.
+ _cmake_find_compiler(ISPC)
+
+else()
+ _cmake_find_compiler_path(ISPC)
+endif()
+mark_as_advanced(CMAKE_ISPC_COMPILER)
+
+if(NOT CMAKE_ISPC_COMPILER_ID_RUN)
+set(CMAKE_ISPC_COMPILER_ID_RUN 1)
+
+ # Try to identify the compiler.
+ set(CMAKE_ISPC_COMPILER_ID)
+ set(CMAKE_ISPC_PLATFORM_ID)
+
+
+ set(CMAKE_ISPC_COMPILER_ID_TEST_FLAGS_FIRST
+ # setup logic to make sure ISPC outputs a file
+ "-o cmake_ispc_output"
+ )
+
+ include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
+ CMAKE_DETERMINE_COMPILER_ID(ISPC ISPCFLAGS CMakeISPCCompilerId.ispc)
+
+ _cmake_find_compiler_sysroot(ISPC)
+endif()
+
+if (NOT _CMAKE_TOOLCHAIN_LOCATION)
+ get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_ISPC_COMPILER}" PATH)
+endif ()
+
+set(_CMAKE_PROCESSING_LANGUAGE "ISPC")
+include(CMakeFindBinUtils)
+include(Compiler/${CMAKE_ISPC_COMPILER_ID}-FindBinUtils OPTIONAL)
+unset(_CMAKE_PROCESSING_LANGUAGE)
+
+if(CMAKE_ISPC_COMPILER_ID_VENDOR_MATCH)
+ set(_SET_CMAKE_ISPC_COMPILER_ID_VENDOR_MATCH
+ "set(CMAKE_ISPC_COMPILER_ID_VENDOR_MATCH [==[${CMAKE_ISPC_COMPILER_ID_VENDOR_MATCH}]==])")
+else()
+ set(_SET_CMAKE_ISPC_COMPILER_ID_VENDOR_MATCH "")
+endif()
+
+
+# configure variables set in this file for fast reload later on
+configure_file(${CMAKE_ROOT}/Modules/CMakeISPCCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeISPCCompiler.cmake @ONLY)
+
+set(CMAKE_ISPC_COMPILER_ENV_VAR "ISPC")
diff --git a/Modules/CMakeDetermineJavaCompiler.cmake b/Modules/CMakeDetermineJavaCompiler.cmake
new file mode 100644
index 0000000..db456c0
--- /dev/null
+++ b/Modules/CMakeDetermineJavaCompiler.cmake
@@ -0,0 +1,94 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# determine the compiler to use for Java programs
+# NOTE, a generator may set CMAKE_Java_COMPILER before
+# loading this file to force a compiler.
+
+if(NOT CMAKE_Java_COMPILER)
+ # prefer the environment variable CC
+ if(NOT $ENV{JAVA_COMPILER} STREQUAL "")
+ get_filename_component(CMAKE_Java_COMPILER_INIT $ENV{JAVA_COMPILER} PROGRAM PROGRAM_ARGS CMAKE_Java_FLAGS_ENV_INIT)
+ if(CMAKE_Java_FLAGS_ENV_INIT)
+ set(CMAKE_Java_COMPILER_ARG1 "${CMAKE_Java_FLAGS_ENV_INIT}" CACHE STRING "Arguments to Java compiler")
+ endif()
+ if(NOT EXISTS ${CMAKE_Java_COMPILER_INIT})
+ message(SEND_ERROR "Could not find compiler set in environment variable JAVA_COMPILER:\n$ENV{JAVA_COMPILER}.")
+ endif()
+ endif()
+
+ if(NOT $ENV{JAVA_RUNTIME} STREQUAL "")
+ get_filename_component(CMAKE_Java_RUNTIME_INIT $ENV{JAVA_RUNTIME} PROGRAM PROGRAM_ARGS CMAKE_Java_FLAGS_ENV_INIT)
+ if(NOT EXISTS ${CMAKE_Java_RUNTIME_INIT})
+ message(SEND_ERROR "Could not find compiler set in environment variable JAVA_RUNTIME:\n$ENV{JAVA_RUNTIME}.")
+ endif()
+ endif()
+
+ if(NOT $ENV{JAVA_ARCHIVE} STREQUAL "")
+ get_filename_component(CMAKE_Java_ARCHIVE_INIT $ENV{JAVA_ARCHIVE} PROGRAM PROGRAM_ARGS CMAKE_Java_FLAGS_ENV_INIT)
+ if(NOT EXISTS ${CMAKE_Java_ARCHIVE_INIT})
+ message(SEND_ERROR "Could not find compiler set in environment variable JAVA_ARCHIVE:\n$ENV{JAVA_ARCHIVE}.")
+ endif()
+ endif()
+
+ set(Java_BIN_PATH
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\2.0;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/bin"
+ $ENV{JAVA_HOME}/bin
+ /usr/bin
+ /usr/lib/java/bin
+ /usr/share/java/bin
+ /usr/local/bin
+ /usr/local/java/bin
+ /usr/local/java/share/bin
+ /usr/java/j2sdk1.4.2_04
+ /usr/lib/j2sdk1.4-sun/bin
+ /usr/java/j2sdk1.4.2_09/bin
+ /usr/lib/j2sdk1.5-sun/bin
+ /opt/sun-jdk-1.5.0.04/bin
+ /usr/local/jdk-1.7.0/bin
+ /usr/local/jdk-1.6.0/bin
+ )
+ # if no compiler has been specified yet, then look for one
+ if(CMAKE_Java_COMPILER_INIT)
+ set(CMAKE_Java_COMPILER ${CMAKE_Java_COMPILER_INIT} CACHE PATH "Java Compiler")
+ else()
+ find_program(CMAKE_Java_COMPILER
+ NAMES javac
+ PATHS ${Java_BIN_PATH}
+ )
+ endif()
+
+ # if no runtime has been specified yet, then look for one
+ if(CMAKE_Java_RUNTIME_INIT)
+ set(CMAKE_Java_RUNTIME ${CMAKE_Java_RUNTIME_INIT} CACHE PATH "Java Compiler")
+ else()
+ find_program(CMAKE_Java_RUNTIME
+ NAMES java
+ PATHS ${Java_BIN_PATH}
+ )
+ endif()
+
+ # if no archive has been specified yet, then look for one
+ if(CMAKE_Java_ARCHIVE_INIT)
+ set(CMAKE_Java_ARCHIVE ${CMAKE_Java_ARCHIVE_INIT} CACHE PATH "Java Compiler")
+ else()
+ find_program(CMAKE_Java_ARCHIVE
+ NAMES jar
+ PATHS ${Java_BIN_PATH}
+ )
+ endif()
+endif()
+mark_as_advanced(CMAKE_Java_COMPILER)
+
+# configure variables set in this file for fast reload later on
+configure_file(${CMAKE_ROOT}/Modules/CMakeJavaCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeJavaCompiler.cmake @ONLY)
+set(CMAKE_Java_COMPILER_ENV_VAR "JAVA_COMPILER")
diff --git a/Modules/CMakeDetermineOBJCCompiler.cmake b/Modules/CMakeDetermineOBJCCompiler.cmake
new file mode 100644
index 0000000..4b84c8a
--- /dev/null
+++ b/Modules/CMakeDetermineOBJCCompiler.cmake
@@ -0,0 +1,189 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# determine the compiler to use for Objective-C programs
+# NOTE, a generator may set CMAKE_OBJC_COMPILER before
+# loading this file to force a compiler.
+# use environment variable OBJC first if defined by user, next use
+# the cmake variable CMAKE_GENERATOR_OBJC which can be defined by a generator
+# as a default compiler
+#
+# Sets the following variables:
+# CMAKE_OBJC_COMPILER
+# CMAKE_AR
+# CMAKE_RANLIB
+# CMAKE_COMPILER_IS_GNUOBJC
+# CMAKE_COMPILER_IS_CLANGOBJC
+#
+# If not already set before, it also sets
+# _CMAKE_TOOLCHAIN_PREFIX
+
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
+
+# Load system-specific compiler preferences for this language.
+include(Platform/${CMAKE_SYSTEM_NAME}-Determine-OBJC OPTIONAL)
+include(Platform/${CMAKE_SYSTEM_NAME}-OBJC OPTIONAL)
+if(NOT CMAKE_OBJC_COMPILER_NAMES)
+ set(CMAKE_OBJC_COMPILER_NAMES clang)
+endif()
+
+if("${CMAKE_GENERATOR}" MATCHES "Xcode")
+ set(CMAKE_OBJC_COMPILER_XCODE_TYPE sourcecode.c.objc)
+else()
+ if(NOT CMAKE_OBJC_COMPILER)
+ set(CMAKE_OBJC_COMPILER_INIT NOTFOUND)
+
+ # prefer the environment variable OBJC or CC
+ foreach(var OBJC CC)
+ if($ENV{${var}} MATCHES ".+")
+ get_filename_component(CMAKE_OBJC_COMPILER_INIT $ENV{${var}} PROGRAM PROGRAM_ARGS CMAKE_OBJC_FLAGS_ENV_INIT)
+ if(CMAKE_OBJC_FLAGS_ENV_INIT)
+ set(CMAKE_OBJC_COMPILER_ARG1 "${CMAKE_OBJC_FLAGS_ENV_INIT}" CACHE STRING "Arguments to Objective-C compiler")
+ endif()
+ if(NOT EXISTS ${CMAKE_OBJC_COMPILER_INIT})
+ message(FATAL_ERROR "Could not find compiler set in environment variable ${var}:\n $ENV{${var}}")
+ endif()
+ break()
+ endif()
+ endforeach()
+
+ # next try prefer the compiler specified by the generator
+ if(CMAKE_GENERATOR_OBJC)
+ if(NOT CMAKE_OBJC_COMPILER_INIT)
+ set(CMAKE_OBJC_COMPILER_INIT ${CMAKE_GENERATOR_OBJC})
+ endif()
+ endif()
+
+ # finally list compilers to try
+ if(NOT CMAKE_OBJC_COMPILER_INIT)
+ set(CMAKE_OBJC_COMPILER_LIST ${_CMAKE_TOOLCHAIN_PREFIX}cc ${_CMAKE_TOOLCHAIN_PREFIX}gcc clang)
+ endif()
+
+ _cmake_find_compiler(OBJC)
+
+ else()
+ # we only get here if CMAKE_OBJC_COMPILER was specified using -D or a pre-made CMakeCache.txt
+ # (e.g. via ctest) or set in CMAKE_TOOLCHAIN_FILE
+ # if CMAKE_OBJC_COMPILER is a list, use the first item as
+ # CMAKE_OBJC_COMPILER and the rest as CMAKE_OBJC_COMPILER_ARG1
+ set(CMAKE_OBJC_COMPILER_ARG1 "${CMAKE_OBJC_COMPILER}")
+ list(POP_FRONT CMAKE_OBJC_COMPILER_ARG1 CMAKE_OBJC_COMPILER)
+ list(JOIN CMAKE_OBJC_COMPILER_ARG1 " " CMAKE_OBJC_COMPILER_ARG1)
+
+ # if a compiler was specified by the user but without path,
+ # now try to find it with the full path
+ # if it is found, force it into the cache,
+ # if not, don't overwrite the setting (which was given by the user) with "NOTFOUND"
+ # if the C compiler already had a path, reuse it for searching the CXX compiler
+ get_filename_component(_CMAKE_USER_OBJC_COMPILER_PATH "${CMAKE_OBJC_COMPILER}" PATH)
+ if(NOT _CMAKE_USER_OBJC_COMPILER_PATH)
+ find_program(CMAKE_OBJC_COMPILER_WITH_PATH NAMES ${CMAKE_OBJC_COMPILER})
+ if(CMAKE_OBJC_COMPILER_WITH_PATH)
+ set(CMAKE_OBJC_COMPILER ${CMAKE_OBJC_COMPILER_WITH_PATH} CACHE STRING "Objective-C compiler" FORCE)
+ endif()
+ unset(CMAKE_OBJC_COMPILER_WITH_PATH CACHE)
+ endif()
+ endif()
+ mark_as_advanced(CMAKE_OBJC_COMPILER)
+
+ # Each entry in this list is a set of extra flags to try
+ # adding to the compile line to see if it helps produce
+ # a valid identification file.
+ set(CMAKE_OBJC_COMPILER_ID_TEST_FLAGS_FIRST)
+ set(CMAKE_OBJC_COMPILER_ID_TEST_FLAGS
+ # Try compiling to an object file only.
+ "-c"
+
+ )
+endif()
+
+# Build a small source file to identify the compiler.
+if(NOT CMAKE_OBJC_COMPILER_ID_RUN)
+ set(CMAKE_OBJC_COMPILER_ID_RUN 1)
+
+ # Try to identify the compiler.
+ set(CMAKE_OBJC_COMPILER_ID)
+ file(READ ${CMAKE_ROOT}/Modules/CMakePlatformId.h.in
+ CMAKE_OBJC_COMPILER_ID_PLATFORM_CONTENT)
+
+ # Match the link line from xcodebuild output of the form
+ # Ld ...
+ # ...
+ # /path/to/cc ...CompilerIdOBJC/...
+ # to extract the compiler front-end for the language.
+ set(CMAKE_OBJC_COMPILER_ID_TOOL_MATCH_REGEX "\nLd[^\n]*(\n[ \t]+[^\n]*)*\n[ \t]+([^ \t\r\n]+)[^\r\n]*-o[^\r\n]*CompilerIdOBJC/(\\./)?(CompilerIdOBJC.(framework|xctest|build/[^ \t\r\n]+)/)?CompilerIdOBJC[ \t\n\\\"]")
+ set(CMAKE_OBJC_COMPILER_ID_TOOL_MATCH_INDEX 2)
+
+ include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
+ CMAKE_DETERMINE_COMPILER_ID(OBJC OBJCCFLAGS CMakeOBJCCompilerId.m)
+
+ # Set old compiler and platform id variables.
+ if(CMAKE_OBJC_COMPILER_ID STREQUAL "GNU")
+ set(CMAKE_COMPILER_IS_GNUOBJC 1)
+ endif()
+ if(CMAKE_OBJC_COMPILER_ID STREQUAL "Clang")
+ set(CMAKE_COMPILER_IS_CLANGOBJC 1)
+ endif()
+endif()
+
+if (NOT _CMAKE_TOOLCHAIN_LOCATION)
+ get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_OBJC_COMPILER}" PATH)
+endif ()
+
+# If we have a gcc cross compiler, they have usually some prefix, like
+# e.g. powerpc-linux-gcc, arm-elf-gcc or i586-mingw32msvc-gcc, optionally
+# with a 3-component version number at the end (e.g. arm-eabi-gcc-4.5.2).
+# The other tools of the toolchain usually have the same prefix
+# NAME_WE cannot be used since then this test will fail for names like
+# "arm-unknown-nto-qnx6.3.0-gcc.exe", where BASENAME would be
+# "arm-unknown-nto-qnx6" instead of the correct "arm-unknown-nto-qnx6.3.0-"
+if (CMAKE_CROSSCOMPILING AND NOT _CMAKE_TOOLCHAIN_PREFIX)
+
+ if(CMAKE_OBJC_COMPILER_ID MATCHES "GNU|Clang|QCC")
+ get_filename_component(COMPILER_BASENAME "${CMAKE_OBJC_COMPILER}" NAME)
+ if (COMPILER_BASENAME MATCHES "^(.+-)(clang|g?cc)(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$")
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_5})
+ elseif(CMAKE_OBJC_COMPILER_ID MATCHES "Clang")
+ if(CMAKE_OBJC_COMPILER_TARGET)
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_OBJC_COMPILER_TARGET}-)
+ endif()
+ elseif(COMPILER_BASENAME MATCHES "qcc(\\.exe)?$")
+ if(CMAKE_OBJC_COMPILER_TARGET MATCHES "gcc_nto([a-z0-9]+_[0-9]+|[^_le]+)(le)?")
+ set(_CMAKE_TOOLCHAIN_PREFIX nto${CMAKE_MATCH_1}-)
+ endif()
+ endif ()
+
+ # if "llvm-" is part of the prefix, remove it, since llvm doesn't have its own binutils
+ # but uses the regular ar, objcopy, etc. (instead of llvm-objcopy etc.)
+ if ("${_CMAKE_TOOLCHAIN_PREFIX}" MATCHES "(.+-)?llvm-$")
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ endif ()
+ endif()
+
+endif ()
+
+set(_CMAKE_PROCESSING_LANGUAGE "OBJC")
+include(CMakeFindBinUtils)
+include(Compiler/${CMAKE_OBJC_COMPILER_ID}-FindBinUtils OPTIONAL)
+unset(_CMAKE_PROCESSING_LANGUAGE)
+
+if(CMAKE_OBJC_COMPILER_ARCHITECTURE_ID)
+ set(_SET_CMAKE_OBJC_COMPILER_ARCHITECTURE_ID
+ "set(CMAKE_OBJC_COMPILER_ARCHITECTURE_ID ${CMAKE_OBJC_COMPILER_ARCHITECTURE_ID})")
+else()
+ set(_SET_CMAKE_OBJC_COMPILER_ARCHITECTURE_ID "")
+endif()
+
+if(CMAKE_OBJC_XCODE_ARCHS)
+ set(SET_CMAKE_XCODE_ARCHS
+ "set(CMAKE_XCODE_ARCHS \"${CMAKE_OBJC_XCODE_ARCHS}\")")
+endif()
+
+# configure variables set in this file for fast reload later on
+configure_file(${CMAKE_ROOT}/Modules/CMakeOBJCCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeOBJCCompiler.cmake
+ @ONLY
+ )
+set(CMAKE_OBJC_COMPILER_ENV_VAR "OBJC")
diff --git a/Modules/CMakeDetermineOBJCXXCompiler.cmake b/Modules/CMakeDetermineOBJCXXCompiler.cmake
new file mode 100644
index 0000000..7403847
--- /dev/null
+++ b/Modules/CMakeDetermineOBJCXXCompiler.cmake
@@ -0,0 +1,197 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# determine the compiler to use for Objective-C++ programs
+# NOTE, a generator may set CMAKE_OBJCXX_COMPILER before
+# loading this file to force a compiler.
+# use environment variable OBJCXX first if defined by user, next use
+# the cmake variable CMAKE_GENERATOR_OBJCXX which can be defined by a generator
+# as a default compiler
+# If the internal cmake variable _CMAKE_TOOLCHAIN_PREFIX is set, this is used
+# as prefix for the tools (e.g. arm-elf-g++, arm-elf-ar etc.)
+#
+# Sets the following variables:
+# CMAKE_OBJCXX_COMPILER
+# CMAKE_COMPILER_IS_GNUOBJCXX
+# CMAKE_COMPILER_IS_CLANGOBJCXX
+# CMAKE_AR
+# CMAKE_RANLIB
+#
+# If not already set before, it also sets
+# _CMAKE_TOOLCHAIN_PREFIX
+
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
+
+# Load system-specific compiler preferences for this language.
+include(Platform/${CMAKE_SYSTEM_NAME}-Determine-OBJCXX OPTIONAL)
+include(Platform/${CMAKE_SYSTEM_NAME}-OBJCXX OPTIONAL)
+if(NOT CMAKE_OBJCXX_COMPILER_NAMES)
+ set(CMAKE_OBJCXX_COMPILER_NAMES clang++)
+endif()
+
+if("${CMAKE_GENERATOR}" MATCHES "Xcode")
+ set(CMAKE_OBJCXX_COMPILER_XCODE_TYPE sourcecode.cpp.objcpp)
+else()
+ if(NOT CMAKE_OBJCXX_COMPILER)
+ set(CMAKE_OBJCXX_COMPILER_INIT NOTFOUND)
+
+ # prefer the environment variable OBJCXX or CXX
+ foreach(var OBJCXX CXX)
+ if($ENV{${var}} MATCHES ".+")
+ get_filename_component(CMAKE_OBJCXX_COMPILER_INIT $ENV{${var}} PROGRAM PROGRAM_ARGS CMAKE_OBJCXX_FLAGS_ENV_INIT)
+ if(CMAKE_OBJCXX_FLAGS_ENV_INIT)
+ set(CMAKE_OBJCXX_COMPILER_ARG1 "${CMAKE_OBJCXX_FLAGS_ENV_INIT}" CACHE STRING "Arguments to Objective-C++ compiler")
+ endif()
+ if(NOT EXISTS ${CMAKE_OBJCXX_COMPILER_INIT})
+ message(FATAL_ERROR "Could not find compiler set in environment variable ${var}:\n $ENV{${var}}")
+ endif()
+ break()
+ endif()
+ endforeach()
+
+ # next prefer the generator specified compiler
+ if(CMAKE_GENERATOR_OBJCXX)
+ if(NOT CMAKE_OBJCXX_COMPILER_INIT)
+ set(CMAKE_OBJCXX_COMPILER_INIT ${CMAKE_GENERATOR_OBJCXX})
+ endif()
+ endif()
+
+ # finally list compilers to try
+ if(NOT CMAKE_OBJCXX_COMPILER_INIT)
+ set(CMAKE_OBJCXX_COMPILER_LIST ${_CMAKE_TOOLCHAIN_PREFIX}c++ ${_CMAKE_TOOLCHAIN_PREFIX}g++ clang++)
+ endif()
+
+ _cmake_find_compiler(OBJCXX)
+
+ else()
+ # we only get here if CMAKE_OBJCXX_COMPILER was specified using -D or a pre-made CMakeCache.txt
+ # (e.g. via ctest) or set in CMAKE_TOOLCHAIN_FILE
+ # if CMAKE_OBJCXX_COMPILER is a list, use the first item as
+ # CMAKE_OBJCXX_COMPILER and the rest as CMAKE_OBJCXX_COMPILER_ARG1
+ set(CMAKE_OBJCXX_COMPILER_ARG1 "${CMAKE_OBJCXX_COMPILER}")
+ list(POP_FRONT CMAKE_OBJCXX_COMPILER_ARG1 CMAKE_OBJCXX_COMPILER)
+ list(JOIN CMAKE_OBJCXX_COMPILER_ARG1 " " CMAKE_OBJCXX_COMPILER_ARG1)
+
+ # if a compiler was specified by the user but without path,
+ # now try to find it with the full path
+ # if it is found, force it into the cache,
+ # if not, don't overwrite the setting (which was given by the user) with "NOTFOUND"
+ # if the C compiler already had a path, reuse it for searching the CXX compiler
+ get_filename_component(_CMAKE_USER_OBJCXX_COMPILER_PATH "${CMAKE_OBJCXX_COMPILER}" PATH)
+ if(NOT _CMAKE_USER_OBJCXX_COMPILER_PATH)
+ find_program(CMAKE_OBJCXX_COMPILER_WITH_PATH NAMES ${CMAKE_OBJCXX_COMPILER})
+ if(CMAKE_OBJCXX_COMPILER_WITH_PATH)
+ set(CMAKE_OBJCXX_COMPILER ${CMAKE_OBJCXX_COMPILER_WITH_PATH} CACHE STRING "Objective-C++ compiler" FORCE)
+ endif()
+ unset(CMAKE_OBJCXX_COMPILER_WITH_PATH CACHE)
+ endif()
+
+ endif()
+ mark_as_advanced(CMAKE_OBJCXX_COMPILER)
+
+ # Each entry in this list is a set of extra flags to try
+ # adding to the compile line to see if it helps produce
+ # a valid identification file.
+ set(CMAKE_OBJCXX_COMPILER_ID_TEST_FLAGS_FIRST)
+ set(CMAKE_OBJCXX_COMPILER_ID_TEST_FLAGS
+ # Try compiling to an object file only.
+ "-c"
+
+ # ARMClang need target options
+ "--target=arm-arm-none-eabi -mcpu=cortex-m3"
+ )
+endif()
+
+# Build a small source file to identify the compiler.
+if(NOT CMAKE_OBJCXX_COMPILER_ID_RUN)
+ set(CMAKE_OBJCXX_COMPILER_ID_RUN 1)
+
+ # Try to identify the compiler.
+ set(CMAKE_OBJCXX_COMPILER_ID)
+ file(READ ${CMAKE_ROOT}/Modules/CMakePlatformId.h.in
+ CMAKE_OBJCXX_COMPILER_ID_PLATFORM_CONTENT)
+
+ # Match the link line from xcodebuild output of the form
+ # Ld ...
+ # ...
+ # /path/to/cc ...CompilerIdOBJCXX/...
+ # to extract the compiler front-end for the language.
+ set(CMAKE_OBJCXX_COMPILER_ID_TOOL_MATCH_REGEX "\nLd[^\n]*(\n[ \t]+[^\n]*)*\n[ \t]+([^ \t\r\n]+)[^\r\n]*-o[^\r\n]*CompilerIdOBJCXX/(\\./)?(CompilerIdOBJCXX.(framework|xctest|build/[^ \t\r\n]+)/)?CompilerIdOBJCXX[ \t\n\\\"]")
+ set(CMAKE_OBJCXX_COMPILER_ID_TOOL_MATCH_INDEX 2)
+
+ include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
+ CMAKE_DETERMINE_COMPILER_ID(OBJCXX OBJCXXFLAGS CMakeOBJCXXCompilerId.mm)
+
+ # Set old compiler and platform id variables.
+ if(CMAKE_OBJCXX_COMPILER_ID MATCHES "GNU")
+ set(CMAKE_COMPILER_IS_GNUOBJCXX 1)
+ endif()
+ if(CMAKE_OBJCXX_COMPILER_ID MATCHES "Clang")
+ set(CMAKE_COMPILER_IS_CLANGOBJCXX 1)
+ endif()
+endif()
+
+if (NOT _CMAKE_TOOLCHAIN_LOCATION)
+ get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_OBJCXX_COMPILER}" PATH)
+endif ()
+
+# if we have a g++ cross compiler, they have usually some prefix, like
+# e.g. powerpc-linux-g++, arm-elf-g++ or i586-mingw32msvc-g++ , optionally
+# with a 3-component version number at the end (e.g. arm-eabi-gcc-4.5.2).
+# The other tools of the toolchain usually have the same prefix
+# NAME_WE cannot be used since then this test will fail for names like
+# "arm-unknown-nto-qnx6.3.0-gcc.exe", where BASENAME would be
+# "arm-unknown-nto-qnx6" instead of the correct "arm-unknown-nto-qnx6.3.0-"
+
+
+if (NOT _CMAKE_TOOLCHAIN_PREFIX)
+
+ if("${CMAKE_OBJCXX_COMPILER_ID}" MATCHES "GNU|Clang|QCC")
+ get_filename_component(COMPILER_BASENAME "${CMAKE_OBJCXX_COMPILER}" NAME)
+ if (COMPILER_BASENAME MATCHES "^(.+-)(clan)?[gc]\\+\\+(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$")
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_5})
+ elseif("${CMAKE_OBJCXX_COMPILER_ID}" MATCHES "Clang")
+ if(CMAKE_OBJCXX_COMPILER_TARGET)
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_OBJCXX_COMPILER_TARGET}-)
+ endif()
+ elseif(COMPILER_BASENAME MATCHES "QCC(\\.exe)?$")
+ if(CMAKE_OBJCXX_COMPILER_TARGET MATCHES "gcc_nto([a-z0-9]+_[0-9]+|[^_le]+)(le)")
+ set(_CMAKE_TOOLCHAIN_PREFIX nto${CMAKE_MATCH_1}-)
+ endif()
+ endif ()
+
+ # if "llvm-" is part of the prefix, remove it, since llvm doesn't have its own binutils
+ # but uses the regular ar, objcopy, etc. (instead of llvm-objcopy etc.)
+ if ("${_CMAKE_TOOLCHAIN_PREFIX}" MATCHES "(.+-)?llvm-$")
+ set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+ endif ()
+ endif()
+
+endif ()
+
+set(_CMAKE_PROCESSING_LANGUAGE "OBJCXX")
+include(CMakeFindBinUtils)
+include(Compiler/${CMAKE_OBJCXX_COMPILER_ID}-FindBinUtils OPTIONAL)
+unset(_CMAKE_PROCESSING_LANGUAGE)
+
+if(CMAKE_OBJCXX_COMPILER_ARCHITECTURE_ID)
+ set(_SET_CMAKE_OBJCXX_COMPILER_ARCHITECTURE_ID
+ "set(CMAKE_OBJCXX_COMPILER_ARCHITECTURE_ID ${CMAKE_OBJCXX_COMPILER_ARCHITECTURE_ID})")
+else()
+ set(_SET_CMAKE_OBJCXX_COMPILER_ARCHITECTURE_ID "")
+endif()
+
+if(CMAKE_OBJCXX_XCODE_ARCHS)
+ set(SET_CMAKE_XCODE_ARCHS
+ "set(CMAKE_XCODE_ARCHS \"${CMAKE_OBJCXX_XCODE_ARCHS}\")")
+endif()
+
+# configure all variables set in this file
+configure_file(${CMAKE_ROOT}/Modules/CMakeOBJCXXCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeOBJCXXCompiler.cmake
+ @ONLY
+ )
+
+set(CMAKE_OBJCXX_COMPILER_ENV_VAR "OBJCXX")
diff --git a/Modules/CMakeDetermineRCCompiler.cmake b/Modules/CMakeDetermineRCCompiler.cmake
new file mode 100644
index 0000000..f8d55a5
--- /dev/null
+++ b/Modules/CMakeDetermineRCCompiler.cmake
@@ -0,0 +1,57 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# determine the compiler to use for RC programs
+# NOTE, a generator may set CMAKE_RC_COMPILER before
+# loading this file to force a compiler.
+# use environment variable RC first if defined by user, next use
+# the cmake variable CMAKE_GENERATOR_RC which can be defined by a generator
+# as a default compiler
+if(NOT CMAKE_RC_COMPILER)
+ # prefer the environment variable RC
+ if(NOT $ENV{RC} STREQUAL "")
+ get_filename_component(CMAKE_RC_COMPILER_INIT $ENV{RC} PROGRAM PROGRAM_ARGS CMAKE_RC_FLAGS_ENV_INIT)
+ if(CMAKE_RC_FLAGS_ENV_INIT)
+ set(CMAKE_RC_COMPILER_ARG1 "${CMAKE_RC_FLAGS_ENV_INIT}" CACHE STRING "Arguments to RC compiler")
+ endif()
+ if(EXISTS ${CMAKE_RC_COMPILER_INIT})
+ else()
+ message(FATAL_ERROR "Could not find compiler set in environment variable RC:\n$ENV{RC}.")
+ endif()
+ endif()
+
+ # next try prefer the compiler specified by the generator
+ if(CMAKE_GENERATOR_RC)
+ if(NOT CMAKE_RC_COMPILER_INIT)
+ set(CMAKE_RC_COMPILER_INIT ${CMAKE_GENERATOR_RC})
+ endif()
+ endif()
+
+ # finally list compilers to try
+ if(CMAKE_RC_COMPILER_INIT)
+ set(CMAKE_RC_COMPILER_LIST ${CMAKE_RC_COMPILER_INIT})
+ else()
+ set(CMAKE_RC_COMPILER_LIST rc)
+ endif()
+
+ # Find the compiler.
+ find_program(CMAKE_RC_COMPILER NAMES ${CMAKE_RC_COMPILER_LIST} DOC "RC compiler")
+ if(CMAKE_RC_COMPILER_INIT AND NOT CMAKE_RC_COMPILER)
+ set(CMAKE_RC_COMPILER "${CMAKE_RC_COMPILER_INIT}" CACHE FILEPATH "RC compiler" FORCE)
+ endif()
+endif()
+
+mark_as_advanced(CMAKE_RC_COMPILER)
+
+get_filename_component(_CMAKE_RC_COMPILER_NAME_WE ${CMAKE_RC_COMPILER} NAME_WE)
+if(_CMAKE_RC_COMPILER_NAME_WE STREQUAL "windres")
+ set(CMAKE_RC_OUTPUT_EXTENSION .obj)
+else()
+ set(CMAKE_RC_OUTPUT_EXTENSION .res)
+endif()
+
+# configure variables set in this file for fast reload later on
+configure_file(${CMAKE_ROOT}/Modules/CMakeRCCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeRCCompiler.cmake)
+set(CMAKE_RC_COMPILER_ENV_VAR "RC")
diff --git a/Modules/CMakeDetermineSwiftCompiler.cmake b/Modules/CMakeDetermineSwiftCompiler.cmake
new file mode 100644
index 0000000..aaad560
--- /dev/null
+++ b/Modules/CMakeDetermineSwiftCompiler.cmake
@@ -0,0 +1,78 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
+
+# Local system-specific compiler preferences for this language.
+include(Platform/${CMAKE_SYSTEM_NAME}-Determine-Swift OPTIONAL)
+include(Platform/${CMAKE_SYSTEM_NAME}-Swift OPTIONAL)
+if(NOT CMAKE_Swift_COMPILER_NAMES)
+ set(CMAKE_Swift_COMPILER_NAMES swiftc)
+endif()
+
+if("${CMAKE_GENERATOR}" STREQUAL "Xcode")
+ if(XCODE_VERSION VERSION_LESS 6.1)
+ message(FATAL_ERROR "Swift language not supported by Xcode ${XCODE_VERSION}")
+ endif()
+ set(CMAKE_Swift_COMPILER_XCODE_TYPE sourcecode.swift)
+ _cmake_find_compiler_path(Swift)
+elseif("${CMAKE_GENERATOR}" MATCHES "^Ninja")
+ if(CMAKE_Swift_COMPILER)
+ _cmake_find_compiler_path(Swift)
+ else()
+ set(CMAKE_Swift_COMPILER_INIT NOTFOUND)
+
+ if(NOT $ENV{SWIFTC} STREQUAL "")
+ get_filename_component(CMAKE_Swift_COMPILER_INIT $ENV{SWIFTC} PROGRAM
+ PROGRAM_ARGS CMAKE_Swift_FLAGS_ENV_INIT)
+ if(CMAKE_Swift_FLAGS_ENV_INIT)
+ set(CMAKE_Swift_COMPILER_ARG1 "${CMAKE_Swift_FLAGS_ENV_INIT}" CACHE
+ STRING "Arguments to the Swift compiler")
+ endif()
+ if(NOT EXISTS ${CMAKE_Swift_COMPILER_INIT})
+ message(FATAL_ERROR "Could not find compiler set in environment variable SWIFTC\n$ENV{SWIFTC}.\n${CMAKE_Swift_COMPILER_INIT}")
+ endif()
+ endif()
+
+ if(NOT CMAKE_Swift_COMPILER_INIT)
+ set(CMAKE_Swift_COMPILER_LIST swiftc ${_CMAKE_TOOLCHAIN_PREFIX}swiftc)
+ endif()
+
+ _cmake_find_compiler(Swift)
+ endif()
+ mark_as_advanced(CMAKE_Swift_COMPILER)
+else()
+ message(FATAL_ERROR "Swift language not supported by \"${CMAKE_GENERATOR}\" generator")
+endif()
+
+# Build a small source file to identify the compiler.
+if(NOT CMAKE_Swift_COMPILER_ID_RUN)
+ set(CMAKE_Swift_COMPILER_ID_RUN 1)
+
+ if("${CMAKE_GENERATOR}" STREQUAL "Xcode")
+ list(APPEND CMAKE_Swift_COMPILER_ID_MATCH_VENDORS Apple)
+ set(CMAKE_Swift_COMPILER_ID_MATCH_VENDOR_REGEX_Apple "com.apple.xcode.tools.swift.compiler")
+
+ set(CMAKE_Swift_COMPILER_ID_TOOL_MATCH_REGEX "\nCompileSwift[^\n]*(\n[ \t]+[^\n]*)*\n[ \t]+([^ \t\r\n]+)[^\r\n]* -c[^\r\n]*CompilerIdSwift/CompilerId/main.swift")
+ set(CMAKE_Swift_COMPILER_ID_TOOL_MATCH_INDEX 2)
+ endif()
+
+ # Try to identify the compiler.
+ set(CMAKE_Swift_COMPILER_ID)
+ include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
+ CMAKE_DETERMINE_COMPILER_ID(Swift "" CompilerId/main.swift)
+endif()
+
+if (NOT _CMAKE_TOOLCHAIN_LOCATION)
+ get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_Swift_COMPILER}" PATH)
+endif ()
+
+set(_CMAKE_PROCESSING_LANGUAGE "Swift")
+include(CMakeFindBinUtils)
+unset(_CMAKE_PROCESSING_LANGUAGE)
+
+# configure variables set in this file for fast reload later on
+configure_file(${CMAKE_ROOT}/Modules/CMakeSwiftCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeSwiftCompiler.cmake @ONLY)
+
+set(CMAKE_Swift_COMPILER_ENV_VAR "SWIFTC")
diff --git a/Modules/CMakeDetermineSystem.cmake b/Modules/CMakeDetermineSystem.cmake
new file mode 100644
index 0000000..c3f2b74
--- /dev/null
+++ b/Modules/CMakeDetermineSystem.cmake
@@ -0,0 +1,196 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is used by the Makefile generator to determine the following variables:
+# CMAKE_SYSTEM_NAME - on unix this is uname -s, for windows it is Windows
+# CMAKE_SYSTEM_VERSION - on unix this is uname -r, for windows it is empty
+# CMAKE_SYSTEM - ${CMAKE_SYSTEM}-${CMAKE_SYSTEM_VERSION}, for windows: ${CMAKE_SYSTEM}
+#
+# Expected uname -s output:
+#
+# AIX AIX
+# BSD/OS BSD/OS
+# FreeBSD FreeBSD
+# HP-UX HP-UX
+# Linux Linux
+# GNU/kFreeBSD GNU/kFreeBSD
+# NetBSD NetBSD
+# OpenBSD OpenBSD
+# OFS/1 (Digital Unix) OSF1
+# SCO OpenServer 5 SCO_SV
+# SCO UnixWare 7 UnixWare
+# SCO UnixWare (pre release 7) UNIX_SV
+# SCO XENIX Xenix
+# Solaris SunOS
+# SunOS SunOS
+# Tru64 Tru64
+# Ultrix ULTRIX
+# cygwin CYGWIN_NT-5.1
+# MacOSX Darwin
+
+
+# find out on which system cmake runs
+if(CMAKE_HOST_UNIX)
+ find_program(CMAKE_UNAME uname /bin /usr/bin /usr/local/bin )
+ if(CMAKE_UNAME)
+ if(CMAKE_HOST_SYSTEM_NAME STREQUAL "AIX")
+ exec_program(${CMAKE_UNAME} ARGS -v OUTPUT_VARIABLE _CMAKE_HOST_SYSTEM_MAJOR_VERSION)
+ exec_program(${CMAKE_UNAME} ARGS -r OUTPUT_VARIABLE _CMAKE_HOST_SYSTEM_MINOR_VERSION)
+ set(CMAKE_HOST_SYSTEM_VERSION "${_CMAKE_HOST_SYSTEM_MAJOR_VERSION}.${_CMAKE_HOST_SYSTEM_MINOR_VERSION}")
+ unset(_CMAKE_HOST_SYSTEM_MAJOR_VERSION)
+ unset(_CMAKE_HOST_SYSTEM_MINOR_VERSION)
+ else()
+ exec_program(${CMAKE_UNAME} ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)
+ endif()
+ if(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux|CYGWIN.*|^GNU$|Android")
+ exec_program(${CMAKE_UNAME} ARGS -m OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
+ RETURN_VALUE val)
+ elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
+ # If we are running on Apple Silicon, honor CMAKE_APPLE_SILICON_PROCESSOR.
+ if(DEFINED CMAKE_APPLE_SILICON_PROCESSOR)
+ set(_CMAKE_APPLE_SILICON_PROCESSOR "${CMAKE_APPLE_SILICON_PROCESSOR}")
+ elseif(DEFINED ENV{CMAKE_APPLE_SILICON_PROCESSOR})
+ set(_CMAKE_APPLE_SILICON_PROCESSOR "$ENV{CMAKE_APPLE_SILICON_PROCESSOR}")
+ else()
+ set(_CMAKE_APPLE_SILICON_PROCESSOR "")
+ endif()
+ if(_CMAKE_APPLE_SILICON_PROCESSOR)
+ if(";${_CMAKE_APPLE_SILICON_PROCESSOR};" MATCHES "^;(arm64|x86_64);$")
+ execute_process(COMMAND sysctl -q hw.optional.arm64
+ OUTPUT_VARIABLE _sysctl_stdout
+ ERROR_VARIABLE _sysctl_stderr
+ RESULT_VARIABLE _sysctl_result
+ )
+ if(NOT _sysctl_result EQUAL 0 OR NOT _sysctl_stdout MATCHES "hw.optional.arm64: 1")
+ set(_CMAKE_APPLE_SILICON_PROCESSOR "")
+ endif()
+ unset(_sysctl_result)
+ unset(_sysctl_stderr)
+ unset(_sysctl_stdout)
+ endif()
+ endif()
+ if(_CMAKE_APPLE_SILICON_PROCESSOR)
+ set(CMAKE_HOST_SYSTEM_PROCESSOR "${_CMAKE_APPLE_SILICON_PROCESSOR}")
+ else()
+ exec_program(${CMAKE_UNAME} ARGS -m OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
+ RETURN_VALUE val)
+ endif()
+ unset(_CMAKE_APPLE_SILICON_PROCESSOR)
+ if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "Power Macintosh")
+ # OS X ppc 'uname -m' may report 'Power Macintosh' instead of 'powerpc'
+ set(CMAKE_HOST_SYSTEM_PROCESSOR "powerpc")
+ endif()
+ elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "OpenBSD")
+ exec_program(arch ARGS -s OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
+ RETURN_VALUE val)
+ else()
+ exec_program(${CMAKE_UNAME} ARGS -p OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
+ RETURN_VALUE val)
+ if("${val}" GREATER 0)
+ exec_program(${CMAKE_UNAME} ARGS -m OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
+ RETURN_VALUE val)
+ endif()
+ endif()
+ # check the return of the last uname -m or -p
+ if("${val}" GREATER 0)
+ set(CMAKE_HOST_SYSTEM_PROCESSOR "unknown")
+ endif()
+ set(CMAKE_UNAME ${CMAKE_UNAME} CACHE INTERNAL "uname command")
+ # processor may have double quote in the name, and that needs to be removed
+ string(REPLACE "\"" "" CMAKE_HOST_SYSTEM_PROCESSOR "${CMAKE_HOST_SYSTEM_PROCESSOR}")
+ string(REPLACE "/" "_" CMAKE_HOST_SYSTEM_PROCESSOR "${CMAKE_HOST_SYSTEM_PROCESSOR}")
+ endif()
+else()
+ if(CMAKE_HOST_WIN32)
+ if (DEFINED ENV{PROCESSOR_ARCHITEW6432})
+ set (CMAKE_HOST_SYSTEM_PROCESSOR "$ENV{PROCESSOR_ARCHITEW6432}")
+ else()
+ set (CMAKE_HOST_SYSTEM_PROCESSOR "$ENV{PROCESSOR_ARCHITECTURE}")
+ endif()
+ endif()
+endif()
+
+# if a toolchain file is used, the user wants to cross compile.
+# in this case read the toolchain file and keep the CMAKE_HOST_SYSTEM_*
+# variables around so they can be used in CMakeLists.txt.
+# In all other cases, the host and target platform are the same.
+if(CMAKE_TOOLCHAIN_FILE)
+ # at first try to load it as path relative to the directory from which cmake has been run
+ include("${CMAKE_BINARY_DIR}/${CMAKE_TOOLCHAIN_FILE}" OPTIONAL RESULT_VARIABLE _INCLUDED_TOOLCHAIN_FILE)
+ if(NOT _INCLUDED_TOOLCHAIN_FILE)
+ # if the file isn't found there, check the default locations
+ include("${CMAKE_TOOLCHAIN_FILE}" OPTIONAL RESULT_VARIABLE _INCLUDED_TOOLCHAIN_FILE)
+ endif()
+
+ if(_INCLUDED_TOOLCHAIN_FILE)
+ set(CMAKE_TOOLCHAIN_FILE "${_INCLUDED_TOOLCHAIN_FILE}" CACHE FILEPATH "The CMake toolchain file" FORCE)
+ else()
+ message(FATAL_ERROR "Could not find toolchain file: ${CMAKE_TOOLCHAIN_FILE}")
+ set(CMAKE_TOOLCHAIN_FILE "NOTFOUND" CACHE FILEPATH "The CMake toolchain file" FORCE)
+ endif()
+endif()
+
+
+# if CMAKE_SYSTEM_NAME is here already set, either it comes from a toolchain file
+# or it was set via -DCMAKE_SYSTEM_NAME=...
+# if that's the case, assume we are crosscompiling
+if(CMAKE_SYSTEM_NAME)
+ if(NOT DEFINED CMAKE_CROSSCOMPILING)
+ set(CMAKE_CROSSCOMPILING TRUE)
+ endif()
+ set(PRESET_CMAKE_SYSTEM_NAME TRUE)
+elseif(CMAKE_VS_WINCE_VERSION)
+ set(CMAKE_SYSTEM_NAME "WindowsCE")
+ set(CMAKE_SYSTEM_VERSION "${CMAKE_VS_WINCE_VERSION}")
+ set(CMAKE_SYSTEM_PROCESSOR "${MSVC_C_ARCHITECTURE_ID}")
+ set(CMAKE_CROSSCOMPILING TRUE)
+ set(PRESET_CMAKE_SYSTEM_NAME TRUE)
+else()
+ set(CMAKE_SYSTEM_NAME "${CMAKE_HOST_SYSTEM_NAME}")
+ if(NOT DEFINED CMAKE_SYSTEM_VERSION)
+ set(CMAKE_SYSTEM_VERSION "${CMAKE_HOST_SYSTEM_VERSION}")
+ endif()
+ set(CMAKE_SYSTEM_PROCESSOR "${CMAKE_HOST_SYSTEM_PROCESSOR}")
+ set(CMAKE_CROSSCOMPILING FALSE)
+ set(PRESET_CMAKE_SYSTEM_NAME FALSE)
+endif()
+
+include(Platform/${CMAKE_SYSTEM_NAME}-Determine OPTIONAL)
+
+set(CMAKE_SYSTEM ${CMAKE_SYSTEM_NAME})
+if(CMAKE_SYSTEM_VERSION)
+ string(APPEND CMAKE_SYSTEM -${CMAKE_SYSTEM_VERSION})
+endif()
+set(CMAKE_HOST_SYSTEM ${CMAKE_HOST_SYSTEM_NAME})
+if(CMAKE_HOST_SYSTEM_VERSION)
+ string(APPEND CMAKE_HOST_SYSTEM -${CMAKE_HOST_SYSTEM_VERSION})
+endif()
+
+# this file is also executed from cpack, then we don't need to generate these files
+# in this case there is no CMAKE_BINARY_DIR
+if(CMAKE_BINARY_DIR)
+ # write entry to the log file
+ if(PRESET_CMAKE_SYSTEM_NAME)
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "The target system is: ${CMAKE_SYSTEM_NAME} - ${CMAKE_SYSTEM_VERSION} - ${CMAKE_SYSTEM_PROCESSOR}\n")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "The host system is: ${CMAKE_HOST_SYSTEM_NAME} - ${CMAKE_HOST_SYSTEM_VERSION} - ${CMAKE_HOST_SYSTEM_PROCESSOR}\n")
+ else()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "The system is: ${CMAKE_SYSTEM_NAME} - ${CMAKE_SYSTEM_VERSION} - ${CMAKE_SYSTEM_PROCESSOR}\n")
+ endif()
+
+ # if a toolchain file is used, it needs to be included in the configured file,
+ # so settings done there are also available if they don't go in the cache and in try_compile()
+ set(INCLUDE_CMAKE_TOOLCHAIN_FILE_IF_REQUIRED)
+ if(CMAKE_TOOLCHAIN_FILE)
+ set(INCLUDE_CMAKE_TOOLCHAIN_FILE_IF_REQUIRED "include(\"${CMAKE_TOOLCHAIN_FILE}\")")
+ endif()
+
+ # configure variables set in this file for fast reload, the template file is defined at the top of this file
+ configure_file(${CMAKE_ROOT}/Modules/CMakeSystem.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeSystem.cmake
+ @ONLY)
+
+endif()
diff --git a/Modules/CMakeDetermineVSServicePack.cmake b/Modules/CMakeDetermineVSServicePack.cmake
new file mode 100644
index 0000000..53868d2
--- /dev/null
+++ b/Modules/CMakeDetermineVSServicePack.cmake
@@ -0,0 +1,174 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CMakeDetermineVSServicePack
+---------------------------
+
+.. deprecated:: 3.0
+
+ Do not use.
+
+The functionality of this module has been superseded by the
+:variable:`CMAKE_<LANG>_COMPILER_VERSION` variable that contains
+the compiler version number.
+
+Determine the Visual Studio service pack of the 'cl' in use.
+
+Usage::
+
+ if(MSVC)
+ include(CMakeDetermineVSServicePack)
+ DetermineVSServicePack( my_service_pack )
+ if( my_service_pack )
+ message(STATUS "Detected: ${my_service_pack}")
+ endif()
+ endif()
+
+Function DetermineVSServicePack sets the given variable to one of the
+following values or an empty string if unknown::
+
+ vc80, vc80sp1
+ vc90, vc90sp1
+ vc100, vc100sp1
+ vc110, vc110sp1, vc110sp2, vc110sp3, vc110sp4
+#]=======================================================================]
+
+if(NOT CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.8)
+ message(DEPRECATION
+ "This module is deprecated and should not be used. "
+ "Use the CMAKE_<LANG>_COMPILER_VERSION variable instead."
+ )
+endif()
+
+# [INTERNAL]
+# Please do not call this function directly
+function(_DetermineVSServicePackFromCompiler _OUT_VAR _cl_version)
+ if (${_cl_version} VERSION_EQUAL "14.00.50727.42")
+ set(_version "vc80")
+ elseif(${_cl_version} VERSION_EQUAL "14.00.50727.762")
+ set(_version "vc80sp1")
+ elseif(${_cl_version} VERSION_EQUAL "15.00.21022.08")
+ set(_version "vc90")
+ elseif(${_cl_version} VERSION_EQUAL "15.00.30729.01")
+ set(_version "vc90sp1")
+ elseif(${_cl_version} VERSION_EQUAL "16.00.30319.01")
+ set(_version "vc100")
+ elseif(${_cl_version} VERSION_EQUAL "16.00.40219.01")
+ set(_version "vc100sp1")
+ elseif(${_cl_version} VERSION_EQUAL "17.00.50727.1")
+ set(_version "vc110")
+ elseif(${_cl_version} VERSION_EQUAL "17.00.51106.1")
+ set(_version "vc110sp1")
+ elseif(${_cl_version} VERSION_EQUAL "17.00.60315.1")
+ set(_version "vc110sp2")
+ elseif(${_cl_version} VERSION_EQUAL "17.00.60610.1")
+ set(_version "vc110sp3")
+ elseif(${_cl_version} VERSION_EQUAL "17.00.61030")
+ set(_version "vc110sp4")
+ else()
+ set(_version "")
+ endif()
+ set(${_OUT_VAR} ${_version} PARENT_SCOPE)
+endfunction()
+
+
+############################################################
+# [INTERNAL]
+# Please do not call this function directly
+function(_DetermineVSServicePack_FastCheckVersionWithCompiler _SUCCESS_VAR _VERSION_VAR)
+ if(EXISTS ${CMAKE_CXX_COMPILER})
+ execute_process(
+ COMMAND ${CMAKE_CXX_COMPILER} -?
+ ERROR_VARIABLE _output
+ OUTPUT_QUIET
+ )
+
+ if(_output MATCHES "Compiler Version (([0-9]+)\\.([0-9]+)\\.([0-9]+)(\\.([0-9]+))?)")
+ set(_cl_version ${CMAKE_MATCH_1})
+ set(_major ${CMAKE_MATCH_2})
+ set(_minor ${CMAKE_MATCH_3})
+ if("${_major}${_minor}" STREQUAL "${MSVC_VERSION}")
+ set(${_SUCCESS_VAR} true PARENT_SCOPE)
+ set(${_VERSION_VAR} ${_cl_version} PARENT_SCOPE)
+ endif()
+ endif()
+ endif()
+endfunction()
+
+############################################################
+# [INTERNAL]
+# Please do not call this function directly
+function(_DetermineVSServicePack_CheckVersionWithTryCompile _SUCCESS_VAR _VERSION_VAR)
+ file(WRITE "${CMAKE_BINARY_DIR}/return0.cc"
+ "int main() { return 0; }\n")
+
+ try_compile(
+ _CompileResult
+ "${CMAKE_BINARY_DIR}"
+ "${CMAKE_BINARY_DIR}/return0.cc"
+ OUTPUT_VARIABLE _output
+ COPY_FILE "${CMAKE_BINARY_DIR}/return0.cc")
+
+ file(REMOVE "${CMAKE_BINARY_DIR}/return0.cc")
+
+ if(_output MATCHES "Compiler Version (([0-9]+)\\.([0-9]+)\\.([0-9]+)(\\.([0-9]+))?)")
+ set(${_SUCCESS_VAR} true PARENT_SCOPE)
+ set(${_VERSION_VAR} "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+############################################################
+# [INTERNAL]
+# Please do not call this function directly
+function(_DetermineVSServicePack_CheckVersionWithTryRun _SUCCESS_VAR _VERSION_VAR)
+ file(WRITE "${CMAKE_BINARY_DIR}/return0.cc"
+ "#include <stdio.h>\n\nconst unsigned int CompilerVersion=_MSC_FULL_VER;\n\nint main(int argc, char* argv[])\n{\n int M( CompilerVersion/10000000);\n int m((CompilerVersion%10000000)/100000);\n int b(CompilerVersion%100000);\n\n printf(\"%d.%02d.%05d.01\",M,m,b);\n return 0;\n}\n")
+
+ try_run(
+ _RunResult
+ _CompileResult
+ "${CMAKE_BINARY_DIR}"
+ "${CMAKE_BINARY_DIR}/return0.cc"
+ RUN_OUTPUT_VARIABLE _runoutput
+ )
+
+ file(REMOVE "${CMAKE_BINARY_DIR}/return0.cc")
+
+ string(REGEX MATCH "[0-9]+.[0-9]+.[0-9]+.[0-9]+"
+ _cl_version "${_runoutput}")
+
+ if(_cl_version)
+ set(${_SUCCESS_VAR} true PARENT_SCOPE)
+ set(${_VERSION_VAR} ${_cl_version} PARENT_SCOPE)
+ endif()
+endfunction()
+
+
+#
+# A function to call to determine the Visual Studio service pack
+# in use. See documentation above.
+function(DetermineVSServicePack _pack)
+ if(NOT DETERMINED_VS_SERVICE_PACK OR NOT ${_pack})
+
+ _DetermineVSServicePack_FastCheckVersionWithCompiler(DETERMINED_VS_SERVICE_PACK _cl_version)
+ if(NOT DETERMINED_VS_SERVICE_PACK)
+ _DetermineVSServicePack_CheckVersionWithTryCompile(DETERMINED_VS_SERVICE_PACK _cl_version)
+ if(NOT DETERMINED_VS_SERVICE_PACK)
+ _DetermineVSServicePack_CheckVersionWithTryRun(DETERMINED_VS_SERVICE_PACK _cl_version)
+ endif()
+ endif()
+
+ if(DETERMINED_VS_SERVICE_PACK)
+
+ if(_cl_version)
+ # Call helper function to determine VS version
+ _DetermineVSServicePackFromCompiler(_sp "${_cl_version}")
+ if(_sp)
+ set(${_pack} ${_sp} CACHE INTERNAL
+ "The Visual Studio Release with Service Pack")
+ endif()
+ endif()
+ endif()
+ endif()
+endfunction()
diff --git a/Modules/CMakeExpandImportedTargets.cmake b/Modules/CMakeExpandImportedTargets.cmake
new file mode 100644
index 0000000..b8f471c
--- /dev/null
+++ b/Modules/CMakeExpandImportedTargets.cmake
@@ -0,0 +1,148 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CMakeExpandImportedTargets
+--------------------------
+
+.. deprecated:: 3.4
+
+ Do not use.
+
+This module was once needed to expand imported targets to the underlying
+libraries they reference on disk for use with the :command:`try_compile`
+and :command:`try_run` commands. These commands now support imported
+libraries in their ``LINK_LIBRARIES`` options (since CMake 2.8.11
+for :command:`try_compile` and since CMake 3.2 for :command:`try_run`).
+
+This module does not support the policy :policy:`CMP0022` ``NEW``
+behavior or use of the :prop_tgt:`INTERFACE_LINK_LIBRARIES` property
+because :manual:`generator expressions <cmake-generator-expressions(7)>`
+cannot be evaluated during configuration.
+
+::
+
+ CMAKE_EXPAND_IMPORTED_TARGETS(<var> LIBRARIES lib1 lib2...libN
+ [CONFIGURATION <config>])
+
+CMAKE_EXPAND_IMPORTED_TARGETS() takes a list of libraries and replaces
+all imported targets contained in this list with their actual file
+paths of the referenced libraries on disk, including the libraries
+from their link interfaces. If a CONFIGURATION is given, it uses the
+respective configuration of the imported targets if it exists. If no
+CONFIGURATION is given, it uses the first configuration from
+${CMAKE_CONFIGURATION_TYPES} if set, otherwise ${CMAKE_BUILD_TYPE}.
+
+::
+
+ cmake_expand_imported_targets(expandedLibs
+ LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}
+ CONFIGURATION "${CMAKE_TRY_COMPILE_CONFIGURATION}" )
+#]=======================================================================]
+
+function(CMAKE_EXPAND_IMPORTED_TARGETS _RESULT )
+
+ set(options )
+ set(oneValueArgs CONFIGURATION )
+ set(multiValueArgs LIBRARIES )
+
+ cmake_parse_arguments(CEIT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(CEIT_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to CMAKE_EXPAND_IMPORTED_TARGETS(): \"${CEIT_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if(NOT CEIT_CONFIGURATION)
+ # Would be better to test GENERATOR_IS_MULTI_CONFIG global property,
+ # but the documented behavior specifically says we check
+ # CMAKE_CONFIGURATION_TYPES and fall back to CMAKE_BUILD_TYPE if no
+ # config types are defined.
+ if(CMAKE_CONFIGURATION_TYPES)
+ list(GET CMAKE_CONFIGURATION_TYPES 0 CEIT_CONFIGURATION)
+ else()
+ set(CEIT_CONFIGURATION ${CMAKE_BUILD_TYPE})
+ endif()
+ endif()
+
+ # handle imported library targets
+
+ set(_CCSR_REQ_LIBS ${CEIT_LIBRARIES})
+
+ set(_CHECK_FOR_IMPORTED_TARGETS TRUE)
+ set(_CCSR_LOOP_COUNTER 0)
+ while(_CHECK_FOR_IMPORTED_TARGETS)
+ math(EXPR _CCSR_LOOP_COUNTER "${_CCSR_LOOP_COUNTER} + 1 ")
+ set(_CCSR_NEW_REQ_LIBS )
+ set(_CHECK_FOR_IMPORTED_TARGETS FALSE)
+ foreach(_CURRENT_LIB ${_CCSR_REQ_LIBS})
+ if(TARGET "${_CURRENT_LIB}")
+ get_target_property(_importedConfigs "${_CURRENT_LIB}" IMPORTED_CONFIGURATIONS)
+ else()
+ set(_importedConfigs "")
+ endif()
+ if (_importedConfigs)
+ # message(STATUS "Detected imported target ${_CURRENT_LIB}")
+ # Ok, so this is an imported target.
+ # First we get the imported configurations.
+ # Then we get the location of the actual library on disk of the first configuration.
+ # then we'll get its link interface libraries property,
+ # iterate through it and replace all imported targets we find there
+ # with there actual location.
+
+ # guard against infinite loop: abort after 100 iterations ( 100 is arbitrary chosen)
+ if ("${_CCSR_LOOP_COUNTER}" LESS 100)
+ set(_CHECK_FOR_IMPORTED_TARGETS TRUE)
+# else ()
+# message(STATUS "********* aborting loop, counter : ${_CCSR_LOOP_COUNTER}")
+ endif ()
+
+ # if one of the imported configurations equals ${CMAKE_TRY_COMPILE_CONFIGURATION},
+ # use it, otherwise simply use the first one:
+ list(FIND _importedConfigs "${CEIT_CONFIGURATION}" _configIndexToUse)
+ if("${_configIndexToUse}" EQUAL -1)
+ set(_configIndexToUse 0)
+ endif()
+ list(GET _importedConfigs ${_configIndexToUse} _importedConfigToUse)
+
+ get_target_property(_importedLocation "${_CURRENT_LIB}" IMPORTED_LOCATION_${_importedConfigToUse})
+ get_target_property(_linkInterfaceLibs "${_CURRENT_LIB}" IMPORTED_LINK_INTERFACE_LIBRARIES_${_importedConfigToUse} )
+
+ list(APPEND _CCSR_NEW_REQ_LIBS "${_importedLocation}")
+# message(STATUS "Appending lib ${_CURRENT_LIB} as ${_importedLocation}")
+ if(_linkInterfaceLibs)
+ foreach(_currentLinkInterfaceLib ${_linkInterfaceLibs})
+# message(STATUS "Appending link interface lib ${_currentLinkInterfaceLib}")
+ if(_currentLinkInterfaceLib)
+ list(APPEND _CCSR_NEW_REQ_LIBS "${_currentLinkInterfaceLib}" )
+ endif()
+ endforeach()
+ endif()
+ else()
+ # "Normal" libraries are just used as they are.
+ list(APPEND _CCSR_NEW_REQ_LIBS "${_CURRENT_LIB}" )
+# message(STATUS "Appending lib directly: ${_CURRENT_LIB}")
+ endif()
+ endforeach()
+ set(_CCSR_REQ_LIBS ${_CCSR_NEW_REQ_LIBS} )
+ endwhile()
+
+ # Finally we iterate once more over all libraries. This loop only removes
+ # all remaining imported target names (there shouldn't be any left anyway).
+ set(_CCSR_NEW_REQ_LIBS )
+ foreach(_CURRENT_LIB ${_CCSR_REQ_LIBS})
+ if(TARGET "${_CURRENT_LIB}")
+ get_target_property(_importedConfigs "${_CURRENT_LIB}" IMPORTED_CONFIGURATIONS)
+ else()
+ set(_importedConfigs "")
+ endif()
+ if (NOT _importedConfigs)
+ list(APPEND _CCSR_NEW_REQ_LIBS "${_CURRENT_LIB}" )
+# message(STATUS "final: appending ${_CURRENT_LIB}")
+# else ()
+# message(STATUS "final: skipping ${_CURRENT_LIB}")
+ endif ()
+ endforeach()
+# message(STATUS "setting -${_RESULT}- to -${_CCSR_NEW_REQ_LIBS}-")
+ set(${_RESULT} "${_CCSR_NEW_REQ_LIBS}" PARENT_SCOPE)
+
+endfunction()
diff --git a/Modules/CMakeExportBuildSettings.cmake b/Modules/CMakeExportBuildSettings.cmake
new file mode 100644
index 0000000..cafc830
--- /dev/null
+++ b/Modules/CMakeExportBuildSettings.cmake
@@ -0,0 +1,26 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is purposely no longer documented. It does nothing useful.
+if(NOT "${CMAKE_MINIMUM_REQUIRED_VERSION}" VERSION_LESS 2.7)
+ message(FATAL_ERROR
+ "The functionality of this module has been dropped as of CMake 2.8. "
+ "It was deemed harmful (confusing users by changing their compiler). "
+ "Please remove calls to the CMAKE_EXPORT_BUILD_SETTINGS macro and "
+ "stop including this module. "
+ "If this project generates any files for use by external projects, "
+ "remove any use of the CMakeImportBuildSettings module from them.")
+endif()
+
+# This macro used to store build settings of a project in a file to be
+# loaded by another project using CMAKE_IMPORT_BUILD_SETTINGS. Now it
+# creates a file that refuses to load (with comment explaining why).
+macro(CMAKE_EXPORT_BUILD_SETTINGS SETTINGS_FILE)
+ if(NOT ${SETTINGS_FILE} STREQUAL "")
+ configure_file(${CMAKE_ROOT}/Modules/CMakeBuildSettings.cmake.in
+ ${SETTINGS_FILE} @ONLY)
+ else()
+ message(SEND_ERROR "CMAKE_EXPORT_BUILD_SETTINGS called with no argument.")
+ endif()
+endmacro()
diff --git a/Modules/CMakeExtraGeneratorDetermineCompilerMacrosAndIncludeDirs.cmake b/Modules/CMakeExtraGeneratorDetermineCompilerMacrosAndIncludeDirs.cmake
new file mode 100644
index 0000000..f90301b
--- /dev/null
+++ b/Modules/CMakeExtraGeneratorDetermineCompilerMacrosAndIncludeDirs.cmake
@@ -0,0 +1,114 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is included by CMakeFindEclipseCDT4.cmake and CMakeFindCodeBlocks.cmake
+
+# The Eclipse and the CodeBlocks generators need to know the standard include path
+# so that they can find the headers at runtime and parsing etc. works better
+# This is done here by actually running gcc with the options so it prints its
+# system include directories, which are parsed then and stored in the cache.
+macro(_DETERMINE_GCC_SYSTEM_INCLUDE_DIRS _lang _resultIncludeDirs _resultDefines)
+ set(${_resultIncludeDirs})
+ set(_gccOutput)
+ file(WRITE "${CMAKE_BINARY_DIR}/CMakeFiles/dummy" "\n" )
+
+ if (${_lang} STREQUAL "c++")
+ set(_compilerExecutable "${CMAKE_CXX_COMPILER}")
+ set(_arg1 "${CMAKE_CXX_COMPILER_ARG1}")
+
+ if (CMAKE_CXX_FLAGS MATCHES "(-stdlib=[^ ]+)")
+ set(_stdlib "${CMAKE_MATCH_1}")
+ endif ()
+ if (CMAKE_CXX_FLAGS MATCHES "(-std=[^ ]+)")
+ set(_stdver "${CMAKE_MATCH_1}")
+ endif ()
+ else ()
+ set(_compilerExecutable "${CMAKE_C_COMPILER}")
+ set(_arg1 "${CMAKE_C_COMPILER_ARG1}")
+ endif ()
+ separate_arguments(_arg1 NATIVE_COMMAND "${_arg1}")
+ execute_process(COMMAND ${_compilerExecutable} ${_arg1} ${_stdver} ${_stdlib} -v -E -x ${_lang} -dD dummy
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/CMakeFiles
+ ERROR_VARIABLE _gccOutput
+ OUTPUT_VARIABLE _gccStdout )
+ file(REMOVE "${CMAKE_BINARY_DIR}/CMakeFiles/dummy")
+
+ # First find the system include dirs:
+ if( "${_gccOutput}" MATCHES "> search starts here[^\n]+\n *(.+ *\n) *End of (search) list" )
+
+ # split the output into lines and then remove leading and trailing spaces from each of them:
+ string(REGEX MATCHALL "[^\n]+\n" _includeLines "${CMAKE_MATCH_1}")
+ foreach(nextLine ${_includeLines})
+ # on OSX, gcc says things like this: "/System/Library/Frameworks (framework directory)", strip the last part
+ string(REGEX REPLACE "\\(framework directory\\)" "" nextLineNoFramework "${nextLine}")
+ # strip spaces at the beginning and the end
+ string(STRIP "${nextLineNoFramework}" _includePath)
+ list(APPEND ${_resultIncludeDirs} "${_includePath}")
+ endforeach()
+
+ endif()
+
+
+ # now find the builtin macros:
+ string(REGEX MATCHALL "#define[^\n]+\n" _defineLines "${_gccStdout}")
+# A few example lines which the regexp below has to match properly:
+# #define MAX(a,b) ((a) > (b) ? (a) : (b))
+# #define __fastcall __attribute__((__fastcall__))
+# #define FOO (23)
+# #define __UINTMAX_TYPE__ long long unsigned int
+# #define __UINTMAX_TYPE__ long long unsigned int
+# #define __i386__ 1
+
+ foreach(nextLine ${_defineLines})
+ string(REGEX MATCH "^#define +([A-Za-z_][A-Za-z0-9_]*)(\\([^\\)]+\\))? +(.+) *$" _dummy "${nextLine}")
+ set(_name "${CMAKE_MATCH_1}${CMAKE_MATCH_2}")
+ string(STRIP "${CMAKE_MATCH_3}" _value)
+ #message(STATUS "m1: -${CMAKE_MATCH_1}- m2: -${CMAKE_MATCH_2}- m3: -${CMAKE_MATCH_3}-")
+
+ list(APPEND ${_resultDefines} "${_name}")
+ if ("${_value}" STREQUAL "")
+ list(APPEND ${_resultDefines} " ")
+ else()
+ list(APPEND ${_resultDefines} "${_value}")
+ endif()
+ endforeach()
+
+endmacro()
+
+# Save the current LC_ALL, LC_MESSAGES, and LANG environment variables and set them
+# to "C" that way GCC's "search starts here" text is in English and we can grok it.
+set(_orig_lc_all $ENV{LC_ALL})
+set(_orig_lc_messages $ENV{LC_MESSAGES})
+set(_orig_lang $ENV{LANG})
+
+set(ENV{LC_ALL} C)
+set(ENV{LC_MESSAGES} C)
+set(ENV{LANG} C)
+
+# Now check for C, works for gcc and Intel compiler at least
+if (NOT CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS)
+ if (CMAKE_C_COMPILER_ID MATCHES GNU OR CMAKE_C_COMPILER_ID MATCHES "Intel" OR CMAKE_C_COMPILER_ID MATCHES Clang)
+ _DETERMINE_GCC_SYSTEM_INCLUDE_DIRS(c _dirs _defines)
+ set(CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS "${_dirs}" CACHE INTERNAL "C compiler system include directories")
+ set(CMAKE_EXTRA_GENERATOR_C_SYSTEM_DEFINED_MACROS "${_defines}" CACHE INTERNAL "C compiler system defined macros")
+ elseif ("${CMAKE_C_COMPILER_ID}" MATCHES MSVC)
+ set(CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS "$ENV{INCLUDE}" CACHE INTERNAL "C compiler system include directories")
+ endif ()
+endif ()
+
+# And now the same for C++
+if (NOT CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS)
+ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES GNU OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES Clang)
+ _DETERMINE_GCC_SYSTEM_INCLUDE_DIRS(c++ _dirs _defines)
+ set(CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS "${_dirs}" CACHE INTERNAL "CXX compiler system include directories")
+ set(CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_DEFINED_MACROS "${_defines}" CACHE INTERNAL "CXX compiler system defined macros")
+ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES MSVC)
+ set(CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS "$ENV{INCLUDE}" CACHE INTERNAL "CXX compiler system include directories")
+ endif ()
+endif ()
+
+# Restore original LC_ALL, LC_MESSAGES, and LANG
+set(ENV{LC_ALL} ${_orig_lc_all})
+set(ENV{LC_MESSAGES} ${_orig_lc_messages})
+set(ENV{LANG} ${_orig_lang})
diff --git a/Modules/CMakeFindBinUtils.cmake b/Modules/CMakeFindBinUtils.cmake
new file mode 100644
index 0000000..f32266f
--- /dev/null
+++ b/Modules/CMakeFindBinUtils.cmake
@@ -0,0 +1,165 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# search for additional tools required for C/C++ (and other languages ?)
+#
+# If the internal cmake variable _CMAKE_TOOLCHAIN_PREFIX is set, this is used
+# as prefix for the tools (e.g. arm-elf-gcc etc.)
+# If the cmake variable _CMAKE_TOOLCHAIN_LOCATION is set, the compiler is
+# searched only there. The other tools are at first searched there, then
+# also in the default locations.
+#
+# Sets the following variables:
+# CMAKE_AR
+# CMAKE_RANLIB
+# CMAKE_LINKER
+# CMAKE_MT
+# CMAKE_STRIP
+# CMAKE_INSTALL_NAME_TOOL
+
+# on UNIX, cygwin and mingw
+
+# Resolve full path of CMAKE_TOOL from user-defined name and SEARCH_PATH.
+function(__resolve_tool_path CMAKE_TOOL SEARCH_PATH DOCSTRING)
+
+ if(${CMAKE_TOOL})
+ # We only get here if CMAKE_TOOL was
+ # specified using -D or a pre-made CMakeCache.txt (e.g. via ctest)
+ # or set in CMAKE_TOOLCHAIN_FILE.
+
+ get_filename_component(_CMAKE_USER_TOOL_PATH "${${CMAKE_TOOL}}" DIRECTORY)
+ # Is CMAKE_TOOL a user-defined name instead of a full path?
+ if(NOT _CMAKE_USER_TOOL_PATH)
+
+ # Find CMAKE_TOOL in the SEARCH_PATH directory by user-defined name.
+ find_program(_CMAKE_TOOL_WITH_PATH NAMES ${${CMAKE_TOOL}} HINTS ${SEARCH_PATH})
+ if(_CMAKE_TOOL_WITH_PATH)
+
+ # Overwrite CMAKE_TOOL with full path found in SEARCH_PATH.
+ set(${CMAKE_TOOL} ${_CMAKE_TOOL_WITH_PATH} PARENT_SCOPE)
+
+ get_property(_CMAKE_TOOL_CACHED CACHE ${CMAKE_TOOL} PROPERTY TYPE)
+ # If CMAKE_TOOL is present in the CMake Cache, then overwrit it as well.
+ if(_CMAKE_TOOL_CACHED)
+ set(${CMAKE_TOOL} "${_CMAKE_TOOL_WITH_PATH}" CACHE STRING ${DOCSTRING} FORCE)
+ endif()
+
+ endif()
+ unset(_CMAKE_TOOL_WITH_PATH CACHE)
+
+ endif()
+
+ endif()
+
+endfunction()
+
+__resolve_tool_path(CMAKE_LINKER "${_CMAKE_TOOLCHAIN_LOCATION}" "Default Linker")
+__resolve_tool_path(CMAKE_MT "${_CMAKE_TOOLCHAIN_LOCATION}" "Default Manifest Tool")
+
+set(_CMAKE_TOOL_VARS "")
+
+# if it's the MS C/CXX compiler, search for link
+if(("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC" AND
+ ("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC"
+ OR NOT "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xClang"))
+ OR "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xMSVC"
+ OR (CMAKE_HOST_WIN32 AND "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xPGI")
+ OR (CMAKE_HOST_WIN32 AND "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xNVIDIA")
+ OR (CMAKE_HOST_WIN32 AND "x${_CMAKE_PROCESSING_LANGUAGE}" STREQUAL "xISPC")
+ OR (CMAKE_GENERATOR MATCHES "Visual Studio"
+ AND NOT CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android"))
+
+ set(_CMAKE_LINKER_NAMES "link")
+ set(_CMAKE_AR_NAMES "lib")
+ set(_CMAKE_MT_NAMES "mt")
+ if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xClang")
+ set(_CMAKE_NM_NAMES "llvm-nm" "nm")
+ list(APPEND _CMAKE_AR_NAMES "lib" "llvm-lib")
+ list(APPEND _CMAKE_MT_NAMES "mt" "llvm-mt")
+ list(APPEND _CMAKE_LINKER_NAMES "lld-link")
+ list(APPEND _CMAKE_TOOL_VARS NM)
+ endif()
+
+ list(APPEND _CMAKE_TOOL_VARS LINKER MT AR)
+
+# in all other cases search for ar, ranlib, etc.
+else()
+ if(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN)
+ set(_CMAKE_TOOLCHAIN_LOCATION ${_CMAKE_TOOLCHAIN_LOCATION} ${CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN}/bin)
+ endif()
+ if(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN)
+ set(_CMAKE_TOOLCHAIN_LOCATION ${_CMAKE_TOOLCHAIN_LOCATION} ${CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN}/bin)
+ endif()
+
+ if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL Clang)
+ if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC")
+ set(_CMAKE_LINKER_NAMES "lld-link")
+ else()
+ set(_CMAKE_LINKER_NAMES "ld.lld")
+ endif()
+ list(APPEND _CMAKE_AR_NAMES "llvm-ar")
+ list(APPEND _CMAKE_RANLIB_NAMES "llvm-ranlib")
+ list(APPEND _CMAKE_STRIP_NAMES "llvm-strip")
+ list(APPEND _CMAKE_NM_NAMES "llvm-nm")
+ list(APPEND _CMAKE_OBJDUMP_NAMES "llvm-objdump")
+ list(APPEND _CMAKE_OBJCOPY_NAMES "llvm-objcopy")
+ list(APPEND _CMAKE_READELF_NAMES "llvm-readelf")
+ list(APPEND _CMAKE_DLLTOOL_NAMES "llvm-dlltool")
+ list(APPEND _CMAKE_ADDR2LINE_NAMES "llvm-addr2line")
+ endif()
+
+ list(APPEND _CMAKE_AR_NAMES "ar")
+ list(APPEND _CMAKE_RANLIB_NAMES "ranlib")
+ list(APPEND _CMAKE_STRIP_NAMES "strip")
+ list(APPEND _CMAKE_LINKER_NAMES "ld")
+ list(APPEND _CMAKE_NM_NAMES "nm")
+ list(APPEND _CMAKE_OBJDUMP_NAMES "objdump")
+ list(APPEND _CMAKE_OBJCOPY_NAMES "objcopy")
+ list(APPEND _CMAKE_READELF_NAMES "readelf")
+ list(APPEND _CMAKE_DLLTOOL_NAMES "dlltool")
+ list(APPEND _CMAKE_ADDR2LINE_NAMES "addr2line")
+
+ list(APPEND _CMAKE_TOOL_VARS AR RANLIB STRIP LINKER NM OBJDUMP OBJCOPY READELF DLLTOOL ADDR2LINE)
+endif()
+
+foreach(_tool IN LISTS _CMAKE_TOOL_VARS)
+ foreach(_name IN LISTS _CMAKE_${_tool}_NAMES)
+ if(NOT _CMAKE_TOOLCHAIN_PREFIX STREQUAL "")
+ if(NOT _CMAKE_TOOLCHAIN_SUFFIX STREQUAL "")
+ list(PREPEND _CMAKE_${_tool}_NAMES ${_name}${_CMAKE_TOOLCHAIN_SUFFIX})
+ endif()
+ list(PREPEND _CMAKE_${_tool}_NAMES ${_CMAKE_TOOLCHAIN_PREFIX}${_name})
+ endif()
+ if(NOT _CMAKE_TOOLCHAIN_SUFFIX STREQUAL "")
+ list(PREPEND _CMAKE_${_tool}_NAMES ${_CMAKE_TOOLCHAIN_PREFIX}${_name}${_CMAKE_TOOLCHAIN_SUFFIX})
+ endif()
+ endforeach()
+ find_program(CMAKE_${_tool} NAMES ${_CMAKE_${_tool}_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
+endforeach()
+
+if(NOT CMAKE_RANLIB)
+ set(CMAKE_RANLIB : CACHE INTERNAL "noop for ranlib")
+endif()
+
+
+if(CMAKE_PLATFORM_HAS_INSTALLNAME)
+ find_program(CMAKE_INSTALL_NAME_TOOL NAMES ${_CMAKE_TOOLCHAIN_PREFIX}install_name_tool HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
+
+ if(NOT CMAKE_INSTALL_NAME_TOOL)
+ message(FATAL_ERROR "Could not find install_name_tool, please check your installation.")
+ endif()
+
+ list(APPEND _CMAKE_TOOL_VARS INSTALL_NAME_TOOL)
+endif()
+
+# Mark any tool cache entries as advanced.
+foreach(_tool IN LISTS _CMAKE_TOOL_VARS)
+ get_property(_CMAKE_TOOL_CACHED CACHE CMAKE_${_tool} PROPERTY TYPE)
+ if(_CMAKE_TOOL_CACHED)
+ mark_as_advanced(CMAKE_${_tool})
+ endif()
+ unset(_CMAKE_${_tool}_NAMES)
+endforeach()
+unset(_CMAKE_TOOL_VARS)
+unset(_CMAKE_TOOL_CACHED)
diff --git a/Modules/CMakeFindCodeBlocks.cmake b/Modules/CMakeFindCodeBlocks.cmake
new file mode 100644
index 0000000..bf27ec1
--- /dev/null
+++ b/Modules/CMakeFindCodeBlocks.cmake
@@ -0,0 +1,33 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is included in CMakeSystemSpecificInformation.cmake if
+# the CodeBlocks extra generator has been selected.
+
+find_program(CMAKE_CODEBLOCKS_EXECUTABLE NAMES codeblocks DOC "The CodeBlocks executable")
+
+if(CMAKE_CODEBLOCKS_EXECUTABLE)
+ set(CMAKE_OPEN_PROJECT_COMMAND "${CMAKE_CODEBLOCKS_EXECUTABLE} <PROJECT_FILE>" )
+endif()
+
+# Determine builtin macros and include dirs:
+include(${CMAKE_CURRENT_LIST_DIR}/CMakeExtraGeneratorDetermineCompilerMacrosAndIncludeDirs.cmake)
+
+# Try to find out how many CPUs we have and set the -j argument for make accordingly
+set(_CMAKE_CODEBLOCKS_INITIAL_MAKE_ARGS "")
+
+include(ProcessorCount)
+processorcount(_CMAKE_CODEBLOCKS_PROCESSOR_COUNT)
+
+# Only set -j if we are under UNIX and if the make-tool used actually has "make" in the name
+# (we may also get here in the future e.g. for ninja)
+if("${_CMAKE_CODEBLOCKS_PROCESSOR_COUNT}" GREATER 1 AND CMAKE_HOST_UNIX AND "${CMAKE_MAKE_PROGRAM}" MATCHES make)
+ set(_CMAKE_CODEBLOCKS_INITIAL_MAKE_ARGS "-j${_CMAKE_CODEBLOCKS_PROCESSOR_COUNT}")
+endif()
+
+# This variable is used by the CodeBlocks generator and appended to the make invocation commands.
+set(CMAKE_CODEBLOCKS_MAKE_ARGUMENTS "${_CMAKE_CODEBLOCKS_INITIAL_MAKE_ARGS}" CACHE STRING "Additional command line arguments when CodeBlocks invokes make. Enter e.g. -j<some_number> to get parallel builds")
+
+# This variable is used by the CodeBlocks generator and allows the user to overwrite the autodetected CodeBlocks compiler id
+set(CMAKE_CODEBLOCKS_COMPILER_ID "" CACHE STRING "Id string of the compiler for the CodeBlocks IDE. Automatically detected when left empty")
diff --git a/Modules/CMakeFindDependencyMacro.cmake b/Modules/CMakeFindDependencyMacro.cmake
new file mode 100644
index 0000000..bcdfbeb
--- /dev/null
+++ b/Modules/CMakeFindDependencyMacro.cmake
@@ -0,0 +1,63 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CMakeFindDependencyMacro
+-------------------------
+
+.. command:: find_dependency
+
+ The ``find_dependency()`` macro wraps a :command:`find_package` call for
+ a package dependency::
+
+ find_dependency(<dep> [...])
+
+ It is designed to be used in a
+ :ref:`Package Configuration File <Config File Packages>`
+ (``<PackageName>Config.cmake``). ``find_dependency`` forwards the correct
+ parameters for ``QUIET`` and ``REQUIRED`` which were passed to
+ the original :command:`find_package` call. Any additional arguments
+ specified are forwarded to :command:`find_package`.
+
+ If the dependency could not be found it sets an informative diagnostic
+ message and calls :command:`return` to end processing of the calling
+ package configuration file and return to the :command:`find_package`
+ command that loaded it.
+
+ .. note::
+
+ The call to :command:`return` makes this macro unsuitable to call
+ from :ref:`Find Modules`.
+#]=======================================================================]
+
+macro(find_dependency dep)
+ set(cmake_fd_quiet_arg)
+ if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
+ set(cmake_fd_quiet_arg QUIET)
+ endif()
+ set(cmake_fd_required_arg)
+ if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
+ set(cmake_fd_required_arg REQUIRED)
+ endif()
+
+ get_property(cmake_fd_alreadyTransitive GLOBAL PROPERTY
+ _CMAKE_${dep}_TRANSITIVE_DEPENDENCY
+ )
+
+ find_package(${dep} ${ARGN}
+ ${cmake_fd_quiet_arg}
+ ${cmake_fd_required_arg}
+ )
+
+ if(NOT DEFINED cmake_fd_alreadyTransitive OR cmake_fd_alreadyTransitive)
+ set_property(GLOBAL PROPERTY _CMAKE_${dep}_TRANSITIVE_DEPENDENCY TRUE)
+ endif()
+
+ if (NOT ${dep}_FOUND)
+ set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "${CMAKE_FIND_PACKAGE_NAME} could not be found because dependency ${dep} could not be found.")
+ set(${CMAKE_FIND_PACKAGE_NAME}_FOUND False)
+ return()
+ endif()
+ set(cmake_fd_required_arg)
+ set(cmake_fd_quiet_arg)
+endmacro()
diff --git a/Modules/CMakeFindEclipseCDT4.cmake b/Modules/CMakeFindEclipseCDT4.cmake
new file mode 100644
index 0000000..e563a12
--- /dev/null
+++ b/Modules/CMakeFindEclipseCDT4.cmake
@@ -0,0 +1,89 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is included in CMakeSystemSpecificInformation.cmake if
+# the Eclipse CDT4 extra generator has been selected.
+
+find_program(CMAKE_ECLIPSE_EXECUTABLE NAMES eclipse DOC "The Eclipse executable")
+
+function(_FIND_ECLIPSE_VERSION)
+ # This code is in a function so the variables used here have only local scope
+
+ # Set up a map with the names of the Eclipse releases:
+ set(_ECLIPSE_VERSION_NAME_ "Unknown" )
+ set(_ECLIPSE_VERSION_NAME_3.2 "Callisto" )
+ set(_ECLIPSE_VERSION_NAME_3.3 "Europa" )
+ set(_ECLIPSE_VERSION_NAME_3.4 "Ganymede" )
+ set(_ECLIPSE_VERSION_NAME_3.5 "Galileo" )
+ set(_ECLIPSE_VERSION_NAME_3.6 "Helios" )
+ set(_ECLIPSE_VERSION_NAME_3.7 "Indigo" )
+ set(_ECLIPSE_VERSION_NAME_4.2 "Juno" )
+ set(_ECLIPSE_VERSION_NAME_4.3 "Kepler" )
+ set(_ECLIPSE_VERSION_NAME_4.4 "Luna" )
+ set(_ECLIPSE_VERSION_NAME_4.5 "Mars" )
+
+ if(NOT DEFINED CMAKE_ECLIPSE_VERSION)
+ if(CMAKE_ECLIPSE_EXECUTABLE)
+ # use REALPATH to resolve symlinks (https://gitlab.kitware.com/cmake/cmake/-/issues/13036)
+ get_filename_component(_REALPATH_CMAKE_ECLIPSE_EXECUTABLE "${CMAKE_ECLIPSE_EXECUTABLE}" REALPATH)
+ get_filename_component(_ECLIPSE_DIR "${_REALPATH_CMAKE_ECLIPSE_EXECUTABLE}" PATH)
+ file(GLOB _ECLIPSE_FEATURE_DIR "${_ECLIPSE_DIR}/features/org.eclipse.platform*")
+ if(APPLE AND NOT _ECLIPSE_FEATURE_DIR)
+ file(GLOB _ECLIPSE_FEATURE_DIR "${_ECLIPSE_DIR}/../../../features/org.eclipse.platform*")
+ endif()
+ if("${_ECLIPSE_FEATURE_DIR}" MATCHES ".+org.eclipse.platform_([0-9]+\\.[0-9]+).+")
+ set(_ECLIPSE_VERSION ${CMAKE_MATCH_1})
+ endif()
+ endif()
+
+ if(_ECLIPSE_VERSION)
+ message(STATUS "Found Eclipse version ${_ECLIPSE_VERSION} (${_ECLIPSE_VERSION_NAME_${_ECLIPSE_VERSION}})")
+ else()
+ set(_ECLIPSE_VERSION "3.6" )
+ message(STATUS "Could not determine Eclipse version, assuming at least ${_ECLIPSE_VERSION} (${_ECLIPSE_VERSION_NAME_${_ECLIPSE_VERSION}}). Adjust CMAKE_ECLIPSE_VERSION if this is wrong.")
+ endif()
+
+ set(CMAKE_ECLIPSE_VERSION "${_ECLIPSE_VERSION} (${_ECLIPSE_VERSION_NAME_${_ECLIPSE_VERSION}})" CACHE STRING "The version of Eclipse. If Eclipse has not been found, 3.6 (Helios) is assumed.")
+ else()
+ message(STATUS "Eclipse version is set to ${CMAKE_ECLIPSE_VERSION}. Adjust CMAKE_ECLIPSE_VERSION if this is wrong.")
+ endif()
+
+ set_property(CACHE CMAKE_ECLIPSE_VERSION PROPERTY STRINGS "3.2 (${_ECLIPSE_VERSION_NAME_3.2})"
+ "3.3 (${_ECLIPSE_VERSION_NAME_3.3})"
+ "3.4 (${_ECLIPSE_VERSION_NAME_3.4})"
+ "3.5 (${_ECLIPSE_VERSION_NAME_3.5})"
+ "3.6 (${_ECLIPSE_VERSION_NAME_3.6})"
+ "3.7 (${_ECLIPSE_VERSION_NAME_3.7})"
+ "4.2 (${_ECLIPSE_VERSION_NAME_4.2})"
+ "4.3 (${_ECLIPSE_VERSION_NAME_4.3})"
+ "4.4 (${_ECLIPSE_VERSION_NAME_4.4})"
+ "4.5 (${_ECLIPSE_VERSION_NAME_4.5})"
+ )
+endfunction()
+
+_find_eclipse_version()
+
+# Try to find out how many CPUs we have and set the -j argument for make accordingly
+set(_CMAKE_ECLIPSE_INITIAL_MAKE_ARGS "")
+
+include(ProcessorCount)
+processorcount(_CMAKE_ECLIPSE_PROCESSOR_COUNT)
+
+# Only set -j if we are under UNIX and if the make-tool used actually has "make" in the name
+# (we may also get here in the future e.g. for ninja)
+if("${_CMAKE_ECLIPSE_PROCESSOR_COUNT}" GREATER 1 AND CMAKE_HOST_UNIX AND "${CMAKE_MAKE_PROGRAM}" MATCHES make)
+ set(_CMAKE_ECLIPSE_INITIAL_MAKE_ARGS "-j${_CMAKE_ECLIPSE_PROCESSOR_COUNT}")
+endif()
+
+# This variable is used by the Eclipse generator and appended to the make invocation commands.
+set(CMAKE_ECLIPSE_MAKE_ARGUMENTS "${_CMAKE_ECLIPSE_INITIAL_MAKE_ARGS}" CACHE STRING "Additional command line arguments when Eclipse invokes make. Enter e.g. -j<some_number> to get parallel builds")
+
+set(CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES TRUE CACHE BOOL "If disabled, CMake will not generate linked resource to the subprojects and to the source files within targets")
+
+# This variable is used by the Eclipse generator in out-of-source builds only.
+set(CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT FALSE CACHE BOOL "If enabled, CMake will generate a source project for Eclipse in CMAKE_SOURCE_DIR")
+mark_as_advanced(CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT)
+
+# Determine builtin macros and include dirs:
+include(${CMAKE_CURRENT_LIST_DIR}/CMakeExtraGeneratorDetermineCompilerMacrosAndIncludeDirs.cmake)
diff --git a/Modules/CMakeFindFrameworks.cmake b/Modules/CMakeFindFrameworks.cmake
new file mode 100644
index 0000000..8906f48
--- /dev/null
+++ b/Modules/CMakeFindFrameworks.cmake
@@ -0,0 +1,45 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CMakeFindFrameworks
+-------------------
+
+helper module to find OSX frameworks
+
+This module reads hints about search locations from variables::
+
+ CMAKE_FIND_FRAMEWORK_EXTRA_LOCATIONS - Extra directories
+#]=======================================================================]
+
+if(NOT CMAKE_FIND_FRAMEWORKS_INCLUDED)
+ set(CMAKE_FIND_FRAMEWORKS_INCLUDED 1)
+ macro(CMAKE_FIND_FRAMEWORKS fwk)
+ set(${fwk}_FRAMEWORKS)
+ if(APPLE)
+ file(TO_CMAKE_PATH "$ENV{CMAKE_FRAMEWORK_PATH}" _cmff_CMAKE_FRAMEWORK_PATH)
+ set(_cmff_search_paths
+ ${CMAKE_FRAMEWORK_PATH}
+ ${_cmff_CMAKE_FRAMEWORK_PATH}
+ ~/Library/Frameworks
+ /usr/local/Frameworks
+ /Library/Frameworks
+ /System/Library/Frameworks
+ /Network/Library/Frameworks
+ ${CMAKE_SYSTEM_FRAMEWORK_PATH})
+
+ # For backwards compatibility reasons,
+ # CMAKE_FIND_FRAMEWORK_EXTRA_LOCATIONS includes ${fwk}.framework
+ list(TRANSFORM _cmff_search_paths APPEND /${fwk}.framework)
+ list(APPEND _cmff_search_paths ${CMAKE_FIND_FRAMEWORK_EXTRA_LOCATIONS})
+
+ list(REMOVE_DUPLICATES _cmff_search_paths)
+
+ foreach(dir IN LISTS _cmff_search_paths)
+ if(EXISTS ${dir})
+ set(${fwk}_FRAMEWORKS ${${fwk}_FRAMEWORKS} ${dir})
+ endif()
+ endforeach()
+ endif()
+ endmacro()
+endif()
diff --git a/Modules/CMakeFindJavaCommon.cmake b/Modules/CMakeFindJavaCommon.cmake
new file mode 100644
index 0000000..46b6280
--- /dev/null
+++ b/Modules/CMakeFindJavaCommon.cmake
@@ -0,0 +1,31 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# Do not include this module directly from code outside CMake!
+set(_JAVA_HOME "")
+if(JAVA_HOME AND IS_DIRECTORY "${JAVA_HOME}")
+ set(_JAVA_HOME "${JAVA_HOME}")
+ set(_JAVA_HOME_EXPLICIT 1)
+else()
+ set(_ENV_JAVA_HOME "")
+ if(DEFINED ENV{JAVA_HOME})
+ file(TO_CMAKE_PATH "$ENV{JAVA_HOME}" _ENV_JAVA_HOME)
+ endif()
+ if(_ENV_JAVA_HOME AND IS_DIRECTORY "${_ENV_JAVA_HOME}")
+ set(_JAVA_HOME "${_ENV_JAVA_HOME}")
+ set(_JAVA_HOME_EXPLICIT 1)
+ else()
+ set(_CMD_JAVA_HOME "")
+ if(APPLE AND EXISTS /usr/libexec/java_home)
+ execute_process(COMMAND /usr/libexec/java_home
+ OUTPUT_VARIABLE _CMD_JAVA_HOME OUTPUT_STRIP_TRAILING_WHITESPACE)
+ endif()
+ if(_CMD_JAVA_HOME AND IS_DIRECTORY "${_CMD_JAVA_HOME}")
+ set(_JAVA_HOME "${_CMD_JAVA_HOME}")
+ set(_JAVA_HOME_EXPLICIT 0)
+ endif()
+ unset(_CMD_JAVA_HOME)
+ endif()
+ unset(_ENV_JAVA_HOME)
+endif()
diff --git a/Modules/CMakeFindKate.cmake b/Modules/CMakeFindKate.cmake
new file mode 100644
index 0000000..9aaf6e5
--- /dev/null
+++ b/Modules/CMakeFindKate.cmake
@@ -0,0 +1,21 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is included in CMakeSystemSpecificInformation.cmake if
+# the Eclipse CDT4 extra generator has been selected.
+
+
+# Try to find out how many CPUs we have and set the -j argument for make accordingly
+
+include(ProcessorCount)
+processorcount(_CMAKE_KATE_PROCESSOR_COUNT)
+
+# Only set -j if we are under UNIX and if the make-tool used actually has "make" in the name
+# (we may also get here in the future e.g. for ninja)
+if("${_CMAKE_KATE_PROCESSOR_COUNT}" GREATER 1 AND CMAKE_HOST_UNIX AND "${CMAKE_MAKE_PROGRAM}" MATCHES make)
+ set(_CMAKE_KATE_INITIAL_MAKE_ARGS "-j${_CMAKE_KATE_PROCESSOR_COUNT}")
+endif()
+
+# This variable is used by the Eclipse generator and appended to the make invocation commands.
+set(CMAKE_KATE_MAKE_ARGUMENTS "${_CMAKE_KATE_INITIAL_MAKE_ARGS}" CACHE STRING "Additional command line arguments when Kate invokes make. Enter e.g. -j<some_number> to get parallel builds")
diff --git a/Modules/CMakeFindPackageMode.cmake b/Modules/CMakeFindPackageMode.cmake
new file mode 100644
index 0000000..815dfc9
--- /dev/null
+++ b/Modules/CMakeFindPackageMode.cmake
@@ -0,0 +1,204 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CMakeFindPackageMode
+--------------------
+
+
+
+This file is executed by cmake when invoked with --find-package. It
+expects that the following variables are set using -D:
+
+``NAME``
+ name of the package
+``COMPILER_ID``
+ the CMake compiler ID for which the result is,
+ i.e. GNU/Intel/Clang/MSVC, etc.
+``LANGUAGE``
+ language for which the result will be used,
+ i.e. C/CXX/Fortran/ASM
+``MODE``
+ ``EXIST``
+ only check for existence of the given package
+ ``COMPILE``
+ print the flags needed for compiling an object file which uses
+ the given package
+ ``LINK``
+ print the flags needed for linking when using the given package
+``QUIET``
+ if TRUE, don't print anything
+#]=======================================================================]
+
+if(NOT NAME)
+ message(FATAL_ERROR "Name of the package to be searched not specified. Set the CMake variable NAME, e.g. -DNAME=JPEG .")
+endif()
+
+if(NOT COMPILER_ID)
+ message(FATAL_ERROR "COMPILER_ID argument not specified. In doubt, use GNU.")
+endif()
+
+if(NOT LANGUAGE)
+ message(FATAL_ERROR "LANGUAGE argument not specified. Use C, CXX or Fortran.")
+endif()
+
+if(NOT MODE)
+ message(FATAL_ERROR "MODE argument not specified. Use either EXIST, COMPILE or LINK.")
+endif()
+
+# require the current version. If we don't do this, Platforms/CYGWIN.cmake complains because
+# it doesn't know whether it should set WIN32 or not:
+cmake_minimum_required(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} )
+
+macro(ENABLE_LANGUAGE)
+ # disable the enable_language() command, otherwise --find-package breaks on Windows.
+ # On Windows, enable_language(RC) is called in the platform files unconditionally.
+ # But in --find-package mode, we don't want (and can't) enable any language.
+endmacro()
+
+set(CMAKE_PLATFORM_INFO_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY})
+
+include(CMakeDetermineSystem)
+
+# short-cut some tests on Darwin, see Darwin-GNU.cmake:
+if("${CMAKE_SYSTEM_NAME}" MATCHES Darwin AND "${COMPILER_ID}" MATCHES GNU)
+ set(CMAKE_${LANGUAGE}_SYSROOT_FLAG "")
+ set(CMAKE_${LANGUAGE}_OSX_DEPLOYMENT_TARGET_FLAG "")
+endif()
+
+include(CMakeSystemSpecificInitialize)
+
+# Also load the system specific file, which sets up e.g. the search paths.
+# This makes the FIND_XXX() calls work much better
+include(CMakeSystemSpecificInformation)
+
+if(UNIX)
+
+ # try to guess whether we have a 64bit system, if it has not been set
+ # from the outside
+ if(NOT CMAKE_SIZEOF_VOID_P)
+ set(CMAKE_SIZEOF_VOID_P 4)
+ if(EXISTS /usr/lib64)
+ set(CMAKE_SIZEOF_VOID_P 8)
+ else()
+ # use the file utility to check whether itself is 64 bit:
+ find_program(FILE_EXECUTABLE file)
+ if(FILE_EXECUTABLE)
+ get_filename_component(FILE_ABSPATH "${FILE_EXECUTABLE}" ABSOLUTE)
+ execute_process(COMMAND "${FILE_ABSPATH}" "${FILE_ABSPATH}" OUTPUT_VARIABLE fileOutput ERROR_QUIET)
+ if("${fileOutput}" MATCHES "64-bit")
+ set(CMAKE_SIZEOF_VOID_P 8)
+ endif()
+ endif()
+ endif()
+ endif()
+
+ # guess Debian multiarch if it has not been set:
+ if(EXISTS /etc/debian_version)
+ if(NOT CMAKE_${LANGUAGE}_LIBRARY_ARCHITECTURE )
+ file(GLOB filesInLib RELATIVE /lib /lib/*-linux-gnu* )
+ foreach(file ${filesInLib})
+ if("${file}" MATCHES "${CMAKE_LIBRARY_ARCHITECTURE_REGEX}")
+ set(CMAKE_${LANGUAGE}_LIBRARY_ARCHITECTURE ${file})
+ break()
+ endif()
+ endforeach()
+ endif()
+ if(NOT CMAKE_LIBRARY_ARCHITECTURE)
+ set(CMAKE_LIBRARY_ARCHITECTURE ${CMAKE_${LANGUAGE}_LIBRARY_ARCHITECTURE})
+ endif()
+ endif()
+
+endif()
+
+set(CMAKE_${LANGUAGE}_COMPILER "dummy")
+set(CMAKE_${LANGUAGE}_COMPILER_ID "${COMPILER_ID}")
+include(CMake${LANGUAGE}Information)
+
+
+function(set_compile_flags_var _packageName)
+ string(TOUPPER "${_packageName}" PACKAGE_NAME)
+ # Check the following variables:
+ # FOO_INCLUDE_DIRS
+ # Foo_INCLUDE_DIRS
+ # FOO_INCLUDES
+ # Foo_INCLUDES
+ # FOO_INCLUDE_DIR
+ # Foo_INCLUDE_DIR
+ set(includes)
+ if(DEFINED ${_packageName}_INCLUDE_DIRS)
+ set(includes ${_packageName}_INCLUDE_DIRS)
+ elseif(DEFINED ${PACKAGE_NAME}_INCLUDE_DIRS)
+ set(includes ${PACKAGE_NAME}_INCLUDE_DIRS)
+ elseif(DEFINED ${_packageName}_INCLUDES)
+ set(includes ${_packageName}_INCLUDES)
+ elseif(DEFINED ${PACKAGE_NAME}_INCLUDES)
+ set(includes ${PACKAGE_NAME}_INCLUDES)
+ elseif(DEFINED ${_packageName}_INCLUDE_DIR)
+ set(includes ${_packageName}_INCLUDE_DIR)
+ elseif(DEFINED ${PACKAGE_NAME}_INCLUDE_DIR)
+ set(includes ${PACKAGE_NAME}_INCLUDE_DIR)
+ endif()
+
+ set(PACKAGE_INCLUDE_DIRS "${${includes}}" PARENT_SCOPE)
+
+ # Check the following variables:
+ # FOO_DEFINITIONS
+ # Foo_DEFINITIONS
+ set(definitions)
+ if(DEFINED ${_packageName}_DEFINITIONS)
+ set(definitions ${_packageName}_DEFINITIONS)
+ elseif(DEFINED ${PACKAGE_NAME}_DEFINITIONS)
+ set(definitions ${PACKAGE_NAME}_DEFINITIONS)
+ endif()
+
+ set(PACKAGE_DEFINITIONS "${${definitions}}" )
+
+endfunction()
+
+
+function(set_link_flags_var _packageName)
+ string(TOUPPER "${_packageName}" PACKAGE_NAME)
+ # Check the following variables:
+ # FOO_LIBRARIES
+ # Foo_LIBRARIES
+ # FOO_LIBS
+ # Foo_LIBS
+ set(libs)
+ if(DEFINED ${_packageName}_LIBRARIES)
+ set(libs ${_packageName}_LIBRARIES)
+ elseif(DEFINED ${PACKAGE_NAME}_LIBRARIES)
+ set(libs ${PACKAGE_NAME}_LIBRARIES)
+ elseif(DEFINED ${_packageName}_LIBS)
+ set(libs ${_packageName}_LIBS)
+ elseif(DEFINED ${PACKAGE_NAME}_LIBS)
+ set(libs ${PACKAGE_NAME}_LIBS)
+ endif()
+
+ set(PACKAGE_LIBRARIES "${${libs}}" PARENT_SCOPE )
+
+endfunction()
+
+
+find_package("${NAME}" QUIET)
+
+set(PACKAGE_FOUND FALSE)
+
+string(TOUPPER "${NAME}" UPPERCASE_NAME)
+
+if(${NAME}_FOUND OR ${UPPERCASE_NAME}_FOUND)
+ set(PACKAGE_FOUND TRUE)
+
+ if("${MODE}" STREQUAL "EXIST")
+ # do nothing
+ elseif("${MODE}" STREQUAL "COMPILE")
+ set_compile_flags_var(${NAME})
+ elseif("${MODE}" STREQUAL "LINK")
+ set_link_flags_var(${NAME})
+ else()
+ message(FATAL_ERROR "Invalid mode argument ${MODE} given.")
+ endif()
+
+endif()
+
+set(PACKAGE_QUIET ${SILENT} )
diff --git a/Modules/CMakeFindSublimeText2.cmake b/Modules/CMakeFindSublimeText2.cmake
new file mode 100644
index 0000000..7f67bf0
--- /dev/null
+++ b/Modules/CMakeFindSublimeText2.cmake
@@ -0,0 +1,23 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is included in CMakeSystemSpecificInformation.cmake if
+# the Sublime Text 2 extra generator has been selected.
+
+find_program(CMAKE_SUBLIMETEXT_EXECUTABLE
+ NAMES subl3 subl sublime_text
+ PATHS
+ "/Applications/Sublime Text.app/Contents/SharedSupport/bin"
+ "/Applications/Sublime Text 3.app/Contents/SharedSupport/bin"
+ "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin"
+ "$ENV{HOME}/Applications/Sublime Text.app/Contents/SharedSupport/bin"
+ "$ENV{HOME}/Applications/Sublime Text 3.app/Contents/SharedSupport/bin"
+ "$ENV{HOME}/Applications/Sublime Text 2.app/Contents/SharedSupport/bin"
+ "/opt/sublime_text"
+ "/opt/sublime_text_3"
+ DOC "The Sublime Text executable")
+
+if(CMAKE_SUBLIMETEXT_EXECUTABLE)
+ set(CMAKE_OPEN_PROJECT_COMMAND "${CMAKE_SUBLIMETEXT_EXECUTABLE} --project <PROJECT_FILE>" )
+endif()
diff --git a/Modules/CMakeFindWMake.cmake b/Modules/CMakeFindWMake.cmake
new file mode 100644
index 0000000..a20d069
--- /dev/null
+++ b/Modules/CMakeFindWMake.cmake
@@ -0,0 +1,7 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+set (CMAKE_MAKE_PROGRAM "wmake" CACHE STRING
+ "Program used to build from makefiles.")
+mark_as_advanced(CMAKE_MAKE_PROGRAM)
diff --git a/Modules/CMakeFindXCode.cmake b/Modules/CMakeFindXCode.cmake
new file mode 100644
index 0000000..281af96
--- /dev/null
+++ b/Modules/CMakeFindXCode.cmake
@@ -0,0 +1,6 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# Empty placeholder for input dependencies in existing
+# build trees produced by older versions of CMake.
diff --git a/Modules/CMakeForceCompiler.cmake b/Modules/CMakeForceCompiler.cmake
new file mode 100644
index 0000000..7048806
--- /dev/null
+++ b/Modules/CMakeForceCompiler.cmake
@@ -0,0 +1,114 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CMakeForceCompiler
+------------------
+
+.. deprecated:: 3.6
+
+ Do not use.
+
+The macros provided by this module were once intended for use by
+cross-compiling toolchain files when CMake was not able to automatically
+detect the compiler identification. Since the introduction of this module,
+CMake's compiler identification capabilities have improved and can now be
+taught to recognize any compiler. Furthermore, the suite of information
+CMake detects from a compiler is now too extensive to be provided by
+toolchain files using these macros.
+
+One common use case for this module was to skip CMake's checks for a
+working compiler when using a cross-compiler that cannot link binaries
+without special flags or custom linker scripts. This case is now supported
+by setting the :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable in the
+toolchain file instead.
+
+-------------------------------------------------------------------------
+
+Macro ``CMAKE_FORCE_C_COMPILER`` has the following signature:
+
+::
+
+ CMAKE_FORCE_C_COMPILER(<compiler> <compiler-id>)
+
+It sets :variable:`CMAKE_C_COMPILER <CMAKE_<LANG>_COMPILER>` to
+the given compiler and the cmake internal variable
+:variable:`CMAKE_C_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` to the given
+compiler-id. It also bypasses the check for working compiler and basic
+compiler information tests.
+
+Macro ``CMAKE_FORCE_CXX_COMPILER`` has the following signature:
+
+::
+
+ CMAKE_FORCE_CXX_COMPILER(<compiler> <compiler-id>)
+
+It sets :variable:`CMAKE_CXX_COMPILER <CMAKE_<LANG>_COMPILER>` to
+the given compiler and the cmake internal variable
+:variable:`CMAKE_CXX_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` to the given
+compiler-id. It also bypasses the check for working compiler and basic
+compiler information tests.
+
+Macro ``CMAKE_FORCE_Fortran_COMPILER`` has the following signature:
+
+::
+
+ CMAKE_FORCE_Fortran_COMPILER(<compiler> <compiler-id>)
+
+It sets :variable:`CMAKE_Fortran_COMPILER <CMAKE_<LANG>_COMPILER>` to
+the given compiler and the cmake internal variable
+:variable:`CMAKE_Fortran_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` to the given
+compiler-id. It also bypasses the check for working compiler and basic
+compiler information tests.
+
+So a simple toolchain file could look like this:
+
+::
+
+ include (CMakeForceCompiler)
+ set(CMAKE_SYSTEM_NAME Generic)
+ CMAKE_FORCE_C_COMPILER (chc12 MetrowerksHicross)
+ CMAKE_FORCE_CXX_COMPILER (chc12 MetrowerksHicross)
+#]=======================================================================]
+
+macro(CMAKE_FORCE_C_COMPILER compiler id)
+ message(DEPRECATION "The CMAKE_FORCE_C_COMPILER macro is deprecated. "
+ "Instead just set CMAKE_C_COMPILER and allow CMake to identify the compiler.")
+ set(CMAKE_C_COMPILER "${compiler}")
+ set(CMAKE_C_COMPILER_ID_RUN TRUE)
+ set(CMAKE_C_COMPILER_ID ${id})
+ set(CMAKE_C_COMPILER_FORCED TRUE)
+
+ # Set old compiler id variables.
+ if(CMAKE_C_COMPILER_ID MATCHES "GNU")
+ set(CMAKE_COMPILER_IS_GNUCC 1)
+ endif()
+endmacro()
+
+macro(CMAKE_FORCE_CXX_COMPILER compiler id)
+ message(DEPRECATION "The CMAKE_FORCE_CXX_COMPILER macro is deprecated. "
+ "Instead just set CMAKE_CXX_COMPILER and allow CMake to identify the compiler.")
+ set(CMAKE_CXX_COMPILER "${compiler}")
+ set(CMAKE_CXX_COMPILER_ID_RUN TRUE)
+ set(CMAKE_CXX_COMPILER_ID ${id})
+ set(CMAKE_CXX_COMPILER_FORCED TRUE)
+
+ # Set old compiler id variables.
+ if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
+ set(CMAKE_COMPILER_IS_GNUCXX 1)
+ endif()
+endmacro()
+
+macro(CMAKE_FORCE_Fortran_COMPILER compiler id)
+ message(DEPRECATION "The CMAKE_FORCE_Fortran_COMPILER macro is deprecated. "
+ "Instead just set CMAKE_Fortran_COMPILER and allow CMake to identify the compiler.")
+ set(CMAKE_Fortran_COMPILER "${compiler}")
+ set(CMAKE_Fortran_COMPILER_ID_RUN TRUE)
+ set(CMAKE_Fortran_COMPILER_ID ${id})
+ set(CMAKE_Fortran_COMPILER_FORCED TRUE)
+
+ # Set old compiler id variables.
+ if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU")
+ set(CMAKE_COMPILER_IS_GNUG77 1)
+ endif()
+endmacro()
diff --git a/Modules/CMakeFortranCompiler.cmake.in b/Modules/CMakeFortranCompiler.cmake.in
new file mode 100644
index 0000000..06ee528
--- /dev/null
+++ b/Modules/CMakeFortranCompiler.cmake.in
@@ -0,0 +1,69 @@
+set(CMAKE_Fortran_COMPILER "@CMAKE_Fortran_COMPILER@")
+set(CMAKE_Fortran_COMPILER_ARG1 "@CMAKE_Fortran_COMPILER_ARG1@")
+set(CMAKE_Fortran_COMPILER_ID "@CMAKE_Fortran_COMPILER_ID@")
+set(CMAKE_Fortran_COMPILER_VERSION "@CMAKE_Fortran_COMPILER_VERSION@")
+set(CMAKE_Fortran_COMPILER_WRAPPER "@CMAKE_Fortran_COMPILER_WRAPPER@")
+set(CMAKE_Fortran_PLATFORM_ID "@CMAKE_Fortran_PLATFORM_ID@")
+set(CMAKE_Fortran_SIMULATE_ID "@CMAKE_Fortran_SIMULATE_ID@")
+set(CMAKE_Fortran_SIMULATE_VERSION "@CMAKE_Fortran_SIMULATE_VERSION@")
+@_SET_CMAKE_Fortran_XL_CPP@
+@_SET_CMAKE_Fortran_COMPILER_ARCHITECTURE_ID@
+@_SET_CMAKE_Fortran_COMPILER_SYSROOT@
+@SET_MSVC_Fortran_ARCHITECTURE_ID@
+set(CMAKE_AR "@CMAKE_AR@")
+set(CMAKE_Fortran_COMPILER_AR "@CMAKE_Fortran_COMPILER_AR@")
+set(CMAKE_RANLIB "@CMAKE_RANLIB@")
+set(CMAKE_Fortran_COMPILER_RANLIB "@CMAKE_Fortran_COMPILER_RANLIB@")
+set(CMAKE_COMPILER_IS_GNUG77 @CMAKE_COMPILER_IS_GNUG77@)
+set(CMAKE_Fortran_COMPILER_LOADED 1)
+set(CMAKE_Fortran_COMPILER_WORKS @CMAKE_Fortran_COMPILER_WORKS@)
+set(CMAKE_Fortran_ABI_COMPILED @CMAKE_Fortran_ABI_COMPILED@)
+set(CMAKE_COMPILER_IS_MINGW @CMAKE_COMPILER_IS_MINGW@)
+set(CMAKE_COMPILER_IS_CYGWIN @CMAKE_COMPILER_IS_CYGWIN@)
+if(CMAKE_COMPILER_IS_CYGWIN)
+ set(CYGWIN 1)
+ set(UNIX 1)
+endif()
+
+set(CMAKE_Fortran_COMPILER_ENV_VAR "FC")
+
+set(CMAKE_Fortran_COMPILER_SUPPORTS_F90 @CMAKE_Fortran_COMPILER_SUPPORTS_F90@)
+
+if(CMAKE_COMPILER_IS_MINGW)
+ set(MINGW 1)
+endif()
+set(CMAKE_Fortran_COMPILER_ID_RUN 1)
+set(CMAKE_Fortran_SOURCE_FILE_EXTENSIONS f;F;fpp;FPP;f77;F77;f90;F90;for;For;FOR;f95;F95)
+set(CMAKE_Fortran_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC)
+set(CMAKE_Fortran_LINKER_PREFERENCE 20)
+if(UNIX)
+ set(CMAKE_Fortran_OUTPUT_EXTENSION .o)
+else()
+ set(CMAKE_Fortran_OUTPUT_EXTENSION .obj)
+endif()
+
+# Save compiler ABI information.
+set(CMAKE_Fortran_SIZEOF_DATA_PTR "@CMAKE_Fortran_SIZEOF_DATA_PTR@")
+set(CMAKE_Fortran_COMPILER_ABI "@CMAKE_Fortran_COMPILER_ABI@")
+set(CMAKE_Fortran_LIBRARY_ARCHITECTURE "@CMAKE_Fortran_LIBRARY_ARCHITECTURE@")
+
+if(CMAKE_Fortran_SIZEOF_DATA_PTR AND NOT CMAKE_SIZEOF_VOID_P)
+ set(CMAKE_SIZEOF_VOID_P "${CMAKE_Fortran_SIZEOF_DATA_PTR}")
+endif()
+
+if(CMAKE_Fortran_COMPILER_ABI)
+ set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_Fortran_COMPILER_ABI}")
+endif()
+
+if(CMAKE_Fortran_LIBRARY_ARCHITECTURE)
+ set(CMAKE_LIBRARY_ARCHITECTURE "@CMAKE_Fortran_LIBRARY_ARCHITECTURE@")
+endif()
+
+@CMAKE_Fortran_COMPILER_CUSTOM_CODE@
+@CMAKE_Fortran_SYSROOT_FLAG_CODE@
+@CMAKE_Fortran_OSX_DEPLOYMENT_TARGET_FLAG_CODE@
+
+set(CMAKE_Fortran_IMPLICIT_INCLUDE_DIRECTORIES "@CMAKE_Fortran_IMPLICIT_INCLUDE_DIRECTORIES@")
+set(CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES "@CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES@")
+set(CMAKE_Fortran_IMPLICIT_LINK_DIRECTORIES "@CMAKE_Fortran_IMPLICIT_LINK_DIRECTORIES@")
+set(CMAKE_Fortran_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_Fortran_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@")
diff --git a/Modules/CMakeFortranCompilerABI.F b/Modules/CMakeFortranCompilerABI.F
new file mode 100644
index 0000000..f4a5489
--- /dev/null
+++ b/Modules/CMakeFortranCompilerABI.F
@@ -0,0 +1,40 @@
+ PROGRAM CMakeFortranCompilerABI
+#if 0
+! Address Size
+#endif
+#if defined(_LP64)
+ PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(_M_IA64)
+ PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(_M_X64)
+ PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(_M_AMD64)
+ PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(__x86_64__)
+ PRINT *, 'INFO:sizeof_dptr[8]'
+
+#elif defined(_ILP32)
+ PRINT *, 'INFO:sizeof_dptr[4]'
+#elif defined(_M_IX86)
+ PRINT *, 'INFO:sizeof_dptr[4]'
+#elif defined(__i386__)
+ PRINT *, 'INFO:sizeof_dptr[4]'
+
+#elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8
+ PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 4
+ PRINT *, 'INFO:sizeof_dptr[4]'
+#elif defined(__SIZEOF_SIZE_T__) && __SIZEOF_SIZE_T__ == 8
+ PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(__SIZEOF_SIZE_T__) && __SIZEOF_SIZE_T__ == 4
+ PRINT *, 'INFO:sizeof_dptr[4]'
+#endif
+
+#if 0
+! Application Binary Interface
+#endif
+#if defined(__ELF__)
+ PRINT *, 'INFO:abi[ELF]'
+#endif
+ PRINT *, 'ABI Detection'
+ END
diff --git a/Modules/CMakeFortranCompilerId.F.in b/Modules/CMakeFortranCompilerId.F.in
new file mode 100644
index 0000000..f61a3f2
--- /dev/null
+++ b/Modules/CMakeFortranCompilerId.F.in
@@ -0,0 +1,243 @@
+ PROGRAM CMakeFortranCompilerId
+#if 0
+! Identify the compiler
+#endif
+#if defined(_MSC_VER)
+ PRINT *, 'INFO:simulate[MSVC]'
+# if _MSC_VER >= 1900
+ PRINT *, 'INFO:simulate_version[019.00]'
+# elif _MSC_VER >= 1800
+ PRINT *, 'INFO:simulate_version[018.00]'
+# elif _MSC_VER >= 1700
+ PRINT *, 'INFO:simulate_version[017.00]'
+# elif _MSC_VER >= 1600
+ PRINT *, 'INFO:simulate_version[016.00]'
+# elif _MSC_VER >= 1500
+ PRINT *, 'INFO:simulate_version[015.00]'
+# elif _MSC_VER >= 1400
+ PRINT *, 'INFO:simulate_version[014.00]'
+# elif _MSC_VER >= 1310
+ PRINT *, 'INFO:simulate_version[013.01]'
+# else
+ PRINT *, 'INFO:simulate_version[013.00]'
+# endif
+#endif
+#if defined(__INTEL_LLVM_COMPILER)
+ PRINT *, 'INFO:compiler[IntelLLVM]'
+! __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and
+! later. Look for 6 digit vs. 8 digit version number to decide encoding.
+! VVVV is no smaller than the current year when a versio is released.
+# if __INTEL_LLVM_COMPILER < 1000000
+# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/100)
+# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/10 % 10)
+# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 10)
+# else
+# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/10000)
+# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/100 % 100)
+# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 100)
+# endif
+#elif defined(__INTEL_COMPILER) || defined(__ICC)
+ PRINT *, 'INFO:compiler[Intel]'
+# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100)
+# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10)
+# if defined(__INTEL_COMPILER_UPDATE)
+# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE)
+# else
+# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10)
+# endif
+# if defined(__INTEL_COMPILER_BUILD_DATE)
+# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE)
+# endif
+#elif defined(__SUNPRO_F95)
+ PRINT *, 'INFO:compiler[SunPro]'
+# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_F95>>8)
+# define COMPILER_VERSION_MINOR HEX(__SUNPRO_F95>>4 & 0xF)
+# define COMPILER_VERSION_PATCH HEX(__SUNPRO_F95 & 0xF)
+#elif defined(__SUNPRO_F90)
+ PRINT *, 'INFO:compiler[SunPro]'
+# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_F90>>8)
+# define COMPILER_VERSION_MINOR HEX(__SUNPRO_F90>>4 & 0xF)
+# define COMPILER_VERSION_PATCH HEX(__SUNPRO_F90 & 0xF)
+#elif defined(_CRAYFTN)
+ PRINT *, 'INFO:compiler[Cray]'
+# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR)
+# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR)
+# if defined(_RELEASE_PATCHLEVEL)
+# define COMPILER_VERSION_PATCH DEC(_RELEASE_PATCHLEVEL)
+# endif
+#elif defined(__G95__)
+ PRINT *, 'INFO:compiler[G95]'
+# define COMPILER_VERSION_MAJOR DEC(__G95__)
+# define COMPILER_VERSION_MINOR DEC(__G95_MINOR__)
+#elif defined(__PATHSCALE__)
+ PRINT *, 'INFO:compiler[PathScale]'
+# define COMPILER_VERSION_MAJOR DEC(__PATHCC__)
+# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__)
+# if defined(__PATHCC_PATCHLEVEL__)
+# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__)
+# endif
+#elif defined(__ABSOFT__)
+ PRINT *, 'INFO:compiler[Absoft]'
+#elif defined(__GNUC__)
+ PRINT *, 'INFO:compiler[GNU]'
+# define COMPILER_VERSION_MAJOR DEC(__GNUC__)
+# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__)
+# if defined(__GNUC_PATCHLEVEL__)
+# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
+# endif
+#elif defined(__IBMC__)
+# if defined(__COMPILER_VER__)
+ PRINT *, 'INFO:compiler[zOS]'
+# elif __IBMC__ >= 800
+ PRINT *, 'INFO:compiler[XL]'
+# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
+# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
+# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10)
+# else
+ PRINT *, 'INFO:compiler[VisualAge]'
+# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
+# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
+# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10)
+# endif
+#elif defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__)
+ PRINT *, 'INFO:compiler[NVHPC]'
+# if defined(__NVCOMPILER_MAJOR__)
+# define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__)
+# else
+# define COMPILER_VERSION_MAJOR DEC(__PGIC__)
+# endif
+# if defined(__NVCOMPILER_MINOR__)
+# define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__)
+# else
+# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__)
+# endif
+# if defined(__NVCOMPILER_PATCHLEVEL__)
+# define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__)
+# elif defined(__PGIC_PATCHLEVEL__)
+# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__)
+# endif
+#elif defined(__PGI)
+ PRINT *, 'INFO:compiler[PGI]'
+# define COMPILER_VERSION_MAJOR DEC(__PGIC__)
+# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__)
+# if defined(__PGIC_PATCHLEVEL__)
+# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__)
+# endif
+#elif defined(__FLANG)
+ PRINT *, 'INFO:compiler[Flang]'
+# define COMPILER_VERSION_MAJOR DEC(__FLANG_MAJOR__)
+# define COMPILER_VERSION_MINOR DEC(__FLANG_MINOR__)
+# if defined(__FLANG_PATCHLEVEL__)
+# define COMPILER_VERSION_PATCH DEC(__FLANG_PATCHLEVEL__)
+# endif
+#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
+ PRINT *, 'INFO:compiler[VisualAge]'
+#elif defined(__hpux) || defined(__hpux__)
+ PRINT *, 'INFO:compiler[HP]'
+#elif defined(NAGFOR)
+ PRINT *, 'INFO:compiler[NAG]'
+#define COMPILER_VERSION_MAJOR DEC(__NAG_COMPILER_RELEASE/10)
+#define COMPILER_VERSION_MINOR DEC(__NAG_COMPILER_RELEASE % 10)
+#define COMPILER_VERSION_PATCH DEC(__NAG_COMPILER_BUILD)
+#elif defined(__FUJITSU)
+ PRINT *, 'INFO:compiler[Fujitsu]'
+# if defined(__FRT_major__)
+# define COMPILER_VERSION_MAJOR DEC(__FRT_major__)
+# define COMPILER_VERSION_MINOR DEC(__FRT_minor__)
+# define COMPILER_VERSION_PATCH DEC(__FRT_patchlevel__)
+# elif defined(__FRT_version__)
+ PRINT *, 'INFO:compiler_version['//__FRT_version__//']'
+# endif
+#else
+ PRINT *, 'INFO:compiler[]'
+#endif
+#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
+ PRINT *, 'INFO:compiler_wrapper[CrayPrgEnv]'
+#endif
+
+#if 0
+! Identify the platform
+#endif
+#if defined(__linux) || defined(__linux__) || defined(linux)
+ PRINT *, 'INFO:platform[Linux]'
+#elif defined(__CYGWIN__)
+ PRINT *, 'INFO:platform[Cygwin]'
+#elif defined(__MINGW32__)
+ PRINT *, 'INFO:platform[MinGW]'
+#elif defined(__APPLE__)
+ PRINT *, 'INFO:platform[Darwin]'
+#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
+ PRINT *, 'INFO:platform[Windows]'
+#elif defined(__FreeBSD__) || defined(__FreeBSD)
+ PRINT *, 'INFO:platform[FreeBSD]'
+#elif defined(__NetBSD__) || defined(__NetBSD)
+ PRINT *, 'INFO:platform[NetBSD]'
+#elif defined(__OpenBSD__) || defined(__OPENBSD)
+ PRINT *, 'INFO:platform[OpenBSD]'
+#elif defined(__sun) || defined(sun)
+ PRINT *, 'INFO:platform[SunOS]'
+#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
+ PRINT *, 'INFO:platform[AIX]'
+#elif defined(__hpux) || defined(__hpux__)
+ PRINT *, 'INFO:platform[HP-UX]'
+#elif defined(__HAIKU__)
+ PRINT *, 'INFO:platform[Haiku]'
+#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
+ PRINT *, 'INFO:platform[BeOS]'
+#elif defined(__QNX__) || defined(__QNXNTO__)
+ PRINT *, 'INFO:platform[QNX]'
+#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
+ PRINT *, 'INFO:platform[Tru64]'
+#elif defined(__riscos) || defined(__riscos__)
+ PRINT *, 'INFO:platform[RISCos]'
+#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
+ PRINT *, 'INFO:platform[SINIX]'
+#elif defined(__UNIX_SV__)
+ PRINT *, 'INFO:platform[UNIX_SV]'
+#elif defined(__bsdos__)
+ PRINT *, 'INFO:platform[BSDOS]'
+#elif defined(_MPRAS) || defined(MPRAS)
+ PRINT *, 'INFO:platform[MP-RAS]'
+#elif defined(__osf) || defined(__osf__)
+ PRINT *, 'INFO:platform[OSF1]'
+#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
+ PRINT *, 'INFO:platform[SCO_SV]'
+#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
+ PRINT *, 'INFO:platform[ULTRIX]'
+#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
+ PRINT *, 'INFO:platform[Xenix]'
+#else
+ PRINT *, 'INFO:platform[]'
+#endif
+#if defined(_WIN32) && (defined(__INTEL_COMPILER) || defined(__ICC))
+# if defined(_M_IA64)
+ PRINT *, 'INFO:arch[IA64]'
+# elif defined(_M_X64) || defined(_M_AMD64)
+ PRINT *, 'INFO:arch[x64]'
+# elif defined(_M_IX86)
+ PRINT *, 'INFO:arch[X86]'
+# endif
+#endif
+
+#if 0
+! Encode compiler version digits
+#endif
+#define DEC_8(n) (((n) / 10000000) % 10)
+#define DEC_7(n) (((n) / 1000000) % 10)
+#define DEC_6(n) (((n) / 100000) % 10)
+#define DEC_5(n) (((n) / 10000) % 10)
+#define DEC_4(n) (((n) / 1000) % 10)
+#define DEC_3(n) (((n) / 100) % 10)
+#define DEC_2(n) (((n) / 10) % 10)
+#define DEC_1(n) (((n) ) % 10)
+#define HEX_8(n) ((n)>>28 & 0xF)
+#define HEX_7(n) ((n)>>24 & 0xF)
+#define HEX_6(n) ((n)>>20 & 0xF)
+#define HEX_5(n) ((n)>>16 & 0xF)
+#define HEX_4(n) ((n)>>12 & 0xF)
+#define HEX_3(n) ((n)>>8 & 0xF)
+#define HEX_2(n) ((n)>>4 & 0xF)
+#define HEX_1(n) ((n) & 0xF)
+@CMAKE_Fortran_COMPILER_ID_VERSION_INFO@
+
+ END
diff --git a/Modules/CMakeFortranInformation.cmake b/Modules/CMakeFortranInformation.cmake
new file mode 100644
index 0000000..9a4ce63
--- /dev/null
+++ b/Modules/CMakeFortranInformation.cmake
@@ -0,0 +1,222 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+include(CMakeLanguageInformation)
+
+# This file sets the basic flags for the Fortran language in CMake.
+# It also loads the available platform file for the system-compiler
+# if it exists.
+
+set(_INCLUDED_FILE 0)
+
+# Load compiler-specific information.
+if(CMAKE_Fortran_COMPILER_ID)
+ include(Compiler/${CMAKE_Fortran_COMPILER_ID}-Fortran OPTIONAL)
+endif()
+
+set(CMAKE_BASE_NAME)
+get_filename_component(CMAKE_BASE_NAME "${CMAKE_Fortran_COMPILER}" NAME_WE)
+# since the gnu compiler has several names force g++
+if(CMAKE_COMPILER_IS_GNUG77)
+ set(CMAKE_BASE_NAME g77)
+endif()
+if(CMAKE_Fortran_COMPILER_ID)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_Fortran_COMPILER_ID}-Fortran OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
+endif()
+if (NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME} OPTIONAL
+ RESULT_VARIABLE _INCLUDED_FILE)
+endif ()
+
+# load any compiler-wrapper specific information
+if (CMAKE_Fortran_COMPILER_WRAPPER)
+ __cmake_include_compiler_wrapper(Fortran)
+endif ()
+
+# We specify the compiler information in the system file for some
+# platforms, but this language may not have been enabled when the file
+# was first included. Include it again to get the language info.
+# Remove this when all compiler info is removed from system files.
+if (NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_SYSTEM_NAME} OPTIONAL)
+endif ()
+
+if(CMAKE_Fortran_SIZEOF_DATA_PTR)
+ foreach(f ${CMAKE_Fortran_ABI_FILES})
+ include(${f})
+ endforeach()
+ unset(CMAKE_Fortran_ABI_FILES)
+endif()
+
+# This should be included before the _INIT variables are
+# used to initialize the cache. Since the rule variables
+# have if blocks on them, users can still define them here.
+# But, it should still be after the platform file so changes can
+# be made to those values.
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE "${_override}")
+endif()
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE_Fortran)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE_Fortran} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE_Fortran "${_override}")
+endif()
+
+if(NOT CMAKE_Fortran_COMPILE_OPTIONS_PIC)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_PIC ${CMAKE_C_COMPILE_OPTIONS_PIC})
+endif()
+
+if(NOT CMAKE_Fortran_COMPILE_OPTIONS_PIE)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_PIE ${CMAKE_C_COMPILE_OPTIONS_PIE})
+endif()
+if(NOT CMAKE_Fortran_LINK_OPTIONS_PIE)
+ set(CMAKE_Fortran_LINK_OPTIONS_PIE ${CMAKE_C_LINK_OPTIONS_PIE})
+endif()
+if(NOT CMAKE_Fortran_LINK_OPTIONS_NO_PIE)
+ set(CMAKE_Fortran_LINK_OPTIONS_NO_PIE ${CMAKE_C_LINK_OPTIONS_NO_PIE})
+endif()
+
+if(NOT CMAKE_Fortran_COMPILE_OPTIONS_DLL)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_DLL ${CMAKE_C_COMPILE_OPTIONS_DLL})
+endif()
+
+# Create a set of shared library variable specific to Fortran
+# For 90% of the systems, these are the same flags as the C versions
+# so if these are not set just copy the flags from the c version
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS)
+ set(CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_Fortran_FLAGS)
+ set(CMAKE_SHARED_LIBRARY_Fortran_FLAGS ${CMAKE_SHARED_LIBRARY_C_FLAGS})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS)
+ set(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS ${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_RPATH_LINK_Fortran_FLAG)
+ set(CMAKE_SHARED_LIBRARY_RPATH_LINK_Fortran_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG})
+endif()
+
+if(NOT DEFINED CMAKE_EXE_EXPORTS_Fortran_FLAG)
+ set(CMAKE_EXE_EXPORTS_Fortran_FLAG ${CMAKE_EXE_EXPORTS_C_FLAG})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG)
+ set(CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_C_FLAG})
+endif()
+
+# for most systems a module is the same as a shared library
+# so unless the variable CMAKE_MODULE_EXISTS is set just
+# copy the values from the LIBRARY variables
+if(NOT CMAKE_MODULE_EXISTS)
+ set(CMAKE_SHARED_MODULE_Fortran_FLAGS ${CMAKE_SHARED_LIBRARY_Fortran_FLAGS})
+ set(CMAKE_SHARED_MODULE_CREATE_Fortran_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS})
+endif()
+
+# repeat for modules
+if(NOT DEFINED CMAKE_SHARED_MODULE_CREATE_Fortran_FLAGS)
+ set(CMAKE_SHARED_MODULE_CREATE_Fortran_FLAGS ${CMAKE_SHARED_MODULE_CREATE_C_FLAGS})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_MODULE_Fortran_FLAGS)
+ set(CMAKE_SHARED_MODULE_Fortran_FLAGS ${CMAKE_SHARED_MODULE_C_FLAGS})
+endif()
+
+if(NOT DEFINED CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG)
+ set(CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG})
+endif()
+
+if(NOT DEFINED CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG_SEP)
+ set(CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP})
+endif()
+
+if(NOT DEFINED CMAKE_EXECUTABLE_RPATH_LINK_Fortran_FLAG)
+ set(CMAKE_EXECUTABLE_RPATH_LINK_Fortran_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_Fortran_FLAG})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_Fortran_WITH_RUNTIME_PATH)
+ set(CMAKE_SHARED_LIBRARY_LINK_Fortran_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH})
+endif()
+
+if(NOT CMAKE_INCLUDE_FLAG_Fortran)
+ set(CMAKE_INCLUDE_FLAG_Fortran ${CMAKE_INCLUDE_FLAG_C})
+endif()
+
+set(CMAKE_VERBOSE_MAKEFILE FALSE CACHE BOOL "If this value is on, makefiles will be generated without the .SILENT directive, and all commands will be echoed to the console during the make. This is useful for debugging only. With Visual Studio IDE projects all commands are done without /nologo.")
+
+set(CMAKE_Fortran_FLAGS_INIT "$ENV{FFLAGS} ${CMAKE_Fortran_FLAGS_INIT}")
+
+cmake_initialize_per_config_variable(CMAKE_Fortran_FLAGS "Flags used by the Fortran compiler")
+
+if(NOT CMAKE_Fortran_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_Fortran_COMPILER_LAUNCHER})
+ set(CMAKE_Fortran_COMPILER_LAUNCHER "$ENV{CMAKE_Fortran_COMPILER_LAUNCHER}"
+ CACHE STRING "Compiler launcher for Fortran.")
+endif()
+
+include(CMakeCommonLanguageInclude)
+
+# now define the following rule variables
+# CMAKE_Fortran_CREATE_SHARED_LIBRARY
+# CMAKE_Fortran_CREATE_SHARED_MODULE
+# CMAKE_Fortran_COMPILE_OBJECT
+# CMAKE_Fortran_LINK_EXECUTABLE
+
+# create a Fortran shared library
+if(NOT CMAKE_Fortran_CREATE_SHARED_LIBRARY)
+ set(CMAKE_Fortran_CREATE_SHARED_LIBRARY
+ "<CMAKE_Fortran_COMPILER> <CMAKE_SHARED_LIBRARY_Fortran_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
+endif()
+
+# create a Fortran shared module just copy the shared library rule
+if(NOT CMAKE_Fortran_CREATE_SHARED_MODULE)
+ set(CMAKE_Fortran_CREATE_SHARED_MODULE ${CMAKE_Fortran_CREATE_SHARED_LIBRARY})
+endif()
+
+# Create a static archive incrementally for large object file counts.
+# If CMAKE_Fortran_CREATE_STATIC_LIBRARY is set it will override these.
+if(NOT DEFINED CMAKE_Fortran_ARCHIVE_CREATE)
+ set(CMAKE_Fortran_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_Fortran_ARCHIVE_APPEND)
+ set(CMAKE_Fortran_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_Fortran_ARCHIVE_FINISH)
+ set(CMAKE_Fortran_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
+endif()
+
+# compile a Fortran file into an object file
+# (put -o after -c to workaround bug in at least one mpif77 wrapper)
+if(NOT CMAKE_Fortran_COMPILE_OBJECT)
+ set(CMAKE_Fortran_COMPILE_OBJECT
+ "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -c <SOURCE> -o <OBJECT>")
+endif()
+
+# link a fortran program
+if(NOT CMAKE_Fortran_LINK_EXECUTABLE)
+ set(CMAKE_Fortran_LINK_EXECUTABLE
+ "<CMAKE_Fortran_COMPILER> <CMAKE_Fortran_LINK_FLAGS> <LINK_FLAGS> <FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+endif()
+
+if(CMAKE_Fortran_STANDARD_LIBRARIES_INIT)
+ set(CMAKE_Fortran_STANDARD_LIBRARIES "${CMAKE_Fortran_STANDARD_LIBRARIES_INIT}"
+ CACHE STRING "Libraries linked by default with all Fortran applications.")
+ mark_as_advanced(CMAKE_Fortran_STANDARD_LIBRARIES)
+endif()
+
+# set this variable so we can avoid loading this more than once.
+set(CMAKE_Fortran_INFORMATION_LOADED 1)
diff --git a/Modules/CMakeGenericSystem.cmake b/Modules/CMakeGenericSystem.cmake
new file mode 100644
index 0000000..649b6f7
--- /dev/null
+++ b/Modules/CMakeGenericSystem.cmake
@@ -0,0 +1,187 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(CMakeInitializeConfigs)
+
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "") # -pic
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared") # -shared
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # +s, flag for exe link to use shared lib
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "") # -rpath
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP "") # : or empty
+set(CMAKE_INCLUDE_FLAG_C "-I") # -I
+set(CMAKE_LIBRARY_PATH_FLAG "-L")
+set(CMAKE_LIBRARY_PATH_TERMINATOR "") # for the Digital Mars D compiler the link paths have to be terminated with a "/"
+set(CMAKE_LINK_LIBRARY_FLAG "-l")
+
+set(CMAKE_LINK_LIBRARY_SUFFIX "")
+set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
+set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
+set(CMAKE_SHARED_LIBRARY_PREFIX "lib") # lib
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".so") # .so
+set(CMAKE_EXECUTABLE_SUFFIX "") # .exe
+set(CMAKE_DL_LIBS "dl")
+
+set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
+
+set(CMAKE_AUTOGEN_ORIGIN_DEPENDS ON)
+set(CMAKE_AUTOMOC_COMPILER_PREDEFINES ON)
+if(NOT DEFINED CMAKE_AUTOMOC_PATH_PREFIX)
+ set(CMAKE_AUTOMOC_PATH_PREFIX OFF)
+endif()
+set(CMAKE_AUTOMOC_MACRO_NAMES "Q_OBJECT" "Q_GADGET" "Q_NAMESPACE" "Q_NAMESPACE_EXPORT")
+
+# basically all general purpose OSs support shared libs
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
+
+set (CMAKE_SKIP_RPATH "NO" CACHE BOOL
+ "If set, runtime paths are not added when using shared libraries.")
+set (CMAKE_SKIP_INSTALL_RPATH "NO" CACHE BOOL
+ "If set, runtime paths are not added when installing shared libraries, but are added when building.")
+
+set(CMAKE_VERBOSE_MAKEFILE FALSE CACHE BOOL "If this value is on, makefiles will be generated without the .SILENT directive, and all commands will be echoed to the console during the make. This is useful for debugging only. With Visual Studio IDE projects all commands are done without /nologo.")
+
+if(CMAKE_GENERATOR MATCHES "Make")
+ set(CMAKE_COLOR_MAKEFILE ON CACHE BOOL
+ "Enable/Disable color output during build."
+ )
+ mark_as_advanced(CMAKE_COLOR_MAKEFILE)
+ if(DEFINED CMAKE_RULE_MESSAGES)
+ set_property(GLOBAL PROPERTY RULE_MESSAGES ${CMAKE_RULE_MESSAGES})
+ endif()
+ if(DEFINED CMAKE_TARGET_MESSAGES)
+ set_property(GLOBAL PROPERTY TARGET_MESSAGES ${CMAKE_TARGET_MESSAGES})
+ endif()
+endif()
+
+if(NOT DEFINED CMAKE_EXPORT_COMPILE_COMMANDS AND CMAKE_GENERATOR MATCHES "Ninja|Unix Makefiles")
+ set(CMAKE_EXPORT_COMPILE_COMMANDS "$ENV{CMAKE_EXPORT_COMPILE_COMMANDS}"
+ CACHE BOOL "Enable/Disable output of compile commands during generation."
+ )
+ mark_as_advanced(CMAKE_EXPORT_COMPILE_COMMANDS)
+endif()
+
+# GetDefaultWindowsPrefixBase
+#
+# Compute the base directory for CMAKE_INSTALL_PREFIX based on:
+# - is this 32-bit or 64-bit Windows
+# - is this 32-bit or 64-bit CMake running
+# - what architecture targets will be built
+#
+function(GetDefaultWindowsPrefixBase var)
+
+ # Try to guess what architecture targets will end up being built as,
+ # even if CMAKE_SIZEOF_VOID_P is not computed yet... We need to know
+ # the architecture of the targets being built to choose the right
+ # default value for CMAKE_INSTALL_PREFIX.
+ #
+ 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)")
+ set(arch_hint "x64")
+ endif()
+
+ if(NOT arch_hint)
+ set(arch_hint "x86")
+ endif()
+
+ # default env in a 64-bit app on Win64:
+ # ProgramFiles=C:\Program Files
+ # ProgramFiles(x86)=C:\Program Files (x86)
+ # ProgramW6432=C:\Program Files
+ #
+ # default env in a 32-bit app on Win64:
+ # ProgramFiles=C:\Program Files (x86)
+ # ProgramFiles(x86)=C:\Program Files (x86)
+ # ProgramW6432=C:\Program Files
+ #
+ # default env in a 32-bit app on Win32:
+ # ProgramFiles=C:\Program Files
+ # ProgramFiles(x86) NOT DEFINED
+ # ProgramW6432 NOT DEFINED
+
+ # By default, use the ProgramFiles env var as the base value of
+ # CMAKE_INSTALL_PREFIX:
+ #
+ set(_PREFIX_ENV_VAR "ProgramFiles")
+
+ if ("$ENV{ProgramW6432}" STREQUAL "")
+ # running on 32-bit Windows
+ # must be a 32-bit CMake, too...
+ #message("guess: this is a 32-bit CMake running on 32-bit Windows")
+ else()
+ # running on 64-bit Windows
+ if ("$ENV{ProgramW6432}" STREQUAL "$ENV{ProgramFiles}")
+ # 64-bit CMake
+ #message("guess: this is a 64-bit CMake running on 64-bit Windows")
+ if(NOT "${arch_hint}" STREQUAL "x64")
+ # building 32-bit targets
+ set(_PREFIX_ENV_VAR "ProgramFiles(x86)")
+ endif()
+ else()
+ # 32-bit CMake
+ #message("guess: this is a 32-bit CMake running on 64-bit Windows")
+ if("${arch_hint}" STREQUAL "x64")
+ # building 64-bit targets
+ set(_PREFIX_ENV_VAR "ProgramW6432")
+ endif()
+ endif()
+ endif()
+
+ #if("${arch_hint}" STREQUAL "x64")
+ # message("guess: you are building a 64-bit app")
+ #else()
+ # message("guess: you are building a 32-bit app")
+ #endif()
+
+ if(NOT "$ENV{${_PREFIX_ENV_VAR}}" STREQUAL "")
+ file(TO_CMAKE_PATH "$ENV{${_PREFIX_ENV_VAR}}" _base)
+ elseif(NOT "$ENV{SystemDrive}" STREQUAL "")
+ set(_base "$ENV{SystemDrive}/Program Files")
+ else()
+ set(_base "C:/Program Files")
+ endif()
+
+ set(${var} "${_base}" PARENT_SCOPE)
+endfunction()
+
+
+# Set a variable to indicate whether the value of CMAKE_INSTALL_PREFIX
+# was initialized by the block below. This is useful for user
+# projects to change the default prefix while still allowing the
+# command line to override it.
+if(NOT DEFINED CMAKE_INSTALL_PREFIX)
+ set(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT 1)
+endif()
+
+# Choose a default install prefix for this platform.
+if(CMAKE_HOST_UNIX)
+ set(CMAKE_INSTALL_PREFIX "/usr/local"
+ CACHE PATH "Install path prefix, prepended onto install directories.")
+else()
+ GetDefaultWindowsPrefixBase(CMAKE_GENERIC_PROGRAM_FILES)
+ set(CMAKE_INSTALL_PREFIX
+ "${CMAKE_GENERIC_PROGRAM_FILES}/${PROJECT_NAME}"
+ CACHE PATH "Install path prefix, prepended onto install directories.")
+ set(CMAKE_GENERIC_PROGRAM_FILES)
+endif()
+
+# Set a variable which will be used as component name in install() commands
+# where no COMPONENT has been given:
+set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "Unspecified")
+
+mark_as_advanced(
+ CMAKE_SKIP_RPATH
+ CMAKE_SKIP_INSTALL_RPATH
+ CMAKE_VERBOSE_MAKEFILE
+)
diff --git a/Modules/CMakeGraphVizOptions.cmake b/Modules/CMakeGraphVizOptions.cmake
new file mode 100644
index 0000000..7086722
--- /dev/null
+++ b/Modules/CMakeGraphVizOptions.cmake
@@ -0,0 +1,150 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CMakeGraphVizOptions
+--------------------
+
+The builtin Graphviz support of CMake.
+
+Generating Graphviz files
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+CMake can generate `Graphviz <https://www.graphviz.org/>`_ files showing the
+dependencies between the targets in a project, as well as external libraries
+which are linked against.
+
+When running CMake with the ``--graphviz=foo.dot`` option, it produces:
+
+* a ``foo.dot`` file, showing all dependencies in the project
+* a ``foo.dot.<target>`` file for each target, showing on which other targets
+ it depends
+* a ``foo.dot.<target>.dependers`` file for each target, showing which other
+ targets depend on it
+
+Those .dot files can be converted to images using the *dot* command from the
+Graphviz package:
+
+.. code-block:: shell
+
+ dot -Tpng -o foo.png foo.dot
+
+.. versionadded:: 3.10
+ The different dependency types ``PUBLIC``, ``INTERFACE`` and ``PRIVATE``
+ are represented as solid, dashed and dotted edges.
+
+Variables specific to the Graphviz support
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The resulting graphs can be huge. The look and content of the generated graphs
+can be controlled using the file ``CMakeGraphVizOptions.cmake``. This file is
+first searched in :variable:`CMAKE_BINARY_DIR`, and then in
+:variable:`CMAKE_SOURCE_DIR`. If found, the variables set in it are used to
+adjust options for the generated Graphviz files.
+
+.. variable:: GRAPHVIZ_GRAPH_NAME
+
+ The graph name.
+
+ * Mandatory: NO
+ * Default: value of :variable:`CMAKE_PROJECT_NAME`
+
+.. variable:: GRAPHVIZ_GRAPH_HEADER
+
+ The header written at the top of the Graphviz files.
+
+ * Mandatory: NO
+ * Default: "node [ fontsize = "12" ];"
+
+.. variable:: GRAPHVIZ_NODE_PREFIX
+
+ The prefix for each node in the Graphviz files.
+
+ * Mandatory: NO
+ * Default: "node"
+
+.. variable:: GRAPHVIZ_EXECUTABLES
+
+ Set to FALSE to exclude executables from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_STATIC_LIBS
+
+ Set to FALSE to exclude static libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_SHARED_LIBS
+
+ Set to FALSE to exclude shared libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_MODULE_LIBS
+
+ Set to FALSE to exclude module libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_INTERFACE_LIBS
+
+ Set to FALSE to exclude interface libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_OBJECT_LIBS
+
+ Set to FALSE to exclude object libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_UNKNOWN_LIBS
+
+ Set to FALSE to exclude unknown libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_EXTERNAL_LIBS
+
+ Set to FALSE to exclude external libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_CUSTOM_TARGETS
+
+ Set to TRUE to include custom targets in the generated graphs.
+
+ * Mandatory: NO
+ * Default: FALSE
+
+.. variable:: GRAPHVIZ_IGNORE_TARGETS
+
+ A list of regular expressions for names of targets to exclude from the
+ generated graphs.
+
+ * Mandatory: NO
+ * Default: empty
+
+.. variable:: GRAPHVIZ_GENERATE_PER_TARGET
+
+ Set to FALSE to not generate per-target graphs ``foo.dot.<target>``.
+
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_GENERATE_DEPENDERS
+
+ Set to FALSE to not generate depender graphs ``foo.dot.<target>.dependers``.
+
+ * Mandatory: NO
+ * Default: TRUE
+#]=======================================================================]
diff --git a/Modules/CMakeIOSInstallCombined.cmake b/Modules/CMakeIOSInstallCombined.cmake
new file mode 100644
index 0000000..b022217
--- /dev/null
+++ b/Modules/CMakeIOSInstallCombined.cmake
@@ -0,0 +1,329 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+cmake_policy(SET CMP0054 NEW)
+
+# Function to print messages of this module
+function(_ios_install_combined_message)
+ message(STATUS "[iOS combined] " ${ARGN})
+endfunction()
+
+# Get build settings for the current target/config/SDK by running
+# `xcodebuild -sdk ... -showBuildSettings` and parsing it's output
+function(_ios_install_combined_get_build_setting sdk variable resultvar)
+ if("${sdk}" STREQUAL "")
+ message(FATAL_ERROR "`sdk` is empty")
+ endif()
+
+ if("${variable}" STREQUAL "")
+ message(FATAL_ERROR "`variable` is empty")
+ endif()
+
+ if("${resultvar}" STREQUAL "")
+ message(FATAL_ERROR "`resultvar` is empty")
+ endif()
+
+ set(
+ cmd
+ xcodebuild -showBuildSettings
+ -sdk "${sdk}"
+ -target "${CURRENT_TARGET}"
+ -config "${CURRENT_CONFIG}"
+ )
+
+ execute_process(
+ COMMAND ${cmd}
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE output
+ )
+
+ if(NOT result EQUAL 0)
+ message(FATAL_ERROR "Command failed (${result}): ${cmd}")
+ endif()
+
+ if(NOT output MATCHES " ${variable} = ([^\n]*)")
+ if("${variable}" STREQUAL "VALID_ARCHS")
+ # VALID_ARCHS may be unset by user for given SDK
+ # (e.g. for build without simulator).
+ set("${resultvar}" "" PARENT_SCOPE)
+ return()
+ else()
+ message(FATAL_ERROR "${variable} not found.")
+ endif()
+ endif()
+
+ set("${resultvar}" "${CMAKE_MATCH_1}" PARENT_SCOPE)
+endfunction()
+
+# Get architectures of given SDK (iphonesimulator/iphoneos)
+function(_ios_install_combined_get_valid_archs sdk resultvar)
+ cmake_policy(PUSH)
+ cmake_policy(SET CMP0007 NEW)
+
+ if("${resultvar}" STREQUAL "")
+ message(FATAL_ERROR "`resultvar` is empty")
+ endif()
+
+ _ios_install_combined_get_build_setting("${sdk}" "VALID_ARCHS" valid_archs)
+
+ separate_arguments(valid_archs)
+ list(REMOVE_ITEM valid_archs "") # remove empty elements
+ list(REMOVE_DUPLICATES valid_archs)
+
+ string(REPLACE ";" " " printable "${valid_archs}")
+ _ios_install_combined_message("Architectures (${sdk}): ${printable}")
+
+ set("${resultvar}" "${valid_archs}" PARENT_SCOPE)
+
+ cmake_policy(POP)
+endfunction()
+
+# Make both arch lists a disjoint set by preferring the current SDK
+# (starting with Xcode 12 arm64 is available as device and simulator arch on iOS)
+function(_ios_install_combined_prune_common_archs corr_sdk corr_archs_var this_archs_var)
+ list(REMOVE_ITEM ${corr_archs_var} ${${this_archs_var}})
+
+ string(REPLACE ";" " " printable "${${corr_archs_var}}")
+ _ios_install_combined_message("Architectures (${corr_sdk}) after pruning: ${printable}")
+
+ set("${corr_archs_var}" "${${corr_archs_var}}" PARENT_SCOPE)
+endfunction()
+
+# Final target can contain more architectures that specified by SDK. This
+# function will run 'lipo -info' and parse output. Result will be returned
+# as a CMake list.
+function(_ios_install_combined_get_real_archs filename resultvar)
+ set(cmd "${_lipo_path}" -info "${filename}")
+ execute_process(
+ COMMAND ${cmd}
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE output
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_STRIP_TRAILING_WHITESPACE
+ )
+ if(NOT result EQUAL 0)
+ message(
+ FATAL_ERROR "Command failed (${result}): ${cmd}\n\nOutput:\n${output}"
+ )
+ endif()
+
+ if(NOT output MATCHES "(Architectures in the fat file: [^\n]+ are|Non-fat file: [^\n]+ is architecture): ([^\n]*)")
+ message(FATAL_ERROR "Could not detect architecture from: ${output}")
+ endif()
+
+ separate_arguments(CMAKE_MATCH_2)
+ set(${resultvar} ${CMAKE_MATCH_2} PARENT_SCOPE)
+endfunction()
+
+# Run build command for the given SDK
+function(_ios_install_combined_build sdk)
+ if("${sdk}" STREQUAL "")
+ message(FATAL_ERROR "`sdk` is empty")
+ endif()
+
+ _ios_install_combined_message("Build `${CURRENT_TARGET}` for `${sdk}`")
+
+ execute_process(
+ COMMAND
+ "${CMAKE_COMMAND}"
+ --build
+ .
+ --target "${CURRENT_TARGET}"
+ --config ${CURRENT_CONFIG}
+ --
+ -sdk "${sdk}"
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ RESULT_VARIABLE result
+ )
+
+ if(NOT result EQUAL 0)
+ message(FATAL_ERROR "Build failed")
+ endif()
+endfunction()
+
+# Remove given architecture from file. This step needed only in rare cases
+# when target was built in "unusual" way. Emit warning message.
+function(_ios_install_combined_remove_arch lib arch)
+ _ios_install_combined_message(
+ "Warning! Unexpected architecture `${arch}` detected and will be removed "
+ "from file `${lib}`")
+ set(cmd "${_lipo_path}" -remove ${arch} -output ${lib} ${lib})
+ execute_process(
+ COMMAND ${cmd}
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE output
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_STRIP_TRAILING_WHITESPACE
+ )
+ if(NOT result EQUAL 0)
+ message(
+ FATAL_ERROR "Command failed (${result}): ${cmd}\n\nOutput:\n${output}"
+ )
+ endif()
+endfunction()
+
+# Check that 'lib' contains only 'archs' architectures (remove others).
+function(_ios_install_combined_keep_archs lib archs)
+ _ios_install_combined_get_real_archs("${lib}" real_archs)
+ set(archs_to_remove ${real_archs})
+ list(REMOVE_ITEM archs_to_remove ${archs})
+ foreach(x ${archs_to_remove})
+ _ios_install_combined_remove_arch("${lib}" "${x}")
+ endforeach()
+endfunction()
+
+function(_ios_install_combined_detect_associated_sdk corr_sdk_var)
+ if("${PLATFORM_NAME}" STREQUAL "")
+ message(FATAL_ERROR "PLATFORM_NAME should not be empty")
+ endif()
+
+ set(all_platforms "$ENV{SUPPORTED_PLATFORMS}")
+ if("${SUPPORTED_PLATFORMS}" STREQUAL "")
+ _ios_install_combined_get_build_setting(
+ ${PLATFORM_NAME} SUPPORTED_PLATFORMS all_platforms)
+ if("${all_platforms}" STREQUAL "")
+ message(FATAL_ERROR
+ "SUPPORTED_PLATFORMS not set as an environment variable nor "
+ "able to be determined from project")
+ endif()
+ endif()
+
+ separate_arguments(all_platforms)
+ if(NOT PLATFORM_NAME IN_LIST all_platforms)
+ message(FATAL_ERROR "`${PLATFORM_NAME}` not found in `${all_platforms}`")
+ endif()
+
+ list(REMOVE_ITEM all_platforms "" "${PLATFORM_NAME}")
+ list(LENGTH all_platforms all_platforms_length)
+ if(NOT all_platforms_length EQUAL 1)
+ message(FATAL_ERROR "Expected one element: ${all_platforms}")
+ endif()
+
+ set(${corr_sdk_var} "${all_platforms}" PARENT_SCOPE)
+endfunction()
+
+# Create combined binary for the given target.
+#
+# Preconditions:
+# * Target already installed at ${destination}
+# for the ${PLATFORM_NAME} platform
+#
+# This function will:
+# * Run build for the lacking platform, i.e. opposite to the ${PLATFORM_NAME}
+# * Fuse both libraries by running lipo
+function(ios_install_combined target destination)
+ if("${target}" STREQUAL "")
+ message(FATAL_ERROR "`target` is empty")
+ endif()
+
+ if("${destination}" STREQUAL "")
+ message(FATAL_ERROR "`destination` is empty")
+ endif()
+
+ if(NOT IS_ABSOLUTE "${destination}")
+ message(FATAL_ERROR "`destination` is not absolute: ${destination}")
+ endif()
+
+ if(IS_DIRECTORY "${destination}" OR IS_SYMLINK "${destination}")
+ message(FATAL_ERROR "`destination` is no regular file: ${destination}")
+ endif()
+
+ if("${CMAKE_BINARY_DIR}" STREQUAL "")
+ message(FATAL_ERROR "`CMAKE_BINARY_DIR` is empty")
+ endif()
+
+ if(NOT IS_DIRECTORY "${CMAKE_BINARY_DIR}")
+ message(FATAL_ERROR "Is not a directory: ${CMAKE_BINARY_DIR}")
+ endif()
+
+ if("${CMAKE_INSTALL_CONFIG_NAME}" STREQUAL "")
+ message(FATAL_ERROR "CMAKE_INSTALL_CONFIG_NAME is empty")
+ endif()
+
+ set(cmd xcrun -f lipo)
+
+ # Do not merge OUTPUT_VARIABLE and ERROR_VARIABLE since latter may contain
+ # some diagnostic information even for the successful run.
+ execute_process(
+ COMMAND ${cmd}
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE error_output
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_STRIP_TRAILING_WHITESPACE
+ )
+ if(NOT result EQUAL 0)
+ message(
+ FATAL_ERROR "Command failed (${result}): ${cmd}\n\nOutput:\n${output}\nOutput(error):\n${error_output}"
+ )
+ endif()
+ set(_lipo_path ${output})
+ list(LENGTH _lipo_path len)
+ if(NOT len EQUAL 1)
+ message(FATAL_ERROR "Unexpected xcrun output: ${_lipo_path}")
+ endif()
+ if(NOT EXISTS "${_lipo_path}")
+ message(FATAL_ERROR "File not found: ${_lipo_path}")
+ endif()
+
+ set(CURRENT_CONFIG "${CMAKE_INSTALL_CONFIG_NAME}")
+ set(CURRENT_TARGET "${target}")
+
+ _ios_install_combined_message("Target: ${CURRENT_TARGET}")
+ _ios_install_combined_message("Config: ${CURRENT_CONFIG}")
+ _ios_install_combined_message("Destination: ${destination}")
+
+ # Get SDKs
+ _ios_install_combined_detect_associated_sdk(corr_sdk)
+
+ # Get architectures of the target
+ _ios_install_combined_get_valid_archs("${PLATFORM_NAME}" this_valid_archs)
+ _ios_install_combined_get_valid_archs("${corr_sdk}" corr_valid_archs)
+ _ios_install_combined_prune_common_archs("${corr_sdk}" corr_valid_archs this_valid_archs)
+
+ # Return if there are no valid architectures for the SDK.
+ # (note that library already installed)
+ if("${corr_valid_archs}" STREQUAL "")
+ _ios_install_combined_message(
+ "No architectures detected for `${corr_sdk}` (skip)"
+ )
+ return()
+ endif()
+
+ # Trigger build of corresponding target
+ _ios_install_combined_build("${corr_sdk}")
+
+ # Get location of the library in build directory
+ _ios_install_combined_get_build_setting(
+ "${corr_sdk}" "CONFIGURATION_BUILD_DIR" corr_build_dir)
+ _ios_install_combined_get_build_setting(
+ "${corr_sdk}" "EXECUTABLE_PATH" corr_executable_path)
+ set(corr "${corr_build_dir}/${corr_executable_path}")
+
+ _ios_install_combined_keep_archs("${corr}" "${corr_valid_archs}")
+ _ios_install_combined_keep_archs("${destination}" "${this_valid_archs}")
+
+ _ios_install_combined_message("Current: ${destination}")
+ _ios_install_combined_message("Corresponding: ${corr}")
+
+ set(cmd "${_lipo_path}" -create ${corr} ${destination} -output ${destination})
+
+ execute_process(
+ COMMAND ${cmd}
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+ RESULT_VARIABLE result
+ )
+
+ if(NOT result EQUAL 0)
+ message(FATAL_ERROR "Command failed: ${cmd}")
+ endif()
+
+ _ios_install_combined_message("Install done: ${destination}")
+endfunction()
+
+cmake_policy(POP)
diff --git a/Modules/CMakeISPCCompiler.cmake.in b/Modules/CMakeISPCCompiler.cmake.in
new file mode 100644
index 0000000..28c31cc
--- /dev/null
+++ b/Modules/CMakeISPCCompiler.cmake.in
@@ -0,0 +1,30 @@
+set(CMAKE_ISPC_COMPILER "@CMAKE_ISPC_COMPILER@")
+set(CMAKE_ISPC_COMPILER_ARG1 "@CMAKE_ISPC_COMPILER_ARG1@")
+set(CMAKE_ISPC_COMPILER_ID "@CMAKE_ISPC_COMPILER_ID@")
+set(CMAKE_ISPC_COMPILER_VERSION "@CMAKE_ISPC_COMPILER_VERSION@")
+set(CMAKE_ISPC_COMPILER_VERSION_INTERNAL "@CMAKE_ISPC_COMPILER_VERSION_INTERNAL@")
+
+set(CMAKE_ISPC_PLATFORM_ID "@CMAKE_ISPC_PLATFORM_ID@")
+set(CMAKE_ISPC_SIMULATE_ID "@CMAKE_ISPC_SIMULATE_ID@")
+set(CMAKE_ISPC_COMPILER_FRONTEND_VARIANT "@CMAKE_ISPC_COMPILER_FRONTEND_VARIANT@")
+set(CMAKE_ISPC_SIMULATE_VERSION "@CMAKE_ISPC_SIMULATE_VERSION@")
+
+set(CMAKE_AR "@CMAKE_AR@")
+set(CMAKE_ISPC_COMPILER_AR "@CMAKE_ISPC_COMPILER_AR@")
+set(CMAKE_RANLIB "@CMAKE_RANLIB@")
+set(CMAKE_ISPC_COMPILER_RANLIB "@CMAKE_ISPC_COMPILER_RANLIB@")
+
+set(CMAKE_ISPC_COMPILER_LOADED 1)
+set(CMAKE_ISPC_COMPILER_WORKS @CMAKE_ISPC_COMPILER_WORKS@)
+set(CMAKE_ISPC_ABI_COMPILED @CMAKE_ISPC_ABI_COMPILED@)
+
+set(CMAKE_ISPC_COMPILER_ENV_VAR "ISPC")
+
+set(CMAKE_ISPC_COMPILER_ID_RUN 1)
+set(CMAKE_ISPC_SOURCE_FILE_EXTENSIONS ispc)
+set(CMAKE_ISPC_IGNORE_EXTENSIONS o;O)
+
+set(CMAKE_ISPC_LINKER_PREFERENCE 0)
+set(CMAKE_ISPC_LINKER_PREFERENCE_PROPAGATES 0)
+
+@CMAKE_ISPC_COMPILER_CUSTOM_CODE@
diff --git a/Modules/CMakeISPCCompilerABI.ispc b/Modules/CMakeISPCCompilerABI.ispc
new file mode 100644
index 0000000..e23abce
--- /dev/null
+++ b/Modules/CMakeISPCCompilerABI.ispc
@@ -0,0 +1,20 @@
+
+export void ispcCompilerABI() {
+
+#if defined(__GNU__) && defined(__ELF__) && defined(__ARM_EABI__)
+ print("INFO:abi[ELF ARMEABI]");
+ static char const info_abi[] =
+#elif defined(__GNU__) && defined(__ELF__) && defined(__ARMEB__)
+ print("INFO:abi[ELF ARM]");
+#elif defined(__GNU__) && defined(__ELF__) && defined(__ARMEL__)
+ print("INFO:abi[ELF ARM]");
+
+#elif defined(__linux__) && defined(__ELF__) && defined(__amd64__) && \
+ defined(__ILP32__)
+print("INFO:abi[ELF X32]");
+
+#elif defined(__ELF__)
+print("INFO:abi[ELF]");
+#endif
+
+}
diff --git a/Modules/CMakeISPCCompilerId.ispc.in b/Modules/CMakeISPCCompilerId.ispc.in
new file mode 100644
index 0000000..03380f3
--- /dev/null
+++ b/Modules/CMakeISPCCompilerId.ispc.in
@@ -0,0 +1,62 @@
+
+export void ispcCompilerId() {
+
+// Identify the compiler
+#if defined(ISPC)
+ print("INFO:compiler[Intel]");
+#endif
+
+// Identify the platform
+#if defined(__linux) || defined(__linux__) || defined(linux)
+ print("INFO:platform[Linux]");
+#elif defined(__CYGWIN__)
+ print("INFO:platform[Cygwin]");
+#elif defined(__MINGW32__)
+ print("INFO:platform[MinGW]");
+#elif defined(__APPLE__)
+ print("INFO:platform[Darwin]");
+#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
+ print("INFO:platform[Windows]");
+#elif defined(__FreeBSD__) || defined(__FreeBSD)
+ print("INFO:platform[FreeBSD]");
+#elif defined(__NetBSD__) || defined(__NetBSD)
+ print("INFO:platform[NetBSD]");
+#elif defined(__OpenBSD__) || defined(__OPENBSD)
+ print("INFO:platform[OpenBSD]");
+#elif defined(__sun) || defined(sun)
+ print("INFO:platform[SunOS]");
+#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
+ print("INFO:platform[AIX]");
+#elif defined(__hpux) || defined(__hpux__)
+ print("INFO:platform[HP-UX]");
+#elif defined(__HAIKU__)
+ print("INFO:platform[Haiku]");
+#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
+ print("INFO:platform[BeOS]");
+#elif defined(__QNX__) || defined(__QNXNTO__)
+ print("INFO:platform[QNX]");
+#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
+ print("INFO:platform[Tru64]");
+#elif defined(__riscos) || defined(__riscos__)
+ print("INFO:platform[RISCos]");
+#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
+ print("INFO:platform[SINIX]");
+#elif defined(__UNIX_SV__)
+ print("INFO:platform[UNIX_SV]");
+#elif defined(__bsdos__)
+ print("INFO:platform[BSDOS]");
+#elif defined(_MPRAS) || defined(MPRAS)
+ print("INFO:platform[MP-RAS]");
+#elif defined(__osf) || defined(__osf__)
+ print("INFO:platform[OSF1]");
+#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
+ print("INFO:platform[SCO_SV]");
+#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
+ print("INFO:platform[ULTRIX]");
+#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
+ print("INFO:platform[Xenix]");
+#else
+ print("INFO:platform[]");
+#endif
+
+}
diff --git a/Modules/CMakeISPCInformation.cmake b/Modules/CMakeISPCInformation.cmake
new file mode 100644
index 0000000..5acb682
--- /dev/null
+++ b/Modules/CMakeISPCInformation.cmake
@@ -0,0 +1,65 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+if(UNIX)
+ set(CMAKE_ISPC_OUTPUT_EXTENSION .o)
+else()
+ set(CMAKE_ISPC_OUTPUT_EXTENSION .obj)
+endif()
+set(CMAKE_INCLUDE_FLAG_ISPC "-I")
+
+# Load compiler-specific information.
+if(CMAKE_ISPC_COMPILER_ID)
+ include(Compiler/${CMAKE_ISPC_COMPILER_ID}-ISPC OPTIONAL)
+endif()
+
+# load the system- and compiler specific files
+if(CMAKE_ISPC_COMPILER_ID)
+ # load a hardware specific file, mostly useful for embedded compilers
+ if(CMAKE_SYSTEM_PROCESSOR)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_ISPC_COMPILER_ID}-ISPC-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL)
+ endif()
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_ISPC_COMPILER_ID}-ISPC OPTIONAL)
+endif()
+
+# add the flags to the cache based
+# on the initial values computed in the platform/*.cmake files
+# use _INIT variables so that this only happens the first time
+# and you can set these flags in the cmake cache
+set(CMAKE_ISPC_FLAGS_INIT "$ENV{ISPCFLAGS} ${CMAKE_ISPC_FLAGS_INIT}")
+
+cmake_initialize_per_config_variable(CMAKE_ISPC_FLAGS "Flags used by the ISPC compiler")
+
+if(CMAKE_ISPC_STANDARD_LIBRARIES_INIT)
+ set(CMAKE_ISPC_STANDARD_LIBRARIES "${CMAKE_ISPC_STANDARD_LIBRARIES_INIT}"
+ CACHE STRING "Libraries linked by default with all ISPC applications.")
+ mark_as_advanced(CMAKE_ISPC_STANDARD_LIBRARIES)
+endif()
+
+if(NOT CMAKE_ISPC_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_ISPC_COMPILER_LAUNCHER})
+ set(CMAKE_ISPC_COMPILER_LAUNCHER "$ENV{CMAKE_ISPC_COMPILER_LAUNCHER}"
+ CACHE STRING "Compiler launcher for ISPC.")
+endif()
+
+include(CMakeCommonLanguageInclude)
+
+# now define the following rules:
+# CMAKE_ISPC_COMPILE_OBJECT
+
+# Create a static archive incrementally for large object file counts.
+if(NOT DEFINED CMAKE_ISPC_ARCHIVE_CREATE)
+ set(CMAKE_ISPC_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_ISPC_ARCHIVE_APPEND)
+ set(CMAKE_ISPC_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_ISPC_ARCHIVE_FINISH)
+ set(CMAKE_ISPC_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
+endif()
+
+if(NOT CMAKE_ISPC_COMPILE_OBJECT)
+ set(CMAKE_ISPC_COMPILE_OBJECT
+ "<CMAKE_ISPC_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> --emit-obj <SOURCE> -h <ISPC_HEADER>")
+endif()
+
+set(CMAKE_ISPC_INFORMATION_LOADED 1)
diff --git a/Modules/CMakeImportBuildSettings.cmake b/Modules/CMakeImportBuildSettings.cmake
new file mode 100644
index 0000000..ec1effb
--- /dev/null
+++ b/Modules/CMakeImportBuildSettings.cmake
@@ -0,0 +1,13 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is purposely no longer documented. It does nothing useful.
+
+# This macro used to load build settings from another project that
+# stored settings using the CMAKE_EXPORT_BUILD_SETTINGS macro.
+macro(CMAKE_IMPORT_BUILD_SETTINGS SETTINGS_FILE)
+ if("${SETTINGS_FILE}" STREQUAL "")
+ message(SEND_ERROR "CMAKE_IMPORT_BUILD_SETTINGS called with no argument.")
+ endif()
+endmacro()
diff --git a/Modules/CMakeInitializeConfigs.cmake b/Modules/CMakeInitializeConfigs.cmake
new file mode 100644
index 0000000..9dfe040
--- /dev/null
+++ b/Modules/CMakeInitializeConfigs.cmake
@@ -0,0 +1,39 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include_guard(GLOBAL)
+
+# Initializes `<_PREFIX>_<CONFIG>` variables from the corresponding
+# `<_PREFIX>_<CONFIG>_INIT`, for the configurations currently used.
+function(cmake_initialize_per_config_variable _PREFIX _DOCSTRING)
+ string(STRIP "${${_PREFIX}_INIT}" _INIT)
+ set("${_PREFIX}" "${_INIT}"
+ CACHE STRING "${_DOCSTRING} during all build types.")
+ mark_as_advanced("${_PREFIX}")
+
+ if (NOT CMAKE_NOT_USING_CONFIG_FLAGS)
+ set(_CONFIGS Debug Release MinSizeRel RelWithDebInfo)
+
+ get_property(_GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if (_GENERATOR_IS_MULTI_CONFIG)
+ list(APPEND _CONFIGS ${CMAKE_CONFIGURATION_TYPES})
+ else()
+ if (NOT CMAKE_NO_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE_INIT}" CACHE STRING
+ "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel ...")
+ endif()
+ list(APPEND _CONFIGS ${CMAKE_BUILD_TYPE})
+ endif()
+
+ list(REMOVE_DUPLICATES _CONFIGS)
+ foreach(_BUILD_TYPE IN LISTS _CONFIGS)
+ if (NOT "${_BUILD_TYPE}" STREQUAL "")
+ string(TOUPPER "${_BUILD_TYPE}" _BUILD_TYPE)
+ string(STRIP "${${_PREFIX}_${_BUILD_TYPE}_INIT}" _INIT)
+ set("${_PREFIX}_${_BUILD_TYPE}" "${_INIT}"
+ CACHE STRING "${_DOCSTRING} during ${_BUILD_TYPE} builds.")
+ mark_as_advanced("${_PREFIX}_${_BUILD_TYPE}")
+ endif()
+ endforeach()
+ endif()
+endfunction()
diff --git a/Modules/CMakeJOMFindMake.cmake b/Modules/CMakeJOMFindMake.cmake
new file mode 100644
index 0000000..f56a588
--- /dev/null
+++ b/Modules/CMakeJOMFindMake.cmake
@@ -0,0 +1,7 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+set (CMAKE_MAKE_PROGRAM "jom" CACHE STRING
+ "Program used to build from makefiles.")
+mark_as_advanced(CMAKE_MAKE_PROGRAM)
diff --git a/Modules/CMakeJavaCompiler.cmake.in b/Modules/CMakeJavaCompiler.cmake.in
new file mode 100644
index 0000000..cd4158c
--- /dev/null
+++ b/Modules/CMakeJavaCompiler.cmake.in
@@ -0,0 +1,13 @@
+set(CMAKE_Java_COMPILER "@CMAKE_Java_COMPILER@")
+set(CMAKE_Java_COMPILER_ARG1 "@CMAKE_Java_COMPILER_ARG1@")
+set(CMAKE_Java_RUNTIME "@CMAKE_Java_RUNTIME@")
+set(CMAKE_Java_ARCHIVE "@CMAKE_Java_ARCHIVE@")
+set(CMAKE_Java_COMPILER_LOADED 1)
+
+set(CMAKE_Java_SOURCE_FILE_EXTENSIONS java)
+set(CMAKE_Java_LINKER_PREFERENCE 40)
+set(CMAKE_Java_OUTPUT_EXTENSION .class)
+set(CMAKE_Java_OUTPUT_EXTENSION_REPLACE 1)
+set(CMAKE_STATIC_LIBRARY_PREFIX_Java "")
+set(CMAKE_STATIC_LIBRARY_SUFFIX_Java ".jar")
+set(CMAKE_Java_COMPILER_ENV_VAR "JAVA_COMPILER")
diff --git a/Modules/CMakeJavaInformation.cmake b/Modules/CMakeJavaInformation.cmake
new file mode 100644
index 0000000..989afc1
--- /dev/null
+++ b/Modules/CMakeJavaInformation.cmake
@@ -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.
+
+
+# This should be included before the _INIT variables are
+# used to initialize the cache. Since the rule variables
+# have if blocks on them, users can still define them here.
+# But, it should still be after the platform file so changes can
+# be made to those values.
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE "${_override}")
+endif()
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE_Java)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE_Java} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE_Java "${_override}")
+endif()
+
+# this is a place holder if java needed flags for javac they would go here.
+if(NOT CMAKE_Java_CREATE_STATIC_LIBRARY)
+# if(WIN32)
+# set(class_files_mask "*.class")
+# else()
+ set(class_files_mask ".")
+# endif()
+
+ set(CMAKE_Java_CREATE_STATIC_LIBRARY
+ "<CMAKE_Java_ARCHIVE> -cf <TARGET> -C <OBJECT_DIR> ${class_files_mask}")
+ # "${class_files_mask}" should really be "<OBJECTS>" but compiling a *.java
+ # file can create more than one *.class file...
+endif()
+
+# compile a Java file into an object file
+if(NOT CMAKE_Java_COMPILE_OBJECT)
+ set(CMAKE_Java_COMPILE_OBJECT
+ "<CMAKE_Java_COMPILER> <FLAGS> <SOURCE> -d <OBJECT_DIR>")
+endif()
+
+# set java include flag option and the separator for multiple include paths
+set(CMAKE_INCLUDE_FLAG_Java "-classpath ")
+if(WIN32 AND NOT CYGWIN)
+ set(CMAKE_INCLUDE_FLAG_SEP_Java ";")
+else()
+ set(CMAKE_INCLUDE_FLAG_SEP_Java ":")
+endif()
diff --git a/Modules/CMakeLanguageInformation.cmake b/Modules/CMakeLanguageInformation.cmake
new file mode 100644
index 0000000..674ab86
--- /dev/null
+++ b/Modules/CMakeLanguageInformation.cmake
@@ -0,0 +1,27 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file contains common code blocks used by all the language information
+# files
+
+# load any compiler-wrapper specific information
+macro(__cmake_include_compiler_wrapper lang)
+ set(_INCLUDED_WRAPPER_FILE 0)
+ if (CMAKE_${lang}_COMPILER_ID)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_${lang}_COMPILER_WRAPPER}-${CMAKE_${lang}_COMPILER_ID}-${lang} OPTIONAL RESULT_VARIABLE _INCLUDED_WRAPPER_FILE)
+ endif()
+ if (NOT _INCLUDED_WRAPPER_FILE)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_${lang}_COMPILER_WRAPPER}-${lang} OPTIONAL RESULT_VARIABLE _INCLUDED_WRAPPER_FILE)
+ endif ()
+
+ # No platform - wrapper - lang information so maybe there's just wrapper - lang information
+ if(NOT _INCLUDED_WRAPPER_FILE)
+ if (CMAKE_${lang}_COMPILER_ID)
+ include(Compiler/${CMAKE_${lang}_COMPILER_WRAPPER}-${CMAKE_${lang}_COMPILER_ID}-${lang} OPTIONAL RESULT_VARIABLE _INCLUDED_WRAPPER_FILE)
+ endif()
+ if (NOT _INCLUDED_WRAPPER_FILE)
+ include(Compiler/${CMAKE_${lang}_COMPILER_WRAPPER}-${lang} OPTIONAL RESULT_VARIABLE _INCLUDED_WRAPPER_FILE)
+ endif ()
+ endif ()
+endmacro ()
diff --git a/Modules/CMakeMSYSFindMake.cmake b/Modules/CMakeMSYSFindMake.cmake
new file mode 100644
index 0000000..33b02c9
--- /dev/null
+++ b/Modules/CMakeMSYSFindMake.cmake
@@ -0,0 +1,10 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+find_program(CMAKE_MAKE_PROGRAM make
+ PATHS
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MSYS-1.0_is1;Inno Setup: App Path]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MinGW;InstallLocation]/bin"
+ c:/msys/1.0/bin /msys/1.0/bin)
+mark_as_advanced(CMAKE_MAKE_PROGRAM)
diff --git a/Modules/CMakeMinGWFindMake.cmake b/Modules/CMakeMinGWFindMake.cmake
new file mode 100644
index 0000000..f026e9a
--- /dev/null
+++ b/Modules/CMakeMinGWFindMake.cmake
@@ -0,0 +1,11 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+find_program(CMAKE_MAKE_PROGRAM mingw32-make.exe PATHS
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MinGW;InstallLocation]/bin"
+ c:/MinGW/bin /MinGW/bin
+ "[HKEY_CURRENT_USER\\Software\\CodeBlocks;Path]/MinGW/bin"
+ )
+
+mark_as_advanced(CMAKE_MAKE_PROGRAM)
diff --git a/Modules/CMakeNMakeFindMake.cmake b/Modules/CMakeNMakeFindMake.cmake
new file mode 100644
index 0000000..0335744
--- /dev/null
+++ b/Modules/CMakeNMakeFindMake.cmake
@@ -0,0 +1,7 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+set (CMAKE_MAKE_PROGRAM "nmake" CACHE STRING
+ "Program used to build from makefiles.")
+mark_as_advanced(CMAKE_MAKE_PROGRAM)
diff --git a/Modules/CMakeNinjaFindMake.cmake b/Modules/CMakeNinjaFindMake.cmake
new file mode 100644
index 0000000..32f78da
--- /dev/null
+++ b/Modules/CMakeNinjaFindMake.cmake
@@ -0,0 +1,9 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+find_program(CMAKE_MAKE_PROGRAM
+ NAMES ninja-build ninja samu
+ NAMES_PER_DIR
+ DOC "Program used to build from build.ninja files.")
+mark_as_advanced(CMAKE_MAKE_PROGRAM)
diff --git a/Modules/CMakeOBJCCompiler.cmake.in b/Modules/CMakeOBJCCompiler.cmake.in
new file mode 100644
index 0000000..608adce
--- /dev/null
+++ b/Modules/CMakeOBJCCompiler.cmake.in
@@ -0,0 +1,70 @@
+set(CMAKE_OBJC_COMPILER "@CMAKE_OBJC_COMPILER@")
+set(CMAKE_OBJC_COMPILER_ARG1 "@CMAKE_OBJC_COMPILER_ARG1@")
+set(CMAKE_OBJC_COMPILER_ID "@CMAKE_OBJC_COMPILER_ID@")
+set(CMAKE_OBJC_COMPILER_VERSION "@CMAKE_OBJC_COMPILER_VERSION@")
+set(CMAKE_OBJC_COMPILER_VERSION_INTERNAL "@CMAKE_OBJC_COMPILER_VERSION_INTERNAL@")
+set(CMAKE_OBJC_COMPILER_WRAPPER "@CMAKE_OBJC_COMPILER_WRAPPER@")
+set(CMAKE_OBJC_STANDARD_COMPUTED_DEFAULT "@CMAKE_OBJC_STANDARD_COMPUTED_DEFAULT@")
+set(CMAKE_OBJC_COMPILE_FEATURES "@CMAKE_OBJC_COMPILE_FEATURES@")
+set(CMAKE_OBJC90_COMPILE_FEATURES "@CMAKE_OBJC90_COMPILE_FEATURES@")
+set(CMAKE_OBJC99_COMPILE_FEATURES "@CMAKE_OBJC99_COMPILE_FEATURES@")
+set(CMAKE_OBJC11_COMPILE_FEATURES "@CMAKE_OBJC11_COMPILE_FEATURES@")
+
+set(CMAKE_OBJC_PLATFORM_ID "@CMAKE_OBJC_PLATFORM_ID@")
+set(CMAKE_OBJC_SIMULATE_ID "@CMAKE_OBJC_SIMULATE_ID@")
+set(CMAKE_OBJC_COMPILER_FRONTEND_VARIANT "@CMAKE_OBJC_COMPILER_FRONTEND_VARIANT@")
+set(CMAKE_OBJC_SIMULATE_VERSION "@CMAKE_OBJC_SIMULATE_VERSION@")
+@_SET_CMAKE_OBJC_COMPILER_ARCHITECTURE_ID@
+@SET_CMAKE_XCODE_ARCHS@
+set(CMAKE_AR "@CMAKE_AR@")
+set(CMAKE_OBJC_COMPILER_AR "@CMAKE_OBJC_COMPILER_AR@")
+set(CMAKE_RANLIB "@CMAKE_RANLIB@")
+set(CMAKE_OBJC_COMPILER_RANLIB "@CMAKE_OBJC_COMPILER_RANLIB@")
+set(CMAKE_LINKER "@CMAKE_LINKER@")
+set(CMAKE_MT "@CMAKE_MT@")
+set(CMAKE_COMPILER_IS_GNUOBJC @CMAKE_COMPILER_IS_GNUOBJC@)
+set(CMAKE_OBJC_COMPILER_LOADED 1)
+set(CMAKE_OBJC_COMPILER_WORKS @CMAKE_OBJC_COMPILER_WORKS@)
+set(CMAKE_OBJC_ABI_COMPILED @CMAKE_OBJC_ABI_COMPILED@)
+
+set(CMAKE_OBJC_COMPILER_ENV_VAR "OBJC")
+
+set(CMAKE_OBJC_COMPILER_ID_RUN 1)
+set(CMAKE_OBJC_SOURCE_FILE_EXTENSIONS m)
+set(CMAKE_OBJC_IGNORE_EXTENSIONS h;H;o;O)
+set(CMAKE_OBJC_LINKER_PREFERENCE 5)
+
+foreach (lang C CXX OBJCXX)
+ foreach(extension IN LISTS CMAKE_OBJC_SOURCE_FILE_EXTENSIONS)
+ if (CMAKE_${lang}_COMPILER_ID_RUN)
+ list(REMOVE_ITEM CMAKE_${lang}_SOURCE_FILE_EXTENSIONS ${extension})
+ endif()
+ endforeach()
+endforeach()
+
+# Save compiler ABI information.
+set(CMAKE_OBJC_SIZEOF_DATA_PTR "@CMAKE_OBJC_SIZEOF_DATA_PTR@")
+set(CMAKE_OBJC_COMPILER_ABI "@CMAKE_OBJC_COMPILER_ABI@")
+set(CMAKE_OBJC_BYTE_ORDER "@CMAKE_OBJC_BYTE_ORDER@")
+set(CMAKE_OBJC_LIBRARY_ARCHITECTURE "@CMAKE_OBJC_LIBRARY_ARCHITECTURE@")
+
+if(CMAKE_OBJC_SIZEOF_DATA_PTR)
+ set(CMAKE_SIZEOF_VOID_P "${CMAKE_OBJC_SIZEOF_DATA_PTR}")
+endif()
+
+if(CMAKE_OBJC_COMPILER_ABI)
+ set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_OBJC_COMPILER_ABI}")
+endif()
+
+if(CMAKE_OBJC_LIBRARY_ARCHITECTURE)
+ set(CMAKE_LIBRARY_ARCHITECTURE "@CMAKE_OBJC_LIBRARY_ARCHITECTURE@")
+endif()
+
+@CMAKE_OBJC_COMPILER_CUSTOM_CODE@
+@CMAKE_OBJC_SYSROOT_FLAG_CODE@
+@CMAKE_OBJC_OSX_DEPLOYMENT_TARGET_FLAG_CODE@
+
+set(CMAKE_OBJC_IMPLICIT_INCLUDE_DIRECTORIES "@CMAKE_OBJC_IMPLICIT_INCLUDE_DIRECTORIES@")
+set(CMAKE_OBJC_IMPLICIT_LINK_LIBRARIES "@CMAKE_OBJC_IMPLICIT_LINK_LIBRARIES@")
+set(CMAKE_OBJC_IMPLICIT_LINK_DIRECTORIES "@CMAKE_OBJC_IMPLICIT_LINK_DIRECTORIES@")
+set(CMAKE_OBJC_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_OBJC_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@")
diff --git a/Modules/CMakeOBJCCompilerABI.m b/Modules/CMakeOBJCCompilerABI.m
new file mode 100644
index 0000000..0726cd3
--- /dev/null
+++ b/Modules/CMakeOBJCCompilerABI.m
@@ -0,0 +1,22 @@
+#ifdef __cplusplus
+# error "A C++ compiler has been selected for Objective-C."
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+#include "CMakeCompilerABI.h"
+
+/*--------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+ int require = 0;
+ require += info_sizeof_dptr[argc];
+ require += info_byte_order_big_endian[argc];
+ require += info_byte_order_little_endian[argc];
+#if defined(ABI_ID)
+ require += info_abi[argc];
+#endif
+ (void)argv;
+ return require;
+}
diff --git a/Modules/CMakeOBJCCompilerId.m.in b/Modules/CMakeOBJCCompilerId.m.in
new file mode 100644
index 0000000..2b8aa30
--- /dev/null
+++ b/Modules/CMakeOBJCCompilerId.m.in
@@ -0,0 +1,63 @@
+#ifdef __cplusplus
+# error "An Objective-C++ compiler has been selected for Objective-C."
+#endif
+
+@CMAKE_OBJC_COMPILER_ID_CONTENT@
+
+/* Construct the string literal in pieces to prevent the source from
+ getting matched. Store it in a pointer rather than an array
+ because some compilers will just produce instructions to fill the
+ array rather than assigning a pointer to a static array. */
+char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
+#ifdef SIMULATE_ID
+char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
+#endif
+
+#ifdef __QNXNTO__
+char const* qnxnto = "INFO" ":" "qnxnto[]";
+#endif
+
+@CMAKE_OBJC_COMPILER_ID_PLATFORM_CONTENT@
+@CMAKE_OBJC_COMPILER_ID_ERROR_FOR_TEST@
+
+#if !defined(__STDC__)
+# if (defined(_MSC_VER) && !defined(__clang__)) \
+ || (defined(__ibmxl__) || defined(__IBMC__))
+# define C_DIALECT "90"
+# else
+# define C_DIALECT
+# endif
+#elif __STDC_VERSION__ >= 201000L
+# define C_DIALECT "11"
+#elif __STDC_VERSION__ >= 199901L
+# define C_DIALECT "99"
+#else
+# define C_DIALECT "90"
+#endif
+const char* info_language_dialect_default =
+ "INFO" ":" "dialect_default[" C_DIALECT "]";
+
+/*--------------------------------------------------------------------------*/
+
+int main(int argc, char* argv[])
+{
+ int require = 0;
+ require += info_compiler[argc];
+ require += info_platform[argc];
+ require += info_arch[argc];
+#ifdef COMPILER_VERSION_MAJOR
+ require += info_version[argc];
+#endif
+#ifdef COMPILER_VERSION_INTERNAL
+ require += info_version_internal[argc];
+#endif
+#ifdef SIMULATE_ID
+ require += info_simulate[argc];
+#endif
+#ifdef SIMULATE_VERSION_MAJOR
+ require += info_simulate_version[argc];
+#endif
+ require += info_language_dialect_default[argc];
+ (void)argv;
+ return require;
+}
diff --git a/Modules/CMakeOBJCInformation.cmake b/Modules/CMakeOBJCInformation.cmake
new file mode 100644
index 0000000..d530191
--- /dev/null
+++ b/Modules/CMakeOBJCInformation.cmake
@@ -0,0 +1,193 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file sets the basic flags for the Objective-C language in CMake.
+# It also loads the available platform file for the system-compiler
+# if it exists.
+# It also loads a system - compiler - processor (or target hardware)
+# specific file, which is mainly useful for crosscompiling and embedded systems.
+
+include(CMakeLanguageInformation)
+
+# some compilers use different extensions (e.g. sdcc uses .rel)
+# so set the extension here first so it can be overridden by the compiler specific file
+set(CMAKE_OBJC_OUTPUT_EXTENSION .o)
+
+if(NOT CMAKE_INCLUDE_FLAG_OBJC)
+ set(CMAKE_INCLUDE_FLAG_OBJC ${CMAKE_INCLUDE_FLAG_C})
+endif()
+
+set(_INCLUDED_FILE 0)
+
+# Load compiler-specific information.
+if(CMAKE_OBJC_COMPILER_ID)
+ include(Compiler/${CMAKE_OBJC_COMPILER_ID}-OBJC OPTIONAL)
+endif()
+
+set(CMAKE_BASE_NAME)
+get_filename_component(CMAKE_BASE_NAME "${CMAKE_OBJC_COMPILER}" NAME_WE)
+if(CMAKE_COMPILER_IS_GNUOBJC)
+ set(CMAKE_BASE_NAME gcc)
+endif()
+
+
+# load a hardware specific file, mostly useful for embedded compilers
+if(CMAKE_SYSTEM_PROCESSOR)
+ if(CMAKE_OBJC_COMPILER_ID)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_OBJC_COMPILER_ID}-OBJC-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
+ endif()
+ if (NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME}-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL)
+ endif ()
+endif()
+
+
+# load the system- and compiler specific files
+if(CMAKE_OBJC_COMPILER_ID)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_OBJC_COMPILER_ID}-OBJC
+ OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
+endif()
+if (NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME}
+ OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
+endif ()
+
+# load any compiler-wrapper specific information
+if (CMAKE_OBJC_COMPILER_WRAPPER)
+ __cmake_include_compiler_wrapper(OBJC)
+endif ()
+
+# We specify the compiler information in the system file for some
+# platforms, but this language may not have been enabled when the file
+# was first included. Include it again to get the language info.
+# Remove this when all compiler info is removed from system files.
+if (NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_SYSTEM_NAME} OPTIONAL)
+endif ()
+
+if(CMAKE_OBJC_SIZEOF_DATA_PTR)
+ foreach(f ${CMAKE_OBJC_ABI_FILES})
+ include(${f})
+ endforeach()
+ unset(CMAKE_OBJC_ABI_FILES)
+endif()
+
+# This should be included before the _INIT variables are
+# used to initialize the cache. Since the rule variables
+# have if blocks on them, users can still define them here.
+# But, it should still be after the platform file so changes can
+# be made to those values.
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE "${_override}")
+endif()
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE_OBJC)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE_OBJC} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE_OBJC "${_override}")
+endif()
+
+
+# for most systems a module is the same as a shared library
+# so unless the variable CMAKE_MODULE_EXISTS is set just
+# copy the values from the LIBRARY variables
+if(NOT CMAKE_MODULE_EXISTS)
+ set(CMAKE_SHARED_MODULE_OBJC_FLAGS ${CMAKE_SHARED_LIBRARY_OBJC_FLAGS})
+ set(CMAKE_SHARED_MODULE_CREATE_OBJC_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_OBJC_FLAGS})
+endif()
+
+set(CMAKE_OBJC_FLAGS_INIT "$ENV{OBJCFLAGS} ${CMAKE_OBJC_FLAGS_INIT}")
+
+cmake_initialize_per_config_variable(CMAKE_OBJC_FLAGS "Flags used by the Objective-C compiler")
+
+if(CMAKE_OBJC_STANDARD_LIBRARIES_INIT)
+ set(CMAKE_OBJC_STANDARD_LIBRARIES "${CMAKE_OBJC_STANDARD_LIBRARIES_INIT}"
+ CACHE STRING "Libraries linked by default with all Objective-C applications.")
+ mark_as_advanced(CMAKE_OBJC_STANDARD_LIBRARIES)
+endif()
+
+if(NOT CMAKE_OBJC_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_OBJC_COMPILER_LAUNCHER})
+ set(CMAKE_OBJC_COMPILER_LAUNCHER "$ENV{CMAKE_OBJC_COMPILER_LAUNCHER}"
+ CACHE STRING "Compiler launcher for OBJC.")
+endif()
+
+include(CMakeCommonLanguageInclude)
+
+# now define the following rule variables
+
+# CMAKE_OBJC_CREATE_SHARED_LIBRARY
+# CMAKE_OBJC_CREATE_SHARED_MODULE
+# CMAKE_OBJC_COMPILE_OBJECT
+# CMAKE_OBJC_LINK_EXECUTABLE
+
+# variables supplied by the generator at use time
+# <TARGET>
+# <TARGET_BASE> the target without the suffix
+# <OBJECTS>
+# <OBJECT>
+# <LINK_LIBRARIES>
+# <FLAGS>
+# <LINK_FLAGS>
+
+# Objective-C compiler information
+# <CMAKE_OBJC_COMPILER>
+# <CMAKE_SHARED_LIBRARY_CREATE_OBJC_FLAGS>
+# <CMAKE_SHARED_MODULE_CREATE_OBJC_FLAGS>
+# <CMAKE_OBJC_LINK_FLAGS>
+
+# Static library tools
+# <CMAKE_AR>
+# <CMAKE_RANLIB>
+
+
+# create an Objective-C shared library
+if(NOT CMAKE_OBJC_CREATE_SHARED_LIBRARY)
+ set(CMAKE_OBJC_CREATE_SHARED_LIBRARY
+ "<CMAKE_OBJC_COMPILER> <CMAKE_SHARED_LIBRARY_OBJC_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_OBJC_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
+endif()
+
+# create an Objective-C shared module just copy the shared library rule
+if(NOT CMAKE_OBJC_CREATE_SHARED_MODULE)
+ set(CMAKE_OBJC_CREATE_SHARED_MODULE ${CMAKE_OBJC_CREATE_SHARED_LIBRARY})
+endif()
+
+# Create an static archive incrementally for large object file counts.
+# If CMAKE_OBJC_CREATE_STATIC_LIBRARY is set it will override these.
+if(NOT DEFINED CMAKE_OBJC_ARCHIVE_CREATE)
+ set(CMAKE_OBJC_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_OBJC_ARCHIVE_APPEND)
+ set(CMAKE_OBJC_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_OBJC_ARCHIVE_FINISH)
+ set(CMAKE_OBJC_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
+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> -x objective-c <FLAGS> -o <OBJECT> -c <SOURCE>")
+endif()
+
+if(NOT CMAKE_OBJC_LINK_EXECUTABLE)
+ set(CMAKE_OBJC_LINK_EXECUTABLE
+ "<CMAKE_OBJC_COMPILER> <FLAGS> <CMAKE_OBJC_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RUNTIME_OBJC_FLAG)
+ set(CMAKE_EXECUTABLE_RUNTIME_OBJC_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJC_FLAG})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RUNTIME_OBJC_FLAG_SEP)
+ set(CMAKE_EXECUTABLE_RUNTIME_OBJC_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJC_FLAG_SEP})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RPATH_LINK_OBJC_FLAG)
+ set(CMAKE_EXECUTABLE_RPATH_LINK_OBJC_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_OBJC_FLAG})
+endif()
+
+set(CMAKE_OBJC_INFORMATION_LOADED 1)
diff --git a/Modules/CMakeOBJCXXCompiler.cmake.in b/Modules/CMakeOBJCXXCompiler.cmake.in
new file mode 100644
index 0000000..a24582b
--- /dev/null
+++ b/Modules/CMakeOBJCXXCompiler.cmake.in
@@ -0,0 +1,81 @@
+set(CMAKE_OBJCXX_COMPILER "@CMAKE_OBJCXX_COMPILER@")
+set(CMAKE_OBJCXX_COMPILER_ARG1 "@CMAKE_OBJCXX_COMPILER_ARG1@")
+set(CMAKE_OBJCXX_COMPILER_ID "@CMAKE_OBJCXX_COMPILER_ID@")
+set(CMAKE_OBJCXX_COMPILER_VERSION "@CMAKE_OBJCXX_COMPILER_VERSION@")
+set(CMAKE_OBJCXX_COMPILER_VERSION_INTERNAL "@CMAKE_OBJCXX_COMPILER_VERSION_INTERNAL@")
+set(CMAKE_OBJCXX_COMPILER_WRAPPER "@CMAKE_OBJCXX_COMPILER_WRAPPER@")
+set(CMAKE_OBJCXX_STANDARD_COMPUTED_DEFAULT "@CMAKE_OBJCXX_STANDARD_COMPUTED_DEFAULT@")
+set(CMAKE_OBJCXX_COMPILE_FEATURES "@CMAKE_OBJCXX_COMPILE_FEATURES@")
+set(CMAKE_OBJCXX98_COMPILE_FEATURES "@CMAKE_OBJCXX98_COMPILE_FEATURES@")
+set(CMAKE_OBJCXX11_COMPILE_FEATURES "@CMAKE_OBJCXX11_COMPILE_FEATURES@")
+set(CMAKE_OBJCXX14_COMPILE_FEATURES "@CMAKE_OBJCXX14_COMPILE_FEATURES@")
+set(CMAKE_OBJCXX17_COMPILE_FEATURES "@CMAKE_OBJCXX17_COMPILE_FEATURES@")
+set(CMAKE_OBJCXX20_COMPILE_FEATURES "@CMAKE_OBJCXX20_COMPILE_FEATURES@")
+set(CMAKE_OBJCXX23_COMPILE_FEATURES "@CMAKE_OBJCXX23_COMPILE_FEATURES@")
+
+set(CMAKE_OBJCXX_PLATFORM_ID "@CMAKE_OBJCXX_PLATFORM_ID@")
+set(CMAKE_OBJCXX_SIMULATE_ID "@CMAKE_OBJCXX_SIMULATE_ID@")
+set(CMAKE_OBJCXX_COMPILER_FRONTEND_VARIANT "@CMAKE_OBJCXX_COMPILER_FRONTEND_VARIANT@")
+set(CMAKE_OBJCXX_SIMULATE_VERSION "@CMAKE_OBJCXX_SIMULATE_VERSION@")
+@_SET_CMAKE_OBJCXX_COMPILER_ARCHITECTURE_ID@
+@SET_CMAKE_XCODE_ARCHS@
+set(CMAKE_AR "@CMAKE_AR@")
+set(CMAKE_OBJCXX_COMPILER_AR "@CMAKE_OBJCXX_COMPILER_AR@")
+set(CMAKE_RANLIB "@CMAKE_RANLIB@")
+set(CMAKE_OBJCXX_COMPILER_RANLIB "@CMAKE_OBJCXX_COMPILER_RANLIB@")
+set(CMAKE_LINKER "@CMAKE_LINKER@")
+set(CMAKE_MT "@CMAKE_MT@")
+set(CMAKE_COMPILER_IS_GNUOBJCXX @CMAKE_COMPILER_IS_GNUOBJCXX@)
+set(CMAKE_OBJCXX_COMPILER_LOADED 1)
+set(CMAKE_OBJCXX_COMPILER_WORKS @CMAKE_OBJCXX_COMPILER_WORKS@)
+set(CMAKE_OBJCXX_ABI_COMPILED @CMAKE_OBJCXX_ABI_COMPILED@)
+
+set(CMAKE_OBJCXX_COMPILER_ENV_VAR "OBJCXX")
+
+set(CMAKE_OBJCXX_COMPILER_ID_RUN 1)
+set(CMAKE_OBJCXX_SOURCE_FILE_EXTENSIONS M;m;mm)
+set(CMAKE_OBJCXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O)
+
+if (CMAKE_OBJC_COMPILER_ID_RUN)
+ foreach(extension IN LISTS CMAKE_OBJC_SOURCE_FILE_EXTENSIONS)
+ list(REMOVE_ITEM CMAKE_OBJCXX_SOURCE_FILE_EXTENSIONS ${extension})
+ endforeach()
+endif()
+
+foreach (lang C CXX OBJC)
+ foreach(extension IN LISTS CMAKE_OBJCXX_SOURCE_FILE_EXTENSIONS)
+ if (CMAKE_${lang}_COMPILER_ID_RUN)
+ list(REMOVE_ITEM CMAKE_${lang}_SOURCE_FILE_EXTENSIONS ${extension})
+ endif()
+ endforeach()
+endforeach()
+
+set(CMAKE_OBJCXX_LINKER_PREFERENCE 25)
+set(CMAKE_OBJCXX_LINKER_PREFERENCE_PROPAGATES 1)
+
+# Save compiler ABI information.
+set(CMAKE_OBJCXX_SIZEOF_DATA_PTR "@CMAKE_OBJCXX_SIZEOF_DATA_PTR@")
+set(CMAKE_OBJCXX_COMPILER_ABI "@CMAKE_OBJCXX_COMPILER_ABI@")
+set(CMAKE_OBJCXX_BYTE_ORDER "@CMAKE_OBJCXX_BYTE_ORDER@")
+set(CMAKE_OBJCXX_LIBRARY_ARCHITECTURE "@CMAKE_OBJCXX_LIBRARY_ARCHITECTURE@")
+
+if(CMAKE_OBJCXX_SIZEOF_DATA_PTR)
+ set(CMAKE_SIZEOF_VOID_P "${CMAKE_OBJCXX_SIZEOF_DATA_PTR}")
+endif()
+
+if(CMAKE_OBJCXX_COMPILER_ABI)
+ set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_OBJCXX_COMPILER_ABI}")
+endif()
+
+if(CMAKE_OBJCXX_LIBRARY_ARCHITECTURE)
+ set(CMAKE_LIBRARY_ARCHITECTURE "@CMAKE_OBJCXX_LIBRARY_ARCHITECTURE@")
+endif()
+
+@CMAKE_OBJCXX_COMPILER_CUSTOM_CODE@
+@CMAKE_OBJCXX_SYSROOT_FLAG_CODE@
+@CMAKE_OBJCXX_OSX_DEPLOYMENT_TARGET_FLAG_CODE@
+
+set(CMAKE_OBJCXX_IMPLICIT_INCLUDE_DIRECTORIES "@CMAKE_OBJCXX_IMPLICIT_INCLUDE_DIRECTORIES@")
+set(CMAKE_OBJCXX_IMPLICIT_LINK_LIBRARIES "@CMAKE_OBJCXX_IMPLICIT_LINK_LIBRARIES@")
+set(CMAKE_OBJCXX_IMPLICIT_LINK_DIRECTORIES "@CMAKE_OBJCXX_IMPLICIT_LINK_DIRECTORIES@")
+set(CMAKE_OBJCXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_OBJCXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@")
diff --git a/Modules/CMakeOBJCXXCompilerABI.mm b/Modules/CMakeOBJCXXCompilerABI.mm
new file mode 100644
index 0000000..7b9fefc
--- /dev/null
+++ b/Modules/CMakeOBJCXXCompilerABI.mm
@@ -0,0 +1,22 @@
+#ifndef __cplusplus
+# error "A C compiler has been selected for Objective-C++."
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+#include "CMakeCompilerABI.h"
+
+/*--------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+ int require = 0;
+ require += info_sizeof_dptr[argc];
+ require += info_byte_order_big_endian[argc];
+ require += info_byte_order_little_endian[argc];
+#if defined(ABI_ID)
+ require += info_abi[argc];
+#endif
+ (void)argv;
+ return require;
+}
diff --git a/Modules/CMakeOBJCXXCompilerId.mm.in b/Modules/CMakeOBJCXXCompilerId.mm.in
new file mode 100644
index 0000000..e2ac35d
--- /dev/null
+++ b/Modules/CMakeOBJCXXCompilerId.mm.in
@@ -0,0 +1,70 @@
+/* This source file must have a .cpp extension so that all C++ compilers
+ recognize the extension without flags. Borland does not know .cxx for
+ example. */
+#ifndef __cplusplus
+# error "An Objective-C compiler has been selected for Objective-C++."
+#endif
+
+@CMAKE_OBJCXX_COMPILER_ID_CONTENT@
+
+/* Construct the string literal in pieces to prevent the source from
+ getting matched. Store it in a pointer rather than an array
+ because some compilers will just produce instructions to fill the
+ array rather than assigning a pointer to a static array. */
+char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
+#ifdef SIMULATE_ID
+char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
+#endif
+
+#ifdef __QNXNTO__
+char const* qnxnto = "INFO" ":" "qnxnto[]";
+#endif
+
+@CMAKE_OBJCXX_COMPILER_ID_PLATFORM_CONTENT@
+@CMAKE_OBJCXX_COMPILER_ID_ERROR_FOR_TEST@
+
+#if defined(_MSC_VER) && defined(_MSVC_LANG)
+#define CXX_STD _MSVC_LANG
+#else
+#define CXX_STD __cplusplus
+#endif
+
+const char* info_language_dialect_default = "INFO" ":" "dialect_default["
+#if CXX_STD > 202002L
+ "23"
+#elfif CXX_STD > 201703L
+ "20"
+#elif CXX_STD >= 201703L
+ "17"
+#elif CXX_STD >= 201402L
+ "14"
+#elif CXX_STD >= 201103L
+ "11"
+#else
+ "98"
+#endif
+"]";
+
+/*--------------------------------------------------------------------------*/
+
+int main(int argc, char* argv[])
+{
+ int require = 0;
+ require += info_compiler[argc];
+ require += info_platform[argc];
+#ifdef COMPILER_VERSION_MAJOR
+ require += info_version[argc];
+#endif
+#ifdef COMPILER_VERSION_INTERNAL
+ require += info_version_internal[argc];
+#endif
+#ifdef SIMULATE_ID
+ require += info_simulate[argc];
+#endif
+#ifdef SIMULATE_VERSION_MAJOR
+ require += info_simulate_version[argc];
+#endif
+ require += info_language_dialect_default[argc];
+ (void)argv;
+ return require;
+}
diff --git a/Modules/CMakeOBJCXXInformation.cmake b/Modules/CMakeOBJCXXInformation.cmake
new file mode 100644
index 0000000..7a3b9d7
--- /dev/null
+++ b/Modules/CMakeOBJCXXInformation.cmake
@@ -0,0 +1,278 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file sets the basic flags for the Objective-C++ language in CMake.
+# It also loads the available platform file for the system-compiler
+# if it exists.
+# It also loads a system - compiler - processor (or target hardware)
+# specific file, which is mainly useful for crosscompiling and embedded systems.
+
+include(CMakeLanguageInformation)
+
+# some compilers use different extensions (e.g. sdcc uses .rel)
+# so set the extension here first so it can be overridden by the compiler specific file
+set(CMAKE_OBJCXX_OUTPUT_EXTENSION .o)
+
+set(_INCLUDED_FILE 0)
+
+# Load compiler-specific information.
+if(CMAKE_OBJCXX_COMPILER_ID)
+ include(Compiler/${CMAKE_OBJCXX_COMPILER_ID}-OBJCXX OPTIONAL)
+endif()
+
+set(CMAKE_BASE_NAME)
+get_filename_component(CMAKE_BASE_NAME "${CMAKE_OBJCXX_COMPILER}" NAME_WE)
+# since the gnu compiler has several names force g++
+if(CMAKE_COMPILER_IS_GNUOBJCXX)
+ set(CMAKE_BASE_NAME g++)
+endif()
+
+
+# load a hardware specific file, mostly useful for embedded compilers
+if(CMAKE_SYSTEM_PROCESSOR)
+ if(CMAKE_OBJCXX_COMPILER_ID)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_OBJCXX_COMPILER_ID}-OBJCXX-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
+ endif()
+ if (NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME}-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL)
+ endif ()
+endif()
+
+# load the system- and compiler specific files
+if(CMAKE_OBJCXX_COMPILER_ID)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_OBJCXX_COMPILER_ID}-OBJCXX OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
+endif()
+if (NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME} OPTIONAL
+ RESULT_VARIABLE _INCLUDED_FILE)
+endif ()
+
+# load any compiler-wrapper specific information
+if (CMAKE_OBJCXX_COMPILER_WRAPPER)
+ __cmake_include_compiler_wrapper(OBJCXX)
+endif ()
+
+# We specify the compiler information in the system file for some
+# platforms, but this language may not have been enabled when the file
+# was first included. Include it again to get the language info.
+# Remove this when all compiler info is removed from system files.
+if (NOT _INCLUDED_FILE)
+ include(Platform/${CMAKE_SYSTEM_NAME} OPTIONAL)
+endif ()
+
+if(CMAKE_OBJCXX_SIZEOF_DATA_PTR)
+ foreach(f ${CMAKE_OBJCXX_ABI_FILES})
+ include(${f})
+ endforeach()
+ unset(CMAKE_OBJCXX_ABI_FILES)
+endif()
+
+# This should be included before the _INIT variables are
+# used to initialize the cache. Since the rule variables
+# have if blocks on them, users can still define them here.
+# But, it should still be after the platform file so changes can
+# be made to those values.
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE "${_override}")
+endif()
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE_OBJCXX)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE_OBJCXX} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE_OBJCXX "${_override}")
+endif()
+
+
+# Create a set of shared library variable specific to Objective-C++
+# For 90% of the systems, these are the same flags as the Objective-C versions
+# so if these are not set just copy the flags from the Objective-C version
+if(NOT CMAKE_SHARED_LIBRARY_CREATE_OBJCXX_FLAGS)
+ set(CMAKE_SHARED_LIBRARY_CREATE_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_OBJC_FLAGS})
+endif()
+
+if(NOT CMAKE_OBJCXX_COMPILE_OPTIONS_PIC)
+ set(CMAKE_OBJCXX_COMPILE_OPTIONS_PIC ${CMAKE_OBJC_COMPILE_OPTIONS_PIC})
+endif()
+
+if(NOT CMAKE_OBJCXX_COMPILE_OPTIONS_PIE)
+ set(CMAKE_OBJCXX_COMPILE_OPTIONS_PIE ${CMAKE_OBJC_COMPILE_OPTIONS_PIE})
+endif()
+if(NOT CMAKE_OBJCXX_LINK_OPTIONS_PIE)
+ set(CMAKE_OBJCXX_LINK_OPTIONS_PIE ${CMAKE_OBJC_LINK_OPTIONS_PIE})
+endif()
+if(NOT CMAKE_OBJCXX_LINK_OPTIONS_NO_PIE)
+ set(CMAKE_OBJCXX_LINK_OPTIONS_NO_PIE ${CMAKE_OBJC_LINK_OPTIONS_NO_PIE})
+endif()
+
+if(NOT CMAKE_OBJCXX_COMPILE_OPTIONS_DLL)
+ set(CMAKE_OBJCXX_COMPILE_OPTIONS_DLL ${CMAKE_OBJC_COMPILE_OPTIONS_DLL})
+endif()
+
+if(NOT CMAKE_SHARED_LIBRARY_OBJCXX_FLAGS)
+ set(CMAKE_SHARED_LIBRARY_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_OBJC_FLAGS})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_OBJCXX_FLAGS)
+ set(CMAKE_SHARED_LIBRARY_LINK_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_LINK_OBJC_FLAGS})
+endif()
+
+if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJC_FLAG})
+endif()
+
+if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG_SEP)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJC_FLAG_SEP})
+endif()
+
+if(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_OBJCXX_FLAG)
+ set(CMAKE_SHARED_LIBRARY_RPATH_LINK_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_OBJC_FLAG})
+endif()
+
+if(NOT DEFINED CMAKE_EXE_EXPORTS_OBJCXX_FLAG)
+ set(CMAKE_EXE_EXPORTS_OBJCXX_FLAG ${CMAKE_EXE_EXPORTS_OBJC_FLAG})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_SONAME_OBJCXX_FLAG)
+ set(CMAKE_SHARED_LIBRARY_SONAME_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_OBJC_FLAG})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RUNTIME_OBJCXX_FLAG)
+ set(CMAKE_EXECUTABLE_RUNTIME_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RUNTIME_OBJCXX_FLAG_SEP)
+ set(CMAKE_EXECUTABLE_RUNTIME_OBJCXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG_SEP})
+endif()
+
+if(NOT CMAKE_EXECUTABLE_RPATH_LINK_OBJCXX_FLAG)
+ set(CMAKE_EXECUTABLE_RPATH_LINK_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_OBJCXX_FLAG})
+endif()
+
+if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_OBJCXX_WITH_RUNTIME_PATH)
+ set(CMAKE_SHARED_LIBRARY_LINK_OBJCXX_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_OBJC_WITH_RUNTIME_PATH})
+endif()
+
+if(NOT CMAKE_INCLUDE_FLAG_OBJCXX)
+ set(CMAKE_INCLUDE_FLAG_OBJCXX ${CMAKE_INCLUDE_FLAG_C})
+endif()
+
+# for most systems a module is the same as a shared library
+# so unless the variable CMAKE_MODULE_EXISTS is set just
+# copy the values from the LIBRARY variables
+if(NOT CMAKE_MODULE_EXISTS)
+ set(CMAKE_SHARED_MODULE_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_OBJCXX_FLAGS})
+ set(CMAKE_SHARED_MODULE_CREATE_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_OBJCXX_FLAGS})
+endif()
+
+# repeat for modules
+if(NOT CMAKE_SHARED_MODULE_CREATE_OBJCXX_FLAGS)
+ set(CMAKE_SHARED_MODULE_CREATE_OBJCXX_FLAGS ${CMAKE_SHARED_MODULE_CREATE_OBJC_FLAGS})
+endif()
+
+if(NOT CMAKE_SHARED_MODULE_OBJCXX_FLAGS)
+ set(CMAKE_SHARED_MODULE_OBJCXX_FLAGS ${CMAKE_SHARED_MODULE_OBJC_FLAGS})
+endif()
+
+# Initialize OBJCXX link type selection flags from OBJC versions.
+foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+ if(NOT CMAKE_${type}_LINK_STATIC_OBJCXX_FLAGS)
+ set(CMAKE_${type}_LINK_STATIC_OBJCXX_FLAGS
+ ${CMAKE_${type}_LINK_STATIC_OBJC_FLAGS})
+ endif()
+ if(NOT CMAKE_${type}_LINK_DYNAMIC_OBJCXX_FLAGS)
+ set(CMAKE_${type}_LINK_DYNAMIC_OBJCXX_FLAGS
+ ${CMAKE_${type}_LINK_DYNAMIC_OBJC_FLAGS})
+ endif()
+endforeach()
+
+# add the flags to the cache based
+# on the initial values computed in the platform/*.cmake files
+# use _INIT variables so that this only happens the first time
+# and you can set these flags in the cmake cache
+set(CMAKE_OBJCXX_FLAGS_INIT "$ENV{OBJCXXFLAGS} ${CMAKE_OBJCXX_FLAGS_INIT}")
+
+cmake_initialize_per_config_variable(CMAKE_OBJCXX_FLAGS "Flags used by the Objective-C++ compiler")
+
+if(CMAKE_OBJCXX_STANDARD_LIBRARIES_INIT)
+ set(CMAKE_OBJCXX_STANDARD_LIBRARIES "${CMAKE_OBJCXX_STANDARD_LIBRARIES_INIT}"
+ CACHE STRING "Libraries linked by default with all Objective-C++ applications.")
+ mark_as_advanced(CMAKE_OBJCXX_STANDARD_LIBRARIES)
+endif()
+
+if(NOT CMAKE_OBJCXX_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_OBJCXX_COMPILER_LAUNCHER})
+ set(CMAKE_OBJCXX_COMPILER_LAUNCHER "$ENV{CMAKE_OBJCXX_COMPILER_LAUNCHER}"
+ CACHE STRING "Compiler launcher for OBJCXX.")
+endif()
+
+include(CMakeCommonLanguageInclude)
+
+# now define the following rules:
+# CMAKE_OBJCXX_CREATE_SHARED_LIBRARY
+# CMAKE_OBJCXX_CREATE_SHARED_MODULE
+# CMAKE_OBJCXX_COMPILE_OBJECT
+# CMAKE_OBJCXX_LINK_EXECUTABLE
+
+# variables supplied by the generator at use time
+# <TARGET>
+# <TARGET_BASE> the target without the suffix
+# <OBJECTS>
+# <OBJECT>
+# <LINK_LIBRARIES>
+# <FLAGS>
+# <LINK_FLAGS>
+
+# Objective-C++ compiler information
+# <CMAKE_OBJCXX_COMPILER>
+# <CMAKE_SHARED_LIBRARY_CREATE_OBJCXX_FLAGS>
+# <CMAKE_OBJCXX_SHARED_MODULE_CREATE_FLAGS>
+# <CMAKE_OBJCXX_LINK_FLAGS>
+
+# Static library tools
+# <CMAKE_AR>
+# <CMAKE_RANLIB>
+
+
+# create a shared Objective-C++ library
+if(NOT CMAKE_OBJCXX_CREATE_SHARED_LIBRARY)
+ set(CMAKE_OBJCXX_CREATE_SHARED_LIBRARY
+ "<CMAKE_OBJCXX_COMPILER> <CMAKE_SHARED_LIBRARY_OBJCXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_OBJCXX_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
+endif()
+
+# create an Objective-C++ shared module copy the shared library rule by default
+if(NOT CMAKE_OBJCXX_CREATE_SHARED_MODULE)
+ set(CMAKE_OBJCXX_CREATE_SHARED_MODULE ${CMAKE_OBJCXX_CREATE_SHARED_LIBRARY})
+endif()
+
+
+# Create a static archive incrementally for large object file counts.
+# If CMAKE_OBJCXX_CREATE_STATIC_LIBRARY is set it will override these.
+if(NOT DEFINED CMAKE_OBJCXX_ARCHIVE_CREATE)
+ set(CMAKE_OBJCXX_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_OBJCXX_ARCHIVE_APPEND)
+ set(CMAKE_OBJCXX_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_OBJCXX_ARCHIVE_FINISH)
+ set(CMAKE_OBJCXX_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
+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> -x objective-c++ <FLAGS> -o <OBJECT> -c <SOURCE>")
+endif()
+
+if(NOT CMAKE_OBJCXX_LINK_EXECUTABLE)
+ set(CMAKE_OBJCXX_LINK_EXECUTABLE
+ "<CMAKE_OBJCXX_COMPILER> <FLAGS> <CMAKE_OBJCXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+endif()
+
+mark_as_advanced(
+CMAKE_VERBOSE_MAKEFILE
+)
+
+set(CMAKE_OBJCXX_INFORMATION_LOADED 1)
diff --git a/Modules/CMakePackageConfigHelpers.cmake b/Modules/CMakePackageConfigHelpers.cmake
new file mode 100644
index 0000000..ad719ef
--- /dev/null
+++ b/Modules/CMakePackageConfigHelpers.cmake
@@ -0,0 +1,344 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CMakePackageConfigHelpers
+-------------------------
+
+Helpers functions for creating config files that can be included by other
+projects to find and use a package.
+
+Adds the :command:`configure_package_config_file()` and
+:command:`write_basic_package_version_file()` commands.
+
+Generating a Package Configuration File
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. command:: configure_package_config_file
+
+ Create a config file for a project::
+
+ configure_package_config_file(<input> <output>
+ INSTALL_DESTINATION <path>
+ [PATH_VARS <var1> <var2> ... <varN>]
+ [NO_SET_AND_CHECK_MACRO]
+ [NO_CHECK_REQUIRED_COMPONENTS_MACRO]
+ [INSTALL_PREFIX <path>]
+ )
+
+``configure_package_config_file()`` should be used instead of the plain
+:command:`configure_file()` command when creating the ``<PackageName>Config.cmake``
+or ``<PackageName>-config.cmake`` file for installing a project or library.
+It helps making the resulting package relocatable by avoiding hardcoded paths
+in the installed ``Config.cmake`` file.
+
+In a ``FooConfig.cmake`` file there may be code like this to make the install
+destinations know to the using project:
+
+.. code-block:: cmake
+
+ set(FOO_INCLUDE_DIR "@CMAKE_INSTALL_FULL_INCLUDEDIR@" )
+ set(FOO_DATA_DIR "@CMAKE_INSTALL_PREFIX@/@RELATIVE_DATA_INSTALL_DIR@" )
+ set(FOO_ICONS_DIR "@CMAKE_INSTALL_PREFIX@/share/icons" )
+ #...logic to determine installedPrefix from the own location...
+ set(FOO_CONFIG_DIR "${installedPrefix}/@CONFIG_INSTALL_DIR@" )
+
+All 4 options shown above are not sufficient, since the first 3 hardcode the
+absolute directory locations, and the 4th case works only if the logic to
+determine the ``installedPrefix`` is correct, and if ``CONFIG_INSTALL_DIR``
+contains a relative path, which in general cannot be guaranteed. This has the
+effect that the resulting ``FooConfig.cmake`` file would work poorly under
+Windows and OSX, where users are used to choose the install location of a
+binary package at install time, independent from how
+:variable:`CMAKE_INSTALL_PREFIX` was set at build/cmake time.
+
+Using ``configure_package_config_file`` helps. If used correctly, it makes
+the resulting ``FooConfig.cmake`` file relocatable. Usage:
+
+1. write a ``FooConfig.cmake.in`` file as you are used to
+2. insert a line containing only the string ``@PACKAGE_INIT@``
+3. instead of ``set(FOO_DIR "@SOME_INSTALL_DIR@")``, use
+ ``set(FOO_DIR "@PACKAGE_SOME_INSTALL_DIR@")`` (this must be after the
+ ``@PACKAGE_INIT@`` line)
+4. instead of using the normal :command:`configure_file()`, use
+ ``configure_package_config_file()``
+
+
+
+The ``<input>`` and ``<output>`` arguments are the input and output file, the
+same way as in :command:`configure_file()`.
+
+The ``<path>`` given to ``INSTALL_DESTINATION`` must be the destination where
+the ``FooConfig.cmake`` file will be installed to. This path can either be
+absolute, or relative to the ``INSTALL_PREFIX`` path.
+
+The variables ``<var1>`` to ``<varN>`` given as ``PATH_VARS`` are the
+variables which contain install destinations. For each of them the macro will
+create a helper variable ``PACKAGE_<var...>``. These helper variables must be
+used in the ``FooConfig.cmake.in`` file for setting the installed location.
+They are calculated by ``configure_package_config_file`` so that they are
+always relative to the installed location of the package. This works both for
+relative and also for absolute locations. For absolute locations it works
+only if the absolute location is a subdirectory of ``INSTALL_PREFIX``.
+
+.. versionadded:: 3.1
+ If the ``INSTALL_PREFIX`` argument is passed, this is used as base path to
+ calculate all the relative paths. The ``<path>`` argument must be an absolute
+ path. If this argument is not passed, the :variable:`CMAKE_INSTALL_PREFIX`
+ variable will be used instead. The default value is good when generating a
+ FooConfig.cmake file to use your package from the install tree. When
+ generating a FooConfig.cmake file to use your package from the build tree this
+ option should be used.
+
+By default ``configure_package_config_file`` also generates two helper macros,
+``set_and_check()`` and ``check_required_components()`` into the
+``FooConfig.cmake`` file.
+
+``set_and_check()`` should be used instead of the normal ``set()`` command for
+setting directories and file locations. Additionally to setting the variable
+it also checks that the referenced file or directory actually exists and fails
+with a ``FATAL_ERROR`` otherwise. This makes sure that the created
+``FooConfig.cmake`` file does not contain wrong references.
+When using the ``NO_SET_AND_CHECK_MACRO``, this macro is not generated
+into the ``FooConfig.cmake`` file.
+
+``check_required_components(<PackageName>)`` should be called at the end of
+the ``FooConfig.cmake`` file. This macro checks whether all requested,
+non-optional components have been found, and if this is not the case, sets
+the ``Foo_FOUND`` variable to ``FALSE``, so that the package is considered to
+be not found. It does that by testing the ``Foo_<Component>_FOUND``
+variables for all requested required components. This macro should be
+called even if the package doesn't provide any components to make sure
+users are not specifying components erroneously. When using the
+``NO_CHECK_REQUIRED_COMPONENTS_MACRO`` option, this macro is not generated
+into the ``FooConfig.cmake`` file.
+
+For an example see below the documentation for
+:command:`write_basic_package_version_file()`.
+
+Generating a Package Version File
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. command:: write_basic_package_version_file
+
+ Create a version file for a project::
+
+ write_basic_package_version_file(<filename>
+ [VERSION <major.minor.patch>]
+ COMPATIBILITY <AnyNewerVersion|SameMajorVersion|SameMinorVersion|ExactVersion>
+ [ARCH_INDEPENDENT] )
+
+
+Writes a file for use as ``<PackageName>ConfigVersion.cmake`` file to
+``<filename>``. See the documentation of :command:`find_package()` for
+details on this.
+
+``<filename>`` is the output filename, it should be in the build tree.
+``<major.minor.patch>`` is the version number of the project to be installed.
+
+If no ``VERSION`` is given, the :variable:`PROJECT_VERSION` variable is used.
+If this hasn't been set, it errors out.
+
+The ``COMPATIBILITY`` mode ``AnyNewerVersion`` means that the installed
+package version will be considered compatible if it is newer or exactly the
+same as the requested version. This mode should be used for packages which
+are fully backward compatible, also across major versions.
+If ``SameMajorVersion`` is used instead, then the behaviour differs from
+``AnyNewerVersion`` in that the major version number must be the same as
+requested, e.g. version 2.0 will not be considered compatible if 1.0 is
+requested. This mode should be used for packages which guarantee backward
+compatibility within the same major version.
+If ``SameMinorVersion`` is used, the behaviour is the same as
+``SameMajorVersion``, but both major and minor version must be the same as
+requested, e.g version 0.2 will not be compatible if 0.1 is requested.
+If ``ExactVersion`` is used, then the package is only considered compatible if
+the requested version matches exactly its own version number (not considering
+the tweak version). For example, version 1.2.3 of a package is only
+considered compatible to requested version 1.2.3. This mode is for packages
+without compatibility guarantees.
+If your project has more elaborated version matching rules, you will need to
+write your own custom ``ConfigVersion.cmake`` file instead of using this
+macro.
+
+.. versionadded:: 3.11
+ The ``SameMinorVersion`` compatibility mode.
+
+.. versionadded:: 3.14
+ If ``ARCH_INDEPENDENT`` is given, the installed package version will be
+ considered compatible even if it was built for a different architecture than
+ the requested architecture. Otherwise, an architecture check will be performed,
+ and the package will be considered compatible only if the architecture matches
+ exactly. For example, if the package is built for a 32-bit architecture, the
+ package is only considered compatible if it is used on a 32-bit architecture,
+ unless ``ARCH_INDEPENDENT`` is given, in which case the package is considered
+ compatible on any architecture.
+
+.. note:: ``ARCH_INDEPENDENT`` is intended for header-only libraries or similar
+ packages with no binaries.
+
+.. versionadded:: 3.19
+ ``COMPATIBILITY_MODE`` ``AnyNewerVersion``, ``SameMajorVersion`` and
+ ``SameMinorVersion`` handle the version range if any is specified
+ (see :command:`find_package` command for the details).
+ ``ExactVersion`` mode is incompatible with version ranges and will display an
+ author warning if one is specified.
+
+Internally, this macro executes :command:`configure_file()` to create the
+resulting version file. Depending on the ``COMPATIBILITY``, the corresponding
+``BasicConfigVersion-<COMPATIBILITY>.cmake.in`` file is used.
+Please note that these files are internal to CMake and you should not call
+:command:`configure_file()` on them yourself, but they can be used as starting
+point to create more sophisticted custom ``ConfigVersion.cmake`` files.
+
+Example Generating Package Files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Example using both :command:`configure_package_config_file` and
+``write_basic_package_version_file()``:
+
+``CMakeLists.txt``:
+
+.. code-block:: cmake
+
+ set(INCLUDE_INSTALL_DIR include/ ... CACHE )
+ set(LIB_INSTALL_DIR lib/ ... CACHE )
+ set(SYSCONFIG_INSTALL_DIR etc/foo/ ... CACHE )
+ #...
+ include(CMakePackageConfigHelpers)
+ configure_package_config_file(FooConfig.cmake.in
+ ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake
+ INSTALL_DESTINATION ${LIB_INSTALL_DIR}/Foo/cmake
+ PATH_VARS INCLUDE_INSTALL_DIR SYSCONFIG_INSTALL_DIR)
+ write_basic_package_version_file(
+ ${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake
+ VERSION 1.2.3
+ COMPATIBILITY SameMajorVersion )
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake
+ DESTINATION ${LIB_INSTALL_DIR}/Foo/cmake )
+
+``FooConfig.cmake.in``:
+
+::
+
+ set(FOO_VERSION x.y.z)
+ ...
+ @PACKAGE_INIT@
+ ...
+ set_and_check(FOO_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
+ set_and_check(FOO_SYSCONFIG_DIR "@PACKAGE_SYSCONFIG_INSTALL_DIR@")
+
+ check_required_components(Foo)
+#]=======================================================================]
+
+include(WriteBasicConfigVersionFile)
+
+macro(WRITE_BASIC_PACKAGE_VERSION_FILE)
+ write_basic_config_version_file(${ARGN})
+endmacro()
+
+function(CONFIGURE_PACKAGE_CONFIG_FILE _inputFile _outputFile)
+ set(options NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO)
+ set(oneValueArgs INSTALL_DESTINATION INSTALL_PREFIX)
+ set(multiValueArgs PATH_VARS )
+
+ cmake_parse_arguments(CCF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(CCF_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to CONFIGURE_PACKAGE_CONFIG_FILE(): \"${CCF_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if(NOT CCF_INSTALL_DESTINATION)
+ message(FATAL_ERROR "No INSTALL_DESTINATION given to CONFIGURE_PACKAGE_CONFIG_FILE()")
+ endif()
+
+ if(DEFINED CCF_INSTALL_PREFIX)
+ if(IS_ABSOLUTE "${CCF_INSTALL_PREFIX}")
+ set(installPrefix "${CCF_INSTALL_PREFIX}")
+ else()
+ message(FATAL_ERROR "INSTALL_PREFIX must be an absolute path")
+ endif()
+ elseif(IS_ABSOLUTE "${CMAKE_INSTALL_PREFIX}")
+ set(installPrefix "${CMAKE_INSTALL_PREFIX}")
+ else()
+ get_filename_component(installPrefix "${CMAKE_INSTALL_PREFIX}" ABSOLUTE)
+ endif()
+
+ if(IS_ABSOLUTE "${CCF_INSTALL_DESTINATION}")
+ set(absInstallDir "${CCF_INSTALL_DESTINATION}")
+ else()
+ set(absInstallDir "${installPrefix}/${CCF_INSTALL_DESTINATION}")
+ endif()
+
+ file(RELATIVE_PATH PACKAGE_RELATIVE_PATH "${absInstallDir}" "${installPrefix}" )
+
+ foreach(var ${CCF_PATH_VARS})
+ if(NOT DEFINED ${var})
+ message(FATAL_ERROR "Variable ${var} does not exist")
+ else()
+ if(IS_ABSOLUTE "${${var}}")
+ string(REPLACE "${installPrefix}" "\${PACKAGE_PREFIX_DIR}"
+ PACKAGE_${var} "${${var}}")
+ else()
+ set(PACKAGE_${var} "\${PACKAGE_PREFIX_DIR}/${${var}}")
+ endif()
+ endif()
+ endforeach()
+
+ get_filename_component(inputFileName "${_inputFile}" NAME)
+
+ set(PACKAGE_INIT "
+####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() #######
+####### Any changes to this file will be overwritten by the next CMake run ####
+####### The input file was ${inputFileName} ########
+
+get_filename_component(PACKAGE_PREFIX_DIR \"\${CMAKE_CURRENT_LIST_DIR}/${PACKAGE_RELATIVE_PATH}\" ABSOLUTE)
+")
+
+ if("${absInstallDir}" MATCHES "^(/usr)?/lib(64)?/.+")
+ # Handle "/usr move" symlinks created by some Linux distros.
+ string(APPEND PACKAGE_INIT "
+# Use original install prefix when loaded through a \"/usr move\"
+# cross-prefix symbolic link such as /lib -> /usr/lib.
+get_filename_component(_realCurr \"\${CMAKE_CURRENT_LIST_DIR}\" REALPATH)
+get_filename_component(_realOrig \"${absInstallDir}\" REALPATH)
+if(_realCurr STREQUAL _realOrig)
+ set(PACKAGE_PREFIX_DIR \"${installPrefix}\")
+endif()
+unset(_realOrig)
+unset(_realCurr)
+")
+ endif()
+
+ if(NOT CCF_NO_SET_AND_CHECK_MACRO)
+ string(APPEND PACKAGE_INIT "
+macro(set_and_check _var _file)
+ set(\${_var} \"\${_file}\")
+ if(NOT EXISTS \"\${_file}\")
+ message(FATAL_ERROR \"File or directory \${_file} referenced by variable \${_var} does not exist !\")
+ endif()
+endmacro()
+")
+ endif()
+
+
+ if(NOT CCF_NO_CHECK_REQUIRED_COMPONENTS_MACRO)
+ string(APPEND PACKAGE_INIT "
+macro(check_required_components _NAME)
+ foreach(comp \${\${_NAME}_FIND_COMPONENTS})
+ if(NOT \${_NAME}_\${comp}_FOUND)
+ if(\${_NAME}_FIND_REQUIRED_\${comp})
+ set(\${_NAME}_FOUND FALSE)
+ endif()
+ endif()
+ endforeach()
+endmacro()
+")
+ endif()
+
+ string(APPEND PACKAGE_INIT "
+####################################################################################")
+
+ configure_file("${_inputFile}" "${_outputFile}" @ONLY)
+
+endfunction()
diff --git a/Modules/CMakeParseArguments.cmake b/Modules/CMakeParseArguments.cmake
new file mode 100644
index 0000000..c753b7f
--- /dev/null
+++ b/Modules/CMakeParseArguments.cmake
@@ -0,0 +1,12 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CMakeParseArguments
+-------------------
+
+This module once implemented the :command:`cmake_parse_arguments` command
+that is now implemented natively by CMake. It is now an empty placeholder
+for compatibility with projects that include it to get the command from
+CMake 3.4 and lower.
+#]=======================================================================]
diff --git a/Modules/CMakeParseImplicitIncludeInfo.cmake b/Modules/CMakeParseImplicitIncludeInfo.cmake
new file mode 100644
index 0000000..a8e6ac0
--- /dev/null
+++ b/Modules/CMakeParseImplicitIncludeInfo.cmake
@@ -0,0 +1,262 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This is used internally by CMake and should not be included by user code.
+
+# helper function that parses implicit include dirs from a single line
+# for compilers that report them that way. on success we return the
+# list of dirs in id_var and set state_var to the 'done' state.
+function(cmake_parse_implicit_include_line line lang id_var log_var state_var)
+ # clear variables we append to (avoids possible pollution from parent scopes)
+ unset(rv)
+ set(log "")
+
+ # Cray compiler (from cray wrapper, via PrgEnv-cray)
+ if("${CMAKE_${lang}_COMPILER_ID}" STREQUAL "Cray" AND
+ "${line}" MATCHES "^/" AND "${line}" MATCHES "/ccfe |/ftnfe " AND
+ "${line}" MATCHES " -isystem| -I")
+ string(REGEX MATCHALL " (-I ?|-isystem )(\"[^\"]+\"|[^ \"]+)" incs "${line}")
+ foreach(inc IN LISTS incs)
+ string(REGEX REPLACE " (-I ?|-isystem )(\"[^\"]+\"|[^ \"]+)" "\\2" idir "${inc}")
+ list(APPEND rv "${idir}")
+ endforeach()
+ if(rv)
+ string(APPEND log " got implicit includes via cray ccfe parser!\n")
+ else()
+ string(APPEND log " warning: cray ccfe parse failed!\n")
+ endif()
+ endif()
+
+ # PGI compiler
+ if("${CMAKE_${lang}_COMPILER_ID}" STREQUAL "PGI")
+ # pgc++ verbose output differs
+ if(("${lang}" STREQUAL "C" OR "${lang}" STREQUAL "Fortran") AND
+ "${line}" MATCHES "^/" AND
+ "${line}" MATCHES "/pgc |/pgf901 |/pgftnc " AND
+ "${line}" MATCHES " -cmdline ")
+ # cmdline has unparsed cmdline, remove it
+ string(REGEX REPLACE "-cmdline .*" "" line "${line}")
+ if("${line}" MATCHES " -nostdinc ")
+ set(rv "") # defined, but empty
+ else()
+ string(REGEX MATCHALL " -stdinc ([^ ]*)" incs "${line}")
+ foreach(inc IN LISTS incs)
+ string(REGEX REPLACE " -stdinc ([^ ]*)" "\\1" idir "${inc}")
+ string(REPLACE ":" ";" idir "${idir}")
+ list(APPEND rv ${idir})
+ endforeach()
+ endif()
+ if(DEFINED rv)
+ string(APPEND log " got implicit includes via PGI C/F parser!\n")
+ else()
+ string(APPEND log " warning: PGI C/F parse failed!\n")
+ endif()
+ elseif("${lang}" STREQUAL "CXX" AND "${line}" MATCHES "^/" AND
+ "${line}" MATCHES "/pggpp1 " AND "${line}" MATCHES " -I")
+ # oddly, -Mnostdinc does not get rid of system -I's, at least in
+ # PGI 18.10.1 ...
+ string(REGEX MATCHALL " (-I ?)([^ ]*)" incs "${line}")
+ foreach(inc IN LISTS incs)
+ string(REGEX REPLACE " (-I ?)([^ ]*)" "\\2" idir "${inc}")
+ if(NOT "${idir}" STREQUAL "-") # filter out "-I-"
+ list(APPEND rv "${idir}")
+ endif()
+ endforeach()
+ if(DEFINED rv)
+ string(APPEND log " got implicit includes via PGI CXX parser!\n")
+ else()
+ string(APPEND log " warning: PGI CXX parse failed!\n")
+ endif()
+ endif()
+ endif()
+
+ # SunPro compiler
+ if("${CMAKE_${lang}_COMPILER_ID}" STREQUAL "SunPro" AND
+ ("${line}" MATCHES "-D__SUNPRO_C" OR "${line}" MATCHES "-D__SUNPRO_F") )
+ string(REGEX MATCHALL " (-I ?)([^ ]*)" incs "${line}")
+ foreach(inc IN LISTS incs)
+ string(REGEX REPLACE " (-I ?)([^ ]*)" "\\2" idir "${inc}")
+ if(NOT "${idir}" STREQUAL "-xbuiltin")
+ list(APPEND rv "${idir}")
+ endif()
+ endforeach()
+ if(rv)
+ if ("${lang}" STREQUAL "C" OR "${lang}" STREQUAL "CXX")
+ # /usr/include appears to be hardwired in
+ list(APPEND rv "/usr/include")
+ endif()
+ string(APPEND log " got implicit includes via sunpro parser!\n")
+ else()
+ string(APPEND log " warning: sunpro parse failed!\n")
+ endif()
+ endif()
+
+ # XL compiler
+ if(("${CMAKE_${lang}_COMPILER_ID}" STREQUAL "XL"
+ OR "${CMAKE_${lang}_COMPILER_ID}" STREQUAL "XLClang")
+ AND "${line}" MATCHES "^/"
+ AND ( ("${lang}" STREQUAL "Fortran" AND
+ "${line}" MATCHES "/xl[fF]entry " AND
+ "${line}" MATCHES "OSVAR\\([^ ]+\\)")
+ OR
+ ( ("${lang}" STREQUAL "C" OR "${lang}" STREQUAL "CXX") AND
+ "${line}" MATCHES "/xl[cC]2?entry " AND
+ "${line}" MATCHES " -qosvar=")
+ ) )
+ # -qnostdinc cancels other stdinc flags, even if present
+ string(FIND "${line}" " -qnostdinc" nostd)
+ if(NOT ${nostd} EQUAL -1)
+ set(rv "") # defined but empty
+ string(APPEND log " got implicit includes via XL parser (nostdinc)\n")
+ else()
+ if("${lang}" STREQUAL "CXX")
+ string(REGEX MATCHALL " -qcpp_stdinc=([^ ]*)" std "${line}")
+ string(REGEX MATCHALL " -qgcc_cpp_stdinc=([^ ]*)" gcc_std "${line}")
+ else()
+ string(REGEX MATCHALL " -qc_stdinc=([^ ]*)" std "${line}")
+ string(REGEX MATCHALL " -qgcc_c_stdinc=([^ ]*)" gcc_std "${line}")
+ endif()
+ set(xlstd ${std} ${gcc_std})
+ foreach(inc IN LISTS xlstd)
+ string(REGEX REPLACE " -q(cpp|gcc_cpp|c|gcc_c)_stdinc=([^ ]*)" "\\2"
+ ipath "${inc}")
+ string(REPLACE ":" ";" ipath "${ipath}")
+ list(APPEND rv ${ipath})
+ endforeach()
+ endif()
+ # user can add -I flags via CMAKE_{C,CXX}_FLAGS, look for that too
+ string(REGEX MATCHALL " (-I ?)([^ ]*)" incs "${line}")
+ unset(urv)
+ foreach(inc IN LISTS incs)
+ string(REGEX REPLACE " (-I ?)([^ ]*)" "\\2" idir "${inc}")
+ list(APPEND urv "${idir}")
+ endforeach()
+ if(urv)
+ if ("${rv}" STREQUAL "")
+ set(rv ${urv})
+ else()
+ list(APPEND rv ${urv})
+ endif()
+ endif()
+
+ if(DEFINED rv)
+ string(APPEND log " got implicit includes via XL parser!\n")
+ else()
+ string(APPEND log " warning: XL parse failed!\n")
+ endif()
+ endif()
+
+ # Fujitsu compiler
+ if(CMAKE_${lang}_COMPILER_ID STREQUAL "Fujitsu" AND
+ line MATCHES "/ccpcom")
+ string(REGEX MATCHALL " (-I *|--sys_include=|--preinclude +)(\"[^\"]+\"|[^ \"]+)" incs "${line}")
+ foreach(inc IN LISTS incs)
+ string(REGEX REPLACE " (-I *|--sys_include=|--preinclude +)(\"[^\"]+\"|[^ \"]+)" "\\2" idir "${inc}")
+ list(APPEND rv "${idir}")
+ endforeach()
+ if(rv)
+ string(APPEND log " got implicit includes via fujitsu ccpcom parser!\n")
+ else()
+ string(APPEND log " warning: fujitsu ccpcom parse failed!\n")
+ endif()
+ endif()
+
+ if(log)
+ set(${log_var} "${log}" PARENT_SCOPE)
+ else()
+ unset(${log_var} PARENT_SCOPE)
+ endif()
+ if(DEFINED rv)
+ set(${id_var} "${rv}" PARENT_SCOPE)
+ set(${state_var} "done" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# top-level function to parse implicit include directory information
+# from verbose compiler output. sets state_var in parent to 'done' on success.
+function(cmake_parse_implicit_include_info text lang dir_var log_var state_var)
+ set(state start) # values: start, loading, done
+
+ # clear variables we append to (avoids possible pollution from parent scopes)
+ set(implicit_dirs_tmp)
+ set(log "")
+
+ # go through each line of output...
+ string(REGEX REPLACE "\r*\n" ";" output_lines "${text}")
+ foreach(line IN LISTS output_lines)
+ if(state STREQUAL start)
+ string(FIND "${line}" "#include \"...\" search starts here:" rv)
+ if(rv GREATER -1)
+ set(state loading)
+ set(preload 1) # looking for include <...> now
+ string(APPEND log " found start of include info\n")
+ else()
+ cmake_parse_implicit_include_line("${line}" "${lang}" implicit_dirs_tmp
+ linelog state)
+ if(linelog)
+ string(APPEND log ${linelog})
+ endif()
+ if(state STREQUAL done)
+ break()
+ endif()
+ endif()
+ elseif(state STREQUAL loading)
+ string(FIND "${line}" "End of search list." rv)
+ if(rv GREATER -1)
+ set(state done)
+ string(APPEND log " end of search list found\n")
+ break()
+ endif()
+ if(preload)
+ string(FIND "${line}" "#include <...> search starts here:" rv)
+ if(rv GREATER -1)
+ set(preload 0)
+ string(APPEND log " found start of implicit include info\n")
+ endif()
+ continue()
+ endif()
+ if("${line}" MATCHES "^ ")
+ string(SUBSTRING "${line}" 1 -1 line) # remove leading space
+ endif()
+ if ("${line}" MATCHES " \\(framework directory\\)$")
+ continue() # frameworks are handled elsewhere, ignore them here
+ endif()
+ string(REPLACE "\\" "/" path "${line}")
+ list(APPEND implicit_dirs_tmp "${path}")
+ string(APPEND log " add: [${path}]\n")
+ endif()
+ endforeach()
+
+ set(implicit_dirs "")
+ foreach(d IN LISTS implicit_dirs_tmp)
+ if(IS_ABSOLUTE "${d}")
+ get_filename_component(dir "${d}" ABSOLUTE)
+ list(APPEND implicit_dirs "${dir}")
+ string(APPEND log " collapse include dir [${d}] ==> [${dir}]\n")
+ elseif("${d}" MATCHES [[^\.\.[\/]\.\.[\/](.*)$]])
+ # This relative path is deep enough to get out of the CMakeFiles/CMakeTmp
+ # directory where the ABI check is done. Assume that the compiler has
+ # computed this path adaptively based on the current working directory
+ # such that the effective result is absolute.
+ get_filename_component(dir "${CMAKE_BINARY_DIR}/${CMAKE_MATCH_1}" ABSOLUTE)
+ list(APPEND implicit_dirs "${dir}")
+ string(APPEND log " collapse relative include dir [${d}] ==> [${dir}]\n")
+ else()
+ string(APPEND log " skipping relative include dir [${d}]\n")
+ endif()
+ endforeach()
+ list(REMOVE_DUPLICATES implicit_dirs)
+
+ # Log results.
+ if(state STREQUAL done)
+ string(APPEND log " implicit include dirs: [${implicit_dirs}]\n")
+ else()
+ string(APPEND log " warn: unable to parse implicit include dirs!\n")
+ endif()
+
+ # Return results.
+ set(${dir_var} "${implicit_dirs}" PARENT_SCOPE)
+ set(${log_var} "${log}" PARENT_SCOPE)
+ set(${state_var} "${state}" PARENT_SCOPE)
+
+endfunction()
diff --git a/Modules/CMakeParseImplicitLinkInfo.cmake b/Modules/CMakeParseImplicitLinkInfo.cmake
new file mode 100644
index 0000000..e848b55
--- /dev/null
+++ b/Modules/CMakeParseImplicitLinkInfo.cmake
@@ -0,0 +1,239 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0053 NEW)
+cmake_policy(SET CMP0054 NEW)
+
+# Function to parse implicit linker options.
+#
+# This is used internally by CMake and should not be included by user
+# code.
+#
+# Note: this function is leaked/exposed by FindOpenMP and therefore needs
+# to have a stable API so projects that copied `FindOpenMP` for backwards
+# compatibility don't break.
+#
+function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj_regex)
+ set(implicit_libs_tmp "")
+ set(implicit_objs_tmp "")
+ set(implicit_dirs_tmp)
+ set(implicit_fwks_tmp)
+ set(log "")
+
+ set(keywordArgs)
+ set(oneValueArgs COMPUTE_IMPLICIT_OBJECTS)
+ set(multiValueArgs )
+ cmake_parse_arguments(EXTRA_PARSE "${keywordArgs}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ # Parse implicit linker arguments.
+ set(linker "CMAKE_LINKER-NOTFOUND")
+ if(CMAKE_LINKER)
+ get_filename_component(linker ${CMAKE_LINKER} NAME)
+ string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" linker "${linker}")
+ endif()
+ set(startfile "CMAKE_LINK_STARTFILE-NOTFOUND")
+ if(CMAKE_LINK_STARTFILE)
+ set(startfile "${CMAKE_LINK_STARTFILE}")
+ endif()
+ # Construct a regex to match linker lines. It must match both the
+ # whole line and just the command (argv[0]).
+ set(linker_regex "^( *|.*[/\\])(${linker}|${startfile}|([^/\\]+-)?ld|collect2)[^/\\]*( |$)")
+ set(linker_exclude_regex "collect2 version |^[A-Za-z0-9_]+=|/ldfe ")
+ string(APPEND log " link line regex: [${linker_regex}]\n")
+ string(REGEX REPLACE "\r?\n" ";" output_lines "${text}")
+ foreach(line IN LISTS output_lines)
+ set(cmd)
+ if("${line}" MATCHES "${linker_regex}" AND
+ NOT "${line}" MATCHES "${linker_exclude_regex}")
+ if(XCODE)
+ # Xcode unconditionally adds a path under the project build tree and
+ # on older versions it is not reported with proper quotes. Remove it.
+ string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" _dir_regex "${CMAKE_BINARY_DIR}")
+ string(REGEX REPLACE " -[FL]${_dir_regex}/([^ ]| [^-])+( |$)" " " xline "${line}")
+ if(NOT "x${xline}" STREQUAL "x${line}")
+ string(APPEND log " reduced line: [${line}]\n to: [${xline}]\n")
+ set(line "${xline}")
+ endif()
+ endif()
+ separate_arguments(args NATIVE_COMMAND "${line}")
+ list(GET args 0 cmd)
+ else()
+ #check to see if the link line is comma-separated instead of space separated
+ string(REGEX REPLACE "," " " line "${line}")
+ if("${line}" MATCHES "${linker_regex}" AND
+ NOT "${line}" MATCHES "${linker_exclude_regex}")
+ separate_arguments(args NATIVE_COMMAND "${line}")
+ list(GET args 0 cmd)
+ if("${cmd}" MATCHES "exec:")
+ # ibm xl sometimes has 'exec: ' in-front of the linker
+ list(GET args 1 cmd)
+ endif()
+ endif()
+ endif()
+ set(is_msvc 0)
+ if("${cmd}" MATCHES "${linker_regex}")
+ string(APPEND log " link line: [${line}]\n")
+ string(REGEX REPLACE ";-([LYz]);" ";-\\1" args "${args}")
+ set(skip_value_of "")
+ foreach(arg IN LISTS args)
+ if(skip_value_of)
+ string(APPEND log " arg [${arg}] ==> skip value of ${skip_value_of}\n")
+ set(skip_value_of "")
+ elseif("${arg}" MATCHES "^-L(.:)?[/\\]")
+ # Unix search path.
+ string(REGEX REPLACE "^-L" "" dir "${arg}")
+ list(APPEND implicit_dirs_tmp ${dir})
+ string(APPEND log " arg [${arg}] ==> dir [${dir}]\n")
+ elseif("${arg}" MATCHES "^[-/](LIBPATH|libpath):(.+)")
+ # MSVC search path.
+ set(dir "${CMAKE_MATCH_2}")
+ list(APPEND implicit_dirs_tmp ${dir})
+ string(APPEND log " arg [${arg}] ==> dir [${dir}]\n")
+ elseif(is_msvc AND "${arg}" STREQUAL "-link")
+ string(APPEND log " arg [${arg}] ==> ignore MSVC cl option\n")
+ elseif(is_msvc AND "${arg}" MATCHES "^(.*\\.[Ll][Ii][Bb])$")
+ set(lib "${CMAKE_MATCH_1}")
+ list(APPEND implicit_libs_tmp ${lib})
+ string(APPEND log " arg [${arg}] ==> lib [${lib}]\n")
+ elseif("${arg}" STREQUAL "-lto_library")
+ # ld argument "-lto_library <path>"
+ set(skip_value_of "${arg}")
+ string(APPEND log " arg [${arg}] ==> ignore, skip following value\n")
+ elseif("${arg}" MATCHES "^-l([^:].*)$")
+ # Unix library.
+ set(lib "${CMAKE_MATCH_1}")
+ list(APPEND implicit_libs_tmp ${lib})
+ string(APPEND log " arg [${arg}] ==> lib [${lib}]\n")
+ elseif("${arg}" MATCHES "^(.:)?[/\\].*\\.a$")
+ # Unix library full path.
+ list(APPEND implicit_libs_tmp ${arg})
+ string(APPEND log " arg [${arg}] ==> lib [${arg}]\n")
+ elseif("${arg}" MATCHES "^[-/](DEFAULTLIB|defaultlib):(.+)")
+ # Windows library.
+ set(lib "${CMAKE_MATCH_2}")
+ list(APPEND implicit_libs_tmp ${lib})
+ string(APPEND log " arg [${arg}] ==> lib [${lib}]\n")
+ elseif("${arg}" MATCHES "^(.:)?[/\\].*\\.o$")
+ if(EXTRA_PARSE_COMPUTE_IMPLICIT_OBJECTS)
+ list(APPEND implicit_objs_tmp ${arg})
+ string(APPEND log " arg [${arg}] ==> obj [${arg}]\n")
+ endif()
+ if(obj_regex AND "${arg}" MATCHES "${obj_regex}")
+ # Object file full path.
+ list(APPEND implicit_libs_tmp ${arg})
+ endif()
+ elseif("${arg}" MATCHES "^-Y(P,)?[^0-9]")
+ # Sun search path ([^0-9] avoids conflict with Mac -Y<num>).
+ string(REGEX REPLACE "^-Y(P,)?" "" dirs "${arg}")
+ string(REPLACE ":" ";" dirs "${dirs}")
+ list(APPEND implicit_dirs_tmp ${dirs})
+ string(APPEND log " arg [${arg}] ==> dirs [${dirs}]\n")
+ elseif("${arg}" MATCHES "^-l:")
+ # HP named library.
+ list(APPEND implicit_libs_tmp ${arg})
+ string(APPEND log " arg [${arg}] ==> lib [${arg}]\n")
+ elseif("${arg}" MATCHES "^-z(all|default|weak)extract")
+ # Link editor option.
+ list(APPEND implicit_libs_tmp ${arg})
+ string(APPEND log " arg [${arg}] ==> opt [${arg}]\n")
+ elseif("${arg}" STREQUAL "cl.exe")
+ string(APPEND log " arg [${arg}] ==> recognize MSVC cl\n")
+ set(is_msvc 1)
+ else()
+ string(APPEND log " arg [${arg}] ==> ignore\n")
+ endif()
+ endforeach()
+ break()
+ elseif("${line}" MATCHES "LPATH(=| is:? *)(.*)$")
+ string(APPEND log " LPATH line: [${line}]\n")
+ # HP search path.
+ string(REPLACE ":" ";" paths "${CMAKE_MATCH_2}")
+ list(APPEND implicit_dirs_tmp ${paths})
+ string(APPEND log " dirs [${paths}]\n")
+ else()
+ string(APPEND log " ignore line: [${line}]\n")
+ endif()
+ endforeach()
+
+ # Look for library search paths reported by linker.
+ if("${output_lines}" MATCHES ";Library search paths:((;\t[^;]+)+)")
+ string(REPLACE ";\t" ";" implicit_dirs_match "${CMAKE_MATCH_1}")
+ string(APPEND log " Library search paths: [${implicit_dirs_match}]\n")
+ list(APPEND implicit_dirs_tmp ${implicit_dirs_match})
+ endif()
+ if("${output_lines}" MATCHES ";Framework search paths:((;\t[^;]+)+)")
+ string(REPLACE ";\t" ";" implicit_fwks_match "${CMAKE_MATCH_1}")
+ string(APPEND log " Framework search paths: [${implicit_fwks_match}]\n")
+ list(APPEND implicit_fwks_tmp ${implicit_fwks_match})
+ endif()
+
+ # Cleanup list of libraries and flags.
+ # We remove items that are not language-specific.
+ set(implicit_libs "")
+ foreach(lib IN LISTS implicit_libs_tmp)
+ if("x${lib}" MATCHES "^x(crt.*\\.o|gcc_eh.*|.*libgcc_eh.*|System.*|.*libclang_rt.*|msvcrt.*|libvcruntime.*|libucrt.*|libcmt.*)$")
+ string(APPEND log " remove lib [${lib}]\n")
+ elseif(IS_ABSOLUTE "${lib}")
+ get_filename_component(abs "${lib}" ABSOLUTE)
+ if(NOT "x${lib}" STREQUAL "x${abs}")
+ string(APPEND log " collapse lib [${lib}] ==> [${abs}]\n")
+ endif()
+ list(APPEND implicit_libs "${abs}")
+ else()
+ list(APPEND implicit_libs "${lib}")
+ endif()
+ endforeach()
+
+ if(EXTRA_PARSE_COMPUTE_IMPLICIT_OBJECTS)
+ set(implicit_objs "")
+ foreach(obj IN LISTS implicit_objs_tmp)
+ if(IS_ABSOLUTE "${obj}")
+ get_filename_component(abs "${obj}" ABSOLUTE)
+ if(NOT "x${obj}" STREQUAL "x${abs}")
+ string(APPEND log " collapse obj [${obj}] ==> [${abs}]\n")
+ endif()
+ list(APPEND implicit_objs "${abs}")
+ else()
+ list(APPEND implicit_objs "${obj}")
+ endif()
+ endforeach()
+ endif()
+
+ # Cleanup list of library and framework directories.
+ set(desc_dirs "library")
+ set(desc_fwks "framework")
+ foreach(t dirs fwks)
+ set(implicit_${t} "")
+ foreach(d IN LISTS implicit_${t}_tmp)
+ get_filename_component(dir "${d}" ABSOLUTE)
+ string(FIND "${dir}" "${CMAKE_FILES_DIRECTORY}/" pos)
+ if(NOT pos LESS 0)
+ set(msg ", skipping non-system directory")
+ else()
+ set(msg "")
+ list(APPEND implicit_${t} "${dir}")
+ endif()
+ string(APPEND log " collapse ${desc_${t}} dir [${d}] ==> [${dir}]${msg}\n")
+ endforeach()
+ list(REMOVE_DUPLICATES implicit_${t})
+ endforeach()
+
+ # Log results.
+ string(APPEND log " implicit libs: [${implicit_libs}]\n")
+ string(APPEND log " implicit objs: [${implicit_objs}]\n")
+ string(APPEND log " implicit dirs: [${implicit_dirs}]\n")
+ string(APPEND log " implicit fwks: [${implicit_fwks}]\n")
+
+ # Return results.
+ set(${lib_var} "${implicit_libs}" PARENT_SCOPE)
+ set(${dir_var} "${implicit_dirs}" PARENT_SCOPE)
+ set(${fwk_var} "${implicit_fwks}" PARENT_SCOPE)
+ set(${log_var} "${log}" PARENT_SCOPE)
+
+ if(EXTRA_PARSE_COMPUTE_IMPLICIT_OBJECTS)
+ set(${EXTRA_PARSE_COMPUTE_IMPLICIT_OBJECTS} "${implicit_objs}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+cmake_policy(POP)
diff --git a/Modules/CMakeParseLibraryArchitecture.cmake b/Modules/CMakeParseLibraryArchitecture.cmake
new file mode 100644
index 0000000..6fb9c6b
--- /dev/null
+++ b/Modules/CMakeParseLibraryArchitecture.cmake
@@ -0,0 +1,54 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0053 NEW)
+cmake_policy(SET CMP0054 NEW)
+
+# Function parse implicit linker options.
+# This is used internally by CMake and should not be included by user
+# code.
+
+function(cmake_parse_library_architecture lang implicit_dirs implicit_objs output_var)
+ unset(library_arch)
+ # Detect library architecture directory name.
+ if(CMAKE_LIBRARY_ARCHITECTURE_REGEX)
+ foreach(dir IN LISTS implicit_dirs)
+ if("${dir}" MATCHES "/lib/${CMAKE_LIBRARY_ARCHITECTURE_REGEX}$")
+ get_filename_component(arch "${dir}" NAME)
+ set(library_arch "${arch}")
+ break()
+ endif()
+ endforeach()
+
+ foreach(obj IN LISTS implicit_objs)
+ get_filename_component(dir "${obj}" DIRECTORY)
+ if("${dir}" MATCHES "(/usr)+/lib/${CMAKE_LIBRARY_ARCHITECTURE_REGEX}$")
+ get_filename_component(arch "${dir}" NAME)
+ set(library_arch "${arch}")
+ break()
+ endif()
+ endforeach()
+ endif()
+
+ if(CMAKE_CXX_COMPILER_ID STREQUAL QCC)
+ foreach(dir ${implicit_dirs})
+ if (dir MATCHES "/lib$")
+ get_filename_component(assumedArchDir "${dir}" DIRECTORY)
+ get_filename_component(archParentDir "${assumedArchDir}" DIRECTORY)
+ if (archParentDir STREQUAL CMAKE_SYSROOT)
+ get_filename_component(archDirName "${assumedArchDir}" NAME)
+ set(library_arch "${archDirName}")
+ break()
+ endif()
+ endif()
+ endforeach()
+ endif()
+
+ # Return results.
+ if(library_arch)
+ set(${output_var} "${library_arch}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+cmake_policy(POP)
diff --git a/Modules/CMakePlatformId.h.in b/Modules/CMakePlatformId.h.in
new file mode 100644
index 0000000..2643874
--- /dev/null
+++ b/Modules/CMakePlatformId.h.in
@@ -0,0 +1,315 @@
+#define STRINGIFY_HELPER(X) #X
+#define STRINGIFY(X) STRINGIFY_HELPER(X)
+
+/* Identify known platforms by name. */
+#if defined(__linux) || defined(__linux__) || defined(linux)
+# define PLATFORM_ID "Linux"
+
+#elif defined(__CYGWIN__)
+# define PLATFORM_ID "Cygwin"
+
+#elif defined(__MINGW32__)
+# define PLATFORM_ID "MinGW"
+
+#elif defined(__APPLE__)
+# define PLATFORM_ID "Darwin"
+
+#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
+# define PLATFORM_ID "Windows"
+
+#elif defined(__FreeBSD__) || defined(__FreeBSD)
+# define PLATFORM_ID "FreeBSD"
+
+#elif defined(__NetBSD__) || defined(__NetBSD)
+# define PLATFORM_ID "NetBSD"
+
+#elif defined(__OpenBSD__) || defined(__OPENBSD)
+# define PLATFORM_ID "OpenBSD"
+
+#elif defined(__sun) || defined(sun)
+# define PLATFORM_ID "SunOS"
+
+#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
+# define PLATFORM_ID "AIX"
+
+#elif defined(__hpux) || defined(__hpux__)
+# define PLATFORM_ID "HP-UX"
+
+#elif defined(__HAIKU__)
+# define PLATFORM_ID "Haiku"
+
+#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
+# define PLATFORM_ID "BeOS"
+
+#elif defined(__QNX__) || defined(__QNXNTO__)
+# define PLATFORM_ID "QNX"
+
+#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
+# define PLATFORM_ID "Tru64"
+
+#elif defined(__riscos) || defined(__riscos__)
+# define PLATFORM_ID "RISCos"
+
+#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
+# define PLATFORM_ID "SINIX"
+
+#elif defined(__UNIX_SV__)
+# define PLATFORM_ID "UNIX_SV"
+
+#elif defined(__bsdos__)
+# define PLATFORM_ID "BSDOS"
+
+#elif defined(_MPRAS) || defined(MPRAS)
+# define PLATFORM_ID "MP-RAS"
+
+#elif defined(__osf) || defined(__osf__)
+# define PLATFORM_ID "OSF1"
+
+#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
+# define PLATFORM_ID "SCO_SV"
+
+#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
+# define PLATFORM_ID "ULTRIX"
+
+#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
+# define PLATFORM_ID "Xenix"
+
+#elif defined(__WATCOMC__)
+# if defined(__LINUX__)
+# define PLATFORM_ID "Linux"
+
+# elif defined(__DOS__)
+# define PLATFORM_ID "DOS"
+
+# elif defined(__OS2__)
+# define PLATFORM_ID "OS2"
+
+# elif defined(__WINDOWS__)
+# define PLATFORM_ID "Windows3x"
+
+# elif defined(__VXWORKS__)
+# define PLATFORM_ID "VxWorks"
+
+# else /* unknown platform */
+# define PLATFORM_ID
+# endif
+
+#elif defined(__INTEGRITY)
+# if defined(INT_178B)
+# define PLATFORM_ID "Integrity178"
+
+# else /* regular Integrity */
+# define PLATFORM_ID "Integrity"
+# endif
+
+#else /* unknown platform */
+# define PLATFORM_ID
+
+#endif
+
+/* For windows compilers MSVC and Intel we can determine
+ the architecture of the compiler being used. This is because
+ the compilers do not have flags that can change the architecture,
+ but rather depend on which compiler is being used
+*/
+#if defined(_WIN32) && defined(_MSC_VER)
+# if defined(_M_IA64)
+# define ARCHITECTURE_ID "IA64"
+
+# elif defined(_M_ARM64EC)
+# define ARCHITECTURE_ID "ARM64EC"
+
+# elif defined(_M_X64) || defined(_M_AMD64)
+# define ARCHITECTURE_ID "x64"
+
+# elif defined(_M_IX86)
+# define ARCHITECTURE_ID "X86"
+
+# elif defined(_M_ARM64)
+# define ARCHITECTURE_ID "ARM64"
+
+# elif defined(_M_ARM)
+# if _M_ARM == 4
+# define ARCHITECTURE_ID "ARMV4I"
+# elif _M_ARM == 5
+# define ARCHITECTURE_ID "ARMV5I"
+# else
+# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM)
+# endif
+
+# elif defined(_M_MIPS)
+# define ARCHITECTURE_ID "MIPS"
+
+# elif defined(_M_SH)
+# define ARCHITECTURE_ID "SHx"
+
+# else /* unknown architecture */
+# define ARCHITECTURE_ID ""
+# endif
+
+#elif defined(__WATCOMC__)
+# if defined(_M_I86)
+# define ARCHITECTURE_ID "I86"
+
+# elif defined(_M_IX86)
+# define ARCHITECTURE_ID "X86"
+
+# else /* unknown architecture */
+# define ARCHITECTURE_ID ""
+# endif
+
+#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
+# if defined(__ICCARM__)
+# define ARCHITECTURE_ID "ARM"
+
+# elif defined(__ICCRX__)
+# define ARCHITECTURE_ID "RX"
+
+# elif defined(__ICCRH850__)
+# define ARCHITECTURE_ID "RH850"
+
+# elif defined(__ICCRL78__)
+# define ARCHITECTURE_ID "RL78"
+
+# elif defined(__ICCRISCV__)
+# define ARCHITECTURE_ID "RISCV"
+
+# elif defined(__ICCAVR__)
+# define ARCHITECTURE_ID "AVR"
+
+# elif defined(__ICC430__)
+# define ARCHITECTURE_ID "MSP430"
+
+# elif defined(__ICCV850__)
+# define ARCHITECTURE_ID "V850"
+
+# elif defined(__ICC8051__)
+# define ARCHITECTURE_ID "8051"
+
+# elif defined(__ICCSTM8__)
+# define ARCHITECTURE_ID "STM8"
+
+# else /* unknown architecture */
+# define ARCHITECTURE_ID ""
+# endif
+
+#elif defined(__ghs__)
+# if defined(__PPC64__)
+# define ARCHITECTURE_ID "PPC64"
+
+# elif defined(__ppc__)
+# define ARCHITECTURE_ID "PPC"
+
+# elif defined(__ARM__)
+# define ARCHITECTURE_ID "ARM"
+
+# elif defined(__x86_64__)
+# define ARCHITECTURE_ID "x64"
+
+# elif defined(__i386__)
+# define ARCHITECTURE_ID "X86"
+
+# else /* unknown architecture */
+# define ARCHITECTURE_ID ""
+# endif
+
+#elif defined(__TI_COMPILER_VERSION__)
+# if defined(__TI_ARM__)
+# define ARCHITECTURE_ID "ARM"
+
+# elif defined(__MSP430__)
+# define ARCHITECTURE_ID "MSP430"
+
+# elif defined(__TMS320C28XX__)
+# define ARCHITECTURE_ID "TMS320C28x"
+
+# elif defined(__TMS320C6X__) || defined(_TMS320C6X)
+# define ARCHITECTURE_ID "TMS320C6x"
+
+# else /* unknown architecture */
+# define ARCHITECTURE_ID ""
+# endif
+
+#else
+# define ARCHITECTURE_ID
+#endif
+
+/* Convert integer to decimal digit literals. */
+#define DEC(n) \
+ ('0' + (((n) / 10000000)%10)), \
+ ('0' + (((n) / 1000000)%10)), \
+ ('0' + (((n) / 100000)%10)), \
+ ('0' + (((n) / 10000)%10)), \
+ ('0' + (((n) / 1000)%10)), \
+ ('0' + (((n) / 100)%10)), \
+ ('0' + (((n) / 10)%10)), \
+ ('0' + ((n) % 10))
+
+/* Convert integer to hex digit literals. */
+#define HEX(n) \
+ ('0' + ((n)>>28 & 0xF)), \
+ ('0' + ((n)>>24 & 0xF)), \
+ ('0' + ((n)>>20 & 0xF)), \
+ ('0' + ((n)>>16 & 0xF)), \
+ ('0' + ((n)>>12 & 0xF)), \
+ ('0' + ((n)>>8 & 0xF)), \
+ ('0' + ((n)>>4 & 0xF)), \
+ ('0' + ((n) & 0xF))
+
+/* Construct a string literal encoding the version number. */
+#ifdef COMPILER_VERSION
+char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]";
+
+/* Construct a string literal encoding the version number components. */
+#elif defined(COMPILER_VERSION_MAJOR)
+char const info_version[] = {
+ 'I', 'N', 'F', 'O', ':',
+ 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[',
+ COMPILER_VERSION_MAJOR,
+# ifdef COMPILER_VERSION_MINOR
+ '.', COMPILER_VERSION_MINOR,
+# ifdef COMPILER_VERSION_PATCH
+ '.', COMPILER_VERSION_PATCH,
+# ifdef COMPILER_VERSION_TWEAK
+ '.', COMPILER_VERSION_TWEAK,
+# endif
+# endif
+# endif
+ ']','\0'};
+#endif
+
+/* Construct a string literal encoding the internal version number. */
+#ifdef COMPILER_VERSION_INTERNAL
+char const info_version_internal[] = {
+ 'I', 'N', 'F', 'O', ':',
+ 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_',
+ 'i','n','t','e','r','n','a','l','[',
+ COMPILER_VERSION_INTERNAL,']','\0'};
+#elif defined(COMPILER_VERSION_INTERNAL_STR)
+char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]";
+#endif
+
+/* Construct a string literal encoding the version number components. */
+#ifdef SIMULATE_VERSION_MAJOR
+char const info_simulate_version[] = {
+ 'I', 'N', 'F', 'O', ':',
+ 's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[',
+ SIMULATE_VERSION_MAJOR,
+# ifdef SIMULATE_VERSION_MINOR
+ '.', SIMULATE_VERSION_MINOR,
+# ifdef SIMULATE_VERSION_PATCH
+ '.', SIMULATE_VERSION_PATCH,
+# ifdef SIMULATE_VERSION_TWEAK
+ '.', SIMULATE_VERSION_TWEAK,
+# endif
+# endif
+# endif
+ ']','\0'};
+#endif
+
+/* Construct the string literal in pieces to prevent the source from
+ getting matched. Store it in a pointer rather than an array
+ because some compilers will just produce instructions to fill the
+ array rather than assigning a pointer to a static array. */
+char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";
+char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";
diff --git a/Modules/CMakePrintHelpers.cmake b/Modules/CMakePrintHelpers.cmake
new file mode 100644
index 0000000..8c25a73
--- /dev/null
+++ b/Modules/CMakePrintHelpers.cmake
@@ -0,0 +1,150 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CMakePrintHelpers
+-----------------
+
+Convenience functions for printing properties and variables, useful
+e.g. for debugging.
+
+::
+
+ cmake_print_properties([TARGETS target1 .. targetN]
+ [SOURCES source1 .. sourceN]
+ [DIRECTORIES dir1 .. dirN]
+ [TESTS test1 .. testN]
+ [CACHE_ENTRIES entry1 .. entryN]
+ PROPERTIES prop1 .. propN )
+
+This function prints the values of the properties of the given targets,
+source files, directories, tests or cache entries. Exactly one of the
+scope keywords must be used. Example::
+
+ cmake_print_properties(TARGETS foo bar PROPERTIES
+ LOCATION INTERFACE_INCLUDE_DIRECTORIES)
+
+This will print the LOCATION and INTERFACE_INCLUDE_DIRECTORIES properties for
+both targets foo and bar.
+
+::
+
+ cmake_print_variables(var1 var2 .. varN)
+
+This function will print the name of each variable followed by its value.
+Example::
+
+ cmake_print_variables(CMAKE_C_COMPILER CMAKE_MAJOR_VERSION DOES_NOT_EXIST)
+
+Gives::
+
+ -- CMAKE_C_COMPILER="/usr/bin/gcc" ; CMAKE_MAJOR_VERSION="2" ; DOES_NOT_EXIST=""
+#]=======================================================================]
+
+function(cmake_print_variables)
+ set(msg "")
+ foreach(var ${ARGN})
+ if(msg)
+ string(APPEND msg " ; ")
+ endif()
+ string(APPEND msg "${var}=\"${${var}}\"")
+ endforeach()
+ message(STATUS "${msg}")
+endfunction()
+
+
+function(cmake_print_properties)
+ set(options )
+ set(oneValueArgs )
+ set(multiValueArgs TARGETS SOURCES TESTS DIRECTORIES CACHE_ENTRIES PROPERTIES )
+
+ cmake_parse_arguments(CPP "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(CPP_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to cmake_print_properties(): \"${CPP_UNPARSED_ARGUMENTS}\"")
+ return()
+ endif()
+
+ if(NOT CPP_PROPERTIES)
+ message(FATAL_ERROR "Required argument PROPERTIES missing in cmake_print_properties() call")
+ return()
+ endif()
+
+ set(mode)
+ set(items)
+ set(keyword)
+
+ if(CPP_TARGETS)
+ set(items ${CPP_TARGETS})
+ set(mode ${mode} TARGETS)
+ set(keyword TARGET)
+ endif()
+
+ if(CPP_SOURCES)
+ set(items ${CPP_SOURCES})
+ set(mode ${mode} SOURCES)
+ set(keyword SOURCE)
+ endif()
+
+ if(CPP_TESTS)
+ set(items ${CPP_TESTS})
+ set(mode ${mode} TESTS)
+ set(keyword TEST)
+ endif()
+
+ if(CPP_DIRECTORIES)
+ set(items ${CPP_DIRECTORIES})
+ set(mode ${mode} DIRECTORIES)
+ set(keyword DIRECTORY)
+ endif()
+
+ if(CPP_CACHE_ENTRIES)
+ set(items ${CPP_CACHE_ENTRIES})
+ set(mode ${mode} CACHE_ENTRIES)
+ # This is a workaround for the fact that passing `CACHE` as an argument to
+ # set() causes a cache variable to be set.
+ set(keyword "")
+ string(APPEND keyword CACHE)
+ endif()
+
+ if(NOT mode)
+ message(FATAL_ERROR "Mode keyword missing in cmake_print_properties() call, must be one of TARGETS SOURCES TESTS DIRECTORIES CACHE_ENTRIES PROPERTIES")
+ return()
+ endif()
+
+ list(LENGTH mode modeLength)
+ if("${modeLength}" GREATER 1)
+ message(FATAL_ERROR "Multiple mode keyword used in cmake_print_properties() call, it must be exactly one of TARGETS SOURCES TESTS DIRECTORIES CACHE_ENTRIES PROPERTIES")
+ return()
+ endif()
+
+ set(msg "\n")
+ foreach(item ${items})
+
+ set(itemExists TRUE)
+ if(keyword STREQUAL "TARGET")
+ if(NOT TARGET ${item})
+ set(itemExists FALSE)
+ string(APPEND msg "\n No such TARGET \"${item}\" !\n\n")
+ endif()
+ endif()
+
+ if (itemExists)
+ string(APPEND msg " Properties for ${keyword} ${item}:\n")
+ foreach(prop ${CPP_PROPERTIES})
+
+ get_property(propertySet ${keyword} ${item} PROPERTY "${prop}" SET)
+
+ if(propertySet)
+ get_property(property ${keyword} ${item} PROPERTY "${prop}")
+ string(APPEND msg " ${item}.${prop} = \"${property}\"\n")
+ else()
+ string(APPEND msg " ${item}.${prop} = <NOTFOUND>\n")
+ endif()
+ endforeach()
+ endif()
+
+ endforeach()
+ message(STATUS "${msg}")
+
+endfunction()
diff --git a/Modules/CMakePrintSystemInformation.cmake b/Modules/CMakePrintSystemInformation.cmake
new file mode 100644
index 0000000..d44e933
--- /dev/null
+++ b/Modules/CMakePrintSystemInformation.cmake
@@ -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.
+
+#[=======================================================================[.rst:
+CMakePrintSystemInformation
+---------------------------
+
+Print system information.
+
+This module serves diagnostic purposes. Just include it in a
+project to see various internal CMake variables.
+#]=======================================================================]
+
+message("CMAKE_SYSTEM is ${CMAKE_SYSTEM} ${CMAKE_SYSTEM_NAME} ${CMAKE_SYSTEM_VERSION} ${CMAKE_SYSTEM_PROCESSOR}")
+message("CMAKE_SYSTEM file is ${CMAKE_SYSTEM_INFO_FILE}")
+message("CMAKE_C_COMPILER is ${CMAKE_C_COMPILER}")
+message("CMAKE_CXX_COMPILER is ${CMAKE_CXX_COMPILER}")
+
+
+message("CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS is ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS}")
+message("CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS is ${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS}")
+message("CMAKE_DL_LIBS is ${CMAKE_DL_LIBS}")
+message("CMAKE_SHARED_LIBRARY_PREFIX is ${CMAKE_SHARED_LIBRARY_PREFIX}")
+message("CMAKE_SHARED_LIBRARY_SUFFIX is ${CMAKE_SHARED_LIBRARY_SUFFIX}")
+message("CMAKE_COMPILER_IS_GNUCC = ${CMAKE_COMPILER_IS_GNUCC}")
+message("CMAKE_COMPILER_IS_GNUCXX = ${CMAKE_COMPILER_IS_GNUCXX}")
+
+message("CMAKE_CXX_CREATE_SHARED_LIBRARY is ${CMAKE_CXX_CREATE_SHARED_LIBRARY}")
+message("CMAKE_CXX_CREATE_SHARED_MODULE is ${CMAKE_CXX_CREATE_SHARED_MODULE}")
+message("CMAKE_CXX_CREATE_STATIC_LIBRARY is ${CMAKE_CXX_CREATE_STATIC_LIBRARY}")
+message("CMAKE_CXX_COMPILE_OBJECT is ${CMAKE_CXX_COMPILE_OBJECT}")
+message("CMAKE_CXX_LINK_EXECUTABLE ${CMAKE_CXX_LINK_EXECUTABLE}")
+
+message("CMAKE_C_CREATE_SHARED_LIBRARY is ${CMAKE_C_CREATE_SHARED_LIBRARY}")
+message("CMAKE_C_CREATE_SHARED_MODULE is ${CMAKE_C_CREATE_SHARED_MODULE}")
+message("CMAKE_C_CREATE_STATIC_LIBRARY is ${CMAKE_C_CREATE_STATIC_LIBRARY}")
+message("CMAKE_C_COMPILE_OBJECT is ${CMAKE_C_COMPILE_OBJECT}")
+message("CMAKE_C_LINK_EXECUTABLE ${CMAKE_C_LINK_EXECUTABLE}")
+
+message("CMAKE_SYSTEM_AND_CXX_COMPILER_INFO_FILE ${CMAKE_SYSTEM_AND_CXX_COMPILER_INFO_FILE}")
+message("CMAKE_SYSTEM_AND_C_COMPILER_INFO_FILE ${CMAKE_SYSTEM_AND_C_COMPILER_INFO_FILE}")
diff --git a/Modules/CMakePushCheckState.cmake b/Modules/CMakePushCheckState.cmake
new file mode 100644
index 0000000..3e519ee
--- /dev/null
+++ b/Modules/CMakePushCheckState.cmake
@@ -0,0 +1,91 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CMakePushCheckState
+-------------------
+
+
+
+This module defines three macros: ``CMAKE_PUSH_CHECK_STATE()``
+``CMAKE_POP_CHECK_STATE()`` and ``CMAKE_RESET_CHECK_STATE()`` These macros can
+be used to save, restore and reset (i.e., clear contents) the state of
+the variables ``CMAKE_REQUIRED_FLAGS``, ``CMAKE_REQUIRED_DEFINITIONS``,
+``CMAKE_REQUIRED_LINK_OPTIONS``, ``CMAKE_REQUIRED_LIBRARIES``,
+``CMAKE_REQUIRED_INCLUDES`` and ``CMAKE_EXTRA_INCLUDE_FILES`` used by the
+various Check-files coming with CMake, like e.g. ``check_function_exists()``
+etc.
+The variable contents are pushed on a stack, pushing multiple times is
+supported. This is useful e.g. when executing such tests in a Find-module,
+where they have to be set, but after the Find-module has been executed they
+should have the same value as they had before.
+
+``CMAKE_PUSH_CHECK_STATE()`` macro receives optional argument ``RESET``.
+Whether it's specified, ``CMAKE_PUSH_CHECK_STATE()`` will set all
+``CMAKE_REQUIRED_*`` variables to empty values, same as
+``CMAKE_RESET_CHECK_STATE()`` call will do.
+
+Usage:
+
+.. code-block:: cmake
+
+ cmake_push_check_state(RESET)
+ set(CMAKE_REQUIRED_DEFINITIONS -DSOME_MORE_DEF)
+ check_function_exists(...)
+ cmake_reset_check_state()
+ set(CMAKE_REQUIRED_DEFINITIONS -DANOTHER_DEF)
+ check_function_exists(...)
+ cmake_pop_check_state()
+#]=======================================================================]
+
+macro(CMAKE_RESET_CHECK_STATE)
+
+ set(CMAKE_EXTRA_INCLUDE_FILES)
+ set(CMAKE_REQUIRED_INCLUDES)
+ set(CMAKE_REQUIRED_DEFINITIONS)
+ set(CMAKE_REQUIRED_LINK_OPTIONS)
+ set(CMAKE_REQUIRED_LIBRARIES)
+ set(CMAKE_REQUIRED_FLAGS)
+ set(CMAKE_REQUIRED_QUIET)
+
+endmacro()
+
+macro(CMAKE_PUSH_CHECK_STATE)
+
+ if(NOT DEFINED _CMAKE_PUSH_CHECK_STATE_COUNTER)
+ set(_CMAKE_PUSH_CHECK_STATE_COUNTER 0)
+ endif()
+
+ math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}+1")
+
+ set(_CMAKE_EXTRA_INCLUDE_FILES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_EXTRA_INCLUDE_FILES})
+ set(_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_INCLUDES})
+ set(_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_DEFINITIONS})
+ set(_CMAKE_REQUIRED_LINK_OPTIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_LINK_OPTIONS})
+ set(_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_LIBRARIES})
+ set(_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_FLAGS})
+ set(_CMAKE_REQUIRED_QUIET_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_QUIET})
+
+ if (${ARGC} GREATER 0 AND "${ARGV0}" STREQUAL "RESET")
+ cmake_reset_check_state()
+ endif()
+
+endmacro()
+
+macro(CMAKE_POP_CHECK_STATE)
+
+# don't pop more than we pushed
+ if("${_CMAKE_PUSH_CHECK_STATE_COUNTER}" GREATER "0")
+
+ set(CMAKE_EXTRA_INCLUDE_FILES ${_CMAKE_EXTRA_INCLUDE_FILES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_INCLUDES ${_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_DEFINITIONS ${_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_LINK_OPTIONS ${_CMAKE_REQUIRED_LINK_OPTIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_LIBRARIES ${_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_FLAGS ${_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+ set(CMAKE_REQUIRED_QUIET ${_CMAKE_REQUIRED_QUIET_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
+
+ math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}-1")
+ endif()
+
+endmacro()
diff --git a/Modules/CMakeRCCompiler.cmake.in b/Modules/CMakeRCCompiler.cmake.in
new file mode 100644
index 0000000..8257cd6
--- /dev/null
+++ b/Modules/CMakeRCCompiler.cmake.in
@@ -0,0 +1,6 @@
+set(CMAKE_RC_COMPILER "@CMAKE_RC_COMPILER@")
+set(CMAKE_RC_COMPILER_ARG1 "@CMAKE_RC_COMPILER_ARG1@")
+set(CMAKE_RC_COMPILER_LOADED 1)
+set(CMAKE_RC_SOURCE_FILE_EXTENSIONS rc;RC)
+set(CMAKE_RC_OUTPUT_EXTENSION @CMAKE_RC_OUTPUT_EXTENSION@)
+set(CMAKE_RC_COMPILER_ENV_VAR "RC")
diff --git a/Modules/CMakeRCInformation.cmake b/Modules/CMakeRCInformation.cmake
new file mode 100644
index 0000000..b634796
--- /dev/null
+++ b/Modules/CMakeRCInformation.cmake
@@ -0,0 +1,50 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file sets the basic flags for the Windows Resource Compiler.
+# It also loads the available platform file for the system-compiler
+# if it exists.
+
+# make sure we don't use CMAKE_BASE_NAME from somewhere else
+set(CMAKE_BASE_NAME)
+if(CMAKE_RC_COMPILER MATCHES "windres[^/]*$")
+ set(CMAKE_BASE_NAME "windres")
+else()
+ get_filename_component(CMAKE_BASE_NAME ${CMAKE_RC_COMPILER} NAME_WE)
+endif()
+set(CMAKE_SYSTEM_AND_RC_COMPILER_INFO_FILE
+ ${CMAKE_ROOT}/Modules/Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME}.cmake)
+include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME} OPTIONAL)
+
+# This should be included before the _INIT variables are
+# used to initialize the cache. Since the rule variables
+# have if blocks on them, users can still define them here.
+# But, it should still be after the platform file so changes can
+# be made to those values.
+if(CMAKE_USER_MAKE_RULES_OVERRIDE)
+ # Save the full path of the file so try_compile can use it.
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE} RESULT_VARIABLE _override)
+ set(CMAKE_USER_MAKE_RULES_OVERRIDE "${_override}")
+endif()
+
+set(CMAKE_RC_FLAGS_INIT "$ENV{RCFLAGS} ${CMAKE_RC_FLAGS_INIT}")
+
+cmake_initialize_per_config_variable(CMAKE_RC_FLAGS "Flags for Windows Resource Compiler")
+
+# These are the only types of flags that should be passed to the rc
+# command, if COMPILE_FLAGS is used on a target this will be used
+# to filter out any other flags
+set(CMAKE_RC_FLAG_REGEX "^[-/](D|I)")
+
+# now define the following rule variables
+# CMAKE_RC_COMPILE_OBJECT
+set(CMAKE_INCLUDE_FLAG_RC "-I ")
+# compile a Resource file into an object file
+if(NOT CMAKE_RC_COMPILE_OBJECT)
+ set(CMAKE_RC_COMPILE_OBJECT
+ "<CMAKE_RC_COMPILER> <DEFINES> <INCLUDES> <FLAGS> /fo <OBJECT> <SOURCE>")
+endif()
+
+# set this variable so we can avoid loading this more than once.
+set(CMAKE_RC_INFORMATION_LOADED 1)
diff --git a/Modules/CMakeSwiftCompiler.cmake.in b/Modules/CMakeSwiftCompiler.cmake.in
new file mode 100644
index 0000000..47ada38
--- /dev/null
+++ b/Modules/CMakeSwiftCompiler.cmake.in
@@ -0,0 +1,16 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+set(CMAKE_Swift_COMPILER "@CMAKE_Swift_COMPILER@")
+set(CMAKE_Swift_COMPILER_ID "@CMAKE_Swift_COMPILER_ID@")
+set(CMAKE_Swift_COMPILER_VERSION "@CMAKE_Swift_COMPILER_VERSION@")
+
+set(CMAKE_Swift_COMPILER_LOADED 1)
+set(CMAKE_Swift_COMPILER_WORKS "@CMAKE_Swift_COMPILER_WORKS@")
+
+set(CMAKE_Swift_COMPILER_ENV_VAR "SWIFTC")
+
+set(CMAKE_Swift_COMPILER_ID_RUN 1)
+set(CMAKE_Swift_SOURCE_FILE_EXTENSIONS swift)
+
+set(CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES "@CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES@")
diff --git a/Modules/CMakeSwiftInformation.cmake b/Modules/CMakeSwiftInformation.cmake
new file mode 100644
index 0000000..8f0909c
--- /dev/null
+++ b/Modules/CMakeSwiftInformation.cmake
@@ -0,0 +1,103 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+if(UNIX)
+ set(CMAKE_Swift_OUTPUT_EXTENSION .o)
+else()
+ set(CMAKE_Swift_OUTPUT_EXTENSION .obj)
+endif()
+
+# Load compiler-specific information.
+if(CMAKE_Swift_COMPILER_ID)
+ include(Compiler/${CMAKE_Swift_COMPILER_ID}-Swift OPTIONAL)
+
+ if(CMAKE_SYSTEM_PROCESSOR)
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_Swift_COMPILER_ID}-Swift-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL)
+ endif()
+ include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_Swift_COMPILER_ID}-Swift OPTIONAL)
+endif()
+
+set(CMAKE_EXE_EXPORTS_Swift_FLAG "-emit-module -emit-module-path <SWIFT_MODULE> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS}")
+
+set(CMAKE_INCLUDE_FLAG_Swift "-I ")
+if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+ set(CMAKE_SHARED_LIBRARY_SONAME_Swift_FLAG "-Xlinker -install_name -Xlinker ")
+elseif(NOT CMAKE_SYSTEM_NAME STREQUAL Windows)
+ set(CMAKE_SHARED_LIBRARY_SONAME_Swift_FLAG "-Xlinker -soname -Xlinker ")
+endif()
+
+if(NOT CMAKE_SYSTEM_NAME STREQUAL Windows)
+ set(CMAKE_EXECUTABLE_RUNTIME_Swift_FLAG "-Xlinker -rpath -Xlinker ")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_Swift_FLAG "-Xlinker -rpath -Xlinker ")
+ if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+ set(CMAKE_EXECUTABLE_RUNTIME_Swift_FLAG_SEP "")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_Swift_FLAG_SEP "")
+ else()
+ set(CMAKE_EXECUTABLE_RUNTIME_Swift_FLAG_SEP ":")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_Swift_FLAG_SEP ":")
+ endif()
+endif()
+
+set(CMAKE_Swift_COMPILE_OPTIONS_TARGET "-target ")
+set(CMAKE_Swift_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN "-tools-directory ")
+# NOTE(compnerd) the `-sdk` support is not yet ready in the compiler; when that
+# is fully working, we should be able to enable this.
+# set(CMAKE_Swift_COMPILE_OPTIONS_SYSROOT "-sdk ")
+# NOTE(compnerd) do not setup `-frontend` as we use the compiler as the driver
+# during the link phase and use that to drive the compilation
+set(CMAKE_Swift_COMPILER_ARG1 "")
+set(CMAKE_Swift_DEFINE_FLAG -D)
+set(CMAKE_Swift_FRAMEWORK_SEARCH_FLAG "-F ")
+set(CMAKE_Swift_LIBRARY_PATH_FLAG "-L ")
+set(CMAKE_Swift_LIBRARY_PATH_TERMINATOR "")
+set(CMAKE_Swift_LINK_LIBRARY_FLAG "-l")
+set(CMAKE_Swift_LINKER_WRAPPER_FLAG "-Xlinker" " ")
+set(CMAKE_Swift_RESPONSE_FILE_LINK_FLAG @)
+
+set(CMAKE_Swift_LINKER_PREFERENCE 50)
+set(CMAKE_Swift_LINKER_PREFERENCE_PROPAGATES 1)
+
+# NOTE(compnerd) use the short form for convenience and ease of search. They
+# are treated equivalent to their long form names as well as custom Swift
+# specific names.
+set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -libc MT)
+set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -libc MD)
+set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -libc MTd)
+set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -libc MDd)
+
+set(CMAKE_Swift_FLAGS_DEBUG_INIT "-g")
+set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O")
+set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g")
+set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize")
+
+cmake_initialize_per_config_variable(CMAKE_Swift_FLAGS "Swift Compiler Flags")
+
+# NOTE(compnerd) we do not have an object compile rule since we build the objects as part of the link step
+if(NOT CMAKE_Swift_COMPILE_OBJECT)
+ set(CMAKE_Swift_COMPILE_OBJECT ":")
+endif()
+
+if(NOT CMAKE_Swift_NUM_THREADS MATCHES "^[0-9]+$")
+ cmake_host_system_information(RESULT CMAKE_Swift_NUM_THREADS QUERY NUMBER_OF_LOGICAL_CORES)
+endif()
+
+if(NOT CMAKE_Swift_CREATE_SHARED_LIBRARY)
+ set(CMAKE_Swift_CREATE_SHARED_LIBRARY "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-library -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS} <LINK_LIBRARIES>")
+endif()
+
+if(NOT CMAKE_Swift_CREATE_SHARED_MODULE)
+ set(CMAKE_Swift_CREATE_SHARED_MODULE ${CMAKE_Swift_CREATE_SHARED_LIBRARY})
+endif()
+
+if(NOT CMAKE_Swift_LINK_EXECUTABLE)
+ set(CMAKE_Swift_LINK_EXECUTABLE "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-executable -o <TARGET> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
+endif()
+
+if(NOT CMAKE_Swift_CREATE_STATIC_LIBRARY)
+ set(CMAKE_Swift_CREATE_STATIC_LIBRARY "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-library -static -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
+
+ set(CMAKE_Swift_ARCHIVE_CREATE "<CMAKE_AR> crs <TARGET> <OBJECTS>")
+ set(CMAKE_Swift_ARCHIVE_FINISH "")
+endif()
+
+set(CMAKE_Swift_INFORMATION_LOADED 1)
diff --git a/Modules/CMakeSystem.cmake.in b/Modules/CMakeSystem.cmake.in
new file mode 100644
index 0000000..ef8aaa0
--- /dev/null
+++ b/Modules/CMakeSystem.cmake.in
@@ -0,0 +1,15 @@
+set(CMAKE_HOST_SYSTEM "@CMAKE_HOST_SYSTEM@")
+set(CMAKE_HOST_SYSTEM_NAME "@CMAKE_HOST_SYSTEM_NAME@")
+set(CMAKE_HOST_SYSTEM_VERSION "@CMAKE_HOST_SYSTEM_VERSION@")
+set(CMAKE_HOST_SYSTEM_PROCESSOR "@CMAKE_HOST_SYSTEM_PROCESSOR@")
+
+@INCLUDE_CMAKE_TOOLCHAIN_FILE_IF_REQUIRED@
+
+set(CMAKE_SYSTEM "@CMAKE_SYSTEM@")
+set(CMAKE_SYSTEM_NAME "@CMAKE_SYSTEM_NAME@")
+set(CMAKE_SYSTEM_VERSION "@CMAKE_SYSTEM_VERSION@")
+set(CMAKE_SYSTEM_PROCESSOR "@CMAKE_SYSTEM_PROCESSOR@")
+@CMAKE_SYSTEM_CUSTOM_CODE@
+set(CMAKE_CROSSCOMPILING "@CMAKE_CROSSCOMPILING@")
+
+set(CMAKE_SYSTEM_LOADED 1)
diff --git a/Modules/CMakeSystemSpecificInformation.cmake b/Modules/CMakeSystemSpecificInformation.cmake
new file mode 100644
index 0000000..ea3a445
--- /dev/null
+++ b/Modules/CMakeSystemSpecificInformation.cmake
@@ -0,0 +1,58 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is included by cmGlobalGenerator::EnableLanguage.
+# It is included after the compiler has been determined, so
+# we know things like the compiler name and if the compiler is gnu.
+
+# before cmake 2.6 these variables were set in cmMakefile.cxx. This is still
+# done to keep scripts and custom language and compiler modules working.
+# But they are reset here and set again in the platform files for the target
+# platform, so they can be used for testing the target platform instead
+# of testing the host platform.
+set(APPLE )
+set(UNIX )
+set(CYGWIN )
+set(WIN32 )
+
+
+# include Generic system information
+include(CMakeGenericSystem)
+
+# 2. now include SystemName.cmake file to set the system specific information
+set(CMAKE_SYSTEM_INFO_FILE Platform/${CMAKE_SYSTEM_NAME})
+
+include(${CMAKE_SYSTEM_INFO_FILE} OPTIONAL RESULT_VARIABLE _INCLUDED_SYSTEM_INFO_FILE)
+
+if(NOT _INCLUDED_SYSTEM_INFO_FILE)
+ message("System is unknown to cmake, create:\n${CMAKE_SYSTEM_INFO_FILE}"
+ " to use this system, please post your config file on "
+ "discourse.cmake.org so it can be added to cmake")
+ if(EXISTS ${CMAKE_BINARY_DIR}/CMakeCache.txt)
+ configure_file(${CMAKE_BINARY_DIR}/CMakeCache.txt
+ ${CMAKE_BINARY_DIR}/CopyOfCMakeCache.txt COPYONLY)
+ message("Your CMakeCache.txt file was copied to CopyOfCMakeCache.txt. "
+ "Please post that file on discourse.cmake.org.")
+ endif()
+endif()
+
+# optionally include a file which can do extra-generator specific things, e.g.
+# CMakeFindEclipseCDT4.cmake asks gcc for the system include dirs for the Eclipse CDT4 generator
+if(CMAKE_EXTRA_GENERATOR)
+ string(REPLACE " " "" _CMAKE_EXTRA_GENERATOR_NO_SPACES ${CMAKE_EXTRA_GENERATOR} )
+ include("CMakeFind${_CMAKE_EXTRA_GENERATOR_NO_SPACES}" OPTIONAL)
+endif()
+
+
+# for most systems a module is the same as a shared library
+# so unless the variable CMAKE_MODULE_EXISTS is set just
+# copy the values from the LIBRARY variables
+# this has to be done after the system information has been loaded
+if(NOT CMAKE_MODULE_EXISTS)
+ set(CMAKE_SHARED_MODULE_PREFIX "${CMAKE_SHARED_LIBRARY_PREFIX}")
+ set(CMAKE_SHARED_MODULE_SUFFIX "${CMAKE_SHARED_LIBRARY_SUFFIX}")
+endif()
+
+
+set(CMAKE_SYSTEM_SPECIFIC_INFORMATION_LOADED 1)
diff --git a/Modules/CMakeSystemSpecificInitialize.cmake b/Modules/CMakeSystemSpecificInitialize.cmake
new file mode 100644
index 0000000..21bcd40
--- /dev/null
+++ b/Modules/CMakeSystemSpecificInitialize.cmake
@@ -0,0 +1,23 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is included by cmGlobalGenerator::EnableLanguage.
+# It is included before the compiler has been determined.
+
+# The CMAKE_EFFECTIVE_SYSTEM_NAME is used to load compiler and compiler
+# wrapper configuration files. By default it equals to CMAKE_SYSTEM_NAME
+# but could be overridden in the ${CMAKE_SYSTEM_NAME}-Initialize files.
+#
+# It is useful to share the same aforementioned configuration files and
+# avoids duplicating them in case of tightly related platforms.
+#
+# An example are the platforms supported by Xcode (macOS, iOS, tvOS,
+# and watchOS). For all of those the CMAKE_EFFECTIVE_SYSTEM_NAME is
+# set to Apple which results in using
+# Platform/Apple-AppleClang-CXX.cmake for the Apple C++ compiler.
+set(CMAKE_EFFECTIVE_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}")
+
+include(Platform/${CMAKE_SYSTEM_NAME}-Initialize OPTIONAL)
+
+set(CMAKE_SYSTEM_SPECIFIC_INITIALIZE_LOADED 1)
diff --git a/Modules/CMakeTestASM-ATTCompiler.cmake b/Modules/CMakeTestASM-ATTCompiler.cmake
new file mode 100644
index 0000000..df735c4
--- /dev/null
+++ b/Modules/CMakeTestASM-ATTCompiler.cmake
@@ -0,0 +1,13 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that the selected ASM-ATT "compiler" works.
+# For assembler this can only check whether the compiler has been found,
+# because otherwise there would have to be a separate assembler source file
+# for each assembler on every architecture.
+
+set(ASM_DIALECT "-ATT")
+include(CMakeTestASMCompiler)
+set(ASM_DIALECT)
diff --git a/Modules/CMakeTestASMCompiler.cmake b/Modules/CMakeTestASMCompiler.cmake
new file mode 100644
index 0000000..7f0b9a7
--- /dev/null
+++ b/Modules/CMakeTestASMCompiler.cmake
@@ -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.
+
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that the selected ASM compiler works.
+# For assembler this can only check whether the compiler has been found,
+# because otherwise there would have to be a separate assembler source file
+# for each assembler on every architecture.
+
+
+set(_ASM_COMPILER_WORKS 0)
+
+if(CMAKE_ASM${ASM_DIALECT}_COMPILER)
+ set(_ASM_COMPILER_WORKS 1)
+endif()
+
+# when using generic "ASM" support, we must have detected the compiler ID, fail otherwise:
+if("ASM${ASM_DIALECT}" STREQUAL "ASM")
+ if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
+ set(_ASM_COMPILER_WORKS 0)
+ endif()
+endif()
+
+set(CMAKE_ASM${ASM_DIALECT}_COMPILER_WORKS ${_ASM_COMPILER_WORKS} CACHE INTERNAL "")
diff --git a/Modules/CMakeTestASM_MASMCompiler.cmake b/Modules/CMakeTestASM_MASMCompiler.cmake
new file mode 100644
index 0000000..c1308ff
--- /dev/null
+++ b/Modules/CMakeTestASM_MASMCompiler.cmake
@@ -0,0 +1,13 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that the selected ASM_MASM "compiler" (should be masm or masm64)
+# works. For assembler this can only check whether the compiler has been found,
+# because otherwise there would have to be a separate assembler source file
+# for each assembler on every architecture.
+
+set(ASM_DIALECT "_MASM")
+include(CMakeTestASMCompiler)
+set(ASM_DIALECT)
diff --git a/Modules/CMakeTestASM_NASMCompiler.cmake b/Modules/CMakeTestASM_NASMCompiler.cmake
new file mode 100644
index 0000000..a9ee39d
--- /dev/null
+++ b/Modules/CMakeTestASM_NASMCompiler.cmake
@@ -0,0 +1,13 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that the selected ASM_NASM "compiler" works.
+# For assembler this can only check whether the compiler has been found,
+# because otherwise there would have to be a separate assembler source file
+# for each assembler on every architecture.
+
+set(ASM_DIALECT "_NASM")
+include(CMakeTestASMCompiler)
+set(ASM_DIALECT)
diff --git a/Modules/CMakeTestCCompiler.cmake b/Modules/CMakeTestCCompiler.cmake
new file mode 100644
index 0000000..03f2db2
--- /dev/null
+++ b/Modules/CMakeTestCCompiler.cmake
@@ -0,0 +1,98 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+if(CMAKE_C_COMPILER_FORCED)
+ # The compiler configuration was forced by the user.
+ # Assume the user has configured all compiler information.
+ set(CMAKE_C_COMPILER_WORKS TRUE)
+ return()
+endif()
+
+include(CMakeTestCompilerCommon)
+
+# work around enforced code signing and / or missing executable target type
+set(__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE})
+if(_CMAKE_FEATURE_DETECTION_TARGET_TYPE)
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_CMAKE_FEATURE_DETECTION_TARGET_TYPE})
+endif()
+
+# Remove any cached result from an older CMake version.
+# We now store this in CMakeCCompiler.cmake.
+unset(CMAKE_C_COMPILER_WORKS CACHE)
+
+# Try to identify the ABI and configure it into CMakeCCompiler.cmake
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
+CMAKE_DETERMINE_COMPILER_ABI(C ${CMAKE_ROOT}/Modules/CMakeCCompilerABI.c)
+if(CMAKE_C_ABI_COMPILED)
+ # The compiler worked so skip dedicated test below.
+ set(CMAKE_C_COMPILER_WORKS TRUE)
+ message(STATUS "Check for working C compiler: ${CMAKE_C_COMPILER} - skipped")
+endif()
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that that selected C compiler can actually compile
+# and link the most basic of programs. If not, a fatal error
+# is set and cmake stops processing commands and will not generate
+# any makefiles or projects.
+if(NOT CMAKE_C_COMPILER_WORKS)
+ PrintTestCompilerStatus("C")
+ __TestCompiler_setTryCompileTargetType()
+ file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testCCompiler.c
+ "#ifdef __cplusplus\n"
+ "# error \"The CMAKE_C_COMPILER is set to a C++ compiler\"\n"
+ "#endif\n"
+ "#if defined(__CLASSIC_C__)\n"
+ "int main(argc, argv)\n"
+ " int argc;\n"
+ " char* argv[];\n"
+ "#else\n"
+ "int main(int argc, char* argv[])\n"
+ "#endif\n"
+ "{ (void)argv; return argc-1;}\n")
+ try_compile(CMAKE_C_COMPILER_WORKS ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testCCompiler.c
+ OUTPUT_VARIABLE __CMAKE_C_COMPILER_OUTPUT)
+ # Move result from cache to normal variable.
+ set(CMAKE_C_COMPILER_WORKS ${CMAKE_C_COMPILER_WORKS})
+ unset(CMAKE_C_COMPILER_WORKS CACHE)
+ __TestCompiler_restoreTryCompileTargetType()
+ if(NOT CMAKE_C_COMPILER_WORKS)
+ PrintTestCompilerResult(CHECK_FAIL "broken")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the C compiler works failed with "
+ "the following output:\n${__CMAKE_C_COMPILER_OUTPUT}\n\n")
+ string(REPLACE "\n" "\n " _output "${__CMAKE_C_COMPILER_OUTPUT}")
+ message(FATAL_ERROR "The C compiler\n \"${CMAKE_C_COMPILER}\"\n"
+ "is not able to compile a simple test program.\nIt fails "
+ "with the following output:\n ${_output}\n\n"
+ "CMake will not be able to correctly generate this project.")
+ endif()
+ PrintTestCompilerResult(CHECK_PASS "works")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the C compiler works passed with "
+ "the following output:\n${__CMAKE_C_COMPILER_OUTPUT}\n\n")
+endif()
+
+# Try to identify the compiler features
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompileFeatures.cmake)
+CMAKE_DETERMINE_COMPILE_FEATURES(C)
+
+# Re-configure to save learned information.
+configure_file(
+ ${CMAKE_ROOT}/Modules/CMakeCCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeCCompiler.cmake
+ @ONLY
+ )
+include(${CMAKE_PLATFORM_INFO_DIR}/CMakeCCompiler.cmake)
+
+if(CMAKE_C_SIZEOF_DATA_PTR)
+ foreach(f ${CMAKE_C_ABI_FILES})
+ include(${f})
+ endforeach()
+ unset(CMAKE_C_ABI_FILES)
+endif()
+
+set(CMAKE_TRY_COMPILE_TARGET_TYPE ${__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE})
+unset(__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE)
+unset(__CMAKE_C_COMPILER_OUTPUT)
diff --git a/Modules/CMakeTestCSharpCompiler.cmake b/Modules/CMakeTestCSharpCompiler.cmake
new file mode 100644
index 0000000..1119a45
--- /dev/null
+++ b/Modules/CMakeTestCSharpCompiler.cmake
@@ -0,0 +1,67 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+if(CMAKE_CSharp_COMPILER_FORCED)
+ # The compiler configuration was forced by the user.
+ # Assume the user has configured all compiler information.
+ set(CMAKE_CSharp_COMPILER_WORKS TRUE)
+ return()
+endif()
+
+include(CMakeTestCompilerCommon)
+
+unset(CMAKE_CSharp_COMPILER_WORKS CACHE)
+
+set(test_compile_file "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testCSharpCompiler.cs")
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that the selected C# compiler can actually compile
+# and link the most basic of programs. If not, a fatal error
+# is set and cmake stops processing commands and will not generate
+# any makefiles or projects.
+if(NOT CMAKE_CSharp_COMPILER_WORKS)
+ # Don't call PrintTestCompilerStatus() because the "C#" we want to pass
+ # as the LANG doesn't match with the variable name "CMAKE_CSharp_COMPILER"
+ message(CHECK_START "Check for working C# compiler: ${CMAKE_CSharp_COMPILER}")
+ file(WRITE "${test_compile_file}"
+ "namespace Test {"
+ " public class CSharp {"
+ " static void Main(string[] args) {}"
+ " }"
+ "}"
+ )
+ try_compile(CMAKE_CSharp_COMPILER_WORKS ${CMAKE_BINARY_DIR} "${test_compile_file}"
+ OUTPUT_VARIABLE __CMAKE_CSharp_COMPILER_OUTPUT
+ )
+ # Move result from cache to normal variable.
+ set(CMAKE_CSharp_COMPILER_WORKS ${CMAKE_CSharp_COMPILER_WORKS})
+ unset(CMAKE_CSharp_COMPILER_WORKS CACHE)
+ set(CSharp_TEST_WAS_RUN 1)
+endif()
+
+if(NOT CMAKE_CSharp_COMPILER_WORKS)
+ PrintTestCompilerResult(CHECK_FAIL "broken")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the C# compiler works failed with "
+ "the following output:\n${__CMAKE_CSharp_COMPILER_OUTPUT}\n\n")
+ string(REPLACE "\n" "\n " _output "${__CMAKE_CSharp_COMPILER_OUTPUT}")
+ message(FATAL_ERROR "The C# compiler\n \"${CMAKE_CSharp_COMPILER}\"\n"
+ "is not able to compile a simple test program.\nIt fails "
+ "with the following output:\n ${_output}\n\n"
+ "CMake will not be able to correctly generate this project.")
+else()
+ if(CSharp_TEST_WAS_RUN)
+ PrintTestCompilerResult(CHECK_PASS "works")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the C# compiler works passed with "
+ "the following output:\n${__CMAKE_CSharp_COMPILER_OUTPUT}\n\n")
+ endif()
+
+ # Re-configure to save learned information.
+ configure_file(
+ ${CMAKE_ROOT}/Modules/CMakeCSharpCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeCSharpCompiler.cmake
+ @ONLY
+ )
+ include(${CMAKE_PLATFORM_INFO_DIR}/CMakeCSharpCompiler.cmake)
+endif()
diff --git a/Modules/CMakeTestCUDACompiler.cmake b/Modules/CMakeTestCUDACompiler.cmake
new file mode 100644
index 0000000..a18947b
--- /dev/null
+++ b/Modules/CMakeTestCUDACompiler.cmake
@@ -0,0 +1,98 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+if(CMAKE_CUDA_COMPILER_FORCED)
+ # The compiler configuration was forced by the user.
+ # Assume the user has configured all compiler information.
+ set(CMAKE_CUDA_COMPILER_WORKS TRUE)
+ return()
+endif()
+
+include(CMakeTestCompilerCommon)
+
+# Remove any cached result from an older CMake version.
+# We now store this in CMakeCUDACompiler.cmake.
+unset(CMAKE_CUDA_COMPILER_WORKS CACHE)
+
+# Try to identify the ABI and configure it into CMakeCUDACompiler.cmake
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
+CMAKE_DETERMINE_COMPILER_ABI(CUDA ${CMAKE_ROOT}/Modules/CMakeCUDACompilerABI.cu)
+if(CMAKE_CUDA_ABI_COMPILED)
+ # The compiler worked so skip dedicated test below.
+ set(CMAKE_CUDA_COMPILER_WORKS TRUE)
+ message(STATUS "Check for working CUDA compiler: ${CMAKE_CUDA_COMPILER} - skipped")
+endif()
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that the selected cuda compiler can actually compile
+# and link the most basic of programs. If not, a fatal error
+# is set and cmake stops processing commands and will not generate
+# any makefiles or projects.
+if(NOT CMAKE_CUDA_COMPILER_WORKS)
+ PrintTestCompilerStatus("CUDA")
+ file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/main.cu
+ "#ifndef __CUDACC__\n"
+ "# error \"The CMAKE_CUDA_COMPILER is set to an invalid CUDA compiler\"\n"
+ "#endif\n"
+ "int main(){return 0;}\n")
+
+ try_compile(CMAKE_CUDA_COMPILER_WORKS ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/main.cu
+ OUTPUT_VARIABLE __CMAKE_CUDA_COMPILER_OUTPUT)
+
+ # Move result from cache to normal variable.
+ set(CMAKE_CUDA_COMPILER_WORKS ${CMAKE_CUDA_COMPILER_WORKS})
+ unset(CMAKE_CUDA_COMPILER_WORKS CACHE)
+ if(NOT CMAKE_CUDA_COMPILER_WORKS)
+ PrintTestCompilerResult(CHECK_FAIL "broken")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the CUDA compiler works failed with "
+ "the following output:\n${__CMAKE_CUDA_COMPILER_OUTPUT}\n\n")
+ string(REPLACE "\n" "\n " _output "${__CMAKE_CUDA_COMPILER_OUTPUT}")
+ message(FATAL_ERROR "The CUDA compiler\n \"${CMAKE_CUDA_COMPILER}\"\n"
+ "is not able to compile a simple test program.\nIt fails "
+ "with the following output:\n ${_output}\n\n"
+ "CMake will not be able to correctly generate this project.")
+ endif()
+ PrintTestCompilerResult(CHECK_PASS "works")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the CUDA compiler works passed with "
+ "the following output:\n${__CMAKE_CUDA_COMPILER_OUTPUT}\n\n")
+endif()
+
+# Try to identify the compiler features
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompileFeatures.cmake)
+CMAKE_DETERMINE_COMPILE_FEATURES(CUDA)
+
+if("x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC")
+ set(CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES "${CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES}")
+ set(CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES "${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES}")
+endif()
+
+# Filter out implicit link libraries that should not be passed unconditionally.
+# See CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES_EXCLUDE in CMakeDetermineCUDACompiler.
+list(REMOVE_ITEM CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES ${CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES_EXCLUDE})
+
+if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
+ # Remove the CUDA Toolkit include directories from the set of
+ # implicit system include directories.
+ # This resolves the issue that NVCC doesn't specify these
+ # includes as SYSTEM includes when compiling device code, and sometimes
+ # they contain headers that generate warnings, so let users mark them
+ # as SYSTEM explicitly
+ if(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES)
+ list(REMOVE_ITEM CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES
+ ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}
+ )
+ endif()
+endif()
+
+# Re-configure to save learned information.
+configure_file(
+ ${CMAKE_ROOT}/Modules/CMakeCUDACompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeCUDACompiler.cmake
+ @ONLY
+ )
+include(${CMAKE_PLATFORM_INFO_DIR}/CMakeCUDACompiler.cmake)
+
+unset(__CMAKE_CUDA_COMPILER_OUTPUT)
diff --git a/Modules/CMakeTestCXXCompiler.cmake b/Modules/CMakeTestCXXCompiler.cmake
new file mode 100644
index 0000000..0d2d0b0
--- /dev/null
+++ b/Modules/CMakeTestCXXCompiler.cmake
@@ -0,0 +1,91 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+if(CMAKE_CXX_COMPILER_FORCED)
+ # The compiler configuration was forced by the user.
+ # Assume the user has configured all compiler information.
+ set(CMAKE_CXX_COMPILER_WORKS TRUE)
+ return()
+endif()
+
+include(CMakeTestCompilerCommon)
+
+# work around enforced code signing and / or missing executable target type
+set(__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE})
+if(_CMAKE_FEATURE_DETECTION_TARGET_TYPE)
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_CMAKE_FEATURE_DETECTION_TARGET_TYPE})
+endif()
+
+# Remove any cached result from an older CMake version.
+# We now store this in CMakeCXXCompiler.cmake.
+unset(CMAKE_CXX_COMPILER_WORKS CACHE)
+
+# Try to identify the ABI and configure it into CMakeCXXCompiler.cmake
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
+CMAKE_DETERMINE_COMPILER_ABI(CXX ${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp)
+if(CMAKE_CXX_ABI_COMPILED)
+ # The compiler worked so skip dedicated test below.
+ set(CMAKE_CXX_COMPILER_WORKS TRUE)
+ message(STATUS "Check for working CXX compiler: ${CMAKE_CXX_COMPILER} - skipped")
+endif()
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that the selected C++ compiler can actually compile
+# and link the most basic of programs. If not, a fatal error
+# is set and cmake stops processing commands and will not generate
+# any makefiles or projects.
+if(NOT CMAKE_CXX_COMPILER_WORKS)
+ PrintTestCompilerStatus("CXX")
+ __TestCompiler_setTryCompileTargetType()
+ file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testCXXCompiler.cxx
+ "#ifndef __cplusplus\n"
+ "# error \"The CMAKE_CXX_COMPILER is set to a C compiler\"\n"
+ "#endif\n"
+ "int main(){return 0;}\n")
+ try_compile(CMAKE_CXX_COMPILER_WORKS ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testCXXCompiler.cxx
+ OUTPUT_VARIABLE __CMAKE_CXX_COMPILER_OUTPUT)
+ # Move result from cache to normal variable.
+ set(CMAKE_CXX_COMPILER_WORKS ${CMAKE_CXX_COMPILER_WORKS})
+ unset(CMAKE_CXX_COMPILER_WORKS CACHE)
+ __TestCompiler_restoreTryCompileTargetType()
+ if(NOT CMAKE_CXX_COMPILER_WORKS)
+ PrintTestCompilerResult(CHECK_FAIL "broken")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the CXX compiler works failed with "
+ "the following output:\n${__CMAKE_CXX_COMPILER_OUTPUT}\n\n")
+ string(REPLACE "\n" "\n " _output "${__CMAKE_CXX_COMPILER_OUTPUT}")
+ message(FATAL_ERROR "The C++ compiler\n \"${CMAKE_CXX_COMPILER}\"\n"
+ "is not able to compile a simple test program.\nIt fails "
+ "with the following output:\n ${_output}\n\n"
+ "CMake will not be able to correctly generate this project.")
+ endif()
+ PrintTestCompilerResult(CHECK_PASS "works")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the CXX compiler works passed with "
+ "the following output:\n${__CMAKE_CXX_COMPILER_OUTPUT}\n\n")
+endif()
+
+# Try to identify the compiler features
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompileFeatures.cmake)
+CMAKE_DETERMINE_COMPILE_FEATURES(CXX)
+
+# Re-configure to save learned information.
+configure_file(
+ ${CMAKE_ROOT}/Modules/CMakeCXXCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeCXXCompiler.cmake
+ @ONLY
+ )
+include(${CMAKE_PLATFORM_INFO_DIR}/CMakeCXXCompiler.cmake)
+
+if(CMAKE_CXX_SIZEOF_DATA_PTR)
+ foreach(f ${CMAKE_CXX_ABI_FILES})
+ include(${f})
+ endforeach()
+ unset(CMAKE_CXX_ABI_FILES)
+endif()
+
+set(CMAKE_TRY_COMPILE_TARGET_TYPE ${__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE})
+unset(__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE)
+unset(__CMAKE_CXX_COMPILER_OUTPUT)
diff --git a/Modules/CMakeTestCompilerCommon.cmake b/Modules/CMakeTestCompilerCommon.cmake
new file mode 100644
index 0000000..da7c007
--- /dev/null
+++ b/Modules/CMakeTestCompilerCommon.cmake
@@ -0,0 +1,34 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+function(PrintTestCompilerStatus LANG)
+ # ARGN shouldn't be needed now, but it is there to preserve backward
+ # compatibility in case this function is called from project code or
+ # custom toolchains (they shouldn't, but we can easily support it)
+ message(CHECK_START "Check for working ${LANG} compiler: ${CMAKE_${LANG}_COMPILER}${ARGN}")
+endfunction()
+
+function(PrintTestCompilerResult TYPE MSG)
+ message(${TYPE} "${MSG}")
+endfunction()
+
+# if required set the target type if not already explicitly set
+macro(__TestCompiler_setTryCompileTargetType)
+ if(NOT CMAKE_TRY_COMPILE_TARGET_TYPE)
+ if("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
+ #prefer static libraries to avoid linking issues
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+ set(__CMAKE_TEST_COMPILER_TARGET_TYPE_RESTORE 1)
+ endif()
+ endif()
+endmacro()
+
+# restore the original value
+# -- not necessary if __TestCompiler_setTryCompileTargetType() was used in function scope
+macro(__TestCompiler_restoreTryCompileTargetType)
+ if(__CMAKE_TEST_COMPILER_TARGET_TYPE_RESTORE)
+ unset(CMAKE_TRY_COMPILE_TARGET_TYPE)
+ unset(__CMAKE_TEST_COMPILER_TARGET_TYPE_RESTORE)
+ endif()
+endmacro()
diff --git a/Modules/CMakeTestFortranCompiler.cmake b/Modules/CMakeTestFortranCompiler.cmake
new file mode 100644
index 0000000..10fb0a7
--- /dev/null
+++ b/Modules/CMakeTestFortranCompiler.cmake
@@ -0,0 +1,102 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+if(CMAKE_Fortran_COMPILER_FORCED)
+ # The compiler configuration was forced by the user.
+ # Assume the user has configured all compiler information.
+ set(CMAKE_Fortran_COMPILER_WORKS TRUE)
+ return()
+endif()
+
+include(CMakeTestCompilerCommon)
+
+# Remove any cached result from an older CMake version.
+# We now store this in CMakeFortranCompiler.cmake.
+unset(CMAKE_Fortran_COMPILER_WORKS CACHE)
+
+# Try to identify the ABI and configure it into CMakeFortranCompiler.cmake
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
+CMAKE_DETERMINE_COMPILER_ABI(Fortran ${CMAKE_ROOT}/Modules/CMakeFortranCompilerABI.F)
+if(CMAKE_Fortran_ABI_COMPILED)
+ # The compiler worked so skip dedicated test below.
+ set(CMAKE_Fortran_COMPILER_WORKS TRUE)
+ message(STATUS "Check for working Fortran compiler: ${CMAKE_Fortran_COMPILER} - skipped")
+endif()
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that the selected Fortran compiler can actually compile
+# and link the most basic of programs. If not, a fatal error
+# is set and cmake stops processing commands and will not generate
+# any makefiles or projects.
+if(NOT CMAKE_Fortran_COMPILER_WORKS)
+ PrintTestCompilerStatus("Fortran")
+ file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompiler.f "
+ PROGRAM TESTFortran
+ PRINT *, 'Hello'
+ END
+ ")
+ try_compile(CMAKE_Fortran_COMPILER_WORKS ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompiler.f
+ OUTPUT_VARIABLE OUTPUT)
+ # Move result from cache to normal variable.
+ set(CMAKE_Fortran_COMPILER_WORKS ${CMAKE_Fortran_COMPILER_WORKS})
+ unset(CMAKE_Fortran_COMPILER_WORKS CACHE)
+ if(NOT CMAKE_Fortran_COMPILER_WORKS)
+ PrintTestCompilerResult(CHECK_FAIL "broken")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the Fortran compiler works failed with "
+ "the following output:\n${OUTPUT}\n\n")
+ string(REPLACE "\n" "\n " _output "${OUTPUT}")
+ message(FATAL_ERROR "The Fortran compiler\n \"${CMAKE_Fortran_COMPILER}\"\n"
+ "is not able to compile a simple test program.\nIt fails "
+ "with the following output:\n ${_output}\n\n"
+ "CMake will not be able to correctly generate this project.")
+ endif()
+ PrintTestCompilerResult(CHECK_PASS "works")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the Fortran compiler works passed with "
+ "the following output:\n${OUTPUT}\n\n")
+endif()
+
+# Test for Fortran 90 support by using an f90-specific construct.
+if(NOT DEFINED CMAKE_Fortran_COMPILER_SUPPORTS_F90)
+ message(CHECK_START "Checking whether ${CMAKE_Fortran_COMPILER} supports Fortran 90")
+ file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompilerF90.f90 "
+ PROGRAM TESTFortran90
+ integer stop ; stop = 1 ; do while ( stop .eq. 0 ) ; end do
+ END PROGRAM TESTFortran90
+")
+ try_compile(CMAKE_Fortran_COMPILER_SUPPORTS_F90 ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompilerF90.f90
+ OUTPUT_VARIABLE OUTPUT)
+ if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
+ message(CHECK_PASS "yes")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the Fortran compiler supports Fortran 90 passed with "
+ "the following output:\n${OUTPUT}\n\n")
+ set(CMAKE_Fortran_COMPILER_SUPPORTS_F90 1)
+ else()
+ message(CHECK_FAIL "no")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the Fortran compiler supports Fortran 90 failed with "
+ "the following output:\n${OUTPUT}\n\n")
+ set(CMAKE_Fortran_COMPILER_SUPPORTS_F90 0)
+ endif()
+ unset(CMAKE_Fortran_COMPILER_SUPPORTS_F90 CACHE)
+endif()
+
+# Re-configure to save learned information.
+configure_file(
+ ${CMAKE_ROOT}/Modules/CMakeFortranCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeFortranCompiler.cmake
+ @ONLY
+ )
+include(${CMAKE_PLATFORM_INFO_DIR}/CMakeFortranCompiler.cmake)
+
+if(CMAKE_Fortran_SIZEOF_DATA_PTR)
+ foreach(f ${CMAKE_Fortran_ABI_FILES})
+ include(${f})
+ endforeach()
+ unset(CMAKE_Fortran_ABI_FILES)
+endif()
diff --git a/Modules/CMakeTestGNU.c b/Modules/CMakeTestGNU.c
new file mode 100644
index 0000000..7dcafde
--- /dev/null
+++ b/Modules/CMakeTestGNU.c
@@ -0,0 +1,10 @@
+#if defined(__GNUC__) && \
+ !(defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER))
+void THIS_IS_GNU();
+#endif
+#ifdef __MINGW32__
+void THIS_IS_MINGW();
+#endif
+#ifdef __CYGWIN__
+void THIS_IS_CYGWIN();
+#endif
diff --git a/Modules/CMakeTestISPCCompiler.cmake b/Modules/CMakeTestISPCCompiler.cmake
new file mode 100644
index 0000000..6b16393
--- /dev/null
+++ b/Modules/CMakeTestISPCCompiler.cmake
@@ -0,0 +1,43 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+
+if(CMAKE_ISPC_COMPILER_FORCED)
+ # The compiler configuration was forced by the user.
+ # Assume the user has configured all compiler information.
+ set(CMAKE_ISPC_COMPILER_WORKS TRUE)
+ return()
+endif()
+
+include(CMakeTestCompilerCommon)
+
+# Make sure we try to compile as a STATIC_LIBRARY
+set(__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE})
+set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+
+# # Try to identify the ABI and configure it into CMakeISPCCompiler.cmake
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
+CMAKE_DETERMINE_COMPILER_ABI(ISPC ${CMAKE_ROOT}/Modules/CMakeISPCCompilerABI.ispc)
+if(CMAKE_ISPC_ABI_COMPILED)
+# # The compiler worked so skip dedicated test below.
+ set(CMAKE_ISPC_COMPILER_WORKS TRUE)
+ message(STATUS "Check for working ISPC compiler: ${CMAKE_ISPC_COMPILER} - skipped")
+endif()
+
+# Re-configure to save learned information.
+configure_file(
+ ${CMAKE_ROOT}/Modules/CMakeISPCCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeISPCCompiler.cmake
+ @ONLY
+ )
+include(${CMAKE_PLATFORM_INFO_DIR}/CMakeISPCCompiler.cmake)
+
+if(CMAKE_ISPC_SIZEOF_DATA_PTR)
+ foreach(f ${CMAKE_ISPC_ABI_FILES})
+ include(${f})
+ endforeach()
+ unset(CMAKE_ISPC_ABI_FILES)
+endif()
+
+set(CMAKE_TRY_COMPILE_TARGET_TYPE ${__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE})
diff --git a/Modules/CMakeTestJavaCompiler.cmake b/Modules/CMakeTestJavaCompiler.cmake
new file mode 100644
index 0000000..3c33573
--- /dev/null
+++ b/Modules/CMakeTestJavaCompiler.cmake
@@ -0,0 +1,10 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that the selected Fortran compiler can actually compile
+# and link the most basic of programs. If not, a fatal error
+# is set and cmake stops processing commands and will not generate
+# any makefiles or projects.
+set(CMAKE_Java_COMPILER_WORKS 1 CACHE INTERNAL "")
diff --git a/Modules/CMakeTestOBJCCompiler.cmake b/Modules/CMakeTestOBJCCompiler.cmake
new file mode 100644
index 0000000..298272b
--- /dev/null
+++ b/Modules/CMakeTestOBJCCompiler.cmake
@@ -0,0 +1,95 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+if(CMAKE_OBJC_COMPILER_FORCED)
+ # The compiler configuration was forced by the user.
+ # Assume the user has configured all compiler information.
+ set(CMAKE_OBJC_COMPILER_WORKS TRUE)
+ return()
+endif()
+
+include(CMakeTestCompilerCommon)
+
+# work around enforced code signing and / or missing executable target type
+set(__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE})
+if(_CMAKE_FEATURE_DETECTION_TARGET_TYPE)
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_CMAKE_FEATURE_DETECTION_TARGET_TYPE})
+endif()
+
+# Remove any cached result from an older CMake version.
+# We now store this in CMakeCCompiler.cmake.
+unset(CMAKE_OBJC_COMPILER_WORKS CACHE)
+
+# Try to identify the ABI and configure it into CMakeOBJCCompiler.cmake
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
+CMAKE_DETERMINE_COMPILER_ABI(OBJC ${CMAKE_ROOT}/Modules/CMakeOBJCCompilerABI.m)
+if(CMAKE_OBJC_ABI_COMPILED)
+ # The compiler worked so skip dedicated test below.
+ set(CMAKE_OBJC_COMPILER_WORKS TRUE)
+ message(STATUS "Check for working OBJC compiler: ${CMAKE_OBJC_COMPILER} - skipped")
+endif()
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that that selected Objective-C compiler can actually compile
+# and link the most basic of programs. If not, a fatal error
+# is set and cmake stops processing commands and will not generate
+# any makefiles or projects.
+if(NOT CMAKE_OBJC_COMPILER_WORKS)
+ PrintTestCompilerStatus("OBJC")
+ __TestCompiler_setTryCompileTargetType()
+ file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testOBJCCompiler.m
+ "#ifdef __cplusplus\n"
+ "# error \"The CMAKE_OBJC_COMPILER is set to a C++ compiler\"\n"
+ "#endif\n"
+ "#ifndef __OBJC__\n"
+ "# error \"The CMAKE_OBJC_COMPILER is not an Objective-C compiler\"\n"
+ "#endif\n"
+ "int main(int argc, char* argv[])\n"
+ "{ (void)argv; return argc-1;}\n")
+ try_compile(CMAKE_OBJC_COMPILER_WORKS ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testOBJCCompiler.m
+ OUTPUT_VARIABLE __CMAKE_OBJC_COMPILER_OUTPUT)
+ # Move result from cache to normal variable.
+ set(CMAKE_OBJC_COMPILER_WORKS ${CMAKE_OBJC_COMPILER_WORKS})
+ unset(CMAKE_OBJC_COMPILER_WORKS CACHE)
+ __TestCompiler_restoreTryCompileTargetType()
+ if(NOT CMAKE_OBJC_COMPILER_WORKS)
+ PrintTestCompilerResult(CHECK_FAIL "broken")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the Objective-C compiler works failed with "
+ "the following output:\n${__CMAKE_OBJC_COMPILER_OUTPUT}\n\n")
+ string(REPLACE "\n" "\n " _output "${__CMAKE_OBJC_COMPILER_OUTPUT}")
+ message(FATAL_ERROR "The Objective-C compiler\n \"${CMAKE_OBJC_COMPILER}\"\n"
+ "is not able to compile a simple test program.\nIt fails "
+ "with the following output:\n ${_output}\n\n"
+ "CMake will not be able to correctly generate this project.")
+ endif()
+ PrintTestCompilerResult(CHECK_PASS "works")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the Objective-C compiler works passed with "
+ "the following output:\n${__CMAKE_OBJC_COMPILER_OUTPUT}\n\n")
+endif()
+
+# Try to identify the compiler features
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompileFeatures.cmake)
+CMAKE_DETERMINE_COMPILE_FEATURES(OBJC)
+
+# Re-configure to save learned information.
+configure_file(
+ ${CMAKE_ROOT}/Modules/CMakeOBJCCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeOBJCCompiler.cmake
+ @ONLY
+ )
+include(${CMAKE_PLATFORM_INFO_DIR}/CMakeOBJCCompiler.cmake)
+
+if(CMAKE_OBJC_SIZEOF_DATA_PTR)
+ foreach(f ${CMAKE_OBJC_ABI_FILES})
+ include(${f})
+ endforeach()
+ unset(CMAKE_OBJC_ABI_FILES)
+endif()
+
+set(CMAKE_TRY_COMPILE_TARGET_TYPE ${__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE})
+unset(__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE)
+unset(__CMAKE_OBJC_COMPILER_OUTPUT)
diff --git a/Modules/CMakeTestOBJCXXCompiler.cmake b/Modules/CMakeTestOBJCXXCompiler.cmake
new file mode 100644
index 0000000..36e3efc
--- /dev/null
+++ b/Modules/CMakeTestOBJCXXCompiler.cmake
@@ -0,0 +1,94 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+if(CMAKE_OBJCXX_COMPILER_FORCED)
+ # The compiler configuration was forced by the user.
+ # Assume the user has configured all compiler information.
+ set(CMAKE_OBJCXX_COMPILER_WORKS TRUE)
+ return()
+endif()
+
+include(CMakeTestCompilerCommon)
+
+# work around enforced code signing and / or missing executable target type
+set(__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE})
+if(_CMAKE_FEATURE_DETECTION_TARGET_TYPE)
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_CMAKE_FEATURE_DETECTION_TARGET_TYPE})
+endif()
+
+# Remove any cached result from an older CMake version.
+# We now store this in CMakeOBJCXXCompiler.cmake.
+unset(CMAKE_OBJCXX_COMPILER_WORKS CACHE)
+
+# Try to identify the ABI and configure it into CMakeOBJCXXCompiler.cmake
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
+CMAKE_DETERMINE_COMPILER_ABI(OBJCXX ${CMAKE_ROOT}/Modules/CMakeOBJCXXCompilerABI.mm)
+if(CMAKE_OBJCXX_ABI_COMPILED)
+ # The compiler worked so skip dedicated test below.
+ set(CMAKE_OBJCXX_COMPILER_WORKS TRUE)
+ message(STATUS "Check for working OBJCXX compiler: ${CMAKE_OBJCXX_COMPILER} - skipped")
+endif()
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that the selected Objective-C++ compiler can actually compile
+# and link the most basic of programs. If not, a fatal error
+# is set and cmake stops processing commands and will not generate
+# any makefiles or projects.
+if(NOT CMAKE_OBJCXX_COMPILER_WORKS)
+ PrintTestCompilerStatus("OBJCXX")
+ __TestCompiler_setTryCompileTargetType()
+ file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testOBJCXXCompiler.mm
+ "#ifndef __cplusplus\n"
+ "# error \"The CMAKE_OBJCXX_COMPILER is set to a C compiler\"\n"
+ "#endif\n"
+ "#ifndef __OBJC__\n"
+ "# error \"The CMAKE_OBJCXX_COMPILER is not an Objective-C++ compiler\"\n"
+ "#endif\n"
+ "int main(){return 0;}\n")
+ try_compile(CMAKE_OBJCXX_COMPILER_WORKS ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testOBJCXXCompiler.mm
+ OUTPUT_VARIABLE __CMAKE_OBJCXX_COMPILER_OUTPUT)
+ # Move result from cache to normal variable.
+ set(CMAKE_OBJCXX_COMPILER_WORKS ${CMAKE_OBJCXX_COMPILER_WORKS})
+ unset(CMAKE_OBJCXX_COMPILER_WORKS CACHE)
+ __TestCompiler_restoreTryCompileTargetType()
+ if(NOT CMAKE_OBJCXX_COMPILER_WORKS)
+ PrintTestCompilerResult(CHECK_FAIL "broken")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the Objective-C++ compiler works failed with "
+ "the following output:\n${__CMAKE_OBJCXX_COMPILER_OUTPUT}\n\n")
+ string(REPLACE "\n" "\n " _output "${__CMAKE_OBJCXX_COMPILER_OUTPUT}")
+ message(FATAL_ERROR "The Objective-C++ compiler\n \"${CMAKE_OBJCXX_COMPILER}\"\n"
+ "is not able to compile a simple test program.\nIt fails "
+ "with the following output:\n ${_output}\n\n"
+ "CMake will not be able to correctly generate this project.")
+ endif()
+ PrintTestCompilerResult(CHECK_PASS "works")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the Objective-C++ compiler works passed with "
+ "the following output:\n${__CMAKE_OBJCXX_COMPILER_OUTPUT}\n\n")
+endif()
+
+# Try to identify the compiler features
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompileFeatures.cmake)
+CMAKE_DETERMINE_COMPILE_FEATURES(OBJCXX)
+
+# Re-configure to save learned information.
+configure_file(
+ ${CMAKE_ROOT}/Modules/CMakeOBJCXXCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeOBJCXXCompiler.cmake
+ @ONLY
+ )
+include(${CMAKE_PLATFORM_INFO_DIR}/CMakeOBJCXXCompiler.cmake)
+
+if(CMAKE_OBJCXX_SIZEOF_DATA_PTR)
+ foreach(f ${CMAKE_OBJCXX_ABI_FILES})
+ include(${f})
+ endforeach()
+ unset(CMAKE_OBJCXX_ABI_FILES)
+endif()
+
+set(CMAKE_TRY_COMPILE_TARGET_TYPE ${__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE})
+unset(__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE)
+unset(__CMAKE_OBJCXX_COMPILER_OUTPUT)
diff --git a/Modules/CMakeTestRCCompiler.cmake b/Modules/CMakeTestRCCompiler.cmake
new file mode 100644
index 0000000..3123a6c
--- /dev/null
+++ b/Modules/CMakeTestRCCompiler.cmake
@@ -0,0 +1,13 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that the selected RC compiler can actually compile
+# and link the most basic of programs. If not, a fatal error
+# is set and cmake stops processing commands and will not generate
+# any makefiles or projects.
+
+# For now there is no way to do a try compile on just a .rc file
+# so just do nothing in here.
+set(CMAKE_RC_COMPILER_WORKS 1 CACHE INTERNAL "")
diff --git a/Modules/CMakeTestSwiftCompiler.cmake b/Modules/CMakeTestSwiftCompiler.cmake
new file mode 100644
index 0000000..d98dc9d
--- /dev/null
+++ b/Modules/CMakeTestSwiftCompiler.cmake
@@ -0,0 +1,64 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+if(CMAKE_Swift_COMPILER_FORCED)
+ # The compiler configuration was forced by the user.
+ # Assume the user has configured all compiler information.
+ set(CMAKE_Swift_COMPILER_WORKS TRUE)
+ return()
+endif()
+
+include(CMakeTestCompilerCommon)
+
+# Remove any cached result from an older CMake version.
+# We now store this in CMakeSwiftCompiler.cmake.
+unset(CMAKE_Swift_COMPILER_WORKS CACHE)
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that the selected C++ compiler can actually compile
+# and link the most basic of programs. If not, a fatal error
+# is set and cmake stops processing commands and will not generate
+# any makefiles or projects.
+if(NOT CMAKE_Swift_COMPILER_WORKS)
+ PrintTestCompilerStatus("Swift")
+ file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/main.swift
+ "print(\"CMake\")\n")
+ try_compile(CMAKE_Swift_COMPILER_WORKS ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/main.swift
+ OUTPUT_VARIABLE __CMAKE_Swift_COMPILER_OUTPUT)
+ # Move result from cache to normal variable.
+ set(CMAKE_Swift_COMPILER_WORKS ${CMAKE_Swift_COMPILER_WORKS})
+ unset(CMAKE_Swift_COMPILER_WORKS CACHE)
+ set(Swift_TEST_WAS_RUN 1)
+endif()
+
+if(NOT CMAKE_Swift_COMPILER_WORKS)
+ PrintTestCompilerResult(CHECK_FAIL "broken")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the Swift compiler works failed with "
+ "the following output:\n${__CMAKE_Swift_COMPILER_OUTPUT}\n\n")
+ string(REPLACE "\n" "\n " _output "${__CMAKE_Swift_COMPILER_OUTPUT}")
+ message(FATAL_ERROR "The Swift compiler\n \"${CMAKE_Swift_COMPILER}\"\n"
+ "is not able to compile a simple test program.\nIt fails "
+ "with the following output:\n ${_output}\n\n"
+ "CMake will not be able to correctly generate this project.")
+else()
+ if(Swift_TEST_WAS_RUN)
+ PrintTestCompilerResult(CHECK_PASS "works")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the Swift compiler works passed with "
+ "the following output:\n${__CMAKE_Swift_COMPILER_OUTPUT}\n\n")
+ endif()
+
+ # Unlike C and CXX we do not yet detect any information about the Swift ABI.
+ # However, one of the steps done for C and CXX as part of that detection is
+ # to initialize the implicit include directories. That is relevant here.
+ set(CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES "${_CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES_INIT}")
+
+ # Re-configure to save learned information.
+ configure_file(${CMAKE_ROOT}/Modules/CMakeSwiftCompiler.cmake.in
+ ${CMAKE_PLATFORM_INFO_DIR}/CMakeSwiftCompiler.cmake @ONLY)
+ include(${CMAKE_PLATFORM_INFO_DIR}/CMakeSwiftCompiler.cmake)
+endif()
+
+unset(__CMAKE_Swift_COMPILER_OUTPUT)
diff --git a/Modules/CMakeUnixFindMake.cmake b/Modules/CMakeUnixFindMake.cmake
new file mode 100644
index 0000000..1165656
--- /dev/null
+++ b/Modules/CMakeUnixFindMake.cmake
@@ -0,0 +1,16 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+find_program(CMAKE_MAKE_PROGRAM NAMES gmake make smake)
+mark_as_advanced(CMAKE_MAKE_PROGRAM)
+
+# Look for a make tool provided by Xcode
+if(NOT CMAKE_MAKE_PROGRAM AND CMAKE_HOST_APPLE)
+ execute_process(COMMAND xcrun --find make
+ OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE _xcrun_err)
+ if(_xcrun_out)
+ set_property(CACHE CMAKE_MAKE_PROGRAM PROPERTY VALUE "${_xcrun_out}")
+ endif()
+endif()
diff --git a/Modules/CMakeVerifyManifest.cmake b/Modules/CMakeVerifyManifest.cmake
new file mode 100644
index 0000000..705ef8a
--- /dev/null
+++ b/Modules/CMakeVerifyManifest.cmake
@@ -0,0 +1,110 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CMakeVerifyManifest
+-------------------
+
+
+
+CMakeVerifyManifest.cmake
+
+This script is used to verify that embedded manifests and side by side
+manifests for a project match. To run this script, cd to a directory
+and run the script with cmake -P. On the command line you can pass in
+versions that are OK even if not found in the .manifest files. For
+example, cmake -Dallow_versions=8.0.50608.0
+-PCmakeVerifyManifest.cmake could be used to allow an embedded manifest
+of 8.0.50608.0 to be used in a project even if that version was not
+found in the .manifest file.
+#]=======================================================================]
+
+# This script first recursively globs *.manifest files from
+# the current directory. Then globs *.exe and *.dll. Each
+# .exe and .dll is scanned for embedded manifests and the versions
+# of CRT are compared to those found in the .manifest files
+# from the first glob.
+
+# crt_version:
+# function to extract the CRT version from a file
+# this can be passed a .exe, .dll, or a .manifest file
+# it will put the list of versions found into the variable
+# specified by list_var
+function(crt_version file list_var)
+ file(STRINGS "${file}" strings REGEX "Microsoft.VC...CRT" NEWLINE_CONSUME)
+ foreach(s ${strings})
+ set(has_match 1)
+ string(REGEX
+ REPLACE ".*<assembly.*\"Microsoft.VC...CRT\".*version=\"([^\"]*)\".*</assembly>.*$" "\\1"
+ version "${s}")
+ if(NOT "${version}" STREQUAL "")
+ list(APPEND version_list ${version})
+ else()
+ message(FATAL_ERROR "Parse error could not find version in [${s}]")
+ endif()
+ endforeach()
+ if(NOT DEFINED has_match)
+ message("Information: no embedded manifest in: ${file}")
+ return()
+ endif()
+ list(APPEND version_list ${${list_var}})
+ list(REMOVE_DUPLICATES version_list)
+ if(version_list)
+ set(${list_var} ${version_list} PARENT_SCOPE)
+ endif()
+endfunction()
+set(fatal_error FALSE)
+
+# check_version:
+#
+# test a file against the shipped manifest versions
+# for a directory
+function(check_version file manifest_versions)
+ set(manifest_versions ${manifest_versions} ${allow_versions})
+ # collect versions for a given file
+ crt_version(${file} file_versions)
+ # see if the versions
+ foreach(ver ${file_versions})
+ list(FIND manifest_versions "${ver}" found_version)
+ if("${found_version}" EQUAL -1)
+ message("ERROR: ${file} uses ${ver} not found in shipped manifests:[${manifest_versions}].")
+ set(fatal_error TRUE PARENT_SCOPE)
+ endif()
+ endforeach()
+ list(LENGTH file_versions len)
+ if(${len} GREATER 1)
+ message("WARNING: found more than one version of MICROSOFT.VC80.CRT referenced in ${file}: [${file_versions}]")
+ endif()
+endfunction()
+
+# collect up the versions of CRT that are shipped
+# in .manifest files
+set(manifest_version_list )
+file(GLOB_RECURSE manifest_files "*.manifest")
+foreach(f ${manifest_files})
+ crt_version("${f}" manifest_version_list)
+endforeach()
+list(LENGTH manifest_version_list LEN)
+if(LEN EQUAL 0)
+ message(FATAL_ERROR "No .manifest files found, no version check can be done.")
+endif()
+message("Versions found in ${manifest_files}: ${manifest_version_list}")
+if(DEFINED allow_versions)
+ message("Extra versions allowed: ${allow_versions}")
+endif()
+
+# now find all .exe and .dll files
+# and call check_version on each of them
+file(GLOB_RECURSE exe_files "*.exe")
+file(GLOB_RECURSE dll_files "*.dll")
+set(exe_files ${exe_files} ${dll_files})
+foreach(f ${exe_files})
+ check_version(${f} "${manifest_version_list}")
+endforeach()
+
+# report a fatal error if there were any so that cmake will return
+# a non zero value
+if(fatal_error)
+ message(FATAL_ERROR "This distribution embeds dll "
+ " versions that it does not ship, and may not work on other machines.")
+endif()
diff --git a/Modules/CPack.cmake b/Modules/CPack.cmake
new file mode 100644
index 0000000..ef5a7d5
--- /dev/null
+++ b/Modules/CPack.cmake
@@ -0,0 +1,875 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CPack
+-----
+
+Configure generators for binary installers and source packages.
+
+Introduction
+^^^^^^^^^^^^
+
+The CPack module generates the configuration files ``CPackConfig.cmake``
+and ``CPackSourceConfig.cmake``. They are intended for use in a subsequent
+run of the :manual:`cpack <cpack(1)>` program where they steer the generation
+of installers or/and source packages.
+
+Depending on the CMake generator, the CPack module may also add two new build
+targets, ``package`` and ``package_source``. See the `packaging targets`_
+section below for details.
+
+The generated binary installers will contain all files that have been installed
+via CMake's :command:`install` command (and the deprecated commands
+:command:`install_files`, :command:`install_programs`, and
+:command:`install_targets`). Note that the ``DESTINATION`` option of the
+:command:`install` command must be a relative path; otherwise installed files
+are ignored by CPack.
+
+Certain kinds of binary installers can be configured such that users can select
+individual application components to install. See the :module:`CPackComponent`
+module for further details.
+
+Source packages (configured through ``CPackSourceConfig.cmake`` and generated
+by the :cpack_gen:`CPack Archive Generator`) will contain all source files in
+the project directory except those specified in
+:variable:`CPACK_SOURCE_IGNORE_FILES`.
+
+CPack Generators
+^^^^^^^^^^^^^^^^
+
+The :variable:`CPACK_GENERATOR` variable has different meanings in different
+contexts. In a ``CMakeLists.txt`` file, :variable:`CPACK_GENERATOR` is a
+*list of generators*: and when :manual:`cpack <cpack(1)>` is run with no other
+arguments, it will iterate over that list and produce one package for each
+generator. In a :variable:`CPACK_PROJECT_CONFIG_FILE`,
+:variable:`CPACK_GENERATOR` is a *string naming a single generator*. If you
+need per-cpack-generator logic to control *other* cpack settings, then you
+need a :variable:`CPACK_PROJECT_CONFIG_FILE`.
+If set, the :variable:`CPACK_PROJECT_CONFIG_FILE` is included automatically
+on a per-generator basis. It only need contain overrides.
+
+Here's how it works:
+
+* :manual:`cpack <cpack(1)>` runs
+* it includes ``CPackConfig.cmake``
+* it iterates over the generators given by the ``-G`` command line option,
+ or if no such option was specified, over the list of generators given by
+ the :variable:`CPACK_GENERATOR` variable set in the ``CPackConfig.cmake``
+ input file.
+* foreach generator, it then
+
+ - sets :variable:`CPACK_GENERATOR` to the one currently being iterated
+ - includes the :variable:`CPACK_PROJECT_CONFIG_FILE`
+ - produces the package for that generator
+
+This is the key: For each generator listed in :variable:`CPACK_GENERATOR` in
+``CPackConfig.cmake``, cpack will *reset* :variable:`CPACK_GENERATOR`
+internally to *the one currently being used* and then include the
+:variable:`CPACK_PROJECT_CONFIG_FILE`.
+
+For a list of available generators, see :manual:`cpack-generators(7)`.
+
+.. _`packaging targets`:
+
+Targets package and package_source
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If CMake is run with the Makefile, Ninja, or Xcode generator, then
+``include(CPack)`` generates a target ``package``. This makes it possible
+to build a binary installer from CMake, Make, or Ninja: Instead of ``cpack``,
+one may call ``cmake --build . --target package`` or ``make package`` or
+``ninja package``. The VS generator creates an uppercase target ``PACKAGE``.
+
+If CMake is run with the Makefile or Ninja generator, then ``include(CPack)``
+also generates a target ``package_source``. To build a source package,
+instead of ``cpack -G TGZ --config CPackSourceConfig.cmake`` one may call
+``cmake --build . --target package_source``, ``make package_source``,
+or ``ninja package_source``.
+
+
+Variables common to all CPack Generators
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Before including this CPack module in your ``CMakeLists.txt`` file, there
+are a variety of variables that can be set to customize the resulting
+installers. The most commonly-used variables are:
+
+.. variable:: CPACK_PACKAGE_NAME
+
+ The name of the package (or application). If not specified, it defaults to
+ the project name.
+
+.. variable:: CPACK_PACKAGE_VENDOR
+
+ The name of the package vendor. (e.g., "Kitware"). The default is "Humanity".
+
+.. variable:: CPACK_PACKAGE_DIRECTORY
+
+ The directory in which CPack is doing its packaging. If it is not set
+ then this will default (internally) to the build dir. This variable may
+ be defined in a CPack config file or from the :manual:`cpack <cpack(1)>`
+ command line option ``-B``. If set, the command line option overrides the
+ value found in the config file.
+
+.. variable:: CPACK_PACKAGE_VERSION_MAJOR
+
+ Package major version. This variable will always be set, but its default
+ value depends on whether or not version details were given to the
+ :command:`project` command in the top level CMakeLists.txt file. If version
+ details were given, the default value will be
+ :variable:`CMAKE_PROJECT_VERSION_MAJOR`. If no version details were given,
+ a default version of 0.1.1 will be assumed, leading to
+ ``CPACK_PACKAGE_VERSION_MAJOR`` having a default value of 0.
+
+.. variable:: CPACK_PACKAGE_VERSION_MINOR
+
+ Package minor version. The default value is determined based on whether or
+ not version details were given to the :command:`project` command in the top
+ level CMakeLists.txt file. If version details were given, the default
+ value will be :variable:`CMAKE_PROJECT_VERSION_MINOR`, but if no minor
+ version component was specified then ``CPACK_PACKAGE_VERSION_MINOR`` will be
+ left unset. If no project version was given at all, a default version of
+ 0.1.1 will be assumed, leading to ``CPACK_PACKAGE_VERSION_MINOR`` having a
+ default value of 1.
+
+.. variable:: CPACK_PACKAGE_VERSION_PATCH
+
+ Package patch version. The default value is determined based on whether or
+ not version details were given to the :command:`project` command in the top
+ level CMakeLists.txt file. If version details were given, the default
+ value will be :variable:`CMAKE_PROJECT_VERSION_PATCH`, but if no patch
+ version component was specified then ``CPACK_PACKAGE_VERSION_PATCH`` will be
+ left unset. If no project version was given at all, a default version of
+ 0.1.1 will be assumed, leading to ``CPACK_PACKAGE_VERSION_PATCH`` having a
+ default value of 1.
+
+.. variable:: CPACK_PACKAGE_DESCRIPTION
+
+ A description of the project, used in places such as the introduction
+ screen of CPack-generated Windows installers. If not set, the value of
+ this variable is populated from the file named by
+ :variable:`CPACK_PACKAGE_DESCRIPTION_FILE`.
+
+.. variable:: CPACK_PACKAGE_DESCRIPTION_FILE
+
+ A text file used to describe the project when
+ :variable:`CPACK_PACKAGE_DESCRIPTION` is not explicitly set. The default
+ value for ``CPACK_PACKAGE_DESCRIPTION_FILE`` points to a built-in template
+ file ``Templates/CPack.GenericDescription.txt``.
+
+.. variable:: CPACK_PACKAGE_DESCRIPTION_SUMMARY
+
+ Short description of the project (only a few words). If the
+ :variable:`CMAKE_PROJECT_DESCRIPTION` variable is set, it is used as the
+ default value, otherwise the default will be a string generated by CMake
+ based on :variable:`CMAKE_PROJECT_NAME`.
+
+.. variable:: CPACK_PACKAGE_HOMEPAGE_URL
+
+ Project homepage URL. The default value is taken from the
+ :variable:`CMAKE_PROJECT_HOMEPAGE_URL` variable, which is set by the top
+ level :command:`project` command, or else the default will be empty if no
+ URL was provided to :command:`project`.
+
+.. variable:: CPACK_PACKAGE_FILE_NAME
+
+ The name of the package file to generate, not including the
+ extension. For example, ``cmake-2.6.1-Linux-i686``. The default value
+ is::
+
+ ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_SYSTEM_NAME}
+
+.. variable:: CPACK_PACKAGE_INSTALL_DIRECTORY
+
+ Installation directory on the target system. This may be used by some
+ CPack generators like NSIS to create an installation directory e.g.,
+ "CMake 2.5" below the installation prefix. All installed elements will be
+ put inside this directory.
+
+.. variable:: CPACK_PACKAGE_ICON
+
+ A branding image that will be displayed inside the installer (used by GUI
+ installers).
+
+.. variable:: CPACK_PACKAGE_CHECKSUM
+
+ .. versionadded:: 3.7
+
+ An algorithm that will be used to generate an additional file with the
+ checksum of the package. The output file name will be::
+
+ ${CPACK_PACKAGE_FILE_NAME}.${CPACK_PACKAGE_CHECKSUM}
+
+ Supported algorithms are those listed by the
+ :ref:`string(\<HASH\>) <Supported Hash Algorithms>` command.
+
+.. variable:: CPACK_PROJECT_CONFIG_FILE
+
+ CPack-time project CPack configuration file. This file is included at cpack
+ time, once per generator after CPack has set :variable:`CPACK_GENERATOR`
+ to the actual generator being used. It allows per-generator setting of
+ ``CPACK_*`` variables at cpack time.
+
+.. variable:: CPACK_RESOURCE_FILE_LICENSE
+
+ License to be embedded in the installer. It will typically be displayed
+ to the user by the produced installer (often with an explicit "Accept"
+ button, for graphical installers) prior to installation. This license
+ file is NOT added to the installed files but is used by some CPack generators
+ like NSIS. If you want to install a license file (may be the same as this
+ one) along with your project, you must add an appropriate CMake
+ :command:`install` command in your ``CMakeLists.txt``.
+
+.. variable:: CPACK_RESOURCE_FILE_README
+
+ ReadMe file to be embedded in the installer. It typically describes in
+ some detail the purpose of the project during the installation. Not all
+ CPack generators use this file.
+
+.. variable:: CPACK_RESOURCE_FILE_WELCOME
+
+ Welcome file to be embedded in the installer. It welcomes users to this
+ installer. Typically used in the graphical installers on Windows and Mac
+ OS X.
+
+.. variable:: CPACK_MONOLITHIC_INSTALL
+
+ Disables the component-based installation mechanism. When set, the
+ component specification is ignored and all installed items are put in a
+ single "MONOLITHIC" package. Some CPack generators do monolithic
+ packaging by default and may be asked to do component packaging by
+ setting ``CPACK_<GENNAME>_COMPONENT_INSTALL`` to ``TRUE``.
+
+.. variable:: CPACK_GENERATOR
+
+ List of CPack generators to use. If not specified, CPack will create a
+ set of options following the naming pattern
+ :variable:`CPACK_BINARY_<GENNAME>` (e.g. ``CPACK_BINARY_NSIS``) allowing
+ the user to enable/disable individual generators. If the ``-G`` option is
+ given on the :manual:`cpack <cpack(1)>` command line, it will override this
+ variable and any ``CPACK_BINARY_<GENNAME>`` options.
+
+.. variable:: CPACK_OUTPUT_CONFIG_FILE
+
+ The name of the CPack binary configuration file. This file is the CPack
+ configuration generated by the CPack module for binary installers.
+ Defaults to ``CPackConfig.cmake``.
+
+.. variable:: CPACK_PACKAGE_EXECUTABLES
+
+ Lists each of the executables and associated text label to be used to
+ create Start Menu shortcuts. For example, setting this to the list
+ ``ccmake;CMake`` will create a shortcut named "CMake" that will execute the
+ installed executable ``ccmake``. Not all CPack generators use it (at least
+ NSIS, WIX and OSXX11 do).
+
+.. variable:: CPACK_STRIP_FILES
+
+ List of files to be stripped. Starting with CMake 2.6.0,
+ ``CPACK_STRIP_FILES`` will be a boolean variable which enables
+ stripping of all files (a list of files evaluates to ``TRUE`` in CMake,
+ so this change is compatible).
+
+.. variable:: CPACK_VERBATIM_VARIABLES
+
+ .. versionadded:: 3.4
+
+ If set to ``TRUE``, values of variables prefixed with ``CPACK_`` will be
+ escaped before being written to the configuration files, so that the cpack
+ program receives them exactly as they were specified. If not, characters
+ like quotes and backslashes can cause parsing errors or alter the value
+ received by the cpack program. Defaults to ``FALSE`` for backwards
+ compatibility.
+
+.. variable:: CPACK_THREADS
+
+ .. versionadded:: 3.20
+
+ Number of threads to use when performing parallelized operations, such
+ as compressing the installer package.
+
+ Some compression methods used by CPack generators such as Debian or Archive
+ may take advantage of multiple CPU cores to speed up compression.
+ ``CPACK_THREADS`` can be set to positive integer to specify how many threads
+ will be used for compression. If it is set to 0, CPack will set it so that
+ all available CPU cores are used.
+ By default ``CPACK_THREADS`` is set to ``1``.
+
+ Currently only ``xz`` compression *may* take advantage of multiple cores. Other
+ compression methods ignore this value and use only one thread.
+
+ .. note::
+
+ Official CMake binaries available on ``cmake.org`` ship with a ``liblzma``
+ that does not support parallel compression.
+
+Variables for Source Package Generators
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following CPack variables are specific to source packages, and
+will not affect binary packages:
+
+.. variable:: CPACK_SOURCE_PACKAGE_FILE_NAME
+
+ The name of the source package. For example ``cmake-2.6.1``.
+
+.. variable:: CPACK_SOURCE_STRIP_FILES
+
+ List of files in the source tree that will be stripped. Starting with
+ CMake 2.6.0, ``CPACK_SOURCE_STRIP_FILES`` will be a boolean
+ variable which enables stripping of all files (a list of files evaluates
+ to ``TRUE`` in CMake, so this change is compatible).
+
+.. variable:: CPACK_SOURCE_GENERATOR
+
+ List of generators used for the source packages. As with
+ :variable:`CPACK_GENERATOR`, if this is not specified then CPack will
+ create a set of options (e.g. ``CPACK_SOURCE_ZIP``) allowing
+ users to select which packages will be generated.
+
+.. variable:: CPACK_SOURCE_OUTPUT_CONFIG_FILE
+
+ The name of the CPack source configuration file. This file is the CPack
+ configuration generated by the CPack module for source installers.
+ Defaults to ``CPackSourceConfig.cmake``.
+
+.. variable:: CPACK_SOURCE_IGNORE_FILES
+
+ Pattern of files in the source tree that won't be packaged when building
+ a source package. This is a list of regular expression patterns (that
+ must be properly escaped), e.g.,
+ ``/CVS/;/\\.svn/;\\.swp$;\\.#;/#;.*~;cscope.*``
+
+Variables for Advanced Use
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following variables are for advanced uses of CPack:
+
+.. variable:: CPACK_CMAKE_GENERATOR
+
+ What CMake generator should be used if the project is a CMake
+ project. Defaults to the value of :variable:`CMAKE_GENERATOR`. Few users
+ will want to change this setting.
+
+.. variable:: CPACK_INSTALL_CMAKE_PROJECTS
+
+ List of four values that specify what project to install. The four values
+ are: Build directory, Project Name, Project Component, Directory. If
+ omitted, CPack will build an installer that installs everything.
+
+.. variable:: CPACK_SYSTEM_NAME
+
+ System name, defaults to the value of :variable:`CMAKE_SYSTEM_NAME`,
+ except on Windows where it will be ``win32`` or ``win64``.
+
+.. variable:: CPACK_PACKAGE_VERSION
+
+ Package full version, used internally. By default, this is built from
+ :variable:`CPACK_PACKAGE_VERSION_MAJOR`,
+ :variable:`CPACK_PACKAGE_VERSION_MINOR`, and
+ :variable:`CPACK_PACKAGE_VERSION_PATCH`.
+
+.. variable:: CPACK_TOPLEVEL_TAG
+
+ Directory for the installed files.
+
+.. variable:: CPACK_INSTALL_COMMANDS
+
+ Extra commands to install components. The environment variable
+ ``CMAKE_INSTALL_PREFIX`` is set to the temporary install directory
+ during execution.
+
+.. variable:: CPACK_INSTALL_SCRIPTS
+
+ .. versionadded:: 3.16
+
+ Extra CMake scripts executed by CPack during its local staging
+ installation. They are executed before installing the files to be packaged.
+ The scripts are not called by a standalone install (e.g.: ``make install``).
+ For every script, the following variables will be set:
+ :variable:`CMAKE_CURRENT_SOURCE_DIR`, :variable:`CMAKE_CURRENT_BINARY_DIR`
+ and :variable:`CMAKE_INSTALL_PREFIX` (which is set to the staging install
+ directory). The singular form ``CMAKE_INSTALL_SCRIPT`` is supported as
+ an alternative variable for historical reasons, but its value is ignored if
+ ``CMAKE_INSTALL_SCRIPTS`` is set and a warning will be issued.
+
+ See also :variable:`CPACK_PRE_BUILD_SCRIPTS` and
+ :variable:`CPACK_POST_BUILD_SCRIPTS` which can be used to specify scripts
+ to be executed later in the packaging process.
+
+.. variable:: CPACK_PRE_BUILD_SCRIPTS
+
+ .. versionadded:: 3.19
+
+ List of CMake scripts to execute after CPack has installed the files to
+ be packaged into a staging directory and before producing the package(s)
+ from those files. See also :variable:`CPACK_INSTALL_SCRIPTS` and
+ :variable:`CPACK_POST_BUILD_SCRIPTS`.
+
+.. variable:: CPACK_POST_BUILD_SCRIPTS
+
+ .. versionadded:: 3.19
+
+ List of CMake scripts to execute after CPack has produced the resultant
+ packages and before copying them back to the build directory.
+ See also :variable:`CPACK_INSTALL_SCRIPTS`,
+ :variable:`CPACK_PRE_BUILD_SCRIPTS` and :variable:`CPACK_PACKAGE_FILES`.
+
+.. variable:: CPACK_PACKAGE_FILES
+
+ .. versionadded:: 3.19
+
+ List of package files created in the staging directory, with each file
+ provided as a full absolute path. This variable is populated by CPack
+ just before invoking the post-build scripts listed in
+ :variable:`CPACK_POST_BUILD_SCRIPTS`. It is the preferred way for the
+ post-build scripts to know the set of package files to operate on.
+ Projects should not try to set this variable themselves.
+
+.. variable:: CPACK_INSTALLED_DIRECTORIES
+
+ Extra directories to install.
+
+.. variable:: CPACK_PACKAGE_INSTALL_REGISTRY_KEY
+
+ Registry key used when installing this project. This is only used by
+ installers for Windows. The default value is based on the installation
+ directory.
+
+.. variable:: CPACK_CREATE_DESKTOP_LINKS
+
+ List of desktop links to create. Each desktop link requires a
+ corresponding start menu shortcut as created by
+ :variable:`CPACK_PACKAGE_EXECUTABLES`.
+
+.. variable:: CPACK_BINARY_<GENNAME>
+
+ CPack generated options for binary generators. The ``CPack.cmake`` module
+ generates (when :variable:`CPACK_GENERATOR` is not set) a set of CMake
+ options (see CMake :command:`option` command) which may then be used to
+ select the CPack generator(s) to be used when building the ``package``
+ target or when running :manual:`cpack <cpack(1)>` without the ``-G`` option.
+
+#]=======================================================================]
+
+# Define this var in order to avoid (or warn) concerning multiple inclusion
+if(CPack_CMake_INCLUDED)
+ message(WARNING "CPack.cmake has already been included!!")
+else()
+ set(CPack_CMake_INCLUDED 1)
+endif()
+
+# Pick a configuration file
+set(cpack_input_file "${CMAKE_ROOT}/Templates/CPackConfig.cmake.in")
+if(EXISTS "${CMAKE_SOURCE_DIR}/CPackConfig.cmake.in")
+ set(cpack_input_file "${CMAKE_SOURCE_DIR}/CPackConfig.cmake.in")
+endif()
+set(cpack_source_input_file "${CMAKE_ROOT}/Templates/CPackConfig.cmake.in")
+if(EXISTS "${CMAKE_SOURCE_DIR}/CPackSourceConfig.cmake.in")
+ set(cpack_source_input_file "${CMAKE_SOURCE_DIR}/CPackSourceConfig.cmake.in")
+endif()
+
+# Backward compatibility
+# Include CPackComponent macros if it has not already been included before.
+include(CPackComponent)
+
+# Macro for setting values if a user did not overwrite them
+# Mangles CMake-special characters. Only kept for backwards compatibility.
+macro(cpack_set_if_not_set name value)
+ message(DEPRECATION "cpack_set_if_not_set is obsolete; do not use.")
+ _cpack_set_default("${name}" "${value}")
+endmacro()
+
+# cpack_encode_variables - Function to encode variables for the configuration file
+# find any variable that starts with CPACK and create a variable
+# _CPACK_OTHER_VARIABLES_ that contains SET commands for
+# each cpack variable. _CPACK_OTHER_VARIABLES_ is then
+# used as an @ replacement in configure_file for the CPackConfig.
+function(cpack_encode_variables)
+ set(commands "")
+ get_cmake_property(res VARIABLES)
+ foreach(var ${res})
+ if(var MATCHES "^CPACK")
+ if(CPACK_VERBATIM_VARIABLES)
+ _cpack_escape_for_cmake(value "${${var}}")
+ else()
+ set(value "${${var}}")
+ endif()
+
+ string(APPEND commands "\nset(${var} \"${value}\")")
+ endif()
+ endforeach()
+
+ set(_CPACK_OTHER_VARIABLES_ "${commands}" PARENT_SCOPE)
+endfunction()
+
+# Internal use functions
+function(_cpack_set_default name value)
+ if(NOT DEFINED "${name}")
+ set("${name}" "${value}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_cpack_escape_for_cmake var value)
+ string(REGEX REPLACE "([\\\$\"])" "\\\\\\1" escaped "${value}")
+ set("${var}" "${escaped}" PARENT_SCOPE)
+endfunction()
+
+# Set the package name
+_cpack_set_default(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
+
+# Set the package version
+if(CMAKE_PROJECT_VERSION_MAJOR GREATER_EQUAL 0)
+ _cpack_set_default(CPACK_PACKAGE_VERSION_MAJOR "${CMAKE_PROJECT_VERSION_MAJOR}")
+ if(CMAKE_PROJECT_VERSION_MINOR GREATER_EQUAL 0)
+ _cpack_set_default(CPACK_PACKAGE_VERSION_MINOR "${CMAKE_PROJECT_VERSION_MINOR}")
+ if(CMAKE_PROJECT_VERSION_PATCH GREATER_EQUAL 0)
+ _cpack_set_default(CPACK_PACKAGE_VERSION_PATCH "${CMAKE_PROJECT_VERSION_PATCH}")
+ endif()
+ endif()
+else()
+ _cpack_set_default(CPACK_PACKAGE_VERSION_MAJOR "0")
+ _cpack_set_default(CPACK_PACKAGE_VERSION_MINOR "1")
+ _cpack_set_default(CPACK_PACKAGE_VERSION_PATCH "1")
+endif()
+if(NOT DEFINED CPACK_PACKAGE_VERSION)
+ set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}")
+ if(CPACK_PACKAGE_VERSION_MINOR GREATER_EQUAL 0)
+ string(APPEND CPACK_PACKAGE_VERSION ".${CPACK_PACKAGE_VERSION_MINOR}")
+ if(CPACK_PACKAGE_VERSION_PATCH GREATER_EQUAL 0)
+ string(APPEND CPACK_PACKAGE_VERSION ".${CPACK_PACKAGE_VERSION_PATCH}")
+ endif()
+ endif()
+endif()
+
+_cpack_set_default(CPACK_PACKAGE_VENDOR "Humanity")
+set(CPACK_DEFAULT_PACKAGE_DESCRIPTION_SUMMARY "${CMAKE_PROJECT_NAME} built using CMake")
+if(CMAKE_PROJECT_DESCRIPTION)
+ _cpack_set_default(CPACK_PACKAGE_DESCRIPTION_SUMMARY
+ "${CMAKE_PROJECT_DESCRIPTION}")
+else()
+ _cpack_set_default(CPACK_PACKAGE_DESCRIPTION_SUMMARY
+ "${CPACK_DEFAULT_PACKAGE_DESCRIPTION_SUMMARY}")
+endif()
+if(CMAKE_PROJECT_HOMEPAGE_URL)
+ _cpack_set_default(CPACK_PACKAGE_HOMEPAGE_URL
+ "${CMAKE_PROJECT_HOMEPAGE_URL}")
+endif()
+
+set(CPACK_DEFAULT_PACKAGE_DESCRIPTION_FILE
+ "${CMAKE_ROOT}/Templates/CPack.GenericDescription.txt")
+_cpack_set_default(CPACK_PACKAGE_DESCRIPTION_FILE
+ "${CPACK_DEFAULT_PACKAGE_DESCRIPTION_FILE}")
+_cpack_set_default(CPACK_RESOURCE_FILE_LICENSE
+ "${CMAKE_ROOT}/Templates/CPack.GenericLicense.txt")
+_cpack_set_default(CPACK_RESOURCE_FILE_README
+ "${CMAKE_ROOT}/Templates/CPack.GenericDescription.txt")
+_cpack_set_default(CPACK_RESOURCE_FILE_WELCOME
+ "${CMAKE_ROOT}/Templates/CPack.GenericWelcome.txt")
+
+_cpack_set_default(CPACK_MODULE_PATH "${CMAKE_MODULE_PATH}")
+
+# Set default directory creation permissions mode
+if(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS)
+ _cpack_set_default(CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
+ "${CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS}")
+endif()
+
+if(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL)
+ set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
+endif()
+
+if(CPACK_NSIS_MODIFY_PATH)
+ set(CPACK_NSIS_MODIFY_PATH ON)
+endif()
+
+set(__cpack_system_name ${CMAKE_SYSTEM_NAME})
+if(__cpack_system_name MATCHES "Windows")
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(__cpack_system_name win64)
+ else()
+ set(__cpack_system_name win32)
+ endif()
+endif()
+_cpack_set_default(CPACK_SYSTEM_NAME "${__cpack_system_name}")
+
+# Root dir: default value should be the string literal "$PROGRAMFILES"
+# for backwards compatibility. Projects may set this value to anything.
+# When creating 64 bit binaries we set the default value to "$PROGRAMFILES64"
+if("x${__cpack_system_name}" STREQUAL "xwin64")
+ set(__cpack_root_default "$PROGRAMFILES64")
+else()
+ set(__cpack_root_default "$PROGRAMFILES")
+endif()
+_cpack_set_default(CPACK_NSIS_INSTALL_ROOT "${__cpack_root_default}")
+
+# <project>-<major>.<minor>.<patch>-<release>-<platform>.<pkgtype>
+_cpack_set_default(CPACK_PACKAGE_FILE_NAME
+ "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_SYSTEM_NAME}")
+_cpack_set_default(CPACK_PACKAGE_INSTALL_DIRECTORY
+ "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION}")
+_cpack_set_default(CPACK_PACKAGE_INSTALL_REGISTRY_KEY
+ "${CPACK_PACKAGE_INSTALL_DIRECTORY}")
+_cpack_set_default(CPACK_PACKAGE_DEFAULT_LOCATION "/")
+_cpack_set_default(CPACK_PACKAGE_RELOCATABLE "true")
+
+# always force to exactly "true" or "false" for CPack.Info.plist.in:
+if(CPACK_PACKAGE_RELOCATABLE)
+ set(CPACK_PACKAGE_RELOCATABLE "true")
+else()
+ set(CPACK_PACKAGE_RELOCATABLE "false")
+endif()
+
+macro(cpack_check_file_exists file description)
+ if(NOT EXISTS "${file}")
+ message(SEND_ERROR "CPack ${description} file: \"${file}\" could not be found.")
+ endif()
+endmacro()
+
+cpack_check_file_exists("${CPACK_PACKAGE_DESCRIPTION_FILE}" "package description")
+cpack_check_file_exists("${CPACK_RESOURCE_FILE_LICENSE}" "license resource")
+cpack_check_file_exists("${CPACK_RESOURCE_FILE_README}" "readme resource")
+cpack_check_file_exists("${CPACK_RESOURCE_FILE_WELCOME}" "welcome resource")
+
+macro(cpack_optional_append _list _cond _item)
+ if(${_cond})
+ set(${_list} ${${_list}} ${_item})
+ endif()
+endmacro()
+
+# Provide options to choose generators we might check here if the required
+# tools for the generators exist and set the defaults according to the
+# results.
+if(NOT CPACK_GENERATOR)
+ if(UNIX)
+ if(CYGWIN)
+ option(CPACK_BINARY_CYGWIN "Enable to build Cygwin binary packages" ON)
+ else()
+ if(APPLE)
+ option(CPACK_BINARY_BUNDLE "Enable to build OSX bundles" OFF)
+ option(CPACK_BINARY_DRAGNDROP "Enable to build OSX Drag And Drop package" OFF)
+ option(CPACK_BINARY_OSXX11 "Enable to build OSX X11 packages (deprecated)" OFF)
+ option(CPACK_BINARY_PACKAGEMAKER "Enable to build PackageMaker packages (deprecated)" OFF)
+ option(CPACK_BINARY_PRODUCTBUILD "Enable to build productbuild packages" OFF)
+ mark_as_advanced(
+ CPACK_BINARY_BUNDLE
+ CPACK_BINARY_DRAGNDROP
+ CPACK_BINARY_OSXX11
+ CPACK_BINARY_PACKAGEMAKER
+ CPACK_BINARY_PRODUCTBUILD
+ )
+ else()
+ option(CPACK_BINARY_TZ "Enable to build TZ packages" ON)
+ mark_as_advanced(CPACK_BINARY_TZ)
+ endif()
+ option(CPACK_BINARY_DEB "Enable to build Debian packages" OFF)
+ option(CPACK_BINARY_FREEBSD "Enable to build FreeBSD packages" OFF)
+ option(CPACK_BINARY_NSIS "Enable to build NSIS packages" OFF)
+ option(CPACK_BINARY_RPM "Enable to build RPM packages" OFF)
+ option(CPACK_BINARY_STGZ "Enable to build STGZ packages" ON)
+ option(CPACK_BINARY_TBZ2 "Enable to build TBZ2 packages" OFF)
+ option(CPACK_BINARY_TGZ "Enable to build TGZ packages" ON)
+ option(CPACK_BINARY_TXZ "Enable to build TXZ packages" OFF)
+ mark_as_advanced(
+ CPACK_BINARY_DEB
+ CPACK_BINARY_FREEBSD
+ CPACK_BINARY_NSIS
+ CPACK_BINARY_RPM
+ CPACK_BINARY_STGZ
+ CPACK_BINARY_TBZ2
+ CPACK_BINARY_TGZ
+ CPACK_BINARY_TXZ
+ )
+ endif()
+ else()
+ option(CPACK_BINARY_7Z "Enable to build 7-Zip packages" OFF)
+ option(CPACK_BINARY_NSIS "Enable to build NSIS packages" ON)
+ option(CPACK_BINARY_NUGET "Enable to build NuGet packages" OFF)
+ option(CPACK_BINARY_WIX "Enable to build WiX packages" OFF)
+ option(CPACK_BINARY_ZIP "Enable to build ZIP packages" OFF)
+ mark_as_advanced(
+ CPACK_BINARY_7Z
+ CPACK_BINARY_NSIS
+ CPACK_BINARY_NUGET
+ CPACK_BINARY_WIX
+ CPACK_BINARY_ZIP
+ )
+ endif()
+ option(CPACK_BINARY_IFW "Enable to build IFW packages" OFF)
+ mark_as_advanced(CPACK_BINARY_IFW)
+
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_7Z 7Z)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_BUNDLE Bundle)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_CYGWIN CygwinBinary)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_DEB DEB)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_DRAGNDROP DragNDrop)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_FREEBSD FREEBSD)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_IFW IFW)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_NSIS NSIS)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_NUGET NuGet)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_OSXX11 OSXX11)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_PACKAGEMAKER PackageMaker)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_PRODUCTBUILD productbuild)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_RPM RPM)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_STGZ STGZ)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TBZ2 TBZ2)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TGZ TGZ)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TXZ TXZ)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TZ TZ)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_WIX WIX)
+ cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_ZIP ZIP)
+
+endif()
+
+# Provide options to choose source generators
+if(NOT CPACK_SOURCE_GENERATOR)
+ if(UNIX)
+ if(CYGWIN)
+ option(CPACK_SOURCE_CYGWIN "Enable to build Cygwin source packages" ON)
+ mark_as_advanced(CPACK_SOURCE_CYGWIN)
+ else()
+ option(CPACK_SOURCE_RPM "Enable to build RPM source packages" OFF)
+ option(CPACK_SOURCE_TBZ2 "Enable to build TBZ2 source packages" ON)
+ option(CPACK_SOURCE_TGZ "Enable to build TGZ source packages" ON)
+ option(CPACK_SOURCE_TXZ "Enable to build TXZ source packages" ON)
+ option(CPACK_SOURCE_TZ "Enable to build TZ source packages" ON)
+ option(CPACK_SOURCE_ZIP "Enable to build ZIP source packages" OFF)
+ mark_as_advanced(
+ CPACK_SOURCE_RPM
+ CPACK_SOURCE_TBZ2
+ CPACK_SOURCE_TGZ
+ CPACK_SOURCE_TXZ
+ CPACK_SOURCE_TZ
+ CPACK_SOURCE_ZIP
+ )
+ endif()
+ else()
+ option(CPACK_SOURCE_7Z "Enable to build 7-Zip source packages" ON)
+ option(CPACK_SOURCE_ZIP "Enable to build ZIP source packages" ON)
+ mark_as_advanced(
+ CPACK_SOURCE_7Z
+ CPACK_SOURCE_ZIP
+ )
+ endif()
+
+ cpack_optional_append(CPACK_SOURCE_GENERATOR CPACK_SOURCE_7Z 7Z)
+ cpack_optional_append(CPACK_SOURCE_GENERATOR CPACK_SOURCE_CYGWIN CygwinSource)
+ cpack_optional_append(CPACK_SOURCE_GENERATOR CPACK_SOURCE_RPM RPM)
+ cpack_optional_append(CPACK_SOURCE_GENERATOR CPACK_SOURCE_TBZ2 TBZ2)
+ cpack_optional_append(CPACK_SOURCE_GENERATOR CPACK_SOURCE_TGZ TGZ)
+ cpack_optional_append(CPACK_SOURCE_GENERATOR CPACK_SOURCE_TXZ TXZ)
+ cpack_optional_append(CPACK_SOURCE_GENERATOR CPACK_SOURCE_TZ TZ)
+ cpack_optional_append(CPACK_SOURCE_GENERATOR CPACK_SOURCE_ZIP ZIP)
+endif()
+
+# Set some other variables
+_cpack_set_default(CPACK_INSTALL_CMAKE_PROJECTS
+ "${CMAKE_BINARY_DIR};${CMAKE_PROJECT_NAME};ALL;/")
+_cpack_set_default(CPACK_CMAKE_GENERATOR "${CMAKE_GENERATOR}")
+_cpack_set_default(CPACK_TOPLEVEL_TAG "${CPACK_SYSTEM_NAME}")
+_cpack_set_default(CPACK_THREADS 1)
+# if the user has set CPACK_NSIS_DISPLAY_NAME remember it
+if(DEFINED CPACK_NSIS_DISPLAY_NAME)
+ set(CPACK_NSIS_DISPLAY_NAME_SET TRUE)
+endif()
+# if the user has set CPACK_NSIS_DISPLAY
+# explicitly, then use that as the default
+# value of CPACK_NSIS_PACKAGE_NAME instead
+# of CPACK_PACKAGE_INSTALL_DIRECTORY
+_cpack_set_default(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY}")
+# Specify the name of the Uninstall file in NSIS
+_cpack_set_default(CPACK_NSIS_UNINSTALL_NAME "Uninstall")
+
+if(CPACK_NSIS_DISPLAY_NAME_SET)
+ _cpack_set_default(CPACK_NSIS_PACKAGE_NAME "${CPACK_NSIS_DISPLAY_NAME}")
+else()
+ _cpack_set_default(CPACK_NSIS_PACKAGE_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY}")
+endif()
+
+_cpack_set_default(CPACK_OUTPUT_CONFIG_FILE
+ "${CMAKE_BINARY_DIR}/CPackConfig.cmake")
+
+_cpack_set_default(CPACK_SOURCE_OUTPUT_CONFIG_FILE
+ "${CMAKE_BINARY_DIR}/CPackSourceConfig.cmake")
+
+_cpack_set_default(CPACK_SET_DESTDIR OFF)
+_cpack_set_default(CPACK_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
+
+_cpack_set_default(CPACK_NSIS_INSTALLER_ICON_CODE "")
+_cpack_set_default(CPACK_NSIS_INSTALLER_MUI_ICON_CODE "")
+
+# WiX specific variables
+_cpack_set_default(CPACK_WIX_SIZEOF_VOID_P "${CMAKE_SIZEOF_VOID_P}")
+
+# set sysroot so SDK tools can be used
+if(CMAKE_OSX_SYSROOT)
+ _cpack_set_default(CPACK_OSX_SYSROOT "${_CMAKE_OSX_SYSROOT_PATH}")
+endif()
+
+_cpack_set_default(CPACK_BUILD_SOURCE_DIRS "${CMAKE_SOURCE_DIR};${CMAKE_BINARY_DIR}")
+
+if(DEFINED CPACK_COMPONENTS_ALL)
+ if(CPACK_MONOLITHIC_INSTALL)
+ message("CPack warning: both CPACK_COMPONENTS_ALL and CPACK_MONOLITHIC_INSTALL have been set.\nDefaulting to a monolithic installation.")
+ set(CPACK_COMPONENTS_ALL)
+ else()
+ # The user has provided the set of components to be installed as
+ # part of a component-based installation; trust her.
+ set(CPACK_COMPONENTS_ALL_SET_BY_USER TRUE)
+ endif()
+else()
+ # If the user has not specifically requested a monolithic installer
+ # but has specified components in various "install" commands, tell
+ # CPack about those components.
+ if(NOT CPACK_MONOLITHIC_INSTALL)
+ get_cmake_property(CPACK_COMPONENTS_ALL COMPONENTS)
+ list(LENGTH CPACK_COMPONENTS_ALL CPACK_COMPONENTS_LEN)
+ if(CPACK_COMPONENTS_LEN EQUAL 1)
+ # Only one component: this is not a component-based installation
+ # (at least, it isn't a component-based installation, but may
+ # become one later if the user uses the cpack_add_* commands).
+ set(CPACK_COMPONENTS_ALL)
+ endif()
+ set(CPACK_COMPONENTS_LEN)
+ endif()
+endif()
+
+# CMake always generates a component named "Unspecified", which is
+# used to install everything that doesn't have an explicitly-provided
+# component. Since these files should always be installed, we'll make
+# them hidden and required.
+set(CPACK_COMPONENT_UNSPECIFIED_HIDDEN TRUE)
+set(CPACK_COMPONENT_UNSPECIFIED_REQUIRED TRUE)
+
+cpack_encode_variables()
+configure_file("${cpack_input_file}" "${CPACK_OUTPUT_CONFIG_FILE}" @ONLY)
+
+# Generate source file
+_cpack_set_default(CPACK_SOURCE_INSTALLED_DIRECTORIES
+ "${CMAKE_SOURCE_DIR};/")
+_cpack_set_default(CPACK_SOURCE_TOPLEVEL_TAG "${CPACK_SYSTEM_NAME}-Source")
+_cpack_set_default(CPACK_SOURCE_PACKAGE_FILE_NAME
+ "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-Source")
+
+set(__cpack_source_ignore_files_default
+ "/CVS/;/\\.svn/;/\\.bzr/;/\\.hg/;/\\.git/;\\.swp$;\\.#;/#")
+if(NOT CPACK_VERBATIM_VARIABLES)
+ _cpack_escape_for_cmake(__cpack_source_ignore_files_default
+ "${__cpack_source_ignore_files_default}")
+endif()
+_cpack_set_default(CPACK_SOURCE_IGNORE_FILES "${__cpack_source_ignore_files_default}")
+
+set(CPACK_INSTALL_CMAKE_PROJECTS "${CPACK_SOURCE_INSTALL_CMAKE_PROJECTS}")
+set(CPACK_INSTALLED_DIRECTORIES "${CPACK_SOURCE_INSTALLED_DIRECTORIES}")
+set(CPACK_GENERATOR "${CPACK_SOURCE_GENERATOR}")
+set(CPACK_TOPLEVEL_TAG "${CPACK_SOURCE_TOPLEVEL_TAG}")
+set(CPACK_PACKAGE_FILE_NAME "${CPACK_SOURCE_PACKAGE_FILE_NAME}")
+set(CPACK_IGNORE_FILES "${CPACK_SOURCE_IGNORE_FILES}")
+set(CPACK_STRIP_FILES "${CPACK_SOURCE_STRIP_FILES}")
+
+set(CPACK_RPM_PACKAGE_SOURCES "ON")
+
+cpack_encode_variables()
+configure_file("${cpack_source_input_file}"
+ "${CPACK_SOURCE_OUTPUT_CONFIG_FILE}" @ONLY)
diff --git a/Modules/CPackComponent.cmake b/Modules/CPackComponent.cmake
new file mode 100644
index 0000000..1f8c38c
--- /dev/null
+++ b/Modules/CPackComponent.cmake
@@ -0,0 +1,554 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CPackComponent
+--------------
+
+Configure components for binary installers and source packages.
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+^^^^^^^^^^^^
+
+This module is automatically included by :module:`CPack`.
+
+Certain binary installers (especially the graphical installers) generated
+by CPack allow users to select individual application *components* to install.
+This module allows developers to configure the packaging of such components.
+
+Contents is assigned to components by the ``COMPONENT``
+argument of CMake's :command:`install` command. Components can be
+annotated with user-friendly names and descriptions, inter-component
+dependencies, etc., and grouped in various ways to customize the
+resulting installer, using the commands described below.
+
+To specify different groupings for different CPack generators use
+a CPACK_PROJECT_CONFIG_FILE.
+
+Variables
+^^^^^^^^^
+
+The following variables influence the component-specific packaging:
+
+.. variable:: CPACK_COMPONENTS_ALL
+
+ The list of component to install.
+
+ The default value of this variable is computed by CPack and contains all
+ components defined by the project. The user may set it to only include the
+ specified components.
+
+ Instead of specifying all the desired components, it is possible to obtain a
+ list of all defined components and then remove the unwanted ones from the
+ list. The :command:`get_cmake_property` command can be used to obtain the
+ ``COMPONENTS`` property, then the :command:`list(REMOVE_ITEM)` command can be
+ used to remove the unwanted ones. For example, to use all defined components
+ except ``foo`` and ``bar``::
+
+ get_cmake_property(CPACK_COMPONENTS_ALL COMPONENTS)
+ list(REMOVE_ITEM CPACK_COMPONENTS_ALL "foo" "bar")
+
+.. variable:: CPACK_<GENNAME>_COMPONENT_INSTALL
+
+ Enable/Disable component install for CPack generator <GENNAME>.
+
+ Each CPack Generator (RPM, DEB, ARCHIVE, NSIS, DMG, etc...) has a legacy
+ default behavior. e.g. RPM builds monolithic whereas NSIS builds
+ component. One can change the default behavior by setting this variable to
+ 0/1 or OFF/ON.
+
+.. variable:: CPACK_COMPONENTS_GROUPING
+
+ Specify how components are grouped for multi-package component-aware CPack
+ generators.
+
+ Some generators like RPM or ARCHIVE (TGZ, ZIP, ...) may generate
+ several packages files when there are components, depending
+ on the value of this variable:
+
+ * ONE_PER_GROUP (default): create one package per component group
+ * IGNORE : create one package per component (ignore the groups)
+ * ALL_COMPONENTS_IN_ONE : create a single package with all requested
+ components
+
+.. variable:: CPACK_COMPONENT_<compName>_DISPLAY_NAME
+
+ The name to be displayed for a component.
+
+.. variable:: CPACK_COMPONENT_<compName>_DESCRIPTION
+
+ The description of a component.
+
+.. variable:: CPACK_COMPONENT_<compName>_GROUP
+
+ The group of a component.
+
+.. variable:: CPACK_COMPONENT_<compName>_DEPENDS
+
+ The dependencies (list of components) on which this component depends.
+
+.. variable:: CPACK_COMPONENT_<compName>_HIDDEN
+
+ True if this component is hidden from the user.
+
+.. variable:: CPACK_COMPONENT_<compName>_REQUIRED
+
+ True if this component is required.
+
+.. variable:: CPACK_COMPONENT_<compName>_DISABLED
+
+ True if this component is not selected to be installed by default.
+
+Commands
+^^^^^^^^
+
+Add component
+"""""""""""""
+
+.. command:: cpack_add_component
+
+Describe an installation component.
+
+::
+
+ cpack_add_component(compname
+ [DISPLAY_NAME name]
+ [DESCRIPTION description]
+ [HIDDEN | REQUIRED | DISABLED ]
+ [GROUP group]
+ [DEPENDS comp1 comp2 ... ]
+ [INSTALL_TYPES type1 type2 ... ]
+ [DOWNLOADED]
+ [ARCHIVE_FILE filename]
+ [PLIST filename])
+
+``compname`` is the name of an installation component, as defined by the
+``COMPONENT`` argument of one or more CMake :command:`install` commands.
+With the ``cpack_add_component`` command one can set a name, a description,
+and other attributes of an installation component.
+One can also assign a component to a component group.
+
+DISPLAY_NAME is the displayed name of the component, used in graphical
+installers to display the component name. This value can be any
+string.
+
+DESCRIPTION is an extended description of the component, used in
+graphical installers to give the user additional information about the
+component. Descriptions can span multiple lines using ``\n`` as the
+line separator. Typically, these descriptions should be no more than
+a few lines long.
+
+HIDDEN indicates that this component will be hidden in the graphical
+installer, so that the user cannot directly change whether it is
+installed or not.
+
+REQUIRED indicates that this component is required, and therefore will
+always be installed. It will be visible in the graphical installer,
+but it cannot be unselected. (Typically, required components are
+shown greyed out).
+
+DISABLED indicates that this component should be disabled (unselected)
+by default. The user is free to select this component for
+installation, unless it is also HIDDEN.
+
+DEPENDS lists the components on which this component depends. If this
+component is selected, then each of the components listed must also be
+selected. The dependency information is encoded within the installer
+itself, so that users cannot install inconsistent sets of components.
+
+GROUP names the component group of which this component is a part. If
+not provided, the component will be a standalone component, not part
+of any component group. Component groups are described with the
+cpack_add_component_group command, detailed below.
+
+INSTALL_TYPES lists the installation types of which this component is
+a part. When one of these installations types is selected, this
+component will automatically be selected. Installation types are
+described with the cpack_add_install_type command, detailed below.
+
+DOWNLOADED indicates that this component should be downloaded
+on-the-fly by the installer, rather than packaged in with the
+installer itself. For more information, see the
+cpack_configure_downloads command.
+
+ARCHIVE_FILE provides a name for the archive file created by CPack to
+be used for downloaded components. If not supplied, CPack will create
+a file with some name based on CPACK_PACKAGE_FILE_NAME and the name of
+the component. See cpack_configure_downloads for more information.
+
+PLIST gives a filename that is passed to pkgbuild with the
+``--component-plist`` argument when using the productbuild generator.
+
+Add component group
+"""""""""""""""""""
+
+.. command:: cpack_add_component_group
+
+Describes a group of related CPack installation components.
+
+::
+
+ cpack_add_component_group(groupname
+ [DISPLAY_NAME name]
+ [DESCRIPTION description]
+ [PARENT_GROUP parent]
+ [EXPANDED]
+ [BOLD_TITLE])
+
+
+
+The cpack_add_component_group describes a group of installation
+components, which will be placed together within the listing of
+options. Typically, component groups allow the user to
+select/deselect all of the components within a single group via a
+single group-level option. Use component groups to reduce the
+complexity of installers with many options. groupname is an arbitrary
+name used to identify the group in the GROUP argument of the
+cpack_add_component command, which is used to place a component in a
+group. The name of the group must not conflict with the name of any
+component.
+
+DISPLAY_NAME is the displayed name of the component group, used in
+graphical installers to display the component group name. This value
+can be any string.
+
+DESCRIPTION is an extended description of the component group, used in
+graphical installers to give the user additional information about the
+components within that group. Descriptions can span multiple lines
+using ``\n`` as the line separator. Typically, these descriptions
+should be no more than a few lines long.
+
+PARENT_GROUP, if supplied, names the parent group of this group.
+Parent groups are used to establish a hierarchy of groups, providing
+an arbitrary hierarchy of groups.
+
+EXPANDED indicates that, by default, the group should show up as
+"expanded", so that the user immediately sees all of the components
+within the group. Otherwise, the group will initially show up as a
+single entry.
+
+BOLD_TITLE indicates that the group title should appear in bold, to
+call the user's attention to the group.
+
+Add installation type
+"""""""""""""""""""""
+
+.. command:: cpack_add_install_type
+
+Add a new installation type containing
+a set of predefined component selections to the graphical installer.
+
+::
+
+ cpack_add_install_type(typename
+ [DISPLAY_NAME name])
+
+
+
+The cpack_add_install_type command identifies a set of preselected
+components that represents a common use case for an application. For
+example, a "Developer" install type might include an application along
+with its header and library files, while an "End user" install type
+might just include the application's executable. Each component
+identifies itself with one or more install types via the INSTALL_TYPES
+argument to cpack_add_component.
+
+DISPLAY_NAME is the displayed name of the install type, which will
+typically show up in a drop-down box within a graphical installer.
+This value can be any string.
+
+Configure downloads
+"""""""""""""""""""
+
+.. command:: cpack_configure_downloads
+
+Configure CPack to download
+selected components on-the-fly as part of the installation process.
+
+::
+
+ cpack_configure_downloads(site
+ [UPLOAD_DIRECTORY dirname]
+ [ALL]
+ [ADD_REMOVE|NO_ADD_REMOVE])
+
+
+
+The cpack_configure_downloads command configures installation-time
+downloads of selected components. For each downloadable component,
+CPack will create an archive containing the contents of that
+component, which should be uploaded to the given site. When the user
+selects that component for installation, the installer will download
+and extract the component in place. This feature is useful for
+creating small installers that only download the requested components,
+saving bandwidth. Additionally, the installers are small enough that
+they will be installed as part of the normal installation process, and
+the "Change" button in Windows Add/Remove Programs control panel will
+allow one to add or remove parts of the application after the original
+installation. On Windows, the downloaded-components functionality
+requires the ZipDLL plug-in for NSIS, available at:
+
+::
+
+ http://nsis.sourceforge.net/ZipDLL_plug-in
+
+On macOS, installers that download components on-the-fly can only
+be built and installed on system using macOS 10.5 or later.
+
+The site argument is a URL where the archives for downloadable
+components will reside, e.g.,
+https://cmake.org/files/2.6.1/installer/ All of the archives
+produced by CPack should be uploaded to that location.
+
+UPLOAD_DIRECTORY is the local directory where CPack will create the
+various archives for each of the components. The contents of this
+directory should be uploaded to a location accessible by the URL given
+in the site argument. If omitted, CPack will use the directory
+CPackUploads inside the CMake binary directory to store the generated
+archives.
+
+The ALL flag indicates that all components be downloaded. Otherwise,
+only those components explicitly marked as DOWNLOADED or that have a
+specified ARCHIVE_FILE will be downloaded. Additionally, the ALL
+option implies ADD_REMOVE (unless NO_ADD_REMOVE is specified).
+
+ADD_REMOVE indicates that CPack should install a copy of the installer
+that can be called from Windows' Add/Remove Programs dialog (via the
+"Modify" button) to change the set of installed components.
+NO_ADD_REMOVE turns off this behavior. This option is ignored on Mac
+OS X.
+#]=======================================================================]
+
+# Define var in order to avoid multiple inclusion
+if(NOT CPackComponent_CMake_INCLUDED)
+set(CPackComponent_CMake_INCLUDED 1)
+
+# Macro that appends a SET command for the given variable name (var)
+# to the macro named strvar, but only if the variable named "var"
+# has been defined. The string will eventually be appended to a CPack
+# configuration file.
+macro(cpack_append_variable_set_command var strvar)
+ if (DEFINED ${var})
+ string(APPEND ${strvar} "set(${var}")
+ foreach(APPENDVAL ${${var}})
+ string(APPEND ${strvar} " ${APPENDVAL}")
+ endforeach()
+ string(APPEND ${strvar} ")\n")
+ endif ()
+endmacro()
+
+# Macro that appends a SET command for the given variable name (var)
+# to the macro named strvar, but only if the variable named "var"
+# has been defined and is a string. The string will eventually be
+# appended to a CPack configuration file.
+macro(cpack_append_string_variable_set_command var strvar)
+ if (DEFINED ${var})
+ list(LENGTH ${var} CPACK_APP_VALUE_LEN)
+ if(${CPACK_APP_VALUE_LEN} EQUAL 1)
+ string(APPEND ${strvar} "set(${var} \"${${var}}\")\n")
+ endif()
+ endif ()
+endmacro()
+
+# Macro that appends a SET command for the given list variable name (var)
+# to the macro named strvar, but only if the variable named "var"
+# has been defined. It's like add variable, but wrap each item to quotes.
+# The string will eventually be appended to a CPack configuration file.
+macro(cpack_append_list_variable_set_command var strvar)
+ if (DEFINED ${var})
+ string(APPEND ${strvar} "set(${var}")
+ foreach(_val IN LISTS ${var})
+ string(APPEND ${strvar} "\n \"${_val}\"")
+ endforeach()
+ string(APPEND ${strvar} ")\n")
+ endif ()
+endmacro()
+
+# Macro that appends a SET command for the given variable name (var)
+# to the macro named strvar, but only if the variable named "var"
+# has been set to true. The string will eventually be
+# appended to a CPack configuration file.
+macro(cpack_append_option_set_command var strvar)
+ if (${var})
+ list(LENGTH ${var} CPACK_APP_VALUE_LEN)
+ if(${CPACK_APP_VALUE_LEN} EQUAL 1)
+ string(APPEND ${strvar} "set(${var} TRUE)\n")
+ endif()
+ endif ()
+endmacro()
+
+# Macro that adds a component to the CPack installer
+macro(cpack_add_component compname)
+ string(TOUPPER ${compname} _CPACK_ADDCOMP_UNAME)
+ cmake_parse_arguments(CPACK_COMPONENT_${_CPACK_ADDCOMP_UNAME}
+ "HIDDEN;REQUIRED;DISABLED;DOWNLOADED"
+ "DISPLAY_NAME;DESCRIPTION;GROUP;ARCHIVE_FILE;PLIST"
+ "DEPENDS;INSTALL_TYPES"
+ ${ARGN}
+ )
+
+ if (CPACK_COMPONENT_${_CPACK_ADDCOMP_UNAME}_DOWNLOADED)
+ set(_CPACK_ADDCOMP_STR "\n# Configuration for downloaded component \"${compname}\"\n")
+ else ()
+ set(_CPACK_ADDCOMP_STR "\n# Configuration for component \"${compname}\"\n")
+ endif ()
+
+ if(NOT CPACK_MONOLITHIC_INSTALL)
+ # If the user didn't set CPACK_COMPONENTS_ALL explicitly, update the
+ # value of CPACK_COMPONENTS_ALL in the configuration file. This will
+ # take care of any components that have been added after the CPack
+ # moduled was included.
+ if(NOT CPACK_COMPONENTS_ALL_SET_BY_USER)
+ get_cmake_property(_CPACK_ADDCOMP_COMPONENTS COMPONENTS)
+ string(APPEND _CPACK_ADDCOMP_STR "\nSET(CPACK_COMPONENTS_ALL")
+ foreach(COMP ${_CPACK_ADDCOMP_COMPONENTS})
+ string(APPEND _CPACK_ADDCOMP_STR " ${COMP}")
+ endforeach()
+ string(APPEND _CPACK_ADDCOMP_STR ")\n")
+ endif()
+ endif()
+
+ cpack_append_string_variable_set_command(
+ CPACK_COMPONENT_${_CPACK_ADDCOMP_UNAME}_DISPLAY_NAME
+ _CPACK_ADDCOMP_STR)
+ cpack_append_string_variable_set_command(
+ CPACK_COMPONENT_${_CPACK_ADDCOMP_UNAME}_DESCRIPTION
+ _CPACK_ADDCOMP_STR)
+ cpack_append_variable_set_command(
+ CPACK_COMPONENT_${_CPACK_ADDCOMP_UNAME}_GROUP
+ _CPACK_ADDCOMP_STR)
+ cpack_append_variable_set_command(
+ CPACK_COMPONENT_${_CPACK_ADDCOMP_UNAME}_DEPENDS
+ _CPACK_ADDCOMP_STR)
+ cpack_append_variable_set_command(
+ CPACK_COMPONENT_${_CPACK_ADDCOMP_UNAME}_INSTALL_TYPES
+ _CPACK_ADDCOMP_STR)
+ cpack_append_string_variable_set_command(
+ CPACK_COMPONENT_${_CPACK_ADDCOMP_UNAME}_ARCHIVE_FILE
+ _CPACK_ADDCOMP_STR)
+ cpack_append_option_set_command(
+ CPACK_COMPONENT_${_CPACK_ADDCOMP_UNAME}_HIDDEN
+ _CPACK_ADDCOMP_STR)
+ cpack_append_option_set_command(
+ CPACK_COMPONENT_${_CPACK_ADDCOMP_UNAME}_REQUIRED
+ _CPACK_ADDCOMP_STR)
+ cpack_append_option_set_command(
+ CPACK_COMPONENT_${_CPACK_ADDCOMP_UNAME}_DISABLED
+ _CPACK_ADDCOMP_STR)
+ cpack_append_option_set_command(
+ CPACK_COMPONENT_${_CPACK_ADDCOMP_UNAME}_DOWNLOADED
+ _CPACK_ADDCOMP_STR)
+ cpack_append_string_variable_set_command(
+ CPACK_COMPONENT_${_CPACK_ADDCOMP_UNAME}_PLIST
+ _CPACK_ADDCOMP_STR)
+ # Backward compatibility issue.
+ # Write to config iff the macros is used after CPack.cmake has been
+ # included, other it's not necessary because the variables
+ # will be encoded by cpack_encode_variables.
+ if(CPack_CMake_INCLUDED)
+ file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "${_CPACK_ADDCOMP_STR}")
+ endif()
+endmacro()
+
+# Macro that adds a component group to the CPack installer
+macro(cpack_add_component_group grpname)
+ string(TOUPPER ${grpname} _CPACK_ADDGRP_UNAME)
+ cmake_parse_arguments(CPACK_COMPONENT_GROUP_${_CPACK_ADDGRP_UNAME}
+ "EXPANDED;BOLD_TITLE"
+ "DISPLAY_NAME;DESCRIPTION;PARENT_GROUP"
+ ""
+ ${ARGN}
+ )
+
+ set(_CPACK_ADDGRP_STR "\n# Configuration for component group \"${grpname}\"\n")
+ cpack_append_string_variable_set_command(
+ CPACK_COMPONENT_GROUP_${_CPACK_ADDGRP_UNAME}_DISPLAY_NAME
+ _CPACK_ADDGRP_STR)
+ cpack_append_string_variable_set_command(
+ CPACK_COMPONENT_GROUP_${_CPACK_ADDGRP_UNAME}_DESCRIPTION
+ _CPACK_ADDGRP_STR)
+ cpack_append_string_variable_set_command(
+ CPACK_COMPONENT_GROUP_${_CPACK_ADDGRP_UNAME}_PARENT_GROUP
+ _CPACK_ADDGRP_STR)
+ cpack_append_option_set_command(
+ CPACK_COMPONENT_GROUP_${_CPACK_ADDGRP_UNAME}_EXPANDED
+ _CPACK_ADDGRP_STR)
+ cpack_append_option_set_command(
+ CPACK_COMPONENT_GROUP_${_CPACK_ADDGRP_UNAME}_BOLD_TITLE
+ _CPACK_ADDGRP_STR)
+ # Backward compatibility issue.
+ # Write to config iff the macros is used after CPack.cmake has been
+ # included, other it's not necessary because the variables
+ # will be encoded by cpack_encode_variables.
+ if(CPack_CMake_INCLUDED)
+ file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "${_CPACK_ADDGRP_STR}")
+ endif()
+endmacro()
+
+# Macro that adds an installation type to the CPack installer
+macro(cpack_add_install_type insttype)
+ string(TOUPPER ${insttype} _CPACK_INSTTYPE_UNAME)
+ cmake_parse_arguments(CPACK_INSTALL_TYPE_${_CPACK_INSTTYPE_UNAME}
+ ""
+ "DISPLAY_NAME"
+ ""
+ ${ARGN}
+ )
+
+ set(_CPACK_INSTTYPE_STR
+ "\n# Configuration for installation type \"${insttype}\"\n")
+ string(APPEND _CPACK_INSTTYPE_STR
+ "list(APPEND CPACK_ALL_INSTALL_TYPES ${insttype})\n")
+ cpack_append_string_variable_set_command(
+ CPACK_INSTALL_TYPE_${_CPACK_INSTTYPE_UNAME}_DISPLAY_NAME
+ _CPACK_INSTTYPE_STR)
+ # Backward compatibility issue.
+ # Write to config iff the macros is used after CPack.cmake has been
+ # included, other it's not necessary because the variables
+ # will be encoded by cpack_encode_variables.
+ if(CPack_CMake_INCLUDED)
+ file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "${_CPACK_INSTTYPE_STR}")
+ endif()
+endmacro()
+
+macro(cpack_configure_downloads site)
+ cmake_parse_arguments(CPACK_DOWNLOAD
+ "ALL;ADD_REMOVE;NO_ADD_REMOVE"
+ "UPLOAD_DIRECTORY"
+ ""
+ ${ARGN}
+ )
+
+ set(CPACK_CONFIG_DL_STR
+ "\n# Downloaded components configuration\n")
+ set(CPACK_UPLOAD_DIRECTORY ${CPACK_DOWNLOAD_UPLOAD_DIRECTORY})
+ set(CPACK_DOWNLOAD_SITE ${site})
+ cpack_append_string_variable_set_command(
+ CPACK_DOWNLOAD_SITE
+ CPACK_CONFIG_DL_STR)
+ cpack_append_string_variable_set_command(
+ CPACK_UPLOAD_DIRECTORY
+ CPACK_CONFIG_DL_STR)
+ cpack_append_option_set_command(
+ CPACK_DOWNLOAD_ALL
+ CPACK_CONFIG_DL_STR)
+ if (${CPACK_DOWNLOAD_ALL} AND NOT ${CPACK_DOWNLOAD_NO_ADD_REMOVE})
+ set(CPACK_DOWNLOAD_ADD_REMOVE ON)
+ endif ()
+ set(CPACK_ADD_REMOVE ${CPACK_DOWNLOAD_ADD_REMOVE})
+ cpack_append_option_set_command(
+ CPACK_ADD_REMOVE
+ CPACK_CONFIG_DL_STR)
+ # Backward compatibility issue.
+ # Write to config iff the macros is used after CPack.cmake has been
+ # included, other it's not necessary because the variables
+ # will be encoded by cpack_encode_variables.
+ if(CPack_CMake_INCLUDED)
+ file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "${CPACK_CONFIG_DL_STR}")
+ endif()
+endmacro()
+endif()
diff --git a/Modules/CPackIFW.cmake b/Modules/CPackIFW.cmake
new file mode 100644
index 0000000..2087a51
--- /dev/null
+++ b/Modules/CPackIFW.cmake
@@ -0,0 +1,830 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CPackIFW
+--------
+
+.. versionadded:: 3.1
+
+This module looks for the location of the command-line utilities supplied with the
+`Qt Installer Framework <http://doc.qt.io/qtinstallerframework/index.html>`_
+(QtIFW).
+
+The module also defines several commands to control the behavior of the
+:cpack_gen:`CPack IFW Generator`.
+
+Commands
+^^^^^^^^
+
+The module defines the following commands:
+
+.. command:: cpack_ifw_configure_component
+
+ Sets the arguments specific to the CPack IFW generator.
+
+ ::
+
+ cpack_ifw_configure_component(<compname> [COMMON] [ESSENTIAL] [VIRTUAL]
+ [FORCED_INSTALLATION] [REQUIRES_ADMIN_RIGHTS]
+ [NAME <name>]
+ [DISPLAY_NAME <display_name>] # Note: Internationalization supported
+ [DESCRIPTION <description>] # Note: Internationalization supported
+ [UPDATE_TEXT <update_text>]
+ [VERSION <version>]
+ [RELEASE_DATE <release_date>]
+ [SCRIPT <script>]
+ [PRIORITY|SORTING_PRIORITY <sorting_priority>] # Note: PRIORITY is deprecated
+ [DEPENDS|DEPENDENCIES <com_id> ...]
+ [AUTO_DEPEND_ON <comp_id> ...]
+ [LICENSES <display_name> <file_path> ...]
+ [DEFAULT <value>]
+ [USER_INTERFACES <file_path> <file_path> ...]
+ [TRANSLATIONS <file_path> <file_path> ...]
+ [REPLACES <comp_id> ...]
+ [CHECKABLE <value>])
+
+ This command should be called after :command:`cpack_add_component` command.
+
+ ``COMMON``
+ if set, then the component will be packaged and installed as part
+ of a group to which it belongs.
+
+ ``ESSENTIAL``
+ .. versionadded:: 3.6
+
+ if set, then the package manager stays disabled until that
+ component is updated.
+
+ ``VIRTUAL``
+ .. versionadded:: 3.8
+
+ if set, then the component will be hidden from the installer.
+ It is a equivalent of the ``HIDDEN`` option from the
+ :command:`cpack_add_component` command.
+
+ ``FORCED_INSTALLATION``
+ .. versionadded:: 3.8
+
+ if set, then the component must always be installed.
+ It is a equivalent of the ``REQUIRED`` option from the
+ :command:`cpack_add_component` command.
+
+ ``REQUIRES_ADMIN_RIGHTS``
+ .. versionadded:: 3.8
+
+ set it if the component needs to be installed with elevated permissions.
+
+ ``NAME``
+ is used to create domain-like identification for this component.
+ By default used origin component name.
+
+ ``DISPLAY_NAME``
+ .. versionadded:: 3.8
+
+ set to rewrite original name configured by
+ :command:`cpack_add_component` command.
+
+ ``DESCRIPTION``
+ .. versionadded:: 3.8
+
+ set to rewrite original description configured by
+ :command:`cpack_add_component` command.
+
+ ``UPDATE_TEXT``
+ .. versionadded:: 3.8
+
+ will be added to the component description if this is an update to
+ the component.
+
+ ``VERSION``
+ is version of component.
+ By default used :variable:`CPACK_PACKAGE_VERSION`.
+
+ ``RELEASE_DATE``
+ .. versionadded:: 3.8
+
+ keep empty to auto generate.
+
+ ``SCRIPT``
+ is a relative or absolute path to operations script
+ for this component.
+
+ ``SORTING_PRIORITY``
+ .. versionadded:: 3.8
+
+ is priority of the component in the tree.
+
+ ``PRIORITY``
+ .. deprecated:: 3.8
+ Old name for ``SORTING_PRIORITY``.
+
+ ``DEPENDS``, ``DEPENDENCIES``
+ .. versionadded:: 3.8
+
+ list of dependency component or component group identifiers in
+ QtIFW style.
+
+ .. versionadded:: 3.21
+
+ Component or group names listed as dependencies may contain hyphens.
+ This requires QtIFW 3.1 or later.
+
+ ``AUTO_DEPEND_ON``
+ .. versionadded:: 3.8
+
+ list of identifiers of component or component group in QtIFW style
+ that this component has an automatic dependency on.
+
+ ``LICENSES``
+ pair of <display_name> and <file_path> of license text for this
+ component. You can specify more then one license.
+
+ ``DEFAULT``
+ .. versionadded:: 3.8
+
+ Possible values are: TRUE, FALSE, and SCRIPT.
+ Set to FALSE to disable the component in the installer or to SCRIPT
+ to resolved during runtime (don't forget add the file of the script
+ as a value of the ``SCRIPT`` option).
+
+ ``USER_INTERFACES``
+ .. versionadded:: 3.7
+
+ is a list of <file_path> ('.ui' files) representing pages to load.
+
+ ``TRANSLATIONS``
+ .. versionadded:: 3.8
+
+ is a list of <file_path> ('.qm' files) representing translations to load.
+
+ ``REPLACES``
+ .. versionadded:: 3.10
+
+ list of identifiers of component or component group to replace.
+
+ ``CHECKABLE``
+ .. versionadded:: 3.10
+
+ Possible values are: TRUE, FALSE.
+ Set to FALSE if you want to hide the checkbox for an item.
+ This is useful when only a few subcomponents should be selected
+ instead of all.
+
+
+.. command:: cpack_ifw_configure_component_group
+
+ Sets the arguments specific to the CPack IFW generator.
+
+ ::
+
+ cpack_ifw_configure_component_group(<groupname> [VIRTUAL]
+ [FORCED_INSTALLATION] [REQUIRES_ADMIN_RIGHTS]
+ [NAME <name>]
+ [DISPLAY_NAME <display_name>] # Note: Internationalization supported
+ [DESCRIPTION <description>] # Note: Internationalization supported
+ [UPDATE_TEXT <update_text>]
+ [VERSION <version>]
+ [RELEASE_DATE <release_date>]
+ [SCRIPT <script>]
+ [PRIORITY|SORTING_PRIORITY <sorting_priority>] # Note: PRIORITY is deprecated
+ [DEPENDS|DEPENDENCIES <com_id> ...]
+ [AUTO_DEPEND_ON <comp_id> ...]
+ [LICENSES <display_name> <file_path> ...]
+ [DEFAULT <value>]
+ [USER_INTERFACES <file_path> <file_path> ...]
+ [TRANSLATIONS <file_path> <file_path> ...]
+ [REPLACES <comp_id> ...]
+ [CHECKABLE <value>])
+
+ This command should be called after :command:`cpack_add_component_group`
+ command.
+
+ ``VIRTUAL``
+ .. versionadded:: 3.8
+
+ if set, then the group will be hidden from the installer.
+ Note that setting this on a root component does not work.
+
+ ``FORCED_INSTALLATION``
+ .. versionadded:: 3.8
+
+ if set, then the group must always be installed.
+
+ ``REQUIRES_ADMIN_RIGHTS``
+ .. versionadded:: 3.8
+
+ set it if the component group needs to be installed with elevated
+ permissions.
+
+ ``NAME``
+ is used to create domain-like identification for this component group.
+ By default used origin component group name.
+
+ ``DISPLAY_NAME``
+ .. versionadded:: 3.8
+
+ set to rewrite original name configured by
+ :command:`cpack_add_component_group` command.
+
+ ``DESCRIPTION``
+ .. versionadded:: 3.8
+
+ set to rewrite original description configured by
+ :command:`cpack_add_component_group` command.
+
+ ``UPDATE_TEXT``
+ .. versionadded:: 3.8
+
+ will be added to the component group description if this is an update to
+ the component group.
+
+ ``VERSION``
+ is version of component group.
+ By default used :variable:`CPACK_PACKAGE_VERSION`.
+
+ ``RELEASE_DATE``
+ .. versionadded:: 3.8
+
+ keep empty to auto generate.
+
+ ``SCRIPT``
+ is a relative or absolute path to operations script
+ for this component group.
+
+ ``SORTING_PRIORITY``
+ is priority of the component group in the tree.
+
+ ``PRIORITY``
+ .. deprecated:: 3.8
+ Old name for ``SORTING_PRIORITY``.
+
+ ``DEPENDS``, ``DEPENDENCIES``
+ .. versionadded:: 3.8
+
+ list of dependency component or component group identifiers in
+ QtIFW style.
+
+ .. versionadded:: 3.21
+
+ Component or group names listed as dependencies may contain hyphens.
+ This requires QtIFW 3.1 or later.
+
+ ``AUTO_DEPEND_ON``
+ .. versionadded:: 3.8
+
+ list of identifiers of component or component group in QtIFW style
+ that this component group has an automatic dependency on.
+
+ ``LICENSES``
+ pair of <display_name> and <file_path> of license text for this
+ component group. You can specify more then one license.
+
+ ``DEFAULT``
+ .. versionadded:: 3.8
+
+ Possible values are: TRUE, FALSE, and SCRIPT.
+ Set to TRUE to preselect the group in the installer
+ (this takes effect only on groups that have no visible child components)
+ or to SCRIPT to resolved during runtime (don't forget add the file of
+ the script as a value of the ``SCRIPT`` option).
+
+ ``USER_INTERFACES``
+ .. versionadded:: 3.7
+
+ is a list of <file_path> ('.ui' files) representing pages to load.
+
+ ``TRANSLATIONS``
+ .. versionadded:: 3.8
+
+ is a list of <file_path> ('.qm' files) representing translations to load.
+
+ ``REPLACES``
+ .. versionadded:: 3.10
+
+ list of identifiers of component or component group to replace.
+
+ ``CHECKABLE``
+ .. versionadded:: 3.10
+
+ Possible values are: TRUE, FALSE.
+ Set to FALSE if you want to hide the checkbox for an item.
+ This is useful when only a few subcomponents should be selected
+ instead of all.
+
+
+.. command:: cpack_ifw_add_repository
+
+ Add QtIFW specific remote repository to binary installer.
+
+ ::
+
+ cpack_ifw_add_repository(<reponame> [DISABLED]
+ URL <url>
+ [USERNAME <username>]
+ [PASSWORD <password>]
+ [DISPLAY_NAME <display_name>])
+
+ This command will also add the <reponame> repository
+ to a variable :variable:`CPACK_IFW_REPOSITORIES_ALL`.
+
+ ``DISABLED``
+ if set, then the repository will be disabled by default.
+
+ ``URL``
+ is points to a list of available components.
+
+ ``USERNAME``
+ is used as user on a protected repository.
+
+ ``PASSWORD``
+ is password to use on a protected repository.
+
+ ``DISPLAY_NAME``
+ is string to display instead of the URL.
+
+
+.. command:: cpack_ifw_update_repository
+
+ .. versionadded:: 3.6
+
+ Update QtIFW specific repository from remote repository.
+
+ ::
+
+ cpack_ifw_update_repository(<reponame>
+ [[ADD|REMOVE] URL <url>]|
+ [REPLACE OLD_URL <old_url> NEW_URL <new_url>]]
+ [USERNAME <username>]
+ [PASSWORD <password>]
+ [DISPLAY_NAME <display_name>])
+
+ This command will also add the <reponame> repository
+ to a variable :variable:`CPACK_IFW_REPOSITORIES_ALL`.
+
+ ``URL``
+ is points to a list of available components.
+
+ ``OLD_URL``
+ is points to a list that will replaced.
+
+ ``NEW_URL``
+ is points to a list that will replace to.
+
+ ``USERNAME``
+ is used as user on a protected repository.
+
+ ``PASSWORD``
+ is password to use on a protected repository.
+
+ ``DISPLAY_NAME``
+ is string to display instead of the URL.
+
+
+.. command:: cpack_ifw_add_package_resources
+
+ .. versionadded:: 3.7
+
+ Add additional resources in the installer binary.
+
+ ::
+
+ cpack_ifw_add_package_resources(<file_path> <file_path> ...)
+
+ This command will also add the specified files
+ to a variable :variable:`CPACK_IFW_PACKAGE_RESOURCES`.
+
+#]=======================================================================]
+
+# TODO:
+# All of the internal implementation CMake modules for other CPack generators
+# have been moved into the Internal/CPack directory. This one has not, because
+# it contains user-facing macros which would be lost if it were moved. At some
+# point, this module should be split into user-facing macros (which would live
+# in this module) and internal implementation details (which would live in
+# Internal/CPack/CPackIFW.cmake).
+
+#=============================================================================
+# Search Qt Installer Framework tools
+#=============================================================================
+
+# Default path
+
+foreach(_CPACK_IFW_PATH_VAR "CPACK_IFW_ROOT" "QTIFWDIR" "QTDIR")
+ if(DEFINED ${_CPACK_IFW_PATH_VAR}
+ AND NOT "${${_CPACK_IFW_PATH_VAR}}" STREQUAL "")
+ list(APPEND _CPACK_IFW_PATHS "${${_CPACK_IFW_PATH_VAR}}")
+ endif()
+ if(NOT "$ENV{${_CPACK_IFW_PATH_VAR}}" STREQUAL "")
+ list(APPEND _CPACK_IFW_PATHS "$ENV{${_CPACK_IFW_PATH_VAR}}")
+ endif()
+endforeach()
+if(WIN32)
+ list(APPEND _CPACK_IFW_PATHS
+ "$ENV{HOMEDRIVE}/Qt"
+ "C:/Qt")
+else()
+ list(APPEND _CPACK_IFW_PATHS
+ "$ENV{HOME}/Qt"
+ "/opt/Qt")
+endif()
+list(REMOVE_DUPLICATES _CPACK_IFW_PATHS)
+
+set(_CPACK_IFW_PREFIXES
+ # QtSDK
+ "Tools/QtInstallerFramework/"
+ # Second branch
+ "QtIFW"
+ # First branch
+ "QtIFW-")
+
+set(_CPACK_IFW_VERSIONS
+ "4.0"
+ "3.2"
+ "3.2.0"
+ "3.1"
+ "3.1.0"
+ "3.0"
+ "3.0.0"
+ "2.3"
+ "2.3.0"
+ "2.2"
+ "2.2.0"
+ "2.1"
+ "2.1.0"
+ "2.0"
+ "2.0.5"
+ "2.0.3"
+ "2.0.2"
+ "2.0.1"
+ "2.0.0"
+ "1.6"
+ "1.6.0"
+ "1.5"
+ "1.5.0"
+ "1.4"
+ "1.4.0"
+ "1.3"
+ "1.3.0")
+
+set(_CPACK_IFW_SUFFIXES "bin")
+foreach(_CPACK_IFW_PREFIX ${_CPACK_IFW_PREFIXES})
+ foreach(_CPACK_IFW_VERSION ${_CPACK_IFW_VERSIONS})
+ list(APPEND
+ _CPACK_IFW_SUFFIXES "${_CPACK_IFW_PREFIX}${_CPACK_IFW_VERSION}/bin")
+ endforeach()
+endforeach()
+
+# Look for 'binarycreator'
+
+find_program(CPACK_IFW_BINARYCREATOR_EXECUTABLE
+ NAMES binarycreator
+ PATHS ${_CPACK_IFW_PATHS}
+ PATH_SUFFIXES ${_CPACK_IFW_SUFFIXES}
+ DOC "QtIFW binarycreator command line client")
+
+mark_as_advanced(CPACK_IFW_BINARYCREATOR_EXECUTABLE)
+
+# Look for 'repogen'
+
+find_program(CPACK_IFW_REPOGEN_EXECUTABLE
+ NAMES repogen
+ PATHS ${_CPACK_IFW_PATHS}
+ PATH_SUFFIXES ${_CPACK_IFW_SUFFIXES}
+ DOC "QtIFW repogen command line client"
+ )
+mark_as_advanced(CPACK_IFW_REPOGEN_EXECUTABLE)
+
+# Look for 'installerbase'
+
+find_program(CPACK_IFW_INSTALLERBASE_EXECUTABLE
+ NAMES installerbase
+ PATHS ${_CPACK_IFW_PATHS}
+ PATH_SUFFIXES ${_CPACK_IFW_SUFFIXES}
+ DOC "QtIFW installer executable base"
+ )
+mark_as_advanced(CPACK_IFW_INSTALLERBASE_EXECUTABLE)
+
+# Look for 'devtool' (appeared in the second branch)
+
+find_program(CPACK_IFW_DEVTOOL_EXECUTABLE
+ NAMES devtool
+ PATHS ${_CPACK_IFW_PATHS}
+ PATH_SUFFIXES ${_CPACK_IFW_SUFFIXES}
+ DOC "QtIFW devtool command line client"
+ )
+mark_as_advanced(CPACK_IFW_DEVTOOL_EXECUTABLE)
+
+# Look for 'archivegen'
+
+find_program(CPACK_IFW_ARCHIVEGEN_EXECUTABLE
+ NAMES archivegen
+ PATHS ${_CPACK_IFW_PATHS}
+ PATH_SUFFIXES ${_CPACK_IFW_SUFFIXES}
+ DOC "QtIFW archivegen command line client"
+ )
+mark_as_advanced(CPACK_IFW_ARCHIVEGEN_EXECUTABLE)
+
+#
+## Next code is included only once
+#
+
+if(NOT CPackIFW_CMake_INCLUDED)
+set(CPackIFW_CMake_INCLUDED 1)
+
+#=============================================================================
+# Framework version
+#=============================================================================
+
+set(CPACK_IFW_FRAMEWORK_VERSION_FORCED ""
+ CACHE STRING "The forced version of used QtIFW tools")
+mark_as_advanced(CPACK_IFW_FRAMEWORK_VERSION_FORCED)
+set(CPACK_IFW_FRAMEWORK_VERSION_TIMEOUT 1
+ CACHE STRING "The timeout to return QtIFW framework version string from \"installerbase\" executable")
+mark_as_advanced(CPACK_IFW_FRAMEWORK_VERSION_TIMEOUT)
+if(CPACK_IFW_INSTALLERBASE_EXECUTABLE AND NOT CPACK_IFW_FRAMEWORK_VERSION_FORCED)
+ set(CPACK_IFW_FRAMEWORK_VERSION)
+ # Invoke version from "installerbase" executable
+ foreach(_ifw_version_argument --version --framework-version)
+ if(NOT CPACK_IFW_FRAMEWORK_VERSION)
+ execute_process(COMMAND
+ "${CPACK_IFW_INSTALLERBASE_EXECUTABLE}" ${_ifw_version_argument}
+ TIMEOUT ${CPACK_IFW_FRAMEWORK_VERSION_TIMEOUT}
+ RESULT_VARIABLE CPACK_IFW_FRAMEWORK_VERSION_RESULT
+ OUTPUT_VARIABLE CPACK_IFW_FRAMEWORK_VERSION_OUTPUT
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ENCODING UTF8)
+ if(NOT CPACK_IFW_FRAMEWORK_VERSION_RESULT AND CPACK_IFW_FRAMEWORK_VERSION_OUTPUT)
+ string(REGEX MATCH "[0-9]+(\\.[0-9]+)*"
+ CPACK_IFW_FRAMEWORK_VERSION "${CPACK_IFW_FRAMEWORK_VERSION_OUTPUT}")
+ if(CPACK_IFW_FRAMEWORK_VERSION)
+ if("${_ifw_version_argument}" STREQUAL "--framework-version")
+ set(CPACK_IFW_FRAMEWORK_VERSION_SOURCE "INSTALLERBASE_FRAMEWORK_VERSION")
+ elseif("${_ifw_version_argument}" STREQUAL "--version")
+ set(CPACK_IFW_FRAMEWORK_VERSION_SOURCE "INSTALLERBASE_FRAMEWORK_VERSION")
+ endif()
+ endif()
+ endif()
+ endif()
+ endforeach()
+ # Finally try to get version from executable path
+ if(NOT CPACK_IFW_FRAMEWORK_VERSION)
+ string(REGEX MATCH "[0-9]+(\\.[0-9]+)*"
+ CPACK_IFW_FRAMEWORK_VERSION "${CPACK_IFW_INSTALLERBASE_EXECUTABLE}")
+ if(CPACK_IFW_FRAMEWORK_VERSION)
+ set(CPACK_IFW_FRAMEWORK_VERSION_SOURCE "INSTALLERBASE_PATH")
+ endif()
+ endif()
+elseif(CPACK_IFW_FRAMEWORK_VERSION_FORCED)
+ set(CPACK_IFW_FRAMEWORK_VERSION ${CPACK_IFW_FRAMEWORK_VERSION_FORCED})
+ set(CPACK_IFW_FRAMEWORK_VERSION_SOURCE "FORCED")
+endif()
+if(CPACK_IFW_VERBOSE)
+ if(CPACK_IFW_FRAMEWORK_VERSION AND CPACK_IFW_FRAMEWORK_VERSION_FORCED)
+ message(STATUS "Found QtIFW ${CPACK_IFW_FRAMEWORK_VERSION} (forced) version")
+ elseif(CPACK_IFW_FRAMEWORK_VERSION)
+ message(STATUS "Found QtIFW ${CPACK_IFW_FRAMEWORK_VERSION} version")
+ endif()
+endif()
+if(CPACK_IFW_INSTALLERBASE_EXECUTABLE AND NOT CPACK_IFW_FRAMEWORK_VERSION)
+ message(WARNING "Could not detect QtIFW tools version. Set used version to variable \"CPACK_IFW_FRAMEWORK_VERSION_FORCED\" manually.")
+endif()
+
+#=============================================================================
+# Macro definition
+#=============================================================================
+
+# Macro definition based on CPackComponent
+
+if(NOT CPackComponent_CMake_INCLUDED)
+ include(CPackComponent)
+endif()
+
+# Resolve full filename for script file
+macro(_cpack_ifw_resolve_script _variable)
+ set(_ifw_script_macro ${_variable})
+ set(_ifw_script_file ${${_ifw_script_macro}})
+ if(DEFINED ${_ifw_script_macro})
+ get_filename_component(${_ifw_script_macro} ${_ifw_script_file} ABSOLUTE)
+ set(_ifw_script_file ${${_ifw_script_macro}})
+ if(NOT EXISTS ${_ifw_script_file})
+ message(WARNING "CPack IFW: script file \"${_ifw_script_file}\" does not exist")
+ set(${_ifw_script_macro})
+ endif()
+ endif()
+endmacro()
+
+# Resolve full path to license file
+macro(_cpack_ifw_resolve_lisenses _variable)
+ if(${_variable})
+ set(_ifw_license_file FALSE)
+ set(_ifw_licenses_fix)
+ foreach(_ifw_licenses_arg ${${_variable}})
+ if(_ifw_license_file)
+ get_filename_component(_ifw_licenses_arg "${_ifw_licenses_arg}" ABSOLUTE)
+ set(_ifw_license_file FALSE)
+ else()
+ set(_ifw_license_file TRUE)
+ endif()
+ list(APPEND _ifw_licenses_fix "${_ifw_licenses_arg}")
+ endforeach(_ifw_licenses_arg)
+ set(${_variable} "${_ifw_licenses_fix}")
+ endif()
+endmacro()
+
+# Resolve full path to a list of provided files
+macro(_cpack_ifw_resolve_file_list _variable)
+ if(${_variable})
+ set(_ifw_list_fix)
+ foreach(_ifw_file_arg ${${_variable}})
+ get_filename_component(_ifw_file_arg "${_ifw_file_arg}" ABSOLUTE)
+ if(EXISTS ${_ifw_file_arg})
+ list(APPEND _ifw_list_fix "${_ifw_file_arg}")
+ else()
+ message(WARNING "CPack IFW: page file \"${_ifw_file_arg}\" does not exist. Skipping")
+ endif()
+ endforeach(_ifw_file_arg)
+ set(${_variable} "${_ifw_list_fix}")
+ endif()
+endmacro()
+
+# Macro for configure component
+macro(cpack_ifw_configure_component compname)
+
+ string(TOUPPER ${compname} _CPACK_IFWCOMP_UNAME)
+
+ set(_IFW_OPT COMMON ESSENTIAL VIRTUAL FORCED_INSTALLATION REQUIRES_ADMIN_RIGHTS)
+ set(_IFW_ARGS NAME VERSION RELEASE_DATE SCRIPT PRIORITY SORTING_PRIORITY UPDATE_TEXT DEFAULT CHECKABLE)
+ set(_IFW_MULTI_ARGS DISPLAY_NAME DESCRIPTION DEPENDS DEPENDENCIES AUTO_DEPEND_ON LICENSES USER_INTERFACES TRANSLATIONS REPLACES)
+ cmake_parse_arguments(CPACK_IFW_COMPONENT_${_CPACK_IFWCOMP_UNAME} "${_IFW_OPT}" "${_IFW_ARGS}" "${_IFW_MULTI_ARGS}" ${ARGN})
+
+ _cpack_ifw_resolve_script(CPACK_IFW_COMPONENT_${_CPACK_IFWCOMP_UNAME}_SCRIPT)
+ _cpack_ifw_resolve_lisenses(CPACK_IFW_COMPONENT_${_CPACK_IFWCOMP_UNAME}_LICENSES)
+ _cpack_ifw_resolve_file_list(CPACK_IFW_COMPONENT_${_CPACK_IFWCOMP_UNAME}_USER_INTERFACES)
+ _cpack_ifw_resolve_file_list(CPACK_IFW_COMPONENT_${_CPACK_IFWCOMP_UNAME}_TRANSLATIONS)
+
+ set(_CPACK_IFWCOMP_STR "\n# Configuration for IFW component \"${compname}\"\n")
+
+ foreach(_IFW_ARG_NAME ${_IFW_OPT})
+ cpack_append_option_set_command(
+ CPACK_IFW_COMPONENT_${_CPACK_IFWCOMP_UNAME}_${_IFW_ARG_NAME}
+ _CPACK_IFWCOMP_STR)
+ endforeach()
+
+ foreach(_IFW_ARG_NAME ${_IFW_ARGS})
+ cpack_append_string_variable_set_command(
+ CPACK_IFW_COMPONENT_${_CPACK_IFWCOMP_UNAME}_${_IFW_ARG_NAME}
+ _CPACK_IFWCOMP_STR)
+ endforeach()
+
+ foreach(_IFW_ARG_NAME ${_IFW_MULTI_ARGS})
+ cpack_append_list_variable_set_command(
+ CPACK_IFW_COMPONENT_${_CPACK_IFWCOMP_UNAME}_${_IFW_ARG_NAME}
+ _CPACK_IFWCOMP_STR)
+ endforeach()
+
+ if(CPack_CMake_INCLUDED)
+ file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "${_CPACK_IFWCOMP_STR}")
+ endif()
+
+endmacro()
+
+# Macro for configure group
+macro(cpack_ifw_configure_component_group grpname)
+
+ string(TOUPPER ${grpname} _CPACK_IFWGRP_UNAME)
+
+ set(_IFW_OPT VIRTUAL FORCED_INSTALLATION REQUIRES_ADMIN_RIGHTS)
+ set(_IFW_ARGS NAME VERSION RELEASE_DATE SCRIPT PRIORITY SORTING_PRIORITY UPDATE_TEXT DEFAULT CHECKABLE)
+ set(_IFW_MULTI_ARGS DISPLAY_NAME DESCRIPTION DEPENDS DEPENDENCIES AUTO_DEPEND_ON LICENSES USER_INTERFACES TRANSLATIONS REPLACES)
+ cmake_parse_arguments(CPACK_IFW_COMPONENT_GROUP_${_CPACK_IFWGRP_UNAME} "${_IFW_OPT}" "${_IFW_ARGS}" "${_IFW_MULTI_ARGS}" ${ARGN})
+
+ _cpack_ifw_resolve_script(CPACK_IFW_COMPONENT_GROUP_${_CPACK_IFWGRP_UNAME}_SCRIPT)
+ _cpack_ifw_resolve_lisenses(CPACK_IFW_COMPONENT_GROUP_${_CPACK_IFWGRP_UNAME}_LICENSES)
+ _cpack_ifw_resolve_file_list(CPACK_IFW_COMPONENT_GROUP_${_CPACK_IFWGRP_UNAME}_USER_INTERFACES)
+ _cpack_ifw_resolve_file_list(CPACK_IFW_COMPONENT_GROUP_${_CPACK_IFWGRP_UNAME}_TRANSLATIONS)
+
+ set(_CPACK_IFWGRP_STR "\n# Configuration for IFW component group \"${grpname}\"\n")
+
+ foreach(_IFW_ARG_NAME ${_IFW_OPT})
+ cpack_append_option_set_command(
+ CPACK_IFW_COMPONENT_GROUP_${_CPACK_IFWGRP_UNAME}_${_IFW_ARG_NAME}
+ _CPACK_IFWGRP_STR)
+ endforeach()
+
+ foreach(_IFW_ARG_NAME ${_IFW_ARGS})
+ cpack_append_string_variable_set_command(
+ CPACK_IFW_COMPONENT_GROUP_${_CPACK_IFWGRP_UNAME}_${_IFW_ARG_NAME}
+ _CPACK_IFWGRP_STR)
+ endforeach()
+
+ foreach(_IFW_ARG_NAME ${_IFW_MULTI_ARGS})
+ cpack_append_list_variable_set_command(
+ CPACK_IFW_COMPONENT_GROUP_${_CPACK_IFWGRP_UNAME}_${_IFW_ARG_NAME}
+ _CPACK_IFWGRP_STR)
+ endforeach()
+
+ if(CPack_CMake_INCLUDED)
+ file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "${_CPACK_IFWGRP_STR}")
+ endif()
+endmacro()
+
+# Macro for adding repository
+macro(cpack_ifw_add_repository reponame)
+
+ string(TOUPPER ${reponame} _CPACK_IFWREPO_UNAME)
+
+ set(_IFW_OPT DISABLED)
+ set(_IFW_ARGS URL USERNAME PASSWORD DISPLAY_NAME)
+ set(_IFW_MULTI_ARGS)
+ cmake_parse_arguments(CPACK_IFW_REPOSITORY_${_CPACK_IFWREPO_UNAME} "${_IFW_OPT}" "${_IFW_ARGS}" "${_IFW_MULTI_ARGS}" ${ARGN})
+
+ set(_CPACK_IFWREPO_STR "\n# Configuration for IFW repository \"${reponame}\"\n")
+
+ foreach(_IFW_ARG_NAME ${_IFW_OPT})
+ cpack_append_option_set_command(
+ CPACK_IFW_REPOSITORY_${_CPACK_IFWREPO_UNAME}_${_IFW_ARG_NAME}
+ _CPACK_IFWREPO_STR)
+ endforeach()
+
+ foreach(_IFW_ARG_NAME ${_IFW_ARGS})
+ cpack_append_string_variable_set_command(
+ CPACK_IFW_REPOSITORY_${_CPACK_IFWREPO_UNAME}_${_IFW_ARG_NAME}
+ _CPACK_IFWREPO_STR)
+ endforeach()
+
+ foreach(_IFW_ARG_NAME ${_IFW_MULTI_ARGS})
+ cpack_append_variable_set_command(
+ CPACK_IFW_REPOSITORY_${_CPACK_IFWREPO_UNAME}_${_IFW_ARG_NAME}
+ _CPACK_IFWREPO_STR)
+ endforeach()
+
+ list(APPEND CPACK_IFW_REPOSITORIES_ALL ${reponame})
+ string(APPEND _CPACK_IFWREPO_STR "list(APPEND CPACK_IFW_REPOSITORIES_ALL ${reponame})\n")
+
+ if(CPack_CMake_INCLUDED)
+ file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "${_CPACK_IFWREPO_STR}")
+ endif()
+
+endmacro()
+
+# Macro for updating repository
+macro(cpack_ifw_update_repository reponame)
+
+ string(TOUPPER ${reponame} _CPACK_IFWREPO_UNAME)
+
+ set(_IFW_OPT ADD REMOVE REPLACE DISABLED)
+ set(_IFW_ARGS URL OLD_URL NEW_URL USERNAME PASSWORD DISPLAY_NAME)
+ set(_IFW_MULTI_ARGS)
+ cmake_parse_arguments(CPACK_IFW_REPOSITORY_${_CPACK_IFWREPO_UNAME} "${_IFW_OPT}" "${_IFW_ARGS}" "${_IFW_MULTI_ARGS}" ${ARGN})
+
+ set(_CPACK_IFWREPO_STR "\n# Configuration for IFW repository \"${reponame}\" update\n")
+
+ foreach(_IFW_ARG_NAME ${_IFW_OPT})
+ cpack_append_option_set_command(
+ CPACK_IFW_REPOSITORY_${_CPACK_IFWREPO_UNAME}_${_IFW_ARG_NAME}
+ _CPACK_IFWREPO_STR)
+ endforeach()
+
+ foreach(_IFW_ARG_NAME ${_IFW_ARGS})
+ cpack_append_string_variable_set_command(
+ CPACK_IFW_REPOSITORY_${_CPACK_IFWREPO_UNAME}_${_IFW_ARG_NAME}
+ _CPACK_IFWREPO_STR)
+ endforeach()
+
+ foreach(_IFW_ARG_NAME ${_IFW_MULTI_ARGS})
+ cpack_append_variable_set_command(
+ CPACK_IFW_REPOSITORY_${_CPACK_IFWREPO_UNAME}_${_IFW_ARG_NAME}
+ _CPACK_IFWREPO_STR)
+ endforeach()
+
+ if(CPACK_IFW_REPOSITORY_${_CPACK_IFWREPO_UNAME}_ADD
+ OR CPACK_IFW_REPOSITORY_${_CPACK_IFWREPO_UNAME}_REMOVE
+ OR CPACK_IFW_REPOSITORY_${_CPACK_IFWREPO_UNAME}_REPLACE)
+ list(APPEND CPACK_IFW_REPOSITORIES_ALL ${reponame})
+ string(APPEND _CPACK_IFWREPO_STR "list(APPEND CPACK_IFW_REPOSITORIES_ALL ${reponame})\n")
+ else()
+ set(_CPACK_IFWREPO_STR)
+ endif()
+
+ if(CPack_CMake_INCLUDED AND _CPACK_IFWREPO_STR)
+ file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "${_CPACK_IFWREPO_STR}")
+ endif()
+
+endmacro()
+
+# Macro for adding resources
+macro(cpack_ifw_add_package_resources)
+ set(_CPACK_IFW_PACKAGE_RESOURCES ${ARGV})
+ _cpack_ifw_resolve_file_list(_CPACK_IFW_PACKAGE_RESOURCES)
+ list(APPEND CPACK_IFW_PACKAGE_RESOURCES ${_CPACK_IFW_PACKAGE_RESOURCES})
+ set(_CPACK_IFWQRC_STR "list(APPEND CPACK_IFW_PACKAGE_RESOURCES \"${_CPACK_IFW_PACKAGE_RESOURCES}\")\n")
+ if(CPack_CMake_INCLUDED)
+ file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "${_CPACK_IFWQRC_STR}")
+ endif()
+endmacro()
+
+# Resolve package control script
+_cpack_ifw_resolve_script(CPACK_IFW_PACKAGE_CONTROL_SCRIPT)
+
+endif() # NOT CPackIFW_CMake_INCLUDED
diff --git a/Modules/CPackIFWConfigureFile.cmake b/Modules/CPackIFWConfigureFile.cmake
new file mode 100644
index 0000000..296b13f
--- /dev/null
+++ b/Modules/CPackIFWConfigureFile.cmake
@@ -0,0 +1,68 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CPackIFWConfigureFile
+---------------------
+
+.. versionadded:: 3.8
+
+The module defines :command:`configure_file` similar command to
+configure file templates prepared in QtIFW/SDK/Creator style.
+
+
+Commands
+^^^^^^^^
+
+The module defines the following commands:
+
+.. command:: cpack_ifw_configure_file
+
+ Copy a file to another location and modify its contents.
+
+ ::
+
+ cpack_ifw_configure_file(<input> <output>)
+
+ Copies an ``<input>`` file to an ``<output>`` file and substitutes variable
+ values referenced as ``%{VAR}`` or ``%VAR%`` in the input file content.
+ Each variable reference will be replaced with the current value of the
+ variable, or the empty string if the variable is not defined.
+
+#]=======================================================================]
+
+# NOTE: This file used to himself packaging via CPack IFW generator and
+# should be compatible with minimal CMake version defined in
+# ../CMakeLists.txt file.
+
+if(NOT DEFINED CPackIFWConfigureFile_CMake_INCLUDED)
+set(CPackIFWConfigureFile_CMake_INCLUDED 1)
+
+macro(cpack_ifw_configure_file INPUT OUTPUT)
+ file(READ "${INPUT}" _tmp)
+ foreach(_tmp_regex "%{([^%}]+)}" "%([^%]+)%")
+ string(REGEX MATCHALL "${_tmp_regex}" _tmp_vars "${_tmp}")
+ while(_tmp_vars)
+ foreach(_tmp_var ${_tmp_vars})
+ string(REGEX REPLACE "${_tmp_regex}" "\\1"
+ _tmp_var_name "${_tmp_var}")
+ if(DEFINED ${_tmp_var_name})
+ set(_tmp_var_value "${${_tmp_var_name}}")
+ elseif(NOT "$ENV{${_tmp_var_name}}" STREQUAL "")
+ set(_tmp_var_value "$ENV{${_tmp_var_name}}")
+ else()
+ set(_tmp_var_value "")
+ endif()
+ string(REPLACE "${_tmp_var}" "${_tmp_var_value}" _tmp "${_tmp}")
+ endforeach()
+ string(REGEX MATCHALL "${_tmp_regex}" _tmp_vars "${_tmp}")
+ endwhile()
+ endforeach()
+ if(IS_ABSOLUTE "${OUTPUT}")
+ file(WRITE "${OUTPUT}" "${_tmp}")
+ else()
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT}" "${_tmp}")
+ endif()
+endmacro()
+
+endif() # NOT DEFINED CPackIFWConfigureFile_CMake_INCLUDED
diff --git a/Modules/CSharpUtilities.cmake b/Modules/CSharpUtilities.cmake
new file mode 100644
index 0000000..dedb146
--- /dev/null
+++ b/Modules/CSharpUtilities.cmake
@@ -0,0 +1,313 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CSharpUtilities
+---------------
+
+.. versionadded:: 3.8
+
+Functions to make configuration of CSharp/.NET targets easier.
+
+A collection of CMake utility functions useful for dealing with CSharp
+targets for Visual Studio generators from version 2010 and later.
+
+The following functions are provided by this module:
+
+**Main functions**
+
+- :command:`csharp_set_windows_forms_properties`
+- :command:`csharp_set_designer_cs_properties`
+- :command:`csharp_set_xaml_cs_properties`
+
+**Helper functions**
+
+- :command:`csharp_get_filename_keys`
+- :command:`csharp_get_filename_key_base`
+- :command:`csharp_get_dependentupon_name`
+
+Main functions provided by the module
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. command:: csharp_set_windows_forms_properties
+
+ Sets source file properties for use of Windows Forms. Use this, if your CSharp
+ target uses Windows Forms::
+
+ csharp_set_windows_forms_properties([<file1> [<file2> [...]]])
+
+ ``<fileN>``
+ List of all source files which are relevant for setting the
+ :prop_sf:`VS_CSHARP_<tagname>` properties (including ``.cs``, ``.resx`` and
+ ``.Designer.cs`` extensions).
+
+ In the list of all given files for all files ending with ``.Designer.cs`` and
+ ``.resx`` is searched. For every *designer* or *resource* file a file with the
+ same base name but only ``.cs`` as extension is searched. If this is found, the
+ :prop_sf:`VS_CSHARP_<tagname>` properties are set as follows:
+
+ for the **.cs** file:
+ - VS_CSHARP_SubType "Form"
+
+ for the **.Designer.cs** file (if it exists):
+ - VS_CSHARP_DependentUpon <cs-filename>
+ - VS_CSHARP_DesignTime "" (delete tag if previously defined)
+ - VS_CSHARP_AutoGen ""(delete tag if previously defined)
+
+ for the **.resx** file (if it exists):
+ - VS_RESOURCE_GENERATOR "" (delete tag if previously defined)
+ - VS_CSHARP_DependentUpon <cs-filename>
+ - VS_CSHARP_SubType "Designer"
+
+.. command:: csharp_set_designer_cs_properties
+
+ Sets source file properties of ``.Designer.cs`` files depending on
+ sibling filenames. Use this, if your CSharp target does **not**
+ use Windows Forms (for Windows Forms use
+ :command:`csharp_set_designer_cs_properties` instead)::
+
+ csharp_set_designer_cs_properties([<file1> [<file2> [...]]])
+
+ ``<fileN>``
+ List of all source files which are relevant for setting the
+ :prop_sf:`VS_CSHARP_<tagname>` properties (including ``.cs``,
+ ``.resx``, ``.settings`` and ``.Designer.cs`` extensions).
+
+ In the list of all given files for all files ending with
+ ``.Designer.cs`` is searched. For every *designer* file all files
+ with the same base name but different extensions are searched. If
+ a match is found, the source file properties of the *designer* file
+ are set depending on the extension of the matched file:
+
+ if match is **.resx** file:
+ - VS_CSHARP_AutoGen "True"
+ - VS_CSHARP_DesignTime "True"
+ - VS_CSHARP_DependentUpon <resx-filename>
+
+ if match is **.cs** file:
+ - VS_CSHARP_DependentUpon <cs-filename>
+
+ if match is **.settings** file:
+ - VS_CSHARP_AutoGen "True"
+ - VS_CSHARP_DesignTimeSharedInput "True"
+ - VS_CSHARP_DependentUpon <settings-filename>
+
+.. note::
+
+ Because the source file properties of the ``.Designer.cs`` file are set according
+ to the found matches and every match sets the **VS_CSHARP_DependentUpon**
+ property, there should only be one match for each ``Designer.cs`` file.
+
+.. command:: csharp_set_xaml_cs_properties
+
+ Sets source file properties for use of Windows Presentation Foundation (WPF) and
+ XAML. Use this, if your CSharp target uses WPF/XAML::
+
+ csharp_set_xaml_cs_properties([<file1> [<file2> [...]]])
+
+ ``<fileN>``
+ List of all source files which are relevant for setting the
+ :prop_sf:`VS_CSHARP_<tagname>` properties (including ``.cs``,
+ ``.xaml``, and ``.xaml.cs`` extensions).
+
+ In the list of all given files for all files ending with
+ ``.xaml.cs`` is searched. For every *xaml-cs* file, a file
+ with the same base name but extension ``.xaml`` is searched.
+ If a match is found, the source file properties of the ``.xaml.cs``
+ file are set:
+
+ - VS_CSHARP_DependentUpon <xaml-filename>
+
+Helper functions which are used by the above ones
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. command:: csharp_get_filename_keys
+
+ Helper function which computes a list of key values to identify
+ source files independently of relative/absolute paths given in cmake
+ and eliminates case sensitivity::
+
+ csharp_get_filename_keys(OUT [<file1> [<file2> [...]]])
+
+ ``OUT``
+ Name of the variable in which the list of keys is stored
+
+ ``<fileN>``
+ filename(s) as given to to CSharp target using :command:`add_library`
+ or :command:`add_executable`
+
+ In some way the function applies a canonicalization to the source names.
+ This is necessary to find file matches if the files have been added to
+ the target with different directory prefixes:
+
+ .. code-block:: cmake
+
+ add_library(lib
+ myfile.cs
+ ${CMAKE_CURRENT_SOURCE_DIR}/myfile.Designer.cs)
+
+ set_source_files_properties(myfile.Designer.cs PROPERTIES
+ VS_CSHARP_DependentUpon myfile.cs)
+
+ # this will fail, because in cmake
+ # - ${CMAKE_CURRENT_SOURCE_DIR}/myfile.Designer.cs
+ # - myfile.Designer.cs
+ # are not the same source file. The source file property is not set.
+
+.. command:: csharp_get_filename_key_base
+
+ Returns the full filepath and name **without** extension of a key.
+ KEY is expected to be a key from csharp_get_filename_keys. In BASE
+ the value of KEY without the file extension is returned::
+
+ csharp_get_filename_key_base(BASE KEY)
+
+ ``BASE``
+ Name of the variable with the computed "base" of ``KEY``.
+
+ ``KEY``
+ The key of which the base will be computed. Expected to be a
+ upper case full filename.
+
+.. command:: csharp_get_dependentupon_name
+
+ Computes a string which can be used as value for the source file property
+ :prop_sf:`VS_CSHARP_<tagname>` with *target* being ``DependentUpon``::
+
+ csharp_get_dependentupon_name(NAME FILE)
+
+ ``NAME``
+ Name of the variable with the result value
+
+ ``FILE``
+ Filename to convert to ``<DependentUpon>`` value
+
+ Actually this is only the filename without any path given at the moment.
+
+#]=======================================================================]
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+function(csharp_get_filename_keys OUT)
+ set(${OUT} "")
+ foreach(f ${ARGN})
+ get_filename_component(f ${f} REALPATH)
+ string(TOUPPER ${f} f)
+ list(APPEND ${OUT} ${f})
+ endforeach()
+ set(${OUT} "${${OUT}}" PARENT_SCOPE)
+endfunction()
+
+function(csharp_get_filename_key_base base key)
+ get_filename_component(dir ${key} DIRECTORY)
+ get_filename_component(fil ${key} NAME_WE)
+ set(${base} "${dir}/${fil}" PARENT_SCOPE)
+endfunction()
+
+function(csharp_get_dependentupon_name out in)
+ get_filename_component(${out} ${in} NAME)
+ set(${out} ${${out}} PARENT_SCOPE)
+endfunction()
+
+function(csharp_set_windows_forms_properties)
+ csharp_get_filename_keys(fileKeys ${ARGN})
+ foreach(key ${fileKeys})
+ get_filename_component(ext ${key} EXT)
+ if(${ext} STREQUAL ".DESIGNER.CS" OR
+ ${ext} STREQUAL ".RESX")
+ csharp_get_filename_key_base(NAME_BASE ${key})
+ list(FIND fileKeys "${NAME_BASE}.CS" FILE_INDEX)
+ if(NOT ${FILE_INDEX} EQUAL -1)
+ list(GET ARGN ${FILE_INDEX} FILE_NAME)
+ # set properties of main form file
+ set_source_files_properties("${FILE_NAME}"
+ PROPERTIES
+ VS_CSHARP_SubType "Form")
+ csharp_get_dependentupon_name(LINK "${FILE_NAME}")
+ # set properties of designer file (if found)
+ list(FIND fileKeys "${NAME_BASE}.DESIGNER.CS" FILE_INDEX)
+ if(NOT ${FILE_INDEX} EQUAL -1)
+ list(GET ARGN ${FILE_INDEX} FILE_NAME)
+ set_source_files_properties("${FILE_NAME}"
+ PROPERTIES
+ VS_CSHARP_DependentUpon "${LINK}"
+ VS_CSHARP_DesignTime ""
+ VS_CSHARP_AutoGen "")
+ endif()
+ # set properties of corresponding resource file (if found)
+ list(FIND fileKeys "${NAME_BASE}.RESX" FILE_INDEX)
+ if(NOT ${FILE_INDEX} EQUAL -1)
+ list(GET ARGN ${FILE_INDEX} FILE_NAME)
+ set_source_files_properties("${FILE_NAME}"
+ PROPERTIES
+ VS_RESOURCE_GENERATOR ""
+ VS_CSHARP_DependentUpon "${LINK}"
+ VS_CSHARP_SubType "Designer")
+ endif()
+ endif()
+ endif()
+ endforeach()
+endfunction()
+
+function(csharp_set_designer_cs_properties)
+ csharp_get_filename_keys(fileKeys ${ARGN})
+ set(INDEX -1)
+ foreach(key ${fileKeys})
+ math(EXPR INDEX "${INDEX}+1")
+ list(GET ARGN ${INDEX} source)
+ get_filename_component(ext ${key} EXT)
+ if(${ext} STREQUAL ".DESIGNER.CS")
+ csharp_get_filename_key_base(NAME_BASE ${key})
+ if("${NAME_BASE}.RESX" IN_LIST fileKeys)
+ list(FIND fileKeys "${NAME_BASE}.RESX" FILE_INDEX)
+ list(GET ARGN ${FILE_INDEX} FILE_NAME)
+ csharp_get_dependentupon_name(LINK "${FILE_NAME}")
+ set_source_files_properties("${source}"
+ PROPERTIES
+ VS_CSHARP_AutoGen "True"
+ VS_CSHARP_DesignTime "True"
+ VS_CSHARP_DependentUpon "${LINK}")
+ elseif("${NAME_BASE}.CS" IN_LIST fileKeys)
+ list(FIND fileKeys "${NAME_BASE}.CS" FILE_INDEX)
+ list(GET ARGN ${FILE_INDEX} FILE_NAME)
+ csharp_get_dependentupon_name(LINK "${FILE_NAME}")
+ set_source_files_properties("${source}"
+ PROPERTIES
+ VS_CSHARP_DependentUpon "${LINK}")
+ elseif("${NAME_BASE}.SETTINGS" IN_LIST fileKeys)
+ list(FIND fileKeys "${NAME_BASE}.SETTINGS" FILE_INDEX)
+ list(GET ARGN ${FILE_INDEX} FILE_NAME)
+ csharp_get_dependentupon_name(LINK "${FILE_NAME}")
+ set_source_files_properties("${source}"
+ PROPERTIES
+ VS_CSHARP_AutoGen "True"
+ VS_CSHARP_DesignTimeSharedInput "True"
+ VS_CSHARP_DependentUpon "${LINK}")
+ endif()
+ endif()
+ endforeach()
+endfunction()
+
+function(csharp_set_xaml_cs_properties)
+ csharp_get_filename_keys(fileKeys ${ARGN})
+ set(INDEX -1)
+ foreach(key ${fileKeys})
+ math(EXPR INDEX "${INDEX}+1")
+ list(GET ARGN ${INDEX} source)
+ get_filename_component(ext ${key} EXT)
+ if(${ext} STREQUAL ".XAML.CS")
+ csharp_get_filename_key_base(NAME_BASE ${key})
+ if("${NAME_BASE}.XAML" IN_LIST fileKeys)
+ list(FIND fileKeys "${NAME_BASE}.XAML" FILE_INDEX)
+ list(GET ARGN ${FILE_INDEX} FILE_NAME)
+ csharp_get_dependentupon_name(LINK "${FILE_NAME}")
+ set_source_files_properties("${source}"
+ PROPERTIES
+ VS_CSHARP_DependentUpon "${LINK}")
+ endif()
+ endif()
+ endforeach()
+endfunction()
+
+cmake_policy(POP)
diff --git a/Modules/CTest.cmake b/Modules/CTest.cmake
new file mode 100644
index 0000000..8f8ebb4
--- /dev/null
+++ b/Modules/CTest.cmake
@@ -0,0 +1,267 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CTest
+-----
+
+Configure a project for testing with CTest/CDash
+
+Include this module in the top CMakeLists.txt file of a project to
+enable testing with CTest and dashboard submissions to CDash::
+
+ project(MyProject)
+ ...
+ include(CTest)
+
+The module automatically creates a ``BUILD_TESTING`` option that selects
+whether to enable testing support (``ON`` by default). After including
+the module, use code like::
+
+ if(BUILD_TESTING)
+ # ... CMake code to create tests ...
+ endif()
+
+to creating tests when testing is enabled.
+
+To enable submissions to a CDash server, create a ``CTestConfig.cmake``
+file at the top of the project with content such as::
+
+ set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
+ set(CTEST_SUBMIT_URL "http://my.cdash.org/submit.php?project=MyProject")
+
+(the CDash server can provide the file to a project administrator who
+configures ``MyProject``). Settings in the config file are shared by
+both this ``CTest`` module and the :manual:`ctest(1)` command-line
+:ref:`Dashboard Client` mode (``ctest -S``).
+
+While building a project for submission to CDash, CTest scans the
+build output for errors and warnings and reports them with surrounding
+context from the build log. This generic approach works for all build
+tools, but does not give details about the command invocation that
+produced a given problem. One may get more detailed reports by setting
+the :variable:`CTEST_USE_LAUNCHERS` variable::
+
+ set(CTEST_USE_LAUNCHERS 1)
+
+in the ``CTestConfig.cmake`` file.
+#]=======================================================================]
+
+option(BUILD_TESTING "Build the testing tree." ON)
+
+# function to turn generator name into a version string
+# like vs9 or vs10
+function(GET_VS_VERSION_STRING generator var)
+ string(REGEX REPLACE "Visual Studio ([0-9][0-9]?)($|.*)" "\\1"
+ NUMBER "${generator}")
+ set(ver_string "vs${NUMBER}")
+ set(${var} ${ver_string} PARENT_SCOPE)
+endfunction()
+
+include(CTestUseLaunchers)
+
+if(BUILD_TESTING)
+ # Setup some auxiliary macros
+ macro(SET_IF_NOT_SET var val)
+ if(NOT DEFINED "${var}")
+ set("${var}" "${val}")
+ endif()
+ endmacro()
+
+ macro(SET_IF_SET var val)
+ if(NOT "${val}" STREQUAL "")
+ set("${var}" "${val}")
+ endif()
+ endmacro()
+
+ macro(SET_IF_SET_AND_NOT_SET var val)
+ if(NOT "${val}" STREQUAL "")
+ SET_IF_NOT_SET("${var}" "${val}")
+ endif()
+ endmacro()
+
+ # Make sure testing is enabled
+ enable_testing()
+
+ if(EXISTS "${PROJECT_SOURCE_DIR}/CTestConfig.cmake")
+ include("${PROJECT_SOURCE_DIR}/CTestConfig.cmake")
+ SET_IF_SET_AND_NOT_SET(NIGHTLY_START_TIME "${CTEST_NIGHTLY_START_TIME}")
+ SET_IF_SET_AND_NOT_SET(SUBMIT_URL "${CTEST_SUBMIT_URL}")
+ SET_IF_SET_AND_NOT_SET(DROP_METHOD "${CTEST_DROP_METHOD}")
+ SET_IF_SET_AND_NOT_SET(DROP_SITE "${CTEST_DROP_SITE}")
+ SET_IF_SET_AND_NOT_SET(DROP_SITE_USER "${CTEST_DROP_SITE_USER}")
+ SET_IF_SET_AND_NOT_SET(DROP_SITE_PASSWORD "${CTEST_DROP_SITE_PASWORD}")
+ SET_IF_SET_AND_NOT_SET(DROP_SITE_MODE "${CTEST_DROP_SITE_MODE}")
+ SET_IF_SET_AND_NOT_SET(DROP_LOCATION "${CTEST_DROP_LOCATION}")
+ SET_IF_SET_AND_NOT_SET(TRIGGER_SITE "${CTEST_TRIGGER_SITE}")
+ SET_IF_SET_AND_NOT_SET(UPDATE_TYPE "${CTEST_UPDATE_TYPE}")
+ endif()
+
+ # the project can have a DartConfig.cmake file
+ if(EXISTS "${PROJECT_SOURCE_DIR}/DartConfig.cmake")
+ include("${PROJECT_SOURCE_DIR}/DartConfig.cmake")
+ else()
+ # Dashboard is opened for submissions for a 24 hour period starting at
+ # the specified NIGHTLY_START_TIME. Time is specified in 24 hour format.
+ SET_IF_NOT_SET (NIGHTLY_START_TIME "00:00:00 EDT")
+ SET_IF_NOT_SET(DROP_METHOD "http")
+ SET_IF_NOT_SET (COMPRESS_SUBMISSION ON)
+ endif()
+ SET_IF_NOT_SET (NIGHTLY_START_TIME "00:00:00 EDT")
+
+ if(NOT SUBMIT_URL)
+ set(SUBMIT_URL "${DROP_METHOD}://")
+ if(DROP_SITE_USER)
+ string(APPEND SUBMIT_URL "${DROP_SITE_USER}")
+ if(DROP_SITE_PASSWORD)
+ string(APPEND SUBMIT_URL ":${DROP_SITE_PASSWORD}")
+ endif()
+ string(APPEND SUBMIT_URL "@")
+ endif()
+ string(APPEND SUBMIT_URL "${DROP_SITE}${DROP_LOCATION}")
+ endif()
+
+ if(NOT UPDATE_TYPE)
+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CVS")
+ set(UPDATE_TYPE cvs)
+ elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.svn")
+ set(UPDATE_TYPE svn)
+ elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.bzr")
+ set(UPDATE_TYPE bzr)
+ elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.hg")
+ set(UPDATE_TYPE hg)
+ elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git")
+ set(UPDATE_TYPE git)
+ endif()
+ endif()
+
+ string(TOLOWER "${UPDATE_TYPE}" _update_type)
+ if("${_update_type}" STREQUAL "cvs")
+ find_program(CVSCOMMAND cvs )
+ set(CVS_UPDATE_OPTIONS "-d -A -P" CACHE STRING
+ "Options passed to the cvs update command.")
+ set(UPDATE_COMMAND "${CVSCOMMAND}")
+ set(UPDATE_OPTIONS "${CVS_UPDATE_OPTIONS}")
+ elseif("${_update_type}" STREQUAL "svn")
+ find_program(SVNCOMMAND svn)
+ set(UPDATE_COMMAND "${SVNCOMMAND}")
+ set(UPDATE_OPTIONS "${SVN_UPDATE_OPTIONS}")
+ elseif("${_update_type}" STREQUAL "bzr")
+ find_program(BZRCOMMAND bzr)
+ set(UPDATE_COMMAND "${BZRCOMMAND}")
+ set(UPDATE_OPTIONS "${BZR_UPDATE_OPTIONS}")
+ elseif("${_update_type}" STREQUAL "hg")
+ find_program(HGCOMMAND hg)
+ set(UPDATE_COMMAND "${HGCOMMAND}")
+ set(UPDATE_OPTIONS "${HG_UPDATE_OPTIONS}")
+ elseif("${_update_type}" STREQUAL "git")
+ find_program(GITCOMMAND git)
+ set(UPDATE_COMMAND "${GITCOMMAND}")
+ set(UPDATE_OPTIONS "${GIT_UPDATE_OPTIONS}")
+ elseif("${_update_type}" STREQUAL "p4")
+ find_program(P4COMMAND p4)
+ set(UPDATE_COMMAND "${P4COMMAND}")
+ set(UPDATE_OPTIONS "${P4_UPDATE_OPTIONS}")
+ endif()
+
+ set(DART_TESTING_TIMEOUT 1500 CACHE STRING
+ "Maximum time allowed before CTest will kill the test.")
+
+ set(CTEST_SUBMIT_RETRY_DELAY 5 CACHE STRING
+ "How long to wait between timed-out CTest submissions.")
+ set(CTEST_SUBMIT_RETRY_COUNT 3 CACHE STRING
+ "How many times to retry timed-out CTest submissions.")
+
+ find_program(MEMORYCHECK_COMMAND
+ NAMES purify valgrind boundscheck drmemory cuda-memcheck compute-sanitizer
+ PATHS
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Rational Software\\Purify\\Setup;InstallFolder]"
+ DOC "Path to the memory checking command, used for memory error detection."
+ )
+ set(MEMORYCHECK_SUPPRESSIONS_FILE "" CACHE FILEPATH
+ "File that contains suppressions for the memory checker")
+ find_program(COVERAGE_COMMAND gcov DOC
+ "Path to the coverage program that CTest uses for performing coverage inspection"
+ )
+ set(COVERAGE_EXTRA_FLAGS "-l" CACHE STRING
+ "Extra command line flags to pass to the coverage tool")
+
+ # set the site name
+ if(COMMAND cmake_host_system_information)
+ cmake_host_system_information(RESULT _ctest_hostname QUERY HOSTNAME)
+ set(SITE "${_ctest_hostname}" CACHE STRING "Name of the computer/site where compile is being run")
+ unset(_ctest_hostname)
+ else()
+ # This code path is needed for CMake itself during bootstrap.
+ site_name(SITE)
+ endif()
+ # set the build name
+ if(NOT BUILDNAME)
+ set(DART_COMPILER "${CMAKE_CXX_COMPILER}")
+ if(NOT DART_COMPILER)
+ set(DART_COMPILER "${CMAKE_C_COMPILER}")
+ endif()
+ if(NOT DART_COMPILER)
+ set(DART_COMPILER "unknown")
+ endif()
+ if(WIN32)
+ set(DART_NAME_COMPONENT "NAME_WE")
+ else()
+ set(DART_NAME_COMPONENT "NAME")
+ endif()
+ if(NOT BUILD_NAME_SYSTEM_NAME)
+ set(BUILD_NAME_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}")
+ endif()
+ if(WIN32)
+ set(BUILD_NAME_SYSTEM_NAME "Win32")
+ endif()
+ if(UNIX OR BORLAND)
+ get_filename_component(DART_COMPILER_NAME
+ "${DART_COMPILER}" ${DART_NAME_COMPONENT})
+ else()
+ get_filename_component(DART_COMPILER_NAME
+ "${CMAKE_MAKE_PROGRAM}" ${DART_NAME_COMPONENT})
+ endif()
+ if(DART_COMPILER_NAME MATCHES "devenv")
+ GET_VS_VERSION_STRING("${CMAKE_GENERATOR}" DART_COMPILER_NAME)
+ endif()
+ set(BUILDNAME "${BUILD_NAME_SYSTEM_NAME}-${DART_COMPILER_NAME}")
+ endif()
+
+ # the build command
+ build_command(MAKECOMMAND_DEFAULT_VALUE
+ CONFIGURATION "\${CTEST_CONFIGURATION_TYPE}")
+ set(MAKECOMMAND ${MAKECOMMAND_DEFAULT_VALUE}
+ CACHE STRING "Command to build the project")
+
+ # the default build configuration the ctest build handler will use
+ # if there is no -C arg given to ctest:
+ set(DEFAULT_CTEST_CONFIGURATION_TYPE "$ENV{CMAKE_CONFIG_TYPE}")
+ if(DEFAULT_CTEST_CONFIGURATION_TYPE STREQUAL "")
+ set(DEFAULT_CTEST_CONFIGURATION_TYPE "Release")
+ endif()
+
+ mark_as_advanced(
+ BZRCOMMAND
+ COVERAGE_COMMAND
+ COVERAGE_EXTRA_FLAGS
+ CTEST_SUBMIT_RETRY_DELAY
+ CTEST_SUBMIT_RETRY_COUNT
+ CVSCOMMAND
+ CVS_UPDATE_OPTIONS
+ DART_TESTING_TIMEOUT
+ GITCOMMAND
+ P4COMMAND
+ HGCOMMAND
+ MAKECOMMAND
+ MEMORYCHECK_COMMAND
+ MEMORYCHECK_SUPPRESSIONS_FILE
+ SITE
+ SVNCOMMAND
+ )
+ if(NOT RUN_FROM_DART)
+ set(RUN_FROM_CTEST_OR_DART 1)
+ include(CTestTargets)
+ set(RUN_FROM_CTEST_OR_DART)
+ endif()
+endif()
diff --git a/Modules/CTestCoverageCollectGCOV.cmake b/Modules/CTestCoverageCollectGCOV.cmake
new file mode 100644
index 0000000..a6fa3a4
--- /dev/null
+++ b/Modules/CTestCoverageCollectGCOV.cmake
@@ -0,0 +1,352 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CTestCoverageCollectGCOV
+------------------------
+
+.. versionadded:: 3.2
+
+This module provides the ``ctest_coverage_collect_gcov`` function.
+
+This function runs gcov on all .gcda files found in the binary tree
+and packages the resulting .gcov files into a tar file.
+This tarball also contains the following:
+
+* *data.json* defines the source and build directories for use by CDash.
+* *Labels.json* indicates any :prop_sf:`LABELS` that have been set on the
+ source files.
+* The *uncovered* directory holds any uncovered files found by
+ :variable:`CTEST_EXTRA_COVERAGE_GLOB`.
+
+After generating this tar file, it can be sent to CDash for display with the
+:command:`ctest_submit(CDASH_UPLOAD)` command.
+
+.. command:: ctest_coverage_collect_gcov
+
+ ::
+
+ ctest_coverage_collect_gcov(TARBALL <tarfile>
+ [SOURCE <source_dir>][BUILD <build_dir>]
+ [GCOV_COMMAND <gcov_command>]
+ [GCOV_OPTIONS <options>...]
+ )
+
+ Run gcov and package a tar file for CDash. The options are:
+
+ ``TARBALL <tarfile>``
+ Specify the location of the ``.tar`` file to be created for later
+ upload to CDash. Relative paths will be interpreted with respect
+ to the top-level build directory.
+
+ ``TARBALL_COMPRESSION <option>``
+ .. versionadded:: 3.18
+
+ Specify a compression algorithm for the
+ ``TARBALL`` data file. Using this option reduces the size of the data file
+ before it is submitted to CDash. ``<option>`` must be one of ``GZIP``,
+ ``BZIP2``, ``XZ``, ``ZSTD``, ``FROM_EXT``, or an expression that CMake
+ evaluates as ``FALSE``. The default value is ``BZIP2``.
+
+ If ``FROM_EXT`` is specified, the resulting file will be compressed based on
+ the file extension of the ``<tarfile>`` (i.e. ``.tar.gz`` will use ``GZIP``
+ compression). File extensions that will produce compressed output include
+ ``.tar.gz``, ``.tgz``, ``.tar.bzip2``, ``.tbz``, ``.tar.xz``, and ``.txz``.
+
+ ``SOURCE <source_dir>``
+ Specify the top-level source directory for the build.
+ Default is the value of :variable:`CTEST_SOURCE_DIRECTORY`.
+
+ ``BUILD <build_dir>``
+ Specify the top-level build directory for the build.
+ Default is the value of :variable:`CTEST_BINARY_DIRECTORY`.
+
+ ``GCOV_COMMAND <gcov_command>``
+ Specify the full path to the ``gcov`` command on the machine.
+ Default is the value of :variable:`CTEST_COVERAGE_COMMAND`.
+
+ ``GCOV_OPTIONS <options>...``
+ Specify options to be passed to gcov. The ``gcov`` command
+ is run as ``gcov <options>... -o <gcov-dir> <file>.gcda``.
+ If not specified, the default option is just ``-b -x``.
+
+ ``GLOB``
+ .. versionadded:: 3.6
+
+ Recursively search for .gcda files in build_dir rather than
+ determining search locations by reading TargetDirectories.txt.
+
+ ``DELETE``
+ .. versionadded:: 3.6
+
+ Delete coverage files after they've been packaged into the .tar.
+
+ ``QUIET``
+ Suppress non-error messages that otherwise would have been
+ printed out by this function.
+
+ .. versionadded:: 3.3
+ Added support for the :variable:`CTEST_CUSTOM_COVERAGE_EXCLUDE` variable.
+
+#]=======================================================================]
+
+function(ctest_coverage_collect_gcov)
+ set(options QUIET GLOB DELETE)
+ set(oneValueArgs TARBALL SOURCE BUILD GCOV_COMMAND TARBALL_COMPRESSION)
+ set(multiValueArgs GCOV_OPTIONS)
+ cmake_parse_arguments(GCOV "${options}" "${oneValueArgs}"
+ "${multiValueArgs}" "" ${ARGN} )
+ if(NOT DEFINED GCOV_TARBALL)
+ message(FATAL_ERROR
+ "TARBALL must be specified. for ctest_coverage_collect_gcov")
+ endif()
+ if(NOT DEFINED GCOV_SOURCE)
+ set(source_dir "${CTEST_SOURCE_DIRECTORY}")
+ else()
+ set(source_dir "${GCOV_SOURCE}")
+ endif()
+ if(NOT DEFINED GCOV_BUILD)
+ set(binary_dir "${CTEST_BINARY_DIRECTORY}")
+ else()
+ set(binary_dir "${GCOV_BUILD}")
+ endif()
+ if(NOT DEFINED GCOV_GCOV_COMMAND)
+ set(gcov_command "${CTEST_COVERAGE_COMMAND}")
+ else()
+ set(gcov_command "${GCOV_GCOV_COMMAND}")
+ endif()
+ if(NOT DEFINED GCOV_TARBALL_COMPRESSION)
+ set(GCOV_TARBALL_COMPRESSION "BZIP2")
+ elseif( GCOV_TARBALL_COMPRESSION AND
+ NOT GCOV_TARBALL_COMPRESSION MATCHES "^(GZIP|BZIP2|XZ|ZSTD|FROM_EXT)$")
+ message(FATAL_ERROR "TARBALL_COMPRESSION must be one of OFF, GZIP, "
+ "BZIP2, XZ, ZSTD, or FROM_EXT for ctest_coverage_collect_gcov")
+ endif()
+ # run gcov on each gcda file in the binary tree
+ set(gcda_files)
+ set(label_files)
+ if (GCOV_GLOB)
+ file(GLOB_RECURSE gfiles "${binary_dir}/*.gcda")
+ list(LENGTH gfiles len)
+ # if we have gcda files then also grab the labels file for that target
+ if(${len} GREATER 0)
+ file(GLOB_RECURSE lfiles RELATIVE ${binary_dir} "${binary_dir}/Labels.json")
+ list(APPEND gcda_files ${gfiles})
+ list(APPEND label_files ${lfiles})
+ endif()
+ else()
+ # look for gcda files in the target directories
+ # this will be faster and only look where the files will be
+ file(STRINGS "${binary_dir}/CMakeFiles/TargetDirectories.txt" target_dirs
+ ENCODING UTF-8)
+ foreach(target_dir ${target_dirs})
+ file(GLOB_RECURSE gfiles "${target_dir}/*.gcda")
+ list(LENGTH gfiles len)
+ # if we have gcda files then also grab the labels file for that target
+ if(${len} GREATER 0)
+ file(GLOB_RECURSE lfiles RELATIVE ${binary_dir}
+ "${target_dir}/Labels.json")
+ list(APPEND gcda_files ${gfiles})
+ list(APPEND label_files ${lfiles})
+ endif()
+ endforeach()
+ endif()
+ # return early if no coverage files were found
+ list(LENGTH gcda_files len)
+ if(len EQUAL 0)
+ if (NOT GCOV_QUIET)
+ message("ctest_coverage_collect_gcov: No .gcda files found, "
+ "ignoring coverage request.")
+ endif()
+ return()
+ endif()
+ # setup the dir for the coverage files
+ set(coverage_dir "${binary_dir}/Testing/CoverageInfo")
+ file(MAKE_DIRECTORY "${coverage_dir}")
+ # run gcov, this will produce the .gcov files in the current
+ # working directory
+ if(NOT DEFINED GCOV_GCOV_OPTIONS)
+ set(GCOV_GCOV_OPTIONS -b -x)
+ endif()
+ if (GCOV_QUIET)
+ set(coverage_out_opts
+ OUTPUT_QUIET
+ ERROR_QUIET
+ )
+ else()
+ set(coverage_out_opts
+ OUTPUT_FILE "${coverage_dir}/gcov.log"
+ ERROR_FILE "${coverage_dir}/gcov.log"
+ )
+ endif()
+ execute_process(COMMAND
+ ${gcov_command} ${GCOV_GCOV_OPTIONS} ${gcda_files}
+ RESULT_VARIABLE res
+ WORKING_DIRECTORY ${coverage_dir}
+ ${coverage_out_opts}
+ )
+
+ if (GCOV_DELETE)
+ file(REMOVE ${gcda_files})
+ endif()
+
+ if(NOT "${res}" EQUAL 0)
+ if (NOT GCOV_QUIET)
+ message(STATUS "Error running gcov: ${res}, see\n ${coverage_dir}/gcov.log")
+ endif()
+ endif()
+ # create json file with project information
+ file(WRITE ${coverage_dir}/data.json
+ "{
+ \"Source\": \"${source_dir}\",
+ \"Binary\": \"${binary_dir}\"
+}")
+ # collect the gcov files
+ set(unfiltered_gcov_files)
+ file(GLOB_RECURSE unfiltered_gcov_files RELATIVE ${binary_dir} "${coverage_dir}/*.gcov")
+
+ # if CTEST_EXTRA_COVERAGE_GLOB was specified we search for files
+ # that might be uncovered
+ if (DEFINED CTEST_EXTRA_COVERAGE_GLOB)
+ set(uncovered_files)
+ foreach(search_entry IN LISTS CTEST_EXTRA_COVERAGE_GLOB)
+ if(NOT GCOV_QUIET)
+ message("Add coverage glob: ${search_entry}")
+ endif()
+ file(GLOB_RECURSE matching_files "${source_dir}/${search_entry}")
+ if (matching_files)
+ list(APPEND uncovered_files "${matching_files}")
+ endif()
+ endforeach()
+ endif()
+
+ set(gcov_files)
+ foreach(gcov_file ${unfiltered_gcov_files})
+ file(STRINGS ${binary_dir}/${gcov_file} first_line LIMIT_COUNT 1 ENCODING UTF-8)
+
+ set(is_excluded false)
+ if(first_line MATCHES "^ -: 0:Source:(.*)$")
+ set(source_file ${CMAKE_MATCH_1})
+ elseif(NOT GCOV_QUIET)
+ message(STATUS "Could not determine source file corresponding to: ${gcov_file}")
+ endif()
+
+ foreach(exclude_entry IN LISTS CTEST_CUSTOM_COVERAGE_EXCLUDE)
+ if(source_file MATCHES "${exclude_entry}")
+ set(is_excluded true)
+
+ if(NOT GCOV_QUIET)
+ message("Excluding coverage for: ${source_file} which matches ${exclude_entry}")
+ endif()
+
+ break()
+ endif()
+ endforeach()
+
+ get_filename_component(resolved_source_file "${source_file}" ABSOLUTE)
+ foreach(uncovered_file IN LISTS uncovered_files)
+ get_filename_component(resolved_uncovered_file "${uncovered_file}" ABSOLUTE)
+ if (resolved_uncovered_file STREQUAL resolved_source_file)
+ list(REMOVE_ITEM uncovered_files "${uncovered_file}")
+ endif()
+ endforeach()
+
+ if(NOT is_excluded)
+ list(APPEND gcov_files ${gcov_file})
+ endif()
+ endforeach()
+
+ foreach (uncovered_file ${uncovered_files})
+ # Check if this uncovered file should be excluded.
+ set(is_excluded false)
+ foreach(exclude_entry IN LISTS CTEST_CUSTOM_COVERAGE_EXCLUDE)
+ if(uncovered_file MATCHES "${exclude_entry}")
+ set(is_excluded true)
+ if(NOT GCOV_QUIET)
+ message("Excluding coverage for: ${uncovered_file} which matches ${exclude_entry}")
+ endif()
+ break()
+ endif()
+ endforeach()
+ if(is_excluded)
+ continue()
+ endif()
+
+ # Copy from source to binary dir, preserving any intermediate subdirectories.
+ get_filename_component(filename "${uncovered_file}" NAME)
+ get_filename_component(relative_path "${uncovered_file}" DIRECTORY)
+ string(REPLACE "${source_dir}" "" relative_path "${relative_path}")
+ if (relative_path)
+ # Strip leading slash.
+ string(SUBSTRING "${relative_path}" 1 -1 relative_path)
+ endif()
+ file(COPY ${uncovered_file} DESTINATION ${binary_dir}/uncovered/${relative_path})
+ if(relative_path)
+ list(APPEND uncovered_files_for_tar uncovered/${relative_path}/${filename})
+ else()
+ list(APPEND uncovered_files_for_tar uncovered/${filename})
+ endif()
+ endforeach()
+
+ # tar up the coverage info with the same date so that the md5
+ # sum will be the same for the tar file independent of file time
+ # stamps
+ string(REPLACE ";" "\n" gcov_files "${gcov_files}")
+ string(REPLACE ";" "\n" label_files "${label_files}")
+ string(REPLACE ";" "\n" uncovered_files_for_tar "${uncovered_files_for_tar}")
+ file(WRITE "${coverage_dir}/coverage_file_list.txt"
+ "${gcov_files}
+${coverage_dir}/data.json
+${label_files}
+${uncovered_files_for_tar}
+")
+
+ # Prepare tar command line arguments
+
+ set(tar_opts "")
+ # Select data compression mode
+ if( GCOV_TARBALL_COMPRESSION STREQUAL "FROM_EXT")
+ if( GCOV_TARBALL MATCHES [[\.(tgz|tar.gz)$]] )
+ string(APPEND tar_opts "z")
+ elseif( GCOV_TARBALL MATCHES [[\.(txz|tar.xz)$]] )
+ string(APPEND tar_opts "J")
+ elseif( GCOV_TARBALL MATCHES [[\.(tbz|tar.bz)$]] )
+ string(APPEND tar_opts "j")
+ endif()
+ elseif(GCOV_TARBALL_COMPRESSION STREQUAL "GZIP")
+ string(APPEND tar_opts "z")
+ elseif(GCOV_TARBALL_COMPRESSION STREQUAL "XZ")
+ string(APPEND tar_opts "J")
+ elseif(GCOV_TARBALL_COMPRESSION STREQUAL "BZIP2")
+ string(APPEND tar_opts "j")
+ elseif(GCOV_TARBALL_COMPRESSION STREQUAL "ZSTD")
+ set(zstd_tar_opt "--zstd")
+ endif()
+ # Verbosity options
+ if(NOT GCOV_QUIET AND NOT tar_opts MATCHES v)
+ string(APPEND tar_opts "v")
+ endif()
+ # Prepend option 'c' specifying 'create'
+ string(PREPEND tar_opts "c")
+ # Append option 'f' so that the next argument is the filename
+ string(APPEND tar_opts "f")
+
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E tar ${tar_opts} ${GCOV_TARBALL} ${zstd_tar_opt}
+ "--mtime=1970-01-01 0:0:0 UTC"
+ "--format=gnutar"
+ --files-from=${coverage_dir}/coverage_file_list.txt
+ WORKING_DIRECTORY ${binary_dir})
+
+ if (GCOV_DELETE)
+ foreach(gcov_file ${unfiltered_gcov_files})
+ file(REMOVE ${binary_dir}/${gcov_file})
+ endforeach()
+ file(REMOVE ${coverage_dir}/coverage_file_list.txt)
+ file(REMOVE ${coverage_dir}/data.json)
+ if (EXISTS ${binary_dir}/uncovered)
+ file(REMOVE ${binary_dir}/uncovered)
+ endif()
+ endif()
+
+endfunction()
diff --git a/Modules/CTestScriptMode.cmake b/Modules/CTestScriptMode.cmake
new file mode 100644
index 0000000..7af3577
--- /dev/null
+++ b/Modules/CTestScriptMode.cmake
@@ -0,0 +1,20 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CTestScriptMode
+---------------
+
+
+
+This file is read by ctest in script mode (-S)
+#]=======================================================================]
+
+# Determine the current system, so this information can be used
+# in ctest scripts
+include(CMakeDetermineSystem)
+
+# Also load the system specific file, which sets up e.g. the search paths.
+# This makes the FIND_XXX() calls work much better
+include(CMakeSystemSpecificInformation)
+
diff --git a/Modules/CTestTargets.cmake b/Modules/CTestTargets.cmake
new file mode 100644
index 0000000..838fbbf
--- /dev/null
+++ b/Modules/CTestTargets.cmake
@@ -0,0 +1,93 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+if(NOT RUN_FROM_CTEST_OR_DART)
+ message(FATAL_ERROR "Do not include CTestTargets.cmake directly")
+endif()
+
+if(NOT PROJECT_BINARY_DIR)
+ message(FATAL_ERROR "Do not include(CTest) before calling project().")
+endif()
+
+# make directories in the binary tree
+file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/Testing/Temporary)
+get_filename_component(CMAKE_HOST_PATH ${CMAKE_COMMAND} PATH)
+set(CMAKE_TARGET_PATH ${EXECUTABLE_OUTPUT_PATH})
+find_program(CMAKE_CTEST_COMMAND ctest ${CMAKE_HOST_PATH} ${CMAKE_TARGET_PATH})
+mark_as_advanced(CMAKE_CTEST_COMMAND)
+
+# Use CTest
+# configure files
+
+if(CTEST_NEW_FORMAT)
+ configure_file(
+ ${CMAKE_ROOT}/Modules/DartConfiguration.tcl.in
+ ${PROJECT_BINARY_DIR}/CTestConfiguration.ini )
+else()
+ configure_file(
+ ${CMAKE_ROOT}/Modules/DartConfiguration.tcl.in
+ ${PROJECT_BINARY_DIR}/DartConfiguration.tcl )
+endif()
+
+#
+# Section 3:
+#
+# Custom targets to perform dashboard builds and submissions.
+# These should NOT need to be modified from project to project.
+#
+
+set(__conf_types "")
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ # We need to pass the configuration type on the test command line.
+ set(__conf_types -C "${CMAKE_CFG_INTDIR}")
+endif()
+
+# Add convenience targets. Do this at most once in case of nested
+# projects.
+define_property(GLOBAL PROPERTY CTEST_TARGETS_ADDED
+ BRIEF_DOCS "Internal property used by CTestTargets module."
+ FULL_DOCS "Set by the CTestTargets module to track addition of testing targets."
+ )
+get_property(_CTEST_TARGETS_ADDED GLOBAL PROPERTY CTEST_TARGETS_ADDED)
+if(NOT _CTEST_TARGETS_ADDED)
+ set_property(GLOBAL PROPERTY CTEST_TARGETS_ADDED 1)
+
+ # For all generators add basic testing targets.
+ foreach(mode Experimental Nightly Continuous NightlyMemoryCheck)
+ add_custom_target(${mode}
+ ${CMAKE_CTEST_COMMAND} ${__conf_types} -D ${mode}
+ USES_TERMINAL
+ )
+ set_property(TARGET ${mode} PROPERTY RULE_LAUNCH_CUSTOM "")
+ set_property(TARGET ${mode} PROPERTY FOLDER "CTestDashboardTargets")
+ endforeach()
+
+ # For Makefile generators add more granular targets.
+ if("${CMAKE_GENERATOR}" MATCHES "(Ninja|Make)")
+ # Make targets for Experimental builds
+ foreach(mode Nightly Experimental Continuous)
+ foreach(testtype
+ Start Update Configure Build Test Coverage MemCheck Submit
+ # missing purify
+ )
+ add_custom_target(${mode}${testtype}
+ ${CMAKE_CTEST_COMMAND} ${__conf_types} -D ${mode}${testtype}
+ USES_TERMINAL
+ )
+ set_property(TARGET ${mode}${testtype} PROPERTY RULE_LAUNCH_CUSTOM "")
+ set_property(TARGET ${mode}${testtype} PROPERTY FOLDER "CTestDashboardTargets")
+ endforeach()
+ endforeach()
+ endif()
+
+ # If requested, add an alias that is the equivalent of the built-in "test"
+ # or "RUN_TESTS" target:
+ if(CTEST_TEST_TARGET_ALIAS)
+ add_custom_target(${CTEST_TEST_TARGET_ALIAS}
+ ${CMAKE_CTEST_COMMAND} ${__conf_types}
+ USES_TERMINAL
+ )
+ endif()
+endif()
diff --git a/Modules/CTestUseLaunchers.cmake b/Modules/CTestUseLaunchers.cmake
new file mode 100644
index 0000000..23a206b
--- /dev/null
+++ b/Modules/CTestUseLaunchers.cmake
@@ -0,0 +1,73 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CTestUseLaunchers
+-----------------
+
+Set the RULE_LAUNCH_* global properties when CTEST_USE_LAUNCHERS is on.
+
+CTestUseLaunchers is automatically included when you include(CTest).
+However, it is split out into its own module file so projects can use
+the CTEST_USE_LAUNCHERS functionality independently.
+
+To use launchers, set CTEST_USE_LAUNCHERS to ON in a ctest -S
+dashboard script, and then also set it in the cache of the configured
+project. Both cmake and ctest need to know the value of it for the
+launchers to work properly. CMake needs to know in order to generate
+proper build rules, and ctest, in order to produce the proper error
+and warning analysis.
+
+For convenience, you may set the ENV variable
+CTEST_USE_LAUNCHERS_DEFAULT in your ctest -S script, too. Then, as
+long as your CMakeLists uses include(CTest) or
+include(CTestUseLaunchers), it will use the value of the ENV variable
+to initialize a CTEST_USE_LAUNCHERS cache variable. This cache
+variable initialization only occurs if CTEST_USE_LAUNCHERS is not
+already defined.
+
+.. versionadded:: 3.8
+ If CTEST_USE_LAUNCHERS is on in a ctest -S script
+ the ctest_configure command will add -DCTEST_USE_LAUNCHERS:BOOL=TRUE
+ to the cmake command used to configure the project.
+#]=======================================================================]
+
+if(NOT DEFINED CTEST_USE_LAUNCHERS AND DEFINED ENV{CTEST_USE_LAUNCHERS_DEFAULT})
+ set(CTEST_USE_LAUNCHERS "$ENV{CTEST_USE_LAUNCHERS_DEFAULT}"
+ CACHE INTERNAL "CTEST_USE_LAUNCHERS initial value from ENV")
+endif()
+
+if(NOT "${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
+ set(CTEST_USE_LAUNCHERS 0)
+endif()
+
+if(CTEST_USE_LAUNCHERS)
+ set(__launch_common_options
+ "--target-name <TARGET_NAME> --build-dir <CMAKE_CURRENT_BINARY_DIR>")
+
+ set(__launch_compile_options
+ "${__launch_common_options} --output <OBJECT> --source <SOURCE> --language <LANGUAGE>")
+
+ set(__launch_link_options
+ "${__launch_common_options} --output <TARGET> --target-type <TARGET_TYPE> --language <LANGUAGE>")
+
+ set(__launch_custom_options
+ "${__launch_common_options} --output <OUTPUT>")
+
+ if("${CMAKE_GENERATOR}" MATCHES "Ninja")
+ string(APPEND __launch_compile_options " --filter-prefix <CMAKE_CL_SHOWINCLUDES_PREFIX>")
+ endif()
+
+ set(CTEST_LAUNCH_COMPILE
+ "\"${CMAKE_CTEST_COMMAND}\" --launch ${__launch_compile_options} --")
+
+ set(CTEST_LAUNCH_LINK
+ "\"${CMAKE_CTEST_COMMAND}\" --launch ${__launch_link_options} --")
+
+ set(CTEST_LAUNCH_CUSTOM
+ "\"${CMAKE_CTEST_COMMAND}\" --launch ${__launch_custom_options} --")
+
+ set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CTEST_LAUNCH_COMPILE}")
+ set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CTEST_LAUNCH_LINK}")
+ set_property(GLOBAL PROPERTY RULE_LAUNCH_CUSTOM "${CTEST_LAUNCH_CUSTOM}")
+endif()
diff --git a/Modules/CheckCCompilerFlag.cmake b/Modules/CheckCCompilerFlag.cmake
new file mode 100644
index 0000000..335b437
--- /dev/null
+++ b/Modules/CheckCCompilerFlag.cmake
@@ -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.
+
+#[=======================================================================[.rst:
+CheckCCompilerFlag
+------------------
+
+Check whether the C compiler supports a given flag.
+
+.. command:: check_c_compiler_flag
+
+ .. code-block:: cmake
+
+ check_c_compiler_flag(<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_c_source_compiles`` macro from the
+:module:`CheckCSourceCompiles` 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_C_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags
+ in such variables may cause a false negative for this check.
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(CheckCSourceCompiles)
+include(Internal/CheckCompilerFlag)
+
+macro (CHECK_C_COMPILER_FLAG _FLAG _RESULT)
+ cmake_check_compiler_flag(C "${_FLAG}" ${_RESULT})
+endmacro ()
diff --git a/Modules/CheckCSourceCompiles.cmake b/Modules/CheckCSourceCompiles.cmake
new file mode 100644
index 0000000..b24da49
--- /dev/null
+++ b/Modules/CheckCSourceCompiles.cmake
@@ -0,0 +1,77 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckCSourceCompiles
+--------------------
+
+Check if given C source compiles and links into an executable.
+
+.. command:: check_c_source_compiles
+
+ .. code-block:: cmake
+
+ check_c_source_compiles(<code> <resultVar>
+ [FAIL_REGEX <regex1> [<regex2>...]])
+
+ Check that the source supplied in ``<code>`` can be compiled as a C source
+ file and linked as an executable (so it must contain at least a ``main()``
+ function). The result will be stored in the internal cache variable specified
+ by ``<resultVar>``, with a boolean true value for success and boolean false
+ for failure. If ``FAIL_REGEX`` is provided, then failure is determined by
+ checking if anything in the output matches any of the specified regular
+ expressions.
+
+ The underlying check is performed by the :command:`try_compile` command. The
+ compile and link commands can be influenced by setting any of the following
+ variables prior to calling ``check_c_source_compiles()``:
+
+ ``CMAKE_REQUIRED_FLAGS``
+ Additional flags to pass to the compiler. Note that the contents of
+ :variable:`CMAKE_C_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated
+ configuration-specific variable are automatically added to the compiler
+ command before the contents of ``CMAKE_REQUIRED_FLAGS``.
+
+ ``CMAKE_REQUIRED_DEFINITIONS``
+ A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form
+ ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by
+ ``<resultVar>`` will also be added automatically.
+
+ ``CMAKE_REQUIRED_INCLUDES``
+ A :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler. These will be the only header search paths used by
+ ``try_compile()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES`
+ directory property will be ignored.
+
+ ``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+
+ A :ref:`;-list <CMake Language Lists>` of options to add to the link
+ command (see :command:`try_compile` for further details).
+
+ ``CMAKE_REQUIRED_LIBRARIES``
+ A :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. These can be the name of system libraries or they can be
+ :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for
+ further details).
+
+ ``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+
+ If this variable evaluates to a boolean true value, all status messages
+ associated with the check will be suppressed.
+
+ The check is only performed once, with the result cached in the variable
+ named by ``<resultVar>``. Every subsequent CMake run will re-use this cached
+ value rather than performing the check again, even if the ``<code>`` changes.
+ In order to force the check to be re-evaluated, the variable named by
+ ``<resultVar>`` must be manually removed from the cache.
+
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(Internal/CheckSourceCompiles)
+
+macro(CHECK_C_SOURCE_COMPILES SOURCE VAR)
+ cmake_check_source_compiles(C "${SOURCE}" ${VAR} ${ARGN})
+endmacro()
diff --git a/Modules/CheckCSourceRuns.cmake b/Modules/CheckCSourceRuns.cmake
new file mode 100644
index 0000000..a6081ff
--- /dev/null
+++ b/Modules/CheckCSourceRuns.cmake
@@ -0,0 +1,78 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckCSourceRuns
+----------------
+
+Check if given C source compiles and links into an executable and can
+subsequently be run.
+
+.. command:: check_c_source_runs
+
+ .. code-block:: cmake
+
+ check_c_source_runs(<code> <resultVar>)
+
+ Check that the source supplied in ``<code>`` can be compiled as a C source
+ file, linked as an executable and then run. The ``<code>`` must contain at
+ least a ``main()`` function. If the ``<code>`` could be built and run
+ successfully, the internal cache variable specified by ``<resultVar>`` will
+ be set to 1, otherwise it will be set to an value that evaluates to boolean
+ false (e.g. an empty string or an error message).
+
+ The underlying check is performed by the :command:`try_run` command. The
+ compile and link commands can be influenced by setting any of the following
+ variables prior to calling ``check_c_source_runs()``:
+
+ ``CMAKE_REQUIRED_FLAGS``
+ Additional flags to pass to the compiler. Note that the contents of
+ :variable:`CMAKE_C_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated
+ configuration-specific variable are automatically added to the compiler
+ command before the contents of ``CMAKE_REQUIRED_FLAGS``.
+
+ ``CMAKE_REQUIRED_DEFINITIONS``
+ A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form
+ ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by
+ ``<resultVar>`` will also be added automatically.
+
+ ``CMAKE_REQUIRED_INCLUDES``
+ A :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler. These will be the only header search paths used by
+ ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES`
+ directory property will be ignored.
+
+ ``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+
+ A :ref:`;-list <CMake Language Lists>` of options to add to the link
+ command (see :command:`try_run` for further details).
+
+ ``CMAKE_REQUIRED_LIBRARIES``
+ A :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. These can be the name of system libraries or they can be
+ :ref:`Imported Targets <Imported Targets>` (see :command:`try_run` for
+ further details).
+
+ ``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+
+ If this variable evaluates to a boolean true value, all status messages
+ associated with the check will be suppressed.
+
+ The check is only performed once, with the result cached in the variable
+ named by ``<resultVar>``. Every subsequent CMake run will re-use this cached
+ value rather than performing the check again, even if the ``<code>`` changes.
+ In order to force the check to be re-evaluated, the variable named by
+ ``<resultVar>`` must be manually removed from the cache.
+
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(Internal/CheckSourceRuns)
+
+macro(CHECK_C_SOURCE_RUNS SOURCE VAR)
+ set(_CheckSourceRuns_old_signature 1)
+ cmake_check_source_runs(C "${SOURCE}" ${VAR} ${ARGN})
+ unset(_CheckSourceRuns_old_signature)
+endmacro()
diff --git a/Modules/CheckCXXCompilerFlag.cmake b/Modules/CheckCXXCompilerFlag.cmake
new file mode 100644
index 0000000..3bc3463
--- /dev/null
+++ b/Modules/CheckCXXCompilerFlag.cmake
@@ -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.
+
+#[=======================================================================[.rst:
+CheckCXXCompilerFlag
+------------------------
+
+Check whether the CXX compiler supports a given flag.
+
+.. command:: check_cxx_compiler_flag
+
+ .. code-block:: cmake
+
+ check_cxx_compiler_flag(<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_cxx_source_compiles`` macro from the
+:module:`CheckCXXSourceCompiles` 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_CXX_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags
+ in such variables may cause a false negative for this check.
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(CheckCXXSourceCompiles)
+include(Internal/CheckCompilerFlag)
+
+macro (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT)
+ cmake_check_compiler_flag(CXX "${_FLAG}" ${_RESULT})
+endmacro ()
diff --git a/Modules/CheckCXXSourceCompiles.cmake b/Modules/CheckCXXSourceCompiles.cmake
new file mode 100644
index 0000000..502bfa7
--- /dev/null
+++ b/Modules/CheckCXXSourceCompiles.cmake
@@ -0,0 +1,77 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckCXXSourceCompiles
+----------------------
+
+Check if given C++ source compiles and links into an executable.
+
+.. command:: check_cxx_source_compiles
+
+ .. code-block:: cmake
+
+ check_cxx_source_compiles(<code> <resultVar>
+ [FAIL_REGEX <regex1> [<regex2>...]])
+
+ Check that the source supplied in ``<code>`` can be compiled as a C++ source
+ file and linked as an executable (so it must contain at least a ``main()``
+ function). The result will be stored in the internal cache variable specified
+ by ``<resultVar>``, with a boolean true value for success and boolean false
+ for failure. If ``FAIL_REGEX`` is provided, then failure is determined by
+ checking if anything in the output matches any of the specified regular
+ expressions.
+
+ The underlying check is performed by the :command:`try_compile` command. The
+ compile and link commands can be influenced by setting any of the following
+ variables prior to calling ``check_cxx_source_compiles()``:
+
+ ``CMAKE_REQUIRED_FLAGS``
+ Additional flags to pass to the compiler. Note that the contents of
+ :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated
+ configuration-specific variable are automatically added to the compiler
+ command before the contents of ``CMAKE_REQUIRED_FLAGS``.
+
+ ``CMAKE_REQUIRED_DEFINITIONS``
+ A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form
+ ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by
+ ``<resultVar>`` will also be added automatically.
+
+ ``CMAKE_REQUIRED_INCLUDES``
+ A :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler. These will be the only header search paths used by
+ ``try_compile()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES`
+ directory property will be ignored.
+
+ ``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+
+ A :ref:`;-list <CMake Language Lists>` of options to add to the link
+ command (see :command:`try_compile` for further details).
+
+ ``CMAKE_REQUIRED_LIBRARIES``
+ A :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. These can be the name of system libraries or they can be
+ :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for
+ further details).
+
+ ``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+
+ If this variable evaluates to a boolean true value, all status messages
+ associated with the check will be suppressed.
+
+ The check is only performed once, with the result cached in the variable
+ named by ``<resultVar>``. Every subsequent CMake run will re-use this cached
+ value rather than performing the check again, even if the ``<code>`` changes.
+ In order to force the check to be re-evaluated, the variable named by
+ ``<resultVar>`` must be manually removed from the cache.
+
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(Internal/CheckSourceCompiles)
+
+macro(CHECK_CXX_SOURCE_COMPILES SOURCE VAR)
+ cmake_check_source_compiles(CXX "${SOURCE}" ${VAR} ${ARGN})
+endmacro()
diff --git a/Modules/CheckCXXSourceRuns.cmake b/Modules/CheckCXXSourceRuns.cmake
new file mode 100644
index 0000000..af03453
--- /dev/null
+++ b/Modules/CheckCXXSourceRuns.cmake
@@ -0,0 +1,78 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckCXXSourceRuns
+------------------
+
+Check if given C++ source compiles and links into an executable and can
+subsequently be run.
+
+.. command:: check_cxx_source_runs
+
+ .. code-block:: cmake
+
+ check_cxx_source_runs(<code> <resultVar>)
+
+ Check that the source supplied in ``<code>`` can be compiled as a C++ source
+ file, linked as an executable and then run. The ``<code>`` must contain at
+ least a ``main()`` function. If the ``<code>`` could be built and run
+ successfully, the internal cache variable specified by ``<resultVar>`` will
+ be set to 1, otherwise it will be set to an value that evaluates to boolean
+ false (e.g. an empty string or an error message).
+
+ The underlying check is performed by the :command:`try_run` command. The
+ compile and link commands can be influenced by setting any of the following
+ variables prior to calling ``check_cxx_source_runs()``:
+
+ ``CMAKE_REQUIRED_FLAGS``
+ Additional flags to pass to the compiler. Note that the contents of
+ :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated
+ configuration-specific variable are automatically added to the compiler
+ command before the contents of ``CMAKE_REQUIRED_FLAGS``.
+
+ ``CMAKE_REQUIRED_DEFINITIONS``
+ A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form
+ ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by
+ ``<resultVar>`` will also be added automatically.
+
+ ``CMAKE_REQUIRED_INCLUDES``
+ A :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler. These will be the only header search paths used by
+ ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES`
+ directory property will be ignored.
+
+ ``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+
+ A :ref:`;-list <CMake Language Lists>` of options to add to the link
+ command (see :command:`try_run` for further details).
+
+ ``CMAKE_REQUIRED_LIBRARIES``
+ A :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. These can be the name of system libraries or they can be
+ :ref:`Imported Targets <Imported Targets>` (see :command:`try_run` for
+ further details).
+
+ ``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+
+ If this variable evaluates to a boolean true value, all status messages
+ associated with the check will be suppressed.
+
+ The check is only performed once, with the result cached in the variable
+ named by ``<resultVar>``. Every subsequent CMake run will re-use this cached
+ value rather than performing the check again, even if the ``<code>`` changes.
+ In order to force the check to be re-evaluated, the variable named by
+ ``<resultVar>`` must be manually removed from the cache.
+
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(Internal/CheckSourceRuns)
+
+macro(CHECK_CXX_SOURCE_RUNS SOURCE VAR)
+ set(_CheckSourceRuns_old_signature 1)
+ cmake_check_source_runs(CXX "${SOURCE}" ${VAR} ${ARGN})
+ unset(_CheckSourceRuns_old_signature)
+endmacro()
diff --git a/Modules/CheckCXXSymbolExists.cmake b/Modules/CheckCXXSymbolExists.cmake
new file mode 100644
index 0000000..b4da4fa
--- /dev/null
+++ b/Modules/CheckCXXSymbolExists.cmake
@@ -0,0 +1,78 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckCXXSymbolExists
+--------------------
+
+Check if a symbol exists as a function, variable, or macro in ``C++``.
+
+.. command:: check_cxx_symbol_exists
+
+ .. code-block:: cmake
+
+ check_cxx_symbol_exists(<symbol> <files> <variable>)
+
+ Check that the ``<symbol>`` is available after including given header
+ ``<files>`` and store the result in a ``<variable>``. Specify the list of
+ files in one argument as a semicolon-separated list.
+ ``check_cxx_symbol_exists()`` can be used to check for symbols as seen by
+ the C++ compiler, as opposed to :command:`check_symbol_exists`, which always
+ uses the ``C`` compiler.
+
+ If the header files define the symbol as a macro it is considered
+ available and assumed to work. If the header files declare the symbol
+ as a function or variable then the symbol must also be available for
+ linking. If the symbol is a type, enum value, or C++ template it will
+ not be recognized: consider using the :module:`CheckTypeSize`
+ or :module:`CheckCXXSourceCompiles` module instead.
+
+.. note::
+
+ This command is unreliable when ``<symbol>`` is (potentially) an overloaded
+ function. Since there is no reliable way to predict whether a given function
+ in the system environment may be defined as an overloaded function or may be
+ an overloaded function on other systems or will become so in the future, it
+ is generally advised to use the :module:`CheckCXXSourceCompiles` module for
+ checking any function symbol (unless somehow you surely know the checked
+ function is not overloaded on other systems or will not be so in the
+ future).
+
+The following variables may be set before calling this macro to modify
+the way the check is run:
+
+``CMAKE_REQUIRED_FLAGS``
+ string of compile command line flags.
+``CMAKE_REQUIRED_DEFINITIONS``
+ a :ref:`;-list <CMake Language Lists>` of macros to define (-DFOO=bar).
+``CMAKE_REQUIRED_INCLUDES``
+ a :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler.
+``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+ a :ref:`;-list <CMake Language Lists>` of options to add to the link command.
+``CMAKE_REQUIRED_LIBRARIES``
+ a :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. See policy :policy:`CMP0075`.
+``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+ execute quietly without messages.
+
+For example:
+
+.. code-block:: cmake
+
+ include(CheckCXXSymbolExists)
+
+ # Check for macro SEEK_SET
+ check_cxx_symbol_exists(SEEK_SET "cstdio" HAVE_SEEK_SET)
+ # Check for function std::fopen
+ check_cxx_symbol_exists(std::fopen "cstdio" HAVE_STD_FOPEN)
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(CheckSymbolExists)
+
+macro(CHECK_CXX_SYMBOL_EXISTS SYMBOL FILES VARIABLE)
+ __CHECK_SYMBOL_EXISTS_IMPL("${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.cxx" "${SYMBOL}" "${FILES}" "${VARIABLE}" )
+endmacro()
diff --git a/Modules/CheckCompilerFlag.cmake b/Modules/CheckCompilerFlag.cmake
new file mode 100644
index 0000000..77c07b9
--- /dev/null
+++ b/Modules/CheckCompilerFlag.cmake
@@ -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.
+
+#[=======================================================================[.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(Internal/CheckCompilerFlag)
+
+function(CHECK_COMPILER_FLAG _lang _flag _var)
+ cmake_check_compiler_flag(${_lang} "${_flag}" ${_var})
+endfunction()
diff --git a/Modules/CheckForPthreads.c b/Modules/CheckForPthreads.c
new file mode 100644
index 0000000..e70ceb1
--- /dev/null
+++ b/Modules/CheckForPthreads.c
@@ -0,0 +1,15 @@
+#include <pthread.h>
+
+void* start_routine(void* args)
+{
+ return args;
+}
+
+int main(void)
+{
+ /* This is a compile and link test, no code to actually run things. */
+ pthread_t thread;
+ pthread_create(&thread, 0, start_routine, 0);
+ pthread_join(thread, 0);
+ return 0;
+}
diff --git a/Modules/CheckFortranCompilerFlag.cmake b/Modules/CheckFortranCompilerFlag.cmake
new file mode 100644
index 0000000..5b1cd02
--- /dev/null
+++ b/Modules/CheckFortranCompilerFlag.cmake
@@ -0,0 +1,43 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckFortranCompilerFlag
+------------------------
+
+.. versionadded:: 3.3
+
+Check whether the Fortran compiler supports a given flag.
+
+.. command:: check_fortran_compiler_flag
+
+ .. code-block:: cmake
+
+ check_fortran_compiler_flag(<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_fortran_source_compiles`` macro from the
+:module:`CheckFortranSourceCompiles` 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_Fortran_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags
+ in such variables may cause a false negative for this check.
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(CheckFortranSourceCompiles)
+include(Internal/CheckCompilerFlag)
+
+macro (CHECK_FORTRAN_COMPILER_FLAG _FLAG _RESULT)
+ cmake_check_compiler_flag(Fortran "${_FLAG}" ${_RESULT})
+endmacro ()
diff --git a/Modules/CheckFortranFunctionExists.cmake b/Modules/CheckFortranFunctionExists.cmake
new file mode 100644
index 0000000..ad72e2f
--- /dev/null
+++ b/Modules/CheckFortranFunctionExists.cmake
@@ -0,0 +1,85 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckFortranFunctionExists
+--------------------------
+
+Check if a Fortran function exists.
+
+.. command:: CHECK_FORTRAN_FUNCTION_EXISTS
+
+ .. code-block:: cmake
+
+ CHECK_FORTRAN_FUNCTION_EXISTS(<function> <result>)
+
+ where
+
+ ``<function>``
+ the name of the Fortran function
+ ``<result>``
+ variable to store the result; will be created as an internal cache variable.
+
+The following variables may be set before calling this macro to modify
+the way the check is run:
+
+``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+ A :ref:`;-list <CMake Language Lists>` of options to add to the link
+ command (see :command:`try_compile` for further details).
+
+``CMAKE_REQUIRED_LIBRARIES``
+ A :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. These can be the name of system libraries or they can be
+ :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for
+ further details).
+#]=======================================================================]
+
+include_guard(GLOBAL)
+
+macro(CHECK_FORTRAN_FUNCTION_EXISTS FUNCTION VARIABLE)
+ if(NOT DEFINED ${VARIABLE})
+ message(CHECK_START "Looking for Fortran ${FUNCTION}")
+ if(CMAKE_REQUIRED_LINK_OPTIONS)
+ set(CHECK_FUNCTION_EXISTS_ADD_LINK_OPTIONS
+ LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
+ else()
+ set(CHECK_FUNCTION_EXISTS_ADD_LINK_OPTIONS)
+ endif()
+ if(CMAKE_REQUIRED_LIBRARIES)
+ set(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES
+ LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
+ else()
+ set(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES)
+ endif()
+ file(WRITE
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompiler.f
+ "
+ program TESTFortran
+ external ${FUNCTION}
+ call ${FUNCTION}()
+ end program TESTFortran
+ "
+ )
+ try_compile(${VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompiler.f
+ ${CHECK_FUNCTION_EXISTS_ADD_LINK_OPTIONS}
+ ${CHECK_FUNCTION_EXISTS_ADD_LIBRARIES}
+ OUTPUT_VARIABLE OUTPUT
+ )
+ if(${VARIABLE})
+ set(${VARIABLE} 1 CACHE INTERNAL "Have Fortran function ${FUNCTION}")
+ message(CHECK_PASS "found")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the Fortran ${FUNCTION} exists passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ else()
+ message(CHECK_FAIL "not found")
+ set(${VARIABLE} "" CACHE INTERNAL "Have Fortran function ${FUNCTION}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the Fortran ${FUNCTION} exists failed with the following output:\n"
+ "${OUTPUT}\n\n")
+ endif()
+ endif()
+endmacro()
diff --git a/Modules/CheckFortranSourceCompiles.cmake b/Modules/CheckFortranSourceCompiles.cmake
new file mode 100644
index 0000000..e134329
--- /dev/null
+++ b/Modules/CheckFortranSourceCompiles.cmake
@@ -0,0 +1,98 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckFortranSourceCompiles
+--------------------------
+
+.. versionadded:: 3.1
+
+Check if given Fortran source compiles and links into an executable.
+
+.. command:: check_fortran_source_compiles
+
+ .. code-block:: cmake
+
+ check_fortran_source_compiles(<code> <resultVar>
+ [FAIL_REGEX <regex>...]
+ [SRC_EXT <extension>]
+ )
+
+ Checks that the source supplied in ``<code>`` can be compiled as a Fortran
+ source file and linked as an executable. The ``<code>`` must be a Fortran program
+ containing at least an ``end`` statement--for example:
+
+ .. code-block:: cmake
+
+ check_fortran_source_compiles("character :: b; error stop b; end" F2018ESTOPOK SRC_EXT F90)
+
+ This command can help avoid costly build processes when a compiler lacks support
+ for a necessary feature, or a particular vendor library is not compatible with
+ the Fortran compiler version being used. This generate-time check may advise the
+ user of such before the main build process. See also the
+ :command:`check_fortran_source_runs` command to actually run the compiled code.
+
+ The result will be stored in the internal cache
+ variable ``<resultVar>``, with a boolean true value for success and boolean
+ false for failure.
+
+ If ``FAIL_REGEX`` is provided, then failure is determined by checking
+ if anything in the output matches any of the specified regular expressions.
+
+ By default, the test source file will be given a ``.F`` file extension. The
+ ``SRC_EXT`` option can be used to override this with ``.<extension>`` instead--
+ ``.F90`` is a typical choice.
+
+ The underlying check is performed by the :command:`try_compile` command. The
+ compile and link commands can be influenced by setting any of the following
+ variables prior to calling ``check_fortran_source_compiles()``:
+
+ ``CMAKE_REQUIRED_FLAGS``
+ Additional flags to pass to the compiler. Note that the contents of
+ :variable:`CMAKE_Fortran_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated
+ configuration-specific variable are automatically added to the compiler
+ command before the contents of ``CMAKE_REQUIRED_FLAGS``.
+
+ ``CMAKE_REQUIRED_DEFINITIONS``
+ A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form
+ ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by
+ ``<resultVar>`` will also be added automatically.
+
+ ``CMAKE_REQUIRED_INCLUDES``
+ A :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler. These will be the only header search paths used by
+ ``try_compile()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES`
+ directory property will be ignored.
+
+ ``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+
+ A :ref:`;-list <CMake Language Lists>` of options to add to the link
+ command (see :command:`try_compile` for further details).
+
+ ``CMAKE_REQUIRED_LIBRARIES``
+ A :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. These can be the name of system libraries or they can be
+ :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for
+ further details).
+
+ ``CMAKE_REQUIRED_QUIET``
+ If this variable evaluates to a boolean true value, all status messages
+ associated with the check will be suppressed.
+
+ The check is only performed once, with the result cached in the variable
+ named by ``<resultVar>``. Every subsequent CMake run will re-use this cached
+ value rather than performing the check again, even if the ``<code>`` changes.
+ In order to force the check to be re-evaluated, the variable named by
+ ``<resultVar>`` must be manually removed from the cache.
+
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(Internal/CheckSourceCompiles)
+
+macro(CHECK_Fortran_SOURCE_COMPILES SOURCE VAR)
+ # Pass the SRC_EXT we used by default historically.
+ # A user-provided SRC_EXT argument in ARGN will override ours.
+ cmake_check_source_compiles(Fortran "${SOURCE}" ${VAR} SRC_EXT "F" ${ARGN})
+endmacro()
diff --git a/Modules/CheckFortranSourceRuns.cmake b/Modules/CheckFortranSourceRuns.cmake
new file mode 100644
index 0000000..28f713f
--- /dev/null
+++ b/Modules/CheckFortranSourceRuns.cmake
@@ -0,0 +1,92 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckFortranSourceRuns
+----------------------
+
+.. versionadded:: 3.14
+
+Check if given Fortran source compiles and links into an executable and can
+subsequently be run.
+
+.. command:: check_fortran_source_runs
+
+ .. code-block:: cmake
+
+ check_fortran_source_runs(<code> <resultVar>
+ [SRC_EXT <extension>])
+
+ Check that the source supplied in ``<code>`` can be compiled as a Fortran source
+ file, linked as an executable and then run. The ``<code>`` must be a Fortran program
+ containing at least an ``end`` statement--for example:
+
+ .. code-block:: cmake
+
+ check_fortran_source_runs("real :: x[*]; call co_sum(x); end" F2018coarrayOK)
+
+ This command can help avoid costly build processes when a compiler lacks support
+ for a necessary feature, or a particular vendor library is not compatible with
+ the Fortran compiler version being used. Some of these failures only occur at runtime
+ instead of linktime, and a trivial runtime example can catch the issue before the
+ main build process.
+
+ If the ``<code>`` could be built and run
+ successfully, the internal cache variable specified by ``<resultVar>`` will
+ be set to 1, otherwise it will be set to an value that evaluates to boolean
+ false (e.g. an empty string or an error message).
+
+ By default, the test source file will be given a ``.F90`` file extension. The
+ ``SRC_EXT`` option can be used to override this with ``.<extension>`` instead.
+
+ The underlying check is performed by the :command:`try_run` command. The
+ compile and link commands can be influenced by setting any of the following
+ variables prior to calling ``check_fortran_source_runs()``:
+
+ ``CMAKE_REQUIRED_FLAGS``
+ Additional flags to pass to the compiler. Note that the contents of
+ :variable:`CMAKE_Fortran_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated
+ configuration-specific variable are automatically added to the compiler
+ command before the contents of ``CMAKE_REQUIRED_FLAGS``.
+
+ ``CMAKE_REQUIRED_DEFINITIONS``
+ A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form
+ ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by
+ ``<resultVar>`` will also be added automatically.
+
+ ``CMAKE_REQUIRED_INCLUDES``
+ A :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler. These will be the only header search paths used by
+ ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES`
+ directory property will be ignored.
+
+ ``CMAKE_REQUIRED_LINK_OPTIONS``
+ A :ref:`;-list <CMake Language Lists>` of options to add to the link
+ command (see :command:`try_run` for further details).
+
+ ``CMAKE_REQUIRED_LIBRARIES``
+ A :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. These can be the name of system libraries or they can be
+ :ref:`Imported Targets <Imported Targets>` (see :command:`try_run` for
+ further details).
+
+ ``CMAKE_REQUIRED_QUIET``
+ If this variable evaluates to a boolean true value, all status messages
+ associated with the check will be suppressed.
+
+ The check is only performed once, with the result cached in the variable
+ named by ``<resultVar>``. Every subsequent CMake run will re-use this cached
+ value rather than performing the check again, even if the ``<code>`` changes.
+ In order to force the check to be re-evaluated, the variable named by
+ ``<resultVar>`` must be manually removed from the cache.
+
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(Internal/CheckSourceRuns)
+
+macro(CHECK_Fortran_SOURCE_RUNS SOURCE VAR)
+ # Pass the SRC_EXT we used by default historically.
+ # A user-provided SRC_EXT argument in ARGN will override ours.
+ cmake_check_source_runs(Fortran "${SOURCE}" ${VAR} SRC_EXT "F90" ${ARGN})
+endmacro()
diff --git a/Modules/CheckFunctionExists.c b/Modules/CheckFunctionExists.c
new file mode 100644
index 0000000..13435e0
--- /dev/null
+++ b/Modules/CheckFunctionExists.c
@@ -0,0 +1,28 @@
+#ifdef CHECK_FUNCTION_EXISTS
+
+# ifdef __cplusplus
+extern "C"
+# endif
+ char
+ CHECK_FUNCTION_EXISTS(void);
+# ifdef __CLASSIC_C__
+int main()
+{
+ int ac;
+ char* av[];
+# else
+int main(int ac, char* av[])
+{
+# endif
+ CHECK_FUNCTION_EXISTS();
+ if (ac > 1000) {
+ return *av[0];
+ }
+ return 0;
+}
+
+#else /* CHECK_FUNCTION_EXISTS */
+
+# error "CHECK_FUNCTION_EXISTS has to specify the function"
+
+#endif /* CHECK_FUNCTION_EXISTS */
diff --git a/Modules/CheckFunctionExists.cmake b/Modules/CheckFunctionExists.cmake
new file mode 100644
index 0000000..9efa132
--- /dev/null
+++ b/Modules/CheckFunctionExists.cmake
@@ -0,0 +1,121 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckFunctionExists
+-------------------
+
+Check if a C function can be linked
+
+.. command:: check_function_exists
+
+ .. code-block:: cmake
+
+ check_function_exists(<function> <variable>)
+
+ Checks that the ``<function>`` is provided by libraries on the system and store
+ the result in a ``<variable>``, which will be created as an internal
+ cache variable.
+
+The following variables may be set before calling this macro to modify the
+way the check is run:
+
+``CMAKE_REQUIRED_FLAGS``
+ string of compile command line flags.
+``CMAKE_REQUIRED_DEFINITIONS``
+ a :ref:`;-list <CMake Language Lists>` of macros to define (-DFOO=bar).
+``CMAKE_REQUIRED_INCLUDES``
+ a :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler.
+``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+ a :ref:`;-list <CMake Language Lists>` of options to add to the link command.
+``CMAKE_REQUIRED_LIBRARIES``
+ a :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. See policy :policy:`CMP0075`.
+``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+ execute quietly without messages.
+
+.. note::
+
+ Prefer using :Module:`CheckSymbolExists` instead of this module,
+ for the following reasons:
+
+ * ``check_function_exists()`` can't detect functions that are inlined
+ in headers or specified as a macro.
+
+ * ``check_function_exists()`` can't detect anything in the 32-bit
+ versions of the Win32 API, because of a mismatch in calling conventions.
+
+ * ``check_function_exists()`` only verifies linking, it does not verify
+ that the function is declared in system headers.
+#]=======================================================================]
+
+include_guard(GLOBAL)
+
+macro(CHECK_FUNCTION_EXISTS FUNCTION VARIABLE)
+ if(NOT DEFINED "${VARIABLE}" OR "x${${VARIABLE}}" STREQUAL "x${VARIABLE}")
+ set(MACRO_CHECK_FUNCTION_DEFINITIONS
+ "-DCHECK_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}")
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_START "Looking for ${FUNCTION}")
+ endif()
+ if(CMAKE_REQUIRED_LINK_OPTIONS)
+ set(CHECK_FUNCTION_EXISTS_ADD_LINK_OPTIONS
+ LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
+ else()
+ set(CHECK_FUNCTION_EXISTS_ADD_LINK_OPTIONS)
+ endif()
+ if(CMAKE_REQUIRED_LIBRARIES)
+ set(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES
+ LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
+ else()
+ set(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES)
+ endif()
+ if(CMAKE_REQUIRED_INCLUDES)
+ set(CHECK_FUNCTION_EXISTS_ADD_INCLUDES
+ "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+ else()
+ set(CHECK_FUNCTION_EXISTS_ADD_INCLUDES)
+ endif()
+
+ if(CMAKE_C_COMPILER_LOADED)
+ set(_cfe_source ${CMAKE_ROOT}/Modules/CheckFunctionExists.c)
+ elseif(CMAKE_CXX_COMPILER_LOADED)
+ set(_cfe_source ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckFunctionExists/CheckFunctionExists.cxx)
+ configure_file(${CMAKE_ROOT}/Modules/CheckFunctionExists.c "${_cfe_source}" COPYONLY)
+ else()
+ message(FATAL_ERROR "CHECK_FUNCTION_EXISTS needs either C or CXX language enabled")
+ endif()
+
+ try_compile(${VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${_cfe_source}
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ ${CHECK_FUNCTION_EXISTS_ADD_LINK_OPTIONS}
+ ${CHECK_FUNCTION_EXISTS_ADD_LIBRARIES}
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+ "${CHECK_FUNCTION_EXISTS_ADD_INCLUDES}"
+ OUTPUT_VARIABLE OUTPUT)
+ unset(_cfe_source)
+
+ if(${VARIABLE})
+ set(${VARIABLE} 1 CACHE INTERNAL "Have function ${FUNCTION}")
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_PASS "found")
+ endif()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the function ${FUNCTION} exists passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ else()
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_FAIL "not found")
+ endif()
+ set(${VARIABLE} "" CACHE INTERNAL "Have function ${FUNCTION}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the function ${FUNCTION} exists failed with the following output:\n"
+ "${OUTPUT}\n\n")
+ endif()
+ endif()
+endmacro()
diff --git a/Modules/CheckIPOSupported.cmake b/Modules/CheckIPOSupported.cmake
new file mode 100644
index 0000000..0bc3c92
--- /dev/null
+++ b/Modules/CheckIPOSupported.cmake
@@ -0,0 +1,244 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckIPOSupported
+-----------------
+
+.. versionadded:: 3.9
+
+Check whether the compiler supports an interprocedural optimization (IPO/LTO).
+Use this before enabling the :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` target
+property.
+
+.. command:: check_ipo_supported
+
+ ::
+
+ check_ipo_supported([RESULT <result>] [OUTPUT <output>]
+ [LANGUAGES <lang>...])
+
+ Options are:
+
+ ``RESULT <result>``
+ Set ``<result>`` variable to ``YES`` if IPO is supported by the
+ compiler and ``NO`` otherwise. If this option is not given then
+ the command will issue a fatal error if IPO is not supported.
+ ``OUTPUT <output>``
+ Set ``<output>`` variable with details about any error.
+ ``LANGUAGES <lang>...``
+ Specify languages whose compilers to check.
+ Languages ``C``, ``CXX``, and ``Fortran`` are supported.
+
+It makes no sense to use this module when :policy:`CMP0069` is set to ``OLD`` so
+module will return error in this case. See policy :policy:`CMP0069` for details.
+
+.. versionadded:: 3.13
+ Add support for Visual Studio generators.
+
+Examples
+^^^^^^^^
+
+.. code-block:: cmake
+
+ check_ipo_supported() # fatal error if IPO is not supported
+ set_property(TARGET foo PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
+
+.. code-block:: cmake
+
+ # Optional IPO. Do not use IPO if it's not supported by compiler.
+ check_ipo_supported(RESULT result OUTPUT output)
+ if(result)
+ set_property(TARGET foo PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
+ else()
+ message(WARNING "IPO is not supported: ${output}")
+ endif()
+
+#]=======================================================================]
+
+# X_RESULT - name of the final result variable
+# X_OUTPUT - name of the variable with information about error
+macro(_ipo_not_supported output)
+ if(NOT X_RESULT)
+ message(FATAL_ERROR "IPO is not supported (${output}).")
+ endif()
+
+ set("${X_RESULT}" NO PARENT_SCOPE)
+ if(X_OUTPUT)
+ set("${X_OUTPUT}" "${output}" PARENT_SCOPE)
+ endif()
+endmacro()
+
+# Run IPO/LTO test
+macro(_ipo_run_language_check language)
+ set(testdir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/_CMakeLTOTest-${language}")
+
+ file(REMOVE_RECURSE "${testdir}")
+ file(MAKE_DIRECTORY "${testdir}")
+
+ set(bindir "${testdir}/bin")
+ set(srcdir "${testdir}/src")
+
+ file(MAKE_DIRECTORY "${bindir}")
+ file(MAKE_DIRECTORY "${srcdir}")
+
+ set(TRY_COMPILE_PROJECT_NAME "lto-test")
+
+ set(try_compile_src "${CMAKE_ROOT}/Modules/CheckIPOSupported")
+
+ # Use:
+ # * TRY_COMPILE_PROJECT_NAME
+ # * CMAKE_VERSION
+ configure_file(
+ "${try_compile_src}/CMakeLists-${language}.txt.in"
+ "${srcdir}/CMakeLists.txt"
+ @ONLY
+ )
+
+ string(COMPARE EQUAL "${language}" "C" is_c)
+ string(COMPARE EQUAL "${language}" "CXX" is_cxx)
+ string(COMPARE EQUAL "${language}" "Fortran" is_fortran)
+
+ if(is_c)
+ set(copy_sources foo.c main.c)
+ elseif(is_cxx)
+ set(copy_sources foo.cpp main.cpp)
+ elseif(is_fortran)
+ set(copy_sources foo.f main.f)
+ else()
+ message(FATAL_ERROR "Language not supported")
+ endif()
+
+ foreach(x ${copy_sources})
+ configure_file(
+ "${try_compile_src}/${x}"
+ "${srcdir}/${x}"
+ COPYONLY
+ )
+ endforeach()
+
+ try_compile(
+ _IPO_LANGUAGE_CHECK_RESULT
+ "${bindir}"
+ "${srcdir}"
+ "${TRY_COMPILE_PROJECT_NAME}"
+ CMAKE_FLAGS
+ "-DCMAKE_VERBOSE_MAKEFILE=ON"
+ "-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON"
+ OUTPUT_VARIABLE output
+ )
+ set(_IPO_LANGUAGE_CHECK_RESULT "${_IPO_LANGUAGE_CHECK_RESULT}")
+ unset(_IPO_LANGUAGE_CHECK_RESULT CACHE)
+
+ if(NOT _IPO_LANGUAGE_CHECK_RESULT)
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "${language} compiler IPO check failed with the following output:\n"
+ "${output}\n")
+ _ipo_not_supported("check failed to compile")
+ if(X_OUTPUT)
+ set("${X_OUTPUT}" "${output}" PARENT_SCOPE)
+ endif()
+ return()
+ endif()
+endmacro()
+
+function(check_ipo_supported)
+ cmake_policy(GET CMP0069 x)
+
+ string(COMPARE EQUAL "${x}" "" not_set)
+ if(not_set)
+ message(FATAL_ERROR "Policy CMP0069 is not set")
+ endif()
+
+ string(COMPARE EQUAL "${x}" "OLD" is_old)
+ if(is_old)
+ message(FATAL_ERROR "Policy CMP0069 set to OLD")
+ endif()
+
+ set(optional)
+ set(one RESULT OUTPUT)
+ set(multiple LANGUAGES)
+
+ # Introduce:
+ # * X_RESULT
+ # * X_OUTPUT
+ # * X_LANGUAGES
+ cmake_parse_arguments(X "${optional}" "${one}" "${multiple}" "${ARGV}")
+
+ string(COMPARE NOTEQUAL "${X_UNPARSED_ARGUMENTS}" "" has_unparsed)
+ if(has_unparsed)
+ message(FATAL_ERROR "Unparsed arguments: ${X_UNPARSED_ARGUMENTS}")
+ endif()
+
+ string(COMPARE EQUAL "${X_LANGUAGES}" "" no_languages)
+ if(no_languages)
+ # User did not set any languages, use defaults
+ get_property(enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
+ string(COMPARE EQUAL "${enabled_languages}" "" no_languages)
+ if(no_languages)
+ _ipo_not_supported(
+ "no languages found in ENABLED_LANGUAGES global property"
+ )
+ return()
+ endif()
+
+ set(languages "")
+ list(FIND enabled_languages "CXX" result)
+ if(NOT result EQUAL -1)
+ list(APPEND languages "CXX")
+ endif()
+
+ list(FIND enabled_languages "C" result)
+ if(NOT result EQUAL -1)
+ list(APPEND languages "C")
+ endif()
+
+ list(FIND enabled_languages "Fortran" result)
+ if(NOT result EQUAL -1)
+ list(APPEND languages "Fortran")
+ endif()
+
+ string(COMPARE EQUAL "${languages}" "" no_languages)
+ if(no_languages)
+ _ipo_not_supported(
+ "no C/CXX/Fortran languages found in ENABLED_LANGUAGES global property"
+ )
+ return()
+ endif()
+ else()
+ set(languages "${X_LANGUAGES}")
+
+ set(unsupported_languages "${languages}")
+ list(REMOVE_ITEM unsupported_languages "C" "CXX" "Fortran")
+ string(COMPARE NOTEQUAL "${unsupported_languages}" "" has_unsupported)
+ if(has_unsupported)
+ _ipo_not_supported(
+ "language(s) '${unsupported_languages}' not supported"
+ )
+ return()
+ endif()
+ endif()
+
+ foreach(lang ${languages})
+ if(NOT _CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE)
+ _ipo_not_supported("CMake doesn't support IPO for current ${lang} compiler")
+ return()
+ endif()
+
+ if(NOT _CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER)
+ _ipo_not_supported("${lang} compiler doesn't support IPO")
+ return()
+ endif()
+ endforeach()
+
+ if(CMAKE_GENERATOR MATCHES "^Visual Studio 9 ")
+ _ipo_not_supported("CMake doesn't support IPO for current generator")
+ return()
+ endif()
+
+ foreach(x ${languages})
+ _ipo_run_language_check(${x})
+ endforeach()
+
+ set("${X_RESULT}" YES PARENT_SCOPE)
+endfunction()
diff --git a/Modules/CheckIPOSupported/CMakeLists-C.txt.in b/Modules/CheckIPOSupported/CMakeLists-C.txt.in
new file mode 100644
index 0000000..5a3b8ee
--- /dev/null
+++ b/Modules/CheckIPOSupported/CMakeLists-C.txt.in
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION "@CMAKE_VERSION@")
+project("@TRY_COMPILE_PROJECT_NAME@" LANGUAGES C)
+
+cmake_policy(SET CMP0069 NEW)
+
+add_library(foo foo.c)
+add_executable(boo main.c)
+target_link_libraries(boo PUBLIC foo)
diff --git a/Modules/CheckIPOSupported/CMakeLists-CXX.txt.in b/Modules/CheckIPOSupported/CMakeLists-CXX.txt.in
new file mode 100644
index 0000000..30993fa
--- /dev/null
+++ b/Modules/CheckIPOSupported/CMakeLists-CXX.txt.in
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION "@CMAKE_VERSION@")
+project("@TRY_COMPILE_PROJECT_NAME@" LANGUAGES CXX)
+
+cmake_policy(SET CMP0069 NEW)
+
+add_library(foo foo.cpp)
+add_executable(boo main.cpp)
+target_link_libraries(boo PUBLIC foo)
diff --git a/Modules/CheckIPOSupported/CMakeLists-Fortran.txt.in b/Modules/CheckIPOSupported/CMakeLists-Fortran.txt.in
new file mode 100644
index 0000000..9fab077
--- /dev/null
+++ b/Modules/CheckIPOSupported/CMakeLists-Fortran.txt.in
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION "@CMAKE_VERSION@")
+project("@TRY_COMPILE_PROJECT_NAME@" LANGUAGES Fortran)
+
+cmake_policy(SET CMP0069 NEW)
+
+add_library(foo foo.f)
+add_executable(boo main.f)
+target_link_libraries(boo PUBLIC foo)
diff --git a/Modules/CheckIPOSupported/foo.c b/Modules/CheckIPOSupported/foo.c
new file mode 100644
index 0000000..1e56597
--- /dev/null
+++ b/Modules/CheckIPOSupported/foo.c
@@ -0,0 +1,4 @@
+int foo()
+{
+ return 0x42;
+}
diff --git a/Modules/CheckIPOSupported/foo.cpp b/Modules/CheckIPOSupported/foo.cpp
new file mode 100644
index 0000000..1e56597
--- /dev/null
+++ b/Modules/CheckIPOSupported/foo.cpp
@@ -0,0 +1,4 @@
+int foo()
+{
+ return 0x42;
+}
diff --git a/Modules/CheckIPOSupported/foo.f b/Modules/CheckIPOSupported/foo.f
new file mode 100644
index 0000000..945d2d5
--- /dev/null
+++ b/Modules/CheckIPOSupported/foo.f
@@ -0,0 +1,2 @@
+ SUBROUTINE FOO
+ END
diff --git a/Modules/CheckIPOSupported/main.c b/Modules/CheckIPOSupported/main.c
new file mode 100644
index 0000000..5be0864
--- /dev/null
+++ b/Modules/CheckIPOSupported/main.c
@@ -0,0 +1,6 @@
+int foo();
+
+int main()
+{
+ return foo();
+}
diff --git a/Modules/CheckIPOSupported/main.cpp b/Modules/CheckIPOSupported/main.cpp
new file mode 100644
index 0000000..5be0864
--- /dev/null
+++ b/Modules/CheckIPOSupported/main.cpp
@@ -0,0 +1,6 @@
+int foo();
+
+int main()
+{
+ return foo();
+}
diff --git a/Modules/CheckIPOSupported/main.f b/Modules/CheckIPOSupported/main.f
new file mode 100644
index 0000000..9d1de9f
--- /dev/null
+++ b/Modules/CheckIPOSupported/main.f
@@ -0,0 +1,3 @@
+ PROGRAM BOO
+ CALL FOO()
+ END
diff --git a/Modules/CheckIncludeFile.c.in b/Modules/CheckIncludeFile.c.in
new file mode 100644
index 0000000..ddfbee8
--- /dev/null
+++ b/Modules/CheckIncludeFile.c.in
@@ -0,0 +1,13 @@
+#include <${CHECK_INCLUDE_FILE_VAR}>
+
+#ifdef __CLASSIC_C__
+int main()
+{
+ return 0;
+}
+#else
+int main(void)
+{
+ return 0;
+}
+#endif
diff --git a/Modules/CheckIncludeFile.cmake b/Modules/CheckIncludeFile.cmake
new file mode 100644
index 0000000..71ddde7
--- /dev/null
+++ b/Modules/CheckIncludeFile.cmake
@@ -0,0 +1,132 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckIncludeFile
+----------------
+
+Provides a macro to check if a header file can be included in ``C``.
+
+.. command:: CHECK_INCLUDE_FILE
+
+ .. code-block:: cmake
+
+ CHECK_INCLUDE_FILE(<include> <variable> [<flags>])
+
+ Check if the given ``<include>`` file may be included in a ``C``
+ source file and store the result in an internal cache entry named
+ ``<variable>``. The optional third argument may be used to add
+ compilation flags to the check (or use ``CMAKE_REQUIRED_FLAGS`` below).
+
+The following variables may be set before calling this macro to modify
+the way the check is run:
+
+``CMAKE_REQUIRED_FLAGS``
+ string of compile command line flags.
+``CMAKE_REQUIRED_DEFINITIONS``
+ a :ref:`;-list <CMake Language Lists>` of macros to define (-DFOO=bar).
+``CMAKE_REQUIRED_INCLUDES``
+ a :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler.
+``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+ a :ref:`;-list <CMake Language Lists>` of options to add to the link command.
+``CMAKE_REQUIRED_LIBRARIES``
+ a :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. See policy :policy:`CMP0075`.
+``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+ execute quietly without messages.
+
+See the :module:`CheckIncludeFiles` module to check for multiple headers
+at once. See the :module:`CheckIncludeFileCXX` module to check for headers
+using the ``CXX`` language.
+#]=======================================================================]
+
+include_guard(GLOBAL)
+
+macro(CHECK_INCLUDE_FILE INCLUDE VARIABLE)
+ if(NOT DEFINED "${VARIABLE}")
+ if(CMAKE_REQUIRED_INCLUDES)
+ set(CHECK_INCLUDE_FILE_C_INCLUDE_DIRS "-DINCLUDE_DIRECTORIES=${CMAKE_REQUIRED_INCLUDES}")
+ else()
+ set(CHECK_INCLUDE_FILE_C_INCLUDE_DIRS)
+ endif()
+ set(MACRO_CHECK_INCLUDE_FILE_FLAGS ${CMAKE_REQUIRED_FLAGS})
+ set(CHECK_INCLUDE_FILE_VAR ${INCLUDE})
+ configure_file(${CMAKE_ROOT}/Modules/CheckIncludeFile.c.in
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.c)
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_START "Looking for ${INCLUDE}")
+ endif()
+ if(${ARGC} EQUAL 3)
+ set(CMAKE_C_FLAGS_SAVE ${CMAKE_C_FLAGS})
+ string(APPEND CMAKE_C_FLAGS " ${ARGV2}")
+ endif()
+
+ set(_CIF_LINK_OPTIONS)
+ if(CMAKE_REQUIRED_LINK_OPTIONS)
+ set(_CIF_LINK_OPTIONS LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
+ endif()
+
+ set(_CIF_LINK_LIBRARIES "")
+ if(CMAKE_REQUIRED_LIBRARIES)
+ cmake_policy(GET CMP0075 _CIF_CMP0075
+ PARENT_SCOPE # undocumented, do not use outside of CMake
+ )
+ if("x${_CIF_CMP0075}x" STREQUAL "xNEWx")
+ set(_CIF_LINK_LIBRARIES LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
+ elseif("x${_CIF_CMP0075}x" STREQUAL "xOLDx")
+ elseif(NOT _CIF_CMP0075_WARNED)
+ set(_CIF_CMP0075_WARNED 1)
+ message(AUTHOR_WARNING
+ "Policy CMP0075 is not set: Include file check macros honor CMAKE_REQUIRED_LIBRARIES. "
+ "Run \"cmake --help-policy CMP0075\" for policy details. "
+ "Use the cmake_policy command to set the policy and suppress this warning."
+ "\n"
+ "CMAKE_REQUIRED_LIBRARIES is set to:\n"
+ " ${CMAKE_REQUIRED_LIBRARIES}\n"
+ "For compatibility with CMake 3.11 and below this check is ignoring it."
+ )
+ endif()
+ unset(_CIF_CMP0075)
+ endif()
+
+ try_compile(${VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ ${_CIF_LINK_OPTIONS}
+ ${_CIF_LINK_LIBRARIES}
+ CMAKE_FLAGS
+ -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_INCLUDE_FILE_FLAGS}
+ "${CHECK_INCLUDE_FILE_C_INCLUDE_DIRS}"
+ OUTPUT_VARIABLE OUTPUT)
+ unset(_CIF_LINK_OPTIONS)
+ unset(_CIF_LINK_LIBRARIES)
+
+ if(${ARGC} EQUAL 3)
+ set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS_SAVE})
+ endif()
+
+ if(${VARIABLE})
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_PASS "found")
+ endif()
+ set(${VARIABLE} 1 CACHE INTERNAL "Have include ${INCLUDE}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the include file ${INCLUDE} "
+ "exists passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ else()
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_FAIL "not found")
+ endif()
+ set(${VARIABLE} "" CACHE INTERNAL "Have include ${INCLUDE}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the include file ${INCLUDE} "
+ "exists failed with the following output:\n"
+ "${OUTPUT}\n\n")
+ endif()
+ endif()
+endmacro()
diff --git a/Modules/CheckIncludeFile.cxx.in b/Modules/CheckIncludeFile.cxx.in
new file mode 100644
index 0000000..40441f1
--- /dev/null
+++ b/Modules/CheckIncludeFile.cxx.in
@@ -0,0 +1,6 @@
+#include <${CHECK_INCLUDE_FILE_VAR}>
+
+int main()
+{
+ return 0;
+}
diff --git a/Modules/CheckIncludeFileCXX.cmake b/Modules/CheckIncludeFileCXX.cmake
new file mode 100644
index 0000000..953224e
--- /dev/null
+++ b/Modules/CheckIncludeFileCXX.cmake
@@ -0,0 +1,131 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckIncludeFileCXX
+-------------------
+
+Provides a macro to check if a header file can be included in ``CXX``.
+
+.. command:: CHECK_INCLUDE_FILE_CXX
+
+ .. code-block:: cmake
+
+ CHECK_INCLUDE_FILE_CXX(<include> <variable> [<flags>])
+
+ Check if the given ``<include>`` file may be included in a ``CXX``
+ source file and store the result in an internal cache entry named
+ ``<variable>``. The optional third argument may be used to add
+ compilation flags to the check (or use ``CMAKE_REQUIRED_FLAGS`` below).
+
+The following variables may be set before calling this macro to modify
+the way the check is run:
+
+``CMAKE_REQUIRED_FLAGS``
+ string of compile command line flags.
+``CMAKE_REQUIRED_DEFINITIONS``
+ a :ref:`;-list <CMake Language Lists>` of macros to define (-DFOO=bar).
+``CMAKE_REQUIRED_INCLUDES``
+ a :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler.
+``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+ a :ref:`;-list <CMake Language Lists>` of options to add to the link command.
+``CMAKE_REQUIRED_LIBRARIES``
+ a :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. See policy :policy:`CMP0075`.
+``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+ execute quietly without messages.
+
+See modules :module:`CheckIncludeFile` and :module:`CheckIncludeFiles`
+to check for one or more ``C`` headers.
+#]=======================================================================]
+
+include_guard(GLOBAL)
+
+macro(CHECK_INCLUDE_FILE_CXX INCLUDE VARIABLE)
+ if(NOT DEFINED "${VARIABLE}" OR "x${${VARIABLE}}" STREQUAL "x${VARIABLE}")
+ if(CMAKE_REQUIRED_INCLUDES)
+ set(CHECK_INCLUDE_FILE_CXX_INCLUDE_DIRS "-DINCLUDE_DIRECTORIES=${CMAKE_REQUIRED_INCLUDES}")
+ else()
+ set(CHECK_INCLUDE_FILE_CXX_INCLUDE_DIRS)
+ endif()
+ set(MACRO_CHECK_INCLUDE_FILE_FLAGS ${CMAKE_REQUIRED_FLAGS})
+ set(CHECK_INCLUDE_FILE_VAR ${INCLUDE})
+ configure_file(${CMAKE_ROOT}/Modules/CheckIncludeFile.cxx.in
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.cxx)
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_START "Looking for C++ include ${INCLUDE}")
+ endif()
+ if(${ARGC} EQUAL 3)
+ set(CMAKE_CXX_FLAGS_SAVE ${CMAKE_CXX_FLAGS})
+ string(APPEND CMAKE_CXX_FLAGS " ${ARGV2}")
+ endif()
+
+ set(_CIF_LINK_OPTIONS)
+ if(CMAKE_REQUIRED_LINK_OPTIONS)
+ set(_CIF_LINK_OPTIONS LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
+ endif()
+
+ set(_CIF_LINK_LIBRARIES "")
+ if(CMAKE_REQUIRED_LIBRARIES)
+ cmake_policy(GET CMP0075 _CIF_CMP0075
+ PARENT_SCOPE # undocumented, do not use outside of CMake
+ )
+ if("x${_CIF_CMP0075}x" STREQUAL "xNEWx")
+ set(_CIF_LINK_LIBRARIES LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
+ elseif("x${_CIF_CMP0075}x" STREQUAL "xOLDx")
+ elseif(NOT _CIF_CMP0075_WARNED)
+ set(_CIF_CMP0075_WARNED 1)
+ message(AUTHOR_WARNING
+ "Policy CMP0075 is not set: Include file check macros honor CMAKE_REQUIRED_LIBRARIES. "
+ "Run \"cmake --help-policy CMP0075\" for policy details. "
+ "Use the cmake_policy command to set the policy and suppress this warning."
+ "\n"
+ "CMAKE_REQUIRED_LIBRARIES is set to:\n"
+ " ${CMAKE_REQUIRED_LIBRARIES}\n"
+ "For compatibility with CMake 3.11 and below this check is ignoring it."
+ )
+ endif()
+ unset(_CIF_CMP0075)
+ endif()
+
+ try_compile(${VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.cxx
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ ${_CIF_LINK_OPTIONS}
+ ${_CIF_LINK_LIBRARIES}
+ CMAKE_FLAGS
+ -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_INCLUDE_FILE_FLAGS}
+ "${CHECK_INCLUDE_FILE_CXX_INCLUDE_DIRS}"
+ OUTPUT_VARIABLE OUTPUT)
+ unset(_CIF_LINK_OPTIONS)
+ unset(_CIF_LINK_LIBRARIES)
+
+ if(${ARGC} EQUAL 3)
+ set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS_SAVE})
+ endif()
+
+ if(${VARIABLE})
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_PASS "found")
+ endif()
+ set(${VARIABLE} 1 CACHE INTERNAL "Have include ${INCLUDE}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the include file ${INCLUDE} "
+ "exists passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ else()
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_FAIL "not found")
+ endif()
+ set(${VARIABLE} "" CACHE INTERNAL "Have include ${INCLUDE}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the include file ${INCLUDE} "
+ "exists failed with the following output:\n"
+ "${OUTPUT}\n\n")
+ endif()
+ endif()
+endmacro()
diff --git a/Modules/CheckIncludeFiles.cmake b/Modules/CheckIncludeFiles.cmake
new file mode 100644
index 0000000..1800ca8
--- /dev/null
+++ b/Modules/CheckIncludeFiles.cmake
@@ -0,0 +1,170 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckIncludeFiles
+-----------------
+
+Provides a macro to check if a list of one or more header files can
+be included together.
+
+.. command:: CHECK_INCLUDE_FILES
+
+ .. code-block:: cmake
+
+ CHECK_INCLUDE_FILES("<includes>" <variable> [LANGUAGE <language>])
+
+ Check if the given ``<includes>`` list may be included together
+ in a source file and store the result in an internal cache
+ entry named ``<variable>``. Specify the ``<includes>`` argument
+ as a :ref:`;-list <CMake Language Lists>` of header file names.
+
+ If ``LANGUAGE`` is set, the specified compiler will be used to perform the
+ check. Acceptable values are ``C`` and ``CXX``. If not set, the C compiler
+ will be used if enabled. If the C compiler is not enabled, the C++
+ compiler will be used if enabled.
+
+The following variables may be set before calling this macro to modify
+the way the check is run:
+
+``CMAKE_REQUIRED_FLAGS``
+ string of compile command line flags.
+``CMAKE_REQUIRED_DEFINITIONS``
+ a :ref:`;-list <CMake Language Lists>` of macros to define (-DFOO=bar).
+``CMAKE_REQUIRED_INCLUDES``
+ a :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler.
+``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+ a :ref:`;-list <CMake Language Lists>` of options to add to the link command.
+``CMAKE_REQUIRED_LIBRARIES``
+ a :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. See policy :policy:`CMP0075`.
+``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+ execute quietly without messages.
+
+See modules :module:`CheckIncludeFile` and :module:`CheckIncludeFileCXX`
+to check for a single header file in ``C`` or ``CXX`` languages.
+#]=======================================================================]
+
+include_guard(GLOBAL)
+
+macro(CHECK_INCLUDE_FILES INCLUDE VARIABLE)
+ if(NOT DEFINED "${VARIABLE}")
+ set(CMAKE_CONFIGURABLE_FILE_CONTENT "/* */\n")
+
+ if("x${ARGN}" STREQUAL "x")
+ if(CMAKE_C_COMPILER_LOADED)
+ set(_lang C)
+ elseif(CMAKE_CXX_COMPILER_LOADED)
+ set(_lang CXX)
+ else()
+ message(FATAL_ERROR "CHECK_INCLUDE_FILES needs either C or CXX language enabled.\n")
+ endif()
+ elseif("x${ARGN}" MATCHES "^xLANGUAGE;([a-zA-Z]+)$")
+ set(_lang "${CMAKE_MATCH_1}")
+ elseif("x${ARGN}" MATCHES "^xLANGUAGE$")
+ message(FATAL_ERROR "No languages listed for LANGUAGE option.\nSupported languages: C, CXX.\n")
+ else()
+ message(FATAL_ERROR "Unknown arguments:\n ${ARGN}\n")
+ endif()
+
+ if(_lang STREQUAL "C")
+ set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckIncludeFiles/${VARIABLE}.c)
+ elseif(_lang STREQUAL "CXX")
+ set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckIncludeFiles/${VARIABLE}.cpp)
+ else()
+ message(FATAL_ERROR "Unknown language:\n ${_lang}\nSupported languages: C, CXX.\n")
+ endif()
+
+ if(CMAKE_REQUIRED_INCLUDES)
+ set(CHECK_INCLUDE_FILES_INCLUDE_DIRS "-DINCLUDE_DIRECTORIES=${CMAKE_REQUIRED_INCLUDES}")
+ else()
+ set(CHECK_INCLUDE_FILES_INCLUDE_DIRS)
+ endif()
+ set(CHECK_INCLUDE_FILES_CONTENT "/* */\n")
+ set(MACRO_CHECK_INCLUDE_FILES_FLAGS ${CMAKE_REQUIRED_FLAGS})
+ foreach(FILE ${INCLUDE})
+ string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT
+ "#include <${FILE}>\n")
+ endforeach()
+ string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT
+ "\n\nint main(void){return 0;}\n")
+ configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
+ "${src}" @ONLY)
+
+ set(_INCLUDE ${INCLUDE}) # remove empty elements
+ if("${_INCLUDE}" MATCHES "^([^;]+);.+;([^;]+)$")
+ list(LENGTH _INCLUDE _INCLUDE_LEN)
+ set(_description "${_INCLUDE_LEN} include files ${CMAKE_MATCH_1}, ..., ${CMAKE_MATCH_2}")
+ elseif("${_INCLUDE}" MATCHES "^([^;]+);([^;]+)$")
+ set(_description "include files ${CMAKE_MATCH_1}, ${CMAKE_MATCH_2}")
+ else()
+ set(_description "include file ${_INCLUDE}")
+ endif()
+
+ set(_CIF_LINK_OPTIONS)
+ if(CMAKE_REQUIRED_LINK_OPTIONS)
+ set(_CIF_LINK_OPTIONS LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
+ endif()
+
+ set(_CIF_LINK_LIBRARIES "")
+ if(CMAKE_REQUIRED_LIBRARIES)
+ cmake_policy(GET CMP0075 _CIF_CMP0075
+ PARENT_SCOPE # undocumented, do not use outside of CMake
+ )
+ if("x${_CIF_CMP0075}x" STREQUAL "xNEWx")
+ set(_CIF_LINK_LIBRARIES LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
+ elseif("x${_CIF_CMP0075}x" STREQUAL "xOLDx")
+ elseif(NOT _CIF_CMP0075_WARNED)
+ set(_CIF_CMP0075_WARNED 1)
+ message(AUTHOR_WARNING
+ "Policy CMP0075 is not set: Include file check macros honor CMAKE_REQUIRED_LIBRARIES. "
+ "Run \"cmake --help-policy CMP0075\" for policy details. "
+ "Use the cmake_policy command to set the policy and suppress this warning."
+ "\n"
+ "CMAKE_REQUIRED_LIBRARIES is set to:\n"
+ " ${CMAKE_REQUIRED_LIBRARIES}\n"
+ "For compatibility with CMake 3.11 and below this check is ignoring it."
+ )
+ endif()
+ unset(_CIF_CMP0075)
+ endif()
+
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_START "Looking for ${_description}")
+ endif()
+ try_compile(${VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${src}
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ ${_CIF_LINK_OPTIONS}
+ ${_CIF_LINK_LIBRARIES}
+ CMAKE_FLAGS
+ -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_INCLUDE_FILES_FLAGS}
+ "${CHECK_INCLUDE_FILES_INCLUDE_DIRS}"
+ OUTPUT_VARIABLE OUTPUT)
+ unset(_CIF_LINK_OPTIONS)
+ unset(_CIF_LINK_LIBRARIES)
+ if(${VARIABLE})
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_PASS "found")
+ endif()
+ set(${VARIABLE} 1 CACHE INTERNAL "Have include ${INCLUDE}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if files ${INCLUDE} "
+ "exist passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ else()
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_FAIL "not found")
+ endif()
+ set(${VARIABLE} "" CACHE INTERNAL "Have includes ${INCLUDE}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if files ${INCLUDE} "
+ "exist failed with the following output:\n"
+ "${OUTPUT}\nSource:\n${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
+ endif()
+ endif()
+endmacro()
diff --git a/Modules/CheckLanguage.cmake b/Modules/CheckLanguage.cmake
new file mode 100644
index 0000000..928881c
--- /dev/null
+++ b/Modules/CheckLanguage.cmake
@@ -0,0 +1,112 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckLanguage
+-------------
+
+Check if a language can be enabled
+
+Usage:
+
+::
+
+ check_language(<lang>)
+
+where ``<lang>`` is a language that may be passed to :command:`enable_language`
+such as ``Fortran``. If :variable:`CMAKE_<LANG>_COMPILER` is already defined
+the check does nothing. Otherwise it tries enabling the language in a
+test project. The result is cached in :variable:`CMAKE_<LANG>_COMPILER`
+as the compiler that was found, or ``NOTFOUND`` if the language cannot be
+enabled. For CUDA which can have an explicit host compiler, the cache
+:variable:`CMAKE_CUDA_HOST_COMPILER` variable will be set if it was required
+for compilation (and cleared if it was not).
+
+Example:
+
+::
+
+ check_language(Fortran)
+ if(CMAKE_Fortran_COMPILER)
+ enable_language(Fortran)
+ else()
+ message(STATUS "No Fortran support")
+ endif()
+#]=======================================================================]
+
+include_guard(GLOBAL)
+
+macro(check_language lang)
+ if(NOT DEFINED CMAKE_${lang}_COMPILER)
+ set(_desc "Looking for a ${lang} compiler")
+ message(CHECK_START "${_desc}")
+ file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang})
+
+ set(extra_compiler_variables)
+ if(${lang} STREQUAL CUDA)
+ set(extra_compiler_variables "set(CMAKE_CUDA_HOST_COMPILER \\\"\${CMAKE_CUDA_HOST_COMPILER}\\\")")
+ endif()
+
+ set(_cl_content
+ "cmake_minimum_required(VERSION ${CMAKE_VERSION})
+project(Check${lang} ${lang})
+file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
+ \"set(CMAKE_${lang}_COMPILER \\\"\${CMAKE_${lang}_COMPILER}\\\")\\n\"
+ \"${extra_compiler_variables}\\n\"
+ )"
+ )
+
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}/CMakeLists.txt"
+ "${_cl_content}")
+ if(CMAKE_GENERATOR_INSTANCE)
+ set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${CMAKE_GENERATOR_INSTANCE}")
+ else()
+ set(_D_CMAKE_GENERATOR_INSTANCE "")
+ endif()
+ if(CMAKE_GENERATOR MATCHES "^(Xcode$|Green Hills MULTI$|Visual Studio)")
+ set(_D_CMAKE_MAKE_PROGRAM "")
+ else()
+ set(_D_CMAKE_MAKE_PROGRAM "-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}")
+ endif()
+ if(CMAKE_TOOLCHAIN_FILE)
+ set(_D_CMAKE_TOOLCHAIN_FILE "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}")
+ else()
+ set(_D_CMAKE_TOOLCHAIN_FILE "")
+ endif()
+ execute_process(
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}
+ COMMAND ${CMAKE_COMMAND} . -G ${CMAKE_GENERATOR}
+ -A "${CMAKE_GENERATOR_PLATFORM}"
+ -T "${CMAKE_GENERATOR_TOOLSET}"
+ ${_D_CMAKE_GENERATOR_INSTANCE}
+ ${_D_CMAKE_MAKE_PROGRAM}
+ ${_D_CMAKE_TOOLCHAIN_FILE}
+ OUTPUT_VARIABLE _cl_output
+ ERROR_VARIABLE _cl_output
+ RESULT_VARIABLE _cl_result
+ )
+ include(${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}/result.cmake OPTIONAL)
+ if(CMAKE_${lang}_COMPILER AND "${_cl_result}" STREQUAL "0")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "${_desc} passed with the following output:\n"
+ "${_cl_output}\n")
+ set(_CHECK_COMPILER_STATUS CHECK_PASS)
+ else()
+ set(CMAKE_${lang}_COMPILER NOTFOUND)
+ set(_CHECK_COMPILER_STATUS CHECK_FAIL)
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "${_desc} failed with the following output:\n"
+ "${_cl_output}\n")
+ endif()
+ message(${_CHECK_COMPILER_STATUS} "${CMAKE_${lang}_COMPILER}")
+ set(CMAKE_${lang}_COMPILER "${CMAKE_${lang}_COMPILER}" CACHE FILEPATH "${lang} compiler")
+ mark_as_advanced(CMAKE_${lang}_COMPILER)
+
+ if(CMAKE_${lang}_HOST_COMPILER)
+ message(STATUS "Looking for a ${lang} host compiler - ${CMAKE_${lang}_HOST_COMPILER}")
+ set(CMAKE_${lang}_HOST_COMPILER "${CMAKE_${lang}_HOST_COMPILER}" CACHE FILEPATH "${lang} host compiler")
+ mark_as_advanced(CMAKE_${lang}_HOST_COMPILER)
+ endif()
+
+ endif()
+endmacro()
diff --git a/Modules/CheckLibraryExists.cmake b/Modules/CheckLibraryExists.cmake
new file mode 100644
index 0000000..804e0cb
--- /dev/null
+++ b/Modules/CheckLibraryExists.cmake
@@ -0,0 +1,104 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckLibraryExists
+------------------
+
+Check if the function exists.
+
+.. command:: CHECK_LIBRARY_EXISTS
+
+ .. code-block:: cmake
+
+ CHECK_LIBRARY_EXISTS(LIBRARY FUNCTION LOCATION VARIABLE)
+
+ ::
+
+ LIBRARY - the name of the library you are looking for
+ FUNCTION - the name of the function
+ LOCATION - location where the library should be found
+ VARIABLE - variable to store the result
+ Will be created as an internal cache variable.
+
+
+
+The following variables may be set before calling this macro to modify
+the way the check is run:
+
+``CMAKE_REQUIRED_FLAGS``
+ string of compile command line flags.
+``CMAKE_REQUIRED_DEFINITIONS``
+ list of macros to define (-DFOO=bar).
+``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+ list of options to pass to link command.
+``CMAKE_REQUIRED_LIBRARIES``
+ list of libraries to link.
+``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+ execute quietly without messages.
+#]=======================================================================]
+
+include_guard(GLOBAL)
+
+macro(CHECK_LIBRARY_EXISTS LIBRARY FUNCTION LOCATION VARIABLE)
+ if(NOT DEFINED "${VARIABLE}")
+ set(MACRO_CHECK_LIBRARY_EXISTS_DEFINITION
+ "-DCHECK_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}")
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_START "Looking for ${FUNCTION} in ${LIBRARY}")
+ endif()
+ set(CHECK_LIBRARY_EXISTS_LINK_OPTIONS)
+ if(CMAKE_REQUIRED_LINK_OPTIONS)
+ set(CHECK_LIBRARY_EXISTS_LINK_OPTIONS
+ LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
+ endif()
+ set(CHECK_LIBRARY_EXISTS_LIBRARIES ${LIBRARY})
+ if(CMAKE_REQUIRED_LIBRARIES)
+ set(CHECK_LIBRARY_EXISTS_LIBRARIES
+ ${CHECK_LIBRARY_EXISTS_LIBRARIES} ${CMAKE_REQUIRED_LIBRARIES})
+ endif()
+
+ if(CMAKE_C_COMPILER_LOADED)
+ set(_cle_source ${CMAKE_ROOT}/Modules/CheckFunctionExists.c)
+ elseif(CMAKE_CXX_COMPILER_LOADED)
+ set(_cle_source ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckLibraryExists/CheckFunctionExists.cxx)
+ configure_file(${CMAKE_ROOT}/Modules/CheckFunctionExists.c "${_cle_source}" COPYONLY)
+ else()
+ message(FATAL_ERROR "CHECK_FUNCTION_EXISTS needs either C or CXX language enabled")
+ endif()
+
+ try_compile(${VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${_cle_source}
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ ${CHECK_LIBRARY_EXISTS_LINK_OPTIONS}
+ LINK_LIBRARIES ${CHECK_LIBRARY_EXISTS_LIBRARIES}
+ CMAKE_FLAGS
+ -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_LIBRARY_EXISTS_DEFINITION}
+ -DLINK_DIRECTORIES:STRING=${LOCATION}
+ OUTPUT_VARIABLE OUTPUT)
+ unset(_cle_source)
+
+ if(${VARIABLE})
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_PASS "found")
+ endif()
+ set(${VARIABLE} 1 CACHE INTERNAL "Have library ${LIBRARY}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the function ${FUNCTION} exists in the ${LIBRARY} "
+ "passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ else()
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_FAIL "not found")
+ endif()
+ set(${VARIABLE} "" CACHE INTERNAL "Have library ${LIBRARY}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the function ${FUNCTION} exists in the ${LIBRARY} "
+ "failed with the following output:\n"
+ "${OUTPUT}\n\n")
+ endif()
+ endif()
+endmacro()
diff --git a/Modules/CheckLibraryExists.lists.in b/Modules/CheckLibraryExists.lists.in
new file mode 100644
index 0000000..741b87d
--- /dev/null
+++ b/Modules/CheckLibraryExists.lists.in
@@ -0,0 +1,8 @@
+PROJECT(CHECK_LIBRARY_EXISTS)
+
+
+ADD_DEFINITIONS(-DCHECK_FUNCTION_EXISTS=${CHECK_LIBRARY_EXISTS_FUNCTION})
+LINK_DIRECTORIES(${CHECK_LIBRARY_EXISTS_LOCATION})
+ADD_EXECUTABLE(CheckLibraryExists ${CHECK_LIBRARY_EXISTS_SOURCE})
+TARGET_LINK_LIBRARIES(CheckLibraryExists ${CHECK_LIBRARY_EXISTS_LIBRARY})
+
diff --git a/Modules/CheckLinkerFlag.cmake b/Modules/CheckLinkerFlag.cmake
new file mode 100644
index 0000000..3c7a828
--- /dev/null
+++ b/Modules/CheckLinkerFlag.cmake
@@ -0,0 +1,82 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckLinkerFlag
+---------------
+
+.. versionadded:: 3.18
+
+Check whether the compiler supports a given link flag.
+
+.. command:: check_linker_flag
+
+ .. code-block:: cmake
+
+ check_linker_flag(<lang> <flag> <var>)
+
+Check that the link ``<flag>`` is accepted by the ``<lang>`` compiler without
+a diagnostic. Stores the result in an internal cache entry named ``<var>``.
+
+This command temporarily sets the ``CMAKE_REQUIRED_LINK_OPTIONS`` variable
+and calls the :command:`check_source_compiles` command from the
+:module:`CheckSourceCompiles` module. See that module's documentation
+for a listing of variables that can otherwise modify the build.
+
+The underlying implementation relies on the :prop_tgt:`LINK_OPTIONS` property
+to check the specified flag. The ``LINKER:`` prefix, as described in the
+:command:`target_link_options` command, can be used as well.
+
+A positive result from this check indicates only that the compiler did not
+issue a diagnostic message when given the link 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`, unknown flags in such variables may
+ cause a false negative for this check.
+#]=======================================================================]
+
+include_guard(GLOBAL)
+
+include(CMakeCheckCompilerFlagCommonPatterns)
+
+function(CHECK_LINKER_FLAG _lang _flag _var)
+ get_property (_supported_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
+ if (NOT _lang IN_LIST _supported_languages)
+ message (SEND_ERROR "check_linker_flag: ${_lang}: unknown language.")
+ return()
+ endif()
+
+ include (CheckSourceCompiles)
+
+ set(CMAKE_REQUIRED_LINK_OPTIONS "${_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()
+
+ if (_lang MATCHES "^(C|CXX)$")
+ set (_source "int main() { return 0; }")
+ elseif (_lang STREQUAL "Fortran")
+ set (_source " program test\n stop\n end program")
+ elseif (_lang MATCHES "CUDA")
+ set (_source "__host__ int main() { return 0; }")
+ elseif (_lang MATCHES "^(OBJC|OBJCXX)$")
+ set (_source "#ifndef __OBJC__\n# error \"Not an Objective-C++ compiler\"\n#endif\nint main(void) { return 0; }")
+ else()
+ message (SEND_ERROR "check_linker_flag: ${_lang}: unsupported language.")
+ return()
+ endif()
+ check_compiler_flag_common_patterns(_common_patterns)
+
+ check_source_compiles(${_lang} "${_source}" ${_var} ${_common_patterns})
+
+ foreach(v IN LISTS _locale_vars)
+ set(ENV{${v}} ${_locale_vars_saved_${v}})
+ endforeach()
+ set(${_var} "${${_var}}" PARENT_SCOPE)
+endfunction()
diff --git a/Modules/CheckOBJCCompilerFlag.cmake b/Modules/CheckOBJCCompilerFlag.cmake
new file mode 100644
index 0000000..d8d8741
--- /dev/null
+++ b/Modules/CheckOBJCCompilerFlag.cmake
@@ -0,0 +1,43 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckOBJCCompilerFlag
+---------------------
+
+.. versionadded:: 3.16
+
+Check whether the Objective-C compiler supports a given flag.
+
+.. command:: check_objc_compiler_flag
+
+ .. code-block:: cmake
+
+ check_objc_compiler_flag(<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_objc_source_compiles`` macro from the
+:module:`CheckOBJCSourceCompiles` 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_OBJC_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags
+ in such variables may cause a false negative for this check.
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(CheckOBJCSourceCompiles)
+include(Internal/CheckCompilerFlag)
+
+macro (CHECK_OBJC_COMPILER_FLAG _FLAG _RESULT)
+ cmake_check_compiler_flag(OBJC "${_FLAG}" ${_RESULT})
+endmacro ()
diff --git a/Modules/CheckOBJCSourceCompiles.cmake b/Modules/CheckOBJCSourceCompiles.cmake
new file mode 100644
index 0000000..c268ef9
--- /dev/null
+++ b/Modules/CheckOBJCSourceCompiles.cmake
@@ -0,0 +1,75 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckOBJCSourceCompiles
+-----------------------
+
+.. versionadded:: 3.16
+
+Check if given Objective-C source compiles and links into an executable.
+
+.. command:: check_objc_source_compiles
+
+ .. code-block:: cmake
+
+ check_objc_source_compiles(<code> <resultVar>
+ [FAIL_REGEX <regex1> [<regex2>...]])
+
+ Check that the source supplied in ``<code>`` can be compiled as a Objectie-C source
+ file and linked as an executable (so it must contain at least a ``main()``
+ function). The result will be stored in the internal cache variable specified
+ by ``<resultVar>``, with a boolean true value for success and boolean false
+ for failure. If ``FAIL_REGEX`` is provided, then failure is determined by
+ checking if anything in the output matches any of the specified regular
+ expressions.
+
+ The underlying check is performed by the :command:`try_compile` command. The
+ compile and link commands can be influenced by setting any of the following
+ variables prior to calling ``check_objc_source_compiles()``:
+
+ ``CMAKE_REQUIRED_FLAGS``
+ Additional flags to pass to the compiler. Note that the contents of
+ :variable:`CMAKE_OBJC_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated
+ configuration-specific variable are automatically added to the compiler
+ command before the contents of ``CMAKE_REQUIRED_FLAGS``.
+
+ ``CMAKE_REQUIRED_DEFINITIONS``
+ A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form
+ ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by
+ ``<resultVar>`` will also be added automatically.
+
+ ``CMAKE_REQUIRED_INCLUDES``
+ A :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler. These will be the only header search paths used by
+ ``try_compile()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES`
+ directory property will be ignored.
+
+ ``CMAKE_REQUIRED_LINK_OPTIONS``
+ A :ref:`;-list <CMake Language Lists>` of options to add to the link
+ command (see :command:`try_compile` for further details).
+
+ ``CMAKE_REQUIRED_LIBRARIES``
+ A :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. These can be the name of system libraries or they can be
+ :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for
+ further details).
+
+ ``CMAKE_REQUIRED_QUIET``
+ If this variable evaluates to a boolean true value, all status messages
+ associated with the check will be suppressed.
+
+ The check is only performed once, with the result cached in the variable
+ named by ``<resultVar>``. Every subsequent CMake run will re-use this cached
+ value rather than performing the check again, even if the ``<code>`` changes.
+ In order to force the check to be re-evaluated, the variable named by
+ ``<resultVar>`` must be manually removed from the cache.
+
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(Internal/CheckSourceCompiles)
+
+macro(CHECK_OBJC_SOURCE_COMPILES SOURCE VAR)
+ cmake_check_source_compiles(OBJC "${SOURCE}" ${VAR} ${ARGN})
+endmacro()
diff --git a/Modules/CheckOBJCSourceRuns.cmake b/Modules/CheckOBJCSourceRuns.cmake
new file mode 100644
index 0000000..dd03309
--- /dev/null
+++ b/Modules/CheckOBJCSourceRuns.cmake
@@ -0,0 +1,76 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckOBJCSourceRuns
+-------------------
+
+.. versionadded:: 3.16
+
+Check if given Objective-C source compiles and links into an executable and can
+subsequently be run.
+
+.. command:: check_objc_source_runs
+
+ .. code-block:: cmake
+
+ check_objc_source_runs(<code> <resultVar>)
+
+ Check that the source supplied in ``<code>`` can be compiled as a Objective-C source
+ file, linked as an executable and then run. The ``<code>`` must contain at
+ least a ``main()`` function. If the ``<code>`` could be built and run
+ successfully, the internal cache variable specified by ``<resultVar>`` will
+ be set to 1, otherwise it will be set to an value that evaluates to boolean
+ false (e.g. an empty string or an error message).
+
+ The underlying check is performed by the :command:`try_run` command. The
+ compile and link commands can be influenced by setting any of the following
+ variables prior to calling ``check_objc_source_runs()``:
+
+ ``CMAKE_REQUIRED_FLAGS``
+ Additional flags to pass to the compiler. Note that the contents of
+ :variable:`CMAKE_OBJC_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated
+ configuration-specific variable are automatically added to the compiler
+ command before the contents of ``CMAKE_REQUIRED_FLAGS``.
+
+ ``CMAKE_REQUIRED_DEFINITIONS``
+ A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form
+ ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by
+ ``<resultVar>`` will also be added automatically.
+
+ ``CMAKE_REQUIRED_INCLUDES``
+ A :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler. These will be the only header search paths used by
+ ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES`
+ directory property will be ignored.
+
+ ``CMAKE_REQUIRED_LINK_OPTIONS``
+ A :ref:`;-list <CMake Language Lists>` of options to add to the link
+ command (see :command:`try_run` for further details).
+
+ ``CMAKE_REQUIRED_LIBRARIES``
+ A :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. These can be the name of system libraries or they can be
+ :ref:`Imported Targets <Imported Targets>` (see :command:`try_run` for
+ further details).
+
+ ``CMAKE_REQUIRED_QUIET``
+ If this variable evaluates to a boolean true value, all status messages
+ associated with the check will be suppressed.
+
+ The check is only performed once, with the result cached in the variable
+ named by ``<resultVar>``. Every subsequent CMake run will re-use this cached
+ value rather than performing the check again, even if the ``<code>`` changes.
+ In order to force the check to be re-evaluated, the variable named by
+ ``<resultVar>`` must be manually removed from the cache.
+
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(Internal/CheckSourceRuns)
+
+macro(CHECK_OBJC_SOURCE_RUNS SOURCE VAR)
+ set(_CheckSourceRuns_old_signature 1)
+ cmake_check_source_runs(OBJC "${SOURCE}" ${VAR} ${ARGN})
+ unset(_CheckSourceRuns_old_signature)
+endmacro()
diff --git a/Modules/CheckOBJCXXCompilerFlag.cmake b/Modules/CheckOBJCXXCompilerFlag.cmake
new file mode 100644
index 0000000..3f3f8fe
--- /dev/null
+++ b/Modules/CheckOBJCXXCompilerFlag.cmake
@@ -0,0 +1,43 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckOBJCXXCompilerFlag
+-----------------------
+
+.. versionadded:: 3.16
+
+Check whether the Objective-C++ compiler supports a given flag.
+
+.. command:: check_objcxx_compiler_flag
+
+ .. code-block:: cmake
+
+ check_objcxx_compiler_flag(<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_objcxx_source_compiles`` macro from the
+:module:`CheckOBJCXXSourceCompiles` 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_OBJCXX_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags
+ in such variables may cause a false negative for this check.
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(CheckOBJCXXSourceCompiles)
+include(Internal/CheckCompilerFlag)
+
+macro (CHECK_OBJCXX_COMPILER_FLAG _FLAG _RESULT)
+ cmake_check_compiler_flag(OBJCXX "${_FLAG}" ${_RESULT})
+endmacro ()
diff --git a/Modules/CheckOBJCXXSourceCompiles.cmake b/Modules/CheckOBJCXXSourceCompiles.cmake
new file mode 100644
index 0000000..1186934
--- /dev/null
+++ b/Modules/CheckOBJCXXSourceCompiles.cmake
@@ -0,0 +1,75 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckOBJCXXSourceCompiles
+-------------------------
+
+.. versionadded:: 3.16
+
+Check if given Objective-C++ source compiles and links into an executable.
+
+.. command:: check_objcxx_source_compiles
+
+ .. code-block:: cmake
+
+ check_objcxx_source_compiles(<code> <resultVar>
+ [FAIL_REGEX <regex1> [<regex2>...]])
+
+ Check that the source supplied in ``<code>`` can be compiled as a Objective-C++ source
+ file and linked as an executable (so it must contain at least a ``main()``
+ function). The result will be stored in the internal cache variable specified
+ by ``<resultVar>``, with a boolean true value for success and boolean false
+ for failure. If ``FAIL_REGEX`` is provided, then failure is determined by
+ checking if anything in the output matches any of the specified regular
+ expressions.
+
+ The underlying check is performed by the :command:`try_compile` command. The
+ compile and link commands can be influenced by setting any of the following
+ variables prior to calling ``check_objcxx_source_compiles()``:
+
+ ``CMAKE_REQUIRED_FLAGS``
+ Additional flags to pass to the compiler. Note that the contents of
+ :variable:`CMAKE_OBJCXX_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated
+ configuration-specific variable are automatically added to the compiler
+ command before the contents of ``CMAKE_REQUIRED_FLAGS``.
+
+ ``CMAKE_REQUIRED_DEFINITIONS``
+ A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form
+ ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by
+ ``<resultVar>`` will also be added automatically.
+
+ ``CMAKE_REQUIRED_INCLUDES``
+ A :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler. These will be the only header search paths used by
+ ``try_compile()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES`
+ directory property will be ignored.
+
+ ``CMAKE_REQUIRED_LINK_OPTIONS``
+ A :ref:`;-list <CMake Language Lists>` of options to add to the link
+ command (see :command:`try_compile` for further details).
+
+ ``CMAKE_REQUIRED_LIBRARIES``
+ A :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. These can be the name of system libraries or they can be
+ :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for
+ further details).
+
+ ``CMAKE_REQUIRED_QUIET``
+ If this variable evaluates to a boolean true value, all status messages
+ associated with the check will be suppressed.
+
+ The check is only performed once, with the result cached in the variable
+ named by ``<resultVar>``. Every subsequent CMake run will re-use this cached
+ value rather than performing the check again, even if the ``<code>`` changes.
+ In order to force the check to be re-evaluated, the variable named by
+ ``<resultVar>`` must be manually removed from the cache.
+
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(Internal/CheckSourceCompiles)
+
+macro(CHECK_OBJCXX_SOURCE_COMPILES SOURCE VAR)
+ cmake_check_source_compiles(OBJCXX "${SOURCE}" ${VAR} ${ARGN})
+endmacro()
diff --git a/Modules/CheckOBJCXXSourceRuns.cmake b/Modules/CheckOBJCXXSourceRuns.cmake
new file mode 100644
index 0000000..05a5e4c
--- /dev/null
+++ b/Modules/CheckOBJCXXSourceRuns.cmake
@@ -0,0 +1,76 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckOBJCXXSourceRuns
+---------------------
+
+.. versionadded:: 3.16
+
+Check if given Objective-C++ source compiles and links into an executable and can
+subsequently be run.
+
+.. command:: check_objcxx_source_runs
+
+ .. code-block:: cmake
+
+ check_objcxx_source_runs(<code> <resultVar>)
+
+ Check that the source supplied in ``<code>`` can be compiled as a Objective-C++ source
+ file, linked as an executable and then run. The ``<code>`` must contain at
+ least a ``main()`` function. If the ``<code>`` could be built and run
+ successfully, the internal cache variable specified by ``<resultVar>`` will
+ be set to 1, otherwise it will be set to an value that evaluates to boolean
+ false (e.g. an empty string or an error message).
+
+ The underlying check is performed by the :command:`try_run` command. The
+ compile and link commands can be influenced by setting any of the following
+ variables prior to calling ``check_objcxx_source_runs()``:
+
+ ``CMAKE_REQUIRED_FLAGS``
+ Additional flags to pass to the compiler. Note that the contents of
+ :variable:`CMAKE_OBJCXX_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated
+ configuration-specific variable are automatically added to the compiler
+ command before the contents of ``CMAKE_REQUIRED_FLAGS``.
+
+ ``CMAKE_REQUIRED_DEFINITIONS``
+ A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form
+ ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by
+ ``<resultVar>`` will also be added automatically.
+
+ ``CMAKE_REQUIRED_INCLUDES``
+ A :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler. These will be the only header search paths used by
+ ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES`
+ directory property will be ignored.
+
+ ``CMAKE_REQUIRED_LINK_OPTIONS``
+ A :ref:`;-list <CMake Language Lists>` of options to add to the link
+ command (see :command:`try_run` for further details).
+
+ ``CMAKE_REQUIRED_LIBRARIES``
+ A :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. These can be the name of system libraries or they can be
+ :ref:`Imported Targets <Imported Targets>` (see :command:`try_run` for
+ further details).
+
+ ``CMAKE_REQUIRED_QUIET``
+ If this variable evaluates to a boolean true value, all status messages
+ associated with the check will be suppressed.
+
+ The check is only performed once, with the result cached in the variable
+ named by ``<resultVar>``. Every subsequent CMake run will re-use this cached
+ value rather than performing the check again, even if the ``<code>`` changes.
+ In order to force the check to be re-evaluated, the variable named by
+ ``<resultVar>`` must be manually removed from the cache.
+
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(Internal/CheckSourceRuns)
+
+macro(CHECK_OBJCXX_SOURCE_RUNS SOURCE VAR)
+ set(_CheckSourceRuns_old_signature 1)
+ cmake_check_source_runs(OBJCXX "${SOURCE}" ${VAR} ${ARGN})
+ unset(_CheckSourceRuns_old_signature)
+endmacro()
diff --git a/Modules/CheckPIESupported.cmake b/Modules/CheckPIESupported.cmake
new file mode 100644
index 0000000..fb87822
--- /dev/null
+++ b/Modules/CheckPIESupported.cmake
@@ -0,0 +1,138 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckPIESupported
+-----------------
+
+.. versionadded:: 3.14
+
+Check whether the linker supports Position Independent Code (PIE) or No
+Position Independent Code (NO_PIE) for executables.
+Use this to ensure that the :prop_tgt:`POSITION_INDEPENDENT_CODE` target
+property for executables will be honored at link time.
+
+.. command:: check_pie_supported
+
+ ::
+
+ check_pie_supported([OUTPUT_VARIABLE <output>]
+ [LANGUAGES <lang>...])
+
+ Options are:
+
+ ``OUTPUT_VARIABLE <output>``
+ Set ``<output>`` variable with details about any error.
+ ``LANGUAGES <lang>...``
+ Check the linkers used for each of the specified languages.
+ Supported languages are ``C``, ``CXX``, and ``Fortran``.
+
+It makes no sense to use this module when :policy:`CMP0083` is set to ``OLD``,
+so the command will return an error in this case. See policy :policy:`CMP0083`
+for details.
+
+Variables
+^^^^^^^^^
+
+For each language checked, two boolean cache variables are defined.
+
+ ``CMAKE_<lang>_LINK_PIE_SUPPORTED``
+ Set to ``YES`` if ``PIE`` is supported by the linker and ``NO`` otherwise.
+ ``CMAKE_<lang>_LINK_NO_PIE_SUPPORTED``
+ Set to ``YES`` if ``NO_PIE`` is supported by the linker and ``NO`` otherwise.
+
+Examples
+^^^^^^^^
+
+.. code-block:: cmake
+
+ check_pie_supported()
+ set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE TRUE)
+
+.. code-block:: cmake
+
+ # Retrieve any error message.
+ check_pie_supported(OUTPUT_VARIABLE output LANGUAGES C)
+ set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE TRUE)
+ if(NOT CMAKE_C_LINK_PIE_SUPPORTED)
+ message(WARNING "PIE is not supported at link time: ${output}.\n"
+ "PIE link options will not be passed to linker.")
+ endif()
+
+#]=======================================================================]
+
+
+include (Internal/CMakeTryCompilerOrLinkerFlag)
+
+function (check_pie_supported)
+ cmake_policy(GET CMP0083 cmp0083)
+
+ if (NOT cmp0083)
+ message(FATAL_ERROR "check_pie_supported: Policy CMP0083 is not set")
+ endif()
+
+ if(cmp0083 STREQUAL "OLD")
+ message(FATAL_ERROR "check_pie_supported: Policy CMP0083 set to OLD")
+ endif()
+
+ set(optional)
+ set(one OUTPUT_VARIABLE)
+ set(multiple LANGUAGES)
+
+ cmake_parse_arguments(CHECK_PIE "${optional}" "${one}" "${multiple}" "${ARGN}")
+ if(CHECK_PIE_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "check_pie_supported: Unparsed arguments: ${CHECK_PIE_UNPARSED_ARGUMENTS}")
+ endif()
+
+ if (CHECK_PIE_LANGUAGES)
+ set (unsupported_languages "${CHECK_PIE_LANGUAGES}")
+ list (REMOVE_ITEM unsupported_languages "C" "CXX" "Fortran")
+ if(unsupported_languages)
+ message(FATAL_ERROR "check_pie_supported: language(s) '${unsupported_languages}' not supported")
+ endif()
+ else()
+ # User did not set any languages, use defaults
+ get_property (enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
+ if (NOT enabled_languages)
+ return()
+ endif()
+
+ list (FILTER enabled_languages INCLUDE REGEX "^(C|CXX|Fortran)$")
+ if (NOT enabled_languages)
+ return()
+ endif()
+
+ set (CHECK_PIE_LANGUAGES ${enabled_languages})
+ endif()
+
+ set (outputs)
+
+ foreach(lang IN LISTS CHECK_PIE_LANGUAGES)
+ if(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER)
+ cmake_try_compiler_or_linker_flag(${lang}
+ "${CMAKE_${lang}_LINK_OPTIONS_PIE}"
+ CMAKE_${lang}_LINK_PIE_SUPPORTED
+ OUTPUT_VARIABLE output)
+ if (NOT CMAKE_${lang}_LINK_PIE_SUPPORTED)
+ string (APPEND outputs "PIE (${lang}): ${output}\n")
+ endif()
+
+ cmake_try_compiler_or_linker_flag(${lang}
+ "${CMAKE_${lang}_LINK_OPTIONS_NO_PIE}"
+ CMAKE_${lang}_LINK_NO_PIE_SUPPORTED
+ OUTPUT_VARIABLE output)
+ if (NOT CMAKE_${lang}_LINK_NO_PIE_SUPPORTED)
+ string (APPEND outputs "NO_PIE (${lang}): ${output}\n")
+ endif()
+ else()
+ # no support at link time. Set cache variables to NO
+ set(CMAKE_${lang}_LINK_PIE_SUPPORTED NO CACHE INTERNAL "PIE (${lang})")
+ set(CMAKE_${lang}_LINK_NO_PIE_SUPPORTED NO CACHE INTERNAL "NO_PIE (${lang})")
+ string (APPEND outputs "PIE and NO_PIE are not supported by linker for ${lang}")
+ endif()
+ endforeach()
+
+ if (CHECK_PIE_OUTPUT_VARIABLE)
+ set (${CHECK_PIE_OUTPUT_VARIABLE} "${outputs}" PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/Modules/CheckPrototypeDefinition.c.in b/Modules/CheckPrototypeDefinition.c.in
new file mode 100644
index 0000000..a97344a
--- /dev/null
+++ b/Modules/CheckPrototypeDefinition.c.in
@@ -0,0 +1,29 @@
+@CHECK_PROTOTYPE_DEFINITION_HEADER@
+
+static void cmakeRequireSymbol(int dummy, ...) {
+ (void) dummy;
+}
+
+static void checkSymbol(void) {
+#ifndef @CHECK_PROTOTYPE_DEFINITION_SYMBOL@
+ cmakeRequireSymbol(0, &@CHECK_PROTOTYPE_DEFINITION_SYMBOL@);
+#endif
+}
+
+@CHECK_PROTOTYPE_DEFINITION_PROTO@ {
+ return @CHECK_PROTOTYPE_DEFINITION_RETURN@;
+}
+
+#ifdef __CLASSIC_C__
+int main() {
+ int ac;
+ char*av[];
+#else
+int main(int ac, char *av[]) {
+#endif
+ checkSymbol();
+ if (ac > 1000) {
+ return *av[0];
+ }
+ return 0;
+}
diff --git a/Modules/CheckPrototypeDefinition.cmake b/Modules/CheckPrototypeDefinition.cmake
new file mode 100644
index 0000000..d29c5e8
--- /dev/null
+++ b/Modules/CheckPrototypeDefinition.cmake
@@ -0,0 +1,131 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckPrototypeDefinition
+------------------------
+
+Check if the prototype we expect is correct.
+
+.. command:: check_prototype_definition
+
+ .. code-block:: cmake
+
+ check_prototype_definition(FUNCTION PROTOTYPE RETURN HEADER VARIABLE)
+
+ ::
+
+ FUNCTION - The name of the function (used to check if prototype exists)
+ PROTOTYPE- The prototype to check.
+ RETURN - The return value of the function.
+ HEADER - The header files required.
+ VARIABLE - The variable to store the result.
+ Will be created as an internal cache variable.
+
+ Example:
+
+ .. code-block:: cmake
+
+ check_prototype_definition(getpwent_r
+ "struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)"
+ "NULL"
+ "unistd.h;pwd.h"
+ SOLARIS_GETPWENT_R)
+
+The following variables may be set before calling this function to modify
+the way the check is run:
+
+``CMAKE_REQUIRED_FLAGS``
+ string of compile command line flags.
+``CMAKE_REQUIRED_DEFINITIONS``
+ list of macros to define (-DFOO=bar).
+``CMAKE_REQUIRED_INCLUDES``
+ list of include directories.
+``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+ list of options to pass to link command.
+``CMAKE_REQUIRED_LIBRARIES``
+ list of libraries to link.
+``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+ execute quietly without messages.
+#]=======================================================================]
+
+#
+
+get_filename_component(__check_proto_def_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+include_guard(GLOBAL)
+
+function(check_prototype_definition _FUNCTION _PROTOTYPE _RETURN _HEADER _VARIABLE)
+
+ if (NOT DEFINED ${_VARIABLE})
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_START "Checking prototype ${_FUNCTION} for ${_VARIABLE}")
+ endif()
+ set(CHECK_PROTOTYPE_DEFINITION_CONTENT "/* */\n")
+
+ set(CHECK_PROTOTYPE_DEFINITION_FLAGS ${CMAKE_REQUIRED_FLAGS})
+ if (CMAKE_REQUIRED_LINK_OPTIONS)
+ set(CHECK_PROTOTYPE_DEFINITION_LINK_OPTIONS
+ LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
+ else()
+ set(CHECK_PROTOTYPE_DEFINITION_LINK_OPTIONS)
+ endif()
+ if (CMAKE_REQUIRED_LIBRARIES)
+ set(CHECK_PROTOTYPE_DEFINITION_LIBS
+ LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
+ else()
+ set(CHECK_PROTOTYPE_DEFINITION_LIBS)
+ endif()
+ if (CMAKE_REQUIRED_INCLUDES)
+ set(CMAKE_SYMBOL_EXISTS_INCLUDES
+ "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+ else()
+ set(CMAKE_SYMBOL_EXISTS_INCLUDES)
+ endif()
+
+ foreach(_FILE ${_HEADER})
+ string(APPEND CHECK_PROTOTYPE_DEFINITION_HEADER
+ "#include <${_FILE}>\n")
+ endforeach()
+
+ set(CHECK_PROTOTYPE_DEFINITION_SYMBOL ${_FUNCTION})
+ set(CHECK_PROTOTYPE_DEFINITION_PROTO ${_PROTOTYPE})
+ set(CHECK_PROTOTYPE_DEFINITION_RETURN ${_RETURN})
+
+ configure_file("${__check_proto_def_dir}/CheckPrototypeDefinition.c.in"
+ "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c" @ONLY)
+
+ file(READ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c _SOURCE)
+
+ try_compile(${_VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ ${CHECK_PROTOTYPE_DEFINITION_LINK_OPTIONS}
+ ${CHECK_PROTOTYPE_DEFINITION_LIBS}
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${CHECK_PROTOTYPE_DEFINITION_FLAGS}
+ "${CMAKE_SYMBOL_EXISTS_INCLUDES}"
+ OUTPUT_VARIABLE OUTPUT)
+
+ if (${_VARIABLE})
+ set(${_VARIABLE} 1 CACHE INTERNAL "Have correct prototype for ${_FUNCTION}")
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_PASS "True")
+ endif()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the prototype ${_FUNCTION} exists for ${_VARIABLE} passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ else ()
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_FAIL "False")
+ endif()
+ set(${_VARIABLE} 0 CACHE INTERNAL "Have correct prototype for ${_FUNCTION}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the prototype ${_FUNCTION} exists for ${_VARIABLE} failed with the following output:\n"
+ "${OUTPUT}\n\n${_SOURCE}\n\n")
+ endif ()
+ endif()
+
+endfunction()
diff --git a/Modules/CheckSizeOf.cmake b/Modules/CheckSizeOf.cmake
new file mode 100644
index 0000000..bd439e1
--- /dev/null
+++ b/Modules/CheckSizeOf.cmake
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+message(SEND_ERROR
+ "Modules/CheckSizeOf.cmake has been removed. "
+ "Use Modules/CheckTypeSize.cmake instead. This "
+ "compatibility check may be removed before the next release!")
diff --git a/Modules/CheckSourceCompiles.cmake b/Modules/CheckSourceCompiles.cmake
new file mode 100644
index 0000000..ad74c3c
--- /dev/null
+++ b/Modules/CheckSourceCompiles.cmake
@@ -0,0 +1,82 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+#[=======================================================================[.rst:
+CheckSourceCompiles
+----------------------
+
+.. versionadded:: 3.19
+
+Check if given source compiles and links into an executable.
+
+.. command:: check_source_compiles
+
+ .. code-block:: cmake
+
+ check_source_compiles(<lang> <code> <resultVar>
+ [FAIL_REGEX <regex1> [<regex2>...]]
+ [SRC_EXT <extension>])
+
+ Check that the source supplied in ``<code>`` can be compiled as a source
+ file for the requested language and linked as an executable (so it must
+ contain at least a ``main()`` function). The result will be stored in the
+ internal cache variable specified by ``<resultVar>``, with a boolean true
+ value for success and boolean false for failure. If ``FAIL_REGEX`` is
+ provided, then failure is determined by checking if anything in the output
+ matches any of the specified regular expressions.
+
+ By default, the test source file will be given a file extension that matches
+ the requested language. The ``SRC_EXT`` option can be used to override this
+ with ``.<extension>`` instead.
+
+ The underlying check is performed by the :command:`try_compile` command. The
+ compile and link commands can be influenced by setting any of the following
+ variables prior to calling ``check_source_compiles()``:
+
+ ``CMAKE_REQUIRED_FLAGS``
+ Additional flags to pass to the compiler. Note that the contents of
+ :variable:`CMAKE_<LANG>_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated
+ configuration-specific variable are automatically added to the compiler
+ command before the contents of ``CMAKE_REQUIRED_FLAGS``.
+
+ ``CMAKE_REQUIRED_DEFINITIONS``
+ A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form
+ ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by
+ ``<resultVar>`` will also be added automatically.
+
+ ``CMAKE_REQUIRED_INCLUDES``
+ A :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler. These will be the only header search paths used by
+ ``try_compile()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES`
+ directory property will be ignored.
+
+ ``CMAKE_REQUIRED_LINK_OPTIONS``
+ A :ref:`;-list <CMake Language Lists>` of options to add to the link
+ command (see :command:`try_compile` for further details).
+
+ ``CMAKE_REQUIRED_LIBRARIES``
+ A :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. These can be the name of system libraries or they can be
+ :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for
+ further details).
+
+ ``CMAKE_REQUIRED_QUIET``
+ If this variable evaluates to a boolean true value, all status messages
+ associated with the check will be suppressed.
+
+ The check is only performed once, with the result cached in the variable
+ named by ``<resultVar>``. Every subsequent CMake run will re-use this cached
+ value rather than performing the check again, even if the ``<code>`` changes.
+ In order to force the check to be re-evaluated, the variable named by
+ ``<resultVar>`` must be manually removed from the cache.
+
+#]=======================================================================]
+
+
+include_guard(GLOBAL)
+include(Internal/CheckSourceCompiles)
+
+function(CHECK_SOURCE_COMPILES _lang _source _var)
+ cmake_check_source_compiles(${_lang} "${_source}" ${_var} ${ARGN})
+endfunction()
diff --git a/Modules/CheckSourceRuns.cmake b/Modules/CheckSourceRuns.cmake
new file mode 100644
index 0000000..8f1cf01
--- /dev/null
+++ b/Modules/CheckSourceRuns.cmake
@@ -0,0 +1,80 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+#[=======================================================================[.rst:
+CheckSourceRuns
+-------------------
+
+.. versionadded:: 3.19
+
+Check if given source compiles and links into an executable and can
+subsequently be run.
+
+.. command:: check_source_runs
+
+ .. code-block:: cmake
+
+ check_source_runs(<lang> <code> <resultVar>
+ [SRC_EXT <extension>])
+
+ Check that the source supplied in ``<code>`` can be compiled as a source
+ file for the requested language, linked as an executable and then run.
+ The ``<code>`` must contain at least a ``main()`` function. If the ``<code>``
+ could be built and run successfully, the internal cache variable specified by
+ ``<resultVar>`` will be set to 1, otherwise it will be set to an value that
+ evaluates to boolean false (e.g. an empty string or an error message).
+
+ By default, the test source file will be given a file extension that matches
+ the requested language. The ``SRC_EXT`` option can be used to override this
+ with ``.<extension>`` instead.
+
+ The underlying check is performed by the :command:`try_run` command. The
+ compile and link commands can be influenced by setting any of the following
+ variables prior to calling ``check_objc_source_runs()``:
+
+ ``CMAKE_REQUIRED_FLAGS``
+ Additional flags to pass to the compiler. Note that the contents of
+ :variable:`CMAKE_OBJC_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated
+ configuration-specific variable are automatically added to the compiler
+ command before the contents of ``CMAKE_REQUIRED_FLAGS``.
+
+ ``CMAKE_REQUIRED_DEFINITIONS``
+ A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form
+ ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by
+ ``<resultVar>`` will also be added automatically.
+
+ ``CMAKE_REQUIRED_INCLUDES``
+ A :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler. These will be the only header search paths used by
+ ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES`
+ directory property will be ignored.
+
+ ``CMAKE_REQUIRED_LINK_OPTIONS``
+ A :ref:`;-list <CMake Language Lists>` of options to add to the link
+ command (see :command:`try_run` for further details).
+
+ ``CMAKE_REQUIRED_LIBRARIES``
+ A :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. These can be the name of system libraries or they can be
+ :ref:`Imported Targets <Imported Targets>` (see :command:`try_run` for
+ further details).
+
+ ``CMAKE_REQUIRED_QUIET``
+ If this variable evaluates to a boolean true value, all status messages
+ associated with the check will be suppressed.
+
+ The check is only performed once, with the result cached in the variable
+ named by ``<resultVar>``. Every subsequent CMake run will re-use this cached
+ value rather than performing the check again, even if the ``<code>`` changes.
+ In order to force the check to be re-evaluated, the variable named by
+ ``<resultVar>`` must be manually removed from the cache.
+
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(Internal/CheckSourceRuns)
+
+function(CHECK_SOURCE_RUNS _lang _source _var)
+ cmake_check_source_runs(${_lang} "${_source}" ${_var} ${ARGN})
+endfunction()
diff --git a/Modules/CheckStructHasMember.cmake b/Modules/CheckStructHasMember.cmake
new file mode 100644
index 0000000..8217c84
--- /dev/null
+++ b/Modules/CheckStructHasMember.cmake
@@ -0,0 +1,87 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckStructHasMember
+--------------------
+
+Check if the given struct or class has the specified member variable
+
+.. command:: CHECK_STRUCT_HAS_MEMBER
+
+ .. code-block:: cmake
+
+ CHECK_STRUCT_HAS_MEMBER(<struct> <member> <header> <variable>
+ [LANGUAGE <language>])
+
+ ::
+
+ <struct> - the name of the struct or class you are interested in
+ <member> - the member which existence you want to check
+ <header> - the header(s) where the prototype should be declared
+ <variable> - variable to store the result
+ <language> - the compiler to use (C or CXX)
+
+
+The following variables may be set before calling this macro to modify
+the way the check is run:
+
+``CMAKE_REQUIRED_FLAGS``
+ string of compile command line flags.
+``CMAKE_REQUIRED_DEFINITIONS``
+ list of macros to define (-DFOO=bar).
+``CMAKE_REQUIRED_INCLUDES``
+ list of include directories.
+``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+ list of options to pass to link command.
+``CMAKE_REQUIRED_LIBRARIES``
+ list of libraries to link.
+``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+ execute quietly without messages.
+
+
+Example:
+
+.. code-block:: cmake
+
+ CHECK_STRUCT_HAS_MEMBER("struct timeval" tv_sec sys/select.h
+ HAVE_TIMEVAL_TV_SEC LANGUAGE C)
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(CheckCSourceCompiles)
+include(CheckCXXSourceCompiles)
+
+macro (CHECK_STRUCT_HAS_MEMBER _STRUCT _MEMBER _HEADER _RESULT)
+ set(_INCLUDE_FILES)
+ foreach (it ${_HEADER})
+ string(APPEND _INCLUDE_FILES "#include <${it}>\n")
+ endforeach ()
+
+ if("x${ARGN}" STREQUAL "x")
+ set(_lang C)
+ elseif("x${ARGN}" MATCHES "^xLANGUAGE;([a-zA-Z]+)$")
+ set(_lang "${CMAKE_MATCH_1}")
+ else()
+ message(FATAL_ERROR "Unknown arguments:\n ${ARGN}\n")
+ endif()
+
+ set(_CHECK_STRUCT_MEMBER_SOURCE_CODE "
+${_INCLUDE_FILES}
+int main()
+{
+ (void)sizeof(((${_STRUCT} *)0)->${_MEMBER});
+ return 0;
+}
+")
+
+ if("${_lang}" STREQUAL "C")
+ CHECK_C_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT})
+ elseif("${_lang}" STREQUAL "CXX")
+ CHECK_CXX_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT})
+ else()
+ message(FATAL_ERROR "Unknown language:\n ${_lang}\nSupported languages: C, CXX.\n")
+ endif()
+endmacro ()
diff --git a/Modules/CheckSymbolExists.cmake b/Modules/CheckSymbolExists.cmake
new file mode 100644
index 0000000..f8ca584
--- /dev/null
+++ b/Modules/CheckSymbolExists.cmake
@@ -0,0 +1,168 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckSymbolExists
+-----------------
+
+Provides a macro to check if a symbol exists as a function, variable,
+or macro in ``C``.
+
+.. command:: check_symbol_exists
+
+ .. code-block:: cmake
+
+ check_symbol_exists(<symbol> <files> <variable>)
+
+ Check that the ``<symbol>`` is available after including given header
+ ``<files>`` and store the result in a ``<variable>``. Specify the list
+ of files in one argument as a semicolon-separated list.
+ ``<variable>`` will be created as an internal cache variable.
+
+If the header files define the symbol as a macro it is considered
+available and assumed to work. If the header files declare the symbol
+as a function or variable then the symbol must also be available for
+linking (so intrinsics may not be detected).
+If the symbol is a type, enum value, or intrinsic it will not be recognized
+(consider using :module:`CheckTypeSize` or :module:`CheckCSourceCompiles`).
+If the check needs to be done in C++, consider using
+:module:`CheckCXXSymbolExists` instead.
+
+The following variables may be set before calling this macro to modify
+the way the check is run:
+
+``CMAKE_REQUIRED_FLAGS``
+ string of compile command line flags.
+``CMAKE_REQUIRED_DEFINITIONS``
+ a :ref:`;-list <CMake Language Lists>` of macros to define (-DFOO=bar).
+``CMAKE_REQUIRED_INCLUDES``
+ a :ref:`;-list <CMake Language Lists>` of header search paths to pass to
+ the compiler.
+``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+ a :ref:`;-list <CMake Language Lists>` of options to add to the link command.
+``CMAKE_REQUIRED_LIBRARIES``
+ a :ref:`;-list <CMake Language Lists>` of libraries to add to the link
+ command. See policy :policy:`CMP0075`.
+``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+ execute quietly without messages.
+
+For example:
+
+.. code-block:: cmake
+
+ include(CheckSymbolExists)
+
+ # Check for macro SEEK_SET
+ check_symbol_exists(SEEK_SET "stdio.h" HAVE_SEEK_SET)
+ # Check for function fopen
+ check_symbol_exists(fopen "stdio.h" HAVE_FOPEN)
+#]=======================================================================]
+
+include_guard(GLOBAL)
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
+
+macro(CHECK_SYMBOL_EXISTS SYMBOL FILES VARIABLE)
+ if(CMAKE_C_COMPILER_LOADED)
+ __CHECK_SYMBOL_EXISTS_IMPL("${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c" "${SYMBOL}" "${FILES}" "${VARIABLE}" )
+ elseif(CMAKE_CXX_COMPILER_LOADED)
+ __CHECK_SYMBOL_EXISTS_IMPL("${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.cxx" "${SYMBOL}" "${FILES}" "${VARIABLE}" )
+ else()
+ message(FATAL_ERROR "CHECK_SYMBOL_EXISTS needs either C or CXX language enabled")
+ endif()
+endmacro()
+
+macro(__CHECK_SYMBOL_EXISTS_IMPL SOURCEFILE SYMBOL FILES VARIABLE)
+ if(NOT DEFINED "${VARIABLE}" OR "x${${VARIABLE}}" STREQUAL "x${VARIABLE}")
+ set(CMAKE_CONFIGURABLE_FILE_CONTENT "/* */\n")
+ set(MACRO_CHECK_SYMBOL_EXISTS_FLAGS ${CMAKE_REQUIRED_FLAGS})
+ if(CMAKE_REQUIRED_LINK_OPTIONS)
+ set(CHECK_SYMBOL_EXISTS_LINK_OPTIONS
+ LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
+ else()
+ set(CHECK_SYMBOL_EXISTS_LINK_OPTIONS)
+ endif()
+ if(CMAKE_REQUIRED_LIBRARIES)
+ set(CHECK_SYMBOL_EXISTS_LIBS
+ LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
+ else()
+ set(CHECK_SYMBOL_EXISTS_LIBS)
+ endif()
+ if(CMAKE_REQUIRED_INCLUDES)
+ set(CMAKE_SYMBOL_EXISTS_INCLUDES
+ "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+ else()
+ set(CMAKE_SYMBOL_EXISTS_INCLUDES)
+ endif()
+ foreach(FILE ${FILES})
+ string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT
+ "#include <${FILE}>\n")
+ endforeach()
+ string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT "
+int main(int argc, char** argv)
+{
+ (void)argv;")
+ set(_CSE_CHECK_NON_MACRO "return ((int*)(&${SYMBOL}))[argc];")
+ if("${SYMBOL}" MATCHES "^[a-zA-Z_][a-zA-Z0-9_]*$")
+ # The SYMBOL has a legal macro name. Test whether it exists as a macro.
+ string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT "
+#ifndef ${SYMBOL}
+ ${_CSE_CHECK_NON_MACRO}
+#else
+ (void)argc;
+ return 0;
+#endif")
+ else()
+ # The SYMBOL cannot be a macro (e.g., a template function).
+ string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT "
+ ${_CSE_CHECK_NON_MACRO}")
+ endif()
+ string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT "
+}")
+ unset(_CSE_CHECK_NON_MACRO)
+
+ configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
+ "${SOURCEFILE}" @ONLY)
+
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_START "Looking for ${SYMBOL}")
+ endif()
+ try_compile(${VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ "${SOURCEFILE}"
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ ${CHECK_SYMBOL_EXISTS_LINK_OPTIONS}
+ ${CHECK_SYMBOL_EXISTS_LIBS}
+ CMAKE_FLAGS
+ -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_SYMBOL_EXISTS_FLAGS}
+ "${CMAKE_SYMBOL_EXISTS_INCLUDES}"
+ OUTPUT_VARIABLE OUTPUT)
+ if(${VARIABLE})
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_PASS "found")
+ endif()
+ set(${VARIABLE} 1 CACHE INTERNAL "Have symbol ${SYMBOL}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the ${SYMBOL} "
+ "exist passed with the following output:\n"
+ "${OUTPUT}\nFile ${SOURCEFILE}:\n"
+ "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
+ else()
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_FAIL "not found")
+ endif()
+ set(${VARIABLE} "" CACHE INTERNAL "Have symbol ${SYMBOL}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the ${SYMBOL} "
+ "exist failed with the following output:\n"
+ "${OUTPUT}\nFile ${SOURCEFILE}:\n"
+ "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
+ endif()
+ unset(CMAKE_CONFIGURABLE_FILE_CONTENT)
+ endif()
+endmacro()
+
+cmake_policy(POP)
diff --git a/Modules/CheckTypeSize.c.in b/Modules/CheckTypeSize.c.in
new file mode 100644
index 0000000..fb93073
--- /dev/null
+++ b/Modules/CheckTypeSize.c.in
@@ -0,0 +1,47 @@
+@headers@
+
+#undef KEY
+#if defined(__i386)
+# define KEY '_','_','i','3','8','6'
+#elif defined(__x86_64)
+# define KEY '_','_','x','8','6','_','6','4'
+#elif defined(__PPC64__)
+# define KEY '_','_','P','P','C','6','4','_','_'
+#elif defined(__ppc64__)
+# define KEY '_','_','p','p','c','6','4','_','_'
+#elif defined(__PPC__)
+# define KEY '_','_','P','P','C','_','_'
+#elif defined(__ppc__)
+# define KEY '_','_','p','p','c','_','_'
+#elif defined(__aarch64__)
+# define KEY '_','_','a','a','r','c','h','6','4','_','_'
+#elif defined(__ARM_ARCH_7A__)
+# define KEY '_','_','A','R','M','_','A','R','C','H','_','7','A','_','_'
+#elif defined(__ARM_ARCH_7S__)
+# define KEY '_','_','A','R','M','_','A','R','C','H','_','7','S','_','_'
+#endif
+
+#define SIZE (sizeof(@type@))
+static char info_size[] = {'I', 'N', 'F', 'O', ':', 's','i','z','e','[',
+ ('0' + ((SIZE / 10000)%10)),
+ ('0' + ((SIZE / 1000)%10)),
+ ('0' + ((SIZE / 100)%10)),
+ ('0' + ((SIZE / 10)%10)),
+ ('0' + (SIZE % 10)),
+ ']',
+#ifdef KEY
+ ' ','k','e','y','[', KEY, ']',
+#endif
+ '\0'};
+
+#ifdef __CLASSIC_C__
+int main(argc, argv) int argc; char *argv[];
+#else
+int main(int argc, char *argv[])
+#endif
+{
+ int require = 0;
+ require += info_size[argc];
+ (void)argv;
+ return require;
+}
diff --git a/Modules/CheckTypeSize.cmake b/Modules/CheckTypeSize.cmake
new file mode 100644
index 0000000..69f68f9
--- /dev/null
+++ b/Modules/CheckTypeSize.cmake
@@ -0,0 +1,294 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckTypeSize
+-------------
+
+Check sizeof a type
+
+.. command:: CHECK_TYPE_SIZE
+
+ .. code-block:: cmake
+
+ CHECK_TYPE_SIZE(TYPE VARIABLE [BUILTIN_TYPES_ONLY]
+ [LANGUAGE <language>])
+
+ Check if the type exists and determine its size. On return,
+ ``HAVE_${VARIABLE}`` holds the existence of the type, and ``${VARIABLE}``
+ holds one of the following:
+
+ ::
+
+ <size> = type has non-zero size <size>
+ "0" = type has arch-dependent size (see below)
+ "" = type does not exist
+
+ Both ``HAVE_${VARIABLE}`` and ``${VARIABLE}`` will be created as internal
+ cache variables.
+
+ Furthermore, the variable ``${VARIABLE}_CODE`` holds C preprocessor code
+ to define the macro ``${VARIABLE}`` to the size of the type, or leave
+ the macro undefined if the type does not exist.
+
+ The variable ``${VARIABLE}`` may be ``0`` when
+ :variable:`CMAKE_OSX_ARCHITECTURES` has multiple architectures for building
+ OS X universal binaries. This indicates that the type size varies across
+ architectures. In this case ``${VARIABLE}_CODE`` contains C preprocessor
+ tests mapping from each architecture macro to the corresponding type size.
+ The list of architecture macros is stored in ``${VARIABLE}_KEYS``, and the
+ value for each key is stored in ``${VARIABLE}-${KEY}``.
+
+ If the ``BUILTIN_TYPES_ONLY`` option is not given, the macro checks for
+ headers ``<sys/types.h>``, ``<stdint.h>``, and ``<stddef.h>``, and saves
+ results in ``HAVE_SYS_TYPES_H``, ``HAVE_STDINT_H``, and ``HAVE_STDDEF_H``.
+ The type size check automatically includes the available headers, thus
+ supporting checks of types defined in the headers.
+
+ If ``LANGUAGE`` is set, the specified compiler will be used to perform the
+ check. Acceptable values are ``C`` and ``CXX``.
+
+Despite the name of the macro you may use it to check the size of more
+complex expressions, too. To check e.g. for the size of a struct
+member you can do something like this:
+
+.. code-block:: cmake
+
+ check_type_size("((struct something*)0)->member" SIZEOF_MEMBER)
+
+
+The following variables may be set before calling this macro to modify
+the way the check is run:
+
+``CMAKE_REQUIRED_FLAGS``
+ string of compile command line flags.
+``CMAKE_REQUIRED_DEFINITIONS``
+ list of macros to define (-DFOO=bar).
+``CMAKE_REQUIRED_INCLUDES``
+ list of include directories.
+``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+ list of options to pass to link command.
+``CMAKE_REQUIRED_LIBRARIES``
+ list of libraries to link.
+``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+ execute quietly without messages.
+``CMAKE_EXTRA_INCLUDE_FILES``
+ list of extra headers to include.
+#]=======================================================================]
+
+include(CheckIncludeFile)
+include(CheckIncludeFileCXX)
+
+get_filename_component(__check_type_size_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+include_guard(GLOBAL)
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0054 NEW)
+
+#-----------------------------------------------------------------------------
+# Helper function. DO NOT CALL DIRECTLY.
+function(__check_type_size_impl type var map builtin language)
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_START "Check size of ${type}")
+ endif()
+
+ # Perform language check
+ if(language STREQUAL "C")
+ set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${var}.c)
+ elseif(language STREQUAL "CXX")
+ set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${var}.cpp)
+ else()
+ message(FATAL_ERROR "Unknown language:\n ${language}\nSupported languages: C, CXX.\n")
+ endif()
+
+ # Include header files.
+ set(headers)
+ if(builtin)
+ if(language STREQUAL "CXX" AND type MATCHES "^std::")
+ if(HAVE_SYS_TYPES_H)
+ string(APPEND headers "#include <sys/types.h>\n")
+ endif()
+ if(HAVE_CSTDINT)
+ string(APPEND headers "#include <cstdint>\n")
+ endif()
+ if(HAVE_CSTDDEF)
+ string(APPEND headers "#include <cstddef>\n")
+ endif()
+ else()
+ if(HAVE_SYS_TYPES_H)
+ string(APPEND headers "#include <sys/types.h>\n")
+ endif()
+ if(HAVE_STDINT_H)
+ string(APPEND headers "#include <stdint.h>\n")
+ endif()
+ if(HAVE_STDDEF_H)
+ string(APPEND headers "#include <stddef.h>\n")
+ endif()
+ endif()
+ endif()
+ foreach(h ${CMAKE_EXTRA_INCLUDE_FILES})
+ string(APPEND headers "#include \"${h}\"\n")
+ endforeach()
+
+ # Perform the check.
+ set(bin ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${var}.bin)
+ configure_file(${__check_type_size_dir}/CheckTypeSize.c.in ${src} @ONLY)
+ try_compile(HAVE_${var} ${CMAKE_BINARY_DIR} ${src}
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}
+ LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}
+ CMAKE_FLAGS
+ "-DCOMPILE_DEFINITIONS:STRING=${CMAKE_REQUIRED_FLAGS}"
+ "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}"
+ OUTPUT_VARIABLE output
+ COPY_FILE ${bin}
+ )
+
+ if(HAVE_${var})
+ # The check compiled. Load information from the binary.
+ file(STRINGS ${bin} strings LIMIT_COUNT 10 REGEX "INFO:size")
+
+ # Parse the information strings.
+ set(regex_size ".*INFO:size\\[0*([^]]*)\\].*")
+ set(regex_key " key\\[([^]]*)\\]")
+ set(keys)
+ set(code)
+ set(mismatch)
+ set(first 1)
+ foreach(info ${strings})
+ if("${info}" MATCHES "${regex_size}")
+ # Get the type size.
+ set(size "${CMAKE_MATCH_1}")
+ if(first)
+ set(${var} ${size})
+ elseif(NOT "${size}" STREQUAL "${${var}}")
+ set(mismatch 1)
+ endif()
+ set(first 0)
+
+ # Get the architecture map key.
+ string(REGEX MATCH "${regex_key}" key "${info}")
+ string(REGEX REPLACE "${regex_key}" "\\1" key "${key}")
+ if(key)
+ string(APPEND code "\nset(${var}-${key} \"${size}\")")
+ list(APPEND keys ${key})
+ endif()
+ endif()
+ endforeach()
+
+ # Update the architecture-to-size map.
+ if(mismatch AND keys)
+ configure_file(${__check_type_size_dir}/CheckTypeSizeMap.cmake.in ${map} @ONLY)
+ set(${var} 0)
+ else()
+ file(REMOVE ${map})
+ endif()
+
+ if(mismatch AND NOT keys)
+ message(SEND_ERROR "CHECK_TYPE_SIZE found different results, consider setting CMAKE_OSX_ARCHITECTURES or CMAKE_TRY_COMPILE_OSX_ARCHITECTURES to one or no architecture !")
+ endif()
+
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_PASS "done")
+ endif()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining size of ${type} passed with the following output:\n${output}\n\n")
+ set(${var} "${${var}}" CACHE INTERNAL "CHECK_TYPE_SIZE: sizeof(${type})")
+ else()
+ # The check failed to compile.
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_FAIL "failed")
+ endif()
+ file(READ ${src} content)
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining size of ${type} failed with the following output:\n${output}\n${src}:\n${content}\n\n")
+ set(${var} "" CACHE INTERNAL "CHECK_TYPE_SIZE: ${type} unknown")
+ file(REMOVE ${map})
+ endif()
+endfunction()
+
+#-----------------------------------------------------------------------------
+macro(CHECK_TYPE_SIZE TYPE VARIABLE)
+ # parse arguments
+ unset(doing)
+ foreach(arg ${ARGN})
+ if("x${arg}" STREQUAL "xBUILTIN_TYPES_ONLY")
+ set(_CHECK_TYPE_SIZE_${arg} 1)
+ unset(doing)
+ elseif("x${arg}" STREQUAL "xLANGUAGE") # change to MATCHES for more keys
+ set(doing "${arg}")
+ set(_CHECK_TYPE_SIZE_${doing} "")
+ elseif("x${doing}" STREQUAL "xLANGUAGE")
+ set(_CHECK_TYPE_SIZE_${doing} "${arg}")
+ unset(doing)
+ else()
+ message(FATAL_ERROR "Unknown argument:\n ${arg}\n")
+ endif()
+ endforeach()
+ if("x${doing}" MATCHES "^x(LANGUAGE)$")
+ message(FATAL_ERROR "Missing argument:\n ${doing} arguments requires a value\n")
+ endif()
+ if(DEFINED _CHECK_TYPE_SIZE_LANGUAGE)
+ if(NOT "x${_CHECK_TYPE_SIZE_LANGUAGE}" MATCHES "^x(C|CXX)$")
+ message(FATAL_ERROR "Unknown language:\n ${_CHECK_TYPE_SIZE_LANGUAGE}.\nSupported languages: C, CXX.\n")
+ endif()
+ set(_language ${_CHECK_TYPE_SIZE_LANGUAGE})
+ else()
+ set(_language C)
+ endif()
+
+ # Optionally check for standard headers.
+ if(_CHECK_TYPE_SIZE_BUILTIN_TYPES_ONLY)
+ set(_builtin 0)
+ else()
+ set(_builtin 1)
+ if(_language STREQUAL "C")
+ check_include_file(sys/types.h HAVE_SYS_TYPES_H)
+ check_include_file(stdint.h HAVE_STDINT_H)
+ check_include_file(stddef.h HAVE_STDDEF_H)
+ elseif(_language STREQUAL "CXX")
+ check_include_file_cxx(sys/types.h HAVE_SYS_TYPES_H)
+ if("${TYPE}" MATCHES "^std::")
+ check_include_file_cxx(cstdint HAVE_CSTDINT)
+ check_include_file_cxx(cstddef HAVE_CSTDDEF)
+ else()
+ check_include_file_cxx(stdint.h HAVE_STDINT_H)
+ check_include_file_cxx(stddef.h HAVE_STDDEF_H)
+ endif()
+ endif()
+ endif()
+ unset(_CHECK_TYPE_SIZE_BUILTIN_TYPES_ONLY)
+ unset(_CHECK_TYPE_SIZE_LANGUAGE)
+
+ # Compute or load the size or size map.
+ set(${VARIABLE}_KEYS)
+ set(_map_file ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${VARIABLE}.cmake)
+ if(NOT DEFINED HAVE_${VARIABLE})
+ __check_type_size_impl(${TYPE} ${VARIABLE} ${_map_file} ${_builtin} ${_language})
+ endif()
+ include(${_map_file} OPTIONAL)
+ set(_map_file)
+ set(_builtin)
+
+ # Create preprocessor code.
+ if(${VARIABLE}_KEYS)
+ set(${VARIABLE}_CODE)
+ set(_if if)
+ foreach(key ${${VARIABLE}_KEYS})
+ string(APPEND ${VARIABLE}_CODE "#${_if} defined(${key})\n# define ${VARIABLE} ${${VARIABLE}-${key}}\n")
+ set(_if elif)
+ endforeach()
+ string(APPEND ${VARIABLE}_CODE "#else\n# error ${VARIABLE} unknown\n#endif")
+ set(_if)
+ elseif(${VARIABLE})
+ set(${VARIABLE}_CODE "#define ${VARIABLE} ${${VARIABLE}}")
+ else()
+ set(${VARIABLE}_CODE "/* #undef ${VARIABLE} */")
+ endif()
+endmacro()
+
+#-----------------------------------------------------------------------------
+cmake_policy(POP)
diff --git a/Modules/CheckTypeSizeMap.cmake.in b/Modules/CheckTypeSizeMap.cmake.in
new file mode 100644
index 0000000..1e73cff
--- /dev/null
+++ b/Modules/CheckTypeSizeMap.cmake.in
@@ -0,0 +1 @@
+set(@var@_KEYS "@keys@")@code@
diff --git a/Modules/CheckVariableExists.c b/Modules/CheckVariableExists.c
new file mode 100644
index 0000000..d68afb4
--- /dev/null
+++ b/Modules/CheckVariableExists.c
@@ -0,0 +1,24 @@
+#ifdef CHECK_VARIABLE_EXISTS
+
+extern int CHECK_VARIABLE_EXISTS;
+
+# ifdef __CLASSIC_C__
+int main()
+{
+ int ac;
+ char* av[];
+# else
+int main(int ac, char* av[])
+{
+# endif
+ if (ac > 1000) {
+ return *av[0];
+ }
+ return CHECK_VARIABLE_EXISTS;
+}
+
+#else /* CHECK_VARIABLE_EXISTS */
+
+# error "CHECK_VARIABLE_EXISTS has to specify the variable"
+
+#endif /* CHECK_VARIABLE_EXISTS */
diff --git a/Modules/CheckVariableExists.cmake b/Modules/CheckVariableExists.cmake
new file mode 100644
index 0000000..7420124
--- /dev/null
+++ b/Modules/CheckVariableExists.cmake
@@ -0,0 +1,90 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckVariableExists
+-------------------
+
+Check if the variable exists.
+
+.. command:: CHECK_VARIABLE_EXISTS
+
+ .. code-block:: cmake
+
+ CHECK_VARIABLE_EXISTS(VAR VARIABLE)
+
+
+ ::
+
+ VAR - the name of the variable
+ VARIABLE - variable to store the result
+ Will be created as an internal cache variable.
+
+
+ This macro is only for ``C`` variables.
+
+The following variables may be set before calling this macro to modify
+the way the check is run:
+
+``CMAKE_REQUIRED_FLAGS``
+ string of compile command line flags.
+``CMAKE_REQUIRED_DEFINITIONS``
+ list of macros to define (-DFOO=bar).
+``CMAKE_REQUIRED_LINK_OPTIONS``
+ .. versionadded:: 3.14
+ list of options to pass to link command.
+``CMAKE_REQUIRED_LIBRARIES``
+ list of libraries to link.
+``CMAKE_REQUIRED_QUIET``
+ .. versionadded:: 3.1
+ execute quietly without messages.
+#]=======================================================================]
+
+include_guard(GLOBAL)
+
+macro(CHECK_VARIABLE_EXISTS VAR VARIABLE)
+ if(NOT DEFINED "${VARIABLE}")
+ set(MACRO_CHECK_VARIABLE_DEFINITIONS
+ "-DCHECK_VARIABLE_EXISTS=${VAR} ${CMAKE_REQUIRED_FLAGS}")
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_START "Looking for ${VAR}")
+ endif()
+ if(CMAKE_REQUIRED_LINK_OPTIONS)
+ set(CHECK_VARIABLE_EXISTS_ADD_LINK_OPTIONS
+ LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
+ else()
+ set(CHECK_VARIABLE_EXISTS_ADD_LINK_OPTIONS)
+ endif()
+ if(CMAKE_REQUIRED_LIBRARIES)
+ set(CHECK_VARIABLE_EXISTS_ADD_LIBRARIES
+ LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
+ else()
+ set(CHECK_VARIABLE_EXISTS_ADD_LIBRARIES)
+ endif()
+ try_compile(${VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_ROOT}/Modules/CheckVariableExists.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ ${CHECK_VARIABLE_EXISTS_ADD_LINK_OPTIONS}
+ ${CHECK_VARIABLE_EXISTS_ADD_LIBRARIES}
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_VARIABLE_DEFINITIONS}
+ OUTPUT_VARIABLE OUTPUT)
+ if(${VARIABLE})
+ set(${VARIABLE} 1 CACHE INTERNAL "Have variable ${VAR}")
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_PASS "found")
+ endif()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the variable ${VAR} exists passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ else()
+ set(${VARIABLE} "" CACHE INTERNAL "Have variable ${VAR}")
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_FAIL "not found")
+ endif()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the variable ${VAR} exists failed with the following output:\n"
+ "${OUTPUT}\n\n")
+ endif()
+ endif()
+endmacro()
diff --git a/Modules/Compiler/ADSP-DetermineCompiler.cmake b/Modules/Compiler/ADSP-DetermineCompiler.cmake
new file mode 100644
index 0000000..0340f69
--- /dev/null
+++ b/Modules/Compiler/ADSP-DetermineCompiler.cmake
@@ -0,0 +1,10 @@
+
+set(_compiler_id_pp_test "defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__)")
+
+set(_compiler_id_version_compute "
+#if defined(__VISUALDSPVERSION__)
+ /* __VISUALDSPVERSION__ = 0xVVRRPP00 */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_HEX@(__VISUALDSPVERSION__>>24)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_HEX@(__VISUALDSPVERSION__>>16 & 0xFF)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_HEX@(__VISUALDSPVERSION__>>8 & 0xFF)
+#endif")
diff --git a/Modules/Compiler/ARMCC-ASM.cmake b/Modules/Compiler/ARMCC-ASM.cmake
new file mode 100644
index 0000000..5819fc7
--- /dev/null
+++ b/Modules/Compiler/ARMCC-ASM.cmake
@@ -0,0 +1,7 @@
+include(Compiler/ARMCC)
+
+set(CMAKE_ASM_OUTPUT_EXTENSION ".o")
+set(CMAKE_ASM_OUTPUT_EXTENSION_REPLACE 1)
+
+set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> <INCLUDES> <FLAGS> -o <OBJECT> <SOURCE>")
+set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS S;s;asm;msa)
diff --git a/Modules/Compiler/ARMCC-C.cmake b/Modules/Compiler/ARMCC-C.cmake
new file mode 100644
index 0000000..dcdcaab
--- /dev/null
+++ b/Modules/Compiler/ARMCC-C.cmake
@@ -0,0 +1,2 @@
+include(Compiler/ARMCC)
+__compiler_armcc(C)
diff --git a/Modules/Compiler/ARMCC-CXX.cmake b/Modules/Compiler/ARMCC-CXX.cmake
new file mode 100644
index 0000000..811fc93
--- /dev/null
+++ b/Modules/Compiler/ARMCC-CXX.cmake
@@ -0,0 +1,2 @@
+include(Compiler/ARMCC)
+__compiler_armcc(CXX)
diff --git a/Modules/Compiler/ARMCC-DetermineCompiler.cmake b/Modules/Compiler/ARMCC-DetermineCompiler.cmake
new file mode 100644
index 0000000..5f2d0f8
--- /dev/null
+++ b/Modules/Compiler/ARMCC-DetermineCompiler.cmake
@@ -0,0 +1,16 @@
+# ARMCC Toolchain
+set(_compiler_id_pp_test "defined(__ARMCC_VERSION) && !defined(__clang__)")
+
+set(_compiler_id_version_compute "
+#if __ARMCC_VERSION >= 1000000
+ /* __ARMCC_VERSION = VRRPPPP */
+ # define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__ARMCC_VERSION/1000000)
+ # define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__ARMCC_VERSION/10000 % 100)
+ # define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__ARMCC_VERSION % 10000)
+#else
+ /* __ARMCC_VERSION = VRPPPP */
+ # define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__ARMCC_VERSION/100000)
+ # define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__ARMCC_VERSION/10000 % 10)
+ # define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__ARMCC_VERSION % 10000)
+#endif
+")
diff --git a/Modules/Compiler/ARMCC.cmake b/Modules/Compiler/ARMCC.cmake
new file mode 100644
index 0000000..f4f1854
--- /dev/null
+++ b/Modules/Compiler/ARMCC.cmake
@@ -0,0 +1,39 @@
+if(_ARMCC_CMAKE_LOADED)
+ return()
+endif()
+set(_ARMCC_CMAKE_LOADED TRUE)
+
+# See ARM Compiler documentation at:
+# http://infocenter.arm.com/help/topic/com.arm.doc.set.swdev/index.html
+
+get_filename_component(_CMAKE_C_TOOLCHAIN_LOCATION "${CMAKE_C_COMPILER}" PATH)
+get_filename_component(_CMAKE_CXX_TOOLCHAIN_LOCATION "${CMAKE_CXX_COMPILER}" PATH)
+
+set(CMAKE_EXECUTABLE_SUFFIX ".elf")
+
+find_program(CMAKE_ARMCC_LINKER armlink HINTS "${_CMAKE_C_TOOLCHAIN_LOCATION}" "${_CMAKE_CXX_TOOLCHAIN_LOCATION}" )
+find_program(CMAKE_ARMCC_AR armar HINTS "${_CMAKE_C_TOOLCHAIN_LOCATION}" "${_CMAKE_CXX_TOOLCHAIN_LOCATION}" )
+
+set(CMAKE_LINKER "${CMAKE_ARMCC_LINKER}" CACHE FILEPATH "The ARMCC linker" FORCE)
+mark_as_advanced(CMAKE_ARMCC_LINKER)
+set(CMAKE_AR "${CMAKE_ARMCC_AR}" CACHE FILEPATH "The ARMCC archiver" FORCE)
+mark_as_advanced(CMAKE_ARMCC_AR)
+
+macro(__compiler_armcc lang)
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Ospace -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -Otime -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
+
+ set(CMAKE_${lang}_OUTPUT_EXTENSION ".o")
+ set(CMAKE_${lang}_OUTPUT_EXTENSION_REPLACE 1)
+ set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "--via=")
+
+ set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> <OBJECTS> -o <TARGET> --list <TARGET_BASE>.map")
+ set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "<CMAKE_AR> --create -cr <TARGET> <LINK_FLAGS> <OBJECTS>")
+
+ set(CMAKE_DEPFILE_FLAGS_${lang} "--depend=<DEP_FILE> --depend_single_line --no_depend_system_headers")
+
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ")
+endmacro()
diff --git a/Modules/Compiler/ARMClang-ASM.cmake b/Modules/Compiler/ARMClang-ASM.cmake
new file mode 100644
index 0000000..6a299be
--- /dev/null
+++ b/Modules/Compiler/ARMClang-ASM.cmake
@@ -0,0 +1,9 @@
+include(Compiler/ARMClang)
+
+set(CMAKE_ASM_OUTPUT_EXTENSION ".o")
+set(CMAKE_ASM_OUTPUT_EXTENSION_REPLACE 1)
+
+set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -c -o <OBJECT> <SOURCE>")
+set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS S;s;asm;msa)
+
+__compiler_armclang(ASM)
diff --git a/Modules/Compiler/ARMClang-C-FeatureTests.cmake b/Modules/Compiler/ARMClang-C-FeatureTests.cmake
new file mode 100644
index 0000000..ef79229
--- /dev/null
+++ b/Modules/Compiler/ARMClang-C-FeatureTests.cmake
@@ -0,0 +1 @@
+include(Compiler/Clang-C-FeatureTests)
diff --git a/Modules/Compiler/ARMClang-C.cmake b/Modules/Compiler/ARMClang-C.cmake
new file mode 100644
index 0000000..0a64a8a
--- /dev/null
+++ b/Modules/Compiler/ARMClang-C.cmake
@@ -0,0 +1,15 @@
+include(Compiler/Clang-C)
+include(Compiler/ARMClang)
+__compiler_armclang(C)
+
+set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
+set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
+set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+
+set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
+set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+
+set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
+set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
diff --git a/Modules/Compiler/ARMClang-CXX-FeatureTests.cmake b/Modules/Compiler/ARMClang-CXX-FeatureTests.cmake
new file mode 100644
index 0000000..e038e80
--- /dev/null
+++ b/Modules/Compiler/ARMClang-CXX-FeatureTests.cmake
@@ -0,0 +1 @@
+include(Compiler/Clang-CXX-FeatureTests)
diff --git a/Modules/Compiler/ARMClang-CXX.cmake b/Modules/Compiler/ARMClang-CXX.cmake
new file mode 100644
index 0000000..5dfb401
--- /dev/null
+++ b/Modules/Compiler/ARMClang-CXX.cmake
@@ -0,0 +1,3 @@
+include(Compiler/Clang-CXX)
+include(Compiler/ARMClang)
+__compiler_armclang(CXX)
diff --git a/Modules/Compiler/ARMClang-DetermineCompiler.cmake b/Modules/Compiler/ARMClang-DetermineCompiler.cmake
new file mode 100644
index 0000000..eb0de53
--- /dev/null
+++ b/Modules/Compiler/ARMClang-DetermineCompiler.cmake
@@ -0,0 +1,10 @@
+# ARMClang Toolchain
+set(_compiler_id_pp_test "defined(__clang__) && defined(__ARMCOMPILER_VERSION)")
+
+set(_compiler_id_version_compute "
+ # define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__ARMCOMPILER_VERSION/1000000)
+ # define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__ARMCOMPILER_VERSION/10000 % 100)
+ # define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__ARMCOMPILER_VERSION % 10000)")
+
+string(APPEND _compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_INTERNAL @MACRO_DEC@(__ARMCOMPILER_VERSION)")
diff --git a/Modules/Compiler/ARMClang.cmake b/Modules/Compiler/ARMClang.cmake
new file mode 100644
index 0000000..da7a43c
--- /dev/null
+++ b/Modules/Compiler/ARMClang.cmake
@@ -0,0 +1,131 @@
+if(_ARMClang_CMAKE_LOADED)
+ return()
+endif()
+set(_ARMClang_CMAKE_LOADED TRUE)
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+get_filename_component(_CMAKE_C_TOOLCHAIN_LOCATION "${CMAKE_C_COMPILER}" PATH)
+get_filename_component(_CMAKE_CXX_TOOLCHAIN_LOCATION "${CMAKE_CXX_COMPILER}" PATH)
+
+set(CMAKE_EXECUTABLE_SUFFIX ".elf")
+
+find_program(CMAKE_ARMClang_LINKER armlink HINTS "${_CMAKE_C_TOOLCHAIN_LOCATION}" "${_CMAKE_CXX_TOOLCHAIN_LOCATION}" )
+find_program(CMAKE_ARMClang_AR armar HINTS "${_CMAKE_C_TOOLCHAIN_LOCATION}" "${_CMAKE_CXX_TOOLCHAIN_LOCATION}" )
+
+set(CMAKE_LINKER "${CMAKE_ARMClang_LINKER}" CACHE FILEPATH "The ARMClang linker" FORCE)
+mark_as_advanced(CMAKE_ARMClang_LINKER)
+set(CMAKE_AR "${CMAKE_ARMClang_AR}" CACHE FILEPATH "The ARMClang archiver" FORCE)
+mark_as_advanced(CMAKE_ARMClang_AR)
+
+if (CMAKE_LINKER MATCHES "armlink")
+ set(__CMAKE_ARMClang_USING_armlink TRUE)
+ set(CMAKE_LIBRARY_PATH_FLAG "--userlibpath=")
+else()
+ set(__CMAKE_ARMClang_USING_armlink FALSE)
+endif()
+
+# get compiler supported cpu list
+function(__armclang_set_processor_list lang out_var)
+ execute_process(COMMAND "${CMAKE_${lang}_COMPILER}" --target=${CMAKE_${lang}_COMPILER_TARGET} -mcpu=list
+ OUTPUT_VARIABLE processor_list
+ ERROR_VARIABLE processor_list)
+ string(REGEX MATCHALL "-mcpu=([^ \n]*)" processor_list "${processor_list}")
+ string(REGEX REPLACE "-mcpu=" "" processor_list "${processor_list}")
+ set(${out_var} "${processor_list}" PARENT_SCOPE)
+endfunction()
+
+# check processor is in list
+function(__armclang_check_processor processor list out_var)
+ string(TOLOWER "${processor}" processor)
+ if(processor IN_LIST list)
+ set(${out_var} TRUE PARENT_SCOPE)
+ else()
+ set(${out_var} FALSE PARENT_SCOPE)
+ endif()
+endfunction()
+
+# get compiler supported arch list
+function(__armclang_set_arch_list lang out_var)
+ execute_process(COMMAND "${CMAKE_${lang}_COMPILER}" --target=${CMAKE_${lang}_COMPILER_TARGET} -march=list
+ OUTPUT_VARIABLE arch_list
+ ERROR_VARIABLE arch_list)
+ string(REGEX MATCHALL "-march=([^ \n]*)" arch_list "${arch_list}")
+ string(REGEX REPLACE "-march=" "" arch_list "${arch_list}")
+ set(${out_var} "${arch_list}" PARENT_SCOPE)
+endfunction()
+
+# get linker supported cpu list
+function(__armlink_set_cpu_list lang out_var)
+ if(__CMAKE_ARMClang_USING_armlink)
+ set(__linker_wrapper_flags "")
+ else()
+ set(__linker_wrapper_flags --target=${CMAKE_${lang}_COMPILER_TARGET} -Xlinker)
+ endif()
+
+ execute_process(COMMAND "${CMAKE_LINKER}" ${__linker_wrapper_flags} --cpu=list
+ OUTPUT_VARIABLE cpu_list
+ ERROR_VARIABLE cpu_list)
+ string(REGEX MATCHALL "--cpu=([^ \n]*)" cpu_list "${cpu_list}")
+ string(REGEX REPLACE "--cpu=" "" cpu_list "${cpu_list}")
+ set(${out_var} "${cpu_list}" PARENT_SCOPE)
+endfunction()
+
+macro(__compiler_armclang lang)
+ if(NOT CMAKE_${lang}_COMPILER_TARGET)
+ set(CMAKE_${lang}_COMPILER_TARGET arm-arm-none-eabi)
+ endif()
+ if(NOT CMAKE_${lang}_COMPILER_PROCESSOR_LIST)
+ __armclang_set_processor_list(${lang} CMAKE_${lang}_COMPILER_PROCESSOR_LIST)
+ endif()
+ if(NOT CMAKE_${lang}_COMPILER_ARCH_LIST)
+ __armclang_set_arch_list(${lang} CMAKE_${lang}_COMPILER_ARCH_LIST)
+ endif()
+ if(NOT CMAKE_SYSTEM_PROCESSOR AND NOT CMAKE_SYSTEM_ARCH)
+ message(FATAL_ERROR " CMAKE_SYSTEM_PROCESSOR or CMAKE_SYSTEM_ARCH must be set for ARMClang\n"
+ " Supported processor: ${CMAKE_${lang}_COMPILER_PROCESSOR_LIST}\n"
+ " Supported Architecture: ${CMAKE_${lang}_COMPILER_ARCH_LIST}")
+ else()
+ __armclang_check_processor("${CMAKE_SYSTEM_ARCH}" "${CMAKE_${lang}_COMPILER_ARCH_LIST}" _CMAKE_${lang}_CHECK_ARCH_RESULT)
+ if( _CMAKE_${lang}_CHECK_ARCH_RESULT)
+ string(APPEND CMAKE_${lang}_FLAGS_INIT "-march=${CMAKE_SYSTEM_ARCH}")
+ set(__march_flag_set TRUE)
+ endif()
+ __armclang_check_processor("${CMAKE_SYSTEM_PROCESSOR}" "${CMAKE_${lang}_COMPILER_PROCESSOR_LIST}" _CMAKE_${lang}_CHECK_PROCESSOR_RESULT)
+ if(_CMAKE_${lang}_CHECK_PROCESSOR_RESULT)
+ string(APPEND CMAKE_${lang}_FLAGS_INIT "-mcpu=${CMAKE_SYSTEM_PROCESSOR}")
+ set(__mcpu_flag_set TRUE)
+ endif()
+ if(NOT __march_flag_set AND NOT __mcpu_flag_set)
+ message(FATAL_ERROR "At least one of the variables CMAKE_SYSTEM_PROCESSOR or CMAKE_SYSTEM_ARCH must be set for ARMClang\n"
+ "Supported processor: ${CMAKE_${lang}_COMPILER_PROCESSOR_LIST}\n"
+ " Supported Architecture: ${CMAKE_${lang}_COMPILER_ARCH_LIST}")
+ endif()
+ unset(_CMAKE_${lang}_CHECK_PROCESSOR_RESULT)
+ unset(_CMAKE_${lang}_CHECK_ARCH_RESULT)
+ endif()
+
+ #check if CMAKE_SYSTEM_PROCESSOR belongs to supported cpu list for armlink
+ __armlink_set_cpu_list( ${lang} CMAKE_LINKER_CPU_LIST)
+ list(TRANSFORM CMAKE_LINKER_CPU_LIST TOLOWER)
+ __armclang_check_processor("${CMAKE_SYSTEM_PROCESSOR}" "${CMAKE_LINKER_CPU_LIST}" _CMAKE_CHECK_LINK_CPU_RESULT)
+ if(_CMAKE_CHECK_LINK_CPU_RESULT)
+ string(APPEND CMAKE_${lang}_LINK_FLAGS "--cpu=${CMAKE_SYSTEM_PROCESSOR}")
+ endif()
+
+ if(__CMAKE_ARMClang_USING_armlink)
+ unset(CMAKE_${lang}_LINKER_WRAPPER_FLAG)
+ set(__CMAKE_ARMClang_USING_armlink_WRAPPER "")
+ else()
+ set(__CMAKE_ARMClang_USING_armlink_WRAPPER "-Xlinker")
+ endif()
+ set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> <OBJECTS> -o <TARGET> ${__CMAKE_ARMClang_USING_armlink_WRAPPER} --list=<TARGET_BASE>.map")
+ set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "<CMAKE_AR> --create -cr <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> --create -cr <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "${__CMAKE_ARMClang_USING_armlink_WRAPPER} --via=")
+ set(CMAKE_${lang}_OUTPUT_EXTENSION ".o")
+ set(CMAKE_${lang}_OUTPUT_EXTENSION_REPLACE 1)
+endmacro()
+
+cmake_policy(POP)
diff --git a/Modules/Compiler/Absoft-Fortran.cmake b/Modules/Compiler/Absoft-Fortran.cmake
new file mode 100644
index 0000000..8724f85
--- /dev/null
+++ b/Modules/Compiler/Absoft-Fortran.cmake
@@ -0,0 +1,13 @@
+string(APPEND CMAKE_Fortran_FLAGS_INIT " ")
+string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -g")
+string(APPEND CMAKE_Fortran_FLAGS_MINSIZEREL_INIT " ")
+string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -O3")
+string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
+set(CMAKE_Fortran_MODDIR_FLAG "-YMOD_OUT_DIR=")
+set(CMAKE_Fortran_MODPATH_FLAG "-p")
+set(CMAKE_Fortran_VERBOSE_FLAG "-v")
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree")
+set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-X")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-no-cpp")
diff --git a/Modules/Compiler/AppleClang-ASM.cmake b/Modules/Compiler/AppleClang-ASM.cmake
new file mode 100644
index 0000000..f52bde0
--- /dev/null
+++ b/Modules/Compiler/AppleClang-ASM.cmake
@@ -0,0 +1 @@
+include(Compiler/Clang-ASM)
diff --git a/Modules/Compiler/AppleClang-C-FeatureTests.cmake b/Modules/Compiler/AppleClang-C-FeatureTests.cmake
new file mode 100644
index 0000000..e80b526
--- /dev/null
+++ b/Modules/Compiler/AppleClang-C-FeatureTests.cmake
@@ -0,0 +1,11 @@
+
+set(_cmake_oldestSupported "((__clang_major__ * 100) + __clang_minor__) >= 400")
+
+set(AppleClang_C11 "${_cmake_oldestSupported} && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L")
+set(_cmake_feature_test_c_static_assert "${AppleClang_C11}")
+set(AppleClang_C99 "${_cmake_oldestSupported} && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L")
+set(_cmake_feature_test_c_restrict "${AppleClang_C99}")
+set(_cmake_feature_test_c_variadic_macros "${AppleClang_C99}")
+
+set(AppleClang_C90 "${_cmake_oldestSupported}")
+set(_cmake_feature_test_c_function_prototypes "${AppleClang_C90}")
diff --git a/Modules/Compiler/AppleClang-C.cmake b/Modules/Compiler/AppleClang-C.cmake
new file mode 100644
index 0000000..bd98193
--- /dev/null
+++ b/Modules/Compiler/AppleClang-C.cmake
@@ -0,0 +1,31 @@
+include(Compiler/Clang)
+__compiler_clang(C)
+
+
+if(NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPFILE_FORMAT gcc)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+ endif()
+endif()
+
+set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
+
+if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.0)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+__compiler_check_default_language_standard(C 4.0 99)
diff --git a/Modules/Compiler/AppleClang-CXX-FeatureTests.cmake b/Modules/Compiler/AppleClang-CXX-FeatureTests.cmake
new file mode 100644
index 0000000..f67082c
--- /dev/null
+++ b/Modules/Compiler/AppleClang-CXX-FeatureTests.cmake
@@ -0,0 +1,52 @@
+
+# No known reference for AppleClang versions.
+# Generic reference: http://clang.llvm.org/cxx_status.html
+# http://clang.llvm.org/docs/LanguageExtensions.html
+
+# Note: CXX compiler in Xcode 4.3 does not set __apple_build_version__ and so is
+# not recognized as AppleClang.
+# Xcode_43 - Apple clang version 3.1 (tags/Apple/clang-318.0.61) (based on LLVM 3.1svn)
+# Xcode_44 - Apple clang version 4.0 (tags/Apple/clang-421.0.60) (based on LLVM 3.1svn)
+# Xcode_45 - Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
+# Xcode_46 - Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)
+# Xcode_50 - Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
+# Xcode_51 - Apple LLVM version 5.1 (clang-503.0.38) (based on LLVM 3.4svn)
+# Xcode_60 - Apple LLVM version 6.0 (clang-600.0.51) (based on LLVM 3.5svn)
+# Xcode_61 - Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
+
+# There is some non-correspondance. __has_feature(cxx_user_literals) is
+# false for AppleClang 4.0 and 4.1, although it is reported as
+# supported in the reference link for Clang 3.1. The compiler does not pass
+# the CompileFeatures/cxx_user_literals.cpp test.
+# cxx_attributes is listed as not supported until Clang 3.3. It works without
+# warning with AppleClang 5.0, but issues a gcc-compat warning for
+# AppleClang 4.0-4.2.
+# cxx_alignof and cxx_alignas tests work for early AppleClang versions, though
+# they are listed as supported for Clang 3.3 and later.
+
+set(_cmake_oldestSupported "((__clang_major__ * 100) + __clang_minor__) >= 400")
+
+include("${CMAKE_CURRENT_LIST_DIR}/Clang-CXX-TestableFeatures.cmake")
+
+set(AppleClang51_CXX14 "((__clang_major__ * 100) + __clang_minor__) >= 501 && __cplusplus > 201103L")
+# http://llvm.org/bugs/show_bug.cgi?id=19242
+set(_cmake_feature_test_cxx_attribute_deprecated "${AppleClang51_CXX14}")
+# http://llvm.org/bugs/show_bug.cgi?id=19698
+set(_cmake_feature_test_cxx_decltype_auto "${AppleClang51_CXX14}")
+set(_cmake_feature_test_cxx_digit_separators "${AppleClang51_CXX14}")
+# http://llvm.org/bugs/show_bug.cgi?id=19674
+set(_cmake_feature_test_cxx_generic_lambdas "${AppleClang51_CXX14}")
+
+set(AppleClang40_CXX11 "${_cmake_oldestSupported} && __cplusplus >= 201103L")
+set(_cmake_feature_test_cxx_enum_forward_declarations "${AppleClang40_CXX11}")
+set(_cmake_feature_test_cxx_sizeof_member "${AppleClang40_CXX11}")
+set(_cmake_feature_test_cxx_extended_friend_declarations "${AppleClang40_CXX11}")
+set(_cmake_feature_test_cxx_extern_templates "${AppleClang40_CXX11}")
+set(_cmake_feature_test_cxx_func_identifier "${AppleClang40_CXX11}")
+set(_cmake_feature_test_cxx_inline_namespaces "${AppleClang40_CXX11}")
+set(_cmake_feature_test_cxx_long_long_type "${AppleClang40_CXX11}")
+set(_cmake_feature_test_cxx_right_angle_brackets "${AppleClang40_CXX11}")
+set(_cmake_feature_test_cxx_variadic_macros "${AppleClang40_CXX11}")
+
+set(AppleClang_CXX98 "${_cmake_oldestSupported} && __cplusplus >= 199711L")
+set(_cmake_feature_test_cxx_template_template_parameters "${AppleClang_CXX98}")
diff --git a/Modules/Compiler/AppleClang-CXX.cmake b/Modules/Compiler/AppleClang-CXX.cmake
new file mode 100644
index 0000000..28be1df
--- /dev/null
+++ b/Modules/Compiler/AppleClang-CXX.cmake
@@ -0,0 +1,55 @@
+include(Compiler/Clang)
+__compiler_clang(CXX)
+
+set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
+
+if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+ endif()
+
+ set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
+endif()
+
+if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0)
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+endif()
+
+if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.1)
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14")
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
+ # AppleClang 5.0 knows this flag, but does not set a __cplusplus macro greater than 201103L
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++1y")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y")
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0)
+ set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++17")
+ set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17")
+elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.1)
+ set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++1z")
+ set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++1z")
+endif()
+
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0)
+ set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std=c++2a")
+ set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std=gnu++2a")
+endif()
+
+__compiler_check_default_language_standard(CXX 4.0 98)
diff --git a/Modules/Compiler/AppleClang-DetermineCompiler.cmake b/Modules/Compiler/AppleClang-DetermineCompiler.cmake
new file mode 100644
index 0000000..83817f7
--- /dev/null
+++ b/Modules/Compiler/AppleClang-DetermineCompiler.cmake
@@ -0,0 +1,7 @@
+
+set(_compiler_id_pp_test "defined(__clang__) && defined(__apple_build_version__)")
+
+include("${CMAKE_CURRENT_LIST_DIR}/Clang-DetermineCompilerInternal.cmake")
+
+string(APPEND _compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(__apple_build_version__)")
diff --git a/Modules/Compiler/AppleClang-OBJC.cmake b/Modules/Compiler/AppleClang-OBJC.cmake
new file mode 100644
index 0000000..d4eab4f
--- /dev/null
+++ b/Modules/Compiler/AppleClang-OBJC.cmake
@@ -0,0 +1,26 @@
+include(Compiler/Clang-OBJC)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles"
+ AND CMAKE_DEPFILE_FLAGS_OBJC)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_OBJC_DEPFILE_FORMAT gcc)
+ set(CMAKE_OBJC_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+
+if(NOT CMAKE_OBJC_COMPILER_VERSION VERSION_LESS 4.0)
+ set(CMAKE_OBJC90_STANDARD_COMPILE_OPTION "-std=c90")
+ set(CMAKE_OBJC90_EXTENSION_COMPILE_OPTION "-std=gnu90")
+ set(CMAKE_OBJC90_STANDARD__HAS_FULL_SUPPORT ON)
+
+ set(CMAKE_OBJC99_STANDARD_COMPILE_OPTION "-std=c99")
+ set(CMAKE_OBJC99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+ set(CMAKE_OBJC99_STANDARD__HAS_FULL_SUPPORT ON)
+
+ set(CMAKE_OBJC11_STANDARD_COMPILE_OPTION "-std=c11")
+ set(CMAKE_OBJC11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+ set(CMAKE_OBJC11_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+__compiler_check_default_language_standard(OBJC 4.0 99)
diff --git a/Modules/Compiler/AppleClang-OBJCXX.cmake b/Modules/Compiler/AppleClang-OBJCXX.cmake
new file mode 100644
index 0000000..172a343
--- /dev/null
+++ b/Modules/Compiler/AppleClang-OBJCXX.cmake
@@ -0,0 +1,52 @@
+include(Compiler/Clang-OBJCXX)
+
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles"
+ AND CMAKE_DEPFILE_FLAGS_OBJCXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_OBJCXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_OBJCXX_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+
+set(CMAKE_OBJCXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
+
+if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 4.0)
+ set(CMAKE_OBJCXX98_STANDARD_COMPILE_OPTION "-std=c++98")
+ set(CMAKE_OBJCXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+ set(CMAKE_OBJCXX98_STANDARD__HAS_FULL_SUPPORT ON)
+
+ set(CMAKE_OBJCXX11_STANDARD_COMPILE_OPTION "-std=c++11")
+ set(CMAKE_OBJCXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+endif()
+
+if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 6.1)
+ set(CMAKE_OBJCXX14_STANDARD_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_OBJCXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14")
+ set(CMAKE_OBJCXX14_STANDARD__HAS_FULL_SUPPORT ON)
+elseif(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 5.1)
+ # AppleClang 5.0 knows this flag, but does not set a __cplusplus macro greater than 201103L
+ set(CMAKE_OBJCXX14_STANDARD_COMPILE_OPTION "-std=c++1y")
+ set(CMAKE_OBJCXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y")
+ set(CMAKE_OBJCXX14_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+if (NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 10.0)
+ set(CMAKE_OBJCXX17_STANDARD_COMPILE_OPTION "-std=c++17")
+ set(CMAKE_OBJCXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17")
+elseif (NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 6.1)
+ set(CMAKE_OBJCXX17_STANDARD_COMPILE_OPTION "-std=c++1z")
+ set(CMAKE_OBJCXX17_EXTENSION_COMPILE_OPTION "-std=gnu++1z")
+endif()
+
+if (NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 8.0)
+ set(CMAKE_OBJCXX11_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+if (NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 10.0)
+ set(CMAKE_OBJCXX20_STANDARD_COMPILE_OPTION "-std=c++2a")
+ set(CMAKE_OBJCXX20_EXTENSION_COMPILE_OPTION "-std=gnu++2a")
+endif()
+
+__compiler_check_default_language_standard(OBJCXX 4.0 98)
diff --git a/Modules/Compiler/Borland-DetermineCompiler.cmake b/Modules/Compiler/Borland-DetermineCompiler.cmake
new file mode 100644
index 0000000..ef3083b
--- /dev/null
+++ b/Modules/Compiler/Borland-DetermineCompiler.cmake
@@ -0,0 +1,7 @@
+
+set(_compiler_id_pp_test "defined(__BORLANDC__)")
+
+set(_compiler_id_version_compute "
+ /* __BORLANDC__ = 0xVRR */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_HEX@(__BORLANDC__>>8)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_HEX@(__BORLANDC__ & 0xFF)")
diff --git a/Modules/Compiler/Bruce-C-DetermineCompiler.cmake b/Modules/Compiler/Bruce-C-DetermineCompiler.cmake
new file mode 100644
index 0000000..bb9f4b9
--- /dev/null
+++ b/Modules/Compiler/Bruce-C-DetermineCompiler.cmake
@@ -0,0 +1 @@
+set(_compiler_id_pp_test "defined(__BCC__)")
diff --git a/Modules/Compiler/Bruce-C.cmake b/Modules/Compiler/Bruce-C.cmake
new file mode 100644
index 0000000..6b64e58
--- /dev/null
+++ b/Modules/Compiler/Bruce-C.cmake
@@ -0,0 +1,9 @@
+# Bruce C Compiler ignores "-g" flag and optimization cannot be
+# enabled here (it is implemented only for 8086 target).
+string(APPEND CMAKE_C_FLAGS_INIT " -D__CLASSIC_C__")
+string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -g")
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
+string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -g -DNDEBUG")
+
+set(CMAKE_C_LINKER_WRAPPER_FLAG "-X")
diff --git a/Modules/Compiler/CCur-Fortran.cmake b/Modules/Compiler/CCur-Fortran.cmake
new file mode 100644
index 0000000..6ec06ae
--- /dev/null
+++ b/Modules/Compiler/CCur-Fortran.cmake
@@ -0,0 +1 @@
+include(Compiler/GNU-Fortran)
diff --git a/Modules/Compiler/CMakeCommonCompilerMacros.cmake b/Modules/Compiler/CMakeCommonCompilerMacros.cmake
new file mode 100644
index 0000000..29e6730
--- /dev/null
+++ b/Modules/Compiler/CMakeCommonCompilerMacros.cmake
@@ -0,0 +1,172 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This module is shared by multiple languages and compilers; use include guard
+if (__COMPILER_CMAKE_COMMON_COMPILER_MACROS)
+ return()
+endif ()
+set(__COMPILER_CMAKE_COMMON_COMPILER_MACROS 1)
+
+
+# Check that a compiler's language standard is properly detected
+# Parameters:
+# lang - Language to check
+# stdver1 - Minimum version to set a given default for
+# std1 - Default to use for compiler ver >= stdver1
+# stdverN - Minimum version to set a given default for
+# stdN - Default to use for compiler ver >= stdverN
+#
+# The order of stdverN stdN pairs passed as arguments is expected to be in
+# monotonically increasing version order.
+#
+# Note:
+# This macro can be called with multiple version / std pairs to convey that
+# newer compiler versions may use a newer standard default.
+#
+# Example:
+# To specify that compiler version 6.1 and newer defaults to C++11 while
+# 4.8 <= ver < 6.1 default to C++98, you would call:
+#
+# __compiler_check_default_language_standard(CXX 4.8 98 6.1 11)
+#
+macro(__compiler_check_default_language_standard lang stdver1 std1)
+ set(__std_ver_pairs "${stdver1};${std1};${ARGN}")
+ string(REGEX REPLACE " *; *" " " __std_ver_pairs "${__std_ver_pairs}")
+ string(REGEX MATCHALL "[^ ]+ [^ ]+" __std_ver_pairs "${__std_ver_pairs}")
+
+ # If the compiler version is below the threshold of even having CMake
+ # support for language standards, then don't bother.
+ if (CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL "${stdver1}")
+ if (NOT CMAKE_${lang}_COMPILER_FORCED)
+ if (NOT CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT)
+ message(FATAL_ERROR "CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT should be set for ${CMAKE_${lang}_COMPILER_ID} (${CMAKE_${lang}_COMPILER}) version ${CMAKE_${lang}_COMPILER_VERSION}")
+ endif ()
+ set(CMAKE_${lang}_STANDARD_DEFAULT ${CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT})
+ else ()
+ list(REVERSE __std_ver_pairs)
+ foreach (__std_ver_pair IN LISTS __std_ver_pairs)
+ string(REGEX MATCH "([^ ]+) (.+)" __std_ver_pair "${__std_ver_pair}")
+ set(__stdver ${CMAKE_MATCH_1})
+ set(__std ${CMAKE_MATCH_2})
+ if (CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL __stdver AND
+ NOT DEFINED CMAKE_${lang}_STANDARD_DEFAULT)
+ # Compiler id was forced so just guess the default standard level.
+ set(CMAKE_${lang}_STANDARD_DEFAULT ${__std})
+ endif ()
+ unset(__std)
+ unset(__stdver)
+ endforeach ()
+ endif ()
+ endif ()
+ unset(__std_ver_pairs)
+endmacro()
+
+# Define to allow compile features to be automatically determined
+macro(cmake_record_c_compile_features)
+ set(_result 0)
+ if(_result EQUAL 0 AND DEFINED CMAKE_C23_STANDARD_COMPILE_OPTION)
+ _has_compiler_features_c(23)
+ endif()
+ if(_result EQUAL 0 AND DEFINED CMAKE_C17_STANDARD_COMPILE_OPTION)
+ _has_compiler_features_c(17)
+ endif()
+ if(_result EQUAL 0 AND DEFINED CMAKE_C11_STANDARD_COMPILE_OPTION)
+ if(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_c(11)
+ else()
+ _record_compiler_features_c(11)
+ endif()
+ unset(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT)
+ endif()
+ if(_result EQUAL 0 AND DEFINED CMAKE_C99_STANDARD_COMPILE_OPTION)
+ if(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_c(99)
+ else()
+ _record_compiler_features_c(99)
+ endif()
+ unset(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT)
+ endif()
+ if(_result EQUAL 0 AND DEFINED CMAKE_C90_STANDARD_COMPILE_OPTION)
+ if(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_c(90)
+ else()
+ _record_compiler_features_c(90)
+ endif()
+ unset(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT)
+ endif()
+endmacro()
+
+# Define to allow compile features to be automatically determined
+macro(cmake_record_cxx_compile_features)
+ set(_result 0)
+ if(_result EQUAL 0 AND DEFINED CMAKE_CXX23_STANDARD_COMPILE_OPTION)
+ _has_compiler_features_cxx(23)
+ endif()
+ if(_result EQUAL 0 AND DEFINED CMAKE_CXX20_STANDARD_COMPILE_OPTION)
+ _has_compiler_features_cxx(20)
+ endif()
+ if(_result EQUAL 0 AND DEFINED CMAKE_CXX17_STANDARD_COMPILE_OPTION)
+ _has_compiler_features_cxx(17)
+ endif()
+ if(_result EQUAL 0 AND DEFINED CMAKE_CXX14_STANDARD_COMPILE_OPTION)
+ if(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_cxx(14)
+ else()
+ _record_compiler_features_cxx(14)
+ endif()
+ unset(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT)
+ endif()
+ if(_result EQUAL 0 AND DEFINED CMAKE_CXX11_STANDARD_COMPILE_OPTION)
+ if(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_cxx(11)
+ else()
+ _record_compiler_features_cxx(11)
+ endif()
+ unset(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT)
+ endif()
+ if(_result EQUAL 0 AND DEFINED CMAKE_CXX98_STANDARD_COMPILE_OPTION)
+ if(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_cxx(98)
+ else()
+ _record_compiler_features_cxx(98)
+ endif()
+ unset(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT)
+ endif()
+endmacro()
+
+macro(cmake_record_cuda_compile_features)
+ set(_result 0)
+ if(_result EQUAL 0 AND DEFINED CMAKE_CUDA23_STANDARD_COMPILE_OPTION)
+ _has_compiler_features_cuda(23)
+ endif()
+ if(_result EQUAL 0 AND DEFINED CMAKE_CUDA20_STANDARD_COMPILE_OPTION)
+ _has_compiler_features_cuda(20)
+ endif()
+ if(_result EQUAL 0 AND DEFINED CMAKE_CUDA17_STANDARD_COMPILE_OPTION)
+ _has_compiler_features_cuda(17)
+ endif()
+ if(_result EQUAL 0 AND DEFINED CMAKE_CUDA14_STANDARD_COMPILE_OPTION)
+ if(CMAKE_CUDA14_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_cuda(14)
+ else()
+ _record_compiler_features_cuda(14)
+ endif()
+ unset(CMAKE_CUDA14_STANDARD__HAS_FULL_SUPPORT)
+ endif()
+ if(_result EQUAL 0 AND DEFINED CMAKE_CUDA11_STANDARD_COMPILE_OPTION)
+ if(CMAKE_CUDA11_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_cuda(11)
+ else()
+ _record_compiler_features_cuda(11)
+ endif()
+ unset(CMAKE_CUDA11_STANDARD__HAS_FULL_SUPPORT)
+ endif()
+ if(_result EQUAL 0 AND DEFINED CMAKE_CUDA03_STANDARD_COMPILE_OPTION)
+ if(CMAKE_CUDA03_STANDARD__HAS_FULL_SUPPORT)
+ _has_compiler_features_cuda(03)
+ else()
+ _record_compiler_features_cuda(03)
+ endif()
+ unset(CMAKE_CUDA03_STANDARD__HAS_FULL_SUPPORT)
+ endif()
+endmacro()
diff --git a/Modules/Compiler/Clang-ASM.cmake b/Modules/Compiler/Clang-ASM.cmake
new file mode 100644
index 0000000..16c9c15
--- /dev/null
+++ b/Modules/Compiler/Clang-ASM.cmake
@@ -0,0 +1,5 @@
+include(Compiler/Clang)
+
+set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;S;asm)
+
+__compiler_clang(ASM)
diff --git a/Modules/Compiler/Clang-C-FeatureTests.cmake b/Modules/Compiler/Clang-C-FeatureTests.cmake
new file mode 100644
index 0000000..99c2252
--- /dev/null
+++ b/Modules/Compiler/Clang-C-FeatureTests.cmake
@@ -0,0 +1,11 @@
+
+set(_cmake_oldestSupported "((__clang_major__ * 100) + __clang_minor__) >= 304")
+
+set(Clang_C11 "${_cmake_oldestSupported} && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L")
+set(_cmake_feature_test_c_static_assert "${Clang_C11}")
+set(Clang_C99 "${_cmake_oldestSupported} && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L")
+set(_cmake_feature_test_c_restrict "${Clang_C99}")
+set(_cmake_feature_test_c_variadic_macros "${Clang_C99}")
+
+set(Clang_C90 "${_cmake_oldestSupported}")
+set(_cmake_feature_test_c_function_prototypes "${Clang_C90}")
diff --git a/Modules/Compiler/Clang-C.cmake b/Modules/Compiler/Clang-C.cmake
new file mode 100644
index 0000000..cf493d7
--- /dev/null
+++ b/Modules/Compiler/Clang-C.cmake
@@ -0,0 +1,84 @@
+include(Compiler/Clang)
+__compiler_clang(C)
+
+cmake_policy(GET CMP0025 appleClangPolicy)
+if(APPLE AND NOT appleClangPolicy STREQUAL NEW)
+ return()
+endif()
+
+if("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+ set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
+ set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+ endif()
+elseif("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPFILE_FORMAT gcc)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+ endif()
+endif()
+
+if("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 2.1)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
+
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+ endif()
+
+ if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.1)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+ elseif(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.0)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c1x")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu1x")
+ endif()
+
+ if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.0)
+ set(CMAKE_C17_STANDARD_COMPILE_OPTION "-std=c17")
+ set(CMAKE_C17_EXTENSION_COMPILE_OPTION "-std=gnu17")
+ endif()
+
+ if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 9.0)
+ set(CMAKE_C23_STANDARD_COMPILE_OPTION "-std=c2x")
+ set(CMAKE_C23_EXTENSION_COMPILE_OPTION "-std=gnu2x")
+ endif()
+else()
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "")
+
+ if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "/std:c11")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "/std:c11")
+
+ set(CMAKE_C17_STANDARD_COMPILE_OPTION "/std:c17")
+ set(CMAKE_C17_EXTENSION_COMPILE_OPTION "/std:c17")
+ else()
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "")
+
+ set(CMAKE_C17_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C17_EXTENSION_COMPILE_OPTION "")
+ endif()
+endif()
+
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 2.1)
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.0)
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+__compiler_check_default_language_standard(C 2.1 99 3.5.2 11 11.0 17)
diff --git a/Modules/Compiler/Clang-CUDA.cmake b/Modules/Compiler/Clang-CUDA.cmake
new file mode 100644
index 0000000..0223081
--- /dev/null
+++ b/Modules/Compiler/Clang-CUDA.cmake
@@ -0,0 +1,35 @@
+include(Compiler/Clang)
+__compiler_clang(CUDA)
+
+# Set explicitly, because __compiler_clang() doesn't set this if we're simulating MSVC.
+set(CMAKE_DEPFILE_FLAGS_CUDA "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CUDA_DEPFILE_FORMAT gcc)
+ set(CMAKE_CUDA_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+# C++03 isn't supported for CXX, but is for CUDA, so we need to set these manually.
+# Do this before __compiler_clang_cxx_standards() since that adds the feature.
+set(CMAKE_CUDA03_STANDARD_COMPILE_OPTION "-std=c++03")
+set(CMAKE_CUDA03_EXTENSION_COMPILE_OPTION "-std=gnu++03")
+__compiler_clang_cxx_standards(CUDA)
+
+set(CMAKE_CUDA_COMPILER_HAS_DEVICE_LINK_PHASE TRUE)
+set(_CMAKE_COMPILE_AS_CUDA_FLAG "-x cuda")
+set(_CMAKE_CUDA_PTX_FLAG "--cuda-device-only -S")
+set(_CMAKE_CUDA_DEVICE_CODE "-fgpu-rdc -c")
+
+# RulePlaceholderExpander expands crosscompile variables like sysroot and target only for CMAKE_<LANG>_COMPILER. Override the default.
+set(CMAKE_CUDA_LINK_EXECUTABLE "<CMAKE_CUDA_COMPILER> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
+set(CMAKE_CUDA_CREATE_SHARED_LIBRARY "<CMAKE_CUDA_COMPILER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
+
+set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "STATIC")
+set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC "cudadevrt;cudart_static")
+set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_SHARED "cudadevrt;cudart")
+set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_NONE "")
+
+if(UNIX)
+ list(APPEND CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC "rt" "pthread" "dl")
+endif()
diff --git a/Modules/Compiler/Clang-CXX-FeatureTests.cmake b/Modules/Compiler/Clang-CXX-FeatureTests.cmake
new file mode 100644
index 0000000..cd04190
--- /dev/null
+++ b/Modules/Compiler/Clang-CXX-FeatureTests.cmake
@@ -0,0 +1,33 @@
+
+# Reference: http://clang.llvm.org/cxx_status.html
+# http://clang.llvm.org/docs/LanguageExtensions.html
+
+set(_cmake_oldestSupported "((__clang_major__ * 100) + __clang_minor__) >= 301")
+
+include("${CMAKE_CURRENT_LIST_DIR}/Clang-CXX-TestableFeatures.cmake")
+
+set(Clang34_CXX14 "((__clang_major__ * 100) + __clang_minor__) >= 304 && __cplusplus > 201103L")
+# http://llvm.org/bugs/show_bug.cgi?id=19242
+set(_cmake_feature_test_cxx_attribute_deprecated "${Clang34_CXX14}")
+# http://llvm.org/bugs/show_bug.cgi?id=19698
+set(_cmake_feature_test_cxx_decltype_auto "${Clang34_CXX14}")
+set(_cmake_feature_test_cxx_digit_separators "${Clang34_CXX14}")
+# http://llvm.org/bugs/show_bug.cgi?id=19674
+set(_cmake_feature_test_cxx_generic_lambdas "${Clang34_CXX14}")
+
+set(Clang31_CXX11 "${_cmake_oldestSupported} && __cplusplus >= 201103L")
+set(_cmake_feature_test_cxx_enum_forward_declarations "${Clang31_CXX11}")
+set(_cmake_feature_test_cxx_sizeof_member "${Clang31_CXX11}")
+# TODO: Should be supported by Clang 2.9
+set(Clang29_CXX11 "${_cmake_oldestSupported} && __cplusplus >= 201103L")
+set(_cmake_feature_test_cxx_extended_friend_declarations "${Clang29_CXX11}")
+set(_cmake_feature_test_cxx_extern_templates "${Clang29_CXX11}")
+set(_cmake_feature_test_cxx_func_identifier "${Clang29_CXX11}")
+set(_cmake_feature_test_cxx_inline_namespaces "${Clang29_CXX11}")
+set(_cmake_feature_test_cxx_long_long_type "${Clang29_CXX11}")
+set(_cmake_feature_test_cxx_right_angle_brackets "${Clang29_CXX11}")
+set(_cmake_feature_test_cxx_variadic_macros "${Clang29_CXX11}")
+
+# TODO: Should be supported forever?
+set(Clang_CXX98 "${_cmake_oldestSupported} && __cplusplus >= 199711L")
+set(_cmake_feature_test_cxx_template_template_parameters "${Clang_CXX98}")
diff --git a/Modules/Compiler/Clang-CXX-TestableFeatures.cmake b/Modules/Compiler/Clang-CXX-TestableFeatures.cmake
new file mode 100644
index 0000000..69965a6
--- /dev/null
+++ b/Modules/Compiler/Clang-CXX-TestableFeatures.cmake
@@ -0,0 +1,56 @@
+
+set(testable_features
+ cxx_alias_templates
+ cxx_alignas
+ cxx_attributes
+ cxx_auto_type
+ cxx_binary_literals
+ cxx_constexpr
+ cxx_contextual_conversions
+ cxx_decltype
+ cxx_default_function_template_args
+ cxx_defaulted_functions
+ cxx_delegating_constructors
+ cxx_deleted_functions
+ cxx_explicit_conversions
+ cxx_generalized_initializers
+ cxx_inheriting_constructors
+ cxx_lambdas
+ cxx_local_type_template_args
+ cxx_noexcept
+ cxx_nonstatic_member_init
+ cxx_nullptr
+ cxx_range_for
+ cxx_raw_string_literals
+ cxx_reference_qualified_functions
+ cxx_relaxed_constexpr
+ cxx_return_type_deduction
+ cxx_rvalue_references
+ cxx_static_assert
+ cxx_strong_enums
+ cxx_thread_local
+ cxx_unicode_literals
+ cxx_unrestricted_unions
+ cxx_user_literals
+ cxx_variable_templates
+ cxx_variadic_templates
+)
+if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ list(APPEND testable_features cxx_decltype_incomplete_return_types)
+endif()
+
+foreach(feature ${testable_features})
+ set(_cmake_feature_test_${feature} "${_cmake_oldestSupported} && __has_feature(${feature})")
+endforeach()
+
+unset(testable_features)
+
+set(_cmake_feature_test_cxx_aggregate_default_initializers "${_cmake_oldestSupported} && __has_feature(cxx_aggregate_nsdmi)")
+
+set(_cmake_feature_test_cxx_trailing_return_types "${_cmake_oldestSupported} && __has_feature(cxx_trailing_return)")
+set(_cmake_feature_test_cxx_alignof "${_cmake_oldestSupported} && __has_feature(cxx_alignas)")
+set(_cmake_feature_test_cxx_final "${_cmake_oldestSupported} && __has_feature(cxx_override_control)")
+set(_cmake_feature_test_cxx_override "${_cmake_oldestSupported} && __has_feature(cxx_override_control)")
+set(_cmake_feature_test_cxx_uniform_initialization "${_cmake_oldestSupported} && __has_feature(cxx_generalized_initializers)")
+set(_cmake_feature_test_cxx_defaulted_move_initializers "${_cmake_oldestSupported} && __has_feature(cxx_defaulted_functions)")
+set(_cmake_feature_test_cxx_lambda_init_captures "${_cmake_oldestSupported} && __has_feature(cxx_init_captures)")
diff --git a/Modules/Compiler/Clang-CXX.cmake b/Modules/Compiler/Clang-CXX.cmake
new file mode 100644
index 0000000..98828e0
--- /dev/null
+++ b/Modules/Compiler/Clang-CXX.cmake
@@ -0,0 +1,30 @@
+include(Compiler/Clang)
+__compiler_clang(CXX)
+__compiler_clang_cxx_standards(CXX)
+
+if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+ endif()
+
+ set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
+ set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
+endif()
+
+cmake_policy(GET CMP0025 appleClangPolicy)
+if(APPLE AND NOT appleClangPolicy STREQUAL NEW)
+ return()
+endif()
+
+if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+ set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+ endif()
+endif()
diff --git a/Modules/Compiler/Clang-DetermineCompiler.cmake b/Modules/Compiler/Clang-DetermineCompiler.cmake
new file mode 100644
index 0000000..89df1b6
--- /dev/null
+++ b/Modules/Compiler/Clang-DetermineCompiler.cmake
@@ -0,0 +1,4 @@
+
+set(_compiler_id_pp_test "defined(__clang__)")
+
+include("${CMAKE_CURRENT_LIST_DIR}/Clang-DetermineCompilerInternal.cmake")
diff --git a/Modules/Compiler/Clang-DetermineCompilerInternal.cmake b/Modules/Compiler/Clang-DetermineCompilerInternal.cmake
new file mode 100644
index 0000000..08c1230
--- /dev/null
+++ b/Modules/Compiler/Clang-DetermineCompilerInternal.cmake
@@ -0,0 +1,15 @@
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__clang_major__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__clang_minor__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__clang_patchlevel__)
+# if defined(_MSC_VER)
+ /* _MSC_VER = VVRR */
+# define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(_MSC_VER / 100)
+# define @PREFIX@SIMULATE_VERSION_MINOR @MACRO_DEC@(_MSC_VER % 100)
+# endif")
+
+set(_compiler_id_simulate "
+# if defined(_MSC_VER)
+# define @PREFIX@SIMULATE_ID \"MSVC\"
+# endif")
diff --git a/Modules/Compiler/Clang-FindBinUtils.cmake b/Modules/Compiler/Clang-FindBinUtils.cmake
new file mode 100644
index 0000000..e6c469a
--- /dev/null
+++ b/Modules/Compiler/Clang-FindBinUtils.cmake
@@ -0,0 +1,43 @@
+if(NOT DEFINED _CMAKE_PROCESSING_LANGUAGE OR _CMAKE_PROCESSING_LANGUAGE STREQUAL "")
+ message(FATAL_ERROR "Internal error: _CMAKE_PROCESSING_LANGUAGE is not set")
+endif()
+
+# Ubuntu:
+# * /usr/bin/llvm-ar-9
+# * /usr/bin/llvm-ranlib-9
+string(REGEX MATCH "^([0-9]+)" __version_x
+ "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_VERSION}")
+
+# Debian:
+# * /usr/bin/llvm-ar-4.0
+# * /usr/bin/llvm-ranlib-4.0
+string(REGEX MATCH "^([0-9]+\\.[0-9]+)" __version_x_y
+ "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_VERSION}")
+
+# Try to find tools in the same directory as Clang itself
+get_filename_component(__clang_hint_1 "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER}" REALPATH)
+get_filename_component(__clang_hint_1 "${__clang_hint_1}" DIRECTORY)
+
+get_filename_component(__clang_hint_2 "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER}" DIRECTORY)
+
+set(__clang_hints ${__clang_hint_1} ${__clang_hint_2})
+
+# http://manpages.ubuntu.com/manpages/precise/en/man1/llvm-ar.1.html
+find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_AR NAMES
+ "${_CMAKE_TOOLCHAIN_PREFIX}llvm-ar-${__version_x_y}"
+ "${_CMAKE_TOOLCHAIN_PREFIX}llvm-ar-${__version_x}"
+ "${_CMAKE_TOOLCHAIN_PREFIX}llvm-ar"
+ HINTS ${__clang_hints}
+ DOC "LLVM archiver"
+)
+mark_as_advanced(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_AR)
+
+# http://manpages.ubuntu.com/manpages/precise/en/man1/llvm-ranlib.1.html
+find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_RANLIB NAMES
+ "${_CMAKE_TOOLCHAIN_PREFIX}llvm-ranlib-${__version_x_y}"
+ "${_CMAKE_TOOLCHAIN_PREFIX}llvm-ranlib-${__version_x}"
+ "${_CMAKE_TOOLCHAIN_PREFIX}llvm-ranlib"
+ HINTS ${__clang_hints}
+ DOC "Generate index for LLVM archive"
+)
+mark_as_advanced(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_RANLIB)
diff --git a/Modules/Compiler/Clang-OBJC.cmake b/Modules/Compiler/Clang-OBJC.cmake
new file mode 100644
index 0000000..19179e3
--- /dev/null
+++ b/Modules/Compiler/Clang-OBJC.cmake
@@ -0,0 +1,27 @@
+include(Compiler/Clang)
+__compiler_clang(OBJC)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_OBJC)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_OBJC_DEPFILE_FORMAT gcc)
+ set(CMAKE_OBJC_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+
+if(NOT CMAKE_OBJC_COMPILER_VERSION VERSION_LESS 3.4)
+ set(CMAKE_OBJC90_STANDARD_COMPILE_OPTION "-std=c90")
+ set(CMAKE_OBJC90_EXTENSION_COMPILE_OPTION "-std=gnu90")
+ set(CMAKE_OBJC90_STANDARD__HAS_FULL_SUPPORT ON)
+
+ set(CMAKE_OBJC99_STANDARD_COMPILE_OPTION "-std=c99")
+ set(CMAKE_OBJC99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+ set(CMAKE_OBJC99_STANDARD__HAS_FULL_SUPPORT ON)
+
+ set(CMAKE_OBJC11_STANDARD_COMPILE_OPTION "-std=c11")
+ set(CMAKE_OBJC11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+ set(CMAKE_OBJC11_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+__compiler_check_default_language_standard(OBJC 3.4 99 3.6 11)
diff --git a/Modules/Compiler/Clang-OBJCXX.cmake b/Modules/Compiler/Clang-OBJCXX.cmake
new file mode 100644
index 0000000..9bdff66
--- /dev/null
+++ b/Modules/Compiler/Clang-OBJCXX.cmake
@@ -0,0 +1,11 @@
+include(Compiler/Clang)
+__compiler_clang(OBJCXX)
+__compiler_clang_cxx_standards(OBJCXX)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_OBJCXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_OBJCXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_OBJCXX_DEPENDS_USE_COMPILER TRUE)
+endif()
diff --git a/Modules/Compiler/Clang.cmake b/Modules/Compiler/Clang.cmake
new file mode 100644
index 0000000..9f93d41
--- /dev/null
+++ b/Modules/Compiler/Clang.cmake
@@ -0,0 +1,244 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_CLANG)
+ return()
+endif()
+set(__COMPILER_CLANG 1)
+
+include(Compiler/CMakeCommonCompilerMacros)
+
+set(__pch_header_C "c-header")
+set(__pch_header_CXX "c++-header")
+set(__pch_header_OBJC "objective-c-header")
+set(__pch_header_OBJCXX "objective-c++-header")
+
+if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC"
+ OR "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC"
+ OR "x${CMAKE_Fortran_SIMULATE_ID}" STREQUAL "xMSVC")
+ macro(__compiler_clang lang)
+ endmacro()
+else()
+ include(Compiler/GNU)
+
+ macro(__compiler_clang lang)
+ __compiler_gnu(${lang})
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
+ # Link options for PIE are already set in 'Compiler/GNU.cmake'
+ # but clang may require alternate syntax on some platforms
+ if (APPLE)
+ set(CMAKE_${lang}_LINK_OPTIONS_PIE ${CMAKE_${lang}_COMPILE_OPTIONS_PIE} -Xlinker -pie)
+ set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE -Xlinker -no_pie)
+ endif()
+ set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-isystem ")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
+ if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.4.0)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_TARGET "-target ")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN "-gcc-toolchain ")
+ else()
+ set(CMAKE_${lang}_COMPILE_OPTIONS_TARGET "--target=")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN "--gcc-toolchain=")
+ endif()
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP)
+
+ if(CMAKE_${lang}_COMPILER_TARGET)
+ if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.4.0)
+ list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "-target" "${CMAKE_${lang}_COMPILER_TARGET}")
+ else()
+ list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "--target=${CMAKE_${lang}_COMPILER_TARGET}")
+ endif()
+ endif()
+
+ set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
+ set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
+
+ string(COMPARE EQUAL "${CMAKE_${lang}_COMPILER_ID}" "AppleClang" __is_apple_clang)
+
+ # '-flto=thin' available since Clang 3.9 and Xcode 8
+ # * http://clang.llvm.org/docs/ThinLTO.html#clang-llvm
+ # * https://trac.macports.org/wiki/XcodeVersionInfo
+ set(_CMAKE_LTO_THIN TRUE)
+ if(__is_apple_clang)
+ if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 8.0)
+ set(_CMAKE_LTO_THIN FALSE)
+ endif()
+ else()
+ if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.9)
+ set(_CMAKE_LTO_THIN FALSE)
+ endif()
+ endif()
+
+ if(_CMAKE_LTO_THIN)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto=thin")
+ else()
+ set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto")
+ endif()
+
+ if(ANDROID AND NOT CMAKE_ANDROID_NDK_VERSION VERSION_GREATER_EQUAL "22")
+ # https://github.com/android-ndk/ndk/issues/242
+ set(CMAKE_${lang}_LINK_OPTIONS_IPO "-fuse-ld=gold")
+ endif()
+
+ if(ANDROID OR __is_apple_clang)
+ set(__ar "${CMAKE_AR}")
+ set(__ranlib "${CMAKE_RANLIB}")
+ else()
+ set(__ar "${CMAKE_${lang}_COMPILER_AR}")
+ set(__ranlib "${CMAKE_${lang}_COMPILER_RANLIB}")
+ endif()
+
+ set(CMAKE_${lang}_ARCHIVE_CREATE_IPO
+ "\"${__ar}\" cr <TARGET> <LINK_FLAGS> <OBJECTS>"
+ )
+
+ set(CMAKE_${lang}_ARCHIVE_APPEND_IPO
+ "\"${__ar}\" r <TARGET> <LINK_FLAGS> <OBJECTS>"
+ )
+
+ set(CMAKE_${lang}_ARCHIVE_FINISH_IPO
+ "\"${__ranlib}\" <TARGET>"
+ )
+
+ set(CMAKE_PCH_EXTENSION .pch)
+ if (NOT CMAKE_GENERATOR MATCHES "Xcode")
+ set(CMAKE_PCH_PROLOGUE "#pragma clang system_header")
+ endif()
+ if(CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 11.0.0 AND NOT __is_apple_clang)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_INSTANTIATE_TEMPLATES_PCH -fpch-instantiate-templates)
+ endif()
+ set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE> -Xclang -include -Xclang <PCH_HEADER>)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Xclang -emit-pch -Xclang -include -Xclang <PCH_HEADER> -x ${__pch_header_${lang}})
+ endmacro()
+endif()
+
+macro(__compiler_clang_cxx_standards lang)
+ if("x${CMAKE_${lang}_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 2.1)
+ set(CMAKE_${lang}98_STANDARD_COMPILE_OPTION "-std=c++98")
+ set(CMAKE_${lang}98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+ endif()
+
+ if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.1)
+ set(CMAKE_${lang}98_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_${lang}11_STANDARD_COMPILE_OPTION "-std=c++11")
+ set(CMAKE_${lang}11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+ set(CMAKE_${lang}11_STANDARD__HAS_FULL_SUPPORT ON)
+ elseif(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 2.1)
+ set(CMAKE_${lang}11_STANDARD_COMPILE_OPTION "-std=c++0x")
+ set(CMAKE_${lang}11_EXTENSION_COMPILE_OPTION "-std=gnu++0x")
+ endif()
+
+ if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.5)
+ set(CMAKE_${lang}14_STANDARD_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_${lang}14_EXTENSION_COMPILE_OPTION "-std=gnu++14")
+ set(CMAKE_${lang}14_STANDARD__HAS_FULL_SUPPORT ON)
+ elseif(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.4)
+ set(CMAKE_${lang}14_STANDARD_COMPILE_OPTION "-std=c++1y")
+ set(CMAKE_${lang}14_EXTENSION_COMPILE_OPTION "-std=gnu++1y")
+ set(CMAKE_${lang}14_STANDARD__HAS_FULL_SUPPORT ON)
+ endif()
+
+ set(_clang_version_std17 5.0)
+ if(CMAKE_SYSTEM_NAME STREQUAL "Android")
+ set(_clang_version_std17 6.0)
+ endif()
+
+ if (NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS "${_clang_version_std17}")
+ set(CMAKE_${lang}17_STANDARD_COMPILE_OPTION "-std=c++17")
+ set(CMAKE_${lang}17_EXTENSION_COMPILE_OPTION "-std=gnu++17")
+ elseif (NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.5)
+ set(CMAKE_${lang}17_STANDARD_COMPILE_OPTION "-std=c++1z")
+ set(CMAKE_${lang}17_EXTENSION_COMPILE_OPTION "-std=gnu++1z")
+ endif()
+
+ if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 11.0)
+ set(CMAKE_${lang}20_STANDARD_COMPILE_OPTION "-std=c++20")
+ set(CMAKE_${lang}20_EXTENSION_COMPILE_OPTION "-std=gnu++20")
+ elseif(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS "${_clang_version_std17}")
+ set(CMAKE_${lang}20_STANDARD_COMPILE_OPTION "-std=c++2a")
+ set(CMAKE_${lang}20_EXTENSION_COMPILE_OPTION "-std=gnu++2a")
+ endif()
+
+ unset(_clang_version_std17)
+
+ if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 12.0)
+ set(CMAKE_${lang}23_STANDARD_COMPILE_OPTION "-std=c++2b")
+ set(CMAKE_${lang}23_EXTENSION_COMPILE_OPTION "-std=gnu++2b")
+ endif()
+
+ if("x${CMAKE_${lang}_SIMULATE_ID}" STREQUAL "xMSVC")
+ # The MSVC standard library requires C++14, and MSVC itself has no
+ # notion of operating in a mode not aware of at least that standard.
+ set(CMAKE_${lang}98_STANDARD_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_${lang}98_EXTENSION_COMPILE_OPTION "-std=gnu++14")
+ set(CMAKE_${lang}11_STANDARD_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_${lang}11_EXTENSION_COMPILE_OPTION "-std=gnu++14")
+
+ # This clang++ is missing some features because of MSVC compatibility.
+ unset(CMAKE_${lang}11_STANDARD__HAS_FULL_SUPPORT)
+ unset(CMAKE_${lang}14_STANDARD__HAS_FULL_SUPPORT)
+ endif()
+
+ __compiler_check_default_language_standard(${lang} 2.1 98)
+ elseif(CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 3.9
+ AND CMAKE_${lang}_SIMULATE_VERSION VERSION_GREATER_EQUAL 19.0)
+ # This version of clang-cl and the MSVC version it simulates have
+ # support for -std: flags.
+ set(CMAKE_${lang}98_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_${lang}98_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_${lang}98_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_${lang}11_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_${lang}11_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_${lang}14_STANDARD_COMPILE_OPTION "-std:c++14")
+ set(CMAKE_${lang}14_EXTENSION_COMPILE_OPTION "-std:c++14")
+ if (CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 6.0)
+ set(CMAKE_${lang}17_STANDARD_COMPILE_OPTION "-std:c++17")
+ set(CMAKE_${lang}17_EXTENSION_COMPILE_OPTION "-std:c++17")
+ set(CMAKE_${lang}20_STANDARD_COMPILE_OPTION "-std:c++latest")
+ set(CMAKE_${lang}20_EXTENSION_COMPILE_OPTION "-std:c++latest")
+ else()
+ set(CMAKE_${lang}17_STANDARD_COMPILE_OPTION "-std:c++latest")
+ set(CMAKE_${lang}17_EXTENSION_COMPILE_OPTION "-std:c++latest")
+ endif()
+
+ __compiler_check_default_language_standard(${lang} 3.9 14)
+ else()
+ # This version of clang-cl, or the MSVC version it simulates, does not have
+ # language standards. Set these options as empty strings so the feature
+ # test infrastructure can at least check to see if they are defined.
+ set(CMAKE_${lang}98_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_${lang}98_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_${lang}11_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_${lang}11_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_${lang}14_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_${lang}14_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_${lang}17_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_${lang}17_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_${lang}20_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_${lang}20_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_${lang}23_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_${lang}23_EXTENSION_COMPILE_OPTION "")
+
+ # There is no meaningful default for this
+ set(CMAKE_${lang}_STANDARD_DEFAULT "")
+
+ # There are no compiler modes so we only need to test features once.
+ # Override the default macro for this special case. Pretend that
+ # all language standards are available so that at least compilation
+ # can be attempted.
+ macro(cmake_record_${lang}_compile_features)
+ list(APPEND CMAKE_${lang}_COMPILE_FEATURES
+ cxx_std_98
+ cxx_std_11
+ cxx_std_14
+ cxx_std_17
+ cxx_std_20
+ cxx_std_23
+ )
+ _record_compiler_features(${lang} "" CMAKE_${lang}_COMPILE_FEATURES)
+ endmacro()
+ endif()
+endmacro()
diff --git a/Modules/Compiler/Comeau-CXX-DetermineCompiler.cmake b/Modules/Compiler/Comeau-CXX-DetermineCompiler.cmake
new file mode 100644
index 0000000..2265e5e
--- /dev/null
+++ b/Modules/Compiler/Comeau-CXX-DetermineCompiler.cmake
@@ -0,0 +1,7 @@
+
+set(_compiler_id_pp_test "defined(__COMO__)")
+
+set(_compiler_id_version_compute "
+ /* __COMO_VERSION__ = VRR */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__COMO_VERSION__ / 100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__COMO_VERSION__ % 100)")
diff --git a/Modules/Compiler/Compaq-C-DetermineCompiler.cmake b/Modules/Compiler/Compaq-C-DetermineCompiler.cmake
new file mode 100644
index 0000000..02e99dc
--- /dev/null
+++ b/Modules/Compiler/Compaq-C-DetermineCompiler.cmake
@@ -0,0 +1,8 @@
+
+set(_compiler_id_pp_test "defined(__DECC)")
+
+set(_compiler_id_version_compute "
+ /* __DECC_VER = VVRRTPPPP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__DECC_VER/10000000)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__DECC_VER/100000 % 100)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__DECC_VER % 10000)")
diff --git a/Modules/Compiler/Compaq-CXX-DetermineCompiler.cmake b/Modules/Compiler/Compaq-CXX-DetermineCompiler.cmake
new file mode 100644
index 0000000..c7d0565
--- /dev/null
+++ b/Modules/Compiler/Compaq-CXX-DetermineCompiler.cmake
@@ -0,0 +1,8 @@
+
+set(_compiler_id_pp_test "defined(__DECCXX)")
+
+set(_compiler_id_version_compute "
+ /* __DECCXX_VER = VVRRTPPPP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__DECCXX_VER/10000000)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__DECCXX_VER/100000 % 100)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__DECCXX_VER % 10000)")
diff --git a/Modules/Compiler/Cray-C.cmake b/Modules/Compiler/Cray-C.cmake
new file mode 100644
index 0000000..9340948
--- /dev/null
+++ b/Modules/Compiler/Cray-C.cmake
@@ -0,0 +1,24 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Compiler/Cray)
+__compiler_cray(C)
+
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
+
+if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.1)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION -h noc99,conform)
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION -h noc99,gnu)
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION -h c99,conform)
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION -h c99,gnu)
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+ if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.5)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION -h std=c11,conform)
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION -h std=c11,gnu)
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+ endif ()
+endif ()
+
+__compiler_check_default_language_standard(C 8.1 99)
diff --git a/Modules/Compiler/Cray-CXX.cmake b/Modules/Compiler/Cray-CXX.cmake
new file mode 100644
index 0000000..38c8b1e
--- /dev/null
+++ b/Modules/Compiler/Cray-CXX.cmake
@@ -0,0 +1,26 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Compiler/Cray)
+__compiler_cray(CXX)
+
+string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -DNDEBUG")
+
+if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.1)
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION -h conform)
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION -h gnu)
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.4)
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION -h std=c++11)
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION -h std=c++11,gnu)
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+ endif()
+ if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.6)
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION -h std=c++14)
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION -h std=c++14,gnu)
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+ endif ()
+endif ()
+
+__compiler_check_default_language_standard(CXX 8.1 98)
diff --git a/Modules/Compiler/Cray-DetermineCompiler.cmake b/Modules/Compiler/Cray-DetermineCompiler.cmake
new file mode 100644
index 0000000..6602294
--- /dev/null
+++ b/Modules/Compiler/Cray-DetermineCompiler.cmake
@@ -0,0 +1,6 @@
+
+set(_compiler_id_pp_test "defined(_CRAYC)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(_RELEASE_MAJOR)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(_RELEASE_MINOR)")
diff --git a/Modules/Compiler/Cray-Fortran.cmake b/Modules/Compiler/Cray-Fortran.cmake
new file mode 100644
index 0000000..0d5e1c7
--- /dev/null
+++ b/Modules/Compiler/Cray-Fortran.cmake
@@ -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(Compiler/Cray)
+__compiler_cray(Fortran)
+
+set(CMAKE_Fortran_SUBMODULE_SEP "")
+set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
+set(CMAKE_Fortran_MODOUT_FLAG -em)
+set(CMAKE_Fortran_MODDIR_FLAG -J)
+set(CMAKE_Fortran_MODDIR_DEFAULT .)
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-f fixed")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-f free")
+
+if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 8.5)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-eT")
+ set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-dT")
+else()
+ set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-eZ")
+ set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-dZ")
+endif()
+
+if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 11.0)
+ set(CMAKE_Fortran_PREPROCESS_SOURCE "<CMAKE_Fortran_COMPILER> -o <PREPROCESSED_SOURCE> <DEFINES> <INCLUDES> <FLAGS> -eP <SOURCE>")
+endif()
diff --git a/Modules/Compiler/Cray.cmake b/Modules/Compiler/Cray.cmake
new file mode 100644
index 0000000..c214afc
--- /dev/null
+++ b/Modules/Compiler/Cray.cmake
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_CRAY)
+ return()
+endif()
+set(__COMPILER_CRAY 1)
+
+include(Compiler/CMakeCommonCompilerMacros)
+
+macro(__compiler_cray lang)
+ set(CMAKE_${lang}_VERBOSE_FLAG "-v")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC -h PIC)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE -h PIC)
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-h PIC")
+endmacro()
diff --git a/Modules/Compiler/CrayPrgEnv-C.cmake b/Modules/Compiler/CrayPrgEnv-C.cmake
new file mode 100644
index 0000000..76aa93b
--- /dev/null
+++ b/Modules/Compiler/CrayPrgEnv-C.cmake
@@ -0,0 +1,7 @@
+if(__craylinux_crayprgenv_c)
+ return()
+endif()
+set(__craylinux_crayprgenv_c 1)
+
+include(Compiler/CrayPrgEnv)
+__CrayPrgEnv_setup(C)
diff --git a/Modules/Compiler/CrayPrgEnv-CXX.cmake b/Modules/Compiler/CrayPrgEnv-CXX.cmake
new file mode 100644
index 0000000..442370e
--- /dev/null
+++ b/Modules/Compiler/CrayPrgEnv-CXX.cmake
@@ -0,0 +1,7 @@
+if(__craylinux_crayprgenv_cxx)
+ return()
+endif()
+set(__craylinux_crayprgenv_cxx 1)
+
+include(Compiler/CrayPrgEnv)
+__CrayPrgEnv_setup(CXX)
diff --git a/Modules/Compiler/CrayPrgEnv-Fortran.cmake b/Modules/Compiler/CrayPrgEnv-Fortran.cmake
new file mode 100644
index 0000000..85f82d3
--- /dev/null
+++ b/Modules/Compiler/CrayPrgEnv-Fortran.cmake
@@ -0,0 +1,7 @@
+if(__craylinux_crayprgenv_fortran)
+ return()
+endif()
+set(__craylinux_crayprgenv_fortran 1)
+
+include(Compiler/CrayPrgEnv)
+__CrayPrgEnv_setup(Fortran)
diff --git a/Modules/Compiler/CrayPrgEnv.cmake b/Modules/Compiler/CrayPrgEnv.cmake
new file mode 100644
index 0000000..f6e46ac
--- /dev/null
+++ b/Modules/Compiler/CrayPrgEnv.cmake
@@ -0,0 +1,136 @@
+# Guard against multiple inclusions
+if(__cmake_craype_crayprgenv)
+ return()
+endif()
+set(__cmake_craype_crayprgenv 1)
+
+# CrayPrgEnv: loaded when compiling through the Cray compiler wrapper.
+# The compiler wrapper can run on a front-end node or a compute node.
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+# One-time setup of the craype environment. First, check the wrapper config.
+# The wrapper's selection of a compiler (gcc, clang, intel, etc.) and
+# default include/library paths is selected using the "module" command.
+# The CRAYPE_LINK_TYPE environment variable partly controls if static
+# or dynamic binaries are generated (see __cmake_craype_linktype below).
+# Running cmake and then changing module and/or linktype configuration
+# may cause build problems (since the data in the cmake cache may no
+# longer be correct after the change). We can look for this and warn
+# the user about it. Second, use the "module" provided PKG_CONFIG_PATH-like
+# environment variable to add additional prefixes to the system prefix
+# path.
+function(__cmake_craype_setupenv)
+ if(NOT DEFINED __cmake_craype_setupenv_done) # only done once per run
+ set(__cmake_craype_setupenv_done 1 PARENT_SCOPE)
+ unset(__cmake_check)
+ set(CMAKE_CRAYPE_LINKTYPE "$ENV{CRAYPE_LINK_TYPE}" CACHE STRING
+ "saved value of CRAYPE_LINK_TYPE environment variable")
+ set(CMAKE_CRAYPE_LOADEDMODULES "$ENV{LOADEDMODULES}" CACHE STRING
+ "saved value of LOADEDMODULES environment variable")
+ mark_as_advanced(CMAKE_CRAYPE_LINKTYPE CMAKE_CRAYPE_LOADEDMODULES)
+ if (NOT "${CMAKE_CRAYPE_LINKTYPE}" STREQUAL "$ENV{CRAYPE_LINK_TYPE}")
+ string(APPEND __cmake_check "CRAYPE_LINK_TYPE ")
+ endif()
+ if (NOT "${CMAKE_CRAYPE_LOADEDMODULES}" STREQUAL "$ENV{LOADEDMODULES}")
+ string(APPEND __cmake_check "LOADEDMODULES ")
+ endif()
+ if(DEFINED __cmake_check)
+ message(STATUS "NOTE: ${__cmake_check}changed since initial config!")
+ message(STATUS "NOTE: this may cause unexpected build errors.")
+ endif()
+ # loop over variables of interest
+ foreach(pkgcfgvar PKG_CONFIG_PATH PKG_CONFIG_PATH_DEFAULT
+ PE_PKG_CONFIG_PATH)
+ file(TO_CMAKE_PATH "$ENV{${pkgcfgvar}}" pkgcfg)
+ foreach(path ${pkgcfg})
+ string(REGEX REPLACE "(.*)/lib[^/]*/pkgconfig$" "\\1" path "${path}")
+ if(NOT "${path}" STREQUAL "" AND
+ NOT "${path}" IN_LIST CMAKE_SYSTEM_PREFIX_PATH)
+ list(APPEND CMAKE_SYSTEM_PREFIX_PATH "${path}")
+ endif()
+ endforeach()
+ endforeach()
+ # push it up out of this function into the parent scope
+ set(CMAKE_SYSTEM_PREFIX_PATH "${CMAKE_SYSTEM_PREFIX_PATH}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# The wrapper disables dynamic linking by default. Dynamic linking is
+# enabled either by setting $ENV{CRAYPE_LINK_TYPE} to "dynamic" or by
+# specifying "-dynamic" to the wrapper when linking. Specifying "-static"
+# to the wrapper when linking takes priority over $ENV{CRAYPE_LINK_TYPE}.
+# Furthermore, if you specify multiple "-dynamic" and "-static" flags to
+# the wrapper when linking, the last one will win. In this case, the
+# wrapper will also print a warning like:
+# Warning: -dynamic was already seen on command line, overriding with -static.
+#
+# note that cmake applies both CMAKE_${lang}_FLAGS and CMAKE_EXE_LINKER_FLAGS
+# (in that order) to the linking command, so -dynamic can appear in either
+# variable.
+#
+# Note: As of CrayPE v19.06 (which translates to the craype/2.6.0 module)
+# the default has changed and is now dynamic by default. This is handled
+# accordingly
+function(__cmake_craype_linktype lang rv)
+ # start with ENV, but allow flags to override
+ if(("$ENV{CRAYPE_VERSION}" STREQUAL "") OR
+ ("$ENV{CRAYPE_VERSION}" VERSION_LESS "2.6"))
+ if("$ENV{CRAYPE_LINK_TYPE}" STREQUAL "dynamic")
+ set(linktype dynamic)
+ else()
+ set(linktype static)
+ endif()
+ else()
+ if("$ENV{CRAYPE_LINK_TYPE}" STREQUAL "static")
+ set(linktype static)
+ else()
+ set(linktype dynamic)
+ endif()
+ endif()
+
+ # combine flags and convert to a list so we can apply the flags in order
+ set(linkflags "${CMAKE_${lang}_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}")
+ string(REPLACE " " ";" linkflags "${linkflags}")
+ foreach(flag IN LISTS linkflags)
+ if("${flag}" STREQUAL "-dynamic")
+ set(linktype dynamic)
+ elseif("${flag}" STREQUAL "-static")
+ set(linktype static)
+ endif()
+ endforeach()
+ set(${rv} ${linktype} PARENT_SCOPE)
+endfunction()
+
+macro(__CrayPrgEnv_setup lang)
+ if(DEFINED ENV{CRAYPE_VERSION})
+ message(STATUS "Cray Programming Environment $ENV{CRAYPE_VERSION} ${lang}")
+ elseif(DEFINED ENV{ASYNCPE_VERSION})
+ message(STATUS "Cray XT Programming Environment $ENV{ASYNCPE_VERSION} ${lang}")
+ else()
+ message(STATUS "Cray Programming Environment (unknown version) ${lang}")
+ endif()
+
+ # setup the craype environment
+ __cmake_craype_setupenv()
+
+ # Flags for the Cray wrappers
+ set(CMAKE_STATIC_LIBRARY_LINK_${lang}_FLAGS "-static")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
+ set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-dynamic")
+
+ # determine linktype from environment and compiler flags
+ __cmake_craype_linktype(${lang} __cmake_craype_${lang}_linktype)
+
+ # switch off shared libs if we get a static linktype
+ if("${__cmake_craype_${lang}_linktype}" STREQUAL "static")
+ set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
+ set(BUILD_SHARED_LIBS FALSE CACHE BOOL "")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
+ set(CMAKE_LINK_SEARCH_START_STATIC TRUE)
+ endif()
+
+endmacro()
+
+cmake_policy(POP)
diff --git a/Modules/Compiler/Embarcadero-DetermineCompiler.cmake b/Modules/Compiler/Embarcadero-DetermineCompiler.cmake
new file mode 100644
index 0000000..8375624
--- /dev/null
+++ b/Modules/Compiler/Embarcadero-DetermineCompiler.cmake
@@ -0,0 +1,7 @@
+
+set(_compiler_id_pp_test "defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_HEX@(__CODEGEARC_VERSION__>>24 & 0x00FF)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_HEX@(__CODEGEARC_VERSION__>>16 & 0x00FF)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__CODEGEARC_VERSION__ & 0xFFFF)")
diff --git a/Modules/Compiler/Flang-FindBinUtils.cmake b/Modules/Compiler/Flang-FindBinUtils.cmake
new file mode 100644
index 0000000..e721c87
--- /dev/null
+++ b/Modules/Compiler/Flang-FindBinUtils.cmake
@@ -0,0 +1 @@
+include(Compiler/Clang-FindBinUtils)
diff --git a/Modules/Compiler/Flang-Fortran.cmake b/Modules/Compiler/Flang-Fortran.cmake
new file mode 100644
index 0000000..de0484e
--- /dev/null
+++ b/Modules/Compiler/Flang-Fortran.cmake
@@ -0,0 +1,16 @@
+include(Compiler/Clang)
+__compiler_clang(Fortran)
+
+set(CMAKE_Fortran_SUBMODULE_SEP "-")
+set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
+
+set(CMAKE_Fortran_PREPROCESS_SOURCE
+ "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
+
+set(CMAKE_Fortran_MODDIR_FLAG "-J")
+
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
diff --git a/Modules/Compiler/Fujitsu-C.cmake b/Modules/Compiler/Fujitsu-C.cmake
new file mode 100644
index 0000000..0e0f1dc
--- /dev/null
+++ b/Modules/Compiler/Fujitsu-C.cmake
@@ -0,0 +1,20 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+include(Compiler/Fujitsu)
+__compiler_fujitsu(C)
+
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4)
+ set(CMAKE_C89_STANDARD_COMPILE_OPTION -std=c89)
+ set(CMAKE_C89_EXTENSION_COMPILE_OPTION -std=gnu89)
+ set(CMAKE_C89_STANDARD__HAS_FULL_SUPPORT ON)
+
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION -std=c99)
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION -std=gnu99)
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION -std=c11)
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION -std=gnu11)
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+__compiler_check_default_language_standard(C 4 11)
diff --git a/Modules/Compiler/Fujitsu-CXX.cmake b/Modules/Compiler/Fujitsu-CXX.cmake
new file mode 100644
index 0000000..0f42196
--- /dev/null
+++ b/Modules/Compiler/Fujitsu-CXX.cmake
@@ -0,0 +1,47 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+include(Compiler/Fujitsu)
+__compiler_fujitsu(CXX)
+
+#set(CMAKE_PCH_EXTENSION .pch)
+#set(CMAKE_PCH_EPILOGUE "#pragma hdrstop")
+#set(CMAKE_CXX_COMPILE_OPTIONS_USE_PCH --no_pch_messages -include <PCH_HEADER> --use_pch <PCH_FILE>)
+#set(CMAKE_CXX_COMPILE_OPTIONS_CREATE_PCH --no_pch_messages -include <PCH_HEADER> --create_pch <PCH_FILE>)
+
+# The Fujitsu compiler offers both a 98 and 03 mode. These two are
+# essentially interchangeable as 03 simply provides clarity to some 98
+# ambiguyity.
+#
+# Re: Stroustrup's C++ FAQ:
+# What is the difference between C++98 and C++03?
+# From a programmer's view there is none. The C++03 revision of the
+# standard was a bug fix release for implementers to ensure greater
+# consistency and portability. In particular, tutorial and reference
+# material describing C++98 and C++03 can be used interchangeably by all
+# except compiler writers and standards gurus.
+#
+# Since CMake doesn't actually have an 03 mode and they're effectively
+# interchangeable then we're just going to explicitly use 03 mode in the
+# compiler when 98 is requested.
+
+# The version matching is messy here. The std support seems to be related to
+# the compiler tweak version derived from the patch id in the version string.
+
+if(CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 4)
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION -std=c++03)
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION -std=gnu++03)
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION -std=c++11)
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION -std=gnu++11)
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION -std=c++14)
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION -std=gnu++14)
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+
+ set(CMAKE_CXX17_STANDARD_COMPILE_OPTION -std=c++17)
+ set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION -std=gnu++17)
+endif()
+
+__compiler_check_default_language_standard(CXX 4 14)
diff --git a/Modules/Compiler/Fujitsu-DetermineCompiler.cmake b/Modules/Compiler/Fujitsu-DetermineCompiler.cmake
new file mode 100644
index 0000000..8534916
--- /dev/null
+++ b/Modules/Compiler/Fujitsu-DetermineCompiler.cmake
@@ -0,0 +1,17 @@
+
+set(_compiler_id_pp_test "defined(__FUJITSU)")
+
+set(_compiler_id_version_compute "
+# if defined(__FCC_version__)
+# define @PREFIX@COMPILER_VERSION __FCC_version__
+# elif defined(__FCC_major__)
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__FCC_major__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__FCC_minor__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__FCC_patchlevel__)
+# endif
+# if defined(__fcc_version)
+# define @PREFIX@COMPILER_VERSION_INTERNAL @MACRO_DEC@(__fcc_version)
+# elif defined(__FCC_VERSION)
+# define @PREFIX@COMPILER_VERSION_INTERNAL @MACRO_DEC@(__FCC_VERSION)
+# endif
+")
diff --git a/Modules/Compiler/Fujitsu-Fortran.cmake b/Modules/Compiler/Fujitsu-Fortran.cmake
new file mode 100644
index 0000000..0f687bc
--- /dev/null
+++ b/Modules/Compiler/Fujitsu-Fortran.cmake
@@ -0,0 +1,16 @@
+include(Compiler/Fujitsu)
+__compiler_fujitsu(Fortran)
+
+set(CMAKE_Fortran_SUBMODULE_SEP ".")
+set(CMAKE_Fortran_SUBMODULE_EXT ".smod")
+
+set(CMAKE_Fortran_PREPROCESS_SOURCE
+ "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -Cpp -E <SOURCE> > <PREPROCESSED_SOURCE>")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-Cpp")
+
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-Fixed")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-Free")
+
+string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT "")
+
+set(CMAKE_Fortran_MODDIR_FLAG "-M ")
diff --git a/Modules/Compiler/Fujitsu.cmake b/Modules/Compiler/Fujitsu.cmake
new file mode 100644
index 0000000..13bc57c
--- /dev/null
+++ b/Modules/Compiler/Fujitsu.cmake
@@ -0,0 +1,33 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_FUJITSU)
+ return()
+endif()
+set(__COMPILER_FUJITSU 1)
+
+include(Compiler/CMakeCommonCompilerMacros)
+
+macro(__compiler_fujitsu lang)
+ set(CMAKE_${lang}_VERBOSE_FLAG "-###")
+
+ # Initial configuration flags
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g -O0")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3 -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG")
+
+ # PIC flags
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
+
+ # Passing link options to the compiler
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
+ # How to actually call the compiler
+ set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE
+ "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E $<$<COMPILE_LANGUAGE:Fortran>:-Cpp> <SOURCE> > <PREPROCESSED_SOURCE>")
+ set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+endmacro()
diff --git a/Modules/Compiler/FujitsuClang-C.cmake b/Modules/Compiler/FujitsuClang-C.cmake
new file mode 100644
index 0000000..f700d2d
--- /dev/null
+++ b/Modules/Compiler/FujitsuClang-C.cmake
@@ -0,0 +1,6 @@
+include(Compiler/FujitsuClang)
+
+set(_fjclang_ver "${CMAKE_C_COMPILER_VERSION_INTERNAL}")
+set(CMAKE_C_COMPILER_VERSION "${CMAKE_C_COMPILER_VERSION_INTERNAL}")
+include(Compiler/Clang-C)
+set(CMAKE_C_COMPILER_VERSION "${_fjclang_ver}")
diff --git a/Modules/Compiler/FujitsuClang-CXX.cmake b/Modules/Compiler/FujitsuClang-CXX.cmake
new file mode 100644
index 0000000..c8790cd
--- /dev/null
+++ b/Modules/Compiler/FujitsuClang-CXX.cmake
@@ -0,0 +1,6 @@
+include(Compiler/FujitsuClang)
+
+set(_fjclang_ver "${CMAKE_CXX_COMPILER_VERSION_INTERNAL}")
+set(CMAKE_CXX_COMPILER_VERSION "${CMAKE_CXX_COMPILER_VERSION_INTERNAL}")
+include(Compiler/Clang-CXX)
+set(CMAKE_CXX_COMPILER_VERSION "${_fjclang_ver}")
diff --git a/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake b/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake
new file mode 100644
index 0000000..f6719b1
--- /dev/null
+++ b/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake
@@ -0,0 +1,9 @@
+
+set(_compiler_id_pp_test "defined(__CLANG_FUJITSU)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__FCC_major__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__FCC_minor__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__FCC_patchlevel__)
+# define @PREFIX@COMPILER_VERSION_INTERNAL_STR __clang_version__
+")
diff --git a/Modules/Compiler/FujitsuClang.cmake b/Modules/Compiler/FujitsuClang.cmake
new file mode 100644
index 0000000..a848248
--- /dev/null
+++ b/Modules/Compiler/FujitsuClang.cmake
@@ -0,0 +1,11 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_FUJITSUCLANG)
+ return()
+endif()
+set(__COMPILER_FUJITSUCLANG 1)
+
+include(Compiler/Clang)
diff --git a/Modules/Compiler/G95-Fortran.cmake b/Modules/Compiler/G95-Fortran.cmake
new file mode 100644
index 0000000..5dba04e
--- /dev/null
+++ b/Modules/Compiler/G95-Fortran.cmake
@@ -0,0 +1,13 @@
+string(APPEND CMAKE_Fortran_FLAGS_INIT " ")
+string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -g")
+string(APPEND CMAKE_Fortran_FLAGS_MINSIZEREL_INIT " -Os")
+string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -O3")
+string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
+set(CMAKE_Fortran_MODDIR_FLAG "-fmod=")
+set(CMAKE_Fortran_VERBOSE_FLAG "-v")
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
+set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
+set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-no-cpp")
diff --git a/Modules/Compiler/GHS-C.cmake b/Modules/Compiler/GHS-C.cmake
new file mode 100644
index 0000000..a825b0b
--- /dev/null
+++ b/Modules/Compiler/GHS-C.cmake
@@ -0,0 +1,10 @@
+include(Compiler/GHS)
+
+set(CMAKE_C_VERBOSE_FLAG "-v")
+set(CMAKE_C_OUTPUT_EXTENSION ".o")
+
+string(APPEND CMAKE_C_FLAGS_INIT " ")
+string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -Odebug -g")
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -Ospace")
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -O")
+string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -O -g")
diff --git a/Modules/Compiler/GHS-CXX.cmake b/Modules/Compiler/GHS-CXX.cmake
new file mode 100644
index 0000000..07b5044
--- /dev/null
+++ b/Modules/Compiler/GHS-CXX.cmake
@@ -0,0 +1,10 @@
+include(Compiler/GHS)
+
+set(CMAKE_CXX_VERBOSE_FLAG "-v")
+set(CMAKE_CXX_OUTPUT_EXTENSION ".o")
+
+string(APPEND CMAKE_CXX_FLAGS_INIT " ")
+string(APPEND CMAKE_CXX_FLAGS_DEBUG_INIT " -Odebug -g")
+string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -Ospace")
+string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -O")
+string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -O -g")
diff --git a/Modules/Compiler/GHS-DetermineCompiler.cmake b/Modules/Compiler/GHS-DetermineCompiler.cmake
new file mode 100644
index 0000000..368b375
--- /dev/null
+++ b/Modules/Compiler/GHS-DetermineCompiler.cmake
@@ -0,0 +1,9 @@
+set(_compiler_id_pp_test "defined(__ghs__)")
+
+set(_compiler_id_version_compute "
+/* __GHS_VERSION_NUMBER = VVVVRP */
+# ifdef __GHS_VERSION_NUMBER
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__GHS_VERSION_NUMBER / 100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__GHS_VERSION_NUMBER / 10 % 10)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__GHS_VERSION_NUMBER % 10)
+# endif")
diff --git a/Modules/Compiler/GHS.cmake b/Modules/Compiler/GHS.cmake
new file mode 100644
index 0000000..b41c3eb
--- /dev/null
+++ b/Modules/Compiler/GHS.cmake
@@ -0,0 +1,8 @@
+if(__COMPILER_GHS)
+ return()
+endif()
+set(__COMPILER_GHS 1)
+
+set(CMAKE_EXECUTABLE_SUFFIX "")
+set(CMAKE_LIBRARY_PATH_TERMINATOR "")
+set(CMAKE_LIBRARY_PATH_FLAG "")
diff --git a/Modules/Compiler/GNU-ASM.cmake b/Modules/Compiler/GNU-ASM.cmake
new file mode 100644
index 0000000..a935416
--- /dev/null
+++ b/Modules/Compiler/GNU-ASM.cmake
@@ -0,0 +1,13 @@
+# This file is loaded when gcc/g++ is used for assembler files (the "ASM" cmake language)
+include(Compiler/GNU)
+
+set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;S;asm)
+
+__compiler_gnu(ASM)
+
+if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_MATCH STREQUAL "GNU assembler")
+ set(CMAKE_DEPFILE_FLAGS_ASM${ASM_DIALECT} "--MD <DEP_FILE>")
+ set(CMAKE_ASM${ASM_DIALECT}_LINK_EXECUTABLE
+ "<CMAKE_LINKER> <FLAGS> <CMAKE_ASM${ASM_DIALECT}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+ set(CMAKE_ASM_DEFINE_FLAG "--defsym ")
+endif()
diff --git a/Modules/Compiler/GNU-C-DetermineCompiler.cmake b/Modules/Compiler/GNU-C-DetermineCompiler.cmake
new file mode 100644
index 0000000..6ddc566
--- /dev/null
+++ b/Modules/Compiler/GNU-C-DetermineCompiler.cmake
@@ -0,0 +1,11 @@
+
+set(_compiler_id_pp_test "defined(__GNUC__)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__GNUC__)
+# if defined(__GNUC_MINOR__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__GNUC_MINOR__)
+# endif
+# if defined(__GNUC_PATCHLEVEL__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__GNUC_PATCHLEVEL__)
+# endif")
diff --git a/Modules/Compiler/GNU-C-FeatureTests.cmake b/Modules/Compiler/GNU-C-FeatureTests.cmake
new file mode 100644
index 0000000..0ab5265
--- /dev/null
+++ b/Modules/Compiler/GNU-C-FeatureTests.cmake
@@ -0,0 +1,17 @@
+
+set(_cmake_oldestSupported "(__GNUC__ * 100 + __GNUC_MINOR__) >= 304")
+
+# GNU 4.7 correctly sets __STDC_VERSION__ to 201112L, but GNU 4.6 sets it
+# to 201000L. As the former is strictly greater than the latter, test only
+# for the latter. If in the future CMake learns about a C feature which was
+# introduced with GNU 4.7, that should test for the correct version, similar
+# to the distinction between __cplusplus and __GXX_EXPERIMENTAL_CXX0X__ tests.
+set(GNU46_C11 "(__GNUC__ * 100 + __GNUC_MINOR__) >= 406 && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201000L")
+set(_cmake_feature_test_c_static_assert "${GNU46_C11}")
+# Since 3.4 at least:
+set(GNU34_C99 "(__GNUC__ * 100 + __GNUC_MINOR__) >= 304 && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L")
+set(_cmake_feature_test_c_restrict "${GNU34_C99}")
+set(_cmake_feature_test_c_variadic_macros "${GNU34_C99}")
+
+set(GNU_C90 "${_cmake_oldestSupported}")
+set(_cmake_feature_test_c_function_prototypes "${GNU_C90}")
diff --git a/Modules/Compiler/GNU-C.cmake b/Modules/Compiler/GNU-C.cmake
new file mode 100644
index 0000000..39e9c72
--- /dev/null
+++ b/Modules/Compiler/GNU-C.cmake
@@ -0,0 +1,49 @@
+include(Compiler/GNU)
+__compiler_gnu(C)
+
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPFILE_FORMAT gcc)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
+
+if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
+elseif (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c89")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu89")
+endif()
+
+if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+elseif (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.6)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c1x")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu1x")
+endif()
+
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.1)
+ set(CMAKE_C17_STANDARD_COMPILE_OPTION "-std=c17")
+ set(CMAKE_C17_EXTENSION_COMPILE_OPTION "-std=gnu17")
+endif()
+
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 9.1)
+ set(CMAKE_C23_STANDARD_COMPILE_OPTION "-std=c23")
+ set(CMAKE_C23_EXTENSION_COMPILE_OPTION "-std=gnu23")
+endif()
+
+__compiler_check_default_language_standard(C 3.4 90 5.0 11 8.1 17)
diff --git a/Modules/Compiler/GNU-CXX-DetermineCompiler.cmake b/Modules/Compiler/GNU-CXX-DetermineCompiler.cmake
new file mode 100644
index 0000000..c25b147
--- /dev/null
+++ b/Modules/Compiler/GNU-CXX-DetermineCompiler.cmake
@@ -0,0 +1,15 @@
+
+set(_compiler_id_pp_test "defined(__GNUC__) || defined(__GNUG__)")
+
+set(_compiler_id_version_compute "
+# if defined(__GNUC__)
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__GNUC__)
+# else
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__GNUG__)
+# endif
+# if defined(__GNUC_MINOR__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__GNUC_MINOR__)
+# endif
+# if defined(__GNUC_PATCHLEVEL__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__GNUC_PATCHLEVEL__)
+# endif")
diff --git a/Modules/Compiler/GNU-CXX-FeatureTests.cmake b/Modules/Compiler/GNU-CXX-FeatureTests.cmake
new file mode 100644
index 0000000..45c5470
--- /dev/null
+++ b/Modules/Compiler/GNU-CXX-FeatureTests.cmake
@@ -0,0 +1,109 @@
+
+# Reference: http://gcc.gnu.org/projects/cxx0x.html
+# http://gcc.gnu.org/projects/cxx1y.html
+
+set(_cmake_oldestSupported "(__GNUC__ * 100 + __GNUC_MINOR__) >= 404")
+
+set(GNU50_CXX14 "(__GNUC__ * 100 + __GNUC_MINOR__) >= 500 && __cplusplus >= 201402L")
+set(_cmake_feature_test_cxx_variable_templates "${GNU50_CXX14}")
+set(_cmake_feature_test_cxx_relaxed_constexpr "${GNU50_CXX14}")
+set(_cmake_feature_test_cxx_aggregate_default_initializers "${GNU50_CXX14}")
+
+# GNU 4.9 in c++14 mode sets __cplusplus to 201300L, so don't test for the
+# correct value of it below.
+# https://patchwork.ozlabs.org/patch/382470/
+set(GNU49_CXX14 "(__GNUC__ * 100 + __GNUC_MINOR__) >= 409 && __cplusplus > 201103L")
+set(_cmake_feature_test_cxx_contextual_conversions "${GNU49_CXX14}")
+set(_cmake_feature_test_cxx_attribute_deprecated "${GNU49_CXX14}")
+set(_cmake_feature_test_cxx_decltype_auto "${GNU49_CXX14}")
+set(_cmake_feature_test_cxx_digit_separators "${GNU49_CXX14}")
+set(_cmake_feature_test_cxx_generic_lambdas "${GNU49_CXX14}")
+# GNU 4.3 supports binary literals as an extension, but may warn about
+# use of extensions prior to GNU 4.9
+# http://stackoverflow.com/questions/16334024/difference-between-gcc-binary-literals-and-c14-ones
+set(_cmake_feature_test_cxx_binary_literals "${GNU49_CXX14}")
+# The features below are documented as available in GNU 4.8 (by implementing an
+# earlier draft of the standard paper), but that version of the compiler
+# does not set __cplusplus to a value greater than 201103L until GNU 4.9:
+# http://gcc.gnu.org/onlinedocs/gcc-4.8.2/cpp/Standard-Predefined-Macros.html#Standard-Predefined-Macros
+# http://gcc.gnu.org/onlinedocs/gcc-4.9.0/cpp/Standard-Predefined-Macros.html#Standard-Predefined-Macros
+# So, CMake only reports availability for it with GNU 4.9 or later.
+set(_cmake_feature_test_cxx_return_type_deduction "${GNU49_CXX14}")
+set(_cmake_feature_test_cxx_lambda_init_captures "${GNU49_CXX14}")
+
+# Introduced in GCC 4.8.1
+set(GNU481_CXX11 "((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40801) && __cplusplus >= 201103L")
+set(_cmake_feature_test_cxx_decltype_incomplete_return_types "${GNU481_CXX11}")
+set(_cmake_feature_test_cxx_reference_qualified_functions "${GNU481_CXX11}")
+set(GNU48_CXX11 "(__GNUC__ * 100 + __GNUC_MINOR__) >= 408 && __cplusplus >= 201103L")
+set(_cmake_feature_test_cxx_alignas "${GNU48_CXX11}")
+# The alignof feature works with GNU 4.7 and -std=c++11, but it is documented
+# as available with GNU 4.8, so treat that as true.
+set(_cmake_feature_test_cxx_alignof "${GNU48_CXX11}")
+set(_cmake_feature_test_cxx_attributes "${GNU48_CXX11}")
+set(_cmake_feature_test_cxx_inheriting_constructors "${GNU48_CXX11}")
+set(_cmake_feature_test_cxx_thread_local "${GNU48_CXX11}")
+set(GNU47_CXX11 "(__GNUC__ * 100 + __GNUC_MINOR__) >= 407 && __cplusplus >= 201103L")
+set(_cmake_feature_test_cxx_alias_templates "${GNU47_CXX11}")
+set(_cmake_feature_test_cxx_delegating_constructors "${GNU47_CXX11}")
+set(_cmake_feature_test_cxx_extended_friend_declarations "${GNU47_CXX11}")
+set(_cmake_feature_test_cxx_final "${GNU47_CXX11}")
+set(_cmake_feature_test_cxx_nonstatic_member_init "${GNU47_CXX11}")
+set(_cmake_feature_test_cxx_override "${GNU47_CXX11}")
+set(_cmake_feature_test_cxx_user_literals "${GNU47_CXX11}")
+# NOTE: C++11 was ratified in September 2011. GNU 4.7 is the first minor
+# release following that (March 2012), and the first minor release to
+# support -std=c++11. Prior to that, support for C++11 features is technically
+# experiemental and possibly incomplete (see for example the note below about
+# cxx_variadic_template_template_parameters)
+# GNU does not define __cplusplus correctly before version 4.7.
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=1773
+# __GXX_EXPERIMENTAL_CXX0X__ is defined in prior versions, but may not be
+# defined in the future.
+set(GNU_CXX0X_DEFINED "(__cplusplus >= 201103L || (defined(__GXX_EXPERIMENTAL_CXX0X__) && __GXX_EXPERIMENTAL_CXX0X__))")
+set(GNU46_CXX11 "(__GNUC__ * 100 + __GNUC_MINOR__) >= 406 && ${GNU_CXX0X_DEFINED}")
+set(_cmake_feature_test_cxx_constexpr "${GNU46_CXX11}")
+set(_cmake_feature_test_cxx_defaulted_move_initializers "${GNU46_CXX11}")
+set(_cmake_feature_test_cxx_enum_forward_declarations "${GNU46_CXX11}")
+set(_cmake_feature_test_cxx_noexcept "${GNU46_CXX11}")
+set(_cmake_feature_test_cxx_nullptr "${GNU46_CXX11}")
+set(_cmake_feature_test_cxx_range_for "${GNU46_CXX11}")
+set(_cmake_feature_test_cxx_unrestricted_unions "${GNU46_CXX11}")
+set(GNU45_CXX11 "(__GNUC__ * 100 + __GNUC_MINOR__) >= 405 && ${GNU_CXX0X_DEFINED}")
+set(_cmake_feature_test_cxx_explicit_conversions "${GNU45_CXX11}")
+set(_cmake_feature_test_cxx_lambdas "${GNU45_CXX11}")
+set(_cmake_feature_test_cxx_local_type_template_args "${GNU45_CXX11}")
+set(_cmake_feature_test_cxx_raw_string_literals "${GNU45_CXX11}")
+set(GNU44_CXX11 "(__GNUC__ * 100 + __GNUC_MINOR__) >= 404 && ${GNU_CXX0X_DEFINED}")
+set(_cmake_feature_test_cxx_auto_type "${GNU44_CXX11}")
+set(_cmake_feature_test_cxx_defaulted_functions "${GNU44_CXX11}")
+set(_cmake_feature_test_cxx_deleted_functions "${GNU44_CXX11}")
+set(_cmake_feature_test_cxx_generalized_initializers "${GNU44_CXX11}")
+set(_cmake_feature_test_cxx_inline_namespaces "${GNU44_CXX11}")
+set(_cmake_feature_test_cxx_sizeof_member "${GNU44_CXX11}")
+set(_cmake_feature_test_cxx_strong_enums "${GNU44_CXX11}")
+set(_cmake_feature_test_cxx_trailing_return_types "${GNU44_CXX11}")
+set(_cmake_feature_test_cxx_unicode_literals "${GNU44_CXX11}")
+set(_cmake_feature_test_cxx_uniform_initialization "${GNU44_CXX11}")
+set(_cmake_feature_test_cxx_variadic_templates "${GNU44_CXX11}")
+# TODO: If features are ever recorded for GNU 4.3, there should possibly
+# be a new feature added like cxx_variadic_template_template_parameters,
+# which is implemented by GNU 4.4, but not 4.3. cxx_variadic_templates is
+# actually implemented by GNU 4.3, but variadic template template parameters
+# 'completes' it, so that is the version we record as having the variadic
+# templates capability in CMake. See
+# http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf
+# TODO: Should be supported by GNU 4.3
+set(GNU43_CXX11 "${_cmake_oldestSupported} && ${GNU_CXX0X_DEFINED}")
+set(_cmake_feature_test_cxx_decltype "${GNU43_CXX11}")
+set(_cmake_feature_test_cxx_default_function_template_args "${GNU43_CXX11}")
+set(_cmake_feature_test_cxx_long_long_type "${GNU43_CXX11}")
+set(_cmake_feature_test_cxx_right_angle_brackets "${GNU43_CXX11}")
+set(_cmake_feature_test_cxx_rvalue_references "${GNU43_CXX11}")
+set(_cmake_feature_test_cxx_static_assert "${GNU43_CXX11}")
+# TODO: Should be supported since GNU 3.4?
+set(_cmake_feature_test_cxx_extern_templates "${_cmake_oldestSupported} && ${GNU_CXX0X_DEFINED}")
+# TODO: Should be supported forever?
+set(_cmake_feature_test_cxx_func_identifier "${_cmake_oldestSupported} && ${GNU_CXX0X_DEFINED}")
+set(_cmake_feature_test_cxx_variadic_macros "${_cmake_oldestSupported} && ${GNU_CXX0X_DEFINED}")
+set(_cmake_feature_test_cxx_template_template_parameters "${_cmake_oldestSupported} && __cplusplus")
diff --git a/Modules/Compiler/GNU-CXX.cmake b/Modules/Compiler/GNU-CXX.cmake
new file mode 100644
index 0000000..758d3c7
--- /dev/null
+++ b/Modules/Compiler/GNU-CXX.cmake
@@ -0,0 +1,69 @@
+include(Compiler/GNU)
+__compiler_gnu(CXX)
+
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
+
+if (WIN32)
+ if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
+ set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fno-keep-inline-dllexport")
+ endif()
+else()
+ if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0)
+ set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
+ endif()
+endif()
+
+if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4)
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+endif()
+
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4)
+ # 4.3 supports 0x variants
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++0x")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++0x")
+endif()
+
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8.1)
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14")
+elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++1y")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y")
+endif()
+
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)
+ set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++17")
+ set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17")
+elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
+ set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++1z")
+ set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++1z")
+endif()
+
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)
+ set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std=c++2a")
+ set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std=gnu++2a")
+endif()
+
+__compiler_check_default_language_standard(CXX 3.4 98 6.0 14)
diff --git a/Modules/Compiler/GNU-FindBinUtils.cmake b/Modules/Compiler/GNU-FindBinUtils.cmake
new file mode 100644
index 0000000..097fbf3
--- /dev/null
+++ b/Modules/Compiler/GNU-FindBinUtils.cmake
@@ -0,0 +1,35 @@
+if(NOT DEFINED _CMAKE_PROCESSING_LANGUAGE OR _CMAKE_PROCESSING_LANGUAGE STREQUAL "")
+ message(FATAL_ERROR "Internal error: _CMAKE_PROCESSING_LANGUAGE is not set")
+endif()
+
+# Ubuntu 16.04:
+# * /usr/bin/gcc-ar-5
+# * /usr/bin/gcc-ranlib-5
+string(REGEX MATCH "^([0-9]+)" __version_x
+ "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_VERSION}")
+
+string(REGEX MATCH "^([0-9]+\\.[0-9]+)" __version_x_y
+ "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_VERSION}")
+
+# Try to find tools in the same directory as GCC itself
+get_filename_component(__gcc_hints "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER}" DIRECTORY)
+
+# http://manpages.ubuntu.com/manpages/wily/en/man1/gcc-ar.1.html
+find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_AR NAMES
+ "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar-${__version_x_y}"
+ "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar-${__version_x}"
+ "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar${_CMAKE_COMPILER_SUFFIX}"
+ HINTS ${__gcc_hints}
+ DOC "A wrapper around 'ar' adding the appropriate '--plugin' option for the GCC compiler"
+)
+mark_as_advanced(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_AR)
+
+# http://manpages.ubuntu.com/manpages/wily/en/man1/gcc-ranlib.1.html
+find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_RANLIB NAMES
+ "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib-${__version_x_y}"
+ "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib-${__version_x}"
+ "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib${_CMAKE_COMPILER_SUFFIX}"
+ HINTS ${__gcc_hints}
+ DOC "A wrapper around 'ranlib' adding the appropriate '--plugin' option for the GCC compiler"
+)
+mark_as_advanced(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_RANLIB)
diff --git a/Modules/Compiler/GNU-Fortran.cmake b/Modules/Compiler/GNU-Fortran.cmake
new file mode 100644
index 0000000..5dfb03e
--- /dev/null
+++ b/Modules/Compiler/GNU-Fortran.cmake
@@ -0,0 +1,28 @@
+include(Compiler/GNU)
+__compiler_gnu(Fortran)
+
+set(CMAKE_Fortran_SUBMODULE_SEP "@")
+set(CMAKE_Fortran_SUBMODULE_EXT ".smod")
+
+set(CMAKE_Fortran_PREPROCESS_SOURCE
+ "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> -o <PREPROCESSED_SOURCE>")
+
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
+
+if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 4.4)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
+ set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
+endif()
+
+set(CMAKE_Fortran_POSTPROCESS_FLAG "-fpreprocessed")
+
+# No -DNDEBUG for Fortran.
+string(APPEND CMAKE_Fortran_FLAGS_MINSIZEREL_INIT " -Os")
+string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -O3")
+
+# No -isystem for Fortran because it will not find .mod files.
+unset(CMAKE_INCLUDE_SYSTEM_FLAG_Fortran)
+
+# Fortran-specific feature flags.
+set(CMAKE_Fortran_MODDIR_FLAG -J)
diff --git a/Modules/Compiler/GNU-OBJC.cmake b/Modules/Compiler/GNU-OBJC.cmake
new file mode 100644
index 0000000..7eeed83
--- /dev/null
+++ b/Modules/Compiler/GNU-OBJC.cmake
@@ -0,0 +1,11 @@
+include(Compiler/GNU)
+__compiler_gnu(OBJC)
+
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_OBJC)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_OBJC_DEPFILE_FORMAT gcc)
+ set(CMAKE_OBJC_DEPENDS_USE_COMPILER TRUE)
+endif()
diff --git a/Modules/Compiler/GNU-OBJCXX.cmake b/Modules/Compiler/GNU-OBJCXX.cmake
new file mode 100644
index 0000000..1047b5d
--- /dev/null
+++ b/Modules/Compiler/GNU-OBJCXX.cmake
@@ -0,0 +1,19 @@
+include(Compiler/GNU)
+__compiler_gnu(OBJCXX)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_OBJCXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_OBJCXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_OBJCXX_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+
+if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 4.2)
+ set(CMAKE_OBJCXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
+endif()
+
+if(NOT CMAKE_OBJCXX_LINK_FLAGS)
+ set(CMAKE_OBCXX_LINK_FLAGS "-lstdc++")
+endif()
diff --git a/Modules/Compiler/GNU.cmake b/Modules/Compiler/GNU.cmake
new file mode 100644
index 0000000..928e726
--- /dev/null
+++ b/Modules/Compiler/GNU.cmake
@@ -0,0 +1,122 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_GNU)
+ return()
+endif()
+set(__COMPILER_GNU 1)
+
+include(Compiler/CMakeCommonCompilerMacros)
+
+set(__pch_header_C "c-header")
+set(__pch_header_CXX "c++-header")
+set(__pch_header_OBJC "objective-c-header")
+set(__pch_header_OBJCXX "objective-c++-header")
+
+macro(__compiler_gnu lang)
+ # Feature flags.
+ set(CMAKE_${lang}_VERBOSE_FLAG "-v")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+ set (_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+ if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.4)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
+ # Support of PIE at link stage depends on various elements : platform, compiler, linker
+ # so to activate it, module CheckPIESupported must be used.
+ set (_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER YES)
+ set(CMAKE_${lang}_LINK_OPTIONS_PIE ${CMAKE_${lang}_COMPILE_OPTIONS_PIE} "-pie")
+ set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE "-no-pie")
+ endif()
+ if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 4.0)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
+ endif()
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_SYSROOT "--sysroot=")
+
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
+ # Older versions of gcc (< 4.5) contain a bug causing them to report a missing
+ # header file as a warning if depfiles are enabled, causing check_header_file
+ # tests to always succeed. Work around this by disabling dependency tracking
+ # in try_compile mode.
+ get_property(_IN_TC GLOBAL PROPERTY IN_TRY_COMPILE)
+ if(CMAKE_${lang}_COMPILER_ID STREQUAL "GNU" AND _IN_TC AND NOT CMAKE_FORCE_DEPFILES)
+ else()
+ # distcc does not transform -o to -MT when invoking the preprocessor
+ # internally, as it ought to. Work around this bug by setting -MT here
+ # even though it isn't strictly necessary.
+ set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+ endif()
+
+ # Initial configuration flags.
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3 -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG")
+ set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+ set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+ if(NOT APPLE OR NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 4) # work around #4462
+ set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-isystem ")
+ endif()
+
+ set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
+ set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER NO)
+
+ # '-flto' introduced since GCC 4.5:
+ # * https://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Option-Summary.html (no)
+ # * https://gcc.gnu.org/onlinedocs/gcc-4.5.4/gcc/Option-Summary.html (yes)
+ if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 4.5)
+ set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
+ set(__lto_flags -flto)
+
+ if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 4.7)
+ # '-ffat-lto-objects' introduced since GCC 4.7:
+ # * https://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Option-Summary.html (no)
+ # * https://gcc.gnu.org/onlinedocs/gcc-4.7.4/gcc/Option-Summary.html (yes)
+ list(APPEND __lto_flags -fno-fat-lto-objects)
+ endif()
+
+ set(CMAKE_${lang}_COMPILE_OPTIONS_IPO ${__lto_flags})
+
+ # Need to use version of 'ar'/'ranlib' with plugin support.
+ # Quote from [documentation][1]:
+ #
+ # To create static libraries suitable for LTO,
+ # use gcc-ar and gcc-ranlib instead of ar and ranlib
+ #
+ # [1]: https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gcc/Optimize-Options.html
+ set(CMAKE_${lang}_ARCHIVE_CREATE_IPO
+ "\"${CMAKE_${lang}_COMPILER_AR}\" cr <TARGET> <LINK_FLAGS> <OBJECTS>"
+ )
+
+ set(CMAKE_${lang}_ARCHIVE_APPEND_IPO
+ "\"${CMAKE_${lang}_COMPILER_AR}\" r <TARGET> <LINK_FLAGS> <OBJECTS>"
+ )
+
+ set(CMAKE_${lang}_ARCHIVE_FINISH_IPO
+ "\"${CMAKE_${lang}_COMPILER_RANLIB}\" <TARGET>"
+ )
+ endif()
+
+ set(CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "${CMAKE_${lang}_COMPILER}")
+ if(CMAKE_${lang}_COMPILER_ARG1)
+ separate_arguments(_COMPILER_ARGS NATIVE_COMMAND "${CMAKE_${lang}_COMPILER_ARG1}")
+ list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND ${_COMPILER_ARGS})
+ unset(_COMPILER_ARGS)
+ endif()
+ list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "-dM" "-E" "-c" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp")
+
+ if(NOT "x${lang}" STREQUAL "xFortran")
+ set(CMAKE_PCH_EXTENSION .gch)
+ if (NOT CMAKE_GENERATOR MATCHES "Xcode")
+ set(CMAKE_PCH_PROLOGUE "#pragma GCC system_header")
+ endif()
+ set(CMAKE_${lang}_COMPILE_OPTIONS_INVALID_PCH -Winvalid-pch)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -include <PCH_HEADER>)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -x ${__pch_header_${lang}} -include <PCH_HEADER>)
+ endif()
+endmacro()
diff --git a/Modules/Compiler/HP-ASM.cmake b/Modules/Compiler/HP-ASM.cmake
new file mode 100644
index 0000000..b60f207
--- /dev/null
+++ b/Modules/Compiler/HP-ASM.cmake
@@ -0,0 +1,3 @@
+set(CMAKE_ASM_VERBOSE_FLAG "-v")
+
+set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s )
diff --git a/Modules/Compiler/HP-C-DetermineCompiler.cmake b/Modules/Compiler/HP-C-DetermineCompiler.cmake
new file mode 100644
index 0000000..4269799
--- /dev/null
+++ b/Modules/Compiler/HP-C-DetermineCompiler.cmake
@@ -0,0 +1,8 @@
+
+set(_compiler_id_pp_test "defined(__HP_cc)")
+
+set(_compiler_id_version_compute "
+ /* __HP_cc = VVRRPP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__HP_cc/10000)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__HP_cc/100 % 100)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__HP_cc % 100)")
diff --git a/Modules/Compiler/HP-C.cmake b/Modules/Compiler/HP-C.cmake
new file mode 100644
index 0000000..8fa4c08
--- /dev/null
+++ b/Modules/Compiler/HP-C.cmake
@@ -0,0 +1,7 @@
+set(CMAKE_C_VERBOSE_FLAG "-v")
+
+set(CMAKE_C_CREATE_ASSEMBLY_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+set(CMAKE_C_CREATE_PREPROCESSED_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+
+set(CMAKE_C_LINKER_WRAPPER_FLAG "-Wl,")
+set(CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",")
diff --git a/Modules/Compiler/HP-CXX-DetermineCompiler.cmake b/Modules/Compiler/HP-CXX-DetermineCompiler.cmake
new file mode 100644
index 0000000..3d4d7e4
--- /dev/null
+++ b/Modules/Compiler/HP-CXX-DetermineCompiler.cmake
@@ -0,0 +1,8 @@
+
+set(_compiler_id_pp_test "defined(__HP_aCC)")
+
+set(_compiler_id_version_compute "
+ /* __HP_aCC = VVRRPP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__HP_aCC/10000)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__HP_aCC/100 % 100)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__HP_aCC % 100)")
diff --git a/Modules/Compiler/HP-CXX.cmake b/Modules/Compiler/HP-CXX.cmake
new file mode 100644
index 0000000..5726b64
--- /dev/null
+++ b/Modules/Compiler/HP-CXX.cmake
@@ -0,0 +1,16 @@
+set(CMAKE_CXX_VERBOSE_FLAG "-v")
+
+set(CMAKE_CXX_CREATE_ASSEMBLY_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+set(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+
+set(CMAKE_CXX_LINKER_WRAPPER_FLAG "-Wl,")
+set(CMAKE_CXX_LINKER_WRAPPER_FLAG_SEP ",")
+
+# HP aCC since version 3.80 supports the flag +hpxstd98 to get ANSI C++98
+# template support. It is known that version 6.25 doesn't need that flag.
+# Current assumption: the flag is needed for every version from 3.80 to 4
+# to get it working.
+if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4 AND
+ NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.80)
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "+hpxstd98")
+endif()
diff --git a/Modules/Compiler/HP-Fortran.cmake b/Modules/Compiler/HP-Fortran.cmake
new file mode 100644
index 0000000..d3e2a30
--- /dev/null
+++ b/Modules/Compiler/HP-Fortran.cmake
@@ -0,0 +1,12 @@
+set(CMAKE_Fortran_VERBOSE_FLAG "-v")
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "+source=fixed")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "+source=free")
+
+set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+
+set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
+set(CMAKE_Fortran_LINKER_WRAPPER_FLAG ",")
+
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "+cpp=yes")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "+cpp=no")
diff --git a/Modules/Compiler/IAR-ASM.cmake b/Modules/Compiler/IAR-ASM.cmake
new file mode 100644
index 0000000..e3ca16e
--- /dev/null
+++ b/Modules/Compiler/IAR-ASM.cmake
@@ -0,0 +1,57 @@
+# This file is processed when the IAR compiler is used for an assembler file
+
+include(Compiler/IAR)
+
+if("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
+ set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+ __compiler_iar_ilink(ASM)
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
+
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX")
+ set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+ __compiler_iar_ilink(ASM)
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
+
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850")
+ set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+ __compiler_iar_ilink(ASM)
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
+
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78")
+ set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+ __compiler_iar_ilink(ASM)
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
+
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RISC-V")
+ set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+ __compiler_iar_ilink(ASM)
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
+
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
+ set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+ __compiler_iar_xlink(ASM)
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s90;asm;msa)
+
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430")
+ set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+ __compiler_iar_xlink(ASM)
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s43;asm;msa)
+
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "V850")
+ set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+ __compiler_iar_xlink(ASM)
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s85;asm;msa)
+
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "8051")
+ set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+ __compiler_iar_xlink(ASM)
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s51;asm;msa)
+
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "STM8")
+ set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+ __compiler_iar_ilink(ASM)
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
+
+else()
+ message(FATAL_ERROR "CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID not detected. This should be automatic.")
+endif()
diff --git a/Modules/Compiler/IAR-C.cmake b/Modules/Compiler/IAR-C.cmake
new file mode 100644
index 0000000..054ee74
--- /dev/null
+++ b/Modules/Compiler/IAR-C.cmake
@@ -0,0 +1,79 @@
+# This file is processed when the IAR compiler is used for a C file
+
+include(Compiler/IAR)
+include(Compiler/CMakeCommonCompilerMacros)
+
+# Common
+if(NOT CMAKE_C_COMPILER_VERSION)
+ message(FATAL_ERROR "CMAKE_C_COMPILER_VERSION not detected. This should be automatic.")
+endif()
+
+set(CMAKE_C_EXTENSION_COMPILE_OPTION -e)
+
+if(CMAKE_C_COMPILER_VERSION_INTERNAL VERSION_GREATER 7)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION --c89)
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION --c89 -e)
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION -e)
+else()
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION -e)
+endif()
+
+if(CMAKE_C_COMPILER_VERSION_INTERNAL VERSION_GREATER 8)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION -e)
+endif()
+
+# Architecture specific
+if("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
+ if(CMAKE_C_COMPILER_VERSION_INTERNAL VERSION_LESS 7)
+ # IAR ARM 4.X uses xlink.exe, detection is not yet implemented
+ message(FATAL_ERROR "CMAKE_C_COMPILER_VERSION = ${CMAKE_C_COMPILER_VERSION} not supported by CMake.")
+ endif()
+ __compiler_iar_ilink(C)
+ __compiler_check_default_language_standard(C 1.10 90 6.10 99 8.10 11)
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX")
+ __compiler_iar_ilink(C)
+ __compiler_check_default_language_standard(C 1.10 90 2.10 99 4.10 11)
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850")
+ __compiler_iar_ilink(C)
+ __compiler_check_default_language_standard(C 1.10 90 1.10 99 2.10 11)
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78")
+ __compiler_iar_ilink(C)
+ __compiler_check_default_language_standard(C 1.10 90 1.10 99 4.10 11)
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RISCV")
+ __compiler_iar_ilink(C)
+ __compiler_check_default_language_standard(C 1.10 90 1.10 99 1.10 11)
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
+ __compiler_iar_xlink(C)
+ __compiler_check_default_language_standard(C 7.10 99)
+ set(CMAKE_C_OUTPUT_EXTENSION ".r90")
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430")
+ __compiler_iar_xlink(C)
+ __compiler_check_default_language_standard(C 1.10 90 5.10 99)
+ set(CMAKE_C_OUTPUT_EXTENSION ".r43")
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "V850")
+ __compiler_iar_xlink(C)
+ __compiler_check_default_language_standard(C 1.10 90 4.10 99)
+ set(CMAKE_C_OUTPUT_EXTENSION ".r85")
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "8051")
+ __compiler_iar_xlink(C)
+ __compiler_check_default_language_standard(C 6.10 90 8.10 99)
+ set(CMAKE_C_OUTPUT_EXTENSION ".r51")
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "STM8")
+ __compiler_iar_ilink(C)
+ __compiler_check_default_language_standard(C 3.11 90 3.11 99)
+
+else()
+ message(FATAL_ERROR "CMAKE_C_COMPILER_ARCHITECTURE_ID not detected. This should be automatic.")
+endif()
diff --git a/Modules/Compiler/IAR-CXX.cmake b/Modules/Compiler/IAR-CXX.cmake
new file mode 100644
index 0000000..d93b272
--- /dev/null
+++ b/Modules/Compiler/IAR-CXX.cmake
@@ -0,0 +1,87 @@
+# This file is processed when the IAR compiler is used for a C++ file
+
+include(Compiler/IAR)
+include(Compiler/CMakeCommonCompilerMacros)
+
+# Common
+if(NOT CMAKE_CXX_COMPILER_VERSION)
+ message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION not detected. This should be automatic.")
+endif()
+
+if(NOT CMAKE_IAR_CXX_FLAG)
+ # The --c++ flag was introduced in platform version 9 for all architectures except ARM where it was introduced already in version 7
+ if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 8 OR
+ (CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 6 AND "${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM") )
+ set(CMAKE_IAR_CXX_FLAG --c++)
+ else()
+ set(CMAKE_IAR_CXX_FLAG --eec++)
+ endif()
+endif()
+
+set(CMAKE_CXX_EXTENSION_COMPILE_OPTION -e)
+
+if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 7)
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION -e)
+ set(CMAKE_CXX03_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX03_EXTENSION_COMPILE_OPTION -e)
+endif()
+
+if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 8)
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION -e)
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION -e)
+endif()
+
+# Architecture specific
+if("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
+ if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_LESS 7)
+ # IAR ARM 4.X uses xlink.exe, detection is not yet implemented
+ message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION = ${CMAKE_C_COMPILER_VERSION} not supported by CMake.")
+ endif()
+ __compiler_iar_ilink(CXX)
+ __compiler_check_default_language_standard(CXX 6.10 98 8.10 14)
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX")
+ __compiler_iar_ilink(CXX)
+ __compiler_check_default_language_standard(CXX 2.10 98 4.10 14)
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850")
+ __compiler_iar_ilink(CXX)
+ __compiler_check_default_language_standard(CXX 1.10 98 2.10 14)
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78")
+ __compiler_iar_ilink(CXX)
+ __compiler_check_default_language_standard(CXX 1.10 98 4.10 14)
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RISCV")
+ __compiler_iar_ilink(CXX)
+ __compiler_check_default_language_standard(CXX 1.10 98 1.10 14)
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
+ __compiler_iar_xlink(CXX)
+ __compiler_check_default_language_standard(CXX 7.10 98)
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430")
+ __compiler_iar_xlink(CXX)
+ __compiler_check_default_language_standard(CXX 5.10 98)
+ set(CMAKE_CXX_OUTPUT_EXTENSION ".r43")
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "V850")
+ __compiler_iar_xlink(CXX)
+ __compiler_check_default_language_standard(CXX 1.10 98)
+ set(CMAKE_C_OUTPUT_EXTENSION ".r85")
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "8051")
+ __compiler_iar_xlink(CXX)
+ __compiler_check_default_language_standard(CXX 6.10 98)
+ set(CMAKE_C_OUTPUT_EXTENSION ".r51")
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "STM8")
+ __compiler_iar_ilink(CXX)
+ __compiler_check_default_language_standard(CXX 3.11 98)
+
+else()
+ message(FATAL_ERROR "CMAKE_CXX_COMPILER_ARCHITECTURE_ID not detected. This should be automatic." )
+endif()
diff --git a/Modules/Compiler/IAR-DetermineCompiler.cmake b/Modules/Compiler/IAR-DetermineCompiler.cmake
new file mode 100644
index 0000000..443b09c
--- /dev/null
+++ b/Modules/Compiler/IAR-DetermineCompiler.cmake
@@ -0,0 +1,39 @@
+# IAR Systems compiler for ARM embedded systems.
+# http://www.iar.com
+# http://supp.iar.com/FilesPublic/UPDINFO/004916/arm/doc/EWARM_DevelopmentGuide.ENU.pdf
+#
+# __IAR_SYSTEMS_ICC__ An integer that identifies the IAR compiler platform:
+# 9 and higher means C11 and C++14 as language default
+# 8 means C99 and C++03 as language default
+# 7 and lower means C89 and EC++ as language default.
+# __ICCARM__ An integer that is set to 1 when the code is compiled with the IAR C/C++ Compiler for ARM
+# __VER__ An integer that identifies the version number of the IAR compiler in use. For example,
+# version 5.11.3 is returned as 5011003.
+#
+# IAR Systems Compiler for AVR embedded systems
+# http://supp.iar.com/FilesPublic/UPDINFO/007051/ew/doc/EWAVR_CompilerReference.pdf
+#
+# __IAR_SYSTEMS_ICC__ An integer that identifies the IAR compiler platform.
+# __ICCAVR__ An integer that is set to 1 when the code is compiled with the IAR C/C++ Compiler for AVR
+# __VER__ An integer that identifies the version number of the IAR compiler in use.
+# The value is calculated by (100 * VERSION_MAJOR + VERSION_MINOR). For example the version
+# 3.34 is given as 334
+# __SUBVERSION__ An integer that identifies the subversion number of the compiler version number
+# for example 3 in 1.2.3.4. THis is used as the patch version, as seen when running iccavr
+# from the command line
+#
+
+set(_compiler_id_pp_test "defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)")
+
+set(_compiler_id_version_compute "
+# if defined(__VER__) && defined(__ICCARM__)
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@((__VER__) / 1000000)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(((__VER__) / 1000) % 1000)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@((__VER__) % 1000)
+# define @PREFIX@COMPILER_VERSION_INTERNAL @MACRO_DEC@(__IAR_SYSTEMS_ICC__)
+# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__))
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@((__VER__) / 100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@((__VER__) - (((__VER__) / 100)*100))
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__SUBVERSION__)
+# define @PREFIX@COMPILER_VERSION_INTERNAL @MACRO_DEC@(__IAR_SYSTEMS_ICC__)
+# endif")
diff --git a/Modules/Compiler/IAR-FindBinUtils.cmake b/Modules/Compiler/IAR-FindBinUtils.cmake
new file mode 100644
index 0000000..6c67d34
--- /dev/null
+++ b/Modules/Compiler/IAR-FindBinUtils.cmake
@@ -0,0 +1,64 @@
+if(NOT DEFINED _CMAKE_PROCESSING_LANGUAGE OR _CMAKE_PROCESSING_LANGUAGE STREQUAL "")
+ message(FATAL_ERROR "Internal error: _CMAKE_PROCESSING_LANGUAGE is not set")
+endif()
+
+# Try to find tools in the same directory as the compiler itself
+get_filename_component(__iar_hint_1 "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER}" REALPATH)
+get_filename_component(__iar_hint_1 "${__iar_hint_1}" DIRECTORY)
+
+get_filename_component(__iar_hint_2 "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER}" DIRECTORY)
+
+set(__iar_hints "${__iar_hint_1}" "${__iar_hint_2}")
+
+if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM" OR
+ "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX" OR
+ "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850" OR
+ "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78" OR
+ "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RISCV" OR
+ "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "STM8")
+
+ string(TOLOWER "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" _archid_lower)
+
+ # Find linker
+ find_program(CMAKE_IAR_LINKER ilink${_archid_lower} HINTS ${__iar_hints}
+ DOC "The IAR ILINK linker")
+ find_program(CMAKE_IAR_ARCHIVE iarchive HINTS ${__iar_hints}
+ DOC "The IAR archiver")
+
+ # Find utility tools
+ find_program(CMAKE_IAR_ELFTOOL ielftool HINTS ${__iar_hints}
+ DOC "The IAR ELF Tool")
+ find_program(CMAKE_IAR_ELFDUMP ielfdump${_archid_lower} HINTS ${__iar_hints}
+ DOC "The IAR ELF Dumper")
+ find_program(CMAKE_IAR_OBJMANIP iobjmanip HINTS ${__iar_hints}
+ DOC "The IAR ELF Object Tool")
+ find_program(CMAKE_IAR_SYMEXPORT isymexport HINTS ${__iar_hints}
+ DOC "The IAR Absolute Symbol Exporter")
+ mark_as_advanced(CMAKE_IAR_LINKER CMAKE_IAR_ARCHIVE CMAKE_IAR_ELFTOOL CMAKE_IAR_ELFDUMP CMAKE_IAR_OBJMANIP CMAKE_IAR_SYMEXPORT)
+
+ set(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_CUSTOM_CODE
+"set(CMAKE_IAR_LINKER \"${CMAKE_IAR_LINKER}\")
+set(CMAKE_IAR_ARCHIVE \"${CMAKE_IAR_ARCHIVE}\")
+set(CMAKE_IAR_ELFTOOL \"${CMAKE_IAR_ELFTOOL}\")
+set(CMAKE_IAR_ELFDUMP \"${CMAKE_IAR_ELFDUMP}\")
+set(CMAKE_IAR_OBJMANIP \"${CMAKE_IAR_OBJMANIP}\")
+set(CMAKE_IAR_LINKER \"${CMAKE_IAR_LINKER}\")
+")
+
+elseif("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR" OR
+ "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430" OR
+ "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "V850" OR
+ "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "8051")
+
+ # Find the "xlink" linker and "xar" archiver:
+ find_program(CMAKE_IAR_LINKER xlink HINTS ${__iar_hints}
+ DOC "The IAR XLINK linker")
+ find_program(CMAKE_IAR_AR xar HINTS ${__iar_hints}
+ DOC "The IAR archiver")
+ mark_as_advanced(CMAKE_IAR_LINKER CMAKE_IAR_AR)
+
+ set(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_CUSTOM_CODE
+"set(CMAKE_IAR_LINKER \"${CMAKE_IAR_LINKER}\")
+set(CMAKE_IAR_AR \"${CMAKE_IAR_AR}\")
+")
+endif()
diff --git a/Modules/Compiler/IAR.cmake b/Modules/Compiler/IAR.cmake
new file mode 100644
index 0000000..b8c0770
--- /dev/null
+++ b/Modules/Compiler/IAR.cmake
@@ -0,0 +1,115 @@
+# This file is processed when the IAR compiler is used for a C or C++ file
+# Documentation can be downloaded here: http://www.iar.com/website1/1.0.1.0/675/1/
+# The initial feature request is here: https://gitlab.kitware.com/cmake/cmake/-/issues/10176
+# It also contains additional links and information.
+# See USER GUIDES -> C/C++ Development Guide and ReleaseNotes for EWARM:
+# version 6.30.8: http://supp.iar.com/FilesPublic/UPDINFO/006607/arm/doc/infocenter/index.ENU.html
+# version 7.60.1: http://supp.iar.com/FilesPublic/UPDINFO/011006/arm/doc/infocenter/index.ENU.html
+# version 8.10.1: http://netstorage.iar.com/SuppDB/Public/UPDINFO/011854/arm/doc/infocenter/index.ENU.html
+
+# The IAR internal compiler platform generations (Predefined symbol __IAR_SYSTEMS_ICC__):
+# 9 and higher means C11 and C++14 as language default (EWARM v8.x, EWRX v4.x and higher)
+# 8 means C99 and C++03 as language default (EWARM v6.x, v7.x. EWRX v2.x, 3.x)
+# 7 and lower means C89 and EC++ as language default. (EWARM v5.x and lower)
+
+# C/C++ Standard versions
+#
+# IAR typically only supports one C and C++ Standard version,
+# the exception is C89 which is always supported and can be selected
+# if its not the default
+#
+# C++ is trickier, there were historically 3 switches,
+# and some IAR versions support multiple of those.
+# they are --eec++, --ec++ and --c++ and where used to
+# enable various language features like exceptions
+#
+# recent versions only have --c++ for full support
+# but can choose to disable features with further arguments
+#
+# C/C++ Standard compliance
+#
+# IAR has 3 modes: default, strict and extended
+# the extended mode is needed for popular libraries like CMSIS
+#
+# "Silent" Operation
+#
+# this really is different to most programs I know.
+# nothing meaningful from the operation is lost, just some redundant
+# code and data size printouts (that can be inspected with common tools).
+
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+macro(__compiler_iar_ilink lang)
+ set(CMAKE_EXECUTABLE_SUFFIX ".elf")
+ set(CMAKE_${lang}_OUTPUT_EXTENSION ".o")
+ if (${lang} STREQUAL "C" OR ${lang} STREQUAL "CXX")
+ set(CMAKE_${lang}_COMPILE_OBJECT "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+ set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> --preprocess=cnl <PREPROCESSED_SOURCE>")
+ set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -lAH <ASSEMBLY_SOURCE> -o <OBJECT>.dummy")
+
+ set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-f ")
+ set(CMAKE_DEPFILE_FLAGS_${lang} "--dependencies=ns <DEP_FILE>")
+
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -r")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Ohz -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -Oh -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -Oh -r -DNDEBUG")
+ endif()
+
+ if (${lang} STREQUAL "ASM")
+ string(APPEND CMAKE_ASM_FLAGS_INIT " ")
+ string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -r")
+ string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+ string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG")
+ string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -r -DNDEBUG")
+ endif()
+
+ set(CMAKE_${lang}_LINK_EXECUTABLE "\"${CMAKE_IAR_LINKER}\" --silent <OBJECTS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
+ set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "\"${CMAKE_IAR_ARCHIVE}\" <TARGET> --create <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_CREATE "\"${CMAKE_IAR_ARCHIVE}\" <TARGET> --create <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_APPEND "\"${CMAKE_IAR_ARCHIVE}\" <TARGET> --replace <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_FINISH "")
+
+ set(CMAKE_LINKER "${CMAKE_IAR_LINKER}" CACHE FILEPATH "The IAR linker" FORCE)
+ set(CMAKE_AR "${CMAKE_IAR_ARCHIVE}" CACHE FILEPATH "The IAR archiver" FORCE)
+endmacro()
+
+macro(__compiler_iar_xlink lang)
+ set(CMAKE_EXECUTABLE_SUFFIX ".bin")
+ if (${lang} STREQUAL "C" OR ${lang} STREQUAL "CXX")
+
+ set(CMAKE_${lang}_COMPILE_OBJECT "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+ set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> --preprocess=cnl <PREPROCESSED_SOURCE>")
+ set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -lAH <ASSEMBLY_SOURCE> -o <OBJECT>.dummy")
+
+ set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-f ")
+ set(CMAKE_DEPFILE_FLAGS_${lang} "--dependencies=ns <DEP_FILE>")
+
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -r")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Ohz -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -Oh -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -Oh -r -DNDEBUG")
+ endif()
+
+ if (${lang} STREQUAL "ASM")
+ string(APPEND CMAKE_ASM_FLAGS_INIT " ")
+ string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -r")
+ string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+ string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG")
+ string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -r -DNDEBUG")
+ endif()
+
+ set(CMAKE_${lang}_LINK_EXECUTABLE "\"${CMAKE_IAR_LINKER}\" -S <OBJECTS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
+ set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "\"${CMAKE_IAR_AR}\" <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_CREATE "\"${CMAKE_IAR_AR}\" <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_APPEND "")
+ set(CMAKE_${lang}_ARCHIVE_FINISH "")
+
+ set(CMAKE_LIBRARY_PATH_FLAG "-I")
+
+ set(CMAKE_LINKER "${CMAKE_IAR_LINKER}" CACHE FILEPATH "The IAR linker" FORCE)
+ set(CMAKE_AR "${CMAKE_IAR_AR}" CACHE FILEPATH "The IAR archiver" FORCE)
+endmacro()
diff --git a/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake b/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake
new file mode 100644
index 0000000..899e284
--- /dev/null
+++ b/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake
@@ -0,0 +1,6 @@
+
+set(_compiler_id_version_compute "
+ /* __IBMC__ = VRP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__IBMC__/100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__IBMC__/10 % 10)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__IBMC__ % 10)")
diff --git a/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake b/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake
new file mode 100644
index 0000000..73aa2b4
--- /dev/null
+++ b/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake
@@ -0,0 +1,6 @@
+
+set(_compiler_id_version_compute "
+ /* __IBMCPP__ = VRP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__IBMCPP__/100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__IBMCPP__/10 % 10)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__IBMCPP__ % 10)")
diff --git a/Modules/Compiler/Intel-ASM.cmake b/Modules/Compiler/Intel-ASM.cmake
new file mode 100644
index 0000000..c2bf465
--- /dev/null
+++ b/Modules/Compiler/Intel-ASM.cmake
@@ -0,0 +1,12 @@
+include(Compiler/Intel)
+__compiler_intel(ASM)
+
+string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG")
+string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG")
+
+if(UNIX)
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;S)
+else()
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS asm)
+endif()
diff --git a/Modules/Compiler/Intel-C-FeatureTests.cmake b/Modules/Compiler/Intel-C-FeatureTests.cmake
new file mode 100644
index 0000000..5d09767
--- /dev/null
+++ b/Modules/Compiler/Intel-C-FeatureTests.cmake
@@ -0,0 +1,20 @@
+# References:
+# - https://software.intel.com/en-us/articles/iso-iec-standards-language-conformance-for-intel-c-compiler
+# - https://software.intel.com/en-us/articles/c99-support-in-intel-c-compiler
+# - https://software.intel.com/en-us/articles/c11-support-in-intel-c-compiler
+
+set(DETECT_C99 "defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L")
+set(DETECT_C11 "defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L")
+
+#static assert is only around in version 1500 update 2 and above
+set(_cmake_feature_test_c_static_assert "(__INTEL_COMPILER > 1500 || (__INTEL_COMPILER == 1500 && __INTEL_COMPILER_UPDATE > 1) ) && (${DETECT_C11} || ${DETECT_C99} && !defined(_MSC_VER))")
+
+set(_cmake_oldestSupported "__INTEL_COMPILER >= 1110")
+set(Intel_C99 "${_cmake_oldestSupported} && ${DETECT_C99}")
+set(_cmake_feature_test_c_restrict "${Intel_C99}")
+set(_cmake_feature_test_c_variadic_macros "${Intel_C99}")
+set(_cmake_feature_test_c_function_prototypes "${_cmake_oldestSupported}")
+unset(Intel_C99)
+
+unset(DETECT_C99)
+unset(DETECT_C11)
diff --git a/Modules/Compiler/Intel-C.cmake b/Modules/Compiler/Intel-C.cmake
new file mode 100644
index 0000000..ead9069
--- /dev/null
+++ b/Modules/Compiler/Intel-C.cmake
@@ -0,0 +1,60 @@
+include(Compiler/Intel)
+__compiler_intel(C)
+
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
+string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG")
+
+set(CMAKE_DEPFILE_FLAGS_C "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPFILE_FORMAT gcc)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
+
+ set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
+ set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
+
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 16.0.0)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-Qstd=c11")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-Qstd=c11")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+ endif()
+
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.0)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "-Qstd=c89")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-Qstd=c89")
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "-Qstd=c99")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-Qstd=c99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+ endif()
+
+else()
+
+ set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
+
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 15.0.0)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+ endif()
+
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.0)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c89")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu89")
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+ endif()
+
+endif()
+
+__compiler_check_default_language_standard(C 12.0 90 15.0.0 11)
+
+set(CMAKE_C_CREATE_PREPROCESSED_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+set(CMAKE_C_CREATE_ASSEMBLY_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
diff --git a/Modules/Compiler/Intel-CXX-FeatureTests.cmake b/Modules/Compiler/Intel-CXX-FeatureTests.cmake
new file mode 100644
index 0000000..bbefe15
--- /dev/null
+++ b/Modules/Compiler/Intel-CXX-FeatureTests.cmake
@@ -0,0 +1,111 @@
+# References:
+# - https://software.intel.com/en-us/articles/c0x-features-supported-by-intel-c-compiler
+# - https://software.intel.com/en-us/articles/c14-features-supported-by-intel-c-compiler
+# - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0096r3.html
+
+# Notes:
+# [1] Some Intel versions define some feature macros under -std=gnu++98
+# that do not work in that mode (or work with warnings):
+# - __cpp_attributes 200809
+# - __cpp_init_captures 201304
+# - __cpp_lambdas 200907
+# - __cpp_rvalue_references 200610
+# - __cpp_variadic_templates 200704
+
+set(_cmake_feature_test_cxx_variable_templates "__cpp_variable_templates >= 201304")
+
+set(_cmake_oldestSupported "__INTEL_COMPILER >= 1210")
+set(DETECT_CXX11 "((__cplusplus >= 201103L) || defined(__INTEL_CXX11_MODE__) || defined(__GXX_EXPERIMENTAL_CXX0X__))")
+#ICC version 15 update 1 has a bug where __cplusplus is defined as 1 no matter
+#if you are compiling as 98/11/14. So to properly detect C++14 with this version
+#we look for the existence of __GXX_EXPERIMENTAL_CXX0X__ but not __INTEL_CXX11_MODE__
+set(DETECT_BUGGY_ICC15 "((__INTEL_COMPILER == 1500) && (__INTEL_COMPILER_UPDATE == 1))")
+set(DETECT_CXX14 "((__cplusplus >= 201300L) || ((__cplusplus == 201103L) && !defined(__INTEL_CXX11_MODE__)) || ((${DETECT_BUGGY_ICC15}) && defined(__GXX_EXPERIMENTAL_CXX0X__) && !defined(__INTEL_CXX11_MODE__) ) || (defined(__INTEL_CXX11_MODE__) && defined(__cpp_aggregate_nsdmi)) )")
+unset(DETECT_BUGGY_ICC15)
+
+set(Intel17_CXX14 "__INTEL_COMPILER >= 1700 && ${DETECT_CXX14}")
+set(_cmake_feature_test_cxx_relaxed_constexpr "__cpp_constexpr >= 201304 || (${Intel17_CXX14} && !defined(_MSC_VER))")
+
+set(Intel16_CXX14 "__INTEL_COMPILER >= 1600 && ${DETECT_CXX14}")
+set(_cmake_feature_test_cxx_aggregate_default_initializers "${Intel16_CXX14}")
+set(_cmake_feature_test_cxx_contextual_conversions "${Intel16_CXX14}")
+set(_cmake_feature_test_cxx_generic_lambdas "__cpp_generic_lambdas >= 201304")
+set(_cmake_feature_test_cxx_digit_separators "${Intel16_CXX14}")
+unset(Intel16_CXX14)
+
+set(Intel15 "__INTEL_COMPILER >= 1500")
+set(Intel15_CXX14 "${Intel15} && ${DETECT_CXX14}")
+set(_cmake_feature_test_cxx_decltype_auto "__cpp_decltype_auto >= 201304 || ${Intel15_CXX14}")
+set(_cmake_feature_test_cxx_lambda_init_captures "(__cpp_init_captures >= 201304 || ${Intel15}) && ${DETECT_CXX14}") # [1]
+set(_cmake_feature_test_cxx_attribute_deprecated "${Intel15_CXX14}")
+set(_cmake_feature_test_cxx_return_type_deduction "__cpp_return_type_deduction >= 201304 || ${Intel15_CXX14}")
+unset(Intel15_CXX14)
+unset(Intel15)
+
+set(Intel15_CXX11 "__INTEL_COMPILER >= 1500 && ${DETECT_CXX11}")
+set(_cmake_feature_test_cxx_alignas "${Intel15_CXX11}")
+set(_cmake_feature_test_cxx_alignof "${Intel15_CXX11}")
+set(_cmake_feature_test_cxx_inheriting_constructors "${Intel15_CXX11}")
+set(_cmake_feature_test_cxx_user_literals "__cpp_user_defined_literals >= 200809 || (${Intel15_CXX11} && (!defined(_MSC_VER) || __INTEL_COMPILER >= 1600))")
+set(_cmake_feature_test_cxx_thread_local "${Intel15_CXX11}")
+unset(Intel15_CXX11)
+
+set(Intel14_CXX11 "${DETECT_CXX11} && (__INTEL_COMPILER > 1400 || (__INTEL_COMPILER == 1400 && __INTEL_COMPILER_UPDATE >= 2))")
+# Documented as 12.0+ but in testing it only works on 14.0.2+
+set(_cmake_feature_test_cxx_decltype_incomplete_return_types "${Intel14_CXX11} && !defined(_MSC_VER)")
+
+set(Intel14_CXX11 "__INTEL_COMPILER >= 1400 && ${DETECT_CXX11}")
+set(_cmake_feature_test_cxx_delegating_constructors "${Intel14_CXX11}")
+set(_cmake_feature_test_cxx_constexpr "__cpp_constexpr >= 200704 || ${Intel14_CXX11}")
+set(_cmake_feature_test_cxx_sizeof_member "${Intel14_CXX11}")
+set(_cmake_feature_test_cxx_strong_enums "${Intel14_CXX11}")
+set(_cmake_feature_test_cxx_reference_qualified_functions "${Intel14_CXX11}")
+set(_cmake_feature_test_cxx_raw_string_literals "__cpp_raw_strings >= 200710 || ${Intel14_CXX11}")
+set(_cmake_feature_test_cxx_unicode_literals "__cpp_unicode_literals >= 200710 || (${Intel14_CXX11} && (!defined(_MSC_VER) || __INTEL_COMPILER >= 1600))")
+set(_cmake_feature_test_cxx_inline_namespaces "${Intel14_CXX11}")
+set(_cmake_feature_test_cxx_unrestricted_unions "${Intel14_CXX11}")
+set(_cmake_feature_test_cxx_nonstatic_member_init "${Intel14_CXX11}")
+set(_cmake_feature_test_cxx_enum_forward_declarations "${Intel14_CXX11}")
+set(_cmake_feature_test_cxx_override "${Intel14_CXX11}")
+set(_cmake_feature_test_cxx_final "${Intel14_CXX11}")
+set(_cmake_feature_test_cxx_noexcept "${Intel14_CXX11}")
+set(_cmake_feature_test_cxx_defaulted_move_initializers "${Intel14_CXX11}")
+set(_cmake_feature_test_cxx_generalized_initializers "${Intel14_CXX11}")
+unset(Intel14_CXX11)
+
+set(Intel13_CXX11 "__INTEL_COMPILER >= 1300 && ${DETECT_CXX11}")
+set(_cmake_feature_test_cxx_explicit_conversions "${Intel13_CXX11}")
+set(_cmake_feature_test_cxx_range_for "${Intel13_CXX11}")
+# Cannot find Intel documentation for N2640: cxx_uniform_initialization
+set(_cmake_feature_test_cxx_uniform_initialization "${Intel13_CXX11}")
+unset(Intel13_CXX11)
+
+set(Intel121 "${_cmake_oldestSupported}")
+set(Intel121_CXX11 "${Intel121} && ${DETECT_CXX11}")
+set(_cmake_feature_test_cxx_variadic_templates "(__cpp_variadic_templates >= 200704 || ${Intel121}) && ${DETECT_CXX11}") # [1]
+set(_cmake_feature_test_cxx_alias_templates "${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_nullptr "${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_trailing_return_types "${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_attributes "(__cpp_attributes >= 200809 || ${Intel121}) && ${DETECT_CXX11}") # [1]
+set(_cmake_feature_test_cxx_default_function_template_args "${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_extended_friend_declarations "${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_rvalue_references "(__cpp_rvalue_references >= 200610 || ${Intel121}) && ${DETECT_CXX11}") # [1]
+set(_cmake_feature_test_cxx_decltype "__cpp_decltype >= 200707 || ${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_defaulted_functions "${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_deleted_functions "${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_local_type_template_args "${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_lambdas "(__cpp_lambdas >= 200907 || ${Intel121}) && ${DETECT_CXX11}") # [1]
+set(_cmake_feature_test_cxx_binary_literals "__cpp_binary_literals >= 201304 || ${Intel121}")
+set(_cmake_feature_test_cxx_static_assert "(__cpp_static_assert >= 200410 || ${Intel121}) && ${DETECT_CXX11}")
+set(_cmake_feature_test_cxx_right_angle_brackets "${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_auto_type "${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_extern_templates "${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_variadic_macros "${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_long_long_type "${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_func_identifier "${Intel121_CXX11}")
+set(_cmake_feature_test_cxx_template_template_parameters "${Intel121_CXX11}")
+unset(Intel121_CXX11)
+unset(Intel121)
+
+unset(DETECT_CXX11)
+unset(DETECT_CXX14)
diff --git a/Modules/Compiler/Intel-CXX.cmake b/Modules/Compiler/Intel-CXX.cmake
new file mode 100644
index 0000000..37f339a
--- /dev/null
+++ b/Modules/Compiler/Intel-CXX.cmake
@@ -0,0 +1,104 @@
+include(Compiler/Intel)
+__compiler_intel(CXX)
+
+string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -DNDEBUG")
+string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG")
+
+set(CMAKE_DEPFILE_FLAGS_CXX "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+
+ set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
+
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0.0)
+ set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-Qstd=c++20")
+ set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-Qstd=c++20")
+ endif()
+
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0.0)
+ set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-Qstd=c++17")
+ set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-Qstd=c++17")
+ endif()
+
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0)
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-Qstd=c++14")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-Qstd=c++14")
+ endif()
+
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0)
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-Qstd=c++11")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-Qstd=c++11")
+ elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-Qstd=c++0x")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-Qstd=c++0x")
+ endif()
+
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+ endif()
+
+else()
+
+ set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
+
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0.0)
+ set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std=c++20")
+ set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std=gnu++20")
+ endif()
+
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0.0)
+ set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++17")
+ set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17")
+ endif()
+
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 17.0)
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+ endif()
+
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.2)
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14")
+ elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.0)
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++1y")
+ endif()
+
+ # Intel 15.0.2 accepts c++14 instead of c++1y, but not gnu++14
+ # instead of gnu++1y. Intel 17.0.0 accepts gnu++14 too.
+ if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 17.0)
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14")
+ elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.0)
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y")
+ endif()
+
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0)
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+ endif()
+
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0)
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+ elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++0x")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++0x")
+ endif()
+
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+ endif()
+
+endif()
+
+__compiler_check_default_language_standard(CXX 12.1 98)
+
+set(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+set(CMAKE_CXX_CREATE_ASSEMBLY_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
diff --git a/Modules/Compiler/Intel-DetermineCompiler.cmake b/Modules/Compiler/Intel-DetermineCompiler.cmake
new file mode 100644
index 0000000..c31aa77
--- /dev/null
+++ b/Modules/Compiler/Intel-DetermineCompiler.cmake
@@ -0,0 +1,40 @@
+
+set(_compiler_id_pp_test "defined(__INTEL_COMPILER) || defined(__ICC)")
+
+set(_compiler_id_version_compute "
+ /* __INTEL_COMPILER = VRP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__INTEL_COMPILER/100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__INTEL_COMPILER/10 % 10)
+# if defined(__INTEL_COMPILER_UPDATE)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__INTEL_COMPILER_UPDATE)
+# else
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__INTEL_COMPILER % 10)
+# endif
+# if defined(__INTEL_COMPILER_BUILD_DATE)
+ /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */
+# define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(__INTEL_COMPILER_BUILD_DATE)
+# endif
+# if defined(_MSC_VER)
+ /* _MSC_VER = VVRR */
+# define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(_MSC_VER / 100)
+# define @PREFIX@SIMULATE_VERSION_MINOR @MACRO_DEC@(_MSC_VER % 100)
+# endif
+# if defined(__GNUC__)
+# define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(__GNUC__)
+# elif defined(__GNUG__)
+# define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(__GNUG__)
+# endif
+# if defined(__GNUC_MINOR__)
+# define @PREFIX@SIMULATE_VERSION_MINOR @MACRO_DEC@(__GNUC_MINOR__)
+# endif
+# if defined(__GNUC_PATCHLEVEL__)
+# define @PREFIX@SIMULATE_VERSION_PATCH @MACRO_DEC@(__GNUC_PATCHLEVEL__)
+# endif")
+
+set(_compiler_id_simulate "
+# if defined(_MSC_VER)
+# define @PREFIX@SIMULATE_ID \"MSVC\"
+# endif
+# if defined(__GNUC__)
+# define @PREFIX@SIMULATE_ID \"GNU\"
+# endif")
diff --git a/Modules/Compiler/Intel-Fortran.cmake b/Modules/Compiler/Intel-Fortran.cmake
new file mode 100644
index 0000000..9fb6d46
--- /dev/null
+++ b/Modules/Compiler/Intel-Fortran.cmake
@@ -0,0 +1,27 @@
+include(Compiler/Intel)
+__compiler_intel(Fortran)
+
+set(CMAKE_Fortran_SUBMODULE_SEP "@")
+set(CMAKE_Fortran_SUBMODULE_EXT ".smod")
+
+set(CMAKE_Fortran_MODDIR_FLAG "-module ")
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-fixed")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-free")
+
+set(CMAKE_Fortran_COMPILE_WITH_DEFINES 1)
+
+set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+
+if(CMAKE_HOST_WIN32)
+ # MSVC-like
+ set(CMAKE_Fortran_PREPROCESS_SOURCE
+ "<CMAKE_Fortran_COMPILER> -fpp <DEFINES> <INCLUDES> <FLAGS> -P <SOURCE> -Fi<PREPROCESSED_SOURCE>")
+else()
+ # GNU-like
+ set(CMAKE_Fortran_PREPROCESS_SOURCE
+ "<CMAKE_Fortran_COMPILER> -fpp <DEFINES> <INCLUDES> <FLAGS> -P <SOURCE> -o <PREPROCESSED_SOURCE>")
+endif()
+
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-fpp")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nofpp")
diff --git a/Modules/Compiler/Intel-ISPC.cmake b/Modules/Compiler/Intel-ISPC.cmake
new file mode 100644
index 0000000..be64cf7
--- /dev/null
+++ b/Modules/Compiler/Intel-ISPC.cmake
@@ -0,0 +1,26 @@
+include(Compiler/CMakeCommonCompilerMacros)
+
+# Not aware of any verbose flag for ISPC
+#set(CMAKE_ISPC_VERBOSE_FLAG )
+
+set(CMAKE_DEPFILE_FLAGS_ISPC "-M -MT <DEP_TARGET> -MF <DEP_FILE>")
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ # dependencies are computed by the compiler itself
+ set(CMAKE_ISPC_DEPFILE_FORMAT gcc)
+ set(CMAKE_ISPC_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+string(APPEND CMAKE_ISPC_FLAGS_INIT " ")
+string(APPEND CMAKE_ISPC_FLAGS_DEBUG_INIT "-O0 -g")
+string(APPEND CMAKE_ISPC_FLAGS_RELEASE_INIT " -O3 -DNDEBUG")
+string(APPEND CMAKE_ISPC_FLAGS_MINSIZEREL_INIT " -O1 -DNDEBUG")
+string(APPEND CMAKE_ISPC_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG")
+
+set(CMAKE_ISPC_COMPILE_OPTIONS_PIE --pic)
+set(CMAKE_ISPC_COMPILE_OPTIONS_PIC --pic)
+
+set(CMAKE_ISPC_RESPONSE_FILE_FLAG "@")
+set(CMAKE_ISPC_USE_RESPONSE_FILE_FOR_INCLUDES 1)
+set(CMAKE_ISPC_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
+set(CMAKE_ISPC_USE_RESPONSE_FILE_FOR_OBJECTS 1)
diff --git a/Modules/Compiler/Intel.cmake b/Modules/Compiler/Intel.cmake
new file mode 100644
index 0000000..9a760c8
--- /dev/null
+++ b/Modules/Compiler/Intel.cmake
@@ -0,0 +1,46 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_INTEL)
+ return()
+endif()
+set(__COMPILER_INTEL 1)
+
+include(Compiler/CMakeCommonCompilerMacros)
+
+if(CMAKE_HOST_WIN32)
+ # MSVC-like
+ macro(__compiler_intel lang)
+ endmacro()
+else()
+ # GNU-like
+ macro(__compiler_intel lang)
+ set(CMAKE_${lang}_VERBOSE_FLAG "-v")
+
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
+
+ set(CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "${CMAKE_${lang}_COMPILER}")
+ if(CMAKE_${lang}_COMPILER_ARG1)
+ separate_arguments(_COMPILER_ARGS NATIVE_COMMAND "${CMAKE_${lang}_COMPILER_ARG1}")
+ list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND ${_COMPILER_ARGS})
+ unset(_COMPILER_ARGS)
+ endif()
+ list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "-QdM" "-P" "-Za" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp")
+
+ if(NOT "x${lang}" STREQUAL "xFortran")
+ # Precompile Headers
+ set(CMAKE_PCH_EXTENSION .pchi)
+ set(CMAKE_LINK_PCH ON)
+ set(CMAKE_PCH_EPILOGUE "#pragma hdrstop")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_INVALID_PCH -Winvalid-pch)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Wno-pch-messages -pch-use <PCH_FILE> -include <PCH_HEADER>)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Wno-pch-messages -pch-create <PCH_FILE> -include <PCH_HEADER>)
+ endif()
+ endmacro()
+endif()
diff --git a/Modules/Compiler/IntelLLVM-ASM.cmake b/Modules/Compiler/IntelLLVM-ASM.cmake
new file mode 100644
index 0000000..c258a0a
--- /dev/null
+++ b/Modules/Compiler/IntelLLVM-ASM.cmake
@@ -0,0 +1,12 @@
+include(Compiler/IntelLLVM)
+__compiler_intel_llvm(ASM)
+
+string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG")
+string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG")
+
+if(UNIX)
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;S)
+else()
+ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS asm)
+endif()
diff --git a/Modules/Compiler/IntelLLVM-C.cmake b/Modules/Compiler/IntelLLVM-C.cmake
new file mode 100644
index 0000000..beb7132
--- /dev/null
+++ b/Modules/Compiler/IntelLLVM-C.cmake
@@ -0,0 +1,62 @@
+include(Compiler/IntelLLVM)
+__compiler_intel_llvm(C)
+
+if("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+ set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
+ set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+ endif()
+else()
+ set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPFILE_FORMAT gcc)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+ endif()
+
+ string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+ string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
+ string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG")
+endif()
+
+set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+
+if(NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
+
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+
+ set(CMAKE_C17_STANDARD_COMPILE_OPTION "-std=c17")
+ set(CMAKE_C17_EXTENSION_COMPILE_OPTION "-std=gnu17")
+else()
+ # clang-cl doesn't have any of these
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "")
+
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "")
+
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "")
+
+ set(CMAKE_C17_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C17_EXTENSION_COMPILE_OPTION "")
+endif()
+
+if(NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
+ __compiler_check_default_language_standard(C 2020 17)
+else()
+ set(CMAKE_C_STANDARD_DEFAULT "")
+endif()
diff --git a/Modules/Compiler/IntelLLVM-CXX.cmake b/Modules/Compiler/IntelLLVM-CXX.cmake
new file mode 100644
index 0000000..4c0c26e
--- /dev/null
+++ b/Modules/Compiler/IntelLLVM-CXX.cmake
@@ -0,0 +1,69 @@
+include(Compiler/IntelLLVM)
+__compiler_intel_llvm(CXX)
+
+if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+ set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TP)
+ set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+ endif()
+else()
+ set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+ endif()
+
+ set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
+
+ string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+ string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -DNDEBUG")
+ string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG")
+endif()
+
+set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+
+if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14")
+
+ set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++17")
+ set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17")
+
+ set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std=c++20")
+ set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std=gnu++20")
+else()
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-Qstd=c++11")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-Qstd=c++11")
+
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-Qstd=c++14")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-Qstd=c++14")
+
+ set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-Qstd=c++17")
+ set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-Qstd=c++17")
+
+ set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-Qstd=c++20")
+ set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-Qstd=c++20")
+endif()
+
+if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ __compiler_check_default_language_standard(CXX 2020 14)
+else()
+ set(CMAKE_CXX_STANDARD_DEFAULT "")
+endif()
diff --git a/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake b/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake
new file mode 100644
index 0000000..124dafe
--- /dev/null
+++ b/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake
@@ -0,0 +1,41 @@
+
+set(_compiler_id_pp_test "(defined(__clang__) && defined(__INTEL_CLANG_COMPILER)) || defined(__INTEL_LLVM_COMPILER)")
+
+set(_compiler_id_version_compute "
+/* __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and
+ * later. Look for 6 digit vs. 8 digit version number to decide encoding.
+ * VVVV is no smaller than the current year when a versio is released.
+ */
+#if __INTEL_LLVM_COMPILER < 1000000L
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__INTEL_LLVM_COMPILER/100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__INTEL_LLVM_COMPILER/10 % 10)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__INTEL_LLVM_COMPILER % 10)
+#else
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__INTEL_LLVM_COMPILER/10000)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__INTEL_LLVM_COMPILER/100 % 100)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__INTEL_LLVM_COMPILER % 100)
+#endif
+#if defined(_MSC_VER)
+ /* _MSC_VER = VVRR */
+# define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(_MSC_VER / 100)
+# define @PREFIX@SIMULATE_VERSION_MINOR @MACRO_DEC@(_MSC_VER % 100)
+#endif
+#if defined(__GNUC__)
+# define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(__GNUC__)
+#elif defined(__GNUG__)
+# define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(__GNUG__)
+#endif
+#if defined(__GNUC_MINOR__)
+# define @PREFIX@SIMULATE_VERSION_MINOR @MACRO_DEC@(__GNUC_MINOR__)
+#endif
+#if defined(__GNUC_PATCHLEVEL__)
+# define @PREFIX@SIMULATE_VERSION_PATCH @MACRO_DEC@(__GNUC_PATCHLEVEL__)
+#endif")
+
+set(_compiler_id_simulate "
+#if defined(_MSC_VER)
+# define @PREFIX@SIMULATE_ID \"MSVC\"
+#endif
+#if defined(__GNUC__)
+# define @PREFIX@SIMULATE_ID \"GNU\"
+#endif")
diff --git a/Modules/Compiler/IntelLLVM-Fortran.cmake b/Modules/Compiler/IntelLLVM-Fortran.cmake
new file mode 100644
index 0000000..710803f
--- /dev/null
+++ b/Modules/Compiler/IntelLLVM-Fortran.cmake
@@ -0,0 +1,27 @@
+include(Compiler/IntelLLVM)
+__compiler_intel_llvm(Fortran)
+
+set(CMAKE_Fortran_SUBMODULE_SEP "@")
+set(CMAKE_Fortran_SUBMODULE_EXT ".smod")
+
+set(CMAKE_Fortran_MODDIR_FLAG "-module ")
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-fixed")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-free")
+
+set(CMAKE_Fortran_COMPILE_WITH_DEFINES 1)
+
+set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+
+if(CMAKE_HOST_WIN32)
+ # MSVC-like
+ set(CMAKE_Fortran_PREPROCESS_SOURCE
+ "<CMAKE_Fortran_COMPILER> -fpp <DEFINES> <INCLUDES> <FLAGS> -P <SOURCE> -Fi<PREPROCESSED_SOURCE>")
+else()
+ # GNU-like
+ set(CMAKE_Fortran_PREPROCESS_SOURCE
+ "<CMAKE_Fortran_COMPILER> -fpp <DEFINES> <INCLUDES> <FLAGS> -P <SOURCE> -o <PREPROCESSED_SOURCE>")
+endif()
+
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-fpp")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nofpp")
diff --git a/Modules/Compiler/IntelLLVM.cmake b/Modules/Compiler/IntelLLVM.cmake
new file mode 100644
index 0000000..14b7ad8
--- /dev/null
+++ b/Modules/Compiler/IntelLLVM.cmake
@@ -0,0 +1,92 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_LLVM_INTEL)
+ return()
+endif()
+set(__COMPILER_LLVM_INTEL 1)
+
+include(Compiler/CMakeCommonCompilerMacros)
+
+set(__pch_header_C "c-header")
+set(__pch_header_CXX "c++-header")
+set(__pch_header_OBJC "objective-c-header")
+set(__pch_header_OBJCXX "objective-c++-header")
+
+if(CMAKE_HOST_WIN32)
+ # MSVC-like
+ macro(__compiler_intel_llvm lang)
+ if(NOT "x${lang}" STREQUAL "xFortran")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_INVALID_PCH -Winvalid-pch)
+ endif()
+ endmacro()
+else()
+ # GNU-like
+ macro(__compiler_intel_llvm lang)
+ set(CMAKE_${lang}_VERBOSE_FLAG "-v")
+
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
+
+ set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER YES)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
+ set(CMAKE_${lang}_LINK_OPTIONS_PIE ${CMAKE_${lang}_COMPILE_OPTIONS_PIE} "-pie")
+ set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE "-no-pie")
+
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
+
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
+ # distcc does not transform -o to -MT when invoking the preprocessor
+ # internally, as it ought to. Work around this bug by setting -MT here
+ # even though it isn't strictly necessary.
+ set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+
+ set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-isystem ")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_TARGET "--target=")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_SYSROOT "--sysroot=")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN "--gcc-toolchain=")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP)
+
+ set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
+ set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto=thin")
+ set(CMAKE_${lang}_ARCHIVE_CREATE_IPO "\"${CMAKE_${lang}_COMPILER_AR}\" cr <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_APPEND_IPO "\"${CMAKE_${lang}_COMPILER_AR}\" r <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_FINISH_IPO "\"${CMAKE_${lang}_COMPILER_RANLIB}\" <TARGET>")
+
+ set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+ set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+
+ set(CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "${CMAKE_${lang}_COMPILER}")
+ if(CMAKE_${lang}_COMPILER_ARG1)
+ separate_arguments(_COMPILER_ARGS NATIVE_COMMAND "${CMAKE_${lang}_COMPILER_ARG1}")
+ list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND ${_COMPILER_ARGS})
+ unset(_COMPILER_ARGS)
+ endif()
+ list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "-dM" "-E" "-c" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp")
+ if(CMAKE_${lang}_COMPILER_TARGET)
+ list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "--target=${CMAKE_${lang}_COMPILER_TARGET}")
+ endif()
+
+ if(NOT "x${lang}" STREQUAL "xFortran")
+ # Precompile Headers
+ set(CMAKE_PCH_EXTENSION .pch)
+ set(CMAKE_PCH_PROLOGUE "#pragma clang system_header")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_INSTANTIATE_TEMPLATES_PCH -fpch-instantiate-templates)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_INVALID_PCH -Winvalid-pch)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE> -Xclang -include -Xclang <PCH_HEADER>)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Xclang -emit-pch -Xclang -include -Xclang <PCH_HEADER> -x ${__pch_header_${lang}})
+ endif()
+ endmacro()
+endif()
diff --git a/Modules/Compiler/MSVC-ASM.cmake b/Modules/Compiler/MSVC-ASM.cmake
new file mode 100644
index 0000000..45978c5
--- /dev/null
+++ b/Modules/Compiler/MSVC-ASM.cmake
@@ -0,0 +1 @@
+# This file is loaded when Visual Studio is used for the ASM language.
diff --git a/Modules/Compiler/MSVC-C-FeatureTests.cmake b/Modules/Compiler/MSVC-C-FeatureTests.cmake
new file mode 100644
index 0000000..4024c12
--- /dev/null
+++ b/Modules/Compiler/MSVC-C-FeatureTests.cmake
@@ -0,0 +1,7 @@
+set(_cmake_oldestSupported "_MSC_VER >= 1600")
+
+set(_cmake_feature_test_c_restrict "_MSC_VER >= 1927")
+set(_cmake_feature_test_c_static_assert "_MSC_VER >= 1928")
+
+set(_cmake_feature_test_c_variadic_macros "${_cmake_oldestSupported}")
+set(_cmake_feature_test_c_function_prototypes "${_cmake_oldestSupported}")
diff --git a/Modules/Compiler/MSVC-C.cmake b/Modules/Compiler/MSVC-C.cmake
new file mode 100644
index 0000000..9a5104b
--- /dev/null
+++ b/Modules/Compiler/MSVC-C.cmake
@@ -0,0 +1,65 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Compiler/CMakeCommonCompilerMacros)
+
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.27)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std:c11")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std:c11")
+
+ __compiler_check_default_language_standard(C 19.27 99)
+else()
+ # MSVC has no specific options to set C language standards, but set them as
+ # empty strings anyways so the feature test infrastructure can at least check
+ # to see if they are defined.
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "")
+
+ # There is no meaningful default for this
+ set(CMAKE_C_STANDARD_DEFAULT "")
+endif()
+
+set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
+set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
+
+# There are no C compiler modes so we hard-code the known compiler supported
+# features. Override the default macro for this special case. Pretend that
+# all language standards are available so that at least compilation
+# can be attempted.
+macro(cmake_record_c_compile_features)
+ list(APPEND CMAKE_C_COMPILE_FEATURES
+ c_std_90
+ c_std_99
+ c_std_11
+ c_function_prototypes
+ )
+ list(APPEND CMAKE_C90_COMPILE_FEATURES c_std_90 c_function_prototypes)
+ list(APPEND CMAKE_C99_COMPILE_FEATURES c_std_99)
+ list(APPEND CMAKE_C11_COMPILE_FEATURES c_std_11)
+ if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 14.0)
+ list(APPEND CMAKE_C_COMPILE_FEATURES c_variadic_macros)
+ list(APPEND CMAKE_C99_COMPILE_FEATURES c_variadic_macros)
+ endif()
+ if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.27)
+ list(APPEND CMAKE_C_COMPILE_FEATURES c_restrict)
+ list(APPEND CMAKE_C99_COMPILE_FEATURES c_restrict)
+ endif()
+ if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.28)
+ list(APPEND CMAKE_C_COMPILE_FEATURES c_static_assert)
+ list(APPEND CMAKE_C11_COMPILE_FEATURES c_static_assert)
+ endif()
+ set(_result 0) # expected by cmake_determine_compile_features
+endmacro()
+
+# /JMC "Just My Code" is only supported by MSVC 19.05 onward.
+if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
+ set(CMAKE_C_COMPILE_OPTIONS_JMC "-JMC")
+endif()
diff --git a/Modules/Compiler/MSVC-CXX-FeatureTests.cmake b/Modules/Compiler/MSVC-CXX-FeatureTests.cmake
new file mode 100644
index 0000000..125974a
--- /dev/null
+++ b/Modules/Compiler/MSVC-CXX-FeatureTests.cmake
@@ -0,0 +1,109 @@
+# Reference: https://docs.microsoft.com/en-us/cpp/visual-cpp-language-conformance
+# https://blogs.msdn.microsoft.com/vcblog/2015/06/19/c111417-features-in-vs-2015-rtm/
+# https://blogs.msdn.microsoft.com/vcblog/2013/12/02/c1114-core-language-features-in-vs-2013-and-the-nov-2013-ctp/
+# https://blogs.msdn.microsoft.com/vcblog/2011/09/12/c11-features-in-visual-c-11/
+
+set(_cmake_oldestSupported "_MSC_VER >= 1600")
+
+# VS 2017 v15.3 fixes support for incomplete decltypes
+# https://docs.microsoft.com/en-us/cpp/cpp-conformance-improvements-2017#update_153
+set(_cmake_feature_test_cxx_decltype_incomplete_return_types "_MSC_VER >= 1911")
+
+# VS 2017 v15.3 fixes support for "N3652 Extended constexpr"
+set(_cmake_feature_test_cxx_relaxed_constexpr "_MSC_VER >= 1911")
+
+# VS 2017 Preview introduces support for aggregate initializers.
+set(_cmake_feature_test_cxx_aggregate_default_initializers "_MSC_FULL_VER >= 190024406")
+
+# VS 2015 Update 2 introduces support for variable templates.
+# https://www.visualstudio.com/en-us/news/vs2015-update2-vs.aspx
+set(_cmake_feature_test_cxx_variable_templates "_MSC_FULL_VER >= 190023918")
+
+set(MSVC_2015 "_MSC_VER >= 1900")
+set(_cmake_feature_test_cxx_alignas "${MSVC_2015}")
+set(_cmake_feature_test_cxx_alignof "${MSVC_2015}")
+set(_cmake_feature_test_cxx_attributes "${MSVC_2015}")
+set(_cmake_feature_test_cxx_attribute_deprecated "${MSVC_2015}")
+set(_cmake_feature_test_cxx_binary_literals "${MSVC_2015}")
+set(_cmake_feature_test_cxx_constexpr "${MSVC_2015}")
+set(_cmake_feature_test_cxx_decltype_auto "${MSVC_2015}")
+set(_cmake_feature_test_cxx_digit_separators "${MSVC_2015}")
+set(_cmake_feature_test_cxx_func_identifier "${MSVC_2015}")
+set(_cmake_feature_test_cxx_nonstatic_member_init "${MSVC_2015}")
+# Microsoft calls this 'rvalue references v3'
+set(_cmake_feature_test_cxx_defaulted_move_initializers "${MSVC_2015}")
+set(_cmake_feature_test_cxx_generic_lambdas "${MSVC_2015}")
+set(_cmake_feature_test_cxx_inheriting_constructors "${MSVC_2015}")
+set(_cmake_feature_test_cxx_inline_namespaces "${MSVC_2015}")
+set(_cmake_feature_test_cxx_lambda_init_captures "${MSVC_2015}")
+set(_cmake_feature_test_cxx_noexcept "${MSVC_2015}")
+set(_cmake_feature_test_cxx_return_type_deduction "${MSVC_2015}")
+set(_cmake_feature_test_cxx_sizeof_member "${MSVC_2015}")
+set(_cmake_feature_test_cxx_thread_local "${MSVC_2015}")
+set(_cmake_feature_test_cxx_unicode_literals "${MSVC_2015}")
+set(_cmake_feature_test_cxx_unrestricted_unions "${MSVC_2015}")
+set(_cmake_feature_test_cxx_user_literals "${MSVC_2015}")
+set(_cmake_feature_test_cxx_reference_qualified_functions "${MSVC_2015}")
+# "The copies and moves don't interact precisely like the Standard says they
+# should. For example, deletion of moves is specified to also suppress
+# copies, but Visual C++ in Visual Studio 2013 does not."
+# http://blogs.msdn.com/b/vcblog/archive/2014/11/17/c-11-14-17-features-in-vs-2015-preview.aspx
+# lists this as 'partial' in 2013
+set(_cmake_feature_test_cxx_deleted_functions "${MSVC_2015}")
+
+# http://blogs.msdn.com/b/vcblog/archive/2014/11/17/c-11-14-17-features-in-vs-2015-preview.aspx
+# Note 1. While previous version of VisualStudio said they supported these
+# they silently produced bad code, and are now marked as having partial
+# support in previous versions. The footnote says the support will be complete
+# in MSVC 2015, so support the feature for that version, assuming that is true.
+# The blog post also says that VS 2013 Update 3 generates an error in cases
+# that previously produced bad code.
+set(_cmake_feature_test_cxx_generalized_initializers "_MSC_FULL_VER >= 180030723")
+
+set(MSVC_2013 "_MSC_VER >= 1800")
+set(_cmake_feature_test_cxx_alias_templates "${MSVC_2013}")
+# Microsoft now states they support contextual conversions in 2013 and above.
+# See footnote 6 at:
+# http://blogs.msdn.com/b/vcblog/archive/2014/11/17/c-11-14-17-features-in-vs-2015-preview.aspx
+set(_cmake_feature_test_cxx_contextual_conversions "${MSVC_2013}")
+set(_cmake_feature_test_cxx_default_function_template_args "${MSVC_2013}")
+set(_cmake_feature_test_cxx_defaulted_functions "${MSVC_2013}")
+set(_cmake_feature_test_cxx_delegating_constructors "${MSVC_2013}")
+set(_cmake_feature_test_cxx_explicit_conversions "${MSVC_2013}")
+set(_cmake_feature_test_cxx_raw_string_literals "${MSVC_2013}")
+set(_cmake_feature_test_cxx_uniform_initialization "${MSVC_2013}")
+# Support is documented, but possibly partly broken:
+# https://msdn.microsoft.com/en-us/library/hh567368.aspx
+# http://thread.gmane.org/gmane.comp.lib.boost.devel/244986/focus=245333
+set(_cmake_feature_test_cxx_variadic_templates "${MSVC_2013}")
+
+set(MSVC_2012 "_MSC_VER >= 1700")
+set(_cmake_feature_test_cxx_enum_forward_declarations "${MSVC_2012}")
+set(_cmake_feature_test_cxx_final "${MSVC_2012}")
+set(_cmake_feature_test_cxx_range_for "${MSVC_2012}")
+set(_cmake_feature_test_cxx_strong_enums "${MSVC_2012}")
+
+set(MSVC_2010 "_MSC_VER >= 1600")
+set(_cmake_feature_test_cxx_auto_type "${MSVC_2010}")
+set(_cmake_feature_test_cxx_decltype "${MSVC_2010}")
+set(_cmake_feature_test_cxx_extended_friend_declarations "${MSVC_2010}")
+set(_cmake_feature_test_cxx_extern_templates "${MSVC_2010}")
+set(_cmake_feature_test_cxx_lambdas "${MSVC_2010}")
+set(_cmake_feature_test_cxx_local_type_template_args "${MSVC_2010}")
+set(_cmake_feature_test_cxx_long_long_type "${MSVC_2010}")
+set(_cmake_feature_test_cxx_nullptr "${MSVC_2010}")
+set(_cmake_feature_test_cxx_override "${MSVC_2010}")
+set(_cmake_feature_test_cxx_right_angle_brackets "${MSVC_2010}")
+set(_cmake_feature_test_cxx_rvalue_references "${MSVC_2010}")
+set(_cmake_feature_test_cxx_static_assert "${MSVC_2010}")
+set(_cmake_feature_test_cxx_template_template_parameters "${MSVC_2010}")
+set(_cmake_feature_test_cxx_trailing_return_types "${MSVC_2010}")
+set(_cmake_feature_test_cxx_variadic_macros "${MSVC_2010}")
+
+# Unset all the variables that we don't need exposed.
+# _cmake_oldestSupported is required by WriteCompilerDetectionHeader
+set(MSVC_2017)
+set(MSVC_2015)
+set(MSVC_2013)
+set(MSVC_2012)
+set(MSVC_2010)
diff --git a/Modules/Compiler/MSVC-CXX.cmake b/Modules/Compiler/MSVC-CXX.cmake
new file mode 100644
index 0000000..1dfc760
--- /dev/null
+++ b/Modules/Compiler/MSVC-CXX.cmake
@@ -0,0 +1,74 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Compiler/CMakeCommonCompilerMacros)
+
+set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
+
+if ((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.0.24215.1 AND
+ CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) OR
+ CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.10.25017)
+
+ # VS 2015 Update 3 and above support language standard level flags,
+ # with the default and minimum level being C++14.
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std:c++14")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std:c++14")
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.11.25505)
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std:c++17")
+ set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std:c++17")
+ else()
+ set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std:c++latest")
+ set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std:c++latest")
+ endif()
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.12.25835)
+ set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std:c++latest")
+ set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std:c++latest")
+ endif()
+
+ __compiler_check_default_language_standard(CXX 19.0 14)
+
+elseif (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)
+ # MSVC has no specific options to set language standards, but set them as
+ # empty strings anyways so the feature test infrastructure can at least check
+ # to see if they are defined.
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "")
+
+ # There is no meaningful default for this
+ set(CMAKE_CXX_STANDARD_DEFAULT "")
+
+ # There are no compiler modes so we only need to test features once.
+ # Override the default macro for this special case. Pretend that
+ # all language standards are available so that at least compilation
+ # can be attempted.
+ macro(cmake_record_cxx_compile_features)
+ list(APPEND CMAKE_CXX_COMPILE_FEATURES
+ cxx_std_98
+ cxx_std_11
+ cxx_std_14
+ cxx_std_17
+ cxx_std_20
+ )
+ _record_compiler_features(CXX "" CMAKE_CXX_COMPILE_FEATURES)
+ endmacro()
+endif()
+
+# /JMC "Just My Code" is only supported by MSVC 19.05 onward.
+if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
+ set(CMAKE_CXX_COMPILE_OPTIONS_JMC "-JMC")
+endif()
diff --git a/Modules/Compiler/MSVC-DetermineCompiler.cmake b/Modules/Compiler/MSVC-DetermineCompiler.cmake
new file mode 100644
index 0000000..313de89
--- /dev/null
+++ b/Modules/Compiler/MSVC-DetermineCompiler.cmake
@@ -0,0 +1,19 @@
+
+set(_compiler_id_pp_test "defined(_MSC_VER)")
+
+set(_compiler_id_version_compute "
+ /* _MSC_VER = VVRR */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(_MSC_VER / 100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(_MSC_VER % 100)
+# if defined(_MSC_FULL_VER)
+# if _MSC_VER >= 1400
+ /* _MSC_FULL_VER = VVRRPPPPP */
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(_MSC_FULL_VER % 100000)
+# else
+ /* _MSC_FULL_VER = VVRRPPPP */
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(_MSC_FULL_VER % 10000)
+# endif
+# endif
+# if defined(_MSC_BUILD)
+# define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(_MSC_BUILD)
+# endif")
diff --git a/Modules/Compiler/NAG-Fortran.cmake b/Modules/Compiler/NAG-Fortran.cmake
new file mode 100644
index 0000000..a65fd2c
--- /dev/null
+++ b/Modules/Compiler/NAG-Fortran.cmake
@@ -0,0 +1,41 @@
+# Help CMAKE_PARSE_IMPLICIT_LINK_INFO detect NAG Fortran object files.
+if(NOT CMAKE_Fortran_COMPILER_WORKS AND NOT CMAKE_Fortran_COMPILER_FORCED)
+ message(CHECK_START "Detecting NAG Fortran directory")
+ # Run with -dryrun to see sample "link" line.
+ execute_process(
+ COMMAND ${CMAKE_Fortran_COMPILER} dummy.o -dryrun
+ OUTPUT_VARIABLE _dryrun
+ ERROR_VARIABLE _dryrun
+ )
+ # Match an object file.
+ string(REGEX MATCH "/[^ ]*/[^ /][^ /]*\\.o" _nag_obj "${_dryrun}")
+ if(_nag_obj)
+ # Parse object directory and convert to a regex.
+ string(REGEX REPLACE "/[^/]*$" "" _nag_dir "${_nag_obj}")
+ string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" _nag_regex "${_nag_dir}")
+ set(CMAKE_Fortran_IMPLICIT_OBJECT_REGEX "^${_nag_regex}/")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Detecting NAG Fortran directory with -dryrun found\n"
+ " object: ${_nag_obj}\n"
+ " directory: ${_nag_dir}\n"
+ " regex: ${CMAKE_Fortran_IMPLICIT_OBJECT_REGEX}\n"
+ "from output:\n${_dryrun}\n\n")
+ message(CHECK_PASS "${_nag_dir}")
+ else()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Detecting NAG Fortran directory with -dryrun failed:\n${_dryrun}\n\n")
+ message(CHECK_FAIL "failed")
+ endif()
+endif()
+
+set(CMAKE_Fortran_SUBMODULE_SEP ".")
+set(CMAKE_Fortran_SUBMODULE_EXT ".sub")
+set(CMAKE_Fortran_MODDIR_FLAG "-mdir ")
+set(CMAKE_Fortran_MODDIR_INCLUDE_FLAG "-I") # -mdir does not affect search path
+set(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-PIC")
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-fixed")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-free")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PIC "-PIC")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PIE "-PIC")
+set(CMAKE_Fortran_RESPONSE_FILE_LINK_FLAG "-Wl,@")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-fpp")
diff --git a/Modules/Compiler/NVHPC-C.cmake b/Modules/Compiler/NVHPC-C.cmake
new file mode 100644
index 0000000..d16c72b
--- /dev/null
+++ b/Modules/Compiler/NVHPC-C.cmake
@@ -0,0 +1,3 @@
+include(Compiler/PGI-C)
+include(Compiler/NVHPC)
+__compiler_nvhpc(C)
diff --git a/Modules/Compiler/NVHPC-CXX.cmake b/Modules/Compiler/NVHPC-CXX.cmake
new file mode 100644
index 0000000..18ace8b
--- /dev/null
+++ b/Modules/Compiler/NVHPC-CXX.cmake
@@ -0,0 +1,3 @@
+include(Compiler/PGI-CXX)
+include(Compiler/NVHPC)
+__compiler_nvhpc(CXX)
diff --git a/Modules/Compiler/NVHPC-DetermineCompiler.cmake b/Modules/Compiler/NVHPC-DetermineCompiler.cmake
new file mode 100644
index 0000000..45b69e1
--- /dev/null
+++ b/Modules/Compiler/NVHPC-DetermineCompiler.cmake
@@ -0,0 +1,9 @@
+
+set(_compiler_id_pp_test "defined(__NVCOMPILER)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__NVCOMPILER_MAJOR__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__NVCOMPILER_MINOR__)
+# if defined(__NVCOMPILER_PATCHLEVEL__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__NVCOMPILER_PATCHLEVEL__)
+# endif")
diff --git a/Modules/Compiler/NVHPC-Fortran.cmake b/Modules/Compiler/NVHPC-Fortran.cmake
new file mode 100644
index 0000000..59755b3
--- /dev/null
+++ b/Modules/Compiler/NVHPC-Fortran.cmake
@@ -0,0 +1,3 @@
+include(Compiler/PGI-Fortran)
+include(Compiler/NVHPC)
+__compiler_nvhpc(Fortran)
diff --git a/Modules/Compiler/NVHPC.cmake b/Modules/Compiler/NVHPC.cmake
new file mode 100644
index 0000000..7048670
--- /dev/null
+++ b/Modules/Compiler/NVHPC.cmake
@@ -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.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_NVHPC)
+ return()
+endif()
+set(__COMPILER_NVHPC 1)
+
+include(Compiler/PGI)
+
+macro(__compiler_nvhpc lang)
+ # Logic specific to NVHPC.
+endmacro()
diff --git a/Modules/Compiler/NVIDIA-CUDA.cmake b/Modules/Compiler/NVIDIA-CUDA.cmake
new file mode 100644
index 0000000..a0f7c05
--- /dev/null
+++ b/Modules/Compiler/NVIDIA-CUDA.cmake
@@ -0,0 +1,144 @@
+include(Compiler/CMakeCommonCompilerMacros)
+
+set(CMAKE_CUDA_COMPILER_HAS_DEVICE_LINK_PHASE True)
+set(CMAKE_CUDA_VERBOSE_FLAG "-v")
+set(CMAKE_CUDA_VERBOSE_COMPILE_FLAG "-Xcompiler=-v")
+
+set(_CMAKE_COMPILE_AS_CUDA_FLAG "-x cu")
+set(_CMAKE_CUDA_PTX_FLAG "-ptx")
+set(_CMAKE_CUDA_DEVICE_CODE "-dc")
+
+if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 10.2.89)
+ # The -forward-unknown-to-host-compiler flag was only
+ # added to nvcc in 10.2 so before that we had no good
+ # way to invoke the CUDA compiler and propagate unknown
+ # flags such as -pthread to the host compiler
+ set(_CMAKE_CUDA_EXTRA_FLAGS "-forward-unknown-to-host-compiler")
+else()
+ set(_CMAKE_CUDA_EXTRA_FLAGS "")
+endif()
+
+if(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "8.0.0")
+ set(_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS "-Wno-deprecated-gpu-targets")
+else()
+ set(_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS "")
+endif()
+
+if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 10.2.89)
+ # The -MD flag was only added to nvcc in 10.2 so
+ # before that we had to invoke the compiler twice
+ # to get header dependency information
+ set(CMAKE_DEPFILE_FLAGS_CUDA "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+else()
+ if(CMAKE_CUDA_HOST_COMPILER AND NOT CMAKE_SYSTEM_NAME STREQUAL "Windows")
+ # FIXME: Move the main -ccbin= flag from CMakeCUDAInformation to
+ # a block above, remove this copy, and update the VS generator too.
+ set(_CMAKE_CUDA_EXTRA_FLAGS_LOCAL " -ccbin=<CMAKE_CUDA_HOST_COMPILER>")
+ else()
+ set(_CMAKE_CUDA_EXTRA_FLAGS_LOCAL "")
+ endif()
+ set(CMAKE_CUDA_DEPENDS_EXTRA_COMMANDS "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS}${_CMAKE_CUDA_EXTRA_FLAGS_LOCAL} <DEFINES> <INCLUDES> <FLAGS> ${_CMAKE_COMPILE_AS_CUDA_FLAG} -M <SOURCE> -MT <OBJECT> -o <DEP_FILE>")
+ unset(_CMAKE_CUDA_EXTRA_FLAGS_LOCAL)
+endif()
+set(CMAKE_CUDA_DEPFILE_FORMAT gcc)
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ set(CMAKE_CUDA_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+if(NOT "x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC")
+ set(CMAKE_CUDA_COMPILE_OPTIONS_PIE -Xcompiler=-fPIE)
+ set(CMAKE_CUDA_COMPILE_OPTIONS_PIC -Xcompiler=-fPIC)
+ set(CMAKE_CUDA_COMPILE_OPTIONS_VISIBILITY -Xcompiler=-fvisibility=)
+ # CMAKE_SHARED_LIBRARY_CUDA_FLAGS is sent to the host linker so we
+ # don't need to forward it through nvcc.
+ set(CMAKE_SHARED_LIBRARY_CUDA_FLAGS -fPIC)
+ string(APPEND CMAKE_CUDA_FLAGS_INIT " ")
+ string(APPEND CMAKE_CUDA_FLAGS_DEBUG_INIT " -g")
+ string(APPEND CMAKE_CUDA_FLAGS_RELEASE_INIT " -O3 -DNDEBUG")
+ string(APPEND CMAKE_CUDA_FLAGS_MINSIZEREL_INIT " -O1 -DNDEBUG")
+ string(APPEND CMAKE_CUDA_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG")
+endif()
+set(CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS -shared)
+set(CMAKE_INCLUDE_SYSTEM_FLAG_CUDA -isystem=)
+
+if (CMAKE_CUDA_SIMULATE_ID STREQUAL "GNU")
+ set(CMAKE_CUDA_LINKER_WRAPPER_FLAG "-Wl,")
+ set(CMAKE_CUDA_LINKER_WRAPPER_FLAG_SEP ",")
+elseif(CMAKE_CUDA_SIMULATE_ID STREQUAL "Clang")
+ set(CMAKE_CUDA_LINKER_WRAPPER_FLAG "-Xlinker" " ")
+ set(CMAKE_CUDA_LINKER_WRAPPER_FLAG_SEP)
+endif()
+
+set(CMAKE_CUDA_DEVICE_COMPILER_WRAPPER_FLAG "-Xcompiler=")
+set(CMAKE_CUDA_DEVICE_COMPILER_WRAPPER_FLAG_SEP ",")
+set(CMAKE_CUDA_DEVICE_LINKER_WRAPPER_FLAG "-Xlinker=")
+set(CMAKE_CUDA_DEVICE_LINKER_WRAPPER_FLAG_SEP ",")
+
+set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC "cudadevrt;cudart_static")
+set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_SHARED "cudadevrt;cudart")
+set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_NONE "")
+
+if(UNIX AND NOT (CMAKE_SYSTEM_NAME STREQUAL "QNX"))
+ list(APPEND CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC "rt" "pthread" "dl")
+endif()
+
+if("x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC")
+ # MSVC requires c++14 as the minimum level
+ set(CMAKE_CUDA03_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CUDA03_EXTENSION_COMPILE_OPTION "")
+
+ # MSVC requires c++14 as the minimum level
+ set(CMAKE_CUDA11_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CUDA11_EXTENSION_COMPILE_OPTION "")
+
+ if (NOT CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 9.0)
+ if(CMAKE_CUDA_SIMULATE_VERSION VERSION_GREATER_EQUAL 19.10.25017)
+ set(CMAKE_CUDA14_STANDARD_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_CUDA14_EXTENSION_COMPILE_OPTION "-std=c++14")
+ else()
+ set(CMAKE_CUDA14_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CUDA14_EXTENSION_COMPILE_OPTION "")
+ endif()
+ endif()
+
+ if (NOT CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 11.0)
+ if(CMAKE_CUDA_SIMULATE_VERSION VERSION_GREATER_EQUAL 19.11.25505)
+ set(CMAKE_CUDA17_STANDARD_COMPILE_OPTION "-std=c++17")
+ set(CMAKE_CUDA17_EXTENSION_COMPILE_OPTION "-std=c++17")
+ endif()
+ endif()
+
+else()
+ set(CMAKE_CUDA03_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CUDA03_EXTENSION_COMPILE_OPTION "")
+
+ set(CMAKE_CUDA11_STANDARD_COMPILE_OPTION "-std=c++11")
+ set(CMAKE_CUDA11_EXTENSION_COMPILE_OPTION "-std=c++11")
+
+ if (NOT CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 9.0)
+ set(CMAKE_CUDA03_STANDARD_COMPILE_OPTION "-std=c++03")
+ set(CMAKE_CUDA03_EXTENSION_COMPILE_OPTION "-std=c++03")
+ set(CMAKE_CUDA14_STANDARD_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_CUDA14_EXTENSION_COMPILE_OPTION "-std=c++14")
+ endif()
+
+ if (NOT CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 11.0)
+ set(CMAKE_CUDA17_STANDARD_COMPILE_OPTION "-std=c++17")
+ set(CMAKE_CUDA17_EXTENSION_COMPILE_OPTION "-std=c++17")
+ endif()
+
+endif()
+
+# FIXME: investigate use of --options-file.
+# Tell Makefile generator that nvcc does not support @<rspfile> syntax.
+set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_INCLUDES 0)
+set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES 0)
+set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS 0)
+
+if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "9.0")
+ set(CMAKE_CUDA_RESPONSE_FILE_DEVICE_LINK_FLAG "--options-file ")
+ set(CMAKE_CUDA_RESPONSE_FILE_FLAG "--options-file ")
+endif()
+
+__compiler_check_default_language_standard(CUDA 6.0 03)
diff --git a/Modules/Compiler/NVIDIA-DetermineCompiler.cmake b/Modules/Compiler/NVIDIA-DetermineCompiler.cmake
new file mode 100644
index 0000000..4f6ddc2
--- /dev/null
+++ b/Modules/Compiler/NVIDIA-DetermineCompiler.cmake
@@ -0,0 +1,29 @@
+
+set(_compiler_id_pp_test "defined(__NVCC__)")
+
+set(_compiler_id_version_compute "
+# if defined(__CUDACC_VER_MAJOR__)
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__CUDACC_VER_MAJOR__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__CUDACC_VER_MINOR__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__CUDACC_VER_BUILD__)
+# endif
+# if defined(_MSC_VER)
+ /* _MSC_VER = VVRR */
+# define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(_MSC_VER / 100)
+# define @PREFIX@SIMULATE_VERSION_MINOR @MACRO_DEC@(_MSC_VER % 100)
+# elif defined(__clang__)
+# define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(__clang_major__)
+# define @PREFIX@SIMULATE_VERSION_MINOR @MACRO_DEC@(__clang_minor__)
+# elif defined(__GNUC__)
+# define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(__GNUC__)
+# define @PREFIX@SIMULATE_VERSION_MINOR @MACRO_DEC@(__GNUC_MINOR__)
+# endif")
+
+set(_compiler_id_simulate "
+# if defined(_MSC_VER)
+# define @PREFIX@SIMULATE_ID \"MSVC\"
+# elif defined(__clang__)
+# define @PREFIX@SIMULATE_ID \"Clang\"
+# elif defined(__GNUC__)
+# define @PREFIX@SIMULATE_ID \"GNU\"
+# endif")
diff --git a/Modules/Compiler/OpenWatcom-C.cmake b/Modules/Compiler/OpenWatcom-C.cmake
new file mode 100644
index 0000000..19e3359
--- /dev/null
+++ b/Modules/Compiler/OpenWatcom-C.cmake
@@ -0,0 +1 @@
+include(Compiler/OpenWatcom)
diff --git a/Modules/Compiler/OpenWatcom-CXX.cmake b/Modules/Compiler/OpenWatcom-CXX.cmake
new file mode 100644
index 0000000..19e3359
--- /dev/null
+++ b/Modules/Compiler/OpenWatcom-CXX.cmake
@@ -0,0 +1 @@
+include(Compiler/OpenWatcom)
diff --git a/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake b/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake
new file mode 100644
index 0000000..2ed116c
--- /dev/null
+++ b/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake
@@ -0,0 +1,10 @@
+
+set(_compiler_id_pp_test "defined(__WATCOMC__)")
+
+set(_compiler_id_version_compute "
+ /* __WATCOMC__ = VVRP + 1100 */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@((__WATCOMC__ - 1100) / 100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@((__WATCOMC__ / 10) % 10)
+# if (__WATCOMC__ % 10) > 0
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__WATCOMC__ % 10)
+# endif")
diff --git a/Modules/Compiler/OpenWatcom.cmake b/Modules/Compiler/OpenWatcom.cmake
new file mode 100644
index 0000000..a962513
--- /dev/null
+++ b/Modules/Compiler/OpenWatcom.cmake
@@ -0,0 +1,118 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+set(CMAKE_LIBRARY_PATH_FLAG "libpath ")
+set(CMAKE_LINK_LIBRARY_FLAG "library ")
+set(CMAKE_LINK_LIBRARY_FILE_FLAG "library ")
+
+if(CMAKE_VERBOSE_MAKEFILE)
+ set(CMAKE_WCL_QUIET)
+ set(CMAKE_WLINK_QUIET)
+ set(CMAKE_LIB_QUIET)
+else()
+ set(CMAKE_WCL_QUIET "-zq")
+ set(CMAKE_WLINK_QUIET "option quiet")
+ set(CMAKE_LIB_QUIET "-q")
+endif()
+
+foreach(type CREATE_SHARED_LIBRARY CREATE_SHARED_MODULE LINK_EXECUTABLE)
+ set(CMAKE_C_${type}_USE_WATCOM_QUOTE 1)
+ set(CMAKE_CXX_${type}_USE_WATCOM_QUOTE 1)
+endforeach()
+
+foreach(type SHARED MODULE EXE)
+ # linker map file creation directives
+ string(APPEND CMAKE_${type}_LINKER_FLAGS_INIT " opt map")
+ # linker debug directives
+ string(APPEND CMAKE_${type}_LINKER_FLAGS_DEBUG_INIT " debug all")
+ string(APPEND CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO_INIT " debug all")
+endforeach()
+
+foreach(lang C CXX)
+ # warning level
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " -w3")
+ # debug options
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -d2")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -s -os -d0 -dNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -s -ot -d0 -dNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -s -ot -d1 -dNDEBUG")
+endforeach()
+
+# C create import library
+set(CMAKE_C_CREATE_IMPORT_LIBRARY
+ "wlib -c -q -n -b <TARGET_IMPLIB> +<TARGET_QUOTED>")
+# C++ create import library
+set(CMAKE_CXX_CREATE_IMPORT_LIBRARY ${CMAKE_C_CREATE_IMPORT_LIBRARY})
+
+# C link a object files into an executable file
+set(CMAKE_C_LINK_EXECUTABLE
+ "wlink ${CMAKE_WLINK_QUIET} name <TARGET> <LINK_FLAGS> file {<OBJECTS>} <LINK_LIBRARIES>")
+# C++ link a object files into an executable file
+set(CMAKE_CXX_LINK_EXECUTABLE ${CMAKE_C_LINK_EXECUTABLE})
+
+# C compile a file into an object file
+set(CMAKE_C_COMPILE_OBJECT
+ "<CMAKE_C_COMPILER> ${CMAKE_WCL_QUIET} -d+ <DEFINES> <INCLUDES> <FLAGS> -fo<OBJECT> -c -cc <SOURCE>")
+# C++ compile a file into an object file
+set(CMAKE_CXX_COMPILE_OBJECT
+ "<CMAKE_CXX_COMPILER> ${CMAKE_WCL_QUIET} -d+ <DEFINES> <INCLUDES> <FLAGS> -fo<OBJECT> -c -cc++ <SOURCE>")
+
+# C preprocess a source file
+set(CMAKE_C_CREATE_PREPROCESSED_SOURCE
+ "<CMAKE_C_COMPILER> ${CMAKE_WCL_QUIET} -d+ <DEFINES> <INCLUDES> <FLAGS> -fo<PREPROCESSED_SOURCE> -pl -cc <SOURCE>")
+# C++ preprocess a source file
+set(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE
+ "<CMAKE_CXX_COMPILER> ${CMAKE_WCL_QUIET} -d+ <DEFINES> <INCLUDES> <FLAGS> -fo<PREPROCESSED_SOURCE> -pl -cc++ <SOURCE>")
+
+# C create a shared library
+set(CMAKE_C_CREATE_SHARED_LIBRARY
+ "wlink ${CMAKE_WLINK_QUIET} name <TARGET> <LINK_FLAGS> option implib=<TARGET_IMPLIB> file {<OBJECTS>} <LINK_LIBRARIES>")
+# C++ create a shared library
+set(CMAKE_CXX_CREATE_SHARED_LIBRARY ${CMAKE_C_CREATE_SHARED_LIBRARY})
+
+# C create a shared module
+set(CMAKE_C_CREATE_SHARED_MODULE
+ "wlink ${CMAKE_WLINK_QUIET} name <TARGET> <LINK_FLAGS> file {<OBJECTS>} <LINK_LIBRARIES>")
+# C++ create a shared module
+set(CMAKE_CXX_CREATE_SHARED_MODULE ${CMAKE_C_CREATE_SHARED_MODULE})
+
+# C create a static library
+set(CMAKE_C_CREATE_STATIC_LIBRARY
+ "wlib ${CMAKE_LIB_QUIET} -c -n -b <TARGET_QUOTED> <LINK_FLAGS> <OBJECTS> ")
+# C++ create a static library
+set(CMAKE_CXX_CREATE_STATIC_LIBRARY ${CMAKE_C_CREATE_STATIC_LIBRARY})
+
+
+# old CMake internally used OpenWatcom version macros
+# for backward compatibility
+if(NOT _CMAKE_WATCOM_VERSION)
+ set(_CMAKE_WATCOM_VERSION 1)
+ if(CMAKE_C_COMPILER_VERSION)
+ set(_compiler_version ${CMAKE_C_COMPILER_VERSION})
+ set(_compiler_id ${CMAKE_C_COMPILER_ID})
+ else()
+ set(_compiler_version ${CMAKE_CXX_COMPILER_VERSION})
+ set(_compiler_id ${CMAKE_CXX_COMPILER_ID})
+ endif()
+ set(WATCOM16)
+ set(WATCOM17)
+ set(WATCOM18)
+ set(WATCOM19)
+ if("${_compiler_id}" STREQUAL "OpenWatcom")
+ if("${_compiler_version}" VERSION_LESS 1.7)
+ set(WATCOM16 1)
+ endif()
+ if("${_compiler_version}" VERSION_EQUAL 1.7)
+ set(WATCOM17 1)
+ endif()
+ if("${_compiler_version}" VERSION_EQUAL 1.8)
+ set(WATCOM18 1)
+ endif()
+ if("${_compiler_version}" VERSION_EQUAL 1.9)
+ set(WATCOM19 1)
+ endif()
+ endif()
+endif()
diff --git a/Modules/Compiler/PGI-C.cmake b/Modules/Compiler/PGI-C.cmake
new file mode 100644
index 0000000..c39dbe5
--- /dev/null
+++ b/Modules/Compiler/PGI-C.cmake
@@ -0,0 +1,20 @@
+include(Compiler/PGI)
+__compiler_pgi(C)
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
+
+if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.10)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION -c89)
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION -c89)
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION -c99)
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION -c99)
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+ if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15.3)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION -c11)
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION -c11)
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+ endif ()
+endif ()
+
+__compiler_check_default_language_standard(C 12.10 90)
diff --git a/Modules/Compiler/PGI-CXX.cmake b/Modules/Compiler/PGI-CXX.cmake
new file mode 100644
index 0000000..1279c19
--- /dev/null
+++ b/Modules/Compiler/PGI-CXX.cmake
@@ -0,0 +1,28 @@
+include(Compiler/PGI)
+__compiler_pgi(CXX)
+string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -DNDEBUG")
+
+if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12.10)
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION --gnu_extensions)
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.10)
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION --c++03)
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION --c++03 --gnu_extensions)
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION --c++11)
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION --c++11 --gnu_extensions)
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15.7)
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION --c++14)
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION --c++14 --gnu_extensions)
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 17.1)
+ set(CMAKE_CXX17_STANDARD_COMPILE_OPTION --c++17)
+ set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION --c++17 --gnu_extensions)
+ endif()
+ endif()
+ endif()
+endif()
+
+__compiler_check_default_language_standard(CXX 12.10 98)
diff --git a/Modules/Compiler/PGI-DetermineCompiler.cmake b/Modules/Compiler/PGI-DetermineCompiler.cmake
new file mode 100644
index 0000000..8d3dc9c
--- /dev/null
+++ b/Modules/Compiler/PGI-DetermineCompiler.cmake
@@ -0,0 +1,9 @@
+
+set(_compiler_id_pp_test "defined(__PGI)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__PGIC__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__PGIC_MINOR__)
+# if defined(__PGIC_PATCHLEVEL__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__PGIC_PATCHLEVEL__)
+# endif")
diff --git a/Modules/Compiler/PGI-Fortran.cmake b/Modules/Compiler/PGI-Fortran.cmake
new file mode 100644
index 0000000..ff87577
--- /dev/null
+++ b/Modules/Compiler/PGI-Fortran.cmake
@@ -0,0 +1,16 @@
+include(Compiler/PGI)
+__compiler_pgi(Fortran)
+
+set(CMAKE_Fortran_SUBMODULE_SEP "-")
+set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
+
+set(CMAKE_Fortran_PREPROCESS_SOURCE
+ "<CMAKE_Fortran_COMPILER> -Mpreprocess <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-Mpreprocess")
+
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-Mnofreeform")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-Mfreeform")
+
+string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -Mbounds")
+
+set(CMAKE_Fortran_MODDIR_FLAG "-module ")
diff --git a/Modules/Compiler/PGI.cmake b/Modules/Compiler/PGI.cmake
new file mode 100644
index 0000000..4f8b90b
--- /dev/null
+++ b/Modules/Compiler/PGI.cmake
@@ -0,0 +1,42 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_PGI)
+ return()
+endif()
+set(__COMPILER_PGI 1)
+
+include(Compiler/CMakeCommonCompilerMacros)
+
+macro(__compiler_pgi lang)
+ # Feature flags.
+ set(CMAKE_${lang}_VERBOSE_FLAG "-v")
+
+ # Initial configuration flags.
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g -O0")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -O2 -s")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -fast -O3")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -gopt")
+
+ if(CMAKE_HOST_WIN32)
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " -Bdynamic")
+ endif()
+
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG ",")
+
+ set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
+ if(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL ppc64le AND (NOT CMAKE_HOST_WIN32 OR CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 16.3))
+ set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-Mipa=fast,inline")
+ else()
+ set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER NO)
+ endif()
+
+ # Preprocessing and assembly rules.
+ set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+ set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+endmacro()
diff --git a/Modules/Compiler/PathScale-C.cmake b/Modules/Compiler/PathScale-C.cmake
new file mode 100644
index 0000000..94c7d08
--- /dev/null
+++ b/Modules/Compiler/PathScale-C.cmake
@@ -0,0 +1,4 @@
+include(Compiler/PathScale)
+__compiler_pathscale(C)
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
diff --git a/Modules/Compiler/PathScale-CXX.cmake b/Modules/Compiler/PathScale-CXX.cmake
new file mode 100644
index 0000000..276b81b
--- /dev/null
+++ b/Modules/Compiler/PathScale-CXX.cmake
@@ -0,0 +1,4 @@
+include(Compiler/PathScale)
+__compiler_pathscale(CXX)
+string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -DNDEBUG")
diff --git a/Modules/Compiler/PathScale-DetermineCompiler.cmake b/Modules/Compiler/PathScale-DetermineCompiler.cmake
new file mode 100644
index 0000000..4eb81de
--- /dev/null
+++ b/Modules/Compiler/PathScale-DetermineCompiler.cmake
@@ -0,0 +1,9 @@
+
+set(_compiler_id_pp_test "defined(__PATHCC__)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__PATHCC__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__PATHCC_MINOR__)
+# if defined(__PATHCC_PATCHLEVEL__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__PATHCC_PATCHLEVEL__)
+# endif")
diff --git a/Modules/Compiler/PathScale-Fortran.cmake b/Modules/Compiler/PathScale-Fortran.cmake
new file mode 100644
index 0000000..891d93e
--- /dev/null
+++ b/Modules/Compiler/PathScale-Fortran.cmake
@@ -0,0 +1,9 @@
+include(Compiler/PathScale)
+__compiler_pathscale(Fortran)
+
+set(CMAKE_Fortran_MODDIR_FLAG "-module ")
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-fixedform")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-freeform")
+
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
diff --git a/Modules/Compiler/PathScale.cmake b/Modules/Compiler/PathScale.cmake
new file mode 100644
index 0000000..d5f8cb1
--- /dev/null
+++ b/Modules/Compiler/PathScale.cmake
@@ -0,0 +1,21 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_PATHSCALE)
+ return()
+endif()
+set(__COMPILER_PATHSCALE 1)
+
+macro(__compiler_pathscale lang)
+ # Feature flags.
+ set(CMAKE_${lang}_VERBOSE_FLAG "-v")
+
+ # Initial configuration flags.
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g -O0")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -g -O2")
+endmacro()
diff --git a/Modules/Compiler/QCC-ASM.cmake b/Modules/Compiler/QCC-ASM.cmake
new file mode 100644
index 0000000..9a9935b
--- /dev/null
+++ b/Modules/Compiler/QCC-ASM.cmake
@@ -0,0 +1,2 @@
+include(Compiler/QCC)
+__compiler_qcc(ASM)
diff --git a/Modules/Compiler/QCC-C-FeatureTests.cmake b/Modules/Compiler/QCC-C-FeatureTests.cmake
new file mode 100644
index 0000000..68f4197
--- /dev/null
+++ b/Modules/Compiler/QCC-C-FeatureTests.cmake
@@ -0,0 +1 @@
+include(Compiler/GNU-C-FeatureTests)
diff --git a/Modules/Compiler/QCC-C.cmake b/Modules/Compiler/QCC-C.cmake
new file mode 100644
index 0000000..6db619e
--- /dev/null
+++ b/Modules/Compiler/QCC-C.cmake
@@ -0,0 +1,5 @@
+# To include compiler feature detection
+include(Compiler/GNU-C)
+
+include(Compiler/QCC)
+__compiler_qcc(C)
diff --git a/Modules/Compiler/QCC-CXX-FeatureTests.cmake b/Modules/Compiler/QCC-CXX-FeatureTests.cmake
new file mode 100644
index 0000000..c836b94
--- /dev/null
+++ b/Modules/Compiler/QCC-CXX-FeatureTests.cmake
@@ -0,0 +1 @@
+include(Compiler/GNU-CXX-FeatureTests)
diff --git a/Modules/Compiler/QCC-CXX.cmake b/Modules/Compiler/QCC-CXX.cmake
new file mode 100644
index 0000000..42303f4
--- /dev/null
+++ b/Modules/Compiler/QCC-CXX.cmake
@@ -0,0 +1,15 @@
+# To include compiler feature detection
+include(Compiler/GNU-CXX)
+
+include(Compiler/QCC)
+__compiler_qcc(CXX)
+
+# If the toolchain uses qcc for CMAKE_CXX_COMPILER instead of QCC, the
+# default for the driver is not c++.
+set(CMAKE_CXX_COMPILE_OBJECT
+ "<CMAKE_CXX_COMPILER> -lang-c++ <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+
+set(CMAKE_CXX_LINK_EXECUTABLE
+ "<CMAKE_CXX_COMPILER> -lang-c++ <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+
+set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
diff --git a/Modules/Compiler/QCC.cmake b/Modules/Compiler/QCC.cmake
new file mode 100644
index 0000000..7fbfd10
--- /dev/null
+++ b/Modules/Compiler/QCC.cmake
@@ -0,0 +1,37 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+include(Compiler/GNU)
+
+macro(__compiler_qcc lang)
+ __compiler_gnu(${lang})
+
+ # http://www.qnx.com/developers/docs/6.4.0/neutrino/utilities/q/qcc.html#examples
+ set(CMAKE_${lang}_COMPILE_OPTIONS_TARGET "-V")
+
+ set(CMAKE_PREFIX_LIBRARY_ARCHITECTURE "ON")
+
+ set(CMAKE_${lang}_COMPILE_OPTIONS_SYSROOT "-Wc,-isysroot,")
+ set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-Wp,-isystem,")
+ set(CMAKE_DEPFILE_FLAGS_${lang} "-Wp,-MD,<DEP_FILE> -Wp,-MT,<DEP_TARGET> -Wp,-MF,<DEP_FILE>")
+
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
+ set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE NO)
+ set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER NO)
+
+ set(CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "${CMAKE_${lang}_COMPILER}")
+ if(CMAKE_${lang}_COMPILER_ARG1)
+ separate_arguments(_COMPILER_ARGS NATIVE_COMMAND "${CMAKE_${lang}_COMPILER_ARG1}")
+ list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND ${_COMPILER_ARGS})
+ unset(_COMPILER_ARGS)
+ endif()
+ list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "-Wp,-dM" "-E" "-c" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp")
+
+ unset(CMAKE_${lang}_COMPILE_OPTIONS_IPO)
+ unset(CMAKE_${lang}_ARCHIVE_CREATE_IPO)
+ unset(CMAKE_${lang}_ARCHIVE_APPEND_IPO)
+ unset(CMAKE_${lang}_ARCHIVE_FINISH_IPO)
+endmacro()
diff --git a/Modules/Compiler/SCO-C.cmake b/Modules/Compiler/SCO-C.cmake
new file mode 100644
index 0000000..6e762cc
--- /dev/null
+++ b/Modules/Compiler/SCO-C.cmake
@@ -0,0 +1,2 @@
+include(Compiler/SCO)
+__compiler_sco(C)
diff --git a/Modules/Compiler/SCO-CXX.cmake b/Modules/Compiler/SCO-CXX.cmake
new file mode 100644
index 0000000..5b713a0
--- /dev/null
+++ b/Modules/Compiler/SCO-CXX.cmake
@@ -0,0 +1,2 @@
+include(Compiler/SCO)
+__compiler_sco(CXX)
diff --git a/Modules/Compiler/SCO-DetermineCompiler.cmake b/Modules/Compiler/SCO-DetermineCompiler.cmake
new file mode 100644
index 0000000..a44b22b
--- /dev/null
+++ b/Modules/Compiler/SCO-DetermineCompiler.cmake
@@ -0,0 +1,2 @@
+
+set(_compiler_id_pp_test "defined(__SCO_VERSION__)")
diff --git a/Modules/Compiler/SCO.cmake b/Modules/Compiler/SCO.cmake
new file mode 100644
index 0000000..7f643d9
--- /dev/null
+++ b/Modules/Compiler/SCO.cmake
@@ -0,0 +1,21 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_SCO)
+ return()
+endif()
+set(__COMPILER_SCO 1)
+
+macro(__compiler_sco lang)
+ # Feature flags.
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC -Kpic)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE -Kpie)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_DLL -belf)
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-Kpic -belf")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-belf -Wl,-Bexport")
+
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+endmacro()
diff --git a/Modules/Compiler/SDCC-C-DetermineCompiler.cmake b/Modules/Compiler/SDCC-C-DetermineCompiler.cmake
new file mode 100644
index 0000000..4c70c5e
--- /dev/null
+++ b/Modules/Compiler/SDCC-C-DetermineCompiler.cmake
@@ -0,0 +1,16 @@
+
+# sdcc, the small devices C compiler for embedded systems,
+# http://sdcc.sourceforge.net */
+set(_compiler_id_pp_test "defined(__SDCC_VERSION_MAJOR) || defined(SDCC)")
+
+set(_compiler_id_version_compute "
+# if defined(__SDCC_VERSION_MAJOR)
+# define COMPILER_VERSION_MAJOR @MACRO_DEC@(__SDCC_VERSION_MAJOR)
+# define COMPILER_VERSION_MINOR @MACRO_DEC@(__SDCC_VERSION_MINOR)
+# define COMPILER_VERSION_PATCH @MACRO_DEC@(__SDCC_VERSION_PATCH)
+# else
+ /* SDCC = VRP */
+# define COMPILER_VERSION_MAJOR @MACRO_DEC@(SDCC/100)
+# define COMPILER_VERSION_MINOR @MACRO_DEC@(SDCC/10 % 10)
+# define COMPILER_VERSION_PATCH @MACRO_DEC@(SDCC % 10)
+# endif")
diff --git a/Modules/Compiler/SunPro-ASM.cmake b/Modules/Compiler/SunPro-ASM.cmake
new file mode 100644
index 0000000..0d67400
--- /dev/null
+++ b/Modules/Compiler/SunPro-ASM.cmake
@@ -0,0 +1,24 @@
+set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s )
+
+set(CMAKE_ASM_VERBOSE_FLAG "-#")
+
+set(CMAKE_SHARED_LIBRARY_ASM_FLAGS "-KPIC")
+set(CMAKE_SHARED_LIBRARY_CREATE_ASM_FLAGS "-G")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_ASM_FLAG "-R")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_ASM_FLAG_SEP ":")
+set(CMAKE_SHARED_LIBRARY_SONAME_ASM_FLAG "-h")
+
+string(APPEND CMAKE_ASM_FLAGS_INIT " ")
+string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -g")
+string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -xO2 -xspace -DNDEBUG")
+string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -xO3 -DNDEBUG")
+string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -g -xO2 -DNDEBUG")
+
+# Initialize ASM link type selection flags. These flags are used when
+# building a shared library, shared module, or executable that links
+# to other libraries to select whether to use the static or shared
+# versions of the libraries.
+foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+ set(CMAKE_${type}_LINK_STATIC_ASM_FLAGS "-Bstatic")
+ set(CMAKE_${type}_LINK_DYNAMIC_ASM_FLAGS "-Bdynamic")
+endforeach()
diff --git a/Modules/Compiler/SunPro-C-DetermineCompiler.cmake b/Modules/Compiler/SunPro-C-DetermineCompiler.cmake
new file mode 100644
index 0000000..e9d7457
--- /dev/null
+++ b/Modules/Compiler/SunPro-C-DetermineCompiler.cmake
@@ -0,0 +1,15 @@
+
+set(_compiler_id_pp_test "defined(__SUNPRO_C)")
+
+set(_compiler_id_version_compute "
+# if __SUNPRO_C >= 0x5100
+ /* __SUNPRO_C = 0xVRRP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_HEX@(__SUNPRO_C>>12)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_HEX@(__SUNPRO_C>>4 & 0xFF)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_HEX@(__SUNPRO_C & 0xF)
+# else
+ /* __SUNPRO_CC = 0xVRP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_HEX@(__SUNPRO_C>>8)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_HEX@(__SUNPRO_C>>4 & 0xF)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_HEX@(__SUNPRO_C & 0xF)
+# endif")
diff --git a/Modules/Compiler/SunPro-C-FeatureTests.cmake b/Modules/Compiler/SunPro-C-FeatureTests.cmake
new file mode 100644
index 0000000..cccf3ae
--- /dev/null
+++ b/Modules/Compiler/SunPro-C-FeatureTests.cmake
@@ -0,0 +1,14 @@
+set(_cmake_oldestSupported "__SUNPRO_C >= 0x5130")
+
+set(SunPro_C11 "${_cmake_oldestSupported} && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L || __STDC_VERSION__ >= 199901L && defined(__C11FEATURES__))")
+set(_cmake_feature_test_c_static_assert "${SunPro_C11}")
+unset(SunPro_C11)
+
+set(SunPro_C99 "${_cmake_oldestSupported} && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L")
+set(_cmake_feature_test_c_restrict "${SunPro_C99}")
+set(_cmake_feature_test_c_variadic_macros "${SunPro_C99}")
+unset(SunPro_C99)
+
+set(SunPro_C90 "${_cmake_oldestSupported}")
+set(_cmake_feature_test_c_function_prototypes "${SunPro_C90}")
+unset(SunPro_C90)
diff --git a/Modules/Compiler/SunPro-C.cmake b/Modules/Compiler/SunPro-C.cmake
new file mode 100644
index 0000000..c98656f
--- /dev/null
+++ b/Modules/Compiler/SunPro-C.cmake
@@ -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.
+
+include(Compiler/SunPro)
+
+set(CMAKE_C_VERBOSE_FLAG "-#")
+
+set(CMAKE_C_COMPILE_OPTIONS_PIC -KPIC)
+set(CMAKE_C_COMPILE_OPTIONS_PIE "")
+set(_CMAKE_C_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+set(CMAKE_C_LINK_OPTIONS_PIE "")
+set(CMAKE_C_LINK_OPTIONS_NO_PIE "")
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-KPIC")
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-G")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-R")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-h")
+
+string(APPEND CMAKE_C_FLAGS_INIT " ")
+string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -g")
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -xO2 -xspace -DNDEBUG")
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -xO3 -DNDEBUG")
+string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -g -xO2 -DNDEBUG")
+
+set(CMAKE_DEPFILE_FLAGS_C "-xMD -xMF <DEP_FILE>")
+
+# Initialize C link type selection flags. These flags are used when
+# building a shared library, shared module, or executable that links
+# to other libraries to select whether to use the static or shared
+# versions of the libraries.
+foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+ set(CMAKE_${type}_LINK_STATIC_C_FLAGS "-Bstatic")
+ set(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-Bdynamic")
+endforeach()
+
+set(CMAKE_C_LINKER_WRAPPER_FLAG "-Qoption" "ld" " ")
+set(CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",")
+
+if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.13)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c89")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=c89")
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=c99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=c11")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+elseif (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.11)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "-xc99")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-xc99")
+endif()
+
+__compiler_check_default_language_standard(C 5.11 90 5.14 11)
+
+set(CMAKE_C_CREATE_PREPROCESSED_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+set(CMAKE_C_CREATE_ASSEMBLY_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
diff --git a/Modules/Compiler/SunPro-CXX-DetermineCompiler.cmake b/Modules/Compiler/SunPro-CXX-DetermineCompiler.cmake
new file mode 100644
index 0000000..5c23a95
--- /dev/null
+++ b/Modules/Compiler/SunPro-CXX-DetermineCompiler.cmake
@@ -0,0 +1,15 @@
+
+set(_compiler_id_pp_test "defined(__SUNPRO_CC)")
+
+set(_compiler_id_version_compute "
+# if __SUNPRO_CC >= 0x5100
+ /* __SUNPRO_CC = 0xVRRP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_HEX@(__SUNPRO_CC>>12)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_HEX@(__SUNPRO_CC>>4 & 0xFF)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_HEX@(__SUNPRO_CC & 0xF)
+# else
+ /* __SUNPRO_CC = 0xVRP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_HEX@(__SUNPRO_CC>>8)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_HEX@(__SUNPRO_CC>>4 & 0xF)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_HEX@(__SUNPRO_CC & 0xF)
+# endif")
diff --git a/Modules/Compiler/SunPro-CXX-FeatureTests.cmake b/Modules/Compiler/SunPro-CXX-FeatureTests.cmake
new file mode 100644
index 0000000..e7133c1
--- /dev/null
+++ b/Modules/Compiler/SunPro-CXX-FeatureTests.cmake
@@ -0,0 +1,68 @@
+
+# Based on GNU 4.8.2
+# https://docs.oracle.com/cd/E37069_01/html/E37071/gncix.html
+# https://docs.oracle.com/cd/E77782_01/html/E77784/gkeza.html
+# Reference: http://gcc.gnu.org/projects/cxx0x.html
+
+set(_cmake_oldestSupported "__SUNPRO_CC >= 0x5130")
+
+set(SolarisStudio126_CXX14 "(__SUNPRO_CC >= 0x5150) && __cplusplus >= 201402L")
+set(_cmake_feature_test_cxx_aggregate_default_initializers "${SolarisStudio126_CXX14}")
+set(_cmake_feature_test_cxx_digit_separators "${SolarisStudio126_CXX14}")
+set(_cmake_feature_test_cxx_generic_lambdas "${SolarisStudio126_CXX14}")
+set(_cmake_feature_test_cxx_lambda_init_captures "${SolarisStudio126_CXX14}")
+set(_cmake_feature_test_cxx_return_type_deduction "${SolarisStudio126_CXX14}")
+set(_cmake_feature_test_cxx_variable_templates "${SolarisStudio126_CXX14}")
+
+set(SolarisStudio126_CXX11 "(__SUNPRO_CC >= 0x5150) && __cplusplus >= 201103L")
+set(_cmake_feature_test_cxx_decltype_auto "${SolarisStudio126_CXX11}")
+
+set(SolarisStudio125_CXX11 "(__SUNPRO_CC >= 0x5140) && __cplusplus >= 201103L")
+set(_cmake_feature_test_cxx_binary_literals "${SolarisStudio125_CXX11}")
+set(_cmake_feature_test_cxx_reference_qualified_functions "${SolarisStudio125_CXX11}")
+
+set(SolarisStudio124_CXX11 "(__SUNPRO_CC >= 0x5130) && __cplusplus >= 201103L")
+set(_cmake_feature_test_cxx_alignas "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_alignof "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_attributes "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_inheriting_constructors "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_thread_local "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_alias_templates "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_delegating_constructors "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_extended_friend_declarations "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_final "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_noexcept "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_nonstatic_member_init "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_override "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_constexpr "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_defaulted_move_initializers "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_enum_forward_declarations "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_nullptr "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_range_for "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_unrestricted_unions "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_explicit_conversions "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_lambdas "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_local_type_template_args "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_raw_string_literals "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_auto_type "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_defaulted_functions "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_deleted_functions "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_generalized_initializers "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_inline_namespaces "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_sizeof_member "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_strong_enums "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_trailing_return_types "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_unicode_literals "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_uniform_initialization "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_variadic_templates "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_decltype "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_default_function_template_args "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_long_long_type "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_right_angle_brackets "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_rvalue_references "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_static_assert "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_extern_templates "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_func_identifier "${SolarisStudio124_CXX11}")
+set(_cmake_feature_test_cxx_variadic_macros "${SolarisStudio124_CXX11}")
+
+set(_cmake_feature_test_cxx_template_template_parameters "${_cmake_oldestSupported} && __cplusplus")
diff --git a/Modules/Compiler/SunPro-CXX.cmake b/Modules/Compiler/SunPro-CXX.cmake
new file mode 100644
index 0000000..aa8a9c5
--- /dev/null
+++ b/Modules/Compiler/SunPro-CXX.cmake
@@ -0,0 +1,66 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Compiler/SunPro)
+
+set(CMAKE_CXX_VERBOSE_FLAG "-v")
+
+set(CMAKE_CXX_COMPILE_OPTIONS_PIC -KPIC)
+set(CMAKE_CXX_COMPILE_OPTIONS_PIE "")
+set(_CMAKE_CXX_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+set(CMAKE_CXX_LINK_OPTIONS_PIE "")
+set(CMAKE_CXX_LINK_OPTIONS_NO_PIE "")
+set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "-KPIC")
+set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-G")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG "-R")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP ":")
+set(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-h")
+
+string(APPEND CMAKE_CXX_FLAGS_INIT " ")
+string(APPEND CMAKE_CXX_FLAGS_DEBUG_INIT " -g")
+string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -xO2 -xspace -DNDEBUG")
+string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -xO3 -DNDEBUG")
+string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -g -xO2 -DNDEBUG")
+
+set(CMAKE_DEPFILE_FLAGS_CXX "-xMD -xMF <DEP_FILE>")
+
+# Initialize C link type selection flags. These flags are used when
+# building a shared library, shared module, or executable that links
+# to other libraries to select whether to use the static or shared
+# versions of the libraries.
+foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+ set(CMAKE_${type}_LINK_STATIC_CXX_FLAGS "-Bstatic")
+ set(CMAKE_${type}_LINK_DYNAMIC_CXX_FLAGS "-Bdynamic")
+endforeach()
+
+set(CMAKE_CXX_LINKER_WRAPPER_FLAG "-Qoption" "ld" " ")
+set(CMAKE_CXX_LINKER_WRAPPER_FLAG_SEP ",")
+
+set(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+set(CMAKE_CXX_CREATE_ASSEMBLY_SOURCE "<CMAKE_CXX_COMPILER> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+
+# Create archives with "CC -xar" in case user adds "-instances=extern"
+# so that template instantiations are available to archive members.
+set(CMAKE_CXX_CREATE_STATIC_LIBRARY
+ "<CMAKE_CXX_COMPILER> -xar -o <TARGET> <OBJECTS> "
+ "<CMAKE_RANLIB> <TARGET> ")
+
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++03")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=c++03")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=c++11")
+ set(CMAKE_CXX_LINK_WITH_STANDARD_COMPILE_OPTION 1)
+
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.14)
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=c++14")
+ endif()
+else()
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-library=stlport4")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-library=stlport4")
+ set(CMAKE_CXX_LINK_WITH_STANDARD_COMPILE_OPTION 1)
+endif()
+
+__compiler_check_default_language_standard(CXX 1 98)
diff --git a/Modules/Compiler/SunPro-Fortran.cmake b/Modules/Compiler/SunPro-Fortran.cmake
new file mode 100644
index 0000000..0ba5015
--- /dev/null
+++ b/Modules/Compiler/SunPro-Fortran.cmake
@@ -0,0 +1,34 @@
+set(CMAKE_Fortran_VERBOSE_FLAG "-v")
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-fixed")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-free")
+
+set(CMAKE_Fortran_COMPILE_OPTIONS_PIC "-KPIC")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PIE "")
+set(_CMAKE_Fortran_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+set(CMAKE_Fortran_LINK_OPTIONS_PIE "")
+set(CMAKE_Fortran_LINK_OPTIONS_NO_PIE "")
+set(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-KPIC")
+set(CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS "-G")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG "-R")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP ":")
+set(CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG "-h")
+set(CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG "-R")
+
+string(APPEND CMAKE_Fortran_FLAGS_INIT " ")
+string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -g")
+string(APPEND CMAKE_Fortran_FLAGS_MINSIZEREL_INIT " -xO2 -xspace -DNDEBUG")
+string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -xO3 -DNDEBUG")
+string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -g -xO2 -DNDEBUG")
+set(CMAKE_Fortran_MODDIR_FLAG "-moddir=")
+set(CMAKE_Fortran_MODPATH_FLAG "-M")
+
+set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Qoption" "ld" " ")
+set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
+
+set(CMAKE_Fortran_PREPROCESS_SOURCE
+ "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -F -fpp <SOURCE> -o <PREPROCESSED_SOURCE>")
+
+set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -F -fpp <SOURCE> -o <PREPROCESSED_SOURCE>")
+set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-fpp")
diff --git a/Modules/Compiler/SunPro.cmake b/Modules/Compiler/SunPro.cmake
new file mode 100644
index 0000000..52da39a
--- /dev/null
+++ b/Modules/Compiler/SunPro.cmake
@@ -0,0 +1,10 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_SUNPRO)
+ return()
+endif()
+set(__COMPILER_SUNPRO 1)
+
+include(Compiler/CMakeCommonCompilerMacros)
diff --git a/Modules/Compiler/TI-ASM.cmake b/Modules/Compiler/TI-ASM.cmake
new file mode 100644
index 0000000..01965d2
--- /dev/null
+++ b/Modules/Compiler/TI-ASM.cmake
@@ -0,0 +1,4 @@
+include(Compiler/TI)
+__compiler_ti(ASM)
+
+set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS asm;s;abs)
diff --git a/Modules/Compiler/TI-C.cmake b/Modules/Compiler/TI-C.cmake
new file mode 100644
index 0000000..bd88989
--- /dev/null
+++ b/Modules/Compiler/TI-C.cmake
@@ -0,0 +1,67 @@
+include(Compiler/TI)
+__compiler_ti(C)
+
+# Architecture specific
+# C99 versions: https://processors.wiki.ti.com/index.php/C99_Support_in_TI_Compilers
+
+if("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
+ set(__COMPILER_TI_C99_VERSION_ARM 5.2)
+ set(__COMPILER_TI_C11_VERSION_ARM 18.12)
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430")
+ set(__COMPILER_TI_C99_VERSION_MSP430 4.3)
+ set(__COMPILER_TI_C11_VERSION_MSP430 18.12)
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "TMS320C28x")
+ set(__COMPILER_TI_C99_VERSION_TMS320C28x 6.3)
+ set(__COMPILER_TI_C11_VERSION_TMS320C28x 18.9)
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "TMS320C6x")
+ set(__COMPILER_TI_C99_VERSION_TMS320C6x 7.5)
+
+else()
+ # architecture not handled
+ return()
+
+endif()
+
+
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL "${__COMPILER_TI_C99_VERSION_${CMAKE_C_COMPILER_ARCHITECTURE_ID}}")
+
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "--c89" "--strict_ansi")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "--c89" "--relaxed_ansi")
+
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "--c99" "--strict_ansi")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "--c99" "--relaxed_ansi")
+
+ if(DEFINED __COMPILER_TI_C11_VERSION_${CMAKE_C_COMPILER_ARCHITECTURE_ID} AND
+ CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL "${__COMPILER_TI_C11_VERSION_${CMAKE_C_COMPILER_ARCHITECTURE_ID}}")
+
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "--c11" "--strict_ansi")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "--c11" "--relaxed_ansi")
+
+ endif()
+
+else()
+
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "--strict_ansi")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "--relaxed_ansi")
+
+endif()
+
+
+# Architecture specific
+
+if("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
+ __compiler_check_default_language_standard(C 2.0 90)
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430")
+ __compiler_check_default_language_standard(C 3.0 90)
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "TMS320C28x")
+ __compiler_check_default_language_standard(C 4.1 90)
+
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "TMS320C6x")
+ __compiler_check_default_language_standard(C 4.45 90)
+
+endif()
diff --git a/Modules/Compiler/TI-CXX.cmake b/Modules/Compiler/TI-CXX.cmake
new file mode 100644
index 0000000..4b6efcd
--- /dev/null
+++ b/Modules/Compiler/TI-CXX.cmake
@@ -0,0 +1,71 @@
+include(Compiler/TI)
+__compiler_ti(CXX)
+
+# Architecture specific
+
+if("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
+ set(__COMPILER_TI_CXX03_VERSION 5.2)
+ set(__COMPILER_TI_CXX14_VERSION 18.1)
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430")
+ set(__COMPILER_TI_CXX03_VERSION 4.4)
+ set(__COMPILER_TI_CXX14_VERSION 18.1)
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "TMS320C28x")
+ set(__COMPILER_TI_CXX03_VERSION 16.9)
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "TMS320C6x")
+ set(__COMPILER_TI_CXX03_VERSION 8.1)
+ set(__COMPILER_TI_CXX14_VERSION 8.3)
+
+else()
+ # architecture not handled
+ return()
+
+endif()
+
+
+if(DEFINED __COMPILER_TI_CXX14_VERSION AND
+ CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "${__COMPILER_TI_CXX14_VERSION}")
+
+ # C++03 is not supported anymore
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "--strict_ansi")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "--relaxed_ansi")
+
+ # C++11 was never supported
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "--strict_ansi")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "--relaxed_ansi")
+
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "--c++14" "--strict_ansi")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "--c++14" "--relaxed_ansi")
+
+
+elseif(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "${__COMPILER_TI_CXX03_VERSION}")
+
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "--c++03" "--strict_ansi")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "--c++03" "--relaxed_ansi")
+
+else()
+
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "--strict_ansi")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "--relaxed_ansi")
+
+endif()
+
+
+# Architecture specific
+# CXX98 versions: https://processors.wiki.ti.com/index.php/C%2B%2B_Support_in_TI_Compilers
+
+if("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
+ __compiler_check_default_language_standard(CXX 4.5 98 ${__COMPILER_TI_CXX14_VERSION} 14)
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430")
+ __compiler_check_default_language_standard(CXX 3.0 98 ${__COMPILER_TI_CXX14_VERSION} 14)
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "TMS320C28x")
+ __compiler_check_default_language_standard(CXX 5.1 98)
+
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "TMS320C6x")
+ __compiler_check_default_language_standard(CXX 6.1 98 ${__COMPILER_TI_CXX14_VERSION} 14)
+
+endif()
diff --git a/Modules/Compiler/TI-DetermineCompiler.cmake b/Modules/Compiler/TI-DetermineCompiler.cmake
new file mode 100644
index 0000000..19aa9e3
--- /dev/null
+++ b/Modules/Compiler/TI-DetermineCompiler.cmake
@@ -0,0 +1,8 @@
+
+set(_compiler_id_pp_test "defined(__TI_COMPILER_VERSION__)")
+
+set(_compiler_id_version_compute "
+ /* __TI_COMPILER_VERSION__ = VVVRRRPPP */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__TI_COMPILER_VERSION__/1000000)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__TI_COMPILER_VERSION__/1000 % 1000)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__TI_COMPILER_VERSION__ % 1000)")
diff --git a/Modules/Compiler/TI.cmake b/Modules/Compiler/TI.cmake
new file mode 100644
index 0000000..c8c1635
--- /dev/null
+++ b/Modules/Compiler/TI.cmake
@@ -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.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_TI)
+ return()
+endif()
+set(__COMPILER_TI 1)
+
+include(Compiler/CMakeCommonCompilerMacros)
+
+set(__COMPILER_TI_SOURCE_FLAG_C "--c_file")
+set(__COMPILER_TI_SOURCE_FLAG_CXX "--cpp_file")
+set(__COMPILER_TI_SOURCE_FLAG_ASM "--asm_file")
+
+macro(__compiler_ti lang)
+ set(CMAKE_${lang}_RESPONSE_FILE_FLAG "--cmd_file=")
+
+ set(CMAKE_INCLUDE_FLAG_${lang} "--include_path=")
+ set(CMAKE_DEPFILE_FLAGS_${lang} "--preproc_with_compile --preproc_dependency=<DEP_FILE>")
+
+ set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> --preproc_only ${__COMPILER_TI_SOURCE_FLAG_${lang}}=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<PREPROCESSED_SOURCE>")
+ set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> --compile_only --skip_assembler ${__COMPILER_TI_SOURCE_FLAG_${lang}}=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<ASSEMBLY_SOURCE>")
+
+ set(CMAKE_${lang}_COMPILE_OBJECT "<CMAKE_${lang}_COMPILER> --compile_only ${__COMPILER_TI_SOURCE_FLAG_${lang}}=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<OBJECT>")
+
+ set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> qr <TARGET> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> qa <TARGET> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_FINISH "")
+
+ # After the --run_linker flag a response file is not possible
+ set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "")
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_LIBRARIES 0)
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_OBJECTS 0)
+
+ set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_${lang}_COMPILER> <FLAGS> --run_linker --output_file=<TARGET> --map_file=<TARGET_NAME>.map <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES>")
+endmacro()
+
+set(CMAKE_LIBRARY_PATH_FLAG "--search_path=")
+set(CMAKE_LINK_LIBRARY_FLAG "--library=")
diff --git a/Modules/Compiler/TinyCC-C-DetermineCompiler.cmake b/Modules/Compiler/TinyCC-C-DetermineCompiler.cmake
new file mode 100644
index 0000000..8d6de7e
--- /dev/null
+++ b/Modules/Compiler/TinyCC-C-DetermineCompiler.cmake
@@ -0,0 +1,2 @@
+
+set(_compiler_id_pp_test "defined(__TINYC__)")
diff --git a/Modules/Compiler/TinyCC-C.cmake b/Modules/Compiler/TinyCC-C.cmake
new file mode 100644
index 0000000..6367695
--- /dev/null
+++ b/Modules/Compiler/TinyCC-C.cmake
@@ -0,0 +1,11 @@
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared")
+
+# no optimization in tcc:
+string(APPEND CMAKE_C_FLAGS_INIT " ")
+string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -g")
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
+string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -g -DNDEBUG")
+
+set(CMAKE_C_LINKER_WRAPPER_FLAG "-Wl,")
+set(CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",")
diff --git a/Modules/Compiler/VisualAge-C-DetermineCompiler.cmake b/Modules/Compiler/VisualAge-C-DetermineCompiler.cmake
new file mode 100644
index 0000000..97c2263
--- /dev/null
+++ b/Modules/Compiler/VisualAge-C-DetermineCompiler.cmake
@@ -0,0 +1,4 @@
+
+set(_compiler_id_pp_test "defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ < 800")
+
+include("${CMAKE_CURRENT_LIST_DIR}/IBMCPP-C-DetermineVersionInternal.cmake")
diff --git a/Modules/Compiler/VisualAge-C.cmake b/Modules/Compiler/VisualAge-C.cmake
new file mode 100644
index 0000000..40b609e
--- /dev/null
+++ b/Modules/Compiler/VisualAge-C.cmake
@@ -0,0 +1 @@
+include(Compiler/XL-C)
diff --git a/Modules/Compiler/VisualAge-CXX-DetermineCompiler.cmake b/Modules/Compiler/VisualAge-CXX-DetermineCompiler.cmake
new file mode 100644
index 0000000..cd53499
--- /dev/null
+++ b/Modules/Compiler/VisualAge-CXX-DetermineCompiler.cmake
@@ -0,0 +1,4 @@
+
+set(_compiler_id_pp_test "defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800")
+
+include("${CMAKE_CURRENT_LIST_DIR}/IBMCPP-CXX-DetermineVersionInternal.cmake")
diff --git a/Modules/Compiler/VisualAge-CXX.cmake b/Modules/Compiler/VisualAge-CXX.cmake
new file mode 100644
index 0000000..2509b43
--- /dev/null
+++ b/Modules/Compiler/VisualAge-CXX.cmake
@@ -0,0 +1 @@
+include(Compiler/XL-CXX)
diff --git a/Modules/Compiler/VisualAge-Fortran.cmake b/Modules/Compiler/VisualAge-Fortran.cmake
new file mode 100644
index 0000000..3ef3178
--- /dev/null
+++ b/Modules/Compiler/VisualAge-Fortran.cmake
@@ -0,0 +1 @@
+include(Compiler/XL-Fortran)
diff --git a/Modules/Compiler/Watcom-DetermineCompiler.cmake b/Modules/Compiler/Watcom-DetermineCompiler.cmake
new file mode 100644
index 0000000..153e350
--- /dev/null
+++ b/Modules/Compiler/Watcom-DetermineCompiler.cmake
@@ -0,0 +1,10 @@
+
+set(_compiler_id_pp_test "defined(__WATCOMC__) && __WATCOMC__ < 1200")
+
+set(_compiler_id_version_compute "
+ /* __WATCOMC__ = VVRR */
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__WATCOMC__ / 100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@((__WATCOMC__ / 10) % 10)
+# if (__WATCOMC__ % 10) > 0
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__WATCOMC__ % 10)
+# endif")
diff --git a/Modules/Compiler/XL-ASM.cmake b/Modules/Compiler/XL-ASM.cmake
new file mode 100644
index 0000000..9177b39
--- /dev/null
+++ b/Modules/Compiler/XL-ASM.cmake
@@ -0,0 +1,12 @@
+set(CMAKE_ASM_VERBOSE_FLAG "-V")
+
+# -qthreaded = Ensures that all optimizations will be thread-safe
+# -qhalt=e = Halt on error messages (rather than just severe errors)
+string(APPEND CMAKE_ASM_FLAGS_INIT " -qthreaded -qhalt=e -qsourcetype=assembler")
+
+string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -g")
+string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -O -DNDEBUG")
+string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -O -DNDEBUG")
+string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -g -DNDEBUG")
+
+set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s )
diff --git a/Modules/Compiler/XL-C-DetermineCompiler.cmake b/Modules/Compiler/XL-C-DetermineCompiler.cmake
new file mode 100644
index 0000000..3f4e05c
--- /dev/null
+++ b/Modules/Compiler/XL-C-DetermineCompiler.cmake
@@ -0,0 +1,4 @@
+
+set(_compiler_id_pp_test "defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ >= 800")
+
+include("${CMAKE_CURRENT_LIST_DIR}/IBMCPP-C-DetermineVersionInternal.cmake")
diff --git a/Modules/Compiler/XL-C.cmake b/Modules/Compiler/XL-C.cmake
new file mode 100644
index 0000000..2077bda
--- /dev/null
+++ b/Modules/Compiler/XL-C.cmake
@@ -0,0 +1,23 @@
+include(Compiler/XL)
+__compiler_xl(C)
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+
+# -qthreaded = Ensures that all optimizations will be thread-safe
+string(APPEND CMAKE_C_FLAGS_INIT " -qthreaded")
+
+if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.1)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "-qlanglvl=stdc89")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-qlanglvl=extc89")
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "-qlanglvl=stdc99")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-qlanglvl=extc99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+ if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.1)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-qlanglvl=extc1x")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-qlanglvl=extc1x")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+ endif ()
+endif()
+
+__compiler_check_default_language_standard(C 10.1 90 11.1 99)
diff --git a/Modules/Compiler/XL-CXX-DetermineCompiler.cmake b/Modules/Compiler/XL-CXX-DetermineCompiler.cmake
new file mode 100644
index 0000000..dffa4bc
--- /dev/null
+++ b/Modules/Compiler/XL-CXX-DetermineCompiler.cmake
@@ -0,0 +1,4 @@
+
+set(_compiler_id_pp_test "defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800")
+
+include("${CMAKE_CURRENT_LIST_DIR}/IBMCPP-CXX-DetermineVersionInternal.cmake")
diff --git a/Modules/Compiler/XL-CXX.cmake b/Modules/Compiler/XL-CXX.cmake
new file mode 100644
index 0000000..41e3e11
--- /dev/null
+++ b/Modules/Compiler/XL-CXX.cmake
@@ -0,0 +1,37 @@
+include(Compiler/XL)
+__compiler_xl(CXX)
+string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -DNDEBUG")
+string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+
+# -qthreaded = Ensures that all optimizations will be thread-safe
+string(APPEND CMAKE_CXX_FLAGS_INIT " -qthreaded")
+
+if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.1)
+ if(CMAKE_SYSTEM MATCHES "Linux")
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+ else()
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-qlanglvl=strict98")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-qlanglvl=extended")
+ endif()
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-qlanglvl=extended0x")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-qlanglvl=extended0x")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+
+ # XL does not really have full C++11 or C++14 support, but since we do not
+ # have a granular XL-CXX-FeatureTests table for it just pretend it does.
+ # This way projects that specify granular features will at least get a
+ # compiler mode for the corresponding standard.
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.1.0 AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-qlanglvl=extended1y")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-qlanglvl=extended1y")
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+ endif()
+endif ()
+
+__compiler_check_default_language_standard(CXX 10.1 98)
+
+set(CMAKE_CXX_COMPILE_OBJECT
+ "<CMAKE_CXX_COMPILER> -+ <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
diff --git a/Modules/Compiler/XL-Fortran.cmake b/Modules/Compiler/XL-Fortran.cmake
new file mode 100644
index 0000000..cc15e65
--- /dev/null
+++ b/Modules/Compiler/XL-Fortran.cmake
@@ -0,0 +1,30 @@
+include(Compiler/XL)
+__compiler_xl(Fortran)
+
+set(CMAKE_Fortran_SUBMODULE_SEP "_")
+set(CMAKE_Fortran_SUBMODULE_EXT ".smod")
+
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-qfixed") # [=<right_margin>]
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-qfree") # [=f90|ibm]
+
+set(CMAKE_Fortran_MODDIR_FLAG "-qmoddir=")
+set(CMAKE_Fortran_MODDIR_INCLUDE_FLAG "-I") # -qmoddir= does not affect search path
+
+set(CMAKE_Fortran_DEFINE_FLAG "-WF,-D")
+
+# -qthreaded = Ensures that all optimizations will be thread-safe
+# -qhalt=e = Halt on error messages (rather than just severe errors)
+string(APPEND CMAKE_Fortran_FLAGS_INIT " -qthreaded -qhalt=e")
+
+# xlf: 1501-214 (W) command option E reserved for future use - ignored
+set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE)
+set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE)
+
+set(CMAKE_Fortran_PREPROCESS_SOURCE
+ "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -qpreprocess -qnoobject -qsuppress=1517-020 -tF -B \"${CMAKE_CURRENT_LIST_DIR}/XL-Fortran/\" -WF,--cpp,\"${CMAKE_Fortran_XL_CPP}\",--out,<PREPROCESSED_SOURCE> <SOURCE>"
+ )
+
+if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 15.1.6)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-qpreprocess")
+ set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-qnopreprocess")
+endif()
diff --git a/Modules/Compiler/XL-Fortran/cpp b/Modules/Compiler/XL-Fortran/cpp
new file mode 100755
index 0000000..1fd62c2
--- /dev/null
+++ b/Modules/Compiler/XL-Fortran/cpp
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+# Source file.
+src="$(printf %q "$1")"
+shift
+
+# Output file the compiler expects.
+out="$(printf %q "$1")"
+shift
+
+# Create the file the compiler expects. It will check syntax.
+>"$out"
+
+cpp='cpp'
+opts=''
+while test "$#" != 0; do
+ case "$1" in
+ # Extract the option for the path to cpp.
+ --cpp) shift; cpp="$(printf %q "$1")" ;;
+ # Extract the option for our own output file.
+ --out) shift; out="$(printf %q "$1")" ;;
+ # Collect the rest of the command line.
+ *) opts="$opts $(printf %q "$1")" ;;
+ esac
+ shift
+done
+
+# Execute the real preprocessor tool.
+eval "exec $cpp $src $out $opts"
diff --git a/Modules/Compiler/XL.cmake b/Modules/Compiler/XL.cmake
new file mode 100644
index 0000000..8b9d4a9
--- /dev/null
+++ b/Modules/Compiler/XL.cmake
@@ -0,0 +1,34 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_XL)
+ return()
+endif()
+set(__COMPILER_XL 1)
+
+include(Compiler/CMakeCommonCompilerMacros)
+
+macro(__compiler_xl lang)
+ # Feature flags.
+ set(CMAKE_${lang}_VERBOSE_FLAG "-V")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-qpic")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-qpic")
+ set(CMAKE_${lang}_RESPONSE_FILE_FLAG "-qoptfile=")
+ set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-qoptfile=")
+
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-qmkshrobj")
+
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -O")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -g")
+ set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+ set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+
+ set(CMAKE_DEPFILE_FLAGS_${lang} "-MF <DEP_FILE> -qmakedep=gcc")
+endmacro()
diff --git a/Modules/Compiler/XLClang-C-DetermineCompiler.cmake b/Modules/Compiler/XLClang-C-DetermineCompiler.cmake
new file mode 100644
index 0000000..4d89921
--- /dev/null
+++ b/Modules/Compiler/XLClang-C-DetermineCompiler.cmake
@@ -0,0 +1,8 @@
+set(_compiler_id_pp_test "defined(__ibmxl__) && defined(__clang__)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__ibmxl_version__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__ibmxl_release__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__ibmxl_modification__)
+# define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(__ibmxl_ptf_fix_level__)
+")
diff --git a/Modules/Compiler/XLClang-C.cmake b/Modules/Compiler/XLClang-C.cmake
new file mode 100644
index 0000000..1668a4d
--- /dev/null
+++ b/Modules/Compiler/XLClang-C.cmake
@@ -0,0 +1,22 @@
+include(Compiler/XLClang)
+__compiler_xlclang(C)
+
+set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
+
+if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.1)
+ set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c89")
+ set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu89")
+ set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
+ set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+ set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-qlanglvl=extc1x")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-qlanglvl=extc1x")
+ if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.2)
+ set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
+ set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+ set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+ endif ()
+endif()
+
+__compiler_check_default_language_standard(C 13.1.1 99)
diff --git a/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake b/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake
new file mode 100644
index 0000000..4d89921
--- /dev/null
+++ b/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake
@@ -0,0 +1,8 @@
+set(_compiler_id_pp_test "defined(__ibmxl__) && defined(__clang__)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__ibmxl_version__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__ibmxl_release__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__ibmxl_modification__)
+# define @PREFIX@COMPILER_VERSION_TWEAK @MACRO_DEC@(__ibmxl_ptf_fix_level__)
+")
diff --git a/Modules/Compiler/XLClang-CXX.cmake b/Modules/Compiler/XLClang-CXX.cmake
new file mode 100644
index 0000000..02638c7
--- /dev/null
+++ b/Modules/Compiler/XLClang-CXX.cmake
@@ -0,0 +1,29 @@
+include(Compiler/XLClang)
+__compiler_xlclang(CXX)
+
+set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
+
+if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.1)
+ set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+ set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-qlanglvl=extended0x")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-qlanglvl=extended0x")
+ set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.2)
+ set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
+ set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++1y")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y")
+ set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+ endif ()
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.1.0)
+ set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14")
+ endif()
+endif()
+
+__compiler_check_default_language_standard(CXX 13.1.1 98)
+
+set(CMAKE_CXX_COMPILE_OBJECT
+ "<CMAKE_CXX_COMPILER> -x c++ <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
diff --git a/Modules/Compiler/XLClang.cmake b/Modules/Compiler/XLClang.cmake
new file mode 100644
index 0000000..cdf0fdc
--- /dev/null
+++ b/Modules/Compiler/XLClang.cmake
@@ -0,0 +1,22 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_XLCLANG)
+ return()
+endif()
+set(__COMPILER_XLCLANG 1)
+
+include(Compiler/XL)
+
+macro(__compiler_xlclang lang)
+ __compiler_xl(${lang})
+
+ # Feature flags.
+ set(CMAKE_${lang}_VERBOSE_FLAG "-V")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIC")
+ set(CMAKE_${lang}_RESPONSE_FILE_FLAG "@")
+ set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "@")
+endmacro()
diff --git a/Modules/Compiler/zOS-C-DetermineCompiler.cmake b/Modules/Compiler/zOS-C-DetermineCompiler.cmake
new file mode 100644
index 0000000..daa3781
--- /dev/null
+++ b/Modules/Compiler/zOS-C-DetermineCompiler.cmake
@@ -0,0 +1,4 @@
+
+set(_compiler_id_pp_test "defined(__IBMC__) && defined(__COMPILER_VER__)")
+
+include("${CMAKE_CURRENT_LIST_DIR}/IBMCPP-C-DetermineVersionInternal.cmake")
diff --git a/Modules/Compiler/zOS-CXX-DetermineCompiler.cmake b/Modules/Compiler/zOS-CXX-DetermineCompiler.cmake
new file mode 100644
index 0000000..a08ff57
--- /dev/null
+++ b/Modules/Compiler/zOS-CXX-DetermineCompiler.cmake
@@ -0,0 +1,4 @@
+
+set(_compiler_id_pp_test "defined(__IBMCPP__) && defined(__COMPILER_VER__)")
+
+include("${CMAKE_CURRENT_LIST_DIR}/IBMCPP-CXX-DetermineVersionInternal.cmake")
diff --git a/Modules/CompilerId/GHS_default.gpj.in b/Modules/CompilerId/GHS_default.gpj.in
new file mode 100644
index 0000000..b5cea5c
--- /dev/null
+++ b/Modules/CompilerId/GHS_default.gpj.in
@@ -0,0 +1,8 @@
+#!gbuild
+@bsp_name@
+@os_dir@
+primaryTarget=@ghs_primary_target@
+[Project]
+ {isdefined(GHS_BSP)} -bsp $GHS_BSP
+ {isdefined(GHS_OS)} -os_dir $GHS_OS
+GHS_lib.gpj [Library]
diff --git a/Modules/CompilerId/GHS_lib.gpj.in b/Modules/CompilerId/GHS_lib.gpj.in
new file mode 100644
index 0000000..149b981
--- /dev/null
+++ b/Modules/CompilerId/GHS_lib.gpj.in
@@ -0,0 +1,3 @@
+#!gbuild
+[Library]
+@id_src@
diff --git a/Modules/CompilerId/VS-10.csproj.in b/Modules/CompilerId/VS-10.csproj.in
new file mode 100644
index 0000000..ed5e847
--- /dev/null
+++ b/Modules/CompilerId/VS-10.csproj.in
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{CAE07175-D007-4FC3-BFE8-47B392814159}</ProjectGuid>
+ <RootNamespace>CompilerId@id_lang@</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ @id_system@
+ @id_system_version@
+ @id_WindowsTargetPlatformVersion@
+ @id_WindowsSDKDesktopARMSupport@
+ </PropertyGroup>
+ <PropertyGroup>
+ @id_PreferredToolArchitecture@
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@id_platform@'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ @id_toolset@
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <!-- ============================================================ -->
+ <!-- == set preprocessor definitions == -->
+ <!-- ============================================================ -->
+ <PropertyGroup>
+ <DefineConstants></DefineConstants>
+ <UnknownValue>Unknown</UnknownValue>
+ </PropertyGroup>
+ <!-- Platform -->
+ <PropertyGroup Condition="'$(Platform)'!=''">
+ <DefineConstants>$(DefineConstants);Platform$(Platform)</DefineConstants>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Platform)'==''">
+ <DefineConstants>$(DefineConstants);Platform$(UnknownValue)</DefineConstants>
+ </PropertyGroup>
+ <!-- PlatformToolset -->
+ <PropertyGroup Condition="'$(PlatformToolset)'!=''">
+ <DefineConstants>$(DefineConstants);PlatformToolset$(PlatformToolset)</DefineConstants>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(PlatformToolset)'==''">
+ <DefineConstants>$(DefineConstants);PlatformToolset$(UnknownValue)</DefineConstants>
+ </PropertyGroup>
+ <!-- ============================================================ -->
+ <PropertyGroup>
+ <OutputPath Condition="'$(Configuration)|$(Platform)'=='Debug|@id_platform@'">.\</OutputPath>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="@id_src@" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <PropertyGroup>
+ <PostBuildEvent>if not "$(RoslynTargetsPath)"=="" if exist "$(RoslynTargetsPath)\@id_cl@" set _CSC=$(RoslynTargetsPath)
+if exist "$(MSBuildToolsPath)\@id_cl@" set _CSC=$(MSBuildToolsPath)
+if "%_CSC%"=="" exit -1
+%40echo CMAKE_@id_lang@_COMPILER=%_CSC%\@id_cl@</PostBuildEvent>
+ </PropertyGroup>
+</Project>
diff --git a/Modules/CompilerId/VS-10.vcxproj.in b/Modules/CompilerId/VS-10.vcxproj.in
new file mode 100644
index 0000000..3598fc7
--- /dev/null
+++ b/Modules/CompilerId/VS-10.vcxproj.in
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|@id_platform@">
+ <Configuration>Debug</Configuration>
+ <Platform>@id_platform@</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{CAE07175-D007-4FC3-BFE8-47B392814159}</ProjectGuid>
+ <RootNamespace>CompilerId@id_lang@</RootNamespace>
+ <Keyword>@id_keyword@</Keyword>
+ @id_system@
+ @id_system_version@
+ @id_WindowsTargetPlatformVersion@
+ @id_WindowsSDKDesktopARMSupport@
+ @id_CudaToolkitCustomDir@
+ @id_ToolsetVCTargetsDir@
+ @id_CustomGlobals@
+ </PropertyGroup>
+ @id_toolset_version_props@
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup>
+ @id_PreferredToolArchitecture@
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@id_platform@'" Label="Configuration">
+ <ConfigurationType>@id_config_type@</ConfigurationType>
+ @id_toolset@
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ @id_Import_props@
+ </ImportGroup>
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|@id_platform@'">.\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|@id_platform@'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|@id_platform@'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@id_platform@'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>TurnOffAllWarnings</WarningLevel>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ </ClCompile>
+ @id_ItemDefinitionGroup_entry@
+ <Link>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ @id_Link_AdditionalDependencies@
+ </Link>
+ <PostBuildEvent>
+ <Command>@id_PostBuildEvent_Command@</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <@id_compile@ Include="@id_src@" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ @id_Import_targets@
+ </ImportGroup>
+</Project>
diff --git a/Modules/CompilerId/VS-7.vcproj.in b/Modules/CompilerId/VS-7.vcproj.in
new file mode 100644
index 0000000..9e3c3c3
--- /dev/null
+++ b/Modules/CompilerId/VS-7.vcproj.in
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="@id_version@"
+ Name="CompilerId@id_lang@"
+ ProjectGUID="{CAE07175-D007-4FC3-BFE8-47B392814159}"
+ RootNamespace="CompilerId@id_lang@"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="@id_platform@"
+ />
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|@id_platform@"
+ OutputDirectory="."
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="0"
+ DebugInformationFormat="0"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ IgnoreDefaultLibraryNames="libc"
+ GenerateDebugInformation="false"
+ SubSystem="@id_subsystem@"
+ EntryPointSymbol="@id_entrypoint@"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="for %%i in (@id_cl@) do @echo CMAKE_@id_lang@_COMPILER=%%~$PATH:i"
+ />
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="@id_src@"
+ >
+ </File>
+ </Filter>
+ </Files>
+</VisualStudioProject>
diff --git a/Modules/CompilerId/VS-Intel.vfproj.in b/Modules/CompilerId/VS-Intel.vfproj.in
new file mode 100644
index 0000000..044dd20
--- /dev/null
+++ b/Modules/CompilerId/VS-Intel.vfproj.in
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<VisualStudioProject
+ ProjectCreator="Intel Fortran"
+ Keyword="Console Application"
+ Version="@CMAKE_VS_INTEL_Fortran_PROJECT_VERSION@"
+ ProjectIdGuid="{AB67BAB7-D7AE-4E97-B492-FE5420447509}"
+ >
+ <Platforms>
+ <Platform Name="@id_platform@"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|@id_platform@"
+ OutputDirectory="."
+ IntermediateDirectory="$(ConfigurationName)"
+ >
+ <Tool
+ Name="VFFortranCompilerTool"
+ DebugInformationFormat="debugEnabled"
+ Optimization="optimizeDisabled"
+ Preprocess="preprocessYes"
+ RuntimeLibrary="rtMultiThreadedDebugDLL"
+ />
+ <Tool
+ Name="VFLinkerTool"
+ LinkIncremental="linkIncrementalNo"
+ GenerateDebugInformation="true"
+ SubSystem="subSystemConsole"
+ />
+ <Tool
+ Name="VFPostBuildEventTool"
+ CommandLine="for %%i in (@id_cl@) do @echo CMAKE_@id_lang@_COMPILER=%%~$PATH:i"
+ />
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter Name="Source Files" Filter="F">
+ <File RelativePath="@id_src@"/>
+ </Filter>
+ </Files>
+ <Globals/>
+</VisualStudioProject>
diff --git a/Modules/CompilerId/VS-NsightTegra.vcxproj.in b/Modules/CompilerId/VS-NsightTegra.vcxproj.in
new file mode 100644
index 0000000..b7389eb
--- /dev/null
+++ b/Modules/CompilerId/VS-NsightTegra.vcxproj.in
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Label="NsightTegraProject">
+ <NsightTegraProjectRevisionNumber>6</NsightTegraProjectRevisionNumber>
+ </PropertyGroup>
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|@id_platform@">
+ <Configuration>Debug</Configuration>
+ <Platform>@id_platform@</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{CAE07175-D007-4FC3-BFE8-47B392814159}</ProjectGuid>
+ <RootNamespace>CompilerId@id_lang@</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@id_platform@'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ @id_toolset@
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|@id_platform@'">.\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|@id_platform@'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|@id_platform@'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@id_platform@'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ </Link>
+ <PostBuildEvent>
+ <Command>
+if "$(ToolchainName)"=="gcc" (
+ for %%i in ($(ToolchainPrebuiltRoot)\bin\*@id_gcc@.exe) do (
+ @echo CMAKE_@id_lang@_COMPILER=%%i
+ goto :done
+ )
+)
+if "$(ToolchainName)"=="clang" (
+ for %%i in ($(ToolchainPrebuiltRoot)\bin\*@id_clang@.exe) do (
+ @echo CMAKE_@id_lang@_COMPILER=%%i
+ goto :done
+ )
+)
+:done
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="@id_src@" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
diff --git a/Modules/CompilerId/Xcode-3.pbxproj.in b/Modules/CompilerId/Xcode-3.pbxproj.in
new file mode 100644
index 0000000..aab357a
--- /dev/null
+++ b/Modules/CompilerId/Xcode-3.pbxproj.in
@@ -0,0 +1,114 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+ 2C18F0B615DC1E0300593670 = {isa = PBXBuildFile; fileRef = 2C18F0B415DC1DC700593670; };
+ 2C18F0B415DC1DC700593670 = {isa = PBXFileReference; fileEncoding = 4; explicitFileType = @id_type@; path = @id_src@; sourceTree = "<group>"; };
+ 08FB7794FE84155DC02AAC07 = {
+ isa = PBXGroup;
+ children = (
+ 2C18F0B415DC1DC700593670,
+ );
+ name = CompilerId@id_lang@;
+ sourceTree = "<group>";
+ };
+ 8DD76FA90486AB0100D96B5E = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1DEB928508733DD80010E9CD;
+ buildPhases = (
+ 2C18F0B515DC1DCE00593670,
+ 2C8FEB8E15DC1A1A00E56A5D,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = CompilerId@id_lang@;
+ productName = CompilerId@id_lang@;
+ productType = "@id_product_type@";
+ };
+ 08FB7793FE84155DC02AAC07 = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB928908733DD80010E9CD;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 08FB7794FE84155DC02AAC07;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8DD76FA90486AB0100D96B5E,
+ );
+ };
+ 2C8FEB8E15DC1A1A00E56A5D = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "echo \"GCC_VERSION=$GCC_VERSION\" ; echo \"ARCHS=$ARCHS\"";
+ showEnvVarsInLog = 0;
+ };
+ 2C18F0B515DC1DCE00593670 = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2C18F0B615DC1E0300593670,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 1DEB928608733DD80010E9CD = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_IDENTITY = "";
+ PRODUCT_NAME = CompilerId@id_lang@;
+ };
+ name = Debug;
+ };
+ 1DEB928A08733DD80010E9CD = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGNING_REQUIRED = NO;
+ CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
+ SYMROOT = .;
+ @id_archs@
+ @id_arch_active@
+ @id_toolset@
+ @id_lang_version@
+ @id_clang_cxx_library@
+ @id_deployment_target@
+ @id_sdkroot@
+ };
+ name = Debug;
+ };
+ 1DEB928508733DD80010E9CD = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB928608733DD80010E9CD,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Debug;
+ };
+ 1DEB928908733DD80010E9CD = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB928A08733DD80010E9CD,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Debug;
+ };
+ };
+ rootObject = 08FB7793FE84155DC02AAC07;
+}
diff --git a/Modules/CompilerId/main.swift.in b/Modules/CompilerId/main.swift.in
new file mode 100644
index 0000000..13f0ba0
--- /dev/null
+++ b/Modules/CompilerId/main.swift.in
@@ -0,0 +1 @@
+print("CMakeSwiftCompilerId")
diff --git a/Modules/Dart.cmake b/Modules/Dart.cmake
new file mode 100644
index 0000000..154fe9d
--- /dev/null
+++ b/Modules/Dart.cmake
@@ -0,0 +1,125 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+Dart
+----
+
+Configure a project for testing with CTest or old Dart Tcl Client
+
+This file is the backwards-compatibility version of the CTest module.
+It supports using the old Dart 1 Tcl client for driving dashboard
+submissions as well as testing with CTest. This module should be
+included in the CMakeLists.txt file at the top of a project. Typical
+usage:
+
+::
+
+ include(Dart)
+ if(BUILD_TESTING)
+ # ... testing related CMake code ...
+ endif()
+
+The BUILD_TESTING option is created by the Dart module to determine
+whether testing support should be enabled. The default is ON.
+#]=======================================================================]
+
+# This file configures a project to use the Dart testing/dashboard process.
+# It is broken into 3 sections.
+#
+# Section #1: Locate programs on the client and determine site and build name
+# Section #2: Configure or copy Tcl scripts from the source tree to build tree
+# Section #3: Custom targets for performing dashboard builds.
+#
+#
+
+option(BUILD_TESTING "Build the testing tree." ON)
+
+if(BUILD_TESTING)
+ find_package(Dart QUIET)
+
+ #
+ # Section #1:
+ #
+ # CMake commands that will not vary from project to project. Locates programs
+ # on the client and configure site name and build name.
+ #
+
+ set(RUN_FROM_DART 1)
+ include(CTest)
+ set(RUN_FROM_DART)
+
+ find_program(COMPRESSIONCOMMAND NAMES gzip compress zip
+ DOC "Path to program used to compress files for transfer to the dart server")
+ find_program(GUNZIPCOMMAND gunzip DOC "Path to gunzip executable")
+ find_program(JAVACOMMAND java DOC "Path to java command, used by the Dart server to create html.")
+ option(DART_VERBOSE_BUILD "Show the actual output of the build, or if off show a . for each 1024 bytes."
+ OFF)
+ option(DART_BUILD_ERROR_REPORT_LIMIT "Limit of reported errors, -1 reports all." -1 )
+ option(DART_BUILD_WARNING_REPORT_LIMIT "Limit of reported warnings, -1 reports all." -1 )
+
+ set(VERBOSE_BUILD ${DART_VERBOSE_BUILD})
+ set(BUILD_ERROR_REPORT_LIMIT ${DART_BUILD_ERROR_REPORT_LIMIT})
+ set(BUILD_WARNING_REPORT_LIMIT ${DART_BUILD_WARNING_REPORT_LIMIT})
+ set (DELIVER_CONTINUOUS_EMAIL "Off" CACHE BOOL "Should Dart server send email when build errors are found in Continuous builds?")
+
+ mark_as_advanced(
+ COMPRESSIONCOMMAND
+ DART_BUILD_ERROR_REPORT_LIMIT
+ DART_BUILD_WARNING_REPORT_LIMIT
+ DART_TESTING_TIMEOUT
+ DART_VERBOSE_BUILD
+ DELIVER_CONTINUOUS_EMAIL
+ GUNZIPCOMMAND
+ JAVACOMMAND
+ )
+
+ set(HAVE_DART)
+ if(EXISTS "${DART_ROOT}/Source/Client/Dart.conf.in")
+ set(HAVE_DART 1)
+ endif()
+
+ #
+ # Section #2:
+ #
+ # Make necessary directories and configure testing scripts
+ #
+ # find a tcl shell command
+ if(HAVE_DART)
+ find_package(Tclsh)
+ endif()
+
+
+ if (HAVE_DART)
+ # make directories in the binary tree
+ file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/Testing/HTML/TestingResults/Dashboard"
+ "${PROJECT_BINARY_DIR}/Testing/HTML/TestingResults/Sites/${SITE}/${BUILDNAME}")
+
+ # configure files
+ configure_file(
+ "${DART_ROOT}/Source/Client/Dart.conf.in"
+ "${PROJECT_BINARY_DIR}/DartConfiguration.tcl" )
+
+ #
+ # Section 3:
+ #
+ # Custom targets to perform dashboard builds and submissions.
+ # These should NOT need to be modified from project to project.
+ #
+
+ # add testing targets
+ set(DART_EXPERIMENTAL_NAME Experimental)
+ if(DART_EXPERIMENTAL_USE_PROJECT_NAME)
+ string(APPEND DART_EXPERIMENTAL_NAME "${PROJECT_NAME}")
+ endif()
+ endif ()
+
+ set(RUN_FROM_CTEST_OR_DART 1)
+ include(CTestTargets)
+ set(RUN_FROM_CTEST_OR_DART)
+endif()
+
+#
+# End of Dart.cmake
+#
+
diff --git a/Modules/DartConfiguration.tcl.in b/Modules/DartConfiguration.tcl.in
new file mode 100644
index 0000000..e5b1e5d
--- /dev/null
+++ b/Modules/DartConfiguration.tcl.in
@@ -0,0 +1,105 @@
+# This file is configured by CMake automatically as DartConfiguration.tcl
+# If you choose not to use CMake, this file may be hand configured, by
+# filling in the required variables.
+
+
+# Configuration directories and files
+SourceDirectory: @PROJECT_SOURCE_DIR@
+BuildDirectory: @PROJECT_BINARY_DIR@
+
+# Where to place the cost data store
+CostDataFile: @CTEST_COST_DATA_FILE@
+
+# Site is something like machine.domain, i.e. pragmatic.crd
+Site: @SITE@
+
+# Build name is osname-revision-compiler, i.e. Linux-2.4.2-2smp-c++
+BuildName: @BUILDNAME@
+
+# Subprojects
+LabelsForSubprojects: @CTEST_LABELS_FOR_SUBPROJECTS@
+
+# Submission information
+SubmitURL: @SUBMIT_URL@
+
+# Dashboard start time
+NightlyStartTime: @NIGHTLY_START_TIME@
+
+# Commands for the build/test/submit cycle
+ConfigureCommand: "@CMAKE_COMMAND@" "@PROJECT_SOURCE_DIR@"
+MakeCommand: @MAKECOMMAND@
+DefaultCTestConfigurationType: @DEFAULT_CTEST_CONFIGURATION_TYPE@
+
+# version control
+UpdateVersionOnly: @CTEST_UPDATE_VERSION_ONLY@
+
+# CVS options
+# Default is "-d -P -A"
+CVSCommand: @CVSCOMMAND@
+CVSUpdateOptions: @CVS_UPDATE_OPTIONS@
+
+# Subversion options
+SVNCommand: @SVNCOMMAND@
+SVNOptions: @CTEST_SVN_OPTIONS@
+SVNUpdateOptions: @SVN_UPDATE_OPTIONS@
+
+# Git options
+GITCommand: @GITCOMMAND@
+GITInitSubmodules: @CTEST_GIT_INIT_SUBMODULES@
+GITUpdateOptions: @GIT_UPDATE_OPTIONS@
+GITUpdateCustom: @CTEST_GIT_UPDATE_CUSTOM@
+
+# Perforce options
+P4Command: @P4COMMAND@
+P4Client: @CTEST_P4_CLIENT@
+P4Options: @CTEST_P4_OPTIONS@
+P4UpdateOptions: @CTEST_P4_UPDATE_OPTIONS@
+P4UpdateCustom: @CTEST_P4_UPDATE_CUSTOM@
+
+# Generic update command
+UpdateCommand: @UPDATE_COMMAND@
+UpdateOptions: @UPDATE_OPTIONS@
+UpdateType: @UPDATE_TYPE@
+
+# Compiler info
+Compiler: @CMAKE_CXX_COMPILER@
+CompilerVersion: @CMAKE_CXX_COMPILER_VERSION@
+
+# Dynamic analysis (MemCheck)
+PurifyCommand: @PURIFYCOMMAND@
+ValgrindCommand: @VALGRIND_COMMAND@
+ValgrindCommandOptions: @VALGRIND_COMMAND_OPTIONS@
+DrMemoryCommand: @DRMEMORY_COMMAND@
+DrMemoryCommandOptions: @DRMEMORY_COMMAND_OPTIONS@
+CudaSanitizerCommand: @CUDA_SANITIZER_COMMAND@
+CudaSanitizerCommandOptions: @CUDA_SANITIZER_COMMAND_OPTIONS@
+MemoryCheckType: @MEMORYCHECK_TYPE@
+MemoryCheckSanitizerOptions: @MEMORYCHECK_SANITIZER_OPTIONS@
+MemoryCheckCommand: @MEMORYCHECK_COMMAND@
+MemoryCheckCommandOptions: @MEMORYCHECK_COMMAND_OPTIONS@
+MemoryCheckSuppressionFile: @MEMORYCHECK_SUPPRESSIONS_FILE@
+
+# Coverage
+CoverageCommand: @COVERAGE_COMMAND@
+CoverageExtraFlags: @COVERAGE_EXTRA_FLAGS@
+
+# Testing options
+# TimeOut is the amount of time in seconds to wait for processes
+# to complete during testing. After TimeOut seconds, the
+# process will be summarily terminated.
+# Currently set to 25 minutes
+TimeOut: @DART_TESTING_TIMEOUT@
+
+# During parallel testing CTest will not start a new test if doing
+# so would cause the system load to exceed this value.
+TestLoad: @CTEST_TEST_LOAD@
+
+UseLaunchers: @CTEST_USE_LAUNCHERS@
+CurlOptions: @CTEST_CURL_OPTIONS@
+# warning, if you add new options here that have to do with submit,
+# you have to update cmCTestSubmitCommand.cxx
+
+# For CTest submissions that timeout, these options
+# specify behavior for retrying the submission
+CTestSubmitRetryDelay: @CTEST_SUBMIT_RETRY_DELAY@
+CTestSubmitRetryCount: @CTEST_SUBMIT_RETRY_COUNT@
diff --git a/Modules/DeployQt4.cmake b/Modules/DeployQt4.cmake
new file mode 100644
index 0000000..9aa4383
--- /dev/null
+++ b/Modules/DeployQt4.cmake
@@ -0,0 +1,399 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+DeployQt4
+---------
+
+Functions to help assemble a standalone Qt4 executable.
+
+A collection of CMake utility functions useful for deploying Qt4
+executables.
+
+The following functions are provided by this module:
+
+::
+
+ write_qt4_conf
+ resolve_qt4_paths
+ fixup_qt4_executable
+ install_qt4_plugin_path
+ install_qt4_plugin
+ install_qt4_executable
+
+Requires CMake 2.6 or greater because it uses function and
+PARENT_SCOPE. Also depends on BundleUtilities.cmake.
+
+::
+
+ write_qt4_conf(<qt_conf_dir> <qt_conf_contents>)
+
+Writes a qt.conf file with the <qt_conf_contents> into <qt_conf_dir>.
+
+::
+
+ resolve_qt4_paths(<paths_var> [<executable_path>])
+
+Loop through <paths_var> list and if any don't exist resolve them
+relative to the <executable_path> (if supplied) or the
+CMAKE_INSTALL_PREFIX.
+
+::
+
+ fixup_qt4_executable(<executable>
+ [<qtplugins> <libs> <dirs> <plugins_dir> <request_qt_conf>])
+
+Copies Qt plugins, writes a Qt configuration file (if needed) and
+fixes up a Qt4 executable using BundleUtilities so it is standalone
+and can be drag-and-drop copied to another machine as long as all of
+the system libraries are compatible.
+
+<executable> should point to the executable to be fixed-up.
+
+<qtplugins> should contain a list of the names or paths of any Qt
+plugins to be installed.
+
+<libs> will be passed to BundleUtilities and should be a list of any
+already installed plugins, libraries or executables to also be
+fixed-up.
+
+<dirs> will be passed to BundleUtilities and should contain and
+directories to be searched to find library dependencies.
+
+<plugins_dir> allows an custom plugins directory to be used.
+
+<request_qt_conf> will force a qt.conf file to be written even if not
+needed.
+
+::
+
+ install_qt4_plugin_path(plugin executable copy installed_plugin_path_var
+ <plugins_dir> <component> <configurations>)
+
+Install (or copy) a resolved <plugin> to the default plugins directory
+(or <plugins_dir>) relative to <executable> and store the result in
+<installed_plugin_path_var>.
+
+If <copy> is set to TRUE then the plugins will be copied rather than
+installed. This is to allow this module to be used at CMake time
+rather than install time.
+
+If <component> is set then anything installed will use this COMPONENT.
+
+::
+
+ install_qt4_plugin(plugin executable copy installed_plugin_path_var
+ <plugins_dir> <component>)
+
+Install (or copy) an unresolved <plugin> to the default plugins
+directory (or <plugins_dir>) relative to <executable> and store the
+result in <installed_plugin_path_var>. See documentation of
+INSTALL_QT4_PLUGIN_PATH.
+
+::
+
+ install_qt4_executable(<executable>
+ [<qtplugins> <libs> <dirs> <plugins_dir> <request_qt_conf> <component>])
+
+Installs Qt plugins, writes a Qt configuration file (if needed) and
+fixes up a Qt4 executable using BundleUtilities so it is standalone
+and can be drag-and-drop copied to another machine as long as all of
+the system libraries are compatible. The executable will be fixed-up
+at install time. <component> is the COMPONENT used for bundle fixup
+and plugin installation. See documentation of FIXUP_QT4_BUNDLE.
+#]=======================================================================]
+
+# The functions defined in this file depend on the fixup_bundle function
+# (and others) found in BundleUtilities.cmake
+
+set(DeployQt4_apple_plugins_dir "PlugIns")
+
+function(write_qt4_conf qt_conf_dir qt_conf_contents)
+ set(qt_conf_path "${qt_conf_dir}/qt.conf")
+ message(STATUS "Writing ${qt_conf_path}")
+ file(WRITE "${qt_conf_path}" "${qt_conf_contents}")
+endfunction()
+
+function(resolve_qt4_paths paths_var)
+ unset(executable_path)
+ if(ARGC GREATER 1)
+ set(executable_path ${ARGV1})
+ endif()
+
+ set(paths_resolved)
+ foreach(path ${${paths_var}})
+ if(EXISTS "${path}")
+ list(APPEND paths_resolved "${path}")
+ else()
+ if(${executable_path})
+ list(APPEND paths_resolved "${executable_path}/${path}")
+ else()
+ list(APPEND paths_resolved "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${path}")
+ endif()
+ endif()
+ endforeach()
+ set(${paths_var} ${paths_resolved} PARENT_SCOPE)
+endfunction()
+
+cmake_policy(GET CMP0080 _cmp0080_value)
+if(NOT DEFINED CMAKE_GENERATOR OR NOT _cmp0080_value STREQUAL "NEW")
+ set(_CMP0080_SUPPRESS_WARNING TRUE)
+ include("${CMAKE_CURRENT_LIST_DIR}/BundleUtilities.cmake")
+ unset(_CMP0080_SUPPRESS_WARNING)
+
+ function(fixup_qt4_executable executable)
+ cmake_policy(GET CMP0080 _cmp0080_value)
+ if(_cmp0080_value STREQUAL "" AND DEFINED CMAKE_GENERATOR)
+ _warn_cmp0080()
+ endif()
+
+ unset(qtplugins)
+ if(ARGC GREATER 1)
+ set(qtplugins ${ARGV1})
+ endif()
+ unset(libs)
+ if(ARGC GREATER 2)
+ set(libs ${ARGV2})
+ endif()
+ unset(dirs)
+ if(ARGC GREATER 3)
+ set(dirs ${ARGV3})
+ endif()
+ unset(plugins_dir)
+ if(ARGC GREATER 4)
+ set(plugins_dir ${ARGV4})
+ endif()
+ unset(request_qt_conf)
+ if(ARGC GREATER 5)
+ set(request_qt_conf ${ARGV5})
+ endif()
+
+ message(STATUS "fixup_qt4_executable")
+ message(STATUS " executable='${executable}'")
+ message(STATUS " qtplugins='${qtplugins}'")
+ message(STATUS " libs='${libs}'")
+ message(STATUS " dirs='${dirs}'")
+ message(STATUS " plugins_dir='${plugins_dir}'")
+ message(STATUS " request_qt_conf='${request_qt_conf}'")
+
+ if(QT_LIBRARY_DIR)
+ list(APPEND dirs "${QT_LIBRARY_DIR}")
+ endif()
+ if(QT_BINARY_DIR)
+ list(APPEND dirs "${QT_BINARY_DIR}")
+ endif()
+
+ if(APPLE)
+ set(qt_conf_dir "${executable}/Contents/Resources")
+ set(executable_path "${executable}")
+ set(write_qt_conf TRUE)
+ if(NOT DEFINED plugins_dir)
+ set(plugins_dir "${DeployQt4_apple_plugins_dir}")
+ endif()
+ else()
+ get_filename_component(executable_path "${executable}" PATH)
+ if(NOT executable_path)
+ set(executable_path ".")
+ endif()
+ set(qt_conf_dir "${executable_path}")
+ set(write_qt_conf ${request_qt_conf})
+ endif()
+
+ foreach(plugin ${qtplugins})
+ set(installed_plugin_path "")
+ install_qt4_plugin("${plugin}" "${executable}" 1 installed_plugin_path)
+ list(APPEND libs ${installed_plugin_path})
+ endforeach()
+
+ foreach(lib ${libs})
+ if(NOT EXISTS "${lib}")
+ message(FATAL_ERROR "Library does not exist: ${lib}")
+ endif()
+ endforeach()
+
+ resolve_qt4_paths(libs "${executable_path}")
+
+ if(write_qt_conf)
+ set(qt_conf_contents "[Paths]\nPlugins = ${plugins_dir}")
+ write_qt4_conf("${qt_conf_dir}" "${qt_conf_contents}")
+ endif()
+
+ fixup_bundle("${executable}" "${libs}" "${dirs}")
+ endfunction()
+endif()
+
+function(install_qt4_plugin_path plugin executable copy installed_plugin_path_var)
+ unset(plugins_dir)
+ if(ARGC GREATER 4)
+ set(plugins_dir ${ARGV4})
+ endif()
+ unset(component)
+ if(ARGC GREATER 5)
+ set(component ${ARGV5})
+ endif()
+ unset(configurations)
+ if(ARGC GREATER 6)
+ set(configurations ${ARGV6})
+ endif()
+
+ if(EXISTS "${plugin}")
+ if(APPLE)
+ if(NOT plugins_dir)
+ set(plugins_dir "${DeployQt4_apple_plugins_dir}")
+ endif()
+ set(plugins_path "${executable}/Contents/${plugins_dir}")
+ else()
+ get_filename_component(plugins_path "${executable}" PATH)
+ if(NOT plugins_path)
+ set(plugins_path ".")
+ endif()
+ if(plugins_dir)
+ string(APPEND plugins_path "/${plugins_dir}")
+ endif()
+ endif()
+
+ set(plugin_group "")
+
+ get_filename_component(plugin_path "${plugin}" PATH)
+ get_filename_component(plugin_parent_path "${plugin_path}" PATH)
+ get_filename_component(plugin_parent_dir_name "${plugin_parent_path}" NAME)
+ get_filename_component(plugin_name "${plugin}" NAME)
+ string(TOLOWER "${plugin_parent_dir_name}" plugin_parent_dir_name)
+
+ if("${plugin_parent_dir_name}" STREQUAL "plugins")
+ get_filename_component(plugin_group "${plugin_path}" NAME)
+ set(${plugin_group_var} "${plugin_group}")
+ endif()
+ string(APPEND plugins_path "/${plugin_group}")
+
+ if(${copy})
+ file(MAKE_DIRECTORY "${plugins_path}")
+ file(COPY "${plugin}" DESTINATION "${plugins_path}")
+ else()
+ get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(configurations AND (_isMultiConfig OR CMAKE_BUILD_TYPE))
+ set(configurations CONFIGURATIONS ${configurations})
+ else()
+ unset(configurations)
+ endif()
+ install(FILES "${plugin}" DESTINATION "${plugins_path}" ${configurations} ${component})
+ endif()
+ set(${installed_plugin_path_var} "${plugins_path}/${plugin_name}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(install_qt4_plugin plugin executable copy installed_plugin_path_var)
+ unset(plugins_dir)
+ if(ARGC GREATER 4)
+ set(plugins_dir ${ARGV4})
+ endif()
+ unset(component)
+ if(ARGC GREATER 5)
+ set(component ${ARGV5})
+ endif()
+
+ if(EXISTS "${plugin}")
+ install_qt4_plugin_path("${plugin}" "${executable}" "${copy}" "${installed_plugin_path_var}" "${plugins_dir}" "${component}")
+ else()
+ string(TOUPPER "QT_${plugin}_PLUGIN" plugin_var)
+ set(plugin_release_var "${plugin_var}_RELEASE")
+ set(plugin_debug_var "${plugin_var}_DEBUG")
+ set(plugin_release "${${plugin_release_var}}")
+ set(plugin_debug "${${plugin_debug_var}}")
+ if(DEFINED "${plugin_release_var}" AND DEFINED "${plugin_debug_var}" AND NOT EXISTS "${plugin_release}" AND NOT EXISTS "${plugin_debug}")
+ message(WARNING "Qt plugin \"${plugin}\" not recognized or found.")
+ endif()
+ if(NOT EXISTS "${${plugin_debug_var}}")
+ set(plugin_debug "${plugin_release}")
+ endif()
+
+ get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(_isMultiConfig OR CMAKE_BUILD_TYPE)
+ set(_RELEASE_CONFIGS ${CMAKE_CONFIGURATION_TYPES} "${CMAKE_BUILD_TYPE}")
+ if (_RELEASE_CONFIGS)
+ list(FILTER _RELEASE_CONFIGS EXCLUDE REGEX "[Dd][Ee][Bb][Uu][Gg]")
+ endif()
+ string(REPLACE ";" "|" _RELEASE_CONFIGS "${_RELEASE_CONFIGS}")
+ install_qt4_plugin_path("${plugin_release}" "${executable}" "${copy}" "${installed_plugin_path_var}_release" "${plugins_dir}" "${component}" "${_RELEASE_CONFIGS}")
+ install_qt4_plugin_path("${plugin_debug}" "${executable}" "${copy}" "${installed_plugin_path_var}_debug" "${plugins_dir}" "${component}" "Debug")
+ unset(_RELEASE_CONFIGS)
+
+ if(CMAKE_BUILD_TYPE MATCHES "^Debug$")
+ set(${installed_plugin_path_var} ${${installed_plugin_path_var}_debug})
+ else()
+ set(${installed_plugin_path_var} ${${installed_plugin_path_var}_release})
+ endif()
+ else()
+ install_qt4_plugin_path("${plugin_release}" "${executable}" "${copy}" "${installed_plugin_path_var}" "${plugins_dir}" "${component}")
+ endif()
+ endif()
+ set(${installed_plugin_path_var} ${${installed_plugin_path_var}} PARENT_SCOPE)
+endfunction()
+
+function(install_qt4_executable executable)
+ unset(qtplugins)
+ if(ARGC GREATER 1)
+ set(qtplugins ${ARGV1})
+ endif()
+ unset(libs)
+ if(ARGC GREATER 2)
+ set(libs ${ARGV2})
+ endif()
+ unset(dirs)
+ if(ARGC GREATER 3)
+ set(dirs ${ARGV3})
+ endif()
+ unset(plugins_dir)
+ if(ARGC GREATER 4)
+ set(plugins_dir ${ARGV4})
+ endif()
+ unset(request_qt_conf)
+ if(ARGC GREATER 5)
+ set(request_qt_conf ${ARGV5})
+ endif()
+ unset(component)
+ if(ARGC GREATER 6)
+ set(component ${ARGV6})
+ endif()
+
+ if(QT_LIBRARY_DIR)
+ list(APPEND dirs "${QT_LIBRARY_DIR}")
+ endif()
+ if(QT_BINARY_DIR)
+ list(APPEND dirs "${QT_BINARY_DIR}")
+ endif()
+ if(component)
+ set(component COMPONENT ${component})
+ else()
+ unset(component)
+ endif()
+
+ get_filename_component(executable_absolute "${executable}" ABSOLUTE)
+ if(EXISTS "${QT_QTCORE_LIBRARY_RELEASE}")
+ gp_file_type("${executable_absolute}" "${QT_QTCORE_LIBRARY_RELEASE}" qtcore_type)
+ elseif(EXISTS "${QT_QTCORE_LIBRARY_DEBUG}")
+ gp_file_type("${executable_absolute}" "${QT_QTCORE_LIBRARY_DEBUG}" qtcore_type)
+ endif()
+ if(qtcore_type STREQUAL "system")
+ set(qt_plugins_dir "")
+ endif()
+
+ if(QT_IS_STATIC)
+ message(WARNING "Qt built statically: not installing plugins.")
+ else()
+ foreach(plugin ${qtplugins})
+ set(installed_plugin_paths "")
+ install_qt4_plugin("${plugin}" "${executable}" 0 installed_plugin_paths "${plugins_dir}" "${component}")
+ list(APPEND libs ${installed_plugin_paths})
+ endforeach()
+ endif()
+
+ resolve_qt4_paths(libs "")
+
+ install(CODE
+"include(\"${CMAKE_CURRENT_FUNCTION_LIST_DIR}/DeployQt4.cmake\")
+set(BU_CHMOD_BUNDLE_ITEMS TRUE)
+FIXUP_QT4_EXECUTABLE(\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${executable}\" \"\" \"${libs}\" \"${dirs}\" \"${plugins_dir}\" \"${request_qt_conf}\")"
+ ${component}
+ )
+endfunction()
diff --git a/Modules/Documentation.cmake b/Modules/Documentation.cmake
new file mode 100644
index 0000000..2430f85
--- /dev/null
+++ b/Modules/Documentation.cmake
@@ -0,0 +1,77 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+Documentation
+-------------
+
+.. deprecated:: 3.18
+ This module does nothing, unless policy :policy:`CMP0106` is set to ``OLD``.
+
+This module provides support for the VTK documentation framework. It
+relies on several tools (Doxygen, Perl, etc).
+#]=======================================================================]
+
+cmake_policy(GET CMP0106 _Documentation_policy)
+
+if (_Documentation_policy STREQUAL "NEW")
+ message(FATAL_ERROR
+ "Documentation.cmake is VTK-specific code and should not be used in "
+ "non-VTK projects. This logic in this module is best shipped with the "
+ "project using it rather than with CMake. This is now an error according "
+ "to policy CMP0106.")
+else ()
+
+if (_Documentation_policy STREQUAL "")
+ # Ignore the warning if the project is detected as VTK itself.
+ if (NOT CMAKE_PROJECT_NAME STREQUAL "VTK" AND
+ NOT PROJECT_NAME STREQUAL "VTK")
+ cmake_policy(GET_WARNING CMP0106 _Documentation_policy_warning)
+ message(AUTHOR_WARNING
+ "${_Documentation_policy_warning}\n"
+ "Documentation.cmake is VTK-specific code and should not be used in "
+ "non-VTK projects. This logic in this module is best shipped with the "
+ "project using it rather than with CMake.")
+ endif ()
+ unset(_Documentation_policy_warning)
+endif ()
+
+#
+# Build the documentation ?
+#
+option(BUILD_DOCUMENTATION "Build the documentation (Doxygen)." OFF)
+mark_as_advanced(BUILD_DOCUMENTATION)
+
+if (BUILD_DOCUMENTATION)
+
+ #
+ # Check for the tools
+ #
+ find_package(UnixCommands)
+ find_package(Doxygen)
+ find_package(Gnuplot)
+ find_package(HTMLHelp)
+ find_package(Perl)
+ find_package(Wget)
+
+ option(DOCUMENTATION_HTML_HELP
+ "Build the HTML Help file (CHM)." OFF)
+
+ option(DOCUMENTATION_HTML_TARZ
+ "Build a compressed tar archive of the HTML doc." OFF)
+
+ mark_as_advanced(
+ DOCUMENTATION_HTML_HELP
+ DOCUMENTATION_HTML_TARZ
+ )
+
+ #
+ # The documentation process is controlled by a batch file.
+ # We will probably need bash to create the custom target
+ #
+
+endif ()
+
+endif ()
+
+unset(_Documentation_policy)
diff --git a/Modules/DummyCXXFile.cxx b/Modules/DummyCXXFile.cxx
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Modules/DummyCXXFile.cxx
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Modules/ExternalData.cmake b/Modules/ExternalData.cmake
new file mode 100644
index 0000000..1850e74
--- /dev/null
+++ b/Modules/ExternalData.cmake
@@ -0,0 +1,1212 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+ExternalData
+------------
+
+.. only:: html
+
+ .. contents::
+
+Manage data files stored outside source tree
+
+Introduction
+^^^^^^^^^^^^
+
+Use this module to unambiguously reference data files stored outside
+the source tree and fetch them at build time from arbitrary local and
+remote content-addressed locations. Functions provided by this module
+recognize arguments with the syntax ``DATA{<name>}`` as references to
+external data, replace them with full paths to local copies of those
+data, and create build rules to fetch and update the local copies.
+
+For example:
+
+.. code-block:: cmake
+
+ include(ExternalData)
+ set(ExternalData_URL_TEMPLATES "file:///local/%(algo)/%(hash)"
+ "file:////host/share/%(algo)/%(hash)"
+ "http://data.org/%(algo)/%(hash)")
+ ExternalData_Add_Test(MyData
+ NAME MyTest
+ COMMAND MyExe DATA{MyInput.png}
+ )
+ ExternalData_Add_Target(MyData)
+
+When test ``MyTest`` runs the ``DATA{MyInput.png}`` argument will be
+replaced by the full path to a real instance of the data file
+``MyInput.png`` on disk. If the source tree contains a content link
+such as ``MyInput.png.md5`` then the ``MyData`` target creates a real
+``MyInput.png`` in the build tree.
+
+Module Functions
+^^^^^^^^^^^^^^^^
+
+.. command:: ExternalData_Expand_Arguments
+
+ The ``ExternalData_Expand_Arguments`` function evaluates ``DATA{}``
+ references in its arguments and constructs a new list of arguments::
+
+ ExternalData_Expand_Arguments(
+ <target> # Name of data management target
+ <outVar> # Output variable
+ [args...] # Input arguments, DATA{} allowed
+ )
+
+ It replaces each ``DATA{}`` reference in an argument with the full path of
+ a real data file on disk that will exist after the ``<target>`` builds.
+
+.. command:: ExternalData_Add_Test
+
+ The ``ExternalData_Add_Test`` function wraps around the CMake
+ :command:`add_test` command but supports ``DATA{}`` references in
+ its arguments::
+
+ ExternalData_Add_Test(
+ <target> # Name of data management target
+ ... # Arguments of add_test(), DATA{} allowed
+ )
+
+ It passes its arguments through ``ExternalData_Expand_Arguments`` and then
+ invokes the :command:`add_test` command using the results.
+
+.. command:: ExternalData_Add_Target
+
+ The ``ExternalData_Add_Target`` function creates a custom target to
+ manage local instances of data files stored externally::
+
+ ExternalData_Add_Target(
+ <target> # Name of data management target
+ [SHOW_PROGRESS <ON|OFF>] # Show progress during the download
+ )
+
+ It creates custom commands in the target as necessary to make data
+ files available for each ``DATA{}`` reference previously evaluated by
+ other functions provided by this module.
+ Data files may be fetched from one of the URL templates specified in
+ the ``ExternalData_URL_TEMPLATES`` variable, or may be found locally
+ in one of the paths specified in the ``ExternalData_OBJECT_STORES``
+ variable.
+
+ .. versionadded:: 3.20
+ The ``SHOW_PROGRESS`` argument may be passed to suppress progress information
+ during the download of objects. If not provided, it defaults to ``OFF`` for
+ :generator:`Ninja` and :generator:`Ninja Multi-Config` generators and ``ON``
+ otherwise.
+
+ Typically only one target is needed to manage all external data within
+ a project. Call this function once at the end of configuration after
+ all data references have been processed.
+
+Module Variables
+^^^^^^^^^^^^^^^^
+
+The following variables configure behavior. They should be set before
+calling any of the functions provided by this module.
+
+.. variable:: ExternalData_BINARY_ROOT
+
+ The ``ExternalData_BINARY_ROOT`` variable may be set to the directory to
+ hold the real data files named by expanded ``DATA{}`` references. The
+ default is ``CMAKE_BINARY_DIR``. The directory layout will mirror that of
+ content links under ``ExternalData_SOURCE_ROOT``.
+
+.. variable:: ExternalData_CUSTOM_SCRIPT_<key>
+
+ .. versionadded:: 3.2
+
+ Specify a full path to a ``.cmake`` custom fetch script identified by
+ ``<key>`` in entries of the ``ExternalData_URL_TEMPLATES`` list.
+ See `Custom Fetch Scripts`_.
+
+.. variable:: ExternalData_LINK_CONTENT
+
+ The ``ExternalData_LINK_CONTENT`` variable may be set to the name of a
+ supported hash algorithm to enable automatic conversion of real data
+ files referenced by the ``DATA{}`` syntax into content links. For each
+ such ``<file>`` a content link named ``<file><ext>`` is created. The
+ original file is renamed to the form ``.ExternalData_<algo>_<hash>`` to
+ stage it for future transmission to one of the locations in the list
+ of URL templates (by means outside the scope of this module). The
+ data fetch rule created for the content link will use the staged
+ object if it cannot be found using any URL template.
+
+.. variable:: ExternalData_NO_SYMLINKS
+
+ .. versionadded:: 3.3
+
+ The real data files named by expanded ``DATA{}`` references may be made
+ available under ``ExternalData_BINARY_ROOT`` using symbolic links on
+ some platforms. The ``ExternalData_NO_SYMLINKS`` variable may be set
+ to disable use of symbolic links and enable use of copies instead.
+
+.. variable:: ExternalData_OBJECT_STORES
+
+ The ``ExternalData_OBJECT_STORES`` variable may be set to a list of local
+ directories that store objects using the layout ``<dir>/%(algo)/%(hash)``.
+ These directories will be searched first for a needed object. If the
+ object is not available in any store then it will be fetched remotely
+ using the URL templates and added to the first local store listed. If
+ no stores are specified the default is a location inside the build
+ tree.
+
+.. variable:: ExternalData_SERIES_PARSE
+ ExternalData_SERIES_PARSE_PREFIX
+ ExternalData_SERIES_PARSE_NUMBER
+ ExternalData_SERIES_PARSE_SUFFIX
+ ExternalData_SERIES_MATCH
+
+ See `Referencing File Series`_.
+
+.. variable:: ExternalData_SOURCE_ROOT
+
+ The ``ExternalData_SOURCE_ROOT`` variable may be set to the highest source
+ directory containing any path named by a ``DATA{}`` reference. The
+ default is ``CMAKE_SOURCE_DIR``. ``ExternalData_SOURCE_ROOT`` and
+ ``CMAKE_SOURCE_DIR`` must refer to directories within a single source
+ distribution (e.g. they come together in one tarball).
+
+.. variable:: ExternalData_TIMEOUT_ABSOLUTE
+
+ The ``ExternalData_TIMEOUT_ABSOLUTE`` variable sets the download
+ absolute timeout, in seconds, with a default of ``300`` seconds.
+ Set to ``0`` to disable enforcement.
+
+.. variable:: ExternalData_TIMEOUT_INACTIVITY
+
+ The ``ExternalData_TIMEOUT_INACTIVITY`` variable sets the download
+ inactivity timeout, in seconds, with a default of ``60`` seconds.
+ Set to ``0`` to disable enforcement.
+
+.. variable:: ExternalData_URL_ALGO_<algo>_<key>
+
+ .. versionadded:: 3.3
+
+ Specify a custom URL component to be substituted for URL template
+ placeholders of the form ``%(algo:<key>)``, where ``<key>`` is a
+ valid C identifier, when fetching an object referenced via hash
+ algorithm ``<algo>``. If not defined, the default URL component
+ is just ``<algo>`` for any ``<key>``.
+
+.. variable:: ExternalData_URL_TEMPLATES
+
+ The ``ExternalData_URL_TEMPLATES`` may be set to provide a list
+ of URL templates using the placeholders ``%(algo)`` and ``%(hash)``
+ in each template. Data fetch rules try each URL template in order
+ by substituting the hash algorithm name for ``%(algo)`` and the hash
+ value for ``%(hash)``. Alternatively one may use ``%(algo:<key>)``
+ with ``ExternalData_URL_ALGO_<algo>_<key>`` variables to gain more
+ flexibility in remote URLs.
+
+Referencing Files
+^^^^^^^^^^^^^^^^^
+
+Referencing Single Files
+""""""""""""""""""""""""
+
+The ``DATA{}`` syntax is literal and the ``<name>`` is a full or relative path
+within the source tree. The source tree must contain either a real
+data file at ``<name>`` or a "content link" at ``<name><ext>`` containing a
+hash of the real file using a hash algorithm corresponding to ``<ext>``.
+For example, the argument ``DATA{img.png}`` may be satisfied by either a
+real ``img.png`` file in the current source directory or a ``img.png.md5``
+file containing its MD5 sum.
+
+.. versionadded:: 3.8
+ Multiple content links of the same name with different hash algorithms
+ are supported (e.g. ``img.png.sha256`` and ``img.png.sha1``) so long as
+ they all correspond to the same real file. This allows objects to be
+ fetched from sources indexed by different hash algorithms.
+
+Referencing File Series
+"""""""""""""""""""""""
+
+The ``DATA{}`` syntax can be told to fetch a file series using the form
+``DATA{<name>,:}``, where the ``:`` is literal. If the source tree
+contains a group of files or content links named like a series then a
+reference to one member adds rules to fetch all of them. Although all
+members of a series are fetched, only the file originally named by the
+``DATA{}`` argument is substituted for it. The default configuration
+recognizes file series names ending with ``#.ext``, ``_#.ext``, ``.#.ext``,
+or ``-#.ext`` where ``#`` is a sequence of decimal digits and ``.ext`` is
+any single extension. Configure it with a regex that parses ``<number>``
+and ``<suffix>`` parts from the end of ``<name>``::
+
+ ExternalData_SERIES_PARSE = regex of the form (<number>)(<suffix>)$
+
+For more complicated cases set::
+
+ ExternalData_SERIES_PARSE = regex with at least two () groups
+ ExternalData_SERIES_PARSE_PREFIX = <prefix> regex group number, if any
+ ExternalData_SERIES_PARSE_NUMBER = <number> regex group number
+ ExternalData_SERIES_PARSE_SUFFIX = <suffix> regex group number
+
+Configure series number matching with a regex that matches the
+``<number>`` part of series members named ``<prefix><number><suffix>``::
+
+ ExternalData_SERIES_MATCH = regex matching <number> in all series members
+
+Note that the ``<suffix>`` of a series does not include a hash-algorithm
+extension.
+
+Referencing Associated Files
+""""""""""""""""""""""""""""
+
+The ``DATA{}`` syntax can alternatively match files associated with the
+named file and contained in the same directory. Associated files may
+be specified by options using the syntax
+``DATA{<name>,<opt1>,<opt2>,...}``. Each option may specify one file by
+name or specify a regular expression to match file names using the
+syntax ``REGEX:<regex>``. For example, the arguments::
+
+ DATA{MyData/MyInput.mhd,MyInput.img} # File pair
+ DATA{MyData/MyFrames00.png,REGEX:MyFrames[0-9]+\\.png} # Series
+
+will pass ``MyInput.mha`` and ``MyFrames00.png`` on the command line but
+ensure that the associated files are present next to them.
+
+Referencing Directories
+"""""""""""""""""""""""
+
+The ``DATA{}`` syntax may reference a directory using a trailing slash and
+a list of associated files. The form ``DATA{<name>/,<opt1>,<opt2>,...}``
+adds rules to fetch any files in the directory that match one of the
+associated file options. For example, the argument
+``DATA{MyDataDir/,REGEX:.*}`` will pass the full path to a ``MyDataDir``
+directory on the command line and ensure that the directory contains
+files corresponding to every file or content link in the ``MyDataDir``
+source directory.
+
+.. versionadded:: 3.3
+ In order to match associated files in subdirectories,
+ specify a ``RECURSE:`` option, e.g. ``DATA{MyDataDir/,RECURSE:,REGEX:.*}``.
+
+Hash Algorithms
+^^^^^^^^^^^^^^^
+
+The following hash algorithms are supported::
+
+ %(algo) <ext> Description
+ ------- ----- -----------
+ MD5 .md5 Message-Digest Algorithm 5, RFC 1321
+ SHA1 .sha1 US Secure Hash Algorithm 1, RFC 3174
+ SHA224 .sha224 US Secure Hash Algorithms, RFC 4634
+ SHA256 .sha256 US Secure Hash Algorithms, RFC 4634
+ SHA384 .sha384 US Secure Hash Algorithms, RFC 4634
+ SHA512 .sha512 US Secure Hash Algorithms, RFC 4634
+ SHA3_224 .sha3-224 Keccak SHA-3
+ SHA3_256 .sha3-256 Keccak SHA-3
+ SHA3_384 .sha3-384 Keccak SHA-3
+ SHA3_512 .sha3-512 Keccak SHA-3
+
+.. versionadded:: 3.8
+ Added the ``SHA3_*`` hash algorithms.
+
+Note that the hashes are used only for unique data identification and
+download verification.
+
+.. _`ExternalData Custom Fetch Scripts`:
+
+Custom Fetch Scripts
+^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.2
+
+When a data file must be fetched from one of the URL templates
+specified in the ``ExternalData_URL_TEMPLATES`` variable, it is
+normally downloaded using the :command:`file(DOWNLOAD)` command.
+One may specify usage of a custom fetch script by using a URL
+template of the form ``ExternalDataCustomScript://<key>/<loc>``.
+The ``<key>`` must be a C identifier, and the ``<loc>`` must
+contain the ``%(algo)`` and ``%(hash)`` placeholders.
+A variable corresponding to the key, ``ExternalData_CUSTOM_SCRIPT_<key>``,
+must be set to the full path to a ``.cmake`` script file. The script
+will be included to perform the actual fetch, and provided with
+the following variables:
+
+.. variable:: ExternalData_CUSTOM_LOCATION
+
+ When a custom fetch script is loaded, this variable is set to the
+ location part of the URL, which will contain the substituted hash
+ algorithm name and content hash value.
+
+.. variable:: ExternalData_CUSTOM_FILE
+
+ When a custom fetch script is loaded, this variable is set to the
+ full path to a file in which the script must store the fetched
+ content. The name of the file is unspecified and should not be
+ interpreted in any way.
+
+The custom fetch script is expected to store fetched content in the
+file or set a variable:
+
+.. variable:: ExternalData_CUSTOM_ERROR
+
+ When a custom fetch script fails to fetch the requested content,
+ it must set this variable to a short one-line message describing
+ the reason for failure.
+
+#]=======================================================================]
+
+function(ExternalData_add_test target)
+ # Expand all arguments as a single string to preserve escaped semicolons.
+ ExternalData_expand_arguments("${target}" testArgs "${ARGN}")
+ add_test(${testArgs})
+endfunction()
+
+function(ExternalData_add_target target)
+ if(NOT ExternalData_URL_TEMPLATES AND NOT ExternalData_OBJECT_STORES)
+ message(FATAL_ERROR
+ "Neither ExternalData_URL_TEMPLATES nor ExternalData_OBJECT_STORES is set!")
+ endif()
+ if(NOT ExternalData_OBJECT_STORES)
+ set(ExternalData_OBJECT_STORES ${CMAKE_BINARY_DIR}/ExternalData/Objects)
+ endif()
+ set(_ExternalData_CONFIG_CODE "")
+
+ cmake_parse_arguments(PARSE_ARGV 1 _ExternalData_add_target
+ ""
+ "SHOW_PROGRESS"
+ "")
+ if (_ExternalData_add_target_UNPARSED_ARGUMENTS)
+ message(AUTHOR_WARNING
+ "Ignoring unrecognized arguments passed to ExternalData_add_target: "
+ "`${_ExternalData_add_target_UNPARSED_ARGUMENTS}`")
+ endif ()
+
+ # Turn `SHOW_PROGRESS` into a boolean
+ if (NOT DEFINED _ExternalData_add_target_SHOW_PROGRESS)
+ # The default setting
+ if (CMAKE_GENERATOR MATCHES "Ninja")
+ set(_ExternalData_add_target_SHOW_PROGRESS OFF)
+ else ()
+ set(_ExternalData_add_target_SHOW_PROGRESS ON)
+ endif ()
+ elseif (_ExternalData_add_target_SHOW_PROGRESS)
+ set(_ExternalData_add_target_SHOW_PROGRESS ON)
+ else ()
+ set(_ExternalData_add_target_SHOW_PROGRESS OFF)
+ endif ()
+
+ # Store custom script configuration.
+ foreach(url_template IN LISTS ExternalData_URL_TEMPLATES)
+ if("${url_template}" MATCHES "^ExternalDataCustomScript://([^/]*)/(.*)$")
+ set(key "${CMAKE_MATCH_1}")
+ if(key MATCHES "^[A-Za-z_][A-Za-z0-9_]*$")
+ if(ExternalData_CUSTOM_SCRIPT_${key})
+ if(IS_ABSOLUTE "${ExternalData_CUSTOM_SCRIPT_${key}}")
+ string(CONCAT _ExternalData_CONFIG_CODE "${_ExternalData_CONFIG_CODE}\n"
+ "set(ExternalData_CUSTOM_SCRIPT_${key} \"${ExternalData_CUSTOM_SCRIPT_${key}}\")")
+ else()
+ message(FATAL_ERROR
+ "No ExternalData_CUSTOM_SCRIPT_${key} is not set to a full path:\n"
+ " ${ExternalData_CUSTOM_SCRIPT_${key}}")
+ endif()
+ else()
+ message(FATAL_ERROR
+ "No ExternalData_CUSTOM_SCRIPT_${key} is set for URL template:\n"
+ " ${url_template}")
+ endif()
+ else()
+ message(FATAL_ERROR
+ "Bad ExternalDataCustomScript key '${key}' in URL template:\n"
+ " ${url_template}\n"
+ "The key must be a valid C identifier.")
+ endif()
+ endif()
+
+ # Store custom algorithm name to URL component maps.
+ if("${url_template}" MATCHES "%\\(algo:([^)]*)\\)")
+ set(key "${CMAKE_MATCH_1}")
+ if(key MATCHES "^[A-Za-z_][A-Za-z0-9_]*$")
+ string(REPLACE "|" ";" _algos "${_ExternalData_REGEX_ALGO}")
+ foreach(algo ${_algos})
+ if(DEFINED ExternalData_URL_ALGO_${algo}_${key})
+ string(CONCAT _ExternalData_CONFIG_CODE "${_ExternalData_CONFIG_CODE}\n"
+ "set(ExternalData_URL_ALGO_${algo}_${key} \"${ExternalData_URL_ALGO_${algo}_${key}}\")")
+ endif()
+ endforeach()
+ else()
+ message(FATAL_ERROR
+ "Bad %(algo:${key}) in URL template:\n"
+ " ${url_template}\n"
+ "The transform name must be a valid C identifier.")
+ endif()
+ endif()
+ endforeach()
+
+ # Store configuration for use by build-time script.
+ set(config ${CMAKE_CURRENT_BINARY_DIR}/${target}_config.cmake)
+ configure_file(${_ExternalData_SELF_DIR}/ExternalData_config.cmake.in ${config} @ONLY)
+
+ set(files "")
+
+ # Set a "_ExternalData_FILE_${file}" variable for each output file to avoid
+ # duplicate entries within this target. Set a directory property of the same
+ # name to avoid repeating custom commands with the same output in this directory.
+ # Repeating custom commands with the same output across directories or across
+ # targets in the same directory may be a race, but this is likely okay because
+ # we use atomic replacement of output files.
+ #
+ # Use local data first to prefer real files over content links.
+
+ # Custom commands to copy or link local data.
+ get_property(data_local GLOBAL PROPERTY _ExternalData_${target}_LOCAL)
+ foreach(entry IN LISTS data_local)
+ string(REPLACE "|" ";" tuple "${entry}")
+ list(GET tuple 0 file)
+ list(GET tuple 1 name)
+ if(NOT DEFINED "_ExternalData_FILE_${file}")
+ set("_ExternalData_FILE_${file}" 1)
+ get_property(added DIRECTORY PROPERTY "_ExternalData_FILE_${file}")
+ if(NOT added)
+ set_property(DIRECTORY PROPERTY "_ExternalData_FILE_${file}" 1)
+ add_custom_command(
+ COMMENT "Generating ${file}"
+ OUTPUT "${file}"
+ COMMAND ${CMAKE_COMMAND} -Drelative_top=${CMAKE_BINARY_DIR}
+ -Dfile=${file} -Dname=${name}
+ -DExternalData_ACTION=local
+ -DExternalData_SHOW_PROGRESS=${_ExternalData_add_target_SHOW_PROGRESS}
+ -DExternalData_CONFIG=${config}
+ -P ${_ExternalData_SELF}
+ MAIN_DEPENDENCY "${name}"
+ )
+ endif()
+ list(APPEND files "${file}")
+ endif()
+ endforeach()
+
+ # Custom commands to fetch remote data.
+ get_property(data_fetch GLOBAL PROPERTY _ExternalData_${target}_FETCH)
+ foreach(entry IN LISTS data_fetch)
+ string(REPLACE "|" ";" tuple "${entry}")
+ list(GET tuple 0 file)
+ list(GET tuple 1 name)
+ list(GET tuple 2 exts)
+ string(REPLACE "+" ";" exts_list "${exts}")
+ list(GET exts_list 0 first_ext)
+ set(stamp "-hash-stamp")
+ if(NOT DEFINED "_ExternalData_FILE_${file}")
+ set("_ExternalData_FILE_${file}" 1)
+ get_property(added DIRECTORY PROPERTY "_ExternalData_FILE_${file}")
+ if(NOT added)
+ set_property(DIRECTORY PROPERTY "_ExternalData_FILE_${file}" 1)
+ add_custom_command(
+ # Users care about the data file, so hide the hash/timestamp file.
+ COMMENT "Generating ${file}"
+ # The hash/timestamp file is the output from the build perspective.
+ # List the real file as a second output in case it is a broken link.
+ # The files must be listed in this order so CMake can hide from the
+ # make tool that a symlink target may not be newer than the input.
+ OUTPUT "${file}${stamp}" "${file}"
+ # Run the data fetch/update script.
+ COMMAND ${CMAKE_COMMAND} -Drelative_top=${CMAKE_BINARY_DIR}
+ -Dfile=${file} -Dname=${name} -Dexts=${exts}
+ -DExternalData_ACTION=fetch
+ -DExternalData_SHOW_PROGRESS=${_ExternalData_add_target_SHOW_PROGRESS}
+ -DExternalData_CONFIG=${config}
+ -P ${_ExternalData_SELF}
+ # Update whenever the object hash changes.
+ MAIN_DEPENDENCY "${name}${first_ext}"
+ )
+ endif()
+ list(APPEND files "${file}${stamp}")
+ endif()
+ endforeach()
+
+ # Custom target to drive all update commands.
+ add_custom_target(${target} ALL DEPENDS ${files})
+endfunction()
+
+function(ExternalData_expand_arguments target outArgsVar)
+ # Replace DATA{} references with real arguments.
+ set(data_regex "DATA{([^;{}\r\n]*)}")
+ set(other_regex "([^D]|D[^A]|DA[^T]|DAT[^A]|DATA[^{])+|.")
+ set(outArgs "")
+ # This list expansion un-escapes semicolons in list element values so we
+ # must re-escape them below anywhere a new list expansion will occur.
+ foreach(arg IN LISTS ARGN)
+ if("x${arg}" MATCHES "${data_regex}")
+ # Re-escape in-value semicolons before expansion in foreach below.
+ string(REPLACE ";" "\\;" tmp "${arg}")
+ # Split argument into DATA{}-pieces and other pieces.
+ string(REGEX MATCHALL "${data_regex}|${other_regex}" pieces "${tmp}")
+ # Compose output argument with DATA{}-pieces replaced.
+ set(outArg "")
+ foreach(piece IN LISTS pieces)
+ if("x${piece}" MATCHES "^x${data_regex}$")
+ # Replace this DATA{}-piece with a file path.
+ _ExternalData_arg("${target}" "${piece}" "${CMAKE_MATCH_1}" file)
+ string(APPEND outArg "${file}")
+ else()
+ # No replacement needed for this piece.
+ string(APPEND outArg "${piece}")
+ endif()
+ endforeach()
+ else()
+ # No replacements needed in this argument.
+ set(outArg "${arg}")
+ endif()
+ # Re-escape in-value semicolons in resulting list.
+ string(REPLACE ";" "\\;" outArg "${outArg}")
+ list(APPEND outArgs "${outArg}")
+ endforeach()
+ set("${outArgsVar}" "${outArgs}" PARENT_SCOPE)
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Private helper interface
+
+set(_ExternalData_REGEX_ALGO "MD5|SHA1|SHA224|SHA256|SHA384|SHA512|SHA3_224|SHA3_256|SHA3_384|SHA3_512")
+set(_ExternalData_REGEX_EXT "md5|sha1|sha224|sha256|sha384|sha512|sha3-224|sha3-256|sha3-384|sha3-512")
+set(_ExternalData_SELF "${CMAKE_CURRENT_LIST_FILE}")
+get_filename_component(_ExternalData_SELF_DIR "${_ExternalData_SELF}" PATH)
+
+function(_ExternalData_compute_hash var_hash algo file)
+ if("${algo}" MATCHES "^${_ExternalData_REGEX_ALGO}$")
+ file("${algo}" "${file}" hash)
+ set("${var_hash}" "${hash}" PARENT_SCOPE)
+ else()
+ message(FATAL_ERROR "Hash algorithm ${algo} unimplemented.")
+ endif()
+endfunction()
+
+function(_ExternalData_random var)
+ string(RANDOM LENGTH 6 random)
+ set("${var}" "${random}" PARENT_SCOPE)
+endfunction()
+
+function(_ExternalData_exact_regex regex_var string)
+ string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" regex "${string}")
+ set("${regex_var}" "${regex}" PARENT_SCOPE)
+endfunction()
+
+function(_ExternalData_atomic_write file content)
+ _ExternalData_random(random)
+ set(tmp "${file}.tmp${random}")
+ file(WRITE "${tmp}" "${content}")
+ file(RENAME "${tmp}" "${file}")
+endfunction()
+
+function(_ExternalData_link_content name var_ext)
+ if("${ExternalData_LINK_CONTENT}" MATCHES "^(${_ExternalData_REGEX_ALGO})$")
+ set(algo "${ExternalData_LINK_CONTENT}")
+ else()
+ message(FATAL_ERROR
+ "Unknown hash algorithm specified by ExternalData_LINK_CONTENT:\n"
+ " ${ExternalData_LINK_CONTENT}")
+ endif()
+ _ExternalData_compute_hash(hash "${algo}" "${name}")
+ get_filename_component(dir "${name}" PATH)
+ set(staged "${dir}/.ExternalData_${algo}_${hash}")
+ string(TOLOWER ".${algo}" ext)
+ _ExternalData_atomic_write("${name}${ext}" "${hash}\n")
+ file(RENAME "${name}" "${staged}")
+ set("${var_ext}" "${ext}" PARENT_SCOPE)
+
+ file(RELATIVE_PATH relname "${ExternalData_SOURCE_ROOT}" "${name}${ext}")
+ message(STATUS "Linked ${relname} to ExternalData ${algo}/${hash}")
+endfunction()
+
+function(_ExternalData_arg target arg options var_file)
+ # Separate data path from the options.
+ string(REPLACE "," ";" options "${options}")
+ list(GET options 0 data)
+ list(REMOVE_AT options 0)
+
+ # Interpret trailing slashes as directories.
+ set(data_is_directory 0)
+ if("x${data}" MATCHES "^x(.*)([/\\])$")
+ set(data_is_directory 1)
+ set(data "${CMAKE_MATCH_1}")
+ endif()
+
+ # Convert to full path.
+ if(IS_ABSOLUTE "${data}")
+ set(absdata "${data}")
+ else()
+ set(absdata "${CMAKE_CURRENT_SOURCE_DIR}/${data}")
+ endif()
+ get_filename_component(absdata "${absdata}" ABSOLUTE)
+
+ # Convert to relative path under the source tree.
+ if(NOT ExternalData_SOURCE_ROOT)
+ set(ExternalData_SOURCE_ROOT "${CMAKE_SOURCE_DIR}")
+ endif()
+ set(top_src "${ExternalData_SOURCE_ROOT}")
+ file(RELATIVE_PATH reldata "${top_src}" "${absdata}")
+ if(IS_ABSOLUTE "${reldata}" OR "${reldata}" MATCHES "^\\.\\./")
+ message(FATAL_ERROR "Data file referenced by argument\n"
+ " ${arg}\n"
+ "does not lie under the top-level source directory\n"
+ " ${top_src}\n")
+ endif()
+ if(data_is_directory AND NOT IS_DIRECTORY "${top_src}/${reldata}")
+ message(FATAL_ERROR "Data directory referenced by argument\n"
+ " ${arg}\n"
+ "corresponds to source tree path\n"
+ " ${reldata}\n"
+ "that does not exist as a directory!")
+ endif()
+ if(NOT ExternalData_BINARY_ROOT)
+ set(ExternalData_BINARY_ROOT "${CMAKE_BINARY_DIR}")
+ endif()
+ set(top_bin "${ExternalData_BINARY_ROOT}")
+
+ # Handle in-source builds gracefully.
+ if("${top_src}" STREQUAL "${top_bin}")
+ if(ExternalData_LINK_CONTENT)
+ message(WARNING "ExternalData_LINK_CONTENT cannot be used in-source")
+ set(ExternalData_LINK_CONTENT 0)
+ endif()
+ set(top_same 1)
+ endif()
+
+ set(external "") # Entries external to the source tree.
+ set(internal "") # Entries internal to the source tree.
+ set(have_original ${data_is_directory})
+ set(have_original_as_dir 0)
+
+ # Process options.
+ set(series_option "")
+ set(recurse_option "")
+ set(associated_files "")
+ set(associated_regex "")
+ foreach(opt ${options})
+ # Regular expression to match associated files.
+ if("x${opt}" MATCHES "^xREGEX:([^:/]+)$")
+ list(APPEND associated_regex "${CMAKE_MATCH_1}")
+ elseif(opt STREQUAL ":")
+ # Activate series matching.
+ set(series_option "${opt}")
+ elseif(opt STREQUAL "RECURSE:")
+ # Activate recursive matching in directories.
+ set(recurse_option "${opt}")
+ elseif("x${opt}" MATCHES "^[^][:/*?]+$")
+ # Specific associated file.
+ list(APPEND associated_files "${opt}")
+ else()
+ message(FATAL_ERROR "Unknown option \"${opt}\" in argument\n"
+ " ${arg}\n")
+ endif()
+ endforeach()
+
+ if(series_option)
+ if(data_is_directory)
+ message(FATAL_ERROR "Series option \"${series_option}\" not allowed with directories.")
+ endif()
+ if(associated_files OR associated_regex)
+ message(FATAL_ERROR "Series option \"${series_option}\" not allowed with associated files.")
+ endif()
+ if(recurse_option)
+ message(FATAL_ERROR "Recurse option \"${recurse_option}\" allowed only with directories.")
+ endif()
+ # Load a whole file series.
+ _ExternalData_arg_series()
+ elseif(data_is_directory)
+ if(associated_files OR associated_regex)
+ # Load listed/matching associated files in the directory.
+ _ExternalData_arg_associated()
+ else()
+ message(FATAL_ERROR "Data directory referenced by argument\n"
+ " ${arg}\n"
+ "must list associated files.")
+ endif()
+ else()
+ if(recurse_option)
+ message(FATAL_ERROR "Recurse option \"${recurse_option}\" allowed only with directories.")
+ endif()
+ # Load the named data file.
+ _ExternalData_arg_single()
+ if(associated_files OR associated_regex)
+ # Load listed/matching associated files.
+ _ExternalData_arg_associated()
+ endif()
+ endif()
+
+ if(NOT have_original)
+ if(have_original_as_dir)
+ set(msg_kind FATAL_ERROR)
+ set(msg "that is directory instead of a file!")
+ else()
+ set(msg_kind AUTHOR_WARNING)
+ set(msg "that does not exist as a file (with or without an extension)!")
+ endif()
+ message(${msg_kind} "Data file referenced by argument\n"
+ " ${arg}\n"
+ "corresponds to source tree path\n"
+ " ${reldata}\n"
+ "${msg}")
+ endif()
+
+ if(external)
+ # Make the series available in the build tree.
+ set_property(GLOBAL APPEND PROPERTY
+ _ExternalData_${target}_FETCH "${external}")
+ set_property(GLOBAL APPEND PROPERTY
+ _ExternalData_${target}_LOCAL "${internal}")
+ set("${var_file}" "${top_bin}/${reldata}" PARENT_SCOPE)
+ else()
+ # The whole series is in the source tree.
+ set("${var_file}" "${top_src}/${reldata}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+macro(_ExternalData_arg_associated)
+ # Associated files lie in the same directory.
+ if(data_is_directory)
+ set(reldir "${reldata}")
+ else()
+ get_filename_component(reldir "${reldata}" PATH)
+ endif()
+ if(reldir)
+ string(APPEND reldir "/")
+ endif()
+ _ExternalData_exact_regex(reldir_regex "${reldir}")
+ if(recurse_option)
+ set(glob GLOB_RECURSE)
+ string(APPEND reldir_regex "(.+/)?")
+ else()
+ set(glob GLOB)
+ endif()
+
+ # Find files named explicitly.
+ foreach(file ${associated_files})
+ _ExternalData_exact_regex(file_regex "${file}")
+ _ExternalData_arg_find_files(${glob} "${reldir}${file}"
+ "${reldir_regex}${file_regex}")
+ endforeach()
+
+ # Find files matching the given regular expressions.
+ set(all "")
+ set(sep "")
+ foreach(regex ${associated_regex})
+ string(APPEND all "${sep}${reldir_regex}${regex}")
+ set(sep "|")
+ endforeach()
+ _ExternalData_arg_find_files(${glob} "${reldir}" "${all}")
+endmacro()
+
+macro(_ExternalData_arg_single)
+ # Match only the named data by itself.
+ _ExternalData_exact_regex(data_regex "${reldata}")
+ _ExternalData_arg_find_files(GLOB "${reldata}" "${data_regex}")
+endmacro()
+
+macro(_ExternalData_arg_series)
+ # Configure series parsing and matching.
+ set(series_parse_prefix "")
+ set(series_parse_number "\\1")
+ set(series_parse_suffix "\\2")
+ if(ExternalData_SERIES_PARSE)
+ if(ExternalData_SERIES_PARSE_NUMBER AND ExternalData_SERIES_PARSE_SUFFIX)
+ if(ExternalData_SERIES_PARSE_PREFIX)
+ set(series_parse_prefix "\\${ExternalData_SERIES_PARSE_PREFIX}")
+ endif()
+ set(series_parse_number "\\${ExternalData_SERIES_PARSE_NUMBER}")
+ set(series_parse_suffix "\\${ExternalData_SERIES_PARSE_SUFFIX}")
+ elseif(NOT "x${ExternalData_SERIES_PARSE}" MATCHES "^x\\([^()]*\\)\\([^()]*\\)\\$$")
+ message(FATAL_ERROR
+ "ExternalData_SERIES_PARSE is set to\n"
+ " ${ExternalData_SERIES_PARSE}\n"
+ "which is not of the form\n"
+ " (<number>)(<suffix>)$\n"
+ "Fix the regular expression or set variables\n"
+ " ExternalData_SERIES_PARSE_PREFIX = <prefix> regex group number, if any\n"
+ " ExternalData_SERIES_PARSE_NUMBER = <number> regex group number\n"
+ " ExternalData_SERIES_PARSE_SUFFIX = <suffix> regex group number\n"
+ )
+ endif()
+ set(series_parse "${ExternalData_SERIES_PARSE}")
+ else()
+ set(series_parse "([0-9]*)(\\.[^./]*)$")
+ endif()
+ if(ExternalData_SERIES_MATCH)
+ set(series_match "${ExternalData_SERIES_MATCH}")
+ else()
+ set(series_match "[_.-]?[0-9]*")
+ endif()
+
+ # Parse the base, number, and extension components of the series.
+ string(REGEX REPLACE "${series_parse}" "${series_parse_prefix};${series_parse_number};${series_parse_suffix}" tuple "${reldata}")
+ list(LENGTH tuple len)
+ if(NOT "${len}" EQUAL 3)
+ message(FATAL_ERROR "Data file referenced by argument\n"
+ " ${arg}\n"
+ "corresponds to path\n"
+ " ${reldata}\n"
+ "that does not match regular expression\n"
+ " ${series_parse}")
+ endif()
+ list(GET tuple 0 relbase)
+ list(GET tuple 2 ext)
+
+ # Glob files that might match the series.
+ # Then match base, number, and extension.
+ _ExternalData_exact_regex(series_base "${relbase}")
+ _ExternalData_exact_regex(series_ext "${ext}")
+ _ExternalData_arg_find_files(GLOB "${relbase}*${ext}"
+ "${series_base}${series_match}${series_ext}")
+endmacro()
+
+function(_ExternalData_arg_find_files glob pattern regex)
+ cmake_policy(PUSH)
+ cmake_policy(SET CMP0009 NEW)
+ file(${glob} globbed RELATIVE "${top_src}" "${top_src}/${pattern}*")
+ cmake_policy(POP)
+ set(externals_count -1)
+ foreach(entry IN LISTS globbed)
+ if("x${entry}" MATCHES "^x(.*)(\\.(${_ExternalData_REGEX_EXT}))$")
+ set(relname "${CMAKE_MATCH_1}")
+ set(alg "${CMAKE_MATCH_2}")
+ else()
+ set(relname "${entry}")
+ set(alg "")
+ endif()
+ if("x${relname}" MATCHES "^x${regex}$" # matches
+ AND NOT "x${relname}" MATCHES "(^x|/)\\.ExternalData_" # not staged obj
+ )
+ if(IS_DIRECTORY "${top_src}/${entry}")
+ if("${relname}" STREQUAL "${reldata}")
+ set(have_original_as_dir 1)
+ endif()
+ else()
+ set(name "${top_src}/${relname}")
+ set(file "${top_bin}/${relname}")
+ if(alg)
+ if(NOT "${external_${externals_count}_file_name}" STREQUAL "${file}|${name}")
+ math(EXPR externals_count "${externals_count} + 1")
+ set(external_${externals_count}_file_name "${file}|${name}")
+ endif()
+ list(APPEND external_${externals_count}_algs "${alg}")
+ elseif(ExternalData_LINK_CONTENT)
+ _ExternalData_link_content("${name}" alg)
+ list(APPEND external "${file}|${name}|${alg}")
+ elseif(NOT top_same)
+ list(APPEND internal "${file}|${name}")
+ endif()
+ if("${relname}" STREQUAL "${reldata}")
+ set(have_original 1)
+ endif()
+ endif()
+ endif()
+ endforeach()
+ if(${externals_count} GREATER -1)
+ foreach(ii RANGE ${externals_count})
+ string(REPLACE ";" "+" algs_delim "${external_${ii}_algs}")
+ list(APPEND external "${external_${ii}_file_name}|${algs_delim}")
+ unset(external_${ii}_algs)
+ unset(external_${ii}_file_name)
+ endforeach()
+ endif()
+ set(external "${external}" PARENT_SCOPE)
+ set(internal "${internal}" PARENT_SCOPE)
+ set(have_original "${have_original}" PARENT_SCOPE)
+ set(have_original_as_dir "${have_original_as_dir}" PARENT_SCOPE)
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Private script mode interface
+
+if(CMAKE_GENERATOR OR NOT ExternalData_ACTION)
+ return()
+endif()
+
+if(ExternalData_CONFIG)
+ include(${ExternalData_CONFIG})
+endif()
+if(NOT ExternalData_URL_TEMPLATES AND NOT ExternalData_OBJECT_STORES)
+ message(FATAL_ERROR
+ "Neither ExternalData_URL_TEMPLATES nor ExternalData_OBJECT_STORES is set!")
+endif()
+
+function(_ExternalData_link_or_copy src dst)
+ # Create a temporary file first.
+ get_filename_component(dst_dir "${dst}" PATH)
+ file(MAKE_DIRECTORY "${dst_dir}")
+ _ExternalData_random(random)
+ set(tmp "${dst}.tmp${random}")
+ if(UNIX AND NOT ExternalData_NO_SYMLINKS)
+ # Create a symbolic link.
+ set(tgt "${src}")
+ if(relative_top)
+ # Use relative path if files are close enough.
+ file(RELATIVE_PATH relsrc "${relative_top}" "${src}")
+ file(RELATIVE_PATH relfile "${relative_top}" "${dst}")
+ if(NOT IS_ABSOLUTE "${relsrc}" AND NOT "${relsrc}" MATCHES "^\\.\\./" AND
+ NOT IS_ABSOLUTE "${reldst}" AND NOT "${reldst}" MATCHES "^\\.\\./")
+ file(RELATIVE_PATH tgt "${dst_dir}" "${src}")
+ endif()
+ endif()
+ # Create link (falling back to copying if there's a problem).
+ file(CREATE_LINK "${tgt}" "${tmp}" RESULT result COPY_ON_ERROR SYMBOLIC)
+ else()
+ # Create a copy.
+ file(COPY_FILE "${src}" "${tmp}" RESULT result)
+ endif()
+ if(result)
+ file(REMOVE "${tmp}")
+ message(FATAL_ERROR "Failed to create\n ${tmp}\nfrom\n ${obj}")
+ endif()
+
+ # Atomically create/replace the real destination.
+ file(RENAME "${tmp}" "${dst}")
+endfunction()
+
+function(_ExternalData_download_file url file err_var msg_var)
+ set(retry 3)
+ while(retry)
+ math(EXPR retry "${retry} - 1")
+ if(ExternalData_TIMEOUT_INACTIVITY)
+ set(inactivity_timeout INACTIVITY_TIMEOUT ${ExternalData_TIMEOUT_INACTIVITY})
+ elseif(NOT "${ExternalData_TIMEOUT_INACTIVITY}" EQUAL 0)
+ set(inactivity_timeout INACTIVITY_TIMEOUT 60)
+ else()
+ set(inactivity_timeout "")
+ endif()
+ if(ExternalData_TIMEOUT_ABSOLUTE)
+ set(absolute_timeout TIMEOUT ${ExternalData_TIMEOUT_ABSOLUTE})
+ elseif(NOT "${ExternalData_TIMEOUT_ABSOLUTE}" EQUAL 0)
+ set(absolute_timeout TIMEOUT 300)
+ else()
+ set(absolute_timeout "")
+ endif()
+ set(show_progress_args)
+ if (ExternalData_SHOW_PROGRESS)
+ list(APPEND show_progress_args SHOW_PROGRESS)
+ endif ()
+ file(DOWNLOAD "${url}" "${file}" STATUS status LOG log ${inactivity_timeout} ${absolute_timeout} ${show_progress_args})
+ list(GET status 0 err)
+ list(GET status 1 msg)
+ if(err)
+ if("${msg}" MATCHES "HTTP response code said error" AND
+ "${log}" MATCHES "error: 503")
+ set(msg "temporarily unavailable")
+ endif()
+ elseif("${log}" MATCHES "\nHTTP[^\n]* 503")
+ set(err TRUE)
+ set(msg "temporarily unavailable")
+ endif()
+ if(NOT err OR NOT "${msg}" MATCHES "partial|timeout|temporarily")
+ break()
+ elseif(retry)
+ message(STATUS "[download terminated: ${msg}, retries left: ${retry}]")
+ endif()
+ endwhile()
+ set("${err_var}" "${err}" PARENT_SCOPE)
+ set("${msg_var}" "${msg}" PARENT_SCOPE)
+endfunction()
+
+function(_ExternalData_custom_fetch key loc file err_var msg_var)
+ if(NOT ExternalData_CUSTOM_SCRIPT_${key})
+ set(err 1)
+ set(msg "No ExternalData_CUSTOM_SCRIPT_${key} set!")
+ elseif(NOT EXISTS "${ExternalData_CUSTOM_SCRIPT_${key}}")
+ set(err 1)
+ set(msg "No '${ExternalData_CUSTOM_SCRIPT_${key}}' exists!")
+ else()
+ set(ExternalData_CUSTOM_LOCATION "${loc}")
+ set(ExternalData_CUSTOM_FILE "${file}")
+ unset(ExternalData_CUSTOM_ERROR)
+ include("${ExternalData_CUSTOM_SCRIPT_${key}}")
+ if(DEFINED ExternalData_CUSTOM_ERROR)
+ set(err 1)
+ set(msg "${ExternalData_CUSTOM_ERROR}")
+ else()
+ set(err 0)
+ set(msg "no error")
+ endif()
+ endif()
+ set("${err_var}" "${err}" PARENT_SCOPE)
+ set("${msg_var}" "${msg}" PARENT_SCOPE)
+endfunction()
+
+function(_ExternalData_get_from_object_store hash algo var_obj var_success)
+ # Search all object stores for an existing object.
+ foreach(dir ${ExternalData_OBJECT_STORES})
+ set(obj "${dir}/${algo}/${hash}")
+ if(EXISTS "${obj}")
+ message(STATUS "Found object: \"${obj}\"")
+ set("${var_obj}" "${obj}" PARENT_SCOPE)
+ set("${var_success}" 1 PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+endfunction()
+
+function(_ExternalData_download_object name hash algo var_obj var_success var_errorMsg)
+ # Search all object stores for an existing object.
+ set(success 1)
+ foreach(dir ${ExternalData_OBJECT_STORES})
+ set(obj "${dir}/${algo}/${hash}")
+ if(EXISTS "${obj}")
+ message(STATUS "Found object: \"${obj}\"")
+ set("${var_obj}" "${obj}" PARENT_SCOPE)
+ set("${var_success}" "${success}" PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+
+ # Download object to the first store.
+ list(GET ExternalData_OBJECT_STORES 0 store)
+ set(obj "${store}/${algo}/${hash}")
+
+ _ExternalData_random(random)
+ set(tmp "${obj}.tmp${random}")
+ set(found 0)
+ set(tried "")
+ foreach(url_template IN LISTS ExternalData_URL_TEMPLATES)
+ string(REPLACE "%(hash)" "${hash}" url_tmp "${url_template}")
+ string(REPLACE "%(algo)" "${algo}" url "${url_tmp}")
+ if(url MATCHES "^(.*)%\\(algo:([A-Za-z_][A-Za-z0-9_]*)\\)(.*)$")
+ set(lhs "${CMAKE_MATCH_1}")
+ set(key "${CMAKE_MATCH_2}")
+ set(rhs "${CMAKE_MATCH_3}")
+ if(DEFINED ExternalData_URL_ALGO_${algo}_${key})
+ set(url "${lhs}${ExternalData_URL_ALGO_${algo}_${key}}${rhs}")
+ else()
+ set(url "${lhs}${algo}${rhs}")
+ endif()
+ endif()
+ string(REGEX REPLACE "((https?|ftp)://)([^@]+@)?(.*)" "\\1\\4" secured_url "${url}")
+ message(STATUS "Fetching \"${secured_url}\"")
+ if(url MATCHES "^ExternalDataCustomScript://([A-Za-z_][A-Za-z0-9_]*)/(.*)$")
+ _ExternalData_custom_fetch("${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}" "${tmp}" err errMsg)
+ else()
+ _ExternalData_download_file("${url}" "${tmp}" err errMsg)
+ endif()
+ string(APPEND tried "\n ${url}")
+ if(err)
+ string(APPEND tried " (${errMsg})")
+ else()
+ # Verify downloaded object.
+ _ExternalData_compute_hash(dl_hash "${algo}" "${tmp}")
+ if("${dl_hash}" STREQUAL "${hash}")
+ set(found 1)
+ break()
+ else()
+ string(APPEND tried " (wrong hash ${algo}=${dl_hash})")
+ if("$ENV{ExternalData_DEBUG_DOWNLOAD}" MATCHES ".")
+ file(RENAME "${tmp}" "${store}/${algo}/${dl_hash}")
+ endif()
+ endif()
+ endif()
+ file(REMOVE "${tmp}")
+ endforeach()
+
+ get_filename_component(dir "${name}" PATH)
+ set(staged "${dir}/.ExternalData_${algo}_${hash}")
+
+ set(success 1)
+ if(found)
+ # Atomically create the object. If we lose a race with another process,
+ # do not replace it. Content-addressing ensures it has what we expect.
+ file(RENAME "${tmp}" "${obj}" NO_REPLACE RESULT result)
+ if (result STREQUAL "NO_REPLACE")
+ file(REMOVE "${tmp}")
+ elseif (result)
+ message(FATAL_ERROR "Failed to rename:\n \"${tmp}\"\nto:\n \"${obj}\"\nwith error:\n ${result}")
+ endif()
+ message(STATUS "Downloaded object: \"${obj}\"")
+ elseif(EXISTS "${staged}")
+ set(obj "${staged}")
+ message(STATUS "Staged object: \"${obj}\"")
+ else()
+ if(NOT tried)
+ set(tried "\n (No ExternalData_URL_TEMPLATES given)")
+ endif()
+ set(success 0)
+ set("${var_errorMsg}" "Object ${algo}=${hash} not found at:${tried}" PARENT_SCOPE)
+ endif()
+
+ set("${var_obj}" "${obj}" PARENT_SCOPE)
+ set("${var_success}" "${success}" PARENT_SCOPE)
+endfunction()
+
+if("${ExternalData_ACTION}" STREQUAL "fetch")
+ foreach(v ExternalData_OBJECT_STORES file name exts)
+ if(NOT DEFINED "${v}")
+ message(FATAL_ERROR "No \"-D${v}=\" value provided!")
+ endif()
+ endforeach()
+
+ string(REPLACE "+" ";" exts_list "${exts}")
+ set(succeeded 0)
+ set(errorMsg "")
+ set(hash_list )
+ set(algo_list )
+ set(hash )
+ set(algo )
+ foreach(ext ${exts_list})
+ file(READ "${name}${ext}" hash)
+ string(STRIP "${hash}" hash)
+
+ if("${ext}" MATCHES "^\\.(${_ExternalData_REGEX_EXT})$")
+ string(TOUPPER "${CMAKE_MATCH_1}" algo)
+ string(REPLACE "-" "_" algo "${algo}")
+ else()
+ message(FATAL_ERROR "Unknown hash algorithm extension \"${ext}\"")
+ endif()
+
+ list(APPEND hash_list ${hash})
+ list(APPEND algo_list ${algo})
+ endforeach()
+
+ list(LENGTH exts_list num_extensions)
+ math(EXPR exts_range "${num_extensions} - 1")
+ foreach(ii RANGE 0 ${exts_range})
+ list(GET hash_list ${ii} hash)
+ list(GET algo_list ${ii} algo)
+ _ExternalData_get_from_object_store("${hash}" "${algo}" obj succeeded)
+ if(succeeded)
+ break()
+ endif()
+ endforeach()
+ if(NOT succeeded)
+ foreach(ii RANGE 0 ${exts_range})
+ list(GET hash_list ${ii} hash)
+ list(GET algo_list ${ii} algo)
+ _ExternalData_download_object("${name}" "${hash}" "${algo}"
+ obj succeeded algoErrorMsg)
+ string(APPEND errorMsg "\n${algoErrorMsg}")
+ if(succeeded)
+ break()
+ endif()
+ endforeach()
+ endif()
+ if(NOT succeeded)
+ message(FATAL_ERROR "${errorMsg}")
+ endif()
+ # Check if file already corresponds to the object.
+ set(stamp "-hash-stamp")
+ set(file_up_to_date 0)
+ if(EXISTS "${file}" AND EXISTS "${file}${stamp}")
+ file(READ "${file}${stamp}" f_hash)
+ string(STRIP "${f_hash}" f_hash)
+ if("${f_hash}" STREQUAL "${hash}")
+ set(file_up_to_date 1)
+ endif()
+ endif()
+
+ if(file_up_to_date)
+ # Touch the file to convince the build system it is up to date.
+ file(TOUCH "${file}")
+ else()
+ _ExternalData_link_or_copy("${obj}" "${file}")
+ endif()
+
+ # Atomically update the hash/timestamp file to record the object referenced.
+ _ExternalData_atomic_write("${file}${stamp}" "${hash}\n")
+elseif("${ExternalData_ACTION}" STREQUAL "local")
+ foreach(v file name)
+ if(NOT DEFINED "${v}")
+ message(FATAL_ERROR "No \"-D${v}=\" value provided!")
+ endif()
+ endforeach()
+ _ExternalData_link_or_copy("${name}" "${file}")
+else()
+ message(FATAL_ERROR "Unknown ExternalData_ACTION=[${ExternalData_ACTION}]")
+endif()
diff --git a/Modules/ExternalData_config.cmake.in b/Modules/ExternalData_config.cmake.in
new file mode 100644
index 0000000..18be6b3
--- /dev/null
+++ b/Modules/ExternalData_config.cmake.in
@@ -0,0 +1,6 @@
+set(ExternalData_OBJECT_STORES "@ExternalData_OBJECT_STORES@")
+set(ExternalData_URL_TEMPLATES "@ExternalData_URL_TEMPLATES@")
+set(ExternalData_TIMEOUT_INACTIVITY "@ExternalData_TIMEOUT_INACTIVITY@")
+set(ExternalData_TIMEOUT_ABSOLUTE "@ExternalData_TIMEOUT_ABSOLUTE@")
+set(ExternalData_NO_SYMLINKS "@ExternalData_NO_SYMLINKS@")
+@_ExternalData_CONFIG_CODE@
diff --git a/Modules/ExternalProject-download.cmake.in b/Modules/ExternalProject-download.cmake.in
new file mode 100644
index 0000000..ff8c659
--- /dev/null
+++ b/Modules/ExternalProject-download.cmake.in
@@ -0,0 +1,173 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.5)
+
+function(check_file_hash has_hash hash_is_good)
+ if("${has_hash}" STREQUAL "")
+ message(FATAL_ERROR "has_hash Can't be empty")
+ endif()
+
+ if("${hash_is_good}" STREQUAL "")
+ message(FATAL_ERROR "hash_is_good Can't be empty")
+ endif()
+
+ if("@ALGO@" STREQUAL "")
+ # No check
+ set("${has_hash}" FALSE PARENT_SCOPE)
+ set("${hash_is_good}" FALSE PARENT_SCOPE)
+ return()
+ endif()
+
+ set("${has_hash}" TRUE PARENT_SCOPE)
+
+ message(STATUS "verifying file...
+ file='@LOCAL@'")
+
+ file("@ALGO@" "@LOCAL@" actual_value)
+
+ if(NOT "${actual_value}" STREQUAL "@EXPECT_VALUE@")
+ set("${hash_is_good}" FALSE PARENT_SCOPE)
+ message(STATUS "@ALGO@ hash of
+ @LOCAL@
+ does not match expected value
+ expected: '@EXPECT_VALUE@'
+ actual: '${actual_value}'")
+ else()
+ set("${hash_is_good}" TRUE PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(sleep_before_download attempt)
+ if(attempt EQUAL 0)
+ return()
+ endif()
+
+ if(attempt EQUAL 1)
+ message(STATUS "Retrying...")
+ return()
+ endif()
+
+ set(sleep_seconds 0)
+
+ if(attempt EQUAL 2)
+ set(sleep_seconds 5)
+ elseif(attempt EQUAL 3)
+ set(sleep_seconds 5)
+ elseif(attempt EQUAL 4)
+ set(sleep_seconds 15)
+ elseif(attempt EQUAL 5)
+ set(sleep_seconds 60)
+ elseif(attempt EQUAL 6)
+ set(sleep_seconds 90)
+ elseif(attempt EQUAL 7)
+ set(sleep_seconds 300)
+ else()
+ set(sleep_seconds 1200)
+ endif()
+
+ message(STATUS "Retry after ${sleep_seconds} seconds (attempt #${attempt}) ...")
+
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep "${sleep_seconds}")
+endfunction()
+
+if("@LOCAL@" STREQUAL "")
+ message(FATAL_ERROR "LOCAL can't be empty")
+endif()
+
+if("@REMOTE@" STREQUAL "")
+ message(FATAL_ERROR "REMOTE can't be empty")
+endif()
+
+if(EXISTS "@LOCAL@")
+ check_file_hash(has_hash hash_is_good)
+ if(has_hash)
+ if(hash_is_good)
+ message(STATUS "File already exists and hash match (skip download):
+ file='@LOCAL@'
+ @ALGO@='@EXPECT_VALUE@'"
+ )
+ return()
+ else()
+ message(STATUS "File already exists but hash mismatch. Removing...")
+ file(REMOVE "@LOCAL@")
+ endif()
+ else()
+ message(STATUS "File already exists but no hash specified (use URL_HASH):
+ file='@LOCAL@'
+Old file will be removed and new file downloaded from URL."
+ )
+ file(REMOVE "@LOCAL@")
+ endif()
+endif()
+
+set(retry_number 5)
+
+message(STATUS "Downloading...
+ dst='@LOCAL@'
+ timeout='@TIMEOUT_MSG@'
+ inactivity timeout='@INACTIVITY_TIMEOUT_MSG@'"
+)
+set(download_retry_codes 7 6 8 15)
+set(skip_url_list)
+set(status_code)
+foreach(i RANGE ${retry_number})
+ if(status_code IN_LIST download_retry_codes)
+ sleep_before_download(${i})
+ endif()
+ foreach(url @REMOTE@)
+ if(NOT url IN_LIST skip_url_list)
+ message(STATUS "Using src='${url}'")
+
+ @TLS_VERIFY_CODE@
+ @TLS_CAINFO_CODE@
+ @NETRC_CODE@
+ @NETRC_FILE_CODE@
+
+ file(
+ DOWNLOAD
+ "${url}" "@LOCAL@"
+ @SHOW_PROGRESS@
+ @TIMEOUT_ARGS@
+ @INACTIVITY_TIMEOUT_ARGS@
+ STATUS status
+ LOG log
+ @USERPWD_ARGS@
+ @HTTP_HEADERS_ARGS@
+ )
+
+ list(GET status 0 status_code)
+ list(GET status 1 status_string)
+
+ if(status_code EQUAL 0)
+ check_file_hash(has_hash hash_is_good)
+ if(has_hash AND NOT hash_is_good)
+ message(STATUS "Hash mismatch, removing...")
+ file(REMOVE "@LOCAL@")
+ else()
+ message(STATUS "Downloading... done")
+ return()
+ endif()
+ else()
+ string(APPEND logFailedURLs "error: downloading '${url}' failed
+ status_code: ${status_code}
+ status_string: ${status_string}
+ log:
+ --- LOG BEGIN ---
+ ${log}
+ --- LOG END ---
+ "
+ )
+ if(NOT status_code IN_LIST download_retry_codes)
+ list(APPEND skip_url_list "${url}")
+ break()
+ endif()
+ endif()
+ endif()
+ endforeach()
+endforeach()
+
+message(FATAL_ERROR "Each download failed!
+ ${logFailedURLs}
+ "
+)
diff --git a/Modules/ExternalProject-gitupdate.cmake.in b/Modules/ExternalProject-gitupdate.cmake.in
new file mode 100644
index 0000000..7033918
--- /dev/null
+++ b/Modules/ExternalProject-gitupdate.cmake.in
@@ -0,0 +1,277 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.5)
+
+function(get_hash_for_ref ref out_var err_var)
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" rev-parse "${ref}"
+ WORKING_DIRECTORY "@work_dir@"
+ RESULT_VARIABLE error_code
+ OUTPUT_VARIABLE ref_hash
+ ERROR_VARIABLE error_msg
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if(error_code)
+ set(${out_var} "" PARENT_SCOPE)
+ else()
+ set(${out_var} "${ref_hash}" PARENT_SCOPE)
+ endif()
+ set(${err_var} "${error_msg}" PARENT_SCOPE)
+endfunction()
+
+get_hash_for_ref(HEAD head_sha error_msg)
+if(head_sha STREQUAL "")
+ message(FATAL_ERROR "Failed to get the hash for HEAD:\n${error_msg}")
+endif()
+
+
+execute_process(
+ COMMAND "@git_EXECUTABLE@" show-ref "@git_tag@"
+ WORKING_DIRECTORY "@work_dir@"
+ OUTPUT_VARIABLE show_ref_output
+)
+if(show_ref_output MATCHES "^[a-z0-9]+[ \\t]+refs/remotes/")
+ # Given a full remote/branch-name and we know about it already. Since
+ # branches can move around, we always have to fetch.
+ set(fetch_required YES)
+ set(checkout_name "@git_tag@")
+
+elseif(show_ref_output MATCHES "^[a-z0-9]+[ \\t]+refs/tags/")
+ # Given a tag name that we already know about. We don't know if the tag we
+ # have matches the remote though (tags can move), so we should fetch.
+ set(fetch_required YES)
+ set(checkout_name "@git_tag@")
+
+ # Special case to preserve backward compatibility: if we are already at the
+ # same commit as the tag we hold locally, don't do a fetch and assume the tag
+ # hasn't moved on the remote.
+ # FIXME: We should provide an option to always fetch for this case
+ get_hash_for_ref("@git_tag@" tag_sha error_msg)
+ if(tag_sha STREQUAL head_sha)
+ message(VERBOSE "Already at requested tag: ${tag_sha}")
+ return()
+ endif()
+
+elseif(show_ref_output MATCHES "^[a-z0-9]+[ \\t]+refs/heads/")
+ # Given a branch name without any remote and we already have a branch by that
+ # name. We might already have that branch checked out or it might be a
+ # different branch. It isn't safe to use a bare branch name without the
+ # remote, so do a fetch and replace the ref with one that includes the remote.
+ set(fetch_required YES)
+ set(checkout_name "@git_remote_name@/@git_tag@")
+
+else()
+ get_hash_for_ref("@git_tag@" tag_sha error_msg)
+ if(tag_sha STREQUAL head_sha)
+ # Have the right commit checked out already
+ message(VERBOSE "Already at requested ref: ${tag_sha}")
+ return()
+
+ elseif(tag_sha STREQUAL "")
+ # We don't know about this ref yet, so we have no choice but to fetch.
+ # We deliberately swallow any error message at the default log level
+ # because it can be confusing for users to see a failed git command.
+ # That failure is being handled here, so it isn't an error.
+ set(fetch_required YES)
+ set(checkout_name "@git_tag@")
+ if(NOT error_msg STREQUAL "")
+ message(VERBOSE "${error_msg}")
+ endif()
+
+ else()
+ # We have the commit, so we know we were asked to find a commit hash
+ # (otherwise it would have been handled further above), but we don't
+ # have that commit checked out yet
+ set(fetch_required NO)
+ set(checkout_name "@git_tag@")
+ if(NOT error_msg STREQUAL "")
+ message(WARNING "${error_msg}")
+ endif()
+
+ endif()
+endif()
+
+if(fetch_required)
+ message(VERBOSE "Fetching latest from the remote @git_remote_name@")
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" fetch --tags --force "@git_remote_name@"
+ WORKING_DIRECTORY "@work_dir@"
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+endif()
+
+set(git_update_strategy "@git_update_strategy@")
+if(git_update_strategy STREQUAL "")
+ # Backward compatibility requires REBASE as the default behavior
+ set(git_update_strategy REBASE)
+endif()
+
+if(git_update_strategy MATCHES "^REBASE(_CHECKOUT)?$")
+ # Asked to potentially try to rebase first, maybe with fallback to checkout.
+ # We can't if we aren't already on a branch and we shouldn't if that local
+ # branch isn't tracking the one we want to checkout.
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" symbolic-ref -q HEAD
+ WORKING_DIRECTORY "@work_dir@"
+ OUTPUT_VARIABLE current_branch
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ # Don't test for an error. If this isn't a branch, we get a non-zero error
+ # code but empty output.
+ )
+
+ if(current_branch STREQUAL "")
+ # Not on a branch, checkout is the only sensible option since any rebase
+ # would always fail (and backward compatibility requires us to checkout in
+ # this situation)
+ set(git_update_strategy CHECKOUT)
+
+ else()
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" for-each-ref "--format='%(upstream:short)'" "${current_branch}"
+ WORKING_DIRECTORY "@work_dir@"
+ OUTPUT_VARIABLE upstream_branch
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ COMMAND_ERROR_IS_FATAL ANY # There is no error if no upstream is set
+ )
+ if(NOT upstream_branch STREQUAL checkout_name)
+ # Not safe to rebase when asked to checkout a different branch to the one
+ # we are tracking. If we did rebase, we could end up with arbitrary
+ # commits added to the ref we were asked to checkout if the current local
+ # branch happens to be able to rebase onto the target branch. There would
+ # be no error message and the user wouldn't know this was occurring.
+ set(git_update_strategy CHECKOUT)
+ endif()
+
+ endif()
+elseif(NOT git_update_strategy STREQUAL "CHECKOUT")
+ message(FATAL_ERROR "Unsupported git update strategy: ${git_update_strategy}")
+endif()
+
+
+# Check if stash is needed
+execute_process(
+ COMMAND "@git_EXECUTABLE@" status --porcelain
+ WORKING_DIRECTORY "@work_dir@"
+ RESULT_VARIABLE error_code
+ OUTPUT_VARIABLE repo_status
+)
+if(error_code)
+ message(FATAL_ERROR "Failed to get the status")
+endif()
+string(LENGTH "${repo_status}" need_stash)
+
+# If not in clean state, stash changes in order to be able to perform a
+# rebase or checkout without losing those changes permanently
+if(need_stash)
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" stash save @git_stash_save_options@
+ WORKING_DIRECTORY "@work_dir@"
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+endif()
+
+if(git_update_strategy STREQUAL "CHECKOUT")
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" checkout "${checkout_name}"
+ WORKING_DIRECTORY "@work_dir@"
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+else()
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" rebase "${checkout_name}"
+ WORKING_DIRECTORY "@work_dir@"
+ RESULT_VARIABLE error_code
+ OUTPUT_VARIABLE rebase_output
+ ERROR_VARIABLE rebase_output
+ )
+ if(error_code)
+ # Rebase failed, undo the rebase attempt before continuing
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" rebase --abort
+ WORKING_DIRECTORY "@work_dir@"
+ )
+
+ if(NOT git_update_strategy STREQUAL "REBASE_CHECKOUT")
+ # Not allowed to do a checkout as a fallback, so cannot proceed
+ if(need_stash)
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
+ WORKING_DIRECTORY "@work_dir@"
+ )
+ endif()
+ message(FATAL_ERROR "\nFailed to rebase in: '@work_dir@'."
+ "\nOutput from the attempted rebase follows:"
+ "\n${rebase_output}"
+ "\n\nYou will have to resolve the conflicts manually")
+ endif()
+
+ # Fall back to checkout. We create an annotated tag so that the user
+ # can manually inspect the situation and revert if required.
+ # We can't log the failed rebase output because MSVC sees it and
+ # intervenes, causing the build to fail even though it completes.
+ # Write it to a file instead.
+ string(TIMESTAMP tag_timestamp "%Y%m%dT%H%M%S" UTC)
+ set(tag_name _cmake_ExternalProject_moved_from_here_${tag_timestamp}Z)
+ set(error_log_file ${CMAKE_CURRENT_LIST_DIR}/rebase_error_${tag_timestamp}Z.log)
+ file(WRITE ${error_log_file} "${rebase_output}")
+ message(WARNING "Rebase failed, output has been saved to ${error_log_file}"
+ "\nFalling back to checkout, previous commit tagged as ${tag_name}")
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" tag -a
+ -m "ExternalProject attempting to move from here to ${checkout_name}"
+ ${tag_name}
+ WORKING_DIRECTORY "@work_dir@"
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" checkout "${checkout_name}"
+ WORKING_DIRECTORY "@work_dir@"
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ endif()
+endif()
+
+if(need_stash)
+ # Put back the stashed changes
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
+ WORKING_DIRECTORY "@work_dir@"
+ RESULT_VARIABLE error_code
+ )
+ if(error_code)
+ # Stash pop --index failed: Try again dropping the index
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" reset --hard --quiet
+ WORKING_DIRECTORY "@work_dir@"
+ )
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" stash pop --quiet
+ WORKING_DIRECTORY "@work_dir@"
+ RESULT_VARIABLE error_code
+ )
+ if(error_code)
+ # Stash pop failed: Restore previous state.
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" reset --hard --quiet ${head_sha}
+ WORKING_DIRECTORY "@work_dir@"
+ )
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
+ WORKING_DIRECTORY "@work_dir@"
+ )
+ message(FATAL_ERROR "\nFailed to unstash changes in: '@work_dir@'."
+ "\nYou will have to resolve the conflicts manually")
+ endif()
+ endif()
+endif()
+
+set(init_submodules "@init_submodules@")
+if(init_submodules)
+ execute_process(
+ COMMAND "@git_EXECUTABLE@" submodule update @git_submodules_recurse@ --init @git_submodules@
+ WORKING_DIRECTORY "@work_dir@"
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+endif()
diff --git a/Modules/ExternalProject-verify.cmake.in b/Modules/ExternalProject-verify.cmake.in
new file mode 100644
index 0000000..c06da4e
--- /dev/null
+++ b/Modules/ExternalProject-verify.cmake.in
@@ -0,0 +1,37 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.5)
+
+if("@LOCAL@" STREQUAL "")
+ message(FATAL_ERROR "LOCAL can't be empty")
+endif()
+
+if(NOT EXISTS "@LOCAL@")
+ message(FATAL_ERROR "File not found: @LOCAL@")
+endif()
+
+if("@ALGO@" STREQUAL "")
+ message(WARNING "File will not be verified since no URL_HASH specified")
+ return()
+endif()
+
+if("@EXPECT_VALUE@" STREQUAL "")
+ message(FATAL_ERROR "EXPECT_VALUE can't be empty")
+endif()
+
+message(STATUS "verifying file...
+ file='@LOCAL@'")
+
+file("@ALGO@" "@LOCAL@" actual_value)
+
+if(NOT "${actual_value}" STREQUAL "@EXPECT_VALUE@")
+ message(FATAL_ERROR "error: @ALGO@ hash of
+ @LOCAL@
+does not match expected value
+ expected: '@EXPECT_VALUE@'
+ actual: '${actual_value}'
+")
+endif()
+
+message(STATUS "verifying file... done")
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake
new file mode 100644
index 0000000..56525080
--- /dev/null
+++ b/Modules/ExternalProject.cmake
@@ -0,0 +1,3694 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include_guard(GLOBAL)
+
+#[=======================================================================[.rst:
+ExternalProject
+---------------
+
+.. only:: html
+
+ .. contents::
+
+Commands
+^^^^^^^^
+
+External Project Definition
+"""""""""""""""""""""""""""
+
+.. command:: ExternalProject_Add
+
+ The ``ExternalProject_Add()`` function creates a custom target to drive
+ download, update/patch, configure, build, install and test steps of an
+ external project:
+
+ .. code-block:: cmake
+
+ ExternalProject_Add(<name> [<option>...])
+
+ The individual steps within the process can be driven independently if
+ required (e.g. for CDash submission) and extra custom steps can be defined,
+ along with the ability to control the step dependencies. The directory
+ structure used for the management of the external project can also be
+ customized. The function supports a large number of options which can be used
+ to tailor the external project behavior.
+
+ **Directory Options:**
+ Most of the time, the default directory layout is sufficient. It is largely
+ an implementation detail that the main project usually doesn't need to
+ change. In some circumstances, however, control over the directory layout
+ can be useful or necessary. The directory options are potentially more
+ useful from the point of view that the main build can use the
+ :command:`ExternalProject_Get_Property` command to retrieve their values,
+ thereby allowing the main project to refer to build artifacts of the
+ external project.
+
+ ``PREFIX <dir>``
+ Root directory for the external project. Unless otherwise noted below,
+ all other directories associated with the external project will be
+ created under here.
+
+ ``TMP_DIR <dir>``
+ Directory in which to store temporary files.
+
+ ``STAMP_DIR <dir>``
+ Directory in which to store the timestamps of each step. Log files from
+ individual steps are also created in here unless overridden by LOG_DIR
+ (see *Logging Options* below).
+
+ ``LOG_DIR <dir>``
+ .. versionadded:: 3.14
+
+ Directory in which to store the logs of each step.
+
+ ``DOWNLOAD_DIR <dir>``
+ Directory in which to store downloaded files before unpacking them. This
+ directory is only used by the URL download method, all other download
+ methods use ``SOURCE_DIR`` directly instead.
+
+ ``SOURCE_DIR <dir>``
+ Source directory into which downloaded contents will be unpacked, or for
+ non-URL download methods, the directory in which the repository should be
+ checked out, cloned, etc. If no download method is specified, this must
+ point to an existing directory where the external project has already
+ been unpacked or cloned/checked out.
+
+ .. note::
+ If a download method is specified, any existing contents of the source
+ directory may be deleted. Only the URL download method checks whether
+ this directory is either missing or empty before initiating the
+ download, stopping with an error if it is not empty. All other
+ download methods silently discard any previous contents of the source
+ directory.
+
+ ``BINARY_DIR <dir>``
+ Specify the build directory location. This option is ignored if
+ ``BUILD_IN_SOURCE`` is enabled.
+
+ ``INSTALL_DIR <dir>``
+ Installation prefix to be placed in the ``<INSTALL_DIR>`` placeholder.
+ This does not actually configure the external project to install to
+ the given prefix. That must be done by passing appropriate arguments
+ to the external project configuration step, e.g. using ``<INSTALL_DIR>``.
+
+ If any of the above ``..._DIR`` options are not specified, their defaults
+ are computed as follows. If the ``PREFIX`` option is given or the
+ ``EP_PREFIX`` directory property is set, then an external project is built
+ and installed under the specified prefix::
+
+ TMP_DIR = <prefix>/tmp
+ STAMP_DIR = <prefix>/src/<name>-stamp
+ DOWNLOAD_DIR = <prefix>/src
+ SOURCE_DIR = <prefix>/src/<name>
+ BINARY_DIR = <prefix>/src/<name>-build
+ INSTALL_DIR = <prefix>
+ LOG_DIR = <STAMP_DIR>
+
+ Otherwise, if the ``EP_BASE`` directory property is set then components
+ of an external project are stored under the specified base::
+
+ TMP_DIR = <base>/tmp/<name>
+ STAMP_DIR = <base>/Stamp/<name>
+ DOWNLOAD_DIR = <base>/Download/<name>
+ SOURCE_DIR = <base>/Source/<name>
+ BINARY_DIR = <base>/Build/<name>
+ INSTALL_DIR = <base>/Install/<name>
+ LOG_DIR = <STAMP_DIR>
+
+ If no ``PREFIX``, ``EP_PREFIX``, or ``EP_BASE`` is specified, then the
+ default is to set ``PREFIX`` to ``<name>-prefix``. Relative paths are
+ interpreted with respect to :variable:`CMAKE_CURRENT_BINARY_DIR` at the
+ point where ``ExternalProject_Add()`` is called.
+
+ **Download Step Options:**
+ A download method can be omitted if the ``SOURCE_DIR`` option is used to
+ point to an existing non-empty directory. Otherwise, one of the download
+ methods below must be specified (multiple download methods should not be
+ given) or a custom ``DOWNLOAD_COMMAND`` provided.
+
+ ``DOWNLOAD_COMMAND <cmd>...``
+ Overrides the command used for the download step
+ (:manual:`generator expressions <cmake-generator-expressions(7)>` are
+ supported). If this option is specified, all other download options will
+ be ignored. Providing an empty string for ``<cmd>`` effectively disables
+ the download step.
+
+ *URL Download*
+ ``URL <url1> [<url2>...]``
+ List of paths and/or URL(s) of the external project's source. When more
+ than one URL is given, they are tried in turn until one succeeds. A URL
+ may be an ordinary path in the local file system (in which case it
+ must be the only URL provided) or any downloadable URL supported by the
+ :command:`file(DOWNLOAD)` command. A local filesystem path may refer to
+ either an existing directory or to an archive file, whereas a URL is
+ expected to point to a file which can be treated as an archive. When an
+ archive is used, it will be unpacked automatically unless the
+ ``DOWNLOAD_NO_EXTRACT`` option is set to prevent it. The archive type
+ is determined by inspecting the actual content rather than using logic
+ based on the file extension.
+
+ .. versionchanged:: 3.7
+ Multiple URLs are allowed.
+
+ ``URL_HASH <algo>=<hashValue>``
+ Hash of the archive file to be downloaded. The argument should be of
+ the form ``<algo>=<hashValue>`` where ``algo`` can be any of the hashing
+ algorithms supported by the :command:`file()` command. Specifying this
+ option is strongly recommended for URL downloads, as it ensures the
+ integrity of the downloaded content. It is also used as a check for a
+ previously downloaded file, allowing connection to the remote location
+ to be avoided altogether if the local directory already has a file from
+ an earlier download that matches the specified hash.
+
+ ``URL_MD5 <md5>``
+ Equivalent to ``URL_HASH MD5=<md5>``.
+
+ ``DOWNLOAD_NAME <fname>``
+ File name to use for the downloaded file. If not given, the end of the
+ URL is used to determine the file name. This option is rarely needed,
+ the default name is generally suitable and is not normally used outside
+ of code internal to the ``ExternalProject`` module.
+
+ ``DOWNLOAD_NO_EXTRACT <bool>``
+ .. versionadded:: 3.6
+
+ Allows the extraction part of the download step to be disabled by
+ passing a boolean true value for this option. If this option is not
+ given, the downloaded contents will be unpacked automatically if
+ required. If extraction has been disabled, the full path to the
+ downloaded file is available as ``<DOWNLOADED_FILE>`` in subsequent
+ steps or as the property ``DOWNLOADED_FILE`` with the
+ :command:`ExternalProject_Get_Property` command.
+
+ ``DOWNLOAD_NO_PROGRESS <bool>``
+ Can be used to disable logging the download progress. If this option is
+ not given, download progress messages will be logged.
+
+ ``TIMEOUT <seconds>``
+ Maximum time allowed for file download operations.
+
+ ``INACTIVITY_TIMEOUT <seconds>``
+ .. versionadded:: 3.19
+
+ Terminate the operation after a period of inactivity.
+
+ ``HTTP_USERNAME <username>``
+ .. versionadded:: 3.7
+
+ Username for the download operation if authentication is required.
+
+ ``HTTP_PASSWORD <password>``
+ .. versionadded:: 3.7
+
+ Password for the download operation if authentication is required.
+
+ ``HTTP_HEADER <header1> [<header2>...]``
+ .. versionadded:: 3.7
+
+ Provides an arbitrary list of HTTP headers for the download operation.
+ This can be useful for accessing content in systems like AWS, etc.
+
+ ``TLS_VERIFY <bool>``
+ Specifies whether certificate verification should be performed for
+ https URLs. If this option is not provided, the default behavior is
+ determined by the ``CMAKE_TLS_VERIFY`` variable (see
+ :command:`file(DOWNLOAD)`). If that is also not set, certificate
+ verification will not be performed. In situations where ``URL_HASH``
+ cannot be provided, this option can be an alternative verification
+ measure.
+
+ .. versionchanged:: 3.6
+ This option also applies to ``git clone`` invocations.
+
+ ``TLS_CAINFO <file>``
+ Specify a custom certificate authority file to use if ``TLS_VERIFY``
+ is enabled. If this option is not specified, the value of the
+ ``CMAKE_TLS_CAINFO`` variable will be used instead (see
+ :command:`file(DOWNLOAD)`)
+
+ ``NETRC <level>``
+ .. versionadded:: 3.11
+
+ Specify whether the ``.netrc`` file is to be used for operation.
+ If this option is not specified, the value of the ``CMAKE_NETRC``
+ variable will be used instead (see :command:`file(DOWNLOAD)`)
+ Valid levels are:
+
+ ``IGNORED``
+ The ``.netrc`` file is ignored.
+ This is the default.
+ ``OPTIONAL``
+ The ``.netrc`` file is optional, and information in the URL
+ is preferred. The file will be scanned to find which ever
+ information is not specified in the URL.
+ ``REQUIRED``
+ The ``.netrc`` file is required, and information in the URL
+ is ignored.
+
+ ``NETRC_FILE <file>``
+ .. versionadded:: 3.11
+
+ Specify an alternative ``.netrc`` file to the one in your home directory
+ if the ``NETRC`` level is ``OPTIONAL`` or ``REQUIRED``. If this option
+ is not specified, the value of the ``CMAKE_NETRC_FILE`` variable will
+ be used instead (see :command:`file(DOWNLOAD)`)
+
+ .. versionadded:: 3.1
+ Added support for `tbz2`, `.tar.xz`, `.txz`, and `.7z` extensions.
+
+ *Git*
+ NOTE: A git version of 1.6.5 or later is required if this download method
+ is used.
+
+ ``GIT_REPOSITORY <url>``
+ URL of the git repository. Any URL understood by the ``git`` command
+ may be used.
+
+ ``GIT_TAG <tag>``
+ Git branch name, tag or commit hash. Note that branch names and tags
+ should generally be specified as remote names (i.e. ``origin/myBranch``
+ rather than simply ``myBranch``). This ensures that if the remote end
+ has its tag moved or branch rebased or history rewritten, the local
+ clone will still be updated correctly. In general, however, specifying
+ a commit hash should be preferred for a number of reasons:
+
+ - If the local clone already has the commit corresponding to the hash,
+ no ``git fetch`` needs to be performed to check for changes each time
+ CMake is re-run. This can result in a significant speed up if many
+ external projects are being used.
+ - Using a specific git hash ensures that the main project's own history
+ is fully traceable to a specific point in the external project's
+ evolution. If a branch or tag name is used instead, then checking out
+ a specific commit of the main project doesn't necessarily pin the
+ whole build to a specific point in the life of the external project.
+ The lack of such deterministic behavior makes the main project lose
+ traceability and repeatability.
+
+ If ``GIT_SHALLOW`` is enabled then ``GIT_TAG`` works only with
+ branch names and tags. A commit hash is not allowed.
+
+ ``GIT_REMOTE_NAME <name>``
+ The optional name of the remote. If this option is not specified, it
+ defaults to ``origin``.
+
+ ``GIT_SUBMODULES <module>...``
+ Specific git submodules that should also be updated. If this option is
+ not provided, all git submodules will be updated.
+
+ .. versionchanged:: 3.16
+ When :policy:`CMP0097` is set to ``NEW``, if this value is set
+ to an empty string then no submodules are initialized or updated.
+
+ ``GIT_SUBMODULES_RECURSE <bool>``
+ .. versionadded:: 3.17
+
+ Specify whether git submodules (if any) should update recursively by
+ passing the ``--recursive`` flag to ``git submodule update``.
+ If not specified, the default is on.
+
+ ``GIT_SHALLOW <bool>``
+ .. versionadded:: 3.6
+
+ When this option is enabled, the ``git clone`` operation will be given
+ the ``--depth 1`` option. This performs a shallow clone, which avoids
+ downloading the whole history and instead retrieves just the commit
+ denoted by the ``GIT_TAG`` option.
+
+ ``GIT_PROGRESS <bool>``
+ .. versionadded:: 3.8
+
+ When enabled, this option instructs the ``git clone`` operation to
+ report its progress by passing it the ``--progress`` option. Without
+ this option, the clone step for large projects may appear to make the
+ build stall, since nothing will be logged until the clone operation
+ finishes. While this option can be used to provide progress to prevent
+ the appearance of the build having stalled, it may also make the build
+ overly noisy if lots of external projects are used.
+
+ ``GIT_CONFIG <option1> [<option2>...]``
+ .. versionadded:: 3.8
+
+ Specify a list of config options to pass to ``git clone``. Each option
+ listed will be transformed into its own ``--config <option>`` on the
+ ``git clone`` command line, with each option required to be in the
+ form ``key=value``.
+
+ ``GIT_REMOTE_UPDATE_STRATEGY <strategy>``
+ .. versionadded:: 3.18
+
+ When ``GIT_TAG`` refers to a remote branch, this option can be used to
+ specify how the update step behaves. The ``<strategy>`` must be one of
+ the following:
+
+ ``CHECKOUT``
+ Ignore the local branch and always checkout the branch specified by
+ ``GIT_TAG``.
+
+ ``REBASE``
+ Try to rebase the current branch to the one specified by ``GIT_TAG``.
+ If there are local uncommitted changes, they will be stashed first
+ and popped again after rebasing. If rebasing or popping stashed
+ changes fail, abort the rebase and halt with an error.
+ When ``GIT_REMOTE_UPDATE_STRATEGY`` is not present, this is the
+ default strategy unless the default has been overridden with
+ ``CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY`` (see below).
+
+ ``REBASE_CHECKOUT``
+ Same as ``REBASE`` except if the rebase fails, an annotated tag will
+ be created at the original ``HEAD`` position from before the rebase
+ and then checkout ``GIT_TAG`` just like the ``CHECKOUT`` strategy.
+ The message stored on the annotated tag will give information about
+ what was attempted and the tag name will include a timestamp so that
+ each failed run will add a new tag. This strategy ensures no changes
+ will be lost, but updates should always succeed if ``GIT_TAG`` refers
+ to a valid ref unless there are uncommitted changes that cannot be
+ popped successfully.
+
+ The variable ``CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY`` can be set to
+ override the default strategy. This variable should not be set by a
+ project, it is intended for the user to set. It is primarily intended
+ for use in continuous integration scripts to ensure that when history
+ is rewritten on a remote branch, the build doesn't end up with unintended
+ changes or failed builds resulting from conflicts during rebase operations.
+
+ *Subversion*
+ ``SVN_REPOSITORY <url>``
+ URL of the Subversion repository.
+
+ ``SVN_REVISION -r<rev>``
+ Revision to checkout from the Subversion repository.
+
+ ``SVN_USERNAME <username>``
+ Username for the Subversion checkout and update.
+
+ ``SVN_PASSWORD <password>``
+ Password for the Subversion checkout and update.
+
+ ``SVN_TRUST_CERT <bool>``
+ Specifies whether to trust the Subversion server site certificate. If
+ enabled, the ``--trust-server-cert`` option is passed to the ``svn``
+ checkout and update commands.
+
+ *Mercurial*
+ ``HG_REPOSITORY <url>``
+ URL of the mercurial repository.
+
+ ``HG_TAG <tag>``
+ Mercurial branch name, tag or commit id.
+
+ *CVS*
+ ``CVS_REPOSITORY <cvsroot>``
+ CVSROOT of the CVS repository.
+
+ ``CVS_MODULE <mod>``
+ Module to checkout from the CVS repository.
+
+ ``CVS_TAG <tag>``
+ Tag to checkout from the CVS repository.
+
+ **Update/Patch Step Options:**
+ Whenever CMake is re-run, by default the external project's sources will be
+ updated if the download method supports updates (e.g. a git repository
+ would be checked if the ``GIT_TAG`` does not refer to a specific commit).
+
+ ``UPDATE_COMMAND <cmd>...``
+ Overrides the download method's update step with a custom command.
+ The command may use
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+ ``UPDATE_DISCONNECTED <bool>``
+ .. versionadded:: 3.2
+
+ When enabled, this option causes the update step to be skipped. It does
+ not, however, prevent the download step. The update step can still be
+ added as a step target (see :command:`ExternalProject_Add_StepTargets`)
+ and called manually. This is useful if you want to allow developers to
+ build the project when disconnected from the network (the network may
+ still be needed for the download step though).
+
+ When this option is present, it is generally advisable to make the value
+ a cache variable under the developer's control rather than hard-coding
+ it. If this option is not present, the default value is taken from the
+ ``EP_UPDATE_DISCONNECTED`` directory property. If that is also not
+ defined, updates are performed as normal. The ``EP_UPDATE_DISCONNECTED``
+ directory property is intended as a convenience for controlling the
+ ``UPDATE_DISCONNECTED`` behavior for an entire section of a project's
+ directory hierarchy and may be a more convenient method of giving
+ developers control over whether or not to perform updates (assuming the
+ project also provides a cache variable or some other convenient method
+ for setting the directory property).
+
+ This may cause a step target to be created automatically for the
+ ``download`` step. See policy :policy:`CMP0114`.
+
+ ``PATCH_COMMAND <cmd>...``
+ Specifies a custom command to patch the sources after an update. By
+ default, no patch command is defined. Note that it can be quite difficult
+ to define an appropriate patch command that performs robustly, especially
+ for download methods such as git where changing the ``GIT_TAG`` will not
+ discard changes from a previous patch, but the patch command will be
+ called again after updating to the new tag.
+
+ **Configure Step Options:**
+ The configure step is run after the download and update steps. By default,
+ the external project is assumed to be a CMake project, but this can be
+ overridden if required.
+
+ ``CONFIGURE_COMMAND <cmd>...``
+ The default configure command runs CMake with options based on the main
+ project. For non-CMake external projects, the ``CONFIGURE_COMMAND``
+ option must be used to override this behavior
+ (:manual:`generator expressions <cmake-generator-expressions(7)>` are
+ supported). For projects that require no configure step, specify this
+ option with an empty string as the command to execute.
+
+ ``CMAKE_COMMAND /.../cmake``
+ Specify an alternative cmake executable for the configure step (use an
+ absolute path). This is generally not recommended, since it is
+ usually desirable to use the same CMake version throughout the whole
+ build. This option is ignored if a custom configure command has been
+ specified with ``CONFIGURE_COMMAND``.
+
+ ``CMAKE_GENERATOR <gen>``
+ Override the CMake generator used for the configure step. Without this
+ option, the same generator as the main build will be used. This option is
+ ignored if a custom configure command has been specified with the
+ ``CONFIGURE_COMMAND`` option.
+
+ ``CMAKE_GENERATOR_PLATFORM <platform>``
+ .. versionadded:: 3.1
+
+ Pass a generator-specific platform name to the CMake command (see
+ :variable:`CMAKE_GENERATOR_PLATFORM`). It is an error to provide this
+ option without the ``CMAKE_GENERATOR`` option.
+
+ ``CMAKE_GENERATOR_TOOLSET <toolset>``
+ Pass a generator-specific toolset name to the CMake command (see
+ :variable:`CMAKE_GENERATOR_TOOLSET`). It is an error to provide this
+ option without the ``CMAKE_GENERATOR`` option.
+
+ ``CMAKE_GENERATOR_INSTANCE <instance>``
+ .. versionadded:: 3.11
+
+ Pass a generator-specific instance selection to the CMake command (see
+ :variable:`CMAKE_GENERATOR_INSTANCE`). It is an error to provide this
+ option without the ``CMAKE_GENERATOR`` option.
+
+ ``CMAKE_ARGS <arg>...``
+ The specified arguments are passed to the ``cmake`` command line. They
+ can be any argument the ``cmake`` command understands, not just cache
+ values defined by ``-D...`` arguments (see also
+ :manual:`CMake Options <cmake(1)>`).
+
+ .. versionadded:: 3.3
+ Arguments may use :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+ ``CMAKE_CACHE_ARGS <arg>...``
+ This is an alternate way of specifying cache variables where command line
+ length issues may become a problem. The arguments are expected to be in
+ the form ``-Dvar:STRING=value``, which are then transformed into
+ CMake :command:`set` commands with the ``FORCE`` option used. These
+ ``set()`` commands are written to a pre-load script which is then applied
+ using the :manual:`cmake -C <cmake(1)>` command line option.
+
+ .. versionadded:: 3.3
+ Arguments may use :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+ ``CMAKE_CACHE_DEFAULT_ARGS <arg>...``
+ .. versionadded:: 3.2
+
+ This is the same as the ``CMAKE_CACHE_ARGS`` option except the ``set()``
+ commands do not include the ``FORCE`` keyword. This means the values act
+ as initial defaults only and will not override any variables already set
+ from a previous run. Use this option with care, as it can lead to
+ different behavior depending on whether the build starts from a fresh
+ build directory or re-uses previous build contents.
+
+ .. versionadded:: 3.15
+ If the CMake generator is the ``Green Hills MULTI`` and not overridden then
+ the original project's settings for the GHS toolset and target system
+ customization cache variables are propagated into the external project.
+
+ ``SOURCE_SUBDIR <dir>``
+ .. versionadded:: 3.7
+
+ When no ``CONFIGURE_COMMAND`` option is specified, the configure step
+ assumes the external project has a ``CMakeLists.txt`` file at the top of
+ its source tree (i.e. in ``SOURCE_DIR``). The ``SOURCE_SUBDIR`` option
+ can be used to point to an alternative directory within the source tree
+ to use as the top of the CMake source tree instead. This must be a
+ relative path and it will be interpreted as being relative to
+ ``SOURCE_DIR``.
+
+ .. versionadded:: 3.14
+ When ``BUILD_IN_SOURCE`` option is enabled, the ``BUILD_COMMAND``
+ is used to point to an alternative directory within the source tree.
+
+ ``CONFIGURE_HANDLED_BY_BUILD <bool>``
+ .. versionadded:: 3.20
+
+ Enabling this option relaxes the dependencies of the configure step on
+ other external projects to order-only. This means the configure step will
+ be executed after its external project dependencies are built but it will
+ not be marked dirty when one of its external project dependencies is
+ rebuilt. This option can be enabled when the build step is smart enough
+ to figure out if the configure step needs to be rerun. CMake and Meson are
+ examples of build systems whose build step is smart enough to know if the
+ configure step needs to be rerun.
+
+ **Build Step Options:**
+ If the configure step assumed the external project uses CMake as its build
+ system, the build step will also. Otherwise, the build step will assume a
+ Makefile-based build and simply run ``make`` with no arguments as the
+ default build step. This can be overridden with custom build commands if
+ required.
+
+ ``BUILD_COMMAND <cmd>...``
+ Overrides the default build command
+ (:manual:`generator expressions <cmake-generator-expressions(7)>` are
+ supported). If this option is not given, the default build command will
+ be chosen to integrate with the main build in the most appropriate way
+ (e.g. using recursive ``make`` for Makefile generators or
+ ``cmake --build`` if the project uses a CMake build). This option can be
+ specified with an empty string as the command to make the build step do
+ nothing.
+
+ ``BUILD_IN_SOURCE <bool>``
+ When this option is enabled, the build will be done directly within the
+ external project's source tree. This should generally be avoided, the use
+ of a separate build directory is usually preferred, but it can be useful
+ when the external project assumes an in-source build. The ``BINARY_DIR``
+ option should not be specified if building in-source.
+
+ ``BUILD_ALWAYS <bool>``
+ Enabling this option forces the build step to always be run. This can be
+ the easiest way to robustly ensure that the external project's own build
+ dependencies are evaluated rather than relying on the default
+ success timestamp-based method. This option is not normally needed unless
+ developers are expected to modify something the external project's build
+ depends on in a way that is not detectable via the step target
+ dependencies (e.g. ``SOURCE_DIR`` is used without a download method and
+ developers might modify the sources in ``SOURCE_DIR``).
+
+ ``BUILD_BYPRODUCTS <file>...``
+ .. versionadded:: 3.2
+
+ Specifies files that will be generated by the build command but which
+ might or might not have their modification time updated by subsequent
+ builds. These ultimately get passed through as ``BYPRODUCTS`` to the
+ build step's own underlying call to :command:`add_custom_command`.
+
+ **Install Step Options:**
+ If the configure step assumed the external project uses CMake as its build
+ system, the install step will also. Otherwise, the install step will assume
+ a Makefile-based build and simply run ``make install`` as the default build
+ step. This can be overridden with custom install commands if required.
+
+ ``INSTALL_COMMAND <cmd>...``
+ The external project's own install step is invoked as part of the main
+ project's *build*. It is done after the external project's build step
+ and may be before or after the external project's test step (see the
+ ``TEST_BEFORE_INSTALL`` option below). The external project's install
+ rules are not part of the main project's install rules, so if anything
+ from the external project should be installed as part of the main build,
+ these need to be specified in the main build as additional
+ :command:`install` commands. The default install step builds the
+ ``install`` target of the external project, but this can be overridden
+ with a custom command using this option
+ (:manual:`generator expressions <cmake-generator-expressions(7)>` are
+ supported). Passing an empty string as the ``<cmd>`` makes the install
+ step do nothing.
+
+ **Test Step Options:**
+ The test step is only defined if at least one of the following ``TEST_...``
+ options are provided.
+
+ ``TEST_COMMAND <cmd>...``
+ Overrides the default test command
+ (:manual:`generator expressions <cmake-generator-expressions(7)>` are
+ supported). If this option is not given, the default behavior of the test
+ step is to build the external project's own ``test`` target. This option
+ can be specified with ``<cmd>`` as an empty string, which allows the test
+ step to still be defined, but it will do nothing. Do not specify any of
+ the other ``TEST_...`` options if providing an empty string as the test
+ command, but prefer to omit all ``TEST_...`` options altogether if the
+ test step target is not needed.
+
+ ``TEST_BEFORE_INSTALL <bool>``
+ When this option is enabled, the test step will be executed before the
+ install step. The default behavior is for the test step to run after the
+ install step.
+
+ ``TEST_AFTER_INSTALL <bool>``
+ This option is mainly useful as a way to indicate that the test step is
+ desired but all default behavior is sufficient. Specifying this option
+ with a boolean true value ensures the test step is defined and that it
+ comes after the install step. If both ``TEST_BEFORE_INSTALL`` and
+ ``TEST_AFTER_INSTALL`` are enabled, the latter is silently ignored.
+
+ ``TEST_EXCLUDE_FROM_MAIN <bool>``
+ .. versionadded:: 3.2
+
+ If enabled, the main build's default ALL target will not depend on the
+ test step. This can be a useful way of ensuring the test step is defined
+ but only gets invoked when manually requested.
+ This may cause a step target to be created automatically for either
+ the ``install`` or ``build`` step. See policy :policy:`CMP0114`.
+
+ **Output Logging Options:**
+ Each of the following ``LOG_...`` options can be used to wrap the relevant
+ step in a script to capture its output to files. The log files will be
+ created in ``LOG_DIR`` if supplied or otherwise the ``STAMP_DIR``
+ directory with step-specific file names.
+
+ ``LOG_DOWNLOAD <bool>``
+ When enabled, the output of the download step is logged to files.
+
+ ``LOG_UPDATE <bool>``
+ When enabled, the output of the update step is logged to files.
+
+ ``LOG_PATCH <bool>``
+ .. versionadded:: 3.14
+
+ When enabled, the output of the patch step is logged to files.
+
+ ``LOG_CONFIGURE <bool>``
+ When enabled, the output of the configure step is logged to files.
+
+ ``LOG_BUILD <bool>``
+ When enabled, the output of the build step is logged to files.
+
+ ``LOG_INSTALL <bool>``
+ When enabled, the output of the install step is logged to files.
+
+ ``LOG_TEST <bool>``
+ When enabled, the output of the test step is logged to files.
+
+ ``LOG_MERGED_STDOUTERR <bool>``
+ .. versionadded:: 3.14
+
+ When enabled, stdout and stderr will be merged for any step whose
+ output is being logged to files.
+
+ ``LOG_OUTPUT_ON_FAILURE <bool>``
+ .. versionadded:: 3.14
+
+ This option only has an effect if at least one of the other ``LOG_<step>``
+ options is enabled. If an error occurs for a step which has logging to
+ file enabled, that step's output will be printed to the console if
+ ``LOG_OUTPUT_ON_FAILURE`` is set to true. For cases where a large amount
+ of output is recorded, just the end of that output may be printed to the
+ console.
+
+ **Terminal Access Options:**
+ .. versionadded:: 3.4
+
+ Steps can be given direct access to the terminal in some cases. Giving a
+ step access to the terminal may allow it to receive terminal input if
+ required, such as for authentication details not provided by other options.
+ With the :generator:`Ninja` generator, these options place the steps in the
+ ``console`` :prop_gbl:`job pool <JOB_POOLS>`. Each step can be given access
+ to the terminal individually via the following options:
+
+ ``USES_TERMINAL_DOWNLOAD <bool>``
+ Give the download step access to the terminal.
+
+ ``USES_TERMINAL_UPDATE <bool>``
+ Give the update step access to the terminal.
+
+ ``USES_TERMINAL_CONFIGURE <bool>``
+ Give the configure step access to the terminal.
+
+ ``USES_TERMINAL_BUILD <bool>``
+ Give the build step access to the terminal.
+
+ ``USES_TERMINAL_INSTALL <bool>``
+ Give the install step access to the terminal.
+
+ ``USES_TERMINAL_TEST <bool>``
+ Give the test step access to the terminal.
+
+ **Target Options:**
+ ``DEPENDS <targets>...``
+ Specify other targets on which the external project depends. The other
+ targets will be brought up to date before any of the external project's
+ steps are executed. Because the external project uses additional custom
+ targets internally for each step, the ``DEPENDS`` option is the most
+ convenient way to ensure all of those steps depend on the other targets.
+ Simply doing
+ :command:`add_dependencies(\<name\> \<targets\>) <add_dependencies>` will
+ not make any of the steps dependent on ``<targets>``.
+
+ ``EXCLUDE_FROM_ALL <bool>``
+ When enabled, this option excludes the external project from the default
+ ALL target of the main build.
+
+ ``STEP_TARGETS <step-target>...``
+ Generate custom targets for the specified steps. This is required if the
+ steps need to be triggered manually or if they need to be used as
+ dependencies of other targets. If this option is not specified, the
+ default value is taken from the ``EP_STEP_TARGETS`` directory property.
+ See :command:`ExternalProject_Add_StepTargets` below for further
+ discussion of the effects of this option.
+
+ ``INDEPENDENT_STEP_TARGETS <step-target>...``
+ .. deprecated:: 3.19
+ This is allowed only if policy :policy:`CMP0114` is not set to ``NEW``.
+
+ Generates custom targets for the specified steps and prevent these targets
+ from having the usual dependencies applied to them. If this option is not
+ specified, the default value is taken from the
+ ``EP_INDEPENDENT_STEP_TARGETS`` directory property. This option is mostly
+ useful for allowing individual steps to be driven independently, such as
+ for a CDash setup where each step should be initiated and reported
+ individually rather than as one whole build. See
+ :command:`ExternalProject_Add_StepTargets` below for further discussion
+ of the effects of this option.
+
+ **Miscellaneous Options:**
+ ``LIST_SEPARATOR <sep>``
+ For any of the various ``..._COMMAND`` options, replace ``;`` with
+ ``<sep>`` in the specified command lines. This can be useful where list
+ variables may be given in commands where they should end up as
+ space-separated arguments (``<sep>`` would be a single space character
+ string in this case).
+
+ ``COMMAND <cmd>...``
+ Any of the other ``..._COMMAND`` options can have additional commands
+ appended to them by following them with as many ``COMMAND ...`` options
+ as needed
+ (:manual:`generator expressions <cmake-generator-expressions(7)>` are
+ supported). For example:
+
+ .. code-block:: cmake
+
+ ExternalProject_Add(example
+ ... # Download options, etc.
+ BUILD_COMMAND ${CMAKE_COMMAND} -E echo "Starting $<CONFIG> build"
+ COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --config $<CONFIG>
+ COMMAND ${CMAKE_COMMAND} -E echo "$<CONFIG> build complete"
+ )
+
+ It should also be noted that each build step is created via a call to
+ :command:`ExternalProject_Add_Step`. See that command's documentation for the
+ automatic substitutions that are supported for some options.
+
+Obtaining Project Properties
+""""""""""""""""""""""""""""
+
+.. command:: ExternalProject_Get_Property
+
+ The ``ExternalProject_Get_Property()`` function retrieves external project
+ target properties:
+
+ .. code-block:: cmake
+
+ ExternalProject_Get_Property(<name> <prop1> [<prop2>...])
+
+ The function stores property values in variables of the same name. Property
+ names correspond to the keyword argument names of ``ExternalProject_Add()``.
+ For example, the source directory might be retrieved like so:
+
+ .. code-block:: cmake
+
+ ExternalProject_Get_property(myExtProj SOURCE_DIR)
+ message("Source dir of myExtProj = ${SOURCE_DIR}")
+
+Explicit Step Management
+""""""""""""""""""""""""
+
+The ``ExternalProject_Add()`` function on its own is often sufficient for
+incorporating an external project into the main build. Certain scenarios
+require additional work to implement desired behavior, such as adding in a
+custom step or making steps available as manually triggerable targets. The
+``ExternalProject_Add_Step()``, ``ExternalProject_Add_StepTargets()`` and
+``ExternalProject_Add_StepDependencies`` functions provide the lower level
+control needed to implement such step-level capabilities.
+
+.. command:: ExternalProject_Add_Step
+
+ The ``ExternalProject_Add_Step()`` function specifies an additional custom
+ step for an external project defined by an earlier call to
+ :command:`ExternalProject_Add`:
+
+ .. code-block:: cmake
+
+ ExternalProject_Add_Step(<name> <step> [<option>...])
+
+ ``<name>`` is the same as the name passed to the original call to
+ :command:`ExternalProject_Add`. The specified ``<step>`` must not be one of
+ the pre-defined steps (``mkdir``, ``download``, ``update``,
+ ``patch``, ``configure``, ``build``, ``install`` or ``test``). The supported
+ options are:
+
+ ``COMMAND <cmd>...``
+ The command line to be executed by this custom step
+ (:manual:`generator expressions <cmake-generator-expressions(7)>` are
+ supported). This option can be repeated multiple times to specify multiple
+ commands to be executed in order.
+
+ ``COMMENT "<text>..."``
+ Text to be printed when the custom step executes.
+
+ ``DEPENDEES <step>...``
+ Other steps (custom or pre-defined) on which this step depends.
+
+ ``DEPENDERS <step>...``
+ Other steps (custom or pre-defined) that depend on this new custom step.
+
+ ``DEPENDS <file>...``
+ Files on which this custom step depends.
+
+ ``INDEPENDENT <bool>``
+ .. versionadded:: 3.19
+
+ Specifies whether this step is independent of the external dependencies
+ specified by the :command:`ExternalProject_Add`'s ``DEPENDS`` option.
+ The default is ``FALSE``. Steps marked as independent may depend only
+ on other steps marked independent. See policy :policy:`CMP0114`.
+
+ Note that this use of the term "independent" refers only to independence
+ from external targets specified by the ``DEPENDS`` option and is
+ orthogonal to a step's dependencies on other steps.
+
+ If a step target is created for an independent step by the
+ :command:`ExternalProject_Add` ``STEP_TARGETS`` option or by the
+ :command:`ExternalProject_Add_StepTargets` function, it will not depend
+ on the external targets, but may depend on targets for other steps.
+
+ ``BYPRODUCTS <file>...``
+ .. versionadded:: 3.2
+
+ Files that will be generated by this custom step but which might or might
+ not have their modification time updated by subsequent builds. This list of
+ files will ultimately be passed through as the ``BYPRODUCTS`` option to the
+ :command:`add_custom_command` used to implement the custom step internally.
+
+ ``ALWAYS <bool>``
+ When enabled, this option specifies that the custom step should always be
+ run (i.e. that it is always considered out of date).
+
+ ``EXCLUDE_FROM_MAIN <bool>``
+ When enabled, this option specifies that the external project's main target
+ does not depend on the custom step.
+ This may cause step targets to be created automatically for the steps on
+ which this step depends. See policy :policy:`CMP0114`.
+
+ ``WORKING_DIRECTORY <dir>``
+ Specifies the working directory to set before running the custom step's
+ command. If this option is not specified, the directory will be the value
+ of the :variable:`CMAKE_CURRENT_BINARY_DIR` at the point where
+ ``ExternalProject_Add_Step()`` was called.
+
+ ``LOG <bool>``
+ If set, this causes the output from the custom step to be captured to files
+ in the external project's ``LOG_DIR`` if supplied or ``STAMP_DIR``.
+
+ ``USES_TERMINAL <bool>``
+ If enabled, this gives the custom step direct access to the terminal if
+ possible.
+
+ The command line, comment, working directory and byproducts of every
+ standard and custom step are processed to replace the tokens
+ ``<SOURCE_DIR>``, ``<SOURCE_SUBDIR>``, ``<BINARY_DIR>``, ``<INSTALL_DIR>``
+ ``<TMP_DIR>``, ``<DOWNLOAD_DIR>`` and ``<DOWNLOADED_FILE>`` with their
+ corresponding property values defined in the original call to
+ :command:`ExternalProject_Add`.
+
+ .. versionadded:: 3.3
+ Token replacement is extended to byproducts.
+
+ .. versionadded:: 3.11
+ The ``<DOWNLOAD_DIR>`` substitution token.
+
+.. command:: ExternalProject_Add_StepTargets
+
+ The ``ExternalProject_Add_StepTargets()`` function generates targets for the
+ steps listed. The name of each created target will be of the form
+ ``<name>-<step>``:
+
+ .. code-block:: cmake
+
+ ExternalProject_Add_StepTargets(<name> <step1> [<step2>...])
+
+ Creating a target for a step allows it to be used as a dependency of another
+ target or to be triggered manually. Having targets for specific steps also
+ allows them to be driven independently of each other by specifying targets on
+ build command lines. For example, you may be submitting to a sub-project
+ based dashboard where you want to drive the configure portion of the build,
+ then submit to the dashboard, followed by the build portion, followed
+ by tests. If you invoke a custom target that depends on a step halfway
+ through the step dependency chain, then all the previous steps will also run
+ to ensure everything is up to date.
+
+ Internally, :command:`ExternalProject_Add` calls
+ :command:`ExternalProject_Add_Step` to create each step. If any
+ ``STEP_TARGETS`` were specified, then ``ExternalProject_Add_StepTargets()``
+ will also be called after :command:`ExternalProject_Add_Step`. Even if a
+ step is not mentioned in the ``STEP_TARGETS`` option,
+ ``ExternalProject_Add_StepTargets()`` can still be called later to manually
+ define a target for the step.
+
+ The ``STEP_TARGETS`` option for :command:`ExternalProject_Add` is generally
+ the easiest way to ensure targets are created for specific steps of interest.
+ For custom steps, ``ExternalProject_Add_StepTargets()`` must be called
+ explicitly if a target should also be created for that custom step.
+ An alternative to these two options is to populate the ``EP_STEP_TARGETS``
+ directory property. It acts as a default for the step target options and
+ can save having to repeatedly specify the same set of step targets when
+ multiple external projects are being defined.
+
+ .. versionadded:: 3.19
+ If :policy:`CMP0114` is set to ``NEW``, step targets are fully responsible
+ for holding the custom commands implementing their steps. The primary target
+ created by ``ExternalProject_Add`` depends on the step targets, and the
+ step targets depend on each other. The target-level dependencies match
+ the file-level dependencies used by the custom commands for each step.
+ The targets for steps created with :command:`ExternalProject_Add_Step`'s
+ ``INDEPENDENT`` option do not depend on the external targets specified
+ by :command:`ExternalProject_Add`'s ``DEPENDS`` option. The predefined
+ steps ``mkdir``, ``download``, ``update``, and ``patch`` are independent.
+
+ If :policy:`CMP0114` is not ``NEW``, the following deprecated behavior
+ is available:
+
+ * A deprecated ``NO_DEPENDS`` option may be specified immediately after the
+ ``<name>`` and before the first step.
+ If the ``NO_DEPENDS`` option is specified, the step target will not depend on
+ the dependencies of the external project (i.e. on any dependencies of the
+ ``<name>`` custom target created by :command:`ExternalProject_Add`). This is
+ usually safe for the ``download``, ``update`` and ``patch`` steps, since they
+ do not typically require that the dependencies are updated and built. Using
+ ``NO_DEPENDS`` for any of the other pre-defined steps, however, may break
+ parallel builds. Only use ``NO_DEPENDS`` where it is certain that the named
+ steps genuinely do not have dependencies. For custom steps, consider whether
+ or not the custom commands require the dependencies to be configured, built
+ and installed.
+
+ * The ``INDEPENDENT_STEP_TARGETS`` option for :command:`ExternalProject_Add`,
+ or the ``EP_INDEPENDENT_STEP_TARGETS`` directory property, tells the
+ function to call ``ExternalProject_Add_StepTargets()`` internally
+ using the ``NO_DEPENDS`` option for the specified steps.
+
+.. command:: ExternalProject_Add_StepDependencies
+
+ .. versionadded:: 3.2
+
+ The ``ExternalProject_Add_StepDependencies()`` function can be used to add
+ dependencies to a step. The dependencies added must be targets CMake already
+ knows about (these can be ordinary executable or library targets, custom
+ targets or even step targets of another external project):
+
+ .. code-block:: cmake
+
+ ExternalProject_Add_StepDependencies(<name> <step> <target1> [<target2>...])
+
+ This function takes care to set both target and file level dependencies and
+ will ensure that parallel builds will not break. It should be used instead of
+ :command:`add_dependencies` whenever adding a dependency for some of the step
+ targets generated by the ``ExternalProject`` module.
+
+Examples
+^^^^^^^^
+
+The following example shows how to download and build a hypothetical project
+called *FooBar* from github:
+
+.. code-block:: cmake
+
+ include(ExternalProject)
+ ExternalProject_Add(foobar
+ GIT_REPOSITORY git@github.com:FooCo/FooBar.git
+ GIT_TAG origin/release/1.2.3
+ )
+
+For the sake of the example, also define a second hypothetical external project
+called *SecretSauce*, which is downloaded from a web server. Two URLs are given
+to take advantage of a faster internal network if available, with a fallback to
+a slower external server. The project is a typical ``Makefile`` project with no
+configure step, so some of the default commands are overridden. The build is
+only required to build the *sauce* target:
+
+.. code-block:: cmake
+
+ find_program(MAKE_EXE NAMES gmake nmake make)
+ ExternalProject_Add(secretsauce
+ URL http://intranet.somecompany.com/artifacts/sauce-2.7.tgz
+ https://www.somecompany.com/downloads/sauce-2.7.zip
+ URL_HASH MD5=d41d8cd98f00b204e9800998ecf8427e
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ${MAKE_EXE} sauce
+ )
+
+Suppose the build step of ``secretsauce`` requires that ``foobar`` must already
+be built. This could be enforced like so:
+
+.. code-block:: cmake
+
+ ExternalProject_Add_StepDependencies(secretsauce build foobar)
+
+Another alternative would be to create a custom target for ``foobar``'s build
+step and make ``secretsauce`` depend on that rather than the whole ``foobar``
+project. This would mean ``foobar`` only needs to be built, it doesn't need to
+run its install or test steps before ``secretsauce`` can be built. The
+dependency can also be defined along with the ``secretsauce`` project:
+
+.. code-block:: cmake
+
+ ExternalProject_Add_StepTargets(foobar build)
+ ExternalProject_Add(secretsauce
+ URL http://intranet.somecompany.com/artifacts/sauce-2.7.tgz
+ https://www.somecompany.com/downloads/sauce-2.7.zip
+ URL_HASH MD5=d41d8cd98f00b204e9800998ecf8427e
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ${MAKE_EXE} sauce
+ DEPENDS foobar-build
+ )
+
+Instead of calling :command:`ExternalProject_Add_StepTargets`, the target could
+be defined along with the ``foobar`` project itself:
+
+.. code-block:: cmake
+
+ ExternalProject_Add(foobar
+ GIT_REPOSITORY git@github.com:FooCo/FooBar.git
+ GIT_TAG origin/release/1.2.3
+ STEP_TARGETS build
+ )
+
+If many external projects should have the same set of step targets, setting a
+directory property may be more convenient. The ``build`` step target could be
+created automatically by setting the ``EP_STEP_TARGETS`` directory property
+before creating the external projects with :command:`ExternalProject_Add`:
+
+.. code-block:: cmake
+
+ set_property(DIRECTORY PROPERTY EP_STEP_TARGETS build)
+
+Lastly, suppose that ``secretsauce`` provides a script called ``makedoc`` which
+can be used to generate its own documentation. Further suppose that the script
+expects the output directory to be provided as the only parameter and that it
+should be run from the ``secretsauce`` source directory. A custom step and a
+custom target to trigger the script can be defined like so:
+
+.. code-block:: cmake
+
+ ExternalProject_Add_Step(secretsauce docs
+ COMMAND <SOURCE_DIR>/makedoc <BINARY_DIR>
+ WORKING_DIRECTORY <SOURCE_DIR>
+ COMMENT "Building secretsauce docs"
+ ALWAYS TRUE
+ EXCLUDE_FROM_MAIN TRUE
+ )
+ ExternalProject_Add_StepTargets(secretsauce docs)
+
+The custom step could then be triggered from the main build like so::
+
+ cmake --build . --target secretsauce-docs
+
+#]=======================================================================]
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
+cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST
+
+macro(_ep_get_hash_algos out_var)
+ set(${out_var}
+ MD5
+ SHA1
+ SHA224
+ SHA256
+ SHA384
+ SHA512
+ SHA3_224
+ SHA3_256
+ SHA3_384
+ SHA3_512
+ )
+endmacro()
+
+macro(_ep_get_hash_regex out_var)
+ _ep_get_hash_algos(${out_var})
+ list(JOIN ${out_var} "|" ${out_var})
+ set(${out_var} "^(${${out_var}})=([0-9A-Fa-f]+)$")
+endmacro()
+
+function(_ep_parse_arguments f keywords name ns args)
+ # Transfer the arguments to this function into target properties for the
+ # new custom target we just added so that we can set up all the build steps
+ # correctly based on target properties.
+ #
+ # Because some keywords can be repeated, we can't use cmake_parse_arguments().
+ # Instead, we loop through ARGN and consider the namespace starting with an
+ # upper-case letter followed by at least two more upper-case letters,
+ # numbers or underscores to be keywords.
+
+ set(key)
+
+ foreach(arg IN LISTS args)
+ set(is_value 1)
+
+ if(arg MATCHES "^[A-Z][A-Z0-9_][A-Z0-9_]+$" AND
+ NOT (("x${arg}x" STREQUAL "x${key}x") AND ("x${key}x" STREQUAL "xCOMMANDx")) AND
+ NOT arg MATCHES "^(TRUE|FALSE)$")
+ if(arg IN_LIST keywords)
+ set(is_value 0)
+ endif()
+ endif()
+
+ if(is_value)
+ if(key)
+ # Value
+ if(NOT arg STREQUAL "")
+ set_property(TARGET ${name} APPEND PROPERTY ${ns}${key} "${arg}")
+ else()
+ get_property(have_key TARGET ${name} PROPERTY ${ns}${key} SET)
+ if(have_key)
+ get_property(value TARGET ${name} PROPERTY ${ns}${key})
+ set_property(TARGET ${name} PROPERTY ${ns}${key} "${value};${arg}")
+ else()
+ set_property(TARGET ${name} PROPERTY ${ns}${key} "${arg}")
+ endif()
+ endif()
+ else()
+ # Missing Keyword
+ message(AUTHOR_WARNING "value '${arg}' with no previous keyword in ${f}")
+ endif()
+ else()
+ set(key "${arg}")
+ endif()
+ endforeach()
+endfunction()
+
+
+define_property(DIRECTORY PROPERTY "EP_BASE" INHERITED
+ BRIEF_DOCS "Base directory for External Project storage."
+ FULL_DOCS
+ "See documentation of the ExternalProject_Add() function in the "
+ "ExternalProject module."
+ )
+
+define_property(DIRECTORY PROPERTY "EP_PREFIX" INHERITED
+ BRIEF_DOCS "Top prefix for External Project storage."
+ FULL_DOCS
+ "See documentation of the ExternalProject_Add() function in the "
+ "ExternalProject module."
+ )
+
+define_property(DIRECTORY PROPERTY "EP_STEP_TARGETS" INHERITED
+ BRIEF_DOCS
+ "List of ExternalProject steps that automatically get corresponding targets"
+ FULL_DOCS
+ "These targets will be dependent on the main target dependencies. "
+ "See documentation of the ExternalProject_Add_StepTargets() function in the "
+ "ExternalProject module."
+ )
+
+define_property(DIRECTORY PROPERTY "EP_INDEPENDENT_STEP_TARGETS" INHERITED
+ BRIEF_DOCS
+ "List of ExternalProject steps that automatically get corresponding targets"
+ FULL_DOCS
+ "These targets will not be dependent on the main target dependencies. "
+ "See documentation of the ExternalProject_Add_StepTargets() function in the "
+ "ExternalProject module."
+ )
+
+define_property(DIRECTORY PROPERTY "EP_UPDATE_DISCONNECTED" INHERITED
+ BRIEF_DOCS "Never update automatically from the remote repo."
+ FULL_DOCS
+ "See documentation of the ExternalProject_Add() function in the "
+ "ExternalProject module."
+ )
+
+function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag git_remote_name init_submodules git_submodules_recurse git_submodules git_shallow git_progress git_config src_name work_dir gitclone_infofile gitclone_stampfile tls_verify)
+ if(NOT GIT_VERSION_STRING VERSION_LESS 1.8.5)
+ # Use `git checkout <tree-ish> --` to avoid ambiguity with a local path.
+ set(git_checkout_explicit-- "--")
+ else()
+ # Use `git checkout <branch>` even though this risks ambiguity with a
+ # local path. Unfortunately we cannot use `git checkout <tree-ish> --`
+ # because that will not search for remote branch names, a common use case.
+ set(git_checkout_explicit-- "")
+ endif()
+ if("${git_tag}" STREQUAL "")
+ message(FATAL_ERROR "Tag for git checkout should not be empty.")
+ endif()
+
+ if(GIT_VERSION_STRING VERSION_LESS 2.20 OR 2.21 VERSION_LESS_EQUAL GIT_VERSION_STRING)
+ set(git_clone_options "--no-checkout")
+ else()
+ set(git_clone_options)
+ endif()
+ if(git_shallow)
+ if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.10)
+ list(APPEND git_clone_options "--depth 1 --no-single-branch")
+ else()
+ list(APPEND git_clone_options "--depth 1")
+ endif()
+ endif()
+ if(git_progress)
+ list(APPEND git_clone_options --progress)
+ endif()
+ foreach(config IN LISTS git_config)
+ list(APPEND git_clone_options --config \"${config}\")
+ endforeach()
+ if(NOT ${git_remote_name} STREQUAL "origin")
+ list(APPEND git_clone_options --origin \"${git_remote_name}\")
+ endif()
+
+ string (REPLACE ";" " " git_clone_options "${git_clone_options}")
+
+ set(git_options)
+ # disable cert checking if explicitly told not to do it
+ if(NOT "x${tls_verify}" STREQUAL "x" AND NOT tls_verify)
+ set(git_options
+ -c http.sslVerify=false)
+ endif()
+ string (REPLACE ";" " " git_options "${git_options}")
+
+ file(WRITE ${script_filename}
+"
+if(NOT \"${gitclone_infofile}\" IS_NEWER_THAN \"${gitclone_stampfile}\")
+ message(STATUS \"Avoiding repeated git clone, stamp file is up to date: '${gitclone_stampfile}'\")
+ return()
+endif()
+
+execute_process(
+ COMMAND \${CMAKE_COMMAND} -E rm -rf \"${source_dir}\"
+ RESULT_VARIABLE error_code
+ )
+if(error_code)
+ message(FATAL_ERROR \"Failed to remove directory: '${source_dir}'\")
+endif()
+
+# try the clone 3 times in case there is an odd git clone issue
+set(error_code 1)
+set(number_of_tries 0)
+while(error_code AND number_of_tries LESS 3)
+ execute_process(
+ COMMAND \"${git_EXECUTABLE}\" ${git_options} clone ${git_clone_options} \"${git_repository}\" \"${src_name}\"
+ WORKING_DIRECTORY \"${work_dir}\"
+ RESULT_VARIABLE error_code
+ )
+ math(EXPR number_of_tries \"\${number_of_tries} + 1\")
+endwhile()
+if(number_of_tries GREATER 1)
+ message(STATUS \"Had to git clone more than once:
+ \${number_of_tries} times.\")
+endif()
+if(error_code)
+ message(FATAL_ERROR \"Failed to clone repository: '${git_repository}'\")
+endif()
+
+execute_process(
+ COMMAND \"${git_EXECUTABLE}\" ${git_options} checkout ${git_tag} ${git_checkout_explicit--}
+ WORKING_DIRECTORY \"${work_dir}/${src_name}\"
+ RESULT_VARIABLE error_code
+ )
+if(error_code)
+ message(FATAL_ERROR \"Failed to checkout tag: '${git_tag}'\")
+endif()
+
+set(init_submodules ${init_submodules})
+if(init_submodules)
+ execute_process(
+ COMMAND \"${git_EXECUTABLE}\" ${git_options} submodule update ${git_submodules_recurse} --init ${git_submodules}
+ WORKING_DIRECTORY \"${work_dir}/${src_name}\"
+ RESULT_VARIABLE error_code
+ )
+endif()
+if(error_code)
+ message(FATAL_ERROR \"Failed to update submodules in: '${work_dir}/${src_name}'\")
+endif()
+
+# Complete success, update the script-last-run stamp file:
+#
+execute_process(
+ COMMAND \${CMAKE_COMMAND} -E copy
+ \"${gitclone_infofile}\"
+ \"${gitclone_stampfile}\"
+ RESULT_VARIABLE error_code
+ )
+if(error_code)
+ message(FATAL_ERROR \"Failed to copy script-last-run stamp file: '${gitclone_stampfile}'\")
+endif()
+
+"
+)
+
+endfunction()
+
+function(_ep_write_hgclone_script script_filename source_dir hg_EXECUTABLE hg_repository hg_tag src_name work_dir hgclone_infofile hgclone_stampfile)
+ if("${hg_tag}" STREQUAL "")
+ message(FATAL_ERROR "Tag for hg checkout should not be empty.")
+ endif()
+ file(WRITE ${script_filename}
+"
+if(NOT \"${hgclone_infofile}\" IS_NEWER_THAN \"${hgclone_stampfile}\")
+ message(STATUS \"Avoiding repeated hg clone, stamp file is up to date: '${hgclone_stampfile}'\")
+ return()
+endif()
+
+execute_process(
+ COMMAND \${CMAKE_COMMAND} -E rm -rf \"${source_dir}\"
+ RESULT_VARIABLE error_code
+ )
+if(error_code)
+ message(FATAL_ERROR \"Failed to remove directory: '${source_dir}'\")
+endif()
+
+execute_process(
+ COMMAND \"${hg_EXECUTABLE}\" clone -U \"${hg_repository}\" \"${src_name}\"
+ WORKING_DIRECTORY \"${work_dir}\"
+ RESULT_VARIABLE error_code
+ )
+if(error_code)
+ message(FATAL_ERROR \"Failed to clone repository: '${hg_repository}'\")
+endif()
+
+execute_process(
+ COMMAND \"${hg_EXECUTABLE}\" update ${hg_tag}
+ WORKING_DIRECTORY \"${work_dir}/${src_name}\"
+ RESULT_VARIABLE error_code
+ )
+if(error_code)
+ message(FATAL_ERROR \"Failed to checkout tag: '${hg_tag}'\")
+endif()
+
+# Complete success, update the script-last-run stamp file:
+#
+execute_process(
+ COMMAND \${CMAKE_COMMAND} -E copy
+ \"${hgclone_infofile}\"
+ \"${hgclone_stampfile}\"
+ RESULT_VARIABLE error_code
+ )
+if(error_code)
+ message(FATAL_ERROR \"Failed to copy script-last-run stamp file: '${hgclone_stampfile}'\")
+endif()
+
+"
+)
+
+endfunction()
+
+
+function(_ep_write_gitupdate_script script_filename git_EXECUTABLE git_tag git_remote_name init_submodules git_submodules_recurse git_submodules git_repository work_dir git_update_strategy)
+ if("${git_tag}" STREQUAL "")
+ message(FATAL_ERROR "Tag for git checkout should not be empty.")
+ endif()
+ set(git_stash_save_options --quiet)
+ if(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.7)
+ # This avoids stashing files covered by .gitignore
+ list(APPEND git_stash_save_options --include-untracked)
+ elseif(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.6)
+ # Untracked files, but also ignored files, so potentially slower
+ list(APPEND git_stash_save_options --all)
+ endif()
+
+ configure_file(
+ "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject-gitupdate.cmake.in"
+ "${script_filename}"
+ @ONLY
+ )
+endfunction()
+
+function(_ep_write_downloadfile_script script_filename REMOTE LOCAL timeout inactivity_timeout no_progress hash tls_verify tls_cainfo userpwd http_headers netrc netrc_file)
+ if(timeout)
+ set(TIMEOUT_ARGS TIMEOUT ${timeout})
+ set(TIMEOUT_MSG "${timeout} seconds")
+ else()
+ set(TIMEOUT_ARGS "# no TIMEOUT")
+ set(TIMEOUT_MSG "none")
+ endif()
+ if(inactivity_timeout)
+ set(INACTIVITY_TIMEOUT_ARGS INACTIVITY_TIMEOUT ${inactivity_timeout})
+ set(INACTIVITY_TIMEOUT_MSG "${inactivity_timeout} seconds")
+ else()
+ set(INACTIVITY_TIMEOUT_ARGS "# no INACTIVITY_TIMEOUT")
+ set(INACTIVITY_TIMEOUT_MSG "none")
+ endif()
+
+
+ if(no_progress)
+ set(SHOW_PROGRESS "")
+ else()
+ set(SHOW_PROGRESS "SHOW_PROGRESS")
+ endif()
+
+ _ep_get_hash_regex(_ep_hash_regex)
+ if("${hash}" MATCHES "${_ep_hash_regex}")
+ set(ALGO "${CMAKE_MATCH_1}")
+ string(TOLOWER "${CMAKE_MATCH_2}" EXPECT_VALUE)
+ else()
+ set(ALGO "")
+ set(EXPECT_VALUE "")
+ endif()
+
+ set(TLS_VERIFY_CODE "")
+ set(TLS_CAINFO_CODE "")
+ set(NETRC_CODE "")
+ set(NETRC_FILE_CODE "")
+
+ # check for curl globals in the project
+ if(DEFINED CMAKE_TLS_VERIFY)
+ set(TLS_VERIFY_CODE "set(CMAKE_TLS_VERIFY ${CMAKE_TLS_VERIFY})")
+ endif()
+ if(DEFINED CMAKE_TLS_CAINFO)
+ set(TLS_CAINFO_CODE "set(CMAKE_TLS_CAINFO \"${CMAKE_TLS_CAINFO}\")")
+ endif()
+ if(DEFINED CMAKE_NETRC)
+ set(NETRC_CODE "set(CMAKE_NETRC \"${CMAKE_NETRC}\")")
+ endif()
+ if(DEFINED CMAKE_NETRC_FILE)
+ set(NETRC_FILE_CODE "set(CMAKE_NETRC_FILE \"${CMAKE_NETRC_FILE}\")")
+ endif()
+
+ # now check for curl locals so that the local values
+ # will override the globals
+
+ # check for tls_verify argument
+ string(LENGTH "${tls_verify}" tls_verify_len)
+ if(tls_verify_len GREATER 0)
+ set(TLS_VERIFY_CODE "set(CMAKE_TLS_VERIFY ${tls_verify})")
+ endif()
+ # check for tls_cainfo argument
+ string(LENGTH "${tls_cainfo}" tls_cainfo_len)
+ if(tls_cainfo_len GREATER 0)
+ set(TLS_CAINFO_CODE "set(CMAKE_TLS_CAINFO \"${tls_cainfo}\")")
+ endif()
+ # check for netrc argument
+ string(LENGTH "${netrc}" netrc_len)
+ if(netrc_len GREATER 0)
+ set(NETRC_CODE "set(CMAKE_NETRC \"${netrc}\")")
+ endif()
+ # check for netrc_file argument
+ string(LENGTH "${netrc_file}" netrc_file_len)
+ if(netrc_file_len GREATER 0)
+ set(NETRC_FILE_CODE "set(CMAKE_NETRC_FILE \"${netrc_file}\")")
+ endif()
+
+ if(userpwd STREQUAL ":")
+ set(USERPWD_ARGS)
+ else()
+ set(USERPWD_ARGS USERPWD "${userpwd}")
+ endif()
+
+ set(HTTP_HEADERS_ARGS "")
+ if(NOT http_headers STREQUAL "")
+ foreach(header ${http_headers})
+ set(
+ HTTP_HEADERS_ARGS
+ "HTTPHEADER \"${header}\"\n ${HTTP_HEADERS_ARGS}"
+ )
+ endforeach()
+ endif()
+
+ # Used variables:
+ # * TLS_VERIFY_CODE
+ # * TLS_CAINFO_CODE
+ # * ALGO
+ # * EXPECT_VALUE
+ # * REMOTE
+ # * LOCAL
+ # * SHOW_PROGRESS
+ # * TIMEOUT_ARGS
+ # * TIMEOUT_MSG
+ # * USERPWD_ARGS
+ # * HTTP_HEADERS_ARGS
+ configure_file(
+ "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject-download.cmake.in"
+ "${script_filename}"
+ @ONLY
+ )
+endfunction()
+
+function(_ep_write_verifyfile_script script_filename LOCAL hash)
+ _ep_get_hash_regex(_ep_hash_regex)
+ if("${hash}" MATCHES "${_ep_hash_regex}")
+ set(ALGO "${CMAKE_MATCH_1}")
+ string(TOLOWER "${CMAKE_MATCH_2}" EXPECT_VALUE)
+ else()
+ set(ALGO "")
+ set(EXPECT_VALUE "")
+ endif()
+
+ # Used variables:
+ # * ALGO
+ # * EXPECT_VALUE
+ # * LOCAL
+ configure_file(
+ "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject-verify.cmake.in"
+ "${script_filename}"
+ @ONLY
+ )
+endfunction()
+
+
+function(_ep_write_extractfile_script script_filename name filename directory)
+ set(args "")
+
+ if(filename MATCHES "(\\.|=)(7z|tar\\.bz2|tar\\.gz|tar\\.xz|tbz2|tgz|txz|zip)$")
+ set(args xfz)
+ endif()
+
+ if(filename MATCHES "(\\.|=)tar$")
+ set(args xf)
+ endif()
+
+ if(args STREQUAL "")
+ message(SEND_ERROR "error: do not know how to extract '${filename}' -- known types are .7z, .tar, .tar.bz2, .tar.gz, .tar.xz, .tbz2, .tgz, .txz and .zip")
+ return()
+ endif()
+
+ file(WRITE ${script_filename}
+"# Make file names absolute:
+#
+get_filename_component(filename \"${filename}\" ABSOLUTE)
+get_filename_component(directory \"${directory}\" ABSOLUTE)
+
+message(STATUS \"extracting...
+ src='\${filename}'
+ dst='\${directory}'\")
+
+if(NOT EXISTS \"\${filename}\")
+ message(FATAL_ERROR \"error: file to extract does not exist: '\${filename}'\")
+endif()
+
+# Prepare a space for extracting:
+#
+set(i 1234)
+while(EXISTS \"\${directory}/../ex-${name}\${i}\")
+ math(EXPR i \"\${i} + 1\")
+endwhile()
+set(ut_dir \"\${directory}/../ex-${name}\${i}\")
+file(MAKE_DIRECTORY \"\${ut_dir}\")
+
+# Extract it:
+#
+message(STATUS \"extracting... [tar ${args}]\")
+execute_process(COMMAND \${CMAKE_COMMAND} -E tar ${args} \${filename}
+ WORKING_DIRECTORY \${ut_dir}
+ RESULT_VARIABLE rv)
+
+if(NOT rv EQUAL 0)
+ message(STATUS \"extracting... [error clean up]\")
+ file(REMOVE_RECURSE \"\${ut_dir}\")
+ message(FATAL_ERROR \"error: extract of '\${filename}' failed\")
+endif()
+
+# Analyze what came out of the tar file:
+#
+message(STATUS \"extracting... [analysis]\")
+file(GLOB contents \"\${ut_dir}/*\")
+list(REMOVE_ITEM contents \"\${ut_dir}/.DS_Store\")
+list(LENGTH contents n)
+if(NOT n EQUAL 1 OR NOT IS_DIRECTORY \"\${contents}\")
+ set(contents \"\${ut_dir}\")
+endif()
+
+# Move \"the one\" directory to the final directory:
+#
+message(STATUS \"extracting... [rename]\")
+file(REMOVE_RECURSE \${directory})
+get_filename_component(contents \${contents} ABSOLUTE)
+file(RENAME \${contents} \${directory})
+
+# Clean up:
+#
+message(STATUS \"extracting... [clean up]\")
+file(REMOVE_RECURSE \"\${ut_dir}\")
+
+message(STATUS \"extracting... done\")
+"
+)
+
+endfunction()
+
+
+function(_ep_set_directories name)
+ get_property(prefix TARGET ${name} PROPERTY _EP_PREFIX)
+ if(NOT prefix)
+ get_property(prefix DIRECTORY PROPERTY EP_PREFIX)
+ if(NOT prefix)
+ get_property(base DIRECTORY PROPERTY EP_BASE)
+ if(NOT base)
+ set(prefix "${name}-prefix")
+ endif()
+ endif()
+ endif()
+ if(prefix)
+ set(tmp_default "${prefix}/tmp")
+ set(download_default "${prefix}/src")
+ set(source_default "${prefix}/src/${name}")
+ set(binary_default "${prefix}/src/${name}-build")
+ set(stamp_default "${prefix}/src/${name}-stamp")
+ set(install_default "${prefix}")
+ else()
+ set(tmp_default "${base}/tmp/${name}")
+ set(download_default "${base}/Download/${name}")
+ set(source_default "${base}/Source/${name}")
+ set(binary_default "${base}/Build/${name}")
+ set(stamp_default "${base}/Stamp/${name}")
+ set(install_default "${base}/Install/${name}")
+ endif()
+ get_property(build_in_source TARGET ${name} PROPERTY _EP_BUILD_IN_SOURCE)
+ if(build_in_source)
+ get_property(have_binary_dir TARGET ${name} PROPERTY _EP_BINARY_DIR SET)
+ if(have_binary_dir)
+ message(FATAL_ERROR
+ "External project ${name} has both BINARY_DIR and BUILD_IN_SOURCE!")
+ endif()
+ endif()
+ set(top "${CMAKE_CURRENT_BINARY_DIR}")
+
+ # Apply defaults and convert to absolute paths.
+ set(places stamp download source binary install tmp)
+ foreach(var ${places})
+ string(TOUPPER "${var}" VAR)
+ get_property(${var}_dir TARGET ${name} PROPERTY _EP_${VAR}_DIR)
+ if(NOT ${var}_dir)
+ set(${var}_dir "${${var}_default}")
+ endif()
+ if(NOT IS_ABSOLUTE "${${var}_dir}")
+ get_filename_component(${var}_dir "${top}/${${var}_dir}" ABSOLUTE)
+ endif()
+ set_property(TARGET ${name} PROPERTY _EP_${VAR}_DIR "${${var}_dir}")
+ endforeach()
+
+ # Special case for default log directory based on stamp directory.
+ get_property(log_dir TARGET ${name} PROPERTY _EP_LOG_DIR)
+ if(NOT log_dir)
+ get_property(log_dir TARGET ${name} PROPERTY _EP_STAMP_DIR)
+ endif()
+ if(NOT IS_ABSOLUTE "${log_dir}")
+ get_filename_component(log_dir "${top}/${log_dir}" ABSOLUTE)
+ endif()
+ set_property(TARGET ${name} PROPERTY _EP_LOG_DIR "${log_dir}")
+
+ get_property(source_subdir TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR)
+ if(NOT source_subdir)
+ set_property(TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR "")
+ elseif(IS_ABSOLUTE "${source_subdir}")
+ message(FATAL_ERROR
+ "External project ${name} has non-relative SOURCE_SUBDIR!")
+ else()
+ # Prefix with a slash so that when appended to the source directory, it
+ # behaves as expected.
+ set_property(TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR "/${source_subdir}")
+ endif()
+ if(build_in_source)
+ get_property(source_dir TARGET ${name} PROPERTY _EP_SOURCE_DIR)
+ if(source_subdir)
+ set_property(TARGET ${name} PROPERTY _EP_BINARY_DIR "${source_dir}/${source_subdir}")
+ else()
+ set_property(TARGET ${name} PROPERTY _EP_BINARY_DIR "${source_dir}")
+ endif()
+ endif()
+
+ # Make the directories at CMake configure time *and* add a custom command
+ # to make them at build time. They need to exist at makefile generation
+ # time for Borland make and wmake so that CMake may generate makefiles
+ # with "cd C:\short\paths\with\no\spaces" commands in them.
+ #
+ # Additionally, the add_custom_command is still used in case somebody
+ # removes one of the necessary directories and tries to rebuild without
+ # re-running cmake.
+ foreach(var ${places})
+ string(TOUPPER "${var}" VAR)
+ get_property(dir TARGET ${name} PROPERTY _EP_${VAR}_DIR)
+ file(MAKE_DIRECTORY "${dir}")
+ if(NOT EXISTS "${dir}")
+ message(FATAL_ERROR "dir '${dir}' does not exist after file(MAKE_DIRECTORY)")
+ endif()
+ endforeach()
+endfunction()
+
+
+# IMPORTANT: this MUST be a macro and not a function because of the
+# in-place replacements that occur in each ${var}
+#
+macro(_ep_replace_location_tags target_name)
+ set(vars ${ARGN})
+ foreach(var ${vars})
+ if(${var})
+ foreach(dir SOURCE_DIR SOURCE_SUBDIR BINARY_DIR INSTALL_DIR TMP_DIR DOWNLOAD_DIR DOWNLOADED_FILE LOG_DIR)
+ get_property(val TARGET ${target_name} PROPERTY _EP_${dir})
+ string(REPLACE "<${dir}>" "${val}" ${var} "${${var}}")
+ endforeach()
+ endif()
+ endforeach()
+endmacro()
+
+
+function(_ep_command_line_to_initial_cache var args force)
+ set(script_initial_cache "")
+ set(regex "^([^:]+):([^=]+)=(.*)$")
+ set(setArg "")
+ set(forceArg "")
+ if(force)
+ set(forceArg "FORCE")
+ endif()
+ foreach(line ${args})
+ if("${line}" MATCHES "^-D(.*)")
+ set(line "${CMAKE_MATCH_1}")
+ if(NOT "${setArg}" STREQUAL "")
+ # This is required to build up lists in variables, or complete an entry
+ string(APPEND setArg "${accumulator}\" CACHE ${type} \"Initial cache\" ${forceArg})")
+ string(APPEND script_initial_cache "\n${setArg}")
+ set(accumulator "")
+ set(setArg "")
+ endif()
+ if("${line}" MATCHES "${regex}")
+ set(name "${CMAKE_MATCH_1}")
+ set(type "${CMAKE_MATCH_2}")
+ set(value "${CMAKE_MATCH_3}")
+ set(setArg "set(${name} \"${value}")
+ else()
+ message(WARNING "Line '${line}' does not match regex. Ignoring.")
+ endif()
+ else()
+ # Assume this is a list to append to the last var
+ string(APPEND accumulator ";${line}")
+ endif()
+ endforeach()
+ # Catch the final line of the args
+ if(NOT "${setArg}" STREQUAL "")
+ string(APPEND setArg "${accumulator}\" CACHE ${type} \"Initial cache\" ${forceArg})")
+ string(APPEND script_initial_cache "\n${setArg}")
+ endif()
+ set(${var} ${script_initial_cache} PARENT_SCOPE)
+endfunction()
+
+
+function(_ep_write_initial_cache target_name script_filename script_initial_cache)
+ # Write out values into an initial cache, that will be passed to CMake with -C
+ # Replace location tags.
+ _ep_replace_location_tags(${target_name} script_initial_cache)
+ _ep_replace_location_tags(${target_name} script_filename)
+ # Replace list separators.
+ get_property(sep TARGET ${target_name} PROPERTY _EP_LIST_SEPARATOR)
+ if(sep AND script_initial_cache)
+ string(REPLACE "${sep}" ";" script_initial_cache "${script_initial_cache}")
+ endif()
+ # Write out the initial cache file to the location specified.
+ file(GENERATE OUTPUT "${script_filename}" CONTENT "${script_initial_cache}")
+endfunction()
+
+
+function(ExternalProject_Get_Property name)
+ foreach(var ${ARGN})
+ string(TOUPPER "${var}" VAR)
+ get_property(is_set TARGET ${name} PROPERTY _EP_${VAR} SET)
+ if(NOT is_set)
+ message(FATAL_ERROR "External project \"${name}\" has no ${var}")
+ endif()
+ get_property(${var} TARGET ${name} PROPERTY _EP_${VAR})
+ set(${var} "${${var}}" PARENT_SCOPE)
+ endforeach()
+endfunction()
+
+
+function(_ep_get_configure_command_id name cfg_cmd_id_var)
+ get_target_property(cmd ${name} _EP_CONFIGURE_COMMAND)
+
+ if(cmd STREQUAL "")
+ # Explicit empty string means no configure step for this project
+ set(${cfg_cmd_id_var} "none" PARENT_SCOPE)
+ else()
+ if(NOT cmd)
+ # Default is "use cmake":
+ set(${cfg_cmd_id_var} "cmake" PARENT_SCOPE)
+ else()
+ # Otherwise we have to analyze the value:
+ if(cmd MATCHES "^[^;]*/configure")
+ set(${cfg_cmd_id_var} "configure" PARENT_SCOPE)
+ elseif(cmd MATCHES "^[^;]*/cmake" AND NOT cmd MATCHES ";-[PE];")
+ set(${cfg_cmd_id_var} "cmake" PARENT_SCOPE)
+ elseif(cmd MATCHES "config")
+ set(${cfg_cmd_id_var} "configure" PARENT_SCOPE)
+ else()
+ set(${cfg_cmd_id_var} "unknown:${cmd}" PARENT_SCOPE)
+ endif()
+ endif()
+ endif()
+endfunction()
+
+
+function(_ep_get_build_command name step cmd_var)
+ set(cmd "")
+ set(args)
+ _ep_get_configure_command_id(${name} cfg_cmd_id)
+ if(cfg_cmd_id STREQUAL "cmake")
+ # CMake project. Select build command based on generator.
+ get_target_property(cmake_generator ${name} _EP_CMAKE_GENERATOR)
+ if("${CMAKE_GENERATOR}" MATCHES "Make" AND
+ ("${cmake_generator}" MATCHES "Make" OR NOT cmake_generator))
+ # The project uses the same Makefile generator. Use recursive make.
+ set(cmd "$(MAKE)")
+ if(step STREQUAL "INSTALL")
+ set(args install)
+ endif()
+ if("x${step}x" STREQUAL "xTESTx")
+ set(args test)
+ endif()
+ else()
+ # Drive the project with "cmake --build".
+ get_target_property(cmake_command ${name} _EP_CMAKE_COMMAND)
+ if(cmake_command)
+ set(cmd "${cmake_command}")
+ else()
+ set(cmd "${CMAKE_COMMAND}")
+ endif()
+ set(args --build ".")
+ get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(_isMultiConfig)
+ if (CMAKE_CFG_INTDIR AND
+ NOT CMAKE_CFG_INTDIR STREQUAL "." AND
+ NOT CMAKE_CFG_INTDIR MATCHES "\\$")
+ # CMake 3.4 and below used the CMAKE_CFG_INTDIR placeholder value
+ # provided by multi-configuration generators. Some projects were
+ # taking advantage of that undocumented implementation detail to
+ # specify a specific configuration here. They should use
+ # BUILD_COMMAND to change the default command instead, but for
+ # compatibility honor the value.
+ set(config ${CMAKE_CFG_INTDIR})
+ message(AUTHOR_WARNING "CMAKE_CFG_INTDIR should not be set by project code.\n"
+ "To get a non-default build command, use the BUILD_COMMAND option.")
+ else()
+ set(config $<CONFIG>)
+ endif()
+ list(APPEND args --config ${config})
+ endif()
+ if(step STREQUAL "INSTALL")
+ list(APPEND args --target install)
+ endif()
+ # But for "TEST" drive the project with corresponding "ctest".
+ if("x${step}x" STREQUAL "xTESTx")
+ string(REGEX REPLACE "^(.*/)cmake([^/]*)$" "\\1ctest\\2" cmd "${cmd}")
+ set(args "")
+ if(_isMultiConfig)
+ list(APPEND args -C ${config})
+ endif()
+ endif()
+ endif()
+ else()
+ # Non-CMake project. Guess "make" and "make install" and "make test".
+ if("${CMAKE_GENERATOR}" MATCHES "Makefiles")
+ # Try to get the parallel arguments
+ set(cmd "$(MAKE)")
+ else()
+ set(cmd "make")
+ endif()
+ if(step STREQUAL "INSTALL")
+ set(args install)
+ endif()
+ if("x${step}x" STREQUAL "xTESTx")
+ set(args test)
+ endif()
+ endif()
+
+ # Use user-specified arguments instead of default arguments, if any.
+ get_property(have_args TARGET ${name} PROPERTY _EP_${step}_ARGS SET)
+ if(have_args)
+ get_target_property(args ${name} _EP_${step}_ARGS)
+ endif()
+
+ if(NOT "${args}" STREQUAL "")
+ # args could have empty items, so we must quote it to prevent them
+ # from being silently removed
+ list(APPEND cmd "${args}")
+ endif()
+ set(${cmd_var} "${cmd}" PARENT_SCOPE)
+endfunction()
+
+function(_ep_write_log_script name step cmd_var)
+ ExternalProject_Get_Property(${name} log_dir)
+ ExternalProject_Get_Property(${name} stamp_dir)
+ set(command "${${cmd_var}}")
+
+ set(make "")
+ set(code_cygpath_make "")
+ if(command MATCHES "^\\$\\(MAKE\\)")
+ # GNU make recognizes the string "$(MAKE)" as recursive make, so
+ # ensure that it appears directly in the makefile.
+ string(REGEX REPLACE "^\\$\\(MAKE\\)" "\${make}" command "${command}")
+ set(make "-Dmake=$(MAKE)")
+
+ if(WIN32 AND NOT CYGWIN)
+ set(code_cygpath_make "
+if(\${make} MATCHES \"^/\")
+ execute_process(
+ COMMAND cygpath -w \${make}
+ OUTPUT_VARIABLE cygpath_make
+ ERROR_VARIABLE cygpath_make
+ RESULT_VARIABLE cygpath_error
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if(NOT cygpath_error)
+ set(make \${cygpath_make})
+ endif()
+endif()
+")
+ endif()
+ endif()
+
+ set(config "")
+ if("${CMAKE_CFG_INTDIR}" MATCHES "^\\$")
+ string(REPLACE "${CMAKE_CFG_INTDIR}" "\${config}" command "${command}")
+ set(config "-Dconfig=${CMAKE_CFG_INTDIR}")
+ endif()
+
+ # Wrap multiple 'COMMAND' lines up into a second-level wrapper
+ # script so all output can be sent to one log file.
+ if(command MATCHES "(^|;)COMMAND;")
+ set(code_execute_process "
+${code_cygpath_make}
+execute_process(COMMAND \${command} RESULT_VARIABLE result)
+if(result)
+ set(msg \"Command failed (\${result}):\\n\")
+ foreach(arg IN LISTS command)
+ set(msg \"\${msg} '\${arg}'\")
+ endforeach()
+ message(FATAL_ERROR \"\${msg}\")
+endif()
+")
+ set(code "")
+ set(cmd "")
+ set(sep "")
+ foreach(arg IN LISTS command)
+ if("x${arg}" STREQUAL "xCOMMAND")
+ if(NOT "x${cmd}" STREQUAL "x")
+ string(APPEND code "set(command \"${cmd}\")${code_execute_process}")
+ endif()
+ set(cmd "")
+ set(sep "")
+ else()
+ string(APPEND cmd "${sep}${arg}")
+ set(sep ";")
+ endif()
+ endforeach()
+ string(APPEND code "set(command \"${cmd}\")${code_execute_process}")
+ file(GENERATE OUTPUT "${stamp_dir}/${name}-${step}-$<CONFIG>-impl.cmake" CONTENT "${code}")
+ set(command ${CMAKE_COMMAND} "-Dmake=\${make}" "-Dconfig=\${config}" -P ${stamp_dir}/${name}-${step}-$<CONFIG>-impl.cmake)
+ endif()
+
+ # Wrap the command in a script to log output to files.
+ set(script ${stamp_dir}/${name}-${step}-$<CONFIG>.cmake)
+ set(logbase ${log_dir}/${name}-${step})
+ get_property(log_merged TARGET ${name} PROPERTY _EP_LOG_MERGED_STDOUTERR)
+ get_property(log_output_on_failure TARGET ${name} PROPERTY _EP_LOG_OUTPUT_ON_FAILURE)
+ if (log_merged)
+ set(stdout_log "${logbase}.log")
+ set(stderr_log "${logbase}.log")
+ else()
+ set(stdout_log "${logbase}-out.log")
+ set(stderr_log "${logbase}-err.log")
+ endif()
+ set(code "
+cmake_minimum_required(VERSION 3.15)
+${code_cygpath_make}
+set(command \"${command}\")
+set(log_merged \"${log_merged}\")
+set(log_output_on_failure \"${log_output_on_failure}\")
+set(stdout_log \"${stdout_log}\")
+set(stderr_log \"${stderr_log}\")
+execute_process(
+ COMMAND \${command}
+ RESULT_VARIABLE result
+ OUTPUT_FILE \"\${stdout_log}\"
+ ERROR_FILE \"\${stderr_log}\"
+ )
+macro(read_up_to_max_size log_file output_var)
+ file(SIZE \${log_file} determined_size)
+ set(max_size 10240)
+ if (determined_size GREATER max_size)
+ math(EXPR seek_position \"\${determined_size} - \${max_size}\")
+ file(READ \${log_file} \${output_var} OFFSET \${seek_position})
+ set(\${output_var} \"...skipping to end...\\n\${\${output_var}}\")
+ else()
+ file(READ \${log_file} \${output_var})
+ endif()
+endmacro()
+if(result)
+ set(msg \"Command failed: \${result}\\n\")
+ foreach(arg IN LISTS command)
+ set(msg \"\${msg} '\${arg}'\")
+ endforeach()
+ if (\${log_merged})
+ set(msg \"\${msg}\\nSee also\\n \${stderr_log}\")
+ else()
+ set(msg \"\${msg}\\nSee also\\n ${logbase}-*.log\")
+ endif()
+ if (\${log_output_on_failure})
+ message(SEND_ERROR \"\${msg}\")
+ if (\${log_merged})
+ read_up_to_max_size(\"\${stderr_log}\" error_log_contents)
+ message(STATUS \"Log output is:\\n\${error_log_contents}\")
+ else()
+ read_up_to_max_size(\"\${stdout_log}\" out_log_contents)
+ read_up_to_max_size(\"\${stderr_log}\" err_log_contents)
+ message(STATUS \"stdout output is:\\n\${out_log_contents}\")
+ message(STATUS \"stderr output is:\\n\${err_log_contents}\")
+ endif()
+ message(FATAL_ERROR \"Stopping after outputting logs.\")
+ else()
+ message(FATAL_ERROR \"\${msg}\")
+ endif()
+else()
+ if(NOT \"${CMAKE_GENERATOR}\" MATCHES \"Ninja\")
+ set(msg \"${name} ${step} command succeeded. See also ${logbase}-*.log\")
+ message(STATUS \"\${msg}\")
+ endif()
+endif()
+")
+ file(GENERATE OUTPUT "${script}" CONTENT "${code}")
+ set(command ${CMAKE_COMMAND} ${make} ${config} -P ${script})
+ set(${cmd_var} "${command}" PARENT_SCOPE)
+endfunction()
+
+# This module used to use "/${CMAKE_CFG_INTDIR}" directly and produced
+# makefiles with "/./" in paths for custom command dependencies. Which
+# resulted in problems with parallel make -j invocations.
+#
+# This function was added so that the suffix (search below for ${cfgdir}) is
+# only set to "/${CMAKE_CFG_INTDIR}" when ${CMAKE_CFG_INTDIR} is not going to
+# be "." (multi-configuration build systems like Visual Studio and Xcode...)
+#
+function(_ep_get_configuration_subdir_suffix suffix_var)
+ set(suffix "")
+ get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(_isMultiConfig)
+ set(suffix "/${CMAKE_CFG_INTDIR}")
+ endif()
+ set(${suffix_var} "${suffix}" PARENT_SCOPE)
+endfunction()
+
+
+function(_ep_get_step_stampfile name step stampfile_var)
+ ExternalProject_Get_Property(${name} stamp_dir)
+
+ _ep_get_configuration_subdir_suffix(cfgdir)
+ set(stampfile "${stamp_dir}${cfgdir}/${name}-${step}")
+
+ set(${stampfile_var} "${stampfile}" PARENT_SCOPE)
+endfunction()
+
+
+function(_ep_get_complete_stampfile name stampfile_var)
+ set(cmf_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
+ _ep_get_configuration_subdir_suffix(cfgdir)
+ set(stampfile "${cmf_dir}${cfgdir}/${name}-complete")
+
+ set(${stampfile_var} ${stampfile} PARENT_SCOPE)
+endfunction()
+
+
+function(_ep_step_add_target name step no_deps)
+ if(TARGET ${name}-${step})
+ return()
+ endif()
+ get_property(cmp0114 TARGET ${name} PROPERTY _EP_CMP0114)
+ _ep_get_step_stampfile(${name} ${step} stamp_file)
+ cmake_policy(PUSH)
+ if(cmp0114 STREQUAL "NEW")
+ # To implement CMP0114 NEW behavior with Makefile generators,
+ # we need CMP0113 NEW behavior.
+ cmake_policy(SET CMP0113 NEW)
+ endif()
+ add_custom_target(${name}-${step}
+ DEPENDS ${stamp_file})
+ cmake_policy(POP)
+ set_property(TARGET ${name}-${step} PROPERTY _EP_IS_EXTERNAL_PROJECT_STEP 1)
+ set_property(TARGET ${name}-${step} PROPERTY LABELS ${name})
+ set_property(TARGET ${name}-${step} PROPERTY FOLDER "ExternalProjectTargets/${name}")
+
+ if(cmp0114 STREQUAL "NEW")
+ # Add target-level dependencies for the step.
+ get_property(exclude_from_main TARGET ${name} PROPERTY _EP_${step}_EXCLUDE_FROM_MAIN)
+ if(NOT exclude_from_main)
+ add_dependencies(${name} ${name}-${step})
+ endif()
+ _ep_step_add_target_dependencies(${name} ${step} ${step})
+ _ep_step_add_target_dependents(${name} ${step} ${step})
+
+ get_property(independent TARGET ${name} PROPERTY _EP_${step}_INDEPENDENT)
+ else()
+ if(no_deps AND "${step}" MATCHES "^(configure|build|install|test)$")
+ message(AUTHOR_WARNING "Using NO_DEPENDS for \"${step}\" step might break parallel builds")
+ endif()
+ set(independent ${no_deps})
+ endif()
+
+ # Depend on other external projects (target-level).
+ if(NOT independent)
+ get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
+ foreach(arg IN LISTS deps)
+ add_dependencies(${name}-${step} ${arg})
+ endforeach()
+ endif()
+endfunction()
+
+
+function(_ep_step_add_target_dependencies name step node)
+ get_property(dependees TARGET ${name} PROPERTY _EP_${node}_INTERNAL_DEPENDEES)
+ list(REMOVE_DUPLICATES dependees)
+ foreach(dependee IN LISTS dependees)
+ get_property(exclude_from_main TARGET ${name} PROPERTY _EP_${step}_EXCLUDE_FROM_MAIN)
+ get_property(dependee_dependers TARGET ${name} PROPERTY _EP_${dependee}_INTERNAL_DEPENDERS)
+ if(exclude_from_main OR dependee_dependers MATCHES ";")
+ # The step on which our step target depends itself has
+ # dependents in multiple targes. It needs a step target too
+ # so that there is a unique place for its custom command.
+ _ep_step_add_target("${name}" "${dependee}" "FALSE")
+ endif()
+
+ if(TARGET ${name}-${dependee})
+ add_dependencies(${name}-${step} ${name}-${dependee})
+ else()
+ _ep_step_add_target_dependencies(${name} ${step} ${dependee})
+ endif()
+ endforeach()
+endfunction()
+
+
+function(_ep_step_add_target_dependents name step node)
+ get_property(dependers TARGET ${name} PROPERTY _EP_${node}_INTERNAL_DEPENDERS)
+ list(REMOVE_DUPLICATES dependers)
+ foreach(depender IN LISTS dependers)
+ if(TARGET ${name}-${depender})
+ add_dependencies(${name}-${depender} ${name}-${step})
+ else()
+ _ep_step_add_target_dependents(${name} ${step} ${depender})
+ endif()
+ endforeach()
+endfunction()
+
+
+function(ExternalProject_Add_StepTargets name)
+ get_property(cmp0114 TARGET ${name} PROPERTY _EP_CMP0114)
+ set(steps ${ARGN})
+ if(ARGC GREATER 1 AND "${ARGV1}" STREQUAL "NO_DEPENDS")
+ set(no_deps 1)
+ list(REMOVE_AT steps 0)
+ else()
+ set(no_deps 0)
+ endif()
+ if(cmp0114 STREQUAL "NEW")
+ if(no_deps)
+ message(FATAL_ERROR
+ "The 'NO_DEPENDS' option is no longer allowed. "
+ "It has been superseded by the per-step 'INDEPENDENT' option. "
+ "See policy CMP0114."
+ )
+ endif()
+ elseif(cmp0114 STREQUAL "")
+ cmake_policy(GET_WARNING CMP0114 _cmp0114_warning)
+ string(APPEND _cmp0114_warning "\n"
+ "ExternalProject target '${name}' would depend on the targets for "
+ "step(s) '${steps}' under policy CMP0114, but this is being left out "
+ "for compatibility since the policy is not set."
+ )
+ if(no_deps)
+ string(APPEND _cmp0114_warning
+ " Also, the NO_DEPENDS option is deprecated in favor of policy CMP0114."
+ )
+ endif()
+ message(AUTHOR_WARNING "${_cmp0114_warning}")
+ endif()
+ foreach(step ${steps})
+ _ep_step_add_target("${name}" "${step}" "${no_deps}")
+ endforeach()
+endfunction()
+
+
+function(ExternalProject_Add_Step name step)
+ get_property(cmp0114 TARGET ${name} PROPERTY _EP_CMP0114)
+ _ep_get_complete_stampfile(${name} complete_stamp_file)
+ _ep_get_step_stampfile(${name} ${step} stamp_file)
+
+ set(keywords
+ COMMAND
+ COMMENT
+ DEPENDEES
+ DEPENDERS
+ DEPENDS
+ INDEPENDENT
+ BYPRODUCTS
+ ALWAYS
+ EXCLUDE_FROM_MAIN
+ WORKING_DIRECTORY
+ LOG
+ USES_TERMINAL
+ )
+ _ep_parse_arguments(ExternalProject_Add_Step "${keywords}"
+ ${name} _EP_${step}_ "${ARGN}")
+
+ get_property(independent TARGET ${name} PROPERTY _EP_${step}_INDEPENDENT)
+ if(independent STREQUAL "")
+ set(independent FALSE)
+ set_property(TARGET ${name} PROPERTY _EP_${step}_INDEPENDENT "${independent}")
+ endif()
+
+ get_property(exclude_from_main TARGET ${name} PROPERTY _EP_${step}_EXCLUDE_FROM_MAIN)
+ if(NOT exclude_from_main)
+ add_custom_command(APPEND
+ OUTPUT ${complete_stamp_file}
+ DEPENDS ${stamp_file}
+ )
+ endif()
+
+ # Steps depending on this step.
+ get_property(dependers TARGET ${name} PROPERTY _EP_${step}_DEPENDERS)
+ set_property(TARGET ${name} APPEND PROPERTY _EP_${step}_INTERNAL_DEPENDERS ${dependers})
+ foreach(depender IN LISTS dependers)
+ set_property(TARGET ${name} APPEND PROPERTY _EP_${depender}_INTERNAL_DEPENDEES ${step})
+ _ep_get_step_stampfile(${name} ${depender} depender_stamp_file)
+ add_custom_command(APPEND
+ OUTPUT ${depender_stamp_file}
+ DEPENDS ${stamp_file}
+ )
+ if(cmp0114 STREQUAL "NEW" AND NOT independent)
+ get_property(dep_independent TARGET ${name} PROPERTY _EP_${depender}_INDEPENDENT)
+ if(dep_independent)
+ message(FATAL_ERROR "ExternalProject '${name}' step '${depender}' is marked INDEPENDENT "
+ "but depends on step '${step}' that is not marked INDEPENDENT.")
+ endif()
+ endif()
+ endforeach()
+
+ # Dependencies on files.
+ get_property(depends TARGET ${name} PROPERTY _EP_${step}_DEPENDS)
+
+ # Byproducts of the step.
+ get_property(byproducts TARGET ${name} PROPERTY _EP_${step}_BYPRODUCTS)
+
+ # Dependencies on steps.
+ get_property(dependees TARGET ${name} PROPERTY _EP_${step}_DEPENDEES)
+ set_property(TARGET ${name} APPEND PROPERTY _EP_${step}_INTERNAL_DEPENDEES ${dependees})
+ foreach(dependee IN LISTS dependees)
+ set_property(TARGET ${name} APPEND PROPERTY _EP_${dependee}_INTERNAL_DEPENDERS ${step})
+ _ep_get_step_stampfile(${name} ${dependee} dependee_stamp_file)
+ list(APPEND depends ${dependee_stamp_file})
+ if(cmp0114 STREQUAL "NEW" AND independent)
+ get_property(dep_independent TARGET ${name} PROPERTY _EP_${dependee}_INDEPENDENT)
+ if(NOT dep_independent)
+ message(FATAL_ERROR "ExternalProject '${name}' step '${step}' is marked INDEPENDENT "
+ "but depends on step '${dependee}' that is not marked INDEPENDENT.")
+ endif()
+ endif()
+ endforeach()
+
+ # The command to run.
+ get_property(command TARGET ${name} PROPERTY _EP_${step}_COMMAND)
+ if(command)
+ set(comment "Performing ${step} step for '${name}'")
+ else()
+ set(comment "No ${step} step for '${name}'")
+ endif()
+ get_property(work_dir TARGET ${name} PROPERTY _EP_${step}_WORKING_DIRECTORY)
+
+ # Replace list separators.
+ get_property(sep TARGET ${name} PROPERTY _EP_LIST_SEPARATOR)
+ if(sep AND command)
+ string(REPLACE "${sep}" "\\;" command "${command}")
+ endif()
+
+ # Replace location tags.
+ _ep_replace_location_tags(${name} comment command work_dir byproducts)
+
+ # Custom comment?
+ get_property(comment_set TARGET ${name} PROPERTY _EP_${step}_COMMENT SET)
+ if(comment_set)
+ get_property(comment TARGET ${name} PROPERTY _EP_${step}_COMMENT)
+ endif()
+
+ # Uses terminal?
+ get_property(uses_terminal TARGET ${name} PROPERTY _EP_${step}_USES_TERMINAL)
+ if(uses_terminal)
+ set(uses_terminal USES_TERMINAL)
+ else()
+ set(uses_terminal "")
+ endif()
+
+ # Run every time?
+ get_property(always TARGET ${name} PROPERTY _EP_${step}_ALWAYS)
+ if(always)
+ set_property(SOURCE ${stamp_file} PROPERTY SYMBOLIC 1)
+ set(touch)
+ # Remove any existing stamp in case the option changed in an existing tree.
+ get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(_isMultiConfig)
+ foreach(cfg ${CMAKE_CONFIGURATION_TYPES})
+ string(REPLACE "/${CMAKE_CFG_INTDIR}" "/${cfg}" stamp_file_config "${stamp_file}")
+ file(REMOVE ${stamp_file_config})
+ endforeach()
+ else()
+ file(REMOVE ${stamp_file})
+ endif()
+ else()
+ set(touch ${CMAKE_COMMAND} -E touch ${stamp_file})
+ endif()
+
+ # Wrap with log script?
+ get_property(log TARGET ${name} PROPERTY _EP_${step}_LOG)
+ if(command AND log)
+ _ep_write_log_script(${name} ${step} command)
+ endif()
+
+ if("${command}" STREQUAL "")
+ # Some generators (i.e. Xcode) will not generate a file level target
+ # if no command is set, and therefore the dependencies on this
+ # target will be broken.
+ # The empty command is replaced by an echo command here in order to
+ # avoid this issue.
+ set(command ${CMAKE_COMMAND} -E echo_append)
+ endif()
+
+ set(__cmdQuoted)
+ foreach(__item IN LISTS command)
+ string(APPEND __cmdQuoted " [==[${__item}]==]")
+ endforeach()
+ cmake_language(EVAL CODE "
+ add_custom_command(
+ OUTPUT \${stamp_file}
+ BYPRODUCTS \${byproducts}
+ COMMENT \${comment}
+ COMMAND ${__cmdQuoted}
+ COMMAND \${touch}
+ DEPENDS \${depends}
+ WORKING_DIRECTORY \${work_dir}
+ VERBATIM
+ ${uses_terminal}
+ )"
+ )
+ set_property(TARGET ${name} APPEND PROPERTY _EP_STEPS ${step})
+
+ # Add custom "step target"?
+ get_property(step_targets TARGET ${name} PROPERTY _EP_STEP_TARGETS)
+ if(NOT step_targets)
+ get_property(step_targets DIRECTORY PROPERTY EP_STEP_TARGETS)
+ endif()
+ foreach(st ${step_targets})
+ if("${st}" STREQUAL "${step}")
+ _ep_step_add_target("${name}" "${step}" "FALSE")
+ break()
+ endif()
+ endforeach()
+
+ get_property(independent_step_targets TARGET ${name} PROPERTY _EP_INDEPENDENT_STEP_TARGETS)
+ if(NOT independent_step_targets)
+ get_property(independent_step_targets DIRECTORY PROPERTY EP_INDEPENDENT_STEP_TARGETS)
+ endif()
+ if(cmp0114 STREQUAL "NEW")
+ if(independent_step_targets)
+ message(FATAL_ERROR
+ "ExternalProject '${name}' option 'INDEPENDENT_STEP_TARGETS' is set to\n"
+ " ${independent_step_targets}\n"
+ "but the option is no longer allowed. "
+ "It has been superseded by the per-step 'INDEPENDENT' option. "
+ "See policy CMP0114."
+ )
+ endif()
+ else()
+ if(independent_step_targets AND cmp0114 STREQUAL "")
+ get_property(warned TARGET ${name} PROPERTY _EP_CMP0114_WARNED_INDEPENDENT_STEP_TARGETS)
+ if(NOT warned)
+ set_property(TARGET ${name} PROPERTY _EP_CMP0114_WARNED_INDEPENDENT_STEP_TARGETS 1)
+ cmake_policy(GET_WARNING CMP0114 _cmp0114_warning)
+ string(APPEND _cmp0114_warning "\n"
+ "ExternalProject '${name}' option INDEPENDENT_STEP_TARGETS is set to\n"
+ " ${independent_step_targets}\n"
+ "but the option is deprecated in favor of policy CMP0114."
+ )
+ message(AUTHOR_WARNING "${_cmp0114_warning}")
+ endif()
+ endif()
+ foreach(st ${independent_step_targets})
+ if("${st}" STREQUAL "${step}")
+ _ep_step_add_target("${name}" "${step}" "TRUE")
+ break()
+ endif()
+ endforeach()
+ endif()
+endfunction()
+
+
+function(ExternalProject_Add_StepDependencies name step)
+ set(dependencies ${ARGN})
+
+ # Sanity checks on "name" and "step".
+ if(NOT TARGET ${name})
+ message(FATAL_ERROR "Cannot find target \"${name}\". Perhaps it has not yet been created using ExternalProject_Add.")
+ endif()
+
+ get_property(type TARGET ${name} PROPERTY TYPE)
+ if(NOT type STREQUAL "UTILITY")
+ message(FATAL_ERROR "Target \"${name}\" was not generated by ExternalProject_Add.")
+ endif()
+
+ get_property(is_ep TARGET ${name} PROPERTY _EP_IS_EXTERNAL_PROJECT)
+ if(NOT is_ep)
+ message(FATAL_ERROR "Target \"${name}\" was not generated by ExternalProject_Add.")
+ endif()
+
+ get_property(steps TARGET ${name} PROPERTY _EP_STEPS)
+ list(FIND steps ${step} is_step)
+ if(is_step LESS 0)
+ message(FATAL_ERROR "External project \"${name}\" does not have a step \"${step}\".")
+ endif()
+
+ if(TARGET ${name}-${step})
+ get_property(type TARGET ${name}-${step} PROPERTY TYPE)
+ if(NOT type STREQUAL "UTILITY")
+ message(FATAL_ERROR "Target \"${name}-${step}\" was not generated by ExternalProject_Add_StepTargets.")
+ endif()
+ get_property(is_ep_step TARGET ${name}-${step} PROPERTY _EP_IS_EXTERNAL_PROJECT_STEP)
+ if(NOT is_ep_step)
+ message(FATAL_ERROR "Target \"${name}-${step}\" was not generated by ExternalProject_Add_StepTargets.")
+ endif()
+ endif()
+
+ # Always add file-level dependency, but add target-level dependency
+ # only if the target exists for that step.
+ _ep_get_step_stampfile(${name} ${step} stamp_file)
+ foreach(dep ${dependencies})
+ add_custom_command(APPEND
+ OUTPUT ${stamp_file}
+ DEPENDS ${dep})
+ if(TARGET ${name}-${step})
+ foreach(dep ${dependencies})
+ add_dependencies(${name}-${step} ${dep})
+ endforeach()
+ endif()
+ endforeach()
+
+endfunction()
+
+
+function(_ep_add_mkdir_command name)
+ ExternalProject_Get_Property(${name}
+ source_dir binary_dir install_dir stamp_dir download_dir tmp_dir log_dir)
+
+ _ep_get_configuration_subdir_suffix(cfgdir)
+
+ ExternalProject_Add_Step(${name} mkdir
+ INDEPENDENT TRUE
+ COMMENT "Creating directories for '${name}'"
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${source_dir}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${binary_dir}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${install_dir}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${tmp_dir}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${stamp_dir}${cfgdir}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${download_dir}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${log_dir}
+ )
+endfunction()
+
+
+function(_ep_is_dir_empty dir empty_var)
+ file(GLOB gr "${dir}/*")
+ if("${gr}" STREQUAL "")
+ set(${empty_var} 1 PARENT_SCOPE)
+ else()
+ set(${empty_var} 0 PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_ep_get_git_submodules_recurse git_submodules_recurse)
+ # Checks for GIT_SUBMODULES_RECURSE property
+ # Default is ON, which sets git_submodules_recurse output variable to "--recursive"
+ # Otherwise, the output variable is set to an empty value ""
+ get_property(git_submodules_recurse_set TARGET ${name} PROPERTY _EP_GIT_SUBMODULES_RECURSE SET)
+ if(NOT git_submodules_recurse_set)
+ set(recurseFlag "--recursive")
+ else()
+ get_property(git_submodules_recurse_value TARGET ${name} PROPERTY _EP_GIT_SUBMODULES_RECURSE)
+ if(git_submodules_recurse_value)
+ set(recurseFlag "--recursive")
+ else()
+ set(recurseFlag "")
+ endif()
+ endif()
+ set(${git_submodules_recurse} "${recurseFlag}" PARENT_SCOPE)
+
+ # The git submodule update '--recursive' flag requires git >= v1.6.5
+ if(recurseFlag AND GIT_VERSION_STRING VERSION_LESS 1.6.5)
+ message(FATAL_ERROR "error: git version 1.6.5 or later required for --recursive flag with 'git submodule ...': GIT_VERSION_STRING='${GIT_VERSION_STRING}'")
+ endif()
+endfunction()
+
+
+function(_ep_add_download_command name)
+ ExternalProject_Get_Property(${name} source_dir stamp_dir download_dir tmp_dir)
+
+ get_property(cmd_set TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND SET)
+ get_property(cmd TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND)
+ get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
+ get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
+ get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
+ get_property(hg_repository TARGET ${name} PROPERTY _EP_HG_REPOSITORY )
+ get_property(url TARGET ${name} PROPERTY _EP_URL)
+ get_property(fname TARGET ${name} PROPERTY _EP_DOWNLOAD_NAME)
+
+ # TODO: Perhaps file:// should be copied to download dir before extraction.
+ string(REGEX REPLACE "file://" "" url "${url}")
+
+ set(depends)
+ set(comment)
+ set(work_dir)
+
+ if(cmd_set)
+ set(work_dir ${download_dir})
+ elseif(cvs_repository)
+ find_package(CVS QUIET)
+ if(NOT CVS_EXECUTABLE)
+ message(FATAL_ERROR "error: could not find cvs for checkout of ${name}")
+ endif()
+
+ get_target_property(cvs_module ${name} _EP_CVS_MODULE)
+ if(NOT cvs_module)
+ message(FATAL_ERROR "error: no CVS_MODULE")
+ endif()
+
+ get_property(cvs_tag TARGET ${name} PROPERTY _EP_CVS_TAG)
+
+ set(repository ${cvs_repository})
+ set(module ${cvs_module})
+ set(tag ${cvs_tag})
+ configure_file(
+ "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
+ "${stamp_dir}/${name}-cvsinfo.txt"
+ @ONLY
+ )
+
+ get_filename_component(src_name "${source_dir}" NAME)
+ get_filename_component(work_dir "${source_dir}" PATH)
+ set(comment "Performing download step (CVS checkout) for '${name}'")
+ set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q co ${cvs_tag} -d ${src_name} ${cvs_module})
+ list(APPEND depends ${stamp_dir}/${name}-cvsinfo.txt)
+ elseif(svn_repository)
+ find_package(Subversion QUIET)
+ if(NOT Subversion_SVN_EXECUTABLE)
+ message(FATAL_ERROR "error: could not find svn for checkout of ${name}")
+ endif()
+
+ get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
+ get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
+ get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
+ get_property(svn_trust_cert TARGET ${name} PROPERTY _EP_SVN_TRUST_CERT)
+
+ set(repository "${svn_repository} user=${svn_username} password=${svn_password}")
+ set(module)
+ set(tag ${svn_revision})
+ configure_file(
+ "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
+ "${stamp_dir}/${name}-svninfo.txt"
+ @ONLY
+ )
+
+ get_filename_component(src_name "${source_dir}" NAME)
+ get_filename_component(work_dir "${source_dir}" PATH)
+ set(comment "Performing download step (SVN checkout) for '${name}'")
+ set(svn_user_pw_args "")
+ if(DEFINED svn_username)
+ set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}")
+ endif()
+ if(DEFINED svn_password)
+ set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}")
+ endif()
+ if(svn_trust_cert)
+ set(svn_trust_cert_args --trust-server-cert)
+ endif()
+ set(cmd ${Subversion_SVN_EXECUTABLE} co ${svn_repository} ${svn_revision}
+ --non-interactive ${svn_trust_cert_args} ${svn_user_pw_args} ${src_name})
+ list(APPEND depends ${stamp_dir}/${name}-svninfo.txt)
+ elseif(git_repository)
+ # FetchContent gives us these directly, so don't try to recompute them
+ if(NOT GIT_EXECUTABLE OR NOT GIT_VERSION_STRING)
+ unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
+ find_package(Git QUIET)
+ if(NOT GIT_EXECUTABLE)
+ message(FATAL_ERROR "error: could not find git for clone of ${name}")
+ endif()
+ endif()
+
+ _ep_get_git_submodules_recurse(git_submodules_recurse)
+
+ get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
+ if(NOT git_tag)
+ set(git_tag "master")
+ endif()
+
+ set(git_init_submodules TRUE)
+ get_property(git_submodules_set TARGET ${name} PROPERTY _EP_GIT_SUBMODULES SET)
+ if(git_submodules_set)
+ get_property(git_submodules TARGET ${name} PROPERTY _EP_GIT_SUBMODULES)
+ if(git_submodules STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW")
+ set(git_init_submodules FALSE)
+ endif()
+ endif()
+
+ get_property(git_remote_name TARGET ${name} PROPERTY _EP_GIT_REMOTE_NAME)
+ if(NOT git_remote_name)
+ set(git_remote_name "origin")
+ endif()
+
+ get_property(tls_verify TARGET ${name} PROPERTY _EP_TLS_VERIFY)
+ if("x${tls_verify}" STREQUAL "x" AND DEFINED CMAKE_TLS_VERIFY)
+ set(tls_verify "${CMAKE_TLS_VERIFY}")
+ endif()
+ get_property(git_shallow TARGET ${name} PROPERTY _EP_GIT_SHALLOW)
+ get_property(git_progress TARGET ${name} PROPERTY _EP_GIT_PROGRESS)
+ get_property(git_config TARGET ${name} PROPERTY _EP_GIT_CONFIG)
+
+ # Make checkouts quiet when checking out a git hash (this avoids the
+ # very noisy detached head message)
+ list(PREPEND git_config advice.detachedHead=false)
+
+ # For the download step, and the git clone operation, only the repository
+ # should be recorded in a configured RepositoryInfo file. If the repo
+ # changes, the clone script should be run again. But if only the tag
+ # changes, avoid running the clone script again. Let the 'always' running
+ # update step checkout the new tag.
+ #
+ set(repository ${git_repository})
+ set(module)
+ set(tag ${git_remote_name})
+ configure_file(
+ "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
+ "${stamp_dir}/${name}-gitinfo.txt"
+ @ONLY
+ )
+
+ get_filename_component(src_name "${source_dir}" NAME)
+ get_filename_component(work_dir "${source_dir}" PATH)
+
+ # Since git clone doesn't succeed if the non-empty source_dir exists,
+ # create a cmake script to invoke as download command.
+ # The script will delete the source directory and then call git clone.
+ #
+ _ep_write_gitclone_script(${tmp_dir}/${name}-gitclone.cmake ${source_dir}
+ ${GIT_EXECUTABLE} ${git_repository} ${git_tag} ${git_remote_name} ${git_init_submodules} "${git_submodules_recurse}" "${git_submodules}" "${git_shallow}" "${git_progress}" "${git_config}" ${src_name} ${work_dir}
+ ${stamp_dir}/${name}-gitinfo.txt ${stamp_dir}/${name}-gitclone-lastrun.txt "${tls_verify}"
+ )
+ set(comment "Performing download step (git clone) for '${name}'")
+ set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitclone.cmake)
+ list(APPEND depends ${stamp_dir}/${name}-gitinfo.txt)
+ elseif(hg_repository)
+ find_package(Hg QUIET)
+ if(NOT HG_EXECUTABLE)
+ message(FATAL_ERROR "error: could not find hg for clone of ${name}")
+ endif()
+
+ get_property(hg_tag TARGET ${name} PROPERTY _EP_HG_TAG)
+ if(NOT hg_tag)
+ set(hg_tag "tip")
+ endif()
+
+ # For the download step, and the hg clone operation, only the repository
+ # should be recorded in a configured RepositoryInfo file. If the repo
+ # changes, the clone script should be run again. But if only the tag
+ # changes, avoid running the clone script again. Let the 'always' running
+ # update step checkout the new tag.
+ #
+ set(repository ${hg_repository})
+ set(module)
+ set(tag)
+ configure_file(
+ "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
+ "${stamp_dir}/${name}-hginfo.txt"
+ @ONLY
+ )
+
+ get_filename_component(src_name "${source_dir}" NAME)
+ get_filename_component(work_dir "${source_dir}" PATH)
+
+ # Since hg clone doesn't succeed if the non-empty source_dir exists,
+ # create a cmake script to invoke as download command.
+ # The script will delete the source directory and then call hg clone.
+ #
+ _ep_write_hgclone_script(${tmp_dir}/${name}-hgclone.cmake ${source_dir}
+ ${HG_EXECUTABLE} ${hg_repository} ${hg_tag} ${src_name} ${work_dir}
+ ${stamp_dir}/${name}-hginfo.txt ${stamp_dir}/${name}-hgclone-lastrun.txt
+ )
+ set(comment "Performing download step (hg clone) for '${name}'")
+ set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-hgclone.cmake)
+ list(APPEND depends ${stamp_dir}/${name}-hginfo.txt)
+ elseif(url)
+ get_filename_component(work_dir "${source_dir}" PATH)
+ get_property(hash TARGET ${name} PROPERTY _EP_URL_HASH)
+ _ep_get_hash_regex(_ep_hash_regex)
+ if(hash AND NOT "${hash}" MATCHES "${_ep_hash_regex}")
+ _ep_get_hash_algos(_ep_hash_algos)
+ list(JOIN _ep_hash_algos "|" _ep_hash_algos)
+ message(FATAL_ERROR "URL_HASH is set to\n ${hash}\n"
+ "but must be ALGO=value where ALGO is\n ${_ep_hash_algos}\n"
+ "and value is a hex string.")
+ endif()
+ get_property(md5 TARGET ${name} PROPERTY _EP_URL_MD5)
+ if(md5 AND NOT "MD5=${md5}" MATCHES "${_ep_hash_regex}")
+ message(FATAL_ERROR "URL_MD5 is set to\n ${md5}\nbut must be a hex string.")
+ endif()
+ if(md5 AND NOT hash)
+ set(hash "MD5=${md5}")
+ endif()
+ set(repository "external project URL")
+ set(module "${url}")
+ set(tag "${hash}")
+ configure_file(
+ "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
+ "${stamp_dir}/${name}-urlinfo.txt"
+ @ONLY
+ )
+ list(APPEND depends ${stamp_dir}/${name}-urlinfo.txt)
+
+ list(LENGTH url url_list_length)
+ if(NOT "${url_list_length}" STREQUAL "1")
+ foreach(entry ${url})
+ if(NOT "${entry}" MATCHES "^[a-z]+://")
+ message(FATAL_ERROR "At least one entry of URL is a path (invalid in a list)")
+ endif()
+ endforeach()
+ if("x${fname}" STREQUAL "x")
+ list(GET url 0 fname)
+ endif()
+ endif()
+
+ if(IS_DIRECTORY "${url}")
+ get_filename_component(abs_dir "${url}" ABSOLUTE)
+ set(comment "Performing download step (DIR copy) for '${name}'")
+ set(cmd ${CMAKE_COMMAND} -E rm -rf ${source_dir}
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${abs_dir} ${source_dir})
+ else()
+ get_property(no_extract TARGET "${name}" PROPERTY _EP_DOWNLOAD_NO_EXTRACT)
+ if("${url}" MATCHES "^[a-z]+://")
+ # TODO: Should download and extraction be different steps?
+ if("x${fname}" STREQUAL "x")
+ set(fname "${url}")
+ endif()
+ if("${fname}" MATCHES [[([^/\?#]+(\.|=)(7z|tar|tar\.bz2|tar\.gz|tar\.xz|tbz2|tgz|txz|zip))([/?#].*)?$]])
+ set(fname "${CMAKE_MATCH_1}")
+ elseif(no_extract)
+ get_filename_component(fname "${fname}" NAME)
+ else()
+ # Fall back to a default file name. The actual file name does not
+ # matter because it is used only internally and our extraction tool
+ # inspects the file content directly. If it turns out the wrong URL
+ # was given that will be revealed during the build which is an easier
+ # place for users to diagnose than an error here anyway.
+ set(fname "archive.tar")
+ endif()
+ string(REPLACE ";" "-" fname "${fname}")
+ set(file ${download_dir}/${fname})
+ get_property(timeout TARGET ${name} PROPERTY _EP_TIMEOUT)
+ get_property(inactivity_timeout TARGET ${name} PROPERTY _EP_INACTIVITY_TIMEOUT)
+ get_property(no_progress TARGET ${name} PROPERTY _EP_DOWNLOAD_NO_PROGRESS)
+ get_property(tls_verify TARGET ${name} PROPERTY _EP_TLS_VERIFY)
+ get_property(tls_cainfo TARGET ${name} PROPERTY _EP_TLS_CAINFO)
+ get_property(netrc TARGET ${name} PROPERTY _EP_NETRC)
+ get_property(netrc_file TARGET ${name} PROPERTY _EP_NETRC_FILE)
+ get_property(http_username TARGET ${name} PROPERTY _EP_HTTP_USERNAME)
+ get_property(http_password TARGET ${name} PROPERTY _EP_HTTP_PASSWORD)
+ get_property(http_headers TARGET ${name} PROPERTY _EP_HTTP_HEADER)
+ set(download_script "${stamp_dir}/download-${name}.cmake")
+ _ep_write_downloadfile_script("${download_script}" "${url}" "${file}" "${timeout}" "${inactivity_timeout}" "${no_progress}" "${hash}" "${tls_verify}" "${tls_cainfo}" "${http_username}:${http_password}" "${http_headers}" "${netrc}" "${netrc_file}")
+ set(cmd ${CMAKE_COMMAND} -P "${download_script}"
+ COMMAND)
+ if (no_extract)
+ set(steps "download and verify")
+ else ()
+ set(steps "download, verify and extract")
+ endif ()
+ set(comment "Performing download step (${steps}) for '${name}'")
+ file(WRITE "${stamp_dir}/verify-${name}.cmake" "") # already verified by 'download_script'
+ else()
+ set(file "${url}")
+ if (no_extract)
+ set(steps "verify")
+ else ()
+ set(steps "verify and extract")
+ endif ()
+ set(comment "Performing download step (${steps}) for '${name}'")
+ _ep_write_verifyfile_script("${stamp_dir}/verify-${name}.cmake" "${file}" "${hash}")
+ endif()
+ list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/verify-${name}.cmake)
+ if (NOT no_extract)
+ _ep_write_extractfile_script("${stamp_dir}/extract-${name}.cmake" "${name}" "${file}" "${source_dir}")
+ list(APPEND cmd COMMAND ${CMAKE_COMMAND} -P ${stamp_dir}/extract-${name}.cmake)
+ else ()
+ set_property(TARGET ${name} PROPERTY _EP_DOWNLOADED_FILE ${file})
+ endif ()
+ endif()
+ else()
+ _ep_is_dir_empty("${source_dir}" empty)
+ if(${empty})
+ message(SEND_ERROR
+ "No download info given for '${name}' and its source directory:\n"
+ " ${source_dir}\n"
+ "is not an existing non-empty directory. Please specify one of:\n"
+ " * SOURCE_DIR with an existing non-empty directory\n"
+ " * DOWNLOAD_COMMAND\n"
+ " * URL\n"
+ " * GIT_REPOSITORY\n"
+ " * SVN_REPOSITORY\n"
+ " * HG_REPOSITORY\n"
+ " * CVS_REPOSITORY and CVS_MODULE"
+ )
+ endif()
+ endif()
+
+ get_property(log TARGET ${name} PROPERTY _EP_LOG_DOWNLOAD)
+ if(log)
+ set(log LOG 1)
+ else()
+ set(log "")
+ endif()
+
+ get_property(uses_terminal TARGET ${name} PROPERTY
+ _EP_USES_TERMINAL_DOWNLOAD)
+ if(uses_terminal)
+ set(uses_terminal USES_TERMINAL 1)
+ else()
+ set(uses_terminal "")
+ endif()
+
+ set(__cmdQuoted)
+ foreach(__item IN LISTS cmd)
+ string(APPEND __cmdQuoted " [==[${__item}]==]")
+ endforeach()
+ cmake_language(EVAL CODE "
+ ExternalProject_Add_Step(\${name} download
+ INDEPENDENT TRUE
+ COMMENT \${comment}
+ COMMAND ${__cmdQuoted}
+ WORKING_DIRECTORY \${work_dir}
+ DEPENDS \${depends}
+ DEPENDEES mkdir
+ ${log}
+ ${uses_terminal}
+ )"
+ )
+endfunction()
+
+function(_ep_get_update_disconnected var name)
+ get_property(update_disconnected_set TARGET ${name} PROPERTY _EP_UPDATE_DISCONNECTED SET)
+ if(update_disconnected_set)
+ get_property(update_disconnected TARGET ${name} PROPERTY _EP_UPDATE_DISCONNECTED)
+ else()
+ get_property(update_disconnected DIRECTORY PROPERTY EP_UPDATE_DISCONNECTED)
+ endif()
+ set(${var} "${update_disconnected}" PARENT_SCOPE)
+endfunction()
+
+function(_ep_add_update_command name)
+ ExternalProject_Get_Property(${name} source_dir tmp_dir)
+
+ get_property(cmd_set TARGET ${name} PROPERTY _EP_UPDATE_COMMAND SET)
+ get_property(cmd TARGET ${name} PROPERTY _EP_UPDATE_COMMAND)
+ get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
+ get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
+ get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
+ get_property(hg_repository TARGET ${name} PROPERTY _EP_HG_REPOSITORY )
+
+ _ep_get_update_disconnected(update_disconnected ${name})
+
+ set(work_dir)
+ set(comment)
+ set(always)
+
+ if(cmd_set)
+ set(work_dir ${source_dir})
+ if(NOT "x${cmd}" STREQUAL "x")
+ set(always 1)
+ endif()
+ elseif(cvs_repository)
+ if(NOT CVS_EXECUTABLE)
+ message(FATAL_ERROR "error: could not find cvs for update of ${name}")
+ endif()
+ set(work_dir ${source_dir})
+ set(comment "Performing update step (CVS update) for '${name}'")
+ get_property(cvs_tag TARGET ${name} PROPERTY _EP_CVS_TAG)
+ set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q up -dP ${cvs_tag})
+ set(always 1)
+ elseif(svn_repository)
+ if(NOT Subversion_SVN_EXECUTABLE)
+ message(FATAL_ERROR "error: could not find svn for update of ${name}")
+ endif()
+ set(work_dir ${source_dir})
+ set(comment "Performing update step (SVN update) for '${name}'")
+ get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
+ get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
+ get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
+ get_property(svn_trust_cert TARGET ${name} PROPERTY _EP_SVN_TRUST_CERT)
+ set(svn_user_pw_args "")
+ if(DEFINED svn_username)
+ set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}")
+ endif()
+ if(DEFINED svn_password)
+ set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}")
+ endif()
+ if(svn_trust_cert)
+ set(svn_trust_cert_args --trust-server-cert)
+ endif()
+ set(cmd ${Subversion_SVN_EXECUTABLE} up ${svn_revision}
+ --non-interactive ${svn_trust_cert_args} ${svn_user_pw_args})
+ set(always 1)
+ elseif(git_repository)
+ # FetchContent gives us these directly, so don't try to recompute them
+ if(NOT GIT_EXECUTABLE OR NOT GIT_VERSION_STRING)
+ unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
+ find_package(Git QUIET)
+ if(NOT GIT_EXECUTABLE)
+ message(FATAL_ERROR "error: could not find git for fetch of ${name}")
+ endif()
+ endif()
+ set(work_dir ${source_dir})
+ set(comment "Performing update step for '${name}'")
+ get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
+ if(NOT git_tag)
+ set(git_tag "master")
+ endif()
+ get_property(git_remote_name TARGET ${name} PROPERTY _EP_GIT_REMOTE_NAME)
+ if(NOT git_remote_name)
+ set(git_remote_name "origin")
+ endif()
+
+ set(git_init_submodules TRUE)
+ get_property(git_submodules_set TARGET ${name} PROPERTY _EP_GIT_SUBMODULES SET)
+ if(git_submodules_set)
+ get_property(git_submodules TARGET ${name} PROPERTY _EP_GIT_SUBMODULES)
+ if(git_submodules STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW")
+ set(git_init_submodules FALSE)
+ endif()
+ endif()
+
+ get_property(git_update_strategy TARGET ${name} PROPERTY _EP_GIT_REMOTE_UPDATE_STRATEGY)
+ if(NOT git_update_strategy)
+ set(git_update_strategy "${CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY}")
+ endif()
+ if(NOT git_update_strategy)
+ set(git_update_strategy REBASE)
+ endif()
+ set(strategies CHECKOUT REBASE REBASE_CHECKOUT)
+ if(NOT git_update_strategy IN_LIST strategies)
+ message(FATAL_ERROR "'${git_update_strategy}' is not one of the supported strategies: ${strategies}")
+ endif()
+
+ _ep_get_git_submodules_recurse(git_submodules_recurse)
+
+ _ep_write_gitupdate_script(${tmp_dir}/${name}-gitupdate.cmake
+ ${GIT_EXECUTABLE} ${git_tag} ${git_remote_name} ${git_init_submodules} "${git_submodules_recurse}" "${git_submodules}" ${git_repository} ${work_dir} ${git_update_strategy}
+ )
+ set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitupdate.cmake)
+ set(always 1)
+ elseif(hg_repository)
+ if(NOT HG_EXECUTABLE)
+ message(FATAL_ERROR "error: could not find hg for pull of ${name}")
+ endif()
+ set(work_dir ${source_dir})
+ set(comment "Performing update step (hg pull) for '${name}'")
+ get_property(hg_tag TARGET ${name} PROPERTY _EP_HG_TAG)
+ if(NOT hg_tag)
+ set(hg_tag "tip")
+ endif()
+ if("${HG_VERSION_STRING}" STREQUAL "2.1")
+ message(WARNING "Mercurial 2.1 does not distinguish an empty pull from a failed pull:
+ http://mercurial.selenic.com/wiki/UpgradeNotes#A2.1.1:_revert_pull_return_code_change.2C_compile_issue_on_OS_X
+ http://thread.gmane.org/gmane.comp.version-control.mercurial.devel/47656
+Update to Mercurial >= 2.1.1.
+")
+ endif()
+ set(cmd ${HG_EXECUTABLE} pull
+ COMMAND ${HG_EXECUTABLE} update ${hg_tag}
+ )
+ set(always 1)
+ endif()
+
+ get_property(log TARGET ${name} PROPERTY _EP_LOG_UPDATE)
+ if(log)
+ set(log LOG 1)
+ else()
+ set(log "")
+ endif()
+
+ get_property(uses_terminal TARGET ${name} PROPERTY
+ _EP_USES_TERMINAL_UPDATE)
+ if(uses_terminal)
+ set(uses_terminal USES_TERMINAL 1)
+ else()
+ set(uses_terminal "")
+ endif()
+
+ set(__cmdQuoted)
+ foreach(__item IN LISTS cmd)
+ string(APPEND __cmdQuoted " [==[${__item}]==]")
+ endforeach()
+ cmake_language(EVAL CODE "
+ ExternalProject_Add_Step(${name} update
+ INDEPENDENT TRUE
+ COMMENT \${comment}
+ COMMAND ${__cmdQuoted}
+ ALWAYS \${always}
+ EXCLUDE_FROM_MAIN \${update_disconnected}
+ WORKING_DIRECTORY \${work_dir}
+ DEPENDEES download
+ ${log}
+ ${uses_terminal}
+ )"
+ )
+
+endfunction()
+
+
+function(_ep_add_patch_command name)
+ ExternalProject_Get_Property(${name} source_dir)
+
+ get_property(cmd_set TARGET ${name} PROPERTY _EP_PATCH_COMMAND SET)
+ get_property(cmd TARGET ${name} PROPERTY _EP_PATCH_COMMAND)
+
+ set(work_dir)
+
+ if(cmd_set)
+ set(work_dir ${source_dir})
+ endif()
+
+ get_property(log TARGET ${name} PROPERTY _EP_LOG_PATCH)
+ if(log)
+ set(log LOG 1)
+ else()
+ set(log "")
+ endif()
+
+ _ep_get_update_disconnected(update_disconnected ${name})
+ if(update_disconnected)
+ set(patch_dep download)
+ else()
+ set(patch_dep update)
+ endif()
+
+ set(__cmdQuoted)
+ foreach(__item IN LISTS cmd)
+ string(APPEND __cmdQuoted " [==[${__item}]==]")
+ endforeach()
+ cmake_language(EVAL CODE "
+ ExternalProject_Add_Step(${name} patch
+ INDEPENDENT TRUE
+ COMMAND ${__cmdQuoted}
+ WORKING_DIRECTORY \${work_dir}
+ DEPENDEES \${patch_dep}
+ ${log}
+ )"
+ )
+endfunction()
+
+function(_ep_get_file_deps var name)
+ set(file_deps)
+
+ get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
+ foreach(dep IN LISTS deps)
+ get_property(dep_type TARGET ${dep} PROPERTY TYPE)
+ if(dep_type STREQUAL "UTILITY")
+ get_property(is_ep TARGET ${dep} PROPERTY _EP_IS_EXTERNAL_PROJECT)
+ if(is_ep)
+ _ep_get_step_stampfile(${dep} "done" done_stamp_file)
+ list(APPEND file_deps ${done_stamp_file})
+ endif()
+ endif()
+ endforeach()
+
+ set("${var}" "${file_deps}" PARENT_SCOPE)
+endfunction()
+
+function(_ep_extract_configure_command var name)
+ get_property(cmd_set TARGET ${name} PROPERTY _EP_CONFIGURE_COMMAND SET)
+ if(cmd_set)
+ get_property(cmd TARGET ${name} PROPERTY _EP_CONFIGURE_COMMAND)
+ else()
+ get_target_property(cmake_command ${name} _EP_CMAKE_COMMAND)
+ if(cmake_command)
+ set(cmd "${cmake_command}")
+ else()
+ set(cmd "${CMAKE_COMMAND}")
+ endif()
+
+ get_property(cmake_args TARGET ${name} PROPERTY _EP_CMAKE_ARGS)
+ list(APPEND cmd ${cmake_args})
+
+ # If there are any CMAKE_CACHE_ARGS or CMAKE_CACHE_DEFAULT_ARGS,
+ # write an initial cache and use it
+ get_property(cmake_cache_args TARGET ${name} PROPERTY _EP_CMAKE_CACHE_ARGS)
+ get_property(cmake_cache_default_args TARGET ${name} PROPERTY _EP_CMAKE_CACHE_DEFAULT_ARGS)
+
+ set(has_cmake_cache_args 0)
+ if(NOT "${cmake_cache_args}" STREQUAL "")
+ set(has_cmake_cache_args 1)
+ endif()
+
+ set(has_cmake_cache_default_args 0)
+ if(NOT "${cmake_cache_default_args}" STREQUAL "")
+ set(has_cmake_cache_default_args 1)
+ endif()
+
+ get_target_property(cmake_generator ${name} _EP_CMAKE_GENERATOR)
+ get_target_property(cmake_generator_instance ${name} _EP_CMAKE_GENERATOR_INSTANCE)
+ get_target_property(cmake_generator_platform ${name} _EP_CMAKE_GENERATOR_PLATFORM)
+ get_target_property(cmake_generator_toolset ${name} _EP_CMAKE_GENERATOR_TOOLSET)
+ if(cmake_generator)
+ list(APPEND cmd "-G${cmake_generator}")
+ if(cmake_generator_platform)
+ list(APPEND cmd "-A${cmake_generator_platform}")
+ endif()
+ if(cmake_generator_toolset)
+ list(APPEND cmd "-T${cmake_generator_toolset}")
+ endif()
+ if(cmake_generator_instance)
+ list(APPEND cmd "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${cmake_generator_instance}")
+ endif()
+ else()
+ if(CMAKE_EXTRA_GENERATOR)
+ list(APPEND cmd "-G${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}")
+ else()
+ list(APPEND cmd "-G${CMAKE_GENERATOR}")
+ if("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
+ set(has_cmake_cache_default_args 1)
+ set(cmake_cache_default_args ${cmake_cache_default_args}
+ "-DGHS_TARGET_PLATFORM:STRING=${GHS_TARGET_PLATFORM}"
+ "-DGHS_PRIMARY_TARGET:STRING=${GHS_PRIMARY_TARGET}"
+ "-DGHS_TOOLSET_ROOT:STRING=${GHS_TOOLSET_ROOT}"
+ "-DGHS_OS_ROOT:STRING=${GHS_OS_ROOT}"
+ "-DGHS_OS_DIR:STRING=${GHS_OS_DIR}"
+ "-DGHS_BSP_NAME:STRING=${GHS_BSP_NAME}")
+ endif()
+ endif()
+ if(cmake_generator_platform)
+ message(FATAL_ERROR "Option CMAKE_GENERATOR_PLATFORM not allowed without CMAKE_GENERATOR.")
+ endif()
+ if(CMAKE_GENERATOR_PLATFORM)
+ list(APPEND cmd "-A${CMAKE_GENERATOR_PLATFORM}")
+ endif()
+ if(cmake_generator_toolset)
+ message(FATAL_ERROR "Option CMAKE_GENERATOR_TOOLSET not allowed without CMAKE_GENERATOR.")
+ endif()
+ if(CMAKE_GENERATOR_TOOLSET)
+ list(APPEND cmd "-T${CMAKE_GENERATOR_TOOLSET}")
+ endif()
+ if(cmake_generator_instance)
+ message(FATAL_ERROR "Option CMAKE_GENERATOR_INSTANCE not allowed without CMAKE_GENERATOR.")
+ endif()
+ if(CMAKE_GENERATOR_INSTANCE)
+ list(APPEND cmd "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${CMAKE_GENERATOR_INSTANCE}")
+ endif()
+ endif()
+
+ if(has_cmake_cache_args OR has_cmake_cache_default_args)
+ set(_ep_cache_args_script "<TMP_DIR>/${name}-cache-$<CONFIG>.cmake")
+ if(has_cmake_cache_args)
+ _ep_command_line_to_initial_cache(script_initial_cache_force "${cmake_cache_args}" 1)
+ endif()
+ if(has_cmake_cache_default_args)
+ _ep_command_line_to_initial_cache(script_initial_cache_default "${cmake_cache_default_args}" 0)
+ endif()
+ _ep_write_initial_cache(${name} "${_ep_cache_args_script}" "${script_initial_cache_force}${script_initial_cache_default}")
+ list(APPEND cmd "-C${_ep_cache_args_script}")
+ _ep_replace_location_tags(${name} _ep_cache_args_script)
+ set(_ep_cache_args_script
+ "${_ep_cache_args_script}"
+ PARENT_SCOPE)
+ endif()
+
+ list(APPEND cmd "<SOURCE_DIR><SOURCE_SUBDIR>")
+ endif()
+
+ set("${var}" "${cmd}" PARENT_SCOPE)
+endfunction()
+
+# TODO: Make sure external projects use the proper compiler
+function(_ep_add_configure_command name)
+ ExternalProject_Get_Property(${name} binary_dir tmp_dir)
+
+ set(file_deps)
+ get_property(configure_handled_by_build TARGET ${name}
+ PROPERTY _EP_CONFIGURE_HANDLED_BY_BUILD)
+ if(NOT configure_handled_by_build)
+ # Depend on other external projects (file-level)
+ _ep_get_file_deps(file_deps ${name})
+ endif()
+
+ _ep_extract_configure_command(cmd ${name})
+
+ # If anything about the configure command changes, (command itself, cmake
+ # used, cmake args or cmake generator) then re-run the configure step.
+ # Fixes issue https://gitlab.kitware.com/cmake/cmake/-/issues/10258
+ #
+ if(NOT EXISTS ${tmp_dir}/${name}-cfgcmd.txt.in)
+ file(WRITE ${tmp_dir}/${name}-cfgcmd.txt.in "cmd='\@cmd\@'\n")
+ endif()
+ configure_file(${tmp_dir}/${name}-cfgcmd.txt.in ${tmp_dir}/${name}-cfgcmd.txt)
+ list(APPEND file_deps ${tmp_dir}/${name}-cfgcmd.txt)
+ list(APPEND file_deps ${_ep_cache_args_script})
+
+ get_property(log TARGET ${name} PROPERTY _EP_LOG_CONFIGURE)
+ if(log)
+ set(log LOG 1)
+ else()
+ set(log "")
+ endif()
+
+ get_property(uses_terminal TARGET ${name} PROPERTY
+ _EP_USES_TERMINAL_CONFIGURE)
+ if(uses_terminal)
+ set(uses_terminal USES_TERMINAL 1)
+ else()
+ set(uses_terminal "")
+ endif()
+
+ set(__cmdQuoted)
+ foreach(__item IN LISTS cmd)
+ string(APPEND __cmdQuoted " [==[${__item}]==]")
+ endforeach()
+ cmake_language(EVAL CODE "
+ ExternalProject_Add_Step(${name} configure
+ INDEPENDENT FALSE
+ COMMAND ${__cmdQuoted}
+ WORKING_DIRECTORY \${binary_dir}
+ DEPENDEES patch
+ DEPENDS \${file_deps}
+ ${log}
+ ${uses_terminal}
+ )"
+ )
+endfunction()
+
+
+function(_ep_add_build_command name)
+ ExternalProject_Get_Property(${name} binary_dir)
+
+ set(file_deps)
+ get_property(configure_handled_by_build TARGET ${name}
+ PROPERTY _EP_CONFIGURE_HANDLED_BY_BUILD)
+ if(configure_handled_by_build)
+ # Depend on other external projects (file-level)
+ _ep_get_file_deps(file_deps ${name})
+ endif()
+
+ get_property(cmd_set TARGET ${name} PROPERTY _EP_BUILD_COMMAND SET)
+ if(cmd_set)
+ get_property(cmd TARGET ${name} PROPERTY _EP_BUILD_COMMAND)
+ else()
+ _ep_get_build_command(${name} BUILD cmd)
+ endif()
+
+ get_property(log TARGET ${name} PROPERTY _EP_LOG_BUILD)
+ if(log)
+ set(log LOG 1)
+ else()
+ set(log "")
+ endif()
+
+ get_property(uses_terminal TARGET ${name} PROPERTY
+ _EP_USES_TERMINAL_BUILD)
+ if(uses_terminal)
+ set(uses_terminal USES_TERMINAL 1)
+ else()
+ set(uses_terminal "")
+ endif()
+
+ get_property(build_always TARGET ${name} PROPERTY _EP_BUILD_ALWAYS)
+ if(build_always)
+ set(always 1)
+ else()
+ set(always 0)
+ endif()
+
+ get_property(build_byproducts TARGET ${name} PROPERTY _EP_BUILD_BYPRODUCTS)
+
+ set(__cmdQuoted)
+ foreach(__item IN LISTS cmd)
+ string(APPEND __cmdQuoted " [==[${__item}]==]")
+ endforeach()
+ cmake_language(EVAL CODE "
+ ExternalProject_Add_Step(${name} build
+ INDEPENDENT FALSE
+ COMMAND ${__cmdQuoted}
+ BYPRODUCTS \${build_byproducts}
+ WORKING_DIRECTORY \${binary_dir}
+ DEPENDEES configure
+ DEPENDS \${file_deps}
+ ALWAYS \${always}
+ ${log}
+ ${uses_terminal}
+ )"
+ )
+endfunction()
+
+
+function(_ep_add_install_command name)
+ ExternalProject_Get_Property(${name} binary_dir)
+
+ get_property(cmd_set TARGET ${name} PROPERTY _EP_INSTALL_COMMAND SET)
+ if(cmd_set)
+ get_property(cmd TARGET ${name} PROPERTY _EP_INSTALL_COMMAND)
+ else()
+ _ep_get_build_command(${name} INSTALL cmd)
+ endif()
+
+ get_property(log TARGET ${name} PROPERTY _EP_LOG_INSTALL)
+ if(log)
+ set(log LOG 1)
+ else()
+ set(log "")
+ endif()
+
+ get_property(uses_terminal TARGET ${name} PROPERTY
+ _EP_USES_TERMINAL_INSTALL)
+ if(uses_terminal)
+ set(uses_terminal USES_TERMINAL 1)
+ else()
+ set(uses_terminal "")
+ endif()
+
+ set(__cmdQuoted)
+ foreach(__item IN LISTS cmd)
+ string(APPEND __cmdQuoted " [==[${__item}]==]")
+ endforeach()
+ cmake_language(EVAL CODE "
+ ExternalProject_Add_Step(${name} install
+ INDEPENDENT FALSE
+ COMMAND ${__cmdQuoted}
+ WORKING_DIRECTORY \${binary_dir}
+ DEPENDEES build
+ ${log}
+ ${uses_terminal}
+ )"
+ )
+endfunction()
+
+
+function(_ep_add_test_command name)
+ ExternalProject_Get_Property(${name} binary_dir)
+
+ get_property(before TARGET ${name} PROPERTY _EP_TEST_BEFORE_INSTALL)
+ get_property(after TARGET ${name} PROPERTY _EP_TEST_AFTER_INSTALL)
+ get_property(exclude TARGET ${name} PROPERTY _EP_TEST_EXCLUDE_FROM_MAIN)
+ get_property(cmd_set TARGET ${name} PROPERTY _EP_TEST_COMMAND SET)
+
+ # Only actually add the test step if one of the test related properties is
+ # explicitly set. (i.e. the test step is omitted unless requested...)
+ #
+ if(cmd_set OR before OR after OR exclude)
+ if(cmd_set)
+ get_property(cmd TARGET ${name} PROPERTY _EP_TEST_COMMAND)
+ else()
+ _ep_get_build_command(${name} TEST cmd)
+ endif()
+
+ if(before)
+ set(dependees_args DEPENDEES build)
+ else()
+ set(dependees_args DEPENDEES install)
+ endif()
+
+ if(exclude)
+ set(dependers_args "")
+ set(exclude_args EXCLUDE_FROM_MAIN 1)
+ else()
+ if(before)
+ set(dependers_args DEPENDERS install)
+ else()
+ set(dependers_args "")
+ endif()
+ set(exclude_args "")
+ endif()
+
+ get_property(log TARGET ${name} PROPERTY _EP_LOG_TEST)
+ if(log)
+ set(log LOG 1)
+ else()
+ set(log "")
+ endif()
+
+ get_property(uses_terminal TARGET ${name} PROPERTY
+ _EP_USES_TERMINAL_TEST)
+ if(uses_terminal)
+ set(uses_terminal USES_TERMINAL 1)
+ else()
+ set(uses_terminal "")
+ endif()
+
+ set(__cmdQuoted)
+ foreach(__item IN LISTS cmd)
+ string(APPEND __cmdQuoted " [==[${__item}]==]")
+ endforeach()
+ cmake_language(EVAL CODE "
+ ExternalProject_Add_Step(${name} test
+ INDEPENDENT FALSE
+ COMMAND ${__cmdQuoted}
+ WORKING_DIRECTORY \${binary_dir}
+ ${dependees_args}
+ ${dependers_args}
+ ${exclude_args}
+ ${log}
+ ${uses_terminal}
+ )"
+ )
+ endif()
+endfunction()
+
+
+function(ExternalProject_Add name)
+ cmake_policy(GET CMP0097 _EP_CMP0097
+ PARENT_SCOPE # undocumented, do not use outside of CMake
+ )
+ cmake_policy(GET CMP0114 cmp0114
+ PARENT_SCOPE # undocumented, do not use outside of CMake
+ )
+ if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12 AND NOT cmp0114 STREQUAL "NEW")
+ message(AUTHOR_WARNING
+ "Policy CMP0114 is not set to NEW. "
+ "In order to support the Xcode \"new build system\", "
+ "this project must be updated to set policy CMP0114 to NEW."
+ "\n"
+ "Since CMake is generating for the Xcode \"new build system\", "
+ "ExternalProject_Add will use policy CMP0114's NEW behavior anyway, "
+ "but the generated build system may not match what the project intends."
+ )
+ set(cmp0114 "NEW")
+ endif()
+
+ _ep_get_configuration_subdir_suffix(cfgdir)
+
+ # Add a custom target for the external project.
+ set(cmf_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
+ _ep_get_complete_stampfile(${name} complete_stamp_file)
+
+ cmake_policy(PUSH)
+ if(cmp0114 STREQUAL "NEW")
+ # To implement CMP0114 NEW behavior with Makefile generators,
+ # we need CMP0113 NEW behavior.
+ cmake_policy(SET CMP0113 NEW)
+ endif()
+ # The "ALL" option to add_custom_target just tells it to not set the
+ # EXCLUDE_FROM_ALL target property. Later, if the EXCLUDE_FROM_ALL
+ # argument was passed, we explicitly set it for the target.
+ add_custom_target(${name} ALL DEPENDS ${complete_stamp_file})
+ cmake_policy(POP)
+ set_property(TARGET ${name} PROPERTY _EP_IS_EXTERNAL_PROJECT 1)
+ set_property(TARGET ${name} PROPERTY LABELS ${name})
+ set_property(TARGET ${name} PROPERTY FOLDER "ExternalProjectTargets/${name}")
+
+ set_property(TARGET ${name} PROPERTY _EP_CMP0114 "${cmp0114}")
+
+ set(keywords
+ #
+ # Directory options
+ #
+ PREFIX
+ TMP_DIR
+ STAMP_DIR
+ LOG_DIR
+ DOWNLOAD_DIR
+ SOURCE_DIR
+ BINARY_DIR
+ INSTALL_DIR
+ #
+ # Download step options
+ #
+ DOWNLOAD_COMMAND
+ #
+ URL
+ URL_HASH
+ URL_MD5
+ DOWNLOAD_NAME
+ DOWNLOAD_NO_EXTRACT
+ DOWNLOAD_NO_PROGRESS
+ TIMEOUT
+ INACTIVITY_TIMEOUT
+ HTTP_USERNAME
+ HTTP_PASSWORD
+ HTTP_HEADER
+ TLS_VERIFY # Also used for git clone operations
+ TLS_CAINFO
+ NETRC
+ NETRC_FILE
+ #
+ GIT_REPOSITORY
+ GIT_TAG
+ GIT_REMOTE_NAME
+ GIT_SUBMODULES
+ GIT_SUBMODULES_RECURSE
+ GIT_SHALLOW
+ GIT_PROGRESS
+ GIT_CONFIG
+ GIT_REMOTE_UPDATE_STRATEGY
+ #
+ SVN_REPOSITORY
+ SVN_REVISION
+ SVN_USERNAME
+ SVN_PASSWORD
+ SVN_TRUST_CERT
+ #
+ HG_REPOSITORY
+ HG_TAG
+ #
+ CVS_REPOSITORY
+ CVS_MODULE
+ CVS_TAG
+ #
+ # Update step options
+ #
+ UPDATE_COMMAND
+ UPDATE_DISCONNECTED
+ #
+ # Patch step options
+ #
+ PATCH_COMMAND
+ #
+ # Configure step options
+ #
+ CONFIGURE_COMMAND
+ CMAKE_COMMAND
+ CMAKE_GENERATOR
+ CMAKE_GENERATOR_PLATFORM
+ CMAKE_GENERATOR_TOOLSET
+ CMAKE_GENERATOR_INSTANCE
+ CMAKE_ARGS
+ CMAKE_CACHE_ARGS
+ CMAKE_CACHE_DEFAULT_ARGS
+ SOURCE_SUBDIR
+ CONFIGURE_HANDLED_BY_BUILD
+ #
+ # Build step options
+ #
+ BUILD_COMMAND
+ BUILD_IN_SOURCE
+ BUILD_ALWAYS
+ BUILD_BYPRODUCTS
+ #
+ # Install step options
+ #
+ INSTALL_COMMAND
+ #
+ # Test step options
+ #
+ TEST_COMMAND
+ TEST_BEFORE_INSTALL
+ TEST_AFTER_INSTALL
+ TEST_EXCLUDE_FROM_MAIN
+ #
+ # Logging options
+ #
+ LOG_DOWNLOAD
+ LOG_UPDATE
+ LOG_PATCH
+ LOG_CONFIGURE
+ LOG_BUILD
+ LOG_INSTALL
+ LOG_TEST
+ LOG_MERGED_STDOUTERR
+ LOG_OUTPUT_ON_FAILURE
+ #
+ # Terminal access options
+ #
+ USES_TERMINAL_DOWNLOAD
+ USES_TERMINAL_UPDATE
+ USES_TERMINAL_CONFIGURE
+ USES_TERMINAL_BUILD
+ USES_TERMINAL_INSTALL
+ USES_TERMINAL_TEST
+ #
+ # Target options
+ #
+ DEPENDS
+ EXCLUDE_FROM_ALL
+ STEP_TARGETS
+ INDEPENDENT_STEP_TARGETS
+ #
+ # Miscellaneous options
+ #
+ LIST_SEPARATOR
+ )
+ _ep_parse_arguments(ExternalProject_Add "${keywords}" ${name} _EP_ "${ARGN}")
+ _ep_set_directories(${name})
+ _ep_get_step_stampfile(${name} "done" done_stamp_file)
+ _ep_get_step_stampfile(${name} "install" install_stamp_file)
+
+ # Set the EXCLUDE_FROM_ALL target property if required.
+ get_property(exclude_from_all TARGET ${name} PROPERTY _EP_EXCLUDE_FROM_ALL)
+ if(exclude_from_all)
+ set_property(TARGET ${name} PROPERTY EXCLUDE_FROM_ALL TRUE)
+ endif()
+
+ # The 'complete' step depends on all other steps and creates a
+ # 'done' mark. A dependent external project's 'configure' step
+ # depends on the 'done' mark so that it rebuilds when this project
+ # rebuilds. It is important that 'done' is not the output of any
+ # custom command so that CMake does not propagate build rules to
+ # other external project targets, which may cause problems during
+ # parallel builds. However, the Ninja generator needs to see the entire
+ # dependency graph, and can cope with custom commands belonging to
+ # multiple targets, so we add the 'done' mark as an output for Ninja only.
+ set(complete_outputs ${complete_stamp_file})
+ if(${CMAKE_GENERATOR} MATCHES "Ninja")
+ set(complete_outputs ${complete_outputs} ${done_stamp_file})
+ endif()
+
+ add_custom_command(
+ OUTPUT ${complete_outputs}
+ COMMENT "Completed '${name}'"
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${cmf_dir}${cfgdir}
+ COMMAND ${CMAKE_COMMAND} -E touch ${complete_stamp_file}
+ COMMAND ${CMAKE_COMMAND} -E touch ${done_stamp_file}
+ DEPENDS ${install_stamp_file}
+ VERBATIM
+ )
+
+
+ # Depend on other external projects (target-level).
+ get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
+ foreach(arg IN LISTS deps)
+ add_dependencies(${name} ${arg})
+ endforeach()
+
+ # Set up custom build steps based on the target properties.
+ # Each step depends on the previous one.
+ #
+ # The target depends on the output of the final step.
+ # (Already set up above in the DEPENDS of the add_custom_target command.)
+ #
+ _ep_add_mkdir_command(${name})
+ _ep_add_download_command(${name})
+ _ep_add_update_command(${name})
+ _ep_add_patch_command(${name})
+ _ep_add_configure_command(${name})
+ _ep_add_build_command(${name})
+ _ep_add_install_command(${name})
+
+ # Test is special in that it might depend on build, or it might depend
+ # on install.
+ #
+ _ep_add_test_command(${name})
+endfunction()
+
+cmake_policy(POP)
diff --git a/Modules/FLTKCompatibility.cmake b/Modules/FLTKCompatibility.cmake
new file mode 100644
index 0000000..e91531f
--- /dev/null
+++ b/Modules/FLTKCompatibility.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+include(CheckIncludeFile)
diff --git a/Modules/FeatureSummary.cmake b/Modules/FeatureSummary.cmake
new file mode 100644
index 0000000..77c66d1
--- /dev/null
+++ b/Modules/FeatureSummary.cmake
@@ -0,0 +1,749 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FeatureSummary
+--------------
+
+Functions for generating a summary of enabled/disabled features.
+
+These functions can be used to generate a summary of enabled and disabled
+packages and/or feature for a build tree such as::
+
+ -- The following OPTIONAL packages have been found:
+ LibXml2 (required version >= 2.4), XML processing lib, <http://xmlsoft.org>
+ * Enables HTML-import in MyWordProcessor
+ * Enables odt-export in MyWordProcessor
+ PNG, A PNG image library., <http://www.libpng.org/pub/png/>
+ * Enables saving screenshots
+ -- The following OPTIONAL packages have not been found:
+ Lua51, The Lua scripting language., <http://www.lua.org>
+ * Enables macros in MyWordProcessor
+ Foo, Foo provides cool stuff.
+
+Global Properties
+^^^^^^^^^^^^^^^^^
+
+.. variable:: FeatureSummary_PKG_TYPES
+
+The global property :variable:`FeatureSummary_PKG_TYPES` defines the type of
+packages used by `FeatureSummary`.
+
+The order in this list is important, the first package type in the list is the
+least important, the last is the most important. the of a package can only be
+changed to higher types.
+
+The default package types are , ``RUNTIME``, ``OPTIONAL``, ``RECOMMENDED`` and
+``REQUIRED``, and their importance is
+``RUNTIME < OPTIONAL < RECOMMENDED < REQUIRED``.
+
+
+.. variable:: FeatureSummary_REQUIRED_PKG_TYPES
+
+The global property :variable:`FeatureSummary_REQUIRED_PKG_TYPES` defines which
+package types are required.
+
+If one or more package in this categories has not been found, CMake will abort
+when calling :command:`feature_summary` with the
+'FATAL_ON_MISSING_REQUIRED_PACKAGES' option enabled.
+
+The default value for this global property is ``REQUIRED``.
+
+
+.. variable:: FeatureSummary_DEFAULT_PKG_TYPE
+
+The global property :variable:`FeatureSummary_DEFAULT_PKG_TYPE` defines which
+package type is the default one.
+When calling :command:`feature_summary`, if the user did not set the package type
+explicitly, the package will be assigned to this category.
+
+This value must be one of the types defined in the
+:variable:`FeatureSummary_PKG_TYPES` global property unless the package type
+is set for all the packages.
+
+The default value for this global property is ``OPTIONAL``.
+
+
+.. variable:: FeatureSummary_<TYPE>_DESCRIPTION
+
+.. versionadded:: 3.9
+
+The global property :variable:`FeatureSummary_<TYPE>_DESCRIPTION` can be defined
+for each type to replace the type name with the specified string whenever the
+package type is used in an output string.
+
+If not set, the string "``<TYPE>`` packages" is used.
+
+
+#]=======================================================================]
+
+get_property(_fsPkgTypeIsSet GLOBAL PROPERTY FeatureSummary_PKG_TYPES SET)
+if(NOT _fsPkgTypeIsSet)
+ set_property(GLOBAL PROPERTY FeatureSummary_PKG_TYPES RUNTIME OPTIONAL RECOMMENDED REQUIRED)
+endif()
+
+get_property(_fsReqPkgTypesIsSet GLOBAL PROPERTY FeatureSummary_REQUIRED_PKG_TYPES SET)
+if(NOT _fsReqPkgTypesIsSet)
+ set_property(GLOBAL PROPERTY FeatureSummary_REQUIRED_PKG_TYPES REQUIRED)
+endif()
+
+get_property(_fsDefaultPkgTypeIsSet GLOBAL PROPERTY FeatureSummary_DEFAULT_PKG_TYPE SET)
+if(NOT _fsDefaultPkgTypeIsSet)
+ set_property(GLOBAL PROPERTY FeatureSummary_DEFAULT_PKG_TYPE OPTIONAL)
+endif()
+
+#[=======================================================================[.rst:
+
+Functions
+^^^^^^^^^
+
+#]=======================================================================]
+
+function(_FS_GET_FEATURE_SUMMARY _property _var _includeQuiet)
+
+ get_property(_fsPkgTypes GLOBAL PROPERTY FeatureSummary_PKG_TYPES)
+ get_property(_fsDefaultPkgType GLOBAL PROPERTY FeatureSummary_DEFAULT_PKG_TYPE)
+
+ set(_type "ANY")
+ foreach(_fsPkgType ${_fsPkgTypes})
+ if("${_property}" MATCHES "${_fsPkgType}_PACKAGES_(NOT_)?FOUND")
+ set(_type "${_fsPkgType}")
+ break()
+ endif()
+ endforeach()
+
+ if("${_property}" MATCHES "PACKAGES_FOUND")
+ set(_property "PACKAGES_FOUND")
+ elseif("${_property}" MATCHES "PACKAGES_NOT_FOUND")
+ set(_property "PACKAGES_NOT_FOUND")
+ endif()
+
+
+ set(_currentFeatureText "")
+ get_property(_EnabledFeatures GLOBAL PROPERTY ${_property})
+ if(_EnabledFeatures)
+ list(REMOVE_DUPLICATES _EnabledFeatures)
+ endif(_EnabledFeatures)
+
+ foreach(_currentFeature ${_EnabledFeatures})
+
+ # does this package belong to the type we currently want to list ?
+ get_property(_currentType GLOBAL PROPERTY _CMAKE_${_currentFeature}_TYPE)
+ if(NOT _currentType)
+ list(FIND _fsPkgTypes "${_fsDefaultPkgType}" _defaultInPkgTypes)
+ if("${_defaultInPkgTypes}" STREQUAL "-1")
+ string(REGEX REPLACE ";([^;]+)$" " and \\1" _fsPkgTypes_msg "${_fsPkgTypes}")
+ string(REPLACE ";" ", " _fsPkgTypes_msg "${_fsPkgTypes_msg}")
+ message(FATAL_ERROR "Bad package property type ${_fsDefaultPkgType} used in global property FeatureSummary_DEFAULT_PKG_TYPE. "
+ "Valid types are ${_fsPkgTypes_msg}. "
+ "Either update FeatureSummary_DEFAULT_PKG_TYPE or add ${_fsDefaultPkgType} to the FeatureSummary_PKG_TYPES global property.")
+ endif()
+ set(_currentType ${_fsDefaultPkgType})
+ endif()
+
+ if("${_type}" STREQUAL ANY OR "${_type}" STREQUAL "${_currentType}")
+ # check whether the current feature/package should be in the output depending on whether it was QUIET or not
+ set(includeThisOne TRUE)
+ set(_required FALSE)
+ # skip QUIET packages, except if they are REQUIRED or INCLUDE_QUIET_PACKAGES has been set
+ get_property(_fsReqPkgTypes GLOBAL PROPERTY FeatureSummary_REQUIRED_PKG_TYPES)
+ foreach(_fsReqPkgType ${_fsReqPkgTypes})
+ if("${_currentType}" STREQUAL "${_fsReqPkgType}")
+ set(_required TRUE)
+ break()
+ endif()
+ endforeach()
+ if(NOT _required AND NOT _includeQuiet)
+ get_property(_isQuiet GLOBAL PROPERTY _CMAKE_${_currentFeature}_QUIET)
+ if(_isQuiet)
+ set(includeThisOne FALSE)
+ endif()
+ endif()
+ get_property(_isTransitiveDepend
+ GLOBAL PROPERTY _CMAKE_${_currentFeature}_TRANSITIVE_DEPENDENCY
+ )
+ if(_isTransitiveDepend)
+ set(includeThisOne FALSE)
+ endif()
+
+ if(includeThisOne)
+
+ string(APPEND _currentFeatureText "\n * ${_currentFeature}")
+ get_property(_info GLOBAL PROPERTY _CMAKE_${_currentFeature}_REQUIRED_VERSION)
+ if(_info)
+ string(APPEND _currentFeatureText " (required version ${_info})")
+ endif()
+ get_property(_info GLOBAL PROPERTY _CMAKE_${_currentFeature}_DESCRIPTION)
+ if(_info)
+ string(APPEND _currentFeatureText ", ${_info}")
+ endif()
+ get_property(_info GLOBAL PROPERTY _CMAKE_${_currentFeature}_URL)
+ if(_info)
+ string(APPEND _currentFeatureText ", <${_info}>")
+ endif()
+
+ get_property(_info GLOBAL PROPERTY _CMAKE_${_currentFeature}_PURPOSE)
+ foreach(_purpose ${_info})
+ string(APPEND _currentFeatureText "\n ${_purpose}")
+ endforeach()
+
+ endif()
+
+ endif()
+
+ endforeach()
+ set(${_var} "${_currentFeatureText}" PARENT_SCOPE)
+endfunction()
+
+
+#[=======================================================================[.rst:
+.. command:: feature_summary
+
+ ::
+
+ feature_summary( [FILENAME <file>]
+ [APPEND]
+ [VAR <variable_name>]
+ [INCLUDE_QUIET_PACKAGES]
+ [FATAL_ON_MISSING_REQUIRED_PACKAGES]
+ [DESCRIPTION "<description>" | DEFAULT_DESCRIPTION]
+ [QUIET_ON_EMPTY]
+ WHAT (ALL
+ | PACKAGES_FOUND | PACKAGES_NOT_FOUND
+ | <TYPE>_PACKAGES_FOUND | <TYPE>_PACKAGES_NOT_FOUND
+ | ENABLED_FEATURES | DISABLED_FEATURES)
+ )
+
+ The ``feature_summary()`` macro can be used to print information about
+ enabled or disabled packages or features of a project. By default,
+ only the names of the features/packages will be printed and their
+ required version when one was specified. Use ``set_package_properties()``
+ to add more useful information, like e.g. a download URL for the
+ respective package or their purpose in the project.
+
+ The ``WHAT`` option is the only mandatory option. Here you specify what
+ information will be printed:
+
+ ``ALL``
+ print everything
+ ``ENABLED_FEATURES``
+ the list of all features which are enabled
+ ``DISABLED_FEATURES``
+ the list of all features which are disabled
+ ``PACKAGES_FOUND``
+ the list of all packages which have been found
+ ``PACKAGES_NOT_FOUND``
+ the list of all packages which have not been found
+
+ For each package type ``<TYPE>`` defined by the
+ :variable:`FeatureSummary_PKG_TYPES` global property, the following
+ information can also be used:
+
+ ``<TYPE>_PACKAGES_FOUND``
+ only those packages which have been found which have the type <TYPE>
+ ``<TYPE>_PACKAGES_NOT_FOUND``
+ only those packages which have not been found which have the type <TYPE>
+
+ .. versionchanged:: 3.1
+ With the exception of the ``ALL`` value, these values can be combined
+ in order to customize the output. For example:
+
+ .. code-block:: cmake
+
+ feature_summary(WHAT ENABLED_FEATURES DISABLED_FEATURES)
+
+ If a ``FILENAME`` is given, the information is printed into this file. If
+ ``APPEND`` is used, it is appended to this file, otherwise the file is
+ overwritten if it already existed. If the VAR option is used, the
+ information is "printed" into the specified variable. If ``FILENAME`` is
+ not used, the information is printed to the terminal. Using the
+ ``DESCRIPTION`` option a description or headline can be set which will be
+ printed above the actual content. If only one type of
+ package was requested, no title is printed, unless it is explicitly set using
+ either ``DESCRIPTION`` to use a custom string, or ``DEFAULT_DESCRIPTION`` to
+ use a default title for the requested type.
+ If ``INCLUDE_QUIET_PACKAGES`` is given, packages which have been searched with
+ ``find_package(... QUIET)`` will also be listed. By default they are skipped.
+ If ``FATAL_ON_MISSING_REQUIRED_PACKAGES`` is given, CMake will abort if a
+ package which is marked as one of the package types listed in the
+ :variable:`FeatureSummary_REQUIRED_PKG_TYPES` global property has not been
+ found.
+ The default value for the :variable:`FeatureSummary_REQUIRED_PKG_TYPES` global
+ property is ``REQUIRED``.
+
+ .. versionadded:: 3.9
+ The ``DEFAULT_DESCRIPTION`` option.
+
+ The :variable:`FeatureSummary_DEFAULT_PKG_TYPE` global property can be
+ modified to change the default package type assigned when not explicitly
+ assigned by the user.
+
+ .. versionadded:: 3.8
+ If the ``QUIET_ON_EMPTY`` option is used, if only one type of package was
+ requested, and no packages belonging to that category were found, then no
+ output (including the ``DESCRIPTION``) is printed or added to the ``VAR``
+ variable.
+
+ Example 1, append everything to a file:
+
+ .. code-block:: cmake
+
+ include(FeatureSummary)
+ feature_summary(WHAT ALL
+ FILENAME ${CMAKE_BINARY_DIR}/all.log APPEND)
+
+ Example 2, print the enabled features into the variable
+ enabledFeaturesText, including QUIET packages:
+
+ .. code-block:: cmake
+
+ include(FeatureSummary)
+ feature_summary(WHAT ENABLED_FEATURES
+ INCLUDE_QUIET_PACKAGES
+ DESCRIPTION "Enabled Features:"
+ VAR enabledFeaturesText)
+ message(STATUS "${enabledFeaturesText}")
+
+ Example 3, change default package types and print only the categories that
+ are not empty:
+
+ .. code-block:: cmake
+
+ include(FeatureSummary)
+ set_property(GLOBAL APPEND PROPERTY FeatureSummary_PKG_TYPES BUILD)
+ find_package(FOO)
+ set_package_properties(FOO PROPERTIES TYPE BUILD)
+ feature_summary(WHAT BUILD_PACKAGES_FOUND
+ Description "Build tools found:"
+ QUIET_ON_EMPTY)
+ feature_summary(WHAT BUILD_PACKAGES_NOT_FOUND
+ Description "Build tools not found:"
+ QUIET_ON_EMPTY)
+
+#]=======================================================================]
+
+function(FEATURE_SUMMARY)
+# CMAKE_PARSE_ARGUMENTS(<prefix> <options> <one_value_keywords> <multi_value_keywords> args...)
+ set(options APPEND
+ INCLUDE_QUIET_PACKAGES
+ FATAL_ON_MISSING_REQUIRED_PACKAGES
+ QUIET_ON_EMPTY
+ DEFAULT_DESCRIPTION)
+ set(oneValueArgs FILENAME
+ VAR
+ DESCRIPTION)
+ set(multiValueArgs WHAT)
+
+ CMAKE_PARSE_ARGUMENTS(_FS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN})
+
+ if(_FS_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to FEATURE_SUMMARY(): \"${_FS_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if(NOT _FS_WHAT)
+ message(FATAL_ERROR "The call to FEATURE_SUMMARY() doesn't set the required WHAT argument.")
+ endif()
+
+ if(_FS_DEFAULT_DESCRIPTION AND DEFINED _FS_DESCRIPTION)
+ message(WARNING "DEFAULT_DESCRIPTION option discarded since DESCRIPTION is set.")
+ set(_FS_DEFAULT_DESCRIPTION 0)
+ endif()
+
+ set(validWhatParts "ENABLED_FEATURES"
+ "DISABLED_FEATURES"
+ "PACKAGES_FOUND"
+ "PACKAGES_NOT_FOUND")
+
+ get_property(_fsPkgTypes GLOBAL PROPERTY FeatureSummary_PKG_TYPES)
+ get_property(_fsReqPkgTypes GLOBAL PROPERTY FeatureSummary_REQUIRED_PKG_TYPES)
+ foreach(_fsPkgType ${_fsPkgTypes})
+ list(APPEND validWhatParts "${_fsPkgType}_PACKAGES_FOUND"
+ "${_fsPkgType}_PACKAGES_NOT_FOUND")
+ endforeach()
+
+ set(title_ENABLED_FEATURES "The following features have been enabled:")
+ set(title_DISABLED_FEATURES "The following features have been disabled:")
+ set(title_PACKAGES_FOUND "The following packages have been found:")
+ set(title_PACKAGES_NOT_FOUND "The following packages have not been found:")
+ foreach(_fsPkgType ${_fsPkgTypes})
+ set(_fsPkgTypeDescription "${_fsPkgType} packages")
+ get_property(_fsPkgTypeDescriptionIsSet GLOBAL PROPERTY FeatureSummary_${_fsPkgType}_DESCRIPTION SET)
+ if(_fsPkgTypeDescriptionIsSet)
+ get_property(_fsPkgTypeDescription GLOBAL PROPERTY FeatureSummary_${_fsPkgType}_DESCRIPTION )
+ endif()
+ set(title_${_fsPkgType}_PACKAGES_FOUND "The following ${_fsPkgTypeDescription} have been found:")
+ set(title_${_fsPkgType}_PACKAGES_NOT_FOUND "The following ${_fsPkgTypeDescription} have not been found:")
+ endforeach()
+
+ list(FIND validWhatParts "${_FS_WHAT}" indexInList)
+ if(NOT "${indexInList}" STREQUAL "-1")
+ _FS_GET_FEATURE_SUMMARY( ${_FS_WHAT} _featureSummary ${_FS_INCLUDE_QUIET_PACKAGES} )
+ if(_featureSummary OR NOT _FS_QUIET_ON_EMPTY)
+ if(_FS_DEFAULT_DESCRIPTION)
+ set(_fullText "${title_${_FS_WHAT}}\n${_featureSummary}\n")
+ else()
+ set(_fullText "${_FS_DESCRIPTION}${_featureSummary}\n")
+ endif()
+ endif()
+
+ if(_featureSummary)
+ foreach(_fsReqPkgType ${_fsReqPkgTypes})
+ if("${_FS_WHAT}" STREQUAL "${_fsReqPkgType}_PACKAGES_NOT_FOUND")
+ set(requiredPackagesNotFound TRUE)
+ break()
+ endif()
+ endforeach()
+ endif()
+
+ else()
+ if("${_FS_WHAT}" STREQUAL "ALL")
+
+ set(allWhatParts "ENABLED_FEATURES")
+ foreach(_fsPkgType ${_fsPkgTypes})
+ list(APPEND allWhatParts "${_fsPkgType}_PACKAGES_FOUND")
+ endforeach()
+ list(APPEND allWhatParts "DISABLED_FEATURES")
+ foreach(_fsPkgType ${_fsPkgTypes})
+ list(APPEND allWhatParts "${_fsPkgType}_PACKAGES_NOT_FOUND")
+ endforeach()
+ else()
+ set(allWhatParts)
+ foreach(part ${_FS_WHAT})
+ list(FIND validWhatParts "${part}" indexInList)
+ if(NOT "${indexInList}" STREQUAL "-1")
+ list(APPEND allWhatParts "${part}")
+ else()
+ if("${part}" STREQUAL "ALL")
+ message(FATAL_ERROR "The WHAT argument of FEATURE_SUMMARY() contains ALL, which cannot be combined with other values.")
+ else()
+ message(FATAL_ERROR "The WHAT argument of FEATURE_SUMMARY() contains ${part}, which is not a valid value.")
+ endif()
+ endif()
+ endforeach()
+ endif()
+
+ set(_fullText "${_FS_DESCRIPTION}")
+ foreach(part ${allWhatParts})
+ set(_tmp)
+ _FS_GET_FEATURE_SUMMARY( ${part} _tmp ${_FS_INCLUDE_QUIET_PACKAGES})
+ if(_tmp)
+ if(_fullText)
+ string(APPEND _fullText "\n-- ")
+ endif()
+ string(APPEND _fullText "${title_${part}}\n${_tmp}\n")
+ foreach(_fsReqPkgType ${_fsReqPkgTypes})
+ if("${part}" STREQUAL "${_fsReqPkgType}_PACKAGES_NOT_FOUND")
+ set(requiredPackagesNotFound TRUE)
+ break()
+ endif()
+ endforeach()
+ endif()
+ endforeach()
+ endif()
+
+ if(_fullText OR NOT _FS_QUIET_ON_EMPTY)
+ if(_FS_FILENAME)
+ if(_FS_APPEND)
+ file(APPEND "${_FS_FILENAME}" "${_fullText}")
+ else()
+ file(WRITE "${_FS_FILENAME}" "${_fullText}")
+ endif()
+
+ else()
+ if(NOT _FS_VAR)
+ message(STATUS "${_fullText}")
+ endif()
+ endif()
+
+ if(_FS_VAR)
+ set(${_FS_VAR} "${_fullText}" PARENT_SCOPE)
+ endif()
+ endif()
+
+ if(requiredPackagesNotFound AND _FS_FATAL_ON_MISSING_REQUIRED_PACKAGES)
+ message(FATAL_ERROR "feature_summary() Error: REQUIRED package(s) are missing, aborting CMake run.")
+ endif()
+
+endfunction()
+
+#[=======================================================================[.rst:
+.. command:: set_package_properties
+
+ ::
+
+ set_package_properties(<name> PROPERTIES
+ [ URL <url> ]
+ [ DESCRIPTION <description> ]
+ [ TYPE (RUNTIME|OPTIONAL|RECOMMENDED|REQUIRED) ]
+ [ PURPOSE <purpose> ]
+ )
+
+ Use this macro to set up information about the named package, which
+ can then be displayed via FEATURE_SUMMARY(). This can be done either
+ directly in the Find-module or in the project which uses the module
+ after the find_package() call. The features for which information can
+ be set are added automatically by the find_package() command.
+
+ ``URL <url>``
+ This should be the homepage of the package, or something similar.
+ Ideally this is set already directly in the Find-module.
+
+ ``DESCRIPTION <description>``
+ A short description what that package is, at most one sentence.
+ Ideally this is set already directly in the Find-module.
+
+ ``TYPE <type>``
+ What type of dependency has the using project on that package.
+ Default is ``OPTIONAL``. In this case it is a package which can be used
+ by the project when available at buildtime, but it also work without.
+ ``RECOMMENDED`` is similar to ``OPTIONAL``, i.e. the project will build if
+ the package is not present, but the functionality of the resulting
+ binaries will be severely limited. If a ``REQUIRED`` package is not
+ available at buildtime, the project may not even build. This can be
+ combined with the ``FATAL_ON_MISSING_REQUIRED_PACKAGES`` argument for
+ ``feature_summary()``. Last, a ``RUNTIME`` package is a package which is
+ actually not used at all during the build, but which is required for
+ actually running the resulting binaries. So if such a package is
+ missing, the project can still be built, but it may not work later on.
+ If ``set_package_properties()`` is called multiple times for the same
+ package with different TYPEs, the ``TYPE`` is only changed to higher
+ TYPEs (``RUNTIME < OPTIONAL < RECOMMENDED < REQUIRED``), lower TYPEs are
+ ignored. The ``TYPE`` property is project-specific, so it cannot be set
+ by the Find-module, but must be set in the project.
+ Type accepted can be changed by setting the
+ :variable:`FeatureSummary_PKG_TYPES` global property.
+
+ ``PURPOSE <purpose>``
+ This describes which features this package enables in the
+ project, i.e. it tells the user what functionality he gets in the
+ resulting binaries. If set_package_properties() is called multiple
+ times for a package, all PURPOSE properties are appended to a list of
+ purposes of the package in the project. As the TYPE property, also
+ the PURPOSE property is project-specific, so it cannot be set by the
+ Find-module, but must be set in the project.
+
+ Example for setting the info for a package:
+
+ .. code-block:: cmake
+
+ find_package(LibXml2)
+ set_package_properties(LibXml2 PROPERTIES
+ DESCRIPTION "A XML processing library."
+ URL "http://xmlsoft.org/")
+ # or
+ set_package_properties(LibXml2 PROPERTIES
+ TYPE RECOMMENDED
+ PURPOSE "Enables HTML-import in MyWordProcessor")
+ # or
+ set_package_properties(LibXml2 PROPERTIES
+ TYPE OPTIONAL
+ PURPOSE "Enables odt-export in MyWordProcessor")
+
+ find_package(DBUS)
+ set_package_properties(DBUS PROPERTIES
+ TYPE RUNTIME
+ PURPOSE "Necessary to disable the screensaver during a presentation")
+#]=======================================================================]
+function(SET_PACKAGE_PROPERTIES _name _props)
+ if(NOT "${_props}" STREQUAL "PROPERTIES")
+ message(FATAL_ERROR "PROPERTIES keyword is missing in SET_PACKAGE_PROPERTIES() call.")
+ endif()
+
+ set(options ) # none
+ set(oneValueArgs DESCRIPTION URL TYPE PURPOSE )
+ set(multiValueArgs ) # none
+
+ CMAKE_PARSE_ARGUMENTS(_SPP "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(_SPP_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to SET_PACKAGE_PROPERTIES(): \"${_SPP_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if(_SPP_DESCRIPTION)
+ get_property(_info GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION)
+ if(_info AND NOT "${_info}" STREQUAL "${_SPP_DESCRIPTION}")
+ message(STATUS "Warning: Property DESCRIPTION for package ${_name} already set to \"${_info}\", overriding it with \"${_SPP_DESCRIPTION}\"")
+ endif()
+
+ set_property(GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION "${_SPP_DESCRIPTION}" )
+ endif()
+
+
+ if(_SPP_URL)
+ get_property(_info GLOBAL PROPERTY _CMAKE_${_name}_URL)
+ if(_info AND NOT "${_info}" STREQUAL "${_SPP_URL}")
+ message(STATUS "Warning: Property URL already set to \"${_info}\", overriding it with \"${_SPP_URL}\"")
+ endif()
+
+ set_property(GLOBAL PROPERTY _CMAKE_${_name}_URL "${_SPP_URL}" )
+ endif()
+
+
+ # handle the PURPOSE: use APPEND, since there can be multiple purposes for one package inside a project
+ if(_SPP_PURPOSE)
+ set_property(GLOBAL APPEND PROPERTY _CMAKE_${_name}_PURPOSE "${_SPP_PURPOSE}" )
+ endif()
+
+ get_property(_fsPkgTypes GLOBAL PROPERTY FeatureSummary_PKG_TYPES)
+ get_property(_fsDefaultPkgType GLOBAL PROPERTY FeatureSummary_DEFAULT_PKG_TYPE)
+
+ # handle the TYPE
+ if(DEFINED _SPP_TYPE)
+ # Supported types are listed in FeatureSummary_PKG_TYPES according to their priority
+ get_property(_fsPkgTypes GLOBAL PROPERTY FeatureSummary_PKG_TYPES)
+ list(FIND _fsPkgTypes ${_SPP_TYPE} _typeIndexInList)
+ if("${_typeIndexInList}" STREQUAL "-1" )
+ string(REGEX REPLACE ";([^;]+)$" " and \\1" _fsPkgTypes_msg "${_fsPkgTypes}")
+ string(REPLACE ";" ", " _fsPkgTypes_msg "${_fsPkgTypes_msg}")
+ message(FATAL_ERROR "Bad package property type ${_SPP_TYPE} used in SET_PACKAGE_PROPERTIES(). "
+ "Valid types are ${_fsPkgTypes_msg}." )
+ endif()
+
+ get_property(_previousType GLOBAL PROPERTY _CMAKE_${_name}_TYPE)
+ list(FIND _fsPkgTypes "${_previousType}" _prevTypeIndexInList)
+
+ # make sure a previously set TYPE is not overridden with a lower new TYPE:
+ if("${_typeIndexInList}" GREATER "${_prevTypeIndexInList}")
+ set_property(GLOBAL PROPERTY _CMAKE_${_name}_TYPE "${_SPP_TYPE}" )
+ endif()
+ endif()
+
+endfunction()
+
+#[=======================================================================[.rst:
+.. command:: add_feature_info
+
+ ::
+
+ add_feature_info(<name> <enabled> <description>)
+
+ Use this macro to add information about a feature with the given ``<name>``.
+ ``<enabled>`` contains whether this feature is enabled or not. It can be a
+ variable or a list of conditions.
+ ``<description>`` is a text describing the feature. The information can
+ be displayed using ``feature_summary()`` for ``ENABLED_FEATURES`` and
+ ``DISABLED_FEATURES`` respectively.
+
+ .. versionchanged:: 3.8
+ ``<enabled>`` can be a list of conditions.
+
+ Example for setting the info for a feature:
+
+ .. code-block:: cmake
+
+ option(WITH_FOO "Help for foo" ON)
+ add_feature_info(Foo WITH_FOO "The Foo feature provides very cool stuff.")
+#]=======================================================================]
+function(ADD_FEATURE_INFO _name _depends _desc)
+ set(_enabled 1)
+ foreach(_d ${_depends})
+ string(REGEX REPLACE " +" ";" _d "${_d}")
+ if(${_d})
+ else()
+ set(_enabled 0)
+ break()
+ endif()
+ endforeach()
+ if (${_enabled})
+ set_property(GLOBAL APPEND PROPERTY ENABLED_FEATURES "${_name}")
+ else ()
+ set_property(GLOBAL APPEND PROPERTY DISABLED_FEATURES "${_name}")
+ endif ()
+
+ set_property(GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION "${_desc}" )
+endfunction()
+
+
+# The stuff below is only kept for compatibility
+
+#[=======================================================================[.rst:
+Legacy Macros
+^^^^^^^^^^^^^
+
+The following macros are provided for compatibility with previous
+CMake versions:
+
+.. command:: set_package_info
+
+ ::
+
+ set_package_info(<name> <description> [ <url> [<purpose>] ])
+
+ Use this macro to set up information about the named package, which
+ can then be displayed via ``feature_summary()``. This can be done either
+ directly in the Find-module or in the project which uses the module
+ after the :command:`find_package` call. The features for which information
+ can be set are added automatically by the ``find_package()`` command.
+#]=======================================================================]
+function(SET_PACKAGE_INFO _name _desc)
+ message(DEPRECATION "SET_PACKAGE_INFO is deprecated. Use SET_PACKAGE_PROPERTIES instead.")
+ unset(_url)
+ unset(_purpose)
+ if(ARGC GREATER 2)
+ set(_url "${ARGV2}")
+ endif()
+ if(ARGC GREATER 3)
+ set(_purpose "${ARGV3}")
+ endif()
+ set_property(GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION "${_desc}" )
+ if(NOT _url STREQUAL "")
+ set_property(GLOBAL PROPERTY _CMAKE_${_name}_URL "${_url}" )
+ endif()
+ if(NOT _purpose STREQUAL "")
+ set_property(GLOBAL APPEND PROPERTY _CMAKE_${_name}_PURPOSE "${_purpose}" )
+ endif()
+endfunction()
+
+#[=======================================================================[.rst:
+.. command:: set_feature_info
+
+ ::
+
+ set_feature_info(<name> <description> [<url>])
+
+ Does the same as::
+
+ set_package_info(<name> <description> <url>)
+#]=======================================================================]
+function(SET_FEATURE_INFO)
+ message(DEPRECATION "SET_FEATURE_INFO is deprecated. Use ADD_FEATURE_INFO instead.")
+ SET_PACKAGE_INFO(${ARGN})
+endfunction()
+
+#[=======================================================================[.rst:
+.. command:: print_enabled_features
+
+ ::
+
+ print_enabled_features()
+
+ Does the same as
+
+ .. code-block:: cmake
+
+ feature_summary(WHAT ENABLED_FEATURES DESCRIPTION "Enabled features:")
+#]=======================================================================]
+function(PRINT_ENABLED_FEATURES)
+ message(DEPRECATION "PRINT_ENABLED_FEATURES is deprecated. Use
+ feature_summary(WHAT ENABLED_FEATURES DESCRIPTION \"Enabled features:\")")
+ FEATURE_SUMMARY(WHAT ENABLED_FEATURES DESCRIPTION "Enabled features:")
+endfunction()
+
+#[=======================================================================[.rst:
+.. command:: print_disabled_features
+
+ ::
+
+ print_disabled_features()
+
+ Does the same as
+
+ .. code-block:: cmake
+
+ feature_summary(WHAT DISABLED_FEATURES DESCRIPTION "Disabled features:")
+#]=======================================================================]
+function(PRINT_DISABLED_FEATURES)
+ message(DEPRECATION "PRINT_DISABLED_FEATURES is deprecated. Use
+ feature_summary(WHAT DISABLED_FEATURES DESCRIPTION \"Disabled features:\")")
+ FEATURE_SUMMARY(WHAT DISABLED_FEATURES DESCRIPTION "Disabled features:")
+endfunction()
diff --git a/Modules/FetchContent.cmake b/Modules/FetchContent.cmake
new file mode 100644
index 0000000..88f7ed6
--- /dev/null
+++ b/Modules/FetchContent.cmake
@@ -0,0 +1,1218 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FetchContent
+------------------
+
+.. versionadded:: 3.11
+
+.. only:: html
+
+ .. contents::
+
+Overview
+^^^^^^^^
+
+This module enables populating content at configure time via any method
+supported by the :module:`ExternalProject` module. Whereas
+:command:`ExternalProject_Add` downloads at build time, the
+``FetchContent`` module makes content available immediately, allowing the
+configure step to use the content in commands like :command:`add_subdirectory`,
+:command:`include` or :command:`file` operations.
+
+Content population details would normally be defined separately from the
+command that performs the actual population. This separation ensures that
+all of the dependency details are defined before anything may try to use those
+details to populate content. This is particularly important in more complex
+project hierarchies where dependencies may be shared between multiple projects.
+
+The following shows a typical example of declaring content details:
+
+.. code-block:: cmake
+
+ FetchContent_Declare(
+ googletest
+ GIT_REPOSITORY https://github.com/google/googletest.git
+ GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
+ )
+
+For most typical cases, populating the content can then be done with a single
+command like so:
+
+.. code-block:: cmake
+
+ FetchContent_MakeAvailable(googletest)
+
+The above command not only populates the content, it also adds it to the main
+build (if possible) so that the main build can use the populated project's
+targets, etc. In some cases, the main project may need to have more precise
+control over the population or may be required to explicitly define the
+population steps (e.g. if CMake versions earlier than 3.14 need to be
+supported). The typical pattern of such custom steps looks like this:
+
+.. code-block:: cmake
+
+ FetchContent_GetProperties(googletest)
+ if(NOT googletest_POPULATED)
+ FetchContent_Populate(googletest)
+ add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
+ endif()
+
+Regardless of which population method is used, when using the
+declare-populate pattern with a hierarchical project arrangement, projects at
+higher levels in the hierarchy are able to override the population details of
+content specified anywhere lower in the project hierarchy. The ability to
+detect whether content has already been populated ensures that even if
+multiple child projects want certain content to be available, the first one
+to populate it wins. The other child project can simply make use of the
+already available content instead of repeating the population for itself.
+See the :ref:`Examples <fetch-content-examples>` section which demonstrates
+this scenario.
+
+The ``FetchContent`` module also supports defining and populating
+content in a single call, with no check for whether the content has been
+populated elsewhere in the project already. This is a more low level
+operation and would not normally be the way the module is used, but it is
+sometimes useful as part of implementing some higher level feature or to
+populate some content in CMake's script mode.
+
+.. versionchanged:: 3.14
+ ``FetchContent`` commands can access the terminal. This is necessary
+ for password prompts and real-time progress displays to work.
+
+Commands
+^^^^^^^^
+
+Declaring Content Details
+"""""""""""""""""""""""""
+
+.. command:: FetchContent_Declare
+
+ .. code-block:: cmake
+
+ FetchContent_Declare(<name> <contentOptions>...)
+
+ The ``FetchContent_Declare()`` function records the options that describe
+ how to populate the specified content, but if such details have already
+ been recorded earlier in this project (regardless of where in the project
+ hierarchy), this and all later calls for the same content ``<name>`` are
+ ignored. This "first to record, wins" approach is what allows hierarchical
+ projects to have parent projects override content details of child projects.
+
+ The content ``<name>`` can be any string without spaces, but good practice
+ would be to use only letters, numbers and underscores. The name will be
+ treated case-insensitively and it should be obvious for the content it
+ represents, often being the name of the child project or the value given
+ to its top level :command:`project` command (if it is a CMake project).
+ For well-known public projects, the name should generally be the official
+ name of the project. Choosing an unusual name makes it unlikely that other
+ projects needing that same content will use the same name, leading to
+ the content being populated multiple times.
+
+ The ``<contentOptions>`` can be any of the download or update/patch options
+ that the :command:`ExternalProject_Add` command understands. The configure,
+ build, install and test steps are explicitly disabled and therefore options
+ related to them will be ignored. The ``SOURCE_SUBDIR`` option is an
+ exception, see :command:`FetchContent_MakeAvailable` for details on how that
+ affects behavior.
+
+ In most cases, ``<contentOptions>`` will just be a couple of options defining
+ the download method and method-specific details like a commit tag or archive
+ hash. For example:
+
+ .. code-block:: cmake
+
+ FetchContent_Declare(
+ googletest
+ GIT_REPOSITORY https://github.com/google/googletest.git
+ GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
+ )
+
+ FetchContent_Declare(
+ myCompanyIcons
+ URL https://intranet.mycompany.com/assets/iconset_1.12.tar.gz
+ URL_HASH MD5=5588a7b18261c20068beabfb4f530b87
+ )
+
+ FetchContent_Declare(
+ myCompanyCertificates
+ SVN_REPOSITORY svn+ssh://svn.mycompany.com/srv/svn/trunk/certs
+ SVN_REVISION -r12345
+ )
+
+ Where contents are being fetched from a remote location and you do not
+ control that server, it is advisable to use a hash for ``GIT_TAG`` rather
+ than a branch or tag name. A commit hash is more secure and helps to
+ confirm that the downloaded contents are what you expected.
+
+Populating The Content
+""""""""""""""""""""""
+
+For most common scenarios, population means making content available to the
+main build according to previously declared details for that dependency.
+There are two main patterns for populating content, one based on calling
+:command:`FetchContent_GetProperties` and
+:command:`FetchContent_Populate` for more precise control and the other on
+calling :command:`FetchContent_MakeAvailable` for a simpler, more automated
+approach. The former generally follows this canonical pattern:
+
+.. _`fetch-content-canonical-pattern`:
+
+.. code-block:: cmake
+
+ # Check if population has already been performed
+ FetchContent_GetProperties(<name>)
+ string(TOLOWER "<name>" lcName)
+ if(NOT ${lcName}_POPULATED)
+ # Fetch the content using previously declared details
+ FetchContent_Populate(<name>)
+
+ # Set custom variables, policies, etc.
+ # ...
+
+ # Bring the populated content into the build
+ add_subdirectory(${${lcName}_SOURCE_DIR} ${${lcName}_BINARY_DIR})
+ endif()
+
+The above is such a common pattern that, where no custom steps are needed
+between the calls to :command:`FetchContent_Populate` and
+:command:`add_subdirectory`, equivalent logic can be obtained by calling
+:command:`FetchContent_MakeAvailable` instead. Where it meets the needs of
+the project, :command:`FetchContent_MakeAvailable` should be preferred, as it
+is simpler and provides additional features over the pattern above.
+
+.. command:: FetchContent_Populate
+
+ .. code-block:: cmake
+
+ FetchContent_Populate( <name> )
+
+ In most cases, the only argument given to ``FetchContent_Populate()`` is the
+ ``<name>``. When used this way, the command assumes the content details have
+ been recorded by an earlier call to :command:`FetchContent_Declare`. The
+ details are stored in a global property, so they are unaffected by things
+ like variable or directory scope. Therefore, it doesn't matter where in the
+ project the details were previously declared, as long as they have been
+ declared before the call to ``FetchContent_Populate()``. Those saved details
+ are then used to construct a call to :command:`ExternalProject_Add` in a
+ private sub-build to perform the content population immediately. The
+ implementation of ``ExternalProject_Add()`` ensures that if the content has
+ already been populated in a previous CMake run, that content will be reused
+ rather than repopulating them again. For the common case where population
+ involves downloading content, the cost of the download is only paid once.
+
+ An internal global property records when a particular content population
+ request has been processed. If ``FetchContent_Populate()`` is called more
+ than once for the same content name within a configure run, the second call
+ will halt with an error. Projects can and should check whether content
+ population has already been processed with the
+ :command:`FetchContent_GetProperties` command before calling
+ ``FetchContent_Populate()``.
+
+ ``FetchContent_Populate()`` will set three variables in the scope of the
+ caller; ``<lcName>_POPULATED``, ``<lcName>_SOURCE_DIR`` and
+ ``<lcName>_BINARY_DIR``, where ``<lcName>`` is the lowercased ``<name>``.
+ ``<lcName>_POPULATED`` will always be set to ``True`` by the call.
+ ``<lcName>_SOURCE_DIR`` is the location where the
+ content can be found upon return (it will have already been populated), while
+ ``<lcName>_BINARY_DIR`` is a directory intended for use as a corresponding
+ build directory. The main use case for the two directory variables is to
+ call :command:`add_subdirectory` immediately after population, i.e.:
+
+ .. code-block:: cmake
+
+ FetchContent_Populate(FooBar ...)
+ add_subdirectory(${foobar_SOURCE_DIR} ${foobar_BINARY_DIR})
+
+ The values of the three variables can also be retrieved from anywhere in the
+ project hierarchy using the :command:`FetchContent_GetProperties` command.
+
+ A number of cache variables influence the behavior of all content population
+ performed using details saved from a :command:`FetchContent_Declare` call:
+
+ ``FETCHCONTENT_BASE_DIR``
+ In most cases, the saved details do not specify any options relating to the
+ directories to use for the internal sub-build, final source and build areas.
+ It is generally best to leave these decisions up to the ``FetchContent``
+ module to handle on the project's behalf. The ``FETCHCONTENT_BASE_DIR``
+ cache variable controls the point under which all content population
+ directories are collected, but in most cases developers would not need to
+ change this. The default location is ``${CMAKE_BINARY_DIR}/_deps``, but if
+ developers change this value, they should aim to keep the path short and
+ just below the top level of the build tree to avoid running into path
+ length problems on Windows.
+
+ ``FETCHCONTENT_QUIET``
+ The logging output during population can be quite verbose, making the
+ configure stage quite noisy. This cache option (``ON`` by default) hides
+ all population output unless an error is encountered. If experiencing
+ problems with hung downloads, temporarily switching this option off may
+ help diagnose which content population is causing the issue.
+
+ ``FETCHCONTENT_FULLY_DISCONNECTED``
+ When this option is enabled, no attempt is made to download or update
+ any content. It is assumed that all content has already been populated in
+ a previous run or the source directories have been pointed at existing
+ contents the developer has provided manually (using options described
+ further below). When the developer knows that no changes have been made to
+ any content details, turning this option ``ON`` can significantly speed up
+ the configure stage. It is ``OFF`` by default.
+
+ ``FETCHCONTENT_UPDATES_DISCONNECTED``
+ This is a less severe download/update control compared to
+ ``FETCHCONTENT_FULLY_DISCONNECTED``. Instead of bypassing all download and
+ update logic, the ``FETCHCONTENT_UPDATES_DISCONNECTED`` only disables the
+ update stage. Therefore, if content has not been downloaded previously,
+ it will still be downloaded when this option is enabled. This can speed up
+ the configure stage, but not as much as
+ ``FETCHCONTENT_FULLY_DISCONNECTED``. It is ``OFF`` by default.
+
+ In addition to the above cache variables, the following cache variables are
+ also defined for each content name (``<ucName>`` is the uppercased value of
+ ``<name>``):
+
+ ``FETCHCONTENT_SOURCE_DIR_<ucName>``
+ If this is set, no download or update steps are performed for the specified
+ content and the ``<lcName>_SOURCE_DIR`` variable returned to the caller is
+ pointed at this location. This gives developers a way to have a separate
+ checkout of the content that they can modify freely without interference
+ from the build. The build simply uses that existing source, but it still
+ defines ``<lcName>_BINARY_DIR`` to point inside its own build area.
+ Developers are strongly encouraged to use this mechanism rather than
+ editing the sources populated in the default location, as changes to
+ sources in the default location can be lost when content population details
+ are changed by the project.
+
+ ``FETCHCONTENT_UPDATES_DISCONNECTED_<ucName>``
+ This is the per-content equivalent of
+ ``FETCHCONTENT_UPDATES_DISCONNECTED``. If the global option or this option
+ is ``ON``, then updates will be disabled for the named content.
+ Disabling updates for individual content can be useful for content whose
+ details rarely change, while still leaving other frequently changing
+ content with updates enabled.
+
+
+ The ``FetchContent_Populate()`` command also supports a syntax allowing the
+ content details to be specified directly rather than using any saved
+ details. This is more low-level and use of this form is generally to be
+ avoided in favour of using saved content details as outlined above.
+ Nevertheless, in certain situations it can be useful to invoke the content
+ population as an isolated operation (typically as part of implementing some
+ other higher level feature or when using CMake in script mode):
+
+ .. code-block:: cmake
+
+ FetchContent_Populate( <name>
+ [QUIET]
+ [SUBBUILD_DIR <subBuildDir>]
+ [SOURCE_DIR <srcDir>]
+ [BINARY_DIR <binDir>]
+ ...
+ )
+
+ This form has a number of key differences to that where only ``<name>`` is
+ provided:
+
+ - All required population details are assumed to have been provided directly
+ in the call to ``FetchContent_Populate()``. Any saved details for
+ ``<name>`` are ignored.
+ - No check is made for whether content for ``<name>`` has already been
+ populated.
+ - No global property is set to record that the population has occurred.
+ - No global properties record the source or binary directories used for the
+ populated content.
+ - The ``FETCHCONTENT_FULLY_DISCONNECTED`` and
+ ``FETCHCONTENT_UPDATES_DISCONNECTED`` cache variables are ignored.
+
+ The ``<lcName>_SOURCE_DIR`` and ``<lcName>_BINARY_DIR`` variables are still
+ returned to the caller, but since these locations are not stored as global
+ properties when this form is used, they are only available to the calling
+ scope and below rather than the entire project hierarchy. No
+ ``<lcName>_POPULATED`` variable is set in the caller's scope with this form.
+
+ The supported options for ``FetchContent_Populate()`` are the same as those
+ for :command:`FetchContent_Declare()`. Those few options shown just
+ above are either specific to ``FetchContent_Populate()`` or their behavior is
+ slightly modified from how :command:`ExternalProject_Add` treats them.
+
+ ``QUIET``
+ The ``QUIET`` option can be given to hide the output associated with
+ populating the specified content. If the population fails, the output will
+ be shown regardless of whether this option was given or not so that the
+ cause of the failure can be diagnosed. The global ``FETCHCONTENT_QUIET``
+ cache variable has no effect on ``FetchContent_Populate()`` calls where the
+ content details are provided directly.
+
+ ``SUBBUILD_DIR``
+ The ``SUBBUILD_DIR`` argument can be provided to change the location of the
+ sub-build created to perform the population. The default value is
+ ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-subbuild`` and it would be unusual
+ to need to override this default. If a relative path is specified, it will
+ be interpreted as relative to :variable:`CMAKE_CURRENT_BINARY_DIR`.
+ This option should not be confused with the ``SOURCE_SUBDIR`` option which
+ only affects the :command:`FetchContent_MakeAvailable` command.
+
+ ``SOURCE_DIR``, ``BINARY_DIR``
+ The ``SOURCE_DIR`` and ``BINARY_DIR`` arguments are supported by
+ :command:`ExternalProject_Add`, but different default values are used by
+ ``FetchContent_Populate()``. ``SOURCE_DIR`` defaults to
+ ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-src`` and ``BINARY_DIR`` defaults to
+ ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-build``. If a relative path is
+ specified, it will be interpreted as relative to
+ :variable:`CMAKE_CURRENT_BINARY_DIR`.
+
+ In addition to the above explicit options, any other unrecognized options are
+ passed through unmodified to :command:`ExternalProject_Add` to perform the
+ download, patch and update steps. The following options are explicitly
+ prohibited (they are disabled by the ``FetchContent_Populate()`` command):
+
+ - ``CONFIGURE_COMMAND``
+ - ``BUILD_COMMAND``
+ - ``INSTALL_COMMAND``
+ - ``TEST_COMMAND``
+
+ If using ``FetchContent_Populate()`` within CMake's script mode, be aware
+ that the implementation sets up a sub-build which therefore requires a CMake
+ generator and build tool to be available. If these cannot be found by
+ default, then the :variable:`CMAKE_GENERATOR` and/or
+ :variable:`CMAKE_MAKE_PROGRAM` variables will need to be set appropriately
+ on the command line invoking the script.
+
+ .. versionadded:: 3.18
+ Added support for ``DOWNLOAD_NO_EXTRACT`` and ``SOURCE_SUBDIR`` options.
+
+.. command:: FetchContent_GetProperties
+
+ When using saved content details, a call to :command:`FetchContent_Populate`
+ records information in global properties which can be queried at any time.
+ This information includes the source and binary directories associated with
+ the content and also whether or not the content population has been processed
+ during the current configure run.
+
+ .. code-block:: cmake
+
+ FetchContent_GetProperties( <name>
+ [SOURCE_DIR <srcDirVar>]
+ [BINARY_DIR <binDirVar>]
+ [POPULATED <doneVar>]
+ )
+
+ The ``SOURCE_DIR``, ``BINARY_DIR`` and ``POPULATED`` options can be used to
+ specify which properties should be retrieved. Each option accepts a value
+ which is the name of the variable in which to store that property. Most of
+ the time though, only ``<name>`` is given, in which case the call will then
+ set the same variables as a call to
+ :command:`FetchContent_Populate(name) <FetchContent_Populate>`. This allows
+ the following canonical pattern to be used, which ensures that the relevant
+ variables will always be defined regardless of whether or not the population
+ has been performed elsewhere in the project already:
+
+ .. code-block:: cmake
+
+ FetchContent_GetProperties(foobar)
+ if(NOT foobar_POPULATED)
+ FetchContent_Populate(foobar)
+ ...
+ endif()
+
+ The above pattern allows other parts of the overall project hierarchy to
+ re-use the same content and ensure that it is only populated once.
+
+
+.. command:: FetchContent_MakeAvailable
+
+ .. code-block:: cmake
+
+ FetchContent_MakeAvailable( <name1> [<name2>...] )
+
+ .. versionadded:: 3.14
+
+ This command implements the common pattern typically needed for most
+ dependencies. It iterates over each of the named dependencies in turn
+ and for each one it loosely follows the
+ :ref:`canonical pattern <fetch-content-canonical-pattern>` as
+ presented at the beginning of this section. An important difference is
+ that :command:`add_subdirectory` will only be called on the
+ populated content if there is a ``CMakeLists.txt`` file in its top level
+ source directory. This allows the command to be used for dependencies
+ that make downloaded content available at a known location but which do
+ not need or support being added directly to the build.
+
+ The ``SOURCE_SUBDIR`` option can be given in the declared details to
+ instruct ``FetchContent_MakeAvailable()`` to look for a ``CMakeLists.txt``
+ file in a subdirectory below the top level (i.e. the same way that
+ ``SOURCE_SUBDIR`` is used by the :command:`ExternalProject_Add` command).
+ ``SOURCE_SUBDIR`` must always be a relative path. See the next section
+ for an example of this option.
+
+
+.. _`fetch-content-examples`:
+
+Examples
+^^^^^^^^
+
+This first fairly straightforward example ensures that some popular testing
+frameworks are available to the main build:
+
+.. code-block:: cmake
+
+ include(FetchContent)
+ FetchContent_Declare(
+ googletest
+ GIT_REPOSITORY https://github.com/google/googletest.git
+ GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
+ )
+ FetchContent_Declare(
+ Catch2
+ GIT_REPOSITORY https://github.com/catchorg/Catch2.git
+ GIT_TAG de6fe184a9ac1a06895cdd1c9b437f0a0bdf14ad # v2.13.4
+ )
+
+ # After the following call, the CMake targets defined by googletest and
+ # Catch2 will be defined and available to the rest of the build
+ FetchContent_MakeAvailable(googletest Catch2)
+
+If the sub-project's ``CMakeLists.txt`` file is not at the top level of its
+source tree, the ``SOURCE_SUBDIR`` option can be used to tell ``FetchContent``
+where to find it. The following example shows how to use that option and
+it also sets a variable which is meaningful to the subproject before pulling
+it into the main build:
+
+.. code-block:: cmake
+
+ include(FetchContent)
+ FetchContent_Declare(
+ protobuf
+ GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git
+ GIT_TAG ae50d9b9902526efd6c7a1907d09739f959c6297 # v3.15.0
+ SOURCE_SUBDIR cmake
+ )
+ set(protobuf_BUILD_TESTS OFF)
+ FetchContent_MakeAvailable(protobuf)
+
+In more complex project hierarchies, the dependency relationships can be more
+complicated. Consider a hierarchy where ``projA`` is the top level project and
+it depends directly on projects ``projB`` and ``projC``. Both ``projB`` and
+``projC`` can be built standalone and they also both depend on another project
+``projD``. ``projB`` additionally depends on ``projE``. This example assumes
+that all five projects are available on a company git server. The
+``CMakeLists.txt`` of each project might have sections like the following:
+
+*projA*:
+
+.. code-block:: cmake
+
+ include(FetchContent)
+ FetchContent_Declare(
+ projB
+ GIT_REPOSITORY git@mycompany.com:git/projB.git
+ GIT_TAG 4a89dc7e24ff212a7b5167bef7ab079d
+ )
+ FetchContent_Declare(
+ projC
+ GIT_REPOSITORY git@mycompany.com:git/projC.git
+ GIT_TAG 4ad4016bd1d8d5412d135cf8ceea1bb9
+ )
+ FetchContent_Declare(
+ projD
+ GIT_REPOSITORY git@mycompany.com:git/projD.git
+ GIT_TAG origin/integrationBranch
+ )
+ FetchContent_Declare(
+ projE
+ GIT_REPOSITORY git@mycompany.com:git/projE.git
+ GIT_TAG v2.3-rc1
+ )
+
+ # Order is important, see notes in the discussion further below
+ FetchContent_MakeAvailable(projD projB projC)
+
+*projB*:
+
+.. code-block:: cmake
+
+ include(FetchContent)
+ FetchContent_Declare(
+ projD
+ GIT_REPOSITORY git@mycompany.com:git/projD.git
+ GIT_TAG 20b415f9034bbd2a2e8216e9a5c9e632
+ )
+ FetchContent_Declare(
+ projE
+ GIT_REPOSITORY git@mycompany.com:git/projE.git
+ GIT_TAG 68e20f674a48be38d60e129f600faf7d
+ )
+
+ FetchContent_MakeAvailable(projD projE)
+
+*projC*:
+
+.. code-block:: cmake
+
+ include(FetchContent)
+ FetchContent_Declare(
+ projD
+ GIT_REPOSITORY git@mycompany.com:git/projD.git
+ GIT_TAG 7d9a17ad2c962aa13e2fbb8043fb6b8a
+ )
+
+ # This particular version of projD requires workarounds
+ FetchContent_GetProperties(projD)
+ if(NOT projd_POPULATED)
+ FetchContent_Populate(projD)
+
+ # Copy an additional/replacement file into the populated source
+ file(COPY someFile.c DESTINATION ${projd_SOURCE_DIR}/src)
+
+ add_subdirectory(${projd_SOURCE_DIR} ${projd_BINARY_DIR})
+ endif()
+
+A few key points should be noted in the above:
+
+- ``projB`` and ``projC`` define different content details for ``projD``,
+ but ``projA`` also defines a set of content details for ``projD``.
+ Because ``projA`` will define them first, the details from ``projB`` and
+ ``projC`` will not be used. The override details defined by ``projA``
+ are not required to match either of those from ``projB`` or ``projC``, but
+ it is up to the higher level project to ensure that the details it does
+ define still make sense for the child projects.
+- In the ``projA`` call to :command:`FetchContent_MakeAvailable`, ``projD``
+ is listed ahead of ``projB`` and ``projC`` to ensure that ``projA`` is in
+ control of how ``projD`` is populated.
+- While ``projA`` defines content details for ``projE``, it does not need
+ to explicitly call ``FetchContent_MakeAvailable(projE)`` or
+ ``FetchContent_Populate(projD)`` itself. Instead, it leaves that to the
+ child ``projB``. For higher level projects, it is often enough to just
+ define the override content details and leave the actual population to the
+ child projects. This saves repeating the same thing at each level of the
+ project hierarchy unnecessarily.
+
+
+Projects don't always need to add the populated content to the build.
+Sometimes the project just wants to make the downloaded content available at
+a predictable location. The next example ensures that a set of standard
+company toolchain files (and potentially even the toolchain binaries
+themselves) is available early enough to be used for that same build.
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.14)
+
+ include(FetchContent)
+ FetchContent_Declare(
+ mycom_toolchains
+ URL https://intranet.mycompany.com//toolchains_1.3.2.tar.gz
+ )
+ FetchContent_MakeAvailable(mycom_toolchains)
+
+ project(CrossCompileExample)
+
+The project could be configured to use one of the downloaded toolchains like
+so:
+
+.. code-block:: shell
+
+ cmake -DCMAKE_TOOLCHAIN_FILE=_deps/mycom_toolchains-src/toolchain_arm.cmake /path/to/src
+
+When CMake processes the ``CMakeLists.txt`` file, it will download and unpack
+the tarball into ``_deps/mycompany_toolchains-src`` relative to the build
+directory. The :variable:`CMAKE_TOOLCHAIN_FILE` variable is not used until
+the :command:`project` command is reached, at which point CMake looks for the
+named toolchain file relative to the build directory. Because the tarball has
+already been downloaded and unpacked by then, the toolchain file will be in
+place, even the very first time that ``cmake`` is run in the build directory.
+
+Lastly, the following example demonstrates how one might download and unpack a
+firmware tarball using CMake's :manual:`script mode <cmake(1)>`. The call to
+:command:`FetchContent_Populate` specifies all the content details and the
+unpacked firmware will be placed in a ``firmware`` directory below the
+current working directory.
+
+*getFirmware.cmake*:
+
+.. code-block:: cmake
+
+ # NOTE: Intended to be run in script mode with cmake -P
+ include(FetchContent)
+ FetchContent_Populate(
+ firmware
+ URL https://mycompany.com/assets/firmware-1.23-arm.tar.gz
+ URL_HASH MD5=68247684da89b608d466253762b0ff11
+ SOURCE_DIR firmware
+ )
+
+#]=======================================================================]
+
+#=======================================================================
+# Recording and retrieving content details for later population
+#=======================================================================
+
+# Internal use, projects must not call this directly. It is
+# intended for use by FetchContent_Declare() only.
+#
+# Sets a content-specific global property (not meant for use
+# outside of functions defined here in this file) which can later
+# be retrieved using __FetchContent_getSavedDetails() with just the
+# same content name. If there is already a value stored in the
+# property, it is left unchanged and this call has no effect.
+# This allows parent projects to define the content details,
+# overriding anything a child project may try to set (properties
+# are not cached between runs, so the first thing to set it in a
+# build will be in control).
+function(__FetchContent_declareDetails contentName)
+
+ string(TOLOWER ${contentName} contentNameLower)
+ set(propertyName "_FetchContent_${contentNameLower}_savedDetails")
+ get_property(alreadyDefined GLOBAL PROPERTY ${propertyName} DEFINED)
+ if(NOT alreadyDefined)
+ define_property(GLOBAL PROPERTY ${propertyName}
+ BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
+ FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}"
+ )
+ set(__cmdArgs)
+ foreach(__item IN LISTS ARGN)
+ string(APPEND __cmdArgs " [==[${__item}]==]")
+ endforeach()
+ cmake_language(EVAL CODE
+ "set_property(GLOBAL PROPERTY ${propertyName} ${__cmdArgs})")
+ endif()
+
+endfunction()
+
+
+# Internal use, projects must not call this directly. It is
+# intended for use by the FetchContent_Declare() function.
+#
+# Retrieves details saved for the specified content in an
+# earlier call to __FetchContent_declareDetails().
+function(__FetchContent_getSavedDetails contentName outVar)
+
+ string(TOLOWER ${contentName} contentNameLower)
+ set(propertyName "_FetchContent_${contentNameLower}_savedDetails")
+ get_property(alreadyDefined GLOBAL PROPERTY ${propertyName} DEFINED)
+ if(NOT alreadyDefined)
+ message(FATAL_ERROR "No content details recorded for ${contentName}")
+ endif()
+ get_property(propertyValue GLOBAL PROPERTY ${propertyName})
+ set(${outVar} "${propertyValue}" PARENT_SCOPE)
+
+endfunction()
+
+
+# Saves population details of the content, sets defaults for the
+# SOURCE_DIR and BUILD_DIR.
+function(FetchContent_Declare contentName)
+
+ set(options "")
+ set(oneValueArgs SVN_REPOSITORY)
+ set(multiValueArgs "")
+
+ cmake_parse_arguments(PARSE_ARGV 1 ARG
+ "${options}" "${oneValueArgs}" "${multiValueArgs}")
+
+ unset(srcDirSuffix)
+ unset(svnRepoArgs)
+ if(ARG_SVN_REPOSITORY)
+ # Add a hash of the svn repository URL to the source dir. This works
+ # around the problem where if the URL changes, the download would
+ # fail because it tries to checkout/update rather than switch the
+ # old URL to the new one. We limit the hash to the first 7 characters
+ # so that the source path doesn't get overly long (which can be a
+ # problem on windows due to path length limits).
+ string(SHA1 urlSHA ${ARG_SVN_REPOSITORY})
+ string(SUBSTRING ${urlSHA} 0 7 urlSHA)
+ set(srcDirSuffix "-${urlSHA}")
+ set(svnRepoArgs SVN_REPOSITORY ${ARG_SVN_REPOSITORY})
+ endif()
+
+ string(TOLOWER ${contentName} contentNameLower)
+
+ set(__argsQuoted)
+ foreach(__item IN LISTS ARG_UNPARSED_ARGUMENTS)
+ string(APPEND __argsQuoted " [==[${__item}]==]")
+ endforeach()
+ cmake_language(EVAL CODE "
+ __FetchContent_declareDetails(
+ ${contentNameLower}
+ SOURCE_DIR \"${FETCHCONTENT_BASE_DIR}/${contentNameLower}-src${srcDirSuffix}\"
+ BINARY_DIR \"${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build\"
+ \${svnRepoArgs}
+ # List these last so they can override things we set above
+ ${__argsQuoted}
+ )"
+ )
+
+endfunction()
+
+
+#=======================================================================
+# Set/get whether the specified content has been populated yet.
+# The setter also records the source and binary dirs used.
+#=======================================================================
+
+# Internal use, projects must not call this directly. It is
+# intended for use by the FetchContent_Populate() function to
+# record when FetchContent_Populate() is called for a particular
+# content name.
+function(__FetchContent_setPopulated contentName sourceDir binaryDir)
+
+ string(TOLOWER ${contentName} contentNameLower)
+ set(prefix "_FetchContent_${contentNameLower}")
+
+ set(propertyName "${prefix}_sourceDir")
+ define_property(GLOBAL PROPERTY ${propertyName}
+ BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
+ FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}"
+ )
+ set_property(GLOBAL PROPERTY ${propertyName} ${sourceDir})
+
+ set(propertyName "${prefix}_binaryDir")
+ define_property(GLOBAL PROPERTY ${propertyName}
+ BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
+ FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}"
+ )
+ set_property(GLOBAL PROPERTY ${propertyName} ${binaryDir})
+
+ set(propertyName "${prefix}_populated")
+ define_property(GLOBAL PROPERTY ${propertyName}
+ BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
+ FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}"
+ )
+ set_property(GLOBAL PROPERTY ${propertyName} True)
+
+endfunction()
+
+
+# Set variables in the calling scope for any of the retrievable
+# properties. If no specific properties are requested, variables
+# will be set for all retrievable properties.
+#
+# This function is intended to also be used by projects as the canonical
+# way to detect whether they should call FetchContent_Populate()
+# and pull the populated source into the build with add_subdirectory(),
+# if they are using the populated content in that way.
+function(FetchContent_GetProperties contentName)
+
+ string(TOLOWER ${contentName} contentNameLower)
+
+ set(options "")
+ set(oneValueArgs SOURCE_DIR BINARY_DIR POPULATED)
+ set(multiValueArgs "")
+
+ cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(NOT ARG_SOURCE_DIR AND
+ NOT ARG_BINARY_DIR AND
+ NOT ARG_POPULATED)
+ # No specific properties requested, provide them all
+ set(ARG_SOURCE_DIR ${contentNameLower}_SOURCE_DIR)
+ set(ARG_BINARY_DIR ${contentNameLower}_BINARY_DIR)
+ set(ARG_POPULATED ${contentNameLower}_POPULATED)
+ endif()
+
+ set(prefix "_FetchContent_${contentNameLower}")
+
+ if(ARG_SOURCE_DIR)
+ set(propertyName "${prefix}_sourceDir")
+ get_property(value GLOBAL PROPERTY ${propertyName})
+ if(value)
+ set(${ARG_SOURCE_DIR} ${value} PARENT_SCOPE)
+ endif()
+ endif()
+
+ if(ARG_BINARY_DIR)
+ set(propertyName "${prefix}_binaryDir")
+ get_property(value GLOBAL PROPERTY ${propertyName})
+ if(value)
+ set(${ARG_BINARY_DIR} ${value} PARENT_SCOPE)
+ endif()
+ endif()
+
+ if(ARG_POPULATED)
+ set(propertyName "${prefix}_populated")
+ get_property(value GLOBAL PROPERTY ${propertyName} DEFINED)
+ set(${ARG_POPULATED} ${value} PARENT_SCOPE)
+ endif()
+
+endfunction()
+
+
+#=======================================================================
+# Performing the population
+#=======================================================================
+
+# The value of contentName will always have been lowercased by the caller.
+# All other arguments are assumed to be options that are understood by
+# ExternalProject_Add(), except for QUIET and SUBBUILD_DIR.
+function(__FetchContent_directPopulate contentName)
+
+ set(options
+ QUIET
+ )
+ set(oneValueArgs
+ SUBBUILD_DIR
+ SOURCE_DIR
+ BINARY_DIR
+ # We need special processing if DOWNLOAD_NO_EXTRACT is true
+ DOWNLOAD_NO_EXTRACT
+ # Prevent the following from being passed through
+ CONFIGURE_COMMAND
+ BUILD_COMMAND
+ INSTALL_COMMAND
+ TEST_COMMAND
+ # We force both of these to be ON since we are always executing serially
+ # and we want all steps to have access to the terminal in case they
+ # need input from the command line (e.g. ask for a private key password)
+ # or they want to provide timely progress. We silently absorb and
+ # discard these if they are set by the caller.
+ USES_TERMINAL_DOWNLOAD
+ USES_TERMINAL_UPDATE
+ )
+ set(multiValueArgs "")
+
+ cmake_parse_arguments(PARSE_ARGV 1 ARG
+ "${options}" "${oneValueArgs}" "${multiValueArgs}")
+
+ if(NOT ARG_SUBBUILD_DIR)
+ message(FATAL_ERROR "Internal error: SUBBUILD_DIR not set")
+ elseif(NOT IS_ABSOLUTE "${ARG_SUBBUILD_DIR}")
+ set(ARG_SUBBUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SUBBUILD_DIR}")
+ endif()
+
+ if(NOT ARG_SOURCE_DIR)
+ message(FATAL_ERROR "Internal error: SOURCE_DIR not set")
+ elseif(NOT IS_ABSOLUTE "${ARG_SOURCE_DIR}")
+ set(ARG_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SOURCE_DIR}")
+ endif()
+
+ if(NOT ARG_BINARY_DIR)
+ message(FATAL_ERROR "Internal error: BINARY_DIR not set")
+ elseif(NOT IS_ABSOLUTE "${ARG_BINARY_DIR}")
+ set(ARG_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/${ARG_BINARY_DIR}")
+ endif()
+
+ # Ensure the caller can know where to find the source and build directories
+ # with some convenient variables. Doing this here ensures the caller sees
+ # the correct result in the case where the default values are overridden by
+ # the content details set by the project.
+ set(${contentName}_SOURCE_DIR "${ARG_SOURCE_DIR}" PARENT_SCOPE)
+ set(${contentName}_BINARY_DIR "${ARG_BINARY_DIR}" PARENT_SCOPE)
+
+ # The unparsed arguments may contain spaces, so build up ARG_EXTRA
+ # in such a way that it correctly substitutes into the generated
+ # CMakeLists.txt file with each argument quoted.
+ unset(ARG_EXTRA)
+ foreach(arg IN LISTS ARG_UNPARSED_ARGUMENTS)
+ set(ARG_EXTRA "${ARG_EXTRA} \"${arg}\"")
+ endforeach()
+
+ if(ARG_DOWNLOAD_NO_EXTRACT)
+ set(ARG_EXTRA "${ARG_EXTRA} DOWNLOAD_NO_EXTRACT YES")
+ set(__FETCHCONTENT_COPY_FILE
+"
+ExternalProject_Get_Property(${contentName}-populate DOWNLOADED_FILE)
+get_filename_component(dlFileName \"\${DOWNLOADED_FILE}\" NAME)
+
+ExternalProject_Add_Step(${contentName}-populate copyfile
+ COMMAND \"${CMAKE_COMMAND}\" -E copy_if_different
+ \"<DOWNLOADED_FILE>\" \"${ARG_SOURCE_DIR}\"
+ DEPENDEES patch
+ DEPENDERS configure
+ BYPRODUCTS \"${ARG_SOURCE_DIR}/\${dlFileName}\"
+ COMMENT \"Copying file to SOURCE_DIR\"
+)
+")
+ else()
+ unset(__FETCHCONTENT_COPY_FILE)
+ endif()
+
+ # Hide output if requested, but save it to a variable in case there's an
+ # error so we can show the output upon failure. When not quiet, don't
+ # capture the output to a variable because the user may want to see the
+ # output as it happens (e.g. progress during long downloads). Combine both
+ # stdout and stderr in the one capture variable so the output stays in order.
+ if (ARG_QUIET)
+ set(outputOptions
+ OUTPUT_VARIABLE capturedOutput
+ ERROR_VARIABLE capturedOutput
+ )
+ else()
+ set(capturedOutput)
+ set(outputOptions)
+ message(STATUS "Populating ${contentName}")
+ endif()
+
+ if(CMAKE_GENERATOR)
+ set(subCMakeOpts "-G${CMAKE_GENERATOR}")
+ if(CMAKE_GENERATOR_PLATFORM)
+ list(APPEND subCMakeOpts "-A${CMAKE_GENERATOR_PLATFORM}")
+ endif()
+ if(CMAKE_GENERATOR_TOOLSET)
+ list(APPEND subCMakeOpts "-T${CMAKE_GENERATOR_TOOLSET}")
+ endif()
+
+ if(CMAKE_MAKE_PROGRAM)
+ list(APPEND subCMakeOpts "-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}")
+ endif()
+
+ else()
+ # Likely we've been invoked via CMake's script mode where no
+ # generator is set (and hence CMAKE_MAKE_PROGRAM could not be
+ # trusted even if provided). We will have to rely on being
+ # able to find the default generator and build tool.
+ unset(subCMakeOpts)
+ endif()
+
+ if(DEFINED CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY)
+ list(APPEND subCMakeOpts
+ "-DCMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY=${CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY}")
+ endif()
+
+ # Avoid using if(... IN_LIST ...) so we don't have to alter policy settings
+ set(__FETCHCONTENT_CACHED_INFO "")
+ list(FIND ARG_UNPARSED_ARGUMENTS GIT_REPOSITORY indexResult)
+ if(indexResult GREATER_EQUAL 0)
+ find_package(Git QUIET)
+ set(__FETCHCONTENT_CACHED_INFO
+"# Pass through things we've already detected in the main project to avoid
+# paying the cost of redetecting them again in ExternalProject_Add()
+set(GIT_EXECUTABLE [==[${GIT_EXECUTABLE}]==])
+set(GIT_VERSION_STRING [==[${GIT_VERSION_STRING}]==])
+set_property(GLOBAL PROPERTY _CMAKE_FindGit_GIT_EXECUTABLE_VERSION
+ [==[${GIT_EXECUTABLE};${GIT_VERSION_STRING}]==]
+)
+")
+ endif()
+
+ # Create and build a separate CMake project to carry out the population.
+ # If we've already previously done these steps, they will not cause
+ # anything to be updated, so extra rebuilds of the project won't occur.
+ # Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project
+ # has this set to something not findable on the PATH.
+ configure_file("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/FetchContent/CMakeLists.cmake.in"
+ "${ARG_SUBBUILD_DIR}/CMakeLists.txt")
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} ${subCMakeOpts} .
+ RESULT_VARIABLE result
+ ${outputOptions}
+ WORKING_DIRECTORY "${ARG_SUBBUILD_DIR}"
+ )
+ if(result)
+ if(capturedOutput)
+ message("${capturedOutput}")
+ endif()
+ message(FATAL_ERROR "CMake step for ${contentName} failed: ${result}")
+ endif()
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} --build .
+ RESULT_VARIABLE result
+ ${outputOptions}
+ WORKING_DIRECTORY "${ARG_SUBBUILD_DIR}"
+ )
+ if(result)
+ if(capturedOutput)
+ message("${capturedOutput}")
+ endif()
+ message(FATAL_ERROR "Build step for ${contentName} failed: ${result}")
+ endif()
+
+endfunction()
+
+
+option(FETCHCONTENT_FULLY_DISCONNECTED "Disables all attempts to download or update content and assumes source dirs already exist")
+option(FETCHCONTENT_UPDATES_DISCONNECTED "Enables UPDATE_DISCONNECTED behavior for all content population")
+option(FETCHCONTENT_QUIET "Enables QUIET option for all content population" ON)
+set(FETCHCONTENT_BASE_DIR "${CMAKE_BINARY_DIR}/_deps" CACHE PATH "Directory under which to collect all populated content")
+
+# Populate the specified content using details stored from
+# an earlier call to FetchContent_Declare().
+function(FetchContent_Populate contentName)
+
+ if(NOT contentName)
+ message(FATAL_ERROR "Empty contentName not allowed for FetchContent_Populate()")
+ endif()
+
+ string(TOLOWER ${contentName} contentNameLower)
+
+ if(ARGN)
+ # This is the direct population form with details fully specified
+ # as part of the call, so we already have everything we need
+ __FetchContent_directPopulate(
+ ${contentNameLower}
+ SUBBUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/${contentNameLower}-subbuild"
+ SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/${contentNameLower}-src"
+ BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/${contentNameLower}-build"
+ ${ARGN} # Could override any of the above ..._DIR variables
+ )
+
+ # Pass source and binary dir variables back to the caller
+ set(${contentNameLower}_SOURCE_DIR "${${contentNameLower}_SOURCE_DIR}" PARENT_SCOPE)
+ set(${contentNameLower}_BINARY_DIR "${${contentNameLower}_BINARY_DIR}" PARENT_SCOPE)
+
+ # Don't set global properties, or record that we did this population, since
+ # this was a direct call outside of the normal declared details form.
+ # We only want to save values in the global properties for content that
+ # honours the hierarchical details mechanism so that projects are not
+ # robbed of the ability to override details set in nested projects.
+ return()
+ endif()
+
+ # No details provided, so assume they were saved from an earlier call
+ # to FetchContent_Declare(). Do a check that we haven't already
+ # populated this content before in case the caller forgot to check.
+ FetchContent_GetProperties(${contentName})
+ if(${contentNameLower}_POPULATED)
+ message(FATAL_ERROR "Content ${contentName} already populated in ${${contentNameLower}_SOURCE_DIR}")
+ endif()
+
+ __FetchContent_getSavedDetails(${contentName} contentDetails)
+ if("${contentDetails}" STREQUAL "")
+ message(FATAL_ERROR "No details have been set for content: ${contentName}")
+ endif()
+
+ string(TOUPPER ${contentName} contentNameUpper)
+ set(FETCHCONTENT_SOURCE_DIR_${contentNameUpper}
+ "${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}"
+ CACHE PATH "When not empty, overrides where to find pre-populated content for ${contentName}")
+
+ if(FETCHCONTENT_SOURCE_DIR_${contentNameUpper})
+ # The source directory has been explicitly provided in the cache,
+ # so no population is required. The build directory may still be specified
+ # by the declared details though.
+
+ if(NOT IS_ABSOLUTE "${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}")
+ # Don't check this directory because we don't know what location it is
+ # expected to be relative to. We can't make this a hard error for backward
+ # compatibility reasons.
+ message(WARNING "Relative source directory specified. This is not safe, "
+ "as it depends on the calling directory scope.\n"
+ " FETCHCONTENT_SOURCE_DIR_${contentNameUpper} --> ${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}")
+ elseif(NOT EXISTS "${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}")
+ message(FATAL_ERROR "Manually specified source directory is missing:\n"
+ " FETCHCONTENT_SOURCE_DIR_${contentNameUpper} --> ${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}")
+ endif()
+
+ set(${contentNameLower}_SOURCE_DIR "${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}")
+
+ cmake_parse_arguments(savedDetails "" "BINARY_DIR" "" ${contentDetails})
+
+ if(savedDetails_BINARY_DIR)
+ set(${contentNameLower}_BINARY_DIR ${savedDetails_BINARY_DIR})
+ else()
+ set(${contentNameLower}_BINARY_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build")
+ endif()
+
+ elseif(FETCHCONTENT_FULLY_DISCONNECTED)
+ # Bypass population and assume source is already there from a previous run.
+ # Declared details may override the default source or build directories.
+
+ cmake_parse_arguments(savedDetails "" "SOURCE_DIR;BINARY_DIR" "" ${contentDetails})
+
+ if(savedDetails_SOURCE_DIR)
+ set(${contentNameLower}_SOURCE_DIR ${savedDetails_SOURCE_DIR})
+ else()
+ set(${contentNameLower}_SOURCE_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-src")
+ endif()
+
+ if(savedDetails_BINARY_DIR)
+ set(${contentNameLower}_BINARY_DIR ${savedDetails_BINARY_DIR})
+ else()
+ set(${contentNameLower}_BINARY_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build")
+ endif()
+
+ else()
+ # Support both a global "disconnect all updates" and a per-content
+ # update test (either one being set disables updates for this content).
+ option(FETCHCONTENT_UPDATES_DISCONNECTED_${contentNameUpper}
+ "Enables UPDATE_DISCONNECTED behavior just for population of ${contentName}")
+ if(FETCHCONTENT_UPDATES_DISCONNECTED OR
+ FETCHCONTENT_UPDATES_DISCONNECTED_${contentNameUpper})
+ set(disconnectUpdates True)
+ else()
+ set(disconnectUpdates False)
+ endif()
+
+ if(FETCHCONTENT_QUIET)
+ set(quietFlag QUIET)
+ else()
+ unset(quietFlag)
+ endif()
+
+ set(__detailsQuoted)
+ foreach(__item IN LISTS contentDetails)
+ string(APPEND __detailsQuoted " [==[${__item}]==]")
+ endforeach()
+ cmake_language(EVAL CODE "
+ __FetchContent_directPopulate(
+ ${contentNameLower}
+ ${quietFlag}
+ UPDATE_DISCONNECTED ${disconnectUpdates}
+ SUBBUILD_DIR \"${FETCHCONTENT_BASE_DIR}/${contentNameLower}-subbuild\"
+ SOURCE_DIR \"${FETCHCONTENT_BASE_DIR}/${contentNameLower}-src\"
+ BINARY_DIR \"${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build\"
+ # Put the saved details last so they can override any of the
+ # the options we set above (this can include SOURCE_DIR or
+ # BUILD_DIR)
+ ${__detailsQuoted}
+ )"
+ )
+ endif()
+
+ __FetchContent_setPopulated(
+ ${contentName}
+ ${${contentNameLower}_SOURCE_DIR}
+ ${${contentNameLower}_BINARY_DIR}
+ )
+
+ # Pass variables back to the caller. The variables passed back here
+ # must match what FetchContent_GetProperties() sets when it is called
+ # with just the content name.
+ set(${contentNameLower}_SOURCE_DIR "${${contentNameLower}_SOURCE_DIR}" PARENT_SCOPE)
+ set(${contentNameLower}_BINARY_DIR "${${contentNameLower}_BINARY_DIR}" PARENT_SCOPE)
+ set(${contentNameLower}_POPULATED True PARENT_SCOPE)
+
+endfunction()
+
+# Arguments are assumed to be the names of dependencies that have been
+# declared previously and should be populated. It is not an error if
+# any of them have already been populated (they will just be skipped in
+# that case). The command is implemented as a macro so that the variables
+# defined by the FetchContent_GetProperties() and FetchContent_Populate()
+# calls will be available to the caller.
+macro(FetchContent_MakeAvailable)
+
+ foreach(contentName IN ITEMS ${ARGV})
+ string(TOLOWER ${contentName} contentNameLower)
+ FetchContent_GetProperties(${contentName})
+ if(NOT ${contentNameLower}_POPULATED)
+ FetchContent_Populate(${contentName})
+
+ # Only try to call add_subdirectory() if the populated content
+ # can be treated that way. Protecting the call with the check
+ # allows this function to be used for projects that just want
+ # to ensure the content exists, such as to provide content at
+ # a known location. We check the saved details for an optional
+ # SOURCE_SUBDIR which can be used in the same way as its meaning
+ # for ExternalProject. It won't matter if it was passed through
+ # to the ExternalProject sub-build, since it would have been
+ # ignored there.
+ set(__fc_srcdir "${${contentNameLower}_SOURCE_DIR}")
+ __FetchContent_getSavedDetails(${contentName} contentDetails)
+ if("${contentDetails}" STREQUAL "")
+ message(FATAL_ERROR "No details have been set for content: ${contentName}")
+ endif()
+ cmake_parse_arguments(__fc_arg "" "SOURCE_SUBDIR" "" ${contentDetails})
+ if(NOT "${__fc_arg_SOURCE_SUBDIR}" STREQUAL "")
+ string(APPEND __fc_srcdir "/${__fc_arg_SOURCE_SUBDIR}")
+ endif()
+
+ if(EXISTS ${__fc_srcdir}/CMakeLists.txt)
+ add_subdirectory(${__fc_srcdir} ${${contentNameLower}_BINARY_DIR})
+ endif()
+
+ unset(__fc_srcdir)
+ endif()
+ endforeach()
+
+endmacro()
diff --git a/Modules/FetchContent/CMakeLists.cmake.in b/Modules/FetchContent/CMakeLists.cmake.in
new file mode 100644
index 0000000..5ebb12f
--- /dev/null
+++ b/Modules/FetchContent/CMakeLists.cmake.in
@@ -0,0 +1,27 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION ${CMAKE_VERSION})
+
+# We name the project and the target for the ExternalProject_Add() call
+# to something that will highlight to the user what we are working on if
+# something goes wrong and an error message is produced.
+
+project(${contentName}-populate NONE)
+
+@__FETCHCONTENT_CACHED_INFO@
+
+include(ExternalProject)
+ExternalProject_Add(${contentName}-populate
+ ${ARG_EXTRA}
+ SOURCE_DIR "${ARG_SOURCE_DIR}"
+ BINARY_DIR "${ARG_BINARY_DIR}"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ USES_TERMINAL_DOWNLOAD YES
+ USES_TERMINAL_UPDATE YES
+)
+
+@__FETCHCONTENT_COPY_FILE@
diff --git a/Modules/FindALSA.cmake b/Modules/FindALSA.cmake
new file mode 100644
index 0000000..627866a
--- /dev/null
+++ b/Modules/FindALSA.cmake
@@ -0,0 +1,76 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindALSA
+--------
+
+Find Advanced Linux Sound Architecture (ALSA)
+
+Find the alsa libraries (``asound``)
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.12
+
+This module defines :prop_tgt:`IMPORTED` target ``ALSA::ALSA``, if
+ALSA has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``ALSA_FOUND``
+ True if ALSA_INCLUDE_DIR & ALSA_LIBRARY are found
+
+``ALSA_LIBRARIES``
+ List of libraries when using ALSA.
+
+``ALSA_INCLUDE_DIRS``
+ Where to find the ALSA headers.
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``ALSA_INCLUDE_DIR``
+ the ALSA include directory
+
+``ALSA_LIBRARY``
+ the absolute path of the asound library
+#]=======================================================================]
+
+find_path(ALSA_INCLUDE_DIR NAMES alsa/asoundlib.h
+ DOC "The ALSA (asound) include directory"
+)
+
+find_library(ALSA_LIBRARY NAMES asound
+ DOC "The ALSA (asound) library"
+)
+
+if(ALSA_INCLUDE_DIR AND EXISTS "${ALSA_INCLUDE_DIR}/alsa/version.h")
+ file(STRINGS "${ALSA_INCLUDE_DIR}/alsa/version.h" alsa_version_str REGEX "^#define[\t ]+SND_LIB_VERSION_STR[\t ]+\".*\"")
+
+ string(REGEX REPLACE "^.*SND_LIB_VERSION_STR[\t ]+\"([^\"]*)\".*$" "\\1" ALSA_VERSION_STRING "${alsa_version_str}")
+ unset(alsa_version_str)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(ALSA
+ REQUIRED_VARS ALSA_LIBRARY ALSA_INCLUDE_DIR
+ VERSION_VAR ALSA_VERSION_STRING)
+
+if(ALSA_FOUND)
+ set( ALSA_LIBRARIES ${ALSA_LIBRARY} )
+ set( ALSA_INCLUDE_DIRS ${ALSA_INCLUDE_DIR} )
+ if(NOT TARGET ALSA::ALSA)
+ add_library(ALSA::ALSA UNKNOWN IMPORTED)
+ set_target_properties(ALSA::ALSA PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${ALSA_INCLUDE_DIRS}")
+ set_property(TARGET ALSA::ALSA APPEND PROPERTY IMPORTED_LOCATION "${ALSA_LIBRARY}")
+ endif()
+endif()
+
+mark_as_advanced(ALSA_INCLUDE_DIR ALSA_LIBRARY)
diff --git a/Modules/FindASPELL.cmake b/Modules/FindASPELL.cmake
new file mode 100644
index 0000000..c2d29e2
--- /dev/null
+++ b/Modules/FindASPELL.cmake
@@ -0,0 +1,32 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindASPELL
+----------
+
+Try to find ASPELL
+
+Once done this will define
+
+::
+
+ ASPELL_FOUND - system has ASPELL
+ ASPELL_EXECUTABLE - the ASPELL executable
+ ASPELL_INCLUDE_DIR - the ASPELL include directory
+ ASPELL_LIBRARIES - The libraries needed to use ASPELL
+ ASPELL_DEFINITIONS - Compiler switches required for using ASPELL
+#]=======================================================================]
+
+find_path(ASPELL_INCLUDE_DIR aspell.h )
+
+find_program(ASPELL_EXECUTABLE
+ NAMES aspell
+)
+
+find_library(ASPELL_LIBRARIES NAMES aspell aspell-15 libaspell-15 libaspell)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(ASPELL DEFAULT_MSG ASPELL_LIBRARIES ASPELL_INCLUDE_DIR ASPELL_EXECUTABLE)
+
+mark_as_advanced(ASPELL_INCLUDE_DIR ASPELL_LIBRARIES ASPELL_EXECUTABLE)
diff --git a/Modules/FindAVIFile.cmake b/Modules/FindAVIFile.cmake
new file mode 100644
index 0000000..9655440
--- /dev/null
+++ b/Modules/FindAVIFile.cmake
@@ -0,0 +1,38 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindAVIFile
+-----------
+
+Locate AVIFILE library and include paths
+
+AVIFILE (http://avifile.sourceforge.net/) is a set of libraries for
+i386 machines to use various AVI codecs. Support is limited beyond
+Linux. Windows provides native AVI support, and so doesn't need this
+library. This module defines
+
+::
+
+ AVIFILE_INCLUDE_DIR, where to find avifile.h , etc.
+ AVIFILE_LIBRARIES, the libraries to link against
+ AVIFILE_DEFINITIONS, definitions to use when compiling
+ AVIFILE_FOUND, If false, don't try to use AVIFILE
+#]=======================================================================]
+
+if (UNIX)
+
+ find_path(AVIFILE_INCLUDE_DIR avifile.h PATH_SUFFIXES avifile/include include/avifile include/avifile-0.7)
+ find_library(AVIFILE_AVIPLAY_LIBRARY aviplay aviplay-0.7 PATH_SUFFIXES avifile/lib)
+
+endif ()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(AVIFile DEFAULT_MSG AVIFILE_INCLUDE_DIR AVIFILE_AVIPLAY_LIBRARY)
+
+if (AVIFILE_FOUND)
+ set(AVIFILE_LIBRARIES ${AVIFILE_AVIPLAY_LIBRARY})
+ set(AVIFILE_DEFINITIONS "")
+endif()
+
+mark_as_advanced(AVIFILE_INCLUDE_DIR AVIFILE_AVIPLAY_LIBRARY)
diff --git a/Modules/FindArmadillo.cmake b/Modules/FindArmadillo.cmake
new file mode 100644
index 0000000..f959356
--- /dev/null
+++ b/Modules/FindArmadillo.cmake
@@ -0,0 +1,135 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindArmadillo
+-------------
+
+Find the Armadillo C++ library.
+Armadillo is a library for linear algebra & scientific computing.
+
+.. versionadded:: 3.18
+ Support for linking wrapped libraries directly (``ARMA_DONT_USE_WRAPPER``).
+
+Using Armadillo:
+
+::
+
+ find_package(Armadillo REQUIRED)
+ include_directories(${ARMADILLO_INCLUDE_DIRS})
+ add_executable(foo foo.cc)
+ target_link_libraries(foo ${ARMADILLO_LIBRARIES})
+
+This module sets the following variables:
+
+::
+
+ ARMADILLO_FOUND - set to true if the library is found
+ ARMADILLO_INCLUDE_DIRS - list of required include directories
+ ARMADILLO_LIBRARIES - list of libraries to be linked
+ ARMADILLO_VERSION_MAJOR - major version number
+ ARMADILLO_VERSION_MINOR - minor version number
+ ARMADILLO_VERSION_PATCH - patch version number
+ ARMADILLO_VERSION_STRING - version number as a string (ex: "1.0.4")
+ ARMADILLO_VERSION_NAME - name of the version (ex: "Antipodean Antileech")
+#]=======================================================================]
+
+find_path(ARMADILLO_INCLUDE_DIR
+ NAMES armadillo
+ PATHS "$ENV{ProgramFiles}/Armadillo/include"
+ )
+mark_as_advanced(ARMADILLO_INCLUDE_DIR)
+
+if(ARMADILLO_INCLUDE_DIR)
+ # ------------------------------------------------------------------------
+ # Extract version information from <armadillo>
+ # ------------------------------------------------------------------------
+
+ # WARNING: Early releases of Armadillo didn't have the arma_version.hpp file.
+ # (e.g. v.0.9.8-1 in ubuntu maverick packages (2001-03-15))
+ # If the file is missing, set all values to 0
+ set(ARMADILLO_VERSION_MAJOR 0)
+ set(ARMADILLO_VERSION_MINOR 0)
+ set(ARMADILLO_VERSION_PATCH 0)
+ set(ARMADILLO_VERSION_NAME "EARLY RELEASE")
+
+ if(EXISTS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/arma_version.hpp")
+
+ # Read and parse armdillo version header file for version number
+ file(STRINGS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/arma_version.hpp" _ARMA_HEADER_CONTENTS REGEX "#define ARMA_VERSION_[A-Z]+ ")
+ string(REGEX REPLACE ".*#define ARMA_VERSION_MAJOR ([0-9]+).*" "\\1" ARMADILLO_VERSION_MAJOR "${_ARMA_HEADER_CONTENTS}")
+ string(REGEX REPLACE ".*#define ARMA_VERSION_MINOR ([0-9]+).*" "\\1" ARMADILLO_VERSION_MINOR "${_ARMA_HEADER_CONTENTS}")
+ string(REGEX REPLACE ".*#define ARMA_VERSION_PATCH ([0-9]+).*" "\\1" ARMADILLO_VERSION_PATCH "${_ARMA_HEADER_CONTENTS}")
+
+ # WARNING: The number of spaces before the version name is not one.
+ string(REGEX REPLACE ".*#define ARMA_VERSION_NAME\ +\"([0-9a-zA-Z\ _-]+)\".*" "\\1" ARMADILLO_VERSION_NAME "${_ARMA_HEADER_CONTENTS}")
+
+ endif()
+
+ set(ARMADILLO_VERSION_STRING "${ARMADILLO_VERSION_MAJOR}.${ARMADILLO_VERSION_MINOR}.${ARMADILLO_VERSION_PATCH}")
+endif ()
+
+if(EXISTS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/config.hpp")
+ file(STRINGS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/config.hpp" _ARMA_CONFIG_CONTENTS REGEX "^#define ARMA_USE_[A-Z]+")
+ string(REGEX MATCH "ARMA_USE_WRAPPER" _ARMA_USE_WRAPPER "${_ARMA_CONFIG_CONTENTS}")
+ string(REGEX MATCH "ARMA_USE_LAPACK" _ARMA_USE_LAPACK "${_ARMA_CONFIG_CONTENTS}")
+ string(REGEX MATCH "ARMA_USE_BLAS" _ARMA_USE_BLAS "${_ARMA_CONFIG_CONTENTS}")
+ string(REGEX MATCH "ARMA_USE_ARPACK" _ARMA_USE_ARPACK "${_ARMA_CONFIG_CONTENTS}")
+ string(REGEX MATCH "ARMA_USE_HDF5" _ARMA_USE_HDF5 "${_ARMA_CONFIG_CONTENTS}")
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+# If _ARMA_USE_WRAPPER is set, then we just link to armadillo, but if it's not then we need support libraries instead
+set(_ARMA_SUPPORT_LIBRARIES)
+
+if(_ARMA_USE_WRAPPER)
+ # Link to the armadillo wrapper library.
+ find_library(ARMADILLO_LIBRARY
+ NAMES armadillo
+ NAMES_PER_DIR
+ PATHS
+ "$ENV{ProgramFiles}/Armadillo/lib"
+ "$ENV{ProgramFiles}/Armadillo/lib64"
+ "$ENV{ProgramFiles}/Armadillo"
+ )
+ mark_as_advanced(ARMADILLO_LIBRARY)
+ set(_ARMA_REQUIRED_VARS ARMADILLO_LIBRARY)
+else()
+ # Link directly to individual components.
+ set(ARMADILLO_LIBRARY "")
+ foreach(pkg
+ LAPACK
+ BLAS
+ ARPACK
+ HDF5
+ )
+ if(_ARMA_USE_${pkg})
+ find_package(${pkg} QUIET)
+ list(APPEND _ARMA_REQUIRED_VARS "${pkg}_FOUND")
+ if(${pkg}_FOUND)
+ list(APPEND _ARMA_SUPPORT_LIBRARIES ${${pkg}_LIBRARIES})
+ endif()
+ endif()
+ endforeach()
+endif()
+
+find_package_handle_standard_args(Armadillo
+ REQUIRED_VARS ARMADILLO_INCLUDE_DIR ${_ARMA_REQUIRED_VARS}
+ VERSION_VAR ARMADILLO_VERSION_STRING)
+
+if (ARMADILLO_FOUND)
+ set(ARMADILLO_INCLUDE_DIRS ${ARMADILLO_INCLUDE_DIR})
+ set(ARMADILLO_LIBRARIES ${ARMADILLO_LIBRARY} ${_ARMA_SUPPORT_LIBRARIES})
+endif ()
+
+# Clean up internal variables
+unset(_ARMA_REQUIRED_VARS)
+unset(_ARMA_SUPPORT_LIBRARIES)
+unset(_ARMA_USE_WRAPPER)
+unset(_ARMA_USE_LAPACK)
+unset(_ARMA_USE_BLAS)
+unset(_ARMA_USE_ARPACK)
+unset(_ARMA_USE_HDF5)
+unset(_ARMA_CONFIG_CONTENTS)
+unset(_ARMA_HEADER_CONTENTS)
diff --git a/Modules/FindBISON.cmake b/Modules/FindBISON.cmake
new file mode 100644
index 0000000..3515bf0
--- /dev/null
+++ b/Modules/FindBISON.cmake
@@ -0,0 +1,307 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindBISON
+---------
+
+Find ``bison`` executable and provide a macro to generate custom build rules.
+
+The module defines the following variables:
+
+``BISON_EXECUTABLE``
+ path to the ``bison`` program
+
+``BISON_VERSION``
+ version of ``bison``
+
+``BISON_FOUND``
+ "True" if the program was found
+
+The minimum required version of ``bison`` can be specified using the
+standard CMake syntax, e.g. :command:`find_package(BISON 2.1.3)`.
+
+If ``bison`` is found, the module defines the macro::
+
+ BISON_TARGET(<Name> <YaccInput> <CodeOutput>
+ [COMPILE_FLAGS <flags>]
+ [DEFINES_FILE <file>]
+ [VERBOSE [<file>]]
+ [REPORT_FILE <file>]
+ )
+
+which will create a custom rule to generate a parser. ``<YaccInput>`` is
+the path to a yacc file. ``<CodeOutput>`` is the name of the source file
+generated by bison. A header file is also be generated, and contains
+the token list.
+
+.. versionchanged:: 3.14
+ When :policy:`CMP0088` is set to ``NEW``, ``bison`` runs in the
+ :variable:`CMAKE_CURRENT_BINARY_DIR` directory.
+
+The options are:
+
+``COMPILE_FLAGS <flags>``
+ Specify flags to be added to the ``bison`` command line.
+
+``DEFINES_FILE <file>``
+ .. versionadded:: 3.4
+
+ Specify a non-default header ``<file>`` to be generated by ``bison``.
+
+``VERBOSE [<file>]``
+ Tell ``bison`` to write a report file of the grammar and parser.
+
+ .. deprecated:: 3.7
+ If ``<file>`` is given, it specifies path the report file is copied to.
+ ``[<file>]`` is left for backward compatibility of this module.
+ Use ``VERBOSE REPORT_FILE <file>``.
+
+``REPORT_FILE <file>``
+ .. versionadded:: 3.7
+
+ Specify a non-default report ``<file>``, if generated.
+
+The macro defines the following variables:
+
+``BISON_<Name>_DEFINED``
+ ``True`` is the macro ran successfully
+
+``BISON_<Name>_INPUT``
+ The input source file, an alias for <YaccInput>
+
+``BISON_<Name>_OUTPUT_SOURCE``
+ The source file generated by bison
+
+``BISON_<Name>_OUTPUT_HEADER``
+ The header file generated by bison
+
+``BISON_<Name>_OUTPUTS``
+ All files generated by bison including the source, the header and the report
+
+``BISON_<Name>_COMPILE_FLAGS``
+ Options used in the ``bison`` command line
+
+Example usage:
+
+.. code-block:: cmake
+
+ find_package(BISON)
+ BISON_TARGET(MyParser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp
+ DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/parser.h)
+ add_executable(Foo main.cpp ${BISON_MyParser_OUTPUTS})
+#]=======================================================================]
+
+find_program(BISON_EXECUTABLE NAMES bison win-bison win_bison DOC "path to the bison executable")
+mark_as_advanced(BISON_EXECUTABLE)
+
+if(BISON_EXECUTABLE)
+ # the bison commands should be executed with the C locale, otherwise
+ # the message (which are parsed) may be translated
+ set(_Bison_SAVED_LC_ALL "$ENV{LC_ALL}")
+ set(ENV{LC_ALL} C)
+
+ execute_process(COMMAND ${BISON_EXECUTABLE} --version
+ OUTPUT_VARIABLE BISON_version_output
+ ERROR_VARIABLE BISON_version_error
+ RESULT_VARIABLE BISON_version_result
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ set(ENV{LC_ALL} ${_Bison_SAVED_LC_ALL})
+
+ if(NOT ${BISON_version_result} EQUAL 0)
+ message(SEND_ERROR "Command \"${BISON_EXECUTABLE} --version\" failed with output:\n${BISON_version_error}")
+ else()
+ # Bison++
+ if("${BISON_version_output}" MATCHES "^bison\\+\\+ Version ([^,]+)")
+ set(BISON_VERSION "${CMAKE_MATCH_1}")
+ # GNU Bison
+ elseif("${BISON_version_output}" MATCHES "^bison \\(GNU Bison\\) ([^\n]+)\n")
+ set(BISON_VERSION "${CMAKE_MATCH_1}")
+ elseif("${BISON_version_output}" MATCHES "^GNU Bison (version )?([^\n]+)")
+ set(BISON_VERSION "${CMAKE_MATCH_2}")
+ endif()
+ endif()
+
+ # internal macro
+ # sets BISON_TARGET_cmdopt
+ macro(BISON_TARGET_option_extraopts Options)
+ set(BISON_TARGET_cmdopt "")
+ set(BISON_TARGET_extraopts "${Options}")
+ separate_arguments(BISON_TARGET_extraopts)
+ list(APPEND BISON_TARGET_cmdopt ${BISON_TARGET_extraopts})
+ endmacro()
+
+ # internal macro
+ # sets BISON_TARGET_output_header and BISON_TARGET_cmdopt
+ macro(BISON_TARGET_option_defines BisonOutput Header)
+ if("${Header}" STREQUAL "")
+ # default header path generated by bison (see option -d)
+ string(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\2" _fileext "${BisonOutput}")
+ string(REPLACE "c" "h" _fileext ${_fileext})
+ string(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\1${_fileext}"
+ BISON_TARGET_output_header "${BisonOutput}")
+ list(APPEND BISON_TARGET_cmdopt "-d")
+ else()
+ set(BISON_TARGET_output_header "${Header}")
+ list(APPEND BISON_TARGET_cmdopt "--defines=${BISON_TARGET_output_header}")
+ endif()
+ endmacro()
+
+ # internal macro
+ # sets BISON_TARGET_verbose_file and BISON_TARGET_cmdopt
+ macro(BISON_TARGET_option_report_file BisonOutput ReportFile)
+ if("${ReportFile}" STREQUAL "")
+ get_filename_component(BISON_TARGET_output_path "${BisonOutput}" PATH)
+ get_filename_component(BISON_TARGET_output_name "${BisonOutput}" NAME_WE)
+ set(BISON_TARGET_verbose_file
+ "${BISON_TARGET_output_path}/${BISON_TARGET_output_name}.output")
+ else()
+ set(BISON_TARGET_verbose_file "${ReportFile}")
+ list(APPEND BISON_TARGET_cmdopt "--report-file=${BISON_TARGET_verbose_file}")
+ endif()
+ if(NOT IS_ABSOLUTE "${BISON_TARGET_verbose_file}")
+ cmake_policy(GET CMP0088 _BISON_CMP0088
+ PARENT_SCOPE # undocumented, do not use outside of CMake
+ )
+ if("x${_BISON_CMP0088}x" STREQUAL "xNEWx")
+ set(BISON_TARGET_verbose_file "${CMAKE_CURRENT_BINARY_DIR}/${BISON_TARGET_verbose_file}")
+ else()
+ set(BISON_TARGET_verbose_file "${CMAKE_CURRENT_SOURCE_DIR}/${BISON_TARGET_verbose_file}")
+ endif()
+ unset(_BISON_CMP0088)
+ endif()
+ endmacro()
+
+ # internal macro
+ # adds a custom command and sets
+ # BISON_TARGET_cmdopt, BISON_TARGET_extraoutputs
+ macro(BISON_TARGET_option_verbose Name BisonOutput filename)
+ cmake_policy(GET CMP0088 _BISON_CMP0088
+ PARENT_SCOPE # undocumented, do not use outside of CMake
+ )
+ set(_BISON_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+ if("x${_BISON_CMP0088}x" STREQUAL "xNEWx")
+ set(_BISON_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ endif()
+ unset(_BISON_CMP0088)
+
+ list(APPEND BISON_TARGET_cmdopt "--verbose")
+ list(APPEND BISON_TARGET_outputs
+ "${BISON_TARGET_verbose_file}")
+ if (NOT "${filename}" STREQUAL "")
+ if(IS_ABSOLUTE "${filename}")
+ set(BISON_TARGET_verbose_extra_file "${filename}")
+ else()
+ set(BISON_TARGET_verbose_extra_file "${_BISON_WORKING_DIRECTORY}/${filename}")
+ endif()
+
+ add_custom_command(OUTPUT ${BISON_TARGET_verbose_extra_file}
+ COMMAND ${CMAKE_COMMAND} -E copy
+ "${BISON_TARGET_verbose_file}"
+ "${filename}"
+ VERBATIM
+ DEPENDS
+ "${BISON_TARGET_verbose_file}"
+ COMMENT "[BISON][${Name}] Copying bison verbose table to ${filename}"
+ WORKING_DIRECTORY ${_BISON_WORKING_DIRECTORY})
+ list(APPEND BISON_TARGET_extraoutputs
+ "${BISON_TARGET_verbose_extra_file}")
+ unset(BISON_TARGET_verbose_extra_file)
+ unset(_BISON_WORKING_DIRECTORY)
+ endif()
+ endmacro()
+
+ #============================================================
+ # BISON_TARGET (public macro)
+ #============================================================
+ #
+ macro(BISON_TARGET Name BisonInput BisonOutput)
+ set(BISON_TARGET_outputs "${BisonOutput}")
+ set(BISON_TARGET_extraoutputs "")
+
+ # Parsing parameters
+ set(BISON_TARGET_PARAM_OPTIONS
+ )
+ set(BISON_TARGET_PARAM_ONE_VALUE_KEYWORDS
+ COMPILE_FLAGS
+ DEFINES_FILE
+ REPORT_FILE
+ )
+ set(BISON_TARGET_PARAM_MULTI_VALUE_KEYWORDS
+ VERBOSE
+ )
+ cmake_parse_arguments(
+ BISON_TARGET_ARG
+ "${BISON_TARGET_PARAM_OPTIONS}"
+ "${BISON_TARGET_PARAM_ONE_VALUE_KEYWORDS}"
+ "${BISON_TARGET_PARAM_MULTI_VALUE_KEYWORDS}"
+ ${ARGN}
+ )
+
+ if(NOT "${BISON_TARGET_ARG_UNPARSED_ARGUMENTS}" STREQUAL "")
+ message(SEND_ERROR "Usage")
+ elseif("${BISON_TARGET_ARG_VERBOSE}" MATCHES ";")
+ # [VERBOSE [<file>] hack: <file> is non-multi value by usage
+ message(SEND_ERROR "Usage")
+ else()
+
+ BISON_TARGET_option_extraopts("${BISON_TARGET_ARG_COMPILE_FLAGS}")
+ BISON_TARGET_option_defines("${BisonOutput}" "${BISON_TARGET_ARG_DEFINES_FILE}")
+ BISON_TARGET_option_report_file("${BisonOutput}" "${BISON_TARGET_ARG_REPORT_FILE}")
+ if(NOT "${BISON_TARGET_ARG_VERBOSE}" STREQUAL "")
+ BISON_TARGET_option_verbose(${Name} ${BisonOutput} "${BISON_TARGET_ARG_VERBOSE}")
+ else()
+ # [VERBOSE [<file>]] is used with no argument or is not used
+ set(BISON_TARGET_args "${ARGN}")
+ list(FIND BISON_TARGET_args "VERBOSE" BISON_TARGET_args_indexof_verbose)
+ if(${BISON_TARGET_args_indexof_verbose} GREATER -1)
+ # VERBOSE is used without <file>
+ BISON_TARGET_option_verbose(${Name} ${BisonOutput} "")
+ endif()
+ endif()
+
+ list(APPEND BISON_TARGET_outputs "${BISON_TARGET_output_header}")
+
+ cmake_policy(GET CMP0088 _BISON_CMP0088
+ PARENT_SCOPE # undocumented, do not use outside of CMake
+ )
+ set(_BISON_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+ set(_BisonInput "${BisonInput}")
+ if("x${_BISON_CMP0088}x" STREQUAL "xNEWx")
+ set(_BISON_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ if(NOT IS_ABSOLUTE "${_BisonInput}")
+ set(_BisonInput "${CMAKE_CURRENT_SOURCE_DIR}/${_BisonInput}")
+ endif()
+ endif()
+ unset(_BISON_CMP0088)
+
+ add_custom_command(OUTPUT ${BISON_TARGET_outputs}
+ COMMAND ${BISON_EXECUTABLE} ${BISON_TARGET_cmdopt} -o ${BisonOutput} ${_BisonInput}
+ VERBATIM
+ DEPENDS ${_BisonInput}
+ COMMENT "[BISON][${Name}] Building parser with bison ${BISON_VERSION}"
+ WORKING_DIRECTORY ${_BISON_WORKING_DIRECTORY})
+
+ unset(_BISON_WORKING_DIRECTORY)
+
+ # define target variables
+ set(BISON_${Name}_DEFINED TRUE)
+ set(BISON_${Name}_INPUT ${_BisonInput})
+ set(BISON_${Name}_OUTPUTS ${BISON_TARGET_outputs} ${BISON_TARGET_extraoutputs})
+ set(BISON_${Name}_COMPILE_FLAGS ${BISON_TARGET_cmdopt})
+ set(BISON_${Name}_OUTPUT_SOURCE "${BisonOutput}")
+ set(BISON_${Name}_OUTPUT_HEADER "${BISON_TARGET_output_header}")
+
+ unset(_BisonInput)
+
+ endif()
+ endmacro()
+ #
+ #============================================================
+
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(BISON REQUIRED_VARS BISON_EXECUTABLE
+ VERSION_VAR BISON_VERSION)
diff --git a/Modules/FindBLAS.cmake b/Modules/FindBLAS.cmake
new file mode 100644
index 0000000..510f47d
--- /dev/null
+++ b/Modules/FindBLAS.cmake
@@ -0,0 +1,1092 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindBLAS
+--------
+
+Find Basic Linear Algebra Subprograms (BLAS) library
+
+This module finds an installed Fortran library that implements the
+BLAS linear-algebra interface (see http://www.netlib.org/blas/).
+
+The approach follows that taken for the ``autoconf`` macro file,
+``acx_blas.m4`` (distributed at
+http://ac-archive.sourceforge.net/ac-archive/acx_blas.html).
+
+Input Variables
+^^^^^^^^^^^^^^^
+
+The following variables may be set to influence this module's behavior:
+
+``BLA_STATIC``
+ if ``ON`` use static linkage
+
+``BLA_VENDOR``
+ If set, checks only the specified vendor, if not set checks all the
+ possibilities. List of vendors valid in this module:
+
+ * ``Goto``
+ * ``FlexiBLAS``
+ * ``OpenBLAS``
+ * ``FLAME``
+ * ``ATLAS PhiPACK``
+ * ``CXML``
+ * ``DXML``
+ * ``SunPerf``
+ * ``SCSL``
+ * ``SGIMATH``
+ * ``IBMESSL``
+ * ``Intel10_32`` (intel mkl v10 32 bit, threaded code)
+ * ``Intel10_64lp`` (intel mkl v10+ 64 bit, threaded code, lp64 model)
+ * ``Intel10_64lp_seq`` (intel mkl v10+ 64 bit, sequential code, lp64 model)
+ * ``Intel10_64ilp`` (intel mkl v10+ 64 bit, threaded code, ilp64 model)
+ * ``Intel10_64ilp_seq`` (intel mkl v10+ 64 bit, sequential code, ilp64 model)
+ * ``Intel10_64_dyn`` (intel mkl v10+ 64 bit, single dynamic library)
+ * ``Intel`` (obsolete versions of mkl 32 and 64 bit)
+ * ``ACML``
+ * ``ACML_MP``
+ * ``ACML_GPU``
+ * ``Apple``
+ * ``NAS``
+ * ``Arm``
+ * ``Arm_mp``
+ * ``Arm_ilp64``
+ * ``Arm_ilp64_mp``
+ * ``EML``
+ * ``EML_mt``
+ * ``Fujitsu_SSL2`` (Fujitsu serial blas / lapack)
+ * ``Fujitsu_SSL2BLAMP`` (Fujitsu parallel blas / lapack)
+ * ``Generic``
+
+ .. versionadded:: 3.6
+ ``OpenBLAS`` support.
+
+ .. versionadded:: 3.11
+ ``FLAME`` support.
+
+ .. versionadded:: 3.13
+ Added ILP64 MKL variants (``Intel10_64ilp``, ``Intel10_64ilp_seq``).
+
+ .. versionadded:: 3.17
+ Added single dynamic library MKL variant (``Intel10_64_dyn``).
+
+ .. versionadded:: 3.18
+ Arm Performance Libraries support (``Arm``, ``Arm_mp``, ``Arm_ilp64``,
+ ``Arm_ilp64_mp``).
+
+ .. versionadded:: 3.19
+ ``FlexiBLAS`` support.
+
+ .. versionadded:: 3.20
+ Elbrus Math Library support (``EML``, ``EML_mt``).
+ Fujitsu SSL2 Library support (``Fujitsu_SSL2``, ``Fujitsu_SSL2BLAMP``)
+
+``BLA_F95``
+ if ``ON`` tries to find the BLAS95 interfaces
+
+``BLA_PREFER_PKGCONFIG``
+ .. versionadded:: 3.11
+
+ if set ``pkg-config`` will be used to search for a BLAS library first
+ and if one is found that is preferred
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.18
+
+This module defines the following :prop_tgt:`IMPORTED` target:
+
+``BLAS::BLAS``
+ The libraries to use for BLAS, if found.
+
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``BLAS_FOUND``
+ library implementing the BLAS interface is found
+``BLAS_LINKER_FLAGS``
+ uncached list of required linker flags (excluding ``-l`` and ``-L``).
+``BLAS_LIBRARIES``
+ uncached list of libraries (using full path name) to link against
+ to use BLAS (may be empty if compiler implicitly links BLAS)
+``BLAS95_LIBRARIES``
+ uncached list of libraries (using full path name) to link against
+ to use BLAS95 interface
+``BLAS95_FOUND``
+ library implementing the BLAS95 interface is found
+
+.. note::
+
+ C, CXX or Fortran must be enabled to detect a BLAS library.
+ C or CXX must be enabled to use Intel Math Kernel Library (MKL).
+
+ For example, to use Intel MKL libraries and/or Intel compiler:
+
+ .. code-block:: cmake
+
+ set(BLA_VENDOR Intel10_64lp)
+ find_package(BLAS)
+
+Hints
+^^^^^
+
+``MKLROOT``
+ .. versionadded:: 3.15
+
+ Set this environment variable to a directory that contains an MKL
+ installation, or add the directory to the dynamic library loader environment
+ variable for your platform (``LIB``, ``DYLD_LIBRARY_PATH`` or
+ ``LD_LIBRARY_PATH``).
+
+#]=======================================================================]
+
+# Check the language being used
+if(NOT (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED))
+ if(BLAS_FIND_REQUIRED)
+ message(FATAL_ERROR "FindBLAS requires Fortran, C, or C++ to be enabled.")
+ else()
+ message(STATUS "Looking for BLAS... - NOT found (Unsupported languages)")
+ return()
+ endif()
+endif()
+
+function(_add_blas_target)
+ if(BLAS_FOUND AND NOT TARGET BLAS::BLAS)
+ add_library(BLAS::BLAS INTERFACE IMPORTED)
+ if(BLAS_LIBRARIES)
+ set_target_properties(BLAS::BLAS PROPERTIES
+ INTERFACE_LINK_LIBRARIES "${BLAS_LIBRARIES}"
+ )
+ endif()
+ if(BLAS_LINKER_FLAGS)
+ set_target_properties(BLAS::BLAS PROPERTIES
+ INTERFACE_LINK_OPTIONS "${BLAS_LINKER_FLAGS}"
+ )
+ endif()
+ endif()
+endfunction()
+
+if(CMAKE_Fortran_COMPILER_LOADED)
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckFortranFunctionExists.cmake)
+else()
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckFunctionExists.cmake)
+endif()
+include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+cmake_push_check_state()
+set(CMAKE_REQUIRED_QUIET ${BLAS_FIND_QUIETLY})
+
+if(BLA_PREFER_PKGCONFIG)
+ find_package(PkgConfig)
+ pkg_check_modules(PKGC_BLAS blas)
+ if(PKGC_BLAS_FOUND)
+ set(BLAS_FOUND ${PKGC_BLAS_FOUND})
+ set(BLAS_LIBRARIES "${PKGC_BLAS_LINK_LIBRARIES}")
+ _add_blas_target()
+ return()
+ endif()
+endif()
+
+set(_blas_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+if(BLA_STATIC)
+ if(WIN32)
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ else()
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ endif()
+else()
+ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ # for ubuntu's libblas3gf and liblapack3gf packages
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} .so.3gf)
+ endif()
+endif()
+
+# TODO: move this stuff to a separate module
+
+macro(CHECK_BLAS_LIBRARIES LIBRARIES _prefix _name _flags _list _threadlibs _addlibdir _subdirs)
+ # This macro checks for the existence of the combination of fortran libraries
+ # given by _list. If the combination is found, this macro checks (using the
+ # Check_Fortran_Function_Exists macro) whether can link against that library
+ # combination using the name of a routine given by _name using the linker
+ # flags given by _flags. If the combination of libraries is found and passes
+ # the link test, LIBRARIES is set to the list of complete library paths that
+ # have been found. Otherwise, LIBRARIES is set to FALSE.
+
+ # N.B. _prefix is the prefix applied to the names of all cached variables that
+ # are generated internally and marked advanced by this macro.
+ # _addlibdir is a list of additional search paths. _subdirs is a list of path
+ # suffixes to be used by find_library().
+
+ set(_libraries_work TRUE)
+ set(${LIBRARIES})
+ set(_combined_name)
+
+ set(_extaddlibdir "${_addlibdir}")
+ if(WIN32)
+ list(APPEND _extaddlibdir ENV LIB)
+ elseif(APPLE)
+ list(APPEND _extaddlibdir ENV DYLD_LIBRARY_PATH)
+ else()
+ list(APPEND _extaddlibdir ENV LD_LIBRARY_PATH)
+ endif()
+ list(APPEND _extaddlibdir "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}")
+
+ foreach(_library ${_list} ${_threadlibs})
+ if(_library MATCHES "^-Wl,--(start|end)-group$")
+ # Respect linker flags like --start/end-group (required by MKL)
+ set(${LIBRARIES} ${${LIBRARIES}} "${_library}")
+ else()
+ string(REGEX REPLACE "[^A-Za-z0-9]" "_" _lib_var "${_library}")
+ set(_combined_name ${_combined_name}_${_lib_var})
+ if(_libraries_work)
+ find_library(${_prefix}_${_lib_var}_LIBRARY
+ NAMES ${_library}
+ NAMES_PER_DIR
+ PATHS ${_extaddlibdir}
+ PATH_SUFFIXES ${_subdirs}
+ )
+ mark_as_advanced(${_prefix}_${_lib_var}_LIBRARY)
+ set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_lib_var}_LIBRARY})
+ set(_libraries_work ${${_prefix}_${_lib_var}_LIBRARY})
+ endif()
+ endif()
+ endforeach()
+
+ foreach(_flag ${_flags})
+ string(REGEX REPLACE "[^A-Za-z0-9]" "_" _flag_var "${_flag}")
+ set(_combined_name ${_combined_name}_${_flag_var})
+ endforeach()
+ if(_libraries_work)
+ # Test this combination of libraries.
+ set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_threadlibs})
+ if(CMAKE_Fortran_COMPILER_LOADED)
+ check_fortran_function_exists("${_name}" ${_prefix}${_combined_name}_WORKS)
+ else()
+ check_function_exists("${_name}_" ${_prefix}${_combined_name}_WORKS)
+ endif()
+ set(CMAKE_REQUIRED_LIBRARIES)
+ set(_libraries_work ${${_prefix}${_combined_name}_WORKS})
+ endif()
+
+ if(_libraries_work)
+ if("${_list}" STREQUAL "")
+ set(${LIBRARIES} "${LIBRARIES}-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
+ else()
+ set(${LIBRARIES} ${${LIBRARIES}} ${_threadlibs})
+ endif()
+ else()
+ set(${LIBRARIES} FALSE)
+ endif()
+endmacro()
+
+set(BLAS_LINKER_FLAGS)
+set(BLAS_LIBRARIES)
+set(BLAS95_LIBRARIES)
+set(_blas_fphsa_req_var BLAS_LIBRARIES)
+if(NOT $ENV{BLA_VENDOR} STREQUAL "")
+ set(BLA_VENDOR $ENV{BLA_VENDOR})
+else()
+ if(NOT BLA_VENDOR)
+ set(BLA_VENDOR "All")
+ endif()
+endif()
+
+# Implicitly linked BLAS libraries?
+if(BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ ""
+ ""
+ ""
+ ""
+ )
+ endif()
+ if(BLAS_WORKS)
+ set(_blas_fphsa_req_var BLAS_WORKS)
+ endif()
+endif()
+
+# BLAS in the Intel MKL 10+ library?
+if(BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ if(CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED)
+ # System-specific settings
+ if(WIN32)
+ if(BLA_STATIC)
+ set(BLAS_mkl_DLL_SUFFIX "")
+ else()
+ set(BLAS_mkl_DLL_SUFFIX "_dll")
+ endif()
+ else()
+ if(BLA_STATIC)
+ set(BLAS_mkl_START_GROUP "-Wl,--start-group")
+ set(BLAS_mkl_END_GROUP "-Wl,--end-group")
+ else()
+ set(BLAS_mkl_START_GROUP "")
+ set(BLAS_mkl_END_GROUP "")
+ endif()
+ # Switch to GNU Fortran support layer if needed (but not on Apple, where MKL does not provide it)
+ if(CMAKE_Fortran_COMPILER_LOADED AND CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
+ set(BLAS_mkl_INTFACE "gf")
+ set(BLAS_mkl_THREADING "gnu")
+ set(BLAS_mkl_OMP "gomp")
+ else()
+ set(BLAS_mkl_INTFACE "intel")
+ set(BLAS_mkl_THREADING "intel")
+ set(BLAS_mkl_OMP "iomp5")
+ endif()
+ set(BLAS_mkl_LM "-lm")
+ set(BLAS_mkl_LDL "-ldl")
+ endif()
+
+ if(BLAS_FIND_QUIETLY OR NOT BLAS_FIND_REQUIRED)
+ find_package(Threads)
+ else()
+ find_package(Threads REQUIRED)
+ endif()
+
+ if(BLA_VENDOR MATCHES "_64ilp")
+ set(BLAS_mkl_ILP_MODE "ilp64")
+ else()
+ set(BLAS_mkl_ILP_MODE "lp64")
+ endif()
+
+ set(BLAS_SEARCH_LIBS "")
+
+ if(BLA_F95)
+ set(BLAS_mkl_SEARCH_SYMBOL "sgemm_f95")
+ set(_LIBRARIES BLAS95_LIBRARIES)
+ if(WIN32)
+ # Find the main file (32-bit or 64-bit)
+ set(BLAS_SEARCH_LIBS_WIN_MAIN "")
+ if(BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
+ list(APPEND BLAS_SEARCH_LIBS_WIN_MAIN
+ "mkl_blas95${BLAS_mkl_DLL_SUFFIX} mkl_intel_c${BLAS_mkl_DLL_SUFFIX}")
+ endif()
+
+ if(BLA_VENDOR MATCHES "^Intel10_64i?lp" OR BLA_VENDOR STREQUAL "All")
+ list(APPEND BLAS_SEARCH_LIBS_WIN_MAIN
+ "mkl_blas95_${BLAS_mkl_ILP_MODE}${BLAS_mkl_DLL_SUFFIX} mkl_intel_${BLAS_mkl_ILP_MODE}${BLAS_mkl_DLL_SUFFIX}")
+ endif()
+
+ # Add threading/sequential libs
+ set(BLAS_SEARCH_LIBS_WIN_THREAD "")
+ if(BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR STREQUAL "All")
+ # old version
+ list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
+ "libguide40 mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
+ # mkl >= 10.3
+ list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
+ "libiomp5md mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
+ endif()
+ if(BLA_VENDOR MATCHES "^Intel10_64i?lp_seq$" OR BLA_VENDOR STREQUAL "All")
+ list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
+ "mkl_sequential${BLAS_mkl_DLL_SUFFIX}")
+ endif()
+
+ # Cartesian product of the above
+ foreach(MAIN ${BLAS_SEARCH_LIBS_WIN_MAIN})
+ foreach(THREAD ${BLAS_SEARCH_LIBS_WIN_THREAD})
+ list(APPEND BLAS_SEARCH_LIBS
+ "${MAIN} ${THREAD} mkl_core${BLAS_mkl_DLL_SUFFIX}")
+ endforeach()
+ endforeach()
+ else()
+ if(BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
+ # old version
+ list(APPEND BLAS_SEARCH_LIBS
+ "mkl_blas95 mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core guide")
+
+ # mkl >= 10.3
+ list(APPEND BLAS_SEARCH_LIBS
+ "${BLAS_mkl_START_GROUP} mkl_blas95 mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_END_GROUP} ${BLAS_mkl_OMP}")
+ endif()
+ if(BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR STREQUAL "All")
+ # old version
+ list(APPEND BLAS_SEARCH_LIBS
+ "mkl_blas95 mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_THREADING}_thread mkl_core guide")
+
+ # mkl >= 10.3
+ list(APPEND BLAS_SEARCH_LIBS
+ "${BLAS_mkl_START_GROUP} mkl_blas95_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_END_GROUP} ${BLAS_mkl_OMP}")
+ endif()
+ if(BLA_VENDOR MATCHES "^Intel10_64i?lp_seq$" OR BLA_VENDOR STREQUAL "All")
+ list(APPEND BLAS_SEARCH_LIBS
+ "${BLAS_mkl_START_GROUP} mkl_blas95_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_sequential mkl_core ${BLAS_mkl_END_GROUP}")
+ endif()
+ endif()
+ else()
+ set(BLAS_mkl_SEARCH_SYMBOL sgemm)
+ set(_LIBRARIES BLAS_LIBRARIES)
+ if(WIN32)
+ # Find the main file (32-bit or 64-bit)
+ set(BLAS_SEARCH_LIBS_WIN_MAIN "")
+ if(BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
+ list(APPEND BLAS_SEARCH_LIBS_WIN_MAIN
+ "mkl_intel_c${BLAS_mkl_DLL_SUFFIX}")
+ endif()
+ if(BLA_VENDOR MATCHES "^Intel10_64i?lp" OR BLA_VENDOR STREQUAL "All")
+ list(APPEND BLAS_SEARCH_LIBS_WIN_MAIN
+ "mkl_intel_${BLAS_mkl_ILP_MODE}${BLAS_mkl_DLL_SUFFIX}")
+ endif()
+
+ # Add threading/sequential libs
+ set(BLAS_SEARCH_LIBS_WIN_THREAD "")
+ if(BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
+ list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
+ "libiomp5md mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
+ endif()
+ if(BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR STREQUAL "All")
+ # old version
+ list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
+ "libguide40 mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
+ # mkl >= 10.3
+ list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
+ "libiomp5md mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
+ endif()
+ if(BLA_VENDOR MATCHES "^Intel10_64i?lp_seq$" OR BLA_VENDOR STREQUAL "All")
+ list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
+ "mkl_sequential${BLAS_mkl_DLL_SUFFIX}")
+ endif()
+
+ # Cartesian product of the above
+ foreach(MAIN ${BLAS_SEARCH_LIBS_WIN_MAIN})
+ foreach(THREAD ${BLAS_SEARCH_LIBS_WIN_THREAD})
+ list(APPEND BLAS_SEARCH_LIBS
+ "${MAIN} ${THREAD} mkl_core${BLAS_mkl_DLL_SUFFIX}")
+ endforeach()
+ endforeach()
+ else()
+ if(BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
+ # old version
+ list(APPEND BLAS_SEARCH_LIBS
+ "mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core guide")
+
+ # mkl >= 10.3
+ list(APPEND BLAS_SEARCH_LIBS
+ "${BLAS_mkl_START_GROUP} mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_END_GROUP} ${BLAS_mkl_OMP}")
+ endif()
+ if(BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR STREQUAL "All")
+ # old version
+ list(APPEND BLAS_SEARCH_LIBS
+ "mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_THREADING}_thread mkl_core guide")
+
+ # mkl >= 10.3
+ list(APPEND BLAS_SEARCH_LIBS
+ "${BLAS_mkl_START_GROUP} mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_END_GROUP} ${BLAS_mkl_OMP}")
+ endif()
+ if(BLA_VENDOR MATCHES "^Intel10_64i?lp_seq$" OR BLA_VENDOR STREQUAL "All")
+ list(APPEND BLAS_SEARCH_LIBS
+ "${BLAS_mkl_START_GROUP} mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_sequential mkl_core ${BLAS_mkl_END_GROUP}")
+ endif()
+
+ #older versions of intel mkl libs
+ if(BLA_VENDOR STREQUAL "Intel" OR BLA_VENDOR STREQUAL "All")
+ list(APPEND BLAS_SEARCH_LIBS
+ "mkl")
+ list(APPEND BLAS_SEARCH_LIBS
+ "mkl_ia32")
+ list(APPEND BLAS_SEARCH_LIBS
+ "mkl_em64t")
+ endif()
+ endif()
+ endif()
+
+ if(BLA_VENDOR MATCHES "^Intel10_64_dyn$" OR BLA_VENDOR STREQUAL "All")
+ # mkl >= 10.3 with single dynamic library
+ list(APPEND BLAS_SEARCH_LIBS
+ "mkl_rt")
+ endif()
+
+ # MKL uses a multitude of partially platform-specific subdirectories:
+ if(BLA_VENDOR STREQUAL "Intel10_32")
+ set(BLAS_mkl_ARCH_NAME "ia32")
+ else()
+ set(BLAS_mkl_ARCH_NAME "intel64")
+ endif()
+ if(WIN32)
+ set(BLAS_mkl_OS_NAME "win")
+ elseif(APPLE)
+ set(BLAS_mkl_OS_NAME "mac")
+ else()
+ set(BLAS_mkl_OS_NAME "lin")
+ endif()
+ if(DEFINED ENV{MKLROOT})
+ file(TO_CMAKE_PATH "$ENV{MKLROOT}" BLAS_mkl_MKLROOT)
+ # If MKLROOT points to the subdirectory 'mkl', use the parent directory instead
+ # so we can better detect other relevant libraries in 'compiler' or 'tbb':
+ get_filename_component(BLAS_mkl_MKLROOT_LAST_DIR "${BLAS_mkl_MKLROOT}" NAME)
+ if(BLAS_mkl_MKLROOT_LAST_DIR STREQUAL "mkl")
+ get_filename_component(BLAS_mkl_MKLROOT "${BLAS_mkl_MKLROOT}" DIRECTORY)
+ endif()
+ endif()
+ set(BLAS_mkl_LIB_PATH_SUFFIXES
+ "compiler/lib" "compiler/lib/${BLAS_mkl_ARCH_NAME}_${BLAS_mkl_OS_NAME}"
+ "compiler/lib/${BLAS_mkl_ARCH_NAME}"
+ "mkl/lib" "mkl/lib/${BLAS_mkl_ARCH_NAME}_${BLAS_mkl_OS_NAME}"
+ "mkl/lib/${BLAS_mkl_ARCH_NAME}"
+ "lib/${BLAS_mkl_ARCH_NAME}_${BLAS_mkl_OS_NAME}")
+
+ foreach(IT ${BLAS_SEARCH_LIBS})
+ string(REPLACE " " ";" SEARCH_LIBS ${IT})
+ if(NOT ${_LIBRARIES})
+ check_blas_libraries(
+ ${_LIBRARIES}
+ BLAS
+ ${BLAS_mkl_SEARCH_SYMBOL}
+ ""
+ "${SEARCH_LIBS}"
+ "${CMAKE_THREAD_LIBS_INIT};${BLAS_mkl_LM};${BLAS_mkl_LDL}"
+ "${BLAS_mkl_MKLROOT}"
+ "${BLAS_mkl_LIB_PATH_SUFFIXES}"
+ )
+ endif()
+ endforeach()
+
+ unset(BLAS_mkl_ILP_MODE)
+ unset(BLAS_mkl_INTFACE)
+ unset(BLAS_mkl_THREADING)
+ unset(BLAS_mkl_OMP)
+ unset(BLAS_mkl_DLL_SUFFIX)
+ unset(BLAS_mkl_LM)
+ unset(BLAS_mkl_LDL)
+ unset(BLAS_mkl_MKLROOT)
+ unset(BLAS_mkl_MKLROOT_LAST_DIR)
+ unset(BLAS_mkl_ARCH_NAME)
+ unset(BLAS_mkl_OS_NAME)
+ unset(BLAS_mkl_LIB_PATH_SUFFIXES)
+ endif()
+ endif()
+endif()
+
+if(BLA_F95)
+ find_package_handle_standard_args(BLAS REQUIRED_VARS BLAS95_LIBRARIES)
+ set(BLAS95_FOUND ${BLAS_FOUND})
+ if(BLAS_FOUND)
+ set(BLAS_LIBRARIES "${BLAS95_LIBRARIES}")
+ endif()
+endif()
+
+# gotoblas? (http://www.tacc.utexas.edu/tacc-projects/gotoblas2)
+if(BLA_VENDOR STREQUAL "Goto" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "goto2"
+ ""
+ ""
+ ""
+ )
+ endif()
+endif()
+
+# FlexiBLAS? (http://www.mpi-magdeburg.mpg.de/mpcsc/software/FlexiBLAS/)
+if(BLA_VENDOR STREQUAL "FlexiBLAS" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "flexiblas"
+ ""
+ ""
+ ""
+ )
+ endif()
+endif()
+
+# OpenBLAS? (http://www.openblas.net)
+if(BLA_VENDOR STREQUAL "OpenBLAS" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "openblas"
+ ""
+ ""
+ ""
+ )
+ endif()
+ if(NOT BLAS_LIBRARIES AND (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED))
+ if(BLAS_FIND_QUIETLY OR NOT BLAS_FIND_REQUIRED)
+ find_package(Threads)
+ else()
+ find_package(Threads REQUIRED)
+ endif()
+ set(_threadlibs "${CMAKE_THREAD_LIBS_INIT}")
+ if(BLA_STATIC)
+ set(_blas_STATIC_CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES}")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES "${_blas_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}")
+ if (CMAKE_C_COMPILER_LOADED)
+ find_package(OpenMP COMPONENTS C)
+ list(PREPEND _threadlibs "${OpenMP_C_LIBRARIES}")
+ elseif(CMAKE_CXX_COMPILER_LOADED)
+ find_package(OpenMP COMPONENTS CXX)
+ list(PREPEND _threadlibs "${OpenMP_CXX_LIBRARIES}")
+ endif()
+ set(CMAKE_FIND_LIBRARY_SUFFIXES "${_blas_STATIC_CMAKE_FIND_LIBRARY_SUFFIXES}")
+ unset(_blas_STATIC_CMAKE_FIND_LIBRARY_SUFFIXES)
+ endif()
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "openblas"
+ "${_threadlibs}"
+ ""
+ ""
+ )
+ unset(_threadlibs)
+ endif()
+endif()
+
+# ArmPL blas library? (https://developer.arm.com/tools-and-software/server-and-hpc/compile/arm-compiler-for-linux/arm-performance-libraries)
+if(BLA_VENDOR MATCHES "Arm" OR BLA_VENDOR STREQUAL "All")
+
+ # Check for 64bit Integer support
+ if(BLA_VENDOR MATCHES "_ilp64")
+ set(BLAS_armpl_LIB "armpl_ilp64")
+ else()
+ set(BLAS_armpl_LIB "armpl_lp64")
+ endif()
+
+ # Check for OpenMP support, VIA BLA_VENDOR of Arm_mp or Arm_ipl64_mp
+ if(BLA_VENDOR MATCHES "_mp")
+ set(BLAS_armpl_LIB "${BLAS_armpl_LIB}_mp")
+ endif()
+
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "${BLAS_armpl_LIB}"
+ ""
+ ""
+ ""
+ )
+ endif()
+
+endif()
+
+# FLAME's blis library? (https://github.com/flame/blis)
+if(BLA_VENDOR STREQUAL "FLAME" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "blis"
+ ""
+ ""
+ ""
+ )
+ endif()
+endif()
+
+# BLAS in the ATLAS library? (http://math-atlas.sourceforge.net/)
+if(BLA_VENDOR STREQUAL "ATLAS" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ dgemm
+ ""
+ "blas;f77blas;atlas"
+ ""
+ ""
+ ""
+ )
+ endif()
+endif()
+
+# BLAS in PhiPACK libraries? (requires generic BLAS lib, too)
+if(BLA_VENDOR STREQUAL "PhiPACK" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "sgemm;dgemm;blas"
+ ""
+ ""
+ ""
+ )
+ endif()
+endif()
+
+# BLAS in Alpha CXML library?
+if(BLA_VENDOR STREQUAL "CXML" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "cxml"
+ ""
+ ""
+ ""
+ )
+ endif()
+endif()
+
+# BLAS in Alpha DXML library? (now called CXML, see above)
+if(BLA_VENDOR STREQUAL "DXML" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "dxml"
+ ""
+ ""
+ ""
+ )
+ endif()
+endif()
+
+# BLAS in Sun Performance library?
+if(BLA_VENDOR STREQUAL "SunPerf" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ "-xlic_lib=sunperf"
+ "sunperf;sunmath"
+ ""
+ ""
+ ""
+ )
+ if(BLAS_LIBRARIES)
+ set(BLAS_LINKER_FLAGS "-xlic_lib=sunperf")
+ endif()
+ endif()
+endif()
+
+# BLAS in SCSL library? (SGI/Cray Scientific Library)
+if(BLA_VENDOR STREQUAL "SCSL" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "scsl"
+ ""
+ ""
+ ""
+ )
+ endif()
+endif()
+
+# BLAS in SGIMATH library?
+if(BLA_VENDOR STREQUAL "SGIMATH" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "complib.sgimath"
+ ""
+ ""
+ ""
+ )
+ endif()
+endif()
+
+# BLAS in IBM ESSL library? (requires generic BLAS lib, too)
+if(BLA_VENDOR STREQUAL "IBMESSL" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "essl;blas"
+ ""
+ ""
+ ""
+ )
+ endif()
+endif()
+
+# BLAS in acml library?
+if(BLA_VENDOR MATCHES "ACML" OR BLA_VENDOR STREQUAL "All")
+ if(((BLA_VENDOR STREQUAL "ACML") AND (NOT BLAS_ACML_LIB_DIRS)) OR
+ ((BLA_VENDOR STREQUAL "ACML_MP") AND (NOT BLAS_ACML_MP_LIB_DIRS)) OR
+ ((BLA_VENDOR STREQUAL "ACML_GPU") AND (NOT BLAS_ACML_GPU_LIB_DIRS))
+ )
+ # try to find acml in "standard" paths
+ if(WIN32)
+ file(GLOB _ACML_ROOT "C:/AMD/acml*/ACML-EULA.txt")
+ else()
+ file(GLOB _ACML_ROOT "/opt/acml*/ACML-EULA.txt")
+ endif()
+ if(WIN32)
+ file(GLOB _ACML_GPU_ROOT "C:/AMD/acml*/GPGPUexamples")
+ else()
+ file(GLOB _ACML_GPU_ROOT "/opt/acml*/GPGPUexamples")
+ endif()
+ list(GET _ACML_ROOT 0 _ACML_ROOT)
+ list(GET _ACML_GPU_ROOT 0 _ACML_GPU_ROOT)
+ if(_ACML_ROOT)
+ get_filename_component(_ACML_ROOT ${_ACML_ROOT} PATH)
+ if(SIZEOF_INTEGER EQUAL 8)
+ set(_ACML_PATH_SUFFIX "_int64")
+ else()
+ set(_ACML_PATH_SUFFIX "")
+ endif()
+ if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")
+ set(_ACML_COMPILER32 "ifort32")
+ set(_ACML_COMPILER64 "ifort64")
+ elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM")
+ # 32-bit not supported
+ set(_ACML_COMPILER64 "ifx")
+ elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "SunPro")
+ set(_ACML_COMPILER32 "sun32")
+ set(_ACML_COMPILER64 "sun64")
+ elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "PGI")
+ set(_ACML_COMPILER32 "pgi32")
+ if(WIN32)
+ set(_ACML_COMPILER64 "win64")
+ else()
+ set(_ACML_COMPILER64 "pgi64")
+ endif()
+ elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Open64")
+ # 32 bit builds not supported on Open64 but for code simplicity
+ # We'll just use the same directory twice
+ set(_ACML_COMPILER32 "open64_64")
+ set(_ACML_COMPILER64 "open64_64")
+ elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "NAG")
+ set(_ACML_COMPILER32 "nag32")
+ set(_ACML_COMPILER64 "nag64")
+ else()
+ set(_ACML_COMPILER32 "gfortran32")
+ set(_ACML_COMPILER64 "gfortran64")
+ endif()
+
+ if(BLA_VENDOR STREQUAL "ACML_MP")
+ set(_ACML_MP_LIB_DIRS
+ "${_ACML_ROOT}/${_ACML_COMPILER32}_mp${_ACML_PATH_SUFFIX}/lib"
+ "${_ACML_ROOT}/${_ACML_COMPILER64}_mp${_ACML_PATH_SUFFIX}/lib")
+ else()
+ set(_ACML_LIB_DIRS
+ "${_ACML_ROOT}/${_ACML_COMPILER32}${_ACML_PATH_SUFFIX}/lib"
+ "${_ACML_ROOT}/${_ACML_COMPILER64}${_ACML_PATH_SUFFIX}/lib")
+ endif()
+ endif()
+elseif(BLAS_${BLA_VENDOR}_LIB_DIRS)
+ set(_${BLA_VENDOR}_LIB_DIRS ${BLAS_${BLA_VENDOR}_LIB_DIRS})
+endif()
+
+if(BLA_VENDOR STREQUAL "ACML_MP")
+ foreach(BLAS_ACML_MP_LIB_DIRS ${_ACML_MP_LIB_DIRS})
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ "" "acml_mp;acml_mv" "" ${BLAS_ACML_MP_LIB_DIRS} ""
+ )
+ if(BLAS_LIBRARIES)
+ break()
+ endif()
+ endforeach()
+elseif(BLA_VENDOR STREQUAL "ACML_GPU")
+ foreach(BLAS_ACML_GPU_LIB_DIRS ${_ACML_GPU_LIB_DIRS})
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ "" "acml;acml_mv;CALBLAS" "" ${BLAS_ACML_GPU_LIB_DIRS} ""
+ )
+ if(BLAS_LIBRARIES)
+ break()
+ endif()
+ endforeach()
+else()
+ foreach(BLAS_ACML_LIB_DIRS ${_ACML_LIB_DIRS})
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ "" "acml;acml_mv" "" ${BLAS_ACML_LIB_DIRS} ""
+ )
+ if(BLAS_LIBRARIES)
+ break()
+ endif()
+ endforeach()
+endif()
+
+# Either acml or acml_mp should be in LD_LIBRARY_PATH but not both
+if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "acml;acml_mv"
+ ""
+ ""
+ ""
+ )
+endif()
+if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "acml_mp;acml_mv"
+ ""
+ ""
+ ""
+ )
+endif()
+if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "acml;acml_mv;CALBLAS"
+ ""
+ ""
+ ""
+ )
+endif()
+endif() # ACML
+
+# Apple BLAS library?
+if(BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ dgemm
+ ""
+ "Accelerate"
+ ""
+ ""
+ ""
+ )
+ endif()
+endif()
+
+# Apple NAS (vecLib) library?
+if(BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ dgemm
+ ""
+ "vecLib"
+ ""
+ ""
+ ""
+ )
+ endif()
+endif()
+
+# Elbrus Math Library?
+if(BLA_VENDOR MATCHES "EML" OR BLA_VENDOR STREQUAL "All")
+
+ set(BLAS_EML_LIB "eml")
+
+ # Check for OpenMP support, VIA BLA_VENDOR of eml_mt
+ if(BLA_VENDOR MATCHES "_mt")
+ set(BLAS_EML_LIB "${BLAS_EML_LIB}_mt")
+ endif()
+
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "${BLAS_EML_LIB}"
+ ""
+ ""
+ ""
+ )
+ endif()
+
+endif()
+
+# Fujitsu SSL2 Library?
+if(NOT BLAS_LIBRARIES AND
+ BLA_VENDOR MATCHES "Fujitsu_SSL2" OR BLA_VENDOR STREQUAL "All")
+ if(BLA_VENDOR STREQUAL "Fujitsu_SSL2BLAMP")
+ set(_ssl2_suffix BLAMP)
+ else()
+ set(_ssl2_suffix)
+ endif()
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ "-SSL2${_ssl2_suffix}"
+ ""
+ ""
+ ""
+ ""
+ )
+ if(BLAS_LIBRARIES)
+ set(BLAS_LINKER_FLAGS "-SSL2${_ssl2_suffix}")
+ set(_blas_fphsa_req_var BLAS_LINKER_FLAGS)
+ endif()
+ unset(_ssl2_suffix)
+endif()
+
+# Generic BLAS library?
+if(BLA_VENDOR STREQUAL "Generic" OR BLA_VENDOR STREQUAL "All")
+ if(NOT BLAS_LIBRARIES)
+ check_blas_libraries(
+ BLAS_LIBRARIES
+ BLAS
+ sgemm
+ ""
+ "blas"
+ ""
+ ""
+ ""
+ )
+ endif()
+endif()
+
+# On compilers that implicitly link BLAS (i.e. CrayPrgEnv) we used a
+# placeholder for empty BLAS_LIBRARIES to get through our logic above.
+if(BLAS_LIBRARIES STREQUAL "BLAS_LIBRARIES-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
+ set(BLAS_LIBRARIES "")
+endif()
+
+if(NOT BLA_F95)
+ find_package_handle_standard_args(BLAS REQUIRED_VARS ${_blas_fphsa_req_var})
+endif()
+
+_add_blas_target()
+cmake_pop_check_state()
+set(CMAKE_FIND_LIBRARY_SUFFIXES ${_blas_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
diff --git a/Modules/FindBZip2.cmake b/Modules/FindBZip2.cmake
new file mode 100644
index 0000000..355c4bb
--- /dev/null
+++ b/Modules/FindBZip2.cmake
@@ -0,0 +1,107 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindBZip2
+---------
+
+Try to find BZip2
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.12
+
+This module defines :prop_tgt:`IMPORTED` target ``BZip2::BZip2``, if
+BZip2 has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``BZIP2_FOUND``
+ system has BZip2
+``BZIP2_INCLUDE_DIRS``
+ .. versionadded:: 3.12
+ the BZip2 include directories
+``BZIP2_LIBRARIES``
+ Link these to use BZip2
+``BZIP2_NEED_PREFIX``
+ this is set if the functions are prefixed with ``BZ2_``
+``BZIP2_VERSION_STRING``
+ the version of BZip2 found
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``BZIP2_INCLUDE_DIR``
+ the BZip2 include directory
+#]=======================================================================]
+
+set(_BZIP2_PATHS PATHS
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Bzip2;InstallPath]"
+ )
+
+find_path(BZIP2_INCLUDE_DIR bzlib.h ${_BZIP2_PATHS} PATH_SUFFIXES include)
+
+if (NOT BZIP2_LIBRARIES)
+ find_library(BZIP2_LIBRARY_RELEASE NAMES bz2 bzip2 libbz2 libbzip2 NAMES_PER_DIR ${_BZIP2_PATHS} PATH_SUFFIXES lib)
+ find_library(BZIP2_LIBRARY_DEBUG NAMES bz2d bzip2d libbz2d libbzip2d NAMES_PER_DIR ${_BZIP2_PATHS} PATH_SUFFIXES lib)
+
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ SELECT_LIBRARY_CONFIGURATIONS(BZIP2)
+else ()
+ file(TO_CMAKE_PATH "${BZIP2_LIBRARIES}" BZIP2_LIBRARIES)
+endif ()
+
+if (BZIP2_INCLUDE_DIR AND EXISTS "${BZIP2_INCLUDE_DIR}/bzlib.h")
+ file(STRINGS "${BZIP2_INCLUDE_DIR}/bzlib.h" BZLIB_H REGEX "bzip2/libbzip2 version [0-9]+\\.[^ ]+ of [0-9]+ ")
+ string(REGEX REPLACE ".* bzip2/libbzip2 version ([0-9]+\\.[^ ]+) of [0-9]+ .*" "\\1" BZIP2_VERSION_STRING "${BZLIB_H}")
+endif ()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(BZip2
+ REQUIRED_VARS BZIP2_LIBRARIES BZIP2_INCLUDE_DIR
+ VERSION_VAR BZIP2_VERSION_STRING)
+
+if (BZIP2_FOUND)
+ set(BZIP2_INCLUDE_DIRS ${BZIP2_INCLUDE_DIR})
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckSymbolExists.cmake)
+ include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_QUIET ${BZip2_FIND_QUIETLY})
+ set(CMAKE_REQUIRED_INCLUDES ${BZIP2_INCLUDE_DIR})
+ set(CMAKE_REQUIRED_LIBRARIES ${BZIP2_LIBRARIES})
+ CHECK_SYMBOL_EXISTS(BZ2_bzCompressInit "bzlib.h" BZIP2_NEED_PREFIX)
+ cmake_pop_check_state()
+
+ if(NOT TARGET BZip2::BZip2)
+ add_library(BZip2::BZip2 UNKNOWN IMPORTED)
+ set_target_properties(BZip2::BZip2 PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${BZIP2_INCLUDE_DIRS}")
+
+ if(BZIP2_LIBRARY_RELEASE)
+ set_property(TARGET BZip2::BZip2 APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(BZip2::BZip2 PROPERTIES
+ IMPORTED_LOCATION_RELEASE "${BZIP2_LIBRARY_RELEASE}")
+ endif()
+
+ if(BZIP2_LIBRARY_DEBUG)
+ set_property(TARGET BZip2::BZip2 APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(BZip2::BZip2 PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${BZIP2_LIBRARY_DEBUG}")
+ endif()
+
+ if(NOT BZIP2_LIBRARY_RELEASE AND NOT BZIP2_LIBRARY_DEBUG)
+ set_property(TARGET BZip2::BZip2 APPEND PROPERTY
+ IMPORTED_LOCATION "${BZIP2_LIBRARY}")
+ endif()
+ endif()
+endif ()
+
+mark_as_advanced(BZIP2_INCLUDE_DIR)
diff --git a/Modules/FindBacktrace.cmake b/Modules/FindBacktrace.cmake
new file mode 100644
index 0000000..3d8ce88
--- /dev/null
+++ b/Modules/FindBacktrace.cmake
@@ -0,0 +1,91 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindBacktrace
+-------------
+
+Find provider for `backtrace(3) <http://man7.org/linux/man-pages/man3/backtrace.3.html>`__.
+
+Checks if OS supports ``backtrace(3)`` via either ``libc`` or custom library.
+This module defines the following variables:
+
+``Backtrace_HEADER``
+ The header file needed for ``backtrace(3)``. Cached.
+ Could be forcibly set by user.
+``Backtrace_INCLUDE_DIRS``
+ The include directories needed to use ``backtrace(3)`` header.
+``Backtrace_LIBRARIES``
+ The libraries (linker flags) needed to use ``backtrace(3)``, if any.
+``Backtrace_FOUND``
+ Is set if and only if ``backtrace(3)`` support detected.
+
+The following cache variables are also available to set or use:
+
+``Backtrace_LIBRARY``
+ The external library providing backtrace, if any.
+``Backtrace_INCLUDE_DIR``
+ The directory holding the ``backtrace(3)`` header.
+
+Typical usage is to generate of header file using :command:`configure_file`
+with the contents like the following::
+
+ #cmakedefine01 Backtrace_FOUND
+ #if Backtrace_FOUND
+ # include <${Backtrace_HEADER}>
+ #endif
+
+And then reference that generated header file in actual source.
+#]=======================================================================]
+
+include(CMakePushCheckState)
+include(CheckSymbolExists)
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+# List of variables to be provided to find_package_handle_standard_args()
+set(_Backtrace_STD_ARGS Backtrace_INCLUDE_DIR)
+
+if(Backtrace_HEADER)
+ set(_Backtrace_HEADER_TRY "${Backtrace_HEADER}")
+else(Backtrace_HEADER)
+ set(_Backtrace_HEADER_TRY "execinfo.h")
+endif(Backtrace_HEADER)
+
+find_path(Backtrace_INCLUDE_DIR "${_Backtrace_HEADER_TRY}")
+set(Backtrace_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
+
+if (NOT DEFINED Backtrace_LIBRARY)
+ # First, check if we already have backtrace(), e.g., in libc
+ cmake_push_check_state(RESET)
+ set(CMAKE_REQUIRED_INCLUDES ${Backtrace_INCLUDE_DIRS})
+ set(CMAKE_REQUIRED_QUIET ${Backtrace_FIND_QUIETLY})
+ check_symbol_exists("backtrace" "${_Backtrace_HEADER_TRY}" _Backtrace_SYM_FOUND)
+ cmake_pop_check_state()
+endif()
+
+if(_Backtrace_SYM_FOUND)
+ # Avoid repeating the message() call below each time CMake is run.
+ if(NOT Backtrace_FIND_QUIETLY AND NOT DEFINED Backtrace_LIBRARY)
+ message(STATUS "backtrace facility detected in default set of libraries")
+ endif()
+ set(Backtrace_LIBRARY "" CACHE FILEPATH "Library providing backtrace(3), empty for default set of libraries")
+else()
+ # Check for external library, for non-glibc systems
+ if(Backtrace_INCLUDE_DIR)
+ # OpenBSD has libbacktrace renamed to libexecinfo
+ find_library(Backtrace_LIBRARY "execinfo")
+ else() # respect user wishes
+ set(_Backtrace_HEADER_TRY "backtrace.h")
+ find_path(Backtrace_INCLUDE_DIR ${_Backtrace_HEADER_TRY})
+ find_library(Backtrace_LIBRARY "backtrace")
+ endif()
+
+ # Prepend list with library path as it's more common practice
+ set(_Backtrace_STD_ARGS Backtrace_LIBRARY ${_Backtrace_STD_ARGS})
+endif()
+
+set(Backtrace_LIBRARIES ${Backtrace_LIBRARY})
+set(Backtrace_HEADER "${_Backtrace_HEADER_TRY}" CACHE STRING "Header providing backtrace(3) facility")
+
+find_package_handle_standard_args(Backtrace FOUND_VAR Backtrace_FOUND REQUIRED_VARS ${_Backtrace_STD_ARGS})
+mark_as_advanced(Backtrace_HEADER Backtrace_INCLUDE_DIR Backtrace_LIBRARY)
diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake
new file mode 100644
index 0000000..3080062
--- /dev/null
+++ b/Modules/FindBoost.cmake
@@ -0,0 +1,2557 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindBoost
+---------
+
+Find Boost include dirs and libraries
+
+Use this module by invoking :command:`find_package` with the form:
+
+.. code-block:: cmake
+
+ find_package(Boost
+ [version] [EXACT] # Minimum or EXACT version e.g. 1.67.0
+ [REQUIRED] # Fail with error if Boost is not found
+ [COMPONENTS <libs>...] # Boost libraries by their canonical name
+ # e.g. "date_time" for "libboost_date_time"
+ [OPTIONAL_COMPONENTS <libs>...]
+ # Optional Boost libraries by their canonical name)
+ ) # e.g. "date_time" for "libboost_date_time"
+
+This module finds headers and requested component libraries OR a CMake
+package configuration file provided by a "Boost CMake" build. For the
+latter case skip to the :ref:`Boost CMake` section below.
+
+.. versionadded:: 3.7
+ ``bzip2`` and ``zlib`` components (Windows only).
+
+.. versionadded:: 3.11
+ The ``OPTIONAL_COMPONENTS`` option.
+
+.. versionadded:: 3.13
+ ``stacktrace_*`` components.
+
+.. versionadded:: 3.19
+ ``bzip2`` and ``zlib`` components on all platforms.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``Boost_FOUND``
+ True if headers and requested libraries were found.
+
+``Boost_INCLUDE_DIRS``
+ Boost include directories.
+
+``Boost_LIBRARY_DIRS``
+ Link directories for Boost libraries.
+
+``Boost_LIBRARIES``
+ Boost component libraries to be linked.
+
+``Boost_<COMPONENT>_FOUND``
+ True if component ``<COMPONENT>`` was found (``<COMPONENT>`` name is upper-case).
+
+``Boost_<COMPONENT>_LIBRARY``
+ Libraries to link for component ``<COMPONENT>`` (may include
+ :command:`target_link_libraries` debug/optimized keywords).
+
+``Boost_VERSION_MACRO``
+ ``BOOST_VERSION`` value from ``boost/version.hpp``.
+
+``Boost_VERSION_STRING``
+ Boost version number in ``X.Y.Z`` format.
+
+``Boost_VERSION``
+ Boost version number in ``X.Y.Z`` format (same as ``Boost_VERSION_STRING``).
+
+ .. versionchanged:: 3.15
+ In previous CMake versions, this variable used the raw version string
+ from the Boost header (same as ``Boost_VERSION_MACRO``).
+ See policy :policy:`CMP0093`.
+
+``Boost_LIB_VERSION``
+ Version string appended to library filenames.
+
+``Boost_VERSION_MAJOR``, ``Boost_MAJOR_VERSION``
+ Boost major version number (``X`` in ``X.Y.Z``).
+
+``Boost_VERSION_MINOR``, ``Boost_MINOR_VERSION``
+ Boost minor version number (``Y`` in ``X.Y.Z``).
+
+``Boost_VERSION_PATCH``, ``Boost_SUBMINOR_VERSION``
+ Boost subminor version number (``Z`` in ``X.Y.Z``).
+
+``Boost_VERSION_COUNT``
+ Amount of version components (3).
+
+``Boost_LIB_DIAGNOSTIC_DEFINITIONS`` (Windows-specific)
+ Pass to :command:`add_definitions` to have diagnostic
+ information about Boost's automatic linking
+ displayed during compilation
+
+.. versionadded:: 3.15
+ The ``Boost_VERSION_<PART>`` variables.
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+Search results are saved persistently in CMake cache entries:
+
+``Boost_INCLUDE_DIR``
+ Directory containing Boost headers.
+
+``Boost_LIBRARY_DIR_RELEASE``
+ Directory containing release Boost libraries.
+
+``Boost_LIBRARY_DIR_DEBUG``
+ Directory containing debug Boost libraries.
+
+``Boost_<COMPONENT>_LIBRARY_DEBUG``
+ Component ``<COMPONENT>`` library debug variant.
+
+``Boost_<COMPONENT>_LIBRARY_RELEASE``
+ Component ``<COMPONENT>`` library release variant.
+
+.. versionadded:: 3.3
+ Per-configuration variables ``Boost_LIBRARY_DIR_RELEASE`` and
+ ``Boost_LIBRARY_DIR_DEBUG``.
+
+Hints
+^^^^^
+
+This module reads hints about search locations from variables:
+
+``BOOST_ROOT``, ``BOOSTROOT``
+ Preferred installation prefix.
+
+``BOOST_INCLUDEDIR``
+ Preferred include directory e.g. ``<prefix>/include``.
+
+``BOOST_LIBRARYDIR``
+ Preferred library directory e.g. ``<prefix>/lib``.
+
+``Boost_NO_SYSTEM_PATHS``
+ Set to ``ON`` to disable searching in locations not
+ specified by these hint variables. Default is ``OFF``.
+
+``Boost_ADDITIONAL_VERSIONS``
+ List of Boost versions not known to this module.
+ (Boost install locations may contain the version).
+
+Users may set these hints or results as ``CACHE`` entries. Projects
+should not read these entries directly but instead use the above
+result variables. Note that some hint names start in upper-case
+``BOOST``. One may specify these as environment variables if they are
+not specified as CMake variables or cache entries.
+
+This module first searches for the Boost header files using the above
+hint variables (excluding ``BOOST_LIBRARYDIR``) and saves the result in
+``Boost_INCLUDE_DIR``. Then it searches for requested component libraries
+using the above hints (excluding ``BOOST_INCLUDEDIR`` and
+``Boost_ADDITIONAL_VERSIONS``), "lib" directories near ``Boost_INCLUDE_DIR``,
+and the library name configuration settings below. It saves the
+library directories in ``Boost_LIBRARY_DIR_DEBUG`` and
+``Boost_LIBRARY_DIR_RELEASE`` and individual library
+locations in ``Boost_<COMPONENT>_LIBRARY_DEBUG`` and ``Boost_<COMPONENT>_LIBRARY_RELEASE``.
+When one changes settings used by previous searches in the same build
+tree (excluding environment variables) this module discards previous
+search results affected by the changes and searches again.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.5
+
+This module defines the following :prop_tgt:`IMPORTED` targets:
+
+``Boost::boost``
+ Target for header-only dependencies. (Boost include directory).
+
+``Boost::headers``
+ .. versionadded:: 3.15
+ Alias for ``Boost::boost``.
+
+``Boost::<component>``
+ Target for specific component dependency (shared or static library);
+ ``<component>`` name is lower-case.
+
+``Boost::diagnostic_definitions``
+ Interface target to enable diagnostic information about Boost's automatic
+ linking during compilation (adds ``-DBOOST_LIB_DIAGNOSTIC``).
+
+``Boost::disable_autolinking``
+ Interface target to disable automatic linking with MSVC
+ (adds ``-DBOOST_ALL_NO_LIB``).
+
+``Boost::dynamic_linking``
+ Interface target to enable dynamic linking with MSVC
+ (adds ``-DBOOST_ALL_DYN_LINK``).
+
+Implicit dependencies such as ``Boost::filesystem`` requiring
+``Boost::system`` will be automatically detected and satisfied, even
+if system is not specified when using :command:`find_package` and if
+``Boost::system`` is not added to :command:`target_link_libraries`. If using
+``Boost::thread``, then ``Threads::Threads`` will also be added automatically.
+
+It is important to note that the imported targets behave differently
+than variables created by this module: multiple calls to
+:command:`find_package(Boost)` in the same directory or sub-directories with
+different options (e.g. static or shared) will not override the
+values of the targets created by the first call.
+
+Other Variables
+^^^^^^^^^^^^^^^
+
+Boost libraries come in many variants encoded in their file name.
+Users or projects may tell this module which variant to find by
+setting variables:
+
+``Boost_USE_DEBUG_LIBS``
+ .. versionadded:: 3.10
+
+ Set to ``ON`` or ``OFF`` to specify whether to search and use the debug
+ libraries. Default is ``ON``.
+
+``Boost_USE_RELEASE_LIBS``
+ .. versionadded:: 3.10
+
+ Set to ``ON`` or ``OFF`` to specify whether to search and use the release
+ libraries. Default is ``ON``.
+
+``Boost_USE_MULTITHREADED``
+ Set to OFF to use the non-multithreaded libraries ("mt" tag). Default is
+ ``ON``.
+
+``Boost_USE_STATIC_LIBS``
+ Set to ON to force the use of the static libraries. Default is ``OFF``.
+
+``Boost_USE_STATIC_RUNTIME``
+ Set to ``ON`` or ``OFF`` to specify whether to use libraries linked
+ statically to the C++ runtime ("s" tag). Default is platform dependent.
+
+``Boost_USE_DEBUG_RUNTIME``
+ Set to ``ON`` or ``OFF`` to specify whether to use libraries linked to the
+ MS debug C++ runtime ("g" tag). Default is ``ON``.
+
+``Boost_USE_DEBUG_PYTHON``
+ Set to ``ON`` to use libraries compiled with a debug Python build ("y"
+ tag). Default is ``OFF``.
+
+``Boost_USE_STLPORT``
+ Set to ``ON`` to use libraries compiled with STLPort ("p" tag). Default is
+ ``OFF``.
+
+``Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS``
+ Set to ON to use libraries compiled with STLPort deprecated "native
+ iostreams" ("n" tag). Default is ``OFF``.
+
+``Boost_COMPILER``
+ Set to the compiler-specific library suffix (e.g. ``-gcc43``). Default is
+ auto-computed for the C++ compiler in use.
+
+ .. versionchanged:: 3.9
+ A list may be used if multiple compatible suffixes should be tested for,
+ in decreasing order of preference.
+
+``Boost_LIB_PREFIX``
+ .. versionadded:: 3.18
+
+ Set to the platform-specific library name prefix (e.g. ``lib``) used by
+ Boost static libs. This is needed only on platforms where CMake does not
+ know the prefix by default.
+
+``Boost_ARCHITECTURE``
+ .. versionadded:: 3.13
+
+ Set to the architecture-specific library suffix (e.g. ``-x64``).
+ Default is auto-computed for the C++ compiler in use.
+
+``Boost_THREADAPI``
+ Suffix for ``thread`` component library name, such as ``pthread`` or
+ ``win32``. Names with and without this suffix will both be tried.
+
+``Boost_NAMESPACE``
+ Alternate namespace used to build boost with e.g. if set to ``myboost``,
+ will search for ``myboost_thread`` instead of ``boost_thread``.
+
+Other variables one may set to control this module are:
+
+``Boost_DEBUG``
+ Set to ``ON`` to enable debug output from ``FindBoost``.
+ Please enable this before filing any bug report.
+
+``Boost_REALPATH``
+ Set to ``ON`` to resolve symlinks for discovered libraries to assist with
+ packaging. For example, the "system" component library may be resolved to
+ ``/usr/lib/libboost_system.so.1.67.0`` instead of
+ ``/usr/lib/libboost_system.so``. This does not affect linking and should
+ not be enabled unless the user needs this information.
+
+``Boost_LIBRARY_DIR``
+ Default value for ``Boost_LIBRARY_DIR_RELEASE`` and
+ ``Boost_LIBRARY_DIR_DEBUG``.
+
+``Boost_NO_WARN_NEW_VERSIONS``
+ .. versionadded:: 3.20
+
+ Set to ``ON`` to suppress the warning about unknown dependencies for new
+ Boost versions.
+
+On Visual Studio and Borland compilers Boost headers request automatic
+linking to corresponding libraries. This requires matching libraries
+to be linked explicitly or available in the link library search path.
+In this case setting ``Boost_USE_STATIC_LIBS`` to ``OFF`` may not achieve
+dynamic linking. Boost automatic linking typically requests static
+libraries with a few exceptions (such as ``Boost.Python``). Use:
+
+.. code-block:: cmake
+
+ add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS})
+
+to ask Boost to report information about automatic linking requests.
+
+Examples
+^^^^^^^^
+
+Find Boost headers only:
+
+.. code-block:: cmake
+
+ find_package(Boost 1.36.0)
+ if(Boost_FOUND)
+ include_directories(${Boost_INCLUDE_DIRS})
+ add_executable(foo foo.cc)
+ endif()
+
+Find Boost libraries and use imported targets:
+
+.. code-block:: cmake
+
+ find_package(Boost 1.56 REQUIRED COMPONENTS
+ date_time filesystem iostreams)
+ add_executable(foo foo.cc)
+ target_link_libraries(foo Boost::date_time Boost::filesystem
+ Boost::iostreams)
+
+Find Boost Python 3.6 libraries and use imported targets:
+
+.. code-block:: cmake
+
+ find_package(Boost 1.67 REQUIRED COMPONENTS
+ python36 numpy36)
+ add_executable(foo foo.cc)
+ target_link_libraries(foo Boost::python36 Boost::numpy36)
+
+Find Boost headers and some *static* (release only) libraries:
+
+.. code-block:: cmake
+
+ set(Boost_USE_STATIC_LIBS ON) # only find static libs
+ set(Boost_USE_DEBUG_LIBS OFF) # ignore debug libs and
+ set(Boost_USE_RELEASE_LIBS ON) # only find release libs
+ set(Boost_USE_MULTITHREADED ON)
+ set(Boost_USE_STATIC_RUNTIME OFF)
+ find_package(Boost 1.66.0 COMPONENTS date_time filesystem system ...)
+ if(Boost_FOUND)
+ include_directories(${Boost_INCLUDE_DIRS})
+ add_executable(foo foo.cc)
+ target_link_libraries(foo ${Boost_LIBRARIES})
+ endif()
+
+.. _`Boost CMake`:
+
+Boost CMake
+^^^^^^^^^^^
+
+If Boost was built using the boost-cmake project or from Boost 1.70.0 on
+it provides a package configuration file for use with find_package's config mode.
+This module looks for the package configuration file called
+``BoostConfig.cmake`` or ``boost-config.cmake`` and stores the result in
+``CACHE`` entry ``Boost_DIR``. If found, the package configuration file is loaded
+and this module returns with no further action. See documentation of
+the Boost CMake package configuration for details on what it provides.
+
+Set ``Boost_NO_BOOST_CMAKE`` to ``ON``, to disable the search for boost-cmake.
+#]=======================================================================]
+
+# The FPHSA helper provides standard way of reporting final search results to
+# the user including the version and component checks.
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+# Save project's policies
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+cmake_policy(SET CMP0102 NEW) # if mark_as_advanced(non_cache_var)
+
+function(_boost_get_existing_target component target_var)
+ set(names "${component}")
+ if(component MATCHES "^([a-z_]*)(python|numpy)([1-9])\\.?([0-9])?$")
+ # handle pythonXY and numpyXY versioned components and also python X.Y, mpi_python etc.
+ list(APPEND names
+ "${CMAKE_MATCH_1}${CMAKE_MATCH_2}" # python
+ "${CMAKE_MATCH_1}${CMAKE_MATCH_2}${CMAKE_MATCH_3}" # pythonX
+ "${CMAKE_MATCH_1}${CMAKE_MATCH_2}${CMAKE_MATCH_3}${CMAKE_MATCH_4}" #pythonXY
+ )
+ endif()
+ # https://github.com/boost-cmake/boost-cmake uses boost::file_system etc.
+ # So handle similar constructions of target names
+ string(TOLOWER "${component}" lower_component)
+ list(APPEND names "${lower_component}")
+ foreach(prefix Boost boost)
+ foreach(name IN LISTS names)
+ if(TARGET "${prefix}::${name}")
+ # The target may be an INTERFACE library that wraps around a single other
+ # target for compatibility. Unwrap this layer so we can extract real info.
+ if("${name}" MATCHES "^(python|numpy|mpi_python)([1-9])([0-9])$")
+ set(name_nv "${CMAKE_MATCH_1}")
+ if(TARGET "${prefix}::${name_nv}")
+ get_property(type TARGET "${prefix}::${name}" PROPERTY TYPE)
+ if(type STREQUAL "INTERFACE_LIBRARY")
+ get_property(lib TARGET "${prefix}::${name}" PROPERTY INTERFACE_LINK_LIBRARIES)
+ if("${lib}" STREQUAL "${prefix}::${name_nv}")
+ set(${target_var} "${prefix}::${name_nv}" PARENT_SCOPE)
+ return()
+ endif()
+ endif()
+ endif()
+ endif()
+ set(${target_var} "${prefix}::${name}" PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+ endforeach()
+ set(${target_var} "" PARENT_SCOPE)
+endfunction()
+
+function(_boost_get_canonical_target_name component target_var)
+ string(TOLOWER "${component}" component)
+ if(component MATCHES "^([a-z_]*)(python|numpy)([1-9])\\.?([0-9])?$")
+ # handle pythonXY and numpyXY versioned components and also python X.Y, mpi_python etc.
+ set(${target_var} "Boost::${CMAKE_MATCH_1}${CMAKE_MATCH_2}" PARENT_SCOPE)
+ else()
+ set(${target_var} "Boost::${component}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+macro(_boost_set_in_parent_scope name value)
+ # Set a variable in parent scope and make it visible in current scope
+ set(${name} "${value}" PARENT_SCOPE)
+ set(${name} "${value}")
+endmacro()
+
+macro(_boost_set_if_unset name value)
+ if(NOT ${name})
+ _boost_set_in_parent_scope(${name} "${value}")
+ endif()
+endmacro()
+
+macro(_boost_set_cache_if_unset name value)
+ if(NOT ${name})
+ set(${name} "${value}" CACHE STRING "" FORCE)
+ endif()
+endmacro()
+
+macro(_boost_append_include_dir target)
+ get_target_property(inc "${target}" INTERFACE_INCLUDE_DIRECTORIES)
+ if(inc)
+ list(APPEND include_dirs "${inc}")
+ endif()
+endmacro()
+
+function(_boost_set_legacy_variables_from_config)
+ # Set legacy variables for compatibility if not set
+ set(include_dirs "")
+ set(library_dirs "")
+ set(libraries "")
+ # Header targets Boost::headers or Boost::boost
+ foreach(comp headers boost)
+ _boost_get_existing_target(${comp} target)
+ if(target)
+ _boost_append_include_dir("${target}")
+ endif()
+ endforeach()
+ # Library targets
+ foreach(comp IN LISTS Boost_FIND_COMPONENTS)
+ string(TOUPPER ${comp} uppercomp)
+ # Overwrite if set
+ _boost_set_in_parent_scope(Boost_${uppercomp}_FOUND "${Boost_${comp}_FOUND}")
+ if(Boost_${comp}_FOUND)
+ _boost_get_existing_target(${comp} target)
+ if(NOT target)
+ if(Boost_DEBUG OR Boost_VERBOSE)
+ message(WARNING "Could not find imported target for required component '${comp}'. Legacy variables for this component might be missing. Refer to the documentation of your Boost installation for help on variables to use.")
+ endif()
+ continue()
+ endif()
+ _boost_append_include_dir("${target}")
+ _boost_set_if_unset(Boost_${uppercomp}_LIBRARY "${target}")
+ _boost_set_if_unset(Boost_${uppercomp}_LIBRARIES "${target}") # Very old legacy variable
+ list(APPEND libraries "${target}")
+ get_property(type TARGET "${target}" PROPERTY TYPE)
+ if(NOT type STREQUAL "INTERFACE_LIBRARY")
+ foreach(cfg RELEASE DEBUG)
+ get_target_property(lib ${target} IMPORTED_LOCATION_${cfg})
+ if(lib)
+ get_filename_component(lib_dir "${lib}" DIRECTORY)
+ list(APPEND library_dirs ${lib_dir})
+ _boost_set_cache_if_unset(Boost_${uppercomp}_LIBRARY_${cfg} "${lib}")
+ endif()
+ endforeach()
+ elseif(Boost_DEBUG OR Boost_VERBOSE)
+ # For projects using only the Boost::* targets this warning can be safely ignored.
+ message(WARNING "Imported target '${target}' for required component '${comp}' has no artifact. Legacy variables for this component might be missing. Refer to the documentation of your Boost installation for help on variables to use.")
+ endif()
+ _boost_get_canonical_target_name("${comp}" canonical_target)
+ if(NOT TARGET "${canonical_target}")
+ add_library("${canonical_target}" INTERFACE IMPORTED)
+ target_link_libraries("${canonical_target}" INTERFACE "${target}")
+ endif()
+ endif()
+ endforeach()
+ list(REMOVE_DUPLICATES include_dirs)
+ list(REMOVE_DUPLICATES library_dirs)
+ _boost_set_if_unset(Boost_INCLUDE_DIRS "${include_dirs}")
+ _boost_set_if_unset(Boost_LIBRARY_DIRS "${library_dirs}")
+ _boost_set_if_unset(Boost_LIBRARIES "${libraries}")
+ _boost_set_if_unset(Boost_VERSION_STRING "${Boost_VERSION_MAJOR}.${Boost_VERSION_MINOR}.${Boost_VERSION_PATCH}")
+ find_path(Boost_INCLUDE_DIR
+ NAMES boost/version.hpp boost/config.hpp
+ HINTS ${Boost_INCLUDE_DIRS}
+ NO_DEFAULT_PATH
+ )
+ if(NOT Boost_VERSION_MACRO OR NOT Boost_LIB_VERSION)
+ set(version_file ${Boost_INCLUDE_DIR}/boost/version.hpp)
+ if(EXISTS "${version_file}")
+ file(STRINGS "${version_file}" contents REGEX "#define BOOST_(LIB_)?VERSION ")
+ if(contents MATCHES "#define BOOST_VERSION ([0-9]+)")
+ _boost_set_if_unset(Boost_VERSION_MACRO "${CMAKE_MATCH_1}")
+ endif()
+ if(contents MATCHES "#define BOOST_LIB_VERSION \"([0-9_]+)\"")
+ _boost_set_if_unset(Boost_LIB_VERSION "${CMAKE_MATCH_1}")
+ endif()
+ endif()
+ endif()
+ _boost_set_if_unset(Boost_MAJOR_VERSION ${Boost_VERSION_MAJOR})
+ _boost_set_if_unset(Boost_MINOR_VERSION ${Boost_VERSION_MINOR})
+ _boost_set_if_unset(Boost_SUBMINOR_VERSION ${Boost_VERSION_PATCH})
+ if(WIN32)
+ _boost_set_if_unset(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC")
+ endif()
+ if(NOT TARGET Boost::headers)
+ add_library(Boost::headers INTERFACE IMPORTED)
+ target_include_directories(Boost::headers INTERFACE ${Boost_INCLUDE_DIRS})
+ endif()
+ # Legacy targets w/o functionality as all handled by defined targets
+ foreach(lib diagnostic_definitions disable_autolinking dynamic_linking)
+ if(NOT TARGET Boost::${lib})
+ add_library(Boost::${lib} INTERFACE IMPORTED)
+ endif()
+ endforeach()
+ if(NOT TARGET Boost::boost)
+ add_library(Boost::boost INTERFACE IMPORTED)
+ target_link_libraries(Boost::boost INTERFACE Boost::headers)
+ endif()
+endfunction()
+
+#-------------------------------------------------------------------------------
+# Before we go searching, check whether a boost cmake package is available, unless
+# the user specifically asked NOT to search for one.
+#
+# If Boost_DIR is set, this behaves as any find_package call would. If not,
+# it looks at BOOST_ROOT and BOOSTROOT to find Boost.
+#
+if (NOT Boost_NO_BOOST_CMAKE)
+ # If Boost_DIR is not set, look for BOOSTROOT and BOOST_ROOT as alternatives,
+ # since these are more conventional for Boost.
+ if ("$ENV{Boost_DIR}" STREQUAL "")
+ if (NOT "$ENV{BOOST_ROOT}" STREQUAL "")
+ set(ENV{Boost_DIR} $ENV{BOOST_ROOT})
+ elseif (NOT "$ENV{BOOSTROOT}" STREQUAL "")
+ set(ENV{Boost_DIR} $ENV{BOOSTROOT})
+ endif()
+ endif()
+
+ set(_boost_FIND_PACKAGE_ARGS "")
+ if(Boost_NO_SYSTEM_PATHS)
+ list(APPEND _boost_FIND_PACKAGE_ARGS NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH)
+ endif()
+
+ # Do the same find_package call but look specifically for the CMake version.
+ # Note that args are passed in the Boost_FIND_xxxxx variables, so there is no
+ # need to delegate them to this find_package call.
+ if(BOOST_ROOT AND NOT Boost_ROOT)
+ # Honor BOOST_ROOT by setting Boost_ROOT with CMP0074 NEW behavior.
+ cmake_policy(PUSH)
+ cmake_policy(SET CMP0074 NEW)
+ set(Boost_ROOT "${BOOST_ROOT}")
+ set(_Boost_ROOT_FOR_CONFIG 1)
+ endif()
+ find_package(Boost QUIET NO_MODULE ${_boost_FIND_PACKAGE_ARGS})
+ if(_Boost_ROOT_FOR_CONFIG)
+ unset(_Boost_ROOT_FOR_CONFIG)
+ unset(Boost_ROOT)
+ cmake_policy(POP)
+ endif()
+ if (DEFINED Boost_DIR)
+ mark_as_advanced(Boost_DIR)
+ endif ()
+
+ # If we found a boost cmake package, then we're done. Print out what we found.
+ # Otherwise let the rest of the module try to find it.
+ if(Boost_FOUND)
+ # Convert component found variables to standard variables if required
+ # Necessary for legacy boost-cmake and 1.70 builtin BoostConfig
+ if(Boost_FIND_COMPONENTS)
+ # Ignore the meta-component "ALL", introduced by Boost 1.73
+ list(REMOVE_ITEM Boost_FIND_COMPONENTS "ALL")
+
+ foreach(_comp IN LISTS Boost_FIND_COMPONENTS)
+ if(DEFINED Boost_${_comp}_FOUND)
+ continue()
+ endif()
+ string(TOUPPER ${_comp} _uppercomp)
+ if(DEFINED Boost${_comp}_FOUND) # legacy boost-cmake project
+ set(Boost_${_comp}_FOUND ${Boost${_comp}_FOUND})
+ elseif(DEFINED Boost_${_uppercomp}_FOUND) # Boost 1.70
+ set(Boost_${_comp}_FOUND ${Boost_${_uppercomp}_FOUND})
+ endif()
+ endforeach()
+ endif()
+
+ find_package_handle_standard_args(Boost HANDLE_COMPONENTS CONFIG_MODE)
+ _boost_set_legacy_variables_from_config()
+
+ # Restore project's policies
+ cmake_policy(POP)
+ return()
+ endif()
+endif()
+
+
+#-------------------------------------------------------------------------------
+# FindBoost functions & macros
+#
+
+#
+# Print debug text if Boost_DEBUG is set.
+# Call example:
+# _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "debug message")
+#
+function(_Boost_DEBUG_PRINT file line text)
+ if(Boost_DEBUG)
+ message(STATUS "[ ${file}:${line} ] ${text}")
+ endif()
+endfunction()
+
+#
+# _Boost_DEBUG_PRINT_VAR(file line variable_name [ENVIRONMENT]
+# [SOURCE "short explanation of origin of var value"])
+#
+# ENVIRONMENT - look up environment variable instead of CMake variable
+#
+# Print variable name and its value if Boost_DEBUG is set.
+# Call example:
+# _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" BOOST_ROOT)
+#
+function(_Boost_DEBUG_PRINT_VAR file line name)
+ if(Boost_DEBUG)
+ cmake_parse_arguments(_args "ENVIRONMENT" "SOURCE" "" ${ARGN})
+
+ unset(source)
+ if(_args_SOURCE)
+ set(source " (${_args_SOURCE})")
+ endif()
+
+ if(_args_ENVIRONMENT)
+ if(DEFINED ENV{${name}})
+ set(value "\"$ENV{${name}}\"")
+ else()
+ set(value "<unset>")
+ endif()
+ set(_name "ENV{${name}}")
+ else()
+ if(DEFINED "${name}")
+ set(value "\"${${name}}\"")
+ else()
+ set(value "<unset>")
+ endif()
+ set(_name "${name}")
+ endif()
+
+ _Boost_DEBUG_PRINT("${file}" "${line}" "${_name} = ${value}${source}")
+ endif()
+endfunction()
+
+############################################
+#
+# Check the existence of the libraries.
+#
+############################################
+# This macro was taken directly from the FindQt4.cmake file that is included
+# with the CMake distribution. This is NOT my work. All work was done by the
+# original authors of the FindQt4.cmake file. Only minor modifications were
+# made to remove references to Qt and make this file more generally applicable
+# And ELSE/ENDIF pairs were removed for readability.
+#########################################################################
+
+macro(_Boost_ADJUST_LIB_VARS basename)
+ if(Boost_INCLUDE_DIR )
+ if(Boost_${basename}_LIBRARY_DEBUG AND Boost_${basename}_LIBRARY_RELEASE)
+ # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for
+ # single-config generators, set optimized and debug libraries
+ get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(_isMultiConfig OR CMAKE_BUILD_TYPE)
+ set(Boost_${basename}_LIBRARY optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG})
+ else()
+ # For single-config generators where CMAKE_BUILD_TYPE has no value,
+ # just use the release libraries
+ set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} )
+ endif()
+ # FIXME: This probably should be set for both cases
+ set(Boost_${basename}_LIBRARIES optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG})
+ endif()
+
+ # if only the release version was found, set the debug variable also to the release version
+ if(Boost_${basename}_LIBRARY_RELEASE AND NOT Boost_${basename}_LIBRARY_DEBUG)
+ set(Boost_${basename}_LIBRARY_DEBUG ${Boost_${basename}_LIBRARY_RELEASE})
+ set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE})
+ set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE})
+ endif()
+
+ # if only the debug version was found, set the release variable also to the debug version
+ if(Boost_${basename}_LIBRARY_DEBUG AND NOT Boost_${basename}_LIBRARY_RELEASE)
+ set(Boost_${basename}_LIBRARY_RELEASE ${Boost_${basename}_LIBRARY_DEBUG})
+ set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_DEBUG})
+ set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_DEBUG})
+ endif()
+
+ # If the debug & release library ends up being the same, omit the keywords
+ if("${Boost_${basename}_LIBRARY_RELEASE}" STREQUAL "${Boost_${basename}_LIBRARY_DEBUG}")
+ set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} )
+ set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE} )
+ endif()
+
+ if(Boost_${basename}_LIBRARY AND Boost_${basename}_HEADER)
+ set(Boost_${basename}_FOUND ON)
+ if("x${basename}" STREQUAL "xTHREAD" AND NOT TARGET Threads::Threads)
+ string(APPEND Boost_ERROR_REASON_THREAD " (missing dependency: Threads)")
+ set(Boost_THREAD_FOUND OFF)
+ endif()
+ endif()
+
+ endif()
+ # Make variables changeable to the advanced user
+ mark_as_advanced(
+ Boost_${basename}_LIBRARY_RELEASE
+ Boost_${basename}_LIBRARY_DEBUG
+ )
+endmacro()
+
+# Detect changes in used variables.
+# Compares the current variable value with the last one.
+# In short form:
+# v != v_LAST -> CHANGED = 1
+# v is defined, v_LAST not -> CHANGED = 1
+# v is not defined, but v_LAST is -> CHANGED = 1
+# otherwise -> CHANGED = 0
+# CHANGED is returned in variable named ${changed_var}
+macro(_Boost_CHANGE_DETECT changed_var)
+ set(${changed_var} 0)
+ foreach(v ${ARGN})
+ if(DEFINED _Boost_COMPONENTS_SEARCHED)
+ if(${v})
+ if(_${v}_LAST)
+ string(COMPARE NOTEQUAL "${${v}}" "${_${v}_LAST}" _${v}_CHANGED)
+ else()
+ set(_${v}_CHANGED 1)
+ endif()
+ elseif(_${v}_LAST)
+ set(_${v}_CHANGED 1)
+ endif()
+ if(_${v}_CHANGED)
+ set(${changed_var} 1)
+ endif()
+ else()
+ set(_${v}_CHANGED 0)
+ endif()
+ endforeach()
+endmacro()
+
+#
+# Find the given library (var).
+# Use 'build_type' to support different lib paths for RELEASE or DEBUG builds
+#
+macro(_Boost_FIND_LIBRARY var build_type)
+
+ find_library(${var} ${ARGN})
+
+ if(${var})
+ # If this is the first library found then save Boost_LIBRARY_DIR_[RELEASE,DEBUG].
+ if(NOT Boost_LIBRARY_DIR_${build_type})
+ get_filename_component(_dir "${${var}}" PATH)
+ set(Boost_LIBRARY_DIR_${build_type} "${_dir}" CACHE PATH "Boost library directory ${build_type}" FORCE)
+ endif()
+ elseif(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT)
+ # Try component-specific hints but do not save Boost_LIBRARY_DIR_[RELEASE,DEBUG].
+ find_library(${var} HINTS ${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT} ${ARGN})
+ endif()
+
+ # If Boost_LIBRARY_DIR_[RELEASE,DEBUG] is known then search only there.
+ if(Boost_LIBRARY_DIR_${build_type})
+ set(_boost_LIBRARY_SEARCH_DIRS_${build_type} ${Boost_LIBRARY_DIR_${build_type}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "Boost_LIBRARY_DIR_${build_type}")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "_boost_LIBRARY_SEARCH_DIRS_${build_type}")
+ endif()
+endmacro()
+
+#-------------------------------------------------------------------------------
+
+# Convert CMAKE_CXX_COMPILER_VERSION to boost compiler suffix version.
+function(_Boost_COMPILER_DUMPVERSION _OUTPUT_VERSION _OUTPUT_VERSION_MAJOR _OUTPUT_VERSION_MINOR)
+ string(REGEX REPLACE "([0-9]+)\\.([0-9]+)(\\.[0-9]+)?" "\\1"
+ _boost_COMPILER_VERSION_MAJOR "${CMAKE_CXX_COMPILER_VERSION}")
+ string(REGEX REPLACE "([0-9]+)\\.([0-9]+)(\\.[0-9]+)?" "\\2"
+ _boost_COMPILER_VERSION_MINOR "${CMAKE_CXX_COMPILER_VERSION}")
+
+ set(_boost_COMPILER_VERSION "${_boost_COMPILER_VERSION_MAJOR}${_boost_COMPILER_VERSION_MINOR}")
+
+ set(${_OUTPUT_VERSION} ${_boost_COMPILER_VERSION} PARENT_SCOPE)
+ set(${_OUTPUT_VERSION_MAJOR} ${_boost_COMPILER_VERSION_MAJOR} PARENT_SCOPE)
+ set(${_OUTPUT_VERSION_MINOR} ${_boost_COMPILER_VERSION_MINOR} PARENT_SCOPE)
+endfunction()
+
+#
+# Take a list of libraries with "thread" in it
+# and prepend duplicates with "thread_${Boost_THREADAPI}"
+# at the front of the list
+#
+function(_Boost_PREPEND_LIST_WITH_THREADAPI _output)
+ set(_orig_libnames ${ARGN})
+ string(REPLACE "thread" "thread_${Boost_THREADAPI}" _threadapi_libnames "${_orig_libnames}")
+ set(${_output} ${_threadapi_libnames} ${_orig_libnames} PARENT_SCOPE)
+endfunction()
+
+#
+# If a library is found, replace its cache entry with its REALPATH
+#
+function(_Boost_SWAP_WITH_REALPATH _library _docstring)
+ if(${_library})
+ get_filename_component(_boost_filepathreal ${${_library}} REALPATH)
+ unset(${_library} CACHE)
+ set(${_library} ${_boost_filepathreal} CACHE FILEPATH "${_docstring}")
+ endif()
+endfunction()
+
+function(_Boost_CHECK_SPELLING _var)
+ if(${_var})
+ string(TOUPPER ${_var} _var_UC)
+ message(FATAL_ERROR "ERROR: ${_var} is not the correct spelling. The proper spelling is ${_var_UC}.")
+ endif()
+endfunction()
+
+# Guesses Boost's compiler prefix used in built library names
+# Returns the guess by setting the variable pointed to by _ret
+function(_Boost_GUESS_COMPILER_PREFIX _ret)
+ if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntel"
+ OR "x${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "xIntelLLVM")
+ if(WIN32)
+ set (_boost_COMPILER "-iw")
+ else()
+ set (_boost_COMPILER "-il")
+ endif()
+ elseif (GHSMULTI)
+ set(_boost_COMPILER "-ghs")
+ elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" OR "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ if(MSVC_TOOLSET_VERSION GREATER_EQUAL 150)
+ # Not yet known.
+ set(_boost_COMPILER "")
+ elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 140)
+ # MSVC toolset 14.x versions are forward compatible.
+ set(_boost_COMPILER "")
+ foreach(v 9 8 7 6 5 4 3 2 1 0)
+ if(MSVC_TOOLSET_VERSION GREATER_EQUAL 14${v})
+ list(APPEND _boost_COMPILER "-vc14${v}")
+ endif()
+ endforeach()
+ elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 80)
+ set(_boost_COMPILER "-vc${MSVC_TOOLSET_VERSION}")
+ elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.10)
+ set(_boost_COMPILER "-vc71")
+ elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13) # Good luck!
+ set(_boost_COMPILER "-vc7") # yes, this is correct
+ else() # VS 6.0 Good luck!
+ set(_boost_COMPILER "-vc6") # yes, this is correct
+ endif()
+
+ if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang")
+ string(REPLACE "." ";" VERSION_LIST "${CMAKE_CXX_COMPILER_VERSION}")
+ list(GET VERSION_LIST 0 CLANG_VERSION_MAJOR)
+ set(_boost_COMPILER "-clangw${CLANG_VERSION_MAJOR};${_boost_COMPILER}")
+ endif()
+ elseif (BORLAND)
+ set(_boost_COMPILER "-bcb")
+ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
+ set(_boost_COMPILER "-sw")
+ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "XL")
+ set(_boost_COMPILER "-xlc")
+ elseif (MINGW)
+ if(Boost_VERSION_STRING VERSION_LESS 1.34)
+ set(_boost_COMPILER "-mgw") # no GCC version encoding prior to 1.34
+ else()
+ _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION _boost_COMPILER_VERSION_MAJOR _boost_COMPILER_VERSION_MINOR)
+ if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.73 AND _boost_COMPILER_VERSION_MAJOR VERSION_GREATER_EQUAL 5)
+ set(_boost_COMPILER "-mgw${_boost_COMPILER_VERSION_MAJOR}")
+ else()
+ set(_boost_COMPILER "-mgw${_boost_COMPILER_VERSION}")
+ endif()
+ endif()
+ elseif (UNIX)
+ _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION _boost_COMPILER_VERSION_MAJOR _boost_COMPILER_VERSION_MINOR)
+ if(NOT Boost_VERSION_STRING VERSION_LESS 1.69.0)
+ # From GCC 5 and clang 4, versioning changes and minor becomes patch.
+ # For those compilers, patch is exclude from compiler tag in Boost 1.69+ library naming.
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND _boost_COMPILER_VERSION_MAJOR VERSION_GREATER 4)
+ set(_boost_COMPILER_VERSION "${_boost_COMPILER_VERSION_MAJOR}")
+ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND _boost_COMPILER_VERSION_MAJOR VERSION_GREATER 3)
+ set(_boost_COMPILER_VERSION "${_boost_COMPILER_VERSION_MAJOR}")
+ endif()
+ endif()
+
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ if(Boost_VERSION_STRING VERSION_LESS 1.34)
+ set(_boost_COMPILER "-gcc") # no GCC version encoding prior to 1.34
+ else()
+ # Determine which version of GCC we have.
+ if(APPLE)
+ if(Boost_VERSION_STRING VERSION_LESS 1.36.0)
+ # In Boost <= 1.35.0, there is no mangled compiler name for
+ # the macOS/Darwin version of GCC.
+ set(_boost_COMPILER "")
+ else()
+ # In Boost 1.36.0 and newer, the mangled compiler name used
+ # on macOS/Darwin is "xgcc".
+ set(_boost_COMPILER "-xgcc${_boost_COMPILER_VERSION}")
+ endif()
+ else()
+ set(_boost_COMPILER "-gcc${_boost_COMPILER_VERSION}")
+ endif()
+ endif()
+ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ # TODO: Find out any Boost version constraints vs clang support.
+ set(_boost_COMPILER "-clang${_boost_COMPILER_VERSION}")
+ endif()
+ else()
+ set(_boost_COMPILER "")
+ endif()
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "_boost_COMPILER" SOURCE "guessed")
+ set(${_ret} ${_boost_COMPILER} PARENT_SCOPE)
+endfunction()
+
+#
+# Get component dependencies. Requires the dependencies to have been
+# defined for the Boost release version.
+#
+# component - the component to check
+# _ret - list of library dependencies
+#
+function(_Boost_COMPONENT_DEPENDENCIES component _ret)
+ # Note: to add a new Boost release, run
+ #
+ # % cmake -DBOOST_DIR=/path/to/boost/source -P Utilities/Scripts/BoostScanDeps.cmake
+ #
+ # The output may be added in a new block below. If it's the same as
+ # the previous release, simply update the version range of the block
+ # for the previous release. Also check if any new components have
+ # been added, and add any new components to
+ # _Boost_COMPONENT_HEADERS.
+ #
+ # This information was originally generated by running
+ # BoostScanDeps.cmake against every boost release to date supported
+ # by FindBoost:
+ #
+ # % for version in /path/to/boost/sources/*
+ # do
+ # cmake -DBOOST_DIR=$version -P Utilities/Scripts/BoostScanDeps.cmake
+ # done
+ #
+ # The output was then updated by search and replace with these regexes:
+ #
+ # - Strip message(STATUS) prefix dashes
+ # s;^-- ;;
+ # - Indent
+ # s;^set(; set(;;
+ # - Add conditionals
+ # s;Scanning /path/to/boost/sources/boost_\(.*\)_\(.*\)_\(.*); elseif(NOT Boost_VERSION_STRING VERSION_LESS \1\.\2\.\3 AND Boost_VERSION_STRING VERSION_LESS xxxx);
+ #
+ # This results in the logic seen below, but will require the xxxx
+ # replacing with the following Boost release version (or the next
+ # minor version to be released, e.g. 1.59 was the latest at the time
+ # of writing, making 1.60 the next. Identical consecutive releases
+ # were then merged together by updating the end range of the first
+ # block and removing the following redundant blocks.
+ #
+ # Running the script against all historical releases should be
+ # required only if the BoostScanDeps.cmake script logic is changed.
+ # The addition of a new release should only require it to be run
+ # against the new release.
+
+ # Handle Python version suffixes
+ if(component MATCHES "^(python|mpi_python|numpy)([0-9][0-9]?|[0-9]\\.[0-9])\$")
+ set(component "${CMAKE_MATCH_1}")
+ set(component_python_version "${CMAKE_MATCH_2}")
+ endif()
+
+ set(_Boost_IMPORTED_TARGETS TRUE)
+ if(Boost_VERSION_STRING)
+ if(Boost_VERSION_STRING VERSION_LESS 1.33.0)
+ message(WARNING "Imported targets and dependency information not available for Boost version ${Boost_VERSION_STRING} (all versions older than 1.33)")
+ set(_Boost_IMPORTED_TARGETS FALSE)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.35.0)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex thread)
+ set(_Boost_REGEX_DEPENDENCIES thread)
+ set(_Boost_WAVE_DEPENDENCIES filesystem thread)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.36.0)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system thread)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.38.0)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system thread)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.43.0)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_THREAD_DEPENDENCIES date_time)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.44.0)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_THREAD_DEPENDENCIES date_time)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.45.0)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random serialization)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_THREAD_DEPENDENCIES date_time)
+ set(_Boost_WAVE_DEPENDENCIES serialization filesystem system thread date_time)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.47.0)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_THREAD_DEPENDENCIES date_time)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.48.0)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_THREAD_DEPENDENCIES date_time)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.50.0)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_THREAD_DEPENDENCIES date_time)
+ set(_Boost_TIMER_DEPENDENCIES chrono system)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.53.0)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_THREAD_DEPENDENCIES chrono system date_time)
+ set(_Boost_TIMER_DEPENDENCIES chrono system)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.54.0)
+ set(_Boost_ATOMIC_DEPENDENCIES thread chrono system date_time)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+ set(_Boost_TIMER_DEPENDENCIES chrono system)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.55.0)
+ set(_Boost_ATOMIC_DEPENDENCIES thread chrono system date_time)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+ set(_Boost_TIMER_DEPENDENCIES chrono system)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.56.0)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_COROUTINE_DEPENDENCIES context system)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+ set(_Boost_TIMER_DEPENDENCIES chrono system)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.59.0)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_COROUTINE_DEPENDENCIES context system)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_RANDOM_DEPENDENCIES system)
+ set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+ set(_Boost_TIMER_DEPENDENCIES chrono system)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.60.0)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_COROUTINE_DEPENDENCIES context system)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono atomic)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_RANDOM_DEPENDENCIES system)
+ set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+ set(_Boost_TIMER_DEPENDENCIES chrono system)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.61.0)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_COROUTINE_DEPENDENCIES context system)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_RANDOM_DEPENDENCIES system)
+ set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+ set(_Boost_TIMER_DEPENDENCIES chrono system)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.62.0)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time)
+ set(_Boost_COROUTINE_DEPENDENCIES context system)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_RANDOM_DEPENDENCIES system)
+ set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.63.0)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time)
+ set(_Boost_COROUTINE_DEPENDENCIES context system)
+ set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_RANDOM_DEPENDENCIES system)
+ set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.65.0)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time)
+ set(_Boost_COROUTINE_DEPENDENCIES context system)
+ set(_Boost_COROUTINE2_DEPENDENCIES context fiber thread chrono system date_time)
+ set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_RANDOM_DEPENDENCIES system)
+ set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.67.0)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time)
+ set(_Boost_COROUTINE_DEPENDENCIES context system)
+ set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_NUMPY_DEPENDENCIES python${component_python_version})
+ set(_Boost_RANDOM_DEPENDENCIES system)
+ set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+ set(_Boost_TIMER_DEPENDENCIES chrono system)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.68.0)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time)
+ set(_Boost_COROUTINE_DEPENDENCIES context system)
+ set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_NUMPY_DEPENDENCIES python${component_python_version})
+ set(_Boost_RANDOM_DEPENDENCIES system)
+ set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+ set(_Boost_TIMER_DEPENDENCIES chrono system)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.69.0)
+ set(_Boost_CHRONO_DEPENDENCIES system)
+ set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time)
+ set(_Boost_CONTRACT_DEPENDENCIES thread chrono system date_time)
+ set(_Boost_COROUTINE_DEPENDENCIES context system)
+ set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time)
+ set(_Boost_FILESYSTEM_DEPENDENCIES system)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_NUMPY_DEPENDENCIES python${component_python_version})
+ set(_Boost_RANDOM_DEPENDENCIES system)
+ set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic)
+ set(_Boost_TIMER_DEPENDENCIES chrono system)
+ set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.70.0)
+ set(_Boost_CONTRACT_DEPENDENCIES thread chrono date_time)
+ set(_Boost_COROUTINE_DEPENDENCIES context)
+ set(_Boost_FIBER_DEPENDENCIES context)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES date_time log_setup filesystem thread regex chrono atomic)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_NUMPY_DEPENDENCIES python${component_python_version})
+ set(_Boost_THREAD_DEPENDENCIES chrono date_time atomic)
+ set(_Boost_TIMER_DEPENDENCIES chrono system)
+ set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.72.0)
+ set(_Boost_CONTRACT_DEPENDENCIES thread chrono date_time)
+ set(_Boost_COROUTINE_DEPENDENCIES context)
+ set(_Boost_FIBER_DEPENDENCIES context)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES date_time log_setup filesystem thread regex chrono atomic)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_NUMPY_DEPENDENCIES python${component_python_version})
+ set(_Boost_THREAD_DEPENDENCIES chrono date_time atomic)
+ set(_Boost_TIMER_DEPENDENCIES chrono)
+ set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.73.0)
+ set(_Boost_CONTRACT_DEPENDENCIES thread chrono date_time)
+ set(_Boost_COROUTINE_DEPENDENCIES context)
+ set(_Boost_FIBER_DEPENDENCIES context)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES date_time log_setup filesystem thread regex chrono atomic)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l chrono atomic)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_NUMPY_DEPENDENCIES python${component_python_version})
+ set(_Boost_THREAD_DEPENDENCIES chrono date_time atomic)
+ set(_Boost_TIMER_DEPENDENCIES chrono)
+ set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ elseif(Boost_VERSION_STRING VERSION_LESS 1.75.0)
+ set(_Boost_CONTRACT_DEPENDENCIES thread chrono date_time)
+ set(_Boost_COROUTINE_DEPENDENCIES context)
+ set(_Boost_FIBER_DEPENDENCIES context)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_LOG_DEPENDENCIES date_time log_setup filesystem thread regex chrono atomic)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_NUMPY_DEPENDENCIES python${component_python_version})
+ set(_Boost_THREAD_DEPENDENCIES chrono date_time atomic)
+ set(_Boost_TIMER_DEPENDENCIES chrono)
+ set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ else()
+ set(_Boost_CONTRACT_DEPENDENCIES thread chrono date_time)
+ set(_Boost_COROUTINE_DEPENDENCIES context)
+ set(_Boost_FIBER_DEPENDENCIES context)
+ set(_Boost_IOSTREAMS_DEPENDENCIES regex)
+ set(_Boost_JSON_DEPENDENCIES container)
+ set(_Boost_LOG_DEPENDENCIES date_time log_setup filesystem thread regex chrono atomic)
+ set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic)
+ set(_Boost_MPI_DEPENDENCIES serialization)
+ set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization)
+ set(_Boost_NUMPY_DEPENDENCIES python${component_python_version})
+ set(_Boost_THREAD_DEPENDENCIES chrono date_time atomic)
+ set(_Boost_TIMER_DEPENDENCIES chrono)
+ set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic)
+ set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
+ if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.76.0 AND NOT Boost_NO_WARN_NEW_VERSIONS)
+ message(WARNING "New Boost version may have incorrect or missing dependencies and imported targets")
+ endif()
+ endif()
+ endif()
+
+ string(TOUPPER ${component} uppercomponent)
+ set(${_ret} ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE)
+ set(_Boost_IMPORTED_TARGETS ${_Boost_IMPORTED_TARGETS} PARENT_SCOPE)
+
+ string(REGEX REPLACE ";" " " _boost_DEPS_STRING "${_Boost_${uppercomponent}_DEPENDENCIES}")
+ if (NOT _boost_DEPS_STRING)
+ set(_boost_DEPS_STRING "(none)")
+ endif()
+ # message(STATUS "Dependencies for Boost::${component}: ${_boost_DEPS_STRING}")
+endfunction()
+
+#
+# Get component headers. This is the primary header (or headers) for
+# a given component, and is used to check that the headers are present
+# as well as the library itself as an extra sanity check of the build
+# environment.
+#
+# component - the component to check
+# _hdrs
+#
+function(_Boost_COMPONENT_HEADERS component _hdrs)
+ # Handle Python version suffixes
+ if(component MATCHES "^(python|mpi_python|numpy)([0-9][0-9]?|[0-9]\\.[0-9])\$")
+ set(component "${CMAKE_MATCH_1}")
+ set(component_python_version "${CMAKE_MATCH_2}")
+ endif()
+
+ # Note: new boost components will require adding here. The header
+ # must be present in all versions of Boost providing a library.
+ set(_Boost_ATOMIC_HEADERS "boost/atomic.hpp")
+ set(_Boost_CHRONO_HEADERS "boost/chrono.hpp")
+ set(_Boost_CONTAINER_HEADERS "boost/container/container_fwd.hpp")
+ set(_Boost_CONTRACT_HEADERS "boost/contract.hpp")
+ if(Boost_VERSION_STRING VERSION_LESS 1.61.0)
+ set(_Boost_CONTEXT_HEADERS "boost/context/all.hpp")
+ else()
+ set(_Boost_CONTEXT_HEADERS "boost/context/detail/fcontext.hpp")
+ endif()
+ set(_Boost_COROUTINE_HEADERS "boost/coroutine/all.hpp")
+ set(_Boost_DATE_TIME_HEADERS "boost/date_time/date.hpp")
+ set(_Boost_EXCEPTION_HEADERS "boost/exception/exception.hpp")
+ set(_Boost_FIBER_HEADERS "boost/fiber/all.hpp")
+ set(_Boost_FILESYSTEM_HEADERS "boost/filesystem/path.hpp")
+ set(_Boost_GRAPH_HEADERS "boost/graph/adjacency_list.hpp")
+ set(_Boost_GRAPH_PARALLEL_HEADERS "boost/graph/adjacency_list.hpp")
+ set(_Boost_IOSTREAMS_HEADERS "boost/iostreams/stream.hpp")
+ set(_Boost_LOCALE_HEADERS "boost/locale.hpp")
+ set(_Boost_LOG_HEADERS "boost/log/core.hpp")
+ set(_Boost_LOG_SETUP_HEADERS "boost/log/detail/setup_config.hpp")
+ set(_Boost_MATH_HEADERS "boost/math_fwd.hpp")
+ set(_Boost_MATH_C99_HEADERS "boost/math/tr1.hpp")
+ set(_Boost_MATH_C99F_HEADERS "boost/math/tr1.hpp")
+ set(_Boost_MATH_C99L_HEADERS "boost/math/tr1.hpp")
+ set(_Boost_MATH_TR1_HEADERS "boost/math/tr1.hpp")
+ set(_Boost_MATH_TR1F_HEADERS "boost/math/tr1.hpp")
+ set(_Boost_MATH_TR1L_HEADERS "boost/math/tr1.hpp")
+ set(_Boost_MPI_HEADERS "boost/mpi.hpp")
+ set(_Boost_MPI_PYTHON_HEADERS "boost/mpi/python/config.hpp")
+ set(_Boost_NUMPY_HEADERS "boost/python/numpy.hpp")
+ set(_Boost_NOWIDE_HEADERS "boost/nowide/cstdlib.hpp")
+ set(_Boost_PRG_EXEC_MONITOR_HEADERS "boost/test/prg_exec_monitor.hpp")
+ set(_Boost_PROGRAM_OPTIONS_HEADERS "boost/program_options.hpp")
+ set(_Boost_PYTHON_HEADERS "boost/python.hpp")
+ set(_Boost_RANDOM_HEADERS "boost/random.hpp")
+ set(_Boost_REGEX_HEADERS "boost/regex.hpp")
+ set(_Boost_SERIALIZATION_HEADERS "boost/serialization/serialization.hpp")
+ set(_Boost_SIGNALS_HEADERS "boost/signals.hpp")
+ set(_Boost_STACKTRACE_ADDR2LINE_HEADERS "boost/stacktrace.hpp")
+ set(_Boost_STACKTRACE_BACKTRACE_HEADERS "boost/stacktrace.hpp")
+ set(_Boost_STACKTRACE_BASIC_HEADERS "boost/stacktrace.hpp")
+ set(_Boost_STACKTRACE_NOOP_HEADERS "boost/stacktrace.hpp")
+ set(_Boost_STACKTRACE_WINDBG_CACHED_HEADERS "boost/stacktrace.hpp")
+ set(_Boost_STACKTRACE_WINDBG_HEADERS "boost/stacktrace.hpp")
+ set(_Boost_SYSTEM_HEADERS "boost/system/config.hpp")
+ set(_Boost_TEST_EXEC_MONITOR_HEADERS "boost/test/test_exec_monitor.hpp")
+ set(_Boost_THREAD_HEADERS "boost/thread.hpp")
+ set(_Boost_TIMER_HEADERS "boost/timer.hpp")
+ set(_Boost_TYPE_ERASURE_HEADERS "boost/type_erasure/config.hpp")
+ set(_Boost_UNIT_TEST_FRAMEWORK_HEADERS "boost/test/framework.hpp")
+ set(_Boost_WAVE_HEADERS "boost/wave.hpp")
+ set(_Boost_WSERIALIZATION_HEADERS "boost/archive/text_wiarchive.hpp")
+ set(_Boost_BZIP2_HEADERS "boost/iostreams/filter/bzip2.hpp")
+ set(_Boost_ZLIB_HEADERS "boost/iostreams/filter/zlib.hpp")
+
+ string(TOUPPER ${component} uppercomponent)
+ set(${_hdrs} ${_Boost_${uppercomponent}_HEADERS} PARENT_SCOPE)
+
+ string(REGEX REPLACE ";" " " _boost_HDRS_STRING "${_Boost_${uppercomponent}_HEADERS}")
+ if (NOT _boost_HDRS_STRING)
+ set(_boost_HDRS_STRING "(none)")
+ endif()
+ # message(STATUS "Headers for Boost::${component}: ${_boost_HDRS_STRING}")
+endfunction()
+
+#
+# Determine if any missing dependencies require adding to the component list.
+#
+# Sets _Boost_${COMPONENT}_DEPENDENCIES for each required component,
+# plus _Boost_IMPORTED_TARGETS (TRUE if imported targets should be
+# defined; FALSE if dependency information is unavailable).
+#
+# componentvar - the component list variable name
+# extravar - the indirect dependency list variable name
+#
+#
+function(_Boost_MISSING_DEPENDENCIES componentvar extravar)
+ # _boost_unprocessed_components - list of components requiring processing
+ # _boost_processed_components - components already processed (or currently being processed)
+ # _boost_new_components - new components discovered for future processing
+ #
+ list(APPEND _boost_unprocessed_components ${${componentvar}})
+
+ while(_boost_unprocessed_components)
+ list(APPEND _boost_processed_components ${_boost_unprocessed_components})
+ foreach(component ${_boost_unprocessed_components})
+ string(TOUPPER ${component} uppercomponent)
+ set(${_ret} ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE)
+ _Boost_COMPONENT_DEPENDENCIES("${component}" _Boost_${uppercomponent}_DEPENDENCIES)
+ set(_Boost_${uppercomponent}_DEPENDENCIES ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE)
+ set(_Boost_IMPORTED_TARGETS ${_Boost_IMPORTED_TARGETS} PARENT_SCOPE)
+ foreach(componentdep ${_Boost_${uppercomponent}_DEPENDENCIES})
+ if (NOT ("${componentdep}" IN_LIST _boost_processed_components OR "${componentdep}" IN_LIST _boost_new_components))
+ list(APPEND _boost_new_components ${componentdep})
+ endif()
+ endforeach()
+ endforeach()
+ set(_boost_unprocessed_components ${_boost_new_components})
+ unset(_boost_new_components)
+ endwhile()
+ set(_boost_extra_components ${_boost_processed_components})
+ if(_boost_extra_components AND ${componentvar})
+ list(REMOVE_ITEM _boost_extra_components ${${componentvar}})
+ endif()
+ set(${componentvar} ${_boost_processed_components} PARENT_SCOPE)
+ set(${extravar} ${_boost_extra_components} PARENT_SCOPE)
+endfunction()
+
+#
+# Some boost libraries may require particular set of compler features.
+# The very first one was `boost::fiber` introduced in Boost 1.62.
+# One can check required compiler features of it in
+# - `${Boost_ROOT}/libs/fiber/build/Jamfile.v2`;
+# - `${Boost_ROOT}/libs/context/build/Jamfile.v2`.
+#
+# TODO (Re)Check compiler features on (every?) release ???
+# One may use the following command to get the files to check:
+#
+# $ find . -name Jamfile.v2 | grep build | xargs grep -l cxx1
+#
+function(_Boost_COMPILER_FEATURES component _ret)
+ # Boost >= 1.62
+ if(NOT Boost_VERSION_STRING VERSION_LESS 1.62.0)
+ set(_Boost_FIBER_COMPILER_FEATURES
+ cxx_alias_templates
+ cxx_auto_type
+ cxx_constexpr
+ cxx_defaulted_functions
+ cxx_final
+ cxx_lambdas
+ cxx_noexcept
+ cxx_nullptr
+ cxx_rvalue_references
+ cxx_thread_local
+ cxx_variadic_templates
+ )
+ # Compiler feature for `context` same as for `fiber`.
+ set(_Boost_CONTEXT_COMPILER_FEATURES ${_Boost_FIBER_COMPILER_FEATURES})
+ endif()
+
+ # Boost Contract library available in >= 1.67
+ if(NOT Boost_VERSION_STRING VERSION_LESS 1.67.0)
+ # From `libs/contract/build/boost_contract_build.jam`
+ set(_Boost_CONTRACT_COMPILER_FEATURES
+ cxx_lambdas
+ cxx_variadic_templates
+ )
+ endif()
+
+ string(TOUPPER ${component} uppercomponent)
+ set(${_ret} ${_Boost_${uppercomponent}_COMPILER_FEATURES} PARENT_SCOPE)
+endfunction()
+
+#
+# Update library search directory hint variable with paths used by prebuilt boost binaries.
+#
+# Prebuilt windows binaries (https://sourceforge.net/projects/boost/files/boost-binaries/)
+# have library directories named using MSVC compiler version and architecture.
+# This function would append corresponding directories if MSVC is a current compiler,
+# so having `BOOST_ROOT` would be enough to specify to find everything.
+#
+function(_Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS componentlibvar basedir)
+ if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(_arch_suffix 64)
+ else()
+ set(_arch_suffix 32)
+ endif()
+ if(MSVC_TOOLSET_VERSION GREATER_EQUAL 150)
+ # Not yet known.
+ elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 140)
+ # MSVC toolset 14.x versions are forward compatible.
+ foreach(v 9 8 7 6 5 4 3 2 1 0)
+ if(MSVC_TOOLSET_VERSION GREATER_EQUAL 14${v})
+ list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-14.${v})
+ endif()
+ endforeach()
+ elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 80)
+ math(EXPR _toolset_major_version "${MSVC_TOOLSET_VERSION} / 10")
+ list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-${_toolset_major_version}.0)
+ endif()
+ set(${componentlibvar} ${${componentlibvar}} PARENT_SCOPE)
+ endif()
+endfunction()
+
+#
+# End functions/macros
+#
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# main.
+#-------------------------------------------------------------------------------
+
+
+# If the user sets Boost_LIBRARY_DIR, use it as the default for both
+# configurations.
+if(NOT Boost_LIBRARY_DIR_RELEASE AND Boost_LIBRARY_DIR)
+ set(Boost_LIBRARY_DIR_RELEASE "${Boost_LIBRARY_DIR}")
+endif()
+if(NOT Boost_LIBRARY_DIR_DEBUG AND Boost_LIBRARY_DIR)
+ set(Boost_LIBRARY_DIR_DEBUG "${Boost_LIBRARY_DIR}")
+endif()
+
+if(NOT DEFINED Boost_USE_DEBUG_LIBS)
+ set(Boost_USE_DEBUG_LIBS TRUE)
+endif()
+if(NOT DEFINED Boost_USE_RELEASE_LIBS)
+ set(Boost_USE_RELEASE_LIBS TRUE)
+endif()
+if(NOT DEFINED Boost_USE_MULTITHREADED)
+ set(Boost_USE_MULTITHREADED TRUE)
+endif()
+if(NOT DEFINED Boost_USE_DEBUG_RUNTIME)
+ set(Boost_USE_DEBUG_RUNTIME TRUE)
+endif()
+
+# Check the version of Boost against the requested version.
+if(Boost_FIND_VERSION AND NOT Boost_FIND_VERSION_MINOR)
+ message(SEND_ERROR "When requesting a specific version of Boost, you must provide at least the major and minor version numbers, e.g., 1.34")
+endif()
+
+if(Boost_FIND_VERSION_EXACT)
+ # The version may appear in a directory with or without the patch
+ # level, even when the patch level is non-zero.
+ set(_boost_TEST_VERSIONS
+ "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}.${Boost_FIND_VERSION_PATCH}"
+ "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}")
+else()
+ # The user has not requested an exact version. Among known
+ # versions, find those that are acceptable to the user request.
+ #
+ # Note: When adding a new Boost release, also update the dependency
+ # information in _Boost_COMPONENT_DEPENDENCIES and
+ # _Boost_COMPONENT_HEADERS. See the instructions at the top of
+ # _Boost_COMPONENT_DEPENDENCIES.
+ set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS}
+ "1.75.0" "1.75" "1.74.0" "1.74"
+ "1.73.0" "1.73" "1.72.0" "1.72" "1.71.0" "1.71" "1.70.0" "1.70" "1.69.0" "1.69"
+ "1.68.0" "1.68" "1.67.0" "1.67" "1.66.0" "1.66" "1.65.1" "1.65.0" "1.65"
+ "1.64.0" "1.64" "1.63.0" "1.63" "1.62.0" "1.62" "1.61.0" "1.61" "1.60.0" "1.60"
+ "1.59.0" "1.59" "1.58.0" "1.58" "1.57.0" "1.57" "1.56.0" "1.56" "1.55.0" "1.55"
+ "1.54.0" "1.54" "1.53.0" "1.53" "1.52.0" "1.52" "1.51.0" "1.51"
+ "1.50.0" "1.50" "1.49.0" "1.49" "1.48.0" "1.48" "1.47.0" "1.47" "1.46.1"
+ "1.46.0" "1.46" "1.45.0" "1.45" "1.44.0" "1.44" "1.43.0" "1.43" "1.42.0" "1.42"
+ "1.41.0" "1.41" "1.40.0" "1.40" "1.39.0" "1.39" "1.38.0" "1.38" "1.37.0" "1.37"
+ "1.36.1" "1.36.0" "1.36" "1.35.1" "1.35.0" "1.35" "1.34.1" "1.34.0"
+ "1.34" "1.33.1" "1.33.0" "1.33")
+
+ set(_boost_TEST_VERSIONS)
+ if(Boost_FIND_VERSION)
+ set(_Boost_FIND_VERSION_SHORT "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}")
+ # Select acceptable versions.
+ foreach(version ${_Boost_KNOWN_VERSIONS})
+ if(NOT "${version}" VERSION_LESS "${Boost_FIND_VERSION}")
+ # This version is high enough.
+ list(APPEND _boost_TEST_VERSIONS "${version}")
+ elseif("${version}.99" VERSION_EQUAL "${_Boost_FIND_VERSION_SHORT}.99")
+ # This version is a short-form for the requested version with
+ # the patch level dropped.
+ list(APPEND _boost_TEST_VERSIONS "${version}")
+ endif()
+ endforeach()
+ else()
+ # Any version is acceptable.
+ set(_boost_TEST_VERSIONS "${_Boost_KNOWN_VERSIONS}")
+ endif()
+endif()
+
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_TEST_VERSIONS")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_USE_MULTITHREADED")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_USE_STATIC_LIBS")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_USE_STATIC_RUNTIME")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_ADDITIONAL_VERSIONS")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_NO_SYSTEM_PATHS")
+
+cmake_policy(GET CMP0074 _Boost_CMP0074)
+if(NOT "x${_Boost_CMP0074}x" STREQUAL "xNEWx")
+ _Boost_CHECK_SPELLING(Boost_ROOT)
+endif()
+unset(_Boost_CMP0074)
+_Boost_CHECK_SPELLING(Boost_LIBRARYDIR)
+_Boost_CHECK_SPELLING(Boost_INCLUDEDIR)
+
+# Collect environment variable inputs as hints. Do not consider changes.
+foreach(v BOOSTROOT BOOST_ROOT BOOST_INCLUDEDIR BOOST_LIBRARYDIR)
+ set(_env $ENV{${v}})
+ if(_env)
+ file(TO_CMAKE_PATH "${_env}" _ENV_${v})
+ else()
+ set(_ENV_${v} "")
+ endif()
+endforeach()
+if(NOT _ENV_BOOST_ROOT AND _ENV_BOOSTROOT)
+ set(_ENV_BOOST_ROOT "${_ENV_BOOSTROOT}")
+endif()
+
+# Collect inputs and cached results. Detect changes since the last run.
+if(NOT BOOST_ROOT AND BOOSTROOT)
+ set(BOOST_ROOT "${BOOSTROOT}")
+endif()
+set(_Boost_VARS_DIR
+ BOOST_ROOT
+ Boost_NO_SYSTEM_PATHS
+ )
+
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_ROOT")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_ROOT" ENVIRONMENT)
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_INCLUDEDIR")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_INCLUDEDIR" ENVIRONMENT)
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_LIBRARYDIR")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_LIBRARYDIR" ENVIRONMENT)
+
+# ------------------------------------------------------------------------
+# Search for Boost include DIR
+# ------------------------------------------------------------------------
+
+set(_Boost_VARS_INC BOOST_INCLUDEDIR Boost_INCLUDE_DIR Boost_ADDITIONAL_VERSIONS)
+_Boost_CHANGE_DETECT(_Boost_CHANGE_INCDIR ${_Boost_VARS_DIR} ${_Boost_VARS_INC})
+# Clear Boost_INCLUDE_DIR if it did not change but other input affecting the
+# location did. We will find a new one based on the new inputs.
+if(_Boost_CHANGE_INCDIR AND NOT _Boost_INCLUDE_DIR_CHANGED)
+ unset(Boost_INCLUDE_DIR CACHE)
+endif()
+
+if(NOT Boost_INCLUDE_DIR)
+ set(_boost_INCLUDE_SEARCH_DIRS "")
+ if(BOOST_INCLUDEDIR)
+ list(APPEND _boost_INCLUDE_SEARCH_DIRS ${BOOST_INCLUDEDIR})
+ elseif(_ENV_BOOST_INCLUDEDIR)
+ list(APPEND _boost_INCLUDE_SEARCH_DIRS ${_ENV_BOOST_INCLUDEDIR})
+ endif()
+
+ if( BOOST_ROOT )
+ list(APPEND _boost_INCLUDE_SEARCH_DIRS ${BOOST_ROOT}/include ${BOOST_ROOT})
+ elseif( _ENV_BOOST_ROOT )
+ list(APPEND _boost_INCLUDE_SEARCH_DIRS ${_ENV_BOOST_ROOT}/include ${_ENV_BOOST_ROOT})
+ endif()
+
+ if( Boost_NO_SYSTEM_PATHS)
+ list(APPEND _boost_INCLUDE_SEARCH_DIRS NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH)
+ else()
+ if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
+ foreach(ver ${_boost_TEST_VERSIONS})
+ string(REPLACE "." "_" ver "${ver}")
+ list(APPEND _boost_INCLUDE_SEARCH_DIRS PATHS "C:/local/boost_${ver}")
+ endforeach()
+ endif()
+ list(APPEND _boost_INCLUDE_SEARCH_DIRS PATHS
+ C:/boost/include
+ C:/boost
+ /sw/local/include
+ )
+ endif()
+
+ # Try to find Boost by stepping backwards through the Boost versions
+ # we know about.
+ # Build a list of path suffixes for each version.
+ set(_boost_PATH_SUFFIXES)
+ foreach(_boost_VER ${_boost_TEST_VERSIONS})
+ # Add in a path suffix, based on the required version, ideally
+ # we could read this from version.hpp, but for that to work we'd
+ # need to know the include dir already
+ set(_boost_BOOSTIFIED_VERSION)
+
+ # Transform 1.35 => 1_35 and 1.36.0 => 1_36_0
+ if(_boost_VER MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)")
+ set(_boost_BOOSTIFIED_VERSION
+ "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}_${CMAKE_MATCH_3}")
+ elseif(_boost_VER MATCHES "([0-9]+)\\.([0-9]+)")
+ set(_boost_BOOSTIFIED_VERSION
+ "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}")
+ endif()
+
+ list(APPEND _boost_PATH_SUFFIXES
+ "boost-${_boost_BOOSTIFIED_VERSION}"
+ "boost_${_boost_BOOSTIFIED_VERSION}"
+ "boost/boost-${_boost_BOOSTIFIED_VERSION}"
+ "boost/boost_${_boost_BOOSTIFIED_VERSION}"
+ )
+
+ endforeach()
+
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_INCLUDE_SEARCH_DIRS")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_PATH_SUFFIXES")
+
+ # Look for a standard boost header file.
+ find_path(Boost_INCLUDE_DIR
+ NAMES boost/config.hpp
+ HINTS ${_boost_INCLUDE_SEARCH_DIRS}
+ PATH_SUFFIXES ${_boost_PATH_SUFFIXES}
+ )
+endif()
+
+# ------------------------------------------------------------------------
+# Extract version information from version.hpp
+# ------------------------------------------------------------------------
+
+if(Boost_INCLUDE_DIR)
+ _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "location of version.hpp: ${Boost_INCLUDE_DIR}/boost/version.hpp")
+
+ # Extract Boost_VERSION_MACRO and Boost_LIB_VERSION from version.hpp
+ set(Boost_VERSION_MACRO 0)
+ set(Boost_LIB_VERSION "")
+ file(STRINGS "${Boost_INCLUDE_DIR}/boost/version.hpp" _boost_VERSION_HPP_CONTENTS REGEX "#define BOOST_(LIB_)?VERSION ")
+ if("${_boost_VERSION_HPP_CONTENTS}" MATCHES "#define BOOST_VERSION ([0-9]+)")
+ set(Boost_VERSION_MACRO "${CMAKE_MATCH_1}")
+ endif()
+ if("${_boost_VERSION_HPP_CONTENTS}" MATCHES "#define BOOST_LIB_VERSION \"([0-9_]+)\"")
+ set(Boost_LIB_VERSION "${CMAKE_MATCH_1}")
+ endif()
+ unset(_boost_VERSION_HPP_CONTENTS)
+
+ # Calculate version components
+ math(EXPR Boost_VERSION_MAJOR "${Boost_VERSION_MACRO} / 100000")
+ math(EXPR Boost_VERSION_MINOR "${Boost_VERSION_MACRO} / 100 % 1000")
+ math(EXPR Boost_VERSION_PATCH "${Boost_VERSION_MACRO} % 100")
+ set(Boost_VERSION_COUNT 3)
+
+ # Define alias variables for backwards compat.
+ set(Boost_MAJOR_VERSION ${Boost_VERSION_MAJOR})
+ set(Boost_MINOR_VERSION ${Boost_VERSION_MINOR})
+ set(Boost_SUBMINOR_VERSION ${Boost_VERSION_PATCH})
+
+ # Define Boost version in x.y.z format
+ set(Boost_VERSION_STRING "${Boost_VERSION_MAJOR}.${Boost_VERSION_MINOR}.${Boost_VERSION_PATCH}")
+
+ # Define final Boost_VERSION
+ cmake_policy(GET CMP0093 _Boost_CMP0093
+ PARENT_SCOPE # undocumented, do not use outside of CMake
+ )
+ if("x${_Boost_CMP0093}x" STREQUAL "xNEWx")
+ set(Boost_VERSION ${Boost_VERSION_STRING})
+ else()
+ set(Boost_VERSION ${Boost_VERSION_MACRO})
+ endif()
+ unset(_Boost_CMP0093)
+
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_STRING")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_MACRO")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_MAJOR")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_MINOR")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_PATCH")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_COUNT")
+endif()
+
+# ------------------------------------------------------------------------
+# Prefix initialization
+# ------------------------------------------------------------------------
+
+if ( NOT DEFINED Boost_LIB_PREFIX )
+ # Boost's static libraries use a "lib" prefix on DLL platforms
+ # to distinguish them from the DLL import libraries.
+ if (Boost_USE_STATIC_LIBS AND (
+ (WIN32 AND NOT CYGWIN)
+ OR GHSMULTI
+ ))
+ set(Boost_LIB_PREFIX "lib")
+ else()
+ set(Boost_LIB_PREFIX "")
+ endif()
+endif()
+
+if ( NOT Boost_NAMESPACE )
+ set(Boost_NAMESPACE "boost")
+endif()
+
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_LIB_PREFIX")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_NAMESPACE")
+
+# ------------------------------------------------------------------------
+# Suffix initialization and compiler suffix detection.
+# ------------------------------------------------------------------------
+
+set(_Boost_VARS_NAME
+ Boost_NAMESPACE
+ Boost_COMPILER
+ Boost_THREADAPI
+ Boost_USE_DEBUG_PYTHON
+ Boost_USE_MULTITHREADED
+ Boost_USE_STATIC_LIBS
+ Boost_USE_STATIC_RUNTIME
+ Boost_USE_STLPORT
+ Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS
+ )
+_Boost_CHANGE_DETECT(_Boost_CHANGE_LIBNAME ${_Boost_VARS_NAME})
+
+# Setting some more suffixes for the library
+if (Boost_COMPILER)
+ set(_boost_COMPILER ${Boost_COMPILER})
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "_boost_COMPILER" SOURCE "user-specified via Boost_COMPILER")
+else()
+ # Attempt to guess the compiler suffix
+ # NOTE: this is not perfect yet, if you experience any issues
+ # please report them and use the Boost_COMPILER variable
+ # to work around the problems.
+ _Boost_GUESS_COMPILER_PREFIX(_boost_COMPILER)
+endif()
+
+set (_boost_MULTITHREADED "-mt")
+if( NOT Boost_USE_MULTITHREADED )
+ set (_boost_MULTITHREADED "")
+endif()
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_MULTITHREADED")
+
+#======================
+# Systematically build up the Boost ABI tag for the 'tagged' and 'versioned' layouts
+# http://boost.org/doc/libs/1_66_0/more/getting_started/windows.html#library-naming
+# http://boost.org/doc/libs/1_66_0/boost/config/auto_link.hpp
+# http://boost.org/doc/libs/1_66_0/tools/build/src/tools/common.jam
+# http://boost.org/doc/libs/1_66_0/boostcpp.jam
+set( _boost_RELEASE_ABI_TAG "-")
+set( _boost_DEBUG_ABI_TAG "-")
+# Key Use this library when:
+# s linking statically to the C++ standard library and
+# compiler runtime support libraries.
+if(Boost_USE_STATIC_RUNTIME)
+ set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}s")
+ set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}s")
+endif()
+# g using debug versions of the standard and runtime
+# support libraries
+if(WIN32 AND Boost_USE_DEBUG_RUNTIME)
+ if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC"
+ OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang"
+ OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntel"
+ OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntelLLVM")
+ string(APPEND _boost_DEBUG_ABI_TAG "g")
+ endif()
+endif()
+# y using special debug build of python
+if(Boost_USE_DEBUG_PYTHON)
+ string(APPEND _boost_DEBUG_ABI_TAG "y")
+endif()
+# d using a debug version of your code
+string(APPEND _boost_DEBUG_ABI_TAG "d")
+# p using the STLport standard library rather than the
+# default one supplied with your compiler
+if(Boost_USE_STLPORT)
+ string(APPEND _boost_RELEASE_ABI_TAG "p")
+ string(APPEND _boost_DEBUG_ABI_TAG "p")
+endif()
+# n using the STLport deprecated "native iostreams" feature
+# removed from the documentation in 1.43.0 but still present in
+# boost/config/auto_link.hpp
+if(Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS)
+ string(APPEND _boost_RELEASE_ABI_TAG "n")
+ string(APPEND _boost_DEBUG_ABI_TAG "n")
+endif()
+
+# -x86 Architecture and address model tag
+# First character is the architecture, then word-size, either 32 or 64
+# Only used in 'versioned' layout, added in Boost 1.66.0
+if(DEFINED Boost_ARCHITECTURE)
+ set(_boost_ARCHITECTURE_TAG "${Boost_ARCHITECTURE}")
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "_boost_ARCHITECTURE_TAG" SOURCE "user-specified via Boost_ARCHITECTURE")
+else()
+ set(_boost_ARCHITECTURE_TAG "")
+ # {CMAKE_CXX_COMPILER_ARCHITECTURE_ID} is not currently set for all compilers
+ if(NOT "x${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "x" AND NOT Boost_VERSION_STRING VERSION_LESS 1.66.0)
+ string(APPEND _boost_ARCHITECTURE_TAG "-")
+ # This needs to be kept in-sync with the section of CMakePlatformId.h.in
+ # inside 'defined(_WIN32) && defined(_MSC_VER)'
+ if(CMAKE_CXX_COMPILER_ARCHITECTURE_ID STREQUAL "IA64")
+ string(APPEND _boost_ARCHITECTURE_TAG "i")
+ elseif(CMAKE_CXX_COMPILER_ARCHITECTURE_ID STREQUAL "X86"
+ OR CMAKE_CXX_COMPILER_ARCHITECTURE_ID STREQUAL "x64")
+ string(APPEND _boost_ARCHITECTURE_TAG "x")
+ elseif(CMAKE_CXX_COMPILER_ARCHITECTURE_ID MATCHES "^ARM")
+ string(APPEND _boost_ARCHITECTURE_TAG "a")
+ elseif(CMAKE_CXX_COMPILER_ARCHITECTURE_ID STREQUAL "MIPS")
+ string(APPEND _boost_ARCHITECTURE_TAG "m")
+ endif()
+
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ string(APPEND _boost_ARCHITECTURE_TAG "64")
+ else()
+ string(APPEND _boost_ARCHITECTURE_TAG "32")
+ endif()
+ endif()
+ _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "_boost_ARCHITECTURE_TAG" SOURCE "detected")
+endif()
+
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_RELEASE_ABI_TAG")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_DEBUG_ABI_TAG")
+
+# ------------------------------------------------------------------------
+# Begin finding boost libraries
+# ------------------------------------------------------------------------
+
+set(_Boost_VARS_LIB "")
+foreach(c DEBUG RELEASE)
+ set(_Boost_VARS_LIB_${c} BOOST_LIBRARYDIR Boost_LIBRARY_DIR_${c})
+ list(APPEND _Boost_VARS_LIB ${_Boost_VARS_LIB_${c}})
+ _Boost_CHANGE_DETECT(_Boost_CHANGE_LIBDIR_${c} ${_Boost_VARS_DIR} ${_Boost_VARS_LIB_${c}} Boost_INCLUDE_DIR)
+ # Clear Boost_LIBRARY_DIR_${c} if it did not change but other input affecting the
+ # location did. We will find a new one based on the new inputs.
+ if(_Boost_CHANGE_LIBDIR_${c} AND NOT _Boost_LIBRARY_DIR_${c}_CHANGED)
+ unset(Boost_LIBRARY_DIR_${c} CACHE)
+ endif()
+
+ # If Boost_LIBRARY_DIR_[RELEASE,DEBUG] is set, prefer its value.
+ if(Boost_LIBRARY_DIR_${c})
+ set(_boost_LIBRARY_SEARCH_DIRS_${c} ${Boost_LIBRARY_DIR_${c}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+ else()
+ set(_boost_LIBRARY_SEARCH_DIRS_${c} "")
+ if(BOOST_LIBRARYDIR)
+ list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${BOOST_LIBRARYDIR})
+ elseif(_ENV_BOOST_LIBRARYDIR)
+ list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${_ENV_BOOST_LIBRARYDIR})
+ endif()
+
+ if(BOOST_ROOT)
+ list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${BOOST_ROOT}/lib ${BOOST_ROOT}/stage/lib)
+ _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${BOOST_ROOT}")
+ elseif(_ENV_BOOST_ROOT)
+ list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${_ENV_BOOST_ROOT}/lib ${_ENV_BOOST_ROOT}/stage/lib)
+ _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${_ENV_BOOST_ROOT}")
+ endif()
+
+ list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c}
+ ${Boost_INCLUDE_DIR}/lib
+ ${Boost_INCLUDE_DIR}/../lib
+ ${Boost_INCLUDE_DIR}/stage/lib
+ )
+ _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${Boost_INCLUDE_DIR}/..")
+ _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${Boost_INCLUDE_DIR}")
+ if( Boost_NO_SYSTEM_PATHS )
+ list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH)
+ else()
+ foreach(ver ${_boost_TEST_VERSIONS})
+ string(REPLACE "." "_" ver "${ver}")
+ _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "C:/local/boost_${ver}")
+ endforeach()
+ _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "C:/boost")
+ list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} PATHS
+ C:/boost/lib
+ C:/boost
+ /sw/local/lib
+ )
+ endif()
+ endif()
+endforeach()
+
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_LIBRARY_SEARCH_DIRS_RELEASE")
+_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_LIBRARY_SEARCH_DIRS_DEBUG")
+
+# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
+if( Boost_USE_STATIC_LIBS )
+ set( _boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ if(WIN32)
+ list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a)
+ else()
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
+ endif()
+endif()
+
+# We want to use the tag inline below without risking double dashes
+if(_boost_RELEASE_ABI_TAG)
+ if(${_boost_RELEASE_ABI_TAG} STREQUAL "-")
+ set(_boost_RELEASE_ABI_TAG "")
+ endif()
+endif()
+if(_boost_DEBUG_ABI_TAG)
+ if(${_boost_DEBUG_ABI_TAG} STREQUAL "-")
+ set(_boost_DEBUG_ABI_TAG "")
+ endif()
+endif()
+
+# The previous behavior of FindBoost when Boost_USE_STATIC_LIBS was enabled
+# on WIN32 was to:
+# 1. Search for static libs compiled against a SHARED C++ standard runtime library (use if found)
+# 2. Search for static libs compiled against a STATIC C++ standard runtime library (use if found)
+# We maintain this behavior since changing it could break people's builds.
+# To disable the ambiguous behavior, the user need only
+# set Boost_USE_STATIC_RUNTIME either ON or OFF.
+set(_boost_STATIC_RUNTIME_WORKAROUND false)
+if(WIN32 AND Boost_USE_STATIC_LIBS)
+ if(NOT DEFINED Boost_USE_STATIC_RUNTIME)
+ set(_boost_STATIC_RUNTIME_WORKAROUND TRUE)
+ endif()
+endif()
+
+# On versions < 1.35, remove the System library from the considered list
+# since it wasn't added until 1.35.
+if(Boost_VERSION_STRING AND Boost_FIND_COMPONENTS)
+ if(Boost_VERSION_STRING VERSION_LESS 1.35.0)
+ list(REMOVE_ITEM Boost_FIND_COMPONENTS system)
+ endif()
+endif()
+
+# Additional components may be required via component dependencies.
+# Add any missing components to the list.
+_Boost_MISSING_DEPENDENCIES(Boost_FIND_COMPONENTS _Boost_EXTRA_FIND_COMPONENTS)
+
+# If thread is required, get the thread libs as a dependency
+if("thread" IN_LIST Boost_FIND_COMPONENTS)
+ if(Boost_FIND_QUIETLY)
+ set(_Boost_find_quiet QUIET)
+ else()
+ set(_Boost_find_quiet "")
+ endif()
+ find_package(Threads ${_Boost_find_quiet})
+ unset(_Boost_find_quiet)
+endif()
+
+# If the user changed any of our control inputs flush previous results.
+if(_Boost_CHANGE_LIBDIR_DEBUG OR _Boost_CHANGE_LIBDIR_RELEASE OR _Boost_CHANGE_LIBNAME)
+ foreach(COMPONENT ${_Boost_COMPONENTS_SEARCHED})
+ string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
+ foreach(c DEBUG RELEASE)
+ set(_var Boost_${UPPERCOMPONENT}_LIBRARY_${c})
+ unset(${_var} CACHE)
+ set(${_var} "${_var}-NOTFOUND")
+ endforeach()
+ endforeach()
+ set(_Boost_COMPONENTS_SEARCHED "")
+endif()
+
+foreach(COMPONENT ${Boost_FIND_COMPONENTS})
+ string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
+
+ set( _boost_docstring_release "Boost ${COMPONENT} library (release)")
+ set( _boost_docstring_debug "Boost ${COMPONENT} library (debug)")
+
+ # Compute component-specific hints.
+ set(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT "")
+ if(${COMPONENT} STREQUAL "mpi" OR ${COMPONENT} STREQUAL "mpi_python" OR
+ ${COMPONENT} STREQUAL "graph_parallel")
+ foreach(lib ${MPI_CXX_LIBRARIES} ${MPI_C_LIBRARIES})
+ if(IS_ABSOLUTE "${lib}")
+ get_filename_component(libdir "${lib}" PATH)
+ string(REPLACE "\\" "/" libdir "${libdir}")
+ list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT ${libdir})
+ endif()
+ endforeach()
+ endif()
+
+ # Handle Python version suffixes
+ unset(COMPONENT_PYTHON_VERSION_MAJOR)
+ unset(COMPONENT_PYTHON_VERSION_MINOR)
+ if(${COMPONENT} MATCHES "^(python|mpi_python|numpy)([0-9])\$")
+ set(COMPONENT_UNVERSIONED "${CMAKE_MATCH_1}")
+ set(COMPONENT_PYTHON_VERSION_MAJOR "${CMAKE_MATCH_2}")
+ elseif(${COMPONENT} MATCHES "^(python|mpi_python|numpy)([0-9])\\.?([0-9])\$")
+ set(COMPONENT_UNVERSIONED "${CMAKE_MATCH_1}")
+ set(COMPONENT_PYTHON_VERSION_MAJOR "${CMAKE_MATCH_2}")
+ set(COMPONENT_PYTHON_VERSION_MINOR "${CMAKE_MATCH_3}")
+ endif()
+
+ unset(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME)
+ if (COMPONENT_PYTHON_VERSION_MINOR)
+ # Boost >= 1.67
+ list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}")
+ # Debian/Ubuntu (Some versions omit the 2 and/or 3 from the suffix)
+ list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}${COMPONENT_PYTHON_VERSION_MAJOR}-py${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}")
+ list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-py${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}")
+ # Gentoo
+ list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-${COMPONENT_PYTHON_VERSION_MAJOR}.${COMPONENT_PYTHON_VERSION_MINOR}")
+ # RPMs
+ list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}")
+ endif()
+ if (COMPONENT_PYTHON_VERSION_MAJOR AND NOT COMPONENT_PYTHON_VERSION_MINOR)
+ # Boost < 1.67
+ list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}${COMPONENT_PYTHON_VERSION_MAJOR}")
+ endif()
+
+ # Consolidate and report component-specific hints.
+ if(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME)
+ list(REMOVE_DUPLICATES _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME)
+ _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "Component-specific library search names for ${COMPONENT_NAME}: ${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME}")
+ endif()
+ if(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT)
+ list(REMOVE_DUPLICATES _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT)
+ _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "Component-specific library search paths for ${COMPONENT}: ${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT}")
+ endif()
+
+ #
+ # Find headers
+ #
+ _Boost_COMPONENT_HEADERS("${COMPONENT}" Boost_${UPPERCOMPONENT}_HEADER_NAME)
+ # Look for a standard boost header file.
+ if(Boost_${UPPERCOMPONENT}_HEADER_NAME)
+ if(EXISTS "${Boost_INCLUDE_DIR}/${Boost_${UPPERCOMPONENT}_HEADER_NAME}")
+ set(Boost_${UPPERCOMPONENT}_HEADER ON)
+ else()
+ set(Boost_${UPPERCOMPONENT}_HEADER OFF)
+ endif()
+ else()
+ set(Boost_${UPPERCOMPONENT}_HEADER ON)
+ message(WARNING "No header defined for ${COMPONENT}; skipping header check "
+ "(note: header-only libraries have no designated component)")
+ endif()
+
+ #
+ # Find RELEASE libraries
+ #
+ unset(_boost_RELEASE_NAMES)
+ foreach(component IN LISTS _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME COMPONENT)
+ foreach(compiler IN LISTS _boost_COMPILER)
+ list(APPEND _boost_RELEASE_NAMES
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} )
+ endforeach()
+ list(APPEND _boost_RELEASE_NAMES
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component} )
+ if(_boost_STATIC_RUNTIME_WORKAROUND)
+ set(_boost_RELEASE_STATIC_ABI_TAG "-s${_boost_RELEASE_ABI_TAG}")
+ foreach(compiler IN LISTS _boost_COMPILER)
+ list(APPEND _boost_RELEASE_NAMES
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} )
+ endforeach()
+ list(APPEND _boost_RELEASE_NAMES
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} )
+ endif()
+ endforeach()
+ if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread")
+ _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_RELEASE_NAMES ${_boost_RELEASE_NAMES})
+ endif()
+ _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "Searching for ${UPPERCOMPONENT}_LIBRARY_RELEASE: ${_boost_RELEASE_NAMES}")
+
+ # if Boost_LIBRARY_DIR_RELEASE is not defined,
+ # but Boost_LIBRARY_DIR_DEBUG is, look there first for RELEASE libs
+ if(NOT Boost_LIBRARY_DIR_RELEASE AND Boost_LIBRARY_DIR_DEBUG)
+ list(INSERT _boost_LIBRARY_SEARCH_DIRS_RELEASE 0 ${Boost_LIBRARY_DIR_DEBUG})
+ endif()
+
+ # Avoid passing backslashes to _Boost_FIND_LIBRARY due to macro re-parsing.
+ string(REPLACE "\\" "/" _boost_LIBRARY_SEARCH_DIRS_tmp "${_boost_LIBRARY_SEARCH_DIRS_RELEASE}")
+
+ if(Boost_USE_RELEASE_LIBS)
+ _Boost_FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE RELEASE
+ NAMES ${_boost_RELEASE_NAMES}
+ HINTS ${_boost_LIBRARY_SEARCH_DIRS_tmp}
+ NAMES_PER_DIR
+ DOC "${_boost_docstring_release}"
+ )
+ endif()
+
+ #
+ # Find DEBUG libraries
+ #
+ unset(_boost_DEBUG_NAMES)
+ foreach(component IN LISTS _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME COMPONENT)
+ foreach(compiler IN LISTS _boost_COMPILER)
+ list(APPEND _boost_DEBUG_NAMES
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} )
+ endforeach()
+ list(APPEND _boost_DEBUG_NAMES
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component} )
+ if(_boost_STATIC_RUNTIME_WORKAROUND)
+ set(_boost_DEBUG_STATIC_ABI_TAG "-s${_boost_DEBUG_ABI_TAG}")
+ foreach(compiler IN LISTS _boost_COMPILER)
+ list(APPEND _boost_DEBUG_NAMES
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} )
+ endforeach()
+ list(APPEND _boost_DEBUG_NAMES
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}
+ ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} )
+ endif()
+ endforeach()
+ if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread")
+ _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_DEBUG_NAMES ${_boost_DEBUG_NAMES})
+ endif()
+ _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "Searching for ${UPPERCOMPONENT}_LIBRARY_DEBUG: ${_boost_DEBUG_NAMES}")
+
+ # if Boost_LIBRARY_DIR_DEBUG is not defined,
+ # but Boost_LIBRARY_DIR_RELEASE is, look there first for DEBUG libs
+ if(NOT Boost_LIBRARY_DIR_DEBUG AND Boost_LIBRARY_DIR_RELEASE)
+ list(INSERT _boost_LIBRARY_SEARCH_DIRS_DEBUG 0 ${Boost_LIBRARY_DIR_RELEASE})
+ endif()
+
+ # Avoid passing backslashes to _Boost_FIND_LIBRARY due to macro re-parsing.
+ string(REPLACE "\\" "/" _boost_LIBRARY_SEARCH_DIRS_tmp "${_boost_LIBRARY_SEARCH_DIRS_DEBUG}")
+
+ if(Boost_USE_DEBUG_LIBS)
+ _Boost_FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG DEBUG
+ NAMES ${_boost_DEBUG_NAMES}
+ HINTS ${_boost_LIBRARY_SEARCH_DIRS_tmp}
+ NAMES_PER_DIR
+ DOC "${_boost_docstring_debug}"
+ )
+ endif ()
+
+ if(Boost_REALPATH)
+ _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE "${_boost_docstring_release}")
+ _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG "${_boost_docstring_debug}" )
+ endif()
+
+ _Boost_ADJUST_LIB_VARS(${UPPERCOMPONENT})
+
+ # Check if component requires some compiler features
+ _Boost_COMPILER_FEATURES(${COMPONENT} _Boost_${UPPERCOMPONENT}_COMPILER_FEATURES)
+
+endforeach()
+
+# Restore the original find library ordering
+if( Boost_USE_STATIC_LIBS )
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ${_boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
+endif()
+
+# ------------------------------------------------------------------------
+# End finding boost libraries
+# ------------------------------------------------------------------------
+
+set(Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIR})
+set(Boost_LIBRARY_DIRS)
+if(Boost_LIBRARY_DIR_RELEASE)
+ list(APPEND Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIR_RELEASE})
+endif()
+if(Boost_LIBRARY_DIR_DEBUG)
+ list(APPEND Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIR_DEBUG})
+endif()
+if(Boost_LIBRARY_DIRS)
+ list(REMOVE_DUPLICATES Boost_LIBRARY_DIRS)
+endif()
+
+# ------------------------------------------------------------------------
+# Call FPHSA helper, see https://cmake.org/cmake/help/latest/module/FindPackageHandleStandardArgs.html
+# ------------------------------------------------------------------------
+
+# Define aliases as needed by the component handler in the FPHSA helper below
+foreach(_comp IN LISTS Boost_FIND_COMPONENTS)
+ string(TOUPPER ${_comp} _uppercomp)
+ if(DEFINED Boost_${_uppercomp}_FOUND)
+ set(Boost_${_comp}_FOUND ${Boost_${_uppercomp}_FOUND})
+ endif()
+endforeach()
+
+find_package_handle_standard_args(Boost
+ REQUIRED_VARS Boost_INCLUDE_DIR
+ VERSION_VAR Boost_VERSION_STRING
+ HANDLE_COMPONENTS)
+
+if(Boost_FOUND)
+ if( NOT Boost_LIBRARY_DIRS )
+ # Compatibility Code for backwards compatibility with CMake
+ # 2.4's FindBoost module.
+
+ # Look for the boost library path.
+ # Note that the user may not have installed any libraries
+ # so it is quite possible the Boost_LIBRARY_DIRS may not exist.
+ set(_boost_LIB_DIR ${Boost_INCLUDE_DIR})
+
+ if("${_boost_LIB_DIR}" MATCHES "boost-[0-9]+")
+ get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH)
+ endif()
+
+ if("${_boost_LIB_DIR}" MATCHES "/include$")
+ # Strip off the trailing "/include" in the path.
+ get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH)
+ endif()
+
+ if(EXISTS "${_boost_LIB_DIR}/lib")
+ string(APPEND _boost_LIB_DIR /lib)
+ elseif(EXISTS "${_boost_LIB_DIR}/stage/lib")
+ string(APPEND _boost_LIB_DIR "/stage/lib")
+ else()
+ set(_boost_LIB_DIR "")
+ endif()
+
+ if(_boost_LIB_DIR AND EXISTS "${_boost_LIB_DIR}")
+ set(Boost_LIBRARY_DIRS ${_boost_LIB_DIR})
+ endif()
+
+ endif()
+else()
+ # Boost headers were not found so no components were found.
+ foreach(COMPONENT ${Boost_FIND_COMPONENTS})
+ string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
+ set(Boost_${UPPERCOMPONENT}_FOUND 0)
+ endforeach()
+endif()
+
+# ------------------------------------------------------------------------
+# Add imported targets
+# ------------------------------------------------------------------------
+
+if(Boost_FOUND)
+ # The builtin CMake package in Boost 1.70+ introduces a new name
+ # for the header-only lib, let's provide the same UI in module mode
+ if(NOT TARGET Boost::headers)
+ add_library(Boost::headers INTERFACE IMPORTED)
+ if(Boost_INCLUDE_DIRS)
+ set_target_properties(Boost::headers PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIRS}")
+ endif()
+ endif()
+
+ # Define the old target name for header-only libraries for backwards
+ # compat.
+ if(NOT TARGET Boost::boost)
+ add_library(Boost::boost INTERFACE IMPORTED)
+ set_target_properties(Boost::boost
+ PROPERTIES INTERFACE_LINK_LIBRARIES Boost::headers)
+ endif()
+
+ foreach(COMPONENT ${Boost_FIND_COMPONENTS})
+ if(_Boost_IMPORTED_TARGETS AND NOT TARGET Boost::${COMPONENT})
+ string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
+ if(Boost_${UPPERCOMPONENT}_FOUND)
+ if(Boost_USE_STATIC_LIBS)
+ add_library(Boost::${COMPONENT} STATIC IMPORTED)
+ else()
+ # Even if Boost_USE_STATIC_LIBS is OFF, we might have static
+ # libraries as a result.
+ add_library(Boost::${COMPONENT} UNKNOWN IMPORTED)
+ endif()
+ if(Boost_INCLUDE_DIRS)
+ set_target_properties(Boost::${COMPONENT} PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIRS}")
+ endif()
+ if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY}")
+ set_target_properties(Boost::${COMPONENT} PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
+ IMPORTED_LOCATION "${Boost_${UPPERCOMPONENT}_LIBRARY}")
+ endif()
+ if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE}")
+ set_property(TARGET Boost::${COMPONENT} APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(Boost::${COMPONENT} PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
+ IMPORTED_LOCATION_RELEASE "${Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE}")
+ endif()
+ if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG}")
+ set_property(TARGET Boost::${COMPONENT} APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(Boost::${COMPONENT} PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
+ IMPORTED_LOCATION_DEBUG "${Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG}")
+ endif()
+ if(_Boost_${UPPERCOMPONENT}_DEPENDENCIES)
+ unset(_Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES)
+ foreach(dep ${_Boost_${UPPERCOMPONENT}_DEPENDENCIES})
+ list(APPEND _Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES Boost::${dep})
+ endforeach()
+ if(COMPONENT STREQUAL "thread")
+ list(APPEND _Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES Threads::Threads)
+ endif()
+ set_target_properties(Boost::${COMPONENT} PROPERTIES
+ INTERFACE_LINK_LIBRARIES "${_Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES}")
+ endif()
+ if(_Boost_${UPPERCOMPONENT}_COMPILER_FEATURES)
+ set_target_properties(Boost::${COMPONENT} PROPERTIES
+ INTERFACE_COMPILE_FEATURES "${_Boost_${UPPERCOMPONENT}_COMPILER_FEATURES}")
+ endif()
+ endif()
+ endif()
+ endforeach()
+
+ # Supply Boost_LIB_DIAGNOSTIC_DEFINITIONS as a convenience target. It
+ # will only contain any interface definitions on WIN32, but is created
+ # on all platforms to keep end user code free from platform dependent
+ # code. Also provide convenience targets to disable autolinking and
+ # enable dynamic linking.
+ if(NOT TARGET Boost::diagnostic_definitions)
+ add_library(Boost::diagnostic_definitions INTERFACE IMPORTED)
+ add_library(Boost::disable_autolinking INTERFACE IMPORTED)
+ add_library(Boost::dynamic_linking INTERFACE IMPORTED)
+ set_target_properties(Boost::dynamic_linking PROPERTIES
+ INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_DYN_LINK")
+ endif()
+ if(WIN32)
+ # In windows, automatic linking is performed, so you do not have
+ # to specify the libraries. If you are linking to a dynamic
+ # runtime, then you can choose to link to either a static or a
+ # dynamic Boost library, the default is to do a static link. You
+ # can alter this for a specific library "whatever" by defining
+ # BOOST_WHATEVER_DYN_LINK to force Boost library "whatever" to be
+ # linked dynamically. Alternatively you can force all Boost
+ # libraries to dynamic link by defining BOOST_ALL_DYN_LINK.
+
+ # This feature can be disabled for Boost library "whatever" by
+ # defining BOOST_WHATEVER_NO_LIB, or for all of Boost by defining
+ # BOOST_ALL_NO_LIB.
+
+ # If you want to observe which libraries are being linked against
+ # then defining BOOST_LIB_DIAGNOSTIC will cause the auto-linking
+ # code to emit a #pragma message each time a library is selected
+ # for linking.
+ set(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC")
+ set_target_properties(Boost::diagnostic_definitions PROPERTIES
+ INTERFACE_COMPILE_DEFINITIONS "BOOST_LIB_DIAGNOSTIC")
+ set_target_properties(Boost::disable_autolinking PROPERTIES
+ INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB")
+ endif()
+endif()
+
+# ------------------------------------------------------------------------
+# Finalize
+# ------------------------------------------------------------------------
+
+# Report Boost_LIBRARIES
+set(Boost_LIBRARIES "")
+foreach(_comp IN LISTS Boost_FIND_COMPONENTS)
+ string(TOUPPER ${_comp} _uppercomp)
+ if(Boost_${_uppercomp}_FOUND)
+ list(APPEND Boost_LIBRARIES ${Boost_${_uppercomp}_LIBRARY})
+ if(_comp STREQUAL "thread")
+ list(APPEND Boost_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+ endif()
+ endif()
+endforeach()
+
+# Configure display of cache entries in GUI.
+foreach(v BOOSTROOT BOOST_ROOT ${_Boost_VARS_INC} ${_Boost_VARS_LIB})
+ get_property(_type CACHE ${v} PROPERTY TYPE)
+ if(_type)
+ set_property(CACHE ${v} PROPERTY ADVANCED 1)
+ if("x${_type}" STREQUAL "xUNINITIALIZED")
+ if("x${v}" STREQUAL "xBoost_ADDITIONAL_VERSIONS")
+ set_property(CACHE ${v} PROPERTY TYPE STRING)
+ else()
+ set_property(CACHE ${v} PROPERTY TYPE PATH)
+ endif()
+ endif()
+ endif()
+endforeach()
+
+# Record last used values of input variables so we can
+# detect on the next run if the user changed them.
+foreach(v
+ ${_Boost_VARS_INC} ${_Boost_VARS_LIB}
+ ${_Boost_VARS_DIR} ${_Boost_VARS_NAME}
+ )
+ if(DEFINED ${v})
+ set(_${v}_LAST "${${v}}" CACHE INTERNAL "Last used ${v} value.")
+ else()
+ unset(_${v}_LAST CACHE)
+ endif()
+endforeach()
+
+# Maintain a persistent list of components requested anywhere since
+# the last flush.
+set(_Boost_COMPONENTS_SEARCHED "${_Boost_COMPONENTS_SEARCHED}")
+list(APPEND _Boost_COMPONENTS_SEARCHED ${Boost_FIND_COMPONENTS})
+list(REMOVE_DUPLICATES _Boost_COMPONENTS_SEARCHED)
+list(SORT _Boost_COMPONENTS_SEARCHED)
+set(_Boost_COMPONENTS_SEARCHED "${_Boost_COMPONENTS_SEARCHED}"
+ CACHE INTERNAL "Components requested for this build tree.")
+
+# Restore project's policies
+cmake_policy(POP)
diff --git a/Modules/FindBullet.cmake b/Modules/FindBullet.cmake
new file mode 100644
index 0000000..6d64185
--- /dev/null
+++ b/Modules/FindBullet.cmake
@@ -0,0 +1,93 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindBullet
+----------
+
+Try to find the Bullet physics engine
+
+
+
+::
+
+ This module defines the following variables
+
+
+
+::
+
+ BULLET_FOUND - Was bullet found
+ BULLET_INCLUDE_DIRS - the Bullet include directories
+ BULLET_LIBRARIES - Link to this, by default it includes
+ all bullet components (Dynamics,
+ Collision, LinearMath, & SoftBody)
+
+
+
+::
+
+ This module accepts the following variables
+
+
+
+::
+
+ BULLET_ROOT - Can be set to bullet install path or Windows build path
+#]=======================================================================]
+
+macro(_FIND_BULLET_LIBRARY _var)
+ find_library(${_var}
+ NAMES
+ ${ARGN}
+ HINTS
+ ${BULLET_ROOT}
+ ${BULLET_ROOT}/lib/Release
+ ${BULLET_ROOT}/lib/Debug
+ ${BULLET_ROOT}/out/release8/libs
+ ${BULLET_ROOT}/out/debug8/libs
+ PATH_SUFFIXES lib
+ )
+ mark_as_advanced(${_var})
+endmacro()
+
+macro(_BULLET_APPEND_LIBRARIES _list _release)
+ set(_debug ${_release}_DEBUG)
+ if(${_debug})
+ set(${_list} ${${_list}} optimized ${${_release}} debug ${${_debug}})
+ else()
+ set(${_list} ${${_list}} ${${_release}})
+ endif()
+endmacro()
+
+find_path(BULLET_INCLUDE_DIR NAMES btBulletCollisionCommon.h
+ HINTS
+ ${BULLET_ROOT}/include
+ ${BULLET_ROOT}/src
+ PATH_SUFFIXES bullet
+)
+
+# Find the libraries
+
+_FIND_BULLET_LIBRARY(BULLET_DYNAMICS_LIBRARY BulletDynamics)
+_FIND_BULLET_LIBRARY(BULLET_DYNAMICS_LIBRARY_DEBUG BulletDynamics_Debug BulletDynamics_d)
+_FIND_BULLET_LIBRARY(BULLET_COLLISION_LIBRARY BulletCollision)
+_FIND_BULLET_LIBRARY(BULLET_COLLISION_LIBRARY_DEBUG BulletCollision_Debug BulletCollision_d)
+_FIND_BULLET_LIBRARY(BULLET_MATH_LIBRARY BulletMath LinearMath)
+_FIND_BULLET_LIBRARY(BULLET_MATH_LIBRARY_DEBUG BulletMath_Debug BulletMath_d LinearMath_Debug LinearMath_d)
+_FIND_BULLET_LIBRARY(BULLET_SOFTBODY_LIBRARY BulletSoftBody)
+_FIND_BULLET_LIBRARY(BULLET_SOFTBODY_LIBRARY_DEBUG BulletSoftBody_Debug BulletSoftBody_d)
+
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Bullet DEFAULT_MSG
+ BULLET_DYNAMICS_LIBRARY BULLET_COLLISION_LIBRARY BULLET_MATH_LIBRARY
+ BULLET_SOFTBODY_LIBRARY BULLET_INCLUDE_DIR)
+
+set(BULLET_INCLUDE_DIRS ${BULLET_INCLUDE_DIR})
+if(BULLET_FOUND)
+ _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_DYNAMICS_LIBRARY)
+ _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_COLLISION_LIBRARY)
+ _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_MATH_LIBRARY)
+ _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_SOFTBODY_LIBRARY)
+endif()
diff --git a/Modules/FindCABLE.cmake b/Modules/FindCABLE.cmake
new file mode 100644
index 0000000..1f4ae76
--- /dev/null
+++ b/Modules/FindCABLE.cmake
@@ -0,0 +1,82 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindCABLE
+---------
+
+Find CABLE
+
+This module finds if CABLE is installed and determines where the
+include files and libraries are. This code sets the following
+variables:
+
+::
+
+ CABLE the path to the cable executable
+ CABLE_TCL_LIBRARY the path to the Tcl wrapper library
+ CABLE_INCLUDE_DIR the path to the include directory
+
+
+
+To build Tcl wrappers, you should add shared library and link it to
+${CABLE_TCL_LIBRARY}. You should also add ${CABLE_INCLUDE_DIR} as an
+include directory.
+#]=======================================================================]
+
+if(NOT CABLE)
+ find_path(CABLE_BUILD_DIR cableVersion.h)
+endif()
+
+if(CABLE_BUILD_DIR)
+ load_cache(${CABLE_BUILD_DIR}
+ EXCLUDE
+ BUILD_SHARED_LIBS
+ LIBRARY_OUTPUT_PATH
+ EXECUTABLE_OUTPUT_PATH
+ MAKECOMMAND
+ CMAKE_INSTALL_PREFIX
+ INCLUDE_INTERNALS
+ CABLE_LIBRARY_PATH
+ CABLE_EXECUTABLE_PATH)
+
+ if(CABLE_LIBRARY_PATH)
+ find_library(CABLE_TCL_LIBRARY NAMES CableTclFacility PATHS
+ ${CABLE_LIBRARY_PATH}
+ ${CABLE_LIBRARY_PATH}/*)
+ else()
+ find_library(CABLE_TCL_LIBRARY NAMES CableTclFacility PATHS
+ ${CABLE_BINARY_DIR}/CableTclFacility
+ ${CABLE_BINARY_DIR}/CableTclFacility/*)
+ endif()
+
+ if(CABLE_EXECUTABLE_PATH)
+ find_program(CABLE NAMES cable PATHS
+ ${CABLE_EXECUTABLE_PATH}
+ ${CABLE_EXECUTABLE_PATH}/*)
+ else()
+ find_program(CABLE NAMES cable PATHS
+ ${CABLE_BINARY_DIR}/Executables
+ ${CABLE_BINARY_DIR}/Executables/*)
+ endif()
+
+ find_path(CABLE_INCLUDE_DIR CableTclFacility/ctCalls.h
+ ${CABLE_SOURCE_DIR})
+else()
+ # Find the cable executable in the path.
+ find_program(CABLE NAMES cable)
+
+ # Get the path where the executable sits, but without the executable
+ # name on it.
+ get_filename_component(CABLE_ROOT_BIN ${CABLE} PATH)
+
+ # Find the cable include directory in a path relative to the cable
+ # executable.
+ find_path(CABLE_INCLUDE_DIR CableTclFacility/ctCalls.h
+ ${CABLE_ROOT_BIN}/../include/Cable)
+
+ # Find the WrapTclFacility library in a path relative to the cable
+ # executable.
+ find_library(CABLE_TCL_LIBRARY NAMES CableTclFacility PATHS
+ ${CABLE_ROOT_BIN}/../lib/Cable)
+endif()
diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake
new file mode 100644
index 0000000..620e32a
--- /dev/null
+++ b/Modules/FindCUDA.cmake
@@ -0,0 +1,2172 @@
+#[=======================================================================[.rst:
+FindCUDA
+--------
+
+.. deprecated:: 3.10
+
+It is no longer necessary to use this module or call ``find_package(CUDA)``
+for compiling CUDA code. Instead, list ``CUDA`` among the languages named
+in the top-level call to the :command:`project` command, or call the
+:command:`enable_language` command with ``CUDA``.
+Then one can add CUDA (``.cu``) sources to programs directly
+in calls to :command:`add_library` and :command:`add_executable`.
+
+.. versionadded:: 3.17
+ To find and use the CUDA toolkit libraries the :module:`FindCUDAToolkit`
+ module has superseded this module. It works whether or not the ``CUDA``
+ language is enabled.
+
+Documentation of Deprecated Usage
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Tools for building CUDA C files: libraries and build dependencies.
+
+This script locates the NVIDIA CUDA C tools. It should work on Linux,
+Windows, and macOS and should be reasonably up to date with CUDA C
+releases.
+
+.. versionadded:: 3.19
+ QNX support.
+
+This script makes use of the standard :command:`find_package` arguments of
+``<VERSION>``, ``REQUIRED`` and ``QUIET``. ``CUDA_FOUND`` will report if an
+acceptable version of CUDA was found.
+
+The script will prompt the user to specify ``CUDA_TOOLKIT_ROOT_DIR`` if
+the prefix cannot be determined by the location of nvcc in the system
+path and ``REQUIRED`` is specified to :command:`find_package`. To use
+a different installed version of the toolkit set the environment variable
+``CUDA_BIN_PATH`` before running cmake (e.g.
+``CUDA_BIN_PATH=/usr/local/cuda1.0`` instead of the default
+``/usr/local/cuda``) or set ``CUDA_TOOLKIT_ROOT_DIR`` after configuring. If
+you change the value of ``CUDA_TOOLKIT_ROOT_DIR``, various components that
+depend on the path will be relocated.
+
+It might be necessary to set ``CUDA_TOOLKIT_ROOT_DIR`` manually on certain
+platforms, or to use a CUDA runtime not installed in the default
+location. In newer versions of the toolkit the CUDA library is
+included with the graphics driver -- be sure that the driver version
+matches what is needed by the CUDA runtime version.
+
+Input Variables
+"""""""""""""""
+
+The following variables affect the behavior of the macros in the
+script (in alphabetical order). Note that any of these flags can be
+changed multiple times in the same directory before calling
+``cuda_add_executable()``, ``cuda_add_library()``, ``cuda_compile()``,
+``cuda_compile_ptx()``, ``cuda_compile_fatbin()``, ``cuda_compile_cubin()``
+or ``cuda_wrap_srcs()``:
+
+``CUDA_64_BIT_DEVICE_CODE`` (Default: host bit size)
+ Set to ``ON`` to compile for 64 bit device code, OFF for 32 bit device code.
+ Note that making this different from the host code when generating object
+ or C files from CUDA code just won't work, because size_t gets defined by
+ nvcc in the generated source. If you compile to PTX and then load the
+ file yourself, you can mix bit sizes between device and host.
+
+``CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE`` (Default: ``ON``)
+ Set to ``ON`` if you want the custom build rule to be attached to the source
+ file in Visual Studio. Turn OFF if you add the same cuda file to multiple
+ targets.
+
+ This allows the user to build the target from the CUDA file; however, bad
+ things can happen if the CUDA source file is added to multiple targets.
+ When performing parallel builds it is possible for the custom build
+ command to be run more than once and in parallel causing cryptic build
+ errors. VS runs the rules for every source file in the target, and a
+ source can have only one rule no matter how many projects it is added to.
+ When the rule is run from multiple targets race conditions can occur on
+ the generated file. Eventually everything will get built, but if the user
+ is unaware of this behavior, there may be confusion. It would be nice if
+ this script could detect the reuse of source files across multiple targets
+ and turn the option off for the user, but no good solution could be found.
+
+``CUDA_BUILD_CUBIN`` (Default: ``OFF``)
+ Set to ``ON`` to enable and extra compilation pass with the ``-cubin`` option in
+ Device mode. The output is parsed and register, shared memory usage is
+ printed during build.
+
+``CUDA_BUILD_EMULATION`` (Default: ``OFF`` for device mode)
+ Set to ``ON`` for Emulation mode. ``-D_DEVICEEMU`` is defined for CUDA C files
+ when ``CUDA_BUILD_EMULATION`` is ``TRUE``.
+
+``CUDA_LINK_LIBRARIES_KEYWORD`` (Default: ``""``)
+ .. versionadded:: 3.9
+
+ The ``<PRIVATE|PUBLIC|INTERFACE>`` keyword to use for internal
+ :command:`target_link_libraries` calls. The default is to use no keyword which
+ uses the old "plain" form of :command:`target_link_libraries`. Note that is matters
+ because whatever is used inside the ``FindCUDA`` module must also be used
+ outside - the two forms of :command:`target_link_libraries` cannot be mixed.
+
+``CUDA_GENERATED_OUTPUT_DIR`` (Default: :variable:`CMAKE_CURRENT_BINARY_DIR`)
+ Set to the path you wish to have the generated files placed. If it is
+ blank output files will be placed in :variable:`CMAKE_CURRENT_BINARY_DIR`.
+ Intermediate files will always be placed in
+ ``CMAKE_CURRENT_BINARY_DIR/CMakeFiles``.
+
+``CUDA_HOST_COMPILATION_CPP`` (Default: ``ON``)
+ Set to ``OFF`` for C compilation of host code.
+
+``CUDA_HOST_COMPILER`` (Default: ``CMAKE_C_COMPILER``)
+ Set the host compiler to be used by nvcc. Ignored if ``-ccbin`` or
+ ``--compiler-bindir`` is already present in the ``CUDA_NVCC_FLAGS`` or
+ ``CUDA_NVCC_FLAGS_<CONFIG>`` variables. For Visual Studio targets,
+ the host compiler is constructed with one or more visual studio macros
+ such as ``$(VCInstallDir)``, that expands out to the path when
+ the command is run from within VS.
+
+ .. versionadded:: 3.13
+ If the :envvar:`CUDAHOSTCXX` environment variable is set it will
+ be used as the default.
+
+``CUDA_NVCC_FLAGS``, ``CUDA_NVCC_FLAGS_<CONFIG>``
+ Additional NVCC command line arguments. NOTE: multiple arguments must be
+ semi-colon delimited (e.g. ``--compiler-options;-Wall``)
+
+ .. versionadded:: 3.6
+ Contents of these variables may use
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+``CUDA_PROPAGATE_HOST_FLAGS`` (Default: ``ON``)
+ Set to ``ON`` to propagate :variable:`CMAKE_{C,CXX}_FLAGS <CMAKE_<LANG>_FLAGS>` and their configuration
+ dependent counterparts (e.g. ``CMAKE_C_FLAGS_DEBUG``) automatically to the
+ host compiler through nvcc's ``-Xcompiler`` flag. This helps make the
+ generated host code match the rest of the system better. Sometimes
+ certain flags give nvcc problems, and this will help you turn the flag
+ propagation off. This does not affect the flags supplied directly to nvcc
+ via ``CUDA_NVCC_FLAGS`` or through the ``OPTION`` flags specified through
+ ``cuda_add_library()``, ``cuda_add_executable()``, or ``cuda_wrap_srcs()``. Flags used for
+ shared library compilation are not affected by this flag.
+
+``CUDA_SEPARABLE_COMPILATION`` (Default: ``OFF``)
+ If set this will enable separable compilation for all CUDA runtime object
+ files. If used outside of ``cuda_add_executable()`` and ``cuda_add_library()``
+ (e.g. calling ``cuda_wrap_srcs()`` directly),
+ ``cuda_compute_separable_compilation_object_file_name()`` and
+ ``cuda_link_separable_compilation_objects()`` should be called.
+
+``CUDA_SOURCE_PROPERTY_FORMAT``
+ .. versionadded:: 3.3
+
+ If this source file property is set, it can override the format specified
+ to ``cuda_wrap_srcs()`` (``OBJ``, ``PTX``, ``CUBIN``, or ``FATBIN``). If an input source file
+ is not a ``.cu`` file, setting this file will cause it to be treated as a ``.cu``
+ file. See documentation for set_source_files_properties on how to set
+ this property.
+
+``CUDA_USE_STATIC_CUDA_RUNTIME`` (Default: ``ON``)
+ .. versionadded:: 3.3
+
+ When enabled the static version of the CUDA runtime library will be used
+ in ``CUDA_LIBRARIES``. If the version of CUDA configured doesn't support
+ this option, then it will be silently disabled.
+
+``CUDA_VERBOSE_BUILD`` (Default: ``OFF``)
+ Set to ``ON`` to see all the commands used when building the CUDA file. When
+ using a Makefile generator the value defaults to ``VERBOSE`` (run
+ ``make VERBOSE=1`` to see output), although setting ``CUDA_VERBOSE_BUILD`` to ``ON`` will
+ always print the output.
+
+Commands
+""""""""
+
+The script creates the following functions and macros (in alphabetical order):
+
+.. code-block:: cmake
+
+ cuda_add_cufft_to_target(<cuda_target>)
+
+Adds the cufft library to the target (can be any target). Handles whether
+you are in emulation mode or not.
+
+.. code-block:: cmake
+
+ cuda_add_cublas_to_target(<cuda_target>)
+
+Adds the cublas library to the target (can be any target). Handles
+whether you are in emulation mode or not.
+
+.. code-block:: cmake
+
+ cuda_add_executable(<cuda_target> <file>...
+ [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [OPTIONS ...])
+
+Creates an executable ``<cuda_target>`` which is made up of the files
+specified. All of the non CUDA C files are compiled using the standard
+build rules specified by CMake and the CUDA files are compiled to object
+files using nvcc and the host compiler. In addition ``CUDA_INCLUDE_DIRS`` is
+added automatically to :command:`include_directories`. Some standard CMake target
+calls can be used on the target after calling this macro
+(e.g. :command:`set_target_properties` and :command:`target_link_libraries`), but setting
+properties that adjust compilation flags will not affect code compiled by
+nvcc. Such flags should be modified before calling ``cuda_add_executable()``,
+``cuda_add_library()`` or ``cuda_wrap_srcs()``.
+
+.. code-block:: cmake
+
+ cuda_add_library(<cuda_target> <file>...
+ [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [OPTIONS ...])
+
+Same as ``cuda_add_executable()`` except that a library is created.
+
+.. code-block:: cmake
+
+ cuda_build_clean_target()
+
+Creates a convenience target that deletes all the dependency files
+generated. You should make clean after running this target to ensure the
+dependency files get regenerated.
+
+.. code-block:: cmake
+
+ cuda_compile(<generated_files> <file>... [STATIC | SHARED | MODULE]
+ [OPTIONS ...])
+
+Returns a list of generated files from the input source files to be used
+with :command:`add_library` or :command:`add_executable`.
+
+.. code-block:: cmake
+
+ cuda_compile_ptx(<generated_files> <file>... [OPTIONS ...])
+
+Returns a list of ``PTX`` files generated from the input source files.
+
+.. code-block:: cmake
+
+ cuda_compile_fatbin(<generated_files> <file>... [OPTIONS ...])
+
+.. versionadded:: 3.1
+
+Returns a list of ``FATBIN`` files generated from the input source files.
+
+.. code-block:: cmake
+
+ cuda_compile_cubin(<generated_files> <file>... [OPTIONS ...])
+
+.. versionadded:: 3.1
+
+Returns a list of ``CUBIN`` files generated from the input source files.
+
+.. code-block:: cmake
+
+ cuda_compute_separable_compilation_object_file_name(<output_file_var>
+ <cuda_target>
+ <object_files>)
+
+Compute the name of the intermediate link file used for separable
+compilation. This file name is typically passed into
+``CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS``. output_file_var is produced
+based on cuda_target the list of objects files that need separable
+compilation as specified by ``<object_files>``. If the ``<object_files>`` list is
+empty, then ``<output_file_var>`` will be empty. This function is called
+automatically for ``cuda_add_library()`` and ``cuda_add_executable()``. Note that
+this is a function and not a macro.
+
+.. code-block:: cmake
+
+ cuda_include_directories(path0 path1 ...)
+
+Sets the directories that should be passed to nvcc
+(e.g. ``nvcc -Ipath0 -Ipath1 ...``). These paths usually contain other ``.cu``
+files.
+
+.. code-block:: cmake
+
+ cuda_link_separable_compilation_objects(<output_file_var> <cuda_target>
+ <nvcc_flags> <object_files>)
+
+Generates the link object required by separable compilation from the given
+object files. This is called automatically for ``cuda_add_executable()`` and
+``cuda_add_library()``, but can be called manually when using ``cuda_wrap_srcs()``
+directly. When called from ``cuda_add_library()`` or ``cuda_add_executable()`` the
+``<nvcc_flags>`` passed in are the same as the flags passed in via the ``OPTIONS``
+argument. The only nvcc flag added automatically is the bitness flag as
+specified by ``CUDA_64_BIT_DEVICE_CODE``. Note that this is a function
+instead of a macro.
+
+.. code-block:: cmake
+
+ cuda_select_nvcc_arch_flags(<out_variable> [<target_CUDA_architecture> ...])
+
+Selects GPU arch flags for nvcc based on ``target_CUDA_architecture``.
+
+Values for ``target_CUDA_architecture``:
+
+* ``Auto``: detects local machine GPU compute arch at runtime.
+* ``Common`` and ``All``: cover common and entire subsets of architectures.
+* ``<name>``: one of ``Fermi``, ``Kepler``, ``Maxwell``, ``Kepler+Tegra``, ``Kepler+Tesla``, ``Maxwell+Tegra``, ``Pascal``.
+* ``<ver>``, ``<ver>(<ver>)``, ``<ver>+PTX``, where ``<ver>`` is one of
+ ``2.0``, ``2.1``, ``3.0``, ``3.2``, ``3.5``, ``3.7``, ``5.0``, ``5.2``, ``5.3``, ``6.0``, ``6.2``.
+
+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::
+
+ cuda_select_nvcc_arch_flags(ARCH_FLAGS 3.0 3.5+PTX 5.2(5.0) Maxwell)
+ list(APPEND CUDA_NVCC_FLAGS ${ARCH_FLAGS})
+
+More info on CUDA architectures: https://en.wikipedia.org/wiki/CUDA.
+Note that this is a function instead of a macro.
+
+.. code-block:: cmake
+
+ cuda_wrap_srcs(<cuda_target> <format> <generated_files> <file>...
+ [STATIC | SHARED | MODULE] [OPTIONS ...])
+
+This is where all the magic happens. ``cuda_add_executable()``,
+``cuda_add_library()``, ``cuda_compile()``, and ``cuda_compile_ptx()`` all call this
+function under the hood.
+
+Given the list of files ``<file>...`` this macro generates
+custom commands that generate either PTX or linkable objects (use ``PTX`` or
+``OBJ`` for the ``<format>`` argument to switch). Files that don't end with ``.cu``
+or have the ``HEADER_FILE_ONLY`` property are ignored.
+
+The arguments passed in after ``OPTIONS`` are extra command line options to
+give to nvcc. You can also specify per configuration options by
+specifying the name of the configuration followed by the options. General
+options must precede configuration specific options. Not all
+configurations need to be specified, only the ones provided will be used.
+For example:
+
+.. code-block:: cmake
+
+ cuda_add_executable(...
+ OPTIONS -DFLAG=2 "-DFLAG_OTHER=space in flag"
+ DEBUG -g
+ RELEASE --use_fast_math
+ RELWITHDEBINFO --use_fast_math;-g
+ MINSIZEREL --use_fast_math)
+
+For certain configurations (namely VS generating object files with
+``CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE`` set to ``ON``), no generated file will
+be produced for the given cuda file. This is because when you add the
+cuda file to Visual Studio it knows that this file produces an object file
+and will link in the resulting object file automatically.
+
+This script will also generate a separate cmake script that is used at
+build time to invoke nvcc. This is for several reasons:
+
+* nvcc can return negative numbers as return values which confuses
+ Visual Studio into thinking that the command succeeded. The script now
+ checks the error codes and produces errors when there was a problem.
+
+* nvcc has been known to not delete incomplete results when it
+ encounters problems. This confuses build systems into thinking the
+ target was generated when in fact an unusable file exists. The script
+ now deletes the output files if there was an error.
+
+* By putting all the options that affect the build into a file and then
+ make the build rule dependent on the file, the output files will be
+ regenerated when the options change.
+
+This script also looks at optional arguments ``STATIC``, ``SHARED``, or ``MODULE`` to
+determine when to target the object compilation for a shared library.
+:variable:`BUILD_SHARED_LIBS` is ignored in ``cuda_wrap_srcs()``, but it is respected in
+``cuda_add_library()``. On some systems special flags are added for building
+objects intended for shared libraries. A preprocessor macro,
+``<target_name>_EXPORTS`` is defined when a shared library compilation is
+detected.
+
+Flags passed into add_definitions with ``-D`` or ``/D`` are passed along to nvcc.
+
+Result Variables
+""""""""""""""""
+
+The script defines the following variables:
+
+``CUDA_VERSION_MAJOR``
+ The major version of cuda as reported by nvcc.
+
+``CUDA_VERSION_MINOR``
+ The minor version.
+
+``CUDA_VERSION``, ``CUDA_VERSION_STRING``
+ Full version in the ``X.Y`` format.
+
+``CUDA_HAS_FP16``
+ .. versionadded:: 3.6
+ Whether a short float (``float16``, ``fp16``) is supported.
+
+``CUDA_TOOLKIT_ROOT_DIR``
+ Path to the CUDA Toolkit (defined if not set).
+
+``CUDA_SDK_ROOT_DIR``
+ Path to the CUDA SDK. Use this to find files in the SDK. This script will
+ not directly support finding specific libraries or headers, as that isn't
+ supported by NVIDIA. If you want to change libraries when the path changes
+ see the ``FindCUDA.cmake`` script for an example of how to clear these
+ variables. There are also examples of how to use the ``CUDA_SDK_ROOT_DIR``
+ to locate headers or libraries, if you so choose (at your own risk).
+
+``CUDA_INCLUDE_DIRS``
+ Include directory for cuda headers. Added automatically
+ for ``cuda_add_executable()`` and ``cuda_add_library()``.
+
+``CUDA_LIBRARIES``
+ Cuda RT library.
+
+``CUDA_CUFFT_LIBRARIES``
+ Device or emulation library for the Cuda FFT implementation (alternative to
+ ``cuda_add_cufft_to_target()`` macro)
+
+``CUDA_CUBLAS_LIBRARIES``
+ Device or emulation library for the Cuda BLAS implementation (alternative to
+ ``cuda_add_cublas_to_target()`` macro).
+
+``CUDA_cudart_static_LIBRARY``
+ Statically linkable cuda runtime library.
+ Only available for CUDA version 5.5+.
+
+``CUDA_cudadevrt_LIBRARY``
+ .. versionadded:: 3.7
+ Device runtime library. Required for separable compilation.
+
+``CUDA_cupti_LIBRARY``
+ CUDA Profiling Tools Interface library.
+ Only available for CUDA version 4.0+.
+
+``CUDA_curand_LIBRARY``
+ CUDA Random Number Generation library.
+ Only available for CUDA version 3.2+.
+
+``CUDA_cusolver_LIBRARY``
+ .. versionadded:: 3.2
+ CUDA Direct Solver library.
+ Only available for CUDA version 7.0+.
+
+``CUDA_cusparse_LIBRARY``
+ CUDA Sparse Matrix library.
+ Only available for CUDA version 3.2+.
+
+``CUDA_npp_LIBRARY``
+ NVIDIA Performance Primitives lib.
+ Only available for CUDA version 4.0+.
+
+``CUDA_nppc_LIBRARY``
+ NVIDIA Performance Primitives lib (core).
+ Only available for CUDA version 5.5+.
+
+``CUDA_nppi_LIBRARY``
+ NVIDIA Performance Primitives lib (image processing).
+ Only available for CUDA version 5.5 - 8.0.
+
+``CUDA_nppial_LIBRARY``
+ NVIDIA Performance Primitives lib (image processing).
+ Only available for CUDA version 9.0.
+
+``CUDA_nppicc_LIBRARY``
+ NVIDIA Performance Primitives lib (image processing).
+ Only available for CUDA version 9.0.
+
+``CUDA_nppicom_LIBRARY``
+ NVIDIA Performance Primitives lib (image processing).
+ Only available for CUDA version 9.0 - 10.2.
+ Replaced by nvjpeg.
+
+``CUDA_nppidei_LIBRARY``
+ NVIDIA Performance Primitives lib (image processing).
+ Only available for CUDA version 9.0.
+
+``CUDA_nppif_LIBRARY``
+ NVIDIA Performance Primitives lib (image processing).
+ Only available for CUDA version 9.0.
+
+``CUDA_nppig_LIBRARY``
+ NVIDIA Performance Primitives lib (image processing).
+ Only available for CUDA version 9.0.
+
+``CUDA_nppim_LIBRARY``
+ NVIDIA Performance Primitives lib (image processing).
+ Only available for CUDA version 9.0.
+
+``CUDA_nppist_LIBRARY``
+ NVIDIA Performance Primitives lib (image processing).
+ Only available for CUDA version 9.0.
+
+``CUDA_nppisu_LIBRARY``
+ NVIDIA Performance Primitives lib (image processing).
+ Only available for CUDA version 9.0.
+
+``CUDA_nppitc_LIBRARY``
+ NVIDIA Performance Primitives lib (image processing).
+ Only available for CUDA version 9.0.
+
+``CUDA_npps_LIBRARY``
+ NVIDIA Performance Primitives lib (signal processing).
+ Only available for CUDA version 5.5+.
+
+``CUDA_nvcuvenc_LIBRARY``
+ CUDA Video Encoder library.
+ Only available for CUDA version 3.2+.
+ Windows only.
+
+``CUDA_nvcuvid_LIBRARY``
+ CUDA Video Decoder library.
+ Only available for CUDA version 3.2+.
+ Windows only.
+
+``CUDA_nvToolsExt_LIBRARY``
+ .. versionadded:: 3.16
+ NVIDA CUDA Tools Extension library.
+ Available for CUDA version 5+.
+
+``CUDA_OpenCL_LIBRARY``
+ .. versionadded:: 3.16
+ NVIDA CUDA OpenCL library.
+ Available for CUDA version 5+.
+
+#]=======================================================================]
+
+# James Bigler, NVIDIA Corp (nvidia.com - jbigler)
+# Abe Stephens, SCI Institute -- http://www.sci.utah.edu/~abe/FindCuda.html
+#
+# Copyright (c) 2008 - 2009 NVIDIA Corporation. All rights reserved.
+#
+# Copyright (c) 2007-2009
+# Scientific Computing and Imaging Institute, University of Utah
+#
+# This code is licensed under the MIT License. See the FindCUDA.cmake script
+# for the text of the license.
+
+# The MIT License
+#
+# License for the specific language governing rights and limitations under
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+###############################################################################
+
+# FindCUDA.cmake
+
+# This macro helps us find the location of helper files we will need the full path to
+macro(CUDA_FIND_HELPER_FILE _name _extension)
+ set(_full_name "${_name}.${_extension}")
+ # CMAKE_CURRENT_LIST_FILE contains the full path to the file currently being
+ # processed. Using this variable, we can pull out the current path, and
+ # provide a way to get access to the other files we need local to here.
+ get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+ set(CUDA_${_name} "${CMAKE_CURRENT_LIST_DIR}/FindCUDA/${_full_name}")
+ if(NOT EXISTS "${CUDA_${_name}}")
+ set(error_message "${_full_name} not found in ${CMAKE_CURRENT_LIST_DIR}/FindCUDA")
+ if(CUDA_FIND_REQUIRED)
+ message(FATAL_ERROR "${error_message}")
+ else()
+ if(NOT CUDA_FIND_QUIETLY)
+ message(STATUS "${error_message}")
+ endif()
+ endif()
+ endif()
+ # Set this variable as internal, so the user isn't bugged with it.
+ set(CUDA_${_name} ${CUDA_${_name}} CACHE INTERNAL "Location of ${_full_name}" FORCE)
+endmacro()
+
+#####################################################################
+## CUDA_INCLUDE_NVCC_DEPENDENCIES
+##
+
+# So we want to try and include the dependency file if it exists. If
+# it doesn't exist then we need to create an empty one, so we can
+# include it.
+
+# If it does exist, then we need to check to see if all the files it
+# depends on exist. If they don't then we should clear the dependency
+# file and regenerate it later. This covers the case where a header
+# file has disappeared or moved.
+
+macro(CUDA_INCLUDE_NVCC_DEPENDENCIES dependency_file)
+ set(CUDA_NVCC_DEPEND)
+ set(CUDA_NVCC_DEPEND_REGENERATE FALSE)
+
+
+ # Include the dependency file. Create it first if it doesn't exist . The
+ # INCLUDE puts a dependency that will force CMake to rerun and bring in the
+ # new info when it changes. DO NOT REMOVE THIS (as I did and spent a few
+ # hours figuring out why it didn't work.
+ if(NOT EXISTS ${dependency_file})
+ file(WRITE ${dependency_file} "#FindCUDA.cmake generated file. Do not edit.\n")
+ endif()
+ # Always include this file to force CMake to run again next
+ # invocation and rebuild the dependencies.
+ #message("including dependency_file = ${dependency_file}")
+ include(${dependency_file})
+
+ # Now we need to verify the existence of all the included files
+ # here. If they aren't there we need to just blank this variable and
+ # make the file regenerate again.
+# if(DEFINED CUDA_NVCC_DEPEND)
+# message("CUDA_NVCC_DEPEND set")
+# else()
+# message("CUDA_NVCC_DEPEND NOT set")
+# endif()
+ if(CUDA_NVCC_DEPEND)
+ #message("CUDA_NVCC_DEPEND found")
+ foreach(f ${CUDA_NVCC_DEPEND})
+ # message("searching for ${f}")
+ if(NOT EXISTS ${f})
+ #message("file ${f} not found")
+ set(CUDA_NVCC_DEPEND_REGENERATE TRUE)
+ endif()
+ endforeach()
+ else()
+ #message("CUDA_NVCC_DEPEND false")
+ # No dependencies, so regenerate the file.
+ set(CUDA_NVCC_DEPEND_REGENERATE TRUE)
+ endif()
+
+ #message("CUDA_NVCC_DEPEND_REGENERATE = ${CUDA_NVCC_DEPEND_REGENERATE}")
+ # No incoming dependencies, so we need to generate them. Make the
+ # output depend on the dependency file itself, which should cause the
+ # rule to re-run.
+ if(CUDA_NVCC_DEPEND_REGENERATE)
+ set(CUDA_NVCC_DEPEND ${dependency_file})
+ #message("Generating an empty dependency_file: ${dependency_file}")
+ file(WRITE ${dependency_file} "#FindCUDA.cmake generated file. Do not edit.\n")
+ endif()
+
+endmacro()
+
+###############################################################################
+###############################################################################
+# Setup variables' defaults
+###############################################################################
+###############################################################################
+
+# Allow the user to specify if the device code is supposed to be 32 or 64 bit.
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(CUDA_64_BIT_DEVICE_CODE_DEFAULT ON)
+else()
+ set(CUDA_64_BIT_DEVICE_CODE_DEFAULT OFF)
+endif()
+option(CUDA_64_BIT_DEVICE_CODE "Compile device code in 64 bit mode" ${CUDA_64_BIT_DEVICE_CODE_DEFAULT})
+
+# Attach the build rule to the source file in VS. This option
+option(CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE "Attach the build rule to the CUDA source file. Enable only when the CUDA source file is added to at most one target." ON)
+
+# Prints out extra information about the cuda file during compilation
+option(CUDA_BUILD_CUBIN "Generate and parse .cubin files in Device mode." OFF)
+
+# Set whether we are using emulation or device mode.
+option(CUDA_BUILD_EMULATION "Build in Emulation mode" OFF)
+
+# Where to put the generated output.
+set(CUDA_GENERATED_OUTPUT_DIR "" CACHE PATH "Directory to put all the output files. If blank it will default to the CMAKE_CURRENT_BINARY_DIR")
+
+# Parse HOST_COMPILATION mode.
+option(CUDA_HOST_COMPILATION_CPP "Generated file extension" ON)
+
+# Extra user settable flags
+cmake_initialize_per_config_variable(CUDA_NVCC_FLAGS "Semi-colon delimit multiple arguments.")
+
+if(DEFINED ENV{CUDAHOSTCXX})
+ set(CUDA_HOST_COMPILER "$ENV{CUDAHOSTCXX}" CACHE FILEPATH "Host side compiler used by NVCC")
+elseif(CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(_CUDA_MSVC_HOST_COMPILER "$(VCInstallDir)Tools/MSVC/$(VCToolsVersion)/bin/Host$(Platform)/$(PlatformTarget)")
+ if(MSVC_VERSION LESS 1910)
+ set(_CUDA_MSVC_HOST_COMPILER "$(VCInstallDir)bin")
+ endif()
+
+ set(CUDA_HOST_COMPILER "${_CUDA_MSVC_HOST_COMPILER}" CACHE FILEPATH "Host side compiler used by NVCC")
+
+else()
+ if(APPLE
+ AND "${CMAKE_C_COMPILER_ID}" MATCHES "Clang"
+ AND "${CMAKE_C_COMPILER}" MATCHES "/cc$")
+ # Using cc which is symlink to clang may let NVCC think it is GCC and issue
+ # unhandled -dumpspecs option to clang. Also in case neither
+ # CMAKE_C_COMPILER is defined (project does not use C language) nor
+ # CUDA_HOST_COMPILER is specified manually we should skip -ccbin and let
+ # nvcc use its own default C compiler.
+ # Only care about this on APPLE with clang to avoid
+ # following symlinks to things like ccache
+ if(DEFINED CMAKE_C_COMPILER AND NOT DEFINED CUDA_HOST_COMPILER)
+ get_filename_component(c_compiler_realpath "${CMAKE_C_COMPILER}" REALPATH)
+ # if the real path does not end up being clang then
+ # go back to using CMAKE_C_COMPILER
+ if(NOT "${c_compiler_realpath}" MATCHES "/clang$")
+ set(c_compiler_realpath "${CMAKE_C_COMPILER}")
+ endif()
+ else()
+ set(c_compiler_realpath "")
+ endif()
+ set(CUDA_HOST_COMPILER "${c_compiler_realpath}" CACHE FILEPATH "Host side compiler used by NVCC")
+ elseif(MSVC AND "${CMAKE_C_COMPILER}" MATCHES "clcache|sccache")
+ # NVCC does not think it will work if it is passed clcache.exe or sccache.exe
+ # as the host compiler, which means that builds with CC=cl.exe won't work.
+ # Best to just feed it whatever the actual cl.exe is as the host compiler.
+ set(CUDA_HOST_COMPILER "cl.exe" CACHE FILEPATH "Host side compiler used by NVCC")
+ else()
+ set(CUDA_HOST_COMPILER "${CMAKE_C_COMPILER}"
+ CACHE FILEPATH "Host side compiler used by NVCC")
+ endif()
+endif()
+
+# Propagate the host flags to the host compiler via -Xcompiler
+option(CUDA_PROPAGATE_HOST_FLAGS "Propagate C/CXX_FLAGS and friends to the host compiler via -Xcompile" ON)
+
+# Enable CUDA_SEPARABLE_COMPILATION
+option(CUDA_SEPARABLE_COMPILATION "Compile CUDA objects with separable compilation enabled. Requires CUDA 5.0+" OFF)
+
+# Specifies whether the commands used when compiling the .cu file will be printed out.
+option(CUDA_VERBOSE_BUILD "Print out the commands run while compiling the CUDA source file. With the Makefile generator this defaults to VERBOSE variable specified on the command line, but can be forced on with this option." OFF)
+
+mark_as_advanced(
+ CUDA_64_BIT_DEVICE_CODE
+ CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE
+ CUDA_GENERATED_OUTPUT_DIR
+ CUDA_HOST_COMPILATION_CPP
+ CUDA_NVCC_FLAGS
+ CUDA_PROPAGATE_HOST_FLAGS
+ CUDA_BUILD_CUBIN
+ CUDA_BUILD_EMULATION
+ CUDA_VERBOSE_BUILD
+ CUDA_SEPARABLE_COMPILATION
+ )
+
+# Single config generators like Makefiles or Ninja don't usually have
+# CMAKE_CONFIGURATION_TYPES defined (but note that it can be defined if set by
+# projects or developers). Even CMAKE_BUILD_TYPE might not be defined for
+# single config generators (and should not be defined for multi-config
+# generators). To ensure we get a complete superset of all possible
+# configurations, we combine CMAKE_CONFIGURATION_TYPES, CMAKE_BUILD_TYPE and
+# all of the standard configurations, then weed out duplicates with
+# list(REMOVE_DUPLICATES). Looping over the unique set then ensures we have
+# each configuration-specific set of nvcc flags defined and marked as advanced.
+set(CUDA_configuration_types ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE} Debug MinSizeRel Release RelWithDebInfo)
+list(REMOVE_DUPLICATES CUDA_configuration_types)
+
+###############################################################################
+###############################################################################
+# Locate CUDA, Set Build Type, etc.
+###############################################################################
+###############################################################################
+
+macro(cuda_unset_include_and_libraries)
+ unset(CUDA_TOOLKIT_INCLUDE CACHE)
+ unset(CUDA_CUDART_LIBRARY CACHE)
+ unset(CUDA_CUDA_LIBRARY CACHE)
+ # Make sure you run this before you unset CUDA_VERSION.
+ if(CUDA_VERSION VERSION_EQUAL "3.0")
+ # This only existed in the 3.0 version of the CUDA toolkit
+ unset(CUDA_CUDARTEMU_LIBRARY CACHE)
+ endif()
+ unset(CUDA_cudart_static_LIBRARY CACHE)
+ unset(CUDA_cudadevrt_LIBRARY CACHE)
+ unset(CUDA_cublas_LIBRARY CACHE)
+ unset(CUDA_cublas_device_LIBRARY CACHE)
+ unset(CUDA_cublasemu_LIBRARY CACHE)
+ unset(CUDA_cufft_LIBRARY CACHE)
+ unset(CUDA_cufftemu_LIBRARY CACHE)
+ unset(CUDA_cupti_LIBRARY CACHE)
+ unset(CUDA_curand_LIBRARY CACHE)
+ unset(CUDA_cusolver_LIBRARY CACHE)
+ unset(CUDA_cusparse_LIBRARY CACHE)
+ unset(CUDA_npp_LIBRARY CACHE)
+ unset(CUDA_nppc_LIBRARY CACHE)
+ unset(CUDA_nppi_LIBRARY CACHE)
+ unset(CUDA_npps_LIBRARY CACHE)
+ unset(CUDA_nvcuvenc_LIBRARY CACHE)
+ unset(CUDA_nvcuvid_LIBRARY CACHE)
+ unset(CUDA_nvToolsExt_LIBRARY CACHE)
+ unset(CUDA_OpenCL_LIBRARY CACHE)
+ unset(CUDA_GPU_DETECT_OUTPUT CACHE)
+endmacro()
+
+# Check to see if the CUDA_TOOLKIT_ROOT_DIR and CUDA_SDK_ROOT_DIR have changed,
+# if they have then clear the cache variables, so that will be detected again.
+if(NOT "${CUDA_TOOLKIT_ROOT_DIR}" STREQUAL "${CUDA_TOOLKIT_ROOT_DIR_INTERNAL}")
+ unset(CUDA_TOOLKIT_TARGET_DIR CACHE)
+ unset(CUDA_NVCC_EXECUTABLE CACHE)
+ cuda_unset_include_and_libraries()
+ unset(CUDA_VERSION CACHE)
+endif()
+
+if(NOT "${CUDA_TOOLKIT_TARGET_DIR}" STREQUAL "${CUDA_TOOLKIT_TARGET_DIR_INTERNAL}")
+ cuda_unset_include_and_libraries()
+endif()
+
+#
+# End of unset()
+#
+
+#
+# Start looking for things
+#
+
+# Search for the cuda distribution.
+if(NOT CUDA_TOOLKIT_ROOT_DIR AND NOT CMAKE_CROSSCOMPILING)
+ # Search in the CUDA_BIN_PATH first.
+ find_program(CUDA_TOOLKIT_ROOT_DIR_NVCC
+ NAMES nvcc nvcc.exe
+ PATHS
+ ENV CUDA_TOOLKIT_ROOT
+ ENV CUDA_PATH
+ ENV CUDA_BIN_PATH
+ PATH_SUFFIXES bin bin64
+ DOC "Toolkit location."
+ NO_DEFAULT_PATH
+ )
+
+ # Now search default paths
+ find_program(CUDA_TOOLKIT_ROOT_DIR_NVCC
+ NAMES nvcc nvcc.exe
+ PATHS /opt/cuda/bin
+ PATH_SUFFIXES cuda/bin
+ DOC "Toolkit location."
+ )
+
+ if (CUDA_TOOLKIT_ROOT_DIR_NVCC)
+ # Given that NVCC can be provided by multiple different sources (NVIDIA HPC SDK, CUDA Toolkit, distro)
+ # each of which has a different layout, we need to extract the CUDA toolkit root from the compiler
+ # itself, allowing us to support numerous different scattered toolkit layouts
+ execute_process(COMMAND ${CUDA_TOOLKIT_ROOT_DIR_NVCC} "-v" "__cmake_determine_cuda"
+ OUTPUT_VARIABLE _CUDA_NVCC_OUT ERROR_VARIABLE _CUDA_NVCC_OUT)
+ if(_CUDA_NVCC_OUT MATCHES "TOP=([^\r\n]*)")
+ get_filename_component(CUDA_TOOLKIT_ROOT_DIR "${CMAKE_MATCH_1}" ABSOLUTE CACHE)
+ else()
+ get_filename_component(CUDA_TOOLKIT_ROOT_DIR "${CUDA_TOOLKIT_ROOT_DIR_NVCC}" DIRECTORY)
+ get_filename_component(CUDA_TOOLKIT_ROOT_DIR "${CUDA_TOOLKIT_ROOT_DIR}" DIRECTORY CACHE)
+ endif()
+ unset(_CUDA_NVCC_OUT)
+
+ string(REGEX REPLACE "[/\\\\]?bin[64]*[/\\\\]?$" "" CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT_DIR})
+ # We need to force this back into the cache.
+ set(CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT_DIR} CACHE PATH "Toolkit location." FORCE)
+ set(CUDA_TOOLKIT_TARGET_DIR ${CUDA_TOOLKIT_ROOT_DIR})
+ endif()
+ unset(CUDA_TOOLKIT_ROOT_DIR_NVCC CACHE)
+
+ if (NOT EXISTS ${CUDA_TOOLKIT_ROOT_DIR})
+ if(CUDA_FIND_REQUIRED)
+ message(FATAL_ERROR "Specify CUDA_TOOLKIT_ROOT_DIR")
+ elseif(NOT CUDA_FIND_QUIETLY)
+ message("CUDA_TOOLKIT_ROOT_DIR not found or specified")
+ endif()
+ endif ()
+endif ()
+
+if(CMAKE_CROSSCOMPILING)
+ SET (CUDA_TOOLKIT_ROOT $ENV{CUDA_TOOLKIT_ROOT})
+ if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7-a")
+ # Support for NVPACK
+ set (CUDA_TOOLKIT_TARGET_NAME "armv7-linux-androideabi")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
+ # Support for arm cross compilation
+ set(CUDA_TOOLKIT_TARGET_NAME "armv7-linux-gnueabihf")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
+ # Support for aarch64 cross compilation
+ if (ANDROID_ARCH_NAME STREQUAL "arm64")
+ set(CUDA_TOOLKIT_TARGET_NAME "aarch64-linux-androideabi")
+ elseif (CMAKE_SYSTEM_NAME STREQUAL "QNX")
+ set(CUDA_TOOLKIT_TARGET_NAME "aarch64-qnx")
+ else()
+ set(CUDA_TOOLKIT_TARGET_NAME "aarch64-linux")
+ endif (ANDROID_ARCH_NAME STREQUAL "arm64")
+ endif()
+
+ if (EXISTS "${CUDA_TOOLKIT_ROOT}/targets/${CUDA_TOOLKIT_TARGET_NAME}")
+ set(CUDA_TOOLKIT_TARGET_DIR "${CUDA_TOOLKIT_ROOT}/targets/${CUDA_TOOLKIT_TARGET_NAME}" CACHE PATH "CUDA Toolkit target location.")
+ SET (CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT})
+ mark_as_advanced(CUDA_TOOLKIT_TARGET_DIR)
+ endif()
+
+ # add known CUDA targetr root path to the set of directories we search for programs, libraries and headers
+ set( CMAKE_FIND_ROOT_PATH "${CUDA_TOOLKIT_TARGET_DIR};${CMAKE_FIND_ROOT_PATH}")
+ macro( cuda_find_host_program )
+ if (COMMAND find_host_program)
+ find_host_program( ${ARGN} )
+ else()
+ find_program( ${ARGN} )
+ endif()
+ endmacro()
+else()
+ # for non-cross-compile, find_host_program == find_program and CUDA_TOOLKIT_TARGET_DIR == CUDA_TOOLKIT_ROOT_DIR
+ macro( cuda_find_host_program )
+ find_program( ${ARGN} )
+ endmacro()
+ SET (CUDA_TOOLKIT_TARGET_DIR ${CUDA_TOOLKIT_ROOT_DIR})
+endif()
+
+
+# CUDA_NVCC_EXECUTABLE
+if(DEFINED ENV{CUDA_NVCC_EXECUTABLE})
+ set(CUDA_NVCC_EXECUTABLE "$ENV{CUDA_NVCC_EXECUTABLE}" CACHE FILEPATH "The CUDA compiler")
+else()
+ cuda_find_host_program(CUDA_NVCC_EXECUTABLE
+ NAMES nvcc
+ PATHS "${CUDA_TOOLKIT_ROOT_DIR}"
+ ENV CUDA_PATH
+ ENV CUDA_BIN_PATH
+ PATH_SUFFIXES bin bin64
+ NO_DEFAULT_PATH
+ )
+ # Search default search paths, after we search our own set of paths.
+ cuda_find_host_program(CUDA_NVCC_EXECUTABLE nvcc)
+endif()
+mark_as_advanced(CUDA_NVCC_EXECUTABLE)
+
+if(CUDA_NVCC_EXECUTABLE AND NOT CUDA_VERSION)
+ # Compute the version.
+ execute_process (COMMAND ${CUDA_NVCC_EXECUTABLE} "--version" OUTPUT_VARIABLE NVCC_OUT)
+ string(REGEX REPLACE ".*release ([0-9]+)\\.([0-9]+).*" "\\1" CUDA_VERSION_MAJOR ${NVCC_OUT})
+ string(REGEX REPLACE ".*release ([0-9]+)\\.([0-9]+).*" "\\2" CUDA_VERSION_MINOR ${NVCC_OUT})
+ set(CUDA_VERSION "${CUDA_VERSION_MAJOR}.${CUDA_VERSION_MINOR}" CACHE STRING "Version of CUDA as computed from nvcc.")
+ mark_as_advanced(CUDA_VERSION)
+else()
+ # Need to set these based off of the cached value
+ string(REGEX REPLACE "([0-9]+)\\.([0-9]+).*" "\\1" CUDA_VERSION_MAJOR "${CUDA_VERSION}")
+ string(REGEX REPLACE "([0-9]+)\\.([0-9]+).*" "\\2" CUDA_VERSION_MINOR "${CUDA_VERSION}")
+endif()
+
+
+# Always set this convenience variable
+set(CUDA_VERSION_STRING "${CUDA_VERSION}")
+
+# CUDA_TOOLKIT_INCLUDE
+find_path(CUDA_TOOLKIT_INCLUDE
+ device_functions.h # Header included in toolkit
+ PATHS ${CUDA_TOOLKIT_TARGET_DIR}
+ ENV CUDA_PATH
+ ENV CUDA_INC_PATH
+ PATH_SUFFIXES include
+ NO_DEFAULT_PATH
+ )
+# Search default search paths, after we search our own set of paths.
+find_path(CUDA_TOOLKIT_INCLUDE device_functions.h)
+mark_as_advanced(CUDA_TOOLKIT_INCLUDE)
+
+if (CUDA_VERSION VERSION_GREATER "7.0" OR EXISTS "${CUDA_TOOLKIT_INCLUDE}/cuda_fp16.h")
+ set(CUDA_HAS_FP16 TRUE)
+else()
+ set(CUDA_HAS_FP16 FALSE)
+endif()
+
+# Set the user list of include dir to nothing to initialize it.
+set (CUDA_NVCC_INCLUDE_DIRS_USER "")
+set (CUDA_INCLUDE_DIRS ${CUDA_TOOLKIT_INCLUDE})
+
+macro(cuda_find_library_local_first_with_path_ext _var _names _doc _path_ext )
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ # CUDA 3.2+ on Windows moved the library directories, so we need the new
+ # and old paths.
+ set(_cuda_64bit_lib_dir "${_path_ext}lib/x64" "${_path_ext}lib64" "${_path_ext}libx64" )
+ endif()
+ # CUDA 3.2+ on Windows moved the library directories, so we need to new
+ # (lib/Win32) and the old path (lib).
+ find_library(${_var}
+ NAMES ${_names}
+ PATHS "${CUDA_TOOLKIT_TARGET_DIR}"
+ ENV CUDA_PATH
+ ENV CUDA_LIB_PATH
+ PATH_SUFFIXES ${_cuda_64bit_lib_dir} "${_path_ext}lib/Win32" "${_path_ext}lib" "${_path_ext}libWin32"
+ DOC ${_doc}
+ NO_DEFAULT_PATH
+ )
+ if (NOT CMAKE_CROSSCOMPILING)
+ # Search default search paths, after we search our own set of paths.
+ find_library(${_var}
+ NAMES ${_names}
+ PATHS "/usr/lib/nvidia-current"
+ DOC ${_doc}
+ )
+ endif()
+endmacro()
+
+macro(cuda_find_library_local_first _var _names _doc)
+ cuda_find_library_local_first_with_path_ext( "${_var}" "${_names}" "${_doc}" "" )
+endmacro()
+
+macro(find_library_local_first _var _names _doc )
+ cuda_find_library_local_first( "${_var}" "${_names}" "${_doc}" "" )
+endmacro()
+
+
+# CUDA_LIBRARIES
+cuda_find_library_local_first(CUDA_CUDART_LIBRARY cudart "\"cudart\" library")
+if(CUDA_VERSION VERSION_EQUAL "3.0")
+ # The cudartemu library only existed for the 3.0 version of CUDA.
+ cuda_find_library_local_first(CUDA_CUDARTEMU_LIBRARY cudartemu "\"cudartemu\" library")
+ mark_as_advanced(
+ CUDA_CUDARTEMU_LIBRARY
+ )
+endif()
+
+if(NOT CUDA_VERSION VERSION_LESS "5.5")
+ cuda_find_library_local_first(CUDA_cudart_static_LIBRARY cudart_static "static CUDA runtime library")
+ mark_as_advanced(CUDA_cudart_static_LIBRARY)
+endif()
+
+
+if(CUDA_cudart_static_LIBRARY)
+ # If static cudart available, use it by default, but provide a user-visible option to disable it.
+ option(CUDA_USE_STATIC_CUDA_RUNTIME "Use the static version of the CUDA runtime library if available" ON)
+else()
+ # If not available, silently disable the option.
+ set(CUDA_USE_STATIC_CUDA_RUNTIME OFF CACHE INTERNAL "")
+endif()
+
+if(CUDA_USE_STATIC_CUDA_RUNTIME)
+ set(CUDA_CUDART_LIBRARY_VAR CUDA_cudart_static_LIBRARY)
+else()
+ set(CUDA_CUDART_LIBRARY_VAR CUDA_CUDART_LIBRARY)
+endif()
+
+if(NOT CUDA_VERSION VERSION_LESS "5.0")
+ cuda_find_library_local_first(CUDA_cudadevrt_LIBRARY cudadevrt "\"cudadevrt\" library")
+ mark_as_advanced(CUDA_cudadevrt_LIBRARY)
+endif()
+
+if(CUDA_USE_STATIC_CUDA_RUNTIME)
+ if(UNIX)
+ # Check for the dependent libraries.
+
+ # Many of the FindXYZ CMake comes with makes use of try_compile with int main(){return 0;}
+ # as the source file. Unfortunately this causes a warning with -Wstrict-prototypes and
+ # -Werror causes the try_compile to fail. We will just temporarily disable other flags
+ # when doing the find_package command here.
+ set(_cuda_cmake_c_flags ${CMAKE_C_FLAGS})
+ set(CMAKE_C_FLAGS "-fPIC")
+ find_package(Threads REQUIRED)
+ set(CMAKE_C_FLAGS ${_cuda_cmake_c_flags})
+
+ if(NOT APPLE AND NOT (CMAKE_SYSTEM_NAME STREQUAL "QNX"))
+ #On Linux, you must link against librt when using the static cuda runtime.
+ find_library(CUDA_rt_LIBRARY rt)
+ if (NOT CUDA_rt_LIBRARY)
+ message(WARNING "Expecting to find librt for libcudart_static, but didn't find it.")
+ endif()
+ endif()
+ endif()
+endif()
+
+# CUPTI library showed up in cuda toolkit 4.0
+if(NOT CUDA_VERSION VERSION_LESS "4.0")
+ cuda_find_library_local_first_with_path_ext(CUDA_cupti_LIBRARY cupti "\"cupti\" library" "extras/CUPTI/")
+ mark_as_advanced(CUDA_cupti_LIBRARY)
+endif()
+
+# Set the CUDA_LIBRARIES variable. This is the set of stuff to link against if you are
+# using the CUDA runtime. For the dynamic version of the runtime, most of the
+# dependencies are brough in, but for the static version there are additional libraries
+# and linker commands needed.
+# Initialize to empty
+set(CUDA_LIBRARIES)
+
+# If we are using emulation mode and we found the cudartemu library then use
+# that one instead of cudart.
+if(CUDA_BUILD_EMULATION AND CUDA_CUDARTEMU_LIBRARY)
+ list(APPEND CUDA_LIBRARIES ${CUDA_CUDARTEMU_LIBRARY})
+elseif(CUDA_USE_STATIC_CUDA_RUNTIME AND CUDA_cudart_static_LIBRARY)
+ list(APPEND CUDA_LIBRARIES ${CUDA_cudart_static_LIBRARY})
+ if (TARGET Threads::Threads)
+ list(APPEND CUDA_LIBRARIES Threads::Threads)
+ endif()
+ list(APPEND CUDA_LIBRARIES ${CMAKE_DL_LIBS})
+ if (CUDA_rt_LIBRARY)
+ list(APPEND CUDA_LIBRARIES ${CUDA_rt_LIBRARY})
+ endif()
+ if(APPLE)
+ # We need to add the default path to the driver (libcuda.dylib) as an rpath, so that
+ # the static cuda runtime can find it at runtime.
+ list(APPEND CUDA_LIBRARIES -Wl,-rpath,/usr/local/cuda/lib)
+ endif()
+else()
+ list(APPEND CUDA_LIBRARIES ${CUDA_CUDART_LIBRARY})
+endif()
+
+# 1.1 toolkit on linux doesn't appear to have a separate library on
+# some platforms.
+cuda_find_library_local_first(CUDA_CUDA_LIBRARY cuda "\"cuda\" library (older versions only).")
+
+mark_as_advanced(
+ CUDA_CUDA_LIBRARY
+ CUDA_CUDART_LIBRARY
+ )
+
+#######################
+# Look for some of the toolkit helper libraries
+macro(FIND_CUDA_HELPER_LIBS _name)
+ cuda_find_library_local_first(CUDA_${_name}_LIBRARY ${_name} "\"${_name}\" library")
+ mark_as_advanced(CUDA_${_name}_LIBRARY)
+endmacro()
+
+#######################
+# Disable emulation for v3.1 onward
+if(CUDA_VERSION VERSION_GREATER "3.0")
+ if(CUDA_BUILD_EMULATION)
+ message(FATAL_ERROR "CUDA_BUILD_EMULATION is not supported in version 3.1 and onwards. You must disable it to proceed. You have version ${CUDA_VERSION}.")
+ endif()
+endif()
+
+# Search for additional CUDA toolkit libraries.
+if(CUDA_VERSION VERSION_LESS "3.1")
+ # Emulation libraries aren't available in version 3.1 onward.
+ find_cuda_helper_libs(cufftemu)
+ find_cuda_helper_libs(cublasemu)
+endif()
+find_cuda_helper_libs(cufft)
+find_cuda_helper_libs(cublas)
+if(NOT CUDA_VERSION VERSION_LESS "3.2")
+ # cusparse showed up in version 3.2
+ find_cuda_helper_libs(cusparse)
+ find_cuda_helper_libs(curand)
+ if (WIN32)
+ find_cuda_helper_libs(nvcuvenc)
+ find_cuda_helper_libs(nvcuvid)
+ endif()
+endif()
+if(CUDA_VERSION VERSION_GREATER "5.0" AND CUDA_VERSION VERSION_LESS "9.2")
+ # In CUDA 9.2 cublas_device was deprecated
+ find_cuda_helper_libs(cublas_device)
+endif()
+
+if(NOT CUDA_VERSION VERSION_LESS "5.0")
+ find_cuda_helper_libs(nvToolsExt)
+ find_cuda_helper_libs(OpenCL)
+endif()
+
+if(NOT CUDA_VERSION VERSION_LESS "9.0")
+ # In CUDA 9.0 NPP was nppi was removed
+ find_cuda_helper_libs(nppc)
+ find_cuda_helper_libs(nppial)
+ find_cuda_helper_libs(nppicc)
+ if(CUDA_VERSION VERSION_LESS "11.0")
+ find_cuda_helper_libs(nppicom)
+ endif()
+ find_cuda_helper_libs(nppidei)
+ find_cuda_helper_libs(nppif)
+ find_cuda_helper_libs(nppig)
+ find_cuda_helper_libs(nppim)
+ find_cuda_helper_libs(nppist)
+ find_cuda_helper_libs(nppisu)
+ find_cuda_helper_libs(nppitc)
+ find_cuda_helper_libs(npps)
+ set(CUDA_npp_LIBRARY "${CUDA_nppc_LIBRARY};${CUDA_nppial_LIBRARY};${CUDA_nppicc_LIBRARY};${CUDA_nppicom_LIBRARY};${CUDA_nppidei_LIBRARY};${CUDA_nppif_LIBRARY};${CUDA_nppig_LIBRARY};${CUDA_nppim_LIBRARY};${CUDA_nppist_LIBRARY};${CUDA_nppisu_LIBRARY};${CUDA_nppitc_LIBRARY};${CUDA_npps_LIBRARY}")
+elseif(CUDA_VERSION VERSION_GREATER "5.0")
+ # In CUDA 5.5 NPP was split into 3 separate libraries.
+ find_cuda_helper_libs(nppc)
+ find_cuda_helper_libs(nppi)
+ find_cuda_helper_libs(npps)
+ set(CUDA_npp_LIBRARY "${CUDA_nppc_LIBRARY};${CUDA_nppi_LIBRARY};${CUDA_npps_LIBRARY}")
+elseif(NOT CUDA_VERSION VERSION_LESS "4.0")
+ find_cuda_helper_libs(npp)
+endif()
+if(NOT CUDA_VERSION VERSION_LESS "7.0")
+ # cusolver showed up in version 7.0
+ find_cuda_helper_libs(cusolver)
+endif()
+
+if (CUDA_BUILD_EMULATION)
+ set(CUDA_CUFFT_LIBRARIES ${CUDA_cufftemu_LIBRARY})
+ set(CUDA_CUBLAS_LIBRARIES ${CUDA_cublasemu_LIBRARY})
+else()
+ set(CUDA_CUFFT_LIBRARIES ${CUDA_cufft_LIBRARY})
+ set(CUDA_CUBLAS_LIBRARIES ${CUDA_cublas_LIBRARY} ${CUDA_cublas_device_LIBRARY})
+endif()
+
+########################
+# Look for the SDK stuff. As of CUDA 3.0 NVSDKCUDA_ROOT has been replaced with
+# NVSDKCOMPUTE_ROOT with the old CUDA C contents moved into the C subdirectory
+find_path(CUDA_SDK_ROOT_DIR common/inc/cutil.h
+ HINTS
+ "$ENV{NVSDKCOMPUTE_ROOT}/C"
+ ENV NVSDKCUDA_ROOT
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\NVIDIA Corporation\\Installed Products\\NVIDIA SDK 10\\Compute;InstallDir]"
+ PATHS
+ "/Developer/GPU\ Computing/C"
+ )
+
+# Keep the CUDA_SDK_ROOT_DIR first in order to be able to override the
+# environment variables.
+set(CUDA_SDK_SEARCH_PATH
+ "${CUDA_SDK_ROOT_DIR}"
+ "${CUDA_TOOLKIT_ROOT_DIR}/local/NVSDK0.2"
+ "${CUDA_TOOLKIT_ROOT_DIR}/NVSDK0.2"
+ "${CUDA_TOOLKIT_ROOT_DIR}/NV_CUDA_SDK"
+ "$ENV{HOME}/NVIDIA_CUDA_SDK"
+ "$ENV{HOME}/NVIDIA_CUDA_SDK_MACOSX"
+ "/Developer/CUDA"
+ )
+
+# Example of how to find an include file from the CUDA_SDK_ROOT_DIR
+
+# find_path(CUDA_CUT_INCLUDE_DIR
+# cutil.h
+# PATHS ${CUDA_SDK_SEARCH_PATH}
+# PATH_SUFFIXES "common/inc"
+# DOC "Location of cutil.h"
+# NO_DEFAULT_PATH
+# )
+# # Now search system paths
+# find_path(CUDA_CUT_INCLUDE_DIR cutil.h DOC "Location of cutil.h")
+
+# mark_as_advanced(CUDA_CUT_INCLUDE_DIR)
+
+
+# Example of how to find a library in the CUDA_SDK_ROOT_DIR
+
+# # cutil library is called cutil64 for 64 bit builds on windows. We don't want
+# # to get these confused, so we are setting the name based on the word size of
+# # the build.
+
+# if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+# set(cuda_cutil_name cutil64)
+# else()
+# set(cuda_cutil_name cutil32)
+# endif()
+
+# find_library(CUDA_CUT_LIBRARY
+# NAMES cutil ${cuda_cutil_name}
+# PATHS ${CUDA_SDK_SEARCH_PATH}
+# # The new version of the sdk shows up in common/lib, but the old one is in lib
+# PATH_SUFFIXES "common/lib" "lib"
+# DOC "Location of cutil library"
+# NO_DEFAULT_PATH
+# )
+# # Now search system paths
+# find_library(CUDA_CUT_LIBRARY NAMES cutil ${cuda_cutil_name} DOC "Location of cutil library")
+# mark_as_advanced(CUDA_CUT_LIBRARY)
+# set(CUDA_CUT_LIBRARIES ${CUDA_CUT_LIBRARY})
+
+
+
+#############################
+# Check for required components
+set(CUDA_FOUND TRUE)
+
+set(CUDA_TOOLKIT_ROOT_DIR_INTERNAL "${CUDA_TOOLKIT_ROOT_DIR}" CACHE INTERNAL
+ "This is the value of the last time CUDA_TOOLKIT_ROOT_DIR was set successfully." FORCE)
+set(CUDA_TOOLKIT_TARGET_DIR_INTERNAL "${CUDA_TOOLKIT_TARGET_DIR}" CACHE INTERNAL
+ "This is the value of the last time CUDA_TOOLKIT_TARGET_DIR was set successfully." FORCE)
+set(CUDA_SDK_ROOT_DIR_INTERNAL "${CUDA_SDK_ROOT_DIR}" CACHE INTERNAL
+ "This is the value of the last time CUDA_SDK_ROOT_DIR was set successfully." FORCE)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+find_package_handle_standard_args(CUDA
+ REQUIRED_VARS
+ CUDA_TOOLKIT_ROOT_DIR
+ CUDA_NVCC_EXECUTABLE
+ CUDA_INCLUDE_DIRS
+ ${CUDA_CUDART_LIBRARY_VAR}
+ VERSION_VAR
+ CUDA_VERSION
+ )
+
+
+
+###############################################################################
+###############################################################################
+# Macros
+###############################################################################
+###############################################################################
+
+###############################################################################
+# Add include directories to pass to the nvcc command.
+macro(CUDA_INCLUDE_DIRECTORIES)
+ foreach(dir ${ARGN})
+ list(APPEND CUDA_NVCC_INCLUDE_DIRS_USER ${dir})
+ endforeach()
+endmacro()
+
+
+##############################################################################
+cuda_find_helper_file(parse_cubin cmake)
+cuda_find_helper_file(make2cmake cmake)
+cuda_find_helper_file(run_nvcc cmake)
+include("${CMAKE_CURRENT_LIST_DIR}/FindCUDA/select_compute_arch.cmake")
+
+##############################################################################
+# Separate the OPTIONS out from the sources
+#
+macro(CUDA_GET_SOURCES_AND_OPTIONS _sources _cmake_options _options)
+ set( ${_sources} )
+ set( ${_cmake_options} )
+ set( ${_options} )
+ set( _found_options FALSE )
+ foreach(arg ${ARGN})
+ if("x${arg}" STREQUAL "xOPTIONS")
+ set( _found_options TRUE )
+ elseif(
+ "x${arg}" STREQUAL "xWIN32" OR
+ "x${arg}" STREQUAL "xMACOSX_BUNDLE" OR
+ "x${arg}" STREQUAL "xEXCLUDE_FROM_ALL" OR
+ "x${arg}" STREQUAL "xSTATIC" OR
+ "x${arg}" STREQUAL "xSHARED" OR
+ "x${arg}" STREQUAL "xMODULE"
+ )
+ list(APPEND ${_cmake_options} ${arg})
+ else()
+ if ( _found_options )
+ list(APPEND ${_options} ${arg})
+ else()
+ # Assume this is a file
+ list(APPEND ${_sources} ${arg})
+ endif()
+ endif()
+ endforeach()
+endmacro()
+
+##############################################################################
+# Parse the OPTIONS from ARGN and set the variables prefixed by _option_prefix
+#
+macro(CUDA_PARSE_NVCC_OPTIONS _option_prefix)
+ set( _found_config )
+ foreach(arg ${ARGN})
+ # Determine if we are dealing with a perconfiguration flag
+ foreach(config ${CUDA_configuration_types})
+ string(TOUPPER ${config} config_upper)
+ if (arg STREQUAL "${config_upper}")
+ set( _found_config _${arg})
+ # Set arg to nothing to keep it from being processed further
+ set( arg )
+ endif()
+ endforeach()
+
+ if ( arg )
+ list(APPEND ${_option_prefix}${_found_config} "${arg}")
+ endif()
+ endforeach()
+endmacro()
+
+##############################################################################
+# Helper to add the include directory for CUDA only once
+function(CUDA_ADD_CUDA_INCLUDE_ONCE)
+ get_directory_property(_include_directories INCLUDE_DIRECTORIES)
+ set(_add TRUE)
+ if(_include_directories)
+ foreach(dir ${_include_directories})
+ if("${dir}" STREQUAL "${CUDA_INCLUDE_DIRS}")
+ set(_add FALSE)
+ endif()
+ endforeach()
+ endif()
+ if(_add)
+ include_directories(${CUDA_INCLUDE_DIRS})
+ endif()
+endfunction()
+
+function(CUDA_BUILD_SHARED_LIBRARY shared_flag)
+ set(cmake_args ${ARGN})
+ # If SHARED, MODULE, or STATIC aren't already in the list of arguments, then
+ # add SHARED or STATIC based on the value of BUILD_SHARED_LIBS.
+ list(FIND cmake_args SHARED _cuda_found_SHARED)
+ list(FIND cmake_args MODULE _cuda_found_MODULE)
+ list(FIND cmake_args STATIC _cuda_found_STATIC)
+ if( _cuda_found_SHARED GREATER -1 OR
+ _cuda_found_MODULE GREATER -1 OR
+ _cuda_found_STATIC GREATER -1)
+ set(_cuda_build_shared_libs)
+ else()
+ if (BUILD_SHARED_LIBS)
+ set(_cuda_build_shared_libs SHARED)
+ else()
+ set(_cuda_build_shared_libs STATIC)
+ endif()
+ endif()
+ set(${shared_flag} ${_cuda_build_shared_libs} PARENT_SCOPE)
+endfunction()
+
+##############################################################################
+# Helper to avoid clashes of files with the same basename but different paths.
+# This doesn't attempt to do exactly what CMake internals do, which is to only
+# add this path when there is a conflict, since by the time a second collision
+# in names is detected it's already too late to fix the first one. For
+# consistency sake the relative path will be added to all files.
+function(CUDA_COMPUTE_BUILD_PATH path build_path)
+ #message("CUDA_COMPUTE_BUILD_PATH([${path}] ${build_path})")
+ # Only deal with CMake style paths from here on out
+ file(TO_CMAKE_PATH "${path}" bpath)
+ if (IS_ABSOLUTE "${bpath}")
+ # Absolute paths are generally unnessary, especially if something like
+ # file(GLOB_RECURSE) is used to pick up the files.
+
+ string(FIND "${bpath}" "${CMAKE_CURRENT_BINARY_DIR}" _binary_dir_pos)
+ if (_binary_dir_pos EQUAL 0)
+ file(RELATIVE_PATH bpath "${CMAKE_CURRENT_BINARY_DIR}" "${bpath}")
+ else()
+ file(RELATIVE_PATH bpath "${CMAKE_CURRENT_SOURCE_DIR}" "${bpath}")
+ endif()
+ endif()
+
+ # This recipe is from cmLocalGenerator::CreateSafeUniqueObjectFileName in the
+ # CMake source.
+
+ # Remove leading /
+ string(REGEX REPLACE "^[/]+" "" bpath "${bpath}")
+ # Avoid absolute paths by removing ':'
+ string(REPLACE ":" "_" bpath "${bpath}")
+ # Avoid relative paths that go up the tree
+ string(REPLACE "../" "__/" bpath "${bpath}")
+ # Avoid spaces
+ string(REPLACE " " "_" bpath "${bpath}")
+
+ # Strip off the filename. I wait until here to do it, since removin the
+ # basename can make a path that looked like path/../basename turn into
+ # path/.. (notice the trailing slash).
+ get_filename_component(bpath "${bpath}" PATH)
+
+ set(${build_path} "${bpath}" PARENT_SCOPE)
+ #message("${build_path} = ${bpath}")
+endfunction()
+
+##############################################################################
+# This helper macro populates the following variables and setups up custom
+# commands and targets to invoke the nvcc compiler to generate C or PTX source
+# dependent upon the format parameter. The compiler is invoked once with -M
+# to generate a dependency file and a second time with -cuda or -ptx to generate
+# a .cpp or .ptx file.
+# INPUT:
+# cuda_target - Target name
+# format - PTX, CUBIN, FATBIN or OBJ
+# FILE1 .. FILEN - The remaining arguments are the sources to be wrapped.
+# OPTIONS - Extra options to NVCC
+# OUTPUT:
+# generated_files - List of generated files
+##############################################################################
+##############################################################################
+
+macro(CUDA_WRAP_SRCS cuda_target format generated_files)
+
+ # Put optional arguments in list.
+ set(_argn_list "${ARGN}")
+ # If one of the given optional arguments is "PHONY", make a note of it, then
+ # remove it from the list.
+ list(FIND _argn_list "PHONY" _phony_idx)
+ if("${_phony_idx}" GREATER "-1")
+ set(_target_is_phony true)
+ list(REMOVE_AT _argn_list ${_phony_idx})
+ else()
+ set(_target_is_phony false)
+ endif()
+
+ # If CMake doesn't support separable compilation, complain
+ if(CUDA_SEPARABLE_COMPILATION AND CMAKE_VERSION VERSION_LESS "2.8.10.1")
+ message(SEND_ERROR "CUDA_SEPARABLE_COMPILATION isn't supported for CMake versions less than 2.8.10.1")
+ endif()
+
+ # Set up all the command line flags here, so that they can be overridden on a per target basis.
+
+ set(nvcc_flags "")
+
+ # Emulation if the card isn't present.
+ if (CUDA_BUILD_EMULATION)
+ # Emulation.
+ set(nvcc_flags ${nvcc_flags} --device-emulation -D_DEVICEEMU -g)
+ else()
+ # Device mode. No flags necessary.
+ endif()
+
+ if(CUDA_HOST_COMPILATION_CPP)
+ set(CUDA_C_OR_CXX CXX)
+ else()
+ if(CUDA_VERSION VERSION_LESS "3.0")
+ set(nvcc_flags ${nvcc_flags} --host-compilation C)
+ else()
+ message(WARNING "--host-compilation flag is deprecated in CUDA version >= 3.0. Removing --host-compilation C flag" )
+ endif()
+ set(CUDA_C_OR_CXX C)
+ endif()
+
+ set(generated_extension ${CMAKE_${CUDA_C_OR_CXX}_OUTPUT_EXTENSION})
+
+ if(CUDA_64_BIT_DEVICE_CODE)
+ set(nvcc_flags ${nvcc_flags} -m64)
+ else()
+ set(nvcc_flags ${nvcc_flags} -m32)
+ endif()
+
+ if(CUDA_TARGET_CPU_ARCH)
+ set(nvcc_flags ${nvcc_flags} "--target-cpu-architecture=${CUDA_TARGET_CPU_ARCH}")
+ endif()
+
+ # This needs to be passed in at this stage, because VS needs to fill out the
+ # various macros from within VS. Note that CCBIN is only used if
+ # -ccbin or --compiler-bindir isn't used and CUDA_HOST_COMPILER matches
+ # _CUDA_MSVC_HOST_COMPILER
+ if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(ccbin_flags -D "\"CCBIN:PATH=${_CUDA_MSVC_HOST_COMPILER}\"" )
+ else()
+ set(ccbin_flags)
+ endif()
+
+ # Figure out which configure we will use and pass that in as an argument to
+ # the script. We need to defer the decision until compilation time, because
+ # for VS projects we won't know if we are making a debug or release build
+ # until build time.
+ if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ set( CUDA_build_configuration "$(ConfigurationName)" )
+ else()
+ set( CUDA_build_configuration "${CMAKE_BUILD_TYPE}")
+ endif()
+
+ # Initialize our list of includes with the user ones followed by the CUDA system ones.
+ set(CUDA_NVCC_INCLUDE_DIRS ${CUDA_NVCC_INCLUDE_DIRS_USER} "${CUDA_INCLUDE_DIRS}")
+ if(_target_is_phony)
+ # If the passed in target name isn't a real target (i.e., this is from a call to one of the
+ # cuda_compile_* functions), need to query directory properties to get include directories
+ # and compile definitions.
+ get_directory_property(_dir_include_dirs INCLUDE_DIRECTORIES)
+ get_directory_property(_dir_compile_defs COMPILE_DEFINITIONS)
+
+ list(APPEND CUDA_NVCC_INCLUDE_DIRS "${_dir_include_dirs}")
+ set(CUDA_NVCC_COMPILE_DEFINITIONS "${_dir_compile_defs}")
+ else()
+ # Append the include directories for this target via generator expression, which is
+ # expanded by the FILE(GENERATE) call below. This generator expression captures all
+ # include dirs set by the user, whether via directory properties or target properties
+ list(APPEND CUDA_NVCC_INCLUDE_DIRS "$<TARGET_PROPERTY:${cuda_target},INCLUDE_DIRECTORIES>")
+
+ # Do the same thing with compile definitions
+ set(CUDA_NVCC_COMPILE_DEFINITIONS "$<TARGET_PROPERTY:${cuda_target},COMPILE_DEFINITIONS>")
+ endif()
+
+
+ # Reset these variables
+ set(CUDA_WRAP_OPTION_NVCC_FLAGS)
+ foreach(config ${CUDA_configuration_types})
+ string(TOUPPER ${config} config_upper)
+ set(CUDA_WRAP_OPTION_NVCC_FLAGS_${config_upper})
+ endforeach()
+
+ CUDA_GET_SOURCES_AND_OPTIONS(_cuda_wrap_sources _cuda_wrap_cmake_options _cuda_wrap_options ${_argn_list})
+ CUDA_PARSE_NVCC_OPTIONS(CUDA_WRAP_OPTION_NVCC_FLAGS ${_cuda_wrap_options})
+
+ # Figure out if we are building a shared library. BUILD_SHARED_LIBS is
+ # respected in CUDA_ADD_LIBRARY.
+ set(_cuda_build_shared_libs FALSE)
+ # SHARED, MODULE
+ list(FIND _cuda_wrap_cmake_options SHARED _cuda_found_SHARED)
+ list(FIND _cuda_wrap_cmake_options MODULE _cuda_found_MODULE)
+ if(_cuda_found_SHARED GREATER -1 OR _cuda_found_MODULE GREATER -1)
+ set(_cuda_build_shared_libs TRUE)
+ endif()
+ # STATIC
+ list(FIND _cuda_wrap_cmake_options STATIC _cuda_found_STATIC)
+ if(_cuda_found_STATIC GREATER -1)
+ set(_cuda_build_shared_libs FALSE)
+ endif()
+
+ # CUDA_HOST_FLAGS
+ if(_cuda_build_shared_libs)
+ # If we are setting up code for a shared library, then we need to add extra flags for
+ # compiling objects for shared libraries.
+ set(CUDA_HOST_SHARED_FLAGS ${CMAKE_SHARED_LIBRARY_${CUDA_C_OR_CXX}_FLAGS})
+ else()
+ set(CUDA_HOST_SHARED_FLAGS)
+ endif()
+ # Only add the CMAKE_{C,CXX}_FLAGS if we are propagating host flags. We
+ # always need to set the SHARED_FLAGS, though.
+ if(CUDA_PROPAGATE_HOST_FLAGS)
+ set(_cuda_host_flags "set(CMAKE_HOST_FLAGS ${CMAKE_${CUDA_C_OR_CXX}_FLAGS} ${CUDA_HOST_SHARED_FLAGS})")
+ else()
+ set(_cuda_host_flags "set(CMAKE_HOST_FLAGS ${CUDA_HOST_SHARED_FLAGS})")
+ endif()
+
+ set(_cuda_nvcc_flags_config "# Build specific configuration flags")
+ # Loop over all the configuration types to generate appropriate flags for run_nvcc.cmake
+ foreach(config ${CUDA_configuration_types})
+ string(TOUPPER ${config} config_upper)
+ # CMAKE_FLAGS are strings and not lists. By not putting quotes around CMAKE_FLAGS
+ # we convert the strings to lists (like we want).
+
+ if(CUDA_PROPAGATE_HOST_FLAGS)
+ # nvcc chokes on -g3 in versions previous to 3.0, so replace it with -g
+ set(_cuda_fix_g3 FALSE)
+
+ if(CMAKE_COMPILER_IS_GNUCC)
+ if (CUDA_VERSION VERSION_LESS "3.0" OR
+ CUDA_VERSION VERSION_EQUAL "4.1" OR
+ CUDA_VERSION VERSION_EQUAL "4.2"
+ )
+ set(_cuda_fix_g3 TRUE)
+ endif()
+ endif()
+ if(_cuda_fix_g3)
+ string(REPLACE "-g3" "-g" _cuda_C_FLAGS "${CMAKE_${CUDA_C_OR_CXX}_FLAGS_${config_upper}}")
+ else()
+ set(_cuda_C_FLAGS "${CMAKE_${CUDA_C_OR_CXX}_FLAGS_${config_upper}}")
+ endif()
+
+ string(APPEND _cuda_host_flags "\nset(CMAKE_HOST_FLAGS_${config_upper} ${_cuda_C_FLAGS})")
+ endif()
+
+ # Note that if we ever want CUDA_NVCC_FLAGS_<CONFIG> to be string (instead of a list
+ # like it is currently), we can remove the quotes around the
+ # ${CUDA_NVCC_FLAGS_${config_upper}} variable like the CMAKE_HOST_FLAGS_<CONFIG> variable.
+ string(APPEND _cuda_nvcc_flags_config "\nset(CUDA_NVCC_FLAGS_${config_upper} ${CUDA_NVCC_FLAGS_${config_upper}} ;; ${CUDA_WRAP_OPTION_NVCC_FLAGS_${config_upper}})")
+ endforeach()
+
+ # Process the C++11 flag. If the host sets the flag, we need to add it to nvcc and
+ # remove it from the host. This is because -Xcompile -std=c++ will choke nvcc (it uses
+ # the C preprocessor). In order to get this to work correctly, we need to use nvcc's
+ # specific c++11 flag.
+ if( "${_cuda_host_flags}" MATCHES "-std=c\\+\\+11")
+ # Add the c++11 flag to nvcc if it isn't already present. Note that we only look at
+ # the main flag instead of the configuration specific flags.
+ if( NOT "${CUDA_NVCC_FLAGS}" MATCHES "-std=c\\+\\+11" )
+ list(APPEND nvcc_flags --std c++11)
+ endif()
+ string(REGEX REPLACE "[-]+std=c\\+\\+11" "" _cuda_host_flags "${_cuda_host_flags}")
+ endif()
+
+ if(_cuda_build_shared_libs)
+ list(APPEND nvcc_flags "-D${cuda_target}_EXPORTS")
+ endif()
+
+ # Reset the output variable
+ set(_cuda_wrap_generated_files "")
+
+ # Iterate over the macro arguments and create custom
+ # commands for all the .cu files.
+ foreach(file ${_argn_list})
+ # Ignore any file marked as a HEADER_FILE_ONLY
+ get_source_file_property(_is_header ${file} HEADER_FILE_ONLY)
+ # Allow per source file overrides of the format. Also allows compiling non-.cu files.
+ get_source_file_property(_cuda_source_format ${file} CUDA_SOURCE_PROPERTY_FORMAT)
+ if((${file} MATCHES "\\.cu$" OR _cuda_source_format) AND NOT _is_header)
+
+ if(NOT _cuda_source_format)
+ set(_cuda_source_format ${format})
+ endif()
+ # If file isn't a .cu file, we need to tell nvcc to treat it as such.
+ if(NOT ${file} MATCHES "\\.cu$")
+ set(cuda_language_flag -x=cu)
+ else()
+ set(cuda_language_flag)
+ endif()
+
+ if( ${_cuda_source_format} MATCHES "OBJ")
+ set( cuda_compile_to_external_module OFF )
+ else()
+ set( cuda_compile_to_external_module ON )
+ if( ${_cuda_source_format} MATCHES "PTX" )
+ set( cuda_compile_to_external_module_type "ptx" )
+ elseif( ${_cuda_source_format} MATCHES "CUBIN")
+ set( cuda_compile_to_external_module_type "cubin" )
+ elseif( ${_cuda_source_format} MATCHES "FATBIN")
+ set( cuda_compile_to_external_module_type "fatbin" )
+ else()
+ message( FATAL_ERROR "Invalid format flag passed to CUDA_WRAP_SRCS or set with CUDA_SOURCE_PROPERTY_FORMAT file property for file '${file}': '${_cuda_source_format}'. Use OBJ, PTX, CUBIN or FATBIN.")
+ endif()
+ endif()
+
+ if(cuda_compile_to_external_module)
+ # Don't use any of the host compilation flags for PTX targets.
+ set(CUDA_HOST_FLAGS)
+ set(CUDA_NVCC_FLAGS_CONFIG)
+ else()
+ set(CUDA_HOST_FLAGS ${_cuda_host_flags})
+ set(CUDA_NVCC_FLAGS_CONFIG ${_cuda_nvcc_flags_config})
+ endif()
+
+ # Determine output directory
+ cuda_compute_build_path("${file}" cuda_build_path)
+ set(cuda_compile_intermediate_directory "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${cuda_target}.dir/${cuda_build_path}")
+ if(CUDA_GENERATED_OUTPUT_DIR)
+ set(cuda_compile_output_dir "${CUDA_GENERATED_OUTPUT_DIR}")
+ else()
+ if ( cuda_compile_to_external_module )
+ set(cuda_compile_output_dir "${CMAKE_CURRENT_BINARY_DIR}")
+ else()
+ set(cuda_compile_output_dir "${cuda_compile_intermediate_directory}")
+ endif()
+ endif()
+
+ # Add a custom target to generate a c or ptx file. ######################
+
+ get_filename_component( basename ${file} NAME )
+ if( cuda_compile_to_external_module )
+ set(generated_file_path "${cuda_compile_output_dir}")
+ set(generated_file_basename "${cuda_target}_generated_${basename}.${cuda_compile_to_external_module_type}")
+ set(format_flag "-${cuda_compile_to_external_module_type}")
+ file(MAKE_DIRECTORY "${cuda_compile_output_dir}")
+ else()
+ set(generated_file_path "${cuda_compile_output_dir}/${CMAKE_CFG_INTDIR}")
+ set(generated_file_basename "${cuda_target}_generated_${basename}${generated_extension}")
+ if(CUDA_SEPARABLE_COMPILATION)
+ set(format_flag "-dc")
+ else()
+ set(format_flag "-c")
+ endif()
+ endif()
+
+ # Set all of our file names. Make sure that whatever filenames that have
+ # generated_file_path in them get passed in through as a command line
+ # argument, so that the ${CMAKE_CFG_INTDIR} gets expanded at run time
+ # instead of configure time.
+ set(generated_file "${generated_file_path}/${generated_file_basename}")
+ set(cmake_dependency_file "${cuda_compile_intermediate_directory}/${generated_file_basename}.depend")
+ set(NVCC_generated_dependency_file "${cuda_compile_intermediate_directory}/${generated_file_basename}.NVCC-depend")
+ set(generated_cubin_file "${generated_file_path}/${generated_file_basename}.cubin.txt")
+ set(custom_target_script_pregen "${cuda_compile_intermediate_directory}/${generated_file_basename}.cmake.pre-gen")
+ set(custom_target_script "${cuda_compile_intermediate_directory}/${generated_file_basename}$<$<BOOL:$<CONFIG>>:.$<CONFIG>>.cmake")
+
+ # Setup properties for obj files:
+ if( NOT cuda_compile_to_external_module )
+ set_source_files_properties("${generated_file}"
+ PROPERTIES
+ EXTERNAL_OBJECT true # This is an object file not to be compiled, but only be linked.
+ )
+ endif()
+
+ # Don't add CMAKE_CURRENT_SOURCE_DIR if the path is already an absolute path.
+ get_filename_component(file_path "${file}" PATH)
+ if(IS_ABSOLUTE "${file_path}")
+ set(source_file "${file}")
+ else()
+ set(source_file "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
+ endif()
+
+ if( NOT cuda_compile_to_external_module AND CUDA_SEPARABLE_COMPILATION)
+ list(APPEND ${cuda_target}_SEPARABLE_COMPILATION_OBJECTS "${generated_file}")
+ endif()
+
+ # Bring in the dependencies. Creates a variable CUDA_NVCC_DEPEND #######
+ cuda_include_nvcc_dependencies(${cmake_dependency_file})
+
+ # Convenience string for output #########################################
+ if(CUDA_BUILD_EMULATION)
+ set(cuda_build_type "Emulation")
+ else()
+ set(cuda_build_type "Device")
+ endif()
+
+ # Build the NVCC made dependency file ###################################
+ set(build_cubin OFF)
+ if ( NOT CUDA_BUILD_EMULATION AND CUDA_BUILD_CUBIN )
+ if ( NOT cuda_compile_to_external_module )
+ set ( build_cubin ON )
+ endif()
+ endif()
+
+ # Configure the build script
+ configure_file("${CUDA_run_nvcc}" "${custom_target_script_pregen}" @ONLY)
+ file(GENERATE
+ OUTPUT "${custom_target_script}"
+ INPUT "${custom_target_script_pregen}"
+ )
+
+ # So if a user specifies the same cuda file as input more than once, you
+ # can have bad things happen with dependencies. Here we check an option
+ # to see if this is the behavior they want.
+ if(CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE)
+ set(main_dep MAIN_DEPENDENCY ${source_file})
+ else()
+ set(main_dep DEPENDS ${source_file})
+ endif()
+
+ if(CUDA_VERBOSE_BUILD)
+ set(verbose_output ON)
+ elseif(CMAKE_GENERATOR MATCHES "Makefiles")
+ set(verbose_output "$(VERBOSE)")
+ else()
+ set(verbose_output OFF)
+ endif()
+
+ # Create up the comment string
+ file(RELATIVE_PATH generated_file_relative_path "${CMAKE_BINARY_DIR}" "${generated_file}")
+ if(cuda_compile_to_external_module)
+ set(cuda_build_comment_string "Building NVCC ${cuda_compile_to_external_module_type} file ${generated_file_relative_path}")
+ else()
+ set(cuda_build_comment_string "Building NVCC (${cuda_build_type}) object ${generated_file_relative_path}")
+ endif()
+
+ set(_verbatim VERBATIM)
+ if(ccbin_flags MATCHES "\\$\\(VCInstallDir\\)")
+ set(_verbatim "")
+ endif()
+
+ # Build the generated file and dependency file ##########################
+ add_custom_command(
+ OUTPUT ${generated_file}
+ # These output files depend on the source_file and the contents of cmake_dependency_file
+ ${main_dep}
+ DEPENDS ${CUDA_NVCC_DEPEND}
+ DEPENDS ${custom_target_script}
+ # Make sure the output directory exists before trying to write to it.
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${generated_file_path}"
+ COMMAND ${CMAKE_COMMAND} ARGS
+ -D verbose:BOOL=${verbose_output}
+ ${ccbin_flags}
+ -D build_configuration:STRING=${CUDA_build_configuration}
+ -D "generated_file:STRING=${generated_file}"
+ -D "generated_cubin_file:STRING=${generated_cubin_file}"
+ -P "${custom_target_script}"
+ WORKING_DIRECTORY "${cuda_compile_intermediate_directory}"
+ COMMENT "${cuda_build_comment_string}"
+ ${_verbatim}
+ )
+
+ # Make sure the build system knows the file is generated.
+ set_source_files_properties(${generated_file} PROPERTIES GENERATED TRUE)
+
+ list(APPEND _cuda_wrap_generated_files ${generated_file})
+
+ # Add the other files that we want cmake to clean on a cleanup ##########
+ list(APPEND CUDA_ADDITIONAL_CLEAN_FILES "${cmake_dependency_file}")
+ list(REMOVE_DUPLICATES CUDA_ADDITIONAL_CLEAN_FILES)
+ set(CUDA_ADDITIONAL_CLEAN_FILES ${CUDA_ADDITIONAL_CLEAN_FILES} CACHE INTERNAL "List of intermediate files that are part of the cuda dependency scanning.")
+
+ endif()
+ endforeach()
+
+ # Set the return parameter
+ set(${generated_files} ${_cuda_wrap_generated_files})
+endmacro()
+
+function(_cuda_get_important_host_flags important_flags flag_string)
+ if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ string(REGEX MATCHALL "/M[DT][d]?" flags "${flag_string}")
+ list(APPEND ${important_flags} ${flags})
+ else()
+ string(REGEX MATCHALL "-fPIC" flags "${flag_string}")
+ list(APPEND ${important_flags} ${flags})
+ endif()
+ set(${important_flags} ${${important_flags}} PARENT_SCOPE)
+endfunction()
+
+###############################################################################
+###############################################################################
+# Separable Compilation Link
+###############################################################################
+###############################################################################
+
+# Compute the filename to be used by CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS
+function(CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME output_file_var cuda_target object_files)
+ if (object_files)
+ set(generated_extension ${CMAKE_${CUDA_C_OR_CXX}_OUTPUT_EXTENSION})
+ set(output_file "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${cuda_target}.dir/${CMAKE_CFG_INTDIR}/${cuda_target}_intermediate_link${generated_extension}")
+ else()
+ set(output_file)
+ endif()
+
+ set(${output_file_var} "${output_file}" PARENT_SCOPE)
+endfunction()
+
+# Setup the build rule for the separable compilation intermediate link file.
+function(CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS output_file cuda_target options object_files)
+ if (object_files)
+
+ set_source_files_properties("${output_file}"
+ PROPERTIES
+ EXTERNAL_OBJECT TRUE # This is an object file not to be compiled, but only
+ # be linked.
+ GENERATED TRUE # This file is generated during the build
+ )
+
+ # For now we are ignoring all the configuration specific flags.
+ set(nvcc_flags)
+ CUDA_PARSE_NVCC_OPTIONS(nvcc_flags ${options})
+ if(CUDA_64_BIT_DEVICE_CODE)
+ list(APPEND nvcc_flags -m64)
+ else()
+ list(APPEND nvcc_flags -m32)
+ endif()
+ # If -ccbin, --compiler-bindir has been specified, don't do anything. Otherwise add it here.
+ list( FIND nvcc_flags "-ccbin" ccbin_found0 )
+ list( FIND nvcc_flags "--compiler-bindir" ccbin_found1 )
+ if( ccbin_found0 LESS 0 AND ccbin_found1 LESS 0 AND CUDA_HOST_COMPILER )
+ # Match VERBATIM check below.
+ if(CUDA_HOST_COMPILER MATCHES "\\$\\(VCInstallDir\\)")
+ list(APPEND nvcc_flags -ccbin "\"${CUDA_HOST_COMPILER}\"")
+ else()
+ list(APPEND nvcc_flags -ccbin "${CUDA_HOST_COMPILER}")
+ endif()
+ endif()
+
+ # Create a list of flags specified by CUDA_NVCC_FLAGS_${CONFIG} and CMAKE_${CUDA_C_OR_CXX}_FLAGS*
+ set(config_specific_flags)
+ set(flags)
+ foreach(config ${CUDA_configuration_types})
+ string(TOUPPER ${config} config_upper)
+ # Add config specific flags
+ foreach(f ${CUDA_NVCC_FLAGS_${config_upper}})
+ list(APPEND config_specific_flags $<$<CONFIG:${config}>:${f}>)
+ endforeach()
+ set(important_host_flags)
+ _cuda_get_important_host_flags(important_host_flags "${CMAKE_${CUDA_C_OR_CXX}_FLAGS_${config_upper}}")
+ foreach(f ${important_host_flags})
+ list(APPEND flags $<$<CONFIG:${config}>:-Xcompiler> $<$<CONFIG:${config}>:${f}>)
+ endforeach()
+ endforeach()
+ # Add CMAKE_${CUDA_C_OR_CXX}_FLAGS
+ set(important_host_flags)
+ _cuda_get_important_host_flags(important_host_flags "${CMAKE_${CUDA_C_OR_CXX}_FLAGS}")
+ foreach(f ${important_host_flags})
+ list(APPEND flags -Xcompiler ${f})
+ endforeach()
+
+ # Add our general CUDA_NVCC_FLAGS with the configuration specifig flags
+ set(nvcc_flags ${CUDA_NVCC_FLAGS} ${config_specific_flags} ${nvcc_flags})
+
+ file(RELATIVE_PATH output_file_relative_path "${CMAKE_BINARY_DIR}" "${output_file}")
+
+ # Some generators don't handle the multiple levels of custom command
+ # dependencies correctly (obj1 depends on file1, obj2 depends on obj1), so
+ # we work around that issue by compiling the intermediate link object as a
+ # pre-link custom command in that situation.
+ set(do_obj_build_rule TRUE)
+ if (MSVC_VERSION GREATER 1599 AND MSVC_VERSION LESS 1800)
+ # VS 2010 and 2012 have this problem.
+ set(do_obj_build_rule FALSE)
+ endif()
+
+ set(_verbatim VERBATIM)
+ if(nvcc_flags MATCHES "\\$\\(VCInstallDir\\)")
+ set(_verbatim "")
+ endif()
+
+ if (do_obj_build_rule)
+ add_custom_command(
+ OUTPUT ${output_file}
+ DEPENDS ${object_files}
+ COMMAND ${CUDA_NVCC_EXECUTABLE} ${nvcc_flags} -dlink ${object_files} -o ${output_file}
+ ${flags}
+ COMMENT "Building NVCC intermediate link file ${output_file_relative_path}"
+ COMMAND_EXPAND_LISTS
+ ${_verbatim}
+ )
+ else()
+ get_filename_component(output_file_dir "${output_file}" DIRECTORY)
+ add_custom_command(
+ TARGET ${cuda_target}
+ PRE_LINK
+ COMMAND ${CMAKE_COMMAND} -E echo "Building NVCC intermediate link file ${output_file_relative_path}"
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${output_file_dir}"
+ COMMAND ${CUDA_NVCC_EXECUTABLE} ${nvcc_flags} ${flags} -dlink ${object_files} -o "${output_file}"
+ COMMAND_EXPAND_LISTS
+ ${_verbatim}
+ )
+ endif()
+ endif()
+endfunction()
+
+###############################################################################
+###############################################################################
+# ADD LIBRARY
+###############################################################################
+###############################################################################
+macro(CUDA_ADD_LIBRARY cuda_target)
+
+ CUDA_ADD_CUDA_INCLUDE_ONCE()
+
+ # Separate the sources from the options
+ CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN})
+ CUDA_BUILD_SHARED_LIBRARY(_cuda_shared_flag ${ARGN})
+ # Create custom commands and targets for each file.
+ CUDA_WRAP_SRCS( ${cuda_target} OBJ _generated_files ${_sources}
+ ${_cmake_options} ${_cuda_shared_flag}
+ OPTIONS ${_options} )
+
+ # Compute the file name of the intermedate link file used for separable
+ # compilation.
+ CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME(link_file ${cuda_target} "${${cuda_target}_SEPARABLE_COMPILATION_OBJECTS}")
+
+ # Add the library.
+ add_library(${cuda_target} ${_cmake_options}
+ ${_generated_files}
+ ${_sources}
+ ${link_file}
+ )
+
+ # Add a link phase for the separable compilation if it has been enabled. If
+ # it has been enabled then the ${cuda_target}_SEPARABLE_COMPILATION_OBJECTS
+ # variable will have been defined.
+ CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS("${link_file}" ${cuda_target} "${_options}" "${${cuda_target}_SEPARABLE_COMPILATION_OBJECTS}")
+
+ target_link_libraries(${cuda_target} ${CUDA_LINK_LIBRARIES_KEYWORD}
+ ${CUDA_LIBRARIES}
+ )
+
+ if(CUDA_SEPARABLE_COMPILATION)
+ target_link_libraries(${cuda_target} ${CUDA_LINK_LIBRARIES_KEYWORD}
+ ${CUDA_cudadevrt_LIBRARY}
+ )
+ endif()
+
+ # We need to set the linker language based on what the expected generated file
+ # would be. CUDA_C_OR_CXX is computed based on CUDA_HOST_COMPILATION_CPP.
+ set_target_properties(${cuda_target}
+ PROPERTIES
+ LINKER_LANGUAGE ${CUDA_C_OR_CXX}
+ )
+
+endmacro()
+
+
+###############################################################################
+###############################################################################
+# ADD EXECUTABLE
+###############################################################################
+###############################################################################
+macro(CUDA_ADD_EXECUTABLE cuda_target)
+
+ CUDA_ADD_CUDA_INCLUDE_ONCE()
+
+ # Separate the sources from the options
+ CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN})
+ # Create custom commands and targets for each file.
+ CUDA_WRAP_SRCS( ${cuda_target} OBJ _generated_files ${_sources} OPTIONS ${_options} )
+
+ # Compute the file name of the intermedate link file used for separable
+ # compilation.
+ CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME(link_file ${cuda_target} "${${cuda_target}_SEPARABLE_COMPILATION_OBJECTS}")
+
+ # Add the library.
+ add_executable(${cuda_target} ${_cmake_options}
+ ${_generated_files}
+ ${_sources}
+ ${link_file}
+ )
+
+ # Add a link phase for the separable compilation if it has been enabled. If
+ # it has been enabled then the ${cuda_target}_SEPARABLE_COMPILATION_OBJECTS
+ # variable will have been defined.
+ CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS("${link_file}" ${cuda_target} "${_options}" "${${cuda_target}_SEPARABLE_COMPILATION_OBJECTS}")
+
+ target_link_libraries(${cuda_target} ${CUDA_LINK_LIBRARIES_KEYWORD}
+ ${CUDA_LIBRARIES}
+ )
+
+ # We need to set the linker language based on what the expected generated file
+ # would be. CUDA_C_OR_CXX is computed based on CUDA_HOST_COMPILATION_CPP.
+ set_target_properties(${cuda_target}
+ PROPERTIES
+ LINKER_LANGUAGE ${CUDA_C_OR_CXX}
+ )
+
+endmacro()
+
+
+###############################################################################
+###############################################################################
+# (Internal) helper for manually added cuda source files with specific targets
+###############################################################################
+###############################################################################
+macro(cuda_compile_base cuda_target format generated_files)
+ # Update a counter in this directory, to keep phony target names unique.
+ set(_cuda_target "${cuda_target}")
+ get_property(_counter DIRECTORY PROPERTY _cuda_internal_phony_counter)
+ if(_counter)
+ math(EXPR _counter "${_counter} + 1")
+ else()
+ set(_counter 1)
+ endif()
+ string(APPEND _cuda_target "_${_counter}")
+ set_property(DIRECTORY PROPERTY _cuda_internal_phony_counter ${_counter})
+
+ # Separate the sources from the options
+ CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN})
+
+ # Create custom commands and targets for each file.
+ CUDA_WRAP_SRCS( ${_cuda_target} ${format} _generated_files ${_sources}
+ ${_cmake_options} OPTIONS ${_options} PHONY)
+
+ set( ${generated_files} ${_generated_files})
+
+endmacro()
+
+###############################################################################
+###############################################################################
+# CUDA COMPILE
+###############################################################################
+###############################################################################
+macro(CUDA_COMPILE generated_files)
+ cuda_compile_base(cuda_compile OBJ ${generated_files} ${ARGN})
+endmacro()
+
+###############################################################################
+###############################################################################
+# CUDA COMPILE PTX
+###############################################################################
+###############################################################################
+macro(CUDA_COMPILE_PTX generated_files)
+ cuda_compile_base(cuda_compile_ptx PTX ${generated_files} ${ARGN})
+endmacro()
+
+###############################################################################
+###############################################################################
+# CUDA COMPILE FATBIN
+###############################################################################
+###############################################################################
+macro(CUDA_COMPILE_FATBIN generated_files)
+ cuda_compile_base(cuda_compile_fatbin FATBIN ${generated_files} ${ARGN})
+endmacro()
+
+###############################################################################
+###############################################################################
+# CUDA COMPILE CUBIN
+###############################################################################
+###############################################################################
+macro(CUDA_COMPILE_CUBIN generated_files)
+ cuda_compile_base(cuda_compile_cubin CUBIN ${generated_files} ${ARGN})
+endmacro()
+
+
+###############################################################################
+###############################################################################
+# CUDA ADD CUFFT TO TARGET
+###############################################################################
+###############################################################################
+macro(CUDA_ADD_CUFFT_TO_TARGET target)
+ if (CUDA_BUILD_EMULATION)
+ target_link_libraries(${target} ${CUDA_LINK_LIBRARIES_KEYWORD} ${CUDA_cufftemu_LIBRARY})
+ else()
+ target_link_libraries(${target} ${CUDA_LINK_LIBRARIES_KEYWORD} ${CUDA_cufft_LIBRARY})
+ endif()
+endmacro()
+
+###############################################################################
+###############################################################################
+# CUDA ADD CUBLAS TO TARGET
+###############################################################################
+###############################################################################
+macro(CUDA_ADD_CUBLAS_TO_TARGET target)
+ if (CUDA_BUILD_EMULATION)
+ target_link_libraries(${target} ${CUDA_LINK_LIBRARIES_KEYWORD} ${CUDA_cublasemu_LIBRARY})
+ else()
+ target_link_libraries(${target} ${CUDA_LINK_LIBRARIES_KEYWORD} ${CUDA_cublas_LIBRARY} ${CUDA_cublas_device_LIBRARY})
+ endif()
+endmacro()
+
+###############################################################################
+###############################################################################
+# CUDA BUILD CLEAN TARGET
+###############################################################################
+###############################################################################
+macro(CUDA_BUILD_CLEAN_TARGET)
+ # Call this after you add all your CUDA targets, and you will get a
+ # convenience target. You should also make clean after running this target
+ # to get the build system to generate all the code again.
+
+ set(cuda_clean_target_name clean_cuda_depends)
+ if (CMAKE_GENERATOR MATCHES "Visual Studio")
+ string(TOUPPER ${cuda_clean_target_name} cuda_clean_target_name)
+ endif()
+ add_custom_target(${cuda_clean_target_name}
+ COMMAND ${CMAKE_COMMAND} -E rm -f ${CUDA_ADDITIONAL_CLEAN_FILES})
+
+ # Clear out the variable, so the next time we configure it will be empty.
+ # This is useful so that the files won't persist in the list after targets
+ # have been removed.
+ set(CUDA_ADDITIONAL_CLEAN_FILES "" CACHE INTERNAL "List of intermediate files that are part of the cuda dependency scanning.")
+endmacro()
diff --git a/Modules/FindCUDA/make2cmake.cmake b/Modules/FindCUDA/make2cmake.cmake
new file mode 100644
index 0000000..580f24a
--- /dev/null
+++ b/Modules/FindCUDA/make2cmake.cmake
@@ -0,0 +1,106 @@
+# James Bigler, NVIDIA Corp (nvidia.com - jbigler)
+# Abe Stephens, SCI Institute -- http://www.sci.utah.edu/~abe/FindCuda.html
+#
+# Copyright (c) 2008 - 2009 NVIDIA Corporation. All rights reserved.
+#
+# Copyright (c) 2007-2009
+# Scientific Computing and Imaging Institute, University of Utah
+#
+# This code is licensed under the MIT License. See the FindCUDA.cmake script
+# for the text of the license.
+
+# The MIT License
+#
+# License for the specific language governing rights and limitations under
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+
+#######################################################################
+# This converts a file written in makefile syntax into one that can be included
+# by CMake.
+
+# Input variables
+#
+# verbose:BOOL=<> OFF: Be as quiet as possible (default)
+# ON : Extra output
+#
+# input_file:FILEPATH=<> Path to dependency file in makefile format
+#
+# output_file:FILEPATH=<> Path to file with dependencies in CMake readable variable
+#
+
+file(READ ${input_file} depend_text)
+
+if (NOT "${depend_text}" STREQUAL "")
+
+ # message("FOUND DEPENDS")
+
+ string(REPLACE "\\ " " " depend_text ${depend_text})
+
+ # This works for the nvcc -M generated dependency files.
+ string(REGEX REPLACE "^.* : " "" depend_text ${depend_text})
+ string(REGEX REPLACE "[ \\\\]*\n" ";" depend_text ${depend_text})
+
+ set(dependency_list "")
+
+ foreach(file ${depend_text})
+
+ string(REGEX REPLACE "^ +" "" file ${file})
+
+ # OK, now if we had a UNC path, nvcc has a tendency to only output the first '/'
+ # instead of '//'. Here we will test to see if the file exists, if it doesn't then
+ # try to prepend another '/' to the path and test again. If it still fails remove the
+ # path.
+
+ if(NOT EXISTS "${file}")
+ if (EXISTS "/${file}")
+ set(file "/${file}")
+ else()
+ if(verbose)
+ message(WARNING " Removing non-existent dependency file: ${file}")
+ endif()
+ set(file "")
+ endif()
+ endif()
+
+ # Make sure we check to see if we have a file, before asking if it is not a directory.
+ # if(NOT IS_DIRECTORY "") will return TRUE.
+ if(file AND NOT IS_DIRECTORY "${file}")
+ # If softlinks start to matter, we should change this to REALPATH. For now we need
+ # to flatten paths, because nvcc can generate stuff like /bin/../include instead of
+ # just /include.
+ get_filename_component(file_absolute "${file}" ABSOLUTE)
+ list(APPEND dependency_list "${file_absolute}")
+ endif()
+
+ endforeach()
+
+else()
+ # message("FOUND NO DEPENDS")
+endif()
+
+# Remove the duplicate entries and sort them.
+list(REMOVE_DUPLICATES dependency_list)
+list(SORT dependency_list)
+
+foreach(file ${dependency_list})
+ string(APPEND cuda_nvcc_depend " \"${file}\"\n")
+endforeach()
+
+file(WRITE ${output_file} "# Generated by: make2cmake.cmake\nSET(CUDA_NVCC_DEPEND\n ${cuda_nvcc_depend})\n\n")
diff --git a/Modules/FindCUDA/parse_cubin.cmake b/Modules/FindCUDA/parse_cubin.cmake
new file mode 100644
index 0000000..626c8a2
--- /dev/null
+++ b/Modules/FindCUDA/parse_cubin.cmake
@@ -0,0 +1,111 @@
+# James Bigler, NVIDIA Corp (nvidia.com - jbigler)
+# Abe Stephens, SCI Institute -- http://www.sci.utah.edu/~abe/FindCuda.html
+#
+# Copyright (c) 2008 - 2009 NVIDIA Corporation. All rights reserved.
+#
+# Copyright (c) 2007-2009
+# Scientific Computing and Imaging Institute, University of Utah
+#
+# This code is licensed under the MIT License. See the FindCUDA.cmake script
+# for the text of the license.
+
+# The MIT License
+#
+# License for the specific language governing rights and limitations under
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+
+#######################################################################
+# Parses a .cubin file produced by nvcc and reports statistics about the file.
+
+
+file(READ ${input_file} file_text)
+
+if (NOT "${file_text}" STREQUAL "")
+
+ string(REPLACE ";" "\\;" file_text ${file_text})
+ string(REPLACE "\ncode" ";code" file_text ${file_text})
+
+ list(LENGTH file_text len)
+
+ foreach(line ${file_text})
+
+ # Only look at "code { }" blocks.
+ if(line MATCHES "^code")
+
+ # Break into individual lines.
+ string(REGEX REPLACE "\n" ";" line ${line})
+
+ foreach(entry ${line})
+
+ # Extract kernel names.
+ if (${entry} MATCHES "[^g]name = ([^ ]+)")
+ set(entry "${CMAKE_MATCH_1}")
+
+ # Check to see if the kernel name starts with "_"
+ set(skip FALSE)
+ # if (${entry} MATCHES "^_")
+ # Skip the rest of this block.
+ # message("Skipping ${entry}")
+ # set(skip TRUE)
+ # else ()
+ message("Kernel: ${entry}")
+ # endif ()
+
+ endif()
+
+ # Skip the rest of the block if necessary
+ if(NOT skip)
+
+ # Registers
+ if (${entry} MATCHES "reg([ ]+)=([ ]+)([^ ]+)")
+ set(entry "${CMAKE_MATCH_3}")
+ message("Registers: ${entry}")
+ endif()
+
+ # Local memory
+ if (${entry} MATCHES "lmem([ ]+)=([ ]+)([^ ]+)")
+ set(entry "${CMAKE_MATCH_3}")
+ message("Local: ${entry}")
+ endif()
+
+ # Shared memory
+ if (${entry} MATCHES "smem([ ]+)=([ ]+)([^ ]+)")
+ set(entry "${CMAKE_MATCH_3}")
+ message("Shared: ${entry}")
+ endif()
+
+ if (${entry} MATCHES "^}")
+ message("")
+ endif()
+
+ endif()
+
+
+ endforeach()
+
+ endif()
+
+ endforeach()
+
+else()
+ # message("FOUND NO DEPENDS")
+endif()
+
+
diff --git a/Modules/FindCUDA/run_nvcc.cmake b/Modules/FindCUDA/run_nvcc.cmake
new file mode 100644
index 0000000..17e12f8
--- /dev/null
+++ b/Modules/FindCUDA/run_nvcc.cmake
@@ -0,0 +1,306 @@
+# James Bigler, NVIDIA Corp (nvidia.com - jbigler)
+#
+# Copyright (c) 2008 - 2009 NVIDIA Corporation. All rights reserved.
+#
+# This code is licensed under the MIT License. See the FindCUDA.cmake script
+# for the text of the license.
+
+# The MIT License
+#
+# License for the specific language governing rights and limitations under
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+
+##########################################################################
+# This file runs the nvcc commands to produce the desired output file along with
+# the dependency file needed by CMake to compute dependencies. In addition the
+# file checks the output of each command and if the command fails it deletes the
+# output files.
+
+# Input variables
+#
+# verbose:BOOL=<> OFF: Be as quiet as possible (default)
+# ON : Describe each step
+#
+# build_configuration:STRING=<> Typically one of Debug, MinSizeRel, Release, or
+# RelWithDebInfo, but it should match one of the
+# entries in CUDA_HOST_FLAGS. This is the build
+# configuration used when compiling the code. If
+# blank or unspecified Debug is assumed as this is
+# what CMake does.
+#
+# generated_file:STRING=<> File to generate. This argument must be passed in.
+#
+# generated_cubin_file:STRING=<> File to generate. This argument must be passed
+# in if build_cubin is true.
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0007 NEW)
+if(NOT generated_file)
+ message(FATAL_ERROR "You must specify generated_file on the command line")
+endif()
+
+# Set these up as variables to make reading the generated file easier
+set(CMAKE_COMMAND "@CMAKE_COMMAND@") # path
+set(source_file "@source_file@") # path
+set(NVCC_generated_dependency_file "@NVCC_generated_dependency_file@") # path
+set(cmake_dependency_file "@cmake_dependency_file@") # path
+set(CUDA_make2cmake "@CUDA_make2cmake@") # path
+set(CUDA_parse_cubin "@CUDA_parse_cubin@") # path
+set(build_cubin @build_cubin@) # bool
+set(CUDA_HOST_COMPILER "@CUDA_HOST_COMPILER@") # path
+# We won't actually use these variables for now, but we need to set this, in
+# order to force this file to be run again if it changes.
+set(generated_file_path "@generated_file_path@") # path
+set(generated_file_internal "@generated_file@") # path
+set(generated_cubin_file_internal "@generated_cubin_file@") # path
+
+set(CUDA_NVCC_EXECUTABLE "@CUDA_NVCC_EXECUTABLE@") # path
+set(CUDA_NVCC_FLAGS @CUDA_NVCC_FLAGS@ ;; @CUDA_WRAP_OPTION_NVCC_FLAGS@) # list
+@CUDA_NVCC_FLAGS_CONFIG@
+set(nvcc_flags @nvcc_flags@) # list
+set(CUDA_NVCC_INCLUDE_DIRS [==[@CUDA_NVCC_INCLUDE_DIRS@]==]) # list (needs to be in lua quotes to address backslashes)
+string(REPLACE "\\" "/" CUDA_NVCC_INCLUDE_DIRS "${CUDA_NVCC_INCLUDE_DIRS}")
+set(CUDA_NVCC_COMPILE_DEFINITIONS [==[@CUDA_NVCC_COMPILE_DEFINITIONS@]==]) # list (needs to be in lua quotes see #16510 ).
+set(format_flag "@format_flag@") # string
+set(cuda_language_flag @cuda_language_flag@) # list
+
+# Clean up list of include directories and add -I flags
+list(REMOVE_DUPLICATES CUDA_NVCC_INCLUDE_DIRS)
+set(CUDA_NVCC_INCLUDE_ARGS)
+foreach(dir ${CUDA_NVCC_INCLUDE_DIRS})
+ # Extra quotes are added around each flag to help nvcc parse out flags with spaces.
+ list(APPEND CUDA_NVCC_INCLUDE_ARGS "-I${dir}")
+endforeach()
+
+# Clean up list of compile definitions, add -D flags, and append to nvcc_flags
+list(REMOVE_DUPLICATES CUDA_NVCC_COMPILE_DEFINITIONS)
+foreach(def ${CUDA_NVCC_COMPILE_DEFINITIONS})
+ list(APPEND nvcc_flags "-D${def}")
+endforeach()
+
+if(build_cubin AND NOT generated_cubin_file)
+ message(FATAL_ERROR "You must specify generated_cubin_file on the command line")
+endif()
+
+# This is the list of host compilation flags. It C or CXX should already have
+# been chosen by FindCUDA.cmake.
+@CUDA_HOST_FLAGS@
+
+# Take the compiler flags and package them up to be sent to the compiler via -Xcompiler
+set(nvcc_host_compiler_flags "")
+# If we weren't given a build_configuration, use Debug.
+if(NOT build_configuration)
+ set(build_configuration Debug)
+endif()
+string(TOUPPER "${build_configuration}" build_configuration)
+#message("CUDA_NVCC_HOST_COMPILER_FLAGS = ${CUDA_NVCC_HOST_COMPILER_FLAGS}")
+foreach(flag ${CMAKE_HOST_FLAGS} ${CMAKE_HOST_FLAGS_${build_configuration}})
+ # Extra quotes are added around each flag to help nvcc parse out flags with spaces.
+ string(APPEND nvcc_host_compiler_flags ",\"${flag}\"")
+endforeach()
+if (nvcc_host_compiler_flags)
+ set(nvcc_host_compiler_flags "-Xcompiler" ${nvcc_host_compiler_flags})
+endif()
+#message("nvcc_host_compiler_flags = \"${nvcc_host_compiler_flags}\"")
+# Add the build specific configuration flags
+list(APPEND CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS_${build_configuration}})
+
+# Any -ccbin existing in CUDA_NVCC_FLAGS gets highest priority
+list( FIND CUDA_NVCC_FLAGS "-ccbin" ccbin_found0 )
+list( FIND CUDA_NVCC_FLAGS "--compiler-bindir" ccbin_found1 )
+if( ccbin_found0 LESS 0 AND ccbin_found1 LESS 0 AND CUDA_HOST_COMPILER )
+ if (CUDA_HOST_COMPILER STREQUAL "@_CUDA_MSVC_HOST_COMPILER@" AND DEFINED CCBIN)
+ set(CCBIN -ccbin "${CCBIN}")
+ else()
+ set(CCBIN -ccbin "${CUDA_HOST_COMPILER}")
+ endif()
+endif()
+
+# cuda_execute_process - Executes a command with optional command echo and status message.
+#
+# status - Status message to print if verbose is true
+# command - COMMAND argument from the usual execute_process argument structure
+# ARGN - Remaining arguments are the command with arguments
+#
+# CUDA_result - return value from running the command
+#
+# Make this a macro instead of a function, so that things like RESULT_VARIABLE
+# and other return variables are present after executing the process.
+macro(cuda_execute_process status command)
+ set(_command ${command})
+ if(NOT "x${_command}" STREQUAL "xCOMMAND")
+ message(FATAL_ERROR "Malformed call to cuda_execute_process. Missing COMMAND as second argument. (command = ${command})")
+ endif()
+ if(verbose)
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E echo -- ${status})
+ # Now we need to build up our command string. We are accounting for quotes
+ # and spaces, anything else is left up to the user to fix if they want to
+ # copy and paste a runnable command line.
+ set(cuda_execute_process_string)
+ foreach(arg ${ARGN})
+ # If there are quotes, escape them, so they come through.
+ string(REPLACE "\"" "\\\"" arg ${arg})
+ # Args with spaces need quotes around them to get them to be parsed as a single argument.
+ if(arg MATCHES " ")
+ list(APPEND cuda_execute_process_string "\"${arg}\"")
+ else()
+ list(APPEND cuda_execute_process_string ${arg})
+ endif()
+ endforeach()
+ # Echo the command
+ execute_process(COMMAND ${CMAKE_COMMAND} -E echo ${cuda_execute_process_string})
+ endif()
+ # Run the command
+ execute_process(COMMAND ${ARGN} RESULT_VARIABLE CUDA_result )
+endmacro()
+
+# Delete the target file
+cuda_execute_process(
+ "Removing ${generated_file}"
+ COMMAND "${CMAKE_COMMAND}" -E rm -f "${generated_file}"
+ )
+
+# For CUDA 2.3 and below, -G -M doesn't work, so remove the -G flag
+# for dependency generation and hope for the best.
+set(depends_CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS}")
+set(CUDA_VERSION @CUDA_VERSION@)
+if(CUDA_VERSION VERSION_LESS "3.0")
+ # Note that this will remove all occurrences of -G.
+ list(REMOVE_ITEM depends_CUDA_NVCC_FLAGS "-G")
+endif()
+
+# nvcc doesn't define __CUDACC__ for some reason when generating dependency files. This
+# can cause incorrect dependencies when #including files based on this macro which is
+# defined in the generating passes of nvcc invocation. We will go ahead and manually
+# define this for now until a future version fixes this bug.
+set(CUDACC_DEFINE -D__CUDACC__)
+
+# Generate the dependency file
+cuda_execute_process(
+ "Generating dependency file: ${NVCC_generated_dependency_file}"
+ COMMAND "${CUDA_NVCC_EXECUTABLE}"
+ -M
+ ${CUDACC_DEFINE}
+ "${source_file}"
+ -o "${NVCC_generated_dependency_file}"
+ ${CCBIN}
+ ${nvcc_flags}
+ ${nvcc_host_compiler_flags}
+ ${depends_CUDA_NVCC_FLAGS}
+ -DNVCC
+ ${CUDA_NVCC_INCLUDE_ARGS}
+ )
+
+if(CUDA_result)
+ message(FATAL_ERROR "Error generating ${generated_file}")
+endif()
+
+# Generate the cmake readable dependency file to a temp file. Don't put the
+# quotes just around the filenames for the input_file and output_file variables.
+# CMake will pass the quotes through and not be able to find the file.
+cuda_execute_process(
+ "Generating temporary cmake readable file: ${cmake_dependency_file}.tmp"
+ COMMAND "${CMAKE_COMMAND}"
+ -D "input_file:FILEPATH=${NVCC_generated_dependency_file}"
+ -D "output_file:FILEPATH=${cmake_dependency_file}.tmp"
+ -D "verbose=${verbose}"
+ -P "${CUDA_make2cmake}"
+ )
+
+if(CUDA_result)
+ message(FATAL_ERROR "Error generating ${generated_file}")
+endif()
+
+# Copy the file if it is different
+cuda_execute_process(
+ "Copy if different ${cmake_dependency_file}.tmp to ${cmake_dependency_file}"
+ COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${cmake_dependency_file}.tmp" "${cmake_dependency_file}"
+ )
+
+if(CUDA_result)
+ message(FATAL_ERROR "Error generating ${generated_file}")
+endif()
+
+# Delete the temporary file
+cuda_execute_process(
+ "Removing ${cmake_dependency_file}.tmp and ${NVCC_generated_dependency_file}"
+ COMMAND "${CMAKE_COMMAND}" -E rm -f "${cmake_dependency_file}.tmp" "${NVCC_generated_dependency_file}"
+ )
+
+if(CUDA_result)
+ message(FATAL_ERROR "Error generating ${generated_file}")
+endif()
+
+# Generate the code
+cuda_execute_process(
+ "Generating ${generated_file}"
+ COMMAND "${CUDA_NVCC_EXECUTABLE}"
+ "${source_file}"
+ ${cuda_language_flag}
+ ${format_flag} -o "${generated_file}"
+ ${CCBIN}
+ ${nvcc_flags}
+ ${nvcc_host_compiler_flags}
+ ${CUDA_NVCC_FLAGS}
+ -DNVCC
+ ${CUDA_NVCC_INCLUDE_ARGS}
+ )
+
+if(CUDA_result)
+ # Since nvcc can sometimes leave half done files make sure that we delete the output file.
+ cuda_execute_process(
+ "Removing ${generated_file}"
+ COMMAND "${CMAKE_COMMAND}" -E rm -f "${generated_file}"
+ )
+ message(FATAL_ERROR "Error generating file ${generated_file}")
+else()
+ if(verbose)
+ message("Generated ${generated_file} successfully.")
+ endif()
+endif()
+
+# Cubin resource report commands.
+if( build_cubin )
+ # Run with -cubin to produce resource usage report.
+ cuda_execute_process(
+ "Generating ${generated_cubin_file}"
+ COMMAND "${CUDA_NVCC_EXECUTABLE}"
+ "${source_file}"
+ ${CUDA_NVCC_FLAGS}
+ ${nvcc_flags}
+ ${CCBIN}
+ ${nvcc_host_compiler_flags}
+ -DNVCC
+ -cubin
+ -o "${generated_cubin_file}"
+ ${CUDA_NVCC_INCLUDE_ARGS}
+ )
+
+ # Execute the parser script.
+ cuda_execute_process(
+ "Executing the parser script"
+ COMMAND "${CMAKE_COMMAND}"
+ -D "input_file:STRING=${generated_cubin_file}"
+ -P "${CUDA_parse_cubin}"
+ )
+
+endif()
+
+cmake_policy(POP)
diff --git a/Modules/FindCUDA/select_compute_arch.cmake b/Modules/FindCUDA/select_compute_arch.cmake
new file mode 100644
index 0000000..a35b3f8
--- /dev/null
+++ b/Modules/FindCUDA/select_compute_arch.cmake
@@ -0,0 +1,298 @@
+# Synopsis:
+# CUDA_SELECT_NVCC_ARCH_FLAGS(out_variable [target_CUDA_architectures])
+# -- Selects GPU arch flags for nvcc based on target_CUDA_architectures
+# target_CUDA_architectures : Auto | Common | All | LIST(ARCH_AND_PTX ...)
+# - "Auto" detects local machine GPU compute arch at runtime.
+# - "Common" and "All" cover common and entire subsets of architectures
+# 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 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:
+# CUDA_SELECT_NVCC_ARCH_FLAGS(ARCH_FLAGS 3.0 3.5+PTX 5.2(5.0) Maxwell)
+# LIST(APPEND CUDA_NVCC_FLAGS ${ARCH_FLAGS})
+#
+# More info on CUDA architectures: https://en.wikipedia.org/wiki/CUDA
+#
+
+if(CMAKE_CUDA_COMPILER_LOADED) # CUDA as a language
+ if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA"
+ AND CMAKE_CUDA_COMPILER_VERSION MATCHES "^([0-9]+\\.[0-9]+)")
+ set(CUDA_VERSION "${CMAKE_MATCH_1}")
+ endif()
+endif()
+
+# See: https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#gpu-feature-list
+# Additions, deprecations, and removals can be found in the release notes:
+# https://developer.nvidia.com/cuda-toolkit-archive
+
+# The initial status here is for CUDA 7.0
+set(CUDA_KNOWN_GPU_ARCHITECTURES "Fermi" "Kepler" "Maxwell" "Kepler+Tegra" "Kepler+Tesla" "Maxwell+Tegra")
+set(CUDA_COMMON_GPU_ARCHITECTURES "2.0" "2.1" "3.0" "3.5" "5.0" "5.3")
+set(CUDA_LIMIT_GPU_ARCHITECTURE "6.0")
+set(CUDA_ALL_GPU_ARCHITECTURES "2.0" "2.1" "3.0" "3.2" "3.5" "3.7" "5.0" "5.2" "5.3")
+set(_CUDA_MAX_COMMON_ARCHITECTURE "5.2+PTX")
+
+
+if(CUDA_VERSION VERSION_GREATER_EQUAL "8.0")
+ list(APPEND CUDA_KNOWN_GPU_ARCHITECTURES "Pascal")
+ list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "6.0" "6.1")
+ list(APPEND CUDA_ALL_GPU_ARCHITECTURES "6.0" "6.1" "6.2")
+
+ set(_CUDA_MAX_COMMON_ARCHITECTURE "6.2+PTX")
+ set(CUDA_LIMIT_GPU_ARCHITECTURE "7.0")
+
+ list(REMOVE_ITEM CUDA_COMMON_GPU_ARCHITECTURES "2.0" "2.1")
+endif ()
+
+if(CUDA_VERSION VERSION_GREATER_EQUAL "9.0")
+ list(APPEND CUDA_KNOWN_GPU_ARCHITECTURES "Volta")
+ list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "7.0")
+ list(APPEND CUDA_ALL_GPU_ARCHITECTURES "7.0" "7.2")
+
+ set(_CUDA_MAX_COMMON_ARCHITECTURE "7.2+PTX")
+ set(CUDA_LIMIT_GPU_ARCHITECTURE "8.0")
+
+ list(REMOVE_ITEM CUDA_KNOWN_GPU_ARCHITECTURES "Fermi")
+ list(REMOVE_ITEM CUDA_ALL_GPU_ARCHITECTURES "2.0" "2.1")
+endif()
+
+if(CUDA_VERSION VERSION_GREATER_EQUAL "10.0")
+ list(APPEND CUDA_KNOWN_GPU_ARCHITECTURES "Turing")
+ list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "7.5")
+ list(APPEND CUDA_ALL_GPU_ARCHITECTURES "7.5")
+
+ set(_CUDA_MAX_COMMON_ARCHITECTURE "7.5+PTX")
+ set(CUDA_LIMIT_GPU_ARCHITECTURE "8.0")
+
+ list(REMOVE_ITEM CUDA_COMMON_GPU_ARCHITECTURES "3.0")
+endif()
+
+# https://docs.nvidia.com/cuda/archive/11.0/cuda-toolkit-release-notes/index.html#cuda-general-new-features
+# https://docs.nvidia.com/cuda/archive/11.0/cuda-toolkit-release-notes/index.html#deprecated-features
+if(CUDA_VERSION VERSION_GREATER_EQUAL "11.0")
+ list(APPEND CUDA_KNOWN_GPU_ARCHITECTURES "Ampere")
+ list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "8.0")
+ list(APPEND CUDA_ALL_GPU_ARCHITECTURES "8.0")
+
+ set(_CUDA_MAX_COMMON_ARCHITECTURE "8.0+PTX")
+ set(CUDA_LIMIT_GPU_ARCHITECTURE "8.6")
+
+ list(REMOVE_ITEM CUDA_COMMON_GPU_ARCHITECTURES "3.5" "5.0")
+ list(REMOVE_ITEM CUDA_ALL_GPU_ARCHITECTURES "3.0" "3.2")
+endif()
+
+if(CUDA_VERSION VERSION_GREATER_EQUAL "11.1")
+ list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "8.6")
+ list(APPEND CUDA_ALL_GPU_ARCHITECTURES "8.6")
+
+ set(_CUDA_MAX_COMMON_ARCHITECTURE "8.6+PTX")
+ set(CUDA_LIMIT_GPU_ARCHITECTURE "9.0")
+endif()
+
+list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "${_CUDA_MAX_COMMON_ARCHITECTURE}")
+
+# Check with: cmake -DCUDA_VERSION=7.0 -P select_compute_arch.cmake
+if(DEFINED CMAKE_SCRIPT_MODE_FILE)
+ include(CMakePrintHelpers)
+ cmake_print_variables(CUDA_KNOWN_GPU_ARCHITECTURES)
+ cmake_print_variables(CUDA_COMMON_GPU_ARCHITECTURES)
+ cmake_print_variables(CUDA_LIMIT_GPU_ARCHITECTURE)
+ cmake_print_variables(CUDA_ALL_GPU_ARCHITECTURES)
+endif()
+
+
+################################################################################################
+# A function for automatic detection of GPUs installed (if autodetection is enabled)
+# Usage:
+# CUDA_DETECT_INSTALLED_GPUS(OUT_VARIABLE)
+#
+function(CUDA_DETECT_INSTALLED_GPUS OUT_VARIABLE)
+ if(NOT CUDA_GPU_DETECT_OUTPUT)
+ if(CMAKE_CUDA_COMPILER_LOADED) # CUDA as a language
+ set(file "${PROJECT_BINARY_DIR}/detect_cuda_compute_capabilities.cu")
+ else()
+ set(file "${PROJECT_BINARY_DIR}/detect_cuda_compute_capabilities.cpp")
+ endif()
+
+ file(WRITE ${file} ""
+ "#include <cuda_runtime.h>\n"
+ "#include <cstdio>\n"
+ "int main()\n"
+ "{\n"
+ " int count = 0;\n"
+ " if (cudaSuccess != cudaGetDeviceCount(&count)) return -1;\n"
+ " if (count == 0) return -1;\n"
+ " for (int device = 0; device < count; ++device)\n"
+ " {\n"
+ " cudaDeviceProp prop;\n"
+ " if (cudaSuccess == cudaGetDeviceProperties(&prop, device))\n"
+ " std::printf(\"%d.%d \", prop.major, prop.minor);\n"
+ " }\n"
+ " return 0;\n"
+ "}\n")
+
+ if(CMAKE_CUDA_COMPILER_LOADED) # CUDA as a language
+ try_run(run_result compile_result ${PROJECT_BINARY_DIR} ${file}
+ RUN_OUTPUT_VARIABLE compute_capabilities)
+ else()
+ try_run(run_result compile_result ${PROJECT_BINARY_DIR} ${file}
+ CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${CUDA_INCLUDE_DIRS}"
+ LINK_LIBRARIES ${CUDA_LIBRARIES}
+ RUN_OUTPUT_VARIABLE compute_capabilities)
+ endif()
+
+ # Filter unrelated content out of the output.
+ string(REGEX MATCHALL "[0-9]+\\.[0-9]+" compute_capabilities "${compute_capabilities}")
+
+ if(run_result EQUAL 0)
+ string(REPLACE "2.1" "2.1(2.0)" compute_capabilities "${compute_capabilities}")
+ set(CUDA_GPU_DETECT_OUTPUT ${compute_capabilities}
+ CACHE INTERNAL "Returned GPU architectures from detect_gpus tool" FORCE)
+ endif()
+ endif()
+
+ if(NOT CUDA_GPU_DETECT_OUTPUT)
+ message(STATUS "Automatic GPU detection failed. Building for common architectures.")
+ set(${OUT_VARIABLE} ${CUDA_COMMON_GPU_ARCHITECTURES} PARENT_SCOPE)
+ else()
+ # Filter based on CUDA version supported archs
+ set(CUDA_GPU_DETECT_OUTPUT_FILTERED "")
+ separate_arguments(CUDA_GPU_DETECT_OUTPUT)
+ foreach(ITEM IN ITEMS ${CUDA_GPU_DETECT_OUTPUT})
+ if(CUDA_LIMIT_GPU_ARCHITECTURE AND ITEM VERSION_GREATER_EQUAL CUDA_LIMIT_GPU_ARCHITECTURE)
+ list(GET CUDA_COMMON_GPU_ARCHITECTURES -1 NEWITEM)
+ string(APPEND CUDA_GPU_DETECT_OUTPUT_FILTERED " ${NEWITEM}")
+ else()
+ string(APPEND CUDA_GPU_DETECT_OUTPUT_FILTERED " ${ITEM}")
+ endif()
+ endforeach()
+
+ set(${OUT_VARIABLE} ${CUDA_GPU_DETECT_OUTPUT_FILTERED} PARENT_SCOPE)
+ endif()
+endfunction()
+
+
+################################################################################################
+# Function for selecting GPU arch flags for nvcc based on CUDA architectures from parameter list
+# Usage:
+# SELECT_NVCC_ARCH_FLAGS(out_variable [list of CUDA compute archs])
+function(CUDA_SELECT_NVCC_ARCH_FLAGS out_variable)
+ set(CUDA_ARCH_LIST "${ARGN}")
+
+ if("X${CUDA_ARCH_LIST}" STREQUAL "X" )
+ set(CUDA_ARCH_LIST "Auto")
+ endif()
+
+ set(cuda_arch_bin)
+ set(cuda_arch_ptx)
+
+ if("${CUDA_ARCH_LIST}" STREQUAL "All")
+ set(CUDA_ARCH_LIST ${CUDA_KNOWN_GPU_ARCHITECTURES})
+ elseif("${CUDA_ARCH_LIST}" STREQUAL "Common")
+ set(CUDA_ARCH_LIST ${CUDA_COMMON_GPU_ARCHITECTURES})
+ elseif("${CUDA_ARCH_LIST}" STREQUAL "Auto")
+ CUDA_DETECT_INSTALLED_GPUS(CUDA_ARCH_LIST)
+ message(STATUS "Autodetected CUDA architecture(s): ${CUDA_ARCH_LIST}")
+ endif()
+
+ # Now process the list and look for names
+ string(REGEX REPLACE "[ \t]+" ";" CUDA_ARCH_LIST "${CUDA_ARCH_LIST}")
+ list(REMOVE_DUPLICATES CUDA_ARCH_LIST)
+ foreach(arch_name ${CUDA_ARCH_LIST})
+ set(arch_bin)
+ set(arch_ptx)
+ set(add_ptx FALSE)
+ # Check to see if we are compiling PTX
+ if(arch_name MATCHES "(.*)\\+PTX$")
+ set(add_ptx TRUE)
+ set(arch_name ${CMAKE_MATCH_1})
+ endif()
+ if(arch_name MATCHES "^([0-9]\\.[0-9](\\([0-9]\\.[0-9]\\))?)$")
+ set(arch_bin ${CMAKE_MATCH_1})
+ set(arch_ptx ${arch_bin})
+ else()
+ # Look for it in our list of known architectures
+ if(${arch_name} STREQUAL "Fermi")
+ set(arch_bin 2.0 "2.1(2.0)")
+ elseif(${arch_name} STREQUAL "Kepler+Tegra")
+ set(arch_bin 3.2)
+ elseif(${arch_name} STREQUAL "Kepler+Tesla")
+ set(arch_bin 3.7)
+ elseif(${arch_name} STREQUAL "Kepler")
+ set(arch_bin 3.0 3.5)
+ set(arch_ptx 3.5)
+ elseif(${arch_name} STREQUAL "Maxwell+Tegra")
+ set(arch_bin 5.3)
+ elseif(${arch_name} STREQUAL "Maxwell")
+ set(arch_bin 5.0 5.2)
+ set(arch_ptx 5.2)
+ elseif(${arch_name} STREQUAL "Pascal")
+ set(arch_bin 6.0 6.1)
+ set(arch_ptx 6.1)
+ elseif(${arch_name} STREQUAL "Volta")
+ set(arch_bin 7.0 7.0)
+ set(arch_ptx 7.0)
+ elseif(${arch_name} STREQUAL "Turing")
+ set(arch_bin 7.5)
+ set(arch_ptx 7.5)
+ elseif(${arch_name} STREQUAL "Ampere")
+ set(arch_bin 8.0)
+ set(arch_ptx 8.0)
+ else()
+ message(SEND_ERROR "Unknown CUDA Architecture Name ${arch_name} in CUDA_SELECT_NVCC_ARCH_FLAGS")
+ endif()
+ endif()
+ if(NOT arch_bin)
+ message(SEND_ERROR "arch_bin wasn't set for some reason")
+ endif()
+ list(APPEND cuda_arch_bin ${arch_bin})
+ if(add_ptx)
+ if (NOT arch_ptx)
+ set(arch_ptx ${arch_bin})
+ endif()
+ list(APPEND cuda_arch_ptx ${arch_ptx})
+ endif()
+ endforeach()
+
+ # remove dots and convert to lists
+ string(REGEX REPLACE "\\." "" cuda_arch_bin "${cuda_arch_bin}")
+ string(REGEX REPLACE "\\." "" cuda_arch_ptx "${cuda_arch_ptx}")
+ string(REGEX MATCHALL "[0-9()]+" cuda_arch_bin "${cuda_arch_bin}")
+ string(REGEX MATCHALL "[0-9]+" cuda_arch_ptx "${cuda_arch_ptx}")
+
+ if(cuda_arch_bin)
+ list(REMOVE_DUPLICATES cuda_arch_bin)
+ endif()
+ if(cuda_arch_ptx)
+ list(REMOVE_DUPLICATES cuda_arch_ptx)
+ endif()
+
+ set(nvcc_flags "")
+ set(nvcc_archs_readable "")
+
+ # Tell NVCC to add binaries for the specified GPUs
+ foreach(arch ${cuda_arch_bin})
+ if(arch MATCHES "([0-9]+)\\(([0-9]+)\\)")
+ # User explicitly specified ARCH for the concrete CODE
+ list(APPEND nvcc_flags -gencode arch=compute_${CMAKE_MATCH_2},code=sm_${CMAKE_MATCH_1})
+ list(APPEND nvcc_archs_readable sm_${CMAKE_MATCH_1})
+ else()
+ # User didn't explicitly specify ARCH for the concrete CODE, we assume ARCH=CODE
+ list(APPEND nvcc_flags -gencode arch=compute_${arch},code=sm_${arch})
+ list(APPEND nvcc_archs_readable sm_${arch})
+ endif()
+ endforeach()
+
+ # Tell NVCC to add PTX intermediate code for the specified architectures
+ foreach(arch ${cuda_arch_ptx})
+ list(APPEND nvcc_flags -gencode arch=compute_${arch},code=compute_${arch})
+ list(APPEND nvcc_archs_readable compute_${arch})
+ endforeach()
+
+ string(REPLACE ";" " " nvcc_archs_readable "${nvcc_archs_readable}")
+ set(${out_variable} ${nvcc_flags} PARENT_SCOPE)
+ set(${out_variable}_readable ${nvcc_archs_readable} PARENT_SCOPE)
+endfunction()
diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake
new file mode 100644
index 0000000..de2b068
--- /dev/null
+++ b/Modules/FindCUDAToolkit.cmake
@@ -0,0 +1,949 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindCUDAToolkit
+---------------
+
+.. versionadded:: 3.17
+
+This script locates the NVIDIA CUDA toolkit and the associated libraries, but
+does not require the ``CUDA`` language be enabled for a given project. This
+module does not search for the NVIDIA CUDA Samples.
+
+.. versionadded:: 3.19
+ QNX support.
+
+Search Behavior
+^^^^^^^^^^^^^^^
+
+The CUDA Toolkit search behavior uses the following order:
+
+1. If the ``CUDA`` language has been enabled we will use the directory
+ containing the compiler as the first search location for ``nvcc``.
+
+2. If the ``CUDAToolkit_ROOT`` cmake configuration variable (e.g.,
+ ``-DCUDAToolkit_ROOT=/some/path``) *or* environment variable is defined, it
+ will be searched. If both an environment variable **and** a
+ configuration variable are specified, the *configuration* variable takes
+ precedence.
+
+ The directory specified here must be such that the executable ``nvcc`` or
+ the appropriate ``version.txt`` file can be found underneath the specified
+ directory.
+
+3. If the CUDA_PATH environment variable is defined, it will be searched
+ for ``nvcc``.
+
+4. The user's path is searched for ``nvcc`` using :command:`find_program`. If
+ this is found, no subsequent search attempts are performed. Users are
+ responsible for ensuring that the first ``nvcc`` to show up in the path is
+ the desired path in the event that multiple CUDA Toolkits are installed.
+
+5. On Unix systems, if the symbolic link ``/usr/local/cuda`` exists, this is
+ used. No subsequent search attempts are performed. No default symbolic link
+ location exists for the Windows platform.
+
+6. The platform specific default install locations are searched. If exactly one
+ candidate is found, this is used. The default CUDA Toolkit install locations
+ searched are:
+
+ +-------------+-------------------------------------------------------------+
+ | Platform | Search Pattern |
+ +=============+=============================================================+
+ | macOS | ``/Developer/NVIDIA/CUDA-X.Y`` |
+ +-------------+-------------------------------------------------------------+
+ | Other Unix | ``/usr/local/cuda-X.Y`` |
+ +-------------+-------------------------------------------------------------+
+ | Windows | ``C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vX.Y`` |
+ +-------------+-------------------------------------------------------------+
+
+ Where ``X.Y`` would be a specific version of the CUDA Toolkit, such as
+ ``/usr/local/cuda-9.0`` or
+ ``C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0``
+
+ .. note::
+
+ When multiple CUDA Toolkits are installed in the default location of a
+ system (e.g., both ``/usr/local/cuda-9.0`` and ``/usr/local/cuda-10.0``
+ exist but the ``/usr/local/cuda`` symbolic link does **not** exist), this
+ package is marked as **not** found.
+
+ There are too many factors involved in making an automatic decision in
+ the presence of multiple CUDA Toolkits being installed. In this
+ situation, users are encouraged to either (1) set ``CUDAToolkit_ROOT`` or
+ (2) ensure that the correct ``nvcc`` executable shows up in ``$PATH`` for
+ :command:`find_program` to find.
+
+Options
+^^^^^^^
+
+``VERSION``
+ If specified, describes the version of the CUDA Toolkit to search for.
+
+``REQUIRED``
+ If specified, configuration will error if a suitable CUDA Toolkit is not
+ found.
+
+``QUIET``
+ If specified, the search for a suitable CUDA Toolkit will not produce any
+ messages.
+
+``EXACT``
+ If specified, the CUDA Toolkit is considered found only if the exact
+ ``VERSION`` specified is recovered.
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+An :ref:`imported target <Imported targets>` named ``CUDA::toolkit`` is provided.
+
+This module defines :prop_tgt:`IMPORTED` targets for each
+of the following libraries that are part of the CUDAToolkit:
+
+- :ref:`CUDA Runtime Library<cuda_toolkit_rt_lib>`
+- :ref:`CUDA Driver Library<cuda_toolkit_driver_lib>`
+- :ref:`cuBLAS<cuda_toolkit_cuBLAS>`
+- :ref:`cuFFT<cuda_toolkit_cuFFT>`
+- :ref:`cuRAND<cuda_toolkit_cuRAND>`
+- :ref:`cuSOLVER<cuda_toolkit_cuSOLVER>`
+- :ref:`cuSPARSE<cuda_toolkit_cuSPARSE>`
+- :ref:`cuPTI<cuda_toolkit_cupti>`
+- :ref:`NPP<cuda_toolkit_NPP>`
+- :ref:`nvBLAS<cuda_toolkit_nvBLAS>`
+- :ref:`nvGRAPH<cuda_toolkit_nvGRAPH>`
+- :ref:`nvJPEG<cuda_toolkit_nvJPEG>`
+- :ref:`nvidia-ML<cuda_toolkit_nvML>`
+- :ref:`nvRTC<cuda_toolkit_nvRTC>`
+- :ref:`nvToolsExt<cuda_toolkit_nvToolsExt>`
+- :ref:`OpenCL<cuda_toolkit_opencl>`
+- :ref:`cuLIBOS<cuda_toolkit_cuLIBOS>`
+
+.. _`cuda_toolkit_rt_lib`:
+
+CUDA Runtime Library
+""""""""""""""""""""
+
+The CUDA Runtime library (cudart) are what most applications will typically
+need to link against to make any calls such as `cudaMalloc`, and `cudaFree`.
+
+Targets Created:
+
+- ``CUDA::cudart``
+- ``CUDA::cudart_static``
+
+.. _`cuda_toolkit_driver_lib`:
+
+CUDA Driver Library
+""""""""""""""""""""
+
+The CUDA Driver library (cuda) are used by applications that use calls
+such as `cuMemAlloc`, and `cuMemFree`. This is generally used by advanced
+
+
+Targets Created:
+
+- ``CUDA::cuda_driver``
+- ``CUDA::cuda_driver``
+
+.. _`cuda_toolkit_cuBLAS`:
+
+cuBLAS
+""""""
+
+The `cuBLAS <https://docs.nvidia.com/cuda/cublas/index.html>`_ library.
+
+Targets Created:
+
+- ``CUDA::cublas``
+- ``CUDA::cublas_static``
+- ``CUDA::cublasLt`` starting in CUDA 10.1
+- ``CUDA::cublasLt_static`` starting in CUDA 10.1
+
+.. _`cuda_toolkit_cuFFT`:
+
+cuFFT
+"""""
+
+The `cuFFT <https://docs.nvidia.com/cuda/cufft/index.html>`_ library.
+
+Targets Created:
+
+- ``CUDA::cufft``
+- ``CUDA::cufftw``
+- ``CUDA::cufft_static``
+- ``CUDA::cufftw_static``
+
+cuRAND
+""""""
+
+The `cuRAND <https://docs.nvidia.com/cuda/curand/index.html>`_ library.
+
+Targets Created:
+
+- ``CUDA::curand``
+- ``CUDA::curand_static``
+
+.. _`cuda_toolkit_cuSOLVER`:
+
+cuSOLVER
+""""""""
+
+The `cuSOLVER <https://docs.nvidia.com/cuda/cusolver/index.html>`_ library.
+
+Targets Created:
+
+- ``CUDA::cusolver``
+- ``CUDA::cusolver_static``
+
+.. _`cuda_toolkit_cuSPARSE`:
+
+cuSPARSE
+""""""""
+
+The `cuSPARSE <https://docs.nvidia.com/cuda/cusparse/index.html>`_ library.
+
+Targets Created:
+
+- ``CUDA::cusparse``
+- ``CUDA::cusparse_static``
+
+.. _`cuda_toolkit_cupti`:
+
+cupti
+"""""
+
+The `NVIDIA CUDA Profiling Tools Interface <https://developer.nvidia.com/CUPTI>`_.
+
+Targets Created:
+
+- ``CUDA::cupti``
+- ``CUDA::cupti_static``
+
+.. _`cuda_toolkit_NPP`:
+
+NPP
+"""
+
+The `NPP <https://docs.nvidia.com/cuda/npp/index.html>`_ libraries.
+
+Targets Created:
+
+- `nppc`:
+
+ - ``CUDA::nppc``
+ - ``CUDA::nppc_static``
+
+- `nppial`: Arithmetic and logical operation functions in `nppi_arithmetic_and_logical_operations.h`
+
+ - ``CUDA::nppial``
+ - ``CUDA::nppial_static``
+
+- `nppicc`: Color conversion and sampling functions in `nppi_color_conversion.h`
+
+ - ``CUDA::nppicc``
+ - ``CUDA::nppicc_static``
+
+- `nppicom`: JPEG compression and decompression functions in `nppi_compression_functions.h`
+ Removed starting in CUDA 11.0, use :ref:`nvJPEG<cuda_toolkit_nvJPEG>` instead.
+
+ - ``CUDA::nppicom``
+ - ``CUDA::nppicom_static``
+
+- `nppidei`: Data exchange and initialization functions in `nppi_data_exchange_and_initialization.h`
+
+ - ``CUDA::nppidei``
+ - ``CUDA::nppidei_static``
+
+- `nppif`: Filtering and computer vision functions in `nppi_filter_functions.h`
+
+ - ``CUDA::nppif``
+ - ``CUDA::nppif_static``
+
+- `nppig`: Geometry transformation functions found in `nppi_geometry_transforms.h`
+
+ - ``CUDA::nppig``
+ - ``CUDA::nppig_static``
+
+- `nppim`: Morphological operation functions found in `nppi_morphological_operations.h`
+
+ - ``CUDA::nppim``
+ - ``CUDA::nppim_static``
+
+- `nppist`: Statistics and linear transform in `nppi_statistics_functions.h` and `nppi_linear_transforms.h`
+
+ - ``CUDA::nppist``
+ - ``CUDA::nppist_static``
+
+- `nppisu`: Memory support functions in `nppi_support_functions.h`
+
+ - ``CUDA::nppisu``
+ - ``CUDA::nppisu_static``
+
+- `nppitc`: Threshold and compare operation functions in `nppi_threshold_and_compare_operations.h`
+
+ - ``CUDA::nppitc``
+ - ``CUDA::nppitc_static``
+
+- `npps`:
+
+ - ``CUDA::npps``
+ - ``CUDA::npps_static``
+
+.. _`cuda_toolkit_nvBLAS`:
+
+nvBLAS
+""""""
+
+The `nvBLAS <https://docs.nvidia.com/cuda/nvblas/index.html>`_ libraries.
+This is a shared library only.
+
+Targets Created:
+
+- ``CUDA::nvblas``
+
+.. _`cuda_toolkit_nvGRAPH`:
+
+nvGRAPH
+"""""""
+
+The `nvGRAPH <https://docs.nvidia.com/cuda/nvgraph/index.html>`_ library.
+Removed starting in CUDA 11.0
+
+Targets Created:
+
+- ``CUDA::nvgraph``
+- ``CUDA::nvgraph_static``
+
+
+.. _`cuda_toolkit_nvJPEG`:
+
+nvJPEG
+""""""
+
+The `nvJPEG <https://docs.nvidia.com/cuda/nvjpeg/index.html>`_ library.
+Introduced in CUDA 10.
+
+Targets Created:
+
+- ``CUDA::nvjpeg``
+- ``CUDA::nvjpeg_static``
+
+.. _`cuda_toolkit_nvRTC`:
+
+nvRTC
+"""""
+
+The `nvRTC <https://docs.nvidia.com/cuda/nvrtc/index.html>`_ (Runtime Compilation) library.
+This is a shared library only.
+
+Targets Created:
+
+- ``CUDA::nvrtc``
+
+.. _`cuda_toolkit_nvml`:
+
+nvidia-ML
+"""""""""
+
+The `NVIDIA Management Library <https://developer.nvidia.com/nvidia-management-library-nvml>`_.
+This is a shared library only.
+
+Targets Created:
+
+- ``CUDA::nvml``
+
+.. _`cuda_toolkit_nvToolsExt`:
+
+nvToolsExt
+""""""""""
+
+The `NVIDIA Tools Extension <https://docs.nvidia.com/gameworks/content/gameworkslibrary/nvtx/nvidia_tools_extension_library_nvtx.htm>`_.
+This is a shared library only.
+
+Targets Created:
+
+- ``CUDA::nvToolsExt``
+
+.. _`cuda_toolkit_opencl`:
+
+OpenCL
+""""""
+
+The `NVIDIA OpenCL Library <https://developer.nvidia.com/opencl>`_.
+This is a shared library only.
+
+Targets Created:
+
+- ``CUDA::OpenCL``
+
+.. _`cuda_toolkit_cuLIBOS`:
+
+cuLIBOS
+"""""""
+
+The cuLIBOS library is a backend thread abstraction layer library which is
+static only. The ``CUDA::cublas_static``, ``CUDA::cusparse_static``,
+``CUDA::cufft_static``, ``CUDA::curand_static``, and (when implemented) NPP
+libraries all automatically have this dependency linked.
+
+Target Created:
+
+- ``CUDA::culibos``
+
+**Note**: direct usage of this target by consumers should not be necessary.
+
+.. _`cuda_toolkit_cuRAND`:
+
+
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+``CUDAToolkit_FOUND``
+ A boolean specifying whether or not the CUDA Toolkit was found.
+
+``CUDAToolkit_VERSION``
+ The exact version of the CUDA Toolkit found (as reported by
+ ``nvcc --version`` or ``version.txt``).
+
+``CUDAToolkit_VERSION_MAJOR``
+ The major version of the CUDA Toolkit.
+
+``CUDAToolkit_VERSION_MAJOR``
+ The minor version of the CUDA Toolkit.
+
+``CUDAToolkit_VERSION_PATCH``
+ The patch version of the CUDA Toolkit.
+
+``CUDAToolkit_BIN_DIR``
+ The path to the CUDA Toolkit library directory that contains the CUDA
+ executable ``nvcc``.
+
+``CUDAToolkit_INCLUDE_DIRS``
+ The path to the CUDA Toolkit ``include`` folder containing the header files
+ required to compile a project linking against CUDA.
+
+``CUDAToolkit_LIBRARY_DIR``
+ The path to the CUDA Toolkit library directory that contains the CUDA
+ Runtime library ``cudart``.
+
+``CUDAToolkit_LIBRARY_ROOT``
+ .. versionadded:: 3.18
+
+ The path to the CUDA Toolkit directory containing the nvvm directory and
+ version.txt.
+
+``CUDAToolkit_TARGET_DIR``
+ The path to the CUDA Toolkit directory including the target architecture
+ when cross-compiling. When not cross-compiling this will be equivalent to
+ the parent directory of ``CUDAToolkit_BIN_DIR``.
+
+``CUDAToolkit_NVCC_EXECUTABLE``
+ The path to the NVIDIA CUDA compiler ``nvcc``. Note that this path may
+ **not** be the same as
+ :variable:`CMAKE_CUDA_COMPILER <CMAKE_<LANG>_COMPILER>`. ``nvcc`` must be
+ found to determine the CUDA Toolkit version as well as determining other
+ features of the Toolkit. This variable is set for the convenience of
+ modules that depend on this one.
+
+
+#]=======================================================================]
+
+# NOTE: much of this was simply extracted from FindCUDA.cmake.
+
+# James Bigler, NVIDIA Corp (nvidia.com - jbigler)
+# Abe Stephens, SCI Institute -- http://www.sci.utah.edu/~abe/FindCuda.html
+#
+# Copyright (c) 2008 - 2009 NVIDIA Corporation. All rights reserved.
+#
+# Copyright (c) 2007-2009
+# Scientific Computing and Imaging Institute, University of Utah
+#
+# This code is licensed under the MIT License. See the FindCUDA.cmake script
+# for the text of the license.
+
+# The MIT License
+#
+# License for the specific language governing rights and limitations under
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+###############################################################################
+
+# The toolkit is located during compiler detection for CUDA and stored in CMakeCUDACompiler.cmake as
+# CMAKE_CUDA_COMPILER_TOOLKIT_ROOT and CMAKE_CUDA_COMPILER_LIBRARY_ROOT.
+# We compute the rest based on those here to avoid re-searching and to avoid finding a possibly
+# different installation.
+if(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT)
+ set(CUDAToolkit_ROOT_DIR "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}")
+ set(CUDAToolkit_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_LIBRARY_ROOT}")
+ set(CUDAToolkit_BIN_DIR "${CUDAToolkit_ROOT_DIR}/bin")
+ set(CUDAToolkit_NVCC_EXECUTABLE "${CUDAToolkit_BIN_DIR}/nvcc${CMAKE_EXECUTABLE_SUFFIX}")
+else()
+
+ function(_CUDAToolkit_find_root_dir )
+ cmake_parse_arguments(arg "" "" "SEARCH_PATHS;FIND_FLAGS" ${ARGN})
+
+
+ if(NOT CUDAToolkit_BIN_DIR)
+ if(NOT CUDAToolkit_SENTINEL_FILE)
+ find_program(CUDAToolkit_NVCC_EXECUTABLE
+ NAMES nvcc nvcc.exe
+ PATHS ${arg_SEARCH_PATHS}
+ ${arg_FIND_FLAGS}
+ )
+ endif()
+
+ if(NOT CUDAToolkit_NVCC_EXECUTABLE)
+ find_file(CUDAToolkit_SENTINEL_FILE
+ NAMES version.txt
+ PATHS ${arg_SEARCH_PATHS}
+ NO_DEFAULT_PATH
+ )
+ endif()
+
+ if(EXISTS "${CUDAToolkit_NVCC_EXECUTABLE}")
+ # If NVCC exists then invoke it to find the toolkit location.
+ # This allows us to support wrapper scripts (e.g. ccache or colornvcc), CUDA Toolkit,
+ # NVIDIA HPC SDK, and distro's splayed layouts
+ execute_process(COMMAND ${CUDAToolkit_NVCC_EXECUTABLE} "-v" "__cmake_determine_cuda"
+ OUTPUT_VARIABLE _CUDA_NVCC_OUT ERROR_VARIABLE _CUDA_NVCC_OUT)
+ if(_CUDA_NVCC_OUT MATCHES "TOP=([^\r\n]*)")
+ get_filename_component(CUDAToolkit_BIN_DIR "${CMAKE_MATCH_1}/bin" ABSOLUTE)
+ else()
+ get_filename_component(CUDAToolkit_BIN_DIR "${CUDAToolkit_NVCC_EXECUTABLE}" DIRECTORY)
+ endif()
+ unset(_CUDA_NVCC_OUT)
+
+ mark_as_advanced(CUDAToolkit_BIN_DIR)
+ set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "" FORCE)
+ endif()
+
+ if(CUDAToolkit_SENTINEL_FILE)
+ get_filename_component(CUDAToolkit_BIN_DIR ${CUDAToolkit_SENTINEL_FILE} DIRECTORY ABSOLUTE)
+ set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}/bin")
+
+ set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "" FORCE)
+ mark_as_advanced(CUDAToolkit_BIN_DIR)
+ endif()
+ endif()
+
+ if(CUDAToolkit_BIN_DIR)
+ get_filename_component(CUDAToolkit_ROOT_DIR ${CUDAToolkit_BIN_DIR} DIRECTORY ABSOLUTE)
+ set(CUDAToolkit_ROOT_DIR "${CUDAToolkit_ROOT_DIR}" PARENT_SCOPE)
+ endif()
+
+ endfunction()
+
+ function(_CUDAToolkit_find_version_file result_variable)
+ # We first check for a non-scattered installation to prefer it over a scattered installation.
+ if(CUDAToolkit_ROOT AND EXISTS "${CUDAToolkit_ROOT}/version.txt")
+ set(${result_variable} "${CUDAToolkit_ROOT}/version.txt" PARENT_SCOPE)
+ elseif(CUDAToolkit_ROOT_DIR AND EXISTS "${CUDAToolkit_ROOT_DIR}/version.txt")
+ set(${result_variable} "${CUDAToolkit_ROOT_DIR}/version.txt" PARENT_SCOPE)
+ elseif(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/cuda/version.txt")
+ set(${result_variable} "${CMAKE_SYSROOT_LINK}/usr/lib/cuda/version.txt" PARENT_SCOPE)
+ elseif(EXISTS "${CMAKE_SYSROOT}/usr/lib/cuda/version.txt")
+ set(${result_variable} "${CMAKE_SYSROOT}/usr/lib/cuda/version.txt" PARENT_SCOPE)
+ endif()
+ endfunction()
+
+ # For NVCC we can easily deduce the SDK binary directory from the compiler path.
+ if(CMAKE_CUDA_COMPILER_LOADED AND NOT CUDAToolkit_BIN_DIR AND CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
+ get_filename_component(CUDAToolkit_BIN_DIR "${CMAKE_CUDA_COMPILER}" DIRECTORY)
+ set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "")
+ # Try language provided path first.
+ _CUDAToolkit_find_root_dir(SEARCH_PATHS "${CUDAToolkit_BIN_DIR}" FIND_FLAGS NO_DEFAULT_PATH)
+ mark_as_advanced(CUDAToolkit_BIN_DIR)
+ endif()
+
+ # Try user provided path
+ if(NOT CUDAToolkit_ROOT_DIR AND CUDAToolkit_ROOT)
+ _CUDAToolkit_find_root_dir(SEARCH_PATHS "${CUDAToolkit_ROOT}" FIND_FLAGS PATH_SUFFIXES bin NO_DEFAULT_PATH)
+ endif()
+ if(NOT CUDAToolkit_ROOT_DIR)
+ _CUDAToolkit_find_root_dir(FIND_FLAGS PATHS ENV CUDA_PATH PATH_SUFFIXES bin)
+ endif()
+
+ # If the user specified CUDAToolkit_ROOT but the toolkit could not be found, this is an error.
+ if(NOT CUDAToolkit_ROOT_DIR AND (DEFINED CUDAToolkit_ROOT OR DEFINED ENV{CUDAToolkit_ROOT}))
+ # Declare error messages now, print later depending on find_package args.
+ set(fail_base "Could not find nvcc executable in path specified by")
+ set(cuda_root_fail "${fail_base} CUDAToolkit_ROOT=${CUDAToolkit_ROOT}")
+ set(env_cuda_root_fail "${fail_base} environment variable CUDAToolkit_ROOT=$ENV{CUDAToolkit_ROOT}")
+
+ if(CUDAToolkit_FIND_REQUIRED)
+ if(DEFINED CUDAToolkit_ROOT)
+ message(FATAL_ERROR ${cuda_root_fail})
+ elseif(DEFINED ENV{CUDAToolkit_ROOT})
+ message(FATAL_ERROR ${env_cuda_root_fail})
+ endif()
+ else()
+ if(NOT CUDAToolkit_FIND_QUIETLY)
+ if(DEFINED CUDAToolkit_ROOT)
+ message(STATUS ${cuda_root_fail})
+ elseif(DEFINED ENV{CUDAToolkit_ROOT})
+ message(STATUS ${env_cuda_root_fail})
+ endif()
+ endif()
+ set(CUDAToolkit_FOUND FALSE)
+ unset(fail_base)
+ unset(cuda_root_fail)
+ unset(env_cuda_root_fail)
+ return()
+ endif()
+ endif()
+
+ # CUDAToolkit_ROOT cmake / env variable not specified, try platform defaults.
+ #
+ # - Linux: /usr/local/cuda-X.Y
+ # - macOS: /Developer/NVIDIA/CUDA-X.Y
+ # - Windows: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vX.Y
+ #
+ # We will also search the default symlink location /usr/local/cuda first since
+ # if CUDAToolkit_ROOT is not specified, it is assumed that the symlinked
+ # directory is the desired location.
+ if(NOT CUDAToolkit_ROOT_DIR)
+ if(UNIX)
+ if(NOT APPLE)
+ set(platform_base "/usr/local/cuda-")
+ else()
+ set(platform_base "/Developer/NVIDIA/CUDA-")
+ endif()
+ else()
+ set(platform_base "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v")
+ endif()
+
+ # Build out a descending list of possible cuda installations, e.g.
+ file(GLOB possible_paths "${platform_base}*")
+ # Iterate the glob results and create a descending list.
+ set(versions)
+ foreach(p ${possible_paths})
+ # Extract version number from end of string
+ string(REGEX MATCH "[0-9][0-9]?\\.[0-9]$" p_version ${p})
+ if(IS_DIRECTORY ${p} AND p_version)
+ list(APPEND versions ${p_version})
+ endif()
+ endforeach()
+
+ # Sort numerically in descending order, so we try the newest versions first.
+ list(SORT versions COMPARE NATURAL ORDER DESCENDING)
+
+ # With a descending list of versions, populate possible paths to search.
+ set(search_paths)
+ foreach(v ${versions})
+ list(APPEND search_paths "${platform_base}${v}")
+ endforeach()
+
+ # Force the global default /usr/local/cuda to the front on Unix.
+ if(UNIX)
+ list(INSERT search_paths 0 "/usr/local/cuda")
+ endif()
+
+ # Now search for the toolkit again using the platform default search paths.
+ _CUDAToolkit_find_root_dir(SEARCH_PATHS "${search_paths}" FIND_FLAGS PATH_SUFFIXES bin)
+
+ # We are done with these variables now, cleanup for caller.
+ unset(platform_base)
+ unset(possible_paths)
+ unset(versions)
+ unset(search_paths)
+
+ if(NOT CUDAToolkit_ROOT_DIR)
+ if(CUDAToolkit_FIND_REQUIRED)
+ message(FATAL_ERROR "Could not find nvcc, please set CUDAToolkit_ROOT.")
+ elseif(NOT CUDAToolkit_FIND_QUIETLY)
+ message(STATUS "Could not find nvcc, please set CUDAToolkit_ROOT.")
+ endif()
+
+ set(CUDAToolkit_FOUND FALSE)
+ return()
+ endif()
+ endif()
+
+ _CUDAToolkit_find_version_file( _CUDAToolkit_version_file )
+ if(_CUDAToolkit_version_file)
+ # CUDAToolkit_LIBRARY_ROOT contains the device library and version file.
+ get_filename_component(CUDAToolkit_LIBRARY_ROOT "${_CUDAToolkit_version_file}" DIRECTORY ABSOLUTE)
+ endif()
+ unset(_CUDAToolkit_version_file)
+endif()
+
+# Find target directory when crosscompiling.
+if(CMAKE_CROSSCOMPILING)
+ if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7-a")
+ # Support for NVPACK
+ set(CUDAToolkit_TARGET_NAME "armv7-linux-androideabi")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
+ set(CUDAToolkit_TARGET_NAME "armv7-linux-gnueabihf")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
+ if(ANDROID_ARCH_NAME STREQUAL "arm64")
+ set(CUDAToolkit_TARGET_NAME "aarch64-linux-androideabi")
+ elseif (CMAKE_SYSTEM_NAME STREQUAL "QNX")
+ set(CUDAToolkit_TARGET_NAME "aarch64-qnx")
+ else()
+ set(CUDAToolkit_TARGET_NAME "aarch64-linux")
+ endif(ANDROID_ARCH_NAME STREQUAL "arm64")
+ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
+ set(CUDAToolkit_TARGET_NAME "x86_64-linux")
+ endif()
+
+ if(EXISTS "${CUDAToolkit_ROOT_DIR}/targets/${CUDAToolkit_TARGET_NAME}")
+ set(CUDAToolkit_TARGET_DIR "${CUDAToolkit_ROOT_DIR}/targets/${CUDAToolkit_TARGET_NAME}")
+ # add known CUDA target root path to the set of directories we search for programs, libraries and headers
+ list(PREPEND CMAKE_FIND_ROOT_PATH "${CUDAToolkit_TARGET_DIR}")
+
+ # Mark that we need to pop the root search path changes after we have
+ # found all cuda libraries so that searches for our cross-compilation
+ # libraries work when another cuda sdk is in CMAKE_PREFIX_PATH or
+ # PATh
+ set(_CUDAToolkit_Pop_ROOT_PATH True)
+ endif()
+endif()
+
+# If not already set we can simply use the toolkit root or it's a scattered installation.
+if(NOT CUDAToolkit_TARGET_DIR)
+ # Not cross compiling
+ set(CUDAToolkit_TARGET_DIR "${CUDAToolkit_ROOT_DIR}")
+ # Now that we have the real ROOT_DIR, find components inside it.
+ list(APPEND CMAKE_PREFIX_PATH ${CUDAToolkit_ROOT_DIR})
+
+ # Mark that we need to pop the prefix path changes after we have
+ # found the cudart library.
+ set(_CUDAToolkit_Pop_Prefix True)
+endif()
+
+# CUDAToolkit_TARGET_DIR always points to the directory containing the include directory.
+# On a scattered installation /usr, on a non-scattered something like /usr/local/cuda or /usr/local/cuda-10.2/targets/aarch64-linux.
+if(EXISTS "${CUDAToolkit_TARGET_DIR}/include/cuda_runtime.h")
+ set(CUDAToolkit_INCLUDE_DIR "${CUDAToolkit_TARGET_DIR}/include")
+elseif(NOT CUDAToolkit_FIND_QUIETLY)
+ message(STATUS "Unable to find cuda_runtime.h in \"${CUDAToolkit_TARGET_DIR}/include\" for CUDAToolkit_INCLUDE_DIR.")
+endif()
+
+if(CUDAToolkit_NVCC_EXECUTABLE AND
+ CMAKE_CUDA_COMPILER_VERSION AND
+ CUDAToolkit_NVCC_EXECUTABLE STREQUAL CMAKE_CUDA_COMPILER)
+ # Need to set these based off the already computed CMAKE_CUDA_COMPILER_VERSION value
+ # This if statement will always match, but is used to provide variables for MATCH 1,2,3...
+ if(CMAKE_CUDA_COMPILER_VERSION MATCHES [=[([0-9]+)\.([0-9]+)\.([0-9]+)]=])
+ set(CUDAToolkit_VERSION_MAJOR "${CMAKE_MATCH_1}")
+ set(CUDAToolkit_VERSION_MINOR "${CMAKE_MATCH_2}")
+ set(CUDAToolkit_VERSION_PATCH "${CMAKE_MATCH_3}")
+ set(CUDAToolkit_VERSION "${CMAKE_CUDA_COMPILER_VERSION}")
+ endif()
+elseif(CUDAToolkit_NVCC_EXECUTABLE)
+ # Compute the version by invoking nvcc
+ execute_process(COMMAND ${CUDAToolkit_NVCC_EXECUTABLE} "--version" OUTPUT_VARIABLE NVCC_OUT)
+ if(NVCC_OUT MATCHES [=[ V([0-9]+)\.([0-9]+)\.([0-9]+)]=])
+ set(CUDAToolkit_VERSION_MAJOR "${CMAKE_MATCH_1}")
+ set(CUDAToolkit_VERSION_MINOR "${CMAKE_MATCH_2}")
+ set(CUDAToolkit_VERSION_PATCH "${CMAKE_MATCH_3}")
+ set(CUDAToolkit_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
+ endif()
+ unset(NVCC_OUT)
+else()
+ _CUDAToolkit_find_version_file(version_file)
+ if(version_file)
+ file(READ "${version_file}" VERSION_INFO)
+ if(VERSION_INFO MATCHES [=[CUDA Version ([0-9]+)\.([0-9]+)\.([0-9]+)]=])
+ set(CUDAToolkit_VERSION_MAJOR "${CMAKE_MATCH_1}")
+ set(CUDAToolkit_VERSION_MINOR "${CMAKE_MATCH_2}")
+ set(CUDAToolkit_VERSION_PATCH "${CMAKE_MATCH_3}")
+ set(CUDAToolkit_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
+ endif()
+ endif()
+endif()
+
+# Find the CUDA Runtime Library libcudart
+find_library(CUDA_CUDART
+ NAMES cudart
+ PATH_SUFFIXES lib64 lib/x64
+)
+find_library(CUDA_CUDART
+ NAMES cudart
+ PATH_SUFFIXES lib64/stubs lib/x64/stubs
+)
+
+if(NOT CUDA_CUDART AND NOT CUDAToolkit_FIND_QUIETLY)
+ message(STATUS "Unable to find cudart library.")
+endif()
+
+if(_CUDAToolkit_Pop_Prefix)
+ list(REMOVE_AT CMAKE_PREFIX_PATH -1)
+ unset(_CUDAToolkit_Pop_Prefix)
+endif()
+
+#-----------------------------------------------------------------------------
+# Perform version comparison and validate all required variables are set.
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(CUDAToolkit
+ REQUIRED_VARS
+ CUDAToolkit_INCLUDE_DIR
+ CUDA_CUDART
+ CUDAToolkit_BIN_DIR
+ VERSION_VAR
+ CUDAToolkit_VERSION
+)
+
+unset(CUDAToolkit_ROOT_DIR)
+mark_as_advanced(CUDA_CUDART
+ CUDAToolkit_INCLUDE_DIR
+ CUDAToolkit_NVCC_EXECUTABLE
+ CUDAToolkit_SENTINEL_FILE
+ )
+
+#-----------------------------------------------------------------------------
+# Construct result variables
+if(CUDAToolkit_FOUND)
+ set(CUDAToolkit_INCLUDE_DIRS ${CUDAToolkit_INCLUDE_DIR})
+ get_filename_component(CUDAToolkit_LIBRARY_DIR ${CUDA_CUDART} DIRECTORY ABSOLUTE)
+endif()
+
+#-----------------------------------------------------------------------------
+# Construct import targets
+if(CUDAToolkit_FOUND)
+
+ function(_CUDAToolkit_find_and_add_import_lib lib_name)
+ cmake_parse_arguments(arg "" "" "ALT;DEPS;EXTRA_PATH_SUFFIXES" ${ARGN})
+
+ set(search_names ${lib_name} ${arg_ALT})
+
+ find_library(CUDA_${lib_name}_LIBRARY
+ NAMES ${search_names}
+ HINTS ${CUDAToolkit_LIBRARY_DIR}
+ ENV CUDA_PATH
+ PATH_SUFFIXES nvidia/current lib64 lib/x64 lib
+ ${arg_EXTRA_PATH_SUFFIXES}
+ )
+ # Don't try any stub directories until we have exhausted all other
+ # search locations.
+ find_library(CUDA_${lib_name}_LIBRARY
+ NAMES ${search_names}
+ HINTS ${CUDAToolkit_LIBRARY_DIR}
+ ENV CUDA_PATH
+ PATH_SUFFIXES lib64/stubs lib/x64/stubs lib/stubs stubs
+ )
+
+ mark_as_advanced(CUDA_${lib_name}_LIBRARY)
+
+ if (NOT TARGET CUDA::${lib_name} AND CUDA_${lib_name}_LIBRARY)
+ add_library(CUDA::${lib_name} IMPORTED INTERFACE)
+ target_include_directories(CUDA::${lib_name} SYSTEM INTERFACE "${CUDAToolkit_INCLUDE_DIRS}")
+ target_link_libraries(CUDA::${lib_name} INTERFACE "${CUDA_${lib_name}_LIBRARY}")
+ foreach(dep ${arg_DEPS})
+ if(TARGET CUDA::${dep})
+ target_link_libraries(CUDA::${lib_name} INTERFACE CUDA::${dep})
+ endif()
+ endforeach()
+ endif()
+ endfunction()
+
+ if(NOT TARGET CUDA::toolkit)
+ add_library(CUDA::toolkit IMPORTED INTERFACE)
+ target_include_directories(CUDA::toolkit SYSTEM INTERFACE "${CUDAToolkit_INCLUDE_DIRS}")
+ target_link_directories(CUDA::toolkit INTERFACE "${CUDAToolkit_LIBRARY_DIR}")
+ endif()
+
+ _CUDAToolkit_find_and_add_import_lib(cuda_driver ALT cuda)
+
+ _CUDAToolkit_find_and_add_import_lib(cudart)
+ _CUDAToolkit_find_and_add_import_lib(cudart_static)
+
+ # setup dependencies that are required for cudart_static when building
+ # on linux. These are generally only required when using the CUDA toolkit
+ # when CUDA language is disabled
+ if(NOT TARGET CUDA::cudart_static_deps
+ AND TARGET CUDA::cudart_static)
+
+ add_library(CUDA::cudart_static_deps IMPORTED INTERFACE)
+ target_link_libraries(CUDA::cudart_static INTERFACE CUDA::cudart_static_deps)
+
+ if(UNIX AND (CMAKE_C_COMPILER OR CMAKE_CXX_COMPILER))
+ find_package(Threads REQUIRED)
+ target_link_libraries(CUDA::cudart_static_deps INTERFACE Threads::Threads ${CMAKE_DL_LIBS})
+ endif()
+
+ if(UNIX AND NOT APPLE AND NOT (CMAKE_SYSTEM_NAME STREQUAL "QNX"))
+ # On Linux, you must link against librt when using the static cuda runtime.
+ find_library(CUDAToolkit_rt_LIBRARY rt)
+ mark_as_advanced(CUDAToolkit_rt_LIBRARY)
+ if(NOT CUDAToolkit_rt_LIBRARY)
+ message(WARNING "Could not find librt library, needed by CUDA::cudart_static")
+ else()
+ target_link_libraries(CUDA::cudart_static_deps INTERFACE ${CUDAToolkit_rt_LIBRARY})
+ endif()
+ endif()
+ endif()
+
+ _CUDAToolkit_find_and_add_import_lib(culibos) # it's a static library
+ foreach (cuda_lib cublasLt cublas cufft curand cusparse nppc nvjpeg)
+ _CUDAToolkit_find_and_add_import_lib(${cuda_lib})
+ _CUDAToolkit_find_and_add_import_lib(${cuda_lib}_static DEPS culibos)
+ endforeach()
+
+ # cuFFTW depends on cuFFT
+ _CUDAToolkit_find_and_add_import_lib(cufftw DEPS cufft)
+ _CUDAToolkit_find_and_add_import_lib(cufftw DEPS cufft_static)
+
+ # cuSOLVER depends on cuBLAS, and cuSPARSE
+ _CUDAToolkit_find_and_add_import_lib(cusolver DEPS cublas cusparse)
+ _CUDAToolkit_find_and_add_import_lib(cusolver_static DEPS cublas_static cusparse_static culibos)
+
+ # nvGRAPH depends on cuRAND, and cuSOLVER.
+ _CUDAToolkit_find_and_add_import_lib(nvgraph DEPS curand cusolver)
+ _CUDAToolkit_find_and_add_import_lib(nvgraph_static DEPS curand_static cusolver_static)
+
+ # Process the majority of the NPP libraries.
+ foreach (cuda_lib nppial nppicc nppidei nppif nppig nppim nppist nppitc npps nppicom nppisu)
+ _CUDAToolkit_find_and_add_import_lib(${cuda_lib} DEPS nppc)
+ _CUDAToolkit_find_and_add_import_lib(${cuda_lib}_static DEPS nppc_static)
+ endforeach()
+
+ _CUDAToolkit_find_and_add_import_lib(cupti
+ EXTRA_PATH_SUFFIXES ../extras/CUPTI/lib64/
+ ../extras/CUPTI/lib/)
+ _CUDAToolkit_find_and_add_import_lib(cupti_static
+ EXTRA_PATH_SUFFIXES ../extras/CUPTI/lib64/
+ ../extras/CUPTI/lib/)
+
+ _CUDAToolkit_find_and_add_import_lib(nvrtc DEPS cuda_driver)
+
+ _CUDAToolkit_find_and_add_import_lib(nvml ALT nvidia-ml nvml)
+
+ if(WIN32)
+ # nvtools can be installed outside the CUDA toolkit directory
+ # so prefer the NVTOOLSEXT_PATH windows only environment variable
+ # In addition on windows the most common name is nvToolsExt64_1
+ find_library(CUDA_nvToolsExt_LIBRARY
+ NAMES nvToolsExt64_1 nvToolsExt64 nvToolsExt
+ PATHS ENV NVTOOLSEXT_PATH
+ ENV CUDA_PATH
+ PATH_SUFFIXES lib/x64 lib
+ )
+ endif()
+ _CUDAToolkit_find_and_add_import_lib(nvToolsExt ALT nvToolsExt64)
+
+ _CUDAToolkit_find_and_add_import_lib(OpenCL)
+endif()
+
+if(_CUDAToolkit_Pop_ROOT_PATH)
+ list(REMOVE_AT CMAKE_FIND_ROOT_PATH 0)
+ unset(_CUDAToolkit_Pop_ROOT_PATH)
+endif()
diff --git a/Modules/FindCURL.cmake b/Modules/FindCURL.cmake
new file mode 100644
index 0000000..e37d225
--- /dev/null
+++ b/Modules/FindCURL.cmake
@@ -0,0 +1,215 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindCURL
+--------
+
+Find the native CURL headers and libraries.
+
+.. versionadded:: 3.14
+ This module accept optional COMPONENTS to check supported features and
+ protocols:
+
+::
+
+ PROTOCOLS: ICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS LDAP LDAPS POP3
+ POP3S RTMP RTSP SCP SFTP SMB SMBS SMTP SMTPS TELNET TFTP
+ FEATURES: SSL IPv6 UnixSockets libz AsynchDNS IDN GSS-API PSL SPNEGO
+ Kerberos NTLM NTLM_WB TLS-SRP HTTP2 HTTPS-proxy
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.12
+
+This module defines :prop_tgt:`IMPORTED` target ``CURL::libcurl``, if
+curl has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``CURL_FOUND``
+ "True" if ``curl`` found.
+
+``CURL_INCLUDE_DIRS``
+ where to find ``curl``/``curl.h``, etc.
+
+``CURL_LIBRARIES``
+ List of libraries when using ``curl``.
+
+``CURL_VERSION_STRING``
+ The version of ``curl`` found.
+
+.. versionadded:: 3.13
+ Debug and Release variants are found separately.
+
+CURL CMake
+^^^^^^^^^^
+
+.. versionadded:: 3.17
+
+If CURL was built using the CMake buildsystem then it provides its own
+``CURLConfig.cmake`` file for use with the :command:`find_package` command's
+config mode. This module looks for this file and, if found,
+returns its results with no further action.
+
+Set ``CURL_NO_CURL_CMAKE`` to ``ON`` to disable this search.
+
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+if(NOT CURL_NO_CURL_CMAKE)
+ # do a find package call to specifically look for the CMake version
+ # of curl
+ find_package(CURL QUIET NO_MODULE)
+ mark_as_advanced(CURL_DIR)
+
+ # if we found the CURL cmake package then we are done, and
+ # can print what we found and return.
+ if(CURL_FOUND)
+ find_package_handle_standard_args(CURL HANDLE_COMPONENTS CONFIG_MODE)
+ return()
+ endif()
+endif()
+
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_CURL QUIET libcurl)
+ if(PC_CURL_FOUND)
+ set(CURL_VERSION_STRING ${PC_CURL_VERSION})
+ pkg_get_variable(CURL_SUPPORTED_PROTOCOLS libcurl supported_protocols)
+ pkg_get_variable(CURL_SUPPORTED_FEATURES libcurl supported_features)
+ endif()
+endif()
+
+# Look for the header file.
+find_path(CURL_INCLUDE_DIR
+ NAMES curl/curl.h
+ HINTS ${PC_CURL_INCLUDE_DIRS})
+mark_as_advanced(CURL_INCLUDE_DIR)
+
+if(NOT CURL_LIBRARY)
+ # Look for the library (sorted from most current/relevant entry to least).
+ find_library(CURL_LIBRARY_RELEASE NAMES
+ curl
+ # Windows MSVC prebuilts:
+ curllib
+ libcurl_imp
+ curllib_static
+ # Windows older "Win32 - MSVC" prebuilts (libcurl.lib, e.g. libcurl-7.15.5-win32-msvc.zip):
+ libcurl
+ NAMES_PER_DIR
+ HINTS ${PC_CURL_LIBRARY_DIRS}
+ )
+ mark_as_advanced(CURL_LIBRARY_RELEASE)
+
+ find_library(CURL_LIBRARY_DEBUG NAMES
+ # Windows MSVC CMake builds in debug configuration on vcpkg:
+ libcurl-d_imp
+ libcurl-d
+ NAMES_PER_DIR
+ HINTS ${PC_CURL_LIBRARY_DIRS}
+ )
+ mark_as_advanced(CURL_LIBRARY_DEBUG)
+
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(CURL)
+endif()
+
+if(CURL_INCLUDE_DIR AND NOT CURL_VERSION_STRING)
+ foreach(_curl_version_header curlver.h curl.h)
+ if(EXISTS "${CURL_INCLUDE_DIR}/curl/${_curl_version_header}")
+ file(STRINGS "${CURL_INCLUDE_DIR}/curl/${_curl_version_header}" curl_version_str REGEX "^#define[\t ]+LIBCURL_VERSION[\t ]+\".*\"")
+
+ string(REGEX REPLACE "^#define[\t ]+LIBCURL_VERSION[\t ]+\"([^\"]*)\".*" "\\1" CURL_VERSION_STRING "${curl_version_str}")
+ unset(curl_version_str)
+ break()
+ endif()
+ endforeach()
+endif()
+
+if(CURL_FIND_COMPONENTS)
+ set(CURL_KNOWN_PROTOCOLS ICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS LDAP LDAPS POP3 POP3S RTMP RTSP SCP SFTP SMB SMBS SMTP SMTPS TELNET TFTP)
+ set(CURL_KNOWN_FEATURES SSL IPv6 UnixSockets libz AsynchDNS IDN GSS-API PSL SPNEGO Kerberos NTLM NTLM_WB TLS-SRP HTTP2 HTTPS-proxy)
+ foreach(component IN LISTS CURL_KNOWN_PROTOCOLS CURL_KNOWN_FEATURES)
+ set(CURL_${component}_FOUND FALSE)
+ endforeach()
+ if(NOT PC_CURL_FOUND)
+ find_program(CURL_CONFIG_EXECUTABLE NAMES curl-config)
+ if(CURL_CONFIG_EXECUTABLE)
+ execute_process(COMMAND ${CURL_CONFIG_EXECUTABLE} --version
+ OUTPUT_VARIABLE CURL_CONFIG_VERSION_STRING
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${CURL_CONFIG_EXECUTABLE} --feature
+ OUTPUT_VARIABLE CURL_CONFIG_FEATURES_STRING
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ string(REPLACE "\n" ";" CURL_SUPPORTED_FEATURES "${CURL_CONFIG_FEATURES_STRING}")
+ execute_process(COMMAND ${CURL_CONFIG_EXECUTABLE} --protocols
+ OUTPUT_VARIABLE CURL_CONFIG_PROTOCOLS_STRING
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ string(REPLACE "\n" ";" CURL_SUPPORTED_PROTOCOLS "${CURL_CONFIG_PROTOCOLS_STRING}")
+ endif()
+
+ endif()
+ foreach(component IN LISTS CURL_FIND_COMPONENTS)
+ list(FIND CURL_KNOWN_PROTOCOLS ${component} _found)
+ if(NOT _found EQUAL -1)
+ list(FIND CURL_SUPPORTED_PROTOCOLS ${component} _found)
+ if(NOT _found EQUAL -1)
+ set(CURL_${component}_FOUND TRUE)
+ elseif(CURL_FIND_REQUIRED)
+ message(FATAL_ERROR "CURL: Required protocol ${component} is not found")
+ endif()
+ else()
+ list(FIND CURL_SUPPORTED_FEATURES ${component} _found)
+ if(NOT _found EQUAL -1)
+ set(CURL_${component}_FOUND TRUE)
+ elseif(CURL_FIND_REQUIRED)
+ message(FATAL_ERROR "CURL: Required feature ${component} is not found")
+ endif()
+ endif()
+ endforeach()
+endif()
+
+find_package_handle_standard_args(CURL
+ REQUIRED_VARS CURL_LIBRARY CURL_INCLUDE_DIR
+ VERSION_VAR CURL_VERSION_STRING
+ HANDLE_COMPONENTS)
+
+if(CURL_FOUND)
+ set(CURL_LIBRARIES ${CURL_LIBRARY})
+ set(CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIR})
+
+ if(NOT TARGET CURL::libcurl)
+ add_library(CURL::libcurl UNKNOWN IMPORTED)
+ set_target_properties(CURL::libcurl PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${CURL_INCLUDE_DIRS}")
+
+ if(EXISTS "${CURL_LIBRARY}")
+ set_target_properties(CURL::libcurl PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${CURL_LIBRARY}")
+ endif()
+ if(CURL_LIBRARY_RELEASE)
+ set_property(TARGET CURL::libcurl APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(CURL::libcurl PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION_RELEASE "${CURL_LIBRARY_RELEASE}")
+ endif()
+ if(CURL_LIBRARY_DEBUG)
+ set_property(TARGET CURL::libcurl APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(CURL::libcurl PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION_DEBUG "${CURL_LIBRARY_DEBUG}")
+ endif()
+ endif()
+endif()
diff --git a/Modules/FindCVS.cmake b/Modules/FindCVS.cmake
new file mode 100644
index 0000000..f819800
--- /dev/null
+++ b/Modules/FindCVS.cmake
@@ -0,0 +1,73 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindCVS
+-------
+
+Find the Concurrent Versions System (CVS).
+
+The module defines the following variables:
+
+::
+
+ CVS_EXECUTABLE - path to cvs command line client
+ CVS_FOUND - true if the command line client was found
+
+Example usage:
+
+::
+
+ find_package(CVS)
+ if(CVS_FOUND)
+ message("CVS found: ${CVS_EXECUTABLE}")
+ endif()
+#]=======================================================================]
+
+# CVSNT
+
+get_filename_component(
+ CVSNT_TypeLib_Win32
+ "[HKEY_CLASSES_ROOT\\TypeLib\\{2BDF7A65-0BFE-4B1A-9205-9AB900C7D0DA}\\1.0\\0\\win32]"
+ PATH)
+
+get_filename_component(
+ CVSNT_Services_EventMessagePath
+ "[HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Eventlog\\Application\\cvsnt;EventMessageFile]"
+ PATH)
+
+# WinCVS (in case CVSNT was installed in the same directory)
+
+get_filename_component(
+ WinCVS_Folder_Command
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Folder\\shell\\wincvs\\command]"
+ PATH)
+
+# TortoiseCVS (in case CVSNT was installed in the same directory)
+
+get_filename_component(
+ TortoiseCVS_Folder_Command
+ "[HKEY_CLASSES_ROOT\\CVS\\shell\\open\\command]"
+ PATH)
+
+get_filename_component(
+ TortoiseCVS_DefaultIcon
+ "[HKEY_CLASSES_ROOT\\CVS\\DefaultIcon]"
+ PATH)
+
+find_program(CVS_EXECUTABLE cvs
+ ${TortoiseCVS_DefaultIcon}
+ ${TortoiseCVS_Folder_Command}
+ ${WinCVS_Folder_Command}
+ ${CVSNT_Services_EventMessagePath}
+ ${CVSNT_TypeLib_Win32}
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\CVS\\Pserver;InstallPath]"
+ DOC "CVS command line client"
+ )
+mark_as_advanced(CVS_EXECUTABLE)
+
+# Handle the QUIETLY and REQUIRED arguments and set CVS_FOUND to TRUE if
+# all listed variables are TRUE
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(CVS DEFAULT_MSG CVS_EXECUTABLE)
diff --git a/Modules/FindCoin3D.cmake b/Modules/FindCoin3D.cmake
new file mode 100644
index 0000000..301e70b
--- /dev/null
+++ b/Modules/FindCoin3D.cmake
@@ -0,0 +1,77 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindCoin3D
+----------
+
+Find Coin3D (Open Inventor)
+
+Coin3D is an implementation of the Open Inventor API. It provides
+data structures and algorithms for 3D visualization.
+
+This module defines the following variables
+
+::
+
+ COIN3D_FOUND - system has Coin3D - Open Inventor
+ COIN3D_INCLUDE_DIRS - where the Inventor include directory can be found
+ COIN3D_LIBRARIES - Link to this to use Coin3D
+#]=======================================================================]
+
+if (WIN32)
+ if (CYGWIN)
+
+ find_path(COIN3D_INCLUDE_DIRS Inventor/So.h)
+ find_library(COIN3D_LIBRARIES Coin)
+
+ else ()
+
+ find_path(COIN3D_INCLUDE_DIRS Inventor/So.h
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\SIM\\Coin3D\\2;Installation Path]/include"
+ )
+
+ find_library(COIN3D_LIBRARY_DEBUG coin2d
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\SIM\\Coin3D\\2;Installation Path]/lib"
+ )
+
+ find_library(COIN3D_LIBRARY_RELEASE coin2
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\SIM\\Coin3D\\2;Installation Path]/lib"
+ )
+
+ if (COIN3D_LIBRARY_DEBUG AND COIN3D_LIBRARY_RELEASE)
+ set(COIN3D_LIBRARIES optimized ${COIN3D_LIBRARY_RELEASE}
+ debug ${COIN3D_LIBRARY_DEBUG})
+ else ()
+ if (COIN3D_LIBRARY_DEBUG)
+ set (COIN3D_LIBRARIES ${COIN3D_LIBRARY_DEBUG})
+ endif ()
+ if (COIN3D_LIBRARY_RELEASE)
+ set (COIN3D_LIBRARIES ${COIN3D_LIBRARY_RELEASE})
+ endif ()
+ endif ()
+
+ endif ()
+
+else ()
+ if(APPLE)
+ find_path(COIN3D_INCLUDE_DIRS Inventor/So.h
+ /Library/Frameworks/Inventor.framework/Headers
+ )
+ find_library(COIN3D_LIBRARIES Coin
+ /Library/Frameworks/Inventor.framework/Libraries
+ )
+ set(COIN3D_LIBRARIES "-framework Coin3d" CACHE STRING "Coin3D library for OSX")
+ else()
+
+ find_path(COIN3D_INCLUDE_DIRS Inventor/So.h)
+ find_library(COIN3D_LIBRARIES Coin)
+
+ endif()
+
+endif ()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Coin3D DEFAULT_MSG COIN3D_LIBRARIES COIN3D_INCLUDE_DIRS)
+
+mark_as_advanced(COIN3D_INCLUDE_DIRS COIN3D_LIBRARIES )
diff --git a/Modules/FindCups.cmake b/Modules/FindCups.cmake
new file mode 100644
index 0000000..cf0d341
--- /dev/null
+++ b/Modules/FindCups.cmake
@@ -0,0 +1,100 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindCups
+--------
+
+Find the Common UNIX Printing System (CUPS).
+
+Set ``CUPS_REQUIRE_IPP_DELETE_ATTRIBUTE`` to ``TRUE`` if you need a version which
+features this function (i.e. at least ``1.1.19``)
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.15
+
+This module defines :prop_tgt:`IMPORTED` target ``Cups::Cups``, if Cups has
+been found.
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``CUPS_FOUND``
+ true if CUPS headers and libraries were found
+``CUPS_INCLUDE_DIRS``
+ the directory containing the Cups headers
+``CUPS_LIBRARIES``
+ the libraries to link against to use CUPS.
+``CUPS_VERSION_STRING``
+ the version of CUPS found (since CMake 2.8.8)
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``CUPS_INCLUDE_DIR``
+ the directory containing the Cups headers
+#]=======================================================================]
+
+find_path(CUPS_INCLUDE_DIR cups/cups.h )
+
+find_library(CUPS_LIBRARIES NAMES cups )
+
+if (CUPS_INCLUDE_DIR AND CUPS_LIBRARIES AND CUPS_REQUIRE_IPP_DELETE_ATTRIBUTE)
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckLibraryExists.cmake)
+ include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_QUIET ${Cups_FIND_QUIETLY})
+
+ # ippDeleteAttribute is new in cups-1.1.19 (and used by kdeprint)
+ CHECK_LIBRARY_EXISTS(cups ippDeleteAttribute "" CUPS_HAS_IPP_DELETE_ATTRIBUTE)
+ cmake_pop_check_state()
+endif ()
+
+if (CUPS_INCLUDE_DIR AND EXISTS "${CUPS_INCLUDE_DIR}/cups/cups.h")
+ file(STRINGS "${CUPS_INCLUDE_DIR}/cups/cups.h" cups_version_str
+ REGEX "^#[\t ]*define[\t ]+CUPS_VERSION_(MAJOR|MINOR|PATCH)[\t ]+[0-9]+$")
+
+ unset(CUPS_VERSION_STRING)
+ foreach(VPART MAJOR MINOR PATCH)
+ foreach(VLINE ${cups_version_str})
+ if(VLINE MATCHES "^#[\t ]*define[\t ]+CUPS_VERSION_${VPART}[\t ]+([0-9]+)$")
+ set(CUPS_VERSION_PART "${CMAKE_MATCH_1}")
+ if(CUPS_VERSION_STRING)
+ string(APPEND CUPS_VERSION_STRING ".${CUPS_VERSION_PART}")
+ else()
+ set(CUPS_VERSION_STRING "${CUPS_VERSION_PART}")
+ endif()
+ endif()
+ endforeach()
+ endforeach()
+endif ()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+if (CUPS_REQUIRE_IPP_DELETE_ATTRIBUTE)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(Cups
+ REQUIRED_VARS CUPS_LIBRARIES CUPS_INCLUDE_DIR CUPS_HAS_IPP_DELETE_ATTRIBUTE
+ VERSION_VAR CUPS_VERSION_STRING)
+else ()
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(Cups
+ REQUIRED_VARS CUPS_LIBRARIES CUPS_INCLUDE_DIR
+ VERSION_VAR CUPS_VERSION_STRING)
+endif ()
+
+mark_as_advanced(CUPS_INCLUDE_DIR CUPS_LIBRARIES)
+
+if (CUPS_FOUND)
+ set(CUPS_INCLUDE_DIRS "${CUPS_INCLUDE_DIR}")
+ if (NOT TARGET Cups::Cups)
+ add_library(Cups::Cups INTERFACE IMPORTED)
+ set_target_properties(Cups::Cups PROPERTIES
+ INTERFACE_LINK_LIBRARIES "${CUPS_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES "${CUPS_INCLUDE_DIR}")
+ endif ()
+endif ()
diff --git a/Modules/FindCurses.cmake b/Modules/FindCurses.cmake
new file mode 100644
index 0000000..5e25deb
--- /dev/null
+++ b/Modules/FindCurses.cmake
@@ -0,0 +1,276 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindCurses
+----------
+
+Find the curses or ncurses include file and library.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``CURSES_FOUND``
+ True if Curses is found.
+``CURSES_INCLUDE_DIRS``
+ The include directories needed to use Curses.
+``CURSES_LIBRARIES``
+ The libraries needed to use Curses.
+``CURSES_CFLAGS``
+ .. versionadded:: 3.16
+
+ Parameters which ought be given to C/C++ compilers when using Curses.
+``CURSES_HAVE_CURSES_H``
+ True if curses.h is available.
+``CURSES_HAVE_NCURSES_H``
+ True if ncurses.h is available.
+``CURSES_HAVE_NCURSES_NCURSES_H``
+ True if ``ncurses/ncurses.h`` is available.
+``CURSES_HAVE_NCURSES_CURSES_H``
+ True if ``ncurses/curses.h`` is available.
+
+Set ``CURSES_NEED_NCURSES`` to ``TRUE`` before the
+``find_package(Curses)`` call if NCurses functionality is required.
+
+.. versionadded:: 3.10
+ Set ``CURSES_NEED_WIDE`` to ``TRUE`` before the
+ ``find_package(Curses)`` call if unicode functionality is required.
+
+Backward Compatibility
+^^^^^^^^^^^^^^^^^^^^^^
+
+The following variable are provided for backward compatibility:
+
+``CURSES_INCLUDE_DIR``
+ Path to Curses include. Use ``CURSES_INCLUDE_DIRS`` instead.
+``CURSES_LIBRARY``
+ Path to Curses library. Use ``CURSES_LIBRARIES`` instead.
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/CheckLibraryExists.cmake)
+
+# we don't know anything about cursesw, so only ncurses
+# may be ncursesw
+if(NOT CURSES_NEED_WIDE)
+ set(NCURSES_LIBRARY_NAME "ncurses")
+ set(CURSES_FORM_LIBRARY_NAME "form")
+else()
+ set(NCURSES_LIBRARY_NAME "ncursesw")
+ set(CURSES_FORM_LIBRARY_NAME "formw")
+ # Also, if we are searching for wide curses - we are actually searching
+ # for ncurses, we don't know about any other unicode version.
+ set(CURSES_NEED_NCURSES TRUE)
+endif()
+
+find_library(CURSES_CURSES_LIBRARY NAMES curses)
+
+find_library(CURSES_NCURSES_LIBRARY NAMES "${NCURSES_LIBRARY_NAME}" )
+set(CURSES_USE_NCURSES FALSE)
+
+if(CURSES_NCURSES_LIBRARY AND ((NOT CURSES_CURSES_LIBRARY) OR CURSES_NEED_NCURSES))
+ set(CURSES_USE_NCURSES TRUE)
+endif()
+# http://cygwin.com/ml/cygwin-announce/2010-01/msg00002.html
+# cygwin ncurses stopped providing curses.h symlinks see above
+# message. Cygwin is an ncurses package, so force ncurses on
+# cygwin if the curses.h is missing
+if(CYGWIN)
+ if (CURSES_NEED_WIDE)
+ if(NOT EXISTS /usr/include/ncursesw/curses.h)
+ set(CURSES_USE_NCURSES TRUE)
+ endif()
+ else()
+ if(NOT EXISTS /usr/include/curses.h)
+ set(CURSES_USE_NCURSES TRUE)
+ endif()
+ endif()
+endif()
+
+
+# Not sure the logic is correct here.
+# If NCurses is required, use the function wsyncup() to check if the library
+# has NCurses functionality (at least this is where it breaks on NetBSD).
+# If wsyncup is in curses, use this one.
+# If not, try to find ncurses and check if this has the symbol.
+# Once the ncurses library is found, search the ncurses.h header first, but
+# some web pages also say that even with ncurses there is not always a ncurses.h:
+# http://osdir.com/ml/gnome.apps.mc.devel/2002-06/msg00029.html
+# So at first try ncurses.h, if not found, try to find curses.h under the same
+# prefix as the library was found, if still not found, try curses.h with the
+# default search paths.
+if(CURSES_CURSES_LIBRARY AND CURSES_NEED_NCURSES)
+ include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_QUIET ${Curses_FIND_QUIETLY})
+ CHECK_LIBRARY_EXISTS("${CURSES_CURSES_LIBRARY}"
+ wsyncup "" CURSES_CURSES_HAS_WSYNCUP)
+
+ if(CURSES_NCURSES_LIBRARY AND NOT CURSES_CURSES_HAS_WSYNCUP)
+ CHECK_LIBRARY_EXISTS("${CURSES_NCURSES_LIBRARY}"
+ wsyncup "" CURSES_NCURSES_HAS_WSYNCUP)
+ if( CURSES_NCURSES_HAS_WSYNCUP)
+ set(CURSES_USE_NCURSES TRUE)
+ endif()
+ endif()
+ cmake_pop_check_state()
+
+endif()
+
+if(CURSES_USE_NCURSES)
+ get_filename_component(_cursesLibDir "${CURSES_NCURSES_LIBRARY}" PATH)
+ get_filename_component(_cursesParentDir "${_cursesLibDir}" PATH)
+
+ # Use CURSES_NCURSES_INCLUDE_PATH if set, for compatibility.
+ if(CURSES_NCURSES_INCLUDE_PATH)
+ if (CURSES_NEED_WIDE)
+ find_path(CURSES_INCLUDE_PATH
+ NAMES ncursesw/ncurses.h ncursesw/curses.h ncursesw.h cursesw.h
+ PATHS ${CURSES_NCURSES_INCLUDE_PATH}
+ NO_DEFAULT_PATH
+ )
+ else()
+ find_path(CURSES_INCLUDE_PATH
+ NAMES ncurses/ncurses.h ncurses/curses.h ncurses.h curses.h
+ PATHS ${CURSES_NCURSES_INCLUDE_PATH}
+ NO_DEFAULT_PATH
+ )
+ endif()
+ endif()
+
+ if (CURSES_NEED_WIDE)
+ set(CURSES_TINFO_LIBRARY_NAME tinfow)
+ find_path(CURSES_INCLUDE_PATH
+ NAMES ncursesw/ncurses.h ncursesw/curses.h ncursesw.h cursesw.h
+ HINTS "${_cursesParentDir}/include"
+ )
+ else()
+ set(CURSES_TINFO_LIBRARY_NAME tinfo)
+ find_path(CURSES_INCLUDE_PATH
+ NAMES ncurses/ncurses.h ncurses/curses.h ncurses.h curses.h
+ HINTS "${_cursesParentDir}/include"
+ )
+ endif()
+
+ # Previous versions of FindCurses provided these values.
+ if(NOT DEFINED CURSES_LIBRARY)
+ set(CURSES_LIBRARY "${CURSES_NCURSES_LIBRARY}")
+ endif()
+
+ CHECK_LIBRARY_EXISTS("${CURSES_NCURSES_LIBRARY}"
+ cbreak "" CURSES_NCURSES_HAS_CBREAK)
+ CHECK_LIBRARY_EXISTS("${CURSES_NCURSES_LIBRARY}"
+ nodelay "" CURSES_NCURSES_HAS_NODELAY)
+ if(NOT CURSES_NCURSES_HAS_CBREAK OR NOT CURSES_NCURSES_HAS_NODELAY)
+ find_library(CURSES_EXTRA_LIBRARY "${CURSES_TINFO_LIBRARY_NAME}" HINTS "${_cursesLibDir}")
+ find_library(CURSES_EXTRA_LIBRARY "${CURSES_TINFO_LIBRARY_NAME}" )
+
+ mark_as_advanced(
+ CURSES_EXTRA_LIBRARY
+ )
+ endif()
+else()
+ get_filename_component(_cursesLibDir "${CURSES_CURSES_LIBRARY}" PATH)
+ get_filename_component(_cursesParentDir "${_cursesLibDir}" PATH)
+
+ #We can't find anything with CURSES_NEED_WIDE because we know
+ #only about ncursesw unicode curses version
+ if(NOT CURSES_NEED_WIDE)
+ find_path(CURSES_INCLUDE_PATH
+ NAMES curses.h
+ HINTS "${_cursesParentDir}/include"
+ )
+ endif()
+
+ # Previous versions of FindCurses provided these values.
+ if(NOT DEFINED CURSES_CURSES_H_PATH)
+ set(CURSES_CURSES_H_PATH "${CURSES_INCLUDE_PATH}")
+ endif()
+ if(NOT DEFINED CURSES_LIBRARY)
+ set(CURSES_LIBRARY "${CURSES_CURSES_LIBRARY}")
+ endif()
+endif()
+
+# Report whether each possible header name exists in the include directory.
+if(NOT DEFINED CURSES_HAVE_NCURSES_NCURSES_H)
+ if(CURSES_NEED_WIDE)
+ if(EXISTS "${CURSES_INCLUDE_PATH}/ncursesw/ncurses.h")
+ set(CURSES_HAVE_NCURSES_NCURSES_H "${CURSES_INCLUDE_PATH}/ncursesw/ncurses.h")
+ endif()
+ elseif(EXISTS "${CURSES_INCLUDE_PATH}/ncurses/ncurses.h")
+ set(CURSES_HAVE_NCURSES_NCURSES_H "${CURSES_INCLUDE_PATH}/ncurses/ncurses.h")
+ endif()
+ if(NOT DEFINED CURSES_HAVE_NCURSES_NCURSES_H)
+ set(CURSES_HAVE_NCURSES_NCURSES_H "CURSES_HAVE_NCURSES_NCURSES_H-NOTFOUND")
+ endif()
+endif()
+if(NOT DEFINED CURSES_HAVE_NCURSES_CURSES_H)
+ if(CURSES_NEED_WIDE)
+ if(EXISTS "${CURSES_INCLUDE_PATH}/ncursesw/curses.h")
+ set(CURSES_HAVE_NCURSES_CURSES_H "${CURSES_INCLUDE_PATH}/ncursesw/curses.h")
+ endif()
+ elseif(EXISTS "${CURSES_INCLUDE_PATH}/ncurses/curses.h")
+ set(CURSES_HAVE_NCURSES_CURSES_H "${CURSES_INCLUDE_PATH}/ncurses/curses.h")
+ endif()
+ if(NOT DEFINED CURSES_HAVE_NCURSES_CURSES_H)
+ set(CURSES_HAVE_NCURSES_CURSES_H "CURSES_HAVE_NCURSES_CURSES_H-NOTFOUND")
+ endif()
+endif()
+if(NOT CURSES_NEED_WIDE)
+ #ncursesw can't be found for this paths
+ if(NOT DEFINED CURSES_HAVE_NCURSES_H)
+ if(EXISTS "${CURSES_INCLUDE_PATH}/ncurses.h")
+ set(CURSES_HAVE_NCURSES_H "${CURSES_INCLUDE_PATH}/ncurses.h")
+ else()
+ set(CURSES_HAVE_NCURSES_H "CURSES_HAVE_NCURSES_H-NOTFOUND")
+ endif()
+ endif()
+ if(NOT DEFINED CURSES_HAVE_CURSES_H)
+ if(EXISTS "${CURSES_INCLUDE_PATH}/curses.h")
+ set(CURSES_HAVE_CURSES_H "${CURSES_INCLUDE_PATH}/curses.h")
+ else()
+ set(CURSES_HAVE_CURSES_H "CURSES_HAVE_CURSES_H-NOTFOUND")
+ endif()
+ endif()
+endif()
+
+find_library(CURSES_FORM_LIBRARY "${CURSES_FORM_LIBRARY_NAME}" HINTS "${_cursesLibDir}")
+find_library(CURSES_FORM_LIBRARY "${CURSES_FORM_LIBRARY_NAME}" )
+
+# Previous versions of FindCurses provided these values.
+if(NOT DEFINED FORM_LIBRARY)
+ set(FORM_LIBRARY "${CURSES_FORM_LIBRARY}")
+endif()
+
+# Need to provide the *_LIBRARIES
+set(CURSES_LIBRARIES ${CURSES_LIBRARY})
+
+if(CURSES_EXTRA_LIBRARY)
+ set(CURSES_LIBRARIES ${CURSES_LIBRARIES} ${CURSES_EXTRA_LIBRARY})
+endif()
+
+if(CURSES_FORM_LIBRARY)
+ set(CURSES_LIBRARIES ${CURSES_LIBRARIES} ${CURSES_FORM_LIBRARY})
+endif()
+
+# Provide the *_INCLUDE_DIRS and *_CFLAGS results.
+set(CURSES_INCLUDE_DIRS ${CURSES_INCLUDE_PATH})
+set(CURSES_INCLUDE_DIR ${CURSES_INCLUDE_PATH}) # compatibility
+
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(NCURSES QUIET ${NCURSES_LIBRARY_NAME})
+ set(CURSES_CFLAGS ${NCURSES_CFLAGS_OTHER})
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Curses DEFAULT_MSG
+ CURSES_LIBRARY CURSES_INCLUDE_PATH)
+
+mark_as_advanced(
+ CURSES_INCLUDE_PATH
+ CURSES_CURSES_LIBRARY
+ CURSES_NCURSES_LIBRARY
+ CURSES_FORM_LIBRARY
+ )
diff --git a/Modules/FindCxxTest.cmake b/Modules/FindCxxTest.cmake
new file mode 100644
index 0000000..3fc0e93
--- /dev/null
+++ b/Modules/FindCxxTest.cmake
@@ -0,0 +1,247 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindCxxTest
+-----------
+
+Find CxxTest unit testing framework.
+
+Find the CxxTest suite and declare a helper macro for creating unit
+tests and integrating them with CTest. For more details on CxxTest
+see http://cxxtest.tigris.org
+
+INPUT Variables
+
+::
+
+ CXXTEST_USE_PYTHON [deprecated since 1.3]
+ Only used in the case both Python & Perl
+ are detected on the system to control
+ which CxxTest code generator is used.
+ Valid only for CxxTest version 3.
+
+
+
+::
+
+ NOTE: In older versions of this Find Module,
+ this variable controlled if the Python test
+ generator was used instead of the Perl one,
+ regardless of which scripting language the
+ user had installed.
+
+
+
+::
+
+ CXXTEST_TESTGEN_ARGS (since CMake 2.8.3)
+ Specify a list of options to pass to the CxxTest code
+ generator. If not defined, --error-printer is
+ passed.
+
+
+
+OUTPUT Variables
+
+::
+
+ CXXTEST_FOUND
+ True if the CxxTest framework was found
+ CXXTEST_INCLUDE_DIRS
+ Where to find the CxxTest include directory
+ CXXTEST_PERL_TESTGEN_EXECUTABLE
+ The perl-based test generator
+ CXXTEST_PYTHON_TESTGEN_EXECUTABLE
+ The python-based test generator
+ CXXTEST_TESTGEN_EXECUTABLE (since CMake 2.8.3)
+ The test generator that is actually used (chosen using user preferences
+ and interpreters found in the system)
+ CXXTEST_TESTGEN_INTERPRETER (since CMake 2.8.3)
+ The full path to the Perl or Python executable on the system, on
+ platforms where the script cannot be executed using its shebang line.
+
+
+
+MACROS for optional use by CMake users:
+
+::
+
+ CXXTEST_ADD_TEST(<test_name> <gen_source_file> <input_files_to_testgen...>)
+ Creates a CxxTest runner and adds it to the CTest testing suite
+ Parameters:
+ test_name The name of the test
+ gen_source_file The generated source filename to be
+ generated by CxxTest
+ input_files_to_testgen The list of header files containing the
+ CxxTest::TestSuite's to be included in
+ this runner
+
+
+
+::
+
+ #==============
+ Example Usage:
+
+
+
+::
+
+ find_package(CxxTest)
+ if(CXXTEST_FOUND)
+ include_directories(${CXXTEST_INCLUDE_DIR})
+ enable_testing()
+
+
+
+::
+
+ CXXTEST_ADD_TEST(unittest_foo foo_test.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/foo_test.h)
+ target_link_libraries(unittest_foo foo) # as needed
+ endif()
+
+
+
+::
+
+ This will (if CxxTest is found):
+ 1. Invoke the testgen executable to autogenerate foo_test.cc in the
+ binary tree from "foo_test.h" in the current source directory.
+ 2. Create an executable and test called unittest_foo.
+
+
+
+::
+
+ #=============
+ Example foo_test.h:
+
+
+
+::
+
+ #include <cxxtest/TestSuite.h>
+
+
+
+::
+
+ class MyTestSuite : public CxxTest::TestSuite
+ {
+ public:
+ void testAddition( void )
+ {
+ TS_ASSERT( 1 + 1 > 1 );
+ TS_ASSERT_EQUALS( 1 + 1, 2 );
+ }
+ };
+#]=======================================================================]
+
+# Version 1.4 (11/18/10) (CMake 2.8.4)
+# Issue 11384: Added support to the CXX_ADD_TEST macro so header
+# files (containing the tests themselves) show up in
+# Visual Studio and other IDEs.
+#
+# Version 1.3 (8/19/10) (CMake 2.8.3)
+# Included patch by Simone Rossetto to check if either Python or Perl
+# are present in the system. Whichever interpreter that is detected
+# is now used to run the test generator program. If both interpreters
+# are detected, the CXXTEST_USE_PYTHON variable is obeyed.
+#
+# Also added support for CXXTEST_TESTGEN_ARGS, for manually specifying
+# options to the CxxTest code generator.
+# Version 1.2 (3/2/08)
+# Included patch from Tyler Roscoe to have the perl & python binaries
+# detected based on CXXTEST_INCLUDE_DIR
+# Version 1.1 (2/9/08)
+# Clarified example to illustrate need to call target_link_libraries()
+# Changed commands to lowercase
+# Added licensing info
+# Version 1.0 (1/8/08)
+# Fixed CXXTEST_INCLUDE_DIRS so it will work properly
+# Eliminated superfluous CXXTEST_FOUND assignment
+# Cleaned up and added more documentation
+
+#=============================================================
+# CXXTEST_ADD_TEST (public macro)
+#=============================================================
+macro(CXXTEST_ADD_TEST _cxxtest_testname _cxxtest_outfname)
+ set(_cxxtest_real_outfname ${CMAKE_CURRENT_BINARY_DIR}/${_cxxtest_outfname})
+
+ add_custom_command(
+ OUTPUT ${_cxxtest_real_outfname}
+ DEPENDS ${ARGN}
+ COMMAND ${CXXTEST_TESTGEN_INTERPRETER}
+ ${CXXTEST_TESTGEN_EXECUTABLE} ${CXXTEST_TESTGEN_ARGS} -o ${_cxxtest_real_outfname} ${ARGN}
+ )
+
+ set_source_files_properties(${_cxxtest_real_outfname} PROPERTIES GENERATED true)
+ add_executable(${_cxxtest_testname} ${_cxxtest_real_outfname} ${ARGN})
+
+ if(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
+ add_test(${_cxxtest_testname} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${_cxxtest_testname})
+ elseif(EXECUTABLE_OUTPUT_PATH)
+ add_test(${_cxxtest_testname} ${EXECUTABLE_OUTPUT_PATH}/${_cxxtest_testname})
+ else()
+ add_test(${_cxxtest_testname} ${CMAKE_CURRENT_BINARY_DIR}/${_cxxtest_testname})
+ endif()
+
+endmacro()
+
+#=============================================================
+# main()
+#=============================================================
+if(NOT DEFINED CXXTEST_TESTGEN_ARGS)
+ set(CXXTEST_TESTGEN_ARGS --error-printer)
+endif()
+
+find_package(Python QUIET)
+find_package(Perl QUIET)
+
+find_path(CXXTEST_INCLUDE_DIR cxxtest/TestSuite.h)
+find_program(CXXTEST_PYTHON_TESTGEN_EXECUTABLE
+ NAMES cxxtestgen cxxtestgen.py
+ PATHS ${CXXTEST_INCLUDE_DIR})
+find_program(CXXTEST_PERL_TESTGEN_EXECUTABLE cxxtestgen.pl
+ PATHS ${CXXTEST_INCLUDE_DIR})
+
+if(PYTHON_FOUND OR PERL_FOUND)
+ include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+ if(PYTHON_FOUND AND (CXXTEST_USE_PYTHON OR NOT PERL_FOUND OR NOT DEFINED CXXTEST_USE_PYTHON))
+ set(CXXTEST_TESTGEN_EXECUTABLE ${CXXTEST_PYTHON_TESTGEN_EXECUTABLE})
+ execute_process(COMMAND ${CXXTEST_PYTHON_TESTGEN_EXECUTABLE} --version
+ OUTPUT_VARIABLE _CXXTEST_OUT ERROR_VARIABLE _CXXTEST_OUT RESULT_VARIABLE _CXXTEST_RESULT)
+ if(_CXXTEST_RESULT EQUAL 0)
+ set(CXXTEST_TESTGEN_INTERPRETER "")
+ else()
+ set(CXXTEST_TESTGEN_INTERPRETER ${Python_EXECUTABLE})
+ endif()
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(CxxTest DEFAULT_MSG
+ CXXTEST_INCLUDE_DIR CXXTEST_PYTHON_TESTGEN_EXECUTABLE)
+
+ elseif(PERL_FOUND)
+ set(CXXTEST_TESTGEN_EXECUTABLE ${CXXTEST_PERL_TESTGEN_EXECUTABLE})
+ set(CXXTEST_TESTGEN_INTERPRETER ${PERL_EXECUTABLE})
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(CxxTest DEFAULT_MSG
+ CXXTEST_INCLUDE_DIR CXXTEST_PERL_TESTGEN_EXECUTABLE)
+ endif()
+
+ if(CXXTEST_FOUND)
+ set(CXXTEST_INCLUDE_DIRS ${CXXTEST_INCLUDE_DIR})
+ endif()
+
+else()
+
+ set(CXXTEST_FOUND false)
+ if(NOT CxxTest_FIND_QUIETLY)
+ if(CxxTest_FIND_REQUIRED)
+ message(FATAL_ERROR "Neither Python nor Perl found, cannot use CxxTest, aborting!")
+ else()
+ message(STATUS "Neither Python nor Perl found, CxxTest will not be used.")
+ endif()
+ endif()
+
+endif()
diff --git a/Modules/FindCygwin.cmake b/Modules/FindCygwin.cmake
new file mode 100644
index 0000000..5bbc802
--- /dev/null
+++ b/Modules/FindCygwin.cmake
@@ -0,0 +1,28 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindCygwin
+----------
+
+Find Cygwin, a POSIX-compatible environment that runs natively
+on Microsoft Windows
+#]=======================================================================]
+
+if (WIN32)
+ if(CYGWIN_INSTALL_PATH)
+ set(CYGWIN_BAT "${CYGWIN_INSTALL_PATH}/cygwin.bat")
+ endif()
+
+ find_program(CYGWIN_BAT
+ NAMES cygwin.bat
+ PATHS
+ "C:/Cygwin"
+ "C:/Cygwin64"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Cygwin\\setup;rootdir]"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2\\/;native]"
+ )
+ get_filename_component(CYGWIN_INSTALL_PATH "${CYGWIN_BAT}" DIRECTORY)
+ mark_as_advanced(CYGWIN_BAT)
+
+endif ()
diff --git a/Modules/FindDCMTK.cmake b/Modules/FindDCMTK.cmake
new file mode 100644
index 0000000..b2e00df
--- /dev/null
+++ b/Modules/FindDCMTK.cmake
@@ -0,0 +1,322 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindDCMTK
+---------
+
+Find DICOM ToolKit (DCMTK) libraries and applications
+
+The module defines the following variables::
+
+ DCMTK_INCLUDE_DIRS - Directories to include to use DCMTK
+ DCMTK_LIBRARIES - Files to link against to use DCMTK
+ DCMTK_FOUND - If false, don't try to use DCMTK
+ DCMTK_DIR - (optional) Source directory for DCMTK
+
+Compatibility
+^^^^^^^^^^^^^
+
+This module is able to find a version of DCMTK that does or does not export
+a *DCMTKConfig.cmake* file. It applies a two step process:
+
+* Step 1: Attempt to find DCMTK version providing a *DCMTKConfig.cmake* file.
+* Step 2: If step 1 failed, rely on *FindDCMTK.cmake* to set `DCMTK_*` variables details below.
+
+
+`Recent DCMTK
+<http://git.dcmtk.org/web?p=dcmtk.git;a=commit;h=662ae187c493c6b9a73dd5e3875372cebd0c11fe>`_
+provides a *DCMTKConfig.cmake* :manual:`package configuration file
+<cmake-packages(7)>`. To exclusively use the package configuration file
+(recommended when possible), pass the `NO_MODULE` option to
+:command:`find_package`. For example, `find_package(DCMTK NO_MODULE)`.
+This requires official DCMTK snapshot *3.6.1_20140617* or newer.
+
+
+Until all clients update to the more recent DCMTK, build systems will need
+to support different versions of DCMTK.
+
+On any given system, the following combinations of DCMTK versions could be
+considered:
+
++--------+---------------------+-----------------------+-------------------+
+| | SYSTEM DCMTK | LOCAL DCMTK | Supported ? |
++--------+---------------------+-----------------------+-------------------+
+| Case A | NA | [ ] DCMTKConfig | YES |
++--------+---------------------+-----------------------+-------------------+
+| Case B | NA | [X] DCMTKConfig | YES |
++--------+---------------------+-----------------------+-------------------+
+| Case C | [ ] DCMTKConfig | NA | YES |
++--------+---------------------+-----------------------+-------------------+
+| Case D | [X] DCMTKConfig | NA | YES |
++--------+---------------------+-----------------------+-------------------+
+| Case E | [ ] DCMTKConfig | [ ] DCMTKConfig | YES (*) |
++--------+---------------------+-----------------------+-------------------+
+| Case F | [X] DCMTKConfig | [ ] DCMTKConfig | NO |
++--------+---------------------+-----------------------+-------------------+
+| Case G | [ ] DCMTKConfig | [X] DCMTKConfig | YES |
++--------+---------------------+-----------------------+-------------------+
+| Case H | [X] DCMTKConfig | [X] DCMTKConfig | YES |
++--------+---------------------+-----------------------+-------------------+
+
+ (*) See Troubleshooting section.
+
+Legend:
+
+ NA ...............: Means that no System or Local DCMTK is available
+
+ [ ] DCMTKConfig ..: Means that the version of DCMTK does NOT export a DCMTKConfig.cmake file.
+
+ [X] DCMTKConfig ..: Means that the version of DCMTK exports a DCMTKConfig.cmake file.
+
+
+Troubleshooting
+^^^^^^^^^^^^^^^
+
+What to do if my project finds a different version of DCMTK?
+
+Remove DCMTK entry from the CMake cache per :command:`find_package`
+documentation.
+#]=======================================================================]
+
+#
+# Written for VXL by Amitha Perera.
+# Upgraded for GDCM by Mathieu Malaterre.
+# Modified for EasyViz by Thomas Sondergaard.
+#
+
+set(_dcmtk_dir_description "The directory of DCMTK build or install tree.")
+
+# Ensure that DCMTK_DIR is set to a reasonable default value
+# so that DCMTK libraries can be found on a standard Unix distribution.
+# It also overwrite the value of DCMTK_DIR after this one has been
+# set by a successful discovery of DCMTK by the unpatched FindDCMTK.cmake module
+# distributed with CMake (as of 0167cea)
+if(NOT DCMTK_DIR OR DCMTK_DIR STREQUAL "/usr/include/dcmtk")
+ set(DCMTK_DIR "/usr" CACHE PATH ${_dcmtk_dir_description} FORCE)
+endif()
+
+set(_SAVED_DCMTK_DIR ${DCMTK_DIR})
+
+#
+# Step1: Attempt to find a version of DCMTK providing a DCMTKConfig.cmake file.
+#
+if(NOT DCMTK_FIND_QUIETLY)
+ message(CHECK_START "Trying to find DCMTK expecting DCMTKConfig.cmake")
+endif()
+find_package(DCMTK QUIET NO_MODULE)
+if(DCMTK_FOUND
+ AND NOT "x" STREQUAL "x${DCMTK_LIBRARIES}"
+ AND NOT "x" STREQUAL "x${DCMTK_INCLUDE_DIRS}")
+
+ if(NOT DCMTK_FIND_QUIETLY)
+ message(CHECK_PASS "ok")
+ endif()
+ return()
+else()
+ if(NOT DCMTK_FIND_QUIETLY)
+ message(CHECK_FAIL "failed")
+ endif()
+endif()
+
+if(NOT DCMTK_FIND_QUIETLY)
+ message(STATUS "Trying to find DCMTK relying on FindDCMTK.cmake")
+endif()
+
+# Restore the value reset by the previous call to 'find_package(DCMTK QUIET NO_MODULE)'
+set(DCMTK_DIR ${_SAVED_DCMTK_DIR} CACHE PATH ${_dcmtk_dir_description} FORCE)
+
+
+#
+# Step2: Attempt to find a version of DCMTK that does NOT provide a DCMTKConfig.cmake file.
+#
+
+# prefer DCMTK_DIR over default system paths like /usr/lib
+if(DCMTK_DIR)
+ set(CMAKE_PREFIX_PATH ${DCMTK_DIR}/lib ${CMAKE_PREFIX_PATH}) # this is given to FIND_LIBRARY or FIND_PATH
+endif()
+
+# Find all libraries, store debug and release separately
+foreach(lib
+ dcmpstat
+ dcmsr
+ dcmsign
+ dcmtls
+ dcmqrdb
+ dcmnet
+ dcmjpeg
+ dcmimage
+ dcmimgle
+ dcmdata
+ oflog
+ ofstd
+ ijg12
+ ijg16
+ ijg8
+ )
+
+ # Find Release libraries
+ find_library(DCMTK_${lib}_LIBRARY_RELEASE
+ ${lib}
+ PATHS
+ ${DCMTK_DIR}/${lib}/libsrc
+ ${DCMTK_DIR}/${lib}/libsrc/Release
+ ${DCMTK_DIR}/${lib}/Release
+ ${DCMTK_DIR}/lib
+ ${DCMTK_DIR}/lib/Release
+ ${DCMTK_DIR}/dcmjpeg/lib${lib}/Release
+ NO_DEFAULT_PATH
+ )
+
+ # Find Debug libraries
+ find_library(DCMTK_${lib}_LIBRARY_DEBUG
+ ${lib}${DCMTK_CMAKE_DEBUG_POSTFIX}
+ PATHS
+ ${DCMTK_DIR}/${lib}/libsrc
+ ${DCMTK_DIR}/${lib}/libsrc/Debug
+ ${DCMTK_DIR}/${lib}/Debug
+ ${DCMTK_DIR}/lib
+ ${DCMTK_DIR}/lib/Debug
+ ${DCMTK_DIR}/dcmjpeg/lib${lib}/Debug
+ NO_DEFAULT_PATH
+ )
+
+ mark_as_advanced(DCMTK_${lib}_LIBRARY_RELEASE)
+ mark_as_advanced(DCMTK_${lib}_LIBRARY_DEBUG)
+
+ # Add libraries to variable according to build type
+ if(DCMTK_${lib}_LIBRARY_RELEASE)
+ list(APPEND DCMTK_LIBRARIES optimized ${DCMTK_${lib}_LIBRARY_RELEASE})
+ endif()
+
+ if(DCMTK_${lib}_LIBRARY_DEBUG)
+ list(APPEND DCMTK_LIBRARIES debug ${DCMTK_${lib}_LIBRARY_DEBUG})
+ endif()
+
+endforeach()
+
+set(CMAKE_THREAD_LIBS_INIT)
+if(DCMTK_oflog_LIBRARY_RELEASE OR DCMTK_oflog_LIBRARY_DEBUG)
+ # Hack - Not having a DCMTKConfig.cmake file to read the settings from, we will attempt to
+ # find the library in all cases.
+ # Ideally, pthread library should be discovered only if DCMTK_WITH_THREADS is enabled.
+ find_package(Threads)
+endif()
+
+if(CMAKE_THREAD_LIBS_INIT)
+ list(APPEND DCMTK_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+endif()
+
+#
+# SPECIFIC CASE FOR DCMTK BUILD DIR as DCMTK_DIR
+# (as opposed to a DCMTK install dir)
+# Have to find the source directory.
+if(EXISTS ${DCMTK_DIR}/CMakeCache.txt)
+ load_cache(${DCMTK_DIR} READ_WITH_PREFIX "EXT"
+ DCMTK_SOURCE_DIR)
+ if(NOT EXISTS ${EXTDCMTK_SOURCE_DIR})
+ message(FATAL_ERROR
+ "DCMTK build directory references
+nonexistent DCMTK source directory ${EXTDCMTK_SOURCE_DIR}")
+ endif()
+endif()
+
+set(DCMTK_config_TEST_HEADER osconfig.h)
+set(DCMTK_dcmdata_TEST_HEADER dctypes.h)
+set(DCMTK_dcmimage_TEST_HEADER dicoimg.h)
+set(DCMTK_dcmimgle_TEST_HEADER dcmimage.h)
+set(DCMTK_dcmjpeg_TEST_HEADER djdecode.h)
+set(DCMTK_dcmnet_TEST_HEADER assoc.h)
+set(DCMTK_dcmpstat_TEST_HEADER dcmpstat.h)
+set(DCMTK_dcmqrdb_TEST_HEADER dcmqrdba.h)
+set(DCMTK_dcmsign_TEST_HEADER sicert.h)
+set(DCMTK_dcmsr_TEST_HEADER dsrtree.h)
+set(DCMTK_dcmtls_TEST_HEADER tlslayer.h)
+set(DCMTK_ofstd_TEST_HEADER ofstdinc.h)
+set(DCMTK_oflog_TEST_HEADER oflog.h)
+set(DCMTK_dcmjpls_TEST_HEADER djlsutil.h)
+
+set(DCMTK_INCLUDE_DIR_NAMES)
+
+foreach(dir
+ config
+ dcmdata
+ dcmimage
+ dcmimgle
+ dcmjpeg
+ dcmjpls
+ dcmnet
+ dcmpstat
+ dcmqrdb
+ dcmsign
+ dcmsr
+ dcmtls
+ ofstd
+ oflog)
+ if(EXTDCMTK_SOURCE_DIR)
+ set(SOURCE_DIR_PATH
+ ${EXTDCMTK_SOURCE_DIR}/${dir}/include/dcmtk/${dir})
+ endif()
+ find_path(DCMTK_${dir}_INCLUDE_DIR
+ ${DCMTK_${dir}_TEST_HEADER}
+ PATHS
+ ${DCMTK_DIR}/${dir}/include
+ ${DCMTK_DIR}/${dir}
+ ${DCMTK_DIR}/include/dcmtk/${dir}
+ ${DCMTK_DIR}/${dir}/include/dcmtk/${dir}
+ ${DCMTK_DIR}/include/${dir}
+ ${SOURCE_DIR_PATH}
+ )
+ mark_as_advanced(DCMTK_${dir}_INCLUDE_DIR)
+ list(APPEND DCMTK_INCLUDE_DIR_NAMES DCMTK_${dir}_INCLUDE_DIR)
+
+ if(DCMTK_${dir}_INCLUDE_DIR)
+ # add the 'include' path so eg
+ #include "dcmtk/dcmimgle/dcmimage.h"
+ # works
+ get_filename_component(_include ${DCMTK_${dir}_INCLUDE_DIR} PATH)
+ get_filename_component(_include ${_include} PATH)
+ list(APPEND
+ DCMTK_INCLUDE_DIRS
+ ${DCMTK_${dir}_INCLUDE_DIR}
+ ${_include})
+ endif()
+endforeach()
+
+list(APPEND DCMTK_INCLUDE_DIRS ${DCMTK_DIR}/include)
+
+if(WIN32)
+ list(APPEND DCMTK_LIBRARIES netapi32 wsock32)
+endif()
+
+if(DCMTK_ofstd_INCLUDE_DIR)
+ get_filename_component(DCMTK_dcmtk_INCLUDE_DIR
+ ${DCMTK_ofstd_INCLUDE_DIR}
+ PATH
+ CACHE)
+ list(APPEND DCMTK_INCLUDE_DIRS ${DCMTK_dcmtk_INCLUDE_DIR})
+ mark_as_advanced(DCMTK_dcmtk_INCLUDE_DIR)
+endif()
+
+# Compatibility: This variable is deprecated
+set(DCMTK_INCLUDE_DIR ${DCMTK_INCLUDE_DIRS})
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(DCMTK
+ REQUIRED_VARS ${DCMTK_INCLUDE_DIR_NAMES} DCMTK_LIBRARIES
+ FAIL_MESSAGE "Please set DCMTK_DIR and re-run configure")
+
+# Workaround bug in packaging of DCMTK 3.6.0 on Debian.
+# See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=637687
+if(DCMTK_FOUND AND UNIX AND NOT APPLE)
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckIncludeFiles.cmake)
+ set(CMAKE_REQUIRED_FLAGS )
+ set(CMAKE_REQUIRED_DEFINITIONS )
+ set(CMAKE_REQUIRED_INCLUDES ${DCMTK_INCLUDE_DIRS})
+ set(CMAKE_REQUIRED_LIBRARIES ${DCMTK_LIBRARIES})
+ set(CMAKE_REQUIRED_QUIET ${DCMTK_FIND_QUIETLY})
+ check_include_files("dcmtk/config/osconfig.h;dcmtk/ofstd/ofstream.h" DCMTK_HAVE_CONFIG_H_OPTIONAL LANGUAGE CXX)
+ if(NOT DCMTK_HAVE_CONFIG_H_OPTIONAL)
+ set(DCMTK_DEFINITIONS "HAVE_CONFIG_H")
+ endif()
+endif()
diff --git a/Modules/FindDart.cmake b/Modules/FindDart.cmake
new file mode 100644
index 0000000..0492578
--- /dev/null
+++ b/Modules/FindDart.cmake
@@ -0,0 +1,33 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindDart
+--------
+
+Find DART
+
+This module looks for the dart testing software and sets DART_ROOT to
+point to where it found it.
+#]=======================================================================]
+
+find_path(DART_ROOT README.INSTALL
+ HINTS
+ ENV DART_ROOT
+ PATHS
+ ${PROJECT_SOURCE_DIR}
+ /usr/share
+ C:/
+ "C:/Program Files"
+ ${PROJECT_SOURCE_DIR}/..
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Dart\\InstallPath]
+ ENV ProgramFiles
+ PATH_SUFFIXES
+ Dart
+ DOC "If you have Dart installed, where is it located?"
+ )
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Dart DEFAULT_MSG DART_ROOT)
+
+mark_as_advanced(DART_ROOT)
diff --git a/Modules/FindDevIL.cmake b/Modules/FindDevIL.cmake
new file mode 100644
index 0000000..c8e5e31
--- /dev/null
+++ b/Modules/FindDevIL.cmake
@@ -0,0 +1,139 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindDevIL
+---------
+
+
+
+This module locates the developer's image library.
+http://openil.sourceforge.net/
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.21
+
+This module defines the :prop_tgt:`IMPORTED` targets:
+
+``DevIL::IL``
+ Defined if the system has DevIL.
+
+``DevIL::ILU``
+ Defined if the system has DevIL Utilities.
+
+``DevIL::ILUT``
+ Defined if the system has DevIL Utility Toolkit.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module sets:
+
+``IL_LIBRARIES``
+ The name of the IL library. These include the full path to
+ the core DevIL library. This one has to be linked into the
+ application.
+
+``ILU_LIBRARIES``
+ The name of the ILU library. Again, the full path. This
+ library is for filters and effects, not actual loading. It
+ doesn't have to be linked if the functionality it provides
+ is not used.
+
+``ILUT_LIBRARIES``
+ The name of the ILUT library. Full path. This part of the
+ library interfaces with OpenGL. It is not strictly needed
+ in applications.
+
+``IL_INCLUDE_DIR``
+ where to find the il.h, ilu.h and ilut.h files.
+
+``DevIL_FOUND``
+ This is set to TRUE if all the above variables were set.
+ This will be set to false if ILU or ILUT are not found,
+ even if they are not needed. In most systems, if one
+ library is found all the others are as well. That's the
+ way the DevIL developers release it.
+
+``DevIL_ILUT_FOUND``
+ .. versionadded:: 3.21
+
+ This is set to TRUE if the ILUT library is found.
+#]=======================================================================]
+
+# TODO: Add version support.
+# Tested under Linux and Windows (MSVC)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+find_path(IL_INCLUDE_DIR il.h
+ PATH_SUFFIXES include IL
+ DOC "The path to the directory that contains il.h"
+)
+
+#message("IL_INCLUDE_DIR is ${IL_INCLUDE_DIR}")
+
+find_library(IL_LIBRARIES
+ NAMES IL DEVIL
+ PATH_SUFFIXES libx32 lib64 lib lib32
+ DOC "The file that corresponds to the base il library."
+)
+
+#message("IL_LIBRARIES is ${IL_LIBRARIES}")
+
+find_library(ILUT_LIBRARIES
+ NAMES ILUT
+ PATH_SUFFIXES libx32 lib64 lib lib32
+ DOC "The file that corresponds to the il (system?) utility library."
+)
+
+#message("ILUT_LIBRARIES is ${ILUT_LIBRARIES}")
+
+find_library(ILU_LIBRARIES
+ NAMES ILU
+ PATH_SUFFIXES libx32 lib64 lib lib32
+ DOC "The file that corresponds to the il utility library."
+)
+
+#message("ILU_LIBRARIES is ${ILU_LIBRARIES}")
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(DevIL DEFAULT_MSG
+ IL_LIBRARIES ILU_LIBRARIES
+ IL_INCLUDE_DIR)
+# provide legacy variable for compatibility
+set(IL_FOUND ${DevIL_FOUND})
+
+# create imported targets ONLY if we found DevIL.
+if(DevIL_FOUND)
+ # Report the ILUT found if ILUT_LIBRARIES contains valid path.
+ if (ILUT_LIBRARIES)
+ set(DevIL_ILUT_FOUND TRUE)
+ else()
+ set(DevIL_ILUT_FOUND FALSE)
+ endif()
+
+ if(NOT TARGET DevIL::IL)
+ add_library(DevIL::IL UNKNOWN IMPORTED)
+ set_target_properties(DevIL::IL PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${IL_INCLUDE_DIR}"
+ IMPORTED_LOCATION "${IL_LIBRARIES}")
+ endif()
+
+ # DevIL Utilities target
+ if(NOT TARGET DevIL::ILU)
+ add_library(DevIL::ILU UNKNOWN IMPORTED)
+ set_target_properties(DevIL::ILU PROPERTIES
+ IMPORTED_LOCATION "${ILU_LIBRARIES}")
+ target_link_libraries(DevIL::ILU INTERFACE DevIL::IL)
+ endif()
+
+ # ILUT (if found)
+ if(NOT TARGET DevIL::ILUT AND DevIL_ILUT_FOUND)
+ add_library(DevIL::ILUT UNKNOWN IMPORTED)
+ set_target_properties(DevIL::ILUT PROPERTIES
+ IMPORTED_LOCATION "${ILUT_LIBRARIES}")
+ target_link_libraries(DevIL::ILUT INTERFACE DevIL::ILU)
+ endif()
+endif()
diff --git a/Modules/FindDoxygen.cmake b/Modules/FindDoxygen.cmake
new file mode 100644
index 0000000..4a16e31
--- /dev/null
+++ b/Modules/FindDoxygen.cmake
@@ -0,0 +1,1177 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindDoxygen
+-----------
+
+Doxygen is a documentation generation tool (see http://www.doxygen.org).
+This module looks for Doxygen and some optional tools it supports:
+
+``dot``
+ `Graphviz <http://graphviz.org>`_ ``dot`` utility used to render various
+ graphs.
+``mscgen``
+ `Message Chart Generator <http://www.mcternan.me.uk/mscgen/>`_ utility used
+ by Doxygen's ``\msc`` and ``\mscfile`` commands.
+``dia``
+ `Dia <https://wiki.gnome.org/Apps/Dia>`_ the diagram editor used by Doxygen's
+ ``\diafile`` command.
+
+.. versionadded:: 3.9
+ These tools are available as components in the :command:`find_package` command.
+ For example:
+
+.. code-block:: cmake
+
+ # Require dot, treat the other components as optional
+ find_package(Doxygen
+ REQUIRED dot
+ OPTIONAL_COMPONENTS mscgen dia)
+
+The following variables are defined by this module:
+
+.. variable:: DOXYGEN_FOUND
+
+ True if the ``doxygen`` executable was found.
+
+.. variable:: DOXYGEN_VERSION
+
+ The version reported by ``doxygen --version``.
+
+.. versionadded:: 3.9
+ The module defines ``IMPORTED`` targets for Doxygen and each component found.
+ These can be used as part of custom commands, etc. and should be preferred over
+ old-style (and now deprecated) variables like ``DOXYGEN_EXECUTABLE``. The
+ following import targets are defined if their corresponding executable could be
+ found (the component import targets will only be defined if that component was
+ requested):
+
+::
+
+ Doxygen::doxygen
+ Doxygen::dot
+ Doxygen::mscgen
+ Doxygen::dia
+
+
+Functions
+^^^^^^^^^
+
+.. command:: doxygen_add_docs
+
+ .. versionadded:: 3.9
+
+ This function is intended as a convenience for adding a target for generating
+ documentation with Doxygen. It aims to provide sensible defaults so that
+ projects can generally just provide the input files and directories and that
+ will be sufficient to give sensible results. The function supports the
+ ability to customize the Doxygen configuration used to build the
+ documentation.
+
+ ::
+
+ doxygen_add_docs(targetName
+ [filesOrDirs...]
+ [ALL]
+ [USE_STAMP_FILE]
+ [WORKING_DIRECTORY dir]
+ [COMMENT comment])
+
+ The function constructs a ``Doxyfile`` and defines a custom target that runs
+ Doxygen on that generated file. The listed files and directories are used as
+ the ``INPUT`` of the generated ``Doxyfile`` and they can contain wildcards.
+ Any files that are listed explicitly will also be added as ``SOURCES`` of the
+ custom target so they will show up in an IDE project's source list.
+
+ So that relative input paths work as expected, by default the working
+ directory of the Doxygen command will be the current source directory (i.e.
+ :variable:`CMAKE_CURRENT_SOURCE_DIR`). This can be overridden with the
+ ``WORKING_DIRECTORY`` option to change the directory used as the relative
+ base point. Note also that Doxygen's default behavior is to strip the working
+ directory from relative paths in the generated documentation (see the
+ ``STRIP_FROM_PATH`` `Doxygen config option
+ <http://www.doxygen.org/manual/config.html>`_ for details).
+
+ If provided, the optional ``comment`` will be passed as the ``COMMENT`` for
+ the :command:`add_custom_target` command used to create the custom target
+ internally.
+
+ .. versionadded:: 3.12
+ If ``ALL`` is set, the target will be added to the default build target.
+
+ .. versionadded:: 3.16
+ If ``USE_STAMP_FILE`` is set, the custom command defined by this function will
+ create a stamp file with the name ``<targetName>.stamp`` in the current
+ binary directory whenever doxygen is re-run. With this option present, all
+ items in ``<filesOrDirs>`` must be files (i.e. no directories, symlinks or
+ wildcards) and each of the files must exist at the time
+ ``doxygen_add_docs()`` is called. An error will be raised if any of the
+ items listed is missing or is not a file when ``USE_STAMP_FILE`` is given.
+ A dependency will be created on each of the files so that doxygen will only
+ be re-run if one of the files is updated. Without the ``USE_STAMP_FILE``
+ option, doxygen will always be re-run if the ``<targetName>`` target is built
+ regardless of whether anything listed in ``<filesOrDirs>`` has changed.
+
+ The contents of the generated ``Doxyfile`` can be customized by setting CMake
+ variables before calling ``doxygen_add_docs()``. Any variable with a name of
+ the form ``DOXYGEN_<tag>`` will have its value substituted for the
+ corresponding ``<tag>`` configuration option in the ``Doxyfile``. See the
+ `Doxygen documentation <http://www.doxygen.org/manual/config.html>`_ for the
+ full list of supported configuration options.
+
+ Some of Doxygen's defaults are overridden to provide more appropriate
+ behavior for a CMake project. Each of the following will be explicitly set
+ unless the variable already has a value before ``doxygen_add_docs()`` is
+ called (with some exceptions noted):
+
+ .. variable:: DOXYGEN_HAVE_DOT
+
+ Set to ``YES`` if the ``dot`` component was requested and it was found,
+ ``NO`` otherwise. Any existing value of ``DOXYGEN_HAVE_DOT`` is ignored.
+
+ .. variable:: DOXYGEN_DOT_MULTI_TARGETS
+
+ Set to ``YES`` by this module (note that this requires a ``dot`` version
+ newer than 1.8.10). This option is only meaningful if ``DOXYGEN_HAVE_DOT``
+ is also set to ``YES``.
+
+ .. variable:: DOXYGEN_GENERATE_LATEX
+
+ Set to ``NO`` by this module.
+
+ .. variable:: DOXYGEN_WARN_FORMAT
+
+ For Visual Studio based generators, this is set to the form recognized by
+ the Visual Studio IDE: ``$file($line) : $text``. For all other generators,
+ Doxygen's default value is not overridden.
+
+ .. variable:: DOXYGEN_PROJECT_NAME
+
+ Populated with the name of the current project (i.e.
+ :variable:`PROJECT_NAME`).
+
+ .. variable:: DOXYGEN_PROJECT_NUMBER
+
+ Populated with the version of the current project (i.e.
+ :variable:`PROJECT_VERSION`).
+
+ .. variable:: DOXYGEN_PROJECT_BRIEF
+
+ Populated with the description of the current project (i.e.
+ :variable:`PROJECT_DESCRIPTION`).
+
+ .. variable:: DOXYGEN_INPUT
+
+ Projects should not set this variable. It will be populated with the set of
+ files and directories passed to ``doxygen_add_docs()``, thereby providing
+ consistent behavior with the other built-in commands like
+ :command:`add_executable`, :command:`add_library` and
+ :command:`add_custom_target`. If a variable named ``DOXYGEN_INPUT`` is set
+ by the project, it will be ignored and a warning will be issued.
+
+ .. variable:: DOXYGEN_RECURSIVE
+
+ Set to ``YES`` by this module.
+
+ .. variable:: DOXYGEN_EXCLUDE_PATTERNS
+
+ If the set of inputs includes directories, this variable will specify
+ patterns used to exclude files from them. The following patterns are added
+ by ``doxygen_add_docs()`` to ensure CMake-specific files and directories
+ are not included in the input. If the project sets
+ ``DOXYGEN_EXCLUDE_PATTERNS``, those contents are merged with these
+ additional patterns rather than replacing them:
+
+ ::
+
+ */.git/*
+ */.svn/*
+ */.hg/*
+ */CMakeFiles/*
+ */_CPack_Packages/*
+ DartConfiguration.tcl
+ CMakeLists.txt
+ CMakeCache.txt
+
+ .. variable:: DOXYGEN_OUTPUT_DIRECTORY
+
+ Set to :variable:`CMAKE_CURRENT_BINARY_DIR` by this module. Note that if
+ the project provides its own value for this and it is a relative path, it
+ will be converted to an absolute path relative to the current binary
+ directory. This is necessary because doxygen will normally be run from a
+ directory within the source tree so that relative source paths work as
+ expected. If this directory does not exist, it will be recursively created
+ prior to executing the doxygen commands.
+
+To change any of these defaults or override any other Doxygen config option,
+set relevant variables before calling ``doxygen_add_docs()``. For example:
+
+ .. code-block:: cmake
+
+ set(DOXYGEN_GENERATE_HTML NO)
+ set(DOXYGEN_GENERATE_MAN YES)
+
+ doxygen_add_docs(
+ doxygen
+ ${PROJECT_SOURCE_DIR}
+ COMMENT "Generate man pages"
+ )
+
+A number of Doxygen config options accept lists of values, but Doxygen requires
+them to be separated by whitespace. CMake variables hold lists as a string with
+items separated by semi-colons, so a conversion needs to be performed. The
+``doxygen_add_docs()`` command specifically checks the following Doxygen config
+options and will convert their associated CMake variable's contents into the
+required form if set. CMake variables are named ``DOXYGEN_<name>`` for the
+Doxygen settings specified here.
+
+::
+
+ ABBREVIATE_BRIEF
+ ALIASES
+ CITE_BIB_FILES
+ DIAFILE_DIRS
+ DOTFILE_DIRS
+ DOT_FONTPATH
+ ENABLED_SECTIONS
+ EXAMPLE_PATH
+ EXAMPLE_PATTERNS
+ EXCLUDE
+ EXCLUDE_PATTERNS
+ EXCLUDE_SYMBOLS
+ EXPAND_AS_DEFINED
+ EXTENSION_MAPPING
+ EXTRA_PACKAGES
+ EXTRA_SEARCH_MAPPINGS
+ FILE_PATTERNS
+ FILTER_PATTERNS
+ FILTER_SOURCE_PATTERNS
+ HTML_EXTRA_FILES
+ HTML_EXTRA_STYLESHEET
+ IGNORE_PREFIX
+ IMAGE_PATH
+ INCLUDE_FILE_PATTERNS
+ INCLUDE_PATH
+ INPUT
+ LATEX_EXTRA_FILES
+ LATEX_EXTRA_STYLESHEET
+ MATHJAX_EXTENSIONS
+ MSCFILE_DIRS
+ PLANTUML_INCLUDE_PATH
+ PREDEFINED
+ QHP_CUST_FILTER_ATTRS
+ QHP_SECT_FILTER_ATTRS
+ STRIP_FROM_INC_PATH
+ STRIP_FROM_PATH
+ TAGFILES
+ TCL_SUBST
+
+The following single value Doxygen options will be quoted automatically
+if they contain at least one space:
+
+::
+
+ CHM_FILE
+ DIA_PATH
+ DOCBOOK_OUTPUT
+ DOCSET_FEEDNAME
+ DOCSET_PUBLISHER_NAME
+ DOT_FONTNAME
+ DOT_PATH
+ EXTERNAL_SEARCH_ID
+ FILE_VERSION_FILTER
+ GENERATE_TAGFILE
+ HHC_LOCATION
+ HTML_FOOTER
+ HTML_HEADER
+ HTML_OUTPUT
+ HTML_STYLESHEET
+ INPUT_FILTER
+ LATEX_FOOTER
+ LATEX_HEADER
+ LATEX_OUTPUT
+ LAYOUT_FILE
+ MAN_OUTPUT
+ MAN_SUBDIR
+ MATHJAX_CODEFILE
+ MSCGEN_PATH
+ OUTPUT_DIRECTORY
+ PERL_PATH
+ PLANTUML_JAR_PATH
+ PROJECT_BRIEF
+ PROJECT_LOGO
+ PROJECT_NAME
+ QCH_FILE
+ QHG_LOCATION
+ QHP_CUST_FILTER_NAME
+ QHP_VIRTUAL_FOLDER
+ RTF_EXTENSIONS_FILE
+ RTF_OUTPUT
+ RTF_STYLESHEET_FILE
+ SEARCHDATA_FILE
+ USE_MDFILE_AS_MAINPAGE
+ WARN_FORMAT
+ WARN_LOGFILE
+ XML_OUTPUT
+
+.. versionadded:: 3.11
+ There are situations where it may be undesirable for a particular config option
+ to be automatically quoted by ``doxygen_add_docs()``, such as ``ALIASES`` which
+ may need to include its own embedded quoting. The ``DOXYGEN_VERBATIM_VARS``
+ variable can be used to specify a list of Doxygen variables (including the
+ leading ``DOXYGEN_`` prefix) which should not be quoted. The project is then
+ responsible for ensuring that those variables' values make sense when placed
+ directly in the Doxygen input file. In the case of list variables, list items
+ are still separated by spaces, it is only the automatic quoting that is
+ skipped. For example, the following allows ``doxygen_add_docs()`` to apply
+ quoting to ``DOXYGEN_PROJECT_BRIEF``, but not each item in the
+ ``DOXYGEN_ALIASES`` list (:ref:`bracket syntax <Bracket Argument>` can also
+ be used to make working with embedded quotes easier):
+
+.. code-block:: cmake
+
+ set(DOXYGEN_PROJECT_BRIEF "String with spaces")
+ set(DOXYGEN_ALIASES
+ [[somealias="@some_command param"]]
+ "anotherAlias=@foobar"
+ )
+ set(DOXYGEN_VERBATIM_VARS DOXYGEN_ALIASES)
+
+The resultant ``Doxyfile`` will contain the following lines:
+
+.. code-block:: text
+
+ PROJECT_BRIEF = "String with spaces"
+ ALIASES = somealias="@some_command param" anotherAlias=@foobar
+
+
+Deprecated Result Variables
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. deprecated:: 3.9
+
+For compatibility with previous versions of CMake, the following variables
+are also defined but they are deprecated and should no longer be used:
+
+.. variable:: DOXYGEN_EXECUTABLE
+
+ The path to the ``doxygen`` command. If projects need to refer to the
+ ``doxygen`` executable directly, they should use the ``Doxygen::doxygen``
+ import target instead.
+
+.. variable:: DOXYGEN_DOT_FOUND
+
+ True if the ``dot`` executable was found.
+
+.. variable:: DOXYGEN_DOT_EXECUTABLE
+
+ The path to the ``dot`` command. If projects need to refer to the ``dot``
+ executable directly, they should use the ``Doxygen::dot`` import target
+ instead.
+
+.. variable:: DOXYGEN_DOT_PATH
+
+ The path to the directory containing the ``dot`` executable as reported in
+ ``DOXYGEN_DOT_EXECUTABLE``. The path may have forward slashes even on Windows
+ and is not suitable for direct substitution into a ``Doxyfile.in`` template.
+ If you need this value, get the :prop_tgt:`IMPORTED_LOCATION` property of the
+ ``Doxygen::dot`` target and use :command:`get_filename_component` to extract
+ the directory part of that path. You may also want to consider using
+ :command:`file(TO_NATIVE_PATH)` to prepare the path for a Doxygen
+ configuration file.
+
+
+Deprecated Hint Variables
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. deprecated:: 3.9
+
+.. variable:: DOXYGEN_SKIP_DOT
+
+ This variable has no effect for the component form of ``find_package``.
+ In backward compatibility mode (i.e. without components list) it prevents
+ the finder module from searching for Graphviz's ``dot`` utility.
+
+#]=======================================================================]
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0054 NEW) # quoted if arguments
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+# For backwards compatibility support
+if(Doxygen_FIND_QUIETLY)
+ set(DOXYGEN_FIND_QUIETLY TRUE)
+endif()
+
+# ===== Rationale for OS X AppBundle mods below =====
+# With the OS X GUI version, Doxygen likes to be installed to /Applications
+# and it contains the doxygen executable in the bundle. In the versions I've
+# seen, it is located in Resources, but in general, more often binaries are
+# located in MacOS.
+#
+# NOTE: The official Doxygen.app distributed for OS X uses non-standard
+# conventions. Instead of the command-line "doxygen" tool being placed in
+# Doxygen.app/Contents/MacOS, "Doxywizard" is placed there instead and
+# "doxygen" is placed in Contents/Resources. This is most likely done
+# so that something happens when people double-click on the Doxygen.app
+# package. Unfortunately, CMake gets confused by this as when it sees the
+# bundle it uses "Doxywizard" as the executable to use instead of
+# "doxygen". Therefore to work-around this issue we temporarily disable
+# the app-bundle feature, just for this CMake module:
+#
+if(APPLE)
+ # Save the old setting
+ set(TEMP_DOXYGEN_SAVE_CMAKE_FIND_APPBUNDLE ${CMAKE_FIND_APPBUNDLE})
+ # Disable the App-bundle detection feature
+ set(CMAKE_FIND_APPBUNDLE "NEVER")
+endif()
+# FYI:
+# In older versions of OS X Doxygen, dot was included with the Doxygen bundle,
+# but newer versions require you to download Graphviz.app which contains "dot"
+# or use something like homebrew.
+# ============== End OSX stuff ================
+
+#
+# Find Doxygen...
+#
+macro(_Doxygen_find_doxygen)
+ find_program(
+ DOXYGEN_EXECUTABLE
+ NAMES doxygen
+ PATHS
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\doxygen_is1;Inno Setup: App Path]/bin"
+ /Applications/Doxygen.app/Contents/Resources
+ /Applications/Doxygen.app/Contents/MacOS
+ /Applications/Utilities/Doxygen.app/Contents/Resources
+ /Applications/Utilities/Doxygen.app/Contents/MacOS
+ DOC "Doxygen documentation generation tool (http://www.doxygen.org)"
+ )
+ mark_as_advanced(DOXYGEN_EXECUTABLE)
+
+ if(DOXYGEN_EXECUTABLE)
+ execute_process(
+ COMMAND "${DOXYGEN_EXECUTABLE}" --version
+ OUTPUT_VARIABLE DOXYGEN_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ RESULT_VARIABLE _Doxygen_version_result
+ )
+ if(_Doxygen_version_result)
+ message(WARNING "Unable to determine doxygen version: ${_Doxygen_version_result}")
+ endif()
+
+ # Create an imported target for Doxygen
+ if(NOT TARGET Doxygen::doxygen)
+ add_executable(Doxygen::doxygen IMPORTED GLOBAL)
+ set_target_properties(Doxygen::doxygen PROPERTIES
+ IMPORTED_LOCATION "${DOXYGEN_EXECUTABLE}"
+ )
+ endif()
+ endif()
+endmacro()
+
+#
+# Find Diagram Editor...
+#
+macro(_Doxygen_find_dia)
+ set(_x86 "(x86)")
+ find_program(
+ DOXYGEN_DIA_EXECUTABLE
+ NAMES dia
+ PATHS
+ "$ENV{ProgramFiles}/Dia"
+ "$ENV{ProgramFiles${_x86}}/Dia"
+ DOC "Diagram Editor tool for use with Doxygen"
+ )
+ mark_as_advanced(DOXYGEN_DIA_EXECUTABLE)
+
+ if(DOXYGEN_DIA_EXECUTABLE)
+ # The Doxyfile wants the path to the utility, not the entire path
+ # including file name
+ get_filename_component(DOXYGEN_DIA_PATH
+ "${DOXYGEN_DIA_EXECUTABLE}"
+ DIRECTORY)
+ if(WIN32)
+ file(TO_NATIVE_PATH "${DOXYGEN_DIA_PATH}" DOXYGEN_DIA_PATH)
+ endif()
+
+ # Create an imported target for component
+ if(NOT TARGET Doxygen::dia)
+ add_executable(Doxygen::dia IMPORTED GLOBAL)
+ set_target_properties(Doxygen::dia PROPERTIES
+ IMPORTED_LOCATION "${DOXYGEN_DIA_EXECUTABLE}"
+ )
+ endif()
+ endif()
+
+ unset(_x86)
+endmacro()
+
+#
+# Find Graphviz Dot...
+#
+macro(_Doxygen_find_dot)
+ if(WIN32)
+ set(_x86 "(x86)")
+ file(
+ GLOB _Doxygen_GRAPHVIZ_BIN_DIRS
+ "$ENV{ProgramFiles}/Graphviz*/bin"
+ "$ENV{ProgramFiles${_x86}}/Graphviz*/bin"
+ )
+ unset(_x86)
+ else()
+ set(_Doxygen_GRAPHVIZ_BIN_DIRS "")
+ endif()
+
+ find_program(
+ DOXYGEN_DOT_EXECUTABLE
+ NAMES dot
+ PATHS
+ ${_Doxygen_GRAPHVIZ_BIN_DIRS}
+ "$ENV{ProgramFiles}/ATT/Graphviz/bin"
+ "C:/Program Files/ATT/Graphviz/bin"
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\ATT\\Graphviz;InstallPath]/bin
+ /Applications/Graphviz.app/Contents/MacOS
+ /Applications/Utilities/Graphviz.app/Contents/MacOS
+ /Applications/Doxygen.app/Contents/Resources
+ /Applications/Doxygen.app/Contents/MacOS
+ /Applications/Utilities/Doxygen.app/Contents/Resources
+ /Applications/Utilities/Doxygen.app/Contents/MacOS
+ DOC "Dot tool for use with Doxygen"
+ )
+ mark_as_advanced(DOXYGEN_DOT_EXECUTABLE)
+
+ if(DOXYGEN_DOT_EXECUTABLE)
+ # The Doxyfile wants the path to the utility, not the entire path
+ # including file name
+ get_filename_component(DOXYGEN_DOT_PATH
+ "${DOXYGEN_DOT_EXECUTABLE}"
+ DIRECTORY)
+ if(WIN32)
+ file(TO_NATIVE_PATH "${DOXYGEN_DOT_PATH}" DOXYGEN_DOT_PATH)
+ endif()
+
+ # Create an imported target for component
+ if(NOT TARGET Doxygen::dot)
+ add_executable(Doxygen::dot IMPORTED GLOBAL)
+ set_target_properties(Doxygen::dot PROPERTIES
+ IMPORTED_LOCATION "${DOXYGEN_DOT_EXECUTABLE}"
+ )
+ endif()
+ endif()
+
+ unset(_Doxygen_GRAPHVIZ_BIN_DIRS)
+endmacro()
+
+#
+# Find Message Sequence Chart...
+#
+macro(_Doxygen_find_mscgen)
+ set(_x86 "(x86)")
+ find_program(
+ DOXYGEN_MSCGEN_EXECUTABLE
+ NAMES mscgen
+ PATHS
+ "$ENV{ProgramFiles}/Mscgen"
+ "$ENV{ProgramFiles${_x86}}/Mscgen"
+ DOC "Message sequence chart tool for use with Doxygen"
+ )
+ mark_as_advanced(DOXYGEN_MSCGEN_EXECUTABLE)
+
+ if(DOXYGEN_MSCGEN_EXECUTABLE)
+ # The Doxyfile wants the path to the utility, not the entire path
+ # including file name
+ get_filename_component(DOXYGEN_MSCGEN_PATH
+ "${DOXYGEN_MSCGEN_EXECUTABLE}"
+ DIRECTORY)
+ if(WIN32)
+ file(TO_NATIVE_PATH "${DOXYGEN_MSCGEN_PATH}" DOXYGEN_MSCGEN_PATH)
+ endif()
+
+ # Create an imported target for component
+ if(NOT TARGET Doxygen::mscgen)
+ add_executable(Doxygen::mscgen IMPORTED GLOBAL)
+ set_target_properties(Doxygen::mscgen PROPERTIES
+ IMPORTED_LOCATION "${DOXYGEN_MSCGEN_EXECUTABLE}"
+ )
+ endif()
+ endif()
+
+ unset(_x86)
+endmacro()
+
+# Make sure `doxygen` is one of the components to find
+set(_Doxygen_keep_backward_compat FALSE)
+if(NOT Doxygen_FIND_COMPONENTS)
+ # Search at least for `doxygen` executable
+ set(Doxygen_FIND_COMPONENTS doxygen)
+ # Preserve backward compatibility:
+ # search for `dot` also if `DOXYGEN_SKIP_DOT` is not explicitly disable this.
+ if(NOT DOXYGEN_SKIP_DOT)
+ list(APPEND Doxygen_FIND_COMPONENTS dot)
+ endif()
+ set(_Doxygen_keep_backward_compat TRUE)
+elseif(NOT doxygen IN_LIST Doxygen_FIND_COMPONENTS)
+ list(INSERT Doxygen_FIND_COMPONENTS 0 doxygen)
+endif()
+
+#
+# Find all requested components of Doxygen...
+#
+foreach(_comp IN LISTS Doxygen_FIND_COMPONENTS)
+ if(_comp STREQUAL "doxygen")
+ _Doxygen_find_doxygen()
+ elseif(_comp STREQUAL "dia")
+ _Doxygen_find_dia()
+ elseif(_comp STREQUAL "dot")
+ _Doxygen_find_dot()
+ elseif(_comp STREQUAL "mscgen")
+ _Doxygen_find_mscgen()
+ else()
+ message(WARNING "${_comp} is not a valid Doxygen component")
+ set(Doxygen_${_comp}_FOUND FALSE)
+ continue()
+ endif()
+
+ if(TARGET Doxygen::${_comp})
+ set(Doxygen_${_comp}_FOUND TRUE)
+ else()
+ set(Doxygen_${_comp}_FOUND FALSE)
+ endif()
+endforeach()
+unset(_comp)
+
+# Verify find results
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(
+ Doxygen
+ REQUIRED_VARS DOXYGEN_EXECUTABLE
+ VERSION_VAR DOXYGEN_VERSION
+ HANDLE_COMPONENTS
+)
+
+#
+# Backwards compatibility...
+#
+if(APPLE)
+ # Restore the old app-bundle setting
+ set(CMAKE_FIND_APPBUNDLE ${TEMP_DOXYGEN_SAVE_CMAKE_FIND_APPBUNDLE})
+endif()
+
+# Maintain the _FOUND variables as "YES" or "NO" for backwards
+# compatibility. This allows people to substitute them directly into
+# Doxyfile with configure_file().
+if(DOXYGEN_FOUND)
+ set(DOXYGEN_FOUND "YES")
+else()
+ set(DOXYGEN_FOUND "NO")
+endif()
+if(_Doxygen_keep_backward_compat)
+ if(Doxygen_dot_FOUND)
+ set(DOXYGEN_DOT_FOUND "YES")
+ else()
+ set(DOXYGEN_DOT_FOUND "NO")
+ endif()
+
+ # For backwards compatibility support for even older CMake versions
+ set(DOXYGEN ${DOXYGEN_EXECUTABLE})
+ set(DOT ${DOXYGEN_DOT_EXECUTABLE})
+
+ # No need to keep any backward compatibility for `DOXYGEN_MSCGEN_XXX`
+ # and `DOXYGEN_DIA_XXX` since they were not supported before component
+ # support was added
+endif()
+unset(_Doxygen_keep_backward_compat)
+
+#
+# Allow full control of Doxygen from CMakeLists.txt
+#
+
+# Prepare a template Doxyfile and Doxygen's default values CMake file
+if(TARGET Doxygen::doxygen)
+ # If doxygen was found, use it to generate a minimal default Doxyfile.
+ # We will delete this file after we have finished using it below to
+ # generate the other files that doxygen_add_docs() will use.
+ set(_Doxygen_tpl "${CMAKE_BINARY_DIR}/CMakeDoxyfile.tpl")
+ execute_process(
+ COMMAND "${DOXYGEN_EXECUTABLE}" -s -g "${_Doxygen_tpl}"
+ OUTPUT_QUIET
+ RESULT_VARIABLE _Doxygen_tpl_result
+ )
+ if(_Doxygen_tpl_result)
+ message(FATAL_ERROR
+ "Unable to generate Doxyfile template: ${_Doxygen_tpl_result}")
+ elseif(NOT EXISTS "${_Doxygen_tpl}")
+ message(FATAL_ERROR
+ "Doxygen has failed to generate a Doxyfile template")
+ endif()
+
+ # Write a do-not-edit header to files we are going to generate...
+ set(_Doxygen_dne_header
+[[
+#
+# DO NOT EDIT! THIS FILE WAS GENERATED BY CMAKE!
+#
+
+]]
+ )
+ # We only need one copy of these across the whole build, since their
+ # content is only dependent on the version of Doxygen being used. Therefore
+ # we always put them at the top of the build tree so that they are in a
+ # predictable location.
+ set(_doxyfile_in "${CMAKE_BINARY_DIR}/CMakeDoxyfile.in")
+ set(_doxyfile_defaults "${CMAKE_BINARY_DIR}/CMakeDoxygenDefaults.cmake")
+
+ set(_doxyfile_in_contents "")
+ set(_doxyfile_defaults_contents "")
+
+ # Get strings containing a configuration key from the template Doxyfile
+ # we obtained from this version of Doxygen. Because some options are split
+ # across multiple lines by ending lines with backslashes, we cannot just
+ # use file(STRINGS...) with a REGEX. Instead, read lines without a REGEX
+ # so that file(STRINGS...) handles the trailing backslash as a line
+ # continuation. It stores multi-lines as lists, so we then have to replace
+ # the ";" list separator with backslashed newlines again so that we get the
+ # original content stored back as the value part.
+ file(STRINGS "${_Doxygen_tpl}" _file_lines)
+ unset(_Doxygen_tpl_params)
+ foreach(_line IN LISTS _file_lines)
+ if(_line MATCHES "([A-Z][A-Z0-9_]+)( *=)(.*)")
+ set(_key "${CMAKE_MATCH_1}")
+ set(_eql "${CMAKE_MATCH_2}")
+ set(_value "${CMAKE_MATCH_3}")
+ string(REPLACE "\\" "\\\\" _value "${_value}")
+ string(REPLACE ";" "\\\n" _value "${_value}")
+ list(APPEND _Doxygen_tpl_params "${_key}${_eql}${_value}")
+ endif()
+ endforeach()
+
+ # Build up a Doxyfile that provides @configVar@ substitutions for each
+ # Doxygen config option as well as a separate CMake script which provides
+ # the default value for each of those options if the project doesn't supply
+ # them. Each config option will support substitution of a CMake variable
+ # of the same name except with DOXYGEN_ prepended.
+ foreach(_Doxygen_param IN LISTS _Doxygen_tpl_params)
+ if(_Doxygen_param MATCHES "([A-Z][A-Z0-9_]+)( *)=( (.*))?")
+ # Ok, this is a config key with a value
+ if(CMAKE_MATCH_COUNT EQUAL 4)
+ string(APPEND _doxyfile_in_contents
+ "${CMAKE_MATCH_1}${CMAKE_MATCH_2}= @DOXYGEN_${CMAKE_MATCH_1}@\n")
+ # Remove the backslashes we had to preserve to handle newlines
+ string(REPLACE "\\\n" "\n" _value "${CMAKE_MATCH_4}")
+ string(APPEND _doxyfile_defaults_contents
+"if(NOT DEFINED DOXYGEN_${CMAKE_MATCH_1})
+ set(DOXYGEN_${CMAKE_MATCH_1} ${_value})
+endif()
+")
+ # Ok, this is a config key with empty default value
+ elseif(CMAKE_MATCH_COUNT EQUAL 2)
+ string(APPEND _doxyfile_in_contents
+ "${CMAKE_MATCH_1}${CMAKE_MATCH_2}= @DOXYGEN_${CMAKE_MATCH_1}@\n")
+ else()
+ message(AUTHOR_WARNING
+"Unexpected line format! Code review required!\nFault line: ${_Doxygen_param}")
+ endif()
+ else()
+ message(AUTHOR_WARNING
+"Unexpected line format! Code review required!\nFault line: ${_Doxygen_param}")
+ endif()
+ endforeach()
+ file(WRITE "${_doxyfile_defaults}" "${_Doxygen_dne_header}"
+ "${_doxyfile_defaults_contents}")
+ file(WRITE "${_doxyfile_in}" "${_Doxygen_dne_header}"
+ "${_doxyfile_in_contents}")
+
+ # Ok, dumped defaults are not needed anymore...
+ file(REMOVE "${_Doxygen_tpl}")
+
+ unset(_Doxygen_param)
+ unset(_Doxygen_tpl_params)
+ unset(_Doxygen_dne_header)
+ unset(_Doxygen_tpl)
+
+endif()
+
+function(doxygen_quote_value VARIABLE)
+ # Quote a value of the given variable if:
+ # - VARIABLE parameter was really given
+ # - the variable it names is defined and is not present in the list
+ # specified by DOXYGEN_VERBATIM_VARS (if set)
+ # - the value of the named variable isn't already quoted
+ # - the value has spaces
+ if(VARIABLE AND DEFINED ${VARIABLE} AND
+ NOT ${VARIABLE} MATCHES "^\".* .*\"$" AND ${VARIABLE} MATCHES " " AND
+ NOT (DEFINED DOXYGEN_VERBATIM_VARS AND
+ "${VARIABLE}" IN_LIST DOXYGEN_VERBATIM_VARS))
+ set(${VARIABLE} "\"${${VARIABLE}}\"" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(doxygen_list_to_quoted_strings LIST_VARIABLE)
+ if(LIST_VARIABLE AND DEFINED ${LIST_VARIABLE})
+ unset(_inputs)
+ unset(_sep)
+ unset(_verbatim)
+ # Have to test if list items should be treated as verbatim here
+ # because we lose the variable name when we pass just one list item
+ # to doxygen_quote_value() below
+ if(DEFINED DOXYGEN_VERBATIM_VARS AND
+ "${LIST_VARIABLE}" IN_LIST DOXYGEN_VERBATIM_VARS)
+ set(_verbatim True)
+ endif()
+ foreach(_in IN LISTS ${LIST_VARIABLE})
+ if(NOT _verbatim)
+ doxygen_quote_value(_in)
+ endif()
+ string(APPEND _inputs "${_sep}${_in}")
+ set(_sep " ")
+ endforeach()
+ set(${LIST_VARIABLE} "${_inputs}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(doxygen_add_docs targetName)
+ set(_options ALL USE_STAMP_FILE)
+ set(_one_value_args WORKING_DIRECTORY COMMENT)
+ set(_multi_value_args)
+ cmake_parse_arguments(_args
+ "${_options}"
+ "${_one_value_args}"
+ "${_multi_value_args}"
+ ${ARGN})
+
+ if(NOT _args_COMMENT)
+ set(_args_COMMENT "Generate API documentation for ${targetName}")
+ endif()
+
+ if(NOT _args_WORKING_DIRECTORY)
+ set(_args_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
+ endif()
+
+ if(DEFINED DOXYGEN_INPUT)
+ message(WARNING
+"DOXYGEN_INPUT is set but it will be ignored. Pass the files and directories \
+directly to the doxygen_add_docs() command instead.")
+ endif()
+ set(DOXYGEN_INPUT ${_args_UNPARSED_ARGUMENTS})
+
+ if(NOT TARGET Doxygen::doxygen)
+ message(FATAL_ERROR "Doxygen was not found, needed by \
+doxygen_add_docs() for target ${targetName}")
+ endif()
+
+ # If not already defined, set some relevant defaults based on the
+ # assumption that the documentation is for the whole project. Details
+ # specified in the project() command will be used to populate a number of
+ # these defaults.
+
+ if(NOT DEFINED DOXYGEN_PROJECT_NAME)
+ # The PROJECT_NAME tag is a single word (or a sequence of words
+ # surrounded by double-quotes, unless you are using Doxywizard) that
+ # should identify the project for which the documentation is generated.
+ # This name is used in the title of most generated pages and in a few
+ # other places. The default value is: My Project.
+ set(DOXYGEN_PROJECT_NAME ${PROJECT_NAME})
+ endif()
+
+ if(NOT DEFINED DOXYGEN_PROJECT_NUMBER)
+ # The PROJECT_NUMBER tag can be used to enter a project or revision
+ # number. This could be handy for archiving the generated documentation
+ # or if some version control system is used.
+ set(DOXYGEN_PROJECT_NUMBER ${PROJECT_VERSION})
+ endif()
+
+ if(NOT DEFINED DOXYGEN_PROJECT_BRIEF)
+ # Using the PROJECT_BRIEF tag one can provide an optional one line
+ # description for a project that appears at the top of each page and
+ # should give viewer a quick idea about the purpose of the project.
+ # Keep the description short.
+ set(DOXYGEN_PROJECT_BRIEF "${PROJECT_DESCRIPTION}")
+ endif()
+
+ if(NOT DEFINED DOXYGEN_RECURSIVE)
+ # The RECURSIVE tag can be used to specify whether or not
+ # subdirectories should be searched for input files as well. CMake
+ # projects generally evolve to span multiple directories, so it makes
+ # more sense for this to be on by default. Doxygen's default value
+ # has this setting turned off, so we override it.
+ set(DOXYGEN_RECURSIVE YES)
+ endif()
+
+ if(NOT DEFINED DOXYGEN_OUTPUT_DIRECTORY)
+ # The OUTPUT_DIRECTORY tag is used to specify the (relative or
+ # absolute) path into which the generated documentation will be
+ # written. If a relative path is used, Doxygen will interpret it as
+ # being relative to the location where doxygen was started, but we need
+ # to run Doxygen in the source tree so that relative input paths work
+ # intuitively. Therefore, we ensure that the output directory is always
+ # an absolute path and if the project provided a relative path, we
+ # treat it as relative to the current BINARY directory so that output
+ # is not generated inside the source tree.
+ set(DOXYGEN_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+ elseif(NOT IS_ABSOLUTE "${DOXYGEN_OUTPUT_DIRECTORY}")
+ get_filename_component(DOXYGEN_OUTPUT_DIRECTORY
+ "${DOXYGEN_OUTPUT_DIRECTORY}"
+ ABSOLUTE
+ BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+
+ if(NOT DEFINED DOXYGEN_HAVE_DOT)
+ # If you set the HAVE_DOT tag to YES then doxygen will assume the dot
+ # tool is available from the path. This tool is part of Graphviz (see:
+ # http://www.graphviz.org/), a graph visualization toolkit from AT&T
+ # and Lucent Bell Labs. The other options in this section have no
+ # effect if this option is set to NO.
+ # Doxygen's default value is: NO.
+ if(Doxygen_dot_FOUND)
+ set(DOXYGEN_HAVE_DOT "YES")
+ else()
+ set(DOXYGEN_HAVE_DOT "NO")
+ endif()
+ endif()
+
+ if(NOT DEFINED DOXYGEN_DOT_MULTI_TARGETS)
+ # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate
+ # multiple output files in one run (i.e. multiple -o and -T options on
+ # the command line). This makes dot run faster, but since only newer
+ # versions of dot (>1.8.10) support this, Doxygen disables this feature
+ # by default.
+ # This tag requires that the tag HAVE_DOT is set to YES.
+ set(DOXYGEN_DOT_MULTI_TARGETS YES)
+ endif()
+
+ if(NOT DEFINED DOXYGEN_GENERATE_LATEX)
+ # If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX
+ # output. We only want the HTML output enabled by default, so we turn
+ # this off if the project hasn't specified it.
+ set(DOXYGEN_GENERATE_LATEX NO)
+ endif()
+
+ if(NOT DEFINED DOXYGEN_WARN_FORMAT)
+ if(CMAKE_VS_MSBUILD_COMMAND OR CMAKE_VS_DEVENV_COMMAND)
+ # The WARN_FORMAT tag determines the format of the warning messages
+ # that doxygen can produce. The string should contain the $file,
+ # $line and $text tags, which will be replaced by the file and line
+ # number from which the warning originated and the warning text.
+ # Optionally, the format may contain $version, which will be
+ # replaced by the version of the file (if it could be obtained via
+ # FILE_VERSION_FILTER).
+ # Doxygen's default value is: $file:$line: $text
+ set(DOXYGEN_WARN_FORMAT "$file($line) : $text ")
+ endif()
+ endif()
+
+ if(DEFINED DOXYGEN_WARN_LOGFILE AND NOT IS_ABSOLUTE "${DOXYGEN_WARN_LOGFILE}")
+ # The WARN_LOGFILE tag can be used to specify a file to which warning and error
+ # messages should be written. If left blank the output is written to standard
+ # error (stderr).
+ get_filename_component(DOXYGEN_WARN_LOGFILE
+ "${DOXYGEN_WARN_LOGFILE}"
+ ABSOLUTE
+ BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+
+ # Any files from the INPUT that match any of the EXCLUDE_PATTERNS will be
+ # excluded from the set of input files. We provide some additional patterns
+ # to prevent commonly unwanted things from CMake builds being pulled in.
+ #
+ # Note that the wildcards are matched against the file with absolute path,
+ # so to exclude all test directories for example use the pattern */test/*
+ list(
+ APPEND
+ DOXYGEN_EXCLUDE_PATTERNS
+ "*/.git/*"
+ "*/.svn/*"
+ "*/.hg/*"
+ "*/CMakeFiles/*"
+ "*/_CPack_Packages/*"
+ "DartConfiguration.tcl"
+ "CMakeLists.txt"
+ "CMakeCache.txt"
+ )
+
+ # Now bring in Doxgen's defaults for those things the project has not
+ # already set and we have not provided above
+ include("${CMAKE_BINARY_DIR}/CMakeDoxygenDefaults.cmake" OPTIONAL)
+
+ # Cleanup built HTMLs on "make clean"
+ # TODO Any other dirs?
+ if(DOXYGEN_GENERATE_HTML)
+ if(IS_ABSOLUTE "${DOXYGEN_HTML_OUTPUT}")
+ set(_args_clean_html_dir "${DOXYGEN_HTML_OUTPUT}")
+ else()
+ set(_args_clean_html_dir
+ "${DOXYGEN_OUTPUT_DIRECTORY}/${DOXYGEN_HTML_OUTPUT}")
+ endif()
+ set_property(DIRECTORY APPEND PROPERTY
+ ADDITIONAL_CLEAN_FILES "${_args_clean_html_dir}")
+ endif()
+
+ # Build up a list of files we can identify from the inputs so we can list
+ # them as DEPENDS and SOURCES in the custom command/target (the latter
+ # makes them display in IDEs). This must be done before we transform the
+ # various DOXYGEN_... variables below because we need to process
+ # DOXYGEN_INPUT as a list first.
+ unset(_sources)
+ foreach(_item IN LISTS DOXYGEN_INPUT)
+ get_filename_component(_abs_item "${_item}" ABSOLUTE
+ BASE_DIR "${_args_WORKING_DIRECTORY}")
+ get_source_file_property(_isGenerated "${_abs_item}" GENERATED)
+ if(_isGenerated OR
+ (EXISTS "${_abs_item}" AND
+ NOT IS_DIRECTORY "${_abs_item}" AND
+ NOT IS_SYMLINK "${_abs_item}"))
+ list(APPEND _sources "${_abs_item}")
+ elseif(_args_USE_STAMP_FILE)
+ message(FATAL_ERROR "Source does not exist or is not a file:\n"
+ " ${_abs_item}\n"
+ "Only existing files may be specified when the "
+ "USE_STAMP_FILE option is given.")
+ endif()
+ endforeach()
+
+ # Transform known list type options into space separated strings.
+ set(_doxygen_list_options
+ ABBREVIATE_BRIEF
+ ALIASES
+ CITE_BIB_FILES
+ DIAFILE_DIRS
+ DOTFILE_DIRS
+ DOT_FONTPATH
+ ENABLED_SECTIONS
+ EXAMPLE_PATH
+ EXAMPLE_PATTERNS
+ EXCLUDE
+ EXCLUDE_PATTERNS
+ EXCLUDE_SYMBOLS
+ EXPAND_AS_DEFINED
+ EXTENSION_MAPPING
+ EXTRA_PACKAGES
+ EXTRA_SEARCH_MAPPINGS
+ FILE_PATTERNS
+ FILTER_PATTERNS
+ FILTER_SOURCE_PATTERNS
+ HTML_EXTRA_FILES
+ HTML_EXTRA_STYLESHEET
+ IGNORE_PREFIX
+ IMAGE_PATH
+ INCLUDE_FILE_PATTERNS
+ INCLUDE_PATH
+ INPUT
+ LATEX_EXTRA_FILES
+ LATEX_EXTRA_STYLESHEET
+ MATHJAX_EXTENSIONS
+ MSCFILE_DIRS
+ PLANTUML_INCLUDE_PATH
+ PREDEFINED
+ QHP_CUST_FILTER_ATTRS
+ QHP_SECT_FILTER_ATTRS
+ STRIP_FROM_INC_PATH
+ STRIP_FROM_PATH
+ TAGFILES
+ TCL_SUBST
+ )
+ foreach(_item IN LISTS _doxygen_list_options)
+ doxygen_list_to_quoted_strings(DOXYGEN_${_item})
+ endforeach()
+
+ # Transform known single value variables which may contain spaces, such as
+ # paths or description strings.
+ set(_doxygen_quoted_options
+ CHM_FILE
+ DIA_PATH
+ DOCBOOK_OUTPUT
+ DOCSET_FEEDNAME
+ DOCSET_PUBLISHER_NAME
+ DOT_FONTNAME
+ DOT_PATH
+ EXTERNAL_SEARCH_ID
+ FILE_VERSION_FILTER
+ GENERATE_TAGFILE
+ HHC_LOCATION
+ HTML_FOOTER
+ HTML_HEADER
+ HTML_OUTPUT
+ HTML_STYLESHEET
+ INPUT_FILTER
+ LATEX_FOOTER
+ LATEX_HEADER
+ LATEX_OUTPUT
+ LAYOUT_FILE
+ MAN_OUTPUT
+ MAN_SUBDIR
+ MATHJAX_CODEFILE
+ MSCGEN_PATH
+ OUTPUT_DIRECTORY
+ PERL_PATH
+ PLANTUML_JAR_PATH
+ PROJECT_BRIEF
+ PROJECT_LOGO
+ PROJECT_NAME
+ QCH_FILE
+ QHG_LOCATION
+ QHP_CUST_FILTER_NAME
+ QHP_VIRTUAL_FOLDER
+ RTF_EXTENSIONS_FILE
+ RTF_OUTPUT
+ RTF_STYLESHEET_FILE
+ SEARCHDATA_FILE
+ USE_MDFILE_AS_MAINPAGE
+ WARN_FORMAT
+ WARN_LOGFILE
+ XML_OUTPUT
+ )
+
+ # Store the unmodified value of DOXYGEN_OUTPUT_DIRECTORY prior to invoking
+ # doxygen_quote_value() below. This will mutate the string specifically for
+ # consumption by Doxygen's config file, which we do not want when we use it
+ # later in the custom target's commands.
+ set( _original_doxygen_output_dir ${DOXYGEN_OUTPUT_DIRECTORY} )
+
+ foreach(_item IN LISTS _doxygen_quoted_options)
+ doxygen_quote_value(DOXYGEN_${_item})
+ endforeach()
+
+ # Prepare doxygen configuration file
+ set(_doxyfile_template "${CMAKE_BINARY_DIR}/CMakeDoxyfile.in")
+ set(_target_doxyfile "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.${targetName}")
+ configure_file("${_doxyfile_template}" "${_target_doxyfile}")
+
+ unset(_all)
+ if(${_args_ALL})
+ set(_all ALL)
+ endif()
+
+ # Only create the stamp file if asked to. If we don't create it,
+ # the target will always be considered out-of-date.
+ if(_args_USE_STAMP_FILE)
+ set(__stamp_file "${CMAKE_CURRENT_BINARY_DIR}/${targetName}.stamp")
+ add_custom_command(
+ VERBATIM
+ OUTPUT ${__stamp_file}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${_original_doxygen_output_dir}
+ COMMAND "${DOXYGEN_EXECUTABLE}" "${_target_doxyfile}"
+ COMMAND ${CMAKE_COMMAND} -E touch ${__stamp_file}
+ WORKING_DIRECTORY "${_args_WORKING_DIRECTORY}"
+ DEPENDS "${_target_doxyfile}" ${_sources}
+ COMMENT "${_args_COMMENT}"
+ )
+ add_custom_target(${targetName} ${_all}
+ DEPENDS ${__stamp_file}
+ SOURCES ${_sources}
+ )
+ unset(__stamp_file)
+ else()
+ add_custom_target( ${targetName} ${_all} VERBATIM
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${_original_doxygen_output_dir}
+ COMMAND "${DOXYGEN_EXECUTABLE}" "${_target_doxyfile}"
+ WORKING_DIRECTORY "${_args_WORKING_DIRECTORY}"
+ DEPENDS "${_target_doxyfile}" ${_sources}
+ COMMENT "${_args_COMMENT}"
+ SOURCES ${_sources}
+ )
+ endif()
+
+endfunction()
+
+cmake_policy(POP)
diff --git a/Modules/FindEXPAT.cmake b/Modules/FindEXPAT.cmake
new file mode 100644
index 0000000..f9cb432
--- /dev/null
+++ b/Modules/FindEXPAT.cmake
@@ -0,0 +1,83 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindEXPAT
+---------
+
+Find the native Expat headers and library.
+Expat is a stream-oriented XML parser library written in C.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.10
+
+This module defines the following :prop_tgt:`IMPORTED` targets:
+
+``EXPAT::EXPAT``
+ The Expat ``expat`` library, if found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``EXPAT_INCLUDE_DIRS``
+ where to find expat.h, etc.
+``EXPAT_LIBRARIES``
+ the libraries to link against to use Expat.
+``EXPAT_FOUND``
+ true if the Expat headers and libraries were found.
+
+#]=======================================================================]
+
+find_package(PkgConfig QUIET)
+
+pkg_check_modules(PC_EXPAT QUIET expat)
+
+# Look for the header file.
+find_path(EXPAT_INCLUDE_DIR NAMES expat.h HINTS ${PC_EXPAT_INCLUDE_DIRS})
+
+# Look for the library.
+find_library(EXPAT_LIBRARY NAMES expat libexpat NAMES_PER_DIR HINTS ${PC_EXPAT_LIBRARY_DIRS})
+
+if (EXPAT_INCLUDE_DIR AND EXISTS "${EXPAT_INCLUDE_DIR}/expat.h")
+ file(STRINGS "${EXPAT_INCLUDE_DIR}/expat.h" expat_version_str
+ REGEX "^#[\t ]*define[\t ]+XML_(MAJOR|MINOR|MICRO)_VERSION[\t ]+[0-9]+$")
+
+ unset(EXPAT_VERSION_STRING)
+ foreach(VPART MAJOR MINOR MICRO)
+ foreach(VLINE ${expat_version_str})
+ if(VLINE MATCHES "^#[\t ]*define[\t ]+XML_${VPART}_VERSION[\t ]+([0-9]+)$")
+ set(EXPAT_VERSION_PART "${CMAKE_MATCH_1}")
+ if(EXPAT_VERSION_STRING)
+ string(APPEND EXPAT_VERSION_STRING ".${EXPAT_VERSION_PART}")
+ else()
+ set(EXPAT_VERSION_STRING "${EXPAT_VERSION_PART}")
+ endif()
+ endif()
+ endforeach()
+ endforeach()
+endif ()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(EXPAT
+ REQUIRED_VARS EXPAT_LIBRARY EXPAT_INCLUDE_DIR
+ VERSION_VAR EXPAT_VERSION_STRING)
+
+# Copy the results to the output variables and target.
+if(EXPAT_FOUND)
+ set(EXPAT_LIBRARIES ${EXPAT_LIBRARY})
+ set(EXPAT_INCLUDE_DIRS ${EXPAT_INCLUDE_DIR})
+
+ if(NOT TARGET EXPAT::EXPAT)
+ add_library(EXPAT::EXPAT UNKNOWN IMPORTED)
+ set_target_properties(EXPAT::EXPAT PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${EXPAT_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${EXPAT_INCLUDE_DIRS}")
+ endif()
+endif()
+
+mark_as_advanced(EXPAT_INCLUDE_DIR EXPAT_LIBRARY)
diff --git a/Modules/FindEnvModules.cmake b/Modules/FindEnvModules.cmake
new file mode 100644
index 0000000..a4ac0b4
--- /dev/null
+++ b/Modules/FindEnvModules.cmake
@@ -0,0 +1,335 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindEnvModules
+--------------
+
+.. versionadded:: 3.15
+
+Locate an environment module implementation and make commands available to
+CMake scripts to use them. This is compatible with both Lua-based Lmod
+and TCL-based EnvironmentModules.
+
+This module is intended for the use case of setting up the compiler and library
+environment within a :ref:`CTest Script <CTest Script>` (``ctest -S``). It can
+also be used in a :ref:`CMake Script <Script Processing Mode>` (``cmake -P``).
+
+.. note::
+
+ The loaded environment will not survive past the end of the calling process.
+ Do not use this module in project code (``CMakeLists.txt`` files) to load
+ a compiler environment; it will not be available during the build. Instead
+ load the environment manually before running CMake or using the generated
+ build system.
+
+Example Usage
+^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ set(CTEST_BUILD_NAME "CrayLinux-CrayPE-Cray-dynamic")
+ set(CTEST_BUILD_CONFIGURATION Release)
+ set(CTEST_BUILD_FLAGS "-k -j8")
+ set(CTEST_CMAKE_GENERATOR "Unix Makefiles")
+
+ ...
+
+ find_package(EnvModules REQUIRED)
+
+ env_module(purge)
+ env_module(load modules)
+ env_module(load craype)
+ env_module(load PrgEnv-cray)
+ env_module(load craype-knl)
+ env_module(load cray-mpich)
+ env_module(load cray-libsci)
+
+ set(ENV{CRAYPE_LINK_TYPE} dynamic)
+
+ ...
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``EnvModules_FOUND``
+ True if a compatible environment modules framework was found.
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+The following cache variable will be set:
+
+``EnvModules_COMMAND``
+ The low level module command to use. Currently supported
+ implementations are the Lua based Lmod and TCL based EnvironmentModules.
+
+Environment Variables
+^^^^^^^^^^^^^^^^^^^^^
+
+``ENV{MODULESHOME}``
+ Usually set by the module environment implementation, used as a hint to
+ locate the module command to execute.
+
+Provided Functions
+^^^^^^^^^^^^^^^^^^
+
+This defines the following CMake functions for interacting with environment
+modules:
+
+.. command:: env_module
+
+ Execute an aribitrary module command:
+
+ .. code-block:: cmake
+
+ env_module(cmd arg1 ... argN)
+ env_module(
+ COMMAND cmd arg1 ... argN
+ [OUTPUT_VARIABLE <out-var>]
+ [RESULT_VARIABLE <ret-var>]
+ )
+
+ The options are:
+
+ ``cmd arg1 ... argN``
+ The module sub-command and arguments to execute as if they were
+ passed directly to the module command in your shell environment.
+
+ ``OUTPUT_VARIABLE <out-var>``
+ The standard output from executing the module command.
+
+ ``RESULT_VARIABLE <ret-var>``
+ The return code from executing the module command.
+
+.. command:: env_module_swap
+
+ Swap one module for another:
+
+ .. code-block:: cmake
+
+ env_module_swap(out_mod in_mod
+ [OUTPUT_VARIABLE <out-var>]
+ [RESULT_VARIABLE <ret-var>]
+ )
+
+ This is functionally equivalent to the ``module swap out_mod in_mod`` shell
+ command. The options are:
+
+ ``OUTPUT_VARIABLE <out-var>``
+ The standard output from executing the module command.
+
+ ``RESULT_VARIABLE <ret-var>``
+ The return code from executing the module command.
+
+.. command:: env_module_list
+
+ Retrieve the list of currently loaded modules:
+
+ .. code-block:: cmake
+
+ env_module_list(<out-var>)
+
+ This is functionally equivalent to the ``module list`` shell command.
+ The result is stored in ``<out-var>`` as a properly formatted CMake
+ :ref:`semicolon-separated list <CMake Language Lists>` variable.
+
+.. command:: env_module_avail
+
+ Retrieve the list of available modules:
+
+ .. code-block:: cmake
+
+ env_module_avail([<mod-prefix>] <out-var>)
+
+ This is functionally equivalent to the ``module avail <mod-prefix>`` shell
+ command. The result is stored in ``<out-var>`` as a properly formatted
+ CMake :ref:`semicolon-separated list <CMake Language Lists>` variable.
+
+#]=======================================================================]
+
+function(env_module)
+ if(NOT EnvModules_COMMAND)
+ message(FATAL_ERROR "Failed to process module command. EnvModules_COMMAND not found")
+ return()
+ endif()
+
+ set(options)
+ set(oneValueArgs OUTPUT_VARIABLE RESULT_VARIABLE)
+ set(multiValueArgs COMMAND)
+ cmake_parse_arguments(MOD_ARGS
+ "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGV}
+ )
+ if(NOT MOD_ARGS_COMMAND)
+ # If no explicit command argument was given, then treat the calling syntax
+ # as: module(cmd args...)
+ set(exec_cmd ${ARGV})
+ else()
+ set(exec_cmd ${MOD_ARGS_COMMAND})
+ endif()
+
+ if(MOD_ARGS_OUTPUT_VARIABLE)
+ set(err_var_args ERROR_VARIABLE err_var)
+ endif()
+
+ execute_process(
+ COMMAND mktemp -t module.cmake.XXXXXXXXXXXX
+ OUTPUT_VARIABLE tempfile_name
+ )
+ string(STRIP "${tempfile_name}" tempfile_name)
+
+ # If the $MODULESHOME/init/cmake file exists then assume that the CMake
+ # "shell" functionality exits
+ if(EXISTS "$ENV{MODULESHOME}/init/cmake")
+ execute_process(
+ COMMAND ${EnvModules_COMMAND} cmake ${exec_cmd}
+ OUTPUT_FILE ${tempfile_name}
+ ${err_var_args}
+ RESULT_VARIABLE ret_var
+ )
+
+ else() # fallback to the sh shell and manually convert to CMake
+ execute_process(
+ COMMAND ${EnvModules_COMMAND} sh ${exec_cmd}
+ OUTPUT_VARIABLE out_var
+ ${err_var_args}
+ RESULT_VARIABLE ret_var
+ )
+ endif()
+
+ # If we executed successfully then process and cleanup the temp file
+ if(ret_var EQUAL 0)
+ # No CMake shell so we need to process the sh output into CMake code
+ if(NOT EXISTS "$ENV{MODULESHOME}/init/cmake")
+ file(WRITE ${tempfile_name} "")
+ string(REPLACE "\n" ";" out_var "${out_var}")
+ foreach(sh_cmd IN LISTS out_var)
+ if(sh_cmd MATCHES "^ *unset *([^ ]*)")
+ set(cmake_cmd "unset(ENV{${CMAKE_MATCH_1}})")
+ elseif(sh_cmd MATCHES "^ *export *([^ ]*)")
+ set(cmake_cmd "set(ENV{${CMAKE_MATCH_1}} \"\${${CMAKE_MATCH_1}}\")")
+ elseif(sh_cmd MATCHES " *([^ =]*) *= *(.*)")
+ set(var_name "${CMAKE_MATCH_1}")
+ set(var_value "${CMAKE_MATCH_2}")
+ if(var_value MATCHES "^\"(.*[^\\])\"")
+ # If it's in quotes, take the value as is
+ set(var_value "${CMAKE_MATCH_1}")
+ else()
+ # Otherwise, strip trailing spaces
+ string(REGEX REPLACE "([^\\])? +$" "\\1" var_value "${var_value}")
+ endif()
+ string(REPLACE "\\ " " " var_value "${var_value}")
+ set(cmake_cmd "set(${var_name} \"${var_value}\")")
+ else()
+ continue()
+ endif()
+ file(APPEND ${tempfile_name} "${cmake_cmd}\n")
+ endforeach()
+ endif()
+
+ # Process the change in environment variables
+ include(${tempfile_name})
+ file(REMOVE ${tempfile_name})
+ endif()
+
+ # Push the output back out to the calling scope
+ if(MOD_ARGS_OUTPUT_VARIABLE)
+ set(${MOD_ARGS_OUTPUT_VARIABLE} "${err_var}" PARENT_SCOPE)
+ endif()
+ if(MOD_ARGS_RESULT_VARIABLE)
+ set(${MOD_ARGS_RESULT_VARIABLE} ${ret_var} PARENT_SCOPE)
+ endif()
+endfunction(env_module)
+
+#------------------------------------------------------------------------------
+function(env_module_swap out_mod in_mod)
+ set(options)
+ set(oneValueArgs OUTPUT_VARIABLE RESULT_VARIABLE)
+ set(multiValueArgs)
+
+ cmake_parse_arguments(MOD_ARGS
+ "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGV}
+ )
+
+ env_module(COMMAND -t swap ${out_mod} ${in_mod}
+ OUTPUT_VARIABLE tmp_out
+ RETURN_VARIABLE tmp_ret
+ )
+
+ if(MOD_ARGS_OUTPUT_VARIABLE)
+ set(${MOD_ARGS_OUTPUT_VARIABLE} "${err_var}" PARENT_SCOPE)
+ endif()
+ if(MOD_ARGS_RESULT_VARIABLE)
+ set(${MOD_ARGS_RESULT_VARIABLE} ${tmp_ret} PARENT_SCOPE)
+ endif()
+endfunction()
+
+#------------------------------------------------------------------------------
+function(env_module_list out_var)
+ cmake_policy(SET CMP0007 NEW)
+ env_module(COMMAND -t list OUTPUT_VARIABLE tmp_out)
+
+ # Convert output into a CMake list
+ string(REPLACE "\n" ";" ${out_var} "${tmp_out}")
+
+ # Remove title headers and empty entries
+ list(REMOVE_ITEM ${out_var} "No modules loaded")
+ if(${out_var})
+ list(FILTER ${out_var} EXCLUDE REGEX "^(.*:)?$")
+ endif()
+ list(FILTER ${out_var} EXCLUDE REGEX "^(.*:)?$")
+
+ set(${out_var} ${${out_var}} PARENT_SCOPE)
+endfunction()
+
+#------------------------------------------------------------------------------
+function(env_module_avail)
+ cmake_policy(SET CMP0007 NEW)
+
+ if(ARGC EQUAL 1)
+ set(mod_prefix)
+ set(out_var ${ARGV0})
+ elseif(ARGC EQUAL 2)
+ set(mod_prefix ${ARGV0})
+ set(out_var ${ARGV1})
+ else()
+ message(FATAL_ERROR "Usage: env_module_avail([mod_prefix] out_var)")
+ endif()
+ env_module(COMMAND -t avail ${mod_prefix} OUTPUT_VARIABLE tmp_out)
+
+ # Convert output into a CMake list
+ string(REPLACE "\n" ";" tmp_out "${tmp_out}")
+
+ set(${out_var})
+ foreach(MOD IN LISTS tmp_out)
+ # Remove directory entries and empty values
+ if(MOD MATCHES "^(.*:)?$")
+ continue()
+ endif()
+
+ # Convert default modules
+ if(MOD MATCHES "^(.*)/$" ) # "foo/"
+ list(APPEND ${out_var} ${CMAKE_MATCH_1})
+ elseif(MOD MATCHES "^((.*)/.*)\\(default\\)$") # "foo/1.2.3(default)"
+ list(APPEND ${out_var} ${CMAKE_MATCH_2})
+ list(APPEND ${out_var} ${CMAKE_MATCH_1})
+ else()
+ list(APPEND ${out_var} ${MOD})
+ endif()
+ endforeach()
+
+ set(${out_var} ${${out_var}} PARENT_SCOPE)
+endfunction()
+
+#------------------------------------------------------------------------------
+# Make sure we know where the underlying module command is
+find_program(EnvModules_COMMAND
+ NAMES lmod modulecmd
+ HINTS ENV MODULESHOME
+ PATH_SUFFIXES libexec
+)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(EnvModules DEFAULT_MSG EnvModules_COMMAND)
diff --git a/Modules/FindFLEX.cmake b/Modules/FindFLEX.cmake
new file mode 100644
index 0000000..e67e931
--- /dev/null
+++ b/Modules/FindFLEX.cmake
@@ -0,0 +1,265 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindFLEX
+--------
+
+Find Fast Lexical Analyzer (Flex) executable and provides a macro
+to generate custom build rules
+
+
+
+The module defines the following variables:
+
+::
+
+ FLEX_FOUND - True is flex executable is found
+ FLEX_EXECUTABLE - the path to the flex executable
+ FLEX_VERSION - the version of flex
+ FLEX_LIBRARIES - The flex libraries
+ FLEX_INCLUDE_DIRS - The path to the flex headers
+
+
+
+The minimum required version of flex can be specified using the
+standard syntax, e.g. :command:`find_package(FLEX 2.5.13)`
+
+
+
+If flex is found on the system, the module provides the macro:
+
+::
+
+ FLEX_TARGET(Name FlexInput FlexOutput
+ [COMPILE_FLAGS <string>]
+ [DEFINES_FILE <string>]
+ )
+
+which creates a custom command to generate the ``FlexOutput`` file from
+the ``FlexInput`` file. Name is an alias used to get details of this custom
+command. If ``COMPILE_FLAGS`` option is specified, the next
+parameter is added to the flex command line.
+
+.. versionadded:: 3.5
+ If flex is configured to
+ output a header file, the ``DEFINES_FILE`` option may be used to specify its
+ name.
+
+.. versionchanged:: 3.17
+ When :policy:`CMP0098` is set to ``NEW``, ``flex`` runs in the
+ :variable:`CMAKE_CURRENT_BINARY_DIR` directory.
+
+The macro defines the following variables:
+
+::
+
+ FLEX_${Name}_DEFINED - true is the macro ran successfully
+ FLEX_${Name}_OUTPUTS - the source file generated by the custom rule, an
+ alias for FlexOutput
+ FLEX_${Name}_INPUT - the flex source file, an alias for ${FlexInput}
+ FLEX_${Name}_OUTPUT_HEADER - the header flex output, if any.
+
+
+
+Flex scanners often use tokens defined by Bison: the code generated
+by Flex depends of the header generated by Bison. This module also
+defines a macro:
+
+::
+
+ ADD_FLEX_BISON_DEPENDENCY(FlexTarget BisonTarget)
+
+which adds the required dependency between a scanner and a parser
+where ``FlexTarget`` and ``BisonTarget`` are the first parameters of
+respectively ``FLEX_TARGET`` and ``BISON_TARGET`` macros.
+
+::
+
+ ====================================================================
+ Example:
+
+
+
+::
+
+ find_package(BISON)
+ find_package(FLEX)
+
+
+
+::
+
+ BISON_TARGET(MyParser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp)
+ FLEX_TARGET(MyScanner lexer.l ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp)
+ ADD_FLEX_BISON_DEPENDENCY(MyScanner MyParser)
+
+
+
+::
+
+ include_directories(${CMAKE_CURRENT_BINARY_DIR})
+ add_executable(Foo
+ Foo.cc
+ ${BISON_MyParser_OUTPUTS}
+ ${FLEX_MyScanner_OUTPUTS}
+ )
+ target_link_libraries(Foo ${FLEX_LIBRARIES})
+ ====================================================================
+#]=======================================================================]
+
+find_program(FLEX_EXECUTABLE NAMES flex win-flex win_flex DOC "path to the flex executable")
+mark_as_advanced(FLEX_EXECUTABLE)
+
+find_library(FL_LIBRARY NAMES fl
+ DOC "Path to the fl library")
+
+find_path(FLEX_INCLUDE_DIR FlexLexer.h
+ DOC "Path to the flex headers")
+
+mark_as_advanced(FL_LIBRARY FLEX_INCLUDE_DIR)
+
+set(FLEX_INCLUDE_DIRS ${FLEX_INCLUDE_DIR})
+set(FLEX_LIBRARIES ${FL_LIBRARY})
+
+if(FLEX_EXECUTABLE)
+
+ execute_process(COMMAND ${FLEX_EXECUTABLE} --version
+ OUTPUT_VARIABLE FLEX_version_output
+ ERROR_VARIABLE FLEX_version_error
+ RESULT_VARIABLE FLEX_version_result
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(NOT ${FLEX_version_result} EQUAL 0)
+ if(FLEX_FIND_REQUIRED)
+ message(SEND_ERROR "Command \"${FLEX_EXECUTABLE} --version\" failed with output:\n${FLEX_version_output}\n${FLEX_version_error}")
+ else()
+ message("Command \"${FLEX_EXECUTABLE} --version\" failed with output:\n${FLEX_version_output}\n${FLEX_version_error}\nFLEX_VERSION will not be available")
+ endif()
+ else()
+ # older versions of flex printed "/full/path/to/executable version X.Y"
+ # newer versions use "basename(executable) X.Y"
+ get_filename_component(FLEX_EXE_NAME_WE "${FLEX_EXECUTABLE}" NAME_WE)
+ get_filename_component(FLEX_EXE_EXT "${FLEX_EXECUTABLE}" EXT)
+ string(REGEX REPLACE "^.*${FLEX_EXE_NAME_WE}(${FLEX_EXE_EXT})?\"? (version )?([0-9]+[^ ]*)( .*)?$" "\\3"
+ FLEX_VERSION "${FLEX_version_output}")
+ unset(FLEX_EXE_EXT)
+ unset(FLEX_EXE_NAME_WE)
+ endif()
+
+ #============================================================
+ # FLEX_TARGET (public macro)
+ #============================================================
+ #
+ macro(FLEX_TARGET Name Input Output)
+
+ set(FLEX_TARGET_PARAM_OPTIONS)
+ set(FLEX_TARGET_PARAM_ONE_VALUE_KEYWORDS
+ COMPILE_FLAGS
+ DEFINES_FILE
+ )
+ set(FLEX_TARGET_PARAM_MULTI_VALUE_KEYWORDS)
+
+ cmake_parse_arguments(
+ FLEX_TARGET_ARG
+ "${FLEX_TARGET_PARAM_OPTIONS}"
+ "${FLEX_TARGET_PARAM_ONE_VALUE_KEYWORDS}"
+ "${FLEX_TARGET_MULTI_VALUE_KEYWORDS}"
+ ${ARGN}
+ )
+
+ set(FLEX_TARGET_usage "FLEX_TARGET(<Name> <Input> <Output> [COMPILE_FLAGS <string>] [DEFINES_FILE <string>]")
+
+ if(NOT "${FLEX_TARGET_ARG_UNPARSED_ARGUMENTS}" STREQUAL "")
+ message(SEND_ERROR ${FLEX_TARGET_usage})
+ else()
+
+ cmake_policy(GET CMP0098 _flex_CMP0098
+ PARENT_SCOPE # undocumented, do not use outside of CMake
+ )
+ set(_flex_INPUT "${Input}")
+ if("x${_flex_CMP0098}x" STREQUAL "xNEWx")
+ set(_flex_WORKING_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+ if(NOT IS_ABSOLUTE "${_flex_INPUT}")
+ set(_flex_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/${_flex_INPUT}")
+ endif()
+ else()
+ set(_flex_WORKING_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ endif()
+ unset(_flex_CMP0098)
+
+ set(_flex_OUTPUT "${Output}")
+ if(NOT IS_ABSOLUTE ${_flex_OUTPUT})
+ set(_flex_OUTPUT "${_flex_WORKING_DIR}/${_flex_OUTPUT}")
+ endif()
+ set(_flex_TARGET_OUTPUTS "${_flex_OUTPUT}")
+
+ set(_flex_EXE_OPTS "")
+ if(NOT "${FLEX_TARGET_ARG_COMPILE_FLAGS}" STREQUAL "")
+ set(_flex_EXE_OPTS "${FLEX_TARGET_ARG_COMPILE_FLAGS}")
+ separate_arguments(_flex_EXE_OPTS)
+ endif()
+
+ set(_flex_OUTPUT_HEADER "")
+ if(NOT "${FLEX_TARGET_ARG_DEFINES_FILE}" STREQUAL "")
+ set(_flex_OUTPUT_HEADER "${FLEX_TARGET_ARG_DEFINES_FILE}")
+ if(IS_ABSOLUTE "${_flex_OUTPUT_HEADER}")
+ set(_flex_OUTPUT_HEADER_ABS "${_flex_OUTPUT_HEADER}")
+ else()
+ set(_flex_OUTPUT_HEADER_ABS "${_flex_WORKING_DIR}/${_flex_OUTPUT_HEADER}")
+ endif()
+ list(APPEND _flex_TARGET_OUTPUTS "${_flex_OUTPUT_HEADER_ABS}")
+ list(APPEND _flex_EXE_OPTS --header-file=${_flex_OUTPUT_HEADER_ABS})
+ endif()
+
+ get_filename_component(_flex_EXE_NAME_WE "${FLEX_EXECUTABLE}" NAME_WE)
+ add_custom_command(OUTPUT ${_flex_TARGET_OUTPUTS}
+ COMMAND ${FLEX_EXECUTABLE} ${_flex_EXE_OPTS} -o${_flex_OUTPUT} ${_flex_INPUT}
+ VERBATIM
+ DEPENDS ${_flex_INPUT}
+ COMMENT "[FLEX][${Name}] Building scanner with ${_flex_EXE_NAME_WE} ${FLEX_VERSION}"
+ WORKING_DIRECTORY ${_flex_WORKING_DIR})
+
+ set(FLEX_${Name}_DEFINED TRUE)
+ set(FLEX_${Name}_OUTPUTS ${_flex_TARGET_OUTPUTS})
+ set(FLEX_${Name}_INPUT ${_flex_INPUT})
+ set(FLEX_${Name}_COMPILE_FLAGS ${_flex_EXE_OPTS})
+ set(FLEX_${Name}_OUTPUT_HEADER ${_flex_OUTPUT_HEADER})
+
+ unset(_flex_EXE_NAME_WE)
+ unset(_flex_EXE_OPTS)
+ unset(_flex_INPUT)
+ unset(_flex_OUTPUT)
+ unset(_flex_OUTPUT_HEADER)
+ unset(_flex_OUTPUT_HEADER_ABS)
+ unset(_flex_TARGET_OUTPUTS)
+ unset(_flex_WORKING_DIR)
+
+ endif()
+ endmacro()
+ #============================================================
+
+
+ #============================================================
+ # ADD_FLEX_BISON_DEPENDENCY (public macro)
+ #============================================================
+ #
+ macro(ADD_FLEX_BISON_DEPENDENCY FlexTarget BisonTarget)
+
+ if(NOT FLEX_${FlexTarget}_OUTPUTS)
+ message(SEND_ERROR "Flex target `${FlexTarget}' does not exist.")
+ endif()
+
+ if(NOT BISON_${BisonTarget}_OUTPUT_HEADER)
+ message(SEND_ERROR "Bison target `${BisonTarget}' does not exist.")
+ endif()
+
+ set_source_files_properties(${FLEX_${FlexTarget}_OUTPUTS}
+ PROPERTIES OBJECT_DEPENDS ${BISON_${BisonTarget}_OUTPUT_HEADER})
+ endmacro()
+ #============================================================
+
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(FLEX REQUIRED_VARS FLEX_EXECUTABLE
+ VERSION_VAR FLEX_VERSION)
diff --git a/Modules/FindFLTK.cmake b/Modules/FindFLTK.cmake
new file mode 100644
index 0000000..e1e239a
--- /dev/null
+++ b/Modules/FindFLTK.cmake
@@ -0,0 +1,340 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindFLTK
+--------
+
+Find the Fast Light Toolkit (FLTK) library
+
+Input Variables
+^^^^^^^^^^^^^^^
+
+By default this module will search for all of the FLTK components and
+add them to the ``FLTK_LIBRARIES`` variable. You can limit the components
+which get placed in ``FLTK_LIBRARIES`` by defining one or more of the
+following three options:
+
+``FLTK_SKIP_OPENGL``
+ Set to true to disable searching for the FLTK GL library
+
+``FLTK_SKIP_FORMS``
+ Set to true to disable searching for the FLTK Forms library
+
+``FLTK_SKIP_IMAGES``
+ Set to true to disable searching for the FLTK Images library
+
+FLTK is composed also by a binary tool. You can set the following option:
+
+``FLTK_SKIP_FLUID``
+ Set to true to not look for the FLUID binary
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+The following variables will be defined:
+
+``FLTK_FOUND``
+ True if all components not skipped were found
+
+``FLTK_INCLUDE_DIR``
+ Path to the include directory for FLTK header files
+
+``FLTK_LIBRARIES``
+ List of the FLTK libraries found
+
+``FLTK_FLUID_EXECUTABLE``
+ Path to the FLUID binary tool
+
+``FLTK_WRAP_UI``
+ True if FLUID is found, used to enable the FLTK_WRAP_UI command
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+The following cache variables are also available to set or use:
+
+``FLTK_BASE_LIBRARY_RELEASE``
+ The FLTK base library (optimized)
+
+``FLTK_BASE_LIBRARY_DEBUG``
+ The FLTK base library (debug)
+
+``FLTK_GL_LIBRARY_RELEASE``
+ The FLTK GL library (optimized)
+
+``FLTK_GL_LIBRARY_DEBUG``
+ The FLTK GL library (debug)
+
+``FLTK_FORMS_LIBRARY_RELEASE``
+ The FLTK Forms library (optimized)
+
+``FLTK_FORMS_LIBRARY_DEBUG``
+ The FLTK Forms library (debug)
+
+``FLTK_IMAGES_LIBRARY_RELEASE``
+ The FLTK Images protobuf library (optimized)
+
+``FLTK_IMAGES_LIBRARY_DEBUG``
+ The FLTK Images library (debug)
+
+.. versionadded:: 3.11
+ Debug and Release variants are found separately and use per-configuration
+ variables.
+#]=======================================================================]
+
+if(NOT FLTK_SKIP_OPENGL)
+ find_package(OpenGL)
+endif()
+
+# Platform dependent libraries required by FLTK
+if(WIN32)
+ if(NOT CYGWIN)
+ if(BORLAND)
+ set( FLTK_PLATFORM_DEPENDENT_LIBS import32 )
+ else()
+ set( FLTK_PLATFORM_DEPENDENT_LIBS wsock32 comctl32 )
+ endif()
+ endif()
+endif()
+
+if(UNIX)
+ include(${CMAKE_CURRENT_LIST_DIR}/FindX11.cmake)
+ find_library(FLTK_MATH_LIBRARY m)
+ set( FLTK_PLATFORM_DEPENDENT_LIBS ${X11_LIBRARIES} ${FLTK_MATH_LIBRARY})
+endif()
+
+if(APPLE)
+ set( FLTK_PLATFORM_DEPENDENT_LIBS "-framework Carbon -framework Cocoa -framework ApplicationServices -lz")
+endif()
+
+# If FLTK_INCLUDE_DIR is already defined we assigne its value to FLTK_DIR
+if(FLTK_INCLUDE_DIR)
+ set(FLTK_DIR ${FLTK_INCLUDE_DIR})
+endif()
+
+
+# If FLTK has been built using CMake we try to find everything directly
+set(FLTK_DIR_STRING "directory containing FLTKConfig.cmake. This is either the root of the build tree, or PREFIX/lib/fltk for an installation.")
+
+# Search only if the location is not already known.
+if(NOT FLTK_DIR)
+ # Get the system search path as a list.
+ file(TO_CMAKE_PATH "$ENV{PATH}" FLTK_DIR_SEARCH2)
+
+ # Construct a set of paths relative to the system search path.
+ set(FLTK_DIR_SEARCH "")
+ foreach(dir ${FLTK_DIR_SEARCH2})
+ set(FLTK_DIR_SEARCH ${FLTK_DIR_SEARCH} "${dir}/../lib/fltk")
+ endforeach()
+ string(REPLACE "//" "/" FLTK_DIR_SEARCH "${FLTK_DIR_SEARCH}")
+
+ #
+ # Look for an installation or build tree.
+ #
+ find_path(FLTK_DIR FLTKConfig.cmake
+ # Look for an environment variable FLTK_DIR.
+ HINTS
+ ENV FLTK_DIR
+
+ # Look in places relative to the system executable search path.
+ ${FLTK_DIR_SEARCH}
+
+ PATH_SUFFIXES
+ fltk
+ fltk/include
+ lib/fltk
+ lib/fltk/include
+
+ # Help the user find it if we cannot.
+ DOC "The ${FLTK_DIR_STRING}"
+ )
+endif()
+
+# Check if FLTK was built using CMake
+if(EXISTS ${FLTK_DIR}/FLTKConfig.cmake)
+ set(FLTK_BUILT_WITH_CMAKE 1)
+endif()
+
+if(FLTK_BUILT_WITH_CMAKE)
+ set(FLTK_FOUND 1)
+ include(${FLTK_DIR}/FLTKConfig.cmake)
+
+ # Fluid
+ if(FLUID_COMMAND)
+ set(FLTK_FLUID_EXECUTABLE ${FLUID_COMMAND} CACHE FILEPATH "Fluid executable")
+ else()
+ find_program(FLTK_FLUID_EXECUTABLE fluid PATHS
+ ${FLTK_EXECUTABLE_DIRS}
+ ${FLTK_EXECUTABLE_DIRS}/RelWithDebInfo
+ ${FLTK_EXECUTABLE_DIRS}/Debug
+ ${FLTK_EXECUTABLE_DIRS}/Release
+ NO_SYSTEM_PATH)
+ endif()
+ # mark_as_advanced(FLTK_FLUID_EXECUTABLE)
+
+ set(FLTK_INCLUDE_DIR ${FLTK_DIR})
+ link_directories(${FLTK_LIBRARY_DIRS})
+
+ set(FLTK_BASE_LIBRARY fltk)
+ set(FLTK_GL_LIBRARY fltk_gl)
+ set(FLTK_FORMS_LIBRARY fltk_forms)
+ set(FLTK_IMAGES_LIBRARY fltk_images)
+
+ # Add the extra libraries
+ load_cache(${FLTK_DIR}
+ READ_WITH_PREFIX
+ FL FLTK_USE_SYSTEM_JPEG
+ FL FLTK_USE_SYSTEM_PNG
+ FL FLTK_USE_SYSTEM_ZLIB
+ )
+
+ set(FLTK_IMAGES_LIBS "")
+ if(FLFLTK_USE_SYSTEM_JPEG)
+ set(FLTK_IMAGES_LIBS ${FLTK_IMAGES_LIBS} fltk_jpeg)
+ endif()
+ if(FLFLTK_USE_SYSTEM_PNG)
+ set(FLTK_IMAGES_LIBS ${FLTK_IMAGES_LIBS} fltk_png)
+ endif()
+ if(FLFLTK_USE_SYSTEM_ZLIB)
+ set(FLTK_IMAGES_LIBS ${FLTK_IMAGES_LIBS} fltk_zlib)
+ endif()
+ set(FLTK_IMAGES_LIBS "${FLTK_IMAGES_LIBS}" CACHE INTERNAL
+ "Extra libraries for fltk_images library.")
+
+else()
+
+ # if FLTK was not built using CMake
+ # Find fluid executable.
+ find_program(FLTK_FLUID_EXECUTABLE fluid ${FLTK_INCLUDE_DIR}/fluid)
+
+ # Use location of fluid to help find everything else.
+ set(FLTK_INCLUDE_SEARCH_PATH "")
+ set(FLTK_LIBRARY_SEARCH_PATH "")
+ if(FLTK_FLUID_EXECUTABLE)
+ get_filename_component(FLTK_BIN_DIR "${FLTK_FLUID_EXECUTABLE}" PATH)
+ set(FLTK_INCLUDE_SEARCH_PATH ${FLTK_INCLUDE_SEARCH_PATH}
+ ${FLTK_BIN_DIR}/../include ${FLTK_BIN_DIR}/..)
+ set(FLTK_LIBRARY_SEARCH_PATH ${FLTK_LIBRARY_SEARCH_PATH}
+ ${FLTK_BIN_DIR}/../lib)
+ set(FLTK_WRAP_UI 1)
+ endif()
+
+ #
+ # Try to find FLTK include dir using fltk-config
+ #
+ if(UNIX)
+ # Use fltk-config to generate a list of possible include directories
+ find_program(FLTK_CONFIG_SCRIPT fltk-config PATHS ${FLTK_BIN_DIR})
+ if(FLTK_CONFIG_SCRIPT)
+ if(NOT FLTK_INCLUDE_DIR)
+ exec_program(${FLTK_CONFIG_SCRIPT} ARGS --cxxflags OUTPUT_VARIABLE FLTK_CXXFLAGS)
+ if(FLTK_CXXFLAGS)
+ string(REGEX MATCHALL "-I[^ ]*" _fltk_temp_dirs ${FLTK_CXXFLAGS})
+ string(REPLACE "-I" "" _fltk_temp_dirs "${_fltk_temp_dirs}")
+ foreach(_dir ${_fltk_temp_dirs})
+ string(STRIP ${_dir} _output)
+ list(APPEND _FLTK_POSSIBLE_INCLUDE_DIRS ${_output})
+ endforeach()
+ endif()
+ endif()
+ endif()
+ endif()
+
+ list(APPEND FLTK_INCLUDE_SEARCH_PATH ${_FLTK_POSSIBLE_INCLUDE_DIRS})
+
+ find_path(FLTK_INCLUDE_DIR
+ NAMES FL/Fl.h FL/Fl.H # fltk 1.1.9 has Fl.H (#8376)
+ PATH_SUFFIXES fltk fltk/include
+ PATHS ${FLTK_INCLUDE_SEARCH_PATH})
+
+ #
+ # Try to find FLTK library
+ if(UNIX)
+ if(FLTK_CONFIG_SCRIPT)
+ exec_program(${FLTK_CONFIG_SCRIPT} ARGS --libs OUTPUT_VARIABLE _FLTK_POSSIBLE_LIBS)
+ if(_FLTK_POSSIBLE_LIBS)
+ get_filename_component(_FLTK_POSSIBLE_LIBRARY_DIR ${_FLTK_POSSIBLE_LIBS} PATH)
+ endif()
+ endif()
+ endif()
+
+ list(APPEND FLTK_LIBRARY_SEARCH_PATH ${FLTK_INCLUDE_DIR}/lib ${_FLTK_POSSIBLE_LIBRARY_DIR})
+
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+
+ # Allow libraries to be set manually
+ if(NOT FLTK_BASE_LIBRARY)
+ find_library(FLTK_BASE_LIBRARY_RELEASE NAMES fltk PATHS ${FLTK_LIBRARY_SEARCH_PATH} PATH_SUFFIXES fltk fltk/lib)
+ find_library(FLTK_BASE_LIBRARY_DEBUG NAMES fltkd PATHS ${FLTK_LIBRARY_SEARCH_PATH} PATH_SUFFIXES fltk fltk/lib)
+ select_library_configurations(FLTK_BASE)
+ endif()
+ if(NOT FLTK_GL_LIBRARY)
+ find_library(FLTK_GL_LIBRARY_RELEASE NAMES fltkgl fltk_gl PATHS ${FLTK_LIBRARY_SEARCH_PATH} PATH_SUFFIXES fltk fltk/lib)
+ find_library(FLTK_GL_LIBRARY_DEBUG NAMES fltkgld fltk_gld PATHS ${FLTK_LIBRARY_SEARCH_PATH} PATH_SUFFIXES fltk fltk/lib)
+ select_library_configurations(FLTK_GL)
+ endif()
+ if(NOT FLTK_FORMS_LIBRARY)
+ find_library(FLTK_FORMS_LIBRARY_RELEASE NAMES fltkforms fltk_forms PATHS ${FLTK_LIBRARY_SEARCH_PATH} PATH_SUFFIXES fltk fltk/lib)
+ find_library(FLTK_FORMS_LIBRARY_DEBUG NAMES fltkformsd fltk_formsd PATHS ${FLTK_LIBRARY_SEARCH_PATH} PATH_SUFFIXES fltk fltk/lib)
+ select_library_configurations(FLTK_FORMS)
+ endif()
+ if(NOT FLTK_IMAGES_LIBRARY)
+ find_library(FLTK_IMAGES_LIBRARY_RELEASE NAMES fltkimages fltk_images PATHS ${FLTK_LIBRARY_SEARCH_PATH} PATH_SUFFIXES fltk fltk/lib)
+ find_library(FLTK_IMAGES_LIBRARY_DEBUG NAMES fltkimagesd fltk_imagesd PATHS ${FLTK_LIBRARY_SEARCH_PATH} PATH_SUFFIXES fltk fltk/lib)
+ select_library_configurations(FLTK_IMAGES)
+ endif()
+
+ # Find the extra libraries needed for the fltk_images library.
+ if(UNIX)
+ if(FLTK_CONFIG_SCRIPT)
+ exec_program(${FLTK_CONFIG_SCRIPT} ARGS --use-images --ldflags
+ OUTPUT_VARIABLE FLTK_IMAGES_LDFLAGS)
+ set(FLTK_LIBS_EXTRACT_REGEX ".*-lfltk_images (.*) -lfltk.*")
+ if("${FLTK_IMAGES_LDFLAGS}" MATCHES "${FLTK_LIBS_EXTRACT_REGEX}")
+ string(REGEX REPLACE " +" ";" FLTK_IMAGES_LIBS "${CMAKE_MATCH_1}")
+ # The EXEC_PROGRAM will not be inherited into subdirectories from
+ # the file that originally included this module. Save the answer.
+ set(FLTK_IMAGES_LIBS "${FLTK_IMAGES_LIBS}" CACHE INTERNAL
+ "Extra libraries for fltk_images library.")
+ endif()
+ endif()
+ endif()
+
+endif()
+
+# Append all of the required libraries together (by default, everything)
+set(FLTK_LIBRARIES)
+if(NOT FLTK_SKIP_IMAGES)
+ list(APPEND FLTK_LIBRARIES ${FLTK_IMAGES_LIBRARY})
+endif()
+if(NOT FLTK_SKIP_FORMS)
+ list(APPEND FLTK_LIBRARIES ${FLTK_FORMS_LIBRARY})
+endif()
+if(NOT FLTK_SKIP_OPENGL)
+ list(APPEND FLTK_LIBRARIES ${FLTK_GL_LIBRARY} ${OPENGL_gl_LIBRARY})
+ list(APPEND FLTK_INCLUDE_DIR ${OPENGL_INCLUDE_DIR})
+ list(REMOVE_DUPLICATES FLTK_INCLUDE_DIR)
+endif()
+list(APPEND FLTK_LIBRARIES ${FLTK_BASE_LIBRARY})
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+if(FLTK_SKIP_FLUID)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(FLTK DEFAULT_MSG FLTK_LIBRARIES FLTK_INCLUDE_DIR)
+else()
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(FLTK DEFAULT_MSG FLTK_LIBRARIES FLTK_INCLUDE_DIR FLTK_FLUID_EXECUTABLE)
+endif()
+
+if(FLTK_FOUND)
+ if(APPLE)
+ set(FLTK_LIBRARIES ${FLTK_PLATFORM_DEPENDENT_LIBS} ${FLTK_LIBRARIES})
+ else()
+ set(FLTK_LIBRARIES ${FLTK_LIBRARIES} ${FLTK_PLATFORM_DEPENDENT_LIBS})
+ endif()
+
+ # The following deprecated settings are for compatibility with CMake 1.4
+ set (HAS_FLTK ${FLTK_FOUND})
+ set (FLTK_INCLUDE_PATH ${FLTK_INCLUDE_DIR})
+ set (FLTK_FLUID_EXE ${FLTK_FLUID_EXECUTABLE})
+ set (FLTK_LIBRARY ${FLTK_LIBRARIES})
+endif()
diff --git a/Modules/FindFLTK2.cmake b/Modules/FindFLTK2.cmake
new file mode 100644
index 0000000..a43f7a4
--- /dev/null
+++ b/Modules/FindFLTK2.cmake
@@ -0,0 +1,245 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindFLTK2
+---------
+
+Find the native FLTK 2.0 includes and library
+
+The following settings are defined
+
+::
+
+ FLTK2_FLUID_EXECUTABLE, where to find the Fluid tool
+ FLTK2_WRAP_UI, This enables the FLTK2_WRAP_UI command
+ FLTK2_INCLUDE_DIR, where to find include files
+ FLTK2_LIBRARIES, list of fltk2 libraries
+ FLTK2_FOUND, Don't use FLTK2 if false.
+
+The following settings should not be used in general.
+
+::
+
+ FLTK2_BASE_LIBRARY = the full path to fltk2.lib
+ FLTK2_GL_LIBRARY = the full path to fltk2_gl.lib
+ FLTK2_IMAGES_LIBRARY = the full path to fltk2_images.lib
+#]=======================================================================]
+
+set (FLTK2_DIR $ENV{FLTK2_DIR} )
+
+# Platform dependent libraries required by FLTK2
+if(WIN32)
+ if(NOT CYGWIN)
+ if(BORLAND)
+ set( FLTK2_PLATFORM_DEPENDENT_LIBS import32 )
+ else()
+ set( FLTK2_PLATFORM_DEPENDENT_LIBS wsock32 comctl32 )
+ endif()
+ endif()
+endif()
+
+if(UNIX)
+ include(${CMAKE_ROOT}/Modules/FindX11.cmake)
+ set( FLTK2_PLATFORM_DEPENDENT_LIBS ${X11_LIBRARIES} -lm)
+endif()
+
+if(APPLE)
+ set( FLTK2_PLATFORM_DEPENDENT_LIBS "-framework Carbon -framework Cocoa -framework ApplicationServices -lz")
+endif()
+
+# If FLTK2_INCLUDE_DIR is already defined we assign its value to FLTK2_DIR
+if(FLTK2_INCLUDE_DIR)
+ set(FLTK2_DIR ${FLTK2_INCLUDE_DIR})
+else()
+ set(FLTK2_INCLUDE_DIR ${FLTK2_DIR})
+endif()
+
+
+# If FLTK2 has been built using CMake we try to find everything directly
+set(FLTK2_DIR_STRING "directory containing FLTK2Config.cmake. This is either the root of the build tree, or PREFIX/lib/fltk for an installation.")
+
+# Search only if the location is not already known.
+if(NOT FLTK2_DIR)
+ # Get the system search path as a list.
+ file(TO_CMAKE_PATH "$ENV{PATH}" FLTK2_DIR_SEARCH2)
+
+ # Construct a set of paths relative to the system search path.
+ set(FLTK2_DIR_SEARCH "")
+ foreach(dir ${FLTK2_DIR_SEARCH2})
+ set(FLTK2_DIR_SEARCH ${FLTK2_DIR_SEARCH} "${dir}/../lib/fltk")
+ endforeach()
+ string(REPLACE "//" "/" FLTK2_DIR_SEARCH "${FLTK2_DIR_SEARCH}")
+
+ #
+ # Look for an installation or build tree.
+ #
+ find_path(FLTK2_DIR FLTK2Config.cmake
+ # Look for an environment variable FLTK2_DIR.
+ ENV FLTK2_DIR
+
+ # Look in places relative to the system executable search path.
+ ${FLTK2_DIR_SEARCH}
+
+ PATH_SUFFIXES
+ fltk2
+ fltk2/include
+ lib/fltk2
+ lib/fltk2/include
+
+ # Help the user find it if we cannot.
+ DOC "The ${FLTK2_DIR_STRING}"
+ )
+
+ if(NOT FLTK2_DIR)
+ find_path(FLTK2_DIR fltk/run.h ${FLTK2_INCLUDE_SEARCH_PATH})
+ endif()
+
+endif()
+
+
+# If FLTK2 was found, load the configuration file to get the rest of the
+# settings.
+if(FLTK2_DIR)
+
+ # Check if FLTK2 was built using CMake
+ if(EXISTS ${FLTK2_DIR}/FLTK2Config.cmake)
+ set(FLTK2_BUILT_WITH_CMAKE 1)
+ endif()
+
+ if(FLTK2_BUILT_WITH_CMAKE)
+ set(FLTK2_FOUND 1)
+ include(${FLTK2_DIR}/FLTK2Config.cmake)
+
+ # Fluid
+ if(FLUID_COMMAND)
+ set(FLTK2_FLUID_EXECUTABLE ${FLUID_COMMAND} CACHE FILEPATH "Fluid executable")
+ else()
+ find_program(FLTK2_FLUID_EXECUTABLE fluid2 PATHS
+ ${FLTK2_EXECUTABLE_DIRS}
+ ${FLTK2_EXECUTABLE_DIRS}/RelWithDebInfo
+ ${FLTK2_EXECUTABLE_DIRS}/Debug
+ ${FLTK2_EXECUTABLE_DIRS}/Release
+ NO_SYSTEM_PATH)
+ endif()
+
+ mark_as_advanced(FLTK2_FLUID_EXECUTABLE)
+ set( FLTK_FLUID_EXECUTABLE ${FLTK2_FLUID_EXECUTABLE} )
+
+
+
+
+ set(FLTK2_INCLUDE_DIR ${FLTK2_DIR})
+ link_directories(${FLTK2_LIBRARY_DIRS})
+
+ set(FLTK2_BASE_LIBRARY fltk2)
+ set(FLTK2_GL_LIBRARY fltk2_gl)
+ set(FLTK2_IMAGES_LIBRARY fltk2_images)
+
+ # Add the extra libraries
+ load_cache(${FLTK2_DIR}
+ READ_WITH_PREFIX
+ FL FLTK2_USE_SYSTEM_JPEG
+ FL FLTK2_USE_SYSTEM_PNG
+ FL FLTK2_USE_SYSTEM_ZLIB
+ )
+
+ set(FLTK2_IMAGES_LIBS "")
+ if(FLFLTK2_USE_SYSTEM_JPEG)
+ set(FLTK2_IMAGES_LIBS ${FLTK2_IMAGES_LIBS} fltk2_jpeg)
+ endif()
+ if(FLFLTK2_USE_SYSTEM_PNG)
+ set(FLTK2_IMAGES_LIBS ${FLTK2_IMAGES_LIBS} fltk2_png)
+ endif()
+ if(FLFLTK2_USE_SYSTEM_ZLIB)
+ set(FLTK2_IMAGES_LIBS ${FLTK2_IMAGES_LIBS} fltk2_zlib)
+ endif()
+ set(FLTK2_IMAGES_LIBS "${FLTK2_IMAGES_LIBS}" CACHE INTERNAL
+ "Extra libraries for fltk2_images library.")
+
+ else()
+
+ # if FLTK2 was not built using CMake
+ # Find fluid executable.
+ find_program(FLTK2_FLUID_EXECUTABLE fluid2 ${FLTK2_INCLUDE_DIR}/fluid)
+
+ # Use location of fluid to help find everything else.
+ set(FLTK2_INCLUDE_SEARCH_PATH "")
+ set(FLTK2_LIBRARY_SEARCH_PATH "")
+ if(FLTK2_FLUID_EXECUTABLE)
+ set( FLTK_FLUID_EXECUTABLE ${FLTK2_FLUID_EXECUTABLE} )
+ get_filename_component(FLTK2_BIN_DIR "${FLTK2_FLUID_EXECUTABLE}" PATH)
+ set(FLTK2_INCLUDE_SEARCH_PATH ${FLTK2_INCLUDE_SEARCH_PATH}
+ ${FLTK2_BIN_DIR}/../include ${FLTK2_BIN_DIR}/..)
+ set(FLTK2_LIBRARY_SEARCH_PATH ${FLTK2_LIBRARY_SEARCH_PATH}
+ ${FLTK2_BIN_DIR}/../lib)
+ set(FLTK2_WRAP_UI 1)
+ endif()
+
+ find_path(FLTK2_INCLUDE_DIR fltk/run.h ${FLTK2_INCLUDE_SEARCH_PATH} PATH_SUFFIXES fltk2 fltk2/include)
+
+ list(APPEND FLTK2_LIBRARY_SEARCH_PATH ${FLTK2_INCLUDE_DIR}/lib)
+
+ find_library(FLTK2_BASE_LIBRARY NAMES fltk2
+ PATHS ${FLTK2_LIBRARY_SEARCH_PATH} PATH_SUFFIXES fltk2 fltk2/lib)
+ find_library(FLTK2_GL_LIBRARY NAMES fltk2_gl
+ PATHS ${FLTK2_LIBRARY_SEARCH_PATH} PATH_SUFFIXES fltk2 fltk2/lib)
+ find_library(FLTK2_IMAGES_LIBRARY NAMES fltk2_images
+ PATHS ${FLTK2_LIBRARY_SEARCH_PATH} PATH_SUFFIXES fltk2 fltk2/lib)
+
+ # Find the extra libraries needed for the fltk_images library.
+ if(UNIX)
+ find_program(FLTK2_CONFIG_SCRIPT fltk2-config PATHS ${FLTK2_BIN_DIR})
+ if(FLTK2_CONFIG_SCRIPT)
+ exec_program(${FLTK2_CONFIG_SCRIPT} ARGS --use-images --ldflags
+ OUTPUT_VARIABLE FLTK2_IMAGES_LDFLAGS)
+ set(FLTK2_LIBS_EXTRACT_REGEX ".*-lfltk2_images (.*) -lfltk2.*")
+ if("${FLTK2_IMAGES_LDFLAGS}" MATCHES "${FLTK2_LIBS_EXTRACT_REGEX}")
+ string(REGEX REPLACE " +" ";" FLTK2_IMAGES_LIBS "${CMAKE_MATCH_1}")
+ # The EXEC_PROGRAM will not be inherited into subdirectories from
+ # the file that originally included this module. Save the answer.
+ set(FLTK2_IMAGES_LIBS "${FLTK2_IMAGES_LIBS}" CACHE INTERNAL
+ "Extra libraries for fltk_images library.")
+ endif()
+ endif()
+ endif()
+
+ endif()
+endif()
+
+
+set(FLTK2_FOUND 1)
+foreach(var FLTK2_FLUID_EXECUTABLE FLTK2_INCLUDE_DIR
+ FLTK2_BASE_LIBRARY FLTK2_GL_LIBRARY
+ FLTK2_IMAGES_LIBRARY)
+ if(NOT ${var})
+ message( STATUS "${var} not found" )
+ set(FLTK2_FOUND 0)
+ endif()
+endforeach()
+
+
+if(FLTK2_FOUND)
+ set(FLTK2_LIBRARIES ${FLTK2_IMAGES_LIBRARY} ${FLTK2_IMAGES_LIBS} ${FLTK2_BASE_LIBRARY} ${FLTK2_GL_LIBRARY} )
+ if(APPLE)
+ set(FLTK2_LIBRARIES ${FLTK2_PLATFORM_DEPENDENT_LIBS} ${FLTK2_LIBRARIES})
+ else()
+ set(FLTK2_LIBRARIES ${FLTK2_LIBRARIES} ${FLTK2_PLATFORM_DEPENDENT_LIBS})
+ endif()
+
+ # The following deprecated settings are for compatibility with CMake 1.4
+ set (HAS_FLTK2 ${FLTK2_FOUND})
+ set (FLTK2_INCLUDE_PATH ${FLTK2_INCLUDE_DIR})
+ set (FLTK2_FLUID_EXE ${FLTK2_FLUID_EXECUTABLE})
+ set (FLTK2_LIBRARY ${FLTK2_LIBRARIES})
+else()
+ # make FIND_PACKAGE friendly
+ if(NOT FLTK2_FIND_QUIETLY)
+ if(FLTK2_FIND_REQUIRED)
+ message(FATAL_ERROR
+ "FLTK2 required, please specify its location with FLTK2_DIR.")
+ else()
+ message(STATUS "FLTK2 was not found.")
+ endif()
+ endif()
+endif()
diff --git a/Modules/FindFontconfig.cmake b/Modules/FindFontconfig.cmake
new file mode 100644
index 0000000..5228831
--- /dev/null
+++ b/Modules/FindFontconfig.cmake
@@ -0,0 +1,103 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindFontconfig
+--------------
+
+.. versionadded:: 3.14
+
+Find Fontconfig headers and library.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+``Fontconfig::Fontconfig``
+ The Fontconfig library, if found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This will define the following variables in your project:
+
+``Fontconfig_FOUND``
+ true if (the requested version of) Fontconfig is available.
+``Fontconfig_VERSION``
+ the version of Fontconfig.
+``Fontconfig_LIBRARIES``
+ the libraries to link against to use Fontconfig.
+``Fontconfig_INCLUDE_DIRS``
+ where to find the Fontconfig headers.
+``Fontconfig_COMPILE_OPTIONS``
+ this should be passed to target_compile_options(), if the
+ target is not used for linking
+
+#]=======================================================================]
+
+
+# use pkg-config to get the directories and then use these values
+# in the FIND_PATH() and FIND_LIBRARY() calls
+find_package(PkgConfig QUIET)
+pkg_check_modules(PKG_FONTCONFIG QUIET fontconfig)
+set(Fontconfig_COMPILE_OPTIONS ${PKG_FONTCONFIG_CFLAGS_OTHER})
+set(Fontconfig_VERSION ${PKG_FONTCONFIG_VERSION})
+
+find_path( Fontconfig_INCLUDE_DIR
+ NAMES
+ fontconfig/fontconfig.h
+ HINTS
+ ${PKG_FONTCONFIG_INCLUDE_DIRS}
+ /usr/X11/include
+)
+
+find_library( Fontconfig_LIBRARY
+ NAMES
+ fontconfig
+ PATHS
+ ${PKG_FONTCONFIG_LIBRARY_DIRS}
+)
+
+if (Fontconfig_INCLUDE_DIR AND NOT Fontconfig_VERSION)
+ file(STRINGS ${Fontconfig_INCLUDE_DIR}/fontconfig/fontconfig.h _contents REGEX "^#define[ \t]+FC_[A-Z]+[ \t]+[0-9]+$")
+ unset(Fontconfig_VERSION)
+ foreach(VPART MAJOR MINOR REVISION)
+ foreach(VLINE ${_contents})
+ if(VLINE MATCHES "^#define[\t ]+FC_${VPART}[\t ]+([0-9]+)$")
+ set(Fontconfig_VERSION_PART "${CMAKE_MATCH_1}")
+ if(Fontconfig_VERSION)
+ string(APPEND Fontconfig_VERSION ".${Fontconfig_VERSION_PART}")
+ else()
+ set(Fontconfig_VERSION "${Fontconfig_VERSION_PART}")
+ endif()
+ endif()
+ endforeach()
+ endforeach()
+endif ()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Fontconfig
+ FOUND_VAR
+ Fontconfig_FOUND
+ REQUIRED_VARS
+ Fontconfig_LIBRARY
+ Fontconfig_INCLUDE_DIR
+ VERSION_VAR
+ Fontconfig_VERSION
+)
+
+
+if(Fontconfig_FOUND AND NOT TARGET Fontconfig::Fontconfig)
+ add_library(Fontconfig::Fontconfig UNKNOWN IMPORTED)
+ set_target_properties(Fontconfig::Fontconfig PROPERTIES
+ IMPORTED_LOCATION "${Fontconfig_LIBRARY}"
+ INTERFACE_COMPILE_OPTIONS "${Fontconfig_COMPILE_OPTIONS}"
+ INTERFACE_INCLUDE_DIRECTORIES "${Fontconfig_INCLUDE_DIR}"
+ )
+endif()
+
+mark_as_advanced(Fontconfig_LIBRARY Fontconfig_INCLUDE_DIR)
+
+if(Fontconfig_FOUND)
+ set(Fontconfig_LIBRARIES ${Fontconfig_LIBRARY})
+ set(Fontconfig_INCLUDE_DIRS ${Fontconfig_INCLUDE_DIR})
+endif()
diff --git a/Modules/FindFreetype.cmake b/Modules/FindFreetype.cmake
new file mode 100644
index 0000000..82885cb
--- /dev/null
+++ b/Modules/FindFreetype.cmake
@@ -0,0 +1,204 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindFreetype
+------------
+
+Find the FreeType font renderer includes and library.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.10
+
+This module defines the following :prop_tgt:`IMPORTED` target:
+
+``Freetype::Freetype``
+ The Freetype ``freetype`` library, if found
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``FREETYPE_FOUND``
+ true if the Freetype headers and libraries were found
+``FREETYPE_INCLUDE_DIRS``
+ directories containing the Freetype headers. This is the
+ concatenation of the variables:
+
+ ``FREETYPE_INCLUDE_DIR_ft2build``
+ directory holding the main Freetype API configuration header
+ ``FREETYPE_INCLUDE_DIR_freetype2``
+ directory holding Freetype public headers
+``FREETYPE_LIBRARIES``
+ the library to link against
+``FREETYPE_VERSION_STRING``
+ the version of freetype found
+
+.. versionadded:: 3.7
+ Debug and Release variants are found separately.
+
+Hints
+^^^^^
+
+The user may set the environment variable ``FREETYPE_DIR`` to the root
+directory of a Freetype installation.
+#]=======================================================================]
+
+# Created by Eric Wing.
+# Modifications by Alexander Neundorf.
+# This file has been renamed to "FindFreetype.cmake" instead of the correct
+# "FindFreeType.cmake" in order to be compatible with the one from KDE4, Alex.
+
+# Ugh, FreeType seems to use some #include trickery which
+# makes this harder than it should be. It looks like they
+# put ft2build.h in a common/easier-to-find location which
+# then contains a #include to a more specific header in a
+# more specific location (#include <freetype/config/ftheader.h>).
+# Then from there, they need to set a bunch of #define's
+# so you can do something like:
+# #include FT_FREETYPE_H
+# Unfortunately, using CMake's mechanisms like include_directories()
+# wants explicit full paths and this trickery doesn't work too well.
+# I'm going to attempt to cut out the middleman and hope
+# everything still works.
+
+set(FREETYPE_FIND_ARGS
+ HINTS
+ ENV FREETYPE_DIR
+ PATHS
+ ENV GTKMM_BASEPATH
+ [HKEY_CURRENT_USER\\SOFTWARE\\gtkmm\\2.4;Path]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\gtkmm\\2.4;Path]
+)
+
+find_path(
+ FREETYPE_INCLUDE_DIR_ft2build
+ ft2build.h
+ ${FREETYPE_FIND_ARGS}
+ PATH_SUFFIXES
+ include/freetype2
+ include
+ freetype2
+)
+
+find_path(
+ FREETYPE_INCLUDE_DIR_freetype2
+ NAMES
+ freetype/config/ftheader.h
+ config/ftheader.h
+ ${FREETYPE_FIND_ARGS}
+ PATH_SUFFIXES
+ include/freetype2
+ include
+ freetype2
+)
+
+if(NOT FREETYPE_LIBRARY)
+ find_library(FREETYPE_LIBRARY_RELEASE
+ NAMES
+ freetype
+ libfreetype
+ freetype219
+ ${FREETYPE_FIND_ARGS}
+ PATH_SUFFIXES
+ lib
+ )
+ find_library(FREETYPE_LIBRARY_DEBUG
+ NAMES
+ freetyped
+ libfreetyped
+ freetype219d
+ ${FREETYPE_FIND_ARGS}
+ PATH_SUFFIXES
+ lib
+ )
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(FREETYPE)
+else()
+ # on Windows, ensure paths are in canonical format (forward slahes):
+ file(TO_CMAKE_PATH "${FREETYPE_LIBRARY}" FREETYPE_LIBRARY)
+endif()
+
+unset(FREETYPE_FIND_ARGS)
+
+# set the user variables
+if(FREETYPE_INCLUDE_DIR_ft2build AND FREETYPE_INCLUDE_DIR_freetype2)
+ set(FREETYPE_INCLUDE_DIRS "${FREETYPE_INCLUDE_DIR_ft2build};${FREETYPE_INCLUDE_DIR_freetype2}")
+ list(REMOVE_DUPLICATES FREETYPE_INCLUDE_DIRS)
+endif()
+set(FREETYPE_LIBRARIES "${FREETYPE_LIBRARY}")
+
+if(EXISTS "${FREETYPE_INCLUDE_DIR_freetype2}/freetype/freetype.h")
+ set(FREETYPE_H "${FREETYPE_INCLUDE_DIR_freetype2}/freetype/freetype.h")
+elseif(EXISTS "${FREETYPE_INCLUDE_DIR_freetype2}/freetype.h")
+ set(FREETYPE_H "${FREETYPE_INCLUDE_DIR_freetype2}/freetype.h")
+endif()
+
+if(FREETYPE_INCLUDE_DIR_freetype2 AND FREETYPE_H)
+ file(STRINGS "${FREETYPE_H}" freetype_version_str
+ REGEX "^#[\t ]*define[\t ]+FREETYPE_(MAJOR|MINOR|PATCH)[\t ]+[0-9]+$")
+
+ unset(FREETYPE_VERSION_STRING)
+ foreach(VPART MAJOR MINOR PATCH)
+ foreach(VLINE ${freetype_version_str})
+ if(VLINE MATCHES "^#[\t ]*define[\t ]+FREETYPE_${VPART}[\t ]+([0-9]+)$")
+ set(FREETYPE_VERSION_PART "${CMAKE_MATCH_1}")
+ if(FREETYPE_VERSION_STRING)
+ string(APPEND FREETYPE_VERSION_STRING ".${FREETYPE_VERSION_PART}")
+ else()
+ set(FREETYPE_VERSION_STRING "${FREETYPE_VERSION_PART}")
+ endif()
+ unset(FREETYPE_VERSION_PART)
+ endif()
+ endforeach()
+ endforeach()
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+find_package_handle_standard_args(
+ Freetype
+ REQUIRED_VARS
+ FREETYPE_LIBRARY
+ FREETYPE_INCLUDE_DIRS
+ VERSION_VAR
+ FREETYPE_VERSION_STRING
+)
+
+mark_as_advanced(
+ FREETYPE_INCLUDE_DIR_freetype2
+ FREETYPE_INCLUDE_DIR_ft2build
+)
+
+if(Freetype_FOUND)
+ if(NOT TARGET Freetype::Freetype)
+ add_library(Freetype::Freetype UNKNOWN IMPORTED)
+ set_target_properties(Freetype::Freetype PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${FREETYPE_INCLUDE_DIRS}")
+
+ if(FREETYPE_LIBRARY_RELEASE)
+ set_property(TARGET Freetype::Freetype APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(Freetype::Freetype PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+ IMPORTED_LOCATION_RELEASE "${FREETYPE_LIBRARY_RELEASE}")
+ endif()
+
+ if(FREETYPE_LIBRARY_DEBUG)
+ set_property(TARGET Freetype::Freetype APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(Freetype::Freetype PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+ IMPORTED_LOCATION_DEBUG "${FREETYPE_LIBRARY_DEBUG}")
+ endif()
+
+ if(NOT FREETYPE_LIBRARY_RELEASE AND NOT FREETYPE_LIBRARY_DEBUG)
+ set_target_properties(Freetype::Freetype PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${FREETYPE_LIBRARY}")
+ endif()
+ endif()
+endif()
diff --git a/Modules/FindGCCXML.cmake b/Modules/FindGCCXML.cmake
new file mode 100644
index 0000000..e6c7f24
--- /dev/null
+++ b/Modules/FindGCCXML.cmake
@@ -0,0 +1,27 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindGCCXML
+----------
+
+Find the GCC-XML front-end executable.
+
+
+
+This module will define the following variables:
+
+::
+
+ GCCXML - the GCC-XML front-end executable.
+#]=======================================================================]
+
+find_program(GCCXML
+ NAMES gccxml
+ ../GCC_XML/gccxml
+ PATHS [HKEY_CURRENT_USER\\Software\\Kitware\\GCC_XML;loc]
+ "$ENV{ProgramFiles}/GCC_XML"
+ "C:/Program Files/GCC_XML"
+)
+
+mark_as_advanced(GCCXML)
diff --git a/Modules/FindGDAL.cmake b/Modules/FindGDAL.cmake
new file mode 100644
index 0000000..5237e15
--- /dev/null
+++ b/Modules/FindGDAL.cmake
@@ -0,0 +1,199 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindGDAL
+--------
+
+Find Geospatial Data Abstraction Library (GDAL).
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.14
+
+This module defines :prop_tgt:`IMPORTED` target ``GDAL::GDAL``
+if GDAL has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``GDAL_FOUND``
+ True if GDAL is found.
+``GDAL_INCLUDE_DIRS``
+ Include directories for GDAL headers.
+``GDAL_LIBRARIES``
+ Libraries to link to GDAL.
+``GDAL_VERSION``
+ .. versionadded:: 3.14
+ The version of GDAL found.
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``GDAL_LIBRARY``
+ The libgdal library file.
+``GDAL_INCLUDE_DIR``
+ The directory containing ``gdal.h``.
+
+Hints
+^^^^^
+
+Set ``GDAL_DIR`` or ``GDAL_ROOT`` in the environment to specify the
+GDAL installation prefix.
+
+The following variables may be set to modify the search strategy:
+
+``FindGDAL_SKIP_GDAL_CONFIG``
+ If set, ``gdal-config`` will not be used. This can be useful if there are
+ GDAL libraries built with autotools (which provide the tool) and CMake (which
+ do not) in the same environment.
+``GDAL_ADDITIONAL_LIBRARY_VERSIONS``
+ Extra versions of library names to search for.
+#]=======================================================================]
+
+# $GDALDIR is an environment variable that would
+# correspond to the ./configure --prefix=$GDAL_DIR
+# used in building gdal.
+#
+# Created by Eric Wing. I'm not a gdal user, but OpenSceneGraph uses it
+# for osgTerrain so I whipped this module together for completeness.
+# I actually don't know the conventions or where files are typically
+# placed in distros.
+# Any real gdal users are encouraged to correct this (but please don't
+# break the OS X framework stuff when doing so which is what usually seems
+# to happen).
+
+# This makes the presumption that you are include gdal.h like
+#
+#include "gdal.h"
+
+find_path(GDAL_INCLUDE_DIR gdal.h
+ HINTS
+ ENV GDAL_DIR
+ ENV GDAL_ROOT
+ PATH_SUFFIXES
+ include/gdal
+ include/GDAL
+ include
+ DOC "Path to the GDAL include directory"
+)
+mark_as_advanced(GDAL_INCLUDE_DIR)
+
+if(UNIX AND NOT FindGDAL_SKIP_GDAL_CONFIG)
+ # Use gdal-config to obtain the library version (this should hopefully
+ # allow us to -lgdal1.x.y where x.y are correct version)
+ # For some reason, libgdal development packages do not contain
+ # libgdal.so...
+ find_program(GDAL_CONFIG gdal-config
+ HINTS
+ ENV GDAL_DIR
+ ENV GDAL_ROOT
+ PATH_SUFFIXES bin
+ DOC "Path to the gdal-config tool"
+ )
+ mark_as_advanced(GDAL_CONFIG)
+
+ if(GDAL_CONFIG)
+ execute_process(COMMAND ${GDAL_CONFIG} --libs OUTPUT_VARIABLE GDAL_CONFIG_LIBS)
+
+ if(GDAL_CONFIG_LIBS)
+ # treat the output as a command line and split it up
+ separate_arguments(args NATIVE_COMMAND "${GDAL_CONFIG_LIBS}")
+
+ # only consider libraries whose name matches this pattern
+ set(name_pattern "[gG][dD][aA][lL]")
+
+ # consider each entry as a possible library path, name, or parent directory
+ foreach(arg IN LISTS args)
+ # library name
+ if("${arg}" MATCHES "^-l(.*)$")
+ set(lib "${CMAKE_MATCH_1}")
+
+ # only consider libraries whose name matches the expected pattern
+ if("${lib}" MATCHES "${name_pattern}")
+ list(APPEND _gdal_lib "${lib}")
+ endif()
+ # library search path
+ elseif("${arg}" MATCHES "^-L(.*)$")
+ list(APPEND _gdal_libpath "${CMAKE_MATCH_1}")
+ # assume this is a full path to a library
+ elseif(IS_ABSOLUTE "${arg}" AND EXISTS "${arg}")
+ # extract the file name
+ get_filename_component(lib "${arg}" NAME)
+
+ # only consider libraries whose name matches the expected pattern
+ if(NOT "${lib}" MATCHES "${name_pattern}")
+ continue()
+ endif()
+
+ # extract the file directory
+ get_filename_component(dir "${arg}" DIRECTORY)
+
+ # remove library prefixes/suffixes
+ string(REGEX REPLACE "^(${CMAKE_SHARED_LIBRARY_PREFIX}|${CMAKE_STATIC_LIBRARY_PREFIX})" "" lib "${lib}")
+ string(REGEX REPLACE "(${CMAKE_SHARED_LIBRARY_SUFFIX}|${CMAKE_STATIC_LIBRARY_SUFFIX})$" "" lib "${lib}")
+
+ # use the file name and directory as hints
+ list(APPEND _gdal_libpath "${dir}")
+ list(APPEND _gdal_lib "${lib}")
+ endif()
+ endforeach()
+ endif()
+ endif()
+endif()
+
+# GDAL name its library when built with CMake as `gdal${major}${minor}`.
+set(_gdal_versions
+ ${GDAL_ADDITIONAL_LIBRARY_VERSIONS} 3.0 2.4 2.3 2.2 2.1 2.0 1.11 1.10 1.9 1.8 1.7 1.6 1.5 1.4 1.3 1.2)
+
+set(_gdal_libnames)
+foreach (_gdal_version IN LISTS _gdal_versions)
+ string(REPLACE "." "" _gdal_version "${_gdal_version}")
+ list(APPEND _gdal_libnames "gdal${_gdal_version}" "GDAL${_gdal_version}")
+endforeach ()
+unset(_gdal_version)
+unset(_gdal_versions)
+
+find_library(GDAL_LIBRARY
+ NAMES ${_gdal_lib} ${_gdal_libnames} gdal gdal_i gdal1.5.0 gdal1.4.0 gdal1.3.2 GDAL
+ HINTS
+ ENV GDAL_DIR
+ ENV GDAL_ROOT
+ ${_gdal_libpath}
+ PATH_SUFFIXES lib
+ DOC "Path to the GDAL library"
+)
+mark_as_advanced(GDAL_LIBRARY)
+unset(_gdal_libnames)
+unset(_gdal_lib)
+
+if (EXISTS "${GDAL_INCLUDE_DIR}/gdal_version.h")
+ file(STRINGS "${GDAL_INCLUDE_DIR}/gdal_version.h" _gdal_version
+ REGEX "GDAL_RELEASE_NAME")
+ string(REGEX REPLACE ".*\"\(.*\)\"" "\\1" GDAL_VERSION "${_gdal_version}")
+ unset(_gdal_version)
+else ()
+ set(GDAL_VERSION GDAL_VERSION-NOTFOUND)
+endif ()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GDAL
+ VERSION_VAR GDAL_VERSION
+ REQUIRED_VARS GDAL_LIBRARY GDAL_INCLUDE_DIR)
+
+if (GDAL_FOUND)
+ set(GDAL_LIBRARIES ${GDAL_LIBRARY})
+ set(GDAL_INCLUDE_DIRS ${GDAL_INCLUDE_DIR})
+
+ if (NOT TARGET GDAL::GDAL)
+ add_library(GDAL::GDAL UNKNOWN IMPORTED)
+ set_target_properties(GDAL::GDAL PROPERTIES
+ IMPORTED_LOCATION "${GDAL_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${GDAL_INCLUDE_DIR}")
+ endif ()
+endif ()
diff --git a/Modules/FindGIF.cmake b/Modules/FindGIF.cmake
new file mode 100644
index 0000000..cea9cd8
--- /dev/null
+++ b/Modules/FindGIF.cmake
@@ -0,0 +1,128 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindGIF
+-------
+
+This finds the Graphics Interchange Format (GIF) library (``giflib``)
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+This module defines the following :prop_tgt:`IMPORTED` target:
+
+``GIF::GIF``
+ The ``giflib`` library, if found.
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``GIF_FOUND``
+ If false, do not try to use GIF.
+``GIF_INCLUDE_DIRS``
+ where to find gif_lib.h, etc.
+``GIF_LIBRARIES``
+ the libraries needed to use GIF.
+``GIF_VERSION``
+ 3, 4 or a full version string (eg 5.1.4) for versions >= 4.1.6.
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``GIF_INCLUDE_DIR``
+ where to find the GIF headers.
+``GIF_LIBRARY``
+ where to find the GIF library.
+
+Hints
+^^^^^
+
+``GIF_DIR`` is an environment variable that would correspond to the
+``./configure --prefix=$GIF_DIR``.
+#]=======================================================================]
+
+# Created by Eric Wing.
+# Modifications by Alexander Neundorf, Ben Campbell
+
+find_path(GIF_INCLUDE_DIR gif_lib.h
+ HINTS
+ ENV GIF_DIR
+ PATH_SUFFIXES include
+)
+
+# the gif library can have many names :-/
+set(POTENTIAL_GIF_LIBS gif libgif ungif libungif giflib giflib4)
+
+find_library(GIF_LIBRARY
+ NAMES ${POTENTIAL_GIF_LIBS}
+ NAMES_PER_DIR
+ HINTS
+ ENV GIF_DIR
+ PATH_SUFFIXES lib
+)
+
+# Very basic version detection.
+# The GIF_LIB_VERSION string in gif_lib.h seems to be unreliable, since it seems
+# to be always " Version 2.0, " in versions 3.x of giflib.
+# In version 4 the member UserData was added to GifFileType, so we check for this
+# one.
+# Versions after 4.1.6 define GIFLIB_MAJOR, GIFLIB_MINOR, and GIFLIB_RELEASE
+# see http://giflib.sourceforge.net/gif_lib.html#compatibility
+if(GIF_INCLUDE_DIR)
+ include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckStructHasMember.cmake)
+ CMAKE_PUSH_CHECK_STATE()
+ set(CMAKE_REQUIRED_QUIET ${GIF_FIND_QUIETLY})
+ set(CMAKE_REQUIRED_INCLUDES "${GIF_INCLUDE_DIR}")
+
+ # Check for the specific version defines (>=4.1.6 only)
+ file(STRINGS ${GIF_INCLUDE_DIR}/gif_lib.h _GIF_DEFS REGEX "^[ \t]*#define[ \t]+GIFLIB_(MAJOR|MINOR|RELEASE)")
+ if(_GIF_DEFS)
+ # yay - got exact version info
+ string(REGEX REPLACE ".*GIFLIB_MAJOR ([0-9]+).*" "\\1" _GIF_MAJ "${_GIF_DEFS}")
+ string(REGEX REPLACE ".*GIFLIB_MINOR ([0-9]+).*" "\\1" _GIF_MIN "${_GIF_DEFS}")
+ string(REGEX REPLACE ".*GIFLIB_RELEASE ([0-9]+).*" "\\1" _GIF_REL "${_GIF_DEFS}")
+ set(GIF_VERSION "${_GIF_MAJ}.${_GIF_MIN}.${_GIF_REL}")
+ else()
+ # use UserData field to sniff version instead
+ CHECK_STRUCT_HAS_MEMBER(GifFileType UserData gif_lib.h GIF_GifFileType_UserData )
+ if(GIF_GifFileType_UserData)
+ set(GIF_VERSION 4)
+ else()
+ set(GIF_VERSION 3)
+ endif()
+ endif()
+
+ unset(_GIF_MAJ)
+ unset(_GIF_MIN)
+ unset(_GIF_REL)
+ unset(_GIF_DEFS)
+ CMAKE_POP_CHECK_STATE()
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GIF REQUIRED_VARS GIF_LIBRARY GIF_INCLUDE_DIR
+ VERSION_VAR GIF_VERSION )
+
+if(GIF_FOUND)
+ set(GIF_INCLUDE_DIRS "${GIF_INCLUDE_DIR}")
+ set(GIF_LIBRARIES ${GIF_LIBRARY})
+
+ if(NOT TARGET GIF::GIF)
+ add_library(GIF::GIF UNKNOWN IMPORTED)
+ set_target_properties(GIF::GIF PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${GIF_INCLUDE_DIRS}")
+ if(EXISTS "${GIF_LIBRARY}")
+ set_target_properties(GIF::GIF PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${GIF_LIBRARY}")
+ endif()
+ endif()
+endif()
+
+mark_as_advanced(GIF_INCLUDE_DIR GIF_LIBRARY)
diff --git a/Modules/FindGLEW.cmake b/Modules/FindGLEW.cmake
new file mode 100644
index 0000000..b9ebe08
--- /dev/null
+++ b/Modules/FindGLEW.cmake
@@ -0,0 +1,350 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindGLEW
+--------
+
+Find the OpenGL Extension Wrangler Library (GLEW)
+
+Input Variables
+^^^^^^^^^^^^^^^
+
+The following variables may be set to influence this module's behavior:
+
+``GLEW_USE_STATIC_LIBS``
+ to find and create :prop_tgt:`IMPORTED` target for static linkage.
+
+``GLEW_VERBOSE``
+ to output a detailed log of this module.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.1
+
+This module defines the following :ref:`Imported Targets <Imported Targets>`:
+
+
+``GLEW::glew``
+ The GLEW shared library.
+``GLEW::glew_s``
+ The GLEW static library, if ``GLEW_USE_STATIC_LIBS`` is set to ``TRUE``.
+``GLEW::GLEW``
+ Duplicates either ``GLEW::glew`` or ``GLEW::glew_s`` based on availability.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``GLEW_INCLUDE_DIRS``
+ include directories for GLEW
+``GLEW_LIBRARIES``
+ libraries to link against GLEW
+``GLEW_SHARED_LIBRARIES``
+ libraries to link against shared GLEW
+``GLEW_STATIC_LIBRARIES``
+ libraries to link against static GLEW
+``GLEW_FOUND``
+ true if GLEW has been found and can be used
+``GLEW_VERSION``
+ GLEW version
+``GLEW_VERSION_MAJOR``
+ GLEW major version
+``GLEW_VERSION_MINOR``
+ GLEW minor version
+``GLEW_VERSION_MICRO``
+ GLEW micro version
+
+.. versionadded:: 3.7
+ Debug and Release variants are found separately.
+
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+find_package(GLEW CONFIG QUIET)
+
+if(GLEW_FOUND)
+ find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_CONFIG)
+ return()
+endif()
+
+if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: did not find GLEW CMake config file. Searching for libraries.")
+endif()
+
+if(APPLE)
+ find_package(OpenGL QUIET)
+
+ if(OpenGL_FOUND)
+ if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: Found OpenGL Framework.")
+ message(STATUS "FindGLEW: OPENGL_LIBRARIES: ${OPENGL_LIBRARIES}")
+ endif()
+ else()
+ if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: could not find GLEW library.")
+ endif()
+ return()
+ endif()
+endif()
+
+
+function(__glew_set_find_library_suffix shared_or_static)
+ if((UNIX AND NOT APPLE) AND "${shared_or_static}" MATCHES "SHARED")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" PARENT_SCOPE)
+ elseif((UNIX AND NOT APPLE) AND "${shared_or_static}" MATCHES "STATIC")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE)
+ elseif(APPLE AND "${shared_or_static}" MATCHES "SHARED")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib;.so" PARENT_SCOPE)
+ elseif(APPLE AND "${shared_or_static}" MATCHES "STATIC")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE)
+ elseif(WIN32 AND "${shared_or_static}" MATCHES "SHARED")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" PARENT_SCOPE)
+ elseif(WIN32 AND "${shared_or_static}" MATCHES "STATIC")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib;.dll.a" PARENT_SCOPE)
+ endif()
+
+ if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: CMAKE_FIND_LIBRARY_SUFFIXES for ${shared_or_static}: ${CMAKE_FIND_LIBRARY_SUFFIXES}")
+ endif()
+endfunction()
+
+
+if(GLEW_VERBOSE)
+ if(DEFINED GLEW_USE_STATIC_LIBS)
+ message(STATUS "FindGLEW: GLEW_USE_STATIC_LIBS: ${GLEW_USE_STATIC_LIBS}.")
+ else()
+ message(STATUS "FindGLEW: GLEW_USE_STATIC_LIBS is undefined. Treated as FALSE.")
+ endif()
+endif()
+
+find_path(GLEW_INCLUDE_DIR GL/glew.h)
+mark_as_advanced(GLEW_INCLUDE_DIR)
+
+set(GLEW_INCLUDE_DIRS ${GLEW_INCLUDE_DIR})
+
+if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: GLEW_INCLUDE_DIR: ${GLEW_INCLUDE_DIR}")
+ message(STATUS "FindGLEW: GLEW_INCLUDE_DIRS: ${GLEW_INCLUDE_DIRS}")
+endif()
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(_arch "x64")
+else()
+ set(_arch "Win32")
+endif()
+
+set(__GLEW_CURRENT_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+
+__glew_set_find_library_suffix(SHARED)
+
+find_library(GLEW_SHARED_LIBRARY_RELEASE
+ NAMES GLEW glew glew32
+ NAMES_PER_DIR
+ PATH_SUFFIXES lib lib64 libx32 lib/Release/${_arch}
+ PATHS ENV GLEW_ROOT)
+
+find_library(GLEW_SHARED_LIBRARY_DEBUG
+ NAMES GLEWd glewd glew32d
+ NAMES_PER_DIR
+ PATH_SUFFIXES lib lib64
+ PATHS ENV GLEW_ROOT)
+
+
+__glew_set_find_library_suffix(STATIC)
+
+find_library(GLEW_STATIC_LIBRARY_RELEASE
+ NAMES GLEW glew glew32s
+ NAMES_PER_DIR
+ PATH_SUFFIXES lib lib64 libx32 lib/Release/${_arch}
+ PATHS ENV GLEW_ROOT)
+
+find_library(GLEW_STATIC_LIBRARY_DEBUG
+ NAMES GLEWds glewds glew32ds
+ NAMES_PER_DIR
+ PATH_SUFFIXES lib lib64
+ PATHS ENV GLEW_ROOT)
+
+set(CMAKE_FIND_LIBRARY_SUFFIXES ${__GLEW_CURRENT_FIND_LIBRARY_SUFFIXES})
+unset(__GLEW_CURRENT_FIND_LIBRARY_SUFFIXES)
+
+include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+
+select_library_configurations(GLEW_SHARED)
+select_library_configurations(GLEW_STATIC)
+
+if(NOT GLEW_USE_STATIC_LIBS)
+ set(GLEW_LIBRARIES ${GLEW_SHARED_LIBRARY})
+else()
+ set(GLEW_LIBRARIES ${GLEW_STATIC_LIBRARY})
+endif()
+
+
+if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY_RELEASE: ${GLEW_SHARED_LIBRARY_RELEASE}")
+ message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY_RELEASE: ${GLEW_STATIC_LIBRARY_RELEASE}")
+ message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY_DEBUG: ${GLEW_SHARED_LIBRARY_DEBUG}")
+ message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY_DEBUG: ${GLEW_STATIC_LIBRARY_DEBUG}")
+ message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY: ${GLEW_SHARED_LIBRARY}")
+ message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY: ${GLEW_STATIC_LIBRARY}")
+ message(STATUS "FindGLEW: GLEW_LIBRARIES: ${GLEW_LIBRARIES}")
+endif()
+
+
+# Read version from GL/glew.h file
+if(EXISTS "${GLEW_INCLUDE_DIR}/GL/glew.h")
+ file(STRINGS "${GLEW_INCLUDE_DIR}/GL/glew.h" _contents REGEX "^VERSION_.+ [0-9]+")
+ if(_contents)
+ string(REGEX REPLACE ".*VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MAJOR "${_contents}")
+ string(REGEX REPLACE ".*VERSION_MINOR[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MINOR "${_contents}")
+ string(REGEX REPLACE ".*VERSION_MICRO[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MICRO "${_contents}")
+ set(GLEW_VERSION "${GLEW_VERSION_MAJOR}.${GLEW_VERSION_MINOR}.${GLEW_VERSION_MICRO}")
+ endif()
+endif()
+
+if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: GLEW_VERSION_MAJOR: ${GLEW_VERSION_MAJOR}")
+ message(STATUS "FindGLEW: GLEW_VERSION_MINOR: ${GLEW_VERSION_MINOR}")
+ message(STATUS "FindGLEW: GLEW_VERSION_MICRO: ${GLEW_VERSION_MICRO}")
+ message(STATUS "FindGLEW: GLEW_VERSION: ${GLEW_VERSION}")
+endif()
+
+find_package_handle_standard_args(GLEW
+ REQUIRED_VARS GLEW_INCLUDE_DIRS GLEW_LIBRARIES
+ VERSION_VAR GLEW_VERSION)
+
+if(NOT GLEW_FOUND)
+ if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: could not find GLEW library.")
+ endif()
+ return()
+endif()
+
+
+if(NOT TARGET GLEW::glew AND NOT GLEW_USE_STATIC_LIBS)
+ if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: Creating GLEW::glew imported target.")
+ endif()
+
+ add_library(GLEW::glew UNKNOWN IMPORTED)
+
+ set_target_properties(GLEW::glew
+ PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
+
+ if(APPLE)
+ set_target_properties(GLEW::glew
+ PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL)
+ endif()
+
+ if(GLEW_SHARED_LIBRARY_RELEASE)
+ set_property(TARGET GLEW::glew
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+
+ set_target_properties(GLEW::glew
+ PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_SHARED_LIBRARY_RELEASE}")
+ endif()
+
+ if(GLEW_SHARED_LIBRARY_DEBUG)
+ set_property(TARGET GLEW::glew
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+
+ set_target_properties(GLEW::glew
+ PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_SHARED_LIBRARY_DEBUG}")
+ endif()
+
+elseif(NOT TARGET GLEW::glew_s AND GLEW_USE_STATIC_LIBS)
+ if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: Creating GLEW::glew_s imported target.")
+ endif()
+
+ add_library(GLEW::glew_s UNKNOWN IMPORTED)
+
+ set_target_properties(GLEW::glew_s
+ PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
+
+ if(APPLE)
+ set_target_properties(GLEW::glew_s
+ PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL)
+ endif()
+
+ if(GLEW_STATIC_LIBRARY_RELEASE)
+ set_property(TARGET GLEW::glew_s
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+
+ set_target_properties(GLEW::glew_s
+ PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_STATIC_LIBRARY_RELEASE}")
+ endif()
+
+ if(GLEW_STATIC_LIBRARY_DEBUG)
+ set_property(TARGET GLEW::glew_s
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+
+ set_target_properties(GLEW::glew_s
+ PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_STATIC_LIBRARY_DEBUG}")
+ endif()
+endif()
+
+if(NOT TARGET GLEW::GLEW)
+ if(GLEW_VERBOSE)
+ message(STATUS "FindGLEW: Creating GLEW::GLEW imported target.")
+ endif()
+
+ add_library(GLEW::GLEW UNKNOWN IMPORTED)
+
+ set_target_properties(GLEW::GLEW
+ PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
+
+ if(APPLE)
+ set_target_properties(GLEW::GLEW
+ PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL)
+ endif()
+
+ if(TARGET GLEW::glew)
+ if(GLEW_SHARED_LIBRARY_RELEASE)
+ set_property(TARGET GLEW::GLEW
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+
+ set_target_properties(GLEW::GLEW
+ PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_SHARED_LIBRARY_RELEASE}")
+ endif()
+
+ if(GLEW_SHARED_LIBRARY_DEBUG)
+ set_property(TARGET GLEW::GLEW
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+
+ set_target_properties(GLEW::GLEW
+ PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_SHARED_LIBRARY_DEBUG}")
+ endif()
+
+ elseif(TARGET GLEW::glew_s)
+ if(GLEW_STATIC_LIBRARY_RELEASE)
+ set_property(TARGET GLEW::GLEW
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+
+ set_target_properties(GLEW::GLEW
+ PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_STATIC_LIBRARY_RELEASE}")
+ endif()
+
+ if(GLEW_STATIC_LIBRARY_DEBUG AND GLEW_USE_STATIC_LIBS)
+ set_property(TARGET GLEW::GLEW
+ APPEND
+ PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+
+ set_target_properties(GLEW::GLEW
+ PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_STATIC_LIBRARY_DEBUG}")
+ endif()
+
+ elseif(GLEW_VERBOSE)
+ message(WARNING "FindGLEW: no `GLEW::glew` or `GLEW::glew_s` target was created. Something went wrong in FindGLEW target creation.")
+ endif()
+endif()
diff --git a/Modules/FindGLU.cmake b/Modules/FindGLU.cmake
new file mode 100644
index 0000000..9892805
--- /dev/null
+++ b/Modules/FindGLU.cmake
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# Use of this file is deprecated, and is here for backwards compatibility with CMake 1.4
+# GLU library is now found by FindOpenGL.cmake
+#
+
+message(STATUS
+ "WARNING: you are using the obsolete 'GLU' package, please use 'OpenGL' instead")
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindOpenGL.cmake)
+
+if (OPENGL_GLU_FOUND)
+ set (GLU_LIBRARY ${OPENGL_LIBRARIES})
+ set (GLU_INCLUDE_PATH ${OPENGL_INCLUDE_DIR})
+endif ()
diff --git a/Modules/FindGLUT.cmake b/Modules/FindGLUT.cmake
new file mode 100644
index 0000000..2770c60
--- /dev/null
+++ b/Modules/FindGLUT.cmake
@@ -0,0 +1,206 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindGLUT
+--------
+
+Find OpenGL Utility Toolkit (GLUT) library and include files.
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.1
+
+This module defines the :prop_tgt:`IMPORTED` targets:
+
+``GLUT::GLUT``
+ Defined if the system has GLUT.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module sets the following variables:
+
+::
+
+ GLUT_INCLUDE_DIR, where to find GL/glut.h, etc.
+ GLUT_LIBRARIES, the libraries to link against
+ GLUT_FOUND, If false, do not try to use GLUT.
+
+Also defined, but not for general use are:
+
+::
+
+ GLUT_glut_LIBRARY = the full path to the glut library.
+ GLUT_Xmu_LIBRARY = the full path to the Xmu library.
+ GLUT_Xi_LIBRARY = the full path to the Xi Library.
+
+.. versionadded:: 3.13
+ Debug and Release variants are found separately.
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+
+if (WIN32)
+ find_path( GLUT_INCLUDE_DIR NAMES GL/glut.h
+ PATHS ${GLUT_ROOT_PATH}/include )
+ find_library( GLUT_glut_LIBRARY_RELEASE NAMES glut glut32 freeglut
+ PATHS
+ ${OPENGL_LIBRARY_DIR}
+ ${GLUT_ROOT_PATH}/Release
+ )
+ find_library( GLUT_glut_LIBRARY_DEBUG NAMES freeglutd
+ PATHS
+ ${OPENGL_LIBRARY_DIR}
+ ${GLUT_ROOT_PATH}/Debug
+ )
+ mark_as_advanced(GLUT_glut_LIBRARY_RELEASE GLUT_glut_LIBRARY_DEBUG)
+ select_library_configurations(GLUT_glut)
+else ()
+
+ if (APPLE)
+ find_path(GLUT_INCLUDE_DIR glut.h ${OPENGL_LIBRARY_DIR})
+ find_library(GLUT_glut_LIBRARY GLUT DOC "GLUT library for OSX")
+ find_library(GLUT_cocoa_LIBRARY Cocoa DOC "Cocoa framework for OSX")
+ mark_as_advanced(GLUT_glut_LIBRARY GLUT_cocoa_LIBRARY)
+
+ if(GLUT_cocoa_LIBRARY AND NOT TARGET GLUT::Cocoa)
+ add_library(GLUT::Cocoa UNKNOWN IMPORTED)
+ # Cocoa should always be a Framework, but we check to make sure.
+ if(GLUT_cocoa_LIBRARY MATCHES "/([^/]+)\\.framework$")
+ set(_glut_cocoa "${GLUT_cocoa_LIBRARY}/${CMAKE_MATCH_1}")
+ if(EXISTS "${_glut_cocoa}.tbd")
+ string(APPEND _glut_cocoa ".tbd")
+ endif()
+ set_target_properties(GLUT::Cocoa PROPERTIES
+ IMPORTED_LOCATION "${_glut_cocoa}")
+ else()
+ set_target_properties(GLUT::Cocoa PROPERTIES
+ IMPORTED_LOCATION "${GLUT_cocoa_LIBRARY}")
+ endif()
+ endif()
+ else ()
+
+ if (BEOS)
+
+ set(_GLUT_INC_DIR /boot/develop/headers/os/opengl)
+ set(_GLUT_glut_LIB_DIR /boot/develop/lib/x86)
+
+ else()
+
+ find_library( GLUT_Xi_LIBRARY Xi
+ /usr/openwin/lib
+ )
+ mark_as_advanced(GLUT_Xi_LIBRARY)
+
+ find_library( GLUT_Xmu_LIBRARY Xmu
+ /usr/openwin/lib
+ )
+ mark_as_advanced(GLUT_Xmu_LIBRARY)
+
+ if(GLUT_Xi_LIBRARY AND NOT TARGET GLUT::Xi)
+ add_library(GLUT::Xi UNKNOWN IMPORTED)
+ set_target_properties(GLUT::Xi PROPERTIES
+ IMPORTED_LOCATION "${GLUT_Xi_LIBRARY}")
+ endif()
+
+ if(GLUT_Xmu_LIBRARY AND NOT TARGET GLUT::Xmu)
+ add_library(GLUT::Xmu UNKNOWN IMPORTED)
+ set_target_properties(GLUT::Xmu PROPERTIES
+ IMPORTED_LOCATION "${GLUT_Xmu_LIBRARY}")
+ endif()
+
+ endif ()
+
+ find_path( GLUT_INCLUDE_DIR GL/glut.h
+ /usr/include/GL
+ /usr/openwin/share/include
+ /usr/openwin/include
+ /opt/graphics/OpenGL/include
+ /opt/graphics/OpenGL/contrib/libglut
+ ${_GLUT_INC_DIR}
+ )
+
+ find_library( GLUT_glut_LIBRARY glut
+ /usr/openwin/lib
+ ${_GLUT_glut_LIB_DIR}
+ )
+ mark_as_advanced(GLUT_glut_LIBRARY)
+
+ unset(_GLUT_INC_DIR)
+ unset(_GLUT_glut_LIB_DIR)
+
+ endif ()
+
+endif ()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLUT REQUIRED_VARS GLUT_glut_LIBRARY GLUT_INCLUDE_DIR)
+
+if (GLUT_FOUND)
+ # Is -lXi and -lXmu required on all platforms that have it?
+ # If not, we need some way to figure out what platform we are on.
+ set( GLUT_LIBRARIES
+ ${GLUT_glut_LIBRARY}
+ )
+ foreach(v GLUT_Xmu_LIBRARY GLUT_Xi_LIBRARY GLUT_cocoa_LIBRARY)
+ if(${v})
+ list(APPEND GLUT_LIBRARIES ${${v}})
+ endif()
+ endforeach()
+
+ if(NOT TARGET GLUT::GLUT)
+ add_library(GLUT::GLUT UNKNOWN IMPORTED)
+ set_target_properties(GLUT::GLUT PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${GLUT_INCLUDE_DIR}")
+ if(GLUT_glut_LIBRARY MATCHES "/([^/]+)\\.framework$")
+ set(_glut_glut "${GLUT_glut_LIBRARY}/${CMAKE_MATCH_1}")
+ if(EXISTS "${_glut_glut}.tbd")
+ string(APPEND _glut_glut ".tbd")
+ endif()
+ set_target_properties(GLUT::GLUT PROPERTIES
+ IMPORTED_LOCATION "${_glut_glut}")
+ else()
+ if(GLUT_glut_LIBRARY_RELEASE)
+ set_property(TARGET GLUT::GLUT APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(GLUT::GLUT PROPERTIES
+ IMPORTED_LOCATION_RELEASE "${GLUT_glut_LIBRARY_RELEASE}")
+ endif()
+
+ if(GLUT_glut_LIBRARY_DEBUG)
+ set_property(TARGET GLUT::GLUT APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(GLUT::GLUT PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${GLUT_glut_LIBRARY_DEBUG}")
+ endif()
+
+ if(NOT GLUT_glut_LIBRARY_RELEASE AND NOT GLUT_glut_LIBRARY_DEBUG)
+ set_property(TARGET GLUT::GLUT APPEND PROPERTY
+ IMPORTED_LOCATION "${GLUT_glut_LIBRARY}")
+ endif()
+ endif()
+
+ if(TARGET GLUT::Xmu)
+ set_property(TARGET GLUT::GLUT APPEND
+ PROPERTY INTERFACE_LINK_LIBRARIES GLUT::Xmu)
+ endif()
+
+ if(TARGET GLUT::Xi)
+ set_property(TARGET GLUT::GLUT APPEND
+ PROPERTY INTERFACE_LINK_LIBRARIES GLUT::Xi)
+ endif()
+
+ if(TARGET GLUT::Cocoa)
+ set_property(TARGET GLUT::GLUT APPEND
+ PROPERTY INTERFACE_LINK_LIBRARIES GLUT::Cocoa)
+ endif()
+ endif()
+
+ #The following deprecated settings are for backwards compatibility with CMake1.4
+ set (GLUT_LIBRARY ${GLUT_LIBRARIES})
+ set (GLUT_INCLUDE_PATH ${GLUT_INCLUDE_DIR})
+endif()
+
+mark_as_advanced(GLUT_INCLUDE_DIR)
diff --git a/Modules/FindGSL.cmake b/Modules/FindGSL.cmake
new file mode 100644
index 0000000..3d4e7f9
--- /dev/null
+++ b/Modules/FindGSL.cmake
@@ -0,0 +1,231 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindGSL
+--------
+
+.. versionadded:: 3.2
+
+Find the native GNU Scientific Library (GSL) includes and libraries.
+
+The GNU Scientific Library (GSL) is a numerical library for C and C++
+programmers. It is free software under the GNU General Public
+License.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+If GSL is found, this module defines the following :prop_tgt:`IMPORTED`
+targets::
+
+ GSL::gsl - The main GSL library.
+ GSL::gslcblas - The CBLAS support library used by GSL.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project::
+
+ GSL_FOUND - True if GSL found on the local system
+ GSL_INCLUDE_DIRS - Location of GSL header files.
+ GSL_LIBRARIES - The GSL libraries.
+ GSL_VERSION - The version of the discovered GSL install.
+
+Hints
+^^^^^
+
+Set ``GSL_ROOT_DIR`` to a directory that contains a GSL installation.
+
+This script expects to find libraries at ``$GSL_ROOT_DIR/lib`` and the GSL
+headers at ``$GSL_ROOT_DIR/include/gsl``. The library directory may
+optionally provide Release and Debug folders. If available, the libraries
+named ``gsld``, ``gslblasd`` or ``cblasd`` are recognized as debug libraries.
+For Unix-like systems, this script will use ``$GSL_ROOT_DIR/bin/gsl-config``
+(if found) to aid in the discovery of GSL.
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+This module may set the following variables depending on platform and type
+of GSL installation discovered. These variables may optionally be set to
+help this module find the correct files::
+
+ GSL_CBLAS_LIBRARY - Location of the GSL CBLAS library.
+ GSL_CBLAS_LIBRARY_DEBUG - Location of the debug GSL CBLAS library (if any).
+ GSL_CONFIG_EXECUTABLE - Location of the ``gsl-config`` script (if any).
+ GSL_LIBRARY - Location of the GSL library.
+ GSL_LIBRARY_DEBUG - Location of the debug GSL library (if any).
+
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+#=============================================================================
+# If the user has provided ``GSL_ROOT_DIR``, use it! Choose items found
+# at this location over system locations.
+if( EXISTS "$ENV{GSL_ROOT_DIR}" )
+ file( TO_CMAKE_PATH "$ENV{GSL_ROOT_DIR}" GSL_ROOT_DIR )
+ set( GSL_ROOT_DIR "${GSL_ROOT_DIR}" CACHE PATH "Prefix for GSL installation." )
+endif()
+if( NOT EXISTS "${GSL_ROOT_DIR}" )
+ set( GSL_USE_PKGCONFIG ON )
+endif()
+
+#=============================================================================
+# As a first try, use the PkgConfig module. This will work on many
+# *NIX systems. See :module:`findpkgconfig`
+# This will return ``GSL_INCLUDEDIR`` and ``GSL_LIBDIR`` used below.
+if( GSL_USE_PKGCONFIG )
+ find_package(PkgConfig)
+ pkg_check_modules( GSL QUIET gsl )
+
+ if( EXISTS "${GSL_INCLUDEDIR}" )
+ get_filename_component( GSL_ROOT_DIR "${GSL_INCLUDEDIR}" DIRECTORY CACHE)
+ endif()
+endif()
+
+#=============================================================================
+# Set GSL_INCLUDE_DIRS and GSL_LIBRARIES. If we skipped the PkgConfig step, try
+# to find the libraries at $GSL_ROOT_DIR (if provided) or in standard system
+# locations. These find_library and find_path calls will prefer custom
+# locations over standard locations (HINTS). If the requested file is not found
+# at the HINTS location, standard system locations will be still be searched
+# (/usr/lib64 (Redhat), lib/i386-linux-gnu (Debian)).
+
+find_path( GSL_INCLUDE_DIR
+ NAMES gsl/gsl_sf.h
+ HINTS ${GSL_ROOT_DIR}/include ${GSL_INCLUDEDIR}
+)
+find_library( GSL_LIBRARY
+ NAMES gsl
+ HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
+ PATH_SUFFIXES Release Debug
+)
+find_library( GSL_CBLAS_LIBRARY
+ NAMES gslcblas cblas
+ HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
+ PATH_SUFFIXES Release Debug
+)
+# Do we also have debug versions?
+find_library( GSL_LIBRARY_DEBUG
+ NAMES gsld gsl
+ HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
+ PATH_SUFFIXES Debug
+)
+find_library( GSL_CBLAS_LIBRARY_DEBUG
+ NAMES gslcblasd cblasd gslcblas cblas
+ HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
+ PATH_SUFFIXES Debug
+)
+set( GSL_INCLUDE_DIRS ${GSL_INCLUDE_DIR} )
+set( GSL_LIBRARIES ${GSL_LIBRARY} ${GSL_CBLAS_LIBRARY} )
+
+# If we didn't use PkgConfig, try to find the version via gsl-config or by
+# reading gsl_version.h.
+if( NOT GSL_VERSION )
+ # 1. If gsl-config exists, query for the version.
+ find_program( GSL_CONFIG_EXECUTABLE
+ NAMES gsl-config
+ HINTS "${GSL_ROOT_DIR}/bin"
+ )
+ if( EXISTS "${GSL_CONFIG_EXECUTABLE}" )
+ execute_process(
+ COMMAND "${GSL_CONFIG_EXECUTABLE}" --version
+ OUTPUT_VARIABLE GSL_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE )
+ endif()
+
+ # 2. If gsl-config is not available, try looking in gsl/gsl_version.h
+ if( NOT GSL_VERSION AND EXISTS "${GSL_INCLUDE_DIRS}/gsl/gsl_version.h" )
+ file( STRINGS "${GSL_INCLUDE_DIRS}/gsl/gsl_version.h" gsl_version_h_contents REGEX "define GSL_VERSION" )
+ string( REGEX REPLACE ".*([0-9]\\.[0-9][0-9]?).*" "\\1" GSL_VERSION ${gsl_version_h_contents} )
+ endif()
+
+ # might also try scraping the directory name for a regex match "gsl-X.X"
+endif()
+
+#=============================================================================
+# handle the QUIETLY and REQUIRED arguments and set GSL_FOUND to TRUE if all
+# listed variables are TRUE
+find_package_handle_standard_args( GSL
+ FOUND_VAR
+ GSL_FOUND
+ REQUIRED_VARS
+ GSL_INCLUDE_DIR
+ GSL_LIBRARY
+ GSL_CBLAS_LIBRARY
+ VERSION_VAR
+ GSL_VERSION
+ )
+
+mark_as_advanced( GSL_ROOT_DIR GSL_VERSION GSL_LIBRARY GSL_INCLUDE_DIR
+ GSL_CBLAS_LIBRARY GSL_LIBRARY_DEBUG GSL_CBLAS_LIBRARY_DEBUG
+ GSL_USE_PKGCONFIG GSL_CONFIG )
+
+#=============================================================================
+# Register imported libraries:
+# 1. If we can find a Windows .dll file (or if we can find both Debug and
+# Release libraries), we will set appropriate target properties for these.
+# 2. However, for most systems, we will only register the import location and
+# include directory.
+
+# Look for dlls, or Release and Debug libraries.
+if(WIN32)
+ string( REPLACE ".lib" ".dll" GSL_LIBRARY_DLL "${GSL_LIBRARY}" )
+ string( REPLACE ".lib" ".dll" GSL_CBLAS_LIBRARY_DLL "${GSL_CBLAS_LIBRARY}" )
+ string( REPLACE ".lib" ".dll" GSL_LIBRARY_DEBUG_DLL "${GSL_LIBRARY_DEBUG}" )
+ string( REPLACE ".lib" ".dll" GSL_CBLAS_LIBRARY_DEBUG_DLL "${GSL_CBLAS_LIBRARY_DEBUG}" )
+endif()
+
+if( GSL_FOUND AND NOT TARGET GSL::gsl )
+ if( EXISTS "${GSL_LIBRARY_DLL}" AND EXISTS "${GSL_CBLAS_LIBRARY_DLL}")
+
+ # Windows systems with dll libraries.
+ add_library( GSL::gsl SHARED IMPORTED )
+ add_library( GSL::gslcblas SHARED IMPORTED )
+
+ # Windows with dlls, but only Release libraries.
+ set_target_properties( GSL::gslcblas PROPERTIES
+ IMPORTED_LOCATION_RELEASE "${GSL_CBLAS_LIBRARY_DLL}"
+ IMPORTED_IMPLIB "${GSL_CBLAS_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${GSL_INCLUDE_DIRS}"
+ IMPORTED_CONFIGURATIONS Release
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C" )
+ set_target_properties( GSL::gsl PROPERTIES
+ IMPORTED_LOCATION_RELEASE "${GSL_LIBRARY_DLL}"
+ IMPORTED_IMPLIB "${GSL_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${GSL_INCLUDE_DIRS}"
+ IMPORTED_CONFIGURATIONS Release
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ INTERFACE_LINK_LIBRARIES GSL::gslcblas )
+
+ # If we have both Debug and Release libraries
+ if( EXISTS "${GSL_LIBRARY_DEBUG_DLL}" AND EXISTS "${GSL_CBLAS_LIBRARY_DEBUG_DLL}")
+ set_property( TARGET GSL::gslcblas APPEND PROPERTY IMPORTED_CONFIGURATIONS Debug )
+ set_target_properties( GSL::gslcblas PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${GSL_CBLAS_LIBRARY_DEBUG_DLL}"
+ IMPORTED_IMPLIB_DEBUG "${GSL_CBLAS_LIBRARY_DEBUG}" )
+ set_property( TARGET GSL::gsl APPEND PROPERTY IMPORTED_CONFIGURATIONS Debug )
+ set_target_properties( GSL::gsl PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${GSL_LIBRARY_DEBUG_DLL}"
+ IMPORTED_IMPLIB_DEBUG "${GSL_LIBRARY_DEBUG}" )
+ endif()
+
+ else()
+
+ # For all other environments (ones without dll libraries), create
+ # the imported library targets.
+ add_library( GSL::gsl UNKNOWN IMPORTED )
+ add_library( GSL::gslcblas UNKNOWN IMPORTED )
+ set_target_properties( GSL::gslcblas PROPERTIES
+ IMPORTED_LOCATION "${GSL_CBLAS_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${GSL_INCLUDE_DIRS}"
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C" )
+ set_target_properties( GSL::gsl PROPERTIES
+ IMPORTED_LOCATION "${GSL_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${GSL_INCLUDE_DIRS}"
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ INTERFACE_LINK_LIBRARIES GSL::gslcblas )
+ endif()
+endif()
diff --git a/Modules/FindGTK.cmake b/Modules/FindGTK.cmake
new file mode 100644
index 0000000..552b19a
--- /dev/null
+++ b/Modules/FindGTK.cmake
@@ -0,0 +1,153 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindGTK
+-------
+
+Find GTK, glib and GTKGLArea
+
+::
+
+ GTK_INCLUDE_DIR - Directories to include to use GTK
+ GTK_LIBRARIES - Files to link against to use GTK
+ GTK_FOUND - GTK was found
+ GTK_GL_FOUND - GTK's GL features were found
+#]=======================================================================]
+
+# don't even bother under WIN32
+if(UNIX)
+
+ find_path( GTK_gtk_INCLUDE_PATH NAMES gtk/gtk.h
+ PATH_SUFFIXES gtk-1.2 gtk12
+ PATHS
+ /usr/openwin/share/include
+ /usr/openwin/include
+ /opt/gnome/include
+ )
+
+ # Some Linux distributions (e.g. Red Hat) have glibconfig.h
+ # and glib.h in different directories, so we need to look
+ # for both.
+ # - Atanas Georgiev <atanas@cs.columbia.edu>
+
+ find_path( GTK_glibconfig_INCLUDE_PATH NAMES glibconfig.h
+ PATH_SUFFIXES glib/include lib/glib/include include/glib12
+ PATHS
+ /usr/openwin/share/include
+ /opt/gnome/include
+ /opt/gnome/lib/glib/include
+ )
+
+ find_path( GTK_glib_INCLUDE_PATH NAMES glib.h
+ PATH_SUFFIXES gtk-1.2 glib-1.2 glib12 glib/include lib/glib/include
+ PATHS
+ /usr/openwin/share/include
+ /opt/gnome/include
+ )
+
+ find_path( GTK_gtkgl_INCLUDE_PATH NAMES gtkgl/gtkglarea.h
+ PATHS /usr/openwin/share/include
+ /opt/gnome/include
+ )
+
+ find_library( GTK_gtkgl_LIBRARY gtkgl
+ /usr/openwin/lib
+ /opt/gnome/lib
+ )
+
+ #
+ # The 12 suffix is thanks to the FreeBSD ports collection
+ #
+
+ find_library( GTK_gtk_LIBRARY
+ NAMES gtk gtk12
+ PATHS /usr/openwin/lib
+ /opt/gnome/lib
+ )
+
+ find_library( GTK_gdk_LIBRARY
+ NAMES gdk gdk12
+ PATHS /usr/openwin/lib
+ /opt/gnome/lib
+ )
+
+ find_library( GTK_gmodule_LIBRARY
+ NAMES gmodule gmodule12
+ PATHS /usr/openwin/lib
+ /opt/gnome/lib
+ )
+
+ find_library( GTK_glib_LIBRARY
+ NAMES glib glib12
+ PATHS /usr/openwin/lib
+ /opt/gnome/lib
+ )
+
+ find_library( GTK_Xi_LIBRARY
+ NAMES Xi
+ PATHS /usr/openwin/lib
+ /opt/gnome/lib
+ )
+
+ find_library( GTK_gthread_LIBRARY
+ NAMES gthread gthread12
+ PATHS /usr/openwin/lib
+ /opt/gnome/lib
+ )
+
+ if(GTK_gtk_INCLUDE_PATH
+ AND GTK_glibconfig_INCLUDE_PATH
+ AND GTK_glib_INCLUDE_PATH
+ AND GTK_gtk_LIBRARY
+ AND GTK_glib_LIBRARY)
+
+ # Assume that if gtk and glib were found, the other
+ # supporting libraries have also been found.
+
+ set( GTK_FOUND "YES" )
+ set( GTK_INCLUDE_DIR ${GTK_gtk_INCLUDE_PATH}
+ ${GTK_glibconfig_INCLUDE_PATH}
+ ${GTK_glib_INCLUDE_PATH} )
+ set( GTK_LIBRARIES ${GTK_gtk_LIBRARY}
+ ${GTK_gdk_LIBRARY}
+ ${GTK_glib_LIBRARY} )
+
+ if(GTK_gmodule_LIBRARY)
+ set(GTK_LIBRARIES ${GTK_LIBRARIES} ${GTK_gmodule_LIBRARY})
+ endif()
+ if(GTK_gthread_LIBRARY)
+ set(GTK_LIBRARIES ${GTK_LIBRARIES} ${GTK_gthread_LIBRARY})
+ endif()
+ if(GTK_Xi_LIBRARY)
+ set(GTK_LIBRARIES ${GTK_LIBRARIES} ${GTK_Xi_LIBRARY})
+ endif()
+
+ if(GTK_gtkgl_INCLUDE_PATH AND GTK_gtkgl_LIBRARY)
+ set( GTK_GL_FOUND "YES" )
+ set( GTK_INCLUDE_DIR ${GTK_INCLUDE_DIR}
+ ${GTK_gtkgl_INCLUDE_PATH} )
+ set( GTK_LIBRARIES ${GTK_gtkgl_LIBRARY} ${GTK_LIBRARIES} )
+ mark_as_advanced(
+ GTK_gtkgl_LIBRARY
+ GTK_gtkgl_INCLUDE_PATH
+ )
+ endif()
+
+ endif()
+
+ mark_as_advanced(
+ GTK_gdk_LIBRARY
+ GTK_glib_INCLUDE_PATH
+ GTK_glib_LIBRARY
+ GTK_glibconfig_INCLUDE_PATH
+ GTK_gmodule_LIBRARY
+ GTK_gthread_LIBRARY
+ GTK_Xi_LIBRARY
+ GTK_gtk_INCLUDE_PATH
+ GTK_gtk_LIBRARY
+ GTK_gtkgl_INCLUDE_PATH
+ GTK_gtkgl_LIBRARY
+ )
+
+endif()
diff --git a/Modules/FindGTK2.cmake b/Modules/FindGTK2.cmake
new file mode 100644
index 0000000..00bfc29
--- /dev/null
+++ b/Modules/FindGTK2.cmake
@@ -0,0 +1,969 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindGTK2
+--------
+
+Find the GTK2 widget libraries and several of its other optional components
+like ``gtkmm``, ``glade``, and ``glademm``.
+
+Specify one or more of the following components as you call this find
+module. See example below.
+
+* ``gtk``
+* ``gtkmm``
+* ``glade``
+* ``glademm``
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+This module defines the following :prop_tgt:`IMPORTED` targets (subject to
+component selection):
+
+``GTK2::atk``, ``GTK2::atkmm``, ``GTK2::cairo``, ``GTK2::cairomm``,
+``GTK2::gdk_pixbuf``, ``GTK2::gdk``, ``GTK2::gdkmm``, ``GTK2::gio``,
+``GTK2::giomm``, ``GTK2::glade``, ``GTK2::glademm``, ``GTK2::glib``,
+``GTK2::glibmm``, ``GTK2::gmodule``, ``GTK2::gobject``, ``GTK2::gthread``,
+``GTK2::gtk``, ``GTK2::gtkmm``, ``GTK2::harfbuzz``, ``GTK2::pango``,
+``GTK2::pangocairo``, ``GTK2::pangoft2``, ``GTK2::pangomm``,
+``GTK2::pangoxft``, ``GTK2::sigc``.
+
+.. versionadded:: 3.16.7
+ Added the ``GTK2::harfbuzz`` target.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+The following variables will be defined for your use
+
+``GTK2_FOUND``
+ Were all of your specified components found?
+``GTK2_INCLUDE_DIRS``
+ All include directories
+``GTK2_LIBRARIES``
+ All libraries
+``GTK2_TARGETS``
+ .. versionadded:: 3.5
+ All imported targets
+``GTK2_DEFINITIONS``
+ Additional compiler flags
+``GTK2_VERSION``
+ The version of GTK2 found (x.y.z)
+``GTK2_MAJOR_VERSION``
+ The major version of GTK2
+``GTK2_MINOR_VERSION``
+ The minor version of GTK2
+``GTK2_PATCH_VERSION``
+ The patch version of GTK2
+
+.. versionadded:: 3.5
+ When ``GTK2_USE_IMPORTED_TARGETS`` is set to ``TRUE``, ``GTK2_LIBRARIES``
+ will list imported targets instead of library paths.
+
+Input Variables
+^^^^^^^^^^^^^^^
+
+Optional variables you can define prior to calling this module:
+
+``GTK2_DEBUG``
+ Enables verbose debugging of the module
+``GTK2_ADDITIONAL_SUFFIXES``
+ Allows defining additional directories to search for include files
+
+Example Usage
+^^^^^^^^^^^^^
+
+Call :command:`find_package` once. Here are some examples to pick from:
+
+Require GTK 2.6 or later:
+
+.. code-block:: cmake
+
+ find_package(GTK2 2.6 REQUIRED gtk)
+
+Require GTK 2.10 or later and Glade:
+
+.. code-block:: cmake
+
+ find_package(GTK2 2.10 REQUIRED gtk glade)
+
+Search for GTK/GTKMM 2.8 or later:
+
+.. code-block:: cmake
+
+ find_package(GTK2 2.8 COMPONENTS gtk gtkmm)
+
+Use the results:
+
+.. code-block:: cmake
+
+ if(GTK2_FOUND)
+ include_directories(${GTK2_INCLUDE_DIRS})
+ add_executable(mygui mygui.cc)
+ target_link_libraries(mygui ${GTK2_LIBRARIES})
+ endif()
+#]=======================================================================]
+
+# Version 1.6 (CMake 3.0)
+# * Create targets for each library
+# * Do not link libfreetype
+# Version 1.5 (CMake 2.8.12)
+# * 14236: Detect gthread library
+# Detect pangocairo on windows
+# Detect pangocairo with gtk module instead of with gtkmm
+# * 14259: Use vc100 libraries with VS 11
+# * 14260: Export a GTK2_DEFINITIONS variable to set /vd2 when appropriate
+# (i.e. MSVC)
+# * Use the optimized/debug syntax for _LIBRARY and _LIBRARIES variables when
+# appropriate. A new set of _RELEASE variables was also added.
+# * Remove GTK2_SKIP_MARK_AS_ADVANCED option, as now the variables are
+# marked as advanced by SelectLibraryConfigurations
+# * Detect gmodule, pangoft2 and pangoxft libraries
+# Version 1.4 (10/4/2012) (CMake 2.8.10)
+# * 12596: Missing paths for FindGTK2 on NetBSD
+# * 12049: Fixed detection of GTK include files in the lib folder on
+# multiarch systems.
+# Version 1.3 (11/9/2010) (CMake 2.8.4)
+# * 11429: Add support for detecting GTK2 built with Visual Studio 10.
+# Thanks to Vincent Levesque for the patch.
+# Version 1.2 (8/30/2010) (CMake 2.8.3)
+# * Merge patch for detecting gdk-pixbuf library (split off
+# from core GTK in 2.21). Thanks to Vincent Untz for the patch
+# and Ricardo Cruz for the heads up.
+# Version 1.1 (8/19/2010) (CMake 2.8.3)
+# * Add support for detecting GTK2 under macports (thanks to Gary Kramlich)
+# Version 1.0 (8/12/2010) (CMake 2.8.3)
+# * Add support for detecting new pangommconfig.h header file
+# (Thanks to Sune Vuorela & the Debian Project for the patch)
+# * Add support for detecting fontconfig.h header
+# * Call find_package(Freetype) since it's required
+# * Add support for allowing users to add additional library directories
+# via the GTK2_ADDITIONAL_SUFFIXES variable (kind of a future-kludge in
+# case the GTK developers change versions on any of the directories in the
+# future).
+# Version 0.8 (1/4/2010)
+# * Get module working under MacOSX fink by adding /sw/include, /sw/lib
+# to PATHS and the gobject library
+# Version 0.7 (3/22/09)
+# * Checked into CMake CVS
+# * Added versioning support
+# * Module now defaults to searching for GTK if COMPONENTS not specified.
+# * Added HKCU prior to HKLM registry key and GTKMM specific environment
+# variable as per mailing list discussion.
+# * Added lib64 to include search path and a few other search paths where GTK
+# may be installed on Unix systems.
+# * Switched to lowercase CMake commands
+# * Prefaced internal variables with _GTK2 to prevent collision
+# * Changed internal macros to functions
+# * Enhanced documentation
+# Version 0.6 (1/8/08)
+# Added GTK2_SKIP_MARK_AS_ADVANCED option
+# Version 0.5 (12/19/08)
+# Second release to cmake mailing list
+
+#=============================================================
+# _GTK2_GET_VERSION
+# Internal function to parse the version number in gtkversion.h
+# _OUT_major = Major version number
+# _OUT_minor = Minor version number
+# _OUT_micro = Micro version number
+# _gtkversion_hdr = Header file to parse
+#=============================================================
+
+include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+
+function(_GTK2_GET_VERSION _OUT_major _OUT_minor _OUT_micro _gtkversion_hdr)
+ file(STRINGS ${_gtkversion_hdr} _contents REGEX "#define GTK_M[A-Z]+_VERSION[ \t]+")
+ if(_contents)
+ string(REGEX REPLACE ".*#define GTK_MAJOR_VERSION[ \t]+\\(([0-9]+)\\).*" "\\1" ${_OUT_major} "${_contents}")
+ string(REGEX REPLACE ".*#define GTK_MINOR_VERSION[ \t]+\\(([0-9]+)\\).*" "\\1" ${_OUT_minor} "${_contents}")
+ string(REGEX REPLACE ".*#define GTK_MICRO_VERSION[ \t]+\\(([0-9]+)\\).*" "\\1" ${_OUT_micro} "${_contents}")
+
+ if(NOT ${_OUT_major} MATCHES "[0-9]+")
+ message(FATAL_ERROR "Version parsing failed for GTK2_MAJOR_VERSION!")
+ endif()
+ if(NOT ${_OUT_minor} MATCHES "[0-9]+")
+ message(FATAL_ERROR "Version parsing failed for GTK2_MINOR_VERSION!")
+ endif()
+ if(NOT ${_OUT_micro} MATCHES "[0-9]+")
+ message(FATAL_ERROR "Version parsing failed for GTK2_MICRO_VERSION!")
+ endif()
+
+ set(${_OUT_major} ${${_OUT_major}} PARENT_SCOPE)
+ set(${_OUT_minor} ${${_OUT_minor}} PARENT_SCOPE)
+ set(${_OUT_micro} ${${_OUT_micro}} PARENT_SCOPE)
+ else()
+ message(FATAL_ERROR "Include file ${_gtkversion_hdr} does not exist")
+ endif()
+endfunction()
+
+
+#=============================================================
+# _GTK2_SIGCXX_GET_VERSION
+# Internal function to parse the version number in
+# sigc++config.h
+# _OUT_major = Major version number
+# _OUT_minor = Minor version number
+# _OUT_micro = Micro version number
+# _sigcxxversion_hdr = Header file to parse
+#=============================================================
+
+function(_GTK2_SIGCXX_GET_VERSION _OUT_major _OUT_minor _OUT_micro _sigcxxversion_hdr)
+ file(STRINGS ${_sigcxxversion_hdr} _contents REGEX "#define SIGCXX_M[A-Z]+_VERSION[ \t]+")
+ if(_contents)
+ string(REGEX REPLACE ".*#define SIGCXX_MAJOR_VERSION[ \t]+([0-9]+).*" "\\1" ${_OUT_major} "${_contents}")
+ string(REGEX REPLACE ".*#define SIGCXX_MINOR_VERSION[ \t]+([0-9]+).*" "\\1" ${_OUT_minor} "${_contents}")
+ string(REGEX REPLACE ".*#define SIGCXX_MICRO_VERSION[ \t]+([0-9]+).*" "\\1" ${_OUT_micro} "${_contents}")
+
+ if(NOT ${_OUT_major} MATCHES "[0-9]+")
+ message(FATAL_ERROR "Version parsing failed for SIGCXX_MAJOR_VERSION!")
+ endif()
+ if(NOT ${_OUT_minor} MATCHES "[0-9]+")
+ message(FATAL_ERROR "Version parsing failed for SIGCXX_MINOR_VERSION!")
+ endif()
+ if(NOT ${_OUT_micro} MATCHES "[0-9]+")
+ message(FATAL_ERROR "Version parsing failed for SIGCXX_MICRO_VERSION!")
+ endif()
+
+ set(${_OUT_major} ${${_OUT_major}} PARENT_SCOPE)
+ set(${_OUT_minor} ${${_OUT_minor}} PARENT_SCOPE)
+ set(${_OUT_micro} ${${_OUT_micro}} PARENT_SCOPE)
+ else()
+ # The header does not have the version macros; assume it is ``0.0.0``.
+ set(${_OUT_major} 0)
+ set(${_OUT_minor} 0)
+ set(${_OUT_micro} 0)
+ endif()
+endfunction()
+
+
+#=============================================================
+# _GTK2_FIND_INCLUDE_DIR
+# Internal function to find the GTK include directories
+# _var = variable to set (_INCLUDE_DIR is appended)
+# _hdr = header file to look for
+#=============================================================
+function(_GTK2_FIND_INCLUDE_DIR _var _hdr)
+
+ if(GTK2_DEBUG)
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "_GTK2_FIND_INCLUDE_DIR( ${_var} ${_hdr} )")
+ endif()
+
+ set(_gtk_packages
+ # If these ever change, things will break.
+ ${GTK2_ADDITIONAL_SUFFIXES}
+ glibmm-2.4
+ glib-2.0
+ atk-1.0
+ atkmm-1.6
+ cairo
+ cairomm-1.0
+ gdk-pixbuf-2.0
+ gdkmm-2.4
+ giomm-2.4
+ gtk-2.0
+ gtkmm-2.4
+ libglade-2.0
+ libglademm-2.4
+ harfbuzz
+ pango-1.0
+ pangomm-1.4
+ sigc++-2.0
+ )
+
+ #
+ # NOTE: The following suffixes cause searching for header files in both of
+ # these directories:
+ # /usr/include/<pkg>
+ # /usr/lib/<pkg>/include
+ #
+
+ set(_suffixes)
+ foreach(_d ${_gtk_packages})
+ list(APPEND _suffixes ${_d})
+ list(APPEND _suffixes ${_d}/include) # for /usr/lib/gtk-2.0/include
+ endforeach()
+
+ if(GTK2_DEBUG)
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "include suffixes = ${_suffixes}")
+ endif()
+
+ if(CMAKE_LIBRARY_ARCHITECTURE)
+ set(_gtk2_arch_dir /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE})
+ if(GTK2_DEBUG)
+ message(STATUS "Adding ${_gtk2_arch_dir} to search path for multiarch support")
+ endif()
+ endif()
+ find_path(GTK2_${_var}_INCLUDE_DIR ${_hdr}
+ PATHS
+ ${_gtk2_arch_dir}
+ /usr/local/libx32
+ /usr/local/lib64
+ /usr/local/lib
+ /usr/libx32
+ /usr/lib64
+ /usr/lib
+ /opt/gnome/include
+ /opt/gnome/lib
+ /opt/openwin/include
+ /usr/openwin/lib
+ /sw/lib
+ /opt/local/lib
+ /usr/pkg/lib
+ /usr/pkg/include/glib
+ $ENV{GTKMM_BASEPATH}/include
+ $ENV{GTKMM_BASEPATH}/lib
+ [HKEY_CURRENT_USER\\SOFTWARE\\gtkmm\\2.4;Path]/include
+ [HKEY_CURRENT_USER\\SOFTWARE\\gtkmm\\2.4;Path]/lib
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\gtkmm\\2.4;Path]/include
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\gtkmm\\2.4;Path]/lib
+ PATH_SUFFIXES
+ ${_suffixes}
+ )
+ mark_as_advanced(GTK2_${_var}_INCLUDE_DIR)
+
+ if(GTK2_${_var}_INCLUDE_DIR)
+ set(GTK2_INCLUDE_DIRS ${GTK2_INCLUDE_DIRS} ${GTK2_${_var}_INCLUDE_DIR} PARENT_SCOPE)
+ endif()
+
+endfunction()
+
+#=============================================================
+# _GTK2_FIND_LIBRARY
+# Internal function to find libraries packaged with GTK2
+# _var = library variable to create (_LIBRARY is appended)
+#=============================================================
+function(_GTK2_FIND_LIBRARY _var _lib _expand_vc _append_version)
+
+ if(GTK2_DEBUG)
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "_GTK2_FIND_LIBRARY( ${_var} ${_lib} ${_expand_vc} ${_append_version} )")
+ endif()
+
+ # Not GTK versions per se but the versions encoded into Windows
+ # import libraries (GtkMM 2.14.1 has a gtkmm-vc80-2_4.lib for example)
+ # Also the MSVC libraries use _ for . (this is handled below)
+ set(_versions 2.20 2.18 2.16 2.14 2.12
+ 2.10 2.8 2.6 2.4 2.2 2.0
+ 1.20 1.18 1.16 1.14 1.12
+ 1.10 1.8 1.6 1.4 1.2 1.0)
+
+ set(_library)
+ set(_library_d)
+
+ set(_library ${_lib})
+
+ if(_expand_vc AND MSVC)
+ # Add vc80/vc90/vc100 midfixes
+ if(MSVC_TOOLSET_VERSION LESS 110)
+ set(_library ${_library}-vc${MSVC_TOOLSET_VERSION})
+ else()
+ # Up to gtkmm-win 2.22.0-2 there are no vc110 libraries but vc100 can be used
+ set(_library ${_library}-vc100)
+ endif()
+ set(_library_d ${_library}-d)
+ endif()
+
+ if(GTK2_DEBUG)
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "After midfix addition = ${_library} and ${_library_d}")
+ endif()
+
+ set(_lib_list)
+ set(_libd_list)
+ if(_append_version)
+ foreach(_ver ${_versions})
+ list(APPEND _lib_list "${_library}-${_ver}")
+ list(APPEND _libd_list "${_library_d}-${_ver}")
+ endforeach()
+ else()
+ set(_lib_list ${_library})
+ set(_libd_list ${_library_d})
+ endif()
+
+ if(GTK2_DEBUG)
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "library list = ${_lib_list} and library debug list = ${_libd_list}")
+ endif()
+
+ # For some silly reason the MSVC libraries use _ instead of .
+ # in the version fields
+ if(_expand_vc AND MSVC)
+ set(_no_dots_lib_list)
+ set(_no_dots_libd_list)
+ foreach(_l ${_lib_list})
+ string(REPLACE "." "_" _no_dots_library ${_l})
+ list(APPEND _no_dots_lib_list ${_no_dots_library})
+ endforeach()
+ # And for debug
+ set(_no_dots_libsd_list)
+ foreach(_l ${_libd_list})
+ string(REPLACE "." "_" _no_dots_libraryd ${_l})
+ list(APPEND _no_dots_libd_list ${_no_dots_libraryd})
+ endforeach()
+
+ # Copy list back to original names
+ set(_lib_list ${_no_dots_lib_list})
+ set(_libd_list ${_no_dots_libd_list})
+ endif()
+
+ if(GTK2_DEBUG)
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "While searching for GTK2_${_var}_LIBRARY, our proposed library list is ${_lib_list}")
+ endif()
+
+ find_library(GTK2_${_var}_LIBRARY_RELEASE
+ NAMES ${_lib_list}
+ PATHS
+ /opt/gnome/lib
+ /usr/openwin/lib
+ $ENV{GTKMM_BASEPATH}/lib
+ [HKEY_CURRENT_USER\\SOFTWARE\\gtkmm\\2.4;Path]/lib
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\gtkmm\\2.4;Path]/lib
+ )
+
+ if(_expand_vc AND MSVC)
+ if(GTK2_DEBUG)
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "While searching for GTK2_${_var}_LIBRARY_DEBUG our proposed library list is ${_libd_list}")
+ endif()
+
+ find_library(GTK2_${_var}_LIBRARY_DEBUG
+ NAMES ${_libd_list}
+ PATHS
+ $ENV{GTKMM_BASEPATH}/lib
+ [HKEY_CURRENT_USER\\SOFTWARE\\gtkmm\\2.4;Path]/lib
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\gtkmm\\2.4;Path]/lib
+ )
+ endif()
+
+ select_library_configurations(GTK2_${_var})
+
+ set(GTK2_${_var}_LIBRARY ${GTK2_${_var}_LIBRARY} PARENT_SCOPE)
+ set(GTK2_${_var}_FOUND ${GTK2_${_var}_FOUND} PARENT_SCOPE)
+
+ if(GTK2_${_var}_FOUND)
+ set(GTK2_LIBRARIES ${GTK2_LIBRARIES} ${GTK2_${_var}_LIBRARY})
+ set(GTK2_LIBRARIES ${GTK2_LIBRARIES} PARENT_SCOPE)
+ endif()
+
+ if(GTK2_DEBUG)
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "GTK2_${_var}_LIBRARY_RELEASE = \"${GTK2_${_var}_LIBRARY_RELEASE}\"")
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "GTK2_${_var}_LIBRARY_DEBUG = \"${GTK2_${_var}_LIBRARY_DEBUG}\"")
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "GTK2_${_var}_LIBRARY = \"${GTK2_${_var}_LIBRARY}\"")
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "GTK2_${_var}_FOUND = \"${GTK2_${_var}_FOUND}\"")
+ endif()
+
+endfunction()
+
+
+function(_GTK2_ADD_TARGET_DEPENDS_INTERNAL _var _property)
+ if(GTK2_DEBUG)
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "_GTK2_ADD_TARGET_DEPENDS_INTERNAL( ${_var} ${_property} )")
+ endif()
+
+ string(TOLOWER "${_var}" _basename)
+
+ if (TARGET GTK2::${_basename})
+ foreach(_depend ${ARGN})
+ set(_valid_depends)
+ if (TARGET GTK2::${_depend})
+ list(APPEND _valid_depends GTK2::${_depend})
+ endif()
+ if (_valid_depends)
+ set_property(TARGET GTK2::${_basename} APPEND PROPERTY ${_property} "${_valid_depends}")
+ endif()
+ set(_valid_depends)
+ endforeach()
+ endif()
+endfunction()
+
+function(_GTK2_ADD_TARGET_DEPENDS _var)
+ if(GTK2_DEBUG)
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "_GTK2_ADD_TARGET_DEPENDS( ${_var} )")
+ endif()
+
+ string(TOLOWER "${_var}" _basename)
+
+ if(TARGET GTK2::${_basename})
+ get_target_property(_configs GTK2::${_basename} IMPORTED_CONFIGURATIONS)
+ _GTK2_ADD_TARGET_DEPENDS_INTERNAL(${_var} INTERFACE_LINK_LIBRARIES ${ARGN})
+ foreach(_config ${_configs})
+ _GTK2_ADD_TARGET_DEPENDS_INTERNAL(${_var} IMPORTED_LINK_INTERFACE_LIBRARIES_${_config} ${ARGN})
+ endforeach()
+ endif()
+endfunction()
+
+function(_GTK2_ADD_TARGET_INCLUDE_DIRS _var)
+ if(GTK2_DEBUG)
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "_GTK2_ADD_TARGET_INCLUDE_DIRS( ${_var} )")
+ endif()
+
+ string(TOLOWER "${_var}" _basename)
+
+ if(TARGET GTK2::${_basename})
+ foreach(_include ${ARGN})
+ set_property(TARGET GTK2::${_basename} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${_include}")
+ endforeach()
+ endif()
+endfunction()
+
+#=============================================================
+# _GTK2_ADD_TARGET
+# Internal function to create targets for GTK2
+# _var = target to create
+#=============================================================
+function(_GTK2_ADD_TARGET _var)
+ if(GTK2_DEBUG)
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "_GTK2_ADD_TARGET( ${_var} )")
+ endif()
+
+ string(TOLOWER "${_var}" _basename)
+
+ cmake_parse_arguments(_${_var} "" "" "GTK2_DEPENDS;GTK2_OPTIONAL_DEPENDS;OPTIONAL_INCLUDES" ${ARGN})
+
+ if(GTK2_${_var}_FOUND)
+ if(NOT TARGET GTK2::${_basename})
+ # Do not create the target if dependencies are missing
+ foreach(_dep ${_${_var}_GTK2_DEPENDS})
+ if(NOT TARGET GTK2::${_dep})
+ return()
+ endif()
+ endforeach()
+
+ add_library(GTK2::${_basename} UNKNOWN IMPORTED)
+
+ if(GTK2_${_var}_LIBRARY_RELEASE)
+ set_property(TARGET GTK2::${_basename} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+ set_property(TARGET GTK2::${_basename} PROPERTY IMPORTED_LOCATION_RELEASE "${GTK2_${_var}_LIBRARY_RELEASE}" )
+ endif()
+
+ if(GTK2_${_var}_LIBRARY_DEBUG)
+ set_property(TARGET GTK2::${_basename} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+ set_property(TARGET GTK2::${_basename} PROPERTY IMPORTED_LOCATION_DEBUG "${GTK2_${_var}_LIBRARY_DEBUG}" )
+ endif()
+
+ if(GTK2_${_var}_INCLUDE_DIR)
+ set_property(TARGET GTK2::${_basename} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${GTK2_${_var}_INCLUDE_DIR}")
+ endif()
+
+ if(GTK2_${_var}CONFIG_INCLUDE_DIR AND NOT "x${GTK2_${_var}CONFIG_INCLUDE_DIR}" STREQUAL "x${GTK2_${_var}_INCLUDE_DIR}")
+ set_property(TARGET GTK2::${_basename} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${GTK2_${_var}CONFIG_INCLUDE_DIR}")
+ endif()
+
+ if(GTK2_DEFINITIONS)
+ set_property(TARGET GTK2::${_basename} PROPERTY INTERFACE_COMPILE_DEFINITIONS "${GTK2_DEFINITIONS}")
+ endif()
+
+ if(_${_var}_GTK2_DEPENDS)
+ _GTK2_ADD_TARGET_DEPENDS(${_var} ${_${_var}_GTK2_DEPENDS} ${_${_var}_GTK2_OPTIONAL_DEPENDS})
+ endif()
+
+ if(_${_var}_OPTIONAL_INCLUDES)
+ foreach(_D ${_${_var}_OPTIONAL_INCLUDES})
+ if(_D)
+ _GTK2_ADD_TARGET_INCLUDE_DIRS(${_var} ${_D})
+ endif()
+ endforeach()
+ endif()
+ endif()
+
+ set(GTK2_TARGETS ${GTK2_TARGETS} GTK2::${_basename})
+ set(GTK2_TARGETS ${GTK2_TARGETS} PARENT_SCOPE)
+
+ if(GTK2_USE_IMPORTED_TARGETS)
+ set(GTK2_${_var}_LIBRARY GTK2::${_basename} PARENT_SCOPE)
+ endif()
+
+ endif()
+endfunction()
+
+
+
+#=============================================================
+
+#
+# main()
+#
+
+set(GTK2_FOUND)
+set(GTK2_INCLUDE_DIRS)
+set(GTK2_LIBRARIES)
+set(GTK2_TARGETS)
+set(GTK2_DEFINITIONS)
+
+if(NOT GTK2_FIND_COMPONENTS)
+ # Assume they only want GTK
+ set(GTK2_FIND_COMPONENTS gtk)
+endif()
+
+#
+# If specified, enforce version number
+#
+if(GTK2_FIND_VERSION)
+ set(GTK2_FAILED_VERSION_CHECK true)
+ if(GTK2_DEBUG)
+ message(STATUS "[FindGTK2.cmake:${CMAKE_CURRENT_LIST_LINE}] "
+ "Searching for version ${GTK2_FIND_VERSION}")
+ endif()
+ _GTK2_FIND_INCLUDE_DIR(GTK gtk/gtk.h)
+ if(GTK2_GTK_INCLUDE_DIR)
+ _GTK2_GET_VERSION(GTK2_MAJOR_VERSION
+ GTK2_MINOR_VERSION
+ GTK2_PATCH_VERSION
+ ${GTK2_GTK_INCLUDE_DIR}/gtk/gtkversion.h)
+ set(GTK2_VERSION
+ ${GTK2_MAJOR_VERSION}.${GTK2_MINOR_VERSION}.${GTK2_PATCH_VERSION})
+ if(GTK2_FIND_VERSION_EXACT)
+ if(GTK2_VERSION VERSION_EQUAL GTK2_FIND_VERSION)
+ set(GTK2_FAILED_VERSION_CHECK false)
+ endif()
+ else()
+ if(GTK2_VERSION VERSION_EQUAL GTK2_FIND_VERSION OR
+ GTK2_VERSION VERSION_GREATER GTK2_FIND_VERSION)
+ set(GTK2_FAILED_VERSION_CHECK false)
+ endif()
+ endif()
+ else()
+ # If we can't find the GTK include dir, we can't do version checking
+ if(GTK2_FIND_REQUIRED AND NOT GTK2_FIND_QUIETLY)
+ message(FATAL_ERROR "Could not find GTK2 include directory")
+ endif()
+ return()
+ endif()
+
+ if(GTK2_FAILED_VERSION_CHECK)
+ if(GTK2_FIND_REQUIRED AND NOT GTK2_FIND_QUIETLY)
+ if(GTK2_FIND_VERSION_EXACT)
+ message(FATAL_ERROR "GTK2 version check failed. Version ${GTK2_VERSION} was found, version ${GTK2_FIND_VERSION} is needed exactly.")
+ else()
+ message(FATAL_ERROR "GTK2 version check failed. Version ${GTK2_VERSION} was found, at least version ${GTK2_FIND_VERSION} is required")
+ endif()
+ endif()
+
+ # If the version check fails, exit out of the module here
+ return()
+ endif()
+endif()
+
+#
+# On MSVC, according to https://wiki.gnome.org/gtkmm/MSWindows, the /vd2 flag needs to be
+# passed to the compiler in order to use gtkmm
+#
+if(MSVC)
+ foreach(_GTK2_component ${GTK2_FIND_COMPONENTS})
+ if(_GTK2_component STREQUAL "gtkmm")
+ set(GTK2_DEFINITIONS "/vd2")
+ elseif(_GTK2_component STREQUAL "glademm")
+ set(GTK2_DEFINITIONS "/vd2")
+ endif()
+ endforeach()
+endif()
+
+#
+# Find all components
+#
+
+find_package(Freetype QUIET)
+if(FREETYPE_INCLUDE_DIR_ft2build AND FREETYPE_INCLUDE_DIR_freetype2)
+ list(APPEND GTK2_INCLUDE_DIRS ${FREETYPE_INCLUDE_DIR_ft2build} ${FREETYPE_INCLUDE_DIR_freetype2})
+endif()
+
+foreach(_GTK2_component ${GTK2_FIND_COMPONENTS})
+ if(_GTK2_component STREQUAL "gtk")
+ # Left for compatibility with previous versions.
+ _GTK2_FIND_INCLUDE_DIR(FONTCONFIG fontconfig/fontconfig.h)
+ _GTK2_FIND_INCLUDE_DIR(X11 X11/Xlib.h)
+
+ _GTK2_FIND_INCLUDE_DIR(GLIB glib.h)
+ _GTK2_FIND_INCLUDE_DIR(GLIBCONFIG glibconfig.h)
+ _GTK2_FIND_LIBRARY (GLIB glib false true)
+ _GTK2_ADD_TARGET (GLIB)
+
+ _GTK2_FIND_INCLUDE_DIR(GOBJECT glib-object.h)
+ _GTK2_FIND_LIBRARY (GOBJECT gobject false true)
+ _GTK2_ADD_TARGET (GOBJECT GTK2_DEPENDS glib)
+
+ _GTK2_FIND_INCLUDE_DIR(ATK atk/atk.h)
+ _GTK2_FIND_LIBRARY (ATK atk false true)
+ _GTK2_ADD_TARGET (ATK GTK2_DEPENDS gobject glib)
+
+ _GTK2_FIND_LIBRARY (GIO gio false true)
+ _GTK2_ADD_TARGET (GIO GTK2_DEPENDS gobject glib)
+
+ _GTK2_FIND_LIBRARY (GTHREAD gthread false true)
+ _GTK2_ADD_TARGET (GTHREAD GTK2_DEPENDS glib)
+
+ _GTK2_FIND_LIBRARY (GMODULE gmodule false true)
+ _GTK2_ADD_TARGET (GMODULE GTK2_DEPENDS glib)
+
+ _GTK2_FIND_INCLUDE_DIR(GDK_PIXBUF gdk-pixbuf/gdk-pixbuf.h)
+ _GTK2_FIND_LIBRARY (GDK_PIXBUF gdk_pixbuf false true)
+ _GTK2_ADD_TARGET (GDK_PIXBUF GTK2_DEPENDS gobject glib)
+
+ _GTK2_FIND_INCLUDE_DIR(CAIRO cairo.h)
+ _GTK2_FIND_LIBRARY (CAIRO cairo false false)
+ _GTK2_ADD_TARGET (CAIRO)
+
+ _GTK2_FIND_INCLUDE_DIR(HARFBUZZ hb.h)
+ _GTK2_FIND_LIBRARY (HARFBUZZ harfbuzz false false)
+ _GTK2_ADD_TARGET (HARFBUZZ)
+
+ _GTK2_FIND_INCLUDE_DIR(PANGO pango/pango.h)
+ _GTK2_FIND_LIBRARY (PANGO pango false true)
+ _GTK2_ADD_TARGET (PANGO GTK2_DEPENDS gobject glib
+ GTK2_OPTIONAL_DEPENDS harfbuzz)
+
+ _GTK2_FIND_LIBRARY (PANGOCAIRO pangocairo false true)
+ _GTK2_ADD_TARGET (PANGOCAIRO GTK2_DEPENDS pango cairo gobject glib)
+
+ _GTK2_FIND_LIBRARY (PANGOFT2 pangoft2 false true)
+ _GTK2_ADD_TARGET (PANGOFT2 GTK2_DEPENDS pango gobject glib
+ OPTIONAL_INCLUDES ${FREETYPE_INCLUDE_DIR_ft2build} ${FREETYPE_INCLUDE_DIR_freetype2}
+ ${GTK2_FONTCONFIG_INCLUDE_DIR}
+ ${GTK2_X11_INCLUDE_DIR})
+
+ _GTK2_FIND_LIBRARY (PANGOXFT pangoxft false true)
+ _GTK2_ADD_TARGET (PANGOXFT GTK2_DEPENDS pangoft2 pango gobject glib
+ OPTIONAL_INCLUDES ${FREETYPE_INCLUDE_DIR_ft2build} ${FREETYPE_INCLUDE_DIR_freetype2}
+ ${GTK2_FONTCONFIG_INCLUDE_DIR}
+ ${GTK2_X11_INCLUDE_DIR})
+
+ _GTK2_FIND_INCLUDE_DIR(GDK gdk/gdk.h)
+ _GTK2_FIND_INCLUDE_DIR(GDKCONFIG gdkconfig.h)
+ if(UNIX)
+ if(APPLE)
+ _GTK2_FIND_LIBRARY (GDK gdk-quartz false true)
+ endif()
+ _GTK2_FIND_LIBRARY (GDK gdk-x11 false true)
+ else()
+ _GTK2_FIND_LIBRARY (GDK gdk-win32 false true)
+ endif()
+ _GTK2_ADD_TARGET (GDK GTK2_DEPENDS pango gdk_pixbuf gobject glib
+ GTK2_OPTIONAL_DEPENDS pangocairo cairo)
+
+ _GTK2_FIND_INCLUDE_DIR(GTK gtk/gtk.h)
+ if(UNIX)
+ if(APPLE)
+ _GTK2_FIND_LIBRARY (GTK gtk-quartz false true)
+ endif()
+ _GTK2_FIND_LIBRARY (GTK gtk-x11 false true)
+ else()
+ _GTK2_FIND_LIBRARY (GTK gtk-win32 false true)
+ endif()
+ _GTK2_ADD_TARGET (GTK GTK2_DEPENDS gdk atk pangoft2 pango gdk_pixbuf gthread gobject glib
+ GTK2_OPTIONAL_DEPENDS gio pangocairo cairo)
+
+ elseif(_GTK2_component STREQUAL "gtkmm")
+
+ _GTK2_FIND_INCLUDE_DIR(SIGC++ sigc++/sigc++.h)
+ _GTK2_FIND_INCLUDE_DIR(SIGC++CONFIG sigc++config.h)
+ _GTK2_FIND_LIBRARY (SIGC++ sigc true true)
+ _GTK2_ADD_TARGET (SIGC++)
+ # Since sigc++ 2.5.1 c++11 support is required
+ if(GTK2_SIGC++CONFIG_INCLUDE_DIR)
+ _GTK2_SIGCXX_GET_VERSION(GTK2_SIGC++_VERSION_MAJOR
+ GTK2_SIGC++_VERSION_MINOR
+ GTK2_SIGC++_VERSION_MICRO
+ ${GTK2_SIGC++CONFIG_INCLUDE_DIR}/sigc++config.h)
+ if(NOT ${GTK2_SIGC++_VERSION_MAJOR}.${GTK2_SIGC++_VERSION_MINOR}.${GTK2_SIGC++_VERSION_MICRO} VERSION_LESS 2.5.1)
+ # These are the features needed by clients in order to include the
+ # project headers:
+ set_property(TARGET GTK2::sigc++
+ PROPERTY INTERFACE_COMPILE_FEATURES cxx_alias_templates
+ cxx_auto_type
+ cxx_decltype
+ cxx_deleted_functions
+ cxx_noexcept
+ cxx_nullptr
+ cxx_right_angle_brackets
+ cxx_rvalue_references
+ cxx_variadic_templates)
+ endif()
+ endif()
+
+ _GTK2_FIND_INCLUDE_DIR(GLIBMM glibmm.h)
+ _GTK2_FIND_INCLUDE_DIR(GLIBMMCONFIG glibmmconfig.h)
+ _GTK2_FIND_LIBRARY (GLIBMM glibmm true true)
+ _GTK2_ADD_TARGET (GLIBMM GTK2_DEPENDS gobject sigc++ glib)
+
+ _GTK2_FIND_INCLUDE_DIR(GIOMM giomm.h)
+ _GTK2_FIND_INCLUDE_DIR(GIOMMCONFIG giommconfig.h)
+ _GTK2_FIND_LIBRARY (GIOMM giomm true true)
+ _GTK2_ADD_TARGET (GIOMM GTK2_DEPENDS gio glibmm gobject sigc++ glib)
+
+ _GTK2_FIND_INCLUDE_DIR(ATKMM atkmm.h)
+ _GTK2_FIND_INCLUDE_DIR(ATKMMCONFIG atkmmconfig.h)
+ _GTK2_FIND_LIBRARY (ATKMM atkmm true true)
+ _GTK2_ADD_TARGET (ATKMM GTK2_DEPENDS atk glibmm gobject sigc++ glib)
+
+ _GTK2_FIND_INCLUDE_DIR(CAIROMM cairomm/cairomm.h)
+ _GTK2_FIND_INCLUDE_DIR(CAIROMMCONFIG cairommconfig.h)
+ _GTK2_FIND_LIBRARY (CAIROMM cairomm true true)
+ _GTK2_ADD_TARGET (CAIROMM GTK2_DEPENDS cairo sigc++
+ OPTIONAL_INCLUDES ${FREETYPE_INCLUDE_DIR_ft2build} ${FREETYPE_INCLUDE_DIR_freetype2}
+ ${GTK2_FONTCONFIG_INCLUDE_DIR}
+ ${GTK2_X11_INCLUDE_DIR})
+
+ _GTK2_FIND_INCLUDE_DIR(PANGOMM pangomm.h)
+ _GTK2_FIND_INCLUDE_DIR(PANGOMMCONFIG pangommconfig.h)
+ _GTK2_FIND_LIBRARY (PANGOMM pangomm true true)
+ _GTK2_ADD_TARGET (PANGOMM GTK2_DEPENDS glibmm sigc++ pango gobject glib
+ GTK2_OPTIONAL_DEPENDS cairomm pangocairo cairo
+ OPTIONAL_INCLUDES ${FREETYPE_INCLUDE_DIR_ft2build} ${FREETYPE_INCLUDE_DIR_freetype2}
+ ${GTK2_FONTCONFIG_INCLUDE_DIR}
+ ${GTK2_X11_INCLUDE_DIR})
+
+ _GTK2_FIND_INCLUDE_DIR(GDKMM gdkmm.h)
+ _GTK2_FIND_INCLUDE_DIR(GDKMMCONFIG gdkmmconfig.h)
+ _GTK2_FIND_LIBRARY (GDKMM gdkmm true true)
+ _GTK2_ADD_TARGET (GDKMM GTK2_DEPENDS pangomm gtk glibmm sigc++ gdk atk pangoft2 gdk_pixbuf pango gobject glib
+ GTK2_OPTIONAL_DEPENDS giomm cairomm gio pangocairo cairo
+ OPTIONAL_INCLUDES ${FREETYPE_INCLUDE_DIR_ft2build} ${FREETYPE_INCLUDE_DIR_freetype2}
+ ${GTK2_FONTCONFIG_INCLUDE_DIR}
+ ${GTK2_X11_INCLUDE_DIR})
+
+ _GTK2_FIND_INCLUDE_DIR(GTKMM gtkmm.h)
+ _GTK2_FIND_INCLUDE_DIR(GTKMMCONFIG gtkmmconfig.h)
+ _GTK2_FIND_LIBRARY (GTKMM gtkmm true true)
+ _GTK2_ADD_TARGET (GTKMM GTK2_DEPENDS atkmm gdkmm pangomm gtk glibmm sigc++ gdk atk pangoft2 gdk_pixbuf pango gthread gobject glib
+ GTK2_OPTIONAL_DEPENDS giomm cairomm gio pangocairo cairo
+ OPTIONAL_INCLUDES ${FREETYPE_INCLUDE_DIR_ft2build} ${FREETYPE_INCLUDE_DIR_freetype2}
+ ${GTK2_FONTCONFIG_INCLUDE_DIR}
+ ${GTK2_X11_INCLUDE_DIR})
+
+ elseif(_GTK2_component STREQUAL "glade")
+
+ _GTK2_FIND_INCLUDE_DIR(GLADE glade/glade.h)
+ _GTK2_FIND_LIBRARY (GLADE glade false true)
+ _GTK2_ADD_TARGET (GLADE GTK2_DEPENDS gtk gdk atk gio pangoft2 gdk_pixbuf pango gobject glib
+ GTK2_OPTIONAL_DEPENDS pangocairo cairo
+ OPTIONAL_INCLUDES ${FREETYPE_INCLUDE_DIR_ft2build} ${FREETYPE_INCLUDE_DIR_freetype2}
+ ${GTK2_FONTCONFIG_INCLUDE_DIR}
+ ${GTK2_X11_INCLUDE_DIR})
+
+ elseif(_GTK2_component STREQUAL "glademm")
+
+ _GTK2_FIND_INCLUDE_DIR(GLADEMM libglademm.h)
+ _GTK2_FIND_INCLUDE_DIR(GLADEMMCONFIG libglademmconfig.h)
+ _GTK2_FIND_LIBRARY (GLADEMM glademm true true)
+ _GTK2_ADD_TARGET (GLADEMM GTK2_DEPENDS gtkmm glade atkmm gdkmm giomm pangomm glibmm sigc++ gtk gdk atk pangoft2 gdk_pixbuf pango gthread gobject glib
+ GTK2_OPTIONAL_DEPENDS giomm cairomm gio pangocairo cairo
+ OPTIONAL_INCLUDES ${FREETYPE_INCLUDE_DIR_ft2build} ${FREETYPE_INCLUDE_DIR_freetype2}
+ ${GTK2_FONTCONFIG_INCLUDE_DIR}
+ ${GTK2_X11_INCLUDE_DIR})
+
+ else()
+ message(FATAL_ERROR "Unknown GTK2 component ${_component}")
+ endif()
+endforeach()
+
+#
+# Solve for the GTK2 version if we haven't already
+#
+if(NOT GTK2_FIND_VERSION AND GTK2_GTK_INCLUDE_DIR)
+ _GTK2_GET_VERSION(GTK2_MAJOR_VERSION
+ GTK2_MINOR_VERSION
+ GTK2_PATCH_VERSION
+ ${GTK2_GTK_INCLUDE_DIR}/gtk/gtkversion.h)
+ set(GTK2_VERSION ${GTK2_MAJOR_VERSION}.${GTK2_MINOR_VERSION}.${GTK2_PATCH_VERSION})
+endif()
+
+#
+# Try to enforce components
+#
+
+set(_GTK2_did_we_find_everything true) # This gets set to GTK2_FOUND
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+foreach(_GTK2_component ${GTK2_FIND_COMPONENTS})
+ string(TOUPPER ${_GTK2_component} _COMPONENT_UPPER)
+
+ set(GTK2_${_COMPONENT_UPPER}_FIND_QUIETLY ${GTK2_FIND_QUIETLY})
+
+ set(FPHSA_NAME_MISMATCHED 1)
+ if(_GTK2_component STREQUAL "gtk")
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTK2_${_COMPONENT_UPPER} "Some or all of the gtk libraries were not found."
+ GTK2_GTK_LIBRARY
+ GTK2_GTK_INCLUDE_DIR
+
+ GTK2_GDK_INCLUDE_DIR
+ GTK2_GDKCONFIG_INCLUDE_DIR
+ GTK2_GDK_LIBRARY
+
+ GTK2_GLIB_INCLUDE_DIR
+ GTK2_GLIBCONFIG_INCLUDE_DIR
+ GTK2_GLIB_LIBRARY
+ )
+ elseif(_GTK2_component STREQUAL "gtkmm")
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTK2_${_COMPONENT_UPPER} "Some or all of the gtkmm libraries were not found."
+ GTK2_GTKMM_LIBRARY
+ GTK2_GTKMM_INCLUDE_DIR
+ GTK2_GTKMMCONFIG_INCLUDE_DIR
+
+ GTK2_GDKMM_INCLUDE_DIR
+ GTK2_GDKMMCONFIG_INCLUDE_DIR
+ GTK2_GDKMM_LIBRARY
+
+ GTK2_GLIBMM_INCLUDE_DIR
+ GTK2_GLIBMMCONFIG_INCLUDE_DIR
+ GTK2_GLIBMM_LIBRARY
+
+ FREETYPE_INCLUDE_DIR_ft2build
+ FREETYPE_INCLUDE_DIR_freetype2
+ )
+ elseif(_GTK2_component STREQUAL "glade")
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTK2_${_COMPONENT_UPPER} "The glade library was not found."
+ GTK2_GLADE_LIBRARY
+ GTK2_GLADE_INCLUDE_DIR
+ )
+ elseif(_GTK2_component STREQUAL "glademm")
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTK2_${_COMPONENT_UPPER} "The glademm library was not found."
+ GTK2_GLADEMM_LIBRARY
+ GTK2_GLADEMM_INCLUDE_DIR
+ GTK2_GLADEMMCONFIG_INCLUDE_DIR
+ )
+ endif()
+ unset(FPHSA_NAME_MISMATCHED)
+
+ if(NOT GTK2_${_COMPONENT_UPPER}_FOUND)
+ set(_GTK2_did_we_find_everything false)
+ endif()
+endforeach()
+
+if(GTK2_USE_IMPORTED_TARGETS)
+ set(GTK2_LIBRARIES ${GTK2_TARGETS})
+endif()
+
+
+if(_GTK2_did_we_find_everything AND NOT GTK2_VERSION_CHECK_FAILED)
+ set(GTK2_FOUND true)
+else()
+ # Unset our variables.
+ set(GTK2_FOUND false)
+ set(GTK2_VERSION)
+ set(GTK2_VERSION_MAJOR)
+ set(GTK2_VERSION_MINOR)
+ set(GTK2_VERSION_PATCH)
+ set(GTK2_INCLUDE_DIRS)
+ set(GTK2_LIBRARIES)
+ set(GTK2_TARGETS)
+ set(GTK2_DEFINITIONS)
+endif()
+
+if(GTK2_INCLUDE_DIRS)
+ list(REMOVE_DUPLICATES GTK2_INCLUDE_DIRS)
+endif()
diff --git a/Modules/FindGTest.cmake b/Modules/FindGTest.cmake
new file mode 100644
index 0000000..8e22f79
--- /dev/null
+++ b/Modules/FindGTest.cmake
@@ -0,0 +1,294 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindGTest
+---------
+
+Locate the Google C++ Testing Framework.
+
+.. versionadded:: 3.20
+ Upstream ``GTestConfig.cmake`` is used if possible.
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.20
+ This module defines the following :prop_tgt:`IMPORTED` targets:
+
+``GTest::gtest``
+ The Google Test ``gtest`` library, if found; adds Thread::Thread
+ automatically
+``GTest::gtest_main``
+ The Google Test ``gtest_main`` library, if found
+
+.. deprecated:: 3.20
+ For backwards compatibility, this module defines additionally the
+ following deprecated :prop_tgt:`IMPORTED` targets (available since 3.5):
+
+``GTest::GTest``
+ The Google Test ``gtest`` library, if found; adds Thread::Thread
+ automatically
+``GTest::Main``
+ The Google Test ``gtest_main`` library, if found
+
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``GTest_FOUND``
+ Found the Google Testing framework
+``GTEST_INCLUDE_DIRS``
+ the directory containing the Google Test headers
+
+The library variables below are set as normal variables. These
+contain debug/optimized keywords when a debugging library is found.
+
+``GTEST_LIBRARIES``
+ The Google Test ``gtest`` library; note it also requires linking
+ with an appropriate thread library
+``GTEST_MAIN_LIBRARIES``
+ The Google Test ``gtest_main`` library
+``GTEST_BOTH_LIBRARIES``
+ Both ``gtest`` and ``gtest_main``
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``GTEST_ROOT``
+ The root directory of the Google Test installation (may also be
+ set as an environment variable)
+``GTEST_MSVC_SEARCH``
+ If compiling with MSVC, this variable can be set to ``MT`` or
+ ``MD`` (the default) to enable searching a GTest build tree
+
+
+Example usage
+^^^^^^^^^^^^^
+
+::
+
+ enable_testing()
+ find_package(GTest REQUIRED)
+
+ add_executable(foo foo.cc)
+ target_link_libraries(foo GTest::gtest GTest::gtest_main)
+
+ add_test(AllTestsInFoo foo)
+
+
+Deeper integration with CTest
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+See :module:`GoogleTest` for information on the :command:`gtest_add_tests`
+and :command:`gtest_discover_tests` commands.
+
+.. versionchanged:: 3.9
+ Previous CMake versions defined :command:`gtest_add_tests` macro in this
+ module.
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/GoogleTest.cmake)
+
+function(__gtest_append_debugs _endvar _library)
+ if(${_library} AND ${_library}_DEBUG)
+ set(_output optimized ${${_library}} debug ${${_library}_DEBUG})
+ else()
+ set(_output ${${_library}})
+ endif()
+ set(${_endvar} ${_output} PARENT_SCOPE)
+endfunction()
+
+function(__gtest_find_library _name)
+ find_library(${_name}
+ NAMES ${ARGN}
+ HINTS
+ ENV GTEST_ROOT
+ ${GTEST_ROOT}
+ PATH_SUFFIXES ${_gtest_libpath_suffixes}
+ )
+ mark_as_advanced(${_name})
+endfunction()
+
+macro(__gtest_determine_windows_library_type _var)
+ if(EXISTS "${${_var}}")
+ file(TO_NATIVE_PATH "${${_var}}" _lib_path)
+ get_filename_component(_name "${${_var}}" NAME_WE)
+ file(STRINGS "${${_var}}" _match REGEX "${_name}\\.dll" LIMIT_COUNT 1)
+ if(NOT _match STREQUAL "")
+ set(${_var}_TYPE SHARED PARENT_SCOPE)
+ else()
+ set(${_var}_TYPE UNKNOWN PARENT_SCOPE)
+ endif()
+ return()
+ endif()
+endmacro()
+
+function(__gtest_determine_library_type _var)
+ if(WIN32)
+ # For now, at least, only Windows really needs to know the library type
+ __gtest_determine_windows_library_type(${_var})
+ __gtest_determine_windows_library_type(${_var}_RELEASE)
+ __gtest_determine_windows_library_type(${_var}_DEBUG)
+ endif()
+ # If we get here, no determination was made from the above checks
+ set(${_var}_TYPE UNKNOWN PARENT_SCOPE)
+endfunction()
+
+function(__gtest_import_library _target _var _config)
+ if(_config)
+ set(_config_suffix "_${_config}")
+ else()
+ set(_config_suffix "")
+ endif()
+
+ set(_lib "${${_var}${_config_suffix}}")
+ if(EXISTS "${_lib}")
+ if(_config)
+ set_property(TARGET ${_target} APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS ${_config})
+ endif()
+ set_target_properties(${_target} PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES${_config_suffix} "CXX")
+ if(WIN32 AND ${_var}_TYPE STREQUAL SHARED)
+ set_target_properties(${_target} PROPERTIES
+ IMPORTED_IMPLIB${_config_suffix} "${_lib}")
+ else()
+ set_target_properties(${_target} PROPERTIES
+ IMPORTED_LOCATION${_config_suffix} "${_lib}")
+ endif()
+ endif()
+endfunction()
+
+function(__gtest_define_backwards_compatible_library_targets)
+ set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} PARENT_SCOPE)
+
+ # Add targets mapping the same library names as defined in
+ # older versions of CMake's FindGTest
+ if(NOT TARGET GTest::GTest)
+ add_library(GTest::GTest INTERFACE IMPORTED)
+ target_link_libraries(GTest::GTest INTERFACE GTest::gtest)
+ endif()
+ if(NOT TARGET GTest::Main)
+ add_library(GTest::Main INTERFACE IMPORTED)
+ target_link_libraries(GTest::Main INTERFACE GTest::gtest_main)
+ endif()
+endfunction()
+
+#
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+# first specifically look for the CMake version of GTest
+find_package(GTest QUIET NO_MODULE)
+
+# if we found the GTest cmake package then we are done, and
+# can print what we found and return.
+if(GTest_FOUND)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTest HANDLE_COMPONENTS CONFIG_MODE)
+
+ set(GTEST_LIBRARIES GTest::gtest)
+ set(GTEST_MAIN_LIBRARIES GTest::gtest_main)
+
+ __gtest_define_backwards_compatible_library_targets()
+
+ return()
+endif()
+
+if(NOT DEFINED GTEST_MSVC_SEARCH)
+ set(GTEST_MSVC_SEARCH MD)
+endif()
+
+set(_gtest_libpath_suffixes lib)
+if(MSVC)
+ if(GTEST_MSVC_SEARCH STREQUAL "MD")
+ list(APPEND _gtest_libpath_suffixes
+ msvc/gtest-md/Debug
+ msvc/gtest-md/Release
+ msvc/x64/Debug
+ msvc/x64/Release
+ msvc/2010/gtest-md/Win32-Debug
+ msvc/2010/gtest-md/Win32-Release
+ msvc/2010/gtest-md/x64-Debug
+ msvc/2010/gtest-md/x64-Release
+ )
+ elseif(GTEST_MSVC_SEARCH STREQUAL "MT")
+ list(APPEND _gtest_libpath_suffixes
+ msvc/gtest/Debug
+ msvc/gtest/Release
+ msvc/x64/Debug
+ msvc/x64/Release
+ msvc/2010/gtest/Win32-Debug
+ msvc/2010/gtest/Win32-Release
+ msvc/2010/gtest/x64-Debug
+ msvc/2010/gtest/x64-Release
+ )
+ endif()
+endif()
+
+
+find_path(GTEST_INCLUDE_DIR gtest/gtest.h
+ HINTS
+ $ENV{GTEST_ROOT}/include
+ ${GTEST_ROOT}/include
+)
+mark_as_advanced(GTEST_INCLUDE_DIR)
+
+if(MSVC AND GTEST_MSVC_SEARCH STREQUAL "MD")
+ # The provided /MD project files for Google Test add -md suffixes to the
+ # library names.
+ __gtest_find_library(GTEST_LIBRARY gtest-md gtest)
+ __gtest_find_library(GTEST_LIBRARY_DEBUG gtest-mdd gtestd)
+ __gtest_find_library(GTEST_MAIN_LIBRARY gtest_main-md gtest_main)
+ __gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_main-mdd gtest_maind)
+else()
+ __gtest_find_library(GTEST_LIBRARY gtest)
+ __gtest_find_library(GTEST_LIBRARY_DEBUG gtestd)
+ __gtest_find_library(GTEST_MAIN_LIBRARY gtest_main)
+ __gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_maind)
+endif()
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTest DEFAULT_MSG GTEST_LIBRARY GTEST_INCLUDE_DIR GTEST_MAIN_LIBRARY)
+
+if(GTest_FOUND)
+ set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIR})
+ __gtest_append_debugs(GTEST_LIBRARIES GTEST_LIBRARY)
+ __gtest_append_debugs(GTEST_MAIN_LIBRARIES GTEST_MAIN_LIBRARY)
+
+ find_package(Threads QUIET)
+
+ if(NOT TARGET GTest::gtest)
+ __gtest_determine_library_type(GTEST_LIBRARY)
+ add_library(GTest::gtest ${GTEST_LIBRARY_TYPE} IMPORTED)
+ if(TARGET Threads::Threads)
+ set_target_properties(GTest::gtest PROPERTIES
+ INTERFACE_LINK_LIBRARIES Threads::Threads)
+ endif()
+ if(GTEST_LIBRARY_TYPE STREQUAL "SHARED")
+ set_target_properties(GTest::gtest PROPERTIES
+ INTERFACE_COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
+ endif()
+ if(GTEST_INCLUDE_DIRS)
+ set_target_properties(GTest::gtest PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIRS}")
+ endif()
+ __gtest_import_library(GTest::gtest GTEST_LIBRARY "")
+ __gtest_import_library(GTest::gtest GTEST_LIBRARY "RELEASE")
+ __gtest_import_library(GTest::gtest GTEST_LIBRARY "DEBUG")
+ endif()
+ if(NOT TARGET GTest::gtest_main)
+ __gtest_determine_library_type(GTEST_MAIN_LIBRARY)
+ add_library(GTest::gtest_main ${GTEST_MAIN_LIBRARY_TYPE} IMPORTED)
+ set_target_properties(GTest::gtest_main PROPERTIES
+ INTERFACE_LINK_LIBRARIES "GTest::gtest")
+ __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "")
+ __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "RELEASE")
+ __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "DEBUG")
+ endif()
+
+ __gtest_define_backwards_compatible_library_targets()
+endif()
diff --git a/Modules/FindGettext.cmake b/Modules/FindGettext.cmake
new file mode 100644
index 0000000..252f2ae
--- /dev/null
+++ b/Modules/FindGettext.cmake
@@ -0,0 +1,232 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindGettext
+-----------
+
+Find GNU gettext tools
+
+This module looks for the GNU gettext tools. This module defines the
+following values:
+
+::
+
+ GETTEXT_MSGMERGE_EXECUTABLE: the full path to the msgmerge tool.
+ GETTEXT_MSGFMT_EXECUTABLE: the full path to the msgfmt tool.
+ GETTEXT_FOUND: True if gettext has been found.
+ GETTEXT_VERSION_STRING: the version of gettext found (since CMake 2.8.8)
+
+
+
+Additionally it provides the following macros:
+
+GETTEXT_CREATE_TRANSLATIONS ( outputFile [ALL] file1 ... fileN )
+
+::
+
+ This will create a target "translations" which will convert the
+ given input po files into the binary output mo file. If the
+ ALL option is used, the translations will also be created when
+ building the default target.
+
+GETTEXT_PROCESS_POT_FILE( <potfile> [ALL] [INSTALL_DESTINATION <destdir>]
+LANGUAGES <lang1> <lang2> ... )
+
+::
+
+ Process the given pot file to mo files.
+ If INSTALL_DESTINATION is given then automatically install rules will
+ be created, the language subdirectory will be taken into account
+ (by default use share/locale/).
+ If ALL is specified, the pot file is processed when building the all traget.
+ It creates a custom target "potfile".
+
+GETTEXT_PROCESS_PO_FILES( <lang> [ALL] [INSTALL_DESTINATION <dir>]
+PO_FILES <po1> <po2> ... )
+
+::
+
+ Process the given po files to mo files for the given language.
+ If INSTALL_DESTINATION is given then automatically install rules will
+ be created, the language subdirectory will be taken into account
+ (by default use share/locale/).
+ If ALL is specified, the po files are processed when building the all traget.
+ It creates a custom target "pofiles".
+
+.. versionadded:: 3.2
+ If you wish to use the Gettext library (libintl), use :module:`FindIntl`.
+#]=======================================================================]
+
+find_program(GETTEXT_MSGMERGE_EXECUTABLE msgmerge)
+
+find_program(GETTEXT_MSGFMT_EXECUTABLE msgfmt)
+
+if(GETTEXT_MSGMERGE_EXECUTABLE)
+ execute_process(COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --version
+ OUTPUT_VARIABLE gettext_version
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ get_filename_component(msgmerge_name ${GETTEXT_MSGMERGE_EXECUTABLE} NAME)
+ get_filename_component(msgmerge_namewe ${GETTEXT_MSGMERGE_EXECUTABLE} NAME_WE)
+ if (gettext_version MATCHES "^(${msgmerge_name}|${msgmerge_namewe}) \\([^\\)]*\\) ([0-9\\.]+[^ \n]*)")
+ set(GETTEXT_VERSION_STRING "${CMAKE_MATCH_2}")
+ endif()
+ unset(gettext_version)
+ unset(msgmerge_name)
+ unset(msgmerge_namewe)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Gettext
+ REQUIRED_VARS GETTEXT_MSGMERGE_EXECUTABLE GETTEXT_MSGFMT_EXECUTABLE
+ VERSION_VAR GETTEXT_VERSION_STRING)
+
+function(_GETTEXT_GET_UNIQUE_TARGET_NAME _name _unique_name)
+ set(propertyName "_GETTEXT_UNIQUE_COUNTER_${_name}")
+ get_property(currentCounter GLOBAL PROPERTY "${propertyName}")
+ if(NOT currentCounter)
+ set(currentCounter 1)
+ endif()
+ set(${_unique_name} "${_name}_${currentCounter}" PARENT_SCOPE)
+ math(EXPR currentCounter "${currentCounter} + 1")
+ set_property(GLOBAL PROPERTY ${propertyName} ${currentCounter} )
+endfunction()
+
+macro(GETTEXT_CREATE_TRANSLATIONS _potFile _firstPoFileArg)
+ # make it a real variable, so we can modify it here
+ set(_firstPoFile "${_firstPoFileArg}")
+
+ set(_gmoFiles)
+ get_filename_component(_potName ${_potFile} NAME)
+ string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName})
+ get_filename_component(_absPotFile ${_potFile} ABSOLUTE)
+
+ set(_addToAll)
+ if(${_firstPoFile} STREQUAL "ALL")
+ set(_addToAll "ALL")
+ set(_firstPoFile)
+ endif()
+
+ foreach (_currentPoFile ${_firstPoFile} ${ARGN})
+ get_filename_component(_absFile ${_currentPoFile} ABSOLUTE)
+ get_filename_component(_abs_PATH ${_absFile} PATH)
+ get_filename_component(_lang ${_absFile} NAME_WE)
+ set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo)
+
+ add_custom_command(
+ OUTPUT ${_gmoFile}
+ COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_absFile} ${_absPotFile}
+ COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_absFile}
+ DEPENDS ${_absPotFile} ${_absFile}
+ )
+
+ install(FILES ${_gmoFile} DESTINATION share/locale/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
+ set(_gmoFiles ${_gmoFiles} ${_gmoFile})
+
+ endforeach ()
+
+ if(NOT TARGET translations)
+ add_custom_target(translations)
+ endif()
+
+ _GETTEXT_GET_UNIQUE_TARGET_NAME(translations uniqueTargetName)
+
+ add_custom_target(${uniqueTargetName} ${_addToAll} DEPENDS ${_gmoFiles})
+
+ add_dependencies(translations ${uniqueTargetName})
+
+endmacro()
+
+
+function(GETTEXT_PROCESS_POT_FILE _potFile)
+ set(_gmoFiles)
+ set(_options ALL)
+ set(_oneValueArgs INSTALL_DESTINATION)
+ set(_multiValueArgs LANGUAGES)
+
+ CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+
+ get_filename_component(_potName ${_potFile} NAME)
+ string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName})
+ get_filename_component(_absPotFile ${_potFile} ABSOLUTE)
+
+ foreach (_lang ${_parsedArguments_LANGUAGES})
+ set(_poFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.po")
+ set(_gmoFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo")
+
+ add_custom_command(
+ OUTPUT "${_poFile}"
+ COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_poFile} ${_absPotFile}
+ DEPENDS ${_absPotFile}
+ )
+
+ add_custom_command(
+ OUTPUT "${_gmoFile}"
+ COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_poFile}
+ DEPENDS ${_absPotFile} ${_poFile}
+ )
+
+ if(_parsedArguments_INSTALL_DESTINATION)
+ install(FILES ${_gmoFile} DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
+ endif()
+ list(APPEND _gmoFiles ${_gmoFile})
+ endforeach ()
+
+ if(NOT TARGET potfiles)
+ add_custom_target(potfiles)
+ endif()
+
+ _GETTEXT_GET_UNIQUE_TARGET_NAME( potfiles uniqueTargetName)
+
+ if(_parsedArguments_ALL)
+ add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles})
+ else()
+ add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles})
+ endif()
+
+ add_dependencies(potfiles ${uniqueTargetName})
+
+endfunction()
+
+
+function(GETTEXT_PROCESS_PO_FILES _lang)
+ set(_options ALL)
+ set(_oneValueArgs INSTALL_DESTINATION)
+ set(_multiValueArgs PO_FILES)
+ set(_gmoFiles)
+
+ CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
+
+ foreach(_current_PO_FILE ${_parsedArguments_PO_FILES})
+ get_filename_component(_name ${_current_PO_FILE} NAME)
+ string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _basename ${_name})
+ set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo)
+ add_custom_command(OUTPUT ${_gmoFile}
+ COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_current_PO_FILE}
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ DEPENDS ${_current_PO_FILE}
+ )
+
+ if(_parsedArguments_INSTALL_DESTINATION)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES/ RENAME ${_basename}.mo)
+ endif()
+ list(APPEND _gmoFiles ${_gmoFile})
+ endforeach()
+
+
+ if(NOT TARGET pofiles)
+ add_custom_target(pofiles)
+ endif()
+
+ _GETTEXT_GET_UNIQUE_TARGET_NAME( pofiles uniqueTargetName)
+
+ if(_parsedArguments_ALL)
+ add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles})
+ else()
+ add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles})
+ endif()
+
+ add_dependencies(pofiles ${uniqueTargetName})
+
+endfunction()
diff --git a/Modules/FindGit.cmake b/Modules/FindGit.cmake
new file mode 100644
index 0000000..99850b4
--- /dev/null
+++ b/Modules/FindGit.cmake
@@ -0,0 +1,130 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindGit
+-------
+
+The module defines the following variables:
+
+``GIT_EXECUTABLE``
+ Path to Git command-line client.
+``Git_FOUND``, ``GIT_FOUND``
+ True if the Git command-line client was found.
+``GIT_VERSION_STRING``
+ The version of Git found.
+
+.. versionadded:: 3.14
+ The module defines the following ``IMPORTED`` targets (when
+ :prop_gbl:`CMAKE_ROLE` is ``PROJECT``):
+
+``Git::Git``
+ Executable of the Git command-line client.
+
+Example usage:
+
+.. code-block:: cmake
+
+ find_package(Git)
+ if(Git_FOUND)
+ message("Git found: ${GIT_EXECUTABLE}")
+ endif()
+#]=======================================================================]
+
+# Look for 'git' or 'eg' (easy git)
+#
+set(git_names git eg)
+
+# Prefer .cmd variants on Windows unless running in a Makefile
+# in the MSYS shell.
+#
+if(CMAKE_HOST_WIN32)
+ if(NOT CMAKE_GENERATOR MATCHES "MSYS")
+ set(git_names git.cmd git eg.cmd eg)
+ # GitHub search path for Windows
+ file(GLOB github_path
+ "$ENV{LOCALAPPDATA}/Github/PortableGit*/cmd"
+ "$ENV{LOCALAPPDATA}/Github/PortableGit*/bin"
+ )
+ # SourceTree search path for Windows
+ set(_git_sourcetree_path "$ENV{LOCALAPPDATA}/Atlassian/SourceTree/git_local/bin")
+ endif()
+endif()
+
+# First search the PATH and specific locations.
+find_program(GIT_EXECUTABLE
+ NAMES ${git_names}
+ PATHS ${github_path} ${_git_sourcetree_path}
+ DOC "Git command line client"
+ )
+
+if(CMAKE_HOST_WIN32)
+ # Now look for installations in Git/ directories under typical installation
+ # prefixes on Windows. Exclude PATH from this search because VS 2017's
+ # command prompt happens to have a PATH entry with a Git/ subdirectory
+ # containing a minimal git not meant for general use.
+ find_program(GIT_EXECUTABLE
+ NAMES ${git_names}
+ PATH_SUFFIXES Git/cmd Git/bin
+ NO_SYSTEM_ENVIRONMENT_PATH
+ DOC "Git command line client"
+ )
+endif()
+
+mark_as_advanced(GIT_EXECUTABLE)
+
+unset(git_names)
+unset(_git_sourcetree_path)
+
+if(GIT_EXECUTABLE)
+ # Avoid querying the version if we've already done that this run. For
+ # projects that use things like ExternalProject or FetchContent heavily,
+ # this saving can be measurable on some platforms.
+ #
+ # This is an internal property, projects must not try to use it.
+ # We don't want this stored in the cache because it might still change
+ # between CMake runs, but it shouldn't change during a run for a given
+ # git executable location.
+ set(__doGitVersionCheck TRUE)
+ get_property(__gitVersionProp GLOBAL
+ PROPERTY _CMAKE_FindGit_GIT_EXECUTABLE_VERSION
+ )
+ if(__gitVersionProp)
+ list(GET __gitVersionProp 0 __gitExe)
+ list(GET __gitVersionProp 1 __gitVersion)
+ if(__gitExe STREQUAL GIT_EXECUTABLE AND NOT __gitVersion STREQUAL "")
+ set(GIT_VERSION_STRING "${__gitVersion}")
+ set(__doGitVersionCheck FALSE)
+ endif()
+ unset(__gitExe)
+ unset(__gitVersion)
+ endif()
+ unset(__gitVersionProp)
+
+ if(__doGitVersionCheck)
+ execute_process(COMMAND ${GIT_EXECUTABLE} --version
+ OUTPUT_VARIABLE git_version
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (git_version MATCHES "^git version [0-9]")
+ string(REPLACE "git version " "" GIT_VERSION_STRING "${git_version}")
+ set_property(GLOBAL PROPERTY _CMAKE_FindGit_GIT_EXECUTABLE_VERSION
+ "${GIT_EXECUTABLE};${GIT_VERSION_STRING}"
+ )
+ endif()
+ unset(git_version)
+ endif()
+ unset(__doGitVersionCheck)
+
+ get_property(_findgit_role GLOBAL PROPERTY CMAKE_ROLE)
+ if(_findgit_role STREQUAL "PROJECT" AND NOT TARGET Git::Git)
+ add_executable(Git::Git IMPORTED)
+ set_property(TARGET Git::Git PROPERTY IMPORTED_LOCATION "${GIT_EXECUTABLE}")
+ endif()
+ unset(_findgit_role)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(Git
+ REQUIRED_VARS GIT_EXECUTABLE
+ VERSION_VAR GIT_VERSION_STRING)
diff --git a/Modules/FindGnuTLS.cmake b/Modules/FindGnuTLS.cmake
new file mode 100644
index 0000000..782a72b
--- /dev/null
+++ b/Modules/FindGnuTLS.cmake
@@ -0,0 +1,84 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindGnuTLS
+----------
+
+Find the GNU Transport Layer Security library (gnutls)
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.16
+
+This module defines :prop_tgt:`IMPORTED` target ``GnuTLS::GnuTLS``, if
+gnutls has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+``GNUTLS_FOUND``
+ System has gnutls
+``GNUTLS_INCLUDE_DIR``
+ The gnutls include directory
+``GNUTLS_LIBRARIES``
+ The libraries needed to use gnutls
+``GNUTLS_DEFINITIONS``
+ Compiler switches required for using gnutls
+``GNUTLS_VERSION``
+ version of gnutls.
+#]=======================================================================]
+
+# Note that this doesn't try to find the gnutls-extra package.
+
+
+if (GNUTLS_INCLUDE_DIR AND GNUTLS_LIBRARY)
+ # in cache already
+ set(gnutls_FIND_QUIETLY TRUE)
+endif ()
+
+if (NOT WIN32)
+ # try using pkg-config to get the directories and then use these values
+ # in the find_path() and find_library() calls
+ # also fills in GNUTLS_DEFINITIONS, although that isn't normally useful
+ find_package(PkgConfig QUIET)
+ PKG_CHECK_MODULES(PC_GNUTLS QUIET gnutls)
+ set(GNUTLS_DEFINITIONS ${PC_GNUTLS_CFLAGS_OTHER})
+ set(GNUTLS_VERSION ${PC_GNUTLS_VERSION})
+ # keep for backward compatibility
+ set(GNUTLS_VERSION_STRING ${PC_GNUTLS_VERSION})
+endif ()
+
+find_path(GNUTLS_INCLUDE_DIR gnutls/gnutls.h
+ HINTS
+ ${PC_GNUTLS_INCLUDEDIR}
+ ${PC_GNUTLS_INCLUDE_DIRS}
+ )
+
+find_library(GNUTLS_LIBRARY NAMES gnutls libgnutls
+ HINTS
+ ${PC_GNUTLS_LIBDIR}
+ ${PC_GNUTLS_LIBRARY_DIRS}
+ )
+
+mark_as_advanced(GNUTLS_INCLUDE_DIR GNUTLS_LIBRARY)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GnuTLS
+ REQUIRED_VARS GNUTLS_LIBRARY GNUTLS_INCLUDE_DIR
+ VERSION_VAR GNUTLS_VERSION_STRING)
+
+if(GNUTLS_FOUND)
+ set(GNUTLS_LIBRARIES ${GNUTLS_LIBRARY})
+ set(GNUTLS_INCLUDE_DIRS ${GNUTLS_INCLUDE_DIR})
+
+ if(NOT TARGET GnuTLS::GnuTLS)
+ add_library(GnuTLS::GnuTLS UNKNOWN IMPORTED)
+ set_target_properties(GnuTLS::GnuTLS PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${GNUTLS_INCLUDE_DIRS}"
+ INTERFACE_COMPILE_DEFINITIONS "${GNUTLS_DEFINITIONS}"
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${GNUTLS_LIBRARIES}")
+ endif()
+endif()
diff --git a/Modules/FindGnuplot.cmake b/Modules/FindGnuplot.cmake
new file mode 100644
index 0000000..ca2467d
--- /dev/null
+++ b/Modules/FindGnuplot.cmake
@@ -0,0 +1,55 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindGnuplot
+-----------
+
+this module looks for gnuplot
+
+
+
+Once done this will define
+
+::
+
+ GNUPLOT_FOUND - system has Gnuplot
+ GNUPLOT_EXECUTABLE - the Gnuplot executable
+ GNUPLOT_VERSION_STRING - the version of Gnuplot found (since CMake 2.8.8)
+
+
+
+GNUPLOT_VERSION_STRING will not work for old versions like 3.7.1.
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindCygwin.cmake)
+
+find_program(GNUPLOT_EXECUTABLE
+ NAMES
+ gnuplot
+ pgnuplot
+ wgnupl32
+ PATHS
+ ${CYGWIN_INSTALL_PATH}/bin
+)
+
+if (GNUPLOT_EXECUTABLE)
+ execute_process(COMMAND "${GNUPLOT_EXECUTABLE}" --version
+ OUTPUT_VARIABLE GNUPLOT_OUTPUT_VARIABLE
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ string(REGEX REPLACE "^gnuplot ([0-9\\.]+)( patchlevel )?" "\\1." GNUPLOT_VERSION_STRING "${GNUPLOT_OUTPUT_VARIABLE}")
+ string(REGEX REPLACE "\\.$" "" GNUPLOT_VERSION_STRING "${GNUPLOT_VERSION_STRING}")
+ unset(GNUPLOT_OUTPUT_VARIABLE)
+endif()
+
+# for compatibility
+set(GNUPLOT ${GNUPLOT_EXECUTABLE})
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Gnuplot
+ REQUIRED_VARS GNUPLOT_EXECUTABLE
+ VERSION_VAR GNUPLOT_VERSION_STRING)
+
+mark_as_advanced( GNUPLOT_EXECUTABLE )
diff --git a/Modules/FindHDF5.cmake b/Modules/FindHDF5.cmake
new file mode 100644
index 0000000..e335355
--- /dev/null
+++ b/Modules/FindHDF5.cmake
@@ -0,0 +1,1183 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindHDF5
+--------
+
+Find Hierarchical Data Format (HDF5), a library for reading and writing
+self describing array data.
+
+
+This module invokes the ``HDF5`` wrapper compiler that should be installed
+alongside ``HDF5``. Depending upon the ``HDF5`` Configuration, the wrapper
+compiler is called either ``h5cc`` or ``h5pcc``. If this succeeds, the module
+will then call the compiler with the show argument to see what flags
+are used when compiling an ``HDF5`` client application.
+
+The module will optionally accept the ``COMPONENTS`` argument. If no
+``COMPONENTS`` are specified, then the find module will default to finding
+only the ``HDF5`` C library. If one or more ``COMPONENTS`` are specified, the
+module will attempt to find the language bindings for the specified
+components. The valid components are ``C``, ``CXX``, ``Fortran``, ``HL``.
+``HL`` refers to the "high-level" HDF5 functions for C and Fortran.
+If the ``COMPONENTS`` argument is not given, the module will
+attempt to find only the C bindings.
+For example, to use Fortran HDF5 and HDF5-HL functions, do:
+``find_package(HDF5 COMPONENTS Fortran HL)``.
+
+This module will read the variable
+``HDF5_USE_STATIC_LIBRARIES`` to determine whether or not to prefer a
+static link to a dynamic link for ``HDF5`` and all of it's dependencies.
+To use this feature, make sure that the ``HDF5_USE_STATIC_LIBRARIES``
+variable is set before the call to find_package.
+
+.. versionadded:: 3.10
+ Support for ``HDF5_USE_STATIC_LIBRARIES`` on Windows.
+
+Both the serial and parallel ``HDF5`` wrappers are considered and the first
+directory to contain either one will be used. In the event that both appear
+in the same directory the serial version is preferentially selected. This
+behavior can be reversed by setting the variable ``HDF5_PREFER_PARALLEL`` to
+``TRUE``.
+
+In addition to finding the includes and libraries required to compile
+an ``HDF5`` client application, this module also makes an effort to find
+tools that come with the ``HDF5`` distribution that may be useful for
+regression testing.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``HDF5_FOUND``
+ HDF5 was found on the system
+``HDF5_VERSION``
+ .. versionadded:: 3.3
+ HDF5 library version
+``HDF5_INCLUDE_DIRS``
+ Location of the HDF5 header files
+``HDF5_DEFINITIONS``
+ Required compiler definitions for HDF5
+``HDF5_LIBRARIES``
+ Required libraries for all requested bindings
+``HDF5_HL_LIBRARIES``
+ Required libraries for the HDF5 high level API for all bindings,
+ if the ``HL`` component is enabled
+
+Available components are: ``C`` ``CXX`` ``Fortran`` and ``HL``.
+For each enabled language binding, a corresponding ``HDF5_${LANG}_LIBRARIES``
+variable, and potentially ``HDF5_${LANG}_DEFINITIONS``, will be defined.
+If the ``HL`` component is enabled, then an ``HDF5_${LANG}_HL_LIBRARIES`` will
+also be defined. With all components enabled, the following variables will be defined:
+
+``HDF5_C_DEFINITIONS``
+ Required compiler definitions for HDF5 C bindings
+``HDF5_CXX_DEFINITIONS``
+ Required compiler definitions for HDF5 C++ bindings
+``HDF5_Fortran_DEFINITIONS``
+ Required compiler definitions for HDF5 Fortran bindings
+``HDF5_C_INCLUDE_DIRS``
+ Required include directories for HDF5 C bindings
+``HDF5_CXX_INCLUDE_DIRS``
+ Required include directories for HDF5 C++ bindings
+``HDF5_Fortran_INCLUDE_DIRS``
+ Required include directories for HDF5 Fortran bindings
+``HDF5_C_LIBRARIES``
+ Required libraries for the HDF5 C bindings
+``HDF5_CXX_LIBRARIES``
+ Required libraries for the HDF5 C++ bindings
+``HDF5_Fortran_LIBRARIES``
+ Required libraries for the HDF5 Fortran bindings
+``HDF5_C_HL_LIBRARIES``
+ Required libraries for the high level C bindings
+``HDF5_CXX_HL_LIBRARIES``
+ Required libraries for the high level C++ bindings
+``HDF5_Fortran_HL_LIBRARIES``
+ Required libraries for the high level Fortran bindings.
+
+``HDF5_IS_PARALLEL``
+ HDF5 library has parallel IO support
+``HDF5_C_COMPILER_EXECUTABLE``
+ path to the HDF5 C wrapper compiler
+``HDF5_CXX_COMPILER_EXECUTABLE``
+ path to the HDF5 C++ wrapper compiler
+``HDF5_Fortran_COMPILER_EXECUTABLE``
+ path to the HDF5 Fortran wrapper compiler
+``HDF5_C_COMPILER_EXECUTABLE_NO_INTERROGATE``
+ path to the primary C compiler which is also the HDF5 wrapper
+``HDF5_CXX_COMPILER_EXECUTABLE_NO_INTERROGATE``
+ path to the primary C++ compiler which is also the HDF5 wrapper
+``HDF5_Fortran_COMPILER_EXECUTABLE_NO_INTERROGATE``
+ path to the primary Fortran compiler which is also the HDF5 wrapper
+``HDF5_DIFF_EXECUTABLE``
+ path to the HDF5 dataset comparison tool
+
+With all components enabled, the following targets will be defined:
+
+``HDF5::HDF5``
+ All detected ``HDF5_LIBRARIES``.
+``hdf5::hdf5``
+ C library.
+``hdf5::hdf5_cpp``
+ C++ library.
+``hdf5::hdf5_fortran``
+ Fortran library.
+``hdf5::hdf5_hl``
+ High-level C library.
+``hdf5::hdf5_hl_cpp``
+ High-level C++ library.
+``hdf5::hdf5_hl_fortran``
+ High-level Fortran library.
+``hdf5::h5diff``
+ ``h5diff`` executable.
+
+Hints
+^^^^^
+
+The following variables can be set to guide the search for HDF5 libraries and includes:
+
+``HDF5_PREFER_PARALLEL``
+ .. versionadded:: 3.4
+
+ set ``true`` to prefer parallel HDF5 (by default, serial is preferred)
+
+``HDF5_FIND_DEBUG``
+ .. versionadded:: 3.9
+
+ Set ``true`` to get extra debugging output.
+
+``HDF5_NO_FIND_PACKAGE_CONFIG_FILE``
+ .. versionadded:: 3.8
+
+ Set ``true`` to skip trying to find ``hdf5-config.cmake``.
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+# We haven't found HDF5 yet. Clear its state in case it is set in the parent
+# scope somewhere else. We can't rely on it because different components may
+# have been requested for this call.
+set(HDF5_FOUND OFF)
+
+# List of the valid HDF5 components
+set(HDF5_VALID_LANGUAGE_BINDINGS C CXX Fortran)
+
+# Validate the list of find components.
+if(NOT HDF5_FIND_COMPONENTS)
+ set(HDF5_LANGUAGE_BINDINGS "C")
+else()
+ set(HDF5_LANGUAGE_BINDINGS)
+ # add the extra specified components, ensuring that they are valid.
+ set(HDF5_FIND_HL OFF)
+ foreach(_component IN LISTS HDF5_FIND_COMPONENTS)
+ list(FIND HDF5_VALID_LANGUAGE_BINDINGS ${_component} _component_location)
+ if(NOT _component_location EQUAL -1)
+ list(APPEND HDF5_LANGUAGE_BINDINGS ${_component})
+ elseif(_component STREQUAL "HL")
+ set(HDF5_FIND_HL ON)
+ elseif(_component STREQUAL "Fortran_HL") # only for compatibility
+ list(APPEND HDF5_LANGUAGE_BINDINGS Fortran)
+ set(HDF5_FIND_HL ON)
+ set(HDF5_FIND_REQUIRED_Fortran_HL FALSE)
+ set(HDF5_FIND_REQUIRED_Fortran TRUE)
+ set(HDF5_FIND_REQUIRED_HL TRUE)
+ else()
+ message(FATAL_ERROR "${_component} is not a valid HDF5 component.")
+ endif()
+ endforeach()
+ unset(_component)
+ unset(_component_location)
+ if(NOT HDF5_LANGUAGE_BINDINGS)
+ get_property(_langs GLOBAL PROPERTY ENABLED_LANGUAGES)
+ foreach(_lang IN LISTS _langs)
+ if(_lang MATCHES "^(C|CXX|Fortran)$")
+ list(APPEND HDF5_LANGUAGE_BINDINGS ${_lang})
+ endif()
+ endforeach()
+ endif()
+ list(REMOVE_ITEM HDF5_FIND_COMPONENTS Fortran_HL) # replaced by Fortran and HL
+ list(REMOVE_DUPLICATES HDF5_LANGUAGE_BINDINGS)
+endif()
+
+# Determine whether to search for serial or parallel executable first
+if(HDF5_PREFER_PARALLEL)
+ set(HDF5_C_COMPILER_NAMES h5pcc h5cc)
+ set(HDF5_CXX_COMPILER_NAMES h5pc++ h5c++)
+ set(HDF5_Fortran_COMPILER_NAMES h5pfc h5fc)
+else()
+ set(HDF5_C_COMPILER_NAMES h5cc h5pcc)
+ set(HDF5_CXX_COMPILER_NAMES h5c++ h5pc++)
+ set(HDF5_Fortran_COMPILER_NAMES h5fc h5pfc)
+endif()
+
+# Test first if the current compilers automatically wrap HDF5
+function(_HDF5_test_regular_compiler_C success version is_parallel)
+ set(scratch_directory
+ ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5)
+ if(NOT ${success} OR
+ NOT EXISTS ${scratch_directory}/compiler_has_h5_c)
+ set(test_file ${scratch_directory}/cmake_hdf5_test.c)
+ file(WRITE ${test_file}
+ "#include <hdf5.h>\n"
+ "const char* info_ver = \"INFO\" \":\" H5_VERSION;\n"
+ "#ifdef H5_HAVE_PARALLEL\n"
+ "const char* info_parallel = \"INFO\" \":\" \"PARALLEL\";\n"
+ "#endif\n"
+ "int main(int argc, char **argv) {\n"
+ " int require = 0;\n"
+ " require += info_ver[argc];\n"
+ "#ifdef H5_HAVE_PARALLEL\n"
+ " require += info_parallel[argc];\n"
+ "#endif\n"
+ " hid_t fid;\n"
+ " fid = H5Fcreate(\"foo.h5\",H5F_ACC_TRUNC,H5P_DEFAULT,H5P_DEFAULT);\n"
+ " return 0;\n"
+ "}")
+ try_compile(${success} ${scratch_directory} ${test_file}
+ COPY_FILE ${scratch_directory}/compiler_has_h5_c
+ )
+ endif()
+ if(${success})
+ file(STRINGS ${scratch_directory}/compiler_has_h5_c INFO_STRINGS
+ REGEX "^INFO:"
+ )
+ string(REGEX MATCH "^INFO:([0-9]+\\.[0-9]+\\.[0-9]+)(-patch([0-9]+))?"
+ INFO_VER "${INFO_STRINGS}"
+ )
+ set(${version} ${CMAKE_MATCH_1})
+ if(CMAKE_MATCH_3)
+ set(${version} ${HDF5_C_VERSION}.${CMAKE_MATCH_3})
+ endif()
+ set(${version} ${${version}} PARENT_SCOPE)
+
+ if(INFO_STRINGS MATCHES "INFO:PARALLEL")
+ set(${is_parallel} TRUE PARENT_SCOPE)
+ else()
+ set(${is_parallel} FALSE PARENT_SCOPE)
+ endif()
+ endif()
+endfunction()
+
+function(_HDF5_test_regular_compiler_CXX success version is_parallel)
+ set(scratch_directory ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5)
+ if(NOT ${success} OR
+ NOT EXISTS ${scratch_directory}/compiler_has_h5_cxx)
+ set(test_file ${scratch_directory}/cmake_hdf5_test.cxx)
+ file(WRITE ${test_file}
+ "#include <H5Cpp.h>\n"
+ "#ifndef H5_NO_NAMESPACE\n"
+ "using namespace H5;\n"
+ "#endif\n"
+ "const char* info_ver = \"INFO\" \":\" H5_VERSION;\n"
+ "#ifdef H5_HAVE_PARALLEL\n"
+ "const char* info_parallel = \"INFO\" \":\" \"PARALLEL\";\n"
+ "#endif\n"
+ "int main(int argc, char **argv) {\n"
+ " int require = 0;\n"
+ " require += info_ver[argc];\n"
+ "#ifdef H5_HAVE_PARALLEL\n"
+ " require += info_parallel[argc];\n"
+ "#endif\n"
+ " H5File file(\"foo.h5\", H5F_ACC_TRUNC);\n"
+ " return 0;\n"
+ "}")
+ try_compile(${success} ${scratch_directory} ${test_file}
+ COPY_FILE ${scratch_directory}/compiler_has_h5_cxx
+ )
+ endif()
+ if(${success})
+ file(STRINGS ${scratch_directory}/compiler_has_h5_cxx INFO_STRINGS
+ REGEX "^INFO:"
+ )
+ string(REGEX MATCH "^INFO:([0-9]+\\.[0-9]+\\.[0-9]+)(-patch([0-9]+))?"
+ INFO_VER "${INFO_STRINGS}"
+ )
+ set(${version} ${CMAKE_MATCH_1})
+ if(CMAKE_MATCH_3)
+ set(${version} ${HDF5_CXX_VERSION}.${CMAKE_MATCH_3})
+ endif()
+ set(${version} ${${version}} PARENT_SCOPE)
+
+ if(INFO_STRINGS MATCHES "INFO:PARALLEL")
+ set(${is_parallel} TRUE PARENT_SCOPE)
+ else()
+ set(${is_parallel} FALSE PARENT_SCOPE)
+ endif()
+ endif()
+endfunction()
+
+function(_HDF5_test_regular_compiler_Fortran success is_parallel)
+ if(NOT ${success})
+ set(scratch_directory
+ ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5)
+ set(test_file ${scratch_directory}/cmake_hdf5_test.f90)
+ file(WRITE ${test_file}
+ "program hdf5_hello\n"
+ " use hdf5\n"
+ " use h5lt\n"
+ " use h5ds\n"
+ " integer error\n"
+ " call h5open_f(error)\n"
+ " call h5close_f(error)\n"
+ "end\n")
+ try_compile(${success} ${scratch_directory} ${test_file})
+ if(${success})
+ execute_process(COMMAND ${CMAKE_Fortran_COMPILER} -showconfig
+ OUTPUT_VARIABLE config_output
+ ERROR_VARIABLE config_error
+ RESULT_VARIABLE config_result
+ )
+ if(config_output MATCHES "Parallel HDF5: yes")
+ set(${is_parallel} TRUE PARENT_SCOPE)
+ else()
+ set(${is_parallel} FALSE PARENT_SCOPE)
+ endif()
+ endif()
+ endif()
+endfunction()
+
+# Invoke the HDF5 wrapper compiler. The compiler return value is stored to the
+# return_value argument, the text output is stored to the output variable.
+function( _HDF5_invoke_compiler language output_var return_value_var version_var is_parallel_var)
+ set(is_parallel FALSE)
+ if(HDF5_USE_STATIC_LIBRARIES)
+ set(lib_type_args -noshlib)
+ else()
+ set(lib_type_args -shlib)
+ endif()
+ set(scratch_dir ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5)
+ if("${language}" STREQUAL "C")
+ set(test_file ${scratch_dir}/cmake_hdf5_test.c)
+ elseif("${language}" STREQUAL "CXX")
+ set(test_file ${scratch_dir}/cmake_hdf5_test.cxx)
+ elseif("${language}" STREQUAL "Fortran")
+ set(test_file ${scratch_dir}/cmake_hdf5_test.f90)
+ endif()
+ # Verify that the compiler wrapper can actually compile: sometimes the compiler
+ # wrapper exists, but not the compiler. E.g. Miniconda / Anaconda Python
+ execute_process(
+ COMMAND ${HDF5_${language}_COMPILER_EXECUTABLE} ${test_file}
+ WORKING_DIRECTORY ${scratch_dir}
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE output
+ RESULT_VARIABLE return_value
+ )
+ if(return_value AND NOT HDF5_FIND_QUIETLY)
+ message(STATUS
+ "HDF5 ${language} compiler wrapper is unable to compile a minimal HDF5 program.")
+ else()
+ execute_process(
+ COMMAND ${HDF5_${language}_COMPILER_EXECUTABLE} -show ${lib_type_args} ${test_file}
+ WORKING_DIRECTORY ${scratch_dir}
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE output
+ RESULT_VARIABLE return_value
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if(return_value AND NOT HDF5_FIND_QUIETLY)
+ message(STATUS
+ "Unable to determine HDF5 ${language} flags from HDF5 wrapper.")
+ endif()
+ execute_process(
+ COMMAND ${HDF5_${language}_COMPILER_EXECUTABLE} -showconfig
+ OUTPUT_VARIABLE config_output
+ ERROR_VARIABLE config_output
+ RESULT_VARIABLE return_value
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if(return_value AND NOT HDF5_FIND_QUIETLY)
+ message(STATUS
+ "Unable to determine HDF5 ${language} version_var from HDF5 wrapper.")
+ endif()
+ string(REGEX MATCH "HDF5 Version: ([a-zA-Z0-9\\.\\-]*)" version "${config_output}")
+ if(version)
+ string(REPLACE "HDF5 Version: " "" version "${version}")
+ string(REPLACE "-patch" "." version "${version}")
+ endif()
+ if(config_output MATCHES "Parallel HDF5: yes")
+ set(is_parallel TRUE)
+ endif()
+ endif()
+ foreach(var output return_value version is_parallel)
+ set(${${var}_var} ${${var}} PARENT_SCOPE)
+ endforeach()
+endfunction()
+
+# Parse a compile line for definitions, includes, library paths, and libraries.
+function(_HDF5_parse_compile_line compile_line_var include_paths definitions
+ library_paths libraries libraries_hl)
+
+ separate_arguments(_compile_args NATIVE_COMMAND "${${compile_line_var}}")
+
+ foreach(_arg IN LISTS _compile_args)
+ if("${_arg}" MATCHES "^-I(.*)$")
+ # include directory
+ list(APPEND include_paths "${CMAKE_MATCH_1}")
+ elseif("${_arg}" MATCHES "^-D(.*)$")
+ # compile definition
+ list(APPEND definitions "-D${CMAKE_MATCH_1}")
+ elseif("${_arg}" MATCHES "^-L(.*)$")
+ # library search path
+ list(APPEND library_paths "${CMAKE_MATCH_1}")
+ elseif("${_arg}" MATCHES "^-l(hdf5.*hl.*)$")
+ # library name (hl)
+ list(APPEND libraries_hl "${CMAKE_MATCH_1}")
+ elseif("${_arg}" MATCHES "^-l(.*)$")
+ # library name
+ list(APPEND libraries "${CMAKE_MATCH_1}")
+ elseif("${_arg}" MATCHES "^(.:)?[/\\].*\\.(a|so|dylib|sl|lib)$")
+ # library file
+ if(NOT EXISTS "${_arg}")
+ continue()
+ endif()
+ get_filename_component(_lpath "${_arg}" DIRECTORY)
+ get_filename_component(_lname "${_arg}" NAME_WE)
+ string(REGEX REPLACE "^lib" "" _lname "${_lname}")
+ list(APPEND library_paths "${_lpath}")
+ if(_lname MATCHES "hdf5.*hl")
+ list(APPEND libraries_hl "${_lname}")
+ else()
+ list(APPEND libraries "${_lname}")
+ endif()
+ endif()
+ endforeach()
+ foreach(var include_paths definitions library_paths libraries libraries_hl)
+ set(${${var}_var} ${${var}} PARENT_SCOPE)
+ endforeach()
+endfunction()
+
+# Select a preferred imported configuration from a target
+function(_HDF5_select_imported_config target imported_conf)
+ # We will first assign the value to a local variable _imported_conf, then assign
+ # it to the function argument at the end.
+ get_target_property(_imported_conf ${target} MAP_IMPORTED_CONFIG_${CMAKE_BUILD_TYPE})
+ if (NOT _imported_conf)
+ # Get available imported configurations by examining target properties
+ get_target_property(_imported_conf ${target} IMPORTED_CONFIGURATIONS)
+ if(HDF5_FIND_DEBUG)
+ message(STATUS "Found imported configurations: ${_imported_conf}")
+ endif()
+ # Find the imported configuration that we prefer.
+ # We do this by making list of configurations in order of preference,
+ # starting with ${CMAKE_BUILD_TYPE} and ending with the first imported_conf
+ set(_preferred_confs ${CMAKE_BUILD_TYPE})
+ list(GET _imported_conf 0 _fallback_conf)
+ list(APPEND _preferred_confs RELWITHDEBINFO RELEASE DEBUG ${_fallback_conf})
+ if(HDF5_FIND_DEBUG)
+ message(STATUS "Start search through imported configurations in the following order: ${_preferred_confs}")
+ endif()
+ # Now find the first of these that is present in imported_conf
+ cmake_policy(PUSH)
+ cmake_policy(SET CMP0057 NEW) # support IN_LISTS
+ foreach (_conf IN LISTS _preferred_confs)
+ if (${_conf} IN_LIST _imported_conf)
+ set(_imported_conf ${_conf})
+ break()
+ endif()
+ endforeach()
+ cmake_policy(POP)
+ endif()
+ if(HDF5_FIND_DEBUG)
+ message(STATUS "Selected imported configuration: ${_imported_conf}")
+ endif()
+ # assign value to function argument
+ set(${imported_conf} ${_imported_conf} PARENT_SCOPE)
+endfunction()
+
+
+if(NOT HDF5_ROOT)
+ set(HDF5_ROOT $ENV{HDF5_ROOT})
+endif()
+if(HDF5_ROOT)
+ set(_HDF5_SEARCH_OPTS NO_DEFAULT_PATH)
+else()
+ set(_HDF5_SEARCH_OPTS)
+endif()
+
+# Try to find HDF5 using an installed hdf5-config.cmake
+if(NOT HDF5_FOUND AND NOT HDF5_NO_FIND_PACKAGE_CONFIG_FILE)
+ find_package(HDF5 QUIET NO_MODULE
+ HINTS ${HDF5_ROOT}
+ ${_HDF5_SEARCH_OPTS}
+ )
+ if( HDF5_FOUND)
+ if(HDF5_FIND_DEBUG)
+ message(STATUS "Found HDF5 at ${HDF5_DIR} via NO_MODULE. Now trying to extract locations etc.")
+ endif()
+ set(HDF5_IS_PARALLEL ${HDF5_ENABLE_PARALLEL})
+ set(HDF5_INCLUDE_DIRS ${HDF5_INCLUDE_DIR})
+ set(HDF5_LIBRARIES)
+ if (NOT TARGET hdf5 AND NOT TARGET hdf5-static AND NOT TARGET hdf5-shared)
+ # Some HDF5 versions (e.g. 1.8.18) used hdf5::hdf5 etc
+ set(_target_prefix "hdf5::")
+ endif()
+ set(HDF5_C_TARGET ${_target_prefix}hdf5)
+ set(HDF5_C_HL_TARGET ${_target_prefix}hdf5_hl)
+ set(HDF5_CXX_TARGET ${_target_prefix}hdf5_cpp)
+ set(HDF5_CXX_HL_TARGET ${_target_prefix}hdf5_hl_cpp)
+ set(HDF5_Fortran_TARGET ${_target_prefix}hdf5_fortran)
+ set(HDF5_Fortran_HL_TARGET ${_target_prefix}hdf5_hl_fortran)
+ set(HDF5_DEFINITIONS "")
+ if(HDF5_USE_STATIC_LIBRARIES)
+ set(_suffix "-static")
+ else()
+ set(_suffix "-shared")
+ endif()
+ foreach(_lang ${HDF5_LANGUAGE_BINDINGS})
+
+ #Older versions of hdf5 don't have a static/shared suffix so
+ #if we detect that occurrence clear the suffix
+ if(_suffix AND NOT TARGET ${HDF5_${_lang}_TARGET}${_suffix})
+ if(NOT TARGET ${HDF5_${_lang}_TARGET})
+ #can't find this component with or without the suffix
+ #so bail out, and let the following locate HDF5
+ set(HDF5_FOUND FALSE)
+ break()
+ endif()
+ set(_suffix "")
+ endif()
+
+ if(HDF5_FIND_DEBUG)
+ message(STATUS "Trying to get properties of target ${HDF5_${_lang}_TARGET}${_suffix}")
+ endif()
+ # Find library for this target. Complicated as on Windows with a DLL, we need to search for the import-lib.
+ _HDF5_select_imported_config(${HDF5_${_lang}_TARGET}${_suffix} _hdf5_imported_conf)
+ get_target_property(_hdf5_lang_location ${HDF5_${_lang}_TARGET}${_suffix} IMPORTED_IMPLIB_${_hdf5_imported_conf} )
+ if (NOT _hdf5_lang_location)
+ # no import lib, just try LOCATION
+ get_target_property(_hdf5_lang_location ${HDF5_${_lang}_TARGET}${_suffix} LOCATION_${_hdf5_imported_conf})
+ if (NOT _hdf5_lang_location)
+ get_target_property(_hdf5_lang_location ${HDF5_${_lang}_TARGET}${_suffix} LOCATION)
+ endif()
+ endif()
+ if( _hdf5_lang_location )
+ set(HDF5_${_lang}_LIBRARY ${_hdf5_lang_location})
+ list(APPEND HDF5_LIBRARIES ${HDF5_${_lang}_TARGET}${_suffix})
+ set(HDF5_${_lang}_LIBRARIES ${HDF5_${_lang}_TARGET}${_suffix})
+ set(HDF5_${_lang}_FOUND TRUE)
+ endif()
+ if(HDF5_FIND_HL)
+ get_target_property(_lang_hl_location ${HDF5_${_lang}_HL_TARGET}${_suffix} IMPORTED_IMPLIB_${_hdf5_imported_conf} )
+ if (NOT _hdf5_lang_hl_location)
+ get_target_property(_hdf5_lang_hl_location ${HDF5_${_lang}_HL_TARGET}${_suffix} LOCATION_${_hdf5_imported_conf})
+ if (NOT _hdf5_hl_lang_location)
+ get_target_property(_hdf5_hl_lang_location ${HDF5_${_lang}_HL_TARGET}${_suffix} LOCATION)
+ endif()
+ endif()
+ if( _hdf5_lang_hl_location )
+ set(HDF5_${_lang}_HL_LIBRARY ${_hdf5_lang_hl_location})
+ list(APPEND HDF5_HL_LIBRARIES ${HDF5_${_lang}_HL_TARGET}${_suffix})
+ set(HDF5_${_lang}_HL_LIBRARIES ${HDF5_${_lang}_HL_TARGET}${_suffix})
+ set(HDF5_HL_FOUND TRUE)
+ endif()
+ unset(_hdf5_lang_hl_location)
+ endif()
+ unset(_hdf5_imported_conf)
+ unset(_hdf5_lang_location)
+ endforeach()
+ endif()
+endif()
+
+if(NOT HDF5_FOUND)
+ set(_HDF5_NEED_TO_SEARCH FALSE)
+ set(HDF5_COMPILER_NO_INTERROGATE TRUE)
+ # Only search for languages we've enabled
+ foreach(_lang IN LISTS HDF5_LANGUAGE_BINDINGS)
+ # First check to see if our regular compiler is one of wrappers
+ if(_lang STREQUAL "C")
+ _HDF5_test_regular_compiler_C(
+ HDF5_${_lang}_COMPILER_NO_INTERROGATE
+ HDF5_${_lang}_VERSION
+ HDF5_${_lang}_IS_PARALLEL)
+ elseif(_lang STREQUAL "CXX")
+ _HDF5_test_regular_compiler_CXX(
+ HDF5_${_lang}_COMPILER_NO_INTERROGATE
+ HDF5_${_lang}_VERSION
+ HDF5_${_lang}_IS_PARALLEL)
+ elseif(_lang STREQUAL "Fortran")
+ _HDF5_test_regular_compiler_Fortran(
+ HDF5_${_lang}_COMPILER_NO_INTERROGATE
+ HDF5_${_lang}_IS_PARALLEL)
+ else()
+ continue()
+ endif()
+ if(HDF5_${_lang}_COMPILER_NO_INTERROGATE)
+ if(HDF5_FIND_DEBUG)
+ message(STATUS "HDF5: Using hdf5 compiler wrapper for all ${_lang} compiling")
+ endif()
+ set(HDF5_${_lang}_FOUND TRUE)
+ set(HDF5_${_lang}_COMPILER_EXECUTABLE_NO_INTERROGATE
+ "${CMAKE_${_lang}_COMPILER}"
+ CACHE FILEPATH "HDF5 ${_lang} compiler wrapper")
+ set(HDF5_${_lang}_DEFINITIONS)
+ set(HDF5_${_lang}_INCLUDE_DIRS)
+ set(HDF5_${_lang}_LIBRARIES)
+ set(HDF5_${_lang}_HL_LIBRARIES)
+
+ mark_as_advanced(HDF5_${_lang}_COMPILER_EXECUTABLE_NO_INTERROGATE)
+
+ set(HDF5_${_lang}_FOUND TRUE)
+ set(HDF5_HL_FOUND TRUE)
+ else()
+ set(HDF5_COMPILER_NO_INTERROGATE FALSE)
+ # If this language isn't using the wrapper, then try to seed the
+ # search options with the wrapper
+ find_program(HDF5_${_lang}_COMPILER_EXECUTABLE
+ NAMES ${HDF5_${_lang}_COMPILER_NAMES} NAMES_PER_DIR
+ HINTS ${HDF5_ROOT}
+ PATH_SUFFIXES bin Bin
+ DOC "HDF5 ${_lang} Wrapper compiler. Used only to detect HDF5 compile flags."
+ ${_HDF5_SEARCH_OPTS}
+ )
+ mark_as_advanced( HDF5_${_lang}_COMPILER_EXECUTABLE )
+ unset(HDF5_${_lang}_COMPILER_NAMES)
+
+ if(HDF5_${_lang}_COMPILER_EXECUTABLE)
+ _HDF5_invoke_compiler(${_lang} HDF5_${_lang}_COMPILE_LINE
+ HDF5_${_lang}_RETURN_VALUE HDF5_${_lang}_VERSION HDF5_${_lang}_IS_PARALLEL)
+ if(HDF5_${_lang}_RETURN_VALUE EQUAL 0)
+ if(HDF5_FIND_DEBUG)
+ message(STATUS "HDF5: Using hdf5 compiler wrapper to determine ${_lang} configuration")
+ endif()
+ _HDF5_parse_compile_line( HDF5_${_lang}_COMPILE_LINE
+ HDF5_${_lang}_INCLUDE_DIRS
+ HDF5_${_lang}_DEFINITIONS
+ HDF5_${_lang}_LIBRARY_DIRS
+ HDF5_${_lang}_LIBRARY_NAMES
+ HDF5_${_lang}_HL_LIBRARY_NAMES
+ )
+ set(HDF5_${_lang}_LIBRARIES)
+
+ foreach(_lib IN LISTS HDF5_${_lang}_LIBRARY_NAMES)
+ set(_HDF5_SEARCH_NAMES_LOCAL)
+ if("x${_lib}" MATCHES "hdf5")
+ # hdf5 library
+ set(_HDF5_SEARCH_OPTS_LOCAL ${_HDF5_SEARCH_OPTS})
+ if(HDF5_USE_STATIC_LIBRARIES)
+ if(WIN32)
+ set(_HDF5_SEARCH_NAMES_LOCAL lib${_lib})
+ else()
+ set(_HDF5_SEARCH_NAMES_LOCAL lib${_lib}.a)
+ endif()
+ endif()
+ else()
+ # external library
+ set(_HDF5_SEARCH_OPTS_LOCAL)
+ endif()
+ find_library(HDF5_${_lang}_LIBRARY_${_lib}
+ NAMES ${_HDF5_SEARCH_NAMES_LOCAL} ${_lib} NAMES_PER_DIR
+ HINTS ${HDF5_${_lang}_LIBRARY_DIRS}
+ ${HDF5_ROOT}
+ ${_HDF5_SEARCH_OPTS_LOCAL}
+ )
+ unset(_HDF5_SEARCH_OPTS_LOCAL)
+ unset(_HDF5_SEARCH_NAMES_LOCAL)
+ if(HDF5_${_lang}_LIBRARY_${_lib})
+ list(APPEND HDF5_${_lang}_LIBRARIES ${HDF5_${_lang}_LIBRARY_${_lib}})
+ else()
+ list(APPEND HDF5_${_lang}_LIBRARIES ${_lib})
+ endif()
+ endforeach()
+ if(HDF5_FIND_HL)
+ set(HDF5_${_lang}_HL_LIBRARIES)
+ foreach(_lib IN LISTS HDF5_${_lang}_HL_LIBRARY_NAMES)
+ set(_HDF5_SEARCH_NAMES_LOCAL)
+ if("x${_lib}" MATCHES "hdf5")
+ # hdf5 library
+ set(_HDF5_SEARCH_OPTS_LOCAL ${_HDF5_SEARCH_OPTS})
+ if(HDF5_USE_STATIC_LIBRARIES)
+ if(WIN32)
+ set(_HDF5_SEARCH_NAMES_LOCAL lib${_lib})
+ else()
+ set(_HDF5_SEARCH_NAMES_LOCAL lib${_lib}.a)
+ endif()
+ endif()
+ else()
+ # external library
+ set(_HDF5_SEARCH_OPTS_LOCAL)
+ endif()
+ find_library(HDF5_${_lang}_LIBRARY_${_lib}
+ NAMES ${_HDF5_SEARCH_NAMES_LOCAL} ${_lib} NAMES_PER_DIR
+ HINTS ${HDF5_${_lang}_LIBRARY_DIRS}
+ ${HDF5_ROOT}
+ ${_HDF5_SEARCH_OPTS_LOCAL}
+ )
+ unset(_HDF5_SEARCH_OPTS_LOCAL)
+ unset(_HDF5_SEARCH_NAMES_LOCAL)
+ if(HDF5_${_lang}_LIBRARY_${_lib})
+ list(APPEND HDF5_${_lang}_HL_LIBRARIES ${HDF5_${_lang}_LIBRARY_${_lib}})
+ else()
+ list(APPEND HDF5_${_lang}_HL_LIBRARIES ${_lib})
+ endif()
+ endforeach()
+ set(HDF5_HL_FOUND TRUE)
+ endif()
+
+ set(HDF5_${_lang}_FOUND TRUE)
+ list(REMOVE_DUPLICATES HDF5_${_lang}_DEFINITIONS)
+ list(REMOVE_DUPLICATES HDF5_${_lang}_INCLUDE_DIRS)
+ else()
+ set(_HDF5_NEED_TO_SEARCH TRUE)
+ endif()
+ else()
+ set(_HDF5_NEED_TO_SEARCH TRUE)
+ endif()
+ endif()
+ if(HDF5_${_lang}_VERSION)
+ if(NOT HDF5_VERSION)
+ set(HDF5_VERSION ${HDF5_${_lang}_VERSION})
+ elseif(NOT HDF5_VERSION VERSION_EQUAL HDF5_${_lang}_VERSION)
+ message(WARNING "HDF5 Version found for language ${_lang}, ${HDF5_${_lang}_VERSION} is different than previously found version ${HDF5_VERSION}")
+ endif()
+ endif()
+ if(DEFINED HDF5_${_lang}_IS_PARALLEL)
+ if(NOT DEFINED HDF5_IS_PARALLEL)
+ set(HDF5_IS_PARALLEL ${HDF5_${_lang}_IS_PARALLEL})
+ elseif(NOT HDF5_IS_PARALLEL AND HDF5_${_lang}_IS_PARALLEL)
+ message(WARNING "HDF5 found for language ${_lang} is parallel but previously found language is not parallel.")
+ elseif(HDF5_IS_PARALLEL AND NOT HDF5_${_lang}_IS_PARALLEL)
+ message(WARNING "HDF5 found for language ${_lang} is not parallel but previously found language is parallel.")
+ endif()
+ endif()
+ endforeach()
+ unset(_lib)
+else()
+ set(_HDF5_NEED_TO_SEARCH TRUE)
+endif()
+
+if(NOT HDF5_FOUND AND HDF5_COMPILER_NO_INTERROGATE)
+ # No arguments necessary, all languages can use the compiler wrappers
+ set(HDF5_FOUND TRUE)
+ set(HDF5_METHOD "Included by compiler wrappers")
+ set(HDF5_REQUIRED_VARS HDF5_METHOD)
+elseif(NOT HDF5_FOUND AND NOT _HDF5_NEED_TO_SEARCH)
+ # Compiler wrappers aren't being used by the build but were found and used
+ # to determine necessary include and library flags
+ set(HDF5_INCLUDE_DIRS)
+ set(HDF5_LIBRARIES)
+ set(HDF5_HL_LIBRARIES)
+ foreach(_lang IN LISTS HDF5_LANGUAGE_BINDINGS)
+ if(HDF5_${_lang}_FOUND)
+ if(NOT HDF5_${_lang}_COMPILER_NO_INTERROGATE)
+ list(APPEND HDF5_DEFINITIONS ${HDF5_${_lang}_DEFINITIONS})
+ list(APPEND HDF5_INCLUDE_DIRS ${HDF5_${_lang}_INCLUDE_DIRS})
+ list(APPEND HDF5_LIBRARIES ${HDF5_${_lang}_LIBRARIES})
+ if(HDF5_FIND_HL)
+ list(APPEND HDF5_HL_LIBRARIES ${HDF5_${_lang}_HL_LIBRARIES})
+ endif()
+ endif()
+ endif()
+ endforeach()
+ list(REMOVE_DUPLICATES HDF5_DEFINITIONS)
+ list(REMOVE_DUPLICATES HDF5_INCLUDE_DIRS)
+ set(HDF5_FOUND TRUE)
+ set(HDF5_REQUIRED_VARS HDF5_LIBRARIES)
+ if(HDF5_FIND_HL)
+ list(APPEND HDF5_REQUIRED_VARS HDF5_HL_LIBRARIES)
+ endif()
+endif()
+
+find_program( HDF5_DIFF_EXECUTABLE
+ NAMES h5diff
+ HINTS ${HDF5_ROOT}
+ PATH_SUFFIXES bin Bin
+ ${_HDF5_SEARCH_OPTS}
+ DOC "HDF5 file differencing tool." )
+mark_as_advanced( HDF5_DIFF_EXECUTABLE )
+
+if( NOT HDF5_FOUND )
+ # seed the initial lists of libraries to find with items we know we need
+ set(HDF5_C_LIBRARY_NAMES hdf5)
+ set(HDF5_C_HL_LIBRARY_NAMES hdf5_hl ${HDF5_C_LIBRARY_NAMES} )
+
+ set(HDF5_CXX_LIBRARY_NAMES hdf5_cpp ${HDF5_C_LIBRARY_NAMES})
+ set(HDF5_CXX_HL_LIBRARY_NAMES hdf5_hl_cpp ${HDF5_C_HL_LIBRARY_NAMES} ${HDF5_CXX_LIBRARY_NAMES})
+
+ set(HDF5_Fortran_LIBRARY_NAMES hdf5_fortran ${HDF5_C_LIBRARY_NAMES})
+ set(HDF5_Fortran_HL_LIBRARY_NAMES hdf5_hl_fortran hdf5hl_fortran ${HDF5_C_HL_LIBRARY_NAMES} ${HDF5_Fortran_LIBRARY_NAMES})
+
+ # suffixes as seen on Linux, MSYS2, ...
+ set(_lib_suffixes hdf5)
+ if(NOT HDF5_PREFER_PARALLEL)
+ list(APPEND _lib_suffixes hdf5/serial)
+ endif()
+ if(HDF5_USE_STATIC_LIBRARIES)
+ set(_inc_suffixes include/static)
+ else()
+ set(_inc_suffixes include/shared)
+ endif()
+
+ foreach(_lang IN LISTS HDF5_LANGUAGE_BINDINGS)
+ # The "main" library.
+ set(_hdf5_main_library "")
+
+ # find the HDF5 libraries
+ foreach(LIB IN LISTS HDF5_${_lang}_LIBRARY_NAMES)
+ if(HDF5_USE_STATIC_LIBRARIES)
+ # According to bug 1643 on the CMake bug tracker, this is the
+ # preferred method for searching for a static library.
+ # See https://gitlab.kitware.com/cmake/cmake/-/issues/1643. We search
+ # first for the full static library name, but fall back to a
+ # generic search on the name if the static search fails.
+ set( THIS_LIBRARY_SEARCH_DEBUG
+ lib${LIB}d.a lib${LIB}_debug.a lib${LIB}d lib${LIB}_D lib${LIB}_debug
+ lib${LIB}d-static.a lib${LIB}_debug-static.a ${LIB}d-static ${LIB}_D-static ${LIB}_debug-static )
+ set( THIS_LIBRARY_SEARCH_RELEASE lib${LIB}.a lib${LIB} lib${LIB}-static.a ${LIB}-static)
+ else()
+ set( THIS_LIBRARY_SEARCH_DEBUG ${LIB}d ${LIB}_D ${LIB}_debug ${LIB}d-shared ${LIB}_D-shared ${LIB}_debug-shared)
+ set( THIS_LIBRARY_SEARCH_RELEASE ${LIB} ${LIB}-shared)
+ if(WIN32)
+ list(APPEND HDF5_DEFINITIONS "-DH5_BUILT_AS_DYNAMIC_LIB")
+ endif()
+ endif()
+ find_library(HDF5_${LIB}_LIBRARY_DEBUG
+ NAMES ${THIS_LIBRARY_SEARCH_DEBUG}
+ HINTS ${HDF5_ROOT} PATH_SUFFIXES lib Lib ${_lib_suffixes}
+ ${_HDF5_SEARCH_OPTS}
+ )
+ find_library(HDF5_${LIB}_LIBRARY_RELEASE
+ NAMES ${THIS_LIBRARY_SEARCH_RELEASE}
+ HINTS ${HDF5_ROOT} PATH_SUFFIXES lib Lib ${_lib_suffixes}
+ ${_HDF5_SEARCH_OPTS}
+ )
+
+ # Set the "main" library if not already set.
+ if (NOT _hdf5_main_library)
+ if (HDF5_${LIB}_LIBRARY_RELEASE)
+ set(_hdf5_main_library "${HDF5_${LIB}_LIBRARY_RELEASE}")
+ elseif (HDF5_${LIB}_LIBRARY_DEBUG)
+ set(_hdf5_main_library "${HDF5_${LIB}_LIBRARY_DEBUG}")
+ endif ()
+ endif ()
+
+ select_library_configurations( HDF5_${LIB} )
+ list(APPEND HDF5_${_lang}_LIBRARIES ${HDF5_${LIB}_LIBRARY})
+ endforeach()
+ if(HDF5_${_lang}_LIBRARIES)
+ set(HDF5_${_lang}_FOUND TRUE)
+ endif()
+
+ # Append the libraries for this language binding to the list of all
+ # required libraries.
+ list(APPEND HDF5_LIBRARIES ${HDF5_${_lang}_LIBRARIES})
+
+ # find the HDF5 include directories
+ set(_hdf5_inc_extra_paths)
+ set(_hdf5_inc_extra_suffixes)
+ if("${_lang}" STREQUAL "Fortran")
+ set(HDF5_INCLUDE_FILENAME hdf5.mod HDF5.mod)
+
+ # Add library-based search paths for Fortran modules.
+ if (NOT _hdf5_main_library STREQUAL "")
+ # gfortran module directory
+ if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
+ get_filename_component(_hdf5_library_dir "${_hdf5_main_library}" DIRECTORY)
+ list(APPEND _hdf5_inc_extra_paths "${_hdf5_library_dir}")
+ unset(_hdf5_library_dir)
+ list(APPEND _hdf5_inc_extra_suffixes gfortran/modules)
+ endif ()
+ endif ()
+ elseif("${_lang}" STREQUAL "CXX")
+ set(HDF5_INCLUDE_FILENAME H5Cpp.h)
+ else()
+ set(HDF5_INCLUDE_FILENAME hdf5.h)
+ endif()
+
+ unset(_hdf5_main_library)
+
+ find_path(HDF5_${_lang}_INCLUDE_DIR ${HDF5_INCLUDE_FILENAME}
+ HINTS ${HDF5_ROOT}
+ PATHS $ENV{HOME}/.local/include ${_hdf5_inc_extra_paths}
+ PATH_SUFFIXES include Include ${_inc_suffixes} ${_lib_suffixes} ${_hdf5_inc_extra_suffixes}
+ ${_HDF5_SEARCH_OPTS}
+ )
+ mark_as_advanced(HDF5_${_lang}_INCLUDE_DIR)
+ unset(_hdf5_inc_extra_paths)
+ unset(_hdf5_inc_extra_suffixes)
+ # set the _DIRS variable as this is what the user will normally use
+ set(HDF5_${_lang}_INCLUDE_DIRS ${HDF5_${_lang}_INCLUDE_DIR})
+ list(APPEND HDF5_INCLUDE_DIRS ${HDF5_${_lang}_INCLUDE_DIR})
+
+ if(HDF5_FIND_HL)
+ foreach(LIB IN LISTS HDF5_${_lang}_HL_LIBRARY_NAMES)
+ if(HDF5_USE_STATIC_LIBRARIES)
+ # According to bug 1643 on the CMake bug tracker, this is the
+ # preferred method for searching for a static library.
+ # See https://gitlab.kitware.com/cmake/cmake/-/issues/1643. We search
+ # first for the full static library name, but fall back to a
+ # generic search on the name if the static search fails.
+ set( THIS_LIBRARY_SEARCH_DEBUG
+ lib${LIB}d.a lib${LIB}_debug.a lib${LIB}d lib${LIB}_D lib${LIB}_debug
+ lib${LIB}d-static.a lib${LIB}_debug-static.a lib${LIB}d-static lib${LIB}_D-static lib${LIB}_debug-static )
+ set( THIS_LIBRARY_SEARCH_RELEASE lib${LIB}.a lib${LIB} lib${LIB}-static.a lib${LIB}-static)
+ else()
+ set( THIS_LIBRARY_SEARCH_DEBUG ${LIB}d ${LIB}_D ${LIB}_debug ${LIB}d-shared ${LIB}_D-shared ${LIB}_debug-shared)
+ set( THIS_LIBRARY_SEARCH_RELEASE ${LIB} ${LIB}-shared)
+ endif()
+ find_library(HDF5_${LIB}_LIBRARY_DEBUG
+ NAMES ${THIS_LIBRARY_SEARCH_DEBUG}
+ HINTS ${HDF5_ROOT} PATH_SUFFIXES lib Lib ${_lib_suffixes}
+ ${_HDF5_SEARCH_OPTS}
+ )
+ find_library(HDF5_${LIB}_LIBRARY_RELEASE
+ NAMES ${THIS_LIBRARY_SEARCH_RELEASE}
+ HINTS ${HDF5_ROOT} PATH_SUFFIXES lib Lib ${_lib_suffixes}
+ ${_HDF5_SEARCH_OPTS}
+ )
+
+ select_library_configurations( HDF5_${LIB} )
+ list(APPEND HDF5_${_lang}_HL_LIBRARIES ${HDF5_${LIB}_LIBRARY})
+ endforeach()
+
+ # Append the libraries for this language binding to the list of all
+ # required libraries.
+ list(APPEND HDF5_HL_LIBRARIES ${HDF5_${_lang}_HL_LIBRARIES})
+ endif()
+ endforeach()
+ if(HDF5_FIND_HL AND HDF5_HL_LIBRARIES)
+ set(HDF5_HL_FOUND TRUE)
+ endif()
+
+ list(REMOVE_DUPLICATES HDF5_DEFINITIONS)
+ list(REMOVE_DUPLICATES HDF5_INCLUDE_DIRS)
+
+ # If the HDF5 include directory was found, open H5pubconf.h to determine if
+ # HDF5 was compiled with parallel IO support
+ set( HDF5_IS_PARALLEL FALSE )
+ set( HDF5_VERSION "" )
+ foreach( _dir IN LISTS HDF5_INCLUDE_DIRS )
+ foreach(_hdr "${_dir}/H5pubconf.h" "${_dir}/H5pubconf-64.h" "${_dir}/H5pubconf-32.h")
+ if( EXISTS "${_hdr}" )
+ file( STRINGS "${_hdr}"
+ HDF5_HAVE_PARALLEL_DEFINE
+ REGEX "HAVE_PARALLEL 1" )
+ if( HDF5_HAVE_PARALLEL_DEFINE )
+ set( HDF5_IS_PARALLEL TRUE )
+ endif()
+ unset(HDF5_HAVE_PARALLEL_DEFINE)
+
+ file( STRINGS "${_hdr}"
+ HDF5_VERSION_DEFINE
+ REGEX "^[ \t]*#[ \t]*define[ \t]+H5_VERSION[ \t]+" )
+ if( "${HDF5_VERSION_DEFINE}" MATCHES
+ "H5_VERSION[ \t]+\"([0-9]+\\.[0-9]+\\.[0-9]+)(-patch([0-9]+))?\"" )
+ set( HDF5_VERSION "${CMAKE_MATCH_1}" )
+ if( CMAKE_MATCH_3 )
+ set( HDF5_VERSION ${HDF5_VERSION}.${CMAKE_MATCH_3})
+ endif()
+ endif()
+ unset(HDF5_VERSION_DEFINE)
+ endif()
+ endforeach()
+ endforeach()
+ unset(_hdr)
+ unset(_dir)
+ set( HDF5_IS_PARALLEL ${HDF5_IS_PARALLEL} CACHE BOOL
+ "HDF5 library compiled with parallel IO support" )
+ mark_as_advanced( HDF5_IS_PARALLEL )
+
+ set(HDF5_REQUIRED_VARS HDF5_LIBRARIES HDF5_INCLUDE_DIRS)
+ if(HDF5_FIND_HL)
+ list(APPEND HDF5_REQUIRED_VARS HDF5_HL_LIBRARIES)
+ endif()
+endif()
+
+# For backwards compatibility we set HDF5_INCLUDE_DIR to the value of
+# HDF5_INCLUDE_DIRS
+if( HDF5_INCLUDE_DIRS )
+ set( HDF5_INCLUDE_DIR "${HDF5_INCLUDE_DIRS}" )
+endif()
+
+# If HDF5_REQUIRED_VARS is empty at this point, then it's likely that
+# something external is trying to explicitly pass already found
+# locations
+if(NOT HDF5_REQUIRED_VARS)
+ set(HDF5_REQUIRED_VARS HDF5_LIBRARIES HDF5_INCLUDE_DIRS)
+endif()
+
+find_package_handle_standard_args(HDF5
+ REQUIRED_VARS ${HDF5_REQUIRED_VARS}
+ VERSION_VAR HDF5_VERSION
+ HANDLE_COMPONENTS
+)
+
+unset(_HDF5_SEARCH_OPTS)
+
+if( HDF5_FOUND AND NOT HDF5_DIR)
+ # hide HDF5_DIR for the non-advanced user to avoid confusion with
+ # HDF5_DIR-NOT_FOUND while HDF5 was found.
+ mark_as_advanced(HDF5_DIR)
+endif()
+
+if (HDF5_FOUND)
+ if (NOT TARGET HDF5::HDF5)
+ add_library(HDF5::HDF5 INTERFACE IMPORTED)
+ string(REPLACE "-D" "" _hdf5_definitions "${HDF5_DEFINITIONS}")
+ set_target_properties(HDF5::HDF5 PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${HDF5_INCLUDE_DIRS}"
+ INTERFACE_COMPILE_DEFINITIONS "${_hdf5_definitions}")
+ unset(_hdf5_definitions)
+ target_link_libraries(HDF5::HDF5 INTERFACE ${HDF5_LIBRARIES})
+ endif ()
+
+ foreach (hdf5_lang IN LISTS HDF5_LANGUAGE_BINDINGS)
+ if (hdf5_lang STREQUAL "C")
+ set(hdf5_target_name "hdf5")
+ elseif (hdf5_lang STREQUAL "CXX")
+ set(hdf5_target_name "hdf5_cpp")
+ elseif (hdf5_lang STREQUAL "Fortran")
+ set(hdf5_target_name "hdf5_fortran")
+ else ()
+ continue ()
+ endif ()
+
+ if (NOT TARGET "hdf5::${hdf5_target_name}")
+ if (HDF5_COMPILER_NO_INTERROGATE)
+ add_library("hdf5::${hdf5_target_name}" INTERFACE IMPORTED)
+ string(REPLACE "-D" "" _hdf5_definitions "${HDF5_${hdf5_lang}_DEFINITIONS}")
+ set_target_properties("hdf5::${hdf5_target_name}" PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${HDF5_${hdf5_lang}_INCLUDE_DIRS}"
+ INTERFACE_COMPILE_DEFINITIONS "${_hdf5_definitions}")
+ else()
+ if (DEFINED "HDF5_${hdf5_target_name}_LIBRARY")
+ set(_hdf5_location "${HDF5_${hdf5_target_name}_LIBRARY}")
+ elseif (DEFINED "HDF5_${hdf5_lang}_LIBRARY")
+ set(_hdf5_location "${HDF5_${hdf5_lang}_LIBRARY}")
+ elseif (DEFINED "HDF5_${hdf5_lang}_LIBRARY_${hdf5_target_name}")
+ set(_hdf5_location "${HDF5_${hdf5_lang}_LIBRARY_${hdf5_target_name}}")
+ else ()
+ # Error if we still don't have the location.
+ message(SEND_ERROR
+ "HDF5 was found, but a different variable was set which contains "
+ "the location of the `hdf5::${hdf5_target_name}` library.")
+ endif ()
+ add_library("hdf5::${hdf5_target_name}" UNKNOWN IMPORTED)
+ string(REPLACE "-D" "" _hdf5_definitions "${HDF5_${hdf5_lang}_DEFINITIONS}")
+ if (NOT HDF5_${hdf5_lang}_INCLUDE_DIRS)
+ set(HDF5_${hdf5_lang}_INCLUDE_DIRS ${HDF5_INCLUDE_DIRS})
+ endif ()
+ set_target_properties("hdf5::${hdf5_target_name}" PROPERTIES
+ IMPORTED_LOCATION "${_hdf5_location}"
+ IMPORTED_IMPLIB "${_hdf5_location}"
+ INTERFACE_INCLUDE_DIRECTORIES "${HDF5_${hdf5_lang}_INCLUDE_DIRS}"
+ INTERFACE_COMPILE_DEFINITIONS "${_hdf5_definitions}")
+ if (_hdf5_libtype STREQUAL "SHARED")
+ set_property(TARGET "hdf5::${hdf5_target_name}" APPEND
+ PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS H5_BUILT_AS_DYNAMIC_LIB)
+ elseif (_hdf5_libtype STREQUAL "STATIC")
+ set_property(TARGET "hdf5::${hdf5_target_name}" APPEND
+ PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS H5_BUILT_AS_STATIC_LIB)
+ endif ()
+ unset(_hdf5_definitions)
+ unset(_hdf5_libtype)
+ unset(_hdf5_location)
+ endif ()
+ endif ()
+
+ if (NOT HDF5_FIND_HL)
+ continue ()
+ endif ()
+
+ set(hdf5_alt_target_name "")
+ if (hdf5_lang STREQUAL "C")
+ set(hdf5_target_name "hdf5_hl")
+ elseif (hdf5_lang STREQUAL "CXX")
+ set(hdf5_target_name "hdf5_hl_cpp")
+ elseif (hdf5_lang STREQUAL "Fortran")
+ set(hdf5_target_name "hdf5_hl_fortran")
+ set(hdf5_alt_target_name "hdf5hl_fortran")
+ else ()
+ continue ()
+ endif ()
+
+ if (NOT TARGET "hdf5::${hdf5_target_name}")
+ if (HDF5_COMPILER_NO_INTERROGATE)
+ add_library("hdf5::${hdf5_target_name}" INTERFACE IMPORTED)
+ string(REPLACE "-D" "" _hdf5_definitions "${HDF5_${hdf5_lang}_HL_DEFINITIONS}")
+ set_target_properties("hdf5::${hdf5_target_name}" PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${HDF5_${hdf5_lang}_HL_INCLUDE_DIRS}"
+ INTERFACE_COMPILE_DEFINITIONS "${_hdf5_definitions}")
+ else()
+ if (DEFINED "HDF5_${hdf5_target_name}_LIBRARY")
+ set(_hdf5_location "${HDF5_${hdf5_target_name}_LIBRARY}")
+ elseif (DEFINED "HDF5_${hdf5_lang}_HL_LIBRARY")
+ set(_hdf5_location "${HDF5_${hdf5_lang}_HL_LIBRARY}")
+ elseif (DEFINED "HDF5_${hdf5_lang}_LIBRARY_${hdf5_target_name}")
+ set(_hdf5_location "${HDF5_${hdf5_lang}_LIBRARY_${hdf5_target_name}}")
+ elseif (hdf5_alt_target_name AND DEFINED "HDF5_${hdf5_lang}_LIBRARY_${hdf5_alt_target_name}")
+ set(_hdf5_location "${HDF5_${hdf5_lang}_LIBRARY_${hdf5_alt_target_name}}")
+ else ()
+ # Error if we still don't have the location.
+ message(SEND_ERROR
+ "HDF5 was found, but a different variable was set which contains "
+ "the location of the `hdf5::${hdf5_target_name}` library.")
+ endif ()
+ add_library("hdf5::${hdf5_target_name}" UNKNOWN IMPORTED)
+ string(REPLACE "-D" "" _hdf5_definitions "${HDF5_${hdf5_lang}_HL_DEFINITIONS}")
+ set_target_properties("hdf5::${hdf5_target_name}" PROPERTIES
+ IMPORTED_LOCATION "${_hdf5_location}"
+ IMPORTED_IMPLIB "${_hdf5_location}"
+ INTERFACE_INCLUDE_DIRECTORIES "${HDF5_${hdf5_lang}_HL_INCLUDE_DIRS}"
+ INTERFACE_COMPILE_DEFINITIONS "${_hdf5_definitions}")
+ if (_hdf5_libtype STREQUAL "SHARED")
+ set_property(TARGET "hdf5::${hdf5_target_name}" APPEND
+ PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS H5_BUILT_AS_DYNAMIC_LIB)
+ elseif (_hdf5_libtype STREQUAL "STATIC")
+ set_property(TARGET "hdf5::${hdf5_target_name}" APPEND
+ PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS H5_BUILT_AS_STATIC_LIB)
+ endif ()
+ unset(_hdf5_definitions)
+ unset(_hdf5_libtype)
+ unset(_hdf5_location)
+ endif ()
+ endif ()
+ endforeach ()
+ unset(hdf5_lang)
+
+ if (HDF5_DIFF_EXECUTABLE AND NOT TARGET hdf5::h5diff)
+ add_executable(hdf5::h5diff IMPORTED)
+ set_target_properties(hdf5::h5diff PROPERTIES
+ IMPORTED_LOCATION "${HDF5_DIFF_EXECUTABLE}")
+ endif ()
+endif ()
+
+if (HDF5_FIND_DEBUG)
+ message(STATUS "HDF5_DIR: ${HDF5_DIR}")
+ message(STATUS "HDF5_DEFINITIONS: ${HDF5_DEFINITIONS}")
+ message(STATUS "HDF5_INCLUDE_DIRS: ${HDF5_INCLUDE_DIRS}")
+ message(STATUS "HDF5_LIBRARIES: ${HDF5_LIBRARIES}")
+ message(STATUS "HDF5_HL_LIBRARIES: ${HDF5_HL_LIBRARIES}")
+ foreach(_lang IN LISTS HDF5_LANGUAGE_BINDINGS)
+ message(STATUS "HDF5_${_lang}_DEFINITIONS: ${HDF5_${_lang}_DEFINITIONS}")
+ message(STATUS "HDF5_${_lang}_INCLUDE_DIR: ${HDF5_${_lang}_INCLUDE_DIR}")
+ message(STATUS "HDF5_${_lang}_INCLUDE_DIRS: ${HDF5_${_lang}_INCLUDE_DIRS}")
+ message(STATUS "HDF5_${_lang}_LIBRARY: ${HDF5_${_lang}_LIBRARY}")
+ message(STATUS "HDF5_${_lang}_LIBRARIES: ${HDF5_${_lang}_LIBRARIES}")
+ message(STATUS "HDF5_${_lang}_HL_LIBRARY: ${HDF5_${_lang}_HL_LIBRARY}")
+ message(STATUS "HDF5_${_lang}_HL_LIBRARIES: ${HDF5_${_lang}_HL_LIBRARIES}")
+ endforeach()
+ message(STATUS "Defined targets (if any):")
+ foreach(_lang IN ITEMS "" "_cpp" "_fortran")
+ foreach(_hl IN ITEMS "" "_hl")
+ foreach(_prefix IN ITEMS "hdf5::" "")
+ foreach(_suffix IN ITEMS "-static" "-shared" "")
+ set (_target ${_prefix}hdf5${_hl}${_lang}${_suffix})
+ if (TARGET ${_target})
+ message(STATUS "... ${_target}")
+ else()
+ #message(STATUS "... ${_target} does not exist")
+ endif()
+ endforeach()
+ endforeach()
+ endforeach()
+ endforeach()
+endif()
+unset(_lang)
+unset(_HDF5_NEED_TO_SEARCH)
diff --git a/Modules/FindHSPELL.cmake b/Modules/FindHSPELL.cmake
new file mode 100644
index 0000000..9724d2c
--- /dev/null
+++ b/Modules/FindHSPELL.cmake
@@ -0,0 +1,45 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindHSPELL
+----------
+
+Try to find Hebrew spell-checker (Hspell) and morphology engine.
+
+Once done this will define
+
+::
+
+ HSPELL_FOUND - system has Hspell
+ HSPELL_INCLUDE_DIR - the Hspell include directory
+ HSPELL_LIBRARIES - The libraries needed to use Hspell
+ HSPELL_DEFINITIONS - Compiler switches required for using Hspell
+
+
+
+::
+
+ HSPELL_VERSION_STRING - The version of Hspell found (x.y)
+ HSPELL_MAJOR_VERSION - the major version of Hspell
+ HSPELL_MINOR_VERSION - The minor version of Hspell
+#]=======================================================================]
+
+find_path(HSPELL_INCLUDE_DIR hspell.h)
+
+find_library(HSPELL_LIBRARIES NAMES hspell)
+
+if (HSPELL_INCLUDE_DIR)
+ file(STRINGS "${HSPELL_INCLUDE_DIR}/hspell.h" HSPELL_H REGEX "#define HSPELL_VERSION_M(AJO|INO)R [0-9]+")
+ string(REGEX REPLACE ".*#define HSPELL_VERSION_MAJOR ([0-9]+).*" "\\1" HSPELL_VERSION_MAJOR "${HSPELL_H}")
+ string(REGEX REPLACE ".*#define HSPELL_VERSION_MINOR ([0-9]+).*" "\\1" HSPELL_VERSION_MINOR "${HSPELL_H}")
+ set(HSPELL_VERSION_STRING "${HSPELL_VERSION_MAJOR}.${HSPELL_VERSION_MINOR}")
+ unset(HSPELL_H)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(HSPELL
+ REQUIRED_VARS HSPELL_LIBRARIES HSPELL_INCLUDE_DIR
+ VERSION_VAR HSPELL_VERSION_STRING)
+
+mark_as_advanced(HSPELL_INCLUDE_DIR HSPELL_LIBRARIES)
diff --git a/Modules/FindHTMLHelp.cmake b/Modules/FindHTMLHelp.cmake
new file mode 100644
index 0000000..a11ad4d
--- /dev/null
+++ b/Modules/FindHTMLHelp.cmake
@@ -0,0 +1,52 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindHTMLHelp
+------------
+
+This module looks for Microsoft HTML Help Compiler
+
+It defines:
+
+::
+
+ HTML_HELP_COMPILER : full path to the Compiler (hhc.exe)
+ HTML_HELP_INCLUDE_PATH : include path to the API (htmlhelp.h)
+ HTML_HELP_LIBRARY : full path to the library (htmlhelp.lib)
+#]=======================================================================]
+
+if(WIN32)
+
+ find_program(HTML_HELP_COMPILER
+ NAMES hhc
+ PATHS
+ "[HKEY_CURRENT_USER\\Software\\Microsoft\\HTML Help Workshop;InstallDir]"
+ PATH_SUFFIXES "HTML Help Workshop"
+ )
+
+ get_filename_component(HTML_HELP_COMPILER_PATH "${HTML_HELP_COMPILER}" PATH)
+
+ find_path(HTML_HELP_INCLUDE_PATH
+ NAMES htmlhelp.h
+ PATHS
+ "${HTML_HELP_COMPILER_PATH}/include"
+ "[HKEY_CURRENT_USER\\Software\\Microsoft\\HTML Help Workshop;InstallDir]/include"
+ PATH_SUFFIXES "HTML Help Workshop/include"
+ )
+
+ find_library(HTML_HELP_LIBRARY
+ NAMES htmlhelp
+ PATHS
+ "${HTML_HELP_COMPILER_PATH}/lib"
+ "[HKEY_CURRENT_USER\\Software\\Microsoft\\HTML Help Workshop;InstallDir]/lib"
+ PATH_SUFFIXES "HTML Help Workshop/lib"
+ )
+
+ mark_as_advanced(
+ HTML_HELP_COMPILER
+ HTML_HELP_INCLUDE_PATH
+ HTML_HELP_LIBRARY
+ )
+
+endif()
diff --git a/Modules/FindHg.cmake b/Modules/FindHg.cmake
new file mode 100644
index 0000000..e9f2c82
--- /dev/null
+++ b/Modules/FindHg.cmake
@@ -0,0 +1,98 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindHg
+------
+
+Extract information from a mercurial working copy.
+
+The module defines the following variables:
+
+::
+
+ HG_EXECUTABLE - path to mercurial command line client (hg)
+ HG_FOUND - true if the command line client was found
+ HG_VERSION_STRING - the version of mercurial found
+
+.. versionadded:: 3.1
+ If the command line client executable is found the following macro is defined:
+
+::
+
+ HG_WC_INFO(<dir> <var-prefix>)
+
+Hg_WC_INFO extracts information of a mercurial working copy
+at a given location. This macro defines the following variables:
+
+::
+
+ <var-prefix>_WC_CHANGESET - current changeset
+ <var-prefix>_WC_REVISION - current revision
+
+Example usage:
+
+::
+
+ find_package(Hg)
+ if(HG_FOUND)
+ message("hg found: ${HG_EXECUTABLE}")
+ HG_WC_INFO(${PROJECT_SOURCE_DIR} Project)
+ message("Current revision is ${Project_WC_REVISION}")
+ message("Current changeset is ${Project_WC_CHANGESET}")
+ endif()
+#]=======================================================================]
+
+find_program(HG_EXECUTABLE
+ NAMES hg
+ PATHS
+ [HKEY_LOCAL_MACHINE\\Software\\TortoiseHG]
+ PATH_SUFFIXES Mercurial
+ DOC "hg command line client"
+ )
+mark_as_advanced(HG_EXECUTABLE)
+
+if(HG_EXECUTABLE)
+ set(_saved_lc_all "$ENV{LC_ALL}")
+ set(ENV{LC_ALL} "C")
+
+ set(_saved_language "$ENV{LANGUAGE}")
+ set(ENV{LANGUAGE})
+
+ execute_process(COMMAND ${HG_EXECUTABLE} --version
+ OUTPUT_VARIABLE hg_version
+ ERROR_QUIET
+ RESULT_VARIABLE hg_result
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ set(ENV{LC_ALL} ${_saved_lc_all})
+ set(ENV{LANGUAGE} ${_saved_language})
+
+ if(hg_result MATCHES "is not a valid Win32 application")
+ set_property(CACHE HG_EXECUTABLE PROPERTY VALUE "HG_EXECUTABLE-NOTFOUND")
+ endif()
+ if(hg_version MATCHES "^Mercurial Distributed SCM \\(version ([0-9][^)]*)\\)")
+ set(HG_VERSION_STRING "${CMAKE_MATCH_1}")
+ endif()
+ unset(hg_version)
+
+ macro(HG_WC_INFO dir prefix)
+ execute_process(COMMAND ${HG_EXECUTABLE} id -i -n
+ WORKING_DIRECTORY ${dir}
+ RESULT_VARIABLE hg_id_result
+ ERROR_VARIABLE hg_id_error
+ OUTPUT_VARIABLE ${prefix}_WC_DATA
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(NOT ${hg_id_result} EQUAL 0)
+ message(SEND_ERROR "Command \"${HG_EXECUTBALE} id -n\" in directory ${dir} failed with output:\n${hg_id_error}")
+ endif()
+
+ string(REGEX REPLACE "([0-9a-f]+)\\+? [0-9]+\\+?" "\\1" ${prefix}_WC_CHANGESET ${${prefix}_WC_DATA})
+ string(REGEX REPLACE "[0-9a-f]+\\+? ([0-9]+)\\+?" "\\1" ${prefix}_WC_REVISION ${${prefix}_WC_DATA})
+ endmacro(HG_WC_INFO)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(Hg
+ REQUIRED_VARS HG_EXECUTABLE
+ VERSION_VAR HG_VERSION_STRING)
diff --git a/Modules/FindICU.cmake b/Modules/FindICU.cmake
new file mode 100644
index 0000000..2bb49ad
--- /dev/null
+++ b/Modules/FindICU.cmake
@@ -0,0 +1,438 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindICU
+-------
+
+.. versionadded:: 3.7
+
+Find the International Components for Unicode (ICU) libraries and
+programs.
+
+This module supports multiple components.
+Components can include any of: ``data``, ``i18n``, ``io``, ``le``,
+``lx``, ``test``, ``tu`` and ``uc``.
+
+Note that on Windows ``data`` is named ``dt`` and ``i18n`` is named
+``in``; any of the names may be used, and the appropriate
+platform-specific library name will be automatically selected.
+
+.. versionadded:: 3.11
+ Added support for static libraries on Windows.
+
+This module reports information about the ICU installation in
+several variables. General variables::
+
+ ICU_VERSION - ICU release version
+ ICU_FOUND - true if the main programs and libraries were found
+ ICU_LIBRARIES - component libraries to be linked
+ ICU_INCLUDE_DIRS - the directories containing the ICU headers
+
+Imported targets::
+
+ ICU::<C>
+
+Where ``<C>`` is the name of an ICU component, for example
+``ICU::i18n``; ``<C>`` is lower-case.
+
+ICU programs are reported in::
+
+ ICU_GENCNVAL_EXECUTABLE - path to gencnval executable
+ ICU_ICUINFO_EXECUTABLE - path to icuinfo executable
+ ICU_GENBRK_EXECUTABLE - path to genbrk executable
+ ICU_ICU-CONFIG_EXECUTABLE - path to icu-config executable
+ ICU_GENRB_EXECUTABLE - path to genrb executable
+ ICU_GENDICT_EXECUTABLE - path to gendict executable
+ ICU_DERB_EXECUTABLE - path to derb executable
+ ICU_PKGDATA_EXECUTABLE - path to pkgdata executable
+ ICU_UCONV_EXECUTABLE - path to uconv executable
+ ICU_GENCFU_EXECUTABLE - path to gencfu executable
+ ICU_MAKECONV_EXECUTABLE - path to makeconv executable
+ ICU_GENNORM2_EXECUTABLE - path to gennorm2 executable
+ ICU_GENCCODE_EXECUTABLE - path to genccode executable
+ ICU_GENSPREP_EXECUTABLE - path to gensprep executable
+ ICU_ICUPKG_EXECUTABLE - path to icupkg executable
+ ICU_GENCMN_EXECUTABLE - path to gencmn executable
+
+ICU component libraries are reported in::
+
+ ICU_<C>_FOUND - ON if component was found; ``<C>`` is upper-case.
+ ICU_<C>_LIBRARIES - libraries for component; ``<C>`` is upper-case.
+
+ICU datafiles are reported in::
+
+ ICU_MAKEFILE_INC - Makefile.inc
+ ICU_PKGDATA_INC - pkgdata.inc
+
+This module reads hints about search results from::
+
+ ICU_ROOT - the root of the ICU installation
+
+The environment variable ``ICU_ROOT`` may also be used; the
+ICU_ROOT variable takes precedence.
+
+The following cache variables may also be set::
+
+ ICU_<P>_EXECUTABLE - the path to executable <P>; ``<P>`` is upper-case.
+ ICU_INCLUDE_DIR - the directory containing the ICU headers
+ ICU_<C>_LIBRARY - the library for component <C>; ``<C>`` is upper-case.
+
+.. note::
+
+ In most cases none of the above variables will require setting,
+ unless multiple ICU versions are available and a specific version
+ is required.
+
+Other variables one may set to control this module are::
+
+ ICU_DEBUG - Set to ON to enable debug output from FindICU.
+#]=======================================================================]
+
+# Written by Roger Leigh <rleigh@codelibre.net>
+
+set(icu_programs
+ gencnval
+ icuinfo
+ genbrk
+ icu-config
+ genrb
+ gendict
+ derb
+ pkgdata
+ uconv
+ gencfu
+ makeconv
+ gennorm2
+ genccode
+ gensprep
+ icupkg
+ gencmn)
+
+set(icu_data
+ Makefile.inc
+ pkgdata.inc)
+
+# The ICU checks are contained in a function due to the large number
+# of temporary variables needed.
+function(_ICU_FIND)
+ # Set up search paths, taking compiler into account. Search ICU_ROOT,
+ # with ICU_ROOT in the environment as a fallback if unset.
+ if(ICU_ROOT)
+ list(APPEND icu_roots "${ICU_ROOT}")
+ else()
+ if(NOT "$ENV{ICU_ROOT}" STREQUAL "")
+ file(TO_CMAKE_PATH "$ENV{ICU_ROOT}" NATIVE_PATH)
+ list(APPEND icu_roots "${NATIVE_PATH}")
+ set(ICU_ROOT "${NATIVE_PATH}"
+ CACHE PATH "Location of the ICU installation" FORCE)
+ endif()
+ endif()
+
+ # Find include directory
+ list(APPEND icu_include_suffixes "include")
+ find_path(ICU_INCLUDE_DIR
+ NAMES "unicode/utypes.h"
+ HINTS ${icu_roots}
+ PATH_SUFFIXES ${icu_include_suffixes}
+ DOC "ICU include directory")
+ set(ICU_INCLUDE_DIR "${ICU_INCLUDE_DIR}" PARENT_SCOPE)
+
+ # Get version
+ if(ICU_INCLUDE_DIR AND EXISTS "${ICU_INCLUDE_DIR}/unicode/uvernum.h")
+ file(STRINGS "${ICU_INCLUDE_DIR}/unicode/uvernum.h" icu_header_str
+ REGEX "^#define[\t ]+U_ICU_VERSION[\t ]+\".*\".*")
+
+ string(REGEX REPLACE "^#define[\t ]+U_ICU_VERSION[\t ]+\"([^ \\n]*)\".*"
+ "\\1" icu_version_string "${icu_header_str}")
+ set(ICU_VERSION "${icu_version_string}")
+ set(ICU_VERSION "${icu_version_string}" PARENT_SCOPE)
+ unset(icu_header_str)
+ unset(icu_version_string)
+ endif()
+
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ # 64-bit binary directory
+ set(_bin64 "bin64")
+ # 64-bit library directory
+ set(_lib64 "lib64")
+ endif()
+
+
+ # Find all ICU programs
+ list(APPEND icu_binary_suffixes "${_bin64}" "bin" "sbin")
+ foreach(program ${icu_programs})
+ string(TOUPPER "${program}" program_upcase)
+ set(cache_var "ICU_${program_upcase}_EXECUTABLE")
+ set(program_var "ICU_${program_upcase}_EXECUTABLE")
+ find_program("${cache_var}"
+ NAMES "${program}"
+ HINTS ${icu_roots}
+ PATH_SUFFIXES ${icu_binary_suffixes}
+ DOC "ICU ${program} executable"
+ NO_PACKAGE_ROOT_PATH
+ )
+ mark_as_advanced(cache_var)
+ set("${program_var}" "${${cache_var}}" PARENT_SCOPE)
+ endforeach()
+
+ # Find all ICU libraries
+ list(APPEND icu_library_suffixes "${_lib64}" "lib")
+ set(ICU_REQUIRED_LIBS_FOUND ON)
+ set(static_prefix )
+ # static icu libraries compiled with MSVC have the prefix 's'
+ if(MSVC)
+ set(static_prefix "s")
+ endif()
+ foreach(component ${ICU_FIND_COMPONENTS})
+ string(TOUPPER "${component}" component_upcase)
+ set(component_cache "ICU_${component_upcase}_LIBRARY")
+ set(component_cache_release "${component_cache}_RELEASE")
+ set(component_cache_debug "${component_cache}_DEBUG")
+ set(component_found "ICU_${component_upcase}_FOUND")
+ set(component_found_compat "${component_upcase}_FOUND")
+ set(component_libnames "icu${component}")
+ set(component_debug_libnames "icu${component}d")
+
+ # Special case deliberate library naming mismatches between Unix
+ # and Windows builds
+ unset(component_libnames)
+ unset(component_debug_libnames)
+ list(APPEND component_libnames "icu${component}")
+ list(APPEND component_debug_libnames "icu${component}d")
+ if(component STREQUAL "data")
+ list(APPEND component_libnames "icudt")
+ # Note there is no debug variant at present
+ list(APPEND component_debug_libnames "icudtd")
+ endif()
+ if(component STREQUAL "dt")
+ list(APPEND component_libnames "icudata")
+ # Note there is no debug variant at present
+ list(APPEND component_debug_libnames "icudatad")
+ endif()
+ if(component STREQUAL "i18n")
+ list(APPEND component_libnames "icuin")
+ list(APPEND component_debug_libnames "icuind")
+ endif()
+ if(component STREQUAL "in")
+ list(APPEND component_libnames "icui18n")
+ list(APPEND component_debug_libnames "icui18nd")
+ endif()
+
+ if(static_prefix)
+ unset(static_component_libnames)
+ unset(static_component_debug_libnames)
+ foreach(component_libname ${component_libnames})
+ list(APPEND static_component_libnames
+ ${static_prefix}${component_libname})
+ endforeach()
+ foreach(component_libname ${component_debug_libnames})
+ list(APPEND static_component_debug_libnames
+ ${static_prefix}${component_libname})
+ endforeach()
+ list(APPEND component_libnames ${static_component_libnames})
+ list(APPEND component_debug_libnames ${static_component_debug_libnames})
+ endif()
+ find_library("${component_cache_release}"
+ NAMES ${component_libnames}
+ HINTS ${icu_roots}
+ PATH_SUFFIXES ${icu_library_suffixes}
+ DOC "ICU ${component} library (release)"
+ NO_PACKAGE_ROOT_PATH
+ )
+ find_library("${component_cache_debug}"
+ NAMES ${component_debug_libnames}
+ HINTS ${icu_roots}
+ PATH_SUFFIXES ${icu_library_suffixes}
+ DOC "ICU ${component} library (debug)"
+ NO_PACKAGE_ROOT_PATH
+ )
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(ICU_${component_upcase})
+ mark_as_advanced("${component_cache_release}" "${component_cache_debug}")
+ if(${component_cache})
+ set("${component_found}" ON)
+ set("${component_found_compat}" ON)
+ list(APPEND ICU_LIBRARY "${${component_cache}}")
+ endif()
+ mark_as_advanced("${component_found}")
+ mark_as_advanced("${component_found_compat}")
+ set("${component_cache}" "${${component_cache}}" PARENT_SCOPE)
+ set("${component_found}" "${${component_found}}" PARENT_SCOPE)
+ set("${component_found_compat}" "${${component_found_compat}}" PARENT_SCOPE)
+ if(component_found OR component_found_compat)
+ if (ICU_FIND_REQUIRED_${component})
+ list(APPEND ICU_LIBS_FOUND "${component} (required)")
+ else()
+ list(APPEND ICU_LIBS_FOUND "${component} (optional)")
+ endif()
+ else()
+ if (ICU_FIND_REQUIRED_${component})
+ set(ICU_REQUIRED_LIBS_FOUND OFF)
+ list(APPEND ICU_LIBS_NOTFOUND "${component} (required)")
+ else()
+ list(APPEND ICU_LIBS_NOTFOUND "${component} (optional)")
+ endif()
+ endif()
+ endforeach()
+ set(_ICU_REQUIRED_LIBS_FOUND "${ICU_REQUIRED_LIBS_FOUND}" PARENT_SCOPE)
+ set(ICU_LIBRARY "${ICU_LIBRARY}" PARENT_SCOPE)
+
+ # Find all ICU data files
+ if(CMAKE_LIBRARY_ARCHITECTURE)
+ list(APPEND icu_data_suffixes
+ "${_lib64}/${CMAKE_LIBRARY_ARCHITECTURE}/icu/${ICU_VERSION}"
+ "lib/${CMAKE_LIBRARY_ARCHITECTURE}/icu/${ICU_VERSION}"
+ "${_lib64}/${CMAKE_LIBRARY_ARCHITECTURE}/icu"
+ "lib/${CMAKE_LIBRARY_ARCHITECTURE}/icu")
+ endif()
+ list(APPEND icu_data_suffixes
+ "${_lib64}/icu/${ICU_VERSION}"
+ "lib/icu/${ICU_VERSION}"
+ "${_lib64}/icu"
+ "lib/icu")
+ foreach(data ${icu_data})
+ string(TOUPPER "${data}" data_upcase)
+ string(REPLACE "." "_" data_upcase "${data_upcase}")
+ set(cache_var "ICU_${data_upcase}")
+ set(data_var "ICU_${data_upcase}")
+ find_file("${cache_var}"
+ NAMES "${data}"
+ HINTS ${icu_roots}
+ PATH_SUFFIXES ${icu_data_suffixes}
+ DOC "ICU ${data} data file")
+ mark_as_advanced(cache_var)
+ set("${data_var}" "${${cache_var}}" PARENT_SCOPE)
+ endforeach()
+
+ if(NOT ICU_FIND_QUIETLY)
+ if(ICU_LIBS_FOUND)
+ message(STATUS "Found the following ICU libraries:")
+ foreach(found ${ICU_LIBS_FOUND})
+ message(STATUS " ${found}")
+ endforeach()
+ endif()
+ if(ICU_LIBS_NOTFOUND)
+ message(STATUS "The following ICU libraries were not found:")
+ foreach(notfound ${ICU_LIBS_NOTFOUND})
+ message(STATUS " ${notfound}")
+ endforeach()
+ endif()
+ endif()
+
+ if(ICU_DEBUG)
+ message(STATUS "--------FindICU.cmake search debug--------")
+ message(STATUS "ICU binary path search order: ${icu_roots}")
+ message(STATUS "ICU include path search order: ${icu_roots}")
+ message(STATUS "ICU library path search order: ${icu_roots}")
+ message(STATUS "----------------")
+ endif()
+endfunction()
+
+_ICU_FIND()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(ICU
+ FOUND_VAR ICU_FOUND
+ REQUIRED_VARS ICU_INCLUDE_DIR
+ ICU_LIBRARY
+ _ICU_REQUIRED_LIBS_FOUND
+ VERSION_VAR ICU_VERSION
+ FAIL_MESSAGE "Failed to find all ICU components")
+
+unset(_ICU_REQUIRED_LIBS_FOUND)
+
+if(ICU_FOUND)
+ set(ICU_INCLUDE_DIRS "${ICU_INCLUDE_DIR}")
+ set(ICU_LIBRARIES "${ICU_LIBRARY}")
+ foreach(_ICU_component ${ICU_FIND_COMPONENTS})
+ string(TOUPPER "${_ICU_component}" _ICU_component_upcase)
+ set(_ICU_component_cache "ICU_${_ICU_component_upcase}_LIBRARY")
+ set(_ICU_component_cache_release "ICU_${_ICU_component_upcase}_LIBRARY_RELEASE")
+ set(_ICU_component_cache_debug "ICU_${_ICU_component_upcase}_LIBRARY_DEBUG")
+ set(_ICU_component_lib "ICU_${_ICU_component_upcase}_LIBRARIES")
+ set(_ICU_component_found "ICU_${_ICU_component_upcase}_FOUND")
+ set(_ICU_imported_target "ICU::${_ICU_component}")
+ if(${_ICU_component_found})
+ set("${_ICU_component_lib}" "${${_ICU_component_cache}}")
+ if(NOT TARGET ${_ICU_imported_target})
+ add_library(${_ICU_imported_target} UNKNOWN IMPORTED)
+ if(ICU_INCLUDE_DIR)
+ set_target_properties(${_ICU_imported_target} PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${ICU_INCLUDE_DIR}")
+ endif()
+ if(EXISTS "${${_ICU_component_cache}}")
+ set_target_properties(${_ICU_imported_target} PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
+ IMPORTED_LOCATION "${${_ICU_component_cache}}")
+ endif()
+ if(EXISTS "${${_ICU_component_cache_release}}")
+ set_property(TARGET ${_ICU_imported_target} APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(${_ICU_imported_target} PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
+ IMPORTED_LOCATION_RELEASE "${${_ICU_component_cache_release}}")
+ endif()
+ if(EXISTS "${${_ICU_component_cache_debug}}")
+ set_property(TARGET ${_ICU_imported_target} APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(${_ICU_imported_target} PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
+ IMPORTED_LOCATION_DEBUG "${${_ICU_component_cache_debug}}")
+ endif()
+ if(CMAKE_DL_LIBS AND _ICU_component STREQUAL "uc")
+ set_target_properties(${_ICU_imported_target} PROPERTIES
+ INTERFACE_LINK_LIBRARIES "${CMAKE_DL_LIBS}")
+ endif()
+ endif()
+ endif()
+ unset(_ICU_component_upcase)
+ unset(_ICU_component_cache)
+ unset(_ICU_component_lib)
+ unset(_ICU_component_found)
+ unset(_ICU_imported_target)
+ endforeach()
+endif()
+
+if(ICU_DEBUG)
+ message(STATUS "--------FindICU.cmake results debug--------")
+ message(STATUS "ICU found: ${ICU_FOUND}")
+ message(STATUS "ICU_VERSION number: ${ICU_VERSION}")
+ message(STATUS "ICU_ROOT directory: ${ICU_ROOT}")
+ message(STATUS "ICU_INCLUDE_DIR directory: ${ICU_INCLUDE_DIR}")
+ message(STATUS "ICU_LIBRARIES: ${ICU_LIBRARIES}")
+
+ foreach(program IN LISTS icu_programs)
+ string(TOUPPER "${program}" program_upcase)
+ set(program_lib "ICU_${program_upcase}_EXECUTABLE")
+ message(STATUS "${program} program: ${program_lib}=${${program_lib}}")
+ unset(program_upcase)
+ unset(program_lib)
+ endforeach()
+
+ foreach(data IN LISTS icu_data)
+ string(TOUPPER "${data}" data_upcase)
+ string(REPLACE "." "_" data_upcase "${data_upcase}")
+ set(data_lib "ICU_${data_upcase}")
+ message(STATUS "${data} data: ${data_lib}=${${data_lib}}")
+ unset(data_upcase)
+ unset(data_lib)
+ endforeach()
+
+ foreach(component IN LISTS ICU_FIND_COMPONENTS)
+ string(TOUPPER "${component}" component_upcase)
+ set(component_lib "ICU_${component_upcase}_LIBRARIES")
+ set(component_found "ICU_${component_upcase}_FOUND")
+ set(component_found_compat "${component_upcase}_FOUND")
+ message(STATUS "${component} library found: ${component_found}=${${component_found}}")
+ message(STATUS "${component} library found (compat name): ${component_found_compat}=${${component_found_compat}}")
+ message(STATUS "${component} library: ${component_lib}=${${component_lib}}")
+ unset(component_upcase)
+ unset(component_lib)
+ unset(component_found)
+ unset(component_found_compat)
+ endforeach()
+ message(STATUS "----------------")
+endif()
+
+unset(icu_programs)
diff --git a/Modules/FindIce.cmake b/Modules/FindIce.cmake
new file mode 100644
index 0000000..543e10c
--- /dev/null
+++ b/Modules/FindIce.cmake
@@ -0,0 +1,633 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindIce
+-------
+
+.. versionadded:: 3.1
+
+Find the ZeroC Internet Communication Engine (ICE) programs,
+libraries and datafiles.
+
+This module supports multiple components.
+Components can include any of: ``Freeze``, ``Glacier2``, ``Ice``,
+``IceBox``, ``IceDB``, ``IceDiscovery``, ``IceGrid``,
+``IceLocatorDiscovery``, ``IcePatch``, ``IceSSL``, ``IceStorm``,
+``IceUtil``, ``IceXML``, or ``Slice``.
+
+Ice 3.7 and later also include C++11-specific components:
+``Glacier2++11``, ``Ice++11``, ``IceBox++11``, ``IceDiscovery++11``
+``IceGrid``, ``IceLocatorDiscovery++11``, ``IceSSL++11``,
+``IceStorm++11``
+
+Note that the set of supported components is Ice version-specific.
+
+.. versionadded:: 3.4
+ Imported targets for components and most ``EXECUTABLE`` variables.
+
+.. versionadded:: 3.7
+ Debug and Release variants are found separately.
+
+.. versionadded:: 3.10
+ Ice 3.7 support, including new components, programs and the Nuget package.
+
+This module reports information about the Ice installation in
+several variables. General variables::
+
+ Ice_VERSION - Ice release version
+ Ice_FOUND - true if the main programs and libraries were found
+ Ice_LIBRARIES - component libraries to be linked
+ Ice_INCLUDE_DIRS - the directories containing the Ice headers
+ Ice_SLICE_DIRS - the directories containing the Ice slice interface
+ definitions
+
+Imported targets::
+
+ Ice::<C>
+
+Where ``<C>`` is the name of an Ice component, for example
+``Ice::Glacier2`` or ``Ice++11``.
+
+Ice slice programs are reported in::
+
+ Ice_SLICE2CONFLUENCE_EXECUTABLE - path to slice2confluence executable
+ Ice_SLICE2CPP_EXECUTABLE - path to slice2cpp executable
+ Ice_SLICE2CS_EXECUTABLE - path to slice2cs executable
+ Ice_SLICE2FREEZEJ_EXECUTABLE - path to slice2freezej executable
+ Ice_SLICE2FREEZE_EXECUTABLE - path to slice2freeze executable
+ Ice_SLICE2HTML_EXECUTABLE - path to slice2html executable
+ Ice_SLICE2JAVA_EXECUTABLE - path to slice2java executable
+ Ice_SLICE2JS_EXECUTABLE - path to slice2js executable
+ Ice_SLICE2MATLAB_EXECUTABLE - path to slice2matlab executable
+ Ice_SLICE2OBJC_EXECUTABLE - path to slice2objc executable
+ Ice_SLICE2PHP_EXECUTABLE - path to slice2php executable
+ Ice_SLICE2PY_EXECUTABLE - path to slice2py executable
+ Ice_SLICE2RB_EXECUTABLE - path to slice2rb executable
+
+.. versionadded:: 3.14
+ Variables for ``slice2confluence`` and ``slice2matlab``.
+
+Ice programs are reported in::
+
+ Ice_GLACIER2ROUTER_EXECUTABLE - path to glacier2router executable
+ Ice_ICEBOX_EXECUTABLE - path to icebox executable
+ Ice_ICEBOXXX11_EXECUTABLE - path to icebox++11 executable
+ Ice_ICEBOXADMIN_EXECUTABLE - path to iceboxadmin executable
+ Ice_ICEBOXD_EXECUTABLE - path to iceboxd executable
+ Ice_ICEBOXNET_EXECUTABLE - path to iceboxnet executable
+ Ice_ICEBRIDGE_EXECUTABLE - path to icebridge executable
+ Ice_ICEGRIDADMIN_EXECUTABLE - path to icegridadmin executable
+ Ice_ICEGRIDDB_EXECUTABLE - path to icegriddb executable
+ Ice_ICEGRIDNODE_EXECUTABLE - path to icegridnode executable
+ Ice_ICEGRIDNODED_EXECUTABLE - path to icegridnoded executable
+ Ice_ICEGRIDREGISTRY_EXECUTABLE - path to icegridregistry executable
+ Ice_ICEGRIDREGISTRYD_EXECUTABLE - path to icegridregistryd executable
+ Ice_ICEPATCH2CALC_EXECUTABLE - path to icepatch2calc executable
+ Ice_ICEPATCH2CLIENT_EXECUTABLE - path to icepatch2client executable
+ Ice_ICEPATCH2SERVER_EXECUTABLE - path to icepatch2server executable
+ Ice_ICESERVICEINSTALL_EXECUTABLE - path to iceserviceinstall executable
+ Ice_ICESTORMADMIN_EXECUTABLE - path to icestormadmin executable
+ Ice_ICESTORMDB_EXECUTABLE - path to icestormdb executable
+ Ice_ICESTORMMIGRATE_EXECUTABLE - path to icestormmigrate executable
+
+Ice db programs (Windows only; standard system versions on all other
+platforms) are reported in::
+
+ Ice_DB_ARCHIVE_EXECUTABLE - path to db_archive executable
+ Ice_DB_CHECKPOINT_EXECUTABLE - path to db_checkpoint executable
+ Ice_DB_DEADLOCK_EXECUTABLE - path to db_deadlock executable
+ Ice_DB_DUMP_EXECUTABLE - path to db_dump executable
+ Ice_DB_HOTBACKUP_EXECUTABLE - path to db_hotbackup executable
+ Ice_DB_LOAD_EXECUTABLE - path to db_load executable
+ Ice_DB_LOG_VERIFY_EXECUTABLE - path to db_log_verify executable
+ Ice_DB_PRINTLOG_EXECUTABLE - path to db_printlog executable
+ Ice_DB_RECOVER_EXECUTABLE - path to db_recover executable
+ Ice_DB_STAT_EXECUTABLE - path to db_stat executable
+ Ice_DB_TUNER_EXECUTABLE - path to db_tuner executable
+ Ice_DB_UPGRADE_EXECUTABLE - path to db_upgrade executable
+ Ice_DB_VERIFY_EXECUTABLE - path to db_verify executable
+ Ice_DUMPDB_EXECUTABLE - path to dumpdb executable
+ Ice_TRANSFORMDB_EXECUTABLE - path to transformdb executable
+
+Ice component libraries are reported in::
+
+ Ice_<C>_FOUND - ON if component was found
+ Ice_<C>_LIBRARIES - libraries for component
+
+Note that ``<C>`` is the uppercased name of the component.
+
+This module reads hints about search results from::
+
+ Ice_HOME - the root of the Ice installation
+
+The environment variable ``ICE_HOME`` may also be used; the
+Ice_HOME variable takes precedence.
+
+.. note::
+ On Windows, Ice 3.7.0 and later provide libraries via the NuGet
+ package manager. Appropriate NuGet packages will be searched for
+ using ``CMAKE_PREFIX_PATH``, or alternatively ``Ice_HOME`` may be
+ set to the location of a specific NuGet package to restrict the
+ search.
+
+The following cache variables may also be set::
+
+ Ice_<P>_EXECUTABLE - the path to executable <P>
+ Ice_INCLUDE_DIR - the directory containing the Ice headers
+ Ice_SLICE_DIR - the directory containing the Ice slice interface
+ definitions
+ Ice_<C>_LIBRARY - the library for component <C>
+
+.. note::
+
+ In most cases none of the above variables will require setting,
+ unless multiple Ice versions are available and a specific version
+ is required. On Windows, the most recent version of Ice will be
+ found through the registry. On Unix, the programs, headers and
+ libraries will usually be in standard locations, but Ice_SLICE_DIRS
+ might not be automatically detected (commonly known locations are
+ searched). All the other variables are defaulted using Ice_HOME,
+ if set. It's possible to set Ice_HOME and selectively specify
+ alternative locations for the other components; this might be
+ required for e.g. newer versions of Visual Studio if the
+ heuristics are not sufficient to identify the correct programs and
+ libraries for the specific Visual Studio version.
+
+Other variables one may set to control this module are::
+
+ Ice_DEBUG - Set to ON to enable debug output from FindIce.
+#]=======================================================================]
+
+# Written by Roger Leigh <rleigh@codelibre.net>
+
+ set(_Ice_db_programs
+ db_archive
+ db_checkpoint
+ db_deadlock
+ db_dump
+ db_hotbackup
+ db_load
+ db_log_verify
+ db_printlog
+ db_recover
+ db_stat
+ db_tuner
+ db_upgrade
+ db_verify
+ dumpdb
+ transformdb)
+
+ set(_Ice_programs
+ glacier2router
+ icebox
+ icebox++11
+ iceboxadmin
+ iceboxd
+ iceboxnet
+ icebridge
+ icegridadmin
+ icegriddb
+ icegridnode
+ icegridnoded
+ icegridregistry
+ icegridregistryd
+ icepatch2calc
+ icepatch2client
+ icepatch2server
+ iceserviceinstall
+ icestormadmin
+ icestormdb
+ icestormmigrate)
+
+ set(_Ice_slice_programs
+ slice2confluence
+ slice2cpp
+ slice2cs
+ slice2freezej
+ slice2freeze
+ slice2html
+ slice2java
+ slice2js
+ slice2matlab
+ slice2objc
+ slice2php
+ slice2py
+ slice2rb)
+
+
+# The Ice checks are contained in a function due to the large number
+# of temporary variables needed.
+function(_Ice_FIND)
+ # Released versions of Ice, including generic short forms
+ set(ice_versions
+ 3
+ 3.7
+ 3.7.0
+ 3.6
+ 3.6.3
+ 3.6.2
+ 3.6.1
+ 3.6.0
+ 3.5
+ 3.5.1
+ 3.5.0
+ 3.4
+ 3.4.2
+ 3.4.1
+ 3.4.0
+ 3.3
+ 3.3.1
+ 3.3.0)
+
+ foreach(ver ${ice_versions})
+ string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\$" two_digit_version_match "${ver}")
+ if(two_digit_version_match)
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\$" "\\1\\2" two_digit_version "${ver}")
+ list(APPEND ice_suffix_versions "${two_digit_version}")
+ endif()
+ endforeach()
+
+ # Set up search paths, taking compiler into account. Search Ice_HOME,
+ # with ICE_HOME in the environment as a fallback if unset.
+ if(Ice_HOME)
+ list(APPEND ice_roots "${Ice_HOME}")
+ else()
+ if(NOT "$ENV{ICE_HOME}" STREQUAL "")
+ file(TO_CMAKE_PATH "$ENV{ICE_HOME}" NATIVE_PATH)
+ list(APPEND ice_roots "${NATIVE_PATH}")
+ set(Ice_HOME "${NATIVE_PATH}"
+ CACHE PATH "Location of the Ice installation" FORCE)
+ endif()
+ endif()
+
+ set(_bin "bin/Win32")
+ set(_lib "lib/Win32")
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(_bin "bin/x64")
+ set(_lib "lib/x64")
+ # 64-bit path suffix
+ set(_x64 "/x64")
+ # 64-bit library directory
+ set(_lib64 "lib64")
+ endif()
+
+ unset(vcvers)
+ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC")
+ if(MSVC_TOOLSET_VERSION GREATER_EQUAL 141)
+ set(vcvers "141;140")
+ elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 100)
+ set(vcvers "${MSVC_TOOLSET_VERSION}")
+ elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 90)
+ set(vcvers "${MSVC_TOOLSET_VERSION}")
+ set(vcyear "2008")
+ elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 80)
+ set(vcvers "${MSVC_TOOLSET_VERSION}")
+ set(vcyear "2005")
+ else() # Unknown version
+ set(vcvers Unknown)
+ endif()
+ endif()
+
+ # For compatibility with ZeroC Windows builds.
+ if(vcvers)
+ list(APPEND ice_binary_suffixes "build/native/${_bin}/Release" "tools")
+ list(APPEND ice_debug_library_suffixes "build/native/${_lib}/Debug")
+ list(APPEND ice_release_library_suffixes "build/native/${_lib}/Release")
+ foreach(vcver IN LISTS vcvers)
+ # Earlier Ice (3.3) builds don't use vcnnn subdirectories, but are harmless to check.
+ list(APPEND ice_binary_suffixes "bin/vc${vcver}${_x64}" "bin/vc${vcver}")
+ list(APPEND ice_debug_library_suffixes "lib/vc${vcver}${_x64}" "lib/vc${vcver}")
+ list(APPEND ice_release_library_suffixes "lib/vc${vcver}${_x64}" "lib/vc${vcver}")
+ endforeach()
+ endif()
+ # Generic 64-bit and 32-bit directories
+ list(APPEND ice_binary_suffixes "bin${_x64}" "bin")
+ list(APPEND ice_debug_library_suffixes "libx32" "${_lib64}" "lib${_x64}" "lib")
+ list(APPEND ice_release_library_suffixes "libx32" "${_lib64}" "lib${_x64}" "lib")
+ if(vcvers)
+ list(APPEND ice_include_suffixes "build/native/include")
+ endif()
+ list(APPEND ice_include_suffixes "include")
+ list(APPEND ice_slice_suffixes "slice")
+
+ # On Windows, look in the registry for install locations. Different
+ # versions of Ice install support different compiler versions.
+ if(vcvers)
+ foreach(ice_version ${ice_versions})
+ foreach(vcver IN LISTS vcvers)
+ list(APPEND ice_nuget_dirs "zeroc.ice.v${vcver}.${ice_version}")
+ list(APPEND freeze_nuget_dirs "zeroc.freeze.v${vcver}.${ice_version}")
+ endforeach()
+ endforeach()
+ find_path(Ice_NUGET_DIR
+ NAMES "tools/slice2cpp.exe"
+ PATH_SUFFIXES ${ice_nuget_dirs}
+ DOC "Ice NuGet directory")
+ if(Ice_NUGET_DIR)
+ list(APPEND ice_roots "${Ice_NUGET_DIR}")
+ endif()
+ find_path(Freeze_NUGET_DIR
+ NAMES "tools/slice2freeze.exe"
+ PATH_SUFFIXES ${freeze_nuget_dirs}
+ DOC "Freeze NuGet directory")
+ if(Freeze_NUGET_DIR)
+ list(APPEND ice_roots "${Freeze_NUGET_DIR}")
+ endif()
+ foreach(ice_version ${ice_versions})
+ # Ice 3.3 releases use a Visual Studio year suffix and value is
+ # enclosed in double quotes, though only the leading quote is
+ # returned by get_filename_component.
+ unset(ice_location)
+ if(vcyear)
+ get_filename_component(ice_location
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ZeroC\\Ice ${ice_version} for Visual Studio ${vcyear};InstallDir]"
+ PATH)
+ if(ice_location AND NOT ("${ice_location}" STREQUAL "/registry" OR "${ice_location}" STREQUAL "/"))
+ string(REGEX REPLACE "^\"(.*)\"?$" "\\1" ice_location "${ice_location}")
+ get_filename_component(ice_location "${ice_location}" ABSOLUTE)
+ else()
+ unset(ice_location)
+ endif()
+ endif()
+ # Ice 3.4+ releases don't use a suffix
+ if(NOT ice_location OR "${ice_location}" STREQUAL "/registry")
+ get_filename_component(ice_location
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ZeroC\\Ice ${ice_version};InstallDir]"
+ ABSOLUTE)
+ endif()
+
+ if(ice_location AND NOT "${ice_location}" STREQUAL "/registry")
+ list(APPEND ice_roots "${ice_location}")
+ endif()
+ endforeach()
+ else()
+ foreach(ice_version ${ice_versions})
+ # Prefer 64-bit variants if present (and using a 64-bit compiler)
+ list(APPEND ice_roots "/opt/Ice-${ice_version}")
+ endforeach()
+ endif()
+
+ # Find all Ice programs
+ foreach(program ${_Ice_db_programs} ${_Ice_programs} ${_Ice_slice_programs})
+ string(TOUPPER "${program}" program_upcase)
+ set(cache_var "Ice_${program_upcase}_EXECUTABLE")
+ set(program_var "Ice_${program_upcase}_EXECUTABLE")
+ find_program("${cache_var}" "${program}"
+ HINTS ${ice_roots}
+ PATH_SUFFIXES ${ice_binary_suffixes}
+ DOC "Ice ${program} executable")
+ mark_as_advanced(cache_var)
+ set("${program_var}" "${${cache_var}}" PARENT_SCOPE)
+ endforeach()
+
+ # Get version.
+ if(Ice_SLICE2CPP_EXECUTABLE)
+ # Execute in C locale for safety
+ set(_Ice_SAVED_LC_ALL "$ENV{LC_ALL}")
+ set(ENV{LC_ALL} C)
+
+ execute_process(COMMAND ${Ice_SLICE2CPP_EXECUTABLE} --version
+ ERROR_VARIABLE Ice_VERSION_SLICE2CPP_FULL
+ ERROR_STRIP_TRAILING_WHITESPACE)
+
+ # restore the previous LC_ALL
+ set(ENV{LC_ALL} ${_Ice_SAVED_LC_ALL})
+
+ # Make short version
+ string(REGEX REPLACE "^(.*)\\.[^.]*$" "\\1" Ice_VERSION_SLICE2CPP_SHORT "${Ice_VERSION_SLICE2CPP_FULL}")
+ set(Ice_VERSION "${Ice_VERSION_SLICE2CPP_FULL}" PARENT_SCOPE)
+ endif()
+
+ if(NOT Ice_FIND_QUIETLY)
+ message(STATUS "Ice version: ${Ice_VERSION_SLICE2CPP_FULL}")
+ endif()
+
+ # Find include directory
+ find_path(Ice_INCLUDE_DIR
+ NAMES "Ice/Ice.h"
+ HINTS ${ice_roots}
+ PATH_SUFFIXES ${ice_include_suffixes}
+ DOC "Ice include directory")
+ set(Ice_INCLUDE_DIR "${Ice_INCLUDE_DIR}" PARENT_SCOPE)
+
+ find_path(Freeze_INCLUDE_DIR
+ NAMES "Freeze/Freeze.h"
+ HINTS ${ice_roots}
+ PATH_SUFFIXES ${ice_include_suffixes}
+ DOC "Freeze include directory")
+ set(Freeze_INCLUDE_DIR "${Freeze_INCLUDE_DIR}" PARENT_SCOPE)
+
+ # In common use on Linux, MacOS X (homebrew) and FreeBSD; prefer
+ # version-specific dir
+ list(APPEND ice_slice_paths
+ /usr/local/share /usr/share)
+ list(APPEND ice_slice_suffixes
+ "Ice-${Ice_VERSION_SLICE2CPP_FULL}/slice"
+ "Ice-${Ice_VERSION_SLICE2CPP_SHORT}/slice"
+ "ice/slice"
+ Ice)
+
+ # Find slice directory
+ find_path(Ice_SLICE_DIR
+ NAMES "Ice/Connection.ice"
+ HINTS ${ice_roots}
+ ${ice_slice_paths}
+ PATH_SUFFIXES ${ice_slice_suffixes}
+ NO_DEFAULT_PATH
+ DOC "Ice slice directory")
+ set(Ice_SLICE_DIR "${Ice_SLICE_DIR}" PARENT_SCOPE)
+
+ # Find all Ice libraries
+ set(Ice_REQUIRED_LIBS_FOUND ON)
+ foreach(component ${Ice_FIND_COMPONENTS})
+ string(TOUPPER "${component}" component_upcase)
+ set(component_cache "Ice_${component_upcase}_LIBRARY")
+ set(component_cache_release "${component_cache}_RELEASE")
+ set(component_cache_debug "${component_cache}_DEBUG")
+ set(component_found "${component_upcase}_FOUND")
+ set(component_library "${component}")
+ unset(component_library_release_names)
+ unset(component_library_debug_names)
+ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC")
+ string(REGEX MATCH ".+\\+\\+11$" component_library_cpp11 "${component_library}")
+ if(component_library_cpp11)
+ string(REGEX REPLACE "^(.+)(\\+\\+11)$" "\\1" component_library "${component_library}")
+ endif()
+ foreach(suffix_ver ${ice_suffix_versions})
+ set(_name "${component_library}${suffix_ver}")
+ if(component_library_cpp11)
+ string(APPEND _name "++11")
+ endif()
+ list(APPEND component_library_debug_names "${_name}d")
+ list(APPEND component_library_release_names "${_name}")
+ endforeach()
+ set(_name "${component_library}")
+ if(component_library_cpp11)
+ string(APPEND _name "++11")
+ endif()
+ list(APPEND component_library_debug_names "${_name}d")
+ list(APPEND component_library_release_names "${_name}")
+ else()
+ list(APPEND component_library_debug_names "${component_library}d")
+ list(APPEND component_library_release_names "${component_library}")
+ endif()
+ find_library("${component_cache_release}" ${component_library_release_names}
+ HINTS ${ice_roots}
+ PATH_SUFFIXES ${ice_release_library_suffixes}
+ DOC "Ice ${component} library (release)")
+ find_library("${component_cache_debug}" ${component_library_debug_names}
+ HINTS ${ice_roots}
+ PATH_SUFFIXES ${ice_debug_library_suffixes}
+ DOC "Ice ${component} library (debug)")
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(Ice_${component_upcase})
+ mark_as_advanced("${component_cache_release}" "${component_cache_debug}")
+ if(${component_cache})
+ set("${component_found}" ON)
+ list(APPEND Ice_LIBRARY "${${component_cache}}")
+ endif()
+ mark_as_advanced("${component_found}")
+ set("${component_cache}" "${${component_cache}}" PARENT_SCOPE)
+ set("${component_found}" "${${component_found}}" PARENT_SCOPE)
+ if(${component_found})
+ if (Ice_FIND_REQUIRED_${component})
+ list(APPEND Ice_LIBS_FOUND "${component} (required)")
+ else()
+ list(APPEND Ice_LIBS_FOUND "${component} (optional)")
+ endif()
+ else()
+ if (Ice_FIND_REQUIRED_${component})
+ set(Ice_REQUIRED_LIBS_FOUND OFF)
+ list(APPEND Ice_LIBS_NOTFOUND "${component} (required)")
+ else()
+ list(APPEND Ice_LIBS_NOTFOUND "${component} (optional)")
+ endif()
+ endif()
+ endforeach()
+ set(_Ice_REQUIRED_LIBS_FOUND "${Ice_REQUIRED_LIBS_FOUND}" PARENT_SCOPE)
+ set(Ice_LIBRARY "${Ice_LIBRARY}" PARENT_SCOPE)
+
+ if(NOT Ice_FIND_QUIETLY)
+ if(Ice_LIBS_FOUND)
+ message(STATUS "Found the following Ice libraries:")
+ foreach(found ${Ice_LIBS_FOUND})
+ message(STATUS " ${found}")
+ endforeach()
+ endif()
+ if(Ice_LIBS_NOTFOUND)
+ message(STATUS "The following Ice libraries were not found:")
+ foreach(notfound ${Ice_LIBS_NOTFOUND})
+ message(STATUS " ${notfound}")
+ endforeach()
+ endif()
+ endif()
+
+ if(Ice_DEBUG)
+ message(STATUS "--------FindIce.cmake search debug--------")
+ message(STATUS "ICE binary path search order: ${ice_roots}")
+ message(STATUS "ICE binary suffixes: ${ice_binary_suffixes}")
+ message(STATUS "ICE include path search order: ${ice_roots}")
+ message(STATUS "ICE include suffixes: ${ice_include_suffixes}")
+ message(STATUS "ICE slice path search order: ${ice_roots} ${ice_slice_paths}")
+ message(STATUS "ICE slice suffixes: ${ice_slice_suffixes}")
+ message(STATUS "ICE library path search order: ${ice_roots}")
+ message(STATUS "ICE debug library suffixes: ${ice_debug_library_suffixes}")
+ message(STATUS "ICE release library suffixes: ${ice_release_library_suffixes}")
+ message(STATUS "----------------")
+ endif()
+endfunction()
+
+_Ice_FIND()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Ice
+ FOUND_VAR Ice_FOUND
+ REQUIRED_VARS Ice_SLICE2CPP_EXECUTABLE
+ Ice_INCLUDE_DIR
+ Ice_SLICE_DIR
+ Ice_LIBRARY
+ _Ice_REQUIRED_LIBS_FOUND
+ VERSION_VAR Ice_VERSION
+ FAIL_MESSAGE "Failed to find all Ice components")
+
+unset(_Ice_REQUIRED_LIBS_FOUND)
+
+if(Ice_FOUND)
+ set(Ice_INCLUDE_DIRS "${Ice_INCLUDE_DIR}")
+ if (Freeze_INCLUDE_DIR)
+ list(APPEND Ice_INCLUDE_DIRS "${Freeze_INCLUDE_DIR}")
+ endif()
+ set(Ice_SLICE_DIRS "${Ice_SLICE_DIR}")
+ set(Ice_LIBRARIES "${Ice_LIBRARY}")
+ foreach(_Ice_component ${Ice_FIND_COMPONENTS})
+ string(TOUPPER "${_Ice_component}" _Ice_component_upcase)
+ set(_Ice_component_cache "Ice_${_Ice_component_upcase}_LIBRARY")
+ set(_Ice_component_cache_release "Ice_${_Ice_component_upcase}_LIBRARY_RELEASE")
+ set(_Ice_component_cache_debug "Ice_${_Ice_component_upcase}_LIBRARY_DEBUG")
+ set(_Ice_component_lib "Ice_${_Ice_component_upcase}_LIBRARIES")
+ set(_Ice_component_found "${_Ice_component_upcase}_FOUND")
+ set(_Ice_imported_target "Ice::${_Ice_component}")
+ if(${_Ice_component_found})
+ set("${_Ice_component_lib}" "${${_Ice_component_cache}}")
+ if(NOT TARGET ${_Ice_imported_target})
+ add_library(${_Ice_imported_target} UNKNOWN IMPORTED)
+ set_target_properties(${_Ice_imported_target} PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${Ice_INCLUDE_DIRS}")
+ if(EXISTS "${${_Ice_component_cache}}")
+ set_target_properties(${_Ice_imported_target} PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
+ IMPORTED_LOCATION "${${_Ice_component_cache}}")
+ endif()
+ if(EXISTS "${${_Ice_component_cache_release}}")
+ set_property(TARGET ${_Ice_imported_target} APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(${_Ice_imported_target} PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
+ IMPORTED_LOCATION_RELEASE "${${_Ice_component_cache_release}}")
+ endif()
+ if(EXISTS "${${_Ice_component_cache_debug}}")
+ set_property(TARGET ${_Ice_imported_target} APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(${_Ice_imported_target} PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
+ IMPORTED_LOCATION_DEBUG "${${_Ice_component_cache_debug}}")
+ endif()
+ endif()
+ endif()
+ unset(_Ice_component_upcase)
+ unset(_Ice_component_cache)
+ unset(_Ice_component_lib)
+ unset(_Ice_component_found)
+ unset(_Ice_imported_target)
+ endforeach()
+endif()
+
+if(Ice_DEBUG)
+ message(STATUS "--------FindIce.cmake results debug--------")
+ message(STATUS "Ice_VERSION number: ${Ice_VERSION}")
+ message(STATUS "Ice_HOME directory: ${Ice_HOME}")
+ message(STATUS "Ice_INCLUDE_DIR directory: ${Ice_INCLUDE_DIR}")
+ message(STATUS "Ice_SLICE_DIR directory: ${Ice_SLICE_DIR}")
+ message(STATUS "Ice_LIBRARIES: ${Ice_LIBRARIES}")
+ message(STATUS "Freeze_INCLUDE_DIR directory: ${Freeze_INCLUDE_DIR}")
+ message(STATUS "Ice_INCLUDE_DIRS directory: ${Ice_INCLUDE_DIRS}")
+
+ foreach(program ${_Ice_db_programs} ${_Ice_programs} ${_Ice_slice_programs})
+ string(TOUPPER "${program}" program_upcase)
+ message(STATUS "${program} executable: ${Ice_${program_upcase}_EXECUTABLE}")
+ endforeach()
+
+ foreach(component ${Ice_FIND_COMPONENTS})
+ string(TOUPPER "${component}" component_upcase)
+ set(component_lib "Ice_${component_upcase}_LIBRARIES")
+ set(component_found "${component_upcase}_FOUND")
+ message(STATUS "${component} library found: ${${component_found}}")
+ message(STATUS "${component} library: ${${component_lib}}")
+ endforeach()
+ message(STATUS "----------------")
+endif()
+
+unset(_Ice_db_programs)
+unset(_Ice_programs)
+unset(_Ice_slice_programs)
diff --git a/Modules/FindIconv.cmake b/Modules/FindIconv.cmake
new file mode 100644
index 0000000..5ec12b2
--- /dev/null
+++ b/Modules/FindIconv.cmake
@@ -0,0 +1,178 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindIconv
+---------
+
+.. versionadded:: 3.11
+
+This module finds the ``iconv()`` POSIX.1 functions on the system.
+These functions might be provided in the regular C library or externally
+in the form of an additional library.
+
+The following variables are provided to indicate iconv support:
+
+.. variable:: Iconv_FOUND
+
+ Variable indicating if the iconv support was found.
+
+.. variable:: Iconv_INCLUDE_DIRS
+
+ The directories containing the iconv headers.
+
+.. variable:: Iconv_LIBRARIES
+
+ The iconv libraries to be linked.
+
+.. variable:: Iconv_VERSION
+
+ .. versionadded:: 3.21
+
+ The version of iconv found (x.y)
+
+.. variable:: Iconv_VERSION_MAJOR
+
+ .. versionadded:: 3.21
+
+ The major version of iconv
+
+.. variable:: Iconv_VERSION_MINOR
+
+ .. versionadded:: 3.21
+
+ The minor version of iconv
+
+.. variable:: Iconv_IS_BUILT_IN
+
+ A variable indicating whether iconv support is stemming from the
+ C library or not. Even if the C library provides `iconv()`, the presence of
+ an external `libiconv` implementation might lead to this being false.
+
+Additionally, the following :prop_tgt:`IMPORTED` target is being provided:
+
+.. variable:: Iconv::Iconv
+
+ Imported target for using iconv.
+
+The following cache variables may also be set:
+
+.. variable:: Iconv_INCLUDE_DIR
+
+ The directory containing the iconv headers.
+
+.. variable:: Iconv_LIBRARY
+
+ The iconv library (if not implicitly given in the C library).
+
+.. note::
+ On POSIX platforms, iconv might be part of the C library and the cache
+ variables ``Iconv_INCLUDE_DIR`` and ``Iconv_LIBRARY`` might be empty.
+
+.. note::
+ Some libiconv implementations don't embed the version number in their header files.
+ In this case the variables ``Iconv_VERSION*`` will be empty.
+
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
+if(CMAKE_C_COMPILER_LOADED)
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckCSourceCompiles.cmake)
+elseif(CMAKE_CXX_COMPILER_LOADED)
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckCXXSourceCompiles.cmake)
+else()
+ # If neither C nor CXX are loaded, implicit iconv makes no sense.
+ set(Iconv_IS_BUILT_IN FALSE)
+endif()
+
+# iconv can only be provided in libc on a POSIX system.
+# If any cache variable is already set, we'll skip this test.
+if(NOT DEFINED Iconv_IS_BUILT_IN)
+ if(UNIX AND NOT DEFINED Iconv_INCLUDE_DIR AND NOT DEFINED Iconv_LIBRARY)
+ cmake_push_check_state(RESET)
+ # We always suppress the message here: Otherwise on supported systems
+ # not having iconv in their C library (e.g. those using libiconv)
+ # would always display a confusing "Looking for iconv - not found" message
+ set(CMAKE_FIND_QUIETLY TRUE)
+ # The following code will not work, but it's sufficient to see if it compiles.
+ # Note: libiconv will define the iconv functions as macros, so CheckSymbolExists
+ # will not yield correct results.
+ set(Iconv_IMPLICIT_TEST_CODE
+ "
+ #include <stddef.h>
+ #include <iconv.h>
+ int main() {
+ char *a, *b;
+ size_t i, j;
+ iconv_t ic;
+ ic = iconv_open(\"to\", \"from\");
+ iconv(ic, &a, &i, &b, &j);
+ iconv_close(ic);
+ }
+ "
+ )
+ if(CMAKE_C_COMPILER_LOADED)
+ check_c_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN)
+ else()
+ check_cxx_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN)
+ endif()
+ cmake_pop_check_state()
+ else()
+ set(Iconv_IS_BUILT_IN FALSE)
+ endif()
+endif()
+
+if(NOT Iconv_IS_BUILT_IN)
+ find_path(Iconv_INCLUDE_DIR
+ NAMES "iconv.h"
+ DOC "iconv include directory")
+ set(Iconv_LIBRARY_NAMES "iconv" "libiconv")
+else()
+ set(Iconv_INCLUDE_DIR "" CACHE FILEPATH "iconv include directory")
+ set(Iconv_LIBRARY_NAMES "c")
+endif()
+
+find_library(Iconv_LIBRARY
+ NAMES ${Iconv_LIBRARY_NAMES}
+ NAMES_PER_DIR
+ DOC "iconv library (potentially the C library)")
+
+mark_as_advanced(Iconv_INCLUDE_DIR)
+mark_as_advanced(Iconv_LIBRARY)
+
+# NOTE: glibc's iconv.h does not define _LIBICONV_VERSION
+if(Iconv_INCLUDE_DIR AND NOT Iconv_IS_BUILT_IN)
+ file(STRINGS ${Iconv_INCLUDE_DIR}/iconv.h Iconv_VERSION_DEFINE REGEX "_LIBICONV_VERSION (.*)")
+
+ if(Iconv_VERSION_DEFINE MATCHES "(0x[A-Fa-f0-9]+)")
+ set(Iconv_VERSION_NUMBER "${CMAKE_MATCH_1}")
+ # encoding -> version number: (major<<8) + minor
+ math(EXPR Iconv_VERSION_MAJOR "${Iconv_VERSION_NUMBER} >> 8" OUTPUT_FORMAT HEXADECIMAL)
+ math(EXPR Iconv_VERSION_MINOR "${Iconv_VERSION_NUMBER} - (${Iconv_VERSION_MAJOR} << 8)" OUTPUT_FORMAT HEXADECIMAL)
+
+ math(EXPR Iconv_VERSION_MAJOR "${Iconv_VERSION_MAJOR}" OUTPUT_FORMAT DECIMAL)
+ math(EXPR Iconv_VERSION_MINOR "${Iconv_VERSION_MINOR}" OUTPUT_FORMAT DECIMAL)
+ set(Iconv_VERSION "${Iconv_VERSION_MAJOR}.${Iconv_VERSION_MINOR}")
+ endif()
+
+ unset(Iconv_VERSION_DEFINE)
+ unset(Iconv_VERSION_NUMBER)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+if(NOT Iconv_IS_BUILT_IN)
+ find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY Iconv_INCLUDE_DIR
+ VERSION_VAR Iconv_VERSION)
+else()
+ find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY)
+endif()
+
+if(Iconv_FOUND)
+ set(Iconv_INCLUDE_DIRS "${Iconv_INCLUDE_DIR}")
+ set(Iconv_LIBRARIES "${Iconv_LIBRARY}")
+ if(NOT TARGET Iconv::Iconv)
+ add_library(Iconv::Iconv INTERFACE IMPORTED)
+ endif()
+ set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${Iconv_INCLUDE_DIRS}")
+ set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_LINK_LIBRARIES "${Iconv_LIBRARIES}")
+endif()
diff --git a/Modules/FindIcotool.cmake b/Modules/FindIcotool.cmake
new file mode 100644
index 0000000..d19c145
--- /dev/null
+++ b/Modules/FindIcotool.cmake
@@ -0,0 +1,52 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindIcotool
+-----------
+
+Find icotool
+
+This module looks for icotool. Convert and create Win32 icon and cursor files.
+This module defines the following values:
+
+::
+
+ ICOTOOL_EXECUTABLE: the full path to the icotool tool.
+ ICOTOOL_FOUND: True if icotool has been found.
+ ICOTOOL_VERSION_STRING: the version of icotool found.
+#]=======================================================================]
+
+find_program(ICOTOOL_EXECUTABLE
+ icotool
+)
+
+if(ICOTOOL_EXECUTABLE)
+ execute_process(
+ COMMAND ${ICOTOOL_EXECUTABLE} --version
+ OUTPUT_VARIABLE _icotool_version
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if("${_icotool_version}" MATCHES "^icotool \\([^\\)]*\\) ([0-9\\.]+[^ \n]*)")
+ set( ICOTOOL_VERSION_STRING
+ "${CMAKE_MATCH_1}"
+ )
+ else()
+ set( ICOTOOL_VERSION_STRING
+ ""
+ )
+ endif()
+ unset(_icotool_version)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(
+ Icotool
+ REQUIRED_VARS ICOTOOL_EXECUTABLE
+ VERSION_VAR ICOTOOL_VERSION_STRING
+)
+
+mark_as_advanced(
+ ICOTOOL_EXECUTABLE
+)
diff --git a/Modules/FindImageMagick.cmake b/Modules/FindImageMagick.cmake
new file mode 100644
index 0000000..d7de0dd
--- /dev/null
+++ b/Modules/FindImageMagick.cmake
@@ -0,0 +1,310 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindImageMagick
+---------------
+
+Find ImageMagick binary suite.
+
+.. versionadded:: 3.9
+ Added support for ImageMagick 7.
+
+This module will search for a set of ImageMagick tools specified as
+components in the :command:`find_package` call. Typical components include,
+but are not limited to (future versions of ImageMagick might have
+additional components not listed here):
+
+::
+
+ animate
+ compare
+ composite
+ conjure
+ convert
+ display
+ identify
+ import
+ mogrify
+ montage
+ stream
+
+
+
+If no component is specified in the :command:`find_package` call, then it only
+searches for the ImageMagick executable directory. This code defines
+the following variables:
+
+::
+
+ ImageMagick_FOUND - TRUE if all components are found.
+ ImageMagick_EXECUTABLE_DIR - Full path to executables directory.
+ ImageMagick_<component>_FOUND - TRUE if <component> is found.
+ ImageMagick_<component>_EXECUTABLE - Full path to <component> executable.
+ ImageMagick_VERSION_STRING - the version of ImageMagick found
+ (since CMake 2.8.8)
+
+
+
+``ImageMagick_VERSION_STRING`` will not work for old versions like 5.2.3.
+
+There are also components for the following ImageMagick APIs:
+
+::
+
+ Magick++
+ MagickWand
+ MagickCore
+
+
+
+For these components the following variables are set:
+
+::
+
+ ImageMagick_FOUND - TRUE if all components are found.
+ ImageMagick_INCLUDE_DIRS - Full paths to all include dirs.
+ ImageMagick_LIBRARIES - Full paths to all libraries.
+ ImageMagick_<component>_FOUND - TRUE if <component> is found.
+ ImageMagick_<component>_INCLUDE_DIRS - Full path to <component> include dirs.
+ ImageMagick_<component>_LIBRARIES - Full path to <component> libraries.
+
+
+
+Example Usages:
+
+::
+
+ find_package(ImageMagick)
+ find_package(ImageMagick COMPONENTS convert)
+ find_package(ImageMagick COMPONENTS convert mogrify display)
+ find_package(ImageMagick COMPONENTS Magick++)
+ find_package(ImageMagick COMPONENTS Magick++ convert)
+
+
+
+Note that the standard :command:`find_package` features are supported (i.e.,
+``QUIET``, ``REQUIRED``, etc.).
+#]=======================================================================]
+
+find_package(PkgConfig QUIET)
+
+#---------------------------------------------------------------------
+# Helper functions
+#---------------------------------------------------------------------
+function(FIND_IMAGEMAGICK_API component header)
+ set(ImageMagick_${component}_FOUND FALSE PARENT_SCOPE)
+
+ pkg_check_modules(PC_${component} QUIET ${component})
+
+ find_path(ImageMagick_${component}_INCLUDE_DIR
+ NAMES ${header}
+ HINTS
+ ${PC_${component}_INCLUDEDIR}
+ ${PC_${component}_INCLUDE_DIRS}
+ PATHS
+ ${ImageMagick_INCLUDE_DIRS}
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ImageMagick\\Current;BinPath]/include"
+ PATH_SUFFIXES
+ ImageMagick ImageMagick-6 ImageMagick-7
+ DOC "Path to the ImageMagick arch-independent include dir."
+ NO_DEFAULT_PATH
+ )
+ find_path(ImageMagick_${component}_ARCH_INCLUDE_DIR
+ NAMES magick/magick-baseconfig.h
+ HINTS
+ ${PC_${component}_INCLUDEDIR}
+ ${PC_${component}_INCLUDE_DIRS}
+ PATHS
+ ${ImageMagick_INCLUDE_DIRS}
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ImageMagick\\Current;BinPath]/include"
+ PATH_SUFFIXES
+ ImageMagick ImageMagick-6 ImageMagick-7
+ DOC "Path to the ImageMagick arch-specific include dir."
+ NO_DEFAULT_PATH
+ )
+ find_library(ImageMagick_${component}_LIBRARY
+ NAMES ${ARGN}
+ HINTS
+ ${PC_${component}_LIBDIR}
+ ${PC_${component}_LIB_DIRS}
+ PATHS
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ImageMagick\\Current;BinPath]/lib"
+ DOC "Path to the ImageMagick Magick++ library."
+ NO_DEFAULT_PATH
+ )
+
+ # old version have only indep dir
+ if(ImageMagick_${component}_INCLUDE_DIR AND ImageMagick_${component}_LIBRARY)
+ set(ImageMagick_${component}_FOUND TRUE PARENT_SCOPE)
+
+ # Construct per-component include directories.
+ set(ImageMagick_${component}_INCLUDE_DIRS
+ ${ImageMagick_${component}_INCLUDE_DIR}
+ )
+ if(ImageMagick_${component}_ARCH_INCLUDE_DIR)
+ list(APPEND ImageMagick_${component}_INCLUDE_DIRS
+ ${ImageMagick_${component}_ARCH_INCLUDE_DIR})
+ endif()
+ list(REMOVE_DUPLICATES ImageMagick_${component}_INCLUDE_DIRS)
+ set(ImageMagick_${component}_INCLUDE_DIRS
+ ${ImageMagick_${component}_INCLUDE_DIRS} PARENT_SCOPE)
+
+ # Add the per-component include directories to the full include dirs.
+ list(APPEND ImageMagick_INCLUDE_DIRS ${ImageMagick_${component}_INCLUDE_DIRS})
+ list(REMOVE_DUPLICATES ImageMagick_INCLUDE_DIRS)
+ set(ImageMagick_INCLUDE_DIRS ${ImageMagick_INCLUDE_DIRS} PARENT_SCOPE)
+
+ list(APPEND ImageMagick_LIBRARIES
+ ${ImageMagick_${component}_LIBRARY}
+ )
+ set(ImageMagick_LIBRARIES ${ImageMagick_LIBRARIES} PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(FIND_IMAGEMAGICK_EXE component)
+ set(_IMAGEMAGICK_EXECUTABLE
+ ${ImageMagick_EXECUTABLE_DIR}/${component}${CMAKE_EXECUTABLE_SUFFIX})
+ if(EXISTS ${_IMAGEMAGICK_EXECUTABLE})
+ set(ImageMagick_${component}_EXECUTABLE
+ ${_IMAGEMAGICK_EXECUTABLE}
+ PARENT_SCOPE
+ )
+ set(ImageMagick_${component}_FOUND TRUE PARENT_SCOPE)
+ else()
+ set(ImageMagick_${component}_FOUND FALSE PARENT_SCOPE)
+ endif()
+endfunction()
+
+#---------------------------------------------------------------------
+# Start Actual Work
+#---------------------------------------------------------------------
+# Try to find a ImageMagick installation binary path.
+find_path(ImageMagick_EXECUTABLE_DIR
+ NAMES mogrify${CMAKE_EXECUTABLE_SUFFIX}
+ PATHS
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ImageMagick\\Current;BinPath]"
+ DOC "Path to the ImageMagick binary directory."
+ NO_DEFAULT_PATH
+ )
+find_path(ImageMagick_EXECUTABLE_DIR
+ NAMES mogrify${CMAKE_EXECUTABLE_SUFFIX}
+ )
+
+# Find each component. Search for all tools in same dir
+# <ImageMagick_EXECUTABLE_DIR>; otherwise they should be found
+# independently and not in a cohesive module such as this one.
+unset(ImageMagick_REQUIRED_VARS)
+unset(ImageMagick_DEFAULT_EXECUTABLES)
+foreach(component ${ImageMagick_FIND_COMPONENTS}
+ # DEPRECATED: forced components for backward compatibility
+ convert mogrify import montage composite
+ )
+ if(component STREQUAL "Magick++")
+ FIND_IMAGEMAGICK_API(Magick++ Magick++.h
+ Magick++ CORE_RL_Magick++_
+ Magick++-6 Magick++-7
+ Magick++-Q8 Magick++-Q16 Magick++-Q16HDRI Magick++-Q8HDRI
+ Magick++-6.Q64 Magick++-6.Q32 Magick++-6.Q64HDRI Magick++-6.Q32HDRI
+ Magick++-6.Q16 Magick++-6.Q8 Magick++-6.Q16HDRI Magick++-6.Q8HDRI
+ Magick++-7.Q64 Magick++-7.Q32 Magick++-7.Q64HDRI Magick++-7.Q32HDRI
+ Magick++-7.Q16 Magick++-7.Q8 Magick++-7.Q16HDRI Magick++-7.Q8HDRI
+ )
+ list(APPEND ImageMagick_REQUIRED_VARS ImageMagick_Magick++_LIBRARY)
+ elseif(component STREQUAL "MagickWand")
+ FIND_IMAGEMAGICK_API(MagickWand "wand/MagickWand.h;MagickWand/MagickWand.h"
+ Wand MagickWand CORE_RL_wand_ CORE_RL_MagickWand_
+ MagickWand-6 MagickWand-7
+ MagickWand-Q16 MagickWand-Q8 MagickWand-Q16HDRI MagickWand-Q8HDRI
+ MagickWand-6.Q64 MagickWand-6.Q32 MagickWand-6.Q64HDRI MagickWand-6.Q32HDRI
+ MagickWand-6.Q16 MagickWand-6.Q8 MagickWand-6.Q16HDRI MagickWand-6.Q8HDRI
+ MagickWand-7.Q64 MagickWand-7.Q32 MagickWand-7.Q64HDRI MagickWand-7.Q32HDRI
+ MagickWand-7.Q16 MagickWand-7.Q8 MagickWand-7.Q16HDRI MagickWand-7.Q8HDRI
+ )
+ list(APPEND ImageMagick_REQUIRED_VARS ImageMagick_MagickWand_LIBRARY)
+ elseif(component STREQUAL "MagickCore")
+ FIND_IMAGEMAGICK_API(MagickCore "magick/MagickCore.h;MagickCore/MagickCore.h"
+ Magick MagickCore CORE_RL_magick_ CORE_RL_MagickCore_
+ MagickCore-6 MagickCore-7
+ MagickCore-Q16 MagickCore-Q8 MagickCore-Q16HDRI MagickCore-Q8HDRI
+ MagickCore-6.Q64 MagickCore-6.Q32 MagickCore-6.Q64HDRI MagickCore-6.Q32HDRI
+ MagickCore-6.Q16 MagickCore-6.Q8 MagickCore-6.Q16HDRI MagickCore-6.Q8HDRI
+ MagickCore-7.Q64 MagickCore-7.Q32 MagickCore-7.Q64HDRI MagickCore-7.Q32HDRI
+ MagickCore-7.Q16 MagickCore-7.Q8 MagickCore-7.Q16HDRI MagickCore-7.Q8HDRI
+ )
+ list(APPEND ImageMagick_REQUIRED_VARS ImageMagick_MagickCore_LIBRARY)
+ else()
+ if(ImageMagick_EXECUTABLE_DIR)
+ FIND_IMAGEMAGICK_EXE(${component})
+ endif()
+
+ if(ImageMagick_FIND_COMPONENTS)
+ list(FIND ImageMagick_FIND_COMPONENTS ${component} is_requested)
+ if(is_requested GREATER -1)
+ list(APPEND ImageMagick_REQUIRED_VARS ImageMagick_${component}_EXECUTABLE)
+ endif()
+ elseif(ImageMagick_${component}_EXECUTABLE)
+ # if no components were requested explicitly put all (default) executables
+ # in the list
+ list(APPEND ImageMagick_DEFAULT_EXECUTABLES ImageMagick_${component}_EXECUTABLE)
+ endif()
+ endif()
+endforeach()
+
+if(NOT ImageMagick_FIND_COMPONENTS AND NOT ImageMagick_DEFAULT_EXECUTABLES)
+ # No components were requested, and none of the default components were
+ # found. Just insert mogrify into the list of the default components to
+ # find so FPHSA below has something to check
+ list(APPEND ImageMagick_REQUIRED_VARS ImageMagick_mogrify_EXECUTABLE)
+elseif(ImageMagick_DEFAULT_EXECUTABLES)
+ list(APPEND ImageMagick_REQUIRED_VARS ${ImageMagick_DEFAULT_EXECUTABLES})
+endif()
+
+set(ImageMagick_INCLUDE_DIRS ${ImageMagick_INCLUDE_DIRS})
+set(ImageMagick_LIBRARIES ${ImageMagick_LIBRARIES})
+
+if(ImageMagick_mogrify_EXECUTABLE)
+ execute_process(COMMAND ${ImageMagick_mogrify_EXECUTABLE} -version
+ OUTPUT_VARIABLE imagemagick_version
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(imagemagick_version MATCHES "^Version: ImageMagick ([-0-9\\.]+)")
+ set(ImageMagick_VERSION_STRING "${CMAKE_MATCH_1}")
+ endif()
+ unset(imagemagick_version)
+endif()
+
+#---------------------------------------------------------------------
+# Standard Package Output
+#---------------------------------------------------------------------
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(ImageMagick
+ REQUIRED_VARS ${ImageMagick_REQUIRED_VARS}
+ VERSION_VAR ImageMagick_VERSION_STRING
+ )
+# Maintain consistency with all other variables.
+set(ImageMagick_FOUND ${IMAGEMAGICK_FOUND})
+
+#---------------------------------------------------------------------
+# DEPRECATED: Setting variables for backward compatibility.
+#---------------------------------------------------------------------
+set(IMAGEMAGICK_BINARY_PATH ${ImageMagick_EXECUTABLE_DIR}
+ CACHE PATH "Path to the ImageMagick binary directory.")
+set(IMAGEMAGICK_CONVERT_EXECUTABLE ${ImageMagick_convert_EXECUTABLE}
+ CACHE FILEPATH "Path to ImageMagick's convert executable.")
+set(IMAGEMAGICK_MOGRIFY_EXECUTABLE ${ImageMagick_mogrify_EXECUTABLE}
+ CACHE FILEPATH "Path to ImageMagick's mogrify executable.")
+set(IMAGEMAGICK_IMPORT_EXECUTABLE ${ImageMagick_import_EXECUTABLE}
+ CACHE FILEPATH "Path to ImageMagick's import executable.")
+set(IMAGEMAGICK_MONTAGE_EXECUTABLE ${ImageMagick_montage_EXECUTABLE}
+ CACHE FILEPATH "Path to ImageMagick's montage executable.")
+set(IMAGEMAGICK_COMPOSITE_EXECUTABLE ${ImageMagick_composite_EXECUTABLE}
+ CACHE FILEPATH "Path to ImageMagick's composite executable.")
+mark_as_advanced(
+ IMAGEMAGICK_BINARY_PATH
+ IMAGEMAGICK_CONVERT_EXECUTABLE
+ IMAGEMAGICK_MOGRIFY_EXECUTABLE
+ IMAGEMAGICK_IMPORT_EXECUTABLE
+ IMAGEMAGICK_MONTAGE_EXECUTABLE
+ IMAGEMAGICK_COMPOSITE_EXECUTABLE
+ )
diff --git a/Modules/FindIntl.cmake b/Modules/FindIntl.cmake
new file mode 100644
index 0000000..038f4da
--- /dev/null
+++ b/Modules/FindIntl.cmake
@@ -0,0 +1,181 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindIntl
+--------
+
+.. versionadded:: 3.2
+
+Find the Gettext libintl headers and libraries.
+
+This module reports information about the Gettext libintl
+installation in several variables.
+
+.. variable:: Intl_FOUND
+
+ True if libintl is found.
+
+.. variable:: Intl_INCLUDE_DIRS
+
+ The directory containing the libintl headers.
+
+.. variable:: Intl_LIBRARIES
+
+ The intl libraries to be linked.
+
+.. variable:: Intl_VERSION
+
+ .. versionadded:: 3.21
+
+ The version of intl found (x.y.z)
+
+.. variable:: Intl_VERSION_MAJOR
+
+ .. versionadded:: 3.21
+
+ The major version of intl
+
+.. variable:: Intl_VERSION_MINOR
+
+ .. versionadded:: 3.21
+
+ The minor version of intl
+
+.. variable:: Intl_VERSION_PATCH
+
+ .. versionadded:: 3.21
+
+ The patch version of intl
+
+.. versionadded:: 3.20
+ This module defines :prop_tgt:`IMPORTED` target ``Intl::Intl``.
+
+The following cache variables may also be set:
+
+.. variable:: Intl_INCLUDE_DIR
+
+ The directory containing the libintl headers
+
+.. variable:: Intl_LIBRARY
+
+ The libintl library (if any)
+
+.. variable:: Intl_IS_BUILT_IN
+
+ .. versionadded:: 3.20
+
+ whether ``intl`` is a part of the C library.
+
+.. note::
+ On some platforms, such as Linux with GNU libc, the gettext
+ functions are present in the C standard library and libintl
+ is not required. ``Intl_LIBRARIES`` will be empty in this
+ case.
+
+.. note::
+ Some libintl implementations don't embed the version number in their header files.
+ In this case the variables ``Intl_VERSION*`` will be empty.
+
+.. note::
+ If you wish to use the Gettext tools (``msgmerge``,
+ ``msgfmt``, etc.), use :module:`FindGettext`.
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
+if(CMAKE_C_COMPILER_LOADED)
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckCSourceCompiles.cmake)
+elseif(CMAKE_CXX_COMPILER_LOADED)
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckCXXSourceCompiles.cmake)
+else()
+ # If neither C nor CXX are loaded, implicit intl makes no sense.
+ set(Intl_IS_BUILT_IN FALSE)
+endif()
+
+# Check if Intl is built in to the C library.
+if(NOT DEFINED Intl_IS_BUILT_IN)
+ if(NOT DEFINED Intl_INCLUDE_DIR AND NOT DEFINED Intl_LIBRARY)
+ cmake_push_check_state(RESET)
+ set(CMAKE_REQUIRED_QUIET TRUE)
+ set(Intl_IMPLICIT_TEST_CODE [[
+#include <libintl.h>
+int main(void) {
+ gettext("");
+ dgettext("", "");
+ dcgettext("", "", 0);
+ return 0;
+}
+]])
+ if(CMAKE_C_COMPILER_LOADED)
+ check_c_source_compiles("${Intl_IMPLICIT_TEST_CODE}" Intl_IS_BUILT_IN)
+ else()
+ check_cxx_source_compiles("${Intl_IMPLICIT_TEST_CODE}" Intl_IS_BUILT_IN)
+ endif()
+ cmake_pop_check_state()
+ else()
+ set(Intl_IS_BUILT_IN FALSE)
+ endif()
+endif()
+
+set(_Intl_REQUIRED_VARS)
+if(Intl_IS_BUILT_IN)
+ set(_Intl_REQUIRED_VARS _Intl_IS_BUILT_IN_MSG)
+ set(_Intl_IS_BUILT_IN_MSG "built in to C library")
+else()
+ set(_Intl_REQUIRED_VARS Intl_LIBRARY Intl_INCLUDE_DIR)
+
+ find_path(Intl_INCLUDE_DIR
+ NAMES "libintl.h"
+ DOC "libintl include directory")
+ mark_as_advanced(Intl_INCLUDE_DIR)
+
+ find_library(Intl_LIBRARY "intl" "libintl" NAMES_PER_DIR
+ DOC "libintl libraries (if not in the C library)")
+ mark_as_advanced(Intl_LIBRARY)
+endif()
+
+# NOTE: glibc's libintl.h does not define LIBINTL_VERSION
+if(Intl_INCLUDE_DIR AND EXISTS "${Intl_INCLUDE_DIR}/libintl.h")
+ file(STRINGS ${Intl_INCLUDE_DIR}/libintl.h Intl_VERSION_DEFINE REGEX "LIBINTL_VERSION (.*)")
+
+ if(Intl_VERSION_DEFINE MATCHES "(0x[A-Fa-f0-9]+)")
+ set(Intl_VERSION_NUMBER "${CMAKE_MATCH_1}")
+ # encoding -> version number: (major<<16) + (minor<<8) + patch
+ math(EXPR Intl_VERSION_MAJOR "${Intl_VERSION_NUMBER} >> 16" OUTPUT_FORMAT HEXADECIMAL)
+ math(EXPR Intl_VERSION_MINOR "(${Intl_VERSION_NUMBER} - (${Intl_VERSION_MAJOR} << 16)) >> 8" OUTPUT_FORMAT HEXADECIMAL)
+ math(EXPR Intl_VERSION_PATCH "${Intl_VERSION_NUMBER} - ((${Intl_VERSION_MAJOR} << 16) + (${Intl_VERSION_MINOR} << 8))" OUTPUT_FORMAT HEXADECIMAL)
+
+ math(EXPR Intl_VERSION_MAJOR "${Intl_VERSION_MAJOR}" OUTPUT_FORMAT DECIMAL)
+ math(EXPR Intl_VERSION_MINOR "${Intl_VERSION_MINOR}" OUTPUT_FORMAT DECIMAL)
+ math(EXPR Intl_VERSION_PATCH "${Intl_VERSION_PATCH}" OUTPUT_FORMAT DECIMAL)
+ set(Intl_VERSION "${Intl_VERSION_MAJOR}.${Intl_VERSION_MINOR}.${Intl_VERSION_PATCH}")
+ endif()
+
+ unset(Intl_VERSION_DEFINE)
+ unset(Intl_VERSION_NUMBER)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Intl
+ FOUND_VAR Intl_FOUND
+ REQUIRED_VARS ${_Intl_REQUIRED_VARS}
+ VERSION_VAR Intl_VERSION
+ FAIL_MESSAGE "Failed to find Gettext libintl")
+unset(_Intl_REQUIRED_VARS)
+unset(_Intl_IS_BUILT_IN_MSG)
+
+if(Intl_FOUND)
+ if(Intl_IS_BUILT_IN)
+ set(Intl_INCLUDE_DIRS "")
+ set(Intl_LIBRARIES "")
+ else()
+ set(Intl_INCLUDE_DIRS "${Intl_INCLUDE_DIR}")
+ set(Intl_LIBRARIES "${Intl_LIBRARY}")
+ endif()
+ if(NOT TARGET Intl::Intl)
+ add_library(Intl::Intl INTERFACE IMPORTED)
+ set_target_properties(Intl::Intl PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${Intl_INCLUDE_DIRS}"
+ INTERFACE_LINK_LIBRARIES "${Intl_LIBRARIES}")
+ endif()
+endif()
diff --git a/Modules/FindJNI.cmake b/Modules/FindJNI.cmake
new file mode 100644
index 0000000..5aa2d60
--- /dev/null
+++ b/Modules/FindJNI.cmake
@@ -0,0 +1,405 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindJNI
+-------
+
+Find Java Native Interface (JNI) libraries.
+
+JNI enables Java code running in a Java Virtual Machine (JVM) to call
+and be called by native applications and libraries written in other
+languages such as C, C++.
+
+This module finds if Java is installed and determines where the
+include files and libraries are. It also determines what the name of
+the library is. The caller may set variable ``JAVA_HOME`` to specify a
+Java installation prefix explicitly.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module sets the following result variables:
+
+``JNI_INCLUDE_DIRS``
+ the include dirs to use
+``JNI_LIBRARIES``
+ the libraries to use (JAWT and JVM)
+``JNI_FOUND``
+ TRUE if JNI headers and libraries were found.
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+The following cache variables are also available to set or use:
+
+``JAVA_AWT_LIBRARY``
+ the path to the Java AWT Native Interface (JAWT) library
+``JAVA_JVM_LIBRARY``
+ the path to the Java Virtual Machine (JVM) library
+``JAVA_INCLUDE_PATH``
+ the include path to jni.h
+``JAVA_INCLUDE_PATH2``
+ the include path to jni_md.h and jniport.h
+``JAVA_AWT_INCLUDE_PATH``
+ the include path to jawt.h
+#]=======================================================================]
+
+# Expand {libarch} occurrences to java_libarch subdirectory(-ies) and set ${_var}
+macro(java_append_library_directories _var)
+ # Determine java arch-specific library subdir
+ # Mostly based on openjdk/jdk/make/common/shared/Platform.gmk as of openjdk
+ # 1.6.0_18 + icedtea patches. However, it would be much better to base the
+ # guess on the first part of the GNU config.guess platform triplet.
+ if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
+ if(CMAKE_LIBRARY_ARCHITECTURE STREQUAL "x86_64-linux-gnux32")
+ set(_java_libarch "x32" "amd64" "i386")
+ else()
+ set(_java_libarch "amd64" "i386")
+ endif()
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$")
+ set(_java_libarch "i386")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64")
+ set(_java_libarch "arm64" "aarch64")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^alpha")
+ set(_java_libarch "alpha")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")
+ # Subdir is "arm" for both big-endian (arm) and little-endian (armel).
+ set(_java_libarch "arm" "aarch32")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips")
+ # mips* machines are bi-endian mostly so processor does not tell
+ # endianness of the underlying system.
+ set(_java_libarch "${CMAKE_SYSTEM_PROCESSOR}"
+ "mips" "mipsel" "mipseb" "mipsr6" "mipsr6el"
+ "mips64" "mips64el" "mips64r6" "mips64r6el"
+ "mipsn32" "mipsn32el" "mipsn32r6" "mipsn32r6el")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64le")
+ set(_java_libarch "ppc64" "ppc64le")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64")
+ set(_java_libarch "ppc64" "ppc")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)")
+ set(_java_libarch "ppc" "ppc64")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^sparc")
+ # Both flavours can run on the same processor
+ set(_java_libarch "${CMAKE_SYSTEM_PROCESSOR}" "sparc" "sparcv9")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(parisc|hppa)")
+ set(_java_libarch "parisc" "parisc64")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^s390")
+ # s390 binaries can run on s390x machines
+ set(_java_libarch "${CMAKE_SYSTEM_PROCESSOR}" "s390" "s390x")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^sh")
+ set(_java_libarch "sh")
+ else()
+ set(_java_libarch "${CMAKE_SYSTEM_PROCESSOR}")
+ endif()
+
+ # Append default list architectures if CMAKE_SYSTEM_PROCESSOR was empty or
+ # system is non-Linux (where the code above has not been well tested)
+ if(NOT _java_libarch OR NOT (CMAKE_SYSTEM_NAME MATCHES "Linux"))
+ list(APPEND _java_libarch "i386" "amd64" "ppc")
+ endif()
+
+ # Sometimes ${CMAKE_SYSTEM_PROCESSOR} is added to the list to prefer
+ # current value to a hardcoded list. Remove possible duplicates.
+ list(REMOVE_DUPLICATES _java_libarch)
+
+ foreach(_path ${ARGN})
+ if(_path MATCHES "{libarch}")
+ foreach(_libarch ${_java_libarch})
+ string(REPLACE "{libarch}" "${_libarch}" _newpath "${_path}")
+ if(EXISTS ${_newpath})
+ list(APPEND ${_var} "${_newpath}")
+ endif()
+ endforeach()
+ else()
+ if(EXISTS ${_path})
+ list(APPEND ${_var} "${_path}")
+ endif()
+ endif()
+ endforeach()
+endmacro()
+
+include(${CMAKE_CURRENT_LIST_DIR}/CMakeFindJavaCommon.cmake)
+
+# Save CMAKE_FIND_FRAMEWORK
+if(DEFINED CMAKE_FIND_FRAMEWORK)
+ set(_JNI_CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK})
+else()
+ unset(_JNI_CMAKE_FIND_FRAMEWORK)
+endif()
+
+if(_JAVA_HOME_EXPLICIT)
+ set(CMAKE_FIND_FRAMEWORK NEVER)
+endif()
+
+set(JAVA_AWT_LIBRARY_DIRECTORIES)
+if(_JAVA_HOME)
+ JAVA_APPEND_LIBRARY_DIRECTORIES(JAVA_AWT_LIBRARY_DIRECTORIES
+ ${_JAVA_HOME}/jre/lib/{libarch}
+ ${_JAVA_HOME}/jre/lib
+ ${_JAVA_HOME}/lib/{libarch}
+ ${_JAVA_HOME}/lib
+ ${_JAVA_HOME}
+ )
+endif()
+
+if (WIN32)
+ set (_JNI_HINTS)
+ execute_process(COMMAND REG QUERY HKLM\\SOFTWARE\\JavaSoft\\JDK
+ RESULT_VARIABLE _JNI_RESULT
+ OUTPUT_VARIABLE _JNI_VERSIONS
+ ERROR_QUIET)
+ if (NOT _JNI_RESULT)
+ string (REGEX MATCHALL "HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\JavaSoft\\\\JDK\\\\[0-9.]+" _JNI_VERSIONS "${_JNI_VERSIONS}")
+ if (_JNI_VERSIONS)
+ # sort versions. Most recent first
+ ## handle version 9 apart from other versions to get correct ordering
+ set (_JNI_V9 ${_JNI_VERSIONS})
+ list (FILTER _JNI_VERSIONS EXCLUDE REGEX "JDK\\\\9")
+ list (SORT _JNI_VERSIONS)
+ list (REVERSE _JNI_VERSIONS)
+ list (FILTER _JNI_V9 INCLUDE REGEX "JDK\\\\9")
+ list (SORT _JNI_V9)
+ list (REVERSE _JNI_V9)
+ list (APPEND _JNI_VERSIONS ${_JNI_V9})
+ foreach (_JNI_HINT IN LISTS _JNI_VERSIONS)
+ list(APPEND _JNI_HINTS "[${_JNI_HINT};JavaHome]")
+ endforeach()
+ endif()
+ endif()
+
+ foreach (_JNI_HINT IN LISTS _JNI_HINTS)
+ list(APPEND JAVA_AWT_LIBRARY_DIRECTORIES "${_JNI_HINT}/lib")
+ endforeach()
+
+ get_filename_component(java_install_version
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit;CurrentVersion]" NAME)
+
+ list(APPEND JAVA_AWT_LIBRARY_DIRECTORIES
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\${java_install_version};JavaHome]/lib"
+ )
+endif()
+
+set(_JNI_JAVA_DIRECTORIES_BASE
+ /usr/lib/jvm/java
+ /usr/lib/java
+ /usr/lib/jvm
+ /usr/local/lib/java
+ /usr/local/share/java
+ /usr/lib/j2sdk1.4-sun
+ /usr/lib/j2sdk1.5-sun
+ /opt/sun-jdk-1.5.0.04
+ /usr/lib/jvm/java-6-sun
+ /usr/lib/jvm/java-1.5.0-sun
+ /usr/lib/jvm/java-6-sun-1.6.0.00 # can this one be removed according to #8821 ? Alex
+ /usr/lib/jvm/java-6-openjdk
+ /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0 # fedora
+ # Debian specific paths for default JVM
+ /usr/lib/jvm/default-java
+ # Arch Linux specific paths for default JVM
+ /usr/lib/jvm/default
+ # Ubuntu specific paths for default JVM
+ /usr/lib/jvm/java-11-openjdk-{libarch} # Ubuntu 18.04 LTS
+ /usr/lib/jvm/java-8-openjdk-{libarch} # Ubuntu 15.10
+ /usr/lib/jvm/java-7-openjdk-{libarch} # Ubuntu 15.10
+ /usr/lib/jvm/java-6-openjdk-{libarch} # Ubuntu 15.10
+ # OpenBSD specific paths for default JVM
+ /usr/local/jdk-1.7.0
+ /usr/local/jre-1.7.0
+ /usr/local/jdk-1.6.0
+ /usr/local/jre-1.6.0
+ # FreeBSD specific paths for default JVM
+ /usr/local/openjdk15
+ /usr/local/openjdk14
+ /usr/local/openjdk13
+ /usr/local/openjdk12
+ /usr/local/openjdk11
+ /usr/local/openjdk8
+ /usr/local/openjdk7
+ # SuSE specific paths for default JVM
+ /usr/lib64/jvm/java
+ /usr/lib64/jvm/jre
+ )
+
+set(_JNI_JAVA_AWT_LIBRARY_TRIES)
+set(_JNI_JAVA_INCLUDE_TRIES)
+
+foreach(_java_dir IN LISTS _JNI_JAVA_DIRECTORIES_BASE)
+ list(APPEND _JNI_JAVA_AWT_LIBRARY_TRIES
+ ${_java_dir}/jre/lib/{libarch}
+ ${_java_dir}/jre/lib
+ ${_java_dir}/lib/{libarch}
+ ${_java_dir}/lib
+ ${_java_dir}
+ )
+ list(APPEND _JNI_JAVA_INCLUDE_TRIES
+ ${_java_dir}/include
+ )
+endforeach()
+
+JAVA_APPEND_LIBRARY_DIRECTORIES(JAVA_AWT_LIBRARY_DIRECTORIES
+ ${_JNI_JAVA_AWT_LIBRARY_TRIES}
+ )
+
+set(JAVA_JVM_LIBRARY_DIRECTORIES)
+foreach(dir ${JAVA_AWT_LIBRARY_DIRECTORIES})
+ list(APPEND JAVA_JVM_LIBRARY_DIRECTORIES
+ "${dir}"
+ "${dir}/client"
+ "${dir}/server"
+ # IBM SDK, Java Technology Edition, specific paths
+ "${dir}/j9vm"
+ "${dir}/default"
+ )
+endforeach()
+
+set(JAVA_AWT_INCLUDE_DIRECTORIES)
+if(_JAVA_HOME)
+ list(APPEND JAVA_AWT_INCLUDE_DIRECTORIES ${_JAVA_HOME}/include)
+endif()
+if (WIN32)
+ foreach (_JNI_HINT IN LISTS _JNI_HINTS)
+ list(APPEND JAVA_AWT_INCLUDE_DIRECTORIES "${_JNI_HINT}/include")
+ endforeach()
+ list(APPEND JAVA_AWT_INCLUDE_DIRECTORIES
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\${java_install_version};JavaHome]/include"
+ )
+endif()
+
+JAVA_APPEND_LIBRARY_DIRECTORIES(JAVA_AWT_INCLUDE_DIRECTORIES
+ ${_JNI_JAVA_INCLUDE_TRIES}
+ )
+
+foreach(JAVA_PROG "${JAVA_RUNTIME}" "${JAVA_COMPILE}" "${JAVA_ARCHIVE}")
+ get_filename_component(jpath "${JAVA_PROG}" PATH)
+ foreach(JAVA_INC_PATH ../include ../java/include ../share/java/include)
+ if(EXISTS ${jpath}/${JAVA_INC_PATH})
+ list(APPEND JAVA_AWT_INCLUDE_DIRECTORIES "${jpath}/${JAVA_INC_PATH}")
+ endif()
+ endforeach()
+ foreach(JAVA_LIB_PATH
+ ../lib ../jre/lib ../jre/lib/i386
+ ../java/lib ../java/jre/lib ../java/jre/lib/i386
+ ../share/java/lib ../share/java/jre/lib ../share/java/jre/lib/i386)
+ if(EXISTS ${jpath}/${JAVA_LIB_PATH})
+ list(APPEND JAVA_AWT_LIBRARY_DIRECTORIES "${jpath}/${JAVA_LIB_PATH}")
+ endif()
+ endforeach()
+endforeach()
+
+if(APPLE)
+ if(CMAKE_FIND_FRAMEWORK STREQUAL "ONLY")
+ set(_JNI_SEARCHES FRAMEWORK)
+ elseif(CMAKE_FIND_FRAMEWORK STREQUAL "NEVER")
+ set(_JNI_SEARCHES NORMAL)
+ elseif(CMAKE_FIND_FRAMEWORK STREQUAL "LAST")
+ set(_JNI_SEARCHES NORMAL FRAMEWORK)
+ else()
+ set(_JNI_SEARCHES FRAMEWORK NORMAL)
+ endif()
+ set(_JNI_FRAMEWORK_JVM NAMES JavaVM)
+ set(_JNI_FRAMEWORK_JAWT "${_JNI_FRAMEWORK_JVM}")
+else()
+ set(_JNI_SEARCHES NORMAL)
+endif()
+
+set(_JNI_NORMAL_JVM
+ NAMES jvm
+ PATHS ${JAVA_JVM_LIBRARY_DIRECTORIES}
+ )
+
+set(_JNI_NORMAL_JAWT
+ NAMES jawt
+ PATHS ${JAVA_AWT_LIBRARY_DIRECTORIES}
+ )
+
+foreach(search ${_JNI_SEARCHES})
+ find_library(JAVA_JVM_LIBRARY ${_JNI_${search}_JVM})
+ find_library(JAVA_AWT_LIBRARY ${_JNI_${search}_JAWT})
+ if(JAVA_JVM_LIBRARY)
+ break()
+ endif()
+endforeach()
+unset(_JNI_SEARCHES)
+unset(_JNI_FRAMEWORK_JVM)
+unset(_JNI_FRAMEWORK_JAWT)
+unset(_JNI_NORMAL_JVM)
+unset(_JNI_NORMAL_JAWT)
+
+# Find headers matching the library.
+if("${JAVA_JVM_LIBRARY};${JAVA_AWT_LIBRARY};" MATCHES "(/JavaVM.framework|-framework JavaVM);")
+ set(CMAKE_FIND_FRAMEWORK ONLY)
+else()
+ set(CMAKE_FIND_FRAMEWORK NEVER)
+endif()
+
+# add in the include path
+find_path(JAVA_INCLUDE_PATH jni.h
+ ${JAVA_AWT_INCLUDE_DIRECTORIES}
+)
+
+find_path(JAVA_INCLUDE_PATH2 NAMES jni_md.h jniport.h
+ PATHS
+ ${JAVA_INCLUDE_PATH}
+ ${JAVA_INCLUDE_PATH}/darwin
+ ${JAVA_INCLUDE_PATH}/win32
+ ${JAVA_INCLUDE_PATH}/linux
+ ${JAVA_INCLUDE_PATH}/freebsd
+ ${JAVA_INCLUDE_PATH}/openbsd
+ ${JAVA_INCLUDE_PATH}/solaris
+ ${JAVA_INCLUDE_PATH}/hp-ux
+ ${JAVA_INCLUDE_PATH}/alpha
+ ${JAVA_INCLUDE_PATH}/aix
+)
+
+find_path(JAVA_AWT_INCLUDE_PATH jawt.h
+ ${JAVA_INCLUDE_PATH}
+)
+
+# Restore CMAKE_FIND_FRAMEWORK
+if(DEFINED _JNI_CMAKE_FIND_FRAMEWORK)
+ set(CMAKE_FIND_FRAMEWORK ${_JNI_CMAKE_FIND_FRAMEWORK})
+ unset(_JNI_CMAKE_FIND_FRAMEWORK)
+else()
+ unset(CMAKE_FIND_FRAMEWORK)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(JNI DEFAULT_MSG JAVA_AWT_LIBRARY
+ JAVA_JVM_LIBRARY
+ JAVA_INCLUDE_PATH
+ JAVA_INCLUDE_PATH2
+ JAVA_AWT_INCLUDE_PATH)
+
+mark_as_advanced(
+ JAVA_AWT_LIBRARY
+ JAVA_JVM_LIBRARY
+ JAVA_AWT_INCLUDE_PATH
+ JAVA_INCLUDE_PATH
+ JAVA_INCLUDE_PATH2
+)
+
+set(JNI_LIBRARIES
+ ${JAVA_AWT_LIBRARY}
+ ${JAVA_JVM_LIBRARY}
+)
+
+set(JNI_INCLUDE_DIRS
+ ${JAVA_INCLUDE_PATH}
+ ${JAVA_INCLUDE_PATH2}
+ ${JAVA_AWT_INCLUDE_PATH}
+)
diff --git a/Modules/FindJPEG.cmake b/Modules/FindJPEG.cmake
new file mode 100644
index 0000000..add2486
--- /dev/null
+++ b/Modules/FindJPEG.cmake
@@ -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.
+
+#[=======================================================================[.rst:
+FindJPEG
+--------
+
+Find the Joint Photographic Experts Group (JPEG) library (``libjpeg``)
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.12
+
+This module defines the following :prop_tgt:`IMPORTED` targets:
+
+``JPEG::JPEG``
+ The JPEG library, if found.
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``JPEG_FOUND``
+ If false, do not try to use JPEG.
+``JPEG_INCLUDE_DIRS``
+ where to find jpeglib.h, etc.
+``JPEG_LIBRARIES``
+ the libraries needed to use JPEG.
+``JPEG_VERSION``
+ .. versionadded:: 3.12
+ the version of the JPEG library found
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``JPEG_INCLUDE_DIRS``
+ where to find jpeglib.h, etc.
+``JPEG_LIBRARY_RELEASE``
+ where to find the JPEG library (optimized).
+``JPEG_LIBRARY_DEBUG``
+ where to find the JPEG library (debug).
+
+.. versionadded:: 3.12
+ Debug and Release variand are found separately.
+
+Obsolete variables
+^^^^^^^^^^^^^^^^^^
+
+``JPEG_INCLUDE_DIR``
+ where to find jpeglib.h, etc. (same as JPEG_INCLUDE_DIRS)
+``JPEG_LIBRARY``
+ where to find the JPEG library.
+#]=======================================================================]
+
+find_path(JPEG_INCLUDE_DIR jpeglib.h)
+
+set(jpeg_names ${JPEG_NAMES} jpeg jpeg-static libjpeg libjpeg-static turbojpeg turbojpeg-static)
+foreach(name ${jpeg_names})
+ list(APPEND jpeg_names_debug "${name}d")
+endforeach()
+
+if(NOT JPEG_LIBRARY)
+ find_library(JPEG_LIBRARY_RELEASE NAMES ${jpeg_names} NAMES_PER_DIR)
+ find_library(JPEG_LIBRARY_DEBUG NAMES ${jpeg_names_debug} NAMES_PER_DIR)
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(JPEG)
+ mark_as_advanced(JPEG_LIBRARY_RELEASE JPEG_LIBRARY_DEBUG)
+endif()
+unset(jpeg_names)
+unset(jpeg_names_debug)
+
+if(JPEG_INCLUDE_DIR)
+ file(GLOB _JPEG_CONFIG_HEADERS_FEDORA "${JPEG_INCLUDE_DIR}/jconfig*.h")
+ file(GLOB _JPEG_CONFIG_HEADERS_DEBIAN "${JPEG_INCLUDE_DIR}/*/jconfig.h")
+ set(_JPEG_CONFIG_HEADERS
+ "${JPEG_INCLUDE_DIR}/jpeglib.h"
+ ${_JPEG_CONFIG_HEADERS_FEDORA}
+ ${_JPEG_CONFIG_HEADERS_DEBIAN})
+ foreach (_JPEG_CONFIG_HEADER IN LISTS _JPEG_CONFIG_HEADERS)
+ if (NOT EXISTS "${_JPEG_CONFIG_HEADER}")
+ continue ()
+ endif ()
+ file(STRINGS "${_JPEG_CONFIG_HEADER}"
+ jpeg_lib_version REGEX "^#define[\t ]+JPEG_LIB_VERSION[\t ]+.*")
+
+ if (NOT jpeg_lib_version)
+ continue ()
+ endif ()
+
+ string(REGEX REPLACE "^#define[\t ]+JPEG_LIB_VERSION[\t ]+([0-9]+).*"
+ "\\1" JPEG_VERSION "${jpeg_lib_version}")
+ break ()
+ endforeach ()
+ unset(jpeg_lib_version)
+ unset(_JPEG_CONFIG_HEADER)
+ unset(_JPEG_CONFIG_HEADERS)
+ unset(_JPEG_CONFIG_HEADERS_FEDORA)
+ unset(_JPEG_CONFIG_HEADERS_DEBIAN)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(JPEG
+ REQUIRED_VARS JPEG_LIBRARY JPEG_INCLUDE_DIR
+ VERSION_VAR JPEG_VERSION)
+
+if(JPEG_FOUND)
+ set(JPEG_LIBRARIES ${JPEG_LIBRARY})
+ set(JPEG_INCLUDE_DIRS "${JPEG_INCLUDE_DIR}")
+
+ if(NOT TARGET JPEG::JPEG)
+ add_library(JPEG::JPEG UNKNOWN IMPORTED)
+ if(JPEG_INCLUDE_DIRS)
+ set_target_properties(JPEG::JPEG PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${JPEG_INCLUDE_DIRS}")
+ endif()
+ if(EXISTS "${JPEG_LIBRARY}")
+ set_target_properties(JPEG::JPEG PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${JPEG_LIBRARY}")
+ endif()
+ if(EXISTS "${JPEG_LIBRARY_RELEASE}")
+ set_property(TARGET JPEG::JPEG APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(JPEG::JPEG PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+ IMPORTED_LOCATION_RELEASE "${JPEG_LIBRARY_RELEASE}")
+ endif()
+ if(EXISTS "${JPEG_LIBRARY_DEBUG}")
+ set_property(TARGET JPEG::JPEG APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(JPEG::JPEG PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+ IMPORTED_LOCATION_DEBUG "${JPEG_LIBRARY_DEBUG}")
+ endif()
+ endif()
+endif()
+
+mark_as_advanced(JPEG_LIBRARY JPEG_INCLUDE_DIR)
diff --git a/Modules/FindJasper.cmake b/Modules/FindJasper.cmake
new file mode 100644
index 0000000..729a503
--- /dev/null
+++ b/Modules/FindJasper.cmake
@@ -0,0 +1,47 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindJasper
+----------
+
+Try to find the Jasper JPEG2000 library
+
+Once done this will define
+
+::
+
+ JASPER_FOUND - system has Jasper
+ JASPER_INCLUDE_DIR - the Jasper include directory
+ JASPER_LIBRARIES - the libraries needed to use Jasper
+ JASPER_VERSION_STRING - the version of Jasper found (since CMake 2.8.8)
+#]=======================================================================]
+
+find_path(JASPER_INCLUDE_DIR jasper/jasper.h)
+
+if (NOT JASPER_LIBRARIES)
+ find_package(JPEG)
+
+ find_library(JASPER_LIBRARY_RELEASE NAMES jasper libjasper)
+ find_library(JASPER_LIBRARY_DEBUG NAMES jasperd)
+
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ SELECT_LIBRARY_CONFIGURATIONS(JASPER)
+endif ()
+
+if (JASPER_INCLUDE_DIR AND EXISTS "${JASPER_INCLUDE_DIR}/jasper/jas_config.h")
+ file(STRINGS "${JASPER_INCLUDE_DIR}/jasper/jas_config.h" jasper_version_str REGEX "^#define[\t ]+JAS_VERSION[\t ]+\".*\".*")
+
+ string(REGEX REPLACE "^#define[\t ]+JAS_VERSION[\t ]+\"([^\"]+)\".*" "\\1" JASPER_VERSION_STRING "${jasper_version_str}")
+endif ()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Jasper
+ REQUIRED_VARS JASPER_LIBRARIES JASPER_INCLUDE_DIR JPEG_LIBRARIES
+ VERSION_VAR JASPER_VERSION_STRING)
+
+if (JASPER_FOUND)
+ set(JASPER_LIBRARIES ${JASPER_LIBRARIES} ${JPEG_LIBRARIES} )
+endif ()
+
+mark_as_advanced(JASPER_INCLUDE_DIR)
diff --git a/Modules/FindJava.cmake b/Modules/FindJava.cmake
new file mode 100644
index 0000000..4f0e0fe
--- /dev/null
+++ b/Modules/FindJava.cmake
@@ -0,0 +1,364 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindJava
+--------
+
+Find Java
+
+This module finds if Java is installed and determines where the
+include files and libraries are. The caller may set variable ``JAVA_HOME``
+to specify a Java installation prefix explicitly.
+
+See also the :module:`FindJNI` module to find Java Native Interface (JNI).
+
+.. versionadded:: 3.10
+ Added support for Java 9+ version parsing.
+
+Specify one or more of the following components as you call this find module. See example below.
+
+::
+
+ Runtime = Java Runtime Environment used to execute Java byte-compiled applications
+ Development = Development tools (java, javac, javah, jar and javadoc), includes Runtime component
+ IdlJ = Interface Description Language (IDL) to Java compiler
+ JarSigner = Signer and verifier tool for Java Archive (JAR) files
+
+
+This module sets the following result variables:
+
+::
+
+ Java_JAVA_EXECUTABLE = the full path to the Java runtime
+ Java_JAVAC_EXECUTABLE = the full path to the Java compiler
+ Java_JAVAH_EXECUTABLE = the full path to the Java header generator
+ Java_JAVADOC_EXECUTABLE = the full path to the Java documentation generator
+ Java_IDLJ_EXECUTABLE = the full path to the Java idl compiler
+ Java_JAR_EXECUTABLE = the full path to the Java archiver
+ Java_JARSIGNER_EXECUTABLE = the full path to the Java jar signer
+ Java_VERSION_STRING = Version of java found, eg. 1.6.0_12
+ Java_VERSION_MAJOR = The major version of the package found.
+ Java_VERSION_MINOR = The minor version of the package found.
+ Java_VERSION_PATCH = The patch version of the package found.
+ Java_VERSION_TWEAK = The tweak version of the package found (after '_')
+ Java_VERSION = This is set to: $major[.$minor[.$patch[.$tweak]]]
+
+.. versionadded:: 3.4
+ Added the ``Java_IDLJ_EXECUTABLE`` and ``Java_JARSIGNER_EXECUTABLE``
+ variables.
+
+The minimum required version of Java can be specified using the
+:command:`find_package` syntax, e.g.
+
+.. code-block:: cmake
+
+ find_package(Java 1.8)
+
+NOTE: ``${Java_VERSION}`` and ``${Java_VERSION_STRING}`` are not guaranteed to
+be identical. For example some java version may return:
+``Java_VERSION_STRING = 1.8.0_17`` and ``Java_VERSION = 1.8.0.17``
+
+another example is the Java OEM, with: ``Java_VERSION_STRING = 1.8.0-oem``
+and ``Java_VERSION = 1.8.0``
+
+For these components the following variables are set:
+
+::
+
+ Java_FOUND - TRUE if all components are found.
+ Java_<component>_FOUND - TRUE if <component> is found.
+
+
+
+Example Usages:
+
+::
+
+ find_package(Java)
+ find_package(Java 1.8 REQUIRED)
+ find_package(Java COMPONENTS Runtime)
+ find_package(Java COMPONENTS Development)
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/CMakeFindJavaCommon.cmake)
+
+# The HINTS option should only be used for values computed from the system.
+set(_JAVA_HINTS)
+if(_JAVA_HOME)
+ list(APPEND _JAVA_HINTS ${_JAVA_HOME}/bin)
+endif()
+if (WIN32)
+ macro (_JAVA_GET_INSTALLED_VERSIONS _KIND)
+ execute_process(COMMAND REG QUERY HKLM\\SOFTWARE\\JavaSoft\\${_KIND}
+ RESULT_VARIABLE _JAVA_RESULT
+ OUTPUT_VARIABLE _JAVA_VERSIONS
+ ERROR_QUIET)
+ if (NOT _JAVA_RESULT)
+ string (REGEX MATCHALL "HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\JavaSoft\\\\${_KIND}\\\\[0-9.]+" _JAVA_VERSIONS "${_JAVA_VERSIONS}")
+ if (_JAVA_VERSIONS)
+ # sort versions. Most recent first
+ ## handle version 9 apart from other versions to get correct ordering
+ set (_JAVA_V9 ${_JAVA_VERSIONS})
+ list (FILTER _JAVA_VERSIONS EXCLUDE REGEX "${_KIND}\\\\9")
+ list (SORT _JAVA_VERSIONS)
+ list (REVERSE _JAVA_VERSIONS)
+ list (FILTER _JAVA_V9 INCLUDE REGEX "${_KIND}\\\\9")
+ list (SORT _JAVA_V9)
+ list (REVERSE _JAVA_V9)
+ list (APPEND _JAVA_VERSIONS ${_JAVA_V9})
+ foreach (_JAVA_HINT IN LISTS _JAVA_VERSIONS)
+ list(APPEND _JAVA_HINTS "[${_JAVA_HINT};JavaHome]/bin")
+ endforeach()
+ endif()
+ endif()
+ endmacro()
+
+ # search for installed versions for version 9 and upper
+ _JAVA_GET_INSTALLED_VERSIONS("JDK")
+ _JAVA_GET_INSTALLED_VERSIONS("JRE")
+
+ list(APPEND _JAVA_HINTS
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.9;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.8;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.7;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.6;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.5;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.4;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.3;JavaHome]/bin"
+ )
+endif()
+
+# Hard-coded guesses should still go in PATHS. This ensures that the user
+# environment can always override hard guesses.
+set(_JAVA_PATHS
+ /usr/lib/java/bin
+ /usr/share/java/bin
+ /usr/local/java/bin
+ /usr/local/java/share/bin
+ /usr/java/j2sdk1.4.2_04
+ /usr/lib/j2sdk1.4-sun/bin
+ /usr/java/j2sdk1.4.2_09/bin
+ /usr/lib/j2sdk1.5-sun/bin
+ /opt/sun-jdk-1.5.0.04/bin
+ /usr/local/jdk-1.7.0/bin
+ /usr/local/jdk-1.6.0/bin
+ )
+find_program(Java_JAVA_EXECUTABLE
+ NAMES java
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+if(Java_JAVA_EXECUTABLE)
+ execute_process(COMMAND "${Java_JAVA_EXECUTABLE}" -version
+ RESULT_VARIABLE res
+ OUTPUT_VARIABLE var
+ ERROR_VARIABLE var # sun-java output to stderr
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_STRIP_TRAILING_WHITESPACE)
+ if( res )
+ if(var MATCHES "Unable to locate a Java Runtime to invoke|No Java runtime present, requesting install")
+ set(Java_JAVA_EXECUTABLE Java_JAVA_EXECUTABLE-NOTFOUND)
+ elseif(${Java_FIND_REQUIRED})
+ message( FATAL_ERROR "Error executing java -version" )
+ else()
+ message( STATUS "Warning, could not run java -version")
+ endif()
+ else()
+ # Extract version components (up to 4 levels) from "java -version" output.
+ set(_java_version_regex [[(([0-9]+)(\.([0-9]+)(\.([0-9]+)(_([0-9]+))?)?)?.*)]])
+ if(var MATCHES "java version \"${_java_version_regex}\"")
+ # Sun, GCJ, older OpenJDK
+ set(Java_VERSION_STRING "${CMAKE_MATCH_1}")
+ set(Java_VERSION_MAJOR "${CMAKE_MATCH_2}")
+ if (CMAKE_MATCH_4)
+ set(Java_VERSION_MINOR "${CMAKE_MATCH_4}")
+ else()
+ set(Java_VERSION_MINOR 0)
+ endif()
+ if (CMAKE_MATCH_6)
+ set(Java_VERSION_PATCH "${CMAKE_MATCH_6}")
+ else()
+ set(Java_VERSION_PATCH 0)
+ endif()
+ set(Java_VERSION_TWEAK "${CMAKE_MATCH_8}")
+ elseif(var MATCHES "openjdk version \"${_java_version_regex}\"")
+ # OpenJDK
+ set(Java_VERSION_STRING "${CMAKE_MATCH_1}")
+ set(Java_VERSION_MAJOR "${CMAKE_MATCH_2}")
+ if (CMAKE_MATCH_4)
+ set(Java_VERSION_MINOR "${CMAKE_MATCH_4}")
+ else()
+ set(Java_VERSION_MINOR 0)
+ endif()
+ if (CMAKE_MATCH_6)
+ set(Java_VERSION_PATCH "${CMAKE_MATCH_6}")
+ else()
+ set(Java_VERSION_PATCH 0)
+ endif()
+ set(Java_VERSION_TWEAK "${CMAKE_MATCH_8}")
+ elseif(var MATCHES "openjdk version \"([0-9]+)-[A-Za-z]+\"")
+ # OpenJDK 9 early access builds or locally built
+ set(Java_VERSION_STRING "1.${CMAKE_MATCH_1}.0")
+ set(Java_VERSION_MAJOR "1")
+ set(Java_VERSION_MINOR "${CMAKE_MATCH_1}")
+ set(Java_VERSION_PATCH "0")
+ set(Java_VERSION_TWEAK "")
+ elseif(var MATCHES "java full version \"kaffe-${_java_version_regex}\"")
+ # Kaffe style
+ set(Java_VERSION_STRING "${CMAKE_MATCH_1}")
+ set(Java_VERSION_MAJOR "${CMAKE_MATCH_2}")
+ set(Java_VERSION_MINOR "${CMAKE_MATCH_4}")
+ set(Java_VERSION_PATCH "${CMAKE_MATCH_6}")
+ set(Java_VERSION_TWEAK "${CMAKE_MATCH_8}")
+ else()
+ if(NOT Java_FIND_QUIETLY)
+ string(REPLACE "\n" "\n " ver_msg "\n${var}")
+ message(WARNING "Java version not recognized:${ver_msg}\nPlease report.")
+ endif()
+ set(Java_VERSION_STRING "")
+ set(Java_VERSION_MAJOR "")
+ set(Java_VERSION_MINOR "")
+ set(Java_VERSION_PATCH "")
+ set(Java_VERSION_TWEAK "")
+ endif()
+ set(Java_VERSION "${Java_VERSION_MAJOR}")
+ if(NOT "x${Java_VERSION}" STREQUAL "x")
+ foreach(c MINOR PATCH TWEAK)
+ if(NOT "x${Java_VERSION_${c}}" STREQUAL "x")
+ string(APPEND Java_VERSION ".${Java_VERSION_${c}}")
+ else()
+ break()
+ endif()
+ endforeach()
+ endif()
+ endif()
+
+endif()
+
+
+find_program(Java_JAR_EXECUTABLE
+ NAMES jar
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+find_program(Java_JAVAC_EXECUTABLE
+ NAMES javac
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+find_program(Java_JAVAH_EXECUTABLE
+ NAMES javah
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+find_program(Java_JAVADOC_EXECUTABLE
+ NAMES javadoc
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+find_program(Java_IDLJ_EXECUTABLE
+ NAMES idlj
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+find_program(Java_JARSIGNER_EXECUTABLE
+ NAMES jarsigner
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+if(Java_FIND_COMPONENTS)
+ set(_JAVA_REQUIRED_VARS)
+ foreach(component ${Java_FIND_COMPONENTS})
+ # User just want to execute some Java byte-compiled
+ If(component STREQUAL "Runtime")
+ list(APPEND _JAVA_REQUIRED_VARS Java_JAVA_EXECUTABLE)
+ if(Java_JAVA_EXECUTABLE)
+ set(Java_Runtime_FOUND TRUE)
+ endif()
+ elseif(component STREQUAL "Development")
+ list(APPEND _JAVA_REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAVAC_EXECUTABLE
+ Java_JAR_EXECUTABLE Java_JAVADOC_EXECUTABLE)
+ if(Java_VERSION VERSION_LESS "10")
+ list(APPEND _JAVA_REQUIRED_VARS Java_JAVAH_EXECUTABLE)
+ if(Java_JAVA_EXECUTABLE AND Java_JAVAC_EXECUTABLE
+ AND Java_JAVAH_EXECUTABLE AND Java_JAR_EXECUTABLE AND Java_JAVADOC_EXECUTABLE)
+ set(Java_Development_FOUND TRUE)
+ endif()
+ else()
+ if(Java_JAVA_EXECUTABLE AND Java_JAVAC_EXECUTABLE
+ AND Java_JAR_EXECUTABLE AND Java_JAVADOC_EXECUTABLE)
+ set(Java_Development_FOUND TRUE)
+ endif()
+ endif()
+ elseif(component STREQUAL "IdlJ")
+ list(APPEND _JAVA_REQUIRED_VARS Java_IDLJ_EXECUTABLE)
+ if(Java_IDLJ_EXECUTABLE)
+ set(Java_IdlJ_FOUND TRUE)
+ endif()
+ elseif(component STREQUAL "JarSigner")
+ list(APPEND _JAVA_REQUIRED_VARS Java_JARSIGNER_EXECUTABLE)
+ if(Java_JARSIGNER_EXECUTABLE)
+ set(Java_JarSigner_FOUND TRUE)
+ endif()
+ else()
+ message(FATAL_ERROR "Comp: ${component} is not handled")
+ endif()
+ endforeach()
+ list (REMOVE_DUPLICATES _JAVA_REQUIRED_VARS)
+ find_package_handle_standard_args(Java
+ REQUIRED_VARS ${_JAVA_REQUIRED_VARS} HANDLE_COMPONENTS
+ VERSION_VAR Java_VERSION
+ )
+ if(Java_FOUND)
+ foreach(component ${Java_FIND_COMPONENTS})
+ set(Java_${component}_FOUND TRUE)
+ endforeach()
+ endif()
+else()
+ # Check for Development
+ if(Java_VERSION VERSION_LESS "10")
+ find_package_handle_standard_args(Java
+ REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
+ Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE
+ VERSION_VAR Java_VERSION_STRING
+ )
+ else()
+ find_package_handle_standard_args(Java
+ REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
+ Java_JAVADOC_EXECUTABLE
+ VERSION_VAR Java_VERSION_STRING
+ )
+ endif()
+endif()
+
+
+mark_as_advanced(
+ Java_JAVA_EXECUTABLE
+ Java_JAR_EXECUTABLE
+ Java_JAVAC_EXECUTABLE
+ Java_JAVAH_EXECUTABLE
+ Java_JAVADOC_EXECUTABLE
+ Java_IDLJ_EXECUTABLE
+ Java_JARSIGNER_EXECUTABLE
+ )
+
+# LEGACY
+set(JAVA_RUNTIME ${Java_JAVA_EXECUTABLE})
+set(JAVA_ARCHIVE ${Java_JAR_EXECUTABLE})
+set(JAVA_COMPILE ${Java_JAVAC_EXECUTABLE})
diff --git a/Modules/FindKDE3.cmake b/Modules/FindKDE3.cmake
new file mode 100644
index 0000000..30ea5e6
--- /dev/null
+++ b/Modules/FindKDE3.cmake
@@ -0,0 +1,360 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindKDE3
+--------
+
+Find the KDE3 include and library dirs, KDE preprocessors and define a some macros
+
+
+
+This module defines the following variables:
+
+``KDE3_DEFINITIONS``
+ compiler definitions required for compiling KDE software
+``KDE3_INCLUDE_DIR``
+ the KDE include directory
+``KDE3_INCLUDE_DIRS``
+ the KDE and the Qt include directory, for use with include_directories()
+``KDE3_LIB_DIR``
+ the directory where the KDE libraries are installed, for use with link_directories()
+``QT_AND_KDECORE_LIBS``
+ this contains both the Qt and the kdecore library
+``KDE3_DCOPIDL_EXECUTABLE``
+ the dcopidl executable
+``KDE3_DCOPIDL2CPP_EXECUTABLE``
+ the dcopidl2cpp executable
+``KDE3_KCFGC_EXECUTABLE``
+ the kconfig_compiler executable
+``KDE3_FOUND``
+ set to TRUE if all of the above has been found
+
+The following user adjustable options are provided:
+
+``KDE3_BUILD_TESTS``
+ enable this to build KDE testcases
+
+It also adds the following macros (from ``KDE3Macros.cmake``) ``SRCS_VAR`` is
+always the variable which contains the list of source files for your
+application or library.
+
+KDE3_AUTOMOC(file1 ... fileN)
+
+::
+
+ Call this if you want to have automatic moc file handling.
+ This means if you include "foo.moc" in the source file foo.cpp
+ a moc file for the header foo.h will be created automatically.
+ You can set the property SKIP_AUTOMAKE using set_source_files_properties()
+ to exclude some files in the list from being processed.
+
+
+
+KDE3_ADD_MOC_FILES(SRCS_VAR file1 ... fileN )
+
+::
+
+ If you don't use the KDE3_AUTOMOC() macro, for the files
+ listed here moc files will be created (named "foo.moc.cpp")
+
+
+
+KDE3_ADD_DCOP_SKELS(SRCS_VAR header1.h ... headerN.h )
+
+::
+
+ Use this to generate DCOP skeletions from the listed headers.
+
+
+
+KDE3_ADD_DCOP_STUBS(SRCS_VAR header1.h ... headerN.h )
+
+::
+
+ Use this to generate DCOP stubs from the listed headers.
+
+
+
+KDE3_ADD_UI_FILES(SRCS_VAR file1.ui ... fileN.ui )
+
+::
+
+ Use this to add the Qt designer ui files to your application/library.
+
+
+
+KDE3_ADD_KCFG_FILES(SRCS_VAR file1.kcfgc ... fileN.kcfgc )
+
+::
+
+ Use this to add KDE kconfig compiler files to your application/library.
+
+
+
+KDE3_INSTALL_LIBTOOL_FILE(target)
+
+::
+
+ This will create and install a simple libtool file for the given target.
+
+
+
+KDE3_ADD_EXECUTABLE(name file1 ... fileN )
+
+::
+
+ Currently identical to add_executable(), may provide some advanced
+ features in the future.
+
+
+
+KDE3_ADD_KPART(name [WITH_PREFIX] file1 ... fileN )
+
+::
+
+ Create a KDE plugin (KPart, kioslave, etc.) from the given source files.
+ If WITH_PREFIX is given, the resulting plugin will have the prefix "lib",
+ otherwise it won't.
+ It creates and installs an appropriate libtool la-file.
+
+
+
+KDE3_ADD_KDEINIT_EXECUTABLE(name file1 ... fileN )
+
+::
+
+ Create a KDE application in the form of a module loadable via kdeinit.
+ A library named kdeinit_<name> will be created and a small executable
+ which links to it.
+
+
+
+The option KDE3_ENABLE_FINAL to enable all-in-one compilation is no
+longer supported.
+
+
+
+Author: Alexander Neundorf <neundorf@kde.org>
+#]=======================================================================]
+
+if(NOT UNIX AND KDE3_FIND_REQUIRED)
+ message(FATAL_ERROR "Compiling KDE3 applications and libraries under Windows is not supported")
+endif()
+
+# If Qt4 has already been found, fail.
+if(QT4_FOUND)
+ if(KDE3_FIND_REQUIRED)
+ message( FATAL_ERROR "KDE3/Qt3 and Qt4 cannot be used together in one project.")
+ else()
+ if(NOT KDE3_FIND_QUIETLY)
+ message( STATUS "KDE3/Qt3 and Qt4 cannot be used together in one project.")
+ endif()
+ return()
+ endif()
+endif()
+
+
+set(QT_MT_REQUIRED TRUE)
+#set(QT_MIN_VERSION "3.0.0")
+
+#this line includes FindQt.cmake, which searches the Qt library and headers
+if(KDE3_FIND_REQUIRED)
+ set(_REQ_STRING_KDE3 "REQUIRED")
+endif()
+
+find_package(Qt3 ${_REQ_STRING_KDE3})
+find_package(X11 ${_REQ_STRING_KDE3})
+
+
+#now try to find some kde stuff
+find_program(KDECONFIG_EXECUTABLE NAMES kde-config
+ HINTS
+ $ENV{KDEDIR}/bin
+ PATHS
+ /opt/kde3/bin
+ /opt/kde/bin
+ )
+
+set(KDE3PREFIX)
+if(KDECONFIG_EXECUTABLE)
+ execute_process(COMMAND ${KDECONFIG_EXECUTABLE} --version
+ OUTPUT_VARIABLE kde_config_version )
+
+ string(REGEX MATCH "KDE: .\\." kde_version "${kde_config_version}")
+ if ("${kde_version}" MATCHES "KDE: 3\\.")
+ execute_process(COMMAND ${KDECONFIG_EXECUTABLE} --prefix
+ OUTPUT_VARIABLE kdedir )
+ string(REPLACE "\n" "" KDE3PREFIX "${kdedir}")
+
+ endif ()
+endif()
+
+
+
+# at first the KDE include directory
+# kpassdlg.h comes from kdeui and doesn't exist in KDE4 anymore
+find_path(KDE3_INCLUDE_DIR kpassdlg.h
+ HINTS
+ $ENV{KDEDIR}/include
+ ${KDE3PREFIX}/include
+ PATHS
+ /opt/kde3/include
+ /opt/kde/include
+ PATH_SUFFIXES include/kde
+ )
+
+#now the KDE library directory
+find_library(KDE3_KDECORE_LIBRARY NAMES kdecore
+ HINTS
+ $ENV{KDEDIR}/lib
+ ${KDE3PREFIX}/lib
+ PATHS
+ /opt/kde3/lib
+ /opt/kde/lib
+)
+
+set(QT_AND_KDECORE_LIBS ${QT_LIBRARIES} ${KDE3_KDECORE_LIBRARY})
+
+get_filename_component(KDE3_LIB_DIR ${KDE3_KDECORE_LIBRARY} PATH )
+
+if(NOT KDE3_LIBTOOL_DIR)
+ if(KDE3_KDECORE_LIBRARY MATCHES lib64)
+ set(KDE3_LIBTOOL_DIR /lib64/kde3)
+ elseif(KDE3_KDECORE_LIBRARY MATCHES libx32)
+ set(KDE3_LIBTOOL_DIR /libx32/kde3)
+ else()
+ set(KDE3_LIBTOOL_DIR /lib/kde3)
+ endif()
+endif()
+
+#now search for the dcop utilities
+find_program(KDE3_DCOPIDL_EXECUTABLE NAMES dcopidl
+ HINTS
+ $ENV{KDEDIR}/bin
+ ${KDE3PREFIX}/bin
+ PATHS
+ /opt/kde3/bin
+ /opt/kde/bin
+ )
+
+find_program(KDE3_DCOPIDL2CPP_EXECUTABLE NAMES dcopidl2cpp
+ HINTS
+ $ENV{KDEDIR}/bin
+ ${KDE3PREFIX}/bin
+ PATHS
+ /opt/kde3/bin
+ /opt/kde/bin
+ )
+
+find_program(KDE3_KCFGC_EXECUTABLE NAMES kconfig_compiler
+ HINTS
+ $ENV{KDEDIR}/bin
+ ${KDE3PREFIX}/bin
+ PATHS
+ /opt/kde3/bin
+ /opt/kde/bin
+ )
+
+
+#SET KDE3_FOUND
+if (KDE3_INCLUDE_DIR AND KDE3_LIB_DIR AND KDE3_DCOPIDL_EXECUTABLE AND KDE3_DCOPIDL2CPP_EXECUTABLE AND KDE3_KCFGC_EXECUTABLE)
+ set(KDE3_FOUND TRUE)
+else ()
+ set(KDE3_FOUND FALSE)
+endif ()
+
+# add some KDE specific stuff
+set(KDE3_DEFINITIONS -DQT_CLEAN_NAMESPACE -D_GNU_SOURCE)
+
+# set compiler flags only if KDE3 has actually been found
+if(KDE3_FOUND)
+ set(_KDE3_USE_FLAGS FALSE)
+ if(CMAKE_COMPILER_IS_GNUCXX)
+ set(_KDE3_USE_FLAGS TRUE) # use flags for gnu compiler
+ execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version
+ OUTPUT_VARIABLE out)
+ # gnu gcc 2.96 does not work with flags
+ # I guess 2.95 also doesn't then
+ if("${out}" MATCHES "2.9[56]")
+ set(_KDE3_USE_FLAGS FALSE)
+ endif()
+ endif()
+
+ #only on linux, but NOT e.g. on FreeBSD:
+ if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND _KDE3_USE_FLAGS)
+ set (KDE3_DEFINITIONS ${KDE3_DEFINITIONS} -D_XOPEN_SOURCE=500 -D_BSD_SOURCE)
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-long-long -ansi -Wundef -Wcast-align -Wconversion -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute -fno-common")
+ set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -ansi -Wundef -Wcast-align -Wconversion -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -fno-exceptions -fno-check-new -fno-common")
+ endif()
+
+ # works on FreeBSD, NOT tested on NetBSD and OpenBSD
+ if (CMAKE_SYSTEM_NAME MATCHES BSD AND _KDE3_USE_FLAGS)
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-long-long -ansi -Wundef -Wcast-align -Wconversion -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute -fno-common")
+ set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -Wundef -Wcast-align -Wconversion -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute -fno-exceptions -fno-check-new -fno-common")
+ endif ()
+
+ # if no special buildtype is selected, add -O2 as default optimization
+ if (NOT CMAKE_BUILD_TYPE AND _KDE3_USE_FLAGS)
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
+ set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
+ endif ()
+
+#set(CMAKE_SHARED_LINKER_FLAGS "-avoid-version -module -Wl,--no-undefined -Wl,--allow-shlib-undefined")
+#set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--fatal-warnings -avoid-version -Wl,--no-undefined -lc")
+#set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--fatal-warnings -avoid-version -Wl,--no-undefined -lc")
+endif()
+
+
+# KDE3Macros.cmake contains all the KDE specific macros
+include(${CMAKE_CURRENT_LIST_DIR}/KDE3Macros.cmake)
+
+
+macro (KDE3_PRINT_RESULTS)
+ if(KDE3_INCLUDE_DIR)
+ message(STATUS "Found KDE3 include dir: ${KDE3_INCLUDE_DIR}")
+ else()
+ message(STATUS "Didn't find KDE3 headers")
+ endif()
+
+ if(KDE3_LIB_DIR)
+ message(STATUS "Found KDE3 library dir: ${KDE3_LIB_DIR}")
+ else()
+ message(STATUS "Didn't find KDE3 core library")
+ endif()
+
+ if(KDE3_DCOPIDL_EXECUTABLE)
+ message(STATUS "Found KDE3 dcopidl preprocessor: ${KDE3_DCOPIDL_EXECUTABLE}")
+ else()
+ message(STATUS "Didn't find the KDE3 dcopidl preprocessor")
+ endif()
+
+ if(KDE3_DCOPIDL2CPP_EXECUTABLE)
+ message(STATUS "Found KDE3 dcopidl2cpp preprocessor: ${KDE3_DCOPIDL2CPP_EXECUTABLE}")
+ else()
+ message(STATUS "Didn't find the KDE3 dcopidl2cpp preprocessor")
+ endif()
+
+ if(KDE3_KCFGC_EXECUTABLE)
+ message(STATUS "Found KDE3 kconfig_compiler preprocessor: ${KDE3_KCFGC_EXECUTABLE}")
+ else()
+ message(STATUS "Didn't find the KDE3 kconfig_compiler preprocessor")
+ endif()
+
+endmacro ()
+
+
+if (KDE3_FIND_REQUIRED AND NOT KDE3_FOUND)
+ #bail out if something wasn't found
+ KDE3_PRINT_RESULTS()
+ message(FATAL_ERROR "Could NOT find everything required for compiling KDE 3 programs")
+
+endif ()
+
+
+if (NOT KDE3_FIND_QUIETLY)
+ KDE3_PRINT_RESULTS()
+endif ()
+
+#add the found Qt and KDE include directories to the current include path
+set(KDE3_INCLUDE_DIRS ${QT_INCLUDE_DIR} ${KDE3_INCLUDE_DIR})
diff --git a/Modules/FindKDE4.cmake b/Modules/FindKDE4.cmake
new file mode 100644
index 0000000..695e9ac
--- /dev/null
+++ b/Modules/FindKDE4.cmake
@@ -0,0 +1,103 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindKDE4
+--------
+
+
+
+Find KDE4 and provide all necessary variables and macros to compile
+software for it. It looks for KDE 4 in the following directories in
+the given order:
+
+::
+
+ CMAKE_INSTALL_PREFIX
+ KDEDIRS
+ /opt/kde4
+
+
+
+Please look in ``FindKDE4Internal.cmake`` and ``KDE4Macros.cmake`` for more
+information. They are installed with the KDE 4 libraries in
+$KDEDIRS/share/apps/cmake/modules/.
+
+Author: Alexander Neundorf <neundorf@kde.org>
+#]=======================================================================]
+
+# If Qt3 has already been found, fail.
+if(QT_QT_LIBRARY)
+ if(KDE4_FIND_REQUIRED)
+ message( FATAL_ERROR "KDE4/Qt4 and Qt3 cannot be used together in one project.")
+ else()
+ if(NOT KDE4_FIND_QUIETLY)
+ message( STATUS "KDE4/Qt4 and Qt3 cannot be used together in one project.")
+ endif()
+ return()
+ endif()
+endif()
+
+file(TO_CMAKE_PATH "$ENV{KDEDIRS}" _KDEDIRS)
+
+# when cross compiling, searching kde4-config in order to run it later on
+# doesn't make a lot of sense. We'll have to do something about this.
+# Searching always in the target environment ? Then we get at least the correct one,
+# still it can't be used to run it. Alex
+
+# For KDE4 kde-config has been renamed to kde4-config
+find_program(KDE4_KDECONFIG_EXECUTABLE NAMES kde4-config
+ # the suffix must be used since KDEDIRS can be a list of directories which don't have bin/ appended
+ PATH_SUFFIXES bin
+ HINTS
+ ${CMAKE_INSTALL_PREFIX}
+ ${_KDEDIRS}
+ /opt/kde4
+ ONLY_CMAKE_FIND_ROOT_PATH
+ )
+
+if (NOT KDE4_KDECONFIG_EXECUTABLE)
+ if (KDE4_FIND_REQUIRED)
+ message(FATAL_ERROR "ERROR: Could not find KDE4 kde4-config")
+ endif ()
+endif ()
+
+
+# when cross compiling, KDE4_DATA_DIR may be already preset
+if(NOT KDE4_DATA_DIR)
+ if(CMAKE_CROSSCOMPILING)
+ # when cross compiling, don't run kde4-config but use its location as install dir
+ get_filename_component(KDE4_DATA_DIR "${KDE4_KDECONFIG_EXECUTABLE}" PATH)
+ get_filename_component(KDE4_DATA_DIR "${KDE4_DATA_DIR}" PATH)
+ else()
+ # then ask kde4-config for the kde data dirs
+
+ if(KDE4_KDECONFIG_EXECUTABLE)
+ execute_process(COMMAND "${KDE4_KDECONFIG_EXECUTABLE}" --path data OUTPUT_VARIABLE _data_DIR ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
+ file(TO_CMAKE_PATH "${_data_DIR}" _data_DIR)
+ # then check the data dirs for FindKDE4Internal.cmake
+ find_path(KDE4_DATA_DIR cmake/modules/FindKDE4Internal.cmake HINTS ${_data_DIR})
+ endif()
+ endif()
+endif()
+
+# if it has been found...
+if (KDE4_DATA_DIR)
+
+ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${KDE4_DATA_DIR}/cmake/modules)
+
+ if (KDE4_FIND_QUIETLY)
+ set(_quiet QUIET)
+ endif ()
+
+ if (KDE4_FIND_REQUIRED)
+ set(_req REQUIRED)
+ endif ()
+
+ # use FindKDE4Internal.cmake to do the rest
+ find_package(KDE4Internal ${_req} ${_quiet} NO_POLICY_SCOPE)
+else ()
+ if (KDE4_FIND_REQUIRED)
+ message(FATAL_ERROR "ERROR: cmake/modules/FindKDE4Internal.cmake not found in ${_data_DIR}")
+ endif ()
+endif ()
diff --git a/Modules/FindLAPACK.cmake b/Modules/FindLAPACK.cmake
new file mode 100644
index 0000000..a5b16ca
--- /dev/null
+++ b/Modules/FindLAPACK.cmake
@@ -0,0 +1,682 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLAPACK
+----------
+
+Find Linear Algebra PACKage (LAPACK) library
+
+This module finds an installed Fortran library that implements the
+LAPACK linear-algebra interface (see http://www.netlib.org/lapack/).
+
+The approach follows that taken for the ``autoconf`` macro file,
+``acx_lapack.m4`` (distributed at
+http://ac-archive.sourceforge.net/ac-archive/acx_lapack.html).
+
+Input Variables
+^^^^^^^^^^^^^^^
+
+The following variables may be set to influence this module's behavior:
+
+``BLA_STATIC``
+ if ``ON`` use static linkage
+
+``BLA_VENDOR``
+ If set, checks only the specified vendor, if not set checks all the
+ possibilities. List of vendors valid in this module:
+
+ * ``FlexiBLAS``
+ * ``OpenBLAS``
+ * ``FLAME``
+ * ``Intel10_32`` (intel mkl v10 32 bit, threaded code)
+ * ``Intel10_64lp`` (intel mkl v10+ 64 bit, threaded code, lp64 model)
+ * ``Intel10_64lp_seq`` (intel mkl v10+ 64 bit, sequential code, lp64 model)
+ * ``Intel10_64ilp`` (intel mkl v10+ 64 bit, threaded code, ilp64 model)
+ * ``Intel10_64ilp_seq`` (intel mkl v10+ 64 bit, sequential code, ilp64 model)
+ * ``Intel10_64_dyn`` (intel mkl v10+ 64 bit, single dynamic library)
+ * ``Intel`` (obsolete versions of mkl 32 and 64 bit)
+ * ``ACML``
+ * ``Apple``
+ * ``NAS``
+ * ``Arm``
+ * ``Arm_mp``
+ * ``Arm_ilp64``
+ * ``Arm_ilp64_mp``
+ * ``EML``
+ * ``EML_mt``
+ * ``Fujitsu_SSL2`` (Fujitsu serial blas / lapack)
+ * ``Fujitsu_SSL2BLAMP`` (Fujitsu parallel blas / lapack)
+ * ``Generic``
+
+ .. versionadded:: 3.6
+ ``OpenBLAS`` support.
+
+ .. versionadded:: 3.11
+ ``FLAME`` support.
+
+ .. versionadded:: 3.13
+ Added ILP64 MKL variants (``Intel10_64ilp``, ``Intel10_64ilp_seq``).
+
+ .. versionadded:: 3.17
+ Added single dynamic library MKL variant (``Intel10_64_dyn``).
+
+ .. versionadded:: 3.18
+ Arm Performance Libraries support (``Arm``, ``Arm_mp``, ``Arm_ilp64``,
+ ``Arm_ilp64_mp``).
+
+ .. versionadded:: 3.19
+ ``FlexiBLAS`` support.
+
+ .. versionadded:: 3.20
+ Elbrus Math Library support (``EML``, ``EML_mt``).
+ Fujitsu SSL2 Library support (``Fujitsu_SSL2``, ``Fujitsu_SSL2BLAMP``)
+
+``BLA_F95``
+ if ``ON`` tries to find the BLAS95/LAPACK95 interfaces
+
+``BLA_PREFER_PKGCONFIG``
+ .. versionadded:: 3.20
+
+ if set ``pkg-config`` will be used to search for a LAPACK library first
+ and if one is found that is preferred
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.18
+
+This module defines the following :prop_tgt:`IMPORTED` target:
+
+``LAPACK::LAPACK``
+ The libraries to use for LAPACK, if found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``LAPACK_FOUND``
+ library implementing the LAPACK interface is found
+``LAPACK_LINKER_FLAGS``
+ uncached list of required linker flags (excluding ``-l`` and ``-L``).
+``LAPACK_LIBRARIES``
+ uncached list of libraries (using full path name) to link against
+ to use LAPACK
+``LAPACK95_LIBRARIES``
+ uncached list of libraries (using full path name) to link against
+ to use LAPACK95
+``LAPACK95_FOUND``
+ library implementing the LAPACK95 interface is found
+
+.. note::
+
+ C, CXX or Fortran must be enabled to detect a BLAS/LAPACK library.
+ C or CXX must be enabled to use Intel Math Kernel Library (MKL).
+
+ For example, to use Intel MKL libraries and/or Intel compiler:
+
+ .. code-block:: cmake
+
+ set(BLA_VENDOR Intel10_64lp)
+ find_package(LAPACK)
+#]=======================================================================]
+
+if(CMAKE_Fortran_COMPILER_LOADED)
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckFortranFunctionExists.cmake)
+else()
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckFunctionExists.cmake)
+endif()
+include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+function(_add_lapack_target)
+ if(LAPACK_FOUND AND NOT TARGET LAPACK::LAPACK)
+ add_library(LAPACK::LAPACK INTERFACE IMPORTED)
+
+ # Filter out redundant BLAS info and replace with the BLAS target
+ set(_lapack_libs "${LAPACK_LIBRARIES}")
+ set(_lapack_flags "${LAPACK_LINKER_FLAGS}")
+ if(TARGET BLAS::BLAS)
+ if(_lapack_libs AND BLAS_LIBRARIES)
+ foreach(_blas_lib IN LISTS BLAS_LIBRARIES)
+ list(REMOVE_ITEM _lapack_libs "${_blas_lib}")
+ endforeach()
+ endif()
+ if(_lapack_flags AND BLAS_LINKER_FLAGS)
+ foreach(_blas_flag IN LISTS BLAS_LINKER_FLAGS)
+ list(REMOVE_ITEM _lapack_flags "${_blas_flag}")
+ endforeach()
+ endif()
+ list(APPEND _lapack_libs BLAS::BLAS)
+ endif()
+ if(_lapack_libs)
+ set_target_properties(LAPACK::LAPACK PROPERTIES
+ INTERFACE_LINK_LIBRARIES "${_lapack_libs}"
+ )
+ endif()
+ if(_lapack_flags)
+ set_target_properties(LAPACK::LAPACK PROPERTIES
+ INTERFACE_LINK_OPTIONS "${_lapack_flags}"
+ )
+ endif()
+ endif()
+endfunction()
+
+macro(_lapack_find_library_setup)
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_QUIET ${LAPACK_FIND_QUIETLY})
+
+ set(_lapack_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ if(BLA_STATIC)
+ if(WIN32)
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ else()
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ endif()
+ else()
+ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ # for ubuntu's libblas3gf and liblapack3gf packages
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} .so.3gf)
+ endif()
+ endif()
+endmacro()
+
+macro(_lapack_find_library_teardown)
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ${_lapack_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
+ unset(_lapack_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES)
+ cmake_pop_check_state()
+endmacro()
+
+# TODO: move this stuff to a separate module
+
+macro(CHECK_LAPACK_LIBRARIES LIBRARIES _prefix _name _flags _list _threadlibs _addlibdir _subdirs _blas)
+ # This macro checks for the existence of the combination of fortran libraries
+ # given by _list. If the combination is found, this macro checks (using the
+ # Check_Fortran_Function_Exists macro) whether can link against that library
+ # combination using the name of a routine given by _name using the linker
+ # flags given by _flags. If the combination of libraries is found and passes
+ # the link test, LIBRARIES is set to the list of complete library paths that
+ # have been found. Otherwise, LIBRARIES is set to FALSE.
+
+ # N.B. _prefix is the prefix applied to the names of all cached variables that
+ # are generated internally and marked advanced by this macro.
+ # _addlibdir is a list of additional search paths. _subdirs is a list of path
+ # suffixes to be used by find_library().
+
+ set(_libraries_work TRUE)
+ set(${LIBRARIES})
+ set(_combined_name)
+
+ set(_extaddlibdir "${_addlibdir}")
+ if(WIN32)
+ list(APPEND _extaddlibdir ENV LIB)
+ elseif(APPLE)
+ list(APPEND _extaddlibdir ENV DYLD_LIBRARY_PATH)
+ else()
+ list(APPEND _extaddlibdir ENV LD_LIBRARY_PATH)
+ endif()
+ list(APPEND _extaddlibdir "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}")
+
+ foreach(_library ${_list} ${_threadlibs})
+ if(_library MATCHES "^-Wl,--(start|end)-group$")
+ # Respect linker flags like --start/end-group (required by MKL)
+ set(${LIBRARIES} ${${LIBRARIES}} "${_library}")
+ else()
+ string(REGEX REPLACE "[^A-Za-z0-9]" "_" _lib_var "${_library}")
+ set(_combined_name ${_combined_name}_${_lib_var})
+ if(_libraries_work)
+ find_library(${_prefix}_${_lib_var}_LIBRARY
+ NAMES ${_library}
+ NAMES_PER_DIR
+ PATHS ${_extaddlibdir}
+ PATH_SUFFIXES ${_subdirs}
+ )
+ mark_as_advanced(${_prefix}_${_lib_var}_LIBRARY)
+ set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_lib_var}_LIBRARY})
+ set(_libraries_work ${${_prefix}_${_lib_var}_LIBRARY})
+ endif()
+ endif()
+ endforeach()
+ unset(_library)
+
+ foreach(_flag ${_flags})
+ string(REGEX REPLACE "[^A-Za-z0-9]" "_" _flag_var "${_flag}")
+ set(_combined_name ${_combined_name}_${_flag_var})
+ endforeach()
+ if(_libraries_work)
+ # Test this combination of libraries.
+ set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_blas} ${_threadlibs})
+ if(CMAKE_Fortran_COMPILER_LOADED)
+ check_fortran_function_exists("${_name}" ${_prefix}${_combined_name}_WORKS)
+ else()
+ check_function_exists("${_name}_" ${_prefix}${_combined_name}_WORKS)
+ endif()
+ set(CMAKE_REQUIRED_LIBRARIES)
+ set(_libraries_work ${${_prefix}${_combined_name}_WORKS})
+ endif()
+
+ if(_libraries_work)
+ if("${_list}${_blas}" STREQUAL "")
+ set(${LIBRARIES} "${LIBRARIES}-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
+ else()
+ set(${LIBRARIES} ${${LIBRARIES}} ${_blas} ${_threadlibs})
+ endif()
+ else()
+ set(${LIBRARIES} FALSE)
+ endif()
+
+ unset(_extaddlibdir)
+ unset(_libraries_work)
+ unset(_combined_name)
+endmacro()
+
+macro(_lapack_find_dependency dep)
+ set(_lapack_quiet_arg)
+ if(LAPACK_FIND_QUIETLY)
+ set(_lapack_quiet_arg QUIET)
+ endif()
+ set(_lapack_required_arg)
+ if(LAPACK_FIND_REQUIRED)
+ set(_lapack_required_arg REQUIRED)
+ endif()
+ find_package(${dep} ${ARGN}
+ ${_lapack_quiet_arg}
+ ${_lapack_required_arg}
+ )
+ if (NOT ${dep}_FOUND)
+ set(LAPACK_NOT_FOUND_MESSAGE "LAPACK could not be found because dependency ${dep} could not be found.")
+ endif()
+
+ set(_lapack_required_arg)
+ set(_lapack_quiet_arg)
+endmacro()
+
+_lapack_find_library_setup()
+
+set(LAPACK_LINKER_FLAGS)
+set(LAPACK_LIBRARIES)
+set(LAPACK95_LIBRARIES)
+set(_lapack_fphsa_req_var LAPACK_LIBRARIES)
+
+# Check the language being used
+if(NOT (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED))
+ set(LAPACK_NOT_FOUND_MESSAGE
+ "FindLAPACK requires Fortran, C, or C++ to be enabled.")
+endif()
+
+# Load BLAS
+if(NOT LAPACK_NOT_FOUND_MESSAGE)
+ _lapack_find_dependency(BLAS)
+endif()
+
+# Search with pkg-config if specified
+if(BLA_PREFER_PKGCONFIG)
+ find_package(PkgConfig)
+ pkg_check_modules(PKGC_LAPACK lapack)
+ if(PKGC_LAPACK_FOUND)
+ set(LAPACK_FOUND TRUE)
+ set(LAPACK_LIBRARIES "${PKGC_LAPACK_LINK_LIBRARIES}")
+ if (BLAS_LIBRARIES)
+ list(APPEND LAPACK_LIBRARIES "${BLAS_LIBRARIES}")
+ endif()
+ _add_lapack_target()
+ return()
+ endif()
+endif()
+
+# Search for different LAPACK distributions if BLAS is found
+if(NOT LAPACK_NOT_FOUND_MESSAGE)
+ set(LAPACK_LINKER_FLAGS ${BLAS_LINKER_FLAGS})
+ if(NOT $ENV{BLA_VENDOR} STREQUAL "")
+ set(BLA_VENDOR $ENV{BLA_VENDOR})
+ elseif(NOT BLA_VENDOR)
+ set(BLA_VENDOR "All")
+ endif()
+
+ # LAPACK in the Intel MKL 10+ library?
+ if(NOT LAPACK_LIBRARIES
+ AND (BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
+ AND (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED))
+ # System-specific settings
+ if(NOT WIN32)
+ set(LAPACK_mkl_LM "-lm")
+ set(LAPACK_mkl_LDL "-ldl")
+ endif()
+
+ _lapack_find_dependency(Threads)
+
+ if(BLA_VENDOR MATCHES "_64ilp")
+ set(LAPACK_mkl_ILP_MODE "ilp64")
+ else()
+ set(LAPACK_mkl_ILP_MODE "lp64")
+ endif()
+
+ set(LAPACK_SEARCH_LIBS "")
+
+ if(BLA_F95)
+ set(LAPACK_mkl_SEARCH_SYMBOL "cheev_f95")
+ set(_LIBRARIES LAPACK95_LIBRARIES)
+ set(_BLAS_LIBRARIES ${BLAS95_LIBRARIES})
+
+ # old
+ list(APPEND LAPACK_SEARCH_LIBS
+ "mkl_lapack95")
+ # new >= 10.3
+ list(APPEND LAPACK_SEARCH_LIBS
+ "mkl_intel_c")
+ list(APPEND LAPACK_SEARCH_LIBS
+ "mkl_lapack95_${LAPACK_mkl_ILP_MODE}")
+ else()
+ set(LAPACK_mkl_SEARCH_SYMBOL "cheev")
+ set(_LIBRARIES LAPACK_LIBRARIES)
+ set(_BLAS_LIBRARIES ${BLAS_LIBRARIES})
+
+ # old and new >= 10.3
+ list(APPEND LAPACK_SEARCH_LIBS
+ "mkl_lapack")
+ endif()
+
+ # MKL uses a multitude of partially platform-specific subdirectories:
+ if(BLA_VENDOR STREQUAL "Intel10_32")
+ set(LAPACK_mkl_ARCH_NAME "ia32")
+ else()
+ set(LAPACK_mkl_ARCH_NAME "intel64")
+ endif()
+ if(WIN32)
+ set(LAPACK_mkl_OS_NAME "win")
+ elseif(APPLE)
+ set(LAPACK_mkl_OS_NAME "mac")
+ else()
+ set(LAPACK_mkl_OS_NAME "lin")
+ endif()
+ if(DEFINED ENV{MKLROOT})
+ file(TO_CMAKE_PATH "$ENV{MKLROOT}" LAPACK_mkl_MKLROOT)
+ # If MKLROOT points to the subdirectory 'mkl', use the parent directory instead
+ # so we can better detect other relevant libraries in 'compiler' or 'tbb':
+ get_filename_component(LAPACK_mkl_MKLROOT_LAST_DIR "${LAPACK_mkl_MKLROOT}" NAME)
+ if(LAPACK_mkl_MKLROOT_LAST_DIR STREQUAL "mkl")
+ get_filename_component(LAPACK_mkl_MKLROOT "${LAPACK_mkl_MKLROOT}" DIRECTORY)
+ endif()
+ endif()
+ set(LAPACK_mkl_LIB_PATH_SUFFIXES
+ "compiler/lib" "compiler/lib/${LAPACK_mkl_ARCH_NAME}_${LAPACK_mkl_OS_NAME}"
+ "compiler/lib/${LAPACK_mkl_ARCH_NAME}"
+ "mkl/lib" "mkl/lib/${LAPACK_mkl_ARCH_NAME}_${LAPACK_mkl_OS_NAME}"
+ "mkl/lib/${LAPACK_mkl_ARCH_NAME}"
+ "lib/${LAPACK_mkl_ARCH_NAME}_${LAPACK_mkl_OS_NAME}")
+
+ # First try empty lapack libs
+ if(NOT ${_LIBRARIES})
+ check_lapack_libraries(
+ ${_LIBRARIES}
+ LAPACK
+ ${LAPACK_mkl_SEARCH_SYMBOL}
+ ""
+ ""
+ "${CMAKE_THREAD_LIBS_INIT};${LAPACK_mkl_LM};${LAPACK_mkl_LDL}"
+ "${LAPACK_mkl_MKLROOT}"
+ "${LAPACK_mkl_LIB_PATH_SUFFIXES}"
+ "${_BLAS_LIBRARIES}"
+ )
+ endif()
+
+ # Then try the search libs
+ foreach(IT ${LAPACK_SEARCH_LIBS})
+ string(REPLACE " " ";" SEARCH_LIBS ${IT})
+ if(NOT ${_LIBRARIES})
+ check_lapack_libraries(
+ ${_LIBRARIES}
+ LAPACK
+ ${LAPACK_mkl_SEARCH_SYMBOL}
+ ""
+ "${SEARCH_LIBS}"
+ "${CMAKE_THREAD_LIBS_INIT};${LAPACK_mkl_LM};${LAPACK_mkl_LDL}"
+ "${LAPACK_mkl_MKLROOT}"
+ "${LAPACK_mkl_LIB_PATH_SUFFIXES}"
+ "${_BLAS_LIBRARIES}"
+ )
+ endif()
+ endforeach()
+
+ unset(LAPACK_mkl_ILP_MODE)
+ unset(LAPACK_mkl_SEARCH_SYMBOL)
+ unset(LAPACK_mkl_LM)
+ unset(LAPACK_mkl_LDL)
+ unset(LAPACK_mkl_MKLROOT)
+ unset(LAPACK_mkl_ARCH_NAME)
+ unset(LAPACK_mkl_OS_NAME)
+ unset(LAPACK_mkl_LIB_PATH_SUFFIXES)
+ endif()
+
+ # gotoblas? (http://www.tacc.utexas.edu/tacc-projects/gotoblas2)
+ if(NOT LAPACK_LIBRARIES
+ AND (BLA_VENDOR STREQUAL "Goto" OR BLA_VENDOR STREQUAL "All"))
+ check_lapack_libraries(
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "goto2"
+ ""
+ ""
+ ""
+ "${BLAS_LIBRARIES}"
+ )
+ endif()
+
+ # FlexiBLAS? (http://www.mpi-magdeburg.mpg.de/mpcsc/software/FlexiBLAS/)
+ if(NOT LAPACK_LIBRARIES
+ AND (BLA_VENDOR STREQUAL "FlexiBLAS" OR BLA_VENDOR STREQUAL "All"))
+ check_lapack_libraries(
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "flexiblas"
+ ""
+ ""
+ ""
+ "${BLAS_LIBRARIES}"
+ )
+ endif()
+
+ # OpenBLAS? (http://www.openblas.net)
+ if(NOT LAPACK_LIBRARIES
+ AND (BLA_VENDOR STREQUAL "OpenBLAS" OR BLA_VENDOR STREQUAL "All"))
+ check_lapack_libraries(
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "openblas"
+ ""
+ ""
+ ""
+ "${BLAS_LIBRARIES}"
+ )
+ endif()
+
+ # ArmPL? (https://developer.arm.com/tools-and-software/server-and-hpc/compile/arm-compiler-for-linux/arm-performance-libraries)
+ if(NOT LAPACK_LIBRARIES
+ AND (BLA_VENDOR MATCHES "Arm" OR BLA_VENDOR STREQUAL "All"))
+ # Check for 64bit Integer support
+ if(BLA_VENDOR MATCHES "_ilp64")
+ set(LAPACK_armpl_LIB "armpl_ilp64")
+ else()
+ set(LAPACK_armpl_LIB "armpl_lp64")
+ endif()
+
+ # Check for OpenMP support, VIA BLA_VENDOR of Arm_mp or Arm_ipl64_mp
+ if(BLA_VENDOR MATCHES "_mp")
+ set(LAPACK_armpl_LIB "${LAPACK_armpl_LIB}_mp")
+ endif()
+
+ check_lapack_libraries(
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "${LAPACK_armpl_LIB}"
+ ""
+ ""
+ ""
+ "${BLAS_LIBRARIES}"
+ )
+ endif()
+
+ # FLAME's blis library? (https://github.com/flame/blis)
+ if(NOT LAPACK_LIBRARIES
+ AND (BLA_VENDOR STREQUAL "FLAME" OR BLA_VENDOR STREQUAL "All"))
+ check_lapack_libraries(
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "flame"
+ ""
+ ""
+ ""
+ "${BLAS_LIBRARIES}"
+ )
+ endif()
+
+ # BLAS in acml library?
+ if(BLA_VENDOR MATCHES "ACML" OR BLA_VENDOR STREQUAL "All")
+ if(BLAS_LIBRARIES MATCHES ".+acml.+")
+ set(LAPACK_LIBRARIES ${BLAS_LIBRARIES})
+ endif()
+ endif()
+
+ # Apple LAPACK library?
+ if(NOT LAPACK_LIBRARIES
+ AND (BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All"))
+ check_lapack_libraries(
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "Accelerate"
+ ""
+ ""
+ ""
+ "${BLAS_LIBRARIES}"
+ )
+ endif()
+
+ # Apple NAS (vecLib) library?
+ if(NOT LAPACK_LIBRARIES
+ AND (BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All"))
+ check_lapack_libraries(
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "vecLib"
+ ""
+ ""
+ ""
+ "${BLAS_LIBRARIES}"
+ )
+ endif()
+
+ # Elbrus Math Library?
+ if(NOT LAPACK_LIBRARIES
+ AND (BLA_VENDOR MATCHES "EML" OR BLA_VENDOR STREQUAL "All"))
+
+ set(LAPACK_EML_LIB "eml")
+
+ # Check for OpenMP support, VIA BLA_VENDOR of eml_mt
+ if(BLA_VENDOR MATCHES "_mt")
+ set(LAPACK_EML_LIB "${LAPACK_EML_LIB}_mt")
+ endif()
+
+ check_lapack_libraries(
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "${LAPACK_EML_LIB}"
+ ""
+ ""
+ ""
+ "${BLAS_LIBRARIES}"
+ )
+ endif()
+
+ # Fujitsu SSL2 Library?
+ if(NOT LAPACK_LIBRARIES
+ AND BLA_VENDOR MATCHES "Fujitsu_SSL2" OR BLA_VENDOR STREQUAL "All")
+ if(BLA_VENDOR STREQUAL "Fujitsu_SSL2BLAMP")
+ set(_ssl2_suffix BLAMP)
+ else()
+ set(_ssl2_suffix)
+ endif()
+ set(_ssl2_blas)
+ if(BLAS_LIBRARIES STREQUAL "")
+ set(_ssl2_blas "${BLAS_LINKER_FLAGS}")
+ else()
+ set(_ssl2_blas "${BLAS_LIBRARIES} ${BLAS_LINKER_FLAGS}")
+ endif()
+ check_lapack_libraries(
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ "-SSL2${_ssl2_suffix}"
+ ""
+ ""
+ ""
+ ""
+ "${_ssl2_blas}"
+ )
+ if(LAPACK_LIBRARIES)
+ set(LAPACK_LINKER_FLAGS "-SSL2${_ssl2_suffix}")
+ set(_lapack_fphsa_req_var LAPACK_LINKER_FLAGS)
+ endif()
+ unset(_ssl2_suffix)
+ endif()
+
+ # Generic LAPACK library?
+ if(NOT LAPACK_LIBRARIES
+ AND (BLA_VENDOR STREQUAL "Generic"
+ OR BLA_VENDOR STREQUAL "ATLAS"
+ OR BLA_VENDOR STREQUAL "All"))
+ check_lapack_libraries(
+ LAPACK_LIBRARIES
+ LAPACK
+ cheev
+ ""
+ "lapack"
+ ""
+ ""
+ ""
+ "${BLAS_LIBRARIES}"
+ )
+ endif()
+endif()
+
+if(BLA_F95)
+ set(LAPACK_LIBRARIES "${LAPACK95_LIBRARIES}")
+endif()
+
+if(LAPACK_NOT_FOUND_MESSAGE)
+ set(LAPACK_NOT_FOUND_MESSAGE
+ REASON_FAILURE_MESSAGE ${LAPACK_NOT_FOUND_MESSAGE})
+endif()
+find_package_handle_standard_args(LAPACK REQUIRED_VARS ${_lapack_fphsa_req_var}
+ ${LAPACK_NOT_FOUND_MESSAGE})
+unset(LAPACK_NOT_FOUND_MESSAGE)
+
+if(BLA_F95)
+ set(LAPACK95_FOUND ${LAPACK_FOUND})
+endif()
+
+# On compilers that implicitly link LAPACK (such as ftn, cc, and CC on Cray HPC machines)
+# we used a placeholder for empty LAPACK_LIBRARIES to get through our logic above.
+if(LAPACK_LIBRARIES STREQUAL "LAPACK_LIBRARIES-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
+ set(LAPACK_LIBRARIES "")
+endif()
+
+_add_lapack_target()
+
+_lapack_find_library_teardown()
diff --git a/Modules/FindLATEX.cmake b/Modules/FindLATEX.cmake
new file mode 100644
index 0000000..1e82651
--- /dev/null
+++ b/Modules/FindLATEX.cmake
@@ -0,0 +1,283 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLATEX
+---------
+
+Find LaTeX
+
+This module finds an installed LaTeX and determines the location
+of the compiler. Additionally the module looks for Latex-related
+software like BibTeX.
+
+.. versionadded:: 3.2
+ Component processing; support for htlatex, pdftops, Biber, xindy, XeLaTeX,
+ LuaLaTeX.
+
+This module sets the following result variables::
+
+ LATEX_FOUND: whether found Latex and requested components
+ LATEX_<component>_FOUND: whether found <component>
+ LATEX_COMPILER: path to the LaTeX compiler
+ PDFLATEX_COMPILER: path to the PdfLaTeX compiler
+ XELATEX_COMPILER: path to the XeLaTeX compiler
+ LUALATEX_COMPILER: path to the LuaLaTeX compiler
+ BIBTEX_COMPILER: path to the BibTeX compiler
+ BIBER_COMPILER: path to the Biber compiler
+ MAKEINDEX_COMPILER: path to the MakeIndex compiler
+ XINDY_COMPILER: path to the xindy compiler
+ DVIPS_CONVERTER: path to the DVIPS converter
+ DVIPDF_CONVERTER: path to the DVIPDF converter
+ PS2PDF_CONVERTER: path to the PS2PDF converter
+ PDFTOPS_CONVERTER: path to the pdftops converter
+ LATEX2HTML_CONVERTER: path to the LaTeX2Html converter
+ HTLATEX_COMPILER: path to the htlatex compiler
+
+Possible components are::
+
+ PDFLATEX
+ XELATEX
+ LUALATEX
+ BIBTEX
+ BIBER
+ MAKEINDEX
+ XINDY
+ DVIPS
+ DVIPDF
+ PS2PDF
+ PDFTOPS
+ LATEX2HTML
+ HTLATEX
+
+Example Usages::
+
+ find_package(LATEX)
+ find_package(LATEX COMPONENTS PDFLATEX)
+ find_package(LATEX COMPONENTS BIBTEX PS2PDF)
+#]=======================================================================]
+
+if (WIN32)
+ # Try to find the MikTex binary path (look for its package manager).
+ find_path(MIKTEX_BINARY_PATH mpm.exe
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MiK\\MiKTeX\\CurrentVersion\\MiKTeX;Install Root]/miktex/bin"
+ DOC
+ "Path to the MikTex binary directory."
+ )
+ mark_as_advanced(MIKTEX_BINARY_PATH)
+
+ # Try to find the GhostScript binary path (look for gswin32).
+ get_filename_component(GHOSTSCRIPT_BINARY_PATH_FROM_REGISTERY_8_00
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\AFPL Ghostscript\\8.00;GS_DLL]" PATH
+ )
+
+ get_filename_component(GHOSTSCRIPT_BINARY_PATH_FROM_REGISTERY_7_04
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\AFPL Ghostscript\\7.04;GS_DLL]" PATH
+ )
+
+ find_path(GHOSTSCRIPT_BINARY_PATH gswin32.exe
+ ${GHOSTSCRIPT_BINARY_PATH_FROM_REGISTERY_8_00}
+ ${GHOSTSCRIPT_BINARY_PATH_FROM_REGISTERY_7_04}
+ DOC "Path to the GhostScript binary directory."
+ )
+ mark_as_advanced(GHOSTSCRIPT_BINARY_PATH)
+
+ find_path(GHOSTSCRIPT_LIBRARY_PATH ps2pdf13.bat
+ "${GHOSTSCRIPT_BINARY_PATH}/../lib"
+ DOC "Path to the GhostScript library directory."
+ )
+ mark_as_advanced(GHOSTSCRIPT_LIBRARY_PATH)
+endif ()
+
+# try to find Latex and the related programs
+find_program(LATEX_COMPILER
+ NAMES latex
+ PATHS ${MIKTEX_BINARY_PATH}
+ /usr/bin
+)
+
+# find pdflatex
+find_program(PDFLATEX_COMPILER
+ NAMES pdflatex
+ PATHS ${MIKTEX_BINARY_PATH}
+ /usr/bin
+)
+if (PDFLATEX_COMPILER)
+ set(LATEX_PDFLATEX_FOUND TRUE)
+else()
+ set(LATEX_PDFLATEX_FOUND FALSE)
+endif()
+
+# find xelatex
+find_program(XELATEX_COMPILER
+ NAMES xelatex
+ PATHS ${MIKTEX_BINARY_PATH}
+ /usr/bin
+)
+if (XELATEX_COMPILER)
+ set(LATEX_XELATEX_FOUND TRUE)
+else()
+ set(LATEX_XELATEX_FOUND FALSE)
+endif()
+
+# find lualatex
+find_program(LUALATEX_COMPILER
+ NAMES lualatex
+ PATHS ${MIKTEX_BINARY_PATH}
+ /usr/bin
+)
+if (LUALATEX_COMPILER)
+ set(LATEX_LUALATEX_FOUND TRUE)
+else()
+ set(LATEX_LUALATEX_FOUND FALSE)
+endif()
+
+# find bibtex
+find_program(BIBTEX_COMPILER
+ NAMES bibtex
+ PATHS ${MIKTEX_BINARY_PATH}
+ /usr/bin
+)
+if (BIBTEX_COMPILER)
+ set(LATEX_BIBTEX_FOUND TRUE)
+else()
+ set(LATEX_BIBTEX_FOUND FALSE)
+endif()
+
+# find biber
+find_program(BIBER_COMPILER
+ NAMES biber
+ PATHS ${MIKTEX_BINARY_PATH}
+ /usr/bin
+)
+if (BIBER_COMPILER)
+ set(LATEX_BIBER_FOUND TRUE)
+else()
+ set(LATEX_BIBER_FOUND FALSE)
+endif()
+
+# find makeindex
+find_program(MAKEINDEX_COMPILER
+ NAMES makeindex
+ PATHS ${MIKTEX_BINARY_PATH}
+ /usr/bin
+)
+if (MAKEINDEX_COMPILER)
+ set(LATEX_MAKEINDEX_FOUND TRUE)
+else()
+ set(LATEX_MAKEINDEX_FOUND FALSE)
+endif()
+
+# find xindy
+find_program(XINDY_COMPILER
+ NAMES xindy
+ PATHS ${MIKTEX_BINARY_PATH}
+ /usr/bin
+)
+if (XINDY_COMPILER)
+ set(LATEX_XINDY_FOUND TRUE)
+else()
+ set(LATEX_XINDY_FOUND FALSE)
+endif()
+
+# find dvips
+find_program(DVIPS_CONVERTER
+ NAMES dvips
+ PATHS ${MIKTEX_BINARY_PATH}
+ /usr/bin
+)
+if (DVIPS_CONVERTER)
+ set(LATEX_DVIPS_FOUND TRUE)
+else()
+ set(LATEX_DVIPS_FOUND FALSE)
+endif()
+
+# find dvipdf
+find_program(DVIPDF_CONVERTER
+ NAMES dvipdfm dvipdft dvipdf
+ PATHS ${MIKTEX_BINARY_PATH}
+ /usr/bin
+)
+if (DVIPDF_CONVERTER)
+ set(LATEX_DVIPDF_FOUND TRUE)
+else()
+ set(LATEX_DVIPDF_FOUND FALSE)
+endif()
+
+# find ps2pdf
+if (WIN32)
+ find_program(PS2PDF_CONVERTER
+ NAMES ps2pdf14.bat ps2pdf14 ps2pdf
+ PATHS ${GHOSTSCRIPT_LIBRARY_PATH}
+ ${MIKTEX_BINARY_PATH}
+ )
+else ()
+ find_program(PS2PDF_CONVERTER
+ NAMES ps2pdf14 ps2pdf
+ )
+endif ()
+if (PS2PDF_CONVERTER)
+ set(LATEX_PS2PDF_FOUND TRUE)
+else()
+ set(LATEX_PS2PDF_FOUND FALSE)
+endif()
+
+# find pdftops
+find_program(PDFTOPS_CONVERTER
+ NAMES pdftops
+ PATHS ${MIKTEX_BINARY_PATH}
+ /usr/bin
+)
+if (PDFTOPS_CONVERTER)
+ set(LATEX_PDFTOPS_FOUND TRUE)
+else()
+ set(LATEX_PDFTOPS_FOUND FALSE)
+endif()
+
+# find latex2html
+find_program(LATEX2HTML_CONVERTER
+ NAMES latex2html
+ PATHS ${MIKTEX_BINARY_PATH}
+ /usr/bin
+)
+if (LATEX2HTML_CONVERTER)
+ set(LATEX_LATEX2HTML_FOUND TRUE)
+else()
+ set(LATEX_LATEX2HTML_FOUND FALSE)
+endif()
+
+# find htlatex
+find_program(HTLATEX_COMPILER
+ NAMES htlatex
+ PATHS ${MIKTEX_BINARY_PATH}
+ /usr/bin
+)
+if (HTLATEX_COMPILER)
+ set(LATEX_HTLATEX_FOUND TRUE)
+else()
+ set(LATEX_HTLATEX_FOUND FALSE)
+endif()
+
+
+mark_as_advanced(
+ LATEX_COMPILER
+ PDFLATEX_COMPILER
+ XELATEX_COMPILER
+ LUALATEX_COMPILER
+ BIBTEX_COMPILER
+ BIBER_COMPILER
+ MAKEINDEX_COMPILER
+ XINDY_COMPILER
+ DVIPS_CONVERTER
+ DVIPDF_CONVERTER
+ PS2PDF_CONVERTER
+ PDFTOPS_CONVERTER
+ LATEX2HTML_CONVERTER
+ HTLATEX_COMPILER
+)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(LATEX
+ REQUIRED_VARS LATEX_COMPILER
+ HANDLE_COMPONENTS
+)
diff --git a/Modules/FindLTTngUST.cmake b/Modules/FindLTTngUST.cmake
new file mode 100644
index 0000000..f478e4d
--- /dev/null
+++ b/Modules/FindLTTngUST.cmake
@@ -0,0 +1,102 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLTTngUST
+------------
+
+.. versionadded:: 3.6
+
+Find
+`Linux Trace Toolkit Next Generation (LTTng-UST) <http://lttng.org/>`__ library.
+
+Imported target
+^^^^^^^^^^^^^^^
+
+This module defines the following :prop_tgt:`IMPORTED` target:
+
+``LTTng::UST``
+ The LTTng-UST library, if found
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module sets the following
+
+``LTTNGUST_FOUND``
+ ``TRUE`` if system has LTTng-UST
+``LTTNGUST_INCLUDE_DIRS``
+ The LTTng-UST include directories
+``LTTNGUST_LIBRARIES``
+ The libraries needed to use LTTng-UST
+``LTTNGUST_VERSION_STRING``
+ The LTTng-UST version
+``LTTNGUST_HAS_TRACEF``
+ ``TRUE`` if the ``tracef()`` API is available in the system's LTTng-UST
+``LTTNGUST_HAS_TRACELOG``
+ ``TRUE`` if the ``tracelog()`` API is available in the system's LTTng-UST
+#]=======================================================================]
+
+find_path(LTTNGUST_INCLUDE_DIRS NAMES lttng/tracepoint.h)
+find_library(LTTNGUST_LIBRARIES NAMES lttng-ust)
+
+if(LTTNGUST_INCLUDE_DIRS AND LTTNGUST_LIBRARIES)
+ # find tracef() and tracelog() support
+ set(LTTNGUST_HAS_TRACEF 0)
+ set(LTTNGUST_HAS_TRACELOG 0)
+
+ if(EXISTS "${LTTNGUST_INCLUDE_DIRS}/lttng/tracef.h")
+ set(LTTNGUST_HAS_TRACEF TRUE)
+ endif()
+
+ if(EXISTS "${LTTNGUST_INCLUDE_DIRS}/lttng/tracelog.h")
+ set(LTTNGUST_HAS_TRACELOG TRUE)
+ endif()
+
+ # get version
+ set(lttngust_version_file "${LTTNGUST_INCLUDE_DIRS}/lttng/ust-version.h")
+
+ if(EXISTS "${lttngust_version_file}")
+ file(STRINGS "${lttngust_version_file}" lttngust_version_major_string
+ REGEX "^[\t ]*#define[\t ]+LTTNG_UST_MAJOR_VERSION[\t ]+[0-9]+[\t ]*$")
+ file(STRINGS "${lttngust_version_file}" lttngust_version_minor_string
+ REGEX "^[\t ]*#define[\t ]+LTTNG_UST_MINOR_VERSION[\t ]+[0-9]+[\t ]*$")
+ file(STRINGS "${lttngust_version_file}" lttngust_version_patch_string
+ REGEX "^[\t ]*#define[\t ]+LTTNG_UST_PATCHLEVEL_VERSION[\t ]+[0-9]+[\t ]*$")
+ string(REGEX REPLACE ".*([0-9]+).*" "\\1"
+ lttngust_v_major "${lttngust_version_major_string}")
+ string(REGEX REPLACE ".*([0-9]+).*" "\\1"
+ lttngust_v_minor "${lttngust_version_minor_string}")
+ string(REGEX REPLACE ".*([0-9]+).*" "\\1"
+ lttngust_v_patch "${lttngust_version_patch_string}")
+ set(LTTNGUST_VERSION_STRING
+ "${lttngust_v_major}.${lttngust_v_minor}.${lttngust_v_patch}")
+ unset(lttngust_version_major_string)
+ unset(lttngust_version_minor_string)
+ unset(lttngust_version_patch_string)
+ unset(lttngust_v_major)
+ unset(lttngust_v_minor)
+ unset(lttngust_v_patch)
+ endif()
+
+ unset(lttngust_version_file)
+
+ if(NOT TARGET LTTng::UST)
+ add_library(LTTng::UST UNKNOWN IMPORTED)
+ set_target_properties(LTTng::UST PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${LTTNGUST_INCLUDE_DIRS}"
+ INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS}
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${LTTNGUST_LIBRARIES}")
+ endif()
+
+ # add libdl to required libraries
+ set(LTTNGUST_LIBRARIES ${LTTNGUST_LIBRARIES} ${CMAKE_DL_LIBS})
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(LTTngUST FOUND_VAR LTTNGUST_FOUND
+ REQUIRED_VARS LTTNGUST_LIBRARIES
+ LTTNGUST_INCLUDE_DIRS
+ VERSION_VAR LTTNGUST_VERSION_STRING)
+mark_as_advanced(LTTNGUST_LIBRARIES LTTNGUST_INCLUDE_DIRS)
diff --git a/Modules/FindLibArchive.cmake b/Modules/FindLibArchive.cmake
new file mode 100644
index 0000000..08078a2
--- /dev/null
+++ b/Modules/FindLibArchive.cmake
@@ -0,0 +1,80 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLibArchive
+--------------
+
+Find libarchive library and headers.
+Libarchive is multi-format archive and compression library.
+
+The module defines the following variables:
+
+::
+
+ LibArchive_FOUND - true if libarchive was found
+ LibArchive_INCLUDE_DIRS - include search path
+ LibArchive_LIBRARIES - libraries to link
+ LibArchive_VERSION - libarchive 3-component version number
+
+The module defines the following ``IMPORTED`` targets:
+
+::
+
+ LibArchive::LibArchive - target for linking against libarchive
+
+.. versionadded:: 3.6
+ Support for new libarchive 3.2 version string format.
+
+#]=======================================================================]
+
+find_path(LibArchive_INCLUDE_DIR
+ NAMES archive.h
+ PATHS
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\LibArchive;InstallPath]/include"
+ DOC "libarchive include directory"
+ )
+
+find_library(LibArchive_LIBRARY
+ NAMES archive libarchive
+ PATHS
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\LibArchive;InstallPath]/lib"
+ DOC "libarchive library"
+ )
+
+mark_as_advanced(LibArchive_INCLUDE_DIR LibArchive_LIBRARY)
+
+# Extract the version number from the header.
+if(LibArchive_INCLUDE_DIR AND EXISTS "${LibArchive_INCLUDE_DIR}/archive.h")
+ # The version string appears in one of three known formats in the header:
+ # #define ARCHIVE_LIBRARY_VERSION "libarchive 2.4.12"
+ # #define ARCHIVE_VERSION_STRING "libarchive 2.8.4"
+ # #define ARCHIVE_VERSION_ONLY_STRING "3.2.0"
+ # Match any format.
+ set(_LibArchive_VERSION_REGEX "^#define[ \t]+ARCHIVE[_A-Z]+VERSION[_A-Z]*[ \t]+\"(libarchive +)?([0-9]+)\\.([0-9]+)\\.([0-9]+)[^\"]*\".*$")
+ file(STRINGS "${LibArchive_INCLUDE_DIR}/archive.h" _LibArchive_VERSION_STRING LIMIT_COUNT 1 REGEX "${_LibArchive_VERSION_REGEX}")
+ if(_LibArchive_VERSION_STRING)
+ string(REGEX REPLACE "${_LibArchive_VERSION_REGEX}" "\\2.\\3.\\4" LibArchive_VERSION "${_LibArchive_VERSION_STRING}")
+ endif()
+ unset(_LibArchive_VERSION_REGEX)
+ unset(_LibArchive_VERSION_STRING)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(LibArchive
+ REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR
+ VERSION_VAR LibArchive_VERSION
+ )
+unset(LIBARCHIVE_FOUND)
+
+if(LibArchive_FOUND)
+ set(LibArchive_INCLUDE_DIRS ${LibArchive_INCLUDE_DIR})
+ set(LibArchive_LIBRARIES ${LibArchive_LIBRARY})
+
+ if (NOT TARGET LibArchive::LibArchive)
+ add_library(LibArchive::LibArchive UNKNOWN IMPORTED)
+ set_target_properties(LibArchive::LibArchive PROPERTIES
+ IMPORTED_LOCATION "${LibArchive_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${LibArchive_INCLUDE_DIR}")
+ endif ()
+endif()
diff --git a/Modules/FindLibLZMA.cmake b/Modules/FindLibLZMA.cmake
new file mode 100644
index 0000000..9ec8f07
--- /dev/null
+++ b/Modules/FindLibLZMA.cmake
@@ -0,0 +1,126 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLibLZMA
+-----------
+
+Find LZMA compression algorithm headers and library.
+
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.14
+
+This module defines :prop_tgt:`IMPORTED` target ``LibLZMA::LibLZMA``, if
+liblzma has been found.
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``LIBLZMA_FOUND``
+ True if liblzma headers and library were found.
+``LIBLZMA_INCLUDE_DIRS``
+ Directory where liblzma headers are located.
+``LIBLZMA_LIBRARIES``
+ Lzma libraries to link against.
+``LIBLZMA_HAS_AUTO_DECODER``
+ True if lzma_auto_decoder() is found (required).
+``LIBLZMA_HAS_EASY_ENCODER``
+ True if lzma_easy_encoder() is found (required).
+``LIBLZMA_HAS_LZMA_PRESET``
+ True if lzma_lzma_preset() is found (required).
+``LIBLZMA_VERSION_MAJOR``
+ The major version of lzma
+``LIBLZMA_VERSION_MINOR``
+ The minor version of lzma
+``LIBLZMA_VERSION_PATCH``
+ The patch version of lzma
+``LIBLZMA_VERSION_STRING``
+ version number as a string (ex: "5.0.3")
+#]=======================================================================]
+
+find_path(LIBLZMA_INCLUDE_DIR lzma.h )
+if(NOT LIBLZMA_LIBRARY)
+ find_library(LIBLZMA_LIBRARY_RELEASE NAMES lzma liblzma NAMES_PER_DIR PATH_SUFFIXES lib)
+ find_library(LIBLZMA_LIBRARY_DEBUG NAMES lzmad liblzmad NAMES_PER_DIR PATH_SUFFIXES lib)
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(LIBLZMA)
+else()
+ file(TO_CMAKE_PATH "${LIBLZMA_LIBRARY}" LIBLZMA_LIBRARY)
+endif()
+
+if(LIBLZMA_INCLUDE_DIR AND EXISTS "${LIBLZMA_INCLUDE_DIR}/lzma/version.h")
+ file(STRINGS "${LIBLZMA_INCLUDE_DIR}/lzma/version.h" LIBLZMA_HEADER_CONTENTS REGEX "#define LZMA_VERSION_[A-Z]+ [0-9]+")
+
+ string(REGEX REPLACE ".*#define LZMA_VERSION_MAJOR ([0-9]+).*" "\\1" LIBLZMA_VERSION_MAJOR "${LIBLZMA_HEADER_CONTENTS}")
+ string(REGEX REPLACE ".*#define LZMA_VERSION_MINOR ([0-9]+).*" "\\1" LIBLZMA_VERSION_MINOR "${LIBLZMA_HEADER_CONTENTS}")
+ string(REGEX REPLACE ".*#define LZMA_VERSION_PATCH ([0-9]+).*" "\\1" LIBLZMA_VERSION_PATCH "${LIBLZMA_HEADER_CONTENTS}")
+
+ set(LIBLZMA_VERSION_STRING "${LIBLZMA_VERSION_MAJOR}.${LIBLZMA_VERSION_MINOR}.${LIBLZMA_VERSION_PATCH}")
+ unset(LIBLZMA_HEADER_CONTENTS)
+endif()
+
+# We're using new code known now as XZ, even library still been called LZMA
+# it can be found in http://tukaani.org/xz/
+# Avoid using old codebase
+if (LIBLZMA_LIBRARY)
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckLibraryExists.cmake)
+ set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
+ set(CMAKE_REQUIRED_QUIET ${LibLZMA_FIND_QUIETLY})
+ if(NOT LIBLZMA_LIBRARY_RELEASE AND NOT LIBLZMA_LIBRARY_DEBUG)
+ set(LIBLZMA_LIBRARY_check ${LIBLZMA_LIBRARY})
+ elseif(LIBLZMA_LIBRARY_RELEASE)
+ set(LIBLZMA_LIBRARY_check ${LIBLZMA_LIBRARY_RELEASE})
+ elseif(LIBLZMA_LIBRARY_DEBUG)
+ set(LIBLZMA_LIBRARY_check ${LIBLZMA_LIBRARY_DEBUG})
+ endif()
+ CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY_check} lzma_auto_decoder "" LIBLZMA_HAS_AUTO_DECODER)
+ CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY_check} lzma_easy_encoder "" LIBLZMA_HAS_EASY_ENCODER)
+ CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY_check} lzma_lzma_preset "" LIBLZMA_HAS_LZMA_PRESET)
+ unset(LIBLZMA_LIBRARY_check)
+ set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE})
+endif ()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(LibLZMA REQUIRED_VARS LIBLZMA_LIBRARY
+ LIBLZMA_INCLUDE_DIR
+ LIBLZMA_HAS_AUTO_DECODER
+ LIBLZMA_HAS_EASY_ENCODER
+ LIBLZMA_HAS_LZMA_PRESET
+ VERSION_VAR LIBLZMA_VERSION_STRING
+ )
+mark_as_advanced( LIBLZMA_INCLUDE_DIR LIBLZMA_LIBRARY )
+
+if (LIBLZMA_FOUND)
+ set(LIBLZMA_LIBRARIES ${LIBLZMA_LIBRARY})
+ set(LIBLZMA_INCLUDE_DIRS ${LIBLZMA_INCLUDE_DIR})
+ if(NOT TARGET LibLZMA::LibLZMA)
+ add_library(LibLZMA::LibLZMA UNKNOWN IMPORTED)
+ set_target_properties(LibLZMA::LibLZMA PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES ${LIBLZMA_INCLUDE_DIR}
+ IMPORTED_LINK_INTERFACE_LANGUAGES C)
+
+ if(LIBLZMA_LIBRARY_RELEASE)
+ set_property(TARGET LibLZMA::LibLZMA APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(LibLZMA::LibLZMA PROPERTIES
+ IMPORTED_LOCATION_RELEASE "${LIBLZMA_LIBRARY_RELEASE}")
+ endif()
+
+ if(LIBLZMA_LIBRARY_DEBUG)
+ set_property(TARGET LibLZMA::LibLZMA APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(LibLZMA::LibLZMA PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${LIBLZMA_LIBRARY_DEBUG}")
+ endif()
+
+ if(NOT LIBLZMA_LIBRARY_RELEASE AND NOT LIBLZMA_LIBRARY_DEBUG)
+ set_target_properties(LibLZMA::LibLZMA PROPERTIES
+ IMPORTED_LOCATION "${LIBLZMA_LIBRARY}")
+ endif()
+ endif()
+endif ()
diff --git a/Modules/FindLibXml2.cmake b/Modules/FindLibXml2.cmake
new file mode 100644
index 0000000..ce28d03
--- /dev/null
+++ b/Modules/FindLibXml2.cmake
@@ -0,0 +1,124 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLibXml2
+-----------
+
+Find the XML processing library (libxml2).
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.12
+
+The following :prop_tgt:`IMPORTED` targets may be defined:
+
+``LibXml2::LibXml2``
+ libxml2 library.
+``LibXml2::xmllint``
+ .. versionadded:: 3.17
+
+ xmllint command-line executable.
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``LibXml2_FOUND``
+ true if libxml2 headers and libraries were found
+``LIBXML2_INCLUDE_DIR``
+ the directory containing LibXml2 headers
+``LIBXML2_INCLUDE_DIRS``
+ list of the include directories needed to use LibXml2
+``LIBXML2_LIBRARIES``
+ LibXml2 libraries to be linked
+``LIBXML2_DEFINITIONS``
+ the compiler switches required for using LibXml2
+``LIBXML2_XMLLINT_EXECUTABLE``
+ path to the XML checking tool xmllint coming with LibXml2
+``LIBXML2_VERSION_STRING``
+ the version of LibXml2 found (since CMake 2.8.8)
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``LIBXML2_INCLUDE_DIR``
+ the directory containing LibXml2 headers
+``LIBXML2_LIBRARY``
+ path to the LibXml2 library
+#]=======================================================================]
+
+# use pkg-config to get the directories and then use these values
+# in the find_path() and find_library() calls
+find_package(PkgConfig QUIET)
+PKG_CHECK_MODULES(PC_LIBXML QUIET libxml-2.0)
+
+find_path(LIBXML2_INCLUDE_DIR NAMES libxml/xpath.h
+ HINTS
+ ${PC_LIBXML_INCLUDEDIR}
+ ${PC_LIBXML_INCLUDE_DIRS}
+ PATH_SUFFIXES libxml2
+ )
+
+# CMake 3.9 and below used 'LIBXML2_LIBRARIES' as the name of
+# the cache entry storing the find_library result. Use the
+# value if it was set by the project or user.
+if(DEFINED LIBXML2_LIBRARIES AND NOT DEFINED LIBXML2_LIBRARY)
+ set(LIBXML2_LIBRARY ${LIBXML2_LIBRARIES})
+endif()
+
+find_library(LIBXML2_LIBRARY NAMES xml2 libxml2 libxml2_a
+ HINTS
+ ${PC_LIBXML_LIBDIR}
+ ${PC_LIBXML_LIBRARY_DIRS}
+ )
+
+find_program(LIBXML2_XMLLINT_EXECUTABLE xmllint)
+# for backwards compat. with KDE 4.0.x:
+set(XMLLINT_EXECUTABLE "${LIBXML2_XMLLINT_EXECUTABLE}")
+
+if(LIBXML2_INCLUDE_DIR AND EXISTS "${LIBXML2_INCLUDE_DIR}/libxml/xmlversion.h")
+ file(STRINGS "${LIBXML2_INCLUDE_DIR}/libxml/xmlversion.h" libxml2_version_str
+ REGEX "^#define[\t ]+LIBXML_DOTTED_VERSION[\t ]+\".*\"")
+
+ string(REGEX REPLACE "^#define[\t ]+LIBXML_DOTTED_VERSION[\t ]+\"([^\"]*)\".*" "\\1"
+ LIBXML2_VERSION_STRING "${libxml2_version_str}")
+ unset(libxml2_version_str)
+endif()
+
+set(LIBXML2_INCLUDE_DIRS ${LIBXML2_INCLUDE_DIR})
+set(LIBXML2_LIBRARIES ${LIBXML2_LIBRARY})
+
+# Did we find the same installation as pkg-config?
+# If so, use additional information from it.
+unset(LIBXML2_DEFINITIONS)
+foreach(libxml2_pc_lib_dir IN LISTS PC_LIBXML_LIBDIR PC_LIBXML_LIBRARY_DIRS)
+ if (LIBXML2_LIBRARY MATCHES "^${libxml2_pc_lib_dir}")
+ list(APPEND LIBXML2_INCLUDE_DIRS ${PC_LIBXML_INCLUDE_DIRS})
+ set(LIBXML2_DEFINITIONS ${PC_LIBXML_CFLAGS_OTHER})
+ break()
+ endif()
+endforeach()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2
+ REQUIRED_VARS LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR
+ VERSION_VAR LIBXML2_VERSION_STRING)
+
+mark_as_advanced(LIBXML2_INCLUDE_DIR LIBXML2_LIBRARY LIBXML2_XMLLINT_EXECUTABLE)
+
+if(LibXml2_FOUND AND NOT TARGET LibXml2::LibXml2)
+ add_library(LibXml2::LibXml2 UNKNOWN IMPORTED)
+ set_target_properties(LibXml2::LibXml2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBXML2_INCLUDE_DIRS}")
+ set_target_properties(LibXml2::LibXml2 PROPERTIES INTERFACE_COMPILE_OPTIONS "${LIBXML2_DEFINITIONS}")
+ set_property(TARGET LibXml2::LibXml2 APPEND PROPERTY IMPORTED_LOCATION "${LIBXML2_LIBRARY}")
+endif()
+
+if(LIBXML2_XMLLINT_EXECUTABLE AND NOT TARGET LibXml2::xmllint)
+ add_executable(LibXml2::xmllint IMPORTED)
+ set_target_properties(LibXml2::xmllint PROPERTIES IMPORTED_LOCATION "${LIBXML2_XMLLINT_EXECUTABLE}")
+endif()
diff --git a/Modules/FindLibXslt.cmake b/Modules/FindLibXslt.cmake
new file mode 100644
index 0000000..97943d6
--- /dev/null
+++ b/Modules/FindLibXslt.cmake
@@ -0,0 +1,134 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLibXslt
+-----------
+
+Find the XSL Transformations, Extensible Stylesheet Language
+Transformations (XSLT) library (LibXslt)
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.18
+
+The following :prop_tgt:`IMPORTED` targets may be defined:
+
+``LibXslt::LibXslt``
+ If the libxslt library has been found
+``LibXslt::LibExslt``
+ If the libexslt library has been found
+``LibXslt::xsltproc``
+ If the xsltproc command-line executable has been found
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+ LIBXSLT_FOUND - system has LibXslt
+ LIBXSLT_INCLUDE_DIR - the LibXslt include directory
+ LIBXSLT_LIBRARIES - Link these to LibXslt
+ LIBXSLT_DEFINITIONS - Compiler switches required for using LibXslt
+ LIBXSLT_VERSION_STRING - version of LibXslt found (since CMake 2.8.8)
+
+Additionally, the following two variables are set (but not required
+for using xslt):
+
+``LIBXSLT_EXSLT_INCLUDE_DIR``
+ .. versionadded:: 3.18
+ The include directory for exslt.
+``LIBXSLT_EXSLT_LIBRARIES``
+ Link to these if you need to link against the exslt library.
+``LIBXSLT_XSLTPROC_EXECUTABLE``
+ Contains the full path to the xsltproc executable if found.
+#]=======================================================================]
+
+# use pkg-config to get the directories and then use these values
+# in the find_path() and find_library() calls
+find_package(PkgConfig QUIET)
+PKG_CHECK_MODULES(PC_LIBXSLT QUIET libxslt)
+set(LIBXSLT_DEFINITIONS ${PC_LIBXSLT_CFLAGS_OTHER})
+
+find_path(LIBXSLT_INCLUDE_DIR NAMES libxslt/xslt.h
+ HINTS
+ ${PC_LIBXSLT_INCLUDEDIR}
+ ${PC_LIBXSLT_INCLUDE_DIRS}
+ )
+
+# CMake 3.17 and below used 'LIBXSLT_LIBRARIES' as the name of
+# the cache entry storing the find_library result. Use the
+# value if it was set by the project or user.
+if(DEFINED LIBXSLT_LIBRARIES AND NOT DEFINED LIBXSLT_LIBRARY)
+ set(LIBXSLT_LIBRARY ${LIBXSLT_LIBRARIES})
+endif()
+
+find_library(LIBXSLT_LIBRARY NAMES xslt libxslt
+ HINTS
+ ${PC_LIBXSLT_LIBDIR}
+ ${PC_LIBXSLT_LIBRARY_DIRS}
+ )
+
+set(LIBXSLT_LIBRARIES ${LIBXSLT_LIBRARY})
+
+PKG_CHECK_MODULES(PC_LIBXSLT_EXSLT QUIET libexslt)
+set(LIBXSLT_EXSLT_DEFINITIONS ${PC_LIBXSLT_EXSLT_CFLAGS_OTHER})
+
+find_path(LIBXSLT_EXSLT_INCLUDE_DIR NAMES libexslt/exslt.h
+ HINTS
+ ${PC_LIBXSLT_EXSLT_INCLUDEDIR}
+ ${PC_LIBXSLT_EXSLT_INCLUDE_DIRS}
+)
+
+find_library(LIBXSLT_EXSLT_LIBRARY NAMES exslt libexslt
+ HINTS
+ ${PC_LIBXSLT_LIBDIR}
+ ${PC_LIBXSLT_LIBRARY_DIRS}
+ ${PC_LIBXSLT_EXSLT_LIBDIR}
+ ${PC_LIBXSLT_EXSLT_LIBRARY_DIRS}
+ )
+
+set(LIBXSLT_EXSLT_LIBRARIES ${LIBXSLT_EXSLT_LIBRARY} )
+
+find_program(LIBXSLT_XSLTPROC_EXECUTABLE xsltproc)
+
+if(PC_LIBXSLT_VERSION)
+ set(LIBXSLT_VERSION_STRING ${PC_LIBXSLT_VERSION})
+elseif(LIBXSLT_INCLUDE_DIR AND EXISTS "${LIBXSLT_INCLUDE_DIR}/libxslt/xsltconfig.h")
+ file(STRINGS "${LIBXSLT_INCLUDE_DIR}/libxslt/xsltconfig.h" libxslt_version_str
+ REGEX "^#define[\t ]+LIBXSLT_DOTTED_VERSION[\t ]+\".*\"")
+
+ string(REGEX REPLACE "^#define[\t ]+LIBXSLT_DOTTED_VERSION[\t ]+\"([^\"]*)\".*" "\\1"
+ LIBXSLT_VERSION_STRING "${libxslt_version_str}")
+ unset(libxslt_version_str)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXslt
+ REQUIRED_VARS LIBXSLT_LIBRARIES LIBXSLT_INCLUDE_DIR
+ VERSION_VAR LIBXSLT_VERSION_STRING)
+
+mark_as_advanced(LIBXSLT_INCLUDE_DIR
+ LIBXSLT_LIBRARIES
+ LIBXSLT_EXSLT_LIBRARY
+ LIBXSLT_XSLTPROC_EXECUTABLE)
+
+if(LIBXSLT_FOUND AND NOT TARGET LibXslt::LibXslt)
+ add_library(LibXslt::LibXslt UNKNOWN IMPORTED)
+ set_target_properties(LibXslt::LibXslt PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBXSLT_INCLUDE_DIR}")
+ set_target_properties(LibXslt::LibXslt PROPERTIES INTERFACE_COMPILE_OPTIONS "${LIBXSLT_DEFINITIONS}")
+ set_property(TARGET LibXslt::LibXslt APPEND PROPERTY IMPORTED_LOCATION "${LIBXSLT_LIBRARY}")
+endif()
+
+if(LIBXSLT_FOUND AND NOT TARGET LibXslt::LibExslt)
+ add_library(LibXslt::LibExslt UNKNOWN IMPORTED)
+ set_target_properties(LibXslt::LibExslt PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBXSLT_EXSLT_INCLUDE_DIR}")
+ set_target_properties(LibXslt::LibExslt PROPERTIES INTERFACE_COMPILE_OPTIONS "${LIBXSLT_EXSLT_DEFINITIONS}")
+ set_property(TARGET LibXslt::LibExslt APPEND PROPERTY IMPORTED_LOCATION "${LIBXSLT_EXSLT_LIBRARY}")
+endif()
+
+if(LIBXSLT_XSLTPROC_EXECUTABLE AND NOT TARGET LibXslt::xsltproc)
+ add_executable(LibXslt::xsltproc IMPORTED)
+ set_target_properties(LibXslt::xsltproc PROPERTIES IMPORTED_LOCATION "${LIBXSLT_XSLTPROC_EXECUTABLE}")
+endif()
diff --git a/Modules/FindLibinput.cmake b/Modules/FindLibinput.cmake
new file mode 100644
index 0000000..88d5b2f
--- /dev/null
+++ b/Modules/FindLibinput.cmake
@@ -0,0 +1,84 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLibinput
+------------
+
+.. versionadded:: 3.14
+
+Find libinput headers and library.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+``Libinput::Libinput``
+ The libinput library, if found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This will define the following variables in your project:
+
+``Libinput_FOUND``
+ true if (the requested version of) libinput is available.
+``Libinput_VERSION``
+ the version of libinput.
+``Libinput_LIBRARIES``
+ the libraries to link against to use libinput.
+``Libinput_INCLUDE_DIRS``
+ where to find the libinput headers.
+``Libinput_COMPILE_OPTIONS``
+ this should be passed to target_compile_options(), if the
+ target is not used for linking
+
+#]=======================================================================]
+
+
+# Use pkg-config to get the directories and then use these values
+# in the FIND_PATH() and FIND_LIBRARY() calls
+find_package(PkgConfig QUIET)
+pkg_check_modules(PKG_Libinput QUIET libinput)
+
+set(Libinput_COMPILE_OPTIONS ${PKG_Libinput_CFLAGS_OTHER})
+set(Libinput_VERSION ${PKG_Libinput_VERSION})
+
+find_path(Libinput_INCLUDE_DIR
+ NAMES
+ libinput.h
+ HINTS
+ ${PKG_Libinput_INCLUDE_DIRS}
+)
+find_library(Libinput_LIBRARY
+ NAMES
+ input
+ HINTS
+ ${PKG_Libinput_LIBRARY_DIRS}
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Libinput
+ FOUND_VAR
+ Libinput_FOUND
+ REQUIRED_VARS
+ Libinput_LIBRARY
+ Libinput_INCLUDE_DIR
+ VERSION_VAR
+ Libinput_VERSION
+)
+
+if(Libinput_FOUND AND NOT TARGET Libinput::Libinput)
+ add_library(Libinput::Libinput UNKNOWN IMPORTED)
+ set_target_properties(Libinput::Libinput PROPERTIES
+ IMPORTED_LOCATION "${Libinput_LIBRARY}"
+ INTERFACE_COMPILE_OPTIONS "${Libinput_COMPILE_OPTIONS}"
+ INTERFACE_INCLUDE_DIRECTORIES "${Libinput_INCLUDE_DIR}"
+ )
+endif()
+
+mark_as_advanced(Libinput_LIBRARY Libinput_INCLUDE_DIR)
+
+if(Libinput_FOUND)
+ set(Libinput_LIBRARIES ${Libinput_LIBRARY})
+ set(Libinput_INCLUDE_DIRS ${Libinput_INCLUDE_DIR})
+endif()
diff --git a/Modules/FindLua.cmake b/Modules/FindLua.cmake
new file mode 100644
index 0000000..32642fe
--- /dev/null
+++ b/Modules/FindLua.cmake
@@ -0,0 +1,239 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLua
+-------
+
+Locate Lua library.
+
+.. versionadded:: 3.18
+ Support for Lua 5.4.
+
+This module defines::
+
+::
+
+ LUA_FOUND - if false, do not try to link to Lua
+ LUA_LIBRARIES - both lua and lualib
+ LUA_INCLUDE_DIR - where to find lua.h
+ LUA_VERSION_STRING - the version of Lua found
+ LUA_VERSION_MAJOR - the major version of Lua
+ LUA_VERSION_MINOR - the minor version of Lua
+ LUA_VERSION_PATCH - the patch version of Lua
+
+
+
+Note that the expected include convention is
+
+::
+
+ #include "lua.h"
+
+and not
+
+::
+
+ #include <lua/lua.h>
+
+This is because, the lua location is not standardized and may exist in
+locations other than lua/
+#]=======================================================================]
+
+cmake_policy(PUSH) # Policies apply to functions at definition-time
+cmake_policy(SET CMP0012 NEW) # For while(TRUE)
+
+unset(_lua_include_subdirs)
+unset(_lua_library_names)
+unset(_lua_append_versions)
+
+# this is a function only to have all the variables inside go away automatically
+function(_lua_get_versions)
+ set(LUA_VERSIONS5 5.4 5.3 5.2 5.1 5.0)
+
+ if (Lua_FIND_VERSION_EXACT)
+ if (Lua_FIND_VERSION_COUNT GREATER 1)
+ set(_lua_append_versions ${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR})
+ endif ()
+ elseif (Lua_FIND_VERSION)
+ # once there is a different major version supported this should become a loop
+ if (NOT Lua_FIND_VERSION_MAJOR GREATER 5)
+ if (Lua_FIND_VERSION_COUNT EQUAL 1)
+ set(_lua_append_versions ${LUA_VERSIONS5})
+ else ()
+ foreach (subver IN LISTS LUA_VERSIONS5)
+ if (NOT subver VERSION_LESS ${Lua_FIND_VERSION})
+ list(APPEND _lua_append_versions ${subver})
+ endif ()
+ endforeach ()
+ # New version -> Search for it (heuristic only! Defines in include might have changed)
+ if (NOT _lua_append_versions)
+ set(_lua_append_versions ${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR})
+ endif()
+ endif ()
+ endif ()
+ else ()
+ # once there is a different major version supported this should become a loop
+ set(_lua_append_versions ${LUA_VERSIONS5})
+ endif ()
+
+ if (LUA_Debug)
+ message(STATUS "Considering following Lua versions: ${_lua_append_versions}")
+ endif()
+
+ set(_lua_append_versions "${_lua_append_versions}" PARENT_SCOPE)
+endfunction()
+
+function(_lua_set_version_vars)
+ set(_lua_include_subdirs_raw "lua")
+
+ foreach (ver IN LISTS _lua_append_versions)
+ string(REGEX MATCH "^([0-9]+)\\.([0-9]+)$" _ver "${ver}")
+ list(APPEND _lua_include_subdirs_raw
+ lua${CMAKE_MATCH_1}${CMAKE_MATCH_2}
+ lua${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
+ lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
+ )
+ endforeach ()
+
+ # Prepend "include/" to each path directly after the path
+ set(_lua_include_subdirs "include")
+ foreach (dir IN LISTS _lua_include_subdirs_raw)
+ list(APPEND _lua_include_subdirs "${dir}" "include/${dir}")
+ endforeach ()
+
+ set(_lua_include_subdirs "${_lua_include_subdirs}" PARENT_SCOPE)
+endfunction(_lua_set_version_vars)
+
+function(_lua_get_header_version)
+ unset(LUA_VERSION_STRING PARENT_SCOPE)
+ set(_hdr_file "${LUA_INCLUDE_DIR}/lua.h")
+
+ if (NOT EXISTS "${_hdr_file}")
+ return()
+ endif ()
+
+ # At least 5.[012] have different ways to express the version
+ # so all of them need to be tested. Lua 5.2 defines LUA_VERSION
+ # and LUA_RELEASE as joined by the C preprocessor, so avoid those.
+ file(STRINGS "${_hdr_file}" lua_version_strings
+ REGEX "^#define[ \t]+LUA_(RELEASE[ \t]+\"Lua [0-9]|VERSION([ \t]+\"Lua [0-9]|_[MR])).*")
+
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MAJOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MAJOR ";${lua_version_strings};")
+ if (LUA_VERSION_MAJOR MATCHES "^[0-9]+$")
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MINOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MINOR ";${lua_version_strings};")
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_RELEASE[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_PATCH ";${lua_version_strings};")
+ set(LUA_VERSION_STRING "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_PATCH}")
+ else ()
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
+ if (NOT LUA_VERSION_STRING MATCHES "^[0-9.]+$")
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
+ endif ()
+ string(REGEX REPLACE "^([0-9]+)\\.[0-9.]*$" "\\1" LUA_VERSION_MAJOR "${LUA_VERSION_STRING}")
+ string(REGEX REPLACE "^[0-9]+\\.([0-9]+)[0-9.]*$" "\\1" LUA_VERSION_MINOR "${LUA_VERSION_STRING}")
+ string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]).*" "\\1" LUA_VERSION_PATCH "${LUA_VERSION_STRING}")
+ endif ()
+ foreach (ver IN LISTS _lua_append_versions)
+ if (ver STREQUAL "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
+ set(LUA_VERSION_MAJOR ${LUA_VERSION_MAJOR} PARENT_SCOPE)
+ set(LUA_VERSION_MINOR ${LUA_VERSION_MINOR} PARENT_SCOPE)
+ set(LUA_VERSION_PATCH ${LUA_VERSION_PATCH} PARENT_SCOPE)
+ set(LUA_VERSION_STRING ${LUA_VERSION_STRING} PARENT_SCOPE)
+ return()
+ endif ()
+ endforeach ()
+endfunction(_lua_get_header_version)
+
+function(_lua_find_header)
+ _lua_set_version_vars()
+
+ # Initialize as local variable
+ set(CMAKE_IGNORE_PATH ${CMAKE_IGNORE_PATH})
+ while (TRUE)
+ # Find the next header to test. Check each possible subdir in order
+ # This prefers e.g. higher versions as they are earlier in the list
+ # It is also consistent with previous versions of FindLua
+ foreach (subdir IN LISTS _lua_include_subdirs)
+ find_path(LUA_INCLUDE_DIR lua.h
+ HINTS ENV LUA_DIR
+ PATH_SUFFIXES ${subdir}
+ )
+ if (LUA_INCLUDE_DIR)
+ break()
+ endif()
+ endforeach()
+ # Did not found header -> Fail
+ if (NOT LUA_INCLUDE_DIR)
+ return()
+ endif()
+ _lua_get_header_version()
+ # Found accepted version -> Ok
+ if (LUA_VERSION_STRING)
+ if (LUA_Debug)
+ message(STATUS "Found suitable version ${LUA_VERSION_STRING} in ${LUA_INCLUDE_DIR}/lua.h")
+ endif()
+ return()
+ endif()
+ # Found wrong version -> Ignore this path and retry
+ if (LUA_Debug)
+ message(STATUS "Ignoring unsuitable version in ${LUA_INCLUDE_DIR}")
+ endif()
+ list(APPEND CMAKE_IGNORE_PATH "${LUA_INCLUDE_DIR}")
+ unset(LUA_INCLUDE_DIR CACHE)
+ unset(LUA_INCLUDE_DIR)
+ unset(LUA_INCLUDE_DIR PARENT_SCOPE)
+ endwhile ()
+endfunction()
+
+_lua_get_versions()
+_lua_find_header()
+_lua_get_header_version()
+unset(_lua_append_versions)
+
+if (LUA_VERSION_STRING)
+ set(_lua_library_names
+ lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}
+ lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}
+ lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}
+ lua.${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}
+ )
+endif ()
+
+find_library(LUA_LIBRARY
+ NAMES ${_lua_library_names} lua
+ NAMES_PER_DIR
+ HINTS
+ ENV LUA_DIR
+ PATH_SUFFIXES lib
+)
+unset(_lua_library_names)
+
+if (LUA_LIBRARY)
+ # include the math library for Unix
+ if (UNIX AND NOT APPLE AND NOT BEOS)
+ find_library(LUA_MATH_LIBRARY m)
+ mark_as_advanced(LUA_MATH_LIBRARY)
+ set(LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}")
+
+ # include dl library for statically-linked Lua library
+ get_filename_component(LUA_LIB_EXT ${LUA_LIBRARY} EXT)
+ if(LUA_LIB_EXT STREQUAL CMAKE_STATIC_LIBRARY_SUFFIX)
+ list(APPEND LUA_LIBRARIES ${CMAKE_DL_LIBS})
+ endif()
+
+ # For Windows and Mac, don't need to explicitly include the math library
+ else ()
+ set(LUA_LIBRARIES "${LUA_LIBRARY}")
+ endif ()
+endif ()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if
+# all listed variables are TRUE
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua
+ REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR
+ VERSION_VAR LUA_VERSION_STRING)
+
+mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARY)
+
+cmake_policy(POP)
diff --git a/Modules/FindLua50.cmake b/Modules/FindLua50.cmake
new file mode 100644
index 0000000..0575caa
--- /dev/null
+++ b/Modules/FindLua50.cmake
@@ -0,0 +1,90 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLua50
+---------
+
+
+
+Locate Lua library.
+This module defines::
+
+::
+
+ LUA50_FOUND, if false, do not try to link to Lua
+ LUA_LIBRARIES, both lua and lualib
+ LUA_INCLUDE_DIR, where to find lua.h and lualib.h (and probably lauxlib.h)
+
+
+
+Note that the expected include convention is
+
+::
+
+ #include "lua.h"
+
+and not
+
+::
+
+ #include <lua/lua.h>
+
+This is because, the lua location is not standardized and may exist in
+locations other than lua/
+#]=======================================================================]
+
+find_path(LUA_INCLUDE_DIR lua.h
+ HINTS
+ ENV LUA_DIR
+ PATH_SUFFIXES include/lua50 include/lua5.0 include/lua5 include/lua include
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /opt
+)
+
+find_library(LUA_LIBRARY_lua
+ NAMES lua50 lua5.0 lua-5.0 lua5 lua
+ HINTS
+ ENV LUA_DIR
+ PATH_SUFFIXES lib
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /opt
+)
+
+# In an OS X framework, lualib is usually included as part of the framework
+# (like GLU in OpenGL.framework)
+if(${LUA_LIBRARY_lua} MATCHES "framework")
+ set( LUA_LIBRARIES "${LUA_LIBRARY_lua}" CACHE STRING "Lua framework")
+else()
+ find_library(LUA_LIBRARY_lualib
+ NAMES lualib50 lualib5.0 lualib5 lualib
+ HINTS
+ ENV LUALIB_DIR
+ ENV LUA_DIR
+ PATH_SUFFIXES lib
+ PATHS
+ /opt
+ )
+ if(LUA_LIBRARY_lualib AND LUA_LIBRARY_lua)
+ # include the math library for Unix
+ if(UNIX AND NOT APPLE)
+ find_library(MATH_LIBRARY_FOR_LUA m)
+ set( LUA_LIBRARIES "${LUA_LIBRARY_lualib};${LUA_LIBRARY_lua};${MATH_LIBRARY_FOR_LUA}" CACHE STRING "This is the concatenation of lua and lualib libraries")
+ # For Windows and Mac, don't need to explicitly include the math library
+ else()
+ set( LUA_LIBRARIES "${LUA_LIBRARY_lualib};${LUA_LIBRARY_lua}" CACHE STRING "This is the concatenation of lua and lualib libraries")
+ endif()
+ endif()
+endif()
+
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if
+# all listed variables are TRUE
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua50 DEFAULT_MSG LUA_LIBRARIES LUA_INCLUDE_DIR)
+
+mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARIES)
diff --git a/Modules/FindLua51.cmake b/Modules/FindLua51.cmake
new file mode 100644
index 0000000..283a3eb
--- /dev/null
+++ b/Modules/FindLua51.cmake
@@ -0,0 +1,84 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLua51
+---------
+
+
+
+Locate Lua library.
+This module defines::
+
+::
+
+ LUA51_FOUND, if false, do not try to link to Lua
+ LUA_LIBRARIES
+ LUA_INCLUDE_DIR, where to find lua.h
+ LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8)
+
+
+
+Note that the expected include convention is
+
+::
+
+ #include "lua.h"
+
+and not
+
+::
+
+ #include <lua/lua.h>
+
+This is because, the lua location is not standardized and may exist in
+locations other than lua/
+#]=======================================================================]
+
+find_path(LUA_INCLUDE_DIR lua.h
+ HINTS
+ ENV LUA_DIR
+ PATH_SUFFIXES include/lua51 include/lua5.1 include/lua-5.1 include/lua include
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /opt
+)
+
+find_library(LUA_LIBRARY
+ NAMES lua51 lua5.1 lua-5.1 lua
+ HINTS
+ ENV LUA_DIR
+ PATH_SUFFIXES lib
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /opt
+)
+
+if(LUA_LIBRARY)
+ # include the math library for Unix
+ if(UNIX AND NOT APPLE AND NOT BEOS AND NOT HAIKU)
+ find_library(LUA_MATH_LIBRARY m)
+ set( LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}" CACHE STRING "Lua Libraries")
+ # For Windows and Mac, don't need to explicitly include the math library
+ else()
+ set( LUA_LIBRARIES "${LUA_LIBRARY}" CACHE STRING "Lua Libraries")
+ endif()
+endif()
+
+if(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h")
+ file(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"")
+
+ string(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}")
+ unset(lua_version_str)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if
+# all listed variables are TRUE
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua51
+ REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR
+ VERSION_VAR LUA_VERSION_STRING)
+
+mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY)
diff --git a/Modules/FindMFC.cmake b/Modules/FindMFC.cmake
new file mode 100644
index 0000000..b8ca71b
--- /dev/null
+++ b/Modules/FindMFC.cmake
@@ -0,0 +1,71 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindMFC
+-------
+
+Find Microsoft Foundation Class Library (MFC) on Windows
+
+Find the native MFC - i.e. decide if an application can link to the
+MFC libraries.
+
+::
+
+ MFC_FOUND - Was MFC support found
+
+You don't need to include anything or link anything to use it.
+#]=======================================================================]
+
+# Assume no MFC support
+set(MFC_FOUND "NO")
+
+# Only attempt the try_compile call if it has a chance to succeed:
+set(MFC_ATTEMPT_TRY_COMPILE 0)
+if(WIN32 AND NOT UNIX AND NOT BORLAND AND NOT MINGW)
+ set(MFC_ATTEMPT_TRY_COMPILE 1)
+endif()
+
+if(MFC_ATTEMPT_TRY_COMPILE)
+ if(NOT DEFINED MFC_HAVE_MFC)
+ set(CHECK_INCLUDE_FILE_VAR "afxwin.h")
+ configure_file(${CMAKE_ROOT}/Modules/CheckIncludeFile.cxx.in
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.cxx)
+ message(CHECK_START "Looking for MFC")
+ # Try both shared and static as the root project may have set the /MT flag
+ try_compile(MFC_HAVE_MFC
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.cxx
+ CMAKE_FLAGS
+ -DCMAKE_MFC_FLAG:STRING=2
+ -DCOMPILE_DEFINITIONS:STRING=-D_AFXDLL
+ OUTPUT_VARIABLE OUTPUT)
+ if(NOT MFC_HAVE_MFC)
+ configure_file(${CMAKE_ROOT}/Modules/CheckIncludeFile.cxx.in
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.cxx)
+ try_compile(MFC_HAVE_MFC
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.cxx
+ CMAKE_FLAGS
+ -DCMAKE_MFC_FLAG:STRING=1
+ OUTPUT_VARIABLE OUTPUT)
+ endif()
+ if(MFC_HAVE_MFC)
+ message(CHECK_PASS "found")
+ set(MFC_HAVE_MFC 1 CACHE INTERNAL "Have MFC?")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if MFC exists passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ else()
+ message(CHECK_FAIL "not found")
+ set(MFC_HAVE_MFC 0 CACHE INTERNAL "Have MFC?")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if MFC exists failed with the following output:\n"
+ "${OUTPUT}\n\n")
+ endif()
+ endif()
+
+ if(MFC_HAVE_MFC)
+ set(MFC_FOUND "YES")
+ endif()
+endif()
diff --git a/Modules/FindMPEG.cmake b/Modules/FindMPEG.cmake
new file mode 100644
index 0000000..e5a80e3
--- /dev/null
+++ b/Modules/FindMPEG.cmake
@@ -0,0 +1,43 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindMPEG
+--------
+
+Find the native MPEG includes and library
+
+This module defines
+
+::
+
+ MPEG_INCLUDE_DIR, where to find MPEG.h, etc.
+ MPEG_LIBRARIES, the libraries required to use MPEG.
+ MPEG_FOUND, If false, do not try to use MPEG.
+
+also defined, but not for general use are
+
+::
+
+ MPEG_mpeg2_LIBRARY, where to find the MPEG library.
+ MPEG_vo_LIBRARY, where to find the vo library.
+#]=======================================================================]
+
+find_path(MPEG_INCLUDE_DIR
+ NAMES mpeg2.h mpeg2dec/mpeg2.h mpeg2dec/include/video_out.h)
+
+find_library(MPEG_mpeg2_LIBRARY mpeg2)
+
+find_library(MPEG_vo_LIBRARY vo)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(MPEG DEFAULT_MSG MPEG_mpeg2_LIBRARY MPEG_INCLUDE_DIR)
+
+if(MPEG_FOUND)
+ set( MPEG_LIBRARIES ${MPEG_mpeg2_LIBRARY} )
+ if(MPEG_vo_LIBRARY)
+ list(APPEND MPEG2_LIBRARIES ${MPEG_vo_LIBRARY})
+ endif()
+endif()
+
+mark_as_advanced(MPEG_INCLUDE_DIR MPEG_mpeg2_LIBRARY MPEG_vo_LIBRARY)
diff --git a/Modules/FindMPEG2.cmake b/Modules/FindMPEG2.cmake
new file mode 100644
index 0000000..763d86a
--- /dev/null
+++ b/Modules/FindMPEG2.cmake
@@ -0,0 +1,50 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindMPEG2
+---------
+
+Find the native MPEG2 includes and library
+
+This module defines
+
+::
+
+ MPEG2_INCLUDE_DIR, path to mpeg2dec/mpeg2.h, etc.
+ MPEG2_LIBRARIES, the libraries required to use MPEG2.
+ MPEG2_FOUND, If false, do not try to use MPEG2.
+
+also defined, but not for general use are
+
+::
+
+ MPEG2_mpeg2_LIBRARY, where to find the MPEG2 library.
+ MPEG2_vo_LIBRARY, where to find the vo library.
+#]=======================================================================]
+
+find_path(MPEG2_INCLUDE_DIR
+ NAMES mpeg2.h mpeg2dec/mpeg2.h)
+
+find_library(MPEG2_mpeg2_LIBRARY mpeg2)
+
+find_library(MPEG2_vo_LIBRARY vo)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(MPEG2 DEFAULT_MSG MPEG2_mpeg2_LIBRARY MPEG2_INCLUDE_DIR)
+
+if(MPEG2_FOUND)
+ set(MPEG2_LIBRARIES ${MPEG2_mpeg2_LIBRARY})
+ if(MPEG2_vo_LIBRARY)
+ list(APPEND MPEG2_LIBRARIES ${MPEG2_vo_LIBRARY})
+ endif()
+
+ #some native mpeg2 installations will depend
+ #on libSDL, if found, add it in.
+ find_package(SDL)
+ if(SDL_FOUND)
+ set( MPEG2_LIBRARIES ${MPEG2_LIBRARIES} ${SDL_LIBRARY})
+ endif()
+endif()
+
+mark_as_advanced(MPEG2_INCLUDE_DIR MPEG2_mpeg2_LIBRARY MPEG2_vo_LIBRARY)
diff --git a/Modules/FindMPI.cmake b/Modules/FindMPI.cmake
new file mode 100644
index 0000000..c48decb
--- /dev/null
+++ b/Modules/FindMPI.cmake
@@ -0,0 +1,1817 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindMPI
+-------
+
+Find a Message Passing Interface (MPI) implementation.
+
+The Message Passing Interface (MPI) is a library used to write
+high-performance distributed-memory parallel applications, and is
+typically deployed on a cluster. MPI is a standard interface (defined
+by the MPI forum) for which many implementations are available.
+
+.. versionadded:: 3.10
+ Major overhaul of the module: many new variables, per-language components,
+ support for a wider variety of runtimes.
+
+Variables for using MPI
+^^^^^^^^^^^^^^^^^^^^^^^
+
+The module exposes the components ``C``, ``CXX``, ``MPICXX`` and ``Fortran``.
+Each of these controls the various MPI languages to search for.
+The difference between ``CXX`` and ``MPICXX`` is that ``CXX`` refers to the
+MPI C API being usable from C++, whereas ``MPICXX`` refers to the MPI-2 C++ API
+that was removed again in MPI-3.
+
+Depending on the enabled components the following variables will be set:
+
+``MPI_FOUND``
+ Variable indicating that MPI settings for all requested languages have been found.
+ If no components are specified, this is true if MPI settings for all enabled languages
+ were detected. Note that the ``MPICXX`` component does not affect this variable.
+``MPI_VERSION``
+ Minimal version of MPI detected among the requested languages, or all enabled languages
+ if no components were specified.
+
+This module will set the following variables per language in your
+project, where ``<lang>`` is one of C, CXX, or Fortran:
+
+``MPI_<lang>_FOUND``
+ Variable indicating the MPI settings for ``<lang>`` were found and that
+ simple MPI test programs compile with the provided settings.
+``MPI_<lang>_COMPILER``
+ MPI compiler for ``<lang>`` if such a program exists.
+``MPI_<lang>_COMPILE_OPTIONS``
+ Compilation options for MPI programs in ``<lang>``, given as a :ref:`;-list <CMake Language Lists>`.
+``MPI_<lang>_COMPILE_DEFINITIONS``
+ Compilation definitions for MPI programs in ``<lang>``, given as a :ref:`;-list <CMake Language Lists>`.
+``MPI_<lang>_INCLUDE_DIRS``
+ Include path(s) for MPI header.
+``MPI_<lang>_LINK_FLAGS``
+ Linker flags for MPI programs.
+``MPI_<lang>_LIBRARIES``
+ All libraries to link MPI programs against.
+
+.. versionadded:: 3.9
+ Additionally, the following :prop_tgt:`IMPORTED` targets are defined:
+
+``MPI::MPI_<lang>``
+ Target for using MPI from ``<lang>``.
+
+The following variables indicating which bindings are present will be defined:
+
+``MPI_MPICXX_FOUND``
+ Variable indicating whether the MPI-2 C++ bindings are present (introduced in MPI-2, removed with MPI-3).
+``MPI_Fortran_HAVE_F77_HEADER``
+ True if the Fortran 77 header ``mpif.h`` is available.
+``MPI_Fortran_HAVE_F90_MODULE``
+ True if the Fortran 90 module ``mpi`` can be used for accessing MPI (MPI-2 and higher only).
+``MPI_Fortran_HAVE_F08_MODULE``
+ True if the Fortran 2008 ``mpi_f08`` is available to MPI programs (MPI-3 and higher only).
+
+If possible, the MPI version will be determined by this module. The facilities to detect the MPI version
+were introduced with MPI-1.2, and therefore cannot be found for older MPI versions.
+
+``MPI_<lang>_VERSION_MAJOR``
+ Major version of MPI implemented for ``<lang>`` by the MPI distribution.
+``MPI_<lang>_VERSION_MINOR``
+ Minor version of MPI implemented for ``<lang>`` by the MPI distribution.
+``MPI_<lang>_VERSION``
+ MPI version implemented for ``<lang>`` by the MPI distribution.
+
+Note that there's no variable for the C bindings being accessible through ``mpi.h``, since the MPI standards
+always have required this binding to work in both C and C++ code.
+
+For running MPI programs, the module sets the following variables
+
+``MPIEXEC_EXECUTABLE``
+ Executable for running MPI programs, if such exists.
+``MPIEXEC_NUMPROC_FLAG``
+ Flag to pass to ``mpiexec`` before giving it the number of processors to run on.
+``MPIEXEC_MAX_NUMPROCS``
+ Number of MPI processors to utilize. Defaults to the number
+ of processors detected on the host system.
+``MPIEXEC_PREFLAGS``
+ Flags to pass to ``mpiexec`` directly before the executable to run.
+``MPIEXEC_POSTFLAGS``
+ Flags to pass to ``mpiexec`` after other flags.
+
+Variables for locating MPI
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This module performs a four step search for an MPI implementation:
+
+1. Search for ``MPIEXEC_EXECUTABLE`` and, if found, use its base directory.
+2. Check if the compiler has MPI support built-in. This is the case if the user passed a
+ compiler wrapper as ``CMAKE_<LANG>_COMPILER`` or if they're on a Cray system.
+3. Attempt to find an MPI compiler wrapper and determine the compiler information from it.
+4. Try to find an MPI implementation that does not ship such a wrapper by guessing settings.
+ Currently, only Microsoft MPI and MPICH2 on Windows are supported.
+
+For controlling the ``MPIEXEC_EXECUTABLE`` step, the following variables may be set:
+
+``MPIEXEC_EXECUTABLE``
+ Manually specify the location of ``mpiexec``.
+``MPI_HOME``
+ Specify the base directory of the MPI installation.
+``ENV{MPI_HOME}``
+ Environment variable to specify the base directory of the MPI installation.
+``ENV{I_MPI_ROOT}``
+ Environment variable to specify the base directory of the MPI installation.
+
+For controlling the compiler wrapper step, the following variables may be set:
+
+``MPI_<lang>_COMPILER``
+ Search for the specified compiler wrapper and use it.
+``MPI_<lang>_COMPILER_FLAGS``
+ Flags to pass to the MPI compiler wrapper during interrogation. Some compiler wrappers
+ support linking debug or tracing libraries if a specific flag is passed and this variable
+ may be used to obtain them.
+``MPI_COMPILER_FLAGS``
+ Used to initialize ``MPI_<lang>_COMPILER_FLAGS`` if no language specific flag has been given.
+ Empty by default.
+``MPI_EXECUTABLE_SUFFIX``
+ A suffix which is appended to all names that are being looked for. For instance you may set this
+ to ``.mpich`` or ``.openmpi`` to prefer the one or the other on Debian and its derivatives.
+
+In order to control the guessing step, the following variable may be set:
+
+``MPI_GUESS_LIBRARY_NAME``
+ Valid values are ``MSMPI`` and ``MPICH2``. If set, only the given library will be searched for.
+ By default, ``MSMPI`` will be preferred over ``MPICH2`` if both are available.
+ This also sets ``MPI_SKIP_COMPILER_WRAPPER`` to ``true``, which may be overridden.
+
+Each of the search steps may be skipped with the following control variables:
+
+``MPI_ASSUME_NO_BUILTIN_MPI``
+ If true, the module assumes that the compiler itself does not provide an MPI implementation and
+ skips to step 2.
+``MPI_SKIP_COMPILER_WRAPPER``
+ If true, no compiler wrapper will be searched for.
+``MPI_SKIP_GUESSING``
+ If true, the guessing step will be skipped.
+
+Additionally, the following control variable is available to change search behavior:
+
+``MPI_CXX_SKIP_MPICXX``
+ Add some definitions that will disable the MPI-2 C++ bindings.
+ Currently supported are MPICH, Open MPI, Platform MPI and derivatives thereof,
+ for example MVAPICH or Intel MPI.
+
+If the find procedure fails for a variable ``MPI_<lang>_WORKS``, then the settings detected by or passed to
+the module did not work and even a simple MPI test program failed to compile.
+
+If all of these parameters were not sufficient to find the right MPI implementation, a user may
+disable the entire autodetection process by specifying both a list of libraries in ``MPI_<lang>_LIBRARIES``
+and a list of include directories in ``MPI_<lang>_ADDITIONAL_INCLUDE_DIRS``.
+Any other variable may be set in addition to these two. The module will then validate the MPI settings and store the
+settings in the cache.
+
+Cache variables for MPI
+^^^^^^^^^^^^^^^^^^^^^^^
+
+The variable ``MPI_<lang>_INCLUDE_DIRS`` will be assembled from the following variables.
+For C and CXX:
+
+``MPI_<lang>_HEADER_DIR``
+ Location of the ``mpi.h`` header on disk.
+
+For Fortran:
+
+``MPI_Fortran_F77_HEADER_DIR``
+ Location of the Fortran 77 header ``mpif.h``, if it exists.
+``MPI_Fortran_MODULE_DIR``
+ Location of the ``mpi`` or ``mpi_f08`` modules, if available.
+
+For all languages the following variables are additionally considered:
+
+``MPI_<lang>_ADDITIONAL_INCLUDE_DIRS``
+ A :ref:`;-list <CMake Language Lists>` of paths needed in addition to the normal include directories.
+``MPI_<include_name>_INCLUDE_DIR``
+ Path variables for include folders referred to by ``<include_name>``.
+``MPI_<lang>_ADDITIONAL_INCLUDE_VARS``
+ A :ref:`;-list <CMake Language Lists>` of ``<include_name>`` that will be added to the include locations of ``<lang>``.
+
+The variable ``MPI_<lang>_LIBRARIES`` will be assembled from the following variables:
+
+``MPI_<lib_name>_LIBRARY``
+ The location of a library called ``<lib_name>`` for use with MPI.
+``MPI_<lang>_LIB_NAMES``
+ A :ref:`;-list <CMake Language Lists>` of ``<lib_name>`` that will be added to the include locations of ``<lang>``.
+
+Usage of mpiexec
+^^^^^^^^^^^^^^^^
+
+When using ``MPIEXEC_EXECUTABLE`` to execute MPI applications, you should typically
+use all of the ``MPIEXEC_EXECUTABLE`` flags as follows:
+
+::
+
+ ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS}
+ ${MPIEXEC_PREFLAGS} EXECUTABLE ${MPIEXEC_POSTFLAGS} ARGS
+
+where ``EXECUTABLE`` is the MPI program, and ``ARGS`` are the arguments to
+pass to the MPI program.
+
+Advanced variables for using MPI
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The module can perform some advanced feature detections upon explicit request.
+
+**Important notice:** The following checks cannot be performed without *executing* an MPI test program.
+Consider the special considerations for the behavior of :command:`try_run` during cross compilation.
+Moreover, running an MPI program can cause additional issues, like a firewall notification on some systems.
+You should only enable these detections if you absolutely need the information.
+
+If the following variables are set to true, the respective search will be performed:
+
+``MPI_DETERMINE_Fortran_CAPABILITIES``
+ Determine for all available Fortran bindings what the values of ``MPI_SUBARRAYS_SUPPORTED`` and
+ ``MPI_ASYNC_PROTECTS_NONBLOCKING`` are and make their values available as ``MPI_Fortran_<binding>_SUBARRAYS``
+ and ``MPI_Fortran_<binding>_ASYNCPROT``, where ``<binding>`` is one of ``F77_HEADER``, ``F90_MODULE`` and
+ ``F08_MODULE``.
+``MPI_DETERMINE_LIBRARY_VERSION``
+ For each language, find the output of ``MPI_Get_library_version`` and make it available as ``MPI_<lang>_LIBRARY_VERSION_STRING``.
+ This information is usually tied to the runtime component of an MPI implementation and might differ depending on ``<lang>``.
+ Note that the return value is entirely implementation defined. This information might be used to identify
+ the MPI vendor and for example pick the correct one of multiple third party binaries that matches the MPI vendor.
+
+Backward Compatibility
+^^^^^^^^^^^^^^^^^^^^^^
+
+.. deprecated:: 3.10
+
+For backward compatibility with older versions of FindMPI, these
+variables are set:
+
+::
+
+ MPI_COMPILER MPI_LIBRARY MPI_EXTRA_LIBRARY
+ MPI_COMPILE_FLAGS MPI_INCLUDE_PATH MPI_LINK_FLAGS
+ MPI_LIBRARIES
+
+In new projects, please use the ``MPI_<lang>_XXX`` equivalents.
+Additionally, the following variables are deprecated:
+
+``MPI_<lang>_COMPILE_FLAGS``
+ Use ``MPI_<lang>_COMPILE_OPTIONS`` and ``MPI_<lang>_COMPILE_DEFINITIONS`` instead.
+``MPI_<lang>_INCLUDE_PATH``
+ For consumption use ``MPI_<lang>_INCLUDE_DIRS`` and for specifying folders use ``MPI_<lang>_ADDITIONAL_INCLUDE_DIRS`` instead.
+``MPIEXEC``
+ Use ``MPIEXEC_EXECUTABLE`` instead.
+#]=======================================================================]
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+# Generic compiler names
+set(_MPI_C_GENERIC_COMPILER_NAMES mpicc mpcc mpicc_r mpcc_r)
+set(_MPI_CXX_GENERIC_COMPILER_NAMES mpicxx mpiCC mpcxx mpCC mpic++ mpc++
+ mpicxx_r mpiCC_r mpcxx_r mpCC_r mpic++_r mpc++_r)
+set(_MPI_Fortran_GENERIC_COMPILER_NAMES mpif95 mpif95_r mpf95 mpf95_r
+ mpif90 mpif90_r mpf90 mpf90_r
+ mpif77 mpif77_r mpf77 mpf77_r
+ mpifc)
+
+#Fujitsu cross/own compiler names
+set(_MPI_Fujitsu_C_COMPILER_NAMES mpifccpx mpifcc)
+set(_MPI_Fujitsu_CXX_COMPILER_NAMES mpiFCCpx mpiFCC)
+set(_MPI_Fujitsu_Fortran_COMPILER_NAMES mpifrtpx mpifrt)
+
+# GNU compiler names
+set(_MPI_GNU_C_COMPILER_NAMES mpigcc mpgcc mpigcc_r mpgcc_r)
+set(_MPI_GNU_CXX_COMPILER_NAMES mpig++ mpg++ mpig++_r mpg++_r mpigxx)
+set(_MPI_GNU_Fortran_COMPILER_NAMES mpigfortran mpgfortran mpigfortran_r mpgfortran_r
+ mpig77 mpig77_r mpg77 mpg77_r)
+
+# Intel MPI compiler names on Windows
+if(WIN32)
+ list(APPEND _MPI_C_GENERIC_COMPILER_NAMES mpicc.bat)
+ list(APPEND _MPI_CXX_GENERIC_COMPILER_NAMES mpicxx.bat)
+ list(APPEND _MPI_Fortran_GENERIC_COMPILER_NAMES mpifc.bat)
+
+ # Intel MPI compiler names
+ set(_MPI_Intel_C_COMPILER_NAMES mpiicc.bat)
+ set(_MPI_Intel_CXX_COMPILER_NAMES mpiicpc.bat)
+ set(_MPI_Intel_Fortran_COMPILER_NAMES mpiifort.bat mpif77.bat mpif90.bat)
+
+ # Intel MPI compiler names
+ set(_MPI_IntelLLVM_C_COMPILER_NAMES mpiicc.bat)
+ set(_MPI_IntelLLVM_CXX_COMPILER_NAMES mpiicpc.bat)
+ set(_MPI_IntelLLVM_Fortran_COMPILER_NAMES mpiifort.bat mpif77.bat mpif90.bat)
+
+ # Intel MPI compiler names for MSMPI
+ set(_MPI_MSVC_C_COMPILER_NAMES mpicl.bat)
+ set(_MPI_MSVC_CXX_COMPILER_NAMES mpicl.bat)
+else()
+ # Intel compiler names
+ set(_MPI_Intel_C_COMPILER_NAMES mpiicc)
+ set(_MPI_Intel_CXX_COMPILER_NAMES mpiicpc mpiicxx mpiic++)
+ set(_MPI_Intel_Fortran_COMPILER_NAMES mpiifort mpiif95 mpiif90 mpiif77)
+
+ # Intel compiler names
+ set(_MPI_IntelLLVM_C_COMPILER_NAMES mpiicc)
+ set(_MPI_IntelLLVM_CXX_COMPILER_NAMES mpiicpc mpiicxx mpiic++)
+ set(_MPI_IntelLLVM_Fortran_COMPILER_NAMES mpiifort mpiif95 mpiif90 mpiif77)
+endif()
+
+# PGI compiler names
+set(_MPI_PGI_C_COMPILER_NAMES mpipgicc mpipgcc mppgcc)
+set(_MPI_PGI_CXX_COMPILER_NAMES mpipgic++ mpipgCC mppgCC)
+set(_MPI_PGI_Fortran_COMPILER_NAMES mpipgifort mpipgf95 mpipgf90 mppgf95 mppgf90 mpipgf77 mppgf77)
+
+# XLC MPI Compiler names
+set(_MPI_XL_C_COMPILER_NAMES mpxlc mpxlc_r mpixlc mpixlc_r)
+set(_MPI_XL_CXX_COMPILER_NAMES mpixlcxx mpixlC mpixlc++ mpxlcxx mpxlc++ mpixlc++ mpxlCC
+ mpixlcxx_r mpixlC_r mpixlc++_r mpxlcxx_r mpxlc++_r mpixlc++_r mpxlCC_r)
+set(_MPI_XL_Fortran_COMPILER_NAMES mpixlf95 mpixlf95_r mpxlf95 mpxlf95_r
+ mpixlf90 mpixlf90_r mpxlf90 mpxlf90_r
+ mpixlf77 mpixlf77_r mpxlf77 mpxlf77_r
+ mpixlf mpixlf_r mpxlf mpxlf_r)
+
+# Prepend vendor-specific compiler wrappers to the list. If we don't know the compiler,
+# attempt all of them.
+# By attempting vendor-specific compiler names first, we should avoid situations where the compiler wrapper
+# stems from a proprietary MPI and won't know which compiler it's being used for. For instance, Intel MPI
+# controls its settings via the I_MPI_CC environment variables if the generic name is being used.
+# If we know which compiler we're working with, we can use the most specialized wrapper there is in order to
+# pick up the right settings for it.
+foreach (LANG IN ITEMS C CXX Fortran)
+ set(_MPI_${LANG}_COMPILER_NAMES "")
+ foreach (id IN ITEMS Fujitsu FujitsuClang GNU Intel IntelLLVM MSVC PGI XL)
+ if (NOT CMAKE_${LANG}_COMPILER_ID OR CMAKE_${LANG}_COMPILER_ID STREQUAL id)
+ foreach(_COMPILER_NAME IN LISTS _MPI_${id}_${LANG}_COMPILER_NAMES)
+ list(APPEND _MPI_${LANG}_COMPILER_NAMES ${_COMPILER_NAME}${MPI_EXECUTABLE_SUFFIX})
+ endforeach()
+ endif()
+ unset(_MPI_${id}_${LANG}_COMPILER_NAMES)
+ endforeach()
+ foreach(_COMPILER_NAME IN LISTS _MPI_${LANG}_GENERIC_COMPILER_NAMES)
+ list(APPEND _MPI_${LANG}_COMPILER_NAMES ${_COMPILER_NAME}${MPI_EXECUTABLE_SUFFIX})
+ endforeach()
+ unset(_MPI_${LANG}_GENERIC_COMPILER_NAMES)
+endforeach()
+
+# Names to try for mpiexec
+# Only mpiexec commands are guaranteed to behave as described in the standard,
+# mpirun commands are not covered by the standard in any way whatsoever.
+# lamexec is the executable for LAM/MPI, srun is for SLURM or Open MPI with SLURM support.
+# srun -n X <executable> is however a valid command, so it behaves 'like' mpiexec.
+set(_MPIEXEC_NAMES_BASE mpiexec mpiexec.hydra mpiexec.mpd mpirun lamexec srun)
+
+unset(_MPIEXEC_NAMES)
+foreach(_MPIEXEC_NAME IN LISTS _MPIEXEC_NAMES_BASE)
+ list(APPEND _MPIEXEC_NAMES "${_MPIEXEC_NAME}${MPI_EXECUTABLE_SUFFIX}")
+endforeach()
+unset(_MPIEXEC_NAMES_BASE)
+
+function (_MPI_check_compiler LANG QUERY_FLAG OUTPUT_VARIABLE RESULT_VARIABLE)
+ if(DEFINED MPI_${LANG}_COMPILER_FLAGS)
+ separate_arguments(_MPI_COMPILER_WRAPPER_OPTIONS NATIVE_COMMAND "${MPI_${LANG}_COMPILER_FLAGS}")
+ else()
+ separate_arguments(_MPI_COMPILER_WRAPPER_OPTIONS NATIVE_COMMAND "${MPI_COMPILER_FLAGS}")
+ endif()
+ execute_process(
+ COMMAND ${MPI_${LANG}_COMPILER} ${_MPI_COMPILER_WRAPPER_OPTIONS} ${QUERY_FLAG}
+ OUTPUT_VARIABLE WRAPPER_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE WRAPPER_OUTPUT ERROR_STRIP_TRAILING_WHITESPACE
+ RESULT_VARIABLE WRAPPER_RETURN)
+ # Some compiler wrappers will yield spurious zero return values, for example
+ # Intel MPI tolerates unknown arguments and if the MPI wrappers loads a shared
+ # library that has invalid or missing version information there would be warning
+ # messages emitted by ld.so in the compiler output. In either case, we'll treat
+ # the output as invalid.
+ if("${WRAPPER_OUTPUT}" MATCHES "undefined reference|unrecognized|need to set|no version information available|command not found")
+ set(WRAPPER_RETURN 255)
+ endif()
+ # Ensure that no error output might be passed upwards.
+ if(NOT WRAPPER_RETURN EQUAL 0)
+ unset(WRAPPER_OUTPUT)
+ else()
+ # Strip leading whitespace
+ string(REGEX REPLACE "^ +" "" WRAPPER_OUTPUT "${WRAPPER_OUTPUT}")
+ endif()
+ set(${OUTPUT_VARIABLE} "${WRAPPER_OUTPUT}" PARENT_SCOPE)
+ set(${RESULT_VARIABLE} "${WRAPPER_RETURN}" PARENT_SCOPE)
+endfunction()
+
+macro(_MPI_env_set_ifnot VAR VALUE)
+ if(NOT DEFINED ENV{${VAR}})
+ set(_MPI_${VAR}_WAS_SET FALSE)
+ set(ENV{${VAR}} ${${VALUE}})
+ else()
+ set(_MPI_${VAR}_WAS_SET TRUE)
+ endif()
+endmacro()
+
+macro(_MPI_env_unset_ifnot VAR)
+ if(NOT _MPI_${VAR}_WAS_SET)
+ unset(ENV{${VAR}})
+ endif()
+endmacro()
+
+function (_MPI_interrogate_compiler LANG)
+ unset(MPI_COMPILE_CMDLINE)
+ unset(MPI_LINK_CMDLINE)
+
+ unset(MPI_COMPILE_OPTIONS_WORK)
+ unset(MPI_COMPILE_DEFINITIONS_WORK)
+ unset(MPI_INCLUDE_DIRS_WORK)
+ unset(MPI_LINK_FLAGS_WORK)
+ unset(MPI_LIB_NAMES_WORK)
+ unset(MPI_LIB_FULLPATHS_WORK)
+
+ # Define the MPICH and Intel MPI compiler variables to the compilers set in CMake.
+ # It's possible to have a per-compiler configuration in these MPI implementations and
+ # a particular MPICH derivate might check compiler interoperability.
+ # Intel MPI in particular does this with I_MPI_CHECK_COMPILER.
+ file(TO_NATIVE_PATH "${CMAKE_${LANG}_COMPILER}" _MPI_UNDERLAYING_COMPILER)
+ # On Windows, the Intel MPI batch scripts can only work with filnames - Full paths will break them.
+ # Due to the lack of other MPICH-based wrappers for Visual C++, we may treat this as default.
+ if(MSVC)
+ get_filename_component(_MPI_UNDERLAYING_COMPILER "${_MPI_UNDERLAYING_COMPILER}" NAME)
+ endif()
+ if("${LANG}" STREQUAL "C")
+ _MPI_env_set_ifnot(I_MPI_CC _MPI_UNDERLAYING_COMPILER)
+ _MPI_env_set_ifnot(MPICH_CC _MPI_UNDERLAYING_COMPILER)
+ elseif("${LANG}" STREQUAL "CXX")
+ _MPI_env_set_ifnot(I_MPI_CXX _MPI_UNDERLAYING_COMPILER)
+ _MPI_env_set_ifnot(MPICH_CXX _MPI_UNDERLAYING_COMPILER)
+ elseif("${LANG}" STREQUAL "Fortran")
+ _MPI_env_set_ifnot(I_MPI_FC _MPI_UNDERLAYING_COMPILER)
+ _MPI_env_set_ifnot(MPICH_FC _MPI_UNDERLAYING_COMPILER)
+ _MPI_env_set_ifnot(I_MPI_F77 _MPI_UNDERLAYING_COMPILER)
+ _MPI_env_set_ifnot(MPICH_F77 _MPI_UNDERLAYING_COMPILER)
+ _MPI_env_set_ifnot(I_MPI_F90 _MPI_UNDERLAYING_COMPILER)
+ _MPI_env_set_ifnot(MPICH_F90 _MPI_UNDERLAYING_COMPILER)
+ endif()
+
+ # Set these two variables for Intel MPI:
+ # - I_MPI_DEBUG_INFO_STRIP: It adds 'objcopy' lines to the compiler output. We support stripping them
+ # (see below), but if we can avoid them in the first place, we should.
+ # - I_MPI_FORT_BIND: By default Intel MPI makes the C/C++ compiler wrappers link Fortran bindings.
+ # This is so that mixed-language code doesn't require additional libraries when linking with mpicc.
+ # For our purposes, this makes little sense, since correct MPI usage from CMake already circumvenes this.
+ set(_MPI_ENV_VALUE "disable")
+ _MPI_env_set_ifnot(I_MPI_DEBUG_INFO_STRIP _MPI_ENV_VALUE)
+ _MPI_env_set_ifnot(I_MPI_FORT_BIND _MPI_ENV_VALUE)
+
+ # Check whether the -showme:compile option works. This indicates that we have either Open MPI
+ # or a newer version of LAM/MPI, and implies that -showme:link will also work.
+ # Open MPI also supports -show, but separates linker and compiler information
+ _MPI_check_compiler(${LANG} "-showme:compile" MPI_COMPILE_CMDLINE MPI_COMPILER_RETURN)
+ if (MPI_COMPILER_RETURN EQUAL 0)
+ _MPI_check_compiler(${LANG} "-showme:link" MPI_LINK_CMDLINE MPI_COMPILER_RETURN)
+
+ if (NOT MPI_COMPILER_RETURN EQUAL 0)
+ unset(MPI_COMPILE_CMDLINE)
+ endif()
+ endif()
+
+ # MPICH and MVAPICH offer -compile-info and -link-info.
+ # For modern versions, both do the same as -show. However, for old versions, they do differ
+ # when called for mpicxx and mpif90 and it's necessary to use them over -show in order to find the
+ # removed MPI C++ bindings.
+ if (NOT MPI_COMPILER_RETURN EQUAL 0)
+ _MPI_check_compiler(${LANG} "-compile-info" MPI_COMPILE_CMDLINE MPI_COMPILER_RETURN)
+
+ if (MPI_COMPILER_RETURN EQUAL 0)
+ _MPI_check_compiler(${LANG} "-link-info" MPI_LINK_CMDLINE MPI_COMPILER_RETURN)
+
+ if (NOT MPI_COMPILER_RETURN EQUAL 0)
+ unset(MPI_COMPILE_CMDLINE)
+ endif()
+ endif()
+ endif()
+
+ # MPICH, MVAPICH2 and Intel MPI just use "-show". Open MPI also offers this, but the
+ # -showme commands are more specialized.
+ if (NOT MPI_COMPILER_RETURN EQUAL 0)
+ _MPI_check_compiler(${LANG} "-show" MPI_COMPILE_CMDLINE MPI_COMPILER_RETURN)
+ endif()
+
+ # Older versions of LAM/MPI have "-showme". Open MPI also supports this.
+ # Unknown to MPICH, MVAPICH and Intel MPI.
+ if (NOT MPI_COMPILER_RETURN EQUAL 0)
+ _MPI_check_compiler(${LANG} "-showme" MPI_COMPILE_CMDLINE MPI_COMPILER_RETURN)
+ endif()
+
+ if (MPI_COMPILER_RETURN EQUAL 0 AND DEFINED MPI_COMPILE_CMDLINE)
+ # Intel MPI can be run with -compchk or I_MPI_CHECK_COMPILER set to 1.
+ # In this case, -show will be prepended with a line to the compiler checker. This is a script that performs
+ # compatibility checks and returns a non-zero exit code together with an error if something fails.
+ # It has to be called as "compchk.sh <arch> <compiler>". Here, <arch> is one out of 32 (i686), 64 (ia64) or 32e (x86_64).
+ # The compiler is identified by filename, and can be either the MPI compiler or the underlying compiler.
+ # NOTE: It is vital to run this script while the environment variables are set up, otherwise it can check the wrong compiler.
+ if("${MPI_COMPILE_CMDLINE}" MATCHES "^([^\" ]+/compchk.sh|\"[^\"]+/compchk.sh\") +([^ ]+)")
+ # Now CMAKE_MATCH_1 contains the path to the compchk.sh file and CMAKE_MATCH_2 the architecture flag.
+ unset(COMPILER_CHECKER_OUTPUT)
+ execute_process(
+ COMMAND ${CMAKE_MATCH_1} ${CMAKE_MATCH_2} ${MPI_${LANG}_COMPILER}
+ OUTPUT_VARIABLE COMPILER_CHECKER_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE COMPILER_CHECKER_OUTPUT ERROR_STRIP_TRAILING_WHITESPACE
+ RESULT_VARIABLE MPI_COMPILER_RETURN)
+ # If it returned a non-zero value, the check below will fail and cause the interrogation to be aborted.
+ if(NOT MPI_COMPILER_RETURN EQUAL 0)
+ if(NOT MPI_FIND_QUIETLY)
+ message(STATUS "Intel MPI compiler check failed: ${COMPILER_CHECKER_OUTPUT}")
+ endif()
+ else()
+ # Since the check passed, we can remove the compchk.sh script.
+ string(REGEX REPLACE "^([^\" ]+|\"[^\"]+\")/compchk.sh.*\n" "" MPI_COMPILE_CMDLINE "${MPI_COMPILE_CMDLINE}")
+ endif()
+ endif()
+ endif()
+
+ # Revert changes to the environment made previously
+ if("${LANG}" STREQUAL "C")
+ _MPI_env_unset_ifnot(I_MPI_CC)
+ _MPI_env_unset_ifnot(MPICH_CC)
+ elseif("${LANG}" STREQUAL "CXX")
+ _MPI_env_unset_ifnot(I_MPI_CXX)
+ _MPI_env_unset_ifnot(MPICH_CXX)
+ elseif("${LANG}" STREQUAL "Fortran")
+ _MPI_env_unset_ifnot(I_MPI_FC)
+ _MPI_env_unset_ifnot(MPICH_FC)
+ _MPI_env_unset_ifnot(I_MPI_F77)
+ _MPI_env_unset_ifnot(MPICH_F77)
+ _MPI_env_unset_ifnot(I_MPI_F90)
+ _MPI_env_unset_ifnot(MPICH_F90)
+ endif()
+
+ _MPI_env_unset_ifnot(I_MPI_DEBUG_INFO_STRIP)
+ _MPI_env_unset_ifnot(I_MPI_FORT_BIND)
+
+ if (NOT (MPI_COMPILER_RETURN EQUAL 0) OR NOT (DEFINED MPI_COMPILE_CMDLINE))
+ # Cannot interrogate this compiler, so exit.
+ set(MPI_${LANG}_WRAPPER_FOUND FALSE PARENT_SCOPE)
+ return()
+ endif()
+ unset(MPI_COMPILER_RETURN)
+
+ # We have our command lines, but we might need to copy MPI_COMPILE_CMDLINE
+ # into MPI_LINK_CMDLINE, if we didn't find the link line.
+ if (NOT DEFINED MPI_LINK_CMDLINE)
+ set(MPI_LINK_CMDLINE "${MPI_COMPILE_CMDLINE}")
+ endif()
+
+ # Visual Studio parsers permit each flag prefixed by either / or -.
+ # We'll normalize this to the - syntax we use for CMake purposes anyways.
+ if(MSVC)
+ foreach(_MPI_VARIABLE IN ITEMS COMPILE LINK)
+ # The Intel MPI wrappers on Windows prefix their output with some copyright boilerplate.
+ # To prevent possible problems, we discard this text before proceeding with any further matching.
+ string(REGEX REPLACE "^[^ ]+ for the Intel\\(R\\) MPI Library [^\n]+ for Windows\\*\nCopyright\\(C\\) [^\n]+, Intel Corporation\\. All rights reserved\\.\n\n" ""
+ MPI_${_MPI_VARIABLE}_CMDLINE "${MPI_${_MPI_VARIABLE}_CMDLINE}")
+ string(REGEX REPLACE "(^| )/" "\\1-" MPI_${_MPI_VARIABLE}_CMDLINE "${MPI_${_MPI_VARIABLE}_CMDLINE}")
+ string(REPLACE "-libpath:" "-LIBPATH:" MPI_${_MPI_VARIABLE}_CMDLINE "${MPI_${_MPI_VARIABLE}_CMDLINE}")
+ endforeach()
+ endif()
+
+ # For MSVC and cl-compatible compilers, the keyword /link indicates a point after which
+ # everything following is passed to the linker. In this case, we drop all prior information
+ # from the link line and treat any unknown extra flags as linker flags.
+ set(_MPI_FILTERED_LINK_INFORMATION FALSE)
+ if(MSVC)
+ if(MPI_LINK_CMDLINE MATCHES " -(link|LINK) ")
+ string(REGEX REPLACE ".+-(link|LINK) +" "" MPI_LINK_CMDLINE "${MPI_LINK_CMDLINE}")
+ set(_MPI_FILTERED_LINK_INFORMATION TRUE)
+ endif()
+ string(REGEX REPLACE " +-(link|LINK) .+" "" MPI_COMPILE_CMDLINE "${MPI_COMPILE_CMDLINE}")
+ endif()
+
+ if(UNIX)
+ # At this point, we obtained some output from a compiler wrapper that works.
+ # We'll now try to parse it into variables with meaning to us.
+ if("${LANG}" STREQUAL "Fortran")
+ # If MPICH (and derivates) didn't recognize the Fortran compiler include flag during configuration,
+ # they'll return a set of three commands, consisting out of a symlink command for mpif.h,
+ # the actual compiler command and deletion of the created symlink.
+ # Especially with M(VA)PICH-1, this appears to happen erroneously, and therefore we should translate
+ # this output into an additional include directory and then drop it from the output.
+ if("${MPI_COMPILE_CMDLINE}" MATCHES "^ln -s ([^\" ]+|\"[^\"]+\") mpif.h")
+ get_filename_component(MPI_INCLUDE_DIRS_WORK "${CMAKE_MATCH_1}" DIRECTORY)
+ string(REGEX REPLACE "^ln -s ([^\" ]+|\"[^\"]+\") mpif.h\n" "" MPI_COMPILE_CMDLINE "${MPI_COMPILE_CMDLINE}")
+ string(REGEX REPLACE "^ln -s ([^\" ]+|\"[^\"]+\") mpif.h\n" "" MPI_LINK_CMDLINE "${MPI_LINK_CMDLINE}")
+ string(REGEX REPLACE "\nrm -f mpif.h$" "" MPI_COMPILE_CMDLINE "${MPI_COMPILE_CMDLINE}")
+ string(REGEX REPLACE "\nrm -f mpif.h$" "" MPI_LINK_CMDLINE "${MPI_LINK_CMDLINE}")
+ endif()
+ endif()
+
+ # If Intel MPI was configured for static linkage with -static_mpi, the wrapper will by default strip
+ # debug information from resulting binaries (see I_MPI_DEBUG_INFO_STRIP).
+ # Since we cannot process this information into CMake logic, we need to discard the resulting objcopy
+ # commands from the output.
+ string(REGEX REPLACE "(^|\n)objcopy[^\n]+(\n|$)" "" MPI_COMPILE_CMDLINE "${MPI_COMPILE_CMDLINE}")
+ string(REGEX REPLACE "(^|\n)objcopy[^\n]+(\n|$)" "" MPI_LINK_CMDLINE "${MPI_LINK_CMDLINE}")
+ endif()
+
+ # For Visual C++, extracting compiler options in a generic fashion isn't easy. However, no MPI implementation
+ # on Windows seems to require any specific ones, either.
+ if(NOT MSVC)
+ # Extract compile options from the compile command line.
+ string(REGEX MATCHALL "(^| )-f([^\" ]+|\"[^\"]+\")" MPI_ALL_COMPILE_OPTIONS "${MPI_COMPILE_CMDLINE}")
+
+ foreach(_MPI_COMPILE_OPTION IN LISTS MPI_ALL_COMPILE_OPTIONS)
+ string(REGEX REPLACE "^ " "" _MPI_COMPILE_OPTION "${_MPI_COMPILE_OPTION}")
+
+ # Ignore -fstack-protector directives: These occur on MPICH and MVAPICH when the libraries
+ # themselves were built with this flag. However, this flag is unrelated to using MPI, and
+ # we won't match the accompanying --param-ssp-size and -Wp,-D_FORTIFY_SOURCE flags and therefore
+ # produce inconsistent results with the regularly flags.
+ # Similarly, aliasing flags do not belong into our flag array.
+ if(NOT "${_MPI_COMPILE_OPTION}" MATCHES "^-f((no-|)(stack-protector|strict-aliasing)|PI[CE]|pi[ce])")
+ list(APPEND MPI_COMPILE_OPTIONS_WORK "${_MPI_COMPILE_OPTION}")
+ endif()
+ endforeach()
+ endif()
+
+ # For GNU-style compilers, it's possible to prefix includes and definitions with certain flags to pass them
+ # only to the preprocessor. For CMake purposes, we need to treat, but ignore such scopings.
+ # Note that we do not support spaces between the arguments, i.e. -Wp,-I -Wp,/opt/mympi will not be parsed
+ # correctly. This form does not seem to occur in any common MPI implementation, however.
+ if(NOT MSVC)
+ set(_MPI_PREPROCESSOR_FLAG_REGEX "(-Wp,|-Xpreprocessor )?")
+ else()
+ set(_MPI_PREPROCESSOR_FLAG_REGEX "")
+ endif()
+
+ # Same deal as above, for the definitions.
+ string(REGEX MATCHALL "(^| )${_MPI_PREPROCESSOR_FLAG_REGEX}-D *([^\" ]+|\"[^\"]+\")" MPI_ALL_COMPILE_DEFINITIONS "${MPI_COMPILE_CMDLINE}")
+
+ foreach(_MPI_COMPILE_DEFINITION IN LISTS MPI_ALL_COMPILE_DEFINITIONS)
+ string(REGEX REPLACE "^ ?${_MPI_PREPROCESSOR_FLAG_REGEX}-D *" "" _MPI_COMPILE_DEFINITION "${_MPI_COMPILE_DEFINITION}")
+ string(REPLACE "\"" "" _MPI_COMPILE_DEFINITION "${_MPI_COMPILE_DEFINITION}")
+ if(NOT "${_MPI_COMPILE_DEFINITION}" MATCHES "^_FORTIFY_SOURCE.*")
+ list(APPEND MPI_COMPILE_DEFINITIONS_WORK "${_MPI_COMPILE_DEFINITION}")
+ endif()
+ endforeach()
+
+ # Extract include paths from compile command line
+ string(REGEX MATCHALL "(^| )${_MPI_PREPROCESSOR_FLAG_REGEX}${CMAKE_INCLUDE_FLAG_${LANG}} *([^\" ]+|\"[^\"]+\")"
+ MPI_ALL_INCLUDE_PATHS "${MPI_COMPILE_CMDLINE}")
+
+ # If extracting failed to work, we'll try using -showme:incdirs.
+ # Unlike before, we do this without the environment variables set up, but since only MPICH derivates are affected by any of them, and
+ # -showme:... is only supported by Open MPI and LAM/MPI, this isn't a concern.
+ if (NOT MPI_ALL_INCLUDE_PATHS)
+ _MPI_check_compiler(${LANG} "-showme:incdirs" MPI_INCDIRS_CMDLINE MPI_INCDIRS_COMPILER_RETURN)
+ if(MPI_INCDIRS_COMPILER_RETURN)
+ separate_arguments(MPI_ALL_INCLUDE_PATHS NATIVE_COMMAND "${MPI_INCDIRS_CMDLINE}")
+ endif()
+ endif()
+
+ foreach(_MPI_INCLUDE_PATH IN LISTS MPI_ALL_INCLUDE_PATHS)
+ string(REGEX REPLACE "^ ?${_MPI_PREPROCESSOR_FLAG_REGEX}${CMAKE_INCLUDE_FLAG_${LANG}} *" "" _MPI_INCLUDE_PATH "${_MPI_INCLUDE_PATH}")
+ string(REPLACE "\"" "" _MPI_INCLUDE_PATH "${_MPI_INCLUDE_PATH}")
+ string(REPLACE "'" "" _MPI_INCLUDE_PATH "${_MPI_INCLUDE_PATH}")
+ get_filename_component(_MPI_INCLUDE_PATH "${_MPI_INCLUDE_PATH}" REALPATH)
+ list(APPEND MPI_INCLUDE_DIRS_WORK "${_MPI_INCLUDE_PATH}")
+ endforeach()
+
+ # The next step are linker flags and library directories. Here, we first take the flags given in raw -L or -LIBPATH: syntax.
+ string(REGEX MATCHALL "(^| )${CMAKE_LIBRARY_PATH_FLAG} *([^\" ]+|\"[^\"]+\")" MPI_DIRECT_LINK_PATHS "${MPI_LINK_CMDLINE}")
+ foreach(_MPI_LPATH IN LISTS MPI_DIRECT_LINK_PATHS)
+ string(REGEX REPLACE "(^| )${CMAKE_LIBRARY_PATH_FLAG} *" "" _MPI_LPATH "${_MPI_LPATH}")
+ list(APPEND MPI_ALL_LINK_PATHS "${_MPI_LPATH}")
+ endforeach()
+
+ # If the link commandline hasn't been filtered (e.g. when using MSVC and /link), we need to extract the relevant parts first.
+ if(NOT _MPI_FILTERED_LINK_INFORMATION)
+ string(REGEX MATCHALL "(^| )(-Wl,|-Xlinker +)([^\" ]+|\"[^\"]+\")" MPI_LINK_FLAGS "${MPI_LINK_CMDLINE}")
+
+ # In this case, we could also find some indirectly given linker paths, e.g. prefixed by -Xlinker or -Wl,
+ # Since syntaxes like -Wl,-L -Wl,/my/path/to/lib are also valid, we parse these paths by first removing -Wl, and -Xlinker
+ # from the list of filtered flags and then parse the remainder of the output.
+ string(REGEX REPLACE "(-Wl,|-Xlinker +)" "" MPI_LINK_FLAGS_RAW "${MPI_LINK_FLAGS}")
+
+ # Now we can parse the leftover output. Note that spaces can now be handled since the above example would reduce to
+ # -L /my/path/to/lib and can be extracted correctly.
+ string(REGEX MATCHALL "^(${CMAKE_LIBRARY_PATH_FLAG},? *|--library-path=)([^\" ]+|\"[^\"]+\")"
+ MPI_INDIRECT_LINK_PATHS "${MPI_LINK_FLAGS_RAW}")
+
+ foreach(_MPI_LPATH IN LISTS MPI_INDIRECT_LINK_PATHS)
+ string(REGEX REPLACE "^(${CMAKE_LIBRARY_PATH_FLAG},? *|--library-path=)" "" _MPI_LPATH "${_MPI_LPATH}")
+ list(APPEND MPI_ALL_LINK_PATHS "${_MPI_LPATH}")
+ endforeach()
+
+ # We need to remove the flags we extracted from the linker flag list now.
+ string(REGEX REPLACE "(^| )(-Wl,|-Xlinker +)(${CMAKE_LIBRARY_PATH_FLAG},? *(-Wl,|-Xlinker +)?|--library-path=)([^\" ]+|\"[^\"]+\")" ""
+ MPI_LINK_CMDLINE_FILTERED "${MPI_LINK_CMDLINE}")
+
+ # Some MPI implementations pass on options they themselves were built with. Since -z,noexecstack is a common
+ # hardening, we should strip it. In general, the -z options should be undesirable.
+ string(REGEX REPLACE "(^| )-Wl,-z(,[^ ]+| +-Wl,[^ ]+)" "" MPI_LINK_CMDLINE_FILTERED "${MPI_LINK_CMDLINE_FILTERED}")
+ string(REGEX REPLACE "(^| )-Xlinker +-z +-Xlinker +[^ ]+" "" MPI_LINK_CMDLINE_FILTERED "${MPI_LINK_CMDLINE_FILTERED}")
+
+ # We only consider options of the form -Wl or -Xlinker:
+ string(REGEX MATCHALL "(^| )(-Wl,|-Xlinker +)([^\" ]+|\"[^\"]+\")" MPI_ALL_LINK_FLAGS "${MPI_LINK_CMDLINE_FILTERED}")
+
+ # As a next step, we assemble the linker flags extracted in a preliminary flags string
+ foreach(_MPI_LINK_FLAG IN LISTS MPI_ALL_LINK_FLAGS)
+ string(STRIP "${_MPI_LINK_FLAG}" _MPI_LINK_FLAG)
+ if (MPI_LINK_FLAGS_WORK)
+ string(APPEND MPI_LINK_FLAGS_WORK " ${_MPI_LINK_FLAG}")
+ else()
+ set(MPI_LINK_FLAGS_WORK "${_MPI_LINK_FLAG}")
+ endif()
+ endforeach()
+ else()
+ # In the filtered case, we obtain the link time flags by just stripping the library paths.
+ string(REGEX REPLACE "(^| )${CMAKE_LIBRARY_PATH_FLAG} *([^\" ]+|\"[^\"]+\")" "" MPI_LINK_CMDLINE_FILTERED "${MPI_LINK_CMDLINE}")
+ endif()
+
+ # If we failed to extract any linker paths, we'll try using the -showme:libdirs option with the MPI compiler.
+ # This will return a list of folders, not a set of flags!
+ if (NOT MPI_ALL_LINK_PATHS)
+ _MPI_check_compiler(${LANG} "-showme:libdirs" MPI_LIBDIRS_CMDLINE MPI_LIBDIRS_COMPILER_RETURN)
+ if(MPI_LIBDIRS_COMPILER_RETURN)
+ separate_arguments(MPI_ALL_LINK_PATHS NATIVE_COMMAND "${MPI_LIBDIRS_CMDLINE}")
+ endif()
+ endif()
+
+ # We need to remove potential quotes and convert the paths to CMake syntax while resolving them, too.
+ foreach(_MPI_LPATH IN LISTS MPI_ALL_LINK_PATHS)
+ string(REPLACE "\"" "" _MPI_LPATH "${_MPI_LPATH}")
+ get_filename_component(_MPI_LPATH "${_MPI_LPATH}" REALPATH)
+ list(APPEND MPI_LINK_DIRECTORIES_WORK "${_MPI_LPATH}")
+ endforeach()
+
+ # Extract the set of libraries to link against from the link command line
+ # This only makes sense if CMAKE_LINK_LIBRARY_FLAG is defined, i.e. a -lxxxx syntax is supported by the compiler.
+ if(CMAKE_LINK_LIBRARY_FLAG)
+ string(REGEX MATCHALL "(^| )${CMAKE_LINK_LIBRARY_FLAG}([^\" ]+|\"[^\"]+\")"
+ MPI_LIBNAMES "${MPI_LINK_CMDLINE}")
+
+ foreach(_MPI_LIB_NAME IN LISTS MPI_LIBNAMES)
+ string(REGEX REPLACE "^ ?${CMAKE_LINK_LIBRARY_FLAG}" "" _MPI_LIB_NAME "${_MPI_LIB_NAME}")
+ string(REPLACE "\"" "" _MPI_LIB_NAME "${_MPI_LIB_NAME}")
+ list(APPEND MPI_LIB_NAMES_WORK "${_MPI_LIB_NAME}")
+ endforeach()
+ endif()
+
+ # Treat linker objects given by full path, for example static libraries, import libraries
+ # or shared libraries if there aren't any import libraries in use on the system.
+ # Note that we do not consider CMAKE_<TYPE>_LIBRARY_PREFIX intentionally here: The linker will for a given file
+ # decide how to link it based on file type, not based on a prefix like 'lib'.
+ set(_MPI_LIB_SUFFIX_REGEX "${CMAKE_STATIC_LIBRARY_SUFFIX}")
+ if(DEFINED CMAKE_IMPORT_LIBRARY_SUFFIX)
+ if(NOT ("${CMAKE_IMPORT_LIBRARY_SUFFIX}" STREQUAL "${CMAKE_STATIC_LIBRARY_SUFFIX}"))
+ string(APPEND _MPI_SUFFIX_REGEX "|${CMAKE_IMPORT_LIBRARY_SUFFIX}")
+ endif()
+ else()
+ string(APPEND _MPI_LIB_SUFFIX_REGEX "|${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ endif()
+ set(_MPI_LIB_NAME_REGEX "(([^\" ]+(${_MPI_LIB_SUFFIX_REGEX}))|(\"[^\"]+(${_MPI_LIB_SUFFIX_REGEX})\"))( +|$)")
+ string(REPLACE "." "\\." _MPI_LIB_NAME_REGEX "${_MPI_LIB_NAME_REGEX}")
+
+ string(REGEX MATCHALL "${_MPI_LIB_NAME_REGEX}" MPI_LIBNAMES "${MPI_LINK_CMDLINE}")
+ foreach(_MPI_LIB_NAME IN LISTS MPI_LIBNAMES)
+ string(REGEX REPLACE "^ +\"?|\"? +$" "" _MPI_LIB_NAME "${_MPI_LIB_NAME}")
+ get_filename_component(_MPI_LIB_PATH "${_MPI_LIB_NAME}" DIRECTORY)
+ if(NOT "${_MPI_LIB_PATH}" STREQUAL "")
+ list(APPEND MPI_LIB_FULLPATHS_WORK "${_MPI_LIB_NAME}")
+ else()
+ list(APPEND MPI_LIB_NAMES_WORK "${_MPI_LIB_NAME}")
+ endif()
+ endforeach()
+
+ # Save the explicitly given link directories
+ set(MPI_LINK_DIRECTORIES_LEFTOVER "${MPI_LINK_DIRECTORIES_WORK}")
+
+ # An MPI compiler wrapper could have its MPI libraries in the implicitly
+ # linked directories of the compiler itself.
+ if(DEFINED CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES)
+ list(APPEND MPI_LINK_DIRECTORIES_WORK "${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES}")
+ endif()
+
+ # Determine full path names for all of the libraries that one needs
+ # to link against in an MPI program
+ unset(MPI_PLAIN_LIB_NAMES_WORK)
+ foreach(_MPI_LIB_NAME IN LISTS MPI_LIB_NAMES_WORK)
+ get_filename_component(_MPI_PLAIN_LIB_NAME "${_MPI_LIB_NAME}" NAME_WE)
+ list(APPEND MPI_PLAIN_LIB_NAMES_WORK "${_MPI_PLAIN_LIB_NAME}")
+ find_library(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY
+ NAMES "${_MPI_LIB_NAME}" "lib${_MPI_LIB_NAME}"
+ HINTS ${MPI_LINK_DIRECTORIES_WORK}
+ DOC "Location of the ${_MPI_PLAIN_LIB_NAME} library for MPI"
+ )
+ mark_as_advanced(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY)
+ # Remove the directory from the remainder list.
+ if(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY)
+ get_filename_component(_MPI_TAKEN_DIRECTORY "${MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY}" DIRECTORY)
+ list(REMOVE_ITEM MPI_LINK_DIRECTORIES_LEFTOVER "${_MPI_TAKEN_DIRECTORY}")
+ endif()
+ endforeach()
+
+ # Add the link directories given explicitly that we haven't used back as linker directories.
+ if(NOT WIN32)
+ foreach(_MPI_LINK_DIRECTORY IN LISTS MPI_LINK_DIRECTORIES_LEFTOVER)
+ file(TO_NATIVE_PATH "${_MPI_LINK_DIRECTORY}" _MPI_LINK_DIRECTORY_ACTUAL)
+ string(FIND "${_MPI_LINK_DIRECTORY_ACTUAL}" " " _MPI_LINK_DIRECTORY_CONTAINS_SPACE)
+ if(NOT _MPI_LINK_DIRECTORY_CONTAINS_SPACE EQUAL -1)
+ set(_MPI_LINK_DIRECTORY_ACTUAL "\"${_MPI_LINK_DIRECTORY_ACTUAL}\"")
+ endif()
+ if(MPI_LINK_FLAGS_WORK)
+ string(APPEND MPI_LINK_FLAGS_WORK " ${CMAKE_LIBRARY_PATH_FLAG}${_MPI_LINK_DIRECTORY_ACTUAL}")
+ else()
+ set(MPI_LINK_FLAGS_WORK "${CMAKE_LIBRARY_PATH_FLAG}${_MPI_LINK_DIRECTORY_ACTUAL}")
+ endif()
+ endforeach()
+ endif()
+
+ # Deal with the libraries given with full path next
+ unset(MPI_DIRECT_LIB_NAMES_WORK)
+ foreach(_MPI_LIB_FULLPATH IN LISTS MPI_LIB_FULLPATHS_WORK)
+ get_filename_component(_MPI_PLAIN_LIB_NAME "${_MPI_LIB_FULLPATH}" NAME_WE)
+ list(APPEND MPI_DIRECT_LIB_NAMES_WORK "${_MPI_PLAIN_LIB_NAME}")
+ set(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY "${_MPI_LIB_FULLPATH}" CACHE FILEPATH "Location of the ${_MPI_PLAIN_LIB_NAME} library for MPI")
+ mark_as_advanced(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY)
+ endforeach()
+ # Directly linked objects should be linked first in case some generic linker flags are needed for them.
+ if(MPI_DIRECT_LIB_NAMES_WORK)
+ set(MPI_PLAIN_LIB_NAMES_WORK "${MPI_DIRECT_LIB_NAMES_WORK};${MPI_PLAIN_LIB_NAMES_WORK}")
+ endif()
+
+ # MPI might require pthread to work. The above mechanism wouldn't detect it, but we need to
+ # link it in that case. -lpthread is covered by the normal library treatment on the other hand.
+ if("${MPI_COMPILE_CMDLINE}" MATCHES "-pthread")
+ list(APPEND MPI_COMPILE_OPTIONS_WORK "-pthread")
+ if(MPI_LINK_FLAGS_WORK)
+ string(APPEND MPI_LINK_FLAGS_WORK " -pthread")
+ else()
+ set(MPI_LINK_FLAGS_WORK "-pthread")
+ endif()
+ endif()
+
+ if(MPI_${LANG}_EXTRA_COMPILE_DEFINITIONS)
+ list(APPEND MPI_COMPILE_DEFINITIONS_WORK "${MPI_${LANG}_EXTRA_COMPILE_DEFINITIONS}")
+ endif()
+ if(MPI_${LANG}_EXTRA_COMPILE_OPTIONS)
+ list(APPEND MPI_COMPILE_OPTIONS_WORK "${MPI_${LANG}_EXTRA_COMPILE_OPTIONS}")
+ endif()
+ if(MPI_${LANG}_EXTRA_LIB_NAMES)
+ list(APPEND MPI_PLAIN_LIB_NAMES_WORK "${MPI_${LANG}_EXTRA_LIB_NAMES}")
+ endif()
+
+ # If we found MPI, set up all of the appropriate cache entries
+ if(NOT MPI_${LANG}_COMPILE_OPTIONS)
+ set(MPI_${LANG}_COMPILE_OPTIONS ${MPI_COMPILE_OPTIONS_WORK} CACHE STRING "MPI ${LANG} compilation options" FORCE)
+ endif()
+ if(NOT MPI_${LANG}_COMPILE_DEFINITIONS)
+ set(MPI_${LANG}_COMPILE_DEFINITIONS ${MPI_COMPILE_DEFINITIONS_WORK} CACHE STRING "MPI ${LANG} compilation definitions" FORCE)
+ endif()
+ if(NOT MPI_${LANG}_COMPILER_INCLUDE_DIRS)
+ set(MPI_${LANG}_COMPILER_INCLUDE_DIRS ${MPI_INCLUDE_DIRS_WORK} CACHE STRING "MPI ${LANG} compiler wrapper include directories" FORCE)
+ endif()
+ if(NOT MPI_${LANG}_LINK_FLAGS)
+ set(MPI_${LANG}_LINK_FLAGS ${MPI_LINK_FLAGS_WORK} CACHE STRING "MPI ${LANG} linker flags" FORCE)
+ endif()
+ if(NOT MPI_${LANG}_LIB_NAMES)
+ set(MPI_${LANG}_LIB_NAMES ${MPI_PLAIN_LIB_NAMES_WORK} CACHE STRING "MPI ${LANG} libraries to link against" FORCE)
+ endif()
+ set(MPI_${LANG}_WRAPPER_FOUND TRUE PARENT_SCOPE)
+endfunction()
+
+function(_MPI_guess_settings LANG)
+ set(MPI_GUESS_FOUND FALSE)
+ # Currently only MSMPI and MPICH2 on Windows are supported, so we can skip this search if we're not targeting that.
+ if(WIN32)
+ # MSMPI
+
+ # The environment variables MSMPI_INC and MSMPILIB32/64 are the only ways of locating the MSMPI_SDK,
+ # which is installed separately from the runtime. Thus it's possible to have mpiexec but not MPI headers
+ # or import libraries and vice versa.
+ if(NOT MPI_GUESS_LIBRARY_NAME OR "${MPI_GUESS_LIBRARY_NAME}" STREQUAL "MSMPI")
+ # We first attempt to locate the msmpi.lib. Should be find it, we'll assume that the MPI present is indeed
+ # Microsoft MPI.
+ if("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
+ file(TO_CMAKE_PATH "$ENV{MSMPI_LIB64}" MPI_MSMPI_LIB_PATH)
+ file(TO_CMAKE_PATH "$ENV{MSMPI_INC}/x64" MPI_MSMPI_INC_PATH_EXTRA)
+ else()
+ file(TO_CMAKE_PATH "$ENV{MSMPI_LIB32}" MPI_MSMPI_LIB_PATH)
+ file(TO_CMAKE_PATH "$ENV{MSMPI_INC}/x86" MPI_MSMPI_INC_PATH_EXTRA)
+ endif()
+
+ find_library(MPI_msmpi_LIBRARY
+ NAMES msmpi
+ HINTS ${MPI_MSMPI_LIB_PATH}
+ DOC "Location of the msmpi library for Microsoft MPI")
+ mark_as_advanced(MPI_msmpi_LIBRARY)
+
+ if(MPI_msmpi_LIBRARY)
+ # Next, we attempt to locate the MPI header. Note that for Fortran we know that mpif.h is a way
+ # MSMPI can be used and therefore that header has to be present.
+ if(NOT MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS)
+ get_filename_component(MPI_MSMPI_INC_DIR "$ENV{MSMPI_INC}" REALPATH)
+ set(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS "${MPI_MSMPI_INC_DIR}" CACHE STRING "MPI ${LANG} additional include directories" FORCE)
+ unset(MPI_MSMPI_INC_DIR)
+ endif()
+
+ # For MSMPI, one can compile the MPI module by building the mpi.f90 shipped with the MSMPI SDK,
+ # thus it might be present or provided by the user. Figuring out which is supported is done later on.
+ # The PGI Fortran compiler for instance ships a prebuilt set of modules in its own include folder.
+ # Should a user be employing PGI or have built its own set and provided it via cache variables, the
+ # splitting routine would have located the module files.
+
+ # For C and C++, we're done here (MSMPI does not ship the MPI-2 C++ bindings) - however, for Fortran
+ # we need some extra library to glue Fortran support together:
+ # MSMPI ships 2-4 Fortran libraries, each for different Fortran compiler behaviors. The library names
+ # ending with a c are using the cdecl calling convention, whereas those ending with an s are for Fortran
+ # implementations using stdcall. Therefore, the 64-bit MSMPI only ships those ending in 'c', whereas the 32-bit
+ # has both variants available.
+ # The second difference is the last but one letter, if it's an e(nd), the length of a string argument is
+ # passed by the Fortran compiler after all other arguments on the parameter list, if it's an m(ixed),
+ # it's passed immediately after the string address.
+
+ # To summarize:
+ # - msmpifec: CHARACTER length passed after the parameter list and using cdecl calling convention
+ # - msmpifmc: CHARACTER length passed directly after string address and using cdecl calling convention
+ # - msmpifes: CHARACTER length passed after the parameter list and using stdcall calling convention
+ # - msmpifms: CHARACTER length passed directly after string address and using stdcall calling convention
+ # 32-bit MSMPI ships all four libraries, 64-bit MSMPI ships only the first two.
+
+ # As is, Intel Fortran and PGI Fortran both use the 'ec' variant of the calling convention, whereas
+ # the old Compaq Visual Fortran compiler defaulted to the 'ms' version. It's possible to make Intel Fortran
+ # use the CVF calling convention using /iface:cvf, but we assume - and this is also assumed in FortranCInterface -
+ # this isn't the case. It's also possible to make CVF use the 'ec' variant, using /iface=(cref,nomixed_str_len_arg).
+
+ # Our strategy is now to locate all libraries, but enter msmpifec into the LIB_NAMES array.
+ # Should this not be adequate it's a straightforward way for a user to change the LIB_NAMES array and
+ # have his library found. Still, this should not be necessary outside of exceptional cases, as reasoned.
+ if ("${LANG}" STREQUAL "Fortran")
+ set(MPI_MSMPI_CALLINGCONVS c)
+ if("${CMAKE_SIZEOF_VOID_P}" EQUAL 4)
+ list(APPEND MPI_MSMPI_CALLINGCONVS s)
+ endif()
+ foreach(mpistrlenpos IN ITEMS e m)
+ foreach(mpicallingconv IN LISTS MPI_MSMPI_CALLINGCONVS)
+ find_library(MPI_msmpif${mpistrlenpos}${mpicallingconv}_LIBRARY
+ NAMES msmpif${mpistrlenpos}${mpicallingconv}
+ HINTS "${MPI_MSMPI_LIB_PATH}"
+ DOC "Location of the msmpi${mpistrlenpos}${mpicallingconv} library for Microsoft MPI")
+ mark_as_advanced(MPI_msmpif${mpistrlenpos}${mpicallingconv}_LIBRARY)
+ endforeach()
+ endforeach()
+ if(NOT MPI_${LANG}_LIB_NAMES)
+ set(MPI_${LANG}_LIB_NAMES "msmpi;msmpifec" CACHE STRING "MPI ${LANG} libraries to link against" FORCE)
+ endif()
+
+ # At this point we're *not* done. MSMPI requires an additional include file for Fortran giving the value
+ # of MPI_AINT. This file is called mpifptr.h located in the x64 and x86 subfolders, respectively.
+ find_path(MPI_mpifptr_INCLUDE_DIR
+ NAMES "mpifptr.h"
+ HINTS "${MPI_MSMPI_INC_PATH_EXTRA}"
+ DOC "Location of the mpifptr.h extra header for Microsoft MPI")
+ if(NOT MPI_${LANG}_ADDITIONAL_INCLUDE_VARS)
+ set(MPI_${LANG}_ADDITIONAL_INCLUDE_VARS "mpifptr" CACHE STRING "MPI ${LANG} additional include directory variables, given in the form MPI_<name>_INCLUDE_DIR." FORCE)
+ endif()
+ mark_as_advanced(MPI_${LANG}_ADDITIONAL_INCLUDE_VARS MPI_mpifptr_INCLUDE_DIR)
+ else()
+ if(NOT MPI_${LANG}_LIB_NAMES)
+ set(MPI_${LANG}_LIB_NAMES "msmpi" CACHE STRING "MPI ${LANG} libraries to link against" FORCE)
+ endif()
+ endif()
+ mark_as_advanced(MPI_${LANG}_LIB_NAMES)
+ set(MPI_GUESS_FOUND TRUE)
+
+ if(_MPIEXEC_NOT_GIVEN)
+ unset(MPIEXEC_EXECUTABLE CACHE)
+ endif()
+
+ find_program(MPIEXEC_EXECUTABLE
+ NAMES mpiexec
+ HINTS $ENV{MSMPI_BIN} "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MPI;InstallRoot]/Bin"
+ DOC "Executable for running MPI programs.")
+ endif()
+ endif()
+
+ # At this point there's not many MPIs that we could still consider.
+ # OpenMPI 1.6.x and below supported Windows, but these ship compiler wrappers that still work.
+ # The only other relevant MPI implementation without a wrapper is MPICH2, which had Windows support in 1.4.1p1 and older.
+ if(NOT MPI_GUESS_FOUND AND (NOT MPI_GUESS_LIBRARY_NAME OR "${MPI_GUESS_LIBRARY_NAME}" STREQUAL "MPICH2"))
+ set(MPI_MPICH_PREFIX_PATHS
+ "$ENV{ProgramW6432}/MPICH2/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MPICH\\SMPD;binary]/../lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MPICH2;Path]/lib"
+ )
+
+ # All of C, C++ and Fortran will need mpi.lib, so we'll look for this first
+ find_library(MPI_mpi_LIBRARY
+ NAMES mpi
+ HINTS ${MPI_MPICH_PREFIX_PATHS})
+ mark_as_advanced(MPI_mpi_LIBRARY)
+ # If we found mpi.lib, we detect the rest of MPICH2
+ if(MPI_mpi_LIBRARY)
+ set(MPI_MPICH_LIB_NAMES "mpi")
+ # If MPI-2 C++ bindings are requested, we need to locate cxx.lib as well.
+ # Otherwise, MPICH_SKIP_MPICXX will be defined and these bindings aren't needed.
+ if("${LANG}" STREQUAL "CXX" AND NOT MPI_CXX_SKIP_MPICXX)
+ find_library(MPI_cxx_LIBRARY
+ NAMES cxx
+ HINTS ${MPI_MPICH_PREFIX_PATHS})
+ mark_as_advanced(MPI_cxx_LIBRARY)
+ list(APPEND MPI_MPICH_LIB_NAMES "cxx")
+ # For Fortran, MPICH2 provides three different libraries:
+ # fmpich2.lib which uses uppercase symbols and cdecl,
+ # fmpich2s.lib which uses uppercase symbols and stdcall (32-bit only),
+ # fmpich2g.lib which uses lowercase symbols with double underscores and cdecl.
+ # fmpich2s.lib would be useful for Compaq Visual Fortran, fmpich2g.lib has to be used with GNU g77 and is also
+ # provided in the form of an .a archive for MinGW and Cygwin. From our perspective, fmpich2.lib is the only one
+ # we need to try, and if it doesn't work with the given Fortran compiler we'd find out later on during validation
+ elseif("${LANG}" STREQUAL "Fortran")
+ find_library(MPI_fmpich2_LIBRARY
+ NAMES fmpich2
+ HINTS ${MPI_MPICH_PREFIX_PATHS})
+ find_library(MPI_fmpich2s_LIBRARY
+ NAMES fmpich2s
+ HINTS ${MPI_MPICH_PREFIX_PATHS})
+ find_library(MPI_fmpich2g_LIBRARY
+ NAMES fmpich2g
+ HINTS ${MPI_MPICH_PREFIX_PATHS})
+ mark_as_advanced(MPI_fmpich2_LIBRARY MPI_fmpich2s_LIBRARY MPI_fmpich2g_LIBRARY)
+ list(APPEND MPI_MPICH_LIB_NAMES "fmpich2")
+ endif()
+
+ if(NOT MPI_${LANG}_LIB_NAMES)
+ set(MPI_${LANG}_LIB_NAMES "${MPI_MPICH_LIB_NAMES}" CACHE STRING "MPI ${LANG} libraries to link against" FORCE)
+ endif()
+ unset(MPI_MPICH_LIB_NAMES)
+
+ if(NOT MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS)
+ # For MPICH2, the include folder would be in ../include relative to the library folder.
+ get_filename_component(MPI_MPICH_ROOT_DIR "${MPI_mpi_LIBRARY}" DIRECTORY)
+ get_filename_component(MPI_MPICH_ROOT_DIR "${MPI_MPICH_ROOT_DIR}" DIRECTORY)
+ if(IS_DIRECTORY "${MPI_MPICH_ROOT_DIR}/include")
+ set(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS "${MPI_MPICH_ROOT_DIR}/include" CACHE STRING "MPI ${LANG} additional include directory variables, given in the form MPI_<name>_INCLUDE_DIR." FORCE)
+ endif()
+ unset(MPI_MPICH_ROOT_DIR)
+ endif()
+ set(MPI_GUESS_FOUND TRUE)
+
+ if(_MPIEXEC_NOT_GIVEN)
+ unset(MPIEXEC_EXECUTABLE CACHE)
+ endif()
+
+ find_program(MPIEXEC_EXECUTABLE
+ NAMES ${_MPIEXEC_NAMES}
+ HINTS "$ENV{ProgramW6432}/MPICH2/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MPICH\\SMPD;binary]"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MPICH2;Path]/bin"
+ DOC "Executable for running MPI programs.")
+ endif()
+ unset(MPI_MPICH_PREFIX_PATHS)
+ endif()
+ endif()
+ set(MPI_${LANG}_GUESS_FOUND "${MPI_GUESS_FOUND}" PARENT_SCOPE)
+endfunction()
+
+function(_MPI_adjust_compile_definitions LANG)
+ if("${LANG}" STREQUAL "CXX")
+ # To disable the C++ bindings, we need to pass some definitions since the mpi.h header has to deal with both C and C++
+ # bindings in MPI-2.
+ if(MPI_CXX_SKIP_MPICXX AND NOT MPI_${LANG}_COMPILE_DEFINITIONS MATCHES "SKIP_MPICXX")
+ # MPICH_SKIP_MPICXX is being used in MPICH and derivatives like MVAPICH or Intel MPI
+ # OMPI_SKIP_MPICXX is being used in Open MPI
+ # _MPICC_H is being used for IBM Platform MPI
+ list(APPEND MPI_${LANG}_COMPILE_DEFINITIONS "MPICH_SKIP_MPICXX" "OMPI_SKIP_MPICXX" "_MPICC_H")
+ set(MPI_${LANG}_COMPILE_DEFINITIONS "${MPI_${LANG}_COMPILE_DEFINITIONS}" CACHE STRING "MPI ${LANG} compilation definitions" FORCE)
+ endif()
+ endif()
+endfunction()
+
+macro(_MPI_assemble_libraries LANG)
+ set(MPI_${LANG}_LIBRARIES "")
+ # Only for libraries do we need to check whether the compiler's linking stage is separate.
+ if(NOT "${MPI_${LANG}_COMPILER}" STREQUAL "${CMAKE_${LANG}_COMPILER}" OR NOT MPI_${LANG}_WORKS_IMPLICIT)
+ foreach(mpilib IN LISTS MPI_${LANG}_LIB_NAMES)
+ list(APPEND MPI_${LANG}_LIBRARIES ${MPI_${mpilib}_LIBRARY})
+ endforeach()
+ endif()
+endmacro()
+
+macro(_MPI_assemble_include_dirs LANG)
+ set(MPI_${LANG}_INCLUDE_DIRS
+ ${MPI_${LANG}_COMPILER_INCLUDE_DIRS}
+ ${MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS}
+ )
+ if("${LANG}" MATCHES "(C|CXX)")
+ if(MPI_${LANG}_HEADER_DIR)
+ list(APPEND MPI_${LANG}_INCLUDE_DIRS "${MPI_${LANG}_HEADER_DIR}")
+ endif()
+ else() # Fortran
+ if(MPI_${LANG}_F77_HEADER_DIR)
+ list(APPEND MPI_${LANG}_INCLUDE_DIRS "${MPI_${LANG}_F77_HEADER_DIR}")
+ endif()
+ if(MPI_${LANG}_MODULE_DIR)
+ list(APPEND MPI_${LANG}_INCLUDE_DIRS "${MPI_${LANG}_MODULE_DIR}")
+ endif()
+ endif()
+ if(MPI_${LANG}_INCLUDE_DIRS)
+ list(REMOVE_DUPLICATES MPI_${LANG}_INCLUDE_DIRS)
+ endif()
+endmacro()
+
+macro(_MPI_split_include_dirs LANG)
+ # Backwards compatibility: Search INCLUDE_PATH if given.
+ if(MPI_${LANG}_INCLUDE_PATH)
+ list(APPEND MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS "${MPI_${LANG}_INCLUDE_PATH}")
+ endif()
+
+ # We try to find the headers/modules among those paths (and system paths)
+ # For C/C++, we just need to have a look for mpi.h.
+ if("${LANG}" MATCHES "(C|CXX)")
+ find_path(MPI_${LANG}_HEADER_DIR "mpi.h"
+ HINTS
+ ${MPI_${LANG}_COMPILER_INCLUDE_DIRS}
+ ${MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS}
+ )
+ mark_as_advanced(MPI_${LANG}_HEADER_DIR)
+ if(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS)
+ list(REMOVE_ITEM MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS "${MPI_${LANG}_HEADER_DIR}")
+ endif()
+
+ # Fortran is more complicated here: An implementation could provide
+ # any of the Fortran 77/90/2008 APIs for MPI. For example, MSMPI
+ # only provides Fortran 77 and - if mpi.f90 is built - potentially
+ # a Fortran 90 module.
+ elseif("${LANG}" STREQUAL "Fortran")
+ find_path(MPI_${LANG}_F77_HEADER_DIR "mpif.h"
+ HINTS
+ ${MPI_${LANG}_COMPILER_INCLUDE_DIRS}
+ ${MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS}
+ )
+ find_path(MPI_${LANG}_MODULE_DIR
+ NAMES "mpi.mod" "mpi_f08.mod"
+ HINTS
+ ${MPI_${LANG}_COMPILER_INCLUDE_DIRS}
+ ${MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS}
+ )
+ if(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS)
+ list(REMOVE_ITEM MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS
+ "${MPI_${LANG}_F77_HEADER_DIR}"
+ "${MPI_${LANG}_MODULE_DIR}"
+ )
+ endif()
+ mark_as_advanced(MPI_${LANG}_F77_HEADER_DIR MPI_${LANG}_MODULE_DIR)
+ endif()
+
+ # Remove duplicates and default system directories from the list.
+ if(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS)
+ list(REMOVE_DUPLICATES MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS)
+ foreach(MPI_IMPLICIT_INC_DIR IN LISTS CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES)
+ list(REMOVE_ITEM MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS ${MPI_IMPLICIT_INC_DIR})
+ endforeach()
+ endif()
+
+ set(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS ${MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS} CACHE STRING "MPI ${LANG} additional include directories" FORCE)
+endmacro()
+
+macro(_MPI_create_imported_target LANG)
+ if(NOT TARGET MPI::MPI_${LANG})
+ add_library(MPI::MPI_${LANG} INTERFACE IMPORTED)
+ endif()
+
+ # When this is consumed for compiling CUDA, use '-Xcompiler' to wrap '-pthread' and '-fexceptions'.
+ string(REPLACE "-pthread" "$<$<COMPILE_LANG_AND_ID:CUDA,NVIDIA>:SHELL:-Xcompiler >-pthread"
+ _MPI_${LANG}_COMPILE_OPTIONS "${MPI_${LANG}_COMPILE_OPTIONS}")
+ string(REPLACE "-fexceptions" "$<$<COMPILE_LANG_AND_ID:CUDA,NVIDIA>:SHELL:-Xcompiler >-fexceptions"
+ _MPI_${LANG}_COMPILE_OPTIONS "${_MPI_${LANG}_COMPILE_OPTIONS}")
+ set_property(TARGET MPI::MPI_${LANG} PROPERTY INTERFACE_COMPILE_OPTIONS "${_MPI_${LANG}_COMPILE_OPTIONS}")
+ unset(_MPI_${LANG}_COMPILE_OPTIONS)
+
+ set_property(TARGET MPI::MPI_${LANG} PROPERTY INTERFACE_COMPILE_DEFINITIONS "${MPI_${LANG}_COMPILE_DEFINITIONS}")
+
+ if(MPI_${LANG}_LINK_FLAGS)
+ string(REPLACE "," "$<COMMA>" _MPI_${LANG}_LINK_FLAGS "${MPI_${LANG}_LINK_FLAGS}")
+ string(PREPEND _MPI_${LANG}_LINK_FLAGS "$<HOST_LINK:SHELL:")
+ string(APPEND _MPI_${LANG}_LINK_FLAGS ">")
+ set_property(TARGET MPI::MPI_${LANG} PROPERTY INTERFACE_LINK_OPTIONS "${_MPI_${LANG}_LINK_FLAGS}")
+ endif()
+ # If the compiler links MPI implicitly, no libraries will be found as they're contained within
+ # CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES already.
+ if(MPI_${LANG}_LIBRARIES)
+ set_property(TARGET MPI::MPI_${LANG} PROPERTY INTERFACE_LINK_LIBRARIES "${MPI_${LANG}_LIBRARIES}")
+ endif()
+ # Given the new design of FindMPI, INCLUDE_DIRS will always be located, even under implicit linking.
+ set_property(TARGET MPI::MPI_${LANG} PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${MPI_${LANG}_INCLUDE_DIRS}")
+endmacro()
+
+function(_MPI_try_staged_settings LANG MPI_TEST_FILE_NAME MODE RUN_BINARY SUPPRESS_ERRORS)
+ set(WORK_DIR "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindMPI")
+ set(SRC_DIR "${CMAKE_ROOT}/Modules/FindMPI")
+ set(BIN_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindMPI/${MPI_TEST_FILE_NAME}_${LANG}.bin")
+ unset(MPI_TEST_COMPILE_DEFINITIONS)
+ if("${LANG}" STREQUAL "Fortran")
+ if("${MODE}" STREQUAL "F90_MODULE")
+ set(MPI_Fortran_INCLUDE_LINE "use mpi\n implicit none")
+ elseif("${MODE}" STREQUAL "F08_MODULE")
+ set(MPI_Fortran_INCLUDE_LINE "use mpi_f08\n implicit none")
+ else() # F77 header
+ set(MPI_Fortran_INCLUDE_LINE "implicit none\n include 'mpif.h'")
+ endif()
+ configure_file("${SRC_DIR}/${MPI_TEST_FILE_NAME}.f90.in" "${WORK_DIR}/${MPI_TEST_FILE_NAME}.f90" @ONLY)
+ set(MPI_TEST_SOURCE_FILE "${WORK_DIR}/${MPI_TEST_FILE_NAME}.f90")
+ elseif("${LANG}" STREQUAL "CXX")
+ configure_file("${SRC_DIR}/${MPI_TEST_FILE_NAME}.c" "${WORK_DIR}/${MPI_TEST_FILE_NAME}.cpp" COPYONLY)
+ set(MPI_TEST_SOURCE_FILE "${WORK_DIR}/${MPI_TEST_FILE_NAME}.cpp")
+ if("${MODE}" STREQUAL "TEST_MPICXX")
+ set(MPI_TEST_COMPILE_DEFINITIONS TEST_MPI_MPICXX)
+ endif()
+ else() # C
+ set(MPI_TEST_SOURCE_FILE "${SRC_DIR}/${MPI_TEST_FILE_NAME}.c")
+ endif()
+ if(RUN_BINARY)
+ try_run(MPI_RUN_RESULT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE} MPI_RESULT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE}
+ "${CMAKE_BINARY_DIR}" SOURCES "${MPI_TEST_SOURCE_FILE}"
+ COMPILE_DEFINITIONS ${MPI_TEST_COMPILE_DEFINITIONS}
+ LINK_LIBRARIES MPI::MPI_${LANG}
+ RUN_OUTPUT_VARIABLE MPI_RUN_OUTPUT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE}
+ COMPILE_OUTPUT_VARIABLE _MPI_TRY_${MPI_TEST_FILE_NAME}_${MODE}_OUTPUT)
+ set(MPI_RUN_OUTPUT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE} "${MPI_RUN_OUTPUT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE}}" PARENT_SCOPE)
+ else()
+ try_compile(MPI_RESULT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE}
+ "${CMAKE_BINARY_DIR}" SOURCES "${MPI_TEST_SOURCE_FILE}"
+ COMPILE_DEFINITIONS ${MPI_TEST_COMPILE_DEFINITIONS}
+ LINK_LIBRARIES MPI::MPI_${LANG}
+ COPY_FILE "${BIN_FILE}"
+ OUTPUT_VARIABLE _MPI_TRY_${MPI_TEST_FILE_NAME}_${MODE}_OUTPUT)
+ endif()
+ if(NOT SUPPRESS_ERRORS)
+ if(NOT MPI_RESULT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE})
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "The MPI test ${MPI_TEST_FILE_NAME} for ${LANG} in mode ${MODE} failed to compile with the following output:\n${_MPI_TRY_${MPI_TEST_FILE_NAME}_${MODE}_OUTPUT}\n\n")
+ elseif(DEFINED MPI_RUN_RESULT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE} AND MPI_RUN_RESULT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE})
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "The MPI test ${MPI_TEST_FILE_NAME} for ${LANG} in mode ${MODE} failed to run with the following output:\n${MPI_RUN_OUTPUT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE}}\n\n")
+ endif()
+ endif()
+endfunction()
+
+macro(_MPI_check_lang_works LANG SUPPRESS_ERRORS)
+ # For Fortran we may have by the MPI-3 standard an implementation that provides:
+ # - the mpi_f08 module
+ # - *both*, the mpi module and 'mpif.h'
+ # Since older MPI standards (MPI-1) did not define anything but 'mpif.h', we need to check all three individually.
+ if( NOT MPI_${LANG}_WORKS )
+ if("${LANG}" STREQUAL "Fortran")
+ set(MPI_Fortran_INTEGER_LINE "(kind=MPI_INTEGER_KIND)")
+ _MPI_try_staged_settings(${LANG} test_mpi F77_HEADER FALSE ${SUPPRESS_ERRORS})
+ _MPI_try_staged_settings(${LANG} test_mpi F90_MODULE FALSE ${SUPPRESS_ERRORS})
+ _MPI_try_staged_settings(${LANG} test_mpi F08_MODULE FALSE ${SUPPRESS_ERRORS})
+
+ set(MPI_${LANG}_WORKS FALSE)
+
+ foreach(mpimethod IN ITEMS F77_HEADER F08_MODULE F90_MODULE)
+ if(MPI_RESULT_${LANG}_test_mpi_${mpimethod})
+ set(MPI_${LANG}_WORKS TRUE)
+ set(MPI_${LANG}_HAVE_${mpimethod} TRUE)
+ else()
+ set(MPI_${LANG}_HAVE_${mpimethod} FALSE)
+ endif()
+ endforeach()
+ # MPI-1 versions had no MPI_INTGER_KIND defined, so we need to try without it.
+ # However, MPI-1 also did not define the Fortran 90 and 08 modules, so we only try the F77 header.
+ unset(MPI_Fortran_INTEGER_LINE)
+ if(NOT MPI_${LANG}_WORKS)
+ _MPI_try_staged_settings(${LANG} test_mpi F77_HEADER_NOKIND FALSE ${SUPPRESS_ERRORS})
+ if(MPI_RESULT_${LANG}_test_mpi_F77_HEADER_NOKIND)
+ set(MPI_${LANG}_WORKS TRUE)
+ set(MPI_${LANG}_HAVE_F77_HEADER TRUE)
+ endif()
+ endif()
+ else()
+ _MPI_try_staged_settings(${LANG} test_mpi normal FALSE ${SUPPRESS_ERRORS})
+ # If 'test_mpi' built correctly, we've found valid MPI settings. There might not be MPI-2 C++ support, but there can't
+ # be MPI-2 C++ support without the C bindings being present, so checking for them is sufficient.
+ set(MPI_${LANG}_WORKS "${MPI_RESULT_${LANG}_test_mpi_normal}")
+ endif()
+ endif()
+endmacro()
+
+# Some systems install various MPI implementations in separate folders in some MPI prefix
+# This macro enumerates all such subfolders and adds them to the list of hints that will be searched.
+macro(MPI_search_mpi_prefix_folder PREFIX_FOLDER)
+ if(EXISTS "${PREFIX_FOLDER}")
+ file(GLOB _MPI_folder_children RELATIVE "${PREFIX_FOLDER}" "${PREFIX_FOLDER}/*")
+ foreach(_MPI_folder_child IN LISTS _MPI_folder_children)
+ if(IS_DIRECTORY "${PREFIX_FOLDER}/${_MPI_folder_child}")
+ list(APPEND MPI_HINT_DIRS "${PREFIX_FOLDER}/${_MPI_folder_child}")
+ endif()
+ endforeach()
+ endif()
+endmacro()
+
+set(MPI_HINT_DIRS ${MPI_HOME} $ENV{MPI_HOME} $ENV{I_MPI_ROOT})
+if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Linux")
+ # SUSE Linux Enterprise Server stores its MPI implementations under /usr/lib64/mpi/gcc/<name>
+ # We enumerate the subfolders and append each as a prefix
+ MPI_search_mpi_prefix_folder("/usr/lib64/mpi/gcc")
+elseif("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "FreeBSD")
+ # FreeBSD ships mpich under the normal system paths - but available openmpi implementations
+ # will be found in /usr/local/mpi/<name>
+ MPI_search_mpi_prefix_folder("/usr/local/mpi")
+endif()
+
+# Most MPI distributions have some form of mpiexec or mpirun which gives us something we can look for.
+# The MPI standard does not mandate the existence of either, but instead only makes requirements if a distribution
+# ships an mpiexec program (mpirun executables are not regulated by the standard).
+
+# We defer searching for mpiexec binaries belonging to guesses until later. By doing so, mismatches between mpiexec
+# and the MPI we found should be reduced.
+if(NOT MPIEXEC_EXECUTABLE)
+ set(_MPIEXEC_NOT_GIVEN TRUE)
+else()
+ set(_MPIEXEC_NOT_GIVEN FALSE)
+endif()
+
+find_program(MPIEXEC_EXECUTABLE
+ NAMES ${_MPIEXEC_NAMES}
+ PATH_SUFFIXES bin sbin
+ HINTS ${MPI_HINT_DIRS}
+ DOC "Executable for running MPI programs.")
+
+# call get_filename_component twice to remove mpiexec and the directory it exists in (typically bin).
+# This gives us a fairly reliable base directory to search for /bin /lib and /include from.
+get_filename_component(_MPI_BASE_DIR "${MPIEXEC_EXECUTABLE}" PATH)
+get_filename_component(_MPI_BASE_DIR "${_MPI_BASE_DIR}" PATH)
+
+# According to the MPI standard, section 8.8 -n is a guaranteed, and the only guaranteed way to
+# launch an MPI process using mpiexec if such a program exists.
+set(MPIEXEC_NUMPROC_FLAG "-n" CACHE STRING "Flag used by MPI to specify the number of processes for mpiexec; the next option will be the number of processes.")
+set(MPIEXEC_PREFLAGS "" CACHE STRING "These flags will be directly before the executable that is being run by mpiexec.")
+set(MPIEXEC_POSTFLAGS "" CACHE STRING "These flags will be placed after all flags passed to mpiexec.")
+
+# Set the number of processes to the physical processor count
+cmake_host_system_information(RESULT _MPIEXEC_NUMPROCS QUERY NUMBER_OF_PHYSICAL_CORES)
+set(MPIEXEC_MAX_NUMPROCS "${_MPIEXEC_NUMPROCS}" CACHE STRING "Maximum number of processors available to run MPI applications.")
+unset(_MPIEXEC_NUMPROCS)
+mark_as_advanced(MPIEXEC_EXECUTABLE MPIEXEC_NUMPROC_FLAG MPIEXEC_PREFLAGS MPIEXEC_POSTFLAGS MPIEXEC_MAX_NUMPROCS)
+
+#=============================================================================
+# Backward compatibility input hacks. Propagate the FindMPI hints to C and
+# CXX if the respective new versions are not defined. Translate the old
+# MPI_LIBRARY and MPI_EXTRA_LIBRARY to respective MPI_${LANG}_LIBRARIES.
+#
+# Once we find the new variables, we translate them back into their old
+# equivalents below.
+if(NOT MPI_IGNORE_LEGACY_VARIABLES)
+ foreach (LANG IN ITEMS C CXX)
+ # Old input variables.
+ set(_MPI_OLD_INPUT_VARS COMPILER COMPILE_FLAGS INCLUDE_PATH LINK_FLAGS)
+
+ # Set new vars based on their old equivalents, if the new versions are not already set.
+ foreach (var ${_MPI_OLD_INPUT_VARS})
+ if (NOT MPI_${LANG}_${var} AND MPI_${var})
+ set(MPI_${LANG}_${var} "${MPI_${var}}")
+ endif()
+ endforeach()
+
+ # Chop the old compile flags into options and definitions
+
+ unset(MPI_${LANG}_EXTRA_COMPILE_DEFINITIONS)
+ unset(MPI_${LANG}_EXTRA_COMPILE_OPTIONS)
+ if(MPI_${LANG}_COMPILE_FLAGS)
+ separate_arguments(MPI_SEPARATE_FLAGS NATIVE_COMMAND "${MPI_${LANG}_COMPILE_FLAGS}")
+ foreach(_MPI_FLAG IN LISTS MPI_SEPARATE_FLAGS)
+ if("${_MPI_FLAG}" MATCHES "^ *-D([^ ]+)")
+ list(APPEND MPI_${LANG}_EXTRA_COMPILE_DEFINITIONS "${CMAKE_MATCH_1}")
+ else()
+ list(APPEND MPI_${LANG}_EXTRA_COMPILE_OPTIONS "${_MPI_FLAG}")
+ endif()
+ endforeach()
+ unset(MPI_SEPARATE_FLAGS)
+ endif()
+
+ # If a list of libraries was given, we'll split it into new-style cache variables
+ unset(MPI_${LANG}_EXTRA_LIB_NAMES)
+ if(NOT MPI_${LANG}_LIB_NAMES)
+ foreach(_MPI_LIB IN LISTS MPI_${LANG}_LIBRARIES MPI_LIBRARY MPI_EXTRA_LIBRARY)
+ if(_MPI_LIB)
+ get_filename_component(_MPI_PLAIN_LIB_NAME "${_MPI_LIB}" NAME_WE)
+ get_filename_component(_MPI_LIB_NAME "${_MPI_LIB}" NAME)
+ get_filename_component(_MPI_LIB_DIR "${_MPI_LIB}" DIRECTORY)
+ list(APPEND MPI_${LANG}_EXTRA_LIB_NAMES "${_MPI_PLAIN_LIB_NAME}")
+ find_library(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY
+ NAMES "${_MPI_LIB_NAME}" "lib${_MPI_LIB_NAME}"
+ HINTS ${_MPI_LIB_DIR} $ENV{MPI_LIB}
+ DOC "Location of the ${_MPI_PLAIN_LIB_NAME} library for MPI"
+ )
+ mark_as_advanced(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY)
+ endif()
+ endforeach()
+ endif()
+ endforeach()
+endif()
+#=============================================================================
+
+unset(MPI_VERSION)
+unset(MPI_VERSION_MAJOR)
+unset(MPI_VERSION_MINOR)
+
+unset(_MPI_MIN_VERSION)
+
+# If the user specified a library name we assume they prefer that library over a wrapper. If not, they can disable skipping manually.
+if(NOT DEFINED MPI_SKIP_COMPILER_WRAPPER AND MPI_GUESS_LIBRARY_NAME)
+ set(MPI_SKIP_COMPILER_WRAPPER TRUE)
+endif()
+
+# This loop finds the compilers and sends them off for interrogation.
+foreach(LANG IN ITEMS C CXX Fortran)
+ if(CMAKE_${LANG}_COMPILER_LOADED)
+ if(NOT MPI_FIND_COMPONENTS)
+ set(_MPI_FIND_${LANG} TRUE)
+ elseif( ${LANG} IN_LIST MPI_FIND_COMPONENTS)
+ set(_MPI_FIND_${LANG} TRUE)
+ elseif( ${LANG} STREQUAL CXX AND NOT MPI_CXX_SKIP_MPICXX AND MPICXX IN_LIST MPI_FIND_COMPONENTS )
+ set(_MPI_FIND_${LANG} TRUE)
+ else()
+ set(_MPI_FIND_${LANG} FALSE)
+ endif()
+ else()
+ set(_MPI_FIND_${LANG} FALSE)
+ if(${LANG} IN_LIST MPI_FIND_COMPONENTS)
+ string(APPEND _MPI_FAIL_REASON "MPI component '${LANG}' was requested, but language ${LANG} is not enabled. ")
+ endif()
+ endif()
+ if(_MPI_FIND_${LANG})
+ if( ${LANG} STREQUAL CXX AND NOT MPICXX IN_LIST MPI_FIND_COMPONENTS )
+ set(MPI_CXX_SKIP_MPICXX FALSE CACHE BOOL "If true, the MPI-2 C++ bindings are disabled using definitions.")
+ mark_as_advanced(MPI_CXX_SKIP_MPICXX)
+ endif()
+ if(NOT (MPI_${LANG}_LIB_NAMES AND (MPI_${LANG}_INCLUDE_PATH OR MPI_${LANG}_INCLUDE_DIRS OR MPI_${LANG}_COMPILER_INCLUDE_DIRS)))
+ set(MPI_${LANG}_TRIED_IMPLICIT FALSE)
+ set(MPI_${LANG}_WORKS_IMPLICIT FALSE)
+ if(NOT MPI_${LANG}_COMPILER AND NOT MPI_ASSUME_NO_BUILTIN_MPI)
+ # Should the imported targets be empty, we effectively try whether the compiler supports MPI on its own, which is the case on e.g.
+ # Cray PrgEnv.
+ _MPI_create_imported_target(${LANG})
+ _MPI_check_lang_works(${LANG} TRUE)
+
+ # If the compiler can build MPI code on its own, it functions as an MPI compiler and we'll set the variable to point to it.
+ if(MPI_${LANG}_WORKS)
+ set(MPI_${LANG}_COMPILER "${CMAKE_${LANG}_COMPILER}" CACHE FILEPATH "MPI compiler for ${LANG}" FORCE)
+ set(MPI_${LANG}_WORKS_IMPLICIT TRUE)
+ endif()
+ set(MPI_${LANG}_TRIED_IMPLICIT TRUE)
+ endif()
+
+ if(NOT "${MPI_${LANG}_COMPILER}" STREQUAL "${CMAKE_${LANG}_COMPILER}" OR NOT MPI_${LANG}_WORKS)
+ set(MPI_${LANG}_WRAPPER_FOUND FALSE)
+ set(MPI_PINNED_COMPILER FALSE)
+
+ if(NOT MPI_SKIP_COMPILER_WRAPPER)
+ if(MPI_${LANG}_COMPILER)
+ # If the user supplies a compiler *name* instead of an absolute path, assume that we need to find THAT compiler.
+ if (NOT IS_ABSOLUTE "${MPI_${LANG}_COMPILER}")
+ # Get rid of our default list of names and just search for the name the user wants.
+ set(_MPI_${LANG}_COMPILER_NAMES "${MPI_${LANG}_COMPILER}")
+ unset(MPI_${LANG}_COMPILER CACHE)
+ endif()
+ # If the user specifies a compiler, we don't want to try to search libraries either.
+ set(MPI_PINNED_COMPILER TRUE)
+ endif()
+
+ # If we have an MPI base directory, we'll try all compiler names in that one first.
+ # This should prevent mixing different MPI environments
+ if(_MPI_BASE_DIR)
+ find_program(MPI_${LANG}_COMPILER
+ NAMES ${_MPI_${LANG}_COMPILER_NAMES}
+ PATH_SUFFIXES bin sbin
+ HINTS ${_MPI_BASE_DIR}
+ NO_DEFAULT_PATH
+ DOC "MPI compiler for ${LANG}"
+ )
+ endif()
+
+ # If the base directory did not help (for example because the mpiexec isn't in the same directory as the compilers),
+ # we shall try searching in the default paths.
+ find_program(MPI_${LANG}_COMPILER
+ NAMES ${_MPI_${LANG}_COMPILER_NAMES}
+ PATH_SUFFIXES bin sbin
+ DOC "MPI compiler for ${LANG}"
+ )
+
+ if("${MPI_${LANG}_COMPILER}" STREQUAL "${CMAKE_${LANG}_COMPILER}")
+ set(MPI_PINNED_COMPILER TRUE)
+
+ # If we haven't made the implicit compiler test yet, perform it now.
+ if(NOT MPI_${LANG}_TRIED_IMPLICIT)
+ _MPI_create_imported_target(${LANG})
+ _MPI_check_lang_works(${LANG} TRUE)
+ endif()
+
+ # Should the MPI compiler not work implicitly for MPI, still interrogate it.
+ # Otherwise, MPI compilers for which CMake has separate linking stages, e.g. Intel MPI on Windows where link.exe is being used
+ # directly during linkage instead of CMAKE_<LANG>_COMPILER will not work.
+ if(NOT MPI_${LANG}_WORKS)
+ set(MPI_${LANG}_WORKS_IMPLICIT FALSE)
+ _MPI_interrogate_compiler(${LANG})
+ else()
+ set(MPI_${LANG}_WORKS_IMPLICIT TRUE)
+ endif()
+ elseif(MPI_${LANG}_COMPILER)
+ _MPI_interrogate_compiler(${LANG})
+ endif()
+ endif()
+
+ if(NOT MPI_PINNED_COMPILER AND NOT MPI_${LANG}_WRAPPER_FOUND)
+ # If MPI_PINNED_COMPILER wasn't given, and the MPI compiler we potentially found didn't work, we withdraw it.
+ set(MPI_${LANG}_COMPILER "MPI_${LANG}_COMPILER-NOTFOUND" CACHE FILEPATH "MPI compiler for ${LANG}" FORCE)
+ if(NOT MPI_SKIP_GUESSING)
+ # For C++, we may use the settings for C. Should a given compiler wrapper for C++ not exist, but one for C does, we copy over the
+ # settings for C. An MPI distribution that is in this situation would be IBM Platform MPI.
+ if("${LANG}" STREQUAL "CXX" AND MPI_C_WRAPPER_FOUND)
+ set(MPI_${LANG}_COMPILE_OPTIONS ${MPI_C_COMPILE_OPTIONS} CACHE STRING "MPI ${LANG} compilation options" )
+ set(MPI_${LANG}_COMPILE_DEFINITIONS ${MPI_C_COMPILE_DEFINITIONS} CACHE STRING "MPI ${LANG} compilation definitions" )
+ set(MPI_${LANG}_COMPILER_INCLUDE_DIRS ${MPI_C_INCLUDE_DIRS} CACHE STRING "MPI ${LANG} compiler wrapper include directories")
+ set(MPI_${LANG}_LINK_FLAGS ${MPI_C_LINK_FLAGS} CACHE STRING "MPI ${LANG} linker flags" )
+ set(MPI_${LANG}_LIB_NAMES ${MPI_C_LIB_NAMES} CACHE STRING "MPI ${LANG} libraries to link against" )
+ else()
+ _MPI_guess_settings(${LANG})
+ endif()
+ endif()
+ endif()
+ endif()
+ endif()
+
+ if(NOT "${MPI_${LANG}_COMPILER}" STREQUAL "${CMAKE_${LANG}_COMPILER}")
+ _MPI_split_include_dirs(${LANG})
+ _MPI_assemble_include_dirs(${LANG})
+ else()
+ set(MPI_${LANG}_INCLUDE_DIRS "")
+ endif()
+ _MPI_assemble_libraries(${LANG})
+
+ _MPI_adjust_compile_definitions(${LANG})
+ # We always create imported targets even if they're empty
+ _MPI_create_imported_target(${LANG})
+
+ if(NOT MPI_${LANG}_WORKS)
+ _MPI_check_lang_works(${LANG} FALSE)
+ endif()
+
+ # Next, we'll initialize the MPI variables that have not been previously set.
+ set(MPI_${LANG}_COMPILE_OPTIONS "" CACHE STRING "MPI ${LANG} compilation flags" )
+ set(MPI_${LANG}_COMPILE_DEFINITIONS "" CACHE STRING "MPI ${LANG} compilation definitions" )
+ set(MPI_${LANG}_COMPILER_INCLUDE_DIRS "" CACHE STRING "MPI ${LANG} compiler wrapper include directories")
+ set(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS "" CACHE STRING "MPI ${LANG} additional include directories")
+ set(MPI_${LANG}_LINK_FLAGS "" CACHE STRING "MPI ${LANG} linker flags" )
+ if(NOT MPI_${LANG}_COMPILER STREQUAL CMAKE_${LANG}_COMPILER)
+ set(MPI_${LANG}_LIB_NAMES "" CACHE STRING "MPI ${LANG} libraries to link against" )
+ endif()
+ mark_as_advanced(
+ MPI_${LANG}_COMPILE_OPTIONS
+ MPI_${LANG}_COMPILE_DEFINITIONS
+ MPI_${LANG}_LINK_FLAGS
+ MPI_${LANG}_LIB_NAMES
+ MPI_${LANG}_COMPILER_INCLUDE_DIRS
+ MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS
+ MPI_${LANG}_COMPILER
+ )
+
+ # If we've found MPI, then we'll perform additional analysis: Determine the MPI version, MPI library version, supported
+ # MPI APIs (i.e. MPI-2 C++ bindings). For Fortran we also need to find specific parameters if we're under MPI-3.
+ if(MPI_${LANG}_WORKS)
+ if("${LANG}" STREQUAL "CXX" AND NOT DEFINED MPI_MPICXX_FOUND)
+ if(NOT MPI_CXX_SKIP_MPICXX AND NOT MPI_CXX_VALIDATE_SKIP_MPICXX)
+ _MPI_try_staged_settings(${LANG} test_mpi MPICXX FALSE FALSE)
+ if(MPI_RESULT_${LANG}_test_mpi_MPICXX)
+ set(MPI_MPICXX_FOUND TRUE)
+ else()
+ set(MPI_MPICXX_FOUND FALSE)
+ endif()
+ else()
+ set(MPI_MPICXX_FOUND FALSE)
+ endif()
+ endif()
+
+ # At this point, we know the bindings present but not the MPI version or anything else.
+ if(NOT DEFINED MPI_${LANG}_VERSION)
+ unset(MPI_${LANG}_VERSION_MAJOR)
+ unset(MPI_${LANG}_VERSION_MINOR)
+ endif()
+ set(MPI_BIN_FOLDER ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindMPI)
+
+ # For Fortran, we'll want to use the most modern MPI binding to test capabilities other than the
+ # Fortran parameters, since those depend on the method of consumption.
+ # For C++, we can always use the C bindings, and should do so, since the C++ bindings do not exist in MPI-3
+ # whereas the C bindings do, and the C++ bindings never offered any feature advantage over their C counterparts.
+ if("${LANG}" STREQUAL "Fortran")
+ if(MPI_${LANG}_HAVE_F08_MODULE)
+ set(MPI_${LANG}_HIGHEST_METHOD F08_MODULE)
+ elseif(MPI_${LANG}_HAVE_F90_MODULE)
+ set(MPI_${LANG}_HIGHEST_METHOD F90_MODULE)
+ else()
+ set(MPI_${LANG}_HIGHEST_METHOD F77_HEADER)
+ endif()
+
+ # Another difference between C and Fortran is that we can't use the preprocessor to determine whether MPI_VERSION
+ # and MPI_SUBVERSION are provided. These defines did not exist in MPI 1.0 and 1.1 and therefore might not
+ # exist. For C/C++, test_mpi.c will handle the MPI_VERSION extraction, but for Fortran, we need mpiver.f90.
+ if(NOT DEFINED MPI_${LANG}_VERSION)
+ _MPI_try_staged_settings(${LANG} mpiver ${MPI_${LANG}_HIGHEST_METHOD} FALSE FALSE)
+ if(MPI_RESULT_${LANG}_mpiver_${MPI_${LANG}_HIGHEST_METHOD})
+ file(STRINGS ${MPI_BIN_FOLDER}/mpiver_${LANG}.bin _MPI_VERSION_STRING LIMIT_COUNT 1 REGEX "INFO:MPI-VER")
+ if("${_MPI_VERSION_STRING}" MATCHES ".*INFO:MPI-VER\\[([0-9]+)\\.([0-9]+)\\].*")
+ set(MPI_${LANG}_VERSION_MAJOR "${CMAKE_MATCH_1}")
+ set(MPI_${LANG}_VERSION_MINOR "${CMAKE_MATCH_2}")
+ set(MPI_${LANG}_VERSION "${MPI_${LANG}_VERSION_MAJOR}.${MPI_${LANG}_VERSION_MINOR}")
+ endif()
+ endif()
+ endif()
+
+ # Finally, we want to find out which capabilities a given interface supports, compare the MPI-3 standard.
+ # This is determined by interface specific parameters MPI_SUBARRAYS_SUPPORTED and MPI_ASYNC_PROTECTS_NONBLOCKING
+ # and might vary between the different methods of consumption.
+ if(MPI_DETERMINE_Fortran_CAPABILITIES AND NOT MPI_Fortran_CAPABILITIES_DETERMINED)
+ foreach(mpimethod IN ITEMS F08_MODULE F90_MODULE F77_HEADER)
+ if(MPI_${LANG}_HAVE_${mpimethod})
+ set(MPI_${LANG}_${mpimethod}_SUBARRAYS FALSE)
+ set(MPI_${LANG}_${mpimethod}_ASYNCPROT FALSE)
+ _MPI_try_staged_settings(${LANG} fortranparam_mpi ${mpimethod} TRUE FALSE)
+ if(MPI_RESULT_${LANG}_fortranparam_mpi_${mpimethod} AND
+ NOT "${MPI_RUN_RESULT_${LANG}_fortranparam_mpi_${mpimethod}}" STREQUAL "FAILED_TO_RUN")
+ if("${MPI_RUN_OUTPUT_${LANG}_fortranparam_mpi_${mpimethod}}" MATCHES
+ ".*INFO:SUBARRAYS\\[ *([TF]) *\\]-ASYNCPROT\\[ *([TF]) *\\].*")
+ if("${CMAKE_MATCH_1}" STREQUAL "T")
+ set(MPI_${LANG}_${mpimethod}_SUBARRAYS TRUE)
+ endif()
+ if("${CMAKE_MATCH_2}" STREQUAL "T")
+ set(MPI_${LANG}_${mpimethod}_ASYNCPROT TRUE)
+ endif()
+ endif()
+ endif()
+ endif()
+ endforeach()
+ set(MPI_Fortran_CAPABILITIES_DETERMINED TRUE)
+ endif()
+ else()
+ set(MPI_${LANG}_HIGHEST_METHOD normal)
+
+ # By the MPI-2 standard, MPI_VERSION and MPI_SUBVERSION are valid for both C and C++ bindings.
+ if(NOT DEFINED MPI_${LANG}_VERSION)
+ file(STRINGS ${MPI_BIN_FOLDER}/test_mpi_${LANG}.bin _MPI_VERSION_STRING LIMIT_COUNT 1 REGEX "INFO:MPI-VER")
+ if("${_MPI_VERSION_STRING}" MATCHES ".*INFO:MPI-VER\\[([0-9]+)\\.([0-9]+)\\].*")
+ set(MPI_${LANG}_VERSION_MAJOR "${CMAKE_MATCH_1}")
+ set(MPI_${LANG}_VERSION_MINOR "${CMAKE_MATCH_2}")
+ set(MPI_${LANG}_VERSION "${MPI_${LANG}_VERSION_MAJOR}.${MPI_${LANG}_VERSION_MINOR}")
+ endif()
+ endif()
+ endif()
+
+ unset(MPI_BIN_FOLDER)
+
+ # At this point, we have dealt with determining the MPI version and parameters for each Fortran method available.
+ # The one remaining issue is to determine which MPI library is installed.
+ # Determining the version and vendor of the MPI library is only possible via MPI_Get_library_version() at runtime,
+ # and therefore we cannot do this while cross-compiling (a user may still define MPI_<lang>_LIBRARY_VERSION_STRING
+ # themselves and we'll attempt splitting it, which is equivalent to provide the try_run output).
+ # It's also worth noting that the installed version string can depend on the language, or on the system the binary
+ # runs on if MPI is not statically linked.
+ if(MPI_DETERMINE_LIBRARY_VERSION AND NOT MPI_${LANG}_LIBRARY_VERSION_STRING)
+ _MPI_try_staged_settings(${LANG} libver_mpi ${MPI_${LANG}_HIGHEST_METHOD} TRUE FALSE)
+ if(MPI_RESULT_${LANG}_libver_mpi_${MPI_${LANG}_HIGHEST_METHOD} AND
+ "${MPI_RUN_RESULT_${LANG}_libver_mpi_${MPI_${LANG}_HIGHEST_METHOD}}" EQUAL "0")
+ string(STRIP "${MPI_RUN_OUTPUT_${LANG}_libver_mpi_${MPI_${LANG}_HIGHEST_METHOD}}"
+ MPI_${LANG}_LIBRARY_VERSION_STRING)
+ else()
+ set(MPI_${LANG}_LIBRARY_VERSION_STRING "NOTFOUND")
+ endif()
+ endif()
+ endif()
+
+ set(MPI_${LANG}_FIND_QUIETLY ${MPI_FIND_QUIETLY})
+ set(MPI_${LANG}_FIND_VERSION ${MPI_FIND_VERSION})
+ set(MPI_${LANG}_FIND_VERSION_EXACT ${MPI_FIND_VERSION_EXACT})
+
+ unset(MPI_${LANG}_REQUIRED_VARS)
+ if (NOT "${MPI_${LANG}_COMPILER}" STREQUAL "${CMAKE_${LANG}_COMPILER}")
+ foreach(mpilibname IN LISTS MPI_${LANG}_LIB_NAMES)
+ list(APPEND MPI_${LANG}_REQUIRED_VARS "MPI_${mpilibname}_LIBRARY")
+ endforeach()
+ list(APPEND MPI_${LANG}_REQUIRED_VARS "MPI_${LANG}_LIB_NAMES")
+ if("${LANG}" STREQUAL "Fortran")
+ # For Fortran we only need one of the module or header directories to have *some* support for MPI.
+ if(NOT MPI_${LANG}_MODULE_DIR)
+ list(APPEND MPI_${LANG}_REQUIRED_VARS "MPI_${LANG}_F77_HEADER_DIR")
+ endif()
+ if(NOT MPI_${LANG}_F77_HEADER_DIR)
+ list(APPEND MPI_${LANG}_REQUIRED_VARS "MPI_${LANG}_MODULE_DIR")
+ endif()
+ else()
+ list(APPEND MPI_${LANG}_REQUIRED_VARS "MPI_${LANG}_HEADER_DIR")
+ endif()
+ if(MPI_${LANG}_ADDITIONAL_INCLUDE_VARS)
+ foreach(mpiincvar IN LISTS MPI_${LANG}_ADDITIONAL_INCLUDE_VARS)
+ list(APPEND MPI_${LANG}_REQUIRED_VARS "MPI_${mpiincvar}_INCLUDE_DIR")
+ endforeach()
+ endif()
+ # Append the works variable now. If the settings did not work, this will show up properly.
+ list(APPEND MPI_${LANG}_REQUIRED_VARS "MPI_${LANG}_WORKS")
+ else()
+ # If the compiler worked implicitly, use its path as output.
+ # Should the compiler variable be set, we also require it to work.
+ list(APPEND MPI_${LANG}_REQUIRED_VARS "MPI_${LANG}_COMPILER")
+ if(MPI_${LANG}_COMPILER)
+ list(APPEND MPI_${LANG}_REQUIRED_VARS "MPI_${LANG}_WORKS")
+ endif()
+ endif()
+ find_package_handle_standard_args(MPI_${LANG} NAME_MISMATCHED
+ REQUIRED_VARS ${MPI_${LANG}_REQUIRED_VARS}
+ VERSION_VAR MPI_${LANG}_VERSION)
+
+ if(DEFINED MPI_${LANG}_VERSION)
+ if(NOT _MPI_MIN_VERSION OR _MPI_MIN_VERSION VERSION_GREATER MPI_${LANG}_VERSION)
+ set(_MPI_MIN_VERSION MPI_${LANG}_VERSION)
+ endif()
+ endif()
+ endif()
+endforeach()
+
+unset(_MPI_REQ_VARS)
+foreach(LANG IN ITEMS C CXX Fortran)
+ if((NOT MPI_FIND_COMPONENTS AND CMAKE_${LANG}_COMPILER_LOADED) OR LANG IN_LIST MPI_FIND_COMPONENTS)
+ list(APPEND _MPI_REQ_VARS "MPI_${LANG}_FOUND")
+ endif()
+endforeach()
+
+if(MPICXX IN_LIST MPI_FIND_COMPONENTS)
+ list(APPEND _MPI_REQ_VARS "MPI_MPICXX_FOUND")
+endif()
+
+find_package_handle_standard_args(MPI
+ REQUIRED_VARS ${_MPI_REQ_VARS}
+ VERSION_VAR ${_MPI_MIN_VERSION}
+ REASON_FAILURE_MESSAGE "${_MPI_FAIL_REASON}"
+ HANDLE_COMPONENTS)
+
+#=============================================================================
+# More backward compatibility stuff
+
+# For compatibility reasons, we also define MPIEXEC
+set(MPIEXEC "${MPIEXEC_EXECUTABLE}")
+
+# Copy over MPI_<LANG>_INCLUDE_PATH from the assembled INCLUDE_DIRS.
+foreach(LANG IN ITEMS C CXX Fortran)
+ if(MPI_${LANG}_FOUND)
+ set(MPI_${LANG}_INCLUDE_PATH "${MPI_${LANG}_INCLUDE_DIRS}")
+ unset(MPI_${LANG}_COMPILE_FLAGS)
+ if(MPI_${LANG}_COMPILE_OPTIONS)
+ list(JOIN MPI_${LANG}_COMPILE_OPTIONS " " MPI_${LANG}_COMPILE_FLAGS)
+ endif()
+ if(MPI_${LANG}_COMPILE_DEFINITIONS)
+ foreach(_MPI_DEF IN LISTS MPI_${LANG}_COMPILE_DEFINITIONS)
+ string(APPEND MPI_${LANG}_COMPILE_FLAGS " -D${_MPI_DEF}")
+ endforeach()
+ endif()
+ endif()
+endforeach()
+
+# Bare MPI sans ${LANG} vars are set to CXX then C, depending on what was found.
+# This mimics the behavior of the old language-oblivious FindMPI.
+set(_MPI_OLD_VARS COMPILER INCLUDE_PATH COMPILE_FLAGS LINK_FLAGS LIBRARIES)
+if (MPI_CXX_FOUND)
+ foreach (var ${_MPI_OLD_VARS})
+ set(MPI_${var} ${MPI_CXX_${var}})
+ endforeach()
+elseif (MPI_C_FOUND)
+ foreach (var ${_MPI_OLD_VARS})
+ set(MPI_${var} ${MPI_C_${var}})
+ endforeach()
+endif()
+
+# Chop MPI_LIBRARIES into the old-style MPI_LIBRARY and MPI_EXTRA_LIBRARY, and set them in cache.
+if (MPI_LIBRARIES)
+ list(GET MPI_LIBRARIES 0 MPI_LIBRARY_WORK)
+ set(MPI_LIBRARY "${MPI_LIBRARY_WORK}")
+ unset(MPI_LIBRARY_WORK)
+else()
+ set(MPI_LIBRARY "MPI_LIBRARY-NOTFOUND")
+endif()
+
+list(LENGTH MPI_LIBRARIES MPI_NUMLIBS)
+if (MPI_NUMLIBS GREATER 1)
+ set(MPI_EXTRA_LIBRARY_WORK "${MPI_LIBRARIES}")
+ list(REMOVE_AT MPI_EXTRA_LIBRARY_WORK 0)
+ set(MPI_EXTRA_LIBRARY "${MPI_EXTRA_LIBRARY_WORK}")
+ unset(MPI_EXTRA_LIBRARY_WORK)
+else()
+ set(MPI_EXTRA_LIBRARY "MPI_EXTRA_LIBRARY-NOTFOUND")
+endif()
+set(MPI_IGNORE_LEGACY_VARIABLES TRUE)
+#=============================================================================
+
+# unset these vars to cleanup namespace
+unset(_MPI_OLD_VARS)
+unset(_MPI_PREFIX_PATH)
+unset(_MPI_BASE_DIR)
+foreach (lang C CXX Fortran)
+ unset(_MPI_${LANG}_COMPILER_NAMES)
+endforeach()
+
+cmake_policy(POP)
diff --git a/Modules/FindMPI/fortranparam_mpi.f90.in b/Modules/FindMPI/fortranparam_mpi.f90.in
new file mode 100644
index 0000000..30f912c
--- /dev/null
+++ b/Modules/FindMPI/fortranparam_mpi.f90.in
@@ -0,0 +1,4 @@
+ program mpi_ver
+ @MPI_Fortran_INCLUDE_LINE@
+ print *, 'INFO:SUBARRAYS[', MPI_SUBARRAYS_SUPPORTED, ']-ASYNCPROT[', MPI_ASYNC_PROTECTS_NONBLOCKING, ']'
+ end program mpi_ver
diff --git a/Modules/FindMPI/libver_mpi.c b/Modules/FindMPI/libver_mpi.c
new file mode 100644
index 0000000..d89328a
--- /dev/null
+++ b/Modules/FindMPI/libver_mpi.c
@@ -0,0 +1,20 @@
+#include <mpi.h>
+
+#ifdef __cplusplus
+# include <cstdio>
+#else
+# include <stdio.h>
+#endif
+
+int main(int argc, char* argv[])
+{
+ char mpilibver_str[MPI_MAX_LIBRARY_VERSION_STRING];
+ int mpilibver_len;
+ MPI_Get_library_version(mpilibver_str, &mpilibver_len);
+#ifdef __cplusplus
+ std::puts(mpilibver_str);
+#else
+ puts(mpilibver_str);
+#endif
+ return 0;
+}
diff --git a/Modules/FindMPI/libver_mpi.f90.in b/Modules/FindMPI/libver_mpi.f90.in
new file mode 100644
index 0000000..7938587
--- /dev/null
+++ b/Modules/FindMPI/libver_mpi.f90.in
@@ -0,0 +1,7 @@
+ program mpi_ver
+ @MPI_Fortran_INCLUDE_LINE@
+ character(len=MPI_MAX_LIBRARY_VERSION_STRING) :: mpilibver_str
+ integer(kind=MPI_INTEGER_KIND) :: ierror, reslen
+ call MPI_GET_LIBRARY_VERSION(mpilibver_str, reslen, ierror)
+ print *, mpilibver_str
+ end program mpi_ver
diff --git a/Modules/FindMPI/mpiver.f90.in b/Modules/FindMPI/mpiver.f90.in
new file mode 100644
index 0000000..a254523
--- /dev/null
+++ b/Modules/FindMPI/mpiver.f90.in
@@ -0,0 +1,10 @@
+ program mpi_ver
+ @MPI_Fortran_INCLUDE_LINE@
+ integer(kind=kind(MPI_VERSION)), parameter :: zero = ichar('0')
+ character, dimension(17), parameter :: mpiver_str =&
+ (/ 'I', 'N', 'F', 'O', ':', 'M', 'P', 'I', '-', 'V', 'E', 'R', '[', &
+ char(zero + MPI_VERSION), &
+ '.', &
+ char(zero + MPI_SUBVERSION), ']' /)
+ print *, mpiver_str
+ end program mpi_ver
diff --git a/Modules/FindMPI/test_mpi.c b/Modules/FindMPI/test_mpi.c
new file mode 100644
index 0000000..7c96d54
--- /dev/null
+++ b/Modules/FindMPI/test_mpi.c
@@ -0,0 +1,38 @@
+#include <mpi.h>
+
+#ifdef __cplusplus
+# include <cstdio>
+#else
+# include <stdio.h>
+#endif
+
+#if defined(MPI_VERSION) && defined(MPI_SUBVERSION)
+const char mpiver_str[] = { 'I', 'N',
+ 'F', 'O',
+ ':', 'M',
+ 'P', 'I',
+ '-', 'V',
+ 'E', 'R',
+ '[', ('0' + MPI_VERSION),
+ '.', ('0' + MPI_SUBVERSION),
+ ']', '\0' };
+#endif
+
+int main(int argc, char* argv[])
+{
+#if defined(MPI_VERSION) && defined(MPI_SUBVERSION)
+# ifdef __cplusplus
+ std::puts(mpiver_str);
+# else
+ puts(mpiver_str);
+# endif
+#endif
+#ifdef TEST_MPI_MPICXX
+ MPI::MPI_Init(&argc, &argv);
+ MPI::MPI_Finalize();
+#else
+ MPI_Init(&argc, &argv);
+ MPI_Finalize();
+#endif
+ return 0;
+}
diff --git a/Modules/FindMPI/test_mpi.f90.in b/Modules/FindMPI/test_mpi.f90.in
new file mode 100644
index 0000000..4d43a04
--- /dev/null
+++ b/Modules/FindMPI/test_mpi.f90.in
@@ -0,0 +1,6 @@
+ program hello
+ @MPI_Fortran_INCLUDE_LINE@
+ integer@MPI_Fortran_INTEGER_LINE@ ierror
+ call MPI_INIT(ierror)
+ call MPI_FINALIZE(ierror)
+ end program
diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake
new file mode 100644
index 0000000..2f56d15
--- /dev/null
+++ b/Modules/FindMatlab.cmake
@@ -0,0 +1,1899 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindMatlab
+----------
+
+Finds Matlab or Matlab Compiler Runtime (MCR) and provides Matlab tools,
+libraries and compilers to CMake.
+
+This package primary purpose is to find the libraries associated with Matlab
+or the MCR in order to be able to build Matlab extensions (mex files). It
+can also be used:
+
+* to run specific commands in Matlab in case Matlab is available
+* for declaring Matlab unit test
+* to retrieve various information from Matlab (mex extensions, versions and
+ release queries, ...)
+
+.. versionadded:: 3.12
+ Added Matlab Compiler Runtime (MCR) support.
+
+The module supports the following components:
+
+* ``ENG_LIBRARY`` and ``MAT_LIBRARY``: respectively the ``ENG`` and ``MAT``
+ libraries of Matlab
+* ``MAIN_PROGRAM`` the Matlab binary program. Note that this component is not
+ available on the MCR version, and will yield an error if the MCR is found
+ instead of the regular Matlab installation.
+* ``MEX_COMPILER`` the MEX compiler.
+* ``MCC_COMPILER`` the MCC compiler, included with the Matlab Compiler add-on.
+* ``SIMULINK`` the Simulink environment.
+
+.. versionadded:: 3.7
+ Added the ``MAT_LIBRARY`` component.
+
+.. versionadded:: 3.13
+ Added the ``ENGINE_LIBRARY``, ``DATAARRAY_LIBRARY`` and ``MCC_COMPILER``
+ components.
+
+.. versionchanged:: 3.14
+ Removed the ``MX_LIBRARY``, ``ENGINE_LIBRARY`` and ``DATAARRAY_LIBRARY``
+ components. These libraries are found unconditionally.
+
+.. note::
+
+ The version given to the :command:`find_package` directive is the Matlab
+ **version**, which should not be confused with the Matlab *release* name
+ (eg. `R2014`).
+ The :command:`matlab_get_version_from_release_name` and
+ :command:`matlab_get_release_name_from_version` provide a mapping
+ between the release name and the version.
+
+The variable :variable:`Matlab_ROOT_DIR` may be specified in order to give
+the path of the desired Matlab version. Otherwise, the behaviour is platform
+specific:
+
+* Windows: The installed versions of Matlab/MCR are retrieved from the
+ Windows registry
+* OS X: The installed versions of Matlab/MCR are given by the MATLAB
+ default installation paths in ``/Application``. If no such application is
+ found, it falls back to the one that might be accessible from the ``PATH``.
+* Unix: The desired Matlab should be accessible from the ``PATH``. This does
+ not work for MCR installation and :variable:`Matlab_ROOT_DIR` should be
+ specified on this platform.
+
+Additional information is provided when :variable:`MATLAB_FIND_DEBUG` is set.
+When a Matlab/MCR installation is found automatically and the ``MATLAB_VERSION``
+is not given, the version is queried from Matlab directly (on Windows this
+may pop up a Matlab window) or from the MCR installation.
+
+The mapping of the release names and the version of Matlab is performed by
+defining pairs (name, version). The variable
+:variable:`MATLAB_ADDITIONAL_VERSIONS` may be provided before the call to
+the :command:`find_package` in order to handle additional versions.
+
+A Matlab scripts can be added to the set of tests using the
+:command:`matlab_add_unit_test`. By default, the Matlab unit test framework
+will be used (>= 2013a) to run this script, but regular ``.m`` files
+returning an exit code can be used as well (0 indicating a success).
+
+Module Input Variables
+^^^^^^^^^^^^^^^^^^^^^^
+
+Users or projects may set the following variables to configure the module
+behaviour:
+
+:variable:`Matlab_ROOT_DIR`
+ the root of the Matlab installation.
+:variable:`MATLAB_FIND_DEBUG`
+ outputs debug information
+:variable:`MATLAB_ADDITIONAL_VERSIONS`
+ additional versions of Matlab for the automatic retrieval of the installed
+ versions.
+
+Variables defined by the module
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Result variables
+""""""""""""""""
+
+``Matlab_FOUND``
+ ``TRUE`` if the Matlab installation is found, ``FALSE``
+ otherwise. All variable below are defined if Matlab is found.
+``Matlab_ROOT_DIR``
+ the final root of the Matlab installation determined by the FindMatlab
+ module.
+``Matlab_MAIN_PROGRAM``
+ the Matlab binary program. Available only if the component ``MAIN_PROGRAM``
+ is given in the :command:`find_package` directive.
+``Matlab_INCLUDE_DIRS``
+ the path of the Matlab libraries headers
+``Matlab_MEX_LIBRARY``
+ library for mex, always available.
+``Matlab_MX_LIBRARY``
+ mx library of Matlab (arrays), always available.
+``Matlab_ENG_LIBRARY``
+ Matlab engine library. Available only if the component ``ENG_LIBRARY``
+ is requested.
+``Matlab_MAT_LIBRARY``
+ Matlab matrix library. Available only if the component ``MAT_LIBRARY``
+ is requested.
+``Matlab_ENGINE_LIBRARY``
+ .. versionadded:: 3.13
+
+ Matlab C++ engine library, always available for R2018a and newer.
+``Matlab_DATAARRAY_LIBRARY``
+ .. versionadded:: 3.13
+
+ Matlab C++ data array library, always available for R2018a and newer.
+``Matlab_LIBRARIES``
+ the whole set of libraries of Matlab
+``Matlab_MEX_COMPILER``
+ the mex compiler of Matlab. Currently not used.
+ Available only if the component ``MEX_COMPILER`` is requested.
+``Matlab_MCC_COMPILER``
+ .. versionadded:: 3.13
+
+ the mcc compiler of Matlab. Included with the Matlab Compiler add-on.
+ Available only if the component ``MCC_COMPILER`` is requested.
+
+Cached variables
+""""""""""""""""
+
+``Matlab_MEX_EXTENSION``
+ the extension of the mex files for the current platform (given by Matlab).
+``Matlab_ROOT_DIR``
+ the location of the root of the Matlab installation found. If this value
+ is changed by the user, the result variables are recomputed.
+
+Provided macros
+^^^^^^^^^^^^^^^
+
+:command:`matlab_get_version_from_release_name`
+ returns the version from the release name
+:command:`matlab_get_release_name_from_version`
+ returns the release name from the Matlab version
+
+Provided functions
+^^^^^^^^^^^^^^^^^^
+
+:command:`matlab_add_mex`
+ adds a target compiling a MEX file.
+:command:`matlab_add_unit_test`
+ adds a Matlab unit test file as a test to the project.
+:command:`matlab_extract_all_installed_versions_from_registry`
+ parses the registry for all Matlab versions. Available on Windows only.
+ The part of the registry parsed is dependent on the host processor
+:command:`matlab_get_all_valid_matlab_roots_from_registry`
+ returns all the possible Matlab or MCR paths, according to a previously
+ given list. Only the existing/accessible paths are kept. This is mainly
+ useful for the searching all possible Matlab installation.
+:command:`matlab_get_mex_suffix`
+ returns the suffix to be used for the mex files
+ (platform/architecture dependent)
+:command:`matlab_get_version_from_matlab_run`
+ returns the version of Matlab/MCR, given the full directory of the Matlab/MCR
+ installation path.
+
+
+Known issues
+^^^^^^^^^^^^
+
+**Symbol clash in a MEX target**
+ By default, every symbols inside a MEX
+ file defined with the command :command:`matlab_add_mex` have hidden
+ visibility, except for the entry point. This is the default behaviour of
+ the MEX compiler, which lowers the risk of symbol collision between the
+ libraries shipped with Matlab, and the libraries to which the MEX file is
+ linking to. This is also the default on Windows platforms.
+
+ However, this is not sufficient in certain case, where for instance your
+ MEX file is linking against libraries that are already loaded by Matlab,
+ even if those libraries have different SONAMES.
+ A possible solution is to hide the symbols of the libraries to which the
+ MEX target is linking to. This can be achieved in GNU GCC compilers with
+ the linker option ``-Wl,--exclude-libs,ALL``.
+
+**Tests using GPU resources**
+ in case your MEX file is using the GPU and
+ in order to be able to run unit tests on this MEX file, the GPU resources
+ should be properly released by Matlab. A possible solution is to make
+ Matlab aware of the use of the GPU resources in the session, which can be
+ performed by a command such as ``D = gpuDevice()`` at the beginning of
+ the test script (or via a fixture).
+
+
+Reference
+^^^^^^^^^
+
+.. variable:: Matlab_ROOT_DIR
+
+ The root folder of the Matlab installation. If set before the call to
+ :command:`find_package`, the module will look for the components in that
+ path. If not set, then an automatic search of Matlab
+ will be performed. If set, it should point to a valid version of Matlab.
+
+.. variable:: MATLAB_FIND_DEBUG
+
+ If set, the lookup of Matlab and the intermediate configuration steps are
+ outputted to the console.
+
+.. variable:: MATLAB_ADDITIONAL_VERSIONS
+
+ If set, specifies additional versions of Matlab that may be looked for.
+ The variable should be a list of strings, organised by pairs of release
+ name and versions, such as follows::
+
+ set(MATLAB_ADDITIONAL_VERSIONS
+ "release_name1=corresponding_version1"
+ "release_name2=corresponding_version2"
+ ...
+ )
+
+ Example::
+
+ set(MATLAB_ADDITIONAL_VERSIONS
+ "R2013b=8.2"
+ "R2013a=8.1"
+ "R2012b=8.0")
+
+ The order of entries in this list matters when several versions of
+ Matlab are installed. The priority is set according to the ordering in
+ this list.
+#]=======================================================================]
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+set(_FindMatlab_SELF_DIR "${CMAKE_CURRENT_LIST_DIR}")
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+include(CheckCXXCompilerFlag)
+include(CheckCCompilerFlag)
+
+
+# The currently supported versions. Other version can be added by the user by
+# providing MATLAB_ADDITIONAL_VERSIONS
+if(NOT MATLAB_ADDITIONAL_VERSIONS)
+ set(MATLAB_ADDITIONAL_VERSIONS)
+endif()
+
+set(MATLAB_VERSIONS_MAPPING
+ "R2021a=9.10"
+ "R2020b=9.9"
+ "R2020a=9.8"
+ "R2019b=9.7"
+ "R2019a=9.6"
+ "R2018b=9.5"
+ "R2018a=9.4"
+ "R2017b=9.3"
+ "R2017a=9.2"
+ "R2016b=9.1"
+ "R2016a=9.0"
+ "R2015b=8.6"
+ "R2015a=8.5"
+ "R2014b=8.4"
+ "R2014a=8.3"
+ "R2013b=8.2"
+ "R2013a=8.1"
+ "R2012b=8.0"
+ "R2012a=7.14"
+ "R2011b=7.13"
+ "R2011a=7.12"
+ "R2010b=7.11"
+
+ ${MATLAB_ADDITIONAL_VERSIONS}
+ )
+
+
+# temporary folder for all Matlab runs
+set(_matlab_temporary_folder ${CMAKE_BINARY_DIR}/Matlab)
+
+if(NOT EXISTS "${_matlab_temporary_folder}")
+ file(MAKE_DIRECTORY "${_matlab_temporary_folder}")
+endif()
+
+#[=======================================================================[.rst:
+.. command:: matlab_get_version_from_release_name
+
+ Returns the version of Matlab (17.58) from a release name (R2017k)
+#]=======================================================================]
+macro(matlab_get_version_from_release_name release_name version_name)
+
+ string(REGEX MATCHALL "${release_name}=([0-9]+\\.?[0-9]*)" _matched ${MATLAB_VERSIONS_MAPPING})
+
+ set(${version_name} "")
+ if(NOT _matched STREQUAL "")
+ set(${version_name} ${CMAKE_MATCH_1})
+ else()
+ message(WARNING "[MATLAB] The release name ${release_name} is not registered")
+ endif()
+ unset(_matched)
+
+endmacro()
+
+
+
+
+
+#[=======================================================================[.rst:
+.. command:: matlab_get_release_name_from_version
+
+ Returns the release name (R2017k) from the version of Matlab (17.58)
+#]=======================================================================]
+macro(matlab_get_release_name_from_version version release_name)
+
+ set(${release_name} "")
+ foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING)
+ string(REGEX MATCHALL "(.+)=${version}" _matched ${_var})
+ if(NOT _matched STREQUAL "")
+ set(${release_name} ${CMAKE_MATCH_1})
+ break()
+ endif()
+ endforeach(_var)
+
+ unset(_var)
+ unset(_matched)
+ if(${release_name} STREQUAL "")
+ message(WARNING "[MATLAB] The version ${version} is not registered")
+ endif()
+
+endmacro()
+
+
+
+
+
+# extracts all the supported release names (R2017k...) of Matlab
+# internal use
+macro(matlab_get_supported_releases list_releases)
+ set(${list_releases})
+ foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING)
+ string(REGEX MATCHALL "(.+)=([0-9]+\\.?[0-9]*)" _matched ${_var})
+ if(NOT _matched STREQUAL "")
+ list(APPEND ${list_releases} ${CMAKE_MATCH_1})
+ endif()
+ unset(_matched)
+ unset(CMAKE_MATCH_1)
+ endforeach(_var)
+ unset(_var)
+endmacro()
+
+
+
+# extracts all the supported versions of Matlab
+# internal use
+macro(matlab_get_supported_versions list_versions)
+ set(${list_versions})
+ foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING)
+ string(REGEX MATCHALL "(.+)=([0-9]+\\.?[0-9]*)" _matched ${_var})
+ if(NOT _matched STREQUAL "")
+ list(APPEND ${list_versions} ${CMAKE_MATCH_2})
+ endif()
+ unset(_matched)
+ unset(CMAKE_MATCH_1)
+ endforeach(_var)
+ unset(_var)
+endmacro()
+
+
+#[=======================================================================[.rst:
+.. command:: matlab_extract_all_installed_versions_from_registry
+
+ This function parses the registry and founds the Matlab versions that are
+ installed. The found versions are returned in `matlab_versions`.
+ Set `win64` to `TRUE` if the 64 bit version of Matlab should be looked for
+ The returned list contains all versions under
+ ``HKLM\\SOFTWARE\\Mathworks\\MATLAB`` and
+ ``HKLM\\SOFTWARE\\Mathworks\\MATLAB Runtime`` or an empty list in case an
+ error occurred (or nothing found).
+
+ .. note::
+
+ Only the versions are provided. No check is made over the existence of the
+ installation referenced in the registry,
+
+#]=======================================================================]
+function(matlab_extract_all_installed_versions_from_registry win64 matlab_versions)
+
+ if(NOT CMAKE_HOST_WIN32)
+ message(FATAL_ERROR "[MATLAB] This macro can only be called by a windows host (call to reg.exe)")
+ endif()
+
+ if(${win64} AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "64")
+ set(APPEND_REG "/reg:64")
+ else()
+ set(APPEND_REG "/reg:32")
+ endif()
+
+ set(matlabs_from_registry)
+
+ foreach(_installation_type IN ITEMS "MATLAB" "MATLAB Runtime" "MATLAB Compiler Runtime")
+
+ # /reg:64 should be added on 64 bits capable OSs in order to enable the
+ # redirection of 64 bits applications
+ execute_process(
+ COMMAND reg query "HKEY_LOCAL_MACHINE\\SOFTWARE\\Mathworks\\${_installation_type}" /f * /k ${APPEND_REG}
+ RESULT_VARIABLE resultMatlab
+ OUTPUT_VARIABLE varMatlab
+ ERROR_VARIABLE errMatlab
+ INPUT_FILE NUL
+ )
+
+
+ if(resultMatlab EQUAL 0)
+
+ string(
+ REGEX MATCHALL "${_installation_type}\\\\([0-9]+(\\.[0-9]+)?)"
+ matlab_versions_regex ${varMatlab})
+
+ foreach(match IN LISTS matlab_versions_regex)
+ string(
+ REGEX MATCH "${_installation_type}\\\\(([0-9]+)(\\.([0-9]+))?)"
+ current_match ${match})
+
+ set(_matlab_current_version ${CMAKE_MATCH_1})
+ set(current_matlab_version_major ${CMAKE_MATCH_2})
+ set(current_matlab_version_minor ${CMAKE_MATCH_4})
+ if(NOT current_matlab_version_minor)
+ set(current_matlab_version_minor "0")
+ endif()
+
+ list(APPEND matlabs_from_registry ${_matlab_current_version})
+ unset(_matlab_current_version)
+ endforeach()
+
+ endif()
+ endforeach()
+
+ if(matlabs_from_registry)
+ list(REMOVE_DUPLICATES matlabs_from_registry)
+ list(SORT matlabs_from_registry)
+ list(REVERSE matlabs_from_registry)
+ endif()
+
+ set(${matlab_versions} ${matlabs_from_registry} PARENT_SCOPE)
+
+endfunction()
+
+
+
+# (internal)
+macro(extract_matlab_versions_from_registry_brute_force matlab_versions)
+ # get the supported versions
+ set(matlab_supported_versions)
+ matlab_get_supported_versions(matlab_supported_versions)
+
+
+ # this is a manual population of the versions we want to look for
+ # this can be done as is, but preferably with the call to
+ # matlab_get_supported_versions and variable
+
+ # populating the versions we want to look for
+ # set(matlab_supported_versions)
+
+ # # Matlab 7
+ # set(matlab_major 7)
+ # foreach(current_matlab_minor RANGE 4 20)
+ # list(APPEND matlab_supported_versions "${matlab_major}.${current_matlab_minor}")
+ # endforeach(current_matlab_minor)
+
+ # # Matlab 8
+ # set(matlab_major 8)
+ # foreach(current_matlab_minor RANGE 0 5)
+ # list(APPEND matlab_supported_versions "${matlab_major}.${current_matlab_minor}")
+ # endforeach(current_matlab_minor)
+
+ # # taking into account the possible additional versions provided by the user
+ # if(DEFINED MATLAB_ADDITIONAL_VERSIONS)
+ # list(APPEND matlab_supported_versions MATLAB_ADDITIONAL_VERSIONS)
+ # endif()
+
+ # we order from more recent to older
+ if(matlab_supported_versions)
+ list(REMOVE_DUPLICATES matlab_supported_versions)
+ list(SORT matlab_supported_versions)
+ list(REVERSE matlab_supported_versions)
+ endif()
+
+ set(${matlab_versions} ${matlab_supported_versions})
+endmacro()
+
+
+
+
+#[=======================================================================[.rst:
+.. command:: matlab_get_all_valid_matlab_roots_from_registry
+
+ Populates the Matlab root with valid versions of Matlab or
+ Matlab Runtime (MCR).
+ The returned matlab_roots is organized in triplets
+ ``(type,version_number,matlab_root_path)``, where ``type``
+ indicates either ``MATLAB`` or ``MCR``.
+
+ ::
+
+ matlab_get_all_valid_matlab_roots_from_registry(
+ matlab_versions
+ matlab_roots)
+
+ ``matlab_versions``
+ the versions of each of the Matlab or MCR installations
+ ``matlab_roots``
+ the location of each of the Matlab or MCR installations
+#]=======================================================================]
+function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_roots)
+
+ # The matlab_versions comes either from
+ # extract_matlab_versions_from_registry_brute_force or
+ # matlab_extract_all_installed_versions_from_registry.
+
+ set(_matlab_roots_list )
+ # check for Matlab installations
+ foreach(_matlab_current_version ${matlab_versions})
+ get_filename_component(
+ current_MATLAB_ROOT
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${_matlab_current_version};MATLABROOT]"
+ ABSOLUTE)
+
+ if(EXISTS "${current_MATLAB_ROOT}")
+ list(APPEND _matlab_roots_list "MATLAB" ${_matlab_current_version} ${current_MATLAB_ROOT})
+ endif()
+
+ endforeach()
+
+ # Check for MCR installations
+ foreach(_matlab_current_version ${matlab_versions})
+ get_filename_component(
+ current_MATLAB_ROOT
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB Runtime\\${_matlab_current_version};MATLABROOT]"
+ ABSOLUTE)
+
+ # remove the dot
+ string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}")
+
+ if(EXISTS "${current_MATLAB_ROOT}")
+ list(APPEND _matlab_roots_list "MCR" ${_matlab_current_version} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}")
+ endif()
+
+ endforeach()
+
+ # Check for old MCR installations
+ foreach(_matlab_current_version ${matlab_versions})
+ get_filename_component(
+ current_MATLAB_ROOT
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB Compiler Runtime\\${_matlab_current_version};MATLABROOT]"
+ ABSOLUTE)
+
+ # remove the dot
+ string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}")
+
+ if(EXISTS "${current_MATLAB_ROOT}")
+ list(APPEND _matlab_roots_list "MCR" ${_matlab_current_version} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}")
+ endif()
+
+ endforeach()
+ set(${matlab_roots} ${_matlab_roots_list} PARENT_SCOPE)
+endfunction()
+
+#[=======================================================================[.rst:
+.. command:: matlab_get_mex_suffix
+
+ Returns the extension of the mex files (the suffixes).
+ This function should not be called before the appropriate Matlab root has
+ been found.
+
+ ::
+
+ matlab_get_mex_suffix(
+ matlab_root
+ mex_suffix)
+
+ ``matlab_root``
+ the root of the Matlab/MCR installation
+ ``mex_suffix``
+ the variable name in which the suffix will be returned.
+#]=======================================================================]
+function(matlab_get_mex_suffix matlab_root mex_suffix)
+
+ # todo setup the extension properly. Currently I do not know if this is
+ # sufficient for all win32 distributions.
+ # there is also CMAKE_EXECUTABLE_SUFFIX that could be tweaked
+ set(mexext_suffix "")
+ if(WIN32)
+ list(APPEND mexext_suffix ".bat")
+ endif()
+
+ # we first try without suffix, since cmake does not understand a list with
+ # one empty string element
+ find_program(
+ Matlab_MEXEXTENSIONS_PROG
+ NAMES mexext
+ PATHS ${matlab_root}/bin
+ DOC "Matlab MEX extension provider"
+ NO_DEFAULT_PATH
+ )
+
+ foreach(current_mexext_suffix IN LISTS mexext_suffix)
+ if(NOT DEFINED Matlab_MEXEXTENSIONS_PROG OR NOT Matlab_MEXEXTENSIONS_PROG)
+ # this call should populate the cache automatically
+ find_program(
+ Matlab_MEXEXTENSIONS_PROG
+ "mexext${current_mexext_suffix}"
+ PATHS ${matlab_root}/bin
+ DOC "Matlab MEX extension provider"
+ NO_DEFAULT_PATH
+ )
+ endif()
+ endforeach(current_mexext_suffix)
+ if(MATLAB_FIND_DEBUG)
+ message(STATUS "[MATLAB] Determining mex files extensions from '${matlab_root}/bin' with program '${Matlab_MEXEXTENSIONS_PROG}'")
+ endif()
+
+ # the program has been found?
+ if((NOT Matlab_MEXEXTENSIONS_PROG) OR (NOT EXISTS ${Matlab_MEXEXTENSIONS_PROG}))
+ if(MATLAB_FIND_DEBUG)
+ message(WARNING "[MATLAB] Cannot found mexext program. Matlab root is ${matlab_root}")
+ endif()
+ unset(Matlab_MEXEXTENSIONS_PROG CACHE)
+ return()
+ endif()
+
+ set(_matlab_mex_extension)
+
+ set(devnull)
+ if(UNIX)
+ set(devnull INPUT_FILE /dev/null)
+ elseif(WIN32)
+ set(devnull INPUT_FILE NUL)
+ endif()
+
+ if(WIN32)
+ # this environment variable is used to determine the arch on Windows
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(ENV{MATLAB_ARCH} "win64")
+ else()
+ set(ENV{MATLAB_ARCH} "win32")
+ endif()
+ endif()
+
+ # this is the preferred way. If this does not work properly (eg. MCR on Windows), then we use our own knowledge
+ execute_process(
+ COMMAND ${Matlab_MEXEXTENSIONS_PROG}
+ OUTPUT_VARIABLE _matlab_mex_extension
+ ERROR_VARIABLE _matlab_mex_extension_error
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ${devnull})
+ unset(ENV{MATLAB_ARCH})
+
+ if(_matlab_mex_extension_error)
+ if(WIN32)
+ # this is only for intel architecture
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(_matlab_mex_extension "mexw64")
+ else()
+ set(_matlab_mex_extension "mexw32")
+ endif()
+ endif()
+ endif()
+
+ string(STRIP "${_matlab_mex_extension}" _matlab_mex_extension)
+ if(MATLAB_FIND_DEBUG)
+ message(STATUS "[MATLAB] '${Matlab_MEXEXTENSIONS_PROG}' : determined extension '${_matlab_mex_extension}' and error string is '${_matlab_mex_extension_error}'")
+ endif()
+
+ unset(Matlab_MEXEXTENSIONS_PROG CACHE)
+ set(${mex_suffix} ${_matlab_mex_extension} PARENT_SCOPE)
+endfunction()
+
+
+
+
+#[=======================================================================[.rst:
+.. command:: matlab_get_version_from_matlab_run
+
+ This function runs Matlab program specified on arguments and extracts its
+ version. If the path provided for the Matlab installation points to an MCR
+ installation, the version is extracted from the installed files.
+
+ ::
+
+ matlab_get_version_from_matlab_run(
+ matlab_binary_path
+ matlab_list_versions)
+
+ ``matlab_binary_path``
+ the location of the `matlab` binary executable
+ ``matlab_list_versions``
+ the version extracted from Matlab
+#]=======================================================================]
+function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_versions)
+
+ set(${matlab_list_versions} "" PARENT_SCOPE)
+
+ if(MATLAB_FIND_DEBUG)
+ message(STATUS "[MATLAB] Determining the version of Matlab from ${matlab_binary_program}")
+ endif()
+
+ if(EXISTS "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp")
+ if(MATLAB_FIND_DEBUG)
+ message(STATUS "[MATLAB] Removing previous ${_matlab_temporary_folder}/matlabVersionLog.cmaketmp file")
+ endif()
+ file(REMOVE "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp")
+ endif()
+
+
+ # the log file is needed since on windows the command executes in a new
+ # window and it is not possible to get back the answer of Matlab
+ # the -wait command is needed on windows, otherwise the call returns
+ # immediately after the program launches itself.
+ if(WIN32)
+ set(_matlab_additional_commands "-wait")
+ endif()
+
+ set(devnull)
+ if(UNIX)
+ set(devnull INPUT_FILE /dev/null)
+ elseif(WIN32)
+ set(devnull INPUT_FILE NUL)
+ endif()
+
+ # timeout set to 120 seconds, in case it does not start
+ # note as said before OUTPUT_VARIABLE cannot be used in a platform
+ # independent manner however, not setting it would flush the output of Matlab
+ # in the current console (unix variant)
+ execute_process(
+ COMMAND "${matlab_binary_program}" -nosplash -nojvm ${_matlab_additional_commands} -logfile "matlabVersionLog.cmaketmp" -nodesktop -nodisplay -r "version, exit"
+ OUTPUT_VARIABLE _matlab_version_from_cmd_dummy
+ RESULT_VARIABLE _matlab_result_version_call
+ ERROR_VARIABLE _matlab_result_version_call_error
+ TIMEOUT 120
+ WORKING_DIRECTORY "${_matlab_temporary_folder}"
+ ${devnull}
+ )
+
+ if(_matlab_result_version_call MATCHES "timeout")
+ if(MATLAB_FIND_DEBUG)
+ message(WARNING "[MATLAB] Unable to determine the version of Matlab."
+ " Matlab call timed out after 120 seconds.")
+ endif()
+ return()
+ endif()
+
+ if(${_matlab_result_version_call})
+ if(MATLAB_FIND_DEBUG)
+ message(WARNING "[MATLAB] Unable to determine the version of Matlab. Matlab call returned with error ${_matlab_result_version_call}.")
+ endif()
+ return()
+ elseif(NOT EXISTS "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp")
+ if(MATLAB_FIND_DEBUG)
+ message(WARNING "[MATLAB] Unable to determine the version of Matlab. The log file does not exist.")
+ endif()
+ return()
+ endif()
+
+ # if successful, read back the log
+ file(READ "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp" _matlab_version_from_cmd)
+ file(REMOVE "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp")
+
+ set(index -1)
+ string(FIND "${_matlab_version_from_cmd}" "ans" index)
+ if(index EQUAL -1)
+
+ if(MATLAB_FIND_DEBUG)
+ message(WARNING "[MATLAB] Cannot find the version of Matlab returned by the run.")
+ endif()
+
+ else()
+ set(matlab_list_of_all_versions_tmp)
+
+ string(SUBSTRING "${_matlab_version_from_cmd}" ${index} -1 substring_ans)
+ string(
+ REGEX MATCHALL "ans[\r\n\t ]*=[\r\n\t ]*'?([0-9]+(\\.[0-9]+)?)"
+ matlab_versions_regex
+ ${substring_ans})
+ foreach(match IN LISTS matlab_versions_regex)
+ string(
+ REGEX MATCH "ans[\r\n\t ]*=[\r\n\t ]*'?(([0-9]+)(\\.([0-9]+))?)"
+ current_match ${match})
+
+ list(APPEND matlab_list_of_all_versions_tmp ${CMAKE_MATCH_1})
+ endforeach()
+ if(matlab_list_of_all_versions_tmp)
+ list(REMOVE_DUPLICATES matlab_list_of_all_versions_tmp)
+ endif()
+ set(${matlab_list_versions} ${matlab_list_of_all_versions_tmp} PARENT_SCOPE)
+
+ endif()
+
+endfunction()
+
+#[=======================================================================[.rst:
+.. command:: matlab_add_unit_test
+
+ Adds a Matlab unit test to the test set of cmake/ctest.
+ This command requires the component ``MAIN_PROGRAM`` and hence is not
+ available for an MCR installation.
+
+ The unit test uses the Matlab unittest framework (default, available
+ starting Matlab 2013b+) except if the option ``NO_UNITTEST_FRAMEWORK``
+ is given.
+
+ The function expects one Matlab test script file to be given.
+ In the case ``NO_UNITTEST_FRAMEWORK`` is given, the unittest script file
+ should contain the script to be run, plus an exit command with the exit
+ value. This exit value will be passed to the ctest framework (0 success,
+ non 0 failure). Additional arguments accepted by :command:`add_test` can be
+ passed through ``TEST_ARGS`` (eg. ``CONFIGURATION <config> ...``).
+
+ ::
+
+ matlab_add_unit_test(
+ NAME <name>
+ UNITTEST_FILE matlab_file_containing_unittest.m
+ [CUSTOM_TEST_COMMAND matlab_command_to_run_as_test]
+ [UNITTEST_PRECOMMAND matlab_command_to_run]
+ [TIMEOUT timeout]
+ [ADDITIONAL_PATH path1 [path2 ...]]
+ [MATLAB_ADDITIONAL_STARTUP_OPTIONS option1 [option2 ...]]
+ [TEST_ARGS arg1 [arg2 ...]]
+ [NO_UNITTEST_FRAMEWORK]
+ )
+
+ The function arguments are:
+
+ ``NAME``
+ name of the unittest in ctest.
+ ``UNITTEST_FILE``
+ the matlab unittest file. Its path will be automatically
+ added to the Matlab path.
+ ``CUSTOM_TEST_COMMAND``
+ Matlab script command to run as the test.
+ If this is not set, then the following is run:
+ ``runtests('matlab_file_name'), exit(max([ans(1,:).Failed]))``
+ where ``matlab_file_name`` is the ``UNITTEST_FILE`` without the extension.
+ ``UNITTEST_PRECOMMAND``
+ Matlab script command to be ran before the file
+ containing the test (eg. GPU device initialisation based on CMake
+ variables).
+ ``TIMEOUT``
+ the test timeout in seconds. Defaults to 180 seconds as the
+ Matlab unit test may hang.
+ ``ADDITIONAL_PATH``
+ a list of paths to add to the Matlab path prior to
+ running the unit test.
+ ``MATLAB_ADDITIONAL_STARTUP_OPTIONS``
+ a list of additional option in order
+ to run Matlab from the command line.
+ ``-nosplash -nodesktop -nodisplay`` are always added.
+ ``TEST_ARGS``
+ Additional options provided to the add_test command. These
+ options are added to the default options (eg. "CONFIGURATIONS Release")
+ ``NO_UNITTEST_FRAMEWORK``
+ when set, indicates that the test should not
+ use the unittest framework of Matlab (available for versions >= R2013a).
+ ``WORKING_DIRECTORY``
+ This will be the working directory for the test. If specified it will
+ also be the output directory used for the log file of the test run.
+ If not specified the temporary directory ``${CMAKE_BINARY_DIR}/Matlab`` will
+ be used as the working directory and the log location.
+
+#]=======================================================================]
+function(matlab_add_unit_test)
+
+ if(NOT Matlab_MAIN_PROGRAM)
+ message(FATAL_ERROR "[MATLAB] This functionality needs the MAIN_PROGRAM component (not default)")
+ endif()
+
+ set(options NO_UNITTEST_FRAMEWORK)
+ set(oneValueArgs NAME UNITTEST_FILE TIMEOUT WORKING_DIRECTORY
+ UNITTEST_PRECOMMAND CUSTOM_TEST_COMMAND)
+ set(multiValueArgs ADDITIONAL_PATH MATLAB_ADDITIONAL_STARTUP_OPTIONS TEST_ARGS)
+
+ set(prefix _matlab_unittest_prefix)
+ cmake_parse_arguments(PARSE_ARGV 0 ${prefix} "${options}" "${oneValueArgs}" "${multiValueArgs}" )
+
+ if(NOT ${prefix}_NAME)
+ message(FATAL_ERROR "[MATLAB] The Matlab test name cannot be empty")
+ endif()
+
+ add_test(NAME ${${prefix}_NAME}
+ COMMAND ${CMAKE_COMMAND}
+ "-Dtest_name=${${prefix}_NAME}"
+ "-Dadditional_paths=${${prefix}_ADDITIONAL_PATH}"
+ "-Dtest_timeout=${${prefix}_TIMEOUT}"
+ "-Doutput_directory=${_matlab_temporary_folder}"
+ "-Dworking_directory=${${prefix}_WORKING_DIRECTORY}"
+ "-DMatlab_PROGRAM=${Matlab_MAIN_PROGRAM}"
+ "-Dno_unittest_framework=${${prefix}_NO_UNITTEST_FRAMEWORK}"
+ "-DMatlab_ADDITIONAL_STARTUP_OPTIONS=${${prefix}_MATLAB_ADDITIONAL_STARTUP_OPTIONS}"
+ "-Dunittest_file_to_run=${${prefix}_UNITTEST_FILE}"
+ "-Dcustom_Matlab_test_command=${${prefix}_CUSTOM_TEST_COMMAND}"
+ "-Dcmd_to_run_before_test=${${prefix}_UNITTEST_PRECOMMAND}"
+ -P ${_FindMatlab_SELF_DIR}/MatlabTestsRedirect.cmake
+ ${${prefix}_TEST_ARGS}
+ ${${prefix}_UNPARSED_ARGUMENTS}
+ )
+endfunction()
+
+
+#[=======================================================================[.rst:
+.. command:: matlab_add_mex
+
+ Adds a Matlab MEX target.
+ This commands compiles the given sources with the current tool-chain in
+ order to produce a MEX file. The final name of the produced output may be
+ specified, as well as additional link libraries, and a documentation entry
+ for the MEX file. Remaining arguments of the call are passed to the
+ :command:`add_library` or :command:`add_executable` command.
+
+ ::
+
+ matlab_add_mex(
+ NAME <name>
+ [EXECUTABLE | MODULE | SHARED]
+ SRC src1 [src2 ...]
+ [OUTPUT_NAME output_name]
+ [DOCUMENTATION file.txt]
+ [LINK_TO target1 target2 ...]
+ [R2017b | R2018a]
+ [EXCLUDE_FROM_ALL]
+ [...]
+ )
+
+ ``NAME``
+ name of the target.
+ ``SRC``
+ list of source files.
+ ``LINK_TO``
+ a list of additional link dependencies. The target links to ``libmex``
+ and ``libmx`` by default.
+ ``OUTPUT_NAME``
+ if given, overrides the default name. The default name is
+ the name of the target without any prefix and
+ with ``Matlab_MEX_EXTENSION`` suffix.
+ ``DOCUMENTATION``
+ if given, the file ``file.txt`` will be considered as
+ being the documentation file for the MEX file. This file is copied into
+ the same folder without any processing, with the same name as the final
+ mex file, and with extension `.m`. In that case, typing ``help <name>``
+ in Matlab prints the documentation contained in this file.
+ ``R2017b`` or ``R2018a``
+ .. versionadded:: 3.14
+
+ May be given to specify the version of the C API
+ to use: ``R2017b`` specifies the traditional (separate complex) C API,
+ and corresponds to the ``-R2017b`` flag for the `mex` command. ``R2018a``
+ specifies the new interleaved complex C API, and corresponds to the
+ ``-R2018a`` flag for the `mex` command. Ignored if MATLAB version prior
+ to R2018a. Defaults to ``R2017b``.
+
+ ``MODULE`` or ``SHARED``
+ .. versionadded:: 3.7
+
+ May be given to specify the type of library to be
+ created.
+
+ ``EXECUTABLE``
+ .. versionadded:: 3.7
+
+ May be given to create an executable instead of
+ a library. If no type is given explicitly, the type is ``SHARED``.
+ ``EXCLUDE_FROM_ALL``
+ This option has the same meaning as for :prop_tgt:`EXCLUDE_FROM_ALL` and
+ is forwarded to :command:`add_library` or :command:`add_executable`
+ commands.
+
+ The documentation file is not processed and should be in the following
+ format:
+
+ ::
+
+ % This is the documentation
+ function ret = mex_target_output_name(input1)
+
+#]=======================================================================]
+function(matlab_add_mex)
+
+ if(NOT WIN32)
+ # we do not need all this on Windows
+ # pthread options
+ if(CMAKE_CXX_COMPILER_LOADED)
+ check_cxx_compiler_flag(-pthread HAS_MINUS_PTHREAD)
+ elseif(CMAKE_C_COMPILER_LOADED)
+ check_c_compiler_flag(-pthread HAS_MINUS_PTHREAD)
+ endif()
+ # we should use try_compile instead, the link flags are discarded from
+ # this compiler_flag function.
+ #check_cxx_compiler_flag(-Wl,--exclude-libs,ALL HAS_SYMBOL_HIDING_CAPABILITY)
+
+ endif()
+
+ set(options EXECUTABLE MODULE SHARED R2017b R2018a EXCLUDE_FROM_ALL)
+ set(oneValueArgs NAME DOCUMENTATION OUTPUT_NAME)
+ set(multiValueArgs LINK_TO SRC)
+
+ set(prefix _matlab_addmex_prefix)
+ cmake_parse_arguments(${prefix} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+ if(NOT ${prefix}_NAME)
+ message(FATAL_ERROR "[MATLAB] The MEX target name cannot be empty")
+ endif()
+
+ if(NOT ${prefix}_OUTPUT_NAME)
+ set(${prefix}_OUTPUT_NAME ${${prefix}_NAME})
+ endif()
+
+ if(NOT Matlab_VERSION_STRING VERSION_LESS "9.1") # For 9.1 (R2016b) and newer, add version source file
+ # Add the correct version file depending on which languages are enabled in the project
+ if(CMAKE_C_COMPILER_LOADED)
+ # If C is enabled, use the .c file as it will work fine also with C++
+ set(MEX_VERSION_FILE "${Matlab_ROOT_DIR}/extern/version/c_mexapi_version.c")
+ elseif(CMAKE_CXX_COMPILER_LOADED)
+ # If C is not enabled, check if CXX is enabled and use the .cpp file
+ # to avoid that the .c file is silently ignored
+ set(MEX_VERSION_FILE "${Matlab_ROOT_DIR}/extern/version/cpp_mexapi_version.cpp")
+ else()
+ # If neither C or CXX is enabled, warn because we cannot add the source.
+ # TODO: add support for fortran mex files
+ message(WARNING "[MATLAB] matlab_add_mex requires that at least C or CXX are enabled languages")
+ endif()
+ endif()
+
+ # For 9.4 (R2018a) and newer, add API macro.
+ # Add it for unknown versions too, just in case.
+ if(NOT Matlab_VERSION_STRING VERSION_LESS "9.4"
+ OR Matlab_VERSION_STRING STREQUAL "unknown")
+ if(${${prefix}_R2018a})
+ set(MEX_API_MACRO "MATLAB_DEFAULT_RELEASE=R2018a")
+ else()
+ set(MEX_API_MACRO "MATLAB_DEFAULT_RELEASE=R2017b")
+ endif()
+ endif()
+
+ set(_option_EXCLUDE_FROM_ALL)
+ if(${prefix}_EXCLUDE_FROM_ALL)
+ set(_option_EXCLUDE_FROM_ALL "EXCLUDE_FROM_ALL")
+ endif()
+
+ if(${prefix}_EXECUTABLE)
+ add_executable(${${prefix}_NAME}
+ ${_option_EXCLUDE_FROM_ALL}
+ ${${prefix}_SRC}
+ ${MEX_VERSION_FILE}
+ ${${prefix}_DOCUMENTATION}
+ ${${prefix}_UNPARSED_ARGUMENTS})
+ else()
+ if(${prefix}_MODULE)
+ set(type MODULE)
+ else()
+ set(type SHARED)
+ endif()
+
+ add_library(${${prefix}_NAME}
+ ${type}
+ ${_option_EXCLUDE_FROM_ALL}
+ ${${prefix}_SRC}
+ ${MEX_VERSION_FILE}
+ ${${prefix}_DOCUMENTATION}
+ ${${prefix}_UNPARSED_ARGUMENTS})
+ endif()
+
+ target_include_directories(${${prefix}_NAME} PRIVATE ${Matlab_INCLUDE_DIRS})
+
+ if(Matlab_HAS_CPP_API)
+ if(Matlab_ENGINE_LIBRARY)
+ target_link_libraries(${${prefix}_NAME} ${Matlab_ENGINE_LIBRARY})
+ endif()
+ if(Matlab_DATAARRAY_LIBRARY)
+ target_link_libraries(${${prefix}_NAME} ${Matlab_DATAARRAY_LIBRARY})
+ endif()
+ endif()
+
+ target_link_libraries(${${prefix}_NAME} ${Matlab_MEX_LIBRARY} ${Matlab_MX_LIBRARY} ${${prefix}_LINK_TO})
+ set_target_properties(${${prefix}_NAME}
+ PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME ${${prefix}_OUTPUT_NAME}
+ SUFFIX ".${Matlab_MEX_EXTENSION}")
+
+ target_compile_definitions(${${prefix}_NAME} PRIVATE ${MEX_API_MACRO} MATLAB_MEX_FILE)
+
+ # documentation
+ if(NOT ${${prefix}_DOCUMENTATION} STREQUAL "")
+ get_target_property(output_name ${${prefix}_NAME} OUTPUT_NAME)
+ add_custom_command(
+ TARGET ${${prefix}_NAME}
+ PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${${prefix}_DOCUMENTATION} $<TARGET_FILE_DIR:${${prefix}_NAME}>/${output_name}.m
+ COMMENT "[MATLAB] Copy ${${prefix}_NAME} documentation file into the output folder"
+ )
+ endif() # documentation
+
+ # entry point in the mex file + taking care of visibility and symbol clashes.
+ if(WIN32)
+
+ if (MSVC)
+
+ set(_link_flags "${_link_flags} /EXPORT:mexFunction")
+ if(NOT Matlab_VERSION_STRING VERSION_LESS "9.1") # For 9.1 (R2016b) and newer, export version
+ set(_link_flags "${_link_flags} /EXPORT:mexfilerequiredapiversion")
+ endif()
+
+ set_property(TARGET ${${prefix}_NAME} APPEND PROPERTY LINK_FLAGS ${_link_flags})
+
+ endif() # No other compiler currently supported on Windows.
+
+ set_target_properties(${${prefix}_NAME}
+ PROPERTIES
+ DEFINE_SYMBOL "DLL_EXPORT_SYM=__declspec(dllexport)")
+
+ else()
+
+ if(Matlab_VERSION_STRING VERSION_LESS "9.1") # For versions prior to 9.1 (R2016b)
+ set(_ver_map_files ${Matlab_EXTERN_LIBRARY_DIR}/mexFunction.map)
+ else() # For 9.1 (R2016b) and newer
+ set(_ver_map_files ${Matlab_EXTERN_LIBRARY_DIR}/c_exportsmexfileversion.map)
+ endif()
+
+ if(NOT Matlab_VERSION_STRING VERSION_LESS "9.5") # For 9.5 (R2018b) (and newer?)
+ target_compile_options(${${prefix}_NAME} PRIVATE "-fvisibility=default")
+ # This one is weird, it might be a bug in <mex.h> for R2018b. When compiling with
+ # -fvisibility=hidden, the symbol `mexFunction` cannot be exported. Reading the
+ # source code for <mex.h>, it seems that the preprocessor macro `MW_NEEDS_VERSION_H`
+ # needs to be defined for `__attribute__((visibility("default")))` to be added
+ # in front of the declaration of `mexFunction`. In previous versions of MATLAB this
+ # was not the case, there `DLL_EXPORT_SYM` needed to be defined.
+ # Adding `-fvisibility=hidden` to the `mex` command causes the build to fail.
+ # TODO: Check that this is still necessary in R2019a when it comes out.
+ endif()
+
+ if(APPLE)
+
+ if(Matlab_HAS_CPP_API)
+ list(APPEND _ver_map_files ${Matlab_EXTERN_LIBRARY_DIR}/cppMexFunction.map) # This one doesn't exist on Linux
+ set(_link_flags "${_link_flags} -Wl,-U,_mexCreateMexFunction -Wl,-U,_mexDestroyMexFunction -Wl,-U,_mexFunctionAdapter")
+ # On MacOS, the MEX command adds the above, without it the link breaks
+ # because we indiscriminately use "cppMexFunction.map" even for C API MEX-files.
+ endif()
+
+ set(_export_flag_name -exported_symbols_list)
+
+ else() # Linux
+
+ if(HAS_MINUS_PTHREAD)
+ # Apparently, compiling with -pthread generated the proper link flags
+ # and some defines at compilation
+ target_compile_options(${${prefix}_NAME} PRIVATE "-pthread")
+ endif()
+
+ set(_link_flags "${_link_flags} -Wl,--as-needed")
+
+ set(_export_flag_name --version-script)
+
+ endif()
+
+ foreach(_file ${_ver_map_files})
+ set(_link_flags "${_link_flags} -Wl,${_export_flag_name},${_file}")
+ endforeach()
+
+ # The `mex` command doesn't add this define. It is specified here in order
+ # to export the symbol in case the client code decides to hide its symbols
+ set_target_properties(${${prefix}_NAME}
+ PROPERTIES
+ DEFINE_SYMBOL "DLL_EXPORT_SYM=__attribute__((visibility(\"default\")))"
+ LINK_FLAGS "${_link_flags}"
+ )
+
+ endif()
+
+endfunction()
+
+
+# (internal)
+# Used to get the version of matlab, using caching. This basically transforms the
+# output of the root list, with possible unknown version, to a version
+# This can possibly run Matlab for extracting the version.
+function(_Matlab_get_version_from_root matlab_root matlab_or_mcr matlab_known_version matlab_final_version)
+
+ # if the version is not trivial, we query matlab (if not MCR) for that
+ # we keep track of the location of matlab that induced this version
+ #if(NOT DEFINED Matlab_PROG_VERSION_STRING_AUTO_DETECT)
+ # set(Matlab_PROG_VERSION_STRING_AUTO_DETECT "" CACHE INTERNAL "internal matlab location for the discovered version")
+ #endif()
+
+ if(NOT matlab_known_version STREQUAL "NOTFOUND")
+ # the version is known, we just return it
+ set(${matlab_final_version} ${matlab_known_version} PARENT_SCOPE)
+ set(Matlab_VERSION_STRING_INTERNAL ${matlab_known_version} CACHE INTERNAL "Matlab version (automatically determined)" FORCE)
+ return()
+ endif()
+
+ if(matlab_or_mcr STREQUAL "UNKNOWN")
+ if(MATLAB_FIND_DEBUG)
+ message(WARNING "[MATLAB] Determining Matlab or MCR")
+ endif()
+
+ if(EXISTS "${matlab_root}/appdata/version.xml")
+ # we inspect the application version.xml file that contains the product information
+ file(STRINGS "${matlab_root}/appdata/version.xml" productinfo_string NEWLINE_CONSUME)
+ string(REGEX MATCH "<installedProductData.*displayedString=\"([a-zA-Z ]+)\".*/>"
+ product_reg_match
+ ${productinfo_string}
+ )
+
+ # default fallback to Matlab
+ set(matlab_or_mcr "MATLAB")
+ if(NOT CMAKE_MATCH_1 STREQUAL "")
+ string(TOLOWER "${CMAKE_MATCH_1}" product_reg_match)
+
+ if(product_reg_match STREQUAL "matlab runtime")
+ set(matlab_or_mcr "MCR")
+ endif()
+ endif()
+ endif()
+
+ if(MATLAB_FIND_DEBUG)
+ message(WARNING "[MATLAB] '${matlab_root}' contains the '${matlab_or_mcr}'")
+ endif()
+ endif()
+
+ # UNKNOWN is the default behaviour in case we
+ # - have an erroneous matlab_root
+ # - have an initial 'UNKNOWN'
+ if(matlab_or_mcr STREQUAL "MATLAB" OR matlab_or_mcr STREQUAL "UNKNOWN")
+ # MATLAB versions
+ set(_matlab_current_program ${Matlab_MAIN_PROGRAM})
+
+ # do we already have a matlab program?
+ if(NOT _matlab_current_program)
+
+ set(_find_matlab_options)
+ if(matlab_root AND EXISTS ${matlab_root})
+ set(_find_matlab_options PATHS ${matlab_root} ${matlab_root}/bin NO_DEFAULT_PATH)
+ endif()
+
+ find_program(
+ _matlab_current_program
+ matlab
+ ${_find_matlab_options}
+ DOC "Matlab main program"
+ )
+ endif()
+
+ if(NOT _matlab_current_program OR NOT EXISTS ${_matlab_current_program})
+ # if not found, clear the dependent variables
+ if(MATLAB_FIND_DEBUG)
+ message(WARNING "[MATLAB] Cannot find the main matlab program under ${matlab_root}")
+ endif()
+ set(Matlab_PROG_VERSION_STRING_AUTO_DETECT "" CACHE INTERNAL "internal matlab location for the discovered version" FORCE)
+ set(Matlab_VERSION_STRING_INTERNAL "" CACHE INTERNAL "internal matlab location for the discovered version" FORCE)
+ unset(_matlab_current_program)
+ unset(_matlab_current_program CACHE)
+ return()
+ endif()
+
+ # full real path for path comparison
+ get_filename_component(_matlab_main_real_path_tmp "${_matlab_current_program}" REALPATH)
+ unset(_matlab_current_program)
+ unset(_matlab_current_program CACHE)
+
+ # is it the same as the previous one?
+ if(_matlab_main_real_path_tmp STREQUAL Matlab_PROG_VERSION_STRING_AUTO_DETECT)
+ set(${matlab_final_version} ${Matlab_VERSION_STRING_INTERNAL} PARENT_SCOPE)
+ return()
+ endif()
+
+ # update the location of the program
+ set(Matlab_PROG_VERSION_STRING_AUTO_DETECT
+ ${_matlab_main_real_path_tmp}
+ CACHE INTERNAL "internal matlab location for the discovered version" FORCE)
+
+ set(matlab_list_of_all_versions)
+ matlab_get_version_from_matlab_run("${Matlab_PROG_VERSION_STRING_AUTO_DETECT}" matlab_list_of_all_versions)
+
+ list(LENGTH matlab_list_of_all_versions list_of_all_versions_length)
+ if(list_of_all_versions_length GREATER 0)
+ list(GET matlab_list_of_all_versions 0 _matlab_version_tmp)
+ else()
+ set(_matlab_version_tmp "unknown")
+ endif()
+
+ # set the version into the cache
+ set(Matlab_VERSION_STRING_INTERNAL ${_matlab_version_tmp} CACHE INTERNAL "Matlab version (automatically determined)" FORCE)
+
+ # warning, just in case several versions found (should not happen)
+ if((list_of_all_versions_length GREATER 1) AND MATLAB_FIND_DEBUG)
+ message(WARNING "[MATLAB] Found several versions, taking the first one (versions found ${matlab_list_of_all_versions})")
+ endif()
+
+ # return the updated value
+ set(${matlab_final_version} ${Matlab_VERSION_STRING_INTERNAL} PARENT_SCOPE)
+ elseif(EXISTS "${matlab_root}/VersionInfo.xml")
+ # MCR
+ # we cannot run anything in order to extract the version. We assume that the file
+ # VersionInfo.xml exists under the MatlabRoot, we look for it and extract the version from there
+ set(_matlab_version_tmp "unknown")
+ file(STRINGS "${matlab_root}/VersionInfo.xml" versioninfo_string NEWLINE_CONSUME)
+
+ if(versioninfo_string)
+ # parses "<version>9.2.0.538062</version>"
+ string(REGEX MATCH "<version>(.*)</version>"
+ version_reg_match
+ ${versioninfo_string}
+ )
+
+ if(CMAKE_MATCH_1 MATCHES "(([0-9])\\.([0-9]))[\\.0-9]*")
+ set(_matlab_version_tmp "${CMAKE_MATCH_1}")
+ endif()
+ endif()
+ set(${matlab_final_version} "${_matlab_version_tmp}" PARENT_SCOPE)
+ set(Matlab_VERSION_STRING_INTERNAL
+ "${_matlab_version_tmp}"
+ CACHE INTERNAL "Matlab (MCR) version (automatically determined)"
+ FORCE)
+ endif() # Matlab or MCR
+
+endfunction()
+
+
+# Utility function for finding Matlab or MCR on Win32
+function(_Matlab_find_instances_win32 matlab_roots)
+ # On WIN32, we look for Matlab installation in the registry
+ # if unsuccessful, we look for all known revision and filter the existing
+ # ones.
+
+ # testing if we are able to extract the needed information from the registry
+ set(_matlab_versions_from_registry)
+
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(_matlab_win64 ON)
+ else()
+ set(_matlab_win64 OFF)
+ endif()
+
+ matlab_extract_all_installed_versions_from_registry(_matlab_win64 _matlab_versions_from_registry)
+
+ # the returned list is empty, doing the search on all known versions
+ if(NOT _matlab_versions_from_registry)
+ if(MATLAB_FIND_DEBUG)
+ message(STATUS "[MATLAB] Search for Matlab from the registry unsuccessful, testing all supported versions")
+ endif()
+ extract_matlab_versions_from_registry_brute_force(_matlab_versions_from_registry)
+ endif()
+
+ # filtering the results with the registry keys
+ matlab_get_all_valid_matlab_roots_from_registry("${_matlab_versions_from_registry}" _matlab_possible_roots)
+ set(${matlab_roots} ${_matlab_possible_roots} PARENT_SCOPE)
+
+endfunction()
+
+# Utility function for finding Matlab or MCR on OSX
+function(_Matlab_find_instances_osx matlab_roots)
+
+ set(_matlab_possible_roots)
+ # on mac, we look for the /Application paths
+ # this corresponds to the behaviour on Windows. On Linux, we do not have
+ # any other guess.
+ matlab_get_supported_releases(_matlab_releases)
+ if(MATLAB_FIND_DEBUG)
+ message(STATUS "[MATLAB] Matlab supported versions ${_matlab_releases}. If more version should be supported "
+ "the variable MATLAB_ADDITIONAL_VERSIONS can be set according to the documentation")
+ endif()
+
+ foreach(_matlab_current_release IN LISTS _matlab_releases)
+ matlab_get_version_from_release_name("${_matlab_current_release}" _matlab_current_version)
+ string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}")
+ set(_matlab_base_path "/Applications/MATLAB_${_matlab_current_release}.app")
+
+ # Check Matlab, has precedence over MCR
+ if(EXISTS ${_matlab_base_path})
+ if(MATLAB_FIND_DEBUG)
+ message(STATUS "[MATLAB] Found version ${_matlab_current_release} (${_matlab_current_version}) in ${_matlab_base_path}")
+ endif()
+ list(APPEND _matlab_possible_roots "MATLAB" ${_matlab_current_version} ${_matlab_base_path})
+ endif()
+
+ # Checks MCR
+ set(_mcr_path "/Applications/MATLAB/MATLAB_Runtime/v${_matlab_current_version_without_dot}")
+ if(EXISTS "${_mcr_path}")
+ if(MATLAB_FIND_DEBUG)
+ message(STATUS "[MATLAB] Found MCR version ${_matlab_current_release} (${_matlab_current_version}) in ${_mcr_path}")
+ endif()
+ list(APPEND _matlab_possible_roots "MCR" ${_matlab_current_version} ${_mcr_path})
+ endif()
+
+ endforeach()
+ set(${matlab_roots} ${_matlab_possible_roots} PARENT_SCOPE)
+
+endfunction()
+
+# Utility function for finding Matlab or MCR from the PATH
+function(_Matlab_find_instances_from_path matlab_roots)
+
+ set(_matlab_possible_roots)
+
+ # At this point, we have no other choice than trying to find it from PATH.
+ # If set by the user, this wont change
+ find_program(
+ _matlab_main_tmp
+ NAMES matlab)
+
+ if(_matlab_main_tmp)
+ # we then populate the list of roots, with empty version
+ if(MATLAB_FIND_DEBUG)
+ message(STATUS "[MATLAB] matlab found from PATH: ${_matlab_main_tmp}")
+ endif()
+
+ # resolve symlinks
+ get_filename_component(_matlab_current_location "${_matlab_main_tmp}" REALPATH)
+
+ # get the directory (the command below has to be run twice)
+ # this will be the matlab root
+ get_filename_component(_matlab_current_location "${_matlab_current_location}" DIRECTORY)
+ get_filename_component(_matlab_current_location "${_matlab_current_location}" DIRECTORY) # Matlab should be in bin
+
+ # We found the Matlab program
+ list(APPEND _matlab_possible_roots "MATLAB" "NOTFOUND" ${_matlab_current_location})
+
+ # we remove this from the CACHE
+ unset(_matlab_main_tmp CACHE)
+ else()
+ find_program(
+ _matlab_mex_tmp
+ NAMES mex)
+ if(_matlab_mex_tmp)
+ # we then populate the list of roots, with empty version
+ if(MATLAB_FIND_DEBUG)
+ message(STATUS "[MATLAB] mex compiler found from PATH: ${_matlab_mex_tmp}")
+ endif()
+
+ # resolve symlinks
+ get_filename_component(_mex_current_location "${_matlab_mex_tmp}" REALPATH)
+
+ # get the directory (the command below has to be run twice)
+ # this will be the matlab root
+ get_filename_component(_mex_current_location "${_mex_current_location}" DIRECTORY)
+ get_filename_component(_mex_current_location "${_mex_current_location}" DIRECTORY) # Matlab Runtime mex compiler should be in bin
+
+ # We found the Matlab program
+ list(APPEND _matlab_possible_roots "MCR" "NOTFOUND" ${_mex_current_location})
+
+ unset(_matlab_mex_tmp CACHE)
+ else()
+ if(MATLAB_FIND_DEBUG)
+ message(STATUS "[MATLAB] mex compiler not found")
+ endif()
+ endif()
+
+
+ endif()
+
+ set(${matlab_roots} ${_matlab_possible_roots} PARENT_SCOPE)
+endfunction()
+
+
+# ###################################
+# Exploring the possible Matlab_ROOTS
+
+# this variable will get all Matlab installations found in the current system.
+set(_matlab_possible_roots)
+
+if(Matlab_ROOT_DIR)
+ # if the user specifies a possible root, we keep this one
+
+ if(NOT EXISTS "${Matlab_ROOT_DIR}")
+ # if Matlab_ROOT_DIR specified but erroneous
+ if(MATLAB_FIND_DEBUG)
+ message(WARNING "[MATLAB] the specified path for Matlab_ROOT_DIR does not exist (${Matlab_ROOT_DIR})")
+ endif()
+ else()
+ # NOTFOUND indicates the code below to search for the version automatically
+ if("${Matlab_VERSION_STRING_INTERNAL}" STREQUAL "")
+ list(APPEND _matlab_possible_roots "UNKNOWN" "NOTFOUND" ${Matlab_ROOT_DIR}) # empty version, empty MCR/Matlab indication
+ else()
+ list(APPEND _matlab_possible_roots "UNKNOWN" ${Matlab_VERSION_STRING_INTERNAL} ${Matlab_ROOT_DIR}) # cached version
+ endif()
+ endif()
+else()
+
+ # if the user does not specify the possible installation root, we look for
+ # one installation using the appropriate heuristics.
+ # There is apparently no standard way on Linux.
+ if(CMAKE_HOST_WIN32)
+ _Matlab_find_instances_win32(_matlab_possible_roots_win32)
+ list(APPEND _matlab_possible_roots ${_matlab_possible_roots_win32})
+ elseif(APPLE)
+ _Matlab_find_instances_osx(_matlab_possible_roots_osx)
+ list(APPEND _matlab_possible_roots ${_matlab_possible_roots_osx})
+ endif()
+endif()
+
+
+list(LENGTH _matlab_possible_roots _numbers_of_matlab_roots)
+if(_numbers_of_matlab_roots EQUAL 0)
+ # if we have not found anything, we fall back on the PATH
+ _Matlab_find_instances_from_path(_matlab_possible_roots)
+endif()
+
+
+if(MATLAB_FIND_DEBUG)
+ message(STATUS "[MATLAB] Matlab root folders are ${_matlab_possible_roots}")
+endif()
+
+
+
+
+
+# take the first possible Matlab root
+list(LENGTH _matlab_possible_roots _numbers_of_matlab_roots)
+set(Matlab_VERSION_STRING "NOTFOUND")
+set(Matlab_Or_MCR "UNKNOWN")
+if(_numbers_of_matlab_roots GREATER 0)
+ if(Matlab_FIND_VERSION_EXACT)
+ list(FIND _matlab_possible_roots ${Matlab_FIND_VERSION} _list_index)
+ if(_list_index LESS 0)
+ set(_list_index 1)
+ endif()
+
+ math(EXPR _matlab_or_mcr_index "${_list_index} - 1")
+ math(EXPR _matlab_root_dir_index "${_list_index} + 1")
+
+ list(GET _matlab_possible_roots ${_matlab_or_mcr_index} Matlab_Or_MCR)
+ list(GET _matlab_possible_roots ${_list_index} Matlab_VERSION_STRING)
+ list(GET _matlab_possible_roots ${_matlab_root_dir_index} Matlab_ROOT_DIR)
+ else()
+ list(GET _matlab_possible_roots 0 Matlab_Or_MCR)
+ list(GET _matlab_possible_roots 1 Matlab_VERSION_STRING)
+ list(GET _matlab_possible_roots 2 Matlab_ROOT_DIR)
+
+ # adding a warning in case of ambiguity
+ if(_numbers_of_matlab_roots GREATER 3 AND MATLAB_FIND_DEBUG)
+ message(WARNING "[MATLAB] Found several distributions of Matlab. Setting the current version to ${Matlab_VERSION_STRING} (located ${Matlab_ROOT_DIR})."
+ " If this is not the desired behaviour, use the EXACT keyword or provide the -DMatlab_ROOT_DIR=... on the command line")
+ endif()
+ endif()
+endif()
+
+
+# check if the root changed wrt. the previous defined one, if so
+# clear all the cached variables for being able to reconfigure properly
+if(DEFINED Matlab_ROOT_DIR_LAST_CACHED)
+
+ if(NOT Matlab_ROOT_DIR_LAST_CACHED STREQUAL Matlab_ROOT_DIR)
+ set(_Matlab_cached_vars
+ Matlab_VERSION_STRING
+ Matlab_INCLUDE_DIRS
+ Matlab_MEX_LIBRARY
+ Matlab_MEX_COMPILER
+ Matlab_MCC_COMPILER
+ Matlab_MAIN_PROGRAM
+ Matlab_MX_LIBRARY
+ Matlab_ENG_LIBRARY
+ Matlab_MAT_LIBRARY
+ Matlab_ENGINE_LIBRARY
+ Matlab_DATAARRAY_LIBRARY
+ Matlab_MEX_EXTENSION
+ Matlab_SIMULINK_INCLUDE_DIR
+
+ # internal
+ Matlab_MEXEXTENSIONS_PROG
+ Matlab_ROOT_DIR_LAST_CACHED
+ #Matlab_PROG_VERSION_STRING_AUTO_DETECT
+ #Matlab_VERSION_STRING_INTERNAL
+ )
+ foreach(_var IN LISTS _Matlab_cached_vars)
+ if(DEFINED ${_var})
+ unset(${_var} CACHE)
+ endif()
+ endforeach()
+ endif()
+endif()
+
+set(Matlab_ROOT_DIR_LAST_CACHED ${Matlab_ROOT_DIR} CACHE INTERNAL "last Matlab root dir location")
+set(Matlab_ROOT_DIR ${Matlab_ROOT_DIR} CACHE PATH "Matlab installation root path" FORCE)
+
+# Fix the version, in case this one is NOTFOUND
+_Matlab_get_version_from_root(
+ "${Matlab_ROOT_DIR}"
+ "${Matlab_Or_MCR}"
+ ${Matlab_VERSION_STRING}
+ Matlab_VERSION_STRING
+)
+
+if(MATLAB_FIND_DEBUG)
+ message(STATUS "[MATLAB] Current version is ${Matlab_VERSION_STRING} located ${Matlab_ROOT_DIR}")
+endif()
+
+# MATLAB 9.4 (R2018a) and newer have a new C++ API
+# This API pulls additional required libraries.
+if(NOT ${Matlab_VERSION_STRING} VERSION_LESS "9.4")
+ set(Matlab_HAS_CPP_API 1)
+endif()
+
+if(Matlab_ROOT_DIR)
+ file(TO_CMAKE_PATH ${Matlab_ROOT_DIR} Matlab_ROOT_DIR)
+endif()
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(_matlab_64Build FALSE)
+else()
+ set(_matlab_64Build TRUE)
+endif()
+
+if(APPLE)
+ set(_matlab_bin_prefix "mac") # i should be for intel
+ set(_matlab_bin_suffix_32bits "i")
+ set(_matlab_bin_suffix_64bits "i64")
+elseif(UNIX)
+ set(_matlab_bin_prefix "gln")
+ set(_matlab_bin_suffix_32bits "x86")
+ set(_matlab_bin_suffix_64bits "xa64")
+else()
+ set(_matlab_bin_prefix "win")
+ set(_matlab_bin_suffix_32bits "32")
+ set(_matlab_bin_suffix_64bits "64")
+endif()
+
+
+
+set(MATLAB_INCLUDE_DIR_TO_LOOK ${Matlab_ROOT_DIR}/extern/include)
+if(_matlab_64Build)
+ set(_matlab_current_suffix ${_matlab_bin_suffix_64bits})
+else()
+ set(_matlab_current_suffix ${_matlab_bin_suffix_32bits})
+endif()
+
+set(Matlab_BINARIES_DIR
+ ${Matlab_ROOT_DIR}/bin/${_matlab_bin_prefix}${_matlab_current_suffix})
+set(Matlab_EXTERN_LIBRARY_DIR
+ ${Matlab_ROOT_DIR}/extern/lib/${_matlab_bin_prefix}${_matlab_current_suffix})
+set(Matlab_EXTERN_BINARIES_DIR
+ ${Matlab_ROOT_DIR}/extern/bin/${_matlab_bin_prefix}${_matlab_current_suffix})
+
+if(WIN32)
+ if(MINGW)
+ set(_matlab_lib_dir_for_search ${Matlab_EXTERN_LIBRARY_DIR}/mingw64)
+ else()
+ set(_matlab_lib_dir_for_search ${Matlab_EXTERN_LIBRARY_DIR}/microsoft)
+ endif()
+ set(_matlab_lib_prefix_for_search "lib")
+else()
+ set(_matlab_lib_dir_for_search ${Matlab_BINARIES_DIR} ${Matlab_EXTERN_BINARIES_DIR})
+ set(_matlab_lib_prefix_for_search "lib")
+endif()
+
+unset(_matlab_64Build)
+
+
+if(NOT DEFINED Matlab_MEX_EXTENSION)
+ set(_matlab_mex_extension "")
+ matlab_get_mex_suffix("${Matlab_ROOT_DIR}" _matlab_mex_extension)
+
+ # This variable goes to the cache.
+ set(Matlab_MEX_EXTENSION ${_matlab_mex_extension} CACHE STRING "Extensions for the mex targets (automatically given by Matlab)")
+ unset(_matlab_mex_extension)
+endif()
+
+
+if(MATLAB_FIND_DEBUG)
+ message(STATUS "[MATLAB] [DEBUG]_matlab_lib_prefix_for_search = ${_matlab_lib_prefix_for_search} | _matlab_lib_dir_for_search = ${_matlab_lib_dir_for_search}")
+endif()
+
+
+
+# internal
+# This small stub around find_library is to prevent any pollution of CMAKE_FIND_LIBRARY_PREFIXES in the global scope.
+# This is the function to be used below instead of the find_library directives.
+function(_Matlab_find_library _matlab_library_prefix)
+ set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} ${_matlab_library_prefix})
+ find_library(${ARGN})
+endfunction()
+
+
+set(_matlab_required_variables)
+
+# Order is as follow:
+# - unconditionally required libraries/headers first
+# - then library components
+# - then program components
+
+# the MEX library/header are required
+find_path(
+ Matlab_INCLUDE_DIRS
+ mex.h
+ PATHS ${MATLAB_INCLUDE_DIR_TO_LOOK}
+ NO_DEFAULT_PATH
+ )
+list(APPEND _matlab_required_variables Matlab_INCLUDE_DIRS)
+
+if(Matlab_Or_MCR STREQUAL "MATLAB" OR Matlab_Or_MCR STREQUAL "UNKNOWN")
+ _Matlab_find_library(
+ ${_matlab_lib_prefix_for_search}
+ Matlab_MEX_LIBRARY
+ mex
+ PATHS ${_matlab_lib_dir_for_search}
+ NO_DEFAULT_PATH
+ )
+ list(APPEND _matlab_required_variables Matlab_MEX_LIBRARY)
+
+ # the MEX extension is required
+ list(APPEND _matlab_required_variables Matlab_MEX_EXTENSION)
+
+ # the matlab root is required
+ list(APPEND _matlab_required_variables Matlab_ROOT_DIR)
+
+ # The MX library is required
+ _Matlab_find_library(
+ ${_matlab_lib_prefix_for_search}
+ Matlab_MX_LIBRARY
+ mx
+ PATHS ${_matlab_lib_dir_for_search}
+ NO_DEFAULT_PATH
+ )
+ list(APPEND _matlab_required_variables Matlab_MX_LIBRARY)
+ if(Matlab_MX_LIBRARY)
+ set(Matlab_MX_LIBRARY_FOUND TRUE)
+ endif()
+endif()
+
+if(Matlab_HAS_CPP_API)
+
+ # The MatlabEngine library is required for R2018a+
+ _Matlab_find_library(
+ ${_matlab_lib_prefix_for_search}
+ Matlab_ENGINE_LIBRARY
+ MatlabEngine
+ PATHS ${_matlab_lib_dir_for_search}
+ DOC "MatlabEngine Library"
+ NO_DEFAULT_PATH
+ )
+ if(Matlab_ENGINE_LIBRARY)
+ set(Matlab_ENGINE_LIBRARY_FOUND TRUE)
+ endif()
+
+ # The MatlabDataArray library is required for R2018a+
+ _Matlab_find_library(
+ ${_matlab_lib_prefix_for_search}
+ Matlab_DATAARRAY_LIBRARY
+ MatlabDataArray
+ PATHS ${_matlab_lib_dir_for_search}
+ DOC "MatlabDataArray Library"
+ NO_DEFAULT_PATH
+ )
+ if(Matlab_DATAARRAY_LIBRARY)
+ set(Matlab_DATAARRAY_LIBRARY_FOUND TRUE)
+ endif()
+
+endif()
+
+# Component ENG library
+if("ENG_LIBRARY" IN_LIST Matlab_FIND_COMPONENTS)
+ _Matlab_find_library(
+ ${_matlab_lib_prefix_for_search}
+ Matlab_ENG_LIBRARY
+ eng
+ PATHS ${_matlab_lib_dir_for_search}
+ NO_DEFAULT_PATH
+ )
+ if(Matlab_ENG_LIBRARY)
+ set(Matlab_ENG_LIBRARY_FOUND TRUE)
+ endif()
+endif()
+
+# Component MAT library
+if("MAT_LIBRARY" IN_LIST Matlab_FIND_COMPONENTS)
+ _Matlab_find_library(
+ ${_matlab_lib_prefix_for_search}
+ Matlab_MAT_LIBRARY
+ mat
+ PATHS ${_matlab_lib_dir_for_search}
+ NO_DEFAULT_PATH
+ )
+ if(Matlab_MAT_LIBRARY)
+ set(Matlab_MAT_LIBRARY_FOUND TRUE)
+ endif()
+endif()
+
+# Component Simulink
+if("SIMULINK" IN_LIST Matlab_FIND_COMPONENTS)
+ find_path(
+ Matlab_SIMULINK_INCLUDE_DIR
+ simstruc.h
+ PATHS "${Matlab_ROOT_DIR}/simulink/include"
+ NO_DEFAULT_PATH
+ )
+ if(Matlab_SIMULINK_INCLUDE_DIR)
+ set(Matlab_SIMULINK_FOUND TRUE)
+ list(APPEND Matlab_INCLUDE_DIRS "${Matlab_SIMULINK_INCLUDE_DIR}")
+ endif()
+endif()
+
+# component Matlab program
+if("MAIN_PROGRAM" IN_LIST Matlab_FIND_COMPONENTS)
+ find_program(
+ Matlab_MAIN_PROGRAM
+ matlab
+ PATHS ${Matlab_ROOT_DIR} ${Matlab_ROOT_DIR}/bin
+ DOC "Matlab main program"
+ NO_DEFAULT_PATH
+ )
+ if(Matlab_MAIN_PROGRAM)
+ set(Matlab_MAIN_PROGRAM_FOUND TRUE)
+ endif()
+endif()
+
+# component Mex Compiler
+if("MEX_COMPILER" IN_LIST Matlab_FIND_COMPONENTS)
+ find_program(
+ Matlab_MEX_COMPILER
+ "mex"
+ PATHS ${Matlab_BINARIES_DIR}
+ DOC "Matlab MEX compiler"
+ NO_DEFAULT_PATH
+ )
+ if(Matlab_MEX_COMPILER)
+ set(Matlab_MEX_COMPILER_FOUND TRUE)
+ endif()
+endif()
+
+# component MCC Compiler
+if("MCC_COMPILER" IN_LIST Matlab_FIND_COMPONENTS)
+ find_program(
+ Matlab_MCC_COMPILER
+ "mcc"
+ PATHS ${Matlab_BINARIES_DIR}
+ DOC "Matlab MCC compiler"
+ NO_DEFAULT_PATH
+ )
+ if(Matlab_MCC_COMPILER)
+ set(Matlab_MCC_COMPILER_FOUND TRUE)
+ endif()
+endif()
+
+set(Matlab_LIBRARIES
+ ${Matlab_MEX_LIBRARY} ${Matlab_MX_LIBRARY}
+ ${Matlab_ENG_LIBRARY} ${Matlab_MAT_LIBRARY})
+
+if(Matlab_ENGINE_LIBRARY)
+ list(APPEND Matlab_LIBRARIES ${Matlab_ENGINE_LIBRARY})
+endif()
+
+if(Matlab_DATAARRAY_LIBRARY)
+ list(APPEND Matlab_LIBRARIES ${Matlab_DATAARRAY_LIBRARY})
+endif()
+
+find_package_handle_standard_args(
+ Matlab
+ FOUND_VAR Matlab_FOUND
+ REQUIRED_VARS ${_matlab_required_variables}
+ VERSION_VAR Matlab_VERSION_STRING
+ HANDLE_COMPONENTS)
+
+unset(_matlab_required_variables)
+unset(_matlab_bin_prefix)
+unset(_matlab_bin_suffix_32bits)
+unset(_matlab_bin_suffix_64bits)
+unset(_matlab_current_suffix)
+unset(_matlab_lib_dir_for_search)
+unset(_matlab_lib_prefix_for_search)
+
+if(Matlab_INCLUDE_DIRS AND Matlab_LIBRARIES)
+ mark_as_advanced(
+ Matlab_MEX_LIBRARY
+ Matlab_MX_LIBRARY
+ Matlab_ENG_LIBRARY
+ Matlab_ENGINE_LIBRARY
+ Matlab_DATAARRAY_LIBRARY
+ Matlab_MAT_LIBRARY
+ Matlab_INCLUDE_DIRS
+ Matlab_FOUND
+ Matlab_MAIN_PROGRAM
+ Matlab_MEXEXTENSIONS_PROG
+ Matlab_MEX_EXTENSION
+ )
+endif()
+
+cmake_policy(POP)
diff --git a/Modules/FindMotif.cmake b/Modules/FindMotif.cmake
new file mode 100644
index 0000000..4f7080a
--- /dev/null
+++ b/Modules/FindMotif.cmake
@@ -0,0 +1,40 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindMotif
+---------
+
+Try to find Motif (or lesstif)
+
+Once done this will define:
+
+::
+
+ MOTIF_FOUND - system has MOTIF
+ MOTIF_INCLUDE_DIR - include paths to use Motif
+ MOTIF_LIBRARIES - Link these to use Motif
+#]=======================================================================]
+
+set(MOTIF_FOUND 0)
+
+if(UNIX)
+ find_path(MOTIF_INCLUDE_DIR
+ Xm/Xm.h
+ /usr/openwin/include
+ )
+
+ find_library(MOTIF_LIBRARIES
+ Xm
+ /usr/openwin/lib
+ )
+
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Motif DEFAULT_MSG MOTIF_LIBRARIES MOTIF_INCLUDE_DIR)
+
+mark_as_advanced(
+ MOTIF_INCLUDE_DIR
+ MOTIF_LIBRARIES
+)
diff --git a/Modules/FindODBC.cmake b/Modules/FindODBC.cmake
new file mode 100644
index 0000000..884653c
--- /dev/null
+++ b/Modules/FindODBC.cmake
@@ -0,0 +1,233 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindODBC
+--------
+
+.. versionadded:: 3.12
+
+Find an Open Database Connectivity (ODBC) include directory and library.
+
+On Windows, when building with Visual Studio, this module assumes the ODBC
+library is provided by the available Windows SDK.
+
+On Unix, this module allows to search for ODBC library provided by
+unixODBC or iODBC implementations of ODBC API.
+This module reads hint about location of the config program:
+
+.. variable:: ODBC_CONFIG
+
+ Location of odbc_config or iodbc-config program
+
+Otherwise, this module tries to find the config program,
+first from unixODBC, then from iODBC.
+If no config program found, this module searches for ODBC header
+and library in list of known locations.
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+This module defines the following :prop_tgt:`IMPORTED` targets:
+
+.. variable:: ODBC::ODBC
+
+ Imported target for using the ODBC library, if found.
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+.. variable:: ODBC_FOUND
+
+ Set to true if ODBC library found, otherwise false or undefined.
+
+.. variable:: ODBC_INCLUDE_DIRS
+
+ Paths to include directories listed in one variable for use by ODBC client.
+ May be empty on Windows, where the include directory corresponding to the
+ expected Windows SDK is already available in the compilation environment.
+
+.. variable:: ODBC_LIBRARIES
+
+ Paths to libraries to linked against to use ODBC.
+ May just a library name on Windows, where the library directory corresponding
+ to the expected Windows SDK is already available in the compilation environment.
+
+.. variable:: ODBC_CONFIG
+
+ Path to unixODBC or iODBC config program, if found or specified.
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+For users who wish to edit and control the module behavior, this module
+reads hints about search locations from the following variables:
+
+.. variable:: ODBC_INCLUDE_DIR
+
+ Path to ODBC include directory with ``sql.h`` header.
+
+.. variable:: ODBC_LIBRARY
+
+ Path to ODBC library to be linked.
+
+These variables should not be used directly by project code.
+
+Limitations
+^^^^^^^^^^^
+
+On Windows, this module does not search for iODBC.
+On Unix, there is no way to prefer unixODBC over iODBC, or vice versa,
+other than providing the config program location using the ``ODBC_CONFIG``.
+This module does not allow to search for a specific ODBC driver.
+
+#]=======================================================================]
+
+# Define lists used internally
+set(_odbc_include_paths)
+set(_odbc_lib_paths)
+set(_odbc_lib_names)
+set(_odbc_required_libs_names)
+
+### Try Windows Kits ##########################################################
+if(WIN32)
+ # List names of ODBC libraries on Windows
+ if(NOT MINGW)
+ set(ODBC_LIBRARY odbc32.lib)
+ else()
+ set(ODBC_LIBRARY libodbc32.a)
+ endif()
+ set(_odbc_lib_names odbc32;)
+
+ # List additional libraries required to use ODBC library
+ if(MSVC OR CMAKE_CXX_COMPILER_ID MATCHES "Intel")
+ set(_odbc_required_libs_names odbccp32;ws2_32)
+ elseif(MINGW)
+ set(_odbc_required_libs_names odbccp32)
+ endif()
+endif()
+
+### Try unixODBC or iODBC config program ######################################
+if (UNIX)
+ find_program(ODBC_CONFIG
+ NAMES odbc_config iodbc-config
+ DOC "Path to unixODBC or iODBC config program")
+ mark_as_advanced(ODBC_CONFIG)
+endif()
+
+if (UNIX AND ODBC_CONFIG)
+ # unixODBC and iODBC accept unified command line options
+ execute_process(COMMAND ${ODBC_CONFIG} --cflags
+ OUTPUT_VARIABLE _cflags OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${ODBC_CONFIG} --libs
+ OUTPUT_VARIABLE _libs OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ # Collect paths of include directories from CFLAGS
+ separate_arguments(_cflags NATIVE_COMMAND "${_cflags}")
+ foreach(arg IN LISTS _cflags)
+ if("${arg}" MATCHES "^-I(.*)$")
+ list(APPEND _odbc_include_paths "${CMAKE_MATCH_1}")
+ endif()
+ endforeach()
+ unset(_cflags)
+
+ # Collect paths of library names and directories from LIBS
+ separate_arguments(_libs NATIVE_COMMAND "${_libs}")
+ foreach(arg IN LISTS _libs)
+ if("${arg}" MATCHES "^-L(.*)$")
+ list(APPEND _odbc_lib_paths "${CMAKE_MATCH_1}")
+ elseif("${arg}" MATCHES "^-l(.*)$")
+ set(_lib_name ${CMAKE_MATCH_1})
+ string(REGEX MATCH "odbc" _is_odbc ${_lib_name})
+ if(_is_odbc)
+ list(APPEND _odbc_lib_names ${_lib_name})
+ else()
+ list(APPEND _odbc_required_libs_names ${_lib_name})
+ endif()
+ unset(_lib_name)
+ endif()
+ endforeach()
+ unset(_libs)
+endif()
+
+### Try unixODBC or iODBC in include/lib filesystems ##########################
+if (UNIX AND NOT ODBC_CONFIG)
+ # List names of both ODBC libraries, unixODBC and iODBC
+ set(_odbc_lib_names odbc;iodbc;unixodbc;)
+endif()
+
+### Find include directories ##################################################
+find_path(ODBC_INCLUDE_DIR
+ NAMES sql.h
+ PATHS ${_odbc_include_paths})
+
+if(NOT ODBC_INCLUDE_DIR AND WIN32)
+ set(ODBC_INCLUDE_DIR "")
+endif()
+
+### Find libraries ############################################################
+if(NOT ODBC_LIBRARY)
+ find_library(ODBC_LIBRARY
+ NAMES ${_odbc_lib_names}
+ PATHS ${_odbc_lib_paths}
+ PATH_SUFFIXES odbc)
+
+ foreach(_lib IN LISTS _odbc_required_libs_names)
+ find_library(_lib_path
+ NAMES ${_lib}
+ PATHS ${_odbc_lib_paths} # system parths or collected from ODBC_CONFIG
+ PATH_SUFFIXES odbc)
+ if(_lib_path)
+ list(APPEND _odbc_required_libs_paths ${_lib_path})
+ endif()
+ unset(_lib_path CACHE)
+ endforeach()
+endif()
+
+# Unset internal lists as no longer used
+unset(_odbc_include_paths)
+unset(_odbc_lib_paths)
+unset(_odbc_lib_names)
+unset(_odbc_required_libs_names)
+
+### Set result variables ######################################################
+set(_odbc_required_vars ODBC_LIBRARY)
+if(NOT WIN32)
+ list(APPEND _odbc_required_vars ODBC_INCLUDE_DIR)
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(ODBC DEFAULT_MSG ${_odbc_required_vars})
+
+unset(_odbc_required_vars)
+
+mark_as_advanced(ODBC_LIBRARY ODBC_INCLUDE_DIR)
+
+set(ODBC_INCLUDE_DIRS ${ODBC_INCLUDE_DIR})
+list(APPEND ODBC_LIBRARIES ${ODBC_LIBRARY})
+list(APPEND ODBC_LIBRARIES ${_odbc_required_libs_paths})
+
+### Import targets ############################################################
+if(ODBC_FOUND)
+ if(NOT TARGET ODBC::ODBC)
+ if(IS_ABSOLUTE "${ODBC_LIBRARY}")
+ add_library(ODBC::ODBC UNKNOWN IMPORTED)
+ set_target_properties(ODBC::ODBC PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${ODBC_LIBRARY}")
+ else()
+ add_library(ODBC::ODBC INTERFACE IMPORTED)
+ set_target_properties(ODBC::ODBC PROPERTIES
+ IMPORTED_LIBNAME "${ODBC_LIBRARY}")
+ endif()
+ set_target_properties(ODBC::ODBC PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${ODBC_INCLUDE_DIR}")
+
+ if(_odbc_required_libs_paths)
+ set_property(TARGET ODBC::ODBC APPEND PROPERTY
+ INTERFACE_LINK_LIBRARIES "${_odbc_required_libs_paths}")
+ endif()
+ endif()
+endif()
+
+unset(_odbc_required_libs_paths)
diff --git a/Modules/FindOpenACC.cmake b/Modules/FindOpenACC.cmake
new file mode 100644
index 0000000..cf58f3b
--- /dev/null
+++ b/Modules/FindOpenACC.cmake
@@ -0,0 +1,296 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindOpenACC
+-----------
+
+.. versionadded:: 3.10
+
+Detect OpenACC support by the compiler.
+
+This module can be used to detect OpenACC support in a compiler.
+If the compiler supports OpenACC, the flags required to compile with
+OpenACC support are returned in variables for the different languages.
+Currently, only NVHPC, PGI, GNU and Cray compilers are supported.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.16
+
+The module provides :prop_tgt:`IMPORTED` targets:
+
+``OpenACC::OpenACC_<lang>``
+ Target for using OpenACC from ``<lang>``.
+
+Variables
+^^^^^^^^^
+
+This module will set the following variables per language in your
+project, where ``<lang>`` is one of C, CXX, or Fortran:
+
+``OpenACC_<lang>_FOUND``
+ Variable indicating if OpenACC support for ``<lang>`` was detected.
+``OpenACC_<lang>_FLAGS``
+ OpenACC compiler flags for ``<lang>``, separated by spaces.
+``OpenACC_<lang>_OPTIONS``
+ .. versionadded:: 3.16
+
+ OpenACC compiler flags for ``<lang>``, as a list. Suitable for usage
+ with target_compile_options or target_link_options.
+
+The module will also try to provide the OpenACC version variables:
+
+``OpenACC_<lang>_SPEC_DATE``
+ Date of the OpenACC specification implemented by the ``<lang>`` compiler.
+``OpenACC_<lang>_VERSION_MAJOR``
+ Major version of OpenACC implemented by the ``<lang>`` compiler.
+``OpenACC_<lang>_VERSION_MINOR``
+ Minor version of OpenACC implemented by the ``<lang>`` compiler.
+``OpenACC_<lang>_VERSION``
+ OpenACC version implemented by the ``<lang>`` compiler.
+
+The specification date is formatted as given in the OpenACC standard:
+``yyyymm`` where ``yyyy`` and ``mm`` represents the year and month of
+the OpenACC specification implemented by the ``<lang>`` compiler.
+
+Input Variables
+^^^^^^^^^^^^^^^
+
+``OpenACC_ACCEL_TARGET=<target>``
+If set, will the correct target accelerator flag set to the <target> will
+be returned with OpenACC_<lang>_FLAGS.
+#]=======================================================================]
+
+set(OpenACC_C_CXX_TEST_SOURCE
+"
+int main(){
+#ifdef _OPENACC
+ return 0;
+#else
+ breaks_on_purpose
+#endif
+}
+"
+)
+set(OpenACC_Fortran_TEST_SOURCE
+"
+program test
+#ifndef _OPENACC
+ breaks_on_purpose
+#endif
+endprogram test
+"
+)
+set(OpenACC_C_CXX_CHECK_VERSION_SOURCE
+"
+#include <stdio.h>
+const char accver_str[] = { 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'A',
+ 'C', 'C', '-', 'd', 'a', 't', 'e', '[',
+ ('0' + ((_OPENACC/100000)%10)),
+ ('0' + ((_OPENACC/10000)%10)),
+ ('0' + ((_OPENACC/1000)%10)),
+ ('0' + ((_OPENACC/100)%10)),
+ ('0' + ((_OPENACC/10)%10)),
+ ('0' + ((_OPENACC/1)%10)),
+ ']', '\\0' };
+int main()
+{
+ puts(accver_str);
+ return 0;
+}
+")
+set(OpenACC_Fortran_CHECK_VERSION_SOURCE
+"
+ program acc_ver
+ implicit none
+ integer, parameter :: zero = ichar('0')
+ character, dimension(25), parameter :: accver_str =&
+ (/ 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'A', 'C', 'C', '-',&
+ 'd', 'a', 't', 'e', '[',&
+ char(zero + mod(_OPENACC/100000, 10)),&
+ char(zero + mod(_OPENACC/10000, 10)),&
+ char(zero + mod(_OPENACC/1000, 10)),&
+ char(zero + mod(_OPENACC/100, 10)),&
+ char(zero + mod(_OPENACC/10, 10)),&
+ char(zero + mod(_OPENACC/1, 10)), ']' /)
+ print *, accver_str
+ end program acc_ver
+"
+)
+
+
+function(_OPENACC_WRITE_SOURCE_FILE LANG SRC_FILE_CONTENT_VAR SRC_FILE_NAME SRC_FILE_FULLPATH)
+ set(WORK_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenACC)
+ if("${LANG}" STREQUAL "C")
+ set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.c")
+ file(WRITE "${SRC_FILE}" "${OpenACC_C_CXX_${SRC_FILE_CONTENT_VAR}}")
+ elseif("${LANG}" STREQUAL "CXX")
+ set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.cpp")
+ file(WRITE "${SRC_FILE}" "${OpenACC_C_CXX_${SRC_FILE_CONTENT_VAR}}")
+ elseif("${LANG}" STREQUAL "Fortran")
+ set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.F90")
+ file(WRITE "${SRC_FILE}_in" "${OpenACC_Fortran_${SRC_FILE_CONTENT_VAR}}")
+ configure_file("${SRC_FILE}_in" "${SRC_FILE}" @ONLY)
+ endif()
+ set(${SRC_FILE_FULLPATH} "${SRC_FILE}" PARENT_SCOPE)
+endfunction()
+
+
+function(_OPENACC_GET_FLAGS_CANDIDATE LANG FLAG_VAR)
+ set(ACC_FLAG_NVHPC "-acc")
+ set(ACC_FLAG_PGI "-acc")
+ set(ACC_FLAG_GNU "-fopenacc")
+ set(ACC_FLAG_Cray "-h acc")
+
+ if(DEFINED ACC_FLAG_${CMAKE_${LANG}_COMPILER_ID})
+ set("${FLAG_VAR}" "${ACC_FLAG_${CMAKE_${LANG}_COMPILER_ID}}" PARENT_SCOPE)
+ else()
+ # Fall back to a few common flags.
+ set("${FLAG_VAR}" ${ACC_FLAG_GNU} ${ACC_FLAG_PGI})
+ endif()
+
+endfunction()
+
+
+function(_OPENACC_GET_ACCEL_TARGET_FLAG LANG TARGET FLAG_VAR)
+ # Find target accelerator flags.
+ set(ACC_TARGET_FLAG_NVHPC "-ta")
+ set(ACC_TARGET_FLAG_PGI "-ta")
+ if(DEFINED ACC_TARGET_FLAG_${CMAKE_${LANG}_COMPILER_ID})
+ set("${FLAG_VAR}" "${ACC_TARGET_FLAG_${CMAKE_${LANG}_COMPILER_ID}}=${TARGET}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+
+function(_OPENACC_GET_VERBOSE_FLAG LANG FLAG_VAR)
+ # Find compiler's verbose flag for OpenACC.
+ set(ACC_VERBOSE_FLAG_NVHPC "-Minfo=accel")
+ set(ACC_VERBOSE_FLAG_PGI "-Minfo=accel")
+ if(DEFINED ACC_VERBOSE_FLAG_${CMAKE_${LANG}_COMPILER_ID})
+ set("${FLAG_VAR}" "${ACC_VERBOSE_FLAG_${CMAKE_${LANG}_COMPILER_ID}}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+
+function(_OPENACC_GET_FLAGS LANG FLAG_VAR)
+ set(FLAG_CANDIDATES "")
+ _OPENACC_GET_FLAGS_CANDIDATE("${LANG}" FLAG_CANDIDATES)
+ _OPENACC_WRITE_SOURCE_FILE("${LANG}" "TEST_SOURCE" OpenACCTryFlag _OPENACC_TEST_SRC)
+
+ foreach(FLAG IN LISTS FLAG_CANDIDATES)
+ try_compile(OpenACC_FLAG_TEST_RESULT ${CMAKE_BINARY_DIR} ${_OPENACC_TEST_SRC}
+ CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${FLAG}"
+ OUTPUT_VARIABLE OpenACC_TRY_COMPILE_OUTPUT
+ )
+ if(OpenACC_FLAG_TEST_RESULT)
+ set("${FLAG_VAR}" "${FLAG}")
+ if(DEFINED OpenACC_ACCEL_TARGET)
+ _OPENACC_GET_ACCEL_TARGET_FLAG("${LANG}" "${OpenACC_ACCEL_TARGET}" TARGET_FLAG)
+ string(APPEND "${FLAG_VAR}" " ${TARGET_FLAG}")
+ endif()
+
+ if(CMAKE_VERBOSE_MAKEFILE)
+ # -Minfo=accel prints out OpenACC's messages on optimizations.
+ _OPENACC_GET_VERBOSE_FLAG("${LANG}" OpenACC_VERBOSE_FLAG)
+ string(APPEND "${FLAG_VAR}" " ${OpenACC_VERBOSE_FLAG}")
+ endif()
+ set("${FLAG_VAR}" "${${FLAG_VAR}}" PARENT_SCOPE)
+ break()
+ endif()
+ endforeach()
+
+endfunction()
+
+
+function(_OPENACC_GET_SPEC_DATE LANG SPEC_DATE)
+ _OPENACC_WRITE_SOURCE_FILE("${LANG}" "CHECK_VERSION_SOURCE" OpenACCCheckVersion _OPENACC_TEST_SRC)
+
+ set(BIN_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenACC/accver_${LANG}.bin")
+ try_compile(OpenACC_SPECTEST_${LANG} "${CMAKE_BINARY_DIR}" "${_OPENACC_TEST_SRC}"
+ CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OpenACC_${LANG}_FLAGS}"
+ COPY_FILE ${BIN_FILE}
+ OUTPUT_VARIABLE OUTPUT)
+
+ if(${OpenACC_SPECTEST_${LANG}})
+ file(STRINGS ${BIN_FILE} specstr LIMIT_COUNT 1 REGEX "INFO:OpenACC-date")
+ set(regex_spec_date ".*INFO:OpenACC-date\\[0*([^]]*)\\].*")
+ if("${specstr}" MATCHES "${regex_spec_date}")
+ set(${SPEC_DATE} "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ endif()
+ endif()
+endfunction()
+
+
+macro(_OPENACC_SET_VERSION_BY_SPEC_DATE LANG)
+ set(OpenACC_SPEC_DATE_MAP
+ # Combined versions, 2.5 onwards
+ "201510=2.5"
+ # 2013 08 is the corrected version.
+ "201308=2.0"
+ "201306=2.0"
+ "201111=1.0"
+ )
+
+ string(REGEX MATCHALL "${OpenACC_${LANG}_SPEC_DATE}=([0-9]+)\\.([0-9]+)" _version_match "${OpenACC_SPEC_DATE_MAP}")
+ if(NOT _version_match STREQUAL "")
+ set(OpenACC_${LANG}_VERSION_MAJOR ${CMAKE_MATCH_1})
+ set(OpenACC_${LANG}_VERSION_MINOR ${CMAKE_MATCH_2})
+ set(OpenACC_${LANG}_VERSION "${OpenACC_${LANG}_VERSION_MAJOR}.${OpenACC_${LANG}_VERSION_MINOR}")
+ else()
+ unset(OpenACC_${LANG}_VERSION_MAJOR)
+ unset(OpenACC_${LANG}_VERSION_MINOR)
+ unset(OpenACC_${LANG}_VERSION)
+ endif()
+ unset(_version_match)
+ unset(OpenACC_SPEC_DATE_MAP)
+endmacro()
+
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+foreach (LANG IN ITEMS C CXX Fortran)
+ if(CMAKE_${LANG}_COMPILER_LOADED)
+ set(OpenACC_${LANG}_FIND_QUIETLY ${OpenACC_FIND_QUIETLY})
+ set(OpenACC_${LANG}_FIND_REQUIRED ${OpenACC_FIND_REQUIRED})
+ set(OpenACC_${LANG}_FIND_VERSION ${OpenACC_FIND_VERSION})
+ set(OpenACC_${LANG}_FIND_VERSION_EXACT ${OpenACC_FIND_VERSION_EXACT})
+
+ if(NOT DEFINED OpenACC_${LANG}_FLAGS)
+ _OPENACC_GET_FLAGS("${LANG}" OpenACC_${LANG}_FLAGS)
+ endif()
+ if(NOT DEFINED OpenACC_${LANG}_OPTIONS)
+ separate_arguments(OpenACC_${LANG}_OPTIONS NATIVE_COMMAND "${OpenACC_${LANG}_FLAGS}")
+ endif()
+ _OPENACC_GET_SPEC_DATE("${LANG}" OpenACC_${LANG}_SPEC_DATE)
+ _OPENACC_SET_VERSION_BY_SPEC_DATE("${LANG}")
+
+ find_package_handle_standard_args(OpenACC_${LANG}
+ NAME_MISMATCHED
+ REQUIRED_VARS OpenACC_${LANG}_FLAGS
+ VERSION_VAR OpenACC_${LANG}_VERSION
+ )
+ endif()
+endforeach()
+
+foreach (LANG IN ITEMS C CXX Fortran)
+ if(OpenACC_${LANG}_FOUND AND NOT TARGET OpenACC::OpenACC_${LANG})
+ add_library(OpenACC::OpenACC_${LANG} INTERFACE IMPORTED)
+ endif()
+ if(OpenACC_${LANG}_LIBRARIES)
+ set_property(TARGET OpenACC::OpenACC_${LANG} PROPERTY
+ INTERFACE_LINK_LIBRARIES "${OpenACC_${LANG}_LIBRARIES}")
+ endif()
+ if(OpenACC_${LANG}_FLAGS)
+ set_property(TARGET OpenACC::OpenACC_${LANG} PROPERTY
+ INTERFACE_COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:${OpenACC_${LANG}_OPTIONS}>")
+ set_property(TARGET OpenACC::OpenACC_${LANG} PROPERTY
+ INTERFACE_LINK_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:${OpenACC_${LANG}_OPTIONS}>")
+ unset(_OpenACC_${LANG}_OPTIONS)
+ endif()
+endforeach()
+
+unset(OpenACC_C_CXX_TEST_SOURCE)
+unset(OpenACC_Fortran_TEST_SOURCE)
+unset(OpenACC_C_CXX_CHECK_VERSION_SOURCE)
+unset(OpenACC_Fortran_CHECK_VERSION_SOURCE)
diff --git a/Modules/FindOpenAL.cmake b/Modules/FindOpenAL.cmake
new file mode 100644
index 0000000..b5b92c5
--- /dev/null
+++ b/Modules/FindOpenAL.cmake
@@ -0,0 +1,96 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindOpenAL
+----------
+
+Finds Open Audio Library (OpenAL).
+
+Projects using this module should use ``#include "al.h"`` to include the OpenAL
+header file, **not** ``#include <AL/al.h>``. The reason for this is that the
+latter is not entirely portable. Windows/Creative Labs does not by default put
+their headers in ``AL/`` and macOS uses the convention ``<OpenAL/al.h>``.
+
+Hints
+^^^^^
+
+Environment variable ``$OPENALDIR`` can be used to set the prefix of OpenAL
+installation to be found.
+
+By default on macOS, system framework is search first. In other words,
+OpenAL is searched in the following order:
+
+1. System framework: ``/System/Library/Frameworks``, whose priority can be
+ changed via setting the :variable:`CMAKE_FIND_FRAMEWORK` variable.
+2. Environment variable ``$OPENALDIR``.
+3. System paths.
+4. User-compiled framework: ``~/Library/Frameworks``.
+5. Manually compiled framework: ``/Library/Frameworks``.
+6. Add-on package: ``/opt``.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``OPENAL_FOUND``
+ If false, do not try to link to OpenAL
+``OPENAL_INCLUDE_DIR``
+ OpenAL include directory
+``OPENAL_LIBRARY``
+ Path to the OpenAL library
+``OPENAL_VERSION_STRING``
+ Human-readable string containing the version of OpenAL
+#]=======================================================================]
+
+# For Windows, Creative Labs seems to have added a registry key for their
+# OpenAL 1.1 installer. I have added that key to the list of search paths,
+# however, the key looks like it could be a little fragile depending on
+# if they decide to change the 1.00.0000 number for bug fix releases.
+# Also, they seem to have laid down groundwork for multiple library platforms
+# which puts the library in an extra subdirectory. Currently there is only
+# Win32 and I have hardcoded that here. This may need to be adjusted as
+# platforms are introduced.
+# The OpenAL 1.0 installer doesn't seem to have a useful key I can use.
+# I do not know if the Nvidia OpenAL SDK has a registry key.
+
+find_path(OPENAL_INCLUDE_DIR al.h
+ HINTS
+ ENV OPENALDIR
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /opt
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir]
+ PATH_SUFFIXES include/AL include/OpenAL include AL OpenAL
+ )
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(_OpenAL_ARCH_DIR libs/Win64)
+else()
+ set(_OpenAL_ARCH_DIR libs/Win32)
+endif()
+
+find_library(OPENAL_LIBRARY
+ NAMES OpenAL al openal OpenAL32
+ HINTS
+ ENV OPENALDIR
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /opt
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir]
+ PATH_SUFFIXES libx32 lib64 lib libs64 libs ${_OpenAL_ARCH_DIR}
+ )
+
+unset(_OpenAL_ARCH_DIR)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(
+ OpenAL
+ REQUIRED_VARS OPENAL_LIBRARY OPENAL_INCLUDE_DIR
+ VERSION_VAR OPENAL_VERSION_STRING
+ )
+
+mark_as_advanced(OPENAL_LIBRARY OPENAL_INCLUDE_DIR)
diff --git a/Modules/FindOpenCL.cmake b/Modules/FindOpenCL.cmake
new file mode 100644
index 0000000..1b4662b
--- /dev/null
+++ b/Modules/FindOpenCL.cmake
@@ -0,0 +1,185 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindOpenCL
+----------
+
+.. versionadded:: 3.1
+
+Finds Open Computing Language (OpenCL)
+
+.. versionadded:: 3.10
+ Detection of OpenCL 2.1 and 2.2.
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.7
+
+This module defines :prop_tgt:`IMPORTED` target ``OpenCL::OpenCL``, if
+OpenCL has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables::
+
+ OpenCL_FOUND - True if OpenCL was found
+ OpenCL_INCLUDE_DIRS - include directories for OpenCL
+ OpenCL_LIBRARIES - link against this library to use OpenCL
+ OpenCL_VERSION_STRING - Highest supported OpenCL version (eg. 1.2)
+ OpenCL_VERSION_MAJOR - The major version of the OpenCL implementation
+ OpenCL_VERSION_MINOR - The minor version of the OpenCL implementation
+
+The module will also define two cache variables::
+
+ OpenCL_INCLUDE_DIR - the OpenCL include directory
+ OpenCL_LIBRARY - the path to the OpenCL library
+
+#]=======================================================================]
+
+function(_FIND_OPENCL_VERSION)
+ include(CheckSymbolExists)
+ include(CMakePushCheckState)
+ set(CMAKE_REQUIRED_QUIET ${OpenCL_FIND_QUIETLY})
+
+ CMAKE_PUSH_CHECK_STATE()
+ foreach(VERSION "2_2" "2_1" "2_0" "1_2" "1_1" "1_0")
+ set(CMAKE_REQUIRED_INCLUDES "${OpenCL_INCLUDE_DIR}")
+
+ if(APPLE)
+ CHECK_SYMBOL_EXISTS(
+ CL_VERSION_${VERSION}
+ "${OpenCL_INCLUDE_DIR}/Headers/cl.h"
+ OPENCL_VERSION_${VERSION})
+ else()
+ CHECK_SYMBOL_EXISTS(
+ CL_VERSION_${VERSION}
+ "${OpenCL_INCLUDE_DIR}/CL/cl.h"
+ OPENCL_VERSION_${VERSION})
+ endif()
+
+ if(OPENCL_VERSION_${VERSION})
+ string(REPLACE "_" "." VERSION "${VERSION}")
+ set(OpenCL_VERSION_STRING ${VERSION} PARENT_SCOPE)
+ string(REGEX MATCHALL "[0-9]+" version_components "${VERSION}")
+ list(GET version_components 0 major_version)
+ list(GET version_components 1 minor_version)
+ set(OpenCL_VERSION_MAJOR ${major_version} PARENT_SCOPE)
+ set(OpenCL_VERSION_MINOR ${minor_version} PARENT_SCOPE)
+ break()
+ endif()
+ endforeach()
+ CMAKE_POP_CHECK_STATE()
+endfunction()
+
+find_path(OpenCL_INCLUDE_DIR
+ NAMES
+ CL/cl.h OpenCL/cl.h
+ PATHS
+ ENV "PROGRAMFILES(X86)"
+ ENV AMDAPPSDKROOT
+ ENV INTELOCLSDKROOT
+ ENV NVSDKCOMPUTE_ROOT
+ ENV CUDA_PATH
+ ENV ATISTREAMSDKROOT
+ ENV OCL_ROOT
+ /usr/local/cuda
+ /opt/cuda
+ PATH_SUFFIXES
+ include
+ OpenCL/common/inc
+ "AMD APP/include")
+
+_FIND_OPENCL_VERSION()
+
+if(WIN32)
+ if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ find_library(OpenCL_LIBRARY
+ NAMES OpenCL
+ PATHS
+ ENV "PROGRAMFILES(X86)"
+ ENV AMDAPPSDKROOT
+ ENV INTELOCLSDKROOT
+ ENV CUDA_PATH
+ ENV NVSDKCOMPUTE_ROOT
+ ENV ATISTREAMSDKROOT
+ ENV OCL_ROOT
+ PATH_SUFFIXES
+ "AMD APP/lib/x86"
+ lib/x86
+ lib/Win32
+ OpenCL/common/lib/Win32)
+ elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ find_library(OpenCL_LIBRARY
+ NAMES OpenCL
+ PATHS
+ ENV "PROGRAMFILES(X86)"
+ ENV AMDAPPSDKROOT
+ ENV INTELOCLSDKROOT
+ ENV CUDA_PATH
+ ENV NVSDKCOMPUTE_ROOT
+ ENV ATISTREAMSDKROOT
+ ENV OCL_ROOT
+ PATH_SUFFIXES
+ "AMD APP/lib/x86_64"
+ lib/x86_64
+ lib/x64
+ OpenCL/common/lib/x64)
+ endif()
+else()
+ if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ find_library(OpenCL_LIBRARY
+ NAMES OpenCL
+ PATHS
+ ENV AMDAPPSDKROOT
+ ENV CUDA_PATH
+ /usr/local/cuda
+ /opt/cuda
+ PATH_SUFFIXES
+ lib/x86
+ lib)
+ elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ find_library(OpenCL_LIBRARY
+ NAMES OpenCL
+ PATHS
+ ENV AMDAPPSDKROOT
+ ENV CUDA_PATH
+ /usr/local/cuda
+ /opt/cuda
+ PATH_SUFFIXES
+ lib/x86_64
+ lib/x64
+ lib
+ lib64)
+ endif()
+endif()
+
+set(OpenCL_LIBRARIES ${OpenCL_LIBRARY})
+set(OpenCL_INCLUDE_DIRS ${OpenCL_INCLUDE_DIR})
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(
+ OpenCL
+ FOUND_VAR OpenCL_FOUND
+ REQUIRED_VARS OpenCL_LIBRARY OpenCL_INCLUDE_DIR
+ VERSION_VAR OpenCL_VERSION_STRING)
+
+mark_as_advanced(
+ OpenCL_INCLUDE_DIR
+ OpenCL_LIBRARY)
+
+if(OpenCL_FOUND AND NOT TARGET OpenCL::OpenCL)
+ if(OpenCL_LIBRARY MATCHES "/([^/]+)\\.framework$")
+ add_library(OpenCL::OpenCL INTERFACE IMPORTED)
+ set_target_properties(OpenCL::OpenCL PROPERTIES
+ INTERFACE_LINK_LIBRARIES "${OpenCL_LIBRARY}")
+ else()
+ add_library(OpenCL::OpenCL UNKNOWN IMPORTED)
+ set_target_properties(OpenCL::OpenCL PROPERTIES
+ IMPORTED_LOCATION "${OpenCL_LIBRARY}")
+ endif()
+ set_target_properties(OpenCL::OpenCL PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${OpenCL_INCLUDE_DIRS}")
+endif()
diff --git a/Modules/FindOpenGL.cmake b/Modules/FindOpenGL.cmake
new file mode 100644
index 0000000..d6d1c00
--- /dev/null
+++ b/Modules/FindOpenGL.cmake
@@ -0,0 +1,583 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindOpenGL
+----------
+
+FindModule for OpenGL and OpenGL Utility Library (GLU).
+
+.. versionchanged:: 3.2
+ X11 is no longer added as a dependency on Unix/Linux systems.
+
+.. versionadded:: 3.10
+ GLVND support on Linux. See the :ref:`Linux Specific` section below.
+
+Optional COMPONENTS
+^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.10
+
+This module respects several optional COMPONENTS: ``EGL``, ``GLX``, and
+``OpenGL``. There are corresponding import targets for each of these flags.
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.8
+
+This module defines the :prop_tgt:`IMPORTED` targets:
+
+``OpenGL::GL``
+ Defined to the platform-specific OpenGL libraries if the system has OpenGL.
+``OpenGL::GLU``
+ Defined if the system has OpenGL Utility Library (GLU).
+
+.. versionadded:: 3.10
+ Additionally, the following GLVND-specific library targets are defined:
+
+``OpenGL::OpenGL``
+ Defined to libOpenGL if the system is GLVND-based.
+``OpenGL::GLX``
+ Defined if the system has OpenGL Extension to the X Window System (GLX).
+``OpenGL::EGL``
+ Defined if the system has EGL.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module sets the following variables:
+
+``OPENGL_FOUND``
+ True, if the system has OpenGL and all components are found.
+``OPENGL_XMESA_FOUND``
+ True, if the system has XMESA.
+``OPENGL_GLU_FOUND``
+ True, if the system has GLU.
+``OpenGL_OpenGL_FOUND``
+ True, if the system has an OpenGL library.
+``OpenGL_GLX_FOUND``
+ True, if the system has GLX.
+``OpenGL_EGL_FOUND``
+ True, if the system has EGL.
+``OPENGL_INCLUDE_DIR``
+ Path to the OpenGL include directory.
+``OPENGL_EGL_INCLUDE_DIRS``
+ Path to the EGL include directory.
+``OPENGL_LIBRARIES``
+ Paths to the OpenGL library, windowing system libraries, and GLU libraries.
+ On Linux, this assumes GLX and is never correct for EGL-based targets.
+ Clients are encouraged to use the ``OpenGL::*`` import targets instead.
+
+.. versionadded:: 3.10
+ Variables for GLVND-specific libraries ``OpenGL``, ``EGL`` and ``GLX``.
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``OPENGL_egl_LIBRARY``
+ Path to the EGL library.
+``OPENGL_glu_LIBRARY``
+ Path to the GLU library.
+``OPENGL_glx_LIBRARY``
+ Path to the GLVND 'GLX' library.
+``OPENGL_opengl_LIBRARY``
+ Path to the GLVND 'OpenGL' library
+``OPENGL_gl_LIBRARY``
+ Path to the OpenGL library. New code should prefer the ``OpenGL::*`` import
+ targets.
+
+.. versionadded:: 3.10
+ Variables for GLVND-specific libraries ``OpenGL``, ``EGL`` and ``GLX``.
+
+.. _`Linux Specific`:
+
+Linux-specific
+^^^^^^^^^^^^^^
+
+Some Linux systems utilize GLVND as a new ABI for OpenGL. GLVND separates
+context libraries from OpenGL itself; OpenGL lives in "libOpenGL", and
+contexts are defined in "libGLX" or "libEGL". GLVND is currently the only way
+to get OpenGL 3+ functionality via EGL in a manner portable across vendors.
+Projects may use GLVND explicitly with target ``OpenGL::OpenGL`` and either
+``OpenGL::GLX`` or ``OpenGL::EGL``.
+
+Projects may use the ``OpenGL::GL`` target (or ``OPENGL_LIBRARIES`` variable)
+to use legacy GL interfaces. These will use the legacy GL library located
+by ``OPENGL_gl_LIBRARY``, if available. If ``OPENGL_gl_LIBRARY`` is empty or
+not found and GLVND is available, the ``OpenGL::GL`` target will use GLVND
+``OpenGL::OpenGL`` and ``OpenGL::GLX`` (and the ``OPENGL_LIBRARIES``
+variable will use the corresponding libraries). Thus, for non-EGL-based
+Linux targets, the ``OpenGL::GL`` target is most portable.
+
+A ``OpenGL_GL_PREFERENCE`` variable may be set to specify the preferred way
+to provide legacy GL interfaces in case multiple choices are available.
+The value may be one of:
+
+``GLVND``
+ If the GLVND OpenGL and GLX libraries are available, prefer them.
+ This forces ``OPENGL_gl_LIBRARY`` to be empty.
+
+ .. versionchanged:: 3.11
+ This is the default, unless policy :policy:`CMP0072` is set to ``OLD``
+ and no components are requeted (since components
+ correspond to GLVND libraries).
+
+``LEGACY``
+ Prefer to use the legacy libGL library, if available.
+
+For EGL targets the client must rely on GLVND support on the user's system.
+Linking should use the ``OpenGL::OpenGL OpenGL::EGL`` targets. Using GLES*
+libraries is theoretically possible in place of ``OpenGL::OpenGL``, but this
+module does not currently support that; contributions welcome.
+
+``OPENGL_egl_LIBRARY`` and ``OPENGL_EGL_INCLUDE_DIRS`` are defined in the case of
+GLVND. For non-GLVND Linux and other systems these are left undefined.
+
+macOS-Specific
+^^^^^^^^^^^^^^
+
+On OSX FindOpenGL defaults to using the framework version of OpenGL. People
+will have to change the cache values of OPENGL_glu_LIBRARY and
+OPENGL_gl_LIBRARY to use OpenGL with X11 on OSX.
+#]=======================================================================]
+
+set(_OpenGL_REQUIRED_VARS OPENGL_gl_LIBRARY)
+
+# Provide OPENGL_USE_<C> variables for each component.
+foreach(component ${OpenGL_FIND_COMPONENTS})
+ string(TOUPPER ${component} _COMPONENT)
+ set(OPENGL_USE_${_COMPONENT} 1)
+endforeach()
+
+set(_OpenGL_CACHE_VARS)
+
+if (WIN32)
+
+ if(BORLAND)
+ set (OPENGL_gl_LIBRARY import32 CACHE STRING "OpenGL library for win32")
+ set (OPENGL_glu_LIBRARY import32 CACHE STRING "GLU library for win32")
+ else()
+ set (OPENGL_gl_LIBRARY opengl32 CACHE STRING "OpenGL library for win32")
+ set (OPENGL_glu_LIBRARY glu32 CACHE STRING "GLU library for win32")
+ endif()
+
+ list(APPEND _OpenGL_CACHE_VARS
+ OPENGL_gl_LIBRARY
+ OPENGL_glu_LIBRARY
+ )
+elseif (APPLE)
+ # The OpenGL.framework provides both gl and glu
+ find_library(OPENGL_gl_LIBRARY OpenGL DOC "OpenGL library for OS X")
+ find_library(OPENGL_glu_LIBRARY OpenGL DOC
+ "GLU library for OS X (usually same as OpenGL library)")
+ find_path(OPENGL_INCLUDE_DIR OpenGL/gl.h DOC "Include for OpenGL on OS X")
+ list(APPEND _OpenGL_REQUIRED_VARS OPENGL_INCLUDE_DIR)
+
+ list(APPEND _OpenGL_CACHE_VARS
+ OPENGL_INCLUDE_DIR
+ OPENGL_gl_LIBRARY
+ OPENGL_glu_LIBRARY
+ )
+else()
+ if (CMAKE_SYSTEM_NAME MATCHES "HP-UX")
+ # Handle HP-UX cases where we only want to find OpenGL in either hpux64
+ # or hpux32 depending on if we're doing a 64 bit build.
+ if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(_OPENGL_LIB_PATH
+ /opt/graphics/OpenGL/lib/hpux32/)
+ else()
+ set(_OPENGL_LIB_PATH
+ /opt/graphics/OpenGL/lib/hpux64/
+ /opt/graphics/OpenGL/lib/pa20_64)
+ endif()
+ elseif(CMAKE_SYSTEM_NAME STREQUAL Haiku)
+ set(_OPENGL_LIB_PATH
+ /boot/develop/lib/x86)
+ set(_OPENGL_INCLUDE_PATH
+ /boot/develop/headers/os/opengl)
+ endif()
+
+ # The first line below is to make sure that the proper headers
+ # are used on a Linux machine with the NVidia drivers installed.
+ # They replace Mesa with NVidia's own library but normally do not
+ # install headers and that causes the linking to
+ # fail since the compiler finds the Mesa headers but NVidia's library.
+ # Make sure the NVIDIA directory comes BEFORE the others.
+ # - Atanas Georgiev <atanas@cs.columbia.edu>
+ find_path(OPENGL_INCLUDE_DIR GL/gl.h
+ /usr/share/doc/NVIDIA_GLX-1.0/include
+ /usr/openwin/share/include
+ /opt/graphics/OpenGL/include
+ ${_OPENGL_INCLUDE_PATH}
+ )
+ find_path(OPENGL_GLX_INCLUDE_DIR GL/glx.h ${_OPENGL_INCLUDE_PATH})
+ find_path(OPENGL_EGL_INCLUDE_DIR EGL/egl.h ${_OPENGL_INCLUDE_PATH})
+ find_path(OPENGL_xmesa_INCLUDE_DIR GL/xmesa.h
+ /usr/share/doc/NVIDIA_GLX-1.0/include
+ /usr/openwin/share/include
+ /opt/graphics/OpenGL/include
+ )
+ list(APPEND _OpenGL_CACHE_VARS
+ OPENGL_INCLUDE_DIR
+ OPENGL_GLX_INCLUDE_DIR
+ OPENGL_EGL_INCLUDE_DIR
+ OPENGL_xmesa_INCLUDE_DIR
+ )
+
+ # Search for the GLVND libraries. We do this regardless of COMPONENTS; we'll
+ # take into account the COMPONENTS logic later.
+ find_library(OPENGL_opengl_LIBRARY
+ NAMES OpenGL
+ PATHS ${_OPENGL_LIB_PATH}
+ )
+
+ find_library(OPENGL_glx_LIBRARY
+ NAMES GLX
+ PATHS ${_OPENGL_LIB_PATH}
+ PATH_SUFFIXES libglvnd
+ )
+
+ find_library(OPENGL_egl_LIBRARY
+ NAMES EGL
+ PATHS ${_OPENGL_LIB_PATH}
+ PATH_SUFFIXES libglvnd
+ )
+
+ find_library(OPENGL_glu_LIBRARY
+ NAMES GLU MesaGLU
+ PATHS ${OPENGL_gl_LIBRARY}
+ /opt/graphics/OpenGL/lib
+ /usr/openwin/lib
+ /usr/shlib
+ )
+
+ list(APPEND _OpenGL_CACHE_VARS
+ OPENGL_opengl_LIBRARY
+ OPENGL_glx_LIBRARY
+ OPENGL_egl_LIBRARY
+ OPENGL_glu_LIBRARY
+ )
+
+ set(_OpenGL_GL_POLICY_WARN 0)
+ if(NOT DEFINED OpenGL_GL_PREFERENCE)
+ set(OpenGL_GL_PREFERENCE "")
+ endif()
+ if(NOT OpenGL_GL_PREFERENCE STREQUAL "")
+ # A preference has been explicitly specified.
+ if(NOT OpenGL_GL_PREFERENCE MATCHES "^(GLVND|LEGACY)$")
+ message(FATAL_ERROR
+ "OpenGL_GL_PREFERENCE value '${OpenGL_GL_PREFERENCE}' not recognized. "
+ "Allowed values are 'GLVND' and 'LEGACY'."
+ )
+ endif()
+ elseif(OpenGL_FIND_COMPONENTS)
+ # No preference was explicitly specified, but the caller did request
+ # at least one GLVND component. Prefer GLVND for legacy GL.
+ set(OpenGL_GL_PREFERENCE "GLVND")
+ else()
+ # No preference was explicitly specified and no GLVND components were
+ # requested. Use a policy to choose the default.
+ cmake_policy(GET CMP0072 _OpenGL_GL_POLICY)
+ if("x${_OpenGL_GL_POLICY}x" STREQUAL "xNEWx")
+ set(OpenGL_GL_PREFERENCE "GLVND")
+ else()
+ set(OpenGL_GL_PREFERENCE "LEGACY")
+ if("x${_OpenGL_GL_POLICY}x" STREQUAL "xx")
+ set(_OpenGL_GL_POLICY_WARN 1)
+ endif()
+ endif()
+ unset(_OpenGL_GL_POLICY)
+ endif()
+
+ if("x${OpenGL_GL_PREFERENCE}x" STREQUAL "xGLVNDx" AND OPENGL_opengl_LIBRARY AND OPENGL_glx_LIBRARY)
+ # We can provide legacy GL using GLVND libraries.
+ # Do not use any legacy GL library.
+ set(OPENGL_gl_LIBRARY "")
+ else()
+ # We cannot provide legacy GL using GLVND libraries.
+ # Search for the legacy GL library.
+ find_library(OPENGL_gl_LIBRARY
+ NAMES GL MesaGL
+ PATHS /opt/graphics/OpenGL/lib
+ /usr/openwin/lib
+ /usr/shlib
+ ${_OPENGL_LIB_PATH}
+ PATH_SUFFIXES libglvnd
+ )
+ list(APPEND _OpenGL_CACHE_VARS OPENGL_gl_LIBRARY)
+ endif()
+
+ if(_OpenGL_GL_POLICY_WARN AND OPENGL_gl_LIBRARY AND OPENGL_opengl_LIBRARY AND OPENGL_glx_LIBRARY)
+ cmake_policy(GET_WARNING CMP0072 _cmp0072_warning)
+ message(AUTHOR_WARNING
+ "${_cmp0072_warning}\n"
+ "FindOpenGL found both a legacy GL library:\n"
+ " OPENGL_gl_LIBRARY: ${OPENGL_gl_LIBRARY}\n"
+ "and GLVND libraries for OpenGL and GLX:\n"
+ " OPENGL_opengl_LIBRARY: ${OPENGL_opengl_LIBRARY}\n"
+ " OPENGL_glx_LIBRARY: ${OPENGL_glx_LIBRARY}\n"
+ "OpenGL_GL_PREFERENCE has not been set to \"GLVND\" or \"LEGACY\", so for "
+ "compatibility with CMake 3.10 and below the legacy GL library will be used."
+ )
+ endif()
+ unset(_OpenGL_GL_POLICY_WARN)
+
+ # FPHSA cannot handle "this OR that is required", so we conditionally set what
+ # it must look for. First clear any previous config we might have done:
+ set(_OpenGL_REQUIRED_VARS)
+
+ # now we append the libraries as appropriate. The complicated logic
+ # basically comes down to "use libOpenGL when we can, and add in specific
+ # context mechanisms when requested, or we need them to preserve the previous
+ # default where glx is always available."
+ if((NOT OPENGL_USE_EGL AND
+ NOT OPENGL_opengl_LIBRARY AND
+ OPENGL_glx_LIBRARY AND
+ NOT OPENGL_gl_LIBRARY) OR
+ (NOT OPENGL_USE_EGL AND
+ NOT OPENGL_glx_LIBRARY AND
+ NOT OPENGL_gl_LIBRARY) OR
+ (NOT OPENGL_USE_EGL AND
+ OPENGL_opengl_LIBRARY AND
+ OPENGL_glx_LIBRARY) OR
+ ( OPENGL_USE_EGL))
+ list(APPEND _OpenGL_REQUIRED_VARS OPENGL_opengl_LIBRARY)
+ endif()
+
+ # GLVND GLX library. Preferred when available.
+ if((NOT OPENGL_USE_OPENGL AND
+ NOT OPENGL_USE_GLX AND
+ NOT OPENGL_USE_EGL AND
+ NOT OPENGL_glx_LIBRARY AND
+ NOT OPENGL_gl_LIBRARY) OR
+ ( OPENGL_USE_GLX AND
+ NOT OPENGL_USE_EGL AND
+ NOT OPENGL_glx_LIBRARY AND
+ NOT OPENGL_gl_LIBRARY) OR
+ (NOT OPENGL_USE_EGL AND
+ OPENGL_opengl_LIBRARY AND
+ OPENGL_glx_LIBRARY) OR
+ (OPENGL_USE_GLX AND OPENGL_USE_EGL))
+ list(APPEND _OpenGL_REQUIRED_VARS OPENGL_glx_LIBRARY)
+ endif()
+
+ # GLVND EGL library.
+ if(OPENGL_USE_EGL)
+ list(APPEND _OpenGL_REQUIRED_VARS OPENGL_egl_LIBRARY)
+ endif()
+
+ # Old-style "libGL" library: used as a fallback when GLVND isn't available.
+ if((NOT OPENGL_USE_EGL AND
+ NOT OPENGL_opengl_LIBRARY AND
+ OPENGL_glx_LIBRARY AND
+ OPENGL_gl_LIBRARY) OR
+ (NOT OPENGL_USE_EGL AND
+ NOT OPENGL_glx_LIBRARY AND
+ OPENGL_gl_LIBRARY))
+ list(APPEND _OpenGL_REQUIRED_VARS OPENGL_gl_LIBRARY)
+ endif()
+
+ # We always need the 'gl.h' include dir.
+ list(APPEND _OpenGL_REQUIRED_VARS OPENGL_INCLUDE_DIR)
+
+ unset(_OPENGL_INCLUDE_PATH)
+ unset(_OPENGL_LIB_PATH)
+
+ find_library(OPENGL_glu_LIBRARY
+ NAMES GLU MesaGLU
+ PATHS ${OPENGL_gl_LIBRARY}
+ /opt/graphics/OpenGL/lib
+ /usr/openwin/lib
+ /usr/shlib
+ )
+endif ()
+
+if(OPENGL_xmesa_INCLUDE_DIR)
+ set( OPENGL_XMESA_FOUND "YES" )
+else()
+ set( OPENGL_XMESA_FOUND "NO" )
+endif()
+
+if(OPENGL_glu_LIBRARY)
+ set( OPENGL_GLU_FOUND "YES" )
+else()
+ set( OPENGL_GLU_FOUND "NO" )
+endif()
+
+# OpenGL_OpenGL_FOUND is a bit unique in that it is okay if /either/ libOpenGL
+# or libGL is found.
+# Using libGL with libEGL is never okay, though; we handle that case later.
+if(NOT OPENGL_opengl_LIBRARY AND NOT OPENGL_gl_LIBRARY)
+ set(OpenGL_OpenGL_FOUND FALSE)
+else()
+ set(OpenGL_OpenGL_FOUND TRUE)
+endif()
+
+if(OPENGL_glx_LIBRARY AND OPENGL_GLX_INCLUDE_DIR)
+ set(OpenGL_GLX_FOUND TRUE)
+else()
+ set(OpenGL_GLX_FOUND FALSE)
+endif()
+
+if(OPENGL_egl_LIBRARY AND OPENGL_EGL_INCLUDE_DIR)
+ set(OpenGL_EGL_FOUND TRUE)
+else()
+ set(OpenGL_EGL_FOUND FALSE)
+endif()
+
+# User-visible names should be plural.
+if(OPENGL_EGL_INCLUDE_DIR)
+ set(OPENGL_EGL_INCLUDE_DIRS ${OPENGL_EGL_INCLUDE_DIR})
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+if (CMAKE_FIND_PACKAGE_NAME STREQUAL "GLU")
+ # FindGLU include()'s this module. It's an old pattern, but rather than
+ # trying to suppress this from outside the module (which is then sensitive to
+ # the contents, detect the case in this module and suppress it explicitly.
+ set(FPHSA_NAME_MISMATCHED 1)
+endif ()
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenGL REQUIRED_VARS ${_OpenGL_REQUIRED_VARS}
+ HANDLE_COMPONENTS)
+unset(FPHSA_NAME_MISMATCHED)
+unset(_OpenGL_REQUIRED_VARS)
+
+# OpenGL:: targets
+if(OPENGL_FOUND)
+ # ::OpenGL is a GLVND library, and thus Linux-only: we don't bother checking
+ # for a framework version of this library.
+ if(OPENGL_opengl_LIBRARY AND NOT TARGET OpenGL::OpenGL)
+ if(IS_ABSOLUTE "${OPENGL_opengl_LIBRARY}")
+ add_library(OpenGL::OpenGL UNKNOWN IMPORTED)
+ set_target_properties(OpenGL::OpenGL PROPERTIES IMPORTED_LOCATION
+ "${OPENGL_opengl_LIBRARY}")
+ else()
+ add_library(OpenGL::OpenGL INTERFACE IMPORTED)
+ set_target_properties(OpenGL::OpenGL PROPERTIES IMPORTED_LIBNAME
+ "${OPENGL_opengl_LIBRARY}")
+ endif()
+ set_target_properties(OpenGL::OpenGL PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
+ "${OPENGL_INCLUDE_DIR}")
+ endif()
+
+ # ::GLX is a GLVND library, and thus Linux-only: we don't bother checking
+ # for a framework version of this library.
+ if(OpenGL_GLX_FOUND AND NOT TARGET OpenGL::GLX AND TARGET OpenGL::OpenGL)
+ if(IS_ABSOLUTE "${OPENGL_glx_LIBRARY}")
+ add_library(OpenGL::GLX UNKNOWN IMPORTED)
+ set_target_properties(OpenGL::GLX PROPERTIES IMPORTED_LOCATION
+ "${OPENGL_glx_LIBRARY}")
+ else()
+ add_library(OpenGL::GLX INTERFACE IMPORTED)
+ set_target_properties(OpenGL::GLX PROPERTIES IMPORTED_LIBNAME
+ "${OPENGL_glx_LIBRARY}")
+ endif()
+ set_target_properties(OpenGL::GLX PROPERTIES INTERFACE_LINK_LIBRARIES
+ OpenGL::OpenGL)
+ set_target_properties(OpenGL::GLX PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
+ "${OPENGL_GLX_INCLUDE_DIR}")
+ endif()
+
+ if(OPENGL_gl_LIBRARY AND NOT TARGET OpenGL::GL)
+ # A legacy GL library is available, so use it for the legacy GL target.
+ if(IS_ABSOLUTE "${OPENGL_gl_LIBRARY}")
+ add_library(OpenGL::GL UNKNOWN IMPORTED)
+ if(OPENGL_gl_LIBRARY MATCHES "/([^/]+)\\.framework$")
+ set(_gl_fw "${OPENGL_gl_LIBRARY}/${CMAKE_MATCH_1}")
+ if(EXISTS "${_gl_fw}.tbd")
+ string(APPEND _gl_fw ".tbd")
+ endif()
+ set_target_properties(OpenGL::GL PROPERTIES
+ IMPORTED_LOCATION "${_gl_fw}")
+ else()
+ set_target_properties(OpenGL::GL PROPERTIES
+ IMPORTED_LOCATION "${OPENGL_gl_LIBRARY}")
+ endif()
+ else()
+ add_library(OpenGL::GL INTERFACE IMPORTED)
+ set_target_properties(OpenGL::GL PROPERTIES
+ IMPORTED_LIBNAME "${OPENGL_gl_LIBRARY}")
+ endif()
+ set_target_properties(OpenGL::GL PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${OPENGL_INCLUDE_DIR}")
+ elseif(NOT TARGET OpenGL::GL AND TARGET OpenGL::OpenGL AND TARGET OpenGL::GLX)
+ # A legacy GL library is not available, but we can provide the legacy GL
+ # target using GLVND OpenGL+GLX.
+ add_library(OpenGL::GL INTERFACE IMPORTED)
+ set_target_properties(OpenGL::GL PROPERTIES INTERFACE_LINK_LIBRARIES
+ OpenGL::OpenGL)
+ set_property(TARGET OpenGL::GL APPEND PROPERTY INTERFACE_LINK_LIBRARIES
+ OpenGL::GLX)
+ set_target_properties(OpenGL::GL PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
+ "${OPENGL_INCLUDE_DIR}")
+ endif()
+
+ # ::EGL is a GLVND library, and thus Linux-only: we don't bother checking
+ # for a framework version of this library.
+ # Note we test for OpenGL::OpenGL as a target. When this module is updated to
+ # support GLES, we would additionally want to check for the hypothetical GLES
+ # target and enable EGL if either ::GLES or ::OpenGL is created.
+ if(TARGET OpenGL::OpenGL AND OpenGL_EGL_FOUND AND NOT TARGET OpenGL::EGL)
+ if(IS_ABSOLUTE "${OPENGL_egl_LIBRARY}")
+ add_library(OpenGL::EGL UNKNOWN IMPORTED)
+ set_target_properties(OpenGL::EGL PROPERTIES IMPORTED_LOCATION
+ "${OPENGL_egl_LIBRARY}")
+ else()
+ add_library(OpenGL::EGL INTERFACE IMPORTED)
+ set_target_properties(OpenGL::EGL PROPERTIES IMPORTED_LIBNAME
+ "${OPENGL_egl_LIBRARY}")
+ endif()
+ set_target_properties(OpenGL::EGL PROPERTIES INTERFACE_LINK_LIBRARIES
+ OpenGL::OpenGL)
+ # Note that EGL's include directory is different from OpenGL/GLX's!
+ set_target_properties(OpenGL::EGL PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
+ "${OPENGL_EGL_INCLUDE_DIR}")
+ endif()
+
+ if(OPENGL_GLU_FOUND AND NOT TARGET OpenGL::GLU)
+ if(IS_ABSOLUTE "${OPENGL_glu_LIBRARY}")
+ add_library(OpenGL::GLU UNKNOWN IMPORTED)
+ if(OPENGL_glu_LIBRARY MATCHES "/([^/]+)\\.framework$")
+ set(_glu_fw "${OPENGL_glu_LIBRARY}/${CMAKE_MATCH_1}")
+ if(EXISTS "${_glu_fw}.tbd")
+ string(APPEND _glu_fw ".tbd")
+ endif()
+ set_target_properties(OpenGL::GLU PROPERTIES
+ IMPORTED_LOCATION "${_glu_fw}")
+ else()
+ set_target_properties(OpenGL::GLU PROPERTIES
+ IMPORTED_LOCATION "${OPENGL_glu_LIBRARY}")
+ endif()
+ else()
+ add_library(OpenGL::GLU INTERFACE IMPORTED)
+ set_target_properties(OpenGL::GLU PROPERTIES
+ IMPORTED_LIBNAME "${OPENGL_glu_LIBRARY}")
+ endif()
+ set_target_properties(OpenGL::GLU PROPERTIES
+ INTERFACE_LINK_LIBRARIES OpenGL::GL)
+ endif()
+
+ # OPENGL_LIBRARIES mirrors OpenGL::GL's logic ...
+ if(OPENGL_gl_LIBRARY)
+ set(OPENGL_LIBRARIES ${OPENGL_gl_LIBRARY})
+ elseif(TARGET OpenGL::OpenGL AND TARGET OpenGL::GLX)
+ set(OPENGL_LIBRARIES ${OPENGL_opengl_LIBRARY} ${OPENGL_glx_LIBRARY})
+ else()
+ set(OPENGL_LIBRARIES "")
+ endif()
+ # ... and also includes GLU, if available.
+ if(TARGET OpenGL::GLU)
+ list(APPEND OPENGL_LIBRARIES ${OPENGL_glu_LIBRARY})
+ endif()
+endif()
+
+# This deprecated setting is for backward compatibility with CMake1.4
+set(OPENGL_LIBRARY ${OPENGL_LIBRARIES})
+# This deprecated setting is for backward compatibility with CMake1.4
+set(OPENGL_INCLUDE_PATH ${OPENGL_INCLUDE_DIR})
+
+mark_as_advanced(${_OpenGL_CACHE_VARS})
+unset(_OpenGL_CACHE_VARS)
diff --git a/Modules/FindOpenMP.cmake b/Modules/FindOpenMP.cmake
new file mode 100644
index 0000000..e982e2d
--- /dev/null
+++ b/Modules/FindOpenMP.cmake
@@ -0,0 +1,620 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindOpenMP
+----------
+
+Finds Open Multi-Processing (OpenMP) support.
+
+This module can be used to detect OpenMP support in a compiler. If
+the compiler supports OpenMP, the flags required to compile with
+OpenMP support are returned in variables for the different languages.
+The variables may be empty if the compiler does not need a special
+flag to support OpenMP.
+
+.. versionadded:: 3.5
+ Clang support.
+
+Variables
+^^^^^^^^^
+
+.. versionadded:: 3.10
+ The module exposes the components ``C``, ``CXX``, and ``Fortran``.
+ Each of these controls the various languages to search OpenMP support for.
+
+Depending on the enabled components the following variables will be set:
+
+``OpenMP_FOUND``
+ Variable indicating that OpenMP flags for all requested languages have been found.
+ If no components are specified, this is true if OpenMP settings for all enabled languages
+ were detected.
+``OpenMP_VERSION``
+ Minimal version of the OpenMP standard detected among the requested languages,
+ or all enabled languages if no components were specified.
+
+This module will set the following variables per language in your
+project, where ``<lang>`` is one of C, CXX, or Fortran:
+
+``OpenMP_<lang>_FOUND``
+ Variable indicating if OpenMP support for ``<lang>`` was detected.
+``OpenMP_<lang>_FLAGS``
+ OpenMP compiler flags for ``<lang>``, separated by spaces.
+``OpenMP_<lang>_INCLUDE_DIRS``
+ Directories that must be added to the header search path for ``<lang>``
+ when using OpenMP.
+
+For linking with OpenMP code written in ``<lang>``, the following
+variables are provided:
+
+``OpenMP_<lang>_LIB_NAMES``
+ :ref:`;-list <CMake Language Lists>` of libraries for OpenMP programs for ``<lang>``.
+``OpenMP_<libname>_LIBRARY``
+ Location of the individual libraries needed for OpenMP support in ``<lang>``.
+``OpenMP_<lang>_LIBRARIES``
+ A list of libraries needed to link with OpenMP code written in ``<lang>``.
+
+Additionally, the module provides :prop_tgt:`IMPORTED` targets:
+
+``OpenMP::OpenMP_<lang>``
+ Target for using OpenMP from ``<lang>``.
+
+Specifically for Fortran, the module sets the following variables:
+
+``OpenMP_Fortran_HAVE_OMPLIB_HEADER``
+ Boolean indicating if OpenMP is accessible through ``omp_lib.h``.
+``OpenMP_Fortran_HAVE_OMPLIB_MODULE``
+ Boolean indicating if OpenMP is accessible through the ``omp_lib`` Fortran module.
+
+The module will also try to provide the OpenMP version variables:
+
+``OpenMP_<lang>_SPEC_DATE``
+ .. versionadded:: 3.7
+
+ Date of the OpenMP specification implemented by the ``<lang>`` compiler.
+``OpenMP_<lang>_VERSION_MAJOR``
+ Major version of OpenMP implemented by the ``<lang>`` compiler.
+``OpenMP_<lang>_VERSION_MINOR``
+ Minor version of OpenMP implemented by the ``<lang>`` compiler.
+``OpenMP_<lang>_VERSION``
+ OpenMP version implemented by the ``<lang>`` compiler.
+
+The specification date is formatted as given in the OpenMP standard:
+``yyyymm`` where ``yyyy`` and ``mm`` represents the year and month of
+the OpenMP specification implemented by the ``<lang>`` compiler.
+
+For some compilers, it may be necessary to add a header search path to find
+the relevant OpenMP headers. This location may be language-specific. Where
+this is needed, the module may attempt to find the location, but it can be
+provided directly by setting the ``OpenMP_<lang>_INCLUDE_DIR`` cache variable.
+Note that this variable is an _input_ control to the module. Project code
+should use the ``OpenMP_<lang>_INCLUDE_DIRS`` _output_ variable if it needs
+to know what include directories are needed.
+#]=======================================================================]
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0012 NEW) # if() recognizes numbers and booleans
+cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+function(_OPENMP_FLAG_CANDIDATES LANG)
+ if(NOT OpenMP_${LANG}_FLAG)
+ unset(OpenMP_FLAG_CANDIDATES)
+
+ set(OMP_FLAG_GNU "-fopenmp")
+ set(OMP_FLAG_Clang "-fopenmp=libomp" "-fopenmp=libiomp5" "-fopenmp" "-Xclang -fopenmp")
+ set(OMP_FLAG_AppleClang "-Xclang -fopenmp")
+ set(OMP_FLAG_HP "+Oopenmp")
+ if(WIN32)
+ set(OMP_FLAG_Intel "-Qopenmp")
+ elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "Intel" AND
+ "${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS "15.0.0.20140528")
+ set(OMP_FLAG_Intel "-openmp")
+ else()
+ set(OMP_FLAG_Intel "-qopenmp")
+ endif()
+ if(CMAKE_${LANG}_COMPILER_ID STREQUAL "IntelLLVM" AND
+ "x${CMAKE_${LANG}_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+ set(OMP_FLAG_IntelLLVM "-Qiopenmp")
+ else()
+ set(OMP_FLAG_IntelLLVM "-fiopenmp")
+ endif()
+ set(OMP_FLAG_MSVC "-openmp")
+ set(OMP_FLAG_PathScale "-openmp")
+ set(OMP_FLAG_NAG "-openmp")
+ set(OMP_FLAG_Absoft "-openmp")
+ set(OMP_FLAG_NVHPC "-mp")
+ set(OMP_FLAG_PGI "-mp")
+ set(OMP_FLAG_Flang "-fopenmp")
+ set(OMP_FLAG_SunPro "-xopenmp")
+ set(OMP_FLAG_XL "-qsmp=omp")
+ # Cray compiler activate OpenMP with -h omp, which is enabled by default.
+ set(OMP_FLAG_Cray " " "-h omp")
+ set(OMP_FLAG_Fujitsu "-Kopenmp" "-KOMP")
+ set(OMP_FLAG_FujitsuClang "-fopenmp" "-Kopenmp")
+
+ # If we know the correct flags, use those
+ if(DEFINED OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID})
+ set(OpenMP_FLAG_CANDIDATES "${OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID}}")
+ # Fall back to reasonable default tries otherwise
+ else()
+ set(OpenMP_FLAG_CANDIDATES "-openmp" "-fopenmp" "-mp" " ")
+ endif()
+ set(OpenMP_${LANG}_FLAG_CANDIDATES "${OpenMP_FLAG_CANDIDATES}" PARENT_SCOPE)
+ else()
+ set(OpenMP_${LANG}_FLAG_CANDIDATES "${OpenMP_${LANG}_FLAG}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# sample openmp source code to test
+set(OpenMP_C_CXX_TEST_SOURCE
+"
+#include <omp.h>
+int main(void) {
+#ifdef _OPENMP
+ omp_get_max_threads();
+ return 0;
+#elif defined(__HIP_DEVICE_COMPILE__)
+ return 0;
+#else
+ breaks_on_purpose
+#endif
+}
+")
+
+# in Fortran, an implementation may provide an omp_lib.h header
+# or omp_lib module, or both (OpenMP standard, section 3.1)
+# Furthmore !$ is the Fortran equivalent of #ifdef _OPENMP (OpenMP standard, 2.2.2)
+# Without the conditional compilation, some compilers (e.g. PGI) might compile OpenMP code
+# while not actually enabling OpenMP, building code sequentially
+set(OpenMP_Fortran_TEST_SOURCE
+ "
+ program test
+ @OpenMP_Fortran_INCLUDE_LINE@
+ !$ integer :: n
+ n = omp_get_num_threads()
+ end program test
+ "
+)
+
+function(_OPENMP_WRITE_SOURCE_FILE LANG SRC_FILE_CONTENT_VAR SRC_FILE_NAME SRC_FILE_FULLPATH)
+ set(WORK_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenMP)
+ if("${LANG}" STREQUAL "C")
+ set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.c")
+ file(WRITE "${SRC_FILE}" "${OpenMP_C_CXX_${SRC_FILE_CONTENT_VAR}}")
+ elseif("${LANG}" STREQUAL "CXX")
+ set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.cpp")
+ file(WRITE "${SRC_FILE}" "${OpenMP_C_CXX_${SRC_FILE_CONTENT_VAR}}")
+ elseif("${LANG}" STREQUAL "Fortran")
+ set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.f90")
+ file(WRITE "${SRC_FILE}_in" "${OpenMP_Fortran_${SRC_FILE_CONTENT_VAR}}")
+ configure_file("${SRC_FILE}_in" "${SRC_FILE}" @ONLY)
+ endif()
+ set(${SRC_FILE_FULLPATH} "${SRC_FILE}" PARENT_SCOPE)
+endfunction()
+
+include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseImplicitLinkInfo.cmake)
+
+function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
+ _OPENMP_FLAG_CANDIDATES("${LANG}")
+ _OPENMP_WRITE_SOURCE_FILE("${LANG}" "TEST_SOURCE" OpenMPTryFlag _OPENMP_TEST_SRC)
+
+ unset(OpenMP_VERBOSE_COMPILE_OPTIONS)
+ separate_arguments(OpenMP_VERBOSE_OPTIONS NATIVE_COMMAND "${CMAKE_${LANG}_VERBOSE_FLAG}")
+ foreach(_VERBOSE_OPTION IN LISTS OpenMP_VERBOSE_OPTIONS)
+ if(NOT _VERBOSE_OPTION MATCHES "^-Wl,")
+ list(APPEND OpenMP_VERBOSE_COMPILE_OPTIONS ${_VERBOSE_OPTION})
+ endif()
+ endforeach()
+
+ foreach(OPENMP_FLAG IN LISTS OpenMP_${LANG}_FLAG_CANDIDATES)
+ set(OPENMP_FLAGS_TEST "${OPENMP_FLAG}")
+ if(OpenMP_VERBOSE_COMPILE_OPTIONS)
+ string(APPEND OPENMP_FLAGS_TEST " ${OpenMP_VERBOSE_COMPILE_OPTIONS}")
+ endif()
+ string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}")
+ try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
+ CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
+ LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG}
+ OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
+ )
+
+ if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
+ set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
+
+ if(CMAKE_${LANG}_VERBOSE_FLAG)
+ unset(OpenMP_${LANG}_IMPLICIT_LIBRARIES)
+ unset(OpenMP_${LANG}_IMPLICIT_LINK_DIRS)
+ unset(OpenMP_${LANG}_IMPLICIT_FWK_DIRS)
+ unset(OpenMP_${LANG}_LOG_VAR)
+
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Detecting ${LANG} OpenMP compiler ABI info compiled with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
+
+ cmake_parse_implicit_link_info("${OpenMP_TRY_COMPILE_OUTPUT}"
+ OpenMP_${LANG}_IMPLICIT_LIBRARIES
+ OpenMP_${LANG}_IMPLICIT_LINK_DIRS
+ OpenMP_${LANG}_IMPLICIT_FWK_DIRS
+ OpenMP_${LANG}_LOG_VAR
+ "${CMAKE_${LANG}_IMPLICIT_OBJECT_REGEX}"
+ )
+
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Parsed ${LANG} OpenMP implicit link information from above output:\n${OpenMP_${LANG}_LOG_VAR}\n\n")
+
+ unset(_OPENMP_LIB_NAMES)
+ foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_IMPLICIT_LIBRARIES)
+ get_filename_component(_OPENMP_IMPLICIT_LIB_DIR "${_OPENMP_IMPLICIT_LIB}" DIRECTORY)
+ get_filename_component(_OPENMP_IMPLICIT_LIB_NAME "${_OPENMP_IMPLICIT_LIB}" NAME)
+ get_filename_component(_OPENMP_IMPLICIT_LIB_PLAIN "${_OPENMP_IMPLICIT_LIB}" NAME_WE)
+ string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PLAIN_ESC "${_OPENMP_IMPLICIT_LIB_PLAIN}")
+ string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PATH_ESC "${_OPENMP_IMPLICIT_LIB}")
+ if(NOT ( "${_OPENMP_IMPLICIT_LIB}" IN_LIST CMAKE_${LANG}_IMPLICIT_LINK_LIBRARIES
+ OR "${CMAKE_${LANG}_STANDARD_LIBRARIES}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)"
+ OR "${CMAKE_${LANG}_LINK_EXECUTABLE}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)" ) )
+ if(_OPENMP_IMPLICIT_LIB_DIR)
+ set(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY "${_OPENMP_IMPLICIT_LIB}" CACHE FILEPATH
+ "Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP")
+ else()
+ find_library(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY
+ NAMES "${_OPENMP_IMPLICIT_LIB_NAME}"
+ DOC "Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP"
+ HINTS ${OpenMP_${LANG}_IMPLICIT_LINK_DIRS}
+ CMAKE_FIND_ROOT_PATH_BOTH
+ NO_DEFAULT_PATH
+ )
+ endif()
+ mark_as_advanced(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY)
+ list(APPEND _OPENMP_LIB_NAMES ${_OPENMP_IMPLICIT_LIB_PLAIN})
+ endif()
+ endforeach()
+ set("${OPENMP_LIB_NAMES_VAR}" "${_OPENMP_LIB_NAMES}" PARENT_SCOPE)
+ else()
+ # We do not know how to extract implicit OpenMP libraries for this compiler.
+ # Assume that it handles them automatically, e.g. the Intel Compiler on
+ # Windows should put the dependency in its object files.
+ set("${OPENMP_LIB_NAMES_VAR}" "" PARENT_SCOPE)
+ endif()
+ break()
+ elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "AppleClang"
+ AND CMAKE_${LANG}_COMPILER_VERSION VERSION_GREATER_EQUAL "7.0")
+
+ # Check for separate OpenMP library on AppleClang 7+
+ find_library(OpenMP_libomp_LIBRARY
+ NAMES omp gomp iomp5
+ HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES}
+ )
+ mark_as_advanced(OpenMP_libomp_LIBRARY)
+
+ if(OpenMP_libomp_LIBRARY)
+ # Try without specifying include directory first. We only want to
+ # explicitly add a search path if the header can't be found on the
+ # default header search path already.
+ try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
+ CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
+ LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY}
+ OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
+ )
+ if(NOT OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
+ find_path(OpenMP_${LANG}_INCLUDE_DIR omp.h)
+ mark_as_advanced(OpenMP_${LANG}_INCLUDE_DIR)
+ set(OpenMP_${LANG}_INCLUDE_DIR "${OpenMP_${LANG}_INCLUDE_DIR}" PARENT_SCOPE)
+ if(OpenMP_${LANG}_INCLUDE_DIR)
+ try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
+ CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
+ "-DINCLUDE_DIRECTORIES:STRING=${OpenMP_${LANG}_INCLUDE_DIR}"
+ LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY}
+ OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
+ )
+ endif()
+ endif()
+ if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
+ set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
+ set("${OPENMP_LIB_NAMES_VAR}" "libomp" PARENT_SCOPE)
+ break()
+ endif()
+ endif()
+ elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "Clang" AND WIN32)
+ # Check for separate OpenMP library for Clang on Windows
+ find_library(OpenMP_libomp_LIBRARY
+ NAMES libomp libgomp libiomp5
+ HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES}
+ )
+ mark_as_advanced(OpenMP_libomp_LIBRARY)
+ if(OpenMP_libomp_LIBRARY)
+ try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
+ CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
+ LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY}
+ OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
+ )
+ if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
+ set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
+ set("${OPENMP_LIB_NAMES_VAR}" "libomp" PARENT_SCOPE)
+ break()
+ endif()
+ endif()
+ else()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Detecting ${LANG} OpenMP failed with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
+ endif()
+ set("${OPENMP_LIB_NAMES_VAR}" "NOTFOUND" PARENT_SCOPE)
+ set("${OPENMP_FLAG_VAR}" "NOTFOUND" PARENT_SCOPE)
+ endforeach()
+
+ unset(OpenMP_VERBOSE_COMPILE_OPTIONS)
+endfunction()
+
+set(OpenMP_C_CXX_CHECK_VERSION_SOURCE
+"
+#include <stdio.h>
+#include <omp.h>
+const char ompver_str[] = { 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'M',
+ 'P', '-', 'd', 'a', 't', 'e', '[',
+ ('0' + ((_OPENMP/100000)%10)),
+ ('0' + ((_OPENMP/10000)%10)),
+ ('0' + ((_OPENMP/1000)%10)),
+ ('0' + ((_OPENMP/100)%10)),
+ ('0' + ((_OPENMP/10)%10)),
+ ('0' + ((_OPENMP/1)%10)),
+ ']', '\\0' };
+int main(void)
+{
+ puts(ompver_str);
+ return 0;
+}
+")
+
+set(OpenMP_Fortran_CHECK_VERSION_SOURCE
+"
+ program omp_ver
+ @OpenMP_Fortran_INCLUDE_LINE@
+ integer, parameter :: zero = ichar('0')
+ integer, parameter :: ompv = openmp_version
+ character, dimension(24), parameter :: ompver_str =&
+ (/ 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'M', 'P', '-',&
+ 'd', 'a', 't', 'e', '[',&
+ char(zero + mod(ompv/100000, 10)),&
+ char(zero + mod(ompv/10000, 10)),&
+ char(zero + mod(ompv/1000, 10)),&
+ char(zero + mod(ompv/100, 10)),&
+ char(zero + mod(ompv/10, 10)),&
+ char(zero + mod(ompv/1, 10)), ']' /)
+ print *, ompver_str
+ end program omp_ver
+")
+
+function(_OPENMP_GET_SPEC_DATE LANG SPEC_DATE)
+ _OPENMP_WRITE_SOURCE_FILE("${LANG}" "CHECK_VERSION_SOURCE" OpenMPCheckVersion _OPENMP_TEST_SRC)
+
+ unset(_includeDirFlags)
+ if(OpenMP_${LANG}_INCLUDE_DIR)
+ set(_includeDirFlags "-DINCLUDE_DIRECTORIES:STRING=${OpenMP_${LANG}_INCLUDE_DIR}")
+ endif()
+
+ set(BIN_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenMP/ompver_${LANG}.bin")
+ string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}")
+ try_compile(OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG} "${CMAKE_BINARY_DIR}" "${_OPENMP_TEST_SRC}"
+ CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OpenMP_${LANG}_FLAGS}" ${_includeDirFlags}
+ COPY_FILE ${BIN_FILE}
+ OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT)
+
+ if(${OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG}})
+ file(STRINGS ${BIN_FILE} specstr LIMIT_COUNT 1 REGEX "INFO:OpenMP-date")
+ set(regex_spec_date ".*INFO:OpenMP-date\\[0*([^]]*)\\].*")
+ if("${specstr}" MATCHES "${regex_spec_date}")
+ set(${SPEC_DATE} "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ endif()
+ else()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Detecting ${LANG} OpenMP version failed with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
+ endif()
+endfunction()
+
+macro(_OPENMP_SET_VERSION_BY_SPEC_DATE LANG)
+ set(OpenMP_SPEC_DATE_MAP
+ # Preview versions
+ "201611=5.0" # OpenMP 5.0 preview 1
+ # Combined versions, 2.5 onwards
+ "201811=5.0"
+ "201511=4.5"
+ "201307=4.0"
+ "201107=3.1"
+ "200805=3.0"
+ "200505=2.5"
+ # C/C++ version 2.0
+ "200203=2.0"
+ # Fortran version 2.0
+ "200011=2.0"
+ # Fortran version 1.1
+ "199911=1.1"
+ # C/C++ version 1.0 (there's no 1.1 for C/C++)
+ "199810=1.0"
+ # Fortran version 1.0
+ "199710=1.0"
+ )
+ if(MSVC)
+ list(APPEND OpenMP_SPEC_DATE_MAP "2019=2.0")
+ endif()
+
+ if(OpenMP_${LANG}_SPEC_DATE)
+ string(REGEX MATCHALL "${OpenMP_${LANG}_SPEC_DATE}=([0-9]+)\\.([0-9]+)" _version_match "${OpenMP_SPEC_DATE_MAP}")
+ else()
+ set(_version_match "")
+ endif()
+ if(NOT _version_match STREQUAL "")
+ set(OpenMP_${LANG}_VERSION_MAJOR ${CMAKE_MATCH_1})
+ set(OpenMP_${LANG}_VERSION_MINOR ${CMAKE_MATCH_2})
+ set(OpenMP_${LANG}_VERSION "${OpenMP_${LANG}_VERSION_MAJOR}.${OpenMP_${LANG}_VERSION_MINOR}")
+ else()
+ unset(OpenMP_${LANG}_VERSION_MAJOR)
+ unset(OpenMP_${LANG}_VERSION_MINOR)
+ unset(OpenMP_${LANG}_VERSION)
+ endif()
+ unset(_version_match)
+ unset(OpenMP_SPEC_DATE_MAP)
+endmacro()
+
+foreach(LANG IN ITEMS C CXX)
+ if(CMAKE_${LANG}_COMPILER_LOADED)
+ if(NOT DEFINED OpenMP_${LANG}_FLAGS OR "${OpenMP_${LANG}_FLAGS}" STREQUAL "NOTFOUND"
+ OR NOT DEFINED OpenMP_${LANG}_LIB_NAMES OR "${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND")
+ _OPENMP_GET_FLAGS("${LANG}" "${LANG}" OpenMP_${LANG}_FLAGS_WORK OpenMP_${LANG}_LIB_NAMES_WORK)
+ set(OpenMP_${LANG}_FLAGS "${OpenMP_${LANG}_FLAGS_WORK}"
+ CACHE STRING "${LANG} compiler flags for OpenMP parallelization" FORCE)
+ set(OpenMP_${LANG}_LIB_NAMES "${OpenMP_${LANG}_LIB_NAMES_WORK}"
+ CACHE STRING "${LANG} compiler libraries for OpenMP parallelization" FORCE)
+ mark_as_advanced(OpenMP_${LANG}_FLAGS OpenMP_${LANG}_LIB_NAMES)
+ endif()
+ endif()
+endforeach()
+
+if(CMAKE_Fortran_COMPILER_LOADED)
+ if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND"
+ OR NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND"
+ OR NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_MODULE)
+ set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n implicit none")
+ _OPENMP_GET_FLAGS("Fortran" "FortranHeader" OpenMP_Fortran_FLAGS_WORK OpenMP_Fortran_LIB_NAMES_WORK)
+ if(OpenMP_Fortran_FLAGS_WORK)
+ set(OpenMP_Fortran_HAVE_OMPLIB_MODULE TRUE CACHE BOOL INTERNAL "")
+ endif()
+
+ set(OpenMP_Fortran_FLAGS "${OpenMP_Fortran_FLAGS_WORK}"
+ CACHE STRING "Fortran compiler flags for OpenMP parallelization")
+ set(OpenMP_Fortran_LIB_NAMES "${OpenMP_Fortran_LIB_NAMES_WORK}"
+ CACHE STRING "Fortran compiler libraries for OpenMP parallelization")
+ mark_as_advanced(OpenMP_Fortran_FLAGS OpenMP_Fortran_LIB_NAMES)
+ endif()
+
+ if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND"
+ OR NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND"
+ OR NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_HEADER)
+ set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n include 'omp_lib.h'")
+ _OPENMP_GET_FLAGS("Fortran" "FortranModule" OpenMP_Fortran_FLAGS_WORK OpenMP_Fortran_LIB_NAMES_WORK)
+ if(OpenMP_Fortran_FLAGS_WORK)
+ set(OpenMP_Fortran_HAVE_OMPLIB_HEADER TRUE CACHE BOOL INTERNAL "")
+ endif()
+
+ set(OpenMP_Fortran_FLAGS "${OpenMP_Fortran_FLAGS_WORK}"
+ CACHE STRING "Fortran compiler flags for OpenMP parallelization")
+
+ set(OpenMP_Fortran_LIB_NAMES "${OpenMP_Fortran_LIB_NAMES}"
+ CACHE STRING "Fortran compiler libraries for OpenMP parallelization")
+ endif()
+
+ if(OpenMP_Fortran_HAVE_OMPLIB_MODULE)
+ set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n implicit none")
+ else()
+ set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n include 'omp_lib.h'")
+ endif()
+endif()
+
+if(NOT OpenMP_FIND_COMPONENTS)
+ set(OpenMP_FINDLIST C CXX Fortran)
+else()
+ set(OpenMP_FINDLIST ${OpenMP_FIND_COMPONENTS})
+endif()
+
+unset(_OpenMP_MIN_VERSION)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+foreach(LANG IN LISTS OpenMP_FINDLIST)
+ if(CMAKE_${LANG}_COMPILER_LOADED)
+ if (NOT OpenMP_${LANG}_SPEC_DATE AND OpenMP_${LANG}_FLAGS)
+ _OPENMP_GET_SPEC_DATE("${LANG}" OpenMP_${LANG}_SPEC_DATE_INTERNAL)
+ set(OpenMP_${LANG}_SPEC_DATE "${OpenMP_${LANG}_SPEC_DATE_INTERNAL}" CACHE
+ INTERNAL "${LANG} compiler's OpenMP specification date")
+ endif()
+ _OPENMP_SET_VERSION_BY_SPEC_DATE("${LANG}")
+
+ set(OpenMP_${LANG}_FIND_QUIETLY ${OpenMP_FIND_QUIETLY})
+ set(OpenMP_${LANG}_FIND_REQUIRED ${OpenMP_FIND_REQUIRED})
+ set(OpenMP_${LANG}_FIND_VERSION ${OpenMP_FIND_VERSION})
+ set(OpenMP_${LANG}_FIND_VERSION_EXACT ${OpenMP_FIND_VERSION_EXACT})
+
+ set(_OPENMP_${LANG}_REQUIRED_VARS OpenMP_${LANG}_FLAGS)
+ if("${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND")
+ set(_OPENMP_${LANG}_REQUIRED_LIB_VARS OpenMP_${LANG}_LIB_NAMES)
+ else()
+ foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_LIB_NAMES)
+ list(APPEND _OPENMP_${LANG}_REQUIRED_LIB_VARS OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY)
+ endforeach()
+ endif()
+
+ find_package_handle_standard_args(OpenMP_${LANG}
+ NAME_MISMATCHED
+ REQUIRED_VARS OpenMP_${LANG}_FLAGS ${_OPENMP_${LANG}_REQUIRED_LIB_VARS}
+ VERSION_VAR OpenMP_${LANG}_VERSION
+ )
+
+ if(OpenMP_${LANG}_FOUND)
+ if(DEFINED OpenMP_${LANG}_VERSION)
+ if(NOT _OpenMP_MIN_VERSION OR _OpenMP_MIN_VERSION VERSION_GREATER OpenMP_${LANG}_VERSION)
+ set(_OpenMP_MIN_VERSION OpenMP_${LANG}_VERSION)
+ endif()
+ endif()
+ set(OpenMP_${LANG}_LIBRARIES "")
+ foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_LIB_NAMES)
+ list(APPEND OpenMP_${LANG}_LIBRARIES "${OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY}")
+ endforeach()
+ if(OpenMP_${LANG}_INCLUDE_DIR)
+ set(OpenMP_${LANG}_INCLUDE_DIRS ${OpenMP_${LANG}_INCLUDE_DIR})
+ else()
+ set(OpenMP_${LANG}_INCLUDE_DIRS "")
+ endif()
+
+ if(NOT TARGET OpenMP::OpenMP_${LANG})
+ add_library(OpenMP::OpenMP_${LANG} INTERFACE IMPORTED)
+ endif()
+ if(OpenMP_${LANG}_FLAGS)
+ separate_arguments(_OpenMP_${LANG}_OPTIONS NATIVE_COMMAND "${OpenMP_${LANG}_FLAGS}")
+ set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
+ INTERFACE_COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:${_OpenMP_${LANG}_OPTIONS}>")
+ unset(_OpenMP_${LANG}_OPTIONS)
+ endif()
+ if(OpenMP_${LANG}_INCLUDE_DIRS)
+ set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${OpenMP_${LANG}_INCLUDE_DIRS}>")
+ endif()
+ if(OpenMP_${LANG}_LIBRARIES)
+ set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
+ INTERFACE_LINK_LIBRARIES "${OpenMP_${LANG}_LIBRARIES}")
+ endif()
+ endif()
+ endif()
+endforeach()
+
+unset(_OpenMP_REQ_VARS)
+foreach(LANG IN ITEMS C CXX Fortran)
+ if((NOT OpenMP_FIND_COMPONENTS AND CMAKE_${LANG}_COMPILER_LOADED) OR LANG IN_LIST OpenMP_FIND_COMPONENTS)
+ list(APPEND _OpenMP_REQ_VARS "OpenMP_${LANG}_FOUND")
+ endif()
+endforeach()
+
+find_package_handle_standard_args(OpenMP
+ REQUIRED_VARS ${_OpenMP_REQ_VARS}
+ VERSION_VAR ${_OpenMP_MIN_VERSION}
+ HANDLE_COMPONENTS)
+
+set(OPENMP_FOUND ${OpenMP_FOUND})
+
+if(CMAKE_Fortran_COMPILER_LOADED AND OpenMP_Fortran_FOUND)
+ if(NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_MODULE)
+ set(OpenMP_Fortran_HAVE_OMPLIB_MODULE FALSE CACHE BOOL INTERNAL "")
+ endif()
+ if(NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_HEADER)
+ set(OpenMP_Fortran_HAVE_OMPLIB_HEADER FALSE CACHE BOOL INTERNAL "")
+ endif()
+endif()
+
+if(NOT ( CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED ))
+ message(SEND_ERROR "FindOpenMP requires the C, CXX or Fortran languages to be enabled")
+endif()
+
+unset(OpenMP_C_CXX_TEST_SOURCE)
+unset(OpenMP_Fortran_TEST_SOURCE)
+unset(OpenMP_C_CXX_CHECK_VERSION_SOURCE)
+unset(OpenMP_Fortran_CHECK_VERSION_SOURCE)
+unset(OpenMP_Fortran_INCLUDE_LINE)
+
+cmake_policy(POP)
diff --git a/Modules/FindOpenSSL.cmake b/Modules/FindOpenSSL.cmake
new file mode 100644
index 0000000..b1afa5f
--- /dev/null
+++ b/Modules/FindOpenSSL.cmake
@@ -0,0 +1,675 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindOpenSSL
+-----------
+
+Find the OpenSSL encryption library.
+
+This module finds an installed OpenSSL library and determines its version.
+
+.. versionadded:: 3.19
+ 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.
+
+.. versionadded:: 3.18
+ Support for OpenSSL 3.0.
+
+Optional COMPONENTS
+^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.12
+
+This module supports two optional COMPONENTS: ``Crypto`` and ``SSL``. Both
+components have associated imported targets, as described below.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.4
+
+This module defines the following :prop_tgt:`IMPORTED` targets:
+
+``OpenSSL::SSL``
+ The OpenSSL ``ssl`` library, if found.
+``OpenSSL::Crypto``
+ The OpenSSL ``crypto`` library, if found.
+``OpenSSL::applink``
+ .. versionadded:: 3.18
+
+ The OpenSSL ``applink`` components that might be need to be compiled into
+ projects under MSVC. This target is available only if found OpenSSL version
+ is not less than 0.9.8. By linking this target the above OpenSSL targets can
+ be linked even if the project has different MSVC runtime configurations with
+ the above OpenSSL targets. This target has no effect on platforms other than
+ MSVC.
+
+NOTE: Due to how ``INTERFACE_SOURCES`` are consumed by the consuming target,
+unless you certainly know what you are doing, it is always preferred to link
+``OpenSSL::applink`` target as ``PRIVATE`` and to make sure that this target is
+linked at most once for the whole dependency graph of any library or
+executable:
+
+.. code-block:: cmake
+
+ target_link_libraries(myTarget PRIVATE OpenSSL::applink)
+
+Otherwise you would probably encounter unexpected random problems when building
+and linking, as both the ISO C and the ISO C++ standard claims almost nothing
+about what a link process should be.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``OPENSSL_FOUND``
+ System has the OpenSSL library. If no components are requested it only
+ requires the crypto library.
+``OPENSSL_INCLUDE_DIR``
+ The OpenSSL include directory.
+``OPENSSL_CRYPTO_LIBRARY``
+ The OpenSSL crypto library.
+``OPENSSL_CRYPTO_LIBRARIES``
+ The OpenSSL crypto library and its dependencies.
+``OPENSSL_SSL_LIBRARY``
+ The OpenSSL SSL library.
+``OPENSSL_SSL_LIBRARIES``
+ The OpenSSL SSL library and its dependencies.
+``OPENSSL_LIBRARIES``
+ All OpenSSL libraries and their dependencies.
+``OPENSSL_VERSION``
+ This is set to ``$major.$minor.$revision$patch`` (e.g. ``0.9.8s``).
+``OPENSSL_APPLINK_SOURCE``
+ The sources in the target ``OpenSSL::applink`` that is mentioned above. This
+ variable shall always be undefined if found openssl version is less than
+ 0.9.8 or if platform is not MSVC.
+
+Hints
+^^^^^
+
+Set ``OPENSSL_ROOT_DIR`` to the root directory of an OpenSSL installation.
+
+.. versionadded:: 3.4
+ Set ``OPENSSL_USE_STATIC_LIBS`` to ``TRUE`` to look for static libraries.
+
+.. versionadded:: 3.5
+ Set ``OPENSSL_MSVC_STATIC_RT`` set ``TRUE`` to choose the MT version of the lib.
+#]=======================================================================]
+
+macro(_OpenSSL_test_and_find_dependencies ssl_library crypto_library)
+ if((CMAKE_SYSTEM_NAME STREQUAL "Linux") AND
+ (("${ssl_library}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$") OR
+ ("${crypto_library}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$")))
+ set(_OpenSSL_has_dependencies TRUE)
+ find_package(Threads)
+ else()
+ set(_OpenSSL_has_dependencies FALSE)
+ endif()
+endmacro()
+
+function(_OpenSSL_add_dependencies libraries_var)
+ if(CMAKE_THREAD_LIBS_INIT)
+ list(APPEND ${libraries_var} ${CMAKE_THREAD_LIBS_INIT})
+ endif()
+ list(APPEND ${libraries_var} ${CMAKE_DL_LIBS})
+ set(${libraries_var} ${${libraries_var}} PARENT_SCOPE)
+endfunction()
+
+function(_OpenSSL_target_add_dependencies target)
+ if(_OpenSSL_has_dependencies)
+ set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES Threads::Threads )
+ set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS} )
+ endif()
+endfunction()
+
+if (UNIX)
+ find_package(PkgConfig QUIET)
+ pkg_check_modules(_OPENSSL QUIET openssl)
+endif ()
+
+# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
+if(OPENSSL_USE_STATIC_LIBS)
+ set(_openssl_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ if(WIN32)
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ else()
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .a )
+ endif()
+endif()
+
+if (WIN32)
+ # http://www.slproweb.com/products/Win32OpenSSL.html
+ set(_OPENSSL_ROOT_HINTS
+ ${OPENSSL_ROOT_DIR}
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]"
+ ENV OPENSSL_ROOT_DIR
+ )
+
+ if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
+ set(_arch "Win64")
+ file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
+ else()
+ set(_arch "Win32")
+ set(_progfiles_x86 "ProgramFiles(x86)")
+ if(NOT "$ENV{${_progfiles_x86}}" STREQUAL "")
+ # under windows 64 bit machine
+ file(TO_CMAKE_PATH "$ENV{${_progfiles_x86}}" _programfiles)
+ else()
+ # under windows 32 bit machine
+ file(TO_CMAKE_PATH "$ENV{ProgramFiles}" _programfiles)
+ endif()
+ endif()
+
+ set(_OPENSSL_ROOT_PATHS
+ "${_programfiles}/OpenSSL"
+ "${_programfiles}/OpenSSL-${_arch}"
+ "C:/OpenSSL/"
+ "C:/OpenSSL-${_arch}/"
+ )
+ unset(_programfiles)
+ unset(_arch)
+else ()
+ set(_OPENSSL_ROOT_HINTS
+ ${OPENSSL_ROOT_DIR}
+ ENV OPENSSL_ROOT_DIR
+ )
+endif ()
+
+set(_OPENSSL_ROOT_HINTS_AND_PATHS
+ HINTS ${_OPENSSL_ROOT_HINTS}
+ PATHS ${_OPENSSL_ROOT_PATHS}
+ )
+
+find_path(OPENSSL_INCLUDE_DIR
+ NAMES
+ openssl/ssl.h
+ ${_OPENSSL_ROOT_HINTS_AND_PATHS}
+ HINTS
+ ${_OPENSSL_INCLUDEDIR}
+ ${_OPENSSL_INCLUDE_DIRS}
+ PATH_SUFFIXES
+ include
+)
+
+if(WIN32 AND NOT CYGWIN)
+ if(MSVC)
+ # /MD and /MDd are the standard values - if someone wants to use
+ # others, the libnames have to change here too
+ # use also ssl and ssleay32 in debug as fallback for openssl < 0.9.8b
+ # enable OPENSSL_MSVC_STATIC_RT to get the libs build /MT (Multithreaded no-DLL)
+ # In Visual C++ naming convention each of these four kinds of Windows libraries has it's standard suffix:
+ # * MD for dynamic-release
+ # * MDd for dynamic-debug
+ # * MT for static-release
+ # * MTd for static-debug
+
+ # Implementation details:
+ # We are using the libraries located in the VC subdir instead of the parent directory even though :
+ # libeay32MD.lib is identical to ../libeay32.lib, and
+ # ssleay32MD.lib is identical to ../ssleay32.lib
+ # enable OPENSSL_USE_STATIC_LIBS to use the static libs located in lib/VC/static
+
+ if (OPENSSL_MSVC_STATIC_RT)
+ set(_OPENSSL_MSVC_RT_MODE "MT")
+ else ()
+ set(_OPENSSL_MSVC_RT_MODE "MD")
+ endif ()
+
+ # Since OpenSSL 1.1, lib names are like libcrypto32MTd.lib and libssl32MTd.lib
+ if( "${CMAKE_SIZEOF_VOID_P}" STREQUAL "8" )
+ set(_OPENSSL_MSVC_ARCH_SUFFIX "64")
+ else()
+ set(_OPENSSL_MSVC_ARCH_SUFFIX "32")
+ endif()
+
+ if(OPENSSL_USE_STATIC_LIBS)
+ set(_OPENSSL_STATIC_SUFFIX
+ "_static"
+ )
+ set(_OPENSSL_PATH_SUFFIXES
+ "lib/VC/static"
+ "VC/static"
+ "lib"
+ )
+ else()
+ set(_OPENSSL_STATIC_SUFFIX
+ ""
+ )
+ set(_OPENSSL_PATH_SUFFIXES
+ "lib/VC"
+ "VC"
+ "lib"
+ )
+ endif ()
+
+ find_library(LIB_EAY_DEBUG
+ NAMES
+ # When OpenSSL is built with default options, the static library name is suffixed with "_static".
+ # Looking the "libcrypto_static.lib" with a higher priority than "libcrypto.lib" which is the
+ # import library of "libcrypto.dll".
+ libcrypto${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
+ libcrypto${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
+ libcrypto${_OPENSSL_STATIC_SUFFIX}d
+ libeay32${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
+ libeay32${_OPENSSL_STATIC_SUFFIX}d
+ crypto${_OPENSSL_STATIC_SUFFIX}d
+ # When OpenSSL is built with the "-static" option, only the static build is produced,
+ # and it is not suffixed with "_static".
+ libcrypto${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
+ libcrypto${_OPENSSL_MSVC_RT_MODE}d
+ libcryptod
+ libeay32${_OPENSSL_MSVC_RT_MODE}d
+ libeay32d
+ cryptod
+ NAMES_PER_DIR
+ ${_OPENSSL_ROOT_HINTS_AND_PATHS}
+ PATH_SUFFIXES
+ ${_OPENSSL_PATH_SUFFIXES}
+ )
+
+ find_library(LIB_EAY_RELEASE
+ NAMES
+ # When OpenSSL is built with default options, the static library name is suffixed with "_static".
+ # Looking the "libcrypto_static.lib" with a higher priority than "libcrypto.lib" which is the
+ # import library of "libcrypto.dll".
+ libcrypto${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}
+ libcrypto${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}
+ libcrypto${_OPENSSL_STATIC_SUFFIX}
+ libeay32${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}
+ libeay32${_OPENSSL_STATIC_SUFFIX}
+ crypto${_OPENSSL_STATIC_SUFFIX}
+ # When OpenSSL is built with the "-static" option, only the static build is produced,
+ # and it is not suffixed with "_static".
+ libcrypto${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}
+ libcrypto${_OPENSSL_MSVC_RT_MODE}
+ libcrypto
+ libeay32${_OPENSSL_MSVC_RT_MODE}
+ libeay32
+ crypto
+ NAMES_PER_DIR
+ ${_OPENSSL_ROOT_HINTS_AND_PATHS}
+ PATH_SUFFIXES
+ ${_OPENSSL_PATH_SUFFIXES}
+ )
+
+ find_library(SSL_EAY_DEBUG
+ NAMES
+ # When OpenSSL is built with default options, the static library name is suffixed with "_static".
+ # Looking the "libssl_static.lib" with a higher priority than "libssl.lib" which is the
+ # import library of "libssl.dll".
+ libssl${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
+ libssl${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
+ libssl${_OPENSSL_STATIC_SUFFIX}d
+ ssleay32${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
+ ssleay32${_OPENSSL_STATIC_SUFFIX}d
+ ssl${_OPENSSL_STATIC_SUFFIX}d
+ # When OpenSSL is built with the "-static" option, only the static build is produced,
+ # and it is not suffixed with "_static".
+ libssl${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d
+ libssl${_OPENSSL_MSVC_RT_MODE}d
+ libssld
+ ssleay32${_OPENSSL_MSVC_RT_MODE}d
+ ssleay32d
+ ssld
+ NAMES_PER_DIR
+ ${_OPENSSL_ROOT_HINTS_AND_PATHS}
+ PATH_SUFFIXES
+ ${_OPENSSL_PATH_SUFFIXES}
+ )
+
+ find_library(SSL_EAY_RELEASE
+ NAMES
+ # When OpenSSL is built with default options, the static library name is suffixed with "_static".
+ # Looking the "libssl_static.lib" with a higher priority than "libssl.lib" which is the
+ # import library of "libssl.dll".
+ libssl${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}
+ libssl${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}
+ libssl${_OPENSSL_STATIC_SUFFIX}
+ ssleay32${_OPENSSL_STATIC_SUFFIX}${_OPENSSL_MSVC_RT_MODE}
+ ssleay32${_OPENSSL_STATIC_SUFFIX}
+ ssl${_OPENSSL_STATIC_SUFFIX}
+ # When OpenSSL is built with the "-static" option, only the static build is produced,
+ # and it is not suffixed with "_static".
+ libssl${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}
+ libssl${_OPENSSL_MSVC_RT_MODE}
+ libssl
+ ssleay32${_OPENSSL_MSVC_RT_MODE}
+ ssleay32
+ ssl
+ NAMES_PER_DIR
+ ${_OPENSSL_ROOT_HINTS_AND_PATHS}
+ PATH_SUFFIXES
+ ${_OPENSSL_PATH_SUFFIXES}
+ )
+
+ set(LIB_EAY_LIBRARY_DEBUG "${LIB_EAY_DEBUG}")
+ set(LIB_EAY_LIBRARY_RELEASE "${LIB_EAY_RELEASE}")
+ set(SSL_EAY_LIBRARY_DEBUG "${SSL_EAY_DEBUG}")
+ set(SSL_EAY_LIBRARY_RELEASE "${SSL_EAY_RELEASE}")
+
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(LIB_EAY)
+ select_library_configurations(SSL_EAY)
+
+ mark_as_advanced(LIB_EAY_LIBRARY_DEBUG LIB_EAY_LIBRARY_RELEASE
+ SSL_EAY_LIBRARY_DEBUG SSL_EAY_LIBRARY_RELEASE)
+ set(OPENSSL_SSL_LIBRARY ${SSL_EAY_LIBRARY} )
+ set(OPENSSL_CRYPTO_LIBRARY ${LIB_EAY_LIBRARY} )
+ elseif(MINGW)
+ # same player, for MinGW
+ set(LIB_EAY_NAMES crypto libeay32)
+ set(SSL_EAY_NAMES ssl ssleay32)
+ find_library(LIB_EAY
+ NAMES
+ ${LIB_EAY_NAMES}
+ NAMES_PER_DIR
+ ${_OPENSSL_ROOT_HINTS_AND_PATHS}
+ PATH_SUFFIXES
+ "lib/MinGW"
+ "lib"
+ )
+
+ find_library(SSL_EAY
+ NAMES
+ ${SSL_EAY_NAMES}
+ NAMES_PER_DIR
+ ${_OPENSSL_ROOT_HINTS_AND_PATHS}
+ PATH_SUFFIXES
+ "lib/MinGW"
+ "lib"
+ )
+
+ mark_as_advanced(SSL_EAY LIB_EAY)
+ set(OPENSSL_SSL_LIBRARY ${SSL_EAY} )
+ set(OPENSSL_CRYPTO_LIBRARY ${LIB_EAY} )
+ unset(LIB_EAY_NAMES)
+ unset(SSL_EAY_NAMES)
+ else()
+ # Not sure what to pick for -say- intel, let's use the toplevel ones and hope someone report issues:
+ find_library(LIB_EAY
+ NAMES
+ libcrypto
+ libeay32
+ NAMES_PER_DIR
+ ${_OPENSSL_ROOT_HINTS_AND_PATHS}
+ HINTS
+ ${_OPENSSL_LIBDIR}
+ PATH_SUFFIXES
+ lib
+ )
+
+ find_library(SSL_EAY
+ NAMES
+ libssl
+ ssleay32
+ NAMES_PER_DIR
+ ${_OPENSSL_ROOT_HINTS_AND_PATHS}
+ HINTS
+ ${_OPENSSL_LIBDIR}
+ PATH_SUFFIXES
+ lib
+ )
+
+ mark_as_advanced(SSL_EAY LIB_EAY)
+ set(OPENSSL_SSL_LIBRARY ${SSL_EAY} )
+ set(OPENSSL_CRYPTO_LIBRARY ${LIB_EAY} )
+ endif()
+else()
+
+ find_library(OPENSSL_SSL_LIBRARY
+ NAMES
+ ssl
+ ssleay32
+ ssleay32MD
+ NAMES_PER_DIR
+ ${_OPENSSL_ROOT_HINTS_AND_PATHS}
+ HINTS
+ ${_OPENSSL_LIBDIR}
+ ${_OPENSSL_LIBRARY_DIRS}
+ PATH_SUFFIXES
+ lib
+ )
+
+ find_library(OPENSSL_CRYPTO_LIBRARY
+ NAMES
+ crypto
+ NAMES_PER_DIR
+ ${_OPENSSL_ROOT_HINTS_AND_PATHS}
+ HINTS
+ ${_OPENSSL_LIBDIR}
+ ${_OPENSSL_LIBRARY_DIRS}
+ PATH_SUFFIXES
+ lib
+ )
+
+ mark_as_advanced(OPENSSL_CRYPTO_LIBRARY OPENSSL_SSL_LIBRARY)
+
+endif()
+
+set(OPENSSL_SSL_LIBRARIES ${OPENSSL_SSL_LIBRARY})
+set(OPENSSL_CRYPTO_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
+set(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARIES} )
+_OpenSSL_test_and_find_dependencies("${OPENSSL_SSL_LIBRARY}" "${OPENSSL_CRYPTO_LIBRARY}")
+if(_OpenSSL_has_dependencies)
+ _OpenSSL_add_dependencies( OPENSSL_SSL_LIBRARIES )
+ _OpenSSL_add_dependencies( OPENSSL_CRYPTO_LIBRARIES )
+ _OpenSSL_add_dependencies( OPENSSL_LIBRARIES )
+endif()
+
+function(from_hex HEX DEC)
+ string(TOUPPER "${HEX}" HEX)
+ set(_res 0)
+ string(LENGTH "${HEX}" _strlen)
+
+ while (_strlen GREATER 0)
+ math(EXPR _res "${_res} * 16")
+ string(SUBSTRING "${HEX}" 0 1 NIBBLE)
+ string(SUBSTRING "${HEX}" 1 -1 HEX)
+ if (NIBBLE STREQUAL "A")
+ math(EXPR _res "${_res} + 10")
+ elseif (NIBBLE STREQUAL "B")
+ math(EXPR _res "${_res} + 11")
+ elseif (NIBBLE STREQUAL "C")
+ math(EXPR _res "${_res} + 12")
+ elseif (NIBBLE STREQUAL "D")
+ math(EXPR _res "${_res} + 13")
+ elseif (NIBBLE STREQUAL "E")
+ math(EXPR _res "${_res} + 14")
+ elseif (NIBBLE STREQUAL "F")
+ math(EXPR _res "${_res} + 15")
+ else()
+ math(EXPR _res "${_res} + ${NIBBLE}")
+ endif()
+
+ string(LENGTH "${HEX}" _strlen)
+ endwhile()
+
+ set(${DEC} ${_res} PARENT_SCOPE)
+endfunction()
+
+if(OPENSSL_INCLUDE_DIR AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h")
+ file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str
+ REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*")
+
+ if(openssl_version_str)
+ # The version number is encoded as 0xMNNFFPPS: major minor fix patch status
+ # The status gives if this is a developer or prerelease and is ignored here.
+ # Major, minor, and fix directly translate into the version numbers shown in
+ # the string. The patch field translates to the single character suffix that
+ # indicates the bug fix state, which 00 -> nothing, 01 -> a, 02 -> b and so
+ # on.
+
+ string(REGEX REPLACE "^.*OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F]).*$"
+ "\\1;\\2;\\3;\\4;\\5" OPENSSL_VERSION_LIST "${openssl_version_str}")
+ list(GET OPENSSL_VERSION_LIST 0 OPENSSL_VERSION_MAJOR)
+ list(GET OPENSSL_VERSION_LIST 1 OPENSSL_VERSION_MINOR)
+ from_hex("${OPENSSL_VERSION_MINOR}" OPENSSL_VERSION_MINOR)
+ list(GET OPENSSL_VERSION_LIST 2 OPENSSL_VERSION_FIX)
+ from_hex("${OPENSSL_VERSION_FIX}" OPENSSL_VERSION_FIX)
+ list(GET OPENSSL_VERSION_LIST 3 OPENSSL_VERSION_PATCH)
+
+ if (NOT OPENSSL_VERSION_PATCH STREQUAL "00")
+ from_hex("${OPENSSL_VERSION_PATCH}" _tmp)
+ # 96 is the ASCII code of 'a' minus 1
+ math(EXPR OPENSSL_VERSION_PATCH_ASCII "${_tmp} + 96")
+ unset(_tmp)
+ # Once anyone knows how OpenSSL would call the patch versions beyond 'z'
+ # this should be updated to handle that, too. This has not happened yet
+ # so it is simply ignored here for now.
+ string(ASCII "${OPENSSL_VERSION_PATCH_ASCII}" OPENSSL_VERSION_PATCH_STRING)
+ endif ()
+
+ set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}${OPENSSL_VERSION_PATCH_STRING}")
+ else ()
+ # Since OpenSSL 3.0.0, the new version format is MAJOR.MINOR.PATCH and
+ # a new OPENSSL_VERSION_STR macro contains exactly that
+ file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" OPENSSL_VERSION_STR
+ REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_STR[\t ]+\"([0-9])+\\.([0-9])+\\.([0-9])+\".*")
+ string(REGEX REPLACE "^.*OPENSSL_VERSION_STR[\t ]+\"([0-9]+\\.[0-9]+\\.[0-9]+)\".*$"
+ "\\1" OPENSSL_VERSION_STR "${OPENSSL_VERSION_STR}")
+
+ set(OPENSSL_VERSION "${OPENSSL_VERSION_STR}")
+
+ unset(OPENSSL_VERSION_STR)
+ endif ()
+endif ()
+
+foreach(_comp IN LISTS OpenSSL_FIND_COMPONENTS)
+ if(_comp STREQUAL "Crypto")
+ if(EXISTS "${OPENSSL_INCLUDE_DIR}" AND
+ (EXISTS "${OPENSSL_CRYPTO_LIBRARY}" OR
+ EXISTS "${LIB_EAY_LIBRARY_DEBUG}" OR
+ EXISTS "${LIB_EAY_LIBRARY_RELEASE}")
+ )
+ set(OpenSSL_${_comp}_FOUND TRUE)
+ else()
+ set(OpenSSL_${_comp}_FOUND FALSE)
+ endif()
+ elseif(_comp STREQUAL "SSL")
+ if(EXISTS "${OPENSSL_INCLUDE_DIR}" AND
+ (EXISTS "${OPENSSL_SSL_LIBRARY}" OR
+ EXISTS "${SSL_EAY_LIBRARY_DEBUG}" OR
+ EXISTS "${SSL_EAY_LIBRARY_RELEASE}")
+ )
+ set(OpenSSL_${_comp}_FOUND TRUE)
+ else()
+ set(OpenSSL_${_comp}_FOUND FALSE)
+ endif()
+ else()
+ message(WARNING "${_comp} is not a valid OpenSSL component")
+ set(OpenSSL_${_comp}_FOUND FALSE)
+ endif()
+endforeach()
+unset(_comp)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(OpenSSL
+ REQUIRED_VARS
+ OPENSSL_CRYPTO_LIBRARY
+ OPENSSL_INCLUDE_DIR
+ VERSION_VAR
+ OPENSSL_VERSION
+ HANDLE_VERSION_RANGE
+ HANDLE_COMPONENTS
+ FAIL_MESSAGE
+ "Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR"
+)
+
+mark_as_advanced(OPENSSL_INCLUDE_DIR)
+
+if(OPENSSL_FOUND)
+ if(NOT TARGET OpenSSL::Crypto AND
+ (EXISTS "${OPENSSL_CRYPTO_LIBRARY}" OR
+ EXISTS "${LIB_EAY_LIBRARY_DEBUG}" OR
+ EXISTS "${LIB_EAY_LIBRARY_RELEASE}")
+ )
+ add_library(OpenSSL::Crypto UNKNOWN IMPORTED)
+ set_target_properties(OpenSSL::Crypto PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}")
+ if(EXISTS "${OPENSSL_CRYPTO_LIBRARY}")
+ set_target_properties(OpenSSL::Crypto PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${OPENSSL_CRYPTO_LIBRARY}")
+ endif()
+ if(EXISTS "${LIB_EAY_LIBRARY_RELEASE}")
+ set_property(TARGET OpenSSL::Crypto APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(OpenSSL::Crypto PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+ IMPORTED_LOCATION_RELEASE "${LIB_EAY_LIBRARY_RELEASE}")
+ endif()
+ if(EXISTS "${LIB_EAY_LIBRARY_DEBUG}")
+ set_property(TARGET OpenSSL::Crypto APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(OpenSSL::Crypto PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+ IMPORTED_LOCATION_DEBUG "${LIB_EAY_LIBRARY_DEBUG}")
+ endif()
+ _OpenSSL_target_add_dependencies(OpenSSL::Crypto)
+ endif()
+
+ if(NOT TARGET OpenSSL::SSL AND
+ (EXISTS "${OPENSSL_SSL_LIBRARY}" OR
+ EXISTS "${SSL_EAY_LIBRARY_DEBUG}" OR
+ EXISTS "${SSL_EAY_LIBRARY_RELEASE}")
+ )
+ add_library(OpenSSL::SSL UNKNOWN IMPORTED)
+ set_target_properties(OpenSSL::SSL PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}")
+ if(EXISTS "${OPENSSL_SSL_LIBRARY}")
+ set_target_properties(OpenSSL::SSL PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${OPENSSL_SSL_LIBRARY}")
+ endif()
+ if(EXISTS "${SSL_EAY_LIBRARY_RELEASE}")
+ set_property(TARGET OpenSSL::SSL APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(OpenSSL::SSL PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+ IMPORTED_LOCATION_RELEASE "${SSL_EAY_LIBRARY_RELEASE}")
+ endif()
+ if(EXISTS "${SSL_EAY_LIBRARY_DEBUG}")
+ set_property(TARGET OpenSSL::SSL APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(OpenSSL::SSL PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+ IMPORTED_LOCATION_DEBUG "${SSL_EAY_LIBRARY_DEBUG}")
+ endif()
+ if(TARGET OpenSSL::Crypto)
+ set_target_properties(OpenSSL::SSL PROPERTIES
+ INTERFACE_LINK_LIBRARIES OpenSSL::Crypto)
+ endif()
+ _OpenSSL_target_add_dependencies(OpenSSL::SSL)
+ endif()
+
+ if("${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_FIX}" VERSION_GREATER_EQUAL "0.9.8")
+ if(MSVC)
+ if(EXISTS "${OPENSSL_INCLUDE_DIR}")
+ set(_OPENSSL_applink_paths PATHS ${OPENSSL_INCLUDE_DIR})
+ endif()
+ find_file(OPENSSL_APPLINK_SOURCE
+ NAMES
+ openssl/applink.c
+ ${_OPENSSL_applink_paths}
+ NO_DEFAULT_PATH)
+ if(OPENSSL_APPLINK_SOURCE)
+ set(_OPENSSL_applink_interface_srcs ${OPENSSL_APPLINK_SOURCE})
+ endif()
+ endif()
+ if(NOT TARGET OpenSSL::applink)
+ add_library(OpenSSL::applink INTERFACE IMPORTED)
+ set_property(TARGET OpenSSL::applink APPEND
+ PROPERTY INTERFACE_SOURCES
+ ${_OPENSSL_applink_interface_srcs})
+ endif()
+ endif()
+endif()
+
+# Restore the original find library ordering
+if(OPENSSL_USE_STATIC_LIBS)
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ${_openssl_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
+endif()
diff --git a/Modules/FindOpenSceneGraph.cmake b/Modules/FindOpenSceneGraph.cmake
new file mode 100644
index 0000000..27909bc
--- /dev/null
+++ b/Modules/FindOpenSceneGraph.cmake
@@ -0,0 +1,232 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindOpenSceneGraph
+------------------
+
+Find OpenSceneGraph (3D graphics application programming interface)
+
+This module searches for the OpenSceneGraph core "osg" library as well
+as :module:`FindOpenThreads`, and whatever additional ``COMPONENTS``
+(nodekits) that you specify.
+
+::
+
+ See http://www.openscenegraph.org
+
+
+
+NOTE: To use this module effectively you must either require ``CMake >=
+2.6.3`` with :command:`cmake_minimum_required(VERSION 2.6.3)` or download
+and place :module:`FindOpenThreads`, :module:`Findosg` functions,
+:module:`Findosg` and ``Find<etc>.cmake`` files into your
+:variable:`CMAKE_MODULE_PATH`.
+
+==================================
+
+This module accepts the following variables (note mixed case)
+
+::
+
+ OpenSceneGraph_DEBUG - Enable debugging output
+
+
+
+::
+
+ OpenSceneGraph_MARK_AS_ADVANCED - Mark cache variables as advanced
+ automatically
+
+
+
+The following environment variables are also respected for finding the
+OSG and it's various components. :variable:`CMAKE_PREFIX_PATH` can also be
+used for this (see :command:`find_library` CMake documentation).
+
+``<MODULE>_DIR``
+ (where ``MODULE`` is of the form "OSGVOLUME" and there is
+ a :module:`FindosgVolume`.cmake` file)
+``OSG_DIR``
+ ..
+``OSGDIR``
+ ..
+``OSG_ROOT``
+ ..
+
+
+[CMake 2.8.10]: The CMake variable ``OSG_DIR`` can now be used as well to
+influence detection, instead of needing to specify an environment
+variable.
+
+This module defines the following output variables:
+
+::
+
+ OPENSCENEGRAPH_FOUND - Was the OSG and all of the specified components found?
+
+
+
+::
+
+ OPENSCENEGRAPH_VERSION - The version of the OSG which was found
+
+
+
+::
+
+ OPENSCENEGRAPH_INCLUDE_DIRS - Where to find the headers
+
+
+
+::
+
+ OPENSCENEGRAPH_LIBRARIES - The OSG libraries
+
+
+
+================================== Example Usage:
+
+::
+
+ find_package(OpenSceneGraph 2.0.0 REQUIRED osgDB osgUtil)
+ # libOpenThreads & libosg automatically searched
+ include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
+
+
+
+::
+
+ add_executable(foo foo.cc)
+ target_link_libraries(foo ${OPENSCENEGRAPH_LIBRARIES})
+#]=======================================================================]
+
+#
+# Naming convention:
+# Local variables of the form _osg_foo
+# Input variables of the form OpenSceneGraph_FOO
+# Output variables of the form OPENSCENEGRAPH_FOO
+#
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+
+set(_osg_modules_to_process)
+foreach(_osg_component ${OpenSceneGraph_FIND_COMPONENTS})
+ list(APPEND _osg_modules_to_process ${_osg_component})
+endforeach()
+list(APPEND _osg_modules_to_process "osg" "OpenThreads")
+list(REMOVE_DUPLICATES _osg_modules_to_process)
+
+if(OpenSceneGraph_DEBUG)
+ message(STATUS "[ FindOpenSceneGraph.cmake:${CMAKE_CURRENT_LIST_LINE} ] "
+ "Components = ${_osg_modules_to_process}")
+endif()
+
+#
+# First we need to find and parse osg/Version
+#
+OSG_FIND_PATH(OSG osg/Version)
+if(OpenSceneGraph_MARK_AS_ADVANCED)
+ OSG_MARK_AS_ADVANCED(OSG)
+endif()
+
+# Try to ascertain the version...
+if(OSG_INCLUDE_DIR)
+ if(OpenSceneGraph_DEBUG)
+ message(STATUS "[ FindOpenSceneGraph.cmake:${CMAKE_CURRENT_LIST_LINE} ] "
+ "Detected OSG_INCLUDE_DIR = ${OSG_INCLUDE_DIR}")
+ endif()
+
+ set(_osg_Version_file "${OSG_INCLUDE_DIR}/osg/Version")
+ if("${OSG_INCLUDE_DIR}" MATCHES "\\.framework$" AND NOT EXISTS "${_osg_Version_file}")
+ set(_osg_Version_file "${OSG_INCLUDE_DIR}/Headers/Version")
+ endif()
+
+ if(EXISTS "${_osg_Version_file}")
+ file(STRINGS "${_osg_Version_file}" _osg_Version_contents
+ REGEX "#define (OSG_VERSION_[A-Z]+|OPENSCENEGRAPH_[A-Z]+_VERSION)[ \t]+[0-9]+")
+ else()
+ set(_osg_Version_contents "unknown")
+ endif()
+
+ string(REGEX MATCH ".*#define OSG_VERSION_MAJOR[ \t]+[0-9]+.*"
+ _osg_old_defines "${_osg_Version_contents}")
+ string(REGEX MATCH ".*#define OPENSCENEGRAPH_MAJOR_VERSION[ \t]+[0-9]+.*"
+ _osg_new_defines "${_osg_Version_contents}")
+ if(_osg_old_defines)
+ string(REGEX REPLACE ".*#define OSG_VERSION_MAJOR[ \t]+([0-9]+).*"
+ "\\1" _osg_VERSION_MAJOR ${_osg_Version_contents})
+ string(REGEX REPLACE ".*#define OSG_VERSION_MINOR[ \t]+([0-9]+).*"
+ "\\1" _osg_VERSION_MINOR ${_osg_Version_contents})
+ string(REGEX REPLACE ".*#define OSG_VERSION_PATCH[ \t]+([0-9]+).*"
+ "\\1" _osg_VERSION_PATCH ${_osg_Version_contents})
+ elseif(_osg_new_defines)
+ string(REGEX REPLACE ".*#define OPENSCENEGRAPH_MAJOR_VERSION[ \t]+([0-9]+).*"
+ "\\1" _osg_VERSION_MAJOR ${_osg_Version_contents})
+ string(REGEX REPLACE ".*#define OPENSCENEGRAPH_MINOR_VERSION[ \t]+([0-9]+).*"
+ "\\1" _osg_VERSION_MINOR ${_osg_Version_contents})
+ string(REGEX REPLACE ".*#define OPENSCENEGRAPH_PATCH_VERSION[ \t]+([0-9]+).*"
+ "\\1" _osg_VERSION_PATCH ${_osg_Version_contents})
+ else()
+ message(WARNING "[ FindOpenSceneGraph.cmake:${CMAKE_CURRENT_LIST_LINE} ] "
+ "Failed to parse version number, please report this as a bug")
+ endif()
+ unset(_osg_Version_contents)
+
+ set(OPENSCENEGRAPH_VERSION "${_osg_VERSION_MAJOR}.${_osg_VERSION_MINOR}.${_osg_VERSION_PATCH}"
+ CACHE INTERNAL "The version of OSG which was detected")
+ if(OpenSceneGraph_DEBUG)
+ message(STATUS "[ FindOpenSceneGraph.cmake:${CMAKE_CURRENT_LIST_LINE} ] "
+ "Detected version ${OPENSCENEGRAPH_VERSION}")
+ endif()
+endif()
+
+set(_osg_quiet)
+if(OpenSceneGraph_FIND_QUIETLY)
+ set(_osg_quiet "QUIET")
+endif()
+#
+# Here we call find_package() on all of the components
+#
+foreach(_osg_module ${_osg_modules_to_process})
+ if(OpenSceneGraph_DEBUG)
+ message(STATUS "[ FindOpenSceneGraph.cmake:${CMAKE_CURRENT_LIST_LINE} ] "
+ "Calling find_package(${_osg_module} ${_osg_required} ${_osg_quiet})")
+ endif()
+ find_package(${_osg_module} ${_osg_quiet})
+
+ string(TOUPPER ${_osg_module} _osg_module_UC)
+ # append to list if module was found OR is required
+ if( ${_osg_module_UC}_FOUND OR OpenSceneGraph_FIND_REQUIRED )
+ list(APPEND OPENSCENEGRAPH_INCLUDE_DIR ${${_osg_module_UC}_INCLUDE_DIR})
+ list(APPEND OPENSCENEGRAPH_LIBRARIES ${${_osg_module_UC}_LIBRARIES})
+ endif()
+
+ if(OpenSceneGraph_MARK_AS_ADVANCED)
+ OSG_MARK_AS_ADVANCED(${_osg_module})
+ endif()
+endforeach()
+
+if(OPENSCENEGRAPH_INCLUDE_DIR)
+ list(REMOVE_DUPLICATES OPENSCENEGRAPH_INCLUDE_DIR)
+endif()
+
+#
+# Check each module to see if it's found
+#
+set(_osg_component_founds)
+if(OpenSceneGraph_FIND_REQUIRED)
+ foreach(_osg_module ${_osg_modules_to_process})
+ string(TOUPPER ${_osg_module} _osg_module_UC)
+ list(APPEND _osg_component_founds ${_osg_module_UC}_FOUND)
+ endforeach()
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenSceneGraph
+ REQUIRED_VARS OPENSCENEGRAPH_LIBRARIES OPENSCENEGRAPH_INCLUDE_DIR ${_osg_component_founds}
+ VERSION_VAR OPENSCENEGRAPH_VERSION)
+
+unset(_osg_component_founds)
+
+set(OPENSCENEGRAPH_INCLUDE_DIRS ${OPENSCENEGRAPH_INCLUDE_DIR})
diff --git a/Modules/FindOpenThreads.cmake b/Modules/FindOpenThreads.cmake
new file mode 100644
index 0000000..bc45eea
--- /dev/null
+++ b/Modules/FindOpenThreads.cmake
@@ -0,0 +1,103 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindOpenThreads
+---------------
+
+
+
+OpenThreads is a C++ based threading library. Its largest userbase
+seems to OpenSceneGraph so you might notice I accept OSGDIR as an
+environment path. I consider this part of the Findosg* suite used to
+find OpenSceneGraph components. Each component is separate and you
+must opt in to each module.
+
+Locate OpenThreads This module defines OPENTHREADS_LIBRARY
+OPENTHREADS_FOUND, if false, do not try to link to OpenThreads
+OPENTHREADS_INCLUDE_DIR, where to find the headers
+
+$OPENTHREADS_DIR is an environment variable that would correspond to
+the ./configure --prefix=$OPENTHREADS_DIR used in building osg.
+
+[CMake 2.8.10]: The CMake variables OPENTHREADS_DIR or OSG_DIR can now
+be used as well to influence detection, instead of needing to specify
+an environment variable.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <OpenThreads/Thread>
+
+# To make it easier for one-step automated configuration/builds,
+# we leverage environmental paths. This is preferable
+# to the -DVAR=value switches because it insulates the
+# users from changes we may make in this script.
+# It also offers a little more flexibility than setting
+# the CMAKE_*_PATH since we can target specific components.
+# However, the default CMake behavior will search system paths
+# before anything else. This is problematic in the cases
+# where you have an older (stable) version installed, but
+# are trying to build a newer version.
+# CMake doesn't offer a nice way to globally control this behavior
+# so we have to do a nasty "double FIND_" in this module.
+# The first FIND disables the CMAKE_ search paths and only checks
+# the environmental paths.
+# If nothing is found, then the second find will search the
+# standard install paths.
+# Explicit -DVAR=value arguments should still be able to override everything.
+
+include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+
+find_path(OPENTHREADS_INCLUDE_DIR OpenThreads/Thread
+ HINTS
+ ENV OPENTHREADS_INCLUDE_DIR
+ ENV OPENTHREADS_DIR
+ ENV OSG_INCLUDE_DIR
+ ENV OSG_DIR
+ ENV OSGDIR
+ ENV OpenThreads_ROOT
+ ENV OSG_ROOT
+ ${OPENTHREADS_DIR}
+ ${OSG_DIR}
+ PATH_SUFFIXES include
+)
+
+
+find_library(OPENTHREADS_LIBRARY_RELEASE
+ NAMES OpenThreads OpenThreadsWin32
+ HINTS
+ ENV OPENTHREADS_LIBRARY_DIR
+ ENV OPENTHREADS_DIR
+ ENV OSG_LIBRARY_DIR
+ ENV OSG_DIR
+ ENV OSGDIR
+ ENV OpenThreads_ROOT
+ ENV OSG_ROOT
+ ${OPENTHREADS_DIR}
+ ${OSG_DIR}
+ PATH_SUFFIXES lib
+)
+
+find_library(OPENTHREADS_LIBRARY_DEBUG
+ NAMES OpenThreadsd OpenThreadsWin32d
+ HINTS
+ ENV OPENTHREADS_DEBUG_LIBRARY_DIR
+ ENV OPENTHREADS_LIBRARY_DIR
+ ENV OPENTHREADS_DIR
+ ENV OSG_LIBRARY_DIR
+ ENV OSG_DIR
+ ENV OSGDIR
+ ENV OpenThreads_ROOT
+ ENV OSG_ROOT
+ ${OPENTHREADS_DIR}
+ ${OSG_DIR}
+ PATH_SUFFIXES lib
+)
+
+select_library_configurations(OPENTHREADS)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenThreads DEFAULT_MSG
+ OPENTHREADS_LIBRARY OPENTHREADS_INCLUDE_DIR)
diff --git a/Modules/FindPHP4.cmake b/Modules/FindPHP4.cmake
new file mode 100644
index 0000000..34b4adb
--- /dev/null
+++ b/Modules/FindPHP4.cmake
@@ -0,0 +1,82 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPHP4
+--------
+
+Find PHP4
+
+This module finds if PHP4 is installed and determines where the
+include files and libraries are. It also determines what the name of
+the library is. This code sets the following variables:
+
+::
+
+ PHP4_INCLUDE_PATH = path to where php.h can be found
+ PHP4_EXECUTABLE = full path to the php4 binary
+#]=======================================================================]
+
+set(PHP4_POSSIBLE_INCLUDE_PATHS
+ /usr/include/php4
+ /usr/local/include/php4
+ /usr/include/php
+ /usr/local/include/php
+ /usr/local/apache/php
+ )
+
+set(PHP4_POSSIBLE_LIB_PATHS
+ /usr/lib
+ )
+
+find_path(PHP4_FOUND_INCLUDE_PATH main/php.h
+ ${PHP4_POSSIBLE_INCLUDE_PATHS})
+
+if(PHP4_FOUND_INCLUDE_PATH)
+ set(php4_paths "${PHP4_POSSIBLE_INCLUDE_PATHS}")
+ foreach(php4_path Zend main TSRM)
+ set(php4_paths ${php4_paths} "${PHP4_FOUND_INCLUDE_PATH}/${php4_path}")
+ endforeach()
+ set(PHP4_INCLUDE_PATH "${php4_paths}")
+endif()
+
+find_program(PHP4_EXECUTABLE NAMES php4 php )
+
+mark_as_advanced(
+ PHP4_EXECUTABLE
+ PHP4_FOUND_INCLUDE_PATH
+ )
+
+if(APPLE)
+# this is a hack for now
+ string(APPEND CMAKE_SHARED_MODULE_CREATE_C_FLAGS
+ " -Wl,-flat_namespace")
+ foreach(symbol
+ __efree
+ __emalloc
+ __estrdup
+ __object_init_ex
+ __zend_get_parameters_array_ex
+ __zend_list_find
+ __zval_copy_ctor
+ _add_property_zval_ex
+ _alloc_globals
+ _compiler_globals
+ _convert_to_double
+ _convert_to_long
+ _zend_error
+ _zend_hash_find
+ _zend_register_internal_class_ex
+ _zend_register_list_destructors_ex
+ _zend_register_resource
+ _zend_rsrc_list_get_rsrc_type
+ _zend_wrong_param_count
+ _zval_used_for_init
+ )
+ string(APPEND CMAKE_SHARED_MODULE_CREATE_C_FLAGS
+ ",-U,${symbol}")
+ endforeach()
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(PHP4 DEFAULT_MSG PHP4_EXECUTABLE PHP4_INCLUDE_PATH)
diff --git a/Modules/FindPNG.cmake b/Modules/FindPNG.cmake
new file mode 100644
index 0000000..94d15db
--- /dev/null
+++ b/Modules/FindPNG.cmake
@@ -0,0 +1,161 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPNG
+-------
+
+Find libpng, the official reference library for the PNG image format.
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.5
+
+This module defines the following :prop_tgt:`IMPORTED` target:
+
+``PNG::PNG``
+ The libpng library, if found.
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``PNG_INCLUDE_DIRS``
+ where to find png.h, etc.
+``PNG_LIBRARIES``
+ the libraries to link against to use PNG.
+``PNG_DEFINITIONS``
+ You should add_definitions(${PNG_DEFINITIONS}) before compiling code
+ that includes png library files.
+``PNG_FOUND``
+ If false, do not try to use PNG.
+``PNG_VERSION_STRING``
+ the version of the PNG library found (since CMake 2.8.8)
+
+Obsolete variables
+^^^^^^^^^^^^^^^^^^
+
+The following variables may also be set, for backwards compatibility:
+
+``PNG_LIBRARY``
+ where to find the PNG library.
+``PNG_INCLUDE_DIR``
+ where to find the PNG headers (same as PNG_INCLUDE_DIRS)
+
+Since PNG depends on the ZLib compression library, none of the above
+will be defined unless ZLib can be found.
+#]=======================================================================]
+
+if(PNG_FIND_QUIETLY)
+ set(_FIND_ZLIB_ARG QUIET)
+endif()
+find_package(ZLIB ${_FIND_ZLIB_ARG})
+
+if(ZLIB_FOUND)
+ find_path(PNG_PNG_INCLUDE_DIR png.h PATH_SUFFIXES include/libpng)
+ mark_as_advanced(PNG_PNG_INCLUDE_DIR)
+
+ list(APPEND PNG_NAMES png libpng)
+ unset(PNG_NAMES_DEBUG)
+ set(_PNG_VERSION_SUFFIXES 17 16 15 14 12)
+ if (PNG_FIND_VERSION MATCHES "^([0-9]+)\\.([0-9]+)(\\..*)?$")
+ set(_PNG_VERSION_SUFFIX_MIN "${CMAKE_MATCH_1}${CMAKE_MATCH_2}")
+ if (PNG_FIND_VERSION_EXACT)
+ set(_PNG_VERSION_SUFFIXES ${_PNG_VERSION_SUFFIX_MIN})
+ else ()
+ string(REGEX REPLACE
+ "${_PNG_VERSION_SUFFIX_MIN}.*" "${_PNG_VERSION_SUFFIX_MIN}"
+ _PNG_VERSION_SUFFIXES "${_PNG_VERSION_SUFFIXES}")
+ endif ()
+ unset(_PNG_VERSION_SUFFIX_MIN)
+ endif ()
+ foreach(v IN LISTS _PNG_VERSION_SUFFIXES)
+ list(APPEND PNG_NAMES png${v} libpng${v} libpng${v}_static)
+ list(APPEND PNG_NAMES_DEBUG png${v}d libpng${v}d libpng${v}_staticd)
+ endforeach()
+ unset(_PNG_VERSION_SUFFIXES)
+ # For compatibility with versions prior to this multi-config search, honor
+ # any PNG_LIBRARY that is already specified and skip the search.
+ if(NOT PNG_LIBRARY)
+ find_library(PNG_LIBRARY_RELEASE NAMES ${PNG_NAMES} NAMES_PER_DIR)
+ find_library(PNG_LIBRARY_DEBUG NAMES ${PNG_NAMES_DEBUG} NAMES_PER_DIR)
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(PNG)
+ mark_as_advanced(PNG_LIBRARY_RELEASE PNG_LIBRARY_DEBUG)
+ endif()
+ unset(PNG_NAMES)
+ unset(PNG_NAMES_DEBUG)
+
+ # Set by select_library_configurations(), but we want the one from
+ # find_package_handle_standard_args() below.
+ unset(PNG_FOUND)
+
+ if (PNG_LIBRARY AND PNG_PNG_INCLUDE_DIR)
+ # png.h includes zlib.h. Sigh.
+ set(PNG_INCLUDE_DIRS ${PNG_PNG_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} )
+ set(PNG_INCLUDE_DIR ${PNG_INCLUDE_DIRS} ) # for backward compatibility
+ set(PNG_LIBRARIES ${PNG_LIBRARY} ${ZLIB_LIBRARY})
+ if((CMAKE_SYSTEM_NAME STREQUAL "Linux") AND
+ ("${PNG_LIBRARY}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$"))
+ list(APPEND PNG_LIBRARIES m)
+ endif()
+
+ if (CYGWIN)
+ if(BUILD_SHARED_LIBS)
+ # No need to define PNG_USE_DLL here, because it's default for Cygwin.
+ else()
+ set (PNG_DEFINITIONS -DPNG_STATIC)
+ set(_PNG_COMPILE_DEFINITIONS PNG_STATIC)
+ endif()
+ endif ()
+
+ if(NOT TARGET PNG::PNG)
+ add_library(PNG::PNG UNKNOWN IMPORTED)
+ set_target_properties(PNG::PNG PROPERTIES
+ INTERFACE_COMPILE_DEFINITIONS "${_PNG_COMPILE_DEFINITIONS}"
+ INTERFACE_INCLUDE_DIRECTORIES "${PNG_INCLUDE_DIRS}"
+ INTERFACE_LINK_LIBRARIES ZLIB::ZLIB)
+ if((CMAKE_SYSTEM_NAME STREQUAL "Linux") AND
+ ("${PNG_LIBRARY}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$"))
+ set_property(TARGET PNG::PNG APPEND PROPERTY
+ INTERFACE_LINK_LIBRARIES m)
+ endif()
+
+ if(EXISTS "${PNG_LIBRARY}")
+ set_target_properties(PNG::PNG PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${PNG_LIBRARY}")
+ endif()
+ if(EXISTS "${PNG_LIBRARY_RELEASE}")
+ set_property(TARGET PNG::PNG APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(PNG::PNG PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+ IMPORTED_LOCATION_RELEASE "${PNG_LIBRARY_RELEASE}")
+ endif()
+ if(EXISTS "${PNG_LIBRARY_DEBUG}")
+ set_property(TARGET PNG::PNG APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(PNG::PNG PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+ IMPORTED_LOCATION_DEBUG "${PNG_LIBRARY_DEBUG}")
+ endif()
+ endif()
+
+ unset(_PNG_COMPILE_DEFINITIONS)
+ endif ()
+
+ if (PNG_PNG_INCLUDE_DIR AND EXISTS "${PNG_PNG_INCLUDE_DIR}/png.h")
+ file(STRINGS "${PNG_PNG_INCLUDE_DIR}/png.h" png_version_str REGEX "^#define[ \t]+PNG_LIBPNG_VER_STRING[ \t]+\".+\"")
+
+ string(REGEX REPLACE "^#define[ \t]+PNG_LIBPNG_VER_STRING[ \t]+\"([^\"]+)\".*" "\\1" PNG_VERSION_STRING "${png_version_str}")
+ unset(png_version_str)
+ endif ()
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(PNG
+ REQUIRED_VARS PNG_LIBRARY PNG_PNG_INCLUDE_DIR
+ VERSION_VAR PNG_VERSION_STRING)
diff --git a/Modules/FindPackageHandleStandardArgs.cmake b/Modules/FindPackageHandleStandardArgs.cmake
new file mode 100644
index 0000000..fbcf7cd
--- /dev/null
+++ b/Modules/FindPackageHandleStandardArgs.cmake
@@ -0,0 +1,605 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPackageHandleStandardArgs
+-----------------------------
+
+This module provides functions intended to be used in :ref:`Find Modules`
+implementing :command:`find_package(<PackageName>)` calls.
+
+.. command:: find_package_handle_standard_args
+
+ This command handles the ``REQUIRED``, ``QUIET`` and version-related
+ arguments of :command:`find_package`. It also sets the
+ ``<PackageName>_FOUND`` variable. The package is considered found if all
+ variables listed contain valid results, e.g. valid filepaths.
+
+ There are two signatures:
+
+ .. code-block:: cmake
+
+ find_package_handle_standard_args(<PackageName>
+ (DEFAULT_MSG|<custom-failure-message>)
+ <required-var>...
+ )
+
+ find_package_handle_standard_args(<PackageName>
+ [FOUND_VAR <result-var>]
+ [REQUIRED_VARS <required-var>...]
+ [VERSION_VAR <version-var>]
+ [HANDLE_VERSION_RANGE]
+ [HANDLE_COMPONENTS]
+ [CONFIG_MODE]
+ [NAME_MISMATCHED]
+ [REASON_FAILURE_MESSAGE <reason-failure-message>]
+ [FAIL_MESSAGE <custom-failure-message>]
+ )
+
+ The ``<PackageName>_FOUND`` variable will be set to ``TRUE`` if all
+ the variables ``<required-var>...`` are valid and any optional
+ constraints are satisfied, and ``FALSE`` otherwise. A success or
+ failure message may be displayed based on the results and on
+ whether the ``REQUIRED`` and/or ``QUIET`` option was given to
+ the :command:`find_package` call.
+
+ The options are:
+
+ ``(DEFAULT_MSG|<custom-failure-message>)``
+ In the simple signature this specifies the failure message.
+ Use ``DEFAULT_MSG`` to ask for a default message to be computed
+ (recommended). Not valid in the full signature.
+
+ ``FOUND_VAR <result-var>``
+ .. deprecated:: 3.3
+
+ Specifies either ``<PackageName>_FOUND`` or
+ ``<PACKAGENAME>_FOUND`` as the result variable. This exists only
+ for compatibility with older versions of CMake and is now ignored.
+ Result variables of both names are always set for compatibility.
+
+ ``REQUIRED_VARS <required-var>...``
+ Specify the variables which are required for this package.
+ These may be named in the generated failure message asking the
+ user to set the missing variable values. Therefore these should
+ typically be cache entries such as ``FOO_LIBRARY`` and not output
+ variables like ``FOO_LIBRARIES``.
+
+ .. versionchanged:: 3.18
+ If ``HANDLE_COMPONENTS`` is specified, this option can be omitted.
+
+ ``VERSION_VAR <version-var>``
+ Specify the name of a variable that holds the version of the package
+ that has been found. This version will be checked against the
+ (potentially) specified required version given to the
+ :command:`find_package` call, including its ``EXACT`` option.
+ The default messages include information about the required
+ version and the version which has been actually found, both
+ if the version is ok or not.
+
+ ``HANDLE_VERSION_RANGE``
+ .. versionadded:: 3.19
+
+ Enable handling of a version range, if one is specified. Without this
+ option, a developer warning will be displayed if a version range is
+ specified.
+
+ ``HANDLE_COMPONENTS``
+ Enable handling of package components. In this case, the command
+ will report which components have been found and which are missing,
+ and the ``<PackageName>_FOUND`` variable will be set to ``FALSE``
+ if any of the required components (i.e. not the ones listed after
+ the ``OPTIONAL_COMPONENTS`` option of :command:`find_package`) are
+ missing.
+
+ ``CONFIG_MODE``
+ Specify that the calling find module is a wrapper around a
+ call to ``find_package(<PackageName> NO_MODULE)``. This implies
+ a ``VERSION_VAR`` value of ``<PackageName>_VERSION``. The command
+ will automatically check whether the package configuration file
+ was found.
+
+ ``REASON_FAILURE_MESSAGE <reason-failure-message>``
+ .. versionadded:: 3.16
+
+ Specify a custom message of the reason for the failure which will be
+ appended to the default generated message.
+
+ ``FAIL_MESSAGE <custom-failure-message>``
+ Specify a custom failure message instead of using the default
+ generated message. Not recommended.
+
+ ``NAME_MISMATCHED``
+ .. versionadded:: 3.17
+
+ Indicate that the ``<PackageName>`` does not match
+ ``${CMAKE_FIND_PACKAGE_NAME}``. This is usually a mistake and raises a
+ warning, but it may be intentional for usage of the command for components
+ of a larger package.
+
+Example for the simple signature:
+
+.. code-block:: cmake
+
+ find_package_handle_standard_args(LibXml2 DEFAULT_MSG
+ LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
+
+The ``LibXml2`` package is considered to be found if both
+``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` are valid.
+Then also ``LibXml2_FOUND`` is set to ``TRUE``. If it is not found
+and ``REQUIRED`` was used, it fails with a
+:command:`message(FATAL_ERROR)`, independent whether ``QUIET`` was
+used or not. If it is found, success will be reported, including
+the content of the first ``<required-var>``. On repeated CMake runs,
+the same message will not be printed again.
+
+.. note::
+
+ If ``<PackageName>`` does not match ``CMAKE_FIND_PACKAGE_NAME`` for the
+ calling module, a warning that there is a mismatch is given. The
+ ``FPHSA_NAME_MISMATCHED`` variable may be set to bypass the warning if using
+ the old signature and the ``NAME_MISMATCHED`` argument using the new
+ signature. To avoid forcing the caller to require newer versions of CMake for
+ usage, the variable's value will be used if defined when the
+ ``NAME_MISMATCHED`` argument is not passed for the new signature (but using
+ both is an error)..
+
+Example for the full signature:
+
+.. code-block:: cmake
+
+ find_package_handle_standard_args(LibArchive
+ REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR
+ VERSION_VAR LibArchive_VERSION)
+
+In this case, the ``LibArchive`` package is considered to be found if
+both ``LibArchive_LIBRARY`` and ``LibArchive_INCLUDE_DIR`` are valid.
+Also the version of ``LibArchive`` will be checked by using the version
+contained in ``LibArchive_VERSION``. Since no ``FAIL_MESSAGE`` is given,
+the default messages will be printed.
+
+Another example for the full signature:
+
+.. code-block:: cmake
+
+ find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
+ find_package_handle_standard_args(Automoc4 CONFIG_MODE)
+
+In this case, a ``FindAutmoc4.cmake`` module wraps a call to
+``find_package(Automoc4 NO_MODULE)`` and adds an additional search
+directory for ``automoc4``. Then the call to
+``find_package_handle_standard_args`` produces a proper success/failure
+message.
+
+.. command:: find_package_check_version
+
+ .. versionadded:: 3.19
+
+ Helper function which can be used to check if a ``<version>`` is valid
+ against version-related arguments of :command:`find_package`.
+
+ .. code-block:: cmake
+
+ find_package_check_version(<version> <result-var>
+ [HANDLE_VERSION_RANGE]
+ [RESULT_MESSAGE_VARIABLE <message-var>]
+ )
+
+ The ``<result-var>`` will hold a boolean value giving the result of the check.
+
+ The options are:
+
+ ``HANDLE_VERSION_RANGE``
+ Enable handling of a version range, if one is specified. Without this
+ option, a developer warning will be displayed if a version range is
+ specified.
+
+ ``RESULT_MESSAGE_VARIABLE <message-var>``
+ Specify a variable to get back a message describing the result of the check.
+
+Example for the usage:
+
+.. code-block:: cmake
+
+ find_package_check_version(1.2.3 result HANDLE_VERSION_RANGE
+ RESULT_MESSAGE_VARIABLE reason)
+ if (result)
+ message (STATUS "${reason}")
+ else()
+ message (FATAL_ERROR "${reason}")
+ endif()
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake)
+
+
+cmake_policy(PUSH)
+# numbers and boolean constants
+cmake_policy (SET CMP0012 NEW)
+# IN_LIST operator
+cmake_policy (SET CMP0057 NEW)
+
+
+# internal helper macro
+macro(_FPHSA_FAILURE_MESSAGE _msg)
+ set (__msg "${_msg}")
+ if (FPHSA_REASON_FAILURE_MESSAGE)
+ string(APPEND __msg "\n Reason given by package: ${FPHSA_REASON_FAILURE_MESSAGE}\n")
+ endif()
+ if (${_NAME}_FIND_REQUIRED)
+ message(FATAL_ERROR "${__msg}")
+ else ()
+ if (NOT ${_NAME}_FIND_QUIETLY)
+ message(STATUS "${__msg}")
+ endif ()
+ endif ()
+endmacro()
+
+
+# internal helper macro to generate the failure message when used in CONFIG_MODE:
+macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
+ # <PackageName>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:
+ if(${_NAME}_CONFIG)
+ _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing:${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})")
+ else()
+ # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.
+ # List them all in the error message:
+ if(${_NAME}_CONSIDERED_CONFIGS)
+ set(configsText "")
+ list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)
+ math(EXPR configsCount "${configsCount} - 1")
+ foreach(currentConfigIndex RANGE ${configsCount})
+ list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)
+ list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)
+ string(APPEND configsText "\n ${filename} (version ${version})")
+ endforeach()
+ if (${_NAME}_NOT_FOUND_MESSAGE)
+ if (FPHSA_REASON_FAILURE_MESSAGE)
+ string(PREPEND FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}\n ")
+ else()
+ set(FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}")
+ endif()
+ else()
+ string(APPEND configsText "\n")
+ endif()
+ _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:${configsText}")
+
+ else()
+ # Simple case: No Config-file was found at all:
+ _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}")
+ endif()
+ endif()
+endmacro()
+
+
+function(FIND_PACKAGE_CHECK_VERSION version result)
+ cmake_parse_arguments (PARSE_ARGV 2 FPCV "HANDLE_VERSION_RANGE;NO_AUTHOR_WARNING_VERSION_RANGE" "RESULT_MESSAGE_VARIABLE" "")
+
+ if (FPCV_UNPARSED_ARGUMENTS)
+ message (FATAL_ERROR "find_package_check_version(): ${FPCV_UNPARSED_ARGUMENTS}: unexpected arguments")
+ endif()
+ if ("RESULT_MESSAGE_VARIABLE" IN_LIST FPCV_KEYWORDS_MISSING_VALUES)
+ message (FATAL_ERROR "find_package_check_version(): RESULT_MESSAGE_VARIABLE expects an argument")
+ endif()
+
+ set (${result} FALSE PARENT_SCOPE)
+ if (FPCV_RESULT_MESSAGE_VARIABLE)
+ unset (${FPCV_RESULT_MESSAGE_VARIABLE} PARENT_SCOPE)
+ endif()
+
+ if (_CMAKE_FPHSA_PACKAGE_NAME)
+ set (package "${_CMAKE_FPHSA_PACKAGE_NAME}")
+ elseif (CMAKE_FIND_PACKAGE_NAME)
+ set (package "${CMAKE_FIND_PACKAGE_NAME}")
+ else()
+ message (FATAL_ERROR "find_package_check_version(): Cannot be used outside a 'Find Module'")
+ endif()
+
+ if (NOT FPCV_NO_AUTHOR_WARNING_VERSION_RANGE
+ AND ${package}_FIND_VERSION_RANGE AND NOT FPCV_HANDLE_VERSION_RANGE)
+ message(AUTHOR_WARNING
+ "`find_package()` specify a version range but the option "
+ "HANDLE_VERSION_RANGE` is not passed to `find_package_check_version()`. "
+ "Only the lower endpoint of the range will be used.")
+ endif()
+
+
+ set (version_ok FALSE)
+ unset (version_msg)
+
+ if (FPCV_HANDLE_VERSION_RANGE AND ${package}_FIND_VERSION_RANGE)
+ 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)))
+ set (version_ok TRUE)
+ set(version_msg "(found suitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\")")
+ else()
+ set(version_msg "Found unsuitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\"")
+ endif()
+ elseif (DEFINED ${package}_FIND_VERSION)
+ if(${package}_FIND_VERSION_EXACT) # exact version required
+ # count the dots in the version string
+ string(REGEX REPLACE "[^.]" "" version_dots "${version}")
+ # add one dot because there is one dot more than there are components
+ string(LENGTH "${version_dots}." version_dots)
+ if (version_dots GREATER ${package}_FIND_VERSION_COUNT)
+ # Because of the C++ implementation of find_package() ${package}_FIND_VERSION_COUNT
+ # is at most 4 here. Therefore a simple lookup table is used.
+ if (${package}_FIND_VERSION_COUNT EQUAL 1)
+ set(version_regex "[^.]*")
+ elseif (${package}_FIND_VERSION_COUNT EQUAL 2)
+ set(version_regex "[^.]*\\.[^.]*")
+ elseif (${package}_FIND_VERSION_COUNT EQUAL 3)
+ set(version_regex "[^.]*\\.[^.]*\\.[^.]*")
+ else()
+ set(version_regex "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*")
+ endif()
+ string(REGEX REPLACE "^(${version_regex})\\..*" "\\1" version_head "${version}")
+ if (NOT ${package}_FIND_VERSION VERSION_EQUAL version_head)
+ set(version_msg "Found unsuitable version \"${version}\", but required is exact version \"${${package}_FIND_VERSION}\"")
+ else ()
+ set(version_ok TRUE)
+ set(version_msg "(found suitable exact version \"${_FOUND_VERSION}\")")
+ endif ()
+ else ()
+ if (NOT ${package}_FIND_VERSION VERSION_EQUAL version)
+ set(version_msg "Found unsuitable version \"${version}\", but required is exact version \"${${package}_FIND_VERSION}\"")
+ else ()
+ set(version_ok TRUE)
+ set(version_msg "(found suitable exact version \"${version}\")")
+ endif ()
+ endif ()
+ else() # minimum version
+ if (${package}_FIND_VERSION VERSION_GREATER version)
+ set(version_msg "Found unsuitable version \"${version}\", but required is at least \"${${package}_FIND_VERSION}\"")
+ else()
+ set(version_ok TRUE)
+ set(version_msg "(found suitable version \"${version}\", minimum required is \"${${package}_FIND_VERSION}\")")
+ endif()
+ endif()
+ else ()
+ set(version_ok TRUE)
+ set(version_msg "(found version \"${version}\")")
+ endif()
+
+ set (${result} ${version_ok} PARENT_SCOPE)
+ if (FPCV_RESULT_MESSAGE_VARIABLE)
+ set (${FPCV_RESULT_MESSAGE_VARIABLE} "${version_msg}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+
+function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
+
+ # Set up the arguments for `cmake_parse_arguments`.
+ set(options CONFIG_MODE HANDLE_COMPONENTS NAME_MISMATCHED HANDLE_VERSION_RANGE)
+ set(oneValueArgs FAIL_MESSAGE REASON_FAILURE_MESSAGE VERSION_VAR FOUND_VAR)
+ set(multiValueArgs REQUIRED_VARS)
+
+ # Check whether we are in 'simple' or 'extended' mode:
+ set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} )
+ list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
+
+ unset(FPHSA_NAME_MISMATCHED_override)
+ if (DEFINED FPHSA_NAME_MISMATCHED)
+ # If the variable NAME_MISMATCHED variable is set, error if it is passed as
+ # an argument. The former is for old signatures, the latter is for new
+ # signatures.
+ list(FIND ARGN "NAME_MISMATCHED" name_mismatched_idx)
+ if (NOT name_mismatched_idx EQUAL "-1")
+ message(FATAL_ERROR
+ "The `NAME_MISMATCHED` argument may only be specified by the argument or "
+ "the variable, not both.")
+ endif ()
+
+ # But use the variable if it is not an argument to avoid forcing minimum
+ # CMake version bumps for calling modules.
+ set(FPHSA_NAME_MISMATCHED_override "${FPHSA_NAME_MISMATCHED}")
+ endif ()
+
+ if(${INDEX} EQUAL -1)
+ set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
+ set(FPHSA_REQUIRED_VARS ${ARGN})
+ set(FPHSA_VERSION_VAR)
+ else()
+ cmake_parse_arguments(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN})
+
+ if(FPHSA_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if(NOT FPHSA_FAIL_MESSAGE)
+ set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG")
+ endif()
+
+ # In config-mode, we rely on the variable <PackageName>_CONFIG, which is set by find_package()
+ # when it successfully found the config-file, including version checking:
+ if(FPHSA_CONFIG_MODE)
+ list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)
+ list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)
+ set(FPHSA_VERSION_VAR ${_NAME}_VERSION)
+ endif()
+
+ if(NOT FPHSA_REQUIRED_VARS AND NOT FPHSA_HANDLE_COMPONENTS)
+ message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()")
+ endif()
+ endif()
+
+ if (DEFINED FPHSA_NAME_MISMATCHED_override)
+ set(FPHSA_NAME_MISMATCHED "${FPHSA_NAME_MISMATCHED_override}")
+ endif ()
+
+ if (DEFINED CMAKE_FIND_PACKAGE_NAME
+ AND NOT FPHSA_NAME_MISMATCHED
+ AND NOT _NAME STREQUAL CMAKE_FIND_PACKAGE_NAME)
+ message(AUTHOR_WARNING
+ "The package name passed to `find_package_handle_standard_args` "
+ "(${_NAME}) does not match the name of the calling package "
+ "(${CMAKE_FIND_PACKAGE_NAME}). This can lead to problems in calling "
+ "code that expects `find_package` result variables (e.g., `_FOUND`) "
+ "to follow a certain pattern.")
+ endif ()
+
+ if (${_NAME}_FIND_VERSION_RANGE AND NOT FPHSA_HANDLE_VERSION_RANGE)
+ message(AUTHOR_WARNING
+ "`find_package()` specify a version range but the module ${_NAME} does "
+ "not support this capability. Only the lower endpoint of the range "
+ "will be used.")
+ endif()
+
+ # to propagate package name to FIND_PACKAGE_CHECK_VERSION
+ set(_CMAKE_FPHSA_PACKAGE_NAME "${_NAME}")
+
+ # now that we collected all arguments, process them
+
+ if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG")
+ set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}")
+ endif()
+
+ if (FPHSA_REQUIRED_VARS)
+ list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)
+ endif()
+
+ string(TOUPPER ${_NAME} _NAME_UPPER)
+ string(TOLOWER ${_NAME} _NAME_LOWER)
+
+ if(FPHSA_FOUND_VAR)
+ set(_FOUND_VAR_UPPER ${_NAME_UPPER}_FOUND)
+ set(_FOUND_VAR_MIXED ${_NAME}_FOUND)
+ if(FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_MIXED OR FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_UPPER)
+ set(_FOUND_VAR ${FPHSA_FOUND_VAR})
+ else()
+ message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_FOUND_VAR_MIXED}\" and \"${_FOUND_VAR_UPPER}\" are valid names.")
+ endif()
+ else()
+ set(_FOUND_VAR ${_NAME_UPPER}_FOUND)
+ endif()
+
+ # collect all variables which were not found, so they can be printed, so the
+ # user knows better what went wrong (#6375)
+ set(MISSING_VARS "")
+ set(DETAILS "")
+ # check if all passed variables are valid
+ set(FPHSA_FOUND_${_NAME} TRUE)
+ foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})
+ if(NOT ${_CURRENT_VAR})
+ set(FPHSA_FOUND_${_NAME} FALSE)
+ string(APPEND MISSING_VARS " ${_CURRENT_VAR}")
+ else()
+ string(APPEND DETAILS "[${${_CURRENT_VAR}}]")
+ endif()
+ endforeach()
+ if(FPHSA_FOUND_${_NAME})
+ set(${_NAME}_FOUND TRUE)
+ set(${_NAME_UPPER}_FOUND TRUE)
+ else()
+ set(${_NAME}_FOUND FALSE)
+ set(${_NAME_UPPER}_FOUND FALSE)
+ endif()
+
+ # component handling
+ unset(FOUND_COMPONENTS_MSG)
+ unset(MISSING_COMPONENTS_MSG)
+
+ if(FPHSA_HANDLE_COMPONENTS)
+ foreach(comp ${${_NAME}_FIND_COMPONENTS})
+ if(${_NAME}_${comp}_FOUND)
+
+ if(NOT DEFINED FOUND_COMPONENTS_MSG)
+ set(FOUND_COMPONENTS_MSG "found components:")
+ endif()
+ string(APPEND FOUND_COMPONENTS_MSG " ${comp}")
+
+ else()
+
+ if(NOT DEFINED MISSING_COMPONENTS_MSG)
+ set(MISSING_COMPONENTS_MSG "missing components:")
+ endif()
+ string(APPEND MISSING_COMPONENTS_MSG " ${comp}")
+
+ if(${_NAME}_FIND_REQUIRED_${comp})
+ set(${_NAME}_FOUND FALSE)
+ string(APPEND MISSING_VARS " ${comp}")
+ endif()
+
+ endif()
+ endforeach()
+ set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}")
+ string(APPEND DETAILS "[c${COMPONENT_MSG}]")
+ endif()
+
+ # version handling:
+ set(VERSION_MSG "")
+ set(VERSION_OK TRUE)
+
+ # check with DEFINED here as the requested or found version may be "0"
+ if (DEFINED ${_NAME}_FIND_VERSION)
+ if(DEFINED ${FPHSA_VERSION_VAR})
+ set(_FOUND_VERSION ${${FPHSA_VERSION_VAR}})
+ if (FPHSA_HANDLE_VERSION_RANGE)
+ set (FPCV_HANDLE_VERSION_RANGE HANDLE_VERSION_RANGE)
+ 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
+ ${FPCV_HANDLE_VERSION_RANGE})
+ else()
+ # if the package was not found, but a version was given, add that to the output:
+ if(${_NAME}_FIND_VERSION_EXACT)
+ set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")")
+ elseif (FPHSA_HANDLE_VERSION_RANGE AND ${_NAME}_FIND_VERSION_RANGE)
+ set(VERSION_MSG "(Required is version range \"${${_NAME}_FIND_VERSION_RANGE}\")")
+ else()
+ set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")")
+ endif()
+ endif()
+ else ()
+ # Check with DEFINED as the found version may be 0.
+ if(DEFINED ${FPHSA_VERSION_VAR})
+ set(VERSION_MSG "(found version \"${${FPHSA_VERSION_VAR}}\")")
+ endif()
+ endif ()
+
+ if(VERSION_OK)
+ string(APPEND DETAILS "[v${${FPHSA_VERSION_VAR}}(${${_NAME}_FIND_VERSION})]")
+ else()
+ set(${_NAME}_FOUND FALSE)
+ endif()
+
+
+ # print the result:
+ if (${_NAME}_FOUND)
+ FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}")
+ else ()
+
+ if(FPHSA_CONFIG_MODE)
+ _FPHSA_HANDLE_FAILURE_CONFIG_MODE()
+ else()
+ if(NOT VERSION_OK)
+ set(RESULT_MSG)
+ if (_FIRST_REQUIRED_VAR)
+ string (APPEND RESULT_MSG "found ${${_FIRST_REQUIRED_VAR}}")
+ endif()
+ if (COMPONENT_MSG)
+ if (RESULT_MSG)
+ string (APPEND RESULT_MSG ", ")
+ endif()
+ string (APPEND RESULT_MSG "${FOUND_COMPONENTS_MSG}")
+ endif()
+ _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (${RESULT_MSG})")
+ else()
+ _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing:${MISSING_VARS}) ${VERSION_MSG}")
+ endif()
+ endif()
+
+ endif ()
+
+ set(${_NAME}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)
+ set(${_NAME_UPPER}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)
+endfunction()
+
+
+cmake_policy(POP)
diff --git a/Modules/FindPackageMessage.cmake b/Modules/FindPackageMessage.cmake
new file mode 100644
index 0000000..0628b98
--- /dev/null
+++ b/Modules/FindPackageMessage.cmake
@@ -0,0 +1,48 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPackageMessage
+------------------
+
+.. code-block:: cmake
+
+ find_package_message(<name> "message for user" "find result details")
+
+This function is intended to be used in FindXXX.cmake modules files.
+It will print a message once for each unique find result. This is
+useful for telling the user where a package was found. The first
+argument specifies the name (XXX) of the package. The second argument
+specifies the message to display. The third argument lists details
+about the find result so that if they change the message will be
+displayed again. The macro also obeys the QUIET argument to the
+find_package command.
+
+Example:
+
+.. code-block:: cmake
+
+ if(X11_FOUND)
+ find_package_message(X11 "Found X11: ${X11_X11_LIB}"
+ "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]")
+ else()
+ ...
+ endif()
+#]=======================================================================]
+
+function(find_package_message pkg msg details)
+ # Avoid printing a message repeatedly for the same find result.
+ if(NOT ${pkg}_FIND_QUIETLY)
+ string(REPLACE "\n" "" details "${details}")
+ set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg})
+ if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}")
+ # The message has not yet been printed.
+ message(STATUS "${msg}")
+
+ # Save the find details in the cache to avoid printing the same
+ # message again.
+ set("${DETAILS_VAR}" "${details}"
+ CACHE INTERNAL "Details about finding ${pkg}")
+ endif()
+ endif()
+endfunction()
diff --git a/Modules/FindPatch.cmake b/Modules/FindPatch.cmake
new file mode 100644
index 0000000..4108651
--- /dev/null
+++ b/Modules/FindPatch.cmake
@@ -0,0 +1,71 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPatch
+---------
+
+.. versionadded:: 3.10
+
+The module defines the following variables:
+
+``Patch_EXECUTABLE``
+ Path to patch command-line executable.
+``Patch_FOUND``
+ True if the patch command-line executable was found.
+
+The following :prop_tgt:`IMPORTED` targets are also defined:
+
+``Patch::patch``
+ The command-line executable.
+
+Example usage:
+
+.. code-block:: cmake
+
+ find_package(Patch)
+ if(Patch_FOUND)
+ message("Patch found: ${Patch_EXECUTABLE}")
+ endif()
+#]=======================================================================]
+
+set(_doc "Patch command line executable")
+set(_patch_path )
+
+if(CMAKE_HOST_WIN32)
+ set(_patch_path
+ "$ENV{LOCALAPPDATA}/Programs/Git/bin"
+ "$ENV{LOCALAPPDATA}/Programs/Git/usr/bin"
+ "$ENV{APPDATA}/Programs/Git/bin"
+ "$ENV{APPDATA}/Programs/Git/usr/bin"
+ )
+endif()
+
+# First search the PATH
+find_program(Patch_EXECUTABLE
+ NAME patch
+ PATHS ${_patch_path}
+ DOC ${_doc}
+ )
+
+if(CMAKE_HOST_WIN32)
+ # Now look for installations in Git/ directories under typical installation
+ # prefixes on Windows.
+ find_program(Patch_EXECUTABLE
+ NAMES patch
+ PATH_SUFFIXES Git/usr/bin Git/bin GnuWin32/bin
+ DOC ${_doc}
+ )
+endif()
+
+if(Patch_EXECUTABLE AND NOT TARGET Patch::patch)
+ add_executable(Patch::patch IMPORTED)
+ set_property(TARGET Patch::patch PROPERTY IMPORTED_LOCATION ${Patch_EXECUTABLE})
+endif()
+
+unset(_patch_path)
+unset(_doc)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(Patch
+ REQUIRED_VARS Patch_EXECUTABLE)
diff --git a/Modules/FindPerl.cmake b/Modules/FindPerl.cmake
new file mode 100644
index 0000000..c14e059
--- /dev/null
+++ b/Modules/FindPerl.cmake
@@ -0,0 +1,87 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPerl
+--------
+
+Find perl
+
+this module looks for Perl
+
+::
+
+ PERL_EXECUTABLE - the full path to perl
+ PERL_FOUND - If false, don't attempt to use perl.
+ PERL_VERSION_STRING - version of perl found (since CMake 2.8.8)
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindCygwin.cmake)
+
+set(PERL_POSSIBLE_BIN_PATHS
+ ${CYGWIN_INSTALL_PATH}/bin
+ )
+
+if(WIN32)
+ get_filename_component(
+ ActivePerl_CurrentVersion
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ActiveState\\ActivePerl;CurrentVersion]"
+ NAME)
+ set(PERL_POSSIBLE_BIN_PATHS ${PERL_POSSIBLE_BIN_PATHS}
+ "C:/Perl/bin"
+ "C:/Strawberry/perl/bin"
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\ActiveState\\ActivePerl\\${ActivePerl_CurrentVersion}]/bin
+ )
+endif()
+
+find_program(PERL_EXECUTABLE
+ NAMES perl
+ PATHS ${PERL_POSSIBLE_BIN_PATHS}
+ )
+
+if(PERL_EXECUTABLE)
+ ### PERL_VERSION
+ execute_process(
+ COMMAND
+ ${PERL_EXECUTABLE} -V:version
+ OUTPUT_VARIABLE
+ PERL_VERSION_OUTPUT_VARIABLE
+ RESULT_VARIABLE
+ PERL_VERSION_RESULT_VARIABLE
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if(NOT PERL_VERSION_RESULT_VARIABLE AND NOT PERL_VERSION_OUTPUT_VARIABLE MATCHES "^version='UNKNOWN'")
+ string(REGEX REPLACE "version='([^']+)'.*" "\\1" PERL_VERSION_STRING ${PERL_VERSION_OUTPUT_VARIABLE})
+ else()
+ execute_process(
+ COMMAND ${PERL_EXECUTABLE} -v
+ OUTPUT_VARIABLE PERL_VERSION_OUTPUT_VARIABLE
+ RESULT_VARIABLE PERL_VERSION_RESULT_VARIABLE
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if(NOT PERL_VERSION_RESULT_VARIABLE AND PERL_VERSION_OUTPUT_VARIABLE MATCHES "This is perl.*[ \\(]v([0-9\\._]+)[ \\)]")
+ set(PERL_VERSION_STRING "${CMAKE_MATCH_1}")
+ elseif(NOT PERL_VERSION_RESULT_VARIABLE AND PERL_VERSION_OUTPUT_VARIABLE MATCHES "This is perl, version ([0-9\\._]+) +")
+ set(PERL_VERSION_STRING "${CMAKE_MATCH_1}")
+ endif()
+ endif()
+endif()
+
+# Deprecated settings for compatibility with CMake1.4
+set(PERL ${PERL_EXECUTABLE})
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+if (CMAKE_FIND_PACKAGE_NAME STREQUAL "PerlLibs")
+ # FindPerlLibs include()'s this module. It's an old pattern, but rather than
+ # trying to suppress this from outside the module (which is then sensitive to
+ # the contents, detect the case in this module and suppress it explicitly.
+ set(FPHSA_NAME_MISMATCHED 1)
+endif ()
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Perl
+ REQUIRED_VARS PERL_EXECUTABLE
+ VERSION_VAR PERL_VERSION_STRING)
+unset(FPHSA_NAME_MISMATCHED)
+
+mark_as_advanced(PERL_EXECUTABLE)
diff --git a/Modules/FindPerlLibs.cmake b/Modules/FindPerlLibs.cmake
new file mode 100644
index 0000000..d576b86
--- /dev/null
+++ b/Modules/FindPerlLibs.cmake
@@ -0,0 +1,162 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPerlLibs
+------------
+
+Find Perl libraries
+
+This module finds if PERL is installed and determines where the
+include files and libraries are. It also determines what the name of
+the library is. This code sets the following variables:
+
+::
+
+ PERLLIBS_FOUND = True if perl.h & libperl were found
+ PERL_INCLUDE_PATH = path to where perl.h is found
+ PERL_LIBRARY = path to libperl
+ PERL_EXECUTABLE = full path to the perl binary
+
+
+
+The minimum required version of Perl can be specified using the
+standard syntax, e.g. find_package(PerlLibs 6.0)
+
+::
+
+ The following variables are also available if needed
+ (introduced after CMake 2.6.4)
+
+
+
+::
+
+ PERL_SITESEARCH = path to the sitesearch install dir (-V:installsitesearch)
+ PERL_SITEARCH = path to the sitelib install directory (-V:installsitearch)
+ PERL_SITELIB = path to the sitelib install directory (-V:installsitelib)
+ PERL_VENDORARCH = path to the vendor arch install directory (-V:installvendorarch)
+ PERL_VENDORLIB = path to the vendor lib install directory (-V:installvendorlib)
+ PERL_ARCHLIB = path to the core arch lib install directory (-V:archlib)
+ PERL_PRIVLIB = path to the core priv lib install directory (-V:privlib)
+ PERL_UPDATE_ARCHLIB = path to the update arch lib install directory (-V:installarchlib)
+ PERL_UPDATE_PRIVLIB = path to the update priv lib install directory (-V:installprivlib)
+ PERL_EXTRA_C_FLAGS = Compilation flags used to build perl
+#]=======================================================================]
+
+# find the perl executable
+include(${CMAKE_CURRENT_LIST_DIR}/FindPerl.cmake)
+
+if (PERL_EXECUTABLE)
+
+ function (perl_get_info _pgi_info tag)
+ cmake_parse_arguments(_PGI "IS_PATH" "" "" ${ARGN})
+
+ set (${_pgi_info} NOTFOUND PARENT_SCOPE)
+
+ execute_process(COMMAND "${PERL_EXECUTABLE}" -V:${tag}
+ OUTPUT_VARIABLE result
+ RESULT_VARIABLE status)
+
+ if (NOT status)
+ string(REGEX REPLACE "${tag}='([^']*)'.*" "\\1" result "${result}")
+ if (_PGI_IS_PATH)
+ file(TO_CMAKE_PATH "${result}" result)
+ endif()
+ set (${_pgi_info} "${result}" PARENT_SCOPE)
+ endif ()
+ endfunction()
+
+ ### PERL_PREFIX
+ perl_get_info(PERL_PREFIX prefix IS_PATH)
+
+ ### PERL_ARCHNAME
+ perl_get_info(PERL_ARCHNAME archname)
+
+ ### PERL_EXTRA_C_FLAGS
+ perl_get_info(PERL_EXTRA_C_FLAGS cppflags)
+
+ ### PERL_SITESEARCH
+ perl_get_info(PERL_SITESEARCH installsitesearch IS_PATH)
+
+ ### PERL_SITEARCH
+ perl_get_info(PERL_SITEARCH installsitearch IS_PATH)
+
+ ### PERL_SITELIB
+ perl_get_info(PERL_SITELIB installsitelib IS_PATH)
+
+ ### PERL_VENDORARCH
+ perl_get_info(PERL_VENDORARCH installvendorarch IS_PATH)
+
+ ### PERL_VENDORLIB
+ perl_get_info(PERL_VENDORLIB installvendorlib IS_PATH)
+
+ ### PERL_ARCHLIB
+ perl_get_info(PERL_ARCHLIB archlib IS_PATH)
+
+ ### PERL_PRIVLIB
+ perl_get_info(PERL_PRIVLIB privlib IS_PATH)
+
+ ### PERL_UPDATE_ARCHLIB
+ perl_get_info(PERL_UPDATE_ARCHLIB installarchlib IS_PATH)
+
+ ### PERL_UPDATE_PRIVLIB
+ perl_get_info(PERL_UPDATE_PRIVLIB installprivlib IS_PATH)
+
+ ### PERL_POSSIBLE_LIBRARY_NAMES
+ perl_get_info(PERL_POSSIBLE_LIBRARY_NAMES libperl)
+ if (NOT PERL_POSSIBLE_LIBRARY_NAMES)
+ set(PERL_POSSIBLE_LIBRARY_NAMES perl${PERL_VERSION_STRING} perl)
+ endif()
+ if(CMAKE_SYSTEM_NAME MATCHES "CYGWIN")
+ list (APPEND PERL_POSSIBLE_LIBRARY_NAMES perl${PERL_VERSION_STRING})
+ endif()
+ if (CMAKE_SYSTEM_NAME MATCHES "MSYS|CYGWIN")
+ # on MSYS and CYGWIN environments, current perl -V:libperl gives shared library name
+ # rather than the import library. So, extends possible library names
+ list (APPEND PERL_POSSIBLE_LIBRARY_NAMES perl)
+ endif()
+
+ ### PERL_INCLUDE_PATH
+ find_path(PERL_INCLUDE_PATH
+ NAMES
+ perl.h
+ PATHS
+ "${PERL_UPDATE_ARCHLIB}/CORE"
+ "${PERL_ARCHLIB}/CORE"
+ /usr/lib/perl5/${PERL_VERSION_STRING}/${PERL_ARCHNAME}/CORE
+ /usr/lib/perl/${PERL_VERSION_STRING}/${PERL_ARCHNAME}/CORE
+ /usr/lib/perl5/${PERL_VERSION_STRING}/CORE
+ /usr/lib/perl/${PERL_VERSION_STRING}/CORE
+ )
+
+ ### PERL_LIBRARY
+ find_library(PERL_LIBRARY
+ NAMES
+ ${PERL_POSSIBLE_LIBRARY_NAMES}
+ PATHS
+ "${PERL_UPDATE_ARCHLIB}/CORE"
+ "${PERL_ARCHLIB}/CORE"
+ /usr/lib/perl5/${PERL_VERSION_STRING}/${PERL_ARCHNAME}/CORE
+ /usr/lib/perl/${PERL_VERSION_STRING}/${PERL_ARCHNAME}/CORE
+ /usr/lib/perl5/${PERL_VERSION_STRING}/CORE
+ /usr/lib/perl/${PERL_VERSION_STRING}/CORE
+ )
+
+endif ()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(PerlLibs REQUIRED_VARS PERL_LIBRARY PERL_INCLUDE_PATH
+ VERSION_VAR PERL_VERSION_STRING)
+
+# Introduced after CMake 2.6.4 to bring module into compliance
+set(PERL_INCLUDE_DIR ${PERL_INCLUDE_PATH})
+set(PERL_INCLUDE_DIRS ${PERL_INCLUDE_PATH})
+set(PERL_LIBRARIES ${PERL_LIBRARY})
+# For backward compatibility with CMake before 2.8.8
+set(PERL_VERSION ${PERL_VERSION_STRING})
+
+mark_as_advanced(
+ PERL_INCLUDE_PATH
+ PERL_LIBRARY
+)
diff --git a/Modules/FindPhysFS.cmake b/Modules/FindPhysFS.cmake
new file mode 100644
index 0000000..a32f83a
--- /dev/null
+++ b/Modules/FindPhysFS.cmake
@@ -0,0 +1,42 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPhysFS
+----------
+
+
+
+Locate PhysFS library This module defines PHYSFS_LIBRARY, the name of
+the library to link against PHYSFS_FOUND, if false, do not try to link
+to PHYSFS PHYSFS_INCLUDE_DIR, where to find physfs.h
+
+$PHYSFSDIR is an environment variable that would correspond to the
+./configure --prefix=$PHYSFSDIR used in building PHYSFS.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+find_path(PHYSFS_INCLUDE_DIR physfs.h
+ HINTS
+ ENV PHYSFSDIR
+ PATH_SUFFIXES include/physfs include
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /opt
+)
+
+find_library(PHYSFS_LIBRARY
+ NAMES physfs
+ HINTS
+ ENV PHYSFSDIR
+ PATH_SUFFIXES lib
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /opt
+)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(PhysFS DEFAULT_MSG PHYSFS_LIBRARY PHYSFS_INCLUDE_DIR)
diff --git a/Modules/FindPike.cmake b/Modules/FindPike.cmake
new file mode 100644
index 0000000..b78db2a
--- /dev/null
+++ b/Modules/FindPike.cmake
@@ -0,0 +1,31 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPike
+--------
+
+Find Pike
+
+This module finds if PIKE is installed and determines where the
+include files and libraries are. It also determines what the name of
+the library is. This code sets the following variables:
+
+::
+
+ PIKE_INCLUDE_PATH = path to where program.h is found
+ PIKE_EXECUTABLE = full path to the pike binary
+#]=======================================================================]
+
+find_path(PIKE_INCLUDE_PATH program.h
+ ${PIKE_POSSIBLE_INCLUDE_PATHS}
+ PATH_SUFFIXES include/pike8.0/pike include/pike7.8/pike include/pike7.4/pike)
+
+find_program(PIKE_EXECUTABLE
+ NAMES pike8.0 pike 7.8 pike7.4
+ )
+
+mark_as_advanced(
+ PIKE_EXECUTABLE
+ PIKE_INCLUDE_PATH
+ )
diff --git a/Modules/FindPkgConfig.cmake b/Modules/FindPkgConfig.cmake
new file mode 100644
index 0000000..38c8da7
--- /dev/null
+++ b/Modules/FindPkgConfig.cmake
@@ -0,0 +1,917 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[========================================[.rst:
+FindPkgConfig
+-------------
+
+A ``pkg-config`` module for CMake.
+
+Finds the ``pkg-config`` executable and adds the :command:`pkg_get_variable`,
+:command:`pkg_check_modules` and :command:`pkg_search_module` commands. The
+following variables will also be set:
+
+``PKG_CONFIG_FOUND``
+ if pkg-config executable was found
+``PKG_CONFIG_EXECUTABLE``
+ pathname of the pkg-config program
+``PKG_CONFIG_VERSION_STRING``
+ version of pkg-config (since CMake 2.8.8)
+
+#]========================================]
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+### Common stuff ####
+set(PKG_CONFIG_VERSION 1)
+
+# find pkg-config, use PKG_CONFIG if set
+if((NOT PKG_CONFIG_EXECUTABLE) AND (NOT "$ENV{PKG_CONFIG}" STREQUAL ""))
+ set(PKG_CONFIG_EXECUTABLE "$ENV{PKG_CONFIG}" CACHE FILEPATH "pkg-config executable")
+endif()
+
+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}
+ NAMES_PER_DIR
+ DOC "pkg-config executable")
+mark_as_advanced(PKG_CONFIG_EXECUTABLE)
+
+set(_PKG_CONFIG_FAILURE_MESSAGE "")
+if (PKG_CONFIG_EXECUTABLE)
+ execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --version
+ OUTPUT_VARIABLE PKG_CONFIG_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE _PKG_CONFIG_VERSION_ERROR ERROR_STRIP_TRAILING_WHITESPACE
+ RESULT_VARIABLE _PKG_CONFIG_VERSION_RESULT
+ )
+
+ if (NOT _PKG_CONFIG_VERSION_RESULT EQUAL 0)
+ string(REPLACE "\n" "\n " _PKG_CONFIG_VERSION_ERROR " ${_PKG_CONFIG_VERSION_ERROR}")
+ string(APPEND _PKG_CONFIG_FAILURE_MESSAGE
+ "The command\n"
+ " \"${PKG_CONFIG_EXECUTABLE}\" --version\n"
+ " 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)
+ endif ()
+ unset(_PKG_CONFIG_VERSION_RESULT)
+endif ()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(PkgConfig
+ REQUIRED_VARS PKG_CONFIG_EXECUTABLE
+ REASON_FAILURE_MESSAGE "${_PKG_CONFIG_FAILURE_MESSAGE}"
+ VERSION_VAR PKG_CONFIG_VERSION_STRING)
+
+# This is needed because the module name is "PkgConfig" but the name of
+# this variable has always been PKG_CONFIG_FOUND so this isn't automatically
+# handled by FPHSA.
+set(PKG_CONFIG_FOUND "${PKGCONFIG_FOUND}")
+
+# Unsets the given variables
+macro(_pkgconfig_unset var)
+ set(${var} "" CACHE INTERNAL "")
+endmacro()
+
+macro(_pkgconfig_set var value)
+ set(${var} ${value} CACHE INTERNAL "")
+endmacro()
+
+# Invokes pkgconfig, cleans up the result and sets variables
+macro(_pkgconfig_invoke _pkglist _prefix _varname _regexp)
+ set(_pkgconfig_invoke_result)
+
+ execute_process(
+ COMMAND ${PKG_CONFIG_EXECUTABLE} ${ARGN} ${_pkglist}
+ OUTPUT_VARIABLE _pkgconfig_invoke_result
+ RESULT_VARIABLE _pkgconfig_failed
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if (_pkgconfig_failed)
+ set(_pkgconfig_${_varname} "")
+ _pkgconfig_unset(${_prefix}_${_varname})
+ else()
+ string(REGEX REPLACE "[\r\n]" " " _pkgconfig_invoke_result "${_pkgconfig_invoke_result}")
+
+ if (NOT ${_regexp} STREQUAL "")
+ string(REGEX REPLACE "${_regexp}" " " _pkgconfig_invoke_result "${_pkgconfig_invoke_result}")
+ endif()
+
+ separate_arguments(_pkgconfig_invoke_result)
+
+ #message(STATUS " ${_varname} ... ${_pkgconfig_invoke_result}")
+ set(_pkgconfig_${_varname} ${_pkgconfig_invoke_result})
+ _pkgconfig_set(${_prefix}_${_varname} "${_pkgconfig_invoke_result}")
+ endif()
+endmacro()
+
+# Internal version of pkg_get_variable; expects PKG_CONFIG_PATH to already be set
+function (_pkg_get_variable result pkg variable)
+ _pkgconfig_invoke("${pkg}" "prefix" "result" "" "--variable=${variable}")
+ set("${result}"
+ "${prefix_result}"
+ PARENT_SCOPE)
+endfunction ()
+
+# Invokes pkgconfig two times; once without '--static' and once with
+# '--static'
+macro(_pkgconfig_invoke_dyn _pkglist _prefix _varname cleanup_regexp)
+ _pkgconfig_invoke("${_pkglist}" ${_prefix} ${_varname} "${cleanup_regexp}" ${ARGN})
+ _pkgconfig_invoke("${_pkglist}" ${_prefix} STATIC_${_varname} "${cleanup_regexp}" --static ${ARGN})
+endmacro()
+
+# Splits given arguments into options and a package list
+macro(_pkgconfig_parse_options _result _is_req _is_silent _no_cmake_path _no_cmake_environment_path _imp_target _imp_target_global)
+ set(${_is_req} 0)
+ set(${_is_silent} 0)
+ set(${_no_cmake_path} 0)
+ set(${_no_cmake_environment_path} 0)
+ set(${_imp_target} 0)
+ set(${_imp_target_global} 0)
+ if(DEFINED PKG_CONFIG_USE_CMAKE_PREFIX_PATH)
+ if(NOT PKG_CONFIG_USE_CMAKE_PREFIX_PATH)
+ set(${_no_cmake_path} 1)
+ set(${_no_cmake_environment_path} 1)
+ endif()
+ elseif(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 3.1)
+ set(${_no_cmake_path} 1)
+ set(${_no_cmake_environment_path} 1)
+ endif()
+
+ foreach(_pkg ${ARGN})
+ if (_pkg STREQUAL "REQUIRED")
+ set(${_is_req} 1)
+ endif ()
+ if (_pkg STREQUAL "QUIET")
+ set(${_is_silent} 1)
+ endif ()
+ if (_pkg STREQUAL "NO_CMAKE_PATH")
+ set(${_no_cmake_path} 1)
+ endif()
+ if (_pkg STREQUAL "NO_CMAKE_ENVIRONMENT_PATH")
+ set(${_no_cmake_environment_path} 1)
+ endif()
+ if (_pkg STREQUAL "IMPORTED_TARGET")
+ set(${_imp_target} 1)
+ endif()
+ if (_pkg STREQUAL "GLOBAL")
+ set(${_imp_target_global} 1)
+ endif()
+ endforeach()
+
+ if (${_imp_target_global} AND NOT ${_imp_target})
+ message(SEND_ERROR "the argument GLOBAL may only be used together with IMPORTED_TARGET")
+ endif()
+
+ set(${_result} ${ARGN})
+ list(REMOVE_ITEM ${_result} "REQUIRED")
+ list(REMOVE_ITEM ${_result} "QUIET")
+ list(REMOVE_ITEM ${_result} "NO_CMAKE_PATH")
+ list(REMOVE_ITEM ${_result} "NO_CMAKE_ENVIRONMENT_PATH")
+ list(REMOVE_ITEM ${_result} "IMPORTED_TARGET")
+ list(REMOVE_ITEM ${_result} "GLOBAL")
+endmacro()
+
+# Add the content of a variable or an environment variable to a list of
+# paths
+# Usage:
+# - _pkgconfig_add_extra_path(_extra_paths VAR)
+# - _pkgconfig_add_extra_path(_extra_paths ENV VAR)
+function(_pkgconfig_add_extra_path _extra_paths_var _var)
+ set(_is_env 0)
+ if(ARGC GREATER 2 AND _var STREQUAL "ENV")
+ set(_var ${ARGV2})
+ set(_is_env 1)
+ endif()
+ if(NOT _is_env)
+ if(NOT "${${_var}}" STREQUAL "")
+ list(APPEND ${_extra_paths_var} ${${_var}})
+ endif()
+ else()
+ if(NOT "$ENV{${_var}}" STREQUAL "")
+ file(TO_CMAKE_PATH "$ENV{${_var}}" _path)
+ list(APPEND ${_extra_paths_var} ${_path})
+ unset(_path)
+ endif()
+ endif()
+ set(${_extra_paths_var} ${${_extra_paths_var}} PARENT_SCOPE)
+endfunction()
+
+# scan the LDFLAGS returned by pkg-config for library directories and
+# libraries, figure out the absolute paths of that libraries in the
+# given directories
+function(_pkg_find_libs _prefix _no_cmake_path _no_cmake_environment_path)
+ unset(_libs)
+ unset(_find_opts)
+
+ # set the options that are used as long as the .pc file does not provide a library
+ # path to look into
+ if(_no_cmake_path)
+ list(APPEND _find_opts "NO_CMAKE_PATH")
+ endif()
+ if(_no_cmake_environment_path)
+ list(APPEND _find_opts "NO_CMAKE_ENVIRONMENT_PATH")
+ endif()
+
+ unset(_search_paths)
+ unset(_next_is_framework)
+ foreach (flag IN LISTS ${_prefix}_LDFLAGS)
+ if (_next_is_framework)
+ list(APPEND _libs "-framework ${flag}")
+ unset(_next_is_framework)
+ continue()
+ endif ()
+ if (flag MATCHES "^-L(.*)")
+ list(APPEND _search_paths ${CMAKE_MATCH_1})
+ continue()
+ endif()
+ if (flag MATCHES "^-l(.*)")
+ set(_pkg_search "${CMAKE_MATCH_1}")
+ else()
+ if (flag STREQUAL "-framework")
+ set(_next_is_framework TRUE)
+ endif ()
+ continue()
+ endif()
+
+ if(_search_paths)
+ # Firstly search in -L paths
+ find_library(pkgcfg_lib_${_prefix}_${_pkg_search}
+ NAMES ${_pkg_search}
+ HINTS ${_search_paths} NO_DEFAULT_PATH)
+ endif()
+ find_library(pkgcfg_lib_${_prefix}_${_pkg_search}
+ NAMES ${_pkg_search}
+ ${_find_opts})
+ mark_as_advanced(pkgcfg_lib_${_prefix}_${_pkg_search})
+ if(pkgcfg_lib_${_prefix}_${_pkg_search})
+ list(APPEND _libs "${pkgcfg_lib_${_prefix}_${_pkg_search}}")
+ else()
+ list(APPEND _libs ${_pkg_search})
+ endif()
+ endforeach()
+
+ set(${_prefix}_LINK_LIBRARIES "${_libs}" PARENT_SCOPE)
+endfunction()
+
+# create an imported target from all the information returned by pkg-config
+function(_pkg_create_imp_target _prefix _imp_target_global)
+ # only create the target if it is linkable, i.e. no executables
+ if (NOT TARGET PkgConfig::${_prefix}
+ AND ( ${_prefix}_INCLUDE_DIRS OR ${_prefix}_LINK_LIBRARIES OR ${_prefix}_LDFLAGS_OTHER OR ${_prefix}_CFLAGS_OTHER ))
+ if(${_imp_target_global})
+ set(_global_opt "GLOBAL")
+ else()
+ unset(_global_opt)
+ endif()
+ add_library(PkgConfig::${_prefix} INTERFACE IMPORTED ${_global_opt})
+
+ if(${_prefix}_INCLUDE_DIRS)
+ set_property(TARGET PkgConfig::${_prefix} PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES "${${_prefix}_INCLUDE_DIRS}")
+ endif()
+ if(${_prefix}_LINK_LIBRARIES)
+ set_property(TARGET PkgConfig::${_prefix} PROPERTY
+ INTERFACE_LINK_LIBRARIES "${${_prefix}_LINK_LIBRARIES}")
+ endif()
+ if(${_prefix}_LDFLAGS_OTHER)
+ set_property(TARGET PkgConfig::${_prefix} PROPERTY
+ INTERFACE_LINK_OPTIONS "${${_prefix}_LDFLAGS_OTHER}")
+ endif()
+ if(${_prefix}_CFLAGS_OTHER)
+ set_property(TARGET PkgConfig::${_prefix} PROPERTY
+ INTERFACE_COMPILE_OPTIONS "${${_prefix}_CFLAGS_OTHER}")
+ endif()
+ endif()
+endfunction()
+
+# recalculate the dynamic output
+# this is a macro and not a function so the result of _pkg_find_libs is automatically propagated
+macro(_pkg_recalculate _prefix _no_cmake_path _no_cmake_environment_path _imp_target _imp_target_global)
+ _pkg_find_libs(${_prefix} ${_no_cmake_path} ${_no_cmake_environment_path})
+ if(${_imp_target})
+ _pkg_create_imp_target(${_prefix} ${_imp_target_global})
+ endif()
+endmacro()
+
+###
+macro(_pkg_set_path_internal)
+ set(_extra_paths)
+
+ if(NOT _no_cmake_path)
+ _pkgconfig_add_extra_path(_extra_paths CMAKE_PREFIX_PATH)
+ _pkgconfig_add_extra_path(_extra_paths CMAKE_FRAMEWORK_PATH)
+ _pkgconfig_add_extra_path(_extra_paths CMAKE_APPBUNDLE_PATH)
+ endif()
+
+ if(NOT _no_cmake_environment_path)
+ _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_PREFIX_PATH)
+ _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_FRAMEWORK_PATH)
+ _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_APPBUNDLE_PATH)
+ endif()
+
+ if(NOT _extra_paths STREQUAL "")
+ # Save the PKG_CONFIG_PATH environment variable, and add paths
+ # from the CMAKE_PREFIX_PATH variables
+ set(_pkgconfig_path_old "$ENV{PKG_CONFIG_PATH}")
+ set(_pkgconfig_path "${_pkgconfig_path_old}")
+ if(NOT _pkgconfig_path STREQUAL "")
+ file(TO_CMAKE_PATH "${_pkgconfig_path}" _pkgconfig_path)
+ endif()
+
+ # Create a list of the possible pkgconfig subfolder (depending on
+ # the system
+ set(_lib_dirs)
+ if(NOT DEFINED CMAKE_SYSTEM_NAME
+ OR (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$"
+ AND NOT CMAKE_CROSSCOMPILING))
+ if(EXISTS "/etc/debian_version") # is this a debian system ?
+ if(CMAKE_LIBRARY_ARCHITECTURE)
+ list(APPEND _lib_dirs "lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig")
+ endif()
+ else()
+ # not debian, check the FIND_LIBRARY_USE_LIB32_PATHS and FIND_LIBRARY_USE_LIB64_PATHS properties
+ get_property(uselib32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS)
+ if(uselib32 AND CMAKE_SIZEOF_VOID_P EQUAL 4)
+ list(APPEND _lib_dirs "lib32/pkgconfig")
+ endif()
+ get_property(uselib64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
+ if(uselib64 AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+ list(APPEND _lib_dirs "lib64/pkgconfig")
+ endif()
+ get_property(uselibx32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIBX32_PATHS)
+ if(uselibx32 AND CMAKE_INTERNAL_PLATFORM_ABI STREQUAL "ELF X32")
+ list(APPEND _lib_dirs "libx32/pkgconfig")
+ endif()
+ endif()
+ endif()
+ if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" AND NOT CMAKE_CROSSCOMPILING)
+ list(APPEND _lib_dirs "libdata/pkgconfig")
+ endif()
+ list(APPEND _lib_dirs "lib/pkgconfig")
+ list(APPEND _lib_dirs "share/pkgconfig")
+
+ # Check if directories exist and eventually append them to the
+ # pkgconfig path list
+ foreach(_prefix_dir ${_extra_paths})
+ foreach(_lib_dir ${_lib_dirs})
+ if(EXISTS "${_prefix_dir}/${_lib_dir}")
+ list(APPEND _pkgconfig_path "${_prefix_dir}/${_lib_dir}")
+ list(REMOVE_DUPLICATES _pkgconfig_path)
+ endif()
+ endforeach()
+ endforeach()
+
+ # Prepare and set the environment variable
+ if(NOT _pkgconfig_path STREQUAL "")
+ # remove empty values from the list
+ list(REMOVE_ITEM _pkgconfig_path "")
+ file(TO_NATIVE_PATH "${_pkgconfig_path}" _pkgconfig_path)
+ if(CMAKE_HOST_UNIX)
+ string(REPLACE ";" ":" _pkgconfig_path "${_pkgconfig_path}")
+ string(REPLACE "\\ " " " _pkgconfig_path "${_pkgconfig_path}")
+ endif()
+ set(ENV{PKG_CONFIG_PATH} "${_pkgconfig_path}")
+ endif()
+
+ # Unset variables
+ unset(_lib_dirs)
+ unset(_pkgconfig_path)
+ endif()
+endmacro()
+
+macro(_pkg_restore_path_internal)
+ if(NOT _extra_paths STREQUAL "")
+ # Restore the environment variable
+ set(ENV{PKG_CONFIG_PATH} "${_pkgconfig_path_old}")
+ endif()
+
+ unset(_extra_paths)
+ unset(_pkgconfig_path_old)
+endmacro()
+
+# pkg-config returns frameworks in --libs-only-other
+# they need to be in ${_prefix}_LIBRARIES so "-framework a -framework b" does
+# not incorrectly be combined to "-framework a b"
+function(_pkgconfig_extract_frameworks _prefix)
+ set(ldflags "${${_prefix}_LDFLAGS_OTHER}")
+ list(FIND ldflags "-framework" FR_POS)
+ list(LENGTH ldflags LD_LENGTH)
+
+ # reduce length by 1 as we need "-framework" and the next entry
+ math(EXPR LD_LENGTH "${LD_LENGTH} - 1")
+ while (FR_POS GREATER -1 AND LD_LENGTH GREATER FR_POS)
+ list(REMOVE_AT ldflags ${FR_POS})
+ list(GET ldflags ${FR_POS} HEAD)
+ list(REMOVE_AT ldflags ${FR_POS})
+ math(EXPR LD_LENGTH "${LD_LENGTH} - 2")
+
+ list(APPEND LIBS "-framework ${HEAD}")
+
+ list(FIND ldflags "-framework" FR_POS)
+ endwhile ()
+ set(${_prefix}_LIBRARIES ${${_prefix}_LIBRARIES} ${LIBS} PARENT_SCOPE)
+ set(${_prefix}_LDFLAGS_OTHER "${ldflags}" PARENT_SCOPE)
+endfunction()
+
+# pkg-config returns -isystem include directories in --cflags-only-other,
+# depending on the version and if there is a space between -isystem and
+# the actual path
+function(_pkgconfig_extract_isystem _prefix)
+ set(cflags "${${_prefix}_CFLAGS_OTHER}")
+ set(outflags "")
+ set(incdirs "${${_prefix}_INCLUDE_DIRS}")
+
+ set(next_is_isystem FALSE)
+ foreach (THING IN LISTS cflags)
+ # This may filter "-isystem -isystem". That would not work anyway,
+ # so let it happen.
+ if (THING STREQUAL "-isystem")
+ set(next_is_isystem TRUE)
+ continue()
+ endif ()
+ if (next_is_isystem)
+ set(next_is_isystem FALSE)
+ list(APPEND incdirs "${THING}")
+ elseif (THING MATCHES "^-isystem")
+ string(SUBSTRING "${THING}" 8 -1 THING)
+ list(APPEND incdirs "${THING}")
+ else ()
+ list(APPEND outflags "${THING}")
+ endif ()
+ endforeach ()
+ set(${_prefix}_CFLAGS_OTHER "${outflags}" PARENT_SCOPE)
+ set(${_prefix}_INCLUDE_DIRS "${incdirs}" PARENT_SCOPE)
+endfunction()
+
+###
+macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path _no_cmake_environment_path _imp_target _imp_target_global _prefix)
+ _pkgconfig_unset(${_prefix}_FOUND)
+ _pkgconfig_unset(${_prefix}_VERSION)
+ _pkgconfig_unset(${_prefix}_PREFIX)
+ _pkgconfig_unset(${_prefix}_INCLUDEDIR)
+ _pkgconfig_unset(${_prefix}_LIBDIR)
+ _pkgconfig_unset(${_prefix}_MODULE_NAME)
+ _pkgconfig_unset(${_prefix}_LIBS)
+ _pkgconfig_unset(${_prefix}_LIBS_L)
+ _pkgconfig_unset(${_prefix}_LIBS_PATHS)
+ _pkgconfig_unset(${_prefix}_LIBS_OTHER)
+ _pkgconfig_unset(${_prefix}_CFLAGS)
+ _pkgconfig_unset(${_prefix}_CFLAGS_I)
+ _pkgconfig_unset(${_prefix}_CFLAGS_OTHER)
+ _pkgconfig_unset(${_prefix}_STATIC_LIBDIR)
+ _pkgconfig_unset(${_prefix}_STATIC_LIBS)
+ _pkgconfig_unset(${_prefix}_STATIC_LIBS_L)
+ _pkgconfig_unset(${_prefix}_STATIC_LIBS_PATHS)
+ _pkgconfig_unset(${_prefix}_STATIC_LIBS_OTHER)
+ _pkgconfig_unset(${_prefix}_STATIC_CFLAGS)
+ _pkgconfig_unset(${_prefix}_STATIC_CFLAGS_I)
+ _pkgconfig_unset(${_prefix}_STATIC_CFLAGS_OTHER)
+
+ # create a better addressable variable of the modules and calculate its size
+ set(_pkg_check_modules_list ${ARGN})
+ list(LENGTH _pkg_check_modules_list _pkg_check_modules_cnt)
+
+ if(PKG_CONFIG_EXECUTABLE)
+ # give out status message telling checked module
+ if (NOT ${_is_silent})
+ if (_pkg_check_modules_cnt EQUAL 1)
+ message(STATUS "Checking for module '${_pkg_check_modules_list}'")
+ else()
+ message(STATUS "Checking for modules '${_pkg_check_modules_list}'")
+ endif()
+ endif()
+
+ set(_pkg_check_modules_packages)
+ set(_pkg_check_modules_failed)
+
+ _pkg_set_path_internal()
+
+ # iterate through module list and check whether they exist and match the required version
+ foreach (_pkg_check_modules_pkg ${_pkg_check_modules_list})
+ set(_pkg_check_modules_exist_query)
+
+ # check whether version is given
+ if (_pkg_check_modules_pkg MATCHES "(.*[^><])(=|[><]=?)(.*)")
+ set(_pkg_check_modules_pkg_name "${CMAKE_MATCH_1}")
+ set(_pkg_check_modules_pkg_op "${CMAKE_MATCH_2}")
+ set(_pkg_check_modules_pkg_ver "${CMAKE_MATCH_3}")
+ else()
+ set(_pkg_check_modules_pkg_name "${_pkg_check_modules_pkg}")
+ set(_pkg_check_modules_pkg_op)
+ set(_pkg_check_modules_pkg_ver)
+ endif()
+
+ _pkgconfig_unset(${_prefix}_${_pkg_check_modules_pkg_name}_VERSION)
+ _pkgconfig_unset(${_prefix}_${_pkg_check_modules_pkg_name}_PREFIX)
+ _pkgconfig_unset(${_prefix}_${_pkg_check_modules_pkg_name}_INCLUDEDIR)
+ _pkgconfig_unset(${_prefix}_${_pkg_check_modules_pkg_name}_LIBDIR)
+
+ list(APPEND _pkg_check_modules_packages "${_pkg_check_modules_pkg_name}")
+
+ # create the final query which is of the format:
+ # * <pkg-name> > <version>
+ # * <pkg-name> >= <version>
+ # * <pkg-name> = <version>
+ # * <pkg-name> <= <version>
+ # * <pkg-name> < <version>
+ # * --exists <pkg-name>
+ list(APPEND _pkg_check_modules_exist_query --print-errors --short-errors)
+ if (_pkg_check_modules_pkg_op)
+ list(APPEND _pkg_check_modules_exist_query "${_pkg_check_modules_pkg_name} ${_pkg_check_modules_pkg_op} ${_pkg_check_modules_pkg_ver}")
+ else()
+ list(APPEND _pkg_check_modules_exist_query --exists)
+ list(APPEND _pkg_check_modules_exist_query "${_pkg_check_modules_pkg_name}")
+ endif()
+
+ # execute the query
+ execute_process(
+ COMMAND ${PKG_CONFIG_EXECUTABLE} ${_pkg_check_modules_exist_query}
+ RESULT_VARIABLE _pkgconfig_retval
+ ERROR_VARIABLE _pkgconfig_error
+ ERROR_STRIP_TRAILING_WHITESPACE)
+
+ # evaluate result and tell failures
+ if (_pkgconfig_retval)
+ if(NOT ${_is_silent})
+ message(STATUS " ${_pkgconfig_error}")
+ endif()
+
+ set(_pkg_check_modules_failed 1)
+ endif()
+ endforeach()
+
+ if(_pkg_check_modules_failed)
+ # fail when requested
+ if (${_is_required})
+ message(FATAL_ERROR "A required package was not found")
+ endif ()
+ else()
+ # when we are here, we checked whether requested modules
+ # exist. Now, go through them and set variables
+
+ _pkgconfig_set(${_prefix}_FOUND 1)
+ list(LENGTH _pkg_check_modules_packages pkg_count)
+
+ # iterate through all modules again and set individual variables
+ foreach (_pkg_check_modules_pkg ${_pkg_check_modules_packages})
+ # handle case when there is only one package required
+ if (pkg_count EQUAL 1)
+ set(_pkg_check_prefix "${_prefix}")
+ else()
+ set(_pkg_check_prefix "${_prefix}_${_pkg_check_modules_pkg}")
+ endif()
+
+ _pkgconfig_invoke(${_pkg_check_modules_pkg} "${_pkg_check_prefix}" VERSION "" --modversion )
+ pkg_get_variable("${_pkg_check_prefix}_PREFIX" ${_pkg_check_modules_pkg} "prefix")
+ pkg_get_variable("${_pkg_check_prefix}_INCLUDEDIR" ${_pkg_check_modules_pkg} "includedir")
+ pkg_get_variable("${_pkg_check_prefix}_LIBDIR" ${_pkg_check_modules_pkg} "libdir")
+ foreach (variable IN ITEMS PREFIX INCLUDEDIR LIBDIR)
+ _pkgconfig_set("${_pkg_check_prefix}_${variable}" "${${_pkg_check_prefix}_${variable}}")
+ endforeach ()
+ _pkgconfig_set("${_pkg_check_prefix}_MODULE_NAME" "${_pkg_check_modules_pkg}")
+
+ if (NOT ${_is_silent})
+ message(STATUS " Found ${_pkg_check_modules_pkg}, version ${_pkgconfig_VERSION}")
+ endif ()
+ endforeach()
+
+ # set variables which are combined for multiple modules
+ _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" LIBRARIES "(^| )-l" --libs-only-l )
+ _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" LIBRARY_DIRS "(^| )-L" --libs-only-L )
+ _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" LDFLAGS "" --libs )
+ _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" LDFLAGS_OTHER "" --libs-only-other )
+
+ if (APPLE AND "-framework" IN_LIST ${_prefix}_LDFLAGS_OTHER)
+ _pkgconfig_extract_frameworks("${_prefix}")
+ endif()
+
+ _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" INCLUDE_DIRS "(^| )(-I|-isystem ?)" --cflags-only-I )
+ _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" CFLAGS "" --cflags )
+ _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" CFLAGS_OTHER "" --cflags-only-other )
+
+ if (${_prefix}_CFLAGS_OTHER MATCHES "-isystem")
+ _pkgconfig_extract_isystem("${_prefix}")
+ endif ()
+
+ _pkg_recalculate("${_prefix}" ${_no_cmake_path} ${_no_cmake_environment_path} ${_imp_target} ${_imp_target_global})
+ endif()
+
+ _pkg_restore_path_internal()
+ else()
+ if (${_is_required})
+ message(SEND_ERROR "pkg-config tool not found")
+ endif ()
+ endif()
+endmacro()
+
+
+#[========================================[.rst:
+.. command:: pkg_check_modules
+
+ Checks for all the given modules, setting a variety of result variables in
+ the calling scope.
+
+ .. code-block:: cmake
+
+ pkg_check_modules(<prefix>
+ [REQUIRED] [QUIET]
+ [NO_CMAKE_PATH]
+ [NO_CMAKE_ENVIRONMENT_PATH]
+ [IMPORTED_TARGET [GLOBAL]]
+ <moduleSpec> [<moduleSpec>...])
+
+ When the ``REQUIRED`` argument is given, the command will fail with an error
+ if module(s) could not be found.
+
+ When the ``QUIET`` argument is given, no status messages will be printed.
+
+ .. versionadded:: 3.1
+ The :variable:`CMAKE_PREFIX_PATH`,
+ :variable:`CMAKE_FRAMEWORK_PATH`, and :variable:`CMAKE_APPBUNDLE_PATH` cache
+ and environment variables will be added to the ``pkg-config`` search path.
+ The ``NO_CMAKE_PATH`` and ``NO_CMAKE_ENVIRONMENT_PATH`` arguments
+ disable this behavior for the cache variables and environment variables
+ respectively.
+ The :variable:`PKG_CONFIG_USE_CMAKE_PREFIX_PATH` variable set to ``FALSE``
+ disables this behavior globally.
+
+ .. This didn't actually work until 3.3.
+
+ .. versionadded:: 3.6
+ The ``IMPORTED_TARGET`` argument will create an imported target named
+ ``PkgConfig::<prefix>`` that can be passed directly as an argument to
+ :command:`target_link_libraries`.
+
+ .. This didn't actually work until 3.7.
+
+ .. versionadded:: 3.13
+ The ``GLOBAL`` argument will make the
+ imported target available in global scope.
+
+ .. versionadded:: 3.15
+ Non-library linker options reported by ``pkg-config`` are stored in the
+ :prop_tgt:`INTERFACE_LINK_OPTIONS` target property.
+
+ .. versionchanged:: 3.18
+ Include directories specified with ``-isystem`` are stored in the
+ :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target property. Previous
+ versions of CMake left them in the :prop_tgt:`INTERFACE_COMPILE_OPTIONS`
+ property.
+
+ Each ``<moduleSpec>`` can be either a bare module name or it can be a
+ module name with a version constraint (operators ``=``, ``<``, ``>``,
+ ``<=`` and ``>=`` are supported). The following are examples for a module
+ named ``foo`` with various constraints:
+
+ - ``foo`` matches any version.
+ - ``foo<2`` only matches versions before 2.
+ - ``foo>=3.1`` matches any version from 3.1 or later.
+ - ``foo=1.2.3`` requires that foo must be exactly version 1.2.3.
+
+ The following variables may be set upon return. Two sets of values exist:
+ One for the common case (``<XXX> = <prefix>``) and another for the
+ information ``pkg-config`` provides when called with the ``--static``
+ option (``<XXX> = <prefix>_STATIC``).
+
+ ``<XXX>_FOUND``
+ set to 1 if module(s) exist
+ ``<XXX>_LIBRARIES``
+ only the libraries (without the '-l')
+ ``<XXX>_LINK_LIBRARIES``
+ the libraries and their absolute paths
+ ``<XXX>_LIBRARY_DIRS``
+ the paths of the libraries (without the '-L')
+ ``<XXX>_LDFLAGS``
+ all required linker flags
+ ``<XXX>_LDFLAGS_OTHER``
+ all other linker flags
+ ``<XXX>_INCLUDE_DIRS``
+ the '-I' preprocessor flags (without the '-I')
+ ``<XXX>_CFLAGS``
+ all required cflags
+ ``<XXX>_CFLAGS_OTHER``
+ the other compiler flags
+
+ All but ``<XXX>_FOUND`` may be a :ref:`;-list <CMake Language Lists>` if the
+ associated variable returned from ``pkg-config`` has multiple values.
+
+ .. versionchanged:: 3.18
+ Include directories specified with ``-isystem`` are stored in the
+ ``<XXX>_INCLUDE_DIRS`` variable. Previous versions of CMake left them
+ in ``<XXX>_CFLAGS_OTHER``.
+
+ There are some special variables whose prefix depends on the number of
+ ``<moduleSpec>`` given. When there is only one ``<moduleSpec>``,
+ ``<YYY>`` will simply be ``<prefix>``, but if two or more ``<moduleSpec>``
+ items are given, ``<YYY>`` will be ``<prefix>_<moduleName>``.
+
+ ``<YYY>_VERSION``
+ version of the module
+ ``<YYY>_PREFIX``
+ prefix directory of the module
+ ``<YYY>_INCLUDEDIR``
+ include directory of the module
+ ``<YYY>_LIBDIR``
+ lib directory of the module
+
+ .. versionchanged:: 3.8
+ For any given ``<prefix>``, ``pkg_check_modules()`` can be called multiple
+ times with different parameters. Previous versions of CMake cached and
+ returned the first successful result.
+
+ .. versionchanged:: 3.16
+ If a full path to the found library can't be determined, but it's still
+ visible to the linker, pass it through as ``-l<name>``. Previous versions
+ of CMake failed in this case.
+
+ Examples:
+
+ .. code-block:: cmake
+
+ pkg_check_modules (GLIB2 glib-2.0)
+
+ Looks for any version of glib2. If found, the output variable
+ ``GLIB2_VERSION`` will hold the actual version found.
+
+ .. code-block:: cmake
+
+ pkg_check_modules (GLIB2 glib-2.0>=2.10)
+
+ Looks for at least version 2.10 of glib2. If found, the output variable
+ ``GLIB2_VERSION`` will hold the actual version found.
+
+ .. code-block:: cmake
+
+ pkg_check_modules (FOO glib-2.0>=2.10 gtk+-2.0)
+
+ Looks for both glib2-2.0 (at least version 2.10) and any version of
+ gtk2+-2.0. Only if both are found will ``FOO`` be considered found.
+ The ``FOO_glib-2.0_VERSION`` and ``FOO_gtk+-2.0_VERSION`` variables will be
+ set to their respective found module versions.
+
+ .. code-block:: cmake
+
+ pkg_check_modules (XRENDER REQUIRED xrender)
+
+ Requires any version of ``xrender``. Example output variables set by a
+ successful call::
+
+ XRENDER_LIBRARIES=Xrender;X11
+ XRENDER_STATIC_LIBRARIES=Xrender;X11;pthread;Xau;Xdmcp
+#]========================================]
+macro(pkg_check_modules _prefix _module0)
+ _pkgconfig_parse_options(_pkg_modules _pkg_is_required _pkg_is_silent _no_cmake_path _no_cmake_environment_path _imp_target _imp_target_global "${_module0}" ${ARGN})
+ # check cached value
+ if (NOT DEFINED __pkg_config_checked_${_prefix} OR __pkg_config_checked_${_prefix} LESS ${PKG_CONFIG_VERSION} OR NOT ${_prefix}_FOUND OR
+ (NOT "${ARGN}" STREQUAL "" AND NOT "${__pkg_config_arguments_${_prefix}}" STREQUAL "${_module0};${ARGN}") OR
+ ( "${ARGN}" STREQUAL "" AND NOT "${__pkg_config_arguments_${_prefix}}" STREQUAL "${_module0}"))
+ _pkg_check_modules_internal("${_pkg_is_required}" "${_pkg_is_silent}" ${_no_cmake_path} ${_no_cmake_environment_path} ${_imp_target} ${_imp_target_global} "${_prefix}" ${_pkg_modules})
+
+ _pkgconfig_set(__pkg_config_checked_${_prefix} ${PKG_CONFIG_VERSION})
+ if (${_prefix}_FOUND)
+ _pkgconfig_set(__pkg_config_arguments_${_prefix} "${_module0};${ARGN}")
+ endif()
+ else()
+ if (${_prefix}_FOUND)
+ _pkg_recalculate("${_prefix}" ${_no_cmake_path} ${_no_cmake_environment_path} ${_imp_target} ${_imp_target_global})
+ endif()
+ endif()
+endmacro()
+
+
+#[========================================[.rst:
+.. command:: pkg_search_module
+
+ The behavior of this command is the same as :command:`pkg_check_modules`,
+ except that rather than checking for all the specified modules, it searches
+ for just the first successful match.
+
+ .. code-block:: cmake
+
+ pkg_search_module(<prefix>
+ [REQUIRED] [QUIET]
+ [NO_CMAKE_PATH]
+ [NO_CMAKE_ENVIRONMENT_PATH]
+ [IMPORTED_TARGET [GLOBAL]]
+ <moduleSpec> [<moduleSpec>...])
+
+ .. versionadded:: 3.16
+ If a module is found, the ``<prefix>_MODULE_NAME`` variable will contain the
+ name of the matching module. This variable can be used if you need to run
+ :command:`pkg_get_variable`.
+
+ Example:
+
+ .. code-block:: cmake
+
+ pkg_search_module (BAR libxml-2.0 libxml2 libxml>=2)
+#]========================================]
+macro(pkg_search_module _prefix _module0)
+ _pkgconfig_parse_options(_pkg_modules_alt _pkg_is_required _pkg_is_silent _no_cmake_path _no_cmake_environment_path _imp_target _imp_target_global "${_module0}" ${ARGN})
+ # check cached value
+ if (NOT DEFINED __pkg_config_checked_${_prefix} OR __pkg_config_checked_${_prefix} LESS ${PKG_CONFIG_VERSION} OR NOT ${_prefix}_FOUND)
+ set(_pkg_modules_found 0)
+
+ if (NOT ${_pkg_is_silent})
+ message(STATUS "Checking for one of the modules '${_pkg_modules_alt}'")
+ endif ()
+
+ # iterate through all modules and stop at the first working one.
+ foreach(_pkg_alt ${_pkg_modules_alt})
+ if(NOT _pkg_modules_found)
+ _pkg_check_modules_internal(0 1 ${_no_cmake_path} ${_no_cmake_environment_path} ${_imp_target} ${_imp_target_global} "${_prefix}" "${_pkg_alt}")
+ endif()
+
+ if (${_prefix}_FOUND)
+ set(_pkg_modules_found 1)
+ break()
+ endif()
+ endforeach()
+
+ if (NOT ${_prefix}_FOUND)
+ if(${_pkg_is_required})
+ message(SEND_ERROR "None of the required '${_pkg_modules_alt}' found")
+ endif()
+ endif()
+
+ _pkgconfig_set(__pkg_config_checked_${_prefix} ${PKG_CONFIG_VERSION})
+ elseif (${_prefix}_FOUND)
+ _pkg_recalculate("${_prefix}" ${_no_cmake_path} ${_no_cmake_environment_path} ${_imp_target} ${_imp_target_global})
+ endif()
+endmacro()
+
+#[========================================[.rst:
+.. command:: pkg_get_variable
+
+ .. versionadded:: 3.4
+
+ Retrieves the value of a pkg-config variable ``varName`` and stores it in the
+ result variable ``resultVar`` in the calling scope.
+
+ .. code-block:: cmake
+
+ pkg_get_variable(<resultVar> <moduleName> <varName>)
+
+ If ``pkg-config`` returns multiple values for the specified variable,
+ ``resultVar`` will contain a :ref:`;-list <CMake Language Lists>`.
+
+ For example:
+
+ .. code-block:: cmake
+
+ pkg_get_variable(GI_GIRDIR gobject-introspection-1.0 girdir)
+#]========================================]
+function (pkg_get_variable result pkg variable)
+ _pkg_set_path_internal()
+ _pkgconfig_invoke("${pkg}" "prefix" "result" "" "--variable=${variable}")
+ set("${result}"
+ "${prefix_result}"
+ PARENT_SCOPE)
+ _pkg_restore_path_internal()
+endfunction ()
+
+
+#[========================================[.rst:
+Variables Affecting Behavior
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. variable:: PKG_CONFIG_EXECUTABLE
+
+ This can be set to the path of the pkg-config executable. If not provided,
+ it will be set by the module as a result of calling :command:`find_program`
+ internally.
+
+ .. versionadded:: 3.1
+ The ``PKG_CONFIG`` environment variable can be used as a hint.
+
+.. variable:: PKG_CONFIG_USE_CMAKE_PREFIX_PATH
+
+ .. versionadded:: 3.1
+
+ Specifies whether :command:`pkg_check_modules` and
+ :command:`pkg_search_module` should add the paths in the
+ :variable:`CMAKE_PREFIX_PATH`, :variable:`CMAKE_FRAMEWORK_PATH` and
+ :variable:`CMAKE_APPBUNDLE_PATH` cache and environment variables to the
+ ``pkg-config`` search path.
+
+ If this variable is not set, this behavior is enabled by default if
+ :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` is 3.1 or later, disabled
+ otherwise.
+#]========================================]
+
+
+### Local Variables:
+### mode: cmake
+### End:
+
+cmake_policy(POP)
diff --git a/Modules/FindPostgreSQL.cmake b/Modules/FindPostgreSQL.cmake
new file mode 100644
index 0000000..147071a
--- /dev/null
+++ b/Modules/FindPostgreSQL.cmake
@@ -0,0 +1,312 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPostgreSQL
+--------------
+
+Find the PostgreSQL installation.
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.14
+
+This module defines :prop_tgt:`IMPORTED` target ``PostgreSQL::PostgreSQL``
+if PostgreSQL has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``PostgreSQL_FOUND``
+ True if PostgreSQL is found.
+``PostgreSQL_LIBRARIES``
+ the PostgreSQL libraries needed for linking
+``PostgreSQL_INCLUDE_DIRS``
+ the directories of the PostgreSQL headers
+``PostgreSQL_LIBRARY_DIRS``
+ the link directories for PostgreSQL libraries
+``PostgreSQL_VERSION_STRING``
+ the version of PostgreSQL found
+``PostgreSQL_TYPE_INCLUDE_DIR``
+ the directories of the PostgreSQL server headers
+
+Components
+^^^^^^^^^^
+
+This module contains additional ``Server`` component, that forcibly checks
+for the presence of server headers. Note that ``PostgreSQL_TYPE_INCLUDE_DIR``
+is set regardless of the presence of the ``Server`` component in find_package call.
+
+#]=======================================================================]
+
+# ----------------------------------------------------------------------------
+# History:
+# This module is derived from the module originally found in the VTK source tree.
+#
+# ----------------------------------------------------------------------------
+# Note:
+# PostgreSQL_ADDITIONAL_VERSIONS is a variable that can be used to set the
+# version number of the implementation of PostgreSQL.
+# In Windows the default installation of PostgreSQL uses that as part of the path.
+# E.g C:\Program Files\PostgreSQL\8.4.
+# Currently, the following version numbers are known to this module:
+# "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0"
+#
+# To use this variable just do something like this:
+# set(PostgreSQL_ADDITIONAL_VERSIONS "9.2" "8.4.4")
+# before calling find_package(PostgreSQL) in your CMakeLists.txt file.
+# This will mean that the versions you set here will be found first in the order
+# specified before the default ones are searched.
+#
+# ----------------------------------------------------------------------------
+# You may need to manually set:
+# PostgreSQL_INCLUDE_DIR - the path to where the PostgreSQL include files are.
+# PostgreSQL_LIBRARY_DIR - The path to where the PostgreSQL library files are.
+# If FindPostgreSQL.cmake cannot find the include files or the library files.
+#
+# ----------------------------------------------------------------------------
+# The following variables are set if PostgreSQL is found:
+# PostgreSQL_FOUND - Set to true when PostgreSQL is found.
+# PostgreSQL_INCLUDE_DIRS - Include directories for PostgreSQL
+# PostgreSQL_LIBRARY_DIRS - Link directories for PostgreSQL libraries
+# PostgreSQL_LIBRARIES - The PostgreSQL libraries.
+#
+# The ``PostgreSQL::PostgreSQL`` imported target is also created.
+#
+# ----------------------------------------------------------------------------
+# If you have installed PostgreSQL in a non-standard location.
+# (Please note that in the following comments, it is assumed that <Your Path>
+# points to the root directory of the include directory of PostgreSQL.)
+# Then you have three options.
+# 1) After CMake runs, set PostgreSQL_INCLUDE_DIR to <Your Path>/include and
+# PostgreSQL_LIBRARY_DIR to wherever the library pq (or libpq in windows) is
+# 2) Use CMAKE_INCLUDE_PATH to set a path to <Your Path>/PostgreSQL<-version>. This will allow find_path()
+# to locate PostgreSQL_INCLUDE_DIR by utilizing the PATH_SUFFIXES option. e.g. In your CMakeLists.txt file
+# set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "<Your Path>/include")
+# 3) Set an environment variable called ${PostgreSQL_ROOT} that points to the root of where you have
+# installed PostgreSQL, e.g. <Your Path>.
+#
+# ----------------------------------------------------------------------------
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+set(PostgreSQL_INCLUDE_PATH_DESCRIPTION "top-level directory containing the PostgreSQL include directories. E.g /usr/local/include/PostgreSQL/8.4 or C:/Program Files/PostgreSQL/8.4/include")
+set(PostgreSQL_INCLUDE_DIR_MESSAGE "Set the PostgreSQL_INCLUDE_DIR cmake cache entry to the ${PostgreSQL_INCLUDE_PATH_DESCRIPTION}")
+set(PostgreSQL_LIBRARY_PATH_DESCRIPTION "top-level directory containing the PostgreSQL libraries.")
+set(PostgreSQL_LIBRARY_DIR_MESSAGE "Set the PostgreSQL_LIBRARY_DIR cmake cache entry to the ${PostgreSQL_LIBRARY_PATH_DESCRIPTION}")
+set(PostgreSQL_ROOT_DIR_MESSAGE "Set the PostgreSQL_ROOT system variable to where PostgreSQL is found on the machine E.g C:/Program Files/PostgreSQL/8.4")
+
+
+set(PostgreSQL_KNOWN_VERSIONS ${PostgreSQL_ADDITIONAL_VERSIONS}
+ "13" "12" "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0")
+
+# Define additional search paths for root directories.
+set( PostgreSQL_ROOT_DIRECTORIES
+ ENV PostgreSQL_ROOT
+ ${PostgreSQL_ROOT}
+)
+foreach(suffix ${PostgreSQL_KNOWN_VERSIONS})
+ if(WIN32)
+ list(APPEND PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES
+ "PostgreSQL/${suffix}/lib")
+ list(APPEND PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES
+ "PostgreSQL/${suffix}/include")
+ list(APPEND PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES
+ "PostgreSQL/${suffix}/include/server")
+ endif()
+ if(UNIX)
+ list(APPEND PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES
+ "postgresql${suffix}"
+ "pgsql-${suffix}/lib")
+ list(APPEND PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES
+ "postgresql${suffix}"
+ "postgresql/${suffix}"
+ "pgsql-${suffix}/include")
+ list(APPEND PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES
+ "postgresql${suffix}/server"
+ "postgresql/${suffix}/server"
+ "pgsql-${suffix}/include/server")
+ endif()
+endforeach()
+
+#
+# Look for an installation.
+#
+find_path(PostgreSQL_INCLUDE_DIR
+ NAMES libpq-fe.h
+ PATHS
+ # Look in other places.
+ ${PostgreSQL_ROOT_DIRECTORIES}
+ PATH_SUFFIXES
+ pgsql
+ postgresql
+ include
+ ${PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES}
+ # Help the user find it if we cannot.
+ DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}"
+)
+
+find_path(PostgreSQL_TYPE_INCLUDE_DIR
+ NAMES catalog/pg_type.h
+ PATHS
+ # Look in other places.
+ ${PostgreSQL_ROOT_DIRECTORIES}
+ PATH_SUFFIXES
+ postgresql
+ pgsql/server
+ postgresql/server
+ include/server
+ ${PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES}
+ # Help the user find it if we cannot.
+ DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}"
+)
+
+# The PostgreSQL library.
+set (PostgreSQL_LIBRARY_TO_FIND pq)
+# Setting some more prefixes for the library
+set (PostgreSQL_LIB_PREFIX "")
+if ( WIN32 )
+ set (PostgreSQL_LIB_PREFIX ${PostgreSQL_LIB_PREFIX} "lib")
+ set (PostgreSQL_LIBRARY_TO_FIND ${PostgreSQL_LIB_PREFIX}${PostgreSQL_LIBRARY_TO_FIND})
+endif()
+
+function(__postgresql_find_library _name)
+ find_library(${_name}
+ NAMES ${ARGN}
+ PATHS
+ ${PostgreSQL_ROOT_DIRECTORIES}
+ PATH_SUFFIXES
+ lib
+ ${PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES}
+ # Help the user find it if we cannot.
+ DOC "The ${PostgreSQL_LIBRARY_DIR_MESSAGE}"
+ )
+endfunction()
+
+# For compatibility with versions prior to this multi-config search, honor
+# any PostgreSQL_LIBRARY that is already specified and skip the search.
+if(PostgreSQL_LIBRARY)
+ set(PostgreSQL_LIBRARIES "${PostgreSQL_LIBRARY}")
+ get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY}" PATH)
+else()
+ __postgresql_find_library(PostgreSQL_LIBRARY_RELEASE ${PostgreSQL_LIBRARY_TO_FIND})
+ __postgresql_find_library(PostgreSQL_LIBRARY_DEBUG ${PostgreSQL_LIBRARY_TO_FIND}d)
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(PostgreSQL)
+ mark_as_advanced(PostgreSQL_LIBRARY_RELEASE PostgreSQL_LIBRARY_DEBUG)
+ if(PostgreSQL_LIBRARY_RELEASE)
+ get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY_RELEASE}" PATH)
+ elseif(PostgreSQL_LIBRARY_DEBUG)
+ get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY_DEBUG}" PATH)
+ else()
+ set(PostgreSQL_LIBRARY_DIR "")
+ endif()
+endif()
+
+if (PostgreSQL_INCLUDE_DIR)
+ # Some platforms include multiple pg_config.hs for multi-lib configurations
+ # This is a temporary workaround. A better solution would be to compile
+ # a dummy c file and extract the value of the symbol.
+ file(GLOB _PG_CONFIG_HEADERS "${PostgreSQL_INCLUDE_DIR}/pg_config*.h")
+ foreach(_PG_CONFIG_HEADER ${_PG_CONFIG_HEADERS})
+ if(EXISTS "${_PG_CONFIG_HEADER}")
+ file(STRINGS "${_PG_CONFIG_HEADER}" pgsql_version_str
+ REGEX "^#define[\t ]+PG_VERSION_NUM[\t ]+.*")
+ if(pgsql_version_str)
+ string(REGEX REPLACE "^#define[\t ]+PG_VERSION_NUM[\t ]+([0-9]*).*"
+ "\\1" _PostgreSQL_VERSION_NUM "${pgsql_version_str}")
+ break()
+ endif()
+ endif()
+ endforeach()
+ if (_PostgreSQL_VERSION_NUM)
+ # 9.x and older encoding
+ if (_PostgreSQL_VERSION_NUM LESS 100000)
+ math(EXPR _PostgreSQL_major_version "${_PostgreSQL_VERSION_NUM} / 10000")
+ math(EXPR _PostgreSQL_minor_version "${_PostgreSQL_VERSION_NUM} % 10000 / 100")
+ math(EXPR _PostgreSQL_patch_version "${_PostgreSQL_VERSION_NUM} % 100")
+ set(PostgreSQL_VERSION_STRING "${_PostgreSQL_major_version}.${_PostgreSQL_minor_version}.${_PostgreSQL_patch_version}")
+ unset(_PostgreSQL_major_version)
+ unset(_PostgreSQL_minor_version)
+ unset(_PostgreSQL_patch_version)
+ else ()
+ math(EXPR _PostgreSQL_major_version "${_PostgreSQL_VERSION_NUM} / 10000")
+ math(EXPR _PostgreSQL_minor_version "${_PostgreSQL_VERSION_NUM} % 10000")
+ set(PostgreSQL_VERSION_STRING "${_PostgreSQL_major_version}.${_PostgreSQL_minor_version}")
+ unset(_PostgreSQL_major_version)
+ unset(_PostgreSQL_minor_version)
+ endif ()
+ else ()
+ foreach(_PG_CONFIG_HEADER ${_PG_CONFIG_HEADERS})
+ if(EXISTS "${_PG_CONFIG_HEADER}")
+ file(STRINGS "${_PG_CONFIG_HEADER}" pgsql_version_str
+ REGEX "^#define[\t ]+PG_VERSION[\t ]+\".*\"")
+ if(pgsql_version_str)
+ string(REGEX REPLACE "^#define[\t ]+PG_VERSION[\t ]+\"([^\"]*)\".*"
+ "\\1" PostgreSQL_VERSION_STRING "${pgsql_version_str}")
+ break()
+ endif()
+ endif()
+ endforeach()
+ endif ()
+ unset(_PostgreSQL_VERSION_NUM)
+ unset(pgsql_version_str)
+endif()
+
+if("Server" IN_LIST PostgreSQL_FIND_COMPONENTS)
+ set(PostgreSQL_Server_FOUND TRUE)
+ if(NOT PostgreSQL_TYPE_INCLUDE_DIR)
+ set(PostgreSQL_Server_FOUND FALSE)
+ endif()
+endif()
+
+# Did we find anything?
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(PostgreSQL
+ REQUIRED_VARS PostgreSQL_LIBRARY PostgreSQL_INCLUDE_DIR
+ HANDLE_COMPONENTS
+ VERSION_VAR PostgreSQL_VERSION_STRING)
+set(PostgreSQL_FOUND ${POSTGRESQL_FOUND})
+
+function(__postgresql_import_library _target _var _config)
+ if(_config)
+ set(_config_suffix "_${_config}")
+ else()
+ set(_config_suffix "")
+ endif()
+
+ set(_lib "${${_var}${_config_suffix}}")
+ if(EXISTS "${_lib}")
+ if(_config)
+ set_property(TARGET ${_target} APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS ${_config})
+ endif()
+ set_target_properties(${_target} PROPERTIES
+ IMPORTED_LOCATION${_config_suffix} "${_lib}")
+ endif()
+endfunction()
+
+# Now try to get the include and library path.
+if(PostgreSQL_FOUND)
+ set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR})
+ if(PostgreSQL_TYPE_INCLUDE_DIR)
+ list(APPEND PostgreSQL_INCLUDE_DIRS ${PostgreSQL_TYPE_INCLUDE_DIR})
+ endif()
+ set(PostgreSQL_LIBRARY_DIRS ${PostgreSQL_LIBRARY_DIR})
+ if (NOT TARGET PostgreSQL::PostgreSQL)
+ add_library(PostgreSQL::PostgreSQL UNKNOWN IMPORTED)
+ set_target_properties(PostgreSQL::PostgreSQL PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${PostgreSQL_INCLUDE_DIRS}")
+ __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "")
+ __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "RELEASE")
+ __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "DEBUG")
+ endif ()
+endif()
+
+mark_as_advanced(PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR)
+
+cmake_policy(POP)
diff --git a/Modules/FindProducer.cmake b/Modules/FindProducer.cmake
new file mode 100644
index 0000000..65495b5
--- /dev/null
+++ b/Modules/FindProducer.cmake
@@ -0,0 +1,66 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindProducer
+------------
+
+
+
+Though Producer isn't directly part of OpenSceneGraph, its primary
+user is OSG so I consider this part of the Findosg* suite used to find
+OpenSceneGraph components. You'll notice that I accept OSGDIR as an
+environment path.
+
+Each component is separate and you must opt in to each module. You
+must also opt into OpenGL (and OpenThreads?) as these modules won't do
+it for you. This is to allow you control over your own system piece
+by piece in case you need to opt out of certain components or change
+the Find behavior for a particular module (perhaps because the default
+FindOpenGL.cmake module doesn't work with your system as an example).
+If you want to use a more convenient module that includes everything,
+use the FindOpenSceneGraph.cmake instead of the Findosg*.cmake
+modules.
+
+Locate Producer This module defines PRODUCER_LIBRARY PRODUCER_FOUND,
+if false, do not try to link to Producer PRODUCER_INCLUDE_DIR, where
+to find the headers
+
+$PRODUCER_DIR is an environment variable that would correspond to the
+./configure --prefix=$PRODUCER_DIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <Producer/CameraGroup>
+
+# Try the user's environment request before anything else.
+find_path(PRODUCER_INCLUDE_DIR Producer/CameraGroup
+ HINTS
+ ENV PRODUCER_DIR
+ ENV OSG_DIR
+ ENV OSGDIR
+ PATH_SUFFIXES include
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /opt
+ [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OpenThreads_ROOT]
+ [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]
+)
+
+find_library(PRODUCER_LIBRARY
+ NAMES Producer
+ HINTS
+ ENV PRODUCER_DIR
+ ENV OSG_DIR
+ ENV OSGDIR
+ PATH_SUFFIXES lib
+ PATHS
+ /opt
+)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Producer DEFAULT_MSG
+ PRODUCER_LIBRARY PRODUCER_INCLUDE_DIR)
diff --git a/Modules/FindProtobuf.cmake b/Modules/FindProtobuf.cmake
new file mode 100644
index 0000000..4b1e336
--- /dev/null
+++ b/Modules/FindProtobuf.cmake
@@ -0,0 +1,681 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindProtobuf
+------------
+
+Locate and configure the Google Protocol Buffers library.
+
+.. versionadded:: 3.6
+ Support for :command:`find_package` version checks.
+
+.. versionchanged:: 3.6
+ All input and output variables use the ``Protobuf_`` prefix.
+ Variables with ``PROTOBUF_`` prefix are still supported for compatibility.
+
+The following variables can be set and are optional:
+
+``Protobuf_SRC_ROOT_FOLDER``
+ When compiling with MSVC, if this cache variable is set
+ the protobuf-default VS project build locations
+ (vsprojects/Debug and vsprojects/Release
+ or vsprojects/x64/Debug and vsprojects/x64/Release)
+ will be searched for libraries and binaries.
+``Protobuf_IMPORT_DIRS``
+ List of additional directories to be searched for
+ imported .proto files.
+``Protobuf_DEBUG``
+ .. versionadded:: 3.6
+
+ Show debug messages.
+``Protobuf_USE_STATIC_LIBS``
+ .. versionadded:: 3.9
+
+ Set to ON to force the use of the static libraries.
+ Default is OFF.
+
+Defines the following variables:
+
+``Protobuf_FOUND``
+ Found the Google Protocol Buffers library
+ (libprotobuf & header files)
+``Protobuf_VERSION``
+ .. versionadded:: 3.6
+
+ Version of package found.
+``Protobuf_INCLUDE_DIRS``
+ Include directories for Google Protocol Buffers
+``Protobuf_LIBRARIES``
+ The protobuf libraries
+``Protobuf_PROTOC_LIBRARIES``
+ The protoc libraries
+``Protobuf_LITE_LIBRARIES``
+ The protobuf-lite libraries
+
+.. versionadded:: 3.9
+ The following :prop_tgt:`IMPORTED` targets are also defined:
+
+``protobuf::libprotobuf``
+ The protobuf library.
+``protobuf::libprotobuf-lite``
+ The protobuf lite library.
+``protobuf::libprotoc``
+ The protoc library.
+``protobuf::protoc``
+ .. versionadded:: 3.10
+ The protoc compiler.
+
+The following cache variables are also available to set or use:
+
+``Protobuf_LIBRARY``
+ The protobuf library
+``Protobuf_PROTOC_LIBRARY``
+ The protoc library
+``Protobuf_INCLUDE_DIR``
+ The include directory for protocol buffers
+``Protobuf_PROTOC_EXECUTABLE``
+ The protoc compiler
+``Protobuf_LIBRARY_DEBUG``
+ The protobuf library (debug)
+``Protobuf_PROTOC_LIBRARY_DEBUG``
+ The protoc library (debug)
+``Protobuf_LITE_LIBRARY``
+ The protobuf lite library
+``Protobuf_LITE_LIBRARY_DEBUG``
+ The protobuf lite library (debug)
+
+Example:
+
+.. code-block:: cmake
+
+ find_package(Protobuf REQUIRED)
+ include_directories(${Protobuf_INCLUDE_DIRS})
+ include_directories(${CMAKE_CURRENT_BINARY_DIR})
+ protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS foo.proto)
+ protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS EXPORT_MACRO DLL_EXPORT foo.proto)
+ protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS DESCRIPTORS PROTO_DESCS foo.proto)
+ protobuf_generate_python(PROTO_PY foo.proto)
+ add_executable(bar bar.cc ${PROTO_SRCS} ${PROTO_HDRS})
+ target_link_libraries(bar ${Protobuf_LIBRARIES})
+
+.. note::
+ The ``protobuf_generate_cpp`` and ``protobuf_generate_python``
+ functions and :command:`add_executable` or :command:`add_library`
+ calls only work properly within the same directory.
+
+.. command:: protobuf_generate_cpp
+
+ Add custom commands to process ``.proto`` files to C++::
+
+ protobuf_generate_cpp (<SRCS> <HDRS>
+ [DESCRIPTORS <DESC>] [EXPORT_MACRO <MACRO>] [<ARGN>...])
+
+ ``SRCS``
+ Variable to define with autogenerated source files
+ ``HDRS``
+ Variable to define with autogenerated header files
+ ``DESCRIPTORS``
+ .. versionadded:: 3.10
+ Variable to define with autogenerated descriptor files, if requested.
+ ``EXPORT_MACRO``
+ is a macro which should expand to ``__declspec(dllexport)`` or
+ ``__declspec(dllimport)`` depending on what is being compiled.
+ ``ARGN``
+ ``.proto`` files
+
+.. command:: protobuf_generate_python
+
+ .. versionadded:: 3.4
+
+ Add custom commands to process ``.proto`` files to Python::
+
+ protobuf_generate_python (<PY> [<ARGN>...])
+
+ ``PY``
+ Variable to define with autogenerated Python files
+ ``ARGN``
+ ``.proto`` files
+#]=======================================================================]
+
+function(protobuf_generate)
+ set(_options APPEND_PATH DESCRIPTORS)
+ set(_singleargs LANGUAGE OUT_VAR EXPORT_MACRO PROTOC_OUT_DIR)
+ if(COMMAND target_sources)
+ list(APPEND _singleargs TARGET)
+ endif()
+ set(_multiargs PROTOS IMPORT_DIRS GENERATE_EXTENSIONS)
+
+ cmake_parse_arguments(protobuf_generate "${_options}" "${_singleargs}" "${_multiargs}" "${ARGN}")
+
+ if(NOT protobuf_generate_PROTOS AND NOT protobuf_generate_TARGET)
+ message(SEND_ERROR "Error: protobuf_generate called without any targets or source files")
+ return()
+ endif()
+
+ if(NOT protobuf_generate_OUT_VAR AND NOT protobuf_generate_TARGET)
+ message(SEND_ERROR "Error: protobuf_generate called without a target or output variable")
+ return()
+ endif()
+
+ if(NOT protobuf_generate_LANGUAGE)
+ set(protobuf_generate_LANGUAGE cpp)
+ endif()
+ string(TOLOWER ${protobuf_generate_LANGUAGE} protobuf_generate_LANGUAGE)
+
+ if(NOT protobuf_generate_PROTOC_OUT_DIR)
+ set(protobuf_generate_PROTOC_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
+ endif()
+
+ if(protobuf_generate_EXPORT_MACRO AND protobuf_generate_LANGUAGE STREQUAL cpp)
+ set(_dll_export_decl "dllexport_decl=${protobuf_generate_EXPORT_MACRO}:")
+ endif()
+
+ if(NOT protobuf_generate_GENERATE_EXTENSIONS)
+ if(protobuf_generate_LANGUAGE STREQUAL cpp)
+ set(protobuf_generate_GENERATE_EXTENSIONS .pb.h .pb.cc)
+ elseif(protobuf_generate_LANGUAGE STREQUAL python)
+ set(protobuf_generate_GENERATE_EXTENSIONS _pb2.py)
+ else()
+ message(SEND_ERROR "Error: protobuf_generate given unknown Language ${LANGUAGE}, please provide a value for GENERATE_EXTENSIONS")
+ return()
+ endif()
+ endif()
+
+ if(protobuf_generate_TARGET)
+ get_target_property(_source_list ${protobuf_generate_TARGET} SOURCES)
+ foreach(_file ${_source_list})
+ if(_file MATCHES "proto$")
+ list(APPEND protobuf_generate_PROTOS ${_file})
+ endif()
+ endforeach()
+ endif()
+
+ if(NOT protobuf_generate_PROTOS)
+ message(SEND_ERROR "Error: protobuf_generate could not find any .proto files")
+ return()
+ endif()
+
+ if(protobuf_generate_APPEND_PATH)
+ # Create an include path for each file specified
+ foreach(_file ${protobuf_generate_PROTOS})
+ get_filename_component(_abs_file ${_file} ABSOLUTE)
+ get_filename_component(_abs_path ${_abs_file} PATH)
+ list(FIND _protobuf_include_path ${_abs_path} _contains_already)
+ if(${_contains_already} EQUAL -1)
+ list(APPEND _protobuf_include_path -I ${_abs_path})
+ endif()
+ endforeach()
+ else()
+ set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR})
+ endif()
+
+ foreach(DIR ${protobuf_generate_IMPORT_DIRS})
+ get_filename_component(ABS_PATH ${DIR} ABSOLUTE)
+ list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
+ if(${_contains_already} EQUAL -1)
+ list(APPEND _protobuf_include_path -I ${ABS_PATH})
+ endif()
+ endforeach()
+
+ set(_generated_srcs_all)
+ foreach(_proto ${protobuf_generate_PROTOS})
+ get_filename_component(_abs_file ${_proto} ABSOLUTE)
+ get_filename_component(_abs_dir ${_abs_file} DIRECTORY)
+ get_filename_component(_basename ${_proto} NAME_WLE)
+ file(RELATIVE_PATH _rel_dir ${CMAKE_CURRENT_SOURCE_DIR} ${_abs_dir})
+
+ set(_possible_rel_dir)
+ if (NOT protobuf_generate_APPEND_PATH)
+ set(_possible_rel_dir ${_rel_dir}/)
+ endif()
+
+ set(_generated_srcs)
+ foreach(_ext ${protobuf_generate_GENERATE_EXTENSIONS})
+ list(APPEND _generated_srcs "${protobuf_generate_PROTOC_OUT_DIR}/${_possible_rel_dir}${_basename}${_ext}")
+ endforeach()
+
+ if(protobuf_generate_DESCRIPTORS AND protobuf_generate_LANGUAGE STREQUAL cpp)
+ set(_descriptor_file "${CMAKE_CURRENT_BINARY_DIR}/${_basename}.desc")
+ set(_dll_desc_out "--descriptor_set_out=${_descriptor_file}")
+ list(APPEND _generated_srcs ${_descriptor_file})
+ endif()
+ list(APPEND _generated_srcs_all ${_generated_srcs})
+
+ add_custom_command(
+ OUTPUT ${_generated_srcs}
+ COMMAND protobuf::protoc
+ ARGS --${protobuf_generate_LANGUAGE}_out ${_dll_export_decl}${protobuf_generate_PROTOC_OUT_DIR} ${_dll_desc_out} ${_protobuf_include_path} ${_abs_file}
+ DEPENDS ${_abs_file} protobuf::protoc
+ COMMENT "Running ${protobuf_generate_LANGUAGE} protocol buffer compiler on ${_proto}"
+ VERBATIM )
+ endforeach()
+
+ set_source_files_properties(${_generated_srcs_all} PROPERTIES GENERATED TRUE)
+ if(protobuf_generate_OUT_VAR)
+ set(${protobuf_generate_OUT_VAR} ${_generated_srcs_all} PARENT_SCOPE)
+ endif()
+ if(protobuf_generate_TARGET)
+ target_sources(${protobuf_generate_TARGET} PRIVATE ${_generated_srcs_all})
+ endif()
+endfunction()
+
+function(PROTOBUF_GENERATE_CPP SRCS HDRS)
+ cmake_parse_arguments(protobuf_generate_cpp "" "EXPORT_MACRO;DESCRIPTORS" "" ${ARGN})
+
+ set(_proto_files "${protobuf_generate_cpp_UNPARSED_ARGUMENTS}")
+ if(NOT _proto_files)
+ message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() called without any proto files")
+ return()
+ endif()
+
+ if(PROTOBUF_GENERATE_CPP_APPEND_PATH)
+ set(_append_arg APPEND_PATH)
+ endif()
+
+ if(protobuf_generate_cpp_DESCRIPTORS)
+ set(_descriptors DESCRIPTORS)
+ endif()
+
+ if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS)
+ set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}")
+ endif()
+
+ if(DEFINED Protobuf_IMPORT_DIRS)
+ set(_import_arg IMPORT_DIRS ${Protobuf_IMPORT_DIRS})
+ endif()
+
+ set(_outvar)
+ protobuf_generate(${_append_arg} ${_descriptors} LANGUAGE cpp EXPORT_MACRO ${protobuf_generate_cpp_EXPORT_MACRO} OUT_VAR _outvar ${_import_arg} PROTOS ${_proto_files})
+
+ set(${SRCS})
+ set(${HDRS})
+ if(protobuf_generate_cpp_DESCRIPTORS)
+ set(${protobuf_generate_cpp_DESCRIPTORS})
+ endif()
+
+ foreach(_file ${_outvar})
+ if(_file MATCHES "cc$")
+ list(APPEND ${SRCS} ${_file})
+ elseif(_file MATCHES "desc$")
+ list(APPEND ${protobuf_generate_cpp_DESCRIPTORS} ${_file})
+ else()
+ list(APPEND ${HDRS} ${_file})
+ endif()
+ endforeach()
+ set(${SRCS} ${${SRCS}} PARENT_SCOPE)
+ set(${HDRS} ${${HDRS}} PARENT_SCOPE)
+ if(protobuf_generate_cpp_DESCRIPTORS)
+ set(${protobuf_generate_cpp_DESCRIPTORS} "${${protobuf_generate_cpp_DESCRIPTORS}}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(PROTOBUF_GENERATE_PYTHON SRCS)
+ if(NOT ARGN)
+ message(SEND_ERROR "Error: PROTOBUF_GENERATE_PYTHON() called without any proto files")
+ return()
+ endif()
+
+ if(PROTOBUF_GENERATE_CPP_APPEND_PATH)
+ set(_append_arg APPEND_PATH)
+ endif()
+
+ if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS)
+ set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}")
+ endif()
+
+ if(DEFINED Protobuf_IMPORT_DIRS)
+ set(_import_arg IMPORT_DIRS ${Protobuf_IMPORT_DIRS})
+ endif()
+
+ set(_outvar)
+ protobuf_generate(${_append_arg} LANGUAGE python OUT_VAR _outvar ${_import_arg} PROTOS ${ARGN})
+ set(${SRCS} ${_outvar} PARENT_SCOPE)
+endfunction()
+
+
+if(Protobuf_DEBUG)
+ # Output some of their choices
+ message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
+ "Protobuf_USE_STATIC_LIBS = ${Protobuf_USE_STATIC_LIBS}")
+endif()
+
+
+# Backwards compatibility
+# Define camel case versions of input variables
+foreach(UPPER
+ PROTOBUF_SRC_ROOT_FOLDER
+ PROTOBUF_IMPORT_DIRS
+ PROTOBUF_DEBUG
+ PROTOBUF_LIBRARY
+ PROTOBUF_PROTOC_LIBRARY
+ PROTOBUF_INCLUDE_DIR
+ PROTOBUF_PROTOC_EXECUTABLE
+ PROTOBUF_LIBRARY_DEBUG
+ PROTOBUF_PROTOC_LIBRARY_DEBUG
+ PROTOBUF_LITE_LIBRARY
+ PROTOBUF_LITE_LIBRARY_DEBUG
+ )
+ if (DEFINED ${UPPER})
+ string(REPLACE "PROTOBUF_" "Protobuf_" Camel ${UPPER})
+ if (NOT DEFINED ${Camel})
+ set(${Camel} ${${UPPER}})
+ endif()
+ endif()
+endforeach()
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(_PROTOBUF_ARCH_DIR x64/)
+endif()
+
+
+# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
+if( Protobuf_USE_STATIC_LIBS )
+ set( _protobuf_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ if(WIN32)
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ else()
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .a )
+ endif()
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+
+# Internal function: search for normal library as well as a debug one
+# if the debug one is specified also include debug/optimized keywords
+# in *_LIBRARIES variable
+function(_protobuf_find_libraries name filename)
+ if(${name}_LIBRARIES)
+ # Use result recorded by a previous call.
+ return()
+ elseif(${name}_LIBRARY)
+ # Honor cache entry used by CMake 3.5 and lower.
+ set(${name}_LIBRARIES "${${name}_LIBRARY}" PARENT_SCOPE)
+ else()
+ find_library(${name}_LIBRARY_RELEASE
+ NAMES ${filename}
+ NAMES_PER_DIR
+ PATHS ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Release)
+ mark_as_advanced(${name}_LIBRARY_RELEASE)
+
+ find_library(${name}_LIBRARY_DEBUG
+ NAMES ${filename}d ${filename}
+ NAMES_PER_DIR
+ PATHS ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Debug)
+ mark_as_advanced(${name}_LIBRARY_DEBUG)
+
+ select_library_configurations(${name})
+
+ if(UNIX AND Threads_FOUND AND ${name}_LIBRARY)
+ list(APPEND ${name}_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+ endif()
+
+ set(${name}_LIBRARY "${${name}_LIBRARY}" PARENT_SCOPE)
+ set(${name}_LIBRARIES "${${name}_LIBRARIES}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+#
+# Main.
+#
+
+# By default have PROTOBUF_GENERATE_CPP macro pass -I to protoc
+# for each directory where a proto file is referenced.
+if(NOT DEFINED PROTOBUF_GENERATE_CPP_APPEND_PATH)
+ set(PROTOBUF_GENERATE_CPP_APPEND_PATH TRUE)
+endif()
+
+
+# Google's provided vcproj files generate libraries with a "lib"
+# prefix on Windows
+if(MSVC)
+ set(Protobuf_ORIG_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}")
+ set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
+
+ find_path(Protobuf_SRC_ROOT_FOLDER protobuf.pc.in)
+endif()
+
+if(UNIX)
+ # Protobuf headers may depend on threading.
+ find_package(Threads QUIET)
+endif()
+
+# The Protobuf library
+_protobuf_find_libraries(Protobuf protobuf)
+#DOC "The Google Protocol Buffers RELEASE Library"
+
+_protobuf_find_libraries(Protobuf_LITE protobuf-lite)
+
+# The Protobuf Protoc Library
+_protobuf_find_libraries(Protobuf_PROTOC protoc)
+
+# Restore original find library prefixes
+if(MSVC)
+ set(CMAKE_FIND_LIBRARY_PREFIXES "${Protobuf_ORIG_FIND_LIBRARY_PREFIXES}")
+endif()
+
+# Find the include directory
+find_path(Protobuf_INCLUDE_DIR
+ google/protobuf/service.h
+ PATHS ${Protobuf_SRC_ROOT_FOLDER}/src
+)
+mark_as_advanced(Protobuf_INCLUDE_DIR)
+
+# Find the protoc Executable
+find_program(Protobuf_PROTOC_EXECUTABLE
+ NAMES protoc
+ DOC "The Google Protocol Buffers Compiler"
+ PATHS
+ ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Release
+ ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Debug
+)
+mark_as_advanced(Protobuf_PROTOC_EXECUTABLE)
+
+if(Protobuf_DEBUG)
+ message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
+ "requested version of Google Protobuf is ${Protobuf_FIND_VERSION}")
+endif()
+
+if(Protobuf_INCLUDE_DIR)
+ set(_PROTOBUF_COMMON_HEADER ${Protobuf_INCLUDE_DIR}/google/protobuf/stubs/common.h)
+
+ if(Protobuf_DEBUG)
+ message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
+ "location of common.h: ${_PROTOBUF_COMMON_HEADER}")
+ endif()
+
+ set(Protobuf_VERSION "")
+ set(Protobuf_LIB_VERSION "")
+ file(STRINGS ${_PROTOBUF_COMMON_HEADER} _PROTOBUF_COMMON_H_CONTENTS REGEX "#define[ \t]+GOOGLE_PROTOBUF_VERSION[ \t]+")
+ if(_PROTOBUF_COMMON_H_CONTENTS MATCHES "#define[ \t]+GOOGLE_PROTOBUF_VERSION[ \t]+([0-9]+)")
+ set(Protobuf_LIB_VERSION "${CMAKE_MATCH_1}")
+ endif()
+ unset(_PROTOBUF_COMMON_H_CONTENTS)
+
+ math(EXPR _PROTOBUF_MAJOR_VERSION "${Protobuf_LIB_VERSION} / 1000000")
+ math(EXPR _PROTOBUF_MINOR_VERSION "${Protobuf_LIB_VERSION} / 1000 % 1000")
+ math(EXPR _PROTOBUF_SUBMINOR_VERSION "${Protobuf_LIB_VERSION} % 1000")
+ set(Protobuf_VERSION "${_PROTOBUF_MAJOR_VERSION}.${_PROTOBUF_MINOR_VERSION}.${_PROTOBUF_SUBMINOR_VERSION}")
+
+ if(Protobuf_DEBUG)
+ message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
+ "${_PROTOBUF_COMMON_HEADER} reveals protobuf ${Protobuf_VERSION}")
+ endif()
+
+ if(Protobuf_PROTOC_EXECUTABLE)
+ # Check Protobuf compiler version to be aligned with libraries version
+ execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} --version
+ OUTPUT_VARIABLE _PROTOBUF_PROTOC_EXECUTABLE_VERSION)
+
+ if("${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}" MATCHES "libprotoc ([0-9.]+)")
+ set(_PROTOBUF_PROTOC_EXECUTABLE_VERSION "${CMAKE_MATCH_1}")
+ endif()
+
+ if(Protobuf_DEBUG)
+ message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
+ "${Protobuf_PROTOC_EXECUTABLE} reveals version ${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}")
+ endif()
+
+ if(NOT "${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}" VERSION_EQUAL "${Protobuf_VERSION}")
+ message(WARNING "Protobuf compiler version ${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}"
+ " doesn't match library version ${Protobuf_VERSION}")
+ endif()
+ endif()
+
+ if(Protobuf_LIBRARY)
+ if(NOT TARGET protobuf::libprotobuf)
+ add_library(protobuf::libprotobuf UNKNOWN IMPORTED)
+ set_target_properties(protobuf::libprotobuf PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${Protobuf_INCLUDE_DIR}")
+ if(EXISTS "${Protobuf_LIBRARY}")
+ set_target_properties(protobuf::libprotobuf PROPERTIES
+ IMPORTED_LOCATION "${Protobuf_LIBRARY}")
+ endif()
+ if(EXISTS "${Protobuf_LIBRARY_RELEASE}")
+ set_property(TARGET protobuf::libprotobuf APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(protobuf::libprotobuf PROPERTIES
+ IMPORTED_LOCATION_RELEASE "${Protobuf_LIBRARY_RELEASE}")
+ endif()
+ if(EXISTS "${Protobuf_LIBRARY_DEBUG}")
+ set_property(TARGET protobuf::libprotobuf APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(protobuf::libprotobuf PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${Protobuf_LIBRARY_DEBUG}")
+ endif()
+ if (Protobuf_VERSION VERSION_GREATER_EQUAL "3.6")
+ set_property(TARGET protobuf::libprotobuf APPEND PROPERTY
+ INTERFACE_COMPILE_FEATURES cxx_std_11
+ )
+ endif()
+ if (MSVC AND NOT Protobuf_USE_STATIC_LIBS)
+ set_property(TARGET protobuf::libprotobuf APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS "PROTOBUF_USE_DLLS"
+ )
+ endif()
+ if(UNIX AND TARGET Threads::Threads)
+ set_property(TARGET protobuf::libprotobuf APPEND PROPERTY
+ INTERFACE_LINK_LIBRARIES Threads::Threads)
+ endif()
+ endif()
+ endif()
+
+ if(Protobuf_LITE_LIBRARY)
+ if(NOT TARGET protobuf::libprotobuf-lite)
+ add_library(protobuf::libprotobuf-lite UNKNOWN IMPORTED)
+ set_target_properties(protobuf::libprotobuf-lite PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${Protobuf_INCLUDE_DIR}")
+ if(EXISTS "${Protobuf_LITE_LIBRARY}")
+ set_target_properties(protobuf::libprotobuf-lite PROPERTIES
+ IMPORTED_LOCATION "${Protobuf_LITE_LIBRARY}")
+ endif()
+ if(EXISTS "${Protobuf_LITE_LIBRARY_RELEASE}")
+ set_property(TARGET protobuf::libprotobuf-lite APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(protobuf::libprotobuf-lite PROPERTIES
+ IMPORTED_LOCATION_RELEASE "${Protobuf_LITE_LIBRARY_RELEASE}")
+ endif()
+ if(EXISTS "${Protobuf_LITE_LIBRARY_DEBUG}")
+ set_property(TARGET protobuf::libprotobuf-lite APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(protobuf::libprotobuf-lite PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${Protobuf_LITE_LIBRARY_DEBUG}")
+ endif()
+ if (MSVC AND NOT Protobuf_USE_STATIC_LIBS)
+ set_property(TARGET protobuf::libprotobuf-lite APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS "PROTOBUF_USE_DLLS"
+ )
+ endif()
+ if(UNIX AND TARGET Threads::Threads)
+ set_property(TARGET protobuf::libprotobuf-lite APPEND PROPERTY
+ INTERFACE_LINK_LIBRARIES Threads::Threads)
+ endif()
+ endif()
+ endif()
+
+ if(Protobuf_PROTOC_LIBRARY)
+ if(NOT TARGET protobuf::libprotoc)
+ add_library(protobuf::libprotoc UNKNOWN IMPORTED)
+ set_target_properties(protobuf::libprotoc PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${Protobuf_INCLUDE_DIR}")
+ if(EXISTS "${Protobuf_PROTOC_LIBRARY}")
+ set_target_properties(protobuf::libprotoc PROPERTIES
+ IMPORTED_LOCATION "${Protobuf_PROTOC_LIBRARY}")
+ endif()
+ if(EXISTS "${Protobuf_PROTOC_LIBRARY_RELEASE}")
+ set_property(TARGET protobuf::libprotoc APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(protobuf::libprotoc PROPERTIES
+ IMPORTED_LOCATION_RELEASE "${Protobuf_PROTOC_LIBRARY_RELEASE}")
+ endif()
+ if(EXISTS "${Protobuf_PROTOC_LIBRARY_DEBUG}")
+ set_property(TARGET protobuf::libprotoc APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(protobuf::libprotoc PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${Protobuf_PROTOC_LIBRARY_DEBUG}")
+ endif()
+ if (Protobuf_VERSION VERSION_GREATER_EQUAL "3.6")
+ set_property(TARGET protobuf::libprotoc APPEND PROPERTY
+ INTERFACE_COMPILE_FEATURES cxx_std_11
+ )
+ endif()
+ if (MSVC AND NOT Protobuf_USE_STATIC_LIBS)
+ set_property(TARGET protobuf::libprotoc APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS "PROTOBUF_USE_DLLS"
+ )
+ endif()
+ if(UNIX AND TARGET Threads::Threads)
+ set_property(TARGET protobuf::libprotoc APPEND PROPERTY
+ INTERFACE_LINK_LIBRARIES Threads::Threads)
+ endif()
+ endif()
+ endif()
+
+ if(Protobuf_PROTOC_EXECUTABLE)
+ if(NOT TARGET protobuf::protoc)
+ add_executable(protobuf::protoc IMPORTED)
+ if(EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
+ set_target_properties(protobuf::protoc PROPERTIES
+ IMPORTED_LOCATION "${Protobuf_PROTOC_EXECUTABLE}")
+ endif()
+ endif()
+ endif()
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Protobuf
+ REQUIRED_VARS Protobuf_LIBRARIES Protobuf_INCLUDE_DIR
+ VERSION_VAR Protobuf_VERSION
+)
+
+if(Protobuf_FOUND)
+ set(Protobuf_INCLUDE_DIRS ${Protobuf_INCLUDE_DIR})
+endif()
+
+# Restore the original find library ordering
+if( Protobuf_USE_STATIC_LIBS )
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ${_protobuf_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
+endif()
+
+# Backwards compatibility
+# Define upper case versions of output variables
+foreach(Camel
+ Protobuf_SRC_ROOT_FOLDER
+ Protobuf_IMPORT_DIRS
+ Protobuf_DEBUG
+ Protobuf_INCLUDE_DIRS
+ Protobuf_LIBRARIES
+ Protobuf_PROTOC_LIBRARIES
+ Protobuf_LITE_LIBRARIES
+ Protobuf_LIBRARY
+ Protobuf_PROTOC_LIBRARY
+ Protobuf_INCLUDE_DIR
+ Protobuf_PROTOC_EXECUTABLE
+ Protobuf_LIBRARY_DEBUG
+ Protobuf_PROTOC_LIBRARY_DEBUG
+ Protobuf_LITE_LIBRARY
+ Protobuf_LITE_LIBRARY_DEBUG
+ )
+ string(TOUPPER ${Camel} UPPER)
+ set(${UPPER} ${${Camel}})
+endforeach()
diff --git a/Modules/FindPython.cmake b/Modules/FindPython.cmake
new file mode 100644
index 0000000..a4b7a03
--- /dev/null
+++ b/Modules/FindPython.cmake
@@ -0,0 +1,581 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPython
+----------
+
+.. versionadded:: 3.12
+
+Find Python interpreter, compiler and development environment (include
+directories and libraries).
+
+.. versionadded:: 3.19
+ 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.
+* ``Compiler``: search for Python compiler. Only offered by IronPython.
+* ``Development``: search for development artifacts (include directories and
+ libraries).
+
+ .. versionadded:: 3.18
+ This component includes two sub-components which can be specified
+ independently:
+
+ * ``Development.Module``: search for artifacts for Python module
+ developments.
+ * ``Development.Embed``: search for artifacts for Python embedding
+ developments.
+
+* ``NumPy``: search for NumPy include directories.
+
+.. versionadded:: 3.14
+ Added the ``NumPy`` component.
+
+If no ``COMPONENTS`` are specified, ``Interpreter`` is assumed.
+
+If component ``Development`` is specified, it implies sub-components
+``Development.Module`` and ``Development.Embed``.
+
+To ensure consistent versions between components ``Interpreter``, ``Compiler``,
+``Development`` (or one of its sub-components) and ``NumPy``, specify all
+components at the same time::
+
+ find_package (Python COMPONENTS Interpreter Development)
+
+This module looks preferably for version 3 of Python. If not found, version 2
+is searched.
+To manage concurrent versions 3 and 2 of Python, use :module:`FindPython3` and
+:module:`FindPython2` modules rather than this one.
+
+.. note::
+
+ If components ``Interpreter`` and ``Development`` (or one of its
+ sub-components) are both specified, this module search only for interpreter
+ with same platform architecture as the one defined by ``CMake``
+ configuration. This constraint does not apply if only ``Interpreter``
+ component is specified.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+This module defines the following :ref:`Imported Targets <Imported Targets>`:
+
+.. versionchanged:: 3.14
+ :ref:`Imported Targets <Imported Targets>` are only created when
+ :prop_gbl:`CMAKE_ROLE` is ``PROJECT``.
+
+``Python::Interpreter``
+ Python interpreter. Target defined if component ``Interpreter`` is found.
+``Python::Compiler``
+ Python compiler. Target defined if component ``Compiler`` is found.
+
+``Python::Module``
+ .. versionadded:: 3.15
+
+ Python library for Python module. Target defined if component
+ ``Development.Module`` is found.
+
+``Python::Python``
+ Python library for Python embedding. Target defined if component
+ ``Development.Embed`` is found.
+
+``Python::NumPy``
+ .. versionadded:: 3.14
+
+ NumPy Python library. Target defined if component ``NumPy`` is found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project
+(see :ref:`Standard Variable Names <CMake Developer Standard Variable Names>`):
+
+``Python_FOUND``
+ System has the Python requested components.
+``Python_Interpreter_FOUND``
+ System has the Python interpreter.
+``Python_EXECUTABLE``
+ Path to the Python interpreter.
+``Python_INTERPRETER_ID``
+ A short string unique to the interpreter. Possible values include:
+ * Python
+ * ActivePython
+ * Anaconda
+ * Canopy
+ * IronPython
+ * PyPy
+``Python_STDLIB``
+ Standard platform independent installation directory.
+
+ Information returned by
+ ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=True)``
+ or else ``sysconfig.get_path('stdlib')``.
+``Python_STDARCH``
+ Standard platform dependent installation directory.
+
+ Information returned by
+ ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=True)``
+ or else ``sysconfig.get_path('platstdlib')``.
+``Python_SITELIB``
+ Third-party platform independent installation directory.
+
+ Information returned by
+ ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=False)``
+ or else ``sysconfig.get_path('purelib')``.
+``Python_SITEARCH``
+ Third-party platform dependent installation directory.
+
+ Information returned by
+ ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)``
+ or else ``sysconfig.get_path('platlib')``.
+
+``Python_SOABI``
+ .. versionadded:: 3.17
+
+ Extension suffix for modules.
+
+ Information returned by
+ ``distutils.sysconfig.get_config_var('SOABI')`` or computed from
+ ``distutils.sysconfig.get_config_var('EXT_SUFFIX')`` or
+ ``python-config --extension-suffix``. If package ``distutils.sysconfig`` is
+ not available, ``sysconfig.get_config_var('SOABI')`` or
+ ``sysconfig.get_config_var('EXT_SUFFIX')`` are used.
+
+``Python_Compiler_FOUND``
+ System has the Python compiler.
+``Python_COMPILER``
+ Path to the Python compiler. Only offered by IronPython.
+``Python_COMPILER_ID``
+ A short string unique to the compiler. Possible values include:
+ * IronPython
+
+``Python_DOTNET_LAUNCHER``
+ .. versionadded:: 3.18
+
+ The ``.Net`` interpreter. Only used by ``IronPython`` implementation.
+
+``Python_Development_FOUND``
+ System has the Python development artifacts.
+
+``Python_Development.Module_FOUND``
+ .. versionadded:: 3.18
+
+ System has the Python development artifacts for Python module.
+
+``Python_Development.Embed_FOUND``
+ .. versionadded:: 3.18
+
+ System has the Python development artifacts for Python embedding.
+
+``Python_INCLUDE_DIRS``
+
+ The Python include directories.
+
+``Python_LINK_OPTIONS``
+ .. versionadded:: 3.19
+
+ The Python link options. Some configurations require specific link options
+ for a correct build and execution.
+
+``Python_LIBRARIES``
+ The Python libraries.
+``Python_LIBRARY_DIRS``
+ The Python library directories.
+``Python_RUNTIME_LIBRARY_DIRS``
+ The Python runtime library directories.
+``Python_VERSION``
+ Python version.
+``Python_VERSION_MAJOR``
+ Python major version.
+``Python_VERSION_MINOR``
+ Python minor version.
+``Python_VERSION_PATCH``
+ Python patch version.
+
+``Python_PyPy_VERSION``
+ .. versionadded:: 3.18
+
+ Python PyPy version.
+
+``Python_NumPy_FOUND``
+ .. versionadded:: 3.14
+
+ System has the NumPy.
+
+``Python_NumPy_INCLUDE_DIRS``
+ .. versionadded:: 3.14
+
+ The NumPy include directories.
+
+``Python_NumPy_VERSION``
+ .. versionadded:: 3.14
+
+ The NumPy version.
+
+Hints
+^^^^^
+
+``Python_ROOT_DIR``
+ Define the root directory of a Python installation.
+
+``Python_USE_STATIC_LIBS``
+ * If not defined, search for shared libraries and static libraries in that
+ order.
+ * If set to TRUE, search **only** for static libraries.
+ * If set to FALSE, search **only** for shared libraries.
+
+``Python_FIND_ABI``
+ .. versionadded:: 3.16
+
+ This variable defines which ABIs, as defined in
+ `PEP 3149 <https://www.python.org/dev/peps/pep-3149/>`_, should be searched.
+
+ .. note::
+
+ This hint will be honored only when searched for ``Python`` version 3.
+
+ .. note::
+
+ If ``Python_FIND_ABI`` is not defined, any ABI will be searched.
+
+ The ``Python_FIND_ABI`` variable is a 3-tuple specifying, in that order,
+ ``pydebug`` (``d``), ``pymalloc`` (``m``) and ``unicode`` (``u``) flags.
+ Each element can be set to one of the following:
+
+ * ``ON``: Corresponding flag is selected.
+ * ``OFF``: Corresponding flag is not selected.
+ * ``ANY``: The two possibilities (``ON`` and ``OFF``) will be searched.
+
+ From this 3-tuple, various ABIs will be searched starting from the most
+ specialized to the most general. Moreover, ``debug`` versions will be
+ searched **after** ``non-debug`` ones.
+
+ For example, if we have::
+
+ set (Python_FIND_ABI "ON" "ANY" "ANY")
+
+ The following flags combinations will be appended, in that order, to the
+ artifact names: ``dmu``, ``dm``, ``du``, and ``d``.
+
+ And to search any possible ABIs::
+
+ set (Python_FIND_ABI "ANY" "ANY" "ANY")
+
+ The following combinations, in that order, will be used: ``mu``, ``m``,
+ ``u``, ``<empty>``, ``dmu``, ``dm``, ``du`` and ``d``.
+
+ .. note::
+
+ This hint is useful only on ``POSIX`` systems. So, on ``Windows`` systems,
+ when ``Python_FIND_ABI`` is defined, ``Python`` distributions from
+ `python.org <https://www.python.org/>`_ will be found only if value for
+ each flag is ``OFF`` or ``ANY``.
+
+``Python_FIND_STRATEGY``
+ .. versionadded:: 3.15
+
+ This variable defines how lookup will be done.
+ The ``Python_FIND_STRATEGY`` variable can be set to one of the following:
+
+ * ``VERSION``: Try to find the most recent version in all specified
+ locations.
+ This is the default if policy :policy:`CMP0094` is undefined or set to
+ ``OLD``.
+ * ``LOCATION``: Stops lookup as soon as a version satisfying version
+ constraints is founded.
+ This is the default if policy :policy:`CMP0094` is set to ``NEW``.
+
+``Python_FIND_REGISTRY``
+ .. versionadded:: 3.13
+
+ On Windows the ``Python_FIND_REGISTRY`` variable determine the order
+ of preference between registry and environment variables.
+ the ``Python_FIND_REGISTRY`` variable can be set to one of the following:
+
+ * ``FIRST``: Try to use registry before environment variables.
+ This is the default.
+ * ``LAST``: Try to use registry after environment variables.
+ * ``NEVER``: Never try to use registry.
+
+``Python_FIND_FRAMEWORK``
+ .. versionadded:: 3.15
+
+ On macOS the ``Python_FIND_FRAMEWORK`` variable determine the order of
+ preference between Apple-style and unix-style package components.
+ This variable can take same values as :variable:`CMAKE_FIND_FRAMEWORK`
+ variable.
+
+ .. note::
+
+ Value ``ONLY`` is not supported so ``FIRST`` will be used instead.
+
+ If ``Python_FIND_FRAMEWORK`` is not defined, :variable:`CMAKE_FIND_FRAMEWORK`
+ variable will be used, if any.
+
+``Python_FIND_VIRTUALENV``
+ .. versionadded:: 3.15
+
+ This variable defines the handling of virtual environments managed by
+ ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment
+ is active (i.e. the ``activate`` script has been evaluated). In this case, it
+ takes precedence over ``Python_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK``
+ variables. The ``Python_FIND_VIRTUALENV`` variable can be set to one of the
+ following:
+
+ * ``FIRST``: The virtual environment is used before any other standard
+ paths to look-up for the interpreter. This is the default.
+ * ``ONLY``: Only the virtual environment is used to look-up for the
+ interpreter.
+ * ``STANDARD``: The virtual environment is not used to look-up for the
+ interpreter but environment variable ``PATH`` is always considered.
+ In this case, variable ``Python_FIND_REGISTRY`` (Windows) or
+ ``CMAKE_FIND_FRAMEWORK`` (macOS) can be set with value ``LAST`` or
+ ``NEVER`` to select preferably the interpreter from the virtual
+ environment.
+
+ .. versionadded:: 3.17
+ Added support for ``conda`` environments.
+
+ .. note::
+
+ If the component ``Development`` is requested, it is **strongly**
+ recommended to also include the component ``Interpreter`` to get expected
+ result.
+
+``Python_FIND_IMPLEMENTATIONS``
+ .. versionadded:: 3.18
+
+ This variable defines, in an ordered list, the different implementations
+ which will be searched. The ``Python_FIND_IMPLEMENTATIONS`` variable can
+ hold the following values:
+
+ * ``CPython``: this is the standard implementation. Various products, like
+ ``Anaconda`` or ``ActivePython``, rely on this implementation.
+ * ``IronPython``: This implementation use the ``CSharp`` language for
+ ``.NET Framework`` on top of the `Dynamic Language Runtime` (``DLR``).
+ See `IronPython <http://ironpython.net>`_.
+ * ``PyPy``: This implementation use ``RPython`` language and
+ ``RPython translation toolchain`` to produce the python interpreter.
+ See `PyPy <https://www.pypy.org>`_.
+
+ The default value is:
+
+ * Windows platform: ``CPython``, ``IronPython``
+ * Other platforms: ``CPython``
+
+ .. note::
+
+ This hint has the lowest priority of all hints, so even if, for example,
+ you specify ``IronPython`` first and ``CPython`` in second, a python
+ product based on ``CPython`` can be selected because, for example with
+ ``Python_FIND_STRATEGY=LOCATION``, each location will be search first for
+ ``IronPython`` and second for ``CPython``.
+
+ .. note::
+
+ When ``IronPython`` is specified, on platforms other than ``Windows``, the
+ ``.Net`` interpreter (i.e. ``mono`` command) is expected to be available
+ through the ``PATH`` variable.
+
+``Python_FIND_UNVERSIONED_NAMES``
+ .. versionadded:: 3.20
+
+ This variable defines how the generic names will be searched. Currently, it
+ only applies to the generic names of the interpreter, namely, ``python3`` or
+ ``python2`` and ``python``.
+ The ``Python_FIND_UNVERSIONED_NAMES`` variable can be set to one of the
+ following values:
+
+ * ``FIRST``: The generic names are searched before the more specialized ones
+ (such as ``python2.5`` for example).
+ * ``LAST``: The generic names are searched after the more specialized ones.
+ This is the default.
+ * ``NEVER``: The generic name are not searched at all.
+
+Artifacts Specification
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.16
+
+To solve special cases, it is possible to specify directly the artifacts by
+setting the following variables:
+
+``Python_EXECUTABLE``
+ The path to the interpreter.
+
+``Python_COMPILER``
+ The path to the compiler.
+
+``Python_DOTNET_LAUNCHER``
+ .. versionadded:: 3.18
+
+ The ``.Net`` interpreter. Only used by ``IronPython`` implementation.
+
+``Python_LIBRARY``
+ The path to the library. It will be used to compute the
+ variables ``Python_LIBRARIES``, ``Python_LIBRARY_DIRS`` and
+ ``Python_RUNTIME_LIBRARY_DIRS``.
+
+``Python_INCLUDE_DIR``
+ The path to the directory of the ``Python`` headers. It will be used to
+ compute the variable ``Python_INCLUDE_DIRS``.
+
+``Python_NumPy_INCLUDE_DIR``
+ The path to the directory of the ``NumPy`` headers. It will be used to
+ compute the variable ``Python_NumPy_INCLUDE_DIRS``.
+
+.. note::
+
+ All paths must be absolute. Any artifact specified with a relative path
+ will be ignored.
+
+.. note::
+
+ When an artifact is specified, all ``HINTS`` will be ignored and no search
+ will be performed for this artifact.
+
+ If more than one artifact is specified, it is the user's responsibility to
+ ensure the consistency of the various artifacts.
+
+By default, this module supports multiple calls in different directories of a
+project with different version/component requirements while providing correct
+and consistent results for each call. To support this behavior, ``CMake`` cache
+is not used in the traditional way which can be problematic for interactive
+specification. So, to enable also interactive specification, module behavior
+can be controlled with the following variable:
+
+``Python_ARTIFACTS_INTERACTIVE``
+ .. versionadded:: 3.18
+
+ Selects the behavior of the module. This is a boolean variable:
+
+ * If set to ``TRUE``: Create CMake cache entries for the above artifact
+ specification variables so that users can edit them interactively.
+ This disables support for multiple version/component requirements.
+ * If set to ``FALSE`` or undefined: Enable multiple version/component
+ requirements.
+
+Commands
+^^^^^^^^
+
+This module defines the command ``Python_add_library`` (when
+:prop_gbl:`CMAKE_ROLE` is ``PROJECT``), which has the same semantics as
+:command:`add_library` and adds a dependency to target ``Python::Python`` or,
+when library type is ``MODULE``, to target ``Python::Module`` and takes care of
+Python module naming rules::
+
+ Python_add_library (<name> [STATIC | SHARED | MODULE [WITH_SOABI]]
+ <source1> [<source2> ...])
+
+If the library type is not specified, ``MODULE`` is assumed.
+
+.. versionadded:: 3.17
+ For ``MODULE`` library type, if option ``WITH_SOABI`` is specified, the
+ module suffix will include the ``Python_SOABI`` value, if any.
+#]=======================================================================]
+
+
+cmake_policy(PUSH)
+# numbers and boolean constants
+cmake_policy (SET CMP0012 NEW)
+
+
+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)
+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})
+ set (_Python_REQUIRED ${Python_FIND_REQUIRED})
+ set (Python_FIND_QUIETLY TRUE)
+ set (Python_FIND_REQUIRED FALSE)
+
+ set (_Python_REQUIRED_VERSION_LAST 2)
+
+ unset (_Python_INPUT_VARS)
+ foreach (_Python_ITEM IN ITEMS Python_EXECUTABLE Python_COMPILER Python_LIBRARY
+ Python_INCLUDE_DIR Python_NumPy_INCLUDE_DIR)
+ if (NOT DEFINED ${_Python_ITEM})
+ list (APPEND _Python_INPUT_VARS ${_Python_ITEM})
+ endif()
+ endforeach()
+
+ foreach (_Python_REQUIRED_VERSION_MAJOR IN LISTS _Python_REQUIRED_VERSIONS)
+ set (Python_FIND_VERSION ${_Python_REQUIRED_VERSION_MAJOR})
+ include (${CMAKE_CURRENT_LIST_DIR}/FindPython/Support.cmake)
+ if (Python_FOUND OR
+ _Python_REQUIRED_VERSION_MAJOR EQUAL _Python_REQUIRED_VERSION_LAST)
+ break()
+ endif()
+ # clean-up INPUT variables not set by the user
+ foreach (_Python_ITEM IN LISTS _Python_INPUT_VARS)
+ unset (${_Python_ITEM})
+ endforeach()
+ # clean-up some CACHE variables to ensure look-up restart from scratch
+ foreach (_Python_ITEM IN LISTS _Python_CACHED_VARS)
+ unset (${_Python_ITEM} CACHE)
+ endforeach()
+ endforeach()
+
+ unset (Python_FIND_VERSION)
+
+ set (Python_FIND_QUIETLY ${_Python_QUIETLY})
+ 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 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)
+ macro (Python_add_library)
+ __Python_add_library (Python ${ARGV})
+ endmacro()
+endif()
+
+unset (_PYTHON_PREFIX)
+
+cmake_policy(POP)
diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake
new file mode 100644
index 0000000..8e70e11
--- /dev/null
+++ b/Modules/FindPython/Support.cmake
@@ -0,0 +1,3369 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#
+# This file is a "template" file used by various FindPython modules.
+#
+
+#
+# Initial configuration
+#
+
+cmake_policy(PUSH)
+# numbers and boolean constants
+cmake_policy (SET CMP0012 NEW)
+# IN_LIST operator
+cmake_policy (SET CMP0057 NEW)
+
+if (NOT DEFINED _PYTHON_PREFIX)
+ message (FATAL_ERROR "FindPython: INTERNAL ERROR")
+endif()
+if (NOT DEFINED _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+ message (FATAL_ERROR "FindPython: INTERNAL ERROR")
+endif()
+if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL "3")
+ set(_${_PYTHON_PREFIX}_VERSIONS 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
+elseif (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL "2")
+ set(_${_PYTHON_PREFIX}_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
+else()
+ message (FATAL_ERROR "FindPython: INTERNAL ERROR")
+endif()
+
+get_property(_${_PYTHON_PREFIX}_CMAKE_ROLE GLOBAL PROPERTY CMAKE_ROLE)
+
+include (${CMAKE_CURRENT_LIST_DIR}/../FindPackageHandleStandardArgs.cmake)
+
+#
+# helper commands
+#
+macro (_PYTHON_DISPLAY_FAILURE _PYTHON_MSG)
+ if (${_PYTHON_PREFIX}_FIND_REQUIRED)
+ message (FATAL_ERROR "${_PYTHON_MSG}")
+ else()
+ if (NOT ${_PYTHON_PREFIX}_FIND_QUIETLY)
+ message(STATUS "${_PYTHON_MSG}")
+ endif ()
+ endif()
+
+ set (${_PYTHON_PREFIX}_FOUND FALSE)
+ string (TOUPPER "${_PYTHON_PREFIX}" _${_PYTHON_PREFIX}_UPPER_PREFIX)
+ set (${_PYTHON_UPPER_PREFIX}_FOUND FALSE)
+endmacro()
+
+
+function (_PYTHON_MARK_AS_INTERNAL)
+ foreach (var IN LISTS ARGV)
+ if (DEFINED CACHE{${var}})
+ set_property (CACHE ${var} PROPERTY TYPE INTERNAL)
+ endif()
+ endforeach()
+endfunction()
+
+
+macro (_PYTHON_SELECT_LIBRARY_CONFIGURATIONS _PYTHON_BASENAME)
+ if(NOT DEFINED ${_PYTHON_BASENAME}_LIBRARY_RELEASE)
+ set(${_PYTHON_BASENAME}_LIBRARY_RELEASE "${_PYTHON_BASENAME}_LIBRARY_RELEASE-NOTFOUND")
+ endif()
+ if(NOT DEFINED ${_PYTHON_BASENAME}_LIBRARY_DEBUG)
+ set(${_PYTHON_BASENAME}_LIBRARY_DEBUG "${_PYTHON_BASENAME}_LIBRARY_DEBUG-NOTFOUND")
+ endif()
+
+ get_property(_PYTHON_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if (${_PYTHON_BASENAME}_LIBRARY_DEBUG AND ${_PYTHON_BASENAME}_LIBRARY_RELEASE AND
+ NOT ${_PYTHON_BASENAME}_LIBRARY_DEBUG STREQUAL ${_PYTHON_BASENAME}_LIBRARY_RELEASE AND
+ (_PYTHON_isMultiConfig OR CMAKE_BUILD_TYPE))
+ # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for
+ # single-config generators, set optimized and debug libraries
+ set (${_PYTHON_BASENAME}_LIBRARIES "")
+ foreach (_PYTHON_libname IN LISTS ${_PYTHON_BASENAME}_LIBRARY_RELEASE)
+ list( APPEND ${_PYTHON_BASENAME}_LIBRARIES optimized "${_PYTHON_libname}")
+ endforeach()
+ foreach (_PYTHON_libname IN LISTS ${_PYTHON_BASENAME}_LIBRARY_DEBUG)
+ list( APPEND ${_PYTHON_BASENAME}_LIBRARIES debug "${_PYTHON_libname}")
+ endforeach()
+ elseif (${_PYTHON_BASENAME}_LIBRARY_RELEASE)
+ set (${_PYTHON_BASENAME}_LIBRARIES "${${_PYTHON_BASENAME}_LIBRARY_RELEASE}")
+ elseif (${_PYTHON_BASENAME}_LIBRARY_DEBUG)
+ set (${_PYTHON_BASENAME}_LIBRARIES "${${_PYTHON_BASENAME}_LIBRARY_DEBUG}")
+ else()
+ set (${_PYTHON_BASENAME}_LIBRARIES "${_PYTHON_BASENAME}_LIBRARY-NOTFOUND")
+ endif()
+endmacro()
+
+
+macro (_PYTHON_FIND_FRAMEWORKS)
+ if (CMAKE_HOST_APPLE OR APPLE)
+ file(TO_CMAKE_PATH "$ENV{CMAKE_FRAMEWORK_PATH}" _pff_CMAKE_FRAMEWORK_PATH)
+ set (_pff_frameworks ${CMAKE_FRAMEWORK_PATH}
+ ${_pff_CMAKE_FRAMEWORK_PATH}
+ ~/Library/Frameworks
+ /usr/local/Frameworks
+ ${CMAKE_SYSTEM_FRAMEWORK_PATH})
+ list (REMOVE_DUPLICATES _pff_frameworks)
+ foreach (_pff_implementation IN LISTS _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+ unset (_${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS)
+ if (_pff_implementation STREQUAL "CPython")
+ foreach (_pff_framework IN LISTS _pff_frameworks)
+ if (EXISTS ${_pff_framework}/Python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}.framework)
+ list (APPEND _${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS ${_pff_framework}/Python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}.framework)
+ endif()
+ if (EXISTS ${_pff_framework}/Python.framework)
+ list (APPEND _${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS ${_pff_framework}/Python.framework)
+ endif()
+ endforeach()
+ elseif (_pff_implementation STREQUAL "IronPython")
+ foreach (_pff_framework IN LISTS _pff_frameworks)
+ if (EXISTS ${_pff_framework}/IronPython.framework)
+ list (APPEND _${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS ${_pff_framework}/IronPython.framework)
+ endif()
+ endforeach()
+ endif()
+ endforeach()
+ unset (_pff_implementation)
+ unset (_pff_frameworks)
+ unset (_pff_framework)
+ endif()
+endmacro()
+
+function (_PYTHON_GET_FRAMEWORKS _PYTHON_PGF_FRAMEWORK_PATHS)
+ cmake_parse_arguments (PARSE_ARGV 1 _PGF "" "" "IMPLEMENTATIONS;VERSION")
+
+ if (NOT _PGF_IMPLEMENTATIONS)
+ set (_PGF_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS})
+ endif()
+
+ set (framework_paths)
+
+ foreach (implementation IN LISTS _PGF_IMPLEMENTATIONS)
+ if (implementation STREQUAL "CPython")
+ foreach (version IN LISTS _PGF_VERSION)
+ foreach (framework IN LISTS _${_PYTHON_PREFIX}_${implementation}_FRAMEWORKS)
+ if (EXISTS "${framework}/Versions/${version}")
+ list (APPEND framework_paths "${framework}/Versions/${version}")
+ endif()
+ endforeach()
+ endforeach()
+ elseif (implementation STREQUAL "IronPython")
+ foreach (version IN LISTS _PGF_VERSION)
+ foreach (framework IN LISTS _${_PYTHON_PREFIX}_${implementation}_FRAMEWORKS)
+ # pick-up all available versions
+ file (GLOB versions LIST_DIRECTORIES true RELATIVE "${framework}/Versions/"
+ "${framework}/Versions/${version}*")
+ list (SORT versions ORDER DESCENDING)
+ list (TRANSFORM versions PREPEND "${framework}/Versions/")
+ list (APPEND framework_paths ${versions})
+ endforeach()
+ endforeach()
+ endif()
+ endforeach()
+
+ set (${_PYTHON_PGF_FRAMEWORK_PATHS} ${framework_paths} PARENT_SCOPE)
+endfunction()
+
+function (_PYTHON_GET_REGISTRIES _PYTHON_PGR_REGISTRY_PATHS)
+ cmake_parse_arguments (PARSE_ARGV 1 _PGR "" "" "IMPLEMENTATIONS;VERSION")
+
+ if (NOT _PGR_IMPLEMENTATIONS)
+ set (_PGR_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS})
+ endif()
+
+ set (registries)
+
+ foreach (implementation IN LISTS _PGR_IMPLEMENTATIONS)
+ if (implementation STREQUAL "CPython")
+ foreach (version IN LISTS _PGR_VERSION)
+ string (REPLACE "." "" version_no_dots ${version})
+ list (APPEND registries
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${version}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${version}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath])
+ if (version VERSION_GREATER_EQUAL "3.5")
+ get_filename_component (arch "[HKEY_CURRENT_USER\\Software\\Python\\PythonCore\\${version};SysArchitecture]" NAME)
+ if (arch MATCHES "(${_${_PYTHON_PREFIX}_ARCH}|${_${_PYTHON_PREFIX}_ARCH2})bit")
+ list (APPEND registries
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${version}\\InstallPath])
+ endif()
+ else()
+ list (APPEND registries
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${version}\\InstallPath])
+ endif()
+ list (APPEND registries
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${version}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${version}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${version}\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath])
+ endforeach()
+ elseif (implementation STREQUAL "IronPython")
+ foreach (version IN LISTS _PGR_VERSION)
+ list (APPEND registries [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${version}\\InstallPath])
+ endforeach()
+ endif()
+ endforeach()
+
+ set (${_PYTHON_PGR_REGISTRY_PATHS} "${registries}" PARENT_SCOPE)
+endfunction()
+
+
+function (_PYTHON_GET_ABIFLAGS _PGABIFLAGS)
+ set (abiflags)
+ list (GET _${_PYTHON_PREFIX}_FIND_ABI 0 pydebug)
+ list (GET _${_PYTHON_PREFIX}_FIND_ABI 1 pymalloc)
+ list (GET _${_PYTHON_PREFIX}_FIND_ABI 2 unicode)
+
+ if (pymalloc STREQUAL "ANY" AND unicode STREQUAL "ANY")
+ set (abiflags "mu" "m" "u" "")
+ elseif (pymalloc STREQUAL "ANY" AND unicode STREQUAL "ON")
+ set (abiflags "mu" "u")
+ elseif (pymalloc STREQUAL "ANY" AND unicode STREQUAL "OFF")
+ set (abiflags "m" "")
+ elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "ANY")
+ set (abiflags "mu" "m")
+ elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "ON")
+ set (abiflags "mu")
+ elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "OFF")
+ set (abiflags "m")
+ elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "ANY")
+ set (abiflags "u" "")
+ elseif (pymalloc STREQUAL "OFF" AND unicode STREQUAL "ON")
+ set (abiflags "u")
+ endif()
+
+ if (pydebug STREQUAL "ON")
+ if (abiflags)
+ list (TRANSFORM abiflags PREPEND "d")
+ else()
+ set (abiflags "d")
+ endif()
+ elseif (pydebug STREQUAL "ANY")
+ if (abiflags)
+ set (flags "${abiflags}")
+ list (TRANSFORM flags PREPEND "d")
+ list (APPEND abiflags "${flags}")
+ else()
+ set (abiflags "" "d")
+ endif()
+ endif()
+
+ set (${_PGABIFLAGS} "${abiflags}" PARENT_SCOPE)
+endfunction()
+
+function (_PYTHON_GET_PATH_SUFFIXES _PYTHON_PGPS_PATH_SUFFIXES)
+ cmake_parse_arguments (PARSE_ARGV 1 _PGPS "INTERPRETER;COMPILER;LIBRARY;INCLUDE" "" "IMPLEMENTATIONS;VERSION")
+
+ if (NOT _PGPS_IMPLEMENTATIONS)
+ set (_PGPS_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS})
+ endif()
+
+ if (DEFINED _${_PYTHON_PREFIX}_ABIFLAGS)
+ set (abi "${_${_PYTHON_PREFIX}_ABIFLAGS}")
+ else()
+ set (abi "mu" "m" "u" "")
+ endif()
+
+ set (path_suffixes)
+
+ foreach (implementation IN LISTS _PGPS_IMPLEMENTATIONS)
+ if (implementation STREQUAL "CPython")
+ if (_PGPS_INTERPRETER)
+ list (APPEND path_suffixes bin Scripts)
+ else()
+ foreach (version IN LISTS _PGPS_VERSION)
+ if (_PGPS_LIBRARY)
+ if (CMAKE_LIBRARY_ARCHITECTURE)
+ list (APPEND path_suffixes lib/${CMAKE_LIBRARY_ARCHITECTURE})
+ endif()
+ list (APPEND path_suffixes lib libs)
+
+ if (CMAKE_LIBRARY_ARCHITECTURE)
+ set (suffixes "${abi}")
+ if (suffixes)
+ list (TRANSFORM suffixes PREPEND "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}")
+ list (TRANSFORM suffixes APPEND "-${CMAKE_LIBRARY_ARCHITECTURE}")
+ else()
+ set (suffixes "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}-${CMAKE_LIBRARY_ARCHITECTURE}")
+ endif()
+ list (APPEND path_suffixes ${suffixes})
+ endif()
+ set (suffixes "${abi}")
+ if (suffixes)
+ list (TRANSFORM suffixes PREPEND "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}")
+ else()
+ set (suffixes "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}")
+ endif()
+ list (APPEND path_suffixes ${suffixes})
+ elseif (_PGPS_INCLUDE)
+ set (suffixes "${abi}")
+ if (suffixes)
+ list (TRANSFORM suffixes PREPEND "include/python${_PGPS_VERSION}")
+ else()
+ set (suffixes "include/python${_PGPS_VERSION}")
+ endif()
+ list (APPEND path_suffixes ${suffixes} include)
+ endif()
+ endforeach()
+ endif()
+ elseif (implementation STREQUAL "IronPython")
+ if (_PGPS_INTERPRETER OR _PGPS_COMPILER)
+ foreach (version IN LISTS _PGPS_VERSION)
+ list (APPEND path_suffixes "share/ironpython${version}")
+ endforeach()
+ list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES})
+ endif()
+ elseif (implementation STREQUAL "PyPy")
+ if (_PGPS_INTERPRETER)
+ list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_PYPY_EXECUTABLE_PATH_SUFFIXES})
+ elseif (_PGPS_LIBRARY)
+ list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_PYPY_LIBRARY_PATH_SUFFIXES})
+ elseif (_PGPS_INCLUDE)
+ list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES})
+ endif()
+ endif()
+ endforeach()
+ list (REMOVE_DUPLICATES path_suffixes)
+
+ set (${_PYTHON_PGPS_PATH_SUFFIXES} ${path_suffixes} PARENT_SCOPE)
+endfunction()
+
+function (_PYTHON_GET_NAMES _PYTHON_PGN_NAMES)
+ cmake_parse_arguments (PARSE_ARGV 1 _PGN "POSIX;INTERPRETER;COMPILER;CONFIG;LIBRARY;WIN32;DEBUG" "" "IMPLEMENTATIONS;VERSION")
+
+ if (NOT _PGN_IMPLEMENTATIONS)
+ set (_PGN_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS})
+ endif()
+
+ set (names)
+
+ foreach (implementation IN LISTS _PGN_IMPLEMENTATIONS)
+ if (implementation STREQUAL "CPython")
+ if (_PGN_INTERPRETER AND _${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES STREQUAL "FIRST")
+ list (APPEND names python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} python)
+ endif()
+ foreach (version IN LISTS _PGN_VERSION)
+ if (_PGN_WIN32)
+ string (REPLACE "." "" version_no_dots ${version})
+
+ set (name python${version_no_dots})
+ if (_PGN_DEBUG)
+ string (APPEND name "_d")
+ endif()
+
+ list (APPEND names "${name}")
+ endif()
+
+ if (_PGN_POSIX)
+ if (DEFINED _${_PYTHON_PREFIX}_ABIFLAGS)
+ set (abi "${_${_PYTHON_PREFIX}_ABIFLAGS}")
+ else()
+ if (_PGN_INTERPRETER OR _PGN_CONFIG)
+ set (abi "")
+ else()
+ set (abi "mu" "m" "u" "")
+ endif()
+ endif()
+
+ if (abi)
+ if (_PGN_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)
+ set (abinames "${abi}")
+ list (TRANSFORM abinames PREPEND "${CMAKE_LIBRARY_ARCHITECTURE}-python${version}")
+ list (TRANSFORM abinames APPEND "-config")
+ list (APPEND names ${abinames})
+ endif()
+ set (abinames "${abi}")
+ list (TRANSFORM abinames PREPEND "python${version}")
+ if (_PGN_CONFIG)
+ list (TRANSFORM abinames APPEND "-config")
+ endif()
+ list (APPEND names ${abinames})
+ else()
+ unset (abinames)
+ if (_PGN_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)
+ set (abinames "${CMAKE_LIBRARY_ARCHITECTURE}-python${version}")
+ endif()
+ list (APPEND abinames "python${version}")
+ if (_PGN_CONFIG)
+ list (TRANSFORM abinames APPEND "-config")
+ endif()
+ list (APPEND names ${abinames})
+ endif()
+ endif()
+ endforeach()
+ if (_PGN_INTERPRETER AND _${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES STREQUAL "LAST")
+ list (APPEND names python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} python)
+ endif()
+ elseif (implementation STREQUAL "IronPython")
+ if (_PGN_INTERPRETER)
+ if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ # Do not use wrapper script on Linux because it is buggy: -c interpreter option cannot be used
+ foreach (version IN LISTS _PGN_VERSION)
+ list (APPEND names "ipy${version}")
+ endforeach()
+ endif()
+ list (APPEND names ${_${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES})
+ elseif (_PGN_COMPILER)
+ list (APPEND names ${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES})
+ endif()
+ elseif (implementation STREQUAL "PyPy")
+ if (_PGN_INTERPRETER)
+ list (APPEND names ${_${_PYTHON_PREFIX}_PYPY_NAMES})
+ elseif (_PGN_LIBRARY)
+ if (_PGN_WIN32)
+ foreach (version IN LISTS _PGN_VERSION)
+ string (REPLACE "." "" version_no_dots ${version})
+
+ set (name "python${version_no_dots}")
+ if (_PGN_DEBUG)
+ string (APPEND name "_d")
+ endif()
+ list (APPEND names "${name}")
+ endforeach()
+ endif()
+ list (APPEND names ${_${_PYTHON_PREFIX}_PYPY_LIB_NAMES})
+ endif()
+ endif()
+ endforeach()
+
+ set (${_PYTHON_PGN_NAMES} ${names} PARENT_SCOPE)
+endfunction()
+
+function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME)
+ unset (${_PYTHON_PGCV_VALUE} PARENT_SCOPE)
+
+ if (NOT NAME MATCHES "^(PREFIX|ABIFLAGS|CONFIGDIR|INCLUDES|LIBS|SOABI)$")
+ return()
+ endif()
+
+ if (_${_PYTHON_PREFIX}_CONFIG)
+ if (NAME STREQUAL "SOABI")
+ set (config_flag "--extension-suffix")
+ else()
+ set (config_flag "--${NAME}")
+ endif()
+ string (TOLOWER "${config_flag}" config_flag)
+ execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" ${config_flag}
+ RESULT_VARIABLE _result
+ OUTPUT_VARIABLE _values
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_result)
+ unset (_values)
+ else()
+ if (NAME STREQUAL "INCLUDES")
+ # do some clean-up
+ string (REGEX MATCHALL "(-I|-iwithsysroot)[ ]*[^ ]+" _values "${_values}")
+ string (REGEX REPLACE "(-I|-iwithsysroot)[ ]*" "" _values "${_values}")
+ list (REMOVE_DUPLICATES _values)
+ elseif (NAME STREQUAL "SOABI")
+ # clean-up: remove prefix character and suffix
+ if (_values MATCHES "^(\\.${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.so|\\.pyd)$")
+ set(_values "")
+ else()
+ string (REGEX REPLACE "^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.(so|pyd))$" "\\1" _values "${_values}")
+ endif()
+ endif()
+ endif()
+ endif()
+
+ if (_${_PYTHON_PREFIX}_EXECUTABLE AND NOT CMAKE_CROSSCOMPILING)
+ if (NAME STREQUAL "PREFIX")
+ execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.PREFIX,sysconfig.EXEC_PREFIX,sysconfig.BASE_EXEC_PREFIX]))\nexcept Exception:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_config_var('base') or '', sysconfig.get_config_var('installed_base') or '']))"
+ RESULT_VARIABLE _result
+ OUTPUT_VARIABLE _values
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_result)
+ unset (_values)
+ else()
+ list (REMOVE_DUPLICATES _values)
+ endif()
+ elseif (NAME STREQUAL "INCLUDES")
+ if (WIN32)
+ set (_scheme "nt")
+ else()
+ set (_scheme "posix_prefix")
+ endif()
+ execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_python_inc(plat_specific=True),sysconfig.get_python_inc(plat_specific=False)]))\nexcept Exception:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_path('platinclude'),sysconfig.get_path('platinclude','${_scheme}'),sysconfig.get_path('include'),sysconfig.get_path('include','${_scheme}')]))"
+ RESULT_VARIABLE _result
+ OUTPUT_VARIABLE _values
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_result)
+ unset (_values)
+ else()
+ list (REMOVE_DUPLICATES _values)
+ endif()
+ elseif (NAME STREQUAL "SOABI")
+ execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('EXT_SUFFIX') or '',sysconfig.get_config_var('SO') or '']))\nexcept Exception:\n import sysconfig;sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('EXT_SUFFIX') or '',sysconfig.get_config_var('SO') or '']))"
+ RESULT_VARIABLE _result
+ OUTPUT_VARIABLE _soabi
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_result)
+ unset (_values)
+ else()
+ foreach (_item IN LISTS _soabi)
+ if (_item)
+ set (_values "${_item}")
+ break()
+ endif()
+ endforeach()
+ if (_values)
+ # clean-up: remove prefix character and suffix
+ if (_values MATCHES "^(\\.${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.so|\\.pyd)$")
+ set(_values "")
+ else()
+ string (REGEX REPLACE "^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.(so|pyd))$" "\\1" _values "${_values}")
+ endif()
+ endif()
+ endif()
+ else()
+ set (config_flag "${NAME}")
+ if (NAME STREQUAL "CONFIGDIR")
+ set (config_flag "LIBPL")
+ endif()
+ execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(sysconfig.get_config_var('${config_flag}'))\nexcept Exception:\n import sysconfig\n sys.stdout.write(sysconfig.get_config_var('${config_flag}'))"
+ RESULT_VARIABLE _result
+ OUTPUT_VARIABLE _values
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_result)
+ unset (_values)
+ endif()
+ endif()
+ endif()
+
+ if (NAME STREQUAL "ABIFLAGS" OR NAME STREQUAL "SOABI")
+ set (${_PYTHON_PGCV_VALUE} "${_values}" PARENT_SCOPE)
+ return()
+ endif()
+
+ if (NOT _values OR _values STREQUAL "None")
+ return()
+ endif()
+
+ if (NAME STREQUAL "LIBS")
+ # do some clean-up
+ string (REGEX MATCHALL "-(l|framework)[ ]*[^ ]+" _values "${_values}")
+ # remove elements relative to python library itself
+ list (FILTER _values EXCLUDE REGEX "-lpython")
+ list (REMOVE_DUPLICATES _values)
+ endif()
+
+ if (WIN32 AND NAME MATCHES "^(PREFIX|CONFIGDIR|INCLUDES)$")
+ file (TO_CMAKE_PATH "${_values}" _values)
+ endif()
+
+ set (${_PYTHON_PGCV_VALUE} "${_values}" PARENT_SCOPE)
+endfunction()
+
+function (_PYTHON_GET_VERSION)
+ cmake_parse_arguments (PARSE_ARGV 0 _PGV "LIBRARY;INCLUDE" "PREFIX" "")
+
+ unset (${_PGV_PREFIX}VERSION PARENT_SCOPE)
+ unset (${_PGV_PREFIX}VERSION_MAJOR PARENT_SCOPE)
+ unset (${_PGV_PREFIX}VERSION_MINOR PARENT_SCOPE)
+ unset (${_PGV_PREFIX}VERSION_PATCH PARENT_SCOPE)
+ unset (${_PGV_PREFIX}ABI PARENT_SCOPE)
+
+ if (_PGV_LIBRARY)
+ # retrieve version and abi from library name
+ if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ get_filename_component (library_name "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" NAME)
+ # extract version from library name
+ if (library_name MATCHES "python([23])([0-9]+)")
+ set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ set (${_PGV_PREFIX}VERSION_MINOR "${CMAKE_MATCH_2}" PARENT_SCOPE)
+ set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}" PARENT_SCOPE)
+ set (${_PGV_PREFIX}ABI "" PARENT_SCOPE)
+ elseif (library_name MATCHES "python([23])\\.([0-9]+)([dmu]*)")
+ set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ set (${_PGV_PREFIX}VERSION_MINOR "${CMAKE_MATCH_2}" PARENT_SCOPE)
+ set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}" PARENT_SCOPE)
+ set (${_PGV_PREFIX}ABI "${CMAKE_MATCH_3}" PARENT_SCOPE)
+ elseif (library_name MATCHES "pypy(3)?-c")
+ set (version "${CMAKE_MATCH_1}")
+ if (version EQUAL "3")
+ set (${_PGV_PREFIX}VERSION_MAJOR "3" PARENT_SCOPE)
+ set (${_PGV_PREFIX}VERSION "3" PARENT_SCOPE)
+ else()
+ set (${_PGV_PREFIX}VERSION_MAJOR "2" PARENT_SCOPE)
+ set (${_PGV_PREFIX}VERSION "2" PARENT_SCOPE)
+ endif()
+ set (${_PGV_PREFIX}ABI "" PARENT_SCOPE)
+ endif()
+ endif()
+ else()
+ if (_${_PYTHON_PREFIX}_INCLUDE_DIR)
+ # retrieve version from header file
+ file (STRINGS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}/patchlevel.h" version
+ REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"")
+ string (REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"]+)\".*" "\\1"
+ version "${version}")
+ string (REGEX MATCHALL "[0-9]+" versions "${version}")
+ list (GET versions 0 version_major)
+ list (GET versions 1 version_minor)
+ list (GET versions 2 version_patch)
+
+ set (${_PGV_PREFIX}VERSION "${version_major}.${version_minor}.${version_patch}" PARENT_SCOPE)
+ set (${_PGV_PREFIX}VERSION_MAJOR ${version_major} PARENT_SCOPE)
+ set (${_PGV_PREFIX}VERSION_MINOR ${version_minor} PARENT_SCOPE)
+ set (${_PGV_PREFIX}VERSION_PATCH ${version_patch} PARENT_SCOPE)
+
+ # compute ABI flags
+ if (version_major VERSION_GREATER "2")
+ file (STRINGS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}/pyconfig.h" config REGEX "(Py_DEBUG|WITH_PYMALLOC|Py_UNICODE_SIZE|MS_WIN32)")
+ set (abi)
+ if (config MATCHES "#[ ]*define[ ]+MS_WIN32")
+ # ABI not used on Windows
+ set (abi "")
+ else()
+ if (NOT config)
+ # pyconfig.h can be a wrapper to a platform specific pyconfig.h
+ # In this case, try to identify ABI from include directory
+ if (_${_PYTHON_PREFIX}_INCLUDE_DIR MATCHES "python${version_major}\\.${version_minor}+([dmu]*)")
+ set (abi "${CMAKE_MATCH_1}")
+ else()
+ set (abi "")
+ endif()
+ else()
+ if (config MATCHES "#[ ]*define[ ]+Py_DEBUG[ ]+1")
+ string (APPEND abi "d")
+ endif()
+ if (config MATCHES "#[ ]*define[ ]+WITH_PYMALLOC[ ]+1")
+ string (APPEND abi "m")
+ endif()
+ if (config MATCHES "#[ ]*define[ ]+Py_UNICODE_SIZE[ ]+4")
+ string (APPEND abi "u")
+ endif()
+ endif()
+ set (${_PGV_PREFIX}ABI "${abi}" PARENT_SCOPE)
+ endif()
+ else()
+ # ABI not supported
+ set (${_PGV_PREFIX}ABI "" PARENT_SCOPE)
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function (_PYTHON_GET_LAUNCHER _PYTHON_PGL_NAME)
+ cmake_parse_arguments (PARSE_ARGV 1 _PGL "INTERPRETER;COMPILER" "" "")
+
+ unset ({_PYTHON_PGL_NAME} PARENT_SCOPE)
+
+ if ((_PGL_INTERPRETER AND NOT _${_PYTHON_PREFIX}_EXECUTABLE)
+ OR (_PGL_COMPILER AND NOT _${_PYTHON_PREFIX}_COMPILER))
+ return()
+ endif()
+
+ if ("IronPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS
+ AND NOT SYSTEM_NAME MATCHES "Windows|Linux")
+ if (_PGL_INTERPRETER)
+ get_filename_component (name "${_${_PYTHON_PREFIX}_EXECUTABLE}" NAME)
+ get_filename_component (ext "${_${_PYTHON_PREFIX}_EXECUTABLE}" LAST_EXT)
+ if (name IN_LIST _${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES
+ AND ext STREQUAL ".exe")
+ set (${_PYTHON_PGL_NAME} "${${_PYTHON_PREFIX}_DOTNET_LAUNCHER}" PARENT_SCOPE)
+ endif()
+ else()
+ get_filename_component (name "${_${_PYTHON_PREFIX}_COMPILER}" NAME)
+ get_filename_component (ext "${_${_PYTHON_PREFIX}_COMPILER}" LAST_EXT)
+ if (name IN_LIST _${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES
+ AND ext STREQUAL ".exe")
+ set (${_PYTHON_PGL_NAME} "${${_PYTHON_PREFIX}_DOTNET_LAUNCHER}" PARENT_SCOPE)
+ endif()
+ endif()
+ endif()
+endfunction()
+
+
+function (_PYTHON_VALIDATE_INTERPRETER)
+ if (NOT _${_PYTHON_PREFIX}_EXECUTABLE)
+ return()
+ 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
+ set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot find the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+ return()
+ endif()
+
+ _python_get_launcher (launcher INTERPRETER)
+
+ # validate ABI compatibility
+ if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI)
+ execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys; sys.stdout.write(sys.abiflags)"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE abi
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (result)
+ # assume ABI is not supported
+ set (abi "")
+ endif()
+ if (NOT abi IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
+ # incompatible ABI
+ set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong ABI for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+ return()
+ endif()
+ endif()
+
+ 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 (_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}")
+
+ 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()
+ # 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")
+ return()
+ endif()
+ endif()
+ 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
+ execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys; sys.stdout.write(str(sys.version_info[0]))"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE version
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (result OR NOT version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+ # interpreter not usable or has wrong major version
+ if (result)
+ set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+ else()
+ set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong major version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+ endif()
+ set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+ return()
+ endif()
+ endif()
+ endif()
+
+ if (CMAKE_SIZEOF_VOID_P AND ("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+ OR "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+ AND NOT CMAKE_CROSSCOMPILING)
+ # In this case, interpreter must have same architecture as environment
+ execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys, struct; sys.stdout.write(str(struct.calcsize(\"P\")))"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE size
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (result OR NOT size EQUAL CMAKE_SIZEOF_VOID_P)
+ # interpreter not usable or has wrong architecture
+ if (result)
+ set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+ else()
+ set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong architecture for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+ endif()
+ set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+ return()
+ endif()
+ endif()
+endfunction()
+
+
+function (_PYTHON_VALIDATE_COMPILER)
+ if (NOT _${_PYTHON_PREFIX}_COMPILER)
+ return()
+ 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
+ set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot find the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
+ return()
+ endif()
+
+ _python_get_launcher (launcher COMPILER)
+
+ # retrieve python environment version from compiler
+ set (working_dir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir")
+ 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"
+ WORKING_DIRECTORY "${working_dir}"
+ OUTPUT_QUIET
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ get_filename_component (ir_dir "${_${_PYTHON_PREFIX}_COMPILER}" DIRECTORY)
+ execute_process (COMMAND "${CMAKE_COMMAND}" -E env "MONO_PATH=${ir_dir}"
+ ${${_PYTHON_PREFIX}_DOTNET_LAUNCHER} "${working_dir}/version.exe"
+ WORKING_DIRECTORY "${working_dir}"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE version
+ ERROR_QUIET)
+ file (REMOVE_RECURSE "${working_dir}")
+ if (result)
+ # 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")
+ 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()
+
+
+function (_PYTHON_VALIDATE_LIBRARY)
+ if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+ return()
+ 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
+ set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
+ if (WIN32)
+ set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_DEBUG PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_DEBUG-NOTFOUND")
+ endif()
+ set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+ return()
+ endif()
+
+ # retrieve version and abi from library name
+ _python_get_version (LIBRARY PREFIX lib_)
+
+ if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT lib_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
+ # incompatible ABI
+ 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 (_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)
+ # library has wrong major version
+ set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong major 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()
+ endif()
+
+ if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ if (WIN32)
+ set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_DEBUG PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_DEBUG-NOTFOUND")
+ endif()
+ unset (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE CACHE)
+ unset (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG CACHE)
+ set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+ endif()
+endfunction()
+
+
+function (_PYTHON_VALIDATE_INCLUDE_DIR)
+ if (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)
+ return()
+ 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
+ set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE)
+ set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+ return()
+ endif()
+
+ # retrieve version from header file
+ _python_get_version (INCLUDE PREFIX inc_)
+
+ if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT inc_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
+ # incompatible ABI
+ 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 (_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)
+ # include dir has wrong major version
+ set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong major 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()
+ endif()
+endfunction()
+
+
+function (_PYTHON_FIND_RUNTIME_LIBRARY _PYTHON_LIB)
+ string (REPLACE "_RUNTIME" "" _PYTHON_LIB "${_PYTHON_LIB}")
+ # look at runtime part on systems supporting it
+ if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR
+ (CMAKE_SYSTEM_NAME MATCHES "MSYS|CYGWIN"
+ AND ${_PYTHON_LIB} MATCHES "${CMAKE_IMPORT_LIBRARY_SUFFIX}$"))
+ set (CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX})
+ # MSYS has a special syntax for runtime libraries
+ if (CMAKE_SYSTEM_NAME MATCHES "MSYS")
+ list (APPEND CMAKE_FIND_LIBRARY_PREFIXES "msys-")
+ endif()
+ find_library (${ARGV})
+ endif()
+endfunction()
+
+
+function (_PYTHON_SET_LIBRARY_DIRS _PYTHON_SLD_RESULT)
+ unset (_PYTHON_DIRS)
+ set (_PYTHON_LIBS ${ARGN})
+ foreach (_PYTHON_LIB IN LISTS _PYTHON_LIBS)
+ if (${_PYTHON_LIB})
+ get_filename_component (_PYTHON_DIR "${${_PYTHON_LIB}}" DIRECTORY)
+ list (APPEND _PYTHON_DIRS "${_PYTHON_DIR}")
+ endif()
+ endforeach()
+ list (REMOVE_DUPLICATES _PYTHON_DIRS)
+ set (${_PYTHON_SLD_RESULT} ${_PYTHON_DIRS} PARENT_SCOPE)
+endfunction()
+
+
+function (_PYTHON_SET_DEVELOPMENT_MODULE_FOUND module)
+ if ("Development.${module}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+ string(TOUPPER "${module}" id)
+ set (module_found TRUE)
+
+ if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS
+ AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ set (module_found FALSE)
+ endif()
+ if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS
+ AND NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)
+ set (module_found FALSE)
+ endif()
+
+ set (${_PYTHON_PREFIX}_Development.${module}_FOUND ${module_found} PARENT_SCOPE)
+ endif()
+endfunction()
+
+
+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()
+ 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()
+
+
+# handle components
+if (NOT ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+ set (${_PYTHON_PREFIX}_FIND_COMPONENTS Interpreter)
+ set (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter TRUE)
+endif()
+if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+ list (APPEND ${_PYTHON_PREFIX}_FIND_COMPONENTS "Interpreter" "Development.Module")
+endif()
+if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+ list (APPEND ${_PYTHON_PREFIX}_FIND_COMPONENTS "Development.Module" "Development.Embed")
+endif()
+list (REMOVE_DUPLICATES ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development Development.Module Development.Embed NumPy)
+ set (${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_FOUND FALSE)
+endforeach()
+if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development)
+ set (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Module TRUE)
+ set (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Embed TRUE)
+endif()
+
+unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS)
+unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS)
+if ("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+ if (CMAKE_SYSTEM_NAME MATCHES "^(Windows.*|CYGWIN|MSYS)$")
+ list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS "LIBRARY")
+ endif()
+ list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS "INCLUDE_DIR")
+endif()
+if ("Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+ list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS "LIBRARY" "INCLUDE_DIR")
+endif()
+set (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS ${_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS} ${_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS})
+list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+
+# Set versions to search
+## default: search any version
+set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSIONS})
+unset (_${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
+
+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()
+
+# Set ABIs to search
+## default: search any ABI
+if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR VERSION_LESS "3")
+ # ABI not supported
+ unset (_${_PYTHON_PREFIX}_FIND_ABI)
+ set (_${_PYTHON_PREFIX}_ABIFLAGS "")
+else()
+ unset (_${_PYTHON_PREFIX}_FIND_ABI)
+ unset (_${_PYTHON_PREFIX}_ABIFLAGS)
+ if (DEFINED ${_PYTHON_PREFIX}_FIND_ABI)
+ # normalization
+ string (TOUPPER "${${_PYTHON_PREFIX}_FIND_ABI}" _${_PYTHON_PREFIX}_FIND_ABI)
+ list (TRANSFORM _${_PYTHON_PREFIX}_FIND_ABI REPLACE "^(TRUE|Y(ES)?|1)$" "ON")
+ list (TRANSFORM _${_PYTHON_PREFIX}_FIND_ABI REPLACE "^(FALSE|N(O)?|0)$" "OFF")
+ if (NOT _${_PYTHON_PREFIX}_FIND_ABI MATCHES "^(ON|OFF|ANY);(ON|OFF|ANY);(ON|OFF|ANY)$")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_ABI}: invalid value for '${_PYTHON_PREFIX}_FIND_ABI'. Ignore it")
+ unset (_${_PYTHON_PREFIX}_FIND_ABI)
+ endif()
+ _python_get_abiflags (_${_PYTHON_PREFIX}_ABIFLAGS)
+ endif()
+endif()
+unset (${_PYTHON_PREFIX}_SOABI)
+
+# Define lookup strategy
+cmake_policy (GET CMP0094 _${_PYTHON_PREFIX}_LOOKUP_POLICY)
+if (_${_PYTHON_PREFIX}_LOOKUP_POLICY STREQUAL "NEW")
+ set (_${_PYTHON_PREFIX}_FIND_STRATEGY "LOCATION")
+else()
+ set (_${_PYTHON_PREFIX}_FIND_STRATEGY "VERSION")
+endif()
+if (DEFINED ${_PYTHON_PREFIX}_FIND_STRATEGY)
+ if (NOT ${_PYTHON_PREFIX}_FIND_STRATEGY MATCHES "^(VERSION|LOCATION)$")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_STRATEGY}: invalid value for '${_PYTHON_PREFIX}_FIND_STRATEGY'. 'VERSION' or 'LOCATION' expected.")
+ set (_${_PYTHON_PREFIX}_FIND_STRATEGY "VERSION")
+ else()
+ set (_${_PYTHON_PREFIX}_FIND_STRATEGY "${${_PYTHON_PREFIX}_FIND_STRATEGY}")
+ endif()
+endif()
+
+# Python and Anaconda distributions: define which architectures can be used
+if (CMAKE_SIZEOF_VOID_P)
+ # In this case, search only for 64bit or 32bit
+ math (EXPR _${_PYTHON_PREFIX}_ARCH "${CMAKE_SIZEOF_VOID_P} * 8")
+ set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH})
+else()
+ # architecture unknown, search for both 64bit and 32bit
+ set (_${_PYTHON_PREFIX}_ARCH 64)
+ set (_${_PYTHON_PREFIX}_ARCH2 32)
+endif()
+
+# IronPython support
+unset (_${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES)
+unset (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES)
+unset (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS)
+if (CMAKE_SIZEOF_VOID_P)
+ if (_${_PYTHON_PREFIX}_ARCH EQUAL "32")
+ set (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS "/platform:x86")
+ else()
+ set (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS "/platform:x64")
+ endif()
+endif()
+if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ # Do not use wrapper script on Linux because it is buggy: -c interpreter option cannot be used
+ list (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES "ipy${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}" "ipy64" "ipy32" "ipy")
+ list (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES "ipyc")
+endif()
+list (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES "ipy.exe")
+list (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES "ipyc.exe")
+set (_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES net45 net40 bin)
+
+# PyPy support
+if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL "3")
+ set (_${_PYTHON_PREFIX}_PYPY_NAMES pypy3)
+ set (_${_PYTHON_PREFIX}_PYPY_LIB_NAMES pypy3-c)
+ if (WIN32)
+ # special name for runtime part
+ list (APPEND _${_PYTHON_PREFIX}_PYPY_LIB_NAMES libpypy3-c)
+ endif()
+ set (_${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES lib/pypy3)
+else()
+ set (_${_PYTHON_PREFIX}_PYPY_NAMES pypy)
+ set (_${_PYTHON_PREFIX}_PYPY_LIB_NAMES pypy-c)
+ if (WIN32)
+ # special name for runtime part
+ list (APPEND _${_PYTHON_PREFIX}_PYPY_LIB_NAMES libpypy-c)
+ endif()
+ set (_${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES lib/pypy)
+endif()
+set (_${_PYTHON_PREFIX}_PYPY_EXECUTABLE_PATH_SUFFIXES bin)
+set (_${_PYTHON_PREFIX}_PYPY_LIBRARY_PATH_SUFFIXES lib libs bin)
+list (APPEND _${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES include)
+
+# Python Implementations handling
+unset (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+if (DEFINED ${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+ foreach (_${_PYTHON_PREFIX}_IMPLEMENTATION IN LISTS ${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+ if (NOT _${_PYTHON_PREFIX}_IMPLEMENTATION MATCHES "^(CPython|IronPython|PyPy)$")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${_${_PYTHON_PREFIX}_IMPLEMENTATION}: invalid value for '${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS'. 'CPython', 'IronPython' or 'PyPy' expected. Value will be ignored.")
+ else()
+ list (APPEND _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_IMPLEMENTATION})
+ endif()
+ endforeach()
+else()
+ if (WIN32)
+ set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS CPython IronPython)
+ else()
+ set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS CPython)
+ endif()
+endif()
+
+# compute list of names for header file
+unset (_${_PYTHON_PREFIX}_INCLUDE_NAMES)
+foreach (_${_PYTHON_PREFIX}_IMPLEMENTATION IN LISTS _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+ if (_${_PYTHON_PREFIX}_IMPLEMENTATION STREQUAL "CPython")
+ list (APPEND _${_PYTHON_PREFIX}_INCLUDE_NAMES "Python.h")
+ elseif (_${_PYTHON_PREFIX}_IMPLEMENTATION STREQUAL "PyPy")
+ list (APPEND _${_PYTHON_PREFIX}_INCLUDE_NAMES "PyPy.h")
+ endif()
+endforeach()
+
+
+# Apple frameworks handling
+_python_find_frameworks ()
+
+set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK "FIRST")
+
+if (DEFINED ${_PYTHON_PREFIX}_FIND_FRAMEWORK)
+ if (NOT ${_PYTHON_PREFIX}_FIND_FRAMEWORK MATCHES "^(FIRST|LAST|NEVER)$")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_FRAMEWORK}: invalid value for '${_PYTHON_PREFIX}_FIND_FRAMEWORK'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.")
+ else()
+ set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${${_PYTHON_PREFIX}_FIND_FRAMEWORK})
+ endif()
+elseif (DEFINED CMAKE_FIND_FRAMEWORK)
+ if (CMAKE_FIND_FRAMEWORK STREQUAL "ONLY")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: CMAKE_FIND_FRAMEWORK: 'ONLY' value is not supported. 'FIRST' will be used instead.")
+ elseif (NOT CMAKE_FIND_FRAMEWORK MATCHES "^(FIRST|LAST|NEVER)$")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${CMAKE_FIND_FRAMEWORK}: invalid value for 'CMAKE_FIND_FRAMEWORK'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.")
+ else()
+ set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK})
+ endif()
+endif()
+
+# Save CMAKE_FIND_APPBUNDLE
+if (DEFINED CMAKE_FIND_APPBUNDLE)
+ set (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE ${CMAKE_FIND_APPBUNDLE})
+else()
+ unset (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE)
+endif()
+# To avoid app bundle lookup
+set (CMAKE_FIND_APPBUNDLE "NEVER")
+
+# Save CMAKE_FIND_FRAMEWORK
+if (DEFINED CMAKE_FIND_FRAMEWORK)
+ set (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK})
+else()
+ unset (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK)
+endif()
+# To avoid framework lookup
+set (CMAKE_FIND_FRAMEWORK "NEVER")
+
+# Windows Registry handling
+if (DEFINED ${_PYTHON_PREFIX}_FIND_REGISTRY)
+ if (NOT ${_PYTHON_PREFIX}_FIND_REGISTRY MATCHES "^(FIRST|LAST|NEVER)$")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_REGISTRY}: invalid value for '${_PYTHON_PREFIX}_FIND_REGISTRY'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.")
+ set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST")
+ else()
+ set (_${_PYTHON_PREFIX}_FIND_REGISTRY ${${_PYTHON_PREFIX}_FIND_REGISTRY})
+ endif()
+else()
+ set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST")
+endif()
+
+# virtual environments recognition
+if (DEFINED ENV{VIRTUAL_ENV} OR DEFINED ENV{CONDA_PREFIX})
+ if (DEFINED ${_PYTHON_PREFIX}_FIND_VIRTUALENV)
+ if (NOT ${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY|STANDARD)$")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_VIRTUALENV}: invalid value for '${_PYTHON_PREFIX}_FIND_VIRTUALENV'. 'FIRST', 'ONLY' or 'STANDARD' expected. 'FIRST' will be used instead.")
+ set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV "FIRST")
+ else()
+ set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV ${${_PYTHON_PREFIX}_FIND_VIRTUALENV})
+ endif()
+ else()
+ set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV FIRST)
+ endif()
+else()
+ set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STANDARD)
+endif()
+
+
+# Python naming handling
+if (DEFINED ${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES)
+ if (NOT ${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES MATCHES "^(FIRST|LAST|NEVER)$")
+ message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES}: invalid value for '${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES'. 'FIRST', 'LAST' or 'NEVER' expected. 'LAST' will be used instead.")
+ set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES LAST)
+ else()
+ set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES ${${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES})
+ endif()
+else()
+ set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES LAST)
+endif()
+
+
+# Compute search signature
+# This signature will be used to check validity of cached variables on new search
+set (_${_PYTHON_PREFIX}_SIGNATURE "${${_PYTHON_PREFIX}_ROOT_DIR}:${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS}:${_${_PYTHON_PREFIX}_FIND_STRATEGY}:${${_PYTHON_PREFIX}_FIND_VIRTUALENV}${_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES}")
+if (NOT WIN32)
+ string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${${_PYTHON_PREFIX}_USE_STATIC_LIBS}:")
+endif()
+if (CMAKE_HOST_APPLE)
+ string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${_${_PYTHON_PREFIX}_FIND_FRAMEWORK}")
+endif()
+if (CMAKE_HOST_WIN32)
+ string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${_${_PYTHON_PREFIX}_FIND_REGISTRY}")
+endif()
+
+function (_PYTHON_CHECK_DEVELOPMENT_SIGNATURE module)
+ if ("Development.${module}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+ string (TOUPPER "${module}" id)
+ set (signature "${_${_PYTHON_PREFIX}_SIGNATURE}:")
+ if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+ list (APPEND signature "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}:")
+ endif()
+ if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+ list (APPEND signature "${_${_PYTHON_PREFIX}_INCLUDE_DIR}:")
+ endif()
+ string (MD5 signature "${signature}")
+ if (signature STREQUAL _${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE)
+ if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+ 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)
+ 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)
+ unset (_${_PYTHON_PREFIX}_LIBRARY_RELEASE CACHE)
+ unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG CACHE)
+ endif()
+ if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+ unset (_${_PYTHON_PREFIX}_INCLUDE_DIR CACHE)
+ endif()
+ endif()
+ if (("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS
+ AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ OR ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS
+ AND NOT _${_PYTHON_PREFIX}_INCLUDE_DIR))
+ unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+ unset (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE CACHE)
+ endif()
+ endif()
+endfunction()
+
+function (_PYTHON_COMPUTE_DEVELOPMENT_SIGNATURE module)
+ string (TOUPPER "${module}" id)
+ if (${_PYTHON_PREFIX}_Development.${module}_FOUND)
+ set (signature "${_${_PYTHON_PREFIX}_SIGNATURE}:")
+ if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+ list (APPEND signature "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}:")
+ endif()
+ if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+ list (APPEND signature "${_${_PYTHON_PREFIX}_INCLUDE_DIR}:")
+ endif()
+ string (MD5 signature "${signature}")
+ set (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE "${signature}" CACHE INTERNAL "")
+ else()
+ unset (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE CACHE)
+ endif()
+endfunction()
+
+
+unset (_${_PYTHON_PREFIX}_REQUIRED_VARS)
+unset (_${_PYTHON_PREFIX}_CACHED_VARS)
+unset (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE)
+unset (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE)
+unset (_${_PYTHON_PREFIX}_Development_REASON_FAILURE)
+unset (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE)
+
+
+# preamble
+## For IronPython on platforms other than Windows, search for the .Net interpreter
+if ("IronPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS
+ AND NOT WIN32)
+ find_program (${_PYTHON_PREFIX}_DOTNET_LAUNCHER
+ NAMES "mono")
+endif()
+
+
+# first step, search for the interpreter
+if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+ list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_EXECUTABLE
+ _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES)
+ if (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter)
+ list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_EXECUTABLE)
+ endif()
+
+ if (DEFINED ${_PYTHON_PREFIX}_EXECUTABLE
+ AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_EXECUTABLE}")
+ if (NOT ${_PYTHON_PREFIX}_EXECUTABLE STREQUAL _${_PYTHON_PREFIX}_EXECUTABLE)
+ # invalidate cache properties
+ unset (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES CACHE)
+ endif()
+ set (_${_PYTHON_PREFIX}_EXECUTABLE "${${_PYTHON_PREFIX}_EXECUTABLE}" CACHE INTERNAL "")
+ elseif (DEFINED _${_PYTHON_PREFIX}_EXECUTABLE)
+ # compute interpreter signature and check validity of definition
+ string (MD5 __${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_EXECUTABLE}")
+ if (__${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE)
+ # check version validity
+ if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
+ _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 (CHECK_EXISTS)
+ endif()
+ else()
+ unset (_${_PYTHON_PREFIX}_EXECUTABLE CACHE)
+ endif()
+ if (NOT _${_PYTHON_PREFIX}_EXECUTABLE)
+ unset (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE CACHE)
+ unset (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES CACHE)
+ endif()
+ endif()
+
+ if (NOT _${_PYTHON_PREFIX}_EXECUTABLE)
+ set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+
+ if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
+ # build all executable names
+ _python_get_names (_${_PYTHON_PREFIX}_NAMES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} POSIX INTERPRETER)
+ _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} INTERPRETER)
+
+ # Framework Paths
+ _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})
+ # 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 _${_PYTHON_PREFIX}_VALIDATE_OPTIONS VERSION ${${_PYTHON_PREFIX}_FIND_VERSION})
+ endif()
+
+ while (TRUE)
+ # Virtual environments handling
+ if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+
+ _python_validate_interpreter (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
+ break()
+ endif()
+ endif()
+
+ # Apple frameworks handling
+ if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ endif()
+ # Windows registry
+ if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ endif()
+
+ # try using HINTS
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ # try using standard paths
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+
+ # Apple frameworks handling
+ if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_DEFAULT_PATH)
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ endif()
+ # Windows registry
+ if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_DEFAULT_PATH)
+ _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ endif()
+
+ break()
+ 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)
+
+ _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})
+ _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})
+
+ # Virtual environments handling
+ if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
+ continue()
+ endif()
+ endif()
+
+ # Apple frameworks handling
+ if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ # Windows registry
+ if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+
+ # try using HINTS
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ # try using standard paths.
+ # NAMES_PER_DIR is not defined on purpose to have a chance to find
+ # expected version.
+ # For example, typical systems have 'python' for version 2.* and 'python3'
+ # for version 3.*. So looking for names per dir will find, potentially,
+ # systematically 'python' (i.e. version 2) even if version 3 is searched.
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
+ _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+
+ # Apple frameworks handling
+ if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_DEFAULT_PATH)
+ endif()
+
+ # Windows registry
+ if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES}
+ NAMES_PER_DIR
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_DEFAULT_PATH)
+ endif()
+
+ _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ endforeach()
+
+ if (NOT _${_PYTHON_PREFIX}_EXECUTABLE AND
+ NOT _${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
+ # No specific version found. Retry with generic names and standard paths.
+ # NAMES_PER_DIR is not defined on purpose to have a chance to find
+ # expected version.
+ # For example, typical systems have 'python' for version 2.* and 'python3'
+ # for version 3.*. So looking for names per dir will find, potentially,
+ # systematically 'python' (i.e. version 2) even if version 3 is searched.
+ _python_get_names (_${_PYTHON_PREFIX}_NAMES POSIX INTERPRETER)
+ find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES ${_${_PYTHON_PREFIX}_NAMES})
+ _python_validate_interpreter ()
+ endif()
+ endif()
+ endif()
+
+ set (${_PYTHON_PREFIX}_EXECUTABLE "${_${_PYTHON_PREFIX}_EXECUTABLE}")
+ _python_get_launcher (_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER INTERPRETER)
+
+ # retrieve exact version of executable found
+ if (_${_PYTHON_PREFIX}_EXECUTABLE)
+ execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))"
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE ${_PYTHON_PREFIX}_VERSION
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (NOT _${_PYTHON_PREFIX}_RESULT)
+ set (_${_PYTHON_PREFIX}_EXECUTABLE_USABLE TRUE)
+ else()
+ # Interpreter is not usable
+ set (_${_PYTHON_PREFIX}_EXECUTABLE_USABLE FALSE)
+ unset (${_PYTHON_PREFIX}_VERSION)
+ set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot run the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+ endif()
+ endif()
+
+ if (_${_PYTHON_PREFIX}_EXECUTABLE AND _${_PYTHON_PREFIX}_EXECUTABLE_USABLE)
+ if (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES)
+ set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE)
+
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 0 ${_PYTHON_PREFIX}_INTERPRETER_ID)
+
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 1 ${_PYTHON_PREFIX}_VERSION_MAJOR)
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 2 ${_PYTHON_PREFIX}_VERSION_MINOR)
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 3 ${_PYTHON_PREFIX}_VERSION_PATCH)
+
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 4 _${_PYTHON_PREFIX}_ARCH)
+ set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH})
+
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 5 _${_PYTHON_PREFIX}_ABIFLAGS)
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 6 ${_PYTHON_PREFIX}_SOABI)
+
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 7 ${_PYTHON_PREFIX}_STDLIB)
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 8 ${_PYTHON_PREFIX}_STDARCH)
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 9 ${_PYTHON_PREFIX}_SITELIB)
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 10 ${_PYTHON_PREFIX}_SITEARCH)
+ else()
+ string (REGEX MATCHALL "[0-9]+" _${_PYTHON_PREFIX}_VERSIONS "${${_PYTHON_PREFIX}_VERSION}")
+ list (GET _${_PYTHON_PREFIX}_VERSIONS 0 ${_PYTHON_PREFIX}_VERSION_MAJOR)
+ list (GET _${_PYTHON_PREFIX}_VERSIONS 1 ${_PYTHON_PREFIX}_VERSION_MINOR)
+ list (GET _${_PYTHON_PREFIX}_VERSIONS 2 ${_PYTHON_PREFIX}_VERSION_PATCH)
+
+ if (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+ set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE)
+
+ # Use interpreter version and ABI for future searches to ensure consistency
+ set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR})
+ execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETR_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys; sys.stdout.write(sys.abiflags)"
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_ABIFLAGS
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_${_PYTHON_PREFIX}_RESULT)
+ # assunme ABI is not supported
+ set (_${_PYTHON_PREFIX}_ABIFLAGS "")
+ endif()
+ endif()
+
+ if (${_PYTHON_PREFIX}_Interpreter_FOUND)
+ unset (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE)
+
+ # compute and save interpreter signature
+ string (MD5 __${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_EXECUTABLE}")
+ set (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${__${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}" CACHE INTERNAL "")
+
+ if (NOT CMAKE_SIZEOF_VOID_P)
+ # determine interpreter architecture
+ execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys; sys.stdout.write(str(sys.maxsize > 2**32))"
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE ${_PYTHON_PREFIX}_IS64BIT
+ ERROR_VARIABLE ${_PYTHON_PREFIX}_IS64BIT)
+ if (NOT _${_PYTHON_PREFIX}_RESULT)
+ if (${_PYTHON_PREFIX}_IS64BIT)
+ set (_${_PYTHON_PREFIX}_ARCH 64)
+ set (_${_PYTHON_PREFIX}_ARCH2 64)
+ else()
+ set (_${_PYTHON_PREFIX}_ARCH 32)
+ set (_${_PYTHON_PREFIX}_ARCH2 32)
+ endif()
+ endif()
+ endif()
+
+ # retrieve interpreter identity
+ execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -V
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID
+ ERROR_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID)
+ if (NOT _${_PYTHON_PREFIX}_RESULT)
+ if (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Anaconda")
+ set (${_PYTHON_PREFIX}_INTERPRETER_ID "Anaconda")
+ elseif (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Enthought")
+ set (${_PYTHON_PREFIX}_INTERPRETER_ID "Canopy")
+ elseif (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "PyPy ([0-9.]+)")
+ set (${_PYTHON_PREFIX}_INTERPRETER_ID "PyPy")
+ set (${_PYTHON_PREFIX}_PyPy_VERSION "${CMAKE_MATCH_1}")
+ else()
+ string (REGEX REPLACE "^([^ ]+).*" "\\1" ${_PYTHON_PREFIX}_INTERPRETER_ID "${${_PYTHON_PREFIX}_INTERPRETER_ID}")
+ if (${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "Python")
+ # try to get a more precise ID
+ execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys; sys.stdout.write(sys.copyright)"
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE ${_PYTHON_PREFIX}_COPYRIGHT
+ ERROR_QUIET)
+ if (${_PYTHON_PREFIX}_COPYRIGHT MATCHES "ActiveState")
+ set (${_PYTHON_PREFIX}_INTERPRETER_ID "ActivePython")
+ endif()
+ endif()
+ endif()
+ else()
+ set (${_PYTHON_PREFIX}_INTERPRETER_ID Python)
+ endif()
+
+ # retrieve various package installation directories
+ execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_python_lib(plat_specific=False,standard_lib=True),sysconfig.get_python_lib(plat_specific=True,standard_lib=True),sysconfig.get_python_lib(plat_specific=False,standard_lib=False),sysconfig.get_python_lib(plat_specific=True,standard_lib=False)]))\nexcept Exception:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_path('stdlib'),sysconfig.get_path('platstdlib'),sysconfig.get_path('purelib'),sysconfig.get_path('platlib')]))"
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_LIBPATHS
+ ERROR_QUIET)
+ if (NOT _${_PYTHON_PREFIX}_RESULT)
+ list (GET _${_PYTHON_PREFIX}_LIBPATHS 0 ${_PYTHON_PREFIX}_STDLIB)
+ list (GET _${_PYTHON_PREFIX}_LIBPATHS 1 ${_PYTHON_PREFIX}_STDARCH)
+ list (GET _${_PYTHON_PREFIX}_LIBPATHS 2 ${_PYTHON_PREFIX}_SITELIB)
+ list (GET _${_PYTHON_PREFIX}_LIBPATHS 3 ${_PYTHON_PREFIX}_SITEARCH)
+ else()
+ unset (${_PYTHON_PREFIX}_STDLIB)
+ unset (${_PYTHON_PREFIX}_STDARCH)
+ unset (${_PYTHON_PREFIX}_SITELIB)
+ unset (${_PYTHON_PREFIX}_SITEARCH)
+ endif()
+
+ _python_get_config_var (${_PYTHON_PREFIX}_SOABI SOABI)
+
+ # store properties in the cache to speed-up future searches
+ set (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES
+ "${${_PYTHON_PREFIX}_INTERPRETER_ID};${${_PYTHON_PREFIX}_VERSION_MAJOR};${${_PYTHON_PREFIX}_VERSION_MINOR};${${_PYTHON_PREFIX}_VERSION_PATCH};${_${_PYTHON_PREFIX}_ARCH};${_${_PYTHON_PREFIX}_ABIFLAGS};${${_PYTHON_PREFIX}_SOABI};${${_PYTHON_PREFIX}_STDLIB};${${_PYTHON_PREFIX}_STDARCH};${${_PYTHON_PREFIX}_SITELIB};${${_PYTHON_PREFIX}_SITEARCH}" CACHE INTERNAL "${_PYTHON_PREFIX} Properties")
+ else()
+ unset (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE CACHE)
+ unset (${_PYTHON_PREFIX}_INTERPRETER_ID)
+ endif()
+ endif()
+ endif()
+
+ if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE)
+ set (${_PYTHON_PREFIX}_EXECUTABLE "${_${_PYTHON_PREFIX}_EXECUTABLE}" CACHE FILEPATH "${_PYTHON_PREFIX} Interpreter")
+ endif()
+
+ _python_mark_as_internal (_${_PYTHON_PREFIX}_EXECUTABLE
+ _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES
+ _${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE)
+endif()
+
+
+# second step, search for compiler (IronPython)
+if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+ list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_COMPILER)
+ if (${_PYTHON_PREFIX}_FIND_REQUIRED_Compiler)
+ list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_COMPILER)
+ endif()
+
+ if (NOT "IronPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+ unset (_${_PYTHON_PREFIX}_COMPILER CACHE)
+ unset (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE CACHE)
+ elseif (DEFINED ${_PYTHON_PREFIX}_COMPILER
+ AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_COMPILER}")
+ set (_${_PYTHON_PREFIX}_COMPILER "${${_PYTHON_PREFIX}_COMPILER}" CACHE INTERNAL "")
+ elseif (DEFINED _${_PYTHON_PREFIX}_COMPILER)
+ # compute compiler signature and check validity of definition
+ string (MD5 __${_PYTHON_PREFIX}_COMPILER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_COMPILER}")
+ if (__${_PYTHON_PREFIX}_COMPILER_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_COMPILER_SIGNATURE)
+ # check version validity
+ if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
+ _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 (CHECK_EXISTS)
+ endif()
+ else()
+ unset (_${_PYTHON_PREFIX}_COMPILER CACHE)
+ unset (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE CACHE)
+ endif()
+ endif()
+
+ if ("IronPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS
+ AND NOT _${_PYTHON_PREFIX}_COMPILER)
+ # IronPython specific artifacts
+ # If IronPython interpreter is found, use its path
+ unset (_${_PYTHON_PREFIX}_IRON_ROOT)
+ if (${_PYTHON_PREFIX}_Interpreter_FOUND AND ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "IronPython")
+ get_filename_component (_${_PYTHON_PREFIX}_IRON_ROOT "${${_PYTHON_PREFIX}_EXECUTABLE}" DIRECTORY)
+ endif()
+
+ if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
+ _python_get_names (_${_PYTHON_PREFIX}_COMPILER_NAMES
+ IMPLEMENTATIONS IronPython
+ VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}
+ COMPILER)
+
+ _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES
+ IMPLEMENTATIONS IronPython
+ VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}
+ COMPILER)
+
+ _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS
+ IMPLEMENTATIONS IronPython
+ VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})
+ _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS
+ 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 _${_PYTHON_PREFIX}_VALIDATE_OPTIONS VERSION ${${_PYTHON_PREFIX}_FIND_VERSION})
+ endif()
+
+ while (TRUE)
+ # Apple frameworks handling
+ if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+ find_program (_${_PYTHON_PREFIX}_COMPILER
+ NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
+ endif()
+ # Windows registry
+ if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ find_program (_${_PYTHON_PREFIX}_COMPILER
+ NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
+ endif()
+
+ # try using HINTS
+ find_program (_${_PYTHON_PREFIX}_COMPILER
+ NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
+
+ # try using standard paths
+ find_program (_${_PYTHON_PREFIX}_COMPILER
+ NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+ NAMES_PER_DIR
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
+ _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
+
+ # Apple frameworks handling
+ if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+ find_program (_${_PYTHON_PREFIX}_COMPILER
+ NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+ NAMES_PER_DIR
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_DEFAULT_PATH)
+ _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
+ endif()
+ # Windows registry
+ if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+ find_program (_${_PYTHON_PREFIX}_COMPILER
+ NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+ NAMES_PER_DIR
+ 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()
+ endif()
+
+ break()
+ 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
+ VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}
+ COMPILER)
+
+ _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES
+ IMPLEMENTATIONS IronPython
+ VERSION ${_${_PYTHON_PREFIX}_FIND_VERSION}
+ COMPILER)
+
+ _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS
+ IMPLEMENTATIONS IronPython
+ VERSION ${_${_PYTHON_PREFIX}_VERSION})
+ _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS
+ IMPLEMENTATIONS IronPython
+ VERSION ${_${_PYTHON_PREFIX}_VERSION})
+
+ # Apple frameworks handling
+ if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+ find_program (_${_PYTHON_PREFIX}_COMPILER
+ NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
+ endif()
+ # Windows registry
+ if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ find_program (_${_PYTHON_PREFIX}_COMPILER
+ NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
+ endif()
+
+ # try using HINTS
+ find_program (_${_PYTHON_PREFIX}_COMPILER
+ NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
+
+ # Apple frameworks handling
+ if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+ find_program (_${_PYTHON_PREFIX}_COMPILER
+ NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+ NAMES_PER_DIR
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_DEFAULT_PATH)
+ _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
+ endif()
+ # Windows registry
+ if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+ find_program (_${_PYTHON_PREFIX}_COMPILER
+ NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+ NAMES_PER_DIR
+ PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_DEFAULT_PATH)
+ _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+ if (_${_PYTHON_PREFIX}_COMPILER)
+ break()
+ endif()
+ endif()
+ endforeach()
+
+ # no specific version found, re-try in standard paths
+ _python_get_names (_${_PYTHON_PREFIX}_COMPILER_NAMES
+ IMPLEMENTATIONS IronPython
+ VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}
+ COMPILER)
+ _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES
+ IMPLEMENTATIONS IronPython
+ VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}
+ COMPILER)
+ find_program (_${_PYTHON_PREFIX}_COMPILER
+ NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+ HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
+ _python_validate_compiler ()
+ endif()
+ endif()
+
+ set (${_PYTHON_PREFIX}_COMPILER "${_${_PYTHON_PREFIX}_COMPILER}")
+
+ if (_${_PYTHON_PREFIX}_COMPILER)
+ # retrieve python environment version from compiler
+ _python_get_launcher (_${_PYTHON_PREFIX}_COMPILER_LAUNCHER COMPILER)
+ set (_${_PYTHON_PREFIX}_VERSION_DIR "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir")
+ file (WRITE "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))\n")
+ execute_process (COMMAND ${_${_PYTHON_PREFIX}_COMPILER_LAUNCHER} "${_${_PYTHON_PREFIX}_COMPILER}"
+ ${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS}
+ /target:exe /embed "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py"
+ WORKING_DIRECTORY "${_${_PYTHON_PREFIX}_VERSION_DIR}"
+ OUTPUT_QUIET
+ ERROR_QUIET)
+ get_filename_component (_${_PYTHON_PREFIX}_IR_DIR "${_${_PYTHON_PREFIX}_COMPILER}" DIRECTORY)
+ execute_process (COMMAND "${CMAKE_COMMAND}" -E env "MONO_PATH=${_${_PYTHON_PREFIX}_IR_DIR}"
+ ${${_PYTHON_PREFIX}_DOTNET_LAUNCHER} "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.exe"
+ WORKING_DIRECTORY "${_${_PYTHON_PREFIX}_VERSION_DIR}"
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_VERSION
+ ERROR_QUIET)
+ if (NOT _${_PYTHON_PREFIX}_RESULT)
+ set (_${_PYTHON_PREFIX}_COMPILER_USABLE TRUE)
+ string (REGEX MATCHALL "[0-9]+" _${_PYTHON_PREFIX}_VERSIONS "${_${_PYTHON_PREFIX}_VERSION}")
+ list (GET _${_PYTHON_PREFIX}_VERSIONS 0 _${_PYTHON_PREFIX}_VERSION_MAJOR)
+ list (GET _${_PYTHON_PREFIX}_VERSIONS 1 _${_PYTHON_PREFIX}_VERSION_MINOR)
+ list (GET _${_PYTHON_PREFIX}_VERSIONS 2 _${_PYTHON_PREFIX}_VERSION_PATCH)
+
+ if (NOT ${_PYTHON_PREFIX}_Interpreter_FOUND)
+ # set public version information
+ set (${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_VERSION})
+ set (${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_VERSION_MAJOR})
+ set (${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_VERSION_MINOR})
+ set (${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_VERSION_PATCH})
+ endif()
+ else()
+ # compiler not usable
+ set (_${_PYTHON_PREFIX}_COMPILER_USABLE FALSE)
+ set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot run the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
+ endif()
+ file (REMOVE_RECURSE "${_${_PYTHON_PREFIX}_VERSION_DIR}")
+ endif()
+
+ if (_${_PYTHON_PREFIX}_COMPILER AND _${_PYTHON_PREFIX}_COMPILER_USABLE)
+ if (${_PYTHON_PREFIX}_Interpreter_FOUND)
+ # Compiler must be compatible with interpreter
+ if ("${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}" VERSION_EQUAL "${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}")
+ set (${_PYTHON_PREFIX}_Compiler_FOUND TRUE)
+ endif()
+ elseif (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+ set (${_PYTHON_PREFIX}_Compiler_FOUND TRUE)
+ # Use compiler version for future searches to ensure consistency
+ set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR})
+ endif()
+ endif()
+
+ if (${_PYTHON_PREFIX}_Compiler_FOUND)
+ unset (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE)
+
+ # compute and save compiler signature
+ string (MD5 __${_PYTHON_PREFIX}_COMPILER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_COMPILER}")
+ set (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE "${__${_PYTHON_PREFIX}_COMPILER_SIGNATURE}" CACHE INTERNAL "")
+
+ set (${_PYTHON_PREFIX}_COMPILER_ID IronPython)
+ else()
+ unset (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE CACHE)
+ unset (${_PYTHON_PREFIX}_COMPILER_ID)
+ endif()
+
+ if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE)
+ set (${_PYTHON_PREFIX}_COMPILER "${_${_PYTHON_PREFIX}_COMPILER}" CACHE FILEPATH "${_PYTHON_PREFIX} Compiler")
+ endif()
+
+ _python_mark_as_internal (_${_PYTHON_PREFIX}_COMPILER
+ _${_PYTHON_PREFIX}_COMPILER_SIGNATURE)
+endif()
+
+# third step, search for the development artifacts
+if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Module)
+ if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS)
+ list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARIES)
+ endif()
+ if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS)
+ list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_INCLUDE_DIRS)
+ endif()
+endif()
+if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Embed)
+ if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS)
+ list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARIES)
+ endif()
+ if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS)
+ list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_INCLUDE_DIRS)
+ endif()
+endif()
+list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_REQUIRED_VARS)
+## Development environment is not compatible with IronPython interpreter
+if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+ OR "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+ AND ((${_PYTHON_PREFIX}_Interpreter_FOUND
+ AND NOT ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "IronPython")
+ OR NOT ${_PYTHON_PREFIX}_Interpreter_FOUND))
+ if (${_PYTHON_PREFIX}_Interpreter_FOUND)
+ # reduce possible implementations to the interpreter one
+ if (${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "PyPy")
+ set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS "PyPy")
+ else()
+ set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS "CPython")
+ endif()
+ else()
+ list (REMOVE_ITEM _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS "IronPython")
+ endif()
+ if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+ list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
+ _${_PYTHON_PREFIX}_LIBRARY_DEBUG
+ _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)
+ endif()
+ if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+ list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_INCLUDE_DIR)
+ endif()
+
+ _python_check_development_signature (Module)
+ _python_check_development_signature (Embed)
+
+ if (DEFINED ${_PYTHON_PREFIX}_LIBRARY
+ AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_LIBRARY}")
+ set (_${_PYTHON_PREFIX}_LIBRARY_RELEASE "${${_PYTHON_PREFIX}_LIBRARY}" CACHE INTERNAL "")
+ unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG CACHE)
+ unset (_${_PYTHON_PREFIX}_INCLUDE_DIR CACHE)
+ endif()
+ if (DEFINED ${_PYTHON_PREFIX}_INCLUDE_DIR
+ AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_INCLUDE_DIR}")
+ set (_${_PYTHON_PREFIX}_INCLUDE_DIR "${${_PYTHON_PREFIX}_INCLUDE_DIR}" CACHE INTERNAL "")
+ endif()
+
+ # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
+ unset (_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES)
+ if (DEFINED ${_PYTHON_PREFIX}_USE_STATIC_LIBS AND NOT WIN32)
+ set(_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ if(${_PYTHON_PREFIX}_USE_STATIC_LIBS)
+ set (CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX})
+ else()
+ list (REMOVE_ITEM CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX})
+ endif()
+ endif()
+
+ if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE OR NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)
+ # if python interpreter is found, use it to look-up for artifacts
+ # to ensure consistency between interpreter and development environments.
+ # If not, try to locate a compatible config tool
+ if ((NOT ${_PYTHON_PREFIX}_Interpreter_FOUND OR CMAKE_CROSSCOMPILING)
+ AND "CPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+ set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+ unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)
+ if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+ set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)
+ endif()
+
+ if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
+ _python_get_names (_${_PYTHON_PREFIX}_CONFIG_NAMES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} POSIX CONFIG)
+ # Framework Paths
+ _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})
+
+ # Apple frameworks handling
+ if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+ find_program (_${_PYTHON_PREFIX}_CONFIG
+ NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+ ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES bin
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ find_program (_${_PYTHON_PREFIX}_CONFIG
+ NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+ PATH_SUFFIXES bin)
+
+ # Apple frameworks handling
+ if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+ find_program (_${_PYTHON_PREFIX}_CONFIG
+ NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+ NAMES_PER_DIR
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES bin
+ NO_DEFAULT_PATH)
+ endif()
+
+ if (_${_PYTHON_PREFIX}_CONFIG)
+ execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --help
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE __${_PYTHON_PREFIX}_HELP
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_${_PYTHON_PREFIX}_RESULT)
+ # assume config tool is not usable
+ unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+ endif()
+ endif()
+
+ if (_${_PYTHON_PREFIX}_CONFIG)
+ execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --abiflags
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE __${_PYTHON_PREFIX}_ABIFLAGS
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_${_PYTHON_PREFIX}_RESULT)
+ # assume ABI is not supported
+ set (__${_PYTHON_PREFIX}_ABIFLAGS "")
+ endif()
+ if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT __${_PYTHON_PREFIX}_ABIFLAGS IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
+ # Wrong ABI
+ unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+ endif()
+ endif()
+
+ if (_${_PYTHON_PREFIX}_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)
+ # check that config tool match library architecture
+ execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --configdir
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_${_PYTHON_PREFIX}_RESULT)
+ unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+ else()
+ string(FIND "${_${_PYTHON_PREFIX}_CONFIGDIR}" "${CMAKE_LIBRARY_ARCHITECTURE}" _${_PYTHON_PREFIX}_RESULT)
+ if (_${_PYTHON_PREFIX}_RESULT EQUAL -1)
+ unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+ endif()
+ endif()
+ endif()
+ else()
+ foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+ # try to use pythonX.Y-config tool
+ _python_get_names (_${_PYTHON_PREFIX}_CONFIG_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX CONFIG)
+
+ # Framework Paths
+ _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})
+
+ # Apple frameworks handling
+ if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+ find_program (_${_PYTHON_PREFIX}_CONFIG
+ NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+ ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES bin
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ find_program (_${_PYTHON_PREFIX}_CONFIG
+ NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+ PATH_SUFFIXES bin)
+
+ # Apple frameworks handling
+ if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+ find_program (_${_PYTHON_PREFIX}_CONFIG
+ NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+ NAMES_PER_DIR
+ PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES bin
+ NO_DEFAULT_PATH)
+ endif()
+
+ unset (_${_PYTHON_PREFIX}_CONFIG_NAMES)
+
+ if (_${_PYTHON_PREFIX}_CONFIG)
+ execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --help
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE __${_PYTHON_PREFIX}_HELP
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_${_PYTHON_PREFIX}_RESULT)
+ # assume config tool is not usable
+ unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+ endif()
+ endif()
+
+ if (NOT _${_PYTHON_PREFIX}_CONFIG)
+ continue()
+ endif()
+
+ execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --abiflags
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE __${_PYTHON_PREFIX}_ABIFLAGS
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_${_PYTHON_PREFIX}_RESULT)
+ # assume ABI is not supported
+ set (__${_PYTHON_PREFIX}_ABIFLAGS "")
+ endif()
+ if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT __${_PYTHON_PREFIX}_ABIFLAGS IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
+ # Wrong ABI
+ unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+ continue()
+ endif()
+
+ if (_${_PYTHON_PREFIX}_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)
+ # check that config tool match library architecture
+ execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --configdir
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_${_PYTHON_PREFIX}_RESULT)
+ unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+ continue()
+ endif()
+ string (FIND "${_${_PYTHON_PREFIX}_CONFIGDIR}" "${CMAKE_LIBRARY_ARCHITECTURE}" _${_PYTHON_PREFIX}_RESULT)
+ if (_${_PYTHON_PREFIX}_RESULT EQUAL -1)
+ unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+ continue()
+ endif()
+ endif()
+
+ if (_${_PYTHON_PREFIX}_CONFIG)
+ break()
+ endif()
+ endforeach()
+ endif()
+ endif()
+ endif()
+
+ if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+ if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ if ((${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT CMAKE_CROSSCOMPILING) OR _${_PYTHON_PREFIX}_CONFIG)
+ # retrieve root install directory
+ _python_get_config_var (_${_PYTHON_PREFIX}_PREFIX PREFIX)
+
+ # enforce current ABI
+ _python_get_config_var (_${_PYTHON_PREFIX}_ABIFLAGS ABIFLAGS)
+
+ set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}")
+
+ # retrieve library
+ ## compute some paths and artifact names
+ if (_${_PYTHON_PREFIX}_CONFIG)
+ string (REGEX REPLACE "^.+python([0-9.]+)[a-z]*-config" "\\1" _${_PYTHON_PREFIX}_VERSION "${_${_PYTHON_PREFIX}_CONFIG}")
+ else()
+ set (_${_PYTHON_PREFIX}_VERSION "${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}")
+ endif()
+ _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} LIBRARY)
+ _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 POSIX LIBRARY)
+
+ _python_get_config_var (_${_PYTHON_PREFIX}_CONFIGDIR CONFIGDIR)
+ list (APPEND _${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_CONFIGDIR}")
+
+ list (APPEND _${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+
+ find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ # Rely on HINTS and standard paths if interpreter or config tool failed to locate artifacts
+ if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+
+ unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)
+ if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+ set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)
+ endif()
+
+ if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
+ # library names
+ _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} WIN32 POSIX LIBRARY)
+ _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} WIN32 DEBUG)
+ # Paths suffixes
+ _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} LIBRARY)
+
+ # Framework Paths
+ _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_FIND_VERSIONS})
+ # Registry Paths
+ _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} )
+
+ if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+ find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+ ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+ ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ # search in HINTS locations
+ find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+
+ if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+ set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS})
+ else()
+ unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS)
+ endif()
+
+ if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+ set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS})
+ else()
+ unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS)
+ endif()
+
+ # search in all default paths
+ find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
+ else()
+ foreach (_${_PYTHON_PREFIX}_LIB_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+ _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} WIN32 POSIX LIBRARY)
+ _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} WIN32 DEBUG)
+
+ _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION})
+ _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION})
+
+ _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} LIBRARY)
+
+ if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+ find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+ ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+ ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ # search in HINTS locations
+ find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+
+ if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+ set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS})
+ else()
+ unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS)
+ endif()
+
+ if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+ set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS})
+ else()
+ unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS)
+ endif()
+
+ # search in all default paths
+ find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
+
+ if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ break()
+ endif()
+ endforeach()
+ endif()
+ endif()
+ endif()
+
+ # finalize library version information
+ _python_get_version (LIBRARY PREFIX _${_PYTHON_PREFIX}_)
+ if (_${_PYTHON_PREFIX}_VERSION EQUAL "${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}")
+ # not able to extract full version from library name
+ if (${_PYTHON_PREFIX}_Interpreter_FOUND)
+ # update from interpreter
+ set (_${_PYTHON_PREFIX}_VERSION ${${_PYTHON_PREFIX}_VERSION})
+ set (_${_PYTHON_PREFIX}_VERSION_MAJOR ${${_PYTHON_PREFIX}_VERSION_MAJOR})
+ set (_${_PYTHON_PREFIX}_VERSION_MINOR ${${_PYTHON_PREFIX}_VERSION_MINOR})
+ set (_${_PYTHON_PREFIX}_VERSION_PATCH ${${_PYTHON_PREFIX}_VERSION_PATCH})
+ endif()
+ endif()
+
+ set (${_PYTHON_PREFIX}_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
+
+ if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
+ set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
+ endif()
+
+ set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+
+ if (WIN32 AND _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ # search for debug library
+ # use release library location as a hint
+ _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 DEBUG)
+ get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
+ find_library (_${_PYTHON_PREFIX}_LIBRARY_DEBUG
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
+ NAMES_PER_DIR
+ HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS}
+ NO_DEFAULT_PATH)
+ # second try including CMAKE variables to catch-up non conventional layouts
+ find_library (_${_PYTHON_PREFIX}_LIBRARY_DEBUG
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
+ NAMES_PER_DIR
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ # retrieve runtime libraries
+ if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 POSIX LIBRARY)
+ get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
+ get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
+ _python_find_runtime_library (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ NAMES_PER_DIR
+ HINTS "${_${_PYTHON_PREFIX}_PATH}"
+ "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES bin)
+ endif()
+ if (_${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+ _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 DEBUG)
+ get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_LIBRARY_DEBUG}" DIRECTORY)
+ get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
+ _python_find_runtime_library (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
+ NAMES_PER_DIR
+ HINTS "${_${_PYTHON_PREFIX}_PATH}"
+ "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
+ PATH_SUFFIXES bin)
+ endif()
+ endif()
+
+ if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+ while (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)
+ if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS
+ AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ # Don't search for include dir if no library was founded
+ break()
+ endif()
+
+ if ((${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT CMAKE_CROSSCOMPILING) OR _${_PYTHON_PREFIX}_CONFIG)
+ _python_get_config_var (_${_PYTHON_PREFIX}_INCLUDE_DIRS INCLUDES)
+
+ find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR
+ NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES}
+ HINTS ${_${_PYTHON_PREFIX}_INCLUDE_DIRS}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ # Rely on HINTS and standard paths if interpreter or config tool failed to locate artifacts
+ if (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)
+ unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)
+ if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+ set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)
+ endif()
+ unset (_${_PYTHON_PREFIX}_INCLUDE_HINTS)
+
+ if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ # Use the library's install prefix as a hint
+ if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "^(.+/Frameworks/Python.framework/Versions/[0-9.]+)")
+ list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
+ elseif (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "^(.+)/lib(64|32)?/python[0-9.]+/config")
+ list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
+ elseif (DEFINED CMAKE_LIBRARY_ARCHITECTURE AND ${_${_PYTHON_PREFIX}_LIBRARY_RELEASE} MATCHES "^(.+)/lib/${CMAKE_LIBRARY_ARCHITECTURE}")
+ list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
+ else()
+ # assume library is in a directory under root
+ get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
+ get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_PREFIX}" DIRECTORY)
+ list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PREFIX}")
+ endif()
+ endif()
+
+ _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})
+ _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})
+ _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} INCLUDE)
+
+ if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+ find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR
+ NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES}
+ HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+ ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+ find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR
+ NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES}
+ HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+ ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+ set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS})
+ else()
+ unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS)
+ endif()
+
+ if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+ set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS})
+ else()
+ unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS)
+ endif()
+
+ find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR
+ NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES}
+ HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+ ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+ ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
+ PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+ endif()
+
+ # search header file in standard locations
+ find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR
+ NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES})
+
+ break()
+ endwhile()
+
+ set (${_PYTHON_PREFIX}_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
+
+ if (_${_PYTHON_PREFIX}_INCLUDE_DIR AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
+ set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+ endif()
+
+ 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)
+ # update versioning
+ set (_${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_INC_VERSION})
+ set (_${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_INC_VERSION_PATCH})
+ endif()
+ else()
+ set (_${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_INC_VERSION})
+ set (_${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR})
+ set (_${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_INC_VERSION_MINOR})
+ set (_${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_INC_VERSION_PATCH})
+ endif()
+ endif()
+ endif()
+
+ if (NOT ${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT ${_PYTHON_PREFIX}_Compiler_FOUND)
+ # set public version information
+ set (${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_VERSION})
+ set (${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_VERSION_MAJOR})
+ set (${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_VERSION_MINOR})
+ set (${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_VERSION_PATCH})
+ endif()
+
+ # define public variables
+ if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+ set (${_PYTHON_PREFIX}_LIBRARY_DEBUG "${_${_PYTHON_PREFIX}_LIBRARY_DEBUG}")
+ _python_select_library_configurations (${_PYTHON_PREFIX})
+
+ set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}")
+ set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}")
+
+ if (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE)
+ set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}")
+ elseif (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)
+ set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}")
+ else()
+ set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${_PYTHON_PREFIX}_RUNTIME_LIBRARY-NOTFOUND")
+ endif()
+
+ _python_set_library_dirs (${_PYTHON_PREFIX}_LIBRARY_DIRS
+ _${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ _${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+ if (UNIX)
+ if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$")
+ set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DIRS ${${_PYTHON_PREFIX}_LIBRARY_DIRS})
+ endif()
+ else()
+ _python_set_library_dirs (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DIRS
+ _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
+ _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)
+ endif()
+ endif()
+
+ if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE OR _${_PYTHON_PREFIX}_INCLUDE_DIR)
+ if (${_PYTHON_PREFIX}_Interpreter_FOUND OR ${_PYTHON_PREFIX}_Compiler_FOUND)
+ # development environment must be compatible with interpreter/compiler
+ if ("${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}" VERSION_EQUAL "${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}"
+ AND "${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}" VERSION_EQUAL "${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}")
+ _python_set_development_module_found (Module)
+ _python_set_development_module_found (Embed)
+ endif()
+ elseif (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR
+ AND "${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}" VERSION_EQUAL "${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}")
+ _python_set_development_module_found (Module)
+ _python_set_development_module_found (Embed)
+ endif()
+ if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND
+ (NOT _${_PYTHON_PREFIX}_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS
+ OR NOT _${_PYTHON_PREFIX}_INC_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS))
+ set (${_PYTHON_PREFIX}_Development.Module_FOUND FALSE)
+ set (${_PYTHON_PREFIX}_Development.Embed_FOUND FALSE)
+ endif()
+ endif()
+
+ if (( ${_PYTHON_PREFIX}_Development.Module_FOUND
+ AND ${_PYTHON_PREFIX}_Development.Embed_FOUND)
+ OR (NOT "Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+ AND ${_PYTHON_PREFIX}_Development.Embed_FOUND)
+ OR (NOT "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+ AND ${_PYTHON_PREFIX}_Development.Module_FOUND))
+ unset (_${_PYTHON_PREFIX}_Development_REASON_FAILURE)
+ endif()
+
+ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+ AND ${_PYTHON_PREFIX}_Development.Module_FOUND
+ AND ${_PYTHON_PREFIX}_Development.Embed_FOUND)
+ set (${_PYTHON_PREFIX}_Development_FOUND TRUE)
+ endif()
+
+ if ((${_PYTHON_PREFIX}_Development.Module_FOUND
+ OR ${_PYTHON_PREFIX}_Development.Embed_FOUND)
+ AND EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}/PyPy.h")
+ # retrieve PyPy version
+ file (STRINGS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}/patchlevel.h" ${_PYTHON_PREFIX}_PyPy_VERSION
+ REGEX "^#define[ \t]+PYPY_VERSION[ \t]+\"[^\"]+\"")
+ string (REGEX REPLACE "^#define[ \t]+PYPY_VERSION[ \t]+\"([^\"]+)\".*" "\\1"
+ ${_PYTHON_PREFIX}_PyPy_VERSION "${${_PYTHON_PREFIX}_PyPy_VERSION}")
+ endif()
+
+ unset(${_PYTHON_PREFIX}_LINK_OPTIONS)
+ if (${_PYTHON_PREFIX}_Development.Embed_FOUND AND APPLE
+ AND ${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$")
+ # rpath must be specified if python is part of a framework
+ unset(_${_PYTHON_PREFIX}_is_prefix)
+ foreach (_${_PYTHON_PREFIX}_implementation IN LISTS _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+ foreach (_${_PYTHON_PREFIX}_framework IN LISTS _${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_implementation}_FRAMEWORKS)
+ cmake_path (IS_PREFIX _${_PYTHON_PREFIX}_framework "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" _${_PYTHON_PREFIX}_is_prefix)
+ if (_${_PYTHON_PREFIX}_is_prefix)
+ cmake_path (GET _${_PYTHON_PREFIX}_framework PARENT_PATH _${_PYTHON_PREFIX}_framework)
+ set (${_PYTHON_PREFIX}_LINK_OPTIONS "LINKER:-rpath,${_${_PYTHON_PREFIX}_framework}")
+ break()
+ endif()
+ endforeach()
+ if (_${_PYTHON_PREFIX}_is_prefix)
+ break()
+ endif()
+ endforeach()
+ unset(_${_PYTHON_PREFIX}_implementation)
+ unset(_${_PYTHON_PREFIX}_framework)
+ unset(_${_PYTHON_PREFIX}_is_prefix)
+ endif()
+
+ if (NOT DEFINED ${_PYTHON_PREFIX}_SOABI)
+ _python_get_config_var (${_PYTHON_PREFIX}_SOABI SOABI)
+ endif()
+
+ _python_compute_development_signature (Module)
+ _python_compute_development_signature (Embed)
+
+ # Restore the original find library ordering
+ if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES)
+ set (CMAKE_FIND_LIBRARY_SUFFIXES ${_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES})
+ endif()
+
+ if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE)
+ if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+ set (${_PYTHON_PREFIX}_LIBRARY "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" CACHE FILEPATH "${_PYTHON_PREFIX} Library")
+ endif()
+ if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+ set (${_PYTHON_PREFIX}_INCLUDE_DIR "${_${_PYTHON_PREFIX}_INCLUDE_DIR}" CACHE FILEPATH "${_PYTHON_PREFIX} Include Directory")
+ endif()
+ endif()
+
+ _python_mark_as_internal (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+ _${_PYTHON_PREFIX}_LIBRARY_DEBUG
+ _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
+ _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG
+ _${_PYTHON_PREFIX}_INCLUDE_DIR
+ _${_PYTHON_PREFIX}_CONFIG
+ _${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE
+ _${_PYTHON_PREFIX}_DEVELOPMENT_EMBED_SIGNATURE)
+endif()
+
+if (${_PYTHON_PREFIX}_FIND_REQUIRED_NumPy)
+ list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS)
+endif()
+if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Interpreter_FOUND)
+ list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)
+
+ if (DEFINED ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR
+ AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
+ set (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}" CACHE INTERNAL "")
+ elseif (DEFINED _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)
+ # compute numpy signature. Depends on interpreter and development signatures
+ string (MD5 __${_PYTHON_PREFIX}_NUMPY_SIGNATURE "${_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}:${_${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE}:${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
+ if (NOT __${_PYTHON_PREFIX}_NUMPY_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_NUMPY_SIGNATURE
+ OR NOT EXISTS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
+ unset (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR CACHE)
+ unset (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE CACHE)
+ endif()
+ endif()
+
+ if (NOT _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)
+ execute_process(COMMAND ${${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys\ntry: import numpy; sys.stdout.write(numpy.get_include())\nexcept:pass\n"
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_NumPy_PATH
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if (NOT _${_PYTHON_PREFIX}_RESULT)
+ find_path (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR
+ NAMES "numpy/arrayobject.h" "numpy/numpyconfig.h"
+ HINTS "${_${_PYTHON_PREFIX}_NumPy_PATH}"
+ NO_DEFAULT_PATH)
+ endif()
+ endif()
+
+ set (${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
+
+ if(_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR AND NOT EXISTS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
+ set (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR-NOTFOUND")
+ endif()
+
+ if (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)
+ execute_process (COMMAND ${${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys\ntry: import numpy; sys.stdout.write(numpy.__version__)\nexcept:pass\n"
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_NumPy_VERSION)
+ if (NOT _${_PYTHON_PREFIX}_RESULT)
+ set (${_PYTHON_PREFIX}_NumPy_VERSION "${_${_PYTHON_PREFIX}_NumPy_VERSION}")
+ else()
+ unset (${_PYTHON_PREFIX}_NumPy_VERSION)
+ endif()
+
+ # final step: set NumPy founded only if Development.Module component is founded as well
+ set(${_PYTHON_PREFIX}_NumPy_FOUND ${${_PYTHON_PREFIX}_Development.Module_FOUND})
+ else()
+ set (${_PYTHON_PREFIX}_NumPy_FOUND FALSE)
+ endif()
+
+ if (${_PYTHON_PREFIX}_NumPy_FOUND)
+ unset (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE)
+
+ # compute and save numpy signature
+ string (MD5 __${_PYTHON_PREFIX}_NUMPY_SIGNATURE "${_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}:${_${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE}:${${_PYTHON_PREFIX}_NumPyINCLUDE_DIR}")
+ set (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE "${__${_PYTHON_PREFIX}_NUMPY_SIGNATURE}" CACHE INTERNAL "")
+ else()
+ unset (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE CACHE)
+ endif()
+
+ if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE)
+ set (${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}" CACHE FILEPATH "${_PYTHON_PREFIX} NumPy Include Directory")
+ endif()
+
+ _python_mark_as_internal (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR
+ _${_PYTHON_PREFIX}_NUMPY_SIGNATURE)
+endif()
+
+# final validation
+if (${_PYTHON_PREFIX}_VERSION_MAJOR AND
+ NOT ${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+ _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Found unsuitable major version \"${${_PYTHON_PREFIX}_VERSION_MAJOR}\", but required major version is exact version \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"")
+
+ cmake_policy(POP)
+ return()
+endif()
+
+unset (_${_PYTHON_PREFIX}_REASON_FAILURE)
+foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development NumPy)
+ if (_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE)
+ string (APPEND _${_PYTHON_PREFIX}_REASON_FAILURE "\n ${_${_PYTHON_PREFIX}_COMPONENT}: ${_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE}")
+ unset (_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE)
+ endif()
+endforeach()
+
+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}")
+
+# Create imported targets and helper functions
+if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
+ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+ AND ${_PYTHON_PREFIX}_Interpreter_FOUND
+ AND NOT TARGET ${_PYTHON_PREFIX}::Interpreter)
+ add_executable (${_PYTHON_PREFIX}::Interpreter IMPORTED)
+ set_property (TARGET ${_PYTHON_PREFIX}::Interpreter
+ PROPERTY IMPORTED_LOCATION "${${_PYTHON_PREFIX}_EXECUTABLE}")
+ endif()
+
+ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+ AND ${_PYTHON_PREFIX}_Compiler_FOUND
+ AND NOT TARGET ${_PYTHON_PREFIX}::Compiler)
+ add_executable (${_PYTHON_PREFIX}::Compiler IMPORTED)
+ set_property (TARGET ${_PYTHON_PREFIX}::Compiler
+ PROPERTY IMPORTED_LOCATION "${${_PYTHON_PREFIX}_COMPILER}")
+ endif()
+
+ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+ AND ${_PYTHON_PREFIX}_Development.Module_FOUND)
+ OR ("Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+ AND ${_PYTHON_PREFIX}_Development.Embed_FOUND))
+
+ macro (__PYTHON_IMPORT_LIBRARY __name)
+ if (${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$"
+ OR ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE)
+ set (_${_PYTHON_PREFIX}_LIBRARY_TYPE SHARED)
+ else()
+ set (_${_PYTHON_PREFIX}_LIBRARY_TYPE STATIC)
+ endif()
+
+ if (NOT TARGET ${__name})
+ add_library (${__name} ${_${_PYTHON_PREFIX}_LIBRARY_TYPE} IMPORTED)
+ endif()
+
+ set_property (TARGET ${__name}
+ PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIRS}")
+
+ if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE)
+ # System manage shared libraries in two parts: import and runtime
+ if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+ set_property (TARGET ${__name} PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG)
+ set_target_properties (${__name}
+ PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+ IMPORTED_IMPLIB_RELEASE "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}"
+ IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}")
+ set_target_properties (${__name}
+ PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+ IMPORTED_IMPLIB_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}"
+ IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}")
+ else()
+ set_target_properties (${__name}
+ PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_IMPLIB "${${_PYTHON_PREFIX}_LIBRARIES}"
+ IMPORTED_LOCATION "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}")
+ endif()
+ else()
+ if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+ set_property (TARGET ${__name} PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG)
+ set_target_properties (${__name}
+ PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+ IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
+ set_target_properties (${__name}
+ PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+ IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}")
+ else()
+ set_target_properties (${__name}
+ PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
+ endif()
+ endif()
+
+ if (_${_PYTHON_PREFIX}_LIBRARY_TYPE STREQUAL "STATIC")
+ # extend link information with dependent libraries
+ _python_get_config_var (_${_PYTHON_PREFIX}_LINK_LIBRARIES LIBS)
+ if (_${_PYTHON_PREFIX}_LINK_LIBRARIES)
+ set_property (TARGET ${__name}
+ PROPERTY INTERFACE_LINK_LIBRARIES ${_${_PYTHON_PREFIX}_LINK_LIBRARIES})
+ endif()
+ endif()
+
+ if (${_PYTHON_PREFIX}_LINK_OPTIONS
+ AND _${_PYTHON_PREFIX}_LIBRARY_TYPE STREQUAL "SHARED")
+ set_property (TARGET ${__name} PROPERTY INTERFACE_LINK_OPTIONS "${${_PYTHON_PREFIX}_LINK_OPTIONS}")
+ endif()
+ endmacro()
+
+ if (${_PYTHON_PREFIX}_Development.Embed_FOUND)
+ __python_import_library (${_PYTHON_PREFIX}::Python)
+ endif()
+
+ if (${_PYTHON_PREFIX}_Development.Module_FOUND)
+ if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS)
+ # On Windows/CYGWIN/MSYS, Python::Module is the same as Python::Python
+ # but ALIAS cannot be used because the imported library is not GLOBAL.
+ __python_import_library (${_PYTHON_PREFIX}::Module)
+ else()
+ if (NOT TARGET ${_PYTHON_PREFIX}::Module)
+ add_library (${_PYTHON_PREFIX}::Module INTERFACE IMPORTED)
+ endif()
+ set_property (TARGET ${_PYTHON_PREFIX}::Module
+ PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIRS}")
+
+ # When available, enforce shared library generation with undefined symbols
+ if (APPLE)
+ set_property (TARGET ${_PYTHON_PREFIX}::Module
+ PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-undefined,dynamic_lookup")
+ endif()
+ if (CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+ set_property (TARGET ${_PYTHON_PREFIX}::Module
+ PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-z,nodefs")
+ endif()
+ if (CMAKE_SYSTEM_NAME STREQUAL "AIX")
+ set_property (TARGET ${_PYTHON_PREFIX}::Module
+ PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-b,erok")
+ endif()
+ endif()
+ endif()
+
+ #
+ # PYTHON_ADD_LIBRARY (<name> [STATIC|SHARED|MODULE] src1 src2 ... srcN)
+ # It is used to build modules for python.
+ #
+ function (__${_PYTHON_PREFIX}_ADD_LIBRARY prefix name)
+ cmake_parse_arguments (PARSE_ARGV 2 PYTHON_ADD_LIBRARY "STATIC;SHARED;MODULE;WITH_SOABI" "" "")
+
+ if (PYTHON_ADD_LIBRARY_STATIC)
+ set (type STATIC)
+ elseif (PYTHON_ADD_LIBRARY_SHARED)
+ set (type SHARED)
+ else()
+ set (type MODULE)
+ endif()
+
+ if (type STREQUAL "MODULE" AND NOT TARGET ${prefix}::Module)
+ message (SEND_ERROR "${prefix}_ADD_LIBRARY: dependent target '${prefix}::Module' is not defined.\n Did you miss to request COMPONENT 'Development.Module'?")
+ return()
+ endif()
+ if (NOT type STREQUAL "MODULE" AND NOT TARGET ${prefix}::Python)
+ message (SEND_ERROR "${prefix}_ADD_LIBRARY: dependent target '${prefix}::Python' is not defined.\n Did you miss to request COMPONENT 'Development.Embed'?")
+ return()
+ endif()
+
+ add_library (${name} ${type} ${PYTHON_ADD_LIBRARY_UNPARSED_ARGUMENTS})
+
+ get_property (type TARGET ${name} PROPERTY TYPE)
+
+ if (type STREQUAL "MODULE_LIBRARY")
+ target_link_libraries (${name} PRIVATE ${prefix}::Module)
+ # customize library name to follow module name rules
+ set_property (TARGET ${name} PROPERTY PREFIX "")
+ if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+ set_property (TARGET ${name} PROPERTY SUFFIX ".pyd")
+ endif()
+
+ if (PYTHON_ADD_LIBRARY_WITH_SOABI AND ${prefix}_SOABI)
+ get_property (suffix TARGET ${name} PROPERTY SUFFIX)
+ if (NOT suffix)
+ set (suffix "${CMAKE_SHARED_MODULE_SUFFIX}")
+ endif()
+ set_property (TARGET ${name} PROPERTY SUFFIX ".${${prefix}_SOABI}${suffix}")
+ endif()
+ else()
+ if (PYTHON_ADD_LIBRARY_WITH_SOABI)
+ message (AUTHOR_WARNING "Find${prefix}: Option `WITH_SOABI` is only supported for `MODULE` library type.")
+ endif()
+ target_link_libraries (${name} PRIVATE ${prefix}::Python)
+ endif()
+ endfunction()
+ endif()
+
+ if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_NumPy_FOUND
+ AND NOT TARGET ${_PYTHON_PREFIX}::NumPy AND TARGET ${_PYTHON_PREFIX}::Module)
+ add_library (${_PYTHON_PREFIX}::NumPy INTERFACE IMPORTED)
+ set_property (TARGET ${_PYTHON_PREFIX}::NumPy
+ PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS}")
+ target_link_libraries (${_PYTHON_PREFIX}::NumPy INTERFACE ${_PYTHON_PREFIX}::Module)
+ endif()
+endif()
+
+# final clean-up
+
+# Restore CMAKE_FIND_APPBUNDLE
+if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE)
+ set (CMAKE_FIND_APPBUNDLE ${_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE})
+ unset (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE)
+else()
+ unset (CMAKE_FIND_APPBUNDLE)
+endif()
+# Restore CMAKE_FIND_FRAMEWORK
+if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK)
+ set (CMAKE_FIND_FRAMEWORK ${_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK})
+ unset (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK)
+else()
+ unset (CMAKE_FIND_FRAMEWORK)
+endif()
+
+cmake_policy(POP)
diff --git a/Modules/FindPython2.cmake b/Modules/FindPython2.cmake
new file mode 100644
index 0000000..bb965b9
--- /dev/null
+++ b/Modules/FindPython2.cmake
@@ -0,0 +1,430 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPython2
+-----------
+
+.. versionadded:: 3.12
+
+Find Python 2 interpreter, compiler and development environment (include
+directories and libraries).
+
+.. versionadded:: 3.19
+ 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
+* ``Compiler``: search for Python 2 compiler. Only offered by IronPython.
+* ``Development``: search for development artifacts (include directories and
+ libraries).
+
+ .. versionadded:: 3.18
+ This component includes two sub-components which can be specified
+ independently:
+
+ * ``Development.Module``: search for artifacts for Python 2 module
+ developments.
+ * ``Development.Embed``: search for artifacts for Python 2 embedding
+ developments.
+
+* ``NumPy``: search for NumPy include directories.
+
+.. versionadded:: 3.14
+ Added the ``NumPy`` component.
+
+If no ``COMPONENTS`` are specified, ``Interpreter`` is assumed.
+
+If component ``Development`` is specified, it implies sub-components
+``Development.Module`` and ``Development.Embed``.
+
+To ensure consistent versions between components ``Interpreter``, ``Compiler``,
+``Development`` (or one of its sub-components) and ``NumPy``, specify all
+components at the same time::
+
+ find_package (Python2 COMPONENTS Interpreter Development)
+
+This module looks only for version 2 of Python. This module can be used
+concurrently with :module:`FindPython3` module to use both Python versions.
+
+The :module:`FindPython` module can be used if Python version does not matter
+for you.
+
+.. note::
+
+ If components ``Interpreter`` and ``Development`` (or one of its
+ sub-components) are both specified, this module search only for interpreter
+ with same platform architecture as the one defined by ``CMake``
+ configuration. This constraint does not apply if only ``Interpreter``
+ component is specified.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+This module defines the following :ref:`Imported Targets <Imported Targets>`:
+
+.. versionchanged:: 3.14
+ :ref:`Imported Targets <Imported Targets>` are only created when
+ :prop_gbl:`CMAKE_ROLE` is ``PROJECT``.
+
+``Python2::Interpreter``
+ Python 2 interpreter. Target defined if component ``Interpreter`` is found.
+``Python2::Compiler``
+ Python 2 compiler. Target defined if component ``Compiler`` is found.
+``Python2::Module``
+ .. versionadded:: 3.15
+
+ Python 2 library for Python module. Target defined if component
+ ``Development.Module`` is found.
+
+``Python2::Python``
+ Python 2 library for Python embedding. Target defined if component
+ ``Development.Embed`` is found.
+
+``Python2::NumPy``
+ .. versionadded:: 3.14
+
+ NumPy library for Python 2. Target defined if component ``NumPy`` is found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project
+(see :ref:`Standard Variable Names <CMake Developer Standard Variable Names>`):
+
+``Python2_FOUND``
+ System has the Python 2 requested components.
+``Python2_Interpreter_FOUND``
+ System has the Python 2 interpreter.
+``Python2_EXECUTABLE``
+ Path to the Python 2 interpreter.
+``Python2_INTERPRETER_ID``
+ A short string unique to the interpreter. Possible values include:
+ * Python
+ * ActivePython
+ * Anaconda
+ * Canopy
+ * IronPython
+ * PyPy
+``Python2_STDLIB``
+ Standard platform independent installation directory.
+
+ Information returned by
+ ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=True)``
+ or else ``sysconfig.get_path('stdlib')``.
+``Python2_STDARCH``
+ Standard platform dependent installation directory.
+
+ Information returned by
+ ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=True)``
+ or else ``sysconfig.get_path('platstdlib')``.
+``Python2_SITELIB``
+ Third-party platform independent installation directory.
+
+ Information returned by
+ ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=False)``
+ or else ``sysconfig.get_path('purelib')``.
+``Python2_SITEARCH``
+ Third-party platform dependent installation directory.
+
+ Information returned by
+ ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)``
+ or else ``sysconfig.get_path('platlib')``.
+``Python2_Compiler_FOUND``
+ System has the Python 2 compiler.
+``Python2_COMPILER``
+ Path to the Python 2 compiler. Only offered by IronPython.
+``Python2_COMPILER_ID``
+ A short string unique to the compiler. Possible values include:
+ * IronPython
+
+``Python2_DOTNET_LAUNCHER``
+ .. versionadded:: 3.18
+
+ The ``.Net`` interpreter. Only used by ``IronPython`` implementation.
+
+``Python2_Development_FOUND``
+ System has the Python 2 development artifacts.
+
+``Python2_Development.Module_FOUND``
+ .. versionadded:: 3.18
+
+ System has the Python 2 development artifacts for Python module.
+
+``Python2_Development.Embed_FOUND``
+ .. versionadded:: 3.18
+
+ System has the Python 2 development artifacts for Python embedding.
+
+``Python2_INCLUDE_DIRS``
+ The Python 2 include directories.
+
+``Python2_LINK_OPTIONS``
+ .. versionadded:: 3.19
+
+ The Python 2 link options. Some configurations require specific link options
+ for a correct build and execution.
+
+``Python2_LIBRARIES``
+ The Python 2 libraries.
+``Python2_LIBRARY_DIRS``
+ The Python 2 library directories.
+``Python2_RUNTIME_LIBRARY_DIRS``
+ The Python 2 runtime library directories.
+``Python2_VERSION``
+ Python 2 version.
+``Python2_VERSION_MAJOR``
+ Python 2 major version.
+``Python2_VERSION_MINOR``
+ Python 2 minor version.
+``Python2_VERSION_PATCH``
+ Python 2 patch version.
+
+``Python2_PyPy_VERSION``
+ .. versionadded:: 3.18
+
+ Python 2 PyPy version.
+
+``Python2_NumPy_FOUND``
+ .. versionadded:: 3.14
+
+ System has the NumPy.
+
+``Python2_NumPy_INCLUDE_DIRS``
+ .. versionadded:: 3.14
+
+ The NumPy include directories.
+
+``Python2_NumPy_VERSION``
+ .. versionadded:: 3.14
+
+ The NumPy version.
+
+Hints
+^^^^^
+
+``Python2_ROOT_DIR``
+ Define the root directory of a Python 2 installation.
+
+``Python2_USE_STATIC_LIBS``
+ * If not defined, search for shared libraries and static libraries in that
+ order.
+ * If set to TRUE, search **only** for static libraries.
+ * If set to FALSE, search **only** for shared libraries.
+
+``Python2_FIND_STRATEGY``
+ .. versionadded:: 3.15
+
+ This variable defines how lookup will be done.
+ The ``Python2_FIND_STRATEGY`` variable can be set to one of the following:
+
+ * ``VERSION``: Try to find the most recent version in all specified
+ locations.
+ This is the default if policy :policy:`CMP0094` is undefined or set to
+ ``OLD``.
+ * ``LOCATION``: Stops lookup as soon as a version satisfying version
+ constraints is founded.
+ This is the default if policy :policy:`CMP0094` is set to ``NEW``.
+
+``Python2_FIND_REGISTRY``
+ .. versionadded:: 3.13
+
+ On Windows the ``Python2_FIND_REGISTRY`` variable determine the order
+ of preference between registry and environment variables.
+ the ``Python2_FIND_REGISTRY`` variable can be set to one of the following:
+
+ * ``FIRST``: Try to use registry before environment variables.
+ This is the default.
+ * ``LAST``: Try to use registry after environment variables.
+ * ``NEVER``: Never try to use registry.
+
+``Python2_FIND_FRAMEWORK``
+ .. versionadded:: 3.15
+
+ On macOS the ``Python2_FIND_FRAMEWORK`` variable determine the order of
+ preference between Apple-style and unix-style package components.
+ This variable can take same values as :variable:`CMAKE_FIND_FRAMEWORK`
+ variable.
+
+ .. note::
+
+ Value ``ONLY`` is not supported so ``FIRST`` will be used instead.
+
+ If ``Python2_FIND_FRAMEWORK`` is not defined, :variable:`CMAKE_FIND_FRAMEWORK`
+ variable will be used, if any.
+
+``Python2_FIND_VIRTUALENV``
+ .. versionadded:: 3.15
+
+ This variable defines the handling of virtual environments managed by
+ ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment
+ is active (i.e. the ``activate`` script has been evaluated). In this case, it
+ takes precedence over ``Python2_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK``
+ variables. The ``Python2_FIND_VIRTUALENV`` variable can be set to one of the
+ following:
+
+ * ``FIRST``: The virtual environment is used before any other standard
+ paths to look-up for the interpreter. This is the default.
+ * ``ONLY``: Only the virtual environment is used to look-up for the
+ interpreter.
+ * ``STANDARD``: The virtual environment is not used to look-up for the
+ interpreter but environment variable ``PATH`` is always considered.
+ In this case, variable ``Python2_FIND_REGISTRY`` (Windows) or
+ ``CMAKE_FIND_FRAMEWORK`` (macOS) can be set with value ``LAST`` or
+ ``NEVER`` to select preferably the interpreter from the virtual
+ environment.
+
+ .. versionadded:: 3.17
+ Added support for ``conda`` environments.
+
+ .. note::
+
+ If the component ``Development`` is requested, it is **strongly**
+ recommended to also include the component ``Interpreter`` to get expected
+ result.
+
+``Python2_FIND_IMPLEMENTATIONS``
+ .. versionadded:: 3.18
+
+ This variable defines, in an ordered list, the different implementations
+ which will be searched. The ``Python2_FIND_IMPLEMENTATIONS`` variable can
+ hold the following values:
+
+ * ``CPython``: this is the standard implementation. Various products, like
+ ``Anaconda`` or ``ActivePython``, rely on this implementation.
+ * ``IronPython``: This implementation use the ``CSharp`` language for
+ ``.NET Framework`` on top of the `Dynamic Language Runtime` (``DLR``).
+ See `IronPython <http://ironpython.net>`_.
+ * ``PyPy``: This implementation use ``RPython`` language and
+ ``RPython translation toolchain`` to produce the python interpreter.
+ See `PyPy <https://www.pypy.org>`_.
+
+ The default value is:
+
+ * Windows platform: ``CPython``, ``IronPython``
+ * Other platforms: ``CPython``
+
+ .. note::
+
+ This hint has the lowest priority of all hints, so even if, for example,
+ you specify ``IronPython`` first and ``CPython`` in second, a python
+ product based on ``CPython`` can be selected because, for example with
+ ``Python2_FIND_STRATEGY=LOCATION``, each location will be search first for
+ ``IronPython`` and second for ``CPython``.
+
+ .. note::
+
+ When ``IronPython`` is specified, on platforms other than ``Windows``, the
+ ``.Net`` interpreter (i.e. ``mono`` command) is expected to be available
+ through the ``PATH`` variable.
+
+``Python2_FIND_UNVERSIONED_NAMES``
+ .. versionadded:: 3.20
+
+ This variable defines how the generic names will be searched. Currently, it
+ only applies to the generic names of the interpreter, namely, ``python2`` and
+ ``python``.
+ The ``Python2_FIND_UNVERSIONED_NAMES`` variable can be set to one of the
+ following values:
+
+ * ``FIRST``: The generic names are searched before the more specialized ones
+ (such as ``python2.5`` for example).
+ * ``LAST``: The generic names are searched after the more specialized ones.
+ This is the default.
+ * ``NEVER``: The generic name are not searched at all.
+
+Artifacts Specification
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.16
+
+To solve special cases, it is possible to specify directly the artifacts by
+setting the following variables:
+
+``Python2_EXECUTABLE``
+ The path to the interpreter.
+
+``Python2_COMPILER``
+ The path to the compiler.
+
+``Python2_DOTNET_LAUNCHER``
+ .. versionadded:: 3.18
+
+ The ``.Net`` interpreter. Only used by ``IronPython`` implementation.
+
+``Python2_LIBRARY``
+ The path to the library. It will be used to compute the
+ variables ``Python2_LIBRARIES``, ``Python2_LIBRARY_DIRS`` and
+ ``Python2_RUNTIME_LIBRARY_DIRS``.
+
+``Python2_INCLUDE_DIR``
+ The path to the directory of the ``Python`` headers. It will be used to
+ compute the variable ``Python2_INCLUDE_DIRS``.
+
+``Python2_NumPy_INCLUDE_DIR``
+ The path to the directory of the ``NumPy`` headers. It will be used to
+ compute the variable ``Python2_NumPy_INCLUDE_DIRS``.
+
+.. note::
+
+ All paths must be absolute. Any artifact specified with a relative path
+ will be ignored.
+
+.. note::
+
+ When an artifact is specified, all ``HINTS`` will be ignored and no search
+ will be performed for this artifact.
+
+ If more than one artifact is specified, it is the user's responsibility to
+ ensure the consistency of the various artifacts.
+
+By default, this module supports multiple calls in different directories of a
+project with different version/component requirements while providing correct
+and consistent results for each call. To support this behavior, ``CMake`` cache
+is not used in the traditional way which can be problematic for interactive
+specification. So, to enable also interactive specification, module behavior
+can be controlled with the following variable:
+
+``Python2_ARTIFACTS_INTERACTIVE``
+ .. versionadded:: 3.18
+
+ Selects the behavior of the module. This is a boolean variable:
+
+ * If set to ``TRUE``: Create CMake cache entries for the above artifact
+ specification variables so that users can edit them interactively.
+ This disables support for multiple version/component requirements.
+ * If set to ``FALSE`` or undefined: Enable multiple version/component
+ requirements.
+
+Commands
+^^^^^^^^
+
+This module defines the command ``Python2_add_library`` (when
+:prop_gbl:`CMAKE_ROLE` is ``PROJECT``), which has the same semantics as
+:command:`add_library` and adds a dependency to target ``Python2::Python`` or,
+when library type is ``MODULE``, to target ``Python2::Module`` and takes care
+of Python module naming rules::
+
+ Python2_add_library (<name> [STATIC | SHARED | MODULE]
+ <source1> [<source2> ...])
+
+If library type is not specified, ``MODULE`` is assumed.
+#]=======================================================================]
+
+
+set (_PYTHON_PREFIX Python2)
+
+set (_Python2_REQUIRED_VERSION_MAJOR 2)
+
+include (${CMAKE_CURRENT_LIST_DIR}/FindPython/Support.cmake)
+
+if (COMMAND __Python2_add_library)
+ macro (Python2_add_library)
+ __Python2_add_library (Python2 ${ARGV})
+ endmacro()
+endif()
+
+unset (_PYTHON_PREFIX)
diff --git a/Modules/FindPython3.cmake b/Modules/FindPython3.cmake
new file mode 100644
index 0000000..f826fcf
--- /dev/null
+++ b/Modules/FindPython3.cmake
@@ -0,0 +1,493 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPython3
+-----------
+
+.. versionadded:: 3.12
+
+Find Python 3 interpreter, compiler and development environment (include
+directories and libraries).
+
+.. versionadded:: 3.19
+ 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
+* ``Compiler``: search for Python 3 compiler. Only offered by IronPython.
+* ``Development``: search for development artifacts (include directories and
+ libraries).
+
+ .. versionadded:: 3.18
+ This component includes two sub-components which can be specified
+ independently:
+
+ * ``Development.Module``: search for artifacts for Python 3 module
+ developments.
+ * ``Development.Embed``: search for artifacts for Python 3 embedding
+ developments.
+
+* ``NumPy``: search for NumPy include directories.
+
+.. versionadded:: 3.14
+ Added the ``NumPy`` component.
+
+If no ``COMPONENTS`` are specified, ``Interpreter`` is assumed.
+
+If component ``Development`` is specified, it implies sub-components
+``Development.Module`` and ``Development.Embed``.
+
+To ensure consistent versions between components ``Interpreter``, ``Compiler``,
+``Development`` (or one of its sub-components) and ``NumPy``, specify all
+components at the same time::
+
+ find_package (Python3 COMPONENTS Interpreter Development)
+
+This module looks only for version 3 of Python. This module can be used
+concurrently with :module:`FindPython2` module to use both Python versions.
+
+The :module:`FindPython` module can be used if Python version does not matter
+for you.
+
+.. note::
+
+ If components ``Interpreter`` and ``Development`` (or one of its
+ sub-components) are both specified, this module search only for interpreter
+ with same platform architecture as the one defined by ``CMake``
+ configuration. This constraint does not apply if only ``Interpreter``
+ component is specified.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+This module defines the following :ref:`Imported Targets <Imported Targets>`:
+
+.. versionchanged:: 3.14
+ :ref:`Imported Targets <Imported Targets>` are only created when
+ :prop_gbl:`CMAKE_ROLE` is ``PROJECT``.
+
+``Python3::Interpreter``
+ Python 3 interpreter. Target defined if component ``Interpreter`` is found.
+``Python3::Compiler``
+ Python 3 compiler. Target defined if component ``Compiler`` is found.
+
+``Python3::Module``
+ .. versionadded:: 3.15
+
+ Python 3 library for Python module. Target defined if component
+ ``Development.Module`` is found.
+
+``Python3::Python``
+ Python 3 library for Python embedding. Target defined if component
+ ``Development.Embed`` is found.
+
+``Python3::NumPy``
+ .. versionadded:: 3.14
+
+ NumPy library for Python 3. Target defined if component ``NumPy`` is found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project
+(see :ref:`Standard Variable Names <CMake Developer Standard Variable Names>`):
+
+``Python3_FOUND``
+ System has the Python 3 requested components.
+``Python3_Interpreter_FOUND``
+ System has the Python 3 interpreter.
+``Python3_EXECUTABLE``
+ Path to the Python 3 interpreter.
+``Python3_INTERPRETER_ID``
+ A short string unique to the interpreter. Possible values include:
+ * Python
+ * ActivePython
+ * Anaconda
+ * Canopy
+ * IronPython
+ * PyPy
+``Python3_STDLIB``
+ Standard platform independent installation directory.
+
+ Information returned by
+ ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=True)``
+ or else ``sysconfig.get_path('stdlib')``.
+``Python3_STDARCH``
+ Standard platform dependent installation directory.
+
+ Information returned by
+ ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=True)``
+ or else ``sysconfig.get_path('platstdlib')``.
+``Python3_SITELIB``
+ Third-party platform independent installation directory.
+
+ Information returned by
+ ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=False)``
+ or else ``sysconfig.get_path('purelib')``.
+``Python3_SITEARCH``
+ Third-party platform dependent installation directory.
+
+ Information returned by
+ ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)``
+ or else ``sysconfig.get_path('platlib')``.
+
+``Python3_SOABI``
+ .. versionadded:: 3.17
+
+ Extension suffix for modules.
+
+ Information returned by
+ ``distutils.sysconfig.get_config_var('SOABI')`` or computed from
+ ``distutils.sysconfig.get_config_var('EXT_SUFFIX')`` or
+ ``python3-config --extension-suffix``. If package ``distutils.sysconfig`` is
+ not available, ``sysconfig.get_config_var('SOABI')`` or
+ ``sysconfig.get_config_var('EXT_SUFFIX')`` are used.
+
+``Python3_Compiler_FOUND``
+ System has the Python 3 compiler.
+``Python3_COMPILER``
+ Path to the Python 3 compiler. Only offered by IronPython.
+``Python3_COMPILER_ID``
+ A short string unique to the compiler. Possible values include:
+ * IronPython
+
+``Python3_DOTNET_LAUNCHER``
+ .. versionadded:: 3.18
+
+ The ``.Net`` interpreter. Only used by ``IronPython`` implementation.
+
+``Python3_Development_FOUND``
+
+ System has the Python 3 development artifacts.
+
+``Python3_Development.Module_FOUND``
+ .. versionadded:: 3.18
+
+ System has the Python 3 development artifacts for Python module.
+
+``Python3_Development.Embed_FOUND``
+ .. versionadded:: 3.18
+
+ System has the Python 3 development artifacts for Python embedding.
+
+``Python3_INCLUDE_DIRS``
+
+ The Python 3 include directories.
+
+``Python3_LINK_OPTIONS``
+ .. versionadded:: 3.19
+
+ The Python 3 link options. Some configurations require specific link options
+ for a correct build and execution.
+
+``Python3_LIBRARIES``
+ The Python 3 libraries.
+``Python3_LIBRARY_DIRS``
+ The Python 3 library directories.
+``Python3_RUNTIME_LIBRARY_DIRS``
+ The Python 3 runtime library directories.
+``Python3_VERSION``
+ Python 3 version.
+``Python3_VERSION_MAJOR``
+ Python 3 major version.
+``Python3_VERSION_MINOR``
+ Python 3 minor version.
+``Python3_VERSION_PATCH``
+ Python 3 patch version.
+
+``Python3_PyPy_VERSION``
+ .. versionadded:: 3.18
+
+ Python 3 PyPy version.
+
+``Python3_NumPy_FOUND``
+ .. versionadded:: 3.14
+
+ System has the NumPy.
+
+``Python3_NumPy_INCLUDE_DIRS``
+ .. versionadded:: 3.14
+
+ The NumPy include directories.
+
+``Python3_NumPy_VERSION``
+ .. versionadded:: 3.14
+
+ The NumPy version.
+
+Hints
+^^^^^
+
+``Python3_ROOT_DIR``
+ Define the root directory of a Python 3 installation.
+
+``Python3_USE_STATIC_LIBS``
+ * If not defined, search for shared libraries and static libraries in that
+ order.
+ * If set to TRUE, search **only** for static libraries.
+ * If set to FALSE, search **only** for shared libraries.
+
+``Python3_FIND_ABI``
+ .. versionadded:: 3.16
+
+ This variable defines which ABIs, as defined in
+ `PEP 3149 <https://www.python.org/dev/peps/pep-3149/>`_, should be searched.
+
+ .. note::
+
+ If ``Python3_FIND_ABI`` is not defined, any ABI will be searched.
+
+ The ``Python3_FIND_ABI`` variable is a 3-tuple specifying, in that order,
+ ``pydebug`` (``d``), ``pymalloc`` (``m``) and ``unicode`` (``u``) flags.
+ Each element can be set to one of the following:
+
+ * ``ON``: Corresponding flag is selected.
+ * ``OFF``: Corresponding flag is not selected.
+ * ``ANY``: The two possibilities (``ON`` and ``OFF``) will be searched.
+
+ From this 3-tuple, various ABIs will be searched starting from the most
+ specialized to the most general. Moreover, ``debug`` versions will be
+ searched **after** ``non-debug`` ones.
+
+ For example, if we have::
+
+ set (Python3_FIND_ABI "ON" "ANY" "ANY")
+
+ The following flags combinations will be appended, in that order, to the
+ artifact names: ``dmu``, ``dm``, ``du``, and ``d``.
+
+ And to search any possible ABIs::
+
+ set (Python3_FIND_ABI "ANY" "ANY" "ANY")
+
+ The following combinations, in that order, will be used: ``mu``, ``m``,
+ ``u``, ``<empty>``, ``dmu``, ``dm``, ``du`` and ``d``.
+
+ .. note::
+
+ This hint is useful only on ``POSIX`` systems. So, on ``Windows`` systems,
+ when ``Python3_FIND_ABI`` is defined, ``Python`` distributions from
+ `python.org <https://www.python.org/>`_ will be found only if value for
+ each flag is ``OFF`` or ``ANY``.
+
+``Python3_FIND_STRATEGY``
+ .. versionadded:: 3.15
+
+ This variable defines how lookup will be done.
+ The ``Python3_FIND_STRATEGY`` variable can be set to one of the following:
+
+ * ``VERSION``: Try to find the most recent version in all specified
+ locations.
+ This is the default if policy :policy:`CMP0094` is undefined or set to
+ ``OLD``.
+ * ``LOCATION``: Stops lookup as soon as a version satisfying version
+ constraints is founded.
+ This is the default if policy :policy:`CMP0094` is set to ``NEW``.
+
+``Python3_FIND_REGISTRY``
+ .. versionadded:: 3.13
+
+ On Windows the ``Python3_FIND_REGISTRY`` variable determine the order
+ of preference between registry and environment variables.
+ The ``Python3_FIND_REGISTRY`` variable can be set to one of the following:
+
+ * ``FIRST``: Try to use registry before environment variables.
+ This is the default.
+ * ``LAST``: Try to use registry after environment variables.
+ * ``NEVER``: Never try to use registry.
+
+``Python3_FIND_FRAMEWORK``
+ .. versionadded:: 3.15
+
+ On macOS the ``Python3_FIND_FRAMEWORK`` variable determine the order of
+ preference between Apple-style and unix-style package components.
+ This variable can take same values as :variable:`CMAKE_FIND_FRAMEWORK`
+ variable.
+
+ .. note::
+
+ Value ``ONLY`` is not supported so ``FIRST`` will be used instead.
+
+ If ``Python3_FIND_FRAMEWORK`` is not defined, :variable:`CMAKE_FIND_FRAMEWORK`
+ variable will be used, if any.
+
+``Python3_FIND_VIRTUALENV``
+ .. versionadded:: 3.15
+
+ This variable defines the handling of virtual environments managed by
+ ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment
+ is active (i.e. the ``activate`` script has been evaluated). In this case, it
+ takes precedence over ``Python3_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK``
+ variables. The ``Python3_FIND_VIRTUALENV`` variable can be set to one of the
+ following:
+
+ * ``FIRST``: The virtual environment is used before any other standard
+ paths to look-up for the interpreter. This is the default.
+ * ``ONLY``: Only the virtual environment is used to look-up for the
+ interpreter.
+ * ``STANDARD``: The virtual environment is not used to look-up for the
+ interpreter but environment variable ``PATH`` is always considered.
+ In this case, variable ``Python3_FIND_REGISTRY`` (Windows) or
+ ``CMAKE_FIND_FRAMEWORK`` (macOS) can be set with value ``LAST`` or
+ ``NEVER`` to select preferably the interpreter from the virtual
+ environment.
+
+ .. versionadded:: 3.17
+ Added support for ``conda`` environments.
+
+ .. note::
+
+ If the component ``Development`` is requested, it is **strongly**
+ recommended to also include the component ``Interpreter`` to get expected
+ result.
+
+``Python3_FIND_IMPLEMENTATIONS``
+ .. versionadded:: 3.18
+
+ This variable defines, in an ordered list, the different implementations
+ which will be searched. The ``Python3_FIND_IMPLEMENTATIONS`` variable can
+ hold the following values:
+
+ * ``CPython``: this is the standard implementation. Various products, like
+ ``Anaconda`` or ``ActivePython``, rely on this implementation.
+ * ``IronPython``: This implementation use the ``CSharp`` language for
+ ``.NET Framework`` on top of the `Dynamic Language Runtime` (``DLR``).
+ See `IronPython <http://ironpython.net>`_.
+ * ``PyPy``: This implementation use ``RPython`` language and
+ ``RPython translation toolchain`` to produce the python interpreter.
+ See `PyPy <https://www.pypy.org>`_.
+
+ The default value is:
+
+ * Windows platform: ``CPython``, ``IronPython``
+ * Other platforms: ``CPython``
+
+ .. note::
+
+ This hint has the lowest priority of all hints, so even if, for example,
+ you specify ``IronPython`` first and ``CPython`` in second, a python
+ product based on ``CPython`` can be selected because, for example with
+ ``Python3_FIND_STRATEGY=LOCATION``, each location will be search first for
+ ``IronPython`` and second for ``CPython``.
+
+ .. note::
+
+ When ``IronPython`` is specified, on platforms other than ``Windows``, the
+ ``.Net`` interpreter (i.e. ``mono`` command) is expected to be available
+ through the ``PATH`` variable.
+
+``Python3_FIND_UNVERSIONED_NAMES``
+ .. versionadded:: 3.20
+
+ This variable defines how the generic names will be searched. Currently, it
+ only applies to the generic names of the interpreter, namely, ``python3`` and
+ ``python``.
+ The ``Python3_FIND_UNVERSIONED_NAMES`` variable can be set to one of the
+ following values:
+
+ * ``FIRST``: The generic names are searched before the more specialized ones
+ (such as ``python3.5`` for example).
+ * ``LAST``: The generic names are searched after the more specialized ones.
+ This is the default.
+ * ``NEVER``: The generic name are not searched at all.
+
+Artifacts Specification
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.16
+
+To solve special cases, it is possible to specify directly the artifacts by
+setting the following variables:
+
+``Python3_EXECUTABLE``
+ The path to the interpreter.
+
+``Python3_COMPILER``
+ The path to the compiler.
+
+``Python3_DOTNET_LAUNCHER``
+ .. versionadded:: 3.18
+
+ The ``.Net`` interpreter. Only used by ``IronPython`` implementation.
+
+``Python3_LIBRARY``
+ The path to the library. It will be used to compute the
+ variables ``Python3_LIBRARIES``, ``Python3_LIBRARY_DIRS`` and
+ ``Python3_RUNTIME_LIBRARY_DIRS``.
+
+``Python3_INCLUDE_DIR``
+ The path to the directory of the ``Python`` headers. It will be used to
+ compute the variable ``Python3_INCLUDE_DIRS``.
+
+``Python3_NumPy_INCLUDE_DIR``
+ The path to the directory of the ``NumPy`` headers. It will be used to
+ compute the variable ``Python3_NumPy_INCLUDE_DIRS``.
+
+.. note::
+
+ All paths must be absolute. Any artifact specified with a relative path
+ will be ignored.
+
+.. note::
+
+ When an artifact is specified, all ``HINTS`` will be ignored and no search
+ will be performed for this artifact.
+
+ If more than one artifact is specified, it is the user's responsibility to
+ ensure the consistency of the various artifacts.
+
+By default, this module supports multiple calls in different directories of a
+project with different version/component requirements while providing correct
+and consistent results for each call. To support this behavior, ``CMake`` cache
+is not used in the traditional way which can be problematic for interactive
+specification. So, to enable also interactive specification, module behavior
+can be controlled with the following variable:
+
+``Python3_ARTIFACTS_INTERACTIVE``
+ .. versionadded:: 3.18
+
+ Selects the behavior of the module. This is a boolean variable:
+
+ * If set to ``TRUE``: Create CMake cache entries for the above artifact
+ specification variables so that users can edit them interactively.
+ This disables support for multiple version/component requirements.
+ * If set to ``FALSE`` or undefined: Enable multiple version/component
+ requirements.
+
+Commands
+^^^^^^^^
+
+This module defines the command ``Python3_add_library`` (when
+:prop_gbl:`CMAKE_ROLE` is ``PROJECT``), which has the same semantics as
+:command:`add_library` and adds a dependency to target ``Python3::Python`` or,
+when library type is ``MODULE``, to target ``Python3::Module`` and takes care
+of Python module naming rules::
+
+ Python3_add_library (<name> [STATIC | SHARED | MODULE [WITH_SOABI]]
+ <source1> [<source2> ...])
+
+If the library type is not specified, ``MODULE`` is assumed.
+
+.. versionadded:: 3.17
+ For ``MODULE`` library type, if option ``WITH_SOABI`` is specified, the
+ module suffix will include the ``Python3_SOABI`` value, if any.
+#]=======================================================================]
+
+
+set (_PYTHON_PREFIX Python3)
+
+set (_Python3_REQUIRED_VERSION_MAJOR 3)
+
+include (${CMAKE_CURRENT_LIST_DIR}/FindPython/Support.cmake)
+
+if (COMMAND __Python3_add_library)
+ macro (Python3_add_library)
+ __Python3_add_library (Python3 ${ARGV})
+ endmacro()
+endif()
+
+unset (_PYTHON_PREFIX)
diff --git a/Modules/FindPythonInterp.cmake b/Modules/FindPythonInterp.cmake
new file mode 100644
index 0000000..efe0f11
--- /dev/null
+++ b/Modules/FindPythonInterp.cmake
@@ -0,0 +1,171 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPythonInterp
+----------------
+
+.. deprecated:: 3.12
+
+ Use :module:`FindPython3`, :module:`FindPython2` or :module:`FindPython` instead.
+
+Find python interpreter
+
+This module finds if Python interpreter is installed and determines
+where the executables are. This code sets the following variables:
+
+::
+
+ PYTHONINTERP_FOUND - Was the Python executable found
+ PYTHON_EXECUTABLE - path to the Python interpreter
+
+
+
+::
+
+ PYTHON_VERSION_STRING - Python version found e.g. 2.5.2
+ PYTHON_VERSION_MAJOR - Python major version found e.g. 2
+ PYTHON_VERSION_MINOR - Python minor version found e.g. 5
+ PYTHON_VERSION_PATCH - Python patch version found e.g. 2
+
+
+
+The Python_ADDITIONAL_VERSIONS variable can be used to specify a list
+of version numbers that should be taken into account when searching
+for Python. You need to set this variable before calling
+find_package(PythonInterp).
+
+If calling both ``find_package(PythonInterp)`` and
+``find_package(PythonLibs)``, call ``find_package(PythonInterp)`` first to
+get the currently active Python version by default with a consistent version
+of PYTHON_LIBRARIES.
+
+.. note::
+
+ A call to ``find_package(PythonInterp ${V})`` for python version ``V``
+ may find a ``python`` executable with no version suffix. In this case
+ no attempt is made to avoid python executables from other versions.
+ Use :module:`FindPython3`, :module:`FindPython2` or :module:`FindPython`
+ instead.
+
+#]=======================================================================]
+
+unset(_Python_NAMES)
+
+set(_PYTHON1_VERSIONS 1.6 1.5)
+set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
+set(_PYTHON3_VERSIONS 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
+
+if(PythonInterp_FIND_VERSION)
+ if(PythonInterp_FIND_VERSION_COUNT GREATER 1)
+ set(_PYTHON_FIND_MAJ_MIN "${PythonInterp_FIND_VERSION_MAJOR}.${PythonInterp_FIND_VERSION_MINOR}")
+ list(APPEND _Python_NAMES
+ python${_PYTHON_FIND_MAJ_MIN}
+ python${PythonInterp_FIND_VERSION_MAJOR})
+ unset(_PYTHON_FIND_OTHER_VERSIONS)
+ if(NOT PythonInterp_FIND_VERSION_EXACT)
+ foreach(_PYTHON_V ${_PYTHON${PythonInterp_FIND_VERSION_MAJOR}_VERSIONS})
+ if(NOT _PYTHON_V VERSION_LESS _PYTHON_FIND_MAJ_MIN)
+ list(APPEND _PYTHON_FIND_OTHER_VERSIONS ${_PYTHON_V})
+ endif()
+ endforeach()
+ endif()
+ unset(_PYTHON_FIND_MAJ_MIN)
+ else()
+ list(APPEND _Python_NAMES python${PythonInterp_FIND_VERSION_MAJOR})
+ set(_PYTHON_FIND_OTHER_VERSIONS ${_PYTHON${PythonInterp_FIND_VERSION_MAJOR}_VERSIONS})
+ endif()
+else()
+ set(_PYTHON_FIND_OTHER_VERSIONS ${_PYTHON3_VERSIONS} ${_PYTHON2_VERSIONS} ${_PYTHON1_VERSIONS})
+endif()
+find_program(PYTHON_EXECUTABLE NAMES ${_Python_NAMES})
+
+# Set up the versions we know about, in the order we will search. Always add
+# the user supplied additional versions to the front.
+set(_Python_VERSIONS ${Python_ADDITIONAL_VERSIONS})
+# If FindPythonInterp has already found the major and minor version,
+# insert that version next to get consistent versions of the interpreter and
+# library.
+if(DEFINED PYTHONLIBS_VERSION_STRING)
+ string(REPLACE "." ";" _PYTHONLIBS_VERSION "${PYTHONLIBS_VERSION_STRING}")
+ list(GET _PYTHONLIBS_VERSION 0 _PYTHONLIBS_VERSION_MAJOR)
+ list(GET _PYTHONLIBS_VERSION 1 _PYTHONLIBS_VERSION_MINOR)
+ list(APPEND _Python_VERSIONS ${_PYTHONLIBS_VERSION_MAJOR}.${_PYTHONLIBS_VERSION_MINOR})
+endif()
+# Search for the current active python version first
+list(APPEND _Python_VERSIONS ";")
+list(APPEND _Python_VERSIONS ${_PYTHON_FIND_OTHER_VERSIONS})
+
+unset(_PYTHON_FIND_OTHER_VERSIONS)
+unset(_PYTHON1_VERSIONS)
+unset(_PYTHON2_VERSIONS)
+unset(_PYTHON3_VERSIONS)
+
+# Search for newest python version if python executable isn't found
+if(NOT PYTHON_EXECUTABLE)
+ foreach(_CURRENT_VERSION IN LISTS _Python_VERSIONS)
+ set(_Python_NAMES python${_CURRENT_VERSION})
+ if(CMAKE_HOST_WIN32)
+ list(APPEND _Python_NAMES python)
+ endif()
+ find_program(PYTHON_EXECUTABLE
+ NAMES ${_Python_NAMES}
+ PATHS
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-32\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-64\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-32\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-64\\InstallPath]
+ )
+ endforeach()
+endif()
+
+# determine python version string
+if(PYTHON_EXECUTABLE)
+ execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c
+ "import sys; sys.stdout.write(';'.join([str(x) for x in sys.version_info[:3]]))"
+ OUTPUT_VARIABLE _VERSION
+ RESULT_VARIABLE _PYTHON_VERSION_RESULT
+ ERROR_QUIET)
+ if(NOT _PYTHON_VERSION_RESULT)
+ string(REPLACE ";" "." PYTHON_VERSION_STRING "${_VERSION}")
+ list(GET _VERSION 0 PYTHON_VERSION_MAJOR)
+ list(GET _VERSION 1 PYTHON_VERSION_MINOR)
+ list(GET _VERSION 2 PYTHON_VERSION_PATCH)
+ if(PYTHON_VERSION_PATCH EQUAL 0)
+ # it's called "Python 2.7", not "2.7.0"
+ string(REGEX REPLACE "\\.0$" "" PYTHON_VERSION_STRING "${PYTHON_VERSION_STRING}")
+ endif()
+ else()
+ # sys.version predates sys.version_info, so use that
+ # sys.version was first documented for Python 1.5, so assume version 1.4
+ # if retrieving sys.version fails.
+ execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "try: import sys; sys.stdout.write(sys.version)\nexcept: sys.stdout.write(\"1.4.0\")"
+ OUTPUT_VARIABLE _VERSION
+ RESULT_VARIABLE _PYTHON_VERSION_RESULT
+ ERROR_QUIET)
+ if(NOT _PYTHON_VERSION_RESULT)
+ string(REGEX REPLACE " .*" "" PYTHON_VERSION_STRING "${_VERSION}")
+ string(REGEX REPLACE "^([0-9]+)\\.[0-9]+.*" "\\1" PYTHON_VERSION_MAJOR "${PYTHON_VERSION_STRING}")
+ string(REGEX REPLACE "^[0-9]+\\.([0-9])+.*" "\\1" PYTHON_VERSION_MINOR "${PYTHON_VERSION_STRING}")
+ if(PYTHON_VERSION_STRING MATCHES "^[0-9]+\\.[0-9]+\\.([0-9]+)")
+ set(PYTHON_VERSION_PATCH "${CMAKE_MATCH_1}")
+ else()
+ set(PYTHON_VERSION_PATCH "0")
+ endif()
+ else()
+ unset(PYTHON_VERSION_STRING)
+ unset(PYTHON_VERSION_MAJOR)
+ unset(PYTHON_VERSION_MINOR)
+ unset(PYTHON_VERSION_PATCH)
+ endif()
+ endif()
+ unset(_PYTHON_VERSION_RESULT)
+ unset(_VERSION)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(PythonInterp REQUIRED_VARS PYTHON_EXECUTABLE VERSION_VAR PYTHON_VERSION_STRING)
+
+mark_as_advanced(PYTHON_EXECUTABLE)
diff --git a/Modules/FindPythonLibs.cmake b/Modules/FindPythonLibs.cmake
new file mode 100644
index 0000000..396f0d2
--- /dev/null
+++ b/Modules/FindPythonLibs.cmake
@@ -0,0 +1,399 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindPythonLibs
+--------------
+
+.. deprecated:: 3.12
+
+ Use :module:`FindPython3`, :module:`FindPython2` or :module:`FindPython` instead.
+
+Find python libraries
+
+This module finds if Python is installed and determines where the
+include files and libraries are. It also determines what the name of
+the library is. This code sets the following variables:
+
+::
+
+ PYTHONLIBS_FOUND - have the Python libs been found
+ PYTHON_LIBRARIES - path to the python library
+ PYTHON_INCLUDE_PATH - path to where Python.h is found (deprecated)
+ PYTHON_INCLUDE_DIRS - path to where Python.h is found
+ PYTHON_DEBUG_LIBRARIES - path to the debug library (deprecated)
+ PYTHONLIBS_VERSION_STRING - version of the Python libs found (since CMake 2.8.8)
+
+
+
+The Python_ADDITIONAL_VERSIONS variable can be used to specify a list
+of version numbers that should be taken into account when searching
+for Python. You need to set this variable before calling
+find_package(PythonLibs).
+
+If you'd like to specify the installation of Python to use, you should
+modify the following cache variables:
+
+::
+
+ PYTHON_LIBRARY - path to the python library
+ PYTHON_INCLUDE_DIR - path to where Python.h is found
+
+If calling both ``find_package(PythonInterp)`` and
+``find_package(PythonLibs)``, call ``find_package(PythonInterp)`` first to
+get the currently active Python version by default with a consistent version
+of PYTHON_LIBRARIES.
+#]=======================================================================]
+
+# Use the executable's path as a hint
+set(_Python_LIBRARY_PATH_HINT)
+if(IS_ABSOLUTE "${PYTHON_EXECUTABLE}")
+ if(WIN32)
+ get_filename_component(_Python_PREFIX "${PYTHON_EXECUTABLE}" PATH)
+ if(_Python_PREFIX)
+ set(_Python_LIBRARY_PATH_HINT ${_Python_PREFIX}/libs)
+ endif()
+ unset(_Python_PREFIX)
+ else()
+ get_filename_component(_Python_PREFIX "${PYTHON_EXECUTABLE}" PATH)
+ get_filename_component(_Python_PREFIX "${_Python_PREFIX}" PATH)
+ if(_Python_PREFIX)
+ set(_Python_LIBRARY_PATH_HINT ${_Python_PREFIX}/lib)
+ endif()
+ unset(_Python_PREFIX)
+ endif()
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/CMakeFindFrameworks.cmake)
+# Search for the python framework on Apple.
+CMAKE_FIND_FRAMEWORKS(Python)
+
+# Save CMAKE_FIND_FRAMEWORK
+if(DEFINED CMAKE_FIND_FRAMEWORK)
+ set(_PythonLibs_CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK})
+else()
+ unset(_PythonLibs_CMAKE_FIND_FRAMEWORK)
+endif()
+# To avoid picking up the system Python.h pre-maturely.
+set(CMAKE_FIND_FRAMEWORK LAST)
+
+set(_PYTHON1_VERSIONS 1.6 1.5)
+set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
+set(_PYTHON3_VERSIONS 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
+
+if(PythonLibs_FIND_VERSION)
+ if(PythonLibs_FIND_VERSION_COUNT GREATER 1)
+ set(_PYTHON_FIND_MAJ_MIN "${PythonLibs_FIND_VERSION_MAJOR}.${PythonLibs_FIND_VERSION_MINOR}")
+ unset(_PYTHON_FIND_OTHER_VERSIONS)
+ if(PythonLibs_FIND_VERSION_EXACT)
+ if(_PYTHON_FIND_MAJ_MIN STREQUAL PythonLibs_FIND_VERSION)
+ set(_PYTHON_FIND_OTHER_VERSIONS "${PythonLibs_FIND_VERSION}")
+ else()
+ set(_PYTHON_FIND_OTHER_VERSIONS "${PythonLibs_FIND_VERSION}" "${_PYTHON_FIND_MAJ_MIN}")
+ endif()
+ else()
+ foreach(_PYTHON_V ${_PYTHON${PythonLibs_FIND_VERSION_MAJOR}_VERSIONS})
+ if(NOT _PYTHON_V VERSION_LESS _PYTHON_FIND_MAJ_MIN)
+ list(APPEND _PYTHON_FIND_OTHER_VERSIONS ${_PYTHON_V})
+ endif()
+ endforeach()
+ endif()
+ unset(_PYTHON_FIND_MAJ_MIN)
+ else()
+ set(_PYTHON_FIND_OTHER_VERSIONS ${_PYTHON${PythonLibs_FIND_VERSION_MAJOR}_VERSIONS})
+ endif()
+else()
+ set(_PYTHON_FIND_OTHER_VERSIONS ${_PYTHON3_VERSIONS} ${_PYTHON2_VERSIONS} ${_PYTHON1_VERSIONS})
+endif()
+
+# Set up the versions we know about, in the order we will search. Always add
+# the user supplied additional versions to the front.
+# If FindPythonInterp has already found the major and minor version,
+# insert that version between the user supplied versions and the stock
+# version list.
+set(_Python_VERSIONS ${Python_ADDITIONAL_VERSIONS})
+if(DEFINED PYTHON_VERSION_MAJOR AND DEFINED PYTHON_VERSION_MINOR)
+ list(APPEND _Python_VERSIONS ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR})
+endif()
+list(APPEND _Python_VERSIONS ${_PYTHON_FIND_OTHER_VERSIONS})
+
+unset(_PYTHON_FIND_OTHER_VERSIONS)
+unset(_PYTHON1_VERSIONS)
+unset(_PYTHON2_VERSIONS)
+unset(_PYTHON3_VERSIONS)
+
+# Python distribution: define which architectures can be used
+if (CMAKE_SIZEOF_VOID_P)
+ # In this case, search only for 64bit or 32bit
+ math (EXPR _PYTHON_ARCH "${CMAKE_SIZEOF_VOID_P} * 8")
+ set (_PYTHON_ARCH2 _PYTHON_PREFIX_ARCH})
+else()
+ if (PYTHON_EXECUTABLE)
+ # determine interpreter architecture
+ execute_process (COMMAND "${PYTHON_EXECUTABLE}" -c "import sys; print(sys.maxsize > 2**32)"
+ RESULT_VARIABLE _PYTHON_RESULT
+ OUTPUT_VARIABLE _PYTHON_IS64BIT
+ ERROR_VARIABLE _PYTHON_IS64BIT)
+ if (NOT _PYTHON_RESULT)
+ if (_PYTHON_IS64BIT)
+ set (_PYTHON_ARCH 64)
+ set (_PYTHON_ARCH2 64)
+ else()
+ set (_PYTHON_ARCH 32)
+ set (_PYTHON_ARCH2 32)
+ endif()
+ endif()
+ else()
+ # architecture unknown, search for both 64bit and 32bit
+ set (_PYTHON_ARCH 64)
+ set (_PYTHON_ARCH2 32)
+ endif()
+endif()
+
+foreach(_CURRENT_VERSION ${_Python_VERSIONS})
+ string(REPLACE "." "" _CURRENT_VERSION_NO_DOTS ${_CURRENT_VERSION})
+ if(WIN32)
+ find_library(PYTHON_DEBUG_LIBRARY
+ NAMES python${_CURRENT_VERSION_NO_DOTS}_d python
+ NAMES_PER_DIR
+ HINTS ${_Python_LIBRARY_PATH_HINT}
+ PATHS
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs/Debug
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/libs/Debug
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/libs/Debug
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs/Debug
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/libs/Debug
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/libs/Debug
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/libs
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/libs
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/libs
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/libs
+ )
+ endif()
+
+ set(PYTHON_FRAMEWORK_LIBRARIES)
+ if(Python_FRAMEWORKS AND NOT PYTHON_LIBRARY)
+ foreach(dir ${Python_FRAMEWORKS})
+ list(APPEND PYTHON_FRAMEWORK_LIBRARIES
+ ${dir}/Versions/${_CURRENT_VERSION}/lib)
+ endforeach()
+ endif()
+ find_library(PYTHON_LIBRARY
+ NAMES
+ python${_CURRENT_VERSION_NO_DOTS}
+ python${_CURRENT_VERSION}mu
+ python${_CURRENT_VERSION}m
+ python${_CURRENT_VERSION}u
+ python${_CURRENT_VERSION}
+ NAMES_PER_DIR
+ HINTS
+ ${_Python_LIBRARY_PATH_HINT}
+ PATHS
+ ${PYTHON_FRAMEWORK_LIBRARIES}
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/libs
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/libs
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/libs
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/libs
+ )
+ # Look for the static library in the Python config directory
+ find_library(PYTHON_LIBRARY
+ NAMES python${_CURRENT_VERSION_NO_DOTS} python${_CURRENT_VERSION}
+ NAMES_PER_DIR
+ # This is where the static library is usually located
+ PATH_SUFFIXES python${_CURRENT_VERSION}/config
+ )
+
+ # Don't search for include dir until library location is known
+ if(PYTHON_LIBRARY)
+
+ # Use the library's install prefix as a hint
+ set(_Python_INCLUDE_PATH_HINT)
+ # PYTHON_LIBRARY may contain a list because of SelectLibraryConfigurations
+ # which may have been run previously. If it is the case, the list can be:
+ # optimized;<FILEPATH_TO_RELEASE_LIBRARY>;debug;<FILEPATH_TO_DEBUG_LIBRARY>
+ foreach(lib ${PYTHON_LIBRARY} ${PYTHON_DEBUG_LIBRARY})
+ if(IS_ABSOLUTE "${lib}")
+ get_filename_component(_Python_PREFIX "${lib}" PATH)
+ get_filename_component(_Python_PREFIX "${_Python_PREFIX}" PATH)
+ if(_Python_PREFIX)
+ list(APPEND _Python_INCLUDE_PATH_HINT ${_Python_PREFIX}/include)
+ endif()
+ unset(_Python_PREFIX)
+ endif()
+ endforeach()
+
+ # Add framework directories to the search paths
+ set(PYTHON_FRAMEWORK_INCLUDES)
+ if(Python_FRAMEWORKS AND NOT PYTHON_INCLUDE_DIR)
+ foreach(dir ${Python_FRAMEWORKS})
+ list(APPEND PYTHON_FRAMEWORK_INCLUDES
+ ${dir}/Versions/${_CURRENT_VERSION}/include)
+ endforeach()
+ endif()
+
+ find_path(PYTHON_INCLUDE_DIR
+ NAMES Python.h
+ HINTS
+ ${_Python_INCLUDE_PATH_HINT}
+ PATHS
+ ${PYTHON_FRAMEWORK_INCLUDES}
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/include
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/include
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/include
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/include
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH}\\InstallPath]/include
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}-${_PYTHON_ARCH2}\\InstallPath]/include
+ PATH_SUFFIXES
+ python${_CURRENT_VERSION}mu
+ python${_CURRENT_VERSION}m
+ python${_CURRENT_VERSION}u
+ python${_CURRENT_VERSION}
+ )
+ endif()
+
+ # For backward compatibility, set PYTHON_INCLUDE_PATH.
+ set(PYTHON_INCLUDE_PATH "${PYTHON_INCLUDE_DIR}")
+
+ if(PYTHON_INCLUDE_DIR AND EXISTS "${PYTHON_INCLUDE_DIR}/patchlevel.h")
+ file(STRINGS "${PYTHON_INCLUDE_DIR}/patchlevel.h" python_version_str
+ REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"")
+ string(REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"]+)\".*" "\\1"
+ PYTHONLIBS_VERSION_STRING "${python_version_str}")
+ unset(python_version_str)
+ endif()
+
+ if(PYTHON_LIBRARY AND PYTHON_INCLUDE_DIR)
+ break()
+ endif()
+endforeach()
+
+unset(_Python_INCLUDE_PATH_HINT)
+unset(_Python_LIBRARY_PATH_HINT)
+
+mark_as_advanced(
+ PYTHON_DEBUG_LIBRARY
+ PYTHON_LIBRARY
+ PYTHON_INCLUDE_DIR
+)
+
+# We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the
+# cache entries because they are meant to specify the location of a single
+# library. We now set the variables listed by the documentation for this
+# module.
+set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
+set(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}")
+
+# These variables have been historically named in this module different from
+# what SELECT_LIBRARY_CONFIGURATIONS() expects.
+set(PYTHON_LIBRARY_DEBUG "${PYTHON_DEBUG_LIBRARY}")
+set(PYTHON_LIBRARY_RELEASE "${PYTHON_LIBRARY}")
+include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+SELECT_LIBRARY_CONFIGURATIONS(PYTHON)
+# SELECT_LIBRARY_CONFIGURATIONS() sets ${PREFIX}_FOUND if it has a library.
+# Unset this, this prefix doesn't match the module prefix, they are different
+# for historical reasons.
+unset(PYTHON_FOUND)
+
+# Restore CMAKE_FIND_FRAMEWORK
+if(DEFINED _PythonLibs_CMAKE_FIND_FRAMEWORK)
+ set(CMAKE_FIND_FRAMEWORK ${_PythonLibs_CMAKE_FIND_FRAMEWORK})
+ unset(_PythonLibs_CMAKE_FIND_FRAMEWORK)
+else()
+ unset(CMAKE_FIND_FRAMEWORK)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(PythonLibs
+ REQUIRED_VARS PYTHON_LIBRARIES PYTHON_INCLUDE_DIRS
+ VERSION_VAR PYTHONLIBS_VERSION_STRING)
+
+# PYTHON_ADD_MODULE(<name> src1 src2 ... srcN) is used to build modules for python.
+# PYTHON_WRITE_MODULES_HEADER(<filename>) writes a header file you can include
+# in your sources to initialize the static python modules
+function(PYTHON_ADD_MODULE _NAME )
+ get_property(_TARGET_SUPPORTS_SHARED_LIBS
+ GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS)
+ option(PYTHON_ENABLE_MODULE_${_NAME} "Add module ${_NAME}" TRUE)
+ option(PYTHON_MODULE_${_NAME}_BUILD_SHARED
+ "Add module ${_NAME} shared" ${_TARGET_SUPPORTS_SHARED_LIBS})
+
+ # Mark these options as advanced
+ mark_as_advanced(PYTHON_ENABLE_MODULE_${_NAME}
+ PYTHON_MODULE_${_NAME}_BUILD_SHARED)
+
+ if(PYTHON_ENABLE_MODULE_${_NAME})
+ if(PYTHON_MODULE_${_NAME}_BUILD_SHARED)
+ set(PY_MODULE_TYPE MODULE)
+ else()
+ set(PY_MODULE_TYPE STATIC)
+ set_property(GLOBAL APPEND PROPERTY PY_STATIC_MODULES_LIST ${_NAME})
+ endif()
+
+ set_property(GLOBAL APPEND PROPERTY PY_MODULES_LIST ${_NAME})
+ add_library(${_NAME} ${PY_MODULE_TYPE} ${ARGN})
+# target_link_libraries(${_NAME} ${PYTHON_LIBRARIES})
+
+ if(PYTHON_MODULE_${_NAME}_BUILD_SHARED)
+ set_target_properties(${_NAME} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}")
+ if(WIN32 AND NOT CYGWIN)
+ set_target_properties(${_NAME} PROPERTIES SUFFIX ".pyd")
+ endif()
+ endif()
+
+ endif()
+endfunction()
+
+function(PYTHON_WRITE_MODULES_HEADER _filename)
+
+ get_property(PY_STATIC_MODULES_LIST GLOBAL PROPERTY PY_STATIC_MODULES_LIST)
+
+ get_filename_component(_name "${_filename}" NAME)
+ string(REPLACE "." "_" _name "${_name}")
+ string(TOUPPER ${_name} _nameUpper)
+ set(_filename ${CMAKE_CURRENT_BINARY_DIR}/${_filename})
+
+ set(_filenameTmp "${_filename}.in")
+ file(WRITE ${_filenameTmp} "/*Created by cmake, do not edit, changes will be lost*/\n")
+ file(APPEND ${_filenameTmp}
+"#ifndef ${_nameUpper}
+#define ${_nameUpper}
+
+#include <Python.h>
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif /* __cplusplus */
+
+")
+
+ foreach(_currentModule ${PY_STATIC_MODULES_LIST})
+ file(APPEND ${_filenameTmp} "extern void init${PYTHON_MODULE_PREFIX}${_currentModule}(void);\n\n")
+ endforeach()
+
+ file(APPEND ${_filenameTmp}
+"#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+")
+
+
+ foreach(_currentModule ${PY_STATIC_MODULES_LIST})
+ file(APPEND ${_filenameTmp} "int ${_name}_${_currentModule}(void) \n{\n static char name[]=\"${PYTHON_MODULE_PREFIX}${_currentModule}\"; return PyImport_AppendInittab(name, init${PYTHON_MODULE_PREFIX}${_currentModule});\n}\n\n")
+ endforeach()
+
+ file(APPEND ${_filenameTmp} "void ${_name}_LoadAllPythonModules(void)\n{\n")
+ foreach(_currentModule ${PY_STATIC_MODULES_LIST})
+ file(APPEND ${_filenameTmp} " ${_name}_${_currentModule}();\n")
+ endforeach()
+ file(APPEND ${_filenameTmp} "}\n\n")
+ file(APPEND ${_filenameTmp} "#ifndef EXCLUDE_LOAD_ALL_FUNCTION\nvoid CMakeLoadAllPythonModules(void)\n{\n ${_name}_LoadAllPythonModules();\n}\n#endif\n\n#endif\n")
+
+# with configure_file() cmake complains that you may not use a file created using file(WRITE) as input file for configure_file()
+ execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_filenameTmp}" "${_filename}" OUTPUT_QUIET ERROR_QUIET)
+
+endfunction()
diff --git a/Modules/FindQt.cmake b/Modules/FindQt.cmake
new file mode 100644
index 0000000..44a1f41
--- /dev/null
+++ b/Modules/FindQt.cmake
@@ -0,0 +1,188 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindQt
+------
+
+.. deprecated:: 3.14
+ This module is available only if policy :policy:`CMP0084` is not set to ``NEW``.
+
+Searches for all installed versions of Qt3 or Qt4.
+
+This module cannot handle Qt5 or any later versions.
+For those, see :manual:`cmake-qt(7)`.
+
+This module should only be used if your project can work with multiple
+versions of Qt. If not, you should just directly use FindQt4 or
+FindQt3. If multiple versions of Qt are found on the machine, then
+The user must set the option DESIRED_QT_VERSION to the version they
+want to use. If only one version of qt is found on the machine, then
+the DESIRED_QT_VERSION is set to that version and the matching FindQt3
+or FindQt4 module is included. Once the user sets DESIRED_QT_VERSION,
+then the FindQt3 or FindQt4 module is included.
+
+::
+
+ QT_REQUIRED if this is set to TRUE then if CMake can
+ not find Qt4 or Qt3 an error is raised
+ and a message is sent to the user.
+
+
+
+::
+
+ DESIRED_QT_VERSION OPTION is created
+ QT4_INSTALLED is set to TRUE if qt4 is found.
+ QT3_INSTALLED is set to TRUE if qt3 is found.
+#]=======================================================================]
+
+if(_findqt_testing)
+ set(_findqt_included TRUE)
+ return()
+endif()
+
+# look for signs of qt3 installations
+file(GLOB GLOB_TEMP_VAR /usr/lib*/qt-3*/bin/qmake /usr/lib*/qt3*/bin/qmake)
+if(GLOB_TEMP_VAR)
+ set(QT3_INSTALLED TRUE)
+endif()
+set(GLOB_TEMP_VAR)
+
+file(GLOB GLOB_TEMP_VAR /usr/local/qt-x11-commercial-3*/bin/qmake)
+if(GLOB_TEMP_VAR)
+ set(QT3_INSTALLED TRUE)
+endif()
+set(GLOB_TEMP_VAR)
+
+file(GLOB GLOB_TEMP_VAR /usr/local/lib/qt3/bin/qmake)
+if(GLOB_TEMP_VAR)
+ set(QT3_INSTALLED TRUE)
+endif()
+set(GLOB_TEMP_VAR)
+
+# look for qt4 installations
+file(GLOB GLOB_TEMP_VAR /usr/local/qt-x11-commercial-4*/bin/qmake)
+if(GLOB_TEMP_VAR)
+ set(QT4_INSTALLED TRUE)
+endif()
+set(GLOB_TEMP_VAR)
+
+file(GLOB GLOB_TEMP_VAR /usr/local/Trolltech/Qt-4*/bin/qmake)
+if(GLOB_TEMP_VAR)
+ set(QT4_INSTALLED TRUE)
+endif()
+set(GLOB_TEMP_VAR)
+
+file(GLOB GLOB_TEMP_VAR /usr/local/lib/qt4/bin/qmake)
+if(GLOB_TEMP_VAR)
+ set(QT4_INSTALLED TRUE)
+endif()
+set(GLOB_TEMP_VAR)
+
+if (Qt_FIND_VERSION)
+ if (Qt_FIND_VERSION MATCHES "^([34])(\\.[0-9]+.*)?$")
+ set(DESIRED_QT_VERSION ${CMAKE_MATCH_1})
+ else ()
+ message(FATAL_ERROR "FindQt was called with invalid version '${Qt_FIND_VERSION}'. Only Qt major versions 3 or 4 are supported. If you do not need to support both Qt3 and Qt4 in your source consider calling find_package(Qt3) or find_package(Qt4) instead of find_package(Qt) instead.")
+ endif ()
+endif ()
+
+# now find qmake
+find_program(QT_QMAKE_EXECUTABLE_FINDQT NAMES qmake PATHS "${QT_SEARCH_PATH}/bin" "$ENV{QTDIR}/bin")
+if(QT_QMAKE_EXECUTABLE_FINDQT)
+ exec_program(${QT_QMAKE_EXECUTABLE_FINDQT} ARGS "-query QT_VERSION"
+ OUTPUT_VARIABLE QTVERSION)
+ if(QTVERSION MATCHES "4")
+ set(QT_QMAKE_EXECUTABLE ${QT_QMAKE_EXECUTABLE_FINDQT} CACHE PATH "Qt4 qmake program.")
+ set(QT4_INSTALLED TRUE)
+ endif()
+ if(QTVERSION MATCHES "Unknown")
+ set(QT3_INSTALLED TRUE)
+ endif()
+endif()
+
+if(QT_QMAKE_EXECUTABLE_FINDQT)
+ exec_program( ${QT_QMAKE_EXECUTABLE_FINDQT}
+ ARGS "-query QT_INSTALL_HEADERS"
+ OUTPUT_VARIABLE qt_headers )
+endif()
+
+find_file( QT4_QGLOBAL_H_FILE qglobal.h
+ "${QT_SEARCH_PATH}/Qt/include"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\4.0.0;InstallDir]/include/Qt"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Versions\\4.0.0;InstallDir]/include/Qt"
+ ${qt_headers}/Qt
+ $ENV{QTDIR}/include/Qt
+ /usr/lib/qt/include/Qt
+ /usr/share/qt4/include/Qt
+ /usr/local/include/X11/qt4/Qt
+ C:/Progra~1/qt/include/Qt
+ PATH_SUFFIXES qt/include/Qt include/Qt)
+
+if(QT4_QGLOBAL_H_FILE)
+ set(QT4_INSTALLED TRUE)
+endif()
+
+find_file( QT3_QGLOBAL_H_FILE qglobal.h
+ "${QT_SEARCH_PATH}/Qt/include"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.1;InstallDir]/include/Qt"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.0;InstallDir]/include/Qt"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.1.0;InstallDir]/include/Qt"
+ C:/Qt/3.3.3Educational/include
+ $ENV{QTDIR}/include
+ /usr/include/qt3/Qt
+ /usr/share/qt3/include
+ /usr/local/include/X11/qt3
+ C:/Progra~1/qt/include
+ PATH_SUFFIXES qt/include include/qt3)
+
+if(QT3_QGLOBAL_H_FILE)
+ set(QT3_INSTALLED TRUE)
+endif()
+
+if(QT3_INSTALLED AND QT4_INSTALLED AND NOT DESIRED_QT_VERSION)
+ # force user to pick if we have both
+ set(DESIRED_QT_VERSION 0 CACHE STRING "Pick a version of Qt to use: 3 or 4")
+else()
+ # if only one found then pick that one
+ if(QT3_INSTALLED AND NOT DESIRED_QT_VERSION EQUAL 4)
+ set(DESIRED_QT_VERSION 3 CACHE STRING "Pick a version of Qt to use: 3 or 4")
+ endif()
+ if(QT4_INSTALLED AND NOT DESIRED_QT_VERSION EQUAL 3)
+ set(DESIRED_QT_VERSION 4 CACHE STRING "Pick a version of Qt to use: 3 or 4")
+ endif()
+endif()
+
+if(DESIRED_QT_VERSION EQUAL 3)
+ set(Qt3_FIND_REQUIRED ${Qt_FIND_REQUIRED})
+ set(Qt3_FIND_QUIETLY ${Qt_FIND_QUIETLY})
+ include(${CMAKE_CURRENT_LIST_DIR}/FindQt3.cmake)
+endif()
+if(DESIRED_QT_VERSION EQUAL 4)
+ set(Qt4_FIND_REQUIRED ${Qt_FIND_REQUIRED})
+ set(Qt4_FIND_QUIETLY ${Qt_FIND_QUIETLY})
+ include(${CMAKE_CURRENT_LIST_DIR}/FindQt4.cmake)
+endif()
+
+if(NOT QT3_INSTALLED AND NOT QT4_INSTALLED)
+ if(QT_REQUIRED)
+ message(SEND_ERROR "CMake was unable to find any Qt versions, put qmake in your path, or set QT_QMAKE_EXECUTABLE.")
+ endif()
+else()
+ if(NOT QT_FOUND AND NOT DESIRED_QT_VERSION)
+ if(QT_REQUIRED)
+ message(SEND_ERROR "Multiple versions of Qt found please set DESIRED_QT_VERSION")
+ else()
+ message("Multiple versions of Qt found please set DESIRED_QT_VERSION")
+ endif()
+ endif()
+ if(NOT QT_FOUND AND DESIRED_QT_VERSION)
+ if(QT_REQUIRED)
+ message(FATAL_ERROR "CMake was unable to find Qt version: ${DESIRED_QT_VERSION}. Set advanced values QT_QMAKE_EXECUTABLE and QT${DESIRED_QT_VERSION}_QGLOBAL_H_FILE, if those are set then QT_QT_LIBRARY or QT_LIBRARY_DIR.")
+ else()
+ message( "CMake was unable to find desired Qt version: ${DESIRED_QT_VERSION}. Set advanced values QT_QMAKE_EXECUTABLE and QT${DESIRED_QT_VERSION}_QGLOBAL_H_FILE.")
+ endif()
+ endif()
+endif()
+mark_as_advanced(QT3_QGLOBAL_H_FILE QT4_QGLOBAL_H_FILE QT_QMAKE_EXECUTABLE_FINDQT)
diff --git a/Modules/FindQt3.cmake b/Modules/FindQt3.cmake
new file mode 100644
index 0000000..da82e59
--- /dev/null
+++ b/Modules/FindQt3.cmake
@@ -0,0 +1,306 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindQt3
+-------
+
+Locate Qt include paths and libraries
+
+This module defines:
+
+::
+
+ QT_INCLUDE_DIR - where to find qt.h, etc.
+ QT_LIBRARIES - the libraries to link against to use Qt.
+ QT_DEFINITIONS - definitions to use when
+ compiling code that uses Qt.
+ QT_FOUND - If false, don't try to use Qt.
+ QT_VERSION_STRING - the version of Qt found
+
+
+
+If you need the multithreaded version of Qt, set QT_MT_REQUIRED to
+TRUE
+
+Also defined, but not for general use are:
+
+::
+
+ QT_MOC_EXECUTABLE, where to find the moc tool.
+ QT_UIC_EXECUTABLE, where to find the uic tool.
+ QT_QT_LIBRARY, where to find the Qt library.
+ QT_QTMAIN_LIBRARY, where to find the qtmain
+ library. This is only required by Qt3 on Windows.
+#]=======================================================================]
+
+# These are around for backwards compatibility
+# they will be set
+# QT_WRAP_CPP, set true if QT_MOC_EXECUTABLE is found
+# QT_WRAP_UI set true if QT_UIC_EXECUTABLE is found
+
+# If Qt4 has already been found, fail.
+if(QT4_FOUND)
+ if(Qt3_FIND_REQUIRED)
+ message( FATAL_ERROR "Qt3 and Qt4 cannot be used together in one project.")
+ else()
+ if(NOT Qt3_FIND_QUIETLY)
+ message( STATUS "Qt3 and Qt4 cannot be used together in one project.")
+ endif()
+ return()
+ endif()
+endif()
+
+
+file(GLOB GLOB_PATHS /usr/lib/qt-3*)
+foreach(GLOB_PATH ${GLOB_PATHS})
+ list(APPEND GLOB_PATHS_BIN "${GLOB_PATH}/bin")
+endforeach()
+find_path(QT_INCLUDE_DIR
+ NAMES qt.h
+ PATHS
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.1;InstallDir]/include/Qt"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.0;InstallDir]/include/Qt"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.1.0;InstallDir]/include/Qt"
+ $ENV{QTDIR}/include
+ ${GLOB_PATHS}
+ /usr/share/qt3/include
+ C:/Progra~1/qt/include
+ /usr/local/include/X11/qt3
+ PATH_SUFFIXES lib/qt/include lib/qt3/include include/qt include/qt3 qt/include qt3/include
+ )
+
+# if qglobal.h is not in the qt_include_dir then set
+# QT_INCLUDE_DIR to NOTFOUND
+if(NOT EXISTS ${QT_INCLUDE_DIR}/qglobal.h)
+ set(QT_INCLUDE_DIR QT_INCLUDE_DIR-NOTFOUND CACHE PATH "path to Qt3 include directory" FORCE)
+endif()
+
+if(QT_INCLUDE_DIR)
+ #extract the version string from qglobal.h
+ file(STRINGS ${QT_INCLUDE_DIR}/qglobal.h QGLOBAL_H REGEX "#define[\t ]+QT_VERSION_STR[\t ]+\"[0-9]+.[0-9]+.[0-9]+[a-z]*\"")
+ string(REGEX REPLACE ".*\"([0-9]+.[0-9]+.[0-9]+[a-z]*)\".*" "\\1" qt_version_str "${QGLOBAL_H}")
+ unset(QGLOBAL_H)
+
+ # Under windows the qt library (MSVC) has the format qt-mtXYZ where XYZ is the
+ # version X.Y.Z, so we need to remove the dots from version
+ string(REGEX REPLACE "\\." "" qt_version_str_lib "${qt_version_str}")
+ set(QT_VERSION_STRING "${qt_version_str}")
+endif()
+
+file(GLOB GLOB_PATHS_LIB /usr/lib/qt-3*/lib/)
+if (QT_MT_REQUIRED)
+ find_library(QT_QT_LIBRARY
+ NAMES
+ qt-mt qt-mt${qt_version_str_lib} qt-mtnc${qt_version_str_lib}
+ qt-mtedu${qt_version_str_lib} qt-mt230nc qt-mtnc321 qt-mt3
+ PATHS
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.1;InstallDir]"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.0;InstallDir]"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.1.0;InstallDir]"
+ ENV QTDIR
+ ${GLOB_PATHS_LIB}
+ /usr/share/qt3
+ C:/Progra~1/qt
+ PATH_SUFFIXES
+ lib lib/qt lib/qt3 qt qt3 qt/lib qt3/lib
+ )
+
+else ()
+ find_library(QT_QT_LIBRARY
+ NAMES
+ qt qt-${qt_version_str_lib} qt-edu${qt_version_str_lib}
+ qt-mt qt-mt${qt_version_str_lib} qt-mtnc${qt_version_str_lib}
+ qt-mtedu${qt_version_str_lib} qt-mt230nc qt-mtnc321 qt-mt3
+ PATHS
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.1;InstallDir]"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.0;InstallDir]"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.1.0;InstallDir]"
+ ENV QTDIR
+ ${GLOB_PATHS_LIB}
+ /usr/share/qt3
+ C:/Progra~1/qt/lib
+ PATH_SUFFIXES
+ lib lib/qt lib/qt3 qt qt3 qt/lib qt3/lib
+ )
+endif ()
+
+
+find_library(QT_QASSISTANTCLIENT_LIBRARY
+ NAMES qassistantclient
+ PATHS
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.1;InstallDir]"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.0;InstallDir]"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.1.0;InstallDir]"
+ ENV QTDIR
+ ${GLOB_PATHS_LIB}
+ /usr/share/qt3
+ C:/Progra~1/qt
+ PATH_SUFFIXES
+ lib lib/qt lib/qt3 qt qt3 qt/lib qt3/lib
+ )
+
+# Qt 3 should prefer QTDIR over the PATH
+find_program(QT_MOC_EXECUTABLE
+ NAMES moc-qt3 moc3 moc3-mt moc
+ HINTS
+ ENV QTDIR
+ PATHS
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.1;InstallDir]/include/Qt"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.0;InstallDir]/include/Qt"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.1.0;InstallDir]/include/Qt"
+ ${GLOB_PATHS_BIN}
+ /usr/share/qt3
+ C:/Progra~1/qt
+ PATH_SUFFIXES
+ bin lib/qt lib/qt3 qt qt3 qt/bin qt3/bin lib/qt/bin lib/qt3/bin
+ )
+
+if(QT_MOC_EXECUTABLE)
+ set ( QT_WRAP_CPP "YES")
+endif()
+
+# Qt 3 should prefer QTDIR over the PATH
+find_program(QT_UIC_EXECUTABLE
+ NAMES uic-qt3 uic3 uic3-mt uic
+ HINTS
+ ENV QTDIR
+ PATHS
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.1;InstallDir]/include/Qt"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.0;InstallDir]/include/Qt"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.1.0;InstallDir]/include/Qt"
+ ${GLOB_PATHS_BIN}
+ /usr/share/qt3
+ C:/Progra~1/qt
+ PATH_SUFFIXES
+ bin lib/qt lib/qt3 qt qt3 qt/bin qt3/bin lib/qt/bin lib/qt3/bin
+ )
+
+if(QT_UIC_EXECUTABLE)
+ set ( QT_WRAP_UI "YES")
+endif()
+
+if (WIN32)
+ find_library(QT_QTMAIN_LIBRARY
+ NAMES qtmain
+ HINTS
+ ENV QTDIR
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.1;InstallDir]"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.0;InstallDir]"
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.1.0;InstallDir]"
+ PATHS
+ "$ENV{ProgramFiles}/qt"
+ "C:/Program Files/qt"
+ PATH_SUFFIXES
+ lib
+ DOC "This Library is only needed by and included with Qt3 on MSWindows. It should be NOTFOUND, undefined or IGNORE otherwise."
+ )
+endif ()
+
+#support old QT_MIN_VERSION if set, but not if version is supplied by find_package()
+if(NOT Qt3_FIND_VERSION AND QT_MIN_VERSION)
+ set(Qt3_FIND_VERSION ${QT_MIN_VERSION})
+endif()
+
+# if the include a library are found then we have it
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+if (CMAKE_FIND_PACKAGE_NAME STREQUAL "Qt")
+ # FindQt include()'s this module. It's an old pattern, but rather than trying
+ # to suppress this from outside the module (which is then sensitive to the
+ # contents, detect the case in this module and suppress it explicitly.
+ set(FPHSA_NAME_MISMATCHED 1)
+endif ()
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Qt3
+ REQUIRED_VARS QT_QT_LIBRARY QT_INCLUDE_DIR QT_MOC_EXECUTABLE
+ VERSION_VAR QT_VERSION_STRING)
+unset(FPHSA_NAME_MISMATCHED)
+set(QT_FOUND ${QT3_FOUND} )
+
+if(QT_FOUND)
+ set( QT_LIBRARIES ${QT_LIBRARIES} ${QT_QT_LIBRARY} )
+ set( QT_DEFINITIONS "")
+
+ if (WIN32 AND NOT CYGWIN)
+ if (QT_QTMAIN_LIBRARY)
+ # for version 3
+ set (QT_DEFINITIONS -DQT_DLL -DQT_THREAD_SUPPORT -DNO_DEBUG)
+ set (QT_LIBRARIES imm32.lib ${QT_QT_LIBRARY} ${QT_QTMAIN_LIBRARY} )
+ set (QT_LIBRARIES ${QT_LIBRARIES} winmm wsock32)
+ else ()
+ # for version 2
+ set (QT_LIBRARIES imm32.lib ws2_32.lib ${QT_QT_LIBRARY} )
+ endif ()
+ else ()
+ set (QT_LIBRARIES ${QT_QT_LIBRARY} )
+
+ set (QT_DEFINITIONS -DQT_SHARED -DQT_NO_DEBUG)
+ if(QT_QT_LIBRARY MATCHES "qt-mt")
+ set (QT_DEFINITIONS ${QT_DEFINITIONS} -DQT_THREAD_SUPPORT -D_REENTRANT)
+ endif()
+
+ endif ()
+
+ if (QT_QASSISTANTCLIENT_LIBRARY)
+ set (QT_LIBRARIES ${QT_QASSISTANTCLIENT_LIBRARY} ${QT_LIBRARIES})
+ endif ()
+
+ # Backwards compatibility for CMake1.4 and 1.2
+ set (QT_MOC_EXE ${QT_MOC_EXECUTABLE} )
+ set (QT_UIC_EXE ${QT_UIC_EXECUTABLE} )
+ # for unix add X11 stuff
+ if(UNIX)
+ find_package(X11)
+ if (X11_FOUND)
+ set (QT_LIBRARIES ${QT_LIBRARIES} ${X11_LIBRARIES})
+ endif ()
+ if (CMAKE_DL_LIBS)
+ set (QT_LIBRARIES ${QT_LIBRARIES} ${CMAKE_DL_LIBS})
+ endif ()
+ endif()
+ if(QT_QT_LIBRARY MATCHES "qt-mt")
+ find_package(Threads)
+ set(QT_LIBRARIES ${QT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
+ endif()
+endif()
+
+if(QT_MOC_EXECUTABLE)
+ execute_process(COMMAND ${QT_MOC_EXECUTABLE} "-v"
+ OUTPUT_VARIABLE QTVERSION_MOC
+ ERROR_QUIET)
+endif()
+if(QT_UIC_EXECUTABLE)
+ execute_process(COMMAND ${QT_UIC_EXECUTABLE} "-version"
+ OUTPUT_VARIABLE QTVERSION_UIC
+ ERROR_QUIET)
+endif()
+
+set(_QT_UIC_VERSION_3 FALSE)
+if("${QTVERSION_UIC}" MATCHES " 3.")
+ set(_QT_UIC_VERSION_3 TRUE)
+endif()
+
+set(_QT_MOC_VERSION_3 FALSE)
+if("${QTVERSION_MOC}" MATCHES " 3.")
+ set(_QT_MOC_VERSION_3 TRUE)
+endif()
+
+set(QT_WRAP_CPP FALSE)
+if (QT_MOC_EXECUTABLE AND _QT_MOC_VERSION_3)
+ set ( QT_WRAP_CPP TRUE)
+endif ()
+
+set(QT_WRAP_UI FALSE)
+if (QT_UIC_EXECUTABLE AND _QT_UIC_VERSION_3)
+ set ( QT_WRAP_UI TRUE)
+endif ()
+
+mark_as_advanced(
+ QT_INCLUDE_DIR
+ QT_QT_LIBRARY
+ QT_QTMAIN_LIBRARY
+ QT_QASSISTANTCLIENT_LIBRARY
+ QT_UIC_EXECUTABLE
+ QT_MOC_EXECUTABLE
+ QT_WRAP_CPP
+ QT_WRAP_UI
+ )
diff --git a/Modules/FindQt4.cmake b/Modules/FindQt4.cmake
new file mode 100644
index 0000000..ec0f453
--- /dev/null
+++ b/Modules/FindQt4.cmake
@@ -0,0 +1,1346 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindQt4
+-------
+
+Finding and Using Qt4
+^^^^^^^^^^^^^^^^^^^^^
+
+This module can be used to find Qt4. The most important issue is that
+the Qt4 qmake is available via the system path. This qmake is then
+used to detect basically everything else. This module defines a
+number of :prop_tgt:`IMPORTED` targets, macros and variables.
+
+Typical usage could be something like:
+
+.. code-block:: cmake
+
+ set(CMAKE_AUTOMOC ON)
+ set(CMAKE_INCLUDE_CURRENT_DIR ON)
+ find_package(Qt4 4.4.3 REQUIRED QtGui QtXml)
+ add_executable(myexe main.cpp)
+ target_link_libraries(myexe Qt4::QtGui Qt4::QtXml)
+
+.. note::
+
+ When using :prop_tgt:`IMPORTED` targets, the qtmain.lib static library is
+ automatically linked on Windows for :prop_tgt:`WIN32 <WIN32_EXECUTABLE>`
+ executables. To disable that globally, set the
+ ``QT4_NO_LINK_QTMAIN`` variable before finding Qt4. To disable that
+ for a particular executable, set the ``QT4_NO_LINK_QTMAIN`` target
+ property to ``TRUE`` on the executable.
+
+Qt Build Tools
+^^^^^^^^^^^^^^
+
+Qt relies on some bundled tools for code generation, such as ``moc`` for
+meta-object code generation,``uic`` for widget layout and population,
+and ``rcc`` for virtual filesystem content generation. These tools may be
+automatically invoked by :manual:`cmake(1)` if the appropriate conditions
+are met. See :manual:`cmake-qt(7)` for more.
+
+Qt Macros
+^^^^^^^^^
+
+In some cases it can be necessary or useful to invoke the Qt build tools in a
+more-manual way. Several macros are available to add targets for such uses.
+
+::
+
+ macro QT4_WRAP_CPP(outfiles inputfile ... [TARGET tgt] OPTIONS ...)
+ create moc code from a list of files containing Qt class with
+ the Q_OBJECT declaration. Per-directory preprocessor definitions
+ are also added. If the <tgt> is specified, the
+ INTERFACE_INCLUDE_DIRECTORIES and INTERFACE_COMPILE_DEFINITIONS from
+ the <tgt> are passed to moc. Options may be given to moc, such as
+ those found when executing "moc -help".
+
+
+::
+
+ macro QT4_WRAP_UI(outfiles inputfile ... OPTIONS ...)
+ create code from a list of Qt designer ui files.
+ Options may be given to uic, such as those found
+ when executing "uic -help"
+
+
+::
+
+ macro QT4_ADD_RESOURCES(outfiles inputfile ... OPTIONS ...)
+ create code from a list of Qt resource files.
+ Options may be given to rcc, such as those found
+ when executing "rcc -help"
+
+
+::
+
+ macro QT4_GENERATE_MOC(inputfile outputfile [TARGET tgt])
+ creates a rule to run moc on infile and create outfile.
+ Use this if for some reason QT4_WRAP_CPP() isn't appropriate, e.g.
+ because you need a custom filename for the moc file or something
+ similar. If the <tgt> is specified, the
+ INTERFACE_INCLUDE_DIRECTORIES and INTERFACE_COMPILE_DEFINITIONS from
+ the <tgt> are passed to moc.
+
+
+::
+
+ macro QT4_ADD_DBUS_INTERFACE(outfiles interface basename)
+ Create the interface header and implementation files with the
+ given basename from the given interface xml file and add it to
+ the list of sources.
+
+ You can pass additional parameters to the qdbusxml2cpp call by setting
+ properties on the input file:
+
+ INCLUDE the given file will be included in the generate interface header
+
+ CLASSNAME the generated class is named accordingly
+
+ NO_NAMESPACE the generated class is not wrapped in a namespace
+
+
+::
+
+ macro QT4_ADD_DBUS_INTERFACES(outfiles inputfile ... )
+ Create the interface header and implementation files
+ for all listed interface xml files.
+ The basename will be automatically determined from the name
+ of the xml file.
+
+ The source file properties described for
+ QT4_ADD_DBUS_INTERFACE also apply here.
+
+
+::
+
+ macro QT4_ADD_DBUS_ADAPTOR(outfiles xmlfile parentheader parentclassname
+ [basename] [classname])
+ create a dbus adaptor (header and implementation file) from the xml file
+ describing the interface, and add it to the list of sources. The adaptor
+ forwards the calls to a parent class, defined in parentheader and named
+ parentclassname. The name of the generated files will be
+ <basename>adaptor.{cpp,h} where basename defaults to the basename of the
+ xml file.
+ If <classname> is provided, then it will be used as the classname of the
+ adaptor itself.
+
+
+::
+
+ macro QT4_GENERATE_DBUS_INTERFACE( header [interfacename] OPTIONS ...)
+ generate the xml interface file from the given header.
+ If the optional argument interfacename is omitted, the name of the
+ interface file is constructed from the basename of the header with
+ the suffix .xml appended.
+ Options may be given to qdbuscpp2xml, such as those found when
+ executing "qdbuscpp2xml --help"
+
+
+::
+
+ macro QT4_CREATE_TRANSLATION( qm_files directories ... sources ...
+ ts_files ... OPTIONS ...)
+ out: qm_files
+ in: directories sources ts_files
+ options: flags to pass to lupdate, such as -extensions to specify
+ extensions for a directory scan.
+ generates commands to create .ts (via lupdate) and .qm
+ (via lrelease) - files from directories and/or sources. The ts files are
+ created and/or updated in the source tree (unless given with full paths).
+ The qm files are generated in the build tree.
+ Updating the translations can be done by adding the qm_files
+ to the source list of your library/executable, so they are
+ always updated, or by adding a custom target to control when
+ they get updated/generated.
+
+
+::
+
+ macro QT4_ADD_TRANSLATION( qm_files ts_files ... )
+ out: qm_files
+ in: ts_files
+ generates commands to create .qm from .ts - files. The generated
+ filenames can be found in qm_files. The ts_files
+ must exist and are not updated in any way.
+
+
+::
+
+ macro QT4_AUTOMOC(sourcefile1 sourcefile2 ... [TARGET tgt])
+ The qt4_automoc macro is obsolete. Use the CMAKE_AUTOMOC feature instead.
+ This macro is still experimental.
+ It can be used to have moc automatically handled.
+ So if you have the files foo.h and foo.cpp, and in foo.h a
+ a class uses the Q_OBJECT macro, moc has to run on it. If you don't
+ want to use QT4_WRAP_CPP() (which is reliable and mature), you can insert
+ #include "foo.moc"
+ in foo.cpp and then give foo.cpp as argument to QT4_AUTOMOC(). This will
+ scan all listed files at cmake-time for such included moc files and if it
+ finds them cause a rule to be generated to run moc at build time on the
+ accompanying header file foo.h.
+ If a source file has the SKIP_AUTOMOC property set it will be ignored by
+ this macro.
+ If the <tgt> is specified, the INTERFACE_INCLUDE_DIRECTORIES and
+ INTERFACE_COMPILE_DEFINITIONS from the <tgt> are passed to moc.
+
+
+::
+
+ function QT4_USE_MODULES( target [link_type] modules...)
+ This function is obsolete. Use target_link_libraries with IMPORTED targets
+ instead.
+ Make <target> use the <modules> from Qt. Using a Qt module means
+ to link to the library, add the relevant include directories for the
+ module, and add the relevant compiler defines for using the module.
+ Modules are roughly equivalent to components of Qt4, so usage would be
+ something like:
+ qt4_use_modules(myexe Core Gui Declarative)
+ to use QtCore, QtGui and QtDeclarative. The optional <link_type> argument
+ can be specified as either LINK_PUBLIC or LINK_PRIVATE to specify the
+ same argument to the target_link_libraries call.
+
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+A particular Qt library may be used by using the corresponding
+:prop_tgt:`IMPORTED` target with the :command:`target_link_libraries`
+command:
+
+.. code-block:: cmake
+
+ target_link_libraries(myexe Qt4::QtGui Qt4::QtXml)
+
+Using a target in this way causes :cmake(1)` to use the appropriate include
+directories and compile definitions for the target when compiling ``myexe``.
+
+Targets are aware of their dependencies, so for example it is not necessary
+to list ``Qt4::QtCore`` if another Qt library is listed, and it is not
+necessary to list ``Qt4::QtGui`` if ``Qt4::QtDeclarative`` is listed.
+Targets may be tested for existence in the usual way with the
+:command:`if(TARGET)` command.
+
+The Qt toolkit may contain both debug and release libraries.
+:manual:`cmake(1)` will choose the appropriate version based on the build
+configuration.
+
+``Qt4::QtCore``
+ The QtCore target
+``Qt4::QtGui``
+ The QtGui target
+``Qt4::Qt3Support``
+ The Qt3Support target
+``Qt4::QtAssistant``
+ The QtAssistant target
+``Qt4::QtAssistantClient``
+ The QtAssistantClient target
+``Qt4::QAxContainer``
+ The QAxContainer target (Windows only)
+``Qt4::QAxServer``
+ The QAxServer target (Windows only)
+``Qt4::QtDBus``
+ The QtDBus target
+``Qt4::QtDeclarative``
+ The QtDeclarative target
+``Qt4::QtDesigner``
+ The QtDesigner target
+``Qt4::QtDesignerComponents``
+ The QtDesignerComponents target
+``Qt4::QtHelp``
+ The QtHelp target
+``Qt4::QtMotif``
+ The QtMotif target
+``Qt4::QtMultimedia``
+ The QtMultimedia target
+``Qt4::QtNetwork``
+ The QtNetwork target
+``Qt4::QtNsPLugin``
+ The QtNsPLugin target
+``Qt4::QtOpenGL``
+ The QtOpenGL target
+``Qt4::QtScript``
+ The QtScript target
+``Qt4::QtScriptTools``
+ The QtScriptTools target
+``Qt4::QtSql``
+ The QtSql target
+``Qt4::QtSvg``
+ The QtSvg target
+``Qt4::QtTest``
+ The QtTest target
+``Qt4::QtUiTools``
+ The QtUiTools target
+``Qt4::QtWebKit``
+ The QtWebKit target
+``Qt4::QtXml``
+ The QtXml target
+``Qt4::QtXmlPatterns``
+ The QtXmlPatterns target
+``Qt4::phonon``
+ The phonon target
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+ Below is a detailed list of variables that FindQt4.cmake sets.
+
+``Qt4_FOUND``
+ If false, don't try to use Qt 4.
+``QT_FOUND``
+ If false, don't try to use Qt. This variable is for compatibility only.
+``QT4_FOUND``
+ If false, don't try to use Qt 4. This variable is for compatibility only.
+``QT_VERSION_MAJOR``
+ The major version of Qt found.
+``QT_VERSION_MINOR``
+ The minor version of Qt found.
+``QT_VERSION_PATCH``
+ The patch version of Qt found.
+#]=======================================================================]
+
+# Use find_package( Qt4 COMPONENTS ... ) to enable modules
+if( Qt4_FIND_COMPONENTS )
+ foreach( component ${Qt4_FIND_COMPONENTS} )
+ string( TOUPPER ${component} _COMPONENT )
+ set( QT_USE_${_COMPONENT} 1 )
+ endforeach()
+
+ # To make sure we don't use QtCore or QtGui when not in COMPONENTS
+ if(NOT QT_USE_QTCORE)
+ set( QT_DONT_USE_QTCORE 1 )
+ endif()
+
+ if(NOT QT_USE_QTGUI)
+ set( QT_DONT_USE_QTGUI 1 )
+ endif()
+
+endif()
+
+# If Qt3 has already been found, fail.
+if(QT_QT_LIBRARY)
+ if(Qt4_FIND_REQUIRED)
+ message( FATAL_ERROR "Qt3 and Qt4 cannot be used together in one project. If switching to Qt4, the CMakeCache.txt needs to be cleaned.")
+ else()
+ if(NOT Qt4_FIND_QUIETLY)
+ message( STATUS "Qt3 and Qt4 cannot be used together in one project. If switching to Qt4, the CMakeCache.txt needs to be cleaned.")
+ endif()
+ return()
+ endif()
+endif()
+
+
+include(${CMAKE_CURRENT_LIST_DIR}/CheckCXXSymbolExists.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/MacroAddFileDependencies.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
+
+set(QT_USE_FILE ${CMAKE_ROOT}/Modules/UseQt4.cmake)
+
+set( QT_DEFINITIONS "")
+
+# convenience macro for dealing with debug/release library names
+macro (_QT4_ADJUST_LIB_VARS _camelCaseBasename)
+
+ string(TOUPPER "${_camelCaseBasename}" basename)
+
+ # The name of the imported targets, i.e. the prefix "Qt4::" must not change,
+ # since it is stored in EXPORT-files as name of a required library. If the name would change
+ # here, this would lead to the imported Qt4-library targets not being resolved by cmake anymore.
+ if (QT_${basename}_LIBRARY_RELEASE OR QT_${basename}_LIBRARY_DEBUG)
+
+ if(NOT TARGET Qt4::${_camelCaseBasename})
+ add_library(Qt4::${_camelCaseBasename} UNKNOWN IMPORTED )
+
+ if (QT_${basename}_LIBRARY_RELEASE)
+ set_property(TARGET Qt4::${_camelCaseBasename} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+ set(_location "${QT_${basename}_LIBRARY_RELEASE}")
+ if(QT_USE_FRAMEWORKS AND EXISTS ${_location}/${_camelCaseBasename})
+ set_property(TARGET Qt4::${_camelCaseBasename} PROPERTY IMPORTED_LOCATION_RELEASE "${_location}/${_camelCaseBasename}" )
+ else()
+ set_property(TARGET Qt4::${_camelCaseBasename} PROPERTY IMPORTED_LOCATION_RELEASE "${_location}" )
+ endif()
+ endif ()
+
+ if (QT_${basename}_LIBRARY_DEBUG)
+ set_property(TARGET Qt4::${_camelCaseBasename} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+ set(_location "${QT_${basename}_LIBRARY_DEBUG}")
+ if(QT_USE_FRAMEWORKS AND EXISTS ${_location}/${_camelCaseBasename})
+ set_property(TARGET Qt4::${_camelCaseBasename} PROPERTY IMPORTED_LOCATION_DEBUG "${_location}/${_camelCaseBasename}" )
+ else()
+ set_property(TARGET Qt4::${_camelCaseBasename} PROPERTY IMPORTED_LOCATION_DEBUG "${_location}" )
+ endif()
+ endif ()
+ set_property(TARGET Qt4::${_camelCaseBasename} PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES
+ "${QT_${basename}_INCLUDE_DIR}"
+ )
+ string(REGEX REPLACE "^QT" "" _stemname ${basename})
+ set_property(TARGET Qt4::${_camelCaseBasename} PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS
+ "QT_${_stemname}_LIB"
+ )
+ endif()
+
+ # If QT_USE_IMPORTED_TARGETS is enabled, the QT_QTFOO_LIBRARY variables are set to point at these
+ # imported targets. This works better in general, and is also in almost all cases fully
+ # backward compatible. The only issue is when a project A which had this enabled then exports its
+ # libraries via export or export_library_dependencies(). In this case the libraries from project
+ # A will depend on the imported Qt targets, and the names of these imported targets will be stored
+ # in the dependency files on disk. This means when a project B then uses project A, these imported
+ # targets must be created again, otherwise e.g. "Qt4__QtCore" will be interpreted as name of a
+ # library file on disk, and not as a target, and linking will fail:
+ if(QT_USE_IMPORTED_TARGETS)
+ set(QT_${basename}_LIBRARY Qt4::${_camelCaseBasename} )
+ set(QT_${basename}_LIBRARIES Qt4::${_camelCaseBasename} )
+ else()
+
+ # if the release- as well as the debug-version of the library have been found:
+ if (QT_${basename}_LIBRARY_DEBUG AND QT_${basename}_LIBRARY_RELEASE)
+ # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for
+ # single-config generators, set optimized and debug libraries
+ get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(_isMultiConfig OR CMAKE_BUILD_TYPE)
+ set(QT_${basename}_LIBRARY optimized ${QT_${basename}_LIBRARY_RELEASE} debug ${QT_${basename}_LIBRARY_DEBUG})
+ else()
+ # For single-config generators where CMAKE_BUILD_TYPE has no value,
+ # just use the release libraries
+ set(QT_${basename}_LIBRARY ${QT_${basename}_LIBRARY_RELEASE} )
+ endif()
+ set(QT_${basename}_LIBRARIES optimized ${QT_${basename}_LIBRARY_RELEASE} debug ${QT_${basename}_LIBRARY_DEBUG})
+ endif ()
+
+ # if only the release version was found, set the debug variable also to the release version
+ if (QT_${basename}_LIBRARY_RELEASE AND NOT QT_${basename}_LIBRARY_DEBUG)
+ set(QT_${basename}_LIBRARY_DEBUG ${QT_${basename}_LIBRARY_RELEASE})
+ set(QT_${basename}_LIBRARY ${QT_${basename}_LIBRARY_RELEASE})
+ set(QT_${basename}_LIBRARIES ${QT_${basename}_LIBRARY_RELEASE})
+ endif ()
+
+ # if only the debug version was found, set the release variable also to the debug version
+ if (QT_${basename}_LIBRARY_DEBUG AND NOT QT_${basename}_LIBRARY_RELEASE)
+ set(QT_${basename}_LIBRARY_RELEASE ${QT_${basename}_LIBRARY_DEBUG})
+ set(QT_${basename}_LIBRARY ${QT_${basename}_LIBRARY_DEBUG})
+ set(QT_${basename}_LIBRARIES ${QT_${basename}_LIBRARY_DEBUG})
+ endif ()
+
+ # put the value in the cache:
+ set(QT_${basename}_LIBRARY ${QT_${basename}_LIBRARY} CACHE STRING "The Qt ${basename} library" FORCE)
+
+ endif()
+
+ set(QT_${basename}_FOUND 1)
+
+ else ()
+
+ set(QT_${basename}_LIBRARY "" CACHE STRING "The Qt ${basename} library" FORCE)
+
+ endif ()
+
+ if (QT_${basename}_INCLUDE_DIR)
+ #add the include directory to QT_INCLUDES
+ set(QT_INCLUDES "${QT_${basename}_INCLUDE_DIR}" ${QT_INCLUDES})
+ endif ()
+
+ # Make variables changeable to the advanced user
+ mark_as_advanced(QT_${basename}_LIBRARY QT_${basename}_LIBRARY_RELEASE QT_${basename}_LIBRARY_DEBUG QT_${basename}_INCLUDE_DIR)
+endmacro ()
+
+function(_QT4_QUERY_QMAKE VAR RESULT)
+ execute_process(COMMAND "${QT_QMAKE_EXECUTABLE}" -query ${VAR}
+ RESULT_VARIABLE return_code
+ OUTPUT_VARIABLE output
+ OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE)
+ if(NOT return_code)
+ file(TO_CMAKE_PATH "${output}" output)
+ set(${RESULT} ${output} PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_QT4_GET_VERSION_COMPONENTS VERSION RESULT_MAJOR RESULT_MINOR RESULT_PATCH)
+ string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" QT_VERSION_MAJOR "${QTVERSION}")
+ string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" QT_VERSION_MINOR "${QTVERSION}")
+ string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" QT_VERSION_PATCH "${QTVERSION}")
+
+ set(${RESULT_MAJOR} ${QT_VERSION_MAJOR} PARENT_SCOPE)
+ set(${RESULT_MINOR} ${QT_VERSION_MINOR} PARENT_SCOPE)
+ set(${RESULT_PATCH} ${QT_VERSION_PATCH} PARENT_SCOPE)
+endfunction()
+
+function(_QT4_FIND_QMAKE QMAKE_NAMES QMAKE_RESULT VERSION_RESULT)
+ list(LENGTH QMAKE_NAMES QMAKE_NAMES_LEN)
+ if(${QMAKE_NAMES_LEN} EQUAL 0)
+ return()
+ endif()
+ list(GET QMAKE_NAMES 0 QMAKE_NAME)
+
+ get_filename_component(qt_install_version "[HKEY_CURRENT_USER\\Software\\trolltech\\Versions;DefaultQtVersion]" NAME)
+
+ find_program(QT_QMAKE_EXECUTABLE NAMES ${QMAKE_NAME}
+ PATHS
+ ENV QTDIR
+ "[HKEY_CURRENT_USER\\Software\\Trolltech\\Versions\\${qt_install_version};InstallDir]"
+ PATH_SUFFIXES bin
+ DOC "The qmake executable for the Qt installation to use"
+ )
+
+ set(major 0)
+ if (QT_QMAKE_EXECUTABLE)
+ _qt4_query_qmake(QT_VERSION QTVERSION)
+ _qt4_get_version_components("${QTVERSION}" major minor patch)
+ endif()
+
+ if (NOT QT_QMAKE_EXECUTABLE OR NOT "${major}" EQUAL 4)
+ set(curr_qmake "${QT_QMAKE_EXECUTABLE}")
+ set(curr_qt_version "${QTVERSION}")
+
+ set(QT_QMAKE_EXECUTABLE NOTFOUND CACHE FILEPATH "" FORCE)
+ list(REMOVE_AT QMAKE_NAMES 0)
+ _qt4_find_qmake("${QMAKE_NAMES}" QMAKE QTVERSION)
+
+ _qt4_get_version_components("${QTVERSION}" major minor patch)
+ if (NOT ${major} EQUAL 4)
+ # Restore possibly found qmake and it's version; these are used later
+ # in error message if incorrect version is found
+ set(QT_QMAKE_EXECUTABLE "${curr_qmake}" CACHE FILEPATH "" FORCE)
+ set(QTVERSION "${curr_qt_version}")
+ endif()
+
+ endif()
+
+
+ set(${QMAKE_RESULT} "${QT_QMAKE_EXECUTABLE}" PARENT_SCOPE)
+ set(${VERSION_RESULT} "${QTVERSION}" PARENT_SCOPE)
+endfunction()
+
+
+set(QT4_INSTALLED_VERSION_TOO_OLD FALSE)
+
+set(_QT4_QMAKE_NAMES qmake qmake4 qmake-qt4 qmake-mac)
+_qt4_find_qmake("${_QT4_QMAKE_NAMES}" QT_QMAKE_EXECUTABLE QTVERSION)
+
+if (QT_QMAKE_EXECUTABLE AND
+ QTVERSION VERSION_GREATER 3 AND QTVERSION VERSION_LESS 5)
+
+ if (Qt5Core_FOUND)
+ # Qt5CoreConfig sets QT_MOC_EXECUTABLE as a non-cache variable to the Qt 5
+ # path to moc. Unset that variable when Qt 4 and 5 are used together, so
+ # that when find_program looks for moc, it is not set to the Qt 5 version.
+ # If FindQt4 has already put the Qt 4 path in the cache, the unset()
+ # command 'unhides' the (correct) cache variable.
+ unset(QT_MOC_EXECUTABLE)
+ endif()
+ if (QT_QMAKE_EXECUTABLE_LAST)
+ string(COMPARE NOTEQUAL "${QT_QMAKE_EXECUTABLE_LAST}" "${QT_QMAKE_EXECUTABLE}" QT_QMAKE_CHANGED)
+ endif()
+ set(QT_QMAKE_EXECUTABLE_LAST "${QT_QMAKE_EXECUTABLE}" CACHE INTERNAL "" FORCE)
+
+ _qt4_get_version_components("${QTVERSION}" QT_VERSION_MAJOR QT_VERSION_MINOR QT_VERSION_PATCH)
+
+ # ask qmake for the mkspecs directory
+ # we do this first because QT_LIBINFIX might be set
+ if (NOT QT_MKSPECS_DIR OR QT_QMAKE_CHANGED)
+ _qt4_query_qmake(QMAKE_MKSPECS qt_mkspecs_dirs)
+ # do not replace : on windows as it might be a drive letter
+ # and windows should already use ; as a separator
+ if(NOT WIN32)
+ string(REPLACE ":" ";" qt_mkspecs_dirs "${qt_mkspecs_dirs}")
+ endif()
+
+ find_path(QT_MKSPECS_DIR NAMES qconfig.pri
+ HINTS ${qt_mkspecs_dirs}
+ PATH_SUFFIXES mkspecs share/qt4/mkspecs
+ DOC "The location of the Qt mkspecs containing qconfig.pri")
+ endif()
+
+ if(EXISTS "${QT_MKSPECS_DIR}/qconfig.pri")
+ file(READ ${QT_MKSPECS_DIR}/qconfig.pri _qconfig_FILE_contents)
+ string(REGEX MATCH "QT_CONFIG[^\n]+" QT_QCONFIG "${_qconfig_FILE_contents}")
+ string(REGEX MATCH "CONFIG[^\n]+" QT_CONFIG "${_qconfig_FILE_contents}")
+ string(REGEX MATCH "EDITION[^\n]+" QT_EDITION "${_qconfig_FILE_contents}")
+ string(REGEX MATCH "QT_LIBINFIX[^\n]+" _qconfig_qt_libinfix "${_qconfig_FILE_contents}")
+ string(REGEX REPLACE "QT_LIBINFIX *= *([^\n]*)" "\\1" QT_LIBINFIX "${_qconfig_qt_libinfix}")
+ endif()
+ if("${QT_EDITION}" MATCHES "DesktopLight")
+ set(QT_EDITION_DESKTOPLIGHT 1)
+ endif()
+
+ # ask qmake for the library dir as a hint, then search for QtCore library and use that as a reference for finding the
+ # others and for setting QT_LIBRARY_DIR
+ if (NOT (QT_QTCORE_LIBRARY_RELEASE OR QT_QTCORE_LIBRARY_DEBUG) OR QT_QMAKE_CHANGED)
+ _qt4_query_qmake(QT_INSTALL_LIBS QT_LIBRARY_DIR_TMP)
+ set(QT_QTCORE_LIBRARY_RELEASE NOTFOUND)
+ set(QT_QTCORE_LIBRARY_DEBUG NOTFOUND)
+ find_library(QT_QTCORE_LIBRARY_RELEASE
+ NAMES QtCore${QT_LIBINFIX} QtCore${QT_LIBINFIX}4
+ HINTS ${QT_LIBRARY_DIR_TMP}
+ NO_DEFAULT_PATH
+ )
+ find_library(QT_QTCORE_LIBRARY_DEBUG
+ NAMES QtCore${QT_LIBINFIX}_debug QtCore${QT_LIBINFIX}d QtCore${QT_LIBINFIX}d4
+ HINTS ${QT_LIBRARY_DIR_TMP}
+ NO_DEFAULT_PATH
+ )
+
+ if(NOT QT_QTCORE_LIBRARY_RELEASE AND NOT QT_QTCORE_LIBRARY_DEBUG)
+ find_library(QT_QTCORE_LIBRARY_RELEASE
+ NAMES QtCore${QT_LIBINFIX} QtCore${QT_LIBINFIX}4
+ HINTS ${QT_LIBRARY_DIR_TMP}
+ )
+ find_library(QT_QTCORE_LIBRARY_DEBUG
+ NAMES QtCore${QT_LIBINFIX}_debug QtCore${QT_LIBINFIX}d QtCore${QT_LIBINFIX}d4
+ HINTS ${QT_LIBRARY_DIR_TMP}
+ )
+ endif()
+
+ # try dropping a hint if trying to use Visual Studio with Qt built by MinGW
+ if(NOT QT_QTCORE_LIBRARY_RELEASE AND MSVC)
+ if(EXISTS ${QT_LIBRARY_DIR_TMP}/libqtmain.a)
+ message( FATAL_ERROR "It appears you're trying to use Visual Studio with Qt built by MinGW. Those compilers do not produce code compatible with each other.")
+ endif()
+ endif()
+
+ endif ()
+
+ # set QT_LIBRARY_DIR based on location of QtCore found.
+ if(QT_QTCORE_LIBRARY_RELEASE)
+ get_filename_component(QT_LIBRARY_DIR_TMP "${QT_QTCORE_LIBRARY_RELEASE}" PATH)
+ set(QT_LIBRARY_DIR ${QT_LIBRARY_DIR_TMP} CACHE INTERNAL "Qt library dir" FORCE)
+ set(QT_QTCORE_FOUND 1)
+ elseif(QT_QTCORE_LIBRARY_DEBUG)
+ get_filename_component(QT_LIBRARY_DIR_TMP "${QT_QTCORE_LIBRARY_DEBUG}" PATH)
+ set(QT_LIBRARY_DIR ${QT_LIBRARY_DIR_TMP} CACHE INTERNAL "Qt library dir" FORCE)
+ set(QT_QTCORE_FOUND 1)
+ else()
+ if(NOT Qt4_FIND_QUIETLY)
+ message(WARNING
+ "${QT_QMAKE_EXECUTABLE} reported QT_INSTALL_LIBS as "
+ "\"${QT_LIBRARY_DIR_TMP}\" "
+ "but QtCore could not be found there. "
+ "Qt is NOT installed correctly for the target build environment.")
+ endif()
+ set(Qt4_FOUND FALSE)
+ if(Qt4_FIND_REQUIRED)
+ message( FATAL_ERROR "Could NOT find QtCore. Check ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log for more details.")
+ else()
+ return()
+ endif()
+ endif()
+
+ # ask qmake for the binary dir
+ if (NOT QT_BINARY_DIR OR QT_QMAKE_CHANGED)
+ _qt4_query_qmake(QT_INSTALL_BINS qt_bins)
+ set(QT_BINARY_DIR ${qt_bins} CACHE INTERNAL "" FORCE)
+ endif ()
+
+ if (APPLE)
+ set(CMAKE_FIND_FRAMEWORK_OLD ${CMAKE_FIND_FRAMEWORK})
+ if (EXISTS ${QT_LIBRARY_DIR}/QtCore.framework)
+ set(QT_USE_FRAMEWORKS ON CACHE INTERNAL "" FORCE)
+ set(CMAKE_FIND_FRAMEWORK FIRST)
+ else ()
+ set(QT_USE_FRAMEWORKS OFF CACHE INTERNAL "" FORCE)
+ set(CMAKE_FIND_FRAMEWORK LAST)
+ endif ()
+ endif ()
+
+ # ask qmake for the include dir
+ if (QT_LIBRARY_DIR AND (NOT QT_QTCORE_INCLUDE_DIR OR NOT QT_HEADERS_DIR OR QT_QMAKE_CHANGED))
+ _qt4_query_qmake(QT_INSTALL_HEADERS qt_headers)
+ set(QT_QTCORE_INCLUDE_DIR NOTFOUND)
+ find_path(QT_QTCORE_INCLUDE_DIR QtCore
+ HINTS ${qt_headers} ${QT_LIBRARY_DIR}
+ PATH_SUFFIXES QtCore qt4/QtCore
+ NO_DEFAULT_PATH
+ )
+ if(NOT QT_QTCORE_INCLUDE_DIR)
+ find_path(QT_QTCORE_INCLUDE_DIR QtCore
+ HINTS ${qt_headers} ${QT_LIBRARY_DIR}
+ PATH_SUFFIXES QtCore qt4/QtCore
+ )
+ endif()
+
+ # Set QT_HEADERS_DIR based on finding QtCore header
+ if(QT_QTCORE_INCLUDE_DIR)
+ if(QT_USE_FRAMEWORKS)
+ set(QT_HEADERS_DIR "${qt_headers}" CACHE INTERNAL "" FORCE)
+ else()
+ get_filename_component(qt_headers "${QT_QTCORE_INCLUDE_DIR}/../" ABSOLUTE)
+ set(QT_HEADERS_DIR "${qt_headers}" CACHE INTERNAL "" FORCE)
+ endif()
+ else()
+ message("Warning: QT_QMAKE_EXECUTABLE reported QT_INSTALL_HEADERS as ${qt_headers}")
+ message("Warning: But QtCore couldn't be found. Qt must NOT be installed correctly.")
+ endif()
+ endif()
+
+ if(APPLE)
+ set(CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK_OLD})
+ endif()
+
+ # Set QT_INCLUDE_DIR based on QT_HEADERS_DIR
+ if(QT_HEADERS_DIR)
+ if(QT_USE_FRAMEWORKS)
+ # Qt/Mac frameworks has two include dirs.
+ # One is the framework include for which CMake will add a -F flag
+ # and the other is an include dir for non-framework Qt modules
+ set(QT_INCLUDE_DIR ${QT_HEADERS_DIR} ${QT_QTCORE_LIBRARY_RELEASE} )
+ else()
+ set(QT_INCLUDE_DIR ${QT_HEADERS_DIR})
+ endif()
+ endif()
+
+ # Set QT_INCLUDES
+ set( QT_INCLUDES ${QT_MKSPECS_DIR}/default ${QT_INCLUDE_DIR} ${QT_QTCORE_INCLUDE_DIR})
+
+
+ # ask qmake for the documentation directory
+ if (QT_LIBRARY_DIR AND NOT QT_DOC_DIR OR QT_QMAKE_CHANGED)
+ _qt4_query_qmake(QT_INSTALL_DOCS qt_doc_dir)
+ set(QT_DOC_DIR ${qt_doc_dir} CACHE PATH "The location of the Qt docs" FORCE)
+ endif ()
+
+
+ # ask qmake for the plugins directory
+ if (QT_LIBRARY_DIR AND NOT QT_PLUGINS_DIR OR QT_QMAKE_CHANGED)
+ _qt4_query_qmake(QT_INSTALL_PLUGINS qt_plugins_dir)
+ if(CMAKE_CROSSCOMPILING OR NOT qt_plugins_dir)
+ find_path(QT_PLUGINS_DIR
+ NAMES accessible bearer codecs designer graphicssystems iconengines imageformats inputmethods qmltooling script sqldrivers
+ HINTS ${qt_plugins_dir}
+ PATH_SUFFIXES plugins lib/qt4/plugins
+ DOC "The location of the Qt plugins")
+ else()
+ set(QT_PLUGINS_DIR ${qt_plugins_dir} CACHE PATH "The location of the Qt plugins")
+ endif()
+ endif ()
+
+ # ask qmake for the translations directory
+ if (QT_LIBRARY_DIR AND NOT QT_TRANSLATIONS_DIR OR QT_QMAKE_CHANGED)
+ _qt4_query_qmake(QT_INSTALL_TRANSLATIONS qt_translations_dir)
+ set(QT_TRANSLATIONS_DIR ${qt_translations_dir} CACHE PATH "The location of the Qt translations" FORCE)
+ endif ()
+
+ # ask qmake for the imports directory
+ if (QT_LIBRARY_DIR AND NOT QT_IMPORTS_DIR OR QT_QMAKE_CHANGED)
+ _qt4_query_qmake(QT_INSTALL_IMPORTS qt_imports_dir)
+ if(CMAKE_CROSSCOMPILING OR NOT qt_imports_dir)
+ find_path(QT_IMPORTS_DIR NAMES Qt
+ HINTS ${qt_imports_dir}
+ PATH_SUFFIXES imports lib/qt4/imports
+ DOC "The location of the Qt imports")
+ else()
+ set(QT_IMPORTS_DIR ${qt_imports_dir} CACHE PATH "The location of the Qt imports")
+ endif()
+ endif ()
+
+ # Make variables changeable to the advanced user
+ mark_as_advanced( QT_LIBRARY_DIR QT_DOC_DIR QT_MKSPECS_DIR
+ QT_PLUGINS_DIR QT_TRANSLATIONS_DIR)
+
+
+
+
+ #############################################
+ #
+ # Find out what window system we're using
+ #
+ #############################################
+ cmake_push_check_state()
+ # Add QT_INCLUDE_DIR to CMAKE_REQUIRED_INCLUDES
+ list(APPEND CMAKE_REQUIRED_INCLUDES "${QT_INCLUDE_DIR}")
+ set(CMAKE_REQUIRED_QUIET ${Qt4_FIND_QUIETLY})
+ # Check for Window system symbols (note: only one should end up being set)
+ CHECK_CXX_SYMBOL_EXISTS(Q_WS_X11 "QtCore/qglobal.h" Q_WS_X11)
+ CHECK_CXX_SYMBOL_EXISTS(Q_WS_WIN "QtCore/qglobal.h" Q_WS_WIN)
+ CHECK_CXX_SYMBOL_EXISTS(Q_WS_QWS "QtCore/qglobal.h" Q_WS_QWS)
+ CHECK_CXX_SYMBOL_EXISTS(Q_WS_MAC "QtCore/qglobal.h" Q_WS_MAC)
+ if(Q_WS_MAC)
+ if(QT_QMAKE_CHANGED)
+ unset(QT_MAC_USE_COCOA CACHE)
+ endif()
+ CHECK_CXX_SYMBOL_EXISTS(QT_MAC_USE_COCOA "QtCore/qconfig.h" QT_MAC_USE_COCOA)
+ endif()
+
+ if (QT_QTCOPY_REQUIRED)
+ CHECK_CXX_SYMBOL_EXISTS(QT_IS_QTCOPY "QtCore/qglobal.h" QT_KDE_QT_COPY)
+ if (NOT QT_IS_QTCOPY)
+ message(FATAL_ERROR "qt-copy is required, but hasn't been found")
+ endif ()
+ endif ()
+
+ cmake_pop_check_state()
+ #
+ #############################################
+
+
+
+ ########################################
+ #
+ # Setting the INCLUDE-Variables
+ #
+ ########################################
+
+ set(QT_MODULES QtGui Qt3Support QtSvg QtScript QtTest QtUiTools
+ QtHelp QtWebKit QtXmlPatterns phonon QtNetwork QtMultimedia
+ QtNsPlugin QtOpenGL QtSql QtXml QtDesigner QtDBus QtScriptTools
+ QtDeclarative)
+
+ if(Q_WS_X11)
+ set(QT_MODULES ${QT_MODULES} QtMotif)
+ endif()
+
+ if(QT_QMAKE_CHANGED)
+ foreach(QT_MODULE ${QT_MODULES})
+ string(TOUPPER ${QT_MODULE} _upper_qt_module)
+ set(QT_${_upper_qt_module}_INCLUDE_DIR NOTFOUND)
+ set(QT_${_upper_qt_module}_LIBRARY_RELEASE NOTFOUND)
+ set(QT_${_upper_qt_module}_LIBRARY_DEBUG NOTFOUND)
+ endforeach()
+ set(QT_QTDESIGNERCOMPONENTS_INCLUDE_DIR NOTFOUND)
+ set(QT_QTDESIGNERCOMPONENTS_LIBRARY_RELEASE NOTFOUND)
+ set(QT_QTDESIGNERCOMPONENTS_LIBRARY_DEBUG NOTFOUND)
+ set(QT_QTASSISTANTCLIENT_INCLUDE_DIR NOTFOUND)
+ set(QT_QTASSISTANTCLIENT_LIBRARY_RELEASE NOTFOUND)
+ set(QT_QTASSISTANTCLIENT_LIBRARY_DEBUG NOTFOUND)
+ set(QT_QTASSISTANT_INCLUDE_DIR NOTFOUND)
+ set(QT_QTASSISTANT_LIBRARY_RELEASE NOTFOUND)
+ set(QT_QTASSISTANT_LIBRARY_DEBUG NOTFOUND)
+ set(QT_QTCLUCENE_LIBRARY_RELEASE NOTFOUND)
+ set(QT_QTCLUCENE_LIBRARY_DEBUG NOTFOUND)
+ set(QT_QAXCONTAINER_INCLUDE_DIR NOTFOUND)
+ set(QT_QAXCONTAINER_LIBRARY_RELEASE NOTFOUND)
+ set(QT_QAXCONTAINER_LIBRARY_DEBUG NOTFOUND)
+ set(QT_QAXSERVER_INCLUDE_DIR NOTFOUND)
+ set(QT_QAXSERVER_LIBRARY_RELEASE NOTFOUND)
+ set(QT_QAXSERVER_LIBRARY_DEBUG NOTFOUND)
+ if(Q_WS_WIN)
+ set(QT_QTMAIN_LIBRARY_DEBUG NOTFOUND)
+ set(QT_QTMAIN_LIBRARY_RELEASE NOTFOUND)
+ endif()
+ endif()
+
+ foreach(QT_MODULE ${QT_MODULES})
+ string(TOUPPER ${QT_MODULE} _upper_qt_module)
+ find_path(QT_${_upper_qt_module}_INCLUDE_DIR ${QT_MODULE}
+ PATHS
+ ${QT_HEADERS_DIR}/${QT_MODULE}
+ ${QT_LIBRARY_DIR}/${QT_MODULE}.framework/Headers
+ NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+ )
+ # phonon doesn't seem consistent, let's try phonondefs.h for some
+ # installations
+ if(${QT_MODULE} STREQUAL "phonon")
+ find_path(QT_${_upper_qt_module}_INCLUDE_DIR phonondefs.h
+ PATHS
+ ${QT_HEADERS_DIR}/${QT_MODULE}
+ ${QT_LIBRARY_DIR}/${QT_MODULE}.framework/Headers
+ NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+ )
+ endif()
+ endforeach()
+
+ if(Q_WS_WIN)
+ set(QT_MODULES ${QT_MODULES} QAxContainer QAxServer)
+ # Set QT_AXCONTAINER_INCLUDE_DIR and QT_AXSERVER_INCLUDE_DIR
+ find_path(QT_QAXCONTAINER_INCLUDE_DIR ActiveQt
+ PATHS ${QT_HEADERS_DIR}/ActiveQt
+ NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+ )
+ find_path(QT_QAXSERVER_INCLUDE_DIR ActiveQt
+ PATHS ${QT_HEADERS_DIR}/ActiveQt
+ NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+ )
+ endif()
+
+ # Set QT_QTDESIGNERCOMPONENTS_INCLUDE_DIR
+ find_path(QT_QTDESIGNERCOMPONENTS_INCLUDE_DIR QDesignerComponents
+ PATHS
+ ${QT_HEADERS_DIR}/QtDesigner
+ ${QT_LIBRARY_DIR}/QtDesigner.framework/Headers
+ NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+ )
+
+ # Set QT_QTASSISTANT_INCLUDE_DIR
+ find_path(QT_QTASSISTANT_INCLUDE_DIR QtAssistant
+ PATHS
+ ${QT_HEADERS_DIR}/QtAssistant
+ ${QT_LIBRARY_DIR}/QtAssistant.framework/Headers
+ NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+ )
+
+ # Set QT_QTASSISTANTCLIENT_INCLUDE_DIR
+ find_path(QT_QTASSISTANTCLIENT_INCLUDE_DIR QAssistantClient
+ PATHS
+ ${QT_HEADERS_DIR}/QtAssistant
+ ${QT_LIBRARY_DIR}/QtAssistant.framework/Headers
+ NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+ )
+
+ ########################################
+ #
+ # Setting the LIBRARY-Variables
+ #
+ ########################################
+
+ # find the libraries
+ foreach(QT_MODULE ${QT_MODULES})
+ string(TOUPPER ${QT_MODULE} _upper_qt_module)
+ find_library(QT_${_upper_qt_module}_LIBRARY_RELEASE
+ NAMES ${QT_MODULE}${QT_LIBINFIX} ${QT_MODULE}${QT_LIBINFIX}4
+ PATHS ${QT_LIBRARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+ )
+ find_library(QT_${_upper_qt_module}_LIBRARY_DEBUG
+ NAMES ${QT_MODULE}${QT_LIBINFIX}_debug ${QT_MODULE}${QT_LIBINFIX}d ${QT_MODULE}${QT_LIBINFIX}d4
+ PATHS ${QT_LIBRARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+ )
+ if(QT_${_upper_qt_module}_LIBRARY_RELEASE MATCHES "/${QT_MODULE}\\.framework$")
+ if(NOT EXISTS "${QT_${_upper_qt_module}_LIBRARY_RELEASE}/${QT_MODULE}")
+ # Release framework library file does not exist... Force to NOTFOUND:
+ set(QT_${_upper_qt_module}_LIBRARY_RELEASE "QT_${_upper_qt_module}_LIBRARY_RELEASE-NOTFOUND" CACHE FILEPATH "Path to a library." FORCE)
+ endif()
+ endif()
+ if(QT_${_upper_qt_module}_LIBRARY_DEBUG MATCHES "/${QT_MODULE}\\.framework$")
+ if(NOT EXISTS "${QT_${_upper_qt_module}_LIBRARY_DEBUG}/${QT_MODULE}")
+ # Debug framework library file does not exist... Force to NOTFOUND:
+ set(QT_${_upper_qt_module}_LIBRARY_DEBUG "QT_${_upper_qt_module}_LIBRARY_DEBUG-NOTFOUND" CACHE FILEPATH "Path to a library." FORCE)
+ endif()
+ endif()
+ endforeach()
+
+ # QtUiTools is sometimes not in the same directory as the other found libraries
+ # e.g. on Mac, its never a framework like the others are
+ if(QT_QTCORE_LIBRARY_RELEASE AND NOT QT_QTUITOOLS_LIBRARY_RELEASE)
+ find_library(QT_QTUITOOLS_LIBRARY_RELEASE NAMES QtUiTools${QT_LIBINFIX} PATHS ${QT_LIBRARY_DIR})
+ endif()
+
+ # Set QT_QTDESIGNERCOMPONENTS_LIBRARY
+ find_library(QT_QTDESIGNERCOMPONENTS_LIBRARY_RELEASE NAMES QtDesignerComponents${QT_LIBINFIX} QtDesignerComponents${QT_LIBINFIX}4 PATHS ${QT_LIBRARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+ find_library(QT_QTDESIGNERCOMPONENTS_LIBRARY_DEBUG NAMES QtDesignerComponents${QT_LIBINFIX}_debug QtDesignerComponents${QT_LIBINFIX}d QtDesignerComponents${QT_LIBINFIX}d4 PATHS ${QT_LIBRARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+
+ # Set QT_QTMAIN_LIBRARY
+ if(Q_WS_WIN)
+ find_library(QT_QTMAIN_LIBRARY_RELEASE NAMES qtmain${QT_LIBINFIX} PATHS ${QT_LIBRARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+ find_library(QT_QTMAIN_LIBRARY_DEBUG NAMES qtmain${QT_LIBINFIX}d PATHS ${QT_LIBRARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+ endif()
+
+ # Set QT_QTASSISTANTCLIENT_LIBRARY
+ find_library(QT_QTASSISTANTCLIENT_LIBRARY_RELEASE NAMES QtAssistantClient${QT_LIBINFIX} QtAssistantClient${QT_LIBINFIX}4 PATHS ${QT_LIBRARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+ find_library(QT_QTASSISTANTCLIENT_LIBRARY_DEBUG NAMES QtAssistantClient${QT_LIBINFIX}_debug QtAssistantClient${QT_LIBINFIX}d QtAssistantClient${QT_LIBINFIX}d4 PATHS ${QT_LIBRARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+
+ # Set QT_QTASSISTANT_LIBRARY
+ find_library(QT_QTASSISTANT_LIBRARY_RELEASE NAMES QtAssistantClient${QT_LIBINFIX} QtAssistantClient${QT_LIBINFIX}4 QtAssistant${QT_LIBINFIX} QtAssistant${QT_LIBINFIX}4 PATHS ${QT_LIBRARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+ find_library(QT_QTASSISTANT_LIBRARY_DEBUG NAMES QtAssistantClient${QT_LIBINFIX}_debug QtAssistantClient${QT_LIBINFIX}d QtAssistantClient${QT_LIBINFIX}d4 QtAssistant${QT_LIBINFIX}_debug QtAssistant${QT_LIBINFIX}d4 PATHS ${QT_LIBRARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+
+ # Set QT_QTHELP_LIBRARY
+ find_library(QT_QTCLUCENE_LIBRARY_RELEASE NAMES QtCLucene${QT_LIBINFIX} QtCLucene${QT_LIBINFIX}4 PATHS ${QT_LIBRARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+ find_library(QT_QTCLUCENE_LIBRARY_DEBUG NAMES QtCLucene${QT_LIBINFIX}_debug QtCLucene${QT_LIBINFIX}d QtCLucene${QT_LIBINFIX}d4 PATHS ${QT_LIBRARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+ if(Q_WS_MAC AND QT_QTCORE_LIBRARY_RELEASE AND NOT QT_QTCLUCENE_LIBRARY_RELEASE)
+ find_library(QT_QTCLUCENE_LIBRARY_RELEASE NAMES QtCLucene${QT_LIBINFIX} PATHS ${QT_LIBRARY_DIR})
+ endif()
+
+
+ ############################################
+ #
+ # Check the existence of the libraries.
+ #
+ ############################################
+
+
+ macro(_qt4_add_target_depends_internal _QT_MODULE _PROPERTY)
+ if (TARGET Qt4::${_QT_MODULE})
+ foreach(_DEPEND ${ARGN})
+ set(_VALID_DEPENDS)
+ if (TARGET Qt4::Qt${_DEPEND})
+ list(APPEND _VALID_DEPENDS Qt4::Qt${_DEPEND})
+ endif()
+ if (_VALID_DEPENDS)
+ set_property(TARGET Qt4::${_QT_MODULE} APPEND PROPERTY
+ ${_PROPERTY}
+ "${_VALID_DEPENDS}"
+ )
+ endif()
+ set(_VALID_DEPENDS)
+ endforeach()
+ endif()
+ endmacro()
+
+ macro(_qt4_add_target_depends _QT_MODULE)
+ if (TARGET Qt4::${_QT_MODULE})
+ get_target_property(_configs Qt4::${_QT_MODULE} IMPORTED_CONFIGURATIONS)
+ _qt4_add_target_depends_internal(${_QT_MODULE} INTERFACE_LINK_LIBRARIES ${ARGN})
+ foreach(_config ${_configs})
+ _qt4_add_target_depends_internal(${_QT_MODULE} IMPORTED_LINK_INTERFACE_LIBRARIES_${_config} ${ARGN})
+ endforeach()
+ set(_configs)
+ endif()
+ endmacro()
+
+ macro(_qt4_add_target_private_depends _QT_MODULE)
+ if (TARGET Qt4::${_QT_MODULE})
+ get_target_property(_configs Qt4::${_QT_MODULE} IMPORTED_CONFIGURATIONS)
+ foreach(_config ${_configs})
+ _qt4_add_target_depends_internal(${_QT_MODULE} IMPORTED_LINK_DEPENDENT_LIBRARIES_${_config} ${ARGN})
+ endforeach()
+ set(_configs)
+ endif()
+ endmacro()
+
+
+ # Set QT_xyz_LIBRARY variable and add
+ # library include path to QT_INCLUDES
+ _QT4_ADJUST_LIB_VARS(QtCore)
+ set_property(TARGET Qt4::QtCore APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES
+ "${QT_MKSPECS_DIR}/default"
+ ${QT_INCLUDE_DIR}
+ )
+ set_property(TARGET Qt4::QtCore APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS
+ $<$<NOT:$<CONFIG:Debug>>:QT_NO_DEBUG>
+ )
+ set_property(TARGET Qt4::QtCore PROPERTY
+ INTERFACE_QT_MAJOR_VERSION 4
+ )
+ set_property(TARGET Qt4::QtCore APPEND PROPERTY
+ COMPATIBLE_INTERFACE_STRING QT_MAJOR_VERSION
+ )
+
+ foreach(QT_MODULE ${QT_MODULES})
+ _QT4_ADJUST_LIB_VARS(${QT_MODULE})
+ _qt4_add_target_depends(${QT_MODULE} Core)
+ endforeach()
+
+ _QT4_ADJUST_LIB_VARS(QtAssistant)
+ _QT4_ADJUST_LIB_VARS(QtAssistantClient)
+ _QT4_ADJUST_LIB_VARS(QtCLucene)
+ _QT4_ADJUST_LIB_VARS(QtDesignerComponents)
+
+ # platform dependent libraries
+ if(Q_WS_WIN)
+ _QT4_ADJUST_LIB_VARS(qtmain)
+
+ _QT4_ADJUST_LIB_VARS(QAxServer)
+ if(QT_QAXSERVER_FOUND)
+ set_property(TARGET Qt4::QAxServer PROPERTY
+ INTERFACE_QT4_NO_LINK_QTMAIN ON
+ )
+ set_property(TARGET Qt4::QAxServer APPEND PROPERTY
+ COMPATIBLE_INTERFACE_BOOL QT4_NO_LINK_QTMAIN)
+ endif()
+
+ _QT4_ADJUST_LIB_VARS(QAxContainer)
+ endif()
+
+ # Only public dependencies are listed here.
+ # Eg, QtDBus links to QtXml, but users of QtDBus do not need to
+ # link to QtXml because QtDBus only uses it internally, not in public
+ # headers.
+ # Everything depends on QtCore, but that is covered above already
+ _qt4_add_target_depends(Qt3Support Sql Gui Network)
+ if (TARGET Qt4::Qt3Support)
+ # An additional define is required for QT3_SUPPORT
+ set_property(TARGET Qt4::Qt3Support APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS QT3_SUPPORT)
+ endif()
+ _qt4_add_target_depends(QtDeclarative Script Gui)
+ _qt4_add_target_depends(QtDesigner Gui)
+ _qt4_add_target_depends(QtHelp Gui)
+ _qt4_add_target_depends(QtMultimedia Gui)
+ _qt4_add_target_depends(QtOpenGL Gui)
+ _qt4_add_target_depends(QtSvg Gui)
+ _qt4_add_target_depends(QtWebKit Gui Network)
+
+ _qt4_add_target_private_depends(Qt3Support Xml)
+ if(QT_VERSION VERSION_GREATER 4.6)
+ _qt4_add_target_private_depends(QtSvg Xml)
+ endif()
+ _qt4_add_target_private_depends(QtDBus Xml)
+ _qt4_add_target_private_depends(QtUiTools Xml Gui)
+ _qt4_add_target_private_depends(QtHelp Sql Xml Network)
+ _qt4_add_target_private_depends(QtXmlPatterns Network)
+ _qt4_add_target_private_depends(QtScriptTools Gui)
+ _qt4_add_target_private_depends(QtWebKit XmlPatterns)
+ _qt4_add_target_private_depends(QtDeclarative XmlPatterns Svg Sql Gui)
+ _qt4_add_target_private_depends(QtMultimedia Gui)
+ _qt4_add_target_private_depends(QtOpenGL Gui)
+ if(QT_QAXSERVER_FOUND)
+ _qt4_add_target_private_depends(QAxServer Gui)
+ endif()
+ if(QT_QAXCONTAINER_FOUND)
+ _qt4_add_target_private_depends(QAxContainer Gui)
+ endif()
+ _qt4_add_target_private_depends(phonon Gui)
+ if(QT_QTDBUS_FOUND)
+ _qt4_add_target_private_depends(phonon DBus)
+ endif()
+
+ if (WIN32 AND NOT QT4_NO_LINK_QTMAIN)
+ set(_isExe $<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>)
+ set(_isWin32 $<BOOL:$<TARGET_PROPERTY:WIN32_EXECUTABLE>>)
+ set(_isNotExcluded $<NOT:$<BOOL:$<TARGET_PROPERTY:QT4_NO_LINK_QTMAIN>>>)
+ set(_isPolicyNEW $<TARGET_POLICY:CMP0020>)
+ get_target_property(_configs Qt4::QtCore IMPORTED_CONFIGURATIONS)
+ set_property(TARGET Qt4::QtCore APPEND PROPERTY
+ INTERFACE_LINK_LIBRARIES
+ $<$<AND:${_isExe},${_isWin32},${_isNotExcluded},${_isPolicyNEW}>:Qt4::qtmain>
+ )
+ foreach(_config ${_configs})
+ set_property(TARGET Qt4::QtCore APPEND PROPERTY
+ IMPORTED_LINK_INTERFACE_LIBRARIES_${_config}
+ $<$<AND:${_isExe},${_isWin32},${_isNotExcluded},${_isPolicyNEW}>:Qt4::qtmain>
+ )
+ endforeach()
+ unset(_configs)
+ unset(_isExe)
+ unset(_isWin32)
+ unset(_isNotExcluded)
+ unset(_isPolicyNEW)
+ endif()
+
+ #######################################
+ #
+ # Check the executables of Qt
+ # ( moc, uic, rcc )
+ #
+ #######################################
+
+
+ if(QT_QMAKE_CHANGED)
+ set(QT_UIC_EXECUTABLE NOTFOUND)
+ set(QT_MOC_EXECUTABLE NOTFOUND)
+ set(QT_UIC3_EXECUTABLE NOTFOUND)
+ set(QT_RCC_EXECUTABLE NOTFOUND)
+ set(QT_DBUSCPP2XML_EXECUTABLE NOTFOUND)
+ set(QT_DBUSXML2CPP_EXECUTABLE NOTFOUND)
+ set(QT_LUPDATE_EXECUTABLE NOTFOUND)
+ set(QT_LRELEASE_EXECUTABLE NOTFOUND)
+ set(QT_QCOLLECTIONGENERATOR_EXECUTABLE NOTFOUND)
+ set(QT_DESIGNER_EXECUTABLE NOTFOUND)
+ set(QT_LINGUIST_EXECUTABLE NOTFOUND)
+ endif()
+
+ macro(_find_qt4_program VAR NAME)
+ find_program(${VAR}
+ NAMES ${ARGN}
+ PATHS ${QT_BINARY_DIR}
+ NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+ )
+ if (${VAR} AND NOT TARGET ${NAME})
+ add_executable(${NAME} IMPORTED)
+ set_property(TARGET ${NAME} PROPERTY IMPORTED_LOCATION ${${VAR}})
+ endif()
+ endmacro()
+
+ _find_qt4_program(QT_MOC_EXECUTABLE Qt4::moc moc-qt4 moc4 moc)
+ _find_qt4_program(QT_UIC_EXECUTABLE Qt4::uic uic-qt4 uic4 uic)
+ _find_qt4_program(QT_UIC3_EXECUTABLE Qt4::uic3 uic3)
+ _find_qt4_program(QT_RCC_EXECUTABLE Qt4::rcc rcc)
+ _find_qt4_program(QT_DBUSCPP2XML_EXECUTABLE Qt4::qdbuscpp2xml qdbuscpp2xml)
+ _find_qt4_program(QT_DBUSXML2CPP_EXECUTABLE Qt4::qdbusxml2cpp qdbusxml2cpp)
+ _find_qt4_program(QT_LUPDATE_EXECUTABLE Qt4::lupdate lupdate-qt4 lupdate4 lupdate)
+ _find_qt4_program(QT_LRELEASE_EXECUTABLE Qt4::lrelease lrelease-qt4 lrelease4 lrelease)
+ _find_qt4_program(QT_QCOLLECTIONGENERATOR_EXECUTABLE Qt4::qcollectiongenerator qcollectiongenerator-qt4 qcollectiongenerator)
+ _find_qt4_program(QT_DESIGNER_EXECUTABLE Qt4::designer designer-qt4 designer4 designer)
+ _find_qt4_program(QT_LINGUIST_EXECUTABLE Qt4::linguist linguist-qt4 linguist4 linguist)
+
+ if (NOT TARGET Qt4::qmake)
+ add_executable(Qt4::qmake IMPORTED)
+ set_property(TARGET Qt4::qmake PROPERTY IMPORTED_LOCATION ${QT_QMAKE_EXECUTABLE})
+ endif()
+
+ if (QT_MOC_EXECUTABLE)
+ set(QT_WRAP_CPP "YES")
+ endif ()
+
+ if (QT_UIC_EXECUTABLE)
+ set(QT_WRAP_UI "YES")
+ endif ()
+
+
+
+ mark_as_advanced( QT_UIC_EXECUTABLE QT_UIC3_EXECUTABLE QT_MOC_EXECUTABLE
+ QT_RCC_EXECUTABLE QT_DBUSXML2CPP_EXECUTABLE QT_DBUSCPP2XML_EXECUTABLE
+ QT_LUPDATE_EXECUTABLE QT_LRELEASE_EXECUTABLE QT_QCOLLECTIONGENERATOR_EXECUTABLE
+ QT_DESIGNER_EXECUTABLE QT_LINGUIST_EXECUTABLE)
+
+
+ # get the directory of the current file, used later on in the file
+ get_filename_component( _qt4_current_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+
+ ###############################################
+ #
+ # configuration/system dependent settings
+ #
+ ###############################################
+
+ include("${_qt4_current_dir}/Qt4ConfigDependentSettings.cmake")
+
+
+ #######################################
+ #
+ # Check the plugins of Qt
+ #
+ #######################################
+
+ set( QT_PLUGIN_TYPES accessible bearer codecs decorations designer gfxdrivers graphicssystems iconengines imageformats inputmethods mousedrivers phonon_backend script sqldrivers )
+
+ set( QT_ACCESSIBLE_PLUGINS qtaccessiblecompatwidgets qtaccessiblewidgets )
+ set( QT_BEARER_PLUGINS qcorewlanbearer qgenericbearer qnativewifibearer )
+ set( QT_CODECS_PLUGINS qcncodecs qjpcodecs qkrcodecs qtwcodecs )
+ set( QT_DECORATIONS_PLUGINS qdecorationdefault qdecorationwindows )
+ set( QT_DESIGNER_PLUGINS arthurplugin containerextension customwidgetplugin phononwidgets qdeclarativeview qt3supportwidgets qwebview taskmenuextension worldtimeclockplugin )
+ set( QT_GRAPHICSDRIVERS_PLUGINS qgfxtransformed qgfxvnc qscreenvfb )
+ set( QT_GRAPHICSSYSTEMS_PLUGINS qglgraphicssystem qtracegraphicssystem )
+ set( QT_ICONENGINES_PLUGINS qsvgicon )
+ set( QT_IMAGEFORMATS_PLUGINS qgif qjpeg qmng qico qsvg qtiff qtga )
+ set( QT_INPUTMETHODS_PLUGINS qimsw_multi )
+ set( QT_MOUSEDRIVERS_PLUGINS qwstslibmousehandler )
+ if(APPLE)
+ set( QT_PHONON_BACKEND_PLUGINS phonon_qt7 )
+ elseif(WIN32)
+ set( QT_PHONON_BACKEND_PLUGINS phonon_ds9 )
+ endif()
+ set( QT_SCRIPT_PLUGINS qtscriptdbus )
+ set( QT_SQLDRIVERS_PLUGINS qsqldb2 qsqlibase qsqlite qsqlite2 qsqlmysql qsqloci qsqlodbc qsqlpsql qsqltds )
+
+ set( QT_PHONON_PLUGINS ${QT_PHONON_BACKEND_PLUGINS} )
+ set( QT_QT3SUPPORT_PLUGINS qtaccessiblecompatwidgets )
+ set( QT_QTCORE_PLUGINS ${QT_BEARER_PLUGINS} ${QT_CODECS_PLUGINS} )
+ set( QT_QTGUI_PLUGINS qtaccessiblewidgets ${QT_IMAGEFORMATS_PLUGINS} ${QT_DECORATIONS_PLUGINS} ${QT_GRAPHICSDRIVERS_PLUGINS} ${QT_GRAPHICSSYSTEMS_PLUGINS} ${QT_INPUTMETHODS_PLUGINS} ${QT_MOUSEDRIVERS_PLUGINS} )
+ set( QT_QTSCRIPT_PLUGINS ${QT_SCRIPT_PLUGINS} )
+ set( QT_QTSQL_PLUGINS ${QT_SQLDRIVERS_PLUGINS} )
+ set( QT_QTSVG_PLUGINS qsvg qsvgicon )
+
+ if(QT_QMAKE_CHANGED)
+ foreach(QT_PLUGIN_TYPE ${QT_PLUGIN_TYPES})
+ string(TOUPPER ${QT_PLUGIN_TYPE} _upper_qt_plugin_type)
+ set(QT_${_upper_qt_plugin_type}_PLUGINS_DIR ${QT_PLUGINS_DIR}/${QT_PLUGIN_TYPE})
+ foreach(QT_PLUGIN ${QT_${_upper_qt_plugin_type}_PLUGINS})
+ string(TOUPPER ${QT_PLUGIN} _upper_qt_plugin)
+ unset(QT_${_upper_qt_plugin}_LIBRARY_RELEASE CACHE)
+ unset(QT_${_upper_qt_plugin}_LIBRARY_DEBUG CACHE)
+ unset(QT_${_upper_qt_plugin}_LIBRARY CACHE)
+ unset(QT_${_upper_qt_plugin}_PLUGIN_RELEASE CACHE)
+ unset(QT_${_upper_qt_plugin}_PLUGIN_DEBUG CACHE)
+ unset(QT_${_upper_qt_plugin}_PLUGIN CACHE)
+ endforeach()
+ endforeach()
+ endif()
+
+ # find_library works better than find_file but we need to set prefixes to only match plugins
+ foreach(QT_PLUGIN_TYPE ${QT_PLUGIN_TYPES})
+ string(TOUPPER ${QT_PLUGIN_TYPE} _upper_qt_plugin_type)
+ set(QT_${_upper_qt_plugin_type}_PLUGINS_DIR ${QT_PLUGINS_DIR}/${QT_PLUGIN_TYPE})
+ foreach(QT_PLUGIN ${QT_${_upper_qt_plugin_type}_PLUGINS})
+ string(TOUPPER ${QT_PLUGIN} _upper_qt_plugin)
+ if(QT_IS_STATIC)
+ find_library(QT_${_upper_qt_plugin}_LIBRARY_RELEASE
+ NAMES ${QT_PLUGIN}${QT_LIBINFIX} ${QT_PLUGIN}${QT_LIBINFIX}4
+ PATHS ${QT_${_upper_qt_plugin_type}_PLUGINS_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+ )
+ find_library(QT_${_upper_qt_plugin}_LIBRARY_DEBUG
+ NAMES ${QT_PLUGIN}${QT_LIBINFIX}_debug ${QT_PLUGIN}${QT_LIBINFIX}d ${QT_PLUGIN}${QT_LIBINFIX}d4
+ PATHS ${QT_${_upper_qt_plugin_type}_PLUGINS_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+ )
+ _QT4_ADJUST_LIB_VARS(${QT_PLUGIN})
+ else()
+ # find_library works easier/better than find_file but we need to set suffixes to only match plugins
+ set(CMAKE_FIND_LIBRARY_SUFFIXES_DEFAULT ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_MODULE_SUFFIX} ${CMAKE_SHARED_LIBRARY_SUFFIX})
+ find_library(QT_${_upper_qt_plugin}_PLUGIN_RELEASE
+ NAMES ${QT_PLUGIN}${QT_LIBINFIX} ${QT_PLUGIN}${QT_LIBINFIX}4
+ PATHS ${QT_${_upper_qt_plugin_type}_PLUGINS_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+ )
+ find_library(QT_${_upper_qt_plugin}_PLUGIN_DEBUG
+ NAMES ${QT_PLUGIN}${QT_LIBINFIX}_debug ${QT_PLUGIN}${QT_LIBINFIX}d ${QT_PLUGIN}${QT_LIBINFIX}d4
+ PATHS ${QT_${_upper_qt_plugin_type}_PLUGINS_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+ )
+ mark_as_advanced(QT_${_upper_qt_plugin}_PLUGIN_RELEASE QT_${_upper_qt_plugin}_PLUGIN_DEBUG)
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_DEFAULT})
+ endif()
+ endforeach()
+ endforeach()
+
+
+ ######################################
+ #
+ # Macros for building Qt files
+ #
+ ######################################
+
+ include("${_qt4_current_dir}/Qt4Macros.cmake")
+
+endif()
+
+#support old QT_MIN_VERSION if set, but not if version is supplied by find_package()
+if(NOT Qt4_FIND_VERSION AND QT_MIN_VERSION)
+ set(Qt4_FIND_VERSION ${QT_MIN_VERSION})
+endif()
+
+if( Qt4_FIND_COMPONENTS )
+
+ # if components specified in find_package(), make sure each of those pieces were found
+ set(_QT4_FOUND_REQUIRED_VARS QT_QMAKE_EXECUTABLE QT_MOC_EXECUTABLE QT_RCC_EXECUTABLE QT_INCLUDE_DIR QT_LIBRARY_DIR)
+ foreach( component ${Qt4_FIND_COMPONENTS} )
+ string( TOUPPER ${component} _COMPONENT )
+ if(${_COMPONENT} STREQUAL "QTMAIN")
+ if(Q_WS_WIN)
+ set(_QT4_FOUND_REQUIRED_VARS ${_QT4_FOUND_REQUIRED_VARS} QT_${_COMPONENT}_LIBRARY)
+ endif()
+ else()
+ set(_QT4_FOUND_REQUIRED_VARS ${_QT4_FOUND_REQUIRED_VARS} QT_${_COMPONENT}_INCLUDE_DIR QT_${_COMPONENT}_LIBRARY)
+ endif()
+ endforeach()
+
+ if(Qt4_FIND_COMPONENTS MATCHES QtGui)
+ set(_QT4_FOUND_REQUIRED_VARS ${_QT4_FOUND_REQUIRED_VARS} QT_UIC_EXECUTABLE)
+ endif()
+
+else()
+
+ # if no components specified, we'll make a default set of required variables to say Qt is found
+ set(_QT4_FOUND_REQUIRED_VARS QT_QMAKE_EXECUTABLE QT_MOC_EXECUTABLE QT_RCC_EXECUTABLE QT_UIC_EXECUTABLE QT_INCLUDE_DIR
+ QT_LIBRARY_DIR QT_QTCORE_LIBRARY)
+
+endif()
+
+if (NOT QT_VERSION_MAJOR EQUAL 4)
+ set(VERSION_MSG "Found unsuitable Qt version \"${QTVERSION}\" from ${QT_QMAKE_EXECUTABLE}")
+ set(Qt4_FOUND FALSE)
+ if(Qt4_FIND_REQUIRED)
+ message( FATAL_ERROR "${VERSION_MSG}, this code requires Qt 4.x")
+ else()
+ if(NOT Qt4_FIND_QUIETLY)
+ message( STATUS "${VERSION_MSG}")
+ endif()
+ endif()
+else()
+ if (CMAKE_FIND_PACKAGE_NAME STREQUAL "Qt")
+ # FindQt include()'s this module. It's an old pattern, but rather than
+ # trying to suppress this from outside the module (which is then sensitive
+ # to the contents, detect the case in this module and suppress it
+ # explicitly.
+ set(FPHSA_NAME_MISMATCHED 1)
+ endif ()
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(Qt4 FOUND_VAR Qt4_FOUND
+ REQUIRED_VARS ${_QT4_FOUND_REQUIRED_VARS}
+ VERSION_VAR QTVERSION
+ )
+ unset(FPHSA_NAME_MISMATCHED)
+endif()
+
+#######################################
+#
+# compatibility settings
+#
+#######################################
+# Backwards compatibility for CMake1.4 and 1.2
+set (QT_MOC_EXE ${QT_MOC_EXECUTABLE} )
+set (QT_UIC_EXE ${QT_UIC_EXECUTABLE} )
+set( QT_QT_LIBRARY "")
+set(QT4_FOUND ${Qt4_FOUND})
+set(QT_FOUND ${Qt4_FOUND})
+
diff --git a/Modules/FindQuickTime.cmake b/Modules/FindQuickTime.cmake
new file mode 100644
index 0000000..107486d
--- /dev/null
+++ b/Modules/FindQuickTime.cmake
@@ -0,0 +1,34 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindQuickTime
+-------------
+
+
+
+Locate QuickTime This module defines QUICKTIME_LIBRARY
+QUICKTIME_FOUND, if false, do not try to link to gdal
+QUICKTIME_INCLUDE_DIR, where to find the headers
+
+$QUICKTIME_DIR is an environment variable that would correspond to the
+./configure --prefix=$QUICKTIME_DIR
+
+Created by Eric Wing.
+#]=======================================================================]
+
+find_path(QUICKTIME_INCLUDE_DIR QuickTime/QuickTime.h QuickTime.h
+ HINTS
+ ENV QUICKTIME_DIR
+ PATH_SUFFIXES
+ include
+)
+find_library(QUICKTIME_LIBRARY QuickTime
+ HINTS
+ ENV QUICKTIME_DIR
+ PATH_SUFFIXES
+ lib
+)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(QuickTime DEFAULT_MSG QUICKTIME_LIBRARY QUICKTIME_INCLUDE_DIR)
diff --git a/Modules/FindRTI.cmake b/Modules/FindRTI.cmake
new file mode 100644
index 0000000..54d2bec
--- /dev/null
+++ b/Modules/FindRTI.cmake
@@ -0,0 +1,102 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindRTI
+-------
+
+Try to find M&S HLA RTI libraries
+
+This module finds if any HLA RTI is installed and locates the standard
+RTI include files and libraries.
+
+RTI is a simulation infrastructure standardized by IEEE and SISO. It
+has a well defined C++ API that assures that simulation applications
+are independent on a particular RTI implementation.
+
+::
+
+ http://en.wikipedia.org/wiki/Run-Time_Infrastructure_(simulation)
+
+
+
+This code sets the following variables:
+
+::
+
+ RTI_INCLUDE_DIR = the directory where RTI includes file are found
+ RTI_LIBRARIES = The libraries to link against to use RTI
+ RTI_DEFINITIONS = -DRTI_USES_STD_FSTREAM
+ RTI_FOUND = Set to FALSE if any HLA RTI was not found
+
+
+
+Report problems to <certi-devel@nongnu.org>
+#]=======================================================================]
+
+macro(RTI_MESSAGE_QUIETLY QUIET TYPE MSG)
+ if(NOT ${QUIET})
+ message(${TYPE} "${MSG}")
+ endif()
+endmacro()
+
+set(RTI_DEFINITIONS "-DRTI_USES_STD_FSTREAM")
+
+# Detect the CERTI installation, http://www.cert.fr/CERTI
+# Detect the MAK Technologies RTI installation, http://www.mak.com/products/rti.php
+# note: the following list is ordered to find the most recent version first
+set(RTI_POSSIBLE_DIRS
+ ENV CERTI_HOME
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MAK Technologies\\MAK RTI 3.2 MSVC++ 8.0;Location]"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MAK RTI 3.2-win32-msvc++8.0;InstallLocation]"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MAK Technologies\\MAK RTI 2.2;Location]"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MAK RTI 2.2;InstallLocation]")
+
+set(RTI_OLD_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}")
+# The MAK RTI has the "lib" prefix even on Windows.
+set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
+
+find_library(RTI_LIBRARY
+ NAMES RTI RTI-NG
+ PATHS ${RTI_POSSIBLE_DIRS}
+ PATH_SUFFIXES lib
+ DOC "The RTI Library")
+
+if (RTI_LIBRARY)
+ set(RTI_LIBRARIES ${RTI_LIBRARY})
+ RTI_MESSAGE_QUIETLY(RTI_FIND_QUIETLY STATUS "RTI library found: ${RTI_LIBRARY}")
+else ()
+ RTI_MESSAGE_QUIETLY(RTI_FIND_QUIETLY STATUS "RTI library NOT found")
+endif ()
+
+find_library(RTI_FEDTIME_LIBRARY
+ NAMES FedTime
+ PATHS ${RTI_POSSIBLE_DIRS}
+ PATH_SUFFIXES lib
+ DOC "The FedTime Library")
+
+if (RTI_FEDTIME_LIBRARY)
+ set(RTI_LIBRARIES ${RTI_LIBRARIES} ${RTI_FEDTIME_LIBRARY})
+ RTI_MESSAGE_QUIETLY(RTI_FIND_QUIETLY STATUS "RTI FedTime found: ${RTI_FEDTIME_LIBRARY}")
+endif ()
+
+find_path(RTI_INCLUDE_DIR
+ NAMES RTI.hh
+ PATHS ${RTI_POSSIBLE_DIRS}
+ PATH_SUFFIXES include
+ DOC "The RTI Include Files")
+
+if (RTI_INCLUDE_DIR)
+ RTI_MESSAGE_QUIETLY(RTI_FIND_QUIETLY STATUS "RTI headers found: ${RTI_INCLUDE_DIR}")
+else ()
+ RTI_MESSAGE_QUIETLY(RTI_FIND_QUIETLY STATUS "RTI headers NOT found")
+endif ()
+
+# Set the modified system variables back to the original value.
+set(CMAKE_FIND_LIBRARY_PREFIXES "${RTI_OLD_FIND_LIBRARY_PREFIXES}")
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(RTI DEFAULT_MSG
+ RTI_LIBRARY RTI_INCLUDE_DIR)
+
+# $Id$
diff --git a/Modules/FindRuby.cmake b/Modules/FindRuby.cmake
new file mode 100644
index 0000000..759f57c
--- /dev/null
+++ b/Modules/FindRuby.cmake
@@ -0,0 +1,533 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindRuby
+--------
+
+Find Ruby
+
+This module finds if Ruby is installed and determines where the
+include files and libraries are. Ruby 1.8 through 2.7 are
+supported.
+
+The minimum required version of Ruby can be specified using the
+standard syntax, e.g.
+
+.. code-block:: cmake
+
+ find_package(Ruby 2.5.1 EXACT REQUIRED)
+ # OR
+ find_package(Ruby 2.4)
+
+It also determines what the name of the library is.
+
+Virtual environments such as RVM are handled as well, by passing
+the argument ``Ruby_FIND_VIRTUALENV``
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``Ruby_FOUND``
+ set to true if ruby was found successfully
+``Ruby_EXECUTABLE``
+ full path to the ruby binary
+``Ruby_INCLUDE_DIRS``
+ include dirs to be used when using the ruby library
+``Ruby_LIBRARIES``
+ .. versionadded:: 3.18
+ libraries needed to use ruby from C.
+``Ruby_VERSION``
+ the version of ruby which was found, e.g. "1.8.7"
+``Ruby_VERSION_MAJOR``
+ Ruby major version.
+``Ruby_VERSION_MINOR``
+ Ruby minor version.
+``Ruby_VERSION_PATCH``
+ Ruby patch version.
+
+.. versionchanged:: 3.18
+ Previous versions of CMake used the ``RUBY_`` prefix for all variables.
+ The following variables are provided for compatibility reasons,
+ don't use them in new code:
+
+``RUBY_EXECUTABLE``
+ same as Ruby_EXECUTABLE.
+``RUBY_INCLUDE_DIRS``
+ same as Ruby_INCLUDE_DIRS.
+``RUBY_INCLUDE_PATH``
+ same as Ruby_INCLUDE_DIRS.
+``RUBY_LIBRARY``
+ same as Ruby_LIBRARY.
+``RUBY_VERSION``
+ same as Ruby_VERSION.
+``RUBY_FOUND``
+ same as Ruby_FOUND.
+
+Hints
+^^^^^
+
+.. versionadded:: 3.18
+
+``Ruby_ROOT_DIR``
+ Define the root directory of a Ruby installation.
+
+``Ruby_FIND_VIRTUALENV``
+ This variable defines the handling of virtual environments managed by
+ ``rvm``. It is meaningful only when a virtual environment
+ is active (i.e. the ``rvm`` script has been evaluated or at least the
+ ``MY_RUBY_HOME`` environment variable is set).
+ The ``Ruby_FIND_VIRTUALENV`` variable can be set to empty or
+ one of the following:
+
+ * ``FIRST``: The virtual environment is used before any other standard
+ paths to look-up for the interpreter. This is the default.
+ * ``ONLY``: Only the virtual environment is used to look-up for the
+ interpreter.
+ * ``STANDARD``: The virtual environment is not used to look-up for the
+ interpreter (assuming it isn't still in the PATH...)
+
+#]=======================================================================]
+
+# Backwards compatibility
+# Define camel case versions of input variables
+foreach(UPPER
+ RUBY_EXECUTABLE
+ RUBY_LIBRARY
+ RUBY_INCLUDE_DIR
+ RUBY_CONFIG_INCLUDE_DIR
+ )
+ if (DEFINED ${UPPER})
+ string(REPLACE "RUBY_" "Ruby_" Camel ${UPPER})
+ if (NOT DEFINED ${Camel})
+ set(${Camel} ${${UPPER}})
+ endif()
+ endif()
+endforeach()
+
+# Ruby_ARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"archdir"@:>@)'`
+# Ruby_SITEARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitearchdir"@:>@)'`
+# Ruby_SITEDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitelibdir"@:>@)'`
+# Ruby_LIBDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"libdir"@:>@)'`
+# Ruby_LIBRUBYARG=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"LIBRUBYARG_SHARED"@:>@)'`
+
+# uncomment the following line to get debug output for this file
+# set(_Ruby_DEBUG_OUTPUT TRUE)
+
+# Determine the list of possible names of the ruby executable depending
+# on which version of ruby is required
+set(_Ruby_POSSIBLE_EXECUTABLE_NAMES ruby)
+
+# If not specified, allow everything as far back as 1.8.0
+if(NOT DEFINED Ruby_FIND_VERSION_MAJOR)
+ set(Ruby_FIND_VERSION "1.8.0")
+ set(Ruby_FIND_VERSION_MAJOR 1)
+ set(Ruby_FIND_VERSION_MINOR 8)
+ set(Ruby_FIND_VERSION_PATCH 0)
+endif()
+
+if(_Ruby_DEBUG_OUTPUT)
+ message("Ruby_FIND_VERSION=${Ruby_FIND_VERSION}")
+ message("Ruby_FIND_VERSION_MAJOR=${Ruby_FIND_VERSION_MAJOR}")
+ message("Ruby_FIND_VERSION_MINOR=${Ruby_FIND_VERSION_MINOR}")
+ message("Ruby_FIND_VERSION_PATCH=${Ruby_FIND_VERSION_PATCH}")
+endif()
+
+set(Ruby_FIND_VERSION_SHORT_NODOT "${Ruby_FIND_VERSION_MAJOR}${Ruby_FIND_VERSION_MINOR}")
+
+# Set name of possible executables, ignoring the minor
+# Eg:
+# 2.1.1 => from ruby27 to ruby21 included
+# 2.1 => from ruby27 to ruby21 included
+# 2 => from ruby26 to ruby20 included
+# empty => from ruby27 to ruby18 included
+if(NOT Ruby_FIND_VERSION_EXACT)
+
+ foreach(_ruby_version RANGE 27 18 -1)
+ string(SUBSTRING "${_ruby_version}" 0 1 _ruby_major_version)
+ string(SUBSTRING "${_ruby_version}" 1 1 _ruby_minor_version)
+
+ if(NOT "${_ruby_major_version}${_ruby_minor_version}" VERSION_LESS ${Ruby_FIND_VERSION_SHORT_NODOT})
+ # Append both rubyX.Y and rubyXY (eg: ruby2.7 ruby27)
+ list(APPEND _Ruby_POSSIBLE_EXECUTABLE_NAMES ruby${_ruby_major_version}.${_ruby_minor_version} ruby${_ruby_major_version}${_ruby_minor_version})
+ else()
+ break()
+ endif()
+
+ endforeach()
+
+ list(REMOVE_DUPLICATES _Ruby_POSSIBLE_EXECUTABLE_NAMES)
+endif()
+
+# virtual environments handling (eg RVM)
+if (DEFINED ENV{MY_RUBY_HOME})
+ if(_Ruby_DEBUG_OUTPUT)
+ message("My ruby home is defined: $ENV{MY_RUBY_HOME}")
+ endif()
+
+ if (DEFINED Ruby_FIND_VIRTUALENV)
+ if (NOT Ruby_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY|STANDARD)$")
+ message (AUTHOR_WARNING "FindRuby: ${Ruby_FIND_VIRTUALENV}: invalid value for 'Ruby_FIND_VIRTUALENV'. 'FIRST', 'ONLY' or 'STANDARD' expected. 'FIRST' will be used instead.")
+ set (_Ruby_FIND_VIRTUALENV "FIRST")
+ else()
+ set (_Ruby_FIND_VIRTUALENV ${Ruby_FIND_VIRTUALENV})
+ endif()
+ else()
+ set (_Ruby_FIND_VIRTUALENV FIRST)
+ endif()
+else()
+ if (DEFINED Ruby_FIND_VIRTUALENV)
+ message("Environment variable MY_RUBY_HOME isn't set, defaulting back to Ruby_FIND_VIRTUALENV=STANDARD")
+ endif()
+ set (_Ruby_FIND_VIRTUALENV STANDARD)
+endif()
+
+if(_Ruby_DEBUG_OUTPUT)
+ message("_Ruby_POSSIBLE_EXECUTABLE_NAMES=${_Ruby_POSSIBLE_EXECUTABLE_NAMES}")
+ message("_Ruby_FIND_VIRTUALENV=${_Ruby_FIND_VIRTUALENV}")
+endif()
+
+function (_RUBY_VALIDATE_INTERPRETER)
+ if (NOT Ruby_EXECUTABLE)
+ return()
+ endif()
+
+ cmake_parse_arguments (PARSE_ARGV 0 _RVI "EXACT;CHECK_EXISTS" "" "")
+ if (_RVI_UNPARSED_ARGUMENTS)
+ set (expected_version ${_RVI_UNPARSED_ARGUMENTS})
+ else()
+ unset (expected_version)
+ endif()
+
+ if (_RVI_CHECK_EXISTS AND NOT EXISTS "${Ruby_EXECUTABLE}")
+ # interpreter does not exist anymore
+ set (_Ruby_Interpreter_REASON_FAILURE "Cannot find the interpreter \"${Ruby_EXECUTABLE}\"")
+ set_property (CACHE Ruby_EXECUTABLE PROPERTY VALUE "Ruby_EXECUTABLE-NOTFOUND")
+ return()
+ endif()
+
+ # Check the version it returns
+ # executable found must have a specific version
+ execute_process (COMMAND "${Ruby_EXECUTABLE}" -e "puts RUBY_VERSION"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE version
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (result OR (_RVI_EXACT AND NOT version VERSION_EQUAL expected_version) OR (version VERSION_LESS expected_version))
+ # interpreter not usable or has wrong major version
+ if (result)
+ set (_Ruby_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${Ruby_EXECUTABLE}\"")
+ else()
+ set (_Ruby_Interpreter_REASON_FAILURE "Wrong major version for the interpreter \"${Ruby_EXECUTABLE}\"")
+ endif()
+ set_property (CACHE Ruby_EXECUTABLE PROPERTY VALUE "Ruby_EXECUTABLE-NOTFOUND")
+ return()
+ endif()
+
+endfunction()
+
+while(1)
+ # Virtual environments handling
+ if(_Ruby_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+ if(_Ruby_DEBUG_OUTPUT)
+ message("Inside Matches")
+ endif()
+ find_program (Ruby_EXECUTABLE
+ NAMES ${_Ruby_POSSIBLE_EXECUTABLE_NAMES}
+ NAMES_PER_DIR
+ PATHS ENV MY_RUBY_HOME
+ PATH_SUFFIXES bin Scripts
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+
+ if(_Ruby_DEBUG_OUTPUT)
+ message("Ruby_EXECUTABLE=${Ruby_EXECUTABLE}")
+ endif()
+
+ _RUBY_VALIDATE_INTERPRETER (${Ruby_FIND_VERSION}})
+ if(Ruby_EXECUTABLE)
+ break()
+ endif()
+ if(NOT _Ruby_FIND_VIRTUALENV STREQUAL "ONLY")
+ break()
+ endif()
+ elseif(_Ruby_DEBUG_OUTPUT)
+ message("_Ruby_FIND_VIRTUALENV doesn't match: ${_Ruby_FIND_VIRTUALENV}")
+ endif()
+
+ # try using standard paths
+ find_program (Ruby_EXECUTABLE
+ NAMES ${_Ruby_POSSIBLE_EXECUTABLE_NAMES}
+ NAMES_PER_DIR)
+ _RUBY_VALIDATE_INTERPRETER (${Ruby_FIND_VERSION})
+ if (Ruby_EXECUTABLE)
+ break()
+ endif()
+
+ break()
+endwhile()
+
+if(Ruby_EXECUTABLE AND NOT Ruby_VERSION_MAJOR)
+ function(_RUBY_CONFIG_VAR RBVAR OUTVAR)
+ execute_process(COMMAND ${Ruby_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['${RBVAR}']"
+ RESULT_VARIABLE _Ruby_SUCCESS
+ OUTPUT_VARIABLE _Ruby_OUTPUT
+ ERROR_QUIET)
+ if(_Ruby_SUCCESS OR _Ruby_OUTPUT STREQUAL "")
+ execute_process(COMMAND ${Ruby_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['${RBVAR}']"
+ RESULT_VARIABLE _Ruby_SUCCESS
+ OUTPUT_VARIABLE _Ruby_OUTPUT
+ ERROR_QUIET)
+ endif()
+ set(${OUTVAR} "${_Ruby_OUTPUT}" PARENT_SCOPE)
+ endfunction()
+
+
+ # query the ruby version
+ _RUBY_CONFIG_VAR("MAJOR" Ruby_VERSION_MAJOR)
+ _RUBY_CONFIG_VAR("MINOR" Ruby_VERSION_MINOR)
+ _RUBY_CONFIG_VAR("TEENY" Ruby_VERSION_PATCH)
+
+ # query the different directories
+ _RUBY_CONFIG_VAR("archdir" Ruby_ARCH_DIR)
+ _RUBY_CONFIG_VAR("arch" Ruby_ARCH)
+ _RUBY_CONFIG_VAR("rubyhdrdir" Ruby_HDR_DIR)
+ _RUBY_CONFIG_VAR("rubyarchhdrdir" Ruby_ARCHHDR_DIR)
+ _RUBY_CONFIG_VAR("libdir" Ruby_POSSIBLE_LIB_DIR)
+ _RUBY_CONFIG_VAR("rubylibdir" Ruby_RUBY_LIB_DIR)
+
+ # site_ruby
+ _RUBY_CONFIG_VAR("sitearchdir" Ruby_SITEARCH_DIR)
+ _RUBY_CONFIG_VAR("sitelibdir" Ruby_SITELIB_DIR)
+
+ # vendor_ruby available ?
+ execute_process(COMMAND ${Ruby_EXECUTABLE} -r vendor-specific -e "print 'true'"
+ OUTPUT_VARIABLE Ruby_HAS_VENDOR_RUBY ERROR_QUIET)
+
+ if(Ruby_HAS_VENDOR_RUBY)
+ _RUBY_CONFIG_VAR("vendorlibdir" Ruby_VENDORLIB_DIR)
+ _RUBY_CONFIG_VAR("vendorarchdir" Ruby_VENDORARCH_DIR)
+ endif()
+
+ # save the results in the cache so we don't have to run ruby the next time again
+ set(Ruby_VERSION_MAJOR ${Ruby_VERSION_MAJOR} CACHE PATH "The Ruby major version" FORCE)
+ set(Ruby_VERSION_MINOR ${Ruby_VERSION_MINOR} CACHE PATH "The Ruby minor version" FORCE)
+ set(Ruby_VERSION_PATCH ${Ruby_VERSION_PATCH} CACHE PATH "The Ruby patch version" FORCE)
+ set(Ruby_ARCH_DIR ${Ruby_ARCH_DIR} CACHE PATH "The Ruby arch dir" FORCE)
+ set(Ruby_HDR_DIR ${Ruby_HDR_DIR} CACHE PATH "The Ruby header dir (1.9+)" FORCE)
+ set(Ruby_ARCHHDR_DIR ${Ruby_ARCHHDR_DIR} CACHE PATH "The Ruby arch header dir (2.0+)" FORCE)
+ set(Ruby_POSSIBLE_LIB_DIR ${Ruby_POSSIBLE_LIB_DIR} CACHE PATH "The Ruby lib dir" FORCE)
+ set(Ruby_RUBY_LIB_DIR ${Ruby_RUBY_LIB_DIR} CACHE PATH "The Ruby ruby-lib dir" FORCE)
+ set(Ruby_SITEARCH_DIR ${Ruby_SITEARCH_DIR} CACHE PATH "The Ruby site arch dir" FORCE)
+ set(Ruby_SITELIB_DIR ${Ruby_SITELIB_DIR} CACHE PATH "The Ruby site lib dir" FORCE)
+ set(Ruby_HAS_VENDOR_RUBY ${Ruby_HAS_VENDOR_RUBY} CACHE BOOL "Vendor Ruby is available" FORCE)
+ set(Ruby_VENDORARCH_DIR ${Ruby_VENDORARCH_DIR} CACHE PATH "The Ruby vendor arch dir" FORCE)
+ set(Ruby_VENDORLIB_DIR ${Ruby_VENDORLIB_DIR} CACHE PATH "The Ruby vendor lib dir" FORCE)
+
+ mark_as_advanced(
+ Ruby_ARCH_DIR
+ Ruby_ARCH
+ Ruby_HDR_DIR
+ Ruby_ARCHHDR_DIR
+ Ruby_POSSIBLE_LIB_DIR
+ Ruby_RUBY_LIB_DIR
+ Ruby_SITEARCH_DIR
+ Ruby_SITELIB_DIR
+ Ruby_HAS_VENDOR_RUBY
+ Ruby_VENDORARCH_DIR
+ Ruby_VENDORLIB_DIR
+ Ruby_VERSION_MAJOR
+ Ruby_VERSION_MINOR
+ Ruby_VERSION_PATCH
+ )
+endif()
+
+# In case Ruby_EXECUTABLE could not be executed (e.g. cross compiling)
+# try to detect which version we found. This is not too good.
+if(Ruby_EXECUTABLE AND NOT Ruby_VERSION_MAJOR)
+ # by default assume 1.8.0
+ set(Ruby_VERSION_MAJOR 1)
+ set(Ruby_VERSION_MINOR 8)
+ set(Ruby_VERSION_PATCH 0)
+ # check whether we found 1.9.x
+ if(${Ruby_EXECUTABLE} MATCHES "ruby1\\.?9")
+ set(Ruby_VERSION_MAJOR 1)
+ set(Ruby_VERSION_MINOR 9)
+ endif()
+ # check whether we found 2.0.x
+ if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?0")
+ set(Ruby_VERSION_MAJOR 2)
+ set(Ruby_VERSION_MINOR 0)
+ endif()
+ # check whether we found 2.1.x
+ if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?1")
+ set(Ruby_VERSION_MAJOR 2)
+ set(Ruby_VERSION_MINOR 1)
+ endif()
+ # check whether we found 2.2.x
+ if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?2")
+ set(Ruby_VERSION_MAJOR 2)
+ set(Ruby_VERSION_MINOR 2)
+ endif()
+ # check whether we found 2.3.x
+ if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?3")
+ set(Ruby_VERSION_MAJOR 2)
+ set(Ruby_VERSION_MINOR 3)
+ endif()
+ # check whether we found 2.4.x
+ if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?4")
+ set(Ruby_VERSION_MAJOR 2)
+ set(Ruby_VERSION_MINOR 4)
+ endif()
+ # check whether we found 2.5.x
+ if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?5")
+ set(Ruby_VERSION_MAJOR 2)
+ set(Ruby_VERSION_MINOR 5)
+ endif()
+ # check whether we found 2.6.x
+ if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?6")
+ set(Ruby_VERSION_MAJOR 2)
+ set(Ruby_VERSION_MINOR 6)
+ endif()
+ # check whether we found 2.7.x
+ if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?7")
+ set(Ruby_VERSION_MAJOR 2)
+ set(Ruby_VERSION_MINOR 7)
+ endif()
+endif()
+
+if(Ruby_VERSION_MAJOR)
+ set(Ruby_VERSION "${Ruby_VERSION_MAJOR}.${Ruby_VERSION_MINOR}.${Ruby_VERSION_PATCH}")
+ set(_Ruby_VERSION_SHORT "${Ruby_VERSION_MAJOR}.${Ruby_VERSION_MINOR}")
+ set(_Ruby_VERSION_SHORT_NODOT "${Ruby_VERSION_MAJOR}${Ruby_VERSION_MINOR}")
+ set(_Ruby_NODOT_VERSION "${Ruby_VERSION_MAJOR}${Ruby_VERSION_MINOR}${Ruby_VERSION_PATCH}")
+ set(_Ruby_NODOT_VERSION_ZERO_PATCH "${Ruby_VERSION_MAJOR}${Ruby_VERSION_MINOR}0")
+endif()
+
+# FIXME: Currently we require both the interpreter and development components to be found
+# in order to use either. See issue #20474.
+find_path(Ruby_INCLUDE_DIR
+ NAMES ruby.h
+ HINTS
+ ${Ruby_HDR_DIR}
+ ${Ruby_ARCH_DIR}
+ /usr/lib/ruby/${_Ruby_VERSION_SHORT}/i586-linux-gnu/
+)
+
+set(Ruby_INCLUDE_DIRS ${Ruby_INCLUDE_DIR})
+
+# if ruby > 1.8 is required or if ruby > 1.8 was found, search for the config.h dir
+if( Ruby_FIND_VERSION VERSION_GREATER_EQUAL "1.9" OR Ruby_VERSION VERSION_GREATER_EQUAL "1.9" OR Ruby_HDR_DIR)
+ find_path(Ruby_CONFIG_INCLUDE_DIR
+ NAMES ruby/config.h config.h
+ HINTS
+ ${Ruby_HDR_DIR}/${Ruby_ARCH}
+ ${Ruby_ARCH_DIR}
+ ${Ruby_ARCHHDR_DIR}
+ )
+
+ set(Ruby_INCLUDE_DIRS ${Ruby_INCLUDE_DIRS} ${Ruby_CONFIG_INCLUDE_DIR} )
+endif()
+
+
+# Determine the list of possible names for the ruby library
+set(_Ruby_POSSIBLE_LIB_NAMES ruby ruby-static ruby${_Ruby_VERSION_SHORT} ruby${_Ruby_VERSION_SHORT_NODOT} ruby${_Ruby_NODOT_VERSION} ruby-${_Ruby_VERSION_SHORT} ruby-${Ruby_VERSION})
+
+if(WIN32)
+ set(_Ruby_POSSIBLE_MSVC_RUNTIMES "msvcrt;vcruntime140;vcruntime140_1")
+ if(MSVC_TOOLSET_VERSION)
+ list(APPEND _Ruby_POSSIBLE_MSVC_RUNTIMES "msvcr${MSVC_TOOLSET_VERSION}")
+ else()
+ list(APPEND _Ruby_POSSIBLE_MSVC_RUNTIMES "msvcr")
+ endif()
+
+ set(_Ruby_POSSIBLE_VERSION_SUFFICES "${_Ruby_NODOT_VERSION};${_Ruby_NODOT_VERSION_ZERO_PATCH}")
+
+ set(_Ruby_ARCH_PREFIX "")
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(_Ruby_ARCH_PREFIX "x64-")
+ endif()
+
+ foreach(_Ruby_MSVC_RUNTIME ${_Ruby_POSSIBLE_MSVC_RUNTIMES})
+ foreach(_Ruby_VERSION_SUFFIX ${_Ruby_POSSIBLE_VERSION_SUFFICES})
+ list(APPEND _Ruby_POSSIBLE_LIB_NAMES
+ "${_Ruby_ARCH_PREFIX}${_Ruby_MSVC_RUNTIME}-ruby${_Ruby_VERSION_SUFFIX}"
+ "${_Ruby_ARCH_PREFIX}${_Ruby_MSVC_RUNTIME}-ruby${_Ruby_VERSION_SUFFIX}-static")
+ endforeach()
+ endforeach()
+endif()
+
+find_library(Ruby_LIBRARY NAMES ${_Ruby_POSSIBLE_LIB_NAMES} HINTS ${Ruby_POSSIBLE_LIB_DIR} )
+
+set(_Ruby_REQUIRED_VARS Ruby_EXECUTABLE Ruby_INCLUDE_DIR Ruby_LIBRARY)
+if(_Ruby_VERSION_SHORT_NODOT GREATER 18)
+ list(APPEND _Ruby_REQUIRED_VARS Ruby_CONFIG_INCLUDE_DIR)
+endif()
+
+if(_Ruby_DEBUG_OUTPUT)
+ message(STATUS "--------FindRuby.cmake debug------------")
+ message(STATUS "_Ruby_POSSIBLE_EXECUTABLE_NAMES: ${_Ruby_POSSIBLE_EXECUTABLE_NAMES}")
+ message(STATUS "_Ruby_POSSIBLE_LIB_NAMES: ${_Ruby_POSSIBLE_LIB_NAMES}")
+ message(STATUS "Ruby_ARCH_DIR: ${Ruby_ARCH_DIR}")
+ message(STATUS "Ruby_HDR_DIR: ${Ruby_HDR_DIR}")
+ message(STATUS "Ruby_POSSIBLE_LIB_DIR: ${Ruby_POSSIBLE_LIB_DIR}")
+ message(STATUS "Found Ruby_VERSION: \"${Ruby_VERSION}\" , short: \"${_Ruby_VERSION_SHORT}\", nodot: \"${_Ruby_VERSION_SHORT_NODOT}\"")
+ message(STATUS "_Ruby_REQUIRED_VARS: ${_Ruby_REQUIRED_VARS}")
+ message(STATUS "Ruby_EXECUTABLE: ${Ruby_EXECUTABLE}")
+ message(STATUS "Ruby_LIBRARY: ${Ruby_LIBRARY}")
+ message(STATUS "Ruby_INCLUDE_DIR: ${Ruby_INCLUDE_DIR}")
+ message(STATUS "Ruby_CONFIG_INCLUDE_DIR: ${Ruby_CONFIG_INCLUDE_DIR}")
+ message(STATUS "--------------------")
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Ruby REQUIRED_VARS ${_Ruby_REQUIRED_VARS}
+ VERSION_VAR Ruby_VERSION )
+
+if(Ruby_FOUND)
+ set(Ruby_LIBRARIES ${Ruby_LIBRARY})
+endif()
+
+mark_as_advanced(
+ Ruby_EXECUTABLE
+ Ruby_LIBRARY
+ Ruby_INCLUDE_DIR
+ Ruby_CONFIG_INCLUDE_DIR
+ )
+
+# Set some variables for compatibility with previous version of this file (no need to provide a CamelCase version of that...)
+set(RUBY_POSSIBLE_LIB_PATH ${Ruby_POSSIBLE_LIB_DIR})
+set(RUBY_RUBY_LIB_PATH ${Ruby_RUBY_LIB_DIR})
+set(RUBY_INCLUDE_PATH ${Ruby_INCLUDE_DIRS})
+
+# Backwards compatibility
+# Define upper case versions of output variables
+foreach(Camel
+ Ruby_EXECUTABLE
+ Ruby_INCLUDE_DIRS
+ Ruby_LIBRARY
+ Ruby_VERSION
+ Ruby_VERSION_MAJOR
+ Ruby_VERSION_MINOR
+ Ruby_VERSION_PATCH
+
+ Ruby_ARCH_DIR
+ Ruby_ARCH
+ Ruby_HDR_DIR
+ Ruby_ARCHHDR_DIR
+ Ruby_POSSIBLE_LIB_DIR
+ Ruby_RUBY_LIB_DIR
+ Ruby_SITEARCH_DIR
+ Ruby_SITELIB_DIR
+ Ruby_HAS_VENDOR_RUBY
+ Ruby_VENDORARCH_DIR
+ Ruby_VENDORLIB_DIR
+
+ )
+ string(TOUPPER ${Camel} UPPER)
+ set(${UPPER} ${${Camel}})
+endforeach()
diff --git a/Modules/FindSDL.cmake b/Modules/FindSDL.cmake
new file mode 100644
index 0000000..c68e18d
--- /dev/null
+++ b/Modules/FindSDL.cmake
@@ -0,0 +1,237 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindSDL
+-------
+
+Locate the SDL library
+
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.19
+
+This module defines the following :prop_tgt:`IMPORTED` target:
+
+``SDL::SDL``
+ The SDL library, if found
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``SDL_INCLUDE_DIRS``
+ where to find SDL.h
+``SDL_LIBRARIES``
+ the name of the library to link against
+``SDL_FOUND``
+ if false, do not try to link to SDL
+``SDL_VERSION``
+ the human-readable string containing the version of SDL if found
+``SDL_VERSION_MAJOR``
+ SDL major version
+``SDL_VERSION_MINOR``
+ SDL minor version
+``SDL_VERSION_PATCH``
+ SDL patch version
+
+.. versionadded:: 3.19
+ Added the ``SDL_INCLUDE_DIRS``, ``SDL_LIBRARIES`` and ``SDL_VERSION[_<PART>]``
+ variables.
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+These variables may optionally be set to help this module find the correct files:
+
+``SDL_INCLUDE_DIR``
+ where to find SDL.h
+``SDL_LIBRARY``
+ the name of the library to link against
+
+
+Variables for locating SDL
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This module responds to the flag:
+
+``SDL_BUILDING_LIBRARY``
+ If this is defined, then no SDL_main will be linked in because
+ only applications need main().
+ Otherwise, it is assumed you are building an application and this
+ module will attempt to locate and set the proper link flags
+ as part of the returned SDL_LIBRARY variable.
+
+
+Obsolete variables
+^^^^^^^^^^^^^^^^^^
+
+.. deprecated:: 3.19
+
+These variables are obsolete and provided for backwards compatibility:
+
+``SDL_VERSION_STRING``
+ the human-readable string containing the version of SDL if found.
+ Identical to SDL_VERSION
+
+
+Don't forget to include SDLmain.h and SDLmain.m your project for the
+OS X framework based version. (Other versions link to -lSDLmain which
+this module will try to find on your behalf.) Also for OS X, this
+module will automatically add the -framework Cocoa on your behalf.
+
+
+
+Additional Note: If you see an empty SDL_LIBRARY_TEMP in your
+configuration and no SDL_LIBRARY, it means CMake did not find your SDL
+library (SDL.dll, libsdl.so, SDL.framework, etc). Set
+SDL_LIBRARY_TEMP to point to your SDL library, and configure again.
+Similarly, if you see an empty SDLMAIN_LIBRARY, you should set this
+value as appropriate. These values are used to generate the final
+SDL_LIBRARY variable, but when these values are unset, SDL_LIBRARY
+does not get created.
+
+
+
+$SDLDIR is an environment variable that would correspond to the
+./configure --prefix=$SDLDIR used in building SDL. l.e.galup 9-20-02
+
+On OSX, this will prefer the Framework version (if found) over others.
+People will have to manually change the cache values of SDL_LIBRARY to
+override this selection or set the CMake environment
+CMAKE_INCLUDE_PATH to modify the search paths.
+
+Note that the header path has changed from SDL/SDL.h to just SDL.h
+This needed to change because "proper" SDL convention is #include
+"SDL.h", not <SDL/SDL.h>. This is done for portability reasons
+because not all systems place things in SDL/ (see FreeBSD).
+#]=======================================================================]
+
+find_path(SDL_INCLUDE_DIR SDL.h
+ HINTS
+ ENV SDLDIR
+ PATH_SUFFIXES SDL SDL12 SDL11
+ # path suffixes to search inside ENV{SDLDIR}
+ include/SDL include/SDL12 include/SDL11 include
+)
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(VC_LIB_PATH_SUFFIX lib/x64)
+else()
+ set(VC_LIB_PATH_SUFFIX lib/x86)
+endif()
+
+# SDL-1.1 is the name used by FreeBSD ports...
+# don't confuse it for the version number.
+find_library(SDL_LIBRARY_TEMP
+ NAMES SDL SDL-1.1
+ HINTS
+ ENV SDLDIR
+ PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
+)
+
+# Hide this cache variable from the user, it's an internal implementation
+# detail. The documented library variable for the user is SDL_LIBRARY
+# which is derived from SDL_LIBRARY_TEMP further below.
+set_property(CACHE SDL_LIBRARY_TEMP PROPERTY TYPE INTERNAL)
+
+if(NOT SDL_BUILDING_LIBRARY)
+ if(NOT SDL_INCLUDE_DIR MATCHES ".framework")
+ # Non-OS X framework versions expect you to also dynamically link to
+ # SDLmain. This is mainly for Windows and OS X. Other (Unix) platforms
+ # seem to provide SDLmain for compatibility even though they don't
+ # necessarily need it.
+ find_library(SDLMAIN_LIBRARY
+ NAMES SDLmain SDLmain-1.1
+ HINTS
+ ENV SDLDIR
+ PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
+ PATHS
+ /opt
+ )
+ endif()
+endif()
+
+# SDL may require threads on your system.
+# The Apple build may not need an explicit flag because one of the
+# frameworks may already provide it.
+# But for non-OSX systems, I will use the CMake Threads package.
+if(NOT APPLE)
+ find_package(Threads)
+endif()
+
+# MinGW needs an additional link flag, -mwindows
+# It's total link flags should look like -lmingw32 -lSDLmain -lSDL -mwindows
+if(MINGW)
+ set(MINGW32_LIBRARY mingw32 "-mwindows" CACHE STRING "link flags for MinGW")
+endif()
+
+if(SDL_LIBRARY_TEMP)
+ # For SDLmain
+ if(SDLMAIN_LIBRARY AND NOT SDL_BUILDING_LIBRARY)
+ list(FIND SDL_LIBRARY_TEMP "${SDLMAIN_LIBRARY}" _SDL_MAIN_INDEX)
+ if(_SDL_MAIN_INDEX EQUAL -1)
+ set(SDL_LIBRARY_TEMP "${SDLMAIN_LIBRARY}" ${SDL_LIBRARY_TEMP})
+ endif()
+ unset(_SDL_MAIN_INDEX)
+ endif()
+
+ # For OS X, SDL uses Cocoa as a backend so it must link to Cocoa.
+ # CMake doesn't display the -framework Cocoa string in the UI even
+ # though it actually is there if I modify a pre-used variable.
+ # I think it has something to do with the CACHE STRING.
+ # So I use a temporary variable until the end so I can set the
+ # "real" variable in one-shot.
+ if(APPLE)
+ set(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} "-framework Cocoa")
+ endif()
+
+ # For threads, as mentioned Apple doesn't need this.
+ # In fact, there seems to be a problem if I used the Threads package
+ # and try using this line, so I'm just skipping it entirely for OS X.
+ if(NOT APPLE)
+ set(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
+ endif()
+
+ # For MinGW library
+ if(MINGW)
+ set(SDL_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL_LIBRARY_TEMP})
+ endif()
+
+ # Set the final string here so the GUI reflects the final state.
+ set(SDL_LIBRARY ${SDL_LIBRARY_TEMP} CACHE STRING "Where the SDL Library can be found")
+endif()
+
+if(SDL_INCLUDE_DIR AND EXISTS "${SDL_INCLUDE_DIR}/SDL_version.h")
+ file(STRINGS "${SDL_INCLUDE_DIR}/SDL_version.h" SDL_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+[0-9]+$")
+ file(STRINGS "${SDL_INCLUDE_DIR}/SDL_version.h" SDL_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MINOR_VERSION[ \t]+[0-9]+$")
+ file(STRINGS "${SDL_INCLUDE_DIR}/SDL_version.h" SDL_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_PATCHLEVEL[ \t]+[0-9]+$")
+ string(REGEX REPLACE "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_VERSION_MAJOR "${SDL_VERSION_MAJOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_VERSION_MINOR "${SDL_VERSION_MINOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL_VERSION_PATCH "${SDL_VERSION_PATCH_LINE}")
+ unset(SDL_VERSION_MAJOR_LINE)
+ unset(SDL_VERSION_MINOR_LINE)
+ unset(SDL_VERSION_PATCH_LINE)
+ set(SDL_VERSION ${SDL_VERSION_MAJOR}.${SDL_VERSION_MINOR}.${SDL_VERSION_PATCH})
+ set(SDL_VERSION_STRING ${SDL_VERSION})
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL
+ REQUIRED_VARS SDL_LIBRARY SDL_INCLUDE_DIR
+ VERSION_VAR SDL_VERSION_STRING)
+
+if(SDL_FOUND)
+ set(SDL_LIBRARIES ${SDL_LIBRARY})
+ set(SDL_INCLUDE_DIRS ${SDL_INCLUDE_DIR})
+ if(NOT TARGET SDL::SDL)
+ add_library(SDL::SDL INTERFACE IMPORTED)
+ set_target_properties(SDL::SDL PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${SDL_INCLUDE_DIR}"
+ INTERFACE_LINK_LIBRARIES "${SDL_LIBRARY}")
+ endif()
+endif()
diff --git a/Modules/FindSDL_image.cmake b/Modules/FindSDL_image.cmake
new file mode 100644
index 0000000..e687b49
--- /dev/null
+++ b/Modules/FindSDL_image.cmake
@@ -0,0 +1,101 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindSDL_image
+-------------
+
+Locate SDL_image library
+
+This module defines:
+
+::
+
+ SDL_IMAGE_LIBRARIES, the name of the library to link against
+ SDL_IMAGE_INCLUDE_DIRS, where to find the headers
+ SDL_IMAGE_FOUND, if false, do not try to link against
+ SDL_IMAGE_VERSION_STRING - human-readable string containing the
+ version of SDL_image
+
+
+
+For backward compatibility the following variables are also set:
+
+::
+
+ SDLIMAGE_LIBRARY (same value as SDL_IMAGE_LIBRARIES)
+ SDLIMAGE_INCLUDE_DIR (same value as SDL_IMAGE_INCLUDE_DIRS)
+ SDLIMAGE_FOUND (same value as SDL_IMAGE_FOUND)
+
+
+
+$SDLDIR is an environment variable that would correspond to the
+./configure --prefix=$SDLDIR used in building SDL.
+
+Created by Eric Wing. This was influenced by the FindSDL.cmake
+module, but with modifications to recognize OS X frameworks and
+additional Unix paths (FreeBSD, etc).
+#]=======================================================================]
+
+if(NOT SDL_IMAGE_INCLUDE_DIR AND SDLIMAGE_INCLUDE_DIR)
+ set(SDL_IMAGE_INCLUDE_DIR ${SDLIMAGE_INCLUDE_DIR} CACHE PATH "directory cache
+entry initialized from old variable name")
+endif()
+find_path(SDL_IMAGE_INCLUDE_DIR SDL_image.h
+ HINTS
+ ENV SDLIMAGEDIR
+ ENV SDLDIR
+ PATH_SUFFIXES SDL
+ # path suffixes to search inside ENV{SDLDIR}
+ include/SDL include/SDL12 include/SDL11 include
+)
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(VC_LIB_PATH_SUFFIX lib/x64)
+else()
+ set(VC_LIB_PATH_SUFFIX lib/x86)
+endif()
+
+if(NOT SDL_IMAGE_LIBRARY AND SDLIMAGE_LIBRARY)
+ set(SDL_IMAGE_LIBRARY ${SDLIMAGE_LIBRARY} CACHE FILEPATH "file cache entry
+initialized from old variable name")
+endif()
+find_library(SDL_IMAGE_LIBRARY
+ NAMES SDL_image
+ HINTS
+ ENV SDLIMAGEDIR
+ ENV SDLDIR
+ PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
+)
+
+if(SDL_IMAGE_INCLUDE_DIR AND EXISTS "${SDL_IMAGE_INCLUDE_DIR}/SDL_image.h")
+ file(STRINGS "${SDL_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL_IMAGE_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+[0-9]+$")
+ file(STRINGS "${SDL_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL_IMAGE_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+[0-9]+$")
+ file(STRINGS "${SDL_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL_IMAGE_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+[0-9]+$")
+ string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_IMAGE_VERSION_MAJOR "${SDL_IMAGE_VERSION_MAJOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_IMAGE_VERSION_MINOR "${SDL_IMAGE_VERSION_MINOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL_IMAGE_VERSION_PATCH "${SDL_IMAGE_VERSION_PATCH_LINE}")
+ set(SDL_IMAGE_VERSION_STRING ${SDL_IMAGE_VERSION_MAJOR}.${SDL_IMAGE_VERSION_MINOR}.${SDL_IMAGE_VERSION_PATCH})
+ unset(SDL_IMAGE_VERSION_MAJOR_LINE)
+ unset(SDL_IMAGE_VERSION_MINOR_LINE)
+ unset(SDL_IMAGE_VERSION_PATCH_LINE)
+ unset(SDL_IMAGE_VERSION_MAJOR)
+ unset(SDL_IMAGE_VERSION_MINOR)
+ unset(SDL_IMAGE_VERSION_PATCH)
+endif()
+
+set(SDL_IMAGE_LIBRARIES ${SDL_IMAGE_LIBRARY})
+set(SDL_IMAGE_INCLUDE_DIRS ${SDL_IMAGE_INCLUDE_DIR})
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL_image
+ REQUIRED_VARS SDL_IMAGE_LIBRARIES SDL_IMAGE_INCLUDE_DIRS
+ VERSION_VAR SDL_IMAGE_VERSION_STRING)
+
+# for backward compatibility
+set(SDLIMAGE_LIBRARY ${SDL_IMAGE_LIBRARIES})
+set(SDLIMAGE_INCLUDE_DIR ${SDL_IMAGE_INCLUDE_DIRS})
+set(SDLIMAGE_FOUND ${SDL_IMAGE_FOUND})
+
+mark_as_advanced(SDL_IMAGE_LIBRARY SDL_IMAGE_INCLUDE_DIR)
diff --git a/Modules/FindSDL_mixer.cmake b/Modules/FindSDL_mixer.cmake
new file mode 100644
index 0000000..315400a
--- /dev/null
+++ b/Modules/FindSDL_mixer.cmake
@@ -0,0 +1,101 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindSDL_mixer
+-------------
+
+Locate SDL_mixer library
+
+This module defines:
+
+::
+
+ SDL_MIXER_LIBRARIES, the name of the library to link against
+ SDL_MIXER_INCLUDE_DIRS, where to find the headers
+ SDL_MIXER_FOUND, if false, do not try to link against
+ SDL_MIXER_VERSION_STRING - human-readable string containing the
+ version of SDL_mixer
+
+
+
+For backward compatibility the following variables are also set:
+
+::
+
+ SDLMIXER_LIBRARY (same value as SDL_MIXER_LIBRARIES)
+ SDLMIXER_INCLUDE_DIR (same value as SDL_MIXER_INCLUDE_DIRS)
+ SDLMIXER_FOUND (same value as SDL_MIXER_FOUND)
+
+
+
+$SDLDIR is an environment variable that would correspond to the
+./configure --prefix=$SDLDIR used in building SDL.
+
+Created by Eric Wing. This was influenced by the FindSDL.cmake
+module, but with modifications to recognize OS X frameworks and
+additional Unix paths (FreeBSD, etc).
+#]=======================================================================]
+
+if(NOT SDL_MIXER_INCLUDE_DIR AND SDLMIXER_INCLUDE_DIR)
+ set(SDL_MIXER_INCLUDE_DIR ${SDLMIXER_INCLUDE_DIR} CACHE PATH "directory cache
+entry initialized from old variable name")
+endif()
+find_path(SDL_MIXER_INCLUDE_DIR SDL_mixer.h
+ HINTS
+ ENV SDLMIXERDIR
+ ENV SDLDIR
+ PATH_SUFFIXES SDL
+ # path suffixes to search inside ENV{SDLDIR}
+ include/SDL include/SDL12 include/SDL11 include
+)
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(VC_LIB_PATH_SUFFIX lib/x64)
+else()
+ set(VC_LIB_PATH_SUFFIX lib/x86)
+endif()
+
+if(NOT SDL_MIXER_LIBRARY AND SDLMIXER_LIBRARY)
+ set(SDL_MIXER_LIBRARY ${SDLMIXER_LIBRARY} CACHE FILEPATH "file cache entry
+initialized from old variable name")
+endif()
+find_library(SDL_MIXER_LIBRARY
+ NAMES SDL_mixer
+ HINTS
+ ENV SDLMIXERDIR
+ ENV SDLDIR
+ PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
+)
+
+if(SDL_MIXER_INCLUDE_DIR AND EXISTS "${SDL_MIXER_INCLUDE_DIR}/SDL_mixer.h")
+ file(STRINGS "${SDL_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL_MIXER_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MIXER_MAJOR_VERSION[ \t]+[0-9]+$")
+ file(STRINGS "${SDL_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL_MIXER_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MIXER_MINOR_VERSION[ \t]+[0-9]+$")
+ file(STRINGS "${SDL_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL_MIXER_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_MIXER_PATCHLEVEL[ \t]+[0-9]+$")
+ string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_MIXER_VERSION_MAJOR "${SDL_MIXER_VERSION_MAJOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_MIXER_VERSION_MINOR "${SDL_MIXER_VERSION_MINOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL_MIXER_VERSION_PATCH "${SDL_MIXER_VERSION_PATCH_LINE}")
+ set(SDL_MIXER_VERSION_STRING ${SDL_MIXER_VERSION_MAJOR}.${SDL_MIXER_VERSION_MINOR}.${SDL_MIXER_VERSION_PATCH})
+ unset(SDL_MIXER_VERSION_MAJOR_LINE)
+ unset(SDL_MIXER_VERSION_MINOR_LINE)
+ unset(SDL_MIXER_VERSION_PATCH_LINE)
+ unset(SDL_MIXER_VERSION_MAJOR)
+ unset(SDL_MIXER_VERSION_MINOR)
+ unset(SDL_MIXER_VERSION_PATCH)
+endif()
+
+set(SDL_MIXER_LIBRARIES ${SDL_MIXER_LIBRARY})
+set(SDL_MIXER_INCLUDE_DIRS ${SDL_MIXER_INCLUDE_DIR})
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL_mixer
+ REQUIRED_VARS SDL_MIXER_LIBRARIES SDL_MIXER_INCLUDE_DIRS
+ VERSION_VAR SDL_MIXER_VERSION_STRING)
+
+# for backward compatibility
+set(SDLMIXER_LIBRARY ${SDL_MIXER_LIBRARIES})
+set(SDLMIXER_INCLUDE_DIR ${SDL_MIXER_INCLUDE_DIRS})
+set(SDLMIXER_FOUND ${SDL_MIXER_FOUND})
+
+mark_as_advanced(SDL_MIXER_LIBRARY SDL_MIXER_INCLUDE_DIR)
diff --git a/Modules/FindSDL_net.cmake b/Modules/FindSDL_net.cmake
new file mode 100644
index 0000000..28cb4d6
--- /dev/null
+++ b/Modules/FindSDL_net.cmake
@@ -0,0 +1,100 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindSDL_net
+-----------
+
+Locate SDL_net library
+
+This module defines:
+
+::
+
+ SDL_NET_LIBRARIES, the name of the library to link against
+ SDL_NET_INCLUDE_DIRS, where to find the headers
+ SDL_NET_FOUND, if false, do not try to link against
+ SDL_NET_VERSION_STRING - human-readable string containing the version of SDL_net
+
+
+
+For backward compatibility the following variables are also set:
+
+::
+
+ SDLNET_LIBRARY (same value as SDL_NET_LIBRARIES)
+ SDLNET_INCLUDE_DIR (same value as SDL_NET_INCLUDE_DIRS)
+ SDLNET_FOUND (same value as SDL_NET_FOUND)
+
+
+
+$SDLDIR is an environment variable that would correspond to the
+./configure --prefix=$SDLDIR used in building SDL.
+
+Created by Eric Wing. This was influenced by the FindSDL.cmake
+module, but with modifications to recognize OS X frameworks and
+additional Unix paths (FreeBSD, etc).
+#]=======================================================================]
+
+if(NOT SDL_NET_INCLUDE_DIR AND SDLNET_INCLUDE_DIR)
+ set(SDL_NET_INCLUDE_DIR ${SDLNET_INCLUDE_DIR} CACHE PATH "directory cache
+entry initialized from old variable name")
+endif()
+find_path(SDL_NET_INCLUDE_DIR SDL_net.h
+ HINTS
+ ENV SDLNETDIR
+ ENV SDLDIR
+ PATH_SUFFIXES SDL
+ # path suffixes to search inside ENV{SDLDIR}
+ include/SDL include/SDL12 include/SDL11 include
+)
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(VC_LIB_PATH_SUFFIX lib/x64)
+else()
+ set(VC_LIB_PATH_SUFFIX lib/x86)
+endif()
+
+if(NOT SDL_NET_LIBRARY AND SDLNET_LIBRARY)
+ set(SDL_NET_LIBRARY ${SDLNET_LIBRARY} CACHE FILEPATH "file cache entry
+initialized from old variable name")
+endif()
+find_library(SDL_NET_LIBRARY
+ NAMES SDL_net
+ HINTS
+ ENV SDLNETDIR
+ ENV SDLDIR
+ PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
+)
+
+if(SDL_NET_INCLUDE_DIR AND EXISTS "${SDL_NET_INCLUDE_DIR}/SDL_net.h")
+ file(STRINGS "${SDL_NET_INCLUDE_DIR}/SDL_net.h" SDL_NET_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_NET_MAJOR_VERSION[ \t]+[0-9]+$")
+ file(STRINGS "${SDL_NET_INCLUDE_DIR}/SDL_net.h" SDL_NET_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_NET_MINOR_VERSION[ \t]+[0-9]+$")
+ file(STRINGS "${SDL_NET_INCLUDE_DIR}/SDL_net.h" SDL_NET_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_NET_PATCHLEVEL[ \t]+[0-9]+$")
+ string(REGEX REPLACE "^#define[ \t]+SDL_NET_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_NET_VERSION_MAJOR "${SDL_NET_VERSION_MAJOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SDL_NET_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_NET_VERSION_MINOR "${SDL_NET_VERSION_MINOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SDL_NET_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL_NET_VERSION_PATCH "${SDL_NET_VERSION_PATCH_LINE}")
+ set(SDL_NET_VERSION_STRING ${SDL_NET_VERSION_MAJOR}.${SDL_NET_VERSION_MINOR}.${SDL_NET_VERSION_PATCH})
+ unset(SDL_NET_VERSION_MAJOR_LINE)
+ unset(SDL_NET_VERSION_MINOR_LINE)
+ unset(SDL_NET_VERSION_PATCH_LINE)
+ unset(SDL_NET_VERSION_MAJOR)
+ unset(SDL_NET_VERSION_MINOR)
+ unset(SDL_NET_VERSION_PATCH)
+endif()
+
+set(SDL_NET_LIBRARIES ${SDL_NET_LIBRARY})
+set(SDL_NET_INCLUDE_DIRS ${SDL_NET_INCLUDE_DIR})
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL_net
+ REQUIRED_VARS SDL_NET_LIBRARIES SDL_NET_INCLUDE_DIRS
+ VERSION_VAR SDL_NET_VERSION_STRING)
+
+# for backward compatibility
+set(SDLNET_LIBRARY ${SDL_NET_LIBRARIES})
+set(SDLNET_INCLUDE_DIR ${SDL_NET_INCLUDE_DIRS})
+set(SDLNET_FOUND ${SDL_NET_FOUND})
+
+mark_as_advanced(SDL_NET_LIBRARY SDL_NET_INCLUDE_DIR)
diff --git a/Modules/FindSDL_sound.cmake b/Modules/FindSDL_sound.cmake
new file mode 100644
index 0000000..8d2f9f8
--- /dev/null
+++ b/Modules/FindSDL_sound.cmake
@@ -0,0 +1,370 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindSDL_sound
+-------------
+
+Locates the SDL_sound library
+
+
+
+This module depends on SDL being found and must be called AFTER
+FindSDL.cmake is called.
+
+This module defines
+
+::
+
+ SDL_SOUND_INCLUDE_DIR, where to find SDL_sound.h
+ SDL_SOUND_FOUND, if false, do not try to link to SDL_sound
+ SDL_SOUND_LIBRARIES, this contains the list of libraries that you need
+ to link against.
+ SDL_SOUND_EXTRAS, this is an optional variable for you to add your own
+ flags to SDL_SOUND_LIBRARIES. This is prepended to SDL_SOUND_LIBRARIES.
+ This is available mostly for cases this module failed to anticipate for
+ and you must add additional flags. This is marked as ADVANCED.
+ SDL_SOUND_VERSION_STRING, human-readable string containing the
+ version of SDL_sound
+
+
+
+This module also defines (but you shouldn't need to use directly)
+
+::
+
+ SDL_SOUND_LIBRARY, the name of just the SDL_sound library you would link
+ against. Use SDL_SOUND_LIBRARIES for you link instructions and not this one.
+
+And might define the following as needed
+
+::
+
+ MIKMOD_LIBRARY
+ MODPLUG_LIBRARY
+ OGG_LIBRARY
+ VORBIS_LIBRARY
+ SMPEG_LIBRARY
+ FLAC_LIBRARY
+ SPEEX_LIBRARY
+
+
+
+Typically, you should not use these variables directly, and you should
+use SDL_SOUND_LIBRARIES which contains SDL_SOUND_LIBRARY and the other
+audio libraries (if needed) to successfully compile on your system.
+
+Created by Eric Wing. This module is a bit more complicated than the
+other FindSDL* family modules. The reason is that SDL_sound can be
+compiled in a large variety of different ways which are independent of
+platform. SDL_sound may dynamically link against other 3rd party
+libraries to get additional codec support, such as Ogg Vorbis, SMPEG,
+ModPlug, MikMod, FLAC, Speex, and potentially others. Under some
+circumstances which I don't fully understand, there seems to be a
+requirement that dependent libraries of libraries you use must also be
+explicitly linked against in order to successfully compile. SDL_sound
+does not currently have any system in place to know how it was
+compiled. So this CMake module does the hard work in trying to
+discover which 3rd party libraries are required for building (if any).
+This module uses a brute force approach to create a test program that
+uses SDL_sound, and then tries to build it. If the build fails, it
+parses the error output for known symbol names to figure out which
+libraries are needed.
+
+Responds to the $SDLDIR and $SDLSOUNDDIR environmental variable that
+would correspond to the ./configure --prefix=$SDLDIR used in building
+SDL.
+
+On OSX, this will prefer the Framework version (if found) over others.
+People will have to manually change the cache values of SDL_LIBRARY to
+override this selectionor set the CMake environment CMAKE_INCLUDE_PATH
+to modify the search paths.
+#]=======================================================================]
+
+set(SDL_SOUND_EXTRAS "" CACHE STRING "SDL_sound extra flags")
+mark_as_advanced(SDL_SOUND_EXTRAS)
+
+# Find SDL_sound.h
+find_path(SDL_SOUND_INCLUDE_DIR SDL_sound.h
+ HINTS
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ PATH_SUFFIXES SDL
+ # path suffixes to search inside ENV{SDLDIR}
+ include/SDL include/SDL12 include/SDL11 include
+ )
+
+find_library(SDL_SOUND_LIBRARY
+ NAMES SDL_sound
+ HINTS
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ PATH_SUFFIXES lib VisualC/win32lib
+ )
+
+if(SDL_FOUND AND SDL_SOUND_INCLUDE_DIR AND SDL_SOUND_LIBRARY)
+
+ # CMake is giving me problems using TRY_COMPILE with the CMAKE_FLAGS
+ # for the :STRING syntax if I have multiple values contained in a
+ # single variable. This is a problem for the SDL_LIBRARY variable
+ # because it does just that. When I feed this variable to the command,
+ # only the first value gets the appropriate modifier (e.g. -I) and
+ # the rest get dropped.
+ # To get multiple single variables to work, I must separate them with a "\;"
+ # I could go back and modify the FindSDL.cmake module, but that's kind of painful.
+ # The solution would be to try something like:
+ # string(APPEND SDL_TRY_COMPILE_LIBRARY_LIST "\;${CMAKE_THREAD_LIBS_INIT}")
+ # Instead, it was suggested on the mailing list to write a temporary CMakeLists.txt
+ # with a temporary test project and invoke that with TRY_COMPILE.
+ # See message thread "Figuring out dependencies for a library in order to build"
+ # 2005-07-16
+ # try_compile(
+ # MY_RESULT
+ # ${CMAKE_BINARY_DIR}
+ # ${PROJECT_SOURCE_DIR}/DetermineSoundLibs.c
+ # CMAKE_FLAGS
+ # -DINCLUDE_DIRECTORIES:STRING=${SDL_INCLUDE_DIR}\;${SDL_SOUND_INCLUDE_DIR}
+ # -DLINK_LIBRARIES:STRING=${SDL_SOUND_LIBRARY}\;${SDL_LIBRARY}
+ # OUTPUT_VARIABLE MY_OUTPUT
+ # )
+
+ # To minimize external dependencies, create a sdlsound test program
+ # which will be used to figure out if additional link dependencies are
+ # required for the link phase.
+ file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/DetermineSoundLibs.c
+ "#include \"SDL_sound.h\"
+ #include \"SDL.h\"
+ int main(int argc, char* argv[])
+ {
+ Sound_AudioInfo desired;
+ Sound_Sample* sample;
+
+ SDL_Init(0);
+ Sound_Init();
+
+ /* This doesn't actually have to work, but Init() is a no-op
+ * for some of the decoders, so this should force more symbols
+ * to be pulled in.
+ */
+ sample = Sound_NewSampleFromFile(argv[1], &desired, 4096);
+
+ Sound_Quit();
+ SDL_Quit();
+ return 0;
+ }"
+ )
+
+ # Calling
+ # target_link_libraries(DetermineSoundLibs "${SDL_SOUND_LIBRARY} ${SDL_LIBRARY})
+ # causes problems when SDL_LIBRARY looks like
+ # /Library/Frameworks/SDL.framework;-framework Cocoa
+ # The ;-framework Cocoa seems to be confusing CMake once the OS X
+ # framework support was added. I was told that breaking up the list
+ # would fix the problem.
+ set(TMP_TRY_LIBS)
+ foreach(lib ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY})
+ string(APPEND TMP_TRY_LIBS " \"${lib}\"")
+ endforeach()
+
+
+ # Write the CMakeLists.txt and test project
+ # Weird, this is still sketchy. If I don't quote the variables
+ # in the TARGET_LINK_LIBRARIES, I seem to loose everything
+ # in the SDL_LIBRARY string after the "-framework".
+ # But if I quote the stuff in INCLUDE_DIRECTORIES, it doesn't work.
+ file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/CMakeLists.txt
+ "cmake_minimum_required(VERSION ${CMAKE_VERSION})
+ project(DetermineSoundLibs)
+ include_directories(${SDL_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR})
+ add_executable(DetermineSoundLibs DetermineSoundLibs.c)
+ target_link_libraries(DetermineSoundLibs ${TMP_TRY_LIBS})"
+ )
+
+ try_compile(
+ MY_RESULT
+ ${PROJECT_BINARY_DIR}/CMakeTmp
+ ${PROJECT_BINARY_DIR}/CMakeTmp
+ DetermineSoundLibs
+ OUTPUT_VARIABLE MY_OUTPUT
+ )
+
+
+ if(NOT MY_RESULT)
+
+ # I expect that MPGLIB, VOC, WAV, AIFF, and SHN are compiled in statically.
+ # I think Timidity is also compiled in statically.
+ # I've never had to explcitly link against Quicktime, so I'll skip that for now.
+
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY})
+
+ # Find MikMod
+ if("${MY_OUTPUT}" MATCHES "MikMod_")
+ find_library(MIKMOD_LIBRARY
+ NAMES libmikmod-coreaudio mikmod
+ PATHS
+ ENV MIKMODDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(MIKMOD_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MIKMOD_LIBRARY})
+ endif(MIKMOD_LIBRARY)
+ endif("${MY_OUTPUT}" MATCHES "MikMod_")
+
+ # Find ModPlug
+ if("${MY_OUTPUT}" MATCHES "MODPLUG_")
+ find_library(MODPLUG_LIBRARY
+ NAMES modplug
+ PATHS
+ ENV MODPLUGDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(MODPLUG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MODPLUG_LIBRARY})
+ endif()
+ endif()
+
+
+ # Find Ogg and Vorbis
+ if("${MY_OUTPUT}" MATCHES "ov_")
+ find_library(VORBIS_LIBRARY
+ NAMES vorbis Vorbis VORBIS
+ PATHS
+ ENV VORBISDIR
+ ENV OGGDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(VORBIS_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBIS_LIBRARY})
+ endif()
+
+ find_library(OGG_LIBRARY
+ NAMES ogg Ogg OGG
+ PATHS
+ ENV OGGDIR
+ ENV VORBISDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(OGG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
+ endif()
+ endif()
+
+
+ # Find SMPEG
+ if("${MY_OUTPUT}" MATCHES "SMPEG_")
+ find_library(SMPEG_LIBRARY
+ NAMES smpeg SMPEG Smpeg SMpeg
+ PATHS
+ ENV SMPEGDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(SMPEG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SMPEG_LIBRARY})
+ endif()
+ endif()
+
+
+ # Find FLAC
+ if("${MY_OUTPUT}" MATCHES "FLAC_")
+ find_library(FLAC_LIBRARY
+ NAMES flac FLAC
+ PATHS
+ ENV FLACDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(FLAC_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${FLAC_LIBRARY})
+ endif()
+ endif()
+
+
+ # Hmmm...Speex seems to depend on Ogg. This might be a problem if
+ # the TRY_COMPILE attempt gets blocked at SPEEX before it can pull
+ # in the Ogg symbols. I'm not sure if I should duplicate the ogg stuff
+ # above for here or if two ogg entries will screw up things.
+ if("${MY_OUTPUT}" MATCHES "speex_")
+ find_library(SPEEX_LIBRARY
+ NAMES speex SPEEX
+ PATHS
+ ENV SPEEXDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(SPEEX_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SPEEX_LIBRARY})
+ endif()
+
+ # Find OGG (needed for Speex)
+ # We might have already found Ogg for Vorbis, so skip it if so.
+ if(NOT OGG_LIBRARY)
+ find_library(OGG_LIBRARY
+ NAMES ogg Ogg OGG
+ PATHS
+ ENV OGGDIR
+ ENV VORBISDIR
+ ENV SPEEXDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /opt
+ PATH_SUFFIXES lib
+ )
+ if(OGG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
+ endif()
+ endif()
+ endif()
+
+ set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARIES_TMP})
+ else()
+ set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARY})
+ endif()
+ endif()
+
+if(SDL_SOUND_INCLUDE_DIR AND EXISTS "${SDL_SOUND_INCLUDE_DIR}/SDL_sound.h")
+ file(STRINGS "${SDL_SOUND_INCLUDE_DIR}/SDL_sound.h" SDL_SOUND_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SOUND_VER_MAJOR[ \t]+[0-9]+$")
+ file(STRINGS "${SDL_SOUND_INCLUDE_DIR}/SDL_sound.h" SDL_SOUND_VERSION_MINOR_LINE REGEX "^#define[ \t]+SOUND_VER_MINOR[ \t]+[0-9]+$")
+ file(STRINGS "${SDL_SOUND_INCLUDE_DIR}/SDL_sound.h" SDL_SOUND_VERSION_PATCH_LINE REGEX "^#define[ \t]+SOUND_VER_PATCH[ \t]+[0-9]+$")
+ string(REGEX REPLACE "^#define[ \t]+SOUND_VER_MAJOR[ \t]+([0-9]+)$" "\\1" SDL_SOUND_VERSION_MAJOR "${SDL_SOUND_VERSION_MAJOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SOUND_VER_MINOR[ \t]+([0-9]+)$" "\\1" SDL_SOUND_VERSION_MINOR "${SDL_SOUND_VERSION_MINOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SOUND_VER_PATCH[ \t]+([0-9]+)$" "\\1" SDL_SOUND_VERSION_PATCH "${SDL_SOUND_VERSION_PATCH_LINE}")
+ set(SDL_SOUND_VERSION_STRING ${SDL_SOUND_VERSION_MAJOR}.${SDL_SOUND_VERSION_MINOR}.${SDL_SOUND_VERSION_PATCH})
+ unset(SDL_SOUND_VERSION_MAJOR_LINE)
+ unset(SDL_SOUND_VERSION_MINOR_LINE)
+ unset(SDL_SOUND_VERSION_PATCH_LINE)
+ unset(SDL_SOUND_VERSION_MAJOR)
+ unset(SDL_SOUND_VERSION_MINOR)
+ unset(SDL_SOUND_VERSION_PATCH)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL_sound
+ REQUIRED_VARS SDL_SOUND_LIBRARY SDL_SOUND_INCLUDE_DIR
+ VERSION_VAR SDL_SOUND_VERSION_STRING)
diff --git a/Modules/FindSDL_ttf.cmake b/Modules/FindSDL_ttf.cmake
new file mode 100644
index 0000000..d5721da
--- /dev/null
+++ b/Modules/FindSDL_ttf.cmake
@@ -0,0 +1,100 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindSDL_ttf
+-----------
+
+Locate SDL_ttf library
+
+This module defines:
+
+::
+
+ SDL_TTF_LIBRARIES, the name of the library to link against
+ SDL_TTF_INCLUDE_DIRS, where to find the headers
+ SDL_TTF_FOUND, if false, do not try to link against
+ SDL_TTF_VERSION_STRING - human-readable string containing the version of SDL_ttf
+
+
+
+For backward compatibility the following variables are also set:
+
+::
+
+ SDLTTF_LIBRARY (same value as SDL_TTF_LIBRARIES)
+ SDLTTF_INCLUDE_DIR (same value as SDL_TTF_INCLUDE_DIRS)
+ SDLTTF_FOUND (same value as SDL_TTF_FOUND)
+
+
+
+$SDLDIR is an environment variable that would correspond to the
+./configure --prefix=$SDLDIR used in building SDL.
+
+Created by Eric Wing. This was influenced by the FindSDL.cmake
+module, but with modifications to recognize OS X frameworks and
+additional Unix paths (FreeBSD, etc).
+#]=======================================================================]
+
+if(NOT SDL_TTF_INCLUDE_DIR AND SDLTTF_INCLUDE_DIR)
+ set(SDL_TTF_INCLUDE_DIR ${SDLTTF_INCLUDE_DIR} CACHE PATH "directory cache
+entry initialized from old variable name")
+endif()
+find_path(SDL_TTF_INCLUDE_DIR SDL_ttf.h
+ HINTS
+ ENV SDLTTFDIR
+ ENV SDLDIR
+ PATH_SUFFIXES SDL
+ # path suffixes to search inside ENV{SDLDIR}
+ include/SDL include/SDL12 include/SDL11 include
+)
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(VC_LIB_PATH_SUFFIX lib/x64)
+else()
+ set(VC_LIB_PATH_SUFFIX lib/x86)
+endif()
+
+if(NOT SDL_TTF_LIBRARY AND SDLTTF_LIBRARY)
+ set(SDL_TTF_LIBRARY ${SDLTTF_LIBRARY} CACHE FILEPATH "file cache entry
+initialized from old variable name")
+endif()
+find_library(SDL_TTF_LIBRARY
+ NAMES SDL_ttf
+ HINTS
+ ENV SDLTTFDIR
+ ENV SDLDIR
+ PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
+)
+
+if(SDL_TTF_INCLUDE_DIR AND EXISTS "${SDL_TTF_INCLUDE_DIR}/SDL_ttf.h")
+ file(STRINGS "${SDL_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL_TTF_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_TTF_MAJOR_VERSION[ \t]+[0-9]+$")
+ file(STRINGS "${SDL_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL_TTF_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_TTF_MINOR_VERSION[ \t]+[0-9]+$")
+ file(STRINGS "${SDL_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL_TTF_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_TTF_PATCHLEVEL[ \t]+[0-9]+$")
+ string(REGEX REPLACE "^#define[ \t]+SDL_TTF_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_TTF_VERSION_MAJOR "${SDL_TTF_VERSION_MAJOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SDL_TTF_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_TTF_VERSION_MINOR "${SDL_TTF_VERSION_MINOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SDL_TTF_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL_TTF_VERSION_PATCH "${SDL_TTF_VERSION_PATCH_LINE}")
+ set(SDL_TTF_VERSION_STRING ${SDL_TTF_VERSION_MAJOR}.${SDL_TTF_VERSION_MINOR}.${SDL_TTF_VERSION_PATCH})
+ unset(SDL_TTF_VERSION_MAJOR_LINE)
+ unset(SDL_TTF_VERSION_MINOR_LINE)
+ unset(SDL_TTF_VERSION_PATCH_LINE)
+ unset(SDL_TTF_VERSION_MAJOR)
+ unset(SDL_TTF_VERSION_MINOR)
+ unset(SDL_TTF_VERSION_PATCH)
+endif()
+
+set(SDL_TTF_LIBRARIES ${SDL_TTF_LIBRARY})
+set(SDL_TTF_INCLUDE_DIRS ${SDL_TTF_INCLUDE_DIR})
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL_ttf
+ REQUIRED_VARS SDL_TTF_LIBRARIES SDL_TTF_INCLUDE_DIRS
+ VERSION_VAR SDL_TTF_VERSION_STRING)
+
+# for backward compatibility
+set(SDLTTF_LIBRARY ${SDL_TTF_LIBRARIES})
+set(SDLTTF_INCLUDE_DIR ${SDL_TTF_INCLUDE_DIRS})
+set(SDLTTF_FOUND ${SDL_TTF_FOUND})
+
+mark_as_advanced(SDL_TTF_LIBRARY SDL_TTF_INCLUDE_DIR)
diff --git a/Modules/FindSQLite3.cmake b/Modules/FindSQLite3.cmake
new file mode 100644
index 0000000..88c7dd2
--- /dev/null
+++ b/Modules/FindSQLite3.cmake
@@ -0,0 +1,68 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindSQLite3
+-----------
+
+.. versionadded:: 3.14
+
+Find the SQLite libraries, v3
+
+IMPORTED targets
+^^^^^^^^^^^^^^^^
+
+This module defines the following :prop_tgt:`IMPORTED` target:
+
+``SQLite::SQLite3``
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables if found:
+
+``SQLite3_INCLUDE_DIRS``
+ where to find sqlite3.h, etc.
+``SQLite3_LIBRARIES``
+ the libraries to link against to use SQLite3.
+``SQLite3_VERSION``
+ version of the SQLite3 library found
+``SQLite3_FOUND``
+ TRUE if found
+
+#]=======================================================================]
+
+# Look for the necessary header
+find_path(SQLite3_INCLUDE_DIR NAMES sqlite3.h)
+mark_as_advanced(SQLite3_INCLUDE_DIR)
+
+# Look for the necessary library
+find_library(SQLite3_LIBRARY NAMES sqlite3 sqlite)
+mark_as_advanced(SQLite3_LIBRARY)
+
+# Extract version information from the header file
+if(SQLite3_INCLUDE_DIR)
+ file(STRINGS ${SQLite3_INCLUDE_DIR}/sqlite3.h _ver_line
+ REGEX "^#define SQLITE_VERSION *\"[0-9]+\\.[0-9]+\\.[0-9]+\""
+ LIMIT_COUNT 1)
+ string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+"
+ SQLite3_VERSION "${_ver_line}")
+ unset(_ver_line)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(SQLite3
+ REQUIRED_VARS SQLite3_INCLUDE_DIR SQLite3_LIBRARY
+ VERSION_VAR SQLite3_VERSION)
+
+# Create the imported target
+if(SQLite3_FOUND)
+ set(SQLite3_INCLUDE_DIRS ${SQLite3_INCLUDE_DIR})
+ set(SQLite3_LIBRARIES ${SQLite3_LIBRARY})
+ if(NOT TARGET SQLite::SQLite3)
+ add_library(SQLite::SQLite3 UNKNOWN IMPORTED)
+ set_target_properties(SQLite::SQLite3 PROPERTIES
+ IMPORTED_LOCATION "${SQLite3_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${SQLite3_INCLUDE_DIR}")
+ endif()
+endif()
diff --git a/Modules/FindSWIG.cmake b/Modules/FindSWIG.cmake
new file mode 100644
index 0000000..4c7ad89
--- /dev/null
+++ b/Modules/FindSWIG.cmake
@@ -0,0 +1,147 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindSWIG
+--------
+
+Find the Simplified Wrapper and Interface Generator (SWIG_) executable.
+
+This module finds an installed SWIG and determines its version.
+
+.. versionadded:: 3.18
+ If a ``COMPONENTS`` or ``OPTIONAL_COMPONENTS`` argument is given to the
+ :command:`find_package` command, it will also determine supported target
+ languages.
+
+.. versionadded:: 3.19
+ 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 module defines the following variables:
+
+``SWIG_FOUND``
+ Whether SWIG and any required components were found on the system.
+``SWIG_EXECUTABLE``
+ Path to the SWIG executable.
+``SWIG_DIR``
+ Path to the installed SWIG ``Lib`` directory (result of ``swig -swiglib``).
+``SWIG_VERSION``
+ SWIG executable version (result of ``swig -version``).
+``SWIG_<lang>_FOUND``
+ If ``COMPONENTS`` or ``OPTIONAL_COMPONENTS`` are requested, each available
+ target language ``<lang>`` (lowercase) will be set to TRUE.
+
+Any ``COMPONENTS`` given to ``find_package`` should be the names of supported
+target languages as provided to the LANGUAGE argument of ``swig_add_library``,
+such as ``python`` or ``perl5``. Language names *must* be lowercase.
+
+All information is collected from the ``SWIG_EXECUTABLE``, so the version
+to be found can be changed from the command line by means of setting
+``SWIG_EXECUTABLE``.
+
+Example usage requiring SWIG 4.0 or higher and Python language support, with
+optional Fortran support:
+
+.. code-block:: cmake
+
+ find_package(SWIG 4.0 COMPONENTS python OPTIONAL_COMPONENTS fortran)
+ if(SWIG_FOUND)
+ message("SWIG found: ${SWIG_EXECUTABLE}")
+ if(NOT SWIG_fortran_FOUND)
+ message(WARNING "SWIG Fortran bindings cannot be generated")
+ endif()
+ endif()
+
+.. _`SWIG`: http://swig.org
+
+#]=======================================================================]
+
+# compute list of possible names
+unset (_SWIG_NAMES)
+if (SWIG_FIND_VERSION_RANGE)
+ foreach (_SWIG_MAJOR IN ITEMS 4 3 2)
+ if (_SWIG_MAJOR VERSION_GREATER_EQUAL SWIG_FIND_VERSION_MIN_MAJOR
+ AND ((SWIG_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND _SWIG_MAJOR VERSION_LESS_EQUAL SWIG_FIND_VERSION_MAX)
+ OR (SWIG_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND _SWIG_MAJOR VERSION_LESS SWIG_FIND_VERSION_MAX)))
+ list (APPEND _SWIG_NAMES swig${_SWIG_MAJOR}.0)
+ endif()
+ endforeach()
+elseif(SWIG_FIND_VERSION)
+ if (SWIG_FIND_VERSION_EXACT)
+ set(_SWIG_NAMES swig${SWIG_FIND_VERSION_MAJOR}.0)
+ else()
+ foreach (_SWIG_MAJOR IN ITEMS 4 3 2)
+ if (_SWIG_MAJOR VERSION_GREATER_EQUAL SWIG_FIND_VERSION_MAJOR)
+ list (APPEND _SWIG_NAMES swig${_SWIG_MAJOR}.0)
+ endif()
+ endforeach()
+ endif()
+else()
+ set (_SWIG_NAMES swig4.0 swig3.0 swig2.0)
+endif()
+if (NOT _SWIG_NAMES)
+ # try to find any version
+ set (_SWIG_NAMES swig4.0 swig3.0 swig2.0)
+endif()
+
+find_program(SWIG_EXECUTABLE NAMES ${_SWIG_NAMES} swig)
+
+if(SWIG_EXECUTABLE)
+ execute_process(COMMAND ${SWIG_EXECUTABLE} -swiglib
+ OUTPUT_VARIABLE SWIG_swiglib_output
+ ERROR_VARIABLE SWIG_swiglib_error
+ RESULT_VARIABLE SWIG_swiglib_result)
+
+ if(SWIG_swiglib_result)
+ if(SWIG_FIND_REQUIRED)
+ message(SEND_ERROR "Command \"${SWIG_EXECUTABLE} -swiglib\" failed with output:\n${SWIG_swiglib_error}")
+ else()
+ message(STATUS "Command \"${SWIG_EXECUTABLE} -swiglib\" failed with output:\n${SWIG_swiglib_error}")
+ endif()
+ else()
+ string(REGEX REPLACE "[\n\r]+" ";" SWIG_swiglib_output ${SWIG_swiglib_output})
+ find_path(SWIG_DIR swig.swg PATHS ${SWIG_swiglib_output} NO_CMAKE_FIND_ROOT_PATH)
+ if(SWIG_DIR)
+ set(SWIG_USE_FILE ${CMAKE_CURRENT_LIST_DIR}/UseSWIG.cmake)
+ execute_process(COMMAND ${SWIG_EXECUTABLE} -version
+ OUTPUT_VARIABLE SWIG_version_output
+ ERROR_VARIABLE SWIG_version_output
+ RESULT_VARIABLE SWIG_version_result)
+ if(SWIG_version_result)
+ message(SEND_ERROR "Command \"${SWIG_EXECUTABLE} -version\" failed with output:\n${SWIG_version_output}")
+ else()
+ string(REGEX REPLACE ".*SWIG Version[^0-9.]*\([0-9.]+\).*" "\\1"
+ SWIG_version_output "${SWIG_version_output}")
+ set(SWIG_VERSION ${SWIG_version_output} CACHE STRING "Swig version" FORCE)
+ endif()
+ endif()
+ endif()
+
+ if(SWIG_FIND_COMPONENTS)
+ execute_process(COMMAND ${SWIG_EXECUTABLE} -help
+ OUTPUT_VARIABLE SWIG_swighelp_output
+ ERROR_VARIABLE SWIG_swighelp_error
+ RESULT_VARIABLE SWIG_swighelp_result)
+ if(SWIG_swighelp_result)
+ message(SEND_ERROR "Command \"${SWIG_EXECUTABLE} -help\" failed with output:\n${SWIG_swiglib_error}")
+ else()
+ string(REPLACE "\n" ";" SWIG_swighelp_output "${SWIG_swighelp_output}")
+ foreach(SWIG_line IN LISTS SWIG_swighelp_output)
+ if(SWIG_line MATCHES "-([A-Za-z0-9_]+) +- *Generate.*wrappers")
+ set(SWIG_${CMAKE_MATCH_1}_FOUND TRUE)
+ endif()
+ endforeach()
+ endif()
+ endif()
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(
+ SWIG HANDLE_COMPONENTS
+ REQUIRED_VARS SWIG_EXECUTABLE SWIG_DIR
+ VERSION_VAR SWIG_VERSION
+ HANDLE_VERSION_RANGE)
+
+mark_as_advanced(SWIG_DIR SWIG_VERSION SWIG_EXECUTABLE)
diff --git a/Modules/FindSelfPackers.cmake b/Modules/FindSelfPackers.cmake
new file mode 100644
index 0000000..1abbcbd
--- /dev/null
+++ b/Modules/FindSelfPackers.cmake
@@ -0,0 +1,58 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindSelfPackers
+---------------
+
+Find upx
+
+This module looks for some executable packers (i.e. software that
+compress executables or shared libs into on-the-fly self-extracting
+executables or shared libs. Examples:
+
+::
+
+ UPX: http://wildsau.idv.uni-linz.ac.at/mfx/upx.html
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindCygwin.cmake)
+
+find_program(SELF_PACKER_FOR_EXECUTABLE
+ upx
+ ${CYGWIN_INSTALL_PATH}/bin
+)
+
+find_program(SELF_PACKER_FOR_SHARED_LIB
+ upx
+ ${CYGWIN_INSTALL_PATH}/bin
+)
+
+mark_as_advanced(
+ SELF_PACKER_FOR_EXECUTABLE
+ SELF_PACKER_FOR_SHARED_LIB
+)
+
+#
+# Set flags
+#
+if (SELF_PACKER_FOR_EXECUTABLE MATCHES "upx")
+ set (SELF_PACKER_FOR_EXECUTABLE_FLAGS "-q" CACHE STRING
+ "Flags for the executable self-packer.")
+else ()
+ set (SELF_PACKER_FOR_EXECUTABLE_FLAGS "" CACHE STRING
+ "Flags for the executable self-packer.")
+endif ()
+
+if (SELF_PACKER_FOR_SHARED_LIB MATCHES "upx")
+ set (SELF_PACKER_FOR_SHARED_LIB_FLAGS "-q" CACHE STRING
+ "Flags for the shared lib self-packer.")
+else ()
+ set (SELF_PACKER_FOR_SHARED_LIB_FLAGS "" CACHE STRING
+ "Flags for the shared lib self-packer.")
+endif ()
+
+mark_as_advanced(
+ SELF_PACKER_FOR_EXECUTABLE_FLAGS
+ SELF_PACKER_FOR_SHARED_LIB_FLAGS
+)
diff --git a/Modules/FindSquish.cmake b/Modules/FindSquish.cmake
new file mode 100644
index 0000000..9a17fdb
--- /dev/null
+++ b/Modules/FindSquish.cmake
@@ -0,0 +1,289 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindSquish
+----------
+
+-- Typical Use
+
+
+
+This module can be used to find Squish.
+
+::
+
+ SQUISH_FOUND If false, don't try to use Squish
+ SQUISH_VERSION The full version of Squish found
+ SQUISH_VERSION_MAJOR The major version of Squish found
+ SQUISH_VERSION_MINOR The minor version of Squish found
+ SQUISH_VERSION_PATCH The patch version of Squish found
+
+
+
+::
+
+ SQUISH_INSTALL_DIR The Squish installation directory
+ (containing bin, lib, etc)
+ SQUISH_SERVER_EXECUTABLE The squishserver executable
+ SQUISH_CLIENT_EXECUTABLE The squishrunner executable
+
+
+
+::
+
+ SQUISH_INSTALL_DIR_FOUND Was the install directory found?
+ SQUISH_SERVER_EXECUTABLE_FOUND Was the server executable found?
+ SQUISH_CLIENT_EXECUTABLE_FOUND Was the client executable found?
+
+
+
+It provides the function squish_add_test() for adding a squish test
+to cmake using Squish >= 4.x:
+
+::
+
+ squish_add_test(cmakeTestName
+ AUT targetName SUITE suiteName TEST squishTestName
+ [SETTINGSGROUP group] [PRE_COMMAND command] [POST_COMMAND command] )
+
+.. versionchanged:: 3.18
+ In previous CMake versions, this function was named ``squish_v4_add_test``.
+
+The arguments have the following meaning:
+
+``cmakeTestName``
+ this will be used as the first argument for add_test()
+``AUT targetName``
+ the name of the cmake target which will be used as AUT, i.e. the
+ executable which will be tested.
+``SUITE suiteName``
+ this is either the full path to the squish suite, or just the
+ last directory of the suite, i.e. the suite name. In this case
+ the CMakeLists.txt which calls squish_add_test() must be located
+ in the parent directory of the suite directory.
+``TEST squishTestName``
+ the name of the squish test, i.e. the name of the subdirectory
+ of the test inside the suite directory.
+``SETTINGSGROUP group``
+ deprecated, this argument will be ignored.
+``PRE_COMMAND command``
+ if specified, the given command will be executed before starting the squish test.
+``POST_COMMAND command``
+ same as PRE_COMMAND, but after the squish test has been executed.
+
+
+
+::
+
+ enable_testing()
+ find_package(Squish 6.5)
+ if (SQUISH_FOUND)
+ squish_add_test(myTestName
+ AUT myApp
+ SUITE ${CMAKE_SOURCE_DIR}/tests/mySuite
+ TEST someSquishTest
+ )
+ endif ()
+
+
+
+
+
+For users of Squish version 3.x the macro squish_v3_add_test() is
+provided:
+
+::
+
+ squish_v3_add_test(testName applicationUnderTest testCase envVars testWrapper)
+ Use this macro to add a test using Squish 3.x.
+
+
+
+::
+
+ enable_testing()
+ find_package(Squish 3.0)
+ if (SQUISH_FOUND)
+ squish_v3_add_test(myTestName myApplication testCase envVars testWrapper)
+ endif ()
+
+
+#]=======================================================================]
+
+set(SQUISH_INSTALL_DIR_STRING "Directory containing the bin, doc, and lib directories for Squish; this should be the root of the installation directory.")
+set(SQUISH_SERVER_EXECUTABLE_STRING "The squishserver executable program.")
+set(SQUISH_CLIENT_EXECUTABLE_STRING "The squishclient executable program.")
+
+# Search only if the location is not already known.
+if(NOT SQUISH_INSTALL_DIR)
+ # Get the system search path as a list.
+ file(TO_CMAKE_PATH "$ENV{PATH}" SQUISH_INSTALL_DIR_SEARCH2)
+
+ # Construct a set of paths relative to the system search path.
+ set(SQUISH_INSTALL_DIR_SEARCH "")
+ foreach(dir ${SQUISH_INSTALL_DIR_SEARCH2})
+ set(SQUISH_INSTALL_DIR_SEARCH ${SQUISH_INSTALL_DIR_SEARCH} "${dir}/../lib/fltk")
+ endforeach()
+ string(REPLACE "//" "/" SQUISH_INSTALL_DIR_SEARCH "${SQUISH_INSTALL_DIR_SEARCH}")
+
+ # Look for an installation
+ find_path(SQUISH_INSTALL_DIR
+ NAMES bin/squishrunner bin/squishrunner.exe
+ HINTS
+ # Look for an environment variable SQUISH_INSTALL_DIR.
+ ENV SQUISH_INSTALL_DIR
+
+ # Look in places relative to the system executable search path.
+ ${SQUISH_INSTALL_DIR_SEARCH}
+
+ DOC "The ${SQUISH_INSTALL_DIR_STRING}"
+ )
+endif()
+
+# search for the executables
+if(SQUISH_INSTALL_DIR)
+ set(SQUISH_INSTALL_DIR_FOUND 1)
+
+ # find the client program
+ if(NOT SQUISH_CLIENT_EXECUTABLE)
+ find_program(SQUISH_CLIENT_EXECUTABLE ${SQUISH_INSTALL_DIR}/bin/squishrunner${CMAKE_EXECUTABLE_SUFFIX} DOC "The ${SQUISH_CLIENT_EXECUTABLE_STRING}")
+ endif()
+
+ # find the server program
+ if(NOT SQUISH_SERVER_EXECUTABLE)
+ find_program(SQUISH_SERVER_EXECUTABLE ${SQUISH_INSTALL_DIR}/bin/squishserver${CMAKE_EXECUTABLE_SUFFIX} DOC "The ${SQUISH_SERVER_EXECUTABLE_STRING}")
+ endif()
+
+else()
+ set(SQUISH_INSTALL_DIR_FOUND 0)
+endif()
+
+
+set(SQUISH_VERSION)
+set(SQUISH_VERSION_MAJOR)
+set(SQUISH_VERSION_MINOR)
+set(SQUISH_VERSION_PATCH)
+
+# record if executables are set
+if(SQUISH_CLIENT_EXECUTABLE)
+ set(SQUISH_CLIENT_EXECUTABLE_FOUND 1)
+ execute_process(COMMAND "${SQUISH_CLIENT_EXECUTABLE}" --version
+ OUTPUT_VARIABLE _squishVersionOutput
+ ERROR_QUIET )
+ if("${_squishVersionOutput}" MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)")
+ set(SQUISH_VERSION_MAJOR "${CMAKE_MATCH_1}")
+ set(SQUISH_VERSION_MINOR "${CMAKE_MATCH_2}")
+ set(SQUISH_VERSION_PATCH "${CMAKE_MATCH_3}")
+ set(SQUISH_VERSION "${SQUISH_VERSION_MAJOR}.${SQUISH_VERSION_MINOR}.${SQUISH_VERSION_PATCH}" )
+ endif()
+else()
+ set(SQUISH_CLIENT_EXECUTABLE_FOUND 0)
+endif()
+
+if(SQUISH_SERVER_EXECUTABLE)
+ set(SQUISH_SERVER_EXECUTABLE_FOUND 1)
+else()
+ set(SQUISH_SERVER_EXECUTABLE_FOUND 0)
+endif()
+
+# record if Squish was found
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(Squish REQUIRED_VARS SQUISH_INSTALL_DIR SQUISH_CLIENT_EXECUTABLE SQUISH_SERVER_EXECUTABLE
+ VERSION_VAR SQUISH_VERSION )
+
+
+set(_SQUISH_MODULE_DIR "${CMAKE_CURRENT_LIST_DIR}")
+
+macro(squish_v3_add_test testName testAUT testCase envVars testWraper)
+ if("${SQUISH_VERSION_MAJOR}" STRGREATER "3")
+ message(STATUS "Using squish_v3_add_test(), but SQUISH_VERSION_MAJOR is ${SQUISH_VERSION_MAJOR}.\nThis may not work.")
+ endif()
+
+ add_test(${testName}
+ ${CMAKE_COMMAND} -V -VV
+ "-Dsquish_version:STRING=3"
+ "-Dsquish_aut:STRING=${testAUT}"
+ "-Dsquish_server_executable:STRING=${SQUISH_SERVER_EXECUTABLE}"
+ "-Dsquish_client_executable:STRING=${SQUISH_CLIENT_EXECUTABLE}"
+ "-Dsquish_libqtdir:STRING=${QT_LIBRARY_DIR}"
+ "-Dsquish_test_case:STRING=${testCase}"
+ "-Dsquish_env_vars:STRING=${envVars}"
+ "-Dsquish_wrapper:STRING=${testWraper}"
+ "-Dsquish_module_dir:STRING=${_SQUISH_MODULE_DIR}"
+ -P "${_SQUISH_MODULE_DIR}/SquishTestScript.cmake"
+ )
+ set_tests_properties(${testName}
+ PROPERTIES FAIL_REGULAR_EXPRESSION "FAILED;ERROR;FATAL"
+ )
+endmacro()
+
+
+function(squish_v4_add_test testName)
+ if(NOT "${SQUISH_VERSION_MAJOR}" STRGREATER "3")
+ message(STATUS "Using squish_add_test(), but SQUISH_VERSION_MAJOR is ${SQUISH_VERSION_MAJOR}.\nThis may not work.")
+ endif()
+
+ set(oneValueArgs AUT SUITE TEST SETTINGSGROUP PRE_COMMAND POST_COMMAND)
+
+ cmake_parse_arguments(_SQUISH "" "${oneValueArgs}" "" ${ARGN} )
+
+ if(_SQUISH_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to SQUISH_ADD_TEST(): \"${_SQUISH_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if(NOT _SQUISH_AUT)
+ message(FATAL_ERROR "Required argument AUT not given for SQUISH_ADD_TEST()")
+ endif()
+
+ if(NOT _SQUISH_SUITE)
+ message(FATAL_ERROR "Required argument SUITE not given for SQUISH_ADD_TEST()")
+ endif()
+
+ if(NOT _SQUISH_TEST)
+ message(FATAL_ERROR "Required argument TEST not given for SQUISH_ADD_TEST()")
+ endif()
+
+ get_filename_component(absTestSuite "${_SQUISH_SUITE}" ABSOLUTE)
+ if(NOT EXISTS "${absTestSuite}")
+ message(FATAL_ERROR "Could not find squish test suite ${_SQUISH_SUITE} (checked ${absTestSuite})")
+ endif()
+
+ set(absTestCase "${absTestSuite}/${_SQUISH_TEST}")
+ if(NOT EXISTS "${absTestCase}")
+ message(FATAL_ERROR "Could not find squish testcase ${_SQUISH_TEST} (checked ${absTestCase})")
+ endif()
+
+ if(_SQUISH_SETTINGSGROUP)
+ message("SETTINGSGROUP is deprecated and will be ignored.")
+ endif()
+
+ add_test(NAME ${testName}
+ COMMAND ${CMAKE_COMMAND} -V -VV
+ "-Dsquish_version:STRING=4"
+ "-Dsquish_aut:STRING=$<TARGET_FILE_BASE_NAME:${_SQUISH_AUT}>"
+ "-Dsquish_aut_dir:STRING=$<TARGET_FILE_DIR:${_SQUISH_AUT}>"
+ "-Dsquish_server_executable:STRING=${SQUISH_SERVER_EXECUTABLE}"
+ "-Dsquish_client_executable:STRING=${SQUISH_CLIENT_EXECUTABLE}"
+ "-Dsquish_libqtdir:STRING=${QT_LIBRARY_DIR}"
+ "-Dsquish_test_suite:STRING=${absTestSuite}"
+ "-Dsquish_test_case:STRING=${_SQUISH_TEST}"
+ "-Dsquish_env_vars:STRING=${envVars}"
+ "-Dsquish_wrapper:STRING=${testWraper}"
+ "-Dsquish_module_dir:STRING=${_SQUISH_MODULE_DIR}"
+ "-Dsquish_pre_command:STRING=${_SQUISH_PRE_COMMAND}"
+ "-Dsquish_post_command:STRING=${_SQUISH_POST_COMMAND}"
+ -P "${_SQUISH_MODULE_DIR}/SquishTestScript.cmake"
+ )
+ set_tests_properties(${testName}
+ PROPERTIES FAIL_REGULAR_EXPRESSION "FAIL;FAILED;ERROR;FATAL"
+ )
+endfunction()
+
+macro(squish_add_test)
+ if("${SQUISH_VERSION_MAJOR}" STRGREATER "3")
+ squish_v4_add_test(${ARGV})
+ else()
+ squish_v3_add_test(${ARGV})
+ endif()
+endmacro()
diff --git a/Modules/FindSubversion.cmake b/Modules/FindSubversion.cmake
new file mode 100644
index 0000000..7a9c440
--- /dev/null
+++ b/Modules/FindSubversion.cmake
@@ -0,0 +1,169 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindSubversion
+--------------
+
+Extract information from a subversion working copy
+
+The module defines the following variables:
+
+::
+
+ Subversion_SVN_EXECUTABLE - path to svn command line client
+ Subversion_VERSION_SVN - version of svn command line client
+ Subversion_FOUND - true if the command line client was found
+ SUBVERSION_FOUND - same as Subversion_FOUND, set for compatibility reasons
+
+
+
+The minimum required version of Subversion can be specified using the
+standard syntax, e.g. ``find_package(Subversion 1.4)``.
+
+If the command line client executable is found two macros are defined:
+
+::
+
+ Subversion_WC_INFO(<dir> <var-prefix> [IGNORE_SVN_FAILURE])
+ Subversion_WC_LOG(<dir> <var-prefix>)
+
+``Subversion_WC_INFO`` extracts information of a subversion working copy at a
+given location. This macro defines the following variables if running
+Subversion's ``info`` command on ``<dir>`` succeeds; otherwise a
+``SEND_ERROR`` message is generated.
+
+.. versionadded:: 3.13
+ The error can be ignored by providing the
+ ``IGNORE_SVN_FAILURE`` option, which causes these variables to remain
+ undefined.
+
+::
+
+ <var-prefix>_WC_URL - url of the repository (at <dir>)
+ <var-prefix>_WC_ROOT - root url of the repository
+ <var-prefix>_WC_REVISION - current revision
+ <var-prefix>_WC_LAST_CHANGED_AUTHOR - author of last commit
+ <var-prefix>_WC_LAST_CHANGED_DATE - date of last commit
+ <var-prefix>_WC_LAST_CHANGED_REV - revision of last commit
+ <var-prefix>_WC_INFO - output of command `svn info <dir>'
+
+``Subversion_WC_LOG`` retrieves the log message of the base revision of a
+subversion working copy at a given location. This macro defines the variable:
+
+::
+
+ <var-prefix>_LAST_CHANGED_LOG - last log of base revision
+
+Example usage:
+
+::
+
+ find_package(Subversion)
+ if(SUBVERSION_FOUND)
+ Subversion_WC_INFO(${PROJECT_SOURCE_DIR} Project)
+ message("Current revision is ${Project_WC_REVISION}")
+ Subversion_WC_LOG(${PROJECT_SOURCE_DIR} Project)
+ message("Last changed log is ${Project_LAST_CHANGED_LOG}")
+ endif()
+#]=======================================================================]
+
+find_program(Subversion_SVN_EXECUTABLE svn
+ PATHS
+ [HKEY_LOCAL_MACHINE\\Software\\TortoiseSVN;Directory]/bin
+ DOC "subversion command line client")
+mark_as_advanced(Subversion_SVN_EXECUTABLE)
+
+if(Subversion_SVN_EXECUTABLE)
+ # the subversion commands should be executed with the C locale, otherwise
+ # the message (which are parsed) may be translated, Alex
+ set(_Subversion_SAVED_LC_ALL "$ENV{LC_ALL}")
+ set(ENV{LC_ALL} C)
+
+ execute_process(COMMAND ${Subversion_SVN_EXECUTABLE} --version
+ OUTPUT_VARIABLE Subversion_VERSION_SVN
+ ERROR_VARIABLE _Subversion_VERSION_STDERR
+ RESULT_VARIABLE _Subversion_VERSION_RESULT
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ # restore the previous LC_ALL
+ set(ENV{LC_ALL} ${_Subversion_SAVED_LC_ALL})
+
+ if(_Subversion_VERSION_RESULT EQUAL 0)
+ string(REGEX REPLACE "^(.*\n)?svn, version ([.0-9]+).*"
+ "\\2" Subversion_VERSION_SVN "${Subversion_VERSION_SVN}")
+ else()
+ unset(Subversion_VERSION_SVN)
+ if(_Subversion_VERSION_STDERR MATCHES "svn: error: The subversion command line tools are no longer provided by Xcode")
+ set(Subversion_SVN_EXECUTABLE Subversion_SVN_EXECUTABLE-NOTFOUND)
+ endif()
+ endif()
+
+ macro(Subversion_WC_INFO dir prefix)
+
+ cmake_parse_arguments(
+ "Subversion_WC_INFO"
+ "IGNORE_SVN_FAILURE"
+ "" ""
+ ${ARGN}
+ )
+
+ # the subversion commands should be executed with the C locale, otherwise
+ # the message (which are parsed) may be translated, Alex
+ set(_Subversion_SAVED_LC_ALL "$ENV{LC_ALL}")
+ set(ENV{LC_ALL} C)
+
+ execute_process(COMMAND ${Subversion_SVN_EXECUTABLE} info ${dir}
+ OUTPUT_VARIABLE ${prefix}_WC_INFO
+ ERROR_VARIABLE Subversion_svn_info_error
+ RESULT_VARIABLE Subversion_svn_info_result
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(${Subversion_svn_info_result} EQUAL 0)
+ string(REGEX REPLACE "^(.*\n)?URL: ([^\n]+).*"
+ "\\2" ${prefix}_WC_URL "${${prefix}_WC_INFO}")
+ string(REGEX REPLACE "^(.*\n)?Repository Root: ([^\n]+).*"
+ "\\2" ${prefix}_WC_ROOT "${${prefix}_WC_INFO}")
+ string(REGEX REPLACE "^(.*\n)?Revision: ([^\n]+).*"
+ "\\2" ${prefix}_WC_REVISION "${${prefix}_WC_INFO}")
+ string(REGEX REPLACE "^(.*\n)?Last Changed Author: ([^\n]+).*"
+ "\\2" ${prefix}_WC_LAST_CHANGED_AUTHOR "${${prefix}_WC_INFO}")
+ string(REGEX REPLACE "^(.*\n)?Last Changed Rev: ([^\n]+).*"
+ "\\2" ${prefix}_WC_LAST_CHANGED_REV "${${prefix}_WC_INFO}")
+ string(REGEX REPLACE "^(.*\n)?Last Changed Date: ([^\n]+).*"
+ "\\2" ${prefix}_WC_LAST_CHANGED_DATE "${${prefix}_WC_INFO}")
+ elseif(NOT Subversion_WC_INFO_IGNORE_SVN_FAILURE)
+ message(SEND_ERROR "Command \"${Subversion_SVN_EXECUTABLE} info ${dir}\" failed with output:\n${Subversion_svn_info_error}")
+ endif()
+
+ # restore the previous LC_ALL
+ set(ENV{LC_ALL} ${_Subversion_SAVED_LC_ALL})
+
+ endmacro()
+
+ macro(Subversion_WC_LOG dir prefix)
+ # This macro can block if the certificate is not signed:
+ # svn ask you to accept the certificate and wait for your answer
+ # This macro requires a svn server network access (Internet most of the time)
+ # and can also be slow since it access the svn server
+ execute_process(COMMAND
+ ${Subversion_SVN_EXECUTABLE} --non-interactive log -r BASE ${dir}
+ OUTPUT_VARIABLE ${prefix}_LAST_CHANGED_LOG
+ ERROR_VARIABLE Subversion_svn_log_error
+ RESULT_VARIABLE Subversion_svn_log_result
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(NOT ${Subversion_svn_log_result} EQUAL 0)
+ message(SEND_ERROR "Command \"${Subversion_SVN_EXECUTABLE} log -r BASE ${dir}\" failed with output:\n${Subversion_svn_log_error}")
+ endif()
+ endmacro()
+
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Subversion REQUIRED_VARS Subversion_SVN_EXECUTABLE
+ VERSION_VAR Subversion_VERSION_SVN )
+
+# for compatibility
+set(Subversion_FOUND ${SUBVERSION_FOUND})
+set(Subversion_SVN_FOUND ${SUBVERSION_FOUND})
diff --git a/Modules/FindTCL.cmake b/Modules/FindTCL.cmake
new file mode 100644
index 0000000..9b771dc
--- /dev/null
+++ b/Modules/FindTCL.cmake
@@ -0,0 +1,247 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindTCL
+-------
+
+TK_INTERNAL_PATH was removed.
+
+This module finds if Tcl is installed and determines where the include
+files and libraries are. It also determines what the name of the
+library is. This code sets the following variables:
+
+::
+
+ TCL_FOUND = Tcl was found
+ TK_FOUND = Tk was found
+ TCLTK_FOUND = Tcl and Tk were found
+ TCL_LIBRARY = path to Tcl library (tcl tcl80)
+ TCL_INCLUDE_PATH = path to where tcl.h can be found
+ TCL_TCLSH = path to tclsh binary (tcl tcl80)
+ TK_LIBRARY = path to Tk library (tk tk80 etc)
+ TK_INCLUDE_PATH = path to where tk.h can be found
+ TK_WISH = full path to the wish executable
+
+
+
+In an effort to remove some clutter and clear up some issues for
+people who are not necessarily Tcl/Tk gurus/developers, some
+variables were moved or removed. Changes compared to CMake 2.4 are:
+
+::
+
+ => they were only useful for people writing Tcl/Tk extensions.
+ => these libs are not packaged by default with Tcl/Tk distributions.
+ Even when Tcl/Tk is built from source, several flavors of debug libs
+ are created and there is no real reason to pick a single one
+ specifically (say, amongst tcl84g, tcl84gs, or tcl84sgx).
+ Let's leave that choice to the user by allowing him to assign
+ TCL_LIBRARY to any Tcl library, debug or not.
+ => this ended up being only a Win32 variable, and there is a lot of
+ confusion regarding the location of this file in an installed Tcl/Tk
+ tree anyway (see 8.5 for example). If you need the internal path at
+ this point it is safer you ask directly where the *source* tree is
+ and dig from there.
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/CMakeFindFrameworks.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/FindTclsh.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/FindWish.cmake)
+
+if(TCLSH_VERSION_STRING)
+ set(TCL_TCLSH_VERSION "${TCLSH_VERSION_STRING}")
+else()
+ get_filename_component(TCL_TCLSH_PATH "${TCL_TCLSH}" PATH)
+ get_filename_component(TCL_TCLSH_PATH_PARENT "${TCL_TCLSH_PATH}" PATH)
+ string(REGEX REPLACE
+ "^.*tclsh([0-9]\\.*[0-9]).*$" "\\1" TCL_TCLSH_VERSION "${TCL_TCLSH}")
+endif()
+
+get_filename_component(TK_WISH_PATH "${TK_WISH}" PATH)
+get_filename_component(TK_WISH_PATH_PARENT "${TK_WISH_PATH}" PATH)
+string(REGEX REPLACE
+ "^.*wish([0-9]\\.*[0-9]).*$" "\\1" TK_WISH_VERSION "${TK_WISH}")
+
+get_filename_component(TCL_INCLUDE_PATH_PARENT "${TCL_INCLUDE_PATH}" PATH)
+get_filename_component(TK_INCLUDE_PATH_PARENT "${TK_INCLUDE_PATH}" PATH)
+
+get_filename_component(TCL_LIBRARY_PATH "${TCL_LIBRARY}" PATH)
+get_filename_component(TCL_LIBRARY_PATH_PARENT "${TCL_LIBRARY_PATH}" PATH)
+string(REGEX REPLACE
+ "^.*tcl([0-9]\\.*[0-9]).*$" "\\1" TCL_LIBRARY_VERSION "${TCL_LIBRARY}")
+
+get_filename_component(TK_LIBRARY_PATH "${TK_LIBRARY}" PATH)
+get_filename_component(TK_LIBRARY_PATH_PARENT "${TK_LIBRARY_PATH}" PATH)
+string(REGEX REPLACE
+ "^.*tk([0-9]\\.*[0-9]).*$" "\\1" TK_LIBRARY_VERSION "${TK_LIBRARY}")
+
+set(TCLTK_POSSIBLE_LIB_PATHS
+ "${TCL_INCLUDE_PATH_PARENT}/lib"
+ "${TK_INCLUDE_PATH_PARENT}/lib"
+ "${TCL_LIBRARY_PATH}"
+ "${TK_LIBRARY_PATH}"
+ "${TCL_TCLSH_PATH_PARENT}/lib"
+ "${TK_WISH_PATH_PARENT}/lib"
+)
+
+set(TCLTK_POSSIBLE_LIB_PATH_SUFFIXES
+ lib/tcl/tcl8.7
+ lib/tcl/tk8.7
+ lib/tcl/tcl8.6
+ lib/tcl/tk8.6
+ lib/tcl/tcl8.5
+ lib/tcl/tk8.5
+ lib/tcl/tcl8.4
+ lib/tcl/tk8.4
+)
+
+if(WIN32)
+ get_filename_component(
+ ActiveTcl_CurrentVersion
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ActiveState\\ActiveTcl;CurrentVersion]"
+ NAME)
+ set(TCLTK_POSSIBLE_LIB_PATHS ${TCLTK_POSSIBLE_LIB_PATHS}
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ActiveState\\ActiveTcl\\${ActiveTcl_CurrentVersion}]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.6;Root]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.5;Root]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.4;Root]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.3;Root]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.2;Root]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.0;Root]/lib"
+ "$ENV{ProgramFiles}/Tcl/Lib"
+ "C:/Program Files/Tcl/lib"
+ "C:/Tcl/lib"
+ )
+endif()
+
+find_library(TCL_LIBRARY
+ NAMES
+ tcl
+ tcl${TCL_LIBRARY_VERSION} tcl${TCL_TCLSH_VERSION} tcl${TK_WISH_VERSION}
+ tcl87 tcl8.7 tcl87t tcl8.7t
+ tcl86 tcl8.6 tcl86t tcl8.6t
+ tcl85 tcl8.5
+ tcl84 tcl8.4
+ tcl83 tcl8.3
+ tcl82 tcl8.2
+ tcl80 tcl8.0
+ PATHS ${TCLTK_POSSIBLE_LIB_PATHS}
+ PATH_SUFFIXES ${TCLTK_POSSIBLE_LIB_PATH_SUFFIXES}
+ )
+
+find_library(TK_LIBRARY
+ NAMES
+ tk
+ tk${TK_LIBRARY_VERSION} tk${TCL_TCLSH_VERSION} tk${TK_WISH_VERSION}
+ tk87 tk8.7 tk87t tk8.7t
+ tk86 tk8.6 tk86t tk8.6t
+ tk85 tk8.5
+ tk84 tk8.4
+ tk83 tk8.3
+ tk82 tk8.2
+ tk80 tk8.0
+ PATHS ${TCLTK_POSSIBLE_LIB_PATHS}
+ PATH_SUFFIXES ${TCLTK_POSSIBLE_LIB_PATH_SUFFIXES}
+ )
+
+CMAKE_FIND_FRAMEWORKS(Tcl)
+CMAKE_FIND_FRAMEWORKS(Tk)
+
+set(TCL_FRAMEWORK_INCLUDES)
+if(Tcl_FRAMEWORKS)
+ if(NOT TCL_INCLUDE_PATH)
+ foreach(dir ${Tcl_FRAMEWORKS})
+ set(TCL_FRAMEWORK_INCLUDES ${TCL_FRAMEWORK_INCLUDES} ${dir}/Headers)
+ endforeach()
+ endif()
+endif()
+
+set(TK_FRAMEWORK_INCLUDES)
+if(Tk_FRAMEWORKS)
+ if(NOT TK_INCLUDE_PATH)
+ foreach(dir ${Tk_FRAMEWORKS})
+ set(TK_FRAMEWORK_INCLUDES ${TK_FRAMEWORK_INCLUDES}
+ ${dir}/Headers ${dir}/PrivateHeaders)
+ endforeach()
+ endif()
+endif()
+
+set(TCLTK_POSSIBLE_INCLUDE_PATHS
+ "${TCL_LIBRARY_PATH_PARENT}/include"
+ "${TK_LIBRARY_PATH_PARENT}/include"
+ "${TCL_INCLUDE_PATH}"
+ "${TK_INCLUDE_PATH}"
+ ${TCL_FRAMEWORK_INCLUDES}
+ ${TK_FRAMEWORK_INCLUDES}
+ "${TCL_TCLSH_PATH_PARENT}/include"
+ "${TK_WISH_PATH_PARENT}/include"
+ )
+
+set(TCLTK_POSSIBLE_INCLUDE_PATH_SUFFIXES
+ include/tcl${TK_LIBRARY_VERSION}
+ include/tcl${TCL_LIBRARY_VERSION}
+ include/tcl8.7
+ include/tk8.7
+ include/tcl8.6
+ include/tk8.6
+ include/tcl8.5
+ include/tk8.5
+ include/tcl8.4
+ include/tk8.4
+ include/tcl8.3
+ include/tcl8.2
+ include/tcl8.0
+ )
+
+if(WIN32)
+ set(TCLTK_POSSIBLE_INCLUDE_PATHS ${TCLTK_POSSIBLE_INCLUDE_PATHS}
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ActiveState\\ActiveTcl\\${ActiveTcl_CurrentVersion}]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.6;Root]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.5;Root]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.4;Root]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.3;Root]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.2;Root]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.0;Root]/include"
+ "$ENV{ProgramFiles}/Tcl/include"
+ "C:/Program Files/Tcl/include"
+ "C:/Tcl/include"
+ )
+endif()
+
+find_path(TCL_INCLUDE_PATH
+ NAMES tcl.h
+ HINTS ${TCLTK_POSSIBLE_INCLUDE_PATHS}
+ PATH_SUFFIXES ${TCLTK_POSSIBLE_INCLUDE_PATH_SUFFIXES}
+ )
+
+find_path(TK_INCLUDE_PATH
+ NAMES tk.h
+ HINTS ${TCLTK_POSSIBLE_INCLUDE_PATHS}
+ PATH_SUFFIXES ${TCLTK_POSSIBLE_INCLUDE_PATH_SUFFIXES}
+ )
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+if (CMAKE_FIND_PACKAGE_NAME STREQUAL "TclStub")
+ # FindTclStub include()'s this module. It's an old pattern, but rather than
+ # trying to suppress this from outside the module (which is then sensitive to
+ # the contents, detect the case in this module and suppress it explicitly.
+ set(FPHSA_NAME_MISMATCHED 1)
+endif ()
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(TCL DEFAULT_MSG TCL_LIBRARY TCL_INCLUDE_PATH)
+set(FPHSA_NAME_MISMATCHED 1)
+set(TCLTK_FIND_REQUIRED ${TCL_FIND_REQUIRED})
+set(TCLTK_FIND_QUIETLY ${TCL_FIND_QUIETLY})
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(TCLTK DEFAULT_MSG TCL_LIBRARY TCL_INCLUDE_PATH TK_LIBRARY TK_INCLUDE_PATH)
+set(TK_FIND_REQUIRED ${TCL_FIND_REQUIRED})
+set(TK_FIND_QUIETLY ${TCL_FIND_QUIETLY})
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(TK DEFAULT_MSG TK_LIBRARY TK_INCLUDE_PATH)
+unset(FPHSA_NAME_MISMATCHED)
+
+mark_as_advanced(
+ TCL_INCLUDE_PATH
+ TK_INCLUDE_PATH
+ TCL_LIBRARY
+ TK_LIBRARY
+ )
diff --git a/Modules/FindTIFF.cmake b/Modules/FindTIFF.cmake
new file mode 100644
index 0000000..ed2657c
--- /dev/null
+++ b/Modules/FindTIFF.cmake
@@ -0,0 +1,200 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindTIFF
+--------
+
+Find the TIFF library (``libtiff``, https://libtiff.gitlab.io/libtiff/).
+
+Optional COMPONENTS
+^^^^^^^^^^^^^^^^^^^
+
+This module supports the optional component `CXX`, for use with the COMPONENTS
+argument of the :command:`find_package` command. This component has an associated
+imported target, as described below.
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.5
+
+This module defines the following :prop_tgt:`IMPORTED` targets:
+
+``TIFF::TIFF``
+ The TIFF library, if found.
+
+``TIFF::CXX``
+ .. versionadded:: 3.19
+
+ The C++ wrapper libtiffxx, if requested by the `COMPONENTS CXX` option,
+ if the compiler is not MSVC (which includes the C++ wrapper in libtiff),
+ and if found.
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``TIFF_FOUND``
+ true if the TIFF headers and libraries were found
+``TIFF_INCLUDE_DIR``
+ the directory containing the TIFF headers
+``TIFF_INCLUDE_DIRS``
+ the directory containing the TIFF headers
+``TIFF_LIBRARIES``
+ TIFF libraries to be linked
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``TIFF_INCLUDE_DIR``
+ the directory containing the TIFF headers
+``TIFF_LIBRARY_RELEASE``
+ the path to the TIFF library for release configurations
+``TIFF_LIBRARY_DEBUG``
+ the path to the TIFF library for debug configurations
+``TIFFXX_LIBRARY_RELEASE``
+ the path to the TIFFXX library for release configurations
+``TIFFXX_LIBRARY_DEBUG``
+ the path to the TIFFXX library for debug configurations
+
+.. versionadded:: 3.4
+ Debug and Release variants are found separately.
+#]=======================================================================]
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW)
+
+find_path(TIFF_INCLUDE_DIR tiff.h)
+
+set(TIFF_NAMES ${TIFF_NAMES} tiff libtiff tiff3 libtiff3)
+foreach(name ${TIFF_NAMES})
+ list(APPEND TIFF_NAMES_DEBUG "${name}d")
+endforeach()
+
+if(NOT TIFF_LIBRARY)
+ find_library(TIFF_LIBRARY_RELEASE NAMES ${TIFF_NAMES})
+ find_library(TIFF_LIBRARY_DEBUG NAMES ${TIFF_NAMES_DEBUG})
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(TIFF)
+ mark_as_advanced(TIFF_LIBRARY_RELEASE TIFF_LIBRARY_DEBUG)
+endif()
+
+if(TIFF_INCLUDE_DIR AND EXISTS "${TIFF_INCLUDE_DIR}/tiffvers.h")
+ file(STRINGS "${TIFF_INCLUDE_DIR}/tiffvers.h" tiff_version_str
+ REGEX "^#define[\t ]+TIFFLIB_VERSION_STR[\t ]+\"LIBTIFF, Version .*")
+
+ string(REGEX REPLACE "^#define[\t ]+TIFFLIB_VERSION_STR[\t ]+\"LIBTIFF, Version +([^ \\n]*).*"
+ "\\1" TIFF_VERSION_STRING "${tiff_version_str}")
+ unset(tiff_version_str)
+endif()
+
+foreach(_comp IN LISTS TIFF_FIND_COMPONENTS)
+ if(_comp STREQUAL "CXX")
+ if(MSVC)
+ # C++ bindings are built into the main tiff library.
+ set(TIFF_CXX_FOUND 1)
+ else()
+ foreach(name ${TIFF_NAMES})
+ list(APPEND TIFFXX_NAMES "${name}xx")
+ list(APPEND TIFFXX_NAMES_DEBUG "${name}xxd")
+ endforeach()
+ find_library(TIFFXX_LIBRARY_RELEASE NAMES ${TIFFXX_NAMES})
+ find_library(TIFFXX_LIBRARY_DEBUG NAMES ${TIFFXX_NAMES_DEBUG})
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(TIFFXX)
+ mark_as_advanced(TIFFXX_LIBRARY_RELEASE TIFFXX_LIBRARY_DEBUG)
+ unset(TIFFXX_NAMES)
+ unset(TIFFXX_NAMES_DEBUG)
+ if(TIFFXX_LIBRARY)
+ set(TIFF_CXX_FOUND 1)
+ endif()
+ endif()
+ endif()
+endforeach()
+unset(_comp)
+
+unset(TIFF_NAMES)
+unset(TIFF_NAMES_DEBUG)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(TIFF
+ HANDLE_COMPONENTS
+ REQUIRED_VARS TIFF_LIBRARY TIFF_INCLUDE_DIR
+ VERSION_VAR TIFF_VERSION_STRING)
+
+if(TIFF_FOUND)
+ set(TIFF_LIBRARIES ${TIFF_LIBRARY})
+ if("CXX" IN_LIST TIFF_FIND_COMPONENTS AND NOT MSVC)
+ list(APPEND TIFF_LIBRARIES ${TIFFXX_LIBRARY})
+ endif()
+
+ set(TIFF_INCLUDE_DIRS "${TIFF_INCLUDE_DIR}")
+
+ if(NOT TARGET TIFF::TIFF)
+ add_library(TIFF::TIFF UNKNOWN IMPORTED)
+ if(TIFF_INCLUDE_DIRS)
+ set_target_properties(TIFF::TIFF PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${TIFF_INCLUDE_DIRS}")
+ endif()
+ if(EXISTS "${TIFF_LIBRARY}")
+ set_target_properties(TIFF::TIFF PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${TIFF_LIBRARY}")
+ endif()
+ if(EXISTS "${TIFF_LIBRARY_RELEASE}")
+ set_property(TARGET TIFF::TIFF APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(TIFF::TIFF PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+ IMPORTED_LOCATION_RELEASE "${TIFF_LIBRARY_RELEASE}")
+ endif()
+ if(EXISTS "${TIFF_LIBRARY_DEBUG}")
+ set_property(TARGET TIFF::TIFF APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(TIFF::TIFF PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+ IMPORTED_LOCATION_DEBUG "${TIFF_LIBRARY_DEBUG}")
+ endif()
+ endif()
+
+ if(NOT TARGET TIFF::CXX)
+ if(MSVC)
+ add_library(TIFF::CXX INTERFACE IMPORTED)
+ set_property(TARGET TIFF::CXX PROPERTY INTERFACE_LINK_LIBRARIES TIFF::TIFF)
+ else()
+ add_library(TIFF::CXX UNKNOWN IMPORTED)
+ set_property(TARGET TIFF::CXX PROPERTY INTERFACE_LINK_LIBRARIES TIFF::TIFF)
+ if(TIFF_INCLUDE_DIRS)
+ set_target_properties(TIFF::CXX PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${TIFF_INCLUDE_DIRS}")
+ endif()
+ if(EXISTS "${TIFFXX_LIBRARY}")
+ set_target_properties(TIFF::CXX PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
+ IMPORTED_LOCATION "${TIFFXX_LIBRARY}")
+ endif()
+ if(EXISTS "${TIFFXX_LIBRARY_RELEASE}")
+ set_property(TARGET TIFF::CXX APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(TIFF::CXX PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
+ IMPORTED_LOCATION_RELEASE "${TIFFXX_LIBRARY_RELEASE}")
+ endif()
+ if(EXISTS "${TIFFXX_LIBRARY_DEBUG}")
+ set_property(TARGET TIFF::CXX APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(TIFF::CXX PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
+ IMPORTED_LOCATION_DEBUG "${TIFFXX_LIBRARY_DEBUG}")
+ endif()
+ endif()
+ endif()
+
+endif()
+
+mark_as_advanced(TIFF_INCLUDE_DIR)
+cmake_policy(POP)
diff --git a/Modules/FindTclStub.cmake b/Modules/FindTclStub.cmake
new file mode 100644
index 0000000..8f63480
--- /dev/null
+++ b/Modules/FindTclStub.cmake
@@ -0,0 +1,143 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindTclStub
+-----------
+
+TCL_STUB_LIBRARY_DEBUG and TK_STUB_LIBRARY_DEBUG were removed.
+
+This module finds Tcl stub libraries. It first finds Tcl include
+files and libraries by calling FindTCL.cmake. How to Use the Tcl
+Stubs Library:
+
+::
+
+ http://tcl.activestate.com/doc/howto/stubs.html
+
+Using Stub Libraries:
+
+::
+
+ http://safari.oreilly.com/0130385603/ch48lev1sec3
+
+This code sets the following variables:
+
+::
+
+ TCL_STUB_LIBRARY = path to Tcl stub library
+ TK_STUB_LIBRARY = path to Tk stub library
+ TTK_STUB_LIBRARY = path to ttk stub library
+
+
+
+In an effort to remove some clutter and clear up some issues for
+people who are not necessarily Tcl/Tk gurus/developers, some
+variables were moved or removed. Changes compared to CMake 2.4 are:
+
+::
+
+ => these libs are not packaged by default with Tcl/Tk distributions.
+ Even when Tcl/Tk is built from source, several flavors of debug libs
+ are created and there is no real reason to pick a single one
+ specifically (say, amongst tclstub84g, tclstub84gs, or tclstub84sgx).
+ Let's leave that choice to the user by allowing him to assign
+ TCL_STUB_LIBRARY to any Tcl library, debug or not.
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindTCL.cmake)
+
+get_filename_component(TCL_TCLSH_PATH "${TCL_TCLSH}" PATH)
+get_filename_component(TCL_TCLSH_PATH_PARENT "${TCL_TCLSH_PATH}" PATH)
+string(REGEX REPLACE
+ "^.*tclsh([0-9]\\.*[0-9]).*$" "\\1" TCL_TCLSH_VERSION "${TCL_TCLSH}")
+
+get_filename_component(TK_WISH_PATH "${TK_WISH}" PATH)
+get_filename_component(TK_WISH_PATH_PARENT "${TK_WISH_PATH}" PATH)
+string(REGEX REPLACE
+ "^.*wish([0-9]\\.*[0-9]).*$" "\\1" TK_WISH_VERSION "${TK_WISH}")
+
+get_filename_component(TCL_INCLUDE_PATH_PARENT "${TCL_INCLUDE_PATH}" PATH)
+get_filename_component(TK_INCLUDE_PATH_PARENT "${TK_INCLUDE_PATH}" PATH)
+
+get_filename_component(TCL_LIBRARY_PATH "${TCL_LIBRARY}" PATH)
+get_filename_component(TCL_LIBRARY_PATH_PARENT "${TCL_LIBRARY_PATH}" PATH)
+string(REGEX REPLACE
+ "^.*tcl([0-9]\\.*[0-9]).*$" "\\1" TCL_LIBRARY_VERSION "${TCL_LIBRARY}")
+
+get_filename_component(TK_LIBRARY_PATH "${TK_LIBRARY}" PATH)
+get_filename_component(TK_LIBRARY_PATH_PARENT "${TK_LIBRARY_PATH}" PATH)
+string(REGEX REPLACE
+ "^.*tk([0-9]\\.*[0-9]).*$" "\\1" TK_LIBRARY_VERSION "${TK_LIBRARY}")
+
+set(TCLTK_POSSIBLE_LIB_PATHS
+ "${TCL_INCLUDE_PATH_PARENT}/lib"
+ "${TK_INCLUDE_PATH_PARENT}/lib"
+ "${TCL_LIBRARY_PATH}"
+ "${TK_LIBRARY_PATH}"
+ "${TCL_TCLSH_PATH_PARENT}/lib"
+ "${TK_WISH_PATH_PARENT}/lib"
+)
+
+if(WIN32)
+ get_filename_component(
+ ActiveTcl_CurrentVersion
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ActiveState\\ActiveTcl;CurrentVersion]"
+ NAME)
+ set(TCLTK_POSSIBLE_LIB_PATHS ${TCLTK_POSSIBLE_LIB_PATHS}
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ActiveState\\ActiveTcl\\${ActiveTcl_CurrentVersion}]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.6;Root]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.5;Root]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.4;Root]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.3;Root]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.2;Root]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.0;Root]/lib"
+ "$ENV{ProgramFiles}/Tcl/Lib"
+ "C:/Program Files/Tcl/lib"
+ "C:/Tcl/lib"
+ )
+endif()
+
+find_library(TCL_STUB_LIBRARY
+ NAMES
+ tclstub
+ tclstub${TK_LIBRARY_VERSION} tclstub${TCL_TCLSH_VERSION} tclstub${TK_WISH_VERSION}
+ tclstub87 tclstub8.7
+ tclstub86 tclstub8.6
+ tclstub85 tclstub8.5
+ tclstub84 tclstub8.4
+ tclstub83 tclstub8.3
+ tclstub82 tclstub8.2
+ tclstub80 tclstub8.0
+ PATHS ${TCLTK_POSSIBLE_LIB_PATHS}
+)
+
+find_library(TK_STUB_LIBRARY
+ NAMES
+ tkstub
+ tkstub${TCL_LIBRARY_VERSION} tkstub${TCL_TCLSH_VERSION} tkstub${TK_WISH_VERSION}
+ tkstub87 tkstub8.7
+ tkstub86 tkstub8.6
+ tkstub85 tkstub8.5
+ tkstub84 tkstub8.4
+ tkstub83 tkstub8.3
+ tkstub82 tkstub8.2
+ tkstub80 tkstub8.0
+ PATHS ${TCLTK_POSSIBLE_LIB_PATHS}
+)
+
+find_library(TTK_STUB_LIBRARY
+ NAMES
+ ttkstub
+ ttkstub${TCL_LIBRARY_VERSION} ttkstub${TCL_TCLSH_VERSION} ttkstub${TK_WISH_VERSION}
+ ttkstub88 ttkstub8.8
+ ttkstub87 ttkstub8.7
+ ttkstub86 ttkstub8.6
+ ttkstub85 ttkstub8.5
+ PATHS ${TCLTK_POSSIBLE_LIB_PATHS}
+)
+
+mark_as_advanced(
+ TCL_STUB_LIBRARY
+ TK_STUB_LIBRARY
+ )
diff --git a/Modules/FindTclsh.cmake b/Modules/FindTclsh.cmake
new file mode 100644
index 0000000..594d0ec
--- /dev/null
+++ b/Modules/FindTclsh.cmake
@@ -0,0 +1,101 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindTclsh
+---------
+
+Find tclsh
+
+This module finds if TCL is installed and determines where the include
+files and libraries are. It also determines what the name of the
+library is. This code sets the following variables:
+
+::
+
+ TCLSH_FOUND = TRUE if tclsh has been found
+ TCL_TCLSH = the path to the tclsh executable
+#]=======================================================================]
+
+get_filename_component(TK_WISH_PATH "${TK_WISH}" PATH)
+get_filename_component(TK_WISH_PATH_PARENT "${TK_WISH_PATH}" PATH)
+string(REGEX REPLACE
+ "^.*wish([0-9]\\.*[0-9]).*$" "\\1" TK_WISH_VERSION "${TK_WISH}")
+
+get_filename_component(TCL_INCLUDE_PATH_PARENT "${TCL_INCLUDE_PATH}" PATH)
+get_filename_component(TK_INCLUDE_PATH_PARENT "${TK_INCLUDE_PATH}" PATH)
+
+get_filename_component(TCL_LIBRARY_PATH "${TCL_LIBRARY}" PATH)
+get_filename_component(TCL_LIBRARY_PATH_PARENT "${TCL_LIBRARY_PATH}" PATH)
+string(REGEX REPLACE
+ "^.*tcl([0-9]\\.*[0-9]).*$" "\\1" TCL_LIBRARY_VERSION "${TCL_LIBRARY}")
+
+get_filename_component(TK_LIBRARY_PATH "${TK_LIBRARY}" PATH)
+get_filename_component(TK_LIBRARY_PATH_PARENT "${TK_LIBRARY_PATH}" PATH)
+string(REGEX REPLACE
+ "^.*tk([0-9]\\.*[0-9]).*$" "\\1" TK_LIBRARY_VERSION "${TK_LIBRARY}")
+
+set(TCLTK_POSSIBLE_BIN_PATHS
+ "${TCL_INCLUDE_PATH_PARENT}/bin"
+ "${TK_INCLUDE_PATH_PARENT}/bin"
+ "${TCL_LIBRARY_PATH_PARENT}/bin"
+ "${TK_LIBRARY_PATH_PARENT}/bin"
+ "${TK_WISH_PATH_PARENT}/bin"
+ )
+
+if(WIN32)
+ get_filename_component(
+ ActiveTcl_CurrentVersion
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ActiveState\\ActiveTcl;CurrentVersion]"
+ NAME)
+ set(TCLTK_POSSIBLE_BIN_PATHS ${TCLTK_POSSIBLE_BIN_PATHS}
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ActiveState\\ActiveTcl\\${ActiveTcl_CurrentVersion}]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.6;Root]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.5;Root]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.4;Root]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.3;Root]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.2;Root]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.0;Root]/bin"
+ )
+endif()
+
+set(TCL_TCLSH_NAMES
+ tclsh
+ tclsh${TCL_LIBRARY_VERSION} tclsh${TK_LIBRARY_VERSION} tclsh${TK_WISH_VERSION}
+ tclsh87 tclsh8.7
+ tclsh86 tclsh8.6
+ tclsh85 tclsh8.5
+ tclsh84 tclsh8.4
+ tclsh83 tclsh8.3
+ tclsh82 tclsh8.2
+ tclsh80 tclsh8.0
+ )
+
+find_program(TCL_TCLSH
+ NAMES ${TCL_TCLSH_NAMES}
+ HINTS ${TCLTK_POSSIBLE_BIN_PATHS}
+ )
+
+if(TCL_TCLSH)
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E echo puts "\$tcl_version"
+ COMMAND "${TCL_TCLSH}"
+ OUTPUT_VARIABLE TCLSH_VERSION_STRING
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+if (CMAKE_FIND_PACKAGE_NAME STREQUAL "TCL" OR
+ CMAKE_FIND_PACKAGE_NAME STREQUAL "TclStub")
+ # FindTCL include()'s this module. It's an old pattern, but rather than
+ # trying to suppress this from outside the module (which is then sensitive to
+ # the contents, detect the case in this module and suppress it explicitly.
+ # Transitively, FindTclStub includes FindTCL.
+ set(FPHSA_NAME_MISMATCHED 1)
+endif ()
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Tclsh
+ REQUIRED_VARS TCL_TCLSH
+ VERSION_VAR TCLSH_VERSION_STRING)
+unset(FPHSA_NAME_MISMATCHED)
+
+mark_as_advanced(TCL_TCLSH)
diff --git a/Modules/FindThreads.cmake b/Modules/FindThreads.cmake
new file mode 100644
index 0000000..28dffc0
--- /dev/null
+++ b/Modules/FindThreads.cmake
@@ -0,0 +1,258 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindThreads
+-----------
+
+This module determines the thread library of the system.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.1
+
+This module defines the following :prop_tgt:`IMPORTED` target:
+
+``Threads::Threads``
+ The thread library, if found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+The following variables are set:
+
+``Threads_FOUND``
+ If a supported thread library was found.
+``CMAKE_THREAD_LIBS_INIT``
+ The thread library to use. This may be empty if the thread functions
+ are provided by the system libraries and no special flags are needed
+ to use them.
+``CMAKE_USE_WIN32_THREADS_INIT``
+ If the found thread library is the win32 one.
+``CMAKE_USE_PTHREADS_INIT``
+ If the found thread library is pthread compatible.
+``CMAKE_HP_PTHREADS_INIT``
+ If the found thread library is the HP thread library.
+
+Variables Affecting Behavior
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. variable:: THREADS_PREFER_PTHREAD_FLAG
+
+ .. versionadded:: 3.1
+
+ If the use of the -pthread compiler and linker flag is preferred then
+ the caller can set this variable to TRUE. The compiler flag can only be
+ used with the imported target. Use of both the imported target as well
+ as this switch is highly recommended for new code.
+
+ This variable has no effect if the system libraries provide the
+ thread functions, i.e. when ``CMAKE_THREAD_LIBS_INIT`` will be empty.
+#]=======================================================================]
+
+include (CheckLibraryExists)
+set(Threads_FOUND FALSE)
+set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
+set(CMAKE_REQUIRED_QUIET ${Threads_FIND_QUIETLY})
+
+if(CMAKE_C_COMPILER_LOADED)
+ include (CheckIncludeFile)
+ include (CheckCSourceCompiles)
+elseif(CMAKE_CXX_COMPILER_LOADED)
+ include (CheckIncludeFileCXX)
+ include (CheckCXXSourceCompiles)
+else()
+ message(FATAL_ERROR "FindThreads only works if either C or CXX language is enabled")
+endif()
+
+# simple pthread test code
+set(PTHREAD_C_CXX_TEST_SOURCE [====[
+#include <pthread.h>
+
+static void* test_func(void* data)
+{
+ return data;
+}
+
+int main(void)
+{
+ pthread_t thread;
+ pthread_create(&thread, NULL, test_func, NULL);
+ pthread_detach(thread);
+ pthread_cancel(thread);
+ pthread_join(thread, NULL);
+ pthread_atfork(NULL, NULL, NULL);
+ pthread_exit(NULL);
+
+ return 0;
+}
+]====])
+
+# Internal helper macro.
+# Do NOT even think about using it outside of this file!
+macro(_check_threads_lib LIBNAME FUNCNAME VARNAME)
+ if(NOT Threads_FOUND)
+ CHECK_LIBRARY_EXISTS(${LIBNAME} ${FUNCNAME} "" ${VARNAME})
+ if(${VARNAME})
+ set(CMAKE_THREAD_LIBS_INIT "-l${LIBNAME}")
+ set(CMAKE_HAVE_THREADS_LIBRARY 1)
+ set(Threads_FOUND TRUE)
+ endif()
+ endif ()
+endmacro()
+
+# Internal helper macro.
+# Do NOT even think about using it outside of this file!
+macro(_check_pthreads_flag)
+ if(NOT Threads_FOUND)
+ # If we did not found -lpthread, -lpthread, or -lthread, look for -pthread
+ if(NOT DEFINED THREADS_HAVE_PTHREAD_ARG)
+ message(CHECK_START "Check if compiler accepts -pthread")
+ if(CMAKE_C_COMPILER_LOADED)
+ set(_threads_src ${CMAKE_CURRENT_LIST_DIR}/CheckForPthreads.c)
+ elseif(CMAKE_CXX_COMPILER_LOADED)
+ set(_threads_src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindThreads/CheckForPthreads.cxx)
+ configure_file(${CMAKE_CURRENT_LIST_DIR}/CheckForPthreads.c "${_threads_src}" COPYONLY)
+ endif()
+ try_compile(THREADS_HAVE_PTHREAD_ARG
+ ${CMAKE_BINARY_DIR}
+ ${_threads_src}
+ CMAKE_FLAGS -DLINK_LIBRARIES:STRING=-pthread
+ OUTPUT_VARIABLE _cmake_check_pthreads_output)
+
+ string(APPEND _cmake_find_threads_output "${_cmake_check_pthreads_output}")
+ unset(_cmake_check_pthreads_output)
+ unset(_threads_src)
+
+ if(THREADS_HAVE_PTHREAD_ARG)
+ set(Threads_FOUND TRUE)
+ message(CHECK_PASS "yes")
+ else()
+ message(CHECK_FAIL "no")
+ endif()
+
+ endif()
+
+ if(THREADS_HAVE_PTHREAD_ARG)
+ set(Threads_FOUND TRUE)
+ set(CMAKE_THREAD_LIBS_INIT "-pthread")
+ endif()
+ endif()
+endmacro()
+
+# Do we have pthreads?
+if(CMAKE_C_COMPILER_LOADED)
+ CHECK_INCLUDE_FILE("pthread.h" CMAKE_HAVE_PTHREAD_H)
+else()
+ CHECK_INCLUDE_FILE_CXX("pthread.h" CMAKE_HAVE_PTHREAD_H)
+endif()
+
+if(CMAKE_HAVE_PTHREAD_H)
+ #
+ # We have pthread.h
+ # Let's check for the library now.
+ #
+ set(CMAKE_HAVE_THREADS_LIBRARY)
+ if(NOT THREADS_HAVE_PTHREAD_ARG)
+ # Check if pthread functions are in normal C library.
+ # We list some pthread functions in PTHREAD_C_CXX_TEST_SOURCE test code.
+ # If the pthread functions already exist in C library, we could just use
+ # them instead of linking to the additional pthread library.
+ if(CMAKE_C_COMPILER_LOADED)
+ CHECK_C_SOURCE_COMPILES("${PTHREAD_C_CXX_TEST_SOURCE}" CMAKE_HAVE_LIBC_PTHREAD)
+ elseif(CMAKE_CXX_COMPILER_LOADED)
+ CHECK_CXX_SOURCE_COMPILES("${PTHREAD_C_CXX_TEST_SOURCE}" CMAKE_HAVE_LIBC_PTHREAD)
+ endif()
+ if(CMAKE_HAVE_LIBC_PTHREAD)
+ set(CMAKE_THREAD_LIBS_INIT "")
+ set(CMAKE_HAVE_THREADS_LIBRARY 1)
+ set(Threads_FOUND TRUE)
+ else()
+ # Check for -pthread first if enabled. This is the recommended
+ # way, but not backwards compatible as one must also pass -pthread
+ # as compiler flag then.
+ if (THREADS_PREFER_PTHREAD_FLAG)
+ _check_pthreads_flag()
+ endif ()
+
+ if(CMAKE_SYSTEM MATCHES "GHS-MULTI")
+ _check_threads_lib(posix pthread_create CMAKE_HAVE_PTHREADS_CREATE)
+ endif()
+ _check_threads_lib(pthreads pthread_create CMAKE_HAVE_PTHREADS_CREATE)
+ _check_threads_lib(pthread pthread_create CMAKE_HAVE_PTHREAD_CREATE)
+ if(CMAKE_SYSTEM_NAME MATCHES "SunOS")
+ # On sun also check for -lthread
+ _check_threads_lib(thread thr_create CMAKE_HAVE_THR_CREATE)
+ endif()
+ endif()
+ endif()
+
+ _check_pthreads_flag()
+endif()
+
+if(CMAKE_THREAD_LIBS_INIT OR CMAKE_HAVE_LIBC_PTHREAD)
+ set(CMAKE_USE_PTHREADS_INIT 1)
+ set(Threads_FOUND TRUE)
+endif()
+
+if(CMAKE_SYSTEM_NAME MATCHES "Windows")
+ set(CMAKE_USE_WIN32_THREADS_INIT 1)
+ set(Threads_FOUND TRUE)
+endif()
+
+if(CMAKE_USE_PTHREADS_INIT)
+ if(CMAKE_SYSTEM_NAME MATCHES "HP-UX")
+ # Use libcma if it exists and can be used. It provides more
+ # symbols than the plain pthread library. CMA threads
+ # have actually been deprecated:
+ # http://docs.hp.com/en/B3920-90091/ch12s03.html#d0e11395
+ # http://docs.hp.com/en/947/d8.html
+ # but we need to maintain compatibility here.
+ # The CMAKE_HP_PTHREADS setting actually indicates whether CMA threads
+ # are available.
+ CHECK_LIBRARY_EXISTS(cma pthread_attr_create "" CMAKE_HAVE_HP_CMA)
+ if(CMAKE_HAVE_HP_CMA)
+ set(CMAKE_THREAD_LIBS_INIT "-lcma")
+ set(CMAKE_HP_PTHREADS_INIT 1)
+ set(Threads_FOUND TRUE)
+ endif()
+ set(CMAKE_USE_PTHREADS_INIT 1)
+ endif()
+
+ if(CMAKE_SYSTEM MATCHES "OSF1-V")
+ set(CMAKE_USE_PTHREADS_INIT 0)
+ set(CMAKE_THREAD_LIBS_INIT )
+ endif()
+
+ if(CMAKE_SYSTEM MATCHES "CYGWIN_NT")
+ set(CMAKE_USE_PTHREADS_INIT 1)
+ set(Threads_FOUND TRUE)
+ set(CMAKE_THREAD_LIBS_INIT )
+ set(CMAKE_USE_WIN32_THREADS_INIT 0)
+ endif()
+endif()
+
+set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE})
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Threads DEFAULT_MSG Threads_FOUND)
+
+if(THREADS_FOUND AND NOT TARGET Threads::Threads)
+ add_library(Threads::Threads INTERFACE IMPORTED)
+
+ if(THREADS_HAVE_PTHREAD_ARG)
+ set_property(TARGET Threads::Threads
+ PROPERTY INTERFACE_COMPILE_OPTIONS "$<$<COMPILE_LANG_AND_ID:CUDA,NVIDIA>:SHELL:-Xcompiler -pthread>"
+ "$<$<NOT:$<COMPILE_LANG_AND_ID:CUDA,NVIDIA>>:-pthread>")
+ endif()
+
+ if(CMAKE_THREAD_LIBS_INIT)
+ set_property(TARGET Threads::Threads PROPERTY INTERFACE_LINK_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}")
+ endif()
+elseif(NOT THREADS_FOUND AND _cmake_find_threads_output)
+ file(APPEND
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if compiler accepts -pthread failed with the following output:\n${_cmake_find_threads_output}\n\n")
+endif()
+
+unset(_cmake_find_threads_output)
diff --git a/Modules/FindUnixCommands.cmake b/Modules/FindUnixCommands.cmake
new file mode 100644
index 0000000..2513f5c
--- /dev/null
+++ b/Modules/FindUnixCommands.cmake
@@ -0,0 +1,71 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindUnixCommands
+----------------
+
+Find Unix commands, including the ones from Cygwin
+
+This module looks for the Unix commands ``bash``, ``cp``, ``gzip``,
+``mv``, ``rm``, and ``tar`` and stores the result in the variables
+``BASH``, ``CP``, ``GZIP``, ``MV``, ``RM``, and ``TAR``.
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindCygwin.cmake)
+
+find_program(BASH
+ bash
+ ${CYGWIN_INSTALL_PATH}/bin
+)
+mark_as_advanced(
+ BASH
+)
+
+find_program(CP
+ cp
+ ${CYGWIN_INSTALL_PATH}/bin
+)
+mark_as_advanced(
+ CP
+)
+
+find_program(GZIP
+ gzip
+ ${CYGWIN_INSTALL_PATH}/bin
+)
+mark_as_advanced(
+ GZIP
+)
+
+find_program(MV
+ mv
+ ${CYGWIN_INSTALL_PATH}/bin
+)
+mark_as_advanced(
+ MV
+)
+
+find_program(RM
+ rm
+ ${CYGWIN_INSTALL_PATH}/bin
+)
+mark_as_advanced(
+ RM
+)
+
+find_program(TAR
+ NAMES
+ tar
+ gtar
+ PATH
+ ${CYGWIN_INSTALL_PATH}/bin
+)
+mark_as_advanced(
+ TAR
+)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(UnixCommands
+ REQUIRED_VARS BASH CP GZIP MV RM TAR
+)
diff --git a/Modules/FindVulkan.cmake b/Modules/FindVulkan.cmake
new file mode 100644
index 0000000..ceb1921
--- /dev/null
+++ b/Modules/FindVulkan.cmake
@@ -0,0 +1,115 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindVulkan
+----------
+
+.. versionadded:: 3.7
+
+Find Vulkan, which is a low-overhead, cross-platform 3D graphics
+and computing API.
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+This module defines :prop_tgt:`IMPORTED` target ``Vulkan::Vulkan``, if
+Vulkan has been found.
+
+.. versionadded:: 3.19
+ This module defines :prop_tgt:`IMPORTED` target ``Vulkan::glslc``, if
+ Vulkan and the GLSLC SPIR-V compiler has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables::
+
+ Vulkan_FOUND - "True" if Vulkan was found
+ Vulkan_INCLUDE_DIRS - include directories for Vulkan
+ Vulkan_LIBRARIES - link against this library to use Vulkan
+
+The module will also define three cache variables::
+
+ Vulkan_INCLUDE_DIR - the Vulkan include directory
+ Vulkan_LIBRARY - the path to the Vulkan library
+ Vulkan_GLSLC_EXECUTABLE - the path to the GLSL SPIR-V compiler
+
+Hints
+^^^^^
+
+.. versionadded:: 3.18
+
+The ``VULKAN_SDK`` environment variable optionally specifies the
+location of the Vulkan SDK root directory for the given
+architecture. It is typically set by sourcing the toplevel
+``setup-env.sh`` script of the Vulkan SDK directory into the shell
+environment.
+
+#]=======================================================================]
+
+if(WIN32)
+ find_path(Vulkan_INCLUDE_DIR
+ NAMES vulkan/vulkan.h
+ HINTS
+ "$ENV{VULKAN_SDK}/Include"
+ )
+
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ find_library(Vulkan_LIBRARY
+ NAMES vulkan-1
+ HINTS
+ "$ENV{VULKAN_SDK}/Lib"
+ "$ENV{VULKAN_SDK}/Bin"
+ )
+ find_program(Vulkan_GLSLC_EXECUTABLE
+ NAMES glslc
+ HINTS
+ "$ENV{VULKAN_SDK}/Bin"
+ )
+ elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ find_library(Vulkan_LIBRARY
+ NAMES vulkan-1
+ HINTS
+ "$ENV{VULKAN_SDK}/Lib32"
+ "$ENV{VULKAN_SDK}/Bin32"
+ )
+ find_program(Vulkan_GLSLC_EXECUTABLE
+ NAMES glslc
+ HINTS
+ "$ENV{VULKAN_SDK}/Bin32"
+ )
+ endif()
+else()
+ find_path(Vulkan_INCLUDE_DIR
+ NAMES vulkan/vulkan.h
+ HINTS "$ENV{VULKAN_SDK}/include")
+ find_library(Vulkan_LIBRARY
+ NAMES vulkan
+ HINTS "$ENV{VULKAN_SDK}/lib")
+ find_program(Vulkan_GLSLC_EXECUTABLE
+ NAMES glslc
+ HINTS "$ENV{VULKAN_SDK}/bin")
+endif()
+
+set(Vulkan_LIBRARIES ${Vulkan_LIBRARY})
+set(Vulkan_INCLUDE_DIRS ${Vulkan_INCLUDE_DIR})
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(Vulkan
+ DEFAULT_MSG
+ Vulkan_LIBRARY Vulkan_INCLUDE_DIR)
+
+mark_as_advanced(Vulkan_INCLUDE_DIR Vulkan_LIBRARY Vulkan_GLSLC_EXECUTABLE)
+
+if(Vulkan_FOUND AND NOT TARGET Vulkan::Vulkan)
+ add_library(Vulkan::Vulkan UNKNOWN IMPORTED)
+ set_target_properties(Vulkan::Vulkan PROPERTIES
+ IMPORTED_LOCATION "${Vulkan_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES "${Vulkan_INCLUDE_DIRS}")
+endif()
+
+if(Vulkan_FOUND AND Vulkan_GLSLC_EXECUTABLE AND NOT TARGET Vulkan::glslc)
+ add_executable(Vulkan::glslc IMPORTED)
+ set_property(TARGET Vulkan::glslc PROPERTY IMPORTED_LOCATION "${Vulkan_GLSLC_EXECUTABLE}")
+endif()
diff --git a/Modules/FindWget.cmake b/Modules/FindWget.cmake
new file mode 100644
index 0000000..bd01ec2
--- /dev/null
+++ b/Modules/FindWget.cmake
@@ -0,0 +1,32 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindWget
+--------
+
+Find wget
+
+This module looks for wget. This module defines the following values:
+
+::
+
+ WGET_EXECUTABLE: the full path to the wget tool.
+ WGET_FOUND: True if wget has been found.
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindCygwin.cmake)
+
+find_program(WGET_EXECUTABLE
+ wget
+ ${CYGWIN_INSTALL_PATH}/bin
+)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Wget DEFAULT_MSG WGET_EXECUTABLE)
+
+mark_as_advanced( WGET_EXECUTABLE )
+
+# WGET option is deprecated.
+# use WGET_EXECUTABLE instead.
+set (WGET ${WGET_EXECUTABLE})
diff --git a/Modules/FindWish.cmake b/Modules/FindWish.cmake
new file mode 100644
index 0000000..b332bde
--- /dev/null
+++ b/Modules/FindWish.cmake
@@ -0,0 +1,85 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindWish
+--------
+
+Find wish installation
+
+This module finds if TCL is installed and determines where the include
+files and libraries are. It also determines what the name of the
+library is. This code sets the following variables:
+
+::
+
+ TK_WISH = the path to the wish executable
+
+
+
+if UNIX is defined, then it will look for the cygwin version first
+#]=======================================================================]
+
+if(UNIX)
+ find_program(TK_WISH cygwish80 )
+endif()
+
+get_filename_component(TCL_TCLSH_PATH "${TCL_TCLSH}" PATH)
+get_filename_component(TCL_TCLSH_PATH_PARENT "${TCL_TCLSH_PATH}" PATH)
+string(REGEX REPLACE
+ "^.*tclsh([0-9]\\.*[0-9]).*$" "\\1" TCL_TCLSH_VERSION "${TCL_TCLSH}")
+
+get_filename_component(TCL_INCLUDE_PATH_PARENT "${TCL_INCLUDE_PATH}" PATH)
+get_filename_component(TK_INCLUDE_PATH_PARENT "${TK_INCLUDE_PATH}" PATH)
+
+get_filename_component(TCL_LIBRARY_PATH "${TCL_LIBRARY}" PATH)
+get_filename_component(TCL_LIBRARY_PATH_PARENT "${TCL_LIBRARY_PATH}" PATH)
+string(REGEX REPLACE
+ "^.*tcl([0-9]\\.*[0-9]).*$" "\\1" TCL_LIBRARY_VERSION "${TCL_LIBRARY}")
+
+get_filename_component(TK_LIBRARY_PATH "${TK_LIBRARY}" PATH)
+get_filename_component(TK_LIBRARY_PATH_PARENT "${TK_LIBRARY_PATH}" PATH)
+string(REGEX REPLACE
+ "^.*tk([0-9]\\.*[0-9]).*$" "\\1" TK_LIBRARY_VERSION "${TK_LIBRARY}")
+
+set(TCLTK_POSSIBLE_BIN_PATHS
+ "${TCL_INCLUDE_PATH_PARENT}/bin"
+ "${TK_INCLUDE_PATH_PARENT}/bin"
+ "${TCL_LIBRARY_PATH_PARENT}/bin"
+ "${TK_LIBRARY_PATH_PARENT}/bin"
+ "${TCL_TCLSH_PATH_PARENT}/bin"
+ )
+
+if(WIN32)
+ get_filename_component(
+ ActiveTcl_CurrentVersion
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ActiveState\\ActiveTcl;CurrentVersion]"
+ NAME)
+ set(TCLTK_POSSIBLE_BIN_PATHS ${TCLTK_POSSIBLE_BIN_PATHS}
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ActiveState\\ActiveTcl\\${ActiveTcl_CurrentVersion}]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.6;Root]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.5;Root]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.4;Root]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.3;Root]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.2;Root]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Scriptics\\Tcl\\8.0;Root]/bin"
+ )
+endif()
+
+set(TK_WISH_NAMES
+ wish
+ wish${TCL_LIBRARY_VERSION} wish${TK_LIBRARY_VERSION} wish${TCL_TCLSH_VERSION}
+ wish86 wish8.6
+ wish85 wish8.5
+ wish84 wish8.4
+ wish83 wish8.3
+ wish82 wish8.2
+ wish80 wish8.0
+ )
+
+find_program(TK_WISH
+ NAMES ${TK_WISH_NAMES}
+ HINTS ${TCLTK_POSSIBLE_BIN_PATHS}
+ )
+
+mark_as_advanced(TK_WISH)
diff --git a/Modules/FindX11.cmake b/Modules/FindX11.cmake
new file mode 100644
index 0000000..d480fc4
--- /dev/null
+++ b/Modules/FindX11.cmake
@@ -0,0 +1,898 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindX11
+-------
+
+Find X11 installation
+
+Try to find X11 on UNIX systems. The following values are defined
+
+::
+
+ X11_FOUND - True if X11 is available
+ X11_INCLUDE_DIR - include directories to use X11
+ X11_LIBRARIES - link against these to use X11
+
+and also the following more fine grained variables and targets:
+
+.. versionadded:: 3.14
+ Imported targets.
+
+::
+
+ X11_ICE_INCLUDE_PATH, X11_ICE_LIB, X11_ICE_FOUND, X11::ICE
+ X11_SM_INCLUDE_PATH, X11_SM_LIB, X11_SM_FOUND, X11::SM
+ X11_X11_INCLUDE_PATH, X11_X11_LIB, X11::X11
+ X11_Xaccessrules_INCLUDE_PATH,
+ X11_Xaccessstr_INCLUDE_PATH, X11_Xaccess_FOUND
+ X11_Xau_INCLUDE_PATH, X11_Xau_LIB, X11_Xau_FOUND, X11::Xau
+ X11_xcb_INCLUDE_PATH, X11_xcb_LIB, X11_xcb_FOUND, X11::xcb
+ X11_X11_xcb_INCLUDE_PATH, X11_X11_xcb_LIB, X11_X11_xcb_FOUND, X11::X11_xcb
+ X11_xcb_icccm_INCLUDE_PATH, X11_xcb_icccm_LIB, X11_xcb_icccm_FOUND, X11::xcb_icccm
+ X11_xcb_util_INCLUDE_PATH, X11_xcb_util_LIB, X11_xcb_util_FOUND, X11::xcb_util
+ X11_xcb_xfixes_INCLUDE_PATH, X11_xcb_xfixes_LIB, X11_xcb_xfixes_FOUND, X11::xcb_xfixes
+ X11_xcb_xkb_INCLUDE_PATH, X11_xcb_xkb_LIB, X11_xcb_xkb_FOUND, X11::xcb_xkb
+ X11_Xcomposite_INCLUDE_PATH, X11_Xcomposite_LIB, X11_Xcomposite_FOUND, X11::Xcomposite
+ X11_Xcursor_INCLUDE_PATH, X11_Xcursor_LIB, X11_Xcursor_FOUND, X11::Xcursor
+ X11_Xdamage_INCLUDE_PATH, X11_Xdamage_LIB, X11_Xdamage_FOUND, X11::Xdamage
+ X11_Xdmcp_INCLUDE_PATH, X11_Xdmcp_LIB, X11_Xdmcp_FOUND, X11::Xdmcp
+ X11_Xext_INCLUDE_PATH, X11_Xext_LIB, X11_Xext_FOUND, X11::Xext
+ X11_Xxf86misc_INCLUDE_PATH, X11_Xxf86misc_LIB, X11_Xxf86misc_FOUND, X11::Xxf86misc
+ X11_Xxf86vm_INCLUDE_PATH, X11_Xxf86vm_LIB X11_Xxf86vm_FOUND, X11::Xxf86vm
+ X11_Xfixes_INCLUDE_PATH, X11_Xfixes_LIB, X11_Xfixes_FOUND, X11::Xfixes
+ X11_Xft_INCLUDE_PATH, X11_Xft_LIB, X11_Xft_FOUND, X11::Xft
+ X11_Xi_INCLUDE_PATH, X11_Xi_LIB, X11_Xi_FOUND, X11::Xi
+ X11_Xinerama_INCLUDE_PATH, X11_Xinerama_LIB, X11_Xinerama_FOUND, X11::Xinerama
+ X11_Xkb_INCLUDE_PATH,
+ X11_Xkblib_INCLUDE_PATH, X11_Xkb_FOUND, X11::Xkb
+ X11_xkbcommon_INCLUDE_PATH, X11_xkbcommon_LIB, X11_xkbcommon_FOUND, X11::xkbcommon
+ X11_xkbcommon_X11_INCLUDE_PATH,X11_xkbcommon_X11_LIB,X11_xkbcommon_X11_FOUND,X11::xkbcommon_X11
+ X11_xkbfile_INCLUDE_PATH, X11_xkbfile_LIB, X11_xkbfile_FOUND, X11::xkbfile
+ X11_Xmu_INCLUDE_PATH, X11_Xmu_LIB, X11_Xmu_FOUND, X11::Xmu
+ X11_Xpm_INCLUDE_PATH, X11_Xpm_LIB, X11_Xpm_FOUND, X11::Xpm
+ X11_Xtst_INCLUDE_PATH, X11_Xtst_LIB, X11_Xtst_FOUND, X11::Xtst
+ X11_Xrandr_INCLUDE_PATH, X11_Xrandr_LIB, X11_Xrandr_FOUND, X11::Xrandr
+ X11_Xrender_INCLUDE_PATH, X11_Xrender_LIB, X11_Xrender_FOUND, X11::Xrender
+ X11_XRes_INCLUDE_PATH, X11_XRes_LIB, X11_XRes_FOUND, X11::XRes
+ X11_Xss_INCLUDE_PATH, X11_Xss_LIB, X11_Xss_FOUND, X11::Xss
+ X11_Xt_INCLUDE_PATH, X11_Xt_LIB, X11_Xt_FOUND, X11::Xt
+ X11_Xutil_INCLUDE_PATH, X11_Xutil_FOUND, X11::Xutil
+ X11_Xv_INCLUDE_PATH, X11_Xv_LIB, X11_Xv_FOUND, X11::Xv
+ X11_dpms_INCLUDE_PATH, (in X11_Xext_LIB), X11_dpms_FOUND
+ X11_XShm_INCLUDE_PATH, (in X11_Xext_LIB), X11_XShm_FOUND
+ X11_Xshape_INCLUDE_PATH, (in X11_Xext_LIB), X11_Xshape_FOUND
+ X11_XSync_INCLUDE_PATH, (in X11_Xext_LIB), X11_XSync_FOUND
+ X11_Xaw_INCLUDE_PATH, X11_Xaw_LIB X11_Xaw_FOUND X11::Xaw
+
+.. versionadded:: 3.14
+ Renamed ``Xxf86misc``, ``X11_Xxf86misc``, ``X11_Xxf86vm``, ``X11_xkbfile``,
+ ``X11_Xtst``, and ``X11_Xss`` libraries to match their file names.
+ Deprecated the ``X11_Xinput`` library. Old names are still available
+ for compatibility.
+
+.. versionadded:: 3.14
+ Added the ``X11_Xext_INCLUDE_PATH`` variable.
+
+.. versionadded:: 3.18
+ Added the ``xcb``, ``X11-xcb``, ``xcb-icccm``, ``xcb-xkb``, ``xkbcommon``,
+ and ``xkbcommon-X11`` libraries.
+
+.. versionadded:: 3.19
+ Added the ``Xaw``, ``xcb_util``, and ``xcb_xfixes`` libraries.
+
+#]=======================================================================]
+
+if (UNIX)
+ set(X11_FOUND 0)
+ # X11 is never a framework and some header files may be
+ # found in tcl on the mac
+ set(CMAKE_FIND_FRAMEWORK_SAVE ${CMAKE_FIND_FRAMEWORK})
+ set(CMAKE_FIND_FRAMEWORK NEVER)
+ set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
+ set(CMAKE_REQUIRED_QUIET ${X11_FIND_QUIETLY})
+ set(X11_INC_SEARCH_PATH
+ /usr/pkg/xorg/include
+ /usr/X11R6/include
+ /usr/X11R7/include
+ /usr/include/X11
+ /usr/openwin/include
+ /usr/openwin/share/include
+ /opt/graphics/OpenGL/include
+ /opt/X11/include
+ )
+
+ set(X11_LIB_SEARCH_PATH
+ /usr/pkg/xorg/lib
+ /usr/X11R6/lib
+ /usr/X11R7/lib
+ /usr/openwin/lib
+ /opt/X11/lib
+ )
+
+ find_path(X11_X11_INCLUDE_PATH X11/X.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xlib_INCLUDE_PATH X11/Xlib.h ${X11_INC_SEARCH_PATH})
+
+ # Look for includes; keep the list sorted by name of the cmake *_INCLUDE_PATH
+ # variable (which doesn't need to match the include file name).
+
+ # Solaris lacks XKBrules.h, so we should skip kxkbd there.
+ find_path(X11_ICE_INCLUDE_PATH X11/ICE/ICE.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_SM_INCLUDE_PATH X11/SM/SM.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xaccessrules_INCLUDE_PATH X11/extensions/XKBrules.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xaccessstr_INCLUDE_PATH X11/extensions/XKBstr.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xau_INCLUDE_PATH X11/Xauth.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xaw_INCLUDE_PATH X11/Xaw/Intrinsic.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_xcb_INCLUDE_PATH xcb/xcb.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_X11_xcb_INCLUDE_PATH X11/Xlib-xcb.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_xcb_icccm_INCLUDE_PATH xcb/xcb_icccm.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_xcb_util_INCLUDE_PATH xcb/xcb_aux.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_xcb_xfixes_INCLUDE_PATH xcb/xfixes.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xcomposite_INCLUDE_PATH X11/extensions/Xcomposite.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xcursor_INCLUDE_PATH X11/Xcursor/Xcursor.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xdamage_INCLUDE_PATH X11/extensions/Xdamage.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xdmcp_INCLUDE_PATH X11/Xdmcp.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xext_INCLUDE_PATH X11/extensions/Xext.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_dpms_INCLUDE_PATH X11/extensions/dpms.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xxf86misc_INCLUDE_PATH X11/extensions/xf86misc.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xxf86vm_INCLUDE_PATH X11/extensions/xf86vmode.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xfixes_INCLUDE_PATH X11/extensions/Xfixes.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xft_INCLUDE_PATH X11/Xft/Xft.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xi_INCLUDE_PATH X11/extensions/XInput.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xinerama_INCLUDE_PATH X11/extensions/Xinerama.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xkb_INCLUDE_PATH X11/extensions/XKB.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_xkbcommon_INCLUDE_PATH xkbcommon/xkbcommon.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_xkbcommon_X11_INCLUDE_PATH xkbcommon/xkbcommon-x11.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xkblib_INCLUDE_PATH X11/XKBlib.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_xkbfile_INCLUDE_PATH X11/extensions/XKBfile.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xmu_INCLUDE_PATH X11/Xmu/Xmu.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xpm_INCLUDE_PATH X11/xpm.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xtst_INCLUDE_PATH X11/extensions/XTest.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_XShm_INCLUDE_PATH X11/extensions/XShm.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xrandr_INCLUDE_PATH X11/extensions/Xrandr.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xrender_INCLUDE_PATH X11/extensions/Xrender.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_XRes_INCLUDE_PATH X11/extensions/XRes.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xss_INCLUDE_PATH X11/extensions/scrnsaver.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xshape_INCLUDE_PATH X11/extensions/shape.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xutil_INCLUDE_PATH X11/Xutil.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xt_INCLUDE_PATH X11/Intrinsic.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_Xv_INCLUDE_PATH X11/extensions/Xvlib.h ${X11_INC_SEARCH_PATH})
+ find_path(X11_XSync_INCLUDE_PATH X11/extensions/sync.h ${X11_INC_SEARCH_PATH})
+
+
+
+ # Backwards compatibility.
+ set(X11_Xinput_INCLUDE_PATH "${X11_Xi_INCLUDE_PATH}")
+ set(X11_xf86misc_INCLUDE_PATH "${X11_Xxf86misc_INCLUDE_PATH}")
+ set(X11_xf86vmode_INCLUDE_PATH "${X11_Xxf8vm_INCLUDE_PATH}")
+ set(X11_Xkbfile_INCLUDE_PATH "${X11_xkbfile_INCLUDE_PATH}")
+ set(X11_XTest_INCLUDE_PATH "${X11_Xtst_INCLUDE_PATH}")
+ set(X11_Xscreensaver_INCLUDE_PATH "${X11_Xss_INCLUDE_PATH}")
+
+ find_library(X11_X11_LIB X11 ${X11_LIB_SEARCH_PATH})
+
+ # Find additional X libraries. Keep list sorted by library name.
+ find_library(X11_ICE_LIB ICE ${X11_LIB_SEARCH_PATH})
+ find_library(X11_SM_LIB SM ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xau_LIB Xau ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xaw_LIB Xaw ${X11_LIB_SEARCH_PATH})
+ find_library(X11_xcb_LIB xcb ${X11_LIB_SEARCH_PATH})
+ find_library(X11_X11_xcb_LIB X11-xcb ${X11_LIB_SEARCH_PATH})
+ find_library(X11_xcb_icccm_LIB xcb-icccm ${X11_LIB_SEARCH_PATH})
+ find_library(X11_xcb_util_LIB xcb-util ${X11_LIB_SEARCH_PATH})
+ find_library(X11_xcb_xfixes_LIB xcb-xfixes ${X11_LIB_SEARCH_PATH})
+ find_library(X11_xcb_xkb_LIB xcb-xkb ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xcomposite_LIB Xcomposite ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xcursor_LIB Xcursor ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xdamage_LIB Xdamage ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xdmcp_LIB Xdmcp ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xext_LIB Xext ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xfixes_LIB Xfixes ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xft_LIB Xft ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xi_LIB Xi ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xinerama_LIB Xinerama ${X11_LIB_SEARCH_PATH})
+ find_library(X11_xkbcommon_LIB xkbcommon ${X11_LIB_SEARCH_PATH})
+ find_library(X11_xkbcommon_X11_LIB xkbcommon-x11 ${X11_LIB_SEARCH_PATH})
+ find_library(X11_xkbfile_LIB xkbfile ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xmu_LIB Xmu ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xpm_LIB Xpm ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xrandr_LIB Xrandr ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xrender_LIB Xrender ${X11_LIB_SEARCH_PATH})
+ find_library(X11_XRes_LIB XRes ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xss_LIB Xss ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xt_LIB Xt ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xtst_LIB Xtst ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xv_LIB Xv ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xxf86misc_LIB Xxf86misc ${X11_LIB_SEARCH_PATH})
+ find_library(X11_Xxf86vm_LIB Xxf86vm ${X11_LIB_SEARCH_PATH})
+
+ # Backwards compatibility.
+ set(X11_Xinput_LIB "${X11_Xi_LIB}")
+ set(X11_Xkbfile_LIB "${X11_xkbfile_LIB}")
+ set(X11_XTest_LIB "${X11_Xtst_LIB}")
+ set(X11_Xscreensaver_LIB "${X11_Xss_LIB}")
+
+ set(X11_LIBRARY_DIR "")
+ if(X11_X11_LIB)
+ get_filename_component(X11_LIBRARY_DIR ${X11_X11_LIB} PATH)
+ endif()
+
+ set(X11_INCLUDE_DIR) # start with empty list
+ if(X11_X11_INCLUDE_PATH)
+ list(APPEND X11_INCLUDE_DIR ${X11_X11_INCLUDE_PATH})
+ endif()
+
+ if(X11_Xlib_INCLUDE_PATH)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xlib_INCLUDE_PATH})
+ endif()
+
+ if(X11_Xutil_INCLUDE_PATH)
+ set(X11_Xutil_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xutil_INCLUDE_PATH})
+ endif()
+
+ if(X11_Xshape_INCLUDE_PATH)
+ set(X11_Xshape_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xshape_INCLUDE_PATH})
+ endif()
+
+ set(X11_LIBRARIES) # start with empty list
+ if(X11_X11_LIB)
+ list(APPEND X11_LIBRARIES ${X11_X11_LIB})
+ endif()
+
+ if(X11_Xext_LIB)
+ set(X11_Xext_FOUND TRUE)
+ list(APPEND X11_LIBRARIES ${X11_Xext_LIB})
+ endif()
+
+ if(X11_Xt_LIB AND X11_Xt_INCLUDE_PATH)
+ set(X11_Xt_FOUND TRUE)
+ endif()
+
+ if(X11_Xft_LIB AND X11_Xft_INCLUDE_PATH)
+ find_package(Freetype QUIET)
+ find_package(Fontconfig QUIET)
+ if (FREETYPE_FOUND AND Fontconfig_FOUND)
+ set(X11_Xft_FOUND TRUE)
+ endif ()
+ list(APPEND X11_INCLUDE_DIR ${X11_Xft_INCLUDE_PATH})
+ endif()
+
+ if(X11_Xv_LIB AND X11_Xv_INCLUDE_PATH)
+ set(X11_Xv_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xv_INCLUDE_PATH})
+ endif()
+
+ if (X11_Xau_LIB AND X11_Xau_INCLUDE_PATH)
+ set(X11_Xau_FOUND TRUE)
+ endif ()
+
+ if (X11_xcb_LIB AND X11_xcb_INCLUDE_PATH)
+ set(X11_xcb_FOUND TRUE)
+ endif ()
+
+ if (X11_X11_xcb_LIB AND X11_X11_xcb_INCLUDE_PATH)
+ set(X11_X11_xcb_FOUND TRUE)
+ endif ()
+
+ if (X11_xcb_icccm_LIB AND X11_xcb_icccm_INCLUDE_PATH)
+ set(X11_xcb_icccm_FOUND TRUE)
+ endif ()
+
+ if (X11_xcb_util_LIB AND X11_xcb_util_INCLUDE_PATH)
+ set(X11_xcb_util_FOUND TRUE)
+ endif ()
+
+ if (X11_xcb_xfixes_LIB)
+ set(X11_xcb_xfixes_FOUND TRUE)
+ endif ()
+
+ if (X11_xcb_xkb_LIB)
+ set(X11_xcb_xkb_FOUND TRUE)
+ endif ()
+
+ if (X11_Xdmcp_INCLUDE_PATH AND X11_Xdmcp_LIB)
+ set(X11_Xdmcp_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xdmcp_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xaccessrules_INCLUDE_PATH AND X11_Xaccessstr_INCLUDE_PATH)
+ set(X11_Xaccess_FOUND TRUE)
+ set(X11_Xaccess_INCLUDE_PATH ${X11_Xaccessstr_INCLUDE_PATH})
+ list(APPEND X11_INCLUDE_DIR ${X11_Xaccess_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xpm_INCLUDE_PATH AND X11_Xpm_LIB)
+ set(X11_Xpm_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xpm_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xcomposite_INCLUDE_PATH AND X11_Xcomposite_LIB)
+ set(X11_Xcomposite_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xcomposite_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xdamage_INCLUDE_PATH AND X11_Xdamage_LIB)
+ set(X11_Xdamage_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xdamage_INCLUDE_PATH})
+ endif ()
+
+ if (X11_XShm_INCLUDE_PATH)
+ set(X11_XShm_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_XShm_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xtst_INCLUDE_PATH AND X11_Xtst_LIB)
+ set(X11_Xtst_FOUND TRUE)
+ # Backwards compatibility.
+ set(X11_XTest_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xtst_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xi_INCLUDE_PATH AND X11_Xi_LIB)
+ set(X11_Xi_FOUND TRUE)
+ # Backwards compatibility.
+ set(X11_Xinput_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xi_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xinerama_INCLUDE_PATH AND X11_Xinerama_LIB)
+ set(X11_Xinerama_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xinerama_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xfixes_INCLUDE_PATH AND X11_Xfixes_LIB)
+ set(X11_Xfixes_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xfixes_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xrender_INCLUDE_PATH AND X11_Xrender_LIB)
+ set(X11_Xrender_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xrender_INCLUDE_PATH})
+ endif ()
+
+ if (X11_XRes_INCLUDE_PATH AND X11_XRes_LIB)
+ set(X11_XRes_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_XRes_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xrandr_INCLUDE_PATH AND X11_Xrandr_LIB)
+ set(X11_Xrandr_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xrandr_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xxf86misc_INCLUDE_PATH AND X11_Xxf86misc_LIB)
+ set(X11_Xxf86misc_FOUND TRUE)
+ # Backwards compatibility.
+ set(X11_xf86misc_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xxf86misc_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xxf86vm_INCLUDE_PATH AND X11_Xxf86vm_LIB)
+ set(X11_Xxf86vm_FOUND TRUE)
+ # Backwards compatibility.
+ set(X11_xf86vmode_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xxf86vm_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xcursor_INCLUDE_PATH AND X11_Xcursor_LIB)
+ set(X11_Xcursor_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xcursor_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xss_INCLUDE_PATH AND X11_Xss_LIB)
+ set(X11_Xss_FOUND TRUE)
+ set(X11_Xscreensaver_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xss_INCLUDE_PATH})
+ endif ()
+
+ if (X11_dpms_INCLUDE_PATH)
+ set(X11_dpms_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_dpms_INCLUDE_PATH})
+ endif ()
+
+ if (X11_Xkb_INCLUDE_PATH AND X11_Xkblib_INCLUDE_PATH AND X11_Xlib_INCLUDE_PATH)
+ set(X11_Xkb_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xkb_INCLUDE_PATH} )
+ endif ()
+
+ if (X11_xkbcommon_INCLUDE_PATH AND X11_xkbcommon_LIB)
+ set(X11_xkbcommon_FOUND TRUE)
+ endif ()
+
+ if (X11_xkbcommon_X11_INCLUDE_PATH AND X11_xkbcommon_X11_LIB)
+ set(X11_xkbcommon_X11_FOUND TRUE)
+ endif ()
+
+ if (X11_xkbfile_INCLUDE_PATH AND X11_xkbfile_LIB AND X11_Xlib_INCLUDE_PATH)
+ set(X11_xkbfile_FOUND TRUE)
+ # Backwards compatibility.
+ set(X11_Xkbfile_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_xkbfile_INCLUDE_PATH} )
+ endif ()
+
+ if (X11_Xmu_INCLUDE_PATH AND X11_Xmu_LIB)
+ set(X11_Xmu_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_Xmu_INCLUDE_PATH})
+ endif ()
+
+ if (X11_XSync_INCLUDE_PATH)
+ set(X11_XSync_FOUND TRUE)
+ list(APPEND X11_INCLUDE_DIR ${X11_XSync_INCLUDE_PATH})
+ endif ()
+
+ if(X11_ICE_LIB AND X11_ICE_INCLUDE_PATH)
+ set(X11_ICE_FOUND TRUE)
+ endif()
+
+ if(X11_SM_LIB AND X11_SM_INCLUDE_PATH)
+ set(X11_SM_FOUND TRUE)
+ endif()
+
+ if(X11_Xaw_LIB AND X11_Xaw_INCLUDE_PATH)
+ set(X11_Xaw_FOUND TRUE)
+ endif()
+
+ # Most of the X11 headers will be in the same directories, avoid
+ # creating a huge list of duplicates.
+ if (X11_INCLUDE_DIR)
+ list(REMOVE_DUPLICATES X11_INCLUDE_DIR)
+ endif ()
+
+ # Deprecated variable for backwards compatibility with CMake 1.4
+ if (X11_X11_INCLUDE_PATH AND X11_LIBRARIES)
+ set(X11_FOUND 1)
+ endif ()
+
+ include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+ if (CMAKE_FIND_PACKAGE_NAME STREQUAL "FLTK")
+ # FindFLTK include()'s this module. It's an old pattern, but rather than
+ # trying to suppress this from outside the module (which is then sensitive
+ # to the contents, detect the case in this module and suppress it
+ # explicitly.
+ set(FPHSA_NAME_MISMATCHED 1)
+ endif ()
+ find_package_handle_standard_args(X11
+ REQUIRED_VARS X11_X11_INCLUDE_PATH X11_X11_LIB
+ HANDLE_COMPONENTS)
+ unset(FPHSA_NAME_MISMATCHED)
+
+ if(X11_FOUND)
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckFunctionExists.cmake)
+ include(${CMAKE_CURRENT_LIST_DIR}/CheckLibraryExists.cmake)
+
+ # Translated from an autoconf-generated configure script.
+ # See libs.m4 in autoconf's m4 directory.
+ if($ENV{ISC} MATCHES "^yes$")
+ set(X11_X_EXTRA_LIBS -lnsl_s -linet)
+ else()
+ set(X11_X_EXTRA_LIBS "")
+
+ # See if XOpenDisplay in X11 works by itself.
+ check_library_exists("${X11_LIBRARIES}" "XOpenDisplay" "${X11_LIBRARY_DIR}" X11_LIB_X11_SOLO)
+ if(NOT X11_LIB_X11_SOLO)
+ # Find library needed for dnet_ntoa.
+ check_library_exists("dnet" "dnet_ntoa" "" X11_LIB_DNET_HAS_DNET_NTOA)
+ if (X11_LIB_DNET_HAS_DNET_NTOA)
+ list(APPEND X11_X_EXTRA_LIBS -ldnet)
+ else ()
+ check_library_exists("dnet_stub" "dnet_ntoa" "" X11_LIB_DNET_STUB_HAS_DNET_NTOA)
+ if (X11_LIB_DNET_STUB_HAS_DNET_NTOA)
+ list(APPEND X11_X_EXTRA_LIBS -ldnet_stub)
+ endif ()
+ endif ()
+ endif()
+
+ # Find library needed for gethostbyname.
+ check_function_exists("gethostbyname" CMAKE_HAVE_GETHOSTBYNAME)
+ if(NOT CMAKE_HAVE_GETHOSTBYNAME)
+ check_library_exists("nsl" "gethostbyname" "" CMAKE_LIB_NSL_HAS_GETHOSTBYNAME)
+ if (CMAKE_LIB_NSL_HAS_GETHOSTBYNAME)
+ list(APPEND X11_X_EXTRA_LIBS -lnsl)
+ else ()
+ check_library_exists("bsd" "gethostbyname" "" CMAKE_LIB_BSD_HAS_GETHOSTBYNAME)
+ if (CMAKE_LIB_BSD_HAS_GETHOSTBYNAME)
+ list(APPEND X11_X_EXTRA_LIBS -lbsd)
+ endif ()
+ endif ()
+ endif()
+
+ # Find library needed for connect.
+ check_function_exists("connect" CMAKE_HAVE_CONNECT)
+ if(NOT CMAKE_HAVE_CONNECT)
+ check_library_exists("socket" "connect" "" CMAKE_LIB_SOCKET_HAS_CONNECT)
+ if (CMAKE_LIB_SOCKET_HAS_CONNECT)
+ list(INSERT X11_X_EXTRA_LIBS 0 -lsocket)
+ endif ()
+ endif()
+
+ # Find library needed for remove.
+ check_function_exists("remove" CMAKE_HAVE_REMOVE)
+ if(NOT CMAKE_HAVE_REMOVE)
+ check_library_exists("posix" "remove" "" CMAKE_LIB_POSIX_HAS_REMOVE)
+ if (CMAKE_LIB_POSIX_HAS_REMOVE)
+ list(APPEND X11_X_EXTRA_LIBS -lposix)
+ endif ()
+ endif()
+
+ # Find library needed for shmat.
+ check_function_exists("shmat" CMAKE_HAVE_SHMAT)
+ if(NOT CMAKE_HAVE_SHMAT)
+ check_library_exists("ipc" "shmat" "" CMAKE_LIB_IPS_HAS_SHMAT)
+ if (CMAKE_LIB_IPS_HAS_SHMAT)
+ list(APPEND X11_X_EXTRA_LIBS -lipc)
+ endif ()
+ endif()
+ endif()
+
+ if (X11_ICE_FOUND)
+ check_library_exists("ICE" "IceConnectionNumber" "${X11_LIBRARY_DIR}"
+ CMAKE_LIB_ICE_HAS_ICECONNECTIONNUMBER)
+ if(CMAKE_LIB_ICE_HAS_ICECONNECTIONNUMBER)
+ set (X11_X_PRE_LIBS ${X11_ICE_LIB})
+ if(X11_SM_LIB)
+ list(INSERT X11_X_PRE_LIBS 0 ${X11_SM_LIB})
+ endif()
+ endif()
+ endif ()
+
+ # Build the final list of libraries.
+ set(X11_LIBRARIES ${X11_X_PRE_LIBS} ${X11_LIBRARIES} ${X11_X_EXTRA_LIBS})
+
+ if (NOT TARGET X11::X11)
+ add_library(X11::X11 UNKNOWN IMPORTED)
+ set_target_properties(X11::X11 PROPERTIES
+ IMPORTED_LOCATION "${X11_X11_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_X11_INCLUDE_PATH}")
+ endif ()
+ endif ()
+
+ if (X11_ICE_FOUND AND NOT TARGET X11::ICE)
+ add_library(X11::ICE UNKNOWN IMPORTED)
+ set_target_properties(X11::ICE PROPERTIES
+ IMPORTED_LOCATION "${X11_ICE_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_ICE_INCLUDE_PATH}")
+ endif ()
+
+ if (X11_SM_FOUND AND NOT TARGET X11::SM)
+ add_library(X11::SM UNKNOWN IMPORTED)
+ set_target_properties(X11::SM PROPERTIES
+ IMPORTED_LOCATION "${X11_SM_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_SM_INCLUDE_PATH}")
+ endif ()
+
+ if (X11_Xau_FOUND AND NOT TARGET X11::Xau)
+ add_library(X11::Xau UNKNOWN IMPORTED)
+ set_target_properties(X11::Xau PROPERTIES
+ IMPORTED_LOCATION "${X11_Xau_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xau_INCLUDE_PATH}")
+ endif ()
+
+ if (X11_Xaw_FOUND AND NOT TARGET X11::Xaw)
+ add_library(X11::Xaw UNKNOWN IMPORTED)
+ set_target_properties(X11::Xaw PROPERTIES
+ IMPORTED_LOCATION "${X11_Xaw_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xaw_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::Xext;X11::Xmu;X11::Xt;X11::Xpm;X11::X11")
+ endif ()
+
+ if (X11_xcb_FOUND AND NOT TARGET X11::xcb)
+ add_library(X11::xcb UNKNOWN IMPORTED)
+ set_target_properties(X11::xcb PROPERTIES
+ IMPORTED_LOCATION "${X11_xcb_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_xcb_INCLUDE_PATH}")
+ endif ()
+
+ if (X11_X11_xcb_FOUND AND NOT TARGET X11::X11_xcb)
+ add_library(X11::X11_xcb UNKNOWN IMPORTED)
+ set_target_properties(X11::X11_xcb PROPERTIES
+ IMPORTED_LOCATION "${X11_X11_xcb_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_X11_xcb_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::xcb;X11::X11")
+ endif ()
+
+ if (X11_xcb_icccm_FOUND AND NOT TARGET X11::xcb_icccm)
+ add_library(X11::xcb_icccm UNKNOWN IMPORTED)
+ set_target_properties(X11::xcb_icccm PROPERTIES
+ IMPORTED_LOCATION "${X11_xcb_icccm_LIB}"
+ INTERFACE_LINK_LIBRARIES "X11::xcb")
+ endif ()
+
+ if (X11_xcb_util_FOUND AND NOT TARGET X11::xcb_util)
+ add_library(X11::xcb_util UNKNOWN IMPORTED)
+ set_target_properties(X11::xcb_util PROPERTIES
+ IMPORTED_LOCATION "${X11_xcb_util_LIB}"
+ INTERFACE_LINK_LIBRARIES "X11::xcb")
+ endif ()
+
+ if (X11_xcb_xfixes_FOUND AND NOT TARGET X11::xcb_xfixes)
+ add_library(X11::xcb_xfixes UNKNOWN IMPORTED)
+ set_target_properties(X11::xcb_xfixes PROPERTIES
+ IMPORTED_LOCATION "${X11_xcb_xfixes_LIB}"
+ INTERFACE_LINK_LIBRARIES "X11::xcb")
+ endif ()
+
+ if (X11_xcb_xkb_FOUND AND NOT TARGET X11::xcb_xkb)
+ add_library(X11::xcb_xkb UNKNOWN IMPORTED)
+ set_target_properties(X11::xcb_xkb PROPERTIES
+ IMPORTED_LOCATION "${X11_xcb_xkb_LIB}"
+ INTERFACE_LINK_LIBRARIES "X11::xcb")
+ endif ()
+
+ if (X11_Xcomposite_FOUND AND NOT TARGET X11::Xcomposite)
+ add_library(X11::Xcomposite UNKNOWN IMPORTED)
+ set_target_properties(X11::Xcomposite PROPERTIES
+ IMPORTED_LOCATION "${X11_Xcomposite_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xcomposite_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::X11")
+ endif ()
+
+ if (X11_Xcursor_FOUND AND NOT TARGET X11::Xcursor)
+ add_library(X11::Xcursor UNKNOWN IMPORTED)
+ set_target_properties(X11::Xcursor PROPERTIES
+ IMPORTED_LOCATION "${X11_Xcursor_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xcursor_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::Xrender;X11::Xfixes;X11::X11")
+ endif ()
+
+ if (X11_Xdamage_FOUND AND NOT TARGET X11::Xdamage)
+ add_library(X11::Xdamage UNKNOWN IMPORTED)
+ set_target_properties(X11::Xdamage PROPERTIES
+ IMPORTED_LOCATION "${X11_Xdamage_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xdamage_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::Xfixes;X11::X11")
+ endif ()
+
+ if (X11_Xdmcp_FOUND AND NOT TARGET X11::Xdmcp)
+ add_library(X11::Xdmcp UNKNOWN IMPORTED)
+ set_target_properties(X11::Xdmcp PROPERTIES
+ IMPORTED_LOCATION "${X11_Xdmcp_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xdmcp_INCLUDE_PATH}")
+ endif ()
+
+ if (X11_Xext_FOUND AND NOT TARGET X11::Xext)
+ add_library(X11::Xext UNKNOWN IMPORTED)
+ set_target_properties(X11::Xext PROPERTIES
+ IMPORTED_LOCATION "${X11_Xext_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xext_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::X11")
+ endif ()
+
+ if (X11_Xxf86misc_FOUND AND NOT TARGET X11::Xxf86misc)
+ add_library(X11::Xxf86misc UNKNOWN IMPORTED)
+ set_target_properties(X11::Xxf86misc PROPERTIES
+ IMPORTED_LOCATION "${X11_Xxf86misc_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xxf86misc_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::X11;X11::Xext")
+ endif ()
+
+ if (X11_Xxf86vm_FOUND AND NOT TARGET X11::Xxf86vm)
+ add_library(X11::Xxf86vm UNKNOWN IMPORTED)
+ set_target_properties(X11::Xxf86vm PROPERTIES
+ IMPORTED_LOCATION "${X11_Xxf86vm_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xxf86vm_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::X11;X11::Xext")
+ endif ()
+
+ if (X11_Xfixes_FOUND AND NOT TARGET X11::Xfixes)
+ add_library(X11::Xfixes UNKNOWN IMPORTED)
+ set_target_properties(X11::Xfixes PROPERTIES
+ IMPORTED_LOCATION "${X11_Xfixes_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xfixes_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::X11")
+ endif ()
+
+ if (X11_Xft_FOUND AND NOT TARGET X11::Xft)
+ add_library(X11::Xft UNKNOWN IMPORTED)
+ set_target_properties(X11::Xft PROPERTIES
+ IMPORTED_LOCATION "${X11_Xft_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xft_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::Xrender;X11::X11;Fontconfig::Fontconfig;Freetype::Freetype")
+ endif ()
+
+ if (X11_Xi_FOUND AND NOT TARGET X11::Xi)
+ add_library(X11::Xi UNKNOWN IMPORTED)
+ set_target_properties(X11::Xi PROPERTIES
+ IMPORTED_LOCATION "${X11_Xi_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xi_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::Xext;X11::X11")
+ endif ()
+
+ if (X11_Xinerama_FOUND AND NOT TARGET X11::Xinerama)
+ add_library(X11::Xinerama UNKNOWN IMPORTED)
+ set_target_properties(X11::Xinerama PROPERTIES
+ IMPORTED_LOCATION "${X11_Xinerama_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xinerama_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::Xext;X11::X11")
+ endif ()
+
+ if (X11_Xkb_FOUND AND NOT TARGET X11::Xkb)
+ add_library(X11::Xkb INTERFACE IMPORTED)
+ set_target_properties(X11::Xkb PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xkb_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::X11")
+ endif ()
+
+ if (X11_xkbcommon_FOUND AND NOT TARGET X11::xkbcommon)
+ add_library(X11::xkbcommon UNKNOWN IMPORTED)
+ set_target_properties(X11::xkbcommon PROPERTIES
+ IMPORTED_LOCATION "${X11_xkbcommon_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_xkbcommon_INCLUDE_PATH}")
+ endif ()
+
+ if (X11_xkbcommon_X11_FOUND AND NOT TARGET X11::xkbcommon_X11)
+ add_library(X11::xkbcommon_X11 UNKNOWN IMPORTED)
+ set_target_properties(X11::xkbcommon_X11 PROPERTIES
+ IMPORTED_LOCATION "${X11_xkbcommon_X11_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_xkbcommon_X11_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::X11;X11::xkbcommon")
+ endif ()
+
+ if (X11_xkbfile_FOUND AND NOT TARGET X11::xkbfile)
+ add_library(X11::xkbfile UNKNOWN IMPORTED)
+ set_target_properties(X11::xkbfile PROPERTIES
+ IMPORTED_LOCATION "${X11_xkbfile_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_xkbfile_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::X11")
+ endif ()
+
+ if (X11_Xmu_FOUND AND NOT TARGET X11::Xmu)
+ add_library(X11::Xmu UNKNOWN IMPORTED)
+ set_target_properties(X11::Xmu PROPERTIES
+ IMPORTED_LOCATION "${X11_Xmu_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xmu_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::Xt;X11::Xext;X11::X11")
+ endif ()
+
+ if (X11_Xpm_FOUND AND NOT TARGET X11::Xpm)
+ add_library(X11::Xpm UNKNOWN IMPORTED)
+ set_target_properties(X11::Xpm PROPERTIES
+ IMPORTED_LOCATION "${X11_Xpm_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xpm_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::X11")
+ endif ()
+
+ if (X11_Xtst_FOUND AND NOT TARGET X11::Xtst)
+ add_library(X11::Xtst UNKNOWN IMPORTED)
+ set_target_properties(X11::Xtst PROPERTIES
+ IMPORTED_LOCATION "${X11_Xtst_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xtst_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::Xi;X11::Xext;X11::X11")
+ endif ()
+
+ if (X11_Xrandr_FOUND AND NOT TARGET X11::Xrandr)
+ add_library(X11::Xrandr UNKNOWN IMPORTED)
+ set_target_properties(X11::Xrandr PROPERTIES
+ IMPORTED_LOCATION "${X11_Xrandr_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xrandr_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::Xrender;X11::Xext;X11::X11")
+ endif ()
+
+ if (X11_Xrender_FOUND AND NOT TARGET X11::Xrender)
+ add_library(X11::Xrender UNKNOWN IMPORTED)
+ set_target_properties(X11::Xrender PROPERTIES
+ IMPORTED_LOCATION "${X11_Xrender_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xrender_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::X11")
+ endif ()
+
+ if (X11_XRes_FOUND AND NOT TARGET X11::XRes)
+ add_library(X11::XRes UNKNOWN IMPORTED)
+ set_target_properties(X11::XRes PROPERTIES
+ IMPORTED_LOCATION "${X11_XRes_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_XRes_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::Xext;X11::X11")
+ endif ()
+
+ if (X11_Xss_FOUND AND NOT TARGET X11::Xss)
+ add_library(X11::Xss UNKNOWN IMPORTED)
+ set_target_properties(X11::Xss PROPERTIES
+ IMPORTED_LOCATION "${X11_Xss_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xss_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::Xext;X11::X11")
+ endif ()
+
+ if (X11_Xt_FOUND AND NOT TARGET X11::Xt)
+ add_library(X11::Xt UNKNOWN IMPORTED)
+ set_target_properties(X11::Xt PROPERTIES
+ IMPORTED_LOCATION "${X11_Xt_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xt_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::ICE;X11::SM;X11::X11")
+ endif ()
+
+ if (X11_Xutil_FOUND AND NOT TARGET X11::Xutil)
+ add_library(X11::Xutil INTERFACE IMPORTED)
+ set_target_properties(X11::Xutil PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xutil_INCLUDE_PATH}"
+ # libX11 contains the implementations for functions in the Xutil.h
+ # header.
+ INTERFACE_LINK_LIBRARIES "X11::X11")
+ endif ()
+
+ if (X11_Xv_FOUND AND NOT TARGET X11::Xv)
+ add_library(X11::Xv UNKNOWN IMPORTED)
+ set_target_properties(X11::Xv PROPERTIES
+ IMPORTED_LOCATION "${X11_Xv_LIB}"
+ INTERFACE_INCLUDE_DIRECTORIES "${X11_Xv_INCLUDE_PATH}"
+ INTERFACE_LINK_LIBRARIES "X11::Xext;X11::X11")
+ endif ()
+
+ mark_as_advanced(
+ X11_X11_INCLUDE_PATH
+ X11_X11_LIB
+ X11_Xext_INCLUDE_PATH
+ X11_Xext_LIB
+ X11_Xau_LIB
+ X11_Xau_INCLUDE_PATH
+ X11_xcb_LIB
+ X11_xcb_INCLUDE_PATH
+ X11_xcb_xkb_LIB
+ X11_X11_xcb_LIB
+ X11_X11_xcb_INCLUDE_PATH
+ X11_Xlib_INCLUDE_PATH
+ X11_Xutil_INCLUDE_PATH
+ X11_Xcomposite_INCLUDE_PATH
+ X11_Xcomposite_LIB
+ X11_Xfixes_LIB
+ X11_Xfixes_INCLUDE_PATH
+ X11_Xrandr_LIB
+ X11_Xrandr_INCLUDE_PATH
+ X11_Xdamage_LIB
+ X11_Xdamage_INCLUDE_PATH
+ X11_Xrender_LIB
+ X11_Xrender_INCLUDE_PATH
+ X11_XRes_LIB
+ X11_XRes_INCLUDE_PATH
+ X11_Xxf86misc_LIB
+ X11_Xxf86misc_INCLUDE_PATH
+ X11_Xxf86vm_LIB
+ X11_Xxf86vm_INCLUDE_PATH
+ X11_Xi_LIB
+ X11_Xi_INCLUDE_PATH
+ X11_Xinerama_LIB
+ X11_Xinerama_INCLUDE_PATH
+ X11_Xtst_LIB
+ X11_Xtst_INCLUDE_PATH
+ X11_Xcursor_LIB
+ X11_Xcursor_INCLUDE_PATH
+ X11_dpms_INCLUDE_PATH
+ X11_Xt_LIB
+ X11_Xt_INCLUDE_PATH
+ X11_Xdmcp_LIB
+ X11_LIBRARIES
+ X11_Xaccessrules_INCLUDE_PATH
+ X11_Xaccessstr_INCLUDE_PATH
+ X11_Xdmcp_INCLUDE_PATH
+ X11_Xkb_INCLUDE_PATH
+ X11_Xkblib_INCLUDE_PATH
+ X11_xkbcommon_INCLUDE_PATH
+ X11_xkbcommon_LIB
+ X11_xkbcommon_X11_INCLUDE_PATH
+ X11_xkbcommon_X11_LIB
+ X11_xkbfile_INCLUDE_PATH
+ X11_xkbfile_LIB
+ X11_Xmu_INCLUDE_PATH
+ X11_Xmu_LIB
+ X11_Xss_INCLUDE_PATH
+ X11_Xss_LIB
+ X11_Xpm_INCLUDE_PATH
+ X11_Xpm_LIB
+ X11_Xft_LIB
+ X11_Xft_INCLUDE_PATH
+ X11_Xshape_INCLUDE_PATH
+ X11_Xv_LIB
+ X11_Xv_INCLUDE_PATH
+ X11_XShm_INCLUDE_PATH
+ X11_ICE_LIB
+ X11_ICE_INCLUDE_PATH
+ X11_SM_LIB
+ X11_SM_INCLUDE_PATH
+ X11_XSync_INCLUDE_PATH
+ X11_Xaw_LIB
+ X11_Xaw_INCLUDE_PATH
+ )
+ set(CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK_SAVE})
+ set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE})
+endif ()
diff --git a/Modules/FindXCTest.cmake b/Modules/FindXCTest.cmake
new file mode 100644
index 0000000..48371e6
--- /dev/null
+++ b/Modules/FindXCTest.cmake
@@ -0,0 +1,222 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindXCTest
+----------
+
+.. versionadded:: 3.3
+
+Functions to help creating and executing XCTest bundles.
+
+An XCTest bundle is a CFBundle with a special product-type
+and bundle extension. The Mac Developer Library provides more
+information in the `Testing with Xcode`_ document.
+
+.. _Testing with Xcode: http://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/testing_with_xcode/
+
+Module Functions
+^^^^^^^^^^^^^^^^
+
+.. command:: xctest_add_bundle
+
+ The ``xctest_add_bundle`` function creates a XCTest bundle named
+ <target> which will test the target <testee>. Supported target types
+ for testee are Frameworks and App Bundles::
+
+ xctest_add_bundle(
+ <target> # Name of the XCTest bundle
+ <testee> # Target name of the testee
+ )
+
+.. command:: xctest_add_test
+
+ The ``xctest_add_test`` function adds an XCTest bundle to the
+ project to be run by :manual:`ctest(1)`. The test will be named
+ <name> and tests <bundle>::
+
+ xctest_add_test(
+ <name> # Test name
+ <bundle> # Target name of XCTest bundle
+ )
+
+Module Variables
+^^^^^^^^^^^^^^^^
+
+The following variables are set by including this module:
+
+.. variable:: XCTest_FOUND
+
+ True if the XCTest Framework and executable were found.
+
+.. variable:: XCTest_EXECUTABLE
+
+ The path to the xctest command line tool used to execute XCTest bundles.
+
+.. variable:: XCTest_INCLUDE_DIRS
+
+ The directory containing the XCTest Framework headers.
+
+.. variable:: XCTest_LIBRARIES
+
+ The location of the XCTest Framework.
+
+#]=======================================================================]
+
+set(_PRESERVED_CMAKE_FIND_ROOT_PATH "${CMAKE_FIND_ROOT_PATH}")
+
+if(CMAKE_EFFECTIVE_SYSTEM_NAME STREQUAL "Apple"
+ AND NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ # Non-macos systems set the CMAKE_FIND_ROOT_PATH_MODE to "ONLY" which
+ # restricts the search paths too much to find XCTest.framework. In
+ # contrast to the regular system frameworks which reside within the
+ # SDK direectory the XCTest framework is located in the respective
+ # platform directory which is not added to the CMAKE_FIND_ROOT_PATH
+ # (only to CMAKE_SYSTEM_FRAMEWORK_PATH) and therefore not searched.
+ #
+ # Until this is properly addressed, temporaily add the platform
+ # directory to CMAKE_FIND_ROOT_PATH.
+ list(APPEND CMAKE_FIND_ROOT_PATH "${_CMAKE_OSX_SYSROOT_PATH}/../..")
+endif()
+
+find_path(XCTest_INCLUDE_DIR
+ NAMES "XCTest/XCTest.h"
+ DOC "XCTest include directory")
+mark_as_advanced(XCTest_INCLUDE_DIR)
+
+find_library(XCTest_LIBRARY
+ NAMES XCTest
+ DOC "XCTest Framework library")
+mark_as_advanced(XCTest_LIBRARY)
+
+set(CMAKE_FIND_ROOT_PATH "${_PRESERVED_CMAKE_FIND_ROOT_PATH}")
+unset(_PRESERVED_CMAKE_FIND_ROOT_PATH)
+
+execute_process(
+ COMMAND xcrun --find xctest
+ OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE _xcrun_err)
+if(_xcrun_out)
+ set(XCTest_EXECUTABLE "${_xcrun_out}" CACHE FILEPATH "XCTest executable")
+ mark_as_advanced(XCTest_EXECUTABLE)
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(XCTest
+ FOUND_VAR XCTest_FOUND
+ REQUIRED_VARS XCTest_LIBRARY XCTest_INCLUDE_DIR XCTest_EXECUTABLE)
+
+if(XCTest_FOUND)
+ set(XCTest_INCLUDE_DIRS "${XCTest_INCLUDE_DIR}")
+ set(XCTest_LIBRARIES "${XCTest_LIBRARY}")
+endif(XCTest_FOUND)
+
+
+function(xctest_add_bundle target testee)
+ if(NOT XCTest_FOUND)
+ message(FATAL_ERROR "XCTest is required to create a XCTest Bundle.")
+ endif(NOT XCTest_FOUND)
+
+ if(NOT CMAKE_OSX_SYSROOT)
+ message(FATAL_ERROR "Adding XCTest bundles requires CMAKE_OSX_SYSROOT to be set.")
+ endif()
+
+ add_library(${target} MODULE ${ARGN})
+
+ set_target_properties(${target} PROPERTIES
+ BUNDLE TRUE
+ XCTEST TRUE
+ XCTEST_TESTEE ${testee})
+
+ target_link_libraries(${target} PRIVATE "-framework Foundation")
+ target_link_libraries(${target} PRIVATE ${XCTest_LIBRARIES})
+ target_include_directories(${target} PRIVATE ${XCTest_INCLUDE_DIRS})
+
+ # retrieve testee target type
+ if(NOT TARGET ${testee})
+ message(FATAL_ERROR "${testee} is not a target.")
+ endif()
+ get_property(_testee_type TARGET ${testee} PROPERTY TYPE)
+ get_property(_testee_framework TARGET ${testee} PROPERTY FRAMEWORK)
+ get_property(_testee_macosx_bundle TARGET ${testee} PROPERTY MACOSX_BUNDLE)
+
+ if(_testee_type STREQUAL "SHARED_LIBRARY" AND _testee_framework)
+ # testee is a Framework
+ target_link_libraries(${target} PRIVATE ${testee})
+
+ elseif(_testee_type STREQUAL "STATIC_LIBRARY")
+ # testee is a static library
+ target_link_libraries(${target} PRIVATE ${testee})
+
+ elseif(_testee_type STREQUAL "EXECUTABLE" AND _testee_macosx_bundle)
+ # testee is an App Bundle
+ add_dependencies(${target} ${testee})
+ if(XCODE)
+ set_target_properties(${target} PROPERTIES
+ XCODE_ATTRIBUTE_BUNDLE_LOADER "$(TEST_HOST)"
+ XCODE_ATTRIBUTE_TEST_HOST "$<TARGET_FILE:${testee}>")
+ if(XCODE_VERSION VERSION_GREATER_EQUAL 7.3)
+ # CMAKE_XCODE_BUILD_SYSTEM equals 12 means that at least Xcode 11.x is used.
+ if(CMAKE_XCODE_BUILD_SYSTEM EQUAL 12 AND
+ NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ set(_output_directory "$<TARGET_BUNDLE_CONTENT_DIR:${testee}>")
+ else()
+ set(_output_directory "$<TARGET_BUNDLE_CONTENT_DIR:${testee}>/PlugIns")
+ endif()
+ set_target_properties(${target} PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${_output_directory}")
+ endif()
+ else(XCODE)
+ target_link_libraries(${target}
+ PRIVATE -bundle_loader $<TARGET_FILE:${testee}>)
+ endif(XCODE)
+
+ else()
+ message(FATAL_ERROR "Testee ${testee} is of unsupported type.")
+ endif()
+endfunction(xctest_add_bundle)
+
+
+function(xctest_add_test name bundle)
+ if(NOT XCTest_EXECUTABLE)
+ message(FATAL_ERROR "XCTest executable is required to register a test.")
+ endif()
+
+ # check that bundle is a XCTest Bundle
+
+ if(NOT TARGET ${bundle})
+ message(FATAL_ERROR "${bundle} is not a target.")
+ endif(NOT TARGET ${bundle})
+
+ get_property(_test_type TARGET ${bundle} PROPERTY TYPE)
+ get_property(_test_bundle TARGET ${bundle} PROPERTY BUNDLE)
+ get_property(_test_xctest TARGET ${bundle} PROPERTY XCTEST)
+
+ if(NOT _test_type STREQUAL "MODULE_LIBRARY"
+ OR NOT _test_xctest OR NOT _test_bundle)
+ message(FATAL_ERROR "Test ${bundle} is not an XCTest Bundle")
+ endif()
+
+ # get and check testee properties
+
+ get_property(_testee TARGET ${bundle} PROPERTY XCTEST_TESTEE)
+ if(NOT TARGET ${_testee})
+ message(FATAL_ERROR "${_testee} is not a target.")
+ endif()
+
+ get_property(_testee_type TARGET ${_testee} PROPERTY TYPE)
+ get_property(_testee_framework TARGET ${_testee} PROPERTY FRAMEWORK)
+
+ # register test
+
+ add_test(
+ NAME ${name}
+ COMMAND ${XCTest_EXECUTABLE} $<TARGET_BUNDLE_DIR:${bundle}>)
+
+ # point loader to testee in case rpath is disabled
+
+ if(_testee_type STREQUAL "SHARED_LIBRARY" AND _testee_framework)
+ set_property(TEST ${name} APPEND PROPERTY
+ ENVIRONMENT DYLD_FRAMEWORK_PATH=$<TARGET_LINKER_FILE_DIR:${_testee}>/..)
+ endif()
+endfunction(xctest_add_test)
diff --git a/Modules/FindXMLRPC.cmake b/Modules/FindXMLRPC.cmake
new file mode 100644
index 0000000..69e6df2
--- /dev/null
+++ b/Modules/FindXMLRPC.cmake
@@ -0,0 +1,129 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindXMLRPC
+----------
+
+Find xmlrpc
+
+Find the native XMLRPC headers and libraries.
+
+::
+
+ XMLRPC_INCLUDE_DIRS - where to find xmlrpc.h, etc.
+ XMLRPC_LIBRARIES - List of libraries when using xmlrpc.
+ XMLRPC_FOUND - True if xmlrpc found.
+
+XMLRPC modules may be specified as components for this find module.
+Modules may be listed by running "xmlrpc-c-config". Modules include:
+
+::
+
+ c++ C++ wrapper code
+ libwww-client libwww-based client
+ cgi-server CGI-based server
+ abyss-server ABYSS-based server
+
+Typical usage:
+
+::
+
+ find_package(XMLRPC REQUIRED libwww-client)
+#]=======================================================================]
+
+# First find the config script from which to obtain other values.
+find_program(XMLRPC_C_CONFIG NAMES xmlrpc-c-config)
+
+# Check whether we found anything.
+if(XMLRPC_C_CONFIG)
+ set(XMLRPC_C_FOUND 1)
+else()
+ set(XMLRPC_C_FOUND 0)
+endif()
+
+# Lookup the include directories needed for the components requested.
+if(XMLRPC_C_FOUND)
+ execute_process(
+ COMMAND ${XMLRPC_C_CONFIG} ${XMLRPC_FIND_COMPONENTS} --cflags
+ OUTPUT_VARIABLE XMLRPC_C_CONFIG_CFLAGS
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ RESULT_VARIABLE XMLRPC_C_CONFIG_RESULT
+ )
+
+ # Parse the include flags.
+ if("${XMLRPC_C_CONFIG_RESULT}" STREQUAL "0")
+ # Convert the compile flags to a CMake list.
+ string(REGEX REPLACE " +" ";"
+ XMLRPC_C_CONFIG_CFLAGS "${XMLRPC_C_CONFIG_CFLAGS}")
+
+ # Look for -I options.
+ # FIXME: Use these as hints to a find_path call to find the headers.
+ set(XMLRPC_INCLUDE_DIRS)
+ foreach(flag ${XMLRPC_C_CONFIG_CFLAGS})
+ if("${flag}" MATCHES "^-I(.+)")
+ file(TO_CMAKE_PATH "${CMAKE_MATCH_1}" DIR)
+ list(APPEND XMLRPC_INCLUDE_DIRS "${DIR}")
+ endif()
+ endforeach()
+ else()
+ message("Error running ${XMLRPC_C_CONFIG}: [${XMLRPC_C_CONFIG_RESULT}]")
+ set(XMLRPC_C_FOUND 0)
+ endif()
+endif()
+
+# Lookup the libraries needed for the components requested.
+if(XMLRPC_C_FOUND)
+ execute_process(
+ COMMAND ${XMLRPC_C_CONFIG} ${XMLRPC_FIND_COMPONENTS} --libs
+ OUTPUT_VARIABLE XMLRPC_C_CONFIG_LIBS
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ RESULT_VARIABLE XMLRPC_C_CONFIG_RESULT
+ )
+
+ # Parse the library names and directories.
+ if("${XMLRPC_C_CONFIG_RESULT}" STREQUAL "0")
+ string(REGEX REPLACE " +" ";"
+ XMLRPC_C_CONFIG_LIBS "${XMLRPC_C_CONFIG_LIBS}")
+
+ # Look for -L flags for directories and -l flags for library names.
+ set(XMLRPC_LIBRARY_DIRS)
+ set(XMLRPC_LIBRARY_NAMES)
+ foreach(flag ${XMLRPC_C_CONFIG_LIBS})
+ if("${flag}" MATCHES "^-L(.+)")
+ file(TO_CMAKE_PATH "${CMAKE_MATCH_1}" DIR)
+ list(APPEND XMLRPC_LIBRARY_DIRS "${DIR}")
+ elseif("${flag}" MATCHES "^-l(.+)")
+ list(APPEND XMLRPC_LIBRARY_NAMES "${CMAKE_MATCH_1}")
+ endif()
+ endforeach()
+
+ # Search for each library needed using the directories given.
+ foreach(name ${XMLRPC_LIBRARY_NAMES})
+ # Look for this library.
+ find_library(XMLRPC_${name}_LIBRARY
+ NAMES ${name}
+ HINTS ${XMLRPC_LIBRARY_DIRS}
+ )
+ mark_as_advanced(XMLRPC_${name}_LIBRARY)
+
+ # If any library is not found then the whole package is not found.
+ if(NOT XMLRPC_${name}_LIBRARY)
+ set(XMLRPC_C_FOUND 0)
+ endif()
+
+ # Build an ordered list of all the libraries needed.
+ set(XMLRPC_LIBRARIES ${XMLRPC_LIBRARIES} "${XMLRPC_${name}_LIBRARY}")
+ endforeach()
+ else()
+ message("Error running ${XMLRPC_C_CONFIG}: [${XMLRPC_C_CONFIG_RESULT}]")
+ set(XMLRPC_C_FOUND 0)
+ endif()
+endif()
+
+# Report the results.
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(
+ XMLRPC
+ REQUIRED_VARS XMLRPC_C_FOUND XMLRPC_LIBRARIES
+ FAIL_MESSAGE "XMLRPC was not found. Make sure the entries XMLRPC_* are set.")
diff --git a/Modules/FindXalanC.cmake b/Modules/FindXalanC.cmake
new file mode 100644
index 0000000..a7fb766
--- /dev/null
+++ b/Modules/FindXalanC.cmake
@@ -0,0 +1,155 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindXalanC
+-----------
+
+.. versionadded:: 3.5
+
+Find the Apache Xalan-C++ XSL transform processor headers and libraries.
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+This module defines the following :prop_tgt:`IMPORTED` targets:
+
+``XalanC::XalanC``
+ The Xalan-C++ ``xalan-c`` library, if found.
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``XalanC_FOUND``
+ true if the Xalan headers and libraries were found
+``XalanC_VERSION``
+ Xalan release version
+``XalanC_INCLUDE_DIRS``
+ the directory containing the Xalan headers; note
+ ``XercesC_INCLUDE_DIRS`` is also required
+``XalanC_LIBRARIES``
+ Xalan libraries to be linked; note ``XercesC_LIBRARIES`` is also
+ required
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``XalanC_INCLUDE_DIR``
+ the directory containing the Xalan headers
+``XalanC_LIBRARY``
+ the Xalan library
+#]=======================================================================]
+
+# Written by Roger Leigh <rleigh@codelibre.net>
+
+function(_XalanC_GET_VERSION version_hdr)
+ file(STRINGS ${version_hdr} _contents REGEX "^[ \t]*#define XALAN_VERSION_.*")
+ if(_contents)
+ string(REGEX REPLACE "[^*]*#define XALAN_VERSION_MAJOR[ \t(]+([0-9]+).*" "\\1" XalanC_MAJOR "${_contents}")
+ string(REGEX REPLACE "[^*]*#define XALAN_VERSION_MINOR[ \t(]+([0-9]+).*" "\\1" XalanC_MINOR "${_contents}")
+ string(REGEX REPLACE "[^*]*#define XALAN_VERSION_REVISION[ \t(]+([0-9]+).*" "\\1" XalanC_PATCH "${_contents}")
+
+ if(NOT XalanC_MAJOR MATCHES "^[0-9]+$")
+ message(FATAL_ERROR "Version parsing failed for XALAN_VERSION_MAJOR!")
+ endif()
+ if(NOT XalanC_MINOR MATCHES "^[0-9]+$")
+ message(FATAL_ERROR "Version parsing failed for XALAN_VERSION_MINOR!")
+ endif()
+ if(NOT XalanC_PATCH MATCHES "^[0-9]+$")
+ message(FATAL_ERROR "Version parsing failed for XALAN_VERSION_REVISION!")
+ endif()
+
+ set(XalanC_VERSION "${XalanC_MAJOR}.${XalanC_MINOR}.${XalanC_PATCH}" PARENT_SCOPE)
+ set(XalanC_VERSION_MAJOR "${XalanC_MAJOR}" PARENT_SCOPE)
+ set(XalanC_VERSION_MINOR "${XalanC_MINOR}" PARENT_SCOPE)
+ set(XalanC_VERSION_PATCH "${XalanC_PATCH}" PARENT_SCOPE)
+ else()
+ message(FATAL_ERROR "Include file ${version_hdr} does not exist or does not contain expected version information")
+ endif()
+endfunction()
+
+# Find include directory
+find_path(XalanC_INCLUDE_DIR
+ NAMES "xalanc/XalanTransformer/XalanTransformer.hpp"
+ DOC "Xalan-C++ include directory")
+mark_as_advanced(XalanC_INCLUDE_DIR)
+
+if(XalanC_INCLUDE_DIR AND EXISTS "${XalanC_INCLUDE_DIR}/xalanc/Include/XalanVersion.hpp")
+ _XalanC_GET_VERSION("${XalanC_INCLUDE_DIR}/xalanc/Include/XalanVersion.hpp")
+endif()
+
+if(NOT XalanC_LIBRARY)
+ # Find all XalanC libraries
+ find_library(XalanC_LIBRARY_RELEASE
+ NAMES "Xalan-C" "xalan-c"
+ "Xalan-C_${XalanC_VERSION_MAJOR}"
+ "Xalan-C_${XalanC_VERSION_MAJOR}_${XalanC_VERSION_MINOR}"
+ DOC "Xalan-C++ libraries (release)")
+ find_library(XalanC_LIBRARY_DEBUG
+ NAMES "Xalan-CD" "xalan-cd"
+ "Xalan-C_${XalanC_VERSION_MAJOR}D"
+ "Xalan-C_${XalanC_VERSION_MAJOR}_${XalanC_VERSION_MINOR}D"
+ DOC "Xalan-C++ libraries (debug)")
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(XalanC)
+ mark_as_advanced(XalanC_LIBRARY_RELEASE XalanC_LIBRARY_DEBUG)
+endif()
+
+unset(XalanC_VERSION_MAJOR)
+unset(XalanC_VERSION_MINOR)
+unset(XalanC_VERSION_PATCH)
+
+unset(XalanC_XERCESC_REQUIRED)
+if(XalanC_FIND_REQUIRED)
+ set(XalanC_XERCESC_REQUIRED REQUIRED)
+endif()
+find_package(XercesC ${XalanC_XERCESC_REQUIRED})
+unset(XalanC_XERCESC_REQUIRED)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(XalanC
+ FOUND_VAR XalanC_FOUND
+ REQUIRED_VARS XalanC_LIBRARY
+ XalanC_INCLUDE_DIR
+ XalanC_VERSION
+ XercesC_FOUND
+ VERSION_VAR XalanC_VERSION
+ FAIL_MESSAGE "Failed to find XalanC")
+
+if(XalanC_FOUND)
+ set(XalanC_INCLUDE_DIRS "${XalanC_INCLUDE_DIR}" ${XercesC_INCLUDE_DIRS})
+ set(XalanC_LIBRARIES "${XalanC_LIBRARY}" ${XercesC_LIBRARIES})
+
+ # For header-only libraries
+ if(NOT TARGET XalanC::XalanC)
+ add_library(XalanC::XalanC UNKNOWN IMPORTED)
+ if(XalanC_INCLUDE_DIRS)
+ set_target_properties(XalanC::XalanC PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${XalanC_INCLUDE_DIRS}")
+ endif()
+ if(EXISTS "${XalanC_LIBRARY}")
+ set_target_properties(XalanC::XalanC PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
+ IMPORTED_LOCATION "${XalanC_LIBRARY}")
+ endif()
+ if(EXISTS "${XalanC_LIBRARY_RELEASE}")
+ set_property(TARGET XalanC::XalanC APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(XalanC::XalanC PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
+ IMPORTED_LOCATION_RELEASE "${XalanC_LIBRARY_RELEASE}")
+ endif()
+ if(EXISTS "${XalanC_LIBRARY_DEBUG}")
+ set_property(TARGET XalanC::XalanC APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(XalanC::XalanC PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
+ IMPORTED_LOCATION_DEBUG "${XalanC_LIBRARY_DEBUG}")
+ endif()
+ set_target_properties(XalanC::XalanC PROPERTIES INTERFACE_LINK_LIBRARIES XercesC::XercesC)
+ endif()
+endif()
diff --git a/Modules/FindXercesC.cmake b/Modules/FindXercesC.cmake
new file mode 100644
index 0000000..af1b0b4
--- /dev/null
+++ b/Modules/FindXercesC.cmake
@@ -0,0 +1,149 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindXercesC
+-----------
+
+.. versionadded:: 3.1
+
+Find the Apache Xerces-C++ validating XML parser headers and libraries.
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.5
+
+This module defines the following :prop_tgt:`IMPORTED` targets:
+
+``XercesC::XercesC``
+ The Xerces-C++ ``xerces-c`` library, if found.
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables in your project:
+
+``XercesC_FOUND``
+ true if the Xerces headers and libraries were found
+``XercesC_VERSION``
+ Xerces release version
+``XercesC_INCLUDE_DIRS``
+ the directory containing the Xerces headers
+``XercesC_LIBRARIES``
+ Xerces libraries to be linked
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
+
+``XercesC_INCLUDE_DIR``
+ the directory containing the Xerces headers
+``XercesC_LIBRARY``
+ the Xerces library
+
+.. versionadded:: 3.4
+ Debug and Release variants are found separately.
+#]=======================================================================]
+
+# Written by Roger Leigh <rleigh@codelibre.net>
+
+function(_XercesC_GET_VERSION version_hdr)
+ file(STRINGS ${version_hdr} _contents REGEX "^[ \t]*#define XERCES_VERSION_.*")
+ if(_contents)
+ string(REGEX REPLACE ".*#define XERCES_VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" XercesC_MAJOR "${_contents}")
+ string(REGEX REPLACE ".*#define XERCES_VERSION_MINOR[ \t]+([0-9]+).*" "\\1" XercesC_MINOR "${_contents}")
+ string(REGEX REPLACE ".*#define XERCES_VERSION_REVISION[ \t]+([0-9]+).*" "\\1" XercesC_PATCH "${_contents}")
+
+ if(NOT XercesC_MAJOR MATCHES "^[0-9]+$")
+ message(FATAL_ERROR "Version parsing failed for XERCES_VERSION_MAJOR!")
+ endif()
+ if(NOT XercesC_MINOR MATCHES "^[0-9]+$")
+ message(FATAL_ERROR "Version parsing failed for XERCES_VERSION_MINOR!")
+ endif()
+ if(NOT XercesC_PATCH MATCHES "^[0-9]+$")
+ message(FATAL_ERROR "Version parsing failed for XERCES_VERSION_REVISION!")
+ endif()
+
+ set(XercesC_VERSION "${XercesC_MAJOR}.${XercesC_MINOR}.${XercesC_PATCH}" PARENT_SCOPE)
+ set(XercesC_VERSION_MAJOR "${XercesC_MAJOR}" PARENT_SCOPE)
+ set(XercesC_VERSION_MINOR "${XercesC_MINOR}" PARENT_SCOPE)
+ set(XercesC_VERSION_PATCH "${XercesC_PATCH}" PARENT_SCOPE)
+ else()
+ message(FATAL_ERROR "Include file ${version_hdr} does not exist or does not contain expected version information")
+ endif()
+endfunction()
+
+# Find include directory
+find_path(XercesC_INCLUDE_DIR
+ NAMES "xercesc/util/PlatformUtils.hpp"
+ DOC "Xerces-C++ include directory")
+mark_as_advanced(XercesC_INCLUDE_DIR)
+
+if(XercesC_INCLUDE_DIR AND EXISTS "${XercesC_INCLUDE_DIR}/xercesc/util/XercesVersion.hpp")
+ _XercesC_GET_VERSION("${XercesC_INCLUDE_DIR}/xercesc/util/XercesVersion.hpp")
+endif()
+
+if(NOT XercesC_LIBRARY)
+ # Find all XercesC libraries
+ find_library(XercesC_LIBRARY_RELEASE
+ NAMES "xerces-c"
+ "xerces-c_${XercesC_VERSION_MAJOR}"
+ "xerces-c-${XercesC_VERSION_MAJOR}.${XercesC_VERSION_MINOR}"
+ DOC "Xerces-C++ libraries (release)")
+ find_library(XercesC_LIBRARY_DEBUG
+ NAMES "xerces-cd"
+ "xerces-c_${XercesC_VERSION_MAJOR}D"
+ "xerces-c_${XercesC_VERSION_MAJOR}_${XercesC_VERSION_MINOR}D"
+ DOC "Xerces-C++ libraries (debug)")
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(XercesC)
+ mark_as_advanced(XercesC_LIBRARY_RELEASE XercesC_LIBRARY_DEBUG)
+endif()
+
+unset(XercesC_VERSION_MAJOR)
+unset(XercesC_VERSION_MINOR)
+unset(XercesC_VERSION_PATCH)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(XercesC
+ FOUND_VAR XercesC_FOUND
+ REQUIRED_VARS XercesC_LIBRARY
+ XercesC_INCLUDE_DIR
+ XercesC_VERSION
+ VERSION_VAR XercesC_VERSION
+ FAIL_MESSAGE "Failed to find XercesC")
+
+if(XercesC_FOUND)
+ set(XercesC_INCLUDE_DIRS "${XercesC_INCLUDE_DIR}")
+ set(XercesC_LIBRARIES "${XercesC_LIBRARY}")
+
+ # For header-only libraries
+ if(NOT TARGET XercesC::XercesC)
+ add_library(XercesC::XercesC UNKNOWN IMPORTED)
+ if(XercesC_INCLUDE_DIRS)
+ set_target_properties(XercesC::XercesC PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${XercesC_INCLUDE_DIRS}")
+ endif()
+ if(EXISTS "${XercesC_LIBRARY}")
+ set_target_properties(XercesC::XercesC PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
+ IMPORTED_LOCATION "${XercesC_LIBRARY}")
+ endif()
+ if(EXISTS "${XercesC_LIBRARY_RELEASE}")
+ set_property(TARGET XercesC::XercesC APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(XercesC::XercesC PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
+ IMPORTED_LOCATION_RELEASE "${XercesC_LIBRARY_RELEASE}")
+ endif()
+ if(EXISTS "${XercesC_LIBRARY_DEBUG}")
+ set_property(TARGET XercesC::XercesC APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(XercesC::XercesC PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
+ IMPORTED_LOCATION_DEBUG "${XercesC_LIBRARY_DEBUG}")
+ endif()
+ endif()
+endif()
diff --git a/Modules/FindZLIB.cmake b/Modules/FindZLIB.cmake
new file mode 100644
index 0000000..5778b03
--- /dev/null
+++ b/Modules/FindZLIB.cmake
@@ -0,0 +1,154 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindZLIB
+--------
+
+Find the native ZLIB includes and library.
+
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.1
+
+This module defines :prop_tgt:`IMPORTED` target ``ZLIB::ZLIB``, if
+ZLIB has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+::
+
+ ZLIB_INCLUDE_DIRS - where to find zlib.h, etc.
+ ZLIB_LIBRARIES - List of libraries when using zlib.
+ ZLIB_FOUND - True if zlib found.
+
+::
+
+ ZLIB_VERSION_STRING - The version of zlib found (x.y.z)
+ ZLIB_VERSION_MAJOR - The major version of zlib
+ ZLIB_VERSION_MINOR - The minor version of zlib
+ ZLIB_VERSION_PATCH - The patch version of zlib
+ ZLIB_VERSION_TWEAK - The tweak version of zlib
+
+.. versionadded:: 3.4
+ Debug and Release variants are found separately.
+
+Backward Compatibility
+^^^^^^^^^^^^^^^^^^^^^^
+
+The following variable are provided for backward compatibility
+
+::
+
+ ZLIB_MAJOR_VERSION - The major version of zlib
+ ZLIB_MINOR_VERSION - The minor version of zlib
+ ZLIB_PATCH_VERSION - The patch version of zlib
+
+Hints
+^^^^^
+
+A user may set ``ZLIB_ROOT`` to a zlib installation root to tell this
+module where to look.
+#]=======================================================================]
+
+set(_ZLIB_SEARCHES)
+
+# Search ZLIB_ROOT first if it is set.
+if(ZLIB_ROOT)
+ set(_ZLIB_SEARCH_ROOT PATHS ${ZLIB_ROOT} NO_DEFAULT_PATH)
+ list(APPEND _ZLIB_SEARCHES _ZLIB_SEARCH_ROOT)
+endif()
+
+# Normal search.
+set(_ZLIB_x86 "(x86)")
+set(_ZLIB_SEARCH_NORMAL
+ PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Zlib;InstallPath]"
+ "$ENV{ProgramFiles}/zlib"
+ "$ENV{ProgramFiles${_ZLIB_x86}}/zlib")
+unset(_ZLIB_x86)
+list(APPEND _ZLIB_SEARCHES _ZLIB_SEARCH_NORMAL)
+
+set(ZLIB_NAMES z zlib zdll zlib1 zlibstatic)
+set(ZLIB_NAMES_DEBUG zd zlibd zdlld zlibd1 zlib1d zlibstaticd)
+
+# Try each search configuration.
+foreach(search ${_ZLIB_SEARCHES})
+ find_path(ZLIB_INCLUDE_DIR NAMES zlib.h ${${search}} PATH_SUFFIXES include)
+endforeach()
+
+# Allow ZLIB_LIBRARY to be set manually, as the location of the zlib library
+if(NOT ZLIB_LIBRARY)
+ foreach(search ${_ZLIB_SEARCHES})
+ find_library(ZLIB_LIBRARY_RELEASE NAMES ${ZLIB_NAMES} NAMES_PER_DIR ${${search}} PATH_SUFFIXES lib)
+ find_library(ZLIB_LIBRARY_DEBUG NAMES ${ZLIB_NAMES_DEBUG} NAMES_PER_DIR ${${search}} PATH_SUFFIXES lib)
+ endforeach()
+
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(ZLIB)
+endif()
+
+unset(ZLIB_NAMES)
+unset(ZLIB_NAMES_DEBUG)
+
+mark_as_advanced(ZLIB_INCLUDE_DIR)
+
+if(ZLIB_INCLUDE_DIR AND EXISTS "${ZLIB_INCLUDE_DIR}/zlib.h")
+ file(STRINGS "${ZLIB_INCLUDE_DIR}/zlib.h" ZLIB_H REGEX "^#define ZLIB_VERSION \"[^\"]*\"$")
+
+ string(REGEX REPLACE "^.*ZLIB_VERSION \"([0-9]+).*$" "\\1" ZLIB_VERSION_MAJOR "${ZLIB_H}")
+ string(REGEX REPLACE "^.*ZLIB_VERSION \"[0-9]+\\.([0-9]+).*$" "\\1" ZLIB_VERSION_MINOR "${ZLIB_H}")
+ string(REGEX REPLACE "^.*ZLIB_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" ZLIB_VERSION_PATCH "${ZLIB_H}")
+ set(ZLIB_VERSION_STRING "${ZLIB_VERSION_MAJOR}.${ZLIB_VERSION_MINOR}.${ZLIB_VERSION_PATCH}")
+
+ # only append a TWEAK version if it exists:
+ set(ZLIB_VERSION_TWEAK "")
+ if( "${ZLIB_H}" MATCHES "ZLIB_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]+\\.([0-9]+)")
+ set(ZLIB_VERSION_TWEAK "${CMAKE_MATCH_1}")
+ string(APPEND ZLIB_VERSION_STRING ".${ZLIB_VERSION_TWEAK}")
+ endif()
+
+ set(ZLIB_MAJOR_VERSION "${ZLIB_VERSION_MAJOR}")
+ set(ZLIB_MINOR_VERSION "${ZLIB_VERSION_MINOR}")
+ set(ZLIB_PATCH_VERSION "${ZLIB_VERSION_PATCH}")
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZLIB REQUIRED_VARS ZLIB_LIBRARY ZLIB_INCLUDE_DIR
+ VERSION_VAR ZLIB_VERSION_STRING)
+
+if(ZLIB_FOUND)
+ set(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR})
+
+ if(NOT ZLIB_LIBRARIES)
+ set(ZLIB_LIBRARIES ${ZLIB_LIBRARY})
+ endif()
+
+ if(NOT TARGET ZLIB::ZLIB)
+ add_library(ZLIB::ZLIB UNKNOWN IMPORTED)
+ set_target_properties(ZLIB::ZLIB PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${ZLIB_INCLUDE_DIRS}")
+
+ if(ZLIB_LIBRARY_RELEASE)
+ set_property(TARGET ZLIB::ZLIB APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(ZLIB::ZLIB PROPERTIES
+ IMPORTED_LOCATION_RELEASE "${ZLIB_LIBRARY_RELEASE}")
+ endif()
+
+ if(ZLIB_LIBRARY_DEBUG)
+ set_property(TARGET ZLIB::ZLIB APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(ZLIB::ZLIB PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${ZLIB_LIBRARY_DEBUG}")
+ endif()
+
+ if(NOT ZLIB_LIBRARY_RELEASE AND NOT ZLIB_LIBRARY_DEBUG)
+ set_property(TARGET ZLIB::ZLIB APPEND PROPERTY
+ IMPORTED_LOCATION "${ZLIB_LIBRARY}")
+ endif()
+ endif()
+endif()
diff --git a/Modules/Findosg.cmake b/Modules/Findosg.cmake
new file mode 100644
index 0000000..027f315
--- /dev/null
+++ b/Modules/Findosg.cmake
@@ -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.
+
+#[=======================================================================[.rst:
+Findosg
+-------
+
+
+
+NOTE: It is highly recommended that you use the new
+FindOpenSceneGraph.cmake introduced in CMake 2.6.3 and not use this
+Find module directly.
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osg This module defines
+
+OSG_FOUND - Was the Osg found? OSG_INCLUDE_DIR - Where to find the
+headers OSG_LIBRARIES - The libraries to link against for the OSG (use
+this)
+
+OSG_LIBRARY - The OSG library OSG_LIBRARY_DEBUG - The OSG debug
+library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgUtil/SceneView>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSG osg/PositionAttitudeTransform)
+OSG_FIND_LIBRARY(OSG osg)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osg DEFAULT_MSG OSG_LIBRARY OSG_INCLUDE_DIR)
diff --git a/Modules/FindosgAnimation.cmake b/Modules/FindosgAnimation.cmake
new file mode 100644
index 0000000..65e3016
--- /dev/null
+++ b/Modules/FindosgAnimation.cmake
@@ -0,0 +1,46 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgAnimation
+----------------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgAnimation This module defines
+
+OSGANIMATION_FOUND - Was osgAnimation found? OSGANIMATION_INCLUDE_DIR
+- Where to find the headers OSGANIMATION_LIBRARIES - The libraries to
+link against for the OSG (use this)
+
+OSGANIMATION_LIBRARY - The OSG library OSGANIMATION_LIBRARY_DEBUG -
+The OSG debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgAnimation/Animation>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGANIMATION osgAnimation/Animation)
+OSG_FIND_LIBRARY(OSGANIMATION osgAnimation)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgAnimation DEFAULT_MSG
+ OSGANIMATION_LIBRARY OSGANIMATION_INCLUDE_DIR)
diff --git a/Modules/FindosgDB.cmake b/Modules/FindosgDB.cmake
new file mode 100644
index 0000000..a28f650
--- /dev/null
+++ b/Modules/FindosgDB.cmake
@@ -0,0 +1,54 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgDB
+---------
+
+
+
+This is part of the ``Findosg*`` suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default :module:`FindOpenGL` module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+:module:`FindOpenSceneGraph` instead of the ``Findosg*.cmake`` modules.
+
+Locate osgDB This module defines:
+
+``OSGDB_FOUND``
+ Was osgDB found?
+
+``OSGDB_INCLUDE_DIR``
+ Where to find the headers
+
+``OSGDB_LIBRARIES``
+ The libraries to link against for the osgDB
+
+``OSGDB_LIBRARY``
+ The osgDB library
+
+``OSGDB_LIBRARY_DEBUG``
+ The osgDB debug library
+
+``$OSGDIR`` is an environment variable that would correspond to::
+
+ ./configure --prefix=$OSGDIR used in building osg.
+
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgDB/DatabasePager>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGDB osgDB/DatabasePager)
+OSG_FIND_LIBRARY(OSGDB osgDB)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgDB DEFAULT_MSG
+ OSGDB_LIBRARY OSGDB_INCLUDE_DIR)
diff --git a/Modules/FindosgFX.cmake b/Modules/FindosgFX.cmake
new file mode 100644
index 0000000..438fab7
--- /dev/null
+++ b/Modules/FindosgFX.cmake
@@ -0,0 +1,46 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgFX
+---------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgFX This module defines
+
+OSGFX_FOUND - Was osgFX found? OSGFX_INCLUDE_DIR - Where to find the
+headers OSGFX_LIBRARIES - The libraries to link against for the osgFX
+(use this)
+
+OSGFX_LIBRARY - The osgFX library OSGFX_LIBRARY_DEBUG - The osgFX
+debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgFX/BumpMapping>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGFX osgFX/BumpMapping)
+OSG_FIND_LIBRARY(OSGFX osgFX)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgFX DEFAULT_MSG
+ OSGFX_LIBRARY OSGFX_INCLUDE_DIR)
diff --git a/Modules/FindosgGA.cmake b/Modules/FindosgGA.cmake
new file mode 100644
index 0000000..7b6ef30
--- /dev/null
+++ b/Modules/FindosgGA.cmake
@@ -0,0 +1,46 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgGA
+---------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgGA This module defines
+
+OSGGA_FOUND - Was osgGA found? OSGGA_INCLUDE_DIR - Where to find the
+headers OSGGA_LIBRARIES - The libraries to link against for the osgGA
+(use this)
+
+OSGGA_LIBRARY - The osgGA library OSGGA_LIBRARY_DEBUG - The osgGA
+debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgGA/FlightManipulator>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGGA osgGA/FlightManipulator)
+OSG_FIND_LIBRARY(OSGGA osgGA)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgGA DEFAULT_MSG
+ OSGGA_LIBRARY OSGGA_INCLUDE_DIR)
diff --git a/Modules/FindosgIntrospection.cmake b/Modules/FindosgIntrospection.cmake
new file mode 100644
index 0000000..625e4c2
--- /dev/null
+++ b/Modules/FindosgIntrospection.cmake
@@ -0,0 +1,47 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgIntrospection
+--------------------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgINTROSPECTION This module defines
+
+OSGINTROSPECTION_FOUND - Was osgIntrospection found?
+OSGINTROSPECTION_INCLUDE_DIR - Where to find the headers
+OSGINTROSPECTION_LIBRARIES - The libraries to link for
+osgIntrospection (use this)
+
+OSGINTROSPECTION_LIBRARY - The osgIntrospection library
+OSGINTROSPECTION_LIBRARY_DEBUG - The osgIntrospection debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgIntrospection/Reflection>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGINTROSPECTION osgIntrospection/Reflection)
+OSG_FIND_LIBRARY(OSGINTROSPECTION osgIntrospection)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgIntrospection DEFAULT_MSG
+ OSGINTROSPECTION_LIBRARY OSGINTROSPECTION_INCLUDE_DIR)
diff --git a/Modules/FindosgManipulator.cmake b/Modules/FindosgManipulator.cmake
new file mode 100644
index 0000000..857ff5d
--- /dev/null
+++ b/Modules/FindosgManipulator.cmake
@@ -0,0 +1,47 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgManipulator
+------------------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgManipulator This module defines
+
+OSGMANIPULATOR_FOUND - Was osgManipulator found?
+OSGMANIPULATOR_INCLUDE_DIR - Where to find the headers
+OSGMANIPULATOR_LIBRARIES - The libraries to link for osgManipulator
+(use this)
+
+OSGMANIPULATOR_LIBRARY - The osgManipulator library
+OSGMANIPULATOR_LIBRARY_DEBUG - The osgManipulator debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgManipulator/TrackballDragger>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGMANIPULATOR osgManipulator/TrackballDragger)
+OSG_FIND_LIBRARY(OSGMANIPULATOR osgManipulator)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgManipulator DEFAULT_MSG
+ OSGMANIPULATOR_LIBRARY OSGMANIPULATOR_INCLUDE_DIR)
diff --git a/Modules/FindosgParticle.cmake b/Modules/FindosgParticle.cmake
new file mode 100644
index 0000000..91a30dc
--- /dev/null
+++ b/Modules/FindosgParticle.cmake
@@ -0,0 +1,46 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgParticle
+---------------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgParticle This module defines
+
+OSGPARTICLE_FOUND - Was osgParticle found? OSGPARTICLE_INCLUDE_DIR -
+Where to find the headers OSGPARTICLE_LIBRARIES - The libraries to
+link for osgParticle (use this)
+
+OSGPARTICLE_LIBRARY - The osgParticle library
+OSGPARTICLE_LIBRARY_DEBUG - The osgParticle debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgParticle/FireEffect>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGPARTICLE osgParticle/FireEffect)
+OSG_FIND_LIBRARY(OSGPARTICLE osgParticle)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgParticle DEFAULT_MSG
+ OSGPARTICLE_LIBRARY OSGPARTICLE_INCLUDE_DIR)
diff --git a/Modules/FindosgPresentation.cmake b/Modules/FindosgPresentation.cmake
new file mode 100644
index 0000000..eae75d6
--- /dev/null
+++ b/Modules/FindosgPresentation.cmake
@@ -0,0 +1,48 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgPresentation
+-------------------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgPresentation This module defines
+
+OSGPRESENTATION_FOUND - Was osgPresentation found?
+OSGPRESENTATION_INCLUDE_DIR - Where to find the headers
+OSGPRESENTATION_LIBRARIES - The libraries to link for osgPresentation
+(use this)
+
+OSGPRESENTATION_LIBRARY - The osgPresentation library
+OSGPRESENTATION_LIBRARY_DEBUG - The osgPresentation debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing. Modified to work with osgPresentation by Robert
+Osfield, January 2012.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgPresentation/SlideEventHandler>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGPRESENTATION osgPresentation/SlideEventHandler)
+OSG_FIND_LIBRARY(OSGPRESENTATION osgPresentation)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgPresentation DEFAULT_MSG
+ OSGPRESENTATION_LIBRARY OSGPRESENTATION_INCLUDE_DIR)
diff --git a/Modules/FindosgProducer.cmake b/Modules/FindosgProducer.cmake
new file mode 100644
index 0000000..33b9f73
--- /dev/null
+++ b/Modules/FindosgProducer.cmake
@@ -0,0 +1,46 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgProducer
+---------------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgProducer This module defines
+
+OSGPRODUCER_FOUND - Was osgProducer found? OSGPRODUCER_INCLUDE_DIR -
+Where to find the headers OSGPRODUCER_LIBRARIES - The libraries to
+link for osgProducer (use this)
+
+OSGPRODUCER_LIBRARY - The osgProducer library
+OSGPRODUCER_LIBRARY_DEBUG - The osgProducer debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgProducer/OsgSceneHandler>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGPRODUCER osgProducer/OsgSceneHandler)
+OSG_FIND_LIBRARY(OSGPRODUCER osgProducer)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgProducer DEFAULT_MSG
+ OSGPRODUCER_LIBRARY OSGPRODUCER_INCLUDE_DIR)
diff --git a/Modules/FindosgQt.cmake b/Modules/FindosgQt.cmake
new file mode 100644
index 0000000..cf35630
--- /dev/null
+++ b/Modules/FindosgQt.cmake
@@ -0,0 +1,46 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgQt
+---------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgQt This module defines
+
+OSGQT_FOUND - Was osgQt found? OSGQT_INCLUDE_DIR - Where to find the
+headers OSGQT_LIBRARIES - The libraries to link for osgQt (use this)
+
+OSGQT_LIBRARY - The osgQt library OSGQT_LIBRARY_DEBUG - The osgQt
+debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing. Modified to work with osgQt by Robert Osfield,
+January 2012.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgQt/GraphicsWindowQt>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGQT osgQt/GraphicsWindowQt)
+OSG_FIND_LIBRARY(OSGQT osgQt)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgQt DEFAULT_MSG
+ OSGQT_LIBRARY OSGQT_INCLUDE_DIR)
diff --git a/Modules/FindosgShadow.cmake b/Modules/FindosgShadow.cmake
new file mode 100644
index 0000000..0049c4e
--- /dev/null
+++ b/Modules/FindosgShadow.cmake
@@ -0,0 +1,46 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgShadow
+-------------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgShadow This module defines
+
+OSGSHADOW_FOUND - Was osgShadow found? OSGSHADOW_INCLUDE_DIR - Where
+to find the headers OSGSHADOW_LIBRARIES - The libraries to link for
+osgShadow (use this)
+
+OSGSHADOW_LIBRARY - The osgShadow library OSGSHADOW_LIBRARY_DEBUG -
+The osgShadow debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgShadow/ShadowTexture>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGSHADOW osgShadow/ShadowTexture)
+OSG_FIND_LIBRARY(OSGSHADOW osgShadow)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgShadow DEFAULT_MSG
+ OSGSHADOW_LIBRARY OSGSHADOW_INCLUDE_DIR)
diff --git a/Modules/FindosgSim.cmake b/Modules/FindosgSim.cmake
new file mode 100644
index 0000000..43ba542
--- /dev/null
+++ b/Modules/FindosgSim.cmake
@@ -0,0 +1,46 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgSim
+----------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgSim This module defines
+
+OSGSIM_FOUND - Was osgSim found? OSGSIM_INCLUDE_DIR - Where to find
+the headers OSGSIM_LIBRARIES - The libraries to link for osgSim (use
+this)
+
+OSGSIM_LIBRARY - The osgSim library OSGSIM_LIBRARY_DEBUG - The osgSim
+debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgSim/ImpostorSprite>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGSIM osgSim/ImpostorSprite)
+OSG_FIND_LIBRARY(OSGSIM osgSim)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgSim DEFAULT_MSG
+ OSGSIM_LIBRARY OSGSIM_INCLUDE_DIR)
diff --git a/Modules/FindosgTerrain.cmake b/Modules/FindosgTerrain.cmake
new file mode 100644
index 0000000..c6f5b69
--- /dev/null
+++ b/Modules/FindosgTerrain.cmake
@@ -0,0 +1,46 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgTerrain
+--------------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgTerrain This module defines
+
+OSGTERRAIN_FOUND - Was osgTerrain found? OSGTERRAIN_INCLUDE_DIR -
+Where to find the headers OSGTERRAIN_LIBRARIES - The libraries to link
+for osgTerrain (use this)
+
+OSGTERRAIN_LIBRARY - The osgTerrain library OSGTERRAIN_LIBRARY_DEBUG -
+The osgTerrain debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgTerrain/Terrain>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGTERRAIN osgTerrain/Terrain)
+OSG_FIND_LIBRARY(OSGTERRAIN osgTerrain)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgTerrain DEFAULT_MSG
+ OSGTERRAIN_LIBRARY OSGTERRAIN_INCLUDE_DIR)
diff --git a/Modules/FindosgText.cmake b/Modules/FindosgText.cmake
new file mode 100644
index 0000000..fd3c232
--- /dev/null
+++ b/Modules/FindosgText.cmake
@@ -0,0 +1,46 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgText
+-----------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgText This module defines
+
+OSGTEXT_FOUND - Was osgText found? OSGTEXT_INCLUDE_DIR - Where to find
+the headers OSGTEXT_LIBRARIES - The libraries to link for osgText (use
+this)
+
+OSGTEXT_LIBRARY - The osgText library OSGTEXT_LIBRARY_DEBUG - The
+osgText debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgText/Text>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGTEXT osgText/Text)
+OSG_FIND_LIBRARY(OSGTEXT osgText)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgText DEFAULT_MSG
+ OSGTEXT_LIBRARY OSGTEXT_INCLUDE_DIR)
diff --git a/Modules/FindosgUtil.cmake b/Modules/FindosgUtil.cmake
new file mode 100644
index 0000000..e84727a
--- /dev/null
+++ b/Modules/FindosgUtil.cmake
@@ -0,0 +1,46 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgUtil
+-----------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgUtil This module defines
+
+OSGUTIL_FOUND - Was osgUtil found? OSGUTIL_INCLUDE_DIR - Where to find
+the headers OSGUTIL_LIBRARIES - The libraries to link for osgUtil (use
+this)
+
+OSGUTIL_LIBRARY - The osgUtil library OSGUTIL_LIBRARY_DEBUG - The
+osgUtil debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgUtil/SceneView>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGUTIL osgUtil/SceneView)
+OSG_FIND_LIBRARY(OSGUTIL osgUtil)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgUtil DEFAULT_MSG
+ OSGUTIL_LIBRARY OSGUTIL_INCLUDE_DIR)
diff --git a/Modules/FindosgViewer.cmake b/Modules/FindosgViewer.cmake
new file mode 100644
index 0000000..2174357
--- /dev/null
+++ b/Modules/FindosgViewer.cmake
@@ -0,0 +1,46 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgViewer
+-------------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgViewer This module defines
+
+OSGVIEWER_FOUND - Was osgViewer found? OSGVIEWER_INCLUDE_DIR - Where
+to find the headers OSGVIEWER_LIBRARIES - The libraries to link for
+osgViewer (use this)
+
+OSGVIEWER_LIBRARY - The osgViewer library OSGVIEWER_LIBRARY_DEBUG -
+The osgViewer debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgViewer/Viewer>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGVIEWER osgViewer/Viewer)
+OSG_FIND_LIBRARY(OSGVIEWER osgViewer)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgViewer DEFAULT_MSG
+ OSGVIEWER_LIBRARY OSGVIEWER_INCLUDE_DIR)
diff --git a/Modules/FindosgVolume.cmake b/Modules/FindosgVolume.cmake
new file mode 100644
index 0000000..35defef
--- /dev/null
+++ b/Modules/FindosgVolume.cmake
@@ -0,0 +1,46 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgVolume
+-------------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgVolume This module defines
+
+OSGVOLUME_FOUND - Was osgVolume found? OSGVOLUME_INCLUDE_DIR - Where
+to find the headers OSGVOLUME_LIBRARIES - The libraries to link for
+osgVolume (use this)
+
+OSGVOLUME_LIBRARY - The osgVolume library OSGVOLUME_LIBRARY_DEBUG -
+The osgVolume debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+Created by Eric Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgVolume/Volume>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGVOLUME osgVolume/Volume)
+OSG_FIND_LIBRARY(OSGVOLUME osgVolume)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgVolume DEFAULT_MSG
+ OSGVOLUME_LIBRARY OSGVOLUME_INCLUDE_DIR)
diff --git a/Modules/FindosgWidget.cmake b/Modules/FindosgWidget.cmake
new file mode 100644
index 0000000..c7aae44
--- /dev/null
+++ b/Modules/FindosgWidget.cmake
@@ -0,0 +1,47 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindosgWidget
+-------------
+
+
+
+This is part of the Findosg* suite used to find OpenSceneGraph
+components. Each component is separate and you must opt in to each
+module. You must also opt into OpenGL and OpenThreads (and Producer
+if needed) as these modules won't do it for you. This is to allow you
+control over your own system piece by piece in case you need to opt
+out of certain components or change the Find behavior for a particular
+module (perhaps because the default FindOpenGL.cmake module doesn't
+work with your system as an example). If you want to use a more
+convenient module that includes everything, use the
+FindOpenSceneGraph.cmake instead of the Findosg*.cmake modules.
+
+Locate osgWidget This module defines
+
+OSGWIDGET_FOUND - Was osgWidget found? OSGWIDGET_INCLUDE_DIR - Where
+to find the headers OSGWIDGET_LIBRARIES - The libraries to link for
+osgWidget (use this)
+
+OSGWIDGET_LIBRARY - The osgWidget library OSGWIDGET_LIBRARY_DEBUG -
+The osgWidget debug library
+
+$OSGDIR is an environment variable that would correspond to the
+./configure --prefix=$OSGDIR used in building osg.
+
+FindosgWidget.cmake tweaked from Findosg* suite as created by Eric
+Wing.
+#]=======================================================================]
+
+# Header files are presumed to be included like
+# #include <osg/PositionAttitudeTransform>
+# #include <osgWidget/Widget>
+
+include(${CMAKE_CURRENT_LIST_DIR}/Findosg_functions.cmake)
+OSG_FIND_PATH (OSGWIDGET osgWidget/Widget)
+OSG_FIND_LIBRARY(OSGWIDGET osgWidget)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(osgWidget DEFAULT_MSG
+ OSGWIDGET_LIBRARY OSGWIDGET_INCLUDE_DIR)
diff --git a/Modules/Findosg_functions.cmake b/Modules/Findosg_functions.cmake
new file mode 100644
index 0000000..563b6bd
--- /dev/null
+++ b/Modules/Findosg_functions.cmake
@@ -0,0 +1,86 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+Findosg_functions
+-----------------
+
+
+
+
+
+This CMake file contains two macros to assist with searching for OSG
+libraries and nodekits. Please see FindOpenSceneGraph.cmake for full
+documentation.
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+
+#
+# OSG_FIND_PATH
+#
+function(OSG_FIND_PATH module header)
+ string(TOUPPER ${module} module_uc)
+
+ # Try the user's environment request before anything else.
+ find_path(${module_uc}_INCLUDE_DIR ${header}
+ HINTS
+ ENV ${module_uc}_DIR
+ ENV OSG_DIR
+ ENV OSGDIR
+ ENV OSG_ROOT
+ ${${module_uc}_DIR}
+ ${OSG_DIR}
+ PATH_SUFFIXES include
+ )
+endfunction()
+
+
+#
+# OSG_FIND_LIBRARY
+#
+function(OSG_FIND_LIBRARY module library)
+ string(TOUPPER ${module} module_uc)
+
+ find_library(${module_uc}_LIBRARY_RELEASE
+ NAMES ${library}
+ HINTS
+ ENV ${module_uc}_DIR
+ ENV OSG_DIR
+ ENV OSGDIR
+ ENV OSG_ROOT
+ ${${module_uc}_DIR}
+ ${OSG_DIR}
+ PATH_SUFFIXES lib
+ )
+
+ find_library(${module_uc}_LIBRARY_DEBUG
+ NAMES ${library}d
+ HINTS
+ ENV ${module_uc}_DIR
+ ENV OSG_DIR
+ ENV OSGDIR
+ ENV OSG_ROOT
+ ${${module_uc}_DIR}
+ ${OSG_DIR}
+ PATH_SUFFIXES lib
+ )
+
+ select_library_configurations(${module_uc})
+
+ # the variables set by select_library_configurations go out of scope
+ # here, so we need to set them again
+ set(${module_uc}_LIBRARY ${${module_uc}_LIBRARY} PARENT_SCOPE)
+ set(${module_uc}_LIBRARIES ${${module_uc}_LIBRARIES} PARENT_SCOPE)
+endfunction()
+
+#
+# OSG_MARK_AS_ADVANCED
+# Just a convenience function for calling MARK_AS_ADVANCED
+#
+function(OSG_MARK_AS_ADVANCED _module)
+ string(TOUPPER ${_module} _module_UC)
+ mark_as_advanced(${_module_UC}_INCLUDE_DIR)
+ mark_as_advanced(${_module_UC}_LIBRARY)
+ mark_as_advanced(${_module_UC}_LIBRARY_DEBUG)
+endfunction()
diff --git a/Modules/FindwxWidgets.cmake b/Modules/FindwxWidgets.cmake
new file mode 100644
index 0000000..63af9b6
--- /dev/null
+++ b/Modules/FindwxWidgets.cmake
@@ -0,0 +1,1243 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindwxWidgets
+-------------
+
+Find a wxWidgets (a.k.a., wxWindows) installation.
+
+This module finds if wxWidgets is installed and selects a default
+configuration to use. wxWidgets is a modular library. To specify the
+modules that you will use, you need to name them as components to the
+package:
+
+find_package(wxWidgets COMPONENTS core base ... OPTIONAL_COMPONENTS net ...)
+
+.. versionadded:: 3.4
+ Support for :command:`find_package` version argument; ``webview`` component.
+
+.. versionadded:: 3.14
+ ``OPTIONAL_COMPONENTS`` support.
+
+There are two search branches: a windows style and a unix style. For
+windows, the following variables are searched for and set to defaults
+in case of multiple choices. Change them if the defaults are not
+desired (i.e., these are the only variables you should change to
+select a configuration):
+
+::
+
+ wxWidgets_ROOT_DIR - Base wxWidgets directory
+ (e.g., C:/wxWidgets-2.6.3).
+ wxWidgets_LIB_DIR - Path to wxWidgets libraries
+ (e.g., C:/wxWidgets-2.6.3/lib/vc_lib).
+ wxWidgets_CONFIGURATION - Configuration to use
+ (e.g., msw, mswd, mswu, mswunivud, etc.)
+ wxWidgets_EXCLUDE_COMMON_LIBRARIES
+ - Set to TRUE to exclude linking of
+ commonly required libs (e.g., png tiff
+ jpeg zlib regex expat).
+
+
+
+For unix style it uses the wx-config utility. You can select between
+debug/release, unicode/ansi, universal/non-universal, and
+static/shared in the QtDialog or ccmake interfaces by turning ON/OFF
+the following variables:
+
+::
+
+ wxWidgets_USE_DEBUG
+ wxWidgets_USE_UNICODE
+ wxWidgets_USE_UNIVERSAL
+ wxWidgets_USE_STATIC
+
+
+
+There is also a wxWidgets_CONFIG_OPTIONS variable for all other
+options that need to be passed to the wx-config utility. For example,
+to use the base toolkit found in the /usr/local path, set the variable
+(before calling the FIND_PACKAGE command) as such:
+
+::
+
+ set(wxWidgets_CONFIG_OPTIONS --toolkit=base --prefix=/usr)
+
+
+
+The following are set after the configuration is done for both windows
+and unix style:
+
+::
+
+ wxWidgets_FOUND - Set to TRUE if wxWidgets was found.
+ wxWidgets_INCLUDE_DIRS - Include directories for WIN32
+ i.e., where to find "wx/wx.h" and
+ "wx/setup.h"; possibly empty for unices.
+ wxWidgets_LIBRARIES - Path to the wxWidgets libraries.
+ wxWidgets_LIBRARY_DIRS - compile time link dirs, useful for
+ rpath on UNIX. Typically an empty string
+ in WIN32 environment.
+ wxWidgets_DEFINITIONS - Contains defines required to compile/link
+ against WX, e.g. WXUSINGDLL
+ wxWidgets_DEFINITIONS_DEBUG- Contains defines required to compile/link
+ against WX debug builds, e.g. __WXDEBUG__
+ wxWidgets_CXX_FLAGS - Include dirs and compiler flags for
+ unices, empty on WIN32. Essentially
+ "`wx-config --cxxflags`".
+ wxWidgets_USE_FILE - Convenience include file.
+
+.. versionadded:: 3.11
+ The following environment variables can be used as hints: ``WX_CONFIG``,
+ ``WXRC_CMD``.
+
+
+Sample usage:
+
+::
+
+ # Note that for MinGW users the order of libs is important!
+ find_package(wxWidgets COMPONENTS gl core base OPTIONAL_COMPONENTS net)
+ if(wxWidgets_FOUND)
+ include(${wxWidgets_USE_FILE})
+ # and for each of your dependent executable/library targets:
+ target_link_libraries(<YourTarget> ${wxWidgets_LIBRARIES})
+ endif()
+
+
+
+If wxWidgets is required (i.e., not an optional part):
+
+::
+
+ find_package(wxWidgets REQUIRED gl core base OPTIONAL_COMPONENTS net)
+ include(${wxWidgets_USE_FILE})
+ # and for each of your dependent executable/library targets:
+ target_link_libraries(<YourTarget> ${wxWidgets_LIBRARIES})
+#]=======================================================================]
+
+#
+# FIXME: check this and provide a correct sample usage...
+# Remember to connect back to the upper text.
+# Sample usage with monolithic wx build:
+#
+# find_package(wxWidgets COMPONENTS mono)
+# ...
+
+# NOTES
+#
+# This module has been tested on the WIN32 platform with wxWidgets
+# 2.6.2, 2.6.3, and 2.5.3. However, it has been designed to
+# easily extend support to all possible builds, e.g., static/shared,
+# debug/release, unicode, universal, multilib/monolithic, etc..
+#
+# If you want to use the module and your build type is not supported
+# out-of-the-box, please contact me to exchange information on how
+# your system is setup and I'll try to add support for it.
+#
+# AUTHOR
+#
+# Miguel A. Figueroa-Villanueva (miguelf at ieee dot org).
+# Jan Woetzel (jw at mip.informatik.uni-kiel.de).
+#
+# Based on previous works of:
+# Jan Woetzel (FindwxWindows.cmake),
+# Jorgen Bodde and Jerry Fath (FindwxWin.cmake).
+
+# TODO/ideas
+#
+# (1) Option/Setting to use all available wx libs
+# In contrast to expert developer who lists the
+# minimal set of required libs in wxWidgets_USE_LIBS
+# there is the newbie user:
+# - who just wants to link against WX with more 'magic'
+# - doesn't know the internal structure of WX or how it was built,
+# in particular if it is monolithic or not
+# - want to link against all available WX libs
+# Basically, the intent here is to mimic what wx-config would do by
+# default (i.e., `wx-config --libs`).
+#
+# Possible solution:
+# Add a reserved keyword "std" that initializes to what wx-config
+# would default to. If the user has not set the wxWidgets_USE_LIBS,
+# default to "std" instead of "base core" as it is now. To implement
+# "std" will basically boil down to a FOR_EACH lib-FOUND, but maybe
+# checking whether a minimal set was found.
+
+
+# FIXME: This and all the DBG_MSG calls should be removed after the
+# module stabilizes.
+#
+# Helper macro to control the debugging output globally. There are
+# two versions for controlling how verbose your output should be.
+macro(DBG_MSG _MSG)
+# message(STATUS
+# "${CMAKE_CURRENT_LIST_FILE}(${CMAKE_CURRENT_LIST_LINE}): ${_MSG}")
+endmacro()
+macro(DBG_MSG_V _MSG)
+# message(STATUS
+# "${CMAKE_CURRENT_LIST_FILE}(${CMAKE_CURRENT_LIST_LINE}): ${_MSG}")
+endmacro()
+
+# Clear return values in case the module is loaded more than once.
+set(wxWidgets_FOUND FALSE)
+set(wxWidgets_INCLUDE_DIRS "")
+set(wxWidgets_LIBRARIES "")
+set(wxWidgets_LIBRARY_DIRS "")
+set(wxWidgets_CXX_FLAGS "")
+
+# DEPRECATED: This is a patch to support the DEPRECATED use of
+# wxWidgets_USE_LIBS.
+#
+# If wxWidgets_USE_LIBS is set:
+# - if using <components>, then override wxWidgets_USE_LIBS
+# - else set wxWidgets_FIND_COMPONENTS to wxWidgets_USE_LIBS
+if(wxWidgets_USE_LIBS AND NOT wxWidgets_FIND_COMPONENTS)
+ set(wxWidgets_FIND_COMPONENTS ${wxWidgets_USE_LIBS})
+endif()
+DBG_MSG("wxWidgets_FIND_COMPONENTS : ${wxWidgets_FIND_COMPONENTS}")
+
+# Add the convenience use file if available.
+#
+# Get dir of this file which may reside in:
+# - CMAKE_MAKE_ROOT/Modules on CMake installation
+# - CMAKE_MODULE_PATH if user prefers his own specialized version
+set(wxWidgets_USE_FILE "")
+get_filename_component(
+ wxWidgets_CURRENT_LIST_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
+# Prefer an existing customized version, but the user might override
+# the FindwxWidgets module and not the UsewxWidgets one.
+if(EXISTS "${wxWidgets_CURRENT_LIST_DIR}/UsewxWidgets.cmake")
+ set(wxWidgets_USE_FILE
+ "${wxWidgets_CURRENT_LIST_DIR}/UsewxWidgets.cmake")
+else()
+ set(wxWidgets_USE_FILE UsewxWidgets)
+endif()
+
+#=====================================================================
+# Determine whether unix or win32 paths should be used
+#=====================================================================
+if(WIN32 AND NOT CYGWIN AND NOT MSYS AND NOT CMAKE_CROSSCOMPILING)
+ set(wxWidgets_FIND_STYLE "win32")
+else()
+ set(wxWidgets_FIND_STYLE "unix")
+endif()
+
+#=====================================================================
+# WIN32_FIND_STYLE
+#=====================================================================
+if(wxWidgets_FIND_STYLE STREQUAL "win32")
+ # Useful common wx libs needed by almost all components.
+ set(wxWidgets_COMMON_LIBRARIES png tiff jpeg zlib regex expat)
+
+ # DEPRECATED: Use find_package(wxWidgets COMPONENTS mono) instead.
+ if(NOT wxWidgets_FIND_COMPONENTS)
+ if(wxWidgets_USE_MONOLITHIC)
+ set(wxWidgets_FIND_COMPONENTS mono)
+ else()
+ set(wxWidgets_FIND_COMPONENTS core base) # this is default
+ endif()
+ endif()
+
+ # Add the common (usually required libs) unless
+ # wxWidgets_EXCLUDE_COMMON_LIBRARIES has been set.
+ if(NOT wxWidgets_EXCLUDE_COMMON_LIBRARIES)
+ list(APPEND wxWidgets_FIND_COMPONENTS
+ ${wxWidgets_COMMON_LIBRARIES})
+ endif()
+
+ #-------------------------------------------------------------------
+ # WIN32: Helper MACROS
+ #-------------------------------------------------------------------
+ #
+ # Get filename components for a configuration. For example,
+ # if _CONFIGURATION = mswunivud, then _PF="msw", _UNV=univ, _UCD=u _DBG=d
+ # if _CONFIGURATION = mswu, then _PF="msw", _UNV="", _UCD=u _DBG=""
+ #
+ macro(WX_GET_NAME_COMPONENTS _CONFIGURATION _PF _UNV _UCD _DBG)
+ DBG_MSG_V(${_CONFIGURATION})
+ string(REGEX MATCH "univ" ${_UNV} "${_CONFIGURATION}")
+ string(REGEX REPLACE "[msw|qt].*(u)[d]*$" "u" ${_UCD} "${_CONFIGURATION}")
+ if(${_UCD} STREQUAL ${_CONFIGURATION})
+ set(${_UCD} "")
+ endif()
+ string(REGEX MATCH "d$" ${_DBG} "${_CONFIGURATION}")
+ string(REGEX MATCH "^[msw|qt]*" ${_PF} "${_CONFIGURATION}")
+ endmacro()
+
+ #
+ # Find libraries associated to a configuration.
+ #
+ macro(WX_FIND_LIBS _PF _UNV _UCD _DBG)
+ DBG_MSG_V("m_unv = ${_UNV}")
+ DBG_MSG_V("m_ucd = ${_UCD}")
+ DBG_MSG_V("m_dbg = ${_DBG}")
+
+ # FIXME: What if both regex libs are available. regex should be
+ # found outside the loop and only wx${LIB}${_UCD}${_DBG}.
+ # Find wxWidgets common libraries.
+ foreach(LIB ${wxWidgets_COMMON_LIBRARIES} scintilla)
+ find_library(WX_${LIB}${_DBG}
+ NAMES
+ wx${LIB}${_UCD}${_DBG} # for regex
+ wx${LIB}${_DBG}
+ PATHS ${WX_LIB_DIR}
+ NO_DEFAULT_PATH
+ )
+ mark_as_advanced(WX_${LIB}${_DBG})
+ endforeach()
+
+ # Find wxWidgets multilib base libraries.
+ find_library(WX_base${_DBG}
+ NAMES
+ wxbase31${_UCD}${_DBG}
+ wxbase30${_UCD}${_DBG}
+ wxbase29${_UCD}${_DBG}
+ wxbase28${_UCD}${_DBG}
+ wxbase27${_UCD}${_DBG}
+ wxbase26${_UCD}${_DBG}
+ wxbase25${_UCD}${_DBG}
+ PATHS ${WX_LIB_DIR}
+ NO_DEFAULT_PATH
+ )
+ mark_as_advanced(WX_base${_DBG})
+ foreach(LIB net odbc xml)
+ find_library(WX_${LIB}${_DBG}
+ NAMES
+ wxbase31${_UCD}${_DBG}_${LIB}
+ wxbase30${_UCD}${_DBG}_${LIB}
+ wxbase29${_UCD}${_DBG}_${LIB}
+ wxbase28${_UCD}${_DBG}_${LIB}
+ wxbase27${_UCD}${_DBG}_${LIB}
+ wxbase26${_UCD}${_DBG}_${LIB}
+ wxbase25${_UCD}${_DBG}_${LIB}
+ PATHS ${WX_LIB_DIR}
+ NO_DEFAULT_PATH
+ )
+ mark_as_advanced(WX_${LIB}${_DBG})
+ endforeach()
+
+ # Find wxWidgets monolithic library.
+ find_library(WX_mono${_DBG}
+ NAMES
+ wx${_PF}${_UNV}31${_UCD}${_DBG}
+ wx${_PF}${_UNV}30${_UCD}${_DBG}
+ wx${_PF}${_UNV}29${_UCD}${_DBG}
+ wx${_PF}${_UNV}28${_UCD}${_DBG}
+ wx${_PF}${_UNV}27${_UCD}${_DBG}
+ wx${_PF}${_UNV}26${_UCD}${_DBG}
+ wx${_PF}${_UNV}25${_UCD}${_DBG}
+ PATHS ${WX_LIB_DIR}
+ NO_DEFAULT_PATH
+ )
+ mark_as_advanced(WX_mono${_DBG})
+
+ # Find wxWidgets multilib libraries.
+ foreach(LIB core adv aui html media xrc dbgrid gl qa richtext
+ stc ribbon propgrid webview)
+ find_library(WX_${LIB}${_DBG}
+ NAMES
+ wx${_PF}${_UNV}31${_UCD}${_DBG}_${LIB}
+ wx${_PF}${_UNV}30${_UCD}${_DBG}_${LIB}
+ wx${_PF}${_UNV}29${_UCD}${_DBG}_${LIB}
+ wx${_PF}${_UNV}28${_UCD}${_DBG}_${LIB}
+ wx${_PF}${_UNV}27${_UCD}${_DBG}_${LIB}
+ wx${_PF}${_UNV}26${_UCD}${_DBG}_${LIB}
+ wx${_PF}${_UNV}25${_UCD}${_DBG}_${LIB}
+ PATHS ${WX_LIB_DIR}
+ NO_DEFAULT_PATH
+ )
+ mark_as_advanced(WX_${LIB}${_DBG})
+ endforeach()
+ endmacro()
+
+ #
+ # Clear all library paths, so that FIND_LIBRARY refinds them.
+ #
+ # Clear a lib, reset its found flag, and mark as advanced.
+ macro(WX_CLEAR_LIB _LIB)
+ set(${_LIB} "${_LIB}-NOTFOUND" CACHE FILEPATH "Cleared." FORCE)
+ set(${_LIB}_FOUND FALSE)
+ mark_as_advanced(${_LIB})
+ endmacro()
+ # Clear all debug or release library paths (arguments are "d" or "").
+ macro(WX_CLEAR_ALL_LIBS _DBG)
+ # Clear wxWidgets common libraries.
+ foreach(LIB ${wxWidgets_COMMON_LIBRARIES} scintilla)
+ WX_CLEAR_LIB(WX_${LIB}${_DBG})
+ endforeach()
+
+ # Clear wxWidgets multilib base libraries.
+ WX_CLEAR_LIB(WX_base${_DBG})
+ foreach(LIB net odbc xml)
+ WX_CLEAR_LIB(WX_${LIB}${_DBG})
+ endforeach()
+
+ # Clear wxWidgets monolithic library.
+ WX_CLEAR_LIB(WX_mono${_DBG})
+
+ # Clear wxWidgets multilib libraries.
+ foreach(LIB core adv aui html media xrc dbgrid gl qa richtext
+ webview stc ribbon propgrid)
+ WX_CLEAR_LIB(WX_${LIB}${_DBG})
+ endforeach()
+ endmacro()
+ # Clear all wxWidgets debug libraries.
+ macro(WX_CLEAR_ALL_DBG_LIBS)
+ WX_CLEAR_ALL_LIBS("d")
+ endmacro()
+ # Clear all wxWidgets release libraries.
+ macro(WX_CLEAR_ALL_REL_LIBS)
+ WX_CLEAR_ALL_LIBS("")
+ endmacro()
+
+ #
+ # Set the wxWidgets_LIBRARIES variable.
+ # Also, Sets output variable wxWidgets_FOUND to FALSE if it fails.
+ #
+ macro(WX_SET_LIBRARIES _LIBS _DBG)
+ DBG_MSG_V("Looking for ${${_LIBS}}")
+ if(WX_USE_REL_AND_DBG)
+ foreach(LIB ${${_LIBS}})
+ DBG_MSG_V("Searching for ${LIB} and ${LIB}d")
+ DBG_MSG_V("WX_${LIB} : ${WX_${LIB}}")
+ DBG_MSG_V("WX_${LIB}d : ${WX_${LIB}d}")
+ if(WX_${LIB} AND WX_${LIB}d)
+ DBG_MSG_V("Found ${LIB} and ${LIB}d")
+ list(APPEND wxWidgets_LIBRARIES
+ debug ${WX_${LIB}d} optimized ${WX_${LIB}}
+ )
+ set(wxWidgets_${LIB}_FOUND TRUE)
+ elseif(NOT wxWidgets_FIND_REQUIRED_${LIB})
+ DBG_MSG_V("- ignored optional missing WX_${LIB}=${WX_${LIB}} or WX_${LIB}d=${WX_${LIB}d}")
+ else()
+ DBG_MSG_V("- not found due to missing WX_${LIB}=${WX_${LIB}} or WX_${LIB}d=${WX_${LIB}d}")
+ set(wxWidgets_FOUND FALSE)
+ endif()
+ endforeach()
+ else()
+ foreach(LIB ${${_LIBS}})
+ DBG_MSG_V("Searching for ${LIB}${_DBG}")
+ DBG_MSG_V("WX_${LIB}${_DBG} : ${WX_${LIB}${_DBG}}")
+ if(WX_${LIB}${_DBG})
+ DBG_MSG_V("Found ${LIB}${_DBG}")
+ list(APPEND wxWidgets_LIBRARIES ${WX_${LIB}${_DBG}})
+ set(wxWidgets_${LIB}_FOUND TRUE)
+ elseif(NOT wxWidgets_FIND_REQUIRED_${LIB})
+ DBG_MSG_V("- ignored optional missing WX_${LIB}${_DBG}=${WX_${LIB}${_DBG}}")
+ else()
+ DBG_MSG_V("- not found due to missing WX_${LIB}${_DBG}=${WX_${LIB}${_DBG}}")
+ set(wxWidgets_FOUND FALSE)
+ endif()
+ endforeach()
+ endif()
+
+ DBG_MSG_V("OpenGL")
+ list(FIND ${_LIBS} gl WX_USE_GL)
+ if(NOT WX_USE_GL EQUAL -1)
+ DBG_MSG_V("- is required.")
+ list(APPEND wxWidgets_LIBRARIES opengl32 glu32)
+ endif()
+
+ list(APPEND wxWidgets_LIBRARIES winmm comctl32 uuid oleacc uxtheme rpcrt4 shlwapi version wsock32)
+ endmacro()
+
+ #-------------------------------------------------------------------
+ # WIN32: Start actual work.
+ #-------------------------------------------------------------------
+
+ # Look for an installation tree.
+ find_path(wxWidgets_ROOT_DIR
+ NAMES include/wx/wx.h
+ PATHS
+ ENV wxWidgets_ROOT_DIR
+ ENV WXWIN
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\wxWidgets_is1;Inno Setup: App Path]" # WX 2.6.x
+ C:/
+ D:/
+ ENV ProgramFiles
+ PATH_SUFFIXES
+ wxWidgets-3.1.0
+ wxWidgets-3.0.2
+ wxWidgets-3.0.1
+ wxWidgets-3.0.0
+ wxWidgets-2.9.5
+ wxWidgets-2.9.4
+ wxWidgets-2.9.3
+ wxWidgets-2.9.2
+ wxWidgets-2.9.1
+ wxWidgets-2.9.0
+ wxWidgets-2.8.9
+ wxWidgets-2.8.8
+ wxWidgets-2.8.7
+ wxWidgets-2.8.6
+ wxWidgets-2.8.5
+ wxWidgets-2.8.4
+ wxWidgets-2.8.3
+ wxWidgets-2.8.2
+ wxWidgets-2.8.1
+ wxWidgets-2.8.0
+ wxWidgets-2.7.4
+ wxWidgets-2.7.3
+ wxWidgets-2.7.2
+ wxWidgets-2.7.1
+ wxWidgets-2.7.0
+ wxWidgets-2.7.0-1
+ wxWidgets-2.6.4
+ wxWidgets-2.6.3
+ wxWidgets-2.6.2
+ wxWidgets-2.6.1
+ wxWidgets-2.5.4
+ wxWidgets-2.5.3
+ wxWidgets-2.5.2
+ wxWidgets-2.5.1
+ wxWidgets
+ DOC "wxWidgets base/installation directory"
+ )
+
+ # If wxWidgets_ROOT_DIR changed, clear lib dir.
+ if(NOT WX_ROOT_DIR STREQUAL wxWidgets_ROOT_DIR)
+ set(WX_ROOT_DIR ${wxWidgets_ROOT_DIR}
+ CACHE INTERNAL "wxWidgets_ROOT_DIR")
+ set(wxWidgets_LIB_DIR "wxWidgets_LIB_DIR-NOTFOUND"
+ CACHE PATH "Cleared." FORCE)
+ endif()
+
+ if(WX_ROOT_DIR)
+ # Select one default tree inside the already determined wx tree.
+ # Prefer static/shared order usually consistent with build
+ # settings.
+ set(_WX_TOOL "")
+ set(_WX_TOOLVER "")
+ set(_WX_ARCH "")
+ if(MINGW)
+ set(_WX_TOOL gcc)
+ elseif(MSVC)
+ set(_WX_TOOL vc)
+ set(_WX_TOOLVER ${MSVC_TOOLSET_VERSION})
+ # support for a lib/vc14x_x64_dll/ path from wxW 3.1.3 distribution
+ string(REGEX REPLACE ".$" "x" _WX_TOOLVERx ${_WX_TOOLVER})
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(_WX_ARCH _x64)
+ endif()
+ endif()
+ if(BUILD_SHARED_LIBS)
+ find_path(wxWidgets_LIB_DIR
+ NAMES
+ qtu/wx/setup.h
+ qtud/wx/setup.h
+ msw/wx/setup.h
+ mswd/wx/setup.h
+ mswu/wx/setup.h
+ mswud/wx/setup.h
+ mswuniv/wx/setup.h
+ mswunivd/wx/setup.h
+ mswunivu/wx/setup.h
+ mswunivud/wx/setup.h
+ PATHS
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVER}_xp${_WX_ARCH}_dll # prefer shared
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVER}${_WX_ARCH}_dll # prefer shared
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVERx}_xp${_WX_ARCH}_dll # prefer shared
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVERx}${_WX_ARCH}_dll # prefer shared
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_ARCH}_dll # prefer shared
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVER}_xp${_WX_ARCH}_lib
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVER}${_WX_ARCH}_lib
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVERx}_xp${_WX_ARCH}_lib
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVERx}${_WX_ARCH}_lib
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_ARCH}_lib
+ DOC "Path to wxWidgets libraries"
+ NO_DEFAULT_PATH
+ )
+ else()
+ find_path(wxWidgets_LIB_DIR
+ NAMES
+ qtu/wx/setup.h
+ qtud/wx/setup.h
+ msw/wx/setup.h
+ mswd/wx/setup.h
+ mswu/wx/setup.h
+ mswud/wx/setup.h
+ mswuniv/wx/setup.h
+ mswunivd/wx/setup.h
+ mswunivu/wx/setup.h
+ mswunivud/wx/setup.h
+ PATHS
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVER}_xp${_WX_ARCH}_lib # prefer static
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVER}${_WX_ARCH}_lib # prefer static
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVERx}_xp${_WX_ARCH}_lib # prefer static
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVERx}${_WX_ARCH}_lib # prefer static
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_ARCH}_lib # prefer static
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVER}_xp${_WX_ARCH}_dll
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVER}${_WX_ARCH}_dll
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVERx}_xp${_WX_ARCH}_dll
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_TOOLVERx}${_WX_ARCH}_dll
+ ${WX_ROOT_DIR}/lib/${_WX_TOOL}${_WX_ARCH}_dll
+ DOC "Path to wxWidgets libraries"
+ NO_DEFAULT_PATH
+ )
+ endif()
+ unset(_WX_TOOL)
+ unset(_WX_TOOLVER)
+ unset(_WX_ARCH)
+
+ # If wxWidgets_LIB_DIR changed, clear all libraries.
+ if(NOT WX_LIB_DIR STREQUAL wxWidgets_LIB_DIR)
+ set(WX_LIB_DIR ${wxWidgets_LIB_DIR} CACHE INTERNAL "wxWidgets_LIB_DIR")
+ WX_CLEAR_ALL_DBG_LIBS()
+ WX_CLEAR_ALL_REL_LIBS()
+ endif()
+
+ if(WX_LIB_DIR)
+ # If building shared libs, define WXUSINGDLL to use dllimport.
+ if(WX_LIB_DIR MATCHES "[dD][lL][lL]")
+ set(wxWidgets_DEFINITIONS WXUSINGDLL)
+ DBG_MSG_V("detected SHARED/DLL tree WX_LIB_DIR=${WX_LIB_DIR}")
+ endif()
+
+ # Search for available configuration types.
+ foreach(CFG mswunivud mswunivd mswud mswd mswunivu mswuniv mswu msw qt qtd qtu qtud)
+ set(WX_${CFG}_FOUND FALSE)
+ if(EXISTS ${WX_LIB_DIR}/${CFG})
+ list(APPEND WX_CONFIGURATION_LIST ${CFG})
+ set(WX_${CFG}_FOUND TRUE)
+ set(WX_CONFIGURATION ${CFG})
+ endif()
+ endforeach()
+ DBG_MSG_V("WX_CONFIGURATION_LIST=${WX_CONFIGURATION_LIST}")
+
+ if(WX_CONFIGURATION)
+ set(wxWidgets_FOUND TRUE)
+
+ # If the selected configuration wasn't found force the default
+ # one. Otherwise, use it but still force a refresh for
+ # updating the doc string with the current list of available
+ # configurations.
+ if(NOT WX_${wxWidgets_CONFIGURATION}_FOUND)
+ set(wxWidgets_CONFIGURATION ${WX_CONFIGURATION} CACHE STRING
+ "Set wxWidgets configuration (${WX_CONFIGURATION_LIST})" FORCE)
+ else()
+ set(wxWidgets_CONFIGURATION ${wxWidgets_CONFIGURATION} CACHE STRING
+ "Set wxWidgets configuration (${WX_CONFIGURATION_LIST})" FORCE)
+ endif()
+
+ # If release config selected, and both release/debug exist.
+ if(WX_${wxWidgets_CONFIGURATION}d_FOUND)
+ option(wxWidgets_USE_REL_AND_DBG
+ "Use release and debug configurations?" TRUE)
+ set(WX_USE_REL_AND_DBG ${wxWidgets_USE_REL_AND_DBG})
+ else()
+ # If the option exists (already in cache), force it false.
+ if(wxWidgets_USE_REL_AND_DBG)
+ set(wxWidgets_USE_REL_AND_DBG FALSE CACHE BOOL
+ "No ${wxWidgets_CONFIGURATION}d found." FORCE)
+ endif()
+ set(WX_USE_REL_AND_DBG FALSE)
+ endif()
+
+ # Get configuration parameters from the name.
+ WX_GET_NAME_COMPONENTS(${wxWidgets_CONFIGURATION} PF UNV UCD DBG)
+
+ # Set wxWidgets lib setup include directory.
+ if(EXISTS ${WX_LIB_DIR}/${wxWidgets_CONFIGURATION}/wx/setup.h)
+ set(wxWidgets_INCLUDE_DIRS
+ ${WX_LIB_DIR}/${wxWidgets_CONFIGURATION})
+ else()
+ DBG_MSG("wxWidgets_FOUND FALSE because ${WX_LIB_DIR}/${wxWidgets_CONFIGURATION}/wx/setup.h does not exists.")
+ set(wxWidgets_FOUND FALSE)
+ endif()
+
+ # Set wxWidgets main include directory.
+ if(EXISTS ${WX_ROOT_DIR}/include/wx/wx.h)
+ list(APPEND wxWidgets_INCLUDE_DIRS ${WX_ROOT_DIR}/include)
+ else()
+ DBG_MSG("wxWidgets_FOUND FALSE because WX_ROOT_DIR=${WX_ROOT_DIR} has no ${WX_ROOT_DIR}/include/wx/wx.h")
+ set(wxWidgets_FOUND FALSE)
+ endif()
+
+ # Find wxWidgets libraries.
+ WX_FIND_LIBS("${PF}" "${UNV}" "${UCD}" "${DBG}")
+ if(WX_USE_REL_AND_DBG)
+ WX_FIND_LIBS("${PF}" "${UNV}" "${UCD}" "d")
+ endif()
+
+ # Settings for requested libs (i.e., include dir, libraries, etc.).
+ WX_SET_LIBRARIES(wxWidgets_FIND_COMPONENTS "${DBG}")
+
+ # Add necessary definitions for unicode builds
+ if("${UCD}" STREQUAL "u")
+ list(APPEND wxWidgets_DEFINITIONS UNICODE _UNICODE)
+ endif()
+
+ # Add necessary definitions for debug builds
+ set(wxWidgets_DEFINITIONS_DEBUG _DEBUG __WXDEBUG__)
+
+ endif()
+ endif()
+ endif()
+
+#=====================================================================
+# UNIX_FIND_STYLE
+#=====================================================================
+else()
+ if(wxWidgets_FIND_STYLE STREQUAL "unix")
+ #-----------------------------------------------------------------
+ # UNIX: Helper MACROS
+ #-----------------------------------------------------------------
+ #
+ # Set the default values based on "wx-config --selected-config".
+ #
+ macro(WX_CONFIG_SELECT_GET_DEFAULT)
+ execute_process(
+ COMMAND sh "${wxWidgets_CONFIG_EXECUTABLE}"
+ ${wxWidgets_CONFIG_OPTIONS} --selected-config
+ OUTPUT_VARIABLE _wx_selected_config
+ RESULT_VARIABLE _wx_result
+ ERROR_QUIET
+ )
+ if(_wx_result EQUAL 0)
+ foreach(_opt_name debug static unicode universal)
+ string(TOUPPER ${_opt_name} _upper_opt_name)
+ if(_wx_selected_config MATCHES "${_opt_name}")
+ set(wxWidgets_DEFAULT_${_upper_opt_name} ON)
+ else()
+ set(wxWidgets_DEFAULT_${_upper_opt_name} OFF)
+ endif()
+ endforeach()
+ else()
+ foreach(_upper_opt_name DEBUG STATIC UNICODE UNIVERSAL)
+ set(wxWidgets_DEFAULT_${_upper_opt_name} OFF)
+ endforeach()
+ endif()
+ endmacro()
+
+ #
+ # Query a boolean configuration option to determine if the system
+ # has both builds available. If so, provide the selection option
+ # to the user.
+ #
+ macro(WX_CONFIG_SELECT_QUERY_BOOL _OPT_NAME _OPT_HELP)
+ execute_process(
+ COMMAND sh "${wxWidgets_CONFIG_EXECUTABLE}"
+ ${wxWidgets_CONFIG_OPTIONS} --${_OPT_NAME}=yes
+ RESULT_VARIABLE _wx_result_yes
+ OUTPUT_QUIET
+ ERROR_QUIET
+ )
+ execute_process(
+ COMMAND sh "${wxWidgets_CONFIG_EXECUTABLE}"
+ ${wxWidgets_CONFIG_OPTIONS} --${_OPT_NAME}=no
+ RESULT_VARIABLE _wx_result_no
+ OUTPUT_QUIET
+ ERROR_QUIET
+ )
+ string(TOUPPER ${_OPT_NAME} _UPPER_OPT_NAME)
+ if(_wx_result_yes EQUAL 0 AND _wx_result_no EQUAL 0)
+ option(wxWidgets_USE_${_UPPER_OPT_NAME}
+ ${_OPT_HELP} ${wxWidgets_DEFAULT_${_UPPER_OPT_NAME}})
+ else()
+ # If option exists (already in cache), force to available one.
+ if(DEFINED wxWidgets_USE_${_UPPER_OPT_NAME})
+ if(_wx_result_yes EQUAL 0)
+ set(wxWidgets_USE_${_UPPER_OPT_NAME} ON CACHE BOOL ${_OPT_HELP} FORCE)
+ else()
+ set(wxWidgets_USE_${_UPPER_OPT_NAME} OFF CACHE BOOL ${_OPT_HELP} FORCE)
+ endif()
+ endif()
+ endif()
+ endmacro()
+
+ #
+ # Set wxWidgets_SELECT_OPTIONS to wx-config options for selecting
+ # among multiple builds.
+ #
+ macro(WX_CONFIG_SELECT_SET_OPTIONS)
+ set(wxWidgets_SELECT_OPTIONS ${wxWidgets_CONFIG_OPTIONS})
+ foreach(_opt_name debug static unicode universal)
+ string(TOUPPER ${_opt_name} _upper_opt_name)
+ if(DEFINED wxWidgets_USE_${_upper_opt_name})
+ if(wxWidgets_USE_${_upper_opt_name})
+ list(APPEND wxWidgets_SELECT_OPTIONS --${_opt_name}=yes)
+ else()
+ list(APPEND wxWidgets_SELECT_OPTIONS --${_opt_name}=no)
+ endif()
+ endif()
+ endforeach()
+ endmacro()
+
+ #-----------------------------------------------------------------
+ # UNIX: Start actual work.
+ #-----------------------------------------------------------------
+ # Support cross-compiling, only search in the target platform.
+ #
+ # Look for wx-config -- this can be set in the environment,
+ # or try versioned and toolchain-versioned variants of the -config
+ # executable as well.
+ find_program(wxWidgets_CONFIG_EXECUTABLE
+ NAMES
+ $ENV{WX_CONFIG}
+ wx-config
+ wx-config-3.1 wx-config-3.0 wx-config-2.9 wx-config-2.8
+ wxgtk3u-3.1-config wxgtk3u-3.0-config wxgtk2u-2.8-config
+ DOC "Location of wxWidgets library configuration provider binary (wx-config)."
+ ONLY_CMAKE_FIND_ROOT_PATH
+ )
+
+ if(wxWidgets_CONFIG_EXECUTABLE)
+ set(wxWidgets_FOUND TRUE)
+
+ # get defaults based on "wx-config --selected-config"
+ WX_CONFIG_SELECT_GET_DEFAULT()
+
+ # for each option: if both builds are available, provide option
+ WX_CONFIG_SELECT_QUERY_BOOL(debug "Use debug build?")
+ WX_CONFIG_SELECT_QUERY_BOOL(unicode "Use unicode build?")
+ WX_CONFIG_SELECT_QUERY_BOOL(universal "Use universal build?")
+ WX_CONFIG_SELECT_QUERY_BOOL(static "Link libraries statically?")
+
+ # process selection to set wxWidgets_SELECT_OPTIONS
+ WX_CONFIG_SELECT_SET_OPTIONS()
+ DBG_MSG("wxWidgets_SELECT_OPTIONS=${wxWidgets_SELECT_OPTIONS}")
+
+ # run the wx-config program to get cxxflags
+ execute_process(
+ COMMAND sh "${wxWidgets_CONFIG_EXECUTABLE}"
+ ${wxWidgets_SELECT_OPTIONS} --cxxflags
+ OUTPUT_VARIABLE wxWidgets_CXX_FLAGS
+ RESULT_VARIABLE RET
+ ERROR_QUIET
+ )
+ if(RET EQUAL 0)
+ string(STRIP "${wxWidgets_CXX_FLAGS}" wxWidgets_CXX_FLAGS)
+ separate_arguments(wxWidgets_CXX_FLAGS_LIST NATIVE_COMMAND "${wxWidgets_CXX_FLAGS}")
+
+ DBG_MSG_V("wxWidgets_CXX_FLAGS=${wxWidgets_CXX_FLAGS}")
+
+ # parse definitions and include dirs from cxxflags
+ # drop the -D and -I prefixes
+ set(wxWidgets_CXX_FLAGS)
+ foreach(arg IN LISTS wxWidgets_CXX_FLAGS_LIST)
+ if("${arg}" MATCHES "^-I(.*)$")
+ # include directory
+ list(APPEND wxWidgets_INCLUDE_DIRS "${CMAKE_MATCH_1}")
+ elseif("${arg}" MATCHES "^-D(.*)$")
+ # compile definition
+ list(APPEND wxWidgets_DEFINITIONS "${CMAKE_MATCH_1}")
+ else()
+ list(APPEND wxWidgets_CXX_FLAGS "${arg}")
+ endif()
+ endforeach()
+
+ DBG_MSG_V("wxWidgets_DEFINITIONS=${wxWidgets_DEFINITIONS}")
+ DBG_MSG_V("wxWidgets_INCLUDE_DIRS=${wxWidgets_INCLUDE_DIRS}")
+ DBG_MSG_V("wxWidgets_CXX_FLAGS=${wxWidgets_CXX_FLAGS}")
+
+ else()
+ set(wxWidgets_FOUND FALSE)
+ DBG_MSG_V(
+ "${wxWidgets_CONFIG_EXECUTABLE} --cxxflags FAILED with RET=${RET}")
+ endif()
+
+ # run the wx-config program to get the libs
+ # - NOTE: wx-config doesn't verify that the libs requested exist
+ # it just produces the names. Maybe a TRY_COMPILE would
+ # be useful here...
+ unset(_cmp_req)
+ unset(_cmp_opt)
+ foreach(_cmp IN LISTS wxWidgets_FIND_COMPONENTS)
+ if(wxWidgets_FIND_REQUIRED_${_cmp})
+ list(APPEND _cmp_req "${_cmp}")
+ else()
+ list(APPEND _cmp_opt "${_cmp}")
+ endif()
+ endforeach()
+ DBG_MSG_V("wxWidgets required components : ${_cmp_req}")
+ DBG_MSG_V("wxWidgets optional components : ${_cmp_opt}")
+ if(DEFINED _cmp_opt)
+ string(REPLACE ";" "," _cmp_opt "--optional-libs ${_cmp_opt}")
+ endif()
+ string(REPLACE ";" "," _cmp_req "${_cmp_req}")
+ execute_process(
+ COMMAND sh "${wxWidgets_CONFIG_EXECUTABLE}"
+ ${wxWidgets_SELECT_OPTIONS} --libs ${_cmp_req} ${_cmp_opt}
+ OUTPUT_VARIABLE wxWidgets_LIBRARIES
+ RESULT_VARIABLE RET
+ ERROR_QUIET
+ )
+ if(RET EQUAL 0)
+ string(STRIP "${wxWidgets_LIBRARIES}" wxWidgets_LIBRARIES)
+ separate_arguments(wxWidgets_LIBRARIES)
+ string(REPLACE "-framework;" "-framework "
+ wxWidgets_LIBRARIES "${wxWidgets_LIBRARIES}")
+ string(REPLACE "-weak_framework;" "-weak_framework "
+ wxWidgets_LIBRARIES "${wxWidgets_LIBRARIES}")
+ string(REPLACE "-arch;" "-arch "
+ wxWidgets_LIBRARIES "${wxWidgets_LIBRARIES}")
+ string(REPLACE "-isysroot;" "-isysroot "
+ wxWidgets_LIBRARIES "${wxWidgets_LIBRARIES}")
+
+ # extract linkdirs (-L) for rpath (i.e., LINK_DIRECTORIES)
+ string(REGEX MATCHALL "-L[^;]+"
+ wxWidgets_LIBRARY_DIRS "${wxWidgets_LIBRARIES}")
+ string(REGEX REPLACE "-L([^;]+)" "\\1"
+ wxWidgets_LIBRARY_DIRS "${wxWidgets_LIBRARY_DIRS}")
+
+ DBG_MSG_V("wxWidgets_LIBRARIES=${wxWidgets_LIBRARIES}")
+ DBG_MSG_V("wxWidgets_LIBRARY_DIRS=${wxWidgets_LIBRARY_DIRS}")
+
+ else()
+ set(wxWidgets_FOUND FALSE)
+ DBG_MSG("${wxWidgets_CONFIG_EXECUTABLE} --libs ${_cmp_req} ${_cmp_opt} FAILED with RET=${RET}")
+ endif()
+ unset(_cmp_req)
+ unset(_cmp_opt)
+ endif()
+
+ # When using wx-config in MSYS, the include paths are UNIX style paths which may or may
+ # not work correctly depending on you MSYS/MinGW configuration. CMake expects native
+ # paths internally.
+ if(wxWidgets_FOUND AND MSYS)
+ find_program(_cygpath_exe cygpath ONLY_CMAKE_FIND_ROOT_PATH)
+ DBG_MSG_V("_cygpath_exe: ${_cygpath_exe}")
+ if(_cygpath_exe)
+ set(_tmp_path "")
+ foreach(_path ${wxWidgets_INCLUDE_DIRS})
+ execute_process(
+ COMMAND cygpath -w ${_path}
+ OUTPUT_VARIABLE _native_path
+ RESULT_VARIABLE _retv
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET
+ )
+ if(_retv EQUAL 0)
+ file(TO_CMAKE_PATH ${_native_path} _native_path)
+ DBG_MSG_V("Path ${_path} converted to ${_native_path}")
+ string(APPEND _tmp_path " ${_native_path}")
+ endif()
+ endforeach()
+ DBG_MSG("Setting wxWidgets_INCLUDE_DIRS = ${_tmp_path}")
+ set(wxWidgets_INCLUDE_DIRS ${_tmp_path})
+ separate_arguments(wxWidgets_INCLUDE_DIRS)
+ list(REMOVE_ITEM wxWidgets_INCLUDE_DIRS "")
+
+ set(_tmp_path "")
+ foreach(_path ${wxWidgets_LIBRARY_DIRS})
+ execute_process(
+ COMMAND cygpath -w ${_path}
+ OUTPUT_VARIABLE _native_path
+ RESULT_VARIABLE _retv
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET
+ )
+ if(_retv EQUAL 0)
+ file(TO_CMAKE_PATH ${_native_path} _native_path)
+ DBG_MSG_V("Path ${_path} converted to ${_native_path}")
+ string(APPEND _tmp_path " ${_native_path}")
+ endif()
+ endforeach()
+ DBG_MSG("Setting wxWidgets_LIBRARY_DIRS = ${_tmp_path}")
+ set(wxWidgets_LIBRARY_DIRS ${_tmp_path})
+ separate_arguments(wxWidgets_LIBRARY_DIRS)
+ list(REMOVE_ITEM wxWidgets_LIBRARY_DIRS "")
+ endif()
+ unset(_cygpath_exe CACHE)
+ endif()
+
+#=====================================================================
+# Neither UNIX_FIND_STYLE, nor WIN32_FIND_STYLE
+#=====================================================================
+ else()
+ if(NOT wxWidgets_FIND_QUIETLY)
+ message(STATUS
+ "${CMAKE_CURRENT_LIST_FILE}(${CMAKE_CURRENT_LIST_LINE}): \n"
+ " Platform unknown/unsupported. It's neither WIN32 nor UNIX "
+ "find style."
+ )
+ endif()
+ endif()
+endif()
+
+# Check that all libraries are present, as wx-config does not check it
+set(_wx_lib_missing "")
+foreach(_wx_lib_ ${wxWidgets_LIBRARIES})
+ if("${_wx_lib_}" MATCHES "^-l(.*)")
+ set(_wx_lib_name "${CMAKE_MATCH_1}")
+ unset(_wx_lib_found CACHE)
+ find_library(_wx_lib_found NAMES ${_wx_lib_name} HINTS ${wxWidgets_LIBRARY_DIRS})
+ if(_wx_lib_found STREQUAL _wx_lib_found-NOTFOUND)
+ list(APPEND _wx_lib_missing ${_wx_lib_name})
+ endif()
+ unset(_wx_lib_found CACHE)
+ endif()
+endforeach()
+
+if (_wx_lib_missing)
+ string(REPLACE ";" " " _wx_lib_missing "${_wx_lib_missing}")
+ DBG_MSG_V("wxWidgets not found due to following missing libraries: ${_wx_lib_missing}")
+ set(wxWidgets_FOUND FALSE)
+ unset(wxWidgets_LIBRARIES)
+endif()
+unset(_wx_lib_missing)
+
+# Check if a specific version was requested by find_package().
+if(wxWidgets_FOUND)
+ unset(_wx_filename)
+ find_file(_wx_filename wx/version.h PATHS ${wxWidgets_INCLUDE_DIRS} NO_DEFAULT_PATH)
+ dbg_msg("_wx_filename: ${_wx_filename}")
+
+ if(NOT _wx_filename)
+ message(FATAL_ERROR "wxWidgets wx/version.h file not found in ${wxWidgets_INCLUDE_DIRS}.")
+ endif()
+
+ file(READ "${_wx_filename}" _wx_version_h)
+ unset(_wx_filename CACHE)
+
+ string(REGEX REPLACE "^(.*\n)?#define +wxMAJOR_VERSION +([0-9]+).*"
+ "\\2" wxWidgets_VERSION_MAJOR "${_wx_version_h}" )
+ string(REGEX REPLACE "^(.*\n)?#define +wxMINOR_VERSION +([0-9]+).*"
+ "\\2" wxWidgets_VERSION_MINOR "${_wx_version_h}" )
+ string(REGEX REPLACE "^(.*\n)?#define +wxRELEASE_NUMBER +([0-9]+).*"
+ "\\2" wxWidgets_VERSION_PATCH "${_wx_version_h}" )
+ set(wxWidgets_VERSION_STRING
+ "${wxWidgets_VERSION_MAJOR}.${wxWidgets_VERSION_MINOR}.${wxWidgets_VERSION_PATCH}" )
+ dbg_msg("wxWidgets_VERSION_STRING: ${wxWidgets_VERSION_STRING}")
+endif()
+
+# Debug output:
+DBG_MSG("wxWidgets_FOUND : ${wxWidgets_FOUND}")
+DBG_MSG("wxWidgets_INCLUDE_DIRS : ${wxWidgets_INCLUDE_DIRS}")
+DBG_MSG("wxWidgets_LIBRARY_DIRS : ${wxWidgets_LIBRARY_DIRS}")
+DBG_MSG("wxWidgets_LIBRARIES : ${wxWidgets_LIBRARIES}")
+DBG_MSG("wxWidgets_CXX_FLAGS : ${wxWidgets_CXX_FLAGS}")
+DBG_MSG("wxWidgets_USE_FILE : ${wxWidgets_USE_FILE}")
+
+#=====================================================================
+#=====================================================================
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+# FIXME: set wxWidgets_<comp>_FOUND for wx-config branch
+# and use HANDLE_COMPONENTS on Unix too
+if(wxWidgets_FIND_STYLE STREQUAL "win32")
+ set(wxWidgets_HANDLE_COMPONENTS "HANDLE_COMPONENTS")
+endif()
+
+find_package_handle_standard_args(wxWidgets
+ REQUIRED_VARS wxWidgets_LIBRARIES wxWidgets_INCLUDE_DIRS
+ VERSION_VAR wxWidgets_VERSION_STRING
+ ${wxWidgets_HANDLE_COMPONENTS}
+ )
+unset(wxWidgets_HANDLE_COMPONENTS)
+
+#=====================================================================
+# Macros for use in wxWidgets apps.
+# - This module will not fail to find wxWidgets based on the code
+# below. Hence, it's required to check for validity of:
+#
+# wxWidgets_wxrc_EXECUTABLE
+#=====================================================================
+
+# Resource file compiler.
+find_program(wxWidgets_wxrc_EXECUTABLE
+ NAMES $ENV{WXRC_CMD} wxrc
+ PATHS ${wxWidgets_ROOT_DIR}/utils/wxrc/vc_msw
+ DOC "Location of wxWidgets resource file compiler binary (wxrc)"
+ )
+
+#
+# WX_SPLIT_ARGUMENTS_ON(<keyword> <left> <right> <arg1> <arg2> ...)
+#
+# Sets <left> and <right> to contain arguments to the left and right,
+# respectively, of <keyword>.
+#
+# Example usage:
+# function(WXWIDGETS_ADD_RESOURCES outfiles)
+# WX_SPLIT_ARGUMENTS_ON(OPTIONS wxrc_files wxrc_options ${ARGN})
+# ...
+# endfunction()
+#
+# WXWIDGETS_ADD_RESOURCES(sources ${xrc_files} OPTIONS -e -o file.C)
+#
+# NOTE: This is a generic piece of code that should be renamed to
+# SPLIT_ARGUMENTS_ON and put in a file serving the same purpose as
+# FindPackageStandardArgs.cmake. At the time of this writing
+# FindQt4.cmake has a QT4_EXTRACT_OPTIONS, which I basically copied
+# here a bit more generalized. So, there are already two find modules
+# using this approach.
+#
+function(WX_SPLIT_ARGUMENTS_ON _keyword _leftvar _rightvar)
+ # FIXME: Document that the input variables will be cleared.
+ #list(APPEND ${_leftvar} "")
+ #list(APPEND ${_rightvar} "")
+ set(${_leftvar} "")
+ set(${_rightvar} "")
+
+ set(_doing_right FALSE)
+ foreach(element ${ARGN})
+ if("${element}" STREQUAL "${_keyword}")
+ set(_doing_right TRUE)
+ else()
+ if(_doing_right)
+ list(APPEND ${_rightvar} "${element}")
+ else()
+ list(APPEND ${_leftvar} "${element}")
+ endif()
+ endif()
+ endforeach()
+
+ set(${_leftvar} ${${_leftvar}} PARENT_SCOPE)
+ set(${_rightvar} ${${_rightvar}} PARENT_SCOPE)
+endfunction()
+
+#
+# WX_GET_DEPENDENCIES_FROM_XML(
+# <depends>
+# <match_pattern>
+# <clean_pattern>
+# <xml_contents>
+# <depends_path>
+# )
+#
+# FIXME: Add documentation here...
+#
+function(WX_GET_DEPENDENCIES_FROM_XML
+ _depends
+ _match_patt
+ _clean_patt
+ _xml_contents
+ _depends_path
+ )
+
+ string(REGEX MATCHALL
+ ${_match_patt}
+ dep_file_list
+ "${${_xml_contents}}"
+ )
+ foreach(dep_file ${dep_file_list})
+ string(REGEX REPLACE ${_clean_patt} "" dep_file "${dep_file}")
+
+ # make the file have an absolute path
+ if(NOT IS_ABSOLUTE "${dep_file}")
+ set(dep_file "${${_depends_path}}/${dep_file}")
+ endif()
+
+ # append file to dependency list
+ list(APPEND ${_depends} "${dep_file}")
+ endforeach()
+
+ set(${_depends} ${${_depends}} PARENT_SCOPE)
+endfunction()
+
+#
+# WXWIDGETS_ADD_RESOURCES(<sources> <xrc_files>
+# OPTIONS <options> [NO_CPP_CODE])
+#
+# Adds a custom command for resource file compilation of the
+# <xrc_files> and appends the output files to <sources>.
+#
+# Example usages:
+# WXWIDGETS_ADD_RESOURCES(sources xrc/main_frame.xrc)
+# WXWIDGETS_ADD_RESOURCES(sources ${xrc_files} OPTIONS -e -o altname.cxx)
+#
+function(WXWIDGETS_ADD_RESOURCES _outfiles)
+ WX_SPLIT_ARGUMENTS_ON(OPTIONS rc_file_list rc_options ${ARGN})
+
+ # Parse files for dependencies.
+ set(rc_file_list_abs "")
+ set(rc_depends "")
+ foreach(rc_file ${rc_file_list})
+ get_filename_component(depends_path ${rc_file} PATH)
+
+ get_filename_component(rc_file_abs ${rc_file} ABSOLUTE)
+ list(APPEND rc_file_list_abs "${rc_file_abs}")
+
+ # All files have absolute paths or paths relative to the location
+ # of the rc file.
+ file(READ "${rc_file_abs}" rc_file_contents)
+
+ # get bitmap/bitmap2 files
+ WX_GET_DEPENDENCIES_FROM_XML(
+ rc_depends
+ "<bitmap[^<]+"
+ "^<bitmap[^>]*>"
+ rc_file_contents
+ depends_path
+ )
+
+ # get url files
+ WX_GET_DEPENDENCIES_FROM_XML(
+ rc_depends
+ "<url[^<]+"
+ "^<url[^>]*>"
+ rc_file_contents
+ depends_path
+ )
+
+ # get wxIcon files
+ WX_GET_DEPENDENCIES_FROM_XML(
+ rc_depends
+ "<object[^>]*class=\"wxIcon\"[^<]+"
+ "^<object[^>]*>"
+ rc_file_contents
+ depends_path
+ )
+ endforeach()
+
+ #
+ # Parse options.
+ #
+ # If NO_CPP_CODE option specified, then produce .xrs file rather
+ # than a .cpp file (i.e., don't add the default --cpp-code option).
+ list(FIND rc_options NO_CPP_CODE index)
+ if(index EQUAL -1)
+ list(APPEND rc_options --cpp-code)
+ # wxrc's default output filename for cpp code.
+ set(outfile resource.cpp)
+ else()
+ list(REMOVE_AT rc_options ${index})
+ # wxrc's default output filename for xrs file.
+ set(outfile resource.xrs)
+ endif()
+
+ # Get output name for use in ADD_CUSTOM_COMMAND.
+ # - short option scanning
+ list(FIND rc_options -o index)
+ if(NOT index EQUAL -1)
+ math(EXPR filename_index "${index} + 1")
+ list(GET rc_options ${filename_index} outfile)
+ #list(REMOVE_AT rc_options ${index} ${filename_index})
+ endif()
+ # - long option scanning
+ string(REGEX MATCH "--output=[^;]*" outfile_opt "${rc_options}")
+ if(outfile_opt)
+ string(REPLACE "--output=" "" outfile "${outfile_opt}")
+ endif()
+ #string(REGEX REPLACE "--output=[^;]*;?" "" rc_options "${rc_options}")
+ #string(REGEX REPLACE ";$" "" rc_options "${rc_options}")
+
+ if(NOT IS_ABSOLUTE "${outfile}")
+ set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${outfile}")
+ endif()
+ add_custom_command(
+ OUTPUT "${outfile}"
+ COMMAND ${wxWidgets_wxrc_EXECUTABLE} ${rc_options} ${rc_file_list_abs}
+ DEPENDS ${rc_file_list_abs} ${rc_depends}
+ )
+
+ # Add generated header to output file list.
+ list(FIND rc_options -e short_index)
+ list(FIND rc_options --extra-cpp-code long_index)
+ if(NOT short_index EQUAL -1 OR NOT long_index EQUAL -1)
+ get_filename_component(outfile_ext ${outfile} EXT)
+ string(REPLACE "${outfile_ext}" ".h" outfile_header "${outfile}")
+ list(APPEND ${_outfiles} "${outfile_header}")
+ set_source_files_properties(
+ "${outfile_header}" PROPERTIES GENERATED TRUE
+ )
+ endif()
+
+ # Add generated file to output file list.
+ list(APPEND ${_outfiles} "${outfile}")
+
+ set(${_outfiles} ${${_outfiles}} PARENT_SCOPE)
+endfunction()
diff --git a/Modules/FindwxWindows.cmake b/Modules/FindwxWindows.cmake
new file mode 100644
index 0000000..07fbc1b
--- /dev/null
+++ b/Modules/FindwxWindows.cmake
@@ -0,0 +1,730 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindwxWindows
+-------------
+
+.. deprecated:: 3.0
+
+ Replaced by :module:`FindwxWidgets`.
+
+Find wxWindows (wxWidgets) installation
+
+This module finds if wxWindows/wxWidgets is installed and determines
+where the include files and libraries are. It also determines what
+the name of the library is. This code sets the following variables:
+
+::
+
+ WXWINDOWS_FOUND = system has WxWindows
+ WXWINDOWS_LIBRARIES = path to the wxWindows libraries
+ on Unix/Linux with additional
+ linker flags from
+ "wx-config --libs"
+ CMAKE_WXWINDOWS_CXX_FLAGS = Compiler flags for wxWindows,
+ essentially "`wx-config --cxxflags`"
+ on Linux
+ WXWINDOWS_INCLUDE_DIR = where to find "wx/wx.h" and "wx/setup.h"
+ WXWINDOWS_LINK_DIRECTORIES = link directories, useful for rpath on
+ Unix
+ WXWINDOWS_DEFINITIONS = extra defines
+
+
+
+OPTIONS If you need OpenGL support please
+
+::
+
+ set(WXWINDOWS_USE_GL 1)
+
+in your CMakeLists.txt *before* you include this file.
+
+::
+
+ HAVE_ISYSTEM - true required to replace -I by -isystem on g++
+
+
+
+For convenience include Use_wxWindows.cmake in your project's
+CMakeLists.txt using
+include(${CMAKE_CURRENT_LIST_DIR}/Use_wxWindows.cmake).
+
+USAGE
+
+::
+
+ set(WXWINDOWS_USE_GL 1)
+ find_package(wxWindows)
+
+
+
+NOTES wxWidgets 2.6.x is supported for monolithic builds e.g.
+compiled in wx/build/msw dir as:
+
+::
+
+ nmake -f makefile.vc BUILD=debug SHARED=0 USE_OPENGL=1 MONOLITHIC=1
+
+
+
+DEPRECATED
+
+::
+
+ CMAKE_WX_CAN_COMPILE
+ WXWINDOWS_LIBRARY
+ CMAKE_WX_CXX_FLAGS
+ WXWINDOWS_INCLUDE_PATH
+
+
+
+AUTHOR Jan Woetzel <http://www.mip.informatik.uni-kiel.de/~jw>
+(07/2003-01/2006)
+#]=======================================================================]
+
+# ------------------------------------------------------------------
+#
+# -removed OPTION for CMAKE_WXWINDOWS_USE_GL. Force the developer to SET it before calling this.
+# -major update for wx 2.6.2 and monolithic build option. (10/2005)
+#
+# STATUS
+# tested with:
+# cmake 1.6.7, Linux (Suse 7.3), wxWindows 2.4.0, gcc 2.95
+# cmake 1.6.7, Linux (Suse 8.2), wxWindows 2.4.0, gcc 3.3
+# cmake 1.6.7, Linux (Suse 8.2), wxWindows 2.4.1-patch1, gcc 3.3
+# cmake 1.6.7, MS Windows XP home, wxWindows 2.4.1, MS Visual Studio .net 7 2002 (static build)
+# cmake 2.0.5 on Windows XP and Suse Linux 9.2
+# cmake 2.0.6 on Windows XP and Suse Linux 9.2, wxWidgets 2.6.2 MONOLITHIC build
+# cmake 2.2.2 on Windows XP, MS Visual Studio .net 2003 7.1 wxWidgets 2.6.2 MONOLITHIC build
+#
+# TODO
+# -OPTION for unicode builds
+# -further testing of DLL linking under MS WIN32
+# -better support for non-monolithic builds
+#
+
+
+if(WIN32)
+ set(WIN32_STYLE_FIND 1)
+endif()
+if(MINGW)
+ set(WIN32_STYLE_FIND 0)
+ set(UNIX_STYLE_FIND 1)
+endif()
+if(UNIX)
+ set(UNIX_STYLE_FIND 1)
+endif()
+
+
+if(WIN32_STYLE_FIND)
+
+ ## ######################################################################
+ ##
+ ## Windows specific:
+ ##
+ ## candidates for root/base directory of wxwindows
+ ## should have subdirs include and lib containing include/wx/wx.h
+ ## fix the root dir to avoid mixing of headers/libs from different
+ ## versions/builds:
+
+ ## WX supports monolithic and multiple smaller libs (since 2.5.x), we prefer monolithic for now.
+ ## monolithic = WX is built as a single big library
+ ## e.g. compile on WIN32 as "nmake -f makefile.vc MONOLITHIC=1 BUILD=debug SHARED=0 USE_OPENGL=1" (JW)
+ option(WXWINDOWS_USE_MONOLITHIC "Use monolithic build of WX??" ON)
+ mark_as_advanced(WXWINDOWS_USE_MONOLITHIC)
+
+ ## GL libs used?
+ option(WXWINDOWS_USE_GL "Use Wx with GL support(glcanvas)?" ON)
+ mark_as_advanced(WXWINDOWS_USE_GL)
+
+
+ ## avoid mixing of headers and libs between multiple installed WX versions,
+ ## select just one tree here:
+ find_path(WXWINDOWS_ROOT_DIR include/wx/wx.h
+ HINTS
+ ENV WXWIN
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\wxWidgets_is1;Inno Setup: App Path]" ## WX 2.6.x
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\wxWindows_is1;Inno Setup: App Path]" ## WX 2.4.x
+ PATHS
+ C:/wxWidgets-2.6.2
+ D:/wxWidgets-2.6.2
+ C:/wxWidgets-2.6.1
+ D:/wxWidgets-2.6.1
+ C:/wxWindows-2.4.2
+ D:/wxWindows-2.4.2
+ )
+ # message("DBG found WXWINDOWS_ROOT_DIR: ${WXWINDOWS_ROOT_DIR}")
+
+
+ ## find libs for combination of static/shared with release/debug
+ ## be careful if you add something here,
+ ## avoid mixing of headers and libs of different wx versions,
+ ## there may be multiple WX versions installed.
+ set (WXWINDOWS_POSSIBLE_LIB_PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib"
+ )
+
+ ## monolithic?
+ if (WXWINDOWS_USE_MONOLITHIC)
+
+ find_library(WXWINDOWS_STATIC_LIBRARY
+ NAMES wx wxmsw wxmsw26
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_lib"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows static release build library" )
+
+ find_library(WXWINDOWS_STATIC_DEBUG_LIBRARY
+ NAMES wxd wxmswd wxmsw26d
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_lib"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows static debug build library" )
+
+ find_library(WXWINDOWS_SHARED_LIBRARY
+ NAMES wxmsw26 wxmsw262 wxmsw24 wxmsw242 wxmsw241 wxmsw240 wx23_2 wx22_9
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_dll"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows shared release build library" )
+
+ find_library(WXWINDOWS_SHARED_DEBUG_LIBRARY
+ NAMES wxmsw26d wxmsw262d wxmsw24d wxmsw241d wxmsw240d wx23_2d wx22_9d
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_dll"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows shared debug build library " )
+
+
+ ##
+ ## required for WXWINDOWS_USE_GL
+ ## gl lib is always build separate:
+ ##
+ find_library(WXWINDOWS_STATIC_LIBRARY_GL
+ NAMES wx_gl wxmsw_gl wxmsw26_gl
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_lib"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows static release build GL library" )
+
+ find_library(WXWINDOWS_STATIC_DEBUG_LIBRARY_GL
+ NAMES wxd_gl wxmswd_gl wxmsw26d_gl
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_lib"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows static debug build GL library" )
+
+
+ find_library(WXWINDOWS_STATIC_DEBUG_LIBRARY_PNG
+ NAMES wxpngd
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_lib"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows static debug png library" )
+
+ find_library(WXWINDOWS_STATIC_LIBRARY_PNG
+ NAMES wxpng
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_lib"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows static png library" )
+
+ find_library(WXWINDOWS_STATIC_DEBUG_LIBRARY_TIFF
+ NAMES wxtiffd
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_lib"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows static debug tiff library" )
+
+ find_library(WXWINDOWS_STATIC_LIBRARY_TIFF
+ NAMES wxtiff
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_lib"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows static tiff library" )
+
+ find_library(WXWINDOWS_STATIC_DEBUG_LIBRARY_JPEG
+ NAMES wxjpegd wxjpgd
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_lib"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows static debug jpeg library" )
+
+ find_library(WXWINDOWS_STATIC_LIBRARY_JPEG
+ NAMES wxjpeg wxjpg
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_lib"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows static jpeg library" )
+
+ find_library(WXWINDOWS_STATIC_DEBUG_LIBRARY_ZLIB
+ NAMES wxzlibd
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_lib"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows static debug zlib library" )
+
+ find_library(WXWINDOWS_STATIC_LIBRARY_ZLIB
+ NAMES wxzlib
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_lib"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows static zib library" )
+
+ find_library(WXWINDOWS_STATIC_DEBUG_LIBRARY_REGEX
+ NAMES wxregexd
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_lib"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows static debug regex library" )
+
+ find_library(WXWINDOWS_STATIC_LIBRARY_REGEX
+ NAMES wxregex
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_lib"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows static regex library" )
+
+
+
+ ## untested:
+ find_library(WXWINDOWS_SHARED_LIBRARY_GL
+ NAMES wx_gl wxmsw_gl wxmsw26_gl
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_dll"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows shared release build GL library" )
+
+ find_library(WXWINDOWS_SHARED_DEBUG_LIBRARY_GL
+ NAMES wxd_gl wxmswd_gl wxmsw26d_gl
+ PATHS
+ "${WXWINDOWS_ROOT_DIR}/lib/vc_dll"
+ ${WXWINDOWS_POSSIBLE_LIB_PATHS}
+ DOC "wxWindows shared debug build GL library" )
+
+
+ else ()
+ ## WX is built as multiple small pieces libraries instead of monolithic
+
+ ## DEPRECATED (jw) replaced by more general WXWINDOWS_USE_MONOLITHIC ON/OFF
+ # option(WXWINDOWS_SEPARATE_LIBS_BUILD "Is wxWindows build with separate libs?" OFF)
+
+ ## HACK: This is very dirty.
+ ## because the libs of a particular version are explicitly listed
+ ## and NOT searched/verified.
+ ## TODO: Really search for each lib, then decide for
+ ## monolithic x debug x shared x GL (=16 combinations) for at least 18 libs
+ ## --> about 288 combinations
+ ## thus we need a different approach so solve this correctly ...
+
+ message(STATUS "Warning: You are trying to use wxWidgets without monolithic build (WXWINDOWS_SEPARATE_LIBS_BUILD). This is a HACK, libraries are not verified! (JW).")
+
+ set(WXWINDOWS_STATIC_LIBS ${WXWINDOWS_STATIC_LIBS}
+ wxbase26
+ wxbase26_net
+ wxbase26_odbc
+ wxbase26_xml
+ wxmsw26_adv
+ wxmsw26_core
+ wxmsw26_dbgrid
+ wxmsw26_gl
+ wxmsw26_html
+ wxmsw26_media
+ wxmsw26_qa
+ wxmsw26_xrc
+ wxexpat
+ wxjpeg
+ wxpng
+ wxregex
+ wxtiff
+ wxzlib
+ comctl32
+ rpcrt4
+ wsock32
+ )
+ ## HACK: feed in to optimized / debug libraries if both were FOUND.
+ set(WXWINDOWS_STATIC_DEBUG_LIBS ${WXWINDOWS_STATIC_DEBUG_LIBS}
+ wxbase26d
+ wxbase26d_net
+ wxbase26d_odbc
+ wxbase26d_xml
+ wxmsw26d_adv
+ wxmsw26d_core
+ wxmsw26d_dbgrid
+ wxmsw26d_gl
+ wxmsw26d_html
+ wxmsw26d_media
+ wxmsw26d_qa
+ wxmsw26d_xrc
+ wxexpatd
+ wxjpegd
+ wxpngd
+ wxregexd
+ wxtiffd
+ wxzlibd
+ comctl32
+ rpcrt4
+ wsock32
+ )
+ endif ()
+
+
+ ##
+ ## now we should have found all WX libs available on the system.
+ ## let the user decide which of the available onse to use.
+ ##
+
+ ## if there is at least one shared lib available
+ ## let user choose whether to use shared or static wxwindows libs
+ if(WXWINDOWS_SHARED_LIBRARY OR WXWINDOWS_SHARED_DEBUG_LIBRARY)
+ ## default value OFF because wxWindows MSVS default build is static
+ option(WXWINDOWS_USE_SHARED_LIBS
+ "Use shared versions (dll) of wxWindows libraries?" OFF)
+ mark_as_advanced(WXWINDOWS_USE_SHARED_LIBS)
+ endif()
+
+ ## add system libraries wxwindows always seems to depend on
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ comctl32
+ rpcrt4
+ wsock32
+ )
+
+ if (NOT WXWINDOWS_USE_SHARED_LIBS)
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ ## these ones don't seem required, in particular ctl3d32 is not necessary (Jan Woetzel 07/2003)
+ # ctl3d32
+ debug ${WXWINDOWS_STATIC_DEBUG_LIBRARY_ZLIB} optimized ${WXWINDOWS_STATIC_LIBRARY_ZLIB}
+ debug ${WXWINDOWS_STATIC_DEBUG_LIBRARY_REGEX} optimized ${WXWINDOWS_STATIC_LIBRARY_REGEX}
+ debug ${WXWINDOWS_STATIC_DEBUG_LIBRARY_PNG} optimized ${WXWINDOWS_STATIC_LIBRARY_PNG}
+ debug ${WXWINDOWS_STATIC_DEBUG_LIBRARY_JPEG} optimized ${WXWINDOWS_STATIC_LIBRARY_JPEG}
+ debug ${WXWINDOWS_STATIC_DEBUG_LIBRARY_TIFF} optimized ${WXWINDOWS_STATIC_LIBRARY_TIFF}
+ )
+ endif ()
+
+ ## opengl/glu: TODO/FIXME: better use FindOpenGL.cmake here
+ ## assume release versions of glu an dopengl, here.
+ if (WXWINDOWS_USE_GL)
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ opengl32
+ glu32 )
+ endif ()
+
+ ##
+ ## select between use of shared or static wxWindows lib then set libs to use
+ ## for debug and optimized build. so the user can switch between debug and
+ ## release build e.g. within MS Visual Studio without running cmake with a
+ ## different build directory again.
+ ##
+ ## then add the build specific include dir for wx/setup.h
+ ##
+
+ if(WXWINDOWS_USE_SHARED_LIBS)
+ ##message("DBG wxWindows use shared lib selected.")
+ ## assume that both builds use the same setup(.h) for simplicity
+
+ ## shared: both wx (debug and release) found?
+ ## assume that both builds use the same setup(.h) for simplicity
+ if(WXWINDOWS_SHARED_DEBUG_LIBRARY AND WXWINDOWS_SHARED_LIBRARY)
+ ##message("DBG wx shared: debug and optimized found.")
+ find_path(WXWINDOWS_INCLUDE_DIR_SETUPH wx/setup.h
+ ${WXWINDOWS_ROOT_DIR}/lib/mswdlld
+ ${WXWINDOWS_ROOT_DIR}/lib/mswdll
+ ${WXWINDOWS_ROOT_DIR}/lib/vc_dll/mswd
+ ${WXWINDOWS_ROOT_DIR}/lib/vc_dll/msw )
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ debug ${WXWINDOWS_SHARED_DEBUG_LIBRARY}
+ optimized ${WXWINDOWS_SHARED_LIBRARY} )
+ if (WXWINDOWS_USE_GL)
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ debug ${WXWINDOWS_SHARED_DEBUG_LIBRARY_GL}
+ optimized ${WXWINDOWS_SHARED_LIBRARY_GL} )
+ endif ()
+ endif()
+
+ ## shared: only debug wx lib found?
+ if(WXWINDOWS_SHARED_DEBUG_LIBRARY)
+ if(NOT WXWINDOWS_SHARED_LIBRARY)
+ ##message("DBG wx shared: debug (but no optimized) found.")
+ find_path(WXWINDOWS_INCLUDE_DIR_SETUPH wx/setup.h
+ ${WXWINDOWS_ROOT_DIR}/lib/mswdlld
+ ${WXWINDOWS_ROOT_DIR}/lib/vc_dll/mswd )
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ ${WXWINDOWS_SHARED_DEBUG_LIBRARY} )
+ if (WXWINDOWS_USE_GL)
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ ${WXWINDOWS_SHARED_DEBUG_LIBRARY_GL} )
+ endif ()
+ endif()
+ endif()
+
+ ## shared: only release wx lib found?
+ if(NOT WXWINDOWS_SHARED_DEBUG_LIBRARY)
+ if(WXWINDOWS_SHARED_LIBRARY)
+ ##message("DBG wx shared: optimized (but no debug) found.")
+ find_path(WXWINDOWS_INCLUDE_DIR_SETUPH wx/setup.h
+ ${WXWINDOWS_ROOT_DIR}/lib/mswdll
+ ${WXWINDOWS_ROOT_DIR}/lib/vc_dll/msw )
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ ${WXWINDOWS_SHARED_DEBUG_LIBRARY} )
+ if (WXWINDOWS_USE_GL)
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ ${WXWINDOWS_SHARED_DEBUG_LIBRARY_GL} )
+ endif ()
+ endif()
+ endif()
+
+ ## shared: none found?
+ if(NOT WXWINDOWS_SHARED_DEBUG_LIBRARY)
+ if(NOT WXWINDOWS_SHARED_LIBRARY)
+ message(STATUS
+ "No shared wxWindows lib found, but WXWINDOWS_USE_SHARED_LIBS=${WXWINDOWS_USE_SHARED_LIBS}.")
+ endif()
+ endif()
+
+ #########################################################################################
+ else()
+
+ ##jw: DEPRECATED if(NOT WXWINDOWS_SEPARATE_LIBS_BUILD)
+
+ ## static: both wx (debug and release) found?
+ ## assume that both builds use the same setup(.h) for simplicity
+ if(WXWINDOWS_STATIC_DEBUG_LIBRARY AND WXWINDOWS_STATIC_LIBRARY)
+ ##message("DBG wx static: debug and optimized found.")
+ find_path(WXWINDOWS_INCLUDE_DIR_SETUPH wx/setup.h
+ ${WXWINDOWS_ROOT_DIR}/lib/mswd
+ ${WXWINDOWS_ROOT_DIR}/lib/msw
+ ${WXWINDOWS_ROOT_DIR}/lib/vc_lib/mswd
+ ${WXWINDOWS_ROOT_DIR}/lib/vc_lib/msw )
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ debug ${WXWINDOWS_STATIC_DEBUG_LIBRARY}
+ optimized ${WXWINDOWS_STATIC_LIBRARY} )
+ if (WXWINDOWS_USE_GL)
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ debug ${WXWINDOWS_STATIC_DEBUG_LIBRARY_GL}
+ optimized ${WXWINDOWS_STATIC_LIBRARY_GL} )
+ endif ()
+ endif()
+
+ ## static: only debug wx lib found?
+ if(WXWINDOWS_STATIC_DEBUG_LIBRARY)
+ if(NOT WXWINDOWS_STATIC_LIBRARY)
+ ##message("DBG wx static: debug (but no optimized) found.")
+ find_path(WXWINDOWS_INCLUDE_DIR_SETUPH wx/setup.h
+ ${WXWINDOWS_ROOT_DIR}/lib/mswd
+ ${WXWINDOWS_ROOT_DIR}/lib/vc_lib/mswd )
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ ${WXWINDOWS_STATIC_DEBUG_LIBRARY} )
+ if (WXWINDOWS_USE_GL)
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ ${WXWINDOWS_STATIC_DEBUG_LIBRARY_GL} )
+ endif ()
+ endif()
+ endif()
+
+ ## static: only release wx lib found?
+ if(NOT WXWINDOWS_STATIC_DEBUG_LIBRARY)
+ if(WXWINDOWS_STATIC_LIBRARY)
+ ##message("DBG wx static: optimized (but no debug) found.")
+ find_path(WXWINDOWS_INCLUDE_DIR_SETUPH wx/setup.h
+ ${WXWINDOWS_ROOT_DIR}/lib/msw
+ ${WXWINDOWS_ROOT_DIR}/lib/vc_lib/msw )
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ ${WXWINDOWS_STATIC_LIBRARY} )
+ if (WXWINDOWS_USE_GL)
+ set(WXWINDOWS_LIBRARIES ${WXWINDOWS_LIBRARIES}
+ ${WXWINDOWS_STATIC_LIBRARY_GL} )
+ endif ()
+ endif()
+ endif()
+
+ ## static: none found?
+ if(NOT WXWINDOWS_STATIC_DEBUG_LIBRARY AND NOT WXWINDOWS_SEPARATE_LIBS_BUILD)
+ if(NOT WXWINDOWS_STATIC_LIBRARY)
+ message(STATUS
+ "No static wxWindows lib found, but WXWINDOWS_USE_SHARED_LIBS=${WXWINDOWS_USE_SHARED_LIBS}.")
+ endif()
+ endif()
+ endif()
+
+
+ ## not necessary in wxWindows 2.4.1 and 2.6.2
+ ## but it may fix a previous bug, see
+ ## http://lists.wxwindows.org/cgi-bin/ezmlm-cgi?8:mss:37574:200305:mpdioeneabobmgjenoap
+ option(WXWINDOWS_SET_DEFINITIONS "Set additional defines for wxWindows" OFF)
+ mark_as_advanced(WXWINDOWS_SET_DEFINITIONS)
+ if (WXWINDOWS_SET_DEFINITIONS)
+ set(WXWINDOWS_DEFINITIONS "-DWINVER=0x400")
+ else ()
+ # clear:
+ set(WXWINDOWS_DEFINITIONS "")
+ endif ()
+
+
+
+ ## Find the include directories for wxwindows
+ ## the first, build specific for wx/setup.h was determined before.
+ ## add inc dir for general for "wx/wx.h"
+ find_path(WXWINDOWS_INCLUDE_DIR wx/wx.h
+ "${WXWINDOWS_ROOT_DIR}/include" )
+ ## append the build specific include dir for wx/setup.h:
+ if (WXWINDOWS_INCLUDE_DIR_SETUPH)
+ set(WXWINDOWS_INCLUDE_DIR ${WXWINDOWS_INCLUDE_DIR} ${WXWINDOWS_INCLUDE_DIR_SETUPH} )
+ endif ()
+
+
+
+ mark_as_advanced(
+ WXWINDOWS_ROOT_DIR
+ WXWINDOWS_INCLUDE_DIR
+ WXWINDOWS_INCLUDE_DIR_SETUPH
+ WXWINDOWS_STATIC_LIBRARY
+ WXWINDOWS_STATIC_LIBRARY_GL
+ WXWINDOWS_STATIC_DEBUG_LIBRARY
+ WXWINDOWS_STATIC_DEBUG_LIBRARY_GL
+ WXWINDOWS_STATIC_LIBRARY_ZLIB
+ WXWINDOWS_STATIC_DEBUG_LIBRARY_ZLIB
+ WXWINDOWS_STATIC_LIBRARY_REGEX
+ WXWINDOWS_STATIC_DEBUG_LIBRARY_REGEX
+ WXWINDOWS_STATIC_LIBRARY_PNG
+ WXWINDOWS_STATIC_DEBUG_LIBRARY_PNG
+ WXWINDOWS_STATIC_LIBRARY_JPEG
+ WXWINDOWS_STATIC_DEBUG_LIBRARY_JPEG
+ WXWINDOWS_STATIC_DEBUG_LIBRARY_TIFF
+ WXWINDOWS_STATIC_LIBRARY_TIFF
+ WXWINDOWS_SHARED_LIBRARY
+ WXWINDOWS_SHARED_DEBUG_LIBRARY
+ WXWINDOWS_SHARED_LIBRARY_GL
+ WXWINDOWS_SHARED_DEBUG_LIBRARY_GL
+ )
+
+
+else()
+
+ if (UNIX_STYLE_FIND)
+ ## ######################################################################
+ ##
+ ## UNIX/Linux specific:
+ ##
+ ## use backquoted wx-config to query and set flags and libs:
+ ## 06/2003 Jan Woetzel
+ ##
+
+ option(WXWINDOWS_USE_SHARED_LIBS "Use shared versions (.so) of wxWindows libraries" ON)
+ mark_as_advanced(WXWINDOWS_USE_SHARED_LIBS)
+
+ # JW removed option and force the develper th SET it.
+ # option(WXWINDOWS_USE_GL "use wxWindows with GL support (use additional
+ # --gl-libs for wx-config)?" OFF)
+
+ # wx-config should be in your path anyhow, usually no need to set WXWIN or
+ # search in ../wx or ../../wx
+ find_program(CMAKE_WXWINDOWS_WXCONFIG_EXECUTABLE
+ NAMES $ENV{WX_CONFIG} wx-config
+ HINTS
+ ENV WXWIN
+ $ENV{WXWIN}/bin
+ PATHS
+ ../wx/bin
+ ../../wx/bin )
+
+ # check whether wx-config was found:
+ if(CMAKE_WXWINDOWS_WXCONFIG_EXECUTABLE)
+
+ # use shared/static wx lib?
+ # remember: always link shared to use systems GL etc. libs (no static
+ # linking, just link *against* static .a libs)
+ if(WXWINDOWS_USE_SHARED_LIBS)
+ set(WX_CONFIG_ARGS_LIBS "--libs")
+ else()
+ set(WX_CONFIG_ARGS_LIBS "--static --libs")
+ endif()
+
+ # do we need additionial wx GL stuff like GLCanvas ?
+ if(WXWINDOWS_USE_GL)
+ string(APPEND WX_CONFIG_ARGS_LIBS " --gl-libs" )
+ endif()
+ ##message("DBG: WX_CONFIG_ARGS_LIBS=${WX_CONFIG_ARGS_LIBS}===")
+
+ # set CXXFLAGS to be fed into CMAKE_CXX_FLAGS by the user:
+ if (HAVE_ISYSTEM) # does the compiler support -isystem ?
+ if (NOT APPLE) # -isystem seem sto be unsuppored on Mac
+ if(CMAKE_COMPILER_IS_GNUCC AND CMAKE_COMPILER_IS_GNUCXX )
+ if (CMAKE_CXX_COMPILER MATCHES g\\+\\+)
+ set(CMAKE_WXWINDOWS_CXX_FLAGS "`${CMAKE_WXWINDOWS_WXCONFIG_EXECUTABLE} --cxxflags|sed -e s/-I/-isystem/g`")
+ else()
+ set(CMAKE_WXWINDOWS_CXX_FLAGS "`${CMAKE_WXWINDOWS_WXCONFIG_EXECUTABLE} --cxxflags`")
+ endif()
+ endif()
+ endif ()
+ endif ()
+ ##message("DBG: for compilation:
+ ##CMAKE_WXWINDOWS_CXX_FLAGS=${CMAKE_WXWINDOWS_CXX_FLAGS}===")
+
+ # keep the back-quoted string for clarity
+ set(WXWINDOWS_LIBRARIES "`${CMAKE_WXWINDOWS_WXCONFIG_EXECUTABLE} ${WX_CONFIG_ARGS_LIBS}`")
+ ##message("DBG2: for linking:
+ ##WXWINDOWS_LIBRARIES=${WXWINDOWS_LIBRARIES}===")
+
+ # evaluate wx-config output to separate linker flags and linkdirs for
+ # rpath:
+ exec_program(${CMAKE_WXWINDOWS_WXCONFIG_EXECUTABLE}
+ ARGS ${WX_CONFIG_ARGS_LIBS}
+ OUTPUT_VARIABLE WX_CONFIG_LIBS )
+
+ ## extract linkdirs (-L) for rpath
+ ## use regular expression to match wildcard equivalent "-L*<endchar>"
+ ## with <endchar> is a space or a semicolon
+ string(REGEX MATCHALL "[-][L]([^ ;])+" WXWINDOWS_LINK_DIRECTORIES_WITH_PREFIX "${WX_CONFIG_LIBS}" )
+ # message("DBG WXWINDOWS_LINK_DIRECTORIES_WITH_PREFIX=${WXWINDOWS_LINK_DIRECTORIES_WITH_PREFIX}")
+
+ ## remove prefix -L because we need the pure directory for LINK_DIRECTORIES
+ ## replace -L by ; because the separator seems to be lost otherwise (bug or
+ ## feature?)
+ if(WXWINDOWS_LINK_DIRECTORIES_WITH_PREFIX)
+ string(REGEX REPLACE "[-][L]" ";" WXWINDOWS_LINK_DIRECTORIES ${WXWINDOWS_LINK_DIRECTORIES_WITH_PREFIX} )
+ # message("DBG WXWINDOWS_LINK_DIRECTORIES=${WXWINDOWS_LINK_DIRECTORIES}")
+ endif()
+
+
+ ## replace space separated string by semicolon separated vector to make it
+ ## work with LINK_DIRECTORIES
+ separate_arguments(WXWINDOWS_LINK_DIRECTORIES)
+
+ mark_as_advanced(
+ CMAKE_WXWINDOWS_CXX_FLAGS
+ WXWINDOWS_INCLUDE_DIR
+ WXWINDOWS_LIBRARIES
+ CMAKE_WXWINDOWS_WXCONFIG_EXECUTABLE
+ )
+
+
+ ## we really need wx-config...
+ else()
+ message(STATUS "Cannot find wx-config anywhere on the system. Please put the file into your path or specify it in CMAKE_WXWINDOWS_WXCONFIG_EXECUTABLE.")
+ mark_as_advanced(CMAKE_WXWINDOWS_WXCONFIG_EXECUTABLE)
+ endif()
+
+
+
+ else()
+ message(STATUS "FindwxWindows.cmake: Platform unknown/unsupported by FindwxWindows.cmake. It's neither WIN32 nor UNIX")
+ endif()
+endif()
+
+
+if(WXWINDOWS_LIBRARIES)
+ if(WXWINDOWS_INCLUDE_DIR OR CMAKE_WXWINDOWS_CXX_FLAGS)
+ ## found all we need.
+ set(WXWINDOWS_FOUND 1)
+
+ ## set deprecated variables for backward compatibility:
+ set(CMAKE_WX_CAN_COMPILE ${WXWINDOWS_FOUND})
+ set(WXWINDOWS_LIBRARY ${WXWINDOWS_LIBRARIES})
+ set(WXWINDOWS_INCLUDE_PATH ${WXWINDOWS_INCLUDE_DIR})
+ set(WXWINDOWS_LINK_DIRECTORIES ${WXWINDOWS_LINK_DIRECTORIES})
+ set(CMAKE_WX_CXX_FLAGS ${CMAKE_WXWINDOWS_CXX_FLAGS})
+
+ endif()
+endif()
diff --git a/Modules/FortranCInterface.cmake b/Modules/FortranCInterface.cmake
new file mode 100644
index 0000000..733c723
--- /dev/null
+++ b/Modules/FortranCInterface.cmake
@@ -0,0 +1,400 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FortranCInterface
+-----------------
+
+Fortran/C Interface Detection
+
+This module automatically detects the API by which C and Fortran
+languages interact.
+
+Module Variables
+^^^^^^^^^^^^^^^^
+
+Variables that indicate if the mangling is found:
+
+``FortranCInterface_GLOBAL_FOUND``
+ Global subroutines and functions.
+
+``FortranCInterface_MODULE_FOUND``
+ Module subroutines and functions (declared by "MODULE PROCEDURE").
+
+This module also provides the following variables to specify
+the detected mangling, though a typical use case does not need
+to reference them and can use the `Module Functions`_ below.
+
+``FortranCInterface_GLOBAL_PREFIX``
+ Prefix for a global symbol without an underscore.
+
+``FortranCInterface_GLOBAL_SUFFIX``
+ Suffix for a global symbol without an underscore.
+
+``FortranCInterface_GLOBAL_CASE``
+ The case for a global symbol without an underscore,
+ either ``UPPER`` or ``LOWER``.
+
+``FortranCInterface_GLOBAL__PREFIX``
+ Prefix for a global symbol with an underscore.
+
+``FortranCInterface_GLOBAL__SUFFIX``
+ Suffix for a global symbol with an underscore.
+
+``FortranCInterface_GLOBAL__CASE``
+ The case for a global symbol with an underscore,
+ either ``UPPER`` or ``LOWER``.
+
+``FortranCInterface_MODULE_PREFIX``
+ Prefix for a module symbol without an underscore.
+
+``FortranCInterface_MODULE_MIDDLE``
+ Middle of a module symbol without an underscore that appears
+ between the name of the module and the name of the symbol.
+
+``FortranCInterface_MODULE_SUFFIX``
+ Suffix for a module symbol without an underscore.
+
+``FortranCInterface_MODULE_CASE``
+ The case for a module symbol without an underscore,
+ either ``UPPER`` or ``LOWER``.
+
+``FortranCInterface_MODULE__PREFIX``
+ Prefix for a module symbol with an underscore.
+
+``FortranCInterface_MODULE__MIDDLE``
+ Middle of a module symbol with an underscore that appears
+ between the name of the module and the name of the symbol.
+
+``FortranCInterface_MODULE__SUFFIX``
+ Suffix for a module symbol with an underscore.
+
+``FortranCInterface_MODULE__CASE``
+ The case for a module symbol with an underscore,
+ either ``UPPER`` or ``LOWER``.
+
+Module Functions
+^^^^^^^^^^^^^^^^
+
+.. command:: FortranCInterface_HEADER
+
+ The ``FortranCInterface_HEADER`` function is provided to generate a
+ C header file containing macros to mangle symbol names::
+
+ FortranCInterface_HEADER(<file>
+ [MACRO_NAMESPACE <macro-ns>]
+ [SYMBOL_NAMESPACE <ns>]
+ [SYMBOLS [<module>:]<function> ...])
+
+ It generates in ``<file>`` definitions of the following macros::
+
+ #define FortranCInterface_GLOBAL (name,NAME) ...
+ #define FortranCInterface_GLOBAL_(name,NAME) ...
+ #define FortranCInterface_MODULE (mod,name, MOD,NAME) ...
+ #define FortranCInterface_MODULE_(mod,name, MOD,NAME) ...
+
+ These macros mangle four categories of Fortran symbols, respectively:
+
+ * Global symbols without '_': ``call mysub()``
+ * Global symbols with '_' : ``call my_sub()``
+ * Module symbols without '_': ``use mymod; call mysub()``
+ * Module symbols with '_' : ``use mymod; call my_sub()``
+
+ If mangling for a category is not known, its macro is left undefined.
+ All macros require raw names in both lower case and upper case.
+
+ The options are:
+
+ ``MACRO_NAMESPACE``
+ Replace the default ``FortranCInterface_`` prefix with a given
+ namespace ``<macro-ns>``.
+
+ ``SYMBOLS``
+ List symbols to mangle automatically with C preprocessor definitions::
+
+ <function> ==> #define <ns><function> ...
+ <module>:<function> ==> #define <ns><module>_<function> ...
+
+ If the mangling for some symbol is not known then no preprocessor
+ definition is created, and a warning is displayed.
+
+ ``SYMBOL_NAMESPACE``
+ Prefix all preprocessor definitions generated by the ``SYMBOLS``
+ option with a given namespace ``<ns>``.
+
+.. command:: FortranCInterface_VERIFY
+
+ The ``FortranCInterface_VERIFY`` function is provided to verify
+ that the Fortran and C/C++ compilers work together::
+
+ FortranCInterface_VERIFY([CXX] [QUIET])
+
+ It tests whether a simple test executable using Fortran and C (and C++
+ when the CXX option is given) compiles and links successfully. The
+ result is stored in the cache entry ``FortranCInterface_VERIFIED_C``
+ (or ``FortranCInterface_VERIFIED_CXX`` if ``CXX`` is given) as a boolean.
+ If the check fails and ``QUIET`` is not given the function terminates with a
+ fatal error message describing the problem. The purpose of this check
+ is to stop a build early for incompatible compiler combinations. The
+ test is built in the ``Release`` configuration.
+
+Example Usage
+^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ include(FortranCInterface)
+ FortranCInterface_HEADER(FC.h MACRO_NAMESPACE "FC_")
+
+This creates a "FC.h" header that defines mangling macros ``FC_GLOBAL()``,
+``FC_GLOBAL_()``, ``FC_MODULE()``, and ``FC_MODULE_()``.
+
+.. code-block:: cmake
+
+ include(FortranCInterface)
+ FortranCInterface_HEADER(FCMangle.h
+ MACRO_NAMESPACE "FC_"
+ SYMBOL_NAMESPACE "FC_"
+ SYMBOLS mysub mymod:my_sub)
+
+This creates a "FCMangle.h" header that defines the same ``FC_*()``
+mangling macros as the previous example plus preprocessor symbols
+``FC_mysub`` and ``FC_mymod_my_sub``.
+
+Additional Manglings
+^^^^^^^^^^^^^^^^^^^^
+
+FortranCInterface is aware of possible ``GLOBAL`` and ``MODULE`` manglings
+for many Fortran compilers, but it also provides an interface to specify
+new possible manglings. Set the variables::
+
+ FortranCInterface_GLOBAL_SYMBOLS
+ FortranCInterface_MODULE_SYMBOLS
+
+before including FortranCInterface to specify manglings of the symbols
+``MySub``, ``My_Sub``, ``MyModule:MySub``, and ``My_Module:My_Sub``.
+For example, the code:
+
+.. code-block:: cmake
+
+ set(FortranCInterface_GLOBAL_SYMBOLS mysub_ my_sub__ MYSUB_)
+ # ^^^^^ ^^^^^^ ^^^^^
+ set(FortranCInterface_MODULE_SYMBOLS
+ __mymodule_MOD_mysub __my_module_MOD_my_sub)
+ # ^^^^^^^^ ^^^^^ ^^^^^^^^^ ^^^^^^
+ include(FortranCInterface)
+
+tells FortranCInterface to try given ``GLOBAL`` and ``MODULE`` manglings.
+(The carets point at raw symbol names for clarity in this example but
+are not needed.)
+#]=======================================================================]
+
+#-----------------------------------------------------------------------------
+# Execute at most once in a project.
+if(FortranCInterface_SOURCE_DIR)
+ return()
+endif()
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0007 NEW)
+
+#-----------------------------------------------------------------------------
+# Verify that C and Fortran are available.
+foreach(lang C Fortran)
+ if(NOT CMAKE_${lang}_COMPILER_LOADED)
+ message(FATAL_ERROR
+ "FortranCInterface requires the ${lang} language to be enabled.")
+ endif()
+endforeach()
+
+#-----------------------------------------------------------------------------
+set(FortranCInterface_SOURCE_DIR ${CMAKE_ROOT}/Modules/FortranCInterface)
+
+# MinGW's make tool does not always like () in the path
+if("${CMAKE_GENERATOR}" MATCHES "MinGW" AND
+ "${FortranCInterface_SOURCE_DIR}" MATCHES "[()]")
+ file(COPY ${FortranCInterface_SOURCE_DIR}/
+ DESTINATION ${CMAKE_BINARY_DIR}/CMakeFiles/FortranCInterfaceMinGW)
+ set(FortranCInterface_SOURCE_DIR ${CMAKE_BINARY_DIR}/CMakeFiles/FortranCInterfaceMinGW)
+endif()
+
+# Create the interface detection project if it does not exist.
+if(NOT FortranCInterface_BINARY_DIR)
+ set(FortranCInterface_BINARY_DIR ${CMAKE_BINARY_DIR}/CMakeFiles/FortranCInterface)
+ include(${FortranCInterface_SOURCE_DIR}/Detect.cmake)
+endif()
+
+# Load the detection results.
+include(${FortranCInterface_BINARY_DIR}/Output.cmake)
+
+#-----------------------------------------------------------------------------
+function(FortranCInterface_HEADER file)
+ # Parse arguments.
+ if(IS_ABSOLUTE "${file}")
+ set(FILE "${file}")
+ else()
+ set(FILE "${CMAKE_CURRENT_BINARY_DIR}/${file}")
+ endif()
+ set(MACRO_NAMESPACE "FortranCInterface_")
+ set(SYMBOL_NAMESPACE)
+ set(SYMBOLS)
+ set(doing)
+ foreach(arg ${ARGN})
+ if("x${arg}" MATCHES "^x(SYMBOLS|SYMBOL_NAMESPACE|MACRO_NAMESPACE)$")
+ set(doing "${arg}")
+ elseif("x${doing}" MATCHES "^x(SYMBOLS)$")
+ list(APPEND "${doing}" "${arg}")
+ elseif("x${doing}" MATCHES "^x(SYMBOL_NAMESPACE|MACRO_NAMESPACE)$")
+ set("${doing}" "${arg}")
+ set(doing)
+ else()
+ message(AUTHOR_WARNING "Unknown argument: \"${arg}\"")
+ endif()
+ endforeach()
+
+ # Generate macro definitions.
+ set(HEADER_CONTENT)
+ set(_desc_GLOBAL "/* Mangling for Fortran global symbols without underscores. */")
+ set(_desc_GLOBAL_ "/* Mangling for Fortran global symbols with underscores. */")
+ set(_desc_MODULE "/* Mangling for Fortran module symbols without underscores. */")
+ set(_desc_MODULE_ "/* Mangling for Fortran module symbols with underscores. */")
+ foreach(macro GLOBAL GLOBAL_ MODULE MODULE_)
+ if(FortranCInterface_${macro}_MACRO)
+ string(APPEND HEADER_CONTENT "
+${_desc_${macro}}
+#define ${MACRO_NAMESPACE}${macro}${FortranCInterface_${macro}_MACRO}
+")
+ endif()
+ endforeach()
+
+ # Generate symbol mangling definitions.
+ if(SYMBOLS)
+ string(APPEND HEADER_CONTENT "
+/*--------------------------------------------------------------------------*/
+/* Mangle some symbols automatically. */
+")
+ endif()
+ foreach(f ${SYMBOLS})
+ if("${f}" MATCHES ":")
+ # Module symbol name. Parse "<module>:<function>" syntax.
+ string(REPLACE ":" ";" pieces "${f}")
+ list(GET pieces 0 module)
+ list(GET pieces 1 function)
+ string(TOUPPER "${module}" m_upper)
+ string(TOLOWER "${module}" m_lower)
+ string(TOUPPER "${function}" f_upper)
+ string(TOLOWER "${function}" f_lower)
+ if("${function}" MATCHES "_")
+ set(form "_")
+ else()
+ set(form "")
+ endif()
+ if(FortranCInterface_MODULE${form}_MACRO)
+ string(APPEND HEADER_CONTENT "#define ${SYMBOL_NAMESPACE}${module}_${function} ${MACRO_NAMESPACE}MODULE${form}(${m_lower},${f_lower}, ${m_upper},${f_upper})\n")
+ else()
+ message(AUTHOR_WARNING "No FortranCInterface mangling known for ${f}")
+ endif()
+ else()
+ # Global symbol name.
+ if("${f}" MATCHES "_")
+ set(form "_")
+ else()
+ set(form "")
+ endif()
+ string(TOUPPER "${f}" f_upper)
+ string(TOLOWER "${f}" f_lower)
+ if(FortranCInterface_GLOBAL${form}_MACRO)
+ string(APPEND HEADER_CONTENT "#define ${SYMBOL_NAMESPACE}${f} ${MACRO_NAMESPACE}GLOBAL${form}(${f_lower}, ${f_upper})\n")
+ else()
+ message(AUTHOR_WARNING "No FortranCInterface mangling known for ${f}")
+ endif()
+ endif()
+ endforeach()
+
+ # Store the content.
+ configure_file(${FortranCInterface_SOURCE_DIR}/Macro.h.in ${FILE} @ONLY)
+endfunction()
+
+function(FortranCInterface_VERIFY)
+ # Check arguments.
+
+ set(lang C)
+ set(quiet 0)
+ set(verify_cxx 0)
+ foreach(arg ${ARGN})
+ if("${arg}" STREQUAL "QUIET")
+ set(quiet 1)
+ elseif("${arg}" STREQUAL "CXX")
+ set(lang CXX)
+ set(verify_cxx 1)
+ else()
+ message(FATAL_ERROR
+ "FortranCInterface_VERIFY - called with unknown argument:\n ${arg}")
+ endif()
+ endforeach()
+
+ if(NOT CMAKE_${lang}_COMPILER_LOADED)
+ message(FATAL_ERROR
+ "FortranCInterface_VERIFY(${lang}) requires ${lang} to be enabled.")
+ endif()
+
+ # Build the verification project if not yet built.
+ if(NOT DEFINED FortranCInterface_VERIFIED_${lang})
+ set(_desc "Verifying Fortran/${lang} Compiler Compatibility")
+ message(CHECK_START "${_desc}")
+
+ cmake_policy(GET CMP0056 _FortranCInterface_CMP0056)
+ if(_FortranCInterface_CMP0056 STREQUAL "NEW")
+ set(_FortranCInterface_EXE_LINKER_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}")
+ else()
+ set(_FortranCInterface_EXE_LINKER_FLAGS "")
+ endif()
+
+ # Build a sample project which reports symbols.
+ set(CMAKE_TRY_COMPILE_CONFIGURATION Release)
+ try_compile(FortranCInterface_VERIFY_${lang}_COMPILED
+ ${FortranCInterface_BINARY_DIR}/Verify${lang}
+ ${FortranCInterface_SOURCE_DIR}/Verify
+ VerifyFortranC # project name
+ VerifyFortranC # target name
+ CMAKE_FLAGS -DVERIFY_CXX=${verify_cxx}
+ -DCMAKE_VERBOSE_MAKEFILE=ON
+ "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}"
+ "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}"
+ "-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}"
+ "-DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE}"
+ "-DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE}"
+ "-DCMAKE_Fortran_FLAGS_RELEASE:STRING=${CMAKE_Fortran_FLAGS_RELEASE}"
+ ${_FortranCInterface_EXE_LINKER_FLAGS}
+ OUTPUT_VARIABLE _output)
+ file(WRITE "${FortranCInterface_BINARY_DIR}/Verify${lang}/output.txt" "${_output}")
+
+ # Report results.
+ if(FortranCInterface_VERIFY_${lang}_COMPILED)
+ message(CHECK_PASS "Success")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "${_desc} passed with the following output:\n${_output}\n\n")
+ set(FortranCInterface_VERIFIED_${lang} 1 CACHE INTERNAL "Fortran/${lang} compatibility")
+ else()
+ message(CHECK_FAIL "Failed")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "${_desc} failed with the following output:\n${_output}\n\n")
+ set(FortranCInterface_VERIFIED_${lang} 0 CACHE INTERNAL "Fortran/${lang} compatibility")
+ endif()
+ unset(FortranCInterface_VERIFY_${lang}_COMPILED CACHE)
+ endif()
+
+ # Error if compilers are incompatible.
+ if(NOT FortranCInterface_VERIFIED_${lang} AND NOT quiet)
+ file(READ "${FortranCInterface_BINARY_DIR}/Verify${lang}/output.txt" _output)
+ string(REPLACE "\n" "\n " _output "${_output}")
+ message(FATAL_ERROR
+ "The Fortran compiler:\n ${CMAKE_Fortran_COMPILER}\n"
+ "and the ${lang} compiler:\n ${CMAKE_${lang}_COMPILER}\n"
+ "failed to compile a simple test project using both languages. "
+ "The output was:\n ${_output}")
+ endif()
+endfunction()
+
+# Restore including context policies.
+cmake_policy(POP)
diff --git a/Modules/FortranCInterface/CMakeLists.txt b/Modules/FortranCInterface/CMakeLists.txt
new file mode 100644
index 0000000..13e4498
--- /dev/null
+++ b/Modules/FortranCInterface/CMakeLists.txt
@@ -0,0 +1,107 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION ${CMAKE_VERSION})
+project(FortranCInterface C Fortran)
+include(${FortranCInterface_BINARY_DIR}/Input.cmake OPTIONAL)
+
+# Check if the C compiler supports '$' in identifiers.
+include(CheckCSourceCompiles)
+check_c_source_compiles("
+extern int dollar$(void);
+int main() { return 0; }
+" C_SUPPORTS_DOLLAR)
+
+# List manglings of global symbol names to try.
+set(global_symbols
+ my_sub # VisualAge
+ my_sub_ # GNU, Intel, HP, SunPro, PGI
+ my_sub__ # GNU g77
+ MY_SUB # Intel on Windows
+ mysub # VisualAge
+ mysub_ # GNU, Intel, HP, SunPro, PGI
+ MYSUB # Intel on Windows
+ ${FortranCInterface_GLOBAL_SYMBOLS}
+ )
+list(REMOVE_DUPLICATES global_symbols)
+
+# List manglings of module symbol names to try.
+set(module_symbols
+ __my_module_MOD_my_sub # GNU 4.3
+ __my_module_NMOD_my_sub # VisualAge
+ __my_module__my_sub # GNU 4.2
+ __mymodule_MOD_mysub # GNU 4.3
+ __mymodule_NMOD_mysub # VisualAge
+ __mymodule__mysub # GNU 4.2
+ my_module$my_sub # HP
+ my_module_mp_my_sub_ # Intel
+ MY_MODULE_mp_MY_SUB # Intel on Windows
+ my_module_my_sub_ # PGI
+ my_module_MP_my_sub # NAG
+ mymodule$mysub # HP
+ mymodule_mp_mysub_ # Intel
+ MYMODULE_mp_MYSUB # Intel on Windows
+ mymodule_mysub_ # PGI
+ mymodule_MP_mysub # NAG
+ ${FortranCInterface_MODULE_SYMBOLS}
+ )
+list(REMOVE_DUPLICATES module_symbols)
+
+# Note that some compiler manglings cannot be invoked from C:
+# SunPro uses "my_module.my_sub_"
+# PathScale uses "MY_SUB.in.MY_MODULE"
+
+# Add module symbols only with Fortran90.
+if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
+ set(myfort_modules mymodule.f90 my_module.f90)
+ set(call_mod call_mod.f90)
+ set_property(SOURCE main.F PROPERTY COMPILE_DEFINITIONS CALL_MOD)
+else()
+ set(module_symbols)
+endif()
+
+# Generate C symbol sources.
+set(symbol_sources)
+if(NOT CMAKE_Fortran_COMPILER_ID MATCHES "^(PathScale|Cray)$")
+ # Provide mymodule_ and my_module_ init symbols because:
+ # - PGI Fortran uses module init symbols
+ # but not for:
+ # - PathScale Fortran uses module init symbols but module symbols
+ # use '.in.' so we cannot provide them anyway.
+ # - Cray Fortran >= 7.3.2 uses module init symbols but module symbols
+ # use 'mysub$mymodule_' so we cannot provide them anyway.
+ list(APPEND symbol_sources mymodule_.c my_module_.c MY_MODULE.c MYMODULE.c)
+endif()
+foreach(symbol IN LISTS global_symbols module_symbols)
+ # Skip symbols with '$' if C cannot handle them.
+ if(C_SUPPORTS_DOLLAR OR NOT "${symbol}" MATCHES "\\$")
+ if("${symbol}" MATCHES "SUB")
+ set(upper "-UPPER")
+ else()
+ set(upper)
+ endif()
+ string(REPLACE "$" "S" name "${symbol}")
+ set(source ${CMAKE_CURRENT_BINARY_DIR}/symbols/${name}${upper}.c)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/symbol.c.in ${source} @ONLY)
+ list(APPEND symbol_sources ${source})
+ endif()
+endforeach()
+
+# Provide symbols through Fortran.
+add_library(myfort STATIC mysub.f my_sub.f ${myfort_modules})
+
+# Provide symbols through C but fall back to Fortran.
+add_library(symbols STATIC ${symbol_sources})
+target_link_libraries(symbols PUBLIC myfort)
+
+# In case the Fortran compiler produces PIC by default make sure
+# the C compiler produces PIC even if it is not its default.
+set_property(TARGET symbols PROPERTY POSITION_INDEPENDENT_CODE 1)
+
+# Require symbols through Fortran.
+add_executable(FortranCInterface main.F call_sub.f ${call_mod})
+target_link_libraries(FortranCInterface PUBLIC symbols)
+
+file(GENERATE OUTPUT exe-$<CONFIG>.cmake CONTENT [[
+set(FortranCInterface_EXE "$<TARGET_FILE:FortranCInterface>")
+]])
diff --git a/Modules/FortranCInterface/Detect.cmake b/Modules/FortranCInterface/Detect.cmake
new file mode 100644
index 0000000..9e5726b
--- /dev/null
+++ b/Modules/FortranCInterface/Detect.cmake
@@ -0,0 +1,187 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+configure_file(${FortranCInterface_SOURCE_DIR}/Input.cmake.in
+ ${FortranCInterface_BINARY_DIR}/Input.cmake @ONLY)
+
+# Detect the Fortran/C interface on the first run or when the
+# configuration changes.
+if(NOT EXISTS ${FortranCInterface_BINARY_DIR}/Output.cmake
+ OR NOT EXISTS ${FortranCInterface_BINARY_DIR}/Input.cmake
+ OR NOT EXISTS ${FortranCInterface_BINARY_DIR}/Output.cmake.in
+ OR NOT ${FortranCInterface_BINARY_DIR}/Output.cmake
+ IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Input.cmake
+ OR NOT ${FortranCInterface_SOURCE_DIR}/Output.cmake
+ IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake.in
+ OR NOT ${FortranCInterface_BINARY_DIR}/Output.cmake
+ IS_NEWER_THAN ${FortranCInterface_SOURCE_DIR}/CMakeLists.txt
+ OR NOT ${FortranCInterface_BINARY_DIR}/Output.cmake
+ IS_NEWER_THAN ${CMAKE_CURRENT_LIST_FILE}
+ )
+ message(CHECK_START "Detecting Fortran/C Interface")
+else()
+ return()
+endif()
+
+# Invalidate verification results.
+unset(FortranCInterface_VERIFIED_C CACHE)
+unset(FortranCInterface_VERIFIED_CXX CACHE)
+
+set(_result)
+
+cmake_policy(GET CMP0056 _FortranCInterface_CMP0056)
+if(_FortranCInterface_CMP0056 STREQUAL "NEW")
+ set(_FortranCInterface_EXE_LINKER_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}")
+else()
+ set(_FortranCInterface_EXE_LINKER_FLAGS "")
+endif()
+unset(_FortranCInterface_CMP0056)
+
+# Build a sample project which reports symbols.
+set(CMAKE_TRY_COMPILE_CONFIGURATION Release)
+try_compile(FortranCInterface_COMPILED
+ ${FortranCInterface_BINARY_DIR}
+ ${FortranCInterface_SOURCE_DIR}
+ FortranCInterface # project name
+ FortranCInterface # target name
+ CMAKE_FLAGS
+ "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}"
+ "-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}"
+ "-DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE}"
+ "-DCMAKE_Fortran_FLAGS_RELEASE:STRING=${CMAKE_Fortran_FLAGS_RELEASE}"
+ ${_FortranCInterface_EXE_LINKER_FLAGS}
+ OUTPUT_VARIABLE FortranCInterface_OUTPUT)
+set(FortranCInterface_COMPILED ${FortranCInterface_COMPILED})
+unset(FortranCInterface_COMPILED CACHE)
+unset(_FortranCInterface_EXE_LINKER_FLAGS)
+
+# Locate the sample project executable.
+set(FortranCInterface_EXE)
+if(FortranCInterface_COMPILED)
+ include(${FortranCInterface_BINARY_DIR}/exe-Release.cmake OPTIONAL)
+else()
+ set(_result "Failed to compile")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Fortran/C interface test project failed with the following output:\n"
+ "${FortranCInterface_OUTPUT}\n")
+endif()
+
+# Load symbols from INFO:symbol[] strings in the executable.
+set(FortranCInterface_SYMBOLS)
+if(FortranCInterface_EXE)
+ file(STRINGS "${FortranCInterface_EXE}" _info_strings
+ LIMIT_COUNT 8 REGEX "INFO:[A-Za-z0-9_]+\\[[^]]*\\]")
+ foreach(info ${_info_strings})
+ if("${info}" MATCHES "INFO:symbol\\[([^]]*)\\]")
+ list(APPEND FortranCInterface_SYMBOLS ${CMAKE_MATCH_1})
+ endif()
+ endforeach()
+elseif(NOT _result)
+ set(_result "Failed to load sample executable")
+endif()
+
+set(_case_mysub "LOWER")
+set(_case_my_sub "LOWER")
+set(_case_MYSUB "UPPER")
+set(_case_MY_SUB "UPPER")
+set(_global_regex "^(_*)(mysub|MYSUB)([_$]*)$")
+set(_global__regex "^(_*)(my_sub|MY_SUB)([_$]*)$")
+set(_module_regex "^(_*)(mymodule|MYMODULE)([A-Za-z_$]*)(mysub|MYSUB)([_$]*)$")
+set(_module__regex "^(_*)(my_module|MY_MODULE)([A-Za-z_$]*)(my_sub|MY_SUB)([_$]*)$")
+
+# Parse the symbol names.
+foreach(symbol ${FortranCInterface_SYMBOLS})
+ foreach(form "" "_")
+ # Look for global symbols.
+ string(REGEX REPLACE "${_global_${form}regex}"
+ "\\1;\\2;\\3" pieces "${symbol}")
+ list(LENGTH pieces len)
+ if(len EQUAL 3)
+ set(FortranCInterface_GLOBAL_${form}SYMBOL "${symbol}")
+ list(GET pieces 0 FortranCInterface_GLOBAL_${form}PREFIX)
+ list(GET pieces 1 name)
+ list(GET pieces 2 FortranCInterface_GLOBAL_${form}SUFFIX)
+ set(FortranCInterface_GLOBAL_${form}CASE "${_case_${name}}")
+ endif()
+
+ # Look for module symbols.
+ string(REGEX REPLACE "${_module_${form}regex}"
+ "\\1;\\2;\\3;\\4;\\5" pieces "${symbol}")
+ list(LENGTH pieces len)
+ if(len EQUAL 5)
+ set(FortranCInterface_MODULE_${form}SYMBOL "${symbol}")
+ list(GET pieces 0 FortranCInterface_MODULE_${form}PREFIX)
+ list(GET pieces 1 module)
+ list(GET pieces 2 FortranCInterface_MODULE_${form}MIDDLE)
+ list(GET pieces 3 name)
+ list(GET pieces 4 FortranCInterface_MODULE_${form}SUFFIX)
+ set(FortranCInterface_MODULE_${form}CASE "${_case_${name}}")
+ endif()
+ endforeach()
+endforeach()
+
+# Construct mangling macro definitions.
+set(_name_LOWER "name")
+set(_name_UPPER "NAME")
+foreach(form "" "_")
+ if(FortranCInterface_GLOBAL_${form}SYMBOL)
+ if(FortranCInterface_GLOBAL_${form}PREFIX)
+ set(_prefix "${FortranCInterface_GLOBAL_${form}PREFIX}##")
+ else()
+ set(_prefix "")
+ endif()
+ if(FortranCInterface_GLOBAL_${form}SUFFIX)
+ set(_suffix "##${FortranCInterface_GLOBAL_${form}SUFFIX}")
+ else()
+ set(_suffix "")
+ endif()
+ set(_name "${_name_${FortranCInterface_GLOBAL_${form}CASE}}")
+ set(FortranCInterface_GLOBAL${form}_MACRO
+ "(name,NAME) ${_prefix}${_name}${_suffix}")
+ endif()
+ if(FortranCInterface_MODULE_${form}SYMBOL)
+ if(FortranCInterface_MODULE_${form}PREFIX)
+ set(_prefix "${FortranCInterface_MODULE_${form}PREFIX}##")
+ else()
+ set(_prefix "")
+ endif()
+ if(FortranCInterface_MODULE_${form}SUFFIX)
+ set(_suffix "##${FortranCInterface_MODULE_${form}SUFFIX}")
+ else()
+ set(_suffix "")
+ endif()
+ set(_name "${_name_${FortranCInterface_MODULE_${form}CASE}}")
+ set(_middle "##${FortranCInterface_MODULE_${form}MIDDLE}##")
+ set(FortranCInterface_MODULE${form}_MACRO
+ "(mod_name,name, mod_NAME,NAME) ${_prefix}mod_${_name}${_middle}${_name}${_suffix}")
+ endif()
+endforeach()
+
+# Summarize what is available.
+foreach(scope GLOBAL MODULE)
+ if(FortranCInterface_${scope}_SYMBOL AND
+ FortranCInterface_${scope}__SYMBOL)
+ set(FortranCInterface_${scope}_FOUND 1)
+ else()
+ set(FortranCInterface_${scope}_FOUND 0)
+ endif()
+endforeach()
+
+# Record the detection results.
+configure_file(${FortranCInterface_SOURCE_DIR}/Output.cmake.in
+ ${FortranCInterface_BINARY_DIR}/Output.cmake @ONLY)
+file(APPEND ${FortranCInterface_BINARY_DIR}/Output.cmake "\n")
+
+# Report the results.
+if(FortranCInterface_GLOBAL_FOUND)
+ if(FortranCInterface_MODULE_FOUND)
+ set(_result "Found GLOBAL and MODULE mangling")
+ else()
+ set(_result "Found GLOBAL but not MODULE mangling")
+ endif()
+ set(_result_type CHECK_PASS)
+elseif(NOT _result)
+ set(_result "Failed to recognize symbols")
+ set(_result_type CHECK_FAIL)
+endif()
+message(${_result_type} "${_result}")
diff --git a/Modules/FortranCInterface/Input.cmake.in b/Modules/FortranCInterface/Input.cmake.in
new file mode 100644
index 0000000..f261e3b
--- /dev/null
+++ b/Modules/FortranCInterface/Input.cmake.in
@@ -0,0 +1,3 @@
+set(CMAKE_Fortran_COMPILER_ID "@CMAKE_Fortran_COMPILER_ID@")
+set(FortranCInterface_GLOBAL_SYMBOLS "@FortranCInterface_GLOBAL_SYMBOLS@")
+set(FortranCInterface_MODULE_SYMBOLS "@FortranCInterface_MODULE_SYMBOLS@")
diff --git a/Modules/FortranCInterface/MYMODULE.c b/Modules/FortranCInterface/MYMODULE.c
new file mode 100644
index 0000000..19b51fb
--- /dev/null
+++ b/Modules/FortranCInterface/MYMODULE.c
@@ -0,0 +1,3 @@
+void MYMODULE(void)
+{
+}
diff --git a/Modules/FortranCInterface/MY_MODULE.c b/Modules/FortranCInterface/MY_MODULE.c
new file mode 100644
index 0000000..87b3071
--- /dev/null
+++ b/Modules/FortranCInterface/MY_MODULE.c
@@ -0,0 +1,3 @@
+void MY_MODULE(void)
+{
+}
diff --git a/Modules/FortranCInterface/Macro.h.in b/Modules/FortranCInterface/Macro.h.in
new file mode 100644
index 0000000..d015a62
--- /dev/null
+++ b/Modules/FortranCInterface/Macro.h.in
@@ -0,0 +1,4 @@
+#ifndef @MACRO_NAMESPACE@HEADER_INCLUDED
+#define @MACRO_NAMESPACE@HEADER_INCLUDED
+@HEADER_CONTENT@
+#endif
diff --git a/Modules/FortranCInterface/Output.cmake.in b/Modules/FortranCInterface/Output.cmake.in
new file mode 100644
index 0000000..bce410e
--- /dev/null
+++ b/Modules/FortranCInterface/Output.cmake.in
@@ -0,0 +1,33 @@
+# Global symbol without underscore.
+set(FortranCInterface_GLOBAL_SYMBOL "@FortranCInterface_GLOBAL_SYMBOL@")
+set(FortranCInterface_GLOBAL_PREFIX "@FortranCInterface_GLOBAL_PREFIX@")
+set(FortranCInterface_GLOBAL_SUFFIX "@FortranCInterface_GLOBAL_SUFFIX@")
+set(FortranCInterface_GLOBAL_CASE "@FortranCInterface_GLOBAL_CASE@")
+set(FortranCInterface_GLOBAL_MACRO "@FortranCInterface_GLOBAL_MACRO@")
+
+# Global symbol with underscore.
+set(FortranCInterface_GLOBAL__SYMBOL "@FortranCInterface_GLOBAL__SYMBOL@")
+set(FortranCInterface_GLOBAL__PREFIX "@FortranCInterface_GLOBAL__PREFIX@")
+set(FortranCInterface_GLOBAL__SUFFIX "@FortranCInterface_GLOBAL__SUFFIX@")
+set(FortranCInterface_GLOBAL__CASE "@FortranCInterface_GLOBAL__CASE@")
+set(FortranCInterface_GLOBAL__MACRO "@FortranCInterface_GLOBAL__MACRO@")
+
+# Module symbol without underscore.
+set(FortranCInterface_MODULE_SYMBOL "@FortranCInterface_MODULE_SYMBOL@")
+set(FortranCInterface_MODULE_PREFIX "@FortranCInterface_MODULE_PREFIX@")
+set(FortranCInterface_MODULE_MIDDLE "@FortranCInterface_MODULE_MIDDLE@")
+set(FortranCInterface_MODULE_SUFFIX "@FortranCInterface_MODULE_SUFFIX@")
+set(FortranCInterface_MODULE_CASE "@FortranCInterface_MODULE_CASE@")
+set(FortranCInterface_MODULE_MACRO "@FortranCInterface_MODULE_MACRO@")
+
+# Module symbol with underscore.
+set(FortranCInterface_MODULE__SYMBOL "@FortranCInterface_MODULE__SYMBOL@")
+set(FortranCInterface_MODULE__PREFIX "@FortranCInterface_MODULE__PREFIX@")
+set(FortranCInterface_MODULE__MIDDLE "@FortranCInterface_MODULE__MIDDLE@")
+set(FortranCInterface_MODULE__SUFFIX "@FortranCInterface_MODULE__SUFFIX@")
+set(FortranCInterface_MODULE__CASE "@FortranCInterface_MODULE__CASE@")
+set(FortranCInterface_MODULE__MACRO "@FortranCInterface_MODULE__MACRO@")
+
+# Summarize what was found.
+set(FortranCInterface_GLOBAL_FOUND @FortranCInterface_GLOBAL_FOUND@)
+set(FortranCInterface_MODULE_FOUND @FortranCInterface_MODULE_FOUND@)
diff --git a/Modules/FortranCInterface/Verify/CMakeLists.txt b/Modules/FortranCInterface/Verify/CMakeLists.txt
new file mode 100644
index 0000000..98cdeb7
--- /dev/null
+++ b/Modules/FortranCInterface/Verify/CMakeLists.txt
@@ -0,0 +1,26 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION ${CMAKE_VERSION})
+project(VerifyFortranC C Fortran)
+
+option(VERIFY_CXX "Whether to verify C++ and Fortran" OFF)
+if(VERIFY_CXX)
+ enable_language(CXX)
+ set(VerifyCXX VerifyCXX.cxx)
+ add_definitions(-DVERIFY_CXX)
+endif()
+
+include(FortranCInterface)
+
+FortranCInterface_HEADER(VerifyFortran.h SYMBOLS VerifyFortran)
+include_directories(${VerifyFortranC_BINARY_DIR})
+
+add_library(VerifyFortran STATIC VerifyFortran.f)
+add_executable(VerifyFortranC main.c VerifyC.c ${VerifyCXX})
+target_link_libraries(VerifyFortranC VerifyFortran)
+
+if(NOT VERIFY_CXX)
+ # The entry point (main) is defined in C; link with the C compiler.
+ set_property(TARGET VerifyFortranC PROPERTY LINKER_LANGUAGE C)
+endif()
diff --git a/Modules/FortranCInterface/Verify/VerifyC.c b/Modules/FortranCInterface/Verify/VerifyC.c
new file mode 100644
index 0000000..7f847ef
--- /dev/null
+++ b/Modules/FortranCInterface/Verify/VerifyC.c
@@ -0,0 +1,5 @@
+#include <stdio.h>
+void VerifyC(void)
+{
+ printf("VerifyC\n");
+}
diff --git a/Modules/FortranCInterface/Verify/VerifyCXX.cxx b/Modules/FortranCInterface/Verify/VerifyCXX.cxx
new file mode 100644
index 0000000..689fac5
--- /dev/null
+++ b/Modules/FortranCInterface/Verify/VerifyCXX.cxx
@@ -0,0 +1,4 @@
+extern "C" void VerifyCXX(void)
+{
+ delete new int;
+}
diff --git a/Modules/FortranCInterface/Verify/VerifyFortran.f b/Modules/FortranCInterface/Verify/VerifyFortran.f
new file mode 100644
index 0000000..a17e48d
--- /dev/null
+++ b/Modules/FortranCInterface/Verify/VerifyFortran.f
@@ -0,0 +1,3 @@
+ subroutine VerifyFortran
+ print *, 'VerifyFortran'
+ end
diff --git a/Modules/FortranCInterface/Verify/main.c b/Modules/FortranCInterface/Verify/main.c
new file mode 100644
index 0000000..582ef1d
--- /dev/null
+++ b/Modules/FortranCInterface/Verify/main.c
@@ -0,0 +1,16 @@
+extern void VerifyC(void);
+#ifdef VERIFY_CXX
+extern void VerifyCXX(void);
+#endif
+#include "VerifyFortran.h"
+extern void VerifyFortran(void);
+
+int main(void)
+{
+ VerifyC();
+#ifdef VERIFY_CXX
+ VerifyCXX();
+#endif
+ VerifyFortran();
+ return 0;
+}
diff --git a/Modules/FortranCInterface/call_mod.f90 b/Modules/FortranCInterface/call_mod.f90
new file mode 100644
index 0000000..9b6af64
--- /dev/null
+++ b/Modules/FortranCInterface/call_mod.f90
@@ -0,0 +1,6 @@
+subroutine call_mod
+ use mymodule
+ use my_module
+ call mysub()
+ call my_sub()
+end subroutine call_mod
diff --git a/Modules/FortranCInterface/call_sub.f b/Modules/FortranCInterface/call_sub.f
new file mode 100644
index 0000000..ce3d50b
--- /dev/null
+++ b/Modules/FortranCInterface/call_sub.f
@@ -0,0 +1,4 @@
+ subroutine call_sub
+ call mysub()
+ call my_sub()
+ end
diff --git a/Modules/FortranCInterface/main.F b/Modules/FortranCInterface/main.F
new file mode 100644
index 0000000..84991b0
--- /dev/null
+++ b/Modules/FortranCInterface/main.F
@@ -0,0 +1,6 @@
+ program main
+ call call_sub()
+#ifdef CALL_MOD
+ call call_mod()
+#endif
+ end
diff --git a/Modules/FortranCInterface/my_module.f90 b/Modules/FortranCInterface/my_module.f90
new file mode 100644
index 0000000..82713b4
--- /dev/null
+++ b/Modules/FortranCInterface/my_module.f90
@@ -0,0 +1,8 @@
+module my_module
+ interface my_interface
+ module procedure my_sub
+ end interface
+contains
+ subroutine my_sub
+ end subroutine my_sub
+end module my_module
diff --git a/Modules/FortranCInterface/my_module_.c b/Modules/FortranCInterface/my_module_.c
new file mode 100644
index 0000000..6fa89d1
--- /dev/null
+++ b/Modules/FortranCInterface/my_module_.c
@@ -0,0 +1,3 @@
+void my_module_(void)
+{
+}
diff --git a/Modules/FortranCInterface/my_sub.f b/Modules/FortranCInterface/my_sub.f
new file mode 100644
index 0000000..247ba06
--- /dev/null
+++ b/Modules/FortranCInterface/my_sub.f
@@ -0,0 +1,2 @@
+ subroutine my_sub
+ end
diff --git a/Modules/FortranCInterface/mymodule.f90 b/Modules/FortranCInterface/mymodule.f90
new file mode 100644
index 0000000..ef6281a
--- /dev/null
+++ b/Modules/FortranCInterface/mymodule.f90
@@ -0,0 +1,8 @@
+module mymodule
+ interface myinterface
+ module procedure mysub
+ end interface
+contains
+ subroutine mysub
+ end subroutine mysub
+end module mymodule
diff --git a/Modules/FortranCInterface/mymodule_.c b/Modules/FortranCInterface/mymodule_.c
new file mode 100644
index 0000000..444953b
--- /dev/null
+++ b/Modules/FortranCInterface/mymodule_.c
@@ -0,0 +1,3 @@
+void mymodule_(void)
+{
+}
diff --git a/Modules/FortranCInterface/mysub.f b/Modules/FortranCInterface/mysub.f
new file mode 100644
index 0000000..1c27ff4
--- /dev/null
+++ b/Modules/FortranCInterface/mysub.f
@@ -0,0 +1,2 @@
+ subroutine mysub
+ end
diff --git a/Modules/FortranCInterface/symbol.c.in b/Modules/FortranCInterface/symbol.c.in
new file mode 100644
index 0000000..369fa45
--- /dev/null
+++ b/Modules/FortranCInterface/symbol.c.in
@@ -0,0 +1,4 @@
+const char* @symbol@(void)
+{
+ return "INFO:symbol[@symbol@]";
+}
diff --git a/Modules/GNUInstallDirs.cmake b/Modules/GNUInstallDirs.cmake
new file mode 100644
index 0000000..e149f4c
--- /dev/null
+++ b/Modules/GNUInstallDirs.cmake
@@ -0,0 +1,423 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+GNUInstallDirs
+--------------
+
+Define GNU standard installation directories
+
+Provides install directory variables as defined by the
+`GNU Coding Standards`_.
+
+.. _`GNU Coding Standards`: https://www.gnu.org/prep/standards/html_node/Directory-Variables.html
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+Inclusion of this module defines the following variables:
+
+``CMAKE_INSTALL_<dir>``
+
+ Destination for files of a given type. This value may be passed to
+ the ``DESTINATION`` options of :command:`install` commands for the
+ corresponding file type. It should typically be a path relative to
+ the installation prefix so that it can be converted to an absolute
+ path in a relocatable way (see ``CMAKE_INSTALL_FULL_<dir>``).
+ However, an absolute path is also allowed.
+
+``CMAKE_INSTALL_FULL_<dir>``
+
+ The absolute path generated from the corresponding ``CMAKE_INSTALL_<dir>``
+ value. If the value is not already an absolute path, an absolute path
+ is constructed typically by prepending the value of the
+ :variable:`CMAKE_INSTALL_PREFIX` variable. However, there are some
+ `special cases`_ as documented below.
+
+where ``<dir>`` is one of:
+
+``BINDIR``
+ user executables (``bin``)
+``SBINDIR``
+ system admin executables (``sbin``)
+``LIBEXECDIR``
+ program executables (``libexec``)
+``SYSCONFDIR``
+ read-only single-machine data (``etc``)
+``SHAREDSTATEDIR``
+ modifiable architecture-independent data (``com``)
+``LOCALSTATEDIR``
+ modifiable single-machine data (``var``)
+``RUNSTATEDIR``
+ .. versionadded:: 3.9
+ run-time variable data (``LOCALSTATEDIR/run``)
+``LIBDIR``
+ object code libraries (``lib`` or ``lib64``
+ or ``lib/<multiarch-tuple>`` on Debian)
+``INCLUDEDIR``
+ C header files (``include``)
+``OLDINCLUDEDIR``
+ C header files for non-gcc (``/usr/include``)
+``DATAROOTDIR``
+ read-only architecture-independent data root (``share``)
+``DATADIR``
+ read-only architecture-independent data (``DATAROOTDIR``)
+``INFODIR``
+ info documentation (``DATAROOTDIR/info``)
+``LOCALEDIR``
+ locale-dependent data (``DATAROOTDIR/locale``)
+``MANDIR``
+ man documentation (``DATAROOTDIR/man``)
+``DOCDIR``
+ documentation root (``DATAROOTDIR/doc/PROJECT_NAME``)
+
+If the includer does not define a value the above-shown default will be
+used and the value will appear in the cache for editing by the user.
+
+Special Cases
+^^^^^^^^^^^^^
+
+.. versionadded:: 3.4
+
+The following values of :variable:`CMAKE_INSTALL_PREFIX` are special:
+
+``/``
+
+ For ``<dir>`` other than the ``SYSCONFDIR``, ``LOCALSTATEDIR`` and
+ ``RUNSTATEDIR``, the value of ``CMAKE_INSTALL_<dir>`` is prefixed
+ with ``usr/`` if it is not user-specified as an absolute path.
+ For example, the ``INCLUDEDIR`` value ``include`` becomes ``usr/include``.
+ This is required by the `GNU Coding Standards`_, which state:
+
+ When building the complete GNU system, the prefix will be empty
+ and ``/usr`` will be a symbolic link to ``/``.
+
+``/usr``
+
+ For ``<dir>`` equal to ``SYSCONFDIR``, ``LOCALSTATEDIR`` or
+ ``RUNSTATEDIR``, the ``CMAKE_INSTALL_FULL_<dir>`` is computed by
+ prepending just ``/`` to the value of ``CMAKE_INSTALL_<dir>``
+ if it is not user-specified as an absolute path.
+ For example, the ``SYSCONFDIR`` value ``etc`` becomes ``/etc``.
+ This is required by the `GNU Coding Standards`_.
+
+``/opt/...``
+
+ For ``<dir>`` equal to ``SYSCONFDIR``, ``LOCALSTATEDIR`` or
+ ``RUNSTATEDIR``, the ``CMAKE_INSTALL_FULL_<dir>`` is computed by
+ *appending* the prefix to the value of ``CMAKE_INSTALL_<dir>``
+ if it is not user-specified as an absolute path.
+ For example, the ``SYSCONFDIR`` value ``etc`` becomes ``/etc/opt/...``.
+ This is defined by the `Filesystem Hierarchy Standard`_.
+
+.. _`Filesystem Hierarchy Standard`: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html
+
+Macros
+^^^^^^
+
+.. command:: GNUInstallDirs_get_absolute_install_dir
+
+ ::
+
+ GNUInstallDirs_get_absolute_install_dir(absvar var dirname)
+
+ .. versionadded:: 3.7
+
+ Set the given variable ``absvar`` to the absolute path contained
+ within the variable ``var``. This is to allow the computation of an
+ absolute path, accounting for all the special cases documented
+ above. While this macro is used to compute the various
+ ``CMAKE_INSTALL_FULL_<dir>`` variables, it is exposed publicly to
+ allow users who create additional path variables to also compute
+ absolute paths where necessary, using the same logic. ``dirname`` is
+ the directory name to get, e.g. ``BINDIR``.
+
+ .. versionchanged:: 3.20
+ Added the ``<dirname>`` parameter. Previous versions of CMake passed
+ this value through the variable ``${dir}``.
+#]=======================================================================]
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
+
+# Convert a cache variable to PATH type
+
+macro(_GNUInstallDirs_cache_convert_to_path var description)
+ get_property(_GNUInstallDirs_cache_type CACHE ${var} PROPERTY TYPE)
+ if(_GNUInstallDirs_cache_type STREQUAL "UNINITIALIZED")
+ file(TO_CMAKE_PATH "${${var}}" _GNUInstallDirs_cmakepath)
+ set_property(CACHE ${var} PROPERTY TYPE PATH)
+ set_property(CACHE ${var} PROPERTY VALUE "${_GNUInstallDirs_cmakepath}")
+ set_property(CACHE ${var} PROPERTY HELPSTRING "${description}")
+ unset(_GNUInstallDirs_cmakepath)
+ endif()
+ unset(_GNUInstallDirs_cache_type)
+endmacro()
+
+# Create a cache variable with default for a path.
+macro(_GNUInstallDirs_cache_path var default description)
+ if(NOT DEFINED ${var})
+ set(${var} "${default}" CACHE PATH "${description}")
+ endif()
+ _GNUInstallDirs_cache_convert_to_path("${var}" "${description}")
+endmacro()
+
+# Create a cache variable with not default for a path, with a fallback
+# when unset; used for entries slaved to other entries such as
+# DATAROOTDIR.
+macro(_GNUInstallDirs_cache_path_fallback var default description)
+ if(NOT ${var})
+ set(${var} "" CACHE PATH "${description}")
+ set(${var} "${default}")
+ endif()
+ _GNUInstallDirs_cache_convert_to_path("${var}" "${description}")
+endmacro()
+
+# Installation directories
+#
+
+_GNUInstallDirs_cache_path(CMAKE_INSTALL_BINDIR "bin"
+ "User executables (bin)")
+_GNUInstallDirs_cache_path(CMAKE_INSTALL_SBINDIR "sbin"
+ "System admin executables (sbin)")
+_GNUInstallDirs_cache_path(CMAKE_INSTALL_SYSCONFDIR "etc"
+ "Read-only single-machine data (etc)")
+_GNUInstallDirs_cache_path(CMAKE_INSTALL_SHAREDSTATEDIR "com"
+ "Modifiable architecture-independent data (com)")
+_GNUInstallDirs_cache_path(CMAKE_INSTALL_LOCALSTATEDIR "var"
+ "Modifiable single-machine data (var)")
+
+# We check if the variable was manually set and not cached, in order to
+# allow projects to set the values as normal variables before including
+# GNUInstallDirs to avoid having the entries cached or user-editable. It
+# replaces the "if(NOT DEFINED CMAKE_INSTALL_XXX)" checks in all the
+# other cases.
+# If CMAKE_INSTALL_LIBDIR is defined, if _libdir_set is false, then the
+# variable is a normal one, otherwise it is a cache one.
+get_property(_libdir_set CACHE CMAKE_INSTALL_LIBDIR PROPERTY TYPE SET)
+if(NOT DEFINED CMAKE_INSTALL_LIBDIR OR (_libdir_set
+ AND DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX
+ AND NOT "${_GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX}" STREQUAL "${CMAKE_INSTALL_PREFIX}"))
+ # If CMAKE_INSTALL_LIBDIR is not defined, it is always executed.
+ # Otherwise:
+ # * if _libdir_set is false it is not executed (meaning that it is
+ # not a cache variable)
+ # * if _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX is not defined it is
+ # not executed
+ # * if _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX and
+ # CMAKE_INSTALL_PREFIX are the same string it is not executed.
+ # _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX is updated after the
+ # execution, of this part of code, therefore at the next inclusion
+ # of the file, CMAKE_INSTALL_LIBDIR is defined, and the 2 strings
+ # are equal, meaning that the if is not executed the code the
+ # second time.
+
+ set(_LIBDIR_DEFAULT "lib")
+ # Override this default 'lib' with 'lib64' iff:
+ # - we are on Linux system but NOT cross-compiling
+ # - we are NOT on debian
+ # - we are on a 64 bits system
+ # reason is: amd64 ABI: https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI
+ # For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if
+ # CMAKE_LIBRARY_ARCHITECTURE is set (which contains e.g. "i386-linux-gnu"
+ # and CMAKE_INSTALL_PREFIX is "/usr"
+ # See http://wiki.debian.org/Multiarch
+ if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX)
+ set(__LAST_LIBDIR_DEFAULT "lib")
+ # __LAST_LIBDIR_DEFAULT is the default value that we compute from
+ # _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX, not a cache entry for
+ # the value that was last used as the default.
+ # This value is used to figure out whether the user changed the
+ # CMAKE_INSTALL_LIBDIR value manually, or if the value was the
+ # default one. When CMAKE_INSTALL_PREFIX changes, the value is
+ # updated to the new default, unless the user explicitly changed it.
+ endif()
+ if (NOT DEFINED CMAKE_SYSTEM_NAME OR NOT DEFINED CMAKE_SIZEOF_VOID_P)
+ message(AUTHOR_WARNING
+ "Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
+ "Please enable at least one language before including GNUInstallDirs.")
+ endif()
+ if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$"
+ AND NOT CMAKE_CROSSCOMPILING
+ AND NOT EXISTS "/etc/arch-release")
+ if (EXISTS "/etc/debian_version") # is this a debian system ?
+ if(CMAKE_LIBRARY_ARCHITECTURE)
+ if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$")
+ set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
+ endif()
+ if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX
+ AND "${_GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$")
+ set(__LAST_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
+ endif()
+ endif()
+ else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
+ if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
+ set(_LIBDIR_DEFAULT "lib64")
+ if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX)
+ set(__LAST_LIBDIR_DEFAULT "lib64")
+ endif()
+ endif()
+ endif()
+ endif()
+ if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
+ set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "Object code libraries (${_LIBDIR_DEFAULT})")
+ elseif(DEFINED __LAST_LIBDIR_DEFAULT
+ AND "${__LAST_LIBDIR_DEFAULT}" STREQUAL "${CMAKE_INSTALL_LIBDIR}")
+ set_property(CACHE CMAKE_INSTALL_LIBDIR PROPERTY VALUE "${_LIBDIR_DEFAULT}")
+ endif()
+endif()
+_GNUInstallDirs_cache_convert_to_path(CMAKE_INSTALL_LIBDIR "Object code libraries (lib)")
+
+# Save for next run
+set(_GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE INTERNAL "CMAKE_INSTALL_PREFIX during last run")
+unset(_libdir_set)
+unset(__LAST_LIBDIR_DEFAULT)
+
+if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$"
+ AND NOT CMAKE_CROSSCOMPILING
+ AND NOT EXISTS "/etc/arch-release"
+ AND EXISTS "/etc/debian_version" # is this a debian system ?
+ AND "${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$")
+ # see https://refspecs.linuxfoundation.org/FHS_3.0/fhs-3.0.html#usrlibexec
+ # and https://www.debian.org/doc/debian-policy/ch-opersys#file-system-structure (section 9.1.1 bullet point 4)
+ _GNUInstallDirs_cache_path(CMAKE_INSTALL_LIBEXECDIR "${CMAKE_INSTALL_LIBDIR}"
+ "Program executables (${CMAKE_INSTALL_LIBDIR})")
+else()
+ _GNUInstallDirs_cache_path(CMAKE_INSTALL_LIBEXECDIR "libexec"
+ "Program executables (libexec)")
+endif()
+_GNUInstallDirs_cache_path(CMAKE_INSTALL_INCLUDEDIR "include"
+ "C header files (include)")
+_GNUInstallDirs_cache_path(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include"
+ "C header files for non-gcc (/usr/include)")
+_GNUInstallDirs_cache_path(CMAKE_INSTALL_DATAROOTDIR "share"
+ "Read-only architecture-independent data root (share)")
+
+#-----------------------------------------------------------------------------
+# Values whose defaults are relative to DATAROOTDIR. Store empty values in
+# the cache and store the defaults in local variables if the cache values are
+# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
+
+_GNUInstallDirs_cache_path_fallback(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}"
+ "Read-only architecture-independent data (DATAROOTDIR)")
+
+if(CMAKE_SYSTEM_NAME MATCHES "^(([^kF].*)?BSD|DragonFly)$")
+ _GNUInstallDirs_cache_path_fallback(CMAKE_INSTALL_INFODIR "info"
+ "Info documentation (info)")
+else()
+ _GNUInstallDirs_cache_path_fallback(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info"
+ "Info documentation (DATAROOTDIR/info)")
+endif()
+
+if(CMAKE_SYSTEM_NAME MATCHES "^(([^k].*)?BSD|DragonFly)$")
+ _GNUInstallDirs_cache_path_fallback(CMAKE_INSTALL_MANDIR "man"
+ "Man documentation (man)")
+else()
+ _GNUInstallDirs_cache_path_fallback(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man"
+ "Man documentation (DATAROOTDIR/man)")
+endif()
+
+_GNUInstallDirs_cache_path_fallback(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale"
+ "Locale-dependent data (DATAROOTDIR/locale)")
+_GNUInstallDirs_cache_path_fallback(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}"
+ "Documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
+
+_GNUInstallDirs_cache_path_fallback(CMAKE_INSTALL_RUNSTATEDIR "${CMAKE_INSTALL_LOCALSTATEDIR}/run"
+ "Run-time variable data (LOCALSTATEDIR/run)")
+
+#-----------------------------------------------------------------------------
+
+mark_as_advanced(
+ CMAKE_INSTALL_BINDIR
+ CMAKE_INSTALL_SBINDIR
+ CMAKE_INSTALL_LIBEXECDIR
+ CMAKE_INSTALL_SYSCONFDIR
+ CMAKE_INSTALL_SHAREDSTATEDIR
+ CMAKE_INSTALL_LOCALSTATEDIR
+ CMAKE_INSTALL_RUNSTATEDIR
+ CMAKE_INSTALL_LIBDIR
+ CMAKE_INSTALL_INCLUDEDIR
+ CMAKE_INSTALL_OLDINCLUDEDIR
+ CMAKE_INSTALL_DATAROOTDIR
+ CMAKE_INSTALL_DATADIR
+ CMAKE_INSTALL_INFODIR
+ CMAKE_INSTALL_LOCALEDIR
+ CMAKE_INSTALL_MANDIR
+ CMAKE_INSTALL_DOCDIR
+ )
+
+macro(GNUInstallDirs_get_absolute_install_dir absvar var)
+ set(GGAID_extra_args ${ARGN})
+ list(LENGTH GGAID_extra_args GGAID_extra_arg_count)
+ if(GGAID_extra_arg_count GREATER 0)
+ list(GET GGAID_extra_args 0 GGAID_dir)
+ else()
+ # Historical behaviour: use ${dir} from caller's scope
+ set(GGAID_dir "${dir}")
+ message(AUTHOR_WARNING
+ "GNUInstallDirs_get_absolute_install_dir called without third argument. "
+ "Using \${dir} from the caller's scope for compatibility with CMake 3.19 and below.")
+ endif()
+
+ if(NOT IS_ABSOLUTE "${${var}}")
+ # Handle special cases:
+ # - CMAKE_INSTALL_PREFIX == /
+ # - CMAKE_INSTALL_PREFIX == /usr
+ # - CMAKE_INSTALL_PREFIX == /opt/...
+ if("${CMAKE_INSTALL_PREFIX}" STREQUAL "/")
+ if("${GGAID_dir}" STREQUAL "SYSCONFDIR" OR "${GGAID_dir}" STREQUAL "LOCALSTATEDIR" OR "${GGAID_dir}" STREQUAL "RUNSTATEDIR")
+ set(${absvar} "/${${var}}")
+ else()
+ if (NOT "${${var}}" MATCHES "^usr/")
+ set(${var} "usr/${${var}}")
+ endif()
+ set(${absvar} "/${${var}}")
+ endif()
+ elseif("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$")
+ if("${GGAID_dir}" STREQUAL "SYSCONFDIR" OR "${GGAID_dir}" STREQUAL "LOCALSTATEDIR" OR "${GGAID_dir}" STREQUAL "RUNSTATEDIR")
+ set(${absvar} "/${${var}}")
+ else()
+ set(${absvar} "${CMAKE_INSTALL_PREFIX}/${${var}}")
+ endif()
+ elseif("${CMAKE_INSTALL_PREFIX}" MATCHES "^/opt/.*")
+ if("${GGAID_dir}" STREQUAL "SYSCONFDIR" OR "${GGAID_dir}" STREQUAL "LOCALSTATEDIR" OR "${GGAID_dir}" STREQUAL "RUNSTATEDIR")
+ set(${absvar} "/${${var}}${CMAKE_INSTALL_PREFIX}")
+ else()
+ set(${absvar} "${CMAKE_INSTALL_PREFIX}/${${var}}")
+ endif()
+ else()
+ set(${absvar} "${CMAKE_INSTALL_PREFIX}/${${var}}")
+ endif()
+ else()
+ set(${absvar} "${${var}}")
+ endif()
+
+ unset(GGAID_dir)
+ unset(GGAID_extra_arg_count)
+ unset(GGAID_extra_args)
+endmacro()
+
+# Result directories
+#
+foreach(dir
+ BINDIR
+ SBINDIR
+ LIBEXECDIR
+ SYSCONFDIR
+ SHAREDSTATEDIR
+ LOCALSTATEDIR
+ RUNSTATEDIR
+ LIBDIR
+ INCLUDEDIR
+ OLDINCLUDEDIR
+ DATAROOTDIR
+ DATADIR
+ INFODIR
+ LOCALEDIR
+ MANDIR
+ DOCDIR
+ )
+ GNUInstallDirs_get_absolute_install_dir(CMAKE_INSTALL_FULL_${dir} CMAKE_INSTALL_${dir} ${dir})
+endforeach()
+
+cmake_policy(POP)
diff --git a/Modules/GenerateExportHeader.cmake b/Modules/GenerateExportHeader.cmake
new file mode 100644
index 0000000..a9a9c59
--- /dev/null
+++ b/Modules/GenerateExportHeader.cmake
@@ -0,0 +1,455 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+GenerateExportHeader
+--------------------
+
+Function for generation of export macros for libraries
+
+This module provides the function ``GENERATE_EXPORT_HEADER()``.
+
+.. versionadded:: 3.12
+ Added support for C projects. Previous versions supported C++ project only.
+
+The ``GENERATE_EXPORT_HEADER`` function can be used to generate a file
+suitable for preprocessor inclusion which contains EXPORT macros to be
+used in library classes::
+
+ GENERATE_EXPORT_HEADER( LIBRARY_TARGET
+ [BASE_NAME <base_name>]
+ [EXPORT_MACRO_NAME <export_macro_name>]
+ [EXPORT_FILE_NAME <export_file_name>]
+ [DEPRECATED_MACRO_NAME <deprecated_macro_name>]
+ [NO_EXPORT_MACRO_NAME <no_export_macro_name>]
+ [INCLUDE_GUARD_NAME <include_guard_name>]
+ [STATIC_DEFINE <static_define>]
+ [NO_DEPRECATED_MACRO_NAME <no_deprecated_macro_name>]
+ [DEFINE_NO_DEPRECATED]
+ [PREFIX_NAME <prefix_name>]
+ [CUSTOM_CONTENT_FROM_VARIABLE <variable>]
+ )
+
+The target properties :prop_tgt:`CXX_VISIBILITY_PRESET <<LANG>_VISIBILITY_PRESET>`
+and :prop_tgt:`VISIBILITY_INLINES_HIDDEN` can be used to add the appropriate
+compile flags for targets. See the documentation of those target properties,
+and the convenience variables
+:variable:`CMAKE_CXX_VISIBILITY_PRESET <CMAKE_<LANG>_VISIBILITY_PRESET>` and
+:variable:`CMAKE_VISIBILITY_INLINES_HIDDEN`.
+
+By default ``GENERATE_EXPORT_HEADER()`` generates macro names in a file
+name determined by the name of the library. This means that in the
+simplest case, users of ``GenerateExportHeader`` will be equivalent to:
+
+.. code-block:: cmake
+
+ set(CMAKE_CXX_VISIBILITY_PRESET hidden)
+ set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
+ add_library(somelib someclass.cpp)
+ generate_export_header(somelib)
+ install(TARGETS somelib DESTINATION ${LIBRARY_INSTALL_DIR})
+ install(FILES
+ someclass.h
+ ${PROJECT_BINARY_DIR}/somelib_export.h DESTINATION ${INCLUDE_INSTALL_DIR}
+ )
+
+
+And in the ABI header files:
+
+.. code-block:: c++
+
+ #include "somelib_export.h"
+ class SOMELIB_EXPORT SomeClass {
+ ...
+ };
+
+
+The CMake fragment will generate a file in the
+``${CMAKE_CURRENT_BINARY_DIR}`` called ``somelib_export.h`` containing the
+macros ``SOMELIB_EXPORT``, ``SOMELIB_NO_EXPORT``, ``SOMELIB_DEPRECATED``,
+``SOMELIB_DEPRECATED_EXPORT`` and ``SOMELIB_DEPRECATED_NO_EXPORT``.
+They will be followed by content taken from the variable specified by
+the ``CUSTOM_CONTENT_FROM_VARIABLE`` option, if any.
+The resulting file should be installed with other headers in the library.
+
+The ``BASE_NAME`` argument can be used to override the file name and the
+names used for the macros:
+
+.. code-block:: cmake
+
+ add_library(somelib someclass.cpp)
+ generate_export_header(somelib
+ BASE_NAME other_name
+ )
+
+
+Generates a file called ``other_name_export.h`` containing the macros
+``OTHER_NAME_EXPORT``, ``OTHER_NAME_NO_EXPORT`` and ``OTHER_NAME_DEPRECATED``
+etc.
+
+The ``BASE_NAME`` may be overridden by specifying other options in the
+function. For example:
+
+.. code-block:: cmake
+
+ add_library(somelib someclass.cpp)
+ generate_export_header(somelib
+ EXPORT_MACRO_NAME OTHER_NAME_EXPORT
+ )
+
+
+creates the macro ``OTHER_NAME_EXPORT`` instead of ``SOMELIB_EXPORT``, but
+other macros and the generated file name is as default:
+
+.. code-block:: cmake
+
+ add_library(somelib someclass.cpp)
+ generate_export_header(somelib
+ DEPRECATED_MACRO_NAME KDE_DEPRECATED
+ )
+
+
+creates the macro ``KDE_DEPRECATED`` instead of ``SOMELIB_DEPRECATED``.
+
+If ``LIBRARY_TARGET`` is a static library, macros are defined without
+values.
+
+If the same sources are used to create both a shared and a static
+library, the uppercased symbol ``${BASE_NAME}_STATIC_DEFINE`` should be
+used when building the static library:
+
+.. code-block:: cmake
+
+ add_library(shared_variant SHARED ${lib_SRCS})
+ add_library(static_variant ${lib_SRCS})
+ generate_export_header(shared_variant BASE_NAME libshared_and_static)
+ set_target_properties(static_variant PROPERTIES
+ COMPILE_FLAGS -DLIBSHARED_AND_STATIC_STATIC_DEFINE)
+
+This will cause the export macros to expand to nothing when building
+the static library.
+
+If ``DEFINE_NO_DEPRECATED`` is specified, then a macro
+``${BASE_NAME}_NO_DEPRECATED`` will be defined This macro can be used to
+remove deprecated code from preprocessor output:
+
+.. code-block:: cmake
+
+ option(EXCLUDE_DEPRECATED "Exclude deprecated parts of the library" FALSE)
+ if (EXCLUDE_DEPRECATED)
+ set(NO_BUILD_DEPRECATED DEFINE_NO_DEPRECATED)
+ endif()
+ generate_export_header(somelib ${NO_BUILD_DEPRECATED})
+
+
+And then in somelib:
+
+.. code-block:: c++
+
+ class SOMELIB_EXPORT SomeClass
+ {
+ public:
+ #ifndef SOMELIB_NO_DEPRECATED
+ SOMELIB_DEPRECATED void oldMethod();
+ #endif
+ };
+
+.. code-block:: c++
+
+ #ifndef SOMELIB_NO_DEPRECATED
+ void SomeClass::oldMethod() { }
+ #endif
+
+
+If ``PREFIX_NAME`` is specified, the argument will be used as a prefix to
+all generated macros.
+
+For example:
+
+.. code-block:: cmake
+
+ generate_export_header(somelib PREFIX_NAME VTK_)
+
+Generates the macros ``VTK_SOMELIB_EXPORT`` etc.
+
+.. versionadded:: 3.1
+ Library target can be an ``OBJECT`` library.
+
+.. versionadded:: 3.7
+ Added the ``CUSTOM_CONTENT_FROM_VARIABLE`` option.
+
+.. versionadded:: 3.11
+ Added the ``INCLUDE_GUARD_NAME`` option.
+
+::
+
+ ADD_COMPILER_EXPORT_FLAGS( [<output_variable>] )
+
+.. deprecated:: 3.0
+ Set the target properties
+ :prop_tgt:`CXX_VISIBILITY_PRESET <<LANG>_VISIBILITY_PRESET>` and
+ :prop_tgt:`VISIBILITY_INLINES_HIDDEN` instead.
+
+The ``ADD_COMPILER_EXPORT_FLAGS`` function adds ``-fvisibility=hidden`` to
+:variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` if supported, and is a no-op
+on Windows which does not need extra compiler flags for exporting support.
+You may optionally pass a single argument to ``ADD_COMPILER_EXPORT_FLAGS``
+that will be populated with the ``CXX_FLAGS`` required to enable visibility
+support for the compiler/architecture in use.
+#]=======================================================================]
+
+include(CheckCCompilerFlag)
+include(CheckCXXCompilerFlag)
+
+# TODO: Install this macro separately?
+macro(_check_cxx_compiler_attribute _ATTRIBUTE _RESULT)
+ check_cxx_source_compiles("${_ATTRIBUTE} int somefunc() { return 0; }
+ int main() { return somefunc();}" ${_RESULT}
+ )
+endmacro()
+
+# TODO: Install this macro separately?
+macro(_check_c_compiler_attribute _ATTRIBUTE _RESULT)
+ check_c_source_compiles("${_ATTRIBUTE} int somefunc() { return 0; }
+ int main() { return somefunc();}" ${_RESULT}
+ )
+endmacro()
+
+macro(_test_compiler_hidden_visibility)
+
+ if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.2")
+ set(GCC_TOO_OLD TRUE)
+ elseif(CMAKE_COMPILER_IS_GNUCC AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.2")
+ set(GCC_TOO_OLD TRUE)
+ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12.0")
+ set(_INTEL_TOO_OLD TRUE)
+ endif()
+
+ # Exclude XL here because it misinterprets -fvisibility=hidden even though
+ # the check_cxx_compiler_flag passes
+ if(NOT GCC_TOO_OLD
+ AND NOT _INTEL_TOO_OLD
+ AND NOT WIN32
+ AND NOT CYGWIN
+ AND NOT CMAKE_CXX_COMPILER_ID MATCHES XL
+ AND NOT CMAKE_CXX_COMPILER_ID MATCHES "^(PGI|NVHPC)$"
+ AND NOT CMAKE_CXX_COMPILER_ID MATCHES Watcom)
+ if (CMAKE_CXX_COMPILER_LOADED)
+ check_cxx_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY)
+ check_cxx_compiler_flag(-fvisibility-inlines-hidden
+ COMPILER_HAS_HIDDEN_INLINE_VISIBILITY)
+ else()
+ check_c_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY)
+ check_c_compiler_flag(-fvisibility-inlines-hidden
+ COMPILER_HAS_HIDDEN_INLINE_VISIBILITY)
+ endif()
+ endif()
+endmacro()
+
+macro(_test_compiler_has_deprecated)
+ # NOTE: Some Embarcadero compilers silently compile __declspec(deprecated)
+ # without error, but this is not a documented feature and the attribute does
+ # not actually generate any warnings.
+ if(CMAKE_CXX_COMPILER_ID MATCHES Borland
+ OR CMAKE_CXX_COMPILER_ID MATCHES Embarcadero
+ OR CMAKE_CXX_COMPILER_ID MATCHES HP
+ OR GCC_TOO_OLD
+ OR CMAKE_CXX_COMPILER_ID MATCHES "^(PGI|NVHPC)$"
+ OR CMAKE_CXX_COMPILER_ID MATCHES Watcom)
+ set(COMPILER_HAS_DEPRECATED "" CACHE INTERNAL
+ "Compiler support for a deprecated attribute")
+ else()
+ if (CMAKE_CXX_COMPILER_LOADED)
+ _check_cxx_compiler_attribute("__attribute__((__deprecated__))"
+ COMPILER_HAS_DEPRECATED_ATTR)
+ if(COMPILER_HAS_DEPRECATED_ATTR)
+ set(COMPILER_HAS_DEPRECATED "${COMPILER_HAS_DEPRECATED_ATTR}"
+ CACHE INTERNAL "Compiler support for a deprecated attribute")
+ else()
+ _check_cxx_compiler_attribute("__declspec(deprecated)"
+ COMPILER_HAS_DEPRECATED)
+ endif()
+ else()
+ _check_c_compiler_attribute("__attribute__((__deprecated__))"
+ COMPILER_HAS_DEPRECATED_ATTR)
+ if(COMPILER_HAS_DEPRECATED_ATTR)
+ set(COMPILER_HAS_DEPRECATED "${COMPILER_HAS_DEPRECATED_ATTR}"
+ CACHE INTERNAL "Compiler support for a deprecated attribute")
+ else()
+ _check_c_compiler_attribute("__declspec(deprecated)"
+ COMPILER_HAS_DEPRECATED)
+ endif()
+
+ endif()
+ endif()
+endmacro()
+
+get_filename_component(_GENERATE_EXPORT_HEADER_MODULE_DIR
+ "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+macro(_DO_SET_MACRO_VALUES TARGET_LIBRARY)
+ set(DEFINE_DEPRECATED)
+ set(DEFINE_EXPORT)
+ set(DEFINE_IMPORT)
+ set(DEFINE_NO_EXPORT)
+
+ if (COMPILER_HAS_DEPRECATED_ATTR)
+ set(DEFINE_DEPRECATED "__attribute__ ((__deprecated__))")
+ elseif(COMPILER_HAS_DEPRECATED)
+ set(DEFINE_DEPRECATED "__declspec(deprecated)")
+ endif()
+
+ get_property(type TARGET ${TARGET_LIBRARY} PROPERTY TYPE)
+
+ if(NOT ${type} STREQUAL "STATIC_LIBRARY")
+ if(WIN32 OR CYGWIN)
+ set(DEFINE_EXPORT "__declspec(dllexport)")
+ set(DEFINE_IMPORT "__declspec(dllimport)")
+ elseif(COMPILER_HAS_HIDDEN_VISIBILITY)
+ set(DEFINE_EXPORT "__attribute__((visibility(\"default\")))")
+ set(DEFINE_IMPORT "__attribute__((visibility(\"default\")))")
+ set(DEFINE_NO_EXPORT "__attribute__((visibility(\"hidden\")))")
+ endif()
+ endif()
+endmacro()
+
+macro(_DO_GENERATE_EXPORT_HEADER TARGET_LIBRARY)
+ # Option overrides
+ set(options DEFINE_NO_DEPRECATED)
+ set(oneValueArgs PREFIX_NAME BASE_NAME EXPORT_MACRO_NAME EXPORT_FILE_NAME
+ DEPRECATED_MACRO_NAME NO_EXPORT_MACRO_NAME STATIC_DEFINE
+ NO_DEPRECATED_MACRO_NAME CUSTOM_CONTENT_FROM_VARIABLE INCLUDE_GUARD_NAME)
+ set(multiValueArgs)
+
+ cmake_parse_arguments(_GEH "${options}" "${oneValueArgs}" "${multiValueArgs}"
+ ${ARGN})
+
+ set(BASE_NAME "${TARGET_LIBRARY}")
+
+ if(_GEH_BASE_NAME)
+ set(BASE_NAME ${_GEH_BASE_NAME})
+ endif()
+
+ string(TOUPPER ${BASE_NAME} BASE_NAME_UPPER)
+ string(TOLOWER ${BASE_NAME} BASE_NAME_LOWER)
+
+ # Default options
+ set(EXPORT_MACRO_NAME "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_EXPORT")
+ set(NO_EXPORT_MACRO_NAME "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_NO_EXPORT")
+ set(EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${BASE_NAME_LOWER}_export.h")
+ set(DEPRECATED_MACRO_NAME "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_DEPRECATED")
+ set(STATIC_DEFINE "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_STATIC_DEFINE")
+ set(NO_DEPRECATED_MACRO_NAME
+ "${_GEH_PREFIX_NAME}${BASE_NAME_UPPER}_NO_DEPRECATED")
+
+ if(_GEH_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to GENERATE_EXPORT_HEADER(): \"${_GEH_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if(_GEH_EXPORT_MACRO_NAME)
+ set(EXPORT_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_EXPORT_MACRO_NAME})
+ endif()
+ string(MAKE_C_IDENTIFIER ${EXPORT_MACRO_NAME} EXPORT_MACRO_NAME)
+ if(_GEH_EXPORT_FILE_NAME)
+ if(IS_ABSOLUTE ${_GEH_EXPORT_FILE_NAME})
+ set(EXPORT_FILE_NAME ${_GEH_EXPORT_FILE_NAME})
+ else()
+ set(EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${_GEH_EXPORT_FILE_NAME}")
+ endif()
+ endif()
+ if(_GEH_DEPRECATED_MACRO_NAME)
+ set(DEPRECATED_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_DEPRECATED_MACRO_NAME})
+ endif()
+ string(MAKE_C_IDENTIFIER ${DEPRECATED_MACRO_NAME} DEPRECATED_MACRO_NAME)
+ if(_GEH_NO_EXPORT_MACRO_NAME)
+ set(NO_EXPORT_MACRO_NAME ${_GEH_PREFIX_NAME}${_GEH_NO_EXPORT_MACRO_NAME})
+ endif()
+ string(MAKE_C_IDENTIFIER ${NO_EXPORT_MACRO_NAME} NO_EXPORT_MACRO_NAME)
+ if(_GEH_STATIC_DEFINE)
+ set(STATIC_DEFINE ${_GEH_PREFIX_NAME}${_GEH_STATIC_DEFINE})
+ endif()
+ string(MAKE_C_IDENTIFIER ${STATIC_DEFINE} STATIC_DEFINE)
+
+ if(_GEH_DEFINE_NO_DEPRECATED)
+ set(DEFINE_NO_DEPRECATED 1)
+ else()
+ set(DEFINE_NO_DEPRECATED 0)
+ endif()
+
+ if(_GEH_NO_DEPRECATED_MACRO_NAME)
+ set(NO_DEPRECATED_MACRO_NAME
+ ${_GEH_PREFIX_NAME}${_GEH_NO_DEPRECATED_MACRO_NAME})
+ endif()
+ string(MAKE_C_IDENTIFIER ${NO_DEPRECATED_MACRO_NAME} NO_DEPRECATED_MACRO_NAME)
+
+ if(_GEH_INCLUDE_GUARD_NAME)
+ set(INCLUDE_GUARD_NAME ${_GEH_INCLUDE_GUARD_NAME})
+ else()
+ set(INCLUDE_GUARD_NAME "${EXPORT_MACRO_NAME}_H")
+ endif()
+
+ get_target_property(EXPORT_IMPORT_CONDITION ${TARGET_LIBRARY} DEFINE_SYMBOL)
+
+ if(NOT EXPORT_IMPORT_CONDITION)
+ set(EXPORT_IMPORT_CONDITION ${TARGET_LIBRARY}_EXPORTS)
+ endif()
+ string(MAKE_C_IDENTIFIER ${EXPORT_IMPORT_CONDITION} EXPORT_IMPORT_CONDITION)
+
+ if(_GEH_CUSTOM_CONTENT_FROM_VARIABLE)
+ if(DEFINED "${_GEH_CUSTOM_CONTENT_FROM_VARIABLE}")
+ set(CUSTOM_CONTENT "${${_GEH_CUSTOM_CONTENT_FROM_VARIABLE}}")
+ else()
+ set(CUSTOM_CONTENT "")
+ endif()
+ endif()
+
+ configure_file("${_GENERATE_EXPORT_HEADER_MODULE_DIR}/exportheader.cmake.in"
+ "${EXPORT_FILE_NAME}" @ONLY)
+endmacro()
+
+function(GENERATE_EXPORT_HEADER TARGET_LIBRARY)
+ get_property(type TARGET ${TARGET_LIBRARY} PROPERTY TYPE)
+ if(NOT ${type} STREQUAL "STATIC_LIBRARY"
+ AND NOT ${type} STREQUAL "SHARED_LIBRARY"
+ AND NOT ${type} STREQUAL "OBJECT_LIBRARY"
+ AND NOT ${type} STREQUAL "MODULE_LIBRARY")
+ message(WARNING "This macro can only be used with libraries")
+ return()
+ endif()
+ _test_compiler_hidden_visibility()
+ _test_compiler_has_deprecated()
+ _do_set_macro_values(${TARGET_LIBRARY})
+ _do_generate_export_header(${TARGET_LIBRARY} ${ARGN})
+endfunction()
+
+function(add_compiler_export_flags)
+ if(NOT CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12)
+ message(DEPRECATION "The add_compiler_export_flags function is obsolete. Use the CXX_VISIBILITY_PRESET and VISIBILITY_INLINES_HIDDEN target properties instead.")
+ endif()
+
+ _test_compiler_hidden_visibility()
+ _test_compiler_has_deprecated()
+
+ option(USE_COMPILER_HIDDEN_VISIBILITY
+ "Use HIDDEN visibility support if available." ON)
+ mark_as_advanced(USE_COMPILER_HIDDEN_VISIBILITY)
+ if(NOT (USE_COMPILER_HIDDEN_VISIBILITY AND COMPILER_HAS_HIDDEN_VISIBILITY))
+ # Just return if there are no flags to add.
+ return()
+ endif()
+
+ set (EXTRA_FLAGS "-fvisibility=hidden")
+
+ if(COMPILER_HAS_HIDDEN_INLINE_VISIBILITY)
+ set (EXTRA_FLAGS "${EXTRA_FLAGS} -fvisibility-inlines-hidden")
+ endif()
+
+ # Either return the extra flags needed in the supplied argument, or to the
+ # CMAKE_CXX_FLAGS if no argument is supplied.
+ if(ARGC GREATER 0)
+ set(${ARGV0} "${EXTRA_FLAGS}" PARENT_SCOPE)
+ else()
+ string(APPEND CMAKE_CXX_FLAGS " ${EXTRA_FLAGS}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/Modules/GetPrerequisites.cmake b/Modules/GetPrerequisites.cmake
new file mode 100644
index 0000000..ed5c38b
--- /dev/null
+++ b/Modules/GetPrerequisites.cmake
@@ -0,0 +1,1048 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+GetPrerequisites
+----------------
+
+.. deprecated:: 3.16
+
+ Use :command:`file(GET_RUNTIME_DEPENDENCIES)` instead.
+
+Functions to analyze and list executable file prerequisites.
+
+This module provides functions to list the .dll, .dylib or .so files
+that an executable or shared library file depends on. (Its
+prerequisites.)
+
+It uses various tools to obtain the list of required shared library
+files:
+
+::
+
+ dumpbin (Windows)
+ objdump (MinGW on Windows)
+ ldd (Linux/Unix)
+ otool (Mac OSX)
+
+.. versionchanged:: 3.16
+ The tool specified by ``CMAKE_OBJDUMP`` will be used, if set.
+
+The following functions are provided by this module:
+
+::
+
+ get_prerequisites
+ list_prerequisites
+ list_prerequisites_by_glob
+ gp_append_unique
+ is_file_executable
+ gp_item_default_embedded_path
+ (projects can override with gp_item_default_embedded_path_override)
+ gp_resolve_item
+ (projects can override with gp_resolve_item_override)
+ gp_resolved_file_type
+ (projects can override with gp_resolved_file_type_override)
+ gp_file_type
+
+::
+
+ GET_PREREQUISITES(<target> <prerequisites_var> <exclude_system> <recurse>
+ <exepath> <dirs> [<rpaths>])
+
+Get the list of shared library files required by <target>. The list
+in the variable named <prerequisites_var> should be empty on first
+entry to this function. On exit, <prerequisites_var> will contain the
+list of required shared library files.
+
+<target> is the full path to an executable file. <prerequisites_var>
+is the name of a CMake variable to contain the results.
+<exclude_system> must be 0 or 1 indicating whether to include or
+exclude "system" prerequisites. If <recurse> is set to 1 all
+prerequisites will be found recursively, if set to 0 only direct
+prerequisites are listed. <exepath> is the path to the top level
+executable used for @executable_path replacement on the Mac. <dirs> is
+a list of paths where libraries might be found: these paths are
+searched first when a target without any path info is given. Then
+standard system locations are also searched: PATH, Framework
+locations, /usr/lib...
+
+.. versionadded:: 3.14
+ The variable GET_PREREQUISITES_VERBOSE can be set to true to enable verbose
+ output.
+
+::
+
+ LIST_PREREQUISITES(<target> [<recurse> [<exclude_system> [<verbose>]]])
+
+Print a message listing the prerequisites of <target>.
+
+<target> is the name of a shared library or executable target or the
+full path to a shared library or executable file. If <recurse> is set
+to 1 all prerequisites will be found recursively, if set to 0 only
+direct prerequisites are listed. <exclude_system> must be 0 or 1
+indicating whether to include or exclude "system" prerequisites. With
+<verbose> set to 0 only the full path names of the prerequisites are
+printed, set to 1 extra informatin will be displayed.
+
+::
+
+ LIST_PREREQUISITES_BY_GLOB(<glob_arg> <glob_exp>)
+
+Print the prerequisites of shared library and executable files
+matching a globbing pattern. <glob_arg> is GLOB or GLOB_RECURSE and
+<glob_exp> is a globbing expression used with "file(GLOB" or
+"file(GLOB_RECURSE" to retrieve a list of matching files. If a
+matching file is executable, its prerequisites are listed.
+
+Any additional (optional) arguments provided are passed along as the
+optional arguments to the list_prerequisites calls.
+
+::
+
+ GP_APPEND_UNIQUE(<list_var> <value>)
+
+Append <value> to the list variable <list_var> only if the value is
+not already in the list.
+
+::
+
+ IS_FILE_EXECUTABLE(<file> <result_var>)
+
+Return 1 in <result_var> if <file> is a binary executable, 0
+otherwise.
+
+::
+
+ GP_ITEM_DEFAULT_EMBEDDED_PATH(<item> <default_embedded_path_var>)
+
+Return the path that others should refer to the item by when the item
+is embedded inside a bundle.
+
+Override on a per-project basis by providing a project-specific
+gp_item_default_embedded_path_override function.
+
+::
+
+ GP_RESOLVE_ITEM(<context> <item> <exepath> <dirs> <resolved_item_var>
+ [<rpaths>])
+
+Resolve an item into an existing full path file.
+
+Override on a per-project basis by providing a project-specific
+gp_resolve_item_override function.
+
+::
+
+ GP_RESOLVED_FILE_TYPE(<original_file> <file> <exepath> <dirs> <type_var>
+ [<rpaths>])
+
+Return the type of <file> with respect to <original_file>. String
+describing type of prerequisite is returned in variable named
+<type_var>.
+
+Use <exepath> and <dirs> if necessary to resolve non-absolute <file>
+values -- but only for non-embedded items.
+
+Possible types are:
+
+::
+
+ system
+ local
+ embedded
+ other
+
+Override on a per-project basis by providing a project-specific
+gp_resolved_file_type_override function.
+
+::
+
+ GP_FILE_TYPE(<original_file> <file> <type_var>)
+
+Return the type of <file> with respect to <original_file>. String
+describing type of prerequisite is returned in variable named
+<type_var>.
+
+Possible types are:
+
+::
+
+ system
+ local
+ embedded
+ other
+#]=======================================================================]
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+function(gp_append_unique list_var value)
+ if(NOT value IN_LIST ${list_var})
+ set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+
+function(is_file_executable file result_var)
+ #
+ # A file is not executable until proven otherwise:
+ #
+ set(${result_var} 0 PARENT_SCOPE)
+
+ get_filename_component(file_full "${file}" ABSOLUTE)
+ string(TOLOWER "${file_full}" file_full_lower)
+
+ # If file name ends in .exe on Windows, *assume* executable:
+ #
+ if(WIN32 AND NOT UNIX)
+ if("${file_full_lower}" MATCHES "\\.exe$")
+ set(${result_var} 1 PARENT_SCOPE)
+ return()
+ endif()
+
+ # A clause could be added here that uses output or return value of dumpbin
+ # to determine ${result_var}. In 99%+? practical cases, the exe name
+ # match will be sufficient...
+ #
+ endif()
+
+ # Use the information returned from the Unix shell command "file" to
+ # determine if ${file_full} should be considered an executable file...
+ #
+ # If the file command's output contains "executable" and does *not* contain
+ # "text" then it is likely an executable suitable for prerequisite analysis
+ # via the get_prerequisites macro.
+ #
+ if(UNIX)
+ if(NOT file_cmd)
+ find_program(file_cmd "file")
+ mark_as_advanced(file_cmd)
+ endif()
+
+ if(file_cmd)
+ execute_process(COMMAND "${file_cmd}" "${file_full}"
+ RESULT_VARIABLE file_rv
+ OUTPUT_VARIABLE file_ov
+ ERROR_VARIABLE file_ev
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if(NOT file_rv STREQUAL "0")
+ message(FATAL_ERROR "${file_cmd} failed: ${file_rv}\n${file_ev}")
+ endif()
+
+ # Replace the name of the file in the output with a placeholder token
+ # (the string " _file_full_ ") so that just in case the path name of
+ # the file contains the word "text" or "executable" we are not fooled
+ # into thinking "the wrong thing" because the file name matches the
+ # other 'file' command output we are looking for...
+ #
+ string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}")
+ string(TOLOWER "${file_ov}" file_ov)
+
+ #message(STATUS "file_ov='${file_ov}'")
+ if("${file_ov}" MATCHES "executable")
+ #message(STATUS "executable!")
+ if("${file_ov}" MATCHES "text")
+ #message(STATUS "but text, so *not* a binary executable!")
+ else()
+ set(${result_var} 1 PARENT_SCOPE)
+ return()
+ endif()
+ endif()
+
+ # Also detect position independent executables on Linux,
+ # where "file" gives "shared object ... (uses shared libraries)"
+ if("${file_ov}" MATCHES "shared object.*\(uses shared libs\)")
+ set(${result_var} 1 PARENT_SCOPE)
+ return()
+ endif()
+
+ # "file" version 5.22 does not print "(used shared libraries)"
+ # but uses "interpreter"
+ if("${file_ov}" MATCHES "shared object.*interpreter")
+ set(${result_var} 1 PARENT_SCOPE)
+ return()
+ endif()
+
+ else()
+ message(STATUS "warning: No 'file' command, skipping execute_process...")
+ endif()
+ endif()
+endfunction()
+
+
+function(gp_item_default_embedded_path item default_embedded_path_var)
+
+ # On Windows and Linux, "embed" prerequisites in the same directory
+ # as the executable by default:
+ #
+ set(path "@executable_path")
+
+ # On the Mac, relative to the executable depending on the type
+ # of the thing we are embedding:
+ #
+ if(APPLE)
+ #
+ # The assumption here is that all executables in the bundle will be
+ # in same-level-directories inside the bundle. The parent directory
+ # of an executable inside the bundle should be MacOS or a sibling of
+ # MacOS and all embedded paths returned from here will begin with
+ # "@executable_path/../" and will work from all executables in all
+ # such same-level-directories inside the bundle.
+ #
+
+ # By default, embed things right next to the main bundle executable:
+ #
+ set(path "@executable_path/../../Contents/MacOS")
+
+ # Embed frameworks and .dylibs in the embedded "Frameworks" directory
+ # (sibling of MacOS):
+ #
+ if(item MATCHES "[^/]+\\.framework/" OR item MATCHES "\\.dylib$")
+ set(path "@executable_path/../Frameworks")
+ endif()
+ endif()
+
+ # Provide a hook so that projects can override the default embedded location
+ # of any given library by whatever logic they choose:
+ #
+ if(COMMAND gp_item_default_embedded_path_override)
+ gp_item_default_embedded_path_override("${item}" path)
+ endif()
+
+ set(${default_embedded_path_var} "${path}" PARENT_SCOPE)
+endfunction()
+
+
+function(gp_resolve_item context item exepath dirs resolved_item_var)
+ set(resolved 0)
+ set(resolved_item "${item}")
+ if(ARGC GREATER 5)
+ set(rpaths "${ARGV5}")
+ else()
+ set(rpaths "")
+ endif()
+
+ # Is it already resolved?
+ #
+ if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}")
+ set(resolved 1)
+ endif()
+
+ if(NOT resolved)
+ if(item MATCHES "^@executable_path")
+ #
+ # @executable_path references are assumed relative to exepath
+ #
+ string(REPLACE "@executable_path" "${exepath}" ri "${item}")
+ get_filename_component(ri "${ri}" ABSOLUTE)
+
+ if(EXISTS "${ri}")
+ #message(STATUS "info: embedded item exists (${ri})")
+ set(resolved 1)
+ set(resolved_item "${ri}")
+ else()
+ message(STATUS "warning: embedded item does not exist '${ri}'")
+ endif()
+ endif()
+ endif()
+
+ if(NOT resolved)
+ if(item MATCHES "^@loader_path")
+ #
+ # @loader_path references are assumed relative to the
+ # PATH of the given "context" (presumably another library)
+ #
+ get_filename_component(contextpath "${context}" PATH)
+ string(REPLACE "@loader_path" "${contextpath}" ri "${item}")
+ get_filename_component(ri "${ri}" ABSOLUTE)
+
+ if(EXISTS "${ri}")
+ #message(STATUS "info: embedded item exists (${ri})")
+ set(resolved 1)
+ set(resolved_item "${ri}")
+ else()
+ message(STATUS "warning: embedded item does not exist '${ri}'")
+ endif()
+ endif()
+ endif()
+
+ if(NOT resolved)
+ if(item MATCHES "^@rpath")
+ #
+ # @rpath references are relative to the paths built into the binaries with -rpath
+ # We handle this case like we do for other Unixes
+ #
+ string(REPLACE "@rpath/" "" norpath_item "${item}")
+
+ set(ri "ri-NOTFOUND")
+ find_file(ri "${norpath_item}" ${exepath} ${dirs} ${rpaths} NO_DEFAULT_PATH)
+ if(ri)
+ #message(STATUS "info: 'find_file' in exepath/dirs/rpaths (${ri})")
+ set(resolved 1)
+ set(resolved_item "${ri}")
+ set(ri "ri-NOTFOUND")
+ endif()
+
+ endif()
+ endif()
+
+ if(NOT resolved)
+ set(ri "ri-NOTFOUND")
+ find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
+ find_file(ri "${item}" ${exepath} ${dirs} /usr/lib)
+
+ get_filename_component(basename_item "${item}" NAME)
+ find_file(ri "${basename_item}" PATHS ${exepath} ${dirs} NO_DEFAULT_PATH)
+ find_file(ri "${basename_item}" PATHS /usr/lib)
+
+ if(ri)
+ #message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
+ set(resolved 1)
+ set(resolved_item "${ri}")
+ set(ri "ri-NOTFOUND")
+ endif()
+ endif()
+
+ if(NOT resolved)
+ if(item MATCHES "[^/]+\\.framework/")
+ set(fw "fw-NOTFOUND")
+ find_file(fw "${item}"
+ "~/Library/Frameworks"
+ "/Library/Frameworks"
+ "/System/Library/Frameworks"
+ )
+ if(fw)
+ #message(STATUS "info: 'find_file' found framework (${fw})")
+ set(resolved 1)
+ set(resolved_item "${fw}")
+ set(fw "fw-NOTFOUND")
+ endif()
+ endif()
+ endif()
+
+ # Using find_program on Windows will find dll files that are in the PATH.
+ # (Converting simple file names into full path names if found.)
+ #
+ if(WIN32 AND NOT UNIX)
+ if(NOT resolved)
+ set(ri "ri-NOTFOUND")
+ find_program(ri "${item}" PATHS ${exepath} ${dirs} NO_DEFAULT_PATH)
+ find_program(ri "${item}" PATHS ${exepath} ${dirs})
+ if(ri)
+ #message(STATUS "info: 'find_program' in exepath/dirs (${ri})")
+ set(resolved 1)
+ set(resolved_item "${ri}")
+ set(ri "ri-NOTFOUND")
+ endif()
+ endif()
+ endif()
+
+ # Provide a hook so that projects can override item resolution
+ # by whatever logic they choose:
+ #
+ if(COMMAND gp_resolve_item_override)
+ gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved)
+ endif()
+
+ if(NOT resolved)
+ message(STATUS "
+warning: cannot resolve item '${item}'
+
+ possible problems:
+ need more directories?
+ need to use InstallRequiredSystemLibraries?
+ run in install tree instead of build tree?
+")
+# message(STATUS "
+#******************************************************************************
+#warning: cannot resolve item '${item}'
+#
+# possible problems:
+# need more directories?
+# need to use InstallRequiredSystemLibraries?
+# run in install tree instead of build tree?
+#
+# context='${context}'
+# item='${item}'
+# exepath='${exepath}'
+# dirs='${dirs}'
+# resolved_item_var='${resolved_item_var}'
+#******************************************************************************
+#")
+ endif()
+
+ set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE)
+endfunction()
+
+
+function(gp_resolved_file_type original_file file exepath dirs type_var)
+ if(ARGC GREATER 5)
+ set(rpaths "${ARGV5}")
+ else()
+ set(rpaths "")
+ endif()
+ #message(STATUS "**")
+
+ if(NOT IS_ABSOLUTE "${original_file}")
+ message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file")
+ endif()
+ if(IS_ABSOLUTE "${original_file}")
+ get_filename_component(original_file "${original_file}" ABSOLUTE) # canonicalize path
+ endif()
+
+ set(is_embedded 0)
+ set(is_local 0)
+ set(is_system 0)
+
+ set(resolved_file "${file}")
+
+ if("${file}" MATCHES "^@(executable|loader)_path")
+ set(is_embedded 1)
+ endif()
+
+ if(NOT is_embedded)
+ if(NOT IS_ABSOLUTE "${file}")
+ gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file "${rpaths}")
+ endif()
+ if(IS_ABSOLUTE "${resolved_file}")
+ get_filename_component(resolved_file "${resolved_file}" ABSOLUTE) # canonicalize path
+ endif()
+
+ string(TOLOWER "${original_file}" original_lower)
+ string(TOLOWER "${resolved_file}" lower)
+
+ if(UNIX)
+ if(resolved_file MATCHES "^(/lib/|/lib32/|/libx32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/libx32/|/usr/lib64/|/usr/X11R6/|/usr/bin/)")
+ set(is_system 1)
+ endif()
+ endif()
+
+ if(APPLE)
+ if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)")
+ set(is_system 1)
+ endif()
+ endif()
+
+ if(WIN32)
+ string(TOLOWER "$ENV{SystemRoot}" sysroot)
+ file(TO_CMAKE_PATH "${sysroot}" sysroot)
+
+ string(TOLOWER "$ENV{windir}" windir)
+ file(TO_CMAKE_PATH "${windir}" windir)
+
+ if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-|vcruntime)[^/]+dll)")
+ set(is_system 1)
+ endif()
+
+ if(UNIX)
+ # if cygwin, we can get the properly formed windows paths from cygpath
+ find_program(CYGPATH_EXECUTABLE cygpath)
+
+ if(CYGPATH_EXECUTABLE)
+ execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W
+ RESULT_VARIABLE env_rv
+ OUTPUT_VARIABLE env_windir
+ ERROR_VARIABLE env_ev
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(NOT env_rv STREQUAL "0")
+ message(FATAL_ERROR "${CYGPATH_EXECUTABLE} -W failed: ${env_rv}\n${env_ev}")
+ endif()
+ execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S
+ RESULT_VARIABLE env_rv
+ OUTPUT_VARIABLE env_sysdir
+ ERROR_VARIABLE env_ev
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(NOT env_rv STREQUAL "0")
+ message(FATAL_ERROR "${CYGPATH_EXECUTABLE} -S failed: ${env_rv}\n${env_ev}")
+ endif()
+ string(TOLOWER "${env_windir}" windir)
+ string(TOLOWER "${env_sysdir}" sysroot)
+
+ if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-|vcruntime)[^/]+dll)")
+ set(is_system 1)
+ endif()
+ endif()
+ endif()
+ endif()
+
+ if(NOT is_system)
+ get_filename_component(original_path "${original_lower}" PATH)
+ get_filename_component(path "${lower}" PATH)
+ if(original_path STREQUAL path)
+ set(is_local 1)
+ else()
+ string(LENGTH "${original_path}/" original_length)
+ string(LENGTH "${lower}" path_length)
+ if(${path_length} GREATER ${original_length})
+ string(SUBSTRING "${lower}" 0 ${original_length} path)
+ if("${original_path}/" STREQUAL path)
+ set(is_embedded 1)
+ endif()
+ endif()
+ endif()
+ endif()
+ endif()
+
+ # Return type string based on computed booleans:
+ #
+ set(type "other")
+
+ if(is_system)
+ set(type "system")
+ elseif(is_embedded)
+ set(type "embedded")
+ elseif(is_local)
+ set(type "local")
+ endif()
+
+ #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'")
+ #message(STATUS " type: '${type}'")
+
+ if(NOT is_embedded)
+ if(NOT IS_ABSOLUTE "${resolved_file}")
+ if(lower MATCHES "^(msvc|api-ms-win-|vcruntime)[^/]+dll" AND is_system)
+ message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'")
+ else()
+ message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect")
+ endif()
+ endif()
+ endif()
+
+ # Provide a hook so that projects can override the decision on whether a
+ # library belongs to the system or not by whatever logic they choose:
+ #
+ if(COMMAND gp_resolved_file_type_override)
+ gp_resolved_file_type_override("${resolved_file}" type)
+ endif()
+
+ set(${type_var} "${type}" PARENT_SCOPE)
+
+ #message(STATUS "**")
+endfunction()
+
+
+function(gp_file_type original_file file type_var)
+ if(NOT IS_ABSOLUTE "${original_file}")
+ message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file")
+ endif()
+
+ get_filename_component(exepath "${original_file}" PATH)
+
+ set(type "")
+ gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type)
+
+ set(${type_var} "${type}" PARENT_SCOPE)
+endfunction()
+
+
+function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs)
+ set(verbose 0)
+ set(eol_char "E")
+ if(ARGC GREATER 6)
+ set(rpaths "${ARGV6}")
+ else()
+ set(rpaths "")
+ endif()
+
+ if(GET_PREREQUISITES_VERBOSE)
+ set(verbose 1)
+ endif()
+
+ if(NOT IS_ABSOLUTE "${target}")
+ message("warning: target '${target}' is not absolute...")
+ endif()
+
+ if(NOT EXISTS "${target}")
+ message("warning: target '${target}' does not exist...")
+ return()
+ endif()
+
+ # Check for a script by extension (.bat,.sh,...) or if the file starts with "#!" (shebang)
+ file(READ ${target} file_contents LIMIT 5)
+ if(target MATCHES "\\.(bat|c?sh|bash|ksh|cmd)$" OR file_contents MATCHES "^#!")
+ message(STATUS "GetPrequisites(${target}) : ignoring script file")
+ # Clear var
+ set(${prerequisites_var} "" PARENT_SCOPE)
+ return()
+ endif()
+
+ set(gp_cmd_paths ${gp_cmd_paths}
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0;InstallDir]/../../VC/bin"
+ "$ENV{VS140COMNTOOLS}/../../VC/bin"
+ "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0;InstallDir]/../../VC/bin"
+ "$ENV{VS120COMNTOOLS}/../../VC/bin"
+ "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0;InstallDir]/../../VC/bin"
+ "$ENV{VS110COMNTOOLS}/../../VC/bin"
+ "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;InstallDir]/../../VC/bin"
+ "$ENV{VS100COMNTOOLS}/../../VC/bin"
+ "C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]/../../VC/bin"
+ "$ENV{VS90COMNTOOLS}/../../VC/bin"
+ "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin"
+ "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]/../../VC/bin"
+ "$ENV{VS80COMNTOOLS}/../../VC/bin"
+ "C:/Program Files/Microsoft Visual Studio 8/VC/BIN"
+ "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1;InstallDir]/../../VC7/bin"
+ "$ENV{VS71COMNTOOLS}/../../VC7/bin"
+ "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN"
+ "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN"
+ )
+
+ # <setup-gp_tool-vars>
+ #
+ # Try to choose the right tool by default. Caller can set gp_tool prior to
+ # calling this function to force using a different tool.
+ #
+ if(NOT gp_tool)
+ set(gp_tool "ldd")
+
+ if(APPLE)
+ set(gp_tool "otool")
+ endif()
+
+ if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har!
+ find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths})
+ if(gp_dumpbin)
+ set(gp_tool "dumpbin")
+ elseif(CMAKE_OBJDUMP) # Try harder. Maybe we're on MinGW
+ set(gp_tool "${CMAKE_OBJDUMP}")
+ else()
+ set(gp_tool "objdump")
+ endif()
+ endif()
+ endif()
+
+ find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths})
+
+ if(NOT gp_cmd)
+ message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...")
+ return()
+ endif()
+
+ set(gp_cmd_maybe_filter) # optional command to pre-filter gp_tool results
+
+ if(gp_tool MATCHES "ldd$")
+ set(gp_cmd_args "")
+ set(gp_regex "^[\t ]*[^\t ]+ =>[\t ]+([^\t\(]+)( \(.+\))?${eol_char}$")
+ set(gp_regex_error "not found${eol_char}$")
+ set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$")
+ set(gp_regex_cmp_count 1)
+ elseif(gp_tool MATCHES "otool$")
+ set(gp_cmd_args "-L")
+ set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)(, weak)?\\)${eol_char}$")
+ set(gp_regex_error "")
+ set(gp_regex_fallback "")
+ set(gp_regex_cmp_count 3)
+ elseif(gp_tool MATCHES "dumpbin$")
+ set(gp_cmd_args "/dependents")
+ set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$")
+ set(gp_regex_error "")
+ set(gp_regex_fallback "")
+ set(gp_regex_cmp_count 1)
+ elseif(gp_tool MATCHES "objdump$")
+ set(gp_cmd_args "-p")
+ set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$")
+ set(gp_regex_error "")
+ set(gp_regex_fallback "")
+ set(gp_regex_cmp_count 1)
+ # objdump generates copious output so we create a grep filter to pre-filter results
+ if(WIN32)
+ find_program(gp_grep_cmd findstr)
+ else()
+ find_program(gp_grep_cmd grep)
+ endif()
+ if(gp_grep_cmd)
+ set(gp_cmd_maybe_filter COMMAND ${gp_grep_cmd} "-a" "^[[:blank:]]*DLL Name: ")
+ endif()
+ else()
+ message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...")
+ message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'")
+ message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.")
+ return()
+ endif()
+
+
+ if(gp_tool MATCHES "dumpbin$")
+ # When running dumpbin, it also needs the "Common7/IDE" directory in the
+ # PATH. It will already be in the PATH if being run from a Visual Studio
+ # command prompt. Add it to the PATH here in case we are running from a
+ # different command prompt.
+ #
+ get_filename_component(gp_cmd_dir "${gp_cmd}" PATH)
+ get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE)
+ # Use cmake paths as a user may have a PATH element ending with a backslash.
+ # This will escape the list delimiter and create havoc!
+ if(EXISTS "${gp_cmd_dlls_dir}")
+ # only add to the path if it is not already in the path
+ set(gp_found_cmd_dlls_dir 0)
+ file(TO_CMAKE_PATH "$ENV{PATH}" env_path)
+ foreach(gp_env_path_element ${env_path})
+ if(gp_env_path_element STREQUAL gp_cmd_dlls_dir)
+ set(gp_found_cmd_dlls_dir 1)
+ endif()
+ endforeach()
+
+ if(NOT gp_found_cmd_dlls_dir)
+ file(TO_NATIVE_PATH "${gp_cmd_dlls_dir}" gp_cmd_dlls_dir)
+ set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}")
+ endif()
+ endif()
+ endif()
+ #
+ # </setup-gp_tool-vars>
+
+ if(gp_tool MATCHES "ldd$")
+ set(old_ld_env "$ENV{LD_LIBRARY_PATH}")
+ set(new_ld_env "${exepath}")
+ foreach(dir ${dirs})
+ string(APPEND new_ld_env ":${dir}")
+ endforeach()
+ set(ENV{LD_LIBRARY_PATH} "${new_ld_env}:$ENV{LD_LIBRARY_PATH}")
+ endif()
+
+
+ # Track new prerequisites at each new level of recursion. Start with an
+ # empty list at each level:
+ #
+ set(unseen_prereqs)
+
+ # Run gp_cmd on the target:
+ #
+ execute_process(
+ COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
+ ${gp_cmd_maybe_filter}
+ RESULT_VARIABLE gp_rv
+ OUTPUT_VARIABLE gp_cmd_ov
+ ERROR_VARIABLE gp_ev
+ )
+
+ if(gp_tool MATCHES "dumpbin$")
+ # Exclude delay load dependencies under windows (they are listed in dumpbin output after the message below)
+ string(FIND "${gp_cmd_ov}" "Image has the following delay load dependencies" gp_delayload_pos)
+ if (${gp_delayload_pos} GREATER -1)
+ string(SUBSTRING "${gp_cmd_ov}" 0 ${gp_delayload_pos} gp_cmd_ov_no_delayload_deps)
+ string(SUBSTRING "${gp_cmd_ov}" ${gp_delayload_pos} -1 gp_cmd_ov_delayload_deps)
+ if (verbose)
+ message(STATUS "GetPrequisites(${target}) : ignoring the following delay load dependencies :\n ${gp_cmd_ov_delayload_deps}")
+ endif()
+ set(gp_cmd_ov ${gp_cmd_ov_no_delayload_deps})
+ endif()
+ endif()
+
+ if(NOT gp_rv STREQUAL "0")
+ if(gp_tool MATCHES "dumpbin$")
+ # dumpbin error messages seem to go to stdout
+ message(FATAL_ERROR "${gp_cmd} failed: ${gp_rv}\n${gp_ev}\n${gp_cmd_ov}")
+ else()
+ message(FATAL_ERROR "${gp_cmd} failed: ${gp_rv}\n${gp_ev}")
+ endif()
+ endif()
+
+ if(gp_tool MATCHES "ldd$")
+ set(ENV{LD_LIBRARY_PATH} "${old_ld_env}")
+ endif()
+
+ if(verbose)
+ message(STATUS "<RawOutput cmd='${gp_cmd} ${gp_cmd_args} ${target}'>")
+ message(STATUS "gp_cmd_ov='${gp_cmd_ov}'")
+ message(STATUS "</RawOutput>")
+ endif()
+
+ get_filename_component(target_dir "${target}" PATH)
+
+ # Convert to a list of lines:
+ #
+ string(REPLACE ";" "\\;" candidates "${gp_cmd_ov}")
+ string(REPLACE "\n" "${eol_char};" candidates "${candidates}")
+
+ # check for install id and remove it from list, since otool -L can include a
+ # reference to itself
+ set(gp_install_id)
+ if(gp_tool MATCHES "otool$")
+ execute_process(
+ COMMAND ${gp_cmd} -D ${target}
+ RESULT_VARIABLE otool_rv
+ OUTPUT_VARIABLE gp_install_id_ov
+ ERROR_VARIABLE otool_ev
+ )
+ if(NOT otool_rv STREQUAL "0")
+ message(FATAL_ERROR "otool -D failed: ${otool_rv}\n${otool_ev}")
+ endif()
+ # second line is install name
+ string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}")
+ if(gp_install_id)
+ # trim
+ string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}")
+ #message("INSTALL ID is \"${gp_install_id}\"")
+ endif()
+ endif()
+
+ # Analyze each line for file names that match the regular expression:
+ #
+ foreach(candidate ${candidates})
+ if("${candidate}" MATCHES "${gp_regex}")
+
+ # Extract information from each candidate:
+ if(gp_regex_error AND "${candidate}" MATCHES "${gp_regex_error}")
+ string(REGEX REPLACE "${gp_regex_fallback}" "\\1" raw_item "${candidate}")
+ else()
+ string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}")
+ endif()
+
+ if(gp_regex_cmp_count GREATER 1)
+ string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}")
+ endif()
+
+ if(gp_regex_cmp_count GREATER 2)
+ string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}")
+ endif()
+
+ # Use the raw_item as the list entries returned by this function. Use the
+ # gp_resolve_item function to resolve it to an actual full path file if
+ # necessary.
+ #
+ set(item "${raw_item}")
+
+ # Add each item unless it is excluded:
+ #
+ set(add_item 1)
+
+ if(item STREQUAL gp_install_id)
+ set(add_item 0)
+ endif()
+
+ if(add_item AND ${exclude_system})
+ set(type "")
+ gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type "${rpaths}")
+
+ if(type STREQUAL "system")
+ set(add_item 0)
+ endif()
+ endif()
+
+ if(add_item)
+ list(LENGTH ${prerequisites_var} list_length_before_append)
+ gp_append_unique(${prerequisites_var} "${item}")
+ list(LENGTH ${prerequisites_var} list_length_after_append)
+
+ if(${recurse})
+ # If item was really added, this is the first time we have seen it.
+ # Add it to unseen_prereqs so that we can recursively add *its*
+ # prerequisites...
+ #
+ # But first: resolve its name to an absolute full path name such
+ # that the analysis tools can simply accept it as input.
+ #
+ if(NOT list_length_before_append EQUAL list_length_after_append)
+ gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item "${rpaths}")
+ if(EXISTS "${resolved_item}")
+ # Recurse only if we could resolve the item.
+ # Otherwise the prerequisites_var list will be cleared
+ set(unseen_prereqs ${unseen_prereqs} "${resolved_item}")
+ endif()
+ endif()
+ endif()
+ endif()
+ else()
+ if(verbose)
+ message(STATUS "ignoring non-matching line: '${candidate}'")
+ endif()
+ endif()
+ endforeach()
+
+ list(LENGTH ${prerequisites_var} prerequisites_var_length)
+ if(prerequisites_var_length GREATER 0)
+ list(SORT ${prerequisites_var})
+ endif()
+ if(${recurse})
+ set(more_inputs ${unseen_prereqs})
+ foreach(input ${more_inputs})
+ get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}" "${rpaths}")
+ endforeach()
+ endif()
+
+ set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE)
+endfunction()
+
+
+function(list_prerequisites target)
+ if(ARGC GREATER 1 AND NOT "${ARGV1}" STREQUAL "")
+ set(all "${ARGV1}")
+ else()
+ set(all 1)
+ endif()
+
+ if(ARGC GREATER 2 AND NOT "${ARGV2}" STREQUAL "")
+ set(exclude_system "${ARGV2}")
+ else()
+ set(exclude_system 0)
+ endif()
+
+ if(ARGC GREATER 3 AND NOT "${ARGV3}" STREQUAL "")
+ set(verbose "${ARGV3}")
+ else()
+ set(verbose 0)
+ endif()
+
+ set(count 0)
+ set(count_str "")
+ set(print_count "${verbose}")
+ set(print_prerequisite_type "${verbose}")
+ set(print_target "${verbose}")
+ set(type_str "")
+
+ get_filename_component(exepath "${target}" PATH)
+
+ set(prereqs "")
+ get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "")
+
+ if(print_target)
+ message(STATUS "File '${target}' depends on:")
+ endif()
+
+ foreach(d ${prereqs})
+ math(EXPR count "${count} + 1")
+
+ if(print_count)
+ set(count_str "${count}. ")
+ endif()
+
+ if(print_prerequisite_type)
+ gp_file_type("${target}" "${d}" type)
+ set(type_str " (${type})")
+ endif()
+
+ message(STATUS "${count_str}${d}${type_str}")
+ endforeach()
+endfunction()
+
+
+function(list_prerequisites_by_glob glob_arg glob_exp)
+ message(STATUS "=============================================================================")
+ message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'")
+ message(STATUS "")
+ file(${glob_arg} file_list ${glob_exp})
+ foreach(f ${file_list})
+ is_file_executable("${f}" is_f_executable)
+ if(is_f_executable)
+ message(STATUS "=============================================================================")
+ list_prerequisites("${f}" ${ARGN})
+ message(STATUS "")
+ endif()
+ endforeach()
+endfunction()
+
+cmake_policy(POP)
diff --git a/Modules/GoogleTest.cmake b/Modules/GoogleTest.cmake
new file mode 100644
index 0000000..80d8e23
--- /dev/null
+++ b/Modules/GoogleTest.cmake
@@ -0,0 +1,560 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+GoogleTest
+----------
+
+.. versionadded:: 3.9
+
+This module defines functions to help use the Google Test infrastructure. Two
+mechanisms for adding tests are provided. :command:`gtest_add_tests` has been
+around for some time, originally via ``find_package(GTest)``.
+:command:`gtest_discover_tests` was introduced in CMake 3.10.
+
+The (older) :command:`gtest_add_tests` scans source files to identify tests.
+This is usually effective, with some caveats, including in cross-compiling
+environments, and makes setting additional properties on tests more convenient.
+However, its handling of parameterized tests is less comprehensive, and it
+requires re-running CMake to detect changes to the list of tests.
+
+The (newer) :command:`gtest_discover_tests` discovers tests by asking the
+compiled test executable to enumerate its tests. This is more robust and
+provides better handling of parameterized tests, and does not require CMake
+to be re-run when tests change. However, it may not work in a cross-compiling
+environment, and setting test properties is less convenient.
+
+More details can be found in the documentation of the respective functions.
+
+Both commands are intended to replace use of :command:`add_test` to register
+tests, and will create a separate CTest test for each Google Test test case.
+Note that this is in some cases less efficient, as common set-up and tear-down
+logic cannot be shared by multiple test cases executing in the same instance.
+However, it provides more fine-grained pass/fail information to CTest, which is
+usually considered as more beneficial. By default, the CTest test name is the
+same as the Google Test name (i.e. ``suite.testcase``); see also
+``TEST_PREFIX`` and ``TEST_SUFFIX``.
+
+.. command:: gtest_add_tests
+
+ Automatically add tests with CTest by scanning source code for Google Test
+ macros::
+
+ gtest_add_tests(TARGET target
+ [SOURCES src1...]
+ [EXTRA_ARGS arg1...]
+ [WORKING_DIRECTORY dir]
+ [TEST_PREFIX prefix]
+ [TEST_SUFFIX suffix]
+ [SKIP_DEPENDENCY]
+ [TEST_LIST outVar]
+ )
+
+ ``gtest_add_tests`` attempts to identify tests by scanning source files.
+ Although this is generally effective, it uses only a basic regular expression
+ match, which can be defeated by atypical test declarations, and is unable to
+ fully "split" parameterized tests. Additionally, it requires that CMake be
+ re-run to discover any newly added, removed or renamed tests (by default,
+ this means that CMake is re-run when any test source file is changed, but see
+ ``SKIP_DEPENDENCY``). However, it has the advantage of declaring tests at
+ CMake time, which somewhat simplifies setting additional properties on tests,
+ and always works in a cross-compiling environment.
+
+ The options are:
+
+ ``TARGET target``
+ Specifies the Google Test executable, which must be a known CMake
+ executable target. CMake will substitute the location of the built
+ executable when running the test.
+
+ ``SOURCES src1...``
+ When provided, only the listed files will be scanned for test cases. If
+ this option is not given, the :prop_tgt:`SOURCES` property of the
+ specified ``target`` will be used to obtain the list of sources.
+
+ ``EXTRA_ARGS arg1...``
+ Any extra arguments to pass on the command line to each test case.
+
+ ``WORKING_DIRECTORY dir``
+ Specifies the directory in which to run the discovered test cases. If this
+ option is not provided, the current binary directory is used.
+
+ ``TEST_PREFIX prefix``
+ Specifies a ``prefix`` to be prepended to the name of each discovered test
+ case. This can be useful when the same source files are being used in
+ multiple calls to ``gtest_add_test()`` but with different ``EXTRA_ARGS``.
+
+ ``TEST_SUFFIX suffix``
+ Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
+ every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
+ be specified.
+
+ ``SKIP_DEPENDENCY``
+ Normally, the function creates a dependency which will cause CMake to be
+ re-run if any of the sources being scanned are changed. This is to ensure
+ that the list of discovered tests is updated. If this behavior is not
+ desired (as may be the case while actually writing the test cases), this
+ option can be used to prevent the dependency from being added.
+
+ ``TEST_LIST outVar``
+ The variable named by ``outVar`` will be populated in the calling scope
+ with the list of discovered test cases. This allows the caller to do
+ things like manipulate test properties of the discovered tests.
+
+ Usage example:
+
+ .. code-block:: cmake
+
+ include(GoogleTest)
+ add_executable(FooTest FooUnitTest.cxx)
+ gtest_add_tests(TARGET FooTest
+ TEST_SUFFIX .noArgs
+ TEST_LIST noArgsTests
+ )
+ gtest_add_tests(TARGET FooTest
+ EXTRA_ARGS --someArg someValue
+ TEST_SUFFIX .withArgs
+ TEST_LIST withArgsTests
+ )
+ set_tests_properties(${noArgsTests} PROPERTIES TIMEOUT 10)
+ set_tests_properties(${withArgsTests} PROPERTIES TIMEOUT 20)
+
+ For backward compatibility, the following form is also supported::
+
+ gtest_add_tests(exe args files...)
+
+ ``exe``
+ The path to the test executable or the name of a CMake target.
+ ``args``
+ A ;-list of extra arguments to be passed to executable. The entire
+ list must be passed as a single argument. Enclose it in quotes,
+ or pass ``""`` for no arguments.
+ ``files...``
+ A list of source files to search for tests and test fixtures.
+ Alternatively, use ``AUTO`` to specify that ``exe`` is the name
+ of a CMake executable target whose sources should be scanned.
+
+ .. code-block:: cmake
+
+ include(GoogleTest)
+ set(FooTestArgs --foo 1 --bar 2)
+ add_executable(FooTest FooUnitTest.cxx)
+ gtest_add_tests(FooTest "${FooTestArgs}" AUTO)
+
+.. command:: gtest_discover_tests
+
+ Automatically add tests with CTest by querying the compiled test executable
+ for available tests::
+
+ gtest_discover_tests(target
+ [EXTRA_ARGS arg1...]
+ [WORKING_DIRECTORY dir]
+ [TEST_PREFIX prefix]
+ [TEST_SUFFIX suffix]
+ [NO_PRETTY_TYPES] [NO_PRETTY_VALUES]
+ [PROPERTIES name1 value1...]
+ [TEST_LIST var]
+ [DISCOVERY_TIMEOUT seconds]
+ [XML_OUTPUT_DIR dir]
+ [DISCOVERY_MODE <POST_BUILD|PRE_TEST>]
+ )
+
+ .. versionadded:: 3.10
+
+ ``gtest_discover_tests()`` sets up a post-build command on the test executable
+ that generates the list of tests by parsing the output from running the test
+ with the ``--gtest_list_tests`` argument. Compared to the source parsing
+ approach of :command:`gtest_add_tests`, this ensures that the full list of
+ tests, including instantiations of parameterized tests, is obtained. Since
+ test discovery occurs at build time, it is not necessary to re-run CMake when
+ the list of tests changes.
+ However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
+ in order to function in a cross-compiling environment.
+
+ Additionally, setting properties on tests is somewhat less convenient, since
+ the tests are not available at CMake time. Additional test properties may be
+ assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
+ more fine-grained test control is needed, custom content may be provided
+ through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
+ directory property. The set of discovered tests is made accessible to such a
+ script via the ``<target>_TESTS`` variable.
+
+ The options are:
+
+ ``target``
+ Specifies the Google Test executable, which must be a known CMake
+ executable target. CMake will substitute the location of the built
+ executable when running the test.
+
+ ``EXTRA_ARGS arg1...``
+ Any extra arguments to pass on the command line to each test case.
+
+ ``WORKING_DIRECTORY dir``
+ Specifies the directory in which to run the discovered test cases. If this
+ option is not provided, the current binary directory is used.
+
+ ``TEST_PREFIX prefix``
+ Specifies a ``prefix`` to be prepended to the name of each discovered test
+ case. This can be useful when the same test executable is being used in
+ multiple calls to ``gtest_discover_tests()`` but with different
+ ``EXTRA_ARGS``.
+
+ ``TEST_SUFFIX suffix``
+ Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
+ every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
+ be specified.
+
+ ``NO_PRETTY_TYPES``
+ By default, the type index of type-parameterized tests is replaced by the
+ actual type name in the CTest test name. If this behavior is undesirable
+ (e.g. because the type names are unwieldy), this option will suppress this
+ behavior.
+
+ ``NO_PRETTY_VALUES``
+ By default, the value index of value-parameterized tests is replaced by the
+ actual value in the CTest test name. If this behavior is undesirable
+ (e.g. because the value strings are unwieldy), this option will suppress
+ this behavior.
+
+ ``PROPERTIES name1 value1...``
+ Specifies additional properties to be set on all tests discovered by this
+ invocation of ``gtest_discover_tests()``.
+
+ ``TEST_LIST var``
+ Make the list of tests available in the variable ``var``, rather than the
+ default ``<target>_TESTS``. This can be useful when the same test
+ executable is being used in multiple calls to ``gtest_discover_tests()``.
+ Note that this variable is only available in CTest.
+
+ ``DISCOVERY_TIMEOUT num``
+ .. versionadded:: 3.10.3
+
+ Specifies how long (in seconds) CMake will wait for the test to enumerate
+ available tests. If the test takes longer than this, discovery (and your
+ build) will fail. Most test executables will enumerate their tests very
+ quickly, but under some exceptional circumstances, a test may require a
+ longer timeout. The default is 5. See also the ``TIMEOUT`` option of
+ :command:`execute_process`.
+
+ .. note::
+
+ In CMake versions 3.10.1 and 3.10.2, this option was called ``TIMEOUT``.
+ This clashed with the ``TIMEOUT`` test property, which is one of the
+ common properties that would be set with the ``PROPERTIES`` keyword,
+ usually leading to legal but unintended behavior. The keyword was
+ changed to ``DISCOVERY_TIMEOUT`` in CMake 3.10.3 to address this
+ problem. The ambiguous behavior of the ``TIMEOUT`` keyword in 3.10.1
+ and 3.10.2 has not been preserved.
+
+ ``XML_OUTPUT_DIR dir``
+ .. versionadded:: 3.18
+
+ If specified, the parameter is passed along with ``--gtest_output=xml:``
+ to test executable. The actual file name is the same as the test target,
+ including prefix and suffix. This should be used instead of
+ ``EXTRA_ARGS --gtest_output=xml`` to avoid race conditions writing the
+ XML result output when using parallel test execution.
+
+ ``DISCOVERY_MODE``
+ .. versionadded:: 3.18
+
+ Provides greater control over when ``gtest_discover_tests()`` performs test
+ discovery. By default, ``POST_BUILD`` sets up a post-build command
+ to perform test discovery at build time. In certain scenarios, like
+ cross-compiling, this ``POST_BUILD`` behavior is not desirable.
+ By contrast, ``PRE_TEST`` delays test discovery until just prior to test
+ execution. This way test discovery occurs in the target environment
+ where the test has a better chance at finding appropriate runtime
+ dependencies.
+
+ ``DISCOVERY_MODE`` defaults to the value of the
+ ``CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE`` variable if it is not
+ passed when calling ``gtest_discover_tests()``. This provides a mechanism
+ for globally selecting a preferred test discovery behavior without having
+ to modify each call site.
+
+#]=======================================================================]
+
+# Save project's policies
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+#------------------------------------------------------------------------------
+function(gtest_add_tests)
+
+ if (ARGC LESS 1)
+ message(FATAL_ERROR "No arguments supplied to gtest_add_tests()")
+ endif()
+
+ set(options
+ SKIP_DEPENDENCY
+ )
+ set(oneValueArgs
+ TARGET
+ WORKING_DIRECTORY
+ TEST_PREFIX
+ TEST_SUFFIX
+ TEST_LIST
+ )
+ set(multiValueArgs
+ SOURCES
+ EXTRA_ARGS
+ )
+ set(allKeywords ${options} ${oneValueArgs} ${multiValueArgs})
+
+ unset(sources)
+ if("${ARGV0}" IN_LIST allKeywords)
+ cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+ set(autoAddSources YES)
+ else()
+ # Non-keyword syntax, convert to keyword form
+ if (ARGC LESS 3)
+ message(FATAL_ERROR "gtest_add_tests() without keyword options requires at least 3 arguments")
+ endif()
+ set(ARGS_TARGET "${ARGV0}")
+ set(ARGS_EXTRA_ARGS "${ARGV1}")
+ if(NOT "${ARGV2}" STREQUAL "AUTO")
+ set(ARGS_SOURCES "${ARGV}")
+ list(REMOVE_AT ARGS_SOURCES 0 1)
+ endif()
+ endif()
+
+ # The non-keyword syntax allows the first argument to be an arbitrary
+ # executable rather than a target if source files are also provided. In all
+ # other cases, both forms require a target.
+ if(NOT TARGET "${ARGS_TARGET}" AND NOT ARGS_SOURCES)
+ message(FATAL_ERROR "${ARGS_TARGET} does not define an existing CMake target")
+ endif()
+ if(NOT ARGS_WORKING_DIRECTORY)
+ unset(workDir)
+ else()
+ set(workDir WORKING_DIRECTORY "${ARGS_WORKING_DIRECTORY}")
+ endif()
+
+ if(NOT ARGS_SOURCES)
+ get_property(ARGS_SOURCES TARGET ${ARGS_TARGET} PROPERTY SOURCES)
+ endif()
+
+ unset(testList)
+
+ set(gtest_case_name_regex ".*\\( *([A-Za-z_0-9]+) *, *([A-Za-z_0-9]+) *\\).*")
+ set(gtest_test_type_regex "(TYPED_TEST|TEST_?[FP]?)")
+
+ foreach(source IN LISTS ARGS_SOURCES)
+ if(NOT ARGS_SKIP_DEPENDENCY)
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${source})
+ endif()
+ file(READ "${source}" contents)
+ string(REGEX MATCHALL "${gtest_test_type_regex} *\\(([A-Za-z_0-9 ,]+)\\)" found_tests "${contents}")
+ foreach(hit ${found_tests})
+ string(REGEX MATCH "${gtest_test_type_regex}" test_type ${hit})
+
+ # Parameterized tests have a different signature for the filter
+ if("x${test_type}" STREQUAL "xTEST_P")
+ string(REGEX REPLACE ${gtest_case_name_regex} "*/\\1.\\2/*" gtest_test_name ${hit})
+ elseif("x${test_type}" STREQUAL "xTEST_F" OR "x${test_type}" STREQUAL "xTEST")
+ string(REGEX REPLACE ${gtest_case_name_regex} "\\1.\\2" gtest_test_name ${hit})
+ elseif("x${test_type}" STREQUAL "xTYPED_TEST")
+ string(REGEX REPLACE ${gtest_case_name_regex} "\\1/*.\\2" gtest_test_name ${hit})
+ else()
+ message(WARNING "Could not parse GTest ${hit} for adding to CTest.")
+ continue()
+ endif()
+
+ # Make sure tests disabled in GTest get disabled in CTest
+ if(gtest_test_name MATCHES "(^|\\.)DISABLED_")
+ # Add the disabled test if CMake is new enough
+ # Note that this check is to allow backwards compatibility so this
+ # module can be copied locally in projects to use with older CMake
+ # versions
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.8.20170401)
+ string(REGEX REPLACE
+ "(^|\\.)DISABLED_" "\\1"
+ orig_test_name "${gtest_test_name}"
+ )
+ set(ctest_test_name
+ ${ARGS_TEST_PREFIX}${orig_test_name}${ARGS_TEST_SUFFIX}
+ )
+ add_test(NAME ${ctest_test_name}
+ ${workDir}
+ COMMAND ${ARGS_TARGET}
+ --gtest_also_run_disabled_tests
+ --gtest_filter=${gtest_test_name}
+ ${ARGS_EXTRA_ARGS}
+ )
+ set_tests_properties(${ctest_test_name} PROPERTIES DISABLED TRUE)
+ list(APPEND testList ${ctest_test_name})
+ endif()
+ else()
+ set(ctest_test_name ${ARGS_TEST_PREFIX}${gtest_test_name}${ARGS_TEST_SUFFIX})
+ add_test(NAME ${ctest_test_name}
+ ${workDir}
+ COMMAND ${ARGS_TARGET}
+ --gtest_filter=${gtest_test_name}
+ ${ARGS_EXTRA_ARGS}
+ )
+ list(APPEND testList ${ctest_test_name})
+ endif()
+ endforeach()
+ endforeach()
+
+ if(ARGS_TEST_LIST)
+ set(${ARGS_TEST_LIST} ${testList} PARENT_SCOPE)
+ endif()
+
+endfunction()
+
+#------------------------------------------------------------------------------
+
+function(gtest_discover_tests TARGET)
+ cmake_parse_arguments(
+ ""
+ "NO_PRETTY_TYPES;NO_PRETTY_VALUES"
+ "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;DISCOVERY_TIMEOUT;XML_OUTPUT_DIR;DISCOVERY_MODE"
+ "EXTRA_ARGS;PROPERTIES"
+ ${ARGN}
+ )
+
+ if(NOT _WORKING_DIRECTORY)
+ set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ if(NOT _TEST_LIST)
+ set(_TEST_LIST ${TARGET}_TESTS)
+ endif()
+ if(NOT _DISCOVERY_TIMEOUT)
+ set(_DISCOVERY_TIMEOUT 5)
+ endif()
+ if(NOT _DISCOVERY_MODE)
+ if(NOT CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE)
+ set(CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE "POST_BUILD")
+ endif()
+ set(_DISCOVERY_MODE ${CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE})
+ endif()
+
+ get_property(
+ has_counter
+ TARGET ${TARGET}
+ PROPERTY CTEST_DISCOVERED_TEST_COUNTER
+ SET
+ )
+ if(has_counter)
+ get_property(
+ counter
+ TARGET ${TARGET}
+ PROPERTY CTEST_DISCOVERED_TEST_COUNTER
+ )
+ math(EXPR counter "${counter} + 1")
+ else()
+ set(counter 1)
+ endif()
+ set_property(
+ TARGET ${TARGET}
+ PROPERTY CTEST_DISCOVERED_TEST_COUNTER
+ ${counter}
+ )
+
+ # Define rule to generate test list for aforementioned test executable
+ set(ctest_file_base "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}[${counter}]")
+ set(ctest_include_file "${ctest_file_base}_include.cmake")
+ set(ctest_tests_file "${ctest_file_base}_tests.cmake")
+ get_property(crosscompiling_emulator
+ TARGET ${TARGET}
+ PROPERTY CROSSCOMPILING_EMULATOR
+ )
+
+ if(_DISCOVERY_MODE STREQUAL "POST_BUILD")
+ add_custom_command(
+ TARGET ${TARGET} POST_BUILD
+ BYPRODUCTS "${ctest_tests_file}"
+ COMMAND "${CMAKE_COMMAND}"
+ -D "TEST_TARGET=${TARGET}"
+ -D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
+ -D "TEST_EXECUTOR=${crosscompiling_emulator}"
+ -D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
+ -D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
+ -D "TEST_PROPERTIES=${_PROPERTIES}"
+ -D "TEST_PREFIX=${_TEST_PREFIX}"
+ -D "TEST_SUFFIX=${_TEST_SUFFIX}"
+ -D "NO_PRETTY_TYPES=${_NO_PRETTY_TYPES}"
+ -D "NO_PRETTY_VALUES=${_NO_PRETTY_VALUES}"
+ -D "TEST_LIST=${_TEST_LIST}"
+ -D "CTEST_FILE=${ctest_tests_file}"
+ -D "TEST_DISCOVERY_TIMEOUT=${_DISCOVERY_TIMEOUT}"
+ -D "TEST_XML_OUTPUT_DIR=${_XML_OUTPUT_DIR}"
+ -P "${_GOOGLETEST_DISCOVER_TESTS_SCRIPT}"
+ VERBATIM
+ )
+
+ file(WRITE "${ctest_include_file}"
+ "if(EXISTS \"${ctest_tests_file}\")\n"
+ " include(\"${ctest_tests_file}\")\n"
+ "else()\n"
+ " add_test(${TARGET}_NOT_BUILT ${TARGET}_NOT_BUILT)\n"
+ "endif()\n"
+ )
+ elseif(_DISCOVERY_MODE STREQUAL "PRE_TEST")
+
+ get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL
+ PROPERTY GENERATOR_IS_MULTI_CONFIG
+ )
+
+ if(GENERATOR_IS_MULTI_CONFIG)
+ set(ctest_tests_file "${ctest_file_base}_tests-$<CONFIG>.cmake")
+ endif()
+
+ string(CONCAT ctest_include_content
+ "if(EXISTS \"$<TARGET_FILE:${TARGET}>\")" "\n"
+ " if(NOT EXISTS \"${ctest_tests_file}\" OR" "\n"
+ " NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"$<TARGET_FILE:${TARGET}>\")" "\n"
+ " include(\"${_GOOGLETEST_DISCOVER_TESTS_SCRIPT}\")" "\n"
+ " gtest_discover_tests_impl(" "\n"
+ " TEST_EXECUTABLE" " [==[" "$<TARGET_FILE:${TARGET}>" "]==]" "\n"
+ " TEST_EXECUTOR" " [==[" "${crosscompiling_emulator}" "]==]" "\n"
+ " TEST_WORKING_DIR" " [==[" "${_WORKING_DIRECTORY}" "]==]" "\n"
+ " TEST_EXTRA_ARGS" " [==[" "${_EXTRA_ARGS}" "]==]" "\n"
+ " TEST_PROPERTIES" " [==[" "${_PROPERTIES}" "]==]" "\n"
+ " TEST_PREFIX" " [==[" "${_TEST_PREFIX}" "]==]" "\n"
+ " TEST_SUFFIX" " [==[" "${_TEST_SUFFIX}" "]==]" "\n"
+ " NO_PRETTY_TYPES" " [==[" "${_NO_PRETTY_TYPES}" "]==]" "\n"
+ " NO_PRETTY_VALUES" " [==[" "${_NO_PRETTY_VALUES}" "]==]" "\n"
+ " TEST_LIST" " [==[" "${_TEST_LIST}" "]==]" "\n"
+ " CTEST_FILE" " [==[" "${ctest_tests_file}" "]==]" "\n"
+ " TEST_DISCOVERY_TIMEOUT" " [==[" "${_DISCOVERY_TIMEOUT}" "]==]" "\n"
+ " TEST_XML_OUTPUT_DIR" " [==[" "${_XML_OUTPUT_DIR}" "]==]" "\n"
+ " )" "\n"
+ " endif()" "\n"
+ " include(\"${ctest_tests_file}\")" "\n"
+ "else()" "\n"
+ " add_test(${TARGET}_NOT_BUILT ${TARGET}_NOT_BUILT)" "\n"
+ "endif()" "\n"
+ )
+
+ if(GENERATOR_IS_MULTI_CONFIG)
+ foreach(_config ${CMAKE_CONFIGURATION_TYPES})
+ file(GENERATE OUTPUT "${ctest_file_base}_include-${_config}.cmake" CONTENT "${ctest_include_content}" CONDITION $<CONFIG:${_config}>)
+ endforeach()
+ file(WRITE "${ctest_include_file}" "include(\"${ctest_file_base}_include-\${CTEST_CONFIGURATION_TYPE}.cmake\")")
+ else()
+ file(GENERATE OUTPUT "${ctest_file_base}_include.cmake" CONTENT "${ctest_include_content}")
+ file(WRITE "${ctest_include_file}" "include(\"${ctest_file_base}_include.cmake\")")
+ endif()
+
+ else()
+ message(FATAL_ERROR "Unknown DISCOVERY_MODE: ${_DISCOVERY_MODE}")
+ endif()
+
+ # Add discovered tests to directory TEST_INCLUDE_FILES
+ set_property(DIRECTORY
+ APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
+ )
+
+endfunction()
+
+###############################################################################
+
+set(_GOOGLETEST_DISCOVER_TESTS_SCRIPT
+ ${CMAKE_CURRENT_LIST_DIR}/GoogleTestAddTests.cmake
+)
+
+# Restore project's policies
+cmake_policy(POP)
diff --git a/Modules/GoogleTestAddTests.cmake b/Modules/GoogleTestAddTests.cmake
new file mode 100644
index 0000000..0f79c9a
--- /dev/null
+++ b/Modules/GoogleTestAddTests.cmake
@@ -0,0 +1,188 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION ${CMAKE_VERSION})
+
+# Overwrite possibly existing ${_CTEST_FILE} with empty file
+set(flush_tests_MODE WRITE)
+
+# Flushes script to ${_CTEST_FILE}
+macro(flush_script)
+ file(${flush_tests_MODE} "${_CTEST_FILE}" "${script}")
+ set(flush_tests_MODE APPEND)
+
+ set(script "")
+endmacro()
+
+# Flushes tests_buffer to tests
+macro(flush_tests_buffer)
+ list(APPEND tests "${tests_buffer}")
+ set(tests_buffer "")
+endmacro()
+
+macro(add_command NAME)
+ set(_args "")
+ foreach(_arg ${ARGN})
+ if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
+ string(APPEND _args " [==[${_arg}]==]")
+ else()
+ string(APPEND _args " ${_arg}")
+ endif()
+ endforeach()
+ string(APPEND script "${NAME}(${_args})\n")
+ string(LENGTH "${script}" _script_len)
+ if(${_script_len} GREATER "50000")
+ flush_script()
+ endif()
+ # Unsets macro local variables to prevent leakage outside of this macro.
+ unset(_args)
+ unset(_script_len)
+endmacro()
+
+function(gtest_discover_tests_impl)
+
+ cmake_parse_arguments(
+ ""
+ ""
+ "NO_PRETTY_TYPES;NO_PRETTY_VALUES;TEST_EXECUTABLE;TEST_WORKING_DIR;TEST_PREFIX;TEST_SUFFIX;TEST_LIST;CTEST_FILE;TEST_DISCOVERY_TIMEOUT;TEST_XML_OUTPUT_DIR"
+ "TEST_EXTRA_ARGS;TEST_PROPERTIES;TEST_EXECUTOR"
+ ${ARGN}
+ )
+
+ set(prefix "${_TEST_PREFIX}")
+ set(suffix "${_TEST_SUFFIX}")
+ set(extra_args ${_TEST_EXTRA_ARGS})
+ set(properties ${_TEST_PROPERTIES})
+ set(script)
+ set(suite)
+ set(tests)
+ set(tests_buffer)
+
+ # Run test executable to get list of available tests
+ if(NOT EXISTS "${_TEST_EXECUTABLE}")
+ message(FATAL_ERROR
+ "Specified test executable does not exist.\n"
+ " Path: '${_TEST_EXECUTABLE}'"
+ )
+ endif()
+ execute_process(
+ COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" --gtest_list_tests
+ WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
+ TIMEOUT ${_TEST_DISCOVERY_TIMEOUT}
+ OUTPUT_VARIABLE output
+ RESULT_VARIABLE result
+ )
+ if(NOT ${result} EQUAL 0)
+ string(REPLACE "\n" "\n " output "${output}")
+ message(FATAL_ERROR
+ "Error running test executable.\n"
+ " Path: '${_TEST_EXECUTABLE}'\n"
+ " Result: ${result}\n"
+ " Output:\n"
+ " ${output}\n"
+ )
+ endif()
+
+ # Preserve semicolon in test-parameters
+ string(REPLACE [[;]] [[\;]] output "${output}")
+ string(REPLACE "\n" ";" output "${output}")
+
+ # Parse output
+ foreach(line ${output})
+ # Skip header
+ if(NOT line MATCHES "gtest_main\\.cc")
+ # Do we have a module name or a test name?
+ if(NOT line MATCHES "^ ")
+ # Module; remove trailing '.' to get just the name...
+ string(REGEX REPLACE "\\.( *#.*)?" "" suite "${line}")
+ if(line MATCHES "#" AND NOT _NO_PRETTY_TYPES)
+ string(REGEX REPLACE "/[0-9]\\.+ +#.*= +" "/" pretty_suite "${line}")
+ else()
+ set(pretty_suite "${suite}")
+ endif()
+ string(REGEX REPLACE "^DISABLED_" "" pretty_suite "${pretty_suite}")
+ else()
+ # Test name; strip spaces and comments to get just the name...
+ string(REGEX REPLACE " +" "" test "${line}")
+ if(test MATCHES "#" AND NOT _NO_PRETTY_VALUES)
+ string(REGEX REPLACE "/[0-9]+#GetParam..=" "/" pretty_test "${test}")
+ else()
+ string(REGEX REPLACE "#.*" "" pretty_test "${test}")
+ endif()
+ string(REGEX REPLACE "^DISABLED_" "" pretty_test "${pretty_test}")
+ string(REGEX REPLACE "#.*" "" test "${test}")
+ if(NOT "${_TEST_XML_OUTPUT_DIR}" STREQUAL "")
+ set(TEST_XML_OUTPUT_PARAM "--gtest_output=xml:${_TEST_XML_OUTPUT_DIR}/${prefix}${suite}.${test}${suffix}.xml")
+ else()
+ unset(TEST_XML_OUTPUT_PARAM)
+ endif()
+
+ # sanitize test name for further processing downstream
+ set(testname "${prefix}${pretty_suite}.${pretty_test}${suffix}")
+ # escape \
+ string(REPLACE [[\]] [[\\]] testname "${testname}")
+ # escape ;
+ string(REPLACE [[;]] [[\;]] testname "${testname}")
+ # escape $
+ string(REPLACE [[$]] [[\$]] testname "${testname}")
+
+ # ...and add to script
+ add_command(add_test
+ "${testname}"
+ ${_TEST_EXECUTOR}
+ "${_TEST_EXECUTABLE}"
+ "--gtest_filter=${suite}.${test}"
+ "--gtest_also_run_disabled_tests"
+ ${TEST_XML_OUTPUT_PARAM}
+ ${extra_args}
+ )
+ if(suite MATCHES "^DISABLED_" OR test MATCHES "^DISABLED_")
+ add_command(set_tests_properties
+ "${testname}"
+ PROPERTIES DISABLED TRUE
+ )
+ endif()
+ add_command(set_tests_properties
+ "${testname}"
+ PROPERTIES
+ WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
+ SKIP_REGULAR_EXPRESSION "\\\\[ SKIPPED \\\\]"
+ ${properties}
+ )
+ list(APPEND tests_buffer "${testname}")
+ list(LENGTH tests_buffer tests_buffer_length)
+ if(${tests_buffer_length} GREATER "250")
+ flush_tests_buffer()
+ endif()
+ endif()
+ endif()
+ endforeach()
+
+
+ # Create a list of all discovered tests, which users may use to e.g. set
+ # properties on the tests
+ flush_tests_buffer()
+ add_command(set ${_TEST_LIST} ${tests})
+
+ # Write CTest script
+ flush_script()
+
+endfunction()
+
+if(CMAKE_SCRIPT_MODE_FILE)
+ gtest_discover_tests_impl(
+ NO_PRETTY_TYPES ${NO_PRETTY_TYPES}
+ NO_PRETTY_VALUES ${NO_PRETTY_VALUES}
+ TEST_EXECUTABLE ${TEST_EXECUTABLE}
+ TEST_EXECUTOR ${TEST_EXECUTOR}
+ TEST_WORKING_DIR ${TEST_WORKING_DIR}
+ TEST_PREFIX ${TEST_PREFIX}
+ TEST_SUFFIX ${TEST_SUFFIX}
+ TEST_LIST ${TEST_LIST}
+ CTEST_FILE ${CTEST_FILE}
+ TEST_DISCOVERY_TIMEOUT ${TEST_DISCOVERY_TIMEOUT}
+ TEST_XML_OUTPUT_DIR ${TEST_XML_OUTPUT_DIR}
+ TEST_EXTRA_ARGS ${TEST_EXTRA_ARGS}
+ TEST_PROPERTIES ${TEST_PROPERTIES}
+ )
+endif()
diff --git a/Modules/ITKCompatibility.cmake b/Modules/ITKCompatibility.cmake
new file mode 100644
index 0000000..7d211b6
--- /dev/null
+++ b/Modules/ITKCompatibility.cmake
@@ -0,0 +1,7 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# work around an old bug in ITK prior to version 3.0
+set(TIFF_RIGHT_VERSION 1)
+
diff --git a/Modules/InstallRequiredSystemLibraries.cmake b/Modules/InstallRequiredSystemLibraries.cmake
new file mode 100644
index 0000000..2d08e08
--- /dev/null
+++ b/Modules/InstallRequiredSystemLibraries.cmake
@@ -0,0 +1,784 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+InstallRequiredSystemLibraries
+------------------------------
+
+Include this module to search for compiler-provided system runtime
+libraries and add install rules for them. Some optional variables
+may be set prior to including the module to adjust behavior:
+
+``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS``
+ Specify additional runtime libraries that may not be detected.
+ After inclusion any detected libraries will be appended to this.
+
+``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP``
+ Set to TRUE to skip calling the :command:`install(PROGRAMS)` command to
+ allow the includer to specify its own install rule, using the value of
+ ``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS`` to get the list of libraries.
+
+``CMAKE_INSTALL_DEBUG_LIBRARIES``
+ Set to TRUE to install the debug runtime libraries when available
+ with MSVC tools.
+
+``CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY``
+ Set to TRUE to install only the debug runtime libraries with MSVC
+ tools even if the release runtime libraries are also available.
+
+``CMAKE_INSTALL_UCRT_LIBRARIES``
+ .. versionadded:: 3.6
+
+ Set to TRUE to install the Windows Universal CRT libraries for
+ app-local deployment (e.g. to Windows XP). This is meaningful
+ only with MSVC from Visual Studio 2015 or higher.
+
+ .. versionadded:: 3.9
+ One may set a ``CMAKE_WINDOWS_KITS_10_DIR`` *environment variable*
+ to an absolute path to tell CMake to look for Windows 10 SDKs in
+ a custom location. The specified directory is expected to contain
+ ``Redist/ucrt/DLLs/*`` directories.
+
+``CMAKE_INSTALL_MFC_LIBRARIES``
+ Set to TRUE to install the MSVC MFC runtime libraries.
+
+``CMAKE_INSTALL_OPENMP_LIBRARIES``
+ Set to TRUE to install the MSVC OpenMP runtime libraries
+
+``CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION``
+ Specify the :command:`install(PROGRAMS)` command ``DESTINATION``
+ option. If not specified, the default is ``bin`` on Windows
+ and ``lib`` elsewhere.
+
+``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS``
+ Set to TRUE to disable warnings about required library files that
+ do not exist. (For example, Visual Studio Express editions may
+ not provide the redistributable files.)
+
+``CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT``
+ .. versionadded:: 3.3
+
+ Specify the :command:`install(PROGRAMS)` command ``COMPONENT``
+ option. If not specified, no such option will be used.
+
+.. versionadded:: 3.10
+ Support for installing Intel compiler runtimes.
+#]=======================================================================]
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
+
+set(_IRSL_HAVE_Intel FALSE)
+set(_IRSL_HAVE_MSVC FALSE)
+foreach(LANG IN ITEMS C CXX Fortran)
+ if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "Intel")
+ if(NOT _IRSL_HAVE_Intel)
+ get_filename_component(_Intel_basedir "${CMAKE_${LANG}_COMPILER}" PATH)
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(_Intel_archdir intel64)
+ else()
+ set(_Intel_archdir ia32)
+ endif()
+ set(_Intel_compiler_ver ${CMAKE_${LANG}_COMPILER_VERSION})
+ if(WIN32)
+ get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../redist/${_Intel_archdir}/compiler" ABSOLUTE)
+ elseif(APPLE)
+ get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../compiler/lib" ABSOLUTE)
+ else()
+ if(EXISTS "${_Intel_basedir}/../lib/${_Intel_archdir}_lin")
+ get_filename_component(_Intel_redistdir "${_Intel_basedir}/../lib/${_Intel_archdir}" ABSOLUTE)
+ else()
+ get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../compiler/lib/${_Intel_archdir}_lin" ABSOLUTE)
+ endif()
+ endif()
+ set(_IRSL_HAVE_Intel TRUE)
+ endif()
+ elseif("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "MSVC")
+ set(_IRSL_HAVE_MSVC TRUE)
+ endif()
+endforeach()
+
+if(MSVC)
+ file(TO_CMAKE_PATH "$ENV{SYSTEMROOT}" SYSTEMROOT)
+
+ if(MSVC_C_ARCHITECTURE_ID)
+ string(TOLOWER "${MSVC_C_ARCHITECTURE_ID}" CMAKE_MSVC_ARCH)
+ elseif(MSVC_CXX_ARCHITECTURE_ID)
+ string(TOLOWER "${MSVC_CXX_ARCHITECTURE_ID}" CMAKE_MSVC_ARCH)
+ else()
+ set(CMAKE_MSVC_ARCH x86)
+ endif()
+ if(CMAKE_MSVC_ARCH STREQUAL "x64")
+ if(MSVC_VERSION LESS 1600)
+ # VS 9 and earlier:
+ set(CMAKE_MSVC_ARCH amd64)
+ endif()
+ endif()
+
+ get_filename_component(devenv_dir "${CMAKE_MAKE_PROGRAM}" PATH)
+ get_filename_component(base_dir "${devenv_dir}/../.." ABSOLUTE)
+
+ if(MSVC_VERSION EQUAL 1300)
+ set(__install__libs
+ "${SYSTEMROOT}/system32/msvcp70.dll"
+ "${SYSTEMROOT}/system32/msvcr70.dll"
+ )
+ endif()
+
+ if(MSVC_VERSION EQUAL 1310)
+ set(__install__libs
+ "${SYSTEMROOT}/system32/msvcp71.dll"
+ "${SYSTEMROOT}/system32/msvcr71.dll"
+ )
+ endif()
+
+ if(MSVC_TOOLSET_VERSION EQUAL 80)
+ # Find the runtime library redistribution directory.
+ get_filename_component(msvc_install_dir
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]" ABSOLUTE)
+ if(DEFINED MSVC80_REDIST_DIR AND EXISTS "${MSVC80_REDIST_DIR}")
+ set(MSVC_REDIST_DIR "${MSVC80_REDIST_DIR}") # use old cache entry
+ endif()
+ find_path(MSVC_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.VC80.CRT/Microsoft.VC80.CRT.manifest
+ PATHS
+ "${msvc_install_dir}/../../VC/redist"
+ "${base_dir}/VC/redist"
+ )
+ mark_as_advanced(MSVC_REDIST_DIR)
+ set(MSVC_CRT_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.CRT")
+
+ # Install the manifest that allows DLLs to be loaded from the
+ # directory containing the executable.
+ if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+ set(__install__libs
+ "${MSVC_CRT_DIR}/Microsoft.VC80.CRT.manifest"
+ "${MSVC_CRT_DIR}/msvcm80.dll"
+ "${MSVC_CRT_DIR}/msvcp80.dll"
+ "${MSVC_CRT_DIR}/msvcr80.dll"
+ )
+ else()
+ set(__install__libs)
+ endif()
+
+ if(CMAKE_INSTALL_DEBUG_LIBRARIES)
+ set(MSVC_CRT_DIR
+ "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC80.DebugCRT")
+ set(__install__libs ${__install__libs}
+ "${MSVC_CRT_DIR}/Microsoft.VC80.DebugCRT.manifest"
+ "${MSVC_CRT_DIR}/msvcm80d.dll"
+ "${MSVC_CRT_DIR}/msvcp80d.dll"
+ "${MSVC_CRT_DIR}/msvcr80d.dll"
+ )
+ endif()
+ endif()
+
+ if(MSVC_TOOLSET_VERSION EQUAL 90)
+ # Find the runtime library redistribution directory.
+ get_filename_component(msvc_install_dir
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]" ABSOLUTE)
+ get_filename_component(msvc_express_install_dir
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\9.0;InstallDir]" ABSOLUTE)
+ if(DEFINED MSVC90_REDIST_DIR AND EXISTS "${MSVC90_REDIST_DIR}")
+ set(MSVC_REDIST_DIR "${MSVC90_REDIST_DIR}") # use old cache entry
+ endif()
+ find_path(MSVC_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest
+ PATHS
+ "${msvc_install_dir}/../../VC/redist"
+ "${msvc_express_install_dir}/../../VC/redist"
+ "${base_dir}/VC/redist"
+ )
+ mark_as_advanced(MSVC_REDIST_DIR)
+ set(MSVC_CRT_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.CRT")
+
+ # Install the manifest that allows DLLs to be loaded from the
+ # directory containing the executable.
+ if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+ set(__install__libs
+ "${MSVC_CRT_DIR}/Microsoft.VC90.CRT.manifest"
+ "${MSVC_CRT_DIR}/msvcm90.dll"
+ "${MSVC_CRT_DIR}/msvcp90.dll"
+ "${MSVC_CRT_DIR}/msvcr90.dll"
+ )
+ else()
+ set(__install__libs)
+ endif()
+
+ if(CMAKE_INSTALL_DEBUG_LIBRARIES)
+ set(MSVC_CRT_DIR
+ "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC90.DebugCRT")
+ set(__install__libs ${__install__libs}
+ "${MSVC_CRT_DIR}/Microsoft.VC90.DebugCRT.manifest"
+ "${MSVC_CRT_DIR}/msvcm90d.dll"
+ "${MSVC_CRT_DIR}/msvcp90d.dll"
+ "${MSVC_CRT_DIR}/msvcr90d.dll"
+ )
+ endif()
+ endif()
+
+ set(MSVC_REDIST_NAME "")
+ set(_MSVC_DLL_VERSION "")
+ set(_MSVC_IDE_VERSION "")
+ if(MSVC_VERSION GREATER_EQUAL 2000)
+ message(WARNING "MSVC ${MSVC_VERSION} not yet supported.")
+ elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 143)
+ message(WARNING "MSVC toolset v${MSVC_TOOLSET_VERSION} not yet supported.")
+ elseif(MSVC_TOOLSET_VERSION EQUAL 142)
+ set(MSVC_REDIST_NAME VC142)
+ set(_MSVC_DLL_VERSION 140)
+ set(_MSVC_IDE_VERSION 16)
+ if(MSVC_VERSION EQUAL 1920)
+ # VS2019 named this differently prior to update 1.
+ set(MSVC_REDIST_NAME VC141)
+ endif()
+ elseif(MSVC_TOOLSET_VERSION EQUAL 141)
+ set(MSVC_REDIST_NAME VC141)
+ set(_MSVC_DLL_VERSION 140)
+ set(_MSVC_IDE_VERSION 15)
+ if(MSVC_VERSION EQUAL 1910)
+ # VS2017 named this differently prior to update 3.
+ set(MSVC_REDIST_NAME VC150)
+ endif()
+ elseif(MSVC_TOOLSET_VERSION)
+ set(MSVC_REDIST_NAME VC${MSVC_TOOLSET_VERSION})
+ math(EXPR _MSVC_DLL_VERSION "${MSVC_TOOLSET_VERSION} / 10 * 10")
+ math(EXPR _MSVC_IDE_VERSION "${MSVC_TOOLSET_VERSION} / 10")
+ endif()
+
+ set(_MSVCRT_DLL_VERSION "")
+ set(_MSVCRT_IDE_VERSION "")
+ if(_MSVC_IDE_VERSION GREATER_EQUAL 10)
+ set(_MSVCRT_DLL_VERSION "${_MSVC_DLL_VERSION}")
+ set(_MSVCRT_IDE_VERSION "${_MSVC_IDE_VERSION}")
+ endif()
+
+ if(_MSVCRT_DLL_VERSION)
+ set(v "${_MSVCRT_DLL_VERSION}")
+ set(vs "${_MSVCRT_IDE_VERSION}")
+
+ # Find the runtime library redistribution directory.
+ if(vs VERSION_LESS 15 AND DEFINED MSVC${vs}_REDIST_DIR AND EXISTS "${MSVC${vs}_REDIST_DIR}")
+ set(MSVC_REDIST_DIR "${MSVC${vs}_REDIST_DIR}") # use old cache entry
+ endif()
+ if(NOT vs VERSION_LESS 15)
+ set(_vs_redist_paths "")
+ # The toolset and its redistributables may come with any VS version 15 or newer.
+ set(_MSVC_IDE_VERSIONS 16 15)
+ foreach(_vs_ver ${_MSVC_IDE_VERSIONS})
+ set(_vs_glob_redist_paths "")
+ cmake_host_system_information(RESULT _vs_dir QUERY VS_${_vs_ver}_DIR) # undocumented query
+ if(IS_DIRECTORY "${_vs_dir}")
+ file(GLOB _vs_glob_redist_paths "${_vs_dir}/VC/Redist/MSVC/*")
+ list(REVERSE _vs_glob_redist_paths)
+ list(APPEND _vs_redist_paths ${_vs_glob_redist_paths})
+ endif()
+ unset(_vs_glob_redist_paths)
+ endforeach()
+ unset(_MSVC_IDE_VERSIONS)
+ unset(_vs_dir)
+ else()
+ get_filename_component(_vs_dir
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\${vs}.0;InstallDir]" ABSOLUTE)
+ set(programfilesx86 "ProgramFiles(x86)")
+ set(_vs_redist_paths
+ "${_vs_dir}/../../VC/redist"
+ "${base_dir}/VC/redist"
+ "$ENV{ProgramFiles}/Microsoft Visual Studio ${vs}.0/VC/redist"
+ "$ENV{${programfilesx86}}/Microsoft Visual Studio ${vs}.0/VC/redist"
+ )
+ unset(_vs_dir)
+ unset(programfilesx86)
+ endif()
+ find_path(MSVC_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.CRT PATHS ${_vs_redist_paths})
+ unset(_vs_redist_paths)
+ mark_as_advanced(MSVC_REDIST_DIR)
+ set(MSVC_CRT_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.CRT")
+
+ if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+ set(__install__libs
+ "${MSVC_CRT_DIR}/msvcp${v}.dll"
+ )
+ if(NOT vs VERSION_LESS 14)
+ foreach(crt
+ "${MSVC_CRT_DIR}/msvcp${v}_1.dll"
+ "${MSVC_CRT_DIR}/msvcp${v}_2.dll"
+ "${MSVC_CRT_DIR}/msvcp${v}_atomic_wait.dll"
+ "${MSVC_CRT_DIR}/msvcp${v}_codecvt_ids.dll"
+ "${MSVC_CRT_DIR}/vcruntime${v}_1.dll"
+ )
+ if(EXISTS "${crt}")
+ list(APPEND __install__libs "${crt}")
+ endif()
+ endforeach()
+ list(APPEND __install__libs
+ "${MSVC_CRT_DIR}/vcruntime${v}.dll"
+ "${MSVC_CRT_DIR}/concrt${v}.dll"
+ )
+ else()
+ list(APPEND __install__libs "${MSVC_CRT_DIR}/msvcr${v}.dll")
+ endif()
+ else()
+ set(__install__libs)
+ endif()
+
+ if(CMAKE_INSTALL_DEBUG_LIBRARIES)
+ set(MSVC_CRT_DIR
+ "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.DebugCRT")
+ set(__install__libs ${__install__libs}
+ "${MSVC_CRT_DIR}/msvcp${v}d.dll"
+ )
+ if(NOT vs VERSION_LESS 14)
+ foreach(crt
+ "${MSVC_CRT_DIR}/msvcp${v}_1d.dll"
+ "${MSVC_CRT_DIR}/msvcp${v}_2d.dll"
+ "${MSVC_CRT_DIR}/msvcp${v}d_atomic_wait.dll"
+ "${MSVC_CRT_DIR}/msvcp${v}d_codecvt_ids.dll"
+ "${MSVC_CRT_DIR}/vcruntime${v}_1d.dll"
+ )
+ if(EXISTS "${crt}")
+ list(APPEND __install__libs "${crt}")
+ endif()
+ endforeach()
+ list(APPEND __install__libs
+ "${MSVC_CRT_DIR}/vcruntime${v}d.dll"
+ "${MSVC_CRT_DIR}/concrt${v}d.dll"
+ )
+ else()
+ list(APPEND __install__libs "${MSVC_CRT_DIR}/msvcr${v}d.dll")
+ endif()
+ endif()
+
+ if(CMAKE_INSTALL_UCRT_LIBRARIES AND NOT vs VERSION_LESS 14)
+ # Find the Windows Kits directory.
+ get_filename_component(windows_kits_dir
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]" ABSOLUTE)
+ set(programfilesx86 "ProgramFiles(x86)")
+ if(";${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION};$ENV{UCRTVersion};$ENV{WindowsSDKVersion};" MATCHES [=[;(10\.[0-9.]+)[;\]]=])
+ set(__ucrt_version "${CMAKE_MATCH_1}/")
+ else()
+ set(__ucrt_version "")
+ endif()
+ find_path(WINDOWS_KITS_DIR
+ NAMES
+ Redist/${__ucrt_version}ucrt/DLLs/${CMAKE_MSVC_ARCH}/ucrtbase.dll
+ Redist/ucrt/DLLs/${CMAKE_MSVC_ARCH}/ucrtbase.dll
+ PATHS
+ $ENV{CMAKE_WINDOWS_KITS_10_DIR}
+ "${windows_kits_dir}"
+ "$ENV{ProgramFiles}/Windows Kits/10"
+ "$ENV{${programfilesx86}}/Windows Kits/10"
+ )
+ mark_as_advanced(WINDOWS_KITS_DIR)
+
+ # Glob the list of UCRT DLLs.
+ if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+ if(EXISTS "${WINDOWS_KITS_DIR}/Redist/${__ucrt_version}ucrt/DLLs/${CMAKE_MSVC_ARCH}/ucrtbase.dll")
+ file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/Redist/${__ucrt_version}ucrt/DLLs/${CMAKE_MSVC_ARCH}/*.dll")
+ else()
+ file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/Redist/ucrt/DLLs/${CMAKE_MSVC_ARCH}/*.dll")
+ endif()
+ list(APPEND __install__libs ${__ucrt_dlls})
+ endif()
+ if(CMAKE_INSTALL_DEBUG_LIBRARIES)
+ if(EXISTS "${WINDOWS_KITS_DIR}/bin/${__ucrt_version}${CMAKE_MSVC_ARCH}/ucrt/ucrtbased.dll")
+ file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/bin/${__ucrt_version}${CMAKE_MSVC_ARCH}/ucrt/*.dll")
+ else()
+ file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/bin/${CMAKE_MSVC_ARCH}/ucrt/*.dll")
+ endif()
+ list(APPEND __install__libs ${__ucrt_dlls})
+ endif()
+ endif()
+ endif()
+
+ if(CMAKE_INSTALL_MFC_LIBRARIES)
+ if(MSVC_VERSION EQUAL 1300)
+ set(__install__libs ${__install__libs}
+ "${SYSTEMROOT}/system32/mfc70.dll"
+ )
+ endif()
+
+ if(MSVC_VERSION EQUAL 1310)
+ set(__install__libs ${__install__libs}
+ "${SYSTEMROOT}/system32/mfc71.dll"
+ )
+ endif()
+
+ if(MSVC_VERSION EQUAL 1400)
+ if(CMAKE_INSTALL_DEBUG_LIBRARIES)
+ set(MSVC_MFC_DIR
+ "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC80.DebugMFC")
+ set(__install__libs ${__install__libs}
+ "${MSVC_MFC_DIR}/Microsoft.VC80.DebugMFC.manifest"
+ "${MSVC_MFC_DIR}/mfc80d.dll"
+ "${MSVC_MFC_DIR}/mfc80ud.dll"
+ "${MSVC_MFC_DIR}/mfcm80d.dll"
+ "${MSVC_MFC_DIR}/mfcm80ud.dll"
+ )
+ endif()
+
+ set(MSVC_MFC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.MFC")
+ # Install the manifest that allows DLLs to be loaded from the
+ # directory containing the executable.
+ if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+ set(__install__libs ${__install__libs}
+ "${MSVC_MFC_DIR}/Microsoft.VC80.MFC.manifest"
+ "${MSVC_MFC_DIR}/mfc80.dll"
+ "${MSVC_MFC_DIR}/mfc80u.dll"
+ "${MSVC_MFC_DIR}/mfcm80.dll"
+ "${MSVC_MFC_DIR}/mfcm80u.dll"
+ )
+ endif()
+
+ # include the language dll's for vs8 as well as the actual dll's
+ set(MSVC_MFCLOC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.MFCLOC")
+ # Install the manifest that allows DLLs to be loaded from the
+ # directory containing the executable.
+ set(__install__libs ${__install__libs}
+ "${MSVC_MFCLOC_DIR}/Microsoft.VC80.MFCLOC.manifest"
+ "${MSVC_MFCLOC_DIR}/mfc80chs.dll"
+ "${MSVC_MFCLOC_DIR}/mfc80cht.dll"
+ "${MSVC_MFCLOC_DIR}/mfc80enu.dll"
+ "${MSVC_MFCLOC_DIR}/mfc80esp.dll"
+ "${MSVC_MFCLOC_DIR}/mfc80deu.dll"
+ "${MSVC_MFCLOC_DIR}/mfc80fra.dll"
+ "${MSVC_MFCLOC_DIR}/mfc80ita.dll"
+ "${MSVC_MFCLOC_DIR}/mfc80jpn.dll"
+ "${MSVC_MFCLOC_DIR}/mfc80kor.dll"
+ )
+ endif()
+
+ if(MSVC_VERSION EQUAL 1500)
+ if(CMAKE_INSTALL_DEBUG_LIBRARIES)
+ set(MSVC_MFC_DIR
+ "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC90.DebugMFC")
+ set(__install__libs ${__install__libs}
+ "${MSVC_MFC_DIR}/Microsoft.VC90.DebugMFC.manifest"
+ "${MSVC_MFC_DIR}/mfc90d.dll"
+ "${MSVC_MFC_DIR}/mfc90ud.dll"
+ "${MSVC_MFC_DIR}/mfcm90d.dll"
+ "${MSVC_MFC_DIR}/mfcm90ud.dll"
+ )
+ endif()
+
+ set(MSVC_MFC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.MFC")
+ # Install the manifest that allows DLLs to be loaded from the
+ # directory containing the executable.
+ if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+ set(__install__libs ${__install__libs}
+ "${MSVC_MFC_DIR}/Microsoft.VC90.MFC.manifest"
+ "${MSVC_MFC_DIR}/mfc90.dll"
+ "${MSVC_MFC_DIR}/mfc90u.dll"
+ "${MSVC_MFC_DIR}/mfcm90.dll"
+ "${MSVC_MFC_DIR}/mfcm90u.dll"
+ )
+ endif()
+
+ # include the language dll's for vs9 as well as the actual dll's
+ set(MSVC_MFCLOC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.MFCLOC")
+ # Install the manifest that allows DLLs to be loaded from the
+ # directory containing the executable.
+ set(__install__libs ${__install__libs}
+ "${MSVC_MFCLOC_DIR}/Microsoft.VC90.MFCLOC.manifest"
+ "${MSVC_MFCLOC_DIR}/mfc90chs.dll"
+ "${MSVC_MFCLOC_DIR}/mfc90cht.dll"
+ "${MSVC_MFCLOC_DIR}/mfc90enu.dll"
+ "${MSVC_MFCLOC_DIR}/mfc90esp.dll"
+ "${MSVC_MFCLOC_DIR}/mfc90deu.dll"
+ "${MSVC_MFCLOC_DIR}/mfc90fra.dll"
+ "${MSVC_MFCLOC_DIR}/mfc90ita.dll"
+ "${MSVC_MFCLOC_DIR}/mfc90jpn.dll"
+ "${MSVC_MFCLOC_DIR}/mfc90kor.dll"
+ )
+ endif()
+
+ set(_MFC_DLL_VERSION "")
+ set(_MFC_IDE_VERSION "")
+ if(_MSVC_IDE_VERSION GREATER_EQUAL 10)
+ set(_MFC_DLL_VERSION ${_MSVC_DLL_VERSION})
+ set(_MFC_IDE_VERSION ${_MSVC_IDE_VERSION})
+ endif()
+
+ if(_MFC_DLL_VERSION)
+ set(v "${_MFC_DLL_VERSION}")
+ set(vs "${_MFC_IDE_VERSION}")
+
+ # Starting with VS 15 the MFC DLLs may be in a different directory.
+ if (NOT vs VERSION_LESS 15)
+ file(GLOB _MSVC_REDIST_DIRS "${MSVC_REDIST_DIR}/../*")
+ find_path(MSVC_REDIST_MFC_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.MFC
+ PATHS ${_MSVC_REDIST_DIRS} NO_DEFAULT_PATH)
+ mark_as_advanced(MSVC_REDIST_MFC_DIR)
+ unset(_MSVC_REDIST_DIRS)
+ else()
+ set(MSVC_REDIST_MFC_DIR "${MSVC_REDIST_DIR}")
+ endif()
+
+ # Multi-Byte Character Set versions of MFC are available as optional
+ # addon since Visual Studio 12. So for version 12 or higher, check
+ # whether they are available and exclude them if they are not.
+
+ if(CMAKE_INSTALL_DEBUG_LIBRARIES)
+ set(MSVC_MFC_DIR
+ "${MSVC_REDIST_MFC_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.DebugMFC")
+ set(__install__libs ${__install__libs}
+ "${MSVC_MFC_DIR}/mfc${v}ud.dll"
+ "${MSVC_MFC_DIR}/mfcm${v}ud.dll"
+ )
+ if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfc${v}d.dll")
+ set(__install__libs ${__install__libs}
+ "${MSVC_MFC_DIR}/mfc${v}d.dll"
+ )
+ endif()
+ if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfcm${v}d.dll")
+ set(__install__libs ${__install__libs}
+ "${MSVC_MFC_DIR}/mfcm${v}d.dll"
+ )
+ endif()
+ endif()
+
+ set(MSVC_MFC_DIR "${MSVC_REDIST_MFC_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.MFC")
+ if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+ set(__install__libs ${__install__libs}
+ "${MSVC_MFC_DIR}/mfc${v}u.dll"
+ "${MSVC_MFC_DIR}/mfcm${v}u.dll"
+ )
+ if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfc${v}.dll")
+ set(__install__libs ${__install__libs}
+ "${MSVC_MFC_DIR}/mfc${v}.dll"
+ )
+ endif()
+ if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfcm${v}.dll")
+ set(__install__libs ${__install__libs}
+ "${MSVC_MFC_DIR}/mfcm${v}.dll"
+ )
+ endif()
+ endif()
+
+ # include the language dll's as well as the actual dll's
+ set(MSVC_MFCLOC_DIR "${MSVC_REDIST_MFC_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.MFCLOC")
+ set(__install__libs ${__install__libs}
+ "${MSVC_MFCLOC_DIR}/mfc${v}chs.dll"
+ "${MSVC_MFCLOC_DIR}/mfc${v}cht.dll"
+ "${MSVC_MFCLOC_DIR}/mfc${v}deu.dll"
+ "${MSVC_MFCLOC_DIR}/mfc${v}enu.dll"
+ "${MSVC_MFCLOC_DIR}/mfc${v}esn.dll"
+ "${MSVC_MFCLOC_DIR}/mfc${v}fra.dll"
+ "${MSVC_MFCLOC_DIR}/mfc${v}ita.dll"
+ "${MSVC_MFCLOC_DIR}/mfc${v}jpn.dll"
+ "${MSVC_MFCLOC_DIR}/mfc${v}kor.dll"
+ "${MSVC_MFCLOC_DIR}/mfc${v}rus.dll"
+ )
+ endif()
+ endif()
+
+ # MSVC 8 was the first version with OpenMP
+ # Furthermore, there is no debug version of this
+ if(CMAKE_INSTALL_OPENMP_LIBRARIES AND _IRSL_HAVE_MSVC)
+ set(_MSOMP_DLL_VERSION ${_MSVC_DLL_VERSION})
+ set(_MSOMP_IDE_VERSION ${_MSVC_IDE_VERSION})
+
+ if(_MSOMP_DLL_VERSION)
+ set(v "${_MSOMP_DLL_VERSION}")
+ set(vs "${_MSOMP_IDE_VERSION}")
+ set(MSVC_OPENMP_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.OPENMP")
+
+ if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+ set(__install__libs ${__install__libs}
+ "${MSVC_OPENMP_DIR}/vcomp${v}.dll")
+ endif()
+ endif()
+ endif()
+
+ foreach(lib
+ ${__install__libs}
+ )
+ if(EXISTS ${lib})
+ set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS
+ ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} ${lib})
+ else()
+ if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
+ message(WARNING "system runtime library file does not exist: '${lib}'")
+ # This warning indicates an incomplete Visual Studio installation
+ # or a bug somewhere above here in this file.
+ # If you would like to avoid this warning, fix the real problem, or
+ # set CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS before including
+ # this file.
+ endif()
+ endif()
+ endforeach()
+endif()
+
+if(_IRSL_HAVE_Intel)
+ unset(__install_libs)
+ if(CMAKE_INSTALL_OPENMP_LIBRARIES)
+ if(WIN32)
+ list(APPEND __install_libs "${_Intel_redistdir}/libiomp5md.dll" "${_Intel_redistdir}/libiompstubs5md.dll")
+ elseif(APPLE)
+ list(APPEND __install_libs "${_Intel_redistdir}/libiomp5.dylib" "${_Intel_redistdir}/libiompstubs5.dylib")
+ else()
+ list(APPEND __install_libs "${_Intel_redistdir}/libiomp5.so" "${_Intel_redistdir}/libiompstubs5.so")
+ if(_Intel_compiler_ver VERSION_LESS 17)
+ list(APPEND __install_libs "${_Intel_redistdir}/libomp_db.so")
+ endif()
+ if(_Intel_compiler_ver VERSION_LESS 13)
+ list(APPEND __install_libs "${_Intel_redistdir}/libiompprof5.so")
+ endif()
+ endif()
+ endif()
+ if(WIN32)
+ set(__install_dirs "${_Intel_redistdir}/1033")
+ if(EXISTS "${_Intel_redistdir}/1041")
+ list(APPEND __install_dirs "${_Intel_redistdir}/1041")
+ endif()
+ if(_Intel_compiler_ver VERSION_LESS 18)
+ list(APPEND __install_dirs "${_Intel_redistdir}/irml" "${_Intel_redistdir}/irml_c")
+ endif()
+ foreach(__Intel_lib IN ITEMS cilkrts20.dll libchkp.dll libioffload_host.dll libirngmd.dll
+ libmmd.dll libmmdd.dll libmpx.dll liboffload.dll svml_dispmd.dll)
+
+ list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+ endforeach()
+ if(CMAKE_C_COMPILER_ID MATCHES Intel OR CMAKE_CXX_COMPILER_ID MATCHES Intel)
+ list(APPEND __install_libs "${_Intel_redistdir}/libgfxoffload.dll")
+ endif()
+ if(CMAKE_Fortran_COMPILER_ID MATCHES Intel)
+ foreach(__Intel_lib IN ITEMS ifdlg100.dll libicaf.dll libifcoremd.dll libifcoremdd.dll libifcorert.dll libifcorertd.dll libifportmd.dll)
+
+ list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+ endforeach()
+ endif()
+ elseif(APPLE)
+ foreach(__Intel_lib IN ITEMS libchkp.dylib libcilkrts.5.dylib libcilkrts.dylib libimf.dylib libintlc.dylib libirc.dylib libirng.dylib libsvml.dylib)
+ list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+ endforeach()
+ if(CMAKE_C_COMPILER_ID MATCHES Intel OR CMAKE_CXX_COMPILER_ID MATCHES Intel)
+ if(_Intel_compiler_ver VERSION_LESS 17)
+ list(APPEND __install_libs "${_Intel_redistdir}/libistrconv.dylib")
+ endif()
+ endif()
+ if(CMAKE_Fortran_COMPILER_ID MATCHES Intel)
+ foreach(__Intel_lib IN ITEMS libifcore.dylib libifcoremt.dylib libifport.dylib libifportmt.dylib)
+
+ list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+ endforeach()
+ endif()
+ else()
+ foreach(__Intel_lib IN ITEMS libchkp.so libcilkrts.so libcilkrts.so.5 libimf.so libintlc.so libintlc.so.5 libirc.so libpdbx.so libpdbx.so.5 libsvml.so)
+
+ list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+ endforeach()
+ if(_Intel_compiler_ver VERSION_GREATER_EQUAL 13)
+ foreach(__Intel_lib IN ITEMS libirng.so liboffload.so liboffload.so.5)
+
+ list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+ endforeach()
+ endif()
+ if(CMAKE_C_COMPILER_ID MATCHES Intel OR CMAKE_CXX_COMPILER_ID MATCHES Intel)
+ set(__install_dirs "${_Intel_redistdir}/irml")
+ list(APPEND __install_libs "${_Intel_redistdir}/cilk_db.so")
+ if(_Intel_compiler_ver VERSION_GREATER_EQUAL 15)
+ list(APPEND __install_libs "${_Intel_redistdir}/libistrconv.so" "${_Intel_redistdir}/libgfxoffload.so")
+ endif()
+ endif()
+ if(_Intel_compiler_ver VERSION_GREATER_EQUAL 16)
+ foreach(__Intel_lib IN ITEMS libioffload_host.so libioffload_host.so.5 libioffload_target.so libioffload_target.so.5 libmpx.so offload_main)
+
+ list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+ endforeach()
+ endif()
+ if(_Intel_compiler_ver VERSION_LESS 15)
+ foreach(__Intel_lib IN ITEMS libcxaguard.so libcxaguard.so.5)
+
+ list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+ endforeach()
+ endif()
+ if(CMAKE_Fortran_COMPILER_ID MATCHES Intel)
+ foreach(__Intel_lib IN ITEMS libicaf.so libifcore.so libifcore.so.5 libifcoremt.so libifcoremt.so.5 libifport.so libifport.so.5)
+
+ list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+ endforeach()
+ endif()
+ endif()
+
+ foreach(lib IN LISTS __install_libs)
+ if(EXISTS ${lib})
+ list(APPEND CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ${lib})
+ else()
+ if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
+ message(WARNING "system runtime library file does not exist: '${lib}'")
+ endif()
+ endif()
+ endforeach()
+
+ foreach(dir IN LISTS __install_dirs)
+ if(EXISTS ${dir})
+ list(APPEND CMAKE_INSTALL_SYSTEM_RUNTIME_DIRECTORIES ${dir})
+ else()
+ if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
+ message(WARNING "system runtime library file does not exist: '${dir}'")
+ endif()
+ endif()
+ endforeach()
+endif()
+
+if(WATCOM)
+ get_filename_component( CompilerPath ${CMAKE_C_COMPILER} PATH )
+ if(CMAKE_C_COMPILER_VERSION)
+ set(_compiler_version ${CMAKE_C_COMPILER_VERSION})
+ else()
+ set(_compiler_version ${CMAKE_CXX_COMPILER_VERSION})
+ endif()
+ string(REGEX MATCHALL "[0-9]+" _watcom_version_list "${_compiler_version}")
+ list(GET _watcom_version_list 0 _watcom_major)
+ list(GET _watcom_version_list 1 _watcom_minor)
+ set( __install__libs
+ ${CompilerPath}/clbr${_watcom_major}${_watcom_minor}.dll
+ ${CompilerPath}/mt7r${_watcom_major}${_watcom_minor}.dll
+ ${CompilerPath}/plbr${_watcom_major}${_watcom_minor}.dll )
+ foreach(lib
+ ${__install__libs}
+ )
+ if(EXISTS ${lib})
+ set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS
+ ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} ${lib})
+ else()
+ if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
+ message(WARNING "system runtime library file does not exist: '${lib}'")
+ # This warning indicates an incomplete Watcom installation
+ # or a bug somewhere above here in this file.
+ # If you would like to avoid this warning, fix the real problem, or
+ # set CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS before including
+ # this file.
+ endif()
+ endif()
+ endforeach()
+endif()
+
+
+# Include system runtime libraries in the installation if any are
+# specified by CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS.
+if(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS)
+ if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP)
+ if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION)
+ if(WIN32)
+ set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION bin)
+ else()
+ set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION lib)
+ endif()
+ endif()
+ if(CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT)
+ set(_CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT
+ COMPONENT ${CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT})
+ endif()
+ install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS}
+ DESTINATION ${CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION}
+ ${_CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT}
+ )
+
+ install(DIRECTORY ${CMAKE_INSTALL_SYSTEM_RUNTIME_DIRECTORIES}
+ DESTINATION ${CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION}
+ ${_CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT}
+ )
+ endif()
+endif()
+
+cmake_policy(POP)
diff --git a/Modules/IntelVSImplicitPath/CMakeLists.txt b/Modules/IntelVSImplicitPath/CMakeLists.txt
new file mode 100644
index 0000000..d115704
--- /dev/null
+++ b/Modules/IntelVSImplicitPath/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION ${CMAKE_VERSION})
+project(IntelFortranImplicit Fortran)
+add_custom_command(
+ OUTPUT output.cmake
+ COMMAND ${CMAKE_COMMAND} -P ${IntelFortranImplicit_SOURCE_DIR}/detect.cmake
+ )
+add_library(FortranLib hello.f output.cmake)
diff --git a/Modules/IntelVSImplicitPath/detect.cmake b/Modules/IntelVSImplicitPath/detect.cmake
new file mode 100644
index 0000000..20753be
--- /dev/null
+++ b/Modules/IntelVSImplicitPath/detect.cmake
@@ -0,0 +1,9 @@
+# look at each path and try to find ifconsol.lib
+set(LIB "$ENV{LIB}")
+foreach(dir ${LIB})
+ file(TO_CMAKE_PATH "${dir}" dir)
+ if(EXISTS "${dir}/ifconsol.lib")
+ file(WRITE output.cmake "list(APPEND implicit_dirs \"${dir}\")\n")
+ break()
+ endif()
+endforeach()
diff --git a/Modules/IntelVSImplicitPath/hello.f b/Modules/IntelVSImplicitPath/hello.f
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Modules/IntelVSImplicitPath/hello.f
diff --git a/Modules/Internal/CMakeTryCompilerOrLinkerFlag.cmake b/Modules/Internal/CMakeTryCompilerOrLinkerFlag.cmake
new file mode 100644
index 0000000..d6fa5f0
--- /dev/null
+++ b/Modules/Internal/CMakeTryCompilerOrLinkerFlag.cmake
@@ -0,0 +1,158 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=[
+
+NOTE: This function is used internally by CMake. Projects should not include
+ this file directly.
+
+The cmake_try_compiler_or_linker_flag() function can be used to compile and link a
+source file to check whether a specific compiler or linker flag is supported.
+The function does not use the try_compile() command so as to avoid infinite
+recursion. It may not work for all platforms or toolchains, the caller is
+responsible for ensuring it is only called in valid situations.
+
+ cmake_try_compiler_or_linker_flag(<lang> <flag> <result>
+ [SRC_EXT <ext>] [COMMAND_PATTERN <pattern>]
+ [FAIL_REGEX <regex> ...]
+ [OUTPUT_VARIABLE <output>])
+
+Parameters:
+ <lang> - Language to check.
+ <flag> - The flag to add to the compile/link command line.
+ <result> - Boolean output variable. It will be stored in the cache as an
+ internal variable and if true, will cause future tests that assign
+ to that variable to be bypassed.
+
+Optional parameters:
+ SRC_EXT - Overrides the extension of the source file used for the
+ check. Defaults are 'c' (C), 'cxx' (CXX), 'F' (Fortran).
+ COMMAND_PATTERN - Pattern to be used for the command line. The default is
+ '<FLAG> -o <OUTPUT> <SOURCE>'
+ FAIL_REGEX - List of additional regular expressions that, if matched by
+ the output, give a failed result for the check. A common
+ set of regular expressions will be included in addition to
+ those given by FAIL_REGEX.
+ OUTPUT_VARIABLE - Set <output> variable with details about any error.
+#]=]
+
+include_guard(GLOBAL)
+include(CMakeCheckCompilerFlagCommonPatterns)
+
+function(CMAKE_TRY_COMPILER_OR_LINKER_FLAG lang flag result)
+ # Cache results between runs similar to check_<lang>_source_compiles()
+ if(DEFINED ${result})
+ return()
+ endif()
+
+ set(comment "Is the '${flag}' option(s) supported")
+ string(REPLACE ";" " " comment "${comment}")
+
+ if (NOT lang MATCHES "^(C|CXX|Fortran|ASM)$")
+ # other possible languages are not supported
+ # log message to keep trace of this problem...
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Function 'CMAKE_CHECK_COMPILER_FLAG' called with unsupported language: ${lang}\n")
+ set(${result} FALSE CACHE INTERNAL ${comment})
+ return()
+ endif()
+ if (lang STREQUAL "ASM")
+ # assume ASM compiler is a multi-language compiler, so supports C language as well
+ set(check_lang C)
+ else()
+ set(check_lang ${lang})
+ endif()
+
+ cmake_parse_arguments(CCCF "" "SRC_EXT;COMMAND_PATTERN;OUTPUT_VARIABLE" "FAIL_REGEX" ${ARGN})
+
+ if (NOT CCCF_COMMAND_PATTERN)
+ set (CCCF_COMMAND_PATTERN "<FLAG> -o <OUTPUT> <SOURCE>")
+ endif()
+
+ list (APPEND CCCF_FAIL_REGEX "argument unused during compilation") # clang
+ if (check_lang STREQUAL "C")
+ list(APPEND CCCF_FAIL_REGEX
+ "command line option .* is valid for .* but not for C") # GNU
+ elseif(check_lang STREQUAL "CXX")
+ list(APPEND CCCF_FAIL_REGEX
+ "command line option .* is valid for .* but not for C\\+\\+") # GNU
+ elseif(check_lang STREQUAL "Fortran")
+ list(APPEND CCCF_FAIL_REGEX
+ "command line option .* is valid for .* but not for Fortran") # GNU
+ endif()
+
+ # Add patterns for common errors
+ check_compiler_flag_common_patterns(COMPILER_FLAG_COMMON_PATTERNS)
+ foreach(arg IN LISTS COMPILER_FLAG_COMMON_PATTERNS)
+ if(arg MATCHES "^FAIL_REGEX$")
+ continue()
+ endif()
+ list(APPEND CCCF_FAIL_REGEX "${arg}")
+ endforeach()
+
+ if(NOT CCCF_SRC_EXT)
+ if (check_lang STREQUAL "C")
+ set(CCCF_SRC_EXT c)
+ elseif(check_lang STREQUAL "CXX")
+ set(CCCF_SRC_EXT cxx)
+ elseif(check_lang STREQUAL "Fortran")
+ set(CCCF_SRC_EXT F)
+ endif()
+ endif()
+
+ if (CCCF_OUTPUT_VARIABLE)
+ unset(${CCCF_OUTPUT_VARIABLE} PARENT_SCOPE)
+ endif()
+
+ # Compute the directory in which to run the test.
+ set(COMPILER_FLAG_DIR "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp")
+ # Compute source and output files.
+ set(COMPILER_FLAG_SRC
+ "${COMPILER_FLAG_DIR}/CompilerFlag${lang}.${CCCF_SRC_EXT}")
+ if(check_lang STREQUAL "Fortran")
+ file(WRITE "${COMPILER_FLAG_SRC}"
+ " program simple\n end program simple\n")
+ else()
+ file(WRITE "${COMPILER_FLAG_SRC}" "int main (void)\n{ return 0; }\n")
+ endif()
+ get_filename_component(COMPILER_FLAG_EXE "${COMPILER_FLAG_SRC}" NAME_WE)
+ string(APPEND COMPILER_FLAG_EXE "${CMAKE_EXECUTABLE_SUFFIX}")
+
+ # Build command line
+ separate_arguments(CCCF_COMMAND_PATTERN UNIX_COMMAND
+ "${CCCF_COMMAND_PATTERN}")
+ list(TRANSFORM CCCF_COMMAND_PATTERN REPLACE "<SOURCE>" "${COMPILER_FLAG_SRC}")
+ list(TRANSFORM CCCF_COMMAND_PATTERN REPLACE "<OUTPUT>" "${COMPILER_FLAG_EXE}")
+ list(TRANSFORM CCCF_COMMAND_PATTERN REPLACE "<FLAG>" "${flag}")
+
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}" -E env LC_ALL=C LC_MESSAGES=C LANG=C
+ "${CMAKE_${lang}_COMPILER}" ${CCCF_COMMAND_PATTERN}
+ WORKING_DIRECTORY "${COMPILER_FLAG_DIR}"
+ OUTPUT_VARIABLE COMPILER_FLAG_OUTPUT
+ ERROR_VARIABLE COMPILER_FLAG_OUTPUT
+ RESULT_VARIABLE COMPILER_FLAG_RESULT)
+
+ # Record result in the cache so we can avoid re-testing every CMake run
+ if (COMPILER_FLAG_RESULT)
+ set(${result} FALSE CACHE INTERNAL ${comment})
+ else()
+ foreach(regex IN LISTS CCCF_FAIL_REGEX)
+ if(COMPILER_FLAG_OUTPUT MATCHES "${regex}")
+ set(${result} FALSE CACHE INTERNAL ${comment})
+ endif()
+ endforeach()
+ endif()
+ if (DEFINED ${result})
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the ${flag} option "
+ "is supported for ${lang} language failed with the following output:\n"
+ "${COMPILER_FLAG_OUTPUT}\n")
+ if (CCCF_OUTPUT_VARIABLE)
+ set(${CCCF_OUTPUT_VARIABLE} "${COMPILER_FLAG_OUTPUT}" PARENT_SCOPE)
+ endif()
+ return()
+ endif()
+
+ set(${result} TRUE CACHE INTERNAL ${comment})
+endfunction()
diff --git a/Modules/Internal/CPack/CPack.DS_Store.in b/Modules/Internal/CPack/CPack.DS_Store.in
new file mode 100644
index 0000000..5be0eeb
--- /dev/null
+++ b/Modules/Internal/CPack/CPack.DS_Store.in
Binary files differ
diff --git a/Modules/Internal/CPack/CPack.Description.plist.in b/Modules/Internal/CPack/CPack.Description.plist.in
new file mode 100644
index 0000000..3d11476
--- /dev/null
+++ b/Modules/Internal/CPack/CPack.Description.plist.in
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.4">
+<dict>
+ <key>IFPkgDescriptionTitle</key>
+ <string>@CPACK_PACKAGE_NAME@</string>
+ <key>IFPkgDescriptionVersion</key>
+ <string>@CPACK_PACKAGE_VERSION@</string>
+ <key>IFPkgDescriptionDescription</key>
+ <string>@CPACK_PACKAGE_DESCRIPTION@</string>
+</dict>
+</plist>
diff --git a/Modules/Internal/CPack/CPack.Info.plist.in b/Modules/Internal/CPack/CPack.Info.plist.in
new file mode 100644
index 0000000..6e32500
--- /dev/null
+++ b/Modules/Internal/CPack/CPack.Info.plist.in
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+
+<plist version="1.0">
+<dict>
+<key>IFMajorVersion</key>
+<integer>@CPACK_PACKAGE_VERSION_MAJOR@</integer>
+<key>IFMinorVersion</key>
+<integer>@CPACK_PACKAGE_VERSION_MINOR@</integer>
+<key>IFPkgFlagAllowBackRev</key>
+<false/>
+<key>IFPkgFlagAuthorizationAction</key>
+<string>AdminAuthorization</string>
+<key>IFPkgFlagDefaultLocation</key>
+<string>@CPACK_PACKAGE_DEFAULT_LOCATION@</string>
+<key>IFPkgFlagInstallFat</key>
+<false/>
+<key>IFPkgFlagIsRequired</key>
+<false/>
+<key>IFPkgFlagOverwritePermissions</key>
+<true/>
+<key>IFPkgFlagRelocatable</key>
+<@CPACK_PACKAGE_RELOCATABLE@/>
+<key>IFPkgFlagRestartAction</key>
+<string>NoRestart</string>
+<key>IFPkgFlagRootVolumeOnly</key>
+<false/>
+<key>IFPkgFlagUpdateInstalledLanguages</key>
+<false/>
+<key>IFPkgFlagUseUserMask</key>
+<false/>
+<key>IFPkgFormatVersion</key>
+<real>0.10000000149011612</real>
+<key>CFBundleIdentifier</key>
+<string>com.@CPACK_PACKAGE_VENDOR@.@CPACK_PACKAGE_NAME@@CPACK_MODULE_VERSION_SUFFIX@</string>
+</dict>
+</plist>
diff --git a/Modules/Internal/CPack/CPack.NuGet.nuspec.in b/Modules/Internal/CPack/CPack.NuGet.nuspec.in
new file mode 100644
index 0000000..d89d69f
--- /dev/null
+++ b/Modules/Internal/CPack/CPack.NuGet.nuspec.in
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
+ <metadata>
+ <!-- Required elements-->
+ <id>@CPACK_NUGET_PACKAGE_NAME@</id>
+ <version>@CPACK_NUGET_PACKAGE_VERSION@</version>
+ <description>@CPACK_NUGET_PACKAGE_DESCRIPTION@</description>
+ <authors>@CPACK_NUGET_PACKAGE_AUTHORS@</authors>
+
+ <!-- Optional elements -->
+ @_CPACK_NUGET_TITLE_TAG@
+ @_CPACK_NUGET_OWNERS_TAG@
+ @_CPACK_NUGET_PROJECTURL_TAG@
+ @_CPACK_NUGET_LICENSEURL_TAG@
+ @_CPACK_NUGET_LICENSE_TAG@
+ @_CPACK_NUGET_ICONURL_TAG@
+ @_CPACK_NUGET_ICON_TAG@
+ @_CPACK_NUGET_REQUIRELICENSEACCEPTANCE_TAG@
+ @_CPACK_NUGET_SUMMARY_TAG@
+ @_CPACK_NUGET_RELEASENOTES_TAG@
+ @_CPACK_NUGET_COPYRIGHT_TAG@
+ @_CPACK_NUGET_LANGUAGE_TAG@
+ @_CPACK_NUGET_TAGS_TAG@
+ @_CPACK_NUGET_DEPENDENCIES_TAG@
+ </metadata>
+ @_CPACK_NUGET_FILES_TAG@
+</package>
diff --git a/Modules/Internal/CPack/CPack.OSXScriptLauncher.in b/Modules/Internal/CPack/CPack.OSXScriptLauncher.in
new file mode 100644
index 0000000..c715860
--- /dev/null
+++ b/Modules/Internal/CPack/CPack.OSXScriptLauncher.in
Binary files differ
diff --git a/Modules/Internal/CPack/CPack.OSXScriptLauncher.rsrc.in b/Modules/Internal/CPack/CPack.OSXScriptLauncher.rsrc.in
new file mode 100644
index 0000000..5f5f17a
--- /dev/null
+++ b/Modules/Internal/CPack/CPack.OSXScriptLauncher.rsrc.in
Binary files differ
diff --git a/Modules/Internal/CPack/CPack.OSXX11.Info.plist.in b/Modules/Internal/CPack/CPack.OSXX11.Info.plist.in
new file mode 100644
index 0000000..23a1483
--- /dev/null
+++ b/Modules/Internal/CPack/CPack.OSXX11.Info.plist.in
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>@CPACK_FILE_ASSOCIATION_EXTENSION@</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>@CPACK_FILE_ASSOCIATION_TYPE@</string>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ </dict>
+ </array>
+ <key>CFBundleExecutable</key>
+ <string>@CPACK_PACKAGE_FILE_NAME@</string>
+ <key>CFBundleGetInfoString</key>
+ <string>@CPACK_APPLE_GUI_INFO_STRING@</string>
+ <key>CFBundleIconFile</key>
+ <string>@CPACK_APPLE_GUI_ICON@</string>
+ <key>CFBundleIdentifier</key>
+ <string>@CPACK_APPLE_GUI_IDENTIFIER@</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleLongVersionString</key>
+ <string>@CPACK_APPLE_GUI_LONG_VERSION_STRING@</string>
+ <key>CFBundleName</key>
+ <string>@CPACK_APPLE_GUI_BUNDLE_NAME@</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>@CPACK_APPLE_GUI_SHORT_VERSION_STRING@</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>@CPACK_APPLE_GUI_BUNDLE_VERSION@</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+ <key>NSHumanReadableCopyright</key>
+ <string>@CPACK_APPLE_GUI_COPYRIGHT@</string>
+</dict>
+</plist>
diff --git a/Modules/Internal/CPack/CPack.OSXX11.main.scpt.in b/Modules/Internal/CPack/CPack.OSXX11.main.scpt.in
new file mode 100644
index 0000000..de30ea1
--- /dev/null
+++ b/Modules/Internal/CPack/CPack.OSXX11.main.scpt.in
Binary files differ
diff --git a/Modules/Internal/CPack/CPack.RuntimeScript.in b/Modules/Internal/CPack/CPack.RuntimeScript.in
new file mode 100755
index 0000000..f27444f
--- /dev/null
+++ b/Modules/Internal/CPack/CPack.RuntimeScript.in
@@ -0,0 +1,87 @@
+#!/bin/sh
+#
+# Modified from: Aaron Voisine <aaron@voisine.org>
+
+CWD="`dirname \"$0\"`"
+TMP=/tmp/$(id -ru)/TemporaryItems
+
+version=`sw_vers -productVersion`
+if [ "$?" = "0" ]; then
+ major=${version%%\.*}
+ rest=${version#*\.}
+ minor=${rest%%\.*}
+ build=${rest#*\.}
+else
+ major=10
+ minor=4
+ build=0
+fi
+
+echo $version
+echo "Major = $major"
+echo "Minor = $minor"
+echo "Build = $build"
+
+
+# if 10.5 or greater, then all the open-x11 stuff need not occur
+if [ "$major" -lt 10 ] || ([ "$major" -eq 10 ] && [ "$minor" -lt 5 ]); then
+version=`sw_vers -productVersion`
+if [ "$?" = "0" ]; then
+ major=${version%%\.*}
+ rest=${version#*\.}
+ minor=${rest%%\.*}
+ build=${rest#*\.}
+else
+ major=10
+ minor=4
+ build=0
+fi
+
+echo $version
+echo "Major = $major"
+echo "Minor = $minor"
+echo "Build = $build"
+
+
+# if 10.5 or greater, then all the open-x11 stuff need not occur
+if [ "$major" -lt 10 ] || ([ "$major" -eq 10 ] && [ "$minor" -lt 5 ]); then
+ps -wx -ocommand | grep -e '[X]11.app' > /dev/null
+if [ "$?" != "0" -a ! -f ~/.xinitrc ]; then
+ echo "rm -f ~/.xinitrc" > ~/.xinitrc
+ sed 's/xterm/# xterm/' /usr/X11R6/lib/X11/xinit/xinitrc >> ~/.xinitrc
+fi
+
+mkdir -p $TMP
+cat << __END_OF_GETDISPLAY_SCRIPT__ > "$TMP/getdisplay.sh"
+#!/bin/sh
+mkdir -p "$TMP"
+
+if [ "\$DISPLAY"x = "x" ]; then
+ echo :0 > "$TMP/display"
+else
+ echo \$DISPLAY > "$TMP/display"
+fi
+__END_OF_GETDISPLAY_SCRIPT__
+fi
+chmod +x "$TMP/getdisplay.sh"
+rm -f $TMP/display
+open-x11 $TMP/getdisplay.sh || \
+open -a XDarwin $TMP/getdisplay.sh || \
+echo ":0" > $TMP/display
+
+while [ "$?" = "0" -a ! -f $TMP/display ];
+do
+ #echo "Waiting for display $TMP/display"
+ sleep 1;
+done
+export "DISPLAY=`cat $TMP/display`"
+
+ps -wx -ocommand | grep -e '[X]11' > /dev/null || exit 11
+
+cd ~/
+echo "$@" > /tmp/arguments.log
+if echo $1 | grep -- "^-psn_"; then
+ shift
+fi
+fi
+exec "$CWD/bin/@CPACK_EXECUTABLE_NAME@" "$@" > /tmp/slicer.output 2>&1
diff --git a/Modules/Internal/CPack/CPack.STGZ_Header.sh.in b/Modules/Internal/CPack/CPack.STGZ_Header.sh.in
new file mode 100755
index 0000000..a857aa5
--- /dev/null
+++ b/Modules/Internal/CPack/CPack.STGZ_Header.sh.in
@@ -0,0 +1,149 @@
+#!/bin/sh
+
+# Display usage
+cpack_usage()
+{
+ cat <<EOF
+Usage: $0 [options]
+Options: [defaults in brackets after descriptions]
+ --help print this message
+ --version print cmake installer version
+ --prefix=dir directory in which to install
+ --include-subdir include the @CPACK_PACKAGE_FILE_NAME@ subdirectory
+ --exclude-subdir exclude the @CPACK_PACKAGE_FILE_NAME@ subdirectory
+ --skip-license accept license
+EOF
+ exit 1
+}
+
+cpack_echo_exit()
+{
+ echo $1
+ exit 1
+}
+
+# Display version
+cpack_version()
+{
+ echo "@CPACK_PACKAGE_NAME@ Installer Version: @CPACK_PACKAGE_VERSION@, Copyright (c) @CPACK_PACKAGE_VENDOR@"
+}
+
+# Helper function to fix windows paths.
+cpack_fix_slashes ()
+{
+ echo "$1" | sed 's/\\/\//g'
+}
+
+interactive=TRUE
+cpack_skip_license=FALSE
+cpack_include_subdir=""
+for a in "$@CPACK_AT_SIGN@"; do
+ if echo $a | grep "^--prefix=" > /dev/null 2> /dev/null; then
+ cpack_prefix_dir=`echo $a | sed "s/^--prefix=//"`
+ cpack_prefix_dir=`cpack_fix_slashes "${cpack_prefix_dir}"`
+ fi
+ if echo $a | grep "^--help" > /dev/null 2> /dev/null; then
+ cpack_usage
+ fi
+ if echo $a | grep "^--version" > /dev/null 2> /dev/null; then
+ cpack_version
+ exit 2
+ fi
+ if echo $a | grep "^--include-subdir" > /dev/null 2> /dev/null; then
+ cpack_include_subdir=TRUE
+ fi
+ if echo $a | grep "^--exclude-subdir" > /dev/null 2> /dev/null; then
+ cpack_include_subdir=FALSE
+ fi
+ if echo $a | grep "^--skip-license" > /dev/null 2> /dev/null; then
+ cpack_skip_license=TRUE
+ fi
+done
+
+if [ "x${cpack_include_subdir}x" != "xx" -o "x${cpack_skip_license}x" = "xTRUEx" ]
+then
+ interactive=FALSE
+fi
+
+cpack_version
+echo "This is a self-extracting archive."
+toplevel="`pwd`"
+if [ "x${cpack_prefix_dir}x" != "xx" ]
+then
+ toplevel="${cpack_prefix_dir}"
+fi
+
+echo "The archive will be extracted to: ${toplevel}"
+
+if [ "x${interactive}x" = "xTRUEx" ]
+then
+ echo ""
+ echo "If you want to stop extracting, please press <ctrl-C>."
+
+ if [ "x${cpack_skip_license}x" != "xTRUEx" ]
+ then
+ more << '____cpack__here_doc____'
+@CPACK_RESOURCE_FILE_LICENSE_CONTENT@
+____cpack__here_doc____
+ echo
+ while true
+ do
+ echo "Do you accept the license? [yn]: "
+ read line leftover
+ case ${line} in
+ y* | Y*)
+ cpack_license_accepted=TRUE
+ break;;
+ n* | N* | q* | Q* | e* | E*)
+ echo "License not accepted. Exiting ..."
+ exit 1;;
+ esac
+ done
+ fi
+
+ if [ "x${cpack_include_subdir}x" = "xx" ]
+ then
+ echo "By default the @CPACK_PACKAGE_NAME@ will be installed in:"
+ echo " \"${toplevel}/@CPACK_PACKAGE_FILE_NAME@\""
+ echo "Do you want to include the subdirectory @CPACK_PACKAGE_FILE_NAME@?"
+ echo "Saying no will install in: \"${toplevel}\" [Yn]: "
+ read line leftover
+ cpack_include_subdir=TRUE
+ case ${line} in
+ n* | N*)
+ cpack_include_subdir=FALSE
+ esac
+ fi
+fi
+
+if [ "x${cpack_include_subdir}x" = "xTRUEx" ]
+then
+ toplevel="${toplevel}/@CPACK_PACKAGE_FILE_NAME@"
+ mkdir -p "${toplevel}"
+fi
+echo
+echo "Using target directory: ${toplevel}"
+echo "Extracting, please wait..."
+echo ""
+
+# take the archive portion of this file and pipe it to tar
+# the NUMERIC parameter in this command should be one more
+# than the number of lines in this header file
+# there are tails which don't understand the "-n" argument, e.g. on SunOS
+# OTOH there are tails which complain when not using the "-n" argument (e.g. GNU)
+# so at first try to tail some file to see if tail fails if used with "-n"
+# if so, don't use "-n"
+use_new_tail_syntax="-n"
+tail $use_new_tail_syntax +1 "$0" > /dev/null 2> /dev/null || use_new_tail_syntax=""
+
+extractor="pax -r"
+command -v pax > /dev/null 2> /dev/null || extractor="tar xf -"
+
+tail $use_new_tail_syntax +###CPACK_HEADER_LENGTH### "$0" | gunzip | (cd "${toplevel}" && ${extractor}) || cpack_echo_exit "Problem unpacking the @CPACK_PACKAGE_FILE_NAME@"
+
+echo "Unpacking finished successfully"
+
+exit 0
+#-----------------------------------------------------------
+# Start of TAR.GZ file
+#-----------------------------------------------------------;
diff --git a/Modules/Internal/CPack/CPack.VolumeIcon.icns.in b/Modules/Internal/CPack/CPack.VolumeIcon.icns.in
new file mode 100644
index 0000000..c59217e
--- /dev/null
+++ b/Modules/Internal/CPack/CPack.VolumeIcon.icns.in
Binary files differ
diff --git a/Modules/Internal/CPack/CPack.background.png.in b/Modules/Internal/CPack/CPack.background.png.in
new file mode 100644
index 0000000..a32ab37
--- /dev/null
+++ b/Modules/Internal/CPack/CPack.background.png.in
Binary files differ
diff --git a/Modules/Internal/CPack/CPack.distribution.dist.in b/Modules/Internal/CPack/CPack.distribution.dist.in
new file mode 100644
index 0000000..f20e66c
--- /dev/null
+++ b/Modules/Internal/CPack/CPack.distribution.dist.in
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<installer-gui-script minSpecVersion="1.0">
+ <title>@CPACK_PACKAGE_NAME@</title>
+ <welcome file="@CPACK_RESOURCE_FILE_WELCOME_NOPATH@"/>
+ <readme file="@CPACK_RESOURCE_FILE_README_NOPATH@"/>
+ <license file="@CPACK_RESOURCE_FILE_LICENSE_NOPATH@"/>
+ <options allow-external-scripts="no" customize="allow" rootVolumeOnly="false"></options>
+ @CPACK_PACKAGEMAKER_CHOICES@
+</installer-gui-script>
diff --git a/Modules/Internal/CPack/CPackDeb.cmake b/Modules/Internal/CPack/CPackDeb.cmake
new file mode 100644
index 0000000..2ef0489
--- /dev/null
+++ b/Modules/Internal/CPack/CPackDeb.cmake
@@ -0,0 +1,793 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# CPack script for creating Debian package
+# Author: Mathieu Malaterre
+#
+# http://wiki.debian.org/HowToPackageForDebian
+
+if(CMAKE_BINARY_DIR)
+ message(FATAL_ERROR "CPackDeb.cmake may only be used by CPack internally.")
+endif()
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+function(cpack_deb_variable_fallback OUTPUT_VAR_NAME)
+ set(FALLBACK_VAR_NAMES ${ARGN})
+
+ foreach(variable_name IN LISTS FALLBACK_VAR_NAMES)
+ if(${variable_name})
+ set(${OUTPUT_VAR_NAME} "${${variable_name}}" PARENT_SCOPE)
+ break()
+ endif()
+ endforeach()
+endfunction()
+
+function(get_component_package_name var component)
+ string(TOUPPER "${component}" component_upcase)
+ if(CPACK_DEBIAN_${component_upcase}_PACKAGE_NAME)
+ string(TOLOWER "${CPACK_DEBIAN_${component_upcase}_PACKAGE_NAME}" package_name)
+ else()
+ string(TOLOWER "${CPACK_DEBIAN_PACKAGE_NAME}-${component}" package_name)
+ endif()
+
+ set("${var}" "${package_name}" PARENT_SCOPE)
+endfunction()
+
+#extract library name and version for given shared object
+function(extract_so_info shared_object libname version)
+ if(READELF_EXECUTABLE)
+ execute_process(COMMAND "${READELF_EXECUTABLE}" -d "${shared_object}"
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE output
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(result EQUAL 0)
+ string(REGEX MATCH "\\(?SONAME\\)?[^\n]*\\[([^\n]+)\\.so\\.([^\n]*)\\]" soname "${output}")
+ set(${libname} "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ set(${version} "${CMAKE_MATCH_2}" PARENT_SCOPE)
+ else()
+ message(WARNING "Error running readelf for \"${shared_object}\"")
+ endif()
+ else()
+ message(FATAL_ERROR "Readelf utility is not available.")
+ endif()
+endfunction()
+
+function(cpack_deb_check_description SUMMARY LINES RESULT_VARIABLE)
+ set(_result TRUE)
+
+ # Get the summary line
+ if(NOT SUMMARY MATCHES "^[^\\s].*$")
+ set(_result FALSE)
+ set(${RESULT_VARIABLE} ${_result} PARENT_SCOPE)
+ return()
+ endif()
+
+ foreach(_line IN LISTS LINES)
+ if(NOT _line MATCHES "^ +[^ ]+.*$")
+ set(_result FALSE)
+ break()
+ endif()
+ endforeach()
+
+ set(${RESULT_VARIABLE} ${_result} PARENT_SCOPE)
+endfunction()
+
+function(cpack_deb_format_package_description TEXT OUTPUT_VAR)
+ # Turn the possible multi-line string into a list
+ string(UUID uuid NAMESPACE 00000000-0000-0000-0000-000000000000 TYPE SHA1)
+ string(REPLACE ";" "${uuid}" _text "${TEXT}")
+ string(REPLACE "\n" ";" _lines "${_text}")
+ list(POP_FRONT _lines _summary)
+
+ # If the description ends with a newline (e.g. typically if it was read
+ # from a file) the last line will be empty. We drop it here, otherwise
+ # it would be replaced by a `.` which would lead to the package violating
+ # the extended-description-contains-empty-paragraph debian policy
+ list(POP_BACK _lines _last_line)
+ string(STRIP "${_last_line}" _last_line_strip)
+ if(_last_line_strip)
+ list(APPEND _lines "${_last_line_strip}")
+ endif()
+
+ # Check if reformatting required
+ cpack_deb_check_description("${_summary}" "${_lines}" _result)
+ if(_result)
+ # Ok, no formatting required
+ set(${OUTPUT_VAR} "${TEXT}" PARENT_SCOPE)
+ return()
+ endif()
+
+ # Format the summary line
+ string(STRIP "${_summary}" _summary)
+
+ # Make sure the rest formatted properly
+ set(_result)
+ foreach(_line IN LISTS _lines)
+ string(STRIP "${_line}" _line_strip)
+ if(NOT _line_strip)
+ # Replace empty lines w/ a _single full stop character_
+ set(_line " .")
+ else()
+ # Prepend the normal lines w/ a single space.
+ # If the line already starts w/ at least one space,
+ # it'll become _verbatim_ (assuming it supposed to be
+ # verbatim in the original text).
+ string(PREPEND _line " ")
+ endif()
+ list(APPEND _result "${_line}")
+ endforeach()
+
+ list(PREPEND _result "${_summary}")
+ list(JOIN _result "\n" _result)
+ string(REPLACE "${uuid}" ";" _result "${_result}")
+ set(${OUTPUT_VAR} "${_result}" PARENT_SCOPE)
+endfunction()
+
+function(cpack_deb_prepare_package_vars)
+ # CPACK_DEBIAN_PACKAGE_SHLIBDEPS
+ # If specify OFF, only user depends are used
+ if(NOT DEFINED CPACK_DEBIAN_PACKAGE_SHLIBDEPS)
+ set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OFF)
+ endif()
+
+ set(WDIR "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_DEB_PACKAGE_COMPONENT_PART_PATH}")
+ set(DBGSYMDIR "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_DEB_PACKAGE_COMPONENT_PART_PATH}-dbgsym")
+ file(REMOVE_RECURSE "${DBGSYMDIR}")
+
+ # per component automatic discover: some of the component might not have
+ # binaries.
+ if(CPACK_DEB_PACKAGE_COMPONENT)
+ string(TOUPPER "${CPACK_DEB_PACKAGE_COMPONENT}" _local_component_name)
+ set(_component_shlibdeps_var "CPACK_DEBIAN_${_local_component_name}_PACKAGE_SHLIBDEPS")
+
+ # if set, overrides the global configuration
+ if(DEFINED ${_component_shlibdeps_var})
+ set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS "${${_component_shlibdeps_var}}")
+ if(CPACK_DEBIAN_PACKAGE_DEBUG)
+ message("CPackDeb Debug: component '${CPACK_DEB_PACKAGE_COMPONENT}' dpkg-shlibdeps set to ${CPACK_DEBIAN_PACKAGE_SHLIBDEPS}")
+ endif()
+ endif()
+ endif()
+
+ cpack_deb_variable_fallback("CPACK_DEBIAN_DEBUGINFO_PACKAGE"
+ "CPACK_DEBIAN_${_local_component_name}_DEBUGINFO_PACKAGE"
+ "CPACK_DEBIAN_DEBUGINFO_PACKAGE")
+ if(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OR CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS OR CPACK_DEBIAN_DEBUGINFO_PACKAGE)
+ # Generating binary list - Get type of all install files
+ file(GLOB_RECURSE FILE_PATHS_ LIST_DIRECTORIES false RELATIVE "${WDIR}" "${WDIR}/*")
+
+ find_program(FILE_EXECUTABLE file)
+ if(NOT FILE_EXECUTABLE)
+ message(FATAL_ERROR "CPackDeb: file utility is not available. CPACK_DEBIAN_PACKAGE_SHLIBDEPS and CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS options are not available.")
+ endif()
+
+ # get file info so that we can determine if file is executable or not
+ unset(CPACK_DEB_INSTALL_FILES)
+ foreach(FILE_ IN LISTS FILE_PATHS_)
+ execute_process(COMMAND ${CMAKE_COMMAND} -E env LC_ALL=C ${FILE_EXECUTABLE} "./${FILE_}"
+ WORKING_DIRECTORY "${WDIR}"
+ RESULT_VARIABLE FILE_RESULT_
+ OUTPUT_VARIABLE INSTALL_FILE_)
+ if(NOT FILE_RESULT_ EQUAL 0)
+ message(FATAL_ERROR "CPackDeb: execution of command: '${FILE_EXECUTABLE} ./${FILE_}' failed with exit code: ${FILE_RESULT_}")
+ endif()
+ list(APPEND CPACK_DEB_INSTALL_FILES "${INSTALL_FILE_}")
+ endforeach()
+
+ # Only dynamically linked ELF files are included
+ # Extract only file name infront of ":"
+ foreach(_FILE IN LISTS CPACK_DEB_INSTALL_FILES)
+ if(_FILE MATCHES "ELF.*dynamically linked")
+ string(REGEX MATCH "(^.*):" _FILE_NAME "${_FILE}")
+ list(APPEND CPACK_DEB_BINARY_FILES "${CMAKE_MATCH_1}")
+ set(CONTAINS_EXECUTABLE_FILES_ TRUE)
+ endif()
+ if(_FILE MATCHES "ELF.*shared object")
+ string(REGEX MATCH "(^.*):" _FILE_NAME "${_FILE}")
+ list(APPEND CPACK_DEB_SHARED_OBJECT_FILES "${CMAKE_MATCH_1}")
+ endif()
+ if(_FILE MATCHES "ELF.*not stripped")
+ string(REGEX MATCH "(^.*):" _FILE_NAME "${_FILE}")
+ list(APPEND CPACK_DEB_UNSTRIPPED_FILES "${CMAKE_MATCH_1}")
+ endif()
+ endforeach()
+ endif()
+
+ find_program(READELF_EXECUTABLE NAMES readelf)
+
+ if(CPACK_DEBIAN_DEBUGINFO_PACKAGE AND CPACK_DEB_UNSTRIPPED_FILES)
+ find_program(OBJCOPY_EXECUTABLE NAMES objcopy)
+
+ if(NOT OBJCOPY_EXECUTABLE)
+ message(FATAL_ERROR "debuginfo packages require the objcopy tool")
+ endif()
+ if(NOT READELF_EXECUTABLE)
+ message(FATAL_ERROR "debuginfo packages require the readelf tool")
+ endif()
+
+ file(RELATIVE_PATH _DBGSYM_ROOT "${CPACK_TEMPORARY_DIRECTORY}" "${DBGSYMDIR}")
+ foreach(_FILE IN LISTS CPACK_DEB_UNSTRIPPED_FILES)
+
+ # Get the file's Build ID
+ execute_process(COMMAND env LC_ALL=C ${READELF_EXECUTABLE} -n "${_FILE}"
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE READELF_OUTPUT
+ RESULT_VARIABLE READELF_RESULT
+ ERROR_VARIABLE READELF_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE )
+ if(NOT READELF_RESULT EQUAL 0)
+ message(FATAL_ERROR "CPackDeb: readelf: '${READELF_ERROR}';\n"
+ "executed command: '${READELF_EXECUTABLE} -n ${_FILE}'")
+ endif()
+ if(READELF_OUTPUT MATCHES "Build ID: ([0-9a-zA-Z][0-9a-zA-Z])([0-9a-zA-Z]*)")
+ set(_BUILD_ID_START ${CMAKE_MATCH_1})
+ set(_BUILD_ID_REMAINING ${CMAKE_MATCH_2})
+ list(APPEND BUILD_IDS ${_BUILD_ID_START}${_BUILD_ID_REMAINING})
+ else()
+ message(FATAL_ERROR "Unable to determine Build ID for ${_FILE}")
+ endif()
+
+ # Split out the debug symbols from the binaries
+ set(_FILE_DBGSYM ${_DBGSYM_ROOT}/usr/lib/debug/.build-id/${_BUILD_ID_START}/${_BUILD_ID_REMAINING}.debug)
+ get_filename_component(_OUT_DIR "${_FILE_DBGSYM}" DIRECTORY)
+ file(MAKE_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}/${_OUT_DIR}")
+ execute_process(COMMAND ${OBJCOPY_EXECUTABLE} --only-keep-debug "${_FILE}" "${_FILE_DBGSYM}"
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE OBJCOPY_OUTPUT
+ RESULT_VARIABLE OBJCOPY_RESULT
+ ERROR_VARIABLE OBJCOPY_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE )
+ if(NOT OBJCOPY_RESULT EQUAL 0)
+ message(FATAL_ERROR "CPackDeb: objcopy: '${OBJCOPY_ERROR}';\n"
+ "executed command: '${OBJCOPY_EXECUTABLE} --only-keep-debug ${_FILE} ${_FILE_DBGSYM}'")
+ endif()
+ execute_process(COMMAND ${OBJCOPY_EXECUTABLE} --strip-unneeded ${_FILE}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE OBJCOPY_OUTPUT
+ RESULT_VARIABLE OBJCOPY_RESULT
+ ERROR_VARIABLE OBJCOPY_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE )
+ if(NOT OBJCOPY_RESULT EQUAL 0)
+ message(FATAL_ERROR "CPackDeb: objcopy: '${OBJCOPY_ERROR}';\n"
+ "executed command: '${OBJCOPY_EXECUTABLE} --strip-debug ${_FILE}'")
+ endif()
+ execute_process(COMMAND ${OBJCOPY_EXECUTABLE} --add-gnu-debuglink=${_FILE_DBGSYM} ${_FILE}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE OBJCOPY_OUTPUT
+ RESULT_VARIABLE OBJCOPY_RESULT
+ ERROR_VARIABLE OBJCOPY_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE )
+ if(NOT OBJCOPY_RESULT EQUAL 0)
+ message(FATAL_ERROR "CPackDeb: objcopy: '${OBJCOPY_ERROR}';\n"
+ "executed command: '${OBJCOPY_EXECUTABLE} --add-gnu-debuglink=${_FILE_DBGSYM} ${_FILE}'")
+ endif()
+ endforeach()
+ endif()
+
+ if(CPACK_DEBIAN_PACKAGE_SHLIBDEPS)
+ # dpkg-shlibdeps is a Debian utility for generating dependency list
+ find_program(SHLIBDEPS_EXECUTABLE dpkg-shlibdeps)
+
+ if(SHLIBDEPS_EXECUTABLE)
+ # Check version of the dpkg-shlibdeps tool using CPackDEB method
+ execute_process(COMMAND ${CMAKE_COMMAND} -E env LC_ALL=C ${SHLIBDEPS_EXECUTABLE} --version
+ OUTPUT_VARIABLE _TMP_VERSION
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(_TMP_VERSION MATCHES "dpkg-shlibdeps version ([0-9]+\\.[0-9]+\\.[0-9]+)")
+ set(SHLIBDEPS_EXECUTABLE_VERSION "${CMAKE_MATCH_1}")
+ else()
+ unset(SHLIBDEPS_EXECUTABLE_VERSION)
+ endif()
+
+ if(CPACK_DEBIAN_PACKAGE_DEBUG)
+ message("CPackDeb Debug: dpkg-shlibdeps --version output is '${_TMP_VERSION}'")
+ message("CPackDeb Debug: dpkg-shlibdeps version is <${SHLIBDEPS_EXECUTABLE_VERSION}>")
+ endif()
+
+ if(CONTAINS_EXECUTABLE_FILES_)
+ message("CPackDeb: - Generating dependency list")
+
+ # Create blank control file for running dpkg-shlibdeps
+ # There might be some other way to invoke dpkg-shlibdeps without creating this file
+ # but standard debian package should not have anything that can collide with this file or directory
+ file(MAKE_DIRECTORY ${CPACK_TEMPORARY_DIRECTORY}/debian)
+ file(WRITE ${CPACK_TEMPORARY_DIRECTORY}/debian/control "")
+
+ # Create a DEBIAN directory so that dpkg-shlibdeps can find the package dir when resolving $ORIGIN.
+ file(MAKE_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}/DEBIAN")
+
+ # Add --ignore-missing-info if the tool supports it
+ execute_process(COMMAND ${CMAKE_COMMAND} -E env LC_ALL=C ${SHLIBDEPS_EXECUTABLE} --help
+ OUTPUT_VARIABLE _TMP_HELP
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(_TMP_HELP MATCHES "--ignore-missing-info")
+ set(IGNORE_MISSING_INFO_FLAG "--ignore-missing-info")
+ endif()
+
+ if(CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS)
+ unset(PRIVATE_SEARCH_DIR_OPTIONS)
+ # Add -l option if the tool supports it
+ if(DEFINED SHLIBDEPS_EXECUTABLE_VERSION AND SHLIBDEPS_EXECUTABLE_VERSION VERSION_GREATER_EQUAL 1.17.0)
+ foreach(dir IN LISTS CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS)
+ list(APPEND PRIVATE_SEARCH_DIR_OPTIONS "-l${dir}")
+ endforeach()
+ else()
+ message(WARNING "CPackDeb: dkpg-shlibdeps is too old. \"CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS\" is therefore ignored.")
+ endif()
+ endif()
+
+ # Execute dpkg-shlibdeps
+ # --ignore-missing-info : allow dpkg-shlibdeps to run even if some libs do not belong to a package
+ # -l<dir>: make dpkg-shlibdeps also search in this directory for (private) shared library dependencies
+ # -O : print to STDOUT
+ execute_process(COMMAND ${SHLIBDEPS_EXECUTABLE} ${PRIVATE_SEARCH_DIR_OPTIONS} ${IGNORE_MISSING_INFO_FLAG} -O ${CPACK_DEB_BINARY_FILES}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE SHLIBDEPS_OUTPUT
+ RESULT_VARIABLE SHLIBDEPS_RESULT
+ ERROR_VARIABLE SHLIBDEPS_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE )
+ if(CPACK_DEBIAN_PACKAGE_DEBUG)
+ # dpkg-shlibdeps will throw some warnings if some input files are not binary
+ message( "CPackDeb Debug: dpkg-shlibdeps warnings \n${SHLIBDEPS_ERROR}")
+ endif()
+ if(NOT SHLIBDEPS_RESULT EQUAL 0)
+ message(FATAL_ERROR "CPackDeb: dpkg-shlibdeps: '${SHLIBDEPS_ERROR}';\n"
+ "executed command: '${SHLIBDEPS_EXECUTABLE} ${PRIVATE_SEARCH_DIR_OPTIONS} ${IGNORE_MISSING_INFO_FLAG} -O ${CPACK_DEB_BINARY_FILES}';\n"
+ "found files: '${INSTALL_FILE_}';\n"
+ "files info: '${CPACK_DEB_INSTALL_FILES}';\n"
+ "binary files: '${CPACK_DEB_BINARY_FILES}'")
+ endif()
+
+ #Get rid of prefix generated by dpkg-shlibdeps
+ string(REGEX REPLACE "^.*Depends=" "" CPACK_DEBIAN_PACKAGE_AUTO_DEPENDS "${SHLIBDEPS_OUTPUT}")
+
+ if(CPACK_DEBIAN_PACKAGE_DEBUG)
+ message("CPackDeb Debug: Found dependency: ${CPACK_DEBIAN_PACKAGE_AUTO_DEPENDS} from output ${SHLIBDEPS_OUTPUT}")
+ endif()
+
+ # Remove blank control file
+ # Might not be safe if package actual contain file or directory named debian
+ file(REMOVE_RECURSE "${CPACK_TEMPORARY_DIRECTORY}/debian")
+
+ # remove temporary directory that was created only for dpkg-shlibdeps execution
+ file(REMOVE_RECURSE "${CPACK_TEMPORARY_DIRECTORY}/DEBIAN")
+ else()
+ if(CPACK_DEBIAN_PACKAGE_DEBUG)
+ message(AUTHOR_WARNING "CPackDeb Debug: Using only user-provided depends because package does not contain executable files that link to shared libraries.")
+ endif()
+ endif()
+ else()
+ message("CPackDeb: Using only user-provided dependencies because dpkg-shlibdeps is not found.")
+ endif()
+
+ else()
+ if(CPACK_DEBIAN_PACKAGE_DEBUG)
+ message("CPackDeb Debug: Using only user-provided dependencies")
+ endif()
+ endif()
+
+ # Let's define the control file found in debian package:
+
+ # Binary package:
+ # http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-binarycontrolfiles
+
+ # DEBIAN/control
+ # debian policy enforce lower case for package name
+ # Package: (mandatory)
+ if(NOT CPACK_DEBIAN_PACKAGE_NAME)
+ string(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_DEBIAN_PACKAGE_NAME)
+ endif()
+
+ # Version: (mandatory)
+ if(NOT CPACK_DEBIAN_PACKAGE_VERSION)
+ if(NOT CPACK_PACKAGE_VERSION)
+ message(FATAL_ERROR "CPackDeb: Debian package requires a package version")
+ endif()
+ set(CPACK_DEBIAN_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION})
+ endif()
+
+ if(DEFINED CPACK_DEBIAN_PACKAGE_RELEASE OR DEFINED CPACK_DEBIAN_PACKAGE_EPOCH)
+ # only test the version format if CPACK_DEBIAN_PACKAGE_RELEASE or
+ # CPACK_DEBIAN_PACKAGE_EPOCH is set
+ if(NOT CPACK_DEBIAN_PACKAGE_VERSION MATCHES "^[0-9][A-Za-z0-9.+~-]*$")
+ message(FATAL_ERROR
+ "CPackDeb: Debian package version must confirm to \"^[0-9][A-Za-z0-9.+~-]*$\" regex!")
+ endif()
+ else()
+ # before CMake 3.10 version format was not tested so only warn to preserve
+ # backward compatibility
+ if(NOT CPACK_DEBIAN_PACKAGE_VERSION MATCHES "^([0-9]+:)?[0-9][A-Za-z0-9.+~-]*$")
+ message(AUTHOR_WARNING
+ "CPackDeb: Debian package versioning ([<epoch>:]<version>[-<release>])"
+ " should confirm to \"^([0-9]+:)?[0-9][A-Za-z0-9.+~-]*$\" regex in"
+ " order to satisfy Debian packaging rules.")
+ endif()
+ endif()
+
+ if(CPACK_DEBIAN_PACKAGE_RELEASE)
+ if(NOT CPACK_DEBIAN_PACKAGE_RELEASE MATCHES "^[A-Za-z0-9.+~]+$")
+ message(FATAL_ERROR
+ "CPackDeb: Debian package release must confirm to \"^[A-Za-z0-9.+~]+$\" regex!")
+ endif()
+ string(APPEND CPACK_DEBIAN_PACKAGE_VERSION
+ "-${CPACK_DEBIAN_PACKAGE_RELEASE}")
+ elseif(DEFINED CPACK_DEBIAN_PACKAGE_EPOCH)
+ # only test the version format if CPACK_DEBIAN_PACKAGE_RELEASE or
+ # CPACK_DEBIAN_PACKAGE_EPOCH is set - versions CPack/Deb generator before
+ # CMake 3.10 did not check for version format so we have to preserve
+ # backward compatibility
+ if(CPACK_DEBIAN_PACKAGE_VERSION MATCHES ".*-.*")
+ message(FATAL_ERROR
+ "CPackDeb: Debian package version must not contain hyphens when CPACK_DEBIAN_PACKAGE_RELEASE is not provided!")
+ endif()
+ endif()
+
+ if(CPACK_DEBIAN_PACKAGE_EPOCH)
+ if(NOT CPACK_DEBIAN_PACKAGE_EPOCH MATCHES "^[0-9]+$")
+ message(FATAL_ERROR
+ "CPackDeb: Debian package epoch must confirm to \"^[0-9]+$\" regex!")
+ endif()
+ set(CPACK_DEBIAN_PACKAGE_VERSION
+ "${CPACK_DEBIAN_PACKAGE_EPOCH}:${CPACK_DEBIAN_PACKAGE_VERSION}")
+ endif()
+
+ # Architecture: (mandatory)
+ if(CPACK_DEB_PACKAGE_COMPONENT AND CPACK_DEBIAN_${_local_component_name}_PACKAGE_ARCHITECTURE)
+ set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "${CPACK_DEBIAN_${_local_component_name}_PACKAGE_ARCHITECTURE}")
+ elseif(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
+ # There is no such thing as i686 architecture on debian, you should use i386 instead
+ # $ dpkg --print-architecture
+ find_program(DPKG_CMD dpkg)
+ if(NOT DPKG_CMD)
+ message(STATUS "CPackDeb: Can not find dpkg in your path, default to i386.")
+ set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE i386)
+ endif()
+ execute_process(COMMAND "${DPKG_CMD}" --print-architecture
+ OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ endif()
+
+ # Source: (optional)
+ # in case several packages are constructed from a unique source
+ # (multipackaging), the source may be indicated as well.
+ # The source might contain a version if the generated package
+ # version is different from the source version
+ if(NOT CPACK_DEBIAN_PACKAGE_SOURCE)
+ set(CPACK_DEBIAN_PACKAGE_SOURCE "")
+ endif()
+
+ # have a look at get_property(result GLOBAL PROPERTY ENABLED_FEATURES),
+ # this returns the successful find_package() calls, maybe this can help
+ # Depends:
+ # You should set: DEBIAN_PACKAGE_DEPENDS
+ # TODO: automate 'objdump -p | grep NEEDED'
+
+ # if per-component variable, overrides the global CPACK_DEBIAN_PACKAGE_${variable_type_}
+ # automatic dependency discovery will be performed afterwards.
+ if(CPACK_DEB_PACKAGE_COMPONENT)
+ foreach(value_type_ IN ITEMS DEPENDS RECOMMENDS SUGGESTS PREDEPENDS ENHANCES BREAKS CONFLICTS PROVIDES REPLACES SOURCE SECTION PRIORITY NAME)
+ set(_component_var "CPACK_DEBIAN_${_local_component_name}_PACKAGE_${value_type_}")
+
+ # if set, overrides the global variable
+ if(DEFINED ${_component_var})
+ set(CPACK_DEBIAN_PACKAGE_${value_type_} "${${_component_var}}")
+ if(CPACK_DEBIAN_PACKAGE_DEBUG)
+ message("CPackDeb Debug: component '${_local_component_name}' ${value_type_} "
+ "value set to '${CPACK_DEBIAN_PACKAGE_${value_type_}}'")
+ endif()
+ endif()
+ endforeach()
+
+ if(CPACK_DEBIAN_ENABLE_COMPONENT_DEPENDS)
+ unset(COMPONENT_DEPENDS)
+ foreach(_PACK IN LISTS CPACK_COMPONENT_${_local_component_name}_DEPENDS)
+ get_component_package_name(_PACK_NAME "${_PACK}")
+ list(PREPEND COMPONENT_DEPENDS "${_PACK_NAME} (= ${CPACK_DEBIAN_PACKAGE_VERSION})")
+ endforeach()
+ list(JOIN COMPONENT_DEPENDS ", " COMPONENT_DEPENDS)
+ if(COMPONENT_DEPENDS)
+ list(PREPEND CPACK_DEBIAN_PACKAGE_DEPENDS ${COMPONENT_DEPENDS})
+ list(JOIN CPACK_DEBIAN_PACKAGE_DEPENDS ", " CPACK_DEBIAN_PACKAGE_DEPENDS)
+ endif()
+ endif()
+ endif()
+
+ # at this point, the CPACK_DEBIAN_PACKAGE_DEPENDS is properly set
+ # to the minimal dependency of the package
+ # Append automatically discovered dependencies .
+ if(CPACK_DEBIAN_PACKAGE_AUTO_DEPENDS)
+ list(APPEND CPACK_DEBIAN_PACKAGE_DEPENDS ${CPACK_DEBIAN_PACKAGE_AUTO_DEPENDS})
+ list(JOIN CPACK_DEBIAN_PACKAGE_DEPENDS ", " CPACK_DEBIAN_PACKAGE_DEPENDS)
+ endif()
+
+ if(NOT CPACK_DEBIAN_PACKAGE_DEPENDS)
+ message(STATUS "CPACK_DEBIAN_PACKAGE_DEPENDS not set, the package will have no dependencies.")
+ endif()
+
+ # Maintainer: (mandatory)
+ if(NOT CPACK_DEBIAN_PACKAGE_MAINTAINER)
+ if(NOT CPACK_PACKAGE_CONTACT)
+ message(FATAL_ERROR "CPackDeb: Debian package requires a maintainer for a package, set CPACK_PACKAGE_CONTACT or CPACK_DEBIAN_PACKAGE_MAINTAINER")
+ endif()
+ set(CPACK_DEBIAN_PACKAGE_MAINTAINER ${CPACK_PACKAGE_CONTACT})
+ endif()
+
+ # Description: (mandatory)
+ # Try package description first
+ if(CPACK_USED_DEFAULT_PACKAGE_DESCRIPTION_FILE)
+ set(_desc_fallback)
+ else()
+ set(_desc_fallback "CPACK_PACKAGE_DESCRIPTION")
+ endif()
+ if(CPACK_DEB_PACKAGE_COMPONENT)
+ cpack_deb_variable_fallback("CPACK_DEBIAN_PACKAGE_DESCRIPTION"
+ "CPACK_DEBIAN_${_local_component_name}_DESCRIPTION"
+ "CPACK_COMPONENT_${_local_component_name}_DESCRIPTION")
+ else()
+ cpack_deb_variable_fallback("CPACK_DEBIAN_PACKAGE_DESCRIPTION"
+ "CPACK_DEBIAN_PACKAGE_DESCRIPTION"
+ ${_desc_fallback})
+ endif()
+
+ # Still no description? ... and description file has set ...
+ if(NOT CPACK_DEBIAN_PACKAGE_DESCRIPTION
+ AND CPACK_PACKAGE_DESCRIPTION_FILE
+ AND NOT CPACK_PACKAGE_DESCRIPTION_FILE STREQUAL CPACK_DEFAULT_PACKAGE_DESCRIPTION_FILE)
+ # Read `CPACK_PACKAGE_DESCRIPTION_FILE` then...
+ file(READ ${CPACK_PACKAGE_DESCRIPTION_FILE} CPACK_DEBIAN_PACKAGE_DESCRIPTION)
+ endif()
+
+ # Still no description? #2
+ if(NOT CPACK_DEBIAN_PACKAGE_DESCRIPTION)
+ # Try to get `CPACK_PACKAGE_DESCRIPTION_SUMMARY` as the last hope
+ if(CPACK_PACKAGE_DESCRIPTION_SUMMARY)
+ set(CPACK_DEBIAN_PACKAGE_DESCRIPTION ${CPACK_PACKAGE_DESCRIPTION_SUMMARY})
+ else()
+ # Giving up! Report an error...
+ set(_description_failure_message
+ "CPackDeb: Debian package requires a summary for a package, set CPACK_PACKAGE_DESCRIPTION_SUMMARY or CPACK_DEBIAN_PACKAGE_DESCRIPTION")
+ if(CPACK_DEB_PACKAGE_COMPONENT)
+ string(APPEND _description_failure_message
+ " or CPACK_DEBIAN_${_local_component_name}_DESCRIPTION")
+ endif()
+ message(FATAL_ERROR _description_failure_message)
+ endif()
+
+ # Ok, description has set. According to the `Debian Policy Manual`_ the first
+ # line is a package summary. Try to get it as well...
+ # See also: https://www.debian.org/doc/debian-policy/ch-controlfields.html#description
+ elseif(CPACK_PACKAGE_DESCRIPTION_SUMMARY AND
+ NOT CPACK_PACKAGE_DESCRIPTION_SUMMARY STREQUAL CPACK_DEFAULT_PACKAGE_DESCRIPTION_SUMMARY)
+ # Merge summary w/ the detailed description
+ string(PREPEND CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}\n")
+ endif()
+ # assert(CPACK_DEBIAN_PACKAGE_DESCRIPTION)
+
+ # Make sure description is properly formatted
+ cpack_deb_format_package_description(
+ "${CPACK_DEBIAN_PACKAGE_DESCRIPTION}"
+ CPACK_DEBIAN_PACKAGE_DESCRIPTION
+ )
+
+ # Homepage: (optional)
+ if(NOT CPACK_DEBIAN_PACKAGE_HOMEPAGE AND CPACK_PACKAGE_HOMEPAGE_URL)
+ set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "${CPACK_PACKAGE_HOMEPAGE_URL}")
+ endif()
+
+ # Section: (recommended)
+ if(NOT CPACK_DEBIAN_PACKAGE_SECTION)
+ set(CPACK_DEBIAN_PACKAGE_SECTION "devel")
+ endif()
+
+ # Priority: (recommended)
+ if(NOT CPACK_DEBIAN_PACKAGE_PRIORITY)
+ set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
+ endif()
+
+ if(CPACK_DEBIAN_ARCHIVE_TYPE)
+ if(CPACK_DEBIAN_ARCHIVE_TYPE STREQUAL "paxr")
+ message(DEPRECATION "CPACK_DEBIAN_ARCHIVE_TYPE set to old and invalid "
+ "type 'paxr', mapping to 'gnutar'")
+ set(CPACK_DEBIAN_ARCHIVE_TYPE "gnutar")
+ elseif(NOT CPACK_DEBIAN_ARCHIVE_TYPE STREQUAL "gnutar")
+ message(FATAL_ERROR "CPACK_DEBIAN_ARCHIVE_TYPE set to unsupported"
+ "type ${CPACK_DEBIAN_ARCHIVE_TYPE}")
+ endif()
+ else()
+ set(CPACK_DEBIAN_ARCHIVE_TYPE "gnutar")
+ endif()
+
+ # Compression: (recommended)
+ if(NOT CPACK_DEBIAN_COMPRESSION_TYPE)
+ set(CPACK_DEBIAN_COMPRESSION_TYPE "gzip")
+ endif()
+
+ # Recommends:
+ # You should set: CPACK_DEBIAN_PACKAGE_RECOMMENDS
+
+ # Suggests:
+ # You should set: CPACK_DEBIAN_PACKAGE_SUGGESTS
+
+ # CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
+ # This variable allow advanced user to add custom script to the control.tar.gz (inside the .deb archive)
+ # Typical examples are:
+ # - conffiles
+ # - postinst
+ # - postrm
+ # - prerm
+ # Usage:
+ # set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
+ # "${CMAKE_CURRENT_SOURCE_DIR}/prerm;${CMAKE_CURRENT_SOURCE_DIR}/postrm")
+
+ # Are we packaging components ?
+ if(CPACK_DEB_PACKAGE_COMPONENT)
+ # override values with per component version if set
+ foreach(VAR_NAME_ IN ITEMS PACKAGE_CONTROL_EXTRA PACKAGE_CONTROL_STRICT_PERMISSION)
+ if(CPACK_DEBIAN_${_local_component_name}_${VAR_NAME_})
+ set(CPACK_DEBIAN_${VAR_NAME_} "${CPACK_DEBIAN_${_local_component_name}_${VAR_NAME_}}")
+ endif()
+ endforeach()
+ get_component_package_name(CPACK_DEBIAN_PACKAGE_NAME ${_local_component_name})
+ endif()
+
+ if(NOT CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY)
+ set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY "=")
+ endif()
+
+ unset(CPACK_DEBIAN_PACKAGE_SHLIBS_LIST)
+
+ if(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS)
+ if(READELF_EXECUTABLE)
+ foreach(_FILE IN LISTS CPACK_DEB_SHARED_OBJECT_FILES)
+ extract_so_info("${_FILE}" libname soversion)
+ if(libname AND DEFINED soversion)
+ list(APPEND CPACK_DEBIAN_PACKAGE_SHLIBS_LIST
+ "${libname} ${soversion} ${CPACK_DEBIAN_PACKAGE_NAME} (${CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY} ${CPACK_DEBIAN_PACKAGE_VERSION})")
+ else()
+ message(AUTHOR_WARNING "Shared library '${_FILE}' is missing soname or soversion. Library will not be added to DEBIAN/shlibs control file.")
+ endif()
+ endforeach()
+ list(JOIN CPACK_DEBIAN_PACKAGE_SHLIBS_LIST "\n" CPACK_DEBIAN_PACKAGE_SHLIBS_LIST)
+ else()
+ message(FATAL_ERROR "Readelf utility is not available. CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS option is not available.")
+ endif()
+ endif()
+
+ # add ldconfig call in default postrm and postint
+ set(CPACK_ADD_LDCONFIG_CALL 0)
+ foreach(_FILE IN LISTS CPACK_DEB_SHARED_OBJECT_FILES)
+ get_filename_component(_DIR ${_FILE} DIRECTORY)
+ # all files in CPACK_DEB_SHARED_OBJECT_FILES have dot at the beginning
+ if(_DIR STREQUAL "./lib" OR _DIR STREQUAL "./usr/lib")
+ set(CPACK_ADD_LDCONFIG_CALL 1)
+ endif()
+ endforeach()
+
+ if(CPACK_ADD_LDCONFIG_CALL)
+ set(CPACK_DEBIAN_GENERATE_POSTINST 1)
+ set(CPACK_DEBIAN_GENERATE_POSTRM 1)
+ foreach(f IN LISTS PACKAGE_CONTROL_EXTRA)
+ get_filename_component(n "${f}" NAME)
+ if(n STREQUAL "postinst")
+ set(CPACK_DEBIAN_GENERATE_POSTINST 0)
+ endif()
+ if(n STREQUAL "postrm")
+ set(CPACK_DEBIAN_GENERATE_POSTRM 0)
+ endif()
+ endforeach()
+ else()
+ set(CPACK_DEBIAN_GENERATE_POSTINST 0)
+ set(CPACK_DEBIAN_GENERATE_POSTRM 0)
+ endif()
+
+ cpack_deb_variable_fallback("CPACK_DEBIAN_FILE_NAME"
+ "CPACK_DEBIAN_${_local_component_name}_FILE_NAME"
+ "CPACK_DEBIAN_FILE_NAME")
+ if(CPACK_DEBIAN_FILE_NAME)
+ if(CPACK_DEBIAN_FILE_NAME STREQUAL "DEB-DEFAULT")
+ # Patch package file name to be in correct debian format:
+ # <foo>_<VersionNumber>-<DebianRevisionNumber>_<DebianArchitecture>.deb
+ set(CPACK_OUTPUT_FILE_NAME
+ "${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
+ set(CPACK_DBGSYM_OUTPUT_FILE_NAME
+ "${CPACK_DEBIAN_PACKAGE_NAME}-dbgsym_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.ddeb")
+ else()
+ if(NOT CPACK_DEBIAN_FILE_NAME MATCHES ".*\\.(deb|ipk)")
+ message(FATAL_ERROR "'${CPACK_DEBIAN_FILE_NAME}' is not a valid DEB package file name as it must end with '.deb' or '.ipk'!")
+ endif()
+
+ set(CPACK_OUTPUT_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}")
+ string(REGEX REPLACE "\.deb$" "-dbgsym.ddeb" CPACK_DBGSYM_OUTPUT_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}")
+ endif()
+
+ set(CPACK_TEMPORARY_PACKAGE_FILE_NAME "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_OUTPUT_FILE_NAME}")
+ get_filename_component(BINARY_DIR "${CPACK_OUTPUT_FILE_PATH}" DIRECTORY)
+ set(CPACK_OUTPUT_FILE_PATH "${BINARY_DIR}/${CPACK_OUTPUT_FILE_NAME}")
+ else()
+ # back compatibility - don't change the name
+ string(REGEX REPLACE "\.deb$" "-dbgsym.ddeb" CPACK_DBGSYM_OUTPUT_FILE_NAME "${CPACK_OUTPUT_FILE_NAME}")
+ endif()
+
+ # Print out some debug information if we were asked for that
+ if(CPACK_DEBIAN_PACKAGE_DEBUG)
+ message("CPackDeb:Debug: CPACK_TOPLEVEL_DIRECTORY = '${CPACK_TOPLEVEL_DIRECTORY}'")
+ message("CPackDeb:Debug: CPACK_TOPLEVEL_TAG = '${CPACK_TOPLEVEL_TAG}'")
+ message("CPackDeb:Debug: CPACK_TEMPORARY_DIRECTORY = '${CPACK_TEMPORARY_DIRECTORY}'")
+ message("CPackDeb:Debug: CPACK_OUTPUT_FILE_NAME = '${CPACK_OUTPUT_FILE_NAME}'")
+ message("CPackDeb:Debug: CPACK_OUTPUT_FILE_PATH = '${CPACK_OUTPUT_FILE_PATH}'")
+ message("CPackDeb:Debug: CPACK_PACKAGE_FILE_NAME = '${CPACK_PACKAGE_FILE_NAME}'")
+ message("CPackDeb:Debug: CPACK_PACKAGE_INSTALL_DIRECTORY = '${CPACK_PACKAGE_INSTALL_DIRECTORY}'")
+ message("CPackDeb:Debug: CPACK_TEMPORARY_PACKAGE_FILE_NAME = '${CPACK_TEMPORARY_PACKAGE_FILE_NAME}'")
+ message("CPackDeb:Debug: CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION = '${CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION}'")
+ message("CPackDeb:Debug: CPACK_DEBIAN_PACKAGE_SOURCE = '${CPACK_DEBIAN_PACKAGE_SOURCE}'")
+ endif()
+
+ # For debian source packages:
+ # debian/control
+ # http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-sourcecontrolfiles
+
+ # .dsc
+ # http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-debiansourcecontrolfiles
+
+ # Builds-Depends:
+ #if(NOT CPACK_DEBIAN_PACKAGE_BUILDS_DEPENDS)
+ # set(CPACK_DEBIAN_PACKAGE_BUILDS_DEPENDS
+ # "debhelper (>> 5.0.0), libncurses5-dev, tcl8.4"
+ # )
+ #endif()
+
+ # move variables to parent scope so that they may be used to create debian package
+ set(GEN_CPACK_OUTPUT_FILE_NAME "${CPACK_OUTPUT_FILE_NAME}" PARENT_SCOPE)
+ set(GEN_CPACK_TEMPORARY_PACKAGE_FILE_NAME "${CPACK_TEMPORARY_PACKAGE_FILE_NAME}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_NAME "${CPACK_DEBIAN_PACKAGE_NAME}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_DEBIAN_PACKAGE_VERSION}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_SECTION "${CPACK_DEBIAN_PACKAGE_SECTION}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_PRIORITY "${CPACK_DEBIAN_PACKAGE_PRIORITY}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE "${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_DEBIAN_PACKAGE_MAINTAINER}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_DEBIAN_PACKAGE_DESCRIPTION}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_ARCHIVE_TYPE "${CPACK_DEBIAN_ARCHIVE_TYPE}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_COMPRESSION_TYPE "${CPACK_DEBIAN_COMPRESSION_TYPE}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_RECOMMENDS "${CPACK_DEBIAN_PACKAGE_RECOMMENDS}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_SUGGESTS "${CPACK_DEBIAN_PACKAGE_SUGGESTS}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_HOMEPAGE "${CPACK_DEBIAN_PACKAGE_HOMEPAGE}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_PREDEPENDS "${CPACK_DEBIAN_PACKAGE_PREDEPENDS}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_ENHANCES "${CPACK_DEBIAN_PACKAGE_ENHANCES}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_BREAKS "${CPACK_DEBIAN_PACKAGE_BREAKS}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_CONFLICTS "${CPACK_DEBIAN_PACKAGE_CONFLICTS}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_PROVIDES "${CPACK_DEBIAN_PACKAGE_PROVIDES}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_REPLACES "${CPACK_DEBIAN_PACKAGE_REPLACES}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_SHLIBS "${CPACK_DEBIAN_PACKAGE_SHLIBS_LIST}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION
+ "${CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_PACKAGE_SOURCE
+ "${CPACK_DEBIAN_PACKAGE_SOURCE}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_GENERATE_POSTINST "${CPACK_DEBIAN_GENERATE_POSTINST}" PARENT_SCOPE)
+ set(GEN_CPACK_DEBIAN_GENERATE_POSTRM "${CPACK_DEBIAN_GENERATE_POSTRM}" PARENT_SCOPE)
+ set(GEN_WDIR "${WDIR}" PARENT_SCOPE)
+
+ set(GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE "${CPACK_DEBIAN_DEBUGINFO_PACKAGE}" PARENT_SCOPE)
+ if(BUILD_IDS)
+ set(GEN_DBGSYMDIR "${DBGSYMDIR}" PARENT_SCOPE)
+ set(GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME "${CPACK_DBGSYM_OUTPUT_FILE_NAME}" PARENT_SCOPE)
+ list(JOIN BUILD_IDS " " BUILD_IDS)
+ set(GEN_BUILD_IDS "${BUILD_IDS}" PARENT_SCOPE)
+ else()
+ unset(GEN_DBGSYMDIR PARENT_SCOPE)
+ unset(GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME PARENT_SCOPE)
+ unset(GEN_BUILD_IDS PARENT_SCOPE)
+ endif()
+endfunction()
+
+cpack_deb_prepare_package_vars()
+
+cmake_policy(POP)
diff --git a/Modules/Internal/CPack/CPackExternal.cmake b/Modules/Internal/CPack/CPackExternal.cmake
new file mode 100644
index 0000000..e4d055a
--- /dev/null
+++ b/Modules/Internal/CPack/CPackExternal.cmake
@@ -0,0 +1,53 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+if(NOT "${CPACK_EXTERNAL_REQUESTED_VERSIONS}" STREQUAL "")
+ unset(_found_major)
+
+ foreach(_req_version IN LISTS CPACK_EXTERNAL_REQUESTED_VERSIONS)
+ if(_req_version MATCHES "^([0-9]+)\\.([0-9]+)$")
+ set(_req_major "${CMAKE_MATCH_1}")
+ set(_req_minor "${CMAKE_MATCH_2}")
+
+ foreach(_known_version IN LISTS CPACK_EXTERNAL_KNOWN_VERSIONS)
+ string(REGEX MATCH
+ "^([0-9]+)\\.([0-9]+)$"
+ _known_version_dummy
+ "${_known_version}"
+ )
+
+ set(_known_major "${CMAKE_MATCH_1}")
+ set(_known_minor "${CMAKE_MATCH_2}")
+
+ if(_req_major EQUAL _known_major AND NOT _known_minor LESS _req_minor)
+ set(_found_major "${_known_major}")
+ set(_found_minor "${_known_minor}")
+ break()
+ endif()
+ endforeach()
+
+ if(DEFINED _found_major)
+ break()
+ endif()
+ endif()
+ endforeach()
+
+ if(DEFINED _found_major)
+ set(CPACK_EXTERNAL_SELECTED_MAJOR "${_found_major}")
+ set(CPACK_EXTERNAL_SELECTED_MINOR "${_found_minor}")
+ set(CPACK_EXTERNAL_SELECTED_VERSION "${_found_major}.${_found_minor}")
+ else()
+ message(FATAL_ERROR
+ "Could not find a suitable version in CPACK_EXTERNAL_REQUESTED_VERSIONS"
+ )
+ endif()
+else()
+ list(GET CPACK_EXTERNAL_KNOWN_VERSIONS 0 CPACK_EXTERNAL_SELECTED_VERSION)
+ string(REGEX MATCH
+ "^([0-9]+)\\.([0-9]+)$"
+ _dummy
+ "${CPACK_EXTERNAL_SELECTED_VERSION}"
+ )
+ set(CPACK_EXTERNAL_SELECTED_MAJOR "${CMAKE_MATCH_1}")
+ set(CPACK_EXTERNAL_SELECTED_MINOR "${CMAKE_MATCH_2}")
+endif()
diff --git a/Modules/Internal/CPack/CPackFreeBSD.cmake b/Modules/Internal/CPack/CPackFreeBSD.cmake
new file mode 100644
index 0000000..ae40532
--- /dev/null
+++ b/Modules/Internal/CPack/CPackFreeBSD.cmake
@@ -0,0 +1,107 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+if(CMAKE_BINARY_DIR)
+ message(FATAL_ERROR "CPackFreeBSD.cmake may only be used by CPack internally.")
+endif()
+
+if(NOT UNIX)
+ message(FATAL_ERROR "CPackFreeBSD.cmake may only be used under UNIX.")
+endif()
+
+
+###
+#
+# These bits are copied from the Debian packaging file; slightly modified.
+# They are used for filling in FreeBSD-packaging variables that can take
+# on values from elsewhere -- e.g. the package description may as well be
+# copied from Debian.
+#
+function(_cpack_freebsd_fallback_var OUTPUT_VAR_NAME)
+ set(FALLBACK_VAR_NAMES ${ARGN})
+
+ set(VALUE "${${OUTPUT_VAR_NAME}}")
+ if(VALUE)
+ return()
+ endif()
+
+ foreach(variable_name IN LISTS FALLBACK_VAR_NAMES)
+ if(${variable_name})
+ set(${OUTPUT_VAR_NAME} "${${variable_name}}" PARENT_SCOPE)
+ set(VALUE "${${variable_name}}")
+ break()
+ endif()
+ endforeach()
+ if(NOT VALUE)
+ message(WARNING "Variable ${OUTPUT_VAR_NAME} could not be given a fallback value from any variable ${FALLBACK_VAR_NAMES}.")
+ endif()
+endfunction()
+
+function(check_required_var VAR_NAME)
+ if(NOT ${VAR_NAME})
+ message(FATAL_ERROR "Variable ${VAR_NAME} is not set.")
+ endif()
+endfunction()
+
+set(_cpack_freebsd_fallback_origin "misc/bogus")
+
+_cpack_freebsd_fallback_var("CPACK_FREEBSD_PACKAGE_NAME"
+ "CPACK_PACKAGE_NAME"
+ "CMAKE_PROJECT_NAME"
+ )
+
+set(_cpack_freebsd_fallback_www "http://example.com/?pkg=${CPACK_FREEBSD_PACKAGE_NAME}")
+
+_cpack_freebsd_fallback_var("CPACK_FREEBSD_PACKAGE_COMMENT"
+ "CPACK_PACKAGE_DESCRIPTION_SUMMARY"
+ )
+
+# TODO: maybe read the PACKAGE_DESCRIPTION file for the longer
+# FreeBSD pkg-descr?
+_cpack_freebsd_fallback_var("CPACK_FREEBSD_PACKAGE_DESCRIPTION"
+ "CPACK_DEBIAN_PACKAGE_DESCRIPTION"
+ "CPACK_PACKAGE_DESCRIPTION_SUMMARY"
+ "PACKAGE_DESCRIPTION"
+ )
+
+# There's really only one homepage for a project, so
+# re-use the Debian setting if it's there.
+_cpack_freebsd_fallback_var("CPACK_FREEBSD_PACKAGE_WWW"
+ "CPACK_PACKAGE_HOMEPAGE_URL"
+ "CPACK_DEBIAN_PACKAGE_HOMEPAGE"
+ "_cpack_freebsd_fallback_www"
+ )
+
+_cpack_freebsd_fallback_var("CPACK_FREEBSD_PACKAGE_VERSION"
+ "CMAKE_PROJECT_VERSION"
+ "${CMAKE_PROJECT_NAME}_VERSION"
+ "PROJECT_VERSION"
+ "CPACK_PACKAGE_VERSION"
+ "CPACK_PACKAGE_VERSION"
+ )
+
+_cpack_freebsd_fallback_var("CPACK_FREEBSD_PACKAGE_MAINTAINER"
+ "CPACK_PACKAGE_CONTACT"
+ )
+
+_cpack_freebsd_fallback_var("CPACK_FREEBSD_PACKAGE_LICENSE"
+ "CPACK_RPM_PACKAGE_LICENSE"
+ )
+
+_cpack_freebsd_fallback_var("CPACK_FREEBSD_PACKAGE_ORIGIN"
+ "_cpack_freebsd_fallback_origin"
+ )
+
+if(NOT CPACK_FREEBSD_PACKAGE_CATEGORIES)
+ string(REGEX REPLACE "/.*" "" CPACK_FREEBSD_PACKAGE_CATEGORIES ${CPACK_FREEBSD_PACKAGE_ORIGIN})
+endif()
+
+check_required_var("CPACK_FREEBSD_PACKAGE_NAME")
+check_required_var("CPACK_FREEBSD_PACKAGE_ORIGIN")
+check_required_var("CPACK_FREEBSD_PACKAGE_VERSION")
+check_required_var("CPACK_FREEBSD_PACKAGE_MAINTAINER")
+check_required_var("CPACK_FREEBSD_PACKAGE_COMMENT")
+check_required_var("CPACK_FREEBSD_PACKAGE_DESCRIPTION")
+check_required_var("CPACK_FREEBSD_PACKAGE_WWW")
+check_required_var("CPACK_FREEBSD_PACKAGE_LICENSE")
diff --git a/Modules/Internal/CPack/CPackNuGet.cmake b/Modules/Internal/CPack/CPackNuGet.cmake
new file mode 100644
index 0000000..fb363f4
--- /dev/null
+++ b/Modules/Internal/CPack/CPackNuGet.cmake
@@ -0,0 +1,440 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# Author: Alex Turbov
+
+if(CMAKE_BINARY_DIR)
+ message(FATAL_ERROR "CPackNuGet.cmake may only be used by CPack internally.")
+endif()
+
+function(_cpack_nuget_debug)
+ if(CPACK_NUGET_PACKAGE_DEBUG)
+ message("CPackNuGet:Debug: " ${ARGN})
+ endif()
+endfunction()
+
+function(_cpack_nuget_debug_var NAME)
+ if(CPACK_NUGET_PACKAGE_DEBUG)
+ message("CPackNuGet:Debug: ${NAME}=`${${NAME}}`")
+ endif()
+endfunction()
+
+function(_cpack_nuget_variable_fallback OUTPUT_VAR_NAME NUGET_VAR_NAME)
+ if(ARGN)
+ list(JOIN ARGN "`, `" _va_args)
+ set(_va_args ", ARGN: `${_va_args}`")
+ endif()
+ _cpack_nuget_debug(
+ "_cpack_nuget_variable_fallback: "
+ "OUTPUT_VAR_NAME=`${OUTPUT_VAR_NAME}`, "
+ "NUGET_VAR_NAME=`${NUGET_VAR_NAME}`"
+ "${_va_args}"
+ )
+
+ set(_options USE_CDATA)
+ set(_one_value_args LIST_GLUE)
+ set(_multi_value_args FALLBACK_VARS)
+ cmake_parse_arguments(PARSE_ARGV 0 _args "${_options}" "${_one_value_args}" "${_multi_value_args}")
+
+ if(CPACK_NUGET_PACKAGE_COMPONENT)
+ string(
+ TOUPPER "${CPACK_NUGET_PACKAGE_COMPONENT}"
+ CPACK_NUGET_PACKAGE_COMPONENT_UPPER
+ )
+ endif()
+
+ if(CPACK_NUGET_PACKAGE_COMPONENT
+ AND CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}
+ )
+ set(
+ _result
+ "${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}}"
+ )
+ _cpack_nuget_debug(
+ " CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_PACKAGE_${NUGET_VAR_NAME}: "
+ "OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
+ )
+
+ elseif(CPACK_NUGET_PACKAGE_COMPONENT_UPPER
+ AND CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}
+ )
+ set(
+ _result
+ "${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}}"
+ )
+ _cpack_nuget_debug(
+ " CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_${NUGET_VAR_NAME}: "
+ "OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
+ )
+
+ elseif(CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME})
+ set(_result "${CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME}}")
+ _cpack_nuget_debug(
+ " CPACK_NUGET_PACKAGE_${NUGET_VAR_NAME}: "
+ "OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
+ )
+
+ else()
+ foreach(_var IN LISTS _args_FALLBACK_VARS)
+ _cpack_nuget_debug(" Fallback: ${_var} ...")
+ if(${_var})
+ _cpack_nuget_debug(" ${_var}=`${${_var}}`")
+ set(_result "${${_var}}")
+ _cpack_nuget_debug(
+ " ${_var}: OUTPUT_VAR_NAME->${OUTPUT_VAR_NAME}=`${_result}`"
+ )
+ break()
+ endif()
+ endforeach()
+ endif()
+
+ if(_result)
+ if(_args_USE_CDATA)
+ set(_value_before "<![CDATA[")
+ set(_value_after "]]>")
+ endif()
+
+ list(LENGTH _result _result_len)
+ if(_result_len GREATER 1 AND _args_LIST_GLUE)
+ list(JOIN _result "${_args_LIST_GLUE}" _result)
+ endif()
+
+ set(${OUTPUT_VAR_NAME} "${_value_before}${_result}${_value_after}" PARENT_SCOPE)
+ endif()
+
+endfunction()
+
+function(_cpack_nuget_variable_fallback_and_wrap_into_element ELEMENT NUGET_VAR_NAME)
+ set(_options)
+ set(_one_value_args)
+ set(_multi_value_args FALLBACK_VARS ATTRIBUTES)
+ cmake_parse_arguments(PARSE_ARGV 2 _args "${_options}" "${_one_value_args}" "${_multi_value_args}")
+
+ if(_args_ATTRIBUTES)
+ list(JOIN _args_ATTRIBUTES " " _attributes)
+ string(PREPEND _attributes " ")
+ endif()
+
+ _cpack_nuget_variable_fallback(_value ${NUGET_VAR_NAME} ${ARGN} USE_CDATA)
+
+ string(TOUPPER "${ELEMENT}" _ELEMENT_UP)
+ if(_value)
+ set(
+ _CPACK_NUGET_${_ELEMENT_UP}_TAG
+ "<${ELEMENT}${_attributes}>${_value}</${ELEMENT}>"
+ PARENT_SCOPE
+ )
+ elseif(_attributes)
+ set(
+ _CPACK_NUGET_${_ELEMENT_UP}_TAG
+ "<${ELEMENT}${_attributes} />"
+ PARENT_SCOPE
+ )
+ endif()
+endfunction()
+
+# Warn of obsolete nuspec fields, referencing CMake variables and suggested
+# replacement, if any
+function(_cpack_nuget_deprecation_warning NUGET_ELEMENT VARNAME REPLACEMENT)
+ if(${VARNAME})
+ if(REPLACEMENT)
+ message(DEPRECATION "nuspec element `${NUGET_ELEMENT}` is deprecated in NuGet; consider replacing `${VARNAME}` with `${REPLACEMENT}`")
+ else()
+ message(DEPRECATION "nuspec element `${NUGET_ELEMENT}` is deprecated in NuGet; consider removing `${VARNAME}`")
+ endif()
+ endif()
+endfunction()
+
+# Print some debug info
+_cpack_nuget_debug("---[CPack NuGet Input Variables]---")
+_cpack_nuget_debug_var(CPACK_PACKAGE_NAME)
+_cpack_nuget_debug_var(CPACK_PACKAGE_VERSION)
+_cpack_nuget_debug_var(CPACK_TOPLEVEL_TAG)
+_cpack_nuget_debug_var(CPACK_TOPLEVEL_DIRECTORY)
+_cpack_nuget_debug_var(CPACK_TEMPORARY_DIRECTORY)
+_cpack_nuget_debug_var(CPACK_NUGET_GROUPS)
+if(CPACK_NUGET_GROUPS)
+ foreach(_group IN LISTS CPACK_NUGET_GROUPS)
+ string(MAKE_C_IDENTIFIER "${_group}" _group_up)
+ string(TOUPPER "${_group_up}" _group_up)
+ _cpack_nuget_debug_var(CPACK_NUGET_${_group_up}_GROUP_COMPONENTS)
+ endforeach()
+endif()
+_cpack_nuget_debug_var(CPACK_NUGET_COMPONENTS)
+_cpack_nuget_debug_var(CPACK_NUGET_ALL_IN_ONE)
+_cpack_nuget_debug_var(CPACK_NUGET_ORDINAL_MONOLITIC)
+_cpack_nuget_debug("-----------------------------------")
+
+function(_cpack_nuget_render_spec)
+ # Make a variable w/ upper-cased component name
+ if(CPACK_NUGET_PACKAGE_COMPONENT)
+ string(TOUPPER "${CPACK_NUGET_PACKAGE_COMPONENT}" CPACK_NUGET_PACKAGE_COMPONENT_UPPER)
+ endif()
+
+ # Set mandatory variables (not wrapped into XML elements)
+ # https://docs.microsoft.com/en-us/nuget/reference/nuspec#required-metadata-elements
+ if(CPACK_NUGET_PACKAGE_COMPONENT)
+ if(CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_NAME)
+ set(
+ CPACK_NUGET_PACKAGE_NAME
+ "${CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_PACKAGE_NAME}"
+ )
+ elseif(NOT CPACK_NUGET_PACKAGE_COMPONENT STREQUAL "Unspecified")
+ set(
+ CPACK_NUGET_PACKAGE_NAME
+ "${CPACK_PACKAGE_NAME}.${CPACK_NUGET_PACKAGE_COMPONENT}"
+ )
+ else()
+ set(CPACK_NUGET_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")
+ endif()
+ elseif(NOT CPACK_NUGET_PACKAGE_NAME)
+ set(CPACK_NUGET_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")
+ endif()
+
+ # Warn about deprecated nuspec elements; warnings only display if
+ # variable is set
+ # Note that while nuspec's "summary" element is deprecated, there
+ # is no suggested replacement so (for now) no deprecation warning
+ # is shown for `CPACK_NUGET_*_DESCRIPTION_SUMMARY`
+ _cpack_nuget_deprecation_warning("licenseUrl" CPACK_NUGET_PACKAGE_LICENSEURL
+ "CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME or CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION")
+ _cpack_nuget_deprecation_warning("licenseUrl" CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSEURL
+ "CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSE_FILE_NAME or CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSE_EXPRESSION")
+ _cpack_nuget_deprecation_warning("iconUrl" CPACK_NUGET_PACKAGE_ICONURL
+ "CPACK_NUGET_PACKAGE_ICON")
+ _cpack_nuget_deprecation_warning("iconUrl" CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_ICONURL
+ "CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_ICON")
+
+ # Set nuspec fields
+ _cpack_nuget_variable_fallback(
+ CPACK_NUGET_PACKAGE_VERSION VERSION
+ FALLBACK_VARS
+ CPACK_PACKAGE_VERSION
+ )
+ _cpack_nuget_variable_fallback(
+ CPACK_NUGET_PACKAGE_DESCRIPTION DESCRIPTION
+ FALLBACK_VARS
+ CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT}_DESCRIPTION
+ CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DESCRIPTION
+ CPACK_COMPONENT_GROUP_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DESCRIPTION
+ CPACK_PACKAGE_DESCRIPTION
+ USE_CDATA
+ )
+ _cpack_nuget_variable_fallback(
+ CPACK_NUGET_PACKAGE_AUTHORS AUTHORS
+ FALLBACK_VARS
+ CPACK_PACKAGE_VENDOR
+ USE_CDATA
+ LIST_GLUE ","
+ )
+
+ # Set optional variables (wrapped into XML elements)
+ # https://docs.microsoft.com/en-us/nuget/reference/nuspec#optional-metadata-elements
+ _cpack_nuget_variable_fallback_and_wrap_into_element(
+ title
+ TITLE
+ FALLBACK_VARS
+ CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT}_DISPLAY_NAME
+ CPACK_COMPONENT_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DISPLAY_NAME
+ CPACK_COMPONENT_GROUP_${CPACK_NUGET_PACKAGE_COMPONENT_UPPER}_DISPLAY_NAME
+ )
+ _cpack_nuget_variable_fallback_and_wrap_into_element(owners OWNERS LIST_GLUE ",")
+ _cpack_nuget_variable_fallback_and_wrap_into_element(
+ projectUrl
+ HOMEPAGE_URL
+ FALLBACK_VARS
+ CPACK_PACKAGE_HOMEPAGE_URL
+ )
+
+ # "licenseUrl" is deprecated in favor of "license"
+ _cpack_nuget_variable_fallback_and_wrap_into_element(licenseUrl LICENSEURL)
+
+ # "iconUrl" is deprecated in favor of "icon"
+ _cpack_nuget_variable_fallback_and_wrap_into_element(iconUrl ICONURL)
+
+ # "license" takes a "type" attribute of either "file" or "expression"
+ # "file" refers to a file path of a .txt or .md file relative to the installation root
+ # "expression" refers to simple or compound expression of license identifiers
+ # listed at https://spdx.org/licenses/
+ # Note that only one of CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME and
+ # CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION may be specified. If both are specified,
+ # CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME takes precedence and CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION is ignored.
+ if(CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME)
+ _cpack_nuget_variable_fallback_and_wrap_into_element(
+ license LICENSE_FILE_NAME
+ ATTRIBUTES [[type="file"]]
+ )
+ elseif(CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION)
+ _cpack_nuget_variable_fallback_and_wrap_into_element(
+ license LICENSE_EXPRESSION
+ ATTRIBUTES [[type="expression"]]
+ )
+ endif()
+
+ # "icon" refers to a file path relative to the installation root
+ _cpack_nuget_variable_fallback_and_wrap_into_element(icon ICON)
+ # "summary" is deprecated in favor of "description"
+ _cpack_nuget_variable_fallback_and_wrap_into_element(
+ summary DESCRIPTION_SUMMARY
+ FALLBACK_VARS
+ CPACK_PACKAGE_DESCRIPTION_SUMMARY
+ )
+ if(CPACK_NUGET_PACKAGE_REQUIRE_LICENSE_ACCEPTANCE)
+ set(
+ _CPACK_NUGET_REQUIRELICENSEACCEPTANCE_TAG
+ "<requireLicenseAcceptance>true</requireLicenseAcceptance>"
+ )
+ endif()
+ _cpack_nuget_variable_fallback_and_wrap_into_element(releaseNotes RELEASE_NOTES)
+ _cpack_nuget_variable_fallback_and_wrap_into_element(copyright COPYRIGHT)
+ # "language" is a locale identifier such as "en_CA"
+ _cpack_nuget_variable_fallback_and_wrap_into_element(language LANGUAGE)
+ _cpack_nuget_variable_fallback_and_wrap_into_element(tags TAGS LIST_GLUE " ")
+ # "repository" holds repository metadata consisting of four optional
+ # attributes: "type", "url", "branch", and "commit". While all fields are
+ # considered optional, they are not independent. Currently unsupported.
+
+ # Handle dependencies
+ _cpack_nuget_variable_fallback(_deps DEPENDENCIES)
+ set(_collected_deps)
+ foreach(_dep IN LISTS _deps)
+ _cpack_nuget_debug(" checking dependency `${_dep}`")
+
+ _cpack_nuget_variable_fallback(_ver DEPENDENCIES_${_dep}_VERSION)
+
+ if(NOT _ver)
+ string(TOUPPER "${_dep}" _dep_upper)
+ _cpack_nuget_variable_fallback(_ver DEPENDENCIES_${_dep_upper}_VERSION)
+ endif()
+
+ if(_ver)
+ _cpack_nuget_debug(" got `${_dep}` dependency version ${_ver}")
+ string(CONCAT _collected_deps "${_collected_deps}" " <dependency id=\"${_dep}\" version=\"${_ver}\" />\n")
+ endif()
+ endforeach()
+
+ # Render deps into the variable
+ if(_collected_deps)
+ string(CONCAT _CPACK_NUGET_DEPENDENCIES_TAG "<dependencies>\n" "${_collected_deps}" " </dependencies>")
+ endif()
+
+ # Render the spec file
+ # NOTE The spec filename doesn't matter. Being included into a package,
+ # NuGet will name it properly.
+ _cpack_nuget_debug("Rendering `${CPACK_TEMPORARY_DIRECTORY}/CPack.NuGet.nuspec` file...")
+ configure_file(
+ "${CMAKE_ROOT}/Modules/Internal/CPack/CPack.NuGet.nuspec.in"
+ "${CPACK_TEMPORARY_DIRECTORY}/CPack.NuGet.nuspec"
+ @ONLY
+ )
+endfunction()
+
+function(_cpack_nuget_make_files_tag)
+ set(_files)
+ foreach(_comp IN LISTS ARGN)
+ string(APPEND _files " <file src=\"${_comp}/**\" target=\".\" />\n")
+ endforeach()
+ set(_CPACK_NUGET_FILES_TAG "<files>\n${_files} </files>" PARENT_SCOPE)
+endfunction()
+
+find_program(NUGET_EXECUTABLE nuget)
+_cpack_nuget_debug_var(NUGET_EXECUTABLE)
+if(NOT NUGET_EXECUTABLE)
+ message(FATAL_ERROR "NuGet executable not found")
+endif()
+
+# Add details for debug run
+if(CPACK_NUGET_PACKAGE_DEBUG)
+ list(APPEND CPACK_NUGET_PACK_ADDITIONAL_OPTIONS "-Verbosity" "detailed")
+endif()
+
+# Case one: ordinal all-in-one package
+if(CPACK_NUGET_ORDINAL_MONOLITIC)
+ # This variable `CPACK_NUGET_ALL_IN_ONE` set by C++ code:
+ # Meaning to pack all installed files into a single package
+ _cpack_nuget_debug("---[Making an ordinal monolitic package]---")
+ _cpack_nuget_render_spec()
+ execute_process(
+ COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ RESULT_VARIABLE _nuget_result
+ )
+ if(NOT _nuget_result EQUAL 0)
+ message(FATAL_ERROR "Nuget pack failed")
+ endif()
+
+elseif(CPACK_NUGET_ALL_IN_ONE)
+ # This variable `CPACK_NUGET_ALL_IN_ONE` set by C++ code:
+ # Meaning to pack all installed components into a single package
+ _cpack_nuget_debug("---[Making a monolitic package from installed components]---")
+
+ # Prepare the `files` element which include files from several components
+ _cpack_nuget_make_files_tag(${CPACK_NUGET_COMPONENTS})
+ _cpack_nuget_render_spec()
+ execute_process(
+ COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ RESULT_VARIABLE _nuget_result
+ )
+ if(NOT _nuget_result EQUAL 0)
+ message(FATAL_ERROR "Nuget pack failed")
+ endif()
+
+else()
+ # Is there any grouped component?
+ if(CPACK_NUGET_GROUPS)
+ _cpack_nuget_debug("---[Making grouped component(s) package(s)]---")
+ foreach(_group IN LISTS CPACK_NUGET_GROUPS)
+ _cpack_nuget_debug("Starting to make the package for group `${_group}`")
+ string(MAKE_C_IDENTIFIER "${_group}" _group_up)
+ string(TOUPPER "${_group_up}" _group_up)
+
+ # Render a spec file which includes all components in the current group
+ unset(_CPACK_NUGET_FILES_TAG)
+ _cpack_nuget_make_files_tag(${CPACK_NUGET_${_group_up}_GROUP_COMPONENTS})
+ # Temporary set `CPACK_NUGET_PACKAGE_COMPONENT` to the group name
+ # to properly collect various per group settings
+ set(CPACK_NUGET_PACKAGE_COMPONENT ${_group})
+ _cpack_nuget_render_spec()
+ unset(CPACK_NUGET_PACKAGE_COMPONENT)
+ execute_process(
+ COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ RESULT_VARIABLE _nuget_result
+ )
+ if(NOT _nuget_result EQUAL 0)
+ message(FATAL_ERROR "Nuget pack failed")
+ endif()
+ endforeach()
+ endif()
+ # Is there any single component package needed?
+ if(CPACK_NUGET_COMPONENTS)
+ _cpack_nuget_debug("---[Making single-component(s) package(s)]---")
+ foreach(_comp IN LISTS CPACK_NUGET_COMPONENTS)
+ _cpack_nuget_debug("Starting to make the package for component `${_comp}`")
+ # Render a spec file which includes only given component
+ unset(_CPACK_NUGET_FILES_TAG)
+ _cpack_nuget_make_files_tag(${_comp})
+ # Temporary set `CPACK_NUGET_PACKAGE_COMPONENT` to the current
+ # component name to properly collect various per group settings
+ set(CPACK_NUGET_PACKAGE_COMPONENT ${_comp})
+ _cpack_nuget_render_spec()
+ unset(CPACK_NUGET_PACKAGE_COMPONENT)
+ execute_process(
+ COMMAND "${NUGET_EXECUTABLE}" pack ${CPACK_NUGET_PACK_ADDITIONAL_OPTIONS}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ RESULT_VARIABLE _nuget_result
+ )
+ if(NOT _nuget_result EQUAL 0)
+ message(FATAL_ERROR "Nuget pack failed")
+ endif()
+ endforeach()
+ endif()
+endif()
+
+file(GLOB_RECURSE GEN_CPACK_OUTPUT_FILES "${CPACK_TEMPORARY_DIRECTORY}/*.nupkg")
+if(NOT GEN_CPACK_OUTPUT_FILES)
+ message(FATAL_ERROR "NuGet package was not generated at `${CPACK_TEMPORARY_DIRECTORY}`!")
+endif()
+
+_cpack_nuget_debug("Generated files: ${GEN_CPACK_OUTPUT_FILES}")
diff --git a/Modules/Internal/CPack/CPackRPM.cmake b/Modules/Internal/CPack/CPackRPM.cmake
new file mode 100644
index 0000000..bece2dd
--- /dev/null
+++ b/Modules/Internal/CPack/CPackRPM.cmake
@@ -0,0 +1,1945 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# Author: Eric Noulard with the help of Alexander Neundorf.
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+function(set_spec_script_if_enabled TYPE PACKAGE_NAME VAR)
+ if(NOT "${VAR}" STREQUAL "" AND NOT "${VAR}" STREQUAL "\n")
+ if(PACKAGE_NAME)
+ set(PACKAGE_NAME " -n ${PACKAGE_NAME}")
+ endif()
+ set(${TYPE}_
+ "%${TYPE}${PACKAGE_NAME}\n"
+ "${VAR}\n" PARENT_SCOPE)
+ else()
+ set(${TYPE} "" PARENT_SCOPE)
+ endif()
+endfunction()
+
+macro(set_spec_scripts PACKAGE_NAME)
+ # we should only set scripts that were provided
+ # as script announcement without content inside
+ # spec file will generate unneeded dependency
+ # on shell
+
+ set_spec_script_if_enabled(
+ "post"
+ "${PACKAGE_NAME}"
+ "${RPM_SYMLINK_POSTINSTALL}\n${CPACK_RPM_SPEC_POSTINSTALL}")
+
+ set_spec_script_if_enabled(
+ "posttrans"
+ "${PACKAGE_NAME}"
+ "${CPACK_RPM_SPEC_POSTTRANS}")
+
+ set_spec_script_if_enabled(
+ "postun"
+ "${PACKAGE_NAME}"
+ "${CPACK_RPM_SPEC_POSTUNINSTALL}")
+
+ set_spec_script_if_enabled(
+ "pre"
+ "${PACKAGE_NAME}"
+ "${CPACK_RPM_SPEC_PREINSTALL}")
+
+ set_spec_script_if_enabled(
+ "pretrans"
+ "${PACKAGE_NAME}"
+ "${CPACK_RPM_SPEC_PRETRANS}")
+
+ set_spec_script_if_enabled(
+ "preun"
+ "${PACKAGE_NAME}"
+ "${CPACK_RPM_SPEC_PREUNINSTALL}")
+endmacro()
+
+function(get_file_permissions FILE RETURN_VAR)
+ execute_process(COMMAND ls -l ${FILE}
+ OUTPUT_VARIABLE permissions_
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ string(REPLACE " " ";" permissions_ "${permissions_}")
+ list(GET permissions_ 0 permissions_)
+
+ unset(text_notation_)
+ set(any_chars_ ".")
+ foreach(PERMISSION_TYPE "OWNER" "GROUP" "WORLD")
+ if(permissions_ MATCHES "${any_chars_}r.*")
+ list(APPEND text_notation_ "${PERMISSION_TYPE}_READ")
+ endif()
+ string(APPEND any_chars_ ".")
+ if(permissions_ MATCHES "${any_chars_}w.*")
+ list(APPEND text_notation_ "${PERMISSION_TYPE}_WRITE")
+ endif()
+ string(APPEND any_chars_ ".")
+ if(permissions_ MATCHES "${any_chars_}x.*")
+ list(APPEND text_notation_ "${PERMISSION_TYPE}_EXECUTE")
+ endif()
+ endforeach()
+
+ set(${RETURN_VAR} "${text_notation_}" PARENT_SCOPE)
+endfunction()
+
+function(get_unix_permissions_octal_notation PERMISSIONS_VAR RETURN_VAR)
+ set(PERMISSIONS ${${PERMISSIONS_VAR}})
+ list(LENGTH PERMISSIONS PERM_LEN_PRE)
+ list(REMOVE_DUPLICATES PERMISSIONS)
+ list(LENGTH PERMISSIONS PERM_LEN_POST)
+
+ if(NOT ${PERM_LEN_PRE} EQUAL ${PERM_LEN_POST})
+ message(FATAL_ERROR "${PERMISSIONS_VAR} contains duplicate values.")
+ endif()
+
+ foreach(PERMISSION_TYPE "OWNER" "GROUP" "WORLD")
+ set(${PERMISSION_TYPE}_PERMISSIONS 0)
+
+ foreach(PERMISSION ${PERMISSIONS})
+ if("${PERMISSION}" STREQUAL "${PERMISSION_TYPE}_READ")
+ math(EXPR ${PERMISSION_TYPE}_PERMISSIONS "${${PERMISSION_TYPE}_PERMISSIONS} + 4")
+ elseif("${PERMISSION}" STREQUAL "${PERMISSION_TYPE}_WRITE")
+ math(EXPR ${PERMISSION_TYPE}_PERMISSIONS "${${PERMISSION_TYPE}_PERMISSIONS} + 2")
+ elseif("${PERMISSION}" STREQUAL "${PERMISSION_TYPE}_EXECUTE")
+ math(EXPR ${PERMISSION_TYPE}_PERMISSIONS "${${PERMISSION_TYPE}_PERMISSIONS} + 1")
+ elseif(PERMISSION MATCHES "${PERMISSION_TYPE}.*")
+ message(FATAL_ERROR "${PERMISSIONS_VAR} contains invalid values.")
+ endif()
+ endforeach()
+ endforeach()
+
+ set(${RETURN_VAR} "${OWNER_PERMISSIONS}${GROUP_PERMISSIONS}${WORLD_PERMISSIONS}" PARENT_SCOPE)
+endfunction()
+
+function(cpack_rpm_exact_regex regex_var string)
+ string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" regex "${string}")
+ set("${regex_var}" "${regex}" PARENT_SCOPE)
+endfunction()
+
+function(cpack_rpm_prepare_relocation_paths)
+ # set appropriate prefix, remove possible trailing slash and convert backslashes to slashes
+ if(CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_PREFIX)
+ file(TO_CMAKE_PATH "${CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_PREFIX}" PATH_PREFIX)
+ elseif(CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_PACKAGE_PREFIX)
+ file(TO_CMAKE_PATH "${CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_PACKAGE_PREFIX}" PATH_PREFIX)
+ else()
+ file(TO_CMAKE_PATH "${CPACK_PACKAGING_INSTALL_PREFIX}" PATH_PREFIX)
+ endif()
+
+ set(RPM_RELOCATION_PATHS "${CPACK_RPM_RELOCATION_PATHS}")
+ list(REMOVE_DUPLICATES RPM_RELOCATION_PATHS)
+
+ # set base path prefix
+ if(EXISTS "${WDIR}/${PATH_PREFIX}")
+ if(NOT CPACK_RPM_NO_INSTALL_PREFIX_RELOCATION AND
+ NOT CPACK_RPM_NO_${CPACK_RPM_PACKAGE_COMPONENT}_INSTALL_PREFIX_RELOCATION AND
+ NOT CPACK_RPM_NO_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_INSTALL_PREFIX_RELOCATION)
+ string(APPEND TMP_RPM_PREFIXES "Prefix: ${PATH_PREFIX}\n")
+ list(APPEND RPM_USED_PACKAGE_PREFIXES "${PATH_PREFIX}")
+
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: removing '${PATH_PREFIX}' from relocation paths")
+ endif()
+ endif()
+ endif()
+
+ # set other path prefixes
+ foreach(RELOCATION_PATH ${RPM_RELOCATION_PATHS})
+ if(IS_ABSOLUTE "${RELOCATION_PATH}")
+ set(PREPARED_RELOCATION_PATH "${RELOCATION_PATH}")
+ elseif(PATH_PREFIX STREQUAL "/")
+ # don't prefix path with a second slash as "//" is treated as network path
+ # by get_filename_component() so it remains in path even inside rpm
+ # package where it may cause problems with relocation
+ set(PREPARED_RELOCATION_PATH "/${RELOCATION_PATH}")
+ else()
+ set(PREPARED_RELOCATION_PATH "${PATH_PREFIX}/${RELOCATION_PATH}")
+ endif()
+
+ # handle cases where path contains extra slashes (e.g. /a//b/ instead of
+ # /a/b)
+ get_filename_component(PREPARED_RELOCATION_PATH
+ "${PREPARED_RELOCATION_PATH}" ABSOLUTE)
+
+ if(EXISTS "${WDIR}/${PREPARED_RELOCATION_PATH}")
+ string(APPEND TMP_RPM_PREFIXES "Prefix: ${PREPARED_RELOCATION_PATH}\n")
+ list(APPEND RPM_USED_PACKAGE_PREFIXES "${PREPARED_RELOCATION_PATH}")
+ endif()
+ endforeach()
+
+ # warn about all the paths that are not relocatable
+ file(GLOB_RECURSE FILE_PATHS_ "${WDIR}/*")
+ foreach(TMP_PATH ${FILE_PATHS_})
+ string(LENGTH "${WDIR}" WDIR_LEN)
+ string(SUBSTRING "${TMP_PATH}" ${WDIR_LEN} -1 TMP_PATH)
+ unset(TMP_PATH_FOUND_)
+
+ foreach(RELOCATION_PATH ${RPM_USED_PACKAGE_PREFIXES})
+ file(RELATIVE_PATH REL_PATH_ "${RELOCATION_PATH}" "${TMP_PATH}")
+ string(SUBSTRING "${REL_PATH_}" 0 2 PREFIX_)
+
+ if(NOT "${PREFIX_}" STREQUAL "..")
+ set(TPM_PATH_FOUND_ TRUE)
+ break()
+ endif()
+ endforeach()
+
+ if(NOT TPM_PATH_FOUND_)
+ message(AUTHOR_WARNING "CPackRPM:Warning: Path ${TMP_PATH} is not on one of the relocatable paths! Package will be partially relocatable.")
+ endif()
+ endforeach()
+
+ set(RPM_USED_PACKAGE_PREFIXES "${RPM_USED_PACKAGE_PREFIXES}" PARENT_SCOPE)
+ set(TMP_RPM_PREFIXES "${TMP_RPM_PREFIXES}" PARENT_SCOPE)
+endfunction()
+
+function(cpack_rpm_prepare_content_list)
+ # get files list
+ file(GLOB_RECURSE CPACK_RPM_INSTALL_FILES LIST_DIRECTORIES true RELATIVE "${WDIR}" "${WDIR}/*")
+ set(CPACK_RPM_INSTALL_FILES "/${CPACK_RPM_INSTALL_FILES}")
+ string(REPLACE ";" ";/" CPACK_RPM_INSTALL_FILES "${CPACK_RPM_INSTALL_FILES}")
+
+ # if we are creating a relocatable package, omit parent directories of
+ # CPACK_RPM_PACKAGE_PREFIX. This is achieved by building a "filter list"
+ # which is passed to the find command that generates the content-list
+ if(CPACK_RPM_PACKAGE_RELOCATABLE)
+ # get a list of the elements in CPACK_RPM_PACKAGE_PREFIXES that are
+ # destinct parent paths of other relocation paths and remove the
+ # final element (so the install-prefix dir itself is not omitted
+ # from the RPM's content-list)
+ list(SORT RPM_USED_PACKAGE_PREFIXES)
+ set(_DISTINCT_PATH "NOT_SET")
+ foreach(_RPM_RELOCATION_PREFIX ${RPM_USED_PACKAGE_PREFIXES})
+ if(NOT "${_RPM_RELOCATION_PREFIX}" MATCHES "${_DISTINCT_PATH}/.*")
+ set(_DISTINCT_PATH "${_RPM_RELOCATION_PREFIX}")
+
+ string(REPLACE "/" ";" _CPACK_RPM_PACKAGE_PREFIX_ELEMS " ${_RPM_RELOCATION_PREFIX}")
+ list(REMOVE_AT _CPACK_RPM_PACKAGE_PREFIX_ELEMS -1)
+ unset(_TMP_LIST)
+ # Now generate all of the parent dirs of the relocation path
+ foreach(_PREFIX_PATH_ELEM ${_CPACK_RPM_PACKAGE_PREFIX_ELEMS})
+ list(APPEND _TMP_LIST "${_PREFIX_PATH_ELEM}")
+ string(REPLACE ";" "/" _OMIT_DIR "${_TMP_LIST}")
+ separate_arguments(_OMIT_DIR)
+ list(APPEND _RPM_DIRS_TO_OMIT ${_OMIT_DIR})
+ endforeach()
+ endif()
+ endforeach()
+ endif()
+
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: Initial list of path to OMIT in RPM: ${_RPM_DIRS_TO_OMIT}")
+ endif()
+
+ if(NOT DEFINED CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST)
+ set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST /etc /etc/init.d /usr /usr/bin
+ /usr/include /usr/lib /usr/libx32 /usr/lib64
+ /usr/share /usr/share/aclocal /usr/share/doc )
+ if(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION)
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: Adding ${CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION} to builtin omit list.")
+ endif()
+ list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST "${CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION}")
+ endif()
+ endif()
+
+ if(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST)
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST= ${CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST}")
+ endif()
+ list(APPEND _RPM_DIRS_TO_OMIT ${CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST})
+ endif()
+
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: Final list of path to OMIT in RPM: ${_RPM_DIRS_TO_OMIT}")
+ endif()
+
+ list(REMOVE_ITEM CPACK_RPM_INSTALL_FILES ${_RPM_DIRS_TO_OMIT})
+
+ # add man paths that will be compressed
+ # (copied from /usr/lib/rpm/brp-compress - script that does the actual
+ # compressing)
+ list(APPEND MAN_LOCATIONS "/usr/man/man.*" "/usr/man/.*/man.*" "/usr/info.*"
+ "/usr/share/man/man.*" "/usr/share/man/.*/man.*" "/usr/share/info.*"
+ "/usr/kerberos/man.*" "/usr/X11R6/man/man.*" "/usr/lib/perl5/man/man.*"
+ "/usr/share/doc/.*/man/man.*" "/usr/lib/.*/man/man.*")
+
+ if(CPACK_RPM_ADDITIONAL_MAN_DIRS)
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: CPACK_RPM_ADDITIONAL_MAN_DIRS= ${CPACK_RPM_ADDITIONAL_MAN_DIRS}")
+ endif()
+ list(APPEND MAN_LOCATIONS ${CPACK_RPM_ADDITIONAL_MAN_DIRS})
+ endif()
+
+ foreach(PACK_LOCATION IN LISTS CPACK_RPM_INSTALL_FILES)
+ foreach(MAN_LOCATION IN LISTS MAN_LOCATIONS)
+ # man pages are files inside a certain location
+ if(PACK_LOCATION MATCHES "${MAN_LOCATION}/"
+ AND NOT IS_DIRECTORY "${WDIR}${PACK_LOCATION}"
+ AND NOT IS_SYMLINK "${WDIR}${PACK_LOCATION}")
+ list(FIND CPACK_RPM_INSTALL_FILES "${PACK_LOCATION}" INDEX)
+ # insert file location that covers compressed man pages
+ # even if using a wildcard causes duplicates as those are
+ # handled by RPM and we still keep the same file list
+ # in spec file - wildcard only represents file type (e.g. .gz)
+ list(INSERT CPACK_RPM_INSTALL_FILES ${INDEX} "${PACK_LOCATION}*")
+ # remove file location that doesn't cover compressed man pages
+ math(EXPR INDEX ${INDEX}+1)
+ list(REMOVE_AT CPACK_RPM_INSTALL_FILES ${INDEX})
+
+ break()
+ endif()
+ endforeach()
+ endforeach()
+
+ set(CPACK_RPM_INSTALL_FILES "${CPACK_RPM_INSTALL_FILES}" PARENT_SCOPE)
+endfunction()
+
+function(cpack_rpm_symlink_get_relocation_prefixes LOCATION PACKAGE_PREFIXES RETURN_VARIABLE)
+ foreach(PKG_PREFIX IN LISTS PACKAGE_PREFIXES)
+ string(REGEX MATCH "^${PKG_PREFIX}/.*" FOUND_ "${LOCATION}")
+ if(FOUND_)
+ list(APPEND TMP_PREFIXES "${PKG_PREFIX}")
+ endif()
+ endforeach()
+
+ set(${RETURN_VARIABLE} "${TMP_PREFIXES}" PARENT_SCOPE)
+endfunction()
+
+function(cpack_rpm_symlink_create_relocation_script PACKAGE_PREFIXES)
+ list(LENGTH PACKAGE_PREFIXES LAST_INDEX)
+ set(SORTED_PACKAGE_PREFIXES "${PACKAGE_PREFIXES}")
+ list(SORT SORTED_PACKAGE_PREFIXES)
+ list(REVERSE SORTED_PACKAGE_PREFIXES)
+ math(EXPR LAST_INDEX ${LAST_INDEX}-1)
+
+ foreach(SYMLINK_INDEX RANGE ${LAST_INDEX})
+ list(GET SORTED_PACKAGE_PREFIXES ${SYMLINK_INDEX} SRC_PATH)
+ list(FIND PACKAGE_PREFIXES "${SRC_PATH}" SYMLINK_INDEX) # reverse magic
+ string(LENGTH "${SRC_PATH}" SRC_PATH_LEN)
+
+ set(PARTS_CNT 0)
+ set(SCRIPT_PART "if [ \"$RPM_INSTALL_PREFIX${SYMLINK_INDEX}\" != \"${SRC_PATH}\" ]; then\n")
+
+ # both paths relocated
+ foreach(POINT_INDEX RANGE ${LAST_INDEX})
+ list(GET SORTED_PACKAGE_PREFIXES ${POINT_INDEX} POINT_PATH)
+ list(FIND PACKAGE_PREFIXES "${POINT_PATH}" POINT_INDEX) # reverse magic
+ string(LENGTH "${POINT_PATH}" POINT_PATH_LEN)
+
+ if(_RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_${POINT_INDEX})
+ if("${SYMLINK_INDEX}" EQUAL "${POINT_INDEX}")
+ set(INDENT "")
+ else()
+ string(APPEND SCRIPT_PART " if [ \"$RPM_INSTALL_PREFIX${POINT_INDEX}\" != \"${POINT_PATH}\" ]; then\n")
+ set(INDENT " ")
+ endif()
+
+ foreach(RELOCATION_NO IN LISTS _RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_${POINT_INDEX})
+ math(EXPR PARTS_CNT ${PARTS_CNT}+1)
+
+ math(EXPR RELOCATION_INDEX ${RELOCATION_NO}-1)
+ list(GET _RPM_RELOCATION_SCRIPT_PAIRS ${RELOCATION_INDEX} RELOCATION_SCRIPT_PAIR)
+ string(FIND "${RELOCATION_SCRIPT_PAIR}" ":" SPLIT_INDEX)
+
+ math(EXPR SRC_PATH_END ${SPLIT_INDEX}-${SRC_PATH_LEN})
+ string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${SRC_PATH_LEN} ${SRC_PATH_END} SYMLINK_)
+
+ math(EXPR POINT_PATH_START ${SPLIT_INDEX}+1+${POINT_PATH_LEN})
+ string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${POINT_PATH_START} -1 POINT_)
+
+ string(APPEND SCRIPT_PART " ${INDENT}if [ -z \"$CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}\" ]; then\n")
+ string(APPEND SCRIPT_PART " ${INDENT}ln -s \"$RPM_INSTALL_PREFIX${POINT_INDEX}${POINT_}\" \"$RPM_INSTALL_PREFIX${SYMLINK_INDEX}${SYMLINK_}\"\n")
+ string(APPEND SCRIPT_PART " ${INDENT}CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}=true\n")
+ string(APPEND SCRIPT_PART " ${INDENT}fi\n")
+ endforeach()
+
+ if(NOT "${SYMLINK_INDEX}" EQUAL "${POINT_INDEX}")
+ string(APPEND SCRIPT_PART " fi\n")
+ endif()
+ endif()
+ endforeach()
+
+ # source path relocated
+ if(_RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_X)
+ foreach(RELOCATION_NO IN LISTS _RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_X)
+ math(EXPR PARTS_CNT ${PARTS_CNT}+1)
+
+ math(EXPR RELOCATION_INDEX ${RELOCATION_NO}-1)
+ list(GET _RPM_RELOCATION_SCRIPT_PAIRS ${RELOCATION_INDEX} RELOCATION_SCRIPT_PAIR)
+ string(FIND "${RELOCATION_SCRIPT_PAIR}" ":" SPLIT_INDEX)
+
+ math(EXPR SRC_PATH_END ${SPLIT_INDEX}-${SRC_PATH_LEN})
+ string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${SRC_PATH_LEN} ${SRC_PATH_END} SYMLINK_)
+
+ math(EXPR POINT_PATH_START ${SPLIT_INDEX}+1)
+ string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${POINT_PATH_START} -1 POINT_)
+
+ string(APPEND SCRIPT_PART " if [ -z \"$CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}\" ]; then\n")
+ string(APPEND SCRIPT_PART " ln -s \"${POINT_}\" \"$RPM_INSTALL_PREFIX${SYMLINK_INDEX}${SYMLINK_}\"\n")
+ string(APPEND SCRIPT_PART " CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}=true\n")
+ string(APPEND SCRIPT_PART " fi\n")
+ endforeach()
+ endif()
+
+ if(PARTS_CNT)
+ set(SCRIPT "${SCRIPT_PART}")
+ string(APPEND SCRIPT "fi\n")
+ endif()
+ endforeach()
+
+ # point path relocated
+ foreach(POINT_INDEX RANGE ${LAST_INDEX})
+ list(GET SORTED_PACKAGE_PREFIXES ${POINT_INDEX} POINT_PATH)
+ list(FIND PACKAGE_PREFIXES "${POINT_PATH}" POINT_INDEX) # reverse magic
+ string(LENGTH "${POINT_PATH}" POINT_PATH_LEN)
+
+ if(_RPM_RELOCATION_SCRIPT_X_${POINT_INDEX})
+ string(APPEND SCRIPT "if [ \"$RPM_INSTALL_PREFIX${POINT_INDEX}\" != \"${POINT_PATH}\" ]; then\n")
+
+ foreach(RELOCATION_NO IN LISTS _RPM_RELOCATION_SCRIPT_X_${POINT_INDEX})
+ math(EXPR RELOCATION_INDEX ${RELOCATION_NO}-1)
+ list(GET _RPM_RELOCATION_SCRIPT_PAIRS ${RELOCATION_INDEX} RELOCATION_SCRIPT_PAIR)
+ string(FIND "${RELOCATION_SCRIPT_PAIR}" ":" SPLIT_INDEX)
+
+ string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} 0 ${SPLIT_INDEX} SYMLINK_)
+
+ math(EXPR POINT_PATH_START ${SPLIT_INDEX}+1+${POINT_PATH_LEN})
+ string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${POINT_PATH_START} -1 POINT_)
+
+ string(APPEND SCRIPT " if [ -z \"$CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}\" ]; then\n")
+ string(APPEND SCRIPT " ln -s \"$RPM_INSTALL_PREFIX${POINT_INDEX}${POINT_}\" \"${SYMLINK_}\"\n")
+ string(APPEND SCRIPT " CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}=true\n")
+ string(APPEND SCRIPT " fi\n")
+ endforeach()
+
+ string(APPEND SCRIPT "fi\n")
+ endif()
+ endforeach()
+
+ # no path relocated
+ if(_RPM_RELOCATION_SCRIPT_X_X)
+ foreach(RELOCATION_NO IN LISTS _RPM_RELOCATION_SCRIPT_X_X)
+ math(EXPR RELOCATION_INDEX ${RELOCATION_NO}-1)
+ list(GET _RPM_RELOCATION_SCRIPT_PAIRS ${RELOCATION_INDEX} RELOCATION_SCRIPT_PAIR)
+ string(FIND "${RELOCATION_SCRIPT_PAIR}" ":" SPLIT_INDEX)
+
+ string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} 0 ${SPLIT_INDEX} SYMLINK_)
+
+ math(EXPR POINT_PATH_START ${SPLIT_INDEX}+1)
+ string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${POINT_PATH_START} -1 POINT_)
+
+ string(APPEND SCRIPT "if [ -z \"$CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}\" ]; then\n")
+ string(APPEND SCRIPT " ln -s \"${POINT_}\" \"${SYMLINK_}\"\n")
+ string(APPEND SCRIPT "fi\n")
+ endforeach()
+ endif()
+
+ set(RPM_SYMLINK_POSTINSTALL "${SCRIPT}" PARENT_SCOPE)
+endfunction()
+
+function(cpack_rpm_symlink_add_for_relocation_script PACKAGE_PREFIXES SYMLINK SYMLINK_RELOCATION_PATHS POINT POINT_RELOCATION_PATHS)
+ list(LENGTH SYMLINK_RELOCATION_PATHS SYMLINK_PATHS_COUTN)
+ list(LENGTH POINT_RELOCATION_PATHS POINT_PATHS_COUNT)
+
+ list(APPEND _RPM_RELOCATION_SCRIPT_PAIRS "${SYMLINK}:${POINT}")
+ list(LENGTH _RPM_RELOCATION_SCRIPT_PAIRS PAIR_NO)
+
+ if(SYMLINK_PATHS_COUTN)
+ foreach(SYMLINK_RELOC_PATH IN LISTS SYMLINK_RELOCATION_PATHS)
+ list(FIND PACKAGE_PREFIXES "${SYMLINK_RELOC_PATH}" SYMLINK_INDEX)
+
+ # source path relocated
+ list(APPEND _RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_X "${PAIR_NO}")
+ list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_X")
+
+ foreach(POINT_RELOC_PATH IN LISTS POINT_RELOCATION_PATHS)
+ list(FIND PACKAGE_PREFIXES "${POINT_RELOC_PATH}" POINT_INDEX)
+
+ # both paths relocated
+ list(APPEND _RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_${POINT_INDEX} "${PAIR_NO}")
+ list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_${POINT_INDEX}")
+
+ # point path relocated
+ list(APPEND _RPM_RELOCATION_SCRIPT_X_${POINT_INDEX} "${PAIR_NO}")
+ list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_X_${POINT_INDEX}")
+ endforeach()
+ endforeach()
+ elseif(POINT_PATHS_COUNT)
+ foreach(POINT_RELOC_PATH IN LISTS POINT_RELOCATION_PATHS)
+ list(FIND PACKAGE_PREFIXES "${POINT_RELOC_PATH}" POINT_INDEX)
+
+ # point path relocated
+ list(APPEND _RPM_RELOCATION_SCRIPT_X_${POINT_INDEX} "${PAIR_NO}")
+ list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_X_${POINT_INDEX}")
+ endforeach()
+ endif()
+
+ # no path relocated
+ list(APPEND _RPM_RELOCATION_SCRIPT_X_X "${PAIR_NO}")
+ list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_X_X")
+
+ # place variables into parent scope
+ foreach(VAR IN LISTS RELOCATION_VARS)
+ set(${VAR} "${${VAR}}" PARENT_SCOPE)
+ endforeach()
+ set(_RPM_RELOCATION_SCRIPT_PAIRS "${_RPM_RELOCATION_SCRIPT_PAIRS}" PARENT_SCOPE)
+ set(REQUIRES_SYMLINK_RELOCATION_SCRIPT "true" PARENT_SCOPE)
+ set(DIRECTIVE "%ghost " PARENT_SCOPE)
+endfunction()
+
+function(cpack_rpm_prepare_install_files INSTALL_FILES_LIST WDIR PACKAGE_PREFIXES IS_RELOCATABLE)
+ # Prepend directories in ${CPACK_RPM_INSTALL_FILES} with %dir
+ # This is necessary to avoid duplicate files since rpmbuild does
+ # recursion on its own when encountering a pathname which is a directory
+ # which is not flagged as %dir
+ string(STRIP "${INSTALL_FILES_LIST}" INSTALL_FILES_LIST)
+ string(REPLACE "\n" ";" INSTALL_FILES_LIST
+ "${INSTALL_FILES_LIST}")
+ string(REPLACE "\"" "" INSTALL_FILES_LIST
+ "${INSTALL_FILES_LIST}")
+ string(LENGTH "${WDIR}" WDR_LEN_)
+
+ list(SORT INSTALL_FILES_LIST) # make file order consistent on all platforms
+
+ foreach(F IN LISTS INSTALL_FILES_LIST)
+ unset(DIRECTIVE)
+
+ if(IS_SYMLINK "${WDIR}/${F}")
+ if(IS_RELOCATABLE)
+ # check that symlink has relocatable format
+ get_filename_component(SYMLINK_LOCATION_ "${WDIR}/${F}" DIRECTORY)
+ execute_process(COMMAND ls -la "${WDIR}/${F}"
+ WORKING_DIRECTORY "${WDIR}"
+ OUTPUT_VARIABLE SYMLINK_POINT_
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ string(FIND "${SYMLINK_POINT_}" "->" SYMLINK_POINT_INDEX_ REVERSE)
+ math(EXPR SYMLINK_POINT_INDEX_ ${SYMLINK_POINT_INDEX_}+3)
+ string(LENGTH "${SYMLINK_POINT_}" SYMLINK_POINT_LENGTH_)
+
+ # get destination path
+ string(SUBSTRING "${SYMLINK_POINT_}" ${SYMLINK_POINT_INDEX_} ${SYMLINK_POINT_LENGTH_} SYMLINK_POINT_)
+
+ # check if path is relative or absolute
+ string(SUBSTRING "${SYMLINK_POINT_}" 0 1 SYMLINK_IS_ABSOLUTE_)
+
+ if(${SYMLINK_IS_ABSOLUTE_} STREQUAL "/")
+ # prevent absolute paths from having /../ or /./ section inside of them
+ get_filename_component(SYMLINK_POINT_ "${SYMLINK_POINT_}" ABSOLUTE)
+ else()
+ # handle relative path
+ get_filename_component(SYMLINK_POINT_ "${SYMLINK_LOCATION_}/${SYMLINK_POINT_}" ABSOLUTE)
+ endif()
+
+ # recalculate path length after conversion to canonical form
+ string(LENGTH "${SYMLINK_POINT_}" SYMLINK_POINT_LENGTH_)
+
+ cpack_rpm_exact_regex(IN_SYMLINK_POINT_REGEX "${WDIR}")
+ string(APPEND IN_SYMLINK_POINT_REGEX "/.*")
+ if(SYMLINK_POINT_ MATCHES "${IN_SYMLINK_POINT_REGEX}")
+ # only symlinks that are pointing inside the packaging structure should be checked for relocation
+ string(SUBSTRING "${SYMLINK_POINT_}" ${WDR_LEN_} -1 SYMLINK_POINT_WD_)
+ cpack_rpm_symlink_get_relocation_prefixes("${F}" "${PACKAGE_PREFIXES}" "SYMLINK_RELOCATIONS")
+ cpack_rpm_symlink_get_relocation_prefixes("${SYMLINK_POINT_WD_}" "${PACKAGE_PREFIXES}" "POINT_RELOCATIONS")
+
+ list(LENGTH SYMLINK_RELOCATIONS SYMLINK_RELOCATIONS_COUNT)
+ list(LENGTH POINT_RELOCATIONS POINT_RELOCATIONS_COUNT)
+ else()
+ # location pointed to is outside WDR so it should be treated as a permanent symlink
+ set(SYMLINK_POINT_WD_ "${SYMLINK_POINT_}")
+
+ unset(SYMLINK_RELOCATIONS)
+ unset(POINT_RELOCATIONS)
+ unset(SYMLINK_RELOCATIONS_COUNT)
+ unset(POINT_RELOCATIONS_COUNT)
+
+ message(AUTHOR_WARNING "CPackRPM:Warning: Symbolic link '${F}' points to location that is outside packaging path! Link will possibly not be relocatable.")
+ endif()
+
+ if(SYMLINK_RELOCATIONS_COUNT AND POINT_RELOCATIONS_COUNT)
+ # find matching
+ foreach(SYMLINK_RELOCATION_PREFIX IN LISTS SYMLINK_RELOCATIONS)
+ list(FIND POINT_RELOCATIONS "${SYMLINK_RELOCATION_PREFIX}" FOUND_INDEX)
+ if(NOT ${FOUND_INDEX} EQUAL -1)
+ break()
+ endif()
+ endforeach()
+
+ if(NOT ${FOUND_INDEX} EQUAL -1)
+ # symlinks have the same subpath
+ if(${SYMLINK_RELOCATIONS_COUNT} EQUAL 1 AND ${POINT_RELOCATIONS_COUNT} EQUAL 1)
+ # permanent symlink
+ get_filename_component(SYMLINK_LOCATION_ "${F}" DIRECTORY)
+ file(RELATIVE_PATH FINAL_PATH_ ${SYMLINK_LOCATION_} ${SYMLINK_POINT_WD_})
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "${FINAL_PATH_}" "${WDIR}/${F}")
+ else()
+ # relocation subpaths
+ cpack_rpm_symlink_add_for_relocation_script("${PACKAGE_PREFIXES}" "${F}" "${SYMLINK_RELOCATIONS}"
+ "${SYMLINK_POINT_WD_}" "${POINT_RELOCATIONS}")
+ endif()
+ else()
+ # not on the same relocation path
+ cpack_rpm_symlink_add_for_relocation_script("${PACKAGE_PREFIXES}" "${F}" "${SYMLINK_RELOCATIONS}"
+ "${SYMLINK_POINT_WD_}" "${POINT_RELOCATIONS}")
+ endif()
+ elseif(POINT_RELOCATIONS_COUNT)
+ # point is relocatable
+ cpack_rpm_symlink_add_for_relocation_script("${PACKAGE_PREFIXES}" "${F}" "${SYMLINK_RELOCATIONS}"
+ "${SYMLINK_POINT_WD_}" "${POINT_RELOCATIONS}")
+ else()
+ # is not relocatable or points to non relocatable path - permanent symlink
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "${SYMLINK_POINT_WD_}" "${WDIR}/${F}")
+ endif()
+ endif()
+ elseif(IS_DIRECTORY "${WDIR}/${F}")
+ set(DIRECTIVE "%dir ")
+ endif()
+
+ string(APPEND INSTALL_FILES "${DIRECTIVE}\"${F}\"\n")
+ endforeach()
+
+ if(REQUIRES_SYMLINK_RELOCATION_SCRIPT)
+ cpack_rpm_symlink_create_relocation_script("${PACKAGE_PREFIXES}")
+ endif()
+
+ set(RPM_SYMLINK_POSTINSTALL "${RPM_SYMLINK_POSTINSTALL}" PARENT_SCOPE)
+ set(CPACK_RPM_INSTALL_FILES "${INSTALL_FILES}" PARENT_SCOPE)
+endfunction()
+
+if(CMAKE_BINARY_DIR)
+ message(FATAL_ERROR "CPackRPM.cmake may only be used by CPack internally.")
+endif()
+
+if(NOT UNIX)
+ message(FATAL_ERROR "CPackRPM.cmake may only be used under UNIX.")
+endif()
+
+# We need to check if the binaries were compiled with debug symbols
+# because without them the package will be useless
+function(cpack_rpm_debugsymbol_check INSTALL_FILES WORKING_DIR)
+ if(NOT CPACK_BUILD_SOURCE_DIRS)
+ message(FATAL_ERROR "CPackRPM: CPACK_BUILD_SOURCE_DIRS variable is not set!"
+ " Required for debuginfo packaging. See documentation of"
+ " CPACK_RPM_DEBUGINFO_PACKAGE variable for details.")
+ endif()
+
+ # With objdump we should check the debug symbols
+ find_program(OBJDUMP_EXECUTABLE objdump)
+ if(NOT OBJDUMP_EXECUTABLE)
+ message(FATAL_ERROR "CPackRPM: objdump binary could not be found!"
+ " Required for debuginfo packaging. See documentation of"
+ " CPACK_RPM_DEBUGINFO_PACKAGE variable for details.")
+ endif()
+
+ # With debugedit we prepare source files list
+ find_program(DEBUGEDIT_EXECUTABLE debugedit "/usr/lib/rpm/")
+ if(NOT DEBUGEDIT_EXECUTABLE)
+ message(FATAL_ERROR "CPackRPM: debugedit binary could not be found!"
+ " Required for debuginfo packaging. See documentation of"
+ " CPACK_RPM_DEBUGINFO_PACKAGE variable for details.")
+ endif()
+
+ unset(mkdir_list_)
+ unset(cp_list_)
+ unset(additional_sources_)
+
+ foreach(F IN LISTS INSTALL_FILES)
+ if(IS_DIRECTORY "${WORKING_DIR}/${F}" OR IS_SYMLINK "${WORKING_DIR}/${F}")
+ continue()
+ endif()
+
+ execute_process(COMMAND "${OBJDUMP_EXECUTABLE}" -h ${WORKING_DIR}/${F}
+ WORKING_DIRECTORY "${CPACK_TOPLEVEL_DIRECTORY}"
+ RESULT_VARIABLE OBJDUMP_EXEC_RESULT
+ OUTPUT_VARIABLE OBJDUMP_OUT
+ ERROR_QUIET)
+ # Check if the given file is an executable or not
+ if(NOT OBJDUMP_EXEC_RESULT)
+ string(FIND "${OBJDUMP_OUT}" "debug" FIND_RESULT)
+ if(FIND_RESULT GREATER -1)
+ set(index_ 0)
+ foreach(source_dir_ IN LISTS CPACK_BUILD_SOURCE_DIRS)
+ string(LENGTH "${source_dir_}" source_dir_len_)
+ string(LENGTH "${CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX}/src_${index_}" debuginfo_dir_len)
+ if(source_dir_len_ LESS debuginfo_dir_len)
+ message(FATAL_ERROR "CPackRPM: source dir path '${source_dir_}' is"
+ " shorter than debuginfo sources dir path '${CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX}/src_${index_}'!"
+ " Source dir path must be longer than debuginfo sources dir path."
+ " Set CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX variable to a shorter value"
+ " or make source dir path longer."
+ " Required for debuginfo packaging. See documentation of"
+ " CPACK_RPM_DEBUGINFO_PACKAGE variable for details.")
+ endif()
+
+ file(REMOVE "${CPACK_RPM_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_PATH}/debugsources_add.list")
+ execute_process(COMMAND "${DEBUGEDIT_EXECUTABLE}" -b "${source_dir_}" -d "${CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX}/src_${index_}" -i -l "${CPACK_RPM_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_PATH}/debugsources_add.list" "${WORKING_DIR}/${F}"
+ RESULT_VARIABLE res_
+ OUTPUT_VARIABLE opt_
+ ERROR_VARIABLE err_
+ )
+
+ file(STRINGS
+ "${CPACK_RPM_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_PATH}/debugsources_add.list"
+ sources_)
+ list(REMOVE_DUPLICATES sources_)
+
+ foreach(source_ IN LISTS sources_)
+ if(EXISTS "${source_dir_}/${source_}" AND NOT IS_DIRECTORY "${source_dir_}/${source_}")
+ get_filename_component(path_part_ "${source_}" DIRECTORY)
+ list(APPEND mkdir_list_ "%{buildroot}${CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX}/src_${index_}/${path_part_}")
+ list(APPEND cp_list_ "cp \"${source_dir_}/${source_}\" \"%{buildroot}${CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX}/src_${index_}/${path_part_}\"")
+
+ list(APPEND additional_sources_ "${CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX}/src_${index_}/${source_}")
+ endif()
+ endforeach()
+
+ math(EXPR index_ "${index_} + 1")
+ endforeach()
+ else()
+ message(WARNING "CPackRPM: File: ${F} does not contain debug symbols. They will possibly be missing from debuginfo package!")
+ endif()
+
+ get_file_permissions("${WORKING_DIR}/${F}" permissions_)
+ if(NOT "USER_EXECUTE" IN_LIST permissions_ AND
+ NOT "GROUP_EXECUTE" IN_LIST permissions_ AND
+ NOT "WORLD_EXECUTE" IN_LIST permissions_)
+ if(CPACK_RPM_INSTALL_WITH_EXEC)
+ execute_process(COMMAND chmod a+x ${WORKING_DIR}/${F}
+ RESULT_VARIABLE res_
+ ERROR_VARIABLE err_
+ OUTPUT_QUIET)
+
+ if(res_)
+ message(FATAL_ERROR "CPackRPM: could not apply execute permissions "
+ "requested by CPACK_RPM_INSTALL_WITH_EXEC variable on "
+ "'${WORKING_DIR}/${F}'! Reason: '${err_}'")
+ endif()
+ else()
+ message(AUTHOR_WARNING "CPackRPM: File: ${WORKING_DIR}/${F} does not "
+ "have execute permissions. Debuginfo symbols will not be extracted"
+ "! Missing debuginfo may cause packaging failure. Consider setting "
+ "execute permissions or setting 'CPACK_RPM_INSTALL_WITH_EXEC' "
+ "variable.")
+ endif()
+ endif()
+ endif()
+ endforeach()
+
+ list(LENGTH mkdir_list_ len_)
+ if(len_)
+ list(REMOVE_DUPLICATES mkdir_list_)
+ unset(TMP_RPM_DEBUGINFO_INSTALL)
+ foreach(part_ IN LISTS mkdir_list_)
+ string(APPEND TMP_RPM_DEBUGINFO_INSTALL "mkdir -p \"${part_}\"\n")
+ endforeach()
+ endif()
+
+ list(LENGTH cp_list_ len_)
+ if(len_)
+ list(REMOVE_DUPLICATES cp_list_)
+ foreach(part_ IN LISTS cp_list_)
+ string(APPEND TMP_RPM_DEBUGINFO_INSTALL "${part_}\n")
+ endforeach()
+ endif()
+
+ if(NOT DEFINED CPACK_RPM_DEBUGINFO_EXCLUDE_DIRS)
+ set(CPACK_RPM_DEBUGINFO_EXCLUDE_DIRS /usr /usr/src /usr/src/debug)
+ if(CPACK_RPM_DEBUGINFO_EXCLUDE_DIRS_ADDITION)
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: Adding ${CPACK_RPM_DEBUGINFO_EXCLUDE_DIRS_ADDITION} to builtin omit list.")
+ endif()
+ list(APPEND CPACK_RPM_DEBUGINFO_EXCLUDE_DIRS "${CPACK_RPM_DEBUGINFO_EXCLUDE_DIRS_ADDITION}")
+ endif()
+ endif()
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: CPACK_RPM_DEBUGINFO_EXCLUDE_DIRS= ${CPACK_RPM_DEBUGINFO_EXCLUDE_DIRS}")
+ endif()
+
+ list(LENGTH additional_sources_ len_)
+ if(len_)
+ list(REMOVE_DUPLICATES additional_sources_)
+ unset(additional_sources_all_)
+ foreach(source_ IN LISTS additional_sources_)
+ string(REPLACE "/" ";" split_source_ " ${source_}")
+ list(REMOVE_AT split_source_ 0)
+ unset(tmp_path_)
+ # Now generate all segments of the path
+ foreach(segment_ IN LISTS split_source_)
+ string(APPEND tmp_path_ "/${segment_}")
+ list(APPEND additional_sources_all_ "${tmp_path_}")
+ endforeach()
+ endforeach()
+
+ list(REMOVE_DUPLICATES additional_sources_all_)
+ list(REMOVE_ITEM additional_sources_all_
+ ${CPACK_RPM_DEBUGINFO_EXCLUDE_DIRS})
+
+ unset(TMP_DEBUGINFO_ADDITIONAL_SOURCES)
+ foreach(source_ IN LISTS additional_sources_all_)
+ string(APPEND TMP_DEBUGINFO_ADDITIONAL_SOURCES "${source_}\n")
+ endforeach()
+ endif()
+
+ set(TMP_RPM_DEBUGINFO_INSTALL "${TMP_RPM_DEBUGINFO_INSTALL}" PARENT_SCOPE)
+ set(TMP_DEBUGINFO_ADDITIONAL_SOURCES "${TMP_DEBUGINFO_ADDITIONAL_SOURCES}"
+ PARENT_SCOPE)
+endfunction()
+
+function(cpack_rpm_variable_fallback OUTPUT_VAR_NAME)
+ set(FALLBACK_VAR_NAMES ${ARGN})
+
+ foreach(variable_name IN LISTS FALLBACK_VAR_NAMES)
+ if(${variable_name})
+ set(${OUTPUT_VAR_NAME} "${${variable_name}}" PARENT_SCOPE)
+ break()
+ endif()
+ endforeach()
+endfunction()
+
+function(cpack_rpm_generate_package)
+ # rpmbuild is the basic command for building RPM package
+ # it may be a simple (symbolic) link to rpm command.
+ find_program(RPMBUILD_EXECUTABLE rpmbuild)
+
+ # Check version of the rpmbuild tool this would be easier to
+ # track bugs with users and CPackRPM debug mode.
+ # We may use RPM version in order to check for available version dependent features
+ if(RPMBUILD_EXECUTABLE)
+ execute_process(COMMAND ${RPMBUILD_EXECUTABLE} --version
+ OUTPUT_VARIABLE _TMP_VERSION
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ string(REGEX REPLACE "^.* " ""
+ RPMBUILD_EXECUTABLE_VERSION
+ ${_TMP_VERSION})
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: rpmbuild version is <${RPMBUILD_EXECUTABLE_VERSION}>")
+ endif()
+ endif()
+
+ if(NOT RPMBUILD_EXECUTABLE)
+ message(FATAL_ERROR "RPM package requires rpmbuild executable")
+ endif()
+
+ # Display lsb_release output if DEBUG mode enable
+ # This will help to diagnose problem with CPackRPM
+ # because we will know on which kind of Linux we are
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ find_program(LSB_RELEASE_EXECUTABLE lsb_release)
+ if(LSB_RELEASE_EXECUTABLE)
+ execute_process(COMMAND ${LSB_RELEASE_EXECUTABLE} -a
+ OUTPUT_VARIABLE _TMP_LSB_RELEASE_OUTPUT
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ string(REGEX REPLACE "\n" ", "
+ LSB_RELEASE_OUTPUT
+ ${_TMP_LSB_RELEASE_OUTPUT})
+ else ()
+ set(LSB_RELEASE_OUTPUT "lsb_release not installed/found!")
+ endif()
+ message("CPackRPM:Debug: LSB_RELEASE = ${LSB_RELEASE_OUTPUT}")
+ endif()
+
+ # We may use RPM version in the future in order
+ # to shut down warning about space in buildtree
+ # some recent RPM version should support space in different places.
+ # not checked [yet].
+ if(CPACK_TOPLEVEL_DIRECTORY MATCHES ".* .*")
+ message(FATAL_ERROR "${RPMBUILD_EXECUTABLE} can't handle paths with spaces, use a build directory without spaces for building RPMs.")
+ endif()
+
+ # If rpmbuild is found
+ # we try to discover alien since we may be on non RPM distro like Debian.
+ # In this case we may try to to use more advanced features
+ # like generating RPM directly from DEB using alien.
+ # FIXME feature not finished (yet)
+ find_program(ALIEN_EXECUTABLE alien)
+ if(ALIEN_EXECUTABLE)
+ message(STATUS "alien found, we may be on a Debian based distro.")
+ endif()
+
+ # Are we packaging components ?
+ if(CPACK_RPM_PACKAGE_COMPONENT)
+ string(TOUPPER ${CPACK_RPM_PACKAGE_COMPONENT} CPACK_RPM_PACKAGE_COMPONENT_UPPER)
+ endif()
+
+ set(WDIR "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_PATH}")
+
+ #
+ # Use user-defined RPM specific variables value
+ # or generate reasonable default value from
+ # CPACK_xxx generic values.
+ # The variables comes from the needed (mandatory or not)
+ # values found in the RPM specification file aka ".spec" file.
+ # The variables which may/should be defined are:
+ #
+
+ # CPACK_RPM_PACKAGE_SUMMARY (mandatory)
+
+ if(CPACK_RPM_PACKAGE_COMPONENT)
+ cpack_rpm_variable_fallback("CPACK_RPM_PACKAGE_SUMMARY"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_SUMMARY"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_PACKAGE_SUMMARY")
+ endif()
+
+ if(NOT CPACK_RPM_PACKAGE_SUMMARY)
+ if(CPACK_PACKAGE_DESCRIPTION_SUMMARY)
+ set(CPACK_RPM_PACKAGE_SUMMARY ${CPACK_PACKAGE_DESCRIPTION_SUMMARY})
+ else()
+ # if neither var is defined lets use the name as summary
+ string(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_RPM_PACKAGE_SUMMARY)
+ endif()
+ endif()
+
+ if(NOT CPACK_RPM_PACKAGE_URL AND CPACK_PACKAGE_HOMEPAGE_URL)
+ set(CPACK_RPM_PACKAGE_URL "${CPACK_PACKAGE_HOMEPAGE_URL}")
+ endif()
+
+ # CPACK_RPM_PACKAGE_NAME (mandatory)
+ if(NOT CPACK_RPM_PACKAGE_NAME)
+ string(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_RPM_PACKAGE_NAME)
+ endif()
+
+ if(CPACK_RPM_PACKAGE_COMPONENT)
+ string(TOUPPER "${CPACK_RPM_MAIN_COMPONENT}"
+ CPACK_RPM_MAIN_COMPONENT_UPPER)
+
+ if(NOT CPACK_RPM_MAIN_COMPONENT_UPPER STREQUAL CPACK_RPM_PACKAGE_COMPONENT_UPPER)
+ string(APPEND CPACK_RPM_PACKAGE_NAME "-${CPACK_RPM_PACKAGE_COMPONENT}")
+
+ cpack_rpm_variable_fallback("CPACK_RPM_PACKAGE_NAME"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_NAME"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_PACKAGE_NAME")
+ endif()
+ endif()
+
+ # CPACK_RPM_PACKAGE_VERSION (mandatory)
+ if(NOT CPACK_RPM_PACKAGE_VERSION)
+ if(NOT CPACK_PACKAGE_VERSION)
+ message(FATAL_ERROR "RPM package requires a package version")
+ endif()
+ set(CPACK_RPM_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION})
+ endif()
+ # Replace '-' in version with '_'
+ # '-' character is an Illegal RPM version character
+ # it is illegal because it is used to separate
+ # RPM "Version" from RPM "Release"
+ string(REPLACE "-" "_" CPACK_RPM_PACKAGE_VERSION ${CPACK_RPM_PACKAGE_VERSION})
+
+ # CPACK_RPM_PACKAGE_ARCHITECTURE (mandatory)
+ if(NOT CPACK_RPM_PACKAGE_ARCHITECTURE)
+ execute_process(COMMAND uname "-m"
+ OUTPUT_VARIABLE CPACK_RPM_PACKAGE_ARCHITECTURE
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ else()
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: using user-specified build arch = ${CPACK_RPM_PACKAGE_ARCHITECTURE}")
+ endif()
+ endif()
+
+ if(CPACK_RPM_PACKAGE_COMPONENT)
+ cpack_rpm_variable_fallback("CPACK_RPM_PACKAGE_ARCHITECTURE"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_ARCHITECTURE"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_PACKAGE_ARCHITECTURE")
+
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: using component build arch = ${CPACK_RPM_PACKAGE_ARCHITECTURE}")
+ endif()
+ endif()
+
+ if(${CPACK_RPM_PACKAGE_ARCHITECTURE} STREQUAL "noarch")
+ set(TMP_RPM_BUILDARCH "Buildarch: ${CPACK_RPM_PACKAGE_ARCHITECTURE}")
+ else()
+ set(TMP_RPM_BUILDARCH "")
+ endif()
+
+ # CPACK_RPM_PACKAGE_RELEASE
+ # The RPM release is the numbering of the RPM package ITSELF
+ # this is the version of the PACKAGING and NOT the version
+ # of the CONTENT of the package.
+ # You may well need to generate a new RPM package release
+ # without changing the version of the packaged software.
+ # This is the case when the packaging is buggy (not) the software :=)
+ # If not set, 1 is a good candidate
+ if(NOT CPACK_RPM_PACKAGE_RELEASE)
+ set(CPACK_RPM_PACKAGE_RELEASE "1")
+ endif()
+
+ if(CPACK_RPM_PACKAGE_RELEASE_DIST)
+ string(APPEND CPACK_RPM_PACKAGE_RELEASE "%{?dist}")
+ endif()
+
+ # CPACK_RPM_PACKAGE_LICENSE
+ if(NOT CPACK_RPM_PACKAGE_LICENSE)
+ set(CPACK_RPM_PACKAGE_LICENSE "unknown")
+ endif()
+
+ # CPACK_RPM_PACKAGE_GROUP
+ if(CPACK_RPM_PACKAGE_COMPONENT)
+ cpack_rpm_variable_fallback("CPACK_RPM_PACKAGE_GROUP"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_GROUP"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_PACKAGE_GROUP")
+ endif()
+
+ if(NOT CPACK_RPM_PACKAGE_GROUP)
+ set(CPACK_RPM_PACKAGE_GROUP "unknown")
+ endif()
+
+ # CPACK_RPM_PACKAGE_VENDOR
+ if(NOT CPACK_RPM_PACKAGE_VENDOR)
+ if(CPACK_PACKAGE_VENDOR)
+ set(CPACK_RPM_PACKAGE_VENDOR "${CPACK_PACKAGE_VENDOR}")
+ else()
+ set(CPACK_RPM_PACKAGE_VENDOR "unknown")
+ endif()
+ endif()
+
+ # CPACK_RPM_PACKAGE_SOURCE
+ # The name of the source tarball in case we generate a source RPM
+
+ # CPACK_RPM_PACKAGE_DESCRIPTION
+ # The variable content may be either
+ # - explicitly given by the user or
+ # - filled with the content of CPACK_PACKAGE_DESCRIPTION_FILE
+ # if it is defined
+ # - set to a default value
+ #
+
+ if(CPACK_RPM_PACKAGE_COMPONENT)
+ cpack_rpm_variable_fallback("CPACK_RPM_PACKAGE_DESCRIPTION"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_DESCRIPTION"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_PACKAGE_DESCRIPTION"
+ "CPACK_COMPONENT_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_DESCRIPTION")
+ endif()
+
+ if(NOT CPACK_RPM_PACKAGE_DESCRIPTION)
+ if(CPACK_PACKAGE_DESCRIPTION_FILE)
+ file(READ ${CPACK_PACKAGE_DESCRIPTION_FILE} CPACK_RPM_PACKAGE_DESCRIPTION)
+ else ()
+ set(CPACK_RPM_PACKAGE_DESCRIPTION "no package description available")
+ endif ()
+ endif ()
+
+ # CPACK_RPM_COMPRESSION_TYPE
+ #
+ if (CPACK_RPM_COMPRESSION_TYPE)
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: User Specified RPM compression type: ${CPACK_RPM_COMPRESSION_TYPE}")
+ endif()
+ if(CPACK_RPM_COMPRESSION_TYPE STREQUAL "lzma")
+ set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w9.lzdio")
+ endif()
+ if(CPACK_RPM_COMPRESSION_TYPE STREQUAL "xz")
+ set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w7.xzdio")
+ endif()
+ if(CPACK_RPM_COMPRESSION_TYPE STREQUAL "bzip2")
+ set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w9.bzdio")
+ endif()
+ if(CPACK_RPM_COMPRESSION_TYPE STREQUAL "gzip")
+ set(CPACK_RPM_COMPRESSION_TYPE_TMP "%define _binary_payload w9.gzdio")
+ endif()
+ else()
+ set(CPACK_RPM_COMPRESSION_TYPE_TMP "")
+ endif()
+
+ if(NOT CPACK_RPM_PACKAGE_SOURCES)
+ if(CPACK_PACKAGE_RELOCATABLE OR CPACK_RPM_PACKAGE_RELOCATABLE)
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: Trying to build a relocatable package")
+ endif()
+ if(CPACK_SET_DESTDIR AND (NOT CPACK_SET_DESTDIR STREQUAL "I_ON"))
+ message("CPackRPM:Warning: CPACK_SET_DESTDIR is set (=${CPACK_SET_DESTDIR}) while requesting a relocatable package (CPACK_RPM_PACKAGE_RELOCATABLE is set): this is not supported, the package won't be relocatable.")
+ set(CPACK_RPM_PACKAGE_RELOCATABLE FALSE)
+ else()
+ set(CPACK_RPM_PACKAGE_PREFIX ${CPACK_PACKAGING_INSTALL_PREFIX}) # kept for back compatibility (provided external RPM spec files)
+ cpack_rpm_prepare_relocation_paths()
+ set(CPACK_RPM_PACKAGE_RELOCATABLE TRUE)
+ endif()
+ endif()
+ else()
+ if(CPACK_RPM_PACKAGE_COMPONENT)
+ message(FATAL_ERROR "CPACK_RPM_PACKAGE_SOURCES parameter can not be used"
+ " in combination with CPACK_RPM_PACKAGE_COMPONENT parameter!")
+ endif()
+
+ set(CPACK_RPM_PACKAGE_RELOCATABLE FALSE) # disable relocatable option if building source RPM
+ endif()
+
+ execute_process(
+ COMMAND "${RPMBUILD_EXECUTABLE}" --querytags
+ OUTPUT_VARIABLE RPMBUILD_TAG_LIST
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ string(REPLACE "\n" ";" RPMBUILD_TAG_LIST "${RPMBUILD_TAG_LIST}")
+
+ if(CPACK_RPM_PACKAGE_EPOCH)
+ set(TMP_RPM_EPOCH "Epoch: ${CPACK_RPM_PACKAGE_EPOCH}")
+ endif()
+
+ # Check if additional fields for RPM spec header are given
+ # There may be some COMPONENT specific variables as well
+ # If component specific var is not provided we use the global one
+ # for each component
+ foreach(_RPM_SPEC_HEADER URL REQUIRES SUGGESTS PROVIDES OBSOLETES PREFIX CONFLICTS AUTOPROV AUTOREQ AUTOREQPROV REQUIRES_PRE REQUIRES_POST REQUIRES_PREUN REQUIRES_POSTUN)
+
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: processing ${_RPM_SPEC_HEADER}")
+ endif()
+
+ if(CPACK_RPM_PACKAGE_COMPONENT)
+ cpack_rpm_variable_fallback("CPACK_RPM_PACKAGE_${_RPM_SPEC_HEADER}"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_${_RPM_SPEC_HEADER}"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_PACKAGE_${_RPM_SPEC_HEADER}")
+ endif()
+
+ if(DEFINED CPACK_RPM_PACKAGE_${_RPM_SPEC_HEADER})
+ # Prefix can be replaced by Prefixes but the old version still works so we'll ignore it for now
+ # Requires* is a special case because it gets transformed to Requires(pre/post/preun/postun)
+ # Auto* is a special case because the tags can not be queried by querytags rpmbuild flag
+ set(special_case_tags_ PREFIX REQUIRES_PRE REQUIRES_POST REQUIRES_PREUN REQUIRES_POSTUN AUTOPROV AUTOREQ AUTOREQPROV)
+ if(NOT _RPM_SPEC_HEADER IN_LIST RPMBUILD_TAG_LIST AND NOT _RPM_SPEC_HEADER IN_LIST special_case_tags_)
+ message(AUTHOR_WARNING "CPackRPM:Warning: ${_RPM_SPEC_HEADER} not "
+ "supported in provided rpmbuild. Tag will not be used.")
+ continue()
+ endif()
+
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: using CPACK_RPM_PACKAGE_${_RPM_SPEC_HEADER}")
+ endif()
+
+ set(CPACK_RPM_PACKAGE_${_RPM_SPEC_HEADER}_TMP ${CPACK_RPM_PACKAGE_${_RPM_SPEC_HEADER}})
+ endif()
+
+ # Treat the RPM Spec keyword iff it has been properly defined
+ if(DEFINED CPACK_RPM_PACKAGE_${_RPM_SPEC_HEADER}_TMP)
+ # Transform NAME --> Name e.g. PROVIDES --> Provides
+ # The Upper-case first letter and lowercase tail is the
+ # appropriate value required in the final RPM spec file.
+ string(SUBSTRING ${_RPM_SPEC_HEADER} 1 -1 _PACKAGE_HEADER_TAIL)
+ string(TOLOWER "${_PACKAGE_HEADER_TAIL}" _PACKAGE_HEADER_TAIL)
+ string(SUBSTRING ${_RPM_SPEC_HEADER} 0 1 _PACKAGE_HEADER_NAME)
+ string(APPEND _PACKAGE_HEADER_NAME "${_PACKAGE_HEADER_TAIL}")
+ # The following keywords require parentheses around the "pre" or "post" suffix in the final RPM spec file.
+ set(SCRIPTS_REQUIREMENTS_LIST REQUIRES_PRE REQUIRES_POST REQUIRES_PREUN REQUIRES_POSTUN)
+ list(FIND SCRIPTS_REQUIREMENTS_LIST ${_RPM_SPEC_HEADER} IS_SCRIPTS_REQUIREMENT_FOUND)
+ if(NOT ${IS_SCRIPTS_REQUIREMENT_FOUND} EQUAL -1)
+ string(REPLACE "_" "(" _PACKAGE_HEADER_NAME "${_PACKAGE_HEADER_NAME}")
+ string(APPEND _PACKAGE_HEADER_NAME ")")
+ endif()
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: User defined ${_PACKAGE_HEADER_NAME}:\n ${CPACK_RPM_PACKAGE_${_RPM_SPEC_HEADER}_TMP}")
+ endif()
+ set(TMP_RPM_${_RPM_SPEC_HEADER} "${_PACKAGE_HEADER_NAME}: ${CPACK_RPM_PACKAGE_${_RPM_SPEC_HEADER}_TMP}")
+ unset(CPACK_RPM_PACKAGE_${_RPM_SPEC_HEADER}_TMP)
+ endif()
+ endforeach()
+
+ # CPACK_RPM_SPEC_INSTALL_POST
+ # May be used to define a RPM post intallation script
+ # for example setting it to "/bin/true" may prevent
+ # rpmbuild from stripping binaries.
+ if(CPACK_RPM_SPEC_INSTALL_POST)
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: User defined CPACK_RPM_SPEC_INSTALL_POST = ${CPACK_RPM_SPEC_INSTALL_POST}")
+ endif()
+ set(TMP_RPM_SPEC_INSTALL_POST "%define __spec_install_post ${CPACK_RPM_SPEC_INSTALL_POST}")
+ endif()
+
+ # CPACK_RPM_POST_INSTALL_SCRIPT_FILE (or CPACK_RPM_<COMPONENT>_POST_INSTALL_SCRIPT_FILE)
+ # CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE (or CPACK_RPM_<COMPONENT>_POST_UNINSTALL_SCRIPT_FILE)
+ # CPACK_RPM_POST_TRANS_SCRIPT_FILE (or CPACK_RPM_<COMPONENT>_POST_TRANS_SCRIPT_FILE)
+ # May be used to embed a post installation/uninstallation/transaction script in the spec file.
+ # The referred script file(s) will be read and directly
+ # put after the %post or %postun or %posttrans section
+ # ----------------------------------------------------------------
+ # CPACK_RPM_PRE_INSTALL_SCRIPT_FILE (or CPACK_RPM_<COMPONENT>_PRE_INSTALL_SCRIPT_FILE)
+ # CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE (or CPACK_RPM_<COMPONENT>_PRE_UNINSTALL_SCRIPT_FILE)
+ # CPACK_RPM_PRE_TRANS_SCRIPT_FILE (or CPACK_RPM_<COMPONENT>_PRE_TRANS_SCRIPT_FILE)
+ # May be used to embed a pre installation/uninstallation/transaction script in the spec file.
+ # The referred script file(s) will be read and directly
+ # put after the %pre or %preun or %pretrans section
+ foreach(RPM_SCRIPT_FILE_TYPE_ "INSTALL" "UNINSTALL" "TRANS")
+ foreach(RPM_SCRIPT_FILE_TIME_ "PRE" "POST")
+ set("CPACK_RPM_${RPM_SCRIPT_FILE_TIME_}_${RPM_SCRIPT_FILE_TYPE_}_READ_FILE"
+ "${CPACK_RPM_${RPM_SCRIPT_FILE_TIME_}_${RPM_SCRIPT_FILE_TYPE_}_SCRIPT_FILE}")
+
+ if(CPACK_RPM_PACKAGE_COMPONENT)
+ cpack_rpm_variable_fallback("CPACK_RPM_${RPM_SCRIPT_FILE_TIME_}_${RPM_SCRIPT_FILE_TYPE_}_READ_FILE"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_${RPM_SCRIPT_FILE_TIME_}_${RPM_SCRIPT_FILE_TYPE_}_SCRIPT_FILE"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_${RPM_SCRIPT_FILE_TIME_}_${RPM_SCRIPT_FILE_TYPE_}_SCRIPT_FILE")
+ endif()
+
+ # Handle file if it has been specified
+ if(CPACK_RPM_${RPM_SCRIPT_FILE_TIME_}_${RPM_SCRIPT_FILE_TYPE_}_READ_FILE)
+ if(EXISTS ${CPACK_RPM_${RPM_SCRIPT_FILE_TIME_}_${RPM_SCRIPT_FILE_TYPE_}_READ_FILE})
+ file(READ ${CPACK_RPM_${RPM_SCRIPT_FILE_TIME_}_${RPM_SCRIPT_FILE_TYPE_}_READ_FILE}
+ "CPACK_RPM_SPEC_${RPM_SCRIPT_FILE_TIME_}${RPM_SCRIPT_FILE_TYPE_}")
+ else()
+ message("CPackRPM:Warning: CPACK_RPM_${RPM_SCRIPT_FILE_TIME_}_${RPM_SCRIPT_FILE_TYPE_}_SCRIPT_FILE <${CPACK_RPM_${RPM_SCRIPT_FILE_TIME_}_${RPM_SCRIPT_FILE_TYPE_}_READ_FILE}> does not exists - ignoring")
+ endif()
+ else()
+ # reset SPEC var value if no file has been specified
+ # (either globally or component-wise)
+ set("CPACK_RPM_SPEC_${RPM_SCRIPT_FILE_TIME_}${RPM_SCRIPT_FILE_TYPE_}" "")
+ endif()
+ endforeach()
+ endforeach()
+
+ # CPACK_RPM_CHANGELOG_FILE
+ # May be used to embed a changelog in the spec file.
+ # The referred file will be read and directly put after the %changelog section
+ if(CPACK_RPM_CHANGELOG_FILE)
+ if(EXISTS ${CPACK_RPM_CHANGELOG_FILE})
+ file(READ ${CPACK_RPM_CHANGELOG_FILE} CPACK_RPM_SPEC_CHANGELOG)
+ else()
+ message(SEND_ERROR "CPackRPM:Warning: CPACK_RPM_CHANGELOG_FILE <${CPACK_RPM_CHANGELOG_FILE}> does not exists - ignoring")
+ endif()
+ else()
+ set(CPACK_RPM_SPEC_CHANGELOG "* Sun Jul 4 2010 Eric Noulard <eric.noulard@gmail.com> - ${CPACK_RPM_PACKAGE_VERSION}-${CPACK_RPM_PACKAGE_RELEASE}\n Generated by CPack RPM (no Changelog file were provided)")
+ endif()
+
+ # CPACK_RPM_SPEC_MORE_DEFINE
+ # This is a generated spec rpm file spaceholder
+ if(CPACK_RPM_SPEC_MORE_DEFINE)
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: User defined more define spec line specified:\n ${CPACK_RPM_SPEC_MORE_DEFINE}")
+ endif()
+ endif()
+
+ # Now we may create the RPM build tree structure
+ set(CPACK_RPM_ROOTDIR "${CPACK_TOPLEVEL_DIRECTORY}")
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: Using CPACK_RPM_ROOTDIR=${CPACK_RPM_ROOTDIR}")
+ endif()
+ # Prepare RPM build tree
+ file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR})
+ file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR}/tmp)
+ file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR}/BUILD)
+ file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR}/RPMS)
+ file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR}/SOURCES)
+ file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR}/SPECS)
+ file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR}/SRPMS)
+
+ # it seems rpmbuild can't handle spaces in the path
+ # neither escaping (as below) nor putting quotes around the path seem to help
+ #string(REGEX REPLACE " " "\\\\ " CPACK_RPM_DIRECTORY "${CPACK_TOPLEVEL_DIRECTORY}")
+ set(CPACK_RPM_DIRECTORY "${CPACK_TOPLEVEL_DIRECTORY}")
+
+ cpack_rpm_prepare_content_list()
+
+ # In component case, put CPACK_ABSOLUTE_DESTINATION_FILES_<COMPONENT>
+ # into CPACK_ABSOLUTE_DESTINATION_FILES_INTERNAL
+ # otherwise, put CPACK_ABSOLUTE_DESTINATION_FILES
+ # This must be done BEFORE the CPACK_ABSOLUTE_DESTINATION_FILES_INTERNAL handling
+ if(CPACK_RPM_PACKAGE_COMPONENT)
+ if(CPACK_ABSOLUTE_DESTINATION_FILES)
+ cpack_rpm_variable_fallback("COMPONENT_FILES_TAG"
+ "CPACK_ABSOLUTE_DESTINATION_FILES_${CPACK_RPM_PACKAGE_COMPONENT}"
+ "CPACK_ABSOLUTE_DESTINATION_FILES_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}")
+ set(CPACK_ABSOLUTE_DESTINATION_FILES_INTERNAL "${${COMPONENT_FILES_TAG}}")
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: Handling Absolute Destination Files: <${CPACK_ABSOLUTE_DESTINATION_FILES_INTERNAL}>")
+ message("CPackRPM:Debug: in component = ${CPACK_RPM_PACKAGE_COMPONENT}")
+ endif()
+ endif()
+ else()
+ if(CPACK_ABSOLUTE_DESTINATION_FILES)
+ set(CPACK_ABSOLUTE_DESTINATION_FILES_INTERNAL "${CPACK_ABSOLUTE_DESTINATION_FILES}")
+ endif()
+ endif()
+
+ # In component case, set CPACK_RPM_USER_FILELIST_INTERNAL with CPACK_RPM_<COMPONENT>_USER_FILELIST.
+ set(CPACK_RPM_USER_FILELIST_INTERNAL "")
+ if(CPACK_RPM_PACKAGE_COMPONENT)
+ cpack_rpm_variable_fallback("CPACK_RPM_USER_FILELIST_INTERNAL"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_USER_FILELIST"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_USER_FILELIST")
+
+ if(CPACK_RPM_PACKAGE_DEBUG AND CPACK_RPM_USER_FILELIST_INTERNAL)
+ message("CPackRPM:Debug: Handling User Filelist: <${CPACK_RPM_USER_FILELIST_INTERNAL}>")
+ message("CPackRPM:Debug: in component = ${CPACK_RPM_PACKAGE_COMPONENT}")
+ endif()
+ elseif(CPACK_RPM_USER_FILELIST)
+ set(CPACK_RPM_USER_FILELIST_INTERNAL "${CPACK_RPM_USER_FILELIST}")
+ endif()
+
+ # Handle user specified file line list in CPACK_RPM_USER_FILELIST_INTERNAL
+ # Remove those files from CPACK_ABSOLUTE_DESTINATION_FILES_INTERNAL
+ # or CPACK_RPM_INSTALL_FILES,
+ # hence it must be done before these auto-generated lists are processed.
+ if(CPACK_RPM_USER_FILELIST_INTERNAL)
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: Handling User Filelist: <${CPACK_RPM_USER_FILELIST_INTERNAL}>")
+ endif()
+
+ # Create CMake list from CPACK_RPM_INSTALL_FILES
+ string(STRIP "${CPACK_RPM_INSTALL_FILES}" CPACK_RPM_INSTALL_FILES_LIST)
+ string(REPLACE "\n" ";" CPACK_RPM_INSTALL_FILES_LIST
+ "${CPACK_RPM_INSTALL_FILES_LIST}")
+ string(REPLACE "\"" "" CPACK_RPM_INSTALL_FILES_LIST
+ "${CPACK_RPM_INSTALL_FILES_LIST}")
+
+ set(CPACK_RPM_USER_INSTALL_FILES "")
+ foreach(F IN LISTS CPACK_RPM_USER_FILELIST_INTERNAL)
+ string(REGEX REPLACE "%[A-Za-z]+(\\([^()]*\\))? " "" F_PATH ${F})
+ string(REGEX MATCH "(%[A-Za-z]+(\\([^()]*\\))? )*" F_PREFIX ${F})
+ string(STRIP ${F_PREFIX} F_PREFIX)
+
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: F_PREFIX=<${F_PREFIX}>, F_PATH=<${F_PATH}>")
+ endif()
+ if(F_PREFIX)
+ string(APPEND F_PREFIX " ")
+ endif()
+ # Rebuild the user list file
+ string(APPEND CPACK_RPM_USER_INSTALL_FILES "${F_PREFIX}\"${F_PATH}\"\n")
+
+ # Remove from CPACK_RPM_INSTALL_FILES and CPACK_ABSOLUTE_DESTINATION_FILES_INTERNAL
+ list(REMOVE_ITEM CPACK_RPM_INSTALL_FILES_LIST ${F_PATH})
+ # ABSOLUTE destination files list may not exists at all
+ if (CPACK_ABSOLUTE_DESTINATION_FILES_INTERNAL)
+ list(REMOVE_ITEM CPACK_ABSOLUTE_DESTINATION_FILES_INTERNAL ${F_PATH})
+ endif()
+ endforeach()
+
+ # Rebuild CPACK_RPM_INSTALL_FILES
+ set(CPACK_RPM_INSTALL_FILES "")
+ foreach(F IN LISTS CPACK_RPM_INSTALL_FILES_LIST)
+ string(APPEND CPACK_RPM_INSTALL_FILES "\"${F}\"\n")
+ endforeach()
+ else()
+ set(CPACK_RPM_USER_INSTALL_FILES "")
+ endif()
+
+ if (CPACK_ABSOLUTE_DESTINATION_FILES_INTERNAL)
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: Handling Absolute Destination Files: ${CPACK_ABSOLUTE_DESTINATION_FILES_INTERNAL}")
+ endif()
+ # Remove trailing space
+ string(STRIP "${CPACK_RPM_INSTALL_FILES}" CPACK_RPM_INSTALL_FILES_LIST)
+ # Transform endline separated - string into CMake List
+ string(REPLACE "\n" ";" CPACK_RPM_INSTALL_FILES_LIST "${CPACK_RPM_INSTALL_FILES_LIST}")
+ # Remove unnecessary quotes
+ string(REPLACE "\"" "" CPACK_RPM_INSTALL_FILES_LIST "${CPACK_RPM_INSTALL_FILES_LIST}")
+ # Remove ABSOLUTE install file from INSTALL FILE LIST
+ list(REMOVE_ITEM CPACK_RPM_INSTALL_FILES_LIST ${CPACK_ABSOLUTE_DESTINATION_FILES_INTERNAL})
+ # Rebuild INSTALL_FILES
+ set(CPACK_RPM_INSTALL_FILES "")
+ foreach(F IN LISTS CPACK_RPM_INSTALL_FILES_LIST)
+ string(APPEND CPACK_RPM_INSTALL_FILES "\"${F}\"\n")
+ endforeach()
+ # Build ABSOLUTE_INSTALL_FILES
+ set(CPACK_RPM_ABSOLUTE_INSTALL_FILES "")
+ foreach(F IN LISTS CPACK_ABSOLUTE_DESTINATION_FILES_INTERNAL)
+ string(APPEND CPACK_RPM_ABSOLUTE_INSTALL_FILES "%config \"${F}\"\n")
+ endforeach()
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: CPACK_RPM_ABSOLUTE_INSTALL_FILES=${CPACK_RPM_ABSOLUTE_INSTALL_FILES}")
+ message("CPackRPM:Debug: CPACK_RPM_INSTALL_FILES=${CPACK_RPM_INSTALL_FILES}")
+ endif()
+ else()
+ # reset vars in order to avoid leakage of value(s) from one component to another
+ set(CPACK_RPM_ABSOLUTE_INSTALL_FILES "")
+ endif()
+
+ cpack_rpm_variable_fallback("CPACK_RPM_DEBUGINFO_PACKAGE"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_DEBUGINFO_PACKAGE"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_DEBUGINFO_PACKAGE"
+ "CPACK_RPM_DEBUGINFO_PACKAGE")
+ if(CPACK_RPM_DEBUGINFO_PACKAGE OR (CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE AND NOT GENERATE_SPEC_PARTS))
+ cpack_rpm_variable_fallback("CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_BUILD_SOURCE_DIRS_PREFIX"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_BUILD_SOURCE_DIRS_PREFIX"
+ "CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX")
+ if(NOT CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX)
+ set(CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX "/usr/src/debug/${CPACK_PACKAGE_FILE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_PATH}")
+ endif()
+
+ # handle cases where path contains extra slashes (e.g. /a//b/ instead of
+ # /a/b)
+ get_filename_component(CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX
+ "${CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX}" ABSOLUTE)
+
+ if(CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE AND GENERATE_SPEC_PARTS)
+ file(WRITE "${CPACK_RPM_ROOTDIR}/SPECS/${CPACK_RPM_PACKAGE_COMPONENT}.files"
+ "${CPACK_RPM_INSTALL_FILES}")
+ else()
+ if(CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE AND CPACK_RPM_PACKAGE_COMPONENT)
+ # this part is only required by components packaging - with monolithic
+ # packages we can be certain that there are no other components present
+ # so CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE is a noop
+ if(CPACK_RPM_DEBUGINFO_PACKAGE)
+ # only add current package files to debuginfo list if debuginfo
+ # generation is enabled for current package
+ string(STRIP "${CPACK_RPM_INSTALL_FILES}" install_files_)
+ string(REPLACE "\n" ";" install_files_ "${install_files_}")
+ string(REPLACE "\"" "" install_files_ "${install_files_}")
+ else()
+ unset(install_files_)
+ endif()
+
+ file(GLOB files_ "${CPACK_RPM_DIRECTORY}/SPECS/*.files")
+
+ foreach(f_ IN LISTS files_)
+ file(READ "${f_}" tmp_)
+ string(APPEND install_files_ ";${tmp_}")
+ endforeach()
+
+ # if there were other components/groups so we need to move files from them
+ # to current component otherwise those files won't be found
+ file(GLOB components_ LIST_DIRECTORIES true RELATIVE
+ "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}"
+ "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}/*")
+ foreach(component_ IN LISTS components_)
+ string(TOUPPER "${component_}" component_dir_upper_)
+ if(component_dir_upper_ STREQUAL CPACK_RPM_PACKAGE_COMPONENT_UPPER)
+ # skip current component
+ continue()
+ endif()
+
+ file(GLOB_RECURSE files_for_move_ LIST_DIRECTORIES true RELATIVE
+ "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}/${component_}"
+ "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}/${component_}/*")
+
+ foreach(f_ IN LISTS files_for_move_)
+ set(src_file_
+ "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}/${component_}/${f_}")
+
+ if(IS_DIRECTORY "${src_file_}")
+ file(MAKE_DIRECTORY "${WDIR}/${f_}")
+ continue()
+ endif()
+
+ get_filename_component(dir_path_ "${f_}" DIRECTORY)
+
+ # check that we are not overriding an existing file that doesn't
+ # match the file that we want to copy
+ if(EXISTS "${src_file_}" AND EXISTS "${WDIR}/${f_}")
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} -E compare_files "${src_file_}" "${WDIR}/${f_}"
+ RESULT_VARIABLE res_
+ )
+ if(res_)
+ message(FATAL_ERROR "CPackRPM:Error: File on path '${WDIR}/${f_}'"
+ " already exists but is a different than the one in component"
+ " '${component_}'! Packages will not be generated.")
+ endif()
+ endif()
+
+ file(MAKE_DIRECTORY "${WDIR}/${dir_path_}")
+ file(RENAME "${src_file_}"
+ "${WDIR}/${f_}")
+ endforeach()
+ endforeach()
+
+ cpack_rpm_debugsymbol_check("${install_files_}" "${WDIR}")
+ else()
+ string(STRIP "${CPACK_RPM_INSTALL_FILES}" install_files_)
+ string(REPLACE "\n" ";" install_files_ "${install_files_}")
+ string(REPLACE "\"" "" install_files_ "${install_files_}")
+
+ cpack_rpm_debugsymbol_check("${install_files_}" "${WDIR}")
+ endif()
+
+ if(TMP_DEBUGINFO_ADDITIONAL_SOURCES)
+ set(TMP_RPM_DEBUGINFO "
+# Modified version of %%debug_package macro
+# defined in /usr/lib/rpm/macros as that one
+# can't handle injection of extra source files.
+%ifnarch noarch
+%global __debug_package 1
+%package debuginfo
+Summary: Debug information for package %{name}
+Group: Development/Debug
+AutoReqProv: 0
+%description debuginfo
+This package provides debug information for package %{name}.
+Debug information is useful when developing applications that use this
+package or when debugging this package.
+%files debuginfo -f debugfiles.list
+%defattr(-,root,root)
+${TMP_DEBUGINFO_ADDITIONAL_SOURCES}
+%endif
+")
+ elseif(CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE)
+ message(AUTHOR_WARNING "CPackRPM:Warning: debuginfo package was requested"
+ " but will not be generated as no source files were found!")
+ else()
+ message(AUTHOR_WARNING "CPackRPM:Warning: debuginfo package was requested"
+ " but will not be generated as no source files were found! Component: '"
+ "${CPACK_RPM_PACKAGE_COMPONENT}'.")
+ endif()
+ endif()
+ endif()
+
+ # Prepare install files
+ cpack_rpm_prepare_install_files(
+ "${CPACK_RPM_INSTALL_FILES}"
+ "${WDIR}"
+ "${RPM_USED_PACKAGE_PREFIXES}"
+ "${CPACK_RPM_PACKAGE_RELOCATABLE}"
+ )
+
+ # set default user and group
+ foreach(_PERM_TYPE "USER" "GROUP")
+ if(CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_DEFAULT_${_PERM_TYPE})
+ set(TMP_DEFAULT_${_PERM_TYPE} "${CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_DEFAULT_${_PERM_TYPE}}")
+ elseif(CPACK_RPM_DEFAULT_${_PERM_TYPE})
+ set(TMP_DEFAULT_${_PERM_TYPE} "${CPACK_RPM_DEFAULT_${_PERM_TYPE}}")
+ else()
+ set(TMP_DEFAULT_${_PERM_TYPE} "root")
+ endif()
+ endforeach()
+
+ # set default file and dir permissions
+ foreach(_PERM_TYPE "FILE" "DIR")
+ if(CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_DEFAULT_${_PERM_TYPE}_PERMISSIONS)
+ get_unix_permissions_octal_notation("CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_DEFAULT_${_PERM_TYPE}_PERMISSIONS" "TMP_DEFAULT_${_PERM_TYPE}_PERMISSIONS")
+ set(_PERMISSIONS_VAR "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_DEFAULT_${_PERM_TYPE}_PERMISSIONS")
+ elseif(CPACK_RPM_DEFAULT_${_PERM_TYPE}_PERMISSIONS)
+ get_unix_permissions_octal_notation("CPACK_RPM_DEFAULT_${_PERM_TYPE}_PERMISSIONS" "TMP_DEFAULT_${_PERM_TYPE}_PERMISSIONS")
+ set(_PERMISSIONS_VAR "CPACK_RPM_DEFAULT_${_PERM_TYPE}_PERMISSIONS")
+ else()
+ set(TMP_DEFAULT_${_PERM_TYPE}_PERMISSIONS "-")
+ endif()
+ endforeach()
+
+ # The name of the final spec file to be used by rpmbuild
+ set(CPACK_RPM_BINARY_SPECFILE "${CPACK_RPM_ROOTDIR}/SPECS/${CPACK_RPM_PACKAGE_NAME}.spec")
+
+ # Print out some debug information if we were asked for that
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: CPACK_TOPLEVEL_DIRECTORY = ${CPACK_TOPLEVEL_DIRECTORY}")
+ message("CPackRPM:Debug: CPACK_TOPLEVEL_TAG = ${CPACK_TOPLEVEL_TAG}")
+ message("CPackRPM:Debug: CPACK_TEMPORARY_DIRECTORY = ${CPACK_TEMPORARY_DIRECTORY}")
+ message("CPackRPM:Debug: CPACK_OUTPUT_FILE_NAME = ${CPACK_OUTPUT_FILE_NAME}")
+ message("CPackRPM:Debug: CPACK_OUTPUT_FILE_PATH = ${CPACK_OUTPUT_FILE_PATH}")
+ message("CPackRPM:Debug: CPACK_PACKAGE_FILE_NAME = ${CPACK_PACKAGE_FILE_NAME}")
+ message("CPackRPM:Debug: CPACK_RPM_BINARY_SPECFILE = ${CPACK_RPM_BINARY_SPECFILE}")
+ message("CPackRPM:Debug: CPACK_PACKAGE_INSTALL_DIRECTORY = ${CPACK_PACKAGE_INSTALL_DIRECTORY}")
+ message("CPackRPM:Debug: CPACK_TEMPORARY_PACKAGE_FILE_NAME = ${CPACK_TEMPORARY_PACKAGE_FILE_NAME}")
+ endif()
+
+ #
+ # USER generated/provided spec file handling.
+ #
+
+ # We can have a component specific spec file.
+ if(CPACK_RPM_PACKAGE_COMPONENT)
+ cpack_rpm_variable_fallback("CPACK_RPM_USER_BINARY_SPECFILE"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_USER_BINARY_SPECFILE"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_USER_BINARY_SPECFILE")
+ endif()
+
+ cpack_rpm_variable_fallback("CPACK_RPM_FILE_NAME"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_FILE_NAME"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_FILE_NAME"
+ "CPACK_RPM_FILE_NAME")
+ if(NOT CPACK_RPM_FILE_NAME STREQUAL "RPM-DEFAULT")
+ if(CPACK_RPM_FILE_NAME)
+ if(NOT CPACK_RPM_FILE_NAME MATCHES ".*\\.rpm")
+ message(FATAL_ERROR "'${CPACK_RPM_FILE_NAME}' is not a valid RPM package file name as it must end with '.rpm'!")
+ endif()
+ else()
+ # old file name format for back compatibility
+ string(TOUPPER "${CPACK_RPM_MAIN_COMPONENT}"
+ CPACK_RPM_MAIN_COMPONENT_UPPER)
+
+ if(CPACK_RPM_MAIN_COMPONENT_UPPER STREQUAL CPACK_RPM_PACKAGE_COMPONENT_UPPER)
+ # this is the main component so ignore the component filename part
+ set(CPACK_RPM_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}.rpm")
+ else()
+ set(CPACK_RPM_FILE_NAME "${CPACK_OUTPUT_FILE_NAME}")
+ endif()
+ endif()
+ # else example:
+ #set(CPACK_RPM_FILE_NAME "${CPACK_RPM_PACKAGE_NAME}-${CPACK_RPM_PACKAGE_VERSION}-${CPACK_RPM_PACKAGE_RELEASE}-${CPACK_RPM_PACKAGE_ARCHITECTURE}.rpm")
+
+ if(CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE AND GENERATE_SPEC_PARTS)
+ string(TOLOWER "${CPACK_RPM_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}.*\\.rpm" expected_filename_)
+
+ file(WRITE "${CPACK_RPM_ROOTDIR}/SPECS/${CPACK_RPM_PACKAGE_COMPONENT}.rpm_name"
+ "${expected_filename_};${CPACK_RPM_FILE_NAME}")
+ elseif(NOT CPACK_RPM_DEBUGINFO_PACKAGE)
+ set(FILE_NAME_DEFINE "%define _rpmfilename ${CPACK_RPM_FILE_NAME}")
+ endif()
+ endif()
+
+ if(CPACK_RPM_PACKAGE_SOURCES) # source rpm
+ set(archive_name_ "${CPACK_RPM_PACKAGE_NAME}-${CPACK_RPM_PACKAGE_VERSION}")
+
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} -E tar "cfvz" "${CPACK_RPM_DIRECTORY}/SOURCES/${archive_name_}.tar.gz" "${CPACK_PACKAGE_FILE_NAME}"
+ WORKING_DIRECTORY ${CPACK_RPM_DIRECTORY}
+ )
+ set(TMP_RPM_SOURCE "Source: ${archive_name_}.tar.gz")
+
+ if(CPACK_RPM_BUILDREQUIRES)
+ set(TMP_RPM_BUILD_REQUIRES "BuildRequires: ${CPACK_RPM_BUILDREQUIRES}")
+ endif()
+
+ # Disable debuginfo packages - srpm generates invalid packages due to
+ # releasing control to cpack to generate binary packages.
+ # Note however that this doesn't prevent cpack to generate debuginfo
+ # packages when run from srpm with --rebuild.
+ set(TMP_RPM_DISABLE_DEBUGINFO "%define debug_package %{nil}")
+
+ if(NOT CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX)
+ set(CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX "/")
+ endif()
+
+ set(TMP_RPM_BUILD
+ "
+%build
+mkdir cpack_rpm_build_dir
+cd cpack_rpm_build_dir
+'${CMAKE_COMMAND}' ${CPACK_RPM_SOURCE_PKG_BUILD_PARAMS} -DCPACK_PACKAGING_INSTALL_PREFIX=${CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX} ../${CPACK_PACKAGE_FILE_NAME}
+make %{?_smp_mflags}" # %{?_smp_mflags} -> -j option
+ )
+ set(TMP_RPM_INSTALL
+ "
+cd cpack_rpm_build_dir
+cpack -G RPM
+mv *.rpm %_rpmdir"
+ )
+ set(TMP_RPM_PREP "%setup -c")
+
+ set(RPMBUILD_FLAGS "-bs")
+
+ file(WRITE ${CPACK_RPM_BINARY_SPECFILE}.in
+ "# Restore old style debuginfo creation for rpm >= 4.14.
+%undefine _debugsource_packages
+%undefine _debuginfo_subpackages
+
+# -*- rpm-spec -*-
+BuildRoot: %_topdir/\@CPACK_PACKAGE_FILE_NAME\@
+Summary: \@CPACK_RPM_PACKAGE_SUMMARY\@
+Name: \@CPACK_RPM_PACKAGE_NAME\@
+Version: \@CPACK_RPM_PACKAGE_VERSION\@
+Release: \@CPACK_RPM_PACKAGE_RELEASE\@
+License: \@CPACK_RPM_PACKAGE_LICENSE\@
+Group: \@CPACK_RPM_PACKAGE_GROUP\@
+Vendor: \@CPACK_RPM_PACKAGE_VENDOR\@
+
+\@TMP_RPM_SOURCE\@
+\@TMP_RPM_BUILD_REQUIRES\@
+\@TMP_RPM_BUILDARCH\@
+\@TMP_RPM_PREFIXES\@
+
+\@TMP_RPM_DISABLE_DEBUGINFO\@
+
+%define _rpmdir %_topdir/RPMS
+%define _srcrpmdir %_topdir/SRPMS
+\@FILE_NAME_DEFINE\@
+%define _unpackaged_files_terminate_build 0
+\@TMP_RPM_SPEC_INSTALL_POST\@
+\@CPACK_RPM_SPEC_MORE_DEFINE\@
+\@CPACK_RPM_COMPRESSION_TYPE_TMP\@
+
+%description
+\@CPACK_RPM_PACKAGE_DESCRIPTION\@
+
+# This is a shortcutted spec file generated by CMake RPM generator
+# we skip _install step because CPack does that for us.
+# We do only save CPack installed tree in _prepr
+# and then restore it in build.
+%prep
+\@TMP_RPM_PREP\@
+
+\@TMP_RPM_BUILD\@
+
+#p build
+
+%install
+\@TMP_RPM_INSTALL\@
+
+%clean
+
+%changelog
+\@CPACK_RPM_SPEC_CHANGELOG\@
+"
+ )
+
+ elseif(GENERATE_SPEC_PARTS) # binary rpm with single debuginfo package
+
+ set_spec_scripts("${CPACK_RPM_PACKAGE_NAME}")
+
+ file(WRITE ${CPACK_RPM_BINARY_SPECFILE}.in
+ "# -*- rpm-spec -*-
+%package -n \@CPACK_RPM_PACKAGE_NAME\@
+Summary: \@CPACK_RPM_PACKAGE_SUMMARY\@
+Version: \@CPACK_RPM_PACKAGE_VERSION\@
+Release: \@CPACK_RPM_PACKAGE_RELEASE\@
+License: \@CPACK_RPM_PACKAGE_LICENSE\@
+Group: \@CPACK_RPM_PACKAGE_GROUP\@
+Vendor: \@CPACK_RPM_PACKAGE_VENDOR\@
+
+\@TMP_RPM_URL\@
+\@TMP_RPM_REQUIRES\@
+\@TMP_RPM_REQUIRES_PRE\@
+\@TMP_RPM_REQUIRES_POST\@
+\@TMP_RPM_REQUIRES_PREUN\@
+\@TMP_RPM_REQUIRES_POSTUN\@
+\@TMP_RPM_PROVIDES\@
+\@TMP_RPM_OBSOLETES\@
+\@TMP_RPM_CONFLICTS\@
+\@TMP_RPM_SUGGESTS\@
+\@TMP_RPM_AUTOPROV\@
+\@TMP_RPM_AUTOREQ\@
+\@TMP_RPM_AUTOREQPROV\@
+\@TMP_RPM_BUILDARCH\@
+\@TMP_RPM_PREFIXES\@
+\@TMP_RPM_EPOCH\@
+
+%description -n \@CPACK_RPM_PACKAGE_NAME\@
+\@CPACK_RPM_PACKAGE_DESCRIPTION\@
+
+\@post_\@
+\@posttrans_\@
+\@postun_\@
+\@pre_\@
+\@pretrans_\@
+\@preun_\@
+
+%files -n \@CPACK_RPM_PACKAGE_NAME\@
+%defattr(\@TMP_DEFAULT_FILE_PERMISSIONS\@,\@TMP_DEFAULT_USER\@,\@TMP_DEFAULT_GROUP\@,\@TMP_DEFAULT_DIR_PERMISSIONS\@)
+\@CPACK_RPM_INSTALL_FILES\@
+\@CPACK_RPM_ABSOLUTE_INSTALL_FILES\@
+\@CPACK_RPM_USER_INSTALL_FILES\@
+"
+ )
+
+ else() # binary rpm
+ if(CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE)
+ # find generated spec file and take its name
+ file(GLOB spec_files_ "${CPACK_RPM_DIRECTORY}/SPECS/*.spec")
+
+ foreach(f_ IN LISTS spec_files_)
+ file(READ "${f_}" tmp_)
+ string(APPEND TMP_OTHER_COMPONENTS "\n${tmp_}\n")
+ endforeach()
+ endif()
+
+ # We should generate a USER spec file template:
+ # - either because the user asked for it : CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE
+ # - or the user did not provide one : NOT CPACK_RPM_USER_BINARY_SPECFILE
+ set(RPMBUILD_FLAGS "-bb")
+ if(CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE OR NOT CPACK_RPM_USER_BINARY_SPECFILE)
+
+ set_spec_scripts("")
+
+ file(WRITE ${CPACK_RPM_BINARY_SPECFILE}.in
+ "# Restore old style debuginfo creation for rpm >= 4.14.
+%undefine _debugsource_packages
+%undefine _debuginfo_subpackages
+
+# -*- rpm-spec -*-
+BuildRoot: %_topdir/\@CPACK_PACKAGE_FILE_NAME\@\@CPACK_RPM_PACKAGE_COMPONENT_PART_PATH\@
+Summary: \@CPACK_RPM_PACKAGE_SUMMARY\@
+Name: \@CPACK_RPM_PACKAGE_NAME\@
+Version: \@CPACK_RPM_PACKAGE_VERSION\@
+Release: \@CPACK_RPM_PACKAGE_RELEASE\@
+License: \@CPACK_RPM_PACKAGE_LICENSE\@
+Group: \@CPACK_RPM_PACKAGE_GROUP\@
+Vendor: \@CPACK_RPM_PACKAGE_VENDOR\@
+
+\@TMP_RPM_URL\@
+\@TMP_RPM_REQUIRES\@
+\@TMP_RPM_REQUIRES_PRE\@
+\@TMP_RPM_REQUIRES_POST\@
+\@TMP_RPM_REQUIRES_PREUN\@
+\@TMP_RPM_REQUIRES_POSTUN\@
+\@TMP_RPM_PROVIDES\@
+\@TMP_RPM_OBSOLETES\@
+\@TMP_RPM_CONFLICTS\@
+\@TMP_RPM_SUGGESTS\@
+\@TMP_RPM_AUTOPROV\@
+\@TMP_RPM_AUTOREQ\@
+\@TMP_RPM_AUTOREQPROV\@
+\@TMP_RPM_BUILDARCH\@
+\@TMP_RPM_PREFIXES\@
+\@TMP_RPM_EPOCH\@
+
+\@TMP_RPM_DEBUGINFO\@
+
+%define _rpmdir %_topdir/RPMS
+%define _srcrpmdir %_topdir/SRPMS
+\@FILE_NAME_DEFINE\@
+%define _unpackaged_files_terminate_build 0
+\@TMP_RPM_SPEC_INSTALL_POST\@
+\@CPACK_RPM_SPEC_MORE_DEFINE\@
+\@CPACK_RPM_COMPRESSION_TYPE_TMP\@
+
+%description
+\@CPACK_RPM_PACKAGE_DESCRIPTION\@
+
+# This is a shortcutted spec file generated by CMake RPM generator
+# we skip _install step because CPack does that for us.
+# We do only save CPack installed tree in _prepr
+# and then restore it in build.
+%prep
+mv $RPM_BUILD_ROOT %_topdir/tmpBBroot
+
+%install
+if [ -e $RPM_BUILD_ROOT ];
+then
+ rm -rf $RPM_BUILD_ROOT
+fi
+mv %_topdir/tmpBBroot $RPM_BUILD_ROOT
+
+\@TMP_RPM_DEBUGINFO_INSTALL\@
+
+%clean
+
+\@post_\@
+\@posttrans_\@
+\@postun_\@
+\@pre_\@
+\@pretrans_\@
+\@preun_\@
+
+%files
+%defattr(\@TMP_DEFAULT_FILE_PERMISSIONS\@,\@TMP_DEFAULT_USER\@,\@TMP_DEFAULT_GROUP\@,\@TMP_DEFAULT_DIR_PERMISSIONS\@)
+\@CPACK_RPM_INSTALL_FILES\@
+\@CPACK_RPM_ABSOLUTE_INSTALL_FILES\@
+\@CPACK_RPM_USER_INSTALL_FILES\@
+
+%changelog
+\@CPACK_RPM_SPEC_CHANGELOG\@
+
+\@TMP_OTHER_COMPONENTS\@
+"
+ )
+ endif()
+
+ # Stop here if we were asked to only generate a template USER spec file
+ # The generated file may then be used as a template by user who wants
+ # to customize their own spec file.
+ if(CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE)
+ message(FATAL_ERROR "CPackRPM: STOP here Generated USER binary spec file template is: ${CPACK_RPM_BINARY_SPECFILE}.in")
+ endif()
+ endif()
+
+ # After that we may either use a user provided spec file
+ # or generate one using appropriate variables value.
+ if(CPACK_RPM_USER_BINARY_SPECFILE)
+ # User may have specified SPECFILE just use it
+ message("CPackRPM: Will use USER specified spec file: ${CPACK_RPM_USER_BINARY_SPECFILE}")
+ # The user provided file is processed for @var replacement
+ configure_file(${CPACK_RPM_USER_BINARY_SPECFILE} ${CPACK_RPM_BINARY_SPECFILE} @ONLY)
+ else()
+ # No User specified spec file, will use the generated spec file
+ message("CPackRPM: Will use GENERATED spec file: ${CPACK_RPM_BINARY_SPECFILE}")
+ # Note the just created file is processed for @var replacement
+ configure_file(${CPACK_RPM_BINARY_SPECFILE}.in ${CPACK_RPM_BINARY_SPECFILE} @ONLY)
+ endif()
+
+ if(NOT GENERATE_SPEC_PARTS) # generate package
+ if(RPMBUILD_EXECUTABLE)
+ # Now call rpmbuild using the SPECFILE
+ execute_process(
+ COMMAND "${RPMBUILD_EXECUTABLE}" ${RPMBUILD_FLAGS}
+ --define "_topdir ${CPACK_RPM_DIRECTORY}"
+ --buildroot "%_topdir/${CPACK_PACKAGE_FILE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_PATH}"
+ --target "${CPACK_RPM_PACKAGE_ARCHITECTURE}"
+ "${CPACK_RPM_BINARY_SPECFILE}"
+ WORKING_DIRECTORY "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_PATH}"
+ RESULT_VARIABLE CPACK_RPMBUILD_EXEC_RESULT
+ ERROR_FILE "${CPACK_TOPLEVEL_DIRECTORY}/rpmbuild${CPACK_RPM_PACKAGE_NAME}.err"
+ OUTPUT_FILE "${CPACK_TOPLEVEL_DIRECTORY}/rpmbuild${CPACK_RPM_PACKAGE_NAME}.out")
+ if(CPACK_RPM_PACKAGE_DEBUG OR CPACK_RPMBUILD_EXEC_RESULT)
+ file(READ ${CPACK_TOPLEVEL_DIRECTORY}/rpmbuild${CPACK_RPM_PACKAGE_NAME}.err RPMBUILDERR)
+ file(READ ${CPACK_TOPLEVEL_DIRECTORY}/rpmbuild${CPACK_RPM_PACKAGE_NAME}.out RPMBUILDOUT)
+ message("CPackRPM:Debug: You may consult rpmbuild logs in: ")
+ message("CPackRPM:Debug: - ${CPACK_TOPLEVEL_DIRECTORY}/rpmbuild${CPACK_RPM_PACKAGE_NAME}.err")
+ message("CPackRPM:Debug: *** ${RPMBUILDERR} ***")
+ message("CPackRPM:Debug: - ${CPACK_TOPLEVEL_DIRECTORY}/rpmbuild${CPACK_RPM_PACKAGE_NAME}.out")
+ message("CPackRPM:Debug: *** ${RPMBUILDOUT} ***")
+ endif()
+ else()
+ if(ALIEN_EXECUTABLE)
+ message(FATAL_ERROR "RPM packaging through alien not done (yet)")
+ endif()
+ endif()
+
+ # find generated rpm files and take their names
+ file(GLOB_RECURSE GENERATED_FILES "${CPACK_RPM_DIRECTORY}/RPMS/*.rpm"
+ "${CPACK_RPM_DIRECTORY}/SRPMS/*.rpm")
+
+ if(NOT GENERATED_FILES)
+ message(FATAL_ERROR "RPM package was not generated! ${CPACK_RPM_DIRECTORY}")
+ endif()
+
+ unset(expected_filenames_)
+ unset(filenames_)
+ if(CPACK_RPM_DEBUGINFO_PACKAGE AND NOT CPACK_RPM_FILE_NAME STREQUAL "RPM-DEFAULT")
+ list(APPEND expected_filenames_
+ "${CPACK_RPM_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}.*\\.rpm")
+ list(APPEND filenames_ "${CPACK_RPM_FILE_NAME}")
+ endif()
+
+ if(CPACK_RPM_DEBUGINFO_PACKAGE)
+ cpack_rpm_variable_fallback("CPACK_RPM_DEBUGINFO_FILE_NAME"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_DEBUGINFO_FILE_NAME"
+ "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_DEBUGINFO_FILE_NAME"
+ "CPACK_RPM_DEBUGINFO_FILE_NAME")
+
+ if(CPACK_RPM_DEBUGINFO_FILE_NAME AND
+ NOT CPACK_RPM_DEBUGINFO_FILE_NAME STREQUAL "RPM-DEFAULT")
+ list(APPEND expected_filenames_
+ "${CPACK_RPM_PACKAGE_NAME}-debuginfo-${CPACK_PACKAGE_VERSION}.*\\.rpm")
+ string(REPLACE "@cpack_component@" "${CPACK_RPM_PACKAGE_COMPONENT}"
+ CPACK_RPM_DEBUGINFO_FILE_NAME "${CPACK_RPM_DEBUGINFO_FILE_NAME}")
+ list(APPEND filenames_ "${CPACK_RPM_DEBUGINFO_FILE_NAME}")
+ endif()
+ endif()
+
+ # check if other files have to be renamed
+ file(GLOB rename_files_ "${CPACK_RPM_DIRECTORY}/SPECS/*.rpm_name")
+ if(rename_files_)
+ foreach(f_ IN LISTS rename_files_)
+ file(READ "${f_}" tmp_)
+ list(GET tmp_ 0 efn_)
+ list(APPEND expected_filenames_ "${efn_}")
+ list(GET tmp_ 1 fn_)
+ list(APPEND filenames_ "${fn_}")
+ endforeach()
+ endif()
+
+ if(expected_filenames_)
+ foreach(F IN LISTS GENERATED_FILES)
+ unset(matched_)
+ foreach(expected_ IN LISTS expected_filenames_)
+ if(F MATCHES ".*/${expected_}")
+ list(FIND expected_filenames_ "${expected_}" idx_)
+ list(GET filenames_ ${idx_} filename_)
+ get_filename_component(FILE_PATH "${F}" DIRECTORY)
+ file(RENAME "${F}" "${FILE_PATH}/${filename_}")
+ list(APPEND new_files_list_ "${FILE_PATH}/${filename_}")
+ set(matched_ "YES")
+
+ break()
+ endif()
+ endforeach()
+
+ if(NOT matched_)
+ list(APPEND new_files_list_ "${F}")
+ endif()
+ endforeach()
+
+ set(GENERATED_FILES "${new_files_list_}")
+ endif()
+ endif()
+
+ set(GEN_CPACK_OUTPUT_FILES "${GENERATED_FILES}" PARENT_SCOPE)
+
+ if(CPACK_RPM_PACKAGE_DEBUG)
+ message("CPackRPM:Debug: GEN_CPACK_OUTPUT_FILES = ${GENERATED_FILES}")
+ endif()
+endfunction()
+
+cpack_rpm_generate_package()
+
+cmake_policy(POP)
diff --git a/Modules/Internal/CPack/CPackWIX.cmake b/Modules/Internal/CPack/CPackWIX.cmake
new file mode 100644
index 0000000..d1875f2
--- /dev/null
+++ b/Modules/Internal/CPack/CPackWIX.cmake
@@ -0,0 +1,20 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+if(NOT CPACK_WIX_ROOT)
+ string(REPLACE "\\" "/" CPACK_WIX_ROOT "$ENV{WIX}")
+endif()
+
+find_program(CPACK_WIX_CANDLE_EXECUTABLE candle
+ PATHS "${CPACK_WIX_ROOT}" PATH_SUFFIXES "bin")
+
+if(NOT CPACK_WIX_CANDLE_EXECUTABLE)
+ message(FATAL_ERROR "Could not find the WiX candle executable.")
+endif()
+
+find_program(CPACK_WIX_LIGHT_EXECUTABLE light
+ PATHS "${CPACK_WIX_ROOT}" PATH_SUFFIXES "bin")
+
+if(NOT CPACK_WIX_LIGHT_EXECUTABLE)
+ message(FATAL_ERROR "Could not find the WiX light executable.")
+endif()
diff --git a/Modules/Internal/CPack/CPackZIP.cmake b/Modules/Internal/CPack/CPackZIP.cmake
new file mode 100644
index 0000000..f619de4
--- /dev/null
+++ b/Modules/Internal/CPack/CPackZIP.cmake
@@ -0,0 +1,30 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+if(CMAKE_BINARY_DIR)
+ message(FATAL_ERROR "CPackZIP.cmake may only be used by CPack internally.")
+endif()
+
+find_program(ZIP_EXECUTABLE wzzip PATHS "$ENV{ProgramFiles}/WinZip")
+if(ZIP_EXECUTABLE)
+ set(CPACK_ZIP_COMMAND "\"${ZIP_EXECUTABLE}\" -P \"<ARCHIVE>\" @<FILELIST>")
+ set(CPACK_ZIP_NEED_QUOTES TRUE)
+endif()
+
+if(NOT ZIP_EXECUTABLE)
+ find_program(ZIP_EXECUTABLE 7z PATHS "$ENV{ProgramFiles}/7-Zip")
+ if(ZIP_EXECUTABLE)
+ set(CPACK_ZIP_COMMAND "\"${ZIP_EXECUTABLE}\" a -tzip \"<ARCHIVE>\" @<FILELIST>")
+ set(CPACK_ZIP_NEED_QUOTES TRUE)
+ endif()
+endif()
+
+if(NOT ZIP_EXECUTABLE)
+ find_package(Cygwin)
+ find_program(ZIP_EXECUTABLE zip PATHS "${CYGWIN_INSTALL_PATH}/bin")
+ if(ZIP_EXECUTABLE)
+ set(CPACK_ZIP_COMMAND "\"${ZIP_EXECUTABLE}\" -r \"<ARCHIVE>\" . -i@<FILELIST>")
+ set(CPACK_ZIP_NEED_QUOTES FALSE)
+ endif()
+endif()
diff --git a/Modules/Internal/CPack/NSIS.InstallOptions.ini.in b/Modules/Internal/CPack/NSIS.InstallOptions.ini.in
new file mode 100644
index 0000000..d92d779
--- /dev/null
+++ b/Modules/Internal/CPack/NSIS.InstallOptions.ini.in
@@ -0,0 +1,46 @@
+[Settings]
+NumFields=5
+
+[Field 1]
+Type=label
+Text=By default @CPACK_PACKAGE_INSTALL_DIRECTORY@ does not add its directory to the system PATH.
+Left=0
+Right=-1
+Top=0
+Bottom=20
+
+[Field 2]
+Type=radiobutton
+Text=Do not add @CPACK_PACKAGE_NAME@ to the system PATH
+Left=0
+Right=-1
+Top=30
+Bottom=40
+State=1
+
+[Field 3]
+Type=radiobutton
+Text=Add @CPACK_PACKAGE_NAME@ to the system PATH for all users
+Left=0
+Right=-1
+Top=40
+Bottom=50
+State=0
+
+[Field 4]
+Type=radiobutton
+Text=Add @CPACK_PACKAGE_NAME@ to the system PATH for current user
+Left=0
+Right=-1
+Top=50
+Bottom=60
+State=0
+
+[Field 5]
+Type=CheckBox
+Text=Create @CPACK_PACKAGE_NAME@ Desktop Icon
+Left=0
+Right=-1
+Top=80
+Bottom=90
+State=0
diff --git a/Modules/Internal/CPack/NSIS.template.in b/Modules/Internal/CPack/NSIS.template.in
new file mode 100644
index 0000000..e6439ad
--- /dev/null
+++ b/Modules/Internal/CPack/NSIS.template.in
@@ -0,0 +1,980 @@
+; CPack install script designed for a nmake build
+
+;--------------------------------
+; You must define these values
+
+ !define VERSION "@CPACK_PACKAGE_VERSION@"
+ !define PATCH "@CPACK_PACKAGE_VERSION_PATCH@"
+ !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@"
+
+;--------------------------------
+;Variables
+
+ Var MUI_TEMP
+ Var STARTMENU_FOLDER
+ Var SV_ALLUSERS
+ Var START_MENU
+ Var DO_NOT_ADD_TO_PATH
+ Var ADD_TO_PATH_ALL_USERS
+ Var ADD_TO_PATH_CURRENT_USER
+ Var INSTALL_DESKTOP
+ Var IS_DEFAULT_INSTALLDIR
+;--------------------------------
+;Include Modern UI
+
+ !include "MUI.nsh"
+
+ ;Default installation folder
+ InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
+
+;--------------------------------
+;General
+
+ ;Name and file
+ Name "@CPACK_NSIS_PACKAGE_NAME@"
+ OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@"
+
+ ;Set compression
+ SetCompressor @CPACK_NSIS_COMPRESSOR@
+
+ ;Require administrator access
+ RequestExecutionLevel admin
+
+@CPACK_NSIS_DEFINES@
+@CPACK_NSIS_MANIFEST_DPI_AWARE_CODE@
+@CPACK_NSIS_BRANDING_TEXT_CODE@
+
+ !include Sections.nsh
+
+;--- Component support macros: ---
+; The code for the add/remove functionality is from:
+; http://nsis.sourceforge.net/Add/Remove_Functionality
+; It has been modified slightly and extended to provide
+; inter-component dependencies.
+Var AR_SecFlags
+Var AR_RegFlags
+@CPACK_NSIS_SECTION_SELECTED_VARS@
+
+; Loads the "selected" flag for the section named SecName into the
+; variable VarName.
+!macro LoadSectionSelectedIntoVar SecName VarName
+ SectionGetFlags ${${SecName}} $${VarName}
+ IntOp $${VarName} $${VarName} & ${SF_SELECTED} ;Turn off all other bits
+!macroend
+
+; Loads the value of a variable... can we get around this?
+!macro LoadVar VarName
+ IntOp $R0 0 + $${VarName}
+!macroend
+
+; Sets the value of a variable
+!macro StoreVar VarName IntValue
+ IntOp $${VarName} 0 + ${IntValue}
+!macroend
+
+!macro InitSection SecName
+ ; This macro reads component installed flag from the registry and
+ ;changes checked state of the section on the components page.
+ ;Input: section index constant name specified in Section command.
+
+ ClearErrors
+ ;Reading component status from registry
+ ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" "Installed"
+ IfErrors "default_${SecName}"
+ ;Status will stay default if registry value not found
+ ;(component was never installed)
+ IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits
+ SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading default section flags
+ IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE ;Turn lowest (enabled) bit off
+ IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags ;Change lowest bit
+
+ ; Note whether this component was installed before
+ !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags
+ IntOp $R0 $AR_RegFlags & $AR_RegFlags
+
+ ;Writing modified flags
+ SectionSetFlags ${${SecName}} $AR_SecFlags
+
+ "default_${SecName}:"
+ !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected
+!macroend
+
+!macro FinishSection SecName
+ ; This macro reads section flag set by user and removes the section
+ ;if it is not selected.
+ ;Then it writes component installed flag to registry
+ ;Input: section index constant name specified in Section command.
+
+ SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading section flags
+ ;Checking lowest bit:
+ IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED}
+ IntCmp $AR_SecFlags 1 "leave_${SecName}"
+ ;Section is not selected:
+ ;Calling Section uninstall macro and writing zero installed flag
+ !insertmacro "Remove_${${SecName}}"
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \
+ "Installed" 0
+ Goto "exit_${SecName}"
+
+ "leave_${SecName}:"
+ ;Section is selected:
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \
+ "Installed" 1
+
+ "exit_${SecName}:"
+!macroend
+
+!macro RemoveSection_CPack SecName
+ ; This macro is used to call section's Remove_... macro
+ ;from the uninstaller.
+ ;Input: section index constant name specified in Section command.
+
+ !insertmacro "Remove_${${SecName}}"
+!macroend
+
+; Determine whether the selection of SecName changed
+!macro MaybeSelectionChanged SecName
+ !insertmacro LoadVar ${SecName}_selected
+ SectionGetFlags ${${SecName}} $R1
+ IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits
+
+ ; See if the status has changed:
+ IntCmp $R0 $R1 "${SecName}_unchanged"
+ !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected
+
+ IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected"
+ !insertmacro "Deselect_required_by_${SecName}"
+ goto "${SecName}_unchanged"
+
+ "${SecName}_was_selected:"
+ !insertmacro "Select_${SecName}_depends"
+
+ "${SecName}_unchanged:"
+!macroend
+;--- End of Add/Remove macros ---
+
+;--------------------------------
+;Interface Settings
+
+ !define MUI_HEADERIMAGE
+ !define MUI_ABORTWARNING
+
+;----------------------------------------
+; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02"
+;----------------------------------------
+!verbose 3
+!include "WinMessages.NSH"
+!verbose 4
+;====================================================
+; get_NT_environment
+; Returns: the selected environment
+; Output : head of the stack
+;====================================================
+!macro select_NT_profile UN
+Function ${UN}select_NT_profile
+ StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single
+ DetailPrint "Selected environment for all users"
+ Push "all"
+ Return
+ environment_single:
+ DetailPrint "Selected environment for current user only."
+ Push "current"
+ Return
+FunctionEnd
+!macroend
+!insertmacro select_NT_profile ""
+!insertmacro select_NT_profile "un."
+;----------------------------------------------------
+!define NT_current_env 'HKCU "Environment"'
+!define NT_all_env 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
+
+!ifndef WriteEnvStr_RegKey
+ !ifdef ALL_USERS
+ !define WriteEnvStr_RegKey \
+ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
+ !else
+ !define WriteEnvStr_RegKey 'HKCU "Environment"'
+ !endif
+!endif
+
+; AddToPath - Adds the given dir to the search path.
+; Input - head of the stack
+; Note - Win9x systems requires reboot
+
+Function AddToPath
+ Exch $0
+ Push $1
+ Push $2
+ Push $3
+
+ # don't add if the path doesn't exist
+ IfFileExists "$0\*.*" "" AddToPath_done
+
+ ReadEnvStr $1 PATH
+ ; if the path is too long for a NSIS variable NSIS will return a 0
+ ; length string. If we find that, then warn and skip any path
+ ; modification as it will trash the existing path.
+ StrLen $2 $1
+ IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done
+ CheckPathLength_ShowPathWarning:
+ Messagebox MB_OK|MB_ICONEXCLAMATION "Warning! PATH too long installer unable to modify PATH!"
+ Goto AddToPath_done
+ CheckPathLength_Done:
+ Push "$1;"
+ Push "$0;"
+ Call StrStr
+ Pop $2
+ StrCmp $2 "" "" AddToPath_done
+ Push "$1;"
+ Push "$0\;"
+ Call StrStr
+ Pop $2
+ StrCmp $2 "" "" AddToPath_done
+ GetFullPathName /SHORT $3 $0
+ Push "$1;"
+ Push "$3;"
+ Call StrStr
+ Pop $2
+ StrCmp $2 "" "" AddToPath_done
+ Push "$1;"
+ Push "$3\;"
+ Call StrStr
+ Pop $2
+ StrCmp $2 "" "" AddToPath_done
+
+ Call IsNT
+ Pop $1
+ StrCmp $1 1 AddToPath_NT
+ ; Not on NT
+ StrCpy $1 $WINDIR 2
+ FileOpen $1 "$1\autoexec.bat" a
+ FileSeek $1 -1 END
+ FileReadByte $1 $2
+ IntCmp $2 26 0 +2 +2 # DOS EOF
+ FileSeek $1 -1 END # write over EOF
+ FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n"
+ FileClose $1
+ SetRebootFlag true
+ Goto AddToPath_done
+
+ AddToPath_NT:
+ StrCmp $ADD_TO_PATH_ALL_USERS "1" ReadAllKey
+ ReadRegStr $1 ${NT_current_env} "PATH"
+ Goto DoTrim
+ ReadAllKey:
+ ReadRegStr $1 ${NT_all_env} "PATH"
+ DoTrim:
+ StrCmp $1 "" AddToPath_NTdoIt
+ Push $1
+ Call Trim
+ Pop $1
+ StrCpy $0 "$1;$0"
+ AddToPath_NTdoIt:
+ StrCmp $ADD_TO_PATH_ALL_USERS "1" WriteAllKey
+ WriteRegExpandStr ${NT_current_env} "PATH" $0
+ Goto DoSend
+ WriteAllKey:
+ WriteRegExpandStr ${NT_all_env} "PATH" $0
+ DoSend:
+ SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
+
+ AddToPath_done:
+ Pop $3
+ Pop $2
+ Pop $1
+ Pop $0
+FunctionEnd
+
+
+; RemoveFromPath - Remove a given dir from the path
+; Input: head of the stack
+
+Function un.RemoveFromPath
+ Exch $0
+ Push $1
+ Push $2
+ Push $3
+ Push $4
+ Push $5
+ Push $6
+
+ IntFmt $6 "%c" 26 # DOS EOF
+
+ Call un.IsNT
+ Pop $1
+ StrCmp $1 1 unRemoveFromPath_NT
+ ; Not on NT
+ StrCpy $1 $WINDIR 2
+ FileOpen $1 "$1\autoexec.bat" r
+ GetTempFileName $4
+ FileOpen $2 $4 w
+ GetFullPathName /SHORT $0 $0
+ StrCpy $0 "SET PATH=%PATH%;$0"
+ Goto unRemoveFromPath_dosLoop
+
+ unRemoveFromPath_dosLoop:
+ FileRead $1 $3
+ StrCpy $5 $3 1 -1 # read last char
+ StrCmp $5 $6 0 +2 # if DOS EOF
+ StrCpy $3 $3 -1 # remove DOS EOF so we can compare
+ StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine
+ StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine
+ StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine
+ StrCmp $3 "" unRemoveFromPath_dosLoopEnd
+ FileWrite $2 $3
+ Goto unRemoveFromPath_dosLoop
+ unRemoveFromPath_dosLoopRemoveLine:
+ SetRebootFlag true
+ Goto unRemoveFromPath_dosLoop
+
+ unRemoveFromPath_dosLoopEnd:
+ FileClose $2
+ FileClose $1
+ StrCpy $1 $WINDIR 2
+ Delete "$1\autoexec.bat"
+ CopyFiles /SILENT $4 "$1\autoexec.bat"
+ Delete $4
+ Goto unRemoveFromPath_done
+
+ unRemoveFromPath_NT:
+ StrCmp $ADD_TO_PATH_ALL_USERS "1" unReadAllKey
+ ReadRegStr $1 ${NT_current_env} "PATH"
+ Goto unDoTrim
+ unReadAllKey:
+ ReadRegStr $1 ${NT_all_env} "PATH"
+ unDoTrim:
+ StrCpy $5 $1 1 -1 # copy last char
+ StrCmp $5 ";" +2 # if last char != ;
+ StrCpy $1 "$1;" # append ;
+ Push $1
+ Push "$0;"
+ Call un.StrStr ; Find `$0;` in $1
+ Pop $2 ; pos of our dir
+ StrCmp $2 "" unRemoveFromPath_done
+ ; else, it is in path
+ # $0 - path to add
+ # $1 - path var
+ StrLen $3 "$0;"
+ StrLen $4 $2
+ StrCpy $5 $1 -$4 # $5 is now the part before the path to remove
+ StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove
+ StrCpy $3 $5$6
+
+ StrCpy $5 $3 1 -1 # copy last char
+ StrCmp $5 ";" 0 +2 # if last char == ;
+ StrCpy $3 $3 -1 # remove last char
+
+ StrCmp $ADD_TO_PATH_ALL_USERS "1" unWriteAllKey
+ WriteRegExpandStr ${NT_current_env} "PATH" $3
+ Goto unDoSend
+ unWriteAllKey:
+ WriteRegExpandStr ${NT_all_env} "PATH" $3
+ unDoSend:
+ SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
+
+ unRemoveFromPath_done:
+ Pop $6
+ Pop $5
+ Pop $4
+ Pop $3
+ Pop $2
+ Pop $1
+ Pop $0
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Uninstall sutff
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+###########################################
+# Utility Functions #
+###########################################
+
+;====================================================
+; IsNT - Returns 1 if the current system is NT, 0
+; otherwise.
+; Output: head of the stack
+;====================================================
+; IsNT
+; no input
+; output, top of the stack = 1 if NT or 0 if not
+;
+; Usage:
+; Call IsNT
+; Pop $R0
+; ($R0 at this point is 1 or 0)
+
+!macro IsNT un
+Function ${un}IsNT
+ Push $0
+ ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
+ StrCmp $0 "" 0 IsNT_yes
+ ; we are not NT.
+ Pop $0
+ Push 0
+ Return
+
+ IsNT_yes:
+ ; NT!!!
+ Pop $0
+ Push 1
+FunctionEnd
+!macroend
+!insertmacro IsNT ""
+!insertmacro IsNT "un."
+
+; StrStr
+; input, top of stack = string to search for
+; top of stack-1 = string to search in
+; output, top of stack (replaces with the portion of the string remaining)
+; modifies no other variables.
+;
+; Usage:
+; Push "this is a long ass string"
+; Push "ass"
+; Call StrStr
+; Pop $R0
+; ($R0 at this point is "ass string")
+
+!macro StrStr un
+Function ${un}StrStr
+Exch $R1 ; st=haystack,old$R1, $R1=needle
+ Exch ; st=old$R1,haystack
+ Exch $R2 ; st=old$R1,old$R2, $R2=haystack
+ Push $R3
+ Push $R4
+ Push $R5
+ StrLen $R3 $R1
+ StrCpy $R4 0
+ ; $R1=needle
+ ; $R2=haystack
+ ; $R3=len(needle)
+ ; $R4=cnt
+ ; $R5=tmp
+ loop:
+ StrCpy $R5 $R2 $R3 $R4
+ StrCmp $R5 $R1 done
+ StrCmp $R5 "" done
+ IntOp $R4 $R4 + 1
+ Goto loop
+done:
+ StrCpy $R1 $R2 "" $R4
+ Pop $R5
+ Pop $R4
+ Pop $R3
+ Pop $R2
+ Exch $R1
+FunctionEnd
+!macroend
+!insertmacro StrStr ""
+!insertmacro StrStr "un."
+
+Function Trim ; Added by Pelaca
+ Exch $R1
+ Push $R2
+Loop:
+ StrCpy $R2 "$R1" 1 -1
+ StrCmp "$R2" " " RTrim
+ StrCmp "$R2" "$\n" RTrim
+ StrCmp "$R2" "$\r" RTrim
+ StrCmp "$R2" ";" RTrim
+ GoTo Done
+RTrim:
+ StrCpy $R1 "$R1" -1
+ Goto Loop
+Done:
+ Pop $R2
+ Exch $R1
+FunctionEnd
+
+Function ConditionalAddToRegisty
+ Pop $0
+ Pop $1
+ StrCmp "$0" "" ConditionalAddToRegisty_EmptyString
+ WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" \
+ "$1" "$0"
+ ;MessageBox MB_OK "Set Registry: '$1' to '$0'"
+ DetailPrint "Set install registry entry: '$1' to '$0'"
+ ConditionalAddToRegisty_EmptyString:
+FunctionEnd
+
+;--------------------------------
+
+!ifdef CPACK_USES_DOWNLOAD
+Function DownloadFile
+ IfFileExists $INSTDIR\* +2
+ CreateDirectory $INSTDIR
+ Pop $0
+
+ ; Skip if already downloaded
+ IfFileExists $INSTDIR\$0 0 +2
+ Return
+
+ StrCpy $1 "@CPACK_DOWNLOAD_SITE@"
+
+ try_again:
+ NSISdl::download "$1/$0" "$INSTDIR\$0"
+
+ Pop $1
+ StrCmp $1 "success" success
+ StrCmp $1 "Cancelled" cancel
+ MessageBox MB_OK "Download failed: $1"
+ cancel:
+ Return
+ success:
+FunctionEnd
+!endif
+
+;--------------------------------
+; Define some macro setting for the gui
+@CPACK_NSIS_INSTALLER_MUI_ICON_CODE@
+@CPACK_NSIS_INSTALLER_ICON_CODE@
+@CPACK_NSIS_INSTALLER_MUI_WELCOMEFINISH_CODE@
+@CPACK_NSIS_INSTALLER_MUI_UNWELCOMEFINISH_CODE@
+@CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@
+@CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@
+
+;--------------------------------
+;Pages
+ @CPACK_NSIS_INSTALLER_WELCOME_TITLE_CODE@
+ @CPACK_NSIS_INSTALLER_WELCOME_TITLE_3LINES_CODE@
+ !insertmacro MUI_PAGE_WELCOME
+
+ !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@"
+ Page custom InstallOptionsPage
+ !insertmacro MUI_PAGE_DIRECTORY
+
+ ;Start Menu Folder Page Configuration
+ !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX"
+ !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
+ !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
+ !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER
+
+ @CPACK_NSIS_PAGE_COMPONENTS@
+
+ !insertmacro MUI_PAGE_INSTFILES
+ @CPACK_NSIS_INSTALLER_FINISH_TITLE_CODE@
+ @CPACK_NSIS_INSTALLER_FINISH_TITLE_3LINES_CODE@
+ !insertmacro MUI_PAGE_FINISH
+
+ !insertmacro MUI_UNPAGE_CONFIRM
+ !insertmacro MUI_UNPAGE_INSTFILES
+
+;--------------------------------
+;Languages
+
+ !insertmacro MUI_LANGUAGE "English" ;first language is the default language
+ !insertmacro MUI_LANGUAGE "Albanian"
+ !insertmacro MUI_LANGUAGE "Arabic"
+ !insertmacro MUI_LANGUAGE "Basque"
+ !insertmacro MUI_LANGUAGE "Belarusian"
+ !insertmacro MUI_LANGUAGE "Bosnian"
+ !insertmacro MUI_LANGUAGE "Breton"
+ !insertmacro MUI_LANGUAGE "Bulgarian"
+ !insertmacro MUI_LANGUAGE "Croatian"
+ !insertmacro MUI_LANGUAGE "Czech"
+ !insertmacro MUI_LANGUAGE "Danish"
+ !insertmacro MUI_LANGUAGE "Dutch"
+ !insertmacro MUI_LANGUAGE "Estonian"
+ !insertmacro MUI_LANGUAGE "Farsi"
+ !insertmacro MUI_LANGUAGE "Finnish"
+ !insertmacro MUI_LANGUAGE "French"
+ !insertmacro MUI_LANGUAGE "German"
+ !insertmacro MUI_LANGUAGE "Greek"
+ !insertmacro MUI_LANGUAGE "Hebrew"
+ !insertmacro MUI_LANGUAGE "Hungarian"
+ !insertmacro MUI_LANGUAGE "Icelandic"
+ !insertmacro MUI_LANGUAGE "Indonesian"
+ !insertmacro MUI_LANGUAGE "Irish"
+ !insertmacro MUI_LANGUAGE "Italian"
+ !insertmacro MUI_LANGUAGE "Japanese"
+ !insertmacro MUI_LANGUAGE "Korean"
+ !insertmacro MUI_LANGUAGE "Kurdish"
+ !insertmacro MUI_LANGUAGE "Latvian"
+ !insertmacro MUI_LANGUAGE "Lithuanian"
+ !insertmacro MUI_LANGUAGE "Luxembourgish"
+ !insertmacro MUI_LANGUAGE "Macedonian"
+ !insertmacro MUI_LANGUAGE "Malay"
+ !insertmacro MUI_LANGUAGE "Mongolian"
+ !insertmacro MUI_LANGUAGE "Norwegian"
+ !insertmacro MUI_LANGUAGE "Polish"
+ !insertmacro MUI_LANGUAGE "Portuguese"
+ !insertmacro MUI_LANGUAGE "PortugueseBR"
+ !insertmacro MUI_LANGUAGE "Romanian"
+ !insertmacro MUI_LANGUAGE "Russian"
+ !insertmacro MUI_LANGUAGE "Serbian"
+ !insertmacro MUI_LANGUAGE "SerbianLatin"
+ !insertmacro MUI_LANGUAGE "SimpChinese"
+ !insertmacro MUI_LANGUAGE "Slovak"
+ !insertmacro MUI_LANGUAGE "Slovenian"
+ !insertmacro MUI_LANGUAGE "Spanish"
+ !insertmacro MUI_LANGUAGE "Swedish"
+ !insertmacro MUI_LANGUAGE "Thai"
+ !insertmacro MUI_LANGUAGE "TradChinese"
+ !insertmacro MUI_LANGUAGE "Turkish"
+ !insertmacro MUI_LANGUAGE "Ukrainian"
+ !insertmacro MUI_LANGUAGE "Welsh"
+
+;--------------------------------
+;Reserve Files
+
+ ;These files should be inserted before other files in the data block
+ ;Keep these lines before any File command
+ ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA)
+
+ ReserveFile "NSIS.InstallOptions.ini"
+ !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
+
+ ; for UserInfo::GetName and UserInfo::GetAccountType
+ ReserveFile /plugin 'UserInfo.dll'
+
+;--------------------------------
+; Installation types
+@CPACK_NSIS_INSTALLATION_TYPES@
+
+;--------------------------------
+; Component sections
+@CPACK_NSIS_COMPONENT_SECTIONS@
+
+;--------------------------------
+;Installer Sections
+
+Section "-Core installation"
+ ;Use the entire tree produced by the INSTALL target. Keep the
+ ;list of directories here in sync with the RMDir commands below.
+ SetOutPath "$INSTDIR"
+ @CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@
+ @CPACK_NSIS_FULL_INSTALL@
+
+ ;Store installation folder
+ WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR
+
+ ;Create uninstaller
+ WriteUninstaller "$INSTDIR\@CPACK_NSIS_UNINSTALL_NAME@.exe"
+ Push "DisplayName"
+ Push "@CPACK_NSIS_DISPLAY_NAME@"
+ Call ConditionalAddToRegisty
+ Push "DisplayVersion"
+ Push "@CPACK_PACKAGE_VERSION@"
+ Call ConditionalAddToRegisty
+ Push "Publisher"
+ Push "@CPACK_PACKAGE_VENDOR@"
+ Call ConditionalAddToRegisty
+ Push "UninstallString"
+ Push "$INSTDIR\@CPACK_NSIS_UNINSTALL_NAME@.exe"
+ Call ConditionalAddToRegisty
+ Push "NoRepair"
+ Push "1"
+ Call ConditionalAddToRegisty
+
+ !ifdef CPACK_NSIS_ADD_REMOVE
+ ;Create add/remove functionality
+ Push "ModifyPath"
+ Push "$INSTDIR\AddRemove.exe"
+ Call ConditionalAddToRegisty
+ !else
+ Push "NoModify"
+ Push "1"
+ Call ConditionalAddToRegisty
+ !endif
+
+ ; Optional registration
+ Push "DisplayIcon"
+ Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@"
+ Call ConditionalAddToRegisty
+ Push "HelpLink"
+ Push "@CPACK_NSIS_HELP_LINK@"
+ Call ConditionalAddToRegisty
+ Push "URLInfoAbout"
+ Push "@CPACK_NSIS_URL_INFO_ABOUT@"
+ Call ConditionalAddToRegisty
+ Push "Contact"
+ Push "@CPACK_NSIS_CONTACT@"
+ Call ConditionalAddToRegisty
+ !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State"
+ !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
+
+ ;Create shortcuts
+ CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
+@CPACK_NSIS_CREATE_ICONS@
+@CPACK_NSIS_CREATE_ICONS_EXTRA@
+ CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\@CPACK_NSIS_UNINSTALL_NAME@.exe"
+
+ ;Read a value from an InstallOptions INI file
+ !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State"
+ !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State"
+ !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State"
+
+ ; Write special uninstall registry entries
+ Push "StartMenu"
+ Push "$STARTMENU_FOLDER"
+ Call ConditionalAddToRegisty
+ Push "DoNotAddToPath"
+ Push "$DO_NOT_ADD_TO_PATH"
+ Call ConditionalAddToRegisty
+ Push "AddToPathAllUsers"
+ Push "$ADD_TO_PATH_ALL_USERS"
+ Call ConditionalAddToRegisty
+ Push "AddToPathCurrentUser"
+ Push "$ADD_TO_PATH_CURRENT_USER"
+ Call ConditionalAddToRegisty
+ Push "InstallToDesktop"
+ Push "$INSTALL_DESKTOP"
+ Call ConditionalAddToRegisty
+
+ !insertmacro MUI_STARTMENU_WRITE_END
+
+@CPACK_NSIS_EXTRA_INSTALL_COMMANDS@
+
+SectionEnd
+
+Section "-Add to path"
+ Push $INSTDIR\bin
+ StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath
+ StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0
+ Call AddToPath
+ doNotAddToPath:
+SectionEnd
+
+;--------------------------------
+; Create custom pages
+Function InstallOptionsPage
+ !insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@"
+ !insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini"
+
+FunctionEnd
+
+;--------------------------------
+; determine admin versus local install
+Function un.onInit
+
+ ClearErrors
+ UserInfo::GetName
+ IfErrors noLM
+ Pop $0
+ UserInfo::GetAccountType
+ Pop $1
+ StrCmp $1 "Admin" 0 +3
+ SetShellVarContext all
+ ;MessageBox MB_OK 'User "$0" is in the Admin group'
+ Goto done
+ StrCmp $1 "Power" 0 +3
+ SetShellVarContext all
+ ;MessageBox MB_OK 'User "$0" is in the Power Users group'
+ Goto done
+
+ noLM:
+ ;Get installation folder from registry if available
+
+ done:
+
+FunctionEnd
+
+;--- Add/Remove callback functions: ---
+!macro SectionList MacroName
+ ;This macro used to perform operation on multiple sections.
+ ;List all of your components in following manner here.
+@CPACK_NSIS_COMPONENT_SECTION_LIST@
+!macroend
+
+Section -FinishComponents
+ ;Removes unselected components and writes component status to registry
+ !insertmacro SectionList "FinishSection"
+
+!ifdef CPACK_NSIS_ADD_REMOVE
+ ; Get the name of the installer executable
+ System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1'
+ StrCpy $R3 $R0
+
+ ; Strip off the last 13 characters, to see if we have AddRemove.exe
+ StrLen $R1 $R0
+ IntOp $R1 $R0 - 13
+ StrCpy $R2 $R0 13 $R1
+ StrCmp $R2 "AddRemove.exe" addremove_installed
+
+ ; We're not running AddRemove.exe, so install it
+ CopyFiles $R3 $INSTDIR\AddRemove.exe
+
+ addremove_installed:
+!endif
+SectionEnd
+;--- End of Add/Remove callback functions ---
+
+;--------------------------------
+; Component dependencies
+Function .onSelChange
+ !insertmacro SectionList MaybeSelectionChanged
+FunctionEnd
+
+;--------------------------------
+;Uninstaller Section
+
+Section "Uninstall"
+ ReadRegStr $START_MENU SHCTX \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu"
+ ;MessageBox MB_OK "Start menu is in: $START_MENU"
+ ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "DoNotAddToPath"
+ ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathAllUsers"
+ ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathCurrentUser"
+ ;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS"
+ ReadRegStr $INSTALL_DESKTOP SHCTX \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "InstallToDesktop"
+ ;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP "
+
+@CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@
+
+ ;Remove files we installed.
+ ;Keep the list of directories here in sync with the File commands above.
+@CPACK_NSIS_DELETE_FILES@
+@CPACK_NSIS_DELETE_DIRECTORIES@
+
+!ifdef CPACK_NSIS_ADD_REMOVE
+ ;Remove the add/remove program
+ Delete "$INSTDIR\AddRemove.exe"
+!endif
+
+ ;Remove the uninstaller itself.
+ Delete "$INSTDIR\@CPACK_NSIS_UNINSTALL_NAME@.exe"
+ DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
+
+ ;Remove the installation directory if it is empty.
+ RMDir "$INSTDIR"
+
+ ; Remove the registry entries.
+ DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
+
+ ; Removes all optional components
+ !insertmacro SectionList "RemoveSection_CPack"
+
+ !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
+
+ Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
+@CPACK_NSIS_DELETE_ICONS@
+@CPACK_NSIS_DELETE_ICONS_EXTRA@
+
+ ;Delete empty start menu parent directories
+ StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP"
+
+ startMenuDeleteLoop:
+ ClearErrors
+ RMDir $MUI_TEMP
+ GetFullPathName $MUI_TEMP "$MUI_TEMP\.."
+
+ IfErrors startMenuDeleteLoopDone
+
+ StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop
+ startMenuDeleteLoopDone:
+
+ ; If the user changed the shortcut, then untinstall may not work. This should
+ ; try to fix it.
+ StrCpy $MUI_TEMP "$START_MENU"
+ Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
+@CPACK_NSIS_DELETE_ICONS_EXTRA@
+
+ ;Delete empty start menu parent directories
+ StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP"
+
+ secondStartMenuDeleteLoop:
+ ClearErrors
+ RMDir $MUI_TEMP
+ GetFullPathName $MUI_TEMP "$MUI_TEMP\.."
+
+ IfErrors secondStartMenuDeleteLoopDone
+
+ StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop
+ secondStartMenuDeleteLoopDone:
+
+ DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
+
+ Push $INSTDIR\bin
+ StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0
+ Call un.RemoveFromPath
+ doNotRemoveFromPath:
+SectionEnd
+
+;--------------------------------
+; determine admin versus local install
+; Is install for "AllUsers" or "JustMe"?
+; Default to "JustMe" - set to "AllUsers" if admin or on Win9x
+; This function is used for the very first "custom page" of the installer.
+; This custom page does not show up visibly, but it executes prior to the
+; first visible page and sets up $INSTDIR properly...
+; Choose different default installation folder based on SV_ALLUSERS...
+; "Program Files" for AllUsers, "My Documents" for JustMe...
+
+Function .onInit
+ StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst
+
+ ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString"
+ StrCmp $0 "" inst
+
+ MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \
+ "@CPACK_NSIS_PACKAGE_NAME@ is already installed. $\n$\nDo you want to uninstall the old version before installing the new one?" \
+ /SD IDYES IDYES uninst IDNO inst
+ Abort
+
+;Run the uninstaller
+uninst:
+ ClearErrors
+ StrLen $2 "\Uninstall.exe"
+ StrCpy $3 $0 -$2 # remove "\Uninstall.exe" from UninstallString to get path
+ ExecWait '"$0" /S _?=$3' ;Do not copy the uninstaller to a temp file
+
+ IfErrors uninst_failed inst
+uninst_failed:
+ MessageBox MB_OK|MB_ICONSTOP "Uninstall failed."
+ Abort
+
+
+inst:
+ ; Reads components status for registry
+ !insertmacro SectionList "InitSection"
+
+ ; check to see if /D has been used to change
+ ; the install directory by comparing it to the
+ ; install directory that is expected to be the
+ ; default
+ StrCpy $IS_DEFAULT_INSTALLDIR 0
+ StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2
+ StrCpy $IS_DEFAULT_INSTALLDIR 1
+
+ StrCpy $SV_ALLUSERS "JustMe"
+ ; if default install dir then change the default
+ ; if it is installed for JustMe
+ StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2
+ StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
+
+ ClearErrors
+ UserInfo::GetName
+ IfErrors noLM
+ Pop $0
+ UserInfo::GetAccountType
+ Pop $1
+ StrCmp $1 "Admin" 0 +4
+ SetShellVarContext all
+ ;MessageBox MB_OK 'User "$0" is in the Admin group'
+ StrCpy $SV_ALLUSERS "AllUsers"
+ Goto done
+ StrCmp $1 "Power" 0 +4
+ SetShellVarContext all
+ ;MessageBox MB_OK 'User "$0" is in the Power Users group'
+ StrCpy $SV_ALLUSERS "AllUsers"
+ Goto done
+
+ noLM:
+ StrCpy $SV_ALLUSERS "AllUsers"
+ ;Get installation folder from registry if available
+
+ done:
+ StrCmp $SV_ALLUSERS "AllUsers" 0 +3
+ StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2
+ StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
+
+ StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage
+ !insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini"
+
+ noOptionsPage:
+FunctionEnd
diff --git a/Modules/Internal/CPack/WIX.template.in b/Modules/Internal/CPack/WIX.template.in
new file mode 100644
index 0000000..c0bf935
--- /dev/null
+++ b/Modules/Internal/CPack/WIX.template.in
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?include "cpack_variables.wxi"?>
+
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" @CPACK_WIX_CUSTOM_XMLNS_EXPANDED@
+ RequiredVersion="3.6.3303.0">
+
+ <Product Id="$(var.CPACK_WIX_PRODUCT_GUID)"
+ Name="$(var.CPACK_PACKAGE_NAME)"
+ Language="1033"
+ Version="$(var.CPACK_PACKAGE_VERSION)"
+ Manufacturer="$(var.CPACK_PACKAGE_VENDOR)"
+ UpgradeCode="$(var.CPACK_WIX_UPGRADE_GUID)">
+
+ <Package InstallerVersion="301" Compressed="yes"/>
+
+ <Media Id="1" Cabinet="media1.cab" EmbedCab="yes"/>
+
+ <MajorUpgrade
+ Schedule="afterInstallInitialize"
+ AllowSameVersionUpgrades="yes"
+ DowngradeErrorMessage="A later version of [ProductName] is already installed. Setup will now exit."/>
+
+ <WixVariable Id="WixUILicenseRtf" Value="$(var.CPACK_WIX_LICENSE_RTF)"/>
+ <Property Id="WIXUI_INSTALLDIR" Value="INSTALL_ROOT"/>
+
+ <?ifdef CPACK_WIX_PRODUCT_ICON?>
+ <Property Id="ARPPRODUCTICON">ProductIcon.ico</Property>
+ <Icon Id="ProductIcon.ico" SourceFile="$(var.CPACK_WIX_PRODUCT_ICON)"/>
+ <?endif?>
+
+ <?ifdef CPACK_WIX_UI_BANNER?>
+ <WixVariable Id="WixUIBannerBmp" Value="$(var.CPACK_WIX_UI_BANNER)"/>
+ <?endif?>
+
+ <?ifdef CPACK_WIX_UI_DIALOG?>
+ <WixVariable Id="WixUIDialogBmp" Value="$(var.CPACK_WIX_UI_DIALOG)"/>
+ <?endif?>
+
+ <FeatureRef Id="ProductFeature"/>
+
+ <UIRef Id="$(var.CPACK_WIX_UI_REF)" />
+
+ <?include "properties.wxi"?>
+ <?include "product_fragment.wxi"?>
+ </Product>
+</Wix>
diff --git a/Modules/Internal/CheckCompilerFlag.cmake b/Modules/Internal/CheckCompilerFlag.cmake
new file mode 100644
index 0000000..6b2a11e
--- /dev/null
+++ b/Modules/Internal/CheckCompilerFlag.cmake
@@ -0,0 +1,79 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include_guard(GLOBAL)
+include(Internal/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(CMAKE_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 "CUDA")
+ set(_lang_src "__host__ int main() { return 0; }")
+ set(_lang_fail_regex FAIL_REGEX "command[ -]line option .* is valid for .* but not for C\\+\\+" # Host GNU
+ FAIL_REGEX "argument unused during compilation: .*") # Clang
+ 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
+ elseif(_lang STREQUAL "ISPC")
+ set(_lang_src "float func(uniform int32, float a) { return a / 2.25; }")
+ 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)
+ cmake_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/Internal/CheckSourceCompiles.cmake b/Modules/Internal/CheckSourceCompiles.cmake
new file mode 100644
index 0000000..3b2152a
--- /dev/null
+++ b/Modules/Internal/CheckSourceCompiles.cmake
@@ -0,0 +1,127 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include_guard(GLOBAL)
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
+cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST
+
+function(CMAKE_CHECK_SOURCE_COMPILES _lang _source _var)
+ if(NOT DEFINED "${_var}")
+
+ if(_lang STREQUAL "C")
+ set(_lang_textual "C")
+ set(_lang_ext "c")
+ elseif(_lang STREQUAL "CXX")
+ set(_lang_textual "C++")
+ set(_lang_ext "cxx")
+ elseif(_lang STREQUAL "CUDA")
+ set(_lang_textual "CUDA")
+ set(_lang_ext "cu")
+ elseif(_lang STREQUAL "Fortran")
+ set(_lang_textual "Fortran")
+ set(_lang_ext "F90")
+ elseif(_lang STREQUAL "ISPC")
+ set(_lang_textual "ISPC")
+ set(_lang_ext "ispc")
+ elseif(_lang STREQUAL "OBJC")
+ set(_lang_textual "Objective-C")
+ set(_lang_ext "m")
+ elseif(_lang STREQUAL "OBJCXX")
+ set(_lang_textual "Objective-C++")
+ set(_lang_ext "mm")
+ else()
+ message (SEND_ERROR "check_source_compiles: ${_lang}: unknown language.")
+ return()
+ endif()
+
+ get_property (_supported_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
+ if (NOT _lang IN_LIST _supported_languages)
+ message (SEND_ERROR "check_source_compiles: ${_lang}: needs to be enabled before use.")
+ return()
+ endif()
+
+ set(_FAIL_REGEX)
+ set(_SRC_EXT)
+ set(_key)
+ foreach(arg ${ARGN})
+ if("${arg}" MATCHES "^(FAIL_REGEX|SRC_EXT)$")
+ set(_key "${arg}")
+ elseif(_key STREQUAL "FAIL_REGEX")
+ list(APPEND _FAIL_REGEX "${arg}")
+ elseif(_key STREQUAL "SRC_EXT")
+ set(_SRC_EXT "${arg}")
+ set(_key "")
+ else()
+ message(FATAL_ERROR "Unknown argument:\n ${arg}\n")
+ endif()
+ endforeach()
+
+ if(NOT _SRC_EXT)
+ set(_SRC_EXT ${_lang_ext})
+ endif()
+
+ if(CMAKE_REQUIRED_LINK_OPTIONS)
+ set(CHECK_${LANG}_SOURCE_COMPILES_ADD_LINK_OPTIONS
+ LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
+ else()
+ set(CHECK_${LANG}_SOURCE_COMPILES_ADD_LINK_OPTIONS)
+ endif()
+ if(CMAKE_REQUIRED_LIBRARIES)
+ set(CHECK_${LANG}_SOURCE_COMPILES_ADD_LIBRARIES
+ LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
+ else()
+ set(CHECK_${LANG}_SOURCE_COMPILES_ADD_LIBRARIES)
+ endif()
+ if(CMAKE_REQUIRED_INCLUDES)
+ set(CHECK_${LANG}_SOURCE_COMPILES_ADD_INCLUDES
+ "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+ else()
+ set(CHECK_${LANG}_SOURCE_COMPILES_ADD_INCLUDES)
+ endif()
+ file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.${_SRC_EXT}"
+ "${_source}\n")
+
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_START "Performing Test ${_var}")
+ endif()
+ try_compile(${_var}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.${_SRC_EXT}
+ COMPILE_DEFINITIONS -D${_var} ${CMAKE_REQUIRED_DEFINITIONS}
+ ${CHECK_${LANG}_SOURCE_COMPILES_ADD_LINK_OPTIONS}
+ ${CHECK_${LANG}_SOURCE_COMPILES_ADD_LIBRARIES}
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${CMAKE_REQUIRED_FLAGS}
+ "${CHECK_${LANG}_SOURCE_COMPILES_ADD_INCLUDES}"
+ OUTPUT_VARIABLE OUTPUT)
+
+ foreach(_regex ${_FAIL_REGEX})
+ if("${OUTPUT}" MATCHES "${_regex}")
+ set(${_var} 0)
+ endif()
+ endforeach()
+
+ if(${_var})
+ set(${_var} 1 CACHE INTERNAL "Test ${_var}")
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_PASS "Success")
+ endif()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Performing ${_lang_textual} SOURCE FILE Test ${_var} succeeded with the following output:\n"
+ "${OUTPUT}\n"
+ "Source file was:\n${_source}\n")
+ else()
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_FAIL "Failed")
+ endif()
+ set(${_var} "" CACHE INTERNAL "Test ${_var}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Performing ${_lang_textual} SOURCE FILE Test ${_var} failed with the following output:\n"
+ "${OUTPUT}\n"
+ "Source file was:\n${_source}\n")
+ endif()
+ endif()
+endfunction()
+
+cmake_policy(POP)
diff --git a/Modules/Internal/CheckSourceRuns.cmake b/Modules/Internal/CheckSourceRuns.cmake
new file mode 100644
index 0000000..676f3d0
--- /dev/null
+++ b/Modules/Internal/CheckSourceRuns.cmake
@@ -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_guard(GLOBAL)
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
+cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST
+
+function(CMAKE_CHECK_SOURCE_RUNS _lang _source _var)
+ if(NOT DEFINED "${_var}")
+
+ if(_lang STREQUAL "C")
+ set(_lang_textual "C")
+ set(_lang_ext "c")
+ elseif(_lang STREQUAL "CXX")
+ set(_lang_textual "C++")
+ set(_lang_ext "cxx")
+ elseif(_lang STREQUAL "CUDA")
+ set(_lang_textual "CUDA")
+ set(_lang_ext "cu")
+ elseif(_lang STREQUAL "Fortran")
+ set(_lang_textual "Fortran")
+ set(_lang_ext "F90")
+ elseif(_lang STREQUAL "OBJC")
+ set(_lang_textual "Objective-C")
+ set(_lang_ext "m")
+ elseif(_lang STREQUAL "OBJCXX")
+ set(_lang_textual "Objective-C++")
+ set(_lang_ext "mm")
+ else()
+ message (SEND_ERROR "check_source_runs: ${_lang}: unknown language.")
+ return()
+ endif()
+
+ get_property (_supported_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
+ if (NOT _lang IN_LIST _supported_languages)
+ message (SEND_ERROR "check_source_runs: ${_lang}: needs to be enabled before use.")
+ return()
+ endif()
+
+ set(_FAIL_REGEX)
+ set(_SRC_EXT)
+ set(_key)
+ foreach(arg ${ARGN})
+ if("${arg}" MATCHES "^(FAIL_REGEX|SRC_EXT)$")
+ set(_key "${arg}")
+ elseif(_key STREQUAL "FAIL_REGEX")
+ list(APPEND _FAIL_REGEX "${arg}")
+ elseif(_key STREQUAL "SRC_EXT")
+ set(_SRC_EXT "${arg}")
+ set(_key "")
+ else()
+ set(message_type FATAL_ERROR)
+ if (_CheckSourceRuns_old_signature)
+ set(message_type AUTHOR_WARNING)
+ endif ()
+ message("${message_type}" "Unknown argument:\n ${arg}\n")
+ unset(message_type)
+ endif()
+ endforeach()
+
+ if(NOT _SRC_EXT)
+ set(_SRC_EXT ${_lang_ext})
+ endif()
+
+ if(CMAKE_REQUIRED_LINK_OPTIONS)
+ set(CHECK_${_lang}_SOURCE_COMPILES_ADD_LINK_OPTIONS
+ LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
+ else()
+ set(CHECK_${_lang}_SOURCE_COMPILES_ADD_LINK_OPTIONS)
+ endif()
+ if(CMAKE_REQUIRED_LIBRARIES)
+ set(CHECK_${_lang}_SOURCE_COMPILES_ADD_LIBRARIES
+ LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
+ else()
+ set(CHECK_${_lang}_SOURCE_COMPILES_ADD_LIBRARIES)
+ endif()
+ if(CMAKE_REQUIRED_INCLUDES)
+ set(CHECK_${_lang}_SOURCE_COMPILES_ADD_INCLUDES
+ "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+ else()
+ set(CHECK_${_lang}_SOURCE_COMPILES_ADD_INCLUDES)
+ endif()
+ file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.${_SRC_EXT}"
+ "${_source}\n")
+
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_START "Performing Test ${_var}")
+ endif()
+ try_run(${_var}_EXITCODE ${_var}_COMPILED
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.${_SRC_EXT}
+ COMPILE_DEFINITIONS -D${_var} ${CMAKE_REQUIRED_DEFINITIONS}
+ ${CHECK_${_lang}_SOURCE_COMPILES_ADD_LINK_OPTIONS}
+ ${CHECK_${_lang}_SOURCE_COMPILES_ADD_LIBRARIES}
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${CMAKE_REQUIRED_FLAGS}
+ -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH}
+ "${CHECK_${_lang}_SOURCE_COMPILES_ADD_INCLUDES}"
+ COMPILE_OUTPUT_VARIABLE OUTPUT
+ RUN_OUTPUT_VARIABLE RUN_OUTPUT)
+ # if it did not compile make the return value fail code of 1
+ if(NOT ${_var}_COMPILED)
+ set(${_var}_EXITCODE 1)
+ set(${_var}_EXITCODE 1 PARENT_SCOPE)
+ endif()
+ # if the return value was 0 then it worked
+ if("${${_var}_EXITCODE}" EQUAL 0)
+ set(${_var} 1 CACHE INTERNAL "Test ${_var}")
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_PASS "Success")
+ endif()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Performing ${_lang_textual} SOURCE FILE Test ${_var} succeeded with the following compile output:\n"
+ "${OUTPUT}\n"
+ "...and run output:\n"
+ "${RUN_OUTPUT}\n"
+ "Return value: ${${_var}}\n"
+ "Source file was:\n${_source}\n")
+ else()
+ if(CMAKE_CROSSCOMPILING AND "${${_var}_EXITCODE}" MATCHES "FAILED_TO_RUN")
+ set(${_var} "${${_var}_EXITCODE}" PARENT_SCOPE)
+ else()
+ set(${_var} "" CACHE INTERNAL "Test ${_var}")
+ endif()
+
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(CHECK_FAIL "Failed")
+ endif()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Performing ${_lang_textual} SOURCE FILE Test ${_var} failed with the following compile output:\n"
+ "${OUTPUT}\n"
+ "...and run output:\n"
+ "${RUN_OUTPUT}\n"
+ "Return value: ${${_var}_EXITCODE}\n"
+ "Source file was:\n${_source}\n")
+
+ endif()
+ endif()
+endfunction()
+
+cmake_policy(POP)
diff --git a/Modules/Internal/FeatureTesting.cmake b/Modules/Internal/FeatureTesting.cmake
new file mode 100644
index 0000000..72d96b3
--- /dev/null
+++ b/Modules/Internal/FeatureTesting.cmake
@@ -0,0 +1,119 @@
+
+macro(_record_compiler_features lang compile_flags feature_list)
+ include("${CMAKE_ROOT}/Modules/Compiler/${CMAKE_${lang}_COMPILER_ID}-${lang}-FeatureTests.cmake" OPTIONAL)
+
+ string(TOLOWER ${lang} lang_lc)
+ file(REMOVE "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.bin")
+ file(WRITE "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.${lang_lc}" "
+ const char features[] = {\"\\n\"\n")
+
+ get_property(known_features GLOBAL PROPERTY CMAKE_${lang}_KNOWN_FEATURES)
+
+ foreach(feature ${known_features})
+ if (_cmake_feature_test_${feature})
+ if (${_cmake_feature_test_${feature}} STREQUAL 1)
+ set(_feature_condition "\"1\" ")
+ else()
+ set(_feature_condition "#if ${_cmake_feature_test_${feature}}\n\"1\"\n#else\n\"0\"\n#endif\n")
+ endif()
+ file(APPEND "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.${lang_lc}" "\"${lang}_FEATURE:\"\n${_feature_condition}\"${feature}\\n\"\n")
+ endif()
+ endforeach()
+ file(APPEND "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.${lang_lc}"
+ "\n};\n\nint main(int argc, char** argv) { (void)argv; return features[argc]; }\n")
+
+ if(CMAKE_${lang}_LINK_WITH_STANDARD_COMPILE_OPTION)
+ # This toolchain requires use of the language standard flag
+ # when linking in order to use the matching standard library.
+ set(compile_flags_for_link "${compile_flags}")
+ else()
+ set(compile_flags_for_link "")
+ endif()
+
+ try_compile(CMAKE_${lang}_FEATURE_TEST
+ ${CMAKE_BINARY_DIR} "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.${lang_lc}"
+ COMPILE_DEFINITIONS "${compile_flags}"
+ LINK_LIBRARIES "${compile_flags_for_link}"
+ OUTPUT_VARIABLE _output
+ COPY_FILE "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.bin"
+ COPY_FILE_ERROR _copy_error
+ )
+ if(CMAKE_${lang}_FEATURE_TEST AND NOT _copy_error)
+ set(_result 0)
+ else()
+ set(_result 255)
+ endif()
+ unset(CMAKE_${lang}_FEATURE_TEST CACHE)
+ unset(compile_flags_for_link)
+
+ if (_result EQUAL 0)
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "\n\nDetecting ${lang} [${compile_flags}] compiler features compiled with the following output:\n${_output}\n\n")
+ if(EXISTS "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.bin")
+ file(STRINGS "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.bin"
+ features REGEX "${lang}_FEATURE:.*")
+ foreach(info ${features})
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ " Feature record: ${info}\n")
+ string(REPLACE "${lang}_FEATURE:" "" info ${info})
+ string(SUBSTRING ${info} 0 1 has_feature)
+ if(has_feature)
+ string(REGEX REPLACE "^1" "" feature ${info})
+ list(APPEND ${feature_list} ${feature})
+ endif()
+ endforeach()
+ endif()
+ else()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Detecting ${lang} [${compile_flags}] compiler features failed to compile with the following output:\n${_output}\n${_copy_error}\n\n")
+ endif()
+endmacro()
+
+macro(_record_compiler_features_c std)
+ list(APPEND CMAKE_C${std}_COMPILE_FEATURES c_std_${std})
+
+ get_property(lang_level_has_features GLOBAL PROPERTY CMAKE_C${std}_KNOWN_FEATURES)
+ if(lang_level_has_features)
+ _record_compiler_features(C "${CMAKE_C${std}_STANDARD_COMPILE_OPTION}" CMAKE_C${std}_COMPILE_FEATURES)
+ endif()
+ unset(lang_level_has_features)
+endmacro()
+
+macro(_record_compiler_features_cxx std)
+ list(APPEND CMAKE_CXX${std}_COMPILE_FEATURES cxx_std_${std})
+
+ get_property(lang_level_has_features GLOBAL PROPERTY CMAKE_CXX${std}_KNOWN_FEATURES)
+ if(lang_level_has_features)
+ _record_compiler_features(CXX "${CMAKE_CXX${std}_STANDARD_COMPILE_OPTION}" CMAKE_CXX${std}_COMPILE_FEATURES)
+ endif()
+ unset(lang_level_has_features)
+endmacro()
+
+macro(_record_compiler_features_cuda std)
+ list(APPEND CMAKE_CUDA${std}_COMPILE_FEATURES cuda_std_${std})
+
+ get_property(lang_level_has_features GLOBAL PROPERTY CMAKE_CUDA${std}_KNOWN_FEATURES)
+ if(lang_level_has_features)
+ _record_compiler_features(CUDA "${CMAKE_CUDA${std}_STANDARD_COMPILE_OPTION}" CMAKE_CUDA${std}_COMPILE_FEATURES)
+ endif()
+ unset(lang_level_has_features)
+endmacro()
+
+macro(_has_compiler_features lang level compile_flags feature_list)
+ # presume all known features are supported
+ get_property(known_features GLOBAL PROPERTY CMAKE_${lang}${level}_KNOWN_FEATURES)
+ list(APPEND ${feature_list} ${known_features})
+endmacro()
+
+macro(_has_compiler_features_c std)
+ list(APPEND CMAKE_C${std}_COMPILE_FEATURES c_std_${std})
+ _has_compiler_features(C ${std} "${CMAKE_C${std}_STANDARD_COMPILE_OPTION}" CMAKE_C${std}_COMPILE_FEATURES)
+endmacro()
+macro(_has_compiler_features_cxx std)
+ list(APPEND CMAKE_CXX${std}_COMPILE_FEATURES cxx_std_${std})
+ _has_compiler_features(CXX ${std} "${CMAKE_CXX${std}_STANDARD_COMPILE_OPTION}" CMAKE_CXX${std}_COMPILE_FEATURES)
+endmacro()
+macro(_has_compiler_features_cuda std)
+ list(APPEND CMAKE_CUDA${std}_COMPILE_FEATURES cuda_std_${std})
+ _has_compiler_features(CUDA ${std} "${CMAKE_CUDA${std}_STANDARD_COMPILE_OPTION}" CMAKE_CUDA${std}_COMPILE_FEATURES)
+endmacro()
diff --git a/Modules/KDE3Macros.cmake b/Modules/KDE3Macros.cmake
new file mode 100644
index 0000000..1c353ba
--- /dev/null
+++ b/Modules/KDE3Macros.cmake
@@ -0,0 +1,400 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#
+
+# See FindKDE3.cmake for documentation.
+#
+# this file contains the following macros:
+# KDE3_ADD_DCOP_SKELS
+# KDE3_ADD_DCOP_STUBS
+# KDE3_ADD_MOC_FILES
+# KDE3_ADD_UI_FILES
+# KDE3_ADD_KCFG_FILES
+# KDE3_AUTOMOC
+# KDE3_INSTALL_LIBTOOL_FILE
+# KDE3_CREATE_FINAL_FILE
+# KDE3_ADD_KPART
+# KDE3_ADD_KDEINIT_EXECUTABLE
+# KDE3_ADD_EXECUTABLE
+
+
+#neundorf@kde.org
+
+include(AddFileDependencies)
+
+#create the kidl and skeletion file for dcop stuff
+#usage: KDE_ADD_COP_SKELS(foo_SRCS ${dcop_headers})
+macro(KDE3_ADD_DCOP_SKELS _sources)
+ foreach (_current_FILE ${ARGN})
+
+ get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
+ get_filename_component(_basename ${_tmp_FILE} NAME_WE)
+
+ set(_skel ${CMAKE_CURRENT_BINARY_DIR}/${_basename}_skel.cpp)
+ set(_kidl ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.kidl)
+
+ if (NOT HAVE_${_basename}_KIDL_RULE)
+ set(HAVE_${_basename}_KIDL_RULE ON)
+
+ add_custom_command(OUTPUT ${_kidl}
+ COMMAND ${KDE3_DCOPIDL_EXECUTABLE}
+ ARGS ${_tmp_FILE} > ${_kidl}
+ DEPENDS ${_tmp_FILE}
+ )
+
+ endif ()
+
+ if (NOT HAVE_${_basename}_SKEL_RULE)
+ set(HAVE_${_basename}_SKEL_RULE ON)
+
+ add_custom_command(OUTPUT ${_skel}
+ COMMAND ${KDE3_DCOPIDL2CPP_EXECUTABLE}
+ ARGS --c++-suffix cpp --no-signals --no-stub ${_kidl}
+ DEPENDS ${_kidl}
+ )
+
+ endif ()
+
+ set(${_sources} ${${_sources}} ${_skel})
+
+ endforeach ()
+
+endmacro()
+
+
+macro(KDE3_ADD_DCOP_STUBS _sources)
+ foreach (_current_FILE ${ARGN})
+
+ get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
+
+ get_filename_component(_basename ${_tmp_FILE} NAME_WE)
+
+ set(_stub_CPP ${CMAKE_CURRENT_BINARY_DIR}/${_basename}_stub.cpp)
+ set(_kidl ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.kidl)
+
+ if (NOT HAVE_${_basename}_KIDL_RULE)
+ set(HAVE_${_basename}_KIDL_RULE ON)
+
+
+ add_custom_command(OUTPUT ${_kidl}
+ COMMAND ${KDE3_DCOPIDL_EXECUTABLE}
+ ARGS ${_tmp_FILE} > ${_kidl}
+ DEPENDS ${_tmp_FILE}
+ )
+
+ endif ()
+
+
+ if (NOT HAVE_${_basename}_STUB_RULE)
+ set(HAVE_${_basename}_STUB_RULE ON)
+
+ add_custom_command(OUTPUT ${_stub_CPP}
+ COMMAND ${KDE3_DCOPIDL2CPP_EXECUTABLE}
+ ARGS --c++-suffix cpp --no-signals --no-skel ${_kidl}
+ DEPENDS ${_kidl}
+ )
+
+ endif ()
+
+ set(${_sources} ${${_sources}} ${_stub_CPP})
+
+ endforeach ()
+
+endmacro()
+
+
+macro(KDE3_ADD_KCFG_FILES _sources)
+ foreach (_current_FILE ${ARGN})
+
+ get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
+
+ get_filename_component(_basename ${_tmp_FILE} NAME_WE)
+
+ file(READ ${_tmp_FILE} _contents)
+ string(REGEX REPLACE "^(.*\n)?File=([^\n]+)\n.*$" "\\2" _kcfg_FILE "${_contents}")
+
+ set(_src_FILE ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.cpp)
+ set(_header_FILE ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.h)
+
+ add_custom_command(OUTPUT ${_src_FILE}
+ COMMAND ${KDE3_KCFGC_EXECUTABLE}
+ ARGS ${CMAKE_CURRENT_SOURCE_DIR}/${_kcfg_FILE} ${_tmp_FILE}
+ DEPENDS ${_tmp_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/${_kcfg_FILE}
+ )
+
+ set(${_sources} ${${_sources}} ${_src_FILE})
+
+ endforeach ()
+
+endmacro()
+
+
+#create the moc files and add them to the list of sources
+#usage: KDE_ADD_MOC_FILES(foo_SRCS ${moc_headers})
+macro(KDE3_ADD_MOC_FILES _sources)
+ foreach (_current_FILE ${ARGN})
+
+ get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
+
+ get_filename_component(_basename ${_tmp_FILE} NAME_WE)
+ set(_moc ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.moc.cpp)
+
+ add_custom_command(OUTPUT ${_moc}
+ COMMAND ${QT_MOC_EXECUTABLE}
+ ARGS ${_tmp_FILE} -o ${_moc}
+ DEPENDS ${_tmp_FILE}
+ )
+
+ set(${_sources} ${${_sources}} ${_moc})
+
+ endforeach ()
+endmacro()
+
+
+get_filename_component( KDE3_MODULE_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
+
+#create the implementation files from the ui files and add them to the list of sources
+#usage: KDE_ADD_UI_FILES(foo_SRCS ${ui_files})
+macro(KDE3_ADD_UI_FILES _sources )
+ foreach (_current_FILE ${ARGN})
+
+ get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE)
+
+ get_filename_component(_basename ${_tmp_FILE} NAME_WE)
+ set(_header ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.h)
+ set(_src ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.cpp)
+ set(_moc ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.moc.cpp)
+
+ add_custom_command(OUTPUT ${_header}
+ COMMAND ${QT_UIC_EXECUTABLE}
+ ARGS -L ${KDE3_LIB_DIR}/kde3/plugins/designer -nounload -o ${_header} ${CMAKE_CURRENT_SOURCE_DIR}/${_current_FILE}
+ DEPENDS ${_tmp_FILE}
+ )
+
+ add_custom_command(OUTPUT ${_src}
+ COMMAND ${CMAKE_COMMAND}
+ ARGS
+ -DKDE_UIC_PLUGIN_DIR:FILEPATH=${KDE3_LIB_DIR}/kde3/plugins/designer
+ -DKDE_UIC_EXECUTABLE:FILEPATH=${QT_UIC_EXECUTABLE}
+ -DKDE_UIC_FILE:FILEPATH=${_tmp_FILE}
+ -DKDE_UIC_CPP_FILE:FILEPATH=${_src}
+ -DKDE_UIC_H_FILE:FILEPATH=${_header}
+ -P ${KDE3_MODULE_DIR}/kde3uic.cmake
+ DEPENDS ${_header}
+ )
+
+ add_custom_command(OUTPUT ${_moc}
+ COMMAND ${QT_MOC_EXECUTABLE}
+ ARGS ${_header} -o ${_moc}
+ DEPENDS ${_header}
+ )
+
+ set(${_sources} ${${_sources}} ${_src} ${_moc} )
+
+ endforeach ()
+endmacro()
+
+
+macro(KDE3_AUTOMOC)
+ set(_matching_FILES )
+ foreach (_current_FILE ${ARGN})
+
+ get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE)
+
+ # if "SKIP_AUTOMOC" is set to true, we will not handle this file here.
+ # here. this is required to make bouic work correctly:
+ # we need to add generated .cpp files to the sources (to compile them),
+ # but we cannot let automoc handle them, as the .cpp files don't exist yet when
+ # cmake is run for the very first time on them -> however the .cpp files might
+ # exist at a later run. at that time we need to skip them, so that we don't add two
+ # different rules for the same moc file
+ get_source_file_property(_skip ${_abs_FILE} SKIP_AUTOMOC)
+
+ if (EXISTS ${_abs_FILE} AND NOT _skip)
+
+ file(STRINGS ${_abs_FILE} _match REGEX "#include +[^ ]+\\.moc[\">]")
+
+ get_filename_component(_abs_PATH ${_abs_FILE} PATH)
+
+ foreach (_current_MOC_INC IN LISTS _match)
+ string(REGEX MATCH "[^ <\"]+\\.moc" _current_MOC "${_current_MOC_INC}")
+
+ get_filename_component(_basename ${_current_MOC} NAME_WE)
+# set(_header ${CMAKE_CURRENT_SOURCE_DIR}/${_basename}.h)
+ set(_header ${_abs_PATH}/${_basename}.h)
+ set(_moc ${CMAKE_CURRENT_BINARY_DIR}/${_current_MOC})
+
+ add_custom_command(OUTPUT ${_moc}
+ COMMAND ${QT_MOC_EXECUTABLE}
+ ARGS ${_header} -o ${_moc}
+ DEPENDS ${_header}
+ )
+
+ ADD_FILE_DEPENDENCIES(${_abs_FILE} ${_moc})
+
+ endforeach ()
+ unset(_match)
+ unset(_header)
+ unset(_moc)
+ endif ()
+ endforeach ()
+endmacro()
+
+# only used internally by KDE3_INSTALL_ICONS
+macro (_KDE3_ADD_ICON_INSTALL_RULE _install_SCRIPT _install_PATH _group _orig_NAME _install_NAME)
+
+ # if the string doesn't match the pattern, the result is the full string, so all three have the same content
+ if (NOT ${_group} STREQUAL ${_install_NAME} )
+ set(_icon_GROUP "actions")
+
+ if (${_group} STREQUAL "mime")
+ set(_icon_GROUP "mimetypes")
+ endif ()
+
+ if (${_group} STREQUAL "filesys")
+ set(_icon_GROUP "filesystems")
+ endif ()
+
+ if (${_group} STREQUAL "device")
+ set(_icon_GROUP "devices")
+ endif ()
+
+ if (${_group} STREQUAL "app")
+ set(_icon_GROUP "apps")
+ endif ()
+
+ if (${_group} STREQUAL "action")
+ set(_icon_GROUP "actions")
+ endif ()
+
+ # message(STATUS "icon: ${_current_ICON} size: ${_size} group: ${_group} name: ${_name}" )
+ install(FILES ${_orig_NAME} DESTINATION ${_install_PATH}/${_icon_GROUP}/ RENAME ${_install_NAME} )
+ endif ()
+
+endmacro ()
+
+
+macro (KDE3_INSTALL_ICONS _theme )
+ set(_defaultpath "${CMAKE_INSTALL_PREFIX}/share/icons")
+ # first the png icons
+ file(GLOB _icons *.png)
+ foreach (_current_ICON ${_icons} )
+ string(REGEX REPLACE "^.*/[a-zA-Z]+([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\1" _size "${_current_ICON}")
+ string(REGEX REPLACE "^.*/[a-zA-Z]+([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\2" _group "${_current_ICON}")
+ string(REGEX REPLACE "^.*/[a-zA-Z]+([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\3" _name "${_current_ICON}")
+ _KDE3_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake
+ ${_defaultpath}/${_theme}/${_size}x${_size}
+ ${_group} ${_current_ICON} ${_name})
+ endforeach ()
+
+ # and now the svg icons
+ file(GLOB _icons *.svgz)
+ foreach (_current_ICON ${_icons} )
+ string(REGEX REPLACE "^.*/crsc\\-([a-z]+)\\-(.+\\.svgz)$" "\\1" _group "${_current_ICON}")
+ string(REGEX REPLACE "^.*/crsc\\-([a-z]+)\\-(.+\\.svgz)$" "\\2" _name "${_current_ICON}")
+ _KDE3_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake
+ ${_defaultpath}/${_theme}/scalable
+ ${_group} ${_current_ICON} ${_name})
+ endforeach ()
+
+endmacro ()
+
+macro(KDE3_INSTALL_LIBTOOL_FILE _target)
+ get_target_property(_target_location ${_target} LOCATION)
+
+ get_filename_component(_laname ${_target_location} NAME_WE)
+ get_filename_component(_soname ${_target_location} NAME)
+ set(_laname ${CMAKE_CURRENT_BINARY_DIR}/${_laname}.la)
+
+ file(WRITE ${_laname} "# ${_laname} - a libtool library file, generated by cmake \n")
+ file(APPEND ${_laname} "# The name that we can dlopen(3).\n")
+ file(APPEND ${_laname} "dlname='${_soname}'\n")
+ file(APPEND ${_laname} "# Names of this library\n")
+ if(CYGWIN)
+ file(APPEND ${_laname} "library_names='${_soname}'\n")
+ else()
+ file(APPEND ${_laname} "library_names='${_soname} ${_soname} ${_soname}'\n")
+ endif()
+ file(APPEND ${_laname} "# The name of the static archive\n")
+ file(APPEND ${_laname} "old_library=''\n")
+ file(APPEND ${_laname} "# Libraries that this one depends upon.\n")
+ file(APPEND ${_laname} "dependency_libs=''\n")
+# file(APPEND ${_laname} "dependency_libs='${${_target}_LIB_DEPENDS}'\n")
+ file(APPEND ${_laname} "# Version information.\ncurrent=0\nage=0\nrevision=0\n")
+ file(APPEND ${_laname} "# Is this an already installed library?\ninstalled=yes\n")
+ file(APPEND ${_laname} "# Should we warn about portability when linking against -modules?\nshouldnotlink=yes\n")
+ file(APPEND ${_laname} "# Files to dlopen/dlpreopen\ndlopen=''\ndlpreopen=''\n")
+ file(APPEND ${_laname} "# Directory that this library needs to be installed in:\n")
+ file(APPEND ${_laname} "libdir='${CMAKE_INSTALL_PREFIX}/lib/kde3'\n")
+
+ install_files(${KDE3_LIBTOOL_DIR} FILES ${_laname})
+endmacro()
+
+
+macro(KDE3_CREATE_FINAL_FILE _filename)
+ file(WRITE ${_filename} "//autogenerated file\n")
+ foreach (_current_FILE ${ARGN})
+ file(APPEND ${_filename} "#include \"${_current_FILE}\"\n")
+ endforeach ()
+
+endmacro()
+
+
+# option(KDE3_ENABLE_FINAL "Enable final all-in-one compilation")
+option(KDE3_BUILD_TESTS "Build the tests")
+
+
+macro(KDE3_ADD_KPART _target_NAME _with_PREFIX)
+#is the first argument is "WITH_PREFIX" then keep the standard "lib" prefix, otherwise SET the prefix empty
+ if (${_with_PREFIX} STREQUAL "WITH_PREFIX")
+ set(_first_SRC)
+ else ()
+ set(_first_SRC ${_with_PREFIX})
+ endif ()
+
+# if (KDE3_ENABLE_FINAL)
+# KDE3_CREATE_FINAL_FILE(${_target_NAME}_final.cpp ${_first_SRC} ${ARGN})
+# add_library(${_target_NAME} MODULE ${_target_NAME}_final.cpp)
+# else ()
+ add_library(${_target_NAME} MODULE ${_first_SRC} ${ARGN})
+# endif ()
+
+ if(_first_SRC)
+ set_target_properties(${_target_NAME} PROPERTIES PREFIX "")
+ endif()
+
+ KDE3_INSTALL_LIBTOOL_FILE(${_target_NAME})
+
+endmacro()
+
+
+macro(KDE3_ADD_KDEINIT_EXECUTABLE _target_NAME )
+
+# if (KDE3_ENABLE_FINAL)
+# KDE3_CREATE_FINAL_FILE(${_target_NAME}_final.cpp ${ARGN})
+# add_library(kdeinit_${_target_NAME} SHARED ${_target_NAME}_final.cpp)
+# else ()
+ add_library(kdeinit_${_target_NAME} SHARED ${ARGN} )
+# endif ()
+
+ configure_file(${KDE3_MODULE_DIR}/kde3init_dummy.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/${_target_NAME}_dummy.cpp)
+
+ add_executable( ${_target_NAME} ${CMAKE_CURRENT_BINARY_DIR}/${_target_NAME}_dummy.cpp )
+ target_link_libraries( ${_target_NAME} kdeinit_${_target_NAME} )
+
+endmacro()
+
+
+macro(KDE3_ADD_EXECUTABLE _target_NAME )
+
+# if (KDE3_ENABLE_FINAL)
+# KDE3_CREATE_FINAL_FILE(${_target_NAME}_final.cpp ${ARGN})
+# add_executable(${_target_NAME} ${_target_NAME}_final.cpp)
+# else ()
+ add_executable(${_target_NAME} ${ARGN} )
+# endif ()
+
+endmacro()
+
+
diff --git a/Modules/MacOSXBundleInfo.plist.in b/Modules/MacOSXBundleInfo.plist.in
new file mode 100644
index 0000000..a4009bc
--- /dev/null
+++ b/Modules/MacOSXBundleInfo.plist.in
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+ <key>CFBundleGetInfoString</key>
+ <string>${MACOSX_BUNDLE_INFO_STRING}</string>
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleLongVersionString</key>
+ <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+ <key>NSHumanReadableCopyright</key>
+ <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+</dict>
+</plist>
diff --git a/Modules/MacOSXFrameworkInfo.plist.in b/Modules/MacOSXFrameworkInfo.plist.in
new file mode 100644
index 0000000..18eaef2
--- /dev/null
+++ b/Modules/MacOSXFrameworkInfo.plist.in
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_FRAMEWORK_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_FRAMEWORK_ICON_FILE}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_FRAMEWORK_IDENTIFIER}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_FRAMEWORK_BUNDLE_VERSION}</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_FRAMEWORK_SHORT_VERSION_STRING}</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+</dict>
+</plist>
diff --git a/Modules/MacroAddFileDependencies.cmake b/Modules/MacroAddFileDependencies.cmake
new file mode 100644
index 0000000..8fdc264
--- /dev/null
+++ b/Modules/MacroAddFileDependencies.cmake
@@ -0,0 +1,29 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+MacroAddFileDependencies
+------------------------
+
+.. deprecated:: 3.14
+
+::
+
+ MACRO_ADD_FILE_DEPENDENCIES(<source> <files>...)
+
+Do not use this command in new code. It is just a wrapper around:
+
+.. code-block:: cmake
+
+ set_property(SOURCE <source> APPEND PROPERTY OBJECT_DEPENDS <files>...)
+
+Instead use the :command:`set_property` command to append to the
+:prop_sf:`OBJECT_DEPENDS` source file property directly.
+
+#]=======================================================================]
+
+macro (MACRO_ADD_FILE_DEPENDENCIES _file)
+
+ set_property(SOURCE "${_file}" APPEND PROPERTY OBJECT_DEPENDS "${ARGN}")
+
+endmacro ()
diff --git a/Modules/MatlabTestsRedirect.cmake b/Modules/MatlabTestsRedirect.cmake
new file mode 100644
index 0000000..fc36fc3
--- /dev/null
+++ b/Modules/MatlabTestsRedirect.cmake
@@ -0,0 +1,106 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This is an undocumented internal helper for the FindMatlab
+# module ``matlab_add_unit_test`` command.
+
+# Usage: cmake
+# -Dtest_timeout=180
+# -Doutput_directory=
+# -Dadditional_paths=""
+# -Dno_unittest_framework=""
+# -DMatlab_PROGRAM=matlab_exe_location
+# -DMatlab_ADDITIONAL_STARTUP_OPTIONS=""
+# -Dtest_name=name_of_the_test
+# -Dcustom_Matlab_test_command=""
+# -Dcmd_to_run_before_test=""
+# -Dunittest_file_to_run
+# -P FindMatlab_TestsRedirect.cmake
+
+set(Matlab_UNIT_TESTS_CMD -nosplash -nodesktop -nodisplay ${Matlab_ADDITIONAL_STARTUP_OPTIONS})
+if(WIN32)
+ set(Matlab_UNIT_TESTS_CMD ${Matlab_UNIT_TESTS_CMD} -wait)
+endif()
+
+if(NOT test_timeout)
+ set(test_timeout 180)
+endif()
+
+# If timeout is -1, then do not put a timeout on the execute_process
+if(test_timeout EQUAL -1)
+ set(test_timeout "")
+else()
+ set(test_timeout TIMEOUT ${test_timeout})
+endif()
+
+if(NOT cmd_to_run_before_test)
+ set(cmd_to_run_before_test)
+endif()
+
+get_filename_component(unittest_file_directory "${unittest_file_to_run}" DIRECTORY)
+get_filename_component(unittest_file_to_run_name "${unittest_file_to_run}" NAME_WE)
+
+set(concat_string '${unittest_file_directory}')
+foreach(s IN LISTS additional_paths)
+ if(NOT "${s}" STREQUAL "")
+ string(APPEND concat_string ", '${s}'")
+ endif()
+endforeach()
+
+if(custom_Matlab_test_command)
+ set(unittest_to_run "${custom_Matlab_test_command}")
+else()
+ set(unittest_to_run "runtests('${unittest_file_to_run_name}'), exit(max([ans(1,:).Failed]))")
+endif()
+
+
+if(no_unittest_framework)
+ set(unittest_to_run "${unittest_file_to_run_name}")
+endif()
+
+set(command_to_run "try, ${unittest_to_run}, catch err, disp('An exception has been thrown during the execution'), disp(err), disp(err.stack), exit(1), end, exit(0)")
+set(Matlab_SCRIPT_TO_RUN
+ "addpath(${concat_string}); ${cmd_to_run_before_test}; ${command_to_run}"
+ )
+# if the working directory is not specified then default
+# to the output_directory because the log file will go there
+# if the working_directory is specified it will override the
+# output_directory
+if(NOT working_directory)
+ set(working_directory "${output_directory}")
+endif()
+
+string(REPLACE "/" "_" log_file_name "${test_name}.log")
+set(Matlab_LOG_FILE "${working_directory}/${log_file_name}")
+
+set(devnull)
+if(UNIX)
+ set(devnull INPUT_FILE /dev/null)
+elseif(WIN32)
+ set(devnull INPUT_FILE NUL)
+endif()
+
+execute_process(
+ # Do not use a full path to log file. Depend on the fact that the log file
+ # is always going to go in the working_directory. This is because matlab
+ # on unix is a shell script that does not handle spaces in the logfile path.
+ COMMAND "${Matlab_PROGRAM}" ${Matlab_UNIT_TESTS_CMD} -logfile "${log_file_name}" -r "${Matlab_SCRIPT_TO_RUN}"
+ RESULT_VARIABLE res
+ ${test_timeout}
+ OUTPUT_QUIET # we do not want the output twice
+ WORKING_DIRECTORY "${working_directory}"
+ ${devnull}
+ )
+
+if(NOT EXISTS ${Matlab_LOG_FILE})
+ message( FATAL_ERROR "[MATLAB] ERROR: cannot find the log file ${Matlab_LOG_FILE}")
+endif()
+
+# print the output in any case.
+file(READ ${Matlab_LOG_FILE} matlab_log_content)
+message("Matlab test ${name_of_the_test} output:\n${matlab_log_content}") # if we put FATAL_ERROR here, the file is indented.
+
+
+if(NOT (res EQUAL 0))
+ message( FATAL_ERROR "[MATLAB] TEST FAILED Matlab returned ${res}" )
+endif()
diff --git a/Modules/Platform/AIX-Clang-C.cmake b/Modules/Platform/AIX-Clang-C.cmake
new file mode 100644
index 0000000..0e8a1c0
--- /dev/null
+++ b/Modules/Platform/AIX-Clang-C.cmake
@@ -0,0 +1 @@
+include(Platform/AIX-GNU-C)
diff --git a/Modules/Platform/AIX-Clang-CXX.cmake b/Modules/Platform/AIX-Clang-CXX.cmake
new file mode 100644
index 0000000..6b9110e
--- /dev/null
+++ b/Modules/Platform/AIX-Clang-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/AIX-GNU-CXX)
diff --git a/Modules/Platform/AIX-GNU-ASM.cmake b/Modules/Platform/AIX-GNU-ASM.cmake
new file mode 100644
index 0000000..c256df6
--- /dev/null
+++ b/Modules/Platform/AIX-GNU-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/AIX-GNU)
+__aix_compiler_gnu(ASM)
diff --git a/Modules/Platform/AIX-GNU-C.cmake b/Modules/Platform/AIX-GNU-C.cmake
new file mode 100644
index 0000000..f49d528
--- /dev/null
+++ b/Modules/Platform/AIX-GNU-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/AIX-GNU)
+__aix_compiler_gnu(C)
diff --git a/Modules/Platform/AIX-GNU-CXX.cmake b/Modules/Platform/AIX-GNU-CXX.cmake
new file mode 100644
index 0000000..d047801
--- /dev/null
+++ b/Modules/Platform/AIX-GNU-CXX.cmake
@@ -0,0 +1,3 @@
+include(Platform/AIX-GNU)
+__aix_compiler_gnu(CXX)
+unset(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN)
diff --git a/Modules/Platform/AIX-GNU-Fortran.cmake b/Modules/Platform/AIX-GNU-Fortran.cmake
new file mode 100644
index 0000000..07772a7
--- /dev/null
+++ b/Modules/Platform/AIX-GNU-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/AIX-GNU)
+__aix_compiler_gnu(Fortran)
diff --git a/Modules/Platform/AIX-GNU.cmake b/Modules/Platform/AIX-GNU.cmake
new file mode 100644
index 0000000..5a532c7
--- /dev/null
+++ b/Modules/Platform/AIX-GNU.cmake
@@ -0,0 +1,33 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__AIX_COMPILER_GNU)
+ return()
+endif()
+set(__AIX_COMPILER_GNU 1)
+
+macro(__aix_compiler_gnu lang)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG "-Wl,-blibpath:")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP ":")
+ string(APPEND CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS " -Wl,-bnoipath")
+ set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-Wl,-bexpall") # CMP0065 old behavior
+ set(CMAKE_${lang}_USE_IMPLICIT_LINK_DIRECTORIES_IN_RUNTIME_PATH 1)
+
+ set(CMAKE_${lang}_LINK_FLAGS "-Wl,-bnoipath")
+ if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 7 OR CMAKE_SYSTEM_VERSION VERSION_LESS 7.1)
+ unset(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY)
+ endif()
+
+ # Construct the export list ourselves to pass only the object files so
+ # that we export only the symbols actually provided by the sources.
+ set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
+ "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp <AIX_EXPORTS> <OBJECTS>"
+ "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/exports.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
+ )
+
+ set(CMAKE_${lang}_LINK_EXECUTABLE_WITH_EXPORTS
+ "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -l . <AIX_EXPORTS> <OBJECTS>"
+ "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<TARGET_IMPLIB> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+endmacro()
diff --git a/Modules/Platform/AIX-VisualAge-C.cmake b/Modules/Platform/AIX-VisualAge-C.cmake
new file mode 100644
index 0000000..67b3171
--- /dev/null
+++ b/Modules/Platform/AIX-VisualAge-C.cmake
@@ -0,0 +1 @@
+include(Platform/AIX-XL-C)
diff --git a/Modules/Platform/AIX-VisualAge-CXX.cmake b/Modules/Platform/AIX-VisualAge-CXX.cmake
new file mode 100644
index 0000000..7894d24
--- /dev/null
+++ b/Modules/Platform/AIX-VisualAge-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/AIX-XL-CXX)
diff --git a/Modules/Platform/AIX-VisualAge-Fortran.cmake b/Modules/Platform/AIX-VisualAge-Fortran.cmake
new file mode 100644
index 0000000..19e59d6
--- /dev/null
+++ b/Modules/Platform/AIX-VisualAge-Fortran.cmake
@@ -0,0 +1 @@
+include(Platform/AIX-XL-Fortran)
diff --git a/Modules/Platform/AIX-XL-ASM.cmake b/Modules/Platform/AIX-XL-ASM.cmake
new file mode 100644
index 0000000..ea0944b
--- /dev/null
+++ b/Modules/Platform/AIX-XL-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/AIX-XL)
+__aix_compiler_xl(ASM)
diff --git a/Modules/Platform/AIX-XL-C.cmake b/Modules/Platform/AIX-XL-C.cmake
new file mode 100644
index 0000000..cbfd58b
--- /dev/null
+++ b/Modules/Platform/AIX-XL-C.cmake
@@ -0,0 +1,5 @@
+include(Platform/AIX-XL)
+__aix_compiler_xl(C)
+
+# -qhalt=e = Halt on error messages (rather than just severe errors)
+string(APPEND CMAKE_C_FLAGS_INIT " -qhalt=e")
diff --git a/Modules/Platform/AIX-XL-CXX.cmake b/Modules/Platform/AIX-XL-CXX.cmake
new file mode 100644
index 0000000..78baef5
--- /dev/null
+++ b/Modules/Platform/AIX-XL-CXX.cmake
@@ -0,0 +1,5 @@
+include(Platform/AIX-XL)
+__aix_compiler_xl(CXX)
+
+# -qhalt=s = Halt on severe error messages
+string(APPEND CMAKE_CXX_FLAGS_INIT " -qhalt=s")
diff --git a/Modules/Platform/AIX-XL-Fortran.cmake b/Modules/Platform/AIX-XL-Fortran.cmake
new file mode 100644
index 0000000..6d4f655
--- /dev/null
+++ b/Modules/Platform/AIX-XL-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/AIX-XL)
+__aix_compiler_xl(Fortran)
diff --git a/Modules/Platform/AIX-XL.cmake b/Modules/Platform/AIX-XL.cmake
new file mode 100644
index 0000000..2a8c159
--- /dev/null
+++ b/Modules/Platform/AIX-XL.cmake
@@ -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.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__AIX_COMPILER_XL)
+ return()
+endif()
+set(__AIX_COMPILER_XL 1)
+
+macro(__aix_compiler_xl lang)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG "-Wl,-blibpath:")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP ":")
+ string(APPEND CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS " -Wl,-bnoipath")
+ set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-Wl,-bexpall") # CMP0065 old behavior
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS " ")
+ set(CMAKE_SHARED_MODULE_${lang}_FLAGS " ")
+
+ set(CMAKE_${lang}_LINK_FLAGS "-Wl,-bnoipath")
+
+ set(_OBJECTS " <OBJECTS>")
+ if(DEFINED CMAKE_XL_CreateExportList AND CMAKE_XL_CreateExportList STREQUAL "")
+ # Prior to CMake 3.16, CMAKE_XL_CreateExportList held the path to the XL CreateExportList tool.
+ # Users could set it to an empty value to skip automatic exports in favor of manual -bE: flags.
+ # Preserve that behavior for compatibility (even though it was undocumented).
+ set(_OBJECTS "")
+ endif()
+
+ # Construct the export list ourselves to pass only the object files so
+ # that we export only the symbols actually provided by the sources.
+ set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
+ "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp <AIX_EXPORTS>${_OBJECTS}"
+ "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/exports.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
+ )
+
+ set(CMAKE_${lang}_LINK_EXECUTABLE_WITH_EXPORTS
+ "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -l . <AIX_EXPORTS> <OBJECTS>"
+ "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<TARGET_IMPLIB> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+
+ unset(_OBJECTS)
+endmacro()
diff --git a/Modules/Platform/AIX-XLClang-C.cmake b/Modules/Platform/AIX-XLClang-C.cmake
new file mode 100644
index 0000000..f0bedc5
--- /dev/null
+++ b/Modules/Platform/AIX-XLClang-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/AIX-XLClang)
+__aix_compiler_xlclang(C)
diff --git a/Modules/Platform/AIX-XLClang-CXX.cmake b/Modules/Platform/AIX-XLClang-CXX.cmake
new file mode 100644
index 0000000..cceb576
--- /dev/null
+++ b/Modules/Platform/AIX-XLClang-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/AIX-XLClang)
+__aix_compiler_xlclang(CXX)
diff --git a/Modules/Platform/AIX-XLClang.cmake b/Modules/Platform/AIX-XLClang.cmake
new file mode 100644
index 0000000..c932095
--- /dev/null
+++ b/Modules/Platform/AIX-XLClang.cmake
@@ -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.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__AIX_COMPILER_XLCLANG)
+ return()
+endif()
+set(__AIX_COMPILER_XLCLANG 1)
+
+include(Platform/AIX-XL)
+
+macro(__aix_compiler_xlclang lang)
+ __aix_compiler_xl(${lang})
+endmacro()
diff --git a/Modules/Platform/AIX.cmake b/Modules/Platform/AIX.cmake
new file mode 100644
index 0000000..03cef51
--- /dev/null
+++ b/Modules/Platform/AIX.cmake
@@ -0,0 +1,33 @@
+set(CMAKE_SHARED_LIBRARY_PREFIX "lib") # lib
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".so") # .so
+set(CMAKE_AIX_IMPORT_FILE_PREFIX "")
+set(CMAKE_AIX_IMPORT_FILE_SUFFIX ".imp")
+set(CMAKE_DL_LIBS "-lld")
+
+# RPATH support on AIX is called libpath. By default the runtime
+# libpath is paths specified by -L followed by /usr/lib and /lib. In
+# order to prevent the -L paths from being used we must force use of
+# -Wl,-blibpath:/usr/lib:/lib whether RPATH support is on or not.
+# When our own RPATH is to be added it may be inserted before the
+# "always" paths.
+if(NOT DEFINED CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH)
+ set(CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH /usr/lib /lib)
+endif()
+
+# Files named "libfoo.a" may actually be shared libraries.
+set_property(GLOBAL PROPERTY TARGET_ARCHIVES_MAY_BE_SHARED_LIBS 1)
+
+# since .a can be a static or shared library on AIX, we can not do this.
+# at some point if we wanted it, we would have to figure out if a .a is
+# static or shared, then we could add this back:
+
+# Initialize C link type selection flags. These flags are used when
+# building a shared library, shared module, or executable that links
+# to other libraries to select whether to use the static or shared
+# versions of the libraries.
+#foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+# set(CMAKE_${type}_LINK_STATIC_C_FLAGS "-bstatic")
+# set(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-bdynamic")
+#endforeach()
+
+include(Platform/UnixPaths)
diff --git a/Modules/Platform/AIX/ExportImportList b/Modules/Platform/AIX/ExportImportList
new file mode 100755
index 0000000..891bce7
--- /dev/null
+++ b/Modules/Platform/AIX/ExportImportList
@@ -0,0 +1,60 @@
+#!/bin/sh
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This script is internal to CMake and meant only to be
+# invoked by CMake-generated build systems on AIX.
+
+usage='usage: ExportImportList -o <out-file> [-l <lib>] [-n] [--] <objects>...'
+
+die() {
+ echo "$@" 1>&2; exit 1
+}
+
+# Process command-line arguments.
+out=''
+lib=''
+no_objects=''
+while test "$#" != 0; do
+ case "$1" in
+ -l) shift; lib="$1" ;;
+ -o) shift; out="$1" ;;
+ -n) no_objects='1' ;;
+ --) shift; break ;;
+ -*) die "$usage" ;;
+ *) break ;;
+ esac
+ shift
+done
+test -n "$out" || die "$usage"
+
+# Build a temporary file that atomically replaces the output later.
+out_tmp="$out.tmp$$"
+trap 'rm -f "$out_tmp"' EXIT INT TERM
+> "$out_tmp"
+
+# Collect symbols exported from all object files.
+if test -z "$no_objects"; then
+ for f in "$@"; do
+ dump -tov -X 32_64 "$f" |
+ awk '
+ BEGIN {
+ V["EXPORTED"]=" export"
+ V["PROTECTED"]=" protected"
+ }
+ /^\[[0-9]+\]\tm +[^ ]+ +\.(text|data|bss) +[^ ]+ +(extern|weak) +(EXPORTED|PROTECTED| ) / {
+ if (!match($NF,/^(\.|__sinit|__sterm|__[0-9]+__)/)) {
+ print $NF V[$(NF-1)]
+ }
+ }
+ '
+ done >> "$out_tmp"
+fi
+
+# Generate the export/import file.
+{
+ if test -n "$lib"; then
+ echo "#! $lib"
+ fi
+ sort -u "$out_tmp"
+} > "$out"
diff --git a/Modules/Platform/ARTOS-GNU-C.cmake b/Modules/Platform/ARTOS-GNU-C.cmake
new file mode 100644
index 0000000..fe8d782
--- /dev/null
+++ b/Modules/Platform/ARTOS-GNU-C.cmake
@@ -0,0 +1,9 @@
+# Define ARTOS to select proper behaviour and tell preprocessor to accept C++ style comments.
+string(APPEND CMAKE_C_FLAGS_INIT " -DARTOS -Xp -+")
+# ac doesn't support -g properly and doesn't support the normal gcc optimization options. Just use the defaults set by ac.
+string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " ")
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
+string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG")
+# Most projects expect the stdio functions to be available.
+set(CMAKE_C_STANDARD_LIBRARIES_INIT "stdio.a")
diff --git a/Modules/Platform/ARTOS.cmake b/Modules/Platform/ARTOS.cmake
new file mode 100644
index 0000000..f9365d6
--- /dev/null
+++ b/Modules/Platform/ARTOS.cmake
@@ -0,0 +1,17 @@
+# Support for ARTOS RTOS (locamation.com)
+set(CMAKE_LINK_LIBRARY_SUFFIX "")
+set(CMAKE_STATIC_LIBRARY_PREFIX "")
+set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".a")
+set(CMAKE_EXECUTABLE_SUFFIX ".x")
+set(CMAKE_DL_LIBS "")
+
+set(CMAKE_FIND_LIBRARY_PREFIXES "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
+
+# ARTOS does not support shared libs
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
+
+set(CMAKE_C_LINK_SHARED_LIBRARY )
+set(CMAKE_C_LINK_MODULE_LIBRARY )
diff --git a/Modules/Platform/Android-Clang-ASM.cmake b/Modules/Platform/Android-Clang-ASM.cmake
new file mode 100644
index 0000000..6448da6
--- /dev/null
+++ b/Modules/Platform/Android-Clang-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/Android-Clang)
+__android_compiler_clang(ASM)
diff --git a/Modules/Platform/Android-Clang-C.cmake b/Modules/Platform/Android-Clang-C.cmake
new file mode 100644
index 0000000..9e16911
--- /dev/null
+++ b/Modules/Platform/Android-Clang-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Android-Clang)
+__android_compiler_clang(C)
diff --git a/Modules/Platform/Android-Clang-CXX.cmake b/Modules/Platform/Android-Clang-CXX.cmake
new file mode 100644
index 0000000..85d5088
--- /dev/null
+++ b/Modules/Platform/Android-Clang-CXX.cmake
@@ -0,0 +1,9 @@
+include(Platform/Android-Clang)
+__android_compiler_clang(CXX)
+if(_ANDROID_STL_NOSTDLIBXX)
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 6)
+ string(APPEND CMAKE_CXX_STANDARD_LIBRARIES " -nostdlib++")
+ else()
+ string(APPEND CMAKE_CXX_STANDARD_LIBRARIES " -nodefaultlibs -lgcc -lc -lm -ldl")
+ endif()
+endif()
diff --git a/Modules/Platform/Android-Clang.cmake b/Modules/Platform/Android-Clang.cmake
new file mode 100644
index 0000000..3a279ca
--- /dev/null
+++ b/Modules/Platform/Android-Clang.cmake
@@ -0,0 +1,91 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This module is shared by multiple languages; use include blocker.
+if(__ANDROID_COMPILER_CLANG)
+ return()
+endif()
+set(__ANDROID_COMPILER_CLANG 1)
+
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+ include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/pre/Android-Clang.cmake OPTIONAL)
+endif()
+
+# Load flags from NDK. This file may provides the following variables:
+# _ANDROID_NDK_INIT_CFLAGS
+# _ANDROID_NDK_INIT_CFLAGS_DEBUG
+# _ANDROID_NDK_INIT_CFLAGS_RELEASE
+# _ANDROID_NDK_INIT_LDFLAGS
+# _ANDROID_NDK_INIT_LDFLAGS_EXE
+if(CMAKE_ANDROID_NDK)
+ include(${CMAKE_ANDROID_NDK}/build/cmake/flags.cmake OPTIONAL
+ RESULT_VARIABLE _INCLUDED_FLAGS)
+endif()
+
+# Support for NVIDIA Nsight Tegra Visual Studio Edition was previously
+# implemented in the CMake VS IDE generators. Avoid interfering with
+# that functionality for now. Later we may try to integrate this.
+if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android")
+ macro(__android_compiler_clang lang)
+ endmacro()
+ return()
+endif()
+
+# Commonly used Android toolchain files that pre-date CMake upstream support
+# set CMAKE_SYSTEM_VERSION to 1. Avoid interfering with them.
+if(CMAKE_SYSTEM_VERSION EQUAL 1)
+ macro(__android_compiler_clang lang)
+ endmacro()
+ return()
+endif()
+
+# Natively compiling on an Android host doesn't use the NDK cross-compilation
+# tools.
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Android")
+ macro(__android_compiler_clang lang)
+ endmacro()
+ return()
+endif()
+
+include(Platform/Android-Common)
+
+if(_INCLUDED_FLAGS)
+ # NDK provides the flags.
+ set(_ANDROID_ABI_INIT_CFLAGS "${_ANDROID_NDK_INIT_CFLAGS}")
+ set(_ANDROID_ABI_INIT_CFLAGS_DEBUG "${_ANDROID_NDK_INIT_CFLAGS_DEBUG}")
+ set(_ANDROID_ABI_INIT_CFLAGS_RELEASE "${_ANDROID_NDK_INIT_CFLAGS_RELEASE}")
+ set(_ANDROID_ABI_INIT_LDFLAGS "${_ANDROID_NDK_INIT_LDFLAGS}")
+ set(_ANDROID_ABI_INIT_EXE_LDFLAGS "${_ANDROID_NDK_INIT_LDFLAGS_EXE}")
+else()
+ # The NDK toolchain configuration files at:
+ #
+ # <ndk>/[build/core/]toolchains/*-clang*/setup.mk
+ #
+ # contain logic to set LLVM_TRIPLE for Clang-based toolchains for each target.
+ # We need to produce the same target here to produce compatible binaries.
+ include(Platform/Android/abi-${CMAKE_ANDROID_ARCH_ABI}-Clang)
+endif()
+
+macro(__android_compiler_clang lang)
+ if(NOT "x${lang}" STREQUAL "xASM")
+ __android_compiler_common(${lang})
+ endif()
+ if(NOT CMAKE_${lang}_COMPILER_TARGET)
+ set(CMAKE_${lang}_COMPILER_TARGET "${CMAKE_ANDROID_ARCH_LLVM_TRIPLE}")
+ if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+ string(APPEND CMAKE_${lang}_COMPILER_TARGET "${CMAKE_SYSTEM_VERSION}")
+ endif()
+ list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "--target=${CMAKE_${lang}_COMPILER_TARGET}")
+ endif()
+ if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(_ANDROID_STL_NOSTDLIBXX 1)
+ endif()
+endmacro()
+
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+ include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/post/Android-Clang.cmake OPTIONAL)
+endif()
diff --git a/Modules/Platform/Android-Common.cmake b/Modules/Platform/Android-Common.cmake
new file mode 100644
index 0000000..39da933
--- /dev/null
+++ b/Modules/Platform/Android-Common.cmake
@@ -0,0 +1,230 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This module is shared by multiple languages; use include blocker.
+if(__ANDROID_COMPILER_COMMON)
+ return()
+endif()
+set(__ANDROID_COMPILER_COMMON 1)
+
+if(CMAKE_ANDROID_NDK)
+ # <ndk>/build/core/definitions.mk
+
+ set(_ANDROID_STL_TYPES
+ none
+ system
+ c++_static
+ c++_shared
+ gabi++_static
+ gabi++_shared
+ gnustl_static
+ gnustl_shared
+ stlport_static
+ stlport_shared
+ )
+
+ if(CMAKE_ANDROID_STL_TYPE)
+ list(FIND _ANDROID_STL_TYPES "${CMAKE_ANDROID_STL_TYPE}" _ANDROID_STL_TYPE_FOUND)
+ if(_ANDROID_STL_TYPE_FOUND EQUAL -1)
+ string(REPLACE ";" "\n " _msg ";${_ANDROID_STL_TYPES}")
+ message(FATAL_ERROR
+ "The CMAKE_ANDROID_STL_TYPE '${CMAKE_ANDROID_STL_TYPE}' is not one of the allowed values:${_msg}\n"
+ )
+ endif()
+ unset(_ANDROID_STL_TYPE_FOUND)
+ elseif(IS_DIRECTORY ${CMAKE_ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++)
+ set(CMAKE_ANDROID_STL_TYPE "gnustl_static")
+ else()
+ set(CMAKE_ANDROID_STL_TYPE "c++_static")
+ endif()
+
+ unset(_ANDROID_STL_TYPES)
+
+ # Forward Android-specific platform variables to try_compile projects.
+ list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES
+ CMAKE_ANDROID_STL_TYPE
+ )
+endif()
+
+if(CMAKE_ANDROID_STL_TYPE)
+ if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+ if(CMAKE_ANDROID_STL_TYPE STREQUAL "system")
+ set(_ANDROID_STL_EXCEPTIONS 0)
+ set(_ANDROID_STL_RTTI 0)
+ macro(__android_stl lang)
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " -stdlib=libstdc++")
+ if(_ANDROID_STL_EXCEPTIONS OR _ANDROID_STL_RTTI)
+ string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " -lc++abi")
+ if(CMAKE_SYSTEM_VERSION LESS 21)
+ list(APPEND CMAKE_${lang}_STANDARD_LIBRARIES "-landroid_support")
+ endif()
+ endif()
+ endmacro()
+ elseif(CMAKE_ANDROID_STL_TYPE STREQUAL "c++_static")
+ set(_ANDROID_STL_EXCEPTIONS 1)
+ set(_ANDROID_STL_RTTI 1)
+ macro(__android_stl lang)
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " -stdlib=libc++")
+ string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " -static-libstdc++")
+ endmacro()
+ elseif(CMAKE_ANDROID_STL_TYPE STREQUAL "c++_shared")
+ set(_ANDROID_STL_EXCEPTIONS 1)
+ set(_ANDROID_STL_RTTI 1)
+ macro(__android_stl lang)
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " -stdlib=libc++")
+ endmacro()
+ elseif(CMAKE_ANDROID_STL_TYPE STREQUAL "none")
+ set(_ANDROID_STL_RTTI 0)
+ set(_ANDROID_STL_EXCEPTIONS 0)
+ macro(__android_stl lang)
+ # FIXME: Add a way to add project-wide language-specific compile-only flags.
+ set(CMAKE_CXX_COMPILE_OBJECT
+ "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE> -nostdinc++")
+ string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " -nostdlib++")
+ endmacro()
+ else()
+ message(FATAL_ERROR
+ "Android: STL '${CMAKE_ANDROID_STL_TYPE}' not supported by this NDK."
+ )
+ endif()
+ if(DEFINED CMAKE_ANDROID_RTTI)
+ set(_ANDROID_STL_RTTI ${CMAKE_ANDROID_RTTI})
+ endif()
+ if(DEFINED CMAKE_ANDROID_EXCEPTIONS)
+ set(_ANDROID_STL_EXCEPTIONS ${CMAKE_ANDROID_EXCEPTIONS})
+ endif()
+ elseif(CMAKE_ANDROID_NDK)
+
+ macro(__android_stl_inc lang dir req)
+ if(EXISTS "${dir}")
+ list(APPEND CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES "${dir}")
+ elseif(${req})
+ message(FATAL_ERROR
+ "Android: STL '${CMAKE_ANDROID_STL_TYPE}' include directory not found:\n"
+ " ${dir}"
+ )
+ endif()
+ endmacro()
+
+ macro(__android_stl_lib lang lib req)
+ if(CMAKE_ANDROID_ARCH_ABI MATCHES "^armeabi" AND NOT CMAKE_ANDROID_ARM_MODE)
+ get_filename_component(_ANDROID_STL_LIBDIR "${lib}" DIRECTORY)
+ get_filename_component(_ANDROID_STL_LIBNAME "${lib}" NAME)
+ set(_ANDROID_STL_LIBTHUMB "${_ANDROID_STL_LIBDIR}/thumb/${_ANDROID_STL_LIBNAME}")
+ unset(_ANDROID_STL_LIBDIR)
+ unset(_ANDROID_STL_LIBNAME)
+ else()
+ set(_ANDROID_STL_LIBTHUMB "")
+ endif()
+
+ if(_ANDROID_STL_LIBTHUMB AND EXISTS "${_ANDROID_STL_LIBTHUMB}")
+ string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " \"${_ANDROID_STL_LIBTHUMB}\"")
+ elseif(EXISTS "${lib}")
+ string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " \"${lib}\"")
+ elseif(${req})
+ message(FATAL_ERROR
+ "Android: STL '${CMAKE_ANDROID_STL_TYPE}' library file not found:\n"
+ " ${lib}"
+ )
+ endif()
+
+ unset(_ANDROID_STL_LIBTHUMB)
+ endmacro()
+
+ include(Platform/Android/ndk-stl-${CMAKE_ANDROID_STL_TYPE})
+ else()
+ macro(__android_stl lang)
+ endmacro()
+ endif()
+else()
+ macro(__android_stl lang)
+ endmacro()
+endif()
+
+# The NDK toolchain configuration files at:
+#
+# <ndk>/[build/core/]toolchains/*/setup.mk
+#
+# contain logic to set TARGET_CFLAGS and TARGET_LDFLAGS (and debug/release
+# variants) to tell their build system what flags to pass for each ABI.
+# We need to produce the same flags here to produce compatible binaries.
+# We initialize these variables here and set them in the compiler-specific
+# modules that include this one. Then we use them in the macro below when
+# it is called.
+set(_ANDROID_ABI_INIT_CFLAGS "")
+set(_ANDROID_ABI_INIT_CFLAGS_DEBUG "")
+set(_ANDROID_ABI_INIT_CFLAGS_RELEASE "")
+set(_ANDROID_ABI_INIT_LDFLAGS "")
+set(_ANDROID_ABI_INIT_EXE_LDFLAGS "")
+
+macro(__android_compiler_common lang)
+ if(_ANDROID_ABI_INIT_CFLAGS)
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_ANDROID_ABI_INIT_CFLAGS}")
+ endif()
+ if(_ANDROID_ABI_INIT_CFLAGS_DEBUG)
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " ${_ANDROID_ABI_INIT_CFLAGS_DEBUG}")
+ endif()
+ if(_ANDROID_ABI_INIT_CFLAGS_RELEASE)
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " ${_ANDROID_ABI_INIT_CFLAGS_RELEASE}")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " ${_ANDROID_ABI_INIT_CFLAGS_RELEASE}")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " ${_ANDROID_ABI_INIT_CFLAGS_RELEASE}")
+ endif()
+ if(_ANDROID_ABI_INIT_LDFLAGS)
+ foreach(t EXE SHARED MODULE)
+ string(APPEND CMAKE_${t}_LINKER_FLAGS_INIT " ${_ANDROID_ABI_INIT_LDFLAGS}")
+ endforeach()
+ endif()
+ if(_ANDROID_ABI_INIT_EXE_LDFLAGS)
+ string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " ${_ANDROID_ABI_INIT_EXE_LDFLAGS}")
+ endif()
+
+ if(DEFINED _ANDROID_STL_EXCEPTIONS)
+ if(_ANDROID_STL_EXCEPTIONS)
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " -fexceptions")
+ else()
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " -fno-exceptions")
+ endif()
+ endif()
+
+ if("x${lang}" STREQUAL "xCXX" AND DEFINED _ANDROID_STL_RTTI)
+ if(_ANDROID_STL_RTTI)
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " -frtti")
+ else()
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " -fno-rtti")
+ endif()
+ endif()
+
+ if("x${lang}" STREQUAL "xCXX")
+ __android_stl(CXX)
+ endif()
+
+ if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+ string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " -latomic -lm")
+ endif()
+
+ # <ndk>/build/core/definitions.mk appends the sysroot's include directory
+ # explicitly at the end of the command-line include path so that it
+ # precedes the toolchain's builtin include directories. This is
+ # necessary so that Android API-version-specific headers are preferred
+ # over those in the toolchain's `include-fixed` directory (which cannot
+ # possibly match all versions).
+ #
+ # Do not do this for a standalone toolchain because it is already
+ # tied to a specific API version.
+ if(CMAKE_ANDROID_NDK AND NOT CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+ if(CMAKE_SYSROOT_COMPILE)
+ set(_cmake_sysroot_compile "${CMAKE_SYSROOT_COMPILE}")
+ else()
+ set(_cmake_sysroot_compile "${CMAKE_SYSROOT}")
+ endif()
+ if(NOT CMAKE_ANDROID_NDK_DEPRECATED_HEADERS)
+ list(APPEND CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES
+ "${_cmake_sysroot_compile}/usr/include"
+ "${_cmake_sysroot_compile}/usr/include/${CMAKE_ANDROID_ARCH_TRIPLE}"
+ )
+ else()
+ list(APPEND CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES "${_cmake_sysroot_compile}/usr/include")
+ endif()
+ unset(_cmake_sysroot_compile)
+ endif()
+endmacro()
diff --git a/Modules/Platform/Android-Determine-C.cmake b/Modules/Platform/Android-Determine-C.cmake
new file mode 100644
index 0000000..c7d1d15
--- /dev/null
+++ b/Modules/Platform/Android-Determine-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Android/Determine-Compiler)
+__android_determine_compiler(C)
diff --git a/Modules/Platform/Android-Determine-CXX.cmake b/Modules/Platform/Android-Determine-CXX.cmake
new file mode 100644
index 0000000..3a3de88
--- /dev/null
+++ b/Modules/Platform/Android-Determine-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/Android/Determine-Compiler)
+__android_determine_compiler(CXX)
diff --git a/Modules/Platform/Android-Determine.cmake b/Modules/Platform/Android-Determine.cmake
new file mode 100644
index 0000000..2d2cd5c
--- /dev/null
+++ b/Modules/Platform/Android-Determine.cmake
@@ -0,0 +1,607 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# When CMAKE_SYSTEM_NAME is "Android", CMakeDetermineSystem loads this module.
+# This module detects platform-wide information about the Android target
+# in order to store it in "CMakeSystem.cmake".
+
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+ include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/pre/Android-Determine.cmake OPTIONAL)
+endif()
+
+# Support for NVIDIA Nsight Tegra Visual Studio Edition was previously
+# implemented in the CMake VS IDE generators. Avoid interfering with
+# that functionality for now.
+if(CMAKE_GENERATOR_PLATFORM STREQUAL "Tegra-Android")
+ return()
+endif()
+
+# Commonly used Android toolchain files that pre-date CMake upstream support
+# set CMAKE_SYSTEM_VERSION to 1. Avoid interfering with them.
+if(CMAKE_SYSTEM_VERSION EQUAL 1)
+ return()
+endif()
+
+# Natively compiling on an Android host doesn't use the NDK cross-compilation
+# tools.
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Android")
+ return()
+endif()
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
+# If using Android tools for Visual Studio, compile a sample project to get the
+# sysroot.
+if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ if(NOT CMAKE_SYSROOT)
+ set(vcx_platform ${CMAKE_GENERATOR_PLATFORM})
+ if(CMAKE_GENERATOR MATCHES "Visual Studio 1[45]")
+ set(vcx_sysroot_var "Sysroot")
+ else()
+ set(vcx_sysroot_var "SysrootLink")
+ endif()
+ if(CMAKE_GENERATOR MATCHES "Visual Studio 14")
+ set(vcx_revision "2.0")
+ elseif(CMAKE_GENERATOR MATCHES "Visual Studio 1[56]")
+ set(vcx_revision "3.0")
+ else()
+ set(vcx_revision "")
+ endif()
+ configure_file(${CMAKE_ROOT}/Modules/Platform/Android/VCXProjInspect.vcxproj.in
+ ${CMAKE_PLATFORM_INFO_DIR}/VCXProjInspect.vcxproj @ONLY)
+ execute_process(
+ COMMAND "${CMAKE_VS_MSBUILD_COMMAND}" "VCXProjInspect.vcxproj"
+ "/p:Configuration=Debug" "/p:Platform=${vcx_platform}"
+ WORKING_DIRECTORY ${CMAKE_PLATFORM_INFO_DIR}
+ OUTPUT_VARIABLE VCXPROJ_INSPECT_OUTPUT
+ ERROR_VARIABLE VCXPROJ_INSPECT_OUTPUT
+ RESULT_VARIABLE VCXPROJ_INSPECT_RESULT
+ )
+ if(NOT CMAKE_SYSROOT AND VCXPROJ_INSPECT_OUTPUT MATCHES "CMAKE_SYSROOT=([^%\r\n]+)[\r\n]")
+ # Strip VS diagnostic output from the end of the line.
+ string(REGEX REPLACE " \\(TaskId:[0-9]*\\)$" "" _sysroot "${CMAKE_MATCH_1}")
+ if(EXISTS "${_sysroot}")
+ file(TO_CMAKE_PATH "${_sysroot}" CMAKE_SYSROOT)
+ endif()
+ endif()
+ if(VCXPROJ_INSPECT_RESULT)
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining the sysroot for the Android NDK failed.
+The output was:
+${VCXPROJ_INSPECT_RESULT}
+${VCXPROJ_INSPECT_OUTPUT}
+
+")
+ else()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining the sysroot for the Android NDK succeeded.
+The output was:
+${VCXPROJ_INSPECT_RESULT}
+${VCXPROJ_INSPECT_OUTPUT}
+
+")
+ endif()
+ endif()
+ if(NOT CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION)
+ set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION "clang")
+ endif()
+endif()
+
+# If the user provided CMAKE_SYSROOT for us, extract information from it.
+set(_ANDROID_SYSROOT_NDK "")
+set(_ANDROID_SYSROOT_API "")
+set(_ANDROID_SYSROOT_ARCH "")
+set(_ANDROID_SYSROOT_STANDALONE_TOOLCHAIN "")
+if(CMAKE_SYSROOT)
+ if(NOT IS_DIRECTORY "${CMAKE_SYSROOT}")
+ message(FATAL_ERROR
+ "Android: The specified CMAKE_SYSROOT:\n"
+ " ${CMAKE_SYSROOT}\n"
+ "is not an existing directory."
+ )
+ endif()
+ if(CMAKE_SYSROOT MATCHES "^([^\\\n]*)/platforms/android-([0-9]+)/arch-([a-z0-9_]+)$")
+ set(_ANDROID_SYSROOT_NDK "${CMAKE_MATCH_1}")
+ set(_ANDROID_SYSROOT_API "${CMAKE_MATCH_2}")
+ set(_ANDROID_SYSROOT_ARCH "${CMAKE_MATCH_3}")
+ elseif(CMAKE_SYSROOT MATCHES "^([^\\\n]*)/sysroot$")
+ set(_ANDROID_SYSROOT_STANDALONE_TOOLCHAIN "${CMAKE_MATCH_1}")
+ else()
+ message(FATAL_ERROR
+ "The value of CMAKE_SYSROOT:\n"
+ " ${CMAKE_SYSROOT}\n"
+ "does not match any of the forms:\n"
+ " <ndk>/platforms/android-<api>/arch-<arch>\n"
+ " <standalone-toolchain>/sysroot\n"
+ "where:\n"
+ " <ndk> = Android NDK directory (with forward slashes)\n"
+ " <api> = Android API version number (decimal digits)\n"
+ " <arch> = Android ARCH name (lower case)\n"
+ " <standalone-toolchain> = Path to standalone toolchain prefix\n"
+ )
+ endif()
+endif()
+
+# Find the Android NDK.
+if(CMAKE_ANDROID_NDK)
+ if(NOT IS_DIRECTORY "${CMAKE_ANDROID_NDK}")
+ message(FATAL_ERROR
+ "Android: The NDK root directory specified by CMAKE_ANDROID_NDK:\n"
+ " ${CMAKE_ANDROID_NDK}\n"
+ "does not exist."
+ )
+ endif()
+elseif(CMAKE_ANDROID_STANDALONE_TOOLCHAIN)
+ if(NOT IS_DIRECTORY "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}")
+ message(FATAL_ERROR
+ "Android: The standalone toolchain directory specified by CMAKE_ANDROID_STANDALONE_TOOLCHAIN:\n"
+ " ${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}\n"
+ "does not exist."
+ )
+ endif()
+ if(NOT EXISTS "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h")
+ message(FATAL_ERROR
+ "Android: The standalone toolchain directory specified by CMAKE_ANDROID_STANDALONE_TOOLCHAIN:\n"
+ " ${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}\n"
+ "does not contain a sysroot with a known layout. The file:\n"
+ " ${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h\n"
+ "does not exist."
+ )
+ endif()
+else()
+ if(IS_DIRECTORY "${_ANDROID_SYSROOT_NDK}")
+ set(CMAKE_ANDROID_NDK "${_ANDROID_SYSROOT_NDK}")
+ elseif(IS_DIRECTORY "${_ANDROID_SYSROOT_STANDALONE_TOOLCHAIN}")
+ set(CMAKE_ANDROID_STANDALONE_TOOLCHAIN "${_ANDROID_SYSROOT_STANDALONE_TOOLCHAIN}")
+ elseif(IS_DIRECTORY "${ANDROID_NDK}")
+ file(TO_CMAKE_PATH "${ANDROID_NDK}" CMAKE_ANDROID_NDK)
+ elseif(IS_DIRECTORY "${ANDROID_STANDALONE_TOOLCHAIN}")
+ file(TO_CMAKE_PATH "${ANDROID_STANDALONE_TOOLCHAIN}" CMAKE_ANDROID_STANDALONE_TOOLCHAIN)
+ elseif(IS_DIRECTORY "$ENV{ANDROID_NDK_ROOT}")
+ file(TO_CMAKE_PATH "$ENV{ANDROID_NDK_ROOT}" CMAKE_ANDROID_NDK)
+ elseif(IS_DIRECTORY "$ENV{ANDROID_NDK}")
+ file(TO_CMAKE_PATH "$ENV{ANDROID_NDK}" CMAKE_ANDROID_NDK)
+ elseif(IS_DIRECTORY "$ENV{ANDROID_STANDALONE_TOOLCHAIN}")
+ file(TO_CMAKE_PATH "$ENV{ANDROID_STANDALONE_TOOLCHAIN}" CMAKE_ANDROID_STANDALONE_TOOLCHAIN)
+ endif()
+ # TODO: Search harder for the NDK or standalone toolchain.
+endif()
+
+set(_ANDROID_STANDALONE_TOOLCHAIN_API "")
+if(CMAKE_ANDROID_STANDALONE_TOOLCHAIN)
+ # Try to read the API level from the toolchain launcher.
+ if(EXISTS "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/clang")
+ set(_ANDROID_API_LEVEL_CLANG_REGEX "__ANDROID_API__=([0-9]+)")
+ file(STRINGS "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/clang" _ANDROID_STANDALONE_TOOLCHAIN_BIN_CLANG
+ REGEX "${_ANDROID_API_LEVEL_CLANG_REGEX}" LIMIT_COUNT 1 LIMIT_INPUT 65536)
+ if(_ANDROID_STANDALONE_TOOLCHAIN_BIN_CLANG MATCHES "${_ANDROID_API_LEVEL_CLANG_REGEX}")
+ set(_ANDROID_STANDALONE_TOOLCHAIN_API "${CMAKE_MATCH_1}")
+ endif()
+ unset(_ANDROID_STANDALONE_TOOLCHAIN_BIN_CLANG)
+ unset(_ANDROID_API_LEVEL_CLANG_REGEX)
+ endif()
+ if(NOT _ANDROID_STANDALONE_TOOLCHAIN_API)
+ # The compiler launcher does not know __ANDROID_API__. Assume this
+ # is not unified headers and look for it in the api-level.h header.
+ set(_ANDROID_API_LEVEL_H_REGEX "^[\t ]*#[\t ]*define[\t ]+__ANDROID_API__[\t ]+([0-9]+)")
+ file(STRINGS "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h"
+ _ANDROID_API_LEVEL_H_CONTENT REGEX "${_ANDROID_API_LEVEL_H_REGEX}")
+ if(_ANDROID_API_LEVEL_H_CONTENT MATCHES "${_ANDROID_API_LEVEL_H_REGEX}")
+ set(_ANDROID_STANDALONE_TOOLCHAIN_API "${CMAKE_MATCH_1}")
+ endif()
+ endif()
+ if(NOT _ANDROID_STANDALONE_TOOLCHAIN_API)
+ message(WARNING
+ "Android: Did not detect API level from\n"
+ " ${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/clang\n"
+ "or\n"
+ " ${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h\n"
+ )
+ endif()
+endif()
+
+if(NOT CMAKE_ANDROID_NDK AND NOT CMAKE_ANDROID_STANDALONE_TOOLCHAIN)
+ message(FATAL_ERROR "Android: Neither the NDK or a standalone toolchain was found.")
+endif()
+
+if(CMAKE_ANDROID_NDK)
+ # NDK >= 18 has platforms.cmake. It provides:
+ # NDK_MIN_PLATFORM_LEVEL
+ # NDK_MAX_PLATFORM_LEVEL
+ include("${CMAKE_ANDROID_NDK}/build/cmake/platforms.cmake" OPTIONAL RESULT_VARIABLE _INCLUDED_PLATFORMS)
+ # NDK >= 18 has abis.cmake. It provides:
+ # NDK_KNOWN_DEVICE_ABI32S
+ # NDK_KNOWN_DEVICE_ABI64S
+ # NDK >= 23 also provides:
+ # NDK_KNOWN_DEVICE_ABIS
+ # NDK_ABI_<abi>_PROC
+ # NDK_ABI_<abi>_ARCH
+ # NDK_ABI_<abi>_TRIPLE
+ # NDK_ABI_<abi>_LLVM_TRIPLE
+ # NDK_PROC_<processor>_ABI
+ # NDK_ARCH_<arch>_ABI
+ include("${CMAKE_ANDROID_NDK}/build/cmake/abis.cmake" OPTIONAL RESULT_VARIABLE _INCLUDED_ABIS)
+endif()
+
+if(CMAKE_ANDROID_NDK AND EXISTS "${CMAKE_ANDROID_NDK}/source.properties")
+ # Android NDK revision
+ # Possible formats:
+ # * r16, build 1234: 16.0.1234
+ # * r16b, build 1234: 16.1.1234
+ # * r16 beta 1, build 1234: 16.0.1234-beta1
+ #
+ # Canary builds are not specially marked.
+ file(READ "${CMAKE_ANDROID_NDK}/source.properties" _ANDROID_NDK_SOURCE_PROPERTIES)
+
+ set(_ANDROID_NDK_REVISION_REGEX
+ "^Pkg\\.Desc = Android NDK\nPkg\\.Revision = ([0-9]+)\\.([0-9]+)\\.([0-9]+)(-beta([0-9]+))?")
+ if(NOT _ANDROID_NDK_SOURCE_PROPERTIES MATCHES "${_ANDROID_NDK_REVISION_REGEX}")
+ string(REPLACE "\n" "\n " _ANDROID_NDK_SOURCE_PROPERTIES "${_ANDROID_NDK_SOURCE_PROPERTIES}")
+ message(FATAL_ERROR
+ "Android: Failed to parse NDK revision from:\n"
+ " ${CMAKE_ANDROID_NDK}/source.properties\n"
+ "with content:\n"
+ " ${_ANDROID_NDK_SOURCE_PROPERTIES}")
+ endif()
+
+ set(_ANDROID_NDK_MAJOR "${CMAKE_MATCH_1}")
+ set(_ANDROID_NDK_MINOR "${CMAKE_MATCH_2}")
+ set(_ANDROID_NDK_BUILD "${CMAKE_MATCH_3}")
+ set(_ANDROID_NDK_BETA "${CMAKE_MATCH_5}")
+ if(_ANDROID_NDK_BETA STREQUAL "")
+ set(_ANDROID_NDK_BETA "0")
+ endif()
+ set(CMAKE_ANDROID_NDK_VERSION "${_ANDROID_NDK_MAJOR}.${_ANDROID_NDK_MINOR}")
+
+ unset(_ANDROID_NDK_SOURCE_PROPERTIES)
+ unset(_ANDROID_NDK_REVISION_REGEX)
+ unset(_ANDROID_NDK_MAJOR)
+ unset(_ANDROID_NDK_MINOR)
+ unset(_ANDROID_NDK_BUILD)
+ unset(_ANDROID_NDK_BETA)
+endif()
+
+if(CMAKE_ANDROID_NDK)
+ # Identify the host platform.
+ if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
+ if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
+ set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "darwin-x86_64")
+ else()
+ set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "darwin-x86")
+ endif()
+ elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
+ if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
+ set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "linux-x86_64")
+ else()
+ set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "linux-x86")
+ endif()
+ elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+ if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64")
+ set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "windows-x86_64")
+ else()
+ set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "windows")
+ endif()
+ else()
+ message(FATAL_ERROR "Android: Builds hosted on '${CMAKE_HOST_SYSTEM_NAME}' not supported.")
+ endif()
+
+ # Look for a unified toolchain/sysroot provided with the NDK.
+ set(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED "${CMAKE_ANDROID_NDK}/toolchains/llvm/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}")
+ if(NOT IS_DIRECTORY "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/sysroot")
+ set(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED "")
+ endif()
+else()
+ set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "")
+ set(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED "")
+endif()
+
+if(_INCLUDED_ABIS)
+ if(NDK_KNOWN_DEVICE_ABIS)
+ set(_ANDROID_KNOWN_ABIS ${NDK_KNOWN_DEVICE_ABIS})
+ else()
+ set(_ANDROID_KNOWN_ABIS ${NDK_KNOWN_DEVICE_ABI32S} ${NDK_KNOWN_DEVICE_ABI64S})
+ endif()
+endif()
+
+if(NOT DEFINED NDK_KNOWN_DEVICE_ABIS)
+ # The NDK is not new enough to provide ABI information.
+ # https://developer.android.com/ndk/guides/abis.html
+
+ set(NDK_ABI_arm64-v8a_PROC "aarch64")
+ set(NDK_ABI_arm64-v8a_ARCH "arm64")
+ set(NDK_ABI_arm64-v8a_TRIPLE "aarch64-linux-android")
+ set(NDK_ABI_arm64-v8a_LLVM_TRIPLE "aarch64-none-linux-android")
+ set(NDK_ABI_armeabi-v7a_PROC "armv7-a")
+ set(NDK_ABI_armeabi-v7a_ARCH "arm")
+ set(NDK_ABI_armeabi-v7a_TRIPLE "arm-linux-androideabi")
+ set(NDK_ABI_armeabi-v7a_LLVM_TRIPLE "armv7-none-linux-androideabi")
+ set(NDK_ABI_armeabi-v6_PROC "armv6")
+ set(NDK_ABI_armeabi-v6_ARCH "arm")
+ set(NDK_ABI_armeabi-v6_TRIPLE "arm-linux-androideabi")
+ set(NDK_ABI_armeabi-v6_LLVM_TRIPLE "armv6-none-linux-androideabi")
+ set(NDK_ABI_armeabi_PROC "armv5te")
+ set(NDK_ABI_armeabi_ARCH "arm")
+ set(NDK_ABI_armeabi_TRIPLE "arm-linux-androideabi")
+ set(NDK_ABI_armeabi_LLVM_TRIPLE "armv5te-none-linux-androideabi")
+ set(NDK_ABI_mips_PROC "mips")
+ set(NDK_ABI_mips_ARCH "mips")
+ set(NDK_ABI_mips_TRIPLE "mipsel-linux-android")
+ set(NDK_ABI_mips_LLVM_TRIPLE "mipsel-none-linux-android")
+ set(NDK_ABI_mips64_PROC "mips64")
+ set(NDK_ABI_mips64_ARCH "mips64")
+ set(NDK_ABI_mips64_TRIPLE "mips64el-linux-android")
+ set(NDK_ABI_mips64_LLVM_TRIPLE "mips64el-none-linux-android")
+ set(NDK_ABI_x86_PROC "i686")
+ set(NDK_ABI_x86_ARCH "x86")
+ set(NDK_ABI_x86_TRIPLE "i686-linux-android")
+ set(NDK_ABI_x86_LLVM_TRIPLE "i686-none-linux-android")
+ set(NDK_ABI_x86_64_PROC "x86_64")
+ set(NDK_ABI_x86_64_ARCH "x86_64")
+ set(NDK_ABI_x86_64_TRIPLE "x86_64-linux-android")
+ set(NDK_ABI_x86_64_LLVM_TRIPLE "x86_64-none-linux-android")
+
+ set(NDK_PROC_aarch64_ABI "arm64-v8a")
+ set(NDK_PROC_armv7-a_ABI "armeabi-v7a")
+ set(NDK_PROC_armv6_ABI "armeabi-v6")
+ set(NDK_PROC_armv5te_ABI "armeabi")
+ set(NDK_PROC_i686_ABI "x86")
+ set(NDK_PROC_mips_ABI "mips")
+ set(NDK_PROC_mips64_ABI "mips64")
+ set(NDK_PROC_x86_64_ABI "x86_64")
+
+ set(NDK_ARCH_arm64_ABI "arm64-v8a")
+ set(NDK_ARCH_arm_ABI "armeabi")
+ set(NDK_ARCH_mips_ABI "mips")
+ set(NDK_ARCH_mips64_ABI "mips64")
+ set(NDK_ARCH_x86_ABI "x86")
+ set(NDK_ARCH_x86_64_ABI "x86_64")
+endif()
+
+# Validate inputs.
+if(CMAKE_ANDROID_ARCH_ABI AND NOT DEFINED "NDK_ABI_${CMAKE_ANDROID_ARCH_ABI}_PROC")
+ message(FATAL_ERROR "Android: Unknown ABI CMAKE_ANDROID_ARCH_ABI='${CMAKE_ANDROID_ARCH_ABI}'.")
+endif()
+if(CMAKE_SYSTEM_PROCESSOR AND NOT DEFINED "NDK_PROC_${CMAKE_SYSTEM_PROCESSOR}_ABI")
+ message(FATAL_ERROR "Android: Unknown processor CMAKE_SYSTEM_PROCESSOR='${CMAKE_SYSTEM_PROCESSOR}'.")
+endif()
+if(_ANDROID_SYSROOT_ARCH AND NOT DEFINED "NDK_ARCH_${_ANDROID_SYSROOT_ARCH}_ABI")
+ message(FATAL_ERROR
+ "Android: Unknown architecture '${_ANDROID_SYSROOT_ARCH}' specified in CMAKE_SYSROOT:\n"
+ " ${CMAKE_SYSROOT}"
+ )
+endif()
+
+# Select an ABI.
+if(NOT CMAKE_ANDROID_ARCH_ABI)
+ if(CMAKE_SYSTEM_PROCESSOR)
+ set(CMAKE_ANDROID_ARCH_ABI "${NDK_PROC_${CMAKE_SYSTEM_PROCESSOR}_ABI}")
+ elseif(_ANDROID_SYSROOT_ARCH)
+ set(CMAKE_ANDROID_ARCH_ABI "${NDK_ARCH_${_ANDROID_SYSROOT_ARCH}_ABI}")
+ elseif(_INCLUDED_ABIS)
+ # Default to the oldest ARM ABI.
+ foreach(abi armeabi armeabi-v7a arm64-v8a)
+ if("${abi}" IN_LIST _ANDROID_KNOWN_ABIS)
+ set(CMAKE_ANDROID_ARCH_ABI "${abi}")
+ break()
+ endif()
+ endforeach()
+ if(NOT CMAKE_ANDROID_ARCH_ABI)
+ message(FATAL_ERROR
+ "Android: Can not determine the default ABI. Please set CMAKE_ANDROID_ARCH_ABI."
+ )
+ endif()
+ else()
+ # https://developer.android.com/ndk/guides/application_mk.html
+ # Default is the oldest ARM ABI.
+
+ # Lookup the available ABIs among all toolchains.
+ set(_ANDROID_ABIS "")
+ file(GLOB _ANDROID_CONFIG_MKS
+ "${CMAKE_ANDROID_NDK}/build/core/toolchains/*/config.mk"
+ "${CMAKE_ANDROID_NDK}/toolchains/*/config.mk"
+ )
+ foreach(config_mk IN LISTS _ANDROID_CONFIG_MKS)
+ file(STRINGS "${config_mk}" _ANDROID_TOOL_ABIS REGEX "^TOOLCHAIN_ABIS :=")
+ string(REPLACE "TOOLCHAIN_ABIS :=" "" _ANDROID_TOOL_ABIS "${_ANDROID_TOOL_ABIS}")
+ separate_arguments(_ANDROID_TOOL_ABIS UNIX_COMMAND "${_ANDROID_TOOL_ABIS}")
+ list(APPEND _ANDROID_ABIS ${_ANDROID_TOOL_ABIS})
+ unset(_ANDROID_TOOL_ABIS)
+ endforeach()
+ unset(_ANDROID_CONFIG_MKS)
+
+ # Choose the oldest among the available arm ABIs.
+ if(_ANDROID_ABIS)
+ list(REMOVE_DUPLICATES _ANDROID_ABIS)
+ foreach(abi armeabi armeabi-v7a arm64-v8a)
+ if("${abi}" IN_LIST _ANDROID_ABIS)
+ set(CMAKE_ANDROID_ARCH_ABI "${abi}")
+ break()
+ endif()
+ endforeach()
+ endif()
+ unset(_ANDROID_ABIS)
+
+ if(NOT CMAKE_ANDROID_ARCH_ABI)
+ set(CMAKE_ANDROID_ARCH_ABI "armeabi")
+ endif()
+ endif()
+endif()
+if(_INCLUDED_ABIS AND NOT CMAKE_ANDROID_ARCH_ABI IN_LIST _ANDROID_KNOWN_ABIS)
+ message(FATAL_ERROR
+ "Android: ABI '${CMAKE_ANDROID_ARCH_ABI}' is not supported by the NDK.\n"
+ "Supported ABIS: ${_ANDROID_KNOWN_ABIS}."
+ )
+endif()
+set(CMAKE_ANDROID_ARCH "${NDK_ABI_${CMAKE_ANDROID_ARCH_ABI}_ARCH}")
+if(_ANDROID_SYSROOT_ARCH AND NOT "x${_ANDROID_SYSROOT_ARCH}" STREQUAL "x${CMAKE_ANDROID_ARCH}")
+ message(FATAL_ERROR
+ "Android: Architecture '${_ANDROID_SYSROOT_ARCH}' specified in CMAKE_SYSROOT:\n"
+ " ${CMAKE_SYSROOT}\n"
+ "does not match architecture '${CMAKE_ANDROID_ARCH}' for the ABI '${CMAKE_ANDROID_ARCH_ABI}'."
+ )
+endif()
+set(CMAKE_ANDROID_ARCH_TRIPLE "${NDK_ABI_${CMAKE_ANDROID_ARCH_ABI}_TRIPLE}")
+set(CMAKE_ANDROID_ARCH_LLVM_TRIPLE
+ "${NDK_ABI_${CMAKE_ANDROID_ARCH_ABI}_LLVM_TRIPLE}")
+
+# Select a processor.
+if(NOT CMAKE_SYSTEM_PROCESSOR)
+ set(CMAKE_SYSTEM_PROCESSOR "${NDK_ABI_${CMAKE_ANDROID_ARCH_ABI}_PROC}")
+endif()
+
+# If the user specified both an ABI and a processor then they might not match.
+if(NOT NDK_ABI_${CMAKE_ANDROID_ARCH_ABI}_PROC STREQUAL CMAKE_SYSTEM_PROCESSOR)
+ message(FATAL_ERROR "Android: The specified CMAKE_ANDROID_ARCH_ABI='${CMAKE_ANDROID_ARCH_ABI}' and CMAKE_SYSTEM_PROCESSOR='${CMAKE_SYSTEM_PROCESSOR}' is not a valid combination.")
+endif()
+
+# Select an API.
+if(CMAKE_SYSTEM_VERSION)
+ set(_ANDROID_API_VAR CMAKE_SYSTEM_VERSION)
+elseif(CMAKE_ANDROID_API)
+ set(CMAKE_SYSTEM_VERSION "${CMAKE_ANDROID_API}")
+ set(_ANDROID_API_VAR CMAKE_ANDROID_API)
+elseif(_ANDROID_SYSROOT_API)
+ set(CMAKE_SYSTEM_VERSION "${_ANDROID_SYSROOT_API}")
+ set(_ANDROID_API_VAR CMAKE_SYSROOT)
+elseif(_ANDROID_STANDALONE_TOOLCHAIN_API)
+ set(CMAKE_SYSTEM_VERSION "${_ANDROID_STANDALONE_TOOLCHAIN_API}")
+endif()
+if(CMAKE_SYSTEM_VERSION)
+ if(CMAKE_ANDROID_API AND NOT "x${CMAKE_ANDROID_API}" STREQUAL "x${CMAKE_SYSTEM_VERSION}")
+ message(FATAL_ERROR
+ "Android: The API specified by CMAKE_ANDROID_API='${CMAKE_ANDROID_API}' is not consistent with CMAKE_SYSTEM_VERSION='${CMAKE_SYSTEM_VERSION}'."
+ )
+ endif()
+ if(_ANDROID_SYSROOT_API)
+ foreach(v CMAKE_ANDROID_API CMAKE_SYSTEM_VERSION)
+ if(${v} AND NOT "x${_ANDROID_SYSROOT_API}" STREQUAL "x${${v}}")
+ message(FATAL_ERROR
+ "Android: The API specified by ${v}='${${v}}' is not consistent with CMAKE_SYSROOT:\n"
+ " ${CMAKE_SYSROOT}"
+ )
+ endif()
+ endforeach()
+ endif()
+ if(CMAKE_ANDROID_NDK)
+ if (_INCLUDED_PLATFORMS)
+ if(CMAKE_SYSTEM_VERSION GREATER NDK_MAX_PLATFORM_LEVEL OR
+ CMAKE_SYSTEM_VERSION LESS NDK_MIN_PLATFORM_LEVEL)
+ message(FATAL_ERROR
+ "Android: The API level ${CMAKE_SYSTEM_VERSION} is not supported by the NDK.\n"
+ "Choose one in the range of [${NDK_MIN_PLATFORM_LEVEL}, ${NDK_MAX_PLATFORM_LEVEL}]."
+ )
+ endif()
+ else()
+ if(NOT IS_DIRECTORY "${CMAKE_ANDROID_NDK}/platforms/android-${CMAKE_SYSTEM_VERSION}")
+ message(FATAL_ERROR
+ "Android: The API specified by ${_ANDROID_API_VAR}='${${_ANDROID_API_VAR}}' does not exist in the NDK. "
+ "The directory:\n"
+ " ${CMAKE_ANDROID_NDK}/platforms/android-${CMAKE_SYSTEM_VERSION}\n"
+ "does not exist."
+ )
+ endif()
+ endif()
+ endif()
+elseif(CMAKE_ANDROID_NDK)
+ if (_INCLUDED_PLATFORMS)
+ set(CMAKE_SYSTEM_VERSION ${NDK_MIN_PLATFORM_LEVEL})
+ # And for LP64 we need to pull up to 21. No diagnostic is provided here because
+ # minSdkVersion < 21 is valid for the project even though it may not be for this
+ # ABI.
+ if(CMAKE_ANDROID_ARCH_ABI MATCHES "64(-v8a)?$" AND CMAKE_SYSTEM_VERSION LESS 21)
+ set(CMAKE_SYSTEM_VERSION 21)
+ endif()
+ else()
+ file(GLOB _ANDROID_APIS_1 RELATIVE "${CMAKE_ANDROID_NDK}/platforms" "${CMAKE_ANDROID_NDK}/platforms/android-[0-9]")
+ file(GLOB _ANDROID_APIS_2 RELATIVE "${CMAKE_ANDROID_NDK}/platforms" "${CMAKE_ANDROID_NDK}/platforms/android-[0-9][0-9]")
+ list(SORT _ANDROID_APIS_1)
+ list(SORT _ANDROID_APIS_2)
+ set(_ANDROID_APIS ${_ANDROID_APIS_1} ${_ANDROID_APIS_2})
+ unset(_ANDROID_APIS_1)
+ unset(_ANDROID_APIS_2)
+ if(_ANDROID_APIS STREQUAL "")
+ message(FATAL_ERROR
+ "Android: No APIs found in the NDK. No\n"
+ " ${CMAKE_ANDROID_NDK}/platforms/android-*\n"
+ "directories exist."
+ )
+ endif()
+ string(REPLACE "android-" "" _ANDROID_APIS "${_ANDROID_APIS}")
+ list(REVERSE _ANDROID_APIS)
+ list(GET _ANDROID_APIS 0 CMAKE_SYSTEM_VERSION)
+ unset(_ANDROID_APIS)
+ endif()
+endif()
+if(NOT CMAKE_SYSTEM_VERSION MATCHES "^[0-9]+$")
+ message(FATAL_ERROR "Android: The API specified by CMAKE_SYSTEM_VERSION='${CMAKE_SYSTEM_VERSION}' is not an integer.")
+endif()
+
+if(CMAKE_ANDROID_NDK AND NOT DEFINED CMAKE_ANDROID_NDK_DEPRECATED_HEADERS)
+ if(IS_DIRECTORY "${CMAKE_ANDROID_NDK}/sysroot/usr/include/${CMAKE_ANDROID_ARCH_TRIPLE}")
+ # Unified headers exist so we use them by default.
+ set(CMAKE_ANDROID_NDK_DEPRECATED_HEADERS 0)
+ else()
+ # Unified headers do not exist so use the deprecated headers.
+ set(CMAKE_ANDROID_NDK_DEPRECATED_HEADERS 1)
+ endif()
+endif()
+
+# Save the Android-specific information in CMakeSystem.cmake.
+set(CMAKE_SYSTEM_CUSTOM_CODE "
+set(CMAKE_ANDROID_NDK \"${CMAKE_ANDROID_NDK}\")
+set(CMAKE_ANDROID_STANDALONE_TOOLCHAIN \"${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}\")
+set(CMAKE_ANDROID_ARCH \"${CMAKE_ANDROID_ARCH}\")
+set(CMAKE_ANDROID_ARCH_ABI \"${CMAKE_ANDROID_ARCH_ABI}\")
+")
+
+if(CMAKE_ANDROID_NDK)
+ string(APPEND CMAKE_SYSTEM_CUSTOM_CODE
+ "set(CMAKE_ANDROID_ARCH_TRIPLE \"${CMAKE_ANDROID_ARCH_TRIPLE}\")\n"
+ "set(CMAKE_ANDROID_ARCH_LLVM_TRIPLE \"${CMAKE_ANDROID_ARCH_LLVM_TRIPLE}\")\n"
+ "set(CMAKE_ANDROID_NDK_VERSION \"${CMAKE_ANDROID_NDK_VERSION}\")\n"
+ "set(CMAKE_ANDROID_NDK_DEPRECATED_HEADERS \"${CMAKE_ANDROID_NDK_DEPRECATED_HEADERS}\")\n"
+ "set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG \"${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}\")\n"
+ "set(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED \"${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}\")\n"
+ )
+endif()
+
+# Select an ARM variant.
+if(CMAKE_ANDROID_ARCH_ABI MATCHES "^armeabi")
+ if(CMAKE_ANDROID_ARM_MODE)
+ set(CMAKE_ANDROID_ARM_MODE 1)
+ else()
+ set(CMAKE_ANDROID_ARM_MODE 0)
+ endif()
+ string(APPEND CMAKE_SYSTEM_CUSTOM_CODE
+ "set(CMAKE_ANDROID_ARM_MODE \"${CMAKE_ANDROID_ARM_MODE}\")\n"
+ )
+elseif(DEFINED CMAKE_ANDROID_ARM_MODE)
+ message(FATAL_ERROR "Android: CMAKE_ANDROID_ARM_MODE is set but is valid only for 'armeabi' architectures.")
+endif()
+
+if(CMAKE_ANDROID_ARCH_ABI STREQUAL "armeabi-v7a")
+ if(CMAKE_ANDROID_ARM_NEON)
+ set(CMAKE_ANDROID_ARM_NEON 1)
+ else()
+ set(CMAKE_ANDROID_ARM_NEON 0)
+ endif()
+ string(APPEND CMAKE_SYSTEM_CUSTOM_CODE
+ "set(CMAKE_ANDROID_ARM_NEON \"${CMAKE_ANDROID_ARM_NEON}\")\n"
+ )
+elseif(DEFINED CMAKE_ANDROID_ARM_NEON)
+ message(FATAL_ERROR "Android: CMAKE_ANDROID_ARM_NEON is set but is valid only for 'armeabi-v7a' architecture.")
+endif()
+
+# Report the chosen architecture.
+message(STATUS "Android: Targeting API '${CMAKE_SYSTEM_VERSION}' with architecture '${CMAKE_ANDROID_ARCH}', ABI '${CMAKE_ANDROID_ARCH_ABI}', and processor '${CMAKE_SYSTEM_PROCESSOR}'")
+
+cmake_policy(POP)
+
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+ include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/post/Android-Determine.cmake OPTIONAL)
+endif()
diff --git a/Modules/Platform/Android-GNU-C.cmake b/Modules/Platform/Android-GNU-C.cmake
new file mode 100644
index 0000000..78a6a50
--- /dev/null
+++ b/Modules/Platform/Android-GNU-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Android-GNU)
+__android_compiler_gnu(C)
diff --git a/Modules/Platform/Android-GNU-CXX.cmake b/Modules/Platform/Android-GNU-CXX.cmake
new file mode 100644
index 0000000..d30d0ff
--- /dev/null
+++ b/Modules/Platform/Android-GNU-CXX.cmake
@@ -0,0 +1,5 @@
+include(Platform/Android-GNU)
+__android_compiler_gnu(CXX)
+if(_ANDROID_STL_NOSTDLIBXX)
+ string(APPEND CMAKE_CXX_STANDARD_LIBRARIES " -nodefaultlibs -lgcc -lc -lm -ldl")
+endif()
diff --git a/Modules/Platform/Android-GNU.cmake b/Modules/Platform/Android-GNU.cmake
new file mode 100644
index 0000000..e1f79ca
--- /dev/null
+++ b/Modules/Platform/Android-GNU.cmake
@@ -0,0 +1,33 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This module is shared by multiple languages; use include blocker.
+if(__ANDROID_COMPILER_GNU)
+ return()
+endif()
+set(__ANDROID_COMPILER_GNU 1)
+
+# Support for NVIDIA Nsight Tegra Visual Studio Edition was previously
+# implemented in the CMake VS IDE generators. Avoid interfering with
+# that functionality for now. Later we may try to integrate this.
+if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android")
+ macro(__android_compiler_gnu lang)
+ endmacro()
+ return()
+endif()
+
+# Commonly used Android toolchain files that pre-date CMake upstream support
+# set CMAKE_SYSTEM_VERSION to 1. Avoid interfering with them.
+if(CMAKE_SYSTEM_VERSION EQUAL 1)
+ macro(__android_compiler_gnu lang)
+ endmacro()
+ return()
+endif()
+
+include(Platform/Android-Common)
+
+include(Platform/Android/abi-${CMAKE_ANDROID_ARCH_ABI}-GNU)
+
+macro(__android_compiler_gnu lang)
+ __android_compiler_common(${lang})
+endmacro()
diff --git a/Modules/Platform/Android-Initialize.cmake b/Modules/Platform/Android-Initialize.cmake
new file mode 100644
index 0000000..50f0620
--- /dev/null
+++ b/Modules/Platform/Android-Initialize.cmake
@@ -0,0 +1,117 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# When CMAKE_SYSTEM_NAME is "Android", CMakeSystemSpecificInitialize loads this
+# module.
+
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+ include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/pre/Android-Initialize.cmake OPTIONAL)
+endif()
+
+# Support for NVIDIA Nsight Tegra Visual Studio Edition was previously
+# implemented in the CMake VS IDE generators. Avoid interfering with
+# that functionality for now.
+if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android")
+ return()
+endif()
+
+# Commonly used Android toolchain files that pre-date CMake upstream support
+# set CMAKE_SYSTEM_VERSION to 1. Avoid interfering with them.
+if(CMAKE_SYSTEM_VERSION EQUAL 1)
+ return()
+endif()
+
+set(CMAKE_BUILD_TYPE_INIT "RelWithDebInfo")
+
+if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+ # Tell CMake not to search host sysroots for headers/libraries.
+
+ # All paths added to CMAKE_SYSTEM_*_PATH below will be rerooted under
+ # CMAKE_FIND_ROOT_PATH. This is set because:
+ # 1. Users may structure their libraries in a way similar to NDK. When they do that,
+ # they can simply append another path to CMAKE_FIND_ROOT_PATH.
+ # 2. CMAKE_FIND_ROOT_PATH must be non-empty for CMAKE_FIND_ROOT_PATH_MODE_* == ONLY
+ # to be meaningful. https://github.com/android-ndk/ndk/issues/890
+ list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/sysroot")
+
+ # Allow users to override these values in case they want more strict behaviors.
+ # For example, they may want to prevent the NDK's libz from being picked up so
+ # they can use their own.
+ # https://github.com/android-ndk/ndk/issues/517
+ if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_PROGRAM)
+ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+ endif()
+
+ if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_LIBRARY)
+ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+ endif()
+
+ if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_INCLUDE)
+ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+ endif()
+
+ if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_PACKAGE)
+ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+ endif()
+
+ # Don't search paths in PATH environment variable.
+ if(NOT DEFINED CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH)
+ set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH OFF)
+ endif()
+
+ # Allows CMake to find headers in the architecture-specific include directories.
+ set(CMAKE_LIBRARY_ARCHITECTURE "${CMAKE_ANDROID_ARCH_TRIPLE}")
+
+ # Instructs CMake to search the correct API level for libraries.
+ # Besides the paths like <root>/<prefix>/lib/<arch>, cmake also searches <root>/<prefix>.
+ # So we can add the API level specific directory directly.
+ # https://github.com/android/ndk/issues/929
+ list(PREPEND CMAKE_SYSTEM_PREFIX_PATH
+ "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/${CMAKE_SYSTEM_VERSION}"
+ )
+
+ list(APPEND CMAKE_SYSTEM_PROGRAM_PATH "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin")
+endif()
+
+# Skip sysroot selection if the NDK has a unified toolchain.
+if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+ return()
+endif()
+
+# Natively compiling on an Android host doesn't use the NDK cross-compilation
+# tools.
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Android")
+ return()
+endif()
+
+if(NOT CMAKE_SYSROOT)
+ if(CMAKE_ANDROID_NDK)
+ set(CMAKE_SYSROOT "${CMAKE_ANDROID_NDK}/platforms/android-${CMAKE_SYSTEM_VERSION}/arch-${CMAKE_ANDROID_ARCH}")
+ if(NOT CMAKE_ANDROID_NDK_DEPRECATED_HEADERS)
+ set(CMAKE_SYSROOT_COMPILE "${CMAKE_ANDROID_NDK}/sysroot")
+ endif()
+ elseif(CMAKE_ANDROID_STANDALONE_TOOLCHAIN)
+ set(CMAKE_SYSROOT "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/sysroot")
+ endif()
+endif()
+
+if(CMAKE_SYSROOT)
+ if(NOT IS_DIRECTORY "${CMAKE_SYSROOT}")
+ message(FATAL_ERROR
+ "Android: The system root directory needed for the selected Android version and architecture does not exist:\n"
+ " ${CMAKE_SYSROOT}\n"
+ )
+ endif()
+else()
+ message(FATAL_ERROR
+ "Android: No CMAKE_SYSROOT was selected."
+ )
+endif()
+
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+ include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/post/Android-Initialize.cmake OPTIONAL)
+endif()
diff --git a/Modules/Platform/Android.cmake b/Modules/Platform/Android.cmake
new file mode 100644
index 0000000..6944e32
--- /dev/null
+++ b/Modules/Platform/Android.cmake
@@ -0,0 +1,42 @@
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+ include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/pre/Android.cmake OPTIONAL)
+endif()
+
+include(Platform/Linux)
+
+set(ANDROID 1)
+
+# Natively compiling on an Android host doesn't need these flags to be reset.
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Android")
+ return()
+endif()
+
+# Conventionally Android does not use versioned soname
+# But in modern versions it is acceptable
+if(NOT DEFINED CMAKE_PLATFORM_NO_VERSIONED_SONAME)
+ set(CMAKE_PLATFORM_NO_VERSIONED_SONAME 1)
+endif()
+
+# Android reportedly ignores RPATH, and we cannot predict the install
+# location anyway.
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "")
+
+# Nsight Tegra Visual Studio Edition takes care of
+# prefixing library names with '-l'.
+if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android")
+ set(CMAKE_LINK_LIBRARY_FLAG "")
+endif()
+
+# Commonly used Android toolchain files that pre-date CMake upstream support
+# set CMAKE_SYSTEM_VERSION to 1. Avoid interfering with them.
+if(CMAKE_SYSTEM_VERSION EQUAL 1)
+ return()
+endif()
+
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+ include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/post/Android.cmake OPTIONAL)
+endif()
diff --git a/Modules/Platform/Android/Determine-Compiler-NDK.cmake b/Modules/Platform/Android/Determine-Compiler-NDK.cmake
new file mode 100644
index 0000000..a4d67c4
--- /dev/null
+++ b/Modules/Platform/Android/Determine-Compiler-NDK.cmake
@@ -0,0 +1,271 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# In Android NDK r19 and above there is a single clang toolchain.
+if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+ if(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION AND NOT CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION STREQUAL "clang")
+ message(FATAL_ERROR
+ "Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value '${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}' "
+ "is not supported by this NDK. It must be 'clang' or not set at all."
+ )
+ endif()
+ message(STATUS "Android: Selected unified Clang toolchain")
+ set(_ANDROID_TOOL_NDK_TOOLCHAIN_VERSION "clang")
+ set(_ANDROID_TOOL_C_COMPILER "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/clang${_ANDROID_HOST_EXT}")
+ set(_ANDROID_TOOL_C_TOOLCHAIN_MACHINE "${CMAKE_ANDROID_ARCH_TRIPLE}")
+ set(_ANDROID_TOOL_C_TOOLCHAIN_VERSION "")
+ set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN "")
+ set(_ANDROID_TOOL_C_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/${CMAKE_ANDROID_ARCH_TRIPLE}-")
+ set(_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX "${_ANDROID_HOST_EXT}")
+ set(_ANDROID_TOOL_CXX_COMPILER "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/clang++${_ANDROID_HOST_EXT}")
+ set(_ANDROID_TOOL_CXX_TOOLCHAIN_MACHINE "${CMAKE_ANDROID_ARCH_TRIPLE}")
+ set(_ANDROID_TOOL_CXX_TOOLCHAIN_VERSION "")
+ set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "")
+ set(_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/${CMAKE_ANDROID_ARCH_TRIPLE}-")
+ set(_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX "${_ANDROID_HOST_EXT}")
+ set(_CMAKE_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_ARCH_TRIPLE}-")
+ return()
+endif()
+
+# In Android NDK releases there is build system toolchain selection logic in
+# these files:
+#
+# * <ndk>/build/core/init.mk
+# * <ndk>/build/core/setup-toolchain.mk
+# * <ndk>/[build/core/]toolchains/<toolchain>/{config.mk,setup.mk}
+#
+# We parse information out of the ``config.mk`` and ``setup.mk`` files below.
+#
+# There is also a "toolchains" directory with the prebuilt toolchains themselves:
+#
+# * <triple-or-arch>-<gcc-version>/prebuilt/<host>/bin/<triple>-gcc(.exe)?
+# The gcc compiler to be invoked.
+#
+# * llvm*/prebuilt/<host>/bin/clang
+# The clang compiler to be invoked with flags:
+# -target <triple>
+# -gcc-toolchain <ndk>/toolchains/<triple-or-arch>-<gcc-version>
+
+# Glob available toolchains in the NDK, restricted by any version request.
+if(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION STREQUAL "clang")
+ set(_ANDROID_TOOL_PATTERNS "*-clang" "*-clang[0-9].[0-9]")
+elseif(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION)
+ if(NOT CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION MATCHES "^(clang)?[0-9]\\.[0-9]$")
+ message(FATAL_ERROR
+ "Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value '${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}' "
+ "is not one of the allowed forms:\n"
+ " <major>.<minor> = GCC of specified version\n"
+ " clang<major>.<minor> = Clang of specified version\n"
+ " clang = Clang of most recent available version\n"
+ )
+ endif()
+ set(_ANDROID_TOOL_PATTERNS "*-${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}")
+else()
+ # If we can find any gcc toolchains then use one by default.
+ # Otherwise we look for clang toolchains (e.g. NDK r18+).
+ file(GLOB _ANDROID_CONFIG_MKS_FOR_GCC
+ "${CMAKE_ANDROID_NDK}/build/core/toolchains/*-[0-9].[0-9]/config.mk"
+ "${CMAKE_ANDROID_NDK}/toolchains/*-[0-9].[0-9]/config.mk"
+ )
+ if(_ANDROID_CONFIG_MKS_FOR_GCC)
+ set(_ANDROID_TOOL_PATTERNS "*-[0-9].[0-9]")
+ else()
+ set(_ANDROID_TOOL_PATTERNS "*-clang")
+ endif()
+ unset(_ANDROID_CONFIG_MKS_FOR_GCC)
+endif()
+set(_ANDROID_CONFIG_MK_PATTERNS)
+foreach(base "build/core/toolchains" "toolchains")
+ foreach(pattern IN LISTS _ANDROID_TOOL_PATTERNS)
+ list(APPEND _ANDROID_CONFIG_MK_PATTERNS
+ "${CMAKE_ANDROID_NDK}/${base}/${pattern}/config.mk"
+ )
+ endforeach()
+endforeach()
+unset(_ANDROID_TOOL_PATTERNS)
+file(GLOB _ANDROID_CONFIG_MKS ${_ANDROID_CONFIG_MK_PATTERNS})
+unset(_ANDROID_CONFIG_MK_PATTERNS)
+
+# Find the newest toolchain version matching the ABI.
+set(_ANDROID_TOOL_NAME "")
+set(_ANDROID_TOOL_VERS 0)
+set(_ANDROID_TOOL_VERS_NDK "")
+set(_ANDROID_TOOL_SETUP_MK "")
+foreach(config_mk IN LISTS _ANDROID_CONFIG_MKS)
+ # Check that the toolchain matches the ABI.
+ file(STRINGS "${config_mk}" _ANDROID_TOOL_ABIS REGEX "^TOOLCHAIN_ABIS :=.* ${CMAKE_ANDROID_ARCH_ABI}( |$)")
+ if(NOT _ANDROID_TOOL_ABIS)
+ continue()
+ endif()
+ unset(_ANDROID_TOOL_ABIS)
+
+ # Check the version.
+ if("${config_mk}" MATCHES [[/([^/]+-((clang)?([0-9]\.[0-9]|)))/config.mk$]])
+ set(_ANDROID_CUR_NAME "${CMAKE_MATCH_1}")
+ set(_ANDROID_CUR_VERS "${CMAKE_MATCH_4}")
+ set(_ANDROID_CUR_VERS_NDK "${CMAKE_MATCH_2}")
+ if(_ANDROID_TOOL_VERS STREQUAL "")
+ # already the latest possible
+ elseif(_ANDROID_CUR_VERS STREQUAL "" OR _ANDROID_CUR_VERS VERSION_GREATER _ANDROID_TOOL_VERS)
+ set(_ANDROID_TOOL_NAME "${_ANDROID_CUR_NAME}")
+ set(_ANDROID_TOOL_VERS "${_ANDROID_CUR_VERS}")
+ set(_ANDROID_TOOL_VERS_NDK "${_ANDROID_CUR_VERS_NDK}")
+ string(REPLACE "/config.mk" "/setup.mk" _ANDROID_TOOL_SETUP_MK "${config_mk}")
+ endif()
+ unset(_ANDROID_CUR_TOOL)
+ unset(_ANDROID_CUR_VERS)
+ unset(_ANDROID_CUR_VERS_NDK)
+ endif()
+endforeach()
+
+# Verify that we have a suitable toolchain.
+if(NOT _ANDROID_TOOL_NAME)
+ if(_ANDROID_CONFIG_MKS)
+ string(REPLACE ";" "\n " _ANDROID_TOOLS_MSG "after considering:;${_ANDROID_CONFIG_MKS}")
+ else()
+ set(_ANDROID_TOOLS_MSG "")
+ endif()
+ if(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION)
+ string(CONCAT _ANDROID_TOOLS_MSG
+ "of the version specified by CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION:\n"
+ " ${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}\n"
+ "${_ANDROID_TOOLS_MSG}")
+ endif()
+ message(FATAL_ERROR
+ "Android: No toolchain for ABI '${CMAKE_ANDROID_ARCH_ABI}' found in the NDK:\n"
+ " ${CMAKE_ANDROID_NDK}\n"
+ "${_ANDROID_TOOLS_MSG}"
+ )
+endif()
+unset(_ANDROID_CONFIG_MKS)
+
+# For clang toolchains we still need to find a gcc toolchain.
+if(_ANDROID_TOOL_NAME MATCHES "-clang")
+ set(_ANDROID_TOOL_CLANG_NAME "${_ANDROID_TOOL_NAME}")
+ set(_ANDROID_TOOL_CLANG_VERS "${_ANDROID_TOOL_VERS}")
+ set(_ANDROID_TOOL_NAME "")
+ set(_ANDROID_TOOL_VERS "")
+else()
+ set(_ANDROID_TOOL_CLANG_NAME "")
+ set(_ANDROID_TOOL_CLANG_VERS "")
+endif()
+
+# Parse the toolchain setup.mk file to extract information we need.
+# Their content is not standardized across toolchains or NDK versions,
+# so we match known cases. Note that the parsing is stateful across
+# lines because we need to substitute for some Make variable references.
+if(CMAKE_ANDROID_NDK_TOOLCHAIN_DEBUG)
+ message(STATUS "loading: ${_ANDROID_TOOL_SETUP_MK}")
+endif()
+file(STRINGS "${_ANDROID_TOOL_SETUP_MK}" _ANDROID_TOOL_SETUP REGEX "^(LLVM|TOOLCHAIN)_[A-Z_]+ +:= +.*$")
+unset(_ANDROID_TOOL_SETUP_MK)
+set(_ANDROID_TOOL_PREFIX "")
+set(_ANDROID_TOOL_NAME_ONLY "")
+set(_ANDROID_TOOL_LLVM_NAME "llvm")
+set(_ANDROID_TOOL_LLVM_VERS "")
+foreach(line IN LISTS _ANDROID_TOOL_SETUP)
+ if(CMAKE_ANDROID_NDK_TOOLCHAIN_DEBUG)
+ message(STATUS "setup.mk: ${line}")
+ endif()
+
+ if(line MATCHES [[^TOOLCHAIN_PREFIX +:= +.*/bin/([^$/ ]*) *$]])
+ # We just matched the toolchain prefix with no Make variable references.
+ set(_ANDROID_TOOL_PREFIX "${CMAKE_MATCH_1}")
+ elseif(_ANDROID_TOOL_CLANG_NAME)
+ # For clang toolchains we need to find more information.
+ if(line MATCHES [[^TOOLCHAIN_VERSION +:= +([0-9.]+) *$]])
+ # We just matched the gcc toolchain version number. Save it for later.
+ set(_ANDROID_TOOL_VERS "${CMAKE_MATCH_1}")
+ elseif(line MATCHES [[^TOOLCHAIN_NAME +:= +(.*\$\(TOOLCHAIN_VERSION\)) *$]])
+ # We just matched the gcc toolchain name with a version number placeholder, so substitute it.
+ # The gcc toolchain version number will have already been extracted from a TOOLCHAIN_VERSION line.
+ string(REPLACE "$(TOOLCHAIN_VERSION)" "${_ANDROID_TOOL_VERS}" _ANDROID_TOOL_NAME "${CMAKE_MATCH_1}")
+ elseif(line MATCHES [[^TOOLCHAIN_NAME +:= +([^$/ ]+) *$]])
+ # We just matched the gcc toolchain name without version number. Save it for later.
+ set(_ANDROID_TOOL_NAME_ONLY "${CMAKE_MATCH_1}")
+ elseif(line MATCHES [[^TOOLCHAIN_PREFIX +:= +.*/bin/(\$\(TOOLCHAIN_NAME\)-) *$]])
+ # We just matched the toolchain prefix with a name placeholder, so substitute it.
+ # The gcc toolchain name will have already been extracted without version number from a TOOLCHAIN_NAME line.
+ string(REPLACE "$(TOOLCHAIN_NAME)" "${_ANDROID_TOOL_NAME_ONLY}" _ANDROID_TOOL_PREFIX "${CMAKE_MATCH_1}")
+ elseif(line MATCHES [[^LLVM_VERSION +:= +([0-9.]+)$]])
+ # We just matched the llvm prebuilt binary toolchain version number. Save it for later.
+ set(_ANDROID_TOOL_LLVM_VERS "${CMAKE_MATCH_1}")
+ elseif(line MATCHES [[^LLVM_NAME +:= +(llvm-\$\(LLVM_VERSION\)) *$]])
+ # We just matched the llvm prebuilt binary toolchain directory name with a version number placeholder,
+ # so substitute it. The llvm prebuilt binary toolchain version number will have already been extracted
+ # from a LLVM_VERSION line.
+ string(REPLACE "$(LLVM_VERSION)" "${_ANDROID_TOOL_LLVM_VERS}" _ANDROID_TOOL_LLVM_NAME "${CMAKE_MATCH_1}")
+ elseif(line MATCHES [[^LLVM_TOOLCHAIN_PREBUILT_ROOT +:= +\$\(call get-toolchain-root.*,([^$ ]+)\) *$]])
+ # We just matched the llvm prebuilt binary toolchain directory name.
+ set(_ANDROID_TOOL_LLVM_NAME "${CMAKE_MATCH_1}")
+ elseif(line MATCHES [[^TOOLCHAIN_ROOT +:= +\$\(call get-toolchain-root.*,(\$\(TOOLCHAIN_NAME\)-[0-9.]+)\) *$]])
+ # We just matched a placeholder for the name followed by a version number.
+ # The gcc toolchain name will have already been extracted without version number from a TOOLCHAIN_NAME line.
+ # Substitute for the placeholder to get the full gcc toolchain name.
+ string(REPLACE "$(TOOLCHAIN_NAME)" "${_ANDROID_TOOL_NAME_ONLY}" _ANDROID_TOOL_NAME "${CMAKE_MATCH_1}")
+ elseif(line MATCHES [[^TOOLCHAIN_ROOT +:= +\$\(call get-toolchain-root.*,([^$ ]+)\) *$]])
+ # We just matched the full gcc toolchain name without placeholder.
+ set(_ANDROID_TOOL_NAME "${CMAKE_MATCH_1}")
+ endif()
+ endif()
+endforeach()
+unset(_ANDROID_TOOL_NAME_ONLY)
+unset(_ANDROID_TOOL_LLVM_VERS)
+unset(_ANDROID_TOOL_SETUP)
+
+# Fall back to parsing the version and prefix from the tool name.
+if(NOT _ANDROID_TOOL_VERS AND "${_ANDROID_TOOL_NAME}" MATCHES "-([0-9.]+)$")
+ set(_ANDROID_TOOL_VERS "${CMAKE_MATCH_1}")
+endif()
+if(NOT _ANDROID_TOOL_PREFIX AND "${_ANDROID_TOOL_NAME}" MATCHES "^(.*-)[0-9.]+$")
+ set(_ANDROID_TOOL_PREFIX "${CMAKE_MATCH_1}")
+endif()
+
+# Help CMakeFindBinUtils locate things.
+set(_CMAKE_TOOLCHAIN_PREFIX "${_ANDROID_TOOL_PREFIX}")
+
+set(_ANDROID_TOOL_NDK_TOOLCHAIN_VERSION "${_ANDROID_TOOL_VERS_NDK}")
+
+# _ANDROID_TOOL_PREFIX should now match `gcc -dumpmachine`.
+string(REGEX REPLACE "-$" "" _ANDROID_TOOL_C_TOOLCHAIN_MACHINE "${_ANDROID_TOOL_PREFIX}")
+
+set(_ANDROID_TOOL_C_TOOLCHAIN_VERSION "${_ANDROID_TOOL_VERS}")
+set(_ANDROID_TOOL_C_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_NAME}/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}/bin/${_ANDROID_TOOL_PREFIX}")
+set(_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX "${_ANDROID_HOST_EXT}")
+
+set(_ANDROID_TOOL_CXX_TOOLCHAIN_MACHINE "${_ANDROID_TOOL_C_TOOLCHAIN_MACHINE}")
+set(_ANDROID_TOOL_CXX_TOOLCHAIN_VERSION "${_ANDROID_TOOL_C_TOOLCHAIN_VERSION}")
+set(_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX "${_ANDROID_TOOL_C_TOOLCHAIN_PREFIX}")
+set(_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX "${_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX}")
+
+if(_ANDROID_TOOL_CLANG_NAME)
+ message(STATUS "Android: Selected Clang toolchain '${_ANDROID_TOOL_CLANG_NAME}' with GCC toolchain '${_ANDROID_TOOL_NAME}'")
+ set(_ANDROID_TOOL_C_COMPILER "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_LLVM_NAME}/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}/bin/clang${_ANDROID_HOST_EXT}")
+ set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN ${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_NAME}/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG})
+ set(_ANDROID_TOOL_CXX_COMPILER "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_LLVM_NAME}/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}/bin/clang++${_ANDROID_HOST_EXT}")
+ set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "${_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN}")
+else()
+ message(STATUS "Android: Selected GCC toolchain '${_ANDROID_TOOL_NAME}'")
+ set(_ANDROID_TOOL_C_COMPILER "${_ANDROID_TOOL_C_TOOLCHAIN_PREFIX}gcc${_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX}")
+ set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN "")
+ set(_ANDROID_TOOL_CXX_COMPILER "${_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX}g++${_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX}")
+ set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "")
+endif()
+
+if(CMAKE_ANDROID_NDK_TOOLCHAIN_DEBUG)
+ message(STATUS "_ANDROID_TOOL_NAME=${_ANDROID_TOOL_NAME}")
+ message(STATUS "_ANDROID_TOOL_VERS=${_ANDROID_TOOL_VERS}")
+ message(STATUS "_ANDROID_TOOL_VERS_NDK=${_ANDROID_TOOL_VERS_NDK}")
+ message(STATUS "_ANDROID_TOOL_PREFIX=${_ANDROID_TOOL_PREFIX}")
+ message(STATUS "_ANDROID_TOOL_CLANG_NAME=${_ANDROID_TOOL_CLANG_NAME}")
+ message(STATUS "_ANDROID_TOOL_CLANG_VERS=${_ANDROID_TOOL_CLANG_VERS}")
+ message(STATUS "_ANDROID_TOOL_LLVM_NAME=${_ANDROID_TOOL_LLVM_NAME}")
+endif()
+
+unset(_ANDROID_TOOL_NAME)
+unset(_ANDROID_TOOL_VERS)
+unset(_ANDROID_TOOL_VERS_NDK)
+unset(_ANDROID_TOOL_PREFIX)
+unset(_ANDROID_TOOL_CLANG_NAME)
+unset(_ANDROID_TOOL_CLANG_VERS)
+unset(_ANDROID_TOOL_LLVM_NAME)
diff --git a/Modules/Platform/Android/Determine-Compiler-Standalone.cmake b/Modules/Platform/Android/Determine-Compiler-Standalone.cmake
new file mode 100644
index 0000000..5095aff
--- /dev/null
+++ b/Modules/Platform/Android/Determine-Compiler-Standalone.cmake
@@ -0,0 +1,65 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+set(_ANDROID_TOOL_C_COMPILER "")
+set(_ANDROID_TOOL_CXX_COMPILER "")
+set(_ANDROID_TOOL_PREFIX "")
+file(GLOB _gcc "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/*-gcc${_ANDROID_HOST_EXT}")
+foreach(gcc IN LISTS _gcc)
+ if("${gcc}" MATCHES "/bin/([^/]*)gcc${_ANDROID_HOST_EXT}$")
+ set(_ANDROID_TOOL_PREFIX "${CMAKE_MATCH_1}")
+ break()
+ endif()
+endforeach()
+
+if(NOT _ANDROID_TOOL_PREFIX)
+ message(FATAL_ERROR
+ "Android: No '*-gcc' compiler found in CMAKE_ANDROID_STANDALONE_TOOLCHAIN:\n"
+ " ${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}"
+ )
+endif()
+
+# Help CMakeFindBinUtils locate things.
+set(_CMAKE_TOOLCHAIN_PREFIX "${_ANDROID_TOOL_PREFIX}")
+
+# _ANDROID_TOOL_PREFIX should now match `gcc -dumpmachine`.
+string(REGEX REPLACE "-$" "" _ANDROID_TOOL_C_TOOLCHAIN_MACHINE "${_ANDROID_TOOL_PREFIX}")
+
+execute_process(
+ COMMAND "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/${_ANDROID_TOOL_PREFIX}gcc${_ANDROID_HOST_EXT}" -dumpversion
+ OUTPUT_VARIABLE _gcc_version
+ ERROR_VARIABLE _gcc_error
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+if(_gcc_version MATCHES "^([0-9]+\\.[0-9]+)")
+ set(_ANDROID_TOOL_C_TOOLCHAIN_VERSION "${CMAKE_MATCH_1}")
+else()
+ message(FATAL_ERROR
+ "Android: Failed to extract the standalone toolchain version. The command:\n"
+ " '${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/${_ANDROID_TOOL_PREFIX}gcc${_ANDROID_HOST_EXT}' '-dumpversion'\n"
+ "produced output:\n"
+ " ${_gcc_version}\n"
+ )
+endif()
+
+set(_ANDROID_TOOL_C_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/${_ANDROID_TOOL_PREFIX}")
+set(_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX "${_ANDROID_HOST_EXT}")
+
+set(_ANDROID_TOOL_CXX_TOOLCHAIN_MACHINE "${_ANDROID_TOOL_C_TOOLCHAIN_MACHINE}")
+set(_ANDROID_TOOL_CXX_TOOLCHAIN_VERSION "${_ANDROID_TOOL_C_TOOLCHAIN_VERSION}")
+set(_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX "${_ANDROID_TOOL_C_TOOLCHAIN_PREFIX}")
+set(_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX "${_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX}")
+
+if(EXISTS "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/clang${_ANDROID_HOST_EXT}")
+ set(_ANDROID_TOOL_C_COMPILER "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/clang${_ANDROID_HOST_EXT}")
+ set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}")
+ set(_ANDROID_TOOL_CXX_COMPILER "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/clang++${_ANDROID_HOST_EXT}")
+ set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}")
+else()
+ set(_ANDROID_TOOL_C_COMPILER "${_ANDROID_TOOL_C_TOOLCHAIN_PREFIX}gcc${_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX}")
+ set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN "")
+ set(_ANDROID_TOOL_CXX_COMPILER "${_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX}g++${_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX}")
+ set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "")
+endif()
+
+set(_ANDROID_TOOL_NDK_TOOLCHAIN_VERSION "")
diff --git a/Modules/Platform/Android/Determine-Compiler.cmake b/Modules/Platform/Android/Determine-Compiler.cmake
new file mode 100644
index 0000000..f8eae62
--- /dev/null
+++ b/Modules/Platform/Android/Determine-Compiler.cmake
@@ -0,0 +1,97 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This module is shared by multiple languages; use include blocker.
+if(__ANDROID_DETERMINE_COMPILER)
+ return()
+endif()
+set(__ANDROID_DETERMINE_COMPILER 1)
+
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+ include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/pre/Determine-Compiler.cmake OPTIONAL)
+endif()
+
+# Support for NVIDIA Nsight Tegra Visual Studio Edition was previously
+# implemented in the CMake VS IDE generators. Avoid interfering with
+# that functionality for now. Later we may try to integrate this.
+if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android")
+ macro(__android_determine_compiler lang)
+ endmacro()
+ return()
+endif()
+
+# Commonly used Android toolchain files that pre-date CMake upstream support
+# set CMAKE_SYSTEM_VERSION to 1. Avoid interfering with them.
+if(CMAKE_SYSTEM_VERSION EQUAL 1)
+ macro(__android_determine_compiler lang)
+ endmacro()
+ return()
+endif()
+
+# Identify the host platform.
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
+ set(_ANDROID_HOST_EXT "")
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
+ set(_ANDROID_HOST_EXT "")
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+ set(_ANDROID_HOST_EXT ".exe")
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Android")
+ # Natively compiling on an Android host doesn't use the NDK cross-compilation
+ # tools.
+ macro(__android_determine_compiler lang)
+ # Do nothing
+ endmacro()
+ if(NOT CMAKE_CXX_COMPILER_NAMES)
+ set(CMAKE_CXX_COMPILER_NAMES c++)
+ endif()
+ return()
+else()
+ message(FATAL_ERROR "Android: Builds hosted on '${CMAKE_HOST_SYSTEM_NAME}' not supported.")
+endif()
+
+if(CMAKE_ANDROID_NDK)
+ include(Platform/Android/Determine-Compiler-NDK)
+elseif(CMAKE_ANDROID_STANDALONE_TOOLCHAIN)
+ include(Platform/Android/Determine-Compiler-Standalone)
+else()
+ set(_ANDROID_TOOL_NDK_TOOLCHAIN_VERSION "")
+ set(_ANDROID_TOOL_C_COMPILER "")
+ set(_ANDROID_TOOL_C_TOOLCHAIN_MACHINE "")
+ set(_ANDROID_TOOL_C_TOOLCHAIN_VERSION "")
+ set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN "")
+ set(_ANDROID_TOOL_C_TOOLCHAIN_PREFIX "")
+ set(_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX "")
+ set(_ANDROID_TOOL_CXX_COMPILER "")
+ set(_ANDROID_TOOL_CXX_TOOLCHAIN_MACHINE "")
+ set(_ANDROID_TOOL_CXX_TOOLCHAIN_VERSION "")
+ set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "")
+ set(_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX "")
+ set(_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX "")
+endif()
+
+unset(_ANDROID_HOST_EXT)
+
+macro(__android_determine_compiler lang)
+ if(_ANDROID_TOOL_${lang}_COMPILER)
+ set(CMAKE_${lang}_COMPILER "${_ANDROID_TOOL_${lang}_COMPILER}")
+ set(CMAKE_${lang}_COMPILER_EXTERNAL_TOOLCHAIN "${_ANDROID_TOOL_${lang}_COMPILER_EXTERNAL_TOOLCHAIN}")
+
+ # Save the Android-specific information in CMake${lang}Compiler.cmake.
+ set(CMAKE_${lang}_COMPILER_CUSTOM_CODE "
+set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION \"${_ANDROID_TOOL_NDK_TOOLCHAIN_VERSION}\")
+set(CMAKE_${lang}_ANDROID_TOOLCHAIN_MACHINE \"${_ANDROID_TOOL_${lang}_TOOLCHAIN_MACHINE}\")
+set(CMAKE_${lang}_ANDROID_TOOLCHAIN_VERSION \"${_ANDROID_TOOL_${lang}_TOOLCHAIN_VERSION}\")
+set(CMAKE_${lang}_COMPILER_EXTERNAL_TOOLCHAIN \"${_ANDROID_TOOL_${lang}_COMPILER_EXTERNAL_TOOLCHAIN}\")
+set(CMAKE_${lang}_ANDROID_TOOLCHAIN_PREFIX \"${_ANDROID_TOOL_${lang}_TOOLCHAIN_PREFIX}\")
+set(CMAKE_${lang}_ANDROID_TOOLCHAIN_SUFFIX \"${_ANDROID_TOOL_${lang}_TOOLCHAIN_SUFFIX}\")
+")
+ endif()
+endmacro()
+
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+ include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/post/Determine-Compiler.cmake OPTIONAL)
+endif()
diff --git a/Modules/Platform/Android/VCXProjInspect.vcxproj.in b/Modules/Platform/Android/VCXProjInspect.vcxproj.in
new file mode 100644
index 0000000..6919d2c
--- /dev/null
+++ b/Modules/Platform/Android/VCXProjInspect.vcxproj.in
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|@vcx_platform@">
+ <Configuration>Debug</Configuration>
+ <Platform>@vcx_platform@</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{14D44772-ECF7-47BD-9E29-BC62FAF940A5}</ProjectGuid>
+ <RootNamespace>VCXProjInspect</RootNamespace>
+ <Keyword>Android</Keyword>
+ <ApplicationType>Android</ApplicationType>
+ <ApplicationTypeRevision>@vcx_revision@</ApplicationTypeRevision>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@vcx_platform@'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|@vcx_platform@'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@vcx_platform@'">
+ <PostBuildEvent>
+ <Command>%40echo CMAKE_SYSROOT=$(@vcx_sysroot_var@)</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
diff --git a/Modules/Platform/Android/abi-arm64-v8a-Clang.cmake b/Modules/Platform/Android/abi-arm64-v8a-Clang.cmake
new file mode 100644
index 0000000..c18c0a2
--- /dev/null
+++ b/Modules/Platform/Android/abi-arm64-v8a-Clang.cmake
@@ -0,0 +1,4 @@
+# Suppress -Wl,-z,nocopyreloc flag on arm64-v8a
+set(_ANDROID_ABI_INIT_EXE_LDFLAGS_NO_nocopyreloc 1)
+
+include(Platform/Android/abi-common-Clang)
diff --git a/Modules/Platform/Android/abi-arm64-v8a-GNU.cmake b/Modules/Platform/Android/abi-arm64-v8a-GNU.cmake
new file mode 100644
index 0000000..b71a674
--- /dev/null
+++ b/Modules/Platform/Android/abi-arm64-v8a-GNU.cmake
@@ -0,0 +1,6 @@
+# <ndk>/build/core/toolchains/aarch64-linux-android-4.9/setup.mk
+
+# Suppress -Wl,-z,nocopyreloc flag on arm64-v8a
+set(_ANDROID_ABI_INIT_EXE_LDFLAGS_NO_nocopyreloc 1)
+
+include(Platform/Android/abi-common-GNU)
diff --git a/Modules/Platform/Android/abi-armeabi-Clang.cmake b/Modules/Platform/Android/abi-armeabi-Clang.cmake
new file mode 100644
index 0000000..2b1de03
--- /dev/null
+++ b/Modules/Platform/Android/abi-armeabi-Clang.cmake
@@ -0,0 +1,16 @@
+string(APPEND _ANDROID_ABI_INIT_CFLAGS
+ " -march=armv5te"
+ )
+
+if(CMAKE_ANDROID_ARM_MODE)
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -marm")
+else()
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mthumb")
+endif()
+
+string(APPEND _ANDROID_ABI_INIT_CFLAGS
+ " -msoft-float"
+ " -mtune=xscale"
+ )
+
+include(Platform/Android/abi-common-Clang)
diff --git a/Modules/Platform/Android/abi-armeabi-GNU.cmake b/Modules/Platform/Android/abi-armeabi-GNU.cmake
new file mode 100644
index 0000000..33e8b31
--- /dev/null
+++ b/Modules/Platform/Android/abi-armeabi-GNU.cmake
@@ -0,0 +1,17 @@
+# <ndk>/build/core/toolchains/arm-linux-androideabi-4.9/setup.mk
+string(APPEND _ANDROID_ABI_INIT_CFLAGS
+ " -march=armv5te"
+ )
+
+if(CMAKE_ANDROID_ARM_MODE)
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -marm")
+else()
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mthumb")
+endif()
+
+string(APPEND _ANDROID_ABI_INIT_CFLAGS
+ " -msoft-float"
+ " -mtune=xscale"
+ )
+
+include(Platform/Android/abi-common-GNU)
diff --git a/Modules/Platform/Android/abi-armeabi-v6-Clang.cmake b/Modules/Platform/Android/abi-armeabi-v6-Clang.cmake
new file mode 100644
index 0000000..bb176ae
--- /dev/null
+++ b/Modules/Platform/Android/abi-armeabi-v6-Clang.cmake
@@ -0,0 +1,15 @@
+string(APPEND _ANDROID_ABI_INIT_CFLAGS
+ " -march=armv6"
+ )
+
+if(CMAKE_ANDROID_ARM_MODE)
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -marm")
+else()
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mthumb")
+endif()
+
+string(APPEND _ANDROID_ABI_INIT_CFLAGS
+ " -mfloat-abi=softfp"
+ )
+
+include(Platform/Android/abi-common-Clang)
diff --git a/Modules/Platform/Android/abi-armeabi-v6-GNU.cmake b/Modules/Platform/Android/abi-armeabi-v6-GNU.cmake
new file mode 100644
index 0000000..1fda184
--- /dev/null
+++ b/Modules/Platform/Android/abi-armeabi-v6-GNU.cmake
@@ -0,0 +1,16 @@
+# <ndk>/build/core/toolchains/arm-linux-androideabi-4.9/setup.mk
+string(APPEND _ANDROID_ABI_INIT_CFLAGS
+ " -march=armv6"
+ )
+
+if(CMAKE_ANDROID_ARM_MODE)
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -marm")
+else()
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mthumb")
+endif()
+
+string(APPEND _ANDROID_ABI_INIT_CFLAGS
+ " -mfloat-abi=softfp"
+ )
+
+include(Platform/Android/abi-common-GNU)
diff --git a/Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake b/Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake
new file mode 100644
index 0000000..6feeef6
--- /dev/null
+++ b/Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake
@@ -0,0 +1,25 @@
+string(APPEND _ANDROID_ABI_INIT_CFLAGS
+ " -march=armv7-a"
+ )
+
+if(CMAKE_ANDROID_ARM_MODE)
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -marm")
+else()
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mthumb")
+endif()
+
+if(CMAKE_ANDROID_ARM_NEON)
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mfpu=neon")
+else()
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mfpu=vfpv3-d16")
+endif()
+
+string(APPEND _ANDROID_ABI_INIT_LDFLAGS
+ " -Wl,--fix-cortex-a8"
+ )
+
+string(APPEND _ANDROID_ABI_INIT_CFLAGS
+ " -mfloat-abi=softfp"
+ )
+
+include(Platform/Android/abi-common-Clang)
diff --git a/Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake b/Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake
new file mode 100644
index 0000000..b7c328d
--- /dev/null
+++ b/Modules/Platform/Android/abi-armeabi-v7a-GNU.cmake
@@ -0,0 +1,26 @@
+# <ndk>/build/core/toolchains/arm-linux-androideabi-4.9/setup.mk
+string(APPEND _ANDROID_ABI_INIT_CFLAGS
+ " -march=armv7-a"
+ )
+
+if(CMAKE_ANDROID_ARM_MODE)
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -marm")
+else()
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mthumb")
+endif()
+
+if(CMAKE_ANDROID_ARM_NEON)
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mfpu=neon")
+else()
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -mfpu=vfpv3-d16")
+endif()
+
+string(APPEND _ANDROID_ABI_INIT_CFLAGS
+ " -mfloat-abi=softfp"
+ )
+
+string(APPEND _ANDROID_ABI_INIT_LDFLAGS
+ " -Wl,--fix-cortex-a8"
+ )
+
+include(Platform/Android/abi-common-GNU)
diff --git a/Modules/Platform/Android/abi-common-Clang.cmake b/Modules/Platform/Android/abi-common-Clang.cmake
new file mode 100644
index 0000000..6025170
--- /dev/null
+++ b/Modules/Platform/Android/abi-common-Clang.cmake
@@ -0,0 +1,6 @@
+string(APPEND _ANDROID_ABI_INIT_CFLAGS
+ #" -Wno-invalid-command-line-argument"
+ #" -Wno-unused-command-line-argument"
+ )
+
+include(Platform/Android/abi-common)
diff --git a/Modules/Platform/Android/abi-common-GNU.cmake b/Modules/Platform/Android/abi-common-GNU.cmake
new file mode 100644
index 0000000..40d829f
--- /dev/null
+++ b/Modules/Platform/Android/abi-common-GNU.cmake
@@ -0,0 +1 @@
+include(Platform/Android/abi-common)
diff --git a/Modules/Platform/Android/abi-common.cmake b/Modules/Platform/Android/abi-common.cmake
new file mode 100644
index 0000000..b01ef61
--- /dev/null
+++ b/Modules/Platform/Android/abi-common.cmake
@@ -0,0 +1,39 @@
+string(APPEND _ANDROID_ABI_INIT_CFLAGS
+ " -funwind-tables"
+ " -no-canonical-prefixes"
+ )
+
+if(CMAKE_ANDROID_NDK AND NOT CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED AND NOT CMAKE_ANDROID_NDK_DEPRECATED_HEADERS)
+ string(APPEND _ANDROID_ABI_INIT_CFLAGS " -D__ANDROID_API__=${CMAKE_SYSTEM_VERSION}")
+endif()
+
+if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE
+ AND NOT CMAKE_SYSTEM_VERSION VERSION_LESS 16)
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+endif()
+
+cmake_policy(GET CMP0083 _CMP0083)
+if(_CMP0083 STREQUAL NEW)
+ # PIE Flags are managed by compiler configuration files
+ if(CMAKE_SYSTEM_VERSION VERSION_GREATER_EQUAL 16)
+ # ensure PIE flags are passed to the linker
+ set(CMAKE_C_LINK_PIE_SUPPORTED YES CACHE INTERNAL "PIE (C)")
+ set(CMAKE_CXX_LINK_PIE_SUPPORTED YES CACHE INTERNAL "PIE (CXX)")
+ if(CMAKE_SYSTEM_VERSION VERSION_GREATER_EQUAL 21)
+ # no PIE executable are no longer supported
+ set(CMAKE_C_LINK_NO_PIE_SUPPORTED NO CACHE INTERNAL "NO_PIE (C)")
+ set(CMAKE_CXX_LINK_NO_PIE_SUPPORTED NO CACHE INTERNAL "NO_PIE (CXX)")
+ endif()
+ endif()
+else()
+ if(CMAKE_POSITION_INDEPENDENT_CODE)
+ string(APPEND _ANDROID_ABI_INIT_EXE_LDFLAGS " -fPIE -pie")
+ endif()
+endif()
+unset(_CMP0083)
+
+string(APPEND _ANDROID_ABI_INIT_EXE_LDFLAGS " -Wl,--gc-sections")
+
+if(NOT _ANDROID_ABI_INIT_EXE_LDFLAGS_NO_nocopyreloc)
+ string(APPEND _ANDROID_ABI_INIT_EXE_LDFLAGS " -Wl,-z,nocopyreloc")
+endif()
diff --git a/Modules/Platform/Android/abi-mips-Clang.cmake b/Modules/Platform/Android/abi-mips-Clang.cmake
new file mode 100644
index 0000000..7df6a36
--- /dev/null
+++ b/Modules/Platform/Android/abi-mips-Clang.cmake
@@ -0,0 +1 @@
+include(Platform/Android/abi-common-Clang)
diff --git a/Modules/Platform/Android/abi-mips-GNU.cmake b/Modules/Platform/Android/abi-mips-GNU.cmake
new file mode 100644
index 0000000..982ad46
--- /dev/null
+++ b/Modules/Platform/Android/abi-mips-GNU.cmake
@@ -0,0 +1,3 @@
+# <ndk>/build/core/toolchains/mipsel-linux-android-4.9/setup.mk
+
+include(Platform/Android/abi-common-GNU)
diff --git a/Modules/Platform/Android/abi-mips64-Clang.cmake b/Modules/Platform/Android/abi-mips64-Clang.cmake
new file mode 100644
index 0000000..7df6a36
--- /dev/null
+++ b/Modules/Platform/Android/abi-mips64-Clang.cmake
@@ -0,0 +1 @@
+include(Platform/Android/abi-common-Clang)
diff --git a/Modules/Platform/Android/abi-mips64-GNU.cmake b/Modules/Platform/Android/abi-mips64-GNU.cmake
new file mode 100644
index 0000000..a1bc2c2
--- /dev/null
+++ b/Modules/Platform/Android/abi-mips64-GNU.cmake
@@ -0,0 +1,3 @@
+# <ndk>/build/core/toolchains/mips64el-linux-android-4.9/setup.mk
+
+include(Platform/Android/abi-common-GNU)
diff --git a/Modules/Platform/Android/abi-x86-Clang.cmake b/Modules/Platform/Android/abi-x86-Clang.cmake
new file mode 100644
index 0000000..7df6a36
--- /dev/null
+++ b/Modules/Platform/Android/abi-x86-Clang.cmake
@@ -0,0 +1 @@
+include(Platform/Android/abi-common-Clang)
diff --git a/Modules/Platform/Android/abi-x86-GNU.cmake b/Modules/Platform/Android/abi-x86-GNU.cmake
new file mode 100644
index 0000000..76ea5ca
--- /dev/null
+++ b/Modules/Platform/Android/abi-x86-GNU.cmake
@@ -0,0 +1,2 @@
+# <ndk>/build/core/toolchains/x86-4.9/setup.mk
+include(Platform/Android/abi-common-GNU)
diff --git a/Modules/Platform/Android/abi-x86_64-Clang.cmake b/Modules/Platform/Android/abi-x86_64-Clang.cmake
new file mode 100644
index 0000000..7df6a36
--- /dev/null
+++ b/Modules/Platform/Android/abi-x86_64-Clang.cmake
@@ -0,0 +1 @@
+include(Platform/Android/abi-common-Clang)
diff --git a/Modules/Platform/Android/abi-x86_64-GNU.cmake b/Modules/Platform/Android/abi-x86_64-GNU.cmake
new file mode 100644
index 0000000..441bdcd
--- /dev/null
+++ b/Modules/Platform/Android/abi-x86_64-GNU.cmake
@@ -0,0 +1,2 @@
+# <ndk>/build/core/toolchains/x86_64-4.9/setup.mk
+include(Platform/Android/abi-common-GNU)
diff --git a/Modules/Platform/Android/ndk-stl-c++.cmake b/Modules/Platform/Android/ndk-stl-c++.cmake
new file mode 100644
index 0000000..1cafd1f
--- /dev/null
+++ b/Modules/Platform/Android/ndk-stl-c++.cmake
@@ -0,0 +1,21 @@
+# <ndk>/sources/cxx-stl/llvm-libc++/Android.mk
+set(_ANDROID_STL_RTTI 1)
+set(_ANDROID_STL_EXCEPTIONS 1)
+set(_ANDROID_STL_NOSTDLIBXX 1)
+macro(__android_stl_cxx lang filename)
+ # Add the include directory.
+ if(EXISTS "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libcxx/include/cstddef")
+ # r12 and below
+ __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libcxx/include" 1)
+ __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/android/support/include" 0)
+ __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++abi/libcxxabi/include" 1)
+ else()
+ # r13 and above
+ __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/include" 1)
+ __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/android/support/include" 0)
+ __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++abi/include" 1)
+ endif()
+
+ # Add the library file.
+ __android_stl_lib(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/${CMAKE_ANDROID_ARCH_ABI}/${filename}" 1)
+endmacro()
diff --git a/Modules/Platform/Android/ndk-stl-c++_shared.cmake b/Modules/Platform/Android/ndk-stl-c++_shared.cmake
new file mode 100644
index 0000000..3389408
--- /dev/null
+++ b/Modules/Platform/Android/ndk-stl-c++_shared.cmake
@@ -0,0 +1,5 @@
+include(Platform/Android/ndk-stl-c++)
+macro(__android_stl lang)
+ __android_stl_cxx(${lang} libc++_shared.so)
+ __android_stl_lib(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/${CMAKE_ANDROID_ARCH_ABI}/libandroid_support.a" 0)
+endmacro()
diff --git a/Modules/Platform/Android/ndk-stl-c++_static.cmake b/Modules/Platform/Android/ndk-stl-c++_static.cmake
new file mode 100644
index 0000000..061a5c2
--- /dev/null
+++ b/Modules/Platform/Android/ndk-stl-c++_static.cmake
@@ -0,0 +1,8 @@
+include(Platform/Android/ndk-stl-c++)
+macro(__android_stl lang)
+ __android_stl_cxx(${lang} libc++_static.a)
+ __android_stl_lib(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/${CMAKE_ANDROID_ARCH_ABI}/libc++abi.a" 0)
+ __android_stl_lib(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/${CMAKE_ANDROID_ARCH_ABI}/libandroid_support.a" 0)
+ __android_stl_lib(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/${CMAKE_ANDROID_ARCH_ABI}/libunwind.a" 0)
+ string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " -latomic") # provided by toolchain
+endmacro()
diff --git a/Modules/Platform/Android/ndk-stl-gabi++.cmake b/Modules/Platform/Android/ndk-stl-gabi++.cmake
new file mode 100644
index 0000000..d3b9e45
--- /dev/null
+++ b/Modules/Platform/Android/ndk-stl-gabi++.cmake
@@ -0,0 +1,8 @@
+# <ndk>/sources/cxx-stl/gabi++/Android.mk
+set(_ANDROID_STL_RTTI 1)
+set(_ANDROID_STL_EXCEPTIONS 1)
+set(_ANDROID_STL_NOSTDLIBXX 1)
+macro(__android_stl_gabixx lang filename)
+ __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/gabi++/include" 1)
+ __android_stl_lib(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/gabi++/libs/${CMAKE_ANDROID_ARCH_ABI}/${filename}" 1)
+endmacro()
diff --git a/Modules/Platform/Android/ndk-stl-gabi++_shared.cmake b/Modules/Platform/Android/ndk-stl-gabi++_shared.cmake
new file mode 100644
index 0000000..314c1e0
--- /dev/null
+++ b/Modules/Platform/Android/ndk-stl-gabi++_shared.cmake
@@ -0,0 +1,4 @@
+include(Platform/Android/ndk-stl-gabi++)
+macro(__android_stl lang)
+ __android_stl_gabixx(${lang} libgabi++_shared.so)
+endmacro()
diff --git a/Modules/Platform/Android/ndk-stl-gabi++_static.cmake b/Modules/Platform/Android/ndk-stl-gabi++_static.cmake
new file mode 100644
index 0000000..f4a1d3c
--- /dev/null
+++ b/Modules/Platform/Android/ndk-stl-gabi++_static.cmake
@@ -0,0 +1,4 @@
+include(Platform/Android/ndk-stl-gabi++)
+macro(__android_stl lang)
+ __android_stl_gabixx(${lang} libgabi++_static.a)
+endmacro()
diff --git a/Modules/Platform/Android/ndk-stl-gnustl.cmake b/Modules/Platform/Android/ndk-stl-gnustl.cmake
new file mode 100644
index 0000000..46cedc6
--- /dev/null
+++ b/Modules/Platform/Android/ndk-stl-gnustl.cmake
@@ -0,0 +1,10 @@
+# <ndk>/sources/cxx-stl/gnu-libstdc++/Android.mk
+set(_ANDROID_STL_RTTI 1)
+set(_ANDROID_STL_EXCEPTIONS 1)
+set(_ANDROID_STL_NOSTDLIBXX 1)
+macro(__android_stl_gnustl lang filename)
+ __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${CMAKE_${lang}_ANDROID_TOOLCHAIN_VERSION}/include" 1)
+ __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${CMAKE_${lang}_ANDROID_TOOLCHAIN_VERSION}/libs/${CMAKE_ANDROID_ARCH_ABI}/include" 1)
+ __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${CMAKE_${lang}_ANDROID_TOOLCHAIN_VERSION}/include/backward" 1)
+ __android_stl_lib(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${CMAKE_${lang}_ANDROID_TOOLCHAIN_VERSION}/libs/${CMAKE_ANDROID_ARCH_ABI}/${filename}" 1)
+endmacro()
diff --git a/Modules/Platform/Android/ndk-stl-gnustl_shared.cmake b/Modules/Platform/Android/ndk-stl-gnustl_shared.cmake
new file mode 100644
index 0000000..f20cc4d
--- /dev/null
+++ b/Modules/Platform/Android/ndk-stl-gnustl_shared.cmake
@@ -0,0 +1,4 @@
+include(Platform/Android/ndk-stl-gnustl)
+macro(__android_stl lang)
+ __android_stl_gnustl(${lang} libgnustl_shared.so)
+endmacro()
diff --git a/Modules/Platform/Android/ndk-stl-gnustl_static.cmake b/Modules/Platform/Android/ndk-stl-gnustl_static.cmake
new file mode 100644
index 0000000..af4cc2a
--- /dev/null
+++ b/Modules/Platform/Android/ndk-stl-gnustl_static.cmake
@@ -0,0 +1,4 @@
+include(Platform/Android/ndk-stl-gnustl)
+macro(__android_stl lang)
+ __android_stl_gnustl(${lang} libgnustl_static.a)
+endmacro()
diff --git a/Modules/Platform/Android/ndk-stl-none.cmake b/Modules/Platform/Android/ndk-stl-none.cmake
new file mode 100644
index 0000000..45122f7
--- /dev/null
+++ b/Modules/Platform/Android/ndk-stl-none.cmake
@@ -0,0 +1,3 @@
+set(_ANDROID_STL_NOSTDLIBXX 1)
+macro(__android_stl lang)
+endmacro()
diff --git a/Modules/Platform/Android/ndk-stl-stlport.cmake b/Modules/Platform/Android/ndk-stl-stlport.cmake
new file mode 100644
index 0000000..efad33b
--- /dev/null
+++ b/Modules/Platform/Android/ndk-stl-stlport.cmake
@@ -0,0 +1,8 @@
+# <ndk>/sources/cxx-stl/stlport/Android.mk
+set(_ANDROID_STL_RTTI 1)
+set(_ANDROID_STL_EXCEPTIONS 1)
+set(_ANDROID_STL_NOSTDLIBXX 0)
+macro(__android_stl_stlport lang filename)
+ __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/stlport/stlport" 1)
+ __android_stl_lib(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/stlport/libs/${CMAKE_ANDROID_ARCH_ABI}/${filename}" 1)
+endmacro()
diff --git a/Modules/Platform/Android/ndk-stl-stlport_shared.cmake b/Modules/Platform/Android/ndk-stl-stlport_shared.cmake
new file mode 100644
index 0000000..2b5846b
--- /dev/null
+++ b/Modules/Platform/Android/ndk-stl-stlport_shared.cmake
@@ -0,0 +1,4 @@
+include(Platform/Android/ndk-stl-stlport)
+macro(__android_stl lang)
+ __android_stl_stlport(${lang} libstlport_shared.so)
+endmacro()
diff --git a/Modules/Platform/Android/ndk-stl-stlport_static.cmake b/Modules/Platform/Android/ndk-stl-stlport_static.cmake
new file mode 100644
index 0000000..bf60307
--- /dev/null
+++ b/Modules/Platform/Android/ndk-stl-stlport_static.cmake
@@ -0,0 +1,4 @@
+include(Platform/Android/ndk-stl-stlport)
+macro(__android_stl lang)
+ __android_stl_stlport(${lang} libstlport_static.a)
+endmacro()
diff --git a/Modules/Platform/Android/ndk-stl-system.cmake b/Modules/Platform/Android/ndk-stl-system.cmake
new file mode 100644
index 0000000..7d86a40
--- /dev/null
+++ b/Modules/Platform/Android/ndk-stl-system.cmake
@@ -0,0 +1,7 @@
+# <ndk>/android-ndk-r11c/sources/cxx-stl/system/Android.mk
+set(_ANDROID_STL_RTTI 0)
+set(_ANDROID_STL_EXCEPTIONS 0)
+set(_ANDROID_STL_NOSTDLIBXX 0)
+macro(__android_stl lang)
+ __android_stl_inc(${lang} "${CMAKE_ANDROID_NDK}/sources/cxx-stl/system/include" 1)
+endmacro()
diff --git a/Modules/Platform/Apple-Absoft-Fortran.cmake b/Modules/Platform/Apple-Absoft-Fortran.cmake
new file mode 100644
index 0000000..8caa202
--- /dev/null
+++ b/Modules/Platform/Apple-Absoft-Fortran.cmake
@@ -0,0 +1,7 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+set(CMAKE_Fortran_VERBOSE_FLAG "-X -v") # Runs gcc under the hood.
+
+set(CMAKE_Fortran_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
+set(CMAKE_Fortran_OSX_CURRENT_VERSION_FLAG "-current_version ")
diff --git a/Modules/Platform/Apple-Apple-Swift.cmake b/Modules/Platform/Apple-Apple-Swift.cmake
new file mode 100644
index 0000000..7ca3e36
--- /dev/null
+++ b/Modules/Platform/Apple-Apple-Swift.cmake
@@ -0,0 +1 @@
+set(CMAKE_Swift_SYSROOT_FLAG "-sdk")
diff --git a/Modules/Platform/Apple-AppleClang-C.cmake b/Modules/Platform/Apple-AppleClang-C.cmake
new file mode 100644
index 0000000..f45ccf4
--- /dev/null
+++ b/Modules/Platform/Apple-AppleClang-C.cmake
@@ -0,0 +1,6 @@
+include(Platform/Apple-Clang-C)
+if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.2)
+ set(CMAKE_C_SYSTEM_FRAMEWORK_SEARCH_FLAG "-iframework ")
+else()
+ unset(CMAKE_C_SYSTEM_FRAMEWORK_SEARCH_FLAG)
+endif()
diff --git a/Modules/Platform/Apple-AppleClang-CXX.cmake b/Modules/Platform/Apple-AppleClang-CXX.cmake
new file mode 100644
index 0000000..1128204
--- /dev/null
+++ b/Modules/Platform/Apple-AppleClang-CXX.cmake
@@ -0,0 +1,6 @@
+include(Platform/Apple-Clang-CXX)
+if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.2)
+ set(CMAKE_CXX_SYSTEM_FRAMEWORK_SEARCH_FLAG "-iframework ")
+else()
+ unset(CMAKE_CXX_SYSTEM_FRAMEWORK_SEARCH_FLAG)
+endif()
diff --git a/Modules/Platform/Apple-AppleClang-OBJC.cmake b/Modules/Platform/Apple-AppleClang-OBJC.cmake
new file mode 100644
index 0000000..b78edb1
--- /dev/null
+++ b/Modules/Platform/Apple-AppleClang-OBJC.cmake
@@ -0,0 +1,6 @@
+include(Platform/Apple-Clang-OBJC)
+if(NOT CMAKE_OBJC_COMPILER_VERSION VERSION_LESS 4.2)
+ set(CMAKE_OBJC_SYSTEM_FRAMEWORK_SEARCH_FLAG "-iframework ")
+else()
+ unset(CMAKE_OBJC_SYSTEM_FRAMEWORK_SEARCH_FLAG)
+endif()
diff --git a/Modules/Platform/Apple-AppleClang-OBJCXX.cmake b/Modules/Platform/Apple-AppleClang-OBJCXX.cmake
new file mode 100644
index 0000000..ed172f1
--- /dev/null
+++ b/Modules/Platform/Apple-AppleClang-OBJCXX.cmake
@@ -0,0 +1,6 @@
+include(Platform/Apple-Clang-OBJCXX)
+if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 4.2)
+ set(CMAKE_OBJCXX_SYSTEM_FRAMEWORK_SEARCH_FLAG "-iframework ")
+else()
+ unset(CMAKE_OBJCXX_SYSTEM_FRAMEWORK_SEARCH_FLAG)
+endif()
diff --git a/Modules/Platform/Apple-Clang-ASM.cmake b/Modules/Platform/Apple-Clang-ASM.cmake
new file mode 100644
index 0000000..935cce9
--- /dev/null
+++ b/Modules/Platform/Apple-Clang-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/Apple-Clang)
+__apple_compiler_clang(ASM)
diff --git a/Modules/Platform/Apple-Clang-C.cmake b/Modules/Platform/Apple-Clang-C.cmake
new file mode 100644
index 0000000..4d0dc82
--- /dev/null
+++ b/Modules/Platform/Apple-Clang-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Apple-Clang)
+__apple_compiler_clang(C)
diff --git a/Modules/Platform/Apple-Clang-CXX.cmake b/Modules/Platform/Apple-Clang-CXX.cmake
new file mode 100644
index 0000000..6c1ddc1
--- /dev/null
+++ b/Modules/Platform/Apple-Clang-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/Apple-Clang)
+__apple_compiler_clang(CXX)
diff --git a/Modules/Platform/Apple-Clang-OBJC.cmake b/Modules/Platform/Apple-Clang-OBJC.cmake
new file mode 100644
index 0000000..63cd846
--- /dev/null
+++ b/Modules/Platform/Apple-Clang-OBJC.cmake
@@ -0,0 +1,2 @@
+include(Platform/Apple-Clang)
+__apple_compiler_clang(OBJC)
diff --git a/Modules/Platform/Apple-Clang-OBJCXX.cmake b/Modules/Platform/Apple-Clang-OBJCXX.cmake
new file mode 100644
index 0000000..28fc352
--- /dev/null
+++ b/Modules/Platform/Apple-Clang-OBJCXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/Apple-Clang)
+__apple_compiler_clang(OBJCXX)
diff --git a/Modules/Platform/Apple-Clang.cmake b/Modules/Platform/Apple-Clang.cmake
new file mode 100644
index 0000000..0681bfb
--- /dev/null
+++ b/Modules/Platform/Apple-Clang.cmake
@@ -0,0 +1,32 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+macro(__apple_compiler_clang lang)
+ set(CMAKE_${lang}_VERBOSE_FLAG "-v -Wl,-v") # also tell linker to print verbose output
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names")
+ set(CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS "-bundle -Wl,-headerpad_max_install_names")
+ set(CMAKE_${lang}_SYSROOT_FLAG "-isysroot")
+ set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "-mmacosx-version-min=")
+ if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.2)
+ set(CMAKE_${lang}_SYSTEM_FRAMEWORK_SEARCH_FLAG "-iframework ")
+ endif()
+ if(_CMAKE_OSX_SYSROOT_PATH MATCHES "/iPhoneOS")
+ set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "-miphoneos-version-min=")
+ elseif(_CMAKE_OSX_SYSROOT_PATH MATCHES "/iPhoneSimulator")
+ set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "-mios-simulator-version-min=")
+ elseif(_CMAKE_OSX_SYSROOT_PATH MATCHES "/AppleTVOS")
+ set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "-mtvos-version-min=")
+ elseif(_CMAKE_OSX_SYSROOT_PATH MATCHES "/AppleTVSimulator")
+ set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "-mtvos-simulator-version-min=")
+ elseif(_CMAKE_OSX_SYSROOT_PATH MATCHES "/WatchOS")
+ set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "-mwatchos-version-min=")
+ elseif(_CMAKE_OSX_SYSROOT_PATH MATCHES "/WatchSimulator")
+ set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "-mwatchos-simulator-version-min=")
+ else()
+ set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "-mmacosx-version-min=")
+ endif()
+endmacro()
diff --git a/Modules/Platform/Apple-GNU-C.cmake b/Modules/Platform/Apple-GNU-C.cmake
new file mode 100644
index 0000000..5481c99
--- /dev/null
+++ b/Modules/Platform/Apple-GNU-C.cmake
@@ -0,0 +1,4 @@
+include(Platform/Apple-GNU)
+__apple_compiler_gnu(C)
+cmake_gnu_set_sysroot_flag(C)
+cmake_gnu_set_osx_deployment_target_flag(C)
diff --git a/Modules/Platform/Apple-GNU-CXX.cmake b/Modules/Platform/Apple-GNU-CXX.cmake
new file mode 100644
index 0000000..727f726
--- /dev/null
+++ b/Modules/Platform/Apple-GNU-CXX.cmake
@@ -0,0 +1,4 @@
+include(Platform/Apple-GNU)
+__apple_compiler_gnu(CXX)
+cmake_gnu_set_sysroot_flag(CXX)
+cmake_gnu_set_osx_deployment_target_flag(CXX)
diff --git a/Modules/Platform/Apple-GNU-Fortran.cmake b/Modules/Platform/Apple-GNU-Fortran.cmake
new file mode 100644
index 0000000..2f53603
--- /dev/null
+++ b/Modules/Platform/Apple-GNU-Fortran.cmake
@@ -0,0 +1,10 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Platform/Apple-GNU)
+__apple_compiler_gnu(Fortran)
+cmake_gnu_set_sysroot_flag(Fortran)
+cmake_gnu_set_osx_deployment_target_flag(Fortran)
+
+set(CMAKE_Fortran_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
+set(CMAKE_Fortran_OSX_CURRENT_VERSION_FLAG "-current_version ")
diff --git a/Modules/Platform/Apple-GNU-OBJC.cmake b/Modules/Platform/Apple-GNU-OBJC.cmake
new file mode 100644
index 0000000..aa8b33f
--- /dev/null
+++ b/Modules/Platform/Apple-GNU-OBJC.cmake
@@ -0,0 +1,4 @@
+include(Platform/Apple-GNU)
+__apple_compiler_gnu(OBJC)
+cmake_gnu_set_sysroot_flag(OBJC)
+cmake_gnu_set_osx_deployment_target_flag(OBJC)
diff --git a/Modules/Platform/Apple-GNU-OBJCXX.cmake b/Modules/Platform/Apple-GNU-OBJCXX.cmake
new file mode 100644
index 0000000..919e11d
--- /dev/null
+++ b/Modules/Platform/Apple-GNU-OBJCXX.cmake
@@ -0,0 +1,4 @@
+include(Platform/Apple-GNU)
+__apple_compiler_gnu(OBJCXX)
+cmake_gnu_set_sysroot_flag(OBJCXX)
+cmake_gnu_set_osx_deployment_target_flag(OBJCXX)
diff --git a/Modules/Platform/Apple-GNU.cmake b/Modules/Platform/Apple-GNU.cmake
new file mode 100644
index 0000000..9572736
--- /dev/null
+++ b/Modules/Platform/Apple-GNU.cmake
@@ -0,0 +1,57 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+macro(__apple_compiler_gnu lang)
+ set(CMAKE_${lang}_VERBOSE_FLAG "-v -Wl,-v") # also tell linker to print verbose output
+ # GNU does not have -shared on OS X
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names")
+ set(CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS "-bundle -Wl,-headerpad_max_install_names")
+
+ if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 4.3)
+ set(CMAKE_${lang}_SYSTEM_FRAMEWORK_SEARCH_FLAG "-iframework ")
+ endif()
+endmacro()
+
+macro(cmake_gnu_set_sysroot_flag lang)
+ if(NOT DEFINED CMAKE_${lang}_SYSROOT_FLAG)
+ set(_doc "${lang} compiler has -isysroot")
+ message(CHECK_START "Checking whether ${_doc}")
+ execute_process(
+ COMMAND ${CMAKE_${lang}_COMPILER} "-v" "--help"
+ OUTPUT_VARIABLE _gcc_help
+ ERROR_VARIABLE _gcc_help
+ )
+ if("${_gcc_help}" MATCHES "isysroot")
+ message(CHECK_PASS "yes")
+ set(CMAKE_${lang}_SYSROOT_FLAG "-isysroot")
+ else()
+ message(CHECK_FAIL "no")
+ set(CMAKE_${lang}_SYSROOT_FLAG "")
+ endif()
+ set(CMAKE_${lang}_SYSROOT_FLAG_CODE "set(CMAKE_${lang}_SYSROOT_FLAG \"${CMAKE_${lang}_SYSROOT_FLAG}\")")
+ endif()
+endmacro()
+
+macro(cmake_gnu_set_osx_deployment_target_flag lang)
+ if(NOT DEFINED CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG)
+ set(_doc "${lang} compiler supports OSX deployment target flag")
+ message(CHECK_START "Checking whether ${_doc}")
+ execute_process(
+ COMMAND ${CMAKE_${lang}_COMPILER} "-v" "--help"
+ OUTPUT_VARIABLE _gcc_help
+ ERROR_VARIABLE _gcc_help
+ )
+ if("${_gcc_help}" MATCHES "macosx-version-min")
+ message(CHECK_PASS "yes")
+ set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "-mmacosx-version-min=")
+ else()
+ message(CHECK_FAIL "no")
+ set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "")
+ endif()
+ set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG_CODE "set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG \"${CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG}\")")
+ endif()
+endmacro()
diff --git a/Modules/Platform/Apple-Intel-C.cmake b/Modules/Platform/Apple-Intel-C.cmake
new file mode 100644
index 0000000..95bb270
--- /dev/null
+++ b/Modules/Platform/Apple-Intel-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Apple-Intel)
+__apple_compiler_intel(C)
diff --git a/Modules/Platform/Apple-Intel-CXX.cmake b/Modules/Platform/Apple-Intel-CXX.cmake
new file mode 100644
index 0000000..b87e512
--- /dev/null
+++ b/Modules/Platform/Apple-Intel-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/Apple-Intel)
+__apple_compiler_intel(CXX)
diff --git a/Modules/Platform/Apple-Intel-Fortran.cmake b/Modules/Platform/Apple-Intel-Fortran.cmake
new file mode 100644
index 0000000..e54e237
--- /dev/null
+++ b/Modules/Platform/Apple-Intel-Fortran.cmake
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Platform/Apple-Intel)
+__apple_compiler_intel(Fortran)
+
+set(CMAKE_Fortran_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
+set(CMAKE_Fortran_OSX_CURRENT_VERSION_FLAG "-current_version ")
diff --git a/Modules/Platform/Apple-Intel.cmake b/Modules/Platform/Apple-Intel.cmake
new file mode 100644
index 0000000..a854be9
--- /dev/null
+++ b/Modules/Platform/Apple-Intel.cmake
@@ -0,0 +1,19 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+macro(__apple_compiler_intel lang)
+ set(CMAKE_${lang}_VERBOSE_FLAG "-v -Wl,-v") # also tell linker to print verbose output
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names")
+ set(CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS "-bundle -Wl,-headerpad_max_install_names")
+
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
+ if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 12.0)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
+ endif()
+endmacro()
diff --git a/Modules/Platform/Apple-IntelLLVM-C.cmake b/Modules/Platform/Apple-IntelLLVM-C.cmake
new file mode 100644
index 0000000..8e74729
--- /dev/null
+++ b/Modules/Platform/Apple-IntelLLVM-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Apple-IntelLLVM)
+__apple_compiler_intel_llvm(C)
diff --git a/Modules/Platform/Apple-IntelLLVM-CXX.cmake b/Modules/Platform/Apple-IntelLLVM-CXX.cmake
new file mode 100644
index 0000000..38640e1
--- /dev/null
+++ b/Modules/Platform/Apple-IntelLLVM-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/Apple-IntelLLVM)
+__apple_compiler_intel_llvm(CXX)
diff --git a/Modules/Platform/Apple-IntelLLVM-Fortran.cmake b/Modules/Platform/Apple-IntelLLVM-Fortran.cmake
new file mode 100644
index 0000000..d0486ed
--- /dev/null
+++ b/Modules/Platform/Apple-IntelLLVM-Fortran.cmake
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Platform/Apple-IntelLLVM)
+__apple_compiler_intel_llvm(Fortran)
+
+set(CMAKE_Fortran_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
+set(CMAKE_Fortran_OSX_CURRENT_VERSION_FLAG "-current_version ")
diff --git a/Modules/Platform/Apple-IntelLLVM.cmake b/Modules/Platform/Apple-IntelLLVM.cmake
new file mode 100644
index 0000000..2f9f0ca
--- /dev/null
+++ b/Modules/Platform/Apple-IntelLLVM.cmake
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+macro(__apple_compiler_intel_llvm lang)
+ set(CMAKE_${lang}_VERBOSE_FLAG "-v -Wl,-v") # also tell linker to print verbose output
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names")
+ set(CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS "-bundle -Wl,-headerpad_max_install_names")
+
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
+ set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
+endmacro()
diff --git a/Modules/Platform/Apple-NAG-Fortran.cmake b/Modules/Platform/Apple-NAG-Fortran.cmake
new file mode 100644
index 0000000..8d3e741
--- /dev/null
+++ b/Modules/Platform/Apple-NAG-Fortran.cmake
@@ -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.
+
+set(CMAKE_Fortran_VERBOSE_FLAG "-Wl,-v") # Runs gcc under the hood.
+
+# Need -fpp explicitly on case-insensitive filesystem.
+set(CMAKE_Fortran_COMPILE_OBJECT
+ "<CMAKE_Fortran_COMPILER> -fpp -o <OBJECT> <DEFINES> <INCLUDES> <FLAGS> -c <SOURCE>")
+
+set(CMAKE_Fortran_OSX_COMPATIBILITY_VERSION_FLAG "-Wl,-compatibility_version -Wl,")
+set(CMAKE_Fortran_OSX_CURRENT_VERSION_FLAG "-Wl,-current_version -Wl,")
+set(CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS "-Wl,-shared")
+set(CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG "-Wl,-install_name -Wl,")
+set(CMAKE_Fortran_CREATE_SHARED_LIBRARY
+ "<CMAKE_Fortran_COMPILER> <LANGUAGE_COMPILE_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS> <LINK_FLAGS> -o <TARGET> <SONAME_FLAG><TARGET_INSTALLNAME_DIR><TARGET_SONAME> <OBJECTS> <LINK_LIBRARIES>")
diff --git a/Modules/Platform/Apple-NVIDIA-CUDA.cmake b/Modules/Platform/Apple-NVIDIA-CUDA.cmake
new file mode 100644
index 0000000..35e759a
--- /dev/null
+++ b/Modules/Platform/Apple-NVIDIA-CUDA.cmake
@@ -0,0 +1,19 @@
+include(Platform/Darwin)
+
+set(__IMPLICIT_LINKS)
+foreach(dir ${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES})
+ string(APPEND __IMPLICIT_LINKS " -L\"${dir}\"")
+endforeach()
+foreach(lib ${CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES})
+ if(${lib} MATCHES "/")
+ string(APPEND __IMPLICIT_LINKS " \"${lib}\"")
+ else()
+ string(APPEND __IMPLICIT_LINKS " -l${lib}")
+ endif()
+endforeach()
+
+set(CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS "-shared -Wl,-headerpad_max_install_names")
+set(CMAKE_SHARED_MODULE_CREATE_CUDA_FLAGS "-shared -Wl,-headerpad_max_install_names")
+
+set(CMAKE_CUDA_CREATE_SHARED_LIBRARY "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> -o <TARGET> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> <OBJECTS> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
+set(CMAKE_CUDA_CREATE_SHARED_MODULE "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
diff --git a/Modules/Platform/Apple-PGI-C.cmake b/Modules/Platform/Apple-PGI-C.cmake
new file mode 100644
index 0000000..1e11724
--- /dev/null
+++ b/Modules/Platform/Apple-PGI-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Apple-PGI)
+__apple_compiler_pgi(C)
diff --git a/Modules/Platform/Apple-PGI-CXX.cmake b/Modules/Platform/Apple-PGI-CXX.cmake
new file mode 100644
index 0000000..aa5daf7
--- /dev/null
+++ b/Modules/Platform/Apple-PGI-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/Apple-PGI)
+__apple_compiler_pgi(CXX)
diff --git a/Modules/Platform/Apple-PGI-Fortran.cmake b/Modules/Platform/Apple-PGI-Fortran.cmake
new file mode 100644
index 0000000..1e3e4b1
--- /dev/null
+++ b/Modules/Platform/Apple-PGI-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/Apple-PGI)
+__apple_compiler_pgi(Fortran)
diff --git a/Modules/Platform/Apple-PGI.cmake b/Modules/Platform/Apple-PGI.cmake
new file mode 100644
index 0000000..8d343b7
--- /dev/null
+++ b/Modules/Platform/Apple-PGI.cmake
@@ -0,0 +1,11 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+macro(__apple_compiler_pgi lang)
+ set(CMAKE_${lang}_OSX_COMPATIBILITY_VERSION_FLAG "-Wl,-compatibility_version,")
+ set(CMAKE_${lang}_OSX_CURRENT_VERSION_FLAG "-Wl,-current_version,")
+ set(CMAKE_SHARED_LIBRARY_SONAME_${lang}_FLAG "-Wl,-install_name")
+endmacro()
diff --git a/Modules/Platform/Apple-VisualAge-C.cmake b/Modules/Platform/Apple-VisualAge-C.cmake
new file mode 100644
index 0000000..7fa6032
--- /dev/null
+++ b/Modules/Platform/Apple-VisualAge-C.cmake
@@ -0,0 +1 @@
+include(Platform/Apple-XL-C)
diff --git a/Modules/Platform/Apple-VisualAge-CXX.cmake b/Modules/Platform/Apple-VisualAge-CXX.cmake
new file mode 100644
index 0000000..12dd347
--- /dev/null
+++ b/Modules/Platform/Apple-VisualAge-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Apple-XL-CXX)
diff --git a/Modules/Platform/Apple-XL-C.cmake b/Modules/Platform/Apple-XL-C.cmake
new file mode 100644
index 0000000..e4fc3dd
--- /dev/null
+++ b/Modules/Platform/Apple-XL-C.cmake
@@ -0,0 +1,7 @@
+set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle")
+
+# Enable shared library versioning.
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-install_name")
+
+# -qhalt=e = Halt on error messages (rather than just severe errors)
+string(APPEND CMAKE_C_FLAGS_INIT " -qhalt=e")
diff --git a/Modules/Platform/Apple-XL-CXX.cmake b/Modules/Platform/Apple-XL-CXX.cmake
new file mode 100644
index 0000000..ea330c8
--- /dev/null
+++ b/Modules/Platform/Apple-XL-CXX.cmake
@@ -0,0 +1,7 @@
+set(CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS "-bundle")
+
+# Enable shared library versioning.
+set(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,-install_name")
+
+# -qhalt=e = Halt on error messages (rather than just severe errors)
+string(APPEND CMAKE_C_FLAGS_INIT " -qhalt=e")
diff --git a/Modules/Platform/BSDOS.cmake b/Modules/Platform/BSDOS.cmake
new file mode 100644
index 0000000..47852f8
--- /dev/null
+++ b/Modules/Platform/BSDOS.cmake
@@ -0,0 +1,2 @@
+include(Platform/UnixPaths)
+
diff --git a/Modules/Platform/BeOS.cmake b/Modules/Platform/BeOS.cmake
new file mode 100644
index 0000000..ef811bd
--- /dev/null
+++ b/Modules/Platform/BeOS.cmake
@@ -0,0 +1,12 @@
+set(BEOS 1)
+
+set(CMAKE_DL_LIBS root be)
+set(CMAKE_C_COMPILE_OPTIONS_PIC "-fPIC")
+set(CMAKE_C_COMPILE_OPTIONS_PIE "-fPIE")
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-fPIC")
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-nostart")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
+
+include(Platform/UnixPaths)
diff --git a/Modules/Platform/BlueGeneL.cmake b/Modules/Platform/BlueGeneL.cmake
new file mode 100644
index 0000000..0ed9975
--- /dev/null
+++ b/Modules/Platform/BlueGeneL.cmake
@@ -0,0 +1,40 @@
+#the compute nodes on BlueGene/L don't support shared libs
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
+
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "") # -pic
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "") # -shared
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # +s, flag for exe link to use shared lib
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "") # -rpath
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP "") # : or empty
+
+set(CMAKE_LINK_LIBRARY_SUFFIX "")
+set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
+set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
+set(CMAKE_SHARED_LIBRARY_PREFIX "lib") # lib
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".a") # .a
+set(CMAKE_EXECUTABLE_SUFFIX "") # .exe
+set(CMAKE_DL_LIBS "" )
+
+set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
+
+
+include(Platform/UnixPaths)
+
+if(CMAKE_COMPILER_IS_GNUCC)
+ set(CMAKE_C_LINK_EXECUTABLE
+ "<CMAKE_C_COMPILER> -Wl,-relax <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-lgcc,-lc -lnss_files -lnss_dns -lresolv")
+else()
+ # when using IBM xlc we probably don't want to link to -lgcc
+ set(CMAKE_C_LINK_EXECUTABLE
+ "<CMAKE_C_COMPILER> -Wl,-relax <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-lc -lnss_files -lnss_dns -lresolv")
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_CXX_LINK_EXECUTABLE
+ "<CMAKE_CXX_COMPILER> -Wl,-relax <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-lstdc++,-lgcc,-lc -lnss_files -lnss_dns -lresolv")
+else()
+ # when using the IBM xlC we probably don't want to link to -lgcc
+ set(CMAKE_CXX_LINK_EXECUTABLE
+ "<CMAKE_CXX_COMPILER> -Wl,-relax <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-lstdc++,-lc -lnss_files -lnss_dns -lresolv")
+endif()
diff --git a/Modules/Platform/BlueGeneP-base.cmake b/Modules/Platform/BlueGeneP-base.cmake
new file mode 100644
index 0000000..7095dd8
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-base.cmake
@@ -0,0 +1,114 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+#
+# BlueGeneP base platform file.
+#
+# NOTE: Do not set your platform to "BlueGeneP-base". This file is included
+# by the real platform files. Use one of these two platforms instead:
+#
+# BlueGeneP-dynamic For dynamically linked builds
+# BlueGeneP-static For statically linked builds
+#
+# This platform file tries its best to adhere to the behavior of the MPI
+# compiler wrappers included with the latest BG/P drivers.
+#
+
+
+#
+# For BGP builds, we're cross compiling, but we don't want to re-root things
+# (e.g. with CMAKE_FIND_ROOT_PATH) because users may have libraries anywhere on
+# the shared filesystems, and this may lie outside the root. Instead, we set the
+# system directories so that the various system BGP CNK library locations are
+# searched first. This is not the clearest thing in the world, given IBM's driver
+# layout, but this should cover all the standard ones.
+#
+set(CMAKE_SYSTEM_LIBRARY_PATH
+ /bgsys/drivers/ppcfloor/comm/default/lib # default comm layer (used by mpi compiler wrappers)
+ /bgsys/drivers/ppcfloor/comm/sys/lib # DCMF, other lower-level comm libraries
+ /bgsys/drivers/ppcfloor/runtime/SPI # other low-level stuff
+ /bgsys/drivers/ppcfloor/gnu-linux/lib # CNK python installation directory
+ /bgsys/drivers/ppcfloor/gnu-linux/powerpc-bgp-linux/lib # CNK Linux image -- standard runtime libs, pthread, etc.
+)
+
+#
+# This adds directories that find commands should specifically ignore for cross compiles.
+# Most of these directories are the includeand lib directories for the frontend on BG/P systems.
+# Not ignoring these can cause things like FindX11 to find a frontend PPC version mistakenly.
+# We use this on BG instead of re-rooting because backend libraries are typically strewn about
+# the filesystem, and we can't re-root ALL backend libraries to a single place.
+#
+set(CMAKE_SYSTEM_IGNORE_PATH
+ /lib /lib64 /include
+ /usr/lib /usr/lib64 /usr/include
+ /usr/local/lib /usr/local/lib64 /usr/local/include
+ /usr/X11/lib /usr/X11/lib64 /usr/X11/include
+ /usr/lib/X11 /usr/lib64/X11 /usr/include/X11
+ /usr/X11R6/lib /usr/X11R6/lib64 /usr/X11R6/include
+ /usr/X11R7/lib /usr/X11R7/lib64 /usr/X11R7/include
+)
+
+#
+# Indicate that this is a unix-like system
+#
+set(UNIX 1)
+
+#
+# Library prefixes, suffixes, extra libs.
+#
+set(CMAKE_LINK_LIBRARY_SUFFIX "")
+set(CMAKE_STATIC_LIBRARY_PREFIX "lib") # lib
+set(CMAKE_STATIC_LIBRARY_SUFFIX ".a") # .a
+
+set(CMAKE_SHARED_LIBRARY_PREFIX "lib") # lib
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".so") # .so
+set(CMAKE_EXECUTABLE_SUFFIX "") # .exe
+set(CMAKE_DL_LIBS "dl")
+
+#
+# This macro needs to be called for dynamic library support. Unfortunately on BGP,
+# We can't support both static and dynamic links in the same platform file. The
+# dynamic link platform file needs to call this explicitly to set up dynamic linking.
+#
+macro(__BlueGeneP_set_dynamic_flags compiler_id lang)
+ if (${compiler_id} STREQUAL XL)
+ # Flags for XL compilers if we explicitly detected XL
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-qpic")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-qpie")
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-qpic")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-qmkshrobj -qnostaticlink")
+ set(BGP_${lang}_DYNAMIC_EXE_FLAGS "-qnostaticlink -qnostaticlink=libgcc")
+ else()
+ # Assume flags for GNU compilers (if the ID is GNU *or* anything else).
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
+ set(BGP_${lang}_DYNAMIC_EXE_FLAGS "-dynamic")
+ endif()
+
+ # Both toolchains use the GNU linker on BG/P, so these options are shared.
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG "-Wl,-rpath,")
+ set(CMAKE_SHARED_LIBRARY_RPATH_LINK_${lang}_FLAG "-Wl,-rpath-link,")
+ set(CMAKE_SHARED_LIBRARY_SONAME_${lang}_FLAG "-Wl,-soname,")
+ set(CMAKE_EXE_EXPORTS_${lang}_FLAG "-Wl,--export-dynamic")
+ set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "") # +s, flag for exe link to use shared lib
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP ":") # : or empty
+
+ set(BGP_${lang}_DEFAULT_EXE_FLAGS
+ "<FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+ set(CMAKE_${lang}_LINK_EXECUTABLE
+ "<CMAKE_${lang}_COMPILER> -Wl,-relax ${BGP_${lang}_DYNAMIC_EXE_FLAGS} ${BGP_${lang}_DEFAULT_EXE_FLAGS}")
+endmacro()
+
+#
+# This macro needs to be called for static builds. Right now it just adds -Wl,-relax
+# to the link line.
+#
+macro(__BlueGeneP_set_static_flags compiler_id lang)
+ set(BGP_${lang}_DEFAULT_EXE_FLAGS
+ "<FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+ set(CMAKE_${lang}_LINK_EXECUTABLE
+ "<CMAKE_${lang}_COMPILER> -Wl,-relax ${BGP_${lang}_DEFAULT_EXE_FLAGS}")
+endmacro()
diff --git a/Modules/Platform/BlueGeneP-dynamic-GNU-C.cmake b/Modules/Platform/BlueGeneP-dynamic-GNU-C.cmake
new file mode 100644
index 0000000..3491870
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-dynamic-GNU-C.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneP_set_dynamic_flags(GNU C)
diff --git a/Modules/Platform/BlueGeneP-dynamic-GNU-CXX.cmake b/Modules/Platform/BlueGeneP-dynamic-GNU-CXX.cmake
new file mode 100644
index 0000000..d3c946b
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-dynamic-GNU-CXX.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneP_set_dynamic_flags(GNU CXX)
diff --git a/Modules/Platform/BlueGeneP-dynamic-GNU-Fortran.cmake b/Modules/Platform/BlueGeneP-dynamic-GNU-Fortran.cmake
new file mode 100644
index 0000000..9db75be
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-dynamic-GNU-Fortran.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneP_set_dynamic_flags(GNU Fortran)
diff --git a/Modules/Platform/BlueGeneP-dynamic-XL-C.cmake b/Modules/Platform/BlueGeneP-dynamic-XL-C.cmake
new file mode 100644
index 0000000..918ee70
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-dynamic-XL-C.cmake
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneP_set_dynamic_flags(XL C)
+
+# -qhalt=e = Halt on error messages (rather than just severe errors)
+string(APPEND CMAKE_C_FLAGS_INIT " -qhalt=e")
diff --git a/Modules/Platform/BlueGeneP-dynamic-XL-CXX.cmake b/Modules/Platform/BlueGeneP-dynamic-XL-CXX.cmake
new file mode 100644
index 0000000..cfefb0b
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-dynamic-XL-CXX.cmake
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneP_set_dynamic_flags(XL CXX)
+
+# -qhalt=s = Halt on severe error messages
+string(APPEND CMAKE_CXX_FLAGS_INIT " -qhalt=s")
diff --git a/Modules/Platform/BlueGeneP-dynamic-XL-Fortran.cmake b/Modules/Platform/BlueGeneP-dynamic-XL-Fortran.cmake
new file mode 100644
index 0000000..9c295bd
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-dynamic-XL-Fortran.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneP_set_dynamic_flags(XL Fortran)
diff --git a/Modules/Platform/BlueGeneP-dynamic.cmake b/Modules/Platform/BlueGeneP-dynamic.cmake
new file mode 100644
index 0000000..daebab3
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-dynamic.cmake
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+include(Platform/BlueGeneP-base)
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
+set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
diff --git a/Modules/Platform/BlueGeneP-static-GNU-C.cmake b/Modules/Platform/BlueGeneP-static-GNU-C.cmake
new file mode 100644
index 0000000..7c60794
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-static-GNU-C.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneP_set_static_flags(GNU C)
diff --git a/Modules/Platform/BlueGeneP-static-GNU-CXX.cmake b/Modules/Platform/BlueGeneP-static-GNU-CXX.cmake
new file mode 100644
index 0000000..edceaad
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-static-GNU-CXX.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneP_set_static_flags(GNU CXX)
diff --git a/Modules/Platform/BlueGeneP-static-GNU-Fortran.cmake b/Modules/Platform/BlueGeneP-static-GNU-Fortran.cmake
new file mode 100644
index 0000000..6b2265a
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-static-GNU-Fortran.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneP_set_static_flags(GNU Fortran)
diff --git a/Modules/Platform/BlueGeneP-static-XL-C.cmake b/Modules/Platform/BlueGeneP-static-XL-C.cmake
new file mode 100644
index 0000000..7d4fc13
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-static-XL-C.cmake
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneP_set_static_flags(XL C)
+
+# -qhalt=e = Halt on error messages (rather than just severe errors)
+string(APPEND CMAKE_C_FLAGS_INIT " -qhalt=e")
diff --git a/Modules/Platform/BlueGeneP-static-XL-CXX.cmake b/Modules/Platform/BlueGeneP-static-XL-CXX.cmake
new file mode 100644
index 0000000..1df276e
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-static-XL-CXX.cmake
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneP_set_static_flags(XL CXX)
+
+# -qhalt=s = Halt on severe error messages
+string(APPEND CMAKE_CXX_FLAGS_INIT " -qhalt=s")
diff --git a/Modules/Platform/BlueGeneP-static-XL-Fortran.cmake b/Modules/Platform/BlueGeneP-static-XL-Fortran.cmake
new file mode 100644
index 0000000..2bdb6d9
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-static-XL-Fortran.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneP_set_static_flags(XL Fortran)
diff --git a/Modules/Platform/BlueGeneP-static.cmake b/Modules/Platform/BlueGeneP-static.cmake
new file mode 100644
index 0000000..3675ed2
--- /dev/null
+++ b/Modules/Platform/BlueGeneP-static.cmake
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+include(Platform/BlueGeneP-base)
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
+set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
diff --git a/Modules/Platform/BlueGeneQ-base.cmake b/Modules/Platform/BlueGeneQ-base.cmake
new file mode 100644
index 0000000..94cb0a8
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-base.cmake
@@ -0,0 +1,166 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+#
+# Blue Gene/Q base platform file.
+#
+# NOTE: Do not set your platform to "BlueGeneQ-base". This file is
+# included by the real platform files. Use one of these two platforms
+# instead:
+#
+# BlueGeneQ-dynamic For dynamically linked executables
+# BlueGeneQ-static For statically linked executables
+#
+# The platform you choose doesn't affect whether or not you can build
+# shared or static libraries -- it ONLY changs whether exeuatbles are linked
+# statically or dynamically.
+#
+# This platform file tries its best to adhere to the behavior of the MPI
+# compiler wrappers included with the latest BG/P drivers.
+#
+
+#
+# This adds directories that find commands should specifically ignore
+# for cross compiles. Most of these directories are the includeand
+# lib directories for the frontend on BG/P systems. Not ignoring
+# these can cause things like FindX11 to find a frontend PPC version
+# mistakenly. We use this on BG instead of re-rooting because backend
+# libraries are typically strewn about the filesystem, and we can't
+# re-root ALL backend libraries to a single place.
+#
+set(CMAKE_SYSTEM_IGNORE_PATH
+ /lib /lib64 /include
+ /usr/lib /usr/lib64 /usr/include
+ /usr/local/lib /usr/local/lib64 /usr/local/include
+ /usr/X11/lib /usr/X11/lib64 /usr/X11/include
+ /usr/lib/X11 /usr/lib64/X11 /usr/include/X11
+ /usr/X11R6/lib /usr/X11R6/lib64 /usr/X11R6/include
+ /usr/X11R7/lib /usr/X11R7/lib64 /usr/X11R7/include
+)
+
+#
+# Indicate that this is a unix-like system
+#
+set(UNIX 1)
+
+#
+# Library prefixes, suffixes, extra libs.
+#
+set(CMAKE_LINK_LIBRARY_SUFFIX "")
+set(CMAKE_STATIC_LIBRARY_PREFIX "lib") # lib
+set(CMAKE_STATIC_LIBRARY_SUFFIX ".a") # .a
+
+set(CMAKE_SHARED_LIBRARY_PREFIX "lib") # lib
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".so") # .so
+set(CMAKE_EXECUTABLE_SUFFIX "") # .exe
+
+set(CMAKE_DL_LIBS "dl")
+
+#
+# BG/Q supports dynamic libraries regardless of whether we're building
+# static or dynamic *executables*.
+#
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
+set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
+
+#
+# For BGQ builds, we're cross compiling, but we don't want to re-root things
+# (e.g. with CMAKE_FIND_ROOT_PATH) because users may have libraries anywhere on
+# the shared filesystems, and this may lie outside the root. Instead, we set the
+# system directories so that the various system BG CNK library locations are
+# searched first. This is not the clearest thing in the world, given IBM's driver
+# layout, but this should cover all the standard ones.
+#
+macro(__BlueGeneQ_common_setup compiler_id lang)
+ # Need to use the version of the comm lib compiled with the right compiler.
+ set(__BlueGeneQ_commlib_dir gcc)
+ if (${compiler_id} STREQUAL XL)
+ set(__BlueGeneQ_commlib_dir xl)
+ endif()
+
+ set(CMAKE_SYSTEM_LIBRARY_PATH
+ /bgsys/drivers/ppcfloor/comm/default/lib # default comm layer (used by mpi compiler wrappers)
+ /bgsys/drivers/ppcfloor/comm/${__BlueGeneQ_commlib_dir}/lib # PAMI, other lower-level comm libraries
+ /bgsys/drivers/ppcfloor/gnu-linux/lib # CNK python installation directory
+ /bgsys/drivers/ppcfloor/gnu-linux/powerpc64-bgq-linux/lib # CNK Linux image -- standard runtime libs, pthread, etc.
+ )
+
+ # Add all the system include paths.
+ set(CMAKE_SYSTEM_INCLUDE_PATH
+ /bgsys/drivers/ppcfloor/comm/sys/include
+ /bgsys/drivers/ppcfloor/
+ /bgsys/drivers/ppcfloor/spi/include
+ /bgsys/drivers/ppcfloor/spi/include/kernel/cnk
+ /bgsys/drivers/ppcfloor/comm/${__BlueGeneQ_commlib_dir}/include
+ )
+
+ # Ensure that the system directories are included with the regular compilers, as users will expect this
+ # to do the same thing as the MPI compilers, which add these flags.
+ set(BGQ_SYSTEM_INCLUDES "")
+ foreach(dir ${CMAKE_SYSTEM_INCLUDE_PATH})
+ string(APPEND BGQ_SYSTEM_INCLUDES " -I${dir}")
+ endforeach()
+ set(CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> <DEFINES> ${BGQ_SYSTEM_INCLUDES} <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+ set(CMAKE_CXX_COMPILE_OBJECT "<CMAKE_CXX_COMPILER> <DEFINES> ${BGQ_SYSTEM_INCLUDES} <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+
+ #
+ # Code below does setup for shared libraries. That this is done
+ # regardless of whether the platform is static or dynamic -- you can make
+ # shared libraries even if you intend to make static executables, you just
+ # can't make a dynamic executable if you use the static platform file.
+ #
+ if (${compiler_id} STREQUAL XL)
+ # Flags for XL compilers if we explicitly detected XL
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-qpic")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-qmkshrobj -qnostaticlink")
+ else()
+ # Assume flags for GNU compilers (if the ID is GNU *or* anything else).
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
+ endif()
+
+ # Both toolchains use the GNU linker on BG/P, so these options are shared.
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG "-Wl,-rpath,")
+ set(CMAKE_SHARED_LIBRARY_RPATH_LINK_${lang}_FLAG "-Wl,-rpath-link,")
+ set(CMAKE_SHARED_LIBRARY_SONAME_${lang}_FLAG "-Wl,-soname,")
+ set(CMAKE_EXE_EXPORTS_${lang}_FLAG "-Wl,--export-dynamic")
+ set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "") # +s, flag for exe link to use shared lib
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP ":") # : or empty
+
+endmacro()
+
+#
+# This macro needs to be called for dynamic library support. Unfortunately on BG,
+# We can't support both static and dynamic links in the same platform file. The
+# dynamic link platform file needs to call this explicitly to set up dynamic linking.
+#
+macro(__BlueGeneQ_setup_dynamic compiler_id lang)
+ __BlueGeneQ_common_setup(${compiler_id} ${lang})
+
+ if (${compiler_id} STREQUAL XL)
+ set(BGQ_${lang}_DYNAMIC_EXE_FLAGS "-qnostaticlink -qnostaticlink=libgcc")
+ else()
+ set(BGQ_${lang}_DYNAMIC_EXE_FLAGS "-dynamic")
+ endif()
+
+ # For dynamic executables, need to provide special BG/Q arguments.
+ set(BGQ_${lang}_DEFAULT_EXE_FLAGS
+ "<FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+ set(CMAKE_${lang}_LINK_EXECUTABLE
+ "<CMAKE_${lang}_COMPILER> -Wl,-relax ${BGQ_${lang}_DYNAMIC_EXE_FLAGS} ${BGQ_${lang}_DEFAULT_EXE_FLAGS}")
+endmacro()
+
+#
+# This macro needs to be called for static builds. Right now it just adds -Wl,-relax
+# to the link line.
+#
+macro(__BlueGeneQ_setup_static compiler_id lang)
+ __BlueGeneQ_common_setup(${compiler_id} ${lang})
+
+ # For static executables, use default link settings.
+ set(BGQ_${lang}_DEFAULT_EXE_FLAGS
+ "<FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+ set(CMAKE_${lang}_LINK_EXECUTABLE
+ "<CMAKE_${lang}_COMPILER> -Wl,-relax ${BGQ_${lang}_DEFAULT_EXE_FLAGS}")
+endmacro()
diff --git a/Modules/Platform/BlueGeneQ-dynamic-GNU-C.cmake b/Modules/Platform/BlueGeneQ-dynamic-GNU-C.cmake
new file mode 100644
index 0000000..6758304
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-dynamic-GNU-C.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneQ_setup_dynamic(GNU C)
diff --git a/Modules/Platform/BlueGeneQ-dynamic-GNU-CXX.cmake b/Modules/Platform/BlueGeneQ-dynamic-GNU-CXX.cmake
new file mode 100644
index 0000000..5d40f9f
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-dynamic-GNU-CXX.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneQ_setup_dynamic(GNU CXX)
diff --git a/Modules/Platform/BlueGeneQ-dynamic-GNU-Fortran.cmake b/Modules/Platform/BlueGeneQ-dynamic-GNU-Fortran.cmake
new file mode 100644
index 0000000..6105999
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-dynamic-GNU-Fortran.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneQ_setup_dynamic(GNU Fortran)
diff --git a/Modules/Platform/BlueGeneQ-dynamic-XL-C.cmake b/Modules/Platform/BlueGeneQ-dynamic-XL-C.cmake
new file mode 100644
index 0000000..c51dacb
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-dynamic-XL-C.cmake
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneQ_setup_dynamic(XL C)
+
+# -qhalt=e = Halt on error messages (rather than just severe errors)
+string(APPEND CMAKE_C_FLAGS_INIT " -qhalt=e")
diff --git a/Modules/Platform/BlueGeneQ-dynamic-XL-CXX.cmake b/Modules/Platform/BlueGeneQ-dynamic-XL-CXX.cmake
new file mode 100644
index 0000000..5dbc836
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-dynamic-XL-CXX.cmake
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneQ_setup_dynamic(XL CXX)
+
+# -qhalt=s = Halt on severe error messages
+string(APPEND CMAKE_CXX_FLAGS_INIT " -qhalt=s")
diff --git a/Modules/Platform/BlueGeneQ-dynamic-XL-Fortran.cmake b/Modules/Platform/BlueGeneQ-dynamic-XL-Fortran.cmake
new file mode 100644
index 0000000..a6ac03b
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-dynamic-XL-Fortran.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneQ_setup_dynamic(XL Fortran)
diff --git a/Modules/Platform/BlueGeneQ-dynamic.cmake b/Modules/Platform/BlueGeneQ-dynamic.cmake
new file mode 100644
index 0000000..9440a3e
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-dynamic.cmake
@@ -0,0 +1,6 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+include(Platform/BlueGeneQ-base)
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
diff --git a/Modules/Platform/BlueGeneQ-static-GNU-C.cmake b/Modules/Platform/BlueGeneQ-static-GNU-C.cmake
new file mode 100644
index 0000000..5fdc25c
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-static-GNU-C.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneQ_setup_static(GNU C)
diff --git a/Modules/Platform/BlueGeneQ-static-GNU-CXX.cmake b/Modules/Platform/BlueGeneQ-static-GNU-CXX.cmake
new file mode 100644
index 0000000..ad7c092
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-static-GNU-CXX.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneQ_setup_static(GNU CXX)
diff --git a/Modules/Platform/BlueGeneQ-static-GNU-Fortran.cmake b/Modules/Platform/BlueGeneQ-static-GNU-Fortran.cmake
new file mode 100644
index 0000000..f32d1d4
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-static-GNU-Fortran.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneQ_setup_static(GNU Fortran)
diff --git a/Modules/Platform/BlueGeneQ-static-XL-C.cmake b/Modules/Platform/BlueGeneQ-static-XL-C.cmake
new file mode 100644
index 0000000..67cd57d
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-static-XL-C.cmake
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneQ_setup_static(XL C)
+
+# -qhalt=e = Halt on error messages (rather than just severe errors)
+string(APPEND CMAKE_C_FLAGS_INIT " -qhalt=e")
diff --git a/Modules/Platform/BlueGeneQ-static-XL-CXX.cmake b/Modules/Platform/BlueGeneQ-static-XL-CXX.cmake
new file mode 100644
index 0000000..a171e7f
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-static-XL-CXX.cmake
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneQ_setup_static(XL CXX)
+
+# -qhalt=s = Halt on severe error messages
+string(APPEND CMAKE_CXX_FLAGS_INIT " -qhalt=s")
diff --git a/Modules/Platform/BlueGeneQ-static-XL-Fortran.cmake b/Modules/Platform/BlueGeneQ-static-XL-Fortran.cmake
new file mode 100644
index 0000000..c7fbb44
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-static-XL-Fortran.cmake
@@ -0,0 +1,5 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+__BlueGeneQ_setup_static(XL Fortran)
diff --git a/Modules/Platform/BlueGeneQ-static.cmake b/Modules/Platform/BlueGeneQ-static.cmake
new file mode 100644
index 0000000..79cd391
--- /dev/null
+++ b/Modules/Platform/BlueGeneQ-static.cmake
@@ -0,0 +1,6 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+include(Platform/BlueGeneQ-base)
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
diff --git a/Modules/Platform/CYGWIN-Clang-C.cmake b/Modules/Platform/CYGWIN-Clang-C.cmake
new file mode 100644
index 0000000..e8343a4
--- /dev/null
+++ b/Modules/Platform/CYGWIN-Clang-C.cmake
@@ -0,0 +1 @@
+include(Platform/CYGWIN-GNU-C)
diff --git a/Modules/Platform/CYGWIN-Clang-CXX.cmake b/Modules/Platform/CYGWIN-Clang-CXX.cmake
new file mode 100644
index 0000000..67775de
--- /dev/null
+++ b/Modules/Platform/CYGWIN-Clang-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/CYGWIN-GNU-CXX)
diff --git a/Modules/Platform/CYGWIN-Determine-CXX.cmake b/Modules/Platform/CYGWIN-Determine-CXX.cmake
new file mode 100644
index 0000000..bf37f79
--- /dev/null
+++ b/Modules/Platform/CYGWIN-Determine-CXX.cmake
@@ -0,0 +1,7 @@
+if(NOT CMAKE_CXX_COMPILER_NAMES)
+ set(CMAKE_CXX_COMPILER_NAMES c++)
+endif()
+
+# Exclude C++ compilers differing from C compiler only by case
+# because this platform may have a case-insensitive filesystem.
+set(CMAKE_CXX_COMPILER_EXCLUDE CC aCC xlC)
diff --git a/Modules/Platform/CYGWIN-GNU-C.cmake b/Modules/Platform/CYGWIN-GNU-C.cmake
new file mode 100644
index 0000000..9eb0ecf
--- /dev/null
+++ b/Modules/Platform/CYGWIN-GNU-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/CYGWIN-GNU)
+__cygwin_compiler_gnu(C)
diff --git a/Modules/Platform/CYGWIN-GNU-CXX.cmake b/Modules/Platform/CYGWIN-GNU-CXX.cmake
new file mode 100644
index 0000000..2603dcd
--- /dev/null
+++ b/Modules/Platform/CYGWIN-GNU-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/CYGWIN-GNU)
+__cygwin_compiler_gnu(CXX)
diff --git a/Modules/Platform/CYGWIN-GNU-Fortran.cmake b/Modules/Platform/CYGWIN-GNU-Fortran.cmake
new file mode 100644
index 0000000..d3b49b6
--- /dev/null
+++ b/Modules/Platform/CYGWIN-GNU-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/CYGWIN-GNU)
+__cygwin_compiler_gnu(Fortran)
diff --git a/Modules/Platform/CYGWIN-GNU.cmake b/Modules/Platform/CYGWIN-GNU.cmake
new file mode 100644
index 0000000..b81bd4d
--- /dev/null
+++ b/Modules/Platform/CYGWIN-GNU.cmake
@@ -0,0 +1,54 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__CYGWIN_COMPILER_GNU)
+ return()
+endif()
+set(__CYGWIN_COMPILER_GNU 1)
+
+# TODO: Is -Wl,--enable-auto-import now always default?
+string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " -Wl,--enable-auto-import")
+
+set(CMAKE_GNULD_IMAGE_VERSION
+ "-Wl,--major-image-version,<TARGET_VERSION_MAJOR>,--minor-image-version,<TARGET_VERSION_MINOR>")
+set(CMAKE_GENERATOR_RC windres)
+macro(__cygwin_compiler_gnu lang)
+ # Binary link rules.
+ set(CMAKE_${lang}_CREATE_SHARED_MODULE
+ "<CMAKE_${lang}_COMPILER> <LANGUAGE_COMPILE_FLAGS> <CMAKE_SHARED_MODULE_${lang}_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>")
+ set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
+ "<CMAKE_${lang}_COMPILER> <LANGUAGE_COMPILE_FLAGS> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>")
+ set(CMAKE_${lang}_LINK_EXECUTABLE
+ "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
+ set(CMAKE_${lang}_CREATE_WIN32_EXE "-mwindows")
+
+ # No -fPIC on cygwin
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "")
+ set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+ set(CMAKE_${lang}_LINK_OPTIONS_PIE "")
+ set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE "")
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "")
+
+ # Initialize C link type selection flags. These flags are used when
+ # building a shared library, shared module, or executable that links
+ # to other libraries to select whether to use the static or shared
+ # versions of the libraries.
+ foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+ set(CMAKE_${type}_LINK_STATIC_${lang}_FLAGS "-Wl,-Bstatic")
+ set(CMAKE_${type}_LINK_DYNAMIC_${lang}_FLAGS "-Wl,-Bdynamic")
+ endforeach()
+
+ set(CMAKE_EXE_EXPORTS_${lang}_FLAG "-Wl,--export-all-symbols")
+ # TODO: Is -Wl,--enable-auto-import now always default?
+ string(APPEND CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS " -Wl,--enable-auto-import")
+ set(CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS}")
+
+ if(NOT CMAKE_RC_COMPILER_INIT)
+ set(CMAKE_RC_COMPILER_INIT windres)
+ endif()
+
+ enable_language(RC)
+endmacro()
diff --git a/Modules/Platform/CYGWIN-windres.cmake b/Modules/Platform/CYGWIN-windres.cmake
new file mode 100644
index 0000000..7d787dd
--- /dev/null
+++ b/Modules/Platform/CYGWIN-windres.cmake
@@ -0,0 +1 @@
+set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> -O coff <DEFINES> <INCLUDES> <FLAGS> <SOURCE> <OBJECT>")
diff --git a/Modules/Platform/CYGWIN.cmake b/Modules/Platform/CYGWIN.cmake
new file mode 100644
index 0000000..9b897bd
--- /dev/null
+++ b/Modules/Platform/CYGWIN.cmake
@@ -0,0 +1,74 @@
+if("${CMAKE_MINIMUM_REQUIRED_VERSION}" VERSION_LESS "2.8.3.20101214")
+ set(__USE_CMAKE_LEGACY_CYGWIN_WIN32 1)
+endif()
+if(NOT DEFINED WIN32)
+ set(WIN32 0)
+ if(DEFINED __USE_CMAKE_LEGACY_CYGWIN_WIN32)
+ if(NOT DEFINED CMAKE_LEGACY_CYGWIN_WIN32
+ AND DEFINED ENV{CMAKE_LEGACY_CYGWIN_WIN32})
+ set(CMAKE_LEGACY_CYGWIN_WIN32 $ENV{CMAKE_LEGACY_CYGWIN_WIN32})
+ endif()
+ if(CMAKE_LEGACY_CYGWIN_WIN32)
+ message(STATUS "Defining WIN32 under Cygwin due to CMAKE_LEGACY_CYGWIN_WIN32")
+ set(WIN32 1)
+ elseif("x${CMAKE_LEGACY_CYGWIN_WIN32}" STREQUAL "x")
+ message(WARNING "CMake no longer defines WIN32 on Cygwin!"
+ "\n"
+ "(1) If you are just trying to build this project, ignore this warning "
+ "or quiet it by setting CMAKE_LEGACY_CYGWIN_WIN32=0 in your environment or "
+ "in the CMake cache. "
+ "If later configuration or build errors occur then this project may "
+ "have been written under the assumption that Cygwin is WIN32. "
+ "In that case, set CMAKE_LEGACY_CYGWIN_WIN32=1 instead."
+ "\n"
+ "(2) If you are developing this project, add the line\n"
+ " set(CMAKE_LEGACY_CYGWIN_WIN32 0) # Remove when CMake >= 2.8.4 is required\n"
+ "at the top of your top-level CMakeLists.txt file or set the minimum "
+ "required version of CMake to 2.8.4 or higher. "
+ "Then teach your project to build on Cygwin without WIN32.")
+ endif()
+ elseif(DEFINED CMAKE_LEGACY_CYGWIN_WIN32)
+ message(AUTHOR_WARNING "CMAKE_LEGACY_CYGWIN_WIN32 ignored because\n"
+ " cmake_minimum_required(VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})\n"
+ "is at least 2.8.4.")
+ endif()
+endif()
+if(DEFINED __USE_CMAKE_LEGACY_CYGWIN_WIN32)
+ # Pass WIN32 legacy setting to scripts.
+ if(WIN32)
+ set(ENV{CMAKE_LEGACY_CYGWIN_WIN32} 1)
+ else()
+ set(ENV{CMAKE_LEGACY_CYGWIN_WIN32} 0)
+ endif()
+ unset(__USE_CMAKE_LEGACY_CYGWIN_WIN32)
+endif()
+
+set(CYGWIN 1)
+
+set(CMAKE_SHARED_LIBRARY_PREFIX "cyg")
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".dll")
+set(CMAKE_SHARED_MODULE_PREFIX "cyg")
+set(CMAKE_SHARED_MODULE_SUFFIX ".dll")
+set(CMAKE_IMPORT_LIBRARY_PREFIX "lib")
+set(CMAKE_IMPORT_LIBRARY_SUFFIX ".dll.a")
+set(CMAKE_EXECUTABLE_SUFFIX ".exe") # .exe
+# Modules have a different default prefix that shared libs.
+set(CMAKE_MODULE_EXISTS 1)
+
+set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.a" ".a")
+
+# Shared libraries on cygwin can be named with their version number.
+set(CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION 1)
+
+include(Platform/UnixPaths)
+
+# Windows API on Cygwin
+list(APPEND CMAKE_SYSTEM_INCLUDE_PATH
+ /usr/include/w32api
+ )
+
+# Windows API on Cygwin
+list(APPEND CMAKE_SYSTEM_LIBRARY_PATH
+ /usr/lib/w32api
+ )
diff --git a/Modules/Platform/Catamount.cmake b/Modules/Platform/Catamount.cmake
new file mode 100644
index 0000000..7e9e021
--- /dev/null
+++ b/Modules/Platform/Catamount.cmake
@@ -0,0 +1,26 @@
+#Catamount, which runs on the compute nodes of Cray machines, e.g. RedStorm, doesn't support shared libs
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
+
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "") # -pic
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "") # -shared
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # +s, flag for exe link to use shared lib
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "") # -rpath
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP "") # : or empty
+
+set(CMAKE_LINK_LIBRARY_SUFFIX "")
+set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
+set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
+set(CMAKE_SHARED_LIBRARY_PREFIX "lib") # lib
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".a") # .a
+set(CMAKE_EXECUTABLE_SUFFIX "") # .exe
+set(CMAKE_DL_LIBS "" )
+
+set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
+
+include(Platform/UnixPaths)
+
+set(CMAKE_CXX_LINK_SHARED_LIBRARY)
+set(CMAKE_CXX_LINK_MODULE_LIBRARY)
+set(CMAKE_C_LINK_SHARED_LIBRARY)
+set(CMAKE_C_LINK_MODULE_LIBRARY)
diff --git a/Modules/Platform/CrayLinuxEnvironment.cmake b/Modules/Platform/CrayLinuxEnvironment.cmake
new file mode 100644
index 0000000..f2aaf3f
--- /dev/null
+++ b/Modules/Platform/CrayLinuxEnvironment.cmake
@@ -0,0 +1,87 @@
+# CrayLinuxEnvironment: loaded by users cross-compiling on a Cray front-end
+# node by specifying "-DCMAKE_SYSTEM_NAME=CrayLinuxEnvironment" to cmake
+
+set(UNIX 1)
+
+if(DEFINED ENV{CRAYOS_VERSION})
+ set(CMAKE_SYSTEM_VERSION "$ENV{CRAYOS_VERSION}")
+elseif(DEFINED ENV{XTOS_VERSION})
+ set(CMAKE_SYSTEM_VERSION "$ENV{XTOS_VERSION}")
+elseif(EXISTS /etc/opt/cray/release/cle-release)
+ file(STRINGS /etc/opt/cray/release/cle-release release REGEX "^RELEASE=.*")
+ string(REGEX REPLACE "^RELEASE=(.*)$" "\\1" CMAKE_SYSTEM_VERSION "${release}")
+ unset(release)
+elseif(EXISTS /etc/opt/cray/release/clerelease)
+ file(READ /etc/opt/cray/release/clerelease CMAKE_SYSTEM_VERSION)
+endif()
+
+# Guard against multiple messages
+if(NOT __CrayLinuxEnvironment_message)
+ set(__CrayLinuxEnvironment_message 1 CACHE INTERNAL "")
+ if(NOT CMAKE_SYSTEM_VERSION)
+ message(STATUS "CrayLinuxEnvironment: Unable to determine CLE version. This platform file should only be used from inside the Cray Linux Environment for targeting compute nodes (NIDs).")
+ else()
+ message(STATUS "Cray Linux Environment ${CMAKE_SYSTEM_VERSION}")
+ endif()
+endif()
+
+# All cray systems are x86 CPUs and have been for quite some time
+# Note: this may need to change in the future with 64-bit ARM
+set(CMAKE_SYSTEM_PROCESSOR "x86_64")
+
+# Don't override shared lib support if it's already been set and possibly
+# overridden elsewhere by the CrayPrgEnv module
+if(NOT CMAKE_FIND_LIBRARY_SUFFIXES)
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
+ set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
+endif()
+
+# The rest of this file is based on UnixPaths.cmake, adjusted for Cray
+
+# add the install directory of the running cmake to the search directories
+# CMAKE_ROOT is CMAKE_INSTALL_PREFIX/share/cmake, so we need to go two levels up
+get_filename_component(__cmake_install_dir "${CMAKE_ROOT}" PATH)
+get_filename_component(__cmake_install_dir "${__cmake_install_dir}" PATH)
+
+# Note: Some Cray's have the SYSROOT_DIR variable defined, pointing to a copy
+# of the NIDs userland. If so, then we'll use it. Otherwise, just assume
+# the userland from the login node is ok
+
+# List common installation prefixes. These will be used for all
+# search types.
+list(APPEND CMAKE_SYSTEM_PREFIX_PATH
+ # Standard
+ $ENV{SYSROOT_DIR}/usr/local $ENV{SYSROOT_DIR}/usr $ENV{SYSROOT_DIR}/
+
+ # CMake install location
+ "${__cmake_install_dir}"
+ )
+if (NOT CMAKE_FIND_NO_INSTALL_PREFIX)
+ list(APPEND CMAKE_SYSTEM_PREFIX_PATH
+ # Project install destination.
+ "${CMAKE_INSTALL_PREFIX}"
+ )
+ if(CMAKE_STAGING_PREFIX)
+ list(APPEND CMAKE_SYSTEM_PREFIX_PATH
+ # User-supplied staging prefix.
+ "${CMAKE_STAGING_PREFIX}"
+ )
+ endif()
+endif()
+
+list(APPEND CMAKE_SYSTEM_INCLUDE_PATH
+ $ENV{SYSROOT_DIR}/usr/include/X11
+)
+list(APPEND CMAKE_SYSTEM_LIBRARY_PATH
+ $ENV{SYSROOT_DIR}/usr/local/lib64
+ $ENV{SYSROOT_DIR}/usr/lib64
+ $ENV{SYSROOT_DIR}/lib64
+)
+list(APPEND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES
+ $ENV{SYSROOT_DIR}/usr/local/lib64
+ $ENV{SYSROOT_DIR}/usr/lib64
+ $ENV{SYSROOT_DIR}/lib64
+)
+
+# Enable use of lib64 search path variants by default.
+set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE)
diff --git a/Modules/Platform/DOS-OpenWatcom-C.cmake b/Modules/Platform/DOS-OpenWatcom-C.cmake
new file mode 100644
index 0000000..cf71c84
--- /dev/null
+++ b/Modules/Platform/DOS-OpenWatcom-C.cmake
@@ -0,0 +1 @@
+include(Platform/DOS-OpenWatcom)
diff --git a/Modules/Platform/DOS-OpenWatcom-CXX.cmake b/Modules/Platform/DOS-OpenWatcom-CXX.cmake
new file mode 100644
index 0000000..cf71c84
--- /dev/null
+++ b/Modules/Platform/DOS-OpenWatcom-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/DOS-OpenWatcom)
diff --git a/Modules/Platform/DOS-OpenWatcom.cmake b/Modules/Platform/DOS-OpenWatcom.cmake
new file mode 100644
index 0000000..54c452e
--- /dev/null
+++ b/Modules/Platform/DOS-OpenWatcom.cmake
@@ -0,0 +1,28 @@
+
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+set(CMAKE_BUILD_TYPE_INIT Debug)
+
+if(DEFINED CMAKE_SYSTEM_PROCESSOR AND CMAKE_SYSTEM_PROCESSOR STREQUAL "I86")
+ string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " system dos")
+ string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " system dos")
+ string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " system dos")
+else()
+ string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " system dos4g")
+ string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " system dos4g")
+ string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " system dos4g")
+endif()
+
+set(CMAKE_C_COMPILE_OPTIONS_DLL "-bd") # Note: This variable is a ';' separated list
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-bd") # ... while this is a space separated string.
+
+string(APPEND CMAKE_C_FLAGS_INIT " -bt=dos")
+string(APPEND CMAKE_CXX_FLAGS_INIT " -bt=dos -xs")
+
+if(NOT CMAKE_C_STANDARD_INCLUDE_DIRECTORIES)
+ set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h)
+endif()
+if(NOT CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES)
+ set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h)
+endif()
diff --git a/Modules/Platform/DOS.cmake b/Modules/Platform/DOS.cmake
new file mode 100644
index 0000000..fc95936
--- /dev/null
+++ b/Modules/Platform/DOS.cmake
@@ -0,0 +1,14 @@
+set(DOS 1)
+
+set(CMAKE_STATIC_LIBRARY_PREFIX "")
+set(CMAKE_STATIC_LIBRARY_SUFFIX ".lib")
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".dll")
+set(CMAKE_IMPORT_LIBRARY_PREFIX "")
+set(CMAKE_IMPORT_LIBRARY_SUFFIX ".lib")
+set(CMAKE_EXECUTABLE_SUFFIX ".exe")
+set(CMAKE_LINK_LIBRARY_SUFFIX ".lib")
+set(CMAKE_DL_LIBS "")
+
+set(CMAKE_FIND_LIBRARY_PREFIXES "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
diff --git a/Modules/Platform/Darwin-Determine-CXX.cmake b/Modules/Platform/Darwin-Determine-CXX.cmake
new file mode 100644
index 0000000..bf37f79
--- /dev/null
+++ b/Modules/Platform/Darwin-Determine-CXX.cmake
@@ -0,0 +1,7 @@
+if(NOT CMAKE_CXX_COMPILER_NAMES)
+ set(CMAKE_CXX_COMPILER_NAMES c++)
+endif()
+
+# Exclude C++ compilers differing from C compiler only by case
+# because this platform may have a case-insensitive filesystem.
+set(CMAKE_CXX_COMPILER_EXCLUDE CC aCC xlC)
diff --git a/Modules/Platform/Darwin-Initialize.cmake b/Modules/Platform/Darwin-Initialize.cmake
new file mode 100644
index 0000000..c2f1851
--- /dev/null
+++ b/Modules/Platform/Darwin-Initialize.cmake
@@ -0,0 +1,318 @@
+# Ask xcode-select where to find /Developer or fall back to ancient location.
+execute_process(COMMAND xcode-select -print-path
+ OUTPUT_VARIABLE _stdout
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE _stderr
+ RESULT_VARIABLE _failed)
+if(NOT _failed AND IS_DIRECTORY ${_stdout})
+ set(OSX_DEVELOPER_ROOT ${_stdout})
+elseif(IS_DIRECTORY "/Developer")
+ set(OSX_DEVELOPER_ROOT "/Developer")
+else()
+ set(OSX_DEVELOPER_ROOT "")
+endif()
+
+execute_process(COMMAND sw_vers -productVersion
+ OUTPUT_VARIABLE CURRENT_OSX_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+# Save CMAKE_OSX_ARCHITECTURES from the environment.
+set(CMAKE_OSX_ARCHITECTURES "$ENV{CMAKE_OSX_ARCHITECTURES}" CACHE STRING
+ "Build architectures for OSX")
+
+if(NOT CMAKE_CROSSCOMPILING AND
+ CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND
+ CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "^(arm64|x86_64)$")
+ execute_process(COMMAND sysctl -q hw.optional.arm64
+ OUTPUT_VARIABLE _sysctl_stdout
+ ERROR_VARIABLE _sysctl_stderr
+ RESULT_VARIABLE _sysctl_result
+ )
+ # When building on an Apple Silicon host, we need to explicitly specify
+ # the architecture to the toolchain since it will otherwise guess the
+ # architecture based on that of the build system tool.
+ # Set an *internal variable* to tell the generators to do this.
+ if(_sysctl_result EQUAL 0 AND _sysctl_stdout MATCHES "hw.optional.arm64: 1")
+ set(_CMAKE_APPLE_ARCHS_DEFAULT "${CMAKE_HOST_SYSTEM_PROCESSOR}")
+ endif()
+ unset(_sysctl_result)
+ unset(_sysctl_stderr)
+ unset(_sysctl_stdout)
+endif()
+
+# macOS, iOS, tvOS, and watchOS should lookup compilers from
+# Platform/Apple-${CMAKE_CXX_COMPILER_ID}-<LANG>
+set(CMAKE_EFFECTIVE_SYSTEM_NAME "Apple")
+
+#----------------------------------------------------------------------------
+# _CURRENT_OSX_VERSION - as a two-component string: 10.5, 10.6, ...
+#
+string(REGEX REPLACE "^([0-9]+\\.[0-9]+).*$" "\\1"
+ _CURRENT_OSX_VERSION "${CURRENT_OSX_VERSION}")
+
+#----------------------------------------------------------------------------
+# CMAKE_OSX_DEPLOYMENT_TARGET
+
+# Set cache variable - end user may change this during ccmake or cmake-gui configure.
+if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND _CURRENT_OSX_VERSION VERSION_GREATER 10.3)
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "$ENV{MACOSX_DEPLOYMENT_TARGET}" CACHE STRING
+ "Minimum OS X version to target for deployment (at runtime); newer APIs weak linked. Set to empty string for default value.")
+endif()
+
+#----------------------------------------------------------------------------
+# CMAKE_OSX_SYSROOT
+
+if(CMAKE_OSX_SYSROOT)
+ # Use the existing value without further computation to choose a default.
+ set(_CMAKE_OSX_SYSROOT_DEFAULT "${CMAKE_OSX_SYSROOT}")
+elseif(NOT "x$ENV{SDKROOT}" STREQUAL "x" AND
+ (NOT "x$ENV{SDKROOT}" MATCHES "/" OR IS_DIRECTORY "$ENV{SDKROOT}"))
+ # Use the value of SDKROOT from the environment.
+ set(_CMAKE_OSX_SYSROOT_DEFAULT "$ENV{SDKROOT}")
+elseif(CMAKE_SYSTEM_NAME STREQUAL iOS)
+ set(_CMAKE_OSX_SYSROOT_DEFAULT "iphoneos")
+elseif(CMAKE_SYSTEM_NAME STREQUAL tvOS)
+ set(_CMAKE_OSX_SYSROOT_DEFAULT "appletvos")
+elseif(CMAKE_SYSTEM_NAME STREQUAL watchOS)
+ set(_CMAKE_OSX_SYSROOT_DEFAULT "watchos")
+elseif("${CMAKE_GENERATOR}" MATCHES Xcode
+ OR CMAKE_OSX_DEPLOYMENT_TARGET
+ OR CMAKE_OSX_ARCHITECTURES MATCHES "[^;]"
+ OR NOT EXISTS "/usr/include/sys/types.h")
+ # Find installed SDKs in either Xcode-4.3+ or pre-4.3 SDKs directory.
+ set(_CMAKE_OSX_SDKS_DIR "")
+ if(OSX_DEVELOPER_ROOT)
+ foreach(_d Platforms/MacOSX.platform/Developer/SDKs SDKs)
+ file(GLOB _CMAKE_OSX_SDKS ${OSX_DEVELOPER_ROOT}/${_d}/*)
+ if(_CMAKE_OSX_SDKS)
+ set(_CMAKE_OSX_SDKS_DIR ${OSX_DEVELOPER_ROOT}/${_d})
+ break()
+ endif()
+ endforeach()
+ endif()
+
+ if(_CMAKE_OSX_SDKS_DIR)
+ # Find the latest SDK as recommended by Apple (Technical Q&A QA1806)
+ set(_CMAKE_OSX_LATEST_SDK_VERSION "0.0")
+ file(GLOB _CMAKE_OSX_SDKS RELATIVE "${_CMAKE_OSX_SDKS_DIR}" "${_CMAKE_OSX_SDKS_DIR}/MacOSX*.sdk")
+ foreach(_SDK ${_CMAKE_OSX_SDKS})
+ if(IS_DIRECTORY "${_CMAKE_OSX_SDKS_DIR}/${_SDK}"
+ AND _SDK MATCHES "MacOSX([0-9]+\\.[0-9]+)[^/]*\\.sdk"
+ AND CMAKE_MATCH_1 VERSION_GREATER ${_CMAKE_OSX_LATEST_SDK_VERSION})
+ set(_CMAKE_OSX_LATEST_SDK_VERSION "${CMAKE_MATCH_1}")
+ endif()
+ endforeach()
+
+ if(NOT _CMAKE_OSX_LATEST_SDK_VERSION STREQUAL "0.0")
+ set(_CMAKE_OSX_SYSROOT_DEFAULT "${_CMAKE_OSX_SDKS_DIR}/MacOSX${_CMAKE_OSX_LATEST_SDK_VERSION}.sdk")
+ else()
+ message(WARNING "Could not find any valid SDKs in ${_CMAKE_OSX_SDKS_DIR}")
+ endif()
+
+ if(NOT CMAKE_CROSSCOMPILING AND NOT CMAKE_OSX_DEPLOYMENT_TARGET
+ AND (_CURRENT_OSX_VERSION VERSION_LESS _CMAKE_OSX_LATEST_SDK_VERSION
+ OR _CMAKE_OSX_LATEST_SDK_VERSION STREQUAL "0.0"))
+ set(CMAKE_OSX_DEPLOYMENT_TARGET ${_CURRENT_OSX_VERSION} CACHE STRING
+ "Minimum OS X version to target for deployment (at runtime); newer APIs weak linked. Set to empty string for default value." FORCE)
+ endif()
+ else()
+ # Assume developer files are in root (such as Xcode 4.5 command-line tools).
+ set(_CMAKE_OSX_SYSROOT_DEFAULT "")
+ endif()
+endif()
+
+# Set cache variable - end user may change this during ccmake or cmake-gui configure.
+# Choose the type based on the current value.
+set(_CMAKE_OSX_SYSROOT_TYPE STRING)
+foreach(_v CMAKE_OSX_SYSROOT _CMAKE_OSX_SYSROOT_DEFAULT)
+ if("x${${_v}}" MATCHES "/")
+ set(_CMAKE_OSX_SYSROOT_TYPE PATH)
+ break()
+ endif()
+endforeach()
+set(CMAKE_OSX_SYSROOT "${_CMAKE_OSX_SYSROOT_DEFAULT}" CACHE ${_CMAKE_OSX_SYSROOT_TYPE}
+ "The product will be built against the headers and libraries located inside the indicated SDK.")
+
+# Resolves the SDK name into a path
+function(_apple_resolve_sdk_path sdk_name ret)
+ execute_process(
+ COMMAND xcrun -sdk ${sdk_name} --show-sdk-path
+ OUTPUT_VARIABLE _stdout
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE _stderr
+ RESULT_VARIABLE _failed
+ )
+ set(${ret} "${_stdout}" PARENT_SCOPE)
+endfunction()
+
+function(_apple_resolve_supported_archs_for_sdk_from_system_lib sdk_path ret ret_failed)
+ # Detect the supported SDK architectures by inspecting the main libSystem library.
+ set(common_lib_prefix "${sdk_path}/usr/lib/libSystem")
+ set(system_lib_dylib_path "${common_lib_prefix}.dylib")
+ set(system_lib_tbd_path "${common_lib_prefix}.tbd")
+
+ # Newer SDKs ship text based dylib stub files which contain the architectures supported by the
+ # library in text form.
+ if(EXISTS "${system_lib_tbd_path}")
+ file(STRINGS "${system_lib_tbd_path}" tbd_lines REGEX "^(archs|targets): +\\[.+\\]")
+ if(NOT tbd_lines)
+ set(${ret_failed} TRUE PARENT_SCOPE)
+ return()
+ endif()
+
+ # The tbd architectures line looks like the following:
+ # archs: [ armv7, armv7s, arm64, arm64e ]
+ # or for version 4 TBD files:
+ # targets: [ armv7-ios, armv7s-ios, arm64-ios, arm64e-ios ]
+ list(GET tbd_lines 0 first_arch_line)
+ string(REGEX REPLACE
+ "(archs|targets): +\\[ (.+) \\]" "\\2" arches_comma_separated "${first_arch_line}")
+ string(STRIP "${arches_comma_separated}" arches_comma_separated)
+ string(REPLACE "," ";" arch_list "${arches_comma_separated}")
+ string(REPLACE " " "" arch_list "${arch_list}")
+
+ # Remove -platform suffix from target (version 4 only)
+ string(REGEX REPLACE "-[a-z-]+" "" arch_list "${arch_list}")
+
+ if(NOT arch_list)
+ set(${ret_failed} TRUE PARENT_SCOPE)
+ return()
+ endif()
+ set(${ret} "${arch_list}" PARENT_SCOPE)
+ elseif(EXISTS "${system_lib_dylib_path}")
+ # Old SDKs (Xcode < 7) ship dylib files, use lipo to inspect the supported architectures.
+ # Can't use -archs because the option is not available in older Xcode versions.
+ execute_process(
+ COMMAND lipo -info ${system_lib_dylib_path}
+ OUTPUT_VARIABLE lipo_output
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE _stderr
+ RESULT_VARIABLE _failed
+ )
+ if(_failed OR NOT lipo_output OR NOT lipo_output MATCHES "(Non-fat file:|Architectures in the fat file:)")
+ set(${ret_failed} TRUE PARENT_SCOPE)
+ return()
+ endif()
+
+ # The lipo output looks like the following:
+ # Non-fat file: <path> is architecture: i386
+ # Architectures in the fat file: <path> are: i386 x86_64
+ string(REGEX REPLACE
+ "^(.+)is architecture:(.+)" "\\2" arches_space_separated "${lipo_output}")
+ string(REGEX REPLACE
+ "^(.+)are:(.+)" "\\2" arches_space_separated "${arches_space_separated}")
+
+ # Need to clean up the arches, with Xcode 4.6.3 the output of lipo -info contains some
+ # additional info, e.g.
+ # Architectures in the fat file: <path> are: armv7 (cputype (12) cpusubtype (11))
+ string(REGEX REPLACE
+ "\\(.+\\)" "" arches_space_separated "${arches_space_separated}")
+
+ # The output is space separated.
+ string(STRIP "${arches_space_separated}" arches_space_separated)
+ string(REPLACE " " ";" arch_list "${arches_space_separated}")
+
+ if(NOT arch_list)
+ set(${ret_failed} TRUE PARENT_SCOPE)
+ return()
+ endif()
+ set(${ret} "${arch_list}" PARENT_SCOPE)
+ else()
+ # This shouldn't happen, but keep it for safety.
+ message(WARNING "No way to find architectures for given sdk_path '${sdk_path}'")
+ set(${ret_failed} TRUE PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Handle multi-arch sysroots. Do this before CMAKE_OSX_SYSROOT is
+# transformed into a path, so that we know the sysroot name.
+function(_apple_resolve_multi_arch_sysroots)
+ if(DEFINED CMAKE_APPLE_ARCH_SYSROOTS)
+ return() # Already cached
+ endif()
+
+ list(LENGTH CMAKE_OSX_ARCHITECTURES _num_archs)
+ if(NOT (_num_archs GREATER 1))
+ return() # Only apply to multi-arch
+ endif()
+
+ if(CMAKE_OSX_SYSROOT STREQUAL "macosx")
+ # macOS doesn't have a simulator sdk / sysroot, so there is no need to handle per-sdk arches.
+ return()
+ endif()
+
+ if(IS_DIRECTORY "${CMAKE_OSX_SYSROOT}")
+ if(NOT CMAKE_OSX_SYSROOT STREQUAL _CMAKE_OSX_SYSROOT_DEFAULT)
+ message(WARNING "Can not resolve multi-arch sysroots with CMAKE_OSX_SYSROOT set to path (${CMAKE_OSX_SYSROOT})")
+ endif()
+ return()
+ endif()
+
+ string(REPLACE "os" "simulator" _simulator_sdk ${CMAKE_OSX_SYSROOT})
+ set(_sdks "${CMAKE_OSX_SYSROOT};${_simulator_sdk}")
+ foreach(sdk ${_sdks})
+ _apple_resolve_sdk_path(${sdk} _sdk_path)
+ if(NOT IS_DIRECTORY "${_sdk_path}")
+ message(WARNING "Failed to resolve SDK path for '${sdk}'")
+ continue()
+ endif()
+
+ _apple_resolve_supported_archs_for_sdk_from_system_lib(${_sdk_path} _sdk_archs _failed)
+
+ if(_failed)
+ # Failure to extract supported architectures for an SDK means that the installed SDK is old
+ # and does not provide such information (SDKs that come with Xcode >= 10.x started providing
+ # the information). In such a case, return early, and handle multi-arch builds the old way
+ # (no per-sdk arches).
+ return()
+ endif()
+
+ set(_sdk_archs_${sdk} ${_sdk_archs})
+ set(_sdk_path_${sdk} ${_sdk_path})
+ endforeach()
+
+ foreach(arch ${CMAKE_OSX_ARCHITECTURES})
+ set(_arch_sysroot "")
+ foreach(sdk ${_sdks})
+ list(FIND _sdk_archs_${sdk} ${arch} arch_index)
+ if(NOT arch_index EQUAL -1)
+ set(_arch_sysroot ${_sdk_path_${sdk}})
+ break()
+ endif()
+ endforeach()
+ if(_arch_sysroot)
+ list(APPEND _arch_sysroots ${_arch_sysroot})
+ else()
+ message(WARNING "No SDK found for architecture '${arch}'")
+ list(APPEND _arch_sysroots "${arch}-SDK-NOTFOUND")
+ endif()
+ endforeach()
+
+ set(CMAKE_APPLE_ARCH_SYSROOTS "${_arch_sysroots}" CACHE INTERNAL
+ "Architecture dependent sysroots, one per CMAKE_OSX_ARCHITECTURES")
+endfunction()
+
+_apple_resolve_multi_arch_sysroots()
+
+# Transform CMAKE_OSX_SYSROOT to absolute path
+set(_CMAKE_OSX_SYSROOT_PATH "")
+if(CMAKE_OSX_SYSROOT)
+ if("x${CMAKE_OSX_SYSROOT}" MATCHES "/")
+ # This is a path to the SDK. Make sure it exists.
+ if(NOT IS_DIRECTORY "${CMAKE_OSX_SYSROOT}")
+ message(WARNING "Ignoring CMAKE_OSX_SYSROOT value:\n ${CMAKE_OSX_SYSROOT}\n"
+ "because the directory does not exist.")
+ set(CMAKE_OSX_SYSROOT "")
+ endif()
+ set(_CMAKE_OSX_SYSROOT_PATH "${CMAKE_OSX_SYSROOT}")
+ else()
+ _apple_resolve_sdk_path(${CMAKE_OSX_SYSROOT} _sdk_path)
+ if(IS_DIRECTORY "${_sdk_path}")
+ set(_CMAKE_OSX_SYSROOT_PATH "${_sdk_path}")
+ # For non-Xcode generators use the path.
+ if(NOT "${CMAKE_GENERATOR}" MATCHES "Xcode")
+ set(CMAKE_OSX_SYSROOT "${_CMAKE_OSX_SYSROOT_PATH}")
+ endif()
+ endif()
+ endif()
+endif()
diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake
new file mode 100644
index 0000000..d9a7894
--- /dev/null
+++ b/Modules/Platform/Darwin.cmake
@@ -0,0 +1,239 @@
+set(APPLE 1)
+
+if(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "tvOS" OR CMAKE_SYSTEM_NAME STREQUAL "watchOS")
+ if(NOT DEFINED CMAKE_MACOSX_BUNDLE)
+ set(CMAKE_MACOSX_BUNDLE ON)
+ endif()
+
+ list(APPEND CMAKE_FIND_ROOT_PATH "${_CMAKE_OSX_SYSROOT_PATH}")
+ if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_LIBRARY)
+ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+ endif()
+ if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_INCLUDE)
+ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+ endif()
+ if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_PACKAGE)
+ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+ endif()
+endif()
+
+# Darwin versions:
+# 6.x == Mac OSX 10.2 (Jaguar)
+# 7.x == Mac OSX 10.3 (Panther)
+# 8.x == Mac OSX 10.4 (Tiger)
+# 9.x == Mac OSX 10.5 (Leopard)
+# 10.x == Mac OSX 10.6 (Snow Leopard)
+# 11.x == Mac OSX 10.7 (Lion)
+# 12.x == Mac OSX 10.8 (Mountain Lion)
+string(REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_SYSTEM_VERSION}")
+string(REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\2" DARWIN_MINOR_VERSION "${CMAKE_SYSTEM_VERSION}")
+
+# Do not use the "-Wl,-search_paths_first" flag with the OSX 10.2 compiler.
+# Done this way because it is too early to do a TRY_COMPILE.
+if(NOT DEFINED HAVE_FLAG_SEARCH_PATHS_FIRST)
+ set(HAVE_FLAG_SEARCH_PATHS_FIRST 0)
+ if("${DARWIN_MAJOR_VERSION}" GREATER 6)
+ set(HAVE_FLAG_SEARCH_PATHS_FIRST 1)
+ endif()
+endif()
+# More desirable, but does not work:
+ #include(CheckCXXCompilerFlag)
+ #CHECK_CXX_COMPILER_FLAG("-Wl,-search_paths_first" HAVE_FLAG_SEARCH_PATHS_FIRST)
+
+set(CMAKE_SHARED_LIBRARY_PREFIX "lib")
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
+set(CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES ".tbd" ".so")
+set(CMAKE_SHARED_MODULE_PREFIX "lib")
+set(CMAKE_SHARED_MODULE_SUFFIX ".so")
+set(CMAKE_MODULE_EXISTS 1)
+set(CMAKE_DL_LIBS "")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
+
+foreach(lang C CXX OBJC OBJCXX)
+ set(CMAKE_${lang}_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
+ set(CMAKE_${lang}_OSX_CURRENT_VERSION_FLAG "-current_version ")
+ set(CMAKE_${lang}_LINK_FLAGS "-Wl,-headerpad_max_install_names")
+
+ if(HAVE_FLAG_SEARCH_PATHS_FIRST)
+ set(CMAKE_${lang}_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_${lang}_LINK_FLAGS}")
+ endif()
+
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names")
+ set(CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS "-bundle -Wl,-headerpad_max_install_names")
+ set(CMAKE_SHARED_MODULE_LOADER_${lang}_FLAG "-Wl,-bundle_loader,")
+endforeach()
+
+set(CMAKE_PLATFORM_HAS_INSTALLNAME 1)
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".tbd" ".dylib" ".so" ".a")
+
+# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree
+# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache
+# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun)
+# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex
+if(NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
+ find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool)
+ mark_as_advanced(CMAKE_INSTALL_NAME_TOOL)
+endif()
+
+# Enable shared library versioning.
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-install_name")
+
+if("${_CURRENT_OSX_VERSION}" VERSION_LESS "10.5")
+ # Need to list dependent shared libraries on link line. When building
+ # with -isysroot (for universal binaries), the linker always looks for
+ # dependent libraries under the sysroot. Listing them on the link
+ # line works around the problem.
+ set(CMAKE_LINK_DEPENDENT_LIBRARY_FILES 1)
+endif()
+
+foreach(lang C CXX Fortran OBJC OBJCXX)
+ # Xcode does not support -isystem yet.
+ if(XCODE)
+ set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang})
+ endif()
+
+ set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
+ "<CMAKE_${lang}_COMPILER> <LANGUAGE_COMPILE_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <LINK_FLAGS> -o <TARGET> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> <OBJECTS> <LINK_LIBRARIES>")
+
+ set(CMAKE_${lang}_CREATE_SHARED_MODULE
+ "<CMAKE_${lang}_COMPILER> <LANGUAGE_COMPILE_FLAGS> <CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS> <LINK_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
+
+ set(CMAKE_${lang}_CREATE_MACOSX_FRAMEWORK
+ "<CMAKE_${lang}_COMPILER> <LANGUAGE_COMPILE_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <LINK_FLAGS> -o <TARGET> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> <OBJECTS> <LINK_LIBRARIES>")
+
+ # Set default framework search path flag for languages known to use a
+ # preprocessor that may find headers in frameworks.
+ set(CMAKE_${lang}_FRAMEWORK_SEARCH_FLAG -F)
+endforeach()
+
+# default to searching for frameworks first
+if(NOT DEFINED CMAKE_FIND_FRAMEWORK)
+ set(CMAKE_FIND_FRAMEWORK FIRST)
+endif()
+
+# Older OS X linkers do not report their framework search path
+# with -v but "man ld" documents the following locations.
+set(CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ ${_CMAKE_OSX_SYSROOT_PATH}/Library/Frameworks
+ ${_CMAKE_OSX_SYSROOT_PATH}/System/Library/Frameworks
+ )
+if(_CMAKE_OSX_SYSROOT_PATH)
+ # Treat some paths as implicit so we do not override the SDK versions.
+ list(APPEND CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ /System/Library/Frameworks)
+endif()
+if("${_CURRENT_OSX_VERSION}" VERSION_LESS "10.5")
+ # Older OS X tools had more implicit paths.
+ list(APPEND CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+ ${_CMAKE_OSX_SYSROOT_PATH}/Network/Library/Frameworks)
+endif()
+
+# set up the default search directories for frameworks
+set(CMAKE_SYSTEM_FRAMEWORK_PATH
+ ~/Library/Frameworks
+ )
+if(_CMAKE_OSX_SYSROOT_PATH)
+ list(APPEND CMAKE_SYSTEM_FRAMEWORK_PATH
+ ${_CMAKE_OSX_SYSROOT_PATH}/Library/Frameworks
+ ${_CMAKE_OSX_SYSROOT_PATH}/Network/Library/Frameworks
+ ${_CMAKE_OSX_SYSROOT_PATH}/System/Library/Frameworks
+ )
+ # add platform developer framework path if exists
+ foreach(_path
+ # Xcode 6
+ ${_CMAKE_OSX_SYSROOT_PATH}/../../Library/Frameworks
+ # Xcode 5 iOS
+ ${_CMAKE_OSX_SYSROOT_PATH}/Developer/Library/Frameworks
+ # Xcode 5 OSX
+ ${_CMAKE_OSX_SYSROOT_PATH}/../../../../../Library/Frameworks
+ )
+ get_filename_component(_abolute_path "${_path}" ABSOLUTE)
+ if(EXISTS "${_abolute_path}")
+ list(APPEND CMAKE_SYSTEM_FRAMEWORK_PATH "${_abolute_path}")
+ break()
+ endif()
+ endforeach()
+
+ if(EXISTS ${_CMAKE_OSX_SYSROOT_PATH}/usr/lib)
+ list(INSERT CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES 0 ${_CMAKE_OSX_SYSROOT_PATH}/usr/lib)
+ endif()
+ if(EXISTS ${_CMAKE_OSX_SYSROOT_PATH}/usr/local/lib)
+ list(INSERT CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES 0 ${_CMAKE_OSX_SYSROOT_PATH}/usr/local/lib)
+ endif()
+endif()
+if (OSX_DEVELOPER_ROOT AND EXISTS "${OSX_DEVELOPER_ROOT}/Library/Frameworks")
+ list(APPEND CMAKE_SYSTEM_FRAMEWORK_PATH
+ ${OSX_DEVELOPER_ROOT}/Library/Frameworks)
+endif()
+list(APPEND CMAKE_SYSTEM_FRAMEWORK_PATH
+ /Library/Frameworks
+ /Network/Library/Frameworks
+ /System/Library/Frameworks)
+
+# Warn about known system mis-configuration case.
+if(CMAKE_OSX_SYSROOT)
+ get_property(_IN_TC GLOBAL PROPERTY IN_TRY_COMPILE)
+ if(NOT _IN_TC AND
+ NOT IS_SYMLINK "${CMAKE_OSX_SYSROOT}/Library/Frameworks"
+ AND IS_SYMLINK "${CMAKE_OSX_SYSROOT}/Library/Frameworks/Frameworks")
+ message(WARNING "The SDK Library/Frameworks path\n"
+ " ${CMAKE_OSX_SYSROOT}/Library/Frameworks\n"
+ "is not set up correctly on this system. "
+ "This is known to occur when installing Xcode 3.2.6:\n"
+ " http://bugs.python.org/issue14018\n"
+ "The problem may cause build errors that report missing system frameworks. "
+ "Fix your SDK symlinks to resolve this issue and avoid this warning."
+ )
+ endif()
+endif()
+
+# default to searching for application bundles first
+if(NOT DEFINED CMAKE_FIND_APPBUNDLE)
+ set(CMAKE_FIND_APPBUNDLE FIRST)
+endif()
+# set up the default search directories for application bundles
+set(_apps_paths)
+foreach(_path
+ "~/Applications"
+ "/Applications"
+ "${OSX_DEVELOPER_ROOT}/../Applications" # Xcode 4.3+
+ "${OSX_DEVELOPER_ROOT}/Applications" # pre-4.3
+ )
+ get_filename_component(_apps "${_path}" ABSOLUTE)
+ if(EXISTS "${_apps}")
+ list(APPEND _apps_paths "${_apps}")
+ endif()
+endforeach()
+if(_apps_paths)
+ list(REMOVE_DUPLICATES _apps_paths)
+endif()
+set(CMAKE_SYSTEM_APPBUNDLE_PATH
+ ${_apps_paths})
+unset(_apps_paths)
+
+include(Platform/UnixPaths)
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
+ list(PREPEND CMAKE_SYSTEM_PREFIX_PATH
+ /opt/homebrew # Brew on Apple Silicon
+ )
+endif()
+
+if(_CMAKE_OSX_SYSROOT_PATH)
+ if(EXISTS ${_CMAKE_OSX_SYSROOT_PATH}/usr/include)
+ list(INSERT CMAKE_SYSTEM_PREFIX_PATH 0 ${_CMAKE_OSX_SYSROOT_PATH}/usr)
+ foreach(lang C CXX OBJC OBJCXX Swift)
+ list(APPEND _CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES_INIT ${_CMAKE_OSX_SYSROOT_PATH}/usr/include)
+ endforeach()
+ endif()
+ if(EXISTS ${_CMAKE_OSX_SYSROOT_PATH}/usr/local/include)
+ list(INSERT CMAKE_SYSTEM_PREFIX_PATH 0 ${_CMAKE_OSX_SYSROOT_PATH}/usr/local)
+ foreach(lang C CXX OBJC OBJCXX Swift)
+ list(APPEND _CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES_INIT ${_CMAKE_OSX_SYSROOT_PATH}/usr/local/include)
+ endforeach()
+ endif()
+endif()
+list(APPEND CMAKE_SYSTEM_PREFIX_PATH
+ /sw # Fink
+ /opt/local # MacPorts
+ )
diff --git a/Modules/Platform/DragonFly.cmake b/Modules/Platform/DragonFly.cmake
new file mode 100644
index 0000000..12e5f3c
--- /dev/null
+++ b/Modules/Platform/DragonFly.cmake
@@ -0,0 +1,9 @@
+# DragonFly BSD was forked from FreeBSD and is still very close to it
+# http://www.dragonflybsd.org
+# see http://archive.netbsd.se/?ml=dfbsd-users&a=2007-07&m=4678361
+
+include(Platform/FreeBSD)
+
+# DragonFly BSD requires -z origin to enable $ORIGIN expansion in RPATH.
+# This is not required for FreeBSD since 10.2-RELEASE.
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-z,origin,-rpath,")
diff --git a/Modules/Platform/Euros.cmake b/Modules/Platform/Euros.cmake
new file mode 100644
index 0000000..4c7b182
--- /dev/null
+++ b/Modules/Platform/Euros.cmake
@@ -0,0 +1,19 @@
+# Support for EUROS RTOS (euros-embedded.com)
+set(CMAKE_LINK_LIBRARY_SUFFIX "")
+set(CMAKE_STATIC_LIBRARY_PREFIX "")
+set(CMAKE_STATIC_LIBRARY_SUFFIX ".lib")
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".lib")
+set(CMAKE_EXECUTABLE_SUFFIX ".elf")
+set(CMAKE_DL_LIBS "")
+
+set(CMAKE_FIND_LIBRARY_PREFIXES "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
+
+# EUROS RTOS does not support shared libs
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
+
+set(CMAKE_CXX_LINK_SHARED_LIBRARY )
+set(CMAKE_CXX_LINK_MODULE_LIBRARY )
+set(CMAKE_C_LINK_SHARED_LIBRARY )
+set(CMAKE_C_LINK_MODULE_LIBRARY )
diff --git a/Modules/Platform/FreeBSD-Determine-CXX.cmake b/Modules/Platform/FreeBSD-Determine-CXX.cmake
new file mode 100644
index 0000000..b594dae
--- /dev/null
+++ b/Modules/Platform/FreeBSD-Determine-CXX.cmake
@@ -0,0 +1,3 @@
+if(NOT CMAKE_CXX_COMPILER_NAMES)
+ set(CMAKE_CXX_COMPILER_NAMES c++)
+endif()
diff --git a/Modules/Platform/FreeBSD.cmake b/Modules/Platform/FreeBSD.cmake
new file mode 100644
index 0000000..4a4c00d
--- /dev/null
+++ b/Modules/Platform/FreeBSD.cmake
@@ -0,0 +1,29 @@
+set(CMAKE_DL_LIBS "")
+set(CMAKE_C_COMPILE_OPTIONS_PIC "-fPIC")
+set(CMAKE_C_COMPILE_OPTIONS_PIE "-fPIE")
+# PIE link options are managed in Compiler/<compiler>.cmake file
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-fPIC") # -pic
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared") # -shared
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # +s, flag for exe link to use shared lib
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,") # -rpath
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":") # : or empty
+# Does not require -z origin since 10.2-RELEASE
+set(CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN "\$ORIGIN")
+set(CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG "-Wl,-rpath-link,")
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
+set(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
+
+# Shared libraries with no builtin soname may not be linked safely by
+# specifying the file path.
+set(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
+
+# Initialize C link type selection flags. These flags are used when
+# building a shared library, shared module, or executable that links
+# to other libraries to select whether to use the static or shared
+# versions of the libraries.
+foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+ set(CMAKE_${type}_LINK_STATIC_C_FLAGS "-Wl,-Bstatic")
+ set(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-Wl,-Bdynamic")
+endforeach()
+
+include(Platform/UnixPaths)
diff --git a/Modules/Platform/Fuchsia.cmake b/Modules/Platform/Fuchsia.cmake
new file mode 100644
index 0000000..4b13805
--- /dev/null
+++ b/Modules/Platform/Fuchsia.cmake
@@ -0,0 +1,28 @@
+set(FUCHSIA 1)
+
+set(CMAKE_DL_LIBS "")
+set(CMAKE_C_COMPILE_OPTIONS_PIC "-fPIC")
+set(CMAKE_C_COMPILE_OPTIONS_PIE "-fPIE")
+set(_CMAKE_C_PIE_MAY_BE_SUPPORTED_BY_LINKER YES)
+set(CMAKE_C_LINK_OPTIONS_PIE ${CMAKE_C_COMPILE_OPTIONS_PIE} "-pie")
+set(CMAKE_C_LINK_OPTIONS_NO_PIE "-no-pie")
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-fPIC")
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
+set(CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG "-Wl,-rpath-link,")
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
+set(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
+
+# Shared libraries with no builtin soname may not be linked safely by
+# specifying the file path.
+set(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
+
+# Initialize C link type selection flags. These flags are used when
+# building a shared library, shared module, or executable that links
+# to other libraries to select whether to use the static or shared
+# versions of the libraries.
+foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+ set(CMAKE_${type}_LINK_STATIC_C_FLAGS "-Wl,-Bstatic")
+ set(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-Wl,-Bdynamic")
+endforeach()
diff --git a/Modules/Platform/GHS-MULTI-Determine.cmake b/Modules/Platform/GHS-MULTI-Determine.cmake
new file mode 100644
index 0000000..349d906
--- /dev/null
+++ b/Modules/Platform/GHS-MULTI-Determine.cmake
@@ -0,0 +1,56 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#Setup Green Hills MULTI specific compilation information
+
+if(CMAKE_HOST_UNIX)
+ set(GHS_OS_ROOT "/usr/ghs" CACHE PATH "GHS platform OS search root directory")
+else()
+ set(GHS_OS_ROOT "C:/ghs" CACHE PATH "GHS platform OS search root directory")
+endif()
+mark_as_advanced(GHS_OS_ROOT)
+
+set(GHS_OS_DIR "NOTFOUND" CACHE PATH "GHS platform OS directory")
+mark_as_advanced(GHS_OS_DIR)
+
+set(GHS_OS_DIR_OPTION "-os_dir " CACHE STRING "GHS compiler OS option")
+mark_as_advanced(GHS_OS_DIR_OPTION)
+
+#set GHS_OS_DIR if not set by user
+if(NOT GHS_OS_DIR)
+ if(EXISTS ${GHS_OS_ROOT})
+
+ #get all directories in root directory
+ FILE(GLOB GHS_CANDIDATE_OS_DIRS
+ LIST_DIRECTORIES true RELATIVE ${GHS_OS_ROOT} ${GHS_OS_ROOT}/*)
+ FILE(GLOB GHS_CANDIDATE_OS_FILES
+ LIST_DIRECTORIES false RELATIVE ${GHS_OS_ROOT} ${GHS_OS_ROOT}/*)
+ if(GHS_CANDIDATE_OS_FILES)
+ list(REMOVE_ITEM GHS_CANDIDATE_OS_DIRS ${GHS_CANDIDATE_OS_FILES})
+ endif ()
+
+ #filter based on platform name
+ if(GHS_TARGET_PLATFORM MATCHES "integrity")
+ list(FILTER GHS_CANDIDATE_OS_DIRS INCLUDE REGEX "int[0-9][0-9][0-9][0-9a-z]")
+ else() #fall-back for standalone
+ unset(GHS_CANDIDATE_OS_DIRS)
+ set(GHS_OS_DIR "IGNORE")
+ endif()
+
+ if(GHS_CANDIDATE_OS_DIRS)
+ list(SORT GHS_CANDIDATE_OS_DIRS)
+ list(GET GHS_CANDIDATE_OS_DIRS -1 GHS_OS_DIR)
+ string(CONCAT GHS_OS_DIR ${GHS_OS_ROOT} "/" ${GHS_OS_DIR})
+ endif()
+
+ #update cache with new value
+ set(GHS_OS_DIR "${GHS_OS_DIR}" CACHE PATH "GHS platform OS directory" FORCE)
+ endif()
+endif()
+
+set(GHS_BSP_NAME "IGNORE" CACHE STRING "BSP name")
+
+set(GHS_CUSTOMIZATION "" CACHE FILEPATH "optional GHS customization")
+mark_as_advanced(GHS_CUSTOMIZATION)
+set(GHS_GPJ_MACROS "" CACHE STRING "optional GHS macros generated in the .gpjs for legacy reasons")
+mark_as_advanced(GHS_GPJ_MACROS)
diff --git a/Modules/Platform/GHS-MULTI.cmake b/Modules/Platform/GHS-MULTI.cmake
new file mode 100644
index 0000000..60a15c4
--- /dev/null
+++ b/Modules/Platform/GHS-MULTI.cmake
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+
+if(__GHSMULTI)
+ return()
+endif()
+set(__GHSMULTI 1)
+
+set(GHSMULTI 1)
+
+set(CMAKE_FIND_LIBRARY_PREFIXES "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
+
+include(Platform/WindowsPaths)
diff --git a/Modules/Platform/GNU.cmake b/Modules/Platform/GNU.cmake
new file mode 100644
index 0000000..fac29a8
--- /dev/null
+++ b/Modules/Platform/GNU.cmake
@@ -0,0 +1,40 @@
+# GCC is the default compiler on GNU/Hurd.
+set(CMAKE_DL_LIBS "dl")
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-fPIC")
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
+set(CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG "-Wl,-rpath-link,")
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
+set(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
+
+# Debian policy requires that shared libraries be installed without
+# executable permission. Fedora policy requires that shared libraries
+# be installed with the executable permission. Since the native tools
+# create shared libraries with execute permission in the first place a
+# reasonable policy seems to be to install with execute permission by
+# default. In order to support debian packages we provide an option
+# here. The option default is based on the current distribution, but
+# packagers can set it explicitly on the command line.
+if(DEFINED CMAKE_INSTALL_SO_NO_EXE)
+ # Store the decision variable in the cache. This preserves any
+ # setting the user provides on the command line.
+ set(CMAKE_INSTALL_SO_NO_EXE "${CMAKE_INSTALL_SO_NO_EXE}" CACHE INTERNAL
+ "Install .so files without execute permission.")
+else()
+ # Store the decision variable as an internal cache entry to avoid
+ # checking the platform every time. This option is advanced enough
+ # that only package maintainers should need to adjust it. They are
+ # capable of providing a setting on the command line.
+ if(EXISTS "/etc/debian_version")
+ set(CMAKE_INSTALL_SO_NO_EXE 1 CACHE INTERNAL
+ "Install .so files without execute permission.")
+ else()
+ set(CMAKE_INSTALL_SO_NO_EXE 0 CACHE INTERNAL
+ "Install .so files without execute permission.")
+ endif()
+endif()
+
+set(CMAKE_LIBRARY_ARCHITECTURE_REGEX "[a-z0-9_]+(-[a-z0-9_]+)?-gnu[a-z0-9_]*")
+
+include(Platform/UnixPaths)
diff --git a/Modules/Platform/GNUtoMS_lib.bat.in b/Modules/Platform/GNUtoMS_lib.bat.in
new file mode 100644
index 0000000..62776f4
--- /dev/null
+++ b/Modules/Platform/GNUtoMS_lib.bat.in
@@ -0,0 +1,4 @@
+@echo off
+set VSCMD_START_DIR=.
+call "@CMAKE_GNUtoMS_BAT@"
+lib /machine:"@CMAKE_GNUtoMS_ARCH@" %*
diff --git a/Modules/Platform/GNUtoMS_lib.cmake b/Modules/Platform/GNUtoMS_lib.cmake
new file mode 100644
index 0000000..ca9b0f8
--- /dev/null
+++ b/Modules/Platform/GNUtoMS_lib.cmake
@@ -0,0 +1,10 @@
+# Usage: cmake -Dlib=lib.bat -Ddef=out.def -Ddll=out.dll -Dimp=out.dll.a -P GNUtoMS_lib.cmake
+get_filename_component(name ${dll} NAME) # .dll file name
+string(REGEX REPLACE "\\.dll\\.a$" ".lib" out "${imp}") # .dll.a -> .lib
+execute_process(
+ COMMAND ${lib} /def:${def} /name:${name} /out:${out}
+ RESULT_VARIABLE res
+ )
+if(res)
+ message(FATAL_ERROR "lib failed: ${res}")
+endif()
diff --git a/Modules/Platform/Generic-ADSP-ASM.cmake b/Modules/Platform/Generic-ADSP-ASM.cmake
new file mode 100644
index 0000000..e718bec
--- /dev/null
+++ b/Modules/Platform/Generic-ADSP-ASM.cmake
@@ -0,0 +1,7 @@
+include(Platform/Generic-ADSP-Common)
+
+set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS asm)
+set(CMAKE_ASM_OUTPUT_EXTENSION ".doj" )
+set(CMAKE_ASM_COMPILE_OBJECT
+ "<CMAKE_ASM_COMPILER> <INCLUDES> <FLAGS> -proc ${ADSP_PROCESSOR} -si-revision ${ADSP_PROCESSOR_SILICIUM_REVISION} -o <OBJECT> <SOURCE>")
+
diff --git a/Modules/Platform/Generic-ADSP-C.cmake b/Modules/Platform/Generic-ADSP-C.cmake
new file mode 100644
index 0000000..c8597cd
--- /dev/null
+++ b/Modules/Platform/Generic-ADSP-C.cmake
@@ -0,0 +1,22 @@
+
+include(Platform/Generic-ADSP-Common)
+
+
+set(CMAKE_C_OUTPUT_EXTENSION ".doj")
+
+string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -g")
+string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " ")
+string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " ")
+string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " ")
+
+set(CMAKE_C_LINKER_WRAPPER_FLAG "-flags-link" " ")
+set(CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",")
+
+set(CMAKE_C_CREATE_STATIC_LIBRARY
+ "<CMAKE_C_COMPILER> -build-lib -proc ${ADSP_PROCESSOR} -si-revision ${ADSP_PROCESSOR_SILICIUM_REVISION} -o <TARGET> <CMAKE_C_LINK_FLAGS> <OBJECTS>")
+
+set(CMAKE_C_LINK_EXECUTABLE
+ "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+
+set(CMAKE_C_CREATE_SHARED_LIBRARY)
+set(CMAKE_C_CREATE_MODULE_LIBRARY)
diff --git a/Modules/Platform/Generic-ADSP-CXX.cmake b/Modules/Platform/Generic-ADSP-CXX.cmake
new file mode 100644
index 0000000..d76bb66
--- /dev/null
+++ b/Modules/Platform/Generic-ADSP-CXX.cmake
@@ -0,0 +1,20 @@
+include(Platform/Generic-ADSP-Common)
+
+set(CMAKE_CXX_OUTPUT_EXTENSION ".doj")
+
+string(APPEND CMAKE_CXX_FLAGS_DEBUG_INIT " -g")
+string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " ")
+string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " ")
+string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " ")
+
+set(CMAKE_CXX_LINKER_WRAPPER_FLAG "-flags-link" " ")
+set(CMAKE_CXX_LINKER_WRAPPER_FLAG_SEP ",")
+
+set(CMAKE_CXX_CREATE_STATIC_LIBRARY
+ "<CMAKE_CXX_COMPILER> -build-lib -proc ${ADSP_PROCESSOR} -si-revision ${ADSP_PROCESSOR_SILICIUM_REVISION} -o <TARGET> <CMAKE_CXX_LINK_FLAGS> <OBJECTS>")
+
+set(CMAKE_CXX_LINK_EXECUTABLE
+ "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+
+set(CMAKE_CXX_CREATE_SHARED_LIBRARY)
+set(CMAKE_CXX_CREATE_MODULE_LIBRARY)
diff --git a/Modules/Platform/Generic-ADSP-Common.cmake b/Modules/Platform/Generic-ADSP-Common.cmake
new file mode 100644
index 0000000..026f83c
--- /dev/null
+++ b/Modules/Platform/Generic-ADSP-Common.cmake
@@ -0,0 +1,120 @@
+# support for the Analog Devices toolchain for their DSPs
+# Raphael Cotty" <raphael.cotty (AT) googlemail.com>
+#
+# it supports three architectures:
+# Blackfin
+# TS (TigerShark)
+# 21k (Sharc 21xxx)
+
+if(NOT ADSP)
+
+ set(ADSP TRUE)
+
+ set(CMAKE_STATIC_LIBRARY_SUFFIX ".dlb")
+ set(CMAKE_SHARED_LIBRARY_SUFFIX "")
+ set(CMAKE_EXECUTABLE_SUFFIX ".dxe")
+
+ # if ADSP_PROCESSOR has not been set, but CMAKE_SYSTEM_PROCESSOR has,
+ # assume that this is the processor name to use for the compiler
+ if(CMAKE_SYSTEM_PROCESSOR AND NOT ADSP_PROCESSOR)
+ set(ADSP_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR})
+ endif()
+
+ # if ADSP_PROCESSOR_SILICIUM_REVISION has not been set, use "none"
+ if(NOT ADSP_PROCESSOR_SILICIUM_REVISION)
+ set(ADSP_PROCESSOR_SILICIUM_REVISION "none")
+ endif()
+
+ # this file is included from the C and CXX files, so handle both here
+
+ get_filename_component(_ADSP_DIR "${CMAKE_C_COMPILER}" PATH)
+ if(NOT _ADSP_DIR)
+ get_filename_component(_ADSP_DIR "${CMAKE_CXX_COMPILER}" PATH)
+ endif()
+ if(NOT _ADSP_DIR)
+ get_filename_component(_ADSP_DIR "${CMAKE_ASM_COMPILER}" PATH)
+ endif()
+
+ # detect architecture
+
+ if(CMAKE_C_COMPILER MATCHES ccblkfn OR CMAKE_CXX_COMPILER MATCHES ccblkfn OR CMAKE_ASM_COMPILER MATCHES easmBLKFN)
+ if(NOT ADSP_PROCESSOR)
+ set(ADSP_PROCESSOR "ADSP-BF561")
+ endif()
+ set(ADSP_BLACKFIN TRUE)
+ set(_ADSP_FAMILY_DIR "${_ADSP_DIR}/Blackfin")
+ endif()
+
+ if(CMAKE_C_COMPILER MATCHES ccts OR CMAKE_CXX_COMPILER MATCHES ccts OR CMAKE_ASM_COMPILER MATCHES easmTS)
+ if(NOT ADSP_PROCESSOR)
+ set(ADSP_PROCESSOR "ADSP-TS101")
+ endif()
+ set(ADSP_TS TRUE)
+ set(_ADSP_FAMILY_DIR "${_ADSP_DIR}/TS")
+ endif()
+
+ if(CMAKE_C_COMPILER MATCHES cc21k OR CMAKE_CXX_COMPILER MATCHES cc21k OR CMAKE_ASM_COMPILER MATCHES easm21k)
+ if(NOT ADSP_PROCESSOR)
+ set(ADSP_PROCESSOR "ADSP-21060")
+ endif()
+ set(ADSP_21K TRUE)
+
+ set(_ADSP_FAMILY_DIR "${_ADSP_DIR}/21k") # default if nothing matches
+ if (ADSP_PROCESSOR MATCHES "210..$")
+ set(_ADSP_FAMILY_DIR "${_ADSP_DIR}/21k")
+ endif()
+
+ if (ADSP_PROCESSOR MATCHES "211..$")
+ set(_ADSP_FAMILY_DIR "${_ADSP_DIR}/211k")
+ endif()
+
+ if (ADSP_PROCESSOR MATCHES "212..$")
+ set(_ADSP_FAMILY_DIR "${_ADSP_DIR}/212k")
+ endif()
+
+ if (ADSP_PROCESSOR MATCHES "213..$")
+ set(_ADSP_FAMILY_DIR "${_ADSP_DIR}/213k")
+ endif()
+
+ set(_ADSP_FAMILY_DIR "${_ADSP_DIR}/21k")
+ endif()
+
+
+ link_directories("${_ADSP_FAMILY_DIR}/lib")
+
+ # vdk support
+ find_program( ADSP_VDKGEN_EXECUTABLE vdkgen "${_ADSP_FAMILY_DIR}/vdk" )
+
+ macro(ADSP_GENERATE_VDK VDK_GENERATED_HEADER VDK_GENERATED_SOURCE VDK_KERNEL_SUPPORT_FILE)
+ add_custom_command(
+ OUTPUT ${VDK_GENERATED_HEADER} ${VDK_GENERATED_SOURCE}
+ COMMAND ${ADSP_VDKGEN_EXECUTABLE} ${VDK_KERNEL_SUPPORT_FILE} -proc ${ADSP_PROCESSOR} -si-revision ${ADSP_PROCESSOR_SILICIUM_REVISION} -MM
+ DEPENDS ${VDK_KERNEL_SUPPORT_FILE}
+ )
+ endmacro()
+
+ # loader support
+ find_program( ADSP_ELFLOADER_EXECUTABLE elfloader "${_ADSP_FAMILY_DIR}" )
+
+ # BOOT_MODE: prom, flash, spi, spislave, UART, TWI, FIFO
+ # FORMAT: hex, ASCII, binary, include
+ # WIDTH: 8, 16
+ macro(ADSP_CREATE_LOADER_FILE TARGET_NAME BOOT_MODE FORMAT WIDTH)
+ add_custom_command(
+ TARGET ${TARGET_NAME}
+ POST_BUILD
+ COMMAND ${ADSP_ELFLOADER_EXECUTABLE} ${EXECUTABLE_OUTPUT_PATH}/${TARGET_NAME}.dxe -proc ${ADSP_PROCESSOR} -si-revision ${ADSP_PROCESSOR_SILICIUM_REVISION} -b ${BOOT_MODE} -f ${FORMAT} -width ${WIDTH} -o ${EXECUTABLE_OUTPUT_PATH}/${TARGET_NAME}.ldr
+ COMMENT "Building the loader file"
+ )
+ endmacro()
+
+ macro(ADSP_CREATE_LOADER_FILE_INIT TARGET_NAME BOOT_MODE FORMAT WIDTH INITIALIZATION_FILE)
+ add_custom_command(
+ TARGET ${TARGET_NAME}
+ POST_BUILD
+ COMMAND ${ADSP_ELFLOADER_EXECUTABLE} ${EXECUTABLE_OUTPUT_PATH}/${TARGET_NAME}.dxe -proc ${ADSP_PROCESSOR} -si-revision ${ADSP_PROCESSOR_SILICIUM_REVISION} -b ${BOOT_MODE} -f ${FORMAT} -width ${WIDTH} -o ${EXECUTABLE_OUTPUT_PATH}/${TARGET_NAME}.ldr -init ${INITIALIZATION_FILE}
+ COMMENT "Building the loader file"
+ )
+ endmacro()
+
+endif()
diff --git a/Modules/Platform/Generic-SDCC-C.cmake b/Modules/Platform/Generic-SDCC-C.cmake
new file mode 100644
index 0000000..c3fd186
--- /dev/null
+++ b/Modules/Platform/Generic-SDCC-C.cmake
@@ -0,0 +1,58 @@
+# This file implements basic support for sdcc (http://sdcc.sourceforge.net/)
+# a free C compiler for 8 and 16 bit microcontrollers.
+# To use it either a toolchain file is required or cmake has to be run like this:
+# cmake -DCMAKE_C_COMPILER=sdcc -DCMAKE_SYSTEM_NAME=Generic <dir...>
+# Since sdcc doesn't support C++, C++ support should be disabled in the
+# CMakeLists.txt using the project() command:
+# project(my_project C)
+
+set(CMAKE_STATIC_LIBRARY_PREFIX "")
+set(CMAKE_STATIC_LIBRARY_SUFFIX ".lib")
+set(CMAKE_SHARED_LIBRARY_PREFIX "") # lib
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".lib") # .so
+set(CMAKE_IMPORT_LIBRARY_PREFIX )
+set(CMAKE_IMPORT_LIBRARY_SUFFIX )
+set(CMAKE_EXECUTABLE_SUFFIX ".ihx") # intel hex file
+set(CMAKE_LINK_LIBRARY_SUFFIX ".lib")
+set(CMAKE_DL_LIBS "")
+
+set(CMAKE_C_OUTPUT_EXTENSION ".rel")
+
+# find sdar/sdcclib as CMAKE_AR
+# since cmake may already have searched for "ar", sdar has to
+# be searched with a different variable name (SDCCAR_EXECUTABLE)
+# and must then be forced into the cache.
+# sdcclib has been deprecated in SDCC 3.2.0 and removed in 3.8.6
+# so we first look for sdar
+get_filename_component(SDCC_LOCATION "${CMAKE_C_COMPILER}" PATH)
+find_program(SDCCAR_EXECUTABLE sdar NAMES sdcclib PATHS "${SDCC_LOCATION}" NO_DEFAULT_PATH)
+find_program(SDCCAR_EXECUTABLE sdar NAMES sdcclib)
+# for compatibility, in case SDCCLIB_EXECUTABLE is set, we use it
+if(DEFINED SDCCLIB_EXECUTABLE)
+ set(CMAKE_AR "${SDCCLIB_EXECUTABLE}" CACHE FILEPATH "The sdcc librarian" FORCE)
+else()
+ set(CMAKE_AR "${SDCCAR_EXECUTABLE}" CACHE FILEPATH "The sdcc librarian" FORCE)
+endif()
+
+if("${SDCCAR_EXECUTABLE}" MATCHES "sdcclib")
+ set(CMAKE_AR_OPTIONS "-a")
+else()
+ set(CMAKE_AR_OPTIONS "-rc")
+endif()
+
+set(CMAKE_C_LINKER_WRAPPER_FLAG "-Wl" ",")
+
+# compile a C file into an object file
+set(CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+
+# link object files to an executable
+set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <OBJECTS> -o <TARGET> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>")
+
+# needs sdcc + sdar/sdcclib
+set(CMAKE_C_CREATE_STATIC_LIBRARY
+ "\"${CMAKE_COMMAND}\" -E remove <TARGET>"
+ "<CMAKE_AR> ${CMAKE_AR_OPTIONS} <TARGET> <LINK_FLAGS> <OBJECTS> ")
+
+# not supported by sdcc
+set(CMAKE_C_CREATE_SHARED_LIBRARY "")
+set(CMAKE_C_CREATE_MODULE_LIBRARY "")
diff --git a/Modules/Platform/Generic.cmake b/Modules/Platform/Generic.cmake
new file mode 100644
index 0000000..fcb2699
--- /dev/null
+++ b/Modules/Platform/Generic.cmake
@@ -0,0 +1,17 @@
+# This is a platform definition file for platforms without
+# operating system, typically embedded platforms.
+# It is used when CMAKE_SYSTEM_NAME is set to "Generic"
+#
+# It is intentionally empty, since nothing is known
+# about the platform. So everything has to be specified
+# in the system/compiler files ${CMAKE_SYSTEM_NAME}-<compiler_basename>.cmake
+# and/or ${CMAKE_SYSTEM_NAME}-<compiler_basename>-${CMAKE_SYSTEM_PROCESSOR}.cmake
+
+# (embedded) targets without operating system usually don't support shared libraries
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
+
+# To help the find_xxx() commands, set at least the following so CMAKE_FIND_ROOT_PATH
+# works at least for some simple cases:
+set(CMAKE_SYSTEM_INCLUDE_PATH /include )
+set(CMAKE_SYSTEM_LIBRARY_PATH /lib )
+set(CMAKE_SYSTEM_PROGRAM_PATH /bin )
diff --git a/Modules/Platform/HP-UX-GNU-ASM.cmake b/Modules/Platform/HP-UX-GNU-ASM.cmake
new file mode 100644
index 0000000..613b859
--- /dev/null
+++ b/Modules/Platform/HP-UX-GNU-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/HP-UX-GNU)
+__hpux_compiler_gnu(ASM)
diff --git a/Modules/Platform/HP-UX-GNU-C.cmake b/Modules/Platform/HP-UX-GNU-C.cmake
new file mode 100644
index 0000000..5f9ac42
--- /dev/null
+++ b/Modules/Platform/HP-UX-GNU-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/HP-UX-GNU)
+__hpux_compiler_gnu(C)
diff --git a/Modules/Platform/HP-UX-GNU-CXX.cmake b/Modules/Platform/HP-UX-GNU-CXX.cmake
new file mode 100644
index 0000000..ac72560
--- /dev/null
+++ b/Modules/Platform/HP-UX-GNU-CXX.cmake
@@ -0,0 +1,3 @@
+include(Platform/HP-UX-GNU)
+__hpux_compiler_gnu(CXX)
+unset(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN)
diff --git a/Modules/Platform/HP-UX-GNU-Fortran.cmake b/Modules/Platform/HP-UX-GNU-Fortran.cmake
new file mode 100644
index 0000000..ee0181f
--- /dev/null
+++ b/Modules/Platform/HP-UX-GNU-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/HP-UX-GNU)
+__hpux_compiler_gnu(Fortran)
diff --git a/Modules/Platform/HP-UX-GNU.cmake b/Modules/Platform/HP-UX-GNU.cmake
new file mode 100644
index 0000000..699c4aa
--- /dev/null
+++ b/Modules/Platform/HP-UX-GNU.cmake
@@ -0,0 +1,20 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__HPUX_COMPILER_GNU)
+ return()
+endif()
+set(__HPUX_COMPILER_GNU 1)
+
+macro(__hpux_compiler_gnu lang)
+ string(APPEND CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS " -Wl,-E,-b,+nodefaultrpath")
+ set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-Wl,-E")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG "-Wl,+b")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP ":")
+ set(CMAKE_SHARED_LIBRARY_SONAME_${lang}_FLAG "-Wl,+h")
+
+ set(CMAKE_${lang}_LINK_FLAGS "-Wl,+s,+nodefaultrpath")
+ unset(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY)
+endmacro()
diff --git a/Modules/Platform/HP-UX-HP-ASM.cmake b/Modules/Platform/HP-UX-HP-ASM.cmake
new file mode 100644
index 0000000..05c69e4
--- /dev/null
+++ b/Modules/Platform/HP-UX-HP-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/HP-UX-HP)
+__hpux_compiler_hp(ASM)
diff --git a/Modules/Platform/HP-UX-HP-C.cmake b/Modules/Platform/HP-UX-HP-C.cmake
new file mode 100644
index 0000000..57ba2eb
--- /dev/null
+++ b/Modules/Platform/HP-UX-HP-C.cmake
@@ -0,0 +1,6 @@
+include(Platform/HP-UX-HP)
+__hpux_compiler_hp(C)
+
+set(CMAKE_C_CREATE_PREPROCESSED_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+set(CMAKE_C_CREATE_ASSEMBLY_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+set(CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> <DEFINES> -Aa -Ae <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
diff --git a/Modules/Platform/HP-UX-HP-CXX.cmake b/Modules/Platform/HP-UX-HP-CXX.cmake
new file mode 100644
index 0000000..d37d2b0
--- /dev/null
+++ b/Modules/Platform/HP-UX-HP-CXX.cmake
@@ -0,0 +1,14 @@
+include(Platform/HP-UX-HP)
+__hpux_compiler_hp(CXX)
+
+set(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+set(CMAKE_CXX_CREATE_ASSEMBLY_SOURCE
+ "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE>"
+ "mv `basename \"<SOURCE>\" | sed 's/\\.[^./]*$$//'`.s <ASSEMBLY_SOURCE>"
+ "rm -f `basename \"<SOURCE>\" | sed 's/\\.[^./]*$$//'`.o"
+ )
+
+string(APPEND CMAKE_CXX_FLAGS_DEBUG_INIT " -g")
+string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " +O3 -DNDEBUG")
+string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " +O2 -DNDEBUG")
+string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -g")
diff --git a/Modules/Platform/HP-UX-HP-Fortran.cmake b/Modules/Platform/HP-UX-HP-Fortran.cmake
new file mode 100644
index 0000000..12007e4
--- /dev/null
+++ b/Modules/Platform/HP-UX-HP-Fortran.cmake
@@ -0,0 +1,5 @@
+include(Platform/HP-UX-HP)
+__hpux_compiler_hp(Fortran)
+
+set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
diff --git a/Modules/Platform/HP-UX-HP.cmake b/Modules/Platform/HP-UX-HP.cmake
new file mode 100644
index 0000000..b301d17
--- /dev/null
+++ b/Modules/Platform/HP-UX-HP.cmake
@@ -0,0 +1,23 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__HPUX_COMPILER_HP)
+ return()
+endif()
+set(__HPUX_COMPILER_HP 1)
+
+macro(__hpux_compiler_hp lang)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "+Z")
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "+Z")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-Wl,-E,+nodefaultrpath -b -L/usr/lib")
+ set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-Wl,-E")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG "-Wl,+b")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP ":")
+ set(CMAKE_SHARED_LIBRARY_SONAME_${lang}_FLAG "-Wl,+h")
+
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
+
+ set(CMAKE_${lang}_LINK_FLAGS "-Wl,+s,+nodefaultrpath")
+endmacro()
diff --git a/Modules/Platform/HP-UX.cmake b/Modules/Platform/HP-UX.cmake
new file mode 100644
index 0000000..425a13f
--- /dev/null
+++ b/Modules/Platform/HP-UX.cmake
@@ -0,0 +1,47 @@
+if(NOT DEFINED CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH)
+ set(CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH /usr/lib)
+endif()
+
+if(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "ia64")
+ set(CMAKE_SHARED_LIBRARY_SUFFIX ".sl") # .so
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".sl" ".so" ".a")
+ set(CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES ".so")
+endif()
+set(CMAKE_DL_LIBS "dld")
+
+# The HP linker needs to find transitive shared library dependencies
+# in the -L path. Therefore the runtime path must be added to the
+# link line with -L flags.
+set(CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH 1)
+set(CMAKE_LINK_DEPENDENT_LIBRARY_DIRS 1)
+
+# Shared libraries with no builtin soname may not be linked safely by
+# specifying the file path.
+set(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
+
+# set flags for gcc support
+include(Platform/UnixPaths)
+
+# Look in both 32-bit and 64-bit implicit link directories, but tell
+# CMake not to pass the paths to the linker. The linker will find the
+# library for the proper architecture. In the future we should detect
+# which path will be used by the linker. Since the pointer type size
+# CMAKE_SIZEOF_VOID_P is not set until after this file executes, we
+# would need to append to CMAKE_SYSTEM_LIBRARY_PATH at a later point
+# (after CMakeTest(LANG)Compiler.cmake runs for at least one language).
+list(APPEND CMAKE_SYSTEM_LIBRARY_PATH /usr/lib/hpux32)
+list(APPEND CMAKE_SYSTEM_LIBRARY_PATH /usr/lib/hpux64)
+list(APPEND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES
+ /usr/lib/hpux32 /usr/lib/hpux64)
+
+# Initialize C and CXX link type selection flags. These flags are
+# used when building a shared library, shared module, or executable
+# that links to other libraries to select whether to use the static or
+# shared versions of the libraries.
+foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+ foreach(lang C CXX)
+ set(CMAKE_${type}_LINK_STATIC_${lang}_FLAGS "-Wl,-a,archive")
+ set(CMAKE_${type}_LINK_DYNAMIC_${lang}_FLAGS "-Wl,-a,default")
+ endforeach()
+endforeach()
+
diff --git a/Modules/Platform/Haiku.cmake b/Modules/Platform/Haiku.cmake
new file mode 100644
index 0000000..7e0af61
--- /dev/null
+++ b/Modules/Platform/Haiku.cmake
@@ -0,0 +1,131 @@
+# process only once
+if(HAIKU)
+ return()
+endif()
+
+set(HAIKU 1)
+set(UNIX 1)
+
+set(CMAKE_DL_LIBS "")
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-fPIC")
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
+set(CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN "\$ORIGIN")
+set(CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG "-Wl,-rpath-link,")
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
+set(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
+
+# Determine, if the C or C++ compiler is configured for a secondary
+# architecture. If so, that will change the search paths we set below. We check
+# whether the compiler's library search paths contain a
+# "/boot/system/develop/lib/<subdir>/", which we assume to be the secondary
+# architecture specific subdirectory and extract the name of the architecture
+# accordingly.
+
+# First of all, find a C or C++ compiler we can run. The "arg1" is necessary
+# here for compilers such as "distcc gcc-x86" or "ccache gcc-x86"
+# TODO See CMakeDetermineCompilerId.cmake for some more things we may want to do.
+if(CMAKE_C_COMPILER)
+ set(__HAIKU_COMPILER ${CMAKE_C_COMPILER})
+ string (STRIP "${CMAKE_C_COMPILER_ARG1}" __HAIKU_COMPILER_FLAGS)
+else()
+ set(__HAIKU_COMPILER ${CMAKE_CXX_COMPILER})
+ string (STRIP "${CMAKE_CXX_COMPILER_ARG1}" __HAIKU_COMPILER_FLAGS)
+endif()
+
+
+execute_process(
+ COMMAND ${__HAIKU_COMPILER} ${__HAIKU_COMPILER_FLAGS} -print-search-dirs
+ OUTPUT_VARIABLE _HAIKU_SEARCH_DIRS
+ RESULT_VARIABLE _HAIKU_SEARCH_DIRS_FOUND
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+string(REGEX MATCH "libraries: =?([^\n]*:)?/boot/system/develop/lib/([^/]*)/?(:?\n+)" _dummy "${_HAIKU_SEARCH_DIRS}\n")
+set(CMAKE_HAIKU_SECONDARY_ARCH "${CMAKE_MATCH_2}")
+
+if(NOT CMAKE_HAIKU_SECONDARY_ARCH)
+ set(CMAKE_HAIKU_SECONDARY_ARCH_SUBDIR "")
+ unset(CMAKE_HAIKU_SECONDARY_ARCH)
+else()
+ set(CMAKE_HAIKU_SECONDARY_ARCH_SUBDIR "/${CMAKE_HAIKU_SECONDARY_ARCH}")
+
+ # Override CMAKE_*LIBRARY_ARCHITECTURE. This will cause FIND_LIBRARY to search
+ # the libraries in the correct subdirectory first. It still isn't completely
+ # correct, since the parent directories shouldn't be searched at all. The
+ # primary architecture library might still be found, if there isn't one
+ # installed for the secondary architecture or it is installed in a less
+ # specific location.
+ set(CMAKE_LIBRARY_ARCHITECTURE ${CMAKE_HAIKU_SECONDARY_ARCH})
+ set(CMAKE_C_LIBRARY_ARCHITECTURE ${CMAKE_HAIKU_SECONDARY_ARCH})
+ set(CMAKE_CXX_LIBRARY_ARCHITECTURE ${CMAKE_HAIKU_SECONDARY_ARCH})
+endif()
+
+list(APPEND CMAKE_SYSTEM_PREFIX_PATH
+ /boot/system/non-packaged
+ /boot/system
+ )
+
+LIST(APPEND CMAKE_HAIKU_COMMON_INCLUDE_DIRECTORIES
+ /boot/system/non-packaged/develop/headers${CMAKE_HAIKU_SECONDARY_ARCH_SUBDIR}
+ /boot/system/develop/headers/os
+ /boot/system/develop/headers/os/app
+ /boot/system/develop/headers/os/device
+ /boot/system/develop/headers/os/drivers
+ /boot/system/develop/headers/os/game
+ /boot/system/develop/headers/os/interface
+ /boot/system/develop/headers/os/kernel
+ /boot/system/develop/headers/os/locale
+ /boot/system/develop/headers/os/mail
+ /boot/system/develop/headers/os/media
+ /boot/system/develop/headers/os/midi
+ /boot/system/develop/headers/os/midi2
+ /boot/system/develop/headers/os/net
+ /boot/system/develop/headers/os/opengl
+ /boot/system/develop/headers/os/storage
+ /boot/system/develop/headers/os/support
+ /boot/system/develop/headers/os/translation
+ /boot/system/develop/headers/os/add-ons/graphics
+ /boot/system/develop/headers/os/add-ons/input_server
+ /boot/system/develop/headers/os/add-ons/screen_saver
+ /boot/system/develop/headers/os/add-ons/tracker
+ /boot/system/develop/headers/os/be_apps/Deskbar
+ /boot/system/develop/headers/os/be_apps/NetPositive
+ /boot/system/develop/headers/os/be_apps/Tracker
+ /boot/system/develop/headers/3rdparty
+ /boot/system/develop/headers/bsd
+ /boot/system/develop/headers/glibc
+ /boot/system/develop/headers/gnu
+ /boot/system/develop/headers/posix
+ /boot/system/develop/headers${CMAKE_HAIKU_SECONDARY_ARCH_SUBDIR}
+ )
+IF (CMAKE_HAIKU_SECONDARY_ARCH)
+ LIST(APPEND CMAKE_HAIKU_COMMON_INCLUDE_DIRECTORIES
+ /boot/system/develop/headers
+ )
+ENDIF (CMAKE_HAIKU_SECONDARY_ARCH)
+
+LIST(APPEND CMAKE_HAIKU_C_INCLUDE_DIRECTORIES
+ ${CMAKE_HAIKU_COMMON_INCLUDE_DIRECTORIES}
+ )
+
+LIST(APPEND CMAKE_HAIKU_CXX_INCLUDE_DIRECTORIES
+ ${CMAKE_HAIKU_COMMON_INCLUDE_DIRECTORIES})
+
+LIST(APPEND CMAKE_SYSTEM_INCLUDE_PATH ${CMAKE_HAIKU_C_INCLUDE_DIRECTORIES})
+
+LIST(APPEND CMAKE_HAIKU_DEVELOP_LIB_DIRECTORIES
+ /boot/system/non-packaged/develop/lib${CMAKE_HAIKU_SECONDARY_ARCH_SUBDIR}
+ /boot/system/develop/lib${CMAKE_HAIKU_SECONDARY_ARCH_SUBDIR}
+ )
+
+LIST(APPEND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES
+ ${CMAKE_HAIKU_DEVELOP_LIB_DIRECTORIES}
+ )
+
+LIST(APPEND CMAKE_SYSTEM_LIBRARY_PATH ${CMAKE_HAIKU_DEVELOP_LIB_DIRECTORIES})
+
+if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX "/boot/system" CACHE PATH
+ "Install path prefix, prepended onto install directories." FORCE)
+endif()
diff --git a/Modules/Platform/Linux-Absoft-Fortran.cmake b/Modules/Platform/Linux-Absoft-Fortran.cmake
new file mode 100644
index 0000000..beb41a3
--- /dev/null
+++ b/Modules/Platform/Linux-Absoft-Fortran.cmake
@@ -0,0 +1 @@
+set(CMAKE_Fortran_VERBOSE_FLAG "-X -v") # Runs gcc under the hood.
diff --git a/Modules/Platform/Linux-CCur-Fortran.cmake b/Modules/Platform/Linux-CCur-Fortran.cmake
new file mode 100644
index 0000000..ceecc2f
--- /dev/null
+++ b/Modules/Platform/Linux-CCur-Fortran.cmake
@@ -0,0 +1 @@
+include(Platform/Linux-GNU-Fortran)
diff --git a/Modules/Platform/Linux-Clang-C.cmake b/Modules/Platform/Linux-Clang-C.cmake
new file mode 100644
index 0000000..2a77d27
--- /dev/null
+++ b/Modules/Platform/Linux-Clang-C.cmake
@@ -0,0 +1 @@
+include(Platform/Linux-GNU-C)
diff --git a/Modules/Platform/Linux-Clang-CXX.cmake b/Modules/Platform/Linux-Clang-CXX.cmake
new file mode 100644
index 0000000..9d9a4df
--- /dev/null
+++ b/Modules/Platform/Linux-Clang-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Linux-GNU-CXX)
diff --git a/Modules/Platform/Linux-Determine-CXX.cmake b/Modules/Platform/Linux-Determine-CXX.cmake
new file mode 100644
index 0000000..b594dae
--- /dev/null
+++ b/Modules/Platform/Linux-Determine-CXX.cmake
@@ -0,0 +1,3 @@
+if(NOT CMAKE_CXX_COMPILER_NAMES)
+ set(CMAKE_CXX_COMPILER_NAMES c++)
+endif()
diff --git a/Modules/Platform/Linux-Fujitsu-C.cmake b/Modules/Platform/Linux-Fujitsu-C.cmake
new file mode 100644
index 0000000..e37573d
--- /dev/null
+++ b/Modules/Platform/Linux-Fujitsu-C.cmake
@@ -0,0 +1 @@
+include(Platform/Linux-Clang-C)
diff --git a/Modules/Platform/Linux-Fujitsu-CXX.cmake b/Modules/Platform/Linux-Fujitsu-CXX.cmake
new file mode 100644
index 0000000..5257f13
--- /dev/null
+++ b/Modules/Platform/Linux-Fujitsu-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Linux-Clang-CXX)
diff --git a/Modules/Platform/Linux-Fujitsu.cmake b/Modules/Platform/Linux-Fujitsu.cmake
new file mode 100644
index 0000000..be11b0a
--- /dev/null
+++ b/Modules/Platform/Linux-Fujitsu.cmake
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__LINUX_COMPILER_FUJITSU)
+ return()
+endif()
+set(__LINUX_COMPILER_FUJITSU 1)
+
+macro(__linux_compiler_fujitsu lang)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
+endmacro()
diff --git a/Modules/Platform/Linux-GNU-C.cmake b/Modules/Platform/Linux-GNU-C.cmake
new file mode 100644
index 0000000..84dd492
--- /dev/null
+++ b/Modules/Platform/Linux-GNU-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Linux-GNU)
+__linux_compiler_gnu(C)
diff --git a/Modules/Platform/Linux-GNU-CXX.cmake b/Modules/Platform/Linux-GNU-CXX.cmake
new file mode 100644
index 0000000..4162335
--- /dev/null
+++ b/Modules/Platform/Linux-GNU-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/Linux-GNU)
+__linux_compiler_gnu(CXX)
diff --git a/Modules/Platform/Linux-GNU-Fortran.cmake b/Modules/Platform/Linux-GNU-Fortran.cmake
new file mode 100644
index 0000000..85e1226
--- /dev/null
+++ b/Modules/Platform/Linux-GNU-Fortran.cmake
@@ -0,0 +1,3 @@
+include(Platform/Linux-GNU)
+__linux_compiler_gnu(Fortran)
+set(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS "")
diff --git a/Modules/Platform/Linux-GNU.cmake b/Modules/Platform/Linux-GNU.cmake
new file mode 100644
index 0000000..6878254
--- /dev/null
+++ b/Modules/Platform/Linux-GNU.cmake
@@ -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.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__LINUX_COMPILER_GNU)
+ return()
+endif()
+set(__LINUX_COMPILER_GNU 1)
+
+macro(__linux_compiler_gnu lang)
+ # We pass this for historical reasons. Projects may have
+ # executables that use dlopen but do not set ENABLE_EXPORTS.
+ set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-rdynamic")
+endmacro()
diff --git a/Modules/Platform/Linux-Intel-C.cmake b/Modules/Platform/Linux-Intel-C.cmake
new file mode 100644
index 0000000..449493a
--- /dev/null
+++ b/Modules/Platform/Linux-Intel-C.cmake
@@ -0,0 +1,3 @@
+include(Platform/Linux-Intel)
+__linux_compiler_intel(C)
+set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-isystem ")
diff --git a/Modules/Platform/Linux-Intel-CXX.cmake b/Modules/Platform/Linux-Intel-CXX.cmake
new file mode 100644
index 0000000..142b6cf
--- /dev/null
+++ b/Modules/Platform/Linux-Intel-CXX.cmake
@@ -0,0 +1,3 @@
+include(Platform/Linux-Intel)
+__linux_compiler_intel(CXX)
+set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-isystem ")
diff --git a/Modules/Platform/Linux-Intel-Fortran.cmake b/Modules/Platform/Linux-Intel-Fortran.cmake
new file mode 100644
index 0000000..a99e793
--- /dev/null
+++ b/Modules/Platform/Linux-Intel-Fortran.cmake
@@ -0,0 +1,4 @@
+include(Platform/Linux-Intel)
+__linux_compiler_intel(Fortran)
+string(APPEND CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS " -nofor-main")
+set(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS "")
diff --git a/Modules/Platform/Linux-Intel.cmake b/Modules/Platform/Linux-Intel.cmake
new file mode 100644
index 0000000..3b5ca59
--- /dev/null
+++ b/Modules/Platform/Linux-Intel.cmake
@@ -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.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__LINUX_COMPILER_INTEL)
+ return()
+endif()
+set(__LINUX_COMPILER_INTEL 1)
+
+if(NOT XIAR)
+ set(_intel_xiar_hints)
+ foreach(lang C CXX Fortran)
+ if(IS_ABSOLUTE "${CMAKE_${lang}_COMPILER}")
+ get_filename_component(_hint "${CMAKE_${lang}_COMPILER}" PATH)
+ list(APPEND _intel_xiar_hints ${_hint})
+ endif()
+ endforeach()
+ find_program(XIAR NAMES xiar HINTS ${_intel_xiar_hints})
+ mark_as_advanced(XIAR)
+endif()
+
+macro(__linux_compiler_intel lang)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
+ set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+ if (NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 13.0)
+ set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER YES)
+ set(CMAKE_${lang}_LINK_OPTIONS_PIE ${CMAKE_${lang}_COMPILE_OPTIONS_PIE} "-pie")
+ set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE "-no-pie")
+ endif()
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
+
+ # We pass this for historical reasons. Projects may have
+ # executables that use dlopen but do not set ENABLE_EXPORTS.
+ set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-rdynamic")
+
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
+ set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
+
+ if(XIAR)
+ # INTERPROCEDURAL_OPTIMIZATION
+ set(CMAKE_${lang}_COMPILE_OPTIONS_IPO -ipo)
+ set(CMAKE_${lang}_CREATE_STATIC_LIBRARY_IPO
+ "${XIAR} cr <TARGET> <LINK_FLAGS> <OBJECTS> "
+ "${XIAR} -s <TARGET> ")
+ set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
+ set(_CMAKE_${lang}_IPO_LEGACY_BEHAVIOR YES)
+ else()
+ set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER NO)
+ endif()
+
+ if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 12.0)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
+ endif()
+endmacro()
diff --git a/Modules/Platform/Linux-IntelLLVM-C.cmake b/Modules/Platform/Linux-IntelLLVM-C.cmake
new file mode 100644
index 0000000..5356c4f
--- /dev/null
+++ b/Modules/Platform/Linux-IntelLLVM-C.cmake
@@ -0,0 +1,3 @@
+include(Platform/Linux-IntelLLVM)
+__linux_compiler_intel_llvm(C)
+set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-isystem ")
diff --git a/Modules/Platform/Linux-IntelLLVM-CXX.cmake b/Modules/Platform/Linux-IntelLLVM-CXX.cmake
new file mode 100644
index 0000000..44ce0e8
--- /dev/null
+++ b/Modules/Platform/Linux-IntelLLVM-CXX.cmake
@@ -0,0 +1,3 @@
+include(Platform/Linux-IntelLLVM)
+__linux_compiler_intel_llvm(CXX)
+set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-isystem ")
diff --git a/Modules/Platform/Linux-IntelLLVM-Fortran.cmake b/Modules/Platform/Linux-IntelLLVM-Fortran.cmake
new file mode 100644
index 0000000..1cd9b1f
--- /dev/null
+++ b/Modules/Platform/Linux-IntelLLVM-Fortran.cmake
@@ -0,0 +1,4 @@
+include(Platform/Linux-IntelLLVM)
+__linux_compiler_intel_llvm(Fortran)
+string(APPEND CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS " -nofor-main")
+set(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS "")
diff --git a/Modules/Platform/Linux-IntelLLVM.cmake b/Modules/Platform/Linux-IntelLLVM.cmake
new file mode 100644
index 0000000..1363b44
--- /dev/null
+++ b/Modules/Platform/Linux-IntelLLVM.cmake
@@ -0,0 +1,55 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__LINUX_COMPILER_INTEL_LLVM)
+ return()
+endif()
+set(__LINUX_COMPILER_INTEL_LLVM 1)
+
+if(NOT XIAR)
+ set(_intel_xiar_hints)
+ foreach(lang C CXX Fortran)
+ if(IS_ABSOLUTE "${CMAKE_${lang}_COMPILER}")
+ get_filename_component(_hint "${CMAKE_${lang}_COMPILER}" PATH)
+ list(APPEND _intel_xiar_hints ${_hint})
+ endif()
+ endforeach()
+ find_program(XIAR NAMES xiar HINTS ${_intel_xiar_hints})
+ mark_as_advanced(XIAR)
+endif()
+
+macro(__linux_compiler_intel_llvm lang)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
+ set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+ set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER YES)
+ set(CMAKE_${lang}_LINK_OPTIONS_PIE ${CMAKE_${lang}_COMPILE_OPTIONS_PIE} "-pie")
+ set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE "-no-pie")
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
+
+ # We pass this for historical reasons. Projects may have
+ # executables that use dlopen but do not set ENABLE_EXPORTS.
+ set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-rdynamic")
+
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
+ set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
+
+ if(XIAR)
+ # INTERPROCEDURAL_OPTIMIZATION
+ set(CMAKE_${lang}_COMPILE_OPTIONS_IPO -ipo)
+ set(CMAKE_${lang}_CREATE_STATIC_LIBRARY_IPO
+ "${XIAR} cr <TARGET> <LINK_FLAGS> <OBJECTS> "
+ "${XIAR} -s <TARGET> ")
+ set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
+ set(_CMAKE_${lang}_IPO_LEGACY_BEHAVIOR YES)
+ else()
+ set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER NO)
+ endif()
+
+ set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
+endmacro()
diff --git a/Modules/Platform/Linux-NAG-Fortran.cmake b/Modules/Platform/Linux-NAG-Fortran.cmake
new file mode 100644
index 0000000..353bae6
--- /dev/null
+++ b/Modules/Platform/Linux-NAG-Fortran.cmake
@@ -0,0 +1,10 @@
+set(CMAKE_Fortran_VERBOSE_FLAG "-Wl,-v") # Runs gcc under the hood.
+
+# Need one "-Wl," level to send flag through to gcc.
+# Use "-Xlinker" to get through gcc to real linker.
+set(CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS "-Wl,-shared")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG "-Wl,-Xlinker,-rpath,-Xlinker,")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP ":")
+set(CMAKE_SHARED_LIBRARY_RPATH_LINK_Fortran_FLAG "-Wl,-Xlinker,-rpath-link,-Xlinker,")
+set(CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG "-Wl,-Xlinker,-soname,-Xlinker,")
+set(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS "-Wl,-rdynamic")
diff --git a/Modules/Platform/Linux-NVHPC-C.cmake b/Modules/Platform/Linux-NVHPC-C.cmake
new file mode 100644
index 0000000..4aab327
--- /dev/null
+++ b/Modules/Platform/Linux-NVHPC-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Linux-NVHPC)
+__linux_compiler_nvhpc(C)
diff --git a/Modules/Platform/Linux-NVHPC-CXX.cmake b/Modules/Platform/Linux-NVHPC-CXX.cmake
new file mode 100644
index 0000000..57380eb
--- /dev/null
+++ b/Modules/Platform/Linux-NVHPC-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/Linux-NVHPC)
+__linux_compiler_nvhpc(CXX)
diff --git a/Modules/Platform/Linux-NVHPC-Fortran.cmake b/Modules/Platform/Linux-NVHPC-Fortran.cmake
new file mode 100644
index 0000000..c68430c
--- /dev/null
+++ b/Modules/Platform/Linux-NVHPC-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/Linux-NVHPC)
+__linux_compiler_nvhpc(Fortran)
diff --git a/Modules/Platform/Linux-NVHPC.cmake b/Modules/Platform/Linux-NVHPC.cmake
new file mode 100644
index 0000000..aad17f1
--- /dev/null
+++ b/Modules/Platform/Linux-NVHPC.cmake
@@ -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.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__LINUX_COMPILER_NVIDIA)
+ return()
+endif()
+set(__LINUX_COMPILER_NVIDIA 1)
+
+include(Platform/Linux-PGI)
+
+macro(__linux_compiler_nvhpc lang)
+ __linux_compiler_pgi(${lang})
+endmacro()
diff --git a/Modules/Platform/Linux-OpenWatcom-C.cmake b/Modules/Platform/Linux-OpenWatcom-C.cmake
new file mode 100644
index 0000000..383349a
--- /dev/null
+++ b/Modules/Platform/Linux-OpenWatcom-C.cmake
@@ -0,0 +1 @@
+include(Platform/Linux-OpenWatcom)
diff --git a/Modules/Platform/Linux-OpenWatcom-CXX.cmake b/Modules/Platform/Linux-OpenWatcom-CXX.cmake
new file mode 100644
index 0000000..383349a
--- /dev/null
+++ b/Modules/Platform/Linux-OpenWatcom-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Linux-OpenWatcom)
diff --git a/Modules/Platform/Linux-OpenWatcom.cmake b/Modules/Platform/Linux-OpenWatcom.cmake
new file mode 100644
index 0000000..5b4e995
--- /dev/null
+++ b/Modules/Platform/Linux-OpenWatcom.cmake
@@ -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.
+
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+set(CMAKE_BUILD_TYPE_INIT Debug)
+
+string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " system linux opt noextension")
+string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " system linux")
+string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " system linux")
+
+# single/multi-threaded /-bm
+# default is setup for single-threaded libraries
+string(APPEND CMAKE_C_FLAGS_INIT " -bt=linux")
+string(APPEND CMAKE_CXX_FLAGS_INIT " -bt=linux -xs")
+
+if(CMAKE_CROSSCOMPILING)
+ if(NOT CMAKE_C_STANDARD_INCLUDE_DIRECTORIES)
+ set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/lh)
+ endif()
+ if(NOT CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES)
+ set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/lh)
+ endif()
+endif()
diff --git a/Modules/Platform/Linux-PGI-C.cmake b/Modules/Platform/Linux-PGI-C.cmake
new file mode 100644
index 0000000..edf4f3f
--- /dev/null
+++ b/Modules/Platform/Linux-PGI-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Linux-PGI)
+__linux_compiler_pgi(C)
diff --git a/Modules/Platform/Linux-PGI-CXX.cmake b/Modules/Platform/Linux-PGI-CXX.cmake
new file mode 100644
index 0000000..d425f88
--- /dev/null
+++ b/Modules/Platform/Linux-PGI-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/Linux-PGI)
+__linux_compiler_pgi(CXX)
diff --git a/Modules/Platform/Linux-PGI-Fortran.cmake b/Modules/Platform/Linux-PGI-Fortran.cmake
new file mode 100644
index 0000000..e8731a3
--- /dev/null
+++ b/Modules/Platform/Linux-PGI-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/Linux-PGI)
+__linux_compiler_pgi(Fortran)
diff --git a/Modules/Platform/Linux-PGI.cmake b/Modules/Platform/Linux-PGI.cmake
new file mode 100644
index 0000000..0341654
--- /dev/null
+++ b/Modules/Platform/Linux-PGI.cmake
@@ -0,0 +1,21 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__LINUX_COMPILER_PGI)
+ return()
+endif()
+set(__LINUX_COMPILER_PGI 1)
+
+macro(__linux_compiler_pgi lang)
+ # Shared library compile and link flags.
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "")
+ set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+ set(CMAKE_${lang}_LINK_OPTIONS_PIE "")
+ set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE "")
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
+ set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS " ")
+endmacro()
diff --git a/Modules/Platform/Linux-PathScale-C.cmake b/Modules/Platform/Linux-PathScale-C.cmake
new file mode 100644
index 0000000..009f398
--- /dev/null
+++ b/Modules/Platform/Linux-PathScale-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Linux-PathScale)
+__linux_compiler_pathscale(C)
diff --git a/Modules/Platform/Linux-PathScale-CXX.cmake b/Modules/Platform/Linux-PathScale-CXX.cmake
new file mode 100644
index 0000000..b6a5771
--- /dev/null
+++ b/Modules/Platform/Linux-PathScale-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/Linux-PathScale)
+__linux_compiler_pathscale(CXX)
diff --git a/Modules/Platform/Linux-PathScale-Fortran.cmake b/Modules/Platform/Linux-PathScale-Fortran.cmake
new file mode 100644
index 0000000..5662d3d
--- /dev/null
+++ b/Modules/Platform/Linux-PathScale-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/Linux-PathScale)
+__linux_compiler_pathscale(Fortran)
diff --git a/Modules/Platform/Linux-PathScale.cmake b/Modules/Platform/Linux-PathScale.cmake
new file mode 100644
index 0000000..6070606
--- /dev/null
+++ b/Modules/Platform/Linux-PathScale.cmake
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__LINUX_COMPILER_PATHSCALE)
+ return()
+endif()
+set(__LINUX_COMPILER_PATHSCALE 1)
+
+macro(__linux_compiler_pathscale lang)
+ # Shared library compile and link flags.
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
+endmacro()
diff --git a/Modules/Platform/Linux-SunPro-CXX.cmake b/Modules/Platform/Linux-SunPro-CXX.cmake
new file mode 100644
index 0000000..a07f1ec
--- /dev/null
+++ b/Modules/Platform/Linux-SunPro-CXX.cmake
@@ -0,0 +1,9 @@
+# Sun C++ 5.9 does not support -Wl, but Sun C++ 5.11 does not work without it.
+# Query the compiler flags to detect whether to use -Wl.
+execute_process(COMMAND ${CMAKE_CXX_COMPILER} -flags OUTPUT_VARIABLE _cxx_flags ERROR_VARIABLE _cxx_error)
+if("${_cxx_flags}" MATCHES "\n-W[^\n]*component")
+ set(CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG "-Wl,-rpath-link,")
+else()
+ set(CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG "-rpath-link ")
+endif()
+set(CMAKE_EXE_EXPORTS_CXX_FLAG "--export-dynamic")
diff --git a/Modules/Platform/Linux-TinyCC-C.cmake b/Modules/Platform/Linux-TinyCC-C.cmake
new file mode 100644
index 0000000..9409d8b
--- /dev/null
+++ b/Modules/Platform/Linux-TinyCC-C.cmake
@@ -0,0 +1,5 @@
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP "")
+set(CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG "")
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-soname ")
+set(CMAKE_EXE_EXPORTS_C_FLAG "-rdynamic ")
diff --git a/Modules/Platform/Linux-VisualAge-C.cmake b/Modules/Platform/Linux-VisualAge-C.cmake
new file mode 100644
index 0000000..0622b63
--- /dev/null
+++ b/Modules/Platform/Linux-VisualAge-C.cmake
@@ -0,0 +1 @@
+include(Platform/Linux-XL-C)
diff --git a/Modules/Platform/Linux-VisualAge-CXX.cmake b/Modules/Platform/Linux-VisualAge-CXX.cmake
new file mode 100644
index 0000000..b878ba0
--- /dev/null
+++ b/Modules/Platform/Linux-VisualAge-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Linux-XL-CXX)
diff --git a/Modules/Platform/Linux-VisualAge-Fortran.cmake b/Modules/Platform/Linux-VisualAge-Fortran.cmake
new file mode 100644
index 0000000..1939a8a
--- /dev/null
+++ b/Modules/Platform/Linux-VisualAge-Fortran.cmake
@@ -0,0 +1 @@
+include(Platform/Linux-XL-Fortran)
diff --git a/Modules/Platform/Linux-XL-C.cmake b/Modules/Platform/Linux-XL-C.cmake
new file mode 100644
index 0000000..ef0c52b
--- /dev/null
+++ b/Modules/Platform/Linux-XL-C.cmake
@@ -0,0 +1 @@
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,-export-dynamic")
diff --git a/Modules/Platform/Linux-XL-CXX.cmake b/Modules/Platform/Linux-XL-CXX.cmake
new file mode 100644
index 0000000..aa57d6e
--- /dev/null
+++ b/Modules/Platform/Linux-XL-CXX.cmake
@@ -0,0 +1 @@
+set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-Wl,-export-dynamic")
diff --git a/Modules/Platform/Linux-XL-Fortran.cmake b/Modules/Platform/Linux-XL-Fortran.cmake
new file mode 100644
index 0000000..d9b4c2d
--- /dev/null
+++ b/Modules/Platform/Linux-XL-Fortran.cmake
@@ -0,0 +1 @@
+set(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS "-Wl,-export-dynamic")
diff --git a/Modules/Platform/Linux-como.cmake b/Modules/Platform/Linux-como.cmake
new file mode 100644
index 0000000..f6db34c
--- /dev/null
+++ b/Modules/Platform/Linux-como.cmake
@@ -0,0 +1,17 @@
+# create a shared C++ library
+set(CMAKE_CXX_CREATE_SHARED_LIBRARY
+ "<CMAKE_CXX_COMPILER> --prelink_objects <OBJECTS>"
+ "<CMAKE_CXX_COMPILER> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <LINK_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
+
+# create a C++ static library
+set(CMAKE_CXX_CREATE_STATIC_LIBRARY
+ "<CMAKE_CXX_COMPILER> --prelink_objects <OBJECTS>"
+ "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS> "
+ "<CMAKE_RANLIB> <TARGET> ")
+
+set(CMAKE_CXX_LINK_EXECUTABLE
+ "<CMAKE_CXX_COMPILER> --prelink_objects <OBJECTS>"
+ "<CMAKE_CXX_COMPILER> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "")
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "")
diff --git a/Modules/Platform/Linux.cmake b/Modules/Platform/Linux.cmake
new file mode 100644
index 0000000..b5d5464
--- /dev/null
+++ b/Modules/Platform/Linux.cmake
@@ -0,0 +1,59 @@
+set(CMAKE_DL_LIBS "dl")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
+set(CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN "\$ORIGIN")
+set(CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG "-Wl,-rpath-link,")
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
+set(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
+
+# Shared libraries with no builtin soname may not be linked safely by
+# specifying the file path.
+set(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
+
+# Initialize C link type selection flags. These flags are used when
+# building a shared library, shared module, or executable that links
+# to other libraries to select whether to use the static or shared
+# versions of the libraries.
+foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+ set(CMAKE_${type}_LINK_STATIC_C_FLAGS "-Wl,-Bstatic")
+ set(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-Wl,-Bdynamic")
+endforeach()
+
+# Debian policy requires that shared libraries be installed without
+# executable permission. Fedora policy requires that shared libraries
+# be installed with the executable permission. Since the native tools
+# create shared libraries with execute permission in the first place a
+# reasonable policy seems to be to install with execute permission by
+# default. In order to support debian packages we provide an option
+# here. The option default is based on the current distribution, but
+# packagers can set it explicitly on the command line.
+if(DEFINED CMAKE_INSTALL_SO_NO_EXE)
+ # Store the decision variable in the cache. This preserves any
+ # setting the user provides on the command line.
+ set(CMAKE_INSTALL_SO_NO_EXE "${CMAKE_INSTALL_SO_NO_EXE}" CACHE INTERNAL
+ "Install .so files without execute permission.")
+else()
+ # Store the decision variable as an internal cache entry to avoid
+ # checking the platform every time. This option is advanced enough
+ # that only package maintainers should need to adjust it. They are
+ # capable of providing a setting on the command line.
+ if(EXISTS "/etc/debian_version")
+ set(CMAKE_INSTALL_SO_NO_EXE 1 CACHE INTERNAL
+ "Install .so files without execute permission.")
+ else()
+ set(CMAKE_INSTALL_SO_NO_EXE 0 CACHE INTERNAL
+ "Install .so files without execute permission.")
+ endif()
+endif()
+
+# Match multiarch library directory names.
+set(CMAKE_LIBRARY_ARCHITECTURE_REGEX "[a-z0-9_]+(-[a-z0-9_]+)?-linux-gnu[a-z0-9_]*")
+
+include(Platform/UnixPaths)
+
+# Debian has lib32 and lib64 paths only for compatibility so they should not be
+# searched.
+if(NOT CMAKE_CROSSCOMPILING AND EXISTS "/etc/debian_version")
+ set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS FALSE)
+ set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS FALSE)
+endif()
diff --git a/Modules/Platform/MP-RAS.cmake b/Modules/Platform/MP-RAS.cmake
new file mode 100644
index 0000000..fe8d81a
--- /dev/null
+++ b/Modules/Platform/MP-RAS.cmake
@@ -0,0 +1,14 @@
+if(CMAKE_SYSTEM MATCHES "MP-RAS-02*.")
+ set(CMAKE_C_COMPILE_OPTIONS_PIC -K PIC)
+ set(CMAKE_C_COMPILE_OPTIONS_PIE -K PIE)
+ set(CMAKE_SHARED_LIBRARY_C_FLAGS "-K PIC")
+else()
+ set(CMAKE_C_COMPILE_OPTIONS_PIC -K PIC)
+ set(CMAKE_C_COMPILE_OPTIONS_PIE -K PIE)
+ set(CMAKE_SHARED_LIBRARY_C_FLAGS "-K PIC")
+ set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,-Bexport")
+endif()
+
+include(Platform/UnixPaths)
+
+
diff --git a/Modules/Platform/Midipix.cmake b/Modules/Platform/Midipix.cmake
new file mode 100644
index 0000000..54a156b
--- /dev/null
+++ b/Modules/Platform/Midipix.cmake
@@ -0,0 +1 @@
+include(Platform/UnixPaths)
diff --git a/Modules/Platform/MirBSD.cmake b/Modules/Platform/MirBSD.cmake
new file mode 100644
index 0000000..7637f9b
--- /dev/null
+++ b/Modules/Platform/MirBSD.cmake
@@ -0,0 +1 @@
+include(Platform/OpenBSD)
diff --git a/Modules/Platform/NetBSD.cmake b/Modules/Platform/NetBSD.cmake
new file mode 100644
index 0000000..d99cb4a
--- /dev/null
+++ b/Modules/Platform/NetBSD.cmake
@@ -0,0 +1,15 @@
+set(CMAKE_DL_LIBS "")
+set(CMAKE_C_COMPILE_OPTIONS_PIC "-fPIC")
+set(CMAKE_C_COMPILE_OPTIONS_PIE "-fPIE")
+# PIE link options are managed in Compiler/<compiler>.cmake file
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-fPIC") # -pic
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared") # -shared
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # +s, flag for exe link to use shared lib
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,") # -rpath
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":") # : or empty
+set(CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN "\$ORIGIN")
+set(CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG "-Wl,-rpath-link,")
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
+set(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
+
+include(Platform/UnixPaths)
diff --git a/Modules/Platform/OS2-OpenWatcom-C.cmake b/Modules/Platform/OS2-OpenWatcom-C.cmake
new file mode 100644
index 0000000..21a4d9e
--- /dev/null
+++ b/Modules/Platform/OS2-OpenWatcom-C.cmake
@@ -0,0 +1 @@
+include(Platform/OS2-OpenWatcom)
diff --git a/Modules/Platform/OS2-OpenWatcom-CXX.cmake b/Modules/Platform/OS2-OpenWatcom-CXX.cmake
new file mode 100644
index 0000000..21a4d9e
--- /dev/null
+++ b/Modules/Platform/OS2-OpenWatcom-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/OS2-OpenWatcom)
diff --git a/Modules/Platform/OS2-OpenWatcom.cmake b/Modules/Platform/OS2-OpenWatcom.cmake
new file mode 100644
index 0000000..998fb9f
--- /dev/null
+++ b/Modules/Platform/OS2-OpenWatcom.cmake
@@ -0,0 +1,35 @@
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+set(CMAKE_BUILD_TYPE_INIT Debug)
+
+if(DEFINED CMAKE_SYSTEM_PROCESSOR AND CMAKE_SYSTEM_PROCESSOR STREQUAL "I86")
+ string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " system os2")
+ string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " system os2_dll")
+ string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " system os2_dll")
+else()
+ string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " system os2v2")
+ string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " system os2v2_dll")
+ string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " system os2v2_dll")
+endif()
+
+set(CMAKE_C_COMPILE_OPTIONS_DLL "-bd") # Note: This variable is a ';' separated list
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-bd") # ... while this is a space separated string.
+
+string(APPEND CMAKE_C_FLAGS_INIT " -bt=os2")
+string(APPEND CMAKE_CXX_FLAGS_INIT " -bt=os2 -xs")
+
+if(NOT CMAKE_C_STANDARD_INCLUDE_DIRECTORIES)
+ if(DEFINED CMAKE_SYSTEM_PROCESSOR AND CMAKE_SYSTEM_PROCESSOR STREQUAL "I86")
+ set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/os21x)
+ else()
+ set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/os2)
+ endif()
+endif()
+if(NOT CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES)
+ if(DEFINED CMAKE_SYSTEM_PROCESSOR AND CMAKE_SYSTEM_PROCESSOR STREQUAL "I86")
+ set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/os21x)
+ else()
+ set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/os2)
+ endif()
+endif()
diff --git a/Modules/Platform/OS2.cmake b/Modules/Platform/OS2.cmake
new file mode 100644
index 0000000..a9df66d
--- /dev/null
+++ b/Modules/Platform/OS2.cmake
@@ -0,0 +1,14 @@
+set(OS2 1)
+
+set(CMAKE_STATIC_LIBRARY_PREFIX "")
+set(CMAKE_STATIC_LIBRARY_SUFFIX ".lib")
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".dll")
+set(CMAKE_IMPORT_LIBRARY_PREFIX "")
+set(CMAKE_IMPORT_LIBRARY_SUFFIX ".lib")
+set(CMAKE_EXECUTABLE_SUFFIX ".exe")
+set(CMAKE_LINK_LIBRARY_SUFFIX ".lib")
+set(CMAKE_DL_LIBS "")
+
+set(CMAKE_FIND_LIBRARY_PREFIXES "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
diff --git a/Modules/Platform/OSF1.cmake b/Modules/Platform/OSF1.cmake
new file mode 100644
index 0000000..f2ad612
--- /dev/null
+++ b/Modules/Platform/OSF1.cmake
@@ -0,0 +1,47 @@
+set(CMAKE_DL_LIBS "")
+
+if(CMAKE_SYSTEM MATCHES "OSF1-1.[012]")
+endif()
+if(CMAKE_SYSTEM MATCHES "OSF1-1")
+ # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2
+ set(CMAKE_C_COMPILE_OPTIONS_PIC "-fpic")
+ set(CMAKE_C_COMPILE_OPTIONS_PIE "-fpie")
+ set(CMAKE_SHARED_LIBRARY_C_FLAGS "-fpic") # -pic
+ set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "-fpic") # -pic
+endif()
+
+
+
+if(CMAKE_SYSTEM MATCHES "OSF1-V")
+ set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared -Wl,-expect_unresolved,\\*") # -shared
+ if(CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG "-Wl,-rpath,")
+ else()
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG "-rpath ")
+ endif()
+ if(CMAKE_COMPILER_IS_GNUCC)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
+ else()
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-rpath ")
+ endif()
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
+endif()
+
+set(CMAKE_MAKE_INCLUDE_FROM_ROOT 1) # include $(CMAKE_BINARY_DIR)/...
+
+if(CMAKE_COMPILER_IS_GNUCXX)
+ # include the gcc flags
+else ()
+ # use default OSF compiler flags
+ set (CMAKE_C_FLAGS_INIT "")
+ set (CMAKE_C_FLAGS_DEBUG_INIT "-g")
+ set (CMAKE_C_FLAGS_MINSIZEREL_INIT "-O2 -DNDEBUG")
+ set (CMAKE_C_FLAGS_RELEASE_INIT "-O2 -DNDEBUG")
+ set (CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2")
+ set (CMAKE_CXX_FLAGS_INIT "")
+ set (CMAKE_CXX_FLAGS_DEBUG_INIT "-g")
+ set (CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-O2 -DNDEBUG")
+ set (CMAKE_CXX_FLAGS_RELEASE_INIT "-O2 -DNDEBUG")
+ set (CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O2")
+endif()
+include(Platform/UnixPaths)
diff --git a/Modules/Platform/OpenBSD.cmake b/Modules/Platform/OpenBSD.cmake
new file mode 100644
index 0000000..97e2a6a
--- /dev/null
+++ b/Modules/Platform/OpenBSD.cmake
@@ -0,0 +1,43 @@
+include(Platform/NetBSD)
+
+# On OpenBSD, the compile time linker does not share it's configuration with
+# the runtime linker. This will extract the library search paths from the
+# system's ld.so.hints file which will allow CMake to set the appropriate
+# -rpath-link flags
+if(NOT CMAKE_PLATFORM_RUNTIME_PATH)
+ execute_process(COMMAND /sbin/ldconfig -r
+ OUTPUT_VARIABLE LDCONFIG_HINTS
+ ERROR_QUIET)
+ string(REGEX REPLACE ".*search\\ directories:\\ ([^\n]*).*" "\\1"
+ LDCONFIG_HINTS "${LDCONFIG_HINTS}")
+ string(REPLACE ":" ";"
+ CMAKE_PLATFORM_RUNTIME_PATH
+ "${LDCONFIG_HINTS}")
+endif()
+
+# OpenBSD requires -z origin to enable $ORIGIN expansion in RPATH.
+# This is not required for NetBSD.
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-z,origin,-rpath,")
+
+set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_OPENBSD_VERSIONING 1)
+
+# OpenBSD has no multilib
+set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS FALSE)
+set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS FALSE)
+
+# OpenBSD policy requires that shared libraries be installed without
+# executable permission.
+set(CMAKE_INSTALL_SO_NO_EXE 1)
+
+if($ENV{LOCALBASE})
+ set(OPENBSD_LOCALBASE $ENV{LOCALBASE})
+else()
+ set(OPENBSD_LOCALBASE /usr/local)
+endif()
+if($ENV{X11BASE})
+ set(OPENBSD_X11BASE $ENV{X11BASE})
+else()
+ set(OPENBSD_X11BASE /usr/X11R6)
+endif()
+
+list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${OPENBSD_LOCALBASE})
diff --git a/Modules/Platform/OpenVMS.cmake b/Modules/Platform/OpenVMS.cmake
new file mode 100644
index 0000000..b10da23
--- /dev/null
+++ b/Modules/Platform/OpenVMS.cmake
@@ -0,0 +1,8 @@
+include(Platform/UnixPaths)
+
+set(CMAKE_C_CREATE_STATIC_LIBRARY
+ "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS>"
+ "<CMAKE_RANLIB> <TARGET>"
+ )
+set(CMAKE_CXX_CREATE_STATIC_LIBRARY ${CMAKE_C_CREATE_STATIC_LIBRARY})
+set(CMAKE_EXECUTABLE_SUFFIX ".exe") # .exe
diff --git a/Modules/Platform/QNX.cmake b/Modules/Platform/QNX.cmake
new file mode 100644
index 0000000..ebc4609
--- /dev/null
+++ b/Modules/Platform/QNX.cmake
@@ -0,0 +1,19 @@
+set(QNXNTO 1)
+
+include(Platform/GNU)
+unset(CMAKE_LIBRARY_ARCHITECTURE_REGEX)
+
+set(CMAKE_DL_LIBS "")
+
+# Shared libraries with no builtin soname may not be linked safely by
+# specifying the file path.
+set(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
+
+# Initialize C link type selection flags. These flags are used when
+# building a shared library, shared module, or executable that links
+# to other libraries to select whether to use the static or shared
+# versions of the libraries.
+foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+ set(CMAKE_${type}_LINK_STATIC_C_FLAGS "-Wl,-Bstatic")
+ set(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-Wl,-Bdynamic")
+endforeach()
diff --git a/Modules/Platform/RISCos.cmake b/Modules/Platform/RISCos.cmake
new file mode 100644
index 0000000..570cd7b
--- /dev/null
+++ b/Modules/Platform/RISCos.cmake
@@ -0,0 +1,6 @@
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-G 0")
+set(CMAKE_SHARED_LIBRARY_SUFFIX "..o")
+set(CMAKE_DL_LIBS "")
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,-D,08000000")
+
+include(Platform/UnixPaths)
diff --git a/Modules/Platform/SCO_SV.cmake b/Modules/Platform/SCO_SV.cmake
new file mode 100644
index 0000000..1cb4b38
--- /dev/null
+++ b/Modules/Platform/SCO_SV.cmake
@@ -0,0 +1,3 @@
+set(CMAKE_DL_LIBS "")
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-h,")
+include(Platform/UnixPaths)
diff --git a/Modules/Platform/SINIX.cmake b/Modules/Platform/SINIX.cmake
new file mode 100644
index 0000000..e3b0a05
--- /dev/null
+++ b/Modules/Platform/SINIX.cmake
@@ -0,0 +1,7 @@
+set(CMAKE_C_COMPILE_OPTIONS_PIC -K PIC)
+set(CMAKE_C_COMPILE_OPTIONS_PIE "")
+set(_CMAKE_C_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+set(CMAKE_C_LINK_OPTIONS_PIE "")
+set(CMAKE_C_LINK_OPTIONS_NO_PIE "")
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-K PIC")
+include(Platform/UnixPaths)
diff --git a/Modules/Platform/SunOS-Clang-C.cmake b/Modules/Platform/SunOS-Clang-C.cmake
new file mode 100644
index 0000000..f06eb8f
--- /dev/null
+++ b/Modules/Platform/SunOS-Clang-C.cmake
@@ -0,0 +1 @@
+include(Platform/SunOS-GNU-C)
diff --git a/Modules/Platform/SunOS-Clang-CXX.cmake b/Modules/Platform/SunOS-Clang-CXX.cmake
new file mode 100644
index 0000000..869182c
--- /dev/null
+++ b/Modules/Platform/SunOS-Clang-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/SunOS-GNU-CXX)
diff --git a/Modules/Platform/SunOS-GNU-C.cmake b/Modules/Platform/SunOS-GNU-C.cmake
new file mode 100644
index 0000000..6a96c00
--- /dev/null
+++ b/Modules/Platform/SunOS-GNU-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/SunOS-GNU)
+__sunos_compiler_gnu(C)
diff --git a/Modules/Platform/SunOS-GNU-CXX.cmake b/Modules/Platform/SunOS-GNU-CXX.cmake
new file mode 100644
index 0000000..6b9f6fa
--- /dev/null
+++ b/Modules/Platform/SunOS-GNU-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/SunOS-GNU)
+__sunos_compiler_gnu(CXX)
diff --git a/Modules/Platform/SunOS-GNU-Fortran.cmake b/Modules/Platform/SunOS-GNU-Fortran.cmake
new file mode 100644
index 0000000..c6b1888
--- /dev/null
+++ b/Modules/Platform/SunOS-GNU-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/SunOS-GNU)
+__sunos_compiler_gnu(Fortran)
diff --git a/Modules/Platform/SunOS-GNU.cmake b/Modules/Platform/SunOS-GNU.cmake
new file mode 100644
index 0000000..47334d6
--- /dev/null
+++ b/Modules/Platform/SunOS-GNU.cmake
@@ -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.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__SUNOS_COMPILER_GNU)
+ return()
+endif()
+set(__SUNOS_COMPILER_GNU 1)
+
+macro(__sunos_compiler_gnu lang)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG "-Wl,-R")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP ":")
+ set(CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN "\$ORIGIN")
+ set(CMAKE_SHARED_LIBRARY_SONAME_${lang}_FLAG "-Wl,-h")
+
+ # Initialize C link type selection flags. These flags are used when
+ # building a shared library, shared module, or executable that links
+ # to other libraries to select whether to use the static or shared
+ # versions of the libraries.
+ foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+ set(CMAKE_${type}_LINK_STATIC_${lang}_FLAGS "-Wl,-Bstatic")
+ set(CMAKE_${type}_LINK_DYNAMIC_${lang}_FLAGS "-Wl,-Bdynamic")
+ endforeach()
+endmacro()
diff --git a/Modules/Platform/SunOS-PathScale-C.cmake b/Modules/Platform/SunOS-PathScale-C.cmake
new file mode 100644
index 0000000..2f78da1
--- /dev/null
+++ b/Modules/Platform/SunOS-PathScale-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/SunOS-PathScale)
+__sunos_compiler_pathscale(C)
diff --git a/Modules/Platform/SunOS-PathScale-CXX.cmake b/Modules/Platform/SunOS-PathScale-CXX.cmake
new file mode 100644
index 0000000..bb79d86
--- /dev/null
+++ b/Modules/Platform/SunOS-PathScale-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/SunOS-PathScale)
+__sunos_compiler_pathscale(CXX)
diff --git a/Modules/Platform/SunOS-PathScale-Fortran.cmake b/Modules/Platform/SunOS-PathScale-Fortran.cmake
new file mode 100644
index 0000000..3c202f7
--- /dev/null
+++ b/Modules/Platform/SunOS-PathScale-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/SunOS-PathScale)
+__sunos_compiler_pathscale(Fortran)
diff --git a/Modules/Platform/SunOS-PathScale.cmake b/Modules/Platform/SunOS-PathScale.cmake
new file mode 100644
index 0000000..25ead80
--- /dev/null
+++ b/Modules/Platform/SunOS-PathScale.cmake
@@ -0,0 +1,21 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__SUNOS_COMPILER_PATHSCALE)
+ return()
+endif()
+set(__SUNOS_COMPILER_PATHSCALE 1)
+
+macro(__sunos_compiler_pathscale lang)
+ # Shared library compile and link flags.
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
+
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG "-Wl,-R")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP ":")
+ set(CMAKE_SHARED_LIBRARY_SONAME_${lang}_FLAG "-Wl,-h")
+endmacro()
diff --git a/Modules/Platform/SunOS.cmake b/Modules/Platform/SunOS.cmake
new file mode 100644
index 0000000..78eccf7
--- /dev/null
+++ b/Modules/Platform/SunOS.cmake
@@ -0,0 +1,23 @@
+if(CMAKE_SYSTEM MATCHES "SunOS-4")
+ set(CMAKE_C_COMPILE_OPTIONS_PIC "-PIC")
+ set(CMAKE_C_COMPILE_OPTIONS_PIE "-PIE")
+ set(CMAKE_SHARED_LIBRARY_C_FLAGS "-PIC")
+ set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared -Wl,-r")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-R")
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
+endif()
+
+include(Platform/UnixPaths)
+
+list(APPEND CMAKE_SYSTEM_PREFIX_PATH
+ /opt/csw
+ /opt/openwin
+ )
+
+# The Sun linker needs to find transitive shared library dependencies
+# in the -L path.
+set(CMAKE_LINK_DEPENDENT_LIBRARY_DIRS 1)
+
+# Shared libraries with no builtin soname may not be linked safely by
+# specifying the file path.
+set(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
diff --git a/Modules/Platform/Tru64.cmake b/Modules/Platform/Tru64.cmake
new file mode 100644
index 0000000..47852f8
--- /dev/null
+++ b/Modules/Platform/Tru64.cmake
@@ -0,0 +1,2 @@
+include(Platform/UnixPaths)
+
diff --git a/Modules/Platform/ULTRIX.cmake b/Modules/Platform/ULTRIX.cmake
new file mode 100644
index 0000000..9db4c7c
--- /dev/null
+++ b/Modules/Platform/ULTRIX.cmake
@@ -0,0 +1,5 @@
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-G 0")
+set(CMAKE_SHARED_LIBRARY_SUFFIX "..o")
+set(CMAKE_DL_LIBS "")
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,-D,08000000")
+include(Platform/UnixPaths)
diff --git a/Modules/Platform/UNIX_SV.cmake b/Modules/Platform/UNIX_SV.cmake
new file mode 100644
index 0000000..bd1ffce
--- /dev/null
+++ b/Modules/Platform/UNIX_SV.cmake
@@ -0,0 +1,8 @@
+set(CMAKE_C_COMPILE_OPTIONS_PIC -K PIC)
+set(CMAKE_C_COMPILE_OPTIONS_PIE "")
+set(_CMAKE_C_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+set(CMAKE_C_LINK_OPTIONS_PIE "")
+set(CMAKE_C_LINK_OPTIONS_NO_PIE "")
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-K PIC")
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,-Bexport")
+include(Platform/UnixPaths)
diff --git a/Modules/Platform/UnixPaths.cmake b/Modules/Platform/UnixPaths.cmake
new file mode 100644
index 0000000..b9381c3
--- /dev/null
+++ b/Modules/Platform/UnixPaths.cmake
@@ -0,0 +1,107 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# Block multiple inclusion because "CMakeCInformation.cmake" includes
+# "Platform/${CMAKE_SYSTEM_NAME}" even though the generic module
+# "CMakeSystemSpecificInformation.cmake" already included it.
+# The extra inclusion is a work-around documented next to the include()
+# call, so this can be removed when the work-around is removed.
+if(__UNIX_PATHS_INCLUDED)
+ return()
+endif()
+set(__UNIX_PATHS_INCLUDED 1)
+
+set(UNIX 1)
+
+# also add the install directory of the running cmake to the search directories
+# CMAKE_ROOT is CMAKE_INSTALL_PREFIX/share/cmake, so we need to go two levels up
+get_filename_component(_CMAKE_INSTALL_DIR "${CMAKE_ROOT}" PATH)
+get_filename_component(_CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" PATH)
+
+# List common installation prefixes. These will be used for all
+# search types.
+#
+# Reminder when adding new locations computed from environment variables
+# please make sure to keep Help/variable/CMAKE_SYSTEM_PREFIX_PATH.rst
+# synchronized
+list(APPEND CMAKE_SYSTEM_PREFIX_PATH
+ # Standard
+ /usr/local /usr /
+
+ # CMake install location
+ "${_CMAKE_INSTALL_DIR}"
+ )
+if (NOT CMAKE_FIND_NO_INSTALL_PREFIX)
+ list(APPEND CMAKE_SYSTEM_PREFIX_PATH
+ # Project install destination.
+ "${CMAKE_INSTALL_PREFIX}"
+ )
+ if(CMAKE_STAGING_PREFIX)
+ list(APPEND CMAKE_SYSTEM_PREFIX_PATH
+ # User-supplied staging prefix.
+ "${CMAKE_STAGING_PREFIX}"
+ )
+ endif()
+endif()
+
+# Non "standard" but common install prefixes
+list(APPEND CMAKE_SYSTEM_PREFIX_PATH
+ /usr/X11R6
+ /usr/pkg
+ /opt
+ )
+
+# List common include file locations not under the common prefixes.
+list(APPEND CMAKE_SYSTEM_INCLUDE_PATH
+ # X11
+ /usr/include/X11
+ )
+
+list(APPEND CMAKE_SYSTEM_LIBRARY_PATH
+ # X11
+ /usr/lib/X11
+ )
+
+list(APPEND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES
+ /lib /lib32 /lib64 /usr/lib /usr/lib32 /usr/lib64
+ )
+
+if(CMAKE_SYSROOT_COMPILE)
+ set(_cmake_sysroot_compile "${CMAKE_SYSROOT_COMPILE}")
+else()
+ set(_cmake_sysroot_compile "${CMAKE_SYSROOT}")
+endif()
+
+# Default per-language values. These may be later replaced after
+# parsing the implicit directory information from compiler output.
+set(_CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES_INIT
+ ${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES}
+ "${_cmake_sysroot_compile}/usr/include"
+ )
+set(_CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES_INIT
+ ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}
+ "${_cmake_sysroot_compile}/usr/include"
+ )
+set(_CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES_INIT
+ ${CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES}
+ "${_cmake_sysroot_compile}/usr/include"
+ )
+
+unset(_cmake_sysroot_compile)
+
+# Reminder when adding new locations computed from environment variables
+# please make sure to keep Help/variable/CMAKE_SYSTEM_PREFIX_PATH.rst
+# synchronized
+if(CMAKE_COMPILER_SYSROOT)
+ list(PREPEND CMAKE_SYSTEM_PREFIX_PATH "${CMAKE_COMPILER_SYSROOT}")
+
+ if(DEFINED ENV{CONDA_PREFIX} AND EXISTS "$ENV{CONDA_PREFIX}")
+ list(APPEND CMAKE_SYSTEM_PREFIX_PATH "$ENV{CONDA_PREFIX}")
+ endif()
+endif()
+
+# Enable use of lib32 and lib64 search path variants by default.
+set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS TRUE)
+set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE)
+set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIBX32_PATHS TRUE)
diff --git a/Modules/Platform/UnixWare.cmake b/Modules/Platform/UnixWare.cmake
new file mode 100644
index 0000000..94888d9
--- /dev/null
+++ b/Modules/Platform/UnixWare.cmake
@@ -0,0 +1,8 @@
+set(CMAKE_C_COMPILE_OPTIONS_PIC -K PIC)
+set(CMAKE_C_COMPILE_OPTIONS_PIE "")
+set(_CMAKE_C_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+set(CMAKE_C_LINK_OPTIONS_PIE "")
+set(CMAKE_C_LINK_OPTIONS_NO_PIE "")
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-K PIC")
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-Wl,-Bexport")
+include(Platform/UnixPaths)
diff --git a/Modules/Platform/Windows-Apple-Swift.cmake b/Modules/Platform/Windows-Apple-Swift.cmake
new file mode 100644
index 0000000..1177755
--- /dev/null
+++ b/Modules/Platform/Windows-Apple-Swift.cmake
@@ -0,0 +1 @@
+set(CMAKE_Swift_IMPLIB_LINKER_FLAGS "-Xlinker -implib:<TARGET_IMPLIB>")
diff --git a/Modules/Platform/Windows-Borland-C.cmake b/Modules/Platform/Windows-Borland-C.cmake
new file mode 100644
index 0000000..e2f76aa
--- /dev/null
+++ b/Modules/Platform/Windows-Borland-C.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-Embarcadero-C)
diff --git a/Modules/Platform/Windows-Borland-CXX.cmake b/Modules/Platform/Windows-Borland-CXX.cmake
new file mode 100644
index 0000000..809490f
--- /dev/null
+++ b/Modules/Platform/Windows-Borland-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-Embarcadero-CXX)
diff --git a/Modules/Platform/Windows-Clang-ASM.cmake b/Modules/Platform/Windows-Clang-ASM.cmake
new file mode 100644
index 0000000..345d77d
--- /dev/null
+++ b/Modules/Platform/Windows-Clang-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows-Clang)
+__windows_compiler_clang(ASM)
diff --git a/Modules/Platform/Windows-Clang-C.cmake b/Modules/Platform/Windows-Clang-C.cmake
new file mode 100644
index 0000000..322e3fb
--- /dev/null
+++ b/Modules/Platform/Windows-Clang-C.cmake
@@ -0,0 +1,18 @@
+include(Platform/Windows-Clang)
+__windows_compiler_clang(C)
+
+if("x${MAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+ endif()
+elseif("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPFILE_FORMAT gcc)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+ endif()
+endif()
diff --git a/Modules/Platform/Windows-Clang-CXX.cmake b/Modules/Platform/Windows-Clang-CXX.cmake
new file mode 100644
index 0000000..b4aaf1e
--- /dev/null
+++ b/Modules/Platform/Windows-Clang-CXX.cmake
@@ -0,0 +1,19 @@
+include(Platform/Windows-Clang)
+set(_COMPILE_CXX_MSVC " -TP")
+__windows_compiler_clang(CXX)
+
+if("x${MAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+ endif()
+elseif("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+ endif()
+endif()
diff --git a/Modules/Platform/Windows-Clang.cmake b/Modules/Platform/Windows-Clang.cmake
new file mode 100644
index 0000000..7365ff5
--- /dev/null
+++ b/Modules/Platform/Windows-Clang.cmake
@@ -0,0 +1,211 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__WINDOWS_CLANG)
+ return()
+endif()
+set(__WINDOWS_CLANG 1)
+
+set(__pch_header_C "c-header")
+set(__pch_header_CXX "c++-header")
+set(__pch_header_OBJC "objective-c-header")
+set(__pch_header_OBJCXX "objective-c++-header")
+
+macro(__windows_compiler_clang_gnu lang)
+ set(CMAKE_LIBRARY_PATH_FLAG "-L")
+ set(CMAKE_LINK_LIBRARY_FLAG "-l")
+
+ set(CMAKE_IMPORT_LIBRARY_PREFIX "")
+ set(CMAKE_SHARED_LIBRARY_PREFIX "")
+ set(CMAKE_SHARED_MODULE_PREFIX "")
+ set(CMAKE_STATIC_LIBRARY_PREFIX "")
+ set(CMAKE_EXECUTABLE_SUFFIX ".exe")
+ set(CMAKE_IMPORT_LIBRARY_SUFFIX ".lib")
+ set(CMAKE_SHARED_LIBRARY_SUFFIX ".dll")
+ set(CMAKE_SHARED_MODULE_SUFFIX ".dll")
+ set(CMAKE_STATIC_LIBRARY_SUFFIX ".lib")
+ if(NOT "${lang}" STREQUAL "ASM")
+ set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+ endif()
+
+ set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.a" ".a" ".lib")
+ set(CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS 1)
+ set (CMAKE_LINK_DEF_FILE_FLAG "-Xlinker /DEF:")
+
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ")
+ set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP)
+
+ if("${CMAKE_${lang}_SIMULATE_VERSION}" MATCHES "^([0-9]+)\\.([0-9]+)")
+ math(EXPR MSVC_VERSION "${CMAKE_MATCH_1}*100 + ${CMAKE_MATCH_2}")
+ endif()
+
+ # No -fPIC on Windows
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "")
+ set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+ set(CMAKE_${lang}_LINK_OPTIONS_PIE "")
+ set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE "")
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "")
+
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_OBJECTS 1)
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_INCLUDES 1)
+
+ set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto")
+ set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
+ set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
+ set(CMAKE_${lang}_ARCHIVE_CREATE_IPO "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_APPEND_IPO "<CMAKE_AR> r <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_FINISH_IPO "<CMAKE_RANLIB> <TARGET>")
+
+ # Create archiving rules to support large object file lists for static libraries.
+ set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
+ set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
+ "<CMAKE_${lang}_COMPILER> -fuse-ld=lld-link -nostartfiles -nostdlib <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <OBJECTS> <LINK_LIBRARIES>")
+ set(CMAKE_${lang}_CREATE_SHARED_MODULE ${CMAKE_${lang}_CREATE_SHARED_LIBRARY})
+ set(CMAKE_${lang}_LINK_EXECUTABLE
+ "<CMAKE_${lang}_COMPILER> -fuse-ld=lld-link -nostartfiles -nostdlib <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
+
+ set(CMAKE_${lang}_CREATE_WIN32_EXE "-Xlinker /subsystem:windows")
+ set(CMAKE_${lang}_CREATE_CONSOLE_EXE "-Xlinker /subsystem:console")
+
+ if(NOT "${lang}" STREQUAL "ASM")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -Xclang -flto-visibility-public-std -D_MT -Xclang --dependent-lib=libcmt)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -D_DLL -D_MT -Xclang --dependent-lib=msvcrt)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -D_DEBUG -Xclang -flto-visibility-public-std -D_MT -Xclang --dependent-lib=libcmtd)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd)
+
+ if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+ set(__ADDED_FLAGS "")
+ set(__ADDED_FLAGS_DEBUG "")
+ else()
+ set(__ADDED_FLAGS_DEBUG "-D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd")
+ set(__ADDED_FLAGS "-D_DLL -D_MT -Xclang --dependent-lib=msvcrt")
+ endif()
+
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g -Xclang -gcodeview -O0 ${__ADDED_FLAGS_DEBUG}")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os -DNDEBUG ${__ADDED_FLAGS}")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3 -DNDEBUG ${__ADDED_FLAGS}")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG -Xclang -gcodeview ${__ADDED_FLAGS}")
+ endif()
+ set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-isystem ")
+
+ set(CMAKE_PCH_EXTENSION .pch)
+ set(CMAKE_PCH_PROLOGUE "#pragma clang system_header")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE> -Xclang -include -Xclang <PCH_HEADER>)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Xclang -emit-pch -Xclang -include -Xclang <PCH_HEADER> -x ${__pch_header_${lang}})
+
+ unset(__ADDED_FLAGS)
+ unset(__ADDED_FLAGS_DEBUG)
+ string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE_LOWER)
+ set(CMAKE_${lang}_STANDARD_LIBRARIES_INIT "-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -loldnames")
+
+ enable_language(RC)
+endmacro()
+
+macro(__enable_llvm_rc_preprocessing clang_option_prefix extra_pp_flags)
+ # Feed the preprocessed rc file to llvm-rc
+ if(CMAKE_RC_COMPILER_INIT MATCHES "llvm-rc" OR CMAKE_RC_COMPILER MATCHES "llvm-rc")
+ if(DEFINED CMAKE_C_COMPILER_ID)
+ set(CMAKE_RC_PREPROCESSOR CMAKE_C_COMPILER)
+ elseif(DEFINED CMAKE_CXX_COMPILER_ID)
+ set(CMAKE_RC_PREPROCESSOR CMAKE_CXX_COMPILER)
+ endif()
+ if(DEFINED CMAKE_RC_PREPROCESSOR)
+ set(CMAKE_DEPFILE_FLAGS_RC "${clang_option_prefix}-MD ${clang_option_prefix}-MF ${clang_option_prefix}<DEP_FILE>")
+ # The <FLAGS> are passed to the preprocess and the resource compiler to pick
+ # up the eventual -D / -C options passed through the CMAKE_RC_FLAGS.
+ set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_COMMAND> -E cmake_llvm_rc <SOURCE> <OBJECT>.pp <${CMAKE_RC_PREPROCESSOR}> <DEFINES> -DRC_INVOKED <INCLUDES> <FLAGS> ${extra_pp_flags} -E -- <SOURCE> ++ <CMAKE_RC_COMPILER> <DEFINES> -I <SOURCE_DIR> <INCLUDES> <FLAGS> /fo <OBJECT> <OBJECT>.pp")
+ if(CMAKE_GENERATOR MATCHES "Ninja")
+ set(CMAKE_NINJA_CMCLDEPS_RC 0)
+ set(CMAKE_NINJA_DEP_TYPE_RC gcc)
+ endif()
+ unset(CMAKE_RC_PREPROCESSOR)
+ endif()
+ endif()
+endmacro()
+
+
+if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC"
+ OR "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+
+ if ( DEFINED CMAKE_C_COMPILER_ID AND DEFINED CMAKE_CXX_COMPILER_ID
+ AND NOT "x${CMAKE_C_COMPILER_ID}" STREQUAL "x${CMAKE_CXX_COMPILER_ID}")
+ message(FATAL_ERROR "The current configuration mixes Clang and MSVC or "
+ "some other CL compatible compiler tool. This is not supported. "
+ "Use either clang or MSVC as both C and C++ compilers.")
+ endif()
+
+ if ( DEFINED CMAKE_C_COMPILER_FRONTEND_VARIANT AND DEFINED CMAKE_CXX_COMPILER_FRONTEND_VARIANT
+ AND NOT "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}")
+ message(FATAL_ERROR "The current configuration uses the Clang compiler "
+ "tool with mixed frontend variants, both the GNU and in MSVC CL "
+ "like variants. This is not supported. Use either clang/clang++ "
+ "or clang-cl as both C and C++ compilers.")
+ endif()
+
+ if(NOT CMAKE_RC_COMPILER_INIT)
+ # Check if rc is already in the path
+ # This may happen in cases where the user is already in a visual studio environment when CMake is invoked
+ find_program(__RC_COMPILER_PATH NAMES rc)
+
+ # Default to rc if it's available, otherwise fall back to llvm-rc
+ if(__RC_COMPILER_PATH)
+ set(CMAKE_RC_COMPILER_INIT rc)
+ else()
+ find_program(__RC_COMPILER_PATH NAMES llvm-rc)
+ if(__RC_COMPILER_PATH)
+ set(CMAKE_RC_COMPILER_INIT llvm-rc)
+ endif()
+ endif()
+
+ unset(__RC_COMPILER_PATH CACHE)
+ endif()
+
+ if ( "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC" OR "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC" )
+ include(Platform/Windows-MSVC)
+ # Set the clang option forwarding prefix for clang-cl usage in the llvm-rc processing stage
+ __enable_llvm_rc_preprocessing("-clang:" "")
+ macro(__windows_compiler_clang_base lang)
+ set(_COMPILE_${lang} "${_COMPILE_${lang}_MSVC}")
+ __windows_compiler_msvc(${lang})
+ set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-imsvc ")
+ endmacro()
+ else()
+ cmake_policy(GET CMP0091 __WINDOWS_CLANG_CMP0091)
+ if(__WINDOWS_CLANG_CMP0091 STREQUAL "NEW")
+ set(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
+ else()
+ set(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT "")
+ endif()
+ unset(__WINDOWS_CLANG_CMP0091)
+
+ set(CMAKE_BUILD_TYPE_INIT Debug)
+
+ __enable_llvm_rc_preprocessing("" "-x c")
+ macro(__windows_compiler_clang_base lang)
+ __windows_compiler_clang_gnu(${lang})
+ endmacro()
+ endif()
+
+else()
+ include(Platform/Windows-GNU)
+ __enable_llvm_rc_preprocessing("" "-x c")
+ macro(__windows_compiler_clang_base lang)
+ __windows_compiler_gnu(${lang})
+ endmacro()
+endif()
+
+macro(__windows_compiler_clang lang)
+ if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.4.0)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_TARGET "-target ")
+ else()
+ set(CMAKE_${lang}_COMPILE_OPTIONS_TARGET "--target=")
+ endif()
+ __windows_compiler_clang_base(${lang})
+endmacro()
diff --git a/Modules/Platform/Windows-Determine-CXX.cmake b/Modules/Platform/Windows-Determine-CXX.cmake
new file mode 100644
index 0000000..bf37f79
--- /dev/null
+++ b/Modules/Platform/Windows-Determine-CXX.cmake
@@ -0,0 +1,7 @@
+if(NOT CMAKE_CXX_COMPILER_NAMES)
+ set(CMAKE_CXX_COMPILER_NAMES c++)
+endif()
+
+# Exclude C++ compilers differing from C compiler only by case
+# because this platform may have a case-insensitive filesystem.
+set(CMAKE_CXX_COMPILER_EXCLUDE CC aCC xlC)
diff --git a/Modules/Platform/Windows-Embarcadero-C.cmake b/Modules/Platform/Windows-Embarcadero-C.cmake
new file mode 100644
index 0000000..607fd4e
--- /dev/null
+++ b/Modules/Platform/Windows-Embarcadero-C.cmake
@@ -0,0 +1,3 @@
+set(_lang C)
+include(Platform/Windows-Embarcadero)
+__embarcadero_language(C)
diff --git a/Modules/Platform/Windows-Embarcadero-CXX.cmake b/Modules/Platform/Windows-Embarcadero-CXX.cmake
new file mode 100644
index 0000000..279a4de
--- /dev/null
+++ b/Modules/Platform/Windows-Embarcadero-CXX.cmake
@@ -0,0 +1,3 @@
+set(_lang CXX)
+include(Platform/Windows-Embarcadero)
+__embarcadero_language(CXX)
diff --git a/Modules/Platform/Windows-Embarcadero.cmake b/Modules/Platform/Windows-Embarcadero.cmake
new file mode 100644
index 0000000..4ecc2c2
--- /dev/null
+++ b/Modules/Platform/Windows-Embarcadero.cmake
@@ -0,0 +1,139 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__WINDOWS_EMBARCADERO)
+ return()
+endif()
+set(__WINDOWS_EMBARCADERO 1)
+
+set(BORLAND 1)
+
+set(__pch_header_C "c-header")
+set(__pch_header_CXX "c++-header")
+set(__pch_header_OBJC "objective-c-header")
+set(__pch_header_OBJCXX "objective-c++-header")
+
+if("${CMAKE_${_lang}_COMPILER_VERSION}" VERSION_LESS 6.30)
+ # Borland target type flags (bcc32 -h -t):
+ set(_tW "-tW") # -tW GUI App (implies -U__CONSOLE__)
+ set(_tC "-tWC") # -tWC Console App (implies -D__CONSOLE__=1)
+ set(_tD "-tWD") # -tWD Build a DLL (implies -D__DLL__=1 -D_DLL=1)
+ set(_tM "-tWM") # -tWM Enable threads (implies -D__MT__=1 -D_MT=1)
+ set(_tR "-tWR -tW-") # -tWR Use DLL runtime (implies -D_RTLDLL, and '-tW' too!!)
+ # Notes:
+ # - The flags affect linking so we pass them to the linker.
+ # - The flags affect preprocessing so we pass them to the compiler.
+ # - Since '-tWR' implies '-tW' we use '-tWR -tW-' instead.
+ # - Since '-tW-' disables '-tWD' we use '-tWR -tW- -tWD' for DLLs.
+else()
+ set(EMBARCADERO 1)
+ set(_tC "-tC") # Target is a console application
+ set(_tD "-tD") # Target is a shared library
+ set(_tM "-tM") # Target is multi-threaded
+ set(_tR "-tR") # Target uses the dynamic RTL
+ set(_tW "-tW") # Target is a Windows application
+endif()
+set(_COMPILE_C "")
+set(_COMPILE_CXX " -P")
+
+set(CMAKE_LIBRARY_PATH_FLAG "-L")
+set(CMAKE_LINK_LIBRARY_FLAG "")
+
+set(CMAKE_FIND_LIBRARY_SUFFIXES "-bcc.lib" ".lib")
+
+# uncomment these out to debug makefiles
+#set(CMAKE_START_TEMP_FILE "")
+#set(CMAKE_END_TEMP_FILE "")
+#set(CMAKE_VERBOSE_MAKEFILE 1)
+
+# Borland cannot handle + in the file name, so mangle object file name
+set (CMAKE_MANGLE_OBJECT_FILE_NAMES "ON")
+
+set (CMAKE_BUILD_TYPE Debug CACHE STRING
+ "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel.")
+
+foreach(t EXE SHARED MODULE)
+ string(APPEND CMAKE_${t}_LINKER_FLAGS_INIT " ${_tM} -lS:1048576 -lSc:4098 -lH:1048576 -lHc:8192 ")
+ string(APPEND CMAKE_${t}_LINKER_FLAGS_DEBUG_INIT " -v")
+ string(APPEND CMAKE_${t}_LINKER_FLAGS_RELWITHDEBINFO_INIT " -v")
+endforeach()
+
+# The Borland link tool does not support multiple concurrent
+# invocations within a single working directory.
+if(NOT DEFINED CMAKE_JOB_POOL_LINK)
+ set(CMAKE_JOB_POOL_LINK BCC32LinkPool)
+ get_property(_bccjp GLOBAL PROPERTY JOB_POOLS)
+ if(NOT _bccjp MATCHES "BCC32LinkPool=")
+ set_property(GLOBAL APPEND PROPERTY JOB_POOLS BCC32LinkPool=1)
+ endif()
+ unset(_bccjp)
+endif()
+
+macro(__embarcadero_language lang)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_DLL "${_tD}") # Note: This variable is a ';' separated list
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "${_tD}") # ... while this is a space separated string.
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_INCLUDES 1)
+
+ set (CMAKE_${lang}_LINKER_WRAPPER_FLAG "-l")
+
+ # compile a source file into an object file
+ # place <DEFINES> outside the response file because Borland refuses
+ # to parse quotes from the response file.
+ set(CMAKE_${lang}_COMPILE_OBJECT
+ "<CMAKE_${lang}_COMPILER> ${_tR} -DWIN32 <DEFINES> <INCLUDES> <FLAGS> -o<OBJECT>${_COMPILE_${lang}} -c <SOURCE>"
+ )
+
+ set(CMAKE_${lang}_LINK_EXECUTABLE
+ "<CMAKE_${lang}_COMPILER> ${_tR} -e<TARGET> <LINK_FLAGS> <FLAGS> ${CMAKE_START_TEMP_FILE} <LINK_LIBRARIES> <OBJECTS>${CMAKE_END_TEMP_FILE}"
+ # "implib -c -w <TARGET_IMPLIB> <TARGET>"
+ )
+
+ # place <DEFINES> outside the response file because Borland refuses
+ # to parse quotes from the response file.
+ set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE
+ "cpp32 -DWIN32 <DEFINES> <INCLUDES> <FLAGS> -o<PREPROCESSED_SOURCE>${_COMPILE_${lang}} -c <SOURCE>"
+ )
+ # Borland >= 5.6 allows -P option for cpp32, <= 5.5 does not
+
+ # Create a module library.
+ set(CMAKE_${lang}_CREATE_SHARED_MODULE
+ "<CMAKE_${lang}_COMPILER> ${_tR} ${_tD} ${CMAKE_START_TEMP_FILE}-e<TARGET> <LINK_FLAGS> <LINK_LIBRARIES> <OBJECTS>${CMAKE_END_TEMP_FILE}"
+ )
+
+ # Create an import library for another target.
+ set(CMAKE_${lang}_CREATE_IMPORT_LIBRARY
+ "implib -c -w <TARGET_IMPLIB> <TARGET>"
+ )
+
+ # Create a shared library.
+ # First create a module and then its import library.
+ set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
+ ${CMAKE_${lang}_CREATE_SHARED_MODULE}
+ ${CMAKE_${lang}_CREATE_IMPORT_LIBRARY}
+ )
+
+ # create a static library
+ set(CMAKE_${lang}_CREATE_STATIC_LIBRARY
+ "tlib ${CMAKE_START_TEMP_FILE}/p512 <LINK_FLAGS> /a <TARGET_QUOTED> <OBJECTS>${CMAKE_END_TEMP_FILE}"
+ )
+
+ set(CMAKE_${lang}_CREATE_WIN32_EXE "${_tW}")
+ set(CMAKE_${lang}_CREATE_CONSOLE_EXE "${_tC}")
+
+ # Precompile Headers
+ if (EMBARCADERO)
+ set(CMAKE_PCH_EXTENSION .pch)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE> -Xclang -include -Xclang <PCH_HEADER>)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Xclang -emit-pch -Xclang -include -Xclang <PCH_HEADER> -x ${__pch_header_${lang}})
+ endif()
+
+ # Initial configuration flags.
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_tM}")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -Od -v")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -O1 -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O2 -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -Od")
+ set(CMAKE_${lang}_STANDARD_LIBRARIES_INIT "import32.lib")
+endmacro()
diff --git a/Modules/Platform/Windows-Flang-Fortran.cmake b/Modules/Platform/Windows-Flang-Fortran.cmake
new file mode 100644
index 0000000..c4420f7
--- /dev/null
+++ b/Modules/Platform/Windows-Flang-Fortran.cmake
@@ -0,0 +1,8 @@
+include(Platform/Windows-MSVC)
+__windows_compiler_msvc(Fortran)
+set(CMAKE_Fortran_COMPILE_OBJECT "<CMAKE_Fortran_COMPILER> ${_COMPILE_Fortran} <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -Xclang --dependent-lib=libcmt)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -Xclang --dependent-lib=msvcrt)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -Xclang --dependent-lib=libcmtd)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -Xclang --dependent-lib=msvcrtd)
diff --git a/Modules/Platform/Windows-G95-Fortran.cmake b/Modules/Platform/Windows-G95-Fortran.cmake
new file mode 100644
index 0000000..af08008
--- /dev/null
+++ b/Modules/Platform/Windows-G95-Fortran.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-GNU-Fortran)
diff --git a/Modules/Platform/Windows-GNU-ASM.cmake b/Modules/Platform/Windows-GNU-ASM.cmake
new file mode 100644
index 0000000..8600892
--- /dev/null
+++ b/Modules/Platform/Windows-GNU-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows-GNU)
+__windows_compiler_gnu(ASM)
diff --git a/Modules/Platform/Windows-GNU-C-ABI.cmake b/Modules/Platform/Windows-GNU-C-ABI.cmake
new file mode 100644
index 0000000..1189263
--- /dev/null
+++ b/Modules/Platform/Windows-GNU-C-ABI.cmake
@@ -0,0 +1 @@
+__windows_compiler_gnu_abi(C)
diff --git a/Modules/Platform/Windows-GNU-C.cmake b/Modules/Platform/Windows-GNU-C.cmake
new file mode 100644
index 0000000..ecf89dc
--- /dev/null
+++ b/Modules/Platform/Windows-GNU-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows-GNU)
+__windows_compiler_gnu(C)
diff --git a/Modules/Platform/Windows-GNU-CXX-ABI.cmake b/Modules/Platform/Windows-GNU-CXX-ABI.cmake
new file mode 100644
index 0000000..f3c701c
--- /dev/null
+++ b/Modules/Platform/Windows-GNU-CXX-ABI.cmake
@@ -0,0 +1 @@
+__windows_compiler_gnu_abi(CXX)
diff --git a/Modules/Platform/Windows-GNU-CXX.cmake b/Modules/Platform/Windows-GNU-CXX.cmake
new file mode 100644
index 0000000..23e6552
--- /dev/null
+++ b/Modules/Platform/Windows-GNU-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows-GNU)
+__windows_compiler_gnu(CXX)
diff --git a/Modules/Platform/Windows-GNU-Fortran-ABI.cmake b/Modules/Platform/Windows-GNU-Fortran-ABI.cmake
new file mode 100644
index 0000000..179280b
--- /dev/null
+++ b/Modules/Platform/Windows-GNU-Fortran-ABI.cmake
@@ -0,0 +1 @@
+__windows_compiler_gnu_abi(Fortran)
diff --git a/Modules/Platform/Windows-GNU-Fortran.cmake b/Modules/Platform/Windows-GNU-Fortran.cmake
new file mode 100644
index 0000000..b81b796
--- /dev/null
+++ b/Modules/Platform/Windows-GNU-Fortran.cmake
@@ -0,0 +1,5 @@
+include(Platform/Windows-GNU)
+__windows_compiler_gnu(Fortran)
+
+# gfortran on 64-bit MinGW defines __SIZEOF_POINTER__
+set(CMAKE_Fortran_SIZEOF_DATA_PTR_DEFAULT 4)
diff --git a/Modules/Platform/Windows-GNU.cmake b/Modules/Platform/Windows-GNU.cmake
new file mode 100644
index 0000000..e50c215
--- /dev/null
+++ b/Modules/Platform/Windows-GNU.cmake
@@ -0,0 +1,206 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__WINDOWS_GNU)
+ return()
+endif()
+set(__WINDOWS_GNU 1)
+
+set(CMAKE_IMPORT_LIBRARY_PREFIX "lib")
+set(CMAKE_SHARED_LIBRARY_PREFIX "lib")
+set(CMAKE_SHARED_MODULE_PREFIX "lib")
+set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
+
+set(CMAKE_EXECUTABLE_SUFFIX ".exe")
+set(CMAKE_IMPORT_LIBRARY_SUFFIX ".dll.a")
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".dll")
+set(CMAKE_SHARED_MODULE_SUFFIX ".dll")
+set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
+
+if(MSYS OR MINGW)
+ set(CMAKE_EXTRA_LINK_EXTENSIONS ".lib") # MinGW can also link to a MS .lib
+endif()
+
+if(MINGW)
+ set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.a" ".a" ".lib")
+ set(CMAKE_C_STANDARD_LIBRARIES_INIT "-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32")
+ set(CMAKE_CXX_STANDARD_LIBRARIES_INIT "${CMAKE_C_STANDARD_LIBRARIES_INIT}")
+endif()
+
+set(CMAKE_DL_LIBS "")
+set(CMAKE_LIBRARY_PATH_FLAG "-L")
+set(CMAKE_LINK_LIBRARY_FLAG "-l")
+set(CMAKE_LINK_DEF_FILE_FLAG "") # Empty string: passing the file is enough
+set(CMAKE_LINK_LIBRARY_SUFFIX "")
+
+set(CMAKE_GNULD_IMAGE_VERSION
+ "-Wl,--major-image-version,<TARGET_VERSION_MAJOR>,--minor-image-version,<TARGET_VERSION_MINOR>")
+
+# Check if GNU ld is too old to support @FILE syntax.
+set(__WINDOWS_GNU_LD_RESPONSE 1)
+execute_process(COMMAND ld -v OUTPUT_VARIABLE _help ERROR_VARIABLE _help)
+if("${_help}" MATCHES "GNU ld .* 2\\.1[1-6]")
+ set(__WINDOWS_GNU_LD_RESPONSE 0)
+endif()
+
+macro(__windows_compiler_gnu lang)
+
+ if(MSYS OR MINGW)
+ # Create archiving rules to support large object file lists for static libraries.
+ set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_${lang}_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
+
+ # Initialize C link type selection flags. These flags are used when
+ # building a shared library, shared module, or executable that links
+ # to other libraries to select whether to use the static or shared
+ # versions of the libraries.
+ foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+ set(CMAKE_${type}_LINK_STATIC_${lang}_FLAGS "-Wl,-Bstatic")
+ set(CMAKE_${type}_LINK_DYNAMIC_${lang}_FLAGS "-Wl,-Bdynamic")
+ endforeach()
+ endif()
+
+ # No -fPIC on Windows
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "")
+ set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+ set(CMAKE_${lang}_LINK_OPTIONS_PIE "")
+ set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE "")
+ set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "")
+
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_OBJECTS ${__WINDOWS_GNU_LD_RESPONSE})
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_LIBRARIES ${__WINDOWS_GNU_LD_RESPONSE})
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_INCLUDES 1)
+
+ # We prefer "@" for response files but it is not supported by gcc 3.
+ execute_process(COMMAND ${CMAKE_${lang}_COMPILER} --version OUTPUT_VARIABLE _ver ERROR_VARIABLE _ver)
+ if("${_ver}" MATCHES "\\(GCC\\) 3\\.")
+ if("${lang}" STREQUAL "Fortran")
+ # The GNU Fortran compiler reports an error:
+ # no input files; unwilling to write output files
+ # when the response file is passed with "-Wl,@".
+ set(CMAKE_Fortran_USE_RESPONSE_FILE_FOR_OBJECTS 0)
+ else()
+ # Use "-Wl,@" to pass the response file to the linker.
+ set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-Wl,@")
+ endif()
+ # The GNU 3.x compilers do not support response files (only linkers).
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_INCLUDES 0)
+ # Link libraries are generated only for the front-end.
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_LIBRARIES 0)
+ else()
+ # Use "@" to pass the response file to the front-end.
+ set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "@")
+ endif()
+
+ # Binary link rules.
+ set(CMAKE_${lang}_CREATE_SHARED_MODULE
+ "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_MODULE_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>")
+ set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
+ "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>")
+ set(CMAKE_${lang}_LINK_EXECUTABLE
+ "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
+ set(CMAKE_${lang}_CREATE_WIN32_EXE "-mwindows")
+
+ list(APPEND CMAKE_${lang}_ABI_FILES "Platform/Windows-GNU-${lang}-ABI")
+
+ # Support very long lists of object files.
+ # TODO: check for which gcc versions this is still needed, not needed for gcc >= 4.4.
+ # Ninja generator doesn't support this work around.
+ if("${CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG}" STREQUAL "@" AND NOT CMAKE_GENERATOR MATCHES "Ninja")
+ foreach(rule CREATE_SHARED_MODULE CREATE_SHARED_LIBRARY LINK_EXECUTABLE)
+ # The gcc/collect2/ld toolchain does not use response files
+ # internally so we cannot pass long object lists. Instead pass
+ # the object file list in a response file to the archiver to put
+ # them in a temporary archive. Hand the archive to the linker.
+ string(REPLACE "<OBJECTS>" "-Wl,--whole-archive <OBJECT_DIR>/objects.a -Wl,--no-whole-archive"
+ CMAKE_${lang}_${rule} "${CMAKE_${lang}_${rule}}")
+ set(CMAKE_${lang}_${rule}
+ "<CMAKE_COMMAND> -E rm -f <OBJECT_DIR>/objects.a"
+ "<CMAKE_AR> cr <OBJECT_DIR>/objects.a <OBJECTS>"
+ "${CMAKE_${lang}_${rule}}"
+ )
+ endforeach()
+ endif()
+
+ if(NOT CMAKE_RC_COMPILER_INIT AND NOT CMAKE_GENERATOR_RC)
+ set(CMAKE_RC_COMPILER_INIT ${_CMAKE_TOOLCHAIN_PREFIX}windres)
+ endif()
+
+ enable_language(RC)
+endmacro()
+
+macro(__windows_compiler_gnu_abi lang)
+ if(CMAKE_NO_GNUtoMS)
+ set(CMAKE_GNUtoMS 0)
+ else()
+ option(CMAKE_GNUtoMS "Convert GNU import libraries to MS format (requires Visual Studio)" OFF)
+ endif()
+
+ if(CMAKE_GNUtoMS AND NOT CMAKE_GNUtoMS_LIB)
+ # Find MS development environment setup script for this architecture.
+ # We need to use the MS Librarian tool (lib.exe).
+ # Find the most recent version available.
+
+ # Query the VS Installer tool for locations of VS 2017 and above.
+ set(_vs_installer_paths "")
+ foreach(vs RANGE 16 15 -1) # change the first number to the largest supported version
+ cmake_host_system_information(RESULT _vs_dir QUERY VS_${vs}_DIR)
+ if(_vs_dir)
+ list(APPEND _vs_installer_paths "${_vs_dir}/VC/Auxiliary/Build")
+ endif()
+ endforeach(vs)
+
+ if("${CMAKE_SIZEOF_VOID_P}" EQUAL 4)
+ find_program(CMAKE_GNUtoMS_VCVARS NAMES vcvars32.bat
+ DOC "Visual Studio vcvars32.bat"
+ PATHS
+ ${_vs_installer_paths}
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0\\Setup\\VC;ProductDir]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0\\Setup\\VC;ProductDir]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0\\Setup\\VC;ProductDir]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0\\Setup\\VC;ProductDir]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0\\Setup\\VC;ProductDir]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1\\Setup\\VC;ProductDir]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\6.0\\Setup\\Microsoft Visual C++;ProductDir]/bin"
+ )
+ set(CMAKE_GNUtoMS_ARCH x86)
+ elseif("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
+ find_program(CMAKE_GNUtoMS_VCVARS NAMES vcvars64.bat vcvarsamd64.bat
+ DOC "Visual Studio vcvarsamd64.bat"
+ PATHS
+ ${_vs_installer_paths}
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0\\Setup\\VC;ProductDir]/bin/amd64"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0\\Setup\\VC;ProductDir]/bin/amd64"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0\\Setup\\VC;ProductDir]/bin/amd64"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0\\Setup\\VC;ProductDir]/bin/amd64"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0\\Setup\\VC;ProductDir]/bin/amd64"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/bin/amd64"
+ )
+ set(CMAKE_GNUtoMS_ARCH amd64)
+ endif()
+ unset(_vs_installer_paths)
+ set_property(CACHE CMAKE_GNUtoMS_VCVARS PROPERTY ADVANCED 1)
+ if(CMAKE_GNUtoMS_VCVARS)
+ # Create helper script to run lib.exe from MS environment.
+ string(REPLACE "/" "\\" CMAKE_GNUtoMS_BAT "${CMAKE_GNUtoMS_VCVARS}")
+ set(CMAKE_GNUtoMS_LIB ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeGNUtoMS_lib.bat)
+ configure_file(${CMAKE_ROOT}/Modules/Platform/GNUtoMS_lib.bat.in ${CMAKE_GNUtoMS_LIB})
+ else()
+ message(WARNING "Disabling CMAKE_GNUtoMS option because CMAKE_GNUtoMS_VCVARS is not set.")
+ set(CMAKE_GNUtoMS 0)
+ endif()
+ endif()
+
+ if(CMAKE_GNUtoMS)
+ # Teach CMake how to create a MS import library at link time.
+ set(CMAKE_${lang}_GNUtoMS_RULE " -Wl,--output-def,<TARGET_NAME>.def"
+ "<CMAKE_COMMAND> -Dlib=\"${CMAKE_GNUtoMS_LIB}\" -Ddef=<TARGET_NAME>.def -Ddll=<TARGET> -Dimp=<TARGET_IMPLIB> -P \"${CMAKE_ROOT}/Modules/Platform/GNUtoMS_lib.cmake\""
+ )
+ endif()
+endmacro()
diff --git a/Modules/Platform/Windows-Intel-ASM.cmake b/Modules/Platform/Windows-Intel-ASM.cmake
new file mode 100644
index 0000000..31d08c7
--- /dev/null
+++ b/Modules/Platform/Windows-Intel-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows-Intel)
+__windows_compiler_intel(ASM)
diff --git a/Modules/Platform/Windows-Intel-C.cmake b/Modules/Platform/Windows-Intel-C.cmake
new file mode 100644
index 0000000..152b27c
--- /dev/null
+++ b/Modules/Platform/Windows-Intel-C.cmake
@@ -0,0 +1,27 @@
+include(Platform/Windows-Intel)
+__windows_compiler_intel(C)
+
+set(CMAKE_DEPFILE_FLAGS_C "-QMMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")
+set(CMAKE_C_DEPFILE_FORMAT gcc)
+
+if(CMAKE_GENERATOR MATCHES "^Ninja")
+ if(_CMAKE_NINJA_VERSION VERSION_LESS 1.9)
+ # This ninja version is too old to support the Intel depfile format.
+ # Fall back to msvc depfile format.
+ set(CMAKE_DEPFILE_FLAGS_C "/showIncludes")
+ set(CMAKE_C_DEPFILE_FORMAT msvc)
+ endif()
+endif()
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+if("${CMAKE_SOURCE_DIR}${CMAKE_BINARY_DIR}" MATCHES " ")
+ # The Intel compiler does not properly escape spaces in a depfile.
+ # Fall back to msvc depfile format.
+ set(CMAKE_DEPFILE_FLAGS_C "/showIncludes")
+ set(CMAKE_C_DEPFILE_FORMAT msvc)
+endif()
diff --git a/Modules/Platform/Windows-Intel-CXX.cmake b/Modules/Platform/Windows-Intel-CXX.cmake
new file mode 100644
index 0000000..ce33ae1
--- /dev/null
+++ b/Modules/Platform/Windows-Intel-CXX.cmake
@@ -0,0 +1,28 @@
+include(Platform/Windows-Intel)
+set(_COMPILE_CXX " /TP")
+__windows_compiler_intel(CXX)
+
+set(CMAKE_DEPFILE_FLAGS_CXX "-QMMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")
+set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+
+if(CMAKE_GENERATOR MATCHES "^Ninja")
+ if(_CMAKE_NINJA_VERSION VERSION_LESS 1.9)
+ # This ninja version is too old to support the Intel depfile format.
+ # Fall back to msvc depfile format.
+ set(CMAKE_DEPFILE_FLAGS_CXX "/showIncludes")
+ set(CMAKE_CXX_DEPFILE_FORMAT msvc)
+ endif()
+endif()
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+if("${CMAKE_SOURCE_DIR}${CMAKE_BINARY_DIR}" MATCHES " ")
+ # The Intel compiler does not properly escape spaces in a depfile.
+ # Fall back to msvc depfile format.
+ set(CMAKE_DEPFILE_FLAGS_CXX "/showIncludes")
+ set(CMAKE_CXX_DEPFILE_FORMAT msvc)
+endif()
diff --git a/Modules/Platform/Windows-Intel-Fortran.cmake b/Modules/Platform/Windows-Intel-Fortran.cmake
new file mode 100644
index 0000000..e3804fb
--- /dev/null
+++ b/Modules/Platform/Windows-Intel-Fortran.cmake
@@ -0,0 +1,44 @@
+include(Platform/Windows-Intel)
+set(CMAKE_BUILD_TYPE_INIT Debug)
+set(_COMPILE_Fortran " /fpp")
+set(CMAKE_Fortran_MODDIR_FLAG "-module:")
+set(CMAKE_Fortran_STANDARD_LIBRARIES_INIT "user32.lib")
+__windows_compiler_intel(Fortran)
+if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+ set(_LIBSDLL "")
+ set(_DBGLIBS "")
+ set(_THREADS "")
+else()
+ set(_LIBSDLL " /libs:dll")
+ set(_DBGLIBS " /dbglibs")
+ set(_THREADS " /threads")
+endif()
+
+cmake_policy(GET CMP0092 _cmp0092)
+if(NOT _cmp0092 STREQUAL "NEW")
+ string(APPEND CMAKE_Fortran_FLAGS_INIT " /W1")
+endif()
+unset(_cmp0092)
+
+string(APPEND CMAKE_Fortran_FLAGS_INIT " /nologo /fpp${_LIBSDLL}${_THREADS}")
+string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " /Od /debug:full${_DBGLIBS}")
+string(APPEND CMAKE_Fortran_FLAGS_MINSIZEREL_INIT " /O1 /DNDEBUG")
+string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " /O2 /DNDEBUG")
+string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " /O2 /debug:full /DNDEBUG")
+unset(_LIBSDLL)
+unset(_DBGLIBS)
+unset(_THREADS)
+
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -threads -libs:static)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -threads -libs:dll)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -threads -libs:static -dbglibs)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -threads -libs:dll -dbglibs)
+
+# Intel Fortran for Windows supports single-threaded RTL but it is
+# not implemented by the Visual Studio integration.
+if(NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreaded -libs:static)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreadedDLL -libs:dll)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreadedDebug -libs:static -dbglibs)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreadedDebugDLL -libs:dll -dbglibs)
+endif()
diff --git a/Modules/Platform/Windows-Intel-ISPC.cmake b/Modules/Platform/Windows-Intel-ISPC.cmake
new file mode 100644
index 0000000..cd26302
--- /dev/null
+++ b/Modules/Platform/Windows-Intel-ISPC.cmake
@@ -0,0 +1,8 @@
+
+if(CMAKE_VERBOSE_MAKEFILE)
+ set(CMAKE_CL_NOLOGO)
+else()
+ set(CMAKE_CL_NOLOGO "/nologo")
+endif()
+
+set(CMAKE_ISPC_CREATE_STATIC_LIBRARY "<CMAKE_AR> ${CMAKE_CL_NOLOGO} <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
diff --git a/Modules/Platform/Windows-Intel.cmake b/Modules/Platform/Windows-Intel.cmake
new file mode 100644
index 0000000..01f8dd0
--- /dev/null
+++ b/Modules/Platform/Windows-Intel.cmake
@@ -0,0 +1,32 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__WINDOWS_INTEL)
+ return()
+endif()
+set(__WINDOWS_INTEL 1)
+
+
+if (CMAKE_GENERATOR MATCHES "^Ninja")
+ # retrieve ninja version to enable dependencies configuration
+ # against Ninja capabilities
+ execute_process(COMMAND "${CMAKE_MAKE_PROGRAM}" --version
+ RESULT_VARIABLE _CMAKE_NINJA_RESULT
+ OUTPUT_VARIABLE _CMAKE_NINJA_VERSION
+ ERROR_VARIABLE _CMAKE_NINJA_VERSION)
+ if (NOT _CMAKE_NINJA_RESULT AND _CMAKE_NINJA_VERSION MATCHES "[0-9]+(\\.[0-9]+)*")
+ set (_CMAKE_NINJA_VERSION "${CMAKE_MATCH_0}")
+ endif()
+ unset(_CMAKE_NINJA_RESULT)
+endif()
+
+include(Platform/Windows-MSVC)
+macro(__windows_compiler_intel lang)
+ __windows_compiler_msvc(${lang})
+ string(REPLACE "<CMAKE_AR>" "xilib" CMAKE_${lang}_CREATE_STATIC_LIBRARY "${CMAKE_${lang}_CREATE_STATIC_LIBRARY}")
+ foreach(rule CREATE_SHARED_LIBRARY CREATE_SHARED_MODULE LINK_EXECUTABLE)
+ string(REPLACE "<CMAKE_LINKER>" "xilink" CMAKE_${lang}_${rule} "${CMAKE_${lang}_${rule}}")
+ endforeach()
+endmacro()
diff --git a/Modules/Platform/Windows-IntelLLVM-ASM.cmake b/Modules/Platform/Windows-IntelLLVM-ASM.cmake
new file mode 100644
index 0000000..f355e49
--- /dev/null
+++ b/Modules/Platform/Windows-IntelLLVM-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows-IntelLLVM)
+__windows_compiler_intel(ASM)
diff --git a/Modules/Platform/Windows-IntelLLVM-C.cmake b/Modules/Platform/Windows-IntelLLVM-C.cmake
new file mode 100644
index 0000000..93c3364
--- /dev/null
+++ b/Modules/Platform/Windows-IntelLLVM-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows-IntelLLVM)
+__windows_compiler_intel(C)
diff --git a/Modules/Platform/Windows-IntelLLVM-CXX.cmake b/Modules/Platform/Windows-IntelLLVM-CXX.cmake
new file mode 100644
index 0000000..4667895
--- /dev/null
+++ b/Modules/Platform/Windows-IntelLLVM-CXX.cmake
@@ -0,0 +1,3 @@
+include(Platform/Windows-IntelLLVM)
+set(_COMPILE_CXX " /TP")
+__windows_compiler_intel(CXX)
diff --git a/Modules/Platform/Windows-IntelLLVM-Fortran.cmake b/Modules/Platform/Windows-IntelLLVM-Fortran.cmake
new file mode 100644
index 0000000..06d0a00
--- /dev/null
+++ b/Modules/Platform/Windows-IntelLLVM-Fortran.cmake
@@ -0,0 +1,44 @@
+include(Platform/Windows-IntelLLVM)
+set(CMAKE_BUILD_TYPE_INIT Debug)
+set(_COMPILE_Fortran " /fpp")
+set(CMAKE_Fortran_MODDIR_FLAG "-module:")
+set(CMAKE_Fortran_STANDARD_LIBRARIES_INIT "user32.lib")
+__windows_compiler_intel(Fortran)
+if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+ set(_LIBSDLL "")
+ set(_DBGLIBS "")
+ set(_THREADS "")
+else()
+ set(_LIBSDLL " /libs:dll")
+ set(_DBGLIBS " /dbglibs")
+ set(_THREADS " /threads")
+endif()
+
+cmake_policy(GET CMP0092 _cmp0092)
+if(NOT _cmp0092 STREQUAL "NEW")
+ string(APPEND CMAKE_Fortran_FLAGS_INIT " /W1")
+endif()
+unset(_cmp0092)
+
+string(APPEND CMAKE_Fortran_FLAGS_INIT " /nologo /fpp${_LIBSDLL}${_THREADS}")
+string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " /Od /debug:full${_DBGLIBS}")
+string(APPEND CMAKE_Fortran_FLAGS_MINSIZEREL_INIT " /O1 /DNDEBUG")
+string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " /O2 /DNDEBUG")
+string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " /O2 /debug:full /DNDEBUG")
+unset(_LIBSDLL)
+unset(_DBGLIBS)
+unset(_THREADS)
+
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -threads -libs:static)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -threads -libs:dll)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -threads -libs:static -dbglibs)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -threads -libs:dll -dbglibs)
+
+# Intel Fortran for Windows supports single-threaded RTL but it is
+# not implemented by the Visual Studio integration.
+if(NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreaded -libs:static)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreadedDLL -libs:dll)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreadedDebug -libs:static -dbglibs)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreadedDebugDLL -libs:dll -dbglibs)
+endif()
diff --git a/Modules/Platform/Windows-IntelLLVM.cmake b/Modules/Platform/Windows-IntelLLVM.cmake
new file mode 100644
index 0000000..b9ea037
--- /dev/null
+++ b/Modules/Platform/Windows-IntelLLVM.cmake
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__WINDOWS_INTEL)
+ return()
+endif()
+set(__WINDOWS_INTEL 1)
+
+include(Platform/Windows-MSVC)
+macro(__windows_compiler_intel lang)
+ __windows_compiler_msvc(${lang})
+
+ set(CMAKE_DEPFILE_FLAGS_${lang} "-QMMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")
+ set(CMAKE_${lang}_DEPFILE_FORMAT gcc)
+endmacro()
diff --git a/Modules/Platform/Windows-MSVC-C.cmake b/Modules/Platform/Windows-MSVC-C.cmake
new file mode 100644
index 0000000..67b6827
--- /dev/null
+++ b/Modules/Platform/Windows-MSVC-C.cmake
@@ -0,0 +1,12 @@
+include(Platform/Windows-MSVC)
+if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 18.0)
+ set(_FS_C " /FS")
+endif()
+__windows_compiler_msvc(C)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+endif()
diff --git a/Modules/Platform/Windows-MSVC-CXX.cmake b/Modules/Platform/Windows-MSVC-CXX.cmake
new file mode 100644
index 0000000..6fea617
--- /dev/null
+++ b/Modules/Platform/Windows-MSVC-CXX.cmake
@@ -0,0 +1,13 @@
+include(Platform/Windows-MSVC)
+set(_COMPILE_CXX " /TP")
+if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0)
+ set(_FS_CXX " /FS")
+endif()
+__windows_compiler_msvc(CXX)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+endif()
diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake
new file mode 100644
index 0000000..4223bde
--- /dev/null
+++ b/Modules/Platform/Windows-MSVC.cmake
@@ -0,0 +1,481 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__WINDOWS_MSVC)
+ return()
+endif()
+set(__WINDOWS_MSVC 1)
+
+set(CMAKE_LIBRARY_PATH_FLAG "-LIBPATH:")
+set(CMAKE_LINK_LIBRARY_FLAG "")
+set(MSVC 1)
+
+# hack: if a new cmake (which uses CMAKE_LINKER) runs on an old build tree
+# (where link was hardcoded) and where CMAKE_LINKER isn't in the cache
+# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun)
+# hardcode CMAKE_LINKER here to link, so it behaves as it did before, Alex
+if(NOT DEFINED CMAKE_LINKER)
+ set(CMAKE_LINKER link)
+endif()
+
+if(CMAKE_VERBOSE_MAKEFILE)
+ set(CMAKE_CL_NOLOGO)
+else()
+ set(CMAKE_CL_NOLOGO "/nologo")
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "WindowsCE")
+ set(_PLATFORM_LINK_FLAGS " /subsystem:windowsce")
+else()
+ set(_PLATFORM_LINK_FLAGS "")
+endif()
+
+set(CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS 1)
+if(NOT CMAKE_NO_BUILD_TYPE AND CMAKE_GENERATOR MATCHES "Visual Studio")
+ set (CMAKE_NO_BUILD_TYPE 1)
+endif()
+
+if("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
+ set(MSVC_IDE 1)
+else()
+ set(MSVC_IDE 0)
+endif()
+
+if(NOT MSVC_VERSION)
+ if("x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC")
+ set(_compiler_version ${CMAKE_C_COMPILER_VERSION})
+ elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
+ set(_compiler_version ${CMAKE_CXX_COMPILER_VERSION})
+ elseif(CMAKE_C_SIMULATE_VERSION)
+ set(_compiler_version ${CMAKE_C_SIMULATE_VERSION})
+ elseif(CMAKE_CXX_SIMULATE_VERSION)
+ set(_compiler_version ${CMAKE_CXX_SIMULATE_VERSION})
+ elseif(CMAKE_Fortran_SIMULATE_VERSION)
+ set(_compiler_version ${CMAKE_Fortran_SIMULATE_VERSION})
+ elseif(CMAKE_CUDA_SIMULATE_VERSION)
+ set(_compiler_version ${CMAKE_CUDA_SIMULATE_VERSION})
+ elseif(CMAKE_C_COMPILER_VERSION)
+ set(_compiler_version ${CMAKE_C_COMPILER_VERSION})
+ else()
+ set(_compiler_version ${CMAKE_CXX_COMPILER_VERSION})
+ endif()
+ if("${_compiler_version}" MATCHES "^([0-9]+)\\.([0-9]+)")
+ math(EXPR MSVC_VERSION "${CMAKE_MATCH_1}*100 + ${CMAKE_MATCH_2}")
+ else()
+ message(FATAL_ERROR "MSVC compiler version not detected properly: ${_compiler_version}")
+ endif()
+
+ if(MSVC_VERSION GREATER_EQUAL 1920)
+ # VS 2019 or greater
+ set(MSVC_TOOLSET_VERSION 142)
+ elseif(MSVC_VERSION GREATER_EQUAL 1910)
+ # VS 2017 or greater
+ set(MSVC_TOOLSET_VERSION 141)
+ elseif(MSVC_VERSION EQUAL 1900)
+ # VS 2015
+ set(MSVC_TOOLSET_VERSION 140)
+ elseif(MSVC_VERSION EQUAL 1800)
+ # VS 2013
+ set(MSVC_TOOLSET_VERSION 120)
+ elseif(MSVC_VERSION EQUAL 1700)
+ # VS 2012
+ set(MSVC_TOOLSET_VERSION 110)
+ elseif(MSVC_VERSION EQUAL 1600)
+ # VS 2010
+ set(MSVC_TOOLSET_VERSION 100)
+ elseif(MSVC_VERSION EQUAL 1500)
+ # VS 2008
+ set(MSVC_TOOLSET_VERSION 90)
+ elseif(MSVC_VERSION EQUAL 1400)
+ # VS 2005
+ set(MSVC_TOOLSET_VERSION 80)
+ else()
+ # We don't support MSVC_TOOLSET_VERSION for earlier compiler.
+ endif()
+
+ set(MSVC10)
+ set(MSVC11)
+ set(MSVC12)
+ set(MSVC14)
+ set(MSVC60)
+ set(MSVC70)
+ set(MSVC71)
+ set(MSVC80)
+ set(MSVC90)
+ set(CMAKE_COMPILER_2005)
+ set(CMAKE_COMPILER_SUPPORTS_PDBTYPE)
+ if(NOT "${_compiler_version}" VERSION_LESS 20)
+ # We no longer provide per-version variables. Use MSVC_VERSION instead.
+ elseif(NOT "${_compiler_version}" VERSION_LESS 19)
+ set(MSVC14 1)
+ elseif(NOT "${_compiler_version}" VERSION_LESS 18)
+ set(MSVC12 1)
+ elseif(NOT "${_compiler_version}" VERSION_LESS 17)
+ set(MSVC11 1)
+ elseif(NOT "${_compiler_version}" VERSION_LESS 16)
+ set(MSVC10 1)
+ elseif(NOT "${_compiler_version}" VERSION_LESS 15)
+ set(MSVC90 1)
+ elseif(NOT "${_compiler_version}" VERSION_LESS 14)
+ set(MSVC80 1)
+ set(CMAKE_COMPILER_2005 1)
+ elseif(NOT "${_compiler_version}" VERSION_LESS 13.10)
+ set(MSVC71 1)
+ elseif(NOT "${_compiler_version}" VERSION_LESS 13)
+ set(MSVC70 1)
+ else()
+ set(MSVC60 1)
+ set(CMAKE_COMPILER_SUPPORTS_PDBTYPE 1)
+ endif()
+endif()
+
+if(MSVC_C_ARCHITECTURE_ID MATCHES 64 OR MSVC_CXX_ARCHITECTURE_ID MATCHES 64)
+ set(CMAKE_CL_64 1)
+else()
+ set(CMAKE_CL_64 0)
+endif()
+if(CMAKE_FORCE_WIN64 OR CMAKE_FORCE_IA64)
+ set(CMAKE_CL_64 1)
+endif()
+
+if("${MSVC_VERSION}" GREATER 1599)
+ set(MSVC_INCREMENTAL_DEFAULT ON)
+endif()
+
+# default to Debug builds
+set(CMAKE_BUILD_TYPE_INIT Debug)
+
+# Compute an architecture family from the architecture id.
+foreach(lang C CXX)
+ set(_MSVC_${lang}_ARCHITECTURE_FAMILY "${MSVC_${lang}_ARCHITECTURE_ID}")
+ if(_MSVC_${lang}_ARCHITECTURE_FAMILY MATCHES "^ARM64EC")
+ set(_MSVC_${lang}_ARCHITECTURE_FAMILY "ARM64EC")
+ elseif(_MSVC_${lang}_ARCHITECTURE_FAMILY MATCHES "^ARM64")
+ set(_MSVC_${lang}_ARCHITECTURE_FAMILY "ARM64")
+ elseif(_MSVC_${lang}_ARCHITECTURE_FAMILY MATCHES "^ARM")
+ set(_MSVC_${lang}_ARCHITECTURE_FAMILY "ARM")
+ elseif(_MSVC_${lang}_ARCHITECTURE_FAMILY MATCHES "^SH")
+ set(_MSVC_${lang}_ARCHITECTURE_FAMILY "SHx")
+ endif()
+endforeach()
+
+cmake_policy(GET CMP0117 __WINDOWS_MSVC_CMP0117)
+if(__WINDOWS_MSVC_CMP0117 STREQUAL "NEW")
+ set(_GR "")
+else()
+ set(_GR " /GR")
+endif()
+unset(__WINDOWS_MSVC_CMP0117)
+
+if(WINCE)
+ foreach(lang C CXX)
+ string(TOUPPER "${_MSVC_${lang}_ARCHITECTURE_FAMILY}" _MSVC_${lang}_ARCHITECTURE_FAMILY_UPPER)
+ endforeach()
+
+ if("${CMAKE_SYSTEM_VERSION}" MATCHES "^([0-9]+)\\.([0-9]+)")
+ math(EXPR _CE_VERSION "${CMAKE_MATCH_1}*100 + ${CMAKE_MATCH_2}")
+ elseif("${CMAKE_SYSTEM_VERSION}" STREQUAL "")
+ set(_CE_VERSION "500")
+ else()
+ message(FATAL_ERROR "Invalid Windows CE version: ${CMAKE_SYSTEM_VERSION}")
+ endif()
+
+ set(_PLATFORM_DEFINES "/D_WIN32_WCE=0x${_CE_VERSION} /DUNDER_CE /DWINCE")
+ set(_PLATFORM_DEFINES_C " /D${_MSVC_C_ARCHITECTURE_FAMILY} /D_${_MSVC_C_ARCHITECTURE_FAMILY_UPPER}_")
+ set(_PLATFORM_DEFINES_CXX " /D${_MSVC_CXX_ARCHITECTURE_FAMILY} /D_${_MSVC_CXX_ARCHITECTURE_FAMILY_UPPER}_")
+
+ set(_RTC1 "")
+ set(_FLAGS_C "")
+ set(_FLAGS_CXX "${_GR} /EHsc")
+
+ foreach(lang C CXX)
+ if(_MSVC_${lang}_ARCHITECTURE_FAMILY STREQUAL "ARM")
+ string(APPEND _PLATFORM_DEFINES_${lang} " /D${MSVC_${lang}_ARCHITECTURE_ID}")
+ if(MSVC_${lang}_ARCHITECTURE_ID MATCHES "^ARMV([45])I$")
+ string(APPEND _FLAGS_${lang} " /QRarch${CMAKE_MATCH_1}T")
+ endif()
+ endif()
+ endforeach()
+
+ set(CMAKE_C_STANDARD_LIBRARIES_INIT "coredll.lib ole32.lib oleaut32.lib uuid.lib commctrl.lib")
+ foreach(t EXE SHARED MODULE)
+ string(APPEND CMAKE_${t}_LINKER_FLAGS_INIT " /NODEFAULTLIB:libc.lib /NODEFAULTLIB:oldnames.lib")
+ endforeach()
+
+ if (MSVC_VERSION LESS 1600)
+ string(APPEND CMAKE_C_STANDARD_LIBRARIES_INIT " corelibc.lib")
+ endif ()
+elseif(WINDOWS_PHONE OR WINDOWS_STORE)
+ set(_PLATFORM_DEFINES "/DWIN32")
+ set(_FLAGS_C " /DUNICODE /D_UNICODE")
+ set(_FLAGS_CXX " /DUNICODE /D_UNICODE${_GR} /EHsc")
+ if(WINDOWS_STORE AND MSVC_VERSION GREATER 1899)
+ set(CMAKE_C_STANDARD_LIBRARIES_INIT "WindowsApp.lib")
+ elseif(WINDOWS_PHONE)
+ set(CMAKE_C_STANDARD_LIBRARIES_INIT "WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelHost.lib")
+ elseif(_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM" OR _MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM" OR _MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64" OR _MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64")
+ set(CMAKE_C_STANDARD_LIBRARIES_INIT "kernel32.lib user32.lib")
+ else()
+ set(CMAKE_C_STANDARD_LIBRARIES_INIT "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib")
+ endif()
+else()
+ set(_PLATFORM_DEFINES "/DWIN32")
+ if((_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64EC") OR (_MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64EC"))
+ set(_PLATFORM_DEFINES "${_PLATFORM_DEFINES} /D_AMD64_ /DAMD64 /D_ARM64EC_ /DARM64EC /D_ARM64EC_WORKAROUND_")
+ endif()
+ if(_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM" OR _MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM")
+ set(CMAKE_C_STANDARD_LIBRARIES_INIT "kernel32.lib user32.lib")
+ elseif(MSVC_VERSION GREATER 1310)
+ if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
+ # Clang/C2 in MSVC14 Update 1 seems to not support -fsantinize (yet?)
+ # set(_RTC1 "-fsantinize=memory,safe-stack")
+ set(_FLAGS_CXX " -frtti -fexceptions")
+ else()
+ set(_RTC1 "/RTC1")
+ set(_FLAGS_CXX "${_GR} /EHsc")
+ endif()
+ set(CMAKE_C_STANDARD_LIBRARIES_INIT "kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib")
+ else()
+ set(_RTC1 "/GZ")
+ set(_FLAGS_CXX "${_GR} /GX")
+ set(CMAKE_C_STANDARD_LIBRARIES_INIT "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib")
+ endif()
+
+ if(MSVC_VERSION LESS 1310)
+ set(_FLAGS_C " /Zm1000${_FLAGS_C}")
+ set(_FLAGS_CXX " /Zm1000${_FLAGS_CXX}")
+ endif()
+endif()
+
+unset(_GR)
+
+set(CMAKE_CXX_STANDARD_LIBRARIES_INIT "${CMAKE_C_STANDARD_LIBRARIES_INIT}")
+
+# executable linker flags
+set (CMAKE_LINK_DEF_FILE_FLAG "/DEF:")
+# set the machine type
+if(MSVC_C_ARCHITECTURE_ID)
+ if(MSVC_C_ARCHITECTURE_ID MATCHES "^ARMV.I")
+ set(_MACHINE_ARCH_FLAG "/machine:THUMB")
+ elseif(_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64")
+ set(_MACHINE_ARCH_FLAG "/machine:ARM64")
+ elseif(_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64EC")
+ set(_MACHINE_ARCH_FLAG "/machine:ARM64EC")
+ elseif(_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM")
+ set(_MACHINE_ARCH_FLAG "/machine:ARM")
+ else()
+ set(_MACHINE_ARCH_FLAG "/machine:${MSVC_C_ARCHITECTURE_ID}")
+ endif()
+elseif(MSVC_CXX_ARCHITECTURE_ID)
+ if(MSVC_CXX_ARCHITECTURE_ID MATCHES "^ARMV.I")
+ set(_MACHINE_ARCH_FLAG "/machine:THUMB")
+ elseif(_MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64")
+ set(_MACHINE_ARCH_FLAG "/machine:ARM64")
+ elseif(_MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64EC")
+ set(_MACHINE_ARCH_FLAG "/machine:ARM64EC")
+ elseif(_MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM")
+ set(_MACHINE_ARCH_FLAG "/machine:ARM")
+ else()
+ set(_MACHINE_ARCH_FLAG "/machine:${MSVC_CXX_ARCHITECTURE_ID}")
+ endif()
+elseif(MSVC_Fortran_ARCHITECTURE_ID)
+ set(_MACHINE_ARCH_FLAG "/machine:${MSVC_Fortran_ARCHITECTURE_ID}")
+endif()
+
+# add /debug and /INCREMENTAL:YES to DEBUG and RELWITHDEBINFO also add pdbtype
+# on versions that support it
+set( MSVC_INCREMENTAL_YES_FLAG "")
+if(NOT WINDOWS_PHONE AND NOT WINDOWS_STORE)
+ if(NOT MSVC_INCREMENTAL_DEFAULT)
+ set( MSVC_INCREMENTAL_YES_FLAG "/INCREMENTAL:YES")
+ else()
+ set( MSVC_INCREMENTAL_YES_FLAG "/INCREMENTAL" )
+ endif()
+endif()
+
+foreach(t EXE SHARED MODULE)
+ string(APPEND CMAKE_${t}_LINKER_FLAGS_INIT " ${_MACHINE_ARCH_FLAG}")
+ if (CMAKE_COMPILER_SUPPORTS_PDBTYPE)
+ string(APPEND CMAKE_${t}_LINKER_FLAGS_DEBUG_INIT " /debug /pdbtype:sept ${MSVC_INCREMENTAL_YES_FLAG}")
+ string(APPEND CMAKE_${t}_LINKER_FLAGS_RELWITHDEBINFO_INIT " /debug /pdbtype:sept ${MSVC_INCREMENTAL_YES_FLAG}")
+ else ()
+ string(APPEND CMAKE_${t}_LINKER_FLAGS_DEBUG_INIT " /debug ${MSVC_INCREMENTAL_YES_FLAG}")
+ string(APPEND CMAKE_${t}_LINKER_FLAGS_RELWITHDEBINFO_INIT " /debug ${MSVC_INCREMENTAL_YES_FLAG}")
+ endif ()
+ # for release and minsize release default to no incremental linking
+ string(APPEND CMAKE_${t}_LINKER_FLAGS_MINSIZEREL_INIT " /INCREMENTAL:NO")
+ string(APPEND CMAKE_${t}_LINKER_FLAGS_RELEASE_INIT " /INCREMENTAL:NO")
+endforeach()
+
+if((_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64EC") OR (_MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64EC"))
+ string(APPEND CMAKE_STATIC_LINKER_FLAGS_INIT " /machine:ARM64X")
+else()
+ string(APPEND CMAKE_STATIC_LINKER_FLAGS_INIT " ${_MACHINE_ARCH_FLAG}")
+endif()
+unset(_MACHINE_ARCH_FLAG)
+
+cmake_policy(GET CMP0091 __WINDOWS_MSVC_CMP0091)
+if(__WINDOWS_MSVC_CMP0091 STREQUAL "NEW")
+ set(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
+else()
+ set(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT "")
+endif()
+unset(__WINDOWS_MSVC_CMP0091)
+
+macro(__windows_compiler_msvc lang)
+ if(NOT MSVC_VERSION LESS 1400)
+ # for 2005 make sure the manifest is put in the dll with mt
+ set(_CMAKE_VS_LINK_DLL "<CMAKE_COMMAND> -E vs_link_dll --intdir=<OBJECT_DIR> --rc=<CMAKE_RC_COMPILER> --mt=<CMAKE_MT> --manifests <MANIFESTS> -- ")
+ set(_CMAKE_VS_LINK_EXE "<CMAKE_COMMAND> -E vs_link_exe --intdir=<OBJECT_DIR> --rc=<CMAKE_RC_COMPILER> --mt=<CMAKE_MT> --manifests <MANIFESTS> -- ")
+ endif()
+ set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
+ "${_CMAKE_VS_LINK_DLL}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /dll /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
+
+ set(CMAKE_${lang}_CREATE_SHARED_MODULE ${CMAKE_${lang}_CREATE_SHARED_LIBRARY})
+ set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "<CMAKE_AR> ${CMAKE_CL_NOLOGO} <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
+
+ set(CMAKE_${lang}_COMPILE_OBJECT
+ "<CMAKE_${lang}_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO}${_COMPILE_${lang}} <DEFINES> <INCLUDES> <FLAGS> /Fo<OBJECT> /Fd<TARGET_COMPILE_PDB>${_FS_${lang}} -c <SOURCE>${CMAKE_END_TEMP_FILE}")
+ set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE
+ "<CMAKE_${lang}_COMPILER> > <PREPROCESSED_SOURCE> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO}${_COMPILE_${lang}} <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE>${CMAKE_END_TEMP_FILE}")
+ set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE
+ "<CMAKE_${lang}_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO}${_COMPILE_${lang}} <DEFINES> <INCLUDES> <FLAGS> /FoNUL /FAs /Fa<ASSEMBLY_SOURCE> /c <SOURCE>${CMAKE_END_TEMP_FILE}")
+
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_OBJECTS 1)
+ set(CMAKE_${lang}_LINK_EXECUTABLE
+ "${_CMAKE_VS_LINK_EXE}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
+
+ if(CMAKE_SYSTEM_NAME STREQUAL "WindowsCE")
+ set(CMAKE_${lang}_CREATE_WIN32_EXE "/entry:WinMainCRTStartup")
+ set(CMAKE_${lang}_CREATE_CONSOLE_EXE "/entry:mainACRTStartup")
+ else()
+ set(CMAKE_${lang}_CREATE_WIN32_EXE "/subsystem:windows")
+ set(CMAKE_${lang}_CREATE_CONSOLE_EXE "/subsystem:console")
+ endif()
+
+ set(CMAKE_PCH_EXTENSION .pch)
+ set(CMAKE_LINK_PCH ON)
+ if (CMAKE_${lang}_COMPILER_ID STREQUAL "Clang")
+ set(CMAKE_PCH_PROLOGUE "#pragma clang system_header")
+
+ # macOS paths usually start with /Users/*. Unfortunately, clang-cl interprets
+ # paths starting with /U as macro undefines, so we need to put a -- before the
+ # input file path to force it to be treated as a path.
+ string(REPLACE "-c <SOURCE>" "-c -- <SOURCE>" CMAKE_${lang}_COMPILE_OBJECT "${CMAKE_${lang}_COMPILE_OBJECT}")
+ string(REPLACE "-c <SOURCE>" "-c -- <SOURCE>" CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "${CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE}")
+ string(REPLACE "-c <SOURCE>" "-c -- <SOURCE>" CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "${CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE}")
+
+ elseif(MSVC_VERSION GREATER_EQUAL 1913)
+ # At least MSVC toolet 14.13 from VS 2017 15.6
+ set(CMAKE_PCH_PROLOGUE "#pragma system_header")
+ endif()
+ if (NOT ${CMAKE_${lang}_COMPILER_ID} STREQUAL "Clang")
+ set(CMAKE_PCH_COPY_COMPILE_PDB ON)
+ endif()
+ set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH /Yu<PCH_HEADER> /Fp<PCH_FILE> /FI<PCH_HEADER>)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH /Yc<PCH_HEADER> /Fp<PCH_FILE> /FI<PCH_HEADER>)
+
+ if("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xMSVC")
+ set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
+ set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
+
+ set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "/GL")
+ set(CMAKE_${lang}_LINK_OPTIONS_IPO "/INCREMENTAL:NO" "/LTCG")
+ string(REPLACE "<LINK_FLAGS> " "/LTCG <LINK_FLAGS> "
+ CMAKE_${lang}_CREATE_STATIC_LIBRARY_IPO "${CMAKE_${lang}_CREATE_STATIC_LIBRARY}")
+ elseif("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xClang" OR
+ "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xFlang")
+ set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
+ set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
+
+ # '-flto=thin' available since Clang 3.9 and Xcode 8
+ # * http://clang.llvm.org/docs/ThinLTO.html#clang-llvm
+ # * https://trac.macports.org/wiki/XcodeVersionInfo
+ set(_CMAKE_LTO_THIN TRUE)
+ if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.9)
+ set(_CMAKE_LTO_THIN FALSE)
+ endif()
+
+ if(_CMAKE_LTO_THIN)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto=thin")
+ else()
+ set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto")
+ endif()
+ endif()
+
+ if("x${lang}" STREQUAL "xC" OR
+ "x${lang}" STREQUAL "xCXX")
+ if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+ set(_MDd "")
+ set(_MD "")
+ else()
+ set(_MDd " /MDd")
+ set(_MD " /MD")
+ endif()
+
+ cmake_policy(GET CMP0092 _cmp0092)
+ if(_cmp0092 STREQUAL "NEW")
+ set(_W3 "")
+ set(_Wall "")
+ else()
+ set(_W3 " /W3")
+ set(_Wall " -Wall")
+ endif()
+ unset(_cmp0092)
+
+ if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
+ # note: MSVC 14 2015 Update 1 sets -fno-ms-compatibility by default, but this does not allow one to compile many projects
+ # that include MS's own headers. CMake itself is affected project too.
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_${lang}} -fms-extensions -fms-compatibility -D_WINDOWS${_Wall}${_FLAGS_${lang}}")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT "${_MDd} -gline-tables-only -fno-inline -O0 ${_RTC1}")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT "${_MD} -O2 -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT "${_MD} -gline-tables-only -O2 -fno-inline -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "${_MD} -DNDEBUG") # TODO: Add '-Os' once VS generator maps it properly for Clang
+ else()
+ string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_${lang}} /D_WINDOWS${_W3}${_FLAGS_${lang}}")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT "${_MDd} /Zi /Ob0 /Od ${_RTC1}")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT "${_MD} /O2 /Ob2 /DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT "${_MD} /Zi /O2 /Ob1 /DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "${_MD} /O1 /Ob1 /DNDEBUG")
+ endif()
+ unset(_Wall)
+ unset(_W3)
+ unset(_MDd)
+ unset(_MD)
+
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -MT)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -MD)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -MTd)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -MDd)
+ endif()
+ set(CMAKE_${lang}_LINKER_SUPPORTS_PDB ON)
+
+ __windows_compiler_msvc_enable_rc("${_PLATFORM_DEFINES} ${_PLATFORM_DEFINES_${lang}}")
+
+ # define generic information about compiler dependencies
+ if (MSVC_VERSION GREATER 1300)
+ set(CMAKE_DEPFILE_FLAGS_${lang} "/showIncludes")
+ set(CMAKE_${lang}_DEPFILE_FORMAT msvc)
+ endif()
+endmacro()
+
+macro(__windows_compiler_msvc_enable_rc flags)
+ if(NOT CMAKE_RC_COMPILER_INIT)
+ set(CMAKE_RC_COMPILER_INIT rc)
+ endif()
+ if(NOT CMAKE_RC_FLAGS_INIT)
+ # llvm-rc fails when flags are specified with /D and no space after
+ string(REPLACE " /D" " -D" fixed_flags " ${flags}")
+ string(APPEND CMAKE_RC_FLAGS_INIT " ${fixed_flags}")
+ endif()
+ if(NOT CMAKE_RC_FLAGS_DEBUG_INIT)
+ string(APPEND CMAKE_RC_FLAGS_DEBUG_INIT " -D_DEBUG")
+ endif()
+
+ enable_language(RC)
+ if(NOT DEFINED CMAKE_NINJA_CMCLDEPS_RC)
+ set(CMAKE_NINJA_CMCLDEPS_RC 1)
+ endif()
+endmacro()
diff --git a/Modules/Platform/Windows-NVIDIA-CUDA.cmake b/Modules/Platform/Windows-NVIDIA-CUDA.cmake
new file mode 100644
index 0000000..b83932e
--- /dev/null
+++ b/Modules/Platform/Windows-NVIDIA-CUDA.cmake
@@ -0,0 +1,88 @@
+include(Platform/Windows-MSVC)
+
+set(CMAKE_CUDA_COMPILE_PTX_COMPILATION
+ "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> ${_CMAKE_COMPILE_AS_CUDA_FLAG} -ptx <SOURCE> -o <OBJECT> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS")
+set(CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION
+ "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> ${_CMAKE_COMPILE_AS_CUDA_FLAG} -dc <SOURCE> -o <OBJECT> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS")
+set(CMAKE_CUDA_COMPILE_WHOLE_COMPILATION
+ "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> ${_CMAKE_COMPILE_AS_CUDA_FLAG} -c <SOURCE> -o <OBJECT> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS")
+
+set(__IMPLICIT_LINKS)
+foreach(dir ${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES})
+ string(APPEND __IMPLICIT_LINKS " -LIBPATH:\"${dir}\"")
+endforeach()
+foreach(lib ${CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES})
+ string(APPEND __IMPLICIT_LINKS " \"${lib}\"")
+endforeach()
+set(CMAKE_CUDA_LINK_EXECUTABLE
+ "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <LINK_FLAGS> <OBJECTS> /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
+
+set(_CMAKE_VS_LINK_DLL "<CMAKE_COMMAND> -E vs_link_dll --intdir=<OBJECT_DIR> --rc=<CMAKE_RC_COMPILER> --mt=<CMAKE_MT> --manifests <MANIFESTS> -- ")
+set(_CMAKE_VS_LINK_EXE "<CMAKE_COMMAND> -E vs_link_exe --intdir=<OBJECT_DIR> --rc=<CMAKE_RC_COMPILER> --mt=<CMAKE_MT> --manifests <MANIFESTS> -- ")
+set(CMAKE_CUDA_CREATE_SHARED_LIBRARY
+ "${_CMAKE_VS_LINK_DLL}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /dll /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES>${__IMPLICIT_LINKS} ${CMAKE_END_TEMP_FILE}")
+
+set(CMAKE_CUDA_CREATE_SHARED_MODULE ${CMAKE_CUDA_CREATE_SHARED_LIBRARY})
+set(CMAKE_CUDA_CREATE_STATIC_LIBRARY "<CMAKE_AR> ${CMAKE_CL_NOLOGO} <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
+set(CMAKE_CUDA_LINKER_SUPPORTS_PDB ON)
+set(CMAKE_CUDA_LINK_EXECUTABLE
+ "${_CMAKE_VS_LINK_EXE}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES>${__IMPLICIT_LINKS} ${CMAKE_END_TEMP_FILE}")
+unset(_CMAKE_VS_LINK_DLL)
+unset(_CMAKE_VS_LINK_EXE)
+
+
+# Add implicit host link directories that contain device libraries
+# to the device link line.
+set(__IMPLICIT_DLINK_DIRS ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+if(__IMPLICIT_DLINK_DIRS)
+ list(REMOVE_ITEM __IMPLICIT_DLINK_DIRS ${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES})
+endif()
+set(__IMPLICIT_DLINK_FLAGS)
+foreach(dir ${__IMPLICIT_DLINK_DIRS})
+ if(EXISTS "${dir}/curand_static.lib")
+ string(APPEND __IMPLICIT_DLINK_FLAGS " -L\"${dir}\"")
+ endif()
+endforeach()
+unset(__IMPLICIT_DLINK_DIRS)
+
+set(CMAKE_CUDA_DEVICE_LINK_LIBRARY
+ "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICIT_DLINK_FLAGS}")
+set(CMAKE_CUDA_DEVICE_LINK_EXECUTABLE
+ "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICIT_DLINK_FLAGS}")
+unset(__IMPLICIT_DLINK_FLAGS)
+
+string(REPLACE "/D" "-D" _PLATFORM_DEFINES_CUDA "${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_CXX}")
+
+if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+ set(_MDd "")
+ set(_MD "")
+else()
+ set(_MDd "-MDd ")
+ set(_MD "-MD ")
+endif()
+
+cmake_policy(GET CMP0092 _cmp0092)
+if(_cmp0092 STREQUAL "NEW")
+ set(_W3 "")
+else()
+ set(_W3 "/W3")
+endif()
+unset(_cmp0092)
+
+string(APPEND CMAKE_CUDA_FLAGS_INIT " ${PLATFORM_DEFINES_CUDA} -D_WINDOWS -Xcompiler=\"${_W3}${_FLAGS_CXX}\"")
+string(APPEND CMAKE_CUDA_FLAGS_DEBUG_INIT " -Xcompiler=\"${_MDd}-Zi -Ob0 -Od ${_RTC1}\"")
+string(APPEND CMAKE_CUDA_FLAGS_RELEASE_INIT " -Xcompiler=\"${_MD}-O2 -Ob2\" -DNDEBUG")
+string(APPEND CMAKE_CUDA_FLAGS_RELWITHDEBINFO_INIT " -Xcompiler=\"${_MD}-Zi -O2 -Ob1\" -DNDEBUG")
+string(APPEND CMAKE_CUDA_FLAGS_MINSIZEREL_INIT " -Xcompiler=\"${_MD}-O1 -Ob1\" -DNDEBUG")
+unset(_W3)
+unset(_MDd)
+unset(_MD)
+
+set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -Xcompiler=-MT)
+set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -Xcompiler=-MD)
+set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -Xcompiler=-MTd)
+set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -Xcompiler=-MDd)
+
+set(CMAKE_CUDA_STANDARD_LIBRARIES_INIT "${CMAKE_C_STANDARD_LIBRARIES_INIT}")
+
+__windows_compiler_msvc_enable_rc("${_PLATFORM_DEFINES} ${_PLATFORM_DEFINES_CXX}")
diff --git a/Modules/Platform/Windows-OpenWatcom-C.cmake b/Modules/Platform/Windows-OpenWatcom-C.cmake
new file mode 100644
index 0000000..b82a4cb
--- /dev/null
+++ b/Modules/Platform/Windows-OpenWatcom-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows-OpenWatcom)
+__windows_open_watcom(C)
diff --git a/Modules/Platform/Windows-OpenWatcom-CXX.cmake b/Modules/Platform/Windows-OpenWatcom-CXX.cmake
new file mode 100644
index 0000000..ac90d28
--- /dev/null
+++ b/Modules/Platform/Windows-OpenWatcom-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows-OpenWatcom)
+__windows_open_watcom(CXX)
diff --git a/Modules/Platform/Windows-OpenWatcom.cmake b/Modules/Platform/Windows-OpenWatcom.cmake
new file mode 100644
index 0000000..19bcb97
--- /dev/null
+++ b/Modules/Platform/Windows-OpenWatcom.cmake
@@ -0,0 +1,35 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+set(CMAKE_BUILD_TYPE_INIT Debug)
+
+string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " system nt_dll")
+string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " system nt_dll")
+
+set(CMAKE_C_COMPILE_OPTIONS_DLL "-bd") # Note: This variable is a ';' separated list
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-bd") # ... while this is a space separated string.
+
+set(CMAKE_RC_COMPILER "rc" )
+
+# single/multi-threaded /-bm
+# static/DLL run-time libraries /-br
+# default is setup for multi-threaded + DLL run-time libraries
+string(APPEND CMAKE_C_FLAGS_INIT " -bt=nt -dWIN32 -br -bm")
+string(APPEND CMAKE_CXX_FLAGS_INIT " -bt=nt -xs -dWIN32 -br -bm")
+
+if(CMAKE_CROSSCOMPILING)
+ if(NOT CMAKE_C_STANDARD_INCLUDE_DIRECTORIES)
+ set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/nt)
+ endif()
+ if(NOT CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES)
+ set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/nt)
+ endif()
+endif()
+
+macro(__windows_open_watcom lang)
+ set(CMAKE_${lang}_CREATE_WIN32_EXE "system nt_win")
+ set(CMAKE_${lang}_CREATE_CONSOLE_EXE "system nt")
+endmacro()
diff --git a/Modules/Platform/Windows-PGI-C.cmake b/Modules/Platform/Windows-PGI-C.cmake
new file mode 100644
index 0000000..0495b93
--- /dev/null
+++ b/Modules/Platform/Windows-PGI-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows-PGI)
+__windows_compiler_pgi(C)
diff --git a/Modules/Platform/Windows-PGI-Fortran.cmake b/Modules/Platform/Windows-PGI-Fortran.cmake
new file mode 100644
index 0000000..2222e33
--- /dev/null
+++ b/Modules/Platform/Windows-PGI-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows-PGI)
+__windows_compiler_pgi(Fortran)
diff --git a/Modules/Platform/Windows-PGI.cmake b/Modules/Platform/Windows-PGI.cmake
new file mode 100644
index 0000000..8166240
--- /dev/null
+++ b/Modules/Platform/Windows-PGI.cmake
@@ -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.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__WINDOWS_COMPILER_PGI)
+ return()
+endif()
+set(__WINDOWS_COMPILER_PGI 1)
+
+# PGI on Windows doesn't support parallel compile processes
+if(NOT DEFINED CMAKE_JOB_POOL_LINK OR NOT DEFINED CMAKE_JOB_POOL_COMPILE OR NOT DEFINED CMAKE_JOB_POOL_PRECOMPILE_HEADER)
+ set(CMAKE_JOB_POOL_LINK PGITaskPool)
+ set(CMAKE_JOB_POOL_COMPILE PGITaskPool)
+ set(CMAKE_JOB_POOL_PRECOMPILE_HEADER PGITaskPool)
+ get_property(_pgijp GLOBAL PROPERTY JOB_POOLS)
+ if(NOT _pgijp MATCHES "PGITaskPool=")
+ set_property(GLOBAL APPEND PROPERTY JOB_POOLS PGITaskPool=1)
+ endif()
+ unset(_pgijp)
+endif()
+
+set(CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS 1)
+set(CMAKE_LINK_DEF_FILE_FLAG "-def:")
+# The link flags for PGI are the raw filename to add a file
+# and the UNIX -L syntax to link directories.
+set(CMAKE_LINK_LIBRARY_FLAG "")
+set(CMAKE_LINK_STARTFILE "pgimain[mx][xpt]+[.]obj")
+
+# Default to Debug builds, mirroring Windows-MSVC behavior
+set(CMAKE_BUILD_TYPE_INIT Debug)
+
+if(CMAKE_VERBOSE_MAKEFILE)
+ set(CMAKE_CL_NOLOGO)
+else()
+ set(CMAKE_CL_NOLOGO "/nologo")
+endif()
+
+macro(__windows_compiler_pgi lang)
+ # Shared library compile and link rules.
+ set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "lib ${CMAKE_CL_NOLOGO} <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
+ set(CMAKE_${lang}_CREATE_SHARED_LIBRARY "<CMAKE_${lang}_COMPILER> ${CMAKE_START_TEMP_FILE} -Mmakedll -implib:<TARGET_IMPLIB> -Xlinker -pdb:<TARGET_PDB> -Xlinker -version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <LINK_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
+ set(CMAKE_${lang}_CREATE_SHARED_MODULE "${CMAKE_${lang}_CREATE_SHARED_LIBRARY}")
+ set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_${lang}_COMPILER> ${CMAKE_START_TEMP_FILE} -implib:<TARGET_IMPLIB> -Xlinker -pdb:<TARGET_PDB> -Xlinker -version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
+
+ if("${lang}" MATCHES "C|CXX")
+ set(CMAKE_${lang}_STANDARD_LIBRARIES_INIT "kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib")
+ endif()
+endmacro()
diff --git a/Modules/Platform/Windows-Watcom-C.cmake b/Modules/Platform/Windows-Watcom-C.cmake
new file mode 100644
index 0000000..44a008b
--- /dev/null
+++ b/Modules/Platform/Windows-Watcom-C.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-OpenWatcom-C)
diff --git a/Modules/Platform/Windows-Watcom-CXX.cmake b/Modules/Platform/Windows-Watcom-CXX.cmake
new file mode 100644
index 0000000..63d109b
--- /dev/null
+++ b/Modules/Platform/Windows-Watcom-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-OpenWatcom-CXX)
diff --git a/Modules/Platform/Windows-df.cmake b/Modules/Platform/Windows-df.cmake
new file mode 100644
index 0000000..c823423
--- /dev/null
+++ b/Modules/Platform/Windows-df.cmake
@@ -0,0 +1,60 @@
+# compiler support for fortran CVF compiler on windows
+
+set(CMAKE_WINDOWS_OBJECT_PATH 1)
+set(CMAKE_LIBRARY_PATH_FLAG "-LIBPATH:")
+set(CMAKE_LINK_LIBRARY_FLAG "")
+set(WIN32 1)
+if(CMAKE_VERBOSE_MAKEFILE)
+ set(CMAKE_CL_NOLOGO)
+else()
+ set(CMAKE_CL_NOLOGO "/nologo")
+endif()
+
+set(CMAKE_Fortran_MODDIR_FLAG "-module:")
+
+set(CMAKE_Fortran_CREATE_SHARED_LIBRARY
+ "link ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} /out:<TARGET> /dll <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
+
+set(CMAKE_Fortran_CREATE_SHARED_MODULE ${CMAKE_Fortran_CREATE_SHARED_LIBRARY})
+
+# create a C++ static library
+set(CMAKE_Fortran_CREATE_STATIC_LIBRARY "lib ${CMAKE_CL_NOLOGO} <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
+
+# compile a C++ file into an object file
+set(CMAKE_Fortran_COMPILE_OBJECT
+ "<CMAKE_Fortran_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /object:<OBJECT> <FLAGS> /compile_only <SOURCE>${CMAKE_END_TEMP_FILE}")
+
+set(CMAKE_Fortran_LINK_EXECUTABLE
+ "<CMAKE_Fortran_COMPILER> ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} <FLAGS> /exe:<TARGET> <OBJECTS> /link <CMAKE_Fortran_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
+
+set(CMAKE_Fortran_CREATE_WIN32_EXE /winapp)
+set(CMAKE_Fortran_CREATE_CONSOLE_EXE )
+
+# does the compiler support pdbtype and is it the newer compiler
+
+set(CMAKE_BUILD_TYPE_INIT Debug)
+set (CMAKE_Fortran_FLAGS_INIT "")
+set (CMAKE_Fortran_FLAGS_DEBUG_INIT "/debug:full")
+set (CMAKE_Fortran_FLAGS_MINSIZEREL_INIT "/Optimize:2 /Define:NDEBUG")
+set (CMAKE_Fortran_FLAGS_RELEASE_INIT "/Optimize:1 /Define:NDEBUG")
+set (CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT "/Optimize:1 /debug:full /Define:NDEBUG")
+
+set (CMAKE_Fortran_STANDARD_LIBRARIES_INIT "user32.lib")
+
+# executable linker flags
+set (CMAKE_LINK_DEF_FILE_FLAG "/DEF:")
+set (CMAKE_EXE_LINKER_FLAGS_INIT " /INCREMENTAL:YES")
+if (CMAKE_COMPILER_SUPPORTS_PDBTYPE)
+ set (CMAKE_EXE_LINKER_FLAGS_DEBUG_INIT "/debug /pdbtype:sept")
+ set (CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO_INIT "/debug /pdbtype:sept")
+else ()
+ set (CMAKE_EXE_LINKER_FLAGS_DEBUG_INIT "/debug")
+ set (CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO_INIT "/debug")
+endif ()
+
+set (CMAKE_SHARED_LINKER_FLAGS_INIT ${CMAKE_EXE_LINKER_FLAGS_INIT})
+set (CMAKE_SHARED_LINKER_FLAGS_DEBUG_INIT ${CMAKE_EXE_LINKER_FLAGS_DEBUG_INIT})
+set (CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO_INIT ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO_INIT})
+set (CMAKE_MODULE_LINKER_FLAGS_INIT ${CMAKE_SHARED_LINKER_FLAGS_INIT})
+set (CMAKE_MODULE_LINKER_FLAGS_DEBUG_INIT ${CMAKE_SHARED_LINKER_FLAGS_DEBUG_INIT})
+set (CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO_INIT ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO_INIT})
diff --git a/Modules/Platform/Windows-windres.cmake b/Modules/Platform/Windows-windres.cmake
new file mode 100644
index 0000000..7d787dd
--- /dev/null
+++ b/Modules/Platform/Windows-windres.cmake
@@ -0,0 +1 @@
+set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> -O coff <DEFINES> <INCLUDES> <FLAGS> <SOURCE> <OBJECT>")
diff --git a/Modules/Platform/Windows.cmake b/Modules/Platform/Windows.cmake
new file mode 100644
index 0000000..d8b3957
--- /dev/null
+++ b/Modules/Platform/Windows.cmake
@@ -0,0 +1,45 @@
+set(WIN32 1)
+
+if(CMAKE_SYSTEM_NAME STREQUAL "WindowsCE")
+ set(WINCE 1)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone")
+ set(WINDOWS_PHONE 1)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
+ set(WINDOWS_STORE 1)
+endif()
+
+set(CMAKE_STATIC_LIBRARY_PREFIX "")
+set(CMAKE_STATIC_LIBRARY_SUFFIX ".lib")
+set(CMAKE_SHARED_LIBRARY_PREFIX "") # lib
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".dll") # .so
+set(CMAKE_IMPORT_LIBRARY_PREFIX "")
+set(CMAKE_IMPORT_LIBRARY_SUFFIX ".lib")
+set(CMAKE_EXECUTABLE_SUFFIX ".exe") # .exe
+set(CMAKE_LINK_LIBRARY_SUFFIX ".lib")
+set(CMAKE_DL_LIBS "")
+set(CMAKE_EXTRA_LINK_EXTENSIONS ".targets")
+
+set(CMAKE_FIND_LIBRARY_PREFIXES "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
+
+# for borland make long command lines are redirected to a file
+# with the following syntax, see Windows-bcc32.cmake for use
+if(CMAKE_GENERATOR MATCHES "Borland")
+ set(CMAKE_START_TEMP_FILE "@&&|\n")
+ set(CMAKE_END_TEMP_FILE "\n|")
+endif()
+
+# for nmake make long command lines are redirected to a file
+# with the following syntax, see Windows-bcc32.cmake for use
+if(CMAKE_GENERATOR MATCHES "NMake")
+ set(CMAKE_START_TEMP_FILE "@<<\n")
+ set(CMAKE_END_TEMP_FILE "\n<<")
+endif()
+
+include(Platform/WindowsPaths)
+
+# uncomment these out to debug nmake and borland makefiles
+#set(CMAKE_START_TEMP_FILE "")
+#set(CMAKE_END_TEMP_FILE "")
+#set(CMAKE_VERBOSE_MAKEFILE 1)
+
diff --git a/Modules/Platform/WindowsCE-MSVC-C.cmake b/Modules/Platform/WindowsCE-MSVC-C.cmake
new file mode 100644
index 0000000..ce8060b
--- /dev/null
+++ b/Modules/Platform/WindowsCE-MSVC-C.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-MSVC-C)
diff --git a/Modules/Platform/WindowsCE-MSVC-CXX.cmake b/Modules/Platform/WindowsCE-MSVC-CXX.cmake
new file mode 100644
index 0000000..281eadc
--- /dev/null
+++ b/Modules/Platform/WindowsCE-MSVC-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-MSVC-CXX)
diff --git a/Modules/Platform/WindowsCE.cmake b/Modules/Platform/WindowsCE.cmake
new file mode 100644
index 0000000..65b2eae
--- /dev/null
+++ b/Modules/Platform/WindowsCE.cmake
@@ -0,0 +1 @@
+include(Platform/Windows)
diff --git a/Modules/Platform/WindowsPaths.cmake b/Modules/Platform/WindowsPaths.cmake
new file mode 100644
index 0000000..b9e2f17
--- /dev/null
+++ b/Modules/Platform/WindowsPaths.cmake
@@ -0,0 +1,96 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# Block multiple inclusion because "CMakeCInformation.cmake" includes
+# "Platform/${CMAKE_SYSTEM_NAME}" even though the generic module
+# "CMakeSystemSpecificInformation.cmake" already included it.
+# The extra inclusion is a work-around documented next to the include()
+# call, so this can be removed when the work-around is removed.
+if(__WINDOWS_PATHS_INCLUDED)
+ return()
+endif()
+set(__WINDOWS_PATHS_INCLUDED 1)
+
+# Add the program-files folder(s) to the list of installation
+# prefixes.
+#
+# Windows 64-bit Binary:
+# ENV{ProgramFiles(x86)} = [C:\Program Files (x86)]
+# ENV{ProgramFiles} = [C:\Program Files]
+# ENV{ProgramW6432} = [C:\Program Files] or <not set>
+#
+# Windows 32-bit Binary on 64-bit Windows:
+# ENV{ProgramFiles(x86)} = [C:\Program Files (x86)]
+# ENV{ProgramFiles} = [C:\Program Files (x86)]
+# ENV{ProgramW6432} = [C:\Program Files]
+#
+# Reminder when adding new locations computed from environment variables
+# please make sure to keep Help/variable/CMAKE_SYSTEM_PREFIX_PATH.rst
+# synchronized
+set(_programfiles "")
+foreach(v "ProgramW6432" "ProgramFiles" "ProgramFiles(x86)")
+ if(DEFINED "ENV{${v}}")
+ file(TO_CMAKE_PATH "$ENV{${v}}" _env_programfiles)
+ list(APPEND _programfiles "${_env_programfiles}")
+ unset(_env_programfiles)
+ endif()
+endforeach()
+if(DEFINED "ENV{SystemDrive}")
+ foreach(d "Program Files" "Program Files (x86)")
+ if(EXISTS "$ENV{SystemDrive}/${d}")
+ list(APPEND _programfiles "$ENV{SystemDrive}/${d}")
+ endif()
+ endforeach()
+endif()
+if(_programfiles)
+ list(REMOVE_DUPLICATES _programfiles)
+ list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${_programfiles})
+endif()
+unset(_programfiles)
+
+# Add the CMake install location.
+get_filename_component(_CMAKE_INSTALL_DIR "${CMAKE_ROOT}" PATH)
+get_filename_component(_CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" PATH)
+list(APPEND CMAKE_SYSTEM_PREFIX_PATH "${_CMAKE_INSTALL_DIR}")
+
+if (NOT CMAKE_FIND_NO_INSTALL_PREFIX)
+ # Add other locations.
+ list(APPEND CMAKE_SYSTEM_PREFIX_PATH
+ # Project install destination.
+ "${CMAKE_INSTALL_PREFIX}"
+ )
+ if (CMAKE_STAGING_PREFIX)
+ list(APPEND CMAKE_SYSTEM_PREFIX_PATH
+ # User-supplied staging prefix.
+ "${CMAKE_STAGING_PREFIX}"
+ )
+ endif()
+endif()
+
+if(CMAKE_CROSSCOMPILING AND NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
+ # MinGW (useful when cross compiling from linux with CMAKE_FIND_ROOT_PATH set)
+ list(APPEND CMAKE_SYSTEM_PREFIX_PATH /)
+endif()
+
+list(APPEND CMAKE_SYSTEM_INCLUDE_PATH
+ )
+
+# mingw can also link against dlls which can also be in /bin, so list this too
+if (NOT CMAKE_FIND_NO_INSTALL_PREFIX)
+ list(APPEND CMAKE_SYSTEM_LIBRARY_PATH
+ "${CMAKE_INSTALL_PREFIX}/bin"
+ )
+ if (CMAKE_STAGING_PREFIX)
+ list(APPEND CMAKE_SYSTEM_LIBRARY_PATH
+ "${CMAKE_STAGING_PREFIX}/bin"
+ )
+ endif()
+endif()
+list(APPEND CMAKE_SYSTEM_LIBRARY_PATH
+ "${_CMAKE_INSTALL_DIR}/bin"
+ /bin
+ )
+
+list(APPEND CMAKE_SYSTEM_PROGRAM_PATH
+ )
diff --git a/Modules/Platform/WindowsPhone-Clang-ASM.cmake b/Modules/Platform/WindowsPhone-Clang-ASM.cmake
new file mode 100644
index 0000000..94f4ca7
--- /dev/null
+++ b/Modules/Platform/WindowsPhone-Clang-ASM.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-Clang-ASM)
diff --git a/Modules/Platform/WindowsPhone-Clang-C.cmake b/Modules/Platform/WindowsPhone-Clang-C.cmake
new file mode 100644
index 0000000..6e38572
--- /dev/null
+++ b/Modules/Platform/WindowsPhone-Clang-C.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-Clang-C)
diff --git a/Modules/Platform/WindowsPhone-Clang-CXX.cmake b/Modules/Platform/WindowsPhone-Clang-CXX.cmake
new file mode 100644
index 0000000..bf47978
--- /dev/null
+++ b/Modules/Platform/WindowsPhone-Clang-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-Clang-CXX)
diff --git a/Modules/Platform/WindowsPhone-GNU-ASM.cmake b/Modules/Platform/WindowsPhone-GNU-ASM.cmake
new file mode 100644
index 0000000..140eea7
--- /dev/null
+++ b/Modules/Platform/WindowsPhone-GNU-ASM.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-GNU-ASM)
diff --git a/Modules/Platform/WindowsPhone-GNU-C.cmake b/Modules/Platform/WindowsPhone-GNU-C.cmake
new file mode 100644
index 0000000..ff6acd5
--- /dev/null
+++ b/Modules/Platform/WindowsPhone-GNU-C.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-GNU-C)
diff --git a/Modules/Platform/WindowsPhone-GNU-CXX.cmake b/Modules/Platform/WindowsPhone-GNU-CXX.cmake
new file mode 100644
index 0000000..6adab6a
--- /dev/null
+++ b/Modules/Platform/WindowsPhone-GNU-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-GNU-CXX)
diff --git a/Modules/Platform/WindowsPhone-MSVC-C.cmake b/Modules/Platform/WindowsPhone-MSVC-C.cmake
new file mode 100644
index 0000000..ce8060b
--- /dev/null
+++ b/Modules/Platform/WindowsPhone-MSVC-C.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-MSVC-C)
diff --git a/Modules/Platform/WindowsPhone-MSVC-CXX.cmake b/Modules/Platform/WindowsPhone-MSVC-CXX.cmake
new file mode 100644
index 0000000..281eadc
--- /dev/null
+++ b/Modules/Platform/WindowsPhone-MSVC-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-MSVC-CXX)
diff --git a/Modules/Platform/WindowsPhone.cmake b/Modules/Platform/WindowsPhone.cmake
new file mode 100644
index 0000000..65b2eae
--- /dev/null
+++ b/Modules/Platform/WindowsPhone.cmake
@@ -0,0 +1 @@
+include(Platform/Windows)
diff --git a/Modules/Platform/WindowsStore-Clang-ASM.cmake b/Modules/Platform/WindowsStore-Clang-ASM.cmake
new file mode 100644
index 0000000..94f4ca7
--- /dev/null
+++ b/Modules/Platform/WindowsStore-Clang-ASM.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-Clang-ASM)
diff --git a/Modules/Platform/WindowsStore-Clang-C.cmake b/Modules/Platform/WindowsStore-Clang-C.cmake
new file mode 100644
index 0000000..6e38572
--- /dev/null
+++ b/Modules/Platform/WindowsStore-Clang-C.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-Clang-C)
diff --git a/Modules/Platform/WindowsStore-Clang-CXX.cmake b/Modules/Platform/WindowsStore-Clang-CXX.cmake
new file mode 100644
index 0000000..bf47978
--- /dev/null
+++ b/Modules/Platform/WindowsStore-Clang-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-Clang-CXX)
diff --git a/Modules/Platform/WindowsStore-GNU-ASM.cmake b/Modules/Platform/WindowsStore-GNU-ASM.cmake
new file mode 100644
index 0000000..140eea7
--- /dev/null
+++ b/Modules/Platform/WindowsStore-GNU-ASM.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-GNU-ASM)
diff --git a/Modules/Platform/WindowsStore-GNU-C.cmake b/Modules/Platform/WindowsStore-GNU-C.cmake
new file mode 100644
index 0000000..ff6acd5
--- /dev/null
+++ b/Modules/Platform/WindowsStore-GNU-C.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-GNU-C)
diff --git a/Modules/Platform/WindowsStore-GNU-CXX.cmake b/Modules/Platform/WindowsStore-GNU-CXX.cmake
new file mode 100644
index 0000000..6adab6a
--- /dev/null
+++ b/Modules/Platform/WindowsStore-GNU-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-GNU-CXX)
diff --git a/Modules/Platform/WindowsStore-MSVC-C.cmake b/Modules/Platform/WindowsStore-MSVC-C.cmake
new file mode 100644
index 0000000..ce8060b
--- /dev/null
+++ b/Modules/Platform/WindowsStore-MSVC-C.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-MSVC-C)
diff --git a/Modules/Platform/WindowsStore-MSVC-CXX.cmake b/Modules/Platform/WindowsStore-MSVC-CXX.cmake
new file mode 100644
index 0000000..281eadc
--- /dev/null
+++ b/Modules/Platform/WindowsStore-MSVC-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-MSVC-CXX)
diff --git a/Modules/Platform/WindowsStore.cmake b/Modules/Platform/WindowsStore.cmake
new file mode 100644
index 0000000..65b2eae
--- /dev/null
+++ b/Modules/Platform/WindowsStore.cmake
@@ -0,0 +1 @@
+include(Platform/Windows)
diff --git a/Modules/Platform/Xenix.cmake b/Modules/Platform/Xenix.cmake
new file mode 100644
index 0000000..47852f8
--- /dev/null
+++ b/Modules/Platform/Xenix.cmake
@@ -0,0 +1,2 @@
+include(Platform/UnixPaths)
+
diff --git a/Modules/Platform/eCos.cmake b/Modules/Platform/eCos.cmake
new file mode 100644
index 0000000..25db028
--- /dev/null
+++ b/Modules/Platform/eCos.cmake
@@ -0,0 +1,65 @@
+# support for eCos http://ecos.sourceware.org
+
+# Guard against multiple inclusion, which e.g. leads to multiple calls to add_definition() #12987
+if(__ECOS_CMAKE_INCLUDED)
+ return()
+endif()
+set(__ECOS_CMAKE_INCLUDED TRUE)
+
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "") # -pic
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "") # -shared
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # +s, flag for exe link to use shared lib
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "") # -rpath
+set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP "") # : or empty
+
+set(CMAKE_LINK_LIBRARY_SUFFIX "")
+set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
+set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
+set(CMAKE_SHARED_LIBRARY_PREFIX "lib") # lib
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".a") # .a
+set(CMAKE_EXECUTABLE_SUFFIX ".elf") # same suffix as if built using UseEcos.cmake
+set(CMAKE_DL_LIBS "" )
+
+set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
+
+
+include(Platform/UnixPaths)
+
+# eCos can be built only with gcc
+get_property(_IN_TC GLOBAL PROPERTY IN_TRY_COMPILE)
+if(CMAKE_C_COMPILER AND NOT CMAKE_C_COMPILER_ID MATCHES "GNU" AND NOT _IN_TC)
+ message(FATAL_ERROR "GNU gcc is required for eCos")
+endif()
+if(CMAKE_CXX_COMPILER AND NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU" AND NOT _IN_TC)
+ message(FATAL_ERROR "GNU g++ is required for eCos")
+endif()
+
+# find eCos system files
+find_path(ECOS_SYSTEM_CONFIG_HEADER_PATH NAMES pkgconf/system.h)
+find_library(ECOS_SYSTEM_TARGET_LIBRARY NAMES libtarget.a)
+
+if(NOT ECOS_SYSTEM_CONFIG_HEADER_PATH)
+ message(FATAL_ERROR "Could not find eCos pkgconf/system.h. Build eCos first and set up CMAKE_FIND_ROOT_PATH correctly.")
+endif()
+
+if(NOT ECOS_SYSTEM_TARGET_LIBRARY)
+ message(FATAL_ERROR "Could not find eCos \"libtarget.a\". Build eCos first and set up CMAKE_FIND_ROOT_PATH correctly.")
+endif()
+
+get_filename_component(ECOS_LIBTARGET_DIRECTORY "${ECOS_SYSTEM_TARGET_LIBRARY}" PATH)
+include_directories(${ECOS_SYSTEM_CONFIG_HEADER_PATH})
+add_definitions(-D__ECOS__=1 -D__ECOS=1)
+
+# special link commands for eCos executables
+set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -nostdlib -nostartfiles -L${ECOS_LIBTARGET_DIRECTORY} -Ttarget.ld <LINK_LIBRARIES>")
+set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -nostdlib -nostartfiles -L${ECOS_LIBTARGET_DIRECTORY} -Ttarget.ld <LINK_LIBRARIES>")
+
+# eCos doesn't support shared libs
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
+
+set(CMAKE_CXX_LINK_SHARED_LIBRARY )
+set(CMAKE_CXX_LINK_MODULE_LIBRARY )
+set(CMAKE_C_LINK_SHARED_LIBRARY )
+set(CMAKE_C_LINK_MODULE_LIBRARY )
+
diff --git a/Modules/Platform/gas.cmake b/Modules/Platform/gas.cmake
new file mode 100644
index 0000000..8484076
--- /dev/null
+++ b/Modules/Platform/gas.cmake
@@ -0,0 +1,19 @@
+if(UNIX)
+ set(CMAKE_ASM${ASM_DIALECT}_OUTPUT_EXTENSION .o)
+else()
+ set(CMAKE_ASM${ASM_DIALECT}_OUTPUT_EXTENSION .obj)
+endif()
+
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <INCLUDES> <FLAGS> -o <OBJECT> <SOURCE>")
+
+set(CMAKE_ASM${ASM_DIALECT}_CREATE_STATIC_LIBRARY
+ "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS> "
+ "<CMAKE_RANLIB> <TARGET> ")
+
+set(CMAKE_ASM${ASM_DIALECT}_LINK_EXECUTABLE
+ "<CMAKE_LINKER> <FLAGS> <CMAKE_ASM${ASM_DIALECT}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+
+# to be done
+set(CMAKE_ASM${ASM_DIALECT}_CREATE_SHARED_LIBRARY)
+set(CMAKE_ASM${ASM_DIALECT}_CREATE_SHARED_MODULE)
+
diff --git a/Modules/Platform/iOS-Determine-CXX.cmake b/Modules/Platform/iOS-Determine-CXX.cmake
new file mode 100644
index 0000000..ac80fa6
--- /dev/null
+++ b/Modules/Platform/iOS-Determine-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Darwin-Determine-CXX)
diff --git a/Modules/Platform/iOS-Initialize.cmake b/Modules/Platform/iOS-Initialize.cmake
new file mode 100644
index 0000000..301ca4c
--- /dev/null
+++ b/Modules/Platform/iOS-Initialize.cmake
@@ -0,0 +1,9 @@
+include(Platform/Darwin-Initialize)
+
+if(NOT _CMAKE_OSX_SYSROOT_PATH MATCHES "/iPhone(OS|Simulator)")
+ message(FATAL_ERROR "${CMAKE_OSX_SYSROOT} is not an iOS SDK")
+endif()
+
+set(IOS 1)
+
+set(_CMAKE_FEATURE_DETECTION_TARGET_TYPE STATIC_LIBRARY)
diff --git a/Modules/Platform/iOS.cmake b/Modules/Platform/iOS.cmake
new file mode 100644
index 0000000..850ddc2
--- /dev/null
+++ b/Modules/Platform/iOS.cmake
@@ -0,0 +1 @@
+include(Platform/Darwin)
diff --git a/Modules/Platform/kFreeBSD.cmake b/Modules/Platform/kFreeBSD.cmake
new file mode 100644
index 0000000..c1db259
--- /dev/null
+++ b/Modules/Platform/kFreeBSD.cmake
@@ -0,0 +1,4 @@
+# kFreeBSD looks just like Linux.
+include(Platform/Linux)
+
+set(CMAKE_LIBRARY_ARCHITECTURE_REGEX "[a-z0-9_]+(-[a-z0-9_]+)?-kfreebsd-gnu[a-z0-9_]*")
diff --git a/Modules/Platform/syllable.cmake b/Modules/Platform/syllable.cmake
new file mode 100644
index 0000000..69c108d
--- /dev/null
+++ b/Modules/Platform/syllable.cmake
@@ -0,0 +1,33 @@
+# this is the platform file for the Syllable OS (http://www.syllable.org)
+# Syllable is a free OS (GPL), which is mostly POSIX conform
+# the linker accepts the rpath related arguments, but this is later on
+# ignored by the runtime linker
+# shared libs are found exclusively via the environment variable DLL_PATH,
+# which may contain also dirs containing the special variable @bindir@
+# by default @bindir@/lib is part of DLL_PATH
+# in order to run the cmake tests successfully it is required that also
+# @bindir@/. and @bindir@/../lib are in DLL_PATH
+
+
+set(CMAKE_DL_LIBS "dl")
+set(CMAKE_C_COMPILE_OPTIONS_PIC "-fPIC")
+set(CMAKE_C_COMPILE_OPTIONS_PIE "-fPIE")
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "-fPIC") # -pic
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared") # -shared
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # +s, flag for exe link to use shared lib
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
+#set(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
+
+# Initialize C link type selection flags. These flags are used when
+# building a shared library, shared module, or executable that links
+# to other libraries to select whether to use the static or shared
+# versions of the libraries.
+foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+ set(CMAKE_${type}_LINK_STATIC_C_FLAGS "-Wl,-Bstatic")
+ set(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-Wl,-Bdynamic")
+endforeach()
+
+include(Platform/UnixPaths)
+
+# these are Syllable specific:
+list(APPEND CMAKE_SYSTEM_PREFIX_PATH /usr/indexes)
diff --git a/Modules/Platform/tvOS-Determine-CXX.cmake b/Modules/Platform/tvOS-Determine-CXX.cmake
new file mode 100644
index 0000000..ac80fa6
--- /dev/null
+++ b/Modules/Platform/tvOS-Determine-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Darwin-Determine-CXX)
diff --git a/Modules/Platform/tvOS-Initialize.cmake b/Modules/Platform/tvOS-Initialize.cmake
new file mode 100644
index 0000000..6834c80
--- /dev/null
+++ b/Modules/Platform/tvOS-Initialize.cmake
@@ -0,0 +1,7 @@
+include(Platform/Darwin-Initialize)
+
+if(NOT _CMAKE_OSX_SYSROOT_PATH MATCHES "/AppleTV(OS|Simulator)")
+ message(FATAL_ERROR "${CMAKE_OSX_SYSROOT} is not an tvOS SDK")
+endif()
+
+set(_CMAKE_FEATURE_DETECTION_TARGET_TYPE STATIC_LIBRARY)
diff --git a/Modules/Platform/tvOS.cmake b/Modules/Platform/tvOS.cmake
new file mode 100644
index 0000000..850ddc2
--- /dev/null
+++ b/Modules/Platform/tvOS.cmake
@@ -0,0 +1 @@
+include(Platform/Darwin)
diff --git a/Modules/Platform/watchOS-Determine-CXX.cmake b/Modules/Platform/watchOS-Determine-CXX.cmake
new file mode 100644
index 0000000..ac80fa6
--- /dev/null
+++ b/Modules/Platform/watchOS-Determine-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Darwin-Determine-CXX)
diff --git a/Modules/Platform/watchOS-Initialize.cmake b/Modules/Platform/watchOS-Initialize.cmake
new file mode 100644
index 0000000..2f396d3
--- /dev/null
+++ b/Modules/Platform/watchOS-Initialize.cmake
@@ -0,0 +1,7 @@
+include(Platform/Darwin-Initialize)
+
+if(NOT _CMAKE_OSX_SYSROOT_PATH MATCHES "/Watch(OS|Simulator)")
+ message(FATAL_ERROR "${CMAKE_OSX_SYSROOT} is not an watchOS SDK")
+endif()
+
+set(_CMAKE_FEATURE_DETECTION_TARGET_TYPE STATIC_LIBRARY)
diff --git a/Modules/Platform/watchOS.cmake b/Modules/Platform/watchOS.cmake
new file mode 100644
index 0000000..850ddc2
--- /dev/null
+++ b/Modules/Platform/watchOS.cmake
@@ -0,0 +1 @@
+include(Platform/Darwin)
diff --git a/Modules/ProcessorCount.cmake b/Modules/ProcessorCount.cmake
new file mode 100644
index 0000000..bda23ab
--- /dev/null
+++ b/Modules/ProcessorCount.cmake
@@ -0,0 +1,240 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+ProcessorCount
+--------------
+
+ProcessorCount(var)
+
+Determine the number of processors/cores and save value in ${var}
+
+Sets the variable named ${var} to the number of physical cores
+available on the machine if the information can be determined.
+Otherwise it is set to 0. Currently this functionality is implemented
+for AIX, cygwin, FreeBSD, HPUX, Linux, macOS, QNX, Sun and
+Windows.
+
+.. versionchanged:: 3.15
+ On Linux, returns the container CPU count instead of the host CPU count.
+
+This function is guaranteed to return a positive integer (>=1) if it
+succeeds. It returns 0 if there's a problem determining the processor
+count.
+
+Example use, in a ctest -S dashboard script:
+
+::
+
+ include(ProcessorCount)
+ ProcessorCount(N)
+ if(NOT N EQUAL 0)
+ set(CTEST_BUILD_FLAGS -j${N})
+ set(ctest_test_args ${ctest_test_args} PARALLEL_LEVEL ${N})
+ endif()
+
+
+
+This function is intended to offer an approximation of the value of
+the number of compute cores available on the current machine, such
+that you may use that value for parallel building and parallel
+testing. It is meant to help utilize as much of the machine as seems
+reasonable. Of course, knowledge of what else might be running on the
+machine simultaneously should be used when deciding whether to request
+a machine's full capacity all for yourself.
+#]=======================================================================]
+
+# A more reliable way might be to compile a small C program that uses the CPUID
+# instruction, but that again requires compiler support or compiling assembler
+# code.
+
+function(ProcessorCount var)
+ # Unknown:
+ set(count 0)
+
+ if(WIN32)
+ # Windows:
+ set(count "$ENV{NUMBER_OF_PROCESSORS}")
+ #message("ProcessorCount: WIN32, trying environment variable")
+ endif()
+
+ if(NOT count)
+ # Mac, FreeBSD, OpenBSD (systems with sysctl):
+ find_program(ProcessorCount_cmd_sysctl sysctl
+ PATHS /usr/sbin /sbin)
+ mark_as_advanced(ProcessorCount_cmd_sysctl)
+ if(ProcessorCount_cmd_sysctl)
+ execute_process(COMMAND ${ProcessorCount_cmd_sysctl} -n hw.ncpu
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ OUTPUT_VARIABLE count)
+ #message("ProcessorCount: trying sysctl '${ProcessorCount_cmd_sysctl}'")
+ endif()
+ endif()
+
+ if(NOT count)
+ # Linux (systems with nproc):
+ # Prefer nproc to getconf if available as getconf may return the host CPU count in Linux containers
+ find_program(ProcessorCount_cmd_nproc nproc)
+ mark_as_advanced(ProcessorCount_cmd_nproc)
+ if(ProcessorCount_cmd_nproc)
+ execute_process(COMMAND ${ProcessorCount_cmd_nproc}
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ OUTPUT_VARIABLE count)
+ #message("ProcessorCount: trying nproc '${ProcessorCount_cmd_nproc}'")
+ endif()
+ endif()
+
+ if(NOT count)
+ # Linux (systems with getconf):
+ find_program(ProcessorCount_cmd_getconf getconf)
+ mark_as_advanced(ProcessorCount_cmd_getconf)
+ if(ProcessorCount_cmd_getconf)
+ execute_process(COMMAND ${ProcessorCount_cmd_getconf} _NPROCESSORS_ONLN
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ OUTPUT_VARIABLE count)
+ #message("ProcessorCount: trying getconf '${ProcessorCount_cmd_getconf}'")
+ endif()
+ endif()
+
+ if(NOT count)
+ # HPUX (systems with machinfo):
+ find_program(ProcessorCount_cmd_machinfo machinfo
+ PATHS /usr/contrib/bin)
+ mark_as_advanced(ProcessorCount_cmd_machinfo)
+ if(ProcessorCount_cmd_machinfo)
+ execute_process(COMMAND ${ProcessorCount_cmd_machinfo}
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ OUTPUT_VARIABLE machinfo_output)
+ string(REGEX MATCHALL "Number of CPUs = ([0-9]+)" procs "${machinfo_output}")
+ set(count "${CMAKE_MATCH_1}")
+ if(NOT count)
+ string(REGEX MATCHALL "([0-9]+) logical processors" procs "${machinfo_output}")
+ set(count "${CMAKE_MATCH_1}")
+ endif()
+ #message("ProcessorCount: trying machinfo '${ProcessorCount_cmd_machinfo}'")
+ else()
+ find_program(ProcessorCount_cmd_mpsched mpsched)
+ mark_as_advanced(ProcessorCount_cmd_mpsched)
+ if(ProcessorCount_cmd_mpsched)
+ execute_process(COMMAND ${ProcessorCount_cmd_mpsched} -s
+ OUTPUT_QUIET
+ ERROR_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE mpsched_output)
+ string(REGEX MATCHALL "Processor Count *: *([0-9]+)" procs "${mpsched_output}")
+ set(count "${CMAKE_MATCH_1}")
+ #message("ProcessorCount: trying mpsched -s '${ProcessorCount_cmd_mpsched}'")
+ endif()
+ endif()
+ endif()
+
+ if(NOT count)
+ # AIX (systems with lsconf):
+ find_program(ProcessorCount_cmd_lsconf lsconf
+ PATHS /usr/sbin)
+ mark_as_advanced(ProcessorCount_cmd_lsconf)
+ if(ProcessorCount_cmd_lsconf)
+ execute_process(COMMAND ${ProcessorCount_cmd_lsconf}
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ OUTPUT_VARIABLE lsconf_output)
+ string(REGEX MATCHALL "Number Of Processors: ([0-9]+)" procs "${lsconf_output}")
+ set(count "${CMAKE_MATCH_1}")
+ #message("ProcessorCount: trying lsconf '${ProcessorCount_cmd_lsconf}'")
+ endif()
+ endif()
+
+ if(NOT count)
+ # QNX (systems with pidin):
+ find_program(ProcessorCount_cmd_pidin pidin)
+ mark_as_advanced(ProcessorCount_cmd_pidin)
+ if(ProcessorCount_cmd_pidin)
+ execute_process(COMMAND ${ProcessorCount_cmd_pidin} info
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ OUTPUT_VARIABLE pidin_output)
+ string(REGEX MATCHALL "Processor[0-9]+: " procs "${pidin_output}")
+ list(LENGTH procs count)
+ #message("ProcessorCount: trying pidin '${ProcessorCount_cmd_pidin}'")
+ endif()
+ endif()
+
+ if(NOT count)
+ # Sun (systems where psrinfo tool is available)
+ find_program(ProcessorCount_cmd_psrinfo psrinfo PATHS /usr/sbin /sbin)
+ mark_as_advanced(ProcessorCount_cmd_psrinfo)
+ if (ProcessorCount_cmd_psrinfo)
+ execute_process(COMMAND ${ProcessorCount_cmd_psrinfo} -p -v
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ OUTPUT_VARIABLE psrinfo_output)
+ string(REGEX MATCHALL "has [0-9]+ virtual processor" procs "${psrinfo_output}")
+ set(count "")
+ foreach(proc ${procs})
+ string(REGEX MATCH "has ([0-9]+) virtual" res ${proc})
+ math(EXPR count "${count} + ${CMAKE_MATCH_1}")
+ endforeach()
+ #message("ProcessorCount: trying '${ProcessorCount_cmd_psrinfo}' -p -v")
+ else()
+ # Sun (systems where uname -X emits "NumCPU" in its output):
+ find_program(ProcessorCount_cmd_uname uname)
+ mark_as_advanced(ProcessorCount_cmd_uname)
+ if(ProcessorCount_cmd_uname)
+ execute_process(COMMAND ${ProcessorCount_cmd_uname} -X
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ OUTPUT_VARIABLE uname_X_output)
+ string(REGEX MATCHALL "NumCPU = ([0-9]+)" procs "${uname_X_output}")
+ set(count "${CMAKE_MATCH_1}")
+ #message("ProcessorCount: trying uname -X '${ProcessorCount_cmd_uname}'")
+ endif()
+ endif()
+ endif()
+
+ # Execute this code when all previously attempted methods return empty
+ # output:
+ #
+ if(NOT count)
+ # Systems with /proc/cpuinfo:
+ set(cpuinfo_file /proc/cpuinfo)
+ if(EXISTS "${cpuinfo_file}")
+ file(STRINGS "${cpuinfo_file}" procs REGEX "^processor.: [0-9]+$")
+ list(LENGTH procs count)
+ #message("ProcessorCount: trying cpuinfo '${cpuinfo_file}'")
+ endif()
+ endif()
+
+ if(NOT count)
+ # Haiku
+ find_program(ProcessorCount_cmd_sysinfo sysinfo)
+ if(ProcessorCount_cmd_sysinfo)
+ execute_process(COMMAND ${ProcessorCount_cmd_sysinfo}
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ OUTPUT_VARIABLE sysinfo_X_output)
+ string(REGEX MATCHALL "\nCPU #[0-9]+:" procs "\n${sysinfo_X_output}")
+ list(LENGTH procs count)
+ #message("ProcessorCount: trying sysinfo '${ProcessorCount_cmd_sysinfo}'")
+ endif()
+ endif()
+
+ # Since cygwin builds of CMake do not define WIN32 anymore, but they still
+ # run on Windows, and will still have this env var defined:
+ #
+ if(NOT count)
+ set(count "$ENV{NUMBER_OF_PROCESSORS}")
+ #message("ProcessorCount: last fallback, trying environment variable")
+ endif()
+
+ # Ensure an integer return (avoid inadvertently returning an empty string
+ # or an error string)... If it's not a decimal integer, return 0:
+ #
+ if(NOT count MATCHES "^[0-9]+$")
+ set(count 0)
+ endif()
+
+ set(${var} ${count} PARENT_SCOPE)
+endfunction()
diff --git a/Modules/Qt4ConfigDependentSettings.cmake b/Modules/Qt4ConfigDependentSettings.cmake
new file mode 100644
index 0000000..4699ecd
--- /dev/null
+++ b/Modules/Qt4ConfigDependentSettings.cmake
@@ -0,0 +1,290 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+Qt4ConfigDependentSettings
+--------------------------
+
+
+
+This file is included by FindQt4.cmake, don't include it directly.
+#]=======================================================================]
+
+###############################################
+#
+# configuration/system dependent settings
+#
+###############################################
+
+# find dependencies for some Qt modules
+# when doing builds against a static Qt, they are required
+# when doing builds against a shared Qt, they are not required
+# if a user needs the dependencies, and they couldn't be found, they can set
+# the variables themselves.
+
+set(QT_QTGUI_LIB_DEPENDENCIES "")
+set(QT_QTCORE_LIB_DEPENDENCIES "")
+set(QT_QTNETWORK_LIB_DEPENDENCIES "")
+set(QT_QTOPENGL_LIB_DEPENDENCIES "")
+set(QT_QTDBUS_LIB_DEPENDENCIES "")
+set(QT_QTHELP_LIB_DEPENDENCIES ${QT_QTCLUCENE_LIBRARY})
+
+
+if(Q_WS_WIN)
+ # On Windows, qconfig.pri has "shared" for shared library builds
+ if(NOT QT_CONFIG MATCHES "shared")
+ set(QT_IS_STATIC 1)
+ endif()
+else()
+ # On other platforms, check file extension to know if its static
+ if(QT_QTCORE_LIBRARY_RELEASE)
+ get_filename_component(qtcore_lib_ext "${QT_QTCORE_LIBRARY_RELEASE}" EXT)
+ if("${qtcore_lib_ext}" STREQUAL "${CMAKE_STATIC_LIBRARY_SUFFIX}")
+ set(QT_IS_STATIC 1)
+ endif()
+ endif()
+ if(QT_QTCORE_LIBRARY_DEBUG)
+ get_filename_component(qtcore_lib_ext "${QT_QTCORE_LIBRARY_DEBUG}" EXT)
+ if(${qtcore_lib_ext} STREQUAL ${CMAKE_STATIC_LIBRARY_SUFFIX})
+ set(QT_IS_STATIC 1)
+ endif()
+ endif()
+endif()
+
+# build using shared Qt needs -DQT_DLL on Windows
+if(Q_WS_WIN AND NOT QT_IS_STATIC)
+ set(QT_DEFINITIONS ${QT_DEFINITIONS} -DQT_DLL)
+endif()
+
+if(NOT QT_IS_STATIC)
+ return()
+endif()
+
+# QtOpenGL dependencies
+find_package(OpenGL)
+set (QT_QTOPENGL_LIB_DEPENDENCIES ${OPENGL_glu_LIBRARY} ${OPENGL_gl_LIBRARY})
+
+
+## system png
+if(QT_QCONFIG MATCHES "system-png")
+ find_package(PNG)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} ${PNG_LIBRARY})
+endif()
+
+## system jpeg
+if(QT_QCONFIG MATCHES "system-jpeg")
+ find_package(JPEG)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} ${JPEG_LIBRARIES})
+endif()
+
+## system tiff
+if(QT_QCONFIG MATCHES "system-tiff")
+ find_package(TIFF)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} ${TIFF_LIBRARIES})
+endif()
+
+## system mng
+if(QT_QCONFIG MATCHES "system-mng")
+ find_library(MNG_LIBRARY NAMES mng)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} ${MNG_LIBRARY})
+endif()
+
+# for X11, get X11 library directory
+if(Q_WS_X11)
+ find_package(X11)
+endif()
+
+
+## X11 SM
+if(QT_QCONFIG MATCHES "x11sm")
+ if(X11_SM_LIB AND X11_ICE_LIB)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} ${X11_SM_LIB} ${X11_ICE_LIB})
+ endif()
+endif()
+
+
+## Xi
+if(QT_QCONFIG MATCHES "tablet")
+ if(X11_Xi_LIB)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} ${X11_Xi_LIB})
+ endif()
+endif()
+
+
+## Xrender
+if(QT_QCONFIG MATCHES "xrender")
+ if(X11_Xrender_LIB)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} ${X11_Xrender_LIB})
+ endif()
+endif()
+
+
+## Xrandr
+if(QT_QCONFIG MATCHES "xrandr")
+ if(X11_Xrandr_LIB)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} ${X11_Xrandr_LIB})
+ endif()
+endif()
+
+
+## Xcursor
+if(QT_QCONFIG MATCHES "xcursor")
+ if(X11_Xcursor_LIB)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} ${X11_Xcursor_LIB})
+ endif()
+endif()
+
+
+## Xinerama
+if(QT_QCONFIG MATCHES "xinerama")
+ if(X11_Xinerama_LIB)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} ${X11_Xinerama_LIB})
+ endif()
+endif()
+
+
+## Xfixes
+if(QT_QCONFIG MATCHES "xfixes")
+ if(X11_Xfixes_LIB)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} ${X11_Xfixes_LIB})
+ endif()
+endif()
+
+
+## fontconfig
+if(QT_QCONFIG MATCHES "fontconfig")
+ find_library(QT_FONTCONFIG_LIBRARY NAMES fontconfig)
+ mark_as_advanced(QT_FONTCONFIG_LIBRARY)
+ if(QT_FONTCONFIG_LIBRARY)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} ${QT_FONTCONFIG_LIBRARY})
+ endif()
+endif()
+
+
+## system-freetype
+if(QT_QCONFIG MATCHES "system-freetype")
+ find_package(Freetype)
+ if(FREETYPE_LIBRARIES)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} ${FREETYPE_LIBRARIES})
+ endif()
+endif()
+
+
+## system-zlib
+if(QT_QCONFIG MATCHES "system-zlib")
+ find_package(ZLIB)
+ set(QT_QTCORE_LIB_DEPENDENCIES ${QT_QTCORE_LIB_DEPENDENCIES} ${ZLIB_LIBRARIES})
+endif()
+
+
+## openssl
+if(NOT Q_WS_WIN)
+ set(_QT_NEED_OPENSSL 0)
+ if(QT_VERSION_MINOR LESS 4 AND QT_QCONFIG MATCHES "openssl")
+ set(_QT_NEED_OPENSSL 1)
+ endif()
+ if(QT_VERSION_MINOR GREATER 3 AND QT_QCONFIG MATCHES "openssl-linked")
+ set(_QT_NEED_OPENSSL 1)
+ endif()
+ if(_QT_NEED_OPENSSL)
+ find_package(OpenSSL)
+ if(OPENSSL_LIBRARIES)
+ set(QT_QTNETWORK_LIB_DEPENDENCIES ${QT_QTNETWORK_LIB_DEPENDENCIES} ${OPENSSL_LIBRARIES})
+ endif()
+ endif()
+endif()
+
+
+## dbus
+if(QT_QCONFIG MATCHES "dbus")
+
+ find_library(QT_DBUS_LIBRARY NAMES dbus-1 )
+ if(QT_DBUS_LIBRARY)
+ set(QT_QTDBUS_LIB_DEPENDENCIES ${QT_QTDBUS_LIB_DEPENDENCIES} ${QT_DBUS_LIBRARY})
+ endif()
+ mark_as_advanced(QT_DBUS_LIBRARY)
+
+endif()
+
+
+## glib
+if(QT_QCONFIG MATCHES "glib")
+
+ # Qt 4.2.0+ uses glib-2.0
+ find_library(QT_GLIB_LIBRARY NAMES glib-2.0 )
+ find_library(QT_GTHREAD_LIBRARY NAMES gthread-2.0 )
+ mark_as_advanced(QT_GLIB_LIBRARY)
+ mark_as_advanced(QT_GTHREAD_LIBRARY)
+
+ if(QT_GLIB_LIBRARY AND QT_GTHREAD_LIBRARY)
+ set(QT_QTCORE_LIB_DEPENDENCIES ${QT_QTCORE_LIB_DEPENDENCIES}
+ ${QT_GTHREAD_LIBRARY} ${QT_GLIB_LIBRARY})
+ endif()
+
+
+ # Qt 4.5+ also links to gobject-2.0
+ if(QT_VERSION_MINOR GREATER 4)
+ find_library(QT_GOBJECT_LIBRARY NAMES gobject-2.0 PATHS ${_glib_query_output} )
+ mark_as_advanced(QT_GOBJECT_LIBRARY)
+
+ if(QT_GOBJECT_LIBRARY)
+ set(QT_QTCORE_LIB_DEPENDENCIES ${QT_QTCORE_LIB_DEPENDENCIES}
+ ${QT_GOBJECT_LIBRARY})
+ endif()
+ endif()
+
+endif()
+
+
+## clock-monotonic, just see if we need to link with rt
+if(QT_QCONFIG MATCHES "clock-monotonic")
+ set(CMAKE_REQUIRED_LIBRARIES_SAVE ${CMAKE_REQUIRED_LIBRARIES})
+ set(CMAKE_REQUIRED_LIBRARIES rt)
+ CHECK_SYMBOL_EXISTS(_POSIX_TIMERS "unistd.h;time.h" QT_POSIX_TIMERS)
+ set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_SAVE})
+ if(QT_POSIX_TIMERS)
+ find_library(QT_RT_LIBRARY NAMES rt)
+ mark_as_advanced(QT_RT_LIBRARY)
+ if(QT_RT_LIBRARY)
+ set(QT_QTCORE_LIB_DEPENDENCIES ${QT_QTCORE_LIB_DEPENDENCIES} ${QT_RT_LIBRARY})
+ endif()
+ endif()
+endif()
+
+
+if(Q_WS_X11)
+ # X11 libraries Qt always depends on
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} ${X11_Xext_LIB} ${X11_X11_LIB})
+
+ find_package(Threads)
+ if(CMAKE_USE_PTHREADS_INIT)
+ set(QT_QTCORE_LIB_DEPENDENCIES ${QT_QTCORE_LIB_DEPENDENCIES} ${CMAKE_THREAD_LIBS_INIT})
+ endif()
+
+ set (QT_QTCORE_LIB_DEPENDENCIES ${QT_QTCORE_LIB_DEPENDENCIES} ${CMAKE_DL_LIBS})
+
+endif()
+
+
+if(Q_WS_WIN)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} imm32 winmm)
+ set(QT_QTCORE_LIB_DEPENDENCIES ${QT_QTCORE_LIB_DEPENDENCIES} ws2_32)
+endif()
+
+
+if(Q_WS_MAC)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} "-framework Carbon")
+
+ # Qt 4.0, 4.1, 4.2 use QuickTime
+ if(QT_VERSION_MINOR LESS 3)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} "-framework QuickTime")
+ endif()
+
+ # Qt 4.2+ use AppKit
+ if(QT_VERSION_MINOR GREATER 1)
+ set(QT_QTGUI_LIB_DEPENDENCIES ${QT_QTGUI_LIB_DEPENDENCIES} "-framework AppKit")
+ endif()
+
+ set(QT_QTCORE_LIB_DEPENDENCIES ${QT_QTCORE_LIB_DEPENDENCIES} "-framework ApplicationServices")
+endif()
+
diff --git a/Modules/Qt4Macros.cmake b/Modules/Qt4Macros.cmake
new file mode 100644
index 0000000..cb6ae43
--- /dev/null
+++ b/Modules/Qt4Macros.cmake
@@ -0,0 +1,516 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+Qt4Macros
+---------
+
+
+
+This file is included by FindQt4.cmake, don't include it directly.
+#]=======================================================================]
+
+######################################
+#
+# Macros for building Qt files
+#
+######################################
+
+
+macro (QT4_EXTRACT_OPTIONS _qt4_files _qt4_options _qt4_target)
+ set(${_qt4_files})
+ set(${_qt4_options})
+ set(_QT4_DOING_OPTIONS FALSE)
+ set(_QT4_DOING_TARGET FALSE)
+ foreach(_currentArg ${ARGN})
+ if ("x${_currentArg}" STREQUAL "xOPTIONS")
+ set(_QT4_DOING_OPTIONS TRUE)
+ elseif ("x${_currentArg}" STREQUAL "xTARGET")
+ set(_QT4_DOING_TARGET TRUE)
+ else ()
+ if(_QT4_DOING_TARGET)
+ set(${_qt4_target} "${_currentArg}")
+ elseif(_QT4_DOING_OPTIONS)
+ list(APPEND ${_qt4_options} "${_currentArg}")
+ else()
+ list(APPEND ${_qt4_files} "${_currentArg}")
+ endif()
+ endif ()
+ endforeach()
+endmacro ()
+
+
+# macro used to create the names of output files preserving relative dirs
+macro (QT4_MAKE_OUTPUT_FILE infile prefix ext outfile )
+ string(LENGTH ${CMAKE_CURRENT_BINARY_DIR} _binlength)
+ string(LENGTH ${infile} _infileLength)
+ set(_checkinfile ${CMAKE_CURRENT_SOURCE_DIR})
+ if(_infileLength GREATER _binlength)
+ string(SUBSTRING "${infile}" 0 ${_binlength} _checkinfile)
+ if(_checkinfile STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
+ file(RELATIVE_PATH rel ${CMAKE_CURRENT_BINARY_DIR} ${infile})
+ else()
+ file(RELATIVE_PATH rel ${CMAKE_CURRENT_SOURCE_DIR} ${infile})
+ endif()
+ else()
+ file(RELATIVE_PATH rel ${CMAKE_CURRENT_SOURCE_DIR} ${infile})
+ endif()
+ if(WIN32 AND rel MATCHES "^([a-zA-Z]):(.*)$") # absolute path
+ set(rel "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}")
+ endif()
+ set(_outfile "${CMAKE_CURRENT_BINARY_DIR}/${rel}")
+ string(REPLACE ".." "__" _outfile ${_outfile})
+ get_filename_component(outpath ${_outfile} PATH)
+ get_filename_component(_outfile ${_outfile} NAME_WE)
+ file(MAKE_DIRECTORY ${outpath})
+ set(${outfile} ${outpath}/${prefix}${_outfile}.${ext})
+endmacro ()
+
+
+macro (QT4_GET_MOC_FLAGS _moc_flags)
+ set(${_moc_flags})
+ get_directory_property(_inc_DIRS INCLUDE_DIRECTORIES)
+
+ foreach(_current ${_inc_DIRS})
+ if("${_current}" MATCHES "\\.framework/?$")
+ string(REGEX REPLACE "/[^/]+\\.framework" "" framework_path "${_current}")
+ set(${_moc_flags} ${${_moc_flags}} "-F${framework_path}")
+ else()
+ set(${_moc_flags} ${${_moc_flags}} "-I${_current}")
+ endif()
+ endforeach()
+
+ get_directory_property(_defines COMPILE_DEFINITIONS)
+ foreach(_current ${_defines})
+ set(${_moc_flags} ${${_moc_flags}} "-D${_current}")
+ endforeach()
+
+ if(Q_WS_WIN)
+ set(${_moc_flags} ${${_moc_flags}} -DWIN32)
+ endif()
+
+endmacro()
+
+
+# helper macro to set up a moc rule
+function (QT4_CREATE_MOC_COMMAND infile outfile moc_flags moc_options moc_target)
+ # For Windows, create a parameters file to work around command line length limit
+ # Pass the parameters in a file. Set the working directory to
+ # be that containing the parameters file and reference it by
+ # just the file name. This is necessary because the moc tool on
+ # MinGW builds does not seem to handle spaces in the path to the
+ # file given with the @ syntax.
+ get_filename_component(_moc_outfile_name "${outfile}" NAME)
+ get_filename_component(_moc_outfile_dir "${outfile}" PATH)
+ if(_moc_outfile_dir)
+ set(_moc_working_dir WORKING_DIRECTORY ${_moc_outfile_dir})
+ endif()
+ set (_moc_parameters_file ${outfile}_parameters)
+ set (_moc_parameters ${moc_flags} ${moc_options} -o "${outfile}" "${infile}")
+ string (REPLACE ";" "\n" _moc_parameters "${_moc_parameters}")
+
+ if(moc_target)
+ set (_moc_parameters_file ${_moc_parameters_file}$<$<BOOL:$<CONFIGURATION>>:_$<CONFIGURATION>>)
+ set(targetincludes "$<TARGET_PROPERTY:${moc_target},INCLUDE_DIRECTORIES>")
+ set(targetdefines "$<TARGET_PROPERTY:${moc_target},COMPILE_DEFINITIONS>")
+
+ set(targetincludes "$<$<BOOL:${targetincludes}>:-I$<JOIN:${targetincludes},\n-I>\n>")
+ set(targetdefines "$<$<BOOL:${targetdefines}>:-D$<JOIN:${targetdefines},\n-D>\n>")
+
+ file (GENERATE
+ OUTPUT ${_moc_parameters_file}
+ CONTENT "${targetdefines}${targetincludes}${_moc_parameters}\n"
+ )
+
+ set(targetincludes)
+ set(targetdefines)
+ else()
+ set(CMAKE_CONFIGURABLE_FILE_CONTENT "${_moc_parameters}")
+ configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
+ "${_moc_parameters_file}" @ONLY)
+ endif()
+
+ set(_moc_extra_parameters_file @${_moc_parameters_file})
+ add_custom_command(OUTPUT ${outfile}
+ COMMAND Qt4::moc ${_moc_extra_parameters_file}
+ DEPENDS ${infile} ${_moc_parameters_file}
+ ${_moc_working_dir}
+ VERBATIM)
+endfunction ()
+
+
+macro (QT4_GENERATE_MOC infile outfile )
+ # get include dirs and flags
+ QT4_GET_MOC_FLAGS(moc_flags)
+ get_filename_component(abs_infile ${infile} ABSOLUTE)
+ set(_outfile "${outfile}")
+ if(NOT IS_ABSOLUTE "${outfile}")
+ set(_outfile "${CMAKE_CURRENT_BINARY_DIR}/${outfile}")
+ endif()
+
+ if (${ARGC} GREATER 3 AND "x${ARGV2}" STREQUAL "xTARGET")
+ set(moc_target ${ARGV3})
+ endif()
+ QT4_CREATE_MOC_COMMAND(${abs_infile} ${_outfile} "${moc_flags}" "" "${moc_target}")
+ set_property(SOURCE ${outfile} PROPERTY SKIP_AUTOMOC TRUE) # don't run automoc on this file
+ set_property(SOURCE ${outfile} PROPERTY SKIP_AUTOUIC TRUE) # don't run autouic on this file
+endmacro ()
+
+
+# QT4_WRAP_CPP(outfiles inputfile ... )
+
+macro (QT4_WRAP_CPP outfiles )
+ # get include dirs
+ QT4_GET_MOC_FLAGS(moc_flags)
+ QT4_EXTRACT_OPTIONS(moc_files moc_options moc_target ${ARGN})
+
+ foreach (it ${moc_files})
+ get_filename_component(it ${it} ABSOLUTE)
+ QT4_MAKE_OUTPUT_FILE(${it} moc_ cxx outfile)
+ QT4_CREATE_MOC_COMMAND(${it} ${outfile} "${moc_flags}" "${moc_options}" "${moc_target}")
+ set_property(SOURCE ${outfile} PROPERTY SKIP_AUTOMOC TRUE) # don't run automoc on this file
+ set_property(SOURCE ${outfile} PROPERTY SKIP_AUTOUIC TRUE) # don't run autouic on this file
+ set(${outfiles} ${${outfiles}} ${outfile})
+ endforeach()
+
+endmacro ()
+
+
+# QT4_WRAP_UI(outfiles inputfile ... )
+
+macro (QT4_WRAP_UI outfiles )
+ QT4_EXTRACT_OPTIONS(ui_files ui_options ui_target ${ARGN})
+
+ foreach (it ${ui_files})
+ get_filename_component(outfile ${it} NAME_WE)
+ get_filename_component(infile ${it} ABSOLUTE)
+ set(outfile ${CMAKE_CURRENT_BINARY_DIR}/ui_${outfile}.h)
+ add_custom_command(OUTPUT ${outfile}
+ COMMAND Qt4::uic
+ ARGS ${ui_options} -o ${outfile} ${infile}
+ MAIN_DEPENDENCY ${infile} VERBATIM)
+ set_property(SOURCE ${outfile} PROPERTY SKIP_AUTOMOC TRUE) # don't run automoc on this file
+ set_property(SOURCE ${outfile} PROPERTY SKIP_AUTOUIC TRUE) # don't run autouic on this file
+ set(${outfiles} ${${outfiles}} ${outfile})
+ endforeach ()
+
+endmacro ()
+
+
+# QT4_ADD_RESOURCES(outfiles inputfile ... )
+
+macro (QT4_ADD_RESOURCES outfiles )
+ QT4_EXTRACT_OPTIONS(rcc_files rcc_options rcc_target ${ARGN})
+
+ foreach (it ${rcc_files})
+ get_filename_component(outfilename ${it} NAME_WE)
+ get_filename_component(infile ${it} ABSOLUTE)
+ get_filename_component(rc_path ${infile} PATH)
+ set(outfile ${CMAKE_CURRENT_BINARY_DIR}/qrc_${outfilename}.cxx)
+
+ set(_RC_DEPENDS)
+ if(EXISTS "${infile}")
+ # parse file for dependencies
+ # all files are absolute paths or relative to the location of the qrc file
+ file(READ "${infile}" _RC_FILE_CONTENTS)
+ string(REGEX MATCHALL "<file[^<]+" _RC_FILES "${_RC_FILE_CONTENTS}")
+ foreach(_RC_FILE ${_RC_FILES})
+ string(REGEX REPLACE "^<file[^>]*>" "" _RC_FILE "${_RC_FILE}")
+ if(NOT IS_ABSOLUTE "${_RC_FILE}")
+ set(_RC_FILE "${rc_path}/${_RC_FILE}")
+ endif()
+ set(_RC_DEPENDS ${_RC_DEPENDS} "${_RC_FILE}")
+ endforeach()
+ unset(_RC_FILES)
+ unset(_RC_FILE_CONTENTS)
+ # Since this cmake macro is doing the dependency scanning for these files,
+ # let's make a configured file and add it as a dependency so cmake is run
+ # again when dependencies need to be recomputed.
+ QT4_MAKE_OUTPUT_FILE("${infile}" "" "qrc.depends" out_depends)
+ configure_file("${infile}" "${out_depends}" COPYONLY)
+ else()
+ # The .qrc file does not exist (yet). Let's add a dependency and hope
+ # that it will be generated later
+ set(out_depends)
+ endif()
+
+ add_custom_command(OUTPUT ${outfile}
+ COMMAND Qt4::rcc
+ ARGS ${rcc_options} -name ${outfilename} -o ${outfile} ${infile}
+ MAIN_DEPENDENCY ${infile}
+ DEPENDS ${_RC_DEPENDS} "${out_depends}" VERBATIM)
+ set_property(SOURCE ${outfile} PROPERTY SKIP_AUTOMOC TRUE) # don't run automoc on this file
+ set_property(SOURCE ${outfile} PROPERTY SKIP_AUTOUIC TRUE) # don't run autouic on this file
+ set(${outfiles} ${${outfiles}} ${outfile})
+ endforeach ()
+
+endmacro ()
+
+
+macro(QT4_ADD_DBUS_INTERFACE _sources _interface _basename)
+ get_filename_component(_infile ${_interface} ABSOLUTE)
+ set(_header "${CMAKE_CURRENT_BINARY_DIR}/${_basename}.h")
+ set(_impl "${CMAKE_CURRENT_BINARY_DIR}/${_basename}.cpp")
+ set(_moc "${CMAKE_CURRENT_BINARY_DIR}/${_basename}.moc")
+
+ get_property(_nonamespace SOURCE ${_interface} PROPERTY NO_NAMESPACE)
+ if(_nonamespace)
+ set(_params -N -m)
+ else()
+ set(_params -m)
+ endif()
+
+ get_property(_classname SOURCE ${_interface} PROPERTY CLASSNAME)
+ if(_classname)
+ set(_params ${_params} -c ${_classname})
+ endif()
+
+ get_property(_include SOURCE ${_interface} PROPERTY INCLUDE)
+ if(_include)
+ set(_params ${_params} -i ${_include})
+ endif()
+
+ add_custom_command(OUTPUT "${_impl}" "${_header}"
+ COMMAND Qt4::qdbusxml2cpp ${_params} -p ${_basename} ${_infile}
+ DEPENDS ${_infile} VERBATIM)
+
+ set_property(SOURCE ${_impl} PROPERTY SKIP_AUTOMOC TRUE) # don't run automoc on this file
+ set_property(SOURCE ${_impl} PROPERTY SKIP_AUTOUIC TRUE) # don't run autouic on this file
+
+ QT4_GENERATE_MOC("${_header}" "${_moc}")
+
+ list(APPEND ${_sources} "${_impl}" "${_header}" "${_moc}")
+ MACRO_ADD_FILE_DEPENDENCIES("${_impl}" "${_moc}")
+
+endmacro()
+
+
+macro(QT4_ADD_DBUS_INTERFACES _sources)
+ foreach (_current_FILE ${ARGN})
+ get_filename_component(_infile ${_current_FILE} ABSOLUTE)
+ get_filename_component(_basename ${_current_FILE} NAME)
+ # get the part before the ".xml" suffix
+ string(TOLOWER ${_basename} _basename)
+ string(REGEX REPLACE "(.*\\.)?([^\\.]+)\\.xml" "\\2" _basename ${_basename})
+ QT4_ADD_DBUS_INTERFACE(${_sources} ${_infile} ${_basename}interface)
+ endforeach ()
+endmacro()
+
+
+macro(QT4_GENERATE_DBUS_INTERFACE _header) # _customName OPTIONS -some -options )
+ QT4_EXTRACT_OPTIONS(_customName _qt4_dbus_options _qt4_dbus_target ${ARGN})
+
+ get_filename_component(_in_file ${_header} ABSOLUTE)
+ get_filename_component(_basename ${_header} NAME_WE)
+
+ if (_customName)
+ if (IS_ABSOLUTE ${_customName})
+ get_filename_component(_containingDir ${_customName} PATH)
+ if (NOT EXISTS ${_containingDir})
+ file(MAKE_DIRECTORY "${_containingDir}")
+ endif()
+ set(_target ${_customName})
+ else()
+ set(_target ${CMAKE_CURRENT_BINARY_DIR}/${_customName})
+ endif()
+ else ()
+ set(_target ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.xml)
+ endif ()
+
+ add_custom_command(OUTPUT ${_target}
+ COMMAND Qt4::qdbuscpp2xml ${_qt4_dbus_options} ${_in_file} -o ${_target}
+ DEPENDS ${_in_file} VERBATIM
+ )
+endmacro()
+
+
+macro(QT4_ADD_DBUS_ADAPTOR _sources _xml_file _include _parentClass) # _optionalBasename _optionalClassName)
+ get_filename_component(_infile ${_xml_file} ABSOLUTE)
+
+ unset(_optionalBasename)
+ if(${ARGC} GREATER 4)
+ set(_optionalBasename "${ARGV4}")
+ endif()
+ if (_optionalBasename)
+ set(_basename ${_optionalBasename} )
+ else ()
+ string(REGEX REPLACE "(.*[/\\.])?([^\\.]+)\\.xml" "\\2adaptor" _basename ${_infile})
+ string(TOLOWER ${_basename} _basename)
+ endif ()
+
+ unset(_optionalClassName)
+ if(${ARGC} GREATER 5)
+ set(_optionalClassName "${ARGV5}")
+ endif()
+ set(_header "${CMAKE_CURRENT_BINARY_DIR}/${_basename}.h")
+ set(_impl "${CMAKE_CURRENT_BINARY_DIR}/${_basename}.cpp")
+ set(_moc "${CMAKE_CURRENT_BINARY_DIR}/${_basename}.moc")
+
+ if(_optionalClassName)
+ add_custom_command(OUTPUT "${_impl}" "${_header}"
+ COMMAND Qt4::qdbusxml2cpp -m -a ${_basename} -c ${_optionalClassName} -i ${_include} -l ${_parentClass} ${_infile}
+ DEPENDS ${_infile} VERBATIM
+ )
+ else()
+ add_custom_command(OUTPUT "${_impl}" "${_header}"
+ COMMAND Qt4::qdbusxml2cpp -m -a ${_basename} -i ${_include} -l ${_parentClass} ${_infile}
+ DEPENDS ${_infile} VERBATIM
+ )
+ endif()
+
+ QT4_GENERATE_MOC("${_header}" "${_moc}")
+ set_property(SOURCE ${_impl} PROPERTY SKIP_AUTOMOC TRUE) # don't run automoc on this file
+ set_property(SOURCE ${_impl} PROPERTY SKIP_AUTOUIC TRUE) # don't run autouic on this file
+ MACRO_ADD_FILE_DEPENDENCIES("${_impl}" "${_moc}")
+
+ list(APPEND ${_sources} "${_impl}" "${_header}" "${_moc}")
+endmacro()
+
+
+macro(QT4_AUTOMOC)
+ if(NOT CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.11)
+ message(DEPRECATION "The qt4_automoc macro is obsolete. Use the CMAKE_AUTOMOC feature instead.")
+ endif()
+ QT4_GET_MOC_FLAGS(_moc_INCS)
+
+ set(_matching_FILES )
+ foreach (_current_FILE ${ARGN})
+
+ get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE)
+ # if "SKIP_AUTOMOC" is set to true, we will not handle this file here.
+ # This is required to make uic work correctly:
+ # we need to add generated .cpp files to the sources (to compile them),
+ # but we cannot let automoc handle them, as the .cpp files don't exist yet when
+ # cmake is run for the very first time on them -> however the .cpp files might
+ # exist at a later run. at that time we need to skip them, so that we don't add two
+ # different rules for the same moc file
+ get_property(_skip SOURCE ${_abs_FILE} PROPERTY SKIP_AUTOMOC)
+
+ if ( NOT _skip AND EXISTS ${_abs_FILE} )
+
+ file(READ ${_abs_FILE} _contents)
+
+ get_filename_component(_abs_PATH ${_abs_FILE} PATH)
+
+ string(REGEX MATCHALL "# *include +[^ ]+\\.moc[\">]" _match "${_contents}")
+ if(_match)
+ foreach (_current_MOC_INC ${_match})
+ string(REGEX MATCH "[^ <\"]+\\.moc" _current_MOC "${_current_MOC_INC}")
+
+ get_filename_component(_basename ${_current_MOC} NAME_WE)
+ if(EXISTS ${_abs_PATH}/${_basename}.hpp)
+ set(_header ${_abs_PATH}/${_basename}.hpp)
+ else()
+ set(_header ${_abs_PATH}/${_basename}.h)
+ endif()
+ set(_moc ${CMAKE_CURRENT_BINARY_DIR}/${_current_MOC})
+ QT4_CREATE_MOC_COMMAND(${_header} ${_moc} "${_moc_INCS}" "" "")
+ MACRO_ADD_FILE_DEPENDENCIES(${_abs_FILE} ${_moc})
+ endforeach ()
+ endif()
+ endif ()
+ endforeach ()
+endmacro()
+
+
+macro(QT4_CREATE_TRANSLATION _qm_files)
+ QT4_EXTRACT_OPTIONS(_lupdate_files _lupdate_options _lupdate_target ${ARGN})
+ set(_my_sources)
+ set(_my_dirs)
+ set(_my_tsfiles)
+ set(_ts_pro)
+ foreach (_file ${_lupdate_files})
+ get_filename_component(_ext ${_file} EXT)
+ get_filename_component(_abs_FILE ${_file} ABSOLUTE)
+ if(_ext MATCHES "ts")
+ list(APPEND _my_tsfiles ${_abs_FILE})
+ else()
+ if(NOT _ext)
+ list(APPEND _my_dirs ${_abs_FILE})
+ else()
+ list(APPEND _my_sources ${_abs_FILE})
+ endif()
+ endif()
+ endforeach()
+ foreach(_ts_file ${_my_tsfiles})
+ if(_my_sources)
+ # make a .pro file to call lupdate on, so we don't make our commands too
+ # long for some systems
+ get_filename_component(_ts_name ${_ts_file} NAME)
+ set(_ts_pro ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_ts_name}_lupdate.pro)
+ set(_pro_srcs)
+ foreach(_pro_src ${_my_sources})
+ string(APPEND _pro_srcs " \\\n \"${_pro_src}\"")
+ endforeach()
+ set(_pro_includes)
+ get_directory_property(_inc_DIRS INCLUDE_DIRECTORIES)
+ list(REMOVE_DUPLICATES _inc_DIRS)
+ foreach(_pro_include ${_inc_DIRS})
+ get_filename_component(_abs_include "${_pro_include}" ABSOLUTE)
+ string(APPEND _pro_includes " \\\n \"${_abs_include}\"")
+ endforeach()
+ file(GENERATE OUTPUT ${_ts_pro} CONTENT "SOURCES =${_pro_srcs}\nINCLUDEPATH =${_pro_includes}\n")
+ endif()
+ add_custom_command(OUTPUT ${_ts_file}
+ COMMAND Qt4::lupdate
+ ARGS ${_lupdate_options} ${_ts_pro} ${_my_dirs} -ts ${_ts_file}
+ DEPENDS ${_my_sources} ${_ts_pro} VERBATIM)
+ endforeach()
+ QT4_ADD_TRANSLATION(${_qm_files} ${_my_tsfiles})
+endmacro()
+
+
+macro(QT4_ADD_TRANSLATION _qm_files)
+ foreach (_current_FILE ${ARGN})
+ get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE)
+ get_filename_component(qm ${_abs_FILE} NAME)
+ # everything before the last dot has to be considered the file name (including other dots)
+ string(REGEX REPLACE "\\.[^.]*$" "" FILE_NAME ${qm})
+ get_source_file_property(output_location ${_abs_FILE} OUTPUT_LOCATION)
+ if(output_location)
+ file(MAKE_DIRECTORY "${output_location}")
+ set(qm "${output_location}/${FILE_NAME}.qm")
+ else()
+ set(qm "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.qm")
+ endif()
+
+ add_custom_command(OUTPUT ${qm}
+ COMMAND Qt4::lrelease
+ ARGS ${_abs_FILE} -qm ${qm}
+ DEPENDS ${_abs_FILE} VERBATIM
+ )
+ set(${_qm_files} ${${_qm_files}} ${qm})
+ endforeach ()
+endmacro()
+
+function(qt4_use_modules _target _link_type)
+ if(NOT CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.11)
+ message(DEPRECATION "The qt4_use_modules function is obsolete. Use target_link_libraries with IMPORTED targets instead.")
+ endif()
+ if ("${_link_type}" STREQUAL "LINK_PUBLIC" OR "${_link_type}" STREQUAL "LINK_PRIVATE")
+ set(modules ${ARGN})
+ set(link_type ${_link_type})
+ else()
+ set(modules ${_link_type} ${ARGN})
+ endif()
+ foreach(_module ${modules})
+ string(TOUPPER ${_module} _ucmodule)
+ set(_targetPrefix QT_QT${_ucmodule})
+ if (_ucmodule STREQUAL QAXCONTAINER OR _ucmodule STREQUAL QAXSERVER)
+ if (NOT QT_Q${_ucmodule}_FOUND)
+ message(FATAL_ERROR "Can not use \"${_module}\" module which has not yet been found.")
+ endif()
+ set(_targetPrefix QT_Q${_ucmodule})
+ else()
+ if (NOT QT_QT${_ucmodule}_FOUND)
+ message(FATAL_ERROR "Can not use \"${_module}\" module which has not yet been found.")
+ endif()
+ if ("${_ucmodule}" STREQUAL "MAIN")
+ message(FATAL_ERROR "Can not use \"${_module}\" module with qt4_use_modules.")
+ endif()
+ endif()
+ target_link_libraries(${_target} ${link_type} ${${_targetPrefix}_LIBRARIES})
+ set_property(TARGET ${_target} APPEND PROPERTY INCLUDE_DIRECTORIES ${${_targetPrefix}_INCLUDE_DIR} ${QT_HEADERS_DIR} ${QT_MKSPECS_DIR}/default)
+ set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS ${${_targetPrefix}_COMPILE_DEFINITIONS})
+ endforeach()
+endfunction()
diff --git a/Modules/RepositoryInfo.txt.in b/Modules/RepositoryInfo.txt.in
new file mode 100644
index 0000000..df8e322
--- /dev/null
+++ b/Modules/RepositoryInfo.txt.in
@@ -0,0 +1,3 @@
+repository='@repository@'
+module='@module@'
+tag='@tag@'
diff --git a/Modules/SelectLibraryConfigurations.cmake b/Modules/SelectLibraryConfigurations.cmake
new file mode 100644
index 0000000..4c0e9a8
--- /dev/null
+++ b/Modules/SelectLibraryConfigurations.cmake
@@ -0,0 +1,80 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+SelectLibraryConfigurations
+---------------------------
+
+.. code-block:: cmake
+
+ select_library_configurations(basename)
+
+This macro takes a library base name as an argument, and will choose
+good values for the variables
+
+::
+
+ basename_LIBRARY
+ basename_LIBRARIES
+ basename_LIBRARY_DEBUG
+ basename_LIBRARY_RELEASE
+
+depending on what has been found and set.
+
+If only ``basename_LIBRARY_RELEASE`` is defined, ``basename_LIBRARY`` will
+be set to the release value, and ``basename_LIBRARY_DEBUG`` will be set
+to ``basename_LIBRARY_DEBUG-NOTFOUND``. If only ``basename_LIBRARY_DEBUG``
+is defined, then ``basename_LIBRARY`` will take the debug value, and
+``basename_LIBRARY_RELEASE`` will be set to ``basename_LIBRARY_RELEASE-NOTFOUND``.
+
+If the generator supports configuration types, then ``basename_LIBRARY``
+and ``basename_LIBRARIES`` will be set with debug and optimized flags
+specifying the library to be used for the given configuration. If no
+build type has been set or the generator in use does not support
+configuration types, then ``basename_LIBRARY`` and ``basename_LIBRARIES``
+will take only the release value, or the debug value if the release one
+is not set.
+#]=======================================================================]
+
+# This macro was adapted from the FindQt4 CMake module and is maintained by Will
+# Dicharry <wdicharry@stellarscience.com>.
+
+macro(select_library_configurations basename)
+ if(NOT ${basename}_LIBRARY_RELEASE)
+ set(${basename}_LIBRARY_RELEASE "${basename}_LIBRARY_RELEASE-NOTFOUND" CACHE FILEPATH "Path to a library.")
+ endif()
+ if(NOT ${basename}_LIBRARY_DEBUG)
+ set(${basename}_LIBRARY_DEBUG "${basename}_LIBRARY_DEBUG-NOTFOUND" CACHE FILEPATH "Path to a library.")
+ endif()
+
+ get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if( ${basename}_LIBRARY_DEBUG AND ${basename}_LIBRARY_RELEASE AND
+ NOT ${basename}_LIBRARY_DEBUG STREQUAL ${basename}_LIBRARY_RELEASE AND
+ ( _isMultiConfig OR CMAKE_BUILD_TYPE ) )
+ # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for
+ # single-config generators, set optimized and debug libraries
+ set( ${basename}_LIBRARY "" )
+ foreach( _libname IN LISTS ${basename}_LIBRARY_RELEASE )
+ list( APPEND ${basename}_LIBRARY optimized "${_libname}" )
+ endforeach()
+ foreach( _libname IN LISTS ${basename}_LIBRARY_DEBUG )
+ list( APPEND ${basename}_LIBRARY debug "${_libname}" )
+ endforeach()
+ elseif( ${basename}_LIBRARY_RELEASE )
+ set( ${basename}_LIBRARY ${${basename}_LIBRARY_RELEASE} )
+ elseif( ${basename}_LIBRARY_DEBUG )
+ set( ${basename}_LIBRARY ${${basename}_LIBRARY_DEBUG} )
+ else()
+ set( ${basename}_LIBRARY "${basename}_LIBRARY-NOTFOUND")
+ endif()
+
+ set( ${basename}_LIBRARIES "${${basename}_LIBRARY}" )
+
+ if( ${basename}_LIBRARY )
+ set( ${basename}_FOUND TRUE )
+ endif()
+
+ mark_as_advanced( ${basename}_LIBRARY_RELEASE
+ ${basename}_LIBRARY_DEBUG
+ )
+endmacro()
diff --git a/Modules/Squish4RunTestCase.bat b/Modules/Squish4RunTestCase.bat
new file mode 100755
index 0000000..fe303b8
--- /dev/null
+++ b/Modules/Squish4RunTestCase.bat
@@ -0,0 +1,23 @@
+set SQUISHSERVER=%1
+set SQUISHRUNNER=%2
+set TESTSUITE=%3
+set TESTCASE=%4
+set AUT=%5
+set AUTDIR=%6
+
+%SQUISHSERVER% --stop
+
+echo "Adding AUT... %SQUISHSERVER% --config addAUT %AUT% %AUTDIR%"
+%SQUISHSERVER% --config addAUT "%AUT%" "%AUTDIR%"
+
+echo "Starting the squish server... %SQUISHSERVER%"
+start /B "Squish Server" %SQUISHSERVER%
+
+echo "Running the test case... %SQUISHRUNNER% --testsuite %TESTSUITE% --testcase %TESTCASE%"
+%SQUISHRUNNER% --testsuite "%TESTSUITE%" --testcase "%TESTCASE%"
+set returnValue=%ERRORLEVEL%
+
+echo "Stopping the squish server... %SQUISHSERVER% --stop"
+%SQUISHSERVER% --stop
+
+exit /B %returnValue%
diff --git a/Modules/Squish4RunTestCase.sh b/Modules/Squish4RunTestCase.sh
new file mode 100755
index 0000000..4d1e382
--- /dev/null
+++ b/Modules/Squish4RunTestCase.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+SQUISHSERVER=$1
+SQUISHRUNNER=$2
+TESTSUITE=$3
+TESTCASE=$4
+AUT=$5
+AUTDIR=$6
+
+$SQUISHSERVER --stop > /dev/null 2>&1
+
+echo "Adding AUT... $SQUISHSERVER --config addAUT $AUT $AUTDIR"
+$SQUISHSERVER --config addAUT "$AUT" "$AUTDIR" || exit 255
+# sleep 1
+
+echo "Starting the squish server... $SQUISHSERVER --daemon"
+$SQUISHSERVER --daemon || exit 255
+# sleep 2
+
+echo "Running the test case... $SQUISHRUNNER --testsuite $TESTSUITE --testcase $TESTCASE"
+$SQUISHRUNNER --testsuite "$TESTSUITE" --testcase "$TESTCASE"
+returnValue=$?
+
+echo "Stopping the squish server... $SQUISHSERVER --stop"
+$SQUISHSERVER --stop
+
+exit $returnValue
diff --git a/Modules/SquishRunTestCase.bat b/Modules/SquishRunTestCase.bat
new file mode 100755
index 0000000..293e88f
--- /dev/null
+++ b/Modules/SquishRunTestCase.bat
@@ -0,0 +1,11 @@
+echo 'Starting the squish server...'
+start %1
+
+echo 'Running the test case...'
+%2 --testcase %3 --wrapper %4 --aut %5
+set result=%ERRORLEVEL%
+
+echo 'Stopping the squish server...'
+%1 --stop
+
+exit \b %result%
diff --git a/Modules/SquishRunTestCase.sh b/Modules/SquishRunTestCase.sh
new file mode 100755
index 0000000..409b46a
--- /dev/null
+++ b/Modules/SquishRunTestCase.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+echo "Starting the squish server...$1 --daemon"
+$1 --daemon
+
+echo "Running the test case...$2 --testcase $3 --wrapper $4 --aut $5"
+$2 --testcase $3 --wrapper $4 --aut $5
+returnValue=$?
+
+echo "Stopping the squish server...$1 --stop"
+$1 --stop
+
+exit $returnValue
diff --git a/Modules/SquishTestScript.cmake b/Modules/SquishTestScript.cmake
new file mode 100644
index 0000000..b0cb4af
--- /dev/null
+++ b/Modules/SquishTestScript.cmake
@@ -0,0 +1,85 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+SquishTestScript
+----------------
+
+
+
+
+
+This script launches a GUI test using Squish. You should not call the
+script directly; instead, you should access it via the SQUISH_ADD_TEST
+macro that is defined in FindSquish.cmake.
+
+This script starts the Squish server, launches the test on the client,
+and finally stops the squish server. If any of these steps fail
+(including if the tests do not pass) then a fatal error is raised.
+#]=======================================================================]
+
+# print out the variable that we are using
+message(STATUS "squish_aut='${squish_aut}'")
+message(STATUS "squish_aut_dir='${squish_aut_dir}'")
+
+message(STATUS "squish_version='${squish_version}'")
+message(STATUS "squish_server_executable='${squish_server_executable}'")
+message(STATUS "squish_client_executable='${squish_client_executable}'")
+message(STATUS "squish_libqtdir ='${squish_libqtdir}'")
+message(STATUS "squish_test_suite='${squish_test_suite}'")
+message(STATUS "squish_test_case='${squish_test_case}'")
+message(STATUS "squish_wrapper='${squish_wrapper}'")
+message(STATUS "squish_env_vars='${squish_env_vars}'")
+message(STATUS "squish_module_dir='${squish_module_dir}'")
+message(STATUS "squish_pre_command='${squish_pre_command}'")
+message(STATUS "squish_post_command='${squish_post_command}'")
+
+# parse environment variables
+foreach(i ${squish_env_vars})
+ message(STATUS "parsing env var key/value pair ${i}")
+ string(REGEX MATCH "([^=]*)=(.*)" squish_env_name ${i})
+ message(STATUS "key=${CMAKE_MATCH_1}")
+ message(STATUS "value=${CMAKE_MATCH_2}")
+ set ( ENV{${CMAKE_MATCH_1}} ${CMAKE_MATCH_2} )
+endforeach()
+
+if (QT4_INSTALLED)
+ # record Qt lib directory
+ set ( ENV{${SQUISH_LIBQTDIR}} ${squish_libqtdir} )
+endif ()
+
+if(squish_pre_command)
+ message(STATUS "Executing pre command: ${squish_pre_command}")
+ execute_process(COMMAND "${squish_pre_command}")
+endif()
+
+# run the test
+if("${squish_version}" STREQUAL "4")
+ if (WIN32)
+ execute_process(COMMAND ${squish_module_dir}/Squish4RunTestCase.bat ${squish_server_executable} ${squish_client_executable} ${squish_test_suite} ${squish_test_case} ${squish_aut} ${squish_aut_dir}
+ RESULT_VARIABLE test_rv )
+ elseif(UNIX)
+ execute_process(COMMAND ${squish_module_dir}/Squish4RunTestCase.sh ${squish_server_executable} ${squish_client_executable} ${squish_test_suite} ${squish_test_case} ${squish_aut} ${squish_aut_dir}
+ RESULT_VARIABLE test_rv )
+ endif ()
+
+else()
+
+ if (WIN32)
+ execute_process(COMMAND ${squish_module_dir}/SquishRunTestCase.bat ${squish_server_executable} ${squish_client_executable} ${squish_test_case} ${squish_wrapper} ${squish_aut}
+ RESULT_VARIABLE test_rv )
+ elseif(UNIX)
+ execute_process(COMMAND ${squish_module_dir}/SquishRunTestCase.sh ${squish_server_executable} ${squish_client_executable} ${squish_test_case} ${squish_wrapper} ${squish_aut}
+ RESULT_VARIABLE test_rv )
+ endif ()
+endif()
+
+if(squish_post_command)
+ message(STATUS "Executing post command: ${squish_post_command}")
+ execute_process(COMMAND "${squish_post_command}")
+endif()
+
+# check for an error with running the test
+if(NOT "${test_rv}" STREQUAL "0")
+ message(FATAL_ERROR "Error running Squish test")
+endif()
diff --git a/Modules/SystemInformation.cmake b/Modules/SystemInformation.cmake
new file mode 100644
index 0000000..5ecc39a
--- /dev/null
+++ b/Modules/SystemInformation.cmake
@@ -0,0 +1,93 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+cmake_minimum_required(VERSION ${CMAKE_VERSION})
+project(DumpInformation)
+
+# first get the standard information for th platform
+include_directories("This does not exists")
+get_directory_property(incl INCLUDE_DIRECTORIES)
+set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES "${DumpInformation_BINARY_DIR};${DumpInformation_SOURCE_DIR}")
+
+configure_file("${CMAKE_ROOT}/Modules/SystemInformation.in" "${RESULT_FILE}")
+
+
+file(APPEND "${RESULT_FILE}"
+ "\n=================================================================\n")
+file(APPEND "${RESULT_FILE}"
+ "=== VARIABLES\n")
+file(APPEND "${RESULT_FILE}"
+ "=================================================================\n")
+get_cmake_property(res VARIABLES)
+foreach(var ${res})
+ file(APPEND "${RESULT_FILE}" "${var} \"${${var}}\"\n")
+endforeach()
+
+file(APPEND "${RESULT_FILE}"
+ "\n=================================================================\n")
+file(APPEND "${RESULT_FILE}"
+ "=== COMMANDS\n")
+file(APPEND "${RESULT_FILE}"
+ "=================================================================\n")
+get_cmake_property(res COMMANDS)
+foreach(var ${res})
+ file(APPEND "${RESULT_FILE}" "${var}\n")
+endforeach()
+
+file(APPEND "${RESULT_FILE}"
+ "\n=================================================================\n")
+file(APPEND "${RESULT_FILE}"
+ "=== MACROS\n")
+file(APPEND "${RESULT_FILE}"
+ "=================================================================\n")
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/AllMacros.txt "")
+get_cmake_property(res MACROS)
+foreach(var ${res})
+ file(APPEND "${RESULT_FILE}" "${var}\n")
+endforeach()
+
+file(APPEND "${RESULT_FILE}"
+ "\n=================================================================\n")
+file(APPEND "${RESULT_FILE}"
+ "=== OTHER\n")
+file(APPEND "${RESULT_FILE}"
+ "=================================================================\n")
+get_directory_property(res INCLUDE_DIRECTORIES)
+foreach(var ${res})
+ file(APPEND "${RESULT_FILE}" "INCLUDE_DIRECTORY: ${var}\n")
+endforeach()
+
+get_directory_property(res LINK_DIRECTORIES)
+foreach(var ${res})
+ file(APPEND "${RESULT_FILE}" "LINK_DIRECTORIES: ${var}\n")
+endforeach()
+
+get_directory_property(res INCLUDE_REGULAR_EXPRESSION)
+file(APPEND "${RESULT_FILE}" "INCLUDE_REGULAR_EXPRESSION: ${res}\n")
+
+# include other files if they are present, such as when run from within the
+# binary tree
+macro(DUMP_FILE THE_FILE)
+ if (EXISTS "${THE_FILE}")
+ file(APPEND "${RESULT_FILE}"
+ "\n=================================================================\n")
+ file(APPEND "${RESULT_FILE}"
+ "=== ${THE_FILE}\n")
+ file(APPEND "${RESULT_FILE}"
+ "=================================================================\n")
+
+ file(READ "${THE_FILE}" FILE_CONTENTS LIMIT 50000)
+ file(APPEND "${RESULT_FILE}" "${FILE_CONTENTS}")
+ endif ()
+endmacro()
+
+DUMP_FILE("../CMakeCache.txt")
+DUMP_FILE("../CMakeFiles/CMakeOutput.log")
+DUMP_FILE("../CMakeFiles/CMakeError.log")
+DUMP_FILE("../CMakeFiles/CMakeSystem.cmake")
+
+foreach (EXTRA_FILE ${EXTRA_DUMP_FILES})
+ DUMP_FILE("${EXTRA_FILE}")
+endforeach ()
+
diff --git a/Modules/SystemInformation.in b/Modules/SystemInformation.in
new file mode 100644
index 0000000..f2aef50
--- /dev/null
+++ b/Modules/SystemInformation.in
@@ -0,0 +1,88 @@
+Avoid ctest truncation of output: CTEST_FULL_OUTPUT
+========================================================
+=== MAIN VARIABLES
+========================================================
+CMAKE_STATIC_LIBRARY_PREFIX == "${CMAKE_STATIC_LIBRARY_PREFIX}"
+CMAKE_STATIC_LIBRARY_SUFFIX == "${CMAKE_STATIC_LIBRARY_SUFFIX}"
+CMAKE_SHARED_LIBRARY_PREFIX == "${CMAKE_SHARED_LIBRARY_PREFIX}"
+CMAKE_SHARED_LIBRARY_SUFFIX == "${CMAKE_SHARED_LIBRARY_SUFFIX}"
+CMAKE_SHARED_MODULE_PREFIX == "${CMAKE_SHARED_MODULE_PREFIX}"
+CMAKE_SHARED_MODULE_SUFFIX == "${CMAKE_SHARED_MODULE_SUFFIX}"
+
+
+CMAKE_DL_LIBS == "${CMAKE_DL_LIBS}"
+CMAKE_LIBRARY_PATH_FLAG == "${CMAKE_LIBRARY_PATH_FLAG}"
+CMAKE_LINK_LIBRARY_FLAG == "${CMAKE_LINK_LIBRARY_FLAG}"
+CMAKE_SKIP_RPATH == "${CMAKE_SKIP_RPATH}"
+CMAKE_SYSTEM_INFO_FILE == "${CMAKE_SYSTEM_INFO_FILE}"
+CMAKE_SYSTEM_NAME == "${CMAKE_SYSTEM_NAME}"
+CMAKE_SYSTEM == "${CMAKE_SYSTEM}"
+CMAKE_CXX_COMPILER == "${CMAKE_CXX_COMPILER}"
+CMAKE_C_COMPILER == "${CMAKE_C_COMPILER}"
+CMAKE_COMPILER_IS_GNUCC == "${CMAKE_COMPILER_IS_GNUCC}"
+CMAKE_COMPILER_IS_GNUCXX == "${CMAKE_COMPILER_IS_GNUCXX}"
+
+// C shared library flag
+CMAKE_SHARED_LIBRARY_C_FLAGS == "${CMAKE_SHARED_LIBRARY_C_FLAGS}"
+CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS == "${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS}"
+CMAKE_SHARED_LIBRARY_LINK_FLAGS == "${CMAKE_SHARED_LIBRARY_LINK_FLAGS}"
+CMAKE_SHARED_LIBRARY_RUNTIME_FLAG == "${CMAKE_SHARED_LIBRARY_RUNTIME_FLAG}"
+CMAKE_SHARED_LIBRARY_RUNTIME_FLAG_SEP == "${CMAKE_SHARED_LIBRARY_RUNTIME_FLAG_SEP}"
+CMAKE_SHARED_LIBRARY_LINK_STATIC_C_FLAGS == "${CMAKE_SHARED_LIBRARY_LINK_STATIC_C_FLAGS}"
+CMAKE_SHARED_LIBRARY_LINK_DYNAMIC_C_FLAGS == "${CMAKE_SHARED_LIBRARY_LINK_DYNAMIC_C_FLAGS}"
+
+// C shared module flags
+CMAKE_SHARED_MODULE_C_FLAGS == "${CMAKE_SHARED_MODULE_C_FLAGS}"
+CMAKE_SHARED_MODULE_CREATE_C_FLAGS == "${CMAKE_SHARED_MODULE_CREATE_C_FLAGS}"
+CMAKE_SHARED_MODULE_LINK_STATIC_C_FLAGS == "${CMAKE_SHARED_MODULE_LINK_STATIC_C_FLAGS}"
+CMAKE_SHARED_MODULE_LINK_DYNAMIC_C_FLAGS == "${CMAKE_SHARED_MODULE_LINK_DYNAMIC_C_FLAGS}"
+
+// C exe flags
+CMAKE_EXE_LINK_STATIC_C_FLAGS == "${CMAKE_EXE_LINK_STATIC_C_FLAGS}"
+CMAKE_EXE_LINK_DYNAMIC_C_FLAGS == "${CMAKE_EXE_LINK_DYNAMIC_C_FLAGS}"
+
+// CXX shared library flags
+CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS == "${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS}"
+CMAKE_SHARED_LIBRARY_CXX_FLAGS == "${CMAKE_SHARED_LIBRARY_CXX_FLAGS}"
+CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS == "${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS}"
+CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG == "${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG}"
+CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP == "${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP}"
+CMAKE_SHARED_LIBRARY_LINK_STATIC_CXX_FLAGS == "${CMAKE_SHARED_LIBRARY_LINK_STATIC_CXX_FLAGS}"
+CMAKE_SHARED_LIBRARY_LINK_DYNAMIC_CXX_FLAGS == "${CMAKE_SHARED_LIBRARY_LINK_DYNAMIC_CXX_FLAGS}"
+
+// CXX shared module flags
+CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS == "${CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS}"
+CMAKE_SHARED_MODULE_CXX_FLAGS == "${CMAKE_SHARED_MODULE_CXX_FLAGS}"
+CMAKE_SHARED_MODULE_LINK_STATIC_CXX_FLAGS == "${CMAKE_SHARED_MODULE_LINK_STATIC_CXX_FLAGS}"
+CMAKE_SHARED_MODULE_LINK_DYNAMIC_CXX_FLAGS == "${CMAKE_SHARED_MODULE_LINK_DYNAMIC_CXX_FLAGS}"
+
+// CXX exe flags
+CMAKE_EXE_LINK_STATIC_CXX_FLAGS == "${CMAKE_EXE_LINK_STATIC_CXX_FLAGS}"
+CMAKE_EXE_LINK_DYNAMIC_CXX_FLAGS == "${CMAKE_EXE_LINK_DYNAMIC_CXX_FLAGS}"
+
+CMAKE_USER_MAKE_RULES_OVERRIDE == "${CMAKE_USER_MAKE_RULES_OVERRIDE}"
+CMAKE_VERBOSE_MAKEFILE == "${CMAKE_VERBOSE_MAKEFILE}"
+CMAKE_BUILD_TYPE == "${CMAKE_BUILD_TYPE}"
+CMAKE_CXX_FLAGS == "${CMAKE_CXX_FLAGS}"
+CMAKE_CXX_FLAGS_DEBUG == "${CMAKE_CXX_FLAGS_DEBUG}"
+CMAKE_CXX_FLAGS_MINSIZEREL == "${CMAKE_CXX_FLAGS_MINSIZEREL}"
+CMAKE_CXX_FLAGS_RELEASE == "${CMAKE_CXX_FLAGS_RELEASE}"
+CMAKE_CXX_FLAGS_RELWITHDEBINFO == "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}"
+
+CMAKE_C_FLAGS == "${CMAKE_C_FLAGS}"
+CMAKE_C_FLAGS_DEBUG == "${CMAKE_C_FLAGS_DEBUG}"
+CMAKE_C_FLAGS_MINSIZEREL == "${CMAKE_C_FLAGS_MINSIZEREL}"
+CMAKE_C_FLAGS_RELEASE == "${CMAKE_C_FLAGS_RELEASE}"
+CMAKE_C_FLAGS_RELWITHDEBINFO == "${CMAKE_C_FLAGS_RELWITHDEBINFO}"
+
+// build rules
+CMAKE_CXX_CREATE_SHARED_LIBRARY == "${CMAKE_CXX_CREATE_SHARED_LIBRARY}"
+CMAKE_CXX_CREATE_SHARED_MODULE == "${CMAKE_CXX_CREATE_SHARED_MODULE}"
+CMAKE_C_CREATE_SHARED_LIBRARY == "${CMAKE_C_CREATE_SHARED_LIBRARY}"
+CMAKE_C_CREATE_SHARED_MODULE == "${CMAKE_C_CREATE_SHARED_MODULE}"
+CMAKE_CXX_CREATE_STATIC_LIBRARY == "${CMAKE_CXX_CREATE_STATIC_LIBRARY}"
+CMAKE_C_CREATE_STATIC_LIBRARY == "${CMAKE_C_CREATE_STATIC_LIBRARY}"
+CMAKE_CXX_COMPILE_OBJECT == "${CMAKE_CXX_COMPILE_OBJECT}"
+CMAKE_C_COMPILE_OBJECT == "${CMAKE_C_COMPILE_OBJECT}"
+CMAKE_C_LINK_EXECUTABLE == "${CMAKE_C_LINK_EXECUTABLE}"
+CMAKE_CXX_LINK_EXECUTABLE == "${CMAKE_CXX_LINK_EXECUTABLE}"
diff --git a/Modules/TestBigEndian.cmake b/Modules/TestBigEndian.cmake
new file mode 100644
index 0000000..ea8ca73
--- /dev/null
+++ b/Modules/TestBigEndian.cmake
@@ -0,0 +1,143 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+TestBigEndian
+-------------
+
+.. deprecated:: 3.20
+
+ Supserseded by the :variable:`CMAKE_<LANG>_BYTE_ORDER` variable.
+
+Check if the target architecture is big endian or little endian.
+
+.. command:: test_big_endian
+
+ .. code-block:: cmake
+
+ test_big_endian(<var>)
+
+ Stores in variable ``<var>`` either 1 or 0 indicating whether the
+ target architecture is big or little endian.
+
+#]=======================================================================]
+include_guard()
+
+include(CheckTypeSize)
+
+function(TEST_BIG_ENDIAN VARIABLE)
+ if(";${CMAKE_C_BYTE_ORDER};${CMAKE_CXX_BYTE_ORDER};${CMAKE_CUDA_BYTE_ORDER};${CMAKE_OBJC_BYTE_ORDER};${CMAKE_OBJCXX_BYTE_ORDER};" MATCHES ";(BIG_ENDIAN|LITTLE_ENDIAN);")
+ set(order "${CMAKE_MATCH_1}")
+ if(order STREQUAL "BIG_ENDIAN")
+ set("${VARIABLE}" 1 PARENT_SCOPE)
+ else()
+ set("${VARIABLE}" 0 PARENT_SCOPE)
+ endif()
+ else()
+ __TEST_BIG_ENDIAN_LEGACY_IMPL(is_big)
+ set("${VARIABLE}" "${is_big}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+macro(__TEST_BIG_ENDIAN_LEGACY_IMPL VARIABLE)
+ if(NOT DEFINED HAVE_${VARIABLE})
+ message(CHECK_START "Check if the system is big endian")
+ message(CHECK_START "Searching 16 bit integer")
+
+ if(CMAKE_C_COMPILER_LOADED)
+ set(_test_language "C")
+ elseif(CMAKE_CXX_COMPILER_LOADED)
+ set(_test_language "CXX")
+ else()
+ message(FATAL_ERROR "TEST_BIG_ENDIAN needs either C or CXX language enabled")
+ endif()
+
+ CHECK_TYPE_SIZE("unsigned short" CMAKE_SIZEOF_UNSIGNED_SHORT LANGUAGE ${_test_language})
+ if(CMAKE_SIZEOF_UNSIGNED_SHORT EQUAL 2)
+ message(CHECK_PASS "Using unsigned short")
+ set(CMAKE_16BIT_TYPE "unsigned short")
+ else()
+ CHECK_TYPE_SIZE("unsigned int" CMAKE_SIZEOF_UNSIGNED_INT LANGUAGE ${_test_language})
+ if(CMAKE_SIZEOF_UNSIGNED_INT)
+ message(CHECK_PASS "Using unsigned int")
+ set(CMAKE_16BIT_TYPE "unsigned int")
+
+ else()
+
+ CHECK_TYPE_SIZE("unsigned long" CMAKE_SIZEOF_UNSIGNED_LONG LANGUAGE ${_test_language})
+ if(CMAKE_SIZEOF_UNSIGNED_LONG)
+ message(CHECK_PASS "Using unsigned long")
+ set(CMAKE_16BIT_TYPE "unsigned long")
+ else()
+ message(FATAL_ERROR "no suitable type found")
+ endif()
+
+ endif()
+
+ endif()
+
+ if(_test_language STREQUAL "CXX")
+ set(_test_file "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/TestEndianess.cpp")
+ else()
+ set(_test_file "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/TestEndianess.c")
+ endif()
+
+ configure_file("${CMAKE_ROOT}/Modules/TestEndianess.c.in"
+ ${_test_file}
+ @ONLY)
+
+ file(READ ${_test_file} TEST_ENDIANESS_FILE_CONTENT)
+
+ try_compile(HAVE_${VARIABLE}
+ "${CMAKE_BINARY_DIR}"
+ ${_test_file}
+ OUTPUT_VARIABLE OUTPUT
+ COPY_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestEndianess.bin" )
+
+ if(HAVE_${VARIABLE})
+
+ file(STRINGS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestEndianess.bin"
+ CMAKE_TEST_ENDIANESS_STRINGS_LE LIMIT_COUNT 1 REGEX "THIS IS LITTLE ENDIAN")
+
+ file(STRINGS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestEndianess.bin"
+ CMAKE_TEST_ENDIANESS_STRINGS_BE LIMIT_COUNT 1 REGEX "THIS IS BIG ENDIAN")
+
+ # on mac, if there are universal binaries built both will be true
+ # return the result depending on the machine on which cmake runs
+ if(CMAKE_TEST_ENDIANESS_STRINGS_BE AND CMAKE_TEST_ENDIANESS_STRINGS_LE)
+ if(CMAKE_SYSTEM_PROCESSOR MATCHES powerpc)
+ set(CMAKE_TEST_ENDIANESS_STRINGS_BE TRUE)
+ set(CMAKE_TEST_ENDIANESS_STRINGS_LE FALSE)
+ else()
+ set(CMAKE_TEST_ENDIANESS_STRINGS_BE FALSE)
+ set(CMAKE_TEST_ENDIANESS_STRINGS_LE TRUE)
+ endif()
+ message(STATUS "TEST_BIG_ENDIAN found different results, consider setting CMAKE_OSX_ARCHITECTURES or CMAKE_TRY_COMPILE_OSX_ARCHITECTURES to one or no architecture !")
+ endif()
+
+ if(CMAKE_TEST_ENDIANESS_STRINGS_LE)
+ set(${VARIABLE} 0 CACHE INTERNAL "Result of TEST_BIG_ENDIAN" FORCE)
+ message(CHECK_PASS "little endian")
+ endif()
+
+ if(CMAKE_TEST_ENDIANESS_STRINGS_BE)
+ set(${VARIABLE} 1 CACHE INTERNAL "Result of TEST_BIG_ENDIAN" FORCE)
+ message(CHECK_PASS "big endian")
+ endif()
+
+ if(NOT CMAKE_TEST_ENDIANESS_STRINGS_BE AND NOT CMAKE_TEST_ENDIANESS_STRINGS_LE)
+ message(CHECK_FAIL "TEST_BIG_ENDIAN found no result!")
+ message(SEND_ERROR "TEST_BIG_ENDIAN found no result!")
+ endif()
+
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the system is big endian passed with the following output:\n${OUTPUT}\nTestEndianess.c:\n${TEST_ENDIANESS_FILE_CONTENT}\n\n")
+
+ else()
+ message(CHECK_FAIL "failed")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the system is big endian failed with the following output:\n${OUTPUT}\nTestEndianess.c:\n${TEST_ENDIANESS_FILE_CONTENT}\n\n")
+ set(${VARIABLE})
+ endif()
+ endif()
+endmacro()
diff --git a/Modules/TestCXXAcceptsFlag.cmake b/Modules/TestCXXAcceptsFlag.cmake
new file mode 100644
index 0000000..ce505f3
--- /dev/null
+++ b/Modules/TestCXXAcceptsFlag.cmake
@@ -0,0 +1,44 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+TestCXXAcceptsFlag
+------------------
+
+.. deprecated:: 3.0
+
+ See :module:`CheckCXXCompilerFlag`.
+
+Check if the CXX compiler accepts a flag.
+
+.. code-block:: cmake
+
+ CHECK_CXX_ACCEPTS_FLAG(<flags> <variable>)
+
+``<flags>``
+ the flags to try
+``<variable>``
+ variable to store the result
+#]=======================================================================]
+
+macro(CHECK_CXX_ACCEPTS_FLAG FLAGS VARIABLE)
+ if(NOT DEFINED ${VARIABLE})
+ message(CHECK_START "Checking to see if CXX compiler accepts flag ${FLAGS}")
+ try_compile(${VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_ROOT}/Modules/DummyCXXFile.cxx
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${FLAGS}
+ OUTPUT_VARIABLE OUTPUT)
+ if(${VARIABLE})
+ message(CHECK_PASS "yes")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the CXX compiler accepts the flag ${FLAGS} passed with "
+ "the following output:\n${OUTPUT}\n\n")
+ else()
+ message(CHECK_FAIL "no")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the CXX compiler accepts the flag ${FLAGS} failed with "
+ "the following output:\n${OUTPUT}\n\n")
+ endif()
+ endif()
+endmacro()
diff --git a/Modules/TestEndianess.c.in b/Modules/TestEndianess.c.in
new file mode 100644
index 0000000..c924f78
--- /dev/null
+++ b/Modules/TestEndianess.c.in
@@ -0,0 +1,23 @@
+/* A 16 bit integer is required. */
+typedef @CMAKE_16BIT_TYPE@ cmakeint16;
+
+/* On a little endian machine, these 16bit ints will give "THIS IS LITTLE ENDIAN."
+ On a big endian machine the characters will be exchanged pairwise. */
+const cmakeint16 info_little[] = {0x4854, 0x5349, 0x4920, 0x2053, 0x494c, 0x5454, 0x454c, 0x4520, 0x444e, 0x4149, 0x2e4e, 0x0000};
+
+/* on a big endian machine, these 16bit ints will give "THIS IS BIG ENDIAN."
+ On a little endian machine the characters will be exchanged pairwise. */
+const cmakeint16 info_big[] = {0x5448, 0x4953, 0x2049, 0x5320, 0x4249, 0x4720, 0x454e, 0x4449, 0x414e, 0x2e2e, 0x0000};
+
+#ifdef __CLASSIC_C__
+int main(argc, argv) int argc; char *argv[];
+#else
+int main(int argc, char *argv[])
+#endif
+{
+ int require = 0;
+ require += info_little[argc];
+ require += info_big[argc];
+ (void)argv;
+ return require;
+}
diff --git a/Modules/TestForANSIForScope.cmake b/Modules/TestForANSIForScope.cmake
new file mode 100644
index 0000000..0f2dc01
--- /dev/null
+++ b/Modules/TestForANSIForScope.cmake
@@ -0,0 +1,43 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+TestForANSIForScope
+-------------------
+
+Check for ANSI for scope support
+
+Check if the compiler restricts the scope of variables declared in a
+for-init-statement to the loop body.
+
+::
+
+ CMAKE_NO_ANSI_FOR_SCOPE - holds result
+#]=======================================================================]
+
+if(NOT DEFINED CMAKE_ANSI_FOR_SCOPE)
+ message(CHECK_START "Check for ANSI scope")
+ try_compile(CMAKE_ANSI_FOR_SCOPE ${CMAKE_BINARY_DIR}
+ ${CMAKE_ROOT}/Modules/TestForAnsiForScope.cxx
+ OUTPUT_VARIABLE OUTPUT)
+ if (CMAKE_ANSI_FOR_SCOPE)
+ message(CHECK_PASS "found")
+ set (CMAKE_NO_ANSI_FOR_SCOPE 0 CACHE INTERNAL
+ "Does the compiler support ansi for scope.")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the CXX compiler understands ansi for scopes passed with "
+ "the following output:\n${OUTPUT}\n\n")
+ else ()
+ message(CHECK_FAIL "not found")
+ set (CMAKE_NO_ANSI_FOR_SCOPE 1 CACHE INTERNAL
+ "Does the compiler support ansi for scope.")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the CXX compiler understands ansi for scopes failed with "
+ "the following output:\n${OUTPUT}\n\n")
+ endif ()
+endif()
+
+
+
+
+
diff --git a/Modules/TestForANSIStreamHeaders.cmake b/Modules/TestForANSIStreamHeaders.cmake
new file mode 100644
index 0000000..e532a71
--- /dev/null
+++ b/Modules/TestForANSIStreamHeaders.cmake
@@ -0,0 +1,33 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+TestForANSIStreamHeaders
+------------------------
+
+Test for compiler support of ANSI stream headers iostream, etc.
+
+check if the compiler supports the standard ANSI iostream header
+(without the .h)
+
+::
+
+ CMAKE_NO_ANSI_STREAM_HEADERS - defined by the results
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/CheckIncludeFileCXX.cmake)
+
+if(NOT CMAKE_NO_ANSI_STREAM_HEADERS)
+ CHECK_INCLUDE_FILE_CXX(iostream CMAKE_ANSI_STREAM_HEADERS)
+ if (CMAKE_ANSI_STREAM_HEADERS)
+ set (CMAKE_NO_ANSI_STREAM_HEADERS 0 CACHE INTERNAL
+ "Does the compiler support headers like iostream.")
+ else ()
+ set (CMAKE_NO_ANSI_STREAM_HEADERS 1 CACHE INTERNAL
+ "Does the compiler support headers like iostream.")
+ endif ()
+
+ mark_as_advanced(CMAKE_NO_ANSI_STREAM_HEADERS)
+endif()
+
+
diff --git a/Modules/TestForANSIStreamHeaders.cxx b/Modules/TestForANSIStreamHeaders.cxx
new file mode 100644
index 0000000..d314d58
--- /dev/null
+++ b/Modules/TestForANSIStreamHeaders.cxx
@@ -0,0 +1,6 @@
+#include <iostream>
+
+int main(int, char* [])
+{
+ return 0;
+}
diff --git a/Modules/TestForAnsiForScope.cxx b/Modules/TestForAnsiForScope.cxx
new file mode 100644
index 0000000..4bc2c67
--- /dev/null
+++ b/Modules/TestForAnsiForScope.cxx
@@ -0,0 +1,8 @@
+int main(int, char* [])
+{
+ int i;
+ for (int i = 0; i < 1; ++i)
+ ;
+ (void)i;
+ return 0;
+}
diff --git a/Modules/TestForSSTREAM.cmake b/Modules/TestForSSTREAM.cmake
new file mode 100644
index 0000000..545b7ec
--- /dev/null
+++ b/Modules/TestForSSTREAM.cmake
@@ -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.
+
+#[=======================================================================[.rst:
+TestForSSTREAM
+--------------
+
+Test for compiler support of ANSI sstream header
+
+check if the compiler supports the standard ANSI sstream header
+
+::
+
+ CMAKE_NO_ANSI_STRING_STREAM - defined by the results
+#]=======================================================================]
+
+if(NOT DEFINED CMAKE_HAS_ANSI_STRING_STREAM)
+ message(CHECK_START "Check for sstream")
+ try_compile(CMAKE_HAS_ANSI_STRING_STREAM ${CMAKE_BINARY_DIR}
+ ${CMAKE_ROOT}/Modules/TestForSSTREAM.cxx
+ OUTPUT_VARIABLE OUTPUT)
+ if (CMAKE_HAS_ANSI_STRING_STREAM)
+ message(CHECK_PASS "found")
+ set (CMAKE_NO_ANSI_STRING_STREAM 0 CACHE INTERNAL
+ "Does the compiler support sstream")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the CXX compiler has sstream passed with "
+ "the following output:\n${OUTPUT}\n\n")
+ else ()
+ message(CHECK_FAIL "not found")
+ set (CMAKE_NO_ANSI_STRING_STREAM 1 CACHE INTERNAL
+ "Does the compiler support sstream")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the CXX compiler has sstream failed with "
+ "the following output:\n${OUTPUT}\n\n")
+ endif ()
+endif()
+
+
+
+
diff --git a/Modules/TestForSSTREAM.cxx b/Modules/TestForSSTREAM.cxx
new file mode 100644
index 0000000..83a75e4
--- /dev/null
+++ b/Modules/TestForSSTREAM.cxx
@@ -0,0 +1,10 @@
+#include <sstream>
+int main(int, char* [])
+{
+ std::ostringstream os;
+ os << "12345";
+ if (os.str().size() == 5) {
+ return 0;
+ }
+ return -1;
+}
diff --git a/Modules/TestForSTDNamespace.cmake b/Modules/TestForSTDNamespace.cmake
new file mode 100644
index 0000000..d101c83
--- /dev/null
+++ b/Modules/TestForSTDNamespace.cmake
@@ -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.
+
+#[=======================================================================[.rst:
+TestForSTDNamespace
+-------------------
+
+Test for std:: namespace support
+
+check if the compiler supports std:: on stl classes
+
+::
+
+ CMAKE_NO_STD_NAMESPACE - defined by the results
+#]=======================================================================]
+
+if(NOT DEFINED CMAKE_STD_NAMESPACE)
+ message(CHECK_START "Check for STD namespace")
+ try_compile(CMAKE_STD_NAMESPACE ${CMAKE_BINARY_DIR}
+ ${CMAKE_ROOT}/Modules/TestForSTDNamespace.cxx
+ OUTPUT_VARIABLE OUTPUT)
+ if (CMAKE_STD_NAMESPACE)
+ message(CHECK_PASS "found")
+ set (CMAKE_NO_STD_NAMESPACE 0 CACHE INTERNAL
+ "Does the compiler support std::.")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the CXX compiler has std namespace passed with "
+ "the following output:\n${OUTPUT}\n\n")
+ else ()
+ message(CHECK_FAIL "not found")
+ set (CMAKE_NO_STD_NAMESPACE 1 CACHE INTERNAL
+ "Does the compiler support std::.")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the CXX compiler has std namespace failed with "
+ "the following output:\n${OUTPUT}\n\n")
+ endif ()
+endif()
+
+
+
+
diff --git a/Modules/TestForSTDNamespace.cxx b/Modules/TestForSTDNamespace.cxx
new file mode 100644
index 0000000..62951ff
--- /dev/null
+++ b/Modules/TestForSTDNamespace.cxx
@@ -0,0 +1,6 @@
+#include <list>
+int main(int, char* [])
+{
+ std::list<int>();
+ return 0;
+}
diff --git a/Modules/UseEcos.cmake b/Modules/UseEcos.cmake
new file mode 100644
index 0000000..83c9b20
--- /dev/null
+++ b/Modules/UseEcos.cmake
@@ -0,0 +1,236 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+UseEcos
+-------
+
+This module defines variables and macros required to build eCos application.
+
+This file contains the following macros:
+ECOS_ADD_INCLUDE_DIRECTORIES() - add the eCos include dirs
+ECOS_ADD_EXECUTABLE(name source1 ... sourceN ) - create an eCos
+executable ECOS_ADJUST_DIRECTORY(VAR source1 ... sourceN ) - adjusts
+the path of the source files and puts the result into VAR
+
+Macros for selecting the toolchain: ECOS_USE_ARM_ELF_TOOLS() - enable
+the ARM ELF toolchain for the directory where it is called
+ECOS_USE_I386_ELF_TOOLS() - enable the i386 ELF toolchain for the
+directory where it is called ECOS_USE_PPC_EABI_TOOLS() - enable the
+PowerPC toolchain for the directory where it is called
+
+It contains the following variables: ECOS_DEFINITIONS
+ECOSCONFIG_EXECUTABLE ECOS_CONFIG_FILE - defaults to ecos.ecc, if your
+eCos configuration file has a different name, adjust this variable for
+internal use only:
+
+::
+
+ ECOS_ADD_TARGET_LIB
+#]=======================================================================]
+
+# first check that ecosconfig is available
+find_program(ECOSCONFIG_EXECUTABLE NAMES ecosconfig)
+if(NOT ECOSCONFIG_EXECUTABLE)
+ message(SEND_ERROR "ecosconfig was not found. Either include it in the system path or set it manually using ccmake.")
+else()
+ message(STATUS "Found ecosconfig: ${ECOSCONFIG_EXECUTABLE}")
+endif()
+
+# check that ECOS_REPOSITORY is set correctly
+if (NOT EXISTS $ENV{ECOS_REPOSITORY}/ecos.db)
+ message(SEND_ERROR "The environment variable ECOS_REPOSITORY is not set correctly. Set it to the directory which contains the file ecos.db")
+else ()
+ message(STATUS "ECOS_REPOSITORY is set to $ENV{ECOS_REPOSITORY}")
+endif ()
+
+# check that tclsh (coming with TCL) is available, otherwise ecosconfig doesn't work
+find_package(Tclsh)
+if (NOT TCL_TCLSH)
+ message(SEND_ERROR "The TCL tclsh was not found. Please install TCL, it is required for building eCos applications.")
+else ()
+ message(STATUS "tlcsh found: ${TCL_TCLSH}")
+endif ()
+
+#add the globale include-diretories
+#usage: ECOS_ADD_INCLUDE_DIRECTORIES()
+macro(ECOS_ADD_INCLUDE_DIRECTORIES)
+#check for ProjectSources.txt one level higher
+ if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../ProjectSources.txt)
+ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../)
+ else ()
+ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/)
+ endif ()
+
+#the ecos include directory
+ include_directories(${CMAKE_CURRENT_BINARY_DIR}/ecos/install/include/)
+
+endmacro()
+
+
+#we want to compile for the xscale processor, in this case the following macro has to be called
+#usage: ECOS_USE_ARM_ELF_TOOLS()
+macro (ECOS_USE_ARM_ELF_TOOLS)
+ set(CMAKE_CXX_COMPILER "arm-elf-c++")
+ set(CMAKE_COMPILER_IS_GNUCXX 1)
+ set(CMAKE_C_COMPILER "arm-elf-gcc")
+ set(CMAKE_AR "arm-elf-ar")
+ set(CMAKE_RANLIB "arm-elf-ranlib")
+#for linking
+ set(ECOS_LD_MCPU "-mcpu=xscale")
+#for compiling
+ add_definitions(-mcpu=xscale -mapcs-frame)
+#for the obj-tools
+ set(ECOS_ARCH_PREFIX "arm-elf-")
+endmacro ()
+
+#usage: ECOS_USE_PPC_EABI_TOOLS()
+macro (ECOS_USE_PPC_EABI_TOOLS)
+ set(CMAKE_CXX_COMPILER "powerpc-eabi-c++")
+ set(CMAKE_COMPILER_IS_GNUCXX 1)
+ set(CMAKE_C_COMPILER "powerpc-eabi-gcc")
+ set(CMAKE_AR "powerpc-eabi-ar")
+ set(CMAKE_RANLIB "powerpc-eabi-ranlib")
+#for linking
+ set(ECOS_LD_MCPU "")
+#for compiling
+ add_definitions()
+#for the obj-tools
+ set(ECOS_ARCH_PREFIX "powerpc-eabi-")
+endmacro ()
+
+#usage: ECOS_USE_I386_ELF_TOOLS()
+macro (ECOS_USE_I386_ELF_TOOLS)
+ set(CMAKE_CXX_COMPILER "i386-elf-c++")
+ set(CMAKE_COMPILER_IS_GNUCXX 1)
+ set(CMAKE_C_COMPILER "i386-elf-gcc")
+ set(CMAKE_AR "i386-elf-ar")
+ set(CMAKE_RANLIB "i386-elf-ranlib")
+#for linking
+ set(ECOS_LD_MCPU "")
+#for compiling
+ add_definitions()
+#for the obj-tools
+ set(ECOS_ARCH_PREFIX "i386-elf-")
+endmacro ()
+
+
+#since the actual sources are located one level upwards
+#a "../" has to be prepended in front of every source file
+#call the following macro to achieve this, the first parameter
+#is the name of the new list of source files with adjusted paths,
+#followed by all source files
+#usage: ECOS_ADJUST_DIRECTORY(adjusted_SRCS ${my_srcs})
+macro(ECOS_ADJUST_DIRECTORY _target_FILES )
+ foreach (_current_FILE ${ARGN})
+ get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE)
+ if (NOT ${_abs_FILE} STREQUAL ${_current_FILE})
+ get_filename_component(_abs_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../${_current_FILE} ABSOLUTE)
+ endif ()
+ list(APPEND ${_target_FILES} ${_abs_FILE})
+ endforeach ()
+endmacro()
+
+# the default ecos config file name
+# maybe in future also out-of-source builds may be possible
+set(ECOS_CONFIG_FILE ecos.ecc)
+
+#creates the dependency from all source files on the ecos target.ld,
+#adds the command for compiling ecos
+macro(ECOS_ADD_TARGET_LIB)
+# when building out-of-source, create the ecos/ subdir
+ if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/ecos)
+ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ecos)
+ endif()
+
+#sources depend on target.ld
+ set_source_files_properties(
+ ${ARGN}
+ PROPERTIES
+ OBJECT_DEPENDS
+ ${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib/target.ld
+ )
+
+ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib/target.ld
+ COMMAND sh -c \"make -C ${CMAKE_CURRENT_BINARY_DIR}/ecos || exit -1\; if [ -e ${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib/target.ld ] \; then touch ${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib/target.ld\; fi\"
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ecos/makefile
+ )
+
+ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ecos/makefile
+ COMMAND sh -c \" cd ${CMAKE_CURRENT_BINARY_DIR}/ecos\; ${ECOSCONFIG_EXECUTABLE} --config=${CMAKE_CURRENT_SOURCE_DIR}/ecos/${ECOS_CONFIG_FILE} tree || exit -1\;\"
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ecos/${ECOS_CONFIG_FILE}
+ )
+
+ add_custom_target( ecos make -C ${CMAKE_CURRENT_BINARY_DIR}/ecos/ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ecos/makefile )
+endmacro()
+
+# get the directory of the current file, used later on in the file
+get_filename_component( ECOS_CMAKE_MODULE_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
+
+#macro for creating an executable ecos application
+#the first parameter is the name of the executable,
+#the second is the list of all source files (where the path
+#has been adjusted beforehand by calling ECOS_ADJUST_DIRECTORY()
+#usage: ECOS_ADD_EXECUTABLE(my_app ${adjusted_SRCS})
+macro(ECOS_ADD_EXECUTABLE _exe_NAME )
+ #definitions, valid for all ecos projects
+ #the optimization and "-g" for debugging has to be enabled
+ #in the project-specific CMakeLists.txt
+ add_definitions(-D__ECOS__=1 -D__ECOS=1)
+ set(ECOS_DEFINITIONS -Wall -Wno-long-long -pipe -fno-builtin)
+
+#the executable depends on ecos target.ld
+ ECOS_ADD_TARGET_LIB(${ARGN})
+
+# when using nmake makefiles, the custom buildtype suppresses the default cl.exe flags
+# and the rules for creating objects are adjusted for gcc
+ set(CMAKE_BUILD_TYPE CUSTOM_ECOS_BUILD)
+ set(CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+ set(CMAKE_CXX_COMPILE_OBJECT "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+# special link commands for ecos-executables
+ set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <CMAKE_CXX_LINK_FLAGS> <OBJECTS> -o <TARGET> ${_ecos_EXTRA_LIBS} -nostdlib -nostartfiles -L${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib -Ttarget.ld ${ECOS_LD_MCPU}")
+ set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <CMAKE_C_LINK_FLAGS> <OBJECTS> -o <TARGET> ${_ecos_EXTRA_LIBS} -nostdlib -nostartfiles -L${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib -Ttarget.ld ${ECOS_LD_MCPU}")
+# some strict compiler flags
+ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-prototypes")
+ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual -fno-rtti -Wctor-dtor-privacy -fno-strict-aliasing -fno-exceptions")
+
+ add_executable(${_exe_NAME} ${ARGN})
+ set_target_properties(${_exe_NAME} PROPERTIES SUFFIX ".elf")
+
+#create a binary file
+ add_custom_command(
+ TARGET ${_exe_NAME}
+ POST_BUILD
+ COMMAND ${ECOS_ARCH_PREFIX}objcopy
+ ARGS -O binary ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.bin
+ )
+
+#and an srec file
+ add_custom_command(
+ TARGET ${_exe_NAME}
+ POST_BUILD
+ COMMAND ${ECOS_ARCH_PREFIX}objcopy
+ ARGS -O srec ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.srec
+ )
+
+#add the created files to the clean-files
+ set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.bin"
+ "${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.srec"
+ "${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst")
+
+ add_custom_target(ecosclean ${CMAKE_COMMAND} -DECOS_DIR=${CMAKE_CURRENT_BINARY_DIR}/ecos/ -P ${ECOS_CMAKE_MODULE_DIR}/ecos_clean.cmake )
+ add_custom_target(normalclean ${CMAKE_MAKE_PROGRAM} clean WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ add_dependencies (ecosclean normalclean)
+
+
+ add_custom_target( listing
+ COMMAND echo -e \"\\n--- Symbols sorted by address ---\\n\" > ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
+ COMMAND ${ECOS_ARCH_PREFIX}nm -S -C -n ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
+ COMMAND echo -e \"\\n--- Symbols sorted by size ---\\n\" >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
+ COMMAND ${ECOS_ARCH_PREFIX}nm -S -C -r --size-sort ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
+ COMMAND echo -e \"\\n--- Full assembly listing ---\\n\" >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst
+ COMMAND ${ECOS_ARCH_PREFIX}objdump -S -x -d -C ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.elf >> ${CMAKE_CURRENT_BINARY_DIR}/${_exe_NAME}.lst )
+
+endmacro()
+
diff --git a/Modules/UseJava.cmake b/Modules/UseJava.cmake
new file mode 100644
index 0000000..120a54c
--- /dev/null
+++ b/Modules/UseJava.cmake
@@ -0,0 +1,1505 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+UseJava
+-------
+
+Use Module for Java
+
+This file provides functions for Java. It is assumed that
+:module:`FindJava` has already been loaded. See :module:`FindJava` for
+information on how to load Java into your CMake project.
+
+Creating And Installing JARs
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ add_jar(<target_name>
+ [SOURCES] <source1> [<source2>...] [<resource1>...]
+ [INCLUDE_JARS <jar1> [<jar2>...]]
+ [ENTRY_POINT <entry>]
+ [VERSION <version>]
+ [OUTPUT_NAME <name>]
+ [OUTPUT_DIR <dir>]
+ [GENERATE_NATIVE_HEADERS <target>
+ [DESTINATION (<dir>|INSTALL <dir> [BUILD <dir>])]]
+ )
+
+This command creates a ``<target_name>.jar``. It compiles the given
+``<source>`` files and adds the given ``<resource>`` files to
+the jar file. Source files can be java files or listing files
+(prefixed by ``@``). If only resource files are given then just a jar file
+is created. The list of ``INCLUDE_JARS`` are added to the classpath when
+compiling the java sources and also to the dependencies of the target.
+``INCLUDE_JARS`` also accepts other target names created by ``add_jar()``.
+For backwards compatibility, jar files listed as sources are ignored (as
+they have been since the first version of this module).
+
+.. versionadded:: 3.4
+ Support for response files (prefixed by ``@``) in the ``SOURCES`` list.
+
+The default ``OUTPUT_DIR`` can also be changed by setting the variable
+``CMAKE_JAVA_TARGET_OUTPUT_DIR``.
+
+.. versionadded:: 3.11
+ Optionally, using option ``GENERATE_NATIVE_HEADERS``, native header files can
+ be generated for methods declared as native. These files provide the
+ connective glue that allow your Java and C code to interact. An INTERFACE
+ target will be created for an easy usage of generated files. Sub-option
+ ``DESTINATION`` can be used to specify the output directory for generated
+ header files.
+
+ ``GENERATE_NATIVE_HEADERS`` option requires, at least, version 1.8 of the JDK.
+
+.. versionadded:: 3.20
+ ``DESTINATION`` sub-option now supports the possibility to specify different
+ output directories for ``BUILD`` and ``INSTALL`` steps. This is required to
+ export the interface target generated by ``GENERATE_NATIVE_HEADERS`` option.
+ If ``BUILD`` directory is not specified, a default directory will be used.
+
+The ``add_jar()`` function sets the following target properties on
+``<target_name>``:
+
+``INSTALL_FILES``
+ The files which should be installed. This is used by ``install_jar()``.
+``JNI_SYMLINK``
+ The JNI symlink which should be installed. This is used by
+ ``install_jni_symlink()``.
+``JAR_FILE``
+ The location of the jar file so that you can include it.
+``CLASSDIR``
+ The directory where the class files can be found. For example to use them
+ with ``javah``.
+
+.. versionadded:: 3.20
+ The target generated by option ``GENERATE_NATIVE_HEADERS`` has the property
+ ``NATIVE_HEADERS_DIRECTORY`` which specify the directory holding the native
+ headers.
+
+.. code-block:: cmake
+
+ install_jar(<target_name> <destination>)
+ install_jar(<target_name> DESTINATION <destination> [COMPONENT <component>])
+
+This command installs the ``<target_name>`` files to the given
+``<destination>``. It should be called in the same scope as ``add_jar()`` or
+it will fail.
+
+The ``install_jar()`` function sets the ``INSTALL_DESTINATION`` target
+property on jars so installed. This property holds the ``<destination>`` as
+described above, and is used by ``install_jar_exports()``. You can get this
+information with :command:`get_property` and the ``INSTALL_DESTINATION``
+property key.
+
+.. versionadded:: 3.4
+ The second signature with ``DESTINATION`` and ``COMPONENT`` options.
+
+.. code-block:: cmake
+
+ install_jni_symlink(<target_name> <destination>)
+ install_jni_symlink(<target_name> DESTINATION <destination> [COMPONENT <component>])
+
+This command installs the ``<target_name>`` JNI symlinks to the given
+``<destination>``. It should be called in the same scope as ``add_jar()`` or
+it will fail.
+
+.. versionadded:: 3.4
+ The second signature with ``DESTINATION`` and ``COMPONENT`` options.
+
+Exporting JAR Targets
+^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.7
+
+.. code-block:: cmake
+
+ install_jar_exports(TARGETS <jars>...
+ [NAMESPACE <namespace>]
+ FILE <filename>
+ DESTINATION <destination> [COMPONENT <component>])
+
+This command installs a target export file ``<filename>`` for the named jar
+targets to the given ``<destination>`` directory. Its function is similar to
+that of :command:`install(EXPORTS)`.
+
+.. versionadded:: 3.9
+ The ``NAMESPACE`` option.
+
+.. code-block:: cmake
+
+ export_jars(TARGETS <jars>...
+ [NAMESPACE <namespace>]
+ FILE <filename>)
+
+This command writes a target export file ``<filename>`` for the named ``<jars>``
+targets. Its function is similar to that of :command:`export`.
+
+.. versionadded:: 3.9
+ The ``NAMESPACE`` option.
+
+
+Examples
+""""""""
+
+To add compile flags to the target you can set these flags with the following
+variable:
+
+.. code-block:: cmake
+
+ set(CMAKE_JAVA_COMPILE_FLAGS -nowarn)
+
+
+To add a path or a jar file to the class path you can do this with the
+``CMAKE_JAVA_INCLUDE_PATH`` variable.
+
+.. code-block:: cmake
+
+ set(CMAKE_JAVA_INCLUDE_PATH /usr/share/java/shibboleet.jar)
+
+To use a different output name for the target you can set it with:
+
+.. code-block:: cmake
+
+ add_jar(foobar foobar.java OUTPUT_NAME shibboleet.jar)
+
+To use a different output directory than ``CMAKE_CURRENT_BINARY_DIR`` you can
+set it with:
+
+.. code-block:: cmake
+
+ add_jar(foobar foobar.java OUTPUT_DIR ${PROJECT_BINARY_DIR}/bin)
+
+To define an entry point in your jar you can set it with the ``ENTRY_POINT``
+named argument:
+
+.. code-block:: cmake
+
+ add_jar(example ENTRY_POINT com/examples/MyProject/Main)
+
+To define a custom manifest for the jar, you can set it with the ``MANIFEST``
+named argument:
+
+.. code-block:: cmake
+
+ add_jar(example MANIFEST /path/to/manifest)
+
+To add a version to the target output name you can set it using the ``VERSION``
+named argument to ``add_jar()``. The following example will create a jar file
+with the name ``shibboleet-1.0.0.jar`` and will create a symlink
+``shibboleet.jar`` pointing to the jar with the version information.
+
+.. code-block:: cmake
+
+ add_jar(shibboleet shibbotleet.java VERSION 1.2.0)
+
+If the target is a JNI library, utilize the following commands to
+create a JNI symbolic link:
+
+.. code-block:: cmake
+
+ set(CMAKE_JNI_TARGET TRUE)
+ add_jar(shibboleet shibbotleet.java VERSION 1.2.0)
+ install_jar(shibboleet ${LIB_INSTALL_DIR}/shibboleet)
+ install_jni_symlink(shibboleet ${JAVA_LIB_INSTALL_DIR})
+
+If a single target needs to produce more than one jar from its
+java source code, to prevent the accumulation of duplicate class
+files in subsequent jars, set/reset ``CMAKE_JAR_CLASSES_PREFIX`` prior
+to calling the ``add_jar()`` function:
+
+.. code-block:: cmake
+
+ set(CMAKE_JAR_CLASSES_PREFIX com/redhat/foo)
+ add_jar(foo foo.java)
+
+ set(CMAKE_JAR_CLASSES_PREFIX com/redhat/bar)
+ add_jar(bar bar.java)
+
+For an optimum usage of option ``GENERATE_NATIVE_HEADERS``, it is recommended to
+include module JNI before any call to ``add_jar()``. The produced target for
+native headers can then be used to compile C/C++ sources with the
+:command:`target_link_libraries` command.
+
+.. code-block:: cmake
+
+ find_package(JNI)
+ add_jar(foo foo.java GENERATE_NATIVE_HEADERS foo-native)
+ add_library(bar bar.cpp)
+ target_link_libraries(bar PRIVATE foo-native)
+
+.. versionadded:: 3.20
+ It is now possible to export the target generated by
+ ``GENERATE_NATIVE_HEADERS`` option.
+
+ .. code-block:: cmake
+
+ add_jar(foo foo.java GENERATE_NATIVE_HEADERS foo-native
+ DESTINATION INSTALL include)
+ install(TARGETS foo-native EXPORT native)
+ install(DIRECTORY "$<TARGET_PROPERTY:foo-native,NATIVE_HEADERS_DIRECTORY>/"
+ DESTINATION include)
+ install(EXPORT native DESTINATION /to/export NAMESPACE foo)
+
+Finding JARs
+^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ find_jar(<VAR>
+ <name> | NAMES <name1> [<name2>...]
+ [PATHS <path1> [<path2>... ENV <var>]]
+ [VERSIONS <version1> [<version2>]]
+ [DOC "cache documentation string"]
+ )
+
+This command is used to find a full path to the named jar. A cache
+entry named by ``<VAR>`` is created to store the result of this command.
+If the full path to a jar is found the result is stored in the
+variable and the search will not repeated unless the variable is
+cleared. If nothing is found, the result will be ``<VAR>-NOTFOUND``, and
+the search will be attempted again next time ``find_jar()`` is invoked with
+the same variable. The name of the full path to a file that is
+searched for is specified by the names listed after ``NAMES`` argument.
+Additional search locations can be specified after the ``PATHS`` argument.
+If you require special a version of a jar file you can specify it with
+the ``VERSIONS`` argument. The argument after ``DOC`` will be used for the
+documentation string in the cache.
+
+
+Javadoc
+^^^^^^^
+
+The ``create_javadoc()`` command can be used to create java documentation
+based on files or packages. For more details please read the javadoc manpage.
+
+There are two main signatures for ``create_javadoc()``. The first signature
+works with package names on a path with source files.
+
+.. code-block:: cmake
+
+ create_javadoc(<VAR>
+ PACKAGES <pkg1> [<pkg2>...]
+ [SOURCEPATH <sourcepath>]
+ [CLASSPATH <classpath>]
+ [INSTALLPATH <install path>]
+ [DOCTITLE "the documentation title"]
+ [WINDOWTITLE "the title of the document"]
+ [AUTHOR TRUE|FALSE]
+ [USE TRUE|FALSE]
+ [VERSION TRUE|FALSE]
+ )
+
+For example:
+
+.. code-block:: cmake
+
+ create_javadoc(my_example_doc
+ PACKAGES com.example.foo com.example.bar
+ SOURCEPATH "${CMAKE_CURRENT_SOURCE_DIR}"
+ CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
+ WINDOWTITLE "My example"
+ DOCTITLE "<h1>My example</h1>"
+ AUTHOR TRUE
+ USE TRUE
+ VERSION TRUE
+ )
+
+The second signature for ``create_javadoc()`` works on a given list of
+files.
+
+.. code-block:: cmake
+
+ create_javadoc(<VAR>
+ FILES <file1> [<file2>...]
+ [CLASSPATH <classpath>]
+ [INSTALLPATH <install path>]
+ [DOCTITLE "the documentation title"]
+ [WINDOWTITLE "the title of the document"]
+ [AUTHOR TRUE|FALSE]
+ [USE TRUE|FALSE]
+ [VERSION TRUE|FALSE]
+ )
+
+For example:
+
+.. code-block:: cmake
+
+ create_javadoc(my_example_doc
+ FILES ${example_SRCS}
+ CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
+ WINDOWTITLE "My example"
+ DOCTITLE "<h1>My example</h1>"
+ AUTHOR TRUE
+ USE TRUE
+ VERSION TRUE
+ )
+
+Both signatures share most of the options. These options are the same
+as what you can find in the javadoc manpage. Please look at the
+manpage for ``CLASSPATH``, ``DOCTITLE``, ``WINDOWTITLE``, ``AUTHOR``, ``USE``
+and ``VERSION``.
+
+If you don't set the ``INSTALLPATH``, then by default the documentation will
+be installed to :
+
+::
+
+ ${CMAKE_INSTALL_PREFIX}/share/javadoc/<VAR>
+
+
+Header Generation
+^^^^^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ create_javah(TARGET <target> | GENERATED_FILES <VAR>
+ CLASSES <class>...
+ [CLASSPATH <classpath>...]
+ [DEPENDS <depend>...]
+ [OUTPUT_NAME <path>|OUTPUT_DIR <path>]
+ )
+
+.. versionadded:: 3.4
+
+.. deprecated:: 3.11
+ This command will no longer be supported starting with version 10 of the JDK
+ due to the `suppression of javah tool <http://openjdk.java.net/jeps/313>`_.
+ The ``add_jar(GENERATE_NATIVE_HEADERS)`` command should be used instead.
+
+Create C header files from java classes. These files provide the connective glue
+that allow your Java and C code to interact.
+
+There are two main signatures for ``create_javah()``. The first signature
+returns generated files through variable specified by the ``GENERATED_FILES``
+option. For example:
+
+.. code-block:: cmake
+
+ create_javah(GENERATED_FILES files_headers
+ CLASSES org.cmake.HelloWorld
+ CLASSPATH hello.jar
+ )
+
+The second signature for ``create_javah()`` creates a target which encapsulates
+header files generation. E.g.
+
+.. code-block:: cmake
+
+ create_javah(TARGET target_headers
+ CLASSES org.cmake.HelloWorld
+ CLASSPATH hello.jar
+ )
+
+Both signatures share same options.
+
+``CLASSES <class>...``
+ Specifies Java classes used to generate headers.
+
+``CLASSPATH <classpath>...``
+ Specifies various paths to look up classes. Here .class files, jar files or
+ targets created by command add_jar can be used.
+
+``DEPENDS <depend>...``
+ Targets on which the javah target depends.
+
+``OUTPUT_NAME <path>``
+ Concatenates the resulting header files for all the classes listed by option
+ ``CLASSES`` into ``<path>``. Same behavior as option ``-o`` of javah tool.
+
+``OUTPUT_DIR <path>``
+ Sets the directory where the header files will be generated. Same behavior
+ as option ``-d`` of javah tool. If not specified,
+ :variable:`CMAKE_CURRENT_BINARY_DIR` is used as the output directory.
+#]=======================================================================]
+
+function (__java_copy_file src dest comment)
+ add_custom_command(
+ OUTPUT ${dest}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ARGS ${src}
+ ${dest}
+ DEPENDS ${src}
+ COMMENT ${comment}
+ VERBATIM
+ )
+endfunction ()
+
+function(__java_lcat VAR)
+ foreach(_line IN LISTS ARGN)
+ string(APPEND ${VAR} "${_line}\n")
+ endforeach()
+
+ set(${VAR} "${${VAR}}" PARENT_SCOPE)
+endfunction()
+
+function(__java_export_jar VAR TARGET PATH)
+ get_target_property(_jarpath ${TARGET} JAR_FILE)
+ get_filename_component(_jarname ${_jarpath} NAME)
+ set(_target "${_jar_NAMESPACE}${TARGET}")
+ __java_lcat(${VAR}
+ "# Create imported target ${_target}"
+ "add_library(${_target} IMPORTED STATIC)"
+ "set_target_properties(${_target} PROPERTIES"
+ " IMPORTED_LOCATION \"${PATH}/${_jarname}\""
+ " JAR_FILE \"${PATH}/${_jarname}\")"
+ ""
+ )
+ set(${VAR} "${${VAR}}" PARENT_SCOPE)
+endfunction()
+
+# define helper scripts
+set(_JAVA_EXPORT_TARGETS_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJava/javaTargets.cmake.in)
+set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJava/Symlinks.cmake)
+
+if (CMAKE_HOST_WIN32 AND NOT CYGWIN AND CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
+ set(_UseJava_PATH_SEP "$<SEMICOLON>")
+else ()
+ set(_UseJava_PATH_SEP ":")
+endif()
+
+function(add_jar _TARGET_NAME)
+
+ cmake_parse_arguments(_add_jar
+ ""
+ "VERSION;OUTPUT_DIR;OUTPUT_NAME;ENTRY_POINT;MANIFEST"
+ "SOURCES;INCLUDE_JARS;GENERATE_NATIVE_HEADERS"
+ ${ARGN}
+ )
+
+ # In CMake < 2.8.12, add_jar used variables which were set prior to calling
+ # add_jar for customizing the behavior of add_jar. In order to be backwards
+ # compatible, check if any of those variables are set, and use them to
+ # initialize values of the named arguments. (Giving the corresponding named
+ # argument will override the value set here.)
+ #
+ # New features should use named arguments only.
+ if(NOT DEFINED _add_jar_VERSION AND DEFINED CMAKE_JAVA_TARGET_VERSION)
+ set(_add_jar_VERSION "${CMAKE_JAVA_TARGET_VERSION}")
+ endif()
+ if(NOT DEFINED _add_jar_OUTPUT_DIR AND DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR)
+ set(_add_jar_OUTPUT_DIR "${CMAKE_JAVA_TARGET_OUTPUT_DIR}")
+ endif()
+ if(NOT DEFINED _add_jar_OUTPUT_NAME AND DEFINED CMAKE_JAVA_TARGET_OUTPUT_NAME)
+ set(_add_jar_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}")
+ # reset
+ set(CMAKE_JAVA_TARGET_OUTPUT_NAME)
+ endif()
+ if(NOT DEFINED _add_jar_ENTRY_POINT AND DEFINED CMAKE_JAVA_JAR_ENTRY_POINT)
+ set(_add_jar_ENTRY_POINT "${CMAKE_JAVA_JAR_ENTRY_POINT}")
+ endif()
+
+ set(_JAVA_SOURCE_FILES ${_add_jar_SOURCES} ${_add_jar_UNPARSED_ARGUMENTS})
+
+ if (NOT DEFINED _add_jar_OUTPUT_DIR)
+ set(_add_jar_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
+ else()
+ get_filename_component(_add_jar_OUTPUT_DIR ${_add_jar_OUTPUT_DIR} ABSOLUTE)
+ endif()
+ # ensure output directory exists
+ file (MAKE_DIRECTORY "${_add_jar_OUTPUT_DIR}")
+
+ if (_add_jar_ENTRY_POINT)
+ set(_ENTRY_POINT_OPTION e)
+ set(_ENTRY_POINT_VALUE ${_add_jar_ENTRY_POINT})
+ endif ()
+
+ if (_add_jar_MANIFEST)
+ set(_MANIFEST_OPTION m)
+ get_filename_component (_MANIFEST_VALUE "${_add_jar_MANIFEST}" ABSOLUTE)
+ endif ()
+
+ unset (_GENERATE_NATIVE_HEADERS)
+ if (_add_jar_GENERATE_NATIVE_HEADERS)
+ # Raise an error if JDK version is less than 1.8 because javac -h is not supported
+ # by earlier versions.
+ if (Java_VERSION VERSION_LESS 1.8)
+ message (FATAL_ERROR "ADD_JAR: GENERATE_NATIVE_HEADERS is not supported with this version of Java.")
+ endif()
+
+ unset (_GENERATE_NATIVE_HEADERS_OUTPUT_DESC)
+
+ cmake_parse_arguments (_add_jar_GENERATE_NATIVE_HEADERS "" "" "DESTINATION" ${_add_jar_GENERATE_NATIVE_HEADERS})
+ if (NOT _add_jar_GENERATE_NATIVE_HEADERS_UNPARSED_ARGUMENTS)
+ message (FATAL_ERROR "ADD_JAR: GENERATE_NATIVE_HEADERS: missing required argument.")
+ endif()
+ list (LENGTH _add_jar_GENERATE_NATIVE_HEADERS_UNPARSED_ARGUMENTS length)
+ if (length GREATER 1)
+ list (REMOVE_AT _add_jar_GENERATE_NATIVE_HEADERS_UNPARSED_ARGUMENTS 0)
+ message (FATAL_ERROR "ADD_JAR: GENERATE_NATIVE_HEADERS: ${_add_jar_GENERATE_NATIVE_HEADERS_UNPARSED_ARGUMENTS}: unexpected argument(s).")
+ endif()
+ if (NOT _add_jar_GENERATE_NATIVE_HEADERS_DESTINATION)
+ set (_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir/native_headers")
+ else()
+ list (LENGTH _add_jar_GENERATE_NATIVE_HEADERS_DESTINATION length)
+ if (NOT length EQUAL 1)
+ cmake_parse_arguments (_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION "" "BUILD;INSTALL" "" "${_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION}")
+ if (_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_UNPARSED_ARGUMENTS)
+ message (FATAL_ERROR "ADD_JAR: GENERATE_NATIVE_HEADERS: DESTINATION: ${_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_UNPARSED_ARGUMENTS}: unexpected argument(s).")
+ endif()
+ if (NOT _add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_INSTALL)
+ message (FATAL_ERROR "ADD_JAR: GENERATE_NATIVE_HEADERS: DESTINATION: INSTALL sub-option is required.")
+ endif()
+ if (NOT _add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_BUILD)
+ set(_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_BUILD "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir/native_headers")
+ endif()
+ set(_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION "${_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_BUILD}")
+ set(_GENERATE_NATIVE_HEADERS_OUTPUT_DESC "$<BUILD_INTERFACE:${_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_BUILD}>" "$<INSTALL_INTERFACE:${_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_INSTALL}>")
+ endif()
+ endif()
+
+ set (_GENERATE_NATIVE_HEADERS_TARGET ${_add_jar_GENERATE_NATIVE_HEADERS_UNPARSED_ARGUMENTS})
+ set (_GENERATE_NATIVE_HEADERS_OUTPUT_DIR "${_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION}")
+ set (_GENERATE_NATIVE_HEADERS -h "${_GENERATE_NATIVE_HEADERS_OUTPUT_DIR}")
+ if(NOT _GENERATE_NATIVE_HEADERS_OUTPUT_DESC)
+ set(_GENERATE_NATIVE_HEADERS_OUTPUT_DESC "${_GENERATE_NATIVE_HEADERS_OUTPUT_DIR}")
+ endif()
+ endif()
+
+ if (LIBRARY_OUTPUT_PATH)
+ set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH})
+ else ()
+ set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${_add_jar_OUTPUT_DIR})
+ endif ()
+
+ set(CMAKE_JAVA_INCLUDE_PATH
+ ${CMAKE_JAVA_INCLUDE_PATH}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_JAVA_OBJECT_OUTPUT_PATH}
+ ${CMAKE_JAVA_LIBRARY_OUTPUT_PATH}
+ )
+
+ foreach (JAVA_INCLUDE_DIR IN LISTS CMAKE_JAVA_INCLUDE_PATH)
+ string(APPEND CMAKE_JAVA_INCLUDE_PATH_FINAL "${_UseJava_PATH_SEP}${JAVA_INCLUDE_DIR}")
+ endforeach()
+
+ set(CMAKE_JAVA_CLASS_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir")
+
+ set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}.jar")
+ if (_add_jar_OUTPUT_NAME AND _add_jar_VERSION)
+ set(_JAVA_TARGET_OUTPUT_NAME "${_add_jar_OUTPUT_NAME}-${_add_jar_VERSION}.jar")
+ set(_JAVA_TARGET_OUTPUT_LINK "${_add_jar_OUTPUT_NAME}.jar")
+ elseif (_add_jar_VERSION)
+ set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}-${_add_jar_VERSION}.jar")
+ set(_JAVA_TARGET_OUTPUT_LINK "${_TARGET_NAME}.jar")
+ elseif (_add_jar_OUTPUT_NAME)
+ set(_JAVA_TARGET_OUTPUT_NAME "${_add_jar_OUTPUT_NAME}.jar")
+ endif ()
+
+ set(_JAVA_CLASS_FILES)
+ set(_JAVA_COMPILE_FILES)
+ set(_JAVA_COMPILE_FILELISTS)
+ set(_JAVA_DEPENDS)
+ set(_JAVA_COMPILE_DEPENDS)
+ set(_JAVA_RESOURCE_FILES)
+ set(_JAVA_RESOURCE_FILES_RELATIVE)
+ foreach(_JAVA_SOURCE_FILE IN LISTS _JAVA_SOURCE_FILES)
+ get_filename_component(_JAVA_EXT ${_JAVA_SOURCE_FILE} EXT)
+ get_filename_component(_JAVA_FILE ${_JAVA_SOURCE_FILE} NAME_WE)
+ get_filename_component(_JAVA_PATH ${_JAVA_SOURCE_FILE} PATH)
+ get_filename_component(_JAVA_FULL ${_JAVA_SOURCE_FILE} ABSOLUTE)
+
+ if (_JAVA_SOURCE_FILE MATCHES "^@(.+)$")
+ get_filename_component(_JAVA_FULL ${CMAKE_MATCH_1} ABSOLUTE)
+ list(APPEND _JAVA_COMPILE_FILELISTS ${_JAVA_FULL})
+
+ elseif (_JAVA_EXT MATCHES ".java")
+ file(RELATIVE_PATH _JAVA_REL_BINARY_PATH ${CMAKE_CURRENT_BINARY_DIR} ${_JAVA_FULL})
+ file(RELATIVE_PATH _JAVA_REL_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${_JAVA_FULL})
+ string(LENGTH ${_JAVA_REL_BINARY_PATH} _BIN_LEN)
+ string(LENGTH ${_JAVA_REL_SOURCE_PATH} _SRC_LEN)
+ if (_BIN_LEN LESS _SRC_LEN)
+ set(_JAVA_REL_PATH ${_JAVA_REL_BINARY_PATH})
+ else ()
+ set(_JAVA_REL_PATH ${_JAVA_REL_SOURCE_PATH})
+ endif ()
+ get_filename_component(_JAVA_REL_PATH ${_JAVA_REL_PATH} PATH)
+
+ list(APPEND _JAVA_COMPILE_FILES ${_JAVA_SOURCE_FILE})
+ set(_JAVA_CLASS_FILE "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_REL_PATH}/${_JAVA_FILE}.class")
+ set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES} ${_JAVA_CLASS_FILE})
+
+ elseif (_JAVA_EXT MATCHES ".jar"
+ OR _JAVA_EXT MATCHES ".war"
+ OR _JAVA_EXT MATCHES ".ear"
+ OR _JAVA_EXT MATCHES ".sar")
+ # Ignored for backward compatibility
+
+ elseif (_JAVA_EXT STREQUAL "")
+ list(APPEND CMAKE_JAVA_INCLUDE_PATH ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}} ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}_CLASSPATH})
+ list(APPEND _JAVA_DEPENDS ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}})
+
+ else ()
+ __java_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/${_JAVA_SOURCE_FILE}
+ ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_SOURCE_FILE}
+ "Copying ${_JAVA_SOURCE_FILE} to the build directory")
+ list(APPEND _JAVA_RESOURCE_FILES ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_SOURCE_FILE})
+ list(APPEND _JAVA_RESOURCE_FILES_RELATIVE ${_JAVA_SOURCE_FILE})
+ endif ()
+ endforeach()
+
+ foreach(_JAVA_INCLUDE_JAR IN LISTS _add_jar_INCLUDE_JARS)
+ if (TARGET ${_JAVA_INCLUDE_JAR})
+ get_target_property(_JAVA_JAR_PATH ${_JAVA_INCLUDE_JAR} JAR_FILE)
+ if (_JAVA_JAR_PATH)
+ string(APPEND CMAKE_JAVA_INCLUDE_PATH_FINAL "${_UseJava_PATH_SEP}${_JAVA_JAR_PATH}")
+ list(APPEND CMAKE_JAVA_INCLUDE_PATH ${_JAVA_JAR_PATH})
+ list(APPEND _JAVA_DEPENDS ${_JAVA_INCLUDE_JAR})
+ list(APPEND _JAVA_COMPILE_DEPENDS ${_JAVA_JAR_PATH})
+ else ()
+ message(SEND_ERROR "add_jar: INCLUDE_JARS target ${_JAVA_INCLUDE_JAR} is not a jar")
+ endif ()
+ else ()
+ string(APPEND CMAKE_JAVA_INCLUDE_PATH_FINAL "${_UseJava_PATH_SEP}${_JAVA_INCLUDE_JAR}")
+ list(APPEND CMAKE_JAVA_INCLUDE_PATH "${_JAVA_INCLUDE_JAR}")
+ list(APPEND _JAVA_DEPENDS "${_JAVA_INCLUDE_JAR}")
+ list(APPEND _JAVA_COMPILE_DEPENDS "${_JAVA_INCLUDE_JAR}")
+ endif ()
+ endforeach()
+
+ if (_JAVA_COMPILE_FILES OR _JAVA_COMPILE_FILELISTS)
+ set (_JAVA_SOURCES_FILELISTS)
+
+ if (_JAVA_COMPILE_FILES)
+ # Create the list of files to compile.
+ set(_JAVA_SOURCES_FILE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_sources)
+ string(REPLACE ";" "\"\n\"" _JAVA_COMPILE_STRING "\"${_JAVA_COMPILE_FILES}\"")
+ set(CMAKE_CONFIGURABLE_FILE_CONTENT "${_JAVA_COMPILE_STRING}")
+ configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
+ "${_JAVA_SOURCES_FILE}" @ONLY)
+ unset(CMAKE_CONFIGURABLE_FILE_CONTENT)
+ list (APPEND _JAVA_SOURCES_FILELISTS "@${_JAVA_SOURCES_FILE}")
+ endif()
+ if (_JAVA_COMPILE_FILELISTS)
+ foreach (_JAVA_FILELIST IN LISTS _JAVA_COMPILE_FILELISTS)
+ list (APPEND _JAVA_SOURCES_FILELISTS "@${_JAVA_FILELIST}")
+ endforeach()
+ endif()
+
+ # Compile the java files and create a list of class files
+ add_custom_command(
+ # NOTE: this command generates an artificial dependency file
+ OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
+ COMMAND ${CMAKE_COMMAND}
+ -DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH}
+ -DCMAKE_JAR_CLASSES_PREFIX=${CMAKE_JAR_CLASSES_PREFIX}
+ -P ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/UseJava/ClearClassFiles.cmake
+ COMMAND ${Java_JAVAC_EXECUTABLE}
+ ${CMAKE_JAVA_COMPILE_FLAGS}
+ -classpath "${CMAKE_JAVA_INCLUDE_PATH_FINAL}"
+ -d ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
+ ${_GENERATE_NATIVE_HEADERS}
+ ${_JAVA_SOURCES_FILELISTS}
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
+ DEPENDS ${_JAVA_COMPILE_FILES} ${_JAVA_COMPILE_FILELISTS} ${_JAVA_COMPILE_DEPENDS} ${_JAVA_SOURCES_FILE}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMENT "Building Java objects for ${_TARGET_NAME}.jar"
+ VERBATIM
+ )
+ add_custom_command(
+ OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
+ COMMAND ${CMAKE_COMMAND}
+ -DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH}
+ -DCMAKE_JAR_CLASSES_PREFIX=${CMAKE_JAR_CLASSES_PREFIX}
+ -P ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/UseJava/ClassFilelist.cmake
+ DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ VERBATIM
+ )
+ else ()
+ # create an empty java_class_filelist
+ if (NOT EXISTS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist)
+ file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist "")
+ endif()
+ endif ()
+
+ # create the jar file
+ set(_JAVA_JAR_OUTPUT_PATH
+ "${_add_jar_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_NAME}")
+ if (CMAKE_JNI_TARGET)
+ add_custom_command(
+ OUTPUT ${_JAVA_JAR_OUTPUT_PATH}
+ COMMAND ${Java_JAR_EXECUTABLE}
+ -cf${_ENTRY_POINT_OPTION}${_MANIFEST_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE} ${_MANIFEST_VALUE}
+ ${_JAVA_RESOURCE_FILES_RELATIVE} @java_class_filelist
+ COMMAND ${CMAKE_COMMAND}
+ -D_JAVA_TARGET_DIR=${_add_jar_OUTPUT_DIR}
+ -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME}
+ -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
+ -P ${_JAVA_SYMLINK_SCRIPT}
+ COMMAND ${CMAKE_COMMAND}
+ -D_JAVA_TARGET_DIR=${_add_jar_OUTPUT_DIR}
+ -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_JAR_OUTPUT_PATH}
+ -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
+ -P ${_JAVA_SYMLINK_SCRIPT}
+ DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
+ WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
+ COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}"
+ VERBATIM
+ )
+ else ()
+ add_custom_command(
+ OUTPUT ${_JAVA_JAR_OUTPUT_PATH}
+ COMMAND ${Java_JAR_EXECUTABLE}
+ -cf${_ENTRY_POINT_OPTION}${_MANIFEST_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE} ${_MANIFEST_VALUE}
+ ${_JAVA_RESOURCE_FILES_RELATIVE} @java_class_filelist
+ COMMAND ${CMAKE_COMMAND}
+ -D_JAVA_TARGET_DIR=${_add_jar_OUTPUT_DIR}
+ -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME}
+ -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
+ -P ${_JAVA_SYMLINK_SCRIPT}
+ WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
+ DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
+ COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}"
+ VERBATIM
+ )
+ endif ()
+
+ # Add the target and make sure we have the latest resource files.
+ add_custom_target(${_TARGET_NAME} ALL DEPENDS ${_JAVA_JAR_OUTPUT_PATH})
+
+ set_property(
+ TARGET
+ ${_TARGET_NAME}
+ PROPERTY
+ INSTALL_FILES
+ ${_JAVA_JAR_OUTPUT_PATH}
+ )
+
+ if (_JAVA_TARGET_OUTPUT_LINK)
+ set_property(
+ TARGET
+ ${_TARGET_NAME}
+ PROPERTY
+ INSTALL_FILES
+ ${_JAVA_JAR_OUTPUT_PATH}
+ ${_add_jar_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK}
+ )
+
+ if (CMAKE_JNI_TARGET)
+ set_property(
+ TARGET
+ ${_TARGET_NAME}
+ PROPERTY
+ JNI_SYMLINK
+ ${_add_jar_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK}
+ )
+ endif ()
+ endif ()
+
+ set_property(
+ TARGET
+ ${_TARGET_NAME}
+ PROPERTY
+ JAR_FILE
+ ${_JAVA_JAR_OUTPUT_PATH}
+ )
+
+ set_property(
+ TARGET
+ ${_TARGET_NAME}
+ PROPERTY
+ CLASSDIR
+ ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
+ )
+
+ if (_GENERATE_NATIVE_HEADERS)
+ # create an INTERFACE library encapsulating include directory for generated headers
+ add_library (${_GENERATE_NATIVE_HEADERS_TARGET} INTERFACE)
+ target_include_directories (${_GENERATE_NATIVE_HEADERS_TARGET} INTERFACE
+ "${_GENERATE_NATIVE_HEADERS_OUTPUT_DESC}"
+ ${JNI_INCLUDE_DIRS})
+ set_property(TARGET ${_GENERATE_NATIVE_HEADERS_TARGET} PROPERTY NATIVE_HEADERS_DIRECTORY "${_GENERATE_NATIVE_HEADERS_OUTPUT_DIR}")
+ # this INTERFACE library depends on jar generation
+ add_dependencies (${_GENERATE_NATIVE_HEADERS_TARGET} ${_TARGET_NAME})
+
+ set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES
+ "${_GENERATE_NATIVE_HEADERS_OUTPUT_DIR}")
+ endif()
+endfunction()
+
+function(INSTALL_JAR _TARGET_NAME)
+ if (ARGC EQUAL 2)
+ set (_DESTINATION ${ARGV1})
+ else()
+ cmake_parse_arguments(_install_jar
+ ""
+ "DESTINATION;COMPONENT"
+ ""
+ ${ARGN})
+ if (_install_jar_DESTINATION)
+ set (_DESTINATION ${_install_jar_DESTINATION})
+ else()
+ message(SEND_ERROR "install_jar: ${_TARGET_NAME}: DESTINATION must be specified.")
+ endif()
+
+ if (_install_jar_COMPONENT)
+ set (_COMPONENT COMPONENT ${_install_jar_COMPONENT})
+ endif()
+ endif()
+
+ get_property(__FILES
+ TARGET
+ ${_TARGET_NAME}
+ PROPERTY
+ INSTALL_FILES
+ )
+ set_property(
+ TARGET
+ ${_TARGET_NAME}
+ PROPERTY
+ INSTALL_DESTINATION
+ ${_DESTINATION}
+ )
+
+ if (__FILES)
+ install(
+ FILES
+ ${__FILES}
+ DESTINATION
+ ${_DESTINATION}
+ ${_COMPONENT}
+ )
+ else ()
+ message(SEND_ERROR "install_jar: The target ${_TARGET_NAME} is not known in this scope.")
+ endif ()
+endfunction()
+
+function(INSTALL_JNI_SYMLINK _TARGET_NAME)
+ if (ARGC EQUAL 2)
+ set (_DESTINATION ${ARGV1})
+ else()
+ cmake_parse_arguments(_install_jni_symlink
+ ""
+ "DESTINATION;COMPONENT"
+ ""
+ ${ARGN})
+ if (_install_jni_symlink_DESTINATION)
+ set (_DESTINATION ${_install_jni_symlink_DESTINATION})
+ else()
+ message(SEND_ERROR "install_jni_symlink: ${_TARGET_NAME}: DESTINATION must be specified.")
+ endif()
+
+ if (_install_jni_symlink_COMPONENT)
+ set (_COMPONENT COMPONENT ${_install_jni_symlink_COMPONENT})
+ endif()
+ endif()
+
+ get_property(__SYMLINK
+ TARGET
+ ${_TARGET_NAME}
+ PROPERTY
+ JNI_SYMLINK
+ )
+
+ if (__SYMLINK)
+ install(
+ FILES
+ ${__SYMLINK}
+ DESTINATION
+ ${_DESTINATION}
+ ${_COMPONENT}
+ )
+ else ()
+ message(SEND_ERROR "install_jni_symlink: The target ${_TARGET_NAME} is not known in this scope.")
+ endif ()
+endfunction()
+
+function (find_jar VARIABLE)
+ set(_jar_names)
+ set(_jar_files)
+ set(_jar_versions)
+ set(_jar_paths
+ /usr/share/java/
+ /usr/local/share/java/
+ ${Java_JAR_PATHS})
+ set(_jar_doc "NOTSET")
+
+ set(_state "name")
+
+ foreach (arg IN LISTS ARGN)
+ if (_state STREQUAL "name")
+ if (arg STREQUAL "VERSIONS")
+ set(_state "versions")
+ elseif (arg STREQUAL "NAMES")
+ set(_state "names")
+ elseif (arg STREQUAL "PATHS")
+ set(_state "paths")
+ elseif (arg STREQUAL "DOC")
+ set(_state "doc")
+ else ()
+ set(_jar_names ${arg})
+ if (_jar_doc STREQUAL "NOTSET")
+ set(_jar_doc "Finding ${arg} jar")
+ endif ()
+ endif ()
+ elseif (_state STREQUAL "versions")
+ if (arg STREQUAL "NAMES")
+ set(_state "names")
+ elseif (arg STREQUAL "PATHS")
+ set(_state "paths")
+ elseif (arg STREQUAL "DOC")
+ set(_state "doc")
+ else ()
+ set(_jar_versions ${_jar_versions} ${arg})
+ endif ()
+ elseif (_state STREQUAL "names")
+ if (arg STREQUAL "VERSIONS")
+ set(_state "versions")
+ elseif (arg STREQUAL "PATHS")
+ set(_state "paths")
+ elseif (arg STREQUAL "DOC")
+ set(_state "doc")
+ else ()
+ set(_jar_names ${_jar_names} ${arg})
+ if (_jar_doc STREQUAL "NOTSET")
+ set(_jar_doc "Finding ${arg} jar")
+ endif ()
+ endif ()
+ elseif (_state STREQUAL "paths")
+ if (arg STREQUAL "VERSIONS")
+ set(_state "versions")
+ elseif (arg STREQUAL "NAMES")
+ set(_state "names")
+ elseif (arg STREQUAL "DOC")
+ set(_state "doc")
+ else ()
+ set(_jar_paths ${_jar_paths} ${arg})
+ endif ()
+ elseif (_state STREQUAL "doc")
+ if (arg STREQUAL "VERSIONS")
+ set(_state "versions")
+ elseif (arg STREQUAL "NAMES")
+ set(_state "names")
+ elseif (arg STREQUAL "PATHS")
+ set(_state "paths")
+ else ()
+ set(_jar_doc ${arg})
+ endif ()
+ endif ()
+ endforeach ()
+
+ if (NOT _jar_names)
+ message(FATAL_ERROR "find_jar: No name to search for given")
+ endif ()
+
+ foreach (jar_name IN LISTS _jar_names)
+ foreach (version IN LISTS _jar_versions)
+ set(_jar_files ${_jar_files} ${jar_name}-${version}.jar)
+ endforeach ()
+ set(_jar_files ${_jar_files} ${jar_name}.jar)
+ endforeach ()
+
+ find_file(${VARIABLE}
+ NAMES ${_jar_files}
+ PATHS ${_jar_paths}
+ DOC ${_jar_doc}
+ NO_DEFAULT_PATH)
+endfunction ()
+
+function(create_javadoc _target)
+ set(_javadoc_packages)
+ set(_javadoc_files)
+ set(_javadoc_sourcepath)
+ set(_javadoc_classpath)
+ set(_javadoc_installpath "${CMAKE_INSTALL_PREFIX}/share/javadoc")
+ set(_javadoc_doctitle)
+ set(_javadoc_windowtitle)
+ set(_javadoc_author FALSE)
+ set(_javadoc_version FALSE)
+ set(_javadoc_use FALSE)
+
+ set(_state "package")
+
+ foreach (arg IN LISTS ARGN)
+ if (_state STREQUAL "package")
+ if (arg STREQUAL "PACKAGES")
+ set(_state "packages")
+ elseif (arg STREQUAL "FILES")
+ set(_state "files")
+ elseif (arg STREQUAL "SOURCEPATH")
+ set(_state "sourcepath")
+ elseif (arg STREQUAL "CLASSPATH")
+ set(_state "classpath")
+ elseif (arg STREQUAL "INSTALLPATH")
+ set(_state "installpath")
+ elseif (arg STREQUAL "DOCTITLE")
+ set(_state "doctitle")
+ elseif (arg STREQUAL "WINDOWTITLE")
+ set(_state "windowtitle")
+ elseif (arg STREQUAL "AUTHOR")
+ set(_state "author")
+ elseif (arg STREQUAL "USE")
+ set(_state "use")
+ elseif (arg STREQUAL "VERSION")
+ set(_state "version")
+ else ()
+ set(_javadoc_packages ${arg})
+ set(_state "packages")
+ endif ()
+ elseif (_state STREQUAL "packages")
+ if (arg STREQUAL "FILES")
+ set(_state "files")
+ elseif (arg STREQUAL "SOURCEPATH")
+ set(_state "sourcepath")
+ elseif (arg STREQUAL "CLASSPATH")
+ set(_state "classpath")
+ elseif (arg STREQUAL "INSTALLPATH")
+ set(_state "installpath")
+ elseif (arg STREQUAL "DOCTITLE")
+ set(_state "doctitle")
+ elseif (arg STREQUAL "WINDOWTITLE")
+ set(_state "windowtitle")
+ elseif (arg STREQUAL "AUTHOR")
+ set(_state "author")
+ elseif (arg STREQUAL "USE")
+ set(_state "use")
+ elseif (arg STREQUAL "VERSION")
+ set(_state "version")
+ else ()
+ list(APPEND _javadoc_packages ${arg})
+ endif ()
+ elseif (_state STREQUAL "files")
+ if (arg STREQUAL "PACKAGES")
+ set(_state "packages")
+ elseif (arg STREQUAL "SOURCEPATH")
+ set(_state "sourcepath")
+ elseif (arg STREQUAL "CLASSPATH")
+ set(_state "classpath")
+ elseif (arg STREQUAL "INSTALLPATH")
+ set(_state "installpath")
+ elseif (arg STREQUAL "DOCTITLE")
+ set(_state "doctitle")
+ elseif (arg STREQUAL "WINDOWTITLE")
+ set(_state "windowtitle")
+ elseif (arg STREQUAL "AUTHOR")
+ set(_state "author")
+ elseif (arg STREQUAL "USE")
+ set(_state "use")
+ elseif (arg STREQUAL "VERSION")
+ set(_state "version")
+ else ()
+ list(APPEND _javadoc_files ${arg})
+ endif ()
+ elseif (_state STREQUAL "sourcepath")
+ if (arg STREQUAL "PACKAGES")
+ set(_state "packages")
+ elseif (arg STREQUAL "FILES")
+ set(_state "files")
+ elseif (arg STREQUAL "CLASSPATH")
+ set(_state "classpath")
+ elseif (arg STREQUAL "INSTALLPATH")
+ set(_state "installpath")
+ elseif (arg STREQUAL "DOCTITLE")
+ set(_state "doctitle")
+ elseif (arg STREQUAL "WINDOWTITLE")
+ set(_state "windowtitle")
+ elseif (arg STREQUAL "AUTHOR")
+ set(_state "author")
+ elseif (arg STREQUAL "USE")
+ set(_state "use")
+ elseif (arg STREQUAL "VERSION")
+ set(_state "version")
+ else ()
+ list(APPEND _javadoc_sourcepath ${arg})
+ endif ()
+ elseif (_state STREQUAL "classpath")
+ if (arg STREQUAL "PACKAGES")
+ set(_state "packages")
+ elseif (arg STREQUAL "FILES")
+ set(_state "files")
+ elseif (arg STREQUAL "SOURCEPATH")
+ set(_state "sourcepath")
+ elseif (arg STREQUAL "INSTALLPATH")
+ set(_state "installpath")
+ elseif (arg STREQUAL "DOCTITLE")
+ set(_state "doctitle")
+ elseif (arg STREQUAL "WINDOWTITLE")
+ set(_state "windowtitle")
+ elseif (arg STREQUAL "AUTHOR")
+ set(_state "author")
+ elseif (arg STREQUAL "USE")
+ set(_state "use")
+ elseif (arg STREQUAL "VERSION")
+ set(_state "version")
+ else ()
+ list(APPEND _javadoc_classpath ${arg})
+ endif ()
+ elseif (_state STREQUAL "installpath")
+ if (arg STREQUAL "PACKAGES")
+ set(_state "packages")
+ elseif (arg STREQUAL "FILES")
+ set(_state "files")
+ elseif (arg STREQUAL "SOURCEPATH")
+ set(_state "sourcepath")
+ elseif (arg STREQUAL "DOCTITLE")
+ set(_state "doctitle")
+ elseif (arg STREQUAL "WINDOWTITLE")
+ set(_state "windowtitle")
+ elseif (arg STREQUAL "AUTHOR")
+ set(_state "author")
+ elseif (arg STREQUAL "USE")
+ set(_state "use")
+ elseif (arg STREQUAL "VERSION")
+ set(_state "version")
+ else ()
+ set(_javadoc_installpath ${arg})
+ endif ()
+ elseif (_state STREQUAL "doctitle")
+ if (${arg} STREQUAL "PACKAGES")
+ set(_state "packages")
+ elseif (arg STREQUAL "FILES")
+ set(_state "files")
+ elseif (arg STREQUAL "SOURCEPATH")
+ set(_state "sourcepath")
+ elseif (arg STREQUAL "INSTALLPATH")
+ set(_state "installpath")
+ elseif (arg STREQUAL "CLASSPATH")
+ set(_state "classpath")
+ elseif (arg STREQUAL "WINDOWTITLE")
+ set(_state "windowtitle")
+ elseif (arg STREQUAL "AUTHOR")
+ set(_state "author")
+ elseif (arg STREQUAL "USE")
+ set(_state "use")
+ elseif (arg STREQUAL "VERSION")
+ set(_state "version")
+ else ()
+ set(_javadoc_doctitle ${arg})
+ endif ()
+ elseif (_state STREQUAL "windowtitle")
+ if (${arg} STREQUAL "PACKAGES")
+ set(_state "packages")
+ elseif (arg STREQUAL "FILES")
+ set(_state "files")
+ elseif (arg STREQUAL "SOURCEPATH")
+ set(_state "sourcepath")
+ elseif (arg STREQUAL "CLASSPATH")
+ set(_state "classpath")
+ elseif (arg STREQUAL "INSTALLPATH")
+ set(_state "installpath")
+ elseif (arg STREQUAL "DOCTITLE")
+ set(_state "doctitle")
+ elseif (arg STREQUAL "AUTHOR")
+ set(_state "author")
+ elseif (arg STREQUAL "USE")
+ set(_state "use")
+ elseif (arg STREQUAL "VERSION")
+ set(_state "version")
+ else ()
+ set(_javadoc_windowtitle ${arg})
+ endif ()
+ elseif (_state STREQUAL "author")
+ if (arg STREQUAL "PACKAGES")
+ set(_state "packages")
+ elseif (arg STREQUAL "FILES")
+ set(_state "files")
+ elseif (arg STREQUAL "SOURCEPATH")
+ set(_state "sourcepath")
+ elseif (arg STREQUAL "CLASSPATH")
+ set(_state "classpath")
+ elseif (arg STREQUAL "INSTALLPATH")
+ set(_state "installpath")
+ elseif (arg STREQUAL "DOCTITLE")
+ set(_state "doctitle")
+ elseif (arg STREQUAL "WINDOWTITLE")
+ set(_state "windowtitle")
+ elseif (arg STREQUAL "AUTHOR")
+ set(_state "author")
+ elseif (arg STREQUAL "USE")
+ set(_state "use")
+ elseif (arg STREQUAL "VERSION")
+ set(_state "version")
+ else ()
+ set(_javadoc_author ${arg})
+ endif ()
+ elseif (_state STREQUAL "use")
+ if (arg STREQUAL "PACKAGES")
+ set(_state "packages")
+ elseif (arg STREQUAL "FILES")
+ set(_state "files")
+ elseif (arg STREQUAL "SOURCEPATH")
+ set(_state "sourcepath")
+ elseif (arg STREQUAL "CLASSPATH")
+ set(_state "classpath")
+ elseif (arg STREQUAL "INSTALLPATH")
+ set(_state "installpath")
+ elseif (arg STREQUAL "DOCTITLE")
+ set(_state "doctitle")
+ elseif (arg STREQUAL "WINDOWTITLE")
+ set(_state "windowtitle")
+ elseif (arg STREQUAL "AUTHOR")
+ set(_state "author")
+ elseif (arg STREQUAL "USE")
+ set(_state "use")
+ elseif (arg STREQUAL "VERSION")
+ set(_state "version")
+ else ()
+ set(_javadoc_use ${arg})
+ endif ()
+ elseif (_state STREQUAL "version")
+ if (arg STREQUAL "PACKAGES")
+ set(_state "packages")
+ elseif (arg STREQUAL "FILES")
+ set(_state "files")
+ elseif (arg STREQUAL "SOURCEPATH")
+ set(_state "sourcepath")
+ elseif (arg STREQUAL "CLASSPATH")
+ set(_state "classpath")
+ elseif (arg STREQUAL "INSTALLPATH")
+ set(_state "installpath")
+ elseif (arg STREQUAL "DOCTITLE")
+ set(_state "doctitle")
+ elseif (arg STREQUAL "WINDOWTITLE")
+ set(_state "windowtitle")
+ elseif (arg STREQUAL "AUTHOR")
+ set(_state "author")
+ elseif (arg STREQUAL "USE")
+ set(_state "use")
+ elseif (arg STREQUAL "VERSION")
+ set(_state "version")
+ else ()
+ set(_javadoc_version ${arg})
+ endif ()
+ endif ()
+ endforeach ()
+
+ set(_javadoc_builddir ${CMAKE_CURRENT_BINARY_DIR}/javadoc/${_target})
+ set(_javadoc_options -d ${_javadoc_builddir})
+
+ if (_javadoc_sourcepath)
+ list(JOIN _javadoc_sourcepath "${_UseJava_PATH_SEP}" _javadoc_sourcepath)
+ list(APPEND _javadoc_options -sourcepath "\"${_javadoc_sourcepath}\"")
+ endif ()
+
+ if (_javadoc_classpath)
+ list(JOIN _javadoc_classpath "${_UseJava_PATH_SEP}" _javadoc_classpath)
+ list(APPEND _javadoc_options -classpath "\"${_javadoc_classpath}\"")
+ endif ()
+
+ if (_javadoc_doctitle)
+ list(APPEND _javadoc_options -doctitle '${_javadoc_doctitle}')
+ endif ()
+
+ if (_javadoc_windowtitle)
+ list(APPEND _javadoc_options -windowtitle '${_javadoc_windowtitle}')
+ endif ()
+
+ if (_javadoc_author)
+ list(APPEND _javadoc_options -author)
+ endif ()
+
+ if (_javadoc_use)
+ list(APPEND _javadoc_options -use)
+ endif ()
+
+ if (_javadoc_version)
+ list(APPEND _javadoc_options -version)
+ endif ()
+
+ add_custom_target(${_target}_javadoc ALL
+ COMMAND ${Java_JAVADOC_EXECUTABLE}
+ ${_javadoc_options}
+ ${_javadoc_files}
+ ${_javadoc_packages}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+
+ install(
+ DIRECTORY ${_javadoc_builddir}
+ DESTINATION ${_javadoc_installpath}
+ )
+endfunction()
+
+function (create_javah)
+ if (Java_VERSION VERSION_GREATER_EQUAL 10)
+ message (FATAL_ERROR "create_javah: not supported with this Java version. Use add_jar(GENERATE_NATIVE_HEADERS) instead.")
+ elseif (Java_VERSION VERSION_GREATER_EQUAL 1.8)
+ message (DEPRECATION "create_javah: this command will no longer be supported starting with version 10 of JDK. Update your project by using command add_jar(GENERATE_NATIVE_HEADERS) instead.")
+ endif()
+
+ cmake_parse_arguments(_create_javah
+ ""
+ "TARGET;GENERATED_FILES;OUTPUT_NAME;OUTPUT_DIR"
+ "CLASSES;CLASSPATH;DEPENDS"
+ ${ARGN})
+
+ # ckeck parameters
+ if (NOT _create_javah_TARGET AND NOT _create_javah_GENERATED_FILES)
+ message (FATAL_ERROR "create_javah: TARGET or GENERATED_FILES must be specified.")
+ endif()
+ if (_create_javah_OUTPUT_NAME AND _create_javah_OUTPUT_DIR)
+ message (FATAL_ERROR "create_javah: OUTPUT_NAME and OUTPUT_DIR are mutually exclusive.")
+ endif()
+
+ if (NOT _create_javah_CLASSES)
+ message (FATAL_ERROR "create_javah: CLASSES is a required parameter.")
+ endif()
+
+ set (_output_files)
+
+ # handle javah options
+ set (_javah_options)
+
+ if (_create_javah_CLASSPATH)
+ # CLASSPATH can specify directories, jar files or targets created with add_jar command
+ set (_classpath)
+ foreach (_path IN LISTS _create_javah_CLASSPATH)
+ if (TARGET ${_path})
+ get_target_property (_jar_path ${_path} JAR_FILE)
+ if (_jar_path)
+ list (APPEND _classpath "${_jar_path}")
+ list (APPEND _create_javah_DEPENDS "${_path}")
+ else()
+ message(SEND_ERROR "create_javah: CLASSPATH target ${_path} is not a jar.")
+ endif()
+ elseif (EXISTS "${_path}")
+ list (APPEND _classpath "${_path}")
+ if (NOT IS_DIRECTORY "${_path}")
+ list (APPEND _create_javah_DEPENDS "${_path}")
+ endif()
+ else()
+ message(SEND_ERROR "create_javah: CLASSPATH entry ${_path} does not exist.")
+ endif()
+ endforeach()
+ string (REPLACE ";" "${_UseJava_PATH_SEP}" _classpath "${_classpath}")
+ list (APPEND _javah_options -classpath "${_classpath}")
+ endif()
+
+ if (_create_javah_OUTPUT_DIR)
+ list (APPEND _javah_options -d "${_create_javah_OUTPUT_DIR}")
+ endif()
+
+ if (_create_javah_OUTPUT_NAME)
+ list (APPEND _javah_options -o "${_create_javah_OUTPUT_NAME}")
+ set (_output_files "${_create_javah_OUTPUT_NAME}")
+
+ get_filename_component (_create_javah_OUTPUT_DIR "${_create_javah_OUTPUT_NAME}" DIRECTORY)
+ get_filename_component (_create_javah_OUTPUT_DIR "${_create_javah_OUTPUT_DIR}" ABSOLUTE)
+ endif()
+
+ if (NOT _create_javah_OUTPUT_DIR)
+ set (_create_javah_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+
+ if (NOT _create_javah_OUTPUT_NAME)
+ # compute output names
+ foreach (_class IN LISTS _create_javah_CLASSES)
+ string (REPLACE "." "_" _c_header "${_class}")
+ set (_c_header "${_create_javah_OUTPUT_DIR}/${_c_header}.h")
+ list (APPEND _output_files "${_c_header}")
+ endforeach()
+ endif()
+
+ # finalize custom command arguments
+ if (_create_javah_DEPENDS)
+ list (INSERT _create_javah_DEPENDS 0 DEPENDS)
+ endif()
+
+ add_custom_command (OUTPUT ${_output_files}
+ COMMAND "${Java_JAVAH_EXECUTABLE}" ${_javah_options} -jni ${_create_javah_CLASSES}
+ ${_create_javah_DEPENDS}
+ WORKING_DIRECTORY ${_create_javah_OUTPUT_DIR}
+ COMMENT "Building C header files from classes...")
+
+ if (_create_javah_TARGET)
+ add_custom_target (${_create_javah_TARGET} ALL DEPENDS ${_output_files})
+ endif()
+ if (_create_javah_GENERATED_FILES)
+ set (${_create_javah_GENERATED_FILES} ${_output_files} PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(export_jars)
+ # Parse and validate arguments
+ cmake_parse_arguments(_export_jars
+ ""
+ "FILE;NAMESPACE"
+ "TARGETS"
+ ${ARGN}
+ )
+ if (NOT _export_jars_FILE)
+ message(SEND_ERROR "export_jars: FILE must be specified.")
+ endif()
+ if (NOT _export_jars_TARGETS)
+ message(SEND_ERROR "export_jars: TARGETS must be specified.")
+ endif()
+ set(_jar_NAMESPACE "${_export_jars_NAMESPACE}")
+
+ # Set content of generated exports file
+ string(REPLACE ";" " " __targets__ "${_export_jars_TARGETS}")
+ set(__targetdefs__ "")
+ foreach(_target IN LISTS _export_jars_TARGETS)
+ get_target_property(_jarpath ${_target} JAR_FILE)
+ get_filename_component(_jarpath ${_jarpath} PATH)
+ __java_export_jar(__targetdefs__ ${_target} "${_jarpath}")
+ endforeach()
+
+ # Generate exports file
+ configure_file(
+ ${_JAVA_EXPORT_TARGETS_SCRIPT}
+ ${_export_jars_FILE}
+ @ONLY
+ )
+endfunction()
+
+function(install_jar_exports)
+ # Parse and validate arguments
+ cmake_parse_arguments(_install_jar_exports
+ ""
+ "FILE;DESTINATION;COMPONENT;NAMESPACE"
+ "TARGETS"
+ ${ARGN}
+ )
+ if (NOT _install_jar_exports_FILE)
+ message(SEND_ERROR "install_jar_exports: FILE must be specified.")
+ endif()
+ if (NOT _install_jar_exports_DESTINATION)
+ message(SEND_ERROR "install_jar_exports: DESTINATION must be specified.")
+ endif()
+ if (NOT _install_jar_exports_TARGETS)
+ message(SEND_ERROR "install_jar_exports: TARGETS must be specified.")
+ endif()
+ set(_jar_NAMESPACE "${_install_jar_exports_NAMESPACE}")
+
+ if (_install_jar_exports_COMPONENT)
+ set (_COMPONENT COMPONENT ${_install_jar_exports_COMPONENT})
+ endif()
+
+ # Determine relative path from installed export file to install prefix
+ if(IS_ABSOLUTE "${_install_jar_exports_DESTINATION}")
+ file(RELATIVE_PATH _relpath
+ ${_install_jar_exports_DESTINATION}
+ ${CMAKE_INSTALL_PREFIX}
+ )
+ else()
+ file(RELATIVE_PATH _relpath
+ ${CMAKE_INSTALL_PREFIX}/${_install_jar_exports_DESTINATION}
+ ${CMAKE_INSTALL_PREFIX}
+ )
+ endif()
+
+ # Set up unique location for generated exports file
+ string(SHA256 _hash "${_install_jar_exports_DESTINATION}")
+ set(_tmpdir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/JavaExports/${_hash})
+
+ # Set content of generated exports file
+ string(REPLACE ";" " " __targets__ "${_install_jar_exports_TARGETS}")
+ set(__targetdefs__ "set(_prefix \${CMAKE_CURRENT_LIST_DIR}/${_relpath})\n\n")
+ foreach(_target IN LISTS _install_jar_exports_TARGETS)
+ get_target_property(_dir ${_target} INSTALL_DESTINATION)
+ __java_export_jar(__targetdefs__ ${_target} "\${_prefix}/${_dir}")
+ endforeach()
+ __java_lcat(__targetdefs__ "\nunset(_prefix)")
+
+ # Generate and install exports file
+ configure_file(
+ ${_JAVA_EXPORT_TARGETS_SCRIPT}
+ ${_tmpdir}/${_install_jar_exports_FILE}
+ @ONLY
+ )
+ install(FILES ${_tmpdir}/${_install_jar_exports_FILE}
+ DESTINATION ${_install_jar_exports_DESTINATION}
+ ${_COMPONENT})
+endfunction()
diff --git a/Modules/UseJava/ClassFilelist.cmake b/Modules/UseJava/ClassFilelist.cmake
new file mode 100644
index 0000000..aa9e35d
--- /dev/null
+++ b/Modules/UseJava/ClassFilelist.cmake
@@ -0,0 +1,40 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This script creates a list of compiled Java class files to be added to
+# a jar file. This avoids including cmake files which get created in
+# the binary directory.
+
+if (CMAKE_JAVA_CLASS_OUTPUT_PATH)
+ if (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
+
+ set(_JAVA_GLOBBED_FILES)
+ if (CMAKE_JAR_CLASSES_PREFIX)
+ foreach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX})
+ message(STATUS "JAR_CLASS_PREFIX: ${JAR_CLASS_PREFIX}")
+
+ file(GLOB_RECURSE _JAVA_GLOBBED_TMP_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${JAR_CLASS_PREFIX}/*.class")
+ if (_JAVA_GLOBBED_TMP_FILES)
+ list(APPEND _JAVA_GLOBBED_FILES ${_JAVA_GLOBBED_TMP_FILES})
+ endif ()
+ endforeach()
+ else()
+ file(GLOB_RECURSE _JAVA_GLOBBED_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/*.class")
+ endif ()
+
+ set(_JAVA_CLASS_FILES)
+ # file(GLOB_RECURSE foo RELATIVE) is broken so we need this.
+ foreach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES})
+ file(RELATIVE_PATH _JAVA_CLASS_FILE ${CMAKE_JAVA_CLASS_OUTPUT_PATH} ${_JAVA_GLOBBED_FILE})
+ set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES}${_JAVA_CLASS_FILE}\n)
+ endforeach()
+
+ # write to file
+ file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist ${_JAVA_CLASS_FILES})
+
+ else ()
+ message(SEND_ERROR "FATAL: Java class output path doesn't exist")
+ endif ()
+else ()
+ message(SEND_ERROR "FATAL: Can't find CMAKE_JAVA_CLASS_OUTPUT_PATH")
+endif ()
diff --git a/Modules/UseJava/ClearClassFiles.cmake b/Modules/UseJava/ClearClassFiles.cmake
new file mode 100644
index 0000000..f3115c6
--- /dev/null
+++ b/Modules/UseJava/ClearClassFiles.cmake
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This script deletes compiled Java class files.
+
+if(CMAKE_JAVA_CLASS_OUTPUT_PATH)
+ if(EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist")
+ file(STRINGS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist" classes)
+ list(TRANSFORM classes PREPEND "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/")
+ if(classes)
+ file(REMOVE ${classes})
+ message(STATUS "Clean class files from previous build")
+ endif()
+ endif()
+else()
+ message(FATAL_ERROR "Can't find CMAKE_JAVA_CLASS_OUTPUT_PATH")
+endif()
diff --git a/Modules/UseJava/Symlinks.cmake b/Modules/UseJava/Symlinks.cmake
new file mode 100644
index 0000000..2788195
--- /dev/null
+++ b/Modules/UseJava/Symlinks.cmake
@@ -0,0 +1,20 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# Helper script for UseJava.cmake
+
+if (UNIX AND _JAVA_TARGET_OUTPUT_LINK)
+ if (_JAVA_TARGET_OUTPUT_NAME)
+ find_program(LN_EXECUTABLE
+ NAMES
+ ln
+ )
+
+ execute_process(
+ COMMAND ${LN_EXECUTABLE} -sf "${_JAVA_TARGET_OUTPUT_NAME}" "${_JAVA_TARGET_OUTPUT_LINK}"
+ WORKING_DIRECTORY ${_JAVA_TARGET_DIR}
+ )
+ else ()
+ message(SEND_ERROR "FATAL: Can't find _JAVA_TARGET_OUTPUT_NAME")
+ endif ()
+endif ()
diff --git a/Modules/UseJava/javaTargets.cmake.in b/Modules/UseJava/javaTargets.cmake.in
new file mode 100644
index 0000000..6e14256
--- /dev/null
+++ b/Modules/UseJava/javaTargets.cmake.in
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 2.8.12)
+cmake_policy(PUSH)
+cmake_policy(VERSION 2.8)
+
+#----------------------------------------------------------------
+# Generated CMake Java target import file.
+#----------------------------------------------------------------
+
+# Protect against multiple inclusion, which would fail when already imported targets are added once more.
+set(_targetsDefined)
+set(_targetsNotDefined)
+set(_expectedTargets)
+foreach(_expectedTarget @__targets__@)
+ list(APPEND _expectedTargets ${_expectedTarget})
+ if(TARGET ${_expectedTarget})
+ list(APPEND _targetsDefined ${_expectedTarget})
+ else()
+ list(APPEND _targetsNotDefined ${_expectedTarget})
+ endif()
+endforeach()
+if("%${_targetsDefined}" STREQUAL "%${_expectedTargets}")
+ unset(_targetsDefined)
+ unset(_targetsNotDefined)
+ unset(_expectedTargets)
+ cmake_policy(POP)
+ return()
+endif()
+if(NOT "${_targetsDefined}" STREQUAL "")
+ message(FATAL_ERROR
+ "Some (but not all) targets in this export set were already defined.\n"
+ "Targets Defined: ${_targetsDefined}\n"
+ "Targets not yet defined: ${_targetsNotDefined}\n")
+endif()
+unset(_targetsDefined)
+unset(_targetsNotDefined)
+unset(_expectedTargets)
+
+@__targetdefs__@
+cmake_policy(POP)
diff --git a/Modules/UsePkgConfig.cmake b/Modules/UsePkgConfig.cmake
new file mode 100644
index 0000000..32d228d
--- /dev/null
+++ b/Modules/UsePkgConfig.cmake
@@ -0,0 +1,75 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+UsePkgConfig
+------------
+
+Obsolete pkg-config module for CMake, use FindPkgConfig instead.
+
+
+
+This module defines the following macro:
+
+PKGCONFIG(package includedir libdir linkflags cflags)
+
+Calling PKGCONFIG will fill the desired information into the 4 given
+arguments, e.g. PKGCONFIG(libart-2.0 LIBART_INCLUDE_DIR
+LIBART_LINK_DIR LIBART_LINK_FLAGS LIBART_CFLAGS) if pkg-config was NOT
+found or the specified software package doesn't exist, the variable
+will be empty when the function returns, otherwise they will contain
+the respective information
+#]=======================================================================]
+
+find_program(PKGCONFIG_EXECUTABLE NAMES pkg-config )
+
+macro(PKGCONFIG _package _include_DIR _link_DIR _link_FLAGS _cflags)
+ message(STATUS
+ "WARNING: you are using the obsolete 'PKGCONFIG' macro, use FindPkgConfig")
+# reset the variables at the beginning
+ set(${_include_DIR})
+ set(${_link_DIR})
+ set(${_link_FLAGS})
+ set(${_cflags})
+
+ # if pkg-config has been found
+ if(PKGCONFIG_EXECUTABLE)
+
+ exec_program(${PKGCONFIG_EXECUTABLE} ARGS ${_package} --exists RETURN_VALUE _return_VALUE OUTPUT_VARIABLE _pkgconfigDevNull )
+
+ # and if the package of interest also exists for pkg-config, then get the information
+ if(NOT _return_VALUE)
+
+ exec_program(${PKGCONFIG_EXECUTABLE} ARGS ${_package} --variable=includedir
+ OUTPUT_VARIABLE ${_include_DIR} )
+ string(REGEX REPLACE "[\r\n]" " " ${_include_DIR} "${${_include_DIR}}")
+
+
+ exec_program(${PKGCONFIG_EXECUTABLE} ARGS ${_package} --variable=libdir
+ OUTPUT_VARIABLE ${_link_DIR} )
+ string(REGEX REPLACE "[\r\n]" " " ${_link_DIR} "${${_link_DIR}}")
+
+ exec_program(${PKGCONFIG_EXECUTABLE} ARGS ${_package} --libs
+ OUTPUT_VARIABLE ${_link_FLAGS} )
+ string(REGEX REPLACE "[\r\n]" " " ${_link_FLAGS} "${${_link_FLAGS}}")
+
+ exec_program(${PKGCONFIG_EXECUTABLE} ARGS ${_package} --cflags
+ OUTPUT_VARIABLE ${_cflags} )
+ string(REGEX REPLACE "[\r\n]" " " ${_cflags} "${${_cflags}}")
+
+ else()
+
+ message(STATUS "PKGCONFIG() indicates that ${_package} is not installed (install the package which contains ${_package}.pc if you want to support this feature)")
+
+ endif()
+
+ # if pkg-config has NOT been found, INFORM the user
+ else()
+
+ message(STATUS "WARNING: PKGCONFIG() indicates that the tool pkg-config has not been found on your system. You should install it.")
+
+ endif()
+
+endmacro()
+
+mark_as_advanced(PKGCONFIG_EXECUTABLE)
diff --git a/Modules/UseQt4.cmake b/Modules/UseQt4.cmake
new file mode 100644
index 0000000..8fec717
--- /dev/null
+++ b/Modules/UseQt4.cmake
@@ -0,0 +1,107 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+UseQt4
+------
+
+Use Module for QT4
+
+Sets up C and C++ to use Qt 4. It is assumed that :module:`FindQt` has
+already been loaded. See :module:`FindQt` for information on how to load
+Qt 4 into your CMake project.
+#]=======================================================================]
+
+add_definitions(${QT_DEFINITIONS})
+set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<NOT:$<CONFIG:Debug>>:QT_NO_DEBUG>)
+
+if(QT_INCLUDE_DIRS_NO_SYSTEM)
+ include_directories(${QT_INCLUDE_DIR})
+else(QT_INCLUDE_DIRS_NO_SYSTEM)
+ include_directories(SYSTEM ${QT_INCLUDE_DIR})
+endif(QT_INCLUDE_DIRS_NO_SYSTEM)
+
+set(QT_LIBRARIES "")
+set(QT_LIBRARIES_PLUGINS "")
+
+if (QT_USE_QTMAIN)
+ if (Q_WS_WIN)
+ set(QT_LIBRARIES ${QT_LIBRARIES} ${QT_QTMAIN_LIBRARY})
+ endif ()
+endif ()
+
+if(QT_DONT_USE_QTGUI)
+ set(QT_USE_QTGUI 0)
+else()
+ set(QT_USE_QTGUI 1)
+endif()
+
+if(QT_DONT_USE_QTCORE)
+ set(QT_USE_QTCORE 0)
+else()
+ set(QT_USE_QTCORE 1)
+endif()
+
+if (QT_USE_QT3SUPPORT)
+ add_definitions(-DQT3_SUPPORT)
+endif ()
+
+# list dependent modules, so dependent libraries are added
+set(QT_QT3SUPPORT_MODULE_DEPENDS QTGUI QTSQL QTXML QTNETWORK QTCORE)
+set(QT_QTSVG_MODULE_DEPENDS QTGUI QTCORE)
+set(QT_QTUITOOLS_MODULE_DEPENDS QTGUI QTXML QTCORE)
+set(QT_QTHELP_MODULE_DEPENDS QTGUI QTSQL QTXML QTNETWORK QTCORE)
+if(QT_QTDBUS_FOUND)
+ set(QT_PHONON_MODULE_DEPENDS QTGUI QTDBUS QTCORE)
+else()
+ set(QT_PHONON_MODULE_DEPENDS QTGUI QTCORE)
+endif()
+set(QT_QTDBUS_MODULE_DEPENDS QTXML QTCORE)
+set(QT_QTXMLPATTERNS_MODULE_DEPENDS QTNETWORK QTCORE)
+set(QT_QAXCONTAINER_MODULE_DEPENDS QTGUI QTCORE)
+set(QT_QAXSERVER_MODULE_DEPENDS QTGUI QTCORE)
+set(QT_QTSCRIPTTOOLS_MODULE_DEPENDS QTGUI QTCORE)
+set(QT_QTWEBKIT_MODULE_DEPENDS QTXMLPATTERNS QTGUI QTCORE)
+set(QT_QTDECLARATIVE_MODULE_DEPENDS QTSCRIPT QTSVG QTSQL QTXMLPATTERNS QTGUI QTCORE)
+set(QT_QTMULTIMEDIA_MODULE_DEPENDS QTGUI QTCORE)
+set(QT_QTOPENGL_MODULE_DEPENDS QTGUI QTCORE)
+set(QT_QTSCRIPT_MODULE_DEPENDS QTCORE)
+set(QT_QTGUI_MODULE_DEPENDS QTCORE)
+set(QT_QTTEST_MODULE_DEPENDS QTCORE)
+set(QT_QTXML_MODULE_DEPENDS QTCORE)
+set(QT_QTSQL_MODULE_DEPENDS QTCORE)
+set(QT_QTNETWORK_MODULE_DEPENDS QTCORE)
+
+# Qt modules (in order of dependence)
+foreach(module QT3SUPPORT QTOPENGL QTASSISTANT QTDESIGNER QTMOTIF QTNSPLUGIN
+ QAXSERVER QAXCONTAINER QTDECLARATIVE QTSCRIPT QTSVG QTUITOOLS QTHELP
+ QTWEBKIT PHONON QTSCRIPTTOOLS QTMULTIMEDIA QTXMLPATTERNS QTGUI QTTEST
+ QTDBUS QTXML QTSQL QTNETWORK QTCORE)
+
+ if (QT_USE_${module} OR QT_USE_${module}_DEPENDS)
+ if (QT_${module}_FOUND)
+ if(QT_USE_${module})
+ string(REPLACE "QT" "" qt_module_def "${module}")
+ add_definitions(-DQT_${qt_module_def}_LIB)
+ if(QT_INCLUDE_DIRS_NO_SYSTEM)
+ include_directories(${QT_${module}_INCLUDE_DIR})
+ else(QT_INCLUDE_DIRS_NO_SYSTEM)
+ include_directories(SYSTEM ${QT_${module}_INCLUDE_DIR})
+ endif(QT_INCLUDE_DIRS_NO_SYSTEM)
+ endif()
+ if(QT_USE_${module} OR QT_IS_STATIC)
+ set(QT_LIBRARIES ${QT_LIBRARIES} ${QT_${module}_LIBRARY})
+ endif()
+ set(QT_LIBRARIES_PLUGINS ${QT_LIBRARIES_PLUGINS} ${QT_${module}_PLUGINS})
+ if(QT_IS_STATIC)
+ set(QT_LIBRARIES ${QT_LIBRARIES} ${QT_${module}_LIB_DEPENDENCIES})
+ endif()
+ foreach(depend_module ${QT_${module}_MODULE_DEPENDS})
+ set(QT_USE_${depend_module}_DEPENDS 1)
+ endforeach()
+ else ()
+ message("Qt ${module} library not found.")
+ endif ()
+ endif ()
+
+endforeach()
diff --git a/Modules/UseSWIG.cmake b/Modules/UseSWIG.cmake
new file mode 100644
index 0000000..8852df8
--- /dev/null
+++ b/Modules/UseSWIG.cmake
@@ -0,0 +1,1021 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+UseSWIG
+-------
+
+This file provides support for ``SWIG``. It is assumed that :module:`FindSWIG`
+module has already been loaded.
+
+Defines the following command for use with ``SWIG``:
+
+.. command:: swig_add_library
+
+ .. versionadded:: 3.8
+
+ Define swig module with given name and specified language::
+
+ swig_add_library(<name>
+ [TYPE <SHARED|MODULE|STATIC|USE_BUILD_SHARED_LIBS>]
+ LANGUAGE <language>
+ [NO_PROXY]
+ [OUTPUT_DIR <directory>]
+ [OUTFILE_DIR <directory>]
+ SOURCES <file>...
+ )
+
+ Targets created with the ``swig_add_library`` command have the same
+ capabilities as targets created with the :command:`add_library` command, so
+ those targets can be used with any command expecting a target (e.g.
+ :command:`target_link_libraries`).
+
+ .. versionchanged:: 3.13
+ This command creates a target with the specified ``<name>`` when
+ policy :policy:`CMP0078` is set to ``NEW``. Otherwise, the legacy
+ behavior will choose a different target name and store it in the
+ ``SWIG_MODULE_<name>_REAL_NAME`` variable.
+
+ .. versionchanged:: 3.15
+ Alternate library name (set with the :prop_tgt:`OUTPUT_NAME` property,
+ for example) will be passed on to ``Python`` and ``CSharp`` wrapper
+ libraries.
+
+ .. versionchanged:: 3.21
+ Generated library use standard naming conventions for ``CSharp`` language
+ when policy :policy:`CMP0122` is set to ``NEW``. Otherwise, the legacy
+ behavior is applied.
+
+ .. note::
+
+ For multi-config generators, this module does not support
+ configuration-specific files generated by ``SWIG``. All build
+ configurations must result in the same generated source file.
+
+ .. note::
+
+ For :ref:`Makefile Generators`, if, for some sources, the
+ ``USE_SWIG_DEPENDENCIES`` property is ``FALSE``, ``swig_add_library`` does
+ not track file dependencies, so depending on the ``<name>_swig_compilation``
+ custom target is required for targets which require the ``swig``-generated
+ files to exist. Other generators may depend on the source files that would
+ be generated by SWIG.
+
+ ``TYPE``
+ ``SHARED``, ``MODULE`` and ``STATIC`` have the same semantic as for the
+ :command:`add_library` command. If ``USE_BUILD_SHARED_LIBS`` is specified,
+ the library type will be ``STATIC`` or ``SHARED`` based on whether the
+ current value of the :variable:`BUILD_SHARED_LIBS` variable is ``ON``. If
+ no type is specified, ``MODULE`` will be used.
+
+ ``LANGUAGE``
+ Specify the target language.
+
+ .. versionadded:: 3.1
+ Go and Lua language support.
+
+ .. versionadded:: 3.2
+ R language support.
+
+ .. versionadded:: 3.18
+ Fortran language support.
+
+ ``NO_PROXY``
+ .. versionadded:: 3.12
+
+ Prevent the generation of the wrapper layer (swig ``-noproxy`` option).
+
+ ``OUTPUT_DIR``
+ .. versionadded:: 3.12
+
+ Specify where to write the language specific files (swig ``-outdir``
+ option). If not given, the ``CMAKE_SWIG_OUTDIR`` variable will be used.
+ If neither is specified, the default depends on the value of the
+ ``UseSWIG_MODULE_VERSION`` variable as follows:
+
+ * If ``UseSWIG_MODULE_VERSION`` is 1 or is undefined, output is written to
+ the :variable:`CMAKE_CURRENT_BINARY_DIR` directory.
+ * If ``UseSWIG_MODULE_VERSION`` is 2, a dedicated directory will be used.
+ The path of this directory can be retrieved from the
+ ``SWIG_SUPPORT_FILES_DIRECTORY`` target property.
+
+ ``OUTFILE_DIR``
+ .. versionadded:: 3.12
+
+ Specify an output directory name where the generated source file will be
+ placed (swig ``-o`` option). If not specified, the ``SWIG_OUTFILE_DIR``
+ variable will be used. If neither is specified, ``OUTPUT_DIR`` or
+ ``CMAKE_SWIG_OUTDIR`` is used instead.
+
+ ``SOURCES``
+ List of sources for the library. Files with extension ``.i`` will be
+ identified as sources for the ``SWIG`` tool. Other files will be handled in
+ the standard way.
+
+ .. versionadded:: 3.14
+ This behavior can be overridden by specifying the variable
+ ``SWIG_SOURCE_FILE_EXTENSIONS``.
+
+ .. note::
+
+ If ``UseSWIG_MODULE_VERSION`` is set to 2, it is **strongly** recommended
+ to use a dedicated directory unique to the target when either the
+ ``OUTPUT_DIR`` option or the ``CMAKE_SWIG_OUTDIR`` variable are specified.
+ The output directory contents are erased as part of the target build, so
+ to prevent interference between targets or losing other important files,
+ each target should have its own dedicated output directory.
+
+.. command:: swig_link_libraries
+
+ Link libraries to swig module::
+
+ swig_link_libraries(<name> <item>...)
+
+ This command has same capabilities as :command:`target_link_libraries`
+ command.
+
+ .. note::
+
+ If variable ``UseSWIG_TARGET_NAME_PREFERENCE`` is set to ``STANDARD``, this
+ command is deprecated and :command:`target_link_libraries` command must be
+ used instead.
+
+Source file properties on module files **must** be set before the invocation
+of the ``swig_add_library`` command to specify special behavior of SWIG and
+ensure generated files will receive the required settings.
+
+``CPLUSPLUS``
+ Call SWIG in c++ mode. For example:
+
+ .. code-block:: cmake
+
+ set_property(SOURCE mymod.i PROPERTY CPLUSPLUS ON)
+ swig_add_library(mymod LANGUAGE python SOURCES mymod.i)
+
+``SWIG_FLAGS``
+ .. deprecated:: 3.12
+ Replaced with the fine-grained properties that follow.
+
+ Pass custom flags to the SWIG executable.
+
+``INCLUDE_DIRECTORIES``, ``COMPILE_DEFINITIONS`` and ``COMPILE_OPTIONS``
+ .. versionadded:: 3.12
+
+ Add custom flags to SWIG compiler and have same semantic as properties
+ :prop_sf:`INCLUDE_DIRECTORIES`, :prop_sf:`COMPILE_DEFINITIONS` and
+ :prop_sf:`COMPILE_OPTIONS`.
+
+``USE_TARGET_INCLUDE_DIRECTORIES``
+ .. versionadded:: 3.13
+
+ If set to ``TRUE``, contents of target property
+ :prop_tgt:`INCLUDE_DIRECTORIES` will be forwarded to ``SWIG`` compiler.
+ If set to ``FALSE`` target property :prop_tgt:`INCLUDE_DIRECTORIES` will be
+ ignored. If not set, target property ``SWIG_USE_TARGET_INCLUDE_DIRECTORIES``
+ will be considered.
+
+``GENERATED_INCLUDE_DIRECTORIES``, ``GENERATED_COMPILE_DEFINITIONS`` and ``GENERATED_COMPILE_OPTIONS``
+ .. versionadded:: 3.12
+
+ Add custom flags to the C/C++ generated source. They will fill, respectively,
+ properties :prop_sf:`INCLUDE_DIRECTORIES`, :prop_sf:`COMPILE_DEFINITIONS` and
+ :prop_sf:`COMPILE_OPTIONS` of generated C/C++ file.
+
+``DEPENDS``
+ .. versionadded:: 3.12
+
+ Specify additional dependencies to the source file.
+
+``USE_SWIG_DEPENDENCIES``
+ .. versionadded:: 3.20
+
+ If set to ``TRUE``, implicit dependencies are generated by the ``swig`` tool
+ itself. This property is only meaningful for
+ :ref:`Makefile <Makefile Generators>` and
+ :ref:`Ninja <Ninja Generators>` generators. Default value is ``FALSE``.
+
+``SWIG_MODULE_NAME``
+ Specify the actual import name of the module in the target language.
+ This is required if it cannot be scanned automatically from source
+ or different from the module file basename. For example:
+
+ .. code-block:: cmake
+
+ set_property(SOURCE mymod.i PROPERTY SWIG_MODULE_NAME mymod_realname)
+
+ .. versionchanged:: 3.14
+ If policy :policy:`CMP0086` is set to ``NEW``, ``-module <module_name>``
+ is passed to ``SWIG`` compiler.
+
+``OUTPUT_DIR``
+ .. versionadded:: 3.19
+
+ Specify where to write the language specific files (swig ``-outdir`` option)
+ for the considered source file. If not specified, the other ways to define
+ the output directory applies (see ``OUTPUT_DIR`` option of
+ ``swig_add_library()`` command).
+
+``OUTFILE_DIR``
+ .. versionadded:: 3.19
+
+ Specify an output directory where the generated source file will be placed
+ (swig ``-o`` option) for the considered source file. If not specified,
+ ``OUTPUT_DIR`` source property will be used. If neither are specified, the
+ other ways to define output file directory applies (see ``OUTFILE_DIR``
+ option of ``swig_add_library()`` command).
+
+Target library properties can be set to apply same configuration to all SWIG
+input files.
+
+``SWIG_INCLUDE_DIRECTORIES``, ``SWIG_COMPILE_DEFINITIONS`` and ``SWIG_COMPILE_OPTIONS``
+ .. versionadded:: 3.12
+
+ These properties will be applied to all SWIG input files and have same
+ semantic as target properties :prop_tgt:`INCLUDE_DIRECTORIES`,
+ :prop_tgt:`COMPILE_DEFINITIONS` and :prop_tgt:`COMPILE_OPTIONS`.
+
+ .. code-block:: cmake
+
+ set (UseSWIG_TARGET_NAME_PREFERENCE STANDARD)
+ swig_add_library(mymod LANGUAGE python SOURCES mymod.i)
+ set_property(TARGET mymod PROPERTY SWIG_COMPILE_DEFINITIONS MY_DEF1 MY_DEF2)
+ set_property(TARGET mymod PROPERTY SWIG_COMPILE_OPTIONS -bla -blb)
+
+``SWIG_USE_TARGET_INCLUDE_DIRECTORIES``
+ .. versionadded:: 3.13
+
+ If set to ``TRUE``, contents of target property
+ :prop_tgt:`INCLUDE_DIRECTORIES` will be forwarded to ``SWIG`` compiler.
+ If set to ``FALSE`` or not defined, target property
+ :prop_tgt:`INCLUDE_DIRECTORIES` will be ignored. This behavior can be
+ overridden by specifying source property ``USE_TARGET_INCLUDE_DIRECTORIES``.
+
+``SWIG_GENERATED_INCLUDE_DIRECTORIES``, ``SWIG_GENERATED_COMPILE_DEFINITIONS`` and ``SWIG_GENERATED_COMPILE_OPTIONS``
+ .. versionadded:: 3.12
+
+ These properties will populate, respectively, properties
+ :prop_sf:`INCLUDE_DIRECTORIES`, :prop_sf:`COMPILE_DEFINITIONS` and
+ :prop_sf:`COMPILE_FLAGS` of all generated C/C++ files.
+
+``SWIG_DEPENDS``
+ .. versionadded:: 3.12
+
+ Add dependencies to all SWIG input files.
+
+The following target properties are output properties and can be used to get
+information about support files generated by ``SWIG`` interface compilation.
+
+``SWIG_SUPPORT_FILES``
+ .. versionadded:: 3.12
+
+ This output property list of wrapper files generated during SWIG compilation.
+
+ .. code-block:: cmake
+
+ set (UseSWIG_TARGET_NAME_PREFERENCE STANDARD)
+ swig_add_library(mymod LANGUAGE python SOURCES mymod.i)
+ get_property(support_files TARGET mymod PROPERTY SWIG_SUPPORT_FILES)
+
+ .. note::
+
+ Only most principal support files are listed. In case some advanced
+ features of ``SWIG`` are used (for example ``%template``), associated
+ support files may not be listed. Prefer to use the
+ ``SWIG_SUPPORT_FILES_DIRECTORY`` property to handle support files.
+
+``SWIG_SUPPORT_FILES_DIRECTORY``
+ .. versionadded:: 3.12
+
+ This output property specifies the directory where support files will be
+ generated.
+
+ .. note::
+
+ When source property ``OUTPUT_DIR`` is defined, multiple directories can be
+ specified as part of ``SWIG_SUPPORT_FILES_DIRECTORY``.
+
+Some variables can be set to customize the behavior of ``swig_add_library``
+as well as ``SWIG``:
+
+``UseSWIG_MODULE_VERSION``
+ .. versionadded:: 3.12
+
+ Specify different behaviors for ``UseSWIG`` module.
+
+ * Set to 1 or undefined: Legacy behavior is applied.
+ * Set to 2: A new strategy is applied regarding support files: the output
+ directory of support files is erased before ``SWIG`` interface compilation.
+
+``CMAKE_SWIG_FLAGS``
+ Add flags to all swig calls.
+
+``CMAKE_SWIG_OUTDIR``
+ Specify where to write the language specific files (swig ``-outdir`` option).
+
+``SWIG_OUTFILE_DIR``
+ .. versionadded:: 3.8
+
+ Specify an output directory name where the generated source file will be
+ placed. If not specified, ``CMAKE_SWIG_OUTDIR`` is used.
+
+``SWIG_MODULE_<name>_EXTRA_DEPS``
+ Specify extra dependencies for the generated module for ``<name>``.
+
+``SWIG_SOURCE_FILE_EXTENSIONS``
+ .. versionadded:: 3.14
+
+ Specify a list of source file extensions to override the default
+ behavior of considering only ``.i`` files as sources for the ``SWIG``
+ tool. For example:
+
+ .. code-block:: cmake
+
+ set(SWIG_SOURCE_FILE_EXTENSIONS ".i" ".swg")
+
+``SWIG_USE_SWIG_DEPENDENCIES``
+ .. versionadded:: 3.20
+
+ If set to ``TRUE``, implicit dependencies are generated by the ``swig`` tool
+ itself. This property is only meaningful for
+ :ref:`Makefile <Makefile Generators>` and
+ :ref:`Ninja <Ninja Generators>` generators. Default value is ``FALSE``.
+
+ Source file property ``USE_SWIG_DEPENDENCIES``, if not defined, will be
+ initialized with the value of this variable.
+#]=======================================================================]
+
+cmake_policy(PUSH)
+# numbers and boolean constants
+cmake_policy (SET CMP0012 NEW)
+# IN_LIST operator
+cmake_policy (SET CMP0057 NEW)
+# Ninja generator normalizes custom command depfile paths
+cmake_policy (SET CMP0116 NEW)
+
+set(SWIG_CXX_EXTENSION "cxx")
+set(SWIG_EXTRA_LIBRARIES "")
+
+set(SWIG_PYTHON_EXTRA_FILE_EXTENSIONS ".py")
+set(SWIG_JAVA_EXTRA_FILE_EXTENSIONS ".java" "JNI.java")
+set(SWIG_CSHARP_EXTRA_FILE_EXTENSIONS ".cs" "PINVOKE.cs")
+
+set(SWIG_MANAGE_SUPPORT_FILES_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/UseSWIG/ManageSupportFiles.cmake")
+
+##
+## PRIVATE functions
+##
+function (__SWIG_COMPUTE_TIMESTAMP name language infile workingdir __timestamp)
+ get_filename_component(filename "${infile}" NAME_WE)
+ set(${__timestamp}
+ "${workingdir}/${filename}${language}.stamp" PARENT_SCOPE)
+ # get_filename_component(filename "${infile}" ABSOLUTE)
+ # string(UUID uuid NAMESPACE 9735D882-D2F8-4E1D-88C9-A0A4F1F6ECA4
+ # NAME ${name}-${language}-${filename} TYPE SHA1)
+ # set(${__timestamp} "${workingdir}/${uuid}.stamp" PARENT_SCOPE)
+endfunction()
+
+#
+# For given swig module initialize variables associated with it
+#
+macro(SWIG_MODULE_INITIALIZE name language)
+ string(TOUPPER "${language}" SWIG_MODULE_${name}_LANGUAGE)
+ string(TOLOWER "${language}" SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG)
+
+ if (NOT DEFINED SWIG_MODULE_${name}_NOPROXY)
+ set (SWIG_MODULE_${name}_NOPROXY FALSE)
+ endif()
+ if ("-noproxy" IN_LIST CMAKE_SWIG_FLAGS)
+ set (SWIG_MODULE_${name}_NOPROXY TRUE)
+ endif ()
+
+ if (SWIG_MODULE_${name}_NOPROXY AND
+ NOT ("-noproxy" IN_LIST CMAKE_SWIG_FLAGS OR "-noproxy" IN_LIST SWIG_MODULE_${name}_EXTRA_FLAGS))
+ list (APPEND SWIG_MODULE_${name}_EXTRA_FLAGS "-noproxy")
+ endif()
+ if(SWIG_MODULE_${name}_LANGUAGE STREQUAL "UNKNOWN")
+ message(FATAL_ERROR "SWIG Error: Language \"${language}\" not found")
+ elseif(SWIG_MODULE_${name}_LANGUAGE STREQUAL "PERL" AND
+ NOT "-shadow" IN_LIST SWIG_MODULE_${name}_EXTRA_FLAGS)
+ list(APPEND SWIG_MODULE_${name}_EXTRA_FLAGS "-shadow")
+ endif()
+endmacro()
+
+#
+# For a given language, input file, and output file, determine extra files that
+# will be generated. This is internal swig macro.
+#
+
+function(SWIG_GET_EXTRA_OUTPUT_FILES language outfiles generatedpath infile)
+ set(files)
+ get_source_file_property(module_basename
+ "${infile}" SWIG_MODULE_NAME)
+ if(NOT module_basename)
+
+ # try to get module name from "%module foo" syntax
+ if ( EXISTS "${infile}" )
+ file ( STRINGS "${infile}" module_basename REGEX "[ ]*%module[ ]*[a-zA-Z0-9_]+.*" )
+ endif ()
+ if ( module_basename )
+ string ( REGEX REPLACE "[ ]*%module[ ]*([a-zA-Z0-9_]+).*" "\\1" module_basename "${module_basename}" )
+
+ else ()
+ # try to get module name from "%module (options=...) foo" syntax
+ if ( EXISTS "${infile}" )
+ file ( STRINGS "${infile}" module_basename REGEX "[ ]*%module[ ]*\\(.*\\)[ ]*[a-zA-Z0-9_]+.*" )
+ endif ()
+ if ( module_basename )
+ string ( REGEX REPLACE "[ ]*%module[ ]*\\(.*\\)[ ]*([a-zA-Z0-9_]+).*" "\\1" module_basename "${module_basename}" )
+
+ else ()
+ # fallback to file basename
+ get_filename_component(module_basename "${infile}" NAME_WE)
+ endif ()
+ endif ()
+
+ endif()
+ foreach(it ${SWIG_${language}_EXTRA_FILE_EXTENSIONS})
+ set(extra_file "${generatedpath}/${module_basename}${it}")
+ if (extra_file MATCHES "\\.cs$" AND CMAKE_CSharp_COMPILER_LOADED)
+ set_source_files_properties(${extra_file} PROPERTIES LANGUAGE "CSharp")
+ else()
+ # Treat extra outputs as plain files regardless of language.
+ set_source_files_properties(${extra_file} PROPERTIES LANGUAGE "")
+ endif()
+ list(APPEND files "${extra_file}")
+ endforeach()
+
+ if (language STREQUAL "FORTRAN" AND CMAKE_Fortran_COMPILER_LOADED)
+ # Process possible user-supplied extension in flags (obtained via parent
+ # scope variable) to determine the source file name.
+ list(FIND SWIG_COMPILATION_FLAGS "-fext" fext_idx)
+ if (fext_idx EQUAL -1)
+ # Default Fortran generated extension
+ set(fext "f90")
+ else()
+ # Get extension from user-provided flag
+ math(EXPR fext_idx "${fext_idx} + 1")
+ list(GET SWIG_COMPILATION_FLAGS "${fext_idx}" fext)
+ endif()
+ set(extra_file "${generatedpath}/${module_basename}.${fext}")
+ set_source_files_properties("${extra_file}" PROPERTIES LANGUAGE "Fortran")
+ list(APPEND files "${extra_file}")
+ endif()
+
+ set (${outfiles} ${files} PARENT_SCOPE)
+endfunction()
+
+#
+# Take swig (*.i) file and add proper custom commands for it
+#
+function(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
+ get_filename_component(swig_source_file_name_we "${infile}" NAME_WE)
+ get_source_file_property(swig_source_file_cplusplus "${infile}" CPLUSPLUS)
+ get_source_file_property(swig_source_file_outdir "${infile}" OUTPUT_DIR)
+ get_source_file_property(swig_source_file_outfiledir "${infile}" OUTFILE_DIR)
+
+ if (swig_source_file_outdir)
+ # use source file property
+ set(outdir "${swig_source_file_outdir}")
+ if (NOT swig_source_file_outfiledir)
+ set (swig_source_file_outfiledir "${outdir}")
+ endif()
+ elseif(CMAKE_SWIG_OUTDIR)
+ set(outdir ${CMAKE_SWIG_OUTDIR})
+ else()
+ set(outdir ${CMAKE_CURRENT_BINARY_DIR})
+ endif()
+
+ if (swig_source_file_outfiledir)
+ set (outfiledir "${swig_source_file_outfiledir}")
+ elseif(SWIG_OUTFILE_DIR)
+ set(outfiledir ${SWIG_OUTFILE_DIR})
+ else()
+ set(outfiledir ${outdir})
+ endif()
+
+ if(SWIG_WORKING_DIR)
+ set (workingdir "${SWIG_WORKING_DIR}")
+ else()
+ set(workingdir "${outdir}")
+ endif()
+
+ if(SWIG_TARGET_NAME)
+ set(target_name ${SWIG_TARGET_NAME})
+ else()
+ set(target_name ${name})
+ endif()
+
+ set (use_swig_dependencies ${SWIG_USE_SWIG_DEPENDENCIES})
+ if (CMAKE_GENERATOR MATCHES "Make|Ninja")
+ get_property(use_swig_dependencies_set SOURCE "${infile}" PROPERTY USE_SWIG_DEPENDENCIES SET)
+ if (use_swig_dependencies_set)
+ get_property(use_swig_dependencies SOURCE "${infile}" PROPERTY USE_SWIG_DEPENDENCIES)
+ endif()
+ endif()
+
+ set (swig_source_file_flags ${CMAKE_SWIG_FLAGS})
+ # handle various swig compile flags properties
+ get_source_file_property (include_directories "${infile}" INCLUDE_DIRECTORIES)
+ if (include_directories)
+ list (APPEND swig_source_file_flags "$<$<BOOL:${include_directories}>:-I$<JOIN:${include_directories},$<SEMICOLON>-I>>")
+ endif()
+ set (property "$<TARGET_PROPERTY:${target_name},SWIG_INCLUDE_DIRECTORIES>")
+ list (APPEND swig_source_file_flags "$<$<BOOL:${property}>:-I$<JOIN:$<TARGET_GENEX_EVAL:${target_name},${property}>,$<SEMICOLON>-I>>")
+ set (property "$<TARGET_PROPERTY:${target_name},INCLUDE_DIRECTORIES>")
+ get_source_file_property(use_target_include_dirs "${infile}" USE_TARGET_INCLUDE_DIRECTORIES)
+ if (use_target_include_dirs)
+ list (APPEND swig_source_file_flags "$<$<BOOL:${property}>:-I$<JOIN:${property},$<SEMICOLON>-I>>")
+ elseif(use_target_include_dirs STREQUAL "NOTFOUND")
+ # not defined at source level, rely on target level
+ list (APPEND swig_source_file_flags "$<$<AND:$<BOOL:$<TARGET_PROPERTY:${target_name},SWIG_USE_TARGET_INCLUDE_DIRECTORIES>>,$<BOOL:${property}>>:-I$<JOIN:${property},$<SEMICOLON>-I>>")
+ endif()
+
+ set (property "$<TARGET_PROPERTY:${target_name},SWIG_COMPILE_DEFINITIONS>")
+ list (APPEND swig_source_file_flags "$<$<BOOL:${property}>:-D$<JOIN:$<TARGET_GENEX_EVAL:${target_name},${property}>,$<SEMICOLON>-D>>")
+ get_source_file_property (compile_definitions "${infile}" COMPILE_DEFINITIONS)
+ if (compile_definitions)
+ list (APPEND swig_source_file_flags "$<$<BOOL:${compile_definitions}>:-D$<JOIN:${compile_definitions},$<SEMICOLON>-D>>")
+ endif()
+
+ list (APPEND swig_source_file_flags "$<TARGET_GENEX_EVAL:${target_name},$<TARGET_PROPERTY:${target_name},SWIG_COMPILE_OPTIONS>>")
+ get_source_file_property (compile_options "${infile}" COMPILE_OPTIONS)
+ if (compile_options)
+ list (APPEND swig_source_file_flags ${compile_options})
+ endif()
+
+ # legacy support
+ get_source_file_property (swig_flags "${infile}" SWIG_FLAGS)
+ if (swig_flags)
+ list (APPEND swig_source_file_flags ${swig_flags})
+ endif()
+
+ get_filename_component(swig_source_file_fullname "${infile}" ABSOLUTE)
+
+ if (NOT SWIG_MODULE_${name}_NOPROXY)
+ set(SWIG_COMPILATION_FLAGS ${swig_source_file_flags})
+ SWIG_GET_EXTRA_OUTPUT_FILES(${SWIG_MODULE_${name}_LANGUAGE}
+ swig_extra_generated_files
+ "${outdir}"
+ "${swig_source_file_fullname}")
+ endif()
+ set(swig_generated_file_fullname
+ "${outfiledir}/${swig_source_file_name_we}")
+ # add the language into the name of the file (i.e. TCL_wrap)
+ # this allows for the same .i file to be wrapped into different languages
+ string(APPEND swig_generated_file_fullname
+ "${SWIG_MODULE_${name}_LANGUAGE}_wrap")
+
+ if(swig_source_file_cplusplus)
+ string(APPEND swig_generated_file_fullname
+ ".${SWIG_CXX_EXTENSION}")
+ else()
+ string(APPEND swig_generated_file_fullname
+ ".c")
+ endif()
+
+ get_directory_property (cmake_include_directories INCLUDE_DIRECTORIES)
+ list (REMOVE_DUPLICATES cmake_include_directories)
+ set (swig_include_dirs)
+ if (cmake_include_directories)
+ set (swig_include_dirs "$<$<BOOL:${cmake_include_directories}>:-I$<JOIN:${cmake_include_directories},$<SEMICOLON>-I>>")
+ endif()
+
+ set(swig_special_flags)
+ # default is c, so add c++ flag if it is c++
+ if(swig_source_file_cplusplus)
+ list (APPEND swig_special_flags "-c++")
+ endif()
+
+ cmake_policy(GET CMP0086 module_name_policy)
+ if (module_name_policy STREQUAL "NEW")
+ get_source_file_property(module_name "${infile}" SWIG_MODULE_NAME)
+ if (module_name)
+ list (APPEND swig_special_flags "-module" "${module_name}")
+ endif()
+ else()
+ if (NOT module_name_policy)
+ cmake_policy(GET_WARNING CMP0086 _cmp0086_warning)
+ message(AUTHOR_WARNING "${_cmp0086_warning}\n")
+ endif()
+ endif()
+
+ set (swig_extra_flags)
+ if(SWIG_MODULE_${name}_LANGUAGE STREQUAL "CSHARP")
+ if(NOT ("-dllimport" IN_LIST swig_source_file_flags OR "-dllimport" IN_LIST SWIG_MODULE_${name}_EXTRA_FLAGS))
+ # This makes sure that the name used in the generated DllImport
+ # matches the library name created by CMake
+ list (APPEND SWIG_MODULE_${name}_EXTRA_FLAGS "-dllimport" "$<TARGET_FILE_PREFIX:${target_name}>$<TARGET_FILE_BASE_NAME:${target_name}>")
+ endif()
+ endif()
+ if (SWIG_MODULE_${name}_LANGUAGE STREQUAL "PYTHON" AND NOT SWIG_MODULE_${name}_NOPROXY)
+ if(SWIG_USE_INTERFACE AND
+ NOT ("-interface" IN_LIST swig_source_file_flags OR "-interface" IN_LIST SWIG_MODULE_${name}_EXTRA_FLAGS))
+ # This makes sure that the name used in the proxy code
+ # matches the library name created by CMake
+ list (APPEND SWIG_MODULE_${name}_EXTRA_FLAGS "-interface" "$<TARGET_FILE_PREFIX:${target_name}>$<TARGET_FILE_BASE_NAME:${target_name}>")
+ endif()
+ endif()
+ list (APPEND swig_extra_flags ${SWIG_MODULE_${name}_EXTRA_FLAGS})
+
+ # dependencies
+ set (swig_dependencies DEPENDS ${SWIG_MODULE_${name}_EXTRA_DEPS} $<TARGET_PROPERTY:${target_name},SWIG_DEPENDS>)
+ get_source_file_property(file_depends "${infile}" DEPENDS)
+ if (file_depends)
+ list (APPEND swig_dependencies ${file_depends})
+ endif()
+
+ if (UseSWIG_MODULE_VERSION VERSION_GREATER 1)
+ # as part of custom command, start by removing old generated files
+ # to ensure obsolete files do not stay
+ set (swig_file_outdir "${workingdir}/${swig_source_file_name_we}.files")
+ set (swig_cleanup_command COMMAND "${CMAKE_COMMAND}" "-DSUPPORT_FILES_WORKING_DIRECTORY=${swig_file_outdir}" "-DSUPPORT_FILES_OUTPUT_DIRECTORY=${outdir}" -DACTION=CLEAN -P "${SWIG_MANAGE_SUPPORT_FILES_SCRIPT}")
+ set (swig_copy_command COMMAND "${CMAKE_COMMAND}" "-DSUPPORT_FILES_WORKING_DIRECTORY=${swig_file_outdir}" "-DSUPPORT_FILES_OUTPUT_DIRECTORY=${outdir}" -DACTION=COPY -P "${SWIG_MANAGE_SUPPORT_FILES_SCRIPT}")
+ else()
+ set (swig_file_outdir "${outdir}")
+ unset (swig_cleanup_command)
+ unset (swig_copy_command)
+ endif()
+
+ set(swig_depends_flags)
+ if(NOT use_swig_dependencies AND CMAKE_GENERATOR MATCHES "Make")
+ # IMPLICIT_DEPENDS can not handle situations where a dependent file is
+ # removed. We need an extra step with timestamp and custom target, see #16830
+ # As this is needed only for Makefile generator do it conditionally
+ __swig_compute_timestamp(${name} ${SWIG_MODULE_${name}_LANGUAGE}
+ "${infile}" "${workingdir}" swig_generated_timestamp)
+ set(swig_custom_output "${swig_generated_timestamp}")
+ set(swig_custom_products
+ BYPRODUCTS "${swig_generated_file_fullname}" ${swig_extra_generated_files})
+ set(swig_timestamp_command
+ COMMAND ${CMAKE_COMMAND} -E touch "${swig_generated_timestamp}")
+ list(APPEND swig_dependencies IMPLICIT_DEPENDS CXX "${swig_source_file_fullname}")
+ else()
+ set(swig_generated_timestamp)
+ set(swig_custom_output
+ "${swig_generated_file_fullname}" ${swig_extra_generated_files})
+ set(swig_custom_products)
+ set(swig_timestamp_command)
+ if (use_swig_dependencies)
+ cmake_path(GET infile FILENAME swig_depends_filename)
+ set(swig_depends_filename "${workingdir}/${swig_depends_filename}.d")
+ list(APPEND swig_dependencies DEPFILE "${swig_depends_filename}")
+ set(swig_depends_flags -MF "${swig_depends_filename}" -MD)
+ endif()
+ endif()
+ add_custom_command(
+ OUTPUT ${swig_custom_output}
+ ${swig_custom_products}
+ ${swig_cleanup_command}
+ # Let's create the ${outdir} at execution time, in case dir contains $(OutDir)
+ COMMAND "${CMAKE_COMMAND}" -E make_directory ${outdir} ${outfiledir}
+ ${swig_timestamp_command}
+ COMMAND "${CMAKE_COMMAND}" -E env "SWIG_LIB=${SWIG_DIR}" "${SWIG_EXECUTABLE}"
+ "-${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}"
+ "${swig_source_file_flags}"
+ -outdir "${swig_file_outdir}"
+ ${swig_special_flags}
+ ${swig_extra_flags}
+ ${swig_depends_flags}
+ "${swig_include_dirs}"
+ -o "${swig_generated_file_fullname}"
+ "${swig_source_file_fullname}"
+ ${swig_copy_command}
+ MAIN_DEPENDENCY "${swig_source_file_fullname}"
+ ${swig_dependencies}
+ COMMENT "Swig compile ${infile} for ${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}"
+ COMMAND_EXPAND_LISTS)
+ set_source_files_properties("${swig_generated_file_fullname}" ${swig_extra_generated_files}
+ PROPERTIES GENERATED 1)
+
+ ## add all properties for generated file to various properties
+ get_property (include_directories SOURCE "${infile}" PROPERTY GENERATED_INCLUDE_DIRECTORIES)
+ set_property (SOURCE "${swig_generated_file_fullname}" PROPERTY INCLUDE_DIRECTORIES ${include_directories} $<TARGET_GENEX_EVAL:${target_name},$<TARGET_PROPERTY:${target_name},SWIG_GENERATED_INCLUDE_DIRECTORIES>>)
+
+ get_property (compile_definitions SOURCE "${infile}" PROPERTY GENERATED_COMPILE_DEFINITIONS)
+ set_property (SOURCE "${swig_generated_file_fullname}" PROPERTY COMPILE_DEFINITIONS $<TARGET_GENEX_EVAL:${target_name},$<TARGET_PROPERTY:${target_name},SWIG_GENERATED_COMPILE_DEFINITIONS>> ${compile_definitions})
+
+ get_property (compile_options SOURCE "${infile}" PROPERTY GENERATED_COMPILE_OPTIONS)
+ set_property (SOURCE "${swig_generated_file_fullname}" PROPERTY COMPILE_OPTIONS $<TARGET_GENEX_EVAL:${target_name},$<TARGET_PROPERTY:${target_name},SWIG_GENERATED_COMPILE_OPTIONS>> ${compile_options})
+
+ if (SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG MATCHES "php")
+ set_property (SOURCE "${swig_generated_file_fullname}" APPEND PROPERTY INCLUDE_DIRECTORIES "${outdir}")
+ endif()
+
+ set(${outfiles} "${swig_generated_file_fullname}" ${swig_extra_generated_files} PARENT_SCOPE)
+ set(swig_timestamp "${swig_generated_timestamp}" PARENT_SCOPE)
+
+ # legacy support
+ set (swig_generated_file_fullname "${swig_generated_file_fullname}" PARENT_SCOPE)
+endfunction()
+
+#
+# Create Swig module
+#
+macro(SWIG_ADD_MODULE name language)
+ message(DEPRECATION "SWIG_ADD_MODULE is deprecated. Use SWIG_ADD_LIBRARY instead.")
+ swig_add_library(${name}
+ LANGUAGE ${language}
+ TYPE MODULE
+ SOURCES ${ARGN})
+endmacro()
+
+
+function(SWIG_ADD_LIBRARY name)
+ set(options NO_PROXY)
+ set(oneValueArgs LANGUAGE
+ TYPE
+ OUTPUT_DIR
+ OUTFILE_DIR)
+ set(multiValueArgs SOURCES)
+ cmake_parse_arguments(_SAM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if (_SAM_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "SWIG_ADD_LIBRARY: ${_SAM_UNPARSED_ARGUMENTS}: unexpected arguments")
+ endif()
+
+ if(NOT DEFINED _SAM_LANGUAGE)
+ message(FATAL_ERROR "SWIG_ADD_LIBRARY: Missing LANGUAGE argument")
+ endif()
+
+ if(NOT DEFINED _SAM_SOURCES)
+ message(FATAL_ERROR "SWIG_ADD_LIBRARY: Missing SOURCES argument")
+ endif()
+
+ if(NOT DEFINED _SAM_TYPE)
+ set(_SAM_TYPE MODULE)
+ elseif(_SAM_TYPE STREQUAL "USE_BUILD_SHARED_LIBS")
+ unset(_SAM_TYPE)
+ endif()
+
+ cmake_policy(GET CMP0078 target_name_policy)
+ if (target_name_policy STREQUAL "NEW")
+ set (UseSWIG_TARGET_NAME_PREFERENCE STANDARD)
+ else()
+ if (NOT target_name_policy)
+ cmake_policy(GET_WARNING CMP0078 _cmp0078_warning)
+ message(AUTHOR_WARNING "${_cmp0078_warning}\n")
+ endif()
+ if (NOT DEFINED UseSWIG_TARGET_NAME_PREFERENCE)
+ set (UseSWIG_TARGET_NAME_PREFERENCE LEGACY)
+ elseif (NOT UseSWIG_TARGET_NAME_PREFERENCE MATCHES "^(LEGACY|STANDARD)$")
+ message (FATAL_ERROR "UseSWIG_TARGET_NAME_PREFERENCE: ${UseSWIG_TARGET_NAME_PREFERENCE}: invalid value. 'LEGACY' or 'STANDARD' is expected.")
+ endif()
+ endif()
+
+ if (NOT DEFINED UseSWIG_MODULE_VERSION)
+ set (UseSWIG_MODULE_VERSION 1)
+ elseif (NOT UseSWIG_MODULE_VERSION MATCHES "^(1|2)$")
+ message (FATAL_ERROR "UseSWIG_MODULE_VERSION: ${UseSWIG_MODULE_VERSION}: invalid value. 1 or 2 is expected.")
+ endif()
+
+ set (SWIG_MODULE_${name}_NOPROXY ${_SAM_NO_PROXY})
+ swig_module_initialize(${name} ${_SAM_LANGUAGE})
+
+ # compute real target name.
+ if (UseSWIG_TARGET_NAME_PREFERENCE STREQUAL "LEGACY" AND
+ SWIG_MODULE_${name}_LANGUAGE STREQUAL "PYTHON" AND NOT SWIG_MODULE_${name}_NOPROXY)
+ # swig will produce a module.py containing an 'import _modulename' statement,
+ # which implies having a corresponding _modulename.so (*NIX), _modulename.pyd (Win32),
+ # unless the -noproxy flag is used
+ set(target_name "_${name}")
+ else()
+ set(target_name "${name}")
+ endif()
+
+ if (TARGET ${target_name})
+ # a target with same name is already defined.
+ # call NOW add_library command to raise the most useful error message
+ add_library(${target_name})
+ return()
+ endif()
+
+ set (workingdir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${target_name}.dir")
+ # set special variable to pass extra information to command SWIG_ADD_SOURCE_TO_MODULE
+ # which cannot be changed due to legacy compatibility
+ set (SWIG_WORKING_DIR "${workingdir}")
+ set (SWIG_TARGET_NAME "${target_name}")
+
+ set (outputdir "${_SAM_OUTPUT_DIR}")
+ if (NOT _SAM_OUTPUT_DIR)
+ if (CMAKE_SWIG_OUTDIR)
+ set (outputdir "${CMAKE_SWIG_OUTDIR}")
+ else()
+ if (UseSWIG_MODULE_VERSION VERSION_GREATER 1)
+ set (outputdir "${workingdir}/${_SAM_LANGUAGE}.files")
+ else()
+ set (outputdir "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ endif()
+ endif()
+
+ set (outfiledir "${_SAM_OUTFILE_DIR}")
+ if(NOT _SAM_OUTFILE_DIR)
+ if (SWIG_OUTFILE_DIR)
+ set (outfiledir "${SWIG_OUTFILE_DIR}")
+ else()
+ if (_SAM_OUTPUT_DIR OR CMAKE_SWIG_OUTDIR)
+ set (outfiledir "${outputdir}")
+ else()
+ set (outfiledir "${workingdir}")
+ endif()
+ endif()
+ endif()
+ # set again, locally, predefined variables to ensure compatibility
+ # with command SWIG_ADD_SOURCE_TO_MODULE
+ set(CMAKE_SWIG_OUTDIR "${outputdir}")
+ set(SWIG_OUTFILE_DIR "${outfiledir}")
+
+ # See if the user has specified source extensions for swig files?
+ if (NOT DEFINED SWIG_SOURCE_FILE_EXTENSIONS)
+ # Assume the default (*.i) file extension for Swig source files
+ set(SWIG_SOURCE_FILE_EXTENSIONS ".i")
+ endif()
+
+ if (CMAKE_GENERATOR MATCHES "Make|Ninja")
+ # For Makefiles and Ninja generators, use SWIG generated dependencies
+ if (NOT DEFINED SWIG_USE_SWIG_DEPENDENCIES)
+ set (SWIG_USE_SWIG_DEPENDENCIES OFF)
+ endif()
+ else()
+ set (SWIG_USE_SWIG_DEPENDENCIES OFF)
+ endif()
+
+ # Generate a regex out of file extensions.
+ string(REGEX REPLACE "([$^.*+?|()-])" "\\\\\\1" swig_source_ext_regex "${SWIG_SOURCE_FILE_EXTENSIONS}")
+ list (JOIN swig_source_ext_regex "|" swig_source_ext_regex)
+ string (PREPEND swig_source_ext_regex "(")
+ string (APPEND swig_source_ext_regex ")$")
+
+ set(swig_dot_i_sources ${_SAM_SOURCES})
+ list(FILTER swig_dot_i_sources INCLUDE REGEX ${swig_source_ext_regex})
+ if (NOT swig_dot_i_sources)
+ message(FATAL_ERROR "SWIG_ADD_LIBRARY: no SWIG interface files specified")
+ endif()
+ set(swig_other_sources ${_SAM_SOURCES})
+ list(REMOVE_ITEM swig_other_sources ${swig_dot_i_sources})
+
+ set(swig_generated_sources)
+ set(swig_generated_timestamps)
+ set(swig_generated_outdirs "${outputdir}")
+ list(LENGTH swig_dot_i_sources swig_sources_count)
+ if (swig_sources_count GREATER "1")
+ # option -interface cannot be used
+ set(SWIG_USE_INTERFACE FALSE)
+ else()
+ set(SWIG_USE_INTERFACE TRUE)
+ endif()
+ foreach(swig_it IN LISTS swig_dot_i_sources)
+ SWIG_ADD_SOURCE_TO_MODULE(${name} swig_generated_source "${swig_it}")
+ list (APPEND swig_generated_sources "${swig_generated_source}")
+ if(swig_timestamp)
+ list (APPEND swig_generated_timestamps "${swig_timestamp}")
+ endif()
+ get_source_file_property(swig_source_file_outdir "${swig_it}" OUTPUT_DIR)
+ if (swig_source_file_outdir)
+ list (APPEND swig_generated_outdirs "${swig_source_file_outdir}")
+ endif()
+ endforeach()
+ list(REMOVE_DUPLICATES swig_generated_outdirs)
+ set_property (DIRECTORY APPEND PROPERTY
+ ADDITIONAL_CLEAN_FILES ${swig_generated_sources} ${swig_generated_timestamps})
+ if (UseSWIG_MODULE_VERSION VERSION_GREATER 1)
+ set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${swig_generated_outdirs})
+ endif()
+
+ add_library(${target_name}
+ ${_SAM_TYPE}
+ ${swig_generated_sources}
+ ${swig_other_sources})
+ if(swig_generated_timestamps)
+ # see IMPLICIT_DEPENDS above
+ add_custom_target(${name}_swig_compilation DEPENDS ${swig_generated_timestamps})
+ add_dependencies(${target_name} ${name}_swig_compilation)
+ endif()
+ if(_SAM_TYPE STREQUAL "MODULE")
+ set_target_properties(${target_name} PROPERTIES NO_SONAME ON)
+ endif()
+ string(TOLOWER "${_SAM_LANGUAGE}" swig_lowercase_language)
+ if (swig_lowercase_language STREQUAL "octave")
+ set_target_properties(${target_name} PROPERTIES PREFIX "")
+ set_target_properties(${target_name} PROPERTIES SUFFIX ".oct")
+ elseif (swig_lowercase_language STREQUAL "go")
+ set_target_properties(${target_name} PROPERTIES PREFIX "")
+ elseif (swig_lowercase_language STREQUAL "java")
+ # In java you want:
+ # System.loadLibrary("LIBRARY");
+ # then JNI will look for a library whose name is platform dependent, namely
+ # MacOS : libLIBRARY.jnilib
+ # Windows: LIBRARY.dll
+ # Linux : libLIBRARY.so
+ if (APPLE)
+ set_target_properties (${target_name} PROPERTIES SUFFIX ".jnilib")
+ endif()
+ if ((WIN32 AND MINGW) OR CYGWIN OR CMAKE_SYSTEM_NAME STREQUAL "MSYS")
+ set_target_properties(${target_name} PROPERTIES PREFIX "")
+ endif()
+ elseif (swig_lowercase_language STREQUAL "lua")
+ if(_SAM_TYPE STREQUAL "MODULE")
+ set_target_properties(${target_name} PROPERTIES PREFIX "")
+ endif()
+ elseif (swig_lowercase_language STREQUAL "python")
+ if (UseSWIG_TARGET_NAME_PREFERENCE STREQUAL "STANDARD" AND NOT SWIG_MODULE_${name}_NOPROXY)
+ # swig will produce a module.py containing an 'import _modulename' statement,
+ # which implies having a corresponding _modulename.so (*NIX), _modulename.pyd (Win32),
+ # unless the -noproxy flag is used
+ set_target_properties(${target_name} PROPERTIES PREFIX "_")
+ else()
+ set_target_properties(${target_name} PROPERTIES PREFIX "")
+ endif()
+ # Python extension modules on Windows must have the extension ".pyd"
+ # instead of ".dll" as of Python 2.5. Older python versions do support
+ # this suffix.
+ # http://docs.python.org/whatsnew/ports.html#SECTION0001510000000000000000
+ # <quote>
+ # Windows: .dll is no longer supported as a filename extension for extension modules.
+ # .pyd is now the only filename extension that will be searched for.
+ # </quote>
+ if(WIN32 AND NOT CYGWIN)
+ set_target_properties(${target_name} PROPERTIES SUFFIX ".pyd")
+ endif()
+ elseif (swig_lowercase_language STREQUAL "r")
+ set_target_properties(${target_name} PROPERTIES PREFIX "")
+ elseif (swig_lowercase_language STREQUAL "ruby")
+ # In ruby you want:
+ # require 'LIBRARY'
+ # then ruby will look for a library whose name is platform dependent, namely
+ # MacOS : LIBRARY.bundle
+ # Windows: LIBRARY.dll
+ # Linux : LIBRARY.so
+ set_target_properties (${target_name} PROPERTIES PREFIX "")
+ if (APPLE)
+ set_target_properties (${target_name} PROPERTIES SUFFIX ".bundle")
+ endif ()
+ elseif (swig_lowercase_language STREQUAL "perl")
+ # assume empty prefix because we expect the module to be dynamically loaded
+ set_target_properties (${target_name} PROPERTIES PREFIX "")
+ if (APPLE)
+ set_target_properties (${target_name} PROPERTIES SUFFIX ".dylib")
+ endif ()
+ elseif (swig_lowercase_language STREQUAL "fortran")
+ # Do *not* override the target's library prefix
+ elseif (swig_lowercase_language STREQUAL "csharp")
+ cmake_policy(GET CMP0122 csharp_naming_policy)
+ if (csharp_naming_policy STREQUAL "NEW")
+ # Do *not* override the target's library prefix
+ else()
+ if (NOT csharp_naming_policy)
+ cmake_policy(GET_WARNING CMP0122 _cmp0122_warning)
+ message(AUTHOR_WARNING "${_cmp0122_warning}\n")
+ endif()
+ set_target_properties (${target_name} PROPERTIES PREFIX "")
+ endif()
+ else()
+ # assume empty prefix because we expect the module to be dynamically loaded
+ set_target_properties (${target_name} PROPERTIES PREFIX "")
+ endif ()
+
+ # target property SWIG_SUPPORT_FILES_DIRECTORY specify output directories of support files
+ set_property (TARGET ${target_name} PROPERTY SWIG_SUPPORT_FILES_DIRECTORY ${swig_generated_outdirs})
+ # target property SWIG_SUPPORT_FILES lists principal proxy support files
+ if (NOT SWIG_MODULE_${name}_NOPROXY)
+ string(TOUPPER "${_SAM_LANGUAGE}" swig_uppercase_language)
+ set(swig_all_support_files)
+ foreach (swig_it IN LISTS SWIG_${swig_uppercase_language}_EXTRA_FILE_EXTENSIONS)
+ set (swig_support_files ${swig_generated_sources})
+ list (FILTER swig_support_files INCLUDE REGEX ".*${swig_it}$")
+ list(APPEND swig_all_support_files ${swig_support_files})
+ endforeach()
+ if (swig_all_support_files)
+ list(REMOVE_DUPLICATES swig_all_support_files)
+ endif()
+ set_property (TARGET ${target_name} PROPERTY SWIG_SUPPORT_FILES ${swig_all_support_files})
+ endif()
+
+ # to ensure legacy behavior, export some variables
+ set (SWIG_MODULE_${name}_LANGUAGE "${SWIG_MODULE_${name}_LANGUAGE}" PARENT_SCOPE)
+ set (SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG "${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}" PARENT_SCOPE)
+ set (SWIG_MODULE_${name}_REAL_NAME "${target_name}" PARENT_SCOPE)
+ set (SWIG_MODULE_${name}_NOPROXY "${SWIG_MODULE_${name}_NOPROXY}" PARENT_SCOPE)
+ set (SWIG_MODULE_${name}_EXTRA_FLAGS "${SWIG_MODULE_${name}_EXTRA_FLAGS}" PARENT_SCOPE)
+ # the last one is a bit crazy but it is documented, so...
+ # NOTA: works as expected if only ONE input file is specified
+ set (swig_generated_file_fullname "${swig_generated_file_fullname}" PARENT_SCOPE)
+endfunction()
+
+#
+# Like TARGET_LINK_LIBRARIES but for swig modules
+#
+function(SWIG_LINK_LIBRARIES name)
+ if (UseSWIG_TARGET_NAME_PREFERENCE STREQUAL "STANDARD")
+ message(DEPRECATION "SWIG_LINK_LIBRARIES is deprecated. Use TARGET_LINK_LIBRARIES instead.")
+ target_link_libraries(${name} ${ARGN})
+ else()
+ if(SWIG_MODULE_${name}_REAL_NAME)
+ target_link_libraries(${SWIG_MODULE_${name}_REAL_NAME} ${ARGN})
+ else()
+ message(SEND_ERROR "Cannot find Swig library \"${name}\".")
+ endif()
+ endif()
+endfunction()
+
+cmake_policy(POP)
diff --git a/Modules/UseSWIG/ManageSupportFiles.cmake b/Modules/UseSWIG/ManageSupportFiles.cmake
new file mode 100644
index 0000000..6618fd5
--- /dev/null
+++ b/Modules/UseSWIG/ManageSupportFiles.cmake
@@ -0,0 +1,31 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+if (ACTION STREQUAL "CLEAN")
+ # Collect current list of generated files
+ file (GLOB_RECURSE files LIST_DIRECTORIES TRUE RELATIVE "${SUPPORT_FILES_WORKING_DIRECTORY}" "${SUPPORT_FILES_WORKING_DIRECTORY}/*")
+
+ if (files)
+ # clean-up the output directory
+ ## compute full paths
+ list (TRANSFORM files PREPEND "${SUPPORT_FILES_OUTPUT_DIRECTORY}/")
+ ## remove generated files from the output directory
+ file (REMOVE ${files})
+
+ # clean-up working directory
+ file (REMOVE_RECURSE "${SUPPORT_FILES_WORKING_DIRECTORY}")
+ endif()
+
+ file (MAKE_DIRECTORY "${SUPPORT_FILES_WORKING_DIRECTORY}")
+endif()
+
+if (ACTION STREQUAL "COPY")
+ # Collect current list of generated files
+ file (GLOB files LIST_DIRECTORIES TRUE "${SUPPORT_FILES_WORKING_DIRECTORY}/*")
+
+ if (files)
+ # copy files to the output directory
+ file (COPY ${files} DESTINATION "${SUPPORT_FILES_OUTPUT_DIRECTORY}")
+ endif()
+endif()
diff --git a/Modules/Use_wxWindows.cmake b/Modules/Use_wxWindows.cmake
new file mode 100644
index 0000000..782874c
--- /dev/null
+++ b/Modules/Use_wxWindows.cmake
@@ -0,0 +1,69 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+Use_wxWindows
+-------------
+
+.. deprecated:: 2.8.10
+
+ Use ``find_package(wxWidgets)`` and ``include(${wxWidgets_USE_FILE})`` instead.
+
+This convenience include finds if wxWindows is installed and set the
+appropriate libs, incdirs, flags etc. author Jan Woetzel <jw -at-
+mip.informatik.uni-kiel.de> (07/2003)
+
+USAGE:
+
+::
+
+ just include Use_wxWindows.cmake
+ in your projects CMakeLists.txt
+
+include( ${CMAKE_MODULE_PATH}/Use_wxWindows.cmake)
+
+::
+
+ if you are sure you need GL then
+
+set(WXWINDOWS_USE_GL 1)
+
+::
+
+ *before* you include this file.
+#]=======================================================================]
+
+# -----------------------------------------------------
+# 16.Feb.2004: changed INCLUDE to FIND_PACKAGE to read from users own non-system CMAKE_MODULE_PATH (Jan Woetzel JW)
+# 07/2006: rewrite as FindwxWidgets.cmake, kept for backward compatibility JW
+
+message(STATUS "Use_wxWindows.cmake is DEPRECATED. \n"
+"Please use find_package(wxWidgets) and include(${wxWidgets_USE_FILE}) instead. (JW)")
+
+
+# ------------------------
+
+find_package( wxWindows )
+
+if(WXWINDOWS_FOUND)
+
+#message("DBG Use_wxWindows.cmake: WXWINDOWS_INCLUDE_DIR=${WXWINDOWS_INCLUDE_DIR} WXWINDOWS_LINK_DIRECTORIES=${WXWINDOWS_LINK_DIRECTORIES} WXWINDOWS_LIBRARIES=${WXWINDOWS_LIBRARIES} CMAKE_WXWINDOWS_CXX_FLAGS=${CMAKE_WXWINDOWS_CXX_FLAGS} WXWINDOWS_DEFINITIONS=${WXWINDOWS_DEFINITIONS}")
+
+ if(WXWINDOWS_INCLUDE_DIR)
+ include_directories(${WXWINDOWS_INCLUDE_DIR})
+ endif()
+ if(WXWINDOWS_LINK_DIRECTORIES)
+ link_directories(${WXWINDOWS_LINK_DIRECTORIES})
+ endif()
+ if(WXWINDOWS_LIBRARIES)
+ link_libraries(${WXWINDOWS_LIBRARIES})
+ endif()
+ if (CMAKE_WXWINDOWS_CXX_FLAGS)
+ string(APPEND CMAKE_CXX_FLAGS " ${CMAKE_WXWINDOWS_CXX_FLAGS}")
+ endif()
+ if(WXWINDOWS_DEFINITIONS)
+ add_definitions(${WXWINDOWS_DEFINITIONS})
+ endif()
+else()
+ message(SEND_ERROR "wxWindows not found by Use_wxWindows.cmake")
+endif()
diff --git a/Modules/UsewxWidgets.cmake b/Modules/UsewxWidgets.cmake
new file mode 100644
index 0000000..eed0410
--- /dev/null
+++ b/Modules/UsewxWidgets.cmake
@@ -0,0 +1,101 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+UsewxWidgets
+------------
+
+Convenience include for using wxWidgets library.
+
+Determines if wxWidgets was FOUND and sets the appropriate libs,
+incdirs, flags, etc. INCLUDE_DIRECTORIES and LINK_DIRECTORIES are
+called.
+
+USAGE
+
+::
+
+ # Note that for MinGW users the order of libs is important!
+ find_package(wxWidgets REQUIRED net gl core base)
+ include(${wxWidgets_USE_FILE})
+ # and for each of your dependent executable/library targets:
+ target_link_libraries(<YourTarget> ${wxWidgets_LIBRARIES})
+
+
+
+DEPRECATED
+
+::
+
+ LINK_LIBRARIES is not called in favor of adding dependencies per target.
+
+
+
+AUTHOR
+
+::
+
+ Jan Woetzel <jw -at- mip.informatik.uni-kiel.de>
+#]=======================================================================]
+
+# debug message and logging.
+# comment these out for distribution
+if (NOT LOGFILE )
+ # set(LOGFILE "${PROJECT_BINARY_DIR}/CMakeOutput.log")
+endif ()
+macro(MSG _MSG)
+ # file(APPEND ${LOGFILE} "${CMAKE_CURRENT_LIST_FILE}(${CMAKE_CURRENT_LIST_LINE}): ${_MSG}\n")
+ # message(STATUS "${CMAKE_CURRENT_LIST_FILE}(${CMAKE_CURRENT_LIST_LINE}): ${_MSG}")
+endmacro()
+
+
+MSG("wxWidgets_FOUND=${wxWidgets_FOUND}")
+if (wxWidgets_FOUND)
+ if (wxWidgets_INCLUDE_DIRS)
+ if(wxWidgets_INCLUDE_DIRS_NO_SYSTEM)
+ include_directories(${wxWidgets_INCLUDE_DIRS})
+ else()
+ include_directories(SYSTEM ${wxWidgets_INCLUDE_DIRS})
+ endif()
+ MSG("wxWidgets_INCLUDE_DIRS=${wxWidgets_INCLUDE_DIRS}")
+ endif()
+
+ if (wxWidgets_LIBRARY_DIRS)
+ link_directories(${wxWidgets_LIBRARY_DIRS})
+ MSG("wxWidgets_LIBRARY_DIRS=${wxWidgets_LIBRARY_DIRS}")
+ endif()
+
+ if (wxWidgets_DEFINITIONS)
+ set_property(DIRECTORY APPEND
+ PROPERTY COMPILE_DEFINITIONS ${wxWidgets_DEFINITIONS})
+ MSG("wxWidgets_DEFINITIONS=${wxWidgets_DEFINITIONS}")
+ endif()
+
+ if (wxWidgets_DEFINITIONS_DEBUG)
+ set_property(DIRECTORY APPEND
+ PROPERTY COMPILE_DEFINITIONS_DEBUG ${wxWidgets_DEFINITIONS_DEBUG})
+ MSG("wxWidgets_DEFINITIONS_DEBUG=${wxWidgets_DEFINITIONS_DEBUG}")
+ endif()
+
+ if (wxWidgets_CXX_FLAGS)
+ # Flags are expected to be a string here, not a list.
+ string(REPLACE ";" " " wxWidgets_CXX_FLAGS_str "${wxWidgets_CXX_FLAGS}")
+ string(APPEND CMAKE_CXX_FLAGS " ${wxWidgets_CXX_FLAGS_str}")
+ MSG("wxWidgets_CXX_FLAGS=${wxWidgets_CXX_FLAGS_str}")
+ unset(wxWidgets_CXX_FLAGS_str)
+ endif()
+
+ # DEPRECATED JW
+ # just for backward compatibility: add deps to all targets
+ # library projects better use advanced find_package(wxWidgets) directly.
+ #if(wxWidgets_LIBRARIES)
+ # link_libraries(${wxWidgets_LIBRARIES})
+ # # BUG: str too long: MSG("wxWidgets_LIBRARIES=${wxWidgets_LIBRARIES}")
+ # if(LOGFILE)
+ # file(APPEND ${LOGFILE} "${CMAKE_CURRENT_LIST_FILE}(${CMAKE_CURRENT_LIST_LINE}): ${wxWidgets_LIBRARIES}\n")
+ # endif()
+ #endif()
+
+else ()
+ message("wxWidgets requested but not found.")
+endif()
diff --git a/Modules/VTKCompatibility.cmake b/Modules/VTKCompatibility.cmake
new file mode 100644
index 0000000..1b0815e
--- /dev/null
+++ b/Modules/VTKCompatibility.cmake
@@ -0,0 +1,42 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+if(APPLE)
+ set(CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}")
+ set(CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_C_CREATE_SHARED_MODULE}")
+ string( REGEX REPLACE "CMAKE_C_COMPILER"
+ CMAKE_CXX_COMPILER CMAKE_CXX_CREATE_SHARED_MODULE
+ "${CMAKE_CXX_CREATE_SHARED_MODULE}")
+ string( REGEX REPLACE "CMAKE_C_COMPILER"
+ CMAKE_CXX_COMPILER CMAKE_CXX_CREATE_SHARED_LIBRARY
+ "${CMAKE_CXX_CREATE_SHARED_LIBRARY}")
+endif()
+
+set(VTKFTGL_BINARY_DIR "${VTK_BINARY_DIR}/Utilities/ftgl"
+ CACHE INTERNAL "")
+set(VTKFREETYPE_BINARY_DIR "${VTK_BINARY_DIR}/Utilities/freetype"
+ CACHE INTERNAL "")
+set(VTKFTGL_SOURCE_DIR "${VTK_SOURCE_DIR}/Utilities/ftgl"
+ CACHE INTERNAL "")
+set(VTKFREETYPE_SOURCE_DIR "${VTK_SOURCE_DIR}/Utilities/freetype"
+ CACHE INTERNAL "")
+
+set(VTK_GLEXT_FILE "${VTK_SOURCE_DIR}/Utilities/ParseOGLExt/headers/glext.h"
+ CACHE FILEPATH
+ "Location of the OpenGL extensions header file (glext.h).")
+set(VTK_GLXEXT_FILE
+ "${VTK_SOURCE_DIR}/Utilities/ParseOGLExt/headers/glxext.h" CACHE FILEPATH
+ "Location of the GLX extensions header file (glxext.h).")
+set(VTK_WGLEXT_FILE "${VTK_SOURCE_DIR}/Utilities/ParseOGLExt/headers/wglext.h"
+ CACHE FILEPATH
+ "Location of the WGL extensions header file (wglext.h).")
+
+# work around an old bug in VTK
+set(TIFF_RIGHT_VERSION 1)
+
+# for very old VTK (versions prior to 4.2)
+macro(SOURCE_FILES)
+ message (FATAL_ERROR "You are trying to build a very old version of VTK (prior to VTK 4.2). To do this you need to use CMake 2.0 as it was the last version of CMake to support VTK 4.0.")
+endmacro()
+
diff --git a/Modules/WriteBasicConfigVersionFile.cmake b/Modules/WriteBasicConfigVersionFile.cmake
new file mode 100644
index 0000000..45f9e58
--- /dev/null
+++ b/Modules/WriteBasicConfigVersionFile.cmake
@@ -0,0 +1,51 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+WriteBasicConfigVersionFile
+---------------------------
+
+.. deprecated:: 3.0
+
+ Use the identical command :command:`write_basic_package_version_file()`
+ from module :module:`CMakePackageConfigHelpers`.
+
+::
+
+ WRITE_BASIC_CONFIG_VERSION_FILE( filename
+ [VERSION major.minor.patch]
+ COMPATIBILITY (AnyNewerVersion|SameMajorVersion|SameMinorVersion|ExactVersion)
+ [ARCH_INDEPENDENT]
+ )
+
+
+#]=======================================================================]
+
+function(WRITE_BASIC_CONFIG_VERSION_FILE _filename)
+
+ set(options ARCH_INDEPENDENT )
+ set(oneValueArgs VERSION COMPATIBILITY )
+ set(multiValueArgs )
+
+ cmake_parse_arguments(CVF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(CVF_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to WRITE_BASIC_CONFIG_VERSION_FILE(): \"${CVF_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ set(versionTemplateFile "${CMAKE_ROOT}/Modules/BasicConfigVersion-${CVF_COMPATIBILITY}.cmake.in")
+ if(NOT EXISTS "${versionTemplateFile}")
+ message(FATAL_ERROR "Bad COMPATIBILITY value used for WRITE_BASIC_CONFIG_VERSION_FILE(): \"${CVF_COMPATIBILITY}\"")
+ endif()
+
+ if("${CVF_VERSION}" STREQUAL "")
+ if ("${PROJECT_VERSION}" STREQUAL "")
+ message(FATAL_ERROR "No VERSION specified for WRITE_BASIC_CONFIG_VERSION_FILE()")
+ else()
+ set(CVF_VERSION "${PROJECT_VERSION}")
+ endif()
+ endif()
+
+ configure_file("${versionTemplateFile}" "${_filename}" @ONLY)
+
+endfunction()
diff --git a/Modules/WriteCompilerDetectionHeader.cmake b/Modules/WriteCompilerDetectionHeader.cmake
new file mode 100644
index 0000000..5e6828f
--- /dev/null
+++ b/Modules/WriteCompilerDetectionHeader.cmake
@@ -0,0 +1,720 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+WriteCompilerDetectionHeader
+----------------------------
+
+.. deprecated:: 3.20
+ This module is available only if policy :policy:`CMP0120`
+ is not set to ``NEW``. Do not use it in new code.
+
+.. versionadded:: 3.1
+
+This module provides the function ``write_compiler_detection_header()``.
+
+This function can be used to generate a file suitable for preprocessor
+inclusion which contains macros to be used in source code::
+
+ write_compiler_detection_header(
+ FILE <file>
+ PREFIX <prefix>
+ [OUTPUT_FILES_VAR <output_files_var> OUTPUT_DIR <output_dir>]
+ COMPILERS <compiler> [...]
+ FEATURES <feature> [...]
+ [BARE_FEATURES <feature> [...]]
+ [VERSION <version>]
+ [PROLOG <prolog>]
+ [EPILOG <epilog>]
+ [ALLOW_UNKNOWN_COMPILERS]
+ [ALLOW_UNKNOWN_COMPILER_VERSIONS]
+ )
+
+This generates the file ``<file>`` with macros which all have the prefix
+``<prefix>``.
+
+By default, all content is written directly to the ``<file>``. The
+``OUTPUT_FILES_VAR`` may be specified to cause the compiler-specific
+content to be written to separate files. The separate files are then
+available in the ``<output_files_var>`` and may be consumed by the caller
+for installation for example. The ``OUTPUT_DIR`` specifies a relative
+path from the main ``<file>`` to the compiler-specific files. For example:
+
+.. code-block:: cmake
+
+ write_compiler_detection_header(
+ FILE climbingstats_compiler_detection.h
+ PREFIX ClimbingStats
+ OUTPUT_FILES_VAR support_files
+ OUTPUT_DIR compilers
+ COMPILERS GNU Clang MSVC Intel
+ FEATURES cxx_variadic_templates
+ )
+ install(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/climbingstats_compiler_detection.h
+ DESTINATION include
+ )
+ install(FILES
+ ${support_files}
+ DESTINATION include/compilers
+ )
+
+
+``VERSION`` may be used to specify the API version to be generated.
+Future versions of CMake may introduce alternative APIs. A given
+API is selected by any ``<version>`` value greater than or equal
+to the version of CMake that introduced the given API and less
+than the version of CMake that introduced its succeeding API.
+The value of the :variable:`CMAKE_MINIMUM_REQUIRED_VERSION`
+variable is used if no explicit version is specified.
+(As of CMake version |release| there is only one API version.)
+
+``PROLOG`` may be specified as text content to write at the start of the
+header. ``EPILOG`` may be specified as text content to write at the end
+of the header
+
+At least one ``<compiler>`` and one ``<feature>`` must be listed. Compilers
+which are known to CMake, but not specified are detected and a preprocessor
+``#error`` is generated for them. A preprocessor macro matching
+``<PREFIX>_COMPILER_IS_<compiler>`` is generated for each compiler
+known to CMake to contain the value ``0`` or ``1``.
+
+Possible compiler identifiers are documented with the
+:variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+Available features in this version of CMake are listed in the
+:prop_gbl:`CMAKE_C_KNOWN_FEATURES` and
+:prop_gbl:`CMAKE_CXX_KNOWN_FEATURES` global properties.
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features.
+
+.. versionadded:: 3.2
+ Added ``MSVC`` and ``AppleClang`` compiler support.
+
+.. versionadded:: 3.6
+ Added ``Intel`` compiler support.
+
+.. versionchanged:: 3.8
+ The ``{c,cxx}_std_*`` meta-features are ignored if requested.
+
+.. versionadded:: 3.8
+ ``ALLOW_UNKNOWN_COMPILERS`` and ``ALLOW_UNKNOWN_COMPILER_VERSIONS`` cause
+ the module to generate conditions that treat unknown compilers as simply
+ lacking all features. Without these options the default behavior is to
+ generate a ``#error`` for unknown compilers and versions.
+
+.. versionadded:: 3.12
+ ``BARE_FEATURES`` will define the compatibility macros with the name used in
+ newer versions of the language standard, so the code can use the new feature
+ name unconditionally.
+
+Feature Test Macros
+===================
+
+For each compiler, a preprocessor macro is generated matching
+``<PREFIX>_COMPILER_IS_<compiler>`` which has the content either ``0``
+or ``1``, depending on the compiler in use. Preprocessor macros for
+compiler version components are generated matching
+``<PREFIX>_COMPILER_VERSION_MAJOR`` ``<PREFIX>_COMPILER_VERSION_MINOR``
+and ``<PREFIX>_COMPILER_VERSION_PATCH`` containing decimal values
+for the corresponding compiler version components, if defined.
+
+A preprocessor test is generated based on the compiler version
+denoting whether each feature is enabled. A preprocessor macro
+matching ``<PREFIX>_COMPILER_<FEATURE>``, where ``<FEATURE>`` is the
+upper-case ``<feature>`` name, is generated to contain the value
+``0`` or ``1`` depending on whether the compiler in use supports the
+feature:
+
+.. code-block:: cmake
+
+ write_compiler_detection_header(
+ FILE climbingstats_compiler_detection.h
+ PREFIX ClimbingStats
+ COMPILERS GNU Clang AppleClang MSVC Intel
+ FEATURES cxx_variadic_templates
+ )
+
+.. code-block:: c++
+
+ #if ClimbingStats_COMPILER_CXX_VARIADIC_TEMPLATES
+ template<typename... T>
+ void someInterface(T t...) { /* ... */ }
+ #else
+ // Compatibility versions
+ template<typename T1>
+ void someInterface(T1 t1) { /* ... */ }
+ template<typename T1, typename T2>
+ void someInterface(T1 t1, T2 t2) { /* ... */ }
+ template<typename T1, typename T2, typename T3>
+ void someInterface(T1 t1, T2 t2, T3 t3) { /* ... */ }
+ #endif
+
+Symbol Macros
+=============
+
+Some additional symbol-defines are created for particular features for
+use as symbols which may be conditionally defined empty:
+
+.. code-block:: c++
+
+ class MyClass ClimbingStats_FINAL
+ {
+ ClimbingStats_CONSTEXPR int someInterface() { return 42; }
+ };
+
+The ``ClimbingStats_FINAL`` macro will expand to ``final`` if the
+compiler (and its flags) support the ``cxx_final`` feature, and the
+``ClimbingStats_CONSTEXPR`` macro will expand to ``constexpr``
+if ``cxx_constexpr`` is supported.
+
+If ``BARE_FEATURES cxx_final`` was given as argument the ``final`` keyword
+will be defined for old compilers, too.
+
+The following features generate corresponding symbol defines and if they
+are available as ``BARE_FEATURES``:
+
+========================== =================================== ================= ======
+ Feature Define Symbol bare
+========================== =================================== ================= ======
+``c_restrict`` ``<PREFIX>_RESTRICT`` ``restrict`` yes
+``cxx_constexpr`` ``<PREFIX>_CONSTEXPR`` ``constexpr`` yes
+``cxx_deleted_functions`` ``<PREFIX>_DELETED_FUNCTION`` ``= delete``
+``cxx_extern_templates`` ``<PREFIX>_EXTERN_TEMPLATE`` ``extern``
+``cxx_final`` ``<PREFIX>_FINAL`` ``final`` yes
+``cxx_noexcept`` ``<PREFIX>_NOEXCEPT`` ``noexcept`` yes
+``cxx_noexcept`` ``<PREFIX>_NOEXCEPT_EXPR(X)`` ``noexcept(X)``
+``cxx_override`` ``<PREFIX>_OVERRIDE`` ``override`` yes
+========================== =================================== ================= ======
+
+Compatibility Implementation Macros
+===================================
+
+Some features are suitable for wrapping in a macro with a backward
+compatibility implementation if the compiler does not support the feature.
+
+When the ``cxx_static_assert`` feature is not provided by the compiler,
+a compatibility implementation is available via the
+``<PREFIX>_STATIC_ASSERT(COND)`` and
+``<PREFIX>_STATIC_ASSERT_MSG(COND, MSG)`` function-like macros. The macros
+expand to ``static_assert`` where that compiler feature is available, and
+to a compatibility implementation otherwise. In the first form, the
+condition is stringified in the message field of ``static_assert``. In
+the second form, the message ``MSG`` is passed to the message field of
+``static_assert``, or ignored if using the backward compatibility
+implementation.
+
+The ``cxx_attribute_deprecated`` feature provides a macro definition
+``<PREFIX>_DEPRECATED``, which expands to either the standard
+``[[deprecated]]`` attribute or a compiler-specific decorator such
+as ``__attribute__((__deprecated__))`` used by GNU compilers.
+
+The ``cxx_alignas`` feature provides a macro definition
+``<PREFIX>_ALIGNAS`` which expands to either the standard ``alignas``
+decorator or a compiler-specific decorator such as
+``__attribute__ ((__aligned__))`` used by GNU compilers.
+
+The ``cxx_alignof`` feature provides a macro definition
+``<PREFIX>_ALIGNOF`` which expands to either the standard ``alignof``
+decorator or a compiler-specific decorator such as ``__alignof__``
+used by GNU compilers.
+
+============================= ================================ ===================== ======
+ Feature Define Symbol bare
+============================= ================================ ===================== ======
+``cxx_alignas`` ``<PREFIX>_ALIGNAS`` ``alignas``
+``cxx_alignof`` ``<PREFIX>_ALIGNOF`` ``alignof``
+``cxx_nullptr`` ``<PREFIX>_NULLPTR`` ``nullptr`` yes
+``cxx_static_assert`` ``<PREFIX>_STATIC_ASSERT`` ``static_assert``
+``cxx_static_assert`` ``<PREFIX>_STATIC_ASSERT_MSG`` ``static_assert``
+``cxx_attribute_deprecated`` ``<PREFIX>_DEPRECATED`` ``[[deprecated]]``
+``cxx_attribute_deprecated`` ``<PREFIX>_DEPRECATED_MSG`` ``[[deprecated]]``
+``cxx_thread_local`` ``<PREFIX>_THREAD_LOCAL`` ``thread_local``
+============================= ================================ ===================== ======
+
+A use-case which arises with such deprecation macros is the deprecation
+of an entire library. In that case, all public API in the library may
+be decorated with the ``<PREFIX>_DEPRECATED`` macro. This results in
+very noisy build output when building the library itself, so the macro
+may be may be defined to empty in that case when building the deprecated
+library:
+
+.. code-block:: cmake
+
+ add_library(compat_support ${srcs})
+ target_compile_definitions(compat_support
+ PRIVATE
+ CompatSupport_DEPRECATED=
+ )
+#]=======================================================================]
+
+# Guard against inclusion by absolute path.
+cmake_policy(GET CMP0120 _WCDH_policy)
+if(_WCDH_policy STREQUAL "NEW")
+ message(FATAL_ERROR "The WriteCompilerDetectionHeader module has been removed by policy CMP0120.")
+elseif(_WCDH_policy STREQUAL "")
+ message(AUTHOR_WARNING
+ "The WriteCompilerDetectionHeader module will be removed by policy CMP0120. "
+ "Projects should be ported away from the module, perhaps by bundling a copy "
+ "of the generated header or using a third-party alternative."
+ )
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/CMakeCompilerIdDetection.cmake)
+
+function(_load_compiler_variables CompilerId lang)
+ include("${CMAKE_ROOT}/Modules/Compiler/${CompilerId}-${lang}-FeatureTests.cmake" OPTIONAL)
+ set(_cmake_oldestSupported_${CompilerId} ${_cmake_oldestSupported} PARENT_SCOPE)
+ foreach(feature ${ARGN})
+ set(_cmake_feature_test_${CompilerId}_${feature} ${_cmake_feature_test_${feature}} PARENT_SCOPE)
+ endforeach()
+ include("${CMAKE_ROOT}/Modules/Compiler/${CompilerId}-${lang}-DetermineCompiler.cmake" OPTIONAL
+ RESULT_VARIABLE determinedCompiler)
+ if (NOT determinedCompiler)
+ include("${CMAKE_ROOT}/Modules/Compiler/${CompilerId}-DetermineCompiler.cmake" OPTIONAL)
+ endif()
+ set(_compiler_id_version_compute_${CompilerId} ${_compiler_id_version_compute} PARENT_SCOPE)
+endfunction()
+
+macro(_simpledefine FEATURE_NAME FEATURE_TESTNAME FEATURE_STRING FEATURE_DEFAULT_STRING)
+ if (feature STREQUAL "${FEATURE_NAME}")
+ set(def_value "${prefix_arg}_${FEATURE_TESTNAME}")
+ string(APPEND file_content "
+# if defined(${def_name}) && ${def_name}
+# define ${def_value} ${FEATURE_STRING}
+# else
+# define ${def_value} ${FEATURE_DEFAULT_STRING}
+# endif
+\n")
+ endif()
+endmacro()
+
+macro(_simplebaredefine FEATURE_NAME FEATURE_STRING FEATURE_DEFAULT_STRING)
+ if (feature STREQUAL "${FEATURE_NAME}")
+ string(APPEND file_content "
+# if !(defined(${def_name}) && ${def_name})
+# define ${FEATURE_STRING} ${FEATURE_DEFAULT_STRING}
+# endif
+\n")
+ endif()
+endmacro()
+
+function(_check_feature_lists C_FEATURE_VAR CXX_FEATURE_VAR)
+ foreach(feature ${ARGN})
+ if (feature MATCHES "^c_std_")
+ # ignored
+ elseif (feature MATCHES "^cxx_std_")
+ # ignored
+ elseif (feature MATCHES "^cxx_")
+ list(APPEND _langs CXX)
+ list(APPEND ${CXX_FEATURE_VAR} ${feature})
+ elseif (feature MATCHES "^c_")
+ list(APPEND _langs C)
+ list(APPEND ${C_FEATURE_VAR} ${feature})
+ else()
+ message(FATAL_ERROR "Unsupported feature ${feature}.")
+ endif()
+ endforeach()
+ set(${C_FEATURE_VAR} ${${C_FEATURE_VAR}} PARENT_SCOPE)
+ set(${CXX_FEATURE_VAR} ${${CXX_FEATURE_VAR}} PARENT_SCOPE)
+ set(_langs ${_langs} PARENT_SCOPE)
+endfunction()
+
+function(write_compiler_detection_header
+ file_keyword file_arg
+ prefix_keyword prefix_arg
+ )
+ if (NOT "x${file_keyword}" STREQUAL "xFILE")
+ message(FATAL_ERROR "write_compiler_detection_header: FILE parameter missing.")
+ endif()
+ if (NOT "x${prefix_keyword}" STREQUAL "xPREFIX")
+ message(FATAL_ERROR "write_compiler_detection_header: PREFIX parameter missing.")
+ endif()
+ set(options ALLOW_UNKNOWN_COMPILERS ALLOW_UNKNOWN_COMPILER_VERSIONS)
+ set(oneValueArgs VERSION EPILOG PROLOG OUTPUT_FILES_VAR OUTPUT_DIR)
+ set(multiValueArgs COMPILERS FEATURES BARE_FEATURES)
+ cmake_parse_arguments(_WCD "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if (NOT _WCD_COMPILERS)
+ message(FATAL_ERROR "Invalid arguments. write_compiler_detection_header requires at least one compiler.")
+ endif()
+ if (NOT _WCD_FEATURES AND NOT _WCD_BARE_FEATURES)
+ message(FATAL_ERROR "Invalid arguments. write_compiler_detection_header requires at least one feature.")
+ endif()
+
+ if(_WCD_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unparsed arguments: ${_WCD_UNPARSED_ARGUMENTS}")
+ endif()
+
+ if (prefix_arg STREQUAL "")
+ message(FATAL_ERROR "A prefix must be specified")
+ endif()
+ string(MAKE_C_IDENTIFIER ${prefix_arg} cleaned_prefix)
+ if (NOT prefix_arg STREQUAL cleaned_prefix)
+ message(FATAL_ERROR "The prefix must be a valid C identifier.")
+ endif()
+
+ if(NOT _WCD_VERSION)
+ set(_WCD_VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})
+ endif()
+ set(_min_version 3.1.0) # Version which introduced this function
+ if (_WCD_VERSION VERSION_LESS _min_version)
+ set(err "VERSION compatibility for write_compiler_detection_header is set to ${_WCD_VERSION}, which is too low.")
+ string(APPEND err " It must be set to at least ${_min_version}. ")
+ string(APPEND err " Either set the VERSION parameter to the write_compiler_detection_header function, or update")
+ string(APPEND err " your minimum required CMake version with the cmake_minimum_required command.")
+ message(FATAL_ERROR "${err}")
+ endif()
+
+ if(_WCD_OUTPUT_FILES_VAR)
+ if(NOT _WCD_OUTPUT_DIR)
+ message(FATAL_ERROR "If OUTPUT_FILES_VAR is specified, then OUTPUT_DIR must also be specified.")
+ endif()
+ endif()
+ if(_WCD_OUTPUT_DIR)
+ if(NOT _WCD_OUTPUT_FILES_VAR)
+ message(FATAL_ERROR "If OUTPUT_DIR is specified, then OUTPUT_FILES_VAR must also be specified.")
+ endif()
+ get_filename_component(main_file_dir ${file_arg} DIRECTORY)
+ if (NOT IS_ABSOLUTE ${main_file_dir})
+ set(main_file_dir "${CMAKE_CURRENT_BINARY_DIR}/${main_file_dir}")
+ endif()
+ if (NOT IS_ABSOLUTE ${_WCD_OUTPUT_DIR})
+ set(_WCD_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${_WCD_OUTPUT_DIR}")
+ endif()
+ get_filename_component(out_file_dir ${_WCD_OUTPUT_DIR} ABSOLUTE)
+ string(FIND ${out_file_dir} ${main_file_dir} idx)
+ if (NOT idx EQUAL 0)
+ message(FATAL_ERROR "The compiler-specific output directory must be within the same directory as the main file.")
+ endif()
+
+ if (main_file_dir STREQUAL out_file_dir)
+ unset(_WCD_OUTPUT_DIR)
+ else()
+ string(REPLACE "${main_file_dir}/" "" _WCD_OUTPUT_DIR "${out_file_dir}/")
+ endif()
+ endif()
+
+ set(compilers
+ GNU
+ Clang
+ AppleClang
+ MSVC
+ SunPro
+ Intel
+ )
+
+ set(_hex_compilers ADSP Borland Embarcadero SunPro)
+
+ foreach(_comp ${_WCD_COMPILERS})
+ list(FIND compilers ${_comp} idx)
+ if (idx EQUAL -1)
+ message(FATAL_ERROR "Unsupported compiler ${_comp}.")
+ endif()
+ if (NOT _need_hex_conversion)
+ list(FIND _hex_compilers ${_comp} idx)
+ if (NOT idx EQUAL -1)
+ set(_need_hex_conversion TRUE)
+ endif()
+ endif()
+ endforeach()
+
+ set(file_content "
+// This is a generated file. Do not edit!
+
+#ifndef ${prefix_arg}_COMPILER_DETECTION_H
+#define ${prefix_arg}_COMPILER_DETECTION_H
+")
+
+ if (_WCD_PROLOG)
+ string(APPEND file_content "\n${_WCD_PROLOG}\n")
+ endif()
+
+ if (_need_hex_conversion)
+ string(APPEND file_content "
+#define ${prefix_arg}_DEC(X) (X)
+#define ${prefix_arg}_HEX(X) ( \\
+ ((X)>>28 & 0xF) * 10000000 + \\
+ ((X)>>24 & 0xF) * 1000000 + \\
+ ((X)>>20 & 0xF) * 100000 + \\
+ ((X)>>16 & 0xF) * 10000 + \\
+ ((X)>>12 & 0xF) * 1000 + \\
+ ((X)>>8 & 0xF) * 100 + \\
+ ((X)>>4 & 0xF) * 10 + \\
+ ((X) & 0xF) \\
+ )\n")
+ endif()
+
+ _check_feature_lists(C_features CXX_features ${_WCD_FEATURES})
+ _check_feature_lists(C_bare_features CXX_bare_features ${_WCD_BARE_FEATURES})
+ list(REMOVE_DUPLICATES _langs)
+
+ if(_WCD_OUTPUT_FILES_VAR)
+ get_filename_component(main_file_name ${file_arg} NAME)
+ set(compiler_file_content_
+"#ifndef ${prefix_arg}_COMPILER_DETECTION_H
+# error This file may only be included from ${main_file_name}
+#endif\n")
+ endif()
+
+ foreach(_lang ${_langs})
+ set(target_compilers)
+ foreach(compiler ${_WCD_COMPILERS})
+ _load_compiler_variables(${compiler} ${_lang} ${${_lang}_features})
+ if(_cmake_oldestSupported_${compiler})
+ list(APPEND target_compilers ${compiler})
+ endif()
+ endforeach()
+
+ get_property(known_features GLOBAL PROPERTY CMAKE_${_lang}_KNOWN_FEATURES)
+ foreach(feature ${${_lang}_features})
+ list(FIND known_features ${feature} idx)
+ if (idx EQUAL -1)
+ message(FATAL_ERROR "Unsupported feature ${feature}.")
+ endif()
+ endforeach()
+
+ if(_lang STREQUAL CXX)
+ string(APPEND file_content "\n#ifdef __cplusplus\n")
+ else()
+ string(APPEND file_content "\n#ifndef __cplusplus\n")
+ endif()
+
+ compiler_id_detection(ID_CONTENT ${_lang} PREFIX ${prefix_arg}_
+ ID_DEFINE
+ )
+
+ string(APPEND file_content "${ID_CONTENT}\n")
+
+ set(pp_if "if")
+ foreach(compiler ${target_compilers})
+ string(APPEND file_content "\n# ${pp_if} ${prefix_arg}_COMPILER_IS_${compiler}\n")
+
+ if(_WCD_OUTPUT_FILES_VAR)
+ set(compile_file_name "${_WCD_OUTPUT_DIR}${prefix_arg}_COMPILER_INFO_${compiler}_${_lang}.h")
+ string(APPEND file_content "\n# include \"${compile_file_name}\"\n")
+ endif()
+
+ if(_WCD_OUTPUT_FILES_VAR)
+ set(compiler_file_content compiler_file_content_${compiler}_${_lang})
+ else()
+ set(compiler_file_content file_content)
+ endif()
+
+ if(NOT _WCD_ALLOW_UNKNOWN_COMPILER_VERSIONS)
+ string(APPEND ${compiler_file_content} "
+# if !(${_cmake_oldestSupported_${compiler}})
+# error Unsupported compiler version
+# endif\n")
+ endif()
+
+ set(PREFIX ${prefix_arg}_)
+ if (_need_hex_conversion)
+ set(MACRO_DEC ${prefix_arg}_DEC)
+ set(MACRO_HEX ${prefix_arg}_HEX)
+ else()
+ set(MACRO_DEC)
+ set(MACRO_HEX)
+ endif()
+ string(CONFIGURE "${_compiler_id_version_compute_${compiler}}" VERSION_BLOCK @ONLY)
+ string(APPEND ${compiler_file_content} "${VERSION_BLOCK}\n")
+ set(PREFIX)
+ set(MACRO_DEC)
+ set(MACRO_HEX)
+
+ set(pp_if "elif")
+ foreach(feature ${${_lang}_features})
+ string(TOUPPER ${feature} feature_upper)
+ set(feature_PP "COMPILER_${feature_upper}")
+ set(_define_item "\n# define ${prefix_arg}_${feature_PP} 0\n")
+ if (_cmake_feature_test_${compiler}_${feature} STREQUAL "1")
+ set(_define_item "\n# define ${prefix_arg}_${feature_PP} 1\n")
+ elseif (_cmake_feature_test_${compiler}_${feature})
+ set(_define_item "\n# define ${prefix_arg}_${feature_PP} 0\n")
+ set(_define_item "\n# if ${_cmake_feature_test_${compiler}_${feature}}\n# define ${prefix_arg}_${feature_PP} 1\n# else${_define_item}# endif\n")
+ endif()
+ string(APPEND ${compiler_file_content} "${_define_item}")
+ endforeach()
+ endforeach()
+ if(pp_if STREQUAL "elif")
+ if(_WCD_ALLOW_UNKNOWN_COMPILERS)
+ string(APPEND file_content "
+# endif\n")
+ else()
+ string(APPEND file_content "
+# else
+# error Unsupported compiler
+# endif\n")
+ endif()
+ endif()
+ foreach(feature ${${_lang}_features})
+ string(TOUPPER ${feature} feature_upper)
+ set(feature_PP "COMPILER_${feature_upper}")
+ set(def_name ${prefix_arg}_${feature_PP})
+ _simpledefine(c_restrict RESTRICT restrict "")
+ _simpledefine(cxx_constexpr CONSTEXPR constexpr "")
+ _simpledefine(cxx_final FINAL final "")
+ _simpledefine(cxx_override OVERRIDE override "")
+ if (feature STREQUAL cxx_static_assert)
+ set(def_value "${prefix_arg}_STATIC_ASSERT(X)")
+ set(def_value_msg "${prefix_arg}_STATIC_ASSERT_MSG(X, MSG)")
+ set(def_fallback "enum { ${prefix_arg}_STATIC_ASSERT_JOIN(${prefix_arg}StaticAssertEnum, __LINE__) = sizeof(${prefix_arg}StaticAssert<X>) }")
+ string(APPEND file_content "# if defined(${def_name}) && ${def_name}
+# define ${def_value} static_assert(X, #X)
+# define ${def_value_msg} static_assert(X, MSG)
+# else
+# define ${prefix_arg}_STATIC_ASSERT_JOIN(X, Y) ${prefix_arg}_STATIC_ASSERT_JOIN_IMPL(X, Y)
+# define ${prefix_arg}_STATIC_ASSERT_JOIN_IMPL(X, Y) X##Y
+template<bool> struct ${prefix_arg}StaticAssert;
+template<> struct ${prefix_arg}StaticAssert<true>{};
+# define ${def_value} ${def_fallback}
+# define ${def_value_msg} ${def_fallback}
+# endif
+\n")
+ endif()
+ if (feature STREQUAL cxx_alignas)
+ set(def_value "${prefix_arg}_ALIGNAS(X)")
+ string(APPEND file_content "
+# if defined(${def_name}) && ${def_name}
+# define ${def_value} alignas(X)
+# elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang || ${prefix_arg}_COMPILER_IS_AppleClang
+# define ${def_value} __attribute__ ((__aligned__(X)))
+# elif ${prefix_arg}_COMPILER_IS_MSVC
+# define ${def_value} __declspec(align(X))
+# else
+# define ${def_value}
+# endif
+\n")
+ endif()
+ if (feature STREQUAL cxx_alignof)
+ set(def_value "${prefix_arg}_ALIGNOF(X)")
+ string(APPEND file_content "
+# if defined(${def_name}) && ${def_name}
+# define ${def_value} alignof(X)
+# elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang || ${prefix_arg}_COMPILER_IS_AppleClang
+# define ${def_value} __alignof__(X)
+# elif ${prefix_arg}_COMPILER_IS_MSVC
+# define ${def_value} __alignof(X)
+# endif
+\n")
+ endif()
+ _simpledefine(cxx_deleted_functions DELETED_FUNCTION "= delete" "")
+ _simpledefine(cxx_extern_templates EXTERN_TEMPLATE extern "")
+ if (feature STREQUAL cxx_noexcept)
+ set(def_value "${prefix_arg}_NOEXCEPT")
+ string(APPEND file_content "
+# if defined(${def_name}) && ${def_name}
+# define ${def_value} noexcept
+# define ${def_value}_EXPR(X) noexcept(X)
+# else
+# define ${def_value}
+# define ${def_value}_EXPR(X)
+# endif
+\n")
+ endif()
+ if (feature STREQUAL cxx_nullptr)
+ set(def_value "${prefix_arg}_NULLPTR")
+ string(APPEND file_content "
+# if defined(${def_name}) && ${def_name}
+# define ${def_value} nullptr
+# elif ${prefix_arg}_COMPILER_IS_GNU
+# define ${def_value} __null
+# else
+# define ${def_value} 0
+# endif
+\n")
+ endif()
+ if (feature STREQUAL cxx_thread_local)
+ set(def_value "${prefix_arg}_THREAD_LOCAL")
+ string(APPEND file_content "
+# if defined(${def_name}) && ${def_name}
+# define ${def_value} thread_local
+# elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang || ${prefix_arg}_COMPILER_IS_AppleClang
+# define ${def_value} __thread
+# elif ${prefix_arg}_COMPILER_IS_MSVC
+# define ${def_value} __declspec(thread)
+# else
+// ${def_value} not defined for this configuration.
+# endif
+\n")
+ endif()
+ if (feature STREQUAL cxx_attribute_deprecated)
+ set(def_name ${prefix_arg}_${feature_PP})
+ set(def_value "${prefix_arg}_DEPRECATED")
+ string(APPEND file_content "
+# ifndef ${def_value}
+# if defined(${def_name}) && ${def_name}
+# define ${def_value} [[deprecated]]
+# define ${def_value}_MSG(MSG) [[deprecated(MSG)]]
+# elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang
+# define ${def_value} __attribute__((__deprecated__))
+# define ${def_value}_MSG(MSG) __attribute__((__deprecated__(MSG)))
+# elif ${prefix_arg}_COMPILER_IS_MSVC
+# define ${def_value} __declspec(deprecated)
+# define ${def_value}_MSG(MSG) __declspec(deprecated(MSG))
+# else
+# define ${def_value}
+# define ${def_value}_MSG(MSG)
+# endif
+# endif
+\n")
+ endif()
+ endforeach()
+
+ foreach(feature ${${_lang}_bare_features})
+ string(TOUPPER ${feature} feature_upper)
+ set(feature_PP "COMPILER_${feature_upper}")
+ set(def_name ${prefix_arg}_${feature_PP})
+ _simplebaredefine(c_restrict restrict "")
+ _simplebaredefine(cxx_constexpr constexpr "")
+ _simplebaredefine(cxx_final final "")
+ _simplebaredefine(cxx_override override "")
+ if (feature STREQUAL cxx_nullptr)
+ set(def_value "nullptr")
+ string(APPEND file_content "
+# if !(defined(${def_name}) && ${def_name})
+# if ${prefix_arg}_COMPILER_IS_GNU
+# define ${def_value} __null
+# else
+# define ${def_value} 0
+# endif
+# endif
+\n")
+ endif()
+ _simplebaredefine(cxx_noexcept noexcept "")
+ endforeach()
+
+ string(APPEND file_content "#endif\n")
+
+ endforeach()
+
+ if(_WCD_OUTPUT_FILES_VAR)
+ foreach(compiler ${_WCD_COMPILERS})
+ foreach(_lang ${_langs})
+ if(compiler_file_content_${compiler}_${_lang})
+ set(CMAKE_CONFIGURABLE_FILE_CONTENT "${compiler_file_content_}")
+ string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT "${compiler_file_content_${compiler}_${_lang}}")
+
+ set(compile_file_name "${_WCD_OUTPUT_DIR}${prefix_arg}_COMPILER_INFO_${compiler}_${_lang}.h")
+ set(full_path "${main_file_dir}/${compile_file_name}")
+ list(APPEND ${_WCD_OUTPUT_FILES_VAR} ${full_path})
+ configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
+ "${full_path}"
+ @ONLY
+ )
+ endif()
+ endforeach()
+ endforeach()
+ set(${_WCD_OUTPUT_FILES_VAR} ${${_WCD_OUTPUT_FILES_VAR}} PARENT_SCOPE)
+ endif()
+
+ if (_WCD_EPILOG)
+ string(APPEND file_content "\n${_WCD_EPILOG}\n")
+ endif()
+ string(APPEND file_content "\n#endif")
+
+ set(CMAKE_CONFIGURABLE_FILE_CONTENT ${file_content})
+ configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
+ "${file_arg}"
+ @ONLY
+ )
+endfunction()
diff --git a/Modules/ecos_clean.cmake b/Modules/ecos_clean.cmake
new file mode 100644
index 0000000..480b1ce
--- /dev/null
+++ b/Modules/ecos_clean.cmake
@@ -0,0 +1,16 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+file(GLOB _files ${ECOS_DIR}/*)
+
+# remove all directories, which consist of lower-case letters only
+# this skips e.g. CVS/ and .subversion/
+foreach(_entry ${_files})
+ if(IS_DIRECTORY ${_entry})
+ get_filename_component(dir ${_entry} NAME)
+ if(${dir} MATCHES "^[a-z]+$")
+ file(REMOVE_RECURSE ${_entry})
+ endif()
+ endif()
+endforeach()
diff --git a/Modules/exportheader.cmake.in b/Modules/exportheader.cmake.in
new file mode 100644
index 0000000..c518b3d
--- /dev/null
+++ b/Modules/exportheader.cmake.in
@@ -0,0 +1,42 @@
+
+#ifndef @INCLUDE_GUARD_NAME@
+#define @INCLUDE_GUARD_NAME@
+
+#ifdef @STATIC_DEFINE@
+# define @EXPORT_MACRO_NAME@
+# define @NO_EXPORT_MACRO_NAME@
+#else
+# ifndef @EXPORT_MACRO_NAME@
+# ifdef @EXPORT_IMPORT_CONDITION@
+ /* We are building this library */
+# define @EXPORT_MACRO_NAME@ @DEFINE_EXPORT@
+# else
+ /* We are using this library */
+# define @EXPORT_MACRO_NAME@ @DEFINE_IMPORT@
+# endif
+# endif
+
+# ifndef @NO_EXPORT_MACRO_NAME@
+# define @NO_EXPORT_MACRO_NAME@ @DEFINE_NO_EXPORT@
+# endif
+#endif
+
+#ifndef @DEPRECATED_MACRO_NAME@
+# define @DEPRECATED_MACRO_NAME@ @DEFINE_DEPRECATED@
+#endif
+
+#ifndef @DEPRECATED_MACRO_NAME@_EXPORT
+# define @DEPRECATED_MACRO_NAME@_EXPORT @EXPORT_MACRO_NAME@ @DEPRECATED_MACRO_NAME@
+#endif
+
+#ifndef @DEPRECATED_MACRO_NAME@_NO_EXPORT
+# define @DEPRECATED_MACRO_NAME@_NO_EXPORT @NO_EXPORT_MACRO_NAME@ @DEPRECATED_MACRO_NAME@
+#endif
+
+#if @DEFINE_NO_DEPRECATED@ /* DEFINE_NO_DEPRECATED */
+# ifndef @NO_DEPRECATED_MACRO_NAME@
+# define @NO_DEPRECATED_MACRO_NAME@
+# endif
+#endif
+@CUSTOM_CONTENT@
+#endif /* @INCLUDE_GUARD_NAME@ */
diff --git a/Modules/kde3init_dummy.cpp.in b/Modules/kde3init_dummy.cpp.in
new file mode 100644
index 0000000..7135c73
--- /dev/null
+++ b/Modules/kde3init_dummy.cpp.in
@@ -0,0 +1,6 @@
+
+/* used by KDE3Macros.cmake */
+
+extern "C" int kdemain(int argc, char* argv[]);
+extern "C" int kdeinitmain(int argc, char* argv[]) { return kdemain(argc,argv); }
+int main(int argc, char* argv[]) { return kdemain(argc,argv); }
diff --git a/Modules/kde3uic.cmake b/Modules/kde3uic.cmake
new file mode 100644
index 0000000..b1f73d5
--- /dev/null
+++ b/Modules/kde3uic.cmake
@@ -0,0 +1,22 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# used internally by KDE3Macros.cmake
+# neundorf@kde.org
+
+
+execute_process(COMMAND ${KDE_UIC_EXECUTABLE}
+ -L ${KDE_UIC_PLUGIN_DIR} -nounload -tr tr2i18n
+ -impl ${KDE_UIC_H_FILE}
+ ${KDE_UIC_FILE}
+ OUTPUT_VARIABLE _uic_CONTENTS
+ ERROR_QUIET
+ )
+
+string(REGEX REPLACE "tr2i18n\\(\"\"\\)" "QString::null" _uic_CONTENTS "${_uic_CONTENTS}" )
+string(REGEX REPLACE "tr2i18n\\(\"\", \"\"\\)" "QString::null" _uic_CONTENTS "${_uic_CONTENTS}" )
+
+file(WRITE ${KDE_UIC_CPP_FILE} "#include <kdialog.h>\n#include <klocale.h>\n\n")
+file(APPEND ${KDE_UIC_CPP_FILE} "${_uic_CONTENTS}")
+
diff --git a/Modules/readme.txt b/Modules/readme.txt
new file mode 100644
index 0000000..da78730
--- /dev/null
+++ b/Modules/readme.txt
@@ -0,0 +1,4 @@
+See the "Find Modules" section of the cmake-developer(7) manual page.
+
+For more information about how to contribute modules to CMake, see this page:
+https://gitlab.kitware.com/cmake/community/-/wikis/doc/cmake/dev/Module-Maintainers
diff --git a/Packaging/CMakeDMGBackground.tif b/Packaging/CMakeDMGBackground.tif
new file mode 100644
index 0000000..91c4b13
--- /dev/null
+++ b/Packaging/CMakeDMGBackground.tif
Binary files differ
diff --git a/Packaging/CMakeDMGSetup.scpt b/Packaging/CMakeDMGSetup.scpt
new file mode 100644
index 0000000..37e7bd1
--- /dev/null
+++ b/Packaging/CMakeDMGSetup.scpt
@@ -0,0 +1,57 @@
+on run argv
+ set image_name to item 1 of argv
+
+ tell application "Finder"
+ tell disk image_name
+
+ -- wait for the image to finish mounting
+ set open_attempts to 0
+ repeat while open_attempts < 4
+ try
+ open
+ delay 1
+ set open_attempts to 5
+ close
+ on error errStr number errorNumber
+ set open_attempts to open_attempts + 1
+ delay 10
+ end try
+ end repeat
+ delay 5
+
+ -- open the image the first time and save a DS_Store with just
+ -- background and icon setup
+ open
+ set current view of container window to icon view
+ set theViewOptions to the icon view options of container window
+ set background picture of theViewOptions to file ".background:background.tif"
+ set arrangement of theViewOptions to not arranged
+ set icon size of theViewOptions to 128
+ delay 5
+ close
+
+ -- next setup the position of the app and Applications symlink
+ -- plus hide all the window decoration
+ open
+ update without registering applications
+ tell container window
+ set sidebar width to 0
+ set statusbar visible to false
+ set toolbar visible to false
+ set the bounds to { 400, 100, 900, 465 }
+ set position of item "CMake.app" to { 133, 200 }
+ set position of item "Applications" to { 378, 200 }
+ end tell
+ update without registering applications
+ delay 5
+ close
+
+ -- one last open and close so you can see everything looks correct
+ open
+ delay 5
+ close
+
+ end tell
+ delay 1
+end tell
+end run
diff --git a/Packaging/QtSDK/ToolsCMakeXX.cmake b/Packaging/QtSDK/ToolsCMakeXX.cmake
new file mode 100644
index 0000000..99731fb
--- /dev/null
+++ b/Packaging/QtSDK/ToolsCMakeXX.cmake
@@ -0,0 +1,45 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# CMake version
+include("${CMAKE_CURRENT_LIST_DIR}/../../Source/CMakeVersion.cmake")
+
+# Install destinations
+set(CMake_INSTALL_INFIX "Tools/CMake/${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}/"
+ CACHE STRING "Location under install CMake tools")
+
+# Package
+set(CMake_IFW_ROOT_COMPONENT_NAME
+ "qt.tools.cmake.${CMake_VERSION_MAJOR}${CMake_VERSION_MINOR}"
+ CACHE STRING "QtSDK CMake tools component name")
+set(CMake_IFW_ROOT_COMPONENT_DISPLAY_NAME
+ "CMake ${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}.${CMake_VERSION_PATCH}"
+ CACHE STRING "QtSDK CMake tools component display name")
+set(CMake_IFW_ROOT_COMPONENT_DESCRIPTION
+ "CMake Build Tools ${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}.${CMake_VERSION_PATH}"
+ CACHE STRING "QtSDK CMake tools component description")
+set(CMake_IFW_ROOT_COMPONENT_SCRIPT_TEMPLATE
+ "${CMAKE_CURRENT_LIST_DIR}/qt.tools.cmake.xx.qs.in"
+ CACHE FILEPATH "QtSDK CMake tools script template")
+set(CMake_IFW_ROOT_COMPONENT_SCRIPT_GENERATED
+ "${CMAKE_CURRENT_BINARY_DIR}/qt.tools.cmake.${CMake_VERSION_MAJOR}${CMake_VERSION_MINOR}.qs"
+ CACHE FILEPATH "QtSDK CMake tools script generated")
+set(CMake_IFW_ROOT_COMPONENT_PRIORITY
+ "${CMake_VERSION_MAJOR}${CMake_VERSION_MINOR}"
+ CACHE STRING "QtSDK CMake tools component sorting priority")
+set(CMake_IFW_ROOT_COMPONENT_DEFAULT ""
+ CACHE STRING "QtSDK CMake tools component default")
+set(CMake_IFW_ROOT_COMPONENT_FORCED_INSTALLATION ""
+ CACHE STRING "QtSDK CMake tools component forsed installation")
+
+# CPack
+set(CPACK_GENERATOR "IFW"
+ CACHE STRING "Generator to build QtSDK CMake package")
+set(CPACK_PACKAGE_FILE_NAME "CMake"
+ CACHE STRING "Short package name")
+set(CPACK_TOPLEVEL_TAG "../QtSDK"
+ CACHE STRING "QtSDK packages dir")
+set(CPACK_IFW_DOWNLOAD_ALL "TRUE"
+ CACHE STRING "All QtSDK components is downloaded")
+set(CPACK_DOWNLOAD_SITE "file:///${CMAKE_CURRENT_BINARY_DIR}/QtSDK/IFW/CMake/repository"
+ CACHE STRING "Local repository for testing")
diff --git a/Packaging/QtSDK/qt.tools.cmake.xx.qs.in b/Packaging/QtSDK/qt.tools.cmake.xx.qs.in
new file mode 100644
index 0000000..e806dd7
--- /dev/null
+++ b/Packaging/QtSDK/qt.tools.cmake.xx.qs.in
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+** file Copyright.txt or https://cmake.org/licensing for details.
+**
+****************************************************************************/
+
+// constructor
+function Component()
+{
+ installer.valueChanged.connect( this, Component.prototype.reactOnTargetDirChange );
+ // set the default values to CMAKE%CMake_VERSION_MAJOR%%CMake_VERSION_MINOR%_BIN_DIR
+ Component.prototype.reactOnTargetDirChange("TargetDir", installer.value("TargetDir"));
+}
+
+Component.prototype.reactOnTargetDirChange = function(key, value)
+{
+ if (key == "TargetDir") {
+ var path = value + "/%CMAKE_BIN_DIR%";
+ installer.setValue("CMAKE%CMake_VERSION_MAJOR%%CMake_VERSION_MINOR%_BIN_DIR", path.replace(/\\/g, "/"));
+ }
+}
+
+Component.prototype.createOperations = function()
+{
+ component.createOperations();
+
+ try {
+ if (installer.value("SDKToolBinary") == "")
+ return;
+
+ var cmId = component.name;
+ installer.setValue("CMAKE%CMake_VERSION_MAJOR%%CMake_VERSION_MINOR%_ID", cmId);
+
+ component.addOperation("Execute",
+ ["{0,2}", "@SDKToolBinary@", "addCMake",
+ "--id", cmId,
+ "--name", "%CMake_IFW_ROOT_COMPONENT_DISPLAY_NAME%",
+ "--path", "@CMAKE%CMake_VERSION_MAJOR%%CMake_VERSION_MINOR%_BIN_DIR@/cmake%CMAKE_EXECUTABLE_SUFFIX%",
+ "UNDOEXECUTE",
+ "@SDKToolBinary@", "rmCMake", "--id", cmId]);
+
+ } catch( e ) {
+ print( e );
+ }
+}
diff --git a/README.rst b/README.rst
index fc6b590..64e2353 100644
--- a/README.rst
+++ b/README.rst
@@ -1,33 +1,128 @@
-KWSys
+CMake
*****
Introduction
============
-KWSys is the Kitware System Library. It provides platform-independent
-APIs to many common system features that are implemented differently on
-every platform. This library is intended to be shared among many
-projects at the source level, so it has a configurable namespace.
-Each project should configure KWSys to use a namespace unique to itself.
-See comments in `CMakeLists.txt`_ for details.
+CMake is a cross-platform, open-source build system generator.
+For full documentation visit the `CMake Home Page`_ and the
+`CMake Documentation Page`_. The `CMake Community Wiki`_ also
+references useful guides and recipes.
-.. _`CMakeLists.txt`: CMakeLists.txt
+.. _`CMake Home Page`: https://cmake.org
+.. _`CMake Documentation Page`: https://cmake.org/documentation
+.. _`CMake Community Wiki`: https://gitlab.kitware.com/cmake/community/-/wikis/home
+
+CMake is maintained and supported by `Kitware`_ and developed in
+collaboration with a productive community of contributors.
+
+.. _`Kitware`: http://www.kitware.com/cmake
License
=======
-KWSys is distributed under the OSI-approved BSD 3-clause License.
+CMake is distributed under the OSI-approved BSD 3-clause License.
See `Copyright.txt`_ for details.
.. _`Copyright.txt`: Copyright.txt
+Building CMake
+==============
+
+Supported Platforms
+-------------------
+
+* Microsoft Windows
+* Apple macOS
+* Linux
+* FreeBSD
+* OpenBSD
+* Solaris
+* AIX
+
+Other UNIX-like operating systems may work too out of the box, if not
+it should not be a major problem to port CMake to this platform.
+Please post to the `CMake Discourse Forum`_ to ask if others have
+had experience with the platform.
+
+.. _`CMake Discourse Forum`: https://discourse.cmake.org
+
+Building CMake from Scratch
+---------------------------
+
+UNIX/Mac OSX/MinGW/MSYS/Cygwin
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You need to have a C++ compiler (supporting C++11) and a ``make`` installed.
+Run the ``bootstrap`` script you find in the source directory of CMake.
+You can use the ``--help`` option to see the supported options.
+You may use the ``--prefix=<install_prefix>`` option to specify a custom
+installation directory for CMake. Once this has finished successfully,
+run ``make`` and ``make install``.
+
+For example, if you simply want to build and install CMake from source,
+you can build directly in the source tree::
+
+ $ ./bootstrap && make && sudo make install
+
+Or, if you plan to develop CMake or otherwise run the test suite, create
+a separate build tree::
+
+ $ mkdir cmake-build && cd cmake-build
+ $ ../cmake-source/bootstrap && make
+
+Windows
+^^^^^^^
+
+There are two ways for building CMake under Windows:
+
+1. Compile with MSVC from VS 2015 or later.
+ You need to download and install a binary release of CMake. You can get
+ these releases from the `CMake Download Page`_. Then proceed with the
+ instructions below for `Building CMake with CMake`_.
+
+2. Bootstrap with MinGW under MSYS2.
+ Download and install `MSYS2`_. Then install the required build tools::
+
+ $ pacman -S --needed git base-devel mingw-w64-x86_64-gcc
+
+ and bootstrap as above.
+
+.. _`CMake Download Page`: https://cmake.org/download
+.. _`MSYS2`: https://www.msys2.org/
+
+Building CMake with CMake
+-------------------------
+
+You can build CMake as any other project with a CMake-based build system:
+run the installed CMake on the sources of this CMake with your preferred
+options and generators. Then build it and install it.
+For instructions how to do this, see documentation on `Running CMake`_.
+
+.. _`Running CMake`: https://cmake.org/runningcmake
+
+To build the documentation, install `Sphinx`_ and configure CMake with
+``-DSPHINX_HTML=ON`` and/or ``-DSPHINX_MAN=ON`` to enable the "html" or
+"man" builder. Add ``-DSPHINX_EXECUTABLE=/path/to/sphinx-build`` if the
+tool is not found automatically.
+
+.. _`Sphinx`: http://sphinx-doc.org
+
Reporting Bugs
==============
-KWSys has no independent issue tracker. After encountering an issue
-(bug) please submit a patch using the instructions for `Contributing`_.
-Otherwise please report the issue to the tracker for the project that
-hosts the copy of KWSys in which the problem was found.
+If you have found a bug:
+
+1. If you have a patch, please read the `CONTRIBUTING.rst`_ document.
+
+2. Otherwise, please post to the `CMake Discourse Forum`_ and ask about
+ the expected and observed behaviors to determine if it is really
+ a bug.
+
+3. Finally, if the issue is not resolved by the above steps, open
+ an entry in the `CMake Issue Tracker`_.
+
+.. _`CMake Issue Tracker`: https://gitlab.kitware.com/cmake/cmake/-/issues
Contributing
============
diff --git a/Source/.gitattributes b/Source/.gitattributes
new file mode 100644
index 0000000..d0aedc2
--- /dev/null
+++ b/Source/.gitattributes
@@ -0,0 +1,4 @@
+CMakeVersion.cmake export-subst
+
+# Do not format third-party sources.
+/kwsys/** -format.clang-format-6.0
diff --git a/Source/CMakeInstallDestinations.cmake b/Source/CMakeInstallDestinations.cmake
new file mode 100644
index 0000000..e82bec3
--- /dev/null
+++ b/Source/CMakeInstallDestinations.cmake
@@ -0,0 +1,59 @@
+# Keep formatting here consistent with bootstrap script expectations.
+if(BEOS)
+ set(CMAKE_BIN_DIR_DEFAULT "bin") # HAIKU
+ set(CMAKE_DATA_DIR_DEFAULT "share/cmake-${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}") # HAIKU
+ set(CMAKE_DOC_DIR_DEFAULT "documentation/doc/cmake-${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}") # HAIKU
+ set(CMAKE_INFO_DIR_DEFAULT "documentation/info") # HAIKU
+ set(CMAKE_MAN_DIR_DEFAULT "documentation/man") # HAIKU
+ set(CMAKE_XDGDATA_DIR_DEFAULT "share") # HAIKU
+elseif(CYGWIN)
+ set(CMAKE_BIN_DIR_DEFAULT "bin") # CYGWIN
+ set(CMAKE_DATA_DIR_DEFAULT "share/cmake-${CMake_VERSION}") # CYGWIN
+ set(CMAKE_DOC_DIR_DEFAULT "share/doc/cmake-${CMake_VERSION}") # CYGWIN
+ set(CMAKE_INFO_DIR_DEFAULT "share/info") # CYGWIN
+ set(CMAKE_MAN_DIR_DEFAULT "share/man") # CYGWIN
+ set(CMAKE_XDGDATA_DIR_DEFAULT "share") # CYGWIN
+else()
+ set(CMAKE_BIN_DIR_DEFAULT "bin") # OTHER
+ set(CMAKE_DATA_DIR_DEFAULT "share/cmake-${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}") # OTHER
+ set(CMAKE_DOC_DIR_DEFAULT "doc/cmake-${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}") # OTHER
+ set(CMAKE_INFO_DIR_DEFAULT "info") # OTHER
+ set(CMAKE_MAN_DIR_DEFAULT "man") # OTHER
+ set(CMAKE_XDGDATA_DIR_DEFAULT "share") # OTHER
+endif()
+
+set(CMAKE_BIN_DIR_DESC "bin")
+set(CMAKE_DATA_DIR_DESC "data")
+set(CMAKE_DOC_DIR_DESC "docs")
+set(CMAKE_INFO_DIR_DESC "Info manual")
+set(CMAKE_MAN_DIR_DESC "man pages")
+set(CMAKE_XDGDATA_DIR_DESC "XDG specific files")
+
+set(CMake_INSTALL_INFIX "" CACHE STRING "")
+set_property(CACHE CMake_INSTALL_INFIX PROPERTY HELPSTRING
+ "Intermediate installation path (empty by default)"
+ )
+mark_as_advanced(CMake_INSTALL_INFIX)
+
+foreach(v
+ CMAKE_BIN_DIR
+ CMAKE_DATA_DIR
+ CMAKE_DOC_DIR
+ CMAKE_INFO_DIR
+ CMAKE_MAN_DIR
+ CMAKE_XDGDATA_DIR
+ )
+ # Populate the cache with empty values so we know when the user sets them.
+ set(${v} "" CACHE STRING "")
+ set_property(CACHE ${v} PROPERTY HELPSTRING
+ "Location under install prefix for ${${v}_DESC} (default \"${${v}_DEFAULT}\")"
+ )
+ set_property(CACHE ${v} PROPERTY ADVANCED 1)
+
+ # Use the default when the user did not set this variable.
+ if(NOT ${v})
+ set(${v} "${CMake_INSTALL_INFIX}${${v}_DEFAULT}")
+ endif()
+ # Remove leading slash to treat as relative to install prefix.
+ string(REGEX REPLACE "^/" "" ${v} "${${v}}")
+endforeach()
diff --git a/Source/CMakeInstallSignTool.cmake.in b/Source/CMakeInstallSignTool.cmake.in
new file mode 100644
index 0000000..fca629c
--- /dev/null
+++ b/Source/CMakeInstallSignTool.cmake.in
@@ -0,0 +1,51 @@
+# The signtool. Default to PATH.
+set(CMake_INSTALL_SIGNTOOL "@CMake_INSTALL_SIGNTOOL@")
+if(NOT CMake_INSTALL_SIGNTOOL)
+ set(CMake_INSTALL_SIGNTOOL signtool)
+endif()
+
+# Select a certificate by Subject Name. Default to automatic selection.
+set(CMake_INSTALL_SIGNTOOL_SUBJECT_NAME "@CMake_INSTALL_SIGNTOOL_SUBJECT_NAME@")
+if(CMake_INSTALL_SIGNTOOL_SUBJECT_NAME)
+ set(select_cert -n "${CMake_INSTALL_SIGNTOOL_SUBJECT_NAME}")
+else()
+ set(select_cert -a)
+endif()
+
+# Timestamp URL. Default to a common provider.
+set(CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL "@CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL@")
+if(NOT CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL)
+ set(CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL "http://timestamp.digicert.com")
+endif()
+
+# Glob files that need a signature.
+file(GLOB files "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/*.exe")
+
+# Sign all files at once.
+if(files)
+ # Run the signtool through 'cmd /c' to enable password prompt popup.
+ # Some providers have trouble when signtool is invoked with SW_HIDE.
+ set(cmd cmd /c "${CMake_INSTALL_SIGNTOOL}" sign -v ${select_cert})
+
+ # Sign with SHA-1 for Windows 7 and below.
+ execute_process(
+ COMMAND ${cmd} -t "${CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL}" ${files}
+ RESULT_VARIABLE result
+ ERROR_VARIABLE stderr
+ )
+ if(NOT result EQUAL 0)
+ string(REPLACE "\n" "\n " stderr " ${stderr}")
+ message(WARNING "signtool failed:\n${stderr}")
+ endif()
+
+ # Sign with SHA-256 for Windows 8 and above.
+ execute_process(
+ COMMAND ${cmd} -tr "${CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL}" -fd sha256 -td sha256 -as ${files}
+ RESULT_VARIABLE result
+ ERROR_VARIABLE stderr
+ )
+ if(NOT result EQUAL 0)
+ string(REPLACE "\n" "\n " stderr " ${stderr}")
+ message(WARNING "signtool failed:\n${stderr}")
+ endif()
+endif()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
new file mode 100644
index 0000000..938745c
--- /dev/null
+++ b/Source/CMakeLists.txt
@@ -0,0 +1,1246 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# To ensure maximum portability across various compilers and platforms
+# deactivate any compiler extensions. Skip this for QNX, where additional
+# work is needed to build without compiler extensions.
+if (NOT CMAKE_SYSTEM_NAME STREQUAL "QNX")
+ set(CMAKE_C_EXTENSIONS FALSE)
+ set(CMAKE_CXX_EXTENSIONS FALSE)
+endif()
+
+include(CheckIncludeFile)
+# Check if we can build support for ELF parsing.
+if(WIN32)
+ set(HAVE_ELF_H 0)
+elseif(CMAKE_CXX_PLATFORM_ID MATCHES "OpenBSD")
+ CHECK_INCLUDE_FILES("stdint.h;elf_abi.h" HAVE_ELF_H)
+else()
+ CHECK_INCLUDE_FILE("elf.h" HAVE_ELF_H)
+endif()
+if(HAVE_ELF_H)
+ set(CMake_USE_ELF_PARSER 1)
+elseif(HAIKU)
+ # On Haiku, we need to include elf32.h from the private headers
+ set(CMake_HAIKU_INCLUDE_DIRS
+ /boot/system/develop/headers/private/system
+ /boot/system/develop/headers/private/system/arch/x86
+ )
+
+ set(CMAKE_REQUIRED_INCLUDES ${CMake_HAIKU_INCLUDE_DIRS})
+ CHECK_INCLUDE_FILE("elf32.h" HAVE_ELF32_H)
+ unset(CMAKE_REQUIRED_INCLUDES)
+
+ if(HAVE_ELF32_H)
+ set(CMake_USE_ELF_PARSER 1)
+ else()
+ unset(CMake_HAIKU_INCLUDE_DIRS)
+ set(CMake_USE_ELF_PARSER)
+ endif()
+else()
+ set(CMake_USE_ELF_PARSER)
+endif()
+
+if(NOT CMake_DEFAULT_RECURSION_LIMIT)
+ if(DEFINED ENV{DASHBOARD_TEST_FROM_CTEST})
+ set(CMake_DEFAULT_RECURSION_LIMIT 100)
+ elseif(MINGW)
+ set(CMake_DEFAULT_RECURSION_LIMIT 400)
+ elseif(WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "IntelLLVM")
+ set(CMake_DEFAULT_RECURSION_LIMIT 600)
+ else()
+ set(CMake_DEFAULT_RECURSION_LIMIT 1000)
+ endif()
+endif()
+
+if(APPLE)
+ set(CMake_USE_MACH_PARSER 1)
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
+ set(CMake_USE_XCOFF_PARSER 1)
+endif()
+
+set(EXECUTABLE_OUTPUT_PATH ${CMake_BIN_DIR})
+
+if(WIN32)
+ # ensure Unicode friendly APIs are used on Windows
+ add_definitions(-DUNICODE -D_UNICODE)
+
+ # minimize windows.h content
+ add_definitions(-DWIN32_LEAN_AND_MEAN)
+endif()
+
+# configure the .dox.in file
+if(CMake_BUILD_DEVELOPER_REFERENCE)
+ configure_file(
+ "${CMake_SOURCE_DIR}/Source/dir.dox.in"
+ "${CMake_BINARY_DIR}/Source/dir.dox"
+ @ONLY
+ )
+endif()
+
+# configure the .h file
+configure_file(
+ "${CMake_SOURCE_DIR}/Source/cmConfigure.cmake.h.in"
+ "${CMake_BINARY_DIR}/Source/cmConfigure.h"
+ )
+configure_file(
+ "${CMake_SOURCE_DIR}/Source/cmVersionConfig.h.in"
+ "${CMake_BINARY_DIR}/Source/cmVersionConfig.h"
+ )
+configure_file(
+ "${CMake_SOURCE_DIR}/Source/CPack/cmCPackConfigure.h.in"
+ "${CMake_BINARY_DIR}/Source/CPack/cmCPackConfigure.h"
+ )
+
+# Tell CMake executable in the build tree where to find the source tree.
+configure_file(
+ "${CMake_SOURCE_DIR}/Source/CMakeSourceDir.txt.in"
+ "${CMake_BINARY_DIR}/CMakeFiles/CMakeSourceDir.txt" @ONLY
+ )
+
+# add the include path to find the .h
+include_directories(
+ "${CMake_BINARY_DIR}/Source"
+ "${CMake_SOURCE_DIR}/Source"
+ "${CMake_SOURCE_DIR}/Source/LexerParser"
+ ${CMAKE_ZLIB_INCLUDES}
+ ${CMAKE_EXPAT_INCLUDES}
+ ${CMAKE_TAR_INCLUDES}
+ ${CMake_HAIKU_INCLUDE_DIRS}
+ )
+
+# Check if we can build the ELF parser.
+if(CMake_USE_ELF_PARSER)
+ set(ELF_SRCS cmELF.h cmELF.cxx)
+endif()
+
+# Check if we can build the Mach-O parser.
+if(CMake_USE_MACH_PARSER)
+ set(MACH_SRCS cmMachO.h cmMachO.cxx)
+endif()
+
+# Check if we can build the XCOFF parser.
+if(CMake_USE_XCOFF_PARSER)
+ set(XCOFF_SRCS cmXCOFF.h cmXCOFF.cxx)
+endif()
+
+#
+# Sources for CMakeLib
+#
+set(SRCS
+ # Lexers/Parsers
+ LexerParser/cmCommandArgumentLexer.cxx
+ LexerParser/cmCommandArgumentLexer.h
+ LexerParser/cmCommandArgumentLexer.in.l
+ LexerParser/cmCommandArgumentParser.cxx
+ LexerParser/cmCommandArgumentParserTokens.h
+ LexerParser/cmCommandArgumentParser.y
+ LexerParser/cmDependsJavaLexer.cxx
+ LexerParser/cmDependsJavaLexer.h
+ LexerParser/cmDependsJavaLexer.in.l
+ LexerParser/cmDependsJavaParser.cxx
+ LexerParser/cmDependsJavaParserTokens.h
+ LexerParser/cmDependsJavaParser.y
+ LexerParser/cmExprLexer.cxx
+ LexerParser/cmExprLexer.h
+ LexerParser/cmExprLexer.in.l
+ LexerParser/cmExprParser.cxx
+ LexerParser/cmExprParserTokens.h
+ LexerParser/cmExprParser.y
+ LexerParser/cmFortranLexer.cxx
+ LexerParser/cmFortranLexer.h
+ LexerParser/cmFortranLexer.in.l
+ LexerParser/cmFortranParser.cxx
+ LexerParser/cmFortranParserTokens.h
+ LexerParser/cmFortranParser.y
+ LexerParser/cmGccDepfileLexer.cxx
+ LexerParser/cmGccDepfileLexer.h
+ LexerParser/cmGccDepfileLexer.in.l
+ LexerParser/cmListFileLexer.c
+ LexerParser/cmListFileLexer.in.l
+
+ cmAffinity.cxx
+ cmAffinity.h
+ cmAlgorithms.h
+ cmArchiveWrite.cxx
+ cmArgumentParser.cxx
+ cmArgumentParser.h
+ cmBase32.cxx
+ cmBinUtilsLinker.cxx
+ cmBinUtilsLinker.h
+ cmBinUtilsLinuxELFGetRuntimeDependenciesTool.cxx
+ cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h
+ cmBinUtilsLinuxELFLinker.cxx
+ cmBinUtilsLinuxELFLinker.h
+ cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx
+ cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h
+ cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.cxx
+ cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h
+ cmBinUtilsMacOSMachOLinker.cxx
+ cmBinUtilsMacOSMachOLinker.h
+ cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx
+ cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h
+ cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx
+ cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h
+ cmBinUtilsWindowsPEGetRuntimeDependenciesTool.cxx
+ cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h
+ cmBinUtilsWindowsPELinker.cxx
+ cmBinUtilsWindowsPELinker.h
+ cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
+ cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
+ cmCacheManager.cxx
+ cmCacheManager.h
+ cmCLocaleEnvironmentScope.h
+ cmCLocaleEnvironmentScope.cxx
+ cmCMakePath.h
+ cmCMakePath.cxx
+ cmCMakePresetsFile.cxx
+ cmCMakePresetsFile.h
+ cmCMakePresetsFileInternal.h
+ cmCMakePresetsFileReadJSON.cxx
+ cmCommandArgumentParserHelper.cxx
+ cmCommonTargetGenerator.cxx
+ cmCommonTargetGenerator.h
+ cmComputeComponentGraph.cxx
+ cmComputeComponentGraph.h
+ cmComputeLinkDepends.cxx
+ cmComputeLinkDepends.h
+ cmComputeLinkInformation.cxx
+ cmComputeLinkInformation.h
+ cmComputeTargetDepends.h
+ cmComputeTargetDepends.cxx
+ cmConsoleBuf.h
+ cmConsoleBuf.cxx
+ cmCPackPropertiesGenerator.h
+ cmCPackPropertiesGenerator.cxx
+ cmCryptoHash.cxx
+ cmCryptoHash.h
+ cmCurl.cxx
+ cmCurl.h
+ cmCustomCommand.cxx
+ cmCustomCommand.h
+ cmCustomCommandGenerator.cxx
+ cmCustomCommandGenerator.h
+ cmCustomCommandLines.cxx
+ cmCustomCommandLines.h
+ cmCustomCommandTypes.h
+ cmDefinitions.cxx
+ cmDefinitions.h
+ cmDepends.cxx
+ cmDepends.h
+ cmDependsC.cxx
+ cmDependsC.h
+ cmDependsFortran.cxx
+ cmDependsFortran.h
+ cmDependsJava.cxx
+ cmDependsJava.h
+ cmDependsJavaParserHelper.cxx
+ cmDependsJavaParserHelper.h
+ cmDependsCompiler.cxx
+ cmDependsCompiler.h
+ cmDocumentation.cxx
+ cmDocumentationFormatter.cxx
+ cmDocumentationSection.cxx
+ cmDynamicLoader.cxx
+ cmDynamicLoader.h
+ ${ELF_SRCS}
+ cmExprParserHelper.cxx
+ cmExportBuildAndroidMKGenerator.h
+ cmExportBuildAndroidMKGenerator.cxx
+ cmExportBuildFileGenerator.h
+ cmExportBuildFileGenerator.cxx
+ cmExportFileGenerator.h
+ cmExportFileGenerator.cxx
+ cmExportInstallAndroidMKGenerator.h
+ cmExportInstallAndroidMKGenerator.cxx
+ cmExportInstallFileGenerator.h
+ cmExportInstallFileGenerator.cxx
+ cmExportTryCompileFileGenerator.h
+ cmExportTryCompileFileGenerator.cxx
+ cmExportSet.h
+ cmExportSet.cxx
+ cmExternalMakefileProjectGenerator.cxx
+ cmExternalMakefileProjectGenerator.h
+ cmExtraCodeBlocksGenerator.cxx
+ cmExtraCodeBlocksGenerator.h
+ cmExtraCodeLiteGenerator.cxx
+ cmExtraCodeLiteGenerator.h
+ cmExtraEclipseCDT4Generator.cxx
+ cmExtraEclipseCDT4Generator.h
+ cmExtraKateGenerator.cxx
+ cmExtraKateGenerator.h
+ cmExtraSublimeTextGenerator.cxx
+ cmExtraSublimeTextGenerator.h
+ cmFileAPI.cxx
+ cmFileAPI.h
+ cmFileAPICache.cxx
+ cmFileAPICache.h
+ cmFileAPICodemodel.cxx
+ cmFileAPICodemodel.h
+ cmFileAPICMakeFiles.cxx
+ cmFileAPICMakeFiles.h
+ cmFileAPIToolchains.cxx
+ cmFileAPIToolchains.h
+ cmFileCopier.cxx
+ cmFileCopier.h
+ cmFileInstaller.cxx
+ cmFileInstaller.h
+ cmFileLock.cxx
+ cmFileLock.h
+ cmFileLockPool.cxx
+ cmFileLockPool.h
+ cmFileLockResult.cxx
+ cmFileLockResult.h
+ cmFilePathChecksum.cxx
+ cmFilePathChecksum.h
+ cmFileTime.cxx
+ cmFileTime.h
+ cmFileTimeCache.cxx
+ cmFileTimeCache.h
+ cmFileTimes.cxx
+ cmFileTimes.h
+ cmFortranParserImpl.cxx
+ cmFSPermissions.cxx
+ cmFSPermissions.h
+ cmGccDepfileLexerHelper.cxx
+ cmGccDepfileLexerHelper.h
+ cmGccDepfileReader.cxx
+ cmGccDepfileReader.h
+ cmGeneratedFileStream.cxx
+ cmGeneratorExpressionContext.cxx
+ cmGeneratorExpressionContext.h
+ cmGeneratorExpressionDAGChecker.cxx
+ cmGeneratorExpressionDAGChecker.h
+ cmGeneratorExpressionEvaluationFile.cxx
+ cmGeneratorExpressionEvaluationFile.h
+ cmGeneratorExpressionEvaluator.cxx
+ cmGeneratorExpressionEvaluator.h
+ cmGeneratorExpressionLexer.cxx
+ cmGeneratorExpressionLexer.h
+ cmGeneratorExpressionNode.cxx
+ cmGeneratorExpressionNode.h
+ cmGeneratorExpressionParser.cxx
+ cmGeneratorExpressionParser.h
+ cmGeneratorExpression.cxx
+ cmGeneratorExpression.h
+ cmGeneratorTarget.cxx
+ cmGeneratorTarget.h
+ cmLinkItemGraphVisitor.cxx
+ cmLinkItemGraphVisitor.h
+ cmGetPipes.cxx
+ cmGetPipes.h
+ cmGlobalCommonGenerator.cxx
+ cmGlobalCommonGenerator.h
+ cmGlobalGenerator.cxx
+ cmGlobalGenerator.h
+ cmGlobalGeneratorFactory.h
+ cmGlobalUnixMakefileGenerator3.cxx
+ cmGlobalUnixMakefileGenerator3.h
+ cmGlobVerificationManager.cxx
+ cmGlobVerificationManager.h
+ cmGraphAdjacencyList.h
+ cmGraphVizWriter.cxx
+ cmGraphVizWriter.h
+ cmInstallGenerator.h
+ cmInstallGenerator.cxx
+ cmInstallExportGenerator.cxx
+ cmInstalledFile.h
+ cmInstalledFile.cxx
+ cmInstallFilesGenerator.h
+ cmInstallFilesGenerator.cxx
+ cmInstallScriptGenerator.h
+ cmInstallScriptGenerator.cxx
+ cmInstallSubdirectoryGenerator.h
+ cmInstallSubdirectoryGenerator.cxx
+ cmInstallTargetGenerator.h
+ cmInstallTargetGenerator.cxx
+ cmInstallDirectoryGenerator.h
+ cmInstallDirectoryGenerator.cxx
+ cmJSONHelpers.h
+ cmLDConfigLDConfigTool.cxx
+ cmLDConfigLDConfigTool.h
+ cmLDConfigTool.cxx
+ cmLDConfigTool.h
+ cmLinkedTree.h
+ cmLinkItem.cxx
+ cmLinkItem.h
+ cmLinkLineComputer.cxx
+ cmLinkLineComputer.h
+ cmLinkLineDeviceComputer.cxx
+ cmLinkLineDeviceComputer.h
+ cmListFileCache.cxx
+ cmListFileCache.h
+ cmLocalCommonGenerator.cxx
+ cmLocalCommonGenerator.h
+ cmLocalGenerator.cxx
+ cmLocalGenerator.h
+ cmRulePlaceholderExpander.cxx
+ cmRulePlaceholderExpander.h
+ cmLocalUnixMakefileGenerator3.cxx
+ cmLocale.h
+ ${MACH_SRCS}
+ cmMakefile.cxx
+ cmMakefile.h
+ cmMakefileTargetGenerator.cxx
+ cmMakefileExecutableTargetGenerator.cxx
+ cmMakefileLibraryTargetGenerator.cxx
+ cmMakefileProfilingData.cxx
+ cmMakefileUtilityTargetGenerator.cxx
+ cmMessageType.h
+ cmMessenger.cxx
+ cmMessenger.h
+ cmMSVC60LinkLineComputer.cxx
+ cmMSVC60LinkLineComputer.h
+ cmOSXBundleGenerator.cxx
+ cmOSXBundleGenerator.h
+ cmOutputConverter.cxx
+ cmOutputConverter.h
+ cmNewLineStyle.h
+ cmNewLineStyle.cxx
+ cmOrderDirectories.cxx
+ cmOrderDirectories.h
+ cmPolicies.h
+ cmPolicies.cxx
+ cmProcessOutput.cxx
+ cmProcessOutput.h
+ cmProcessTools.cxx
+ cmProcessTools.h
+ cmProperty.h
+ cmPropertyDefinition.cxx
+ cmPropertyDefinition.h
+ cmPropertyMap.cxx
+ cmPropertyMap.h
+ cmQtAutoGen.cxx
+ cmQtAutoGen.h
+ cmQtAutoGenerator.cxx
+ cmQtAutoGenerator.h
+ cmQtAutoGenGlobalInitializer.cxx
+ cmQtAutoGenGlobalInitializer.h
+ cmQtAutoGenInitializer.cxx
+ cmQtAutoGenInitializer.h
+ cmQtAutoMocUic.cxx
+ cmQtAutoMocUic.h
+ cmQtAutoRcc.cxx
+ cmQtAutoRcc.h
+ cmRST.cxx
+ cmRST.h
+ cmRuntimeDependencyArchive.cxx
+ cmRuntimeDependencyArchive.h
+ cmScriptGenerator.h
+ cmScriptGenerator.cxx
+ cmSourceFile.cxx
+ cmSourceFile.h
+ cmSourceFileLocation.cxx
+ cmSourceFileLocation.h
+ cmSourceFileLocationKind.h
+ cmSourceGroup.cxx
+ cmSourceGroup.h
+ cmStandardLevelResolver.cxx
+ cmStandardLevelResolver.h
+ cmState.cxx
+ cmState.h
+ cmStateDirectory.cxx
+ cmStateDirectory.h
+ cmStateSnapshot.cxx
+ cmStateSnapshot.h
+ cmStateTypes.h
+ cmStringAlgorithms.cxx
+ cmStringAlgorithms.h
+ cmSystemTools.cxx
+ cmSystemTools.h
+ cmTarget.cxx
+ cmTarget.h
+ cmTargetPropertyComputer.cxx
+ cmTargetPropertyComputer.h
+ cmTargetExport.h
+ cmTest.cxx
+ cmTest.h
+ cmTestGenerator.cxx
+ cmTestGenerator.h
+ cmTransformDepfile.cxx
+ cmTransformDepfile.h
+ cmUuid.cxx
+ cmUVHandlePtr.cxx
+ cmUVHandlePtr.h
+ cmUVProcessChain.cxx
+ cmUVProcessChain.h
+ cmUVStreambuf.h
+ cmUVSignalHackRAII.h
+ cmVariableWatch.cxx
+ cmVariableWatch.h
+ cmVersion.cxx
+ cmVersion.h
+ cmWorkerPool.cxx
+ cmWorkerPool.h
+ cmWorkingDirectory.cxx
+ cmWorkingDirectory.h
+ ${XCOFF_SRCS}
+ cmXMLParser.cxx
+ cmXMLParser.h
+ cmXMLSafe.cxx
+ cmXMLSafe.h
+ cmXMLWriter.cxx
+ cmXMLWriter.h
+ cmake.cxx
+ cmake.h
+
+ cmCommand.cxx
+ cmCommand.h
+ cmCommands.cxx
+ cmCommands.h
+ cmAddCompileDefinitionsCommand.cxx
+ cmAddCompileDefinitionsCommand.h
+ cmAddCompileOptionsCommand.cxx
+ cmAddCompileOptionsCommand.h
+ cmAddLinkOptionsCommand.cxx
+ cmAddLinkOptionsCommand.h
+ cmAddCustomCommandCommand.cxx
+ cmAddCustomCommandCommand.h
+ cmAddCustomTargetCommand.cxx
+ cmAddCustomTargetCommand.h
+ cmAddDefinitionsCommand.cxx
+ cmAddDefinitionsCommand.h
+ cmAddDependenciesCommand.cxx
+ cmAddDependenciesCommand.h
+ cmAddExecutableCommand.cxx
+ cmAddExecutableCommand.h
+ cmAddLibraryCommand.cxx
+ cmAddLibraryCommand.h
+ cmAddSubDirectoryCommand.cxx
+ cmAddSubDirectoryCommand.h
+ cmAddTestCommand.cxx
+ cmAddTestCommand.h
+ cmAuxSourceDirectoryCommand.cxx
+ cmAuxSourceDirectoryCommand.h
+ cmBreakCommand.cxx
+ cmBreakCommand.h
+ cmBuildCommand.cxx
+ cmBuildCommand.h
+ cmBuildNameCommand.cxx
+ cmBuildNameCommand.h
+ cmCMakeHostSystemInformationCommand.cxx
+ cmCMakeHostSystemInformationCommand.h
+ cmCMakeLanguageCommand.cxx
+ cmCMakeLanguageCommand.h
+ cmCMakeMinimumRequired.cxx
+ cmCMakeMinimumRequired.h
+ cmCMakePathCommand.h
+ cmCMakePathCommand.cxx
+ cmCMakePolicyCommand.cxx
+ cmCMakePolicyCommand.h
+ cmConditionEvaluator.cxx
+ cmConditionEvaluator.h
+ cmConfigureFileCommand.cxx
+ cmConfigureFileCommand.h
+ cmContinueCommand.cxx
+ cmContinueCommand.h
+ cmCoreTryCompile.cxx
+ cmCoreTryCompile.h
+ cmCreateTestSourceList.cxx
+ cmCreateTestSourceList.h
+ cmDefinePropertyCommand.cxx
+ cmDefinePropertyCommand.h
+ cmEnableLanguageCommand.cxx
+ cmEnableLanguageCommand.h
+ cmEnableTestingCommand.cxx
+ cmEnableTestingCommand.h
+ cmExecProgramCommand.cxx
+ cmExecProgramCommand.h
+ cmExecuteProcessCommand.cxx
+ cmExecuteProcessCommand.h
+ cmExpandedCommandArgument.cxx
+ cmExpandedCommandArgument.h
+ cmExportCommand.cxx
+ cmExportCommand.h
+ cmExportLibraryDependenciesCommand.cxx
+ cmExportLibraryDependenciesCommand.h
+ cmFLTKWrapUICommand.cxx
+ cmFLTKWrapUICommand.h
+ cmFileCommand.cxx
+ cmFileCommand.h
+ cmFindBase.cxx
+ cmFindBase.h
+ cmFindCommon.cxx
+ cmFindCommon.h
+ cmFindFileCommand.cxx
+ cmFindFileCommand.h
+ cmFindLibraryCommand.cxx
+ cmFindLibraryCommand.h
+ cmFindPackageCommand.cxx
+ cmFindPackageCommand.h
+ cmFindPathCommand.cxx
+ cmFindPathCommand.h
+ cmFindProgramCommand.cxx
+ cmFindProgramCommand.h
+ cmForEachCommand.cxx
+ cmForEachCommand.h
+ cmFunctionBlocker.cxx
+ cmFunctionBlocker.h
+ cmFunctionCommand.cxx
+ cmFunctionCommand.h
+ cmGetCMakePropertyCommand.cxx
+ cmGetCMakePropertyCommand.h
+ cmGetDirectoryPropertyCommand.cxx
+ cmGetDirectoryPropertyCommand.h
+ cmGetFilenameComponentCommand.cxx
+ cmGetFilenameComponentCommand.h
+ cmGetPropertyCommand.cxx
+ cmGetPropertyCommand.h
+ cmGetSourceFilePropertyCommand.cxx
+ cmGetSourceFilePropertyCommand.h
+ cmGetTargetPropertyCommand.cxx
+ cmGetTargetPropertyCommand.h
+ cmGetTestPropertyCommand.cxx
+ cmGetTestPropertyCommand.h
+ cmHexFileConverter.cxx
+ cmHexFileConverter.h
+ cmIfCommand.cxx
+ cmIfCommand.h
+ cmIncludeCommand.cxx
+ cmIncludeCommand.h
+ cmIncludeDirectoryCommand.cxx
+ cmIncludeDirectoryCommand.h
+ cmIncludeExternalMSProjectCommand.cxx
+ cmIncludeExternalMSProjectCommand.h
+ cmIncludeGuardCommand.cxx
+ cmIncludeGuardCommand.h
+ cmIncludeRegularExpressionCommand.cxx
+ cmIncludeRegularExpressionCommand.h
+ cmInstallCommand.cxx
+ cmInstallCommand.h
+ cmInstallCommandArguments.cxx
+ cmInstallCommandArguments.h
+ cmInstallFilesCommand.cxx
+ cmInstallFilesCommand.h
+ cmInstallProgramsCommand.cxx
+ cmInstallProgramsCommand.h
+ cmInstallTargetsCommand.cxx
+ cmInstallTargetsCommand.h
+ cmLinkDirectoriesCommand.cxx
+ cmLinkDirectoriesCommand.h
+ cmLinkLibrariesCommand.cxx
+ cmLinkLibrariesCommand.h
+ cmListCommand.cxx
+ cmListCommand.h
+ cmLoadCacheCommand.cxx
+ cmLoadCacheCommand.h
+ cmLoadCommandCommand.cxx
+ cmLoadCommandCommand.h
+ cmMacroCommand.cxx
+ cmMacroCommand.h
+ cmMakeDirectoryCommand.cxx
+ cmMakeDirectoryCommand.h
+ cmMarkAsAdvancedCommand.cxx
+ cmMarkAsAdvancedCommand.h
+ cmMathCommand.cxx
+ cmMathCommand.h
+ cmMessageCommand.cxx
+ cmMessageCommand.h
+ cmOptionCommand.cxx
+ cmOptionCommand.h
+ cmOutputRequiredFilesCommand.cxx
+ cmOutputRequiredFilesCommand.h
+ cmParseArgumentsCommand.cxx
+ cmParseArgumentsCommand.h
+ cmPathLabel.cxx
+ cmPathLabel.h
+ cmProjectCommand.cxx
+ cmProjectCommand.h
+ cmQTWrapCPPCommand.cxx
+ cmQTWrapCPPCommand.h
+ cmQTWrapUICommand.cxx
+ cmQTWrapUICommand.h
+ cmRemoveCommand.cxx
+ cmRemoveCommand.h
+ cmRemoveDefinitionsCommand.cxx
+ cmRemoveDefinitionsCommand.h
+ cmReturnCommand.cxx
+ cmReturnCommand.h
+ cmSearchPath.cxx
+ cmSearchPath.h
+ cmSeparateArgumentsCommand.cxx
+ cmSeparateArgumentsCommand.h
+ cmSetCommand.cxx
+ cmSetCommand.h
+ cmSetDirectoryPropertiesCommand.cxx
+ cmSetDirectoryPropertiesCommand.h
+ cmSetPropertyCommand.cxx
+ cmSetPropertyCommand.h
+ cmSetSourceFilesPropertiesCommand.cxx
+ cmSetSourceFilesPropertiesCommand.h
+ cmSetTargetPropertiesCommand.cxx
+ cmSetTargetPropertiesCommand.h
+ cmSetTestsPropertiesCommand.cxx
+ cmSetTestsPropertiesCommand.h
+ cmSiteNameCommand.cxx
+ cmSiteNameCommand.h
+ cmSourceGroupCommand.cxx
+ cmSourceGroupCommand.h
+ cmString.cxx
+ cmString.hxx
+ cmStringReplaceHelper.cxx
+ cmStringCommand.cxx
+ cmStringCommand.h
+ cmSubcommandTable.cxx
+ cmSubcommandTable.h
+ cmSubdirCommand.cxx
+ cmSubdirCommand.h
+ cmSubdirDependsCommand.cxx
+ cmSubdirDependsCommand.h
+ cmTargetCompileDefinitionsCommand.cxx
+ cmTargetCompileDefinitionsCommand.h
+ cmTargetCompileFeaturesCommand.cxx
+ cmTargetCompileFeaturesCommand.h
+ cmTargetCompileOptionsCommand.cxx
+ cmTargetCompileOptionsCommand.h
+ cmTargetIncludeDirectoriesCommand.cxx
+ cmTargetIncludeDirectoriesCommand.h
+ cmTargetLinkOptionsCommand.cxx
+ cmTargetLinkOptionsCommand.h
+ cmTargetLinkDirectoriesCommand.cxx
+ cmTargetLinkDirectoriesCommand.h
+ cmTargetLinkLibrariesCommand.cxx
+ cmTargetLinkLibrariesCommand.h
+ cmTargetPrecompileHeadersCommand.cxx
+ cmTargetPrecompileHeadersCommand.h
+ cmTargetPropCommandBase.cxx
+ cmTargetPropCommandBase.h
+ cmTargetSourcesCommand.cxx
+ cmTargetSourcesCommand.h
+ cmTimestamp.cxx
+ cmTimestamp.h
+ cmTryCompileCommand.cxx
+ cmTryCompileCommand.h
+ cmTryRunCommand.cxx
+ cmTryRunCommand.h
+ cmUnsetCommand.cxx
+ cmUnsetCommand.h
+ cmUseMangledMesaCommand.cxx
+ cmUseMangledMesaCommand.h
+ cmUtilitySourceCommand.cxx
+ cmUtilitySourceCommand.h
+ cmVariableRequiresCommand.cxx
+ cmVariableRequiresCommand.h
+ cmVariableWatchCommand.cxx
+ cmVariableWatchCommand.h
+ cmWhileCommand.cxx
+ cmWhileCommand.h
+ cmWriteFileCommand.cxx
+ cmWriteFileCommand.h
+
+ cm_get_date.h
+ cm_get_date.c
+ cm_utf8.h
+ cm_utf8.c
+ cm_codecvt.hxx
+ cm_codecvt.cxx
+
+ cmDuration.h
+ cmDuration.cxx
+
+ bindexplib.cxx
+ )
+
+SET_PROPERTY(SOURCE cmProcessOutput.cxx APPEND PROPERTY COMPILE_DEFINITIONS
+ KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
+
+# Xcode only works on Apple
+if(APPLE)
+ set(SRCS ${SRCS}
+ cmXCodeObject.cxx
+ cmXCode21Object.cxx
+ cmXCodeScheme.cxx
+ cmGlobalXCodeGenerator.cxx
+ cmGlobalXCodeGenerator.h
+ cmLocalXCodeGenerator.cxx
+ cmLocalXCodeGenerator.h)
+endif()
+
+
+if (WIN32)
+ set(SRCS ${SRCS}
+ cmCallVisualStudioMacro.cxx
+ cmCallVisualStudioMacro.h
+ )
+
+ if(NOT UNIX)
+ set(SRCS ${SRCS}
+ cmGlobalBorlandMakefileGenerator.cxx
+ cmGlobalBorlandMakefileGenerator.h
+ cmGlobalMSYSMakefileGenerator.cxx
+ cmGlobalMinGWMakefileGenerator.cxx
+ cmGlobalNMakeMakefileGenerator.cxx
+ cmGlobalNMakeMakefileGenerator.h
+ cmGlobalJOMMakefileGenerator.cxx
+ cmGlobalJOMMakefileGenerator.h
+ cmGlobalVisualStudio71Generator.cxx
+ cmGlobalVisualStudio71Generator.h
+ cmGlobalVisualStudio7Generator.cxx
+ cmGlobalVisualStudio7Generator.h
+ cmGlobalVisualStudio8Generator.cxx
+ cmGlobalVisualStudio8Generator.h
+ cmGlobalVisualStudio9Generator.cxx
+ cmGlobalVisualStudio9Generator.h
+ cmVisualStudioGeneratorOptions.h
+ cmVisualStudioGeneratorOptions.cxx
+ cmVisualStudio10TargetGenerator.h
+ cmVisualStudio10TargetGenerator.cxx
+ cmLocalVisualStudio10Generator.cxx
+ cmLocalVisualStudio10Generator.h
+ cmGlobalVisualStudio10Generator.h
+ cmGlobalVisualStudio10Generator.cxx
+ cmGlobalVisualStudio11Generator.h
+ cmGlobalVisualStudio11Generator.cxx
+ cmGlobalVisualStudio12Generator.h
+ cmGlobalVisualStudio12Generator.cxx
+ cmGlobalVisualStudio14Generator.h
+ cmGlobalVisualStudio14Generator.cxx
+ cmGlobalVisualStudioGenerator.cxx
+ cmGlobalVisualStudioGenerator.h
+ cmGlobalVisualStudioVersionedGenerator.h
+ cmGlobalVisualStudioVersionedGenerator.cxx
+ cmIDEFlagTable.h
+ cmIDEOptions.cxx
+ cmIDEOptions.h
+ cmLocalVisualStudio7Generator.cxx
+ cmLocalVisualStudio7Generator.h
+ cmLocalVisualStudioGenerator.cxx
+ cmLocalVisualStudioGenerator.h
+ cmVisualStudioSlnData.h
+ cmVisualStudioSlnData.cxx
+ cmVisualStudioSlnParser.h
+ cmVisualStudioSlnParser.cxx
+ cmVisualStudioWCEPlatformParser.h
+ cmVisualStudioWCEPlatformParser.cxx
+ cmVSSetupHelper.cxx
+ cmVSSetupHelper.h
+ )
+
+ # Add a manifest file to executables on Windows to allow for
+ # GetVersion to work properly on Windows 8 and above.
+ set(MANIFEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake.version.manifest)
+ endif()
+endif ()
+
+# Watcom support
+if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ set_property(SOURCE cmake.cxx APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_USE_WMAKE)
+ list(APPEND SRCS
+ cmGlobalWatcomWMakeGenerator.cxx
+ cmGlobalWatcomWMakeGenerator.h
+ )
+endif()
+
+# GHS support
+# Works only for windows and linux
+if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ set(SRCS ${SRCS}
+ cmGlobalGhsMultiGenerator.cxx
+ cmGlobalGhsMultiGenerator.h
+ cmLocalGhsMultiGenerator.cxx
+ cmLocalGhsMultiGenerator.h
+ cmGhsMultiTargetGenerator.cxx
+ cmGhsMultiTargetGenerator.h
+ cmGhsMultiGpj.cxx
+ cmGhsMultiGpj.h
+ )
+endif()
+
+
+# Ninja support
+set(SRCS ${SRCS}
+ cmScanDepFormat.cxx
+ cmGlobalNinjaGenerator.cxx
+ cmGlobalNinjaGenerator.h
+ cmNinjaTypes.h
+ cmLocalNinjaGenerator.cxx
+ cmLocalNinjaGenerator.h
+ cmNinjaTargetGenerator.cxx
+ cmNinjaTargetGenerator.h
+ cmNinjaNormalTargetGenerator.cxx
+ cmNinjaNormalTargetGenerator.h
+ cmNinjaUtilityTargetGenerator.cxx
+ cmNinjaUtilityTargetGenerator.h
+ cmNinjaLinkLineComputer.cxx
+ cmNinjaLinkLineComputer.h
+ cmNinjaLinkLineDeviceComputer.cxx
+ cmNinjaLinkLineDeviceComputer.h
+ )
+
+# Temporary variable for tools targets
+set(_tools)
+
+if(WIN32 AND NOT CYGWIN)
+ set_source_files_properties(cmcldeps.cxx PROPERTIES COMPILE_DEFINITIONS _WIN32_WINNT=0x0501)
+ add_executable(cmcldeps cmcldeps.cxx ${MANIFEST_FILE})
+ list(APPEND _tools cmcldeps)
+ target_link_libraries(cmcldeps CMakeLib)
+endif()
+
+foreach(v CURL_CA_BUNDLE CURL_CA_PATH)
+ if(${v})
+ set_property(SOURCE cmCurl.cxx APPEND PROPERTY COMPILE_DEFINITIONS ${v}="${${v}}")
+ endif()
+endforeach()
+
+foreach(check
+ STAT_HAS_ST_MTIM
+ STAT_HAS_ST_MTIMESPEC
+ )
+ if(KWSYS_CXX_${check}_COMPILED) # abuse KWSys check cache entry
+ set(CMake_${check} 1)
+ else()
+ set(CMake_${check} 0)
+ endif()
+ set_property(SOURCE cmFileTime.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS CMake_${check}=${CMake_${check}})
+endforeach()
+
+# create a library used by the command line and the GUI
+add_library(CMakeLib ${SRCS})
+target_link_libraries(CMakeLib cmsys
+ ${CMAKE_STD_LIBRARY}
+ ${CMAKE_EXPAT_LIBRARIES} ${CMAKE_ZLIB_LIBRARIES}
+ ${CMAKE_TAR_LIBRARIES}
+ ${CMAKE_CURL_LIBRARIES}
+ ${CMAKE_JSONCPP_LIBRARIES}
+ ${CMAKE_LIBUV_LIBRARIES}
+ ${CMAKE_LIBRHASH_LIBRARIES}
+ ${CMake_KWIML_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ )
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "sparc")
+ # the atomic instructions are implemented using libatomic on some platforms,
+ # so linking to that may be required
+ check_library_exists(atomic __atomic_fetch_add_4 "" LIBATOMIC_NEEDED)
+ if(LIBATOMIC_NEEDED)
+ target_link_libraries(CMakeLib atomic)
+ endif()
+endif()
+
+# On Apple we need CoreFoundation and CoreServices
+if(APPLE)
+ target_link_libraries(CMakeLib "-framework CoreFoundation")
+ target_link_libraries(CMakeLib "-framework CoreServices")
+endif()
+
+if(WIN32 AND NOT UNIX)
+ # We need the rpcrt4 library on Windows.
+ # We need the crypt32 library on Windows for crypto/cert APIs.
+ target_link_libraries(CMakeLib rpcrt4 crypt32)
+endif()
+
+target_compile_definitions(CMakeLib PUBLIC ${CLANG_TIDY_DEFINITIONS})
+
+#
+# CTestLib
+#
+include_directories(
+ "${CMake_SOURCE_DIR}/Source/CTest"
+ ${CMAKE_CURL_INCLUDES}
+ )
+#
+# Sources for CTestLib
+#
+set(CTEST_SRCS cmCTest.cxx
+ CTest/cmProcess.cxx
+ CTest/cmCTestBinPacker.cxx
+ CTest/cmCTestBuildAndTestHandler.cxx
+ CTest/cmCTestBuildCommand.cxx
+ CTest/cmCTestBuildHandler.cxx
+ CTest/cmCTestConfigureCommand.cxx
+ CTest/cmCTestConfigureHandler.cxx
+ CTest/cmCTestCoverageCommand.cxx
+ CTest/cmCTestCoverageHandler.cxx
+ CTest/cmCTestCurl.cxx
+ CTest/cmParseMumpsCoverage.cxx
+ CTest/cmParseCacheCoverage.cxx
+ CTest/cmParseGTMCoverage.cxx
+ CTest/cmParseJacocoCoverage.cxx
+ CTest/cmParseBlanketJSCoverage.cxx
+ CTest/cmParsePHPCoverage.cxx
+ CTest/cmParseCoberturaCoverage.cxx
+ CTest/cmParseDelphiCoverage.cxx
+ CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
+ CTest/cmCTestGenericHandler.cxx
+ CTest/cmCTestHandlerCommand.cxx
+ CTest/cmCTestResourceAllocator.cxx
+ CTest/cmCTestResourceSpec.cxx
+ CTest/cmCTestLaunch.cxx
+ CTest/cmCTestLaunchReporter.cxx
+ CTest/cmCTestMemCheckCommand.cxx
+ CTest/cmCTestMemCheckHandler.cxx
+ CTest/cmCTestMultiProcessHandler.cxx
+ CTest/cmCTestReadCustomFilesCommand.cxx
+ CTest/cmCTestResourceGroupsLexerHelper.cxx
+ CTest/cmCTestRunScriptCommand.cxx
+ CTest/cmCTestRunTest.cxx
+ CTest/cmCTestScriptHandler.cxx
+ CTest/cmCTestSleepCommand.cxx
+ CTest/cmCTestStartCommand.cxx
+ CTest/cmCTestSubmitCommand.cxx
+ CTest/cmCTestSubmitHandler.cxx
+ CTest/cmCTestTestCommand.cxx
+ CTest/cmCTestTestHandler.cxx
+ CTest/cmCTestUpdateCommand.cxx
+ CTest/cmCTestUpdateHandler.cxx
+ CTest/cmCTestUploadCommand.cxx
+ CTest/cmCTestUploadHandler.cxx
+
+ CTest/cmCTestVC.cxx
+ CTest/cmCTestVC.h
+ CTest/cmCTestGlobalVC.cxx
+ CTest/cmCTestGlobalVC.h
+ CTest/cmCTestCVS.cxx
+ CTest/cmCTestCVS.h
+ CTest/cmCTestSVN.cxx
+ CTest/cmCTestSVN.h
+ CTest/cmCTestBZR.cxx
+ CTest/cmCTestBZR.h
+ CTest/cmCTestGIT.cxx
+ CTest/cmCTestGIT.h
+ CTest/cmCTestHG.cxx
+ CTest/cmCTestHG.h
+ CTest/cmCTestP4.cxx
+ CTest/cmCTestP4.h
+
+ LexerParser/cmCTestResourceGroupsLexer.cxx
+ LexerParser/cmCTestResourceGroupsLexer.h
+ LexerParser/cmCTestResourceGroupsLexer.in.l
+ )
+
+# Build CTestLib
+add_library(CTestLib ${CTEST_SRCS})
+target_link_libraries(CTestLib CMakeLib ${CMAKE_CURL_LIBRARIES})
+
+#
+# CPack
+#
+include_directories(
+ "${CMake_SOURCE_DIR}/Source/CPack"
+ )
+#
+# Sources for CPack
+#
+set(CPACK_SRCS
+ CPack/cmCPackArchiveGenerator.cxx
+ CPack/cmCPackComponentGroup.cxx
+ CPack/cmCPackDebGenerator.cxx
+ CPack/cmCPackExternalGenerator.cxx
+ CPack/cmCPackGeneratorFactory.cxx
+ CPack/cmCPackGenerator.cxx
+ CPack/cmCPackLog.cxx
+ CPack/cmCPackNSISGenerator.cxx
+ CPack/cmCPackNuGetGenerator.cxx
+ CPack/cmCPackSTGZGenerator.cxx
+ )
+# CPack IFW generator
+set(CPACK_SRCS ${CPACK_SRCS}
+ CPack/IFW/cmCPackIFWCommon.cxx
+ CPack/IFW/cmCPackIFWCommon.h
+ CPack/IFW/cmCPackIFWGenerator.cxx
+ CPack/IFW/cmCPackIFWGenerator.h
+ CPack/IFW/cmCPackIFWInstaller.cxx
+ CPack/IFW/cmCPackIFWInstaller.h
+ CPack/IFW/cmCPackIFWPackage.cxx
+ CPack/IFW/cmCPackIFWPackage.h
+ CPack/IFW/cmCPackIFWRepository.cxx
+ CPack/IFW/cmCPackIFWRepository.h
+ )
+
+if(CYGWIN)
+ set(CPACK_SRCS ${CPACK_SRCS}
+ CPack/cmCPackCygwinBinaryGenerator.cxx
+ CPack/cmCPackCygwinSourceGenerator.cxx
+ )
+endif()
+
+option(CPACK_ENABLE_FREEBSD_PKG "Add FreeBSD pkg(8) generator to CPack." OFF)
+
+if(UNIX)
+ set(CPACK_SRCS ${CPACK_SRCS}
+ CPack/cmCPackRPMGenerator.cxx
+ )
+
+ # Optionally, try to use pkg(8)
+ if(CPACK_ENABLE_FREEBSD_PKG)
+ # On UNIX, you may find FreeBSD's pkg(8) and attendant
+ # library -- it can be used on FreeBSD, Dragonfly, NetBSD,
+ # OpenBSD and also Linux and OSX. Look for the header and
+ # the library; it's a warning on FreeBSD if they're not
+ # found, and informational on other platforms.
+ find_path(FREEBSD_PKG_INCLUDE_DIRS "pkg.h")
+ if(FREEBSD_PKG_INCLUDE_DIRS)
+ find_library(FREEBSD_PKG_LIBRARIES
+ pkg
+ DOC "FreeBSD pkg(8) library")
+ if(FREEBSD_PKG_LIBRARIES)
+ set(CPACK_SRCS ${CPACK_SRCS}
+ CPack/cmCPackFreeBSDGenerator.cxx
+ )
+ endif()
+ endif()
+
+ if (NOT FREEBSD_PKG_INCLUDE_DIRS OR NOT FREEBSD_PKG_LIBRARIES)
+ message(FATAL_ERROR "CPack needs libpkg(3) to produce FreeBSD packages natively.")
+ endif()
+ else()
+ set(FREEBSD_PKG_INCLUDE_DIRS NOTFOUND)
+ set(FREEBSD_PKG_LIBRARIES NOTFOUND)
+ endif()
+endif()
+
+if(CYGWIN)
+ find_package(LibUUID)
+endif()
+if(WIN32 OR (CYGWIN AND LibUUID_FOUND))
+ set(CPACK_SRCS ${CPACK_SRCS}
+ CPack/WiX/cmCMakeToWixPath.cxx
+ CPack/WiX/cmCMakeToWixPath.h
+ CPack/WiX/cmCPackWIXGenerator.cxx
+ CPack/WiX/cmCPackWIXGenerator.h
+ CPack/WiX/cmWIXAccessControlList.cxx
+ CPack/WiX/cmWIXAccessControlList.h
+ CPack/WiX/cmWIXDirectoriesSourceWriter.cxx
+ CPack/WiX/cmWIXDirectoriesSourceWriter.h
+ CPack/WiX/cmWIXFeaturesSourceWriter.cxx
+ CPack/WiX/cmWIXFeaturesSourceWriter.h
+ CPack/WiX/cmWIXFilesSourceWriter.cxx
+ CPack/WiX/cmWIXFilesSourceWriter.h
+ CPack/WiX/cmWIXPatch.cxx
+ CPack/WiX/cmWIXPatch.h
+ CPack/WiX/cmWIXPatchParser.cxx
+ CPack/WiX/cmWIXPatchParser.h
+ CPack/WiX/cmWIXRichTextFormatWriter.cxx
+ CPack/WiX/cmWIXRichTextFormatWriter.h
+ CPack/WiX/cmWIXShortcut.cxx
+ CPack/WiX/cmWIXShortcut.h
+ CPack/WiX/cmWIXSourceWriter.cxx
+ CPack/WiX/cmWIXSourceWriter.h
+ )
+endif()
+
+if(APPLE)
+ set(CPACK_SRCS ${CPACK_SRCS}
+ CPack/cmCPackBundleGenerator.cxx
+ CPack/cmCPackDragNDropGenerator.cxx
+ CPack/cmCPackOSXX11Generator.cxx
+ CPack/cmCPackPKGGenerator.cxx
+ CPack/cmCPackPackageMakerGenerator.cxx
+ CPack/cmCPackProductBuildGenerator.cxx
+ )
+endif()
+
+# Build CPackLib
+add_library(CPackLib ${CPACK_SRCS})
+target_link_libraries(CPackLib CMakeLib)
+if(APPLE)
+ # Some compilers produce errors in the CoreServices framework headers.
+ # Ideally such errors should be fixed by either the compiler vendor
+ # or the framework source, but we try to workaround it and build anyway.
+ # If it does not work, build with reduced functionality and warn.
+ check_include_file("CoreServices/CoreServices.h" HAVE_CoreServices)
+ if(HAVE_CoreServices)
+ set_property(SOURCE CPack/cmCPackDragNDropGenerator.cxx PROPERTY COMPILE_DEFINITIONS HAVE_CoreServices)
+ target_link_libraries(CPackLib "-framework CoreServices")
+ else()
+ message(WARNING "This compiler does not appear to support\n"
+ " #include <CoreServices/CoreServices.h>\n"
+ "Some CPack functionality may be limited.\n"
+ "See CMakeFiles/CMakeError.log for details of the failure.")
+ endif()
+endif()
+if(CYGWIN AND LibUUID_FOUND)
+ target_link_libraries(CPackLib ${LibUUID_LIBRARIES})
+ include_directories(CPackLib ${LibUUID_INCLUDE_DIRS})
+ set_property(SOURCE CPack/cmCPackGeneratorFactory.cxx PROPERTY COMPILE_DEFINITIONS HAVE_LIBUUID)
+endif()
+if(CPACK_ENABLE_FREEBSD_PKG AND FREEBSD_PKG_INCLUDE_DIRS AND FREEBSD_PKG_LIBRARIES)
+ target_link_libraries(CPackLib ${FREEBSD_PKG_LIBRARIES})
+ include_directories(${FREEBSD_PKG_INCLUDE_DIRS})
+ add_definitions(-DHAVE_FREEBSD_PKG)
+endif()
+
+if(APPLE)
+ add_executable(OSXScriptLauncher
+ CPack/OSXScriptLauncher.cxx)
+ target_link_libraries(OSXScriptLauncher cmsys)
+ target_link_libraries(OSXScriptLauncher "-framework CoreFoundation")
+endif()
+
+# Build CMake executable
+add_executable(cmake cmakemain.cxx cmcmd.cxx cmcmd.h ${MANIFEST_FILE})
+list(APPEND _tools cmake)
+target_link_libraries(cmake CMakeLib)
+
+# Build CTest executable
+add_executable(ctest ctest.cxx ${MANIFEST_FILE})
+list(APPEND _tools ctest)
+target_link_libraries(ctest CTestLib)
+
+# Build CPack executable
+add_executable(cpack CPack/cpack.cxx ${MANIFEST_FILE})
+list(APPEND _tools cpack)
+target_link_libraries(cpack CPackLib)
+
+# Curses GUI
+if(BUILD_CursesDialog)
+ add_subdirectory(CursesDialog)
+endif()
+
+# Qt GUI
+option(BUILD_QtDialog "Build Qt dialog for CMake" FALSE)
+if(BUILD_QtDialog)
+ add_subdirectory(QtDialog)
+endif()
+
+include (${CMake_BINARY_DIR}/Source/LocalUserOptions.cmake OPTIONAL)
+include (${CMake_SOURCE_DIR}/Source/LocalUserOptions.cmake OPTIONAL)
+
+if(WIN32)
+ # Compute the binary version that appears in the RC file. Version
+ # components in the RC file are 16-bit integers so we may have to
+ # split the patch component.
+ if(CMake_VERSION_PATCH MATCHES "^([0-9]+)([0-9][0-9][0-9][0-9])$")
+ set(CMake_RCVERSION_YEAR "${CMAKE_MATCH_1}")
+ set(CMake_RCVERSION_MONTH_DAY "${CMAKE_MATCH_2}")
+ string(REGEX REPLACE "^0+" "" CMake_RCVERSION_MONTH_DAY "${CMake_RCVERSION_MONTH_DAY}")
+ set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMake_RCVERSION_YEAR},${CMake_RCVERSION_MONTH_DAY})
+ unset(CMake_RCVERSION_MONTH_DAY)
+ unset(CMake_RCVERSION_YEAR)
+ else()
+ set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMake_VERSION_PATCH},0)
+ endif()
+ set(CMake_RCVERSION_STR ${CMake_VERSION})
+
+ # Add Windows executable version information.
+ configure_file("CMakeVersion.rc.in" "CMakeVersion.rc" @ONLY)
+
+ # We use a separate object library for this to work around a limitation of
+ # MinGW's windres tool with spaces in the path to the include directories.
+ add_library(CMakeVersion OBJECT "${CMAKE_CURRENT_BINARY_DIR}/CMakeVersion.rc")
+ set_property(TARGET CMakeVersion PROPERTY INCLUDE_DIRECTORIES "")
+ foreach(_tool ${_tools})
+ target_sources(${_tool} PRIVATE $<TARGET_OBJECTS:CMakeVersion>)
+ endforeach()
+endif()
+
+if(CMake_JOB_POOL_LINK_BIN)
+ set_property(TARGET ${_tools} PROPERTY JOB_POOL_LINK "link-bin")
+ set_property(GLOBAL APPEND PROPERTY JOB_POOLS "link-bin=${CMake_JOB_POOL_LINK_BIN}")
+endif()
+
+# Install tools
+
+foreach(_tool ${_tools})
+ CMake_OPTIONAL_COMPONENT(${_tool})
+ install(TARGETS ${_tool} DESTINATION ${CMAKE_BIN_DIR} ${COMPONENT})
+endforeach()
+
+install(FILES cmCPluginAPI.h DESTINATION ${CMAKE_DATA_DIR}/include)
+
+# Unset temporary variables
+unset(_tools)
diff --git a/Source/CMakeSourceDir.txt.in b/Source/CMakeSourceDir.txt.in
new file mode 100644
index 0000000..5e6a988
--- /dev/null
+++ b/Source/CMakeSourceDir.txt.in
@@ -0,0 +1 @@
+@CMake_SOURCE_DIR@
diff --git a/Source/CMakeVersion.bash b/Source/CMakeVersion.bash
new file mode 100755
index 0000000..853b0ca
--- /dev/null
+++ b/Source/CMakeVersion.bash
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+# Update the version component if it looks like a date or -f is given.
+if test "x$1" = "x-f"; then shift ; n='*' ; else n='\{8\}' ; fi
+if test "$#" -gt 0; then echo 1>&2 "usage: CMakeVersion.bash [-f]"; exit 1; fi
+sed -i -e '
+s/\(^set(CMake_VERSION_PATCH\) [0-9]'"$n"'\(.*\)/\1 '"$(date +%Y%m%d)"'\2/
+' "${BASH_SOURCE%/*}/CMakeVersion.cmake"
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
new file mode 100644
index 0000000..8930a5f
--- /dev/null
+++ b/Source/CMakeVersion.cmake
@@ -0,0 +1,84 @@
+# CMake version number components.
+set(CMake_VERSION_MAJOR 3)
+set(CMake_VERSION_MINOR 20)
+set(CMake_VERSION_PATCH 20210414)
+#set(CMake_VERSION_RC 0)
+set(CMake_VERSION_IS_DIRTY 0)
+
+# Start with the full version number used in tags. It has no dev info.
+set(CMake_VERSION
+ "${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}.${CMake_VERSION_PATCH}")
+if(DEFINED CMake_VERSION_RC)
+ set(CMake_VERSION "${CMake_VERSION}-rc${CMake_VERSION_RC}")
+endif()
+
+# Releases define a small patch level.
+if("${CMake_VERSION_PATCH}" VERSION_LESS 20000000)
+ set(CMake_VERSION_IS_RELEASE 1)
+else()
+ set(CMake_VERSION_IS_RELEASE 0)
+endif()
+
+if(NOT CMake_VERSION_NO_GIT)
+ # If this source was exported by 'git archive', use its commit info.
+ set(git_info [==[$Format:%h %s$]==])
+
+ # Otherwise, try to identify the current development source version.
+ if(NOT git_info MATCHES "^([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]?[0-9a-f]?)[0-9a-f]* "
+ AND EXISTS ${CMake_SOURCE_DIR}/.git)
+ find_package(Git QUIET)
+ if(GIT_FOUND)
+ macro(_git)
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} ${ARGN}
+ WORKING_DIRECTORY ${CMake_SOURCE_DIR}
+ RESULT_VARIABLE _git_res
+ OUTPUT_VARIABLE _git_out OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE _git_err ERROR_STRIP_TRAILING_WHITESPACE
+ )
+ endmacro()
+ endif()
+ if(COMMAND _git)
+ # Get the commit checked out in this work tree.
+ _git(log -n 1 HEAD "--pretty=format:%h %s" --)
+ set(git_info "${_git_out}")
+ endif()
+ endif()
+
+ # Extract commit information if available.
+ if(git_info MATCHES "^([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]?[0-9a-f]?)[0-9a-f]* (.*)$")
+ # Have commit information.
+ set(git_hash "${CMAKE_MATCH_1}")
+ set(git_subject "${CMAKE_MATCH_2}")
+
+ # If this is not the exact commit of a release, add dev info.
+ if(NOT "${git_subject}" MATCHES "^[Cc][Mm]ake ${CMake_VERSION}$")
+ set(CMake_VERSION "${CMake_VERSION}-g${git_hash}")
+ endif()
+
+ # If this is a work tree, check whether it is dirty.
+ if(COMMAND _git)
+ _git(update-index -q --refresh)
+ _git(diff-index --name-only HEAD --)
+ if(_git_out)
+ set(CMake_VERSION_IS_DIRTY 1)
+ endif()
+ endif()
+ else()
+ # No commit information.
+ if(NOT CMake_VERSION_IS_RELEASE)
+ # Generic development version.
+ set(CMake_VERSION "${CMake_VERSION}-git")
+ endif()
+ endif()
+endif()
+
+# Extract the version suffix component.
+if(CMake_VERSION MATCHES "-(.*)$")
+ set(CMake_VERSION_SUFFIX "${CMAKE_MATCH_1}")
+else()
+ set(CMake_VERSION_SUFFIX "")
+endif()
+if(CMake_VERSION_IS_DIRTY)
+ set(CMake_VERSION ${CMake_VERSION}-dirty)
+endif()
diff --git a/Source/CMakeVersion.rc.in b/Source/CMakeVersion.rc.in
new file mode 100644
index 0000000..762d9bb
--- /dev/null
+++ b/Source/CMakeVersion.rc.in
@@ -0,0 +1,28 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+1 VERSIONINFO
+FILEVERSION @CMake_RCVERSION@
+PRODUCTVERSION @CMake_RCVERSION@
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "FileVersion", "@CMake_RCVERSION_STR@\0"
+ VALUE "ProductVersion", "@CMake_RCVERSION_STR@\0"
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ /* The following line should only be modified for localized versions. */
+ /* It consists of any number of WORD,WORD pairs, with each pair */
+ /* describing a language,codepage combination supported by the file. */
+ /* */
+ /* For example, a file might have values "0x409,1252" indicating that it */
+ /* supports English language (0x409) in the Windows ANSI codepage (1252). */
+
+ VALUE "Translation", 0x409, 1252
+ END
+END
diff --git a/Source/CPack/IFW/cmCPackIFWCommon.cxx b/Source/CPack/IFW/cmCPackIFWCommon.cxx
new file mode 100644
index 0000000..87ebbfe
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWCommon.cxx
@@ -0,0 +1,137 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackIFWCommon.h"
+
+#include <cstddef> // IWYU pragma: keep
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include "cmCPackGenerator.h"
+#include "cmCPackIFWGenerator.h"
+#include "cmCPackLog.h" // IWYU pragma: keep
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTimestamp.h"
+#include "cmVersionConfig.h"
+#include "cmXMLWriter.h"
+
+cmCPackIFWCommon::cmCPackIFWCommon()
+ : Generator(nullptr)
+{
+}
+
+const char* cmCPackIFWCommon::GetOption(const std::string& op) const
+{
+ return this->Generator ? this->Generator->cmCPackGenerator::GetOption(op)
+ : nullptr;
+}
+
+bool cmCPackIFWCommon::IsOn(const std::string& op) const
+{
+ return this->Generator ? this->Generator->cmCPackGenerator::IsOn(op) : false;
+}
+
+bool cmCPackIFWCommon::IsSetToOff(const std::string& op) const
+{
+ return this->Generator ? this->Generator->cmCPackGenerator::IsSetToOff(op)
+ : false;
+}
+
+bool cmCPackIFWCommon::IsSetToEmpty(const std::string& op) const
+{
+ return this->Generator ? this->Generator->cmCPackGenerator::IsSetToEmpty(op)
+ : false;
+}
+
+bool cmCPackIFWCommon::IsVersionLess(const char* version) const
+{
+ if (!this->Generator) {
+ return false;
+ }
+
+ return cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->Generator->FrameworkVersion.data(), version);
+}
+
+bool cmCPackIFWCommon::IsVersionGreater(const char* version) const
+{
+ if (!this->Generator) {
+ return false;
+ }
+
+ return cmSystemTools::VersionCompare(
+ cmSystemTools::OP_GREATER, this->Generator->FrameworkVersion.data(),
+ version);
+}
+
+bool cmCPackIFWCommon::IsVersionEqual(const char* version) const
+{
+ if (!this->Generator) {
+ return false;
+ }
+
+ return cmSystemTools::VersionCompare(
+ cmSystemTools::OP_EQUAL, this->Generator->FrameworkVersion.data(),
+ version);
+}
+
+void cmCPackIFWCommon::ExpandListArgument(
+ const std::string& arg, std::map<std::string, std::string>& argsOut)
+{
+ std::vector<std::string> args = cmExpandedList(arg, false);
+ if (args.empty()) {
+ return;
+ }
+
+ std::size_t i = 0;
+ std::size_t c = args.size();
+ if (c % 2) {
+ argsOut[""] = args[i];
+ ++i;
+ }
+
+ --c;
+ for (; i < c; i += 2) {
+ argsOut[args[i]] = args[i + 1];
+ }
+}
+
+void cmCPackIFWCommon::ExpandListArgument(
+ const std::string& arg, std::multimap<std::string, std::string>& argsOut)
+{
+ std::vector<std::string> args = cmExpandedList(arg, false);
+ if (args.empty()) {
+ return;
+ }
+
+ std::size_t i = 0;
+ std::size_t c = args.size();
+ if (c % 2) {
+ argsOut.insert(std::pair<std::string, std::string>("", args[i]));
+ ++i;
+ }
+
+ --c;
+ for (; i < c; i += 2) {
+ argsOut.insert(std::pair<std::string, std::string>(args[i], args[i + 1]));
+ }
+}
+
+void cmCPackIFWCommon::WriteGeneratedByToStrim(cmXMLWriter& xout) const
+{
+ if (!this->Generator) {
+ return;
+ }
+
+ std::ostringstream comment;
+ comment << "Generated by CPack " << CMake_VERSION << " IFW generator "
+ << "for QtIFW ";
+ if (this->IsVersionEqual("1.9.9")) {
+ comment << "less 2.0";
+ } else {
+ comment << this->Generator->FrameworkVersion;
+ }
+ comment << " tools at " << cmTimestamp().CurrentTime("", true);
+ xout.Comment(comment.str().c_str());
+}
diff --git a/Source/CPack/IFW/cmCPackIFWCommon.h b/Source/CPack/IFW/cmCPackIFWCommon.h
new file mode 100644
index 0000000..42deda4
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWCommon.h
@@ -0,0 +1,78 @@
+/* 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 <map>
+#include <string>
+
+class cmCPackIFWGenerator;
+class cmXMLWriter;
+
+/** \class cmCPackIFWCommon
+ * \brief A base class for CPack IFW generator implementation subclasses
+ */
+class cmCPackIFWCommon
+{
+public:
+ // Constructor
+
+ /**
+ * Construct Part
+ */
+ cmCPackIFWCommon();
+
+public:
+ // Internal implementation
+
+ const char* GetOption(const std::string& op) const;
+ bool IsOn(const std::string& op) const;
+ bool IsSetToOff(const std::string& op) const;
+ bool IsSetToEmpty(const std::string& op) const;
+
+ /**
+ * Compare \a version with QtIFW framework version
+ */
+ bool IsVersionLess(const char* version) const;
+
+ /**
+ * Compare \a version with QtIFW framework version
+ */
+ bool IsVersionGreater(const char* version) const;
+
+ /**
+ * Compare \a version with QtIFW framework version
+ */
+ bool IsVersionEqual(const char* version) const;
+
+ /** Expand the list argument containing the map of the key-value pairs.
+ * If the number of elements is odd, then the first value is used as the
+ * default value with an empty key.
+ * Any values with the same keys will be permanently overwritten.
+ */
+ static void ExpandListArgument(const std::string& arg,
+ std::map<std::string, std::string>& argsOut);
+
+ /** Expand the list argument containing the multimap of the key-value pairs.
+ * If the number of elements is odd, then the first value is used as the
+ * default value with an empty key.
+ */
+ static void ExpandListArgument(
+ const std::string& arg, std::multimap<std::string, std::string>& argsOut);
+
+ cmCPackIFWGenerator* Generator;
+
+protected:
+ void WriteGeneratedByToStrim(cmXMLWriter& xout) const;
+};
+
+#define cmCPackIFWLogger(logType, msg) \
+ do { \
+ std::ostringstream cmCPackLog_msg; \
+ cmCPackLog_msg << msg; \
+ if (Generator) { \
+ Generator->Logger->Log(cmCPackLog::LOG_##logType, __FILE__, __LINE__, \
+ cmCPackLog_msg.str().c_str()); \
+ } \
+ } while (false)
diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
new file mode 100644
index 0000000..2806c61
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
@@ -0,0 +1,624 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackIFWGenerator.h"
+
+#include <sstream>
+#include <utility>
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackGenerator.h"
+#include "cmCPackIFWCommon.h"
+#include "cmCPackIFWInstaller.h"
+#include "cmCPackIFWPackage.h"
+#include "cmCPackIFWRepository.h"
+#include "cmCPackLog.h" // IWYU pragma: keep
+#include "cmDuration.h"
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmCPackIFWGenerator::cmCPackIFWGenerator()
+{
+ this->Generator = this;
+}
+
+cmCPackIFWGenerator::~cmCPackIFWGenerator() = default;
+
+int cmCPackIFWGenerator::PackageFiles()
+{
+ cmCPackIFWLogger(OUTPUT, "- Configuration" << std::endl);
+
+ // Installer configuragion
+ this->Installer.GenerateInstallerFile();
+
+ // Packages configuration
+ this->Installer.GeneratePackageFiles();
+
+ std::string ifwTLD = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ std::string ifwTmpFile = cmStrCat(ifwTLD, "/IFWOutput.log");
+
+ // Run repogen
+ if (!this->Installer.RemoteRepositories.empty()) {
+ std::vector<std::string> ifwCmd;
+ std::string ifwArg;
+
+ ifwCmd.emplace_back(this->RepoGen);
+
+ if (this->IsVersionLess("2.0.0")) {
+ ifwCmd.emplace_back("-c");
+ ifwCmd.emplace_back(this->toplevel + "/config/config.xml");
+ }
+
+ ifwCmd.emplace_back("-p");
+ ifwCmd.emplace_back(this->toplevel + "/packages");
+
+ if (!this->PkgsDirsVector.empty()) {
+ for (std::string const& it : this->PkgsDirsVector) {
+ ifwCmd.emplace_back("-p");
+ ifwCmd.emplace_back(it);
+ }
+ }
+
+ if (!this->RepoDirsVector.empty()) {
+ if (!this->IsVersionLess("3.1")) {
+ for (std::string const& rd : this->RepoDirsVector) {
+ ifwCmd.emplace_back("--repository");
+ ifwCmd.emplace_back(rd);
+ }
+ } else {
+ cmCPackIFWLogger(WARNING,
+ "The \"CPACK_IFW_REPOSITORIES_DIRECTORIES\" "
+ << "variable is set, but content will be skipped, "
+ << "because this feature available only since "
+ << "QtIFW 3.1. Please update your QtIFW instance."
+ << std::endl);
+ }
+ }
+
+ if (!this->OnlineOnly && !this->DownloadedPackages.empty()) {
+ ifwCmd.emplace_back("-i");
+ auto it = this->DownloadedPackages.begin();
+ ifwArg = (*it)->Name;
+ ++it;
+ while (it != this->DownloadedPackages.end()) {
+ ifwArg += "," + (*it)->Name;
+ ++it;
+ }
+ ifwCmd.emplace_back(ifwArg);
+ }
+ ifwCmd.emplace_back(this->toplevel + "/repository");
+ cmCPackIFWLogger(VERBOSE,
+ "Execute: " << cmSystemTools::PrintSingleCommand(ifwCmd)
+ << std::endl);
+ std::string output;
+ int retVal = 1;
+ cmCPackIFWLogger(OUTPUT, "- Generate repository" << std::endl);
+ bool res = cmSystemTools::RunSingleCommand(
+ ifwCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(ifwTmpFile);
+ ofs << "# Run command: " << cmSystemTools::PrintSingleCommand(ifwCmd)
+ << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackIFWLogger(
+ ERROR,
+ "Problem running IFW command: "
+ << cmSystemTools::PrintSingleCommand(ifwCmd) << std::endl
+ << "Please check \"" << ifwTmpFile << "\" for errors" << std::endl);
+ return 0;
+ }
+
+ if (!this->Repository.RepositoryUpdate.empty() &&
+ !this->Repository.PatchUpdatesXml()) {
+ cmCPackIFWLogger(WARNING,
+ "Problem patch IFW \"Updates\" "
+ << "file: \"" << this->toplevel
+ << "/repository/Updates.xml\"" << std::endl);
+ }
+
+ cmCPackIFWLogger(OUTPUT,
+ "- repository: \"" << this->toplevel
+ << "/repository\" generated"
+ << std::endl);
+ }
+
+ // Run binary creator
+ {
+ std::vector<std::string> ifwCmd;
+ std::string ifwArg;
+
+ ifwCmd.emplace_back(this->BinCreator);
+
+ ifwCmd.emplace_back("-c");
+ ifwCmd.emplace_back(this->toplevel + "/config/config.xml");
+
+ if (!this->Installer.Resources.empty()) {
+ ifwCmd.emplace_back("-r");
+ auto it = this->Installer.Resources.begin();
+ std::string path = this->toplevel + "/resources/";
+ ifwArg = path + *it;
+ ++it;
+ while (it != this->Installer.Resources.end()) {
+ ifwArg += "," + path + *it;
+ ++it;
+ }
+ ifwCmd.emplace_back(ifwArg);
+ }
+
+ ifwCmd.emplace_back("-p");
+ ifwCmd.emplace_back(this->toplevel + "/packages");
+
+ if (!this->PkgsDirsVector.empty()) {
+ for (std::string const& it : this->PkgsDirsVector) {
+ ifwCmd.emplace_back("-p");
+ ifwCmd.emplace_back(it);
+ }
+ }
+
+ if (!this->RepoDirsVector.empty()) {
+ if (!this->IsVersionLess("3.1")) {
+ for (std::string const& rd : this->RepoDirsVector) {
+ ifwCmd.emplace_back("--repository");
+ ifwCmd.emplace_back(rd);
+ }
+ } else {
+ cmCPackIFWLogger(WARNING,
+ "The \"CPACK_IFW_REPOSITORIES_DIRECTORIES\" "
+ << "variable is set, but content will be skipped, "
+ << "because this feature available only since "
+ << "QtIFW 3.1. Please update your QtIFW instance."
+ << std::endl);
+ }
+ }
+
+ if (this->OnlineOnly) {
+ ifwCmd.emplace_back("--online-only");
+ } else if (!this->DownloadedPackages.empty() &&
+ !this->Installer.RemoteRepositories.empty()) {
+ ifwCmd.emplace_back("-e");
+ auto it = this->DownloadedPackages.begin();
+ ifwArg = (*it)->Name;
+ ++it;
+ while (it != this->DownloadedPackages.end()) {
+ ifwArg += "," + (*it)->Name;
+ ++it;
+ }
+ ifwCmd.emplace_back(ifwArg);
+ } else if (!this->DependentPackages.empty()) {
+ ifwCmd.emplace_back("-i");
+ ifwArg.clear();
+ // Binary
+ auto bit = this->BinaryPackages.begin();
+ while (bit != this->BinaryPackages.end()) {
+ ifwArg += (*bit)->Name + ",";
+ ++bit;
+ }
+ // Depend
+ auto it = this->DependentPackages.begin();
+ ifwArg += it->second.Name;
+ ++it;
+ while (it != this->DependentPackages.end()) {
+ ifwArg += "," + it->second.Name;
+ ++it;
+ }
+ ifwCmd.emplace_back(ifwArg);
+ }
+ // TODO: set correct name for multipackages
+ if (!this->packageFileNames.empty()) {
+ ifwCmd.emplace_back(this->packageFileNames[0]);
+ } else {
+ ifwCmd.emplace_back("installer" + this->OutputExtension);
+ }
+ cmCPackIFWLogger(VERBOSE,
+ "Execute: " << cmSystemTools::PrintSingleCommand(ifwCmd)
+ << std::endl);
+ std::string output;
+ int retVal = 1;
+ cmCPackIFWLogger(OUTPUT, "- Generate package" << std::endl);
+ bool res = cmSystemTools::RunSingleCommand(
+ ifwCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(ifwTmpFile);
+ ofs << "# Run command: " << cmSystemTools::PrintSingleCommand(ifwCmd)
+ << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackIFWLogger(
+ ERROR,
+ "Problem running IFW command: "
+ << cmSystemTools::PrintSingleCommand(ifwCmd) << std::endl
+ << "Please check \"" << ifwTmpFile << "\" for errors" << std::endl);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+const char* cmCPackIFWGenerator::GetPackagingInstallPrefix()
+{
+ const char* defPrefix = this->cmCPackGenerator::GetPackagingInstallPrefix();
+
+ std::string tmpPref = defPrefix ? defPrefix : "";
+
+ if (this->Components.empty()) {
+ tmpPref += "packages/" + this->GetRootPackageName() + "/data";
+ }
+
+ this->SetOption("CPACK_IFW_PACKAGING_INSTALL_PREFIX", tmpPref.c_str());
+
+ return this->GetOption("CPACK_IFW_PACKAGING_INSTALL_PREFIX");
+}
+
+const char* cmCPackIFWGenerator::GetOutputExtension()
+{
+ return this->OutputExtension.c_str();
+}
+
+int cmCPackIFWGenerator::InitializeInternal()
+{
+ // Search Qt Installer Framework tools
+
+ const std::string BinCreatorOpt = "CPACK_IFW_BINARYCREATOR_EXECUTABLE";
+ const std::string RepoGenOpt = "CPACK_IFW_REPOGEN_EXECUTABLE";
+ const std::string FrameworkVersionOpt = "CPACK_IFW_FRAMEWORK_VERSION";
+
+ if (!this->IsSet(BinCreatorOpt) || !this->IsSet(RepoGenOpt) ||
+ !this->IsSet(FrameworkVersionOpt)) {
+ this->ReadListFile("CPackIFW.cmake");
+ }
+
+ // Look 'binarycreator' executable (needs)
+
+ const char* BinCreatorStr = this->GetOption(BinCreatorOpt);
+ if (!BinCreatorStr || cmIsNOTFOUND(BinCreatorStr)) {
+ this->BinCreator.clear();
+ } else {
+ this->BinCreator = BinCreatorStr;
+ }
+
+ if (this->BinCreator.empty()) {
+ cmCPackIFWLogger(ERROR,
+ "Cannot find QtIFW compiler \"binarycreator\": "
+ "likely it is not installed, or not in your PATH"
+ << std::endl);
+ return 0;
+ }
+
+ // Look 'repogen' executable (optional)
+
+ const char* RepoGenStr = this->GetOption(RepoGenOpt);
+ if (!RepoGenStr || cmIsNOTFOUND(RepoGenStr)) {
+ this->RepoGen.clear();
+ } else {
+ this->RepoGen = RepoGenStr;
+ }
+
+ // Framework version
+ if (const char* FrameworkVersionSrt = this->GetOption(FrameworkVersionOpt)) {
+ this->FrameworkVersion = FrameworkVersionSrt;
+ } else {
+ this->FrameworkVersion = "1.9.9";
+ }
+
+ // Variables that Change Behavior
+
+ // Resolve duplicate names
+ this->ResolveDuplicateNames =
+ this->IsOn("CPACK_IFW_RESOLVE_DUPLICATE_NAMES");
+
+ // Additional packages dirs
+ this->PkgsDirsVector.clear();
+ if (const char* dirs = this->GetOption("CPACK_IFW_PACKAGES_DIRECTORIES")) {
+ cmExpandList(dirs, this->PkgsDirsVector);
+ }
+
+ // Additional repositories dirs
+ this->RepoDirsVector.clear();
+ if (const char* dirs =
+ this->GetOption("CPACK_IFW_REPOSITORIES_DIRECTORIES")) {
+ cmExpandList(dirs, this->RepoDirsVector);
+ }
+
+ // Installer
+ this->Installer.Generator = this;
+ this->Installer.ConfigureFromOptions();
+
+ // Repository
+ this->Repository.Generator = this;
+ this->Repository.Name = "Unspecified";
+ if (const char* site = this->GetOption("CPACK_DOWNLOAD_SITE")) {
+ this->Repository.Url = site;
+ this->Installer.RemoteRepositories.push_back(&this->Repository);
+ }
+
+ // Repositories
+ if (const char* RepoAllStr = this->GetOption("CPACK_IFW_REPOSITORIES_ALL")) {
+ std::vector<std::string> RepoAllVector = cmExpandedList(RepoAllStr);
+ for (std::string const& r : RepoAllVector) {
+ this->GetRepository(r);
+ }
+ }
+
+ if (const char* ifwDownloadAll = this->GetOption("CPACK_IFW_DOWNLOAD_ALL")) {
+ this->OnlineOnly = cmIsOn(ifwDownloadAll);
+ } else if (const char* cpackDownloadAll =
+ this->GetOption("CPACK_DOWNLOAD_ALL")) {
+ this->OnlineOnly = cmIsOn(cpackDownloadAll);
+ } else {
+ this->OnlineOnly = false;
+ }
+
+ if (!this->Installer.RemoteRepositories.empty() && this->RepoGen.empty()) {
+ cmCPackIFWLogger(ERROR,
+ "Cannot find QtIFW repository generator \"repogen\": "
+ "likely it is not installed, or not in your PATH"
+ << std::endl);
+ return 0;
+ }
+
+ // Executable suffix
+ std::string exeSuffix(this->GetOption("CMAKE_EXECUTABLE_SUFFIX"));
+ std::string sysName(this->GetOption("CMAKE_SYSTEM_NAME"));
+ if (sysName == "Linux") {
+ this->ExecutableSuffix = ".run";
+ } else if (sysName == "Windows") {
+ this->ExecutableSuffix = ".exe";
+ } else if (sysName == "Darwin") {
+ this->ExecutableSuffix = ".app";
+ } else {
+ this->ExecutableSuffix = exeSuffix;
+ }
+
+ // Output extension
+ if (const char* optOutExt =
+ this->GetOption("CPACK_IFW_PACKAGE_FILE_EXTENSION")) {
+ this->OutputExtension = optOutExt;
+ } else if (sysName == "Darwin") {
+ this->OutputExtension = ".dmg";
+ } else {
+ this->OutputExtension = this->ExecutableSuffix;
+ }
+ if (this->OutputExtension.empty()) {
+ this->OutputExtension = this->cmCPackGenerator::GetOutputExtension();
+ }
+
+ return this->Superclass::InitializeInternal();
+}
+
+std::string cmCPackIFWGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ const std::string prefix = "packages/";
+ const std::string suffix = "/data";
+
+ if (this->componentPackageMethod == this->ONE_PACKAGE) {
+ return std::string(prefix + this->GetRootPackageName() + suffix);
+ }
+
+ return prefix +
+ this->GetComponentPackageName(&this->Components[componentName]) + suffix;
+}
+
+cmCPackComponent* cmCPackIFWGenerator::GetComponent(
+ const std::string& projectName, const std::string& componentName)
+{
+ auto cit = this->Components.find(componentName);
+ if (cit != this->Components.end()) {
+ return &(cit->second);
+ }
+
+ cmCPackComponent* component =
+ this->cmCPackGenerator::GetComponent(projectName, componentName);
+ if (!component) {
+ return component;
+ }
+
+ std::string name = this->GetComponentPackageName(component);
+ auto pit = this->Packages.find(name);
+ if (pit != this->Packages.end()) {
+ return component;
+ }
+
+ cmCPackIFWPackage* package = &this->Packages[name];
+ package->Name = name;
+ package->Generator = this;
+ if (package->ConfigureFromComponent(component)) {
+ package->Installer = &this->Installer;
+ this->Installer.Packages.insert(
+ std::pair<std::string, cmCPackIFWPackage*>(name, package));
+ this->ComponentPackages.insert(
+ std::pair<cmCPackComponent*, cmCPackIFWPackage*>(component, package));
+ if (component->IsDownloaded) {
+ this->DownloadedPackages.insert(package);
+ } else {
+ this->BinaryPackages.insert(package);
+ }
+ } else {
+ this->Packages.erase(name);
+ cmCPackIFWLogger(ERROR,
+ "Cannot configure package \""
+ << name << "\" for component \"" << component->Name
+ << "\"" << std::endl);
+ }
+
+ return component;
+}
+
+cmCPackComponentGroup* cmCPackIFWGenerator::GetComponentGroup(
+ const std::string& projectName, const std::string& groupName)
+{
+ cmCPackComponentGroup* group =
+ this->cmCPackGenerator::GetComponentGroup(projectName, groupName);
+ if (!group) {
+ return group;
+ }
+
+ std::string name = this->GetGroupPackageName(group);
+ auto pit = this->Packages.find(name);
+ if (pit != this->Packages.end()) {
+ return group;
+ }
+
+ cmCPackIFWPackage* package = &this->Packages[name];
+ package->Name = name;
+ package->Generator = this;
+ if (package->ConfigureFromGroup(group)) {
+ package->Installer = &this->Installer;
+ this->Installer.Packages.insert(
+ std::pair<std::string, cmCPackIFWPackage*>(name, package));
+ this->GroupPackages.insert(
+ std::pair<cmCPackComponentGroup*, cmCPackIFWPackage*>(group, package));
+ this->BinaryPackages.insert(package);
+ } else {
+ this->Packages.erase(name);
+ cmCPackIFWLogger(ERROR,
+ "Cannot configure package \""
+ << name << "\" for component group \"" << group->Name
+ << "\"" << std::endl);
+ }
+ return group;
+}
+
+enum cmCPackGenerator::CPackSetDestdirSupport
+cmCPackIFWGenerator::SupportsSetDestdir() const
+{
+ return cmCPackGenerator::SETDESTDIR_SHOULD_NOT_BE_USED;
+}
+
+bool cmCPackIFWGenerator::SupportsAbsoluteDestination() const
+{
+ return false;
+}
+
+bool cmCPackIFWGenerator::SupportsComponentInstallation() const
+{
+ return true;
+}
+
+bool cmCPackIFWGenerator::IsOnePackage() const
+{
+ return this->componentPackageMethod == cmCPackGenerator::ONE_PACKAGE;
+}
+
+std::string cmCPackIFWGenerator::GetRootPackageName()
+{
+ // Default value
+ std::string name = "root";
+ if (const char* optIFW_PACKAGE_GROUP =
+ this->GetOption("CPACK_IFW_PACKAGE_GROUP")) {
+ // Configure from root group
+ cmCPackIFWPackage package;
+ package.Generator = this;
+ package.ConfigureFromGroup(optIFW_PACKAGE_GROUP);
+ name = package.Name;
+ } else if (const char* optIFW_PACKAGE_NAME =
+ this->GetOption("CPACK_IFW_PACKAGE_NAME")) {
+ // Configure from root package name
+ name = optIFW_PACKAGE_NAME;
+ } else if (const char* optPACKAGE_NAME =
+ this->GetOption("CPACK_PACKAGE_NAME")) {
+ // Configure from package name
+ name = optPACKAGE_NAME;
+ }
+ return name;
+}
+
+std::string cmCPackIFWGenerator::GetGroupPackageName(
+ cmCPackComponentGroup* group) const
+{
+ std::string name;
+ if (!group) {
+ return name;
+ }
+ if (cmCPackIFWPackage* package = this->GetGroupPackage(group)) {
+ return package->Name;
+ }
+ const char* option =
+ this->GetOption("CPACK_IFW_COMPONENT_GROUP_" +
+ cmsys::SystemTools::UpperCase(group->Name) + "_NAME");
+ name = option ? option : group->Name;
+ if (group->ParentGroup) {
+ cmCPackIFWPackage* package = this->GetGroupPackage(group->ParentGroup);
+ bool dot = !this->ResolveDuplicateNames;
+ if (dot && !cmHasPrefix(name, package->Name)) {
+ name = package->Name + "." + name;
+ }
+ }
+ return name;
+}
+
+std::string cmCPackIFWGenerator::GetComponentPackageName(
+ cmCPackComponent* component) const
+{
+ std::string name;
+ if (!component) {
+ return name;
+ }
+ if (cmCPackIFWPackage* package = this->GetComponentPackage(component)) {
+ return package->Name;
+ }
+ std::string prefix = "CPACK_IFW_COMPONENT_" +
+ cmsys::SystemTools::UpperCase(component->Name) + "_";
+ const char* option = this->GetOption(prefix + "NAME");
+ name = option ? option : component->Name;
+ if (component->Group) {
+ cmCPackIFWPackage* package = this->GetGroupPackage(component->Group);
+ if ((this->componentPackageMethod ==
+ cmCPackGenerator::ONE_PACKAGE_PER_GROUP) ||
+ this->IsOn(prefix + "COMMON")) {
+ return package->Name;
+ }
+ bool dot = !this->ResolveDuplicateNames;
+ if (dot && !cmHasPrefix(name, package->Name)) {
+ name = package->Name + "." + name;
+ }
+ }
+ return name;
+}
+
+cmCPackIFWPackage* cmCPackIFWGenerator::GetGroupPackage(
+ cmCPackComponentGroup* group) const
+{
+ auto pit = this->GroupPackages.find(group);
+ return pit != this->GroupPackages.end() ? pit->second : nullptr;
+}
+
+cmCPackIFWPackage* cmCPackIFWGenerator::GetComponentPackage(
+ cmCPackComponent* component) const
+{
+ auto pit = this->ComponentPackages.find(component);
+ return pit != this->ComponentPackages.end() ? pit->second : nullptr;
+}
+
+cmCPackIFWRepository* cmCPackIFWGenerator::GetRepository(
+ const std::string& repositoryName)
+{
+ auto rit = this->Repositories.find(repositoryName);
+ if (rit != this->Repositories.end()) {
+ return &(rit->second);
+ }
+
+ cmCPackIFWRepository* repository = &this->Repositories[repositoryName];
+ repository->Name = repositoryName;
+ repository->Generator = this;
+ if (repository->ConfigureFromOptions()) {
+ if (repository->Update == cmCPackIFWRepository::None) {
+ this->Installer.RemoteRepositories.push_back(repository);
+ } else {
+ this->Repository.RepositoryUpdate.push_back(repository);
+ }
+ } else {
+ this->Repositories.erase(repositoryName);
+ repository = nullptr;
+ cmCPackIFWLogger(WARNING,
+ "Invalid repository \""
+ << repositoryName << "\""
+ << " configuration. Repository will be skipped."
+ << std::endl);
+ }
+ return repository;
+}
diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.h b/Source/CPack/IFW/cmCPackIFWGenerator.h
new file mode 100644
index 0000000..024d25d
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWGenerator.h
@@ -0,0 +1,153 @@
+/* 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 <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackGenerator.h"
+#include "cmCPackIFWCommon.h"
+#include "cmCPackIFWInstaller.h"
+#include "cmCPackIFWPackage.h"
+#include "cmCPackIFWRepository.h"
+
+/** \class cmCPackIFWGenerator
+ * \brief A generator for Qt Installer Framework tools
+ *
+ * http://qt-project.org/doc/qtinstallerframework/index.html
+ */
+class cmCPackIFWGenerator
+ : public cmCPackGenerator
+ , public cmCPackIFWCommon
+{
+public:
+ cmCPackTypeMacro(cmCPackIFWGenerator, cmCPackGenerator);
+
+ using PackagesMap = std::map<std::string, cmCPackIFWPackage>;
+ using RepositoriesMap = std::map<std::string, cmCPackIFWRepository>;
+ using ComponentsMap = std::map<std::string, cmCPackComponent>;
+ using ComponentGoupsMap = std::map<std::string, cmCPackComponentGroup>;
+ using DependenceMap =
+ std::map<std::string, cmCPackIFWPackage::DependenceStruct>;
+
+ using cmCPackIFWCommon::GetOption;
+ using cmCPackIFWCommon::IsOn;
+ using cmCPackIFWCommon::IsSetToOff;
+ using cmCPackIFWCommon::IsSetToEmpty;
+
+ /**
+ * Construct IFW generator
+ */
+ cmCPackIFWGenerator();
+
+ /**
+ * Destruct IFW generator
+ */
+ ~cmCPackIFWGenerator() override;
+
+protected:
+ // cmCPackGenerator reimplementation
+
+ /**
+ * @brief Initialize generator
+ * @return 0 on failure
+ */
+ int InitializeInternal() override;
+ int PackageFiles() override;
+ const char* GetPackagingInstallPrefix() override;
+
+ /**
+ * @brief Target binary extension
+ * @return Executable suffix or disk image format
+ */
+ const char* GetOutputExtension() override;
+
+ std::string GetComponentInstallDirNameSuffix(
+ const std::string& componentName) override;
+
+ /**
+ * @brief Get Component
+ * @param projectName Project name
+ * @param componentName Component name
+ *
+ * This method calls the base implementation.
+ *
+ * @return Pointer to component
+ */
+ cmCPackComponent* GetComponent(const std::string& projectName,
+ const std::string& componentName) override;
+
+ /**
+ * @brief Get group of component
+ * @param projectName Project name
+ * @param groupName Component group name
+ *
+ * This method calls the base implementation.
+ *
+ * @return Pointer to component group
+ */
+ cmCPackComponentGroup* GetComponentGroup(
+ const std::string& projectName, const std::string& groupName) override;
+
+ enum cmCPackGenerator::CPackSetDestdirSupport SupportsSetDestdir()
+ const override;
+ bool SupportsAbsoluteDestination() const override;
+ bool SupportsComponentInstallation() const override;
+
+protected:
+ // Methods
+
+ bool IsOnePackage() const;
+
+ std::string GetRootPackageName();
+
+ std::string GetGroupPackageName(cmCPackComponentGroup* group) const;
+ std::string GetComponentPackageName(cmCPackComponent* component) const;
+
+ cmCPackIFWPackage* GetGroupPackage(cmCPackComponentGroup* group) const;
+ cmCPackIFWPackage* GetComponentPackage(cmCPackComponent* component) const;
+
+ cmCPackIFWRepository* GetRepository(const std::string& repositoryName);
+
+protected:
+ // Data
+
+ friend class cmCPackIFWPackage;
+ friend class cmCPackIFWCommon;
+ friend class cmCPackIFWInstaller;
+ friend class cmCPackIFWRepository;
+
+ // Installer
+ cmCPackIFWInstaller Installer;
+ // Repository
+ cmCPackIFWRepository Repository;
+ // Collection of packages
+ PackagesMap Packages;
+ // Collection of repositories
+ RepositoriesMap Repositories;
+ // Collection of binary packages
+ std::set<cmCPackIFWPackage*> BinaryPackages;
+ // Collection of downloaded packages
+ std::set<cmCPackIFWPackage*> DownloadedPackages;
+ // Dependent packages
+ DependenceMap DependentPackages;
+ std::map<cmCPackComponent*, cmCPackIFWPackage*> ComponentPackages;
+ std::map<cmCPackComponentGroup*, cmCPackIFWPackage*> GroupPackages;
+
+private:
+ std::string RepoGen;
+ std::string BinCreator;
+ std::string FrameworkVersion;
+ std::string ExecutableSuffix;
+ std::string OutputExtension;
+
+ bool OnlineOnly;
+ bool ResolveDuplicateNames;
+ std::vector<std::string> PkgsDirsVector;
+ std::vector<std::string> RepoDirsVector;
+};
diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.cxx b/Source/CPack/IFW/cmCPackIFWInstaller.cxx
new file mode 100644
index 0000000..bf8b457
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWInstaller.cxx
@@ -0,0 +1,563 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackIFWInstaller.h"
+
+#include <cstddef>
+#include <sstream>
+#include <utility>
+
+#include "cmCPackIFWCommon.h"
+#include "cmCPackIFWGenerator.h"
+#include "cmCPackIFWPackage.h"
+#include "cmCPackIFWRepository.h"
+#include "cmCPackLog.h" // IWYU pragma: keep
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include "cmXMLWriter.h"
+
+cmCPackIFWInstaller::cmCPackIFWInstaller() = default;
+
+void cmCPackIFWInstaller::printSkippedOptionWarning(
+ const std::string& optionName, const std::string& optionValue)
+{
+ cmCPackIFWLogger(
+ WARNING,
+ "Option "
+ << optionName << " is set to \"" << optionValue
+ << "\" but will be skipped because the specified file does not exist."
+ << std::endl);
+}
+
+void cmCPackIFWInstaller::ConfigureFromOptions()
+{
+ // Name;
+ if (const char* optIFW_PACKAGE_NAME =
+ this->GetOption("CPACK_IFW_PACKAGE_NAME")) {
+ this->Name = optIFW_PACKAGE_NAME;
+ } else if (const char* optPACKAGE_NAME =
+ this->GetOption("CPACK_PACKAGE_NAME")) {
+ this->Name = optPACKAGE_NAME;
+ } else {
+ this->Name = "Your package";
+ }
+
+ // Title;
+ if (const char* optIFW_PACKAGE_TITLE =
+ this->GetOption("CPACK_IFW_PACKAGE_TITLE")) {
+ this->Title = optIFW_PACKAGE_TITLE;
+ } else if (const char* optPACKAGE_DESCRIPTION_SUMMARY =
+ this->GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY")) {
+ this->Title = optPACKAGE_DESCRIPTION_SUMMARY;
+ } else {
+ this->Title = "Your package description";
+ }
+
+ // Version;
+ if (const char* option = this->GetOption("CPACK_PACKAGE_VERSION")) {
+ this->Version = option;
+ } else {
+ this->Version = "1.0.0";
+ }
+
+ // Publisher
+ if (const char* optIFW_PACKAGE_PUBLISHER =
+ this->GetOption("CPACK_IFW_PACKAGE_PUBLISHER")) {
+ this->Publisher = optIFW_PACKAGE_PUBLISHER;
+ } else if (const char* optPACKAGE_VENDOR =
+ this->GetOption("CPACK_PACKAGE_VENDOR")) {
+ this->Publisher = optPACKAGE_VENDOR;
+ }
+
+ // ProductUrl
+ if (const char* option = this->GetOption("CPACK_IFW_PRODUCT_URL")) {
+ this->ProductUrl = option;
+ }
+
+ // ApplicationIcon
+ if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_ICON")) {
+ if (cmSystemTools::FileExists(option)) {
+ this->InstallerApplicationIcon = option;
+ } else {
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_ICON", option);
+ }
+ }
+
+ // WindowIcon
+ if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_WINDOW_ICON")) {
+ if (cmSystemTools::FileExists(option)) {
+ this->InstallerWindowIcon = option;
+ } else {
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_WINDOW_ICON", option);
+ }
+ }
+
+ // RemoveTargetDir
+ if (this->IsSetToOff("CPACK_IFW_PACKAGE_REMOVE_TARGET_DIR")) {
+ this->RemoveTargetDir = "false";
+ } else if (this->IsOn("CPACK_IFW_PACKAGE_REMOVE_TARGET_DIR")) {
+ this->RemoveTargetDir = "true";
+ } else {
+ this->RemoveTargetDir.clear();
+ }
+
+ // Logo
+ if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_LOGO")) {
+ if (cmSystemTools::FileExists(option)) {
+ this->Logo = option;
+ } else {
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_LOGO", option);
+ }
+ }
+
+ // Watermark
+ if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_WATERMARK")) {
+ if (cmSystemTools::FileExists(option)) {
+ this->Watermark = option;
+ } else {
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_WATERMARK", option);
+ }
+ }
+
+ // Banner
+ if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_BANNER")) {
+ if (cmSystemTools::FileExists(option)) {
+ this->Banner = option;
+ } else {
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_BANNER", option);
+ }
+ }
+
+ // Background
+ if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_BACKGROUND")) {
+ if (cmSystemTools::FileExists(option)) {
+ this->Background = option;
+ } else {
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_BACKGROUND", option);
+ }
+ }
+
+ // WizardStyle
+ if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_WIZARD_STYLE")) {
+ // Setting the user value in any case
+ this->WizardStyle = option;
+ // Check known values
+ if (this->WizardStyle != "Modern" && this->WizardStyle != "Aero" &&
+ this->WizardStyle != "Mac" && this->WizardStyle != "Classic") {
+ cmCPackIFWLogger(
+ WARNING,
+ "Option CPACK_IFW_PACKAGE_WIZARD_STYLE has unknown value \""
+ << option << "\". Expected values are: Modern, Aero, Mac, Classic."
+ << std::endl);
+ }
+ }
+
+ // StyleSheet
+ if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_STYLE_SHEET")) {
+ if (cmSystemTools::FileExists(option)) {
+ this->StyleSheet = option;
+ } else {
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_STYLE_SHEET", option);
+ }
+ }
+
+ // WizardDefaultWidth
+ if (const char* option =
+ this->GetOption("CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH")) {
+ this->WizardDefaultWidth = option;
+ }
+
+ // WizardDefaultHeight
+ if (const char* option =
+ this->GetOption("CPACK_IFW_PACKAGE_WIZARD_DEFAULT_HEIGHT")) {
+ this->WizardDefaultHeight = option;
+ }
+
+ // WizardShowPageList
+ if (const char* option =
+ this->GetOption("CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST")) {
+ if (!this->IsVersionLess("4.0")) {
+ if (this->IsSetToOff("CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST")) {
+ this->WizardShowPageList = "false";
+ } else if (this->IsOn("CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST")) {
+ this->WizardShowPageList = "true";
+ } else {
+ this->WizardShowPageList.clear();
+ }
+ } else {
+ std::string currentVersionMsg;
+ if (this->Generator) {
+ currentVersionMsg =
+ "QtIFW version " + this->Generator->FrameworkVersion;
+ } else {
+ currentVersionMsg = "an older QtIFW version";
+ }
+ cmCPackIFWLogger(
+ WARNING,
+ "Option CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST is set to \""
+ << option
+ << "\", but it is only supported with QtIFW version 4.0 or later. "
+ "It is being ignored because you are using "
+ << currentVersionMsg << std::endl);
+ }
+ }
+
+ // TitleColor
+ if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_TITLE_COLOR")) {
+ this->TitleColor = option;
+ }
+
+ // Start menu
+ if (const char* optIFW_START_MENU_DIR =
+ this->GetOption("CPACK_IFW_PACKAGE_START_MENU_DIRECTORY")) {
+ this->StartMenuDir = optIFW_START_MENU_DIR;
+ } else {
+ this->StartMenuDir = this->Name;
+ }
+
+ // Default target directory for installation
+ if (const char* optIFW_TARGET_DIRECTORY =
+ this->GetOption("CPACK_IFW_TARGET_DIRECTORY")) {
+ this->TargetDir = optIFW_TARGET_DIRECTORY;
+ } else if (const char* optPACKAGE_INSTALL_DIRECTORY =
+ this->GetOption("CPACK_PACKAGE_INSTALL_DIRECTORY")) {
+ this->TargetDir =
+ cmStrCat("@ApplicationsDir@/", optPACKAGE_INSTALL_DIRECTORY);
+ } else {
+ this->TargetDir = "@RootDir@/usr/local";
+ }
+
+ // Default target directory for installation with administrator rights
+ if (const char* option =
+ this->GetOption("CPACK_IFW_ADMIN_TARGET_DIRECTORY")) {
+ this->AdminTargetDir = option;
+ }
+
+ // Maintenance tool
+ if (const char* optIFW_MAINTENANCE_TOOL =
+ this->GetOption("CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_NAME")) {
+ this->MaintenanceToolName = optIFW_MAINTENANCE_TOOL;
+ }
+
+ // Maintenance tool ini file
+ if (const char* optIFW_MAINTENANCE_TOOL_INI =
+ this->GetOption("CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_INI_FILE")) {
+ this->MaintenanceToolIniFile = optIFW_MAINTENANCE_TOOL_INI;
+ }
+
+ // Allow non-ASCII characters
+ if (this->GetOption("CPACK_IFW_PACKAGE_ALLOW_NON_ASCII_CHARACTERS")) {
+ if (this->IsOn("CPACK_IFW_PACKAGE_ALLOW_NON_ASCII_CHARACTERS")) {
+ this->AllowNonAsciiCharacters = "true";
+ } else {
+ this->AllowNonAsciiCharacters = "false";
+ }
+ }
+
+ // Space in path
+ if (this->GetOption("CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH")) {
+ if (this->IsOn("CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH")) {
+ this->AllowSpaceInPath = "true";
+ } else {
+ this->AllowSpaceInPath = "false";
+ }
+ }
+
+ // Control script
+ if (const char* optIFW_CONTROL_SCRIPT =
+ this->GetOption("CPACK_IFW_PACKAGE_CONTROL_SCRIPT")) {
+ this->ControlScript = optIFW_CONTROL_SCRIPT;
+ }
+
+ // Resources
+ if (const char* optIFW_PACKAGE_RESOURCES =
+ this->GetOption("CPACK_IFW_PACKAGE_RESOURCES")) {
+ this->Resources.clear();
+ cmExpandList(optIFW_PACKAGE_RESOURCES, this->Resources);
+ }
+}
+
+/** \class cmCPackIFWResourcesParser
+ * \brief Helper class that parse resources form .qrc (Qt)
+ */
+class cmCPackIFWResourcesParser : public cmXMLParser
+{
+public:
+ explicit cmCPackIFWResourcesParser(cmCPackIFWInstaller* i)
+ : installer(i)
+ {
+ this->path = i->Directory + "/resources";
+ }
+
+ bool ParseResource(size_t r)
+ {
+ this->hasFiles = false;
+ this->hasErrors = false;
+
+ this->basePath =
+ cmSystemTools::GetFilenamePath(this->installer->Resources[r]);
+
+ this->ParseFile(this->installer->Resources[r].data());
+
+ return this->hasFiles && !this->hasErrors;
+ }
+
+ cmCPackIFWInstaller* installer;
+ bool file = false;
+ bool hasFiles = false;
+ bool hasErrors = false;
+ std::string path, basePath;
+
+protected:
+ void StartElement(const std::string& name, const char** /*atts*/) override
+ {
+ this->file = name == "file";
+ if (this->file) {
+ this->hasFiles = true;
+ }
+ }
+
+ void CharacterDataHandler(const char* data, int length) override
+ {
+ if (this->file) {
+ std::string content(data, data + length);
+ content = cmTrimWhitespace(content);
+ std::string source = this->basePath + "/" + content;
+ std::string destination = this->path + "/" + content;
+ if (!cmSystemTools::CopyFileIfDifferent(source, destination)) {
+ this->hasErrors = true;
+ }
+ }
+ }
+
+ void EndElement(const std::string& /*name*/) override {}
+};
+
+void cmCPackIFWInstaller::GenerateInstallerFile()
+{
+ // Lazy directory initialization
+ if (this->Directory.empty() && this->Generator) {
+ this->Directory = this->Generator->toplevel;
+ }
+
+ // Output stream
+ cmGeneratedFileStream fout(this->Directory + "/config/config.xml");
+ cmXMLWriter xout(fout);
+
+ xout.StartDocument();
+
+ this->WriteGeneratedByToStrim(xout);
+
+ xout.StartElement("Installer");
+
+ xout.Element("Name", this->Name);
+ xout.Element("Version", this->Version);
+ xout.Element("Title", this->Title);
+
+ if (!this->Publisher.empty()) {
+ xout.Element("Publisher", this->Publisher);
+ }
+
+ if (!this->ProductUrl.empty()) {
+ xout.Element("ProductUrl", this->ProductUrl);
+ }
+
+ // ApplicationIcon
+ if (!this->InstallerApplicationIcon.empty()) {
+ std::string name =
+ cmSystemTools::GetFilenameName(this->InstallerApplicationIcon);
+ std::string path = this->Directory + "/config/" + name;
+ name = cmSystemTools::GetFilenameWithoutExtension(name);
+ cmsys::SystemTools::CopyFileIfDifferent(this->InstallerApplicationIcon,
+ path);
+ xout.Element("InstallerApplicationIcon", name);
+ }
+
+ // WindowIcon
+ if (!this->InstallerWindowIcon.empty()) {
+ std::string name =
+ cmSystemTools::GetFilenameName(this->InstallerWindowIcon);
+ std::string path = this->Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(this->InstallerWindowIcon, path);
+ xout.Element("InstallerWindowIcon", name);
+ }
+
+ // Logo
+ if (!this->Logo.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(this->Logo);
+ std::string path = this->Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(this->Logo, path);
+ xout.Element("Logo", name);
+ }
+
+ // Banner
+ if (!this->Banner.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(this->Banner);
+ std::string path = this->Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(this->Banner, path);
+ xout.Element("Banner", name);
+ }
+
+ // Watermark
+ if (!this->Watermark.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(this->Watermark);
+ std::string path = this->Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(this->Watermark, path);
+ xout.Element("Watermark", name);
+ }
+
+ // Background
+ if (!this->Background.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(this->Background);
+ std::string path = this->Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(this->Background, path);
+ xout.Element("Background", name);
+ }
+
+ // WizardStyle
+ if (!this->WizardStyle.empty()) {
+ xout.Element("WizardStyle", this->WizardStyle);
+ }
+
+ // Stylesheet
+ if (!this->StyleSheet.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(this->StyleSheet);
+ std::string path = this->Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(this->StyleSheet, path);
+ xout.Element("StyleSheet", name);
+ }
+
+ // WizardDefaultWidth
+ if (!this->WizardDefaultWidth.empty()) {
+ xout.Element("WizardDefaultWidth", this->WizardDefaultWidth);
+ }
+
+ // WizardDefaultHeight
+ if (!this->WizardDefaultHeight.empty()) {
+ xout.Element("WizardDefaultHeight", this->WizardDefaultHeight);
+ }
+
+ // WizardShowPageList
+ if (!this->IsVersionLess("4.0") && !this->WizardShowPageList.empty()) {
+ xout.Element("WizardShowPageList", this->WizardShowPageList);
+ }
+
+ // TitleColor
+ if (!this->TitleColor.empty()) {
+ xout.Element("TitleColor", this->TitleColor);
+ }
+
+ // Start menu
+ if (!this->IsVersionLess("2.0")) {
+ xout.Element("StartMenuDir", this->StartMenuDir);
+ }
+
+ // Target dir
+ if (!this->TargetDir.empty()) {
+ xout.Element("TargetDir", this->TargetDir);
+ }
+
+ // Admin target dir
+ if (!this->AdminTargetDir.empty()) {
+ xout.Element("AdminTargetDir", this->AdminTargetDir);
+ }
+
+ // Remote repositories
+ if (!this->RemoteRepositories.empty()) {
+ xout.StartElement("RemoteRepositories");
+ for (cmCPackIFWRepository* r : this->RemoteRepositories) {
+ r->WriteRepositoryConfig(xout);
+ }
+ xout.EndElement();
+ }
+
+ // Maintenance tool
+ if (!this->IsVersionLess("2.0") && !this->MaintenanceToolName.empty()) {
+ xout.Element("MaintenanceToolName", this->MaintenanceToolName);
+ }
+
+ // Maintenance tool ini file
+ if (!this->IsVersionLess("2.0") && !this->MaintenanceToolIniFile.empty()) {
+ xout.Element("MaintenanceToolIniFile", this->MaintenanceToolIniFile);
+ }
+
+ if (!this->RemoveTargetDir.empty()) {
+ xout.Element("RemoveTargetDir", this->RemoveTargetDir);
+ }
+
+ // Different allows
+ if (this->IsVersionLess("2.0")) {
+ // CPack IFW default policy
+ xout.Comment("CPack IFW default policy for QtIFW less 2.0");
+ xout.Element("AllowNonAsciiCharacters", "true");
+ xout.Element("AllowSpaceInPath", "true");
+ } else {
+ if (!this->AllowNonAsciiCharacters.empty()) {
+ xout.Element("AllowNonAsciiCharacters", this->AllowNonAsciiCharacters);
+ }
+ if (!this->AllowSpaceInPath.empty()) {
+ xout.Element("AllowSpaceInPath", this->AllowSpaceInPath);
+ }
+ }
+
+ // Control script (copy to config dir)
+ if (!this->IsVersionLess("2.0") && !this->ControlScript.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(this->ControlScript);
+ std::string path = this->Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(this->ControlScript, path);
+ xout.Element("ControlScript", name);
+ }
+
+ // Resources (copy to resources dir)
+ if (!this->Resources.empty()) {
+ std::vector<std::string> resources;
+ cmCPackIFWResourcesParser parser(this);
+ for (size_t i = 0; i < this->Resources.size(); i++) {
+ if (parser.ParseResource(i)) {
+ std::string name = cmSystemTools::GetFilenameName(this->Resources[i]);
+ std::string path = this->Directory + "/resources/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(this->Resources[i], path);
+ resources.push_back(std::move(name));
+ } else {
+ cmCPackIFWLogger(WARNING,
+ "Can't copy resources from \""
+ << this->Resources[i]
+ << "\". Resource will be skipped." << std::endl);
+ }
+ }
+ this->Resources = resources;
+ }
+
+ xout.EndElement();
+ xout.EndDocument();
+}
+
+void cmCPackIFWInstaller::GeneratePackageFiles()
+{
+ if (this->Packages.empty() || this->Generator->IsOnePackage()) {
+ // Generate default package
+ cmCPackIFWPackage package;
+ package.Generator = this->Generator;
+ package.Installer = this;
+ // Check package group
+ if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_GROUP")) {
+ package.ConfigureFromGroup(option);
+ std::string forcedOption = "CPACK_IFW_COMPONENT_GROUP_" +
+ cmsys::SystemTools::UpperCase(option) + "_FORCED_INSTALLATION";
+ if (!this->GetOption(forcedOption)) {
+ package.ForcedInstallation = "true";
+ }
+ } else {
+ package.ConfigureFromOptions();
+ }
+ package.GeneratePackageFile();
+ return;
+ }
+
+ // Generate packages meta information
+ for (auto& p : this->Packages) {
+ cmCPackIFWPackage* package = p.second;
+ package->GeneratePackageFile();
+ }
+}
diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.h b/Source/CPack/IFW/cmCPackIFWInstaller.h
new file mode 100644
index 0000000..a031fc2
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWInstaller.h
@@ -0,0 +1,137 @@
+/* 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 <map>
+#include <string>
+#include <vector>
+
+#include "cmCPackIFWCommon.h"
+
+class cmCPackIFWPackage;
+class cmCPackIFWRepository;
+
+/** \class cmCPackIFWInstaller
+ * \brief A binary installer to be created CPack IFW generator
+ */
+class cmCPackIFWInstaller : public cmCPackIFWCommon
+{
+public:
+ // Types
+
+ using PackagesMap = std::map<std::string, cmCPackIFWPackage*>;
+ using RepositoriesVector = std::vector<cmCPackIFWRepository*>;
+
+public:
+ // Constructor
+
+ /**
+ * Construct installer
+ */
+ cmCPackIFWInstaller();
+
+public:
+ // Configuration
+
+ /// Name of the product being installed
+ std::string Name;
+
+ /// Version number of the product being installed
+ std::string Version;
+
+ /// Name of the installer as displayed on the title bar
+ std::string Title;
+
+ /// Publisher of the software (as shown in the Windows Control Panel)
+ std::string Publisher;
+
+ /// URL to a page that contains product information on your web site
+ std::string ProductUrl;
+
+ /// Filename for a custom installer icon
+ std::string InstallerApplicationIcon;
+
+ /// Filename for a custom window icon
+ std::string InstallerWindowIcon;
+
+ /// Filename for a logo
+ std::string Logo;
+
+ /// Filename for a watermark
+ std::string Watermark;
+
+ /// Filename for a banner
+ std::string Banner;
+
+ /// Filename for a background
+ std::string Background;
+
+ /// Wizard style name
+ std::string WizardStyle;
+
+ /// Filename for a style sheet
+ std::string StyleSheet;
+
+ /// Wizard width
+ std::string WizardDefaultWidth;
+
+ /// Wizard height
+ std::string WizardDefaultHeight;
+
+ /// Set to false if the widget listing installer pages on the left side
+ /// of the wizard should not be shown
+ std::string WizardShowPageList;
+
+ /// Title color
+ std::string TitleColor;
+
+ /// Name of the default program group in the Windows Start menu
+ std::string StartMenuDir;
+
+ /// Default target directory for installation
+ std::string TargetDir;
+
+ /// Default target directory for installation with administrator rights
+ std::string AdminTargetDir;
+
+ /// Filename of the generated maintenance tool
+ std::string MaintenanceToolName;
+
+ /// Filename for the configuration of the generated maintenance tool
+ std::string MaintenanceToolIniFile;
+
+ /// Set to true if the installation path can contain non-ASCII characters
+ std::string AllowNonAsciiCharacters;
+
+ /// Set to false if the target directory should not be deleted when
+ /// uninstalling
+ std::string RemoveTargetDir;
+
+ /// Set to false if the installation path cannot contain space characters
+ std::string AllowSpaceInPath;
+
+ /// Filename for a custom installer control script
+ std::string ControlScript;
+
+ /// List of resources to include in the installer binary
+ std::vector<std::string> Resources;
+
+public:
+ // Internal implementation
+
+ void ConfigureFromOptions();
+
+ void GenerateInstallerFile();
+
+ void GeneratePackageFiles();
+
+ PackagesMap Packages;
+ RepositoriesVector RemoteRepositories;
+ std::string Directory;
+
+protected:
+ void printSkippedOptionWarning(const std::string& optionName,
+ const std::string& optionValue);
+};
diff --git a/Source/CPack/IFW/cmCPackIFWPackage.cxx b/Source/CPack/IFW/cmCPackIFWPackage.cxx
new file mode 100644
index 0000000..1429c46
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWPackage.cxx
@@ -0,0 +1,758 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackIFWPackage.h"
+
+#include <cstddef>
+#include <map>
+#include <sstream>
+#include <utility>
+
+#include <cm/string_view>
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackIFWCommon.h"
+#include "cmCPackIFWGenerator.h"
+#include "cmCPackIFWInstaller.h"
+#include "cmCPackLog.h" // IWYU pragma: keep
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTimestamp.h"
+#include "cmXMLWriter.h"
+
+//---------------------------------------------------------- CompareStruct ---
+cmCPackIFWPackage::CompareStruct::CompareStruct()
+ : Type(cmCPackIFWPackage::CompareNone)
+{
+}
+
+//------------------------------------------------------- DependenceStruct ---
+cmCPackIFWPackage::DependenceStruct::DependenceStruct() = default;
+
+cmCPackIFWPackage::DependenceStruct::DependenceStruct(
+ const std::string& dependence)
+{
+ // Preferred format is name and version are separated by a colon (:), but
+ // note that this is only supported with QtIFW 3.1 or later. Backward
+ // compatibility allows a hyphen (-) as a separator instead, but names then
+ // cannot contain a hyphen.
+ size_t pos;
+ if ((pos = dependence.find(':')) == std::string::npos) {
+ pos = dependence.find('-');
+ }
+
+ if (pos != std::string::npos) {
+ this->Name = dependence.substr(0, pos);
+ ++pos;
+ if (pos == dependence.size()) {
+ // Nothing after the separator. Treat this as no version constraint.
+ return;
+ }
+
+ const auto versionPart =
+ cm::string_view(dependence.data() + pos, dependence.size() - pos);
+
+ if (cmHasLiteralPrefix(versionPart, "<=")) {
+ this->Compare.Type = cmCPackIFWPackage::CompareLessOrEqual;
+ this->Compare.Value = std::string(versionPart.substr(2));
+ } else if (cmHasLiteralPrefix(versionPart, ">=")) {
+ this->Compare.Type = cmCPackIFWPackage::CompareGreaterOrEqual;
+ this->Compare.Value = std::string(versionPart.substr(2));
+ } else if (cmHasPrefix(versionPart, '<')) {
+ this->Compare.Type = cmCPackIFWPackage::CompareLess;
+ this->Compare.Value = std::string(versionPart.substr(1));
+ } else if (cmHasPrefix(versionPart, '=')) {
+ this->Compare.Type = cmCPackIFWPackage::CompareEqual;
+ this->Compare.Value = std::string(versionPart.substr(1));
+ } else if (cmHasPrefix(versionPart, '>')) {
+ this->Compare.Type = cmCPackIFWPackage::CompareGreater;
+ this->Compare.Value = std::string(versionPart.substr(1));
+ } else {
+ // We found no operator but a version specification is still expected to
+ // follow. The default behavior is to treat this the same as =. We
+ // explicitly record that as our type (it simplifies our logic a little
+ // and is also clearer).
+ this->Compare.Type = cmCPackIFWPackage::CompareEqual;
+ this->Compare.Value = std::string(versionPart);
+ }
+ } else {
+ this->Name = dependence;
+ }
+}
+
+std::string cmCPackIFWPackage::DependenceStruct::NameWithCompare() const
+{
+ std::string result = this->Name;
+ if (this->Name.find('-') != std::string::npos) {
+ // When a name contains a hyphen, we must use a colon after the name to
+ // prevent the hyphen from being parsed by QtIFW as the separator between
+ // the name and the version. Note that a colon is only supported with
+ // QtIFW 3.1 or later.
+ result += ":";
+ } else if (this->Compare.Type != cmCPackIFWPackage::CompareNone ||
+ !this->Compare.Value.empty()) {
+ // No hyphen in the name and we know a version part will follow. Use a
+ // hyphen as a separator since this works for all QtIFW versions.
+ result += "-";
+ }
+
+ if (this->Compare.Type == cmCPackIFWPackage::CompareLessOrEqual) {
+ result += "<=";
+ } else if (this->Compare.Type == cmCPackIFWPackage::CompareGreaterOrEqual) {
+ result += ">=";
+ } else if (this->Compare.Type == cmCPackIFWPackage::CompareLess) {
+ result += "<";
+ } else if (this->Compare.Type == cmCPackIFWPackage::CompareEqual) {
+ result += "=";
+ } else if (this->Compare.Type == cmCPackIFWPackage::CompareGreater) {
+ result += ">";
+ }
+
+ result += this->Compare.Value;
+
+ return result;
+}
+
+//------------------------------------------------------ cmCPackIFWPackage ---
+cmCPackIFWPackage::cmCPackIFWPackage()
+ : Installer(nullptr)
+{
+}
+
+std::string cmCPackIFWPackage::GetComponentName(cmCPackComponent* component)
+{
+ if (!component) {
+ return "";
+ }
+ const char* option =
+ this->GetOption("CPACK_IFW_COMPONENT_" +
+ cmsys::SystemTools::UpperCase(component->Name) + "_NAME");
+ return option ? option : component->Name;
+}
+
+void cmCPackIFWPackage::DefaultConfiguration()
+{
+ this->DisplayName.clear();
+ this->Description.clear();
+ this->Version.clear();
+ this->ReleaseDate.clear();
+ this->Script.clear();
+ this->Licenses.clear();
+ this->UserInterfaces.clear();
+ this->Translations.clear();
+ this->SortingPriority.clear();
+ this->UpdateText.clear();
+ this->Default.clear();
+ this->Essential.clear();
+ this->Virtual.clear();
+ this->ForcedInstallation.clear();
+ this->RequiresAdminRights.clear();
+}
+
+// Default configuration (all in one package)
+int cmCPackIFWPackage::ConfigureFromOptions()
+{
+ // Restore default configuration
+ this->DefaultConfiguration();
+
+ // Name
+ this->Name = this->Generator->GetRootPackageName();
+
+ // Display name
+ if (const char* option = this->GetOption("CPACK_PACKAGE_NAME")) {
+ this->DisplayName[""] = option;
+ } else {
+ this->DisplayName[""] = "Your package";
+ }
+
+ // Description
+ if (const char* option =
+ this->GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY")) {
+ this->Description[""] = option;
+ } else {
+ this->Description[""] = "Your package description";
+ }
+
+ // Version
+ if (const char* option = this->GetOption("CPACK_PACKAGE_VERSION")) {
+ this->Version = option;
+ } else {
+ this->Version = "1.0.0";
+ }
+
+ this->ForcedInstallation = "true";
+
+ return 1;
+}
+
+int cmCPackIFWPackage::ConfigureFromComponent(cmCPackComponent* component)
+{
+ if (!component) {
+ return 0;
+ }
+
+ // Restore default configuration
+ this->DefaultConfiguration();
+
+ std::string prefix = "CPACK_IFW_COMPONENT_" +
+ cmsys::SystemTools::UpperCase(component->Name) + "_";
+
+ // Display name
+ this->DisplayName[""] = component->DisplayName;
+
+ // Description
+ this->Description[""] = component->Description;
+
+ // Version
+ if (const char* optVERSION = this->GetOption(prefix + "VERSION")) {
+ this->Version = optVERSION;
+ } else if (const char* optPACKAGE_VERSION =
+ this->GetOption("CPACK_PACKAGE_VERSION")) {
+ this->Version = optPACKAGE_VERSION;
+ } else {
+ this->Version = "1.0.0";
+ }
+
+ // Script
+ if (const char* option = this->GetOption(prefix + "SCRIPT")) {
+ this->Script = option;
+ }
+
+ // User interfaces
+ if (const char* option = this->GetOption(prefix + "USER_INTERFACES")) {
+ this->UserInterfaces.clear();
+ cmExpandList(option, this->UserInterfaces);
+ }
+
+ // CMake dependencies
+ if (!component->Dependencies.empty()) {
+ for (cmCPackComponent* dep : component->Dependencies) {
+ this->Dependencies.insert(this->Generator->ComponentPackages[dep]);
+ }
+ }
+
+ // Licenses
+ if (const char* option = this->GetOption(prefix + "LICENSES")) {
+ this->Licenses.clear();
+ cmExpandList(option, this->Licenses);
+ if (this->Licenses.size() % 2 != 0) {
+ cmCPackIFWLogger(
+ WARNING,
+ prefix << "LICENSES"
+ << " should contain pairs of <display_name> and <file_path>."
+ << std::endl);
+ this->Licenses.clear();
+ }
+ }
+
+ // Priority
+ if (const char* option = this->GetOption(prefix + "PRIORITY")) {
+ this->SortingPriority = option;
+ cmCPackIFWLogger(
+ WARNING,
+ "The \"PRIORITY\" option is set "
+ << "for component \"" << component->Name << "\", but there option is "
+ << "deprecated. Please use \"SORTING_PRIORITY\" option instead."
+ << std::endl);
+ }
+
+ // Default
+ this->Default = component->IsDisabledByDefault ? "false" : "true";
+
+ // Essential
+ if (this->IsOn(prefix + "ESSENTIAL")) {
+ this->Essential = "true";
+ }
+
+ // Virtual
+ this->Virtual = component->IsHidden ? "true" : "";
+
+ // ForcedInstallation
+ this->ForcedInstallation = component->IsRequired ? "true" : "false";
+
+ return this->ConfigureFromPrefix(prefix);
+}
+
+int cmCPackIFWPackage::ConfigureFromGroup(cmCPackComponentGroup* group)
+{
+ if (!group) {
+ return 0;
+ }
+
+ // Restore default configuration
+ this->DefaultConfiguration();
+
+ std::string prefix = "CPACK_IFW_COMPONENT_GROUP_" +
+ cmsys::SystemTools::UpperCase(group->Name) + "_";
+
+ this->DisplayName[""] = group->DisplayName;
+ this->Description[""] = group->Description;
+
+ // Version
+ if (const char* optVERSION = this->GetOption(prefix + "VERSION")) {
+ this->Version = optVERSION;
+ } else if (const char* optPACKAGE_VERSION =
+ this->GetOption("CPACK_PACKAGE_VERSION")) {
+ this->Version = optPACKAGE_VERSION;
+ } else {
+ this->Version = "1.0.0";
+ }
+
+ // Script
+ if (const char* option = this->GetOption(prefix + "SCRIPT")) {
+ this->Script = option;
+ }
+
+ // User interfaces
+ if (const char* option = this->GetOption(prefix + "USER_INTERFACES")) {
+ this->UserInterfaces.clear();
+ cmExpandList(option, this->UserInterfaces);
+ }
+
+ // Licenses
+ if (const char* option = this->GetOption(prefix + "LICENSES")) {
+ this->Licenses.clear();
+ cmExpandList(option, this->Licenses);
+ if (this->Licenses.size() % 2 != 0) {
+ cmCPackIFWLogger(
+ WARNING,
+ prefix << "LICENSES"
+ << " should contain pairs of <display_name> and <file_path>."
+ << std::endl);
+ this->Licenses.clear();
+ }
+ }
+
+ // Priority
+ if (const char* option = this->GetOption(prefix + "PRIORITY")) {
+ this->SortingPriority = option;
+ cmCPackIFWLogger(
+ WARNING,
+ "The \"PRIORITY\" option is set "
+ << "for component group \"" << group->Name
+ << "\", but there option is "
+ << "deprecated. Please use \"SORTING_PRIORITY\" option instead."
+ << std::endl);
+ }
+
+ return this->ConfigureFromPrefix(prefix);
+}
+
+int cmCPackIFWPackage::ConfigureFromGroup(const std::string& groupName)
+{
+ // Group configuration
+
+ cmCPackComponentGroup group;
+ std::string prefix =
+ "CPACK_COMPONENT_GROUP_" + cmsys::SystemTools::UpperCase(groupName) + "_";
+
+ if (const char* option = this->GetOption(prefix + "DISPLAY_NAME")) {
+ group.DisplayName = option;
+ } else {
+ group.DisplayName = group.Name;
+ }
+
+ if (const char* option = this->GetOption(prefix + "DESCRIPTION")) {
+ group.Description = option;
+ }
+ group.IsBold = this->IsOn(prefix + "BOLD_TITLE");
+ group.IsExpandedByDefault = this->IsOn(prefix + "EXPANDED");
+
+ // Package configuration
+
+ group.Name = groupName;
+
+ if (this->Generator) {
+ this->Name = this->Generator->GetGroupPackageName(&group);
+ } else {
+ this->Name = group.Name;
+ }
+
+ return this->ConfigureFromGroup(&group);
+}
+
+// Common options for components and groups
+int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix)
+{
+ // Temporary variable for full option name
+ std::string option;
+
+ // Display name
+ option = prefix + "DISPLAY_NAME";
+ if (this->IsSetToEmpty(option)) {
+ this->DisplayName.clear();
+ } else if (const char* value = this->GetOption(option)) {
+ cmCPackIFWPackage::ExpandListArgument(value, this->DisplayName);
+ }
+
+ // Description
+ option = prefix + "DESCRIPTION";
+ if (this->IsSetToEmpty(option)) {
+ this->Description.clear();
+ } else if (const char* value = this->GetOption(option)) {
+ cmCPackIFWPackage::ExpandListArgument(value, this->Description);
+ }
+
+ // Release date
+ option = prefix + "RELEASE_DATE";
+ if (this->IsSetToEmpty(option)) {
+ this->ReleaseDate.clear();
+ } else if (const char* value = this->GetOption(option)) {
+ this->ReleaseDate = value;
+ }
+
+ // Sorting priority
+ option = prefix + "SORTING_PRIORITY";
+ if (this->IsSetToEmpty(option)) {
+ this->SortingPriority.clear();
+ } else if (const char* value = this->GetOption(option)) {
+ this->SortingPriority = value;
+ }
+
+ // Update text
+ option = prefix + "UPDATE_TEXT";
+ if (this->IsSetToEmpty(option)) {
+ this->UpdateText.clear();
+ } else if (const char* value = this->GetOption(option)) {
+ this->UpdateText = value;
+ }
+
+ // Translations
+ option = prefix + "TRANSLATIONS";
+ if (this->IsSetToEmpty(option)) {
+ this->Translations.clear();
+ } else if (const char* value = this->GetOption(option)) {
+ this->Translations.clear();
+ cmExpandList(value, this->Translations);
+ }
+
+ // QtIFW dependencies
+ std::vector<std::string> deps;
+ option = prefix + "DEPENDS";
+ if (const char* value = this->GetOption(option)) {
+ cmExpandList(value, deps);
+ }
+ option = prefix + "DEPENDENCIES";
+ if (const char* value = this->GetOption(option)) {
+ cmExpandList(value, deps);
+ }
+ for (std::string const& d : deps) {
+ DependenceStruct dep(d);
+ if (this->Generator->Packages.count(dep.Name)) {
+ cmCPackIFWPackage& depPkg = this->Generator->Packages[dep.Name];
+ dep.Name = depPkg.Name;
+ }
+ bool hasDep = this->Generator->DependentPackages.count(dep.Name) > 0;
+ DependenceStruct& depRef = this->Generator->DependentPackages[dep.Name];
+ if (!hasDep) {
+ depRef = dep;
+ }
+ this->AlienDependencies.insert(&depRef);
+ }
+
+ // Automatic dependency on
+ option = prefix + "AUTO_DEPEND_ON";
+ if (this->IsSetToEmpty(option)) {
+ this->AlienAutoDependOn.clear();
+ } else if (const char* value = this->GetOption(option)) {
+ std::vector<std::string> depsOn = cmExpandedList(value);
+ for (std::string const& d : depsOn) {
+ DependenceStruct dep(d);
+ if (this->Generator->Packages.count(dep.Name)) {
+ cmCPackIFWPackage& depPkg = this->Generator->Packages[dep.Name];
+ dep.Name = depPkg.Name;
+ }
+ bool hasDep = this->Generator->DependentPackages.count(dep.Name) > 0;
+ DependenceStruct& depRef = this->Generator->DependentPackages[dep.Name];
+ if (!hasDep) {
+ depRef = dep;
+ }
+ this->AlienAutoDependOn.insert(&depRef);
+ }
+ }
+
+ // Visibility
+ option = prefix + "VIRTUAL";
+ if (this->IsSetToEmpty(option)) {
+ this->Virtual.clear();
+ } else if (this->IsOn(option)) {
+ this->Virtual = "true";
+ }
+
+ // Default selection
+ option = prefix + "DEFAULT";
+ if (this->IsSetToEmpty(option)) {
+ this->Default.clear();
+ } else if (const char* value = this->GetOption(option)) {
+ std::string lowerValue = cmsys::SystemTools::LowerCase(value);
+ if (lowerValue == "true") {
+ this->Default = "true";
+ } else if (lowerValue == "false") {
+ this->Default = "false";
+ } else if (lowerValue == "script") {
+ this->Default = "script";
+ } else {
+ this->Default = value;
+ }
+ }
+
+ // Forsed installation
+ option = prefix + "FORCED_INSTALLATION";
+ if (this->IsSetToEmpty(option)) {
+ this->ForcedInstallation.clear();
+ } else if (this->IsOn(option)) {
+ this->ForcedInstallation = "true";
+ } else if (this->IsSetToOff(option)) {
+ this->ForcedInstallation = "false";
+ }
+
+ // Replaces
+ option = prefix + "REPLACES";
+ if (this->IsSetToEmpty(option)) {
+ this->Replaces.clear();
+ } else if (const char* value = this->GetOption(option)) {
+ this->Replaces.clear();
+ cmExpandList(value, this->Replaces);
+ }
+
+ // Requires admin rights
+ option = prefix + "REQUIRES_ADMIN_RIGHTS";
+ if (this->IsSetToEmpty(option)) {
+ this->RequiresAdminRights.clear();
+ } else if (this->IsOn(option)) {
+ this->RequiresAdminRights = "true";
+ } else if (this->IsSetToOff(option)) {
+ this->RequiresAdminRights = "false";
+ }
+
+ // Checkable
+ option = prefix + "CHECKABLE";
+ if (this->IsSetToEmpty(option)) {
+ this->Checkable.clear();
+ } else if (this->IsOn(option)) {
+ this->Checkable = "true";
+ } else if (this->IsSetToOff(option)) {
+ this->Checkable = "false";
+ }
+
+ return 1;
+}
+
+void cmCPackIFWPackage::GeneratePackageFile()
+{
+ // Lazy directory initialization
+ if (this->Directory.empty()) {
+ if (this->Installer) {
+ this->Directory = this->Installer->Directory + "/packages/" + this->Name;
+ } else if (this->Generator) {
+ this->Directory = this->Generator->toplevel + "/packages/" + this->Name;
+ }
+ }
+
+ // Output stream
+ cmGeneratedFileStream fout(this->Directory + "/meta/package.xml");
+ cmXMLWriter xout(fout);
+
+ xout.StartDocument();
+
+ this->WriteGeneratedByToStrim(xout);
+
+ xout.StartElement("Package");
+
+ // DisplayName (with translations)
+ for (auto const& dn : this->DisplayName) {
+ xout.StartElement("DisplayName");
+ if (!dn.first.empty()) {
+ xout.Attribute("xml:lang", dn.first);
+ }
+ xout.Content(dn.second);
+ xout.EndElement();
+ }
+
+ // Description (with translations)
+ for (auto const& d : this->Description) {
+ xout.StartElement("Description");
+ if (!d.first.empty()) {
+ xout.Attribute("xml:lang", d.first);
+ }
+ xout.Content(d.second);
+ xout.EndElement();
+ }
+
+ // Update text
+ if (!this->UpdateText.empty()) {
+ xout.Element("UpdateText", this->UpdateText);
+ }
+
+ xout.Element("Name", this->Name);
+ xout.Element("Version", this->Version);
+
+ if (!this->ReleaseDate.empty()) {
+ xout.Element("ReleaseDate", this->ReleaseDate);
+ } else {
+ xout.Element("ReleaseDate", cmTimestamp().CurrentTime("%Y-%m-%d", true));
+ }
+
+ // Script (copy to meta dir)
+ if (!this->Script.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(this->Script);
+ std::string path = this->Directory + "/meta/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(this->Script, path);
+ xout.Element("Script", name);
+ }
+
+ // User Interfaces (copy to meta dir)
+ std::vector<std::string> userInterfaces = this->UserInterfaces;
+ for (std::string& userInterface : userInterfaces) {
+ std::string name = cmSystemTools::GetFilenameName(userInterface);
+ std::string path = this->Directory + "/meta/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(userInterface, path);
+ userInterface = name;
+ }
+ if (!userInterfaces.empty()) {
+ xout.StartElement("UserInterfaces");
+ for (std::string const& userInterface : userInterfaces) {
+ xout.Element("UserInterface", userInterface);
+ }
+ xout.EndElement();
+ }
+
+ // Translations (copy to meta dir)
+ std::vector<std::string> translations = this->Translations;
+ for (std::string& translation : translations) {
+ std::string name = cmSystemTools::GetFilenameName(translation);
+ std::string path = this->Directory + "/meta/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(translation, path);
+ translation = name;
+ }
+ if (!translations.empty()) {
+ xout.StartElement("Translations");
+ for (std::string const& translation : translations) {
+ xout.Element("Translation", translation);
+ }
+ xout.EndElement();
+ }
+
+ // Dependencies
+ const bool hyphensInNamesUnsupported = this->Generator &&
+ !this->Generator->FrameworkVersion.empty() && this->IsVersionLess("3.1");
+ bool warnUnsupportedNames = false;
+ std::set<DependenceStruct> compDepSet;
+ for (DependenceStruct* ad : this->AlienDependencies) {
+ compDepSet.insert(*ad);
+ }
+ for (cmCPackIFWPackage* d : this->Dependencies) {
+ compDepSet.insert(DependenceStruct(d->Name));
+ }
+ // Write dependencies
+ if (!compDepSet.empty()) {
+ std::ostringstream dependencies;
+ auto it = compDepSet.begin();
+ warnUnsupportedNames |=
+ hyphensInNamesUnsupported && it->Name.find('-') != std::string::npos;
+ dependencies << it->NameWithCompare();
+ ++it;
+ while (it != compDepSet.end()) {
+ warnUnsupportedNames |=
+ hyphensInNamesUnsupported && it->Name.find('-') != std::string::npos;
+ dependencies << "," << it->NameWithCompare();
+ ++it;
+ }
+ xout.Element("Dependencies", dependencies.str());
+ }
+
+ // Automatic dependency on
+ std::set<DependenceStruct> compAutoDepSet;
+ for (DependenceStruct* aad : this->AlienAutoDependOn) {
+ compAutoDepSet.insert(*aad);
+ }
+ // Write automatic dependency on
+ if (!compAutoDepSet.empty()) {
+ std::ostringstream dependencies;
+ auto it = compAutoDepSet.begin();
+ warnUnsupportedNames |=
+ hyphensInNamesUnsupported && it->Name.find('-') != std::string::npos;
+ dependencies << it->NameWithCompare();
+ ++it;
+ while (it != compAutoDepSet.end()) {
+ warnUnsupportedNames |=
+ hyphensInNamesUnsupported && it->Name.find('-') != std::string::npos;
+ dependencies << "," << it->NameWithCompare();
+ ++it;
+ }
+ xout.Element("AutoDependOn", dependencies.str());
+ }
+
+ if (warnUnsupportedNames) {
+ cmCPackIFWLogger(
+ WARNING,
+ "The dependencies for component \""
+ << this->Name << "\" specify names that contain hyphens. "
+ << "This requires QtIFW 3.1 or later, but you are using version "
+ << this->Generator->FrameworkVersion << std::endl);
+ }
+
+ // Licenses (copy to meta dir)
+ std::vector<std::string> licenses = this->Licenses;
+ for (size_t i = 1; i < licenses.size(); i += 2) {
+ std::string name = cmSystemTools::GetFilenameName(licenses[i]);
+ std::string path = this->Directory + "/meta/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(licenses[i], path);
+ licenses[i] = name;
+ }
+ if (!licenses.empty()) {
+ xout.StartElement("Licenses");
+ for (size_t i = 0; i < licenses.size(); i += 2) {
+ xout.StartElement("License");
+ xout.Attribute("name", licenses[i]);
+ xout.Attribute("file", licenses[i + 1]);
+ xout.EndElement();
+ }
+ xout.EndElement();
+ }
+
+ if (!this->ForcedInstallation.empty()) {
+ xout.Element("ForcedInstallation", this->ForcedInstallation);
+ }
+
+ // Replaces
+ if (!this->Replaces.empty()) {
+ std::ostringstream replaces;
+ auto it = this->Replaces.begin();
+ replaces << *it;
+ ++it;
+ while (it != this->Replaces.end()) {
+ replaces << "," << *it;
+ ++it;
+ }
+ xout.Element("Replaces", replaces.str());
+ }
+
+ if (!this->RequiresAdminRights.empty()) {
+ xout.Element("RequiresAdminRights", this->RequiresAdminRights);
+ }
+
+ if (!this->Virtual.empty()) {
+ xout.Element("Virtual", this->Virtual);
+ } else if (!this->Default.empty()) {
+ xout.Element("Default", this->Default);
+ }
+
+ // Essential
+ if (!this->Essential.empty()) {
+ xout.Element("Essential", this->Essential);
+ }
+
+ // Priority
+ if (!this->SortingPriority.empty()) {
+ xout.Element("SortingPriority", this->SortingPriority);
+ }
+
+ // Checkable
+ if (!this->Checkable.empty()) {
+ xout.Element("Checkable", this->Checkable);
+ }
+
+ xout.EndElement();
+ xout.EndDocument();
+}
diff --git a/Source/CPack/IFW/cmCPackIFWPackage.h b/Source/CPack/IFW/cmCPackIFWPackage.h
new file mode 100644
index 0000000..0cc6f2f
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWPackage.h
@@ -0,0 +1,150 @@
+/* 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 <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmCPackIFWCommon.h"
+
+class cmCPackComponent;
+class cmCPackComponentGroup;
+class cmCPackIFWInstaller;
+
+/** \class cmCPackIFWPackage
+ * \brief A single component to be installed by CPack IFW generator
+ */
+class cmCPackIFWPackage : public cmCPackIFWCommon
+{
+public:
+ // Types
+
+ enum CompareTypes
+ {
+ CompareNone = 0x0,
+ CompareEqual = 0x1,
+ CompareLess = 0x2,
+ CompareLessOrEqual = 0x3,
+ CompareGreater = 0x4,
+ CompareGreaterOrEqual = 0x5
+ };
+
+ struct CompareStruct
+ {
+ CompareStruct();
+
+ unsigned int Type;
+ std::string Value;
+ };
+
+ struct DependenceStruct
+ {
+ DependenceStruct();
+ DependenceStruct(const std::string& dependence);
+
+ std::string Name;
+ CompareStruct Compare;
+
+ std::string NameWithCompare() const;
+
+ bool operator<(const DependenceStruct& other) const
+ {
+ return this->Name < other.Name;
+ }
+ };
+
+public:
+ // [Con|De]structor
+
+ /**
+ * Construct package
+ */
+ cmCPackIFWPackage();
+
+public:
+ // Configuration
+
+ /// Human-readable name of the component
+ std::map<std::string, std::string> DisplayName;
+
+ /// Human-readable description of the component
+ std::map<std::string, std::string> Description;
+
+ /// Version number of the component
+ std::string Version;
+
+ /// Date when this component version was released
+ std::string ReleaseDate;
+
+ /// Domain-like identification for this component
+ std::string Name;
+
+ /// File name of a script being loaded
+ std::string Script;
+
+ /// List of license agreements to be accepted by the installing user
+ std::vector<std::string> Licenses;
+
+ /// List of pages to load
+ std::vector<std::string> UserInterfaces;
+
+ /// List of translation files to load
+ std::vector<std::string> Translations;
+
+ /// Priority of the component in the tree
+ std::string SortingPriority;
+
+ /// Description added to the component description
+ std::string UpdateText;
+
+ /// Set to true to preselect the component in the installer
+ std::string Default;
+
+ /// Marks the package as essential to force a restart of the MaintenanceTool
+ std::string Essential;
+
+ /// Set to true to hide the component from the installer
+ std::string Virtual;
+
+ /// Determines that the package must always be installed
+ std::string ForcedInstallation;
+
+ /// List of components to replace
+ std::vector<std::string> Replaces;
+
+ /// Package needs to be installed with elevated permissions
+ std::string RequiresAdminRights;
+
+ /// Set to false if you want to hide the checkbox for an item
+ std::string Checkable;
+
+public:
+ // Internal implementation
+
+ std::string GetComponentName(cmCPackComponent* component);
+
+ void DefaultConfiguration();
+
+ int ConfigureFromOptions();
+ int ConfigureFromComponent(cmCPackComponent* component);
+ int ConfigureFromGroup(cmCPackComponentGroup* group);
+ int ConfigureFromGroup(const std::string& groupName);
+ int ConfigureFromPrefix(const std::string& prefix);
+
+ void GeneratePackageFile();
+
+ // Pointer to installer
+ cmCPackIFWInstaller* Installer;
+ // Collection of dependencies
+ std::set<cmCPackIFWPackage*> Dependencies;
+ // Collection of unresolved dependencies
+ std::set<DependenceStruct*> AlienDependencies;
+ // Collection of unresolved automatic dependency on
+ std::set<DependenceStruct*> AlienAutoDependOn;
+ // Patch to package directory
+ std::string Directory;
+};
diff --git a/Source/CPack/IFW/cmCPackIFWRepository.cxx b/Source/CPack/IFW/cmCPackIFWRepository.cxx
new file mode 100644
index 0000000..7ec2256
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWRepository.cxx
@@ -0,0 +1,283 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackIFWRepository.h"
+
+#include <cstddef>
+
+#include "cmCPackIFWGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include "cmXMLWriter.h"
+
+cmCPackIFWRepository::cmCPackIFWRepository()
+ : Update(cmCPackIFWRepository::None)
+{
+}
+
+bool cmCPackIFWRepository::IsValid() const
+{
+ bool valid = true;
+
+ switch (this->Update) {
+ case cmCPackIFWRepository::None:
+ case cmCPackIFWRepository::Add:
+ case cmCPackIFWRepository::Remove:
+ valid = !this->Url.empty();
+ break;
+ case cmCPackIFWRepository::Replace:
+ valid = !this->OldUrl.empty() && !this->NewUrl.empty();
+ break;
+ }
+
+ return valid;
+}
+
+bool cmCPackIFWRepository::ConfigureFromOptions()
+{
+ // Name;
+ if (this->Name.empty()) {
+ return false;
+ }
+
+ std::string prefix =
+ "CPACK_IFW_REPOSITORY_" + cmsys::SystemTools::UpperCase(this->Name) + "_";
+
+ // Update
+ if (this->IsOn(prefix + "ADD")) {
+ this->Update = cmCPackIFWRepository::Add;
+ } else if (this->IsOn(prefix + "REMOVE")) {
+ this->Update = cmCPackIFWRepository::Remove;
+ } else if (this->IsOn(prefix + "REPLACE")) {
+ this->Update = cmCPackIFWRepository::Replace;
+ } else {
+ this->Update = cmCPackIFWRepository::None;
+ }
+
+ // Url
+ if (const char* url = this->GetOption(prefix + "URL")) {
+ this->Url = url;
+ } else {
+ this->Url.clear();
+ }
+
+ // Old url
+ if (const char* oldUrl = this->GetOption(prefix + "OLD_URL")) {
+ this->OldUrl = oldUrl;
+ } else {
+ this->OldUrl.clear();
+ }
+
+ // New url
+ if (const char* newUrl = this->GetOption(prefix + "NEW_URL")) {
+ this->NewUrl = newUrl;
+ } else {
+ this->NewUrl.clear();
+ }
+
+ // Enabled
+ if (this->IsOn(prefix + "DISABLED")) {
+ this->Enabled = "0";
+ } else {
+ this->Enabled.clear();
+ }
+
+ // Username
+ if (const char* username = this->GetOption(prefix + "USERNAME")) {
+ this->Username = username;
+ } else {
+ this->Username.clear();
+ }
+
+ // Password
+ if (const char* password = this->GetOption(prefix + "PASSWORD")) {
+ this->Password = password;
+ } else {
+ this->Password.clear();
+ }
+
+ // DisplayName
+ if (const char* displayName = this->GetOption(prefix + "DISPLAY_NAME")) {
+ this->DisplayName = displayName;
+ } else {
+ this->DisplayName.clear();
+ }
+
+ return this->IsValid();
+}
+
+/** \class cmCPackeIFWUpdatesPatcher
+ * \brief Helper class that parses and patch Updates.xml file (QtIFW)
+ */
+class cmCPackeIFWUpdatesPatcher : public cmXMLParser
+{
+public:
+ cmCPackeIFWUpdatesPatcher(cmCPackIFWRepository* r, cmXMLWriter& x)
+ : repository(r)
+ , xout(x)
+ , patched(false)
+ {
+ }
+
+ cmCPackIFWRepository* repository;
+ cmXMLWriter& xout;
+ bool patched;
+
+protected:
+ void StartElement(const std::string& name, const char** atts) override
+ {
+ this->xout.StartElement(name);
+ this->StartFragment(atts);
+ }
+
+ void StartFragment(const char** atts)
+ {
+ for (size_t i = 0; atts[i]; i += 2) {
+ const char* key = atts[i];
+ const char* value = atts[i + 1];
+ this->xout.Attribute(key, value);
+ }
+ }
+
+ void EndElement(const std::string& name) override
+ {
+ if (name == "Updates" && !this->patched) {
+ this->repository->WriteRepositoryUpdates(this->xout);
+ this->patched = true;
+ }
+ this->xout.EndElement();
+ if (this->patched) {
+ return;
+ }
+ if (name == "Checksum") {
+ this->repository->WriteRepositoryUpdates(this->xout);
+ this->patched = true;
+ }
+ }
+
+ void CharacterDataHandler(const char* data, int length) override
+ {
+ std::string content(data, data + length);
+ if (content.empty() || content == " " || content == " " ||
+ content == "\n") {
+ return;
+ }
+ this->xout.Content(content);
+ }
+};
+
+bool cmCPackIFWRepository::PatchUpdatesXml()
+{
+ // Lazy directory initialization
+ if (this->Directory.empty() && this->Generator) {
+ this->Directory = this->Generator->toplevel;
+ }
+
+ // Filenames
+ std::string updatesXml = this->Directory + "/repository/Updates.xml";
+ std::string updatesPatchXml =
+ this->Directory + "/repository/UpdatesPatch.xml";
+
+ // Output stream
+ cmGeneratedFileStream fout(updatesPatchXml);
+ cmXMLWriter xout(fout);
+
+ xout.StartDocument();
+
+ this->WriteGeneratedByToStrim(xout);
+
+ // Patch
+ {
+ cmCPackeIFWUpdatesPatcher patcher(this, xout);
+ patcher.ParseFile(updatesXml.data());
+ }
+
+ xout.EndDocument();
+
+ fout.Close();
+
+ return cmSystemTools::RenameFile(updatesPatchXml, updatesXml);
+}
+
+void cmCPackIFWRepository::WriteRepositoryConfig(cmXMLWriter& xout) const
+{
+ xout.StartElement("Repository");
+
+ // Url
+ xout.Element("Url", this->Url);
+ // Enabled
+ if (!this->Enabled.empty()) {
+ xout.Element("Enabled", this->Enabled);
+ }
+ // Username
+ if (!this->Username.empty()) {
+ xout.Element("Username", this->Username);
+ }
+ // Password
+ if (!this->Password.empty()) {
+ xout.Element("Password", this->Password);
+ }
+ // DisplayName
+ if (!this->DisplayName.empty()) {
+ xout.Element("DisplayName", this->DisplayName);
+ }
+
+ xout.EndElement();
+}
+
+void cmCPackIFWRepository::WriteRepositoryUpdate(cmXMLWriter& xout) const
+{
+ xout.StartElement("Repository");
+
+ switch (this->Update) {
+ case cmCPackIFWRepository::None:
+ break;
+ case cmCPackIFWRepository::Add:
+ xout.Attribute("action", "add");
+ break;
+ case cmCPackIFWRepository::Remove:
+ xout.Attribute("action", "remove");
+ break;
+ case cmCPackIFWRepository::Replace:
+ xout.Attribute("action", "replace");
+ break;
+ }
+
+ // Url
+ if (this->Update == cmCPackIFWRepository::Add ||
+ this->Update == cmCPackIFWRepository::Remove) {
+ xout.Attribute("url", this->Url);
+ } else if (this->Update == cmCPackIFWRepository::Replace) {
+ xout.Attribute("oldUrl", this->OldUrl);
+ xout.Attribute("newUrl", this->NewUrl);
+ }
+ // Enabled
+ if (!this->Enabled.empty()) {
+ xout.Attribute("enabled", this->Enabled);
+ }
+ // Username
+ if (!this->Username.empty()) {
+ xout.Attribute("username", this->Username);
+ }
+ // Password
+ if (!this->Password.empty()) {
+ xout.Attribute("password", this->Password);
+ }
+ // DisplayName
+ if (!this->DisplayName.empty()) {
+ xout.Attribute("displayname", this->DisplayName);
+ }
+
+ xout.EndElement();
+}
+
+void cmCPackIFWRepository::WriteRepositoryUpdates(cmXMLWriter& xout)
+{
+ if (!this->RepositoryUpdate.empty()) {
+ xout.StartElement("RepositoryUpdate");
+ for (cmCPackIFWRepository* r : this->RepositoryUpdate) {
+ r->WriteRepositoryUpdate(xout);
+ }
+ xout.EndElement();
+ }
+}
diff --git a/Source/CPack/IFW/cmCPackIFWRepository.h b/Source/CPack/IFW/cmCPackIFWRepository.h
new file mode 100644
index 0000000..0153452
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWRepository.h
@@ -0,0 +1,85 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmCPackIFWCommon.h"
+
+class cmXMLWriter;
+
+/** \class cmCPackIFWRepository
+ * \brief A remote repository to be created CPack IFW generator
+ */
+class cmCPackIFWRepository : public cmCPackIFWCommon
+{
+public:
+ // Types
+
+ enum Action
+ {
+ None,
+ Add,
+ Remove,
+ Replace
+ };
+
+ using RepositoriesVector = std::vector<cmCPackIFWRepository*>;
+
+public:
+ // Constructor
+
+ /**
+ * Construct repository
+ */
+ cmCPackIFWRepository();
+
+public:
+ // Configuration
+
+ /// Internal repository name
+ std::string Name;
+
+ /// Optional update action
+ Action Update;
+
+ /// Is points to a list of available components
+ std::string Url;
+
+ /// Is points to a list that will replaced
+ std::string OldUrl;
+
+ /// Is points to a list that will replace to
+ std::string NewUrl;
+
+ /// With "0" disabling this repository
+ std::string Enabled;
+
+ /// Is used as user on a protected repository
+ std::string Username;
+
+ /// Is password to use on a protected repository
+ std::string Password;
+
+ /// Is optional string to display instead of the URL
+ std::string DisplayName;
+
+public:
+ // Internal implementation
+
+ bool IsValid() const;
+
+ bool ConfigureFromOptions();
+
+ bool PatchUpdatesXml();
+
+ void WriteRepositoryConfig(cmXMLWriter& xout) const;
+ void WriteRepositoryUpdate(cmXMLWriter& xout) const;
+ void WriteRepositoryUpdates(cmXMLWriter& xout);
+
+ RepositoriesVector RepositoryUpdate;
+ std::string Directory;
+};
diff --git a/Source/CPack/OSXLauncherScript.scpt b/Source/CPack/OSXLauncherScript.scpt
new file mode 100644
index 0000000..342cf8c
--- /dev/null
+++ b/Source/CPack/OSXLauncherScript.scpt
Binary files differ
diff --git a/Source/CPack/OSXScriptLauncher.cxx b/Source/CPack/OSXScriptLauncher.cxx
new file mode 100644
index 0000000..bdaf779
--- /dev/null
+++ b/Source/CPack/OSXScriptLauncher.cxx
@@ -0,0 +1,122 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include <cstddef>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <cm/memory>
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Process.h"
+#include "cmsys/SystemTools.hxx"
+
+// For the PATH_MAX constant
+#include <sys/syslimits.h>
+
+#define DebugError(x) \
+ ofs << x << std::endl; \
+ std::cout << x << std::endl
+
+int main(int argc, char* argv[])
+{
+ // if ( cmsys::SystemTools::FileExists(
+ cmsys::ofstream ofs("/tmp/output.txt");
+
+ CFStringRef fileName;
+ CFBundleRef appBundle;
+ CFURLRef scriptFileURL;
+
+ // get CF URL for script
+ if (!(appBundle = CFBundleGetMainBundle())) {
+ DebugError("Cannot get main bundle");
+ return 1;
+ }
+ fileName = CFSTR("RuntimeScript");
+ if (!(scriptFileURL =
+ CFBundleCopyResourceURL(appBundle, fileName, nullptr, nullptr))) {
+ DebugError("CFBundleCopyResourceURL failed");
+ return 1;
+ }
+
+ // create path string
+ auto path = cm::make_unique<UInt8[]>(PATH_MAX);
+ if (!path) {
+ return 1;
+ }
+
+ // get the file system path of the url as a cstring
+ // in an encoding suitable for posix apis
+ if (!CFURLGetFileSystemRepresentation(scriptFileURL, true, path.get(),
+ PATH_MAX)) {
+ DebugError("CFURLGetFileSystemRepresentation failed");
+ return 1;
+ }
+
+ // dispose of the CF variable
+ CFRelease(scriptFileURL);
+
+ std::string fullScriptPath = reinterpret_cast<char*>(path.get());
+ path.reset();
+
+ if (!cmsys::SystemTools::FileExists(fullScriptPath)) {
+ return 1;
+ }
+
+ std::string scriptDirectory =
+ cmsys::SystemTools::GetFilenamePath(fullScriptPath);
+ ofs << fullScriptPath << std::endl;
+ std::vector<const char*> args;
+ args.push_back(fullScriptPath.c_str());
+ int cc;
+ for (cc = 1; cc < argc; ++cc) {
+ args.push_back(argv[cc]);
+ }
+ args.push_back(nullptr);
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, args.data());
+ cmsysProcess_SetWorkingDirectory(cp, scriptDirectory.c_str());
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ cmsysProcess_SetTimeout(cp, 0);
+ cmsysProcess_Execute(cp);
+
+ char* data;
+ int length;
+ while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
+ // Translate NULL characters in the output into valid text.
+ for (int i = 0; i < length; ++i) {
+ if (data[i] == '\0') {
+ data[i] = ' ';
+ }
+ }
+ std::cout.write(data, length);
+ }
+
+ cmsysProcess_WaitForExit(cp, nullptr);
+
+ bool result = true;
+ if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
+ if (cmsysProcess_GetExitValue(cp) != 0) {
+ result = false;
+ }
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) {
+ const char* exception_str = cmsysProcess_GetExceptionString(cp);
+ std::cerr << exception_str << std::endl;
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
+ const char* error_str = cmsysProcess_GetErrorString(cp);
+ std::cerr << error_str << std::endl;
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) {
+ const char* error_str = "Process terminated due to timeout\n";
+ std::cerr << error_str << std::endl;
+ result = false;
+ }
+
+ cmsysProcess_Delete(cp);
+
+ return 0;
+}
diff --git a/Source/CPack/WiX/cmCMakeToWixPath.cxx b/Source/CPack/WiX/cmCMakeToWixPath.cxx
new file mode 100644
index 0000000..8738501
--- /dev/null
+++ b/Source/CPack/WiX/cmCMakeToWixPath.cxx
@@ -0,0 +1,39 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCMakeToWixPath.h"
+
+#include <string>
+#include <vector>
+
+#include "cmStringAlgorithms.h"
+
+#ifdef __CYGWIN__
+# include <sys/cygwin.h>
+std::string CMakeToWixPath(const std::string& cygpath)
+{
+ std::vector<char> winpath_chars;
+ ssize_t winpath_size;
+
+ // Get the required buffer size.
+ winpath_size =
+ cygwin_conv_path(CCP_POSIX_TO_WIN_A, cygpath.c_str(), nullptr, 0);
+ if (winpath_size <= 0) {
+ return cygpath;
+ }
+
+ winpath_chars.assign(static_cast<size_t>(winpath_size) + 1, '\0');
+
+ winpath_size = cygwin_conv_path(CCP_POSIX_TO_WIN_A, cygpath.c_str(),
+ winpath_chars.data(), winpath_size);
+ if (winpath_size < 0) {
+ return cygpath;
+ }
+
+ return cmTrimWhitespace(winpath_chars.data());
+}
+#else
+std::string CMakeToWixPath(const std::string& path)
+{
+ return path;
+}
+#endif
diff --git a/Source/CPack/WiX/cmCMakeToWixPath.h b/Source/CPack/WiX/cmCMakeToWixPath.h
new file mode 100644
index 0000000..074cc8e
--- /dev/null
+++ b/Source/CPack/WiX/cmCMakeToWixPath.h
@@ -0,0 +1,9 @@
+/* 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 <string>
+
+std::string CMakeToWixPath(const std::string& cygpath);
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
new file mode 100644
index 0000000..8b3644f
--- /dev/null
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
@@ -0,0 +1,1217 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackWIXGenerator.h"
+
+#include <algorithm>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/algorithm>
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/Encoding.hxx"
+#include "cmsys/FStream.hxx"
+#include "cmsys/SystemTools.hxx"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmCryptoHash.h"
+#include "cmGeneratedFileStream.h"
+#include "cmInstalledFile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmUuid.h"
+#include "cmWIXDirectoriesSourceWriter.h"
+#include "cmWIXFeaturesSourceWriter.h"
+#include "cmWIXFilesSourceWriter.h"
+#include "cmWIXRichTextFormatWriter.h"
+#include "cmWIXSourceWriter.h"
+
+#ifdef _WIN32
+# include <rpc.h> // for GUID generation (windows only)
+#else
+# include <uuid/uuid.h> // for GUID generation (libuuid)
+#endif
+
+#include "cmCMakeToWixPath.h"
+
+cmCPackWIXGenerator::cmCPackWIXGenerator()
+ : ComponentGuidType(cmWIXSourceWriter::WIX_GENERATED_GUID)
+{
+}
+
+cmCPackWIXGenerator::~cmCPackWIXGenerator() = default;
+
+int cmCPackWIXGenerator::InitializeInternal()
+{
+ componentPackageMethod = ONE_PACKAGE;
+ this->Patch = cm::make_unique<cmWIXPatch>(this->Logger);
+
+ return this->Superclass::InitializeInternal();
+}
+
+bool cmCPackWIXGenerator::RunWiXCommand(std::string const& command)
+{
+ std::string logFileName = this->CPackTopLevel + "/wix.log";
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Running WiX command: " << command << std::endl);
+
+ std::string output;
+
+ int returnValue = 0;
+ bool status = cmSystemTools::RunSingleCommand(
+ command, &output, &output, &returnValue, 0, cmSystemTools::OUTPUT_NONE);
+
+ cmsys::ofstream logFile(logFileName.c_str(), std::ios::app);
+ logFile << command << std::endl;
+ logFile << output;
+ logFile.close();
+
+ if (!status || returnValue) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem running WiX candle. "
+ "Please check '"
+ << logFileName << "' for errors." << std::endl);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::RunCandleCommand(std::string const& sourceFile,
+ std::string const& objectFile)
+{
+ std::string executable;
+ if (!RequireOption("CPACK_WIX_CANDLE_EXECUTABLE", executable)) {
+ return false;
+ }
+
+ std::ostringstream command;
+ command << QuotePath(executable);
+ command << " -nologo";
+ command << " -arch " << GetArchitecture();
+ command << " -out " << QuotePath(objectFile);
+
+ for (std::string const& ext : CandleExtensions) {
+ command << " -ext " << QuotePath(ext);
+ }
+
+ if (!cmHasSuffix(sourceFile, this->CPackTopLevel)) {
+ command << " " << QuotePath("-I" + this->CPackTopLevel);
+ }
+
+ AddCustomFlags("CPACK_WIX_CANDLE_EXTRA_FLAGS", command);
+
+ command << " " << QuotePath(sourceFile);
+
+ return RunWiXCommand(command.str());
+}
+
+bool cmCPackWIXGenerator::RunLightCommand(std::string const& objectFiles)
+{
+ std::string executable;
+ if (!RequireOption("CPACK_WIX_LIGHT_EXECUTABLE", executable)) {
+ return false;
+ }
+
+ std::ostringstream command;
+ command << QuotePath(executable);
+ command << " -nologo";
+ command << " -out " << QuotePath(CMakeToWixPath(packageFileNames.at(0)));
+
+ for (std::string const& ext : this->LightExtensions) {
+ command << " -ext " << QuotePath(ext);
+ }
+
+ const char* const cultures = GetOption("CPACK_WIX_CULTURES");
+ if (cultures) {
+ command << " -cultures:" << cultures;
+ }
+
+ AddCustomFlags("CPACK_WIX_LIGHT_EXTRA_FLAGS", command);
+
+ command << " " << objectFiles;
+
+ return RunWiXCommand(command.str());
+}
+
+int cmCPackWIXGenerator::PackageFiles()
+{
+ if (!PackageFilesImpl() || cmSystemTools::GetErrorOccuredFlag()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Fatal WiX Generator Error" << std::endl);
+ return false;
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::InitializeWiXConfiguration()
+{
+ if (!ReadListFile("Internal/CPack/CPackWIX.cmake")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while executing CPackWIX.cmake" << std::endl);
+ return false;
+ }
+
+ if (GetOption("CPACK_WIX_PRODUCT_GUID") == 0) {
+ std::string guid = GenerateGUID();
+ SetOption("CPACK_WIX_PRODUCT_GUID", guid.c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "CPACK_WIX_PRODUCT_GUID implicitly set to " << guid << " . "
+ << std::endl);
+ }
+
+ if (GetOption("CPACK_WIX_UPGRADE_GUID") == 0) {
+ std::string guid = GenerateGUID();
+ SetOption("CPACK_WIX_UPGRADE_GUID", guid.c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "CPACK_WIX_UPGRADE_GUID implicitly set to "
+ << guid
+ << " . "
+ "Please refer to the documentation on how and why "
+ "you might want to set this explicitly."
+ << std::endl);
+ }
+
+ if (!RequireOption("CPACK_TOPLEVEL_DIRECTORY", this->CPackTopLevel)) {
+ return false;
+ }
+
+ if (GetOption("CPACK_WIX_LICENSE_RTF") == 0) {
+ std::string licenseFilename = this->CPackTopLevel + "/License.rtf";
+ SetOption("CPACK_WIX_LICENSE_RTF", licenseFilename.c_str());
+
+ if (!CreateLicenseFile()) {
+ return false;
+ }
+ }
+
+ if (GetOption("CPACK_PACKAGE_VENDOR") == 0) {
+ std::string defaultVendor = "Humanity";
+ SetOption("CPACK_PACKAGE_VENDOR", defaultVendor.c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "CPACK_PACKAGE_VENDOR implicitly set to "
+ << defaultVendor << " . " << std::endl);
+ }
+
+ if (GetOption("CPACK_WIX_UI_REF") == 0) {
+ std::string defaultRef = "WixUI_InstallDir";
+
+ if (!this->Components.empty()) {
+ defaultRef = "WixUI_FeatureTree";
+ }
+
+ SetOption("CPACK_WIX_UI_REF", defaultRef.c_str());
+ }
+
+ const char* packageContact = GetOption("CPACK_PACKAGE_CONTACT");
+ if (packageContact != 0 && GetOption("CPACK_WIX_PROPERTY_ARPCONTACT") == 0) {
+ SetOption("CPACK_WIX_PROPERTY_ARPCONTACT", packageContact);
+ }
+
+ CollectExtensions("CPACK_WIX_EXTENSIONS", this->CandleExtensions);
+ CollectExtensions("CPACK_WIX_CANDLE_EXTENSIONS", this->CandleExtensions);
+
+ this->LightExtensions.insert("WixUIExtension");
+ CollectExtensions("CPACK_WIX_EXTENSIONS", this->LightExtensions);
+ CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", this->LightExtensions);
+ CollectXmlNamespaces("CPACK_WIX_CUSTOM_XMLNS", this->CustomXmlNamespaces);
+
+ const char* patchFilePath = GetOption("CPACK_WIX_PATCH_FILE");
+ if (patchFilePath) {
+ std::vector<std::string> patchFilePaths = cmExpandedList(patchFilePath);
+
+ for (std::string const& p : patchFilePaths) {
+ if (!this->Patch->LoadFragments(p)) {
+ return false;
+ }
+ }
+ }
+
+ // if install folder is supposed to be set absolutely, the default
+ // component guid "*" cannot be used
+ if (cmIsOn(GetOption("CPACK_WIX_SKIP_PROGRAM_FOLDER"))) {
+ this->ComponentGuidType = cmWIXSourceWriter::CMAKE_GENERATED_GUID;
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::PackageFilesImpl()
+{
+ if (!InitializeWiXConfiguration()) {
+ return false;
+ }
+
+ CreateWiXVariablesIncludeFile();
+ CreateWiXPropertiesIncludeFile();
+ CreateWiXProductFragmentIncludeFile();
+
+ if (!CreateWiXSourceFiles()) {
+ return false;
+ }
+
+ AppendUserSuppliedExtraSources();
+
+ std::set<std::string> usedBaseNames;
+
+ std::ostringstream objectFiles;
+ for (std::string const& sourceFilename : this->WixSources) {
+ std::string baseName =
+ cmSystemTools::GetFilenameWithoutLastExtension(sourceFilename);
+
+ unsigned int counter = 0;
+ std::string uniqueBaseName = baseName;
+
+ while (usedBaseNames.find(uniqueBaseName) != usedBaseNames.end()) {
+ std::ostringstream tmp;
+ tmp << baseName << ++counter;
+ uniqueBaseName = tmp.str();
+ }
+
+ usedBaseNames.insert(uniqueBaseName);
+
+ std::string objectFilename =
+ this->CPackTopLevel + "/" + uniqueBaseName + ".wixobj";
+
+ if (!RunCandleCommand(CMakeToWixPath(sourceFilename),
+ CMakeToWixPath(objectFilename))) {
+ return false;
+ }
+
+ objectFiles << " " << QuotePath(CMakeToWixPath(objectFilename));
+ }
+
+ AppendUserSuppliedExtraObjects(objectFiles);
+
+ return RunLightCommand(objectFiles.str());
+}
+
+void cmCPackWIXGenerator::AppendUserSuppliedExtraSources()
+{
+ const char* cpackWixExtraSources = GetOption("CPACK_WIX_EXTRA_SOURCES");
+ if (!cpackWixExtraSources)
+ return;
+
+ cmExpandList(cpackWixExtraSources, this->WixSources);
+}
+
+void cmCPackWIXGenerator::AppendUserSuppliedExtraObjects(std::ostream& stream)
+{
+ const char* cpackWixExtraObjects = GetOption("CPACK_WIX_EXTRA_OBJECTS");
+ if (!cpackWixExtraObjects)
+ return;
+
+ std::vector<std::string> expandedExtraObjects =
+ cmExpandedList(cpackWixExtraObjects);
+
+ for (std::string const& obj : expandedExtraObjects) {
+ stream << " " << QuotePath(obj);
+ }
+}
+
+void cmCPackWIXGenerator::CreateWiXVariablesIncludeFile()
+{
+ std::string includeFilename = this->CPackTopLevel + "/cpack_variables.wxi";
+
+ cmWIXSourceWriter includeFile(this->Logger, includeFilename,
+ this->ComponentGuidType,
+ cmWIXSourceWriter::INCLUDE_ELEMENT_ROOT);
+ InjectXmlNamespaces(includeFile);
+
+ CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_GUID");
+ CopyDefinition(includeFile, "CPACK_WIX_UPGRADE_GUID");
+ CopyDefinition(includeFile, "CPACK_PACKAGE_VENDOR");
+ CopyDefinition(includeFile, "CPACK_PACKAGE_NAME");
+ CopyDefinition(includeFile, "CPACK_PACKAGE_VERSION");
+ CopyDefinition(includeFile, "CPACK_WIX_LICENSE_RTF", DefinitionType::PATH);
+ CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_ICON", DefinitionType::PATH);
+ CopyDefinition(includeFile, "CPACK_WIX_UI_BANNER", DefinitionType::PATH);
+ CopyDefinition(includeFile, "CPACK_WIX_UI_DIALOG", DefinitionType::PATH);
+ SetOptionIfNotSet("CPACK_WIX_PROGRAM_MENU_FOLDER",
+ GetOption("CPACK_PACKAGE_NAME"));
+ CopyDefinition(includeFile, "CPACK_WIX_PROGRAM_MENU_FOLDER");
+ CopyDefinition(includeFile, "CPACK_WIX_UI_REF");
+}
+
+void cmCPackWIXGenerator::CreateWiXPropertiesIncludeFile()
+{
+ std::string includeFilename = this->CPackTopLevel + "/properties.wxi";
+
+ cmWIXSourceWriter includeFile(this->Logger, includeFilename,
+ this->ComponentGuidType,
+ cmWIXSourceWriter::INCLUDE_ELEMENT_ROOT);
+ InjectXmlNamespaces(includeFile);
+
+ std::string prefix = "CPACK_WIX_PROPERTY_";
+ std::vector<std::string> options = GetOptions();
+
+ for (std::string const& name : options) {
+ if (cmHasPrefix(name, prefix)) {
+ std::string id = name.substr(prefix.length());
+ std::string value = GetOption(name.c_str());
+
+ includeFile.BeginElement("Property");
+ includeFile.AddAttribute("Id", id);
+ includeFile.AddAttribute("Value", value);
+ includeFile.EndElement("Property");
+ }
+ }
+
+ if (GetOption("CPACK_WIX_PROPERTY_ARPINSTALLLOCATION") == 0) {
+ includeFile.BeginElement("Property");
+ includeFile.AddAttribute("Id", "INSTALL_ROOT");
+ includeFile.AddAttribute("Secure", "yes");
+
+ includeFile.BeginElement("RegistrySearch");
+ includeFile.AddAttribute("Id", "FindInstallLocation");
+ includeFile.AddAttribute("Root", "HKLM");
+ includeFile.AddAttribute(
+ "Key",
+ "Software\\Microsoft\\Windows\\"
+ "CurrentVersion\\Uninstall\\[WIX_UPGRADE_DETECTED]");
+ includeFile.AddAttribute("Name", "InstallLocation");
+ includeFile.AddAttribute("Type", "raw");
+ includeFile.EndElement("RegistrySearch");
+ includeFile.EndElement("Property");
+
+ includeFile.BeginElement("SetProperty");
+ includeFile.AddAttribute("Id", "ARPINSTALLLOCATION");
+ includeFile.AddAttribute("Value", "[INSTALL_ROOT]");
+ includeFile.AddAttribute("After", "CostFinalize");
+ includeFile.EndElement("SetProperty");
+ }
+}
+
+void cmCPackWIXGenerator::CreateWiXProductFragmentIncludeFile()
+{
+ std::string includeFilename = this->CPackTopLevel + "/product_fragment.wxi";
+
+ cmWIXSourceWriter includeFile(this->Logger, includeFilename,
+ this->ComponentGuidType,
+ cmWIXSourceWriter::INCLUDE_ELEMENT_ROOT);
+ InjectXmlNamespaces(includeFile);
+
+ this->Patch->ApplyFragment("#PRODUCT", includeFile);
+}
+
+void cmCPackWIXGenerator::CopyDefinition(cmWIXSourceWriter& source,
+ std::string const& name,
+ DefinitionType type)
+{
+ const char* value = GetOption(name.c_str());
+ if (value) {
+ if (type == DefinitionType::PATH) {
+ AddDefinition(source, name, CMakeToWixPath(value));
+ } else {
+ AddDefinition(source, name, value);
+ }
+ }
+}
+
+void cmCPackWIXGenerator::AddDefinition(cmWIXSourceWriter& source,
+ std::string const& name,
+ std::string const& value)
+{
+ std::ostringstream tmp;
+ tmp << name << "=\"" << value << '"';
+
+ source.AddProcessingInstruction("define", tmp.str());
+}
+
+bool cmCPackWIXGenerator::CreateWiXSourceFiles()
+{
+ // if install folder is supposed to be set absolutely, the default
+ // component guid "*" cannot be used
+ std::string directoryDefinitionsFilename =
+ this->CPackTopLevel + "/directories.wxs";
+
+ this->WixSources.push_back(directoryDefinitionsFilename);
+
+ cmWIXDirectoriesSourceWriter directoryDefinitions(
+ this->Logger, directoryDefinitionsFilename, this->ComponentGuidType);
+ InjectXmlNamespaces(directoryDefinitions);
+ directoryDefinitions.BeginElement("Fragment");
+
+ std::string installRoot;
+ if (!RequireOption("CPACK_PACKAGE_INSTALL_DIRECTORY", installRoot)) {
+ return false;
+ }
+
+ directoryDefinitions.BeginElement("Directory");
+ directoryDefinitions.AddAttribute("Id", "TARGETDIR");
+ directoryDefinitions.AddAttribute("Name", "SourceDir");
+
+ size_t installRootSize =
+ directoryDefinitions.BeginInstallationPrefixDirectory(GetRootFolderId(),
+ installRoot);
+
+ std::string fileDefinitionsFilename = this->CPackTopLevel + "/files.wxs";
+
+ this->WixSources.push_back(fileDefinitionsFilename);
+
+ cmWIXFilesSourceWriter fileDefinitions(this->Logger, fileDefinitionsFilename,
+ this->ComponentGuidType);
+ InjectXmlNamespaces(fileDefinitions);
+
+ fileDefinitions.BeginElement("Fragment");
+
+ std::string featureDefinitionsFilename =
+ this->CPackTopLevel + "/features.wxs";
+
+ this->WixSources.push_back(featureDefinitionsFilename);
+
+ cmWIXFeaturesSourceWriter featureDefinitions(
+ this->Logger, featureDefinitionsFilename, this->ComponentGuidType);
+ InjectXmlNamespaces(featureDefinitions);
+
+ featureDefinitions.BeginElement("Fragment");
+
+ featureDefinitions.BeginElement("Feature");
+ featureDefinitions.AddAttribute("Id", "ProductFeature");
+ featureDefinitions.AddAttribute("Display", "expand");
+ featureDefinitions.AddAttribute("Absent", "disallow");
+ featureDefinitions.AddAttribute("ConfigurableDirectory", "INSTALL_ROOT");
+
+ std::string cpackPackageName;
+ if (!RequireOption("CPACK_PACKAGE_NAME", cpackPackageName)) {
+ return false;
+ }
+
+ std::string featureTitle = cpackPackageName;
+ if (const char* title = GetOption("CPACK_WIX_ROOT_FEATURE_TITLE")) {
+ featureTitle = title;
+ }
+ featureDefinitions.AddAttribute("Title", featureTitle);
+ if (const char* desc = GetOption("CPACK_WIX_ROOT_FEATURE_DESCRIPTION")) {
+ featureDefinitions.AddAttribute("Description", desc);
+ }
+ featureDefinitions.AddAttribute("Level", "1");
+ this->Patch->ApplyFragment("#PRODUCTFEATURE", featureDefinitions);
+
+ const char* package = GetOption("CPACK_WIX_CMAKE_PACKAGE_REGISTRY");
+ if (package) {
+ featureDefinitions.CreateCMakePackageRegistryEntry(
+ package, GetOption("CPACK_WIX_UPGRADE_GUID"));
+ }
+
+ if (!CreateFeatureHierarchy(featureDefinitions)) {
+ return false;
+ }
+
+ featureDefinitions.EndElement("Feature");
+
+ std::set<cmWIXShortcuts::Type> emittedShortcutTypes;
+
+ cmWIXShortcuts globalShortcuts;
+ if (Components.empty()) {
+ AddComponentsToFeature(toplevel, "ProductFeature", directoryDefinitions,
+ fileDefinitions, featureDefinitions,
+ globalShortcuts);
+
+ globalShortcuts.AddShortcutTypes(emittedShortcutTypes);
+ } else {
+ for (auto const& i : this->Components) {
+ cmCPackComponent const& component = i.second;
+
+ std::string componentPath = cmStrCat(toplevel, '/', component.Name);
+
+ std::string const componentFeatureId = "CM_C_" + component.Name;
+
+ cmWIXShortcuts featureShortcuts;
+ AddComponentsToFeature(componentPath, componentFeatureId,
+ directoryDefinitions, fileDefinitions,
+ featureDefinitions, featureShortcuts);
+
+ featureShortcuts.AddShortcutTypes(emittedShortcutTypes);
+
+ if (!CreateShortcuts(component.Name, componentFeatureId,
+ featureShortcuts, false, fileDefinitions,
+ featureDefinitions)) {
+ return false;
+ }
+ }
+ }
+
+ bool emitUninstallShortcut = true;
+ const char* cpackWixProgramMenuFolder =
+ GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER");
+ if (cpackWixProgramMenuFolder &&
+ cm::string_view(cpackWixProgramMenuFolder) == ".") {
+ emitUninstallShortcut = false;
+ } else if (emittedShortcutTypes.find(cmWIXShortcuts::START_MENU) ==
+ emittedShortcutTypes.end()) {
+ emitUninstallShortcut = false;
+ }
+
+ if (!CreateShortcuts(std::string(), "ProductFeature", globalShortcuts,
+ emitUninstallShortcut, fileDefinitions,
+ featureDefinitions)) {
+ return false;
+ }
+
+ featureDefinitions.EndElement("Fragment");
+ fileDefinitions.EndElement("Fragment");
+
+ directoryDefinitions.EndInstallationPrefixDirectory(installRootSize);
+
+ if (emittedShortcutTypes.find(cmWIXShortcuts::START_MENU) !=
+ emittedShortcutTypes.end()) {
+ directoryDefinitions.EmitStartMenuFolder(
+ GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER"));
+ }
+
+ if (emittedShortcutTypes.find(cmWIXShortcuts::DESKTOP) !=
+ emittedShortcutTypes.end()) {
+ directoryDefinitions.EmitDesktopFolder();
+ }
+
+ if (emittedShortcutTypes.find(cmWIXShortcuts::STARTUP) !=
+ emittedShortcutTypes.end()) {
+ directoryDefinitions.EmitStartupFolder();
+ }
+
+ directoryDefinitions.EndElement("Directory");
+ directoryDefinitions.EndElement("Fragment");
+
+ if (!GenerateMainSourceFileFromTemplate()) {
+ return false;
+ }
+
+ return this->Patch->CheckForUnappliedFragments();
+}
+
+std::string cmCPackWIXGenerator::GetRootFolderId() const
+{
+ if (cmIsOn(GetOption("CPACK_WIX_SKIP_PROGRAM_FOLDER"))) {
+ return "";
+ }
+
+ std::string result = "ProgramFiles<64>Folder";
+
+ const char* rootFolderId = GetOption("CPACK_WIX_ROOT_FOLDER_ID");
+ if (rootFolderId) {
+ result = rootFolderId;
+ }
+
+ if (GetArchitecture() == "x86") {
+ cmSystemTools::ReplaceString(result, "<64>", "");
+ } else {
+ cmSystemTools::ReplaceString(result, "<64>", "64");
+ }
+
+ return result;
+}
+
+bool cmCPackWIXGenerator::GenerateMainSourceFileFromTemplate()
+{
+ std::string wixTemplate = FindTemplate("WIX.template.in");
+ if (GetOption("CPACK_WIX_TEMPLATE") != 0) {
+ wixTemplate = GetOption("CPACK_WIX_TEMPLATE");
+ }
+
+ if (wixTemplate.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Could not find CPack WiX template file WIX.template.in"
+ << std::endl);
+ return false;
+ }
+
+ std::string mainSourceFilePath = this->CPackTopLevel + "/main.wxs";
+
+ if (!ConfigureFile(wixTemplate, mainSourceFilePath)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Failed creating '" << mainSourceFilePath
+ << "'' from template." << std::endl);
+
+ return false;
+ }
+
+ this->WixSources.push_back(mainSourceFilePath);
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::CreateFeatureHierarchy(
+ cmWIXFeaturesSourceWriter& featureDefinitions)
+{
+ for (auto const& i : ComponentGroups) {
+ cmCPackComponentGroup const& group = i.second;
+ if (group.ParentGroup == 0) {
+ featureDefinitions.EmitFeatureForComponentGroup(group, *this->Patch);
+ }
+ }
+
+ for (auto const& i : this->Components) {
+ cmCPackComponent const& component = i.second;
+
+ if (!component.Group) {
+ featureDefinitions.EmitFeatureForComponent(component, *this->Patch);
+ }
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::AddComponentsToFeature(
+ std::string const& rootPath, std::string const& featureId,
+ cmWIXDirectoriesSourceWriter& directoryDefinitions,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions, cmWIXShortcuts& shortcuts)
+{
+ featureDefinitions.BeginElement("FeatureRef");
+ featureDefinitions.AddAttribute("Id", featureId);
+
+ std::vector<std::string> cpackPackageExecutablesList;
+ const char* cpackPackageExecutables = GetOption("CPACK_PACKAGE_EXECUTABLES");
+ if (cpackPackageExecutables) {
+ cmExpandList(cpackPackageExecutables, cpackPackageExecutablesList);
+ if (cpackPackageExecutablesList.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
+ "<text label>."
+ << std::endl);
+ return false;
+ }
+ }
+
+ std::vector<std::string> cpackPackageDesktopLinksList;
+ const char* cpackPackageDesktopLinks =
+ GetOption("CPACK_CREATE_DESKTOP_LINKS");
+ if (cpackPackageDesktopLinks) {
+ cmExpandList(cpackPackageDesktopLinks, cpackPackageDesktopLinksList);
+ }
+
+ AddDirectoryAndFileDefinitions(
+ rootPath, "INSTALL_ROOT", directoryDefinitions, fileDefinitions,
+ featureDefinitions, cpackPackageExecutablesList,
+ cpackPackageDesktopLinksList, shortcuts);
+
+ featureDefinitions.EndElement("FeatureRef");
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::CreateShortcuts(
+ std::string const& cpackComponentName, std::string const& featureId,
+ cmWIXShortcuts const& shortcuts, bool emitUninstallShortcut,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions)
+{
+ if (!shortcuts.empty(cmWIXShortcuts::START_MENU)) {
+ if (!this->CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::START_MENU, cpackComponentName, featureId, "",
+ shortcuts, emitUninstallShortcut, fileDefinitions,
+ featureDefinitions)) {
+ return false;
+ }
+ }
+
+ if (!shortcuts.empty(cmWIXShortcuts::DESKTOP)) {
+ if (!this->CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::DESKTOP, cpackComponentName, featureId, "DESKTOP",
+ shortcuts, false, fileDefinitions, featureDefinitions)) {
+ return false;
+ }
+ }
+
+ if (!shortcuts.empty(cmWIXShortcuts::STARTUP)) {
+ if (!this->CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::STARTUP, cpackComponentName, featureId, "STARTUP",
+ shortcuts, false, fileDefinitions, featureDefinitions)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::Type type, std::string const& cpackComponentName,
+ std::string const& featureId, std::string const& idPrefix,
+ cmWIXShortcuts const& shortcuts, bool emitUninstallShortcut,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions)
+{
+ std::string directoryId;
+ switch (type) {
+ case cmWIXShortcuts::START_MENU: {
+ const char* cpackWixProgramMenuFolder =
+ GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER");
+ if (cpackWixProgramMenuFolder &&
+ cm::string_view(cpackWixProgramMenuFolder) == ".") {
+ directoryId = "ProgramMenuFolder";
+ } else {
+ directoryId = "PROGRAM_MENU_FOLDER";
+ }
+ } break;
+ case cmWIXShortcuts::DESKTOP:
+ directoryId = "DesktopFolder";
+ break;
+ case cmWIXShortcuts::STARTUP:
+ directoryId = "StartupFolder";
+ break;
+ default:
+ return false;
+ }
+
+ featureDefinitions.BeginElement("FeatureRef");
+ featureDefinitions.AddAttribute("Id", featureId);
+
+ std::string cpackVendor;
+ if (!RequireOption("CPACK_PACKAGE_VENDOR", cpackVendor)) {
+ return false;
+ }
+
+ std::string cpackPackageName;
+ if (!RequireOption("CPACK_PACKAGE_NAME", cpackPackageName)) {
+ return false;
+ }
+
+ std::string idSuffix;
+ if (!cpackComponentName.empty()) {
+ idSuffix += "_";
+ idSuffix += cpackComponentName;
+ }
+
+ std::string componentId = "CM_SHORTCUT";
+ if (idPrefix.size()) {
+ componentId += "_" + idPrefix;
+ }
+
+ componentId += idSuffix;
+
+ fileDefinitions.BeginElement("DirectoryRef");
+ fileDefinitions.AddAttribute("Id", directoryId);
+
+ fileDefinitions.BeginElement("Component");
+ fileDefinitions.AddAttribute("Id", componentId);
+ fileDefinitions.AddAttribute(
+ "Guid", fileDefinitions.CreateGuidFromComponentId(componentId));
+
+ this->Patch->ApplyFragment(componentId, fileDefinitions);
+
+ std::string registryKey =
+ std::string("Software\\") + cpackVendor + "\\" + cpackPackageName;
+
+ shortcuts.EmitShortcuts(type, registryKey, cpackComponentName,
+ fileDefinitions);
+
+ if (type == cmWIXShortcuts::START_MENU) {
+ const char* cpackWixProgramMenuFolder =
+ GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER");
+ if (cpackWixProgramMenuFolder &&
+ cm::string_view(cpackWixProgramMenuFolder) != ".") {
+ fileDefinitions.EmitRemoveFolder("CM_REMOVE_PROGRAM_MENU_FOLDER" +
+ idSuffix);
+ }
+ }
+
+ if (emitUninstallShortcut) {
+ fileDefinitions.EmitUninstallShortcut(cpackPackageName);
+ }
+
+ fileDefinitions.EndElement("Component");
+ fileDefinitions.EndElement("DirectoryRef");
+
+ featureDefinitions.EmitComponentRef(componentId);
+ featureDefinitions.EndElement("FeatureRef");
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::CreateLicenseFile()
+{
+ std::string licenseSourceFilename;
+ if (!RequireOption("CPACK_RESOURCE_FILE_LICENSE", licenseSourceFilename)) {
+ return false;
+ }
+
+ std::string licenseDestinationFilename;
+ if (!RequireOption("CPACK_WIX_LICENSE_RTF", licenseDestinationFilename)) {
+ return false;
+ }
+
+ std::string extension = GetRightmostExtension(licenseSourceFilename);
+
+ if (extension == ".rtf") {
+ cmSystemTools::CopyAFile(licenseSourceFilename.c_str(),
+ licenseDestinationFilename.c_str());
+ } else if (extension == ".txt") {
+ cmWIXRichTextFormatWriter rtfWriter(licenseDestinationFilename);
+
+ cmsys::ifstream licenseSource(licenseSourceFilename.c_str());
+
+ std::string line;
+ while (std::getline(licenseSource, line)) {
+ rtfWriter.AddText(line);
+ rtfWriter.AddText("\n");
+ }
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "unsupported WiX License file extension '"
+ << extension << "'" << std::endl);
+
+ return false;
+ }
+
+ return true;
+}
+
+void cmCPackWIXGenerator::AddDirectoryAndFileDefinitions(
+ std::string const& topdir, std::string const& directoryId,
+ cmWIXDirectoriesSourceWriter& directoryDefinitions,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions,
+ std::vector<std::string> const& packageExecutables,
+ std::vector<std::string> const& desktopExecutables,
+ cmWIXShortcuts& shortcuts)
+{
+ cmsys::Directory dir;
+ dir.Load(topdir.c_str());
+
+ std::string relativeDirectoryPath =
+ cmSystemTools::RelativePath(toplevel.c_str(), topdir.c_str());
+
+ if (relativeDirectoryPath.empty()) {
+ relativeDirectoryPath = ".";
+ }
+
+ cmInstalledFile const* directoryInstalledFile = this->GetInstalledFile(
+ this->RelativePathWithoutComponentPrefix(relativeDirectoryPath));
+
+ bool emptyDirectory = dir.GetNumberOfFiles() == 2;
+ bool createDirectory = false;
+
+ if (emptyDirectory) {
+ createDirectory = true;
+ }
+
+ if (directoryInstalledFile) {
+ if (directoryInstalledFile->HasProperty("CPACK_WIX_ACL")) {
+ createDirectory = true;
+ }
+ }
+
+ if (createDirectory) {
+ std::string componentId = fileDefinitions.EmitComponentCreateFolder(
+ directoryId, GenerateGUID(), directoryInstalledFile);
+ featureDefinitions.EmitComponentRef(componentId);
+ }
+
+ if (emptyDirectory) {
+ return;
+ }
+
+ for (size_t i = 0; i < dir.GetNumberOfFiles(); ++i) {
+ std::string fileName = dir.GetFile(static_cast<unsigned long>(i));
+
+ if (fileName == "." || fileName == "..") {
+ continue;
+ }
+
+ std::string fullPath = topdir + "/" + fileName;
+
+ std::string relativePath =
+ cmSystemTools::RelativePath(toplevel.c_str(), fullPath.c_str());
+
+ std::string id = PathToId(relativePath);
+
+ if (cmSystemTools::FileIsDirectory(fullPath.c_str())) {
+ std::string subDirectoryId = std::string("CM_D") + id;
+
+ directoryDefinitions.BeginElement("Directory");
+ directoryDefinitions.AddAttribute("Id", subDirectoryId);
+ directoryDefinitions.AddAttribute("Name", fileName);
+ this->Patch->ApplyFragment(subDirectoryId, directoryDefinitions);
+
+ AddDirectoryAndFileDefinitions(
+ fullPath, subDirectoryId, directoryDefinitions, fileDefinitions,
+ featureDefinitions, packageExecutables, desktopExecutables, shortcuts);
+
+ directoryDefinitions.EndElement("Directory");
+ } else {
+ cmInstalledFile const* installedFile = this->GetInstalledFile(
+ this->RelativePathWithoutComponentPrefix(relativePath));
+
+ if (installedFile) {
+ shortcuts.CreateFromProperties(id, directoryId, *installedFile);
+ }
+
+ std::string componentId = fileDefinitions.EmitComponentFile(
+ directoryId, id, fullPath, *(this->Patch), installedFile);
+
+ featureDefinitions.EmitComponentRef(componentId);
+
+ for (size_t j = 0; j < packageExecutables.size(); ++j) {
+ std::string const& executableName = packageExecutables[j++];
+ std::string const& textLabel = packageExecutables[j];
+
+ if (cmSystemTools::LowerCase(fileName) ==
+ cmSystemTools::LowerCase(executableName) + ".exe") {
+ cmWIXShortcut shortcut;
+ shortcut.label = textLabel;
+ shortcut.workingDirectoryId = directoryId;
+ shortcuts.insert(cmWIXShortcuts::START_MENU, id, shortcut);
+
+ if (cm::contains(desktopExecutables, executableName)) {
+ shortcuts.insert(cmWIXShortcuts::DESKTOP, id, shortcut);
+ }
+ }
+ }
+ }
+ }
+}
+
+bool cmCPackWIXGenerator::RequireOption(std::string const& name,
+ std::string& value) const
+{
+ const char* tmp = GetOption(name.c_str());
+ if (tmp) {
+ value = tmp;
+
+ return true;
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Required variable " << name << " not set" << std::endl);
+
+ return false;
+ }
+}
+
+std::string cmCPackWIXGenerator::GetArchitecture() const
+{
+ std::string void_p_size;
+ RequireOption("CPACK_WIX_SIZEOF_VOID_P", void_p_size);
+
+ if (void_p_size == "8") {
+ return "x64";
+ } else {
+ return "x86";
+ }
+}
+
+std::string cmCPackWIXGenerator::GenerateGUID()
+{
+#ifdef _WIN32
+ UUID guid;
+ UuidCreate(&guid);
+
+ unsigned short* tmp = 0;
+ UuidToStringW(&guid, &tmp);
+
+ std::string result =
+ cmsys::Encoding::ToNarrow(reinterpret_cast<wchar_t*>(tmp));
+ RpcStringFreeW(&tmp);
+#else
+ uuid_t guid;
+ char guid_ch[37] = { 0 };
+
+ uuid_generate(guid);
+ uuid_unparse(guid, guid_ch);
+ std::string result = guid_ch;
+#endif
+
+ return cmSystemTools::UpperCase(result);
+}
+
+std::string cmCPackWIXGenerator::QuotePath(std::string const& path)
+{
+ return std::string("\"") + path + '"';
+}
+
+std::string cmCPackWIXGenerator::GetRightmostExtension(
+ std::string const& filename)
+{
+ std::string extension;
+
+ std::string::size_type i = filename.rfind(".");
+ if (i != std::string::npos) {
+ extension = filename.substr(i);
+ }
+
+ return cmSystemTools::LowerCase(extension);
+}
+
+std::string cmCPackWIXGenerator::PathToId(std::string const& path)
+{
+ id_map_t::const_iterator i = PathToIdMap.find(path);
+ if (i != PathToIdMap.end())
+ return i->second;
+
+ std::string id = CreateNewIdForPath(path);
+ return id;
+}
+
+std::string cmCPackWIXGenerator::CreateNewIdForPath(std::string const& path)
+{
+ std::vector<std::string> components;
+ cmSystemTools::SplitPath(path.c_str(), components, false);
+
+ size_t replacementCount = 0;
+
+ std::string identifier;
+ std::string currentComponent;
+
+ for (size_t i = 1; i < components.size(); ++i) {
+ if (i != 1)
+ identifier += '.';
+
+ currentComponent =
+ NormalizeComponentForId(components[i], replacementCount);
+
+ identifier += currentComponent;
+ }
+
+ std::string idPrefix = "P";
+ size_t replacementPercent = replacementCount * 100 / identifier.size();
+ if (replacementPercent > 33 || identifier.size() > 60) {
+ identifier = CreateHashedId(path, currentComponent);
+ idPrefix = "H";
+ }
+
+ std::ostringstream result;
+ result << idPrefix << "_" << identifier;
+
+ size_t ambiguityCount = ++IdAmbiguityCounter[identifier];
+
+ if (ambiguityCount > 999) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while trying to generate a unique Id for '"
+ << path << "'" << std::endl);
+
+ return std::string();
+ } else if (ambiguityCount > 1) {
+ result << "_" << ambiguityCount;
+ }
+
+ std::string resultString = result.str();
+
+ PathToIdMap[path] = resultString;
+
+ return resultString;
+}
+
+std::string cmCPackWIXGenerator::CreateHashedId(
+ std::string const& path, std::string const& normalizedFilename)
+{
+ cmCryptoHash sha1(cmCryptoHash::AlgoSHA1);
+ std::string const hash = sha1.HashString(path);
+
+ const size_t maxFileNameLength = 52;
+ std::string identifier =
+ cmStrCat(cm::string_view(hash).substr(0, 7), '_',
+ cm::string_view(normalizedFilename).substr(0, maxFileNameLength));
+
+ // if the name was truncated
+ if (normalizedFilename.length() > maxFileNameLength) {
+ identifier += "...";
+ }
+
+ return identifier;
+}
+
+std::string cmCPackWIXGenerator::NormalizeComponentForId(
+ std::string const& component, size_t& replacementCount)
+{
+ std::string result;
+ result.resize(component.size());
+
+ for (size_t i = 0; i < component.size(); ++i) {
+ char c = component[i];
+ if (IsLegalIdCharacter(c)) {
+ result[i] = c;
+ } else {
+ result[i] = '_';
+ ++replacementCount;
+ }
+ }
+
+ return result;
+}
+
+bool cmCPackWIXGenerator::IsLegalIdCharacter(char c)
+{
+ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') || c == '_' || c == '.';
+}
+
+void cmCPackWIXGenerator::CollectExtensions(std::string const& variableName,
+ extension_set_t& extensions)
+{
+ const char* variableContent = GetOption(variableName.c_str());
+ if (!variableContent)
+ return;
+
+ std::vector<std::string> list = cmExpandedList(variableContent);
+ extensions.insert(list.begin(), list.end());
+}
+
+void cmCPackWIXGenerator::CollectXmlNamespaces(std::string const& variableName,
+ xmlns_map_t& namespaces)
+{
+ const char* variableContent = GetOption(variableName.c_str());
+ if (!variableContent) {
+ return;
+ }
+
+ std::vector<std::string> list = cmExpandedList(variableContent);
+ for (std::string const& str : list) {
+ auto pos = str.find('=');
+ if (pos != std::string::npos) {
+ auto name = str.substr(0, pos);
+ auto value = str.substr(pos + 1);
+ namespaces.emplace(std::make_pair(name, value));
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Invalid element in CPACK_WIX_CUSTOM_XMLNS ignored: "
+ << "\"" << str << "\"" << std::endl);
+ }
+ }
+ std::ostringstream oss;
+ for (auto& ns : namespaces) {
+ oss << " xmlns:" << ns.first << "=\""
+ << cmWIXSourceWriter::EscapeAttributeValue(ns.second) << '"';
+ }
+ SetOption("CPACK_WIX_CUSTOM_XMLNS_EXPANDED", oss.str().c_str());
+}
+
+void cmCPackWIXGenerator::AddCustomFlags(std::string const& variableName,
+ std::ostream& stream)
+{
+ const char* variableContent = GetOption(variableName.c_str());
+ if (!variableContent)
+ return;
+
+ std::vector<std::string> list = cmExpandedList(variableContent);
+
+ for (std::string const& i : list) {
+ stream << " " << QuotePath(i);
+ }
+}
+
+std::string cmCPackWIXGenerator::RelativePathWithoutComponentPrefix(
+ std::string const& path)
+{
+ if (this->Components.empty()) {
+ return path;
+ }
+
+ std::string::size_type pos = path.find('/');
+
+ return path.substr(pos + 1);
+}
+
+void cmCPackWIXGenerator::InjectXmlNamespaces(cmWIXSourceWriter& sourceWriter)
+{
+ for (auto& ns : this->CustomXmlNamespaces) {
+ sourceWriter.AddAttributeUnlessEmpty("xmlns:" + ns.first, ns.second);
+ }
+}
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h
new file mode 100644
index 0000000..8609cf3
--- /dev/null
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.h
@@ -0,0 +1,172 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "cmCPackGenerator.h"
+#include "cmWIXPatch.h"
+#include "cmWIXShortcut.h"
+
+class cmWIXSourceWriter;
+class cmWIXDirectoriesSourceWriter;
+class cmWIXFilesSourceWriter;
+class cmWIXFeaturesSourceWriter;
+
+/** \class cmCPackWIXGenerator
+ * \brief A generator for WIX files
+ */
+class cmCPackWIXGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackWIXGenerator, cmCPackGenerator);
+
+ cmCPackWIXGenerator();
+ cmCPackWIXGenerator(const cmCPackWIXGenerator&) = delete;
+ const cmCPackWIXGenerator& operator=(const cmCPackWIXGenerator&) = delete;
+ ~cmCPackWIXGenerator();
+
+protected:
+ int InitializeInternal() override;
+
+ int PackageFiles() override;
+
+ const char* GetOutputExtension() override { return ".msi"; }
+
+ enum CPackSetDestdirSupport SupportsSetDestdir() const override
+ {
+ return SETDESTDIR_UNSUPPORTED;
+ }
+
+ bool SupportsAbsoluteDestination() const override { return false; }
+
+ bool SupportsComponentInstallation() const override { return true; }
+
+private:
+ using id_map_t = std::map<std::string, std::string>;
+ using ambiguity_map_t = std::map<std::string, size_t>;
+ using extension_set_t = std::set<std::string>;
+ using xmlns_map_t = std::map<std::string, std::string>;
+
+ enum class DefinitionType
+ {
+ STRING,
+ PATH
+ };
+
+ bool InitializeWiXConfiguration();
+
+ bool PackageFilesImpl();
+
+ void CreateWiXVariablesIncludeFile();
+
+ void CreateWiXPropertiesIncludeFile();
+
+ void CreateWiXProductFragmentIncludeFile();
+
+ void CopyDefinition(cmWIXSourceWriter& source, std::string const& name,
+ DefinitionType type = DefinitionType::STRING);
+
+ void AddDefinition(cmWIXSourceWriter& source, std::string const& name,
+ std::string const& value);
+
+ bool CreateWiXSourceFiles();
+
+ std::string GetRootFolderId() const;
+
+ bool GenerateMainSourceFileFromTemplate();
+
+ bool CreateFeatureHierarchy(cmWIXFeaturesSourceWriter& featureDefinitions);
+
+ bool AddComponentsToFeature(
+ std::string const& rootPath, std::string const& featureId,
+ cmWIXDirectoriesSourceWriter& directoryDefinitions,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions, cmWIXShortcuts& shortcuts);
+
+ bool CreateShortcuts(std::string const& cpackComponentName,
+ std::string const& featureId,
+ cmWIXShortcuts const& shortcuts,
+ bool emitUninstallShortcut,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions);
+
+ bool CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::Type type, std::string const& cpackComponentName,
+ std::string const& featureId, std::string const& idPrefix,
+ cmWIXShortcuts const& shortcuts, bool emitUninstallShortcut,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions);
+
+ void AppendUserSuppliedExtraSources();
+
+ void AppendUserSuppliedExtraObjects(std::ostream& stream);
+
+ bool CreateLicenseFile();
+
+ bool RunWiXCommand(std::string const& command);
+
+ bool RunCandleCommand(std::string const& sourceFile,
+ std::string const& objectFile);
+
+ bool RunLightCommand(std::string const& objectFiles);
+
+ void AddDirectoryAndFileDefinitions(
+ std::string const& topdir, std::string const& directoryId,
+ cmWIXDirectoriesSourceWriter& directoryDefinitions,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions,
+ std::vector<std::string> const& packageExecutables,
+ std::vector<std::string> const& desktopExecutables,
+ cmWIXShortcuts& shortcuts);
+
+ bool RequireOption(std::string const& name, std::string& value) const;
+
+ std::string GetArchitecture() const;
+
+ static std::string GenerateGUID();
+
+ static std::string QuotePath(std::string const& path);
+
+ static std::string GetRightmostExtension(std::string const& filename);
+
+ std::string PathToId(std::string const& path);
+
+ std::string CreateNewIdForPath(std::string const& path);
+
+ static std::string CreateHashedId(std::string const& path,
+ std::string const& normalizedFilename);
+
+ std::string NormalizeComponentForId(std::string const& component,
+ size_t& replacementCount);
+
+ static bool IsLegalIdCharacter(char c);
+
+ void CollectExtensions(std::string const& variableName,
+ extension_set_t& extensions);
+
+ void CollectXmlNamespaces(std::string const& variableName,
+ xmlns_map_t& namespaces);
+
+ void AddCustomFlags(std::string const& variableName, std::ostream& stream);
+
+ std::string RelativePathWithoutComponentPrefix(std::string const& path);
+
+ void InjectXmlNamespaces(cmWIXSourceWriter& sourceWriter);
+
+ std::vector<std::string> WixSources;
+ id_map_t PathToIdMap;
+ ambiguity_map_t IdAmbiguityCounter;
+
+ extension_set_t CandleExtensions;
+ extension_set_t LightExtensions;
+ xmlns_map_t CustomXmlNamespaces;
+
+ std::string CPackTopLevel;
+
+ std::unique_ptr<cmWIXPatch> Patch;
+
+ cmWIXSourceWriter::GuidType ComponentGuidType;
+};
diff --git a/Source/CPack/WiX/cmWIXAccessControlList.cxx b/Source/CPack/WiX/cmWIXAccessControlList.cxx
new file mode 100644
index 0000000..9685a7f
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXAccessControlList.cxx
@@ -0,0 +1,128 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmWIXAccessControlList.h"
+
+#include <cm/string_view>
+
+#include "cmCPackGenerator.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmWIXAccessControlList::cmWIXAccessControlList(
+ cmCPackLog* logger, cmInstalledFile const& installedFile,
+ cmWIXSourceWriter& sourceWriter)
+ : Logger(logger)
+ , InstalledFile(installedFile)
+ , SourceWriter(sourceWriter)
+{
+}
+
+bool cmWIXAccessControlList::Apply()
+{
+ std::vector<std::string> entries;
+ this->InstalledFile.GetPropertyAsList("CPACK_WIX_ACL", entries);
+
+ for (std::string const& entry : entries) {
+ this->CreatePermissionElement(entry);
+ }
+
+ return true;
+}
+
+void cmWIXAccessControlList::CreatePermissionElement(std::string const& entry)
+{
+ std::string::size_type pos = entry.find('=');
+ if (pos == std::string::npos) {
+ this->ReportError(entry, "Did not find mandatory '='");
+ return;
+ }
+
+ cm::string_view enview(entry);
+ cm::string_view user_and_domain = enview.substr(0, pos);
+ cm::string_view permission_string = enview.substr(pos + 1);
+
+ pos = user_and_domain.find('@');
+ cm::string_view user;
+ cm::string_view domain;
+ if (pos != std::string::npos) {
+ user = user_and_domain.substr(0, pos);
+ domain = user_and_domain.substr(pos + 1);
+ } else {
+ user = user_and_domain;
+ }
+
+ std::vector<std::string> permissions = cmTokenize(permission_string, ",");
+
+ this->SourceWriter.BeginElement("Permission");
+ this->SourceWriter.AddAttribute("User", std::string(user));
+ if (!domain.empty()) {
+ this->SourceWriter.AddAttribute("Domain", std::string(domain));
+ }
+ for (std::string const& permission : permissions) {
+ this->EmitBooleanAttribute(entry, cmTrimWhitespace(permission));
+ }
+ this->SourceWriter.EndElement("Permission");
+}
+
+void cmWIXAccessControlList::ReportError(std::string const& entry,
+ std::string const& message)
+{
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Failed processing ACL entry '" << entry << "': " << message
+ << std::endl);
+}
+
+bool cmWIXAccessControlList::IsBooleanAttribute(std::string const& name)
+{
+ static const char* validAttributes[] = {
+ /* clang-format needs this comment to break after the opening brace */
+ "Append",
+ "ChangePermission",
+ "CreateChild",
+ "CreateFile",
+ "CreateLink",
+ "CreateSubkeys",
+ "Delete",
+ "DeleteChild",
+ "EnumerateSubkeys",
+ "Execute",
+ "FileAllRights",
+ "GenericAll",
+ "GenericExecute",
+ "GenericRead",
+ "GenericWrite",
+ "Notify",
+ "Read",
+ "ReadAttributes",
+ "ReadExtendedAttributes",
+ "ReadPermission",
+ "SpecificRightsAll",
+ "Synchronize",
+ "TakeOwnership",
+ "Traverse",
+ "Write",
+ "WriteAttributes",
+ "WriteExtendedAttributes",
+ 0
+ };
+
+ size_t i = 0;
+ while (validAttributes[i]) {
+ if (name == validAttributes[i++])
+ return true;
+ }
+
+ return false;
+}
+
+void cmWIXAccessControlList::EmitBooleanAttribute(std::string const& entry,
+ std::string const& name)
+{
+ if (!this->IsBooleanAttribute(name)) {
+ std::ostringstream message;
+ message << "Unknown boolean attribute '" << name << "'";
+ this->ReportError(entry, message.str());
+ }
+
+ this->SourceWriter.AddAttribute(name, "yes");
+}
diff --git a/Source/CPack/WiX/cmWIXAccessControlList.h b/Source/CPack/WiX/cmWIXAccessControlList.h
new file mode 100644
index 0000000..ee5efa5
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXAccessControlList.h
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmCPackLog.h"
+#include "cmInstalledFile.h"
+#include "cmWIXSourceWriter.h"
+
+class cmWIXAccessControlList
+{
+public:
+ cmWIXAccessControlList(cmCPackLog* logger,
+ cmInstalledFile const& installedFile,
+ cmWIXSourceWriter& sourceWriter);
+
+ bool Apply();
+
+private:
+ void CreatePermissionElement(std::string const& entry);
+
+ void ReportError(std::string const& entry, std::string const& message);
+
+ bool IsBooleanAttribute(std::string const& name);
+
+ void EmitBooleanAttribute(std::string const& entry, std::string const& name);
+
+ cmCPackLog* Logger;
+ cmInstalledFile const& InstalledFile;
+ cmWIXSourceWriter& SourceWriter;
+};
diff --git a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx
new file mode 100644
index 0000000..0a83ca2
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx
@@ -0,0 +1,84 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmWIXDirectoriesSourceWriter.h"
+
+cmWIXDirectoriesSourceWriter::cmWIXDirectoriesSourceWriter(
+ cmCPackLog* logger, std::string const& filename, GuidType componentGuidType)
+ : cmWIXSourceWriter(logger, filename, componentGuidType)
+{
+}
+
+void cmWIXDirectoriesSourceWriter::EmitStartMenuFolder(
+ std::string const& startMenuFolder)
+{
+ BeginElement("Directory");
+ AddAttribute("Id", "ProgramMenuFolder");
+
+ if (startMenuFolder != ".") {
+ BeginElement("Directory");
+ AddAttribute("Id", "PROGRAM_MENU_FOLDER");
+ AddAttribute("Name", startMenuFolder);
+ EndElement("Directory");
+ }
+
+ EndElement("Directory");
+}
+
+void cmWIXDirectoriesSourceWriter::EmitDesktopFolder()
+{
+ BeginElement("Directory");
+ AddAttribute("Id", "DesktopFolder");
+ AddAttribute("Name", "Desktop");
+ EndElement("Directory");
+}
+
+void cmWIXDirectoriesSourceWriter::EmitStartupFolder()
+{
+ BeginElement("Directory");
+ AddAttribute("Id", "StartupFolder");
+ AddAttribute("Name", "Startup");
+ EndElement("Directory");
+}
+
+size_t cmWIXDirectoriesSourceWriter::BeginInstallationPrefixDirectory(
+ std::string const& programFilesFolderId,
+ std::string const& installRootString)
+{
+ size_t offset = 1;
+ if (!programFilesFolderId.empty()) {
+ BeginElement("Directory");
+ AddAttribute("Id", programFilesFolderId);
+ offset = 0;
+ }
+
+ std::vector<std::string> installRoot;
+
+ cmSystemTools::SplitPath(installRootString.c_str(), installRoot);
+
+ if (!installRoot.empty() && installRoot.back().empty()) {
+ installRoot.pop_back();
+ }
+
+ for (size_t i = 1; i < installRoot.size(); ++i) {
+ BeginElement("Directory");
+
+ if (i == installRoot.size() - 1) {
+ AddAttribute("Id", "INSTALL_ROOT");
+ } else {
+ std::ostringstream tmp;
+ tmp << "INSTALL_PREFIX_" << i;
+ AddAttribute("Id", tmp.str());
+ }
+
+ AddAttribute("Name", installRoot[i]);
+ }
+
+ return installRoot.size() - offset;
+}
+
+void cmWIXDirectoriesSourceWriter::EndInstallationPrefixDirectory(size_t size)
+{
+ for (size_t i = 0; i < size; ++i) {
+ EndElement("Directory");
+ }
+}
diff --git a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h
new file mode 100644
index 0000000..0af3094
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+
+#include "cmCPackGenerator.h"
+#include "cmWIXSourceWriter.h"
+
+/** \class cmWIXDirectoriesSourceWriter
+ * \brief Helper class to generate directories.wxs
+ */
+class cmWIXDirectoriesSourceWriter : public cmWIXSourceWriter
+{
+public:
+ cmWIXDirectoriesSourceWriter(cmCPackLog* logger, std::string const& filename,
+ GuidType componentGuidType);
+
+ void EmitStartMenuFolder(std::string const& startMenuFolder);
+
+ void EmitDesktopFolder();
+
+ void EmitStartupFolder();
+
+ size_t BeginInstallationPrefixDirectory(
+ std::string const& programFilesFolderId,
+ std::string const& installRootString);
+
+ void EndInstallationPrefixDirectory(size_t size);
+};
diff --git a/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx
new file mode 100644
index 0000000..a7a0648
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx
@@ -0,0 +1,91 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmWIXFeaturesSourceWriter.h"
+
+cmWIXFeaturesSourceWriter::cmWIXFeaturesSourceWriter(
+ cmCPackLog* logger, std::string const& filename, GuidType componentGuidType)
+ : cmWIXSourceWriter(logger, filename, componentGuidType)
+{
+}
+
+void cmWIXFeaturesSourceWriter::CreateCMakePackageRegistryEntry(
+ std::string const& package, std::string const& upgradeGuid)
+{
+ BeginElement("Component");
+ AddAttribute("Id", "CM_PACKAGE_REGISTRY");
+ AddAttribute("Directory", "TARGETDIR");
+ AddAttribute("Guid", CreateGuidFromComponentId("CM_PACKAGE_REGISTRY"));
+
+ std::string registryKey =
+ std::string("Software\\Kitware\\CMake\\Packages\\") + package;
+
+ BeginElement("RegistryValue");
+ AddAttribute("Root", "HKLM");
+ AddAttribute("Key", registryKey);
+ AddAttribute("Name", upgradeGuid);
+ AddAttribute("Type", "string");
+ AddAttribute("Value", "[INSTALL_ROOT]");
+ AddAttribute("KeyPath", "yes");
+ EndElement("RegistryValue");
+
+ EndElement("Component");
+}
+
+void cmWIXFeaturesSourceWriter::EmitFeatureForComponentGroup(
+ cmCPackComponentGroup const& group, cmWIXPatch& patch)
+{
+ BeginElement("Feature");
+ AddAttribute("Id", "CM_G_" + group.Name);
+
+ if (group.IsExpandedByDefault) {
+ AddAttribute("Display", "expand");
+ }
+
+ AddAttributeUnlessEmpty("Title", group.DisplayName);
+ AddAttributeUnlessEmpty("Description", group.Description);
+
+ patch.ApplyFragment("CM_G_" + group.Name, *this);
+
+ for (cmCPackComponentGroup* subgroup : group.Subgroups) {
+ EmitFeatureForComponentGroup(*subgroup, patch);
+ }
+
+ for (cmCPackComponent* component : group.Components) {
+ EmitFeatureForComponent(*component, patch);
+ }
+
+ EndElement("Feature");
+}
+
+void cmWIXFeaturesSourceWriter::EmitFeatureForComponent(
+ cmCPackComponent const& component, cmWIXPatch& patch)
+{
+ BeginElement("Feature");
+ AddAttribute("Id", "CM_C_" + component.Name);
+
+ AddAttributeUnlessEmpty("Title", component.DisplayName);
+ AddAttributeUnlessEmpty("Description", component.Description);
+
+ if (component.IsRequired) {
+ AddAttribute("Absent", "disallow");
+ }
+
+ if (component.IsHidden) {
+ AddAttribute("Display", "hidden");
+ }
+
+ if (component.IsDisabledByDefault) {
+ AddAttribute("Level", "2");
+ }
+
+ patch.ApplyFragment("CM_C_" + component.Name, *this);
+
+ EndElement("Feature");
+}
+
+void cmWIXFeaturesSourceWriter::EmitComponentRef(std::string const& id)
+{
+ BeginElement("ComponentRef");
+ AddAttribute("Id", id);
+ EndElement("ComponentRef");
+}
diff --git a/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h
new file mode 100644
index 0000000..0facf97
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h
@@ -0,0 +1,28 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmCPackGenerator.h"
+#include "cmWIXPatch.h"
+#include "cmWIXSourceWriter.h"
+
+/** \class cmWIXFeaturesSourceWriter
+ * \brief Helper class to generate features.wxs
+ */
+class cmWIXFeaturesSourceWriter : public cmWIXSourceWriter
+{
+public:
+ cmWIXFeaturesSourceWriter(cmCPackLog* logger, std::string const& filename,
+ GuidType componentGuidType);
+
+ void CreateCMakePackageRegistryEntry(std::string const& package,
+ std::string const& upgradeGuid);
+
+ void EmitFeatureForComponentGroup(const cmCPackComponentGroup& group,
+ cmWIXPatch& patch);
+
+ void EmitFeatureForComponent(const cmCPackComponent& component,
+ cmWIXPatch& patch);
+
+ void EmitComponentRef(std::string const& id);
+};
diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
new file mode 100644
index 0000000..b4085d5
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
@@ -0,0 +1,168 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#if defined(__CYGWIN__)
+// For S_IWRITE symbol
+# define _DEFAULT_SOURCE
+#endif
+
+#include "cmWIXFilesSourceWriter.h"
+
+#include "cm_sys_stat.h"
+
+#include "cmCMakeToWixPath.h"
+#include "cmInstalledFile.h"
+#include "cmSystemTools.h"
+#include "cmUuid.h"
+#include "cmWIXAccessControlList.h"
+
+cmWIXFilesSourceWriter::cmWIXFilesSourceWriter(cmCPackLog* logger,
+ std::string const& filename,
+ GuidType componentGuidType)
+ : cmWIXSourceWriter(logger, filename, componentGuidType)
+{
+}
+
+void cmWIXFilesSourceWriter::EmitShortcut(std::string const& id,
+ cmWIXShortcut const& shortcut,
+ std::string const& shortcutPrefix,
+ size_t shortcutIndex)
+{
+ std::ostringstream shortcutId;
+ shortcutId << shortcutPrefix << id;
+
+ if (shortcutIndex > 0) {
+ shortcutId << "_" << shortcutIndex;
+ }
+
+ std::string fileId = std::string("CM_F") + id;
+
+ BeginElement("Shortcut");
+ AddAttribute("Id", shortcutId.str());
+ AddAttribute("Name", shortcut.label);
+ std::string target = "[#" + fileId + "]";
+ AddAttribute("Target", target);
+ AddAttribute("WorkingDirectory", shortcut.workingDirectoryId);
+ EndElement("Shortcut");
+}
+
+void cmWIXFilesSourceWriter::EmitRemoveFolder(std::string const& id)
+{
+ BeginElement("RemoveFolder");
+ AddAttribute("Id", id);
+ AddAttribute("On", "uninstall");
+ EndElement("RemoveFolder");
+}
+
+void cmWIXFilesSourceWriter::EmitInstallRegistryValue(
+ std::string const& registryKey, std::string const& cpackComponentName,
+ std::string const& suffix)
+{
+ std::string valueName;
+ if (!cpackComponentName.empty()) {
+ valueName = cpackComponentName + "_";
+ }
+
+ valueName += "installed";
+ valueName += suffix;
+
+ BeginElement("RegistryValue");
+ AddAttribute("Root", "HKCU");
+ AddAttribute("Key", registryKey);
+ AddAttribute("Name", valueName);
+ AddAttribute("Type", "integer");
+ AddAttribute("Value", "1");
+ AddAttribute("KeyPath", "yes");
+ EndElement("RegistryValue");
+}
+
+void cmWIXFilesSourceWriter::EmitUninstallShortcut(
+ std::string const& packageName)
+{
+ BeginElement("Shortcut");
+ AddAttribute("Id", "UNINSTALL");
+ AddAttribute("Name", "Uninstall " + packageName);
+ AddAttribute("Description", "Uninstalls " + packageName);
+ AddAttribute("Target", "[SystemFolder]msiexec.exe");
+ AddAttribute("Arguments", "/x [ProductCode]");
+ EndElement("Shortcut");
+}
+
+std::string cmWIXFilesSourceWriter::EmitComponentCreateFolder(
+ std::string const& directoryId, std::string const& guid,
+ cmInstalledFile const* installedFile)
+{
+ std::string componentId = std::string("CM_C_EMPTY_") + directoryId;
+
+ BeginElement("DirectoryRef");
+ AddAttribute("Id", directoryId);
+
+ BeginElement("Component");
+ AddAttribute("Id", componentId);
+ AddAttribute("Guid", guid);
+
+ BeginElement("CreateFolder");
+
+ if (installedFile) {
+ cmWIXAccessControlList acl(Logger, *installedFile, *this);
+ acl.Apply();
+ }
+
+ EndElement("CreateFolder");
+ EndElement("Component");
+ EndElement("DirectoryRef");
+
+ return componentId;
+}
+
+std::string cmWIXFilesSourceWriter::EmitComponentFile(
+ std::string const& directoryId, std::string const& id,
+ std::string const& filePath, cmWIXPatch& patch,
+ cmInstalledFile const* installedFile)
+{
+ std::string componentId = std::string("CM_C") + id;
+ std::string fileId = std::string("CM_F") + id;
+
+ std::string guid = CreateGuidFromComponentId(componentId);
+
+ BeginElement("DirectoryRef");
+ AddAttribute("Id", directoryId);
+
+ BeginElement("Component");
+ AddAttribute("Id", componentId);
+ AddAttribute("Guid", guid);
+
+ if (installedFile) {
+ if (installedFile->GetPropertyAsBool("CPACK_NEVER_OVERWRITE")) {
+ AddAttribute("NeverOverwrite", "yes");
+ }
+ if (installedFile->GetPropertyAsBool("CPACK_PERMANENT")) {
+ AddAttribute("Permanent", "yes");
+ }
+ }
+
+ patch.ApplyFragment(componentId, *this);
+ BeginElement("File");
+ AddAttribute("Id", fileId);
+ AddAttribute("Source", CMakeToWixPath(filePath));
+ AddAttribute("KeyPath", "yes");
+
+ mode_t fileMode = 0;
+ cmSystemTools::GetPermissions(filePath.c_str(), fileMode);
+
+ if (!(fileMode & S_IWRITE)) {
+ AddAttribute("ReadOnly", "yes");
+ }
+ patch.ApplyFragment(fileId, *this);
+
+ if (installedFile) {
+ cmWIXAccessControlList acl(Logger, *installedFile, *this);
+ acl.Apply();
+ }
+
+ EndElement("File");
+
+ EndElement("Component");
+ EndElement("DirectoryRef");
+
+ return componentId;
+}
diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.h b/Source/CPack/WiX/cmWIXFilesSourceWriter.h
new file mode 100644
index 0000000..60dddd4
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.h
@@ -0,0 +1,38 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmCPackGenerator.h"
+#include "cmWIXPatch.h"
+#include "cmWIXShortcut.h"
+#include "cmWIXSourceWriter.h"
+
+/** \class cmWIXFilesSourceWriter
+ * \brief Helper class to generate files.wxs
+ */
+class cmWIXFilesSourceWriter : public cmWIXSourceWriter
+{
+public:
+ cmWIXFilesSourceWriter(cmCPackLog* logger, std::string const& filename,
+ GuidType componentGuidType);
+
+ void EmitShortcut(std::string const& id, cmWIXShortcut const& shortcut,
+ std::string const& shortcutPrefix, size_t shortcutIndex);
+
+ void EmitRemoveFolder(std::string const& id);
+
+ void EmitInstallRegistryValue(std::string const& registryKey,
+ std::string const& cpackComponentName,
+ std::string const& suffix);
+
+ void EmitUninstallShortcut(std::string const& packageName);
+
+ std::string EmitComponentCreateFolder(std::string const& directoryId,
+ std::string const& guid,
+ cmInstalledFile const* installedFile);
+
+ std::string EmitComponentFile(std::string const& directoryId,
+ std::string const& id,
+ std::string const& filePath, cmWIXPatch& patch,
+ cmInstalledFile const* installedFile);
+};
diff --git a/Source/CPack/WiX/cmWIXPatch.cxx b/Source/CPack/WiX/cmWIXPatch.cxx
new file mode 100644
index 0000000..122ffaf
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXPatch.cxx
@@ -0,0 +1,91 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmWIXPatch.h"
+
+#include "cmCPackGenerator.h"
+
+cmWIXPatch::cmWIXPatch(cmCPackLog* logger)
+ : Logger(logger)
+{
+}
+
+bool cmWIXPatch::LoadFragments(std::string const& patchFilePath)
+{
+ cmWIXPatchParser parser(Fragments, Logger);
+ if (!parser.ParseFile(patchFilePath.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Failed parsing XML patch file: '" << patchFilePath << "'"
+ << std::endl);
+ return false;
+ }
+
+ return true;
+}
+
+void cmWIXPatch::ApplyFragment(std::string const& id,
+ cmWIXSourceWriter& writer)
+{
+ cmWIXPatchParser::fragment_map_t::iterator i = Fragments.find(id);
+ if (i == Fragments.end())
+ return;
+
+ const cmWIXPatchElement& fragment = i->second;
+ for (auto const& attr : fragment.attributes) {
+ writer.AddAttribute(attr.first, attr.second);
+ }
+ this->ApplyElementChildren(fragment, writer);
+
+ Fragments.erase(i);
+}
+
+void cmWIXPatch::ApplyElementChildren(const cmWIXPatchElement& element,
+ cmWIXSourceWriter& writer)
+{
+ for (const auto& node : element.children) {
+ switch (node->type()) {
+ case cmWIXPatchNode::ELEMENT:
+ ApplyElement(dynamic_cast<const cmWIXPatchElement&>(*node), writer);
+ break;
+ case cmWIXPatchNode::TEXT:
+ writer.AddTextNode(dynamic_cast<const cmWIXPatchText&>(*node).text);
+ break;
+ }
+ }
+}
+
+void cmWIXPatch::ApplyElement(const cmWIXPatchElement& element,
+ cmWIXSourceWriter& writer)
+{
+ writer.BeginElement(element.name);
+
+ for (auto const& attr : element.attributes) {
+ writer.AddAttribute(attr.first, attr.second);
+ }
+
+ this->ApplyElementChildren(element, writer);
+
+ writer.EndElement(element.name);
+}
+
+bool cmWIXPatch::CheckForUnappliedFragments()
+{
+ std::string fragmentList;
+ for (auto const& fragment : Fragments) {
+ if (!fragmentList.empty()) {
+ fragmentList += ", ";
+ }
+
+ fragmentList += "'";
+ fragmentList += fragment.first;
+ fragmentList += "'";
+ }
+
+ if (!fragmentList.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Some XML patch fragments did not have matching IDs: "
+ << fragmentList << std::endl);
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/CPack/WiX/cmWIXPatch.h b/Source/CPack/WiX/cmWIXPatch.h
new file mode 100644
index 0000000..c78722d
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXPatch.h
@@ -0,0 +1,34 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+
+#include "cmWIXPatchParser.h"
+#include "cmWIXSourceWriter.h"
+
+/** \class cmWIXPatch
+ * \brief Class that maintains and applies patch fragments
+ */
+class cmWIXPatch
+{
+public:
+ cmWIXPatch(cmCPackLog* logger);
+
+ bool LoadFragments(std::string const& patchFilePath);
+
+ void ApplyFragment(std::string const& id, cmWIXSourceWriter& writer);
+
+ bool CheckForUnappliedFragments();
+
+private:
+ void ApplyElementChildren(const cmWIXPatchElement& element,
+ cmWIXSourceWriter& writer);
+
+ void ApplyElement(const cmWIXPatchElement& element,
+ cmWIXSourceWriter& writer);
+
+ cmCPackLog* Logger;
+
+ cmWIXPatchParser::fragment_map_t Fragments;
+};
diff --git a/Source/CPack/WiX/cmWIXPatchParser.cxx b/Source/CPack/WiX/cmWIXPatchParser.cxx
new file mode 100644
index 0000000..8b26c4e
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXPatchParser.cxx
@@ -0,0 +1,160 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmWIXPatchParser.h"
+
+#include <utility>
+
+#include <cm/memory>
+
+#include <cm3p/expat.h>
+
+#include "cmCPackGenerator.h"
+
+cmWIXPatchNode::Type cmWIXPatchText::type()
+{
+ return cmWIXPatchNode::TEXT;
+}
+
+cmWIXPatchNode::Type cmWIXPatchElement::type()
+{
+ return cmWIXPatchNode::ELEMENT;
+}
+
+cmWIXPatchNode::~cmWIXPatchNode()
+{
+}
+
+cmWIXPatchElement::cmWIXPatchElement() = default;
+cmWIXPatchElement::~cmWIXPatchElement() = default;
+
+cmWIXPatchParser::cmWIXPatchParser(fragment_map_t& fragments,
+ cmCPackLog* logger)
+ : Logger(logger)
+ , State(BEGIN_DOCUMENT)
+ , Valid(true)
+ , Fragments(fragments)
+{
+}
+
+void cmWIXPatchParser::StartElement(const std::string& name, const char** atts)
+{
+ if (State == BEGIN_DOCUMENT) {
+ if (name == "CPackWiXPatch") {
+ State = BEGIN_FRAGMENTS;
+ } else {
+ ReportValidationError("Expected root element 'CPackWiXPatch'");
+ }
+ } else if (State == BEGIN_FRAGMENTS) {
+ if (name == "CPackWiXFragment") {
+ State = INSIDE_FRAGMENT;
+ StartFragment(atts);
+ } else {
+ ReportValidationError("Expected 'CPackWixFragment' element");
+ }
+ } else if (State == INSIDE_FRAGMENT) {
+ cmWIXPatchElement& parent = *ElementStack.back();
+
+ auto element = cm::make_unique<cmWIXPatchElement>();
+
+ element->name = name;
+
+ for (size_t i = 0; atts[i]; i += 2) {
+ std::string key = atts[i];
+ std::string value = atts[i + 1];
+
+ element->attributes[key] = value;
+ }
+
+ ElementStack.push_back(element.get());
+ parent.children.push_back(std::move(element));
+ }
+}
+
+void cmWIXPatchParser::StartFragment(const char** attributes)
+{
+ cmWIXPatchElement* new_element = nullptr;
+ /* find the id of for fragment */
+ for (size_t i = 0; attributes[i]; i += 2) {
+ const std::string key = attributes[i];
+ const std::string value = attributes[i + 1];
+
+ if (key == "Id") {
+ if (Fragments.find(value) != Fragments.end()) {
+ std::ostringstream tmp;
+ tmp << "Invalid reuse of 'CPackWixFragment' 'Id': " << value;
+ ReportValidationError(tmp.str());
+ }
+
+ new_element = &Fragments[value];
+ ElementStack.push_back(new_element);
+ }
+ }
+
+ /* add any additional attributes for the fragment */
+ if (!new_element) {
+ ReportValidationError("No 'Id' specified for 'CPackWixFragment' element");
+ } else {
+ for (size_t i = 0; attributes[i]; i += 2) {
+ const std::string key = attributes[i];
+ const std::string value = attributes[i + 1];
+
+ if (key != "Id") {
+ new_element->attributes[key] = value;
+ }
+ }
+ }
+}
+
+void cmWIXPatchParser::EndElement(const std::string& name)
+{
+ if (State == INSIDE_FRAGMENT) {
+ if (name == "CPackWiXFragment") {
+ State = BEGIN_FRAGMENTS;
+ ElementStack.clear();
+ } else {
+ ElementStack.pop_back();
+ }
+ }
+}
+
+void cmWIXPatchParser::CharacterDataHandler(const char* data, int length)
+{
+ const char* whitespace = "\x20\x09\x0d\x0a";
+
+ if (State == INSIDE_FRAGMENT) {
+ cmWIXPatchElement& parent = *ElementStack.back();
+
+ std::string text(data, length);
+
+ std::string::size_type first = text.find_first_not_of(whitespace);
+ std::string::size_type last = text.find_last_not_of(whitespace);
+
+ if (first != std::string::npos && last != std::string::npos) {
+ auto text_node = cm::make_unique<cmWIXPatchText>();
+ text_node->text = text.substr(first, last - first + 1);
+
+ parent.children.push_back(std::move(text_node));
+ }
+ }
+}
+
+void cmWIXPatchParser::ReportError(int line, int column, const char* msg)
+{
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while processing XML patch file at "
+ << line << ":" << column << ": " << msg << std::endl);
+ Valid = false;
+}
+
+void cmWIXPatchParser::ReportValidationError(std::string const& message)
+{
+ ReportError(
+ XML_GetCurrentLineNumber(static_cast<XML_Parser>(this->Parser)),
+ XML_GetCurrentColumnNumber(static_cast<XML_Parser>(this->Parser)),
+ message.c_str());
+}
+
+bool cmWIXPatchParser::IsValid() const
+{
+ return Valid;
+}
diff --git a/Source/CPack/WiX/cmWIXPatchParser.h b/Source/CPack/WiX/cmWIXPatchParser.h
new file mode 100644
index 0000000..70a21bc
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXPatchParser.h
@@ -0,0 +1,92 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "cmCPackLog.h"
+#include "cmXMLParser.h"
+
+struct cmWIXPatchNode
+{
+ enum Type
+ {
+ TEXT,
+ ELEMENT
+ };
+
+ virtual ~cmWIXPatchNode();
+
+ virtual Type type() = 0;
+};
+
+struct cmWIXPatchText : public cmWIXPatchNode
+{
+ virtual Type type();
+
+ std::string text;
+};
+
+struct cmWIXPatchElement : cmWIXPatchNode
+{
+ virtual Type type();
+
+ cmWIXPatchElement();
+
+ cmWIXPatchElement(const cmWIXPatchElement&) = delete;
+ const cmWIXPatchElement& operator=(const cmWIXPatchElement&) = delete;
+
+ ~cmWIXPatchElement();
+
+ using child_list_t = std::vector<std::unique_ptr<cmWIXPatchNode>>;
+ using attributes_t = std::map<std::string, std::string>;
+
+ std::string name;
+ child_list_t children;
+ attributes_t attributes;
+};
+
+/** \class cmWIXPatchParser
+ * \brief Helper class that parses XML patch files (CPACK_WIX_PATCH_FILE)
+ */
+class cmWIXPatchParser : public cmXMLParser
+{
+public:
+ using fragment_map_t = std::map<std::string, cmWIXPatchElement>;
+
+ cmWIXPatchParser(fragment_map_t& Fragments, cmCPackLog* logger);
+
+private:
+ virtual void StartElement(const std::string& name, const char** atts);
+
+ void StartFragment(const char** attributes);
+
+ virtual void EndElement(const std::string& name);
+
+ virtual void CharacterDataHandler(const char* data, int length);
+
+ virtual void ReportError(int line, int column, const char* msg);
+
+ void ReportValidationError(std::string const& message);
+
+ bool IsValid() const;
+
+ cmCPackLog* Logger;
+
+ enum ParserState
+ {
+ BEGIN_DOCUMENT,
+ BEGIN_FRAGMENTS,
+ INSIDE_FRAGMENT
+ };
+
+ ParserState State;
+
+ bool Valid;
+
+ fragment_map_t& Fragments;
+
+ std::vector<cmWIXPatchElement*> ElementStack;
+};
diff --git a/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx b/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx
new file mode 100644
index 0000000..751f7dc
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx
@@ -0,0 +1,186 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmWIXRichTextFormatWriter.h"
+
+#include "cmVersion.h"
+
+cmWIXRichTextFormatWriter::cmWIXRichTextFormatWriter(
+ std::string const& filename)
+ : File(filename.c_str(), std::ios::binary)
+{
+ StartGroup();
+ WriteHeader();
+ WriteDocumentPrefix();
+}
+
+cmWIXRichTextFormatWriter::~cmWIXRichTextFormatWriter()
+{
+ EndGroup();
+
+ /* I haven't seen this in the RTF spec but
+ * wordpad terminates its RTF like this */
+ File << "\r\n";
+ File.put(0);
+}
+
+void cmWIXRichTextFormatWriter::AddText(std::string const& text)
+{
+ using rtf_byte_t = unsigned char;
+
+ for (size_t i = 0; i < text.size(); ++i) {
+ rtf_byte_t c = rtf_byte_t(text[i]);
+
+ switch (c) {
+ case '\\':
+ File << "\\\\";
+ break;
+ case '{':
+ File << "\\{";
+ break;
+ case '}':
+ File << "\\}";
+ break;
+ case '\n':
+ File << "\\par\r\n";
+ break;
+ case '\r':
+ continue;
+ default: {
+ if (c <= 0x7F) {
+ File << c;
+ } else {
+ if (c <= 0xC0) {
+ EmitInvalidCodepoint(c);
+ } else if (c < 0xE0 && i + 1 < text.size()) {
+ EmitUnicodeCodepoint((text[i + 1] & 0x3F) | ((c & 0x1F) << 6));
+ i += 1;
+ } else if (c < 0xF0 && i + 2 < text.size()) {
+ EmitUnicodeCodepoint((text[i + 2] & 0x3F) |
+ ((text[i + 1] & 0x3F) << 6) |
+ ((c & 0xF) << 12));
+ i += 2;
+ } else if (c < 0xF8 && i + 3 < text.size()) {
+ EmitUnicodeCodepoint(
+ (text[i + 3] & 0x3F) | ((text[i + 2] & 0x3F) << 6) |
+ ((text[i + 1] & 0x3F) << 12) | ((c & 0x7) << 18));
+ i += 3;
+ } else {
+ EmitInvalidCodepoint(c);
+ }
+ }
+ } break;
+ }
+ }
+}
+
+void cmWIXRichTextFormatWriter::WriteHeader()
+{
+ ControlWord("rtf1");
+ ControlWord("ansi");
+ ControlWord("ansicpg1252");
+ ControlWord("deff0");
+ ControlWord("deflang1031");
+
+ WriteFontTable();
+ WriteColorTable();
+ WriteGenerator();
+}
+
+void cmWIXRichTextFormatWriter::WriteFontTable()
+{
+ StartGroup();
+ ControlWord("fonttbl");
+
+ StartGroup();
+ ControlWord("f0");
+ ControlWord("fswiss");
+ ControlWord("fcharset0 Arial;");
+ EndGroup();
+
+ EndGroup();
+}
+
+void cmWIXRichTextFormatWriter::WriteColorTable()
+{
+ StartGroup();
+ ControlWord("colortbl ;");
+ ControlWord("red255");
+ ControlWord("green0");
+ ControlWord("blue0;");
+ ControlWord("red0");
+ ControlWord("green255");
+ ControlWord("blue0;");
+ ControlWord("red0");
+ ControlWord("green0");
+ ControlWord("blue255;");
+ EndGroup();
+}
+
+void cmWIXRichTextFormatWriter::WriteGenerator()
+{
+ StartGroup();
+ NewControlWord("generator");
+ File << " CPack WiX Generator (" << cmVersion::GetCMakeVersion() << ");";
+ EndGroup();
+}
+
+void cmWIXRichTextFormatWriter::WriteDocumentPrefix()
+{
+ ControlWord("viewkind4");
+ ControlWord("uc1");
+ ControlWord("pard");
+ ControlWord("f0");
+ ControlWord("fs20");
+}
+
+void cmWIXRichTextFormatWriter::ControlWord(std::string const& keyword)
+{
+ File << "\\" << keyword;
+}
+
+void cmWIXRichTextFormatWriter::NewControlWord(std::string const& keyword)
+{
+ File << "\\*\\" << keyword;
+}
+
+void cmWIXRichTextFormatWriter::StartGroup()
+{
+ File.put('{');
+}
+
+void cmWIXRichTextFormatWriter::EndGroup()
+{
+ File.put('}');
+}
+
+void cmWIXRichTextFormatWriter::EmitUnicodeCodepoint(int c)
+{
+ // Do not emit byte order mark (BOM)
+ if (c == 0xFEFF) {
+ return;
+ } else if (c <= 0xFFFF) {
+ EmitUnicodeSurrogate(c);
+ } else {
+ c -= 0x10000;
+ EmitUnicodeSurrogate(((c >> 10) & 0x3FF) + 0xD800);
+ EmitUnicodeSurrogate((c & 0x3FF) + 0xDC00);
+ }
+}
+
+void cmWIXRichTextFormatWriter::EmitUnicodeSurrogate(int c)
+{
+ ControlWord("u");
+ if (c <= 32767) {
+ File << c;
+ } else {
+ File << (c - 65536);
+ }
+ File << "?";
+}
+
+void cmWIXRichTextFormatWriter::EmitInvalidCodepoint(int c)
+{
+ ControlWord("cf1 ");
+ File << "[INVALID-BYTE-" << int(c) << "]";
+ ControlWord("cf0 ");
+}
diff --git a/Source/CPack/WiX/cmWIXRichTextFormatWriter.h b/Source/CPack/WiX/cmWIXRichTextFormatWriter.h
new file mode 100644
index 0000000..99471f1
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXRichTextFormatWriter.h
@@ -0,0 +1,43 @@
+/* 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 <string>
+
+#include "cmsys/FStream.hxx"
+
+/** \class cmWIXRichtTextFormatWriter
+ * \brief Helper class to generate Rich Text Format (RTF) documents
+ * from plain text (e.g. for license and welcome text)
+ */
+class cmWIXRichTextFormatWriter
+{
+public:
+ cmWIXRichTextFormatWriter(std::string const& filename);
+ ~cmWIXRichTextFormatWriter();
+
+ void AddText(std::string const& text);
+
+private:
+ void WriteHeader();
+ void WriteFontTable();
+ void WriteColorTable();
+ void WriteGenerator();
+
+ void WriteDocumentPrefix();
+
+ void ControlWord(std::string const& keyword);
+ void NewControlWord(std::string const& keyword);
+
+ void StartGroup();
+ void EndGroup();
+
+ void EmitUnicodeCodepoint(int c);
+ void EmitUnicodeSurrogate(int c);
+
+ void EmitInvalidCodepoint(int c);
+
+ cmsys::ofstream File;
+};
diff --git a/Source/CPack/WiX/cmWIXShortcut.cxx b/Source/CPack/WiX/cmWIXShortcut.cxx
new file mode 100644
index 0000000..cd1988a
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXShortcut.cxx
@@ -0,0 +1,103 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmWIXShortcut.h"
+
+#include "cmWIXFilesSourceWriter.h"
+
+void cmWIXShortcuts::insert(Type type, std::string const& id,
+ cmWIXShortcut const& shortcut)
+{
+ this->Shortcuts[type][id].push_back(shortcut);
+}
+
+bool cmWIXShortcuts::empty(Type type) const
+{
+ return this->Shortcuts.find(type) == this->Shortcuts.end();
+}
+
+bool cmWIXShortcuts::EmitShortcuts(
+ Type type, std::string const& registryKey,
+ std::string const& cpackComponentName,
+ cmWIXFilesSourceWriter& fileDefinitions) const
+{
+ shortcut_type_map_t::const_iterator i = this->Shortcuts.find(type);
+
+ if (i == this->Shortcuts.end()) {
+ return false;
+ }
+
+ shortcut_id_map_t const& id_map = i->second;
+
+ std::string shortcutPrefix;
+ std::string registrySuffix;
+
+ switch (type) {
+ case START_MENU:
+ shortcutPrefix = "CM_S";
+ break;
+ case DESKTOP:
+ shortcutPrefix = "CM_DS";
+ registrySuffix = "_desktop";
+ break;
+ case STARTUP:
+ shortcutPrefix = "CM_SS";
+ registrySuffix = "_startup";
+ break;
+ default:
+ return false;
+ }
+
+ for (auto const& j : id_map) {
+ std::string const& id = j.first;
+ shortcut_list_t const& shortcutList = j.second;
+
+ for (size_t shortcutListIndex = 0; shortcutListIndex < shortcutList.size();
+ ++shortcutListIndex) {
+ cmWIXShortcut const& shortcut = shortcutList[shortcutListIndex];
+ fileDefinitions.EmitShortcut(id, shortcut, shortcutPrefix,
+ shortcutListIndex);
+ }
+ }
+
+ fileDefinitions.EmitInstallRegistryValue(registryKey, cpackComponentName,
+ registrySuffix);
+
+ return true;
+}
+
+void cmWIXShortcuts::AddShortcutTypes(std::set<Type>& types)
+{
+ for (auto const& shortcut : this->Shortcuts) {
+ types.insert(shortcut.first);
+ }
+}
+
+void cmWIXShortcuts::CreateFromProperties(std::string const& id,
+ std::string const& directoryId,
+ cmInstalledFile const& installedFile)
+{
+ CreateFromProperty("CPACK_START_MENU_SHORTCUTS", START_MENU, id, directoryId,
+ installedFile);
+
+ CreateFromProperty("CPACK_DESKTOP_SHORTCUTS", DESKTOP, id, directoryId,
+ installedFile);
+
+ CreateFromProperty("CPACK_STARTUP_SHORTCUTS", STARTUP, id, directoryId,
+ installedFile);
+}
+
+void cmWIXShortcuts::CreateFromProperty(std::string const& propertyName,
+ Type type, std::string const& id,
+ std::string const& directoryId,
+ cmInstalledFile const& installedFile)
+{
+ std::vector<std::string> list;
+ installedFile.GetPropertyAsList(propertyName, list);
+
+ for (std::string const& label : list) {
+ cmWIXShortcut shortcut;
+ shortcut.label = label;
+ shortcut.workingDirectoryId = directoryId;
+ insert(type, id, shortcut);
+ }
+}
diff --git a/Source/CPack/WiX/cmWIXShortcut.h b/Source/CPack/WiX/cmWIXShortcut.h
new file mode 100644
index 0000000..315b5ea
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXShortcut.h
@@ -0,0 +1,57 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmInstalledFile.h"
+
+class cmWIXFilesSourceWriter;
+
+struct cmWIXShortcut
+{
+ std::string label;
+ std::string workingDirectoryId;
+};
+
+class cmWIXShortcuts
+{
+public:
+ enum Type
+ {
+ START_MENU,
+ DESKTOP,
+ STARTUP
+ };
+
+ using shortcut_list_t = std::vector<cmWIXShortcut>;
+ using shortcut_id_map_t = std::map<std::string, shortcut_list_t>;
+
+ void insert(Type type, std::string const& id, cmWIXShortcut const& shortcut);
+
+ bool empty(Type type) const;
+
+ bool EmitShortcuts(Type type, std::string const& registryKey,
+ std::string const& cpackComponentName,
+ cmWIXFilesSourceWriter& fileDefinitions) const;
+
+ void AddShortcutTypes(std::set<Type>& types);
+
+ void CreateFromProperties(std::string const& id,
+ std::string const& directoryId,
+ cmInstalledFile const& installedFile);
+
+private:
+ using shortcut_type_map_t = std::map<Type, shortcut_id_map_t>;
+
+ void CreateFromProperty(std::string const& propertyName, Type type,
+ std::string const& id,
+ std::string const& directoryId,
+ cmInstalledFile const& installedFile);
+
+ shortcut_type_map_t Shortcuts;
+ shortcut_id_map_t EmptyIdMap;
+};
diff --git a/Source/CPack/WiX/cmWIXSourceWriter.cxx b/Source/CPack/WiX/cmWIXSourceWriter.cxx
new file mode 100644
index 0000000..8e9bfdf
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXSourceWriter.cxx
@@ -0,0 +1,183 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmWIXSourceWriter.h"
+
+#include <windows.h>
+
+#include "cmCPackGenerator.h"
+#include "cmUuid.h"
+
+cmWIXSourceWriter::cmWIXSourceWriter(cmCPackLog* logger,
+ std::string const& filename,
+ GuidType componentGuidType,
+ RootElementType rootElementType)
+ : Logger(logger)
+ , File(filename.c_str())
+ , State(DEFAULT)
+ , SourceFilename(filename)
+ , ComponentGuidType(componentGuidType)
+{
+ WriteXMLDeclaration();
+
+ if (rootElementType == INCLUDE_ELEMENT_ROOT) {
+ BeginElement("Include");
+ } else {
+ BeginElement("Wix");
+ }
+
+ AddAttribute("xmlns", "http://schemas.microsoft.com/wix/2006/wi");
+}
+
+cmWIXSourceWriter::~cmWIXSourceWriter()
+{
+ if (Elements.size() > 1) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ Elements.size() - 1
+ << " WiX elements were still open when closing '"
+ << SourceFilename << "'" << std::endl);
+ return;
+ }
+
+ EndElement(Elements.back());
+}
+
+void cmWIXSourceWriter::BeginElement(std::string const& name)
+{
+ if (State == BEGIN) {
+ File << ">";
+ }
+
+ File << "\n";
+ Indent(Elements.size());
+ File << "<" << name;
+
+ Elements.push_back(name);
+ State = BEGIN;
+}
+
+void cmWIXSourceWriter::EndElement(std::string const& name)
+{
+ if (Elements.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "can not end WiX element with no open elements in '"
+ << SourceFilename << "'" << std::endl);
+ return;
+ }
+
+ if (Elements.back() != name) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "WiX element <"
+ << Elements.back() << "> can not be closed by </" << name
+ << "> in '" << SourceFilename << "'" << std::endl);
+ return;
+ }
+
+ if (State == DEFAULT) {
+ File << "\n";
+ Indent(Elements.size() - 1);
+ File << "</" << Elements.back() << ">";
+ } else {
+ File << "/>";
+ }
+
+ Elements.pop_back();
+ State = DEFAULT;
+}
+
+void cmWIXSourceWriter::AddTextNode(std::string const& text)
+{
+ if (State == BEGIN) {
+ File << ">";
+ }
+
+ if (Elements.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "can not add text without open WiX element in '"
+ << SourceFilename << "'" << std::endl);
+ return;
+ }
+
+ File << this->EscapeAttributeValue(text);
+ State = DEFAULT;
+}
+
+void cmWIXSourceWriter::AddProcessingInstruction(std::string const& target,
+ std::string const& content)
+{
+ if (State == BEGIN) {
+ File << ">";
+ }
+
+ File << "\n";
+ Indent(Elements.size());
+ File << "<?" << target << " " << content << "?>";
+
+ State = DEFAULT;
+}
+
+void cmWIXSourceWriter::AddAttribute(std::string const& key,
+ std::string const& value)
+{
+ File << " " << key << "=\"" << EscapeAttributeValue(value) << '"';
+}
+
+void cmWIXSourceWriter::AddAttributeUnlessEmpty(std::string const& key,
+ std::string const& value)
+{
+ if (!value.empty()) {
+ AddAttribute(key, value);
+ }
+}
+
+std::string cmWIXSourceWriter::CreateGuidFromComponentId(
+ std::string const& componentId)
+{
+ std::string guid = "*";
+ if (this->ComponentGuidType == CMAKE_GENERATED_GUID) {
+ std::string md5 = cmSystemTools::ComputeStringMD5(componentId);
+ cmUuid uuid;
+ std::vector<unsigned char> ns;
+ guid = uuid.FromMd5(ns, md5);
+ }
+ return guid;
+}
+
+void cmWIXSourceWriter::WriteXMLDeclaration()
+{
+ File << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
+}
+
+void cmWIXSourceWriter::Indent(size_t count)
+{
+ for (size_t i = 0; i < count; ++i) {
+ File << " ";
+ }
+}
+
+std::string cmWIXSourceWriter::EscapeAttributeValue(std::string const& value)
+{
+ std::string result;
+ result.reserve(value.size());
+
+ for (char c : value) {
+ switch (c) {
+ case '<':
+ result += "&lt;";
+ break;
+ case '>':
+ result += "&gt;";
+ break;
+ case '&':
+ result += "&amp;";
+ break;
+ case '"':
+ result += "&quot;";
+ break;
+ default:
+ result += c;
+ break;
+ }
+ }
+
+ return result;
+}
diff --git a/Source/CPack/WiX/cmWIXSourceWriter.h b/Source/CPack/WiX/cmWIXSourceWriter.h
new file mode 100644
index 0000000..f643acd
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXSourceWriter.h
@@ -0,0 +1,77 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmCPackLog.h"
+
+/** \class cmWIXSourceWriter
+ * \brief Helper class to generate XML WiX source files
+ */
+class cmWIXSourceWriter
+{
+public:
+ enum GuidType
+ {
+ WIX_GENERATED_GUID,
+ CMAKE_GENERATED_GUID
+ };
+
+ enum RootElementType
+ {
+ WIX_ELEMENT_ROOT,
+ INCLUDE_ELEMENT_ROOT
+ };
+
+ cmWIXSourceWriter(cmCPackLog* logger, std::string const& filename,
+ GuidType componentGuidType,
+ RootElementType rootElementType = WIX_ELEMENT_ROOT);
+
+ ~cmWIXSourceWriter();
+
+ void BeginElement(std::string const& name);
+
+ void EndElement(std::string const& name);
+
+ void AddTextNode(std::string const& text);
+
+ void AddProcessingInstruction(std::string const& target,
+ std::string const& content);
+
+ void AddAttribute(std::string const& key, std::string const& value);
+
+ void AddAttributeUnlessEmpty(std::string const& key,
+ std::string const& value);
+
+ std::string CreateGuidFromComponentId(std::string const& componentId);
+
+ static std::string EscapeAttributeValue(std::string const& value);
+
+protected:
+ cmCPackLog* Logger;
+
+private:
+ enum State
+ {
+ DEFAULT,
+ BEGIN
+ };
+
+ void WriteXMLDeclaration();
+
+ void Indent(size_t count);
+
+ cmsys::ofstream File;
+
+ State State;
+
+ std::vector<std::string> Elements;
+
+ std::string SourceFilename;
+
+ GuidType ComponentGuidType;
+};
diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx
new file mode 100644
index 0000000..7fd12dd
--- /dev/null
+++ b/Source/CPack/cmCPackArchiveGenerator.cxx
@@ -0,0 +1,371 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackArchiveGenerator.h"
+
+#include <cstring>
+#include <map>
+#include <ostream>
+#include <utility>
+#include <vector>
+
+#include <cm3p/archive.h>
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackGenerator.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmWorkingDirectory.h"
+
+cmCPackGenerator* cmCPackArchiveGenerator::Create7ZGenerator()
+{
+ return new cmCPackArchiveGenerator(cmArchiveWrite::CompressNone, "7zip",
+ ".7z");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::CreateTBZ2Generator()
+{
+ return new cmCPackArchiveGenerator(cmArchiveWrite::CompressBZip2, "paxr",
+ ".tar.bz2");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::CreateTGZGenerator()
+{
+ return new cmCPackArchiveGenerator(cmArchiveWrite::CompressGZip, "paxr",
+ ".tar.gz");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::CreateTXZGenerator()
+{
+ return new cmCPackArchiveGenerator(cmArchiveWrite::CompressXZ, "paxr",
+ ".tar.xz");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::CreateTZGenerator()
+{
+ return new cmCPackArchiveGenerator(cmArchiveWrite::CompressCompress, "paxr",
+ ".tar.Z");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::CreateTZSTGenerator()
+{
+ return new cmCPackArchiveGenerator(cmArchiveWrite::CompressZstd, "paxr",
+ ".tar.zst");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::CreateZIPGenerator()
+{
+ return new cmCPackArchiveGenerator(cmArchiveWrite::CompressNone, "zip",
+ ".zip");
+}
+
+cmCPackArchiveGenerator::cmCPackArchiveGenerator(
+ cmArchiveWrite::Compress compress, std::string format, std::string extension)
+ : Compress(compress)
+ , ArchiveFormat(std::move(format))
+ , OutputExtension(std::move(extension))
+{
+}
+
+cmCPackArchiveGenerator::~cmCPackArchiveGenerator() = default;
+
+std::string cmCPackArchiveGenerator::GetArchiveComponentFileName(
+ const std::string& component, bool isGroupName)
+{
+ std::string componentUpper(cmSystemTools::UpperCase(component));
+ std::string packageFileName;
+
+ if (this->IsSet("CPACK_ARCHIVE_" + componentUpper + "_FILE_NAME")) {
+ packageFileName +=
+ this->GetOption("CPACK_ARCHIVE_" + componentUpper + "_FILE_NAME");
+ } else if (this->IsSet("CPACK_ARCHIVE_FILE_NAME")) {
+ packageFileName += this->GetComponentPackageFileName(
+ this->GetOption("CPACK_ARCHIVE_FILE_NAME"), component, isGroupName);
+ } else {
+ packageFileName += this->GetComponentPackageFileName(
+ this->GetOption("CPACK_PACKAGE_FILE_NAME"), component, isGroupName);
+ }
+
+ packageFileName += this->GetOutputExtension();
+
+ return packageFileName;
+}
+
+int cmCPackArchiveGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1");
+ return this->Superclass::InitializeInternal();
+}
+
+int cmCPackArchiveGenerator::addOneComponentToArchive(
+ cmArchiveWrite& archive, cmCPackComponent* component)
+{
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ " - packaging component: " << component->Name << std::endl);
+ // Add the files of this component to the archive
+ std::string localToplevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+ localToplevel += "/" + component->Name;
+ // Change to local toplevel
+ cmWorkingDirectory workdir(localToplevel);
+ if (workdir.Failed()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Failed to change working directory to "
+ << localToplevel << " : "
+ << std::strerror(workdir.GetLastResult()) << std::endl);
+ return 0;
+ }
+ std::string filePrefix;
+ if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
+ filePrefix = cmStrCat(this->GetOption("CPACK_PACKAGE_FILE_NAME"), '/');
+ }
+ const char* installPrefix =
+ this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
+ if (installPrefix && installPrefix[0] == '/' && installPrefix[1] != 0) {
+ // add to file prefix and remove the leading '/'
+ filePrefix += installPrefix + 1;
+ filePrefix += "/";
+ }
+ for (std::string const& file : component->Files) {
+ std::string rp = filePrefix + file;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Adding file: " << rp << std::endl);
+ archive.Add(rp, 0, nullptr, false);
+ if (!archive) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "ERROR while packaging files: " << archive.GetError()
+ << std::endl);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * The macro will open/create a file 'filename'
+ * an declare and open the associated
+ * cmArchiveWrite 'archive' object.
+ */
+#define DECLARE_AND_OPEN_ARCHIVE(filename, archive) \
+ cmGeneratedFileStream gf; \
+ gf.Open((filename), false, true); \
+ if (!GenerateHeader(&gf)) { \
+ cmCPackLogger(cmCPackLog::LOG_ERROR, \
+ "Problem to generate Header for archive <" \
+ << (filename) << ">." << std::endl); \
+ return 0; \
+ } \
+ cmArchiveWrite archive(gf, this->Compress, this->ArchiveFormat); \
+ do { \
+ if (!this->SetArchiveOptions(&archive)) { \
+ cmCPackLogger(cmCPackLog::LOG_ERROR, \
+ "Problem to set archive options <" \
+ << (filename) << ">, ERROR = " << (archive).GetError() \
+ << std::endl); \
+ return 0; \
+ } \
+ if (!archive.Open()) { \
+ cmCPackLogger(cmCPackLog::LOG_ERROR, \
+ "Problem to open archive <" \
+ << (filename) << ">, ERROR = " << (archive).GetError() \
+ << std::endl); \
+ return 0; \
+ } \
+ if (!(archive)) { \
+ cmCPackLogger(cmCPackLog::LOG_ERROR, \
+ "Problem to create archive <" \
+ << (filename) << ">, ERROR = " << (archive).GetError() \
+ << std::endl); \
+ return 0; \
+ } \
+ } while (false)
+
+int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup)
+{
+ this->packageFileNames.clear();
+ // The default behavior is to have one package by component group
+ // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
+ if (!ignoreGroup) {
+ for (auto const& compG : this->ComponentGroups) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Packaging component group: " << compG.first << std::endl);
+ // Begin the archive for this group
+ std::string packageFileName = std::string(this->toplevel) + "/" +
+ this->GetArchiveComponentFileName(compG.first, true);
+
+ // open a block in order to automatically close archive
+ // at the end of the block
+ {
+ DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive);
+ // now iterate over the component of this group
+ for (cmCPackComponent* comp : (compG.second).Components) {
+ // Add the files of this component to the archive
+ this->addOneComponentToArchive(archive, comp);
+ }
+ }
+ // add the generated package to package file names list
+ this->packageFileNames.push_back(std::move(packageFileName));
+ }
+ // Handle Orphan components (components not belonging to any groups)
+ for (auto& comp : this->Components) {
+ // Does the component belong to a group?
+ if (comp.second.Group == nullptr) {
+ cmCPackLogger(
+ cmCPackLog::LOG_VERBOSE,
+ "Component <"
+ << comp.second.Name
+ << "> does not belong to any group, package it separately."
+ << std::endl);
+ std::string localToplevel(
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+ std::string packageFileName = std::string(this->toplevel);
+
+ localToplevel += "/" + comp.first;
+ packageFileName +=
+ "/" + this->GetArchiveComponentFileName(comp.first, false);
+
+ {
+ DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive);
+ // Add the files of this component to the archive
+ this->addOneComponentToArchive(archive, &(comp.second));
+ }
+ // add the generated package to package file names list
+ this->packageFileNames.push_back(std::move(packageFileName));
+ }
+ }
+ }
+ // CPACK_COMPONENTS_IGNORE_GROUPS is set
+ // We build 1 package per component
+ else {
+ for (auto& comp : this->Components) {
+ std::string localToplevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+ std::string packageFileName = std::string(this->toplevel);
+
+ localToplevel += "/" + comp.first;
+ packageFileName +=
+ "/" + this->GetArchiveComponentFileName(comp.first, false);
+
+ {
+ DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive);
+ // Add the files of this component to the archive
+ this->addOneComponentToArchive(archive, &(comp.second));
+ }
+ // add the generated package to package file names list
+ this->packageFileNames.push_back(std::move(packageFileName));
+ }
+ }
+ return 1;
+}
+
+int cmCPackArchiveGenerator::PackageComponentsAllInOne()
+{
+ // reset the package file names
+ this->packageFileNames.clear();
+ this->packageFileNames.emplace_back(this->toplevel);
+ this->packageFileNames[0] += "/";
+
+ if (this->IsSet("CPACK_ARCHIVE_FILE_NAME")) {
+ this->packageFileNames[0] += this->GetOption("CPACK_ARCHIVE_FILE_NAME");
+ } else {
+ this->packageFileNames[0] += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ }
+
+ this->packageFileNames[0] += this->GetOutputExtension();
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Packaging all groups in one package..."
+ "(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE is set)"
+ << std::endl);
+ DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive);
+
+ // The ALL COMPONENTS in ONE package case
+ for (auto& comp : this->Components) {
+ // Add the files of this component to the archive
+ this->addOneComponentToArchive(archive, &(comp.second));
+ }
+
+ // archive goes out of scope so it will finalized and closed.
+ return 1;
+}
+
+int cmCPackArchiveGenerator::PackageFiles()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Toplevel: " << this->toplevel << std::endl);
+
+ if (this->WantsComponentInstallation()) {
+ // CASE 1 : COMPONENT ALL-IN-ONE package
+ // If ALL COMPONENTS in ONE package has been requested
+ // then the package file is unique and should be open here.
+ if (this->componentPackageMethod == ONE_PACKAGE) {
+ return this->PackageComponentsAllInOne();
+ }
+ // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
+ // There will be 1 package for each component group
+ // however one may require to ignore component group and
+ // in this case you'll get 1 package for each component.
+ return this->PackageComponents(this->componentPackageMethod ==
+ ONE_PACKAGE_PER_COMPONENT);
+ }
+
+ // CASE 3 : NON COMPONENT package.
+ DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive);
+ cmWorkingDirectory workdir(this->toplevel);
+ if (workdir.Failed()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Failed to change working directory to "
+ << this->toplevel << " : "
+ << std::strerror(workdir.GetLastResult()) << std::endl);
+ return 0;
+ }
+ for (std::string const& file : this->files) {
+ // Get the relative path to the file
+ std::string rp = cmSystemTools::RelativePath(this->toplevel, file);
+ archive.Add(rp, 0, nullptr, false);
+ if (!archive) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem while adding file <"
+ << file << "> to archive <" << this->packageFileNames[0]
+ << ">, ERROR = " << archive.GetError() << std::endl);
+ return 0;
+ }
+ }
+ // The destructor of cmArchiveWrite will close and finish the write
+ return 1;
+}
+
+int cmCPackArchiveGenerator::GenerateHeader(std::ostream* /*unused*/)
+{
+ return 1;
+}
+
+bool cmCPackArchiveGenerator::SupportsComponentInstallation() const
+{
+ // The Component installation support should only
+ // be activated if explicitly requested by the user
+ // (for backward compatibility reason)
+ return this->IsOn("CPACK_ARCHIVE_COMPONENT_INSTALL");
+}
+
+bool cmCPackArchiveGenerator::SetArchiveOptions(cmArchiveWrite* archive)
+{
+#if ARCHIVE_VERSION_NUMBER >= 3004000
+ // Upstream fixed an issue with their integer parsing in 3.4.0 which would
+ // cause spurious errors to be raised from `strtoull`.
+ if (this->Compress == cmArchiveWrite::CompressXZ) {
+ const char* threads = "1";
+
+ // CPACK_ARCHIVE_THREADS overrides CPACK_THREADS
+ if (this->IsSet("CPACK_ARCHIVE_THREADS")) {
+ threads = this->GetOption("CPACK_ARCHIVE_THREADS");
+ } else if (this->IsSet("CPACK_THREADS")) {
+ threads = this->GetOption("CPACK_THREADS");
+ }
+
+ if (!archive->SetFilterOption("xz", "threads", threads)) {
+ return false;
+ }
+ }
+#endif
+
+ return true;
+}
diff --git a/Source/CPack/cmCPackArchiveGenerator.h b/Source/CPack/cmCPackArchiveGenerator.h
new file mode 100644
index 0000000..5b40013
--- /dev/null
+++ b/Source/CPack/cmCPackArchiveGenerator.h
@@ -0,0 +1,94 @@
+/* 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 <iosfwd>
+#include <string>
+
+#include "cmArchiveWrite.h"
+#include "cmCPackGenerator.h"
+
+class cmCPackComponent;
+
+/** \class cmCPackArchiveGenerator
+ * \brief A generator base for libarchive generation.
+ * The generator itself uses the libarchive wrapper
+ * \ref cmArchiveWrite.
+ *
+ */
+class cmCPackArchiveGenerator : public cmCPackGenerator
+{
+public:
+ using Superclass = cmCPackGenerator;
+
+ static cmCPackGenerator* Create7ZGenerator();
+ static cmCPackGenerator* CreateTBZ2Generator();
+ static cmCPackGenerator* CreateTGZGenerator();
+ static cmCPackGenerator* CreateTXZGenerator();
+ static cmCPackGenerator* CreateTZGenerator();
+ static cmCPackGenerator* CreateTZSTGenerator();
+ static cmCPackGenerator* CreateZIPGenerator();
+
+ /**
+ * Construct generator
+ */
+ cmCPackArchiveGenerator(cmArchiveWrite::Compress t, std::string format,
+ std::string extension);
+ ~cmCPackArchiveGenerator() override;
+ // Used to add a header to the archive
+ virtual int GenerateHeader(std::ostream* os);
+ // component support
+ bool SupportsComponentInstallation() const override;
+
+private:
+ // get archive component filename
+ std::string GetArchiveComponentFileName(const std::string& component,
+ bool isGroupName);
+
+protected:
+ int InitializeInternal() override;
+ /**
+ * Add the files belonging to the specified component
+ * to the provided (already opened) archive.
+ * @param[in,out] archive the archive object
+ * @param[in] component the component whose file will be added to archive
+ */
+ int addOneComponentToArchive(cmArchiveWrite& archive,
+ cmCPackComponent* component);
+
+ /**
+ * The main package file method.
+ * If component install was required this
+ * method will call either PackageComponents or
+ * PackageComponentsAllInOne.
+ */
+ int PackageFiles() override;
+ /**
+ * The method used to package files when component
+ * install is used. This will create one
+ * archive for each component group.
+ */
+ int PackageComponents(bool ignoreGroup);
+ /**
+ * Special case of component install where all
+ * components will be put in a single installer.
+ */
+ int PackageComponentsAllInOne();
+
+private:
+ const char* GetNameOfClass() override { return "cmCPackArchiveGenerator"; }
+
+ const char* GetOutputExtension() override
+ {
+ return this->OutputExtension.c_str();
+ }
+
+ bool SetArchiveOptions(cmArchiveWrite* archive);
+
+private:
+ cmArchiveWrite::Compress Compress;
+ std::string ArchiveFormat;
+ std::string OutputExtension;
+};
diff --git a/Source/CPack/cmCPackBundleGenerator.cxx b/Source/CPack/cmCPackBundleGenerator.cxx
new file mode 100644
index 0000000..4d5f43f
--- /dev/null
+++ b/Source/CPack/cmCPackBundleGenerator.cxx
@@ -0,0 +1,275 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackBundleGenerator.h"
+
+#include <sstream>
+#include <vector>
+
+#include "cmCPackLog.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmCPackBundleGenerator::cmCPackBundleGenerator() = default;
+
+cmCPackBundleGenerator::~cmCPackBundleGenerator() = default;
+
+int cmCPackBundleGenerator::InitializeInternal()
+{
+ const char* name = this->GetOption("CPACK_BUNDLE_NAME");
+ if (nullptr == name) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_BUNDLE_NAME must be set to use the Bundle generator."
+ << std::endl);
+
+ return 0;
+ }
+
+ if (this->GetOption("CPACK_BUNDLE_APPLE_CERT_APP")) {
+ const std::string codesign_path = cmSystemTools::FindProgram(
+ "codesign", std::vector<std::string>(), false);
+
+ if (codesign_path.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot locate codesign command" << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_CODESIGN", codesign_path.c_str());
+ }
+
+ return this->Superclass::InitializeInternal();
+}
+
+const char* cmCPackBundleGenerator::GetPackagingInstallPrefix()
+{
+ this->InstallPrefix = cmStrCat('/', this->GetOption("CPACK_BUNDLE_NAME"),
+ ".app/Contents/Resources");
+
+ return this->InstallPrefix.c_str();
+}
+
+int cmCPackBundleGenerator::ConstructBundle()
+{
+
+ // Get required arguments ...
+ const std::string cpack_bundle_name = this->GetOption("CPACK_BUNDLE_NAME")
+ ? this->GetOption("CPACK_BUNDLE_NAME")
+ : "";
+ if (cpack_bundle_name.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_BUNDLE_NAME must be set." << std::endl);
+
+ return 0;
+ }
+
+ const std::string cpack_bundle_plist = this->GetOption("CPACK_BUNDLE_PLIST")
+ ? this->GetOption("CPACK_BUNDLE_PLIST")
+ : "";
+ if (cpack_bundle_plist.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_BUNDLE_PLIST must be set." << std::endl);
+
+ return 0;
+ }
+
+ const std::string cpack_bundle_icon = this->GetOption("CPACK_BUNDLE_ICON")
+ ? this->GetOption("CPACK_BUNDLE_ICON")
+ : "";
+ if (cpack_bundle_icon.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_BUNDLE_ICON must be set." << std::endl);
+
+ return 0;
+ }
+
+ // Get optional arguments ...
+ const std::string cpack_bundle_startup_command =
+ this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND")
+ ? this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND")
+ : "";
+
+ // The staging directory contains everything that will end-up inside the
+ // final disk image ...
+ std::string const staging = toplevel;
+
+ std::ostringstream contents;
+ contents << staging << "/" << cpack_bundle_name << ".app/"
+ << "Contents";
+
+ std::ostringstream application;
+ application << contents.str() << "/"
+ << "MacOS";
+
+ std::ostringstream resources;
+ resources << contents.str() << "/"
+ << "Resources";
+
+ // Install a required, user-provided bundle metadata file ...
+ std::ostringstream plist_source;
+ plist_source << cpack_bundle_plist;
+
+ std::ostringstream plist_target;
+ plist_target << contents.str() << "/"
+ << "Info.plist";
+
+ if (!this->CopyFile(plist_source, plist_target)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Error copying plist. Check the value of CPACK_BUNDLE_PLIST."
+ << std::endl);
+
+ return 0;
+ }
+
+ // Install a user-provided bundle icon ...
+ std::ostringstream icon_source;
+ icon_source << cpack_bundle_icon;
+
+ std::ostringstream icon_target;
+ icon_target << resources.str() << "/" << cpack_bundle_name << ".icns";
+
+ if (!this->CopyFile(icon_source, icon_target)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Error copying bundle icon. Check the value of CPACK_BUNDLE_ICON."
+ << std::endl);
+
+ return 0;
+ }
+
+ // Optionally a user-provided startup command (could be an
+ // executable or a script) ...
+ if (!cpack_bundle_startup_command.empty()) {
+ std::ostringstream command_source;
+ command_source << cpack_bundle_startup_command;
+
+ std::ostringstream command_target;
+ command_target << application.str() << "/" << cpack_bundle_name;
+
+ if (!this->CopyFile(command_source, command_target)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error copying startup command. "
+ " Check the value of CPACK_BUNDLE_STARTUP_COMMAND."
+ << std::endl);
+
+ return 0;
+ }
+
+ cmSystemTools::SetPermissions(command_target.str().c_str(), 0777);
+ }
+
+ return 1;
+}
+
+int cmCPackBundleGenerator::PackageFiles()
+{
+ if (!this->ConstructBundle()) {
+ return 0;
+ }
+
+ if (!this->SignBundle(toplevel)) {
+ return 0;
+ }
+
+ return this->CreateDMG(toplevel, packageFileNames[0]);
+}
+
+bool cmCPackBundleGenerator::SupportsComponentInstallation() const
+{
+ return false;
+}
+
+int cmCPackBundleGenerator::SignBundle(const std::string& src_dir)
+{
+ const std::string cpack_apple_cert_app =
+ this->GetOption("CPACK_BUNDLE_APPLE_CERT_APP")
+ ? this->GetOption("CPACK_BUNDLE_APPLE_CERT_APP")
+ : "";
+
+ // codesign the application.
+ if (!cpack_apple_cert_app.empty()) {
+ std::string output;
+ std::string bundle_path;
+ bundle_path =
+ cmStrCat(src_dir, '/', this->GetOption("CPACK_BUNDLE_NAME"), ".app");
+
+ // A list of additional files to sign, ie. frameworks and plugins.
+ const std::string sign_parameter =
+ this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_PARAMETER")
+ ? this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_PARAMETER")
+ : "--deep -f";
+
+ const std::string sign_files =
+ this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_FILES")
+ ? this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_FILES")
+ : "";
+
+ std::vector<std::string> relFiles = cmExpandedList(sign_files);
+
+ // sign the files supplied by the user, ie. frameworks.
+ for (auto const& file : relFiles) {
+ std::ostringstream temp_sign_file_cmd;
+ temp_sign_file_cmd << this->GetOption("CPACK_COMMAND_CODESIGN");
+ temp_sign_file_cmd << " " << sign_parameter << " -s \""
+ << cpack_apple_cert_app;
+ temp_sign_file_cmd << "\" -i ";
+ temp_sign_file_cmd << this->GetOption("CPACK_APPLE_BUNDLE_ID");
+ temp_sign_file_cmd << " \"";
+ temp_sign_file_cmd << bundle_path;
+ temp_sign_file_cmd << file << "\"";
+
+ if (!this->RunCommand(temp_sign_file_cmd, &output)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error signing file:" << bundle_path << file << std::endl
+ << output << std::endl);
+
+ return 0;
+ }
+ }
+
+ // sign main binary
+ std::ostringstream temp_sign_binary_cmd;
+ temp_sign_binary_cmd << this->GetOption("CPACK_COMMAND_CODESIGN");
+ temp_sign_binary_cmd << " " << sign_parameter << " -s \""
+ << cpack_apple_cert_app;
+ temp_sign_binary_cmd << "\" \"" << bundle_path << "\"";
+
+ if (!this->RunCommand(temp_sign_binary_cmd, &output)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error signing the application binary." << std::endl
+ << output
+ << std::endl);
+
+ return 0;
+ }
+
+ // sign app bundle
+ std::ostringstream temp_codesign_cmd;
+ temp_codesign_cmd << this->GetOption("CPACK_COMMAND_CODESIGN");
+ temp_codesign_cmd << " " << sign_parameter << " -s \""
+ << cpack_apple_cert_app << "\"";
+ if (this->GetOption("CPACK_BUNDLE_APPLE_ENTITLEMENTS")) {
+ temp_codesign_cmd << " --entitlements ";
+ temp_codesign_cmd << this->GetOption("CPACK_BUNDLE_APPLE_ENTITLEMENTS");
+ }
+ temp_codesign_cmd << " \"" << bundle_path << "\"";
+
+ if (!this->RunCommand(temp_codesign_cmd, &output)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error signing the application package." << std::endl
+ << output
+ << std::endl);
+
+ return 0;
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Application has been codesigned" << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ (this->GetOption("CPACK_BUNDLE_APPLE_ENTITLEMENTS")
+ ? "with entitlement sandboxing"
+ : "without entitlement sandboxing")
+ << std::endl);
+ }
+
+ return 1;
+}
diff --git a/Source/CPack/cmCPackBundleGenerator.h b/Source/CPack/cmCPackBundleGenerator.h
new file mode 100644
index 0000000..072d14f
--- /dev/null
+++ b/Source/CPack/cmCPackBundleGenerator.h
@@ -0,0 +1,34 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+
+#include "cmCPackDragNDropGenerator.h"
+#include "cmCPackGenerator.h"
+
+/** \class cmCPackBundleGenerator
+ * \brief A generator for OSX bundles
+ *
+ * Based on Gimp.app
+ */
+class cmCPackBundleGenerator : public cmCPackDragNDropGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackBundleGenerator, cmCPackDragNDropGenerator);
+
+ cmCPackBundleGenerator();
+ ~cmCPackBundleGenerator() override;
+
+protected:
+ int InitializeInternal() override;
+ const char* GetPackagingInstallPrefix() override;
+ int ConstructBundle();
+ int SignBundle(const std::string& src_dir);
+ int PackageFiles() override;
+ bool SupportsComponentInstallation() const override;
+
+ std::string InstallPrefix;
+};
diff --git a/Source/CPack/cmCPackComponentGroup.cxx b/Source/CPack/cmCPackComponentGroup.cxx
new file mode 100644
index 0000000..4305c7e
--- /dev/null
+++ b/Source/CPack/cmCPackComponentGroup.cxx
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackComponentGroup.h"
+
+#include <string>
+
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+unsigned long cmCPackComponent::GetInstalledSize(
+ const std::string& installDir) const
+{
+ if (this->TotalSize != 0) {
+ return this->TotalSize;
+ }
+
+ for (std::string const& file : this->Files) {
+ std::string path = cmStrCat(installDir, '/', file);
+ this->TotalSize += cmSystemTools::FileLength(path);
+ }
+
+ return this->TotalSize;
+}
+
+unsigned long cmCPackComponent::GetInstalledSizeInKbytes(
+ const std::string& installDir) const
+{
+ unsigned long result = (this->GetInstalledSize(installDir) + 512) / 1024;
+ return result ? result : 1;
+}
diff --git a/Source/CPack/cmCPackComponentGroup.h b/Source/CPack/cmCPackComponentGroup.h
new file mode 100644
index 0000000..58377d4
--- /dev/null
+++ b/Source/CPack/cmCPackComponentGroup.h
@@ -0,0 +1,168 @@
+/* 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 <string>
+#include <vector>
+
+class cmCPackComponentGroup;
+
+/** \class cmCPackInstallationType
+ * \brief A certain type of installation, which encompasses a
+ * set of components.
+ */
+class cmCPackInstallationType
+{
+public:
+ /// The name of the installation type (used to reference this
+ /// installation type).
+ std::string Name;
+
+ /// The name of the installation type as displayed to the user.
+ std::string DisplayName;
+
+ /// The index number of the installation type. This is an arbitrary
+ /// numbering from 1 to the number of installation types.
+ unsigned Index;
+};
+
+/** \class cmCPackComponent
+ * \brief A single component to be installed by CPack.
+ */
+class cmCPackComponent
+{
+public:
+ cmCPackComponent()
+ : Group(nullptr)
+ , IsRequired(true)
+ , IsHidden(false)
+ , IsDisabledByDefault(false)
+ , IsDownloaded(false)
+ , TotalSize(0)
+ {
+ }
+
+ /// The name of the component (used to reference the component).
+ std::string Name;
+
+ /// The name of the component as displayed to the user.
+ std::string DisplayName;
+
+ /// The component group that contains this component (if any).
+ cmCPackComponentGroup* Group;
+
+ /// Whether this component group must always be installed.
+ bool IsRequired : 1;
+
+ /// Whether this component group is hidden. A hidden component group
+ /// is always installed. However, it may still be shown to the user.
+ bool IsHidden : 1;
+
+ /// Whether this component defaults to "disabled".
+ bool IsDisabledByDefault : 1;
+
+ /// Whether this component should be downloaded on-the-fly. If false,
+ /// the component will be a part of the installation package.
+ bool IsDownloaded : 1;
+
+ /// A description of this component.
+ std::string Description;
+
+ /// The installation types that this component is a part of.
+ std::vector<cmCPackInstallationType*> InstallationTypes;
+
+ /// If IsDownloaded is true, the name of the archive file that
+ /// contains the files that are part of this component.
+ std::string ArchiveFile;
+
+ /// The file to pass to --component-plist when using the
+ /// productbuild generator.
+ std::string Plist;
+
+ /// The components that this component depends on.
+ std::vector<cmCPackComponent*> Dependencies;
+
+ /// The components that depend on this component.
+ std::vector<cmCPackComponent*> ReverseDependencies;
+
+ /// The list of installed files that are part of this component.
+ std::vector<std::string> Files;
+
+ /// The list of installed directories that are part of this component.
+ std::vector<std::string> Directories;
+
+ /// Get the total installed size of all of the files in this
+ /// component, in bytes. installDir is the directory into which the
+ /// component was installed.
+ unsigned long GetInstalledSize(const std::string& installDir) const;
+
+ /// Identical to GetInstalledSize, but returns the result in
+ /// kilobytes.
+ unsigned long GetInstalledSizeInKbytes(const std::string& installDir) const;
+
+private:
+ mutable unsigned long TotalSize;
+};
+
+/** \class cmCPackComponentGroup
+ * \brief A component group to be installed by CPack.
+ */
+class cmCPackComponentGroup
+{
+public:
+ cmCPackComponentGroup()
+ : ParentGroup(nullptr)
+ {
+ }
+
+ /// The name of the group (used to reference the group).
+ std::string Name;
+
+ /// The name of the component as displayed to the user.
+ std::string DisplayName;
+
+ /// The description of this component group.
+ std::string Description;
+
+ /// Whether the name of the component will be shown in bold.
+ bool IsBold : 1;
+
+ /// Whether the section should be expanded by default
+ bool IsExpandedByDefault : 1;
+
+ /// The components within this group.
+ std::vector<cmCPackComponent*> Components;
+
+ /// The parent group of this component group (if any).
+ cmCPackComponentGroup* ParentGroup;
+
+ /// The subgroups of this group.
+ std::vector<cmCPackComponentGroup*> Subgroups;
+};
+
+/** \class cmCPackInstallCMakeProject
+ * \brief A single quadruplet from the CPACK_INSTALL_CMAKE_PROJECTS variable.
+ */
+class cmCPackInstallCMakeProject
+{
+public:
+ /// The directory of the CMake project.
+ std::string Directory;
+
+ /// The name of the CMake project.
+ std::string ProjectName;
+
+ /// The name of the component (or component set) to install.
+ std::string Component;
+
+ /// The subdirectory to install into.
+ std::string SubDirectory;
+
+ /// The list of installation types.
+ std::vector<cmCPackInstallationType*> InstallationTypes;
+
+ /// The list of components.
+ std::vector<cmCPackComponent*> Components;
+};
diff --git a/Source/CPack/cmCPackConfigure.h.in b/Source/CPack/cmCPackConfigure.h.in
new file mode 100644
index 0000000..8ac1661
--- /dev/null
+++ b/Source/CPack/cmCPackConfigure.h.in
@@ -0,0 +1,2 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
diff --git a/Source/CPack/cmCPackCygwinBinaryGenerator.cxx b/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
new file mode 100644
index 0000000..b5abd5a
--- /dev/null
+++ b/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
@@ -0,0 +1,72 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackCygwinBinaryGenerator.h"
+
+#include "cmsys/SystemTools.hxx"
+
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+cmCPackCygwinBinaryGenerator::cmCPackCygwinBinaryGenerator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressBZip2, "paxr", ".tar.bz2")
+{
+}
+
+cmCPackCygwinBinaryGenerator::~cmCPackCygwinBinaryGenerator()
+{
+}
+
+int cmCPackCygwinBinaryGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
+ this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "0");
+ return this->Superclass::InitializeInternal();
+}
+
+int cmCPackCygwinBinaryGenerator::PackageFiles()
+{
+ std::string packageName =
+ cmStrCat(this->GetOption("CPACK_PACKAGE_NAME"), '-',
+ this->GetOption("CPACK_PACKAGE_VERSION"));
+ packageName = cmsys::SystemTools::LowerCase(packageName);
+ std::string manifest = cmStrCat("/usr/share/doc/", packageName, "/MANIFEST");
+ std::string manifestFile = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ // Create a MANIFEST file that contains all of the files in
+ // the tar file
+ std::string tempdir = manifestFile;
+ manifestFile += manifest;
+ // create an extra scope to force the stream
+ // to create the file before the super class is called
+ {
+ cmGeneratedFileStream ofs(manifestFile.c_str());
+ for (std::string const& file : files) {
+ // remove the temp dir and replace with /usr
+ ofs << file.substr(tempdir.size()) << "\n";
+ }
+ ofs << manifest << "\n";
+ }
+ // add the manifest file to the list of all files
+ files.push_back(manifestFile);
+
+ // create the bzip2 tar file
+ return this->Superclass::PackageFiles();
+}
+
+const char* cmCPackCygwinBinaryGenerator::GetOutputExtension()
+{
+ this->OutputExtension = "-";
+ const char* patchNumber = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
+ if (!patchNumber) {
+ patchNumber = "1";
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "CPACK_CYGWIN_PATCH_NUMBER not specified using 1"
+ << std::endl);
+ }
+ this->OutputExtension += patchNumber;
+ this->OutputExtension += ".tar.bz2";
+ return this->OutputExtension.c_str();
+}
diff --git a/Source/CPack/cmCPackCygwinBinaryGenerator.h b/Source/CPack/cmCPackCygwinBinaryGenerator.h
new file mode 100644
index 0000000..f5f7700
--- /dev/null
+++ b/Source/CPack/cmCPackCygwinBinaryGenerator.h
@@ -0,0 +1,26 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmCPackArchiveGenerator.h"
+
+/** \class cmCPackCygwinBinaryGenerator
+ * \brief A generator for TarBZip2 files
+ */
+class cmCPackCygwinBinaryGenerator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackCygwinBinaryGenerator, cmCPackArchiveGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackCygwinBinaryGenerator();
+ ~cmCPackCygwinBinaryGenerator() override;
+
+protected:
+ virtual int InitializeInternal();
+ int PackageFiles();
+ virtual const char* GetOutputExtension();
+ std::string OutputExtension;
+};
diff --git a/Source/CPack/cmCPackCygwinSourceGenerator.cxx b/Source/CPack/cmCPackCygwinSourceGenerator.cxx
new file mode 100644
index 0000000..64a88eb
--- /dev/null
+++ b/Source/CPack/cmCPackCygwinSourceGenerator.cxx
@@ -0,0 +1,158 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackCygwinSourceGenerator.h"
+
+#include "cmsys/SystemTools.hxx"
+
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+// Includes needed for implementation of RenameFile. This is not in
+// system tools because it is not implemented robustly enough to move
+// files across directories.
+#ifdef _WIN32
+# include <windows.h>
+
+# include "cm_sys_stat.h"
+#endif
+
+cmCPackCygwinSourceGenerator::cmCPackCygwinSourceGenerator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressBZip2, "paxr", ".tar.bz2")
+{
+}
+
+cmCPackCygwinSourceGenerator::~cmCPackCygwinSourceGenerator()
+{
+}
+
+int cmCPackCygwinSourceGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "0");
+ return this->Superclass::InitializeInternal();
+}
+
+int cmCPackCygwinSourceGenerator::PackageFiles()
+{
+ // Create a tar file of the sources
+ std::string packageDirFileName =
+ cmStrCat(this->GetOption("CPACK_TEMPORARY_DIRECTORY"), ".tar.bz2");
+ packageFileNames[0] = packageDirFileName;
+ std::string output;
+ // create tar.bz2 file with the list of source files
+ if (!this->cmCPackArchiveGenerator::PackageFiles()) {
+ return 0;
+ }
+ // Now create a tar file that contains the above .tar.bz2 file
+ // and the CPACK_CYGWIN_PATCH_FILE and CPACK_TOPLEVEL_DIRECTORY
+ // files
+ std::string compressOutFile = packageDirFileName;
+ // at this point compressOutFile is the full path to
+ // _CPack_Package/.../package-2.5.0.tar.bz2
+ // we want to create a tar _CPack_Package/.../package-2.5.0-1-src.tar.bz2
+ // with these
+ // _CPack_Package/.../package-2.5.0-1.patch
+ // _CPack_Package/.../package-2.5.0-1.sh
+ // _CPack_Package/.../package-2.5.0.tar.bz2
+ // the -1 is CPACK_CYGWIN_PATCH_NUMBER
+
+ // first copy the patch file and the .sh file
+ // to the toplevel cpack temp dir
+
+ // copy the patch file into place
+ if (!this->GetOption("CPACK_CYGWIN_PATCH_FILE")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "No patch file specified for cygwin sources.");
+ return 0;
+ }
+ if (!cmSystemTools::CopyFileAlways(
+ this->GetOption("CPACK_CYGWIN_PATCH_FILE"),
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY"))) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "problem copying: ["
+ << this->GetOption("CPACK_CYGWIN_PATCH_FILE") << "]\nto\n["
+ << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "]\n");
+ return 0;
+ }
+ if (!this->GetOption("CPACK_CYGWIN_BUILD_SCRIPT")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "No build script specified for cygwin sources.");
+ return 0;
+ }
+ // copy the build script into place
+ if (!cmSystemTools::CopyFileAlways(
+ this->GetOption("CPACK_CYGWIN_BUILD_SCRIPT"),
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY"))) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "problem copying: "
+ << this->GetOption("CPACK_CYGWIN_BUILD_SCRIPT") << "\nto\n"
+ << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "]\n");
+ return 0;
+ }
+ std::string outerTarFile =
+ cmStrCat(this->GetOption("CPACK_TEMPORARY_DIRECTORY"), '-');
+ const char* patch = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
+ if (!patch) {
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "CPACK_CYGWIN_PATCH_NUMBER"
+ << " not specified, defaulting to 1\n");
+ patch = "1";
+ }
+ outerTarFile += patch;
+ outerTarFile += "-src.tar.bz2";
+ std::string tmpDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ std::string buildScript =
+ cmStrCat(tmpDir, '/',
+ cmSystemTools::GetFilenameName(
+ this->GetOption("CPACK_CYGWIN_BUILD_SCRIPT")));
+ std::string patchFile =
+ cmStrCat(tmpDir, '/',
+ cmSystemTools::GetFilenameName(
+ this->GetOption("CPACK_CYGWIN_PATCH_FILE")));
+
+ std::string file = cmSystemTools::GetFilenameName(compressOutFile);
+ std::string sourceTar =
+ cmStrCat(cmSystemTools::GetFilenamePath(compressOutFile), '/', file);
+ /* reset list of file to be packaged */
+ files.clear();
+ // a source release in cygwin should have the build script used
+ // to build the package, the patch file that is different from the
+ // regular upstream version of the sources, and a bziped tar file
+ // of the original sources
+ files.push_back(buildScript);
+ files.push_back(patchFile);
+ files.push_back(sourceTar);
+ /* update the name of the produced package */
+ packageFileNames[0] = outerTarFile;
+ /* update the toplevel dir */
+ toplevel = tmpDir;
+ if (!this->cmCPackArchiveGenerator::PackageFiles()) {
+ return 0;
+ }
+ return 1;
+}
+
+const char* cmCPackCygwinSourceGenerator::GetPackagingInstallPrefix()
+{
+ this->InstallPrefix =
+ cmStrCat('/', this->GetOption("CPACK_PACKAGE_FILE_NAME"));
+ return this->InstallPrefix.c_str();
+}
+
+const char* cmCPackCygwinSourceGenerator::GetOutputExtension()
+{
+ this->OutputExtension = "-";
+ const char* patch = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
+ if (!patch) {
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "CPACK_CYGWIN_PATCH_NUMBER"
+ << " not specified, defaulting to 1\n");
+ patch = "1";
+ }
+ this->OutputExtension += patch;
+ this->OutputExtension += "-src.tar.bz2";
+ return this->OutputExtension.c_str();
+}
diff --git a/Source/CPack/cmCPackCygwinSourceGenerator.h b/Source/CPack/cmCPackCygwinSourceGenerator.h
new file mode 100644
index 0000000..964a4d4
--- /dev/null
+++ b/Source/CPack/cmCPackCygwinSourceGenerator.h
@@ -0,0 +1,28 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmCPackArchiveGenerator.h"
+
+/** \class cmCPackCygwinSourceGenerator
+ * \brief A generator for cygwin source files
+ */
+class cmCPackCygwinSourceGenerator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackCygwinSourceGenerator, cmCPackArchiveGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackCygwinSourceGenerator();
+ ~cmCPackCygwinSourceGenerator() override;
+
+protected:
+ const char* GetPackagingInstallPrefix();
+ virtual int InitializeInternal();
+ int PackageFiles();
+ virtual const char* GetOutputExtension();
+ std::string InstallPrefix;
+ std::string OutputExtension;
+};
diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx
new file mode 100644
index 0000000..e7bcfac
--- /dev/null
+++ b/Source/CPack/cmCPackDebGenerator.cxx
@@ -0,0 +1,923 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackDebGenerator.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <map>
+#include <ostream>
+#include <set>
+#include <utility>
+
+#include "cmsys/Glob.hxx"
+
+#include "cm_sys_stat.h"
+
+#include "cmArchiveWrite.h"
+#include "cmCPackComponentGroup.h"
+#include "cmCPackGenerator.h"
+#include "cmCPackLog.h"
+#include "cmCryptoHash.h"
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+
+class DebGenerator
+{
+public:
+ DebGenerator(cmCPackLog* logger, std::string outputName, std::string workDir,
+ std::string topLevelDir, std::string temporaryDir,
+ const char* debianCompressionType, const char* numThreads,
+ const char* debianArchiveType,
+ std::map<std::string, std::string> controlValues,
+ bool genShLibs, std::string shLibsFilename, bool genPostInst,
+ std::string postInst, bool genPostRm, std::string postRm,
+ const char* controlExtra, bool permissionStrctPolicy,
+ std::vector<std::string> packageFiles);
+
+ bool generate() const;
+
+private:
+ void generateDebianBinaryFile() const;
+ void generateControlFile() const;
+ bool generateDataTar() const;
+ std::string generateMD5File() const;
+ bool generateControlTar(std::string const& md5Filename) const;
+ bool generateDeb() const;
+
+ cmCPackLog* Logger;
+ const std::string OutputName;
+ const std::string WorkDir;
+ std::string CompressionSuffix;
+ const std::string TopLevelDir;
+ const std::string TemporaryDir;
+ const char* DebianArchiveType;
+ int NumThreads;
+ const std::map<std::string, std::string> ControlValues;
+ const bool GenShLibs;
+ const std::string ShLibsFilename;
+ const bool GenPostInst;
+ const std::string PostInst;
+ const bool GenPostRm;
+ const std::string PostRm;
+ const char* ControlExtra;
+ const bool PermissionStrictPolicy;
+ const std::vector<std::string> PackageFiles;
+ cmArchiveWrite::Compress TarCompressionType;
+};
+
+DebGenerator::DebGenerator(
+ cmCPackLog* logger, std::string outputName, std::string workDir,
+ std::string topLevelDir, std::string temporaryDir,
+ const char* debianCompressionType, const char* numThreads,
+ const char* debianArchiveType,
+ std::map<std::string, std::string> controlValues, bool genShLibs,
+ std::string shLibsFilename, bool genPostInst, std::string postInst,
+ bool genPostRm, std::string postRm, const char* controlExtra,
+ bool permissionStrictPolicy, std::vector<std::string> packageFiles)
+ : Logger(logger)
+ , OutputName(std::move(outputName))
+ , WorkDir(std::move(workDir))
+ , TopLevelDir(std::move(topLevelDir))
+ , TemporaryDir(std::move(temporaryDir))
+ , DebianArchiveType(debianArchiveType ? debianArchiveType : "gnutar")
+ , ControlValues(std::move(controlValues))
+ , GenShLibs(genShLibs)
+ , ShLibsFilename(std::move(shLibsFilename))
+ , GenPostInst(genPostInst)
+ , PostInst(std::move(postInst))
+ , GenPostRm(genPostRm)
+ , PostRm(std::move(postRm))
+ , ControlExtra(controlExtra)
+ , PermissionStrictPolicy(permissionStrictPolicy)
+ , PackageFiles(std::move(packageFiles))
+{
+ if (!debianCompressionType) {
+ debianCompressionType = "gzip";
+ }
+
+ if (!strcmp(debianCompressionType, "lzma")) {
+ this->CompressionSuffix = ".lzma";
+ this->TarCompressionType = cmArchiveWrite::CompressLZMA;
+ } else if (!strcmp(debianCompressionType, "xz")) {
+ this->CompressionSuffix = ".xz";
+ this->TarCompressionType = cmArchiveWrite::CompressXZ;
+ } else if (!strcmp(debianCompressionType, "bzip2")) {
+ this->CompressionSuffix = ".bz2";
+ this->TarCompressionType = cmArchiveWrite::CompressBZip2;
+ } else if (!strcmp(debianCompressionType, "gzip")) {
+ this->CompressionSuffix = ".gz";
+ this->TarCompressionType = cmArchiveWrite::CompressGZip;
+ } else if (!strcmp(debianCompressionType, "none")) {
+ this->CompressionSuffix.clear();
+ this->TarCompressionType = cmArchiveWrite::CompressNone;
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error unrecognized compression type: "
+ << debianCompressionType << std::endl);
+ }
+
+ if (numThreads == nullptr) {
+ numThreads = "1";
+ }
+
+ char* endptr;
+ this->NumThreads = static_cast<int>(strtol(numThreads, &endptr, 10));
+ if (numThreads != endptr && *endptr != '\0') {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Unrecognized number of threads: " << numThreads
+ << std::endl);
+ }
+
+ if (this->NumThreads < 0) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Number of threads cannot be negative" << std::endl);
+ }
+}
+
+bool DebGenerator::generate() const
+{
+ this->generateDebianBinaryFile();
+ this->generateControlFile();
+ if (!this->generateDataTar()) {
+ return false;
+ }
+ std::string md5Filename = this->generateMD5File();
+ if (!this->generateControlTar(md5Filename)) {
+ return false;
+ }
+ return this->generateDeb();
+}
+
+void DebGenerator::generateDebianBinaryFile() const
+{
+ // debian-binary file
+ const std::string dbfilename = this->WorkDir + "/debian-binary";
+ cmGeneratedFileStream out;
+ out.Open(dbfilename, false, true);
+ out << "2.0\n"; // required for valid debian package
+}
+
+void DebGenerator::generateControlFile() const
+{
+ std::string ctlfilename = this->WorkDir + "/control";
+
+ cmGeneratedFileStream out;
+ out.Open(ctlfilename, false, true);
+ for (auto const& kv : this->ControlValues) {
+ out << kv.first << ": " << kv.second << "\n";
+ }
+
+ unsigned long totalSize = 0;
+ {
+ std::string dirName = cmStrCat(this->TemporaryDir, '/');
+ for (std::string const& file : this->PackageFiles) {
+ totalSize += cmSystemTools::FileLength(file);
+ }
+ }
+ out << "Installed-Size: " << (totalSize + 1023) / 1024 << "\n\n";
+}
+
+bool DebGenerator::generateDataTar() const
+{
+ std::string filename_data_tar =
+ this->WorkDir + "/data.tar" + this->CompressionSuffix;
+ cmGeneratedFileStream fileStream_data_tar;
+ fileStream_data_tar.Open(filename_data_tar, false, true);
+ if (!fileStream_data_tar) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error opening the file \""
+ << filename_data_tar << "\" for writing" << std::endl);
+ return false;
+ }
+ cmArchiveWrite data_tar(fileStream_data_tar, this->TarCompressionType,
+ this->DebianArchiveType, 0, this->NumThreads);
+ data_tar.Open();
+
+ // uid/gid should be the one of the root user, and this root user has
+ // always uid/gid equal to 0.
+ data_tar.SetUIDAndGID(0u, 0u);
+ data_tar.SetUNAMEAndGNAME("root", "root");
+
+ // now add all directories which have to be compressed
+ // collect all top level install dirs for that
+ // e.g. /opt/bin/foo, /usr/bin/bar and /usr/bin/baz would
+ // give /usr and /opt
+ size_t topLevelLength = this->WorkDir.length();
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "WDIR: \"" << this->WorkDir
+ << "\", length = " << topLevelLength << std::endl);
+ std::set<std::string> orderedFiles;
+
+ // we have to reconstruct the parent folders as well
+
+ for (std::string currentPath : this->PackageFiles) {
+ while (currentPath != this->WorkDir) {
+ // the last one IS WorkDir, but we do not want this one:
+ // XXX/application/usr/bin/myprogram with GEN_WDIR=XXX/application
+ // should not add XXX/application
+ orderedFiles.insert(currentPath);
+ currentPath = cmSystemTools::CollapseFullPath("..", currentPath);
+ }
+ }
+
+ for (std::string const& file : orderedFiles) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "FILEIT: \"" << file << "\"" << std::endl);
+ std::string::size_type slashPos = file.find('/', topLevelLength + 1);
+ std::string relativeDir =
+ file.substr(topLevelLength, slashPos - topLevelLength);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "RELATIVEDIR: \"" << relativeDir << "\"" << std::endl);
+
+#ifdef WIN32
+ std::string mode_t_adt_filename = file + ":cmake_mode_t";
+ cmsys::ifstream permissionStream(mode_t_adt_filename.c_str());
+
+ mode_t permissions = 0;
+
+ if (permissionStream) {
+ permissionStream >> std::oct >> permissions;
+ }
+
+ if (permissions != 0) {
+ data_tar.SetPermissions(permissions);
+ } else if (cmSystemTools::FileIsDirectory(file)) {
+ data_tar.SetPermissions(0755);
+ } else {
+ data_tar.ClearPermissions();
+ }
+#endif
+
+ // do not recurse because the loop will do it
+ if (!data_tar.Add(file, topLevelLength, ".", false)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem adding file to tar:"
+ << std::endl
+ << "#top level directory: " << this->WorkDir << std::endl
+ << "#file: " << file << std::endl
+ << "#error:" << data_tar.GetError() << std::endl);
+ return false;
+ }
+ }
+ return true;
+}
+
+std::string DebGenerator::generateMD5File() const
+{
+ std::string md5filename = this->WorkDir + "/md5sums";
+
+ cmGeneratedFileStream out;
+ out.Open(md5filename, false, true);
+
+ std::string topLevelWithTrailingSlash = cmStrCat(this->TemporaryDir, '/');
+ for (std::string const& file : this->PackageFiles) {
+ // hash only regular files
+ if (cmSystemTools::FileIsDirectory(file) ||
+ cmSystemTools::FileIsSymlink(file)) {
+ continue;
+ }
+
+ std::string output =
+ cmSystemTools::ComputeFileHash(file, cmCryptoHash::AlgoMD5);
+ if (output.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem computing the md5 of " << file << std::endl);
+ }
+
+ output += " " + file + "\n";
+ // debian md5sums entries are like this:
+ // 014f3604694729f3bf19263bac599765 usr/bin/ccmake
+ // thus strip the full path (with the trailing slash)
+ cmSystemTools::ReplaceString(output, topLevelWithTrailingSlash.c_str(),
+ "");
+ out << output;
+ }
+ // each line contains a eol.
+ // Do not end the md5sum file with yet another (invalid)
+ return md5filename;
+}
+
+bool DebGenerator::generateControlTar(std::string const& md5Filename) const
+{
+ std::string filename_control_tar = this->WorkDir + "/control.tar.gz";
+
+ cmGeneratedFileStream fileStream_control_tar;
+ fileStream_control_tar.Open(filename_control_tar, false, true);
+ if (!fileStream_control_tar) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error opening the file \""
+ << filename_control_tar << "\" for writing" << std::endl);
+ return false;
+ }
+ cmArchiveWrite control_tar(fileStream_control_tar,
+ cmArchiveWrite::CompressGZip,
+ this->DebianArchiveType);
+ control_tar.Open();
+
+ // sets permissions and uid/gid for the files
+ control_tar.SetUIDAndGID(0u, 0u);
+ control_tar.SetUNAMEAndGNAME("root", "root");
+
+ /* permissions are set according to
+ https://www.debian.org/doc/debian-policy/ch-files.html#s-permissions-owners
+ and
+ https://lintian.debian.org/tags/control-file-has-bad-permissions.html
+ */
+ const mode_t permission644 = 0644;
+ const mode_t permissionExecute = 0111;
+ const mode_t permission755 = permission644 | permissionExecute;
+
+ // for md5sum and control (that we have generated here), we use 644
+ // (RW-R--R--)
+ // so that deb lintian doesn't warn about it
+ control_tar.SetPermissions(permission644);
+
+ // adds control and md5sums
+ if (!control_tar.Add(md5Filename, this->WorkDir.length(), ".") ||
+ !control_tar.Add(this->WorkDir + "/control", this->WorkDir.length(),
+ ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << this->WorkDir << std::endl
+ << "#file: \"control\" or \"md5sums\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return false;
+ }
+
+ // adds generated shlibs file
+ if (this->GenShLibs) {
+ if (!control_tar.Add(this->ShLibsFilename, this->WorkDir.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << this->WorkDir << std::endl
+ << "#file: \"shlibs\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return false;
+ }
+ }
+
+ // adds LDCONFIG related files
+ if (this->GenPostInst) {
+ control_tar.SetPermissions(permission755);
+ if (!control_tar.Add(this->PostInst, this->WorkDir.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << this->WorkDir << std::endl
+ << "#file: \"postinst\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return false;
+ }
+ control_tar.SetPermissions(permission644);
+ }
+
+ if (this->GenPostRm) {
+ control_tar.SetPermissions(permission755);
+ if (!control_tar.Add(this->PostRm, this->WorkDir.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << this->WorkDir << std::endl
+ << "#file: \"postinst\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return false;
+ }
+ control_tar.SetPermissions(permission644);
+ }
+
+ // for the other files, we use
+ // -either the original permission on the files
+ // -either a permission strictly defined by the Debian policies
+ if (this->ControlExtra) {
+ // permissions are now controlled by the original file permissions
+
+ static const char* strictFiles[] = { "config", "postinst", "postrm",
+ "preinst", "prerm" };
+ std::set<std::string> setStrictFiles(
+ strictFiles, strictFiles + sizeof(strictFiles) / sizeof(strictFiles[0]));
+
+ // default
+ control_tar.ClearPermissions();
+
+ std::vector<std::string> controlExtraList =
+ cmExpandedList(this->ControlExtra);
+ for (std::string const& i : controlExtraList) {
+ std::string filenamename = cmsys::SystemTools::GetFilenameName(i);
+ std::string localcopy = this->WorkDir + "/" + filenamename;
+
+ if (this->PermissionStrictPolicy) {
+ control_tar.SetPermissions(
+ setStrictFiles.count(filenamename) ? permission755 : permission644);
+ }
+
+ // if we can copy the file, it means it does exist, let's add it:
+ if (!cmsys::SystemTools::FileExists(i)) {
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "Adding file to tar:" << std::endl
+ << "#top level directory: "
+ << this->WorkDir << std::endl
+ << "#missing file: " << i
+ << std::endl);
+ }
+
+ if (cmsys::SystemTools::CopyFileIfDifferent(i, localcopy)) {
+ control_tar.Add(localcopy, this->WorkDir.length(), ".");
+ }
+ }
+ }
+
+ return true;
+}
+
+bool DebGenerator::generateDeb() const
+{
+ // ar -r your-package-name.deb debian-binary control.tar.* data.tar.*
+ // A debian package .deb is simply an 'ar' archive. The only subtle
+ // difference is that debian uses the BSD ar style archive whereas most
+ // Linux distro have a GNU ar.
+ // See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=161593 for more info
+ std::string const outputPath = this->TopLevelDir + "/" + this->OutputName;
+ std::string const tlDir = this->WorkDir + "/";
+ cmGeneratedFileStream debStream;
+ debStream.Open(outputPath, false, true);
+ cmArchiveWrite deb(debStream, cmArchiveWrite::CompressNone, "arbsd");
+ deb.Open();
+
+ // uid/gid should be the one of the root user, and this root user has
+ // always uid/gid equal to 0.
+ deb.SetUIDAndGID(0u, 0u);
+ deb.SetUNAMEAndGNAME("root", "root");
+
+ if (!deb.Add(tlDir + "debian-binary", tlDir.length()) ||
+ !deb.Add(tlDir + "control.tar.gz", tlDir.length()) ||
+ !deb.Add(tlDir + "data.tar" + this->CompressionSuffix, tlDir.length())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error creating debian package:"
+ << std::endl
+ << "#top level directory: " << this->TopLevelDir
+ << std::endl
+ << "#file: " << this->OutputName << std::endl
+ << "#error:" << deb.GetError() << std::endl);
+ return false;
+ }
+ return true;
+}
+
+} // end anonymous namespace
+
+cmCPackDebGenerator::cmCPackDebGenerator() = default;
+
+cmCPackDebGenerator::~cmCPackDebGenerator() = default;
+
+int cmCPackDebGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
+ if (cmIsOff(this->GetOption("CPACK_SET_DESTDIR"))) {
+ this->SetOption("CPACK_SET_DESTDIR", "I_ON");
+ }
+ return this->Superclass::InitializeInternal();
+}
+
+int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
+ std::string const& packageName)
+{
+ int retval = 1;
+ // Begin the archive for this pack
+ std::string localToplevel(initialTopLevel);
+ std::string packageFileName(
+ cmSystemTools::GetParentDirectory(this->toplevel));
+ std::string outputFileName(
+ std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) + "-" +
+ packageName + this->GetOutputExtension());
+
+ localToplevel += "/" + packageName;
+ /* replace the TEMP DIRECTORY with the component one */
+ this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str());
+ packageFileName += "/" + outputFileName;
+ /* replace proposed CPACK_OUTPUT_FILE_NAME */
+ this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName.c_str());
+ /* replace the TEMPORARY package file name */
+ this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
+ packageFileName.c_str());
+ // Tell CPackDeb.cmake the name of the component GROUP.
+ this->SetOption("CPACK_DEB_PACKAGE_COMPONENT", packageName.c_str());
+ // Tell CPackDeb.cmake the path where the component is.
+ std::string component_path = cmStrCat('/', packageName);
+ this->SetOption("CPACK_DEB_PACKAGE_COMPONENT_PART_PATH",
+ component_path.c_str());
+ if (!this->ReadListFile("Internal/CPack/CPackDeb.cmake")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while execution CPackDeb.cmake" << std::endl);
+ retval = 0;
+ return retval;
+ }
+
+ { // Isolate globbing of binaries vs. dbgsyms
+ cmsys::Glob gl;
+ std::string findExpr(this->GetOption("GEN_WDIR"));
+ findExpr += "/*";
+ gl.RecurseOn();
+ gl.SetRecurseListDirs(true);
+ gl.SetRecurseThroughSymlinks(false);
+ if (!gl.FindFiles(findExpr)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find any files in the installed directory"
+ << std::endl);
+ return 0;
+ }
+ this->packageFiles = gl.GetFiles();
+ }
+
+ int res = this->createDeb();
+ if (res != 1) {
+ retval = 0;
+ }
+ // add the generated package to package file names list
+ packageFileName = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
+ this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"));
+ this->packageFileNames.push_back(std::move(packageFileName));
+
+ if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE") &&
+ this->GetOption("GEN_DBGSYMDIR")) {
+ cmsys::Glob gl;
+ std::string findExpr(this->GetOption("GEN_DBGSYMDIR"));
+ findExpr += "/*";
+ gl.RecurseOn();
+ gl.SetRecurseListDirs(true);
+ gl.SetRecurseThroughSymlinks(false);
+ if (!gl.FindFiles(findExpr)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find any files in the installed directory"
+ << std::endl);
+ return 0;
+ }
+ this->packageFiles = gl.GetFiles();
+
+ res = this->createDbgsymDDeb();
+ if (res != 1) {
+ retval = 0;
+ }
+ // add the generated package to package file names list
+ packageFileName =
+ cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
+ this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"));
+ this->packageFileNames.push_back(std::move(packageFileName));
+ }
+
+ return retval;
+}
+
+int cmCPackDebGenerator::PackageComponents(bool ignoreGroup)
+{
+ int retval = 1;
+ /* Reset package file name list it will be populated during the
+ * component packaging run*/
+ this->packageFileNames.clear();
+ std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+
+ // The default behavior is to have one package by component group
+ // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
+ if (!ignoreGroup) {
+ for (auto const& compG : this->ComponentGroups) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Packaging component group: " << compG.first << std::endl);
+ // Begin the archive for this group
+ retval &= this->PackageOnePack(initialTopLevel, compG.first);
+ }
+ // Handle Orphan components (components not belonging to any groups)
+ for (auto const& comp : this->Components) {
+ // Does the component belong to a group?
+ if (comp.second.Group == nullptr) {
+ cmCPackLogger(
+ cmCPackLog::LOG_VERBOSE,
+ "Component <"
+ << comp.second.Name
+ << "> does not belong to any group, package it separately."
+ << std::endl);
+ // Begin the archive for this orphan component
+ retval &= this->PackageOnePack(initialTopLevel, comp.first);
+ }
+ }
+ }
+ // CPACK_COMPONENTS_IGNORE_GROUPS is set
+ // We build 1 package per component
+ else {
+ for (auto const& comp : this->Components) {
+ retval &= this->PackageOnePack(initialTopLevel, comp.first);
+ }
+ }
+ return retval;
+}
+
+//----------------------------------------------------------------------
+int cmCPackDebGenerator::PackageComponentsAllInOne(
+ const std::string& compInstDirName)
+{
+ int retval = 1;
+ /* Reset package file name list it will be populated during the
+ * component packaging run*/
+ this->packageFileNames.clear();
+ std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Packaging all groups in one package..."
+ "(CPACK_COMPONENTS_ALL_[GROUPS_]IN_ONE_PACKAGE is set)"
+ << std::endl);
+
+ // The ALL GROUPS in ONE package case
+ std::string localToplevel(initialTopLevel);
+ std::string packageFileName(
+ cmSystemTools::GetParentDirectory(this->toplevel));
+ std::string outputFileName(
+ std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) +
+ this->GetOutputExtension());
+ // all GROUP in one vs all COMPONENT in one
+ // if must be here otherwise non component paths have a trailing / while
+ // components don't
+ if (!compInstDirName.empty()) {
+ localToplevel += "/" + compInstDirName;
+ }
+
+ /* replace the TEMP DIRECTORY with the component one */
+ this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str());
+ packageFileName += "/" + outputFileName;
+ /* replace proposed CPACK_OUTPUT_FILE_NAME */
+ this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName.c_str());
+ /* replace the TEMPORARY package file name */
+ this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
+ packageFileName.c_str());
+
+ if (!compInstDirName.empty()) {
+ // Tell CPackDeb.cmake the path where the component is.
+ std::string component_path = cmStrCat('/', compInstDirName);
+ this->SetOption("CPACK_DEB_PACKAGE_COMPONENT_PART_PATH",
+ component_path.c_str());
+ }
+ if (!this->ReadListFile("Internal/CPack/CPackDeb.cmake")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while execution CPackDeb.cmake" << std::endl);
+ retval = 0;
+ return retval;
+ }
+
+ cmsys::Glob gl;
+ std::string findExpr(this->GetOption("GEN_WDIR"));
+ findExpr += "/*";
+ gl.RecurseOn();
+ gl.SetRecurseListDirs(true);
+ gl.SetRecurseThroughSymlinks(false);
+ if (!gl.FindFiles(findExpr)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find any files in the installed directory"
+ << std::endl);
+ return 0;
+ }
+ this->packageFiles = gl.GetFiles();
+
+ int res = this->createDeb();
+ if (res != 1) {
+ retval = 0;
+ }
+ // add the generated package to package file names list
+ packageFileName = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
+ this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"));
+ this->packageFileNames.push_back(std::move(packageFileName));
+ return retval;
+}
+
+int cmCPackDebGenerator::PackageFiles()
+{
+ /* Are we in the component packaging case */
+ if (this->WantsComponentInstallation()) {
+ // CASE 1 : COMPONENT ALL-IN-ONE package
+ // If ALL GROUPS or ALL COMPONENTS in ONE package has been requested
+ // then the package file is unique and should be open here.
+ if (this->componentPackageMethod == ONE_PACKAGE) {
+ return this->PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE");
+ }
+ // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
+ // There will be 1 package for each component group
+ // however one may require to ignore component group and
+ // in this case you'll get 1 package for each component.
+ return this->PackageComponents(this->componentPackageMethod ==
+ ONE_PACKAGE_PER_COMPONENT);
+ }
+ // CASE 3 : NON COMPONENT package.
+ return this->PackageComponentsAllInOne("");
+}
+
+int cmCPackDebGenerator::createDeb()
+{
+ std::map<std::string, std::string> controlValues;
+
+ // debian policy enforce lower case for package name
+ controlValues["Package"] = cmsys::SystemTools::LowerCase(
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME"));
+ controlValues["Version"] =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_VERSION");
+ controlValues["Section"] =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SECTION");
+ controlValues["Priority"] =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PRIORITY");
+ controlValues["Architecture"] =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
+ controlValues["Maintainer"] =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER");
+ controlValues["Description"] =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DESCRIPTION");
+
+ const char* debian_pkg_source =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE");
+ if (cmNonempty(debian_pkg_source)) {
+ controlValues["Source"] = debian_pkg_source;
+ }
+ const char* debian_pkg_dep =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DEPENDS");
+ if (cmNonempty(debian_pkg_dep)) {
+ controlValues["Depends"] = debian_pkg_dep;
+ }
+ const char* debian_pkg_rec =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_RECOMMENDS");
+ if (cmNonempty(debian_pkg_rec)) {
+ controlValues["Recommends"] = debian_pkg_rec;
+ }
+ const char* debian_pkg_sug =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SUGGESTS");
+ if (cmNonempty(debian_pkg_sug)) {
+ controlValues["Suggests"] = debian_pkg_sug;
+ }
+ const char* debian_pkg_url =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_HOMEPAGE");
+ if (cmNonempty(debian_pkg_url)) {
+ controlValues["Homepage"] = debian_pkg_url;
+ }
+ const char* debian_pkg_predep =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PREDEPENDS");
+ if (cmNonempty(debian_pkg_predep)) {
+ controlValues["Pre-Depends"] = debian_pkg_predep;
+ }
+ const char* debian_pkg_enhances =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ENHANCES");
+ if (cmNonempty(debian_pkg_enhances)) {
+ controlValues["Enhances"] = debian_pkg_enhances;
+ }
+ const char* debian_pkg_breaks =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_BREAKS");
+ if (cmNonempty(debian_pkg_breaks)) {
+ controlValues["Breaks"] = debian_pkg_breaks;
+ }
+ const char* debian_pkg_conflicts =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONFLICTS");
+ if (cmNonempty(debian_pkg_conflicts)) {
+ controlValues["Conflicts"] = debian_pkg_conflicts;
+ }
+ const char* debian_pkg_provides =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PROVIDES");
+ if (cmNonempty(debian_pkg_provides)) {
+ controlValues["Provides"] = debian_pkg_provides;
+ }
+ const char* debian_pkg_replaces =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_REPLACES");
+ if (cmNonempty(debian_pkg_replaces)) {
+ controlValues["Replaces"] = debian_pkg_replaces;
+ }
+
+ const std::string strGenWDIR(this->GetOption("GEN_WDIR"));
+ const std::string shlibsfilename = strGenWDIR + "/shlibs";
+
+ const char* debian_pkg_shlibs =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SHLIBS");
+ const bool gen_shibs = this->IsOn("CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS") &&
+ cmNonempty(debian_pkg_shlibs);
+ if (gen_shibs) {
+ cmGeneratedFileStream out;
+ out.Open(shlibsfilename, false, true);
+ out << debian_pkg_shlibs;
+ out << '\n';
+ }
+
+ const std::string postinst = strGenWDIR + "/postinst";
+ const std::string postrm = strGenWDIR + "/postrm";
+ if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST")) {
+ cmGeneratedFileStream out;
+ out.Open(postinst, false, true);
+ out << "#!/bin/sh\n\n"
+ "set -e\n\n"
+ "if [ \"$1\" = \"configure\" ]; then\n"
+ "\tldconfig\n"
+ "fi\n";
+ }
+ if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM")) {
+ cmGeneratedFileStream out;
+ out.Open(postrm, false, true);
+ out << "#!/bin/sh\n\n"
+ "set -e\n\n"
+ "if [ \"$1\" = \"remove\" ]; then\n"
+ "\tldconfig\n"
+ "fi\n";
+ }
+
+ DebGenerator gen(
+ this->Logger, this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"), strGenWDIR,
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY"),
+ this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"),
+ this->GetOption("CPACK_THREADS"),
+ this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE"), controlValues, gen_shibs,
+ shlibsfilename, this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST"), postinst,
+ this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM"), postrm,
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA"),
+ this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"),
+ this->packageFiles);
+
+ if (!gen.generate()) {
+ return 0;
+ }
+ return 1;
+}
+
+int cmCPackDebGenerator::createDbgsymDDeb()
+{
+ // Packages containing debug symbols follow the same structure as .debs
+ // but have different metadata and content.
+
+ std::map<std::string, std::string> controlValues;
+ // debian policy enforce lower case for package name
+ std::string packageNameLower = cmsys::SystemTools::LowerCase(
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME"));
+ const char* debian_pkg_version =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_VERSION");
+
+ controlValues["Package"] = packageNameLower + "-dbgsym";
+ controlValues["Package-Type"] = "ddeb";
+ controlValues["Version"] = debian_pkg_version;
+ controlValues["Auto-Built-Package"] = "debug-symbols";
+ controlValues["Depends"] = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME") +
+ std::string(" (= ") + debian_pkg_version + ")";
+ controlValues["Section"] = "debug";
+ controlValues["Priority"] = "optional";
+ controlValues["Architecture"] =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
+ controlValues["Maintainer"] =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER");
+ controlValues["Description"] =
+ std::string("debug symbols for ") + packageNameLower;
+
+ const char* debian_pkg_source =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE");
+ if (cmNonempty(debian_pkg_source)) {
+ controlValues["Source"] = debian_pkg_source;
+ }
+ const char* debian_build_ids = this->GetOption("GEN_BUILD_IDS");
+ if (cmNonempty(debian_build_ids)) {
+ controlValues["Build-Ids"] = debian_build_ids;
+ }
+
+ DebGenerator gen(
+ this->Logger, this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"),
+ this->GetOption("GEN_DBGSYMDIR"),
+
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY"),
+ this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"),
+ this->GetOption("CPACK_THREADS"),
+ this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE"), controlValues, false, "",
+ false, "", false, "", nullptr,
+ this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"),
+ this->packageFiles);
+
+ if (!gen.generate()) {
+ return 0;
+ }
+ return 1;
+}
+
+bool cmCPackDebGenerator::SupportsComponentInstallation() const
+{
+ return this->IsOn("CPACK_DEB_COMPONENT_INSTALL");
+}
+
+std::string cmCPackDebGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ if (this->componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) {
+ return componentName;
+ }
+
+ if (this->componentPackageMethod == ONE_PACKAGE) {
+ return std::string("ALL_COMPONENTS_IN_ONE");
+ }
+ // We have to find the name of the COMPONENT GROUP
+ // the current COMPONENT belongs to.
+ std::string groupVar =
+ "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP";
+ if (nullptr != this->GetOption(groupVar)) {
+ return std::string(this->GetOption(groupVar));
+ }
+ return componentName;
+}
diff --git a/Source/CPack/cmCPackDebGenerator.h b/Source/CPack/cmCPackDebGenerator.h
new file mode 100644
index 0000000..ee8f39a
--- /dev/null
+++ b/Source/CPack/cmCPackDebGenerator.h
@@ -0,0 +1,70 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmCPackGenerator.h"
+
+/** \class cmCPackDebGenerator
+ * \brief A generator for Debian packages
+ *
+ */
+class cmCPackDebGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackDebGenerator, cmCPackGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackDebGenerator();
+ ~cmCPackDebGenerator() override;
+
+ static bool CanGenerate()
+ {
+#ifdef __APPLE__
+ // on MacOS enable CPackDeb iff dpkg is found
+ std::vector<std::string> locations;
+ locations.push_back("/sw/bin"); // Fink
+ locations.push_back("/opt/local/bin"); // MacPorts
+ return cmSystemTools::FindProgram("dpkg", locations) != "" ? true : false;
+#else
+ // legacy behavior on other systems
+ return true;
+#endif
+ }
+
+protected:
+ int InitializeInternal() override;
+ /**
+ * This method factors out the work done in component packaging case.
+ */
+ int PackageOnePack(std::string const& initialToplevel,
+ std::string const& packageName);
+ /**
+ * The method used to package files when component
+ * install is used. This will create one
+ * archive for each component group.
+ */
+ int PackageComponents(bool ignoreGroup);
+ /**
+ * Special case of component install where all
+ * components will be put in a single installer.
+ */
+ int PackageComponentsAllInOne(const std::string& compInstDirName);
+ int PackageFiles() override;
+ const char* GetOutputExtension() override { return ".deb"; }
+ bool SupportsComponentInstallation() const override;
+ std::string GetComponentInstallDirNameSuffix(
+ const std::string& componentName) override;
+
+private:
+ int createDeb();
+ int createDbgsymDDeb();
+
+ std::vector<std::string> packageFiles;
+};
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
new file mode 100644
index 0000000..0d56e5f
--- /dev/null
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -0,0 +1,928 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackDragNDropGenerator.h"
+
+#include <algorithm>
+#include <cstdlib>
+#include <iomanip>
+#include <map>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <cm3p/kwiml/abi.h>
+
+#include "cmsys/Base64.h"
+#include "cmsys/FStream.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCPackGenerator.h"
+#include "cmCPackLog.h"
+#include "cmDuration.h"
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+
+#ifdef HAVE_CoreServices
+// For the old LocaleStringToLangAndRegionCodes() function, to convert
+// to the old Script Manager RegionCode values needed for the 'LPic' data
+// structure used for generating multi-lingual SLAs.
+# include <CoreServices/CoreServices.h>
+#endif
+
+static const uint16_t DefaultLpic[] = {
+ /* clang-format off */
+ 0x0002, 0x0011, 0x0003, 0x0001, 0x0000, 0x0000, 0x0002, 0x0000,
+ 0x0008, 0x0003, 0x0000, 0x0001, 0x0004, 0x0000, 0x0004, 0x0005,
+ 0x0000, 0x000E, 0x0006, 0x0001, 0x0005, 0x0007, 0x0000, 0x0007,
+ 0x0008, 0x0000, 0x0047, 0x0009, 0x0000, 0x0034, 0x000A, 0x0001,
+ 0x0035, 0x000B, 0x0001, 0x0020, 0x000C, 0x0000, 0x0011, 0x000D,
+ 0x0000, 0x005B, 0x0004, 0x0000, 0x0033, 0x000F, 0x0001, 0x000C,
+ 0x0010, 0x0000, 0x000B, 0x000E, 0x0000
+ /* clang-format on */
+};
+
+static const std::vector<std::string> DefaultMenu = {
+ { "English", "Agree", "Disagree", "Print", "Save...",
+ // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
+ "You agree to the License Agreement terms when "
+ "you click the \"Agree\" button.",
+ "Software License Agreement",
+ "This text cannot be saved. "
+ "This disk may be full or locked, or the file may be locked.",
+ "Unable to print. Make sure you have selected a printer." }
+};
+
+cmCPackDragNDropGenerator::cmCPackDragNDropGenerator()
+ : singleLicense(false)
+{
+ // default to one package file for components
+ this->componentPackageMethod = ONE_PACKAGE;
+}
+
+cmCPackDragNDropGenerator::~cmCPackDragNDropGenerator() = default;
+
+int cmCPackDragNDropGenerator::InitializeInternal()
+{
+ // Starting with Xcode 4.3, look in "/Applications/Xcode.app" first:
+ //
+ std::vector<std::string> paths;
+ paths.emplace_back("/Applications/Xcode.app/Contents/Developer/Tools");
+ paths.emplace_back("/Developer/Tools");
+
+ const std::string hdiutil_path =
+ cmSystemTools::FindProgram("hdiutil", std::vector<std::string>(), false);
+ if (hdiutil_path.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot locate hdiutil command" << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_HDIUTIL", hdiutil_path.c_str());
+
+ const std::string setfile_path =
+ cmSystemTools::FindProgram("SetFile", paths, false);
+ if (setfile_path.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot locate SetFile command" << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_SETFILE", setfile_path.c_str());
+
+ const std::string rez_path = cmSystemTools::FindProgram("Rez", paths, false);
+ if (rez_path.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot locate Rez command" << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_REZ", rez_path.c_str());
+
+ if (this->IsSet("CPACK_DMG_SLA_DIR")) {
+ slaDirectory = this->GetOption("CPACK_DMG_SLA_DIR");
+ if (!slaDirectory.empty() && this->IsSet("CPACK_RESOURCE_FILE_LICENSE")) {
+ std::string license_file =
+ this->GetOption("CPACK_RESOURCE_FILE_LICENSE");
+ if (!license_file.empty() &&
+ (license_file.find("CPack.GenericLicense.txt") ==
+ std::string::npos)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_OUTPUT,
+ "Both CPACK_DMG_SLA_DIR and CPACK_RESOURCE_FILE_LICENSE specified, "
+ "using CPACK_RESOURCE_FILE_LICENSE as a license for all languages."
+ << std::endl);
+ singleLicense = true;
+ }
+ }
+ if (!this->IsSet("CPACK_DMG_SLA_LANGUAGES")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_DMG_SLA_DIR set but no languages defined "
+ "(set CPACK_DMG_SLA_LANGUAGES)"
+ << std::endl);
+ return 0;
+ }
+ if (!cmSystemTools::FileExists(slaDirectory, false)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_DMG_SLA_DIR does not exist" << std::endl);
+ return 0;
+ }
+
+ std::vector<std::string> languages =
+ cmExpandedList(this->GetOption("CPACK_DMG_SLA_LANGUAGES"));
+ if (languages.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_DMG_SLA_LANGUAGES set but empty" << std::endl);
+ return 0;
+ }
+ for (auto const& language : languages) {
+ std::string license = slaDirectory + "/" + language + ".license.txt";
+ std::string license_rtf = slaDirectory + "/" + language + ".license.rtf";
+ if (!singleLicense) {
+ if (!cmSystemTools::FileExists(license) &&
+ !cmSystemTools::FileExists(license_rtf)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Missing license file "
+ << language << ".license.txt"
+ << " / " << language << ".license.rtf" << std::endl);
+ return 0;
+ }
+ }
+ std::string menu = slaDirectory + "/" + language + ".menu.txt";
+ if (!cmSystemTools::FileExists(menu)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Missing menu file " << language << ".menu.txt"
+ << std::endl);
+ return 0;
+ }
+ }
+ }
+
+ return this->Superclass::InitializeInternal();
+}
+
+const char* cmCPackDragNDropGenerator::GetOutputExtension()
+{
+ return ".dmg";
+}
+
+int cmCPackDragNDropGenerator::PackageFiles()
+{
+ // gather which directories to make dmg files for
+ // multiple directories occur if packaging components or groups separately
+
+ // monolith
+ if (this->Components.empty()) {
+ return this->CreateDMG(toplevel, packageFileNames[0]);
+ }
+
+ // component install
+ std::vector<std::string> package_files;
+
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ std::string name = GetComponentInstallDirNameSuffix(compIt->first);
+ package_files.push_back(name);
+ }
+ std::sort(package_files.begin(), package_files.end());
+ package_files.erase(std::unique(package_files.begin(), package_files.end()),
+ package_files.end());
+
+ // loop to create dmg files
+ packageFileNames.clear();
+ for (auto const& package_file : package_files) {
+ std::string full_package_name = std::string(toplevel) + std::string("/");
+ if (package_file == "ALL_IN_ONE") {
+ full_package_name += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ } else {
+ full_package_name += package_file;
+ }
+ full_package_name += std::string(GetOutputExtension());
+ packageFileNames.push_back(full_package_name);
+
+ std::string src_dir = cmStrCat(toplevel, '/', package_file);
+
+ if (0 == this->CreateDMG(src_dir, full_package_name)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+bool cmCPackDragNDropGenerator::CopyFile(std::ostringstream& source,
+ std::ostringstream& target)
+{
+ if (!cmSystemTools::CopyFileIfDifferent(source.str(), target.str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error copying " << source.str() << " to " << target.str()
+ << std::endl);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool cmCPackDragNDropGenerator::CreateEmptyFile(std::ostringstream& target,
+ size_t size)
+{
+ cmsys::ofstream fout(target.str().c_str(), std::ios::out | std::ios::binary);
+ if (!fout) {
+ return false;
+ }
+
+ // Seek to desired size - 1 byte
+ fout.seekp(size - 1, std::ios::beg);
+ char byte = 0;
+ // Write one byte to ensure file grows
+ fout.write(&byte, 1);
+
+ return true;
+}
+
+bool cmCPackDragNDropGenerator::RunCommand(std::ostringstream& command,
+ std::string* output)
+{
+ int exit_code = 1;
+
+ bool result = cmSystemTools::RunSingleCommand(
+ command.str(), output, output, &exit_code, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
+
+ if (!result || exit_code) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error executing: " << command.str() << std::endl);
+
+ return false;
+ }
+
+ return true;
+}
+
+int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
+ const std::string& output_file)
+{
+ // Get optional arguments ...
+ const std::string cpack_package_icon = this->GetOption("CPACK_PACKAGE_ICON")
+ ? this->GetOption("CPACK_PACKAGE_ICON")
+ : "";
+
+ const std::string cpack_dmg_volume_name =
+ this->GetOption("CPACK_DMG_VOLUME_NAME")
+ ? this->GetOption("CPACK_DMG_VOLUME_NAME")
+ : this->GetOption("CPACK_PACKAGE_FILE_NAME");
+
+ const std::string cpack_dmg_format = this->GetOption("CPACK_DMG_FORMAT")
+ ? this->GetOption("CPACK_DMG_FORMAT")
+ : "UDZO";
+
+ const std::string cpack_dmg_filesystem =
+ this->GetOption("CPACK_DMG_FILESYSTEM")
+ ? this->GetOption("CPACK_DMG_FILESYSTEM")
+ : "HFS+";
+
+ // Get optional arguments ...
+ std::string cpack_license_file =
+ this->GetOption("CPACK_RESOURCE_FILE_LICENSE")
+ ? this->GetOption("CPACK_RESOURCE_FILE_LICENSE")
+ : "";
+
+ const std::string cpack_dmg_background_image =
+ this->GetOption("CPACK_DMG_BACKGROUND_IMAGE")
+ ? this->GetOption("CPACK_DMG_BACKGROUND_IMAGE")
+ : "";
+
+ const std::string cpack_dmg_ds_store = this->GetOption("CPACK_DMG_DS_STORE")
+ ? this->GetOption("CPACK_DMG_DS_STORE")
+ : "";
+
+ const std::string cpack_dmg_languages =
+ this->GetOption("CPACK_DMG_SLA_LANGUAGES")
+ ? this->GetOption("CPACK_DMG_SLA_LANGUAGES")
+ : "";
+
+ const std::string cpack_dmg_ds_store_setup_script =
+ this->GetOption("CPACK_DMG_DS_STORE_SETUP_SCRIPT")
+ ? this->GetOption("CPACK_DMG_DS_STORE_SETUP_SCRIPT")
+ : "";
+
+ const bool cpack_dmg_disable_applications_symlink =
+ this->IsOn("CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK");
+
+ // only put license on dmg if is user provided
+ if (!cpack_license_file.empty() &&
+ cpack_license_file.find("CPack.GenericLicense.txt") !=
+ std::string::npos) {
+ cpack_license_file = "";
+ }
+
+ // use sla_dir if both sla_dir and license_file are set
+ if (!cpack_license_file.empty() && !slaDirectory.empty() && !singleLicense) {
+ cpack_license_file = "";
+ }
+
+ // The staging directory contains everything that will end-up inside the
+ // final disk image ...
+ std::ostringstream staging;
+ staging << src_dir;
+
+ // Add a symlink to /Applications so users can drag-and-drop the bundle
+ // into it unless this behaviour was disabled
+ if (!cpack_dmg_disable_applications_symlink) {
+ std::ostringstream application_link;
+ application_link << staging.str() << "/Applications";
+ cmSystemTools::CreateSymlink("/Applications", application_link.str());
+ }
+
+ // Optionally add a custom volume icon ...
+ if (!cpack_package_icon.empty()) {
+ std::ostringstream package_icon_source;
+ package_icon_source << cpack_package_icon;
+
+ std::ostringstream package_icon_destination;
+ package_icon_destination << staging.str() << "/.VolumeIcon.icns";
+
+ if (!this->CopyFile(package_icon_source, package_icon_destination)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error copying disk volume icon. "
+ "Check the value of CPACK_PACKAGE_ICON."
+ << std::endl);
+
+ return 0;
+ }
+ }
+
+ // Optionally add a custom .DS_Store file
+ // (e.g. for setting background/layout) ...
+ if (!cpack_dmg_ds_store.empty()) {
+ std::ostringstream package_settings_source;
+ package_settings_source << cpack_dmg_ds_store;
+
+ std::ostringstream package_settings_destination;
+ package_settings_destination << staging.str() << "/.DS_Store";
+
+ if (!this->CopyFile(package_settings_source,
+ package_settings_destination)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error copying disk volume settings file. "
+ "Check the value of CPACK_DMG_DS_STORE."
+ << std::endl);
+
+ return 0;
+ }
+ }
+
+ // Optionally add a custom background image ...
+ // Make sure the background file type is the same as the custom image
+ // and that the file is hidden so it doesn't show up.
+ if (!cpack_dmg_background_image.empty()) {
+ const std::string extension =
+ cmSystemTools::GetFilenameLastExtension(cpack_dmg_background_image);
+ std::ostringstream package_background_source;
+ package_background_source << cpack_dmg_background_image;
+
+ std::ostringstream package_background_destination;
+ package_background_destination << staging.str()
+ << "/.background/background" << extension;
+
+ if (!this->CopyFile(package_background_source,
+ package_background_destination)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error copying disk volume background image. "
+ "Check the value of CPACK_DMG_BACKGROUND_IMAGE."
+ << std::endl);
+
+ return 0;
+ }
+ }
+
+ bool remount_image =
+ !cpack_package_icon.empty() || !cpack_dmg_ds_store_setup_script.empty();
+
+ std::string temp_image_format = "UDZO";
+
+ // Create 1 MB dummy padding file in staging area when we need to remount
+ // image, so we have enough space for storing changes ...
+ if (remount_image) {
+ std::ostringstream dummy_padding;
+ dummy_padding << staging.str() << "/.dummy-padding-file";
+ if (!this->CreateEmptyFile(dummy_padding, 1048576)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error creating dummy padding file." << std::endl);
+
+ return 0;
+ }
+ temp_image_format = "UDRW";
+ }
+
+ // Create a temporary read-write disk image ...
+ std::string temp_image =
+ cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/temp.dmg");
+
+ std::string create_error;
+ std::ostringstream temp_image_command;
+ temp_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ temp_image_command << " create";
+ temp_image_command << " -ov";
+ temp_image_command << " -srcfolder \"" << staging.str() << "\"";
+ temp_image_command << " -volname \"" << cpack_dmg_volume_name << "\"";
+ temp_image_command << " -fs \"" << cpack_dmg_filesystem << "\"";
+ temp_image_command << " -format " << temp_image_format;
+ temp_image_command << " \"" << temp_image << "\"";
+
+ if (!this->RunCommand(temp_image_command, &create_error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error generating temporary disk image." << std::endl
+ << create_error
+ << std::endl);
+
+ return 0;
+ }
+
+ if (remount_image) {
+ // Store that we have a failure so that we always unmount the image
+ // before we exit.
+ bool had_error = false;
+
+ std::ostringstream attach_command;
+ attach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ attach_command << " attach";
+ attach_command << " \"" << temp_image << "\"";
+
+ std::string attach_output;
+ if (!this->RunCommand(attach_command, &attach_output)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error attaching temporary disk image." << std::endl);
+
+ return 0;
+ }
+
+ cmsys::RegularExpression mountpoint_regex(".*(/Volumes/[^\n]+)\n.*");
+ mountpoint_regex.find(attach_output.c_str());
+ std::string const temp_mount = mountpoint_regex.match(1);
+ std::string const temp_mount_name =
+ temp_mount.substr(sizeof("/Volumes/") - 1);
+
+ // Remove dummy padding file so we have enough space on RW image ...
+ std::ostringstream dummy_padding;
+ dummy_padding << temp_mount << "/.dummy-padding-file";
+ if (!cmSystemTools::RemoveFile(dummy_padding.str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error removing dummy padding file." << std::endl);
+
+ had_error = true;
+ }
+
+ // Optionally set the custom icon flag for the image ...
+ if (!had_error && !cpack_package_icon.empty()) {
+ std::string error;
+ std::ostringstream setfile_command;
+ setfile_command << this->GetOption("CPACK_COMMAND_SETFILE");
+ setfile_command << " -a C";
+ setfile_command << " \"" << temp_mount << "\"";
+
+ if (!this->RunCommand(setfile_command, &error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error assigning custom icon to temporary disk image."
+ << std::endl
+ << error << std::endl);
+
+ had_error = true;
+ }
+ }
+
+ // Optionally we can execute a custom apple script to generate
+ // the .DS_Store for the volume folder ...
+ if (!had_error && !cpack_dmg_ds_store_setup_script.empty()) {
+ std::ostringstream setup_script_command;
+ setup_script_command << "osascript"
+ << " \"" << cpack_dmg_ds_store_setup_script << "\""
+ << " \"" << temp_mount_name << "\"";
+ std::string error;
+ if (!this->RunCommand(setup_script_command, &error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error executing custom script on disk image."
+ << std::endl
+ << error << std::endl);
+
+ had_error = true;
+ }
+ }
+
+ std::ostringstream detach_command;
+ detach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ detach_command << " detach";
+ detach_command << " \"" << temp_mount << "\"";
+
+ if (!this->RunCommand(detach_command)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error detaching temporary disk image." << std::endl);
+
+ return 0;
+ }
+
+ if (had_error) {
+ return 0;
+ }
+ }
+
+ // Create the final compressed read-only disk image ...
+ std::ostringstream final_image_command;
+ final_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ final_image_command << " convert \"" << temp_image << "\"";
+ final_image_command << " -format ";
+ final_image_command << cpack_dmg_format;
+ final_image_command << " -imagekey";
+ final_image_command << " zlib-level=9";
+ final_image_command << " -o \"" << output_file << "\"";
+
+ std::string convert_error;
+
+ if (!this->RunCommand(final_image_command, &convert_error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error compressing disk image." << std::endl
+ << convert_error
+ << std::endl);
+
+ return 0;
+ }
+
+ if (!cpack_license_file.empty() || !slaDirectory.empty()) {
+ // Use old hardcoded style if sla_dir is not set
+ bool oldStyle = slaDirectory.empty();
+ std::string sla_xml =
+ cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/sla.xml");
+
+ std::vector<std::string> languages;
+ if (!oldStyle) {
+ cmExpandList(cpack_dmg_languages, languages);
+ }
+
+ std::vector<uint16_t> header_data;
+ if (oldStyle) {
+ header_data = std::vector<uint16_t>(
+ DefaultLpic,
+ DefaultLpic + (sizeof(DefaultLpic) / sizeof(*DefaultLpic)));
+ } else {
+ /*
+ * LPic Layout
+ * (https://github.com/pypt/dmg-add-license/blob/master/main.c)
+ * as far as I can tell (no official documentation seems to exist):
+ * struct LPic {
+ * uint16_t default_language; // points to a resid, defaulting to 0,
+ * // which is the first set language
+ * uint16_t length;
+ * struct {
+ * uint16_t language_code;
+ * uint16_t resid;
+ * uint16_t encoding; // Encoding from TextCommon.h,
+ * // forcing MacRoman (0) for now. Might need to
+ * // allow overwrite per license by user later
+ * } item[1];
+ * }
+ */
+
+ header_data.push_back(0);
+ header_data.push_back(languages.size());
+ for (size_t i = 0; i < languages.size(); ++i) {
+ CFStringRef language_cfstring = CFStringCreateWithCString(
+ nullptr, languages[i].c_str(), kCFStringEncodingUTF8);
+ CFStringRef iso_language =
+ CFLocaleCreateCanonicalLanguageIdentifierFromString(
+ nullptr, language_cfstring);
+ if (!iso_language) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ languages[i] << " is not a recognized language"
+ << std::endl);
+ }
+ char iso_language_cstr[65];
+ CFStringGetCString(iso_language, iso_language_cstr,
+ sizeof(iso_language_cstr) - 1,
+ kCFStringEncodingMacRoman);
+ LangCode lang = 0;
+ RegionCode region = 0;
+#ifdef HAVE_CoreServices
+ OSStatus err =
+ LocaleStringToLangAndRegionCodes(iso_language_cstr, &lang, &region);
+ if (err != noErr)
+#endif
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "No language/region code available for "
+ << iso_language_cstr << std::endl);
+ return 0;
+ }
+#ifdef HAVE_CoreServices
+ header_data.push_back(region);
+ header_data.push_back(i);
+ header_data.push_back(0);
+#endif
+ }
+ }
+
+ RezDoc rez;
+
+ {
+ RezDict lpic = { {}, 5000, {} };
+ lpic.Data.reserve(header_data.size() * sizeof(header_data[0]));
+ for (uint16_t x : header_data) {
+ // LPic header is big-endian.
+ char* d = reinterpret_cast<char*>(&x);
+#if KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_LITTLE
+ lpic.Data.push_back(d[1]);
+ lpic.Data.push_back(d[0]);
+#else
+ lpic.Data.push_back(d[0]);
+ lpic.Data.push_back(d[1]);
+#endif
+ }
+ rez.LPic.Entries.emplace_back(std::move(lpic));
+ }
+
+ bool have_write_license_error = false;
+ std::string error;
+
+ if (oldStyle) {
+ if (!this->WriteLicense(rez, 0, "", cpack_license_file, &error)) {
+ have_write_license_error = true;
+ }
+ } else {
+ for (size_t i = 0; i < languages.size() && !have_write_license_error;
+ ++i) {
+ if (singleLicense) {
+ if (!this->WriteLicense(rez, i + 5000, languages[i],
+ cpack_license_file, &error)) {
+ have_write_license_error = true;
+ }
+ } else {
+ if (!this->WriteLicense(rez, i + 5000, languages[i], "", &error)) {
+ have_write_license_error = true;
+ }
+ }
+ }
+ }
+
+ if (have_write_license_error) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error writing license file to SLA." << std::endl
+ << error
+ << std::endl);
+ return 0;
+ }
+
+ this->WriteRezXML(sla_xml, rez);
+
+ // Create the final compressed read-only disk image ...
+ std::ostringstream embed_sla_command;
+ embed_sla_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ embed_sla_command << " udifrez";
+ embed_sla_command << " -xml";
+ embed_sla_command << " \"" << sla_xml << "\"";
+ embed_sla_command << " FIXME_WHY_IS_THIS_ARGUMENT_NEEDED";
+ embed_sla_command << " \"" << output_file << "\"";
+ std::string embed_error;
+ if (!this->RunCommand(embed_sla_command, &embed_error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error compressing disk image." << std::endl
+ << embed_error
+ << std::endl);
+
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+bool cmCPackDragNDropGenerator::SupportsComponentInstallation() const
+{
+ return true;
+}
+
+std::string cmCPackDragNDropGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ // we want to group components together that go in the same dmg package
+ std::string package_file_name = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+
+ // we have 3 mutually exclusive modes to work in
+ // 1. all components in one package
+ // 2. each group goes in its own package with left over
+ // components in their own package
+ // 3. ignore groups - if grouping is defined, it is ignored
+ // and each component goes in its own package
+
+ if (this->componentPackageMethod == ONE_PACKAGE) {
+ return "ALL_IN_ONE";
+ }
+
+ if (this->componentPackageMethod == ONE_PACKAGE_PER_GROUP) {
+ // We have to find the name of the COMPONENT GROUP
+ // the current COMPONENT belongs to.
+ std::string groupVar =
+ "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP";
+ const char* _groupName = GetOption(groupVar);
+ if (_groupName) {
+ std::string groupName = _groupName;
+
+ groupName =
+ GetComponentPackageFileName(package_file_name, groupName, true);
+ return groupName;
+ }
+ }
+
+ std::string componentFileName =
+ "CPACK_DMG_" + cmSystemTools::UpperCase(componentName) + "_FILE_NAME";
+ if (this->IsSet(componentFileName)) {
+ return this->GetOption(componentFileName);
+ }
+ return GetComponentPackageFileName(package_file_name, componentName, false);
+}
+
+void cmCPackDragNDropGenerator::WriteRezXML(std::string const& file,
+ RezDoc const& rez)
+{
+ cmGeneratedFileStream fxml(file);
+ cmXMLWriter xml(fxml);
+ xml.StartDocument();
+ xml.StartElement("plist");
+ xml.Attribute("version", "1.0");
+ xml.StartElement("dict");
+ this->WriteRezArray(xml, rez.LPic);
+ this->WriteRezArray(xml, rez.Menu);
+ this->WriteRezArray(xml, rez.Text);
+ this->WriteRezArray(xml, rez.RTF);
+ xml.EndElement(); // dict
+ xml.EndElement(); // plist
+ xml.EndDocument();
+ fxml.Close();
+}
+
+void cmCPackDragNDropGenerator::WriteRezArray(cmXMLWriter& xml,
+ RezArray const& array)
+{
+ if (array.Entries.empty()) {
+ return;
+ }
+ xml.StartElement("key");
+ xml.Content(array.Key);
+ xml.EndElement(); // key
+ xml.StartElement("array");
+ for (RezDict const& dict : array.Entries) {
+ this->WriteRezDict(xml, dict);
+ }
+ xml.EndElement(); // array
+}
+
+void cmCPackDragNDropGenerator::WriteRezDict(cmXMLWriter& xml,
+ RezDict const& dict)
+{
+ std::vector<char> base64buf(dict.Data.size() * 3 / 2 + 5);
+ size_t base64len =
+ cmsysBase64_Encode(dict.Data.data(), dict.Data.size(),
+ reinterpret_cast<unsigned char*>(base64buf.data()), 0);
+ std::string base64data(base64buf.data(), base64len);
+ /* clang-format off */
+ xml.StartElement("dict");
+ xml.StartElement("key"); xml.Content("Attributes"); xml.EndElement();
+ xml.StartElement("string"); xml.Content("0x0000"); xml.EndElement();
+ xml.StartElement("key"); xml.Content("Data"); xml.EndElement();
+ xml.StartElement("data"); xml.Content(base64data); xml.EndElement();
+ xml.StartElement("key"); xml.Content("ID"); xml.EndElement();
+ xml.StartElement("string"); xml.Content(dict.ID); xml.EndElement();
+ xml.StartElement("key"); xml.Content("Name"); xml.EndElement();
+ xml.StartElement("string"); xml.Content(dict.Name); xml.EndElement();
+ xml.EndElement(); // dict
+ /* clang-format on */
+}
+
+bool cmCPackDragNDropGenerator::WriteLicense(RezDoc& rez, size_t licenseNumber,
+ std::string licenseLanguage,
+ const std::string& licenseFile,
+ std::string* error)
+{
+ if (!licenseFile.empty() && !singleLicense) {
+ licenseNumber = 5002;
+ licenseLanguage = "English";
+ }
+
+ // License file
+ RezArray* licenseArray = &rez.Text;
+ std::string actual_license;
+ if (!licenseFile.empty()) {
+ if (cmHasLiteralSuffix(licenseFile, ".rtf")) {
+ licenseArray = &rez.RTF;
+ }
+ actual_license = licenseFile;
+ } else {
+ std::string license_wo_ext =
+ slaDirectory + "/" + licenseLanguage + ".license";
+ if (cmSystemTools::FileExists(license_wo_ext + ".txt")) {
+ actual_license = license_wo_ext + ".txt";
+ } else {
+ licenseArray = &rez.RTF;
+ actual_license = license_wo_ext + ".rtf";
+ }
+ }
+
+ // License body
+ {
+ RezDict license = { licenseLanguage, licenseNumber, {} };
+ std::vector<std::string> lines;
+ if (!this->ReadFile(actual_license, lines, error)) {
+ return false;
+ }
+ this->EncodeLicense(license, lines);
+ licenseArray->Entries.emplace_back(std::move(license));
+ }
+
+ // Menu body
+ {
+ RezDict menu = { licenseLanguage, licenseNumber, {} };
+ if (!licenseFile.empty() && !singleLicense) {
+ this->EncodeMenu(menu, DefaultMenu);
+ } else {
+ std::vector<std::string> lines;
+ std::string actual_menu =
+ slaDirectory + "/" + licenseLanguage + ".menu.txt";
+ if (!this->ReadFile(actual_menu, lines, error)) {
+ return false;
+ }
+ this->EncodeMenu(menu, lines);
+ }
+ rez.Menu.Entries.emplace_back(std::move(menu));
+ }
+
+ return true;
+}
+
+void cmCPackDragNDropGenerator::EncodeLicense(
+ RezDict& dict, std::vector<std::string> const& lines)
+{
+ // License text uses CR newlines.
+ for (std::string const& l : lines) {
+ dict.Data.insert(dict.Data.end(), l.begin(), l.end());
+ dict.Data.push_back('\r');
+ }
+ dict.Data.push_back('\r');
+}
+
+void cmCPackDragNDropGenerator::EncodeMenu(
+ RezDict& dict, std::vector<std::string> const& lines)
+{
+ // Menu resources start with a big-endian uint16_t for number of lines:
+ {
+ uint16_t numLines = static_cast<uint16_t>(lines.size());
+ char* d = reinterpret_cast<char*>(&numLines);
+#if KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_LITTLE
+ dict.Data.push_back(d[1]);
+ dict.Data.push_back(d[0]);
+#else
+ dict.Data.push_back(d[0]);
+ dict.Data.push_back(d[1]);
+#endif
+ }
+ // Each line starts with a uint8_t length, plus the bytes themselves:
+ for (std::string const& l : lines) {
+ dict.Data.push_back(static_cast<unsigned char>(l.length()));
+ dict.Data.insert(dict.Data.end(), l.begin(), l.end());
+ }
+}
+
+bool cmCPackDragNDropGenerator::ReadFile(std::string const& file,
+ std::vector<std::string>& lines,
+ std::string* error)
+{
+ cmsys::ifstream ifs(file);
+ std::string line;
+ while (std::getline(ifs, line)) {
+ if (!this->BreakLongLine(line, lines, error)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmCPackDragNDropGenerator::BreakLongLine(const std::string& line,
+ std::vector<std::string>& lines,
+ std::string* error)
+{
+ const size_t max_line_length = 255;
+ size_t line_length = max_line_length;
+ for (size_t i = 0; i < line.size(); i += line_length) {
+ line_length = max_line_length;
+ if (i + line_length > line.size()) {
+ line_length = line.size() - i;
+ } else {
+ while (line_length > 0 && line[i + line_length - 1] != ' ') {
+ line_length = line_length - 1;
+ }
+ }
+
+ if (line_length == 0) {
+ *error = "Please make sure there are no words "
+ "(or character sequences not broken up by spaces or newlines) "
+ "in your license file which are more than 255 characters long.";
+ return false;
+ }
+ lines.push_back(line.substr(i, line_length));
+ }
+ return true;
+}
diff --git a/Source/CPack/cmCPackDragNDropGenerator.h b/Source/CPack/cmCPackDragNDropGenerator.h
new file mode 100644
index 0000000..310b0ab
--- /dev/null
+++ b/Source/CPack/cmCPackDragNDropGenerator.h
@@ -0,0 +1,82 @@
+/* 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 <sstream>
+#include <string>
+#include <vector>
+
+#include <stddef.h>
+
+#include "cmCPackGenerator.h"
+
+class cmGeneratedFileStream;
+class cmXMLWriter;
+
+/** \class cmCPackDragNDropGenerator
+ * \brief A generator for OSX drag-n-drop installs
+ */
+class cmCPackDragNDropGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackDragNDropGenerator, cmCPackGenerator);
+
+ cmCPackDragNDropGenerator();
+ ~cmCPackDragNDropGenerator() override;
+
+protected:
+ int InitializeInternal() override;
+ const char* GetOutputExtension() override;
+ int PackageFiles() override;
+ bool SupportsComponentInstallation() const override;
+
+ bool CopyFile(std::ostringstream& source, std::ostringstream& target);
+ bool CreateEmptyFile(std::ostringstream& target, size_t size);
+ bool RunCommand(std::ostringstream& command, std::string* output = 0);
+
+ std::string GetComponentInstallDirNameSuffix(
+ const std::string& componentName) override;
+
+ int CreateDMG(const std::string& src_dir, const std::string& output_file);
+
+private:
+ std::string slaDirectory;
+ bool singleLicense;
+
+ struct RezDict
+ {
+ std::string Name;
+ size_t ID;
+ std::vector<unsigned char> Data;
+ };
+
+ struct RezArray
+ {
+ std::string Key;
+ std::vector<RezDict> Entries;
+ };
+
+ struct RezDoc
+ {
+ RezArray LPic = { "LPic", {} };
+ RezArray Menu = { "STR#", {} };
+ RezArray Text = { "TEXT", {} };
+ RezArray RTF = { "RTF ", {} };
+ };
+
+ void WriteRezXML(std::string const& file, RezDoc const& rez);
+ void WriteRezArray(cmXMLWriter& xml, RezArray const& array);
+ void WriteRezDict(cmXMLWriter& xml, RezDict const& dict);
+
+ bool WriteLicense(RezDoc& rez, size_t licenseNumber,
+ std::string licenseLanguage,
+ const std::string& licenseFile, std::string* error);
+ void EncodeLicense(RezDict& dict, std::vector<std::string> const& lines);
+ void EncodeMenu(RezDict& dict, std::vector<std::string> const& lines);
+ bool ReadFile(std::string const& file, std::vector<std::string>& lines,
+ std::string* error);
+ bool BreakLongLine(const std::string& line, std::vector<std::string>& lines,
+ std::string* error);
+};
diff --git a/Source/CPack/cmCPackExternalGenerator.cxx b/Source/CPack/cmCPackExternalGenerator.cxx
new file mode 100644
index 0000000..e3521a0
--- /dev/null
+++ b/Source/CPack/cmCPackExternalGenerator.cxx
@@ -0,0 +1,328 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackExternalGenerator.h"
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+
+#include <cm3p/json/value.h>
+#include <cm3p/json/writer.h>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+int cmCPackExternalGenerator::InitializeInternal()
+{
+ this->SetOption("CPACK_EXTERNAL_KNOWN_VERSIONS", "1.0");
+
+ if (!this->ReadListFile("Internal/CPack/CPackExternal.cmake")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while executing CPackExternal.cmake" << std::endl);
+ return 0;
+ }
+
+ std::string major = this->GetOption("CPACK_EXTERNAL_SELECTED_MAJOR");
+ if (major == "1") {
+ this->Generator = cm::make_unique<cmCPackExternalVersion1Generator>(this);
+ }
+
+ return this->Superclass::InitializeInternal();
+}
+
+int cmCPackExternalGenerator::PackageFiles()
+{
+ Json::StreamWriterBuilder builder;
+ builder["indentation"] = " ";
+
+ std::string filename = "package.json";
+ if (!this->packageFileNames.empty()) {
+ filename = this->packageFileNames[0];
+ }
+
+ cmsys::ofstream fout(filename.c_str());
+ std::unique_ptr<Json::StreamWriter> jout(builder.newStreamWriter());
+
+ Json::Value root(Json::objectValue);
+
+ if (!this->Generator->WriteToJSON(root)) {
+ return 0;
+ }
+
+ if (jout->write(root, &fout)) {
+ return 0;
+ }
+
+ const char* packageScript = this->GetOption("CPACK_EXTERNAL_PACKAGE_SCRIPT");
+ if (cmNonempty(packageScript)) {
+ if (!cmSystemTools::FileIsFullPath(packageScript)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_EXTERNAL_PACKAGE_SCRIPT does not contain a full file path"
+ << std::endl);
+ return 0;
+ }
+
+ bool res = this->MakefileMap->ReadListFile(packageScript);
+
+ if (cmSystemTools::GetErrorOccuredFlag() || !res) {
+ return 0;
+ }
+
+ const char* builtPackagesStr =
+ this->GetOption("CPACK_EXTERNAL_BUILT_PACKAGES");
+ if (builtPackagesStr) {
+ cmExpandList(builtPackagesStr, this->packageFileNames, false);
+ }
+ }
+
+ return 1;
+}
+
+bool cmCPackExternalGenerator::SupportsComponentInstallation() const
+{
+ return true;
+}
+
+int cmCPackExternalGenerator::InstallProjectViaInstallCommands(
+ bool setDestDir, const std::string& tempInstallDirectory)
+{
+ if (this->StagingEnabled()) {
+ return this->cmCPackGenerator::InstallProjectViaInstallCommands(
+ setDestDir, tempInstallDirectory);
+ }
+
+ return 1;
+}
+
+int cmCPackExternalGenerator::InstallProjectViaInstallScript(
+ bool setDestDir, const std::string& tempInstallDirectory)
+{
+ if (this->StagingEnabled()) {
+ return this->cmCPackGenerator::InstallProjectViaInstallScript(
+ setDestDir, tempInstallDirectory);
+ }
+
+ return 1;
+}
+
+int cmCPackExternalGenerator::InstallProjectViaInstalledDirectories(
+ bool setDestDir, const std::string& tempInstallDirectory,
+ const mode_t* default_dir_mode)
+{
+ if (this->StagingEnabled()) {
+ return this->cmCPackGenerator::InstallProjectViaInstalledDirectories(
+ setDestDir, tempInstallDirectory, default_dir_mode);
+ }
+
+ return 1;
+}
+
+int cmCPackExternalGenerator::RunPreinstallTarget(
+ const std::string& installProjectName, const std::string& installDirectory,
+ cmGlobalGenerator* globalGenerator, const std::string& buildConfig)
+{
+ if (this->StagingEnabled()) {
+ return this->cmCPackGenerator::RunPreinstallTarget(
+ installProjectName, installDirectory, globalGenerator, buildConfig);
+ }
+
+ return 1;
+}
+
+int cmCPackExternalGenerator::InstallCMakeProject(
+ bool setDestDir, const std::string& installDirectory,
+ const std::string& baseTempInstallDirectory, const mode_t* default_dir_mode,
+ const std::string& component, bool componentInstall,
+ const std::string& installSubDirectory, const std::string& buildConfig,
+ std::string& absoluteDestFiles)
+{
+ if (this->StagingEnabled()) {
+ return this->cmCPackGenerator::InstallCMakeProject(
+ setDestDir, installDirectory, baseTempInstallDirectory, default_dir_mode,
+ component, componentInstall, installSubDirectory, buildConfig,
+ absoluteDestFiles);
+ }
+
+ return 1;
+}
+
+bool cmCPackExternalGenerator::StagingEnabled() const
+{
+ return !cmIsOff(this->GetOption("CPACK_EXTERNAL_ENABLE_STAGING"));
+}
+
+cmCPackExternalGenerator::cmCPackExternalVersionGenerator::
+ cmCPackExternalVersionGenerator(cmCPackExternalGenerator* parent)
+ : Parent(parent)
+{
+}
+
+int cmCPackExternalGenerator::cmCPackExternalVersionGenerator::WriteVersion(
+ Json::Value& root)
+{
+ root["formatVersionMajor"] = this->GetVersionMajor();
+ root["formatVersionMinor"] = this->GetVersionMinor();
+
+ return 1;
+}
+
+int cmCPackExternalGenerator::cmCPackExternalVersionGenerator::WriteToJSON(
+ Json::Value& root)
+{
+ if (!this->WriteVersion(root)) {
+ return 0;
+ }
+
+ const char* packageName = this->Parent->GetOption("CPACK_PACKAGE_NAME");
+ if (packageName) {
+ root["packageName"] = packageName;
+ }
+
+ const char* packageVersion =
+ this->Parent->GetOption("CPACK_PACKAGE_VERSION");
+ if (packageVersion) {
+ root["packageVersion"] = packageVersion;
+ }
+
+ const char* packageDescriptionFile =
+ this->Parent->GetOption("CPACK_PACKAGE_DESCRIPTION_FILE");
+ if (packageDescriptionFile) {
+ root["packageDescriptionFile"] = packageDescriptionFile;
+ }
+
+ const char* packageDescriptionSummary =
+ this->Parent->GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY");
+ if (packageDescriptionSummary) {
+ root["packageDescriptionSummary"] = packageDescriptionSummary;
+ }
+
+ const char* buildConfigCstr = this->Parent->GetOption("CPACK_BUILD_CONFIG");
+ if (buildConfigCstr) {
+ root["buildConfig"] = buildConfigCstr;
+ }
+
+ const char* defaultDirectoryPermissions =
+ this->Parent->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
+ if (cmNonempty(defaultDirectoryPermissions)) {
+ root["defaultDirectoryPermissions"] = defaultDirectoryPermissions;
+ }
+ if (cmIsInternallyOn(this->Parent->GetOption("CPACK_SET_DESTDIR"))) {
+ root["setDestdir"] = true;
+ root["packagingInstallPrefix"] =
+ this->Parent->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
+ } else {
+ root["setDestdir"] = false;
+ }
+
+ root["stripFiles"] = !cmIsOff(this->Parent->GetOption("CPACK_STRIP_FILES"));
+ root["warnOnAbsoluteInstallDestination"] =
+ this->Parent->IsOn("CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION");
+ root["errorOnAbsoluteInstallDestination"] =
+ this->Parent->IsOn("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION");
+
+ Json::Value& projects = root["projects"] = Json::Value(Json::arrayValue);
+ for (auto& project : this->Parent->CMakeProjects) {
+ Json::Value jsonProject(Json::objectValue);
+
+ jsonProject["projectName"] = project.ProjectName;
+ jsonProject["component"] = project.Component;
+ jsonProject["directory"] = project.Directory;
+ jsonProject["subDirectory"] = project.SubDirectory;
+
+ Json::Value& installationTypes = jsonProject["installationTypes"] =
+ Json::Value(Json::arrayValue);
+ for (auto& installationType : project.InstallationTypes) {
+ installationTypes.append(installationType->Name);
+ }
+
+ Json::Value& components = jsonProject["components"] =
+ Json::Value(Json::arrayValue);
+ for (auto& component : project.Components) {
+ components.append(component->Name);
+ }
+
+ projects.append(jsonProject);
+ }
+
+ Json::Value& installationTypes = root["installationTypes"] =
+ Json::Value(Json::objectValue);
+ for (auto& installationType : this->Parent->InstallationTypes) {
+ Json::Value& jsonInstallationType =
+ installationTypes[installationType.first] =
+ Json::Value(Json::objectValue);
+
+ jsonInstallationType["name"] = installationType.second.Name;
+ jsonInstallationType["displayName"] = installationType.second.DisplayName;
+ jsonInstallationType["index"] = installationType.second.Index;
+ }
+
+ Json::Value& components = root["components"] =
+ Json::Value(Json::objectValue);
+ for (auto& component : this->Parent->Components) {
+ Json::Value& jsonComponent = components[component.first] =
+ Json::Value(Json::objectValue);
+
+ jsonComponent["name"] = component.second.Name;
+ jsonComponent["displayName"] = component.second.DisplayName;
+ if (component.second.Group) {
+ jsonComponent["group"] = component.second.Group->Name;
+ }
+ jsonComponent["isRequired"] = component.second.IsRequired;
+ jsonComponent["isHidden"] = component.second.IsHidden;
+ jsonComponent["isDisabledByDefault"] =
+ component.second.IsDisabledByDefault;
+ jsonComponent["isDownloaded"] = component.second.IsDownloaded;
+ jsonComponent["description"] = component.second.Description;
+ jsonComponent["archiveFile"] = component.second.ArchiveFile;
+
+ Json::Value& cmpInstallationTypes = jsonComponent["installationTypes"] =
+ Json::Value(Json::arrayValue);
+ for (auto& installationType : component.second.InstallationTypes) {
+ cmpInstallationTypes.append(installationType->Name);
+ }
+
+ Json::Value& dependencies = jsonComponent["dependencies"] =
+ Json::Value(Json::arrayValue);
+ for (auto& dep : component.second.Dependencies) {
+ dependencies.append(dep->Name);
+ }
+ }
+
+ Json::Value& groups = root["componentGroups"] =
+ Json::Value(Json::objectValue);
+ for (auto& group : this->Parent->ComponentGroups) {
+ Json::Value& jsonGroup = groups[group.first] =
+ Json::Value(Json::objectValue);
+
+ jsonGroup["name"] = group.second.Name;
+ jsonGroup["displayName"] = group.second.DisplayName;
+ jsonGroup["description"] = group.second.Description;
+ jsonGroup["isBold"] = group.second.IsBold;
+ jsonGroup["isExpandedByDefault"] = group.second.IsExpandedByDefault;
+ if (group.second.ParentGroup) {
+ jsonGroup["parentGroup"] = group.second.ParentGroup->Name;
+ }
+
+ Json::Value& subgroups = jsonGroup["subgroups"] =
+ Json::Value(Json::arrayValue);
+ for (auto& subgroup : group.second.Subgroups) {
+ subgroups.append(subgroup->Name);
+ }
+
+ Json::Value& groupComponents = jsonGroup["components"] =
+ Json::Value(Json::arrayValue);
+ for (auto& component : group.second.Components) {
+ groupComponents.append(component->Name);
+ }
+ }
+
+ return 1;
+}
diff --git a/Source/CPack/cmCPackExternalGenerator.h b/Source/CPack/cmCPackExternalGenerator.h
new file mode 100644
index 0000000..dfd13e8
--- /dev/null
+++ b/Source/CPack/cmCPackExternalGenerator.h
@@ -0,0 +1,87 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "cm_sys_stat.h"
+
+#include "cmCPackGenerator.h"
+
+class cmGlobalGenerator;
+namespace Json {
+class Value;
+}
+
+/** \class cmCPackExternalGenerator
+ * \brief A generator for CPack External packaging tools
+ */
+class cmCPackExternalGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackExternalGenerator, cmCPackGenerator);
+
+ const char* GetOutputExtension() override { return ".json"; }
+
+protected:
+ int InitializeInternal() override;
+
+ int PackageFiles() override;
+
+ bool SupportsComponentInstallation() const override;
+
+ int InstallProjectViaInstallCommands(
+ bool setDestDir, const std::string& tempInstallDirectory) override;
+ int InstallProjectViaInstallScript(
+ bool setDestDir, const std::string& tempInstallDirectory) override;
+ int InstallProjectViaInstalledDirectories(
+ bool setDestDir, const std::string& tempInstallDirectory,
+ const mode_t* default_dir_mode) override;
+
+ int RunPreinstallTarget(const std::string& installProjectName,
+ const std::string& installDirectory,
+ cmGlobalGenerator* globalGenerator,
+ const std::string& buildConfig) override;
+ int InstallCMakeProject(bool setDestDir, const std::string& installDirectory,
+ const std::string& baseTempInstallDirectory,
+ const mode_t* default_dir_mode,
+ const std::string& component, bool componentInstall,
+ const std::string& installSubDirectory,
+ const std::string& buildConfig,
+ std::string& absoluteDestFiles) override;
+
+private:
+ bool StagingEnabled() const;
+
+ class cmCPackExternalVersionGenerator
+ {
+ public:
+ cmCPackExternalVersionGenerator(cmCPackExternalGenerator* parent);
+
+ virtual ~cmCPackExternalVersionGenerator() = default;
+
+ virtual int WriteToJSON(Json::Value& root);
+
+ protected:
+ virtual int GetVersionMajor() = 0;
+ virtual int GetVersionMinor() = 0;
+
+ int WriteVersion(Json::Value& root);
+
+ cmCPackExternalGenerator* Parent;
+ };
+
+ class cmCPackExternalVersion1Generator
+ : public cmCPackExternalVersionGenerator
+ {
+ public:
+ using cmCPackExternalVersionGenerator::cmCPackExternalVersionGenerator;
+
+ protected:
+ int GetVersionMajor() override { return 1; }
+ int GetVersionMinor() override { return 0; }
+ };
+
+ std::unique_ptr<cmCPackExternalVersionGenerator> Generator;
+};
diff --git a/Source/CPack/cmCPackFreeBSDGenerator.cxx b/Source/CPack/cmCPackFreeBSDGenerator.cxx
new file mode 100644
index 0000000..b673006
--- /dev/null
+++ b/Source/CPack/cmCPackFreeBSDGenerator.cxx
@@ -0,0 +1,336 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackFreeBSDGenerator.h"
+
+#include "cmArchiveWrite.h"
+#include "cmCPackArchiveGenerator.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmWorkingDirectory.h"
+
+// Needed for ::open() and ::stat()
+#include <algorithm>
+#include <ostream>
+#include <utility>
+#include <vector>
+
+#include <fcntl.h>
+#include <pkg.h>
+
+#include <sys/stat.h>
+
+cmCPackFreeBSDGenerator::cmCPackFreeBSDGenerator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressXZ, "paxr", ".txz")
+{
+}
+
+int cmCPackFreeBSDGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr/local");
+ this->SetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "0");
+ return this->Superclass::InitializeInternal();
+}
+
+cmCPackFreeBSDGenerator::~cmCPackFreeBSDGenerator() = default;
+
+// This is a wrapper, for use only in stream-based output,
+// that will output a string in UCL escaped fashion (in particular,
+// quotes and backslashes are escaped). The list of characters
+// to escape is taken from https://github.com/vstakhov/libucl
+// (which is the reference implementation pkg(8) refers to).
+class EscapeQuotes
+{
+public:
+ const std::string& value;
+
+ EscapeQuotes(const std::string& s)
+ : value(s)
+ {
+ }
+};
+
+// Output a string as "string" with escaping applied.
+cmGeneratedFileStream& operator<<(cmGeneratedFileStream& s,
+ const EscapeQuotes& v)
+{
+ s << '"';
+ for (char c : v.value) {
+ switch (c) {
+ case '\n':
+ s << "\\n";
+ break;
+ case '\r':
+ s << "\\r";
+ break;
+ case '\b':
+ s << "\\b";
+ break;
+ case '\t':
+ s << "\\t";
+ break;
+ case '\f':
+ s << "\\f";
+ break;
+ case '\\':
+ s << "\\\\";
+ break;
+ case '"':
+ s << "\\\"";
+ break;
+ default:
+ s << c;
+ break;
+ }
+ }
+ s << '"';
+ return s;
+}
+
+// The following classes are all helpers for writing out the UCL
+// manifest file (it also looks like JSON). ManifestKey just has
+// a (string-valued) key; subclasses add a specific kind of
+// value-type to the key, and implement write_value() to output
+// the corresponding UCL.
+class ManifestKey
+{
+public:
+ std::string key;
+
+ ManifestKey(std::string k)
+ : key(std::move(k))
+ {
+ }
+
+ virtual ~ManifestKey() = default;
+
+ // Output the value associated with this key to the stream @p s.
+ // Format is to be decided by subclasses.
+ virtual void write_value(cmGeneratedFileStream& s) const = 0;
+};
+
+// Basic string-value (e.g. "name": "cmake")
+class ManifestKeyValue : public ManifestKey
+{
+public:
+ std::string value;
+
+ ManifestKeyValue(const std::string& k, std::string v)
+ : ManifestKey(k)
+ , value(std::move(v))
+ {
+ }
+
+ void write_value(cmGeneratedFileStream& s) const override
+ {
+ s << EscapeQuotes(value);
+ }
+};
+
+// List-of-strings values (e.g. "licenses": ["GPLv2", "LGPLv2"])
+class ManifestKeyListValue : public ManifestKey
+{
+public:
+ using VList = std::vector<std::string>;
+ VList value;
+
+ ManifestKeyListValue(const std::string& k)
+ : ManifestKey(k)
+ {
+ }
+
+ ManifestKeyListValue& operator<<(const std::string& v)
+ {
+ value.push_back(v);
+ return *this;
+ }
+
+ ManifestKeyListValue& operator<<(const std::vector<std::string>& v)
+ {
+ for (std::string const& e : v) {
+ (*this) << e;
+ }
+ return *this;
+ }
+
+ void write_value(cmGeneratedFileStream& s) const override
+ {
+ bool with_comma = false;
+
+ s << '[';
+ for (std::string const& elem : value) {
+ s << (with_comma ? ',' : ' ');
+ s << EscapeQuotes(elem);
+ with_comma = true;
+ }
+ s << " ]";
+ }
+};
+
+// Deps: actually a dictionary, but we'll treat it as a
+// list so we only name the deps, and produce dictionary-
+// like output via write_value()
+class ManifestKeyDepsValue : public ManifestKeyListValue
+{
+public:
+ ManifestKeyDepsValue(const std::string& k)
+ : ManifestKeyListValue(k)
+ {
+ }
+
+ void write_value(cmGeneratedFileStream& s) const override
+ {
+ s << "{\n";
+ for (std::string const& elem : value) {
+ s << " \"" << elem << R"(": {"origin": ")" << elem << "\"},\n";
+ }
+ s << '}';
+ }
+};
+
+// Write one of the key-value classes (above) to the stream @p s
+cmGeneratedFileStream& operator<<(cmGeneratedFileStream& s,
+ const ManifestKey& v)
+{
+ s << '"' << v.key << "\": ";
+ v.write_value(s);
+ s << ",\n";
+ return s;
+}
+
+// Look up variable; if no value is set, returns an empty string;
+// basically a wrapper that handles the NULL-ptr return from GetOption().
+std::string cmCPackFreeBSDGenerator::var_lookup(const char* var_name)
+{
+ const char* pv = this->GetOption(var_name);
+ if (!pv) {
+ return std::string();
+ }
+ return pv;
+}
+
+// Produce UCL in the given @p manifest file for the common
+// manifest fields (common to the compact and regular formats),
+// by reading the CPACK_FREEBSD_* variables.
+void cmCPackFreeBSDGenerator::write_manifest_fields(
+ cmGeneratedFileStream& manifest)
+{
+ manifest << ManifestKeyValue("name",
+ var_lookup("CPACK_FREEBSD_PACKAGE_NAME"));
+ manifest << ManifestKeyValue("origin",
+ var_lookup("CPACK_FREEBSD_PACKAGE_ORIGIN"));
+ manifest << ManifestKeyValue("version",
+ var_lookup("CPACK_FREEBSD_PACKAGE_VERSION"));
+ manifest << ManifestKeyValue("maintainer",
+ var_lookup("CPACK_FREEBSD_PACKAGE_MAINTAINER"));
+ manifest << ManifestKeyValue("comment",
+ var_lookup("CPACK_FREEBSD_PACKAGE_COMMENT"));
+ manifest << ManifestKeyValue(
+ "desc", var_lookup("CPACK_FREEBSD_PACKAGE_DESCRIPTION"));
+ manifest << ManifestKeyValue("www", var_lookup("CPACK_FREEBSD_PACKAGE_WWW"));
+ std::vector<std::string> licenses =
+ cmExpandedList(var_lookup("CPACK_FREEBSD_PACKAGE_LICENSE"));
+ std::string licenselogic("single");
+ if (licenses.empty()) {
+ cmSystemTools::SetFatalErrorOccured();
+ } else if (licenses.size() > 1) {
+ licenselogic = var_lookup("CPACK_FREEBSD_PACKAGE_LICENSE_LOGIC");
+ }
+ manifest << ManifestKeyValue("licenselogic", licenselogic);
+ manifest << (ManifestKeyListValue("licenses") << licenses);
+ std::vector<std::string> categories =
+ cmExpandedList(var_lookup("CPACK_FREEBSD_PACKAGE_CATEGORIES"));
+ manifest << (ManifestKeyListValue("categories") << categories);
+ manifest << ManifestKeyValue("prefix", var_lookup("CMAKE_INSTALL_PREFIX"));
+ std::vector<std::string> deps =
+ cmExpandedList(var_lookup("CPACK_FREEBSD_PACKAGE_DEPS"));
+ if (!deps.empty()) {
+ manifest << (ManifestKeyDepsValue("deps") << deps);
+ }
+}
+
+// Package only actual files; others are ignored (in particular,
+// intermediate subdirectories are ignored).
+static bool ignore_file(const std::string& filename)
+{
+ struct stat statbuf;
+ return stat(filename.c_str(), &statbuf) < 0 ||
+ (statbuf.st_mode & S_IFMT) != S_IFREG;
+}
+
+// Write the given list of @p files to the manifest stream @p s,
+// as the UCL field "files" (which is dictionary-valued, to
+// associate filenames with hashes). All the files are transformed
+// to paths relative to @p toplevel, with a leading / (since the paths
+// in FreeBSD package files are supposed to be absolute).
+void write_manifest_files(cmGeneratedFileStream& s,
+ const std::string& toplevel,
+ const std::vector<std::string>& files)
+{
+ s << "\"files\": {\n";
+ for (std::string const& file : files) {
+ s << " \"/" << cmSystemTools::RelativePath(toplevel, file) << "\": \""
+ << "<sha256>"
+ << "\",\n";
+ }
+ s << " },\n";
+}
+
+int cmCPackFreeBSDGenerator::PackageFiles()
+{
+ if (!this->ReadListFile("Internal/CPack/CPackFreeBSD.cmake")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while execution CPackFreeBSD.cmake" << std::endl);
+ return 0;
+ }
+
+ std::vector<std::string>::const_iterator fileIt;
+ cmWorkingDirectory wd(toplevel);
+
+ files.erase(std::remove_if(files.begin(), files.end(), ignore_file),
+ files.end());
+
+ std::string manifestname = toplevel + "/+MANIFEST";
+ {
+ cmGeneratedFileStream manifest(manifestname);
+ manifest << "{\n";
+ write_manifest_fields(manifest);
+ write_manifest_files(manifest, toplevel, files);
+ manifest << "}\n";
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl);
+
+ if (WantsComponentInstallation()) {
+ // CASE 1 : COMPONENT ALL-IN-ONE package
+ // If ALL COMPONENTS in ONE package has been requested
+ // then the package file is unique and should be open here.
+ if (componentPackageMethod == ONE_PACKAGE) {
+ return PackageComponentsAllInOne();
+ }
+ // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
+ // There will be 1 package for each component group
+ // however one may require to ignore component group and
+ // in this case you'll get 1 package for each component.
+ return PackageComponents(componentPackageMethod ==
+ ONE_PACKAGE_PER_COMPONENT);
+ }
+
+ std::string output_dir = cmSystemTools::CollapseFullPath("../", toplevel);
+ pkg_create_from_manifest(output_dir.c_str(), ::TXZ, toplevel.c_str(),
+ manifestname.c_str(), nullptr);
+
+ std::string broken_suffix =
+ cmStrCat('-', var_lookup("CPACK_TOPLEVEL_TAG"), ".txz");
+ for (std::string& name : packageFileNames) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Packagefile " << name << std::endl);
+ if (cmHasSuffix(name, broken_suffix)) {
+ name.replace(name.size() - broken_suffix.size(), std::string::npos,
+ ".txz");
+ break;
+ }
+ }
+
+ return 1;
+}
diff --git a/Source/CPack/cmCPackFreeBSDGenerator.h b/Source/CPack/cmCPackFreeBSDGenerator.h
new file mode 100644
index 0000000..eed8053
--- /dev/null
+++ b/Source/CPack/cmCPackFreeBSDGenerator.h
@@ -0,0 +1,34 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+
+#include "cmCPackArchiveGenerator.h"
+#include "cmCPackGenerator.h"
+
+class cmGeneratedFileStream;
+
+/** \class cmCPackFreeBSDGenerator
+ * \brief A generator for FreeBSD package files (TXZ with a manifest)
+ *
+ */
+class cmCPackFreeBSDGenerator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackFreeBSDGenerator, cmCPackArchiveGenerator);
+ /**
+ * Construct generator
+ */
+ cmCPackFreeBSDGenerator();
+ ~cmCPackFreeBSDGenerator() override;
+
+ int InitializeInternal() override;
+ int PackageFiles() override;
+
+protected:
+ std::string var_lookup(const char* var_name);
+ void write_manifest_fields(cmGeneratedFileStream&);
+};
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
new file mode 100644
index 0000000..c512a36
--- /dev/null
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -0,0 +1,1634 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackGenerator.h"
+
+#include <algorithm>
+#include <cstring>
+#include <memory>
+#include <utility>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmCryptoHash.h"
+#include "cmDuration.h"
+#include "cmFSPermissions.h"
+#include "cmFileTimes.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+#include "cmWorkingDirectory.h"
+#include "cmXMLSafe.h"
+#include "cmake.h"
+
+#if defined(__HAIKU__)
+# include <FindDirectory.h>
+# include <StorageDefs.h>
+#endif
+
+cmCPackGenerator::cmCPackGenerator()
+{
+ this->GeneratorVerbose = cmSystemTools::OUTPUT_NONE;
+ this->MakefileMap = nullptr;
+ this->Logger = nullptr;
+ this->componentPackageMethod = ONE_PACKAGE_PER_GROUP;
+}
+
+cmCPackGenerator::~cmCPackGenerator()
+{
+ this->MakefileMap = nullptr;
+}
+
+void cmCPackGenerator::DisplayVerboseOutput(const std::string& msg,
+ float progress)
+{
+ (void)progress;
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "" << msg << std::endl);
+}
+
+int cmCPackGenerator::PrepareNames()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Create temp directory." << std::endl);
+
+ // checks CPACK_SET_DESTDIR support
+ if (this->IsOn("CPACK_SET_DESTDIR")) {
+ if (SETDESTDIR_UNSUPPORTED == this->SupportsSetDestdir()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_SET_DESTDIR is set to ON but the '"
+ << this->Name << "' generator does NOT support it."
+ << std::endl);
+ return 0;
+ }
+ if (SETDESTDIR_SHOULD_NOT_BE_USED == this->SupportsSetDestdir()) {
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "CPACK_SET_DESTDIR is set to ON but it is "
+ << "usually a bad idea to do that with '" << this->Name
+ << "' generator. Use at your own risk." << std::endl);
+ }
+ }
+
+ std::string tempDirectory =
+ cmStrCat(this->GetOption("CPACK_PACKAGE_DIRECTORY"), "/_CPack_Packages/");
+ const char* toplevelTag = this->GetOption("CPACK_TOPLEVEL_TAG");
+ if (toplevelTag) {
+ tempDirectory += toplevelTag;
+ tempDirectory += "/";
+ }
+ tempDirectory += this->GetOption("CPACK_GENERATOR");
+ std::string topDirectory = tempDirectory;
+ const char* pfname = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ if (!pfname) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_PACKAGE_FILE_NAME not specified" << std::endl);
+ return 0;
+ }
+ std::string outName = pfname;
+ tempDirectory += "/" + outName;
+ if (!this->GetOutputExtension()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "No output extension specified" << std::endl);
+ return 0;
+ }
+ outName += this->GetOutputExtension();
+ const char* pdir = this->GetOption("CPACK_PACKAGE_DIRECTORY");
+ if (!pdir) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_PACKAGE_DIRECTORY not specified" << std::endl);
+ return 0;
+ }
+
+ std::string destFile = pdir;
+ this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_PREFIX", destFile.c_str());
+ destFile += "/" + outName;
+ std::string outFile = topDirectory + "/" + outName;
+ this->SetOptionIfNotSet("CPACK_TOPLEVEL_DIRECTORY", topDirectory.c_str());
+ this->SetOptionIfNotSet("CPACK_TEMPORARY_DIRECTORY", tempDirectory.c_str());
+ this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_NAME", outName.c_str());
+ this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_PATH", destFile.c_str());
+ this->SetOptionIfNotSet("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
+ outFile.c_str());
+ this->SetOptionIfNotSet("CPACK_INSTALL_DIRECTORY", this->GetInstallPath());
+ this->SetOptionIfNotSet(
+ "CPACK_NATIVE_INSTALL_DIRECTORY",
+ cmsys::SystemTools::ConvertToOutputPath(this->GetInstallPath()).c_str());
+ this->SetOptionIfNotSet("CPACK_TEMPORARY_INSTALL_DIRECTORY",
+ tempDirectory.c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Look for: CPACK_PACKAGE_DESCRIPTION_FILE" << std::endl);
+ const char* descFileName = this->GetOption("CPACK_PACKAGE_DESCRIPTION_FILE");
+ if (descFileName && !this->GetOption("CPACK_PACKAGE_DESCRIPTION")) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Look for: " << descFileName << std::endl);
+ if (!cmSystemTools::FileExists(descFileName)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find description file name: ["
+ << descFileName << "]" << std::endl);
+ return 0;
+ }
+ cmsys::ifstream ifs(descFileName);
+ if (!ifs) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot open description file name: " << descFileName
+ << std::endl);
+ return 0;
+ }
+ std::ostringstream ostr;
+ std::string line;
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Read description file: " << descFileName << std::endl);
+ while (ifs && cmSystemTools::GetLineFromStream(ifs, line)) {
+ ostr << cmXMLSafe(line) << std::endl;
+ }
+ this->SetOption("CPACK_PACKAGE_DESCRIPTION", ostr.str().c_str());
+ const char* defFileName =
+ this->GetOption("CPACK_DEFAULT_PACKAGE_DESCRIPTION_FILE");
+ if (defFileName && !strcmp(defFileName, descFileName)) {
+ this->SetOption("CPACK_USED_DEFAULT_PACKAGE_DESCRIPTION_FILE", "ON");
+ }
+ }
+ if (!this->GetOption("CPACK_PACKAGE_DESCRIPTION")) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Project description not specified. Please specify "
+ "CPACK_PACKAGE_DESCRIPTION or CPACK_PACKAGE_DESCRIPTION_FILE."
+ << std::endl);
+ return 0;
+ }
+ const char* algoSignature = this->GetOption("CPACK_PACKAGE_CHECKSUM");
+ if (algoSignature) {
+ if (!cmCryptoHash::New(algoSignature)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot recognize algorithm: " << algoSignature
+ << std::endl);
+ return 0;
+ }
+ }
+
+ this->SetOptionIfNotSet("CPACK_REMOVE_TOPLEVEL_DIRECTORY", "1");
+
+ return 1;
+}
+
+int cmCPackGenerator::InstallProject()
+{
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Install projects" << std::endl);
+ this->CleanTemporaryDirectory();
+
+ std::string bareTempInstallDirectory =
+ this->GetOption("CPACK_TEMPORARY_INSTALL_DIRECTORY");
+ std::string tempInstallDirectoryStr = bareTempInstallDirectory;
+ bool setDestDir = cmIsOn(this->GetOption("CPACK_SET_DESTDIR")) |
+ cmIsInternallyOn(this->GetOption("CPACK_SET_DESTDIR"));
+ if (!setDestDir) {
+ tempInstallDirectoryStr += this->GetPackagingInstallPrefix();
+ }
+
+ const char* tempInstallDirectory = tempInstallDirectoryStr.c_str();
+ int res = 1;
+ if (!cmsys::SystemTools::MakeDirectory(bareTempInstallDirectory)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating temporary directory: "
+ << (tempInstallDirectory ? tempInstallDirectory : "(NULL)")
+ << std::endl);
+ return 0;
+ }
+
+ if (setDestDir) {
+ std::string destDir = cmStrCat("DESTDIR=", tempInstallDirectory);
+ cmSystemTools::PutEnv(destDir);
+ } else {
+ // Make sure there is no destdir
+ cmSystemTools::PutEnv("DESTDIR=");
+ }
+
+ // prepare default created directory permissions
+ mode_t default_dir_mode_v = 0;
+ mode_t* default_dir_mode = nullptr;
+ const char* default_dir_install_permissions =
+ this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
+ if (cmNonempty(default_dir_install_permissions)) {
+ std::vector<std::string> items =
+ cmExpandedList(default_dir_install_permissions);
+ for (const auto& arg : items) {
+ if (!cmFSPermissions::stringToModeT(arg, default_dir_mode_v)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Invalid permission value '"
+ << arg
+ << "'."
+ " CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS "
+ "value is invalid."
+ << std::endl);
+ return 0;
+ }
+ }
+
+ default_dir_mode = &default_dir_mode_v;
+ }
+
+ // If the CPackConfig file sets CPACK_INSTALL_COMMANDS then run them
+ // as listed
+ if (!this->InstallProjectViaInstallCommands(setDestDir,
+ tempInstallDirectory)) {
+ return 0;
+ }
+
+ // If the CPackConfig file sets CPACK_INSTALL_SCRIPT(S) then run them
+ // as listed
+ if (!this->InstallProjectViaInstallScript(setDestDir,
+ tempInstallDirectory)) {
+ return 0;
+ }
+
+ // If the CPackConfig file sets CPACK_INSTALLED_DIRECTORIES
+ // then glob it and copy it to CPACK_TEMPORARY_DIRECTORY
+ // This is used in Source packaging
+ if (!this->InstallProjectViaInstalledDirectories(
+ setDestDir, tempInstallDirectory, default_dir_mode)) {
+ return 0;
+ }
+
+ // If the project is a CMAKE project then run pre-install
+ // and then read the cmake_install script to run it
+ if (!this->InstallProjectViaInstallCMakeProjects(
+ setDestDir, bareTempInstallDirectory, default_dir_mode)) {
+ return 0;
+ }
+
+ // Run pre-build actions
+ const char* preBuildScripts = this->GetOption("CPACK_PRE_BUILD_SCRIPTS");
+ if (preBuildScripts) {
+ const auto scripts = cmExpandedList(preBuildScripts, false);
+ for (const auto& script : scripts) {
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "Executing pre-build script: " << script << std::endl);
+
+ if (!this->MakefileMap->ReadListFile(script)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "The pre-build script not found: " << script
+ << std::endl);
+ return 0;
+ }
+ }
+ }
+
+ if (setDestDir) {
+ cmSystemTools::PutEnv("DESTDIR=");
+ }
+
+ return res;
+}
+
+int cmCPackGenerator::InstallProjectViaInstallCommands(
+ bool setDestDir, const std::string& tempInstallDirectory)
+{
+ (void)setDestDir;
+ const char* installCommands = this->GetOption("CPACK_INSTALL_COMMANDS");
+ if (cmNonempty(installCommands)) {
+ std::string tempInstallDirectoryEnv =
+ cmStrCat("CMAKE_INSTALL_PREFIX=", tempInstallDirectory);
+ cmSystemTools::PutEnv(tempInstallDirectoryEnv);
+ std::vector<std::string> installCommandsVector =
+ cmExpandedList(installCommands);
+ for (std::string const& ic : installCommandsVector) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << ic << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool resB = cmSystemTools::RunSingleCommand(
+ ic, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
+ if (!resB || retVal) {
+ std::string tmpFile = cmStrCat(
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/InstallOutput.log");
+ cmGeneratedFileStream ofs(tmpFile);
+ ofs << "# Run command: " << ic << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem running install command: "
+ << ic << std::endl
+ << "Please check " << tmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+int cmCPackGenerator::InstallProjectViaInstalledDirectories(
+ bool setDestDir, const std::string& tempInstallDirectory,
+ const mode_t* default_dir_mode)
+{
+ (void)setDestDir;
+ (void)tempInstallDirectory;
+ std::vector<cmsys::RegularExpression> ignoreFilesRegex;
+ const char* cpackIgnoreFiles = this->GetOption("CPACK_IGNORE_FILES");
+ if (cpackIgnoreFiles) {
+ std::vector<std::string> ignoreFilesRegexString =
+ cmExpandedList(cpackIgnoreFiles);
+ for (std::string const& ifr : ignoreFilesRegexString) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Create ignore files regex for: " << ifr << std::endl);
+ ignoreFilesRegex.emplace_back(ifr);
+ }
+ }
+ const char* installDirectories =
+ this->GetOption("CPACK_INSTALLED_DIRECTORIES");
+ if (cmNonempty(installDirectories)) {
+ std::vector<std::string> installDirectoriesVector =
+ cmExpandedList(installDirectories);
+ if (installDirectoriesVector.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_INSTALLED_DIRECTORIES should contain pairs of <directory> "
+ "and "
+ "<subdirectory>. The <subdirectory> can be '.' to be installed in "
+ "the toplevel directory of installation."
+ << std::endl);
+ return 0;
+ }
+ std::vector<std::string>::iterator it;
+ const std::string& tempDir = tempInstallDirectory;
+ for (it = installDirectoriesVector.begin();
+ it != installDirectoriesVector.end(); ++it) {
+ std::vector<std::pair<std::string, std::string>> symlinkedFiles;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Find files" << std::endl);
+ cmsys::Glob gl;
+ std::string top = *it;
+ it++;
+ std::string subdir = *it;
+ std::string findExpr = cmStrCat(top, "/*");
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Install directory: " << top << std::endl);
+ gl.RecurseOn();
+ gl.SetRecurseListDirs(true);
+ gl.SetRecurseThroughSymlinks(false);
+ if (!gl.FindFiles(findExpr)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find any files in the installed directory"
+ << std::endl);
+ return 0;
+ }
+ this->files = gl.GetFiles();
+ for (std::string const& gf : this->files) {
+ bool skip = false;
+ std::string inFile = gf;
+ if (cmSystemTools::FileIsDirectory(gf) &&
+ !cmSystemTools::FileIsSymlink(gf)) {
+ inFile += '/';
+ }
+ for (cmsys::RegularExpression& reg : ignoreFilesRegex) {
+ if (reg.find(inFile)) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Ignore file: " << inFile << std::endl);
+ skip = true;
+ }
+ }
+ if (skip) {
+ continue;
+ }
+ std::string filePath = cmStrCat(tempDir, '/', subdir, '/',
+ cmSystemTools::RelativePath(top, gf));
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Copy file: " << inFile << " -> " << filePath
+ << std::endl);
+ /* If the file is a symlink we will have to re-create it */
+ if (cmSystemTools::FileIsSymlink(inFile)) {
+ std::string targetFile;
+ std::string inFileRelative =
+ cmSystemTools::RelativePath(top, inFile);
+ cmSystemTools::ReadSymlink(inFile, targetFile);
+ symlinkedFiles.emplace_back(std::move(targetFile),
+ std::move(inFileRelative));
+ }
+ /* If it is not a symlink then do a plain copy */
+ else if (!(cmSystemTools::CopyFileIfDifferent(inFile, filePath) &&
+ cmFileTimes::Copy(inFile, filePath))) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem copying file: " << inFile << " -> "
+ << filePath << std::endl);
+ return 0;
+ }
+ }
+ /* rebuild symlinks in the installed tree */
+ if (!symlinkedFiles.empty()) {
+ std::string goToDir = cmStrCat(tempDir, '/', subdir);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Change dir to: " << goToDir << std::endl);
+ cmWorkingDirectory workdir(goToDir);
+ if (workdir.Failed()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Failed to change working directory to "
+ << goToDir << " : "
+ << std::strerror(workdir.GetLastResult())
+ << std::endl);
+ return 0;
+ }
+ for (auto const& symlinked : symlinkedFiles) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Will create a symlink: " << symlinked.second << "--> "
+ << symlinked.first
+ << std::endl);
+ // make sure directory exists for symlink
+ std::string destDir =
+ cmSystemTools::GetFilenamePath(symlinked.second);
+ if (!destDir.empty() &&
+ !cmSystemTools::MakeDirectory(destDir, default_dir_mode)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot create dir: "
+ << destDir << "\nTrying to create symlink: "
+ << symlinked.second << "--> " << symlinked.first
+ << std::endl);
+ }
+ if (!cmSystemTools::CreateSymlink(symlinked.first,
+ symlinked.second)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot create symlink: "
+ << symlinked.second << "--> " << symlinked.first
+ << std::endl);
+ return 0;
+ }
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Going back to: " << workdir.GetOldDirectory()
+ << std::endl);
+ }
+ }
+ }
+ return 1;
+}
+
+int cmCPackGenerator::InstallProjectViaInstallScript(
+ bool setDestDir, const std::string& tempInstallDirectory)
+{
+ const char* cmakeScripts = this->GetOption("CPACK_INSTALL_SCRIPTS");
+ {
+ const char* const cmakeScript = this->GetOption("CPACK_INSTALL_SCRIPT");
+ if (cmakeScript && cmakeScripts) {
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING,
+ "Both CPACK_INSTALL_SCRIPTS and CPACK_INSTALL_SCRIPT are set, "
+ "the latter will be ignored."
+ << std::endl);
+ } else if (cmakeScript && !cmakeScripts) {
+ cmakeScripts = cmakeScript;
+ }
+ }
+ if (cmakeScripts && *cmakeScripts) {
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Install scripts: " << cmakeScripts << std::endl);
+ std::vector<std::string> cmakeScriptsVector = cmExpandedList(cmakeScripts);
+ for (std::string const& installScript : cmakeScriptsVector) {
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Install script: " << installScript << std::endl);
+
+ if (setDestDir) {
+ // For DESTDIR based packaging, use the *project*
+ // CMAKE_INSTALL_PREFIX underneath the tempInstallDirectory. The
+ // value of the project's CMAKE_INSTALL_PREFIX is sent in here as the
+ // value of the CPACK_INSTALL_PREFIX variable.
+
+ std::string dir;
+ if (this->GetOption("CPACK_INSTALL_PREFIX")) {
+ dir += this->GetOption("CPACK_INSTALL_PREFIX");
+ }
+ this->SetOption("CMAKE_INSTALL_PREFIX", dir.c_str());
+ cmCPackLogger(
+ cmCPackLog::LOG_DEBUG,
+ "- Using DESTDIR + CPACK_INSTALL_PREFIX... (this->SetOption)"
+ << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Setting CMAKE_INSTALL_PREFIX to '" << dir << "'"
+ << std::endl);
+ } else {
+ this->SetOption("CMAKE_INSTALL_PREFIX", tempInstallDirectory.c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Using non-DESTDIR install... (this->SetOption)"
+ << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Setting CMAKE_INSTALL_PREFIX to '"
+ << tempInstallDirectory << "'" << std::endl);
+ }
+
+ this->SetOptionIfNotSet("CMAKE_CURRENT_BINARY_DIR",
+ tempInstallDirectory.c_str());
+ this->SetOptionIfNotSet("CMAKE_CURRENT_SOURCE_DIR",
+ tempInstallDirectory.c_str());
+ bool res = this->MakefileMap->ReadListFile(installScript);
+ if (cmSystemTools::GetErrorOccuredFlag() || !res) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
+ bool setDestDir, const std::string& baseTempInstallDirectory,
+ const mode_t* default_dir_mode)
+{
+ const char* cmakeProjects = this->GetOption("CPACK_INSTALL_CMAKE_PROJECTS");
+ const char* cmakeGenerator = this->GetOption("CPACK_CMAKE_GENERATOR");
+ std::string absoluteDestFiles;
+ if (cmNonempty(cmakeProjects)) {
+ if (!cmakeGenerator) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_INSTALL_CMAKE_PROJECTS is specified, but "
+ "CPACK_CMAKE_GENERATOR is not. CPACK_CMAKE_GENERATOR "
+ "is required to install the project."
+ << std::endl);
+ return 0;
+ }
+ std::vector<std::string> cmakeProjectsVector =
+ cmExpandedList(cmakeProjects);
+ std::vector<std::string>::iterator it;
+ for (it = cmakeProjectsVector.begin(); it != cmakeProjectsVector.end();
+ ++it) {
+ if (it + 1 == cmakeProjectsVector.end() ||
+ it + 2 == cmakeProjectsVector.end() ||
+ it + 3 == cmakeProjectsVector.end()) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Not enough items on list: CPACK_INSTALL_CMAKE_PROJECTS. "
+ "CPACK_INSTALL_CMAKE_PROJECTS should hold quadruplet of install "
+ "directory, install project name, install component, and install "
+ "subdirectory."
+ << std::endl);
+ return 0;
+ }
+ std::string installDirectory = *it;
+ ++it;
+ std::string installProjectName = *it;
+ ++it;
+ cmCPackInstallCMakeProject project;
+
+ project.Directory = installDirectory;
+ project.ProjectName = installProjectName;
+ project.Component = *it;
+ ++it;
+ project.SubDirectory = *it;
+
+ std::vector<std::string> componentsVector;
+
+ bool componentInstall = false;
+ /*
+ * We do a component install iff
+ * - the CPack generator support component
+ * - the user did not request Monolithic install
+ * (this works at CPack time too)
+ */
+ if (this->SupportsComponentInstallation() &&
+ !(this->IsOn("CPACK_MONOLITHIC_INSTALL"))) {
+ // Determine the installation types for this project (if provided).
+ std::string installTypesVar = "CPACK_" +
+ cmSystemTools::UpperCase(project.Component) + "_INSTALL_TYPES";
+ const char* installTypes = this->GetOption(installTypesVar);
+ if (cmNonempty(installTypes)) {
+ std::vector<std::string> installTypesVector =
+ cmExpandedList(installTypes);
+ for (std::string const& installType : installTypesVector) {
+ project.InstallationTypes.push_back(
+ this->GetInstallationType(project.ProjectName, installType));
+ }
+ }
+
+ // Determine the set of components that will be used in this project
+ std::string componentsVar =
+ "CPACK_COMPONENTS_" + cmSystemTools::UpperCase(project.Component);
+ const char* components = this->GetOption(componentsVar);
+ if (cmNonempty(components)) {
+ cmExpandList(components, componentsVector);
+ for (std::string const& comp : componentsVector) {
+ project.Components.push_back(
+ this->GetComponent(project.ProjectName, comp));
+ }
+ componentInstall = true;
+ }
+ }
+ if (componentsVector.empty()) {
+ componentsVector.push_back(project.Component);
+ }
+
+ std::vector<std::string> buildConfigs;
+
+ // Try get configuration names given via `-C` CLI option
+ {
+ const char* const buildConfigCstr =
+ this->GetOption("CPACK_BUILD_CONFIG");
+ auto buildConfig = buildConfigCstr ? buildConfigCstr : std::string{};
+ cmExpandList(buildConfig, buildConfigs);
+ }
+
+ // Remove duplicates
+ std::sort(buildConfigs.begin(), buildConfigs.end());
+ buildConfigs.erase(std::unique(buildConfigs.begin(), buildConfigs.end()),
+ buildConfigs.end());
+
+ // Ensure we have at least one configuration.
+ if (buildConfigs.empty()) {
+ buildConfigs.emplace_back();
+ }
+
+ std::unique_ptr<cmGlobalGenerator> globalGenerator =
+ this->MakefileMap->GetCMakeInstance()->CreateGlobalGenerator(
+ cmakeGenerator);
+ if (!globalGenerator) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Specified package generator not found. "
+ "CPACK_CMAKE_GENERATOR value is invalid."
+ << std::endl);
+ return 0;
+ }
+ // set the global flag for unix style paths on cmSystemTools as
+ // soon as the generator is set. This allows gmake to be used
+ // on windows.
+ cmSystemTools::SetForceUnixPaths(globalGenerator->GetForceUnixPaths());
+
+ // Run the installation for the selected build configurations
+ for (auto const& buildConfig : buildConfigs) {
+ if (!this->RunPreinstallTarget(project.ProjectName, project.Directory,
+ globalGenerator.get(), buildConfig)) {
+ return 0;
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Install project: " << project.ProjectName << " ["
+ << buildConfig << ']'
+ << std::endl);
+ // Run the installation for each component
+ for (std::string const& component : componentsVector) {
+ if (!this->InstallCMakeProject(
+ setDestDir, project.Directory, baseTempInstallDirectory,
+ default_dir_mode, component, componentInstall,
+ project.SubDirectory, buildConfig, absoluteDestFiles)) {
+ return 0;
+ }
+ }
+ }
+
+ this->CMakeProjects.emplace_back(std::move(project));
+ }
+ }
+ this->SetOption("CPACK_ABSOLUTE_DESTINATION_FILES",
+ absoluteDestFiles.c_str());
+ return 1;
+}
+
+int cmCPackGenerator::RunPreinstallTarget(
+ const std::string& installProjectName, const std::string& installDirectory,
+ cmGlobalGenerator* globalGenerator, const std::string& buildConfig)
+{
+ // Does this generator require pre-install?
+ if (const char* preinstall = globalGenerator->GetPreinstallTargetName()) {
+ std::string buildCommand = globalGenerator->GenerateCMakeBuildCommand(
+ preinstall, buildConfig, "", false);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Install command: " << buildCommand << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Run preinstall target for: " << installProjectName
+ << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool resB = cmSystemTools::RunSingleCommand(
+ buildCommand, &output, &output, &retVal, installDirectory.c_str(),
+ this->GeneratorVerbose, cmDuration::zero());
+ if (!resB || retVal) {
+ std::string tmpFile = cmStrCat(
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/PreinstallOutput.log");
+ cmGeneratedFileStream ofs(tmpFile);
+ ofs << "# Run command: " << buildCommand << std::endl
+ << "# Directory: " << installDirectory << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem running install command: "
+ << buildCommand << std::endl
+ << "Please check " << tmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int cmCPackGenerator::InstallCMakeProject(
+ bool setDestDir, const std::string& installDirectory,
+ const std::string& baseTempInstallDirectory, const mode_t* default_dir_mode,
+ const std::string& component, bool componentInstall,
+ const std::string& installSubDirectory, const std::string& buildConfig,
+ std::string& absoluteDestFiles)
+{
+ std::string tempInstallDirectory = baseTempInstallDirectory;
+ std::string installFile = installDirectory + "/cmake_install.cmake";
+
+ if (componentInstall) {
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Install component: " << component << std::endl);
+ }
+
+ cmake cm(cmake::RoleScript, cmState::CPack);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cm.AddCMakePaths();
+ cm.SetProgressCallback([this](const std::string& msg, float prog) {
+ this->DisplayVerboseOutput(msg, prog);
+ });
+ cm.SetTrace(this->Trace);
+ cm.SetTraceExpand(this->TraceExpand);
+ cmGlobalGenerator gg(&cm);
+ cmMakefile mf(&gg, cm.GetCurrentSnapshot());
+ if (!installSubDirectory.empty() && installSubDirectory != "/" &&
+ installSubDirectory != ".") {
+ tempInstallDirectory += installSubDirectory;
+ }
+ if (componentInstall) {
+ tempInstallDirectory += "/";
+ // Some CPack generators would rather chose
+ // the local installation directory suffix.
+ // Some (e.g. RPM) use
+ // one install directory for each component **GROUP**
+ // instead of the default
+ // one install directory for each component.
+ tempInstallDirectory += this->GetComponentInstallDirNameSuffix(component);
+ if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
+ tempInstallDirectory += "/";
+ tempInstallDirectory += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ }
+ }
+
+ const char* default_dir_inst_permissions =
+ this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
+ if (cmNonempty(default_dir_inst_permissions)) {
+ mf.AddDefinition("CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS",
+ default_dir_inst_permissions);
+ }
+
+ if (!setDestDir) {
+ tempInstallDirectory += this->GetPackagingInstallPrefix();
+ }
+
+ if (setDestDir) {
+ // For DESTDIR based packaging, use the *project*
+ // CMAKE_INSTALL_PREFIX underneath the tempInstallDirectory. The
+ // value of the project's CMAKE_INSTALL_PREFIX is sent in here as
+ // the value of the CPACK_INSTALL_PREFIX variable.
+ //
+ // If DESTDIR has been 'internally set ON' this means that
+ // the underlying CPack specific generator did ask for that
+ // In this case we may override CPACK_INSTALL_PREFIX with
+ // CPACK_PACKAGING_INSTALL_PREFIX
+ // I know this is tricky and awkward but it's the price for
+ // CPACK_SET_DESTDIR backward compatibility.
+ if (cmIsInternallyOn(this->GetOption("CPACK_SET_DESTDIR"))) {
+ this->SetOption("CPACK_INSTALL_PREFIX",
+ this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX"));
+ }
+ std::string dir;
+ if (this->GetOption("CPACK_INSTALL_PREFIX")) {
+ dir += this->GetOption("CPACK_INSTALL_PREFIX");
+ }
+ mf.AddDefinition("CMAKE_INSTALL_PREFIX", dir);
+
+ cmCPackLogger(
+ cmCPackLog::LOG_DEBUG,
+ "- Using DESTDIR + CPACK_INSTALL_PREFIX... (mf.AddDefinition)"
+ << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Setting CMAKE_INSTALL_PREFIX to '" << dir << "'"
+ << std::endl);
+
+ // Make sure that DESTDIR + CPACK_INSTALL_PREFIX directory
+ // exists:
+ //
+ if (cmHasLiteralPrefix(dir, "/")) {
+ dir = tempInstallDirectory + dir;
+ } else {
+ dir = tempInstallDirectory + "/" + dir;
+ }
+ /*
+ * We must re-set DESTDIR for each component
+ * We must not add the CPACK_INSTALL_PREFIX part because
+ * it will be added using the override of CMAKE_INSTALL_PREFIX
+ * The main reason for this awkward trick is that
+ * are using DESTDIR for 2 different reasons:
+ * - Because it was asked by the CPack Generator or the user
+ * using CPACK_SET_DESTDIR
+ * - Because it was already used for component install
+ * in order to put things in subdirs...
+ */
+ cmSystemTools::PutEnv("DESTDIR=" + tempInstallDirectory);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Creating directory: '" << dir << "'" << std::endl);
+
+ if (!cmsys::SystemTools::MakeDirectory(dir, default_dir_mode)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating temporary directory: " << dir
+ << std::endl);
+ return 0;
+ }
+ } else {
+ mf.AddDefinition("CMAKE_INSTALL_PREFIX", tempInstallDirectory);
+
+ if (!cmsys::SystemTools::MakeDirectory(tempInstallDirectory,
+ default_dir_mode)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating temporary directory: "
+ << tempInstallDirectory << std::endl);
+ return 0;
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Using non-DESTDIR install... (mf.AddDefinition)"
+ << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "- Setting CMAKE_INSTALL_PREFIX to '" << tempInstallDirectory
+ << "'" << std::endl);
+ }
+
+ if (!buildConfig.empty()) {
+ mf.AddDefinition("BUILD_TYPE", buildConfig);
+ }
+ std::string installComponentLowerCase = cmSystemTools::LowerCase(component);
+ if (installComponentLowerCase != "all") {
+ mf.AddDefinition("CMAKE_INSTALL_COMPONENT", component);
+ }
+
+ // strip on TRUE, ON, 1, one or several file names, but not on
+ // FALSE, OFF, 0 and an empty string
+ if (!cmIsOff(this->GetOption("CPACK_STRIP_FILES"))) {
+ mf.AddDefinition("CMAKE_INSTALL_DO_STRIP", "1");
+ }
+ // Remember the list of files before installation
+ // of the current component (if we are in component install)
+ std::string const& InstallPrefix = tempInstallDirectory;
+ std::vector<std::string> filesBefore;
+ std::string findExpr = tempInstallDirectory;
+ if (componentInstall) {
+ cmsys::Glob glB;
+ findExpr += "/*";
+ glB.RecurseOn();
+ glB.SetRecurseListDirs(true);
+ glB.SetRecurseThroughSymlinks(false);
+ glB.FindFiles(findExpr);
+ filesBefore = glB.GetFiles();
+ std::sort(filesBefore.begin(), filesBefore.end());
+ }
+
+ // If CPack was asked to warn on ABSOLUTE INSTALL DESTINATION
+ // then forward request to cmake_install.cmake script
+ if (this->IsOn("CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION")) {
+ mf.AddDefinition("CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION", "1");
+ }
+ // If current CPack generator does support
+ // ABSOLUTE INSTALL DESTINATION or CPack has been asked for
+ // then ask cmake_install.cmake script to error out
+ // as soon as it occurs (before installing file)
+ if (!this->SupportsAbsoluteDestination() ||
+ this->IsOn("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION")) {
+ mf.AddDefinition("CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION", "1");
+ }
+ // do installation
+ bool res = mf.ReadListFile(installFile);
+ // forward definition of CMAKE_ABSOLUTE_DESTINATION_FILES
+ // to CPack (may be used by generators like CPack RPM or DEB)
+ // in order to transparently handle ABSOLUTE PATH
+ if (cmProp def = mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES")) {
+ mf.AddDefinition("CPACK_ABSOLUTE_DESTINATION_FILES", *def);
+ }
+
+ // Now rebuild the list of files after installation
+ // of the current component (if we are in component install)
+ if (componentInstall) {
+ cmsys::Glob glA;
+ glA.RecurseOn();
+ glA.SetRecurseListDirs(true);
+ glA.SetRecurseThroughSymlinks(false);
+ glA.FindFiles(findExpr);
+ std::vector<std::string> filesAfter = glA.GetFiles();
+ std::sort(filesAfter.begin(), filesAfter.end());
+ std::vector<std::string>::iterator diff;
+ std::vector<std::string> result(filesAfter.size());
+ diff = std::set_difference(filesAfter.begin(), filesAfter.end(),
+ filesBefore.begin(), filesBefore.end(),
+ result.begin());
+
+ std::vector<std::string>::iterator fit;
+ std::string localFileName;
+ // Populate the File field of each component
+ for (fit = result.begin(); fit != diff; ++fit) {
+ localFileName = cmSystemTools::RelativePath(InstallPrefix, *fit);
+ localFileName =
+ localFileName.substr(localFileName.find_first_not_of('/'));
+ this->Components[component].Files.push_back(localFileName);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Adding file <" << localFileName << "> to component <"
+ << component << ">" << std::endl);
+ }
+ }
+
+ if (cmProp d = mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")) {
+ if (!absoluteDestFiles.empty()) {
+ absoluteDestFiles += ";";
+ }
+ absoluteDestFiles += *d;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Got some ABSOLUTE DESTINATION FILES: " << absoluteDestFiles
+ << std::endl);
+ // define component specific var
+ if (componentInstall) {
+ std::string absoluteDestFileComponent =
+ std::string("CPACK_ABSOLUTE_DESTINATION_FILES") + "_" +
+ this->GetComponentInstallDirNameSuffix(component);
+ if (nullptr != this->GetOption(absoluteDestFileComponent)) {
+ std::string absoluteDestFilesListComponent =
+ cmStrCat(this->GetOption(absoluteDestFileComponent), ';', *d);
+ this->SetOption(absoluteDestFileComponent,
+ absoluteDestFilesListComponent.c_str());
+ } else {
+ this->SetOption(
+ absoluteDestFileComponent,
+ cmToCStr(mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")));
+ }
+ }
+ }
+ if (cmSystemTools::GetErrorOccuredFlag() || !res) {
+ return 0;
+ }
+ return 1;
+}
+
+bool cmCPackGenerator::ReadListFile(const char* moduleName)
+{
+ bool retval;
+ std::string fullPath = this->MakefileMap->GetModulesFile(moduleName);
+ retval = this->MakefileMap->ReadListFile(fullPath);
+ // include FATAL_ERROR and ERROR in the return status
+ retval = retval && (!cmSystemTools::GetErrorOccuredFlag());
+ return retval;
+}
+
+void cmCPackGenerator::SetOptionIfNotSet(const std::string& op,
+ const char* value)
+{
+ cmProp def = this->MakefileMap->GetDefinition(op);
+ if (cmNonempty(def)) {
+ return;
+ }
+ this->SetOption(op, value);
+}
+
+void cmCPackGenerator::SetOption(const std::string& op, const char* value)
+{
+ if (!value) {
+ this->MakefileMap->RemoveDefinition(op);
+ return;
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ this->GetNameOfClass() << "::SetOption(" << op << ", " << value
+ << ")" << std::endl);
+ this->MakefileMap->AddDefinition(op, value);
+}
+
+int cmCPackGenerator::DoPackage()
+{
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "Create package using " << this->Name << std::endl);
+
+ // Prepare CPack internal name and check
+ // values for many CPACK_xxx vars
+ if (!this->PrepareNames()) {
+ return 0;
+ }
+
+ // Digest Component grouping specification
+ if (!this->PrepareGroupingKind()) {
+ return 0;
+ }
+
+ if (cmIsOn(this->GetOption("CPACK_REMOVE_TOPLEVEL_DIRECTORY"))) {
+ const char* toplevelDirectory =
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ if (cmSystemTools::FileExists(toplevelDirectory)) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Remove toplevel directory: " << toplevelDirectory
+ << std::endl);
+ if (!cmSystemTools::RepeatedRemoveDirectory(toplevelDirectory)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem removing toplevel directory: "
+ << toplevelDirectory << std::endl);
+ return 0;
+ }
+ }
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "About to install project " << std::endl);
+
+ if (!this->InstallProject()) {
+ return 0;
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Done install project " << std::endl);
+
+ const char* tempPackageFileName =
+ this->GetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME");
+ const char* tempDirectory = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Find files" << std::endl);
+ cmsys::Glob gl;
+ std::string findExpr = cmStrCat(tempDirectory, "/*");
+ gl.RecurseOn();
+ gl.SetRecurseListDirs(true);
+ gl.SetRecurseThroughSymlinks(false);
+ if (!gl.FindFiles(findExpr)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find any files in the packaging tree" << std::endl);
+ return 0;
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Create package" << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Package files to: "
+ << (tempPackageFileName ? tempPackageFileName : "(NULL)")
+ << std::endl);
+ if (cmSystemTools::FileExists(tempPackageFileName)) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Remove old package file" << std::endl);
+ cmSystemTools::RemoveFile(tempPackageFileName);
+ }
+ if (cmIsOn(this->GetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY"))) {
+ tempDirectory = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ }
+
+ // The files to be installed
+ this->files = gl.GetFiles();
+
+ this->packageFileNames.clear();
+ /* Put at least one file name into the list of
+ * wanted packageFileNames. The specific generator
+ * may update this during PackageFiles.
+ * (either putting several names or updating the provided one)
+ */
+ this->packageFileNames.emplace_back(tempPackageFileName ? tempPackageFileName
+ : "");
+ this->toplevel = tempDirectory;
+ { // scope that enables package generators to run internal scripts with
+ // latest CMake policies enabled
+ cmMakefile::ScopePushPop pp{ this->MakefileMap };
+ this->MakefileMap->SetPolicyVersion(cmVersion::GetCMakeVersion(),
+ std::string());
+
+ if (!this->PackageFiles() || cmSystemTools::GetErrorOccuredFlag()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem compressing the directory" << std::endl);
+ return 0;
+ }
+ }
+ // Run post-build actions
+ const char* postBuildScripts = this->GetOption("CPACK_POST_BUILD_SCRIPTS");
+ if (postBuildScripts) {
+ this->MakefileMap->AddDefinition("CPACK_PACKAGE_FILES",
+ cmJoin(this->packageFileNames, ";"));
+
+ const auto scripts = cmExpandedList(postBuildScripts, false);
+ for (const auto& script : scripts) {
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "Executing post-build script: " << script << std::endl);
+
+ if (!this->MakefileMap->ReadListFile(script)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "The post-build script not found: " << script
+ << std::endl);
+ return 0;
+ }
+ }
+ }
+
+ /* Prepare checksum algorithm*/
+ const char* algo = this->GetOption("CPACK_PACKAGE_CHECKSUM");
+ std::unique_ptr<cmCryptoHash> crypto = cmCryptoHash::New(algo ? algo : "");
+
+ /*
+ * Copy the generated packages to final destination
+ * - there may be several of them
+ * - the initially provided name may have changed
+ * (because the specific generator did 'normalize' it)
+ */
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Copying final package(s) [" << this->packageFileNames.size()
+ << "]:" << std::endl);
+ /* now copy package one by one */
+ for (std::string const& pkgFileName : this->packageFileNames) {
+ std::string tmpPF(this->GetOption("CPACK_OUTPUT_FILE_PREFIX"));
+ std::string filename(cmSystemTools::GetFilenameName(pkgFileName));
+ tempPackageFileName = pkgFileName.c_str();
+ tmpPF += "/" + filename;
+ const char* packageFileName = tmpPF.c_str();
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Copy final package(s): "
+ << (tempPackageFileName ? tempPackageFileName : "(NULL)")
+ << " to " << (packageFileName ? packageFileName : "(NULL)")
+ << std::endl);
+ if (!cmSystemTools::CopyFileIfDifferent(pkgFileName, tmpPF)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Problem copying the package: "
+ << (tempPackageFileName ? tempPackageFileName : "(NULL)") << " to "
+ << (packageFileName ? packageFileName : "(NULL)") << std::endl);
+ return 0;
+ }
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- package: " << packageFileName << " generated."
+ << std::endl);
+
+ /* Generate checksum file */
+ if (crypto) {
+ std::string hashFile(this->GetOption("CPACK_OUTPUT_FILE_PREFIX"));
+ hashFile += "/" + filename;
+ hashFile += "." + cmSystemTools::LowerCase(algo);
+ cmsys::ofstream outF(hashFile.c_str());
+ if (!outF) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot create checksum file: " << hashFile
+ << std::endl);
+ return 0;
+ }
+ outF << crypto->HashFile(packageFileName) << " " << filename << "\n";
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- checksum file: " << hashFile << " generated."
+ << std::endl);
+ }
+ }
+
+ return 1;
+}
+
+int cmCPackGenerator::Initialize(const std::string& name, cmMakefile* mf)
+{
+ this->MakefileMap = mf;
+ this->Name = name;
+ // set the running generator name
+ this->SetOption("CPACK_GENERATOR", this->Name.c_str());
+ // Load the project specific config file
+ const char* config = this->GetOption("CPACK_PROJECT_CONFIG_FILE");
+ if (config) {
+ mf->ReadListFile(config);
+ }
+ int result = this->InitializeInternal();
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return 0;
+ }
+
+ // If a generator subclass did not already set this option in its
+ // InitializeInternal implementation, and the project did not already set
+ // it, the default value should be:
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/");
+
+ return result;
+}
+
+int cmCPackGenerator::InitializeInternal()
+{
+ return 1;
+}
+
+bool cmCPackGenerator::IsSet(const std::string& name) const
+{
+ return this->MakefileMap->IsSet(name);
+}
+
+bool cmCPackGenerator::IsOn(const std::string& name) const
+{
+ return cmIsOn(this->GetOption(name));
+}
+
+bool cmCPackGenerator::IsSetToOff(const std::string& op) const
+{
+ cmProp ret = this->MakefileMap->GetDefinition(op);
+ if (cmNonempty(ret)) {
+ return cmIsOff(*ret);
+ }
+ return false;
+}
+
+bool cmCPackGenerator::IsSetToEmpty(const std::string& op) const
+{
+ cmProp ret = this->MakefileMap->GetDefinition(op);
+ if (ret) {
+ return ret->empty();
+ }
+ return false;
+}
+
+const char* cmCPackGenerator::GetOption(const std::string& op) const
+{
+ cmProp ret = this->MakefileMap->GetDefinition(op);
+ if (!ret) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Warning, GetOption return NULL for: " << op << std::endl);
+ return nullptr;
+ }
+ return ret->c_str();
+}
+
+std::vector<std::string> cmCPackGenerator::GetOptions() const
+{
+ return this->MakefileMap->GetDefinitions();
+}
+
+int cmCPackGenerator::PackageFiles()
+{
+ return 0;
+}
+
+const char* cmCPackGenerator::GetInstallPath()
+{
+ if (!this->InstallPath.empty()) {
+ return this->InstallPath.c_str();
+ }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ std::string prgfiles;
+ std::string sysDrive;
+ if (cmsys::SystemTools::GetEnv("ProgramFiles", prgfiles)) {
+ this->InstallPath = prgfiles;
+ } else if (cmsys::SystemTools::GetEnv("SystemDrive", sysDrive)) {
+ this->InstallPath = cmStrCat(sysDrive, "/Program Files");
+ } else {
+ this->InstallPath = "c:/Program Files";
+ }
+ this->InstallPath += "/";
+ this->InstallPath += this->GetOption("CPACK_PACKAGE_NAME");
+ this->InstallPath += "-";
+ this->InstallPath += this->GetOption("CPACK_PACKAGE_VERSION");
+#elif defined(__HAIKU__)
+ char dir[B_PATH_NAME_LENGTH];
+ if (find_directory(B_SYSTEM_DIRECTORY, -1, false, dir, sizeof(dir)) ==
+ B_OK) {
+ this->InstallPath = dir;
+ } else {
+ this->InstallPath = "/boot/system";
+ }
+#else
+ this->InstallPath = "/usr/local/";
+#endif
+ return this->InstallPath.c_str();
+}
+
+const char* cmCPackGenerator::GetPackagingInstallPrefix()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "GetPackagingInstallPrefix: '"
+ << this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX") << "'"
+ << std::endl);
+
+ return this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
+}
+
+std::string cmCPackGenerator::FindTemplate(const char* name)
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Look for template: " << (name ? name : "(NULL)")
+ << std::endl);
+ // Search CMAKE_MODULE_PATH for a custom template.
+ std::string ffile = this->MakefileMap->GetModulesFile(name);
+ if (ffile.empty()) {
+ // Fall back to our internal builtin default.
+ ffile = cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/Internal/CPack/",
+ name);
+ cmSystemTools::ConvertToUnixSlashes(ffile);
+ if (!cmSystemTools::FileExists(ffile)) {
+ ffile.clear();
+ }
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Found template: " << ffile << std::endl);
+ return ffile;
+}
+
+bool cmCPackGenerator::ConfigureString(const std::string& inString,
+ std::string& outString)
+{
+ this->MakefileMap->ConfigureString(inString, outString, true, false);
+ return true;
+}
+
+bool cmCPackGenerator::ConfigureFile(const std::string& inName,
+ const std::string& outName,
+ bool copyOnly /* = false */)
+{
+ return this->MakefileMap->ConfigureFile(inName, outName, copyOnly, true,
+ false) == 1;
+}
+
+int cmCPackGenerator::CleanTemporaryDirectory()
+{
+ std::string tempInstallDirectory =
+ this->GetOption("CPACK_TEMPORARY_INSTALL_DIRECTORY");
+ if (cmsys::SystemTools::FileExists(tempInstallDirectory)) {
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Clean temporary : " << tempInstallDirectory << std::endl);
+ if (!cmSystemTools::RepeatedRemoveDirectory(tempInstallDirectory)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem removing temporary directory: "
+ << tempInstallDirectory << std::endl);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+cmInstalledFile const* cmCPackGenerator::GetInstalledFile(
+ std::string const& name) const
+{
+ cmake const* cm = this->MakefileMap->GetCMakeInstance();
+ return cm->GetInstalledFile(name);
+}
+
+int cmCPackGenerator::PrepareGroupingKind()
+{
+ // find a component package method specified by the user
+ ComponentPackageMethod method = UNKNOWN_COMPONENT_PACKAGE_METHOD;
+
+ if (this->GetOption("CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE")) {
+ method = ONE_PACKAGE;
+ }
+
+ if (this->GetOption("CPACK_COMPONENTS_IGNORE_GROUPS")) {
+ method = ONE_PACKAGE_PER_COMPONENT;
+ }
+
+ if (this->GetOption("CPACK_COMPONENTS_ONE_PACKAGE_PER_GROUP")) {
+ method = ONE_PACKAGE_PER_GROUP;
+ }
+
+ std::string groupingType;
+
+ // Second way to specify grouping
+ if (nullptr != this->GetOption("CPACK_COMPONENTS_GROUPING")) {
+ groupingType = this->GetOption("CPACK_COMPONENTS_GROUPING");
+ }
+
+ if (!groupingType.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "[" << this->Name << "]"
+ << " requested component grouping = " << groupingType
+ << std::endl);
+ if (groupingType == "ALL_COMPONENTS_IN_ONE") {
+ method = ONE_PACKAGE;
+ } else if (groupingType == "IGNORE") {
+ method = ONE_PACKAGE_PER_COMPONENT;
+ } else if (groupingType == "ONE_PER_GROUP") {
+ method = ONE_PACKAGE_PER_GROUP;
+ } else {
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING,
+ "[" << this->Name << "]"
+ << " requested component grouping type <" << groupingType
+ << "> UNKNOWN not in (ALL_COMPONENTS_IN_ONE,IGNORE,ONE_PER_GROUP)"
+ << std::endl);
+ }
+ }
+
+ // Some components were defined but NO group
+ // fallback to default if not group based
+ if (method == ONE_PACKAGE_PER_GROUP && this->ComponentGroups.empty() &&
+ !this->Components.empty()) {
+ if (this->componentPackageMethod == ONE_PACKAGE) {
+ method = ONE_PACKAGE;
+ } else {
+ method = ONE_PACKAGE_PER_COMPONENT;
+ }
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING,
+ "[" << this->Name << "]"
+ << " One package per component group requested, "
+ << "but NO component groups exist: Ignoring component group."
+ << std::endl);
+ }
+
+ // if user specified packaging method, override the default packaging
+ // method
+ if (method != UNKNOWN_COMPONENT_PACKAGE_METHOD) {
+ this->componentPackageMethod = method;
+ }
+
+ const char* method_names[] = { "ALL_COMPONENTS_IN_ONE", "IGNORE_GROUPS",
+ "ONE_PER_GROUP" };
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "[" << this->Name << "]"
+ << " requested component grouping = "
+ << method_names[this->componentPackageMethod]
+ << std::endl);
+
+ return 1;
+}
+
+std::string cmCPackGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ return componentName;
+}
+std::string cmCPackGenerator::GetComponentPackageFileName(
+ const std::string& initialPackageFileName,
+ const std::string& groupOrComponentName, bool isGroupName)
+{
+
+ /*
+ * the default behavior is to use the
+ * component [group] name as a suffix
+ */
+ std::string suffix = "-" + groupOrComponentName;
+ /* check if we should use DISPLAY name */
+ std::string dispNameVar =
+ "CPACK_" + this->Name + "_USE_DISPLAY_NAME_IN_FILENAME";
+ if (this->IsOn(dispNameVar)) {
+ /* the component Group case */
+ if (isGroupName) {
+ std::string groupDispVar = "CPACK_COMPONENT_GROUP_" +
+ cmSystemTools::UpperCase(groupOrComponentName) + "_DISPLAY_NAME";
+ const char* groupDispName = this->GetOption(groupDispVar);
+ if (groupDispName) {
+ suffix = "-" + std::string(groupDispName);
+ }
+ }
+ /* the [single] component case */
+ else {
+ std::string dispVar = "CPACK_COMPONENT_" +
+ cmSystemTools::UpperCase(groupOrComponentName) + "_DISPLAY_NAME";
+ const char* dispName = this->GetOption(dispVar);
+ if (dispName) {
+ suffix = "-" + std::string(dispName);
+ }
+ }
+ }
+ return initialPackageFileName + suffix;
+}
+
+enum cmCPackGenerator::CPackSetDestdirSupport
+cmCPackGenerator::SupportsSetDestdir() const
+{
+ return cmCPackGenerator::SETDESTDIR_SUPPORTED;
+}
+
+bool cmCPackGenerator::SupportsAbsoluteDestination() const
+{
+ return true;
+}
+
+bool cmCPackGenerator::SupportsComponentInstallation() const
+{
+ return false;
+}
+
+bool cmCPackGenerator::WantsComponentInstallation() const
+{
+ return (!this->IsOn("CPACK_MONOLITHIC_INSTALL") &&
+ this->SupportsComponentInstallation()
+ // check that we have at least one group or component
+ && (!this->ComponentGroups.empty() || !this->Components.empty()));
+}
+
+cmCPackInstallationType* cmCPackGenerator::GetInstallationType(
+ const std::string& projectName, const std::string& name)
+{
+ (void)projectName;
+ bool hasInstallationType = this->InstallationTypes.count(name) != 0;
+ cmCPackInstallationType* installType = &this->InstallationTypes[name];
+ if (!hasInstallationType) {
+ // Define the installation type
+ std::string macroPrefix =
+ "CPACK_INSTALL_TYPE_" + cmsys::SystemTools::UpperCase(name);
+ installType->Name = name;
+
+ const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
+ if (cmNonempty(displayName)) {
+ installType->DisplayName = displayName;
+ } else {
+ installType->DisplayName = installType->Name;
+ }
+
+ installType->Index = static_cast<unsigned>(this->InstallationTypes.size());
+ }
+ return installType;
+}
+
+cmCPackComponent* cmCPackGenerator::GetComponent(
+ const std::string& projectName, const std::string& name)
+{
+ bool hasComponent = this->Components.count(name) != 0;
+ cmCPackComponent* component = &this->Components[name];
+ if (!hasComponent) {
+ // Define the component
+ std::string macroPrefix =
+ "CPACK_COMPONENT_" + cmsys::SystemTools::UpperCase(name);
+ component->Name = name;
+ const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
+ if (cmNonempty(displayName)) {
+ component->DisplayName = displayName;
+ } else {
+ component->DisplayName = component->Name;
+ }
+ component->IsHidden = this->IsOn(macroPrefix + "_HIDDEN");
+ component->IsRequired = this->IsOn(macroPrefix + "_REQUIRED");
+ component->IsDisabledByDefault = this->IsOn(macroPrefix + "_DISABLED");
+ component->IsDownloaded = this->IsOn(macroPrefix + "_DOWNLOADED") ||
+ cmIsOn(this->GetOption("CPACK_DOWNLOAD_ALL"));
+
+ const char* archiveFile = this->GetOption(macroPrefix + "_ARCHIVE_FILE");
+ if (cmNonempty(archiveFile)) {
+ component->ArchiveFile = archiveFile;
+ }
+
+ const char* plist = this->GetOption(macroPrefix + "_PLIST");
+ if (cmNonempty(plist)) {
+ component->Plist = plist;
+ }
+
+ const char* groupName = this->GetOption(macroPrefix + "_GROUP");
+ if (cmNonempty(groupName)) {
+ component->Group = this->GetComponentGroup(projectName, groupName);
+ component->Group->Components.push_back(component);
+ } else {
+ component->Group = nullptr;
+ }
+
+ const char* description = this->GetOption(macroPrefix + "_DESCRIPTION");
+ if (cmNonempty(description)) {
+ component->Description = description;
+ }
+
+ // Determine the installation types.
+ const char* installTypes = this->GetOption(macroPrefix + "_INSTALL_TYPES");
+ if (cmNonempty(installTypes)) {
+ std::vector<std::string> installTypesVector =
+ cmExpandedList(installTypes);
+ for (std::string const& installType : installTypesVector) {
+ component->InstallationTypes.push_back(
+ this->GetInstallationType(projectName, installType));
+ }
+ }
+
+ // Determine the component dependencies.
+ const char* depends = this->GetOption(macroPrefix + "_DEPENDS");
+ if (cmNonempty(depends)) {
+ std::vector<std::string> dependsVector = cmExpandedList(depends);
+ for (std::string const& depend : dependsVector) {
+ cmCPackComponent* child = this->GetComponent(projectName, depend);
+ component->Dependencies.push_back(child);
+ child->ReverseDependencies.push_back(component);
+ }
+ }
+ }
+ return component;
+}
+
+cmCPackComponentGroup* cmCPackGenerator::GetComponentGroup(
+ const std::string& projectName, const std::string& name)
+{
+ (void)projectName;
+ std::string macroPrefix =
+ "CPACK_COMPONENT_GROUP_" + cmsys::SystemTools::UpperCase(name);
+ bool hasGroup = this->ComponentGroups.count(name) != 0;
+ cmCPackComponentGroup* group = &this->ComponentGroups[name];
+ if (!hasGroup) {
+ // Define the group
+ group->Name = name;
+ const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
+ if (cmNonempty(displayName)) {
+ group->DisplayName = displayName;
+ } else {
+ group->DisplayName = group->Name;
+ }
+
+ const char* description = this->GetOption(macroPrefix + "_DESCRIPTION");
+ if (cmNonempty(description)) {
+ group->Description = description;
+ }
+ group->IsBold = this->IsOn(macroPrefix + "_BOLD_TITLE");
+ group->IsExpandedByDefault = this->IsOn(macroPrefix + "_EXPANDED");
+ const char* parentGroupName =
+ this->GetOption(macroPrefix + "_PARENT_GROUP");
+ if (cmNonempty(parentGroupName)) {
+ group->ParentGroup =
+ this->GetComponentGroup(projectName, parentGroupName);
+ group->ParentGroup->Subgroups.push_back(group);
+ } else {
+ group->ParentGroup = nullptr;
+ }
+ }
+ return group;
+}
diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h
new file mode 100644
index 0000000..2512d42
--- /dev/null
+++ b/Source/CPack/cmCPackGenerator.h
@@ -0,0 +1,340 @@
+/* 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 <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "cm_sys_stat.h"
+
+#include "cmCPackComponentGroup.h"
+#include "cmSystemTools.h"
+
+class cmCPackLog;
+class cmGlobalGenerator;
+class cmInstalledFile;
+class cmMakefile;
+
+/** \class cmCPackGenerator
+ * \brief A superclass of all CPack Generators
+ *
+ */
+class cmCPackGenerator
+{
+public:
+ virtual const char* GetNameOfClass() = 0;
+ /**
+ * If verbose then more information is printed out
+ */
+ void SetVerbose(bool val)
+ {
+ this->GeneratorVerbose =
+ val ? cmSystemTools::OUTPUT_MERGE : cmSystemTools::OUTPUT_NONE;
+ }
+
+ /**
+ * Put underlying cmake scripts in trace mode.
+ */
+ void SetTrace(bool val) { this->Trace = val; }
+
+ /**
+ * Put underlying cmake scripts in expanded trace mode.
+ */
+ void SetTraceExpand(bool val) { this->TraceExpand = val; }
+
+ /**
+ * Returns true if the generator may work on this system.
+ * Rational:
+ * Some CPack generator may run on some host and may not on others
+ * (with the same system) because some tools are missing. If the tool
+ * is missing then CPack won't activate (in the CPackGeneratorFactory)
+ * this particular generator.
+ */
+ static bool CanGenerate() { return true; }
+
+ /**
+ * Do the actual whole package processing.
+ * Subclass may redefine it but its usually enough
+ * to redefine @ref PackageFiles, because in fact
+ * this method do call:
+ * - PrepareName
+ * - clean-up temp dirs
+ * - InstallProject (with the appropriate method)
+ * - prepare list of files and/or components to be package
+ * - PackageFiles
+ * - Copy produced packages at the expected place
+ * @return 0 if error.
+ */
+ virtual int DoPackage();
+
+ /**
+ * Initialize generator
+ */
+ int Initialize(const std::string& name, cmMakefile* mf);
+
+ /**
+ * Construct generator
+ */
+ cmCPackGenerator();
+ virtual ~cmCPackGenerator();
+
+ //! Set and get the options
+ void SetOption(const std::string& op, const char* value);
+ void SetOptionIfNotSet(const std::string& op, const char* value);
+ const char* GetOption(const std::string& op) const;
+ std::vector<std::string> GetOptions() const;
+ bool IsSet(const std::string& name) const;
+ bool IsOn(const std::string& name) const;
+ bool IsSetToOff(const std::string& op) const;
+ bool IsSetToEmpty(const std::string& op) const;
+
+ //! Set the logger
+ void SetLogger(cmCPackLog* log) { this->Logger = log; }
+
+ //! Display verbose information via logger
+ void DisplayVerboseOutput(const std::string& msg, float progress);
+
+ bool ReadListFile(const char* moduleName);
+
+protected:
+ /**
+ * Prepare common used names by inspecting
+ * several CPACK_xxx var values.
+ */
+ int PrepareNames();
+
+ /**
+ * Install the project using appropriate method.
+ */
+ int InstallProject();
+
+ int CleanTemporaryDirectory();
+
+ cmInstalledFile const* GetInstalledFile(std::string const& name) const;
+
+ virtual const char* GetOutputExtension() { return ".cpack"; }
+ virtual const char* GetOutputPostfix() { return nullptr; }
+
+ /**
+ * Prepare requested grouping kind from CPACK_xxx vars
+ * CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE
+ * CPACK_COMPONENTS_IGNORE_GROUPS
+ * or
+ * CPACK_COMPONENTS_ONE_PACKAGE_PER_GROUP
+ * @return 1 on success 0 on failure.
+ */
+ virtual int PrepareGroupingKind();
+
+ /**
+ * Some CPack generators may prefer to have
+ * CPack install all components belonging to the same
+ * [component] group to be install in the same directory.
+ * The default behavior is to install each component in
+ * a separate directory.
+ * @param[in] componentName the name of the component to be installed
+ * @return the name suffix the generator wants for the specified component
+ * default is "componentName"
+ */
+ virtual std::string GetComponentInstallDirNameSuffix(
+ const std::string& componentName);
+
+ /**
+ * CPack specific generator may mangle CPACK_PACKAGE_FILE_NAME
+ * with CPACK_COMPONENT_xxxx_<NAME>_DISPLAY_NAME if
+ * CPACK_<GEN>_USE_DISPLAY_NAME_IN_FILENAME is ON.
+ * @param[in] initialPackageFileName the initial package name to be mangled
+ * @param[in] groupOrComponentName the name of the group/component
+ * @param[in] isGroupName true if previous name refers to a group,
+ * false otherwise
+ */
+ virtual std::string GetComponentPackageFileName(
+ const std::string& initialPackageFileName,
+ const std::string& groupOrComponentName, bool isGroupName);
+
+ /**
+ * Package the list of files and/or components which
+ * has been prepared by the beginning of DoPackage.
+ * @pre the @ref toplevel has been filled-in
+ * @pre the list of file @ref files has been populated
+ * @pre packageFileNames contains at least 1 entry
+ * @post packageFileNames may have been updated and contains
+ * the list of packages generated by the specific generator.
+ */
+ virtual int PackageFiles();
+ virtual const char* GetInstallPath();
+ virtual const char* GetPackagingInstallPrefix();
+
+ virtual std::string FindTemplate(const char* name);
+ virtual bool ConfigureFile(const std::string& inName,
+ const std::string& outName,
+ bool copyOnly = false);
+ virtual bool ConfigureString(const std::string& input, std::string& output);
+ virtual int InitializeInternal();
+
+ //! Run install commands if specified
+ virtual int InstallProjectViaInstallCommands(
+ bool setDestDir, const std::string& tempInstallDirectory);
+ virtual int InstallProjectViaInstallScript(
+ bool setDestDir, const std::string& tempInstallDirectory);
+ virtual int InstallProjectViaInstalledDirectories(
+ bool setDestDir, const std::string& tempInstallDirectory,
+ const mode_t* default_dir_mode);
+ virtual int InstallProjectViaInstallCMakeProjects(
+ bool setDestDir, const std::string& tempInstallDirectory,
+ const mode_t* default_dir_mode);
+
+ virtual int RunPreinstallTarget(const std::string& installProjectName,
+ const std::string& installDirectory,
+ cmGlobalGenerator* globalGenerator,
+ const std::string& buildConfig);
+ virtual int InstallCMakeProject(
+ bool setDestDir, const std::string& installDirectory,
+ const std::string& baseTempInstallDirectory,
+ const mode_t* default_dir_mode, const std::string& component,
+ bool componentInstall, const std::string& installSubDirectory,
+ const std::string& buildConfig, std::string& absoluteDestFiles);
+
+ /**
+ * The various level of support of
+ * CPACK_SET_DESTDIR used by the generator.
+ */
+ enum CPackSetDestdirSupport
+ {
+ /* the generator works with or without it */
+ SETDESTDIR_SUPPORTED,
+ /* the generator works best if automatically handled */
+ SETDESTDIR_INTERNALLY_SUPPORTED,
+ /* no official support, use at your own risk */
+ SETDESTDIR_SHOULD_NOT_BE_USED,
+ /* officially NOT supported */
+ SETDESTDIR_UNSUPPORTED
+ };
+
+ /**
+ * Does the CPack generator support CPACK_SET_DESTDIR?
+ * The default legacy value is 'SETDESTDIR_SUPPORTED' generator
+ * have to override it in order change this.
+ * @return CPackSetDestdirSupport
+ */
+ virtual enum CPackSetDestdirSupport SupportsSetDestdir() const;
+
+ /**
+ * Does the CPack generator support absolute path
+ * in INSTALL DESTINATION?
+ * The default legacy value is 'true' generator
+ * have to override it in order change this.
+ * @return true if supported false otherwise
+ */
+ virtual bool SupportsAbsoluteDestination() const;
+
+ /**
+ * Does the CPack generator support component installation?.
+ * Some Generators requires the user to set
+ * CPACK_<GENNAME>_COMPONENT_INSTALL in order to make this
+ * method return true.
+ * @return true if supported, false otherwise
+ */
+ virtual bool SupportsComponentInstallation() const;
+ /**
+ * Does the currently running generator want a component installation.
+ * The generator may support component installation but he may
+ * be requiring monolithic install using CPACK_MONOLITHIC_INSTALL.
+ * @return true if component installation is supported and wanted.
+ */
+ virtual bool WantsComponentInstallation() const;
+ virtual cmCPackInstallationType* GetInstallationType(
+ const std::string& projectName, const std::string& name);
+ virtual cmCPackComponent* GetComponent(const std::string& projectName,
+ const std::string& name);
+ virtual cmCPackComponentGroup* GetComponentGroup(
+ const std::string& projectName, const std::string& name);
+
+ cmSystemTools::OutputOption GeneratorVerbose;
+ std::string Name;
+
+ std::string InstallPath;
+
+ /**
+ * The list of package file names.
+ * At beginning of DoPackage the (generic) generator will populate
+ * the list of desired package file names then it will
+ * call the redefined method PackageFiles which is may
+ * either use this set of names (usually on entry there should be
+ * only a single name) or update the vector with the list
+ * of created package file names.
+ */
+ std::vector<std::string> packageFileNames;
+
+ /**
+ * The directory where all the files to be packaged reside.
+ * If the installer support components there will be one
+ * sub-directory for each component. In those directories
+ * one will find the file belonging to the specified component.
+ */
+ std::string toplevel;
+
+ /**
+ * The complete list of files to be packaged.
+ * This list will be populated by DoPackage before
+ * PackageFiles is called.
+ */
+ std::vector<std::string> files;
+
+ std::vector<cmCPackInstallCMakeProject> CMakeProjects;
+ std::map<std::string, cmCPackInstallationType> InstallationTypes;
+ /**
+ * The set of components.
+ * If component installation is supported then this map
+ * contains the component specified in CPACK_COMPONENTS_ALL
+ */
+ std::map<std::string, cmCPackComponent> Components;
+ std::map<std::string, cmCPackComponentGroup> ComponentGroups;
+
+ /**
+ * If components are enabled, this enum represents the different
+ * ways of mapping components to package files.
+ */
+ enum ComponentPackageMethod
+ {
+ /* one package for all components */
+ ONE_PACKAGE,
+ /* one package for each component */
+ ONE_PACKAGE_PER_COMPONENT,
+ /* one package for each group,
+ * with left over components in their own package */
+ ONE_PACKAGE_PER_GROUP,
+ UNKNOWN_COMPONENT_PACKAGE_METHOD
+ };
+
+ /**
+ * The component package method
+ * The default is ONE_PACKAGE_PER_GROUP,
+ * and generators may override the default
+ * before PrepareGroupingKind() is called.
+ */
+ ComponentPackageMethod componentPackageMethod;
+
+ cmCPackLog* Logger;
+ bool Trace;
+ bool TraceExpand;
+
+ cmMakefile* MakefileMap;
+};
+
+#define cmCPackTypeMacro(klass, superclass) \
+ using Superclass = superclass; \
+ const char* GetNameOfClass() override { return #klass; } \
+ static cmCPackGenerator* CreateGenerator() { return new klass; } \
+ class cmCPackTypeMacro_UseTrailingSemicolon
+
+#define cmCPackLogger(logType, msg) \
+ do { \
+ std::ostringstream cmCPackLog_msg; \
+ cmCPackLog_msg << msg; \
+ this->Logger->Log(logType, __FILE__, __LINE__, \
+ cmCPackLog_msg.str().c_str()); \
+ } while (false)
diff --git a/Source/CPack/cmCPackGeneratorFactory.cxx b/Source/CPack/cmCPackGeneratorFactory.cxx
new file mode 100644
index 0000000..79e344b
--- /dev/null
+++ b/Source/CPack/cmCPackGeneratorFactory.cxx
@@ -0,0 +1,166 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackGeneratorFactory.h"
+
+#include <ostream>
+#include <utility>
+
+#include "IFW/cmCPackIFWGenerator.h"
+#ifdef HAVE_FREEBSD_PKG
+# include "cmCPackFreeBSDGenerator.h"
+#endif
+#include "cmCPackArchiveGenerator.h"
+#include "cmCPackDebGenerator.h"
+#include "cmCPackExternalGenerator.h"
+#include "cmCPackGenerator.h"
+#include "cmCPackLog.h"
+#include "cmCPackNSISGenerator.h"
+#include "cmCPackNuGetGenerator.h"
+#include "cmCPackSTGZGenerator.h"
+
+#ifdef __APPLE__
+# include "cmCPackBundleGenerator.h"
+# include "cmCPackDragNDropGenerator.h"
+# include "cmCPackOSXX11Generator.h"
+# include "cmCPackPackageMakerGenerator.h"
+# include "cmCPackProductBuildGenerator.h"
+#endif
+
+#ifdef __CYGWIN__
+# include "cmCPackCygwinBinaryGenerator.h"
+# include "cmCPackCygwinSourceGenerator.h"
+#endif
+
+#if !defined(_WIN32) && !defined(__QNXNTO__) && !defined(__BEOS__) && \
+ !defined(__HAIKU__)
+# include "cmCPackRPMGenerator.h"
+#endif
+
+#if defined(_WIN32) || (defined(__CYGWIN__) && defined(HAVE_LIBUUID))
+# include "WiX/cmCPackWIXGenerator.h"
+#endif
+
+cmCPackGeneratorFactory::cmCPackGeneratorFactory()
+{
+ if (cmCPackArchiveGenerator::CanGenerate()) {
+ this->RegisterGenerator("7Z", "7-Zip file format",
+ cmCPackArchiveGenerator::Create7ZGenerator);
+ this->RegisterGenerator("TBZ2", "Tar BZip2 compression",
+ cmCPackArchiveGenerator::CreateTBZ2Generator);
+ this->RegisterGenerator("TGZ", "Tar GZip compression",
+ cmCPackArchiveGenerator::CreateTGZGenerator);
+ this->RegisterGenerator("TXZ", "Tar XZ compression",
+ cmCPackArchiveGenerator::CreateTXZGenerator);
+ this->RegisterGenerator("TZ", "Tar Compress compression",
+ cmCPackArchiveGenerator::CreateTZGenerator);
+ this->RegisterGenerator("TZST", "Tar Zstandard compression",
+ cmCPackArchiveGenerator::CreateTZSTGenerator);
+ this->RegisterGenerator("ZIP", "ZIP file format",
+ cmCPackArchiveGenerator::CreateZIPGenerator);
+ }
+ if (cmCPackSTGZGenerator::CanGenerate()) {
+ this->RegisterGenerator("STGZ", "Self extracting Tar GZip compression",
+ cmCPackSTGZGenerator::CreateGenerator);
+ }
+ if (cmCPackNSISGenerator::CanGenerate()) {
+ this->RegisterGenerator("NSIS", "Null Soft Installer",
+ cmCPackNSISGenerator::CreateGenerator);
+ this->RegisterGenerator("NSIS64", "Null Soft Installer (64-bit)",
+ cmCPackNSISGenerator::CreateGenerator64);
+ }
+ if (cmCPackIFWGenerator::CanGenerate()) {
+ this->RegisterGenerator("IFW", "Qt Installer Framework",
+ cmCPackIFWGenerator::CreateGenerator);
+ }
+#ifdef __CYGWIN__
+ if (cmCPackCygwinBinaryGenerator::CanGenerate()) {
+ this->RegisterGenerator("CygwinBinary", "Cygwin Binary Installer",
+ cmCPackCygwinBinaryGenerator::CreateGenerator);
+ }
+ if (cmCPackCygwinSourceGenerator::CanGenerate()) {
+ this->RegisterGenerator("CygwinSource", "Cygwin Source Installer",
+ cmCPackCygwinSourceGenerator::CreateGenerator);
+ }
+#endif
+#if defined(_WIN32) || (defined(__CYGWIN__) && defined(HAVE_LIBUUID))
+ if (cmCPackWIXGenerator::CanGenerate()) {
+ this->RegisterGenerator("WIX", "MSI file format via WiX tools",
+ cmCPackWIXGenerator::CreateGenerator);
+ }
+#endif
+ if (cmCPackDebGenerator::CanGenerate()) {
+ this->RegisterGenerator("DEB", "Debian packages",
+ cmCPackDebGenerator::CreateGenerator);
+ }
+ if (cmCPackNuGetGenerator::CanGenerate()) {
+ this->RegisterGenerator("NuGet", "NuGet packages",
+ cmCPackNuGetGenerator::CreateGenerator);
+ }
+ if (cmCPackExternalGenerator::CanGenerate()) {
+ this->RegisterGenerator("External", "CPack External packages",
+ cmCPackExternalGenerator::CreateGenerator);
+ }
+#ifdef __APPLE__
+ if (cmCPackDragNDropGenerator::CanGenerate()) {
+ this->RegisterGenerator("DragNDrop", "Mac OSX Drag And Drop",
+ cmCPackDragNDropGenerator::CreateGenerator);
+ }
+ if (cmCPackBundleGenerator::CanGenerate()) {
+ this->RegisterGenerator("Bundle", "Mac OSX bundle",
+ cmCPackBundleGenerator::CreateGenerator);
+ }
+ if (cmCPackPackageMakerGenerator::CanGenerate()) {
+ this->RegisterGenerator("PackageMaker", "Mac OSX Package Maker installer",
+ cmCPackPackageMakerGenerator::CreateGenerator);
+ }
+ if (cmCPackOSXX11Generator::CanGenerate()) {
+ this->RegisterGenerator("OSXX11", "Mac OSX X11 bundle",
+ cmCPackOSXX11Generator::CreateGenerator);
+ }
+ if (cmCPackProductBuildGenerator::CanGenerate()) {
+ this->RegisterGenerator("productbuild", "Mac OSX pkg",
+ cmCPackProductBuildGenerator::CreateGenerator);
+ }
+#endif
+#if !defined(_WIN32) && !defined(__QNXNTO__) && !defined(__BEOS__) && \
+ !defined(__HAIKU__)
+ if (cmCPackRPMGenerator::CanGenerate()) {
+ this->RegisterGenerator("RPM", "RPM packages",
+ cmCPackRPMGenerator::CreateGenerator);
+ }
+#endif
+#ifdef HAVE_FREEBSD_PKG
+ if (cmCPackFreeBSDGenerator::CanGenerate()) {
+ this->RegisterGenerator("FREEBSD", "FreeBSD pkg(8) packages",
+ cmCPackFreeBSDGenerator::CreateGenerator);
+ }
+#endif
+}
+
+std::unique_ptr<cmCPackGenerator> cmCPackGeneratorFactory::NewGenerator(
+ const std::string& name)
+{
+ auto it = this->GeneratorCreators.find(name);
+ if (it == this->GeneratorCreators.end()) {
+ return nullptr;
+ }
+ std::unique_ptr<cmCPackGenerator> gen(it->second());
+ if (!gen) {
+ return nullptr;
+ }
+ gen->SetLogger(this->Logger);
+ return gen;
+}
+
+void cmCPackGeneratorFactory::RegisterGenerator(
+ const std::string& name, const char* generatorDescription,
+ CreateGeneratorCall* createGenerator)
+{
+ if (!createGenerator) {
+ cmCPack_Log(this->Logger, cmCPackLog::LOG_ERROR,
+ "Cannot register generator" << std::endl);
+ return;
+ }
+ this->GeneratorCreators[name] = createGenerator;
+ this->GeneratorDescriptions[name] = generatorDescription;
+}
diff --git a/Source/CPack/cmCPackGeneratorFactory.h b/Source/CPack/cmCPackGeneratorFactory.h
new file mode 100644
index 0000000..0846573
--- /dev/null
+++ b/Source/CPack/cmCPackGeneratorFactory.h
@@ -0,0 +1,45 @@
+/* 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 <map>
+#include <memory>
+#include <string>
+
+class cmCPackGenerator;
+class cmCPackLog;
+
+/** \class cmCPackGeneratorFactory
+ * \brief A container for CPack generators
+ *
+ */
+class cmCPackGeneratorFactory
+{
+public:
+ cmCPackGeneratorFactory();
+
+ //! Get the generator
+ std::unique_ptr<cmCPackGenerator> NewGenerator(const std::string& name);
+
+ using CreateGeneratorCall = cmCPackGenerator*();
+
+ void RegisterGenerator(const std::string& name,
+ const char* generatorDescription,
+ CreateGeneratorCall* createGenerator);
+
+ void SetLogger(cmCPackLog* logger) { this->Logger = logger; }
+
+ using DescriptionsMap = std::map<std::string, std::string>;
+ const DescriptionsMap& GetGeneratorsList() const
+ {
+ return this->GeneratorDescriptions;
+ }
+
+private:
+ using t_GeneratorCreatorsMap = std::map<std::string, CreateGeneratorCall*>;
+ t_GeneratorCreatorsMap GeneratorCreators;
+ DescriptionsMap GeneratorDescriptions;
+ cmCPackLog* Logger;
+};
diff --git a/Source/CPack/cmCPackLog.cxx b/Source/CPack/cmCPackLog.cxx
new file mode 100644
index 0000000..49e4113
--- /dev/null
+++ b/Source/CPack/cmCPackLog.cxx
@@ -0,0 +1,164 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackLog.h"
+
+#include <iostream>
+
+#include <cm/memory>
+
+#include "cmGeneratedFileStream.h"
+#include "cmSystemTools.h"
+
+cmCPackLog::cmCPackLog()
+{
+ this->DefaultOutput = &std::cout;
+ this->DefaultError = &std::cerr;
+}
+
+cmCPackLog::~cmCPackLog() = default;
+
+void cmCPackLog::SetLogOutputStream(std::ostream* os)
+{
+ this->LogOutputStream.reset();
+ this->LogOutput = os;
+}
+
+bool cmCPackLog::SetLogOutputFile(const char* fname)
+{
+ this->LogOutputStream.reset();
+ if (fname) {
+ this->LogOutputStream = cm::make_unique<cmGeneratedFileStream>(fname);
+ }
+ if (this->LogOutputStream && !*this->LogOutputStream) {
+ this->LogOutputStream.reset();
+ }
+
+ this->LogOutput = this->LogOutputStream.get();
+
+ return this->LogOutput != nullptr;
+}
+
+void cmCPackLog::Log(int tag, const char* file, int line, const char* msg,
+ size_t length)
+{
+ // By default no logging
+ bool display = false;
+
+ // Display file and line number if debug
+ bool useFileAndLine = this->Debug;
+
+ bool output = false;
+ bool debug = false;
+ bool warning = false;
+ bool error = false;
+ bool verbose = false;
+
+ // When writing in file, add list of tags whenever tag changes.
+ std::string tagString;
+ bool needTagString = false;
+ if (this->LogOutput && this->LastTag != tag) {
+ needTagString = true;
+ }
+
+ if (tag & LOG_OUTPUT) {
+ output = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString += "VERBOSE";
+ }
+ }
+ if (tag & LOG_WARNING) {
+ warning = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString += "WARNING";
+ }
+ }
+ if (tag & LOG_ERROR) {
+ error = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString += "ERROR";
+ }
+ }
+ if (tag & LOG_DEBUG && this->Debug) {
+ debug = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString += "DEBUG";
+ }
+ useFileAndLine = true;
+ }
+ if (tag & LOG_VERBOSE && this->Verbose) {
+ verbose = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString += "VERBOSE";
+ }
+ }
+ if (this->Quiet) {
+ display = false;
+ }
+ if (this->LogOutput) {
+ if (needTagString) {
+ *this->LogOutput << "[" << file << ":" << line << " " << tagString
+ << "] ";
+ }
+ this->LogOutput->write(msg, length);
+ }
+ this->LastTag = tag;
+ if (!display) {
+ return;
+ }
+ if (this->NewLine) {
+ if (error && !this->ErrorPrefix.empty()) {
+ *this->DefaultError << this->ErrorPrefix;
+ } else if (warning && !this->WarningPrefix.empty()) {
+ *this->DefaultError << this->WarningPrefix;
+ } else if (output && !this->OutputPrefix.empty()) {
+ *this->DefaultOutput << this->OutputPrefix;
+ } else if (verbose && !this->VerbosePrefix.empty()) {
+ *this->DefaultOutput << this->VerbosePrefix;
+ } else if (debug && !this->DebugPrefix.empty()) {
+ *this->DefaultOutput << this->DebugPrefix;
+ } else if (!this->Prefix.empty()) {
+ *this->DefaultOutput << this->Prefix;
+ }
+ if (useFileAndLine) {
+ if (error || warning) {
+ *this->DefaultError << file << ":" << line << " ";
+ } else {
+ *this->DefaultOutput << file << ":" << line << " ";
+ }
+ }
+ }
+ if (error || warning) {
+ this->DefaultError->write(msg, length);
+ this->DefaultError->flush();
+ } else {
+ this->DefaultOutput->write(msg, length);
+ this->DefaultOutput->flush();
+ }
+ if (msg[length - 1] == '\n' || length > 2) {
+ this->NewLine = true;
+ }
+
+ if (error) {
+ cmSystemTools::SetErrorOccured();
+ }
+}
diff --git a/Source/CPack/cmCPackLog.h b/Source/CPack/cmCPackLog.h
new file mode 100644
index 0000000..6cec39c
--- /dev/null
+++ b/Source/CPack/cmCPackLog.h
@@ -0,0 +1,140 @@
+/* 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 <memory>
+#include <ostream>
+#include <string>
+
+#include <string.h>
+
+#define cmCPack_Log(ctSelf, logType, msg) \
+ do { \
+ std::ostringstream cmCPackLog_msg; \
+ cmCPackLog_msg << msg; \
+ (ctSelf)->Log(logType, __FILE__, __LINE__, cmCPackLog_msg.str().c_str()); \
+ } while (false)
+
+/** \class cmCPackLog
+ * \brief A container for CPack generators
+ *
+ */
+class cmCPackLog
+{
+public:
+ cmCPackLog();
+ ~cmCPackLog();
+
+ cmCPackLog(const cmCPackLog&) = delete;
+ cmCPackLog& operator=(const cmCPackLog&) = delete;
+
+ enum __log_tags
+ {
+ NOTAG = 0,
+ LOG_OUTPUT = 0x1,
+ LOG_VERBOSE = 0x2,
+ LOG_DEBUG = 0x4,
+ LOG_WARNING = 0x8,
+ LOG_ERROR = 0x10
+ };
+
+ //! Various signatures for logging.
+ void Log(const char* file, int line, const char* msg)
+ {
+ this->Log(LOG_OUTPUT, file, line, msg);
+ }
+ void Log(const char* file, int line, const char* msg, size_t length)
+ {
+ this->Log(LOG_OUTPUT, file, line, msg, length);
+ }
+ void Log(int tag, const char* file, int line, const char* msg)
+ {
+ this->Log(tag, file, line, msg, strlen(msg));
+ }
+ void Log(int tag, const char* file, int line, const char* msg,
+ size_t length);
+
+ //! Set Verbose
+ void VerboseOn() { this->SetVerbose(true); }
+ void VerboseOff() { this->SetVerbose(true); }
+ void SetVerbose(bool verb) { this->Verbose = verb; }
+ bool GetVerbose() { return this->Verbose; }
+
+ //! Set Debug
+ void DebugOn() { this->SetDebug(true); }
+ void DebugOff() { this->SetDebug(true); }
+ void SetDebug(bool verb) { this->Debug = verb; }
+ bool GetDebug() { return this->Debug; }
+
+ //! Set Quiet
+ void QuietOn() { this->SetQuiet(true); }
+ void QuietOff() { this->SetQuiet(true); }
+ void SetQuiet(bool verb) { this->Quiet = verb; }
+ bool GetQuiet() { return this->Quiet; }
+
+ //! Set the output stream
+ void SetOutputStream(std::ostream* os) { this->DefaultOutput = os; }
+
+ //! Set the error stream
+ void SetErrorStream(std::ostream* os) { this->DefaultError = os; }
+
+ //! Set the log output stream
+ void SetLogOutputStream(std::ostream* os);
+
+ //! Set the log output file. The cmCPackLog will try to create file. If it
+ // cannot, it will report an error.
+ bool SetLogOutputFile(const char* fname);
+
+ //! Set the various prefixes for the logging. SetPrefix sets the generic
+ // prefix that overwrites missing ones.
+ void SetPrefix(std::string const& pfx) { this->Prefix = pfx; }
+ void SetOutputPrefix(std::string const& pfx) { this->OutputPrefix = pfx; }
+ void SetVerbosePrefix(std::string const& pfx) { this->VerbosePrefix = pfx; }
+ void SetDebugPrefix(std::string const& pfx) { this->DebugPrefix = pfx; }
+ void SetWarningPrefix(std::string const& pfx) { this->WarningPrefix = pfx; }
+ void SetErrorPrefix(std::string const& pfx) { this->ErrorPrefix = pfx; }
+
+private:
+ bool Verbose = false;
+ bool Debug = false;
+ bool Quiet = false;
+
+ bool NewLine = true;
+
+ int LastTag = cmCPackLog::NOTAG;
+
+ std::string Prefix;
+ std::string OutputPrefix;
+ std::string VerbosePrefix;
+ std::string DebugPrefix;
+ std::string WarningPrefix;
+ std::string ErrorPrefix;
+
+ std::ostream* DefaultOutput = nullptr;
+ std::ostream* DefaultError = nullptr;
+
+ std::ostream* LogOutput = nullptr;
+ std::unique_ptr<std::ostream> LogOutputStream;
+};
+
+class cmCPackLogWrite
+{
+public:
+ cmCPackLogWrite(const char* data, size_t length)
+ : Data(data)
+ , Length(length)
+ {
+ }
+
+ const char* Data;
+ size_t Length;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const cmCPackLogWrite& c)
+{
+ os.write(c.Data, c.Length);
+ os.flush();
+ return os;
+}
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
new file mode 100644
index 0000000..6bd0d1b
--- /dev/null
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -0,0 +1,973 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackNSISGenerator.h"
+
+#include <algorithm>
+#include <cstdlib>
+#include <cstring>
+#include <map>
+#include <sstream>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackGenerator.h"
+#include "cmCPackLog.h"
+#include "cmDuration.h"
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+/* NSIS uses different command line syntax on Windows and others */
+#ifdef _WIN32
+# define NSIS_OPT "/"
+#else
+# define NSIS_OPT "-"
+#endif
+
+cmCPackNSISGenerator::cmCPackNSISGenerator(bool nsis64)
+{
+ this->Nsis64 = nsis64;
+}
+
+cmCPackNSISGenerator::~cmCPackNSISGenerator() = default;
+
+int cmCPackNSISGenerator::PackageFiles()
+{
+ // TODO: Fix nsis to force out file name
+
+ std::string nsisInFileName = this->FindTemplate("NSIS.template.in");
+ if (nsisInFileName.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPack error: Could not find NSIS installer template file."
+ << std::endl);
+ return false;
+ }
+ std::string nsisInInstallOptions =
+ this->FindTemplate("NSIS.InstallOptions.ini.in");
+ if (nsisInInstallOptions.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPack error: Could not find NSIS installer options file."
+ << std::endl);
+ return false;
+ }
+
+ std::string nsisFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ std::string tmpFile = cmStrCat(nsisFileName, "/NSISOutput.log");
+ std::string nsisInstallOptions = nsisFileName + "/NSIS.InstallOptions.ini";
+ nsisFileName += "/project.nsi";
+ std::ostringstream str;
+ for (std::string const& file : this->files) {
+ std::string outputDir = "$INSTDIR";
+ std::string fileN = cmSystemTools::RelativePath(this->toplevel, file);
+ if (!this->Components.empty()) {
+ const std::string::size_type pos = fileN.find('/');
+
+ // Use the custom component install directory if we have one
+ if (pos != std::string::npos) {
+ auto componentName = cm::string_view(fileN).substr(0, pos);
+ outputDir = this->CustomComponentInstallDirectory(componentName);
+ } else {
+ outputDir = this->CustomComponentInstallDirectory(fileN);
+ }
+
+ // Strip off the component part of the path.
+ fileN = fileN.substr(pos + 1);
+ }
+ std::replace(fileN.begin(), fileN.end(), '/', '\\');
+
+ str << " Delete \"" << outputDir << "\\" << fileN << "\"" << std::endl;
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Uninstall Files: " << str.str() << std::endl);
+ this->SetOptionIfNotSet("CPACK_NSIS_DELETE_FILES", str.str().c_str());
+ std::vector<std::string> dirs;
+ this->GetListOfSubdirectories(this->toplevel.c_str(), dirs);
+ std::ostringstream dstr;
+ for (std::string const& dir : dirs) {
+ std::string componentName;
+ std::string fileN = cmSystemTools::RelativePath(this->toplevel, dir);
+ if (fileN.empty()) {
+ continue;
+ }
+ if (!this->Components.empty()) {
+ // If this is a component installation, strip off the component
+ // part of the path.
+ std::string::size_type slash = fileN.find('/');
+ if (slash != std::string::npos) {
+ // If this is a component installation, determine which component it
+ // is.
+ componentName = fileN.substr(0, slash);
+
+ // Strip off the component part of the path.
+ fileN.erase(0, slash + 1);
+ }
+ }
+ std::replace(fileN.begin(), fileN.end(), '/', '\\');
+
+ const std::string componentOutputDir =
+ this->CustomComponentInstallDirectory(componentName);
+
+ dstr << " RMDir \"" << componentOutputDir << "\\" << fileN << "\""
+ << std::endl;
+ if (!componentName.empty()) {
+ this->Components[componentName].Directories.push_back(std::move(fileN));
+ }
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Uninstall Dirs: " << dstr.str() << std::endl);
+ this->SetOptionIfNotSet("CPACK_NSIS_DELETE_DIRECTORIES", dstr.str().c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Configure file: " << nsisInFileName << " to " << nsisFileName
+ << std::endl);
+ if (this->IsSet("CPACK_NSIS_MUI_ICON") ||
+ this->IsSet("CPACK_NSIS_MUI_UNIICON")) {
+ std::string installerIconCode;
+ if (this->IsSet("CPACK_NSIS_MUI_ICON")) {
+ installerIconCode += cmStrCat(
+ "!define MUI_ICON \"", this->GetOption("CPACK_NSIS_MUI_ICON"), "\"\n");
+ }
+ if (this->IsSet("CPACK_NSIS_MUI_UNIICON")) {
+ installerIconCode +=
+ cmStrCat("!define MUI_UNICON \"",
+ this->GetOption("CPACK_NSIS_MUI_UNIICON"), "\"\n");
+ }
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_ICON_CODE",
+ installerIconCode.c_str());
+ }
+ std::string installerHeaderImage;
+ if (this->IsSet("CPACK_NSIS_MUI_HEADERIMAGE")) {
+ installerHeaderImage = this->GetOption("CPACK_NSIS_MUI_HEADERIMAGE");
+ } else if (this->IsSet("CPACK_PACKAGE_ICON")) {
+ installerHeaderImage = this->GetOption("CPACK_PACKAGE_ICON");
+ }
+ if (!installerHeaderImage.empty()) {
+ std::string installerIconCode = cmStrCat(
+ "!define MUI_HEADERIMAGE_BITMAP \"", installerHeaderImage, "\"\n");
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_ICON_CODE",
+ installerIconCode.c_str());
+ }
+
+ if (this->IsSet("CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP")) {
+ std::string installerBitmapCode = cmStrCat(
+ "!define MUI_WELCOMEFINISHPAGE_BITMAP \"",
+ this->GetOption("CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP"), "\"\n");
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_WELCOMEFINISH_CODE",
+ installerBitmapCode.c_str());
+ }
+
+ if (this->IsSet("CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP")) {
+ std::string installerBitmapCode = cmStrCat(
+ "!define MUI_UNWELCOMEFINISHPAGE_BITMAP \"",
+ this->GetOption("CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP"), "\"\n");
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_UNWELCOMEFINISH_CODE",
+ installerBitmapCode.c_str());
+ }
+
+ if (this->IsSet("CPACK_NSIS_MUI_FINISHPAGE_RUN")) {
+ std::string installerRunCode =
+ cmStrCat("!define MUI_FINISHPAGE_RUN \"$INSTDIR\\",
+ this->GetOption("CPACK_NSIS_EXECUTABLES_DIRECTORY"), '\\',
+ this->GetOption("CPACK_NSIS_MUI_FINISHPAGE_RUN"), "\"\n");
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE",
+ installerRunCode.c_str());
+ }
+
+ if (this->IsSet("CPACK_NSIS_WELCOME_TITLE")) {
+ std::string welcomeTitleCode =
+ cmStrCat("!define MUI_WELCOMEPAGE_TITLE \"",
+ this->GetOption("CPACK_NSIS_WELCOME_TITLE"), "\"");
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_WELCOME_TITLE_CODE",
+ welcomeTitleCode.c_str());
+ }
+
+ if (this->IsSet("CPACK_NSIS_WELCOME_TITLE_3LINES")) {
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_WELCOME_TITLE_3LINES_CODE",
+ "!define MUI_WELCOMEPAGE_TITLE_3LINES");
+ }
+
+ if (this->IsSet("CPACK_NSIS_FINISH_TITLE")) {
+ std::string finishTitleCode =
+ cmStrCat("!define MUI_FINISHPAGE_TITLE \"",
+ this->GetOption("CPACK_NSIS_FINISH_TITLE"), "\"");
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_FINISH_TITLE_CODE",
+ finishTitleCode.c_str());
+ }
+
+ if (this->IsSet("CPACK_NSIS_FINISH_TITLE_3LINES")) {
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_FINISH_TITLE_3LINES_CODE",
+ "!define MUI_FINISHPAGE_TITLE_3LINES");
+ }
+
+ if (this->IsSet("CPACK_NSIS_MANIFEST_DPI_AWARE")) {
+ this->SetOptionIfNotSet("CPACK_NSIS_MANIFEST_DPI_AWARE_CODE",
+ "ManifestDPIAware true");
+ }
+
+ if (this->IsSet("CPACK_NSIS_BRANDING_TEXT")) {
+ // Default position to LEFT
+ std::string brandingTextPosition = "LEFT";
+ if (this->IsSet("CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION")) {
+ std::string wantedPosition =
+ this->GetOption("CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION");
+ if (!wantedPosition.empty()) {
+ const std::set<std::string> possiblePositions{ "CENTER", "LEFT",
+ "RIGHT" };
+ if (possiblePositions.find(wantedPosition) ==
+ possiblePositions.end()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Unsupported branding text trim position "
+ << wantedPosition << std::endl);
+ return false;
+ }
+ brandingTextPosition = wantedPosition;
+ }
+ }
+ std::string brandingTextCode =
+ cmStrCat("BrandingText /TRIM", brandingTextPosition, " \"",
+ this->GetOption("CPACK_NSIS_BRANDING_TEXT"), "\"\n");
+ this->SetOptionIfNotSet("CPACK_NSIS_BRANDING_TEXT_CODE",
+ brandingTextCode.c_str());
+ }
+
+ // Setup all of the component sections
+ if (this->Components.empty()) {
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLATION_TYPES", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_PAGE_COMPONENTS", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_FULL_INSTALL",
+ R"(File /r "${INST_DIR}\*.*")");
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTIONS", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTION_LIST", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_SECTION_SELECTED_VARS", "");
+ } else {
+ std::string componentCode;
+ std::string sectionList;
+ std::string selectedVarsList;
+ std::string componentDescriptions;
+ std::string groupDescriptions;
+ std::string installTypesCode;
+ std::string defines;
+ std::ostringstream macrosOut;
+ bool anyDownloadedComponents = false;
+
+ // Create installation types. The order is significant, so we first fill
+ // in a vector based on the indices, and print them in that order.
+ std::vector<cmCPackInstallationType*> installTypes(
+ this->InstallationTypes.size());
+ for (auto& installType : this->InstallationTypes) {
+ installTypes[installType.second.Index - 1] = &installType.second;
+ }
+ for (cmCPackInstallationType* installType : installTypes) {
+ installTypesCode += "InstType \"";
+ installTypesCode += installType->DisplayName;
+ installTypesCode += "\"\n";
+ }
+
+ // Create installation groups first
+ for (auto& group : this->ComponentGroups) {
+ if (group.second.ParentGroup == nullptr) {
+ componentCode +=
+ this->CreateComponentGroupDescription(&group.second, macrosOut);
+ }
+
+ // Add the group description, if any.
+ if (!group.second.Description.empty()) {
+ groupDescriptions += " !insertmacro MUI_DESCRIPTION_TEXT ${" +
+ group.first + "} \"" +
+ cmCPackNSISGenerator::TranslateNewlines(group.second.Description) +
+ "\"\n";
+ }
+ }
+
+ // Create the remaining components, which aren't associated with groups.
+ for (auto& comp : this->Components) {
+ if (comp.second.Files.empty()) {
+ // NSIS cannot cope with components that have no files.
+ continue;
+ }
+
+ anyDownloadedComponents =
+ anyDownloadedComponents || comp.second.IsDownloaded;
+
+ if (!comp.second.Group) {
+ componentCode +=
+ this->CreateComponentDescription(&comp.second, macrosOut);
+ }
+
+ // Add this component to the various section lists.
+ sectionList += R"( !insertmacro "${MacroName}" ")";
+ sectionList += comp.first;
+ sectionList += "\"\n";
+ selectedVarsList += "Var " + comp.first + "_selected\n";
+ selectedVarsList += "Var " + comp.first + "_was_installed\n";
+
+ // Add the component description, if any.
+ if (!comp.second.Description.empty()) {
+ componentDescriptions += " !insertmacro MUI_DESCRIPTION_TEXT ${" +
+ comp.first + "} \"" +
+ cmCPackNSISGenerator::TranslateNewlines(comp.second.Description) +
+ "\"\n";
+ }
+ }
+
+ componentCode += macrosOut.str();
+
+ if (componentDescriptions.empty() && groupDescriptions.empty()) {
+ // Turn off the "Description" box
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC",
+ "!define MUI_COMPONENTSPAGE_NODESC");
+ } else {
+ componentDescriptions = "!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN\n" +
+ componentDescriptions + groupDescriptions +
+ "!insertmacro MUI_FUNCTION_DESCRIPTION_END\n";
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC",
+ componentDescriptions.c_str());
+ }
+
+ if (anyDownloadedComponents) {
+ defines += "!define CPACK_USES_DOWNLOAD\n";
+ if (cmIsOn(this->GetOption("CPACK_ADD_REMOVE"))) {
+ defines += "!define CPACK_NSIS_ADD_REMOVE\n";
+ }
+ }
+
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLATION_TYPES",
+ installTypesCode.c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_PAGE_COMPONENTS",
+ "!insertmacro MUI_PAGE_COMPONENTS");
+ this->SetOptionIfNotSet("CPACK_NSIS_FULL_INSTALL", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTIONS",
+ componentCode.c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTION_LIST",
+ sectionList.c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_SECTION_SELECTED_VARS",
+ selectedVarsList.c_str());
+ this->SetOption("CPACK_NSIS_DEFINES", defines.c_str());
+ }
+
+ this->ConfigureFile(nsisInInstallOptions, nsisInstallOptions);
+ this->ConfigureFile(nsisInFileName, nsisFileName);
+ std::string nsisCmd =
+ cmStrCat('"', this->GetOption("CPACK_INSTALLER_PROGRAM"), "\" \"",
+ nsisFileName, '"');
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << nsisCmd << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool res = cmSystemTools::RunSingleCommand(
+ nsisCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile);
+ ofs << "# Run command: " << nsisCmd << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem running NSIS command: " << nsisCmd << std::endl
+ << "Please check "
+ << tmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+ return 1;
+}
+
+int cmCPackNSISGenerator::InitializeInternal()
+{
+ if (cmIsOn(this->GetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY"))) {
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING,
+ "NSIS Generator cannot work with CPACK_INCLUDE_TOPLEVEL_DIRECTORY set. "
+ "This option will be reset to 0 (for this generator only)."
+ << std::endl);
+ this->SetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", nullptr);
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "cmCPackNSISGenerator::Initialize()" << std::endl);
+ std::vector<std::string> path;
+ std::string nsisPath;
+ bool gotRegValue = false;
+
+#ifdef _WIN32
+ if (Nsis64) {
+ if (!gotRegValue &&
+ cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS\\Unicode", nsisPath,
+ cmsys::SystemTools::KeyWOW64_64)) {
+ gotRegValue = true;
+ }
+ if (!gotRegValue &&
+ cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS", nsisPath,
+ cmsys::SystemTools::KeyWOW64_64)) {
+ gotRegValue = true;
+ }
+ }
+ if (!gotRegValue &&
+ cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS\\Unicode", nsisPath,
+ cmsys::SystemTools::KeyWOW64_32)) {
+ gotRegValue = true;
+ }
+ if (!gotRegValue &&
+ cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS\\Unicode", nsisPath)) {
+ gotRegValue = true;
+ }
+ if (!gotRegValue &&
+ cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS", nsisPath,
+ cmsys::SystemTools::KeyWOW64_32)) {
+ gotRegValue = true;
+ }
+ if (!gotRegValue &&
+ cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS", nsisPath)) {
+ gotRegValue = true;
+ }
+
+ if (gotRegValue) {
+ path.push_back(nsisPath);
+ }
+#endif
+
+ this->SetOptionIfNotSet("CPACK_NSIS_EXECUTABLE", "makensis");
+ nsisPath = cmSystemTools::FindProgram(
+ this->GetOption("CPACK_NSIS_EXECUTABLE"), path, false);
+
+ if (nsisPath.empty()) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Cannot find NSIS compiler makensis: likely it is not installed, "
+ "or not in your PATH"
+ << std::endl);
+
+ if (!gotRegValue) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Could not read NSIS registry value. This is usually caused by "
+ "NSIS not being installed. Please install NSIS from "
+ "http://nsis.sourceforge.net"
+ << std::endl);
+ }
+
+ return 0;
+ }
+
+ std::string nsisCmd = "\"" + nsisPath + "\" " NSIS_OPT "VERSION";
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Test NSIS version: " << nsisCmd << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool resS = cmSystemTools::RunSingleCommand(
+ nsisCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
+ cmsys::RegularExpression versionRex("v([0-9]+.[0-9]+)");
+ cmsys::RegularExpression versionRexCVS("v(.*)\\.cvs");
+ if (!resS || retVal ||
+ (!versionRex.find(output) && !versionRexCVS.find(output))) {
+ const char* topDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ std::string tmpFile = cmStrCat(topDir ? topDir : ".", "/NSISOutput.log");
+ cmGeneratedFileStream ofs(tmpFile);
+ ofs << "# Run command: " << nsisCmd << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem checking NSIS version with command: "
+ << nsisCmd << std::endl
+ << "Please check " << tmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+ if (versionRex.find(output)) {
+ double nsisVersion = atof(versionRex.match(1).c_str());
+ double minNSISVersion = 3.0;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "NSIS Version: " << nsisVersion << std::endl);
+ if (nsisVersion < minNSISVersion) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPack requires NSIS Version 3.0 or greater. "
+ "NSIS found on the system was: "
+ << nsisVersion << std::endl);
+ return 0;
+ }
+ }
+ if (versionRexCVS.find(output)) {
+ // No version check for NSIS cvs build
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "NSIS Version: CVS " << versionRexCVS.match(1) << std::endl);
+ }
+ this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", nsisPath.c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_EXECUTABLES_DIRECTORY", "bin");
+ const char* cpackPackageExecutables =
+ this->GetOption("CPACK_PACKAGE_EXECUTABLES");
+ const char* cpackPackageDeskTopLinks =
+ this->GetOption("CPACK_CREATE_DESKTOP_LINKS");
+ const char* cpackNsisExecutablesDirectory =
+ this->GetOption("CPACK_NSIS_EXECUTABLES_DIRECTORY");
+ std::vector<std::string> cpackPackageDesktopLinksVector;
+ if (cpackPackageDeskTopLinks) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "CPACK_CREATE_DESKTOP_LINKS: " << cpackPackageDeskTopLinks
+ << std::endl);
+
+ cmExpandList(cpackPackageDeskTopLinks, cpackPackageDesktopLinksVector);
+ for (std::string const& cpdl : cpackPackageDesktopLinksVector) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "CPACK_CREATE_DESKTOP_LINKS: " << cpdl << std::endl);
+ }
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "CPACK_CREATE_DESKTOP_LINKS: "
+ << "not set" << std::endl);
+ }
+
+ std::ostringstream str;
+ std::ostringstream deleteStr;
+
+ if (cpackPackageExecutables) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "The cpackPackageExecutables: " << cpackPackageExecutables
+ << "." << std::endl);
+ std::vector<std::string> cpackPackageExecutablesVector =
+ cmExpandedList(cpackPackageExecutables);
+ if (cpackPackageExecutablesVector.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
+ "<icon name>."
+ << std::endl);
+ return 0;
+ }
+ std::vector<std::string>::iterator it;
+ for (it = cpackPackageExecutablesVector.begin();
+ it != cpackPackageExecutablesVector.end(); ++it) {
+ std::string execName = *it;
+ ++it;
+ std::string linkName = *it;
+ str << R"( CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\)" << linkName
+ << R"(.lnk" "$INSTDIR\)" << cpackNsisExecutablesDirectory << "\\"
+ << execName << ".exe\"" << std::endl;
+ deleteStr << R"( Delete "$SMPROGRAMS\$MUI_TEMP\)" << linkName
+ << ".lnk\"" << std::endl;
+ // see if CPACK_CREATE_DESKTOP_LINK_ExeName is on
+ // if so add a desktop link
+ if (cm::contains(cpackPackageDesktopLinksVector, execName)) {
+ str << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
+ str << " CreateShortCut \"$DESKTOP\\" << linkName
+ << R"(.lnk" "$INSTDIR\)" << cpackNsisExecutablesDirectory << "\\"
+ << execName << ".exe\"" << std::endl;
+ deleteStr << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
+ deleteStr << " Delete \"$DESKTOP\\" << linkName << ".lnk\""
+ << std::endl;
+ }
+ }
+ }
+
+ this->CreateMenuLinks(str, deleteStr);
+ this->SetOptionIfNotSet("CPACK_NSIS_CREATE_ICONS", str.str().c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_DELETE_ICONS", deleteStr.str().c_str());
+
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPRESSOR", "lzma");
+
+ return this->Superclass::InitializeInternal();
+}
+
+void cmCPackNSISGenerator::CreateMenuLinks(std::ostream& str,
+ std::ostream& deleteStr)
+{
+ const char* cpackMenuLinks = this->GetOption("CPACK_NSIS_MENU_LINKS");
+ if (!cpackMenuLinks) {
+ return;
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "The cpackMenuLinks: " << cpackMenuLinks << "." << std::endl);
+ std::vector<std::string> cpackMenuLinksVector =
+ cmExpandedList(cpackMenuLinks);
+ if (cpackMenuLinksVector.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_NSIS_MENU_LINKS should contain pairs of <shortcut target> and "
+ "<shortcut label>."
+ << std::endl);
+ return;
+ }
+
+ static cmsys::RegularExpression urlRegex(
+ "^(mailto:|(ftps?|https?|news)://).*$");
+
+ std::vector<std::string>::iterator it;
+ for (it = cpackMenuLinksVector.begin(); it != cpackMenuLinksVector.end();
+ ++it) {
+ std::string sourceName = *it;
+ const bool url = urlRegex.find(sourceName);
+
+ // Convert / to \ in filenames, but not in urls:
+ //
+ if (!url) {
+ std::replace(sourceName.begin(), sourceName.end(), '/', '\\');
+ }
+
+ ++it;
+ std::string linkName = *it;
+ if (!url) {
+ str << R"( CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\)" << linkName
+ << R"(.lnk" "$INSTDIR\)" << sourceName << "\"" << std::endl;
+ deleteStr << R"( Delete "$SMPROGRAMS\$MUI_TEMP\)" << linkName
+ << ".lnk\"" << std::endl;
+ } else {
+ str << R"( WriteINIStr "$SMPROGRAMS\$STARTMENU_FOLDER\)" << linkName
+ << R"(.url" "InternetShortcut" "URL" ")" << sourceName << "\""
+ << std::endl;
+ deleteStr << R"( Delete "$SMPROGRAMS\$MUI_TEMP\)" << linkName
+ << ".url\"" << std::endl;
+ }
+ // see if CPACK_CREATE_DESKTOP_LINK_ExeName is on
+ // if so add a desktop link
+ std::string desktop = cmStrCat("CPACK_CREATE_DESKTOP_LINK_", linkName);
+ if (this->IsSet(desktop)) {
+ str << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
+ str << " CreateShortCut \"$DESKTOP\\" << linkName
+ << R"(.lnk" "$INSTDIR\)" << sourceName << "\"" << std::endl;
+ deleteStr << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
+ deleteStr << " Delete \"$DESKTOP\\" << linkName << ".lnk\""
+ << std::endl;
+ }
+ }
+}
+
+bool cmCPackNSISGenerator::GetListOfSubdirectories(
+ const char* topdir, std::vector<std::string>& dirs)
+{
+ cmsys::Directory dir;
+ dir.Load(topdir);
+ for (unsigned long i = 0; i < dir.GetNumberOfFiles(); ++i) {
+ const char* fileName = dir.GetFile(i);
+ if (strcmp(fileName, ".") != 0 && strcmp(fileName, "..") != 0) {
+ std::string const fullPath =
+ std::string(topdir).append("/").append(fileName);
+ if (cmsys::SystemTools::FileIsDirectory(fullPath) &&
+ !cmsys::SystemTools::FileIsSymlink(fullPath)) {
+ if (!this->GetListOfSubdirectories(fullPath.c_str(), dirs)) {
+ return false;
+ }
+ }
+ }
+ }
+ dirs.emplace_back(topdir);
+ return true;
+}
+
+enum cmCPackGenerator::CPackSetDestdirSupport
+cmCPackNSISGenerator::SupportsSetDestdir() const
+{
+ return cmCPackGenerator::SETDESTDIR_SHOULD_NOT_BE_USED;
+}
+
+bool cmCPackNSISGenerator::SupportsAbsoluteDestination() const
+{
+ return false;
+}
+
+bool cmCPackNSISGenerator::SupportsComponentInstallation() const
+{
+ return true;
+}
+
+std::string cmCPackNSISGenerator::CreateComponentDescription(
+ cmCPackComponent* component, std::ostream& macrosOut)
+{
+ // Basic description of the component
+ std::string componentCode = "Section ";
+ if (component->IsDisabledByDefault) {
+ componentCode += "/o ";
+ }
+ componentCode += "\"";
+ if (component->IsHidden) {
+ componentCode += "-";
+ }
+ componentCode += component->DisplayName + "\" " + component->Name + "\n";
+ if (component->IsRequired) {
+ componentCode += " SectionIn RO\n";
+ } else if (!component->InstallationTypes.empty()) {
+ std::ostringstream out;
+ for (cmCPackInstallationType const* installType :
+ component->InstallationTypes) {
+ out << " " << installType->Index;
+ }
+ componentCode += " SectionIn" + out.str() + "\n";
+ }
+
+ const std::string componentOutputDir =
+ this->CustomComponentInstallDirectory(component->Name);
+ componentCode += cmStrCat(" SetOutPath \"", componentOutputDir, "\"\n");
+
+ // Create the actual installation commands
+ if (component->IsDownloaded) {
+ if (component->ArchiveFile.empty()) {
+ // Compute the name of the archive.
+ std::string packagesDir =
+ cmStrCat(this->GetOption("CPACK_TEMPORARY_DIRECTORY"), ".dummy");
+ std::ostringstream out;
+ out << cmSystemTools::GetFilenameWithoutLastExtension(packagesDir) << "-"
+ << component->Name << ".zip";
+ component->ArchiveFile = out.str();
+ }
+
+ // Create the directory for the upload area
+ const char* userUploadDirectory =
+ this->GetOption("CPACK_UPLOAD_DIRECTORY");
+ std::string uploadDirectory;
+ if (cmNonempty(userUploadDirectory)) {
+ uploadDirectory = userUploadDirectory;
+ } else {
+ uploadDirectory =
+ cmStrCat(this->GetOption("CPACK_PACKAGE_DIRECTORY"), "/CPackUploads");
+ }
+ if (!cmSystemTools::FileExists(uploadDirectory)) {
+ if (!cmSystemTools::MakeDirectory(uploadDirectory)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Unable to create NSIS upload directory "
+ << uploadDirectory << std::endl);
+ return "";
+ }
+ }
+
+ // Remove the old archive, if one exists
+ std::string archiveFile = uploadDirectory + '/' + component->ArchiveFile;
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Building downloaded component archive: " << archiveFile
+ << std::endl);
+ if (cmSystemTools::FileExists(archiveFile, true)) {
+ if (!cmSystemTools::RemoveFile(archiveFile)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Unable to remove archive file " << archiveFile
+ << std::endl);
+ return "";
+ }
+ }
+
+ // Find a ZIP program
+ if (!this->IsSet("ZIP_EXECUTABLE")) {
+ this->ReadListFile("Internal/CPack/CPackZIP.cmake");
+
+ if (!this->IsSet("ZIP_EXECUTABLE")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Unable to find ZIP program" << std::endl);
+ return "";
+ }
+ }
+
+ // The directory where this component's files reside
+ std::string dirName = cmStrCat(
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY"), '/', component->Name, '/');
+
+ // Build the list of files to go into this archive, and determine the
+ // size of the installed component.
+ std::string zipListFileName = cmStrCat(
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY"), "/winZip.filelist");
+ bool needQuotesInFile = cmIsOn(this->GetOption("CPACK_ZIP_NEED_QUOTES"));
+ unsigned long totalSize = 0;
+ { // the scope is needed for cmGeneratedFileStream
+ cmGeneratedFileStream out(zipListFileName);
+ for (std::string const& file : component->Files) {
+ if (needQuotesInFile) {
+ out << "\"";
+ }
+ out << file;
+ if (needQuotesInFile) {
+ out << "\"";
+ }
+ out << std::endl;
+
+ totalSize += cmSystemTools::FileLength(dirName + file);
+ }
+ }
+
+ // Build the archive in the upload area
+ std::string cmd = this->GetOption("CPACK_ZIP_COMMAND");
+ cmsys::SystemTools::ReplaceString(cmd, "<ARCHIVE>", archiveFile.c_str());
+ cmsys::SystemTools::ReplaceString(cmd, "<FILELIST>",
+ zipListFileName.c_str());
+ std::string output;
+ int retVal = -1;
+ int res = cmSystemTools::RunSingleCommand(
+ cmd, &output, &output, &retVal, dirName.c_str(),
+ cmSystemTools::OUTPUT_NONE, cmDuration::zero());
+ if (!res || retVal) {
+ std::string tmpFile = cmStrCat(
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/CompressZip.log");
+ cmGeneratedFileStream ofs(tmpFile);
+ ofs << "# Run command: " << cmd << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem running zip command: " << cmd << std::endl
+ << "Please check "
+ << tmpFile << " for errors"
+ << std::endl);
+ return "";
+ }
+
+ // Create the NSIS code to download this file on-the-fly.
+ unsigned long totalSizeInKbytes = (totalSize + 512) / 1024;
+ if (totalSizeInKbytes == 0) {
+ totalSizeInKbytes = 1;
+ }
+ std::ostringstream out;
+ /* clang-format off */
+ out << " AddSize " << totalSizeInKbytes << "\n"
+ << " Push \"" << component->ArchiveFile << "\"\n"
+ << " Call DownloadFile\n"
+ << " ZipDLL::extractall \"$INSTDIR\\"
+ << component->ArchiveFile << "\" \"$INSTDIR\"\n"
+ << " Pop $2 ; error message\n"
+ " StrCmp $2 \"success\" +2 0\n"
+ " MessageBox MB_OK \"Failed to unzip $2\"\n"
+ " Delete $INSTDIR\\$0\n";
+ /* clang-format on */
+ componentCode += out.str();
+ } else {
+ componentCode +=
+ " File /r \"${INST_DIR}\\" + component->Name + "\\*.*\"\n";
+ }
+ componentCode += "SectionEnd\n";
+
+ // Macro used to remove the component
+ macrosOut << "!macro Remove_${" << component->Name << "}\n";
+ macrosOut << " IntCmp $" << component->Name << "_was_installed 0 noremove_"
+ << component->Name << "\n";
+ std::string path;
+ for (std::string const& pathIt : component->Files) {
+ path = pathIt;
+ std::replace(path.begin(), path.end(), '/', '\\');
+ macrosOut << " Delete \"" << componentOutputDir << "\\" << path << "\"\n";
+ }
+ for (std::string const& pathIt : component->Directories) {
+ path = pathIt;
+ std::replace(path.begin(), path.end(), '/', '\\');
+ macrosOut << " RMDir \"" << componentOutputDir << "\\" << path << "\"\n";
+ }
+ macrosOut << " noremove_" << component->Name << ":\n";
+ macrosOut << "!macroend\n";
+
+ // Macro used to select each of the components that this component
+ // depends on.
+ std::set<cmCPackComponent*> visited;
+ macrosOut << "!macro Select_" << component->Name << "_depends\n";
+ macrosOut << this->CreateSelectionDependenciesDescription(component,
+ visited);
+ macrosOut << "!macroend\n";
+
+ // Macro used to deselect each of the components that depend on this
+ // component.
+ visited.clear();
+ macrosOut << "!macro Deselect_required_by_" << component->Name << "\n";
+ macrosOut << this->CreateDeselectionDependenciesDescription(component,
+ visited);
+ macrosOut << "!macroend\n";
+ return componentCode;
+}
+
+std::string cmCPackNSISGenerator::CreateSelectionDependenciesDescription(
+ cmCPackComponent* component, std::set<cmCPackComponent*>& visited)
+{
+ // Don't visit a component twice
+ if (visited.count(component)) {
+ return std::string();
+ }
+ visited.insert(component);
+
+ std::ostringstream out;
+ for (cmCPackComponent* depend : component->Dependencies) {
+ // Write NSIS code to select this dependency
+ out << " SectionGetFlags ${" << depend->Name << "} $0\n";
+ out << " IntOp $0 $0 | ${SF_SELECTED}\n";
+ out << " SectionSetFlags ${" << depend->Name << "} $0\n";
+ out << " IntOp $" << depend->Name << "_selected 0 + ${SF_SELECTED}\n";
+ // Recurse
+ out
+ << this->CreateSelectionDependenciesDescription(depend, visited).c_str();
+ }
+
+ return out.str();
+}
+
+std::string cmCPackNSISGenerator::CreateDeselectionDependenciesDescription(
+ cmCPackComponent* component, std::set<cmCPackComponent*>& visited)
+{
+ // Don't visit a component twice
+ if (visited.count(component)) {
+ return std::string();
+ }
+ visited.insert(component);
+
+ std::ostringstream out;
+ for (cmCPackComponent* depend : component->ReverseDependencies) {
+ // Write NSIS code to deselect this dependency
+ out << " SectionGetFlags ${" << depend->Name << "} $0\n";
+ out << " IntOp $1 ${SF_SELECTED} ~\n";
+ out << " IntOp $0 $0 & $1\n";
+ out << " SectionSetFlags ${" << depend->Name << "} $0\n";
+ out << " IntOp $" << depend->Name << "_selected 0 + 0\n";
+
+ // Recurse
+ out << this->CreateDeselectionDependenciesDescription(depend, visited)
+ .c_str();
+ }
+
+ return out.str();
+}
+
+std::string cmCPackNSISGenerator::CreateComponentGroupDescription(
+ cmCPackComponentGroup* group, std::ostream& macrosOut)
+{
+ if (group->Components.empty() && group->Subgroups.empty()) {
+ // Silently skip empty groups. NSIS doesn't support them.
+ return std::string();
+ }
+
+ std::string code = "SectionGroup ";
+ if (group->IsExpandedByDefault) {
+ code += "/e ";
+ }
+ if (group->IsBold) {
+ code += "\"!" + group->DisplayName + "\" " + group->Name + "\n";
+ } else {
+ code += "\"" + group->DisplayName + "\" " + group->Name + "\n";
+ }
+
+ for (cmCPackComponentGroup* g : group->Subgroups) {
+ code += this->CreateComponentGroupDescription(g, macrosOut);
+ }
+
+ for (cmCPackComponent* comp : group->Components) {
+ if (comp->Files.empty()) {
+ continue;
+ }
+
+ code += this->CreateComponentDescription(comp, macrosOut);
+ }
+ code += "SectionGroupEnd\n";
+ return code;
+}
+
+std::string cmCPackNSISGenerator::CustomComponentInstallDirectory(
+ cm::string_view componentName)
+{
+ const char* outputDir = this->GetOption(
+ cmStrCat("CPACK_NSIS_", componentName, "_INSTALL_DIRECTORY"));
+ return outputDir ? outputDir : "$INSTDIR";
+}
+
+std::string cmCPackNSISGenerator::TranslateNewlines(std::string str)
+{
+ cmSystemTools::ReplaceString(str, "\n", "$\\r$\\n");
+ return str;
+}
diff --git a/Source/CPack/cmCPackNSISGenerator.h b/Source/CPack/cmCPackNSISGenerator.h
new file mode 100644
index 0000000..ded02de
--- /dev/null
+++ b/Source/CPack/cmCPackNSISGenerator.h
@@ -0,0 +1,86 @@
+/* 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 <iosfwd>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmCPackGenerator.h"
+
+class cmCPackComponent;
+class cmCPackComponentGroup;
+
+/** \class cmCPackNSISGenerator
+ * \brief A generator for NSIS files
+ *
+ * http://people.freebsd.org/~kientzle/libarchive/
+ */
+class cmCPackNSISGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackNSISGenerator, cmCPackGenerator);
+
+ static cmCPackGenerator* CreateGenerator64()
+ {
+ return new cmCPackNSISGenerator(true);
+ }
+
+ /**
+ * Construct generator
+ */
+ cmCPackNSISGenerator(bool nsis64 = false);
+ ~cmCPackNSISGenerator() override;
+
+protected:
+ int InitializeInternal() override;
+ void CreateMenuLinks(std::ostream& str, std::ostream& deleteStr);
+ int PackageFiles() override;
+ const char* GetOutputExtension() override { return ".exe"; }
+ const char* GetOutputPostfix() override { return "win32"; }
+
+ bool GetListOfSubdirectories(const char* dir,
+ std::vector<std::string>& dirs);
+
+ enum cmCPackGenerator::CPackSetDestdirSupport SupportsSetDestdir()
+ const override;
+ bool SupportsAbsoluteDestination() const override;
+ bool SupportsComponentInstallation() const override;
+
+ /// Produce a string that contains the NSIS code to describe a
+ /// particular component. Any added macros will be emitted via
+ /// macrosOut.
+ std::string CreateComponentDescription(cmCPackComponent* component,
+ std::ostream& macrosOut);
+
+ /// Produce NSIS code that selects all of the components that this component
+ /// depends on, recursively.
+ std::string CreateSelectionDependenciesDescription(
+ cmCPackComponent* component, std::set<cmCPackComponent*>& visited);
+
+ /// Produce NSIS code that de-selects all of the components that are
+ /// dependent on this component, recursively.
+ std::string CreateDeselectionDependenciesDescription(
+ cmCPackComponent* component, std::set<cmCPackComponent*>& visited);
+
+ /// Produce a string that contains the NSIS code to describe a
+ /// particular component group, including its components. Any
+ /// added macros will be emitted via macrosOut.
+ std::string CreateComponentGroupDescription(cmCPackComponentGroup* group,
+ std::ostream& macrosOut);
+
+ /// Returns the custom install directory if available for the specified
+ /// component, otherwise $INSTDIR is returned.
+ std::string CustomComponentInstallDirectory(cm::string_view componentName);
+
+ /// Translations any newlines found in the string into \\r\\n, so that the
+ /// resulting string can be used within NSIS.
+ static std::string TranslateNewlines(std::string str);
+
+ bool Nsis64;
+};
diff --git a/Source/CPack/cmCPackNuGetGenerator.cxx b/Source/CPack/cmCPackNuGetGenerator.cxx
new file mode 100644
index 0000000..98dc890
--- /dev/null
+++ b/Source/CPack/cmCPackNuGetGenerator.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 "cmCPackNuGetGenerator.h"
+
+#include <algorithm>
+#include <iterator>
+#include <map>
+#include <ostream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+bool cmCPackNuGetGenerator::SupportsComponentInstallation() const
+{
+ return this->IsOn("CPACK_NUGET_COMPONENT_INSTALL");
+}
+
+int cmCPackNuGetGenerator::PackageFiles()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Toplevel: " << this->toplevel << std::endl);
+
+ /* Reset package file name list it will be populated after the
+ * `CPackNuGet.cmake` run */
+ this->packageFileNames.clear();
+
+ /* Are we in the component packaging case */
+ if (this->WantsComponentInstallation()) {
+ if (this->componentPackageMethod == ONE_PACKAGE) {
+ // CASE 1 : COMPONENT ALL-IN-ONE package
+ // Meaning that all per-component pre-installed files
+ // goes into the single package.
+ this->SetOption("CPACK_NUGET_ALL_IN_ONE", "TRUE");
+ this->SetupGroupComponentVariables(true);
+ } else {
+ // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
+ // There will be 1 package for each component group
+ // however one may require to ignore component group and
+ // in this case you'll get 1 package for each component.
+ this->SetupGroupComponentVariables(this->componentPackageMethod ==
+ ONE_PACKAGE_PER_COMPONENT);
+ }
+ } else {
+ // CASE 3 : NON COMPONENT package.
+ this->SetOption("CPACK_NUGET_ORDINAL_MONOLITIC", "TRUE");
+ }
+
+ auto retval = this->ReadListFile("Internal/CPack/CPackNuGet.cmake");
+ if (retval) {
+ this->AddGeneratedPackageNames();
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while execution CPackNuGet.cmake" << std::endl);
+ }
+
+ return retval;
+}
+
+void cmCPackNuGetGenerator::SetupGroupComponentVariables(bool ignoreGroup)
+{
+ // The default behavior is to have one package by component group
+ // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
+ if (!ignoreGroup) {
+ std::vector<std::string> groups;
+ for (auto const& compG : this->ComponentGroups) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Packaging component group: " << compG.first << std::endl);
+ groups.push_back(compG.first);
+ auto compGUp =
+ cmSystemTools::UpperCase(cmSystemTools::MakeCidentifier(compG.first));
+
+ // Collect components for this group
+ std::vector<std::string> components;
+ std::transform(begin(compG.second.Components),
+ end(compG.second.Components),
+ std::back_inserter(components),
+ [](cmCPackComponent const* comp) { return comp->Name; });
+ this->SetOption("CPACK_NUGET_" + compGUp + "_GROUP_COMPONENTS",
+ cmJoin(components, ";").c_str());
+ }
+ if (!groups.empty()) {
+ this->SetOption("CPACK_NUGET_GROUPS", cmJoin(groups, ";").c_str());
+ }
+
+ // Handle Orphan components (components not belonging to any groups)
+ std::vector<std::string> components;
+ for (auto const& comp : this->Components) {
+ // Does the component belong to a group?
+ if (comp.second.Group == nullptr) {
+ cmCPackLogger(
+ cmCPackLog::LOG_VERBOSE,
+ "Component <"
+ << comp.second.Name
+ << "> does not belong to any group, package it separately."
+ << std::endl);
+ components.push_back(comp.first);
+ }
+ }
+ if (!components.empty()) {
+ this->SetOption("CPACK_NUGET_COMPONENTS",
+ cmJoin(components, ";").c_str());
+ }
+
+ } else {
+ std::vector<std::string> components;
+ components.reserve(this->Components.size());
+ std::transform(begin(this->Components), end(this->Components),
+ std::back_inserter(components),
+ [](std::pair<std::string, cmCPackComponent> const& comp) {
+ return comp.first;
+ });
+ this->SetOption("CPACK_NUGET_COMPONENTS", cmJoin(components, ";").c_str());
+ }
+}
+
+void cmCPackNuGetGenerator::AddGeneratedPackageNames()
+{
+ const char* const files_list = this->GetOption("GEN_CPACK_OUTPUT_FILES");
+ if (!files_list) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Error while execution CPackNuGet.cmake: No NuGet package has generated"
+ << std::endl);
+ return;
+ }
+ // add the generated packages to package file names list
+ std::string fileNames{ files_list };
+ const char sep = ';';
+ std::string::size_type pos1 = 0;
+ std::string::size_type pos2 = fileNames.find(sep, pos1 + 1);
+ while (pos2 != std::string::npos) {
+ this->packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1));
+ pos1 = pos2 + 1;
+ pos2 = fileNames.find(sep, pos1 + 1);
+ }
+ this->packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1));
+}
diff --git a/Source/CPack/cmCPackNuGetGenerator.h b/Source/CPack/cmCPackNuGetGenerator.h
new file mode 100644
index 0000000..609ec79
--- /dev/null
+++ b/Source/CPack/cmCPackNuGetGenerator.h
@@ -0,0 +1,34 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmCPackGenerator.h"
+
+/** \class cmCPackNuGetGenerator
+ * \brief A generator for RPM packages
+ */
+class cmCPackNuGetGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackNuGetGenerator, cmCPackGenerator);
+
+ // NOTE In fact, it is possible to have NuGet not only for Windows...
+ // https://docs.microsoft.com/en-us/nuget/install-nuget-client-tools
+ static bool CanGenerate() { return true; }
+
+protected:
+ bool SupportsComponentInstallation() const override;
+ int PackageFiles() override;
+
+ const char* GetOutputExtension() override { return ".nupkg"; }
+ bool SupportsAbsoluteDestination() const override { return false; }
+ /**
+ * The method used to prepare variables when component
+ * install is used.
+ */
+ void SetupGroupComponentVariables(bool ignoreGroup);
+ /**
+ * Populate \c packageFileNames vector of built packages.
+ */
+ void AddGeneratedPackageNames();
+};
diff --git a/Source/CPack/cmCPackOSXX11Generator.cxx b/Source/CPack/cmCPackOSXX11Generator.cxx
new file mode 100644
index 0000000..5de4a6f
--- /dev/null
+++ b/Source/CPack/cmCPackOSXX11Generator.cxx
@@ -0,0 +1,273 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackOSXX11Generator.h"
+
+#include <sstream>
+
+#include "cm_sys_stat.h"
+
+#include "cmCPackGenerator.h"
+#include "cmCPackLog.h"
+#include "cmDuration.h"
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmCPackOSXX11Generator::cmCPackOSXX11Generator() = default;
+
+cmCPackOSXX11Generator::~cmCPackOSXX11Generator() = default;
+
+int cmCPackOSXX11Generator::PackageFiles()
+{
+ // TODO: Use toplevel ?
+ // It is used! Is this an obsolete comment?
+
+ const char* cpackPackageExecutables =
+ this->GetOption("CPACK_PACKAGE_EXECUTABLES");
+ if (cpackPackageExecutables) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "The cpackPackageExecutables: " << cpackPackageExecutables
+ << "." << std::endl);
+ std::ostringstream str;
+ std::ostringstream deleteStr;
+ std::vector<std::string> cpackPackageExecutablesVector =
+ cmExpandedList(cpackPackageExecutables);
+ if (cpackPackageExecutablesVector.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
+ "<icon name>."
+ << std::endl);
+ return 0;
+ }
+ std::vector<std::string>::iterator it;
+ for (it = cpackPackageExecutablesVector.begin();
+ it != cpackPackageExecutablesVector.end(); ++it) {
+ std::string cpackExecutableName = *it;
+ ++it;
+ this->SetOptionIfNotSet("CPACK_EXECUTABLE_NAME",
+ cpackExecutableName.c_str());
+ }
+ }
+
+ // Disk image directories
+ std::string diskImageDirectory = toplevel;
+ std::string diskImageBackgroundImageDir =
+ diskImageDirectory + "/.background";
+
+ // App bundle directories
+ std::string packageDirFileName = cmStrCat(
+ toplevel, '/', this->GetOption("CPACK_PACKAGE_FILE_NAME"), ".app");
+ std::string contentsDirectory = packageDirFileName + "/Contents";
+ std::string resourcesDirectory = contentsDirectory + "/Resources";
+ std::string appDirectory = contentsDirectory + "/MacOS";
+ std::string scriptDirectory = resourcesDirectory + "/Scripts";
+ std::string resourceFileName =
+ cmStrCat(this->GetOption("CPACK_PACKAGE_FILE_NAME"), ".rsrc");
+
+ const char* dir = resourcesDirectory.c_str();
+ const char* appdir = appDirectory.c_str();
+ const char* scrDir = scriptDirectory.c_str();
+ const char* contDir = contentsDirectory.c_str();
+ const char* rsrcFile = resourceFileName.c_str();
+ const char* iconFile = this->GetOption("CPACK_PACKAGE_ICON");
+ if (iconFile) {
+ std::string iconFileName = cmsys::SystemTools::GetFilenameName(iconFile);
+ if (!cmSystemTools::FileExists(iconFile)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find icon file: "
+ << iconFile
+ << ". Please check CPACK_PACKAGE_ICON setting."
+ << std::endl);
+ return 0;
+ }
+ std::string destFileName = resourcesDirectory + "/" + iconFileName;
+ this->ConfigureFile(iconFile, destFileName, true);
+ this->SetOptionIfNotSet("CPACK_APPLE_GUI_ICON", iconFileName.c_str());
+ }
+
+ std::string applicationsLinkName = diskImageDirectory + "/Applications";
+ cmSystemTools::CreateSymlink("/Applications", applicationsLinkName);
+
+ if (!this->CopyResourcePlistFile("VolumeIcon.icns", diskImageDirectory,
+ ".VolumeIcon.icns", true) ||
+ !this->CopyResourcePlistFile("DS_Store", diskImageDirectory, ".DS_Store",
+ true) ||
+ !this->CopyResourcePlistFile("background.png",
+ diskImageBackgroundImageDir,
+ "background.png", true) ||
+ !this->CopyResourcePlistFile("RuntimeScript", dir) ||
+ !this->CopyResourcePlistFile("OSXX11.Info.plist", contDir,
+ "Info.plist") ||
+ !this->CopyResourcePlistFile("OSXX11.main.scpt", scrDir, "main.scpt",
+ true) ||
+ !this->CopyResourcePlistFile("OSXScriptLauncher.rsrc", dir, rsrcFile,
+ true) ||
+ !this->CopyResourcePlistFile("OSXScriptLauncher", appdir,
+ this->GetOption("CPACK_PACKAGE_FILE_NAME"),
+ true)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem copying the resource files" << std::endl);
+ return 0;
+ }
+
+ // Two of the files need to have execute permission, so ensure they do:
+ std::string runTimeScript = cmStrCat(dir, "/RuntimeScript");
+
+ std::string appScriptName =
+ cmStrCat(appdir, '/', this->GetOption("CPACK_PACKAGE_FILE_NAME"));
+
+ mode_t mode;
+ if (cmsys::SystemTools::GetPermissions(runTimeScript.c_str(), mode)) {
+ mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
+ cmsys::SystemTools::SetPermissions(runTimeScript.c_str(), mode);
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "Setting: " << runTimeScript << " to permission: " << mode
+ << std::endl);
+ }
+
+ if (cmsys::SystemTools::GetPermissions(appScriptName.c_str(), mode)) {
+ mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
+ cmsys::SystemTools::SetPermissions(appScriptName.c_str(), mode);
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "Setting: " << appScriptName << " to permission: " << mode
+ << std::endl);
+ }
+
+ std::string output;
+ std::string tmpFile = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
+ "/hdiutilOutput.log");
+ std::ostringstream dmgCmd;
+ dmgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM_DISK_IMAGE")
+ << "\" create -ov -fs HFS+ -format UDZO -srcfolder \""
+ << diskImageDirectory << "\" \"" << packageFileNames[0] << "\"";
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Compress disk image using command: " << dmgCmd.str()
+ << std::endl);
+ // since we get random dashboard failures with this one
+ // try running it more than once
+ int retVal = 1;
+ int numTries = 10;
+ bool res = false;
+ while (numTries > 0) {
+ res = cmSystemTools::RunSingleCommand(
+ dmgCmd.str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
+ if (res && !retVal) {
+ numTries = -1;
+ break;
+ }
+ cmSystemTools::Delay(500);
+ numTries--;
+ }
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile);
+ ofs << "# Run command: " << dmgCmd.str() << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem running hdiutil command: "
+ << dmgCmd.str() << std::endl
+ << "Please check " << tmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+
+ return 1;
+}
+
+int cmCPackOSXX11Generator::InitializeInternal()
+{
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "The OSXX11 generator is deprecated "
+ "and will be removed in a future version.\n");
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "cmCPackOSXX11Generator::Initialize()" << std::endl);
+ std::vector<std::string> path;
+ std::string pkgPath = cmSystemTools::FindProgram("hdiutil", path, false);
+ if (pkgPath.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find hdiutil compiler" << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE",
+ pkgPath.c_str());
+
+ return this->Superclass::InitializeInternal();
+}
+
+/*
+bool cmCPackOSXX11Generator::CopyCreateResourceFile(const std::string& name)
+{
+ std::string uname = cmSystemTools::UpperCase(name);
+ std::string cpackVar = "CPACK_RESOURCE_FILE_" + uname;
+ const char* inFileName = this->GetOption(cpackVar.c_str());
+ if ( !inFileName )
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "CPack option: " << cpackVar.c_str()
+ << " not specified. It should point to "
+ << (name ? name : "(NULL)")
+ << ".rtf, " << name
+ << ".html, or " << name << ".txt file" << std::endl);
+ return false;
+ }
+ if ( !cmSystemTools::FileExists(inFileName) )
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find "
+ << (name ? name : "(NULL)")
+ << " resource file: " << inFileName << std::endl);
+ return false;
+ }
+ std::string ext = cmSystemTools::GetFilenameLastExtension(inFileName);
+ if ( ext != ".rtfd" && ext != ".rtf" && ext != ".html" && ext != ".txt" )
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Bad file extension specified: "
+ << ext << ". Currently only .rtfd, .rtf, .html, and .txt files allowed."
+ << std::endl);
+ return false;
+ }
+
+ std::string destFileName = cmStrCat(
+this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/Resources/", name, ext );
+
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
+ << (inFileName ? inFileName : "(NULL)")
+ << " to " << destFileName << std::endl);
+ this->ConfigureFile(inFileName, destFileName);
+ return true;
+}
+*/
+
+bool cmCPackOSXX11Generator::CopyResourcePlistFile(
+ const std::string& name, const std::string& dir,
+ const char* outputFileName /* = 0 */, bool copyOnly /* = false */)
+{
+ std::string inFName = cmStrCat("CPack.", name, ".in");
+ std::string inFileName = this->FindTemplate(inFName.c_str());
+ if (inFileName.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find input file: " << inFName << std::endl);
+ return false;
+ }
+
+ if (!outputFileName) {
+ outputFileName = name.c_str();
+ }
+
+ std::string destFileName = cmStrCat(dir, '/', outputFileName);
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Configure file: " << inFileName << " to " << destFileName
+ << std::endl);
+ this->ConfigureFile(inFileName, destFileName, copyOnly);
+ return true;
+}
+
+const char* cmCPackOSXX11Generator::GetPackagingInstallPrefix()
+{
+ this->InstallPrefix =
+ cmStrCat('/', this->GetOption("CPACK_PACKAGE_FILE_NAME"),
+ ".app/Contents/Resources");
+ return this->InstallPrefix.c_str();
+}
diff --git a/Source/CPack/cmCPackOSXX11Generator.h b/Source/CPack/cmCPackOSXX11Generator.h
new file mode 100644
index 0000000..8fae136
--- /dev/null
+++ b/Source/CPack/cmCPackOSXX11Generator.h
@@ -0,0 +1,39 @@
+/* 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 <string>
+
+#include "cmCPackGenerator.h"
+
+/** \class cmCPackOSXX11Generator
+ * \brief A generator for OSX X11 modules
+ *
+ * Based on Gimp.app
+ */
+class cmCPackOSXX11Generator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackOSXX11Generator, cmCPackGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackOSXX11Generator();
+ ~cmCPackOSXX11Generator() override;
+
+protected:
+ virtual int InitializeInternal() override;
+ int PackageFiles() override;
+ const char* GetPackagingInstallPrefix() override;
+ const char* GetOutputExtension() override { return ".dmg"; }
+
+ // bool CopyCreateResourceFile(const std::string& name,
+ // const std::string& dir);
+ bool CopyResourcePlistFile(const std::string& name, const std::string& dir,
+ const char* outputFileName = 0,
+ bool copyOnly = false);
+ std::string InstallPrefix;
+};
diff --git a/Source/CPack/cmCPackPKGGenerator.cxx b/Source/CPack/cmCPackPKGGenerator.cxx
new file mode 100644
index 0000000..ac3d64d
--- /dev/null
+++ b/Source/CPack/cmCPackPKGGenerator.cxx
@@ -0,0 +1,396 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackPKGGenerator.h"
+
+#include <vector>
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackGenerator.h"
+#include "cmCPackLog.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+
+cmCPackPKGGenerator::cmCPackPKGGenerator()
+{
+ this->componentPackageMethod = ONE_PACKAGE;
+}
+
+cmCPackPKGGenerator::~cmCPackPKGGenerator() = default;
+
+bool cmCPackPKGGenerator::SupportsComponentInstallation() const
+{
+ return true;
+}
+
+int cmCPackPKGGenerator::InitializeInternal()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "cmCPackPKGGenerator::Initialize()" << std::endl);
+
+ return this->Superclass::InitializeInternal();
+}
+
+std::string cmCPackPKGGenerator::GetPackageName(
+ const cmCPackComponent& component)
+{
+ if (component.ArchiveFile.empty()) {
+ std::string packagesDir =
+ cmStrCat(this->GetOption("CPACK_TEMPORARY_DIRECTORY"), ".dummy");
+ std::ostringstream out;
+ out << cmSystemTools::GetFilenameWithoutLastExtension(packagesDir) << "-"
+ << component.Name << ".pkg";
+ return out.str();
+ }
+
+ return component.ArchiveFile + ".pkg";
+}
+
+void cmCPackPKGGenerator::CreateBackground(const char* themeName,
+ const char* metapackageFile,
+ cm::string_view genName,
+ cmXMLWriter& xout)
+{
+ std::string paramSuffix =
+ (themeName == nullptr) ? "" : cmSystemTools::UpperCase(themeName);
+ std::string opt = (themeName == nullptr)
+ ? cmStrCat("CPACK_", genName, "_BACKGROUND")
+ : cmStrCat("CPACK_", genName, "_BACKGROUND_", paramSuffix);
+ const char* bgFileName = this->GetOption(opt);
+ if (bgFileName == nullptr) {
+ return;
+ }
+
+ std::string bgFilePath = cmStrCat(metapackageFile, "/Contents/", bgFileName);
+
+ if (!cmSystemTools::FileExists(bgFilePath)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Background image doesn't exist in the resource directory: "
+ << bgFileName << std::endl);
+ return;
+ }
+
+ if (themeName == nullptr) {
+ xout.StartElement("background");
+ } else {
+ xout.StartElement(cmStrCat("background-", themeName));
+ }
+
+ xout.Attribute("file", bgFileName);
+
+ const char* param = this->GetOption(cmStrCat(opt, "_ALIGNMENT"));
+ if (param != nullptr) {
+ xout.Attribute("alignment", param);
+ }
+
+ param = this->GetOption(cmStrCat(opt, "_SCALING"));
+ if (param != nullptr) {
+ xout.Attribute("scaling", param);
+ }
+
+ // Apple docs say that you must provide either mime-type or uti
+ // attribute for the background, but I've seen examples that
+ // doesn't have them, so don't make them mandatory.
+ param = this->GetOption(cmStrCat(opt, "_MIME_TYPE"));
+ if (param != nullptr) {
+ xout.Attribute("mime-type", param);
+ }
+
+ param = this->GetOption(cmStrCat(opt, "_UTI"));
+ if (param != nullptr) {
+ xout.Attribute("uti", param);
+ }
+
+ xout.EndElement();
+}
+
+void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile,
+ const char* genName)
+{
+ std::string distributionTemplate =
+ this->FindTemplate("CPack.distribution.dist.in");
+ if (distributionTemplate.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find input file: " << distributionTemplate
+ << std::endl);
+ return;
+ }
+
+ std::string distributionFile =
+ cmStrCat(metapackageFile, "/Contents/distribution.dist");
+
+ // Create the choice outline, which provides a tree-based view of
+ // the components in their groups.
+ std::ostringstream choiceOut;
+ cmXMLWriter xout(choiceOut, 1);
+ xout.StartElement("choices-outline");
+
+ // Emit the outline for the groups
+ for (auto const& group : this->ComponentGroups) {
+ if (group.second.ParentGroup == nullptr) {
+ CreateChoiceOutline(group.second, xout);
+ }
+ }
+
+ // Emit the outline for the non-grouped components
+ for (auto const& comp : this->Components) {
+ if (!comp.second.Group) {
+ xout.StartElement("line");
+ xout.Attribute("choice", comp.first + "Choice");
+ xout.Content(""); // Avoid self-closing tag.
+ xout.EndElement();
+ }
+ }
+ if (!this->PostFlightComponent.Name.empty()) {
+ xout.StartElement("line");
+ xout.Attribute("choice", PostFlightComponent.Name + "Choice");
+ xout.Content(""); // Avoid self-closing tag.
+ xout.EndElement();
+ }
+ xout.EndElement(); // choices-outline>
+
+ // Create the actual choices
+ for (auto const& group : this->ComponentGroups) {
+ CreateChoice(group.second, xout);
+ }
+ for (auto const& comp : this->Components) {
+ CreateChoice(comp.second, xout);
+ }
+
+ if (!this->PostFlightComponent.Name.empty()) {
+ CreateChoice(PostFlightComponent, xout);
+ }
+
+ // default background
+ this->CreateBackground(nullptr, metapackageFile, genName, xout);
+ // Dark Aqua
+ this->CreateBackground("darkAqua", metapackageFile, genName, xout);
+
+ this->SetOption("CPACK_PACKAGEMAKER_CHOICES", choiceOut.str().c_str());
+
+ // Create the distribution.dist file in the metapackage to turn it
+ // into a distribution package.
+ this->ConfigureFile(distributionTemplate, distributionFile);
+}
+
+void cmCPackPKGGenerator::CreateChoiceOutline(
+ const cmCPackComponentGroup& group, cmXMLWriter& xout)
+{
+ xout.StartElement("line");
+ xout.Attribute("choice", group.Name + "Choice");
+ for (cmCPackComponentGroup* subgroup : group.Subgroups) {
+ CreateChoiceOutline(*subgroup, xout);
+ }
+
+ for (cmCPackComponent* comp : group.Components) {
+ xout.StartElement("line");
+ xout.Attribute("choice", comp->Name + "Choice");
+ xout.Content(""); // Avoid self-closing tag.
+ xout.EndElement();
+ }
+ xout.EndElement();
+}
+
+void cmCPackPKGGenerator::CreateChoice(const cmCPackComponentGroup& group,
+ cmXMLWriter& xout)
+{
+ xout.StartElement("choice");
+ xout.Attribute("id", group.Name + "Choice");
+ xout.Attribute("title", group.DisplayName);
+ xout.Attribute("start_selected", "true");
+ xout.Attribute("start_enabled", "true");
+ xout.Attribute("start_visible", "true");
+ if (!group.Description.empty()) {
+ xout.Attribute("description", group.Description);
+ }
+ xout.EndElement();
+}
+
+void cmCPackPKGGenerator::CreateChoice(const cmCPackComponent& component,
+ cmXMLWriter& xout)
+{
+ std::string packageId =
+ cmStrCat("com.", this->GetOption("CPACK_PACKAGE_VENDOR"), '.',
+ this->GetOption("CPACK_PACKAGE_NAME"), '.', component.Name);
+
+ xout.StartElement("choice");
+ xout.Attribute("id", component.Name + "Choice");
+ xout.Attribute("title", component.DisplayName);
+ xout.Attribute(
+ "start_selected",
+ component.IsDisabledByDefault && !component.IsRequired ? "false" : "true");
+ xout.Attribute("start_enabled", component.IsRequired ? "false" : "true");
+ xout.Attribute("start_visible", component.IsHidden ? "false" : "true");
+ if (!component.Description.empty()) {
+ xout.Attribute("description", component.Description);
+ }
+ if (!component.Dependencies.empty() ||
+ !component.ReverseDependencies.empty()) {
+ // The "selected" expression is evaluated each time any choice is
+ // selected, for all choices *except* the one that the user
+ // selected. A component is marked selected if it has been
+ // selected (my.choice.selected in Javascript) and all of the
+ // components it depends on have been selected (transitively) or
+ // if any of the components that depend on it have been selected
+ // (transitively). Assume that we have components A, B, C, D, and
+ // E, where each component depends on the previous component (B
+ // depends on A, C depends on B, D depends on C, and E depends on
+ // D). The expression we build for the component C will be
+ // my.choice.selected && B && A || D || E
+ // This way, selecting C will automatically select everything it depends
+ // on (B and A), while selecting something that depends on C--either D
+ // or E--will automatically cause C to get selected.
+ std::ostringstream selected("my.choice.selected", std::ios_base::ate);
+ std::set<const cmCPackComponent*> visited;
+ AddDependencyAttributes(component, visited, selected);
+ visited.clear();
+ AddReverseDependencyAttributes(component, visited, selected);
+ xout.Attribute("selected", selected.str());
+ }
+ xout.StartElement("pkg-ref");
+ xout.Attribute("id", packageId);
+ xout.EndElement(); // pkg-ref
+ xout.EndElement(); // choice
+
+ // Create a description of the package associated with this
+ // component.
+ std::string relativePackageLocation =
+ cmStrCat("Contents/Packages/", this->GetPackageName(component));
+
+ // Determine the installed size of the package.
+ std::string dirName =
+ cmStrCat(this->GetOption("CPACK_TEMPORARY_DIRECTORY"), '/', component.Name,
+ this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX"));
+ unsigned long installedSize = component.GetInstalledSizeInKbytes(dirName);
+
+ xout.StartElement("pkg-ref");
+ xout.Attribute("id", packageId);
+ xout.Attribute("version", this->GetOption("CPACK_PACKAGE_VERSION"));
+ xout.Attribute("installKBytes", installedSize);
+ xout.Attribute("auth", "Admin");
+ xout.Attribute("onConclusion", "None");
+ if (component.IsDownloaded) {
+ xout.Content(this->GetOption("CPACK_DOWNLOAD_SITE"));
+ xout.Content(this->GetPackageName(component));
+ } else {
+ xout.Content("file:./");
+ xout.Content(cmSystemTools::EncodeURL(relativePackageLocation,
+ /*escapeSlashes=*/false));
+ }
+ xout.EndElement(); // pkg-ref
+}
+
+void cmCPackPKGGenerator::AddDependencyAttributes(
+ const cmCPackComponent& component,
+ std::set<const cmCPackComponent*>& visited, std::ostringstream& out)
+{
+ if (visited.find(&component) != visited.end()) {
+ return;
+ }
+ visited.insert(&component);
+
+ for (cmCPackComponent* depend : component.Dependencies) {
+ out << " && choices['" << depend->Name << "Choice'].selected";
+ AddDependencyAttributes(*depend, visited, out);
+ }
+}
+
+void cmCPackPKGGenerator::AddReverseDependencyAttributes(
+ const cmCPackComponent& component,
+ std::set<const cmCPackComponent*>& visited, std::ostringstream& out)
+{
+ if (visited.find(&component) != visited.end()) {
+ return;
+ }
+ visited.insert(&component);
+
+ for (cmCPackComponent* depend : component.ReverseDependencies) {
+ out << " || choices['" << depend->Name << "Choice'].selected";
+ AddReverseDependencyAttributes(*depend, visited, out);
+ }
+}
+
+bool cmCPackPKGGenerator::CopyCreateResourceFile(const std::string& name,
+ const std::string& dirName)
+{
+ std::string uname = cmSystemTools::UpperCase(name);
+ std::string cpackVar = "CPACK_RESOURCE_FILE_" + uname;
+ const char* inFileName = this->GetOption(cpackVar);
+ if (!inFileName) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPack option: " << cpackVar.c_str()
+ << " not specified. It should point to "
+ << (!name.empty() ? name : "<empty>")
+ << ".rtf, " << name << ".html, or " << name
+ << ".txt file" << std::endl);
+ return false;
+ }
+ if (!cmSystemTools::FileExists(inFileName)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find " << (!name.empty() ? name : "<empty>")
+ << " resource file: " << inFileName
+ << std::endl);
+ return false;
+ }
+ std::string ext = cmSystemTools::GetFilenameLastExtension(inFileName);
+ if (ext != ".rtfd" && ext != ".rtf" && ext != ".html" && ext != ".txt") {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Bad file extension specified: "
+ << ext
+ << ". Currently only .rtfd, .rtf, .html, and .txt files allowed."
+ << std::endl);
+ return false;
+ }
+
+ std::string destFileName = cmStrCat(dirName, '/', name, ext);
+
+ // Set this so that distribution.dist gets the right name (without
+ // the path).
+ this->SetOption("CPACK_RESOURCE_FILE_" + uname + "_NOPATH",
+ (name + ext).c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Configure file: " << (inFileName ? inFileName : "(NULL)")
+ << " to " << destFileName << std::endl);
+ this->ConfigureFile(inFileName, destFileName);
+ return true;
+}
+
+bool cmCPackPKGGenerator::CopyResourcePlistFile(const std::string& name,
+ const char* outName)
+{
+ if (!outName) {
+ outName = name.c_str();
+ }
+
+ std::string inFName = cmStrCat("CPack.", name, ".in");
+ std::string inFileName = this->FindTemplate(inFName.c_str());
+ if (inFileName.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find input file: " << inFName << std::endl);
+ return false;
+ }
+
+ std::string destFileName =
+ cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/', outName);
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Configure file: " << inFileName << " to " << destFileName
+ << std::endl);
+ this->ConfigureFile(inFileName, destFileName);
+ return true;
+}
+
+int cmCPackPKGGenerator::CopyInstallScript(const std::string& resdir,
+ const std::string& script,
+ const std::string& name)
+{
+ std::string dst = cmStrCat(resdir, '/', name);
+ cmSystemTools::CopyFileAlways(script, dst);
+ cmSystemTools::SetPermissions(dst.c_str(), 0777);
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "copy script : " << script << "\ninto " << dst << std::endl);
+
+ return 1;
+}
diff --git a/Source/CPack/cmCPackPKGGenerator.h b/Source/CPack/cmCPackPKGGenerator.h
new file mode 100644
index 0000000..17cdcdf
--- /dev/null
+++ b/Source/CPack/cmCPackPKGGenerator.h
@@ -0,0 +1,95 @@
+/* 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 <sstream>
+#include <string>
+
+#include <cm/string_view>
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackGenerator.h"
+
+class cmXMLWriter;
+
+/** \class cmCPackPKGGenerator
+ * \brief A generator for pkg files
+ *
+ */
+class cmCPackPKGGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackPKGGenerator, cmCPackGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackPKGGenerator();
+ ~cmCPackPKGGenerator() override;
+
+ bool SupportsComponentInstallation() const override;
+
+protected:
+ int InitializeInternal() override;
+ const char* GetOutputPostfix() override { return "darwin"; }
+
+ // Copies or creates the resource file with the given name to the
+ // package or package staging directory dirName. The variable
+ // CPACK_RESOURCE_FILE_${NAME} (where ${NAME} is the uppercased
+ // version of name) specifies the input file to use for this file,
+ // which will be configured via ConfigureFile.
+ bool CopyCreateResourceFile(const std::string& name,
+ const std::string& dirName);
+ bool CopyResourcePlistFile(const std::string& name, const char* outName = 0);
+
+ int CopyInstallScript(const std::string& resdir, const std::string& script,
+ const std::string& name);
+
+ // Retrieve the name of package file that will be generated for this
+ // component. The name is just the file name with extension, and
+ // does not include the subdirectory.
+ std::string GetPackageName(const cmCPackComponent& component);
+
+ // Writes a distribution.dist file, which turns a metapackage into a
+ // full-fledged distribution. This file is used to describe
+ // inter-component dependencies. metapackageFile is the name of the
+ // metapackage for the distribution. Only valid for a
+ // component-based install.
+ void WriteDistributionFile(const char* metapackageFile, const char* genName);
+
+ // Subroutine of WriteDistributionFile that writes out the
+ // dependency attributes for inter-component dependencies.
+ void AddDependencyAttributes(const cmCPackComponent& component,
+ std::set<const cmCPackComponent*>& visited,
+ std::ostringstream& out);
+
+ // Subroutine of WriteDistributionFile that writes out the
+ // reverse dependency attributes for inter-component dependencies.
+ void AddReverseDependencyAttributes(
+ const cmCPackComponent& component,
+ std::set<const cmCPackComponent*>& visited, std::ostringstream& out);
+
+ // Generates XML that encodes the hierarchy of component groups and
+ // their components in a form that can be used by distribution
+ // metapackages.
+ void CreateChoiceOutline(const cmCPackComponentGroup& group,
+ cmXMLWriter& xout);
+
+ /// Create the "choice" XML element to describe a component group
+ /// for the installer GUI.
+ void CreateChoice(const cmCPackComponentGroup& group, cmXMLWriter& xout);
+
+ /// Create the "choice" XML element to describe a component for the
+ /// installer GUI.
+ void CreateChoice(const cmCPackComponent& component, cmXMLWriter& xout);
+
+ /// Creates a background in the distribution XML.
+ void CreateBackground(const char* themeName, const char* metapackageFile,
+ cm::string_view genName, cmXMLWriter& xout);
+
+ // The PostFlight component when creating a metapackage
+ cmCPackComponent PostFlightComponent;
+};
diff --git a/Source/CPack/cmCPackPackageMakerGenerator.cxx b/Source/CPack/cmCPackPackageMakerGenerator.cxx
new file mode 100644
index 0000000..f51ea42
--- /dev/null
+++ b/Source/CPack/cmCPackPackageMakerGenerator.cxx
@@ -0,0 +1,578 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackPackageMakerGenerator.h"
+
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <map>
+#include <sstream>
+#include <string>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmDuration.h"
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+
+static inline unsigned int getVersion(unsigned int major, unsigned int minor)
+{
+ assert(major < 256 && minor < 256);
+ return ((major & 0xFF) << 16 | minor);
+}
+
+cmCPackPackageMakerGenerator::cmCPackPackageMakerGenerator()
+{
+ this->PackageMakerVersion = 0.0;
+ this->PackageCompatibilityVersion = getVersion(10, 4);
+}
+
+cmCPackPackageMakerGenerator::~cmCPackPackageMakerGenerator() = default;
+
+bool cmCPackPackageMakerGenerator::SupportsComponentInstallation() const
+{
+ return this->PackageCompatibilityVersion >= getVersion(10, 4);
+}
+
+int cmCPackPackageMakerGenerator::PackageFiles()
+{
+ // TODO: Use toplevel
+ // It is used! Is this an obsolete comment?
+
+ std::string resDir; // Where this package's resources will go.
+ std::string packageDirFileName =
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ if (this->Components.empty()) {
+ packageDirFileName += ".pkg";
+ resDir =
+ cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/Resources");
+ } else {
+ packageDirFileName += ".mpkg";
+ if (!cmsys::SystemTools::MakeDirectory(packageDirFileName.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "unable to create package directory " << packageDirFileName
+ << std::endl);
+ return 0;
+ }
+
+ resDir = cmStrCat(packageDirFileName, "/Contents");
+ if (!cmsys::SystemTools::MakeDirectory(resDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "unable to create package subdirectory " << resDir
+ << std::endl);
+ return 0;
+ }
+
+ resDir += "/Resources";
+ if (!cmsys::SystemTools::MakeDirectory(resDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "unable to create package subdirectory " << resDir
+ << std::endl);
+ return 0;
+ }
+
+ resDir += "/en.lproj";
+ }
+
+ const char* preflight = this->GetOption("CPACK_PREFLIGHT_SCRIPT");
+ const char* postflight = this->GetOption("CPACK_POSTFLIGHT_SCRIPT");
+ const char* postupgrade = this->GetOption("CPACK_POSTUPGRADE_SCRIPT");
+
+ if (this->Components.empty()) {
+ // Create directory structure
+ std::string preflightDirName = resDir + "/PreFlight";
+ std::string postflightDirName = resDir + "/PostFlight";
+ // if preflight or postflight scripts not there create directories
+ // of the same name, I think this makes it work
+ if (!preflight) {
+ if (!cmsys::SystemTools::MakeDirectory(preflightDirName.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating installer directory: "
+ << preflightDirName << std::endl);
+ return 0;
+ }
+ }
+ if (!postflight) {
+ if (!cmsys::SystemTools::MakeDirectory(postflightDirName.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating installer directory: "
+ << postflightDirName << std::endl);
+ return 0;
+ }
+ }
+ // if preflight, postflight, or postupgrade are set
+ // then copy them into the resource directory and make
+ // them executable
+ if (preflight) {
+ this->CopyInstallScript(resDir, preflight, "preflight");
+ }
+ if (postflight) {
+ this->CopyInstallScript(resDir, postflight, "postflight");
+ }
+ if (postupgrade) {
+ this->CopyInstallScript(resDir, postupgrade, "postupgrade");
+ }
+ } else if (postflight) {
+ // create a postflight component to house the script
+ this->PostFlightComponent.Name = "PostFlight";
+ this->PostFlightComponent.DisplayName = "PostFlight";
+ this->PostFlightComponent.Description = "PostFlight";
+ this->PostFlightComponent.IsHidden = true;
+
+ // empty directory for pkg contents
+ std::string packageDir = toplevel + "/" + PostFlightComponent.Name;
+ if (!cmsys::SystemTools::MakeDirectory(packageDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating component packages directory: "
+ << packageDir << std::endl);
+ return 0;
+ }
+
+ // create package
+ std::string packageFileDir = packageDirFileName + "/Contents/Packages/";
+ if (!cmsys::SystemTools::MakeDirectory(packageFileDir.c_str())) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Problem creating component PostFlight Packages directory: "
+ << packageFileDir << std::endl);
+ return 0;
+ }
+ std::string packageFile =
+ packageFileDir + this->GetPackageName(PostFlightComponent);
+ if (!this->GenerateComponentPackage(
+ packageFile.c_str(), packageDir.c_str(), PostFlightComponent)) {
+ return 0;
+ }
+
+ // copy postflight script into resource directory of .pkg
+ std::string resourceDir = packageFile + "/Contents/Resources";
+ this->CopyInstallScript(resourceDir, postflight, "postflight");
+ }
+
+ if (!this->Components.empty()) {
+ // Create the directory where component packages will be built.
+ std::string basePackageDir =
+ cmStrCat(packageDirFileName, "/Contents/Packages");
+ if (!cmsys::SystemTools::MakeDirectory(basePackageDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating component packages directory: "
+ << basePackageDir << std::endl);
+ return 0;
+ }
+
+ // Create the directory where downloaded component packages will
+ // be placed.
+ const char* userUploadDirectory =
+ this->GetOption("CPACK_UPLOAD_DIRECTORY");
+ std::string uploadDirectory;
+ if (userUploadDirectory && *userUploadDirectory) {
+ uploadDirectory = userUploadDirectory;
+ } else {
+ uploadDirectory =
+ cmStrCat(this->GetOption("CPACK_PACKAGE_DIRECTORY"), "/CPackUploads");
+ }
+
+ // Create packages for each component
+ bool warnedAboutDownloadCompatibility = false;
+
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ std::string packageFile;
+ if (compIt->second.IsDownloaded) {
+ if (this->PackageCompatibilityVersion >= getVersion(10, 5) &&
+ this->PackageMakerVersion >= 3.0) {
+ // Build this package within the upload directory.
+ packageFile = uploadDirectory;
+
+ if (!cmSystemTools::FileExists(uploadDirectory.c_str())) {
+ if (!cmSystemTools::MakeDirectory(uploadDirectory.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Unable to create package upload directory "
+ << uploadDirectory << std::endl);
+ return 0;
+ }
+ }
+ } else if (!warnedAboutDownloadCompatibility) {
+ if (this->PackageCompatibilityVersion < getVersion(10, 5)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING,
+ "CPack warning: please set CPACK_OSX_PACKAGE_VERSION to 10.5 "
+ "or greater enable downloaded packages. CPack will build a "
+ "non-downloaded package."
+ << std::endl);
+ }
+
+ if (this->PackageMakerVersion < 3) {
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "CPack warning: unable to build downloaded "
+ "packages with PackageMaker versions prior "
+ "to 3.0. CPack will build a non-downloaded package."
+ << std::endl);
+ }
+
+ warnedAboutDownloadCompatibility = true;
+ }
+ }
+
+ if (packageFile.empty()) {
+ // Build this package within the overall distribution
+ // metapackage.
+ packageFile = basePackageDir;
+
+ // We're not downloading this component, even if the user
+ // requested it.
+ compIt->second.IsDownloaded = false;
+ }
+
+ packageFile += '/';
+ packageFile += GetPackageName(compIt->second);
+
+ std::string packageDir = cmStrCat(toplevel, '/', compIt->first);
+ if (!this->GenerateComponentPackage(
+ packageFile.c_str(), packageDir.c_str(), compIt->second)) {
+ return 0;
+ }
+ }
+ }
+ this->SetOption("CPACK_MODULE_VERSION_SUFFIX", "");
+
+ // Copy or create all of the resource files we need.
+ if (!this->CopyCreateResourceFile("License", resDir) ||
+ !this->CopyCreateResourceFile("ReadMe", resDir) ||
+ !this->CopyCreateResourceFile("Welcome", resDir) ||
+ !this->CopyResourcePlistFile("Info.plist") ||
+ !this->CopyResourcePlistFile("Description.plist")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem copying the resource files" << std::endl);
+ return 0;
+ }
+
+ if (this->Components.empty()) {
+ // Use PackageMaker to build the package.
+ std::ostringstream pkgCmd;
+ pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")
+ << "\" -build -p \"" << packageDirFileName << "\"";
+ if (this->Components.empty()) {
+ pkgCmd << " -f \"" << this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ } else {
+ pkgCmd << " -mi \"" << this->GetOption("CPACK_TEMPORARY_DIRECTORY")
+ << "/packages/";
+ }
+ pkgCmd << "\" -r \"" << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")
+ << "/Resources\" -i \""
+ << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")
+ << "/Info.plist\" -d \""
+ << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")
+ << "/Description.plist\"";
+ if (this->PackageMakerVersion > 2.0) {
+ pkgCmd << " -v";
+ }
+ if (!RunPackageMaker(pkgCmd.str().c_str(), packageDirFileName.c_str())) {
+ return 0;
+ }
+ } else {
+ // We have built the package in place. Generate the
+ // distribution.dist file to describe it for the installer.
+ WriteDistributionFile(packageDirFileName.c_str(), "PACKAGEMAKER");
+ }
+
+ std::string tmpFile = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
+ "/hdiutilOutput.log");
+ std::ostringstream dmgCmd;
+ dmgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM_DISK_IMAGE")
+ << "\" create -ov -fs HFS+ -format UDZO -srcfolder \""
+ << packageDirFileName << "\" \"" << packageFileNames[0] << "\"";
+ std::string output;
+ int retVal = 1;
+ int numTries = 10;
+ bool res = false;
+ while (numTries > 0) {
+ res = cmSystemTools::RunSingleCommand(
+ dmgCmd.str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
+ if (res && !retVal) {
+ numTries = -1;
+ break;
+ }
+ cmSystemTools::Delay(500);
+ numTries--;
+ }
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile);
+ ofs << "# Run command: " << dmgCmd.str() << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem running hdiutil command: "
+ << dmgCmd.str() << std::endl
+ << "Please check " << tmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+
+ return 1;
+}
+
+int cmCPackPackageMakerGenerator::InitializeInternal()
+{
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "The PackageMaker generator is deprecated "
+ "and will be removed in a future version.\n");
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
+
+ // Starting with Xcode 4.3, PackageMaker is a separate app, and you
+ // can put it anywhere you want. So... use a variable for its location.
+ // People who put it in unexpected places can use the variable to tell
+ // us where it is.
+ //
+ // Use the following locations, in "most recent installation" order,
+ // to search for the PackageMaker app. Assume people who copy it into
+ // the new Xcode 4.3 app in "/Applications" will copy it into the nested
+ // Applications folder inside the Xcode bundle itself. Or directly in
+ // the "/Applications" directory.
+ //
+ // If found, save result in the CPACK_INSTALLER_PROGRAM variable.
+
+ std::vector<std::string> paths;
+ paths.emplace_back("/Applications/Xcode.app/Contents/Applications"
+ "/PackageMaker.app/Contents/MacOS");
+ paths.emplace_back("/Applications/Utilities"
+ "/PackageMaker.app/Contents/MacOS");
+ paths.emplace_back("/Applications"
+ "/PackageMaker.app/Contents/MacOS");
+ paths.emplace_back("/Developer/Applications/Utilities"
+ "/PackageMaker.app/Contents/MacOS");
+ paths.emplace_back("/Developer/Applications"
+ "/PackageMaker.app/Contents/MacOS");
+
+ std::string pkgPath;
+ const char* inst_program = this->GetOption("CPACK_INSTALLER_PROGRAM");
+ if (inst_program && *inst_program) {
+ pkgPath = inst_program;
+ } else {
+ pkgPath = cmSystemTools::FindProgram("PackageMaker", paths, false);
+ if (pkgPath.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find PackageMaker compiler" << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", pkgPath.c_str());
+ }
+
+ // Get path to the real PackageMaker, not a symlink:
+ pkgPath = cmSystemTools::GetRealPath(pkgPath);
+ // Up from there to find the version.plist file in the "Contents" dir:
+ std::string contents_dir;
+ contents_dir = cmSystemTools::GetFilenamePath(pkgPath);
+ contents_dir = cmSystemTools::GetFilenamePath(contents_dir);
+
+ std::string versionFile = contents_dir + "/version.plist";
+
+ if (!cmSystemTools::FileExists(versionFile.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find PackageMaker compiler version file: "
+ << versionFile << std::endl);
+ return 0;
+ }
+
+ cmsys::ifstream ifs(versionFile.c_str());
+ if (!ifs) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot open PackageMaker compiler version file"
+ << std::endl);
+ return 0;
+ }
+
+ // Check the PackageMaker version
+ cmsys::RegularExpression rexKey("<key>CFBundleShortVersionString</key>");
+ cmsys::RegularExpression rexVersion("<string>([0-9]+.[0-9.]+)</string>");
+ std::string line;
+ bool foundKey = false;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ if (rexKey.find(line)) {
+ foundKey = true;
+ break;
+ }
+ }
+ if (!foundKey) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Cannot find CFBundleShortVersionString in the PackageMaker compiler "
+ "version file"
+ << std::endl);
+ return 0;
+ }
+ if (!cmSystemTools::GetLineFromStream(ifs, line) || !rexVersion.find(line)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem reading the PackageMaker compiler version file: "
+ << versionFile << std::endl);
+ return 0;
+ }
+ this->PackageMakerVersion = atof(rexVersion.match(1).c_str());
+ if (this->PackageMakerVersion < 1.0) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Require PackageMaker 1.0 or higher" << std::endl);
+ return 0;
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "PackageMaker version is: " << this->PackageMakerVersion
+ << std::endl);
+
+ // Determine the package compatibility version. If it wasn't
+ // specified by the user, we define it based on which features the
+ // user requested.
+ const char* packageCompat = this->GetOption("CPACK_OSX_PACKAGE_VERSION");
+ if (packageCompat && *packageCompat) {
+ unsigned int majorVersion = 10;
+ unsigned int minorVersion = 5;
+ int res = sscanf(packageCompat, "%u.%u", &majorVersion, &minorVersion);
+ if (res == 2) {
+ this->PackageCompatibilityVersion =
+ getVersion(majorVersion, minorVersion);
+ }
+ } else if (this->GetOption("CPACK_DOWNLOAD_SITE")) {
+ this->SetOption("CPACK_OSX_PACKAGE_VERSION", "10.5");
+ this->PackageCompatibilityVersion = getVersion(10, 5);
+ } else if (this->GetOption("CPACK_COMPONENTS_ALL")) {
+ this->SetOption("CPACK_OSX_PACKAGE_VERSION", "10.4");
+ this->PackageCompatibilityVersion = getVersion(10, 4);
+ } else {
+ this->SetOption("CPACK_OSX_PACKAGE_VERSION", "10.3");
+ this->PackageCompatibilityVersion = getVersion(10, 3);
+ }
+
+ std::vector<std::string> no_paths;
+ pkgPath = cmSystemTools::FindProgram("hdiutil", no_paths, false);
+ if (pkgPath.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find hdiutil compiler" << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE",
+ pkgPath.c_str());
+
+ return this->Superclass::InitializeInternal();
+}
+
+bool cmCPackPackageMakerGenerator::RunPackageMaker(const char* command,
+ const char* packageFile)
+{
+ std::string tmpFile = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
+ "/PackageMakerOutput.log");
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << command << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool res = cmSystemTools::RunSingleCommand(
+ command, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Done running package maker" << std::endl);
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile);
+ ofs << "# Run command: " << command << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem running PackageMaker command: "
+ << command << std::endl
+ << "Please check " << tmpFile << " for errors"
+ << std::endl);
+ return false;
+ }
+ // sometimes the command finishes but the directory is not yet
+ // created, so try 10 times to see if it shows up
+ int tries = 10;
+ while (tries > 0 && !cmSystemTools::FileExists(packageFile)) {
+ cmSystemTools::Delay(500);
+ tries--;
+ }
+ if (!cmSystemTools::FileExists(packageFile)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem running PackageMaker command: "
+ << command << std::endl
+ << "Package not created: " << packageFile << std::endl);
+ return false;
+ }
+
+ return true;
+}
+
+bool cmCPackPackageMakerGenerator::GenerateComponentPackage(
+ const char* packageFile, const char* packageDir,
+ const cmCPackComponent& component)
+{
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Building component package: " << packageFile
+ << std::endl);
+
+ // The command that will be used to run PackageMaker
+ std::ostringstream pkgCmd;
+
+ if (this->PackageCompatibilityVersion < getVersion(10, 5) ||
+ this->PackageMakerVersion < 3.0) {
+ // Create Description.plist and Info.plist files for normal Mac OS
+ // X packages, which work on Mac OS X 10.3 and newer.
+ std::string descriptionFile =
+ cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
+ component.Name, "-Description.plist");
+ cmsys::ofstream out(descriptionFile.c_str());
+ cmXMLWriter xout(out);
+ xout.StartDocument();
+ xout.Doctype("plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\""
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"");
+ xout.StartElement("plist");
+ xout.Attribute("version", "1.4");
+ xout.StartElement("dict");
+ xout.Element("key", "IFPkgDescriptionTitle");
+ xout.Element("string", component.DisplayName);
+ xout.Element("key", "IFPkgDescriptionVersion");
+ xout.Element("string", this->GetOption("CPACK_PACKAGE_VERSION"));
+ xout.Element("key", "IFPkgDescriptionDescription");
+ xout.Element("string", component.Description);
+ xout.EndElement(); // dict
+ xout.EndElement(); // plist
+ xout.EndDocument();
+ out.close();
+
+ // Create the Info.plist file for this component
+ std::string moduleVersionSuffix = cmStrCat('.', component.Name);
+ this->SetOption("CPACK_MODULE_VERSION_SUFFIX",
+ moduleVersionSuffix.c_str());
+ std::string infoFileName = cmStrCat(component.Name, "-Info.plist");
+ if (!this->CopyResourcePlistFile("Info.plist", infoFileName.c_str())) {
+ return false;
+ }
+
+ pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")
+ << "\" -build -p \"" << packageFile << "\""
+ << " -f \"" << packageDir << "\""
+ << " -i \"" << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/"
+ << infoFileName << "\""
+ << " -d \"" << descriptionFile << "\"";
+ } else {
+ // Create a "flat" package on Mac OS X 10.5 and newer. Flat
+ // packages are stored in a single file, rather than a directory
+ // like normal packages, and can be downloaded by the installer
+ // on-the-fly in Mac OS X 10.5 or newer. Thus, we need to create
+ // flat packages when the packages will be downloaded on the fly.
+ std::string pkgId =
+ cmStrCat("com.", this->GetOption("CPACK_PACKAGE_VENDOR"), '.',
+ this->GetOption("CPACK_PACKAGE_NAME"), '.', component.Name);
+
+ pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")
+ << "\" --root \"" << packageDir << "\""
+ << " --id " << pkgId << " --target "
+ << this->GetOption("CPACK_OSX_PACKAGE_VERSION") << " --out \""
+ << packageFile << "\"";
+ }
+
+ // Run PackageMaker
+ return RunPackageMaker(pkgCmd.str().c_str(), packageFile);
+}
diff --git a/Source/CPack/cmCPackPackageMakerGenerator.h b/Source/CPack/cmCPackPackageMakerGenerator.h
new file mode 100644
index 0000000..cda9277
--- /dev/null
+++ b/Source/CPack/cmCPackPackageMakerGenerator.h
@@ -0,0 +1,50 @@
+/* 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 "cmCPackGenerator.h"
+#include "cmCPackPKGGenerator.h"
+
+class cmCPackComponent;
+
+/** \class cmCPackPackageMakerGenerator
+ * \brief A generator for PackageMaker files
+ *
+ * http://developer.apple.com/documentation/Darwin
+ * /Reference/ManPages/man1/packagemaker.1.html
+ */
+class cmCPackPackageMakerGenerator : public cmCPackPKGGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackPackageMakerGenerator, cmCPackPKGGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackPackageMakerGenerator();
+ ~cmCPackPackageMakerGenerator() override;
+ bool SupportsComponentInstallation() const override;
+
+protected:
+ int InitializeInternal() override;
+ int PackageFiles() override;
+ const char* GetOutputExtension() override { return ".dmg"; }
+
+ // Run PackageMaker with the given command line, which will (if
+ // successful) produce the given package file. Returns true if
+ // PackageMaker succeeds, false otherwise.
+ bool RunPackageMaker(const char* command, const char* packageFile);
+
+ // Generate a package in the file packageFile for the given
+ // component. All of the files within this component are stored in
+ // the directory packageDir. Returns true if successful, false
+ // otherwise.
+ bool GenerateComponentPackage(const char* packageFile,
+ const char* packageDir,
+ const cmCPackComponent& component);
+
+ double PackageMakerVersion;
+ unsigned int PackageCompatibilityVersion;
+};
diff --git a/Source/CPack/cmCPackProductBuildGenerator.cxx b/Source/CPack/cmCPackProductBuildGenerator.cxx
new file mode 100644
index 0000000..a3e55de
--- /dev/null
+++ b/Source/CPack/cmCPackProductBuildGenerator.cxx
@@ -0,0 +1,253 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackProductBuildGenerator.h"
+
+#include <cstddef>
+#include <map>
+#include <sstream>
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmDuration.h"
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmCPackProductBuildGenerator::cmCPackProductBuildGenerator()
+{
+ this->componentPackageMethod = ONE_PACKAGE;
+}
+
+cmCPackProductBuildGenerator::~cmCPackProductBuildGenerator() = default;
+
+int cmCPackProductBuildGenerator::PackageFiles()
+{
+ // TODO: Use toplevel
+ // It is used! Is this an obsolete comment?
+
+ std::string packageDirFileName =
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+
+ // Create the directory where component packages will be built.
+ std::string basePackageDir =
+ cmStrCat(packageDirFileName, "/Contents/Packages");
+ if (!cmsys::SystemTools::MakeDirectory(basePackageDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating component packages directory: "
+ << basePackageDir << std::endl);
+ return 0;
+ }
+
+ if (!this->Components.empty()) {
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ std::string packageDir = cmStrCat(toplevel, '/', compIt->first);
+ if (!this->GenerateComponentPackage(basePackageDir,
+ GetPackageName(compIt->second),
+ packageDir, &compIt->second)) {
+ return 0;
+ }
+ }
+ } else {
+ if (!this->GenerateComponentPackage(basePackageDir,
+ this->GetOption("CPACK_PACKAGE_NAME"),
+ toplevel, nullptr)) {
+ return 0;
+ }
+ }
+
+ std::string resDir = packageDirFileName + "/Contents";
+
+ if (this->IsSet("CPACK_PRODUCTBUILD_RESOURCES_DIR")) {
+ std::string userResDir =
+ this->GetOption("CPACK_PRODUCTBUILD_RESOURCES_DIR");
+
+ if (!cmSystemTools::CopyADirectory(userResDir, resDir)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem copying the resource files" << std::endl);
+ return 0;
+ }
+ }
+
+ // Copy or create all of the resource files we need.
+ if (!this->CopyCreateResourceFile("License", resDir) ||
+ !this->CopyCreateResourceFile("ReadMe", resDir) ||
+ !this->CopyCreateResourceFile("Welcome", resDir)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem copying the License, ReadMe and Welcome files"
+ << std::endl);
+ return 0;
+ }
+
+ // combine package(s) into a distribution
+ WriteDistributionFile(packageDirFileName.c_str(), "PRODUCTBUILD");
+ std::ostringstream pkgCmd;
+
+ std::string version = this->GetOption("CPACK_PACKAGE_VERSION");
+ std::string productbuild = this->GetOption("CPACK_COMMAND_PRODUCTBUILD");
+ std::string identityName;
+ if (const char* n = this->GetOption("CPACK_PRODUCTBUILD_IDENTITY_NAME")) {
+ identityName = n;
+ }
+ std::string keychainPath;
+ if (const char* p = this->GetOption("CPACK_PRODUCTBUILD_KEYCHAIN_PATH")) {
+ keychainPath = p;
+ }
+
+ pkgCmd << productbuild << " --distribution \"" << packageDirFileName
+ << "/Contents/distribution.dist\""
+ << " --package-path \"" << packageDirFileName << "/Contents/Packages"
+ << "\""
+ << " --resources \"" << resDir << "\""
+ << " --version \"" << version << "\""
+ << (identityName.empty() ? "" : " --sign \"" + identityName + "\"")
+ << (keychainPath.empty() ? ""
+ : " --keychain \"" + keychainPath + "\"")
+ << " \"" << packageFileNames[0] << "\"";
+
+ // Run ProductBuild
+ return RunProductBuild(pkgCmd.str());
+}
+
+int cmCPackProductBuildGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/Applications");
+
+ std::vector<std::string> no_paths;
+ std::string program =
+ cmSystemTools::FindProgram("pkgbuild", no_paths, false);
+ if (program.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find pkgbuild executable" << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_PKGBUILD", program.c_str());
+
+ program = cmSystemTools::FindProgram("productbuild", no_paths, false);
+ if (program.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find productbuild executable" << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_PRODUCTBUILD", program.c_str());
+
+ return this->Superclass::InitializeInternal();
+}
+
+bool cmCPackProductBuildGenerator::RunProductBuild(const std::string& command)
+{
+ std::string tmpFile = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
+ "/ProductBuildOutput.log");
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << command << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool res = cmSystemTools::RunSingleCommand(
+ command, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running command" << std::endl);
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile);
+ ofs << "# Run command: " << command << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem running command: " << command << std::endl
+ << "Please check " << tmpFile
+ << " for errors" << std::endl);
+ return false;
+ }
+ return true;
+}
+
+bool cmCPackProductBuildGenerator::GenerateComponentPackage(
+ const std::string& packageFileDir, const std::string& packageFileName,
+ const std::string& packageDir, const cmCPackComponent* component)
+{
+ std::string packageFile = cmStrCat(packageFileDir, '/', packageFileName);
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Building component package: " << packageFile
+ << std::endl);
+
+ const char* comp_name = component ? component->Name.c_str() : nullptr;
+
+ const char* preflight = this->GetComponentScript("PREFLIGHT", comp_name);
+ const char* postflight = this->GetComponentScript("POSTFLIGHT", comp_name);
+
+ std::string resDir = packageFileDir;
+ if (component) {
+ resDir += "/";
+ resDir += component->Name;
+ }
+ std::string scriptDir = resDir + "/scripts";
+
+ if (!cmsys::SystemTools::MakeDirectory(scriptDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating installer directory: " << scriptDir
+ << std::endl);
+ return false;
+ }
+
+ // if preflight, postflight, or postupgrade are set
+ // then copy them into the script directory and make
+ // them executable
+ if (preflight) {
+ this->CopyInstallScript(scriptDir, preflight, "preinstall");
+ }
+ if (postflight) {
+ this->CopyInstallScript(scriptDir, postflight, "postinstall");
+ }
+
+ // The command that will be used to run ProductBuild
+ std::ostringstream pkgCmd;
+
+ std::string pkgId = cmStrCat("com.", this->GetOption("CPACK_PACKAGE_VENDOR"),
+ '.', this->GetOption("CPACK_PACKAGE_NAME"));
+ if (component) {
+ pkgId += '.';
+ pkgId += component->Name;
+ }
+
+ std::string version = this->GetOption("CPACK_PACKAGE_VERSION");
+ std::string pkgbuild = this->GetOption("CPACK_COMMAND_PKGBUILD");
+ std::string identityName;
+ if (const char* n = this->GetOption("CPACK_PKGBUILD_IDENTITY_NAME")) {
+ identityName = n;
+ }
+ std::string keychainPath;
+ if (const char* p = this->GetOption("CPACK_PKGBUILD_KEYCHAIN_PATH")) {
+ keychainPath = p;
+ }
+
+ pkgCmd << pkgbuild << " --root \"" << packageDir << "\""
+ << " --identifier \"" << pkgId << "\""
+ << " --scripts \"" << scriptDir << "\""
+ << " --version \"" << version << "\""
+ << " --install-location \"/\""
+ << (identityName.empty() ? "" : " --sign \"" + identityName + "\"")
+ << (keychainPath.empty() ? ""
+ : " --keychain \"" + keychainPath + "\"")
+ << " \"" << packageFile << "\"";
+
+ if (component && !component->Plist.empty()) {
+ pkgCmd << " --component-plist \"" << component->Plist << "\"";
+ }
+
+ // Run ProductBuild
+ return RunProductBuild(pkgCmd.str());
+}
+
+const char* cmCPackProductBuildGenerator::GetComponentScript(
+ const char* script, const char* component_name)
+{
+ std::string scriptname = std::string("CPACK_") + script + "_";
+ if (component_name) {
+ scriptname += cmSystemTools::UpperCase(component_name);
+ scriptname += "_";
+ }
+ scriptname += "SCRIPT";
+
+ return this->GetOption(scriptname);
+}
diff --git a/Source/CPack/cmCPackProductBuildGenerator.h b/Source/CPack/cmCPackProductBuildGenerator.h
new file mode 100644
index 0000000..462e2fc
--- /dev/null
+++ b/Source/CPack/cmCPackProductBuildGenerator.h
@@ -0,0 +1,50 @@
+/* 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 <string>
+
+#include "cmCPackGenerator.h"
+#include "cmCPackPKGGenerator.h"
+
+class cmCPackComponent;
+
+/** \class cmCPackProductBuildGenerator
+ * \brief A generator for ProductBuild files
+ *
+ */
+class cmCPackProductBuildGenerator : public cmCPackPKGGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackProductBuildGenerator, cmCPackPKGGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackProductBuildGenerator();
+ ~cmCPackProductBuildGenerator() override;
+
+protected:
+ int InitializeInternal() override;
+ int PackageFiles() override;
+ const char* GetOutputExtension() override { return ".pkg"; }
+
+ // Run ProductBuild with the given command line, which will (if
+ // successful) produce the given package file. Returns true if
+ // ProductBuild succeeds, false otherwise.
+ bool RunProductBuild(const std::string& command);
+
+ // Generate a package in the file packageFile for the given
+ // component. All of the files within this component are stored in
+ // the directory packageDir. Returns true if successful, false
+ // otherwise.
+ bool GenerateComponentPackage(const std::string& packageFileDir,
+ const std::string& packageFileName,
+ const std::string& packageDir,
+ const cmCPackComponent* component);
+
+ const char* GetComponentScript(const char* script,
+ const char* script_component);
+};
diff --git a/Source/CPack/cmCPackRPMGenerator.cxx b/Source/CPack/cmCPackRPMGenerator.cxx
new file mode 100644
index 0000000..c3f6d59
--- /dev/null
+++ b/Source/CPack/cmCPackRPMGenerator.cxx
@@ -0,0 +1,440 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackRPMGenerator.h"
+
+#include <algorithm>
+#include <cctype>
+#include <map>
+#include <ostream>
+#include <utility>
+#include <vector>
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackGenerator.h"
+#include "cmCPackLog.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmCPackRPMGenerator::cmCPackRPMGenerator() = default;
+
+cmCPackRPMGenerator::~cmCPackRPMGenerator() = default;
+
+int cmCPackRPMGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
+ if (cmIsOff(this->GetOption("CPACK_SET_DESTDIR"))) {
+ this->SetOption("CPACK_SET_DESTDIR", "I_ON");
+ }
+ /* Replace space in CPACK_PACKAGE_NAME in order to avoid
+ * rpmbuild scream on unwanted space in filename issue
+ * Moreover RPM file do not usually embed space in filename
+ */
+ if (this->GetOption("CPACK_PACKAGE_NAME")) {
+ std::string packageName = this->GetOption("CPACK_PACKAGE_NAME");
+ std::replace(packageName.begin(), packageName.end(), ' ', '-');
+ this->SetOption("CPACK_PACKAGE_NAME", packageName.c_str());
+ }
+ /* same for CPACK_PACKAGE_FILE_NAME */
+ if (this->GetOption("CPACK_PACKAGE_FILE_NAME")) {
+ std::string packageName = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ std::replace(packageName.begin(), packageName.end(), ' ', '-');
+ this->SetOption("CPACK_PACKAGE_FILE_NAME", packageName.c_str());
+ }
+ return this->Superclass::InitializeInternal();
+}
+
+void cmCPackRPMGenerator::AddGeneratedPackageNames()
+{
+ // add the generated packages to package file names list
+ std::string fileNames(this->GetOption("GEN_CPACK_OUTPUT_FILES"));
+ const char sep = ';';
+ std::string::size_type pos1 = 0;
+ std::string::size_type pos2 = fileNames.find(sep, pos1 + 1);
+ while (pos2 != std::string::npos) {
+ this->packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1));
+ pos1 = pos2 + 1;
+ pos2 = fileNames.find(sep, pos1 + 1);
+ }
+ this->packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1));
+}
+
+int cmCPackRPMGenerator::PackageOnePack(std::string const& initialToplevel,
+ std::string const& packageName)
+{
+ int retval = 1;
+ // Begin the archive for this pack
+ std::string localToplevel(initialToplevel);
+ std::string packageFileName(
+ cmSystemTools::GetParentDirectory(this->toplevel));
+ std::string outputFileName(
+ this->GetComponentPackageFileName(
+ this->GetOption("CPACK_PACKAGE_FILE_NAME"), packageName, true) +
+ this->GetOutputExtension());
+
+ localToplevel += "/" + packageName;
+ /* replace the TEMP DIRECTORY with the component one */
+ this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str());
+ packageFileName += "/" + outputFileName;
+ /* replace proposed CPACK_OUTPUT_FILE_NAME */
+ this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName.c_str());
+ /* replace the TEMPORARY package file name */
+ this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
+ packageFileName.c_str());
+ // Tell CPackRPM.cmake the name of the component NAME.
+ this->SetOption("CPACK_RPM_PACKAGE_COMPONENT", packageName.c_str());
+ // Tell CPackRPM.cmake the path where the component is.
+ std::string component_path = cmStrCat('/', packageName);
+ this->SetOption("CPACK_RPM_PACKAGE_COMPONENT_PART_PATH",
+ component_path.c_str());
+ if (!this->ReadListFile("Internal/CPack/CPackRPM.cmake")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while execution CPackRPM.cmake" << std::endl);
+ retval = 0;
+ }
+
+ return retval;
+}
+
+int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
+{
+ int retval = 1;
+ /* Reset package file name list it will be populated during the
+ * component packaging run*/
+ this->packageFileNames.clear();
+ std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+
+ const char* mainComponent = this->GetOption("CPACK_RPM_MAIN_COMPONENT");
+
+ if (this->IsOn("CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE") &&
+ !this->IsOn("CPACK_RPM_DEBUGINFO_PACKAGE")) {
+ // check if we need to set CPACK_RPM_DEBUGINFO_PACKAGE because non of
+ // the components is setting per component debuginfo package variable
+ bool shouldSet = true;
+
+ if (ignoreGroup) {
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ std::string component(compIt->first);
+ std::transform(component.begin(), component.end(), component.begin(),
+ ::toupper);
+
+ if (this->IsOn("CPACK_RPM_" + compIt->first + "_DEBUGINFO_PACKAGE") ||
+ this->IsOn("CPACK_RPM_" + component + "_DEBUGINFO_PACKAGE")) {
+ shouldSet = false;
+ break;
+ }
+ }
+ } else {
+ std::map<std::string, cmCPackComponentGroup>::iterator compGIt;
+ for (compGIt = this->ComponentGroups.begin();
+ compGIt != this->ComponentGroups.end(); ++compGIt) {
+ std::string component(compGIt->first);
+ std::transform(component.begin(), component.end(), component.begin(),
+ ::toupper);
+
+ if (this->IsOn("CPACK_RPM_" + compGIt->first + "_DEBUGINFO_PACKAGE") ||
+ this->IsOn("CPACK_RPM_" + component + "_DEBUGINFO_PACKAGE")) {
+ shouldSet = false;
+ break;
+ }
+ }
+
+ if (shouldSet) {
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin();
+ compIt != this->Components.end(); ++compIt) {
+ // Does the component belong to a group?
+ if (compIt->second.Group == nullptr) {
+ std::string component(compIt->first);
+ std::transform(component.begin(), component.end(),
+ component.begin(), ::toupper);
+
+ if (this->IsOn("CPACK_RPM_" + compIt->first +
+ "_DEBUGINFO_PACKAGE") ||
+ this->IsOn("CPACK_RPM_" + component + "_DEBUGINFO_PACKAGE")) {
+ shouldSet = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (shouldSet) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Setting "
+ << "CPACK_RPM_DEBUGINFO_PACKAGE because "
+ << "CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE is set but "
+ << " none of the "
+ << "CPACK_RPM_<component>_DEBUGINFO_PACKAGE variables "
+ << "are set." << std::endl);
+ this->SetOption("CPACK_RPM_DEBUGINFO_PACKAGE", "ON");
+ }
+ }
+
+ if (mainComponent) {
+ if (this->IsOn("CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE")) {
+ this->SetOption("GENERATE_SPEC_PARTS", "ON");
+ }
+
+ std::string mainComponentUpper(mainComponent);
+ std::transform(mainComponentUpper.begin(), mainComponentUpper.end(),
+ mainComponentUpper.begin(), ::toupper);
+
+ // The default behavior is to have one package by component group
+ // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
+ if (!ignoreGroup) {
+ auto mainCompGIt = this->ComponentGroups.end();
+
+ std::map<std::string, cmCPackComponentGroup>::iterator compGIt;
+ for (compGIt = this->ComponentGroups.begin();
+ compGIt != this->ComponentGroups.end(); ++compGIt) {
+ std::string component(compGIt->first);
+ std::transform(component.begin(), component.end(), component.begin(),
+ ::toupper);
+
+ if (mainComponentUpper == component) {
+ // main component will be handled last
+ mainCompGIt = compGIt;
+ continue;
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Packaging component group: " << compGIt->first
+ << std::endl);
+ retval &= this->PackageOnePack(initialTopLevel, compGIt->first);
+ }
+ // Handle Orphan components (components not belonging to any groups)
+ auto mainCompIt = this->Components.end();
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ // Does the component belong to a group?
+ if (compIt->second.Group == nullptr) {
+ std::string component(compIt->first);
+ std::transform(component.begin(), component.end(), component.begin(),
+ ::toupper);
+
+ if (mainComponentUpper == component) {
+ // main component will be handled last
+ mainCompIt = compIt;
+ continue;
+ }
+
+ cmCPackLogger(
+ cmCPackLog::LOG_VERBOSE,
+ "Component <"
+ << compIt->second.Name
+ << "> does not belong to any group, package it separately."
+ << std::endl);
+ retval &= this->PackageOnePack(initialTopLevel, compIt->first);
+ }
+ }
+
+ if (retval) {
+ this->SetOption("GENERATE_SPEC_PARTS", "OFF");
+
+ if (mainCompGIt != this->ComponentGroups.end()) {
+ retval &= this->PackageOnePack(initialTopLevel, mainCompGIt->first);
+ } else if (mainCompIt != this->Components.end()) {
+ retval &= this->PackageOnePack(initialTopLevel, mainCompIt->first);
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_RPM_MAIN_COMPONENT set"
+ << " to non existing component.\n");
+ retval = 0;
+ }
+ }
+ }
+ // CPACK_COMPONENTS_IGNORE_GROUPS is set
+ // We build 1 package per component
+ else {
+ auto mainCompIt = this->Components.end();
+
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ std::string component(compIt->first);
+ std::transform(component.begin(), component.end(), component.begin(),
+ ::toupper);
+
+ if (mainComponentUpper == component) {
+ // main component will be handled last
+ mainCompIt = compIt;
+ continue;
+ }
+
+ retval &= this->PackageOnePack(initialTopLevel, compIt->first);
+ }
+
+ if (retval) {
+ this->SetOption("GENERATE_SPEC_PARTS", "OFF");
+
+ if (mainCompIt != this->Components.end()) {
+ retval &= this->PackageOnePack(initialTopLevel, mainCompIt->first);
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_RPM_MAIN_COMPONENT set"
+ << " to non existing component.\n");
+ retval = 0;
+ }
+ }
+ }
+ } else if (!this->IsOn("CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE") ||
+ this->Components.size() == 1) {
+ // The default behavior is to have one package by component group
+ // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
+ if (!ignoreGroup) {
+ std::map<std::string, cmCPackComponentGroup>::iterator compGIt;
+ for (compGIt = this->ComponentGroups.begin();
+ compGIt != this->ComponentGroups.end(); ++compGIt) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Packaging component group: " << compGIt->first
+ << std::endl);
+ retval &= this->PackageOnePack(initialTopLevel, compGIt->first);
+ }
+ // Handle Orphan components (components not belonging to any groups)
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ // Does the component belong to a group?
+ if (compIt->second.Group == nullptr) {
+ cmCPackLogger(
+ cmCPackLog::LOG_VERBOSE,
+ "Component <"
+ << compIt->second.Name
+ << "> does not belong to any group, package it separately."
+ << std::endl);
+ retval &= this->PackageOnePack(initialTopLevel, compIt->first);
+ }
+ }
+ }
+ // CPACK_COMPONENTS_IGNORE_GROUPS is set
+ // We build 1 package per component
+ else {
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ retval &= this->PackageOnePack(initialTopLevel, compIt->first);
+ }
+ }
+ } else {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_RPM_MAIN_COMPONENT not set but"
+ << " it is mandatory with CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE"
+ << " being set.\n");
+ retval = 0;
+ }
+
+ if (retval) {
+ this->AddGeneratedPackageNames();
+ }
+
+ return retval;
+}
+
+int cmCPackRPMGenerator::PackageComponentsAllInOne(
+ const std::string& compInstDirName)
+{
+ int retval = 1;
+ /* Reset package file name list it will be populated during the
+ * component packaging run*/
+ this->packageFileNames.clear();
+ std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+
+ if (this->IsOn("CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE")) {
+ this->SetOption("CPACK_RPM_DEBUGINFO_PACKAGE", "ON");
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Packaging all groups in one package..."
+ "(CPACK_COMPONENTS_ALL_[GROUPS_]IN_ONE_PACKAGE is set)"
+ << std::endl);
+
+ // The ALL GROUPS in ONE package case
+ std::string localToplevel(initialTopLevel);
+ std::string packageFileName(
+ cmSystemTools::GetParentDirectory(this->toplevel));
+ std::string outputFileName(
+ std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) +
+ this->GetOutputExtension());
+ // all GROUP in one vs all COMPONENT in one
+ localToplevel += "/" + compInstDirName;
+
+ /* replace the TEMP DIRECTORY with the component one */
+ this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str());
+ packageFileName += "/" + outputFileName;
+ /* replace proposed CPACK_OUTPUT_FILE_NAME */
+ this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName.c_str());
+ /* replace the TEMPORARY package file name */
+ this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
+ packageFileName.c_str());
+
+ if (!compInstDirName.empty()) {
+ // Tell CPackRPM.cmake the path where the component is.
+ std::string component_path = cmStrCat('/', compInstDirName);
+ this->SetOption("CPACK_RPM_PACKAGE_COMPONENT_PART_PATH",
+ component_path.c_str());
+ }
+
+ if (this->ReadListFile("Internal/CPack/CPackRPM.cmake")) {
+ this->AddGeneratedPackageNames();
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while execution CPackRPM.cmake" << std::endl);
+ retval = 0;
+ }
+
+ return retval;
+}
+
+int cmCPackRPMGenerator::PackageFiles()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Toplevel: " << this->toplevel << std::endl);
+
+ /* Are we in the component packaging case */
+ if (this->WantsComponentInstallation()) {
+ // CASE 1 : COMPONENT ALL-IN-ONE package
+ // If ALL COMPONENTS in ONE package has been requested
+ // then the package file is unique and should be open here.
+ if (this->componentPackageMethod == ONE_PACKAGE) {
+ return this->PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE");
+ }
+ // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
+ // There will be 1 package for each component group
+ // however one may require to ignore component group and
+ // in this case you'll get 1 package for each component.
+ return this->PackageComponents(this->componentPackageMethod ==
+ ONE_PACKAGE_PER_COMPONENT);
+ }
+ // CASE 3 : NON COMPONENT package.
+ return this->PackageComponentsAllInOne("");
+}
+
+bool cmCPackRPMGenerator::SupportsComponentInstallation() const
+{
+ return this->IsOn("CPACK_RPM_COMPONENT_INSTALL");
+}
+
+std::string cmCPackRPMGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ if (this->componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) {
+ return componentName;
+ }
+
+ if (this->componentPackageMethod == ONE_PACKAGE) {
+ return std::string("ALL_COMPONENTS_IN_ONE");
+ }
+ // We have to find the name of the COMPONENT GROUP
+ // the current COMPONENT belongs to.
+ std::string groupVar =
+ "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP";
+ if (nullptr != this->GetOption(groupVar)) {
+ return std::string(this->GetOption(groupVar));
+ }
+ return componentName;
+}
diff --git a/Source/CPack/cmCPackRPMGenerator.h b/Source/CPack/cmCPackRPMGenerator.h
new file mode 100644
index 0000000..0288f2f
--- /dev/null
+++ b/Source/CPack/cmCPackRPMGenerator.h
@@ -0,0 +1,69 @@
+/* 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 <string>
+
+#include "cmCPackGenerator.h"
+
+/** \class cmCPackRPMGenerator
+ * \brief A generator for RPM packages
+ * The idea of the CPack RPM generator is to use
+ * as minimal C++ code as possible.
+ * Ideally the C++ part of the CPack RPM generator
+ * will only 'execute' (aka ->ReadListFile) several
+ * CMake macros files.
+ */
+class cmCPackRPMGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackRPMGenerator, cmCPackGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackRPMGenerator();
+ ~cmCPackRPMGenerator() override;
+
+ static bool CanGenerate()
+ {
+#ifdef __APPLE__
+ // on MacOS enable CPackRPM iff rpmbuild is found
+ std::vector<std::string> locations;
+ locations.push_back("/sw/bin"); // Fink
+ locations.push_back("/opt/local/bin"); // MacPorts
+ return cmSystemTools::FindProgram("rpmbuild") != "" ? true : false;
+#else
+ // legacy behavior on other systems
+ return true;
+#endif
+ }
+
+protected:
+ int InitializeInternal() override;
+ int PackageFiles() override;
+ /**
+ * This method factors out the work done in component packaging case.
+ */
+ int PackageOnePack(std::string const& initialToplevel,
+ std::string const& packageName);
+ /**
+ * The method used to package files when component
+ * install is used. This will create one
+ * archive for each component group.
+ */
+ int PackageComponents(bool ignoreGroup);
+ /**
+ * Special case of component install where all
+ * components will be put in a single installer.
+ */
+ int PackageComponentsAllInOne(const std::string& compInstDirName);
+ const char* GetOutputExtension() override { return ".rpm"; }
+ bool SupportsComponentInstallation() const override;
+ std::string GetComponentInstallDirNameSuffix(
+ const std::string& componentName) override;
+
+ void AddGeneratedPackageNames();
+};
diff --git a/Source/CPack/cmCPackSTGZGenerator.cxx b/Source/CPack/cmCPackSTGZGenerator.cxx
new file mode 100644
index 0000000..3e36e8c
--- /dev/null
+++ b/Source/CPack/cmCPackSTGZGenerator.cxx
@@ -0,0 +1,115 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCPackSTGZGenerator.h"
+
+#include <cstdio>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "cmsys/FStream.hxx"
+
+#include "cm_sys_stat.h"
+
+#include "cmArchiveWrite.h"
+#include "cmCPackGenerator.h"
+#include "cmCPackLog.h"
+#include "cmSystemTools.h"
+
+cmCPackSTGZGenerator::cmCPackSTGZGenerator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressGZip, "paxr", ".sh")
+{
+}
+
+cmCPackSTGZGenerator::~cmCPackSTGZGenerator() = default;
+
+int cmCPackSTGZGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "0");
+
+ std::string inFile = this->FindTemplate("CPack.STGZ_Header.sh.in");
+ if (inFile.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find template file: " << inFile << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_STGZ_HEADER_FILE", inFile.c_str());
+ this->SetOptionIfNotSet("CPACK_AT_SIGN", "@");
+
+ return this->Superclass::InitializeInternal();
+}
+
+int cmCPackSTGZGenerator::PackageFiles()
+{
+ bool retval = true;
+ if (!this->Superclass::PackageFiles()) {
+ return 0;
+ }
+
+ /* TGZ generator (our Superclass) may
+ * have generated several packages (component packaging)
+ * so we must iterate over generated packages.
+ */
+ for (std::string const& pfn : this->packageFileNames) {
+ retval &= cmSystemTools::SetPermissions(pfn.c_str(),
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ S_IREAD | S_IWRITE | S_IEXEC
+#else
+ S_IRUSR | S_IWUSR | S_IXUSR |
+ S_IRGRP | S_IWGRP | S_IXGRP |
+ S_IROTH | S_IWOTH | S_IXOTH
+#endif
+ );
+ }
+ return retval;
+}
+
+int cmCPackSTGZGenerator::GenerateHeader(std::ostream* os)
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Writing header" << std::endl);
+ std::ostringstream str;
+ int counter = 0;
+
+ std::string inLicFile = this->GetOption("CPACK_RESOURCE_FILE_LICENSE");
+ std::string line;
+ cmsys::ifstream ilfs(inLicFile.c_str());
+ std::string licenseText;
+ while (cmSystemTools::GetLineFromStream(ilfs, line)) {
+ licenseText += line + "\n";
+ }
+ this->SetOptionIfNotSet("CPACK_RESOURCE_FILE_LICENSE_CONTENT",
+ licenseText.c_str());
+
+ const char headerLengthTag[] = "###CPACK_HEADER_LENGTH###";
+
+ // Create the header
+ std::string inFile = this->GetOption("CPACK_STGZ_HEADER_FILE");
+ cmsys::ifstream ifs(inFile.c_str());
+ std::string packageHeaderText;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ packageHeaderText += line + "\n";
+ }
+
+ // Configure in the values
+ std::string res;
+ this->ConfigureString(packageHeaderText, res);
+
+ // Count the lines
+ const char* ptr = res.c_str();
+ while (*ptr) {
+ if (*ptr == '\n') {
+ counter++;
+ }
+ ++ptr;
+ }
+ counter++;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Number of lines: " << counter << std::endl);
+ char buffer[1024];
+ sprintf(buffer, "%d", counter);
+ cmSystemTools::ReplaceString(res, headerLengthTag, buffer);
+
+ // Write in file
+ *os << res;
+ return this->Superclass::GenerateHeader(os);
+}
diff --git a/Source/CPack/cmCPackSTGZGenerator.h b/Source/CPack/cmCPackSTGZGenerator.h
new file mode 100644
index 0000000..d2df1f2
--- /dev/null
+++ b/Source/CPack/cmCPackSTGZGenerator.h
@@ -0,0 +1,31 @@
+/* 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 <iosfwd>
+
+#include "cmCPackArchiveGenerator.h"
+#include "cmCPackGenerator.h"
+
+/** \class cmCPackSTGZGenerator
+ * \brief A generator for Self extractable TGZ files
+ *
+ */
+class cmCPackSTGZGenerator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackSTGZGenerator, cmCPackArchiveGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackSTGZGenerator();
+ ~cmCPackSTGZGenerator() override;
+
+protected:
+ int PackageFiles() override;
+ int InitializeInternal() override;
+ int GenerateHeader(std::ostream* os) override;
+};
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
new file mode 100644
index 0000000..85c13ad
--- /dev/null
+++ b/Source/CPack/cpack.cxx
@@ -0,0 +1,474 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <cstddef>
+#include <iostream>
+#include <map>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmsys/CommandLineArguments.hxx"
+#include "cmsys/Encoding.hxx"
+
+#include "cmCPackGenerator.h"
+#include "cmCPackGeneratorFactory.h"
+#include "cmCPackLog.h"
+#include "cmConsoleBuf.h"
+#include "cmDocumentation.h"
+#include "cmDocumentationEntry.h"
+#include "cmDocumentationFormatter.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+namespace {
+const char* cmDocumentationName[][2] = {
+ { nullptr, " cpack - Packaging driver provided by CMake." },
+ { nullptr, nullptr }
+};
+
+const char* cmDocumentationUsage[][2] = {
+ // clang-format off
+ { nullptr, " cpack [options]" },
+ { nullptr, nullptr }
+ // clang-format on
+};
+
+const char* cmDocumentationOptions[][2] = {
+ { "-G <generators>", "Override/define CPACK_GENERATOR" },
+ { "-C <Configuration>", "Specify the project configuration" },
+ { "-D <var>=<value>", "Set a CPack variable." },
+ { "--config <configFile>", "Specify the config file." },
+ { "--verbose,-V", "Enable verbose output" },
+ { "--trace", "Put underlying cmake scripts in trace mode." },
+ { "--trace-expand", "Put underlying cmake scripts in expanded trace mode." },
+ { "--debug", "Enable debug output (for CPack developers)" },
+ { "-P <packageName>", "Override/define CPACK_PACKAGE_NAME" },
+ { "-R <packageVersion>", "Override/define CPACK_PACKAGE_VERSION" },
+ { "-B <packageDirectory>", "Override/define CPACK_PACKAGE_DIRECTORY" },
+ { "--vendor <vendorName>", "Override/define CPACK_PACKAGE_VENDOR" },
+ { nullptr, nullptr }
+};
+
+int cpackUnknownArgument(const char* /*unused*/, void* /*unused*/)
+{
+ return 1;
+}
+
+struct cpackDefinitions
+{
+ using MapType = std::map<std::string, std::string>;
+ MapType Map;
+ cmCPackLog* Log;
+};
+
+int cpackDefinitionArgument(const char* argument, const char* cValue,
+ void* call_data)
+{
+ (void)argument;
+ cpackDefinitions* def = static_cast<cpackDefinitions*>(call_data);
+ std::string value = cValue;
+ size_t pos = value.find_first_of('=');
+ if (pos == std::string::npos) {
+ cmCPack_Log(def->Log, cmCPackLog::LOG_ERROR,
+ "Please specify CPack definitions as: KEY=VALUE" << std::endl);
+ return 0;
+ }
+ std::string key = value.substr(0, pos);
+ value.erase(0, pos + 1);
+ def->Map[key] = value;
+ cmCPack_Log(def->Log, cmCPackLog::LOG_DEBUG,
+ "Set CPack variable: " << key << " to \"" << value << "\""
+ << std::endl);
+ return 1;
+}
+
+void cpackProgressCallback(const std::string& message, float /*unused*/)
+{
+ std::cout << "-- " << message << std::endl;
+}
+} // namespace
+
+// this is CPack.
+int main(int argc, char const* const* argv)
+{
+ cmSystemTools::EnsureStdPipes();
+
+ // Replace streambuf so we can output Unicode to console
+ cmConsoleBuf consoleBuf;
+ consoleBuf.SetUTF8Pipes();
+
+ cmsys::Encoding::CommandLineArguments args =
+ cmsys::Encoding::CommandLineArguments::Main(argc, argv);
+ argc = args.argc();
+ argv = args.argv();
+
+ cmSystemTools::InitializeLibUV();
+ cmSystemTools::FindCMakeResources(argv[0]);
+ cmCPackLog log;
+
+ log.SetErrorPrefix("CPack Error: ");
+ log.SetWarningPrefix("CPack Warning: ");
+ log.SetOutputPrefix("CPack: ");
+ log.SetVerbosePrefix("CPack Verbose: ");
+
+ if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Current working directory cannot be established."
+ << std::endl);
+ return 1;
+ }
+
+ std::string generator;
+ bool help = false;
+ bool helpVersion = false;
+ bool verbose = false;
+ bool trace = false;
+ bool traceExpand = false;
+ bool debug = false;
+ std::string helpFull;
+ std::string helpMAN;
+ std::string helpHTML;
+
+ std::string cpackProjectName;
+ std::string cpackProjectDirectory;
+ std::string cpackBuildConfig;
+ std::string cpackProjectVersion;
+ std::string cpackProjectPatch;
+ std::string cpackProjectVendor;
+ std::string cpackConfigFile;
+
+ cpackDefinitions definitions;
+ definitions.Log = &log;
+
+ cpackConfigFile.clear();
+
+ cmsys::CommandLineArguments arg;
+ arg.Initialize(argc, argv);
+ using argT = cmsys::CommandLineArguments;
+ // Help arguments
+ arg.AddArgument("--help", argT::NO_ARGUMENT, &help, "CPack help");
+ arg.AddArgument("--help-full", argT::SPACE_ARGUMENT, &helpFull,
+ "CPack help");
+ arg.AddArgument("--help-html", argT::SPACE_ARGUMENT, &helpHTML,
+ "CPack help");
+ arg.AddArgument("--help-man", argT::SPACE_ARGUMENT, &helpMAN, "CPack help");
+ arg.AddArgument("--version", argT::NO_ARGUMENT, &helpVersion, "CPack help");
+
+ arg.AddArgument("-V", argT::NO_ARGUMENT, &verbose, "CPack verbose");
+ arg.AddArgument("--verbose", argT::NO_ARGUMENT, &verbose, "-V");
+ arg.AddArgument("--debug", argT::NO_ARGUMENT, &debug, "-V");
+ arg.AddArgument("--config", argT::SPACE_ARGUMENT, &cpackConfigFile,
+ "CPack configuration file");
+ arg.AddArgument("--trace", argT::NO_ARGUMENT, &trace,
+ "Put underlying cmake scripts in trace mode.");
+ arg.AddArgument("--trace-expand", argT::NO_ARGUMENT, &traceExpand,
+ "Put underlying cmake scripts in expanded trace mode.");
+ arg.AddArgument("-C", argT::SPACE_ARGUMENT, &cpackBuildConfig,
+ "CPack build configuration");
+ arg.AddArgument("-G", argT::SPACE_ARGUMENT, &generator, "CPack generator");
+ arg.AddArgument("-P", argT::SPACE_ARGUMENT, &cpackProjectName,
+ "CPack project name");
+ arg.AddArgument("-R", argT::SPACE_ARGUMENT, &cpackProjectVersion,
+ "CPack project version");
+ arg.AddArgument("-B", argT::SPACE_ARGUMENT, &cpackProjectDirectory,
+ "CPack project directory");
+ arg.AddArgument("--patch", argT::SPACE_ARGUMENT, &cpackProjectPatch,
+ "CPack project patch");
+ arg.AddArgument("--vendor", argT::SPACE_ARGUMENT, &cpackProjectVendor,
+ "CPack project vendor");
+ arg.AddCallback("-D", argT::SPACE_ARGUMENT, cpackDefinitionArgument,
+ &definitions, "CPack Definitions");
+ arg.SetUnknownArgumentCallback(cpackUnknownArgument);
+
+ // Parse command line
+ int parsed = arg.Parse();
+
+ // Setup logging
+ if (verbose) {
+ log.SetVerbose(verbose);
+ cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Verbose" << std::endl);
+ }
+ if (debug) {
+ log.SetDebug(debug);
+ cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Debug" << std::endl);
+ }
+
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
+ "Read CPack config file: " << cpackConfigFile << std::endl);
+
+ cmake cminst(cmake::RoleScript, cmState::CPack);
+ cminst.SetHomeDirectory("");
+ cminst.SetHomeOutputDirectory("");
+ cminst.SetProgressCallback(cpackProgressCallback);
+ cminst.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator cmgg(&cminst);
+ cmMakefile globalMF(&cmgg, cminst.GetCurrentSnapshot());
+#if defined(__CYGWIN__)
+ globalMF.AddDefinition("CMAKE_LEGACY_CYGWIN_WIN32", "0");
+#endif
+
+ if (trace) {
+ cminst.SetTrace(true);
+ }
+ if (traceExpand) {
+ cminst.SetTrace(true);
+ cminst.SetTraceExpand(true);
+ }
+
+ bool cpackConfigFileSpecified = true;
+ if (cpackConfigFile.empty()) {
+ cpackConfigFile = cmStrCat(cmSystemTools::GetCurrentWorkingDirectory(),
+ "/CPackConfig.cmake");
+ cpackConfigFileSpecified = false;
+ }
+
+ cmCPackGeneratorFactory generators;
+ generators.SetLogger(&log);
+
+ cmDocumentation doc;
+ doc.addCPackStandardDocSections();
+ /* Were we invoked to display doc or to do some work ?
+ * Unlike cmake launching cpack with zero argument
+ * should launch cpack using "cpackConfigFile" if it exists
+ * in the current directory.
+ */
+ help = doc.CheckOptions(argc, argv, "-G") && argc != 1;
+
+ // This part is used for cpack documentation lookup as well.
+ cminst.AddCMakePaths();
+
+ if (parsed && !help) {
+ // find out which system cpack is running on, so it can setup the search
+ // paths, so FIND_XXX() commands can be used in scripts
+ std::string systemFile =
+ globalMF.GetModulesFile("CMakeDetermineSystem.cmake");
+ if (!globalMF.ReadListFile(systemFile)) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Error reading CMakeDetermineSystem.cmake" << std::endl);
+ return 1;
+ }
+
+ systemFile =
+ globalMF.GetModulesFile("CMakeSystemSpecificInformation.cmake");
+ if (!globalMF.ReadListFile(systemFile)) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Error reading CMakeSystemSpecificInformation.cmake"
+ << std::endl);
+ return 1;
+ }
+
+ if (!cpackBuildConfig.empty()) {
+ globalMF.AddDefinition("CPACK_BUILD_CONFIG", cpackBuildConfig);
+ }
+
+ if (cmSystemTools::FileExists(cpackConfigFile)) {
+ cpackConfigFile = cmSystemTools::CollapseFullPath(cpackConfigFile);
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
+ "Read CPack configuration file: " << cpackConfigFile
+ << std::endl);
+ if (!globalMF.ReadListFile(cpackConfigFile)) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Problem reading CPack config file: \""
+ << cpackConfigFile << "\"" << std::endl);
+ return 1;
+ }
+ } else if (cpackConfigFileSpecified) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Cannot find CPack config file: \"" << cpackConfigFile
+ << "\"" << std::endl);
+ return 1;
+ }
+
+ if (!generator.empty()) {
+ globalMF.AddDefinition("CPACK_GENERATOR", generator);
+ }
+ if (!cpackProjectName.empty()) {
+ globalMF.AddDefinition("CPACK_PACKAGE_NAME", cpackProjectName);
+ }
+ if (!cpackProjectVersion.empty()) {
+ globalMF.AddDefinition("CPACK_PACKAGE_VERSION", cpackProjectVersion);
+ }
+ if (!cpackProjectVendor.empty()) {
+ globalMF.AddDefinition("CPACK_PACKAGE_VENDOR", cpackProjectVendor);
+ }
+ // if this is not empty it has been set on the command line
+ // go for it. Command line override values set in config file.
+ if (!cpackProjectDirectory.empty()) {
+ globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY", cpackProjectDirectory);
+ }
+ // The value has not been set on the command line
+ else {
+ // get a default value (current working directory)
+ cpackProjectDirectory = cmSystemTools::GetCurrentWorkingDirectory();
+ // use default value if no value has been provided by the config file
+ if (!globalMF.IsSet("CPACK_PACKAGE_DIRECTORY")) {
+ globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY",
+ cpackProjectDirectory);
+ }
+ }
+ for (auto const& cd : definitions.Map) {
+ globalMF.AddDefinition(cd.first, cd.second);
+ }
+
+ // Force CPACK_PACKAGE_DIRECTORY as absolute path
+ cpackProjectDirectory =
+ globalMF.GetSafeDefinition("CPACK_PACKAGE_DIRECTORY");
+ cpackProjectDirectory =
+ cmSystemTools::CollapseFullPath(cpackProjectDirectory);
+ globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY", cpackProjectDirectory);
+
+ cmProp cpackModulesPath = globalMF.GetDefinition("CPACK_MODULE_PATH");
+ if (cpackModulesPath) {
+ globalMF.AddDefinition("CMAKE_MODULE_PATH", *cpackModulesPath);
+ }
+ cmProp genList = globalMF.GetDefinition("CPACK_GENERATOR");
+ if (!genList) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "CPack generator not specified" << std::endl);
+ } else {
+ std::vector<std::string> generatorsVector = cmExpandedList(*genList);
+ for (std::string const& gen : generatorsVector) {
+ cmMakefile::ScopePushPop raii(&globalMF);
+ cmMakefile* mf = &globalMF;
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
+ "Specified generator: " << gen << std::endl);
+ if (parsed && !mf->GetDefinition("CPACK_PACKAGE_NAME")) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "CPack project name not specified" << std::endl);
+ parsed = 0;
+ }
+ if (parsed &&
+ !(mf->GetDefinition("CPACK_PACKAGE_VERSION") ||
+ (mf->GetDefinition("CPACK_PACKAGE_VERSION_MAJOR") &&
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR") &&
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH")))) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "CPack project version not specified"
+ << std::endl
+ << "Specify CPACK_PACKAGE_VERSION, or "
+ "CPACK_PACKAGE_VERSION_MAJOR, "
+ "CPACK_PACKAGE_VERSION_MINOR, and "
+ "CPACK_PACKAGE_VERSION_PATCH."
+ << std::endl);
+ parsed = 0;
+ }
+ if (parsed) {
+ std::unique_ptr<cmCPackGenerator> cpackGenerator =
+ generators.NewGenerator(gen);
+ if (cpackGenerator) {
+ cpackGenerator->SetTrace(trace);
+ cpackGenerator->SetTraceExpand(traceExpand);
+ } else {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Could not create CPack generator: " << gen
+ << std::endl);
+ // Print out all the valid generators
+ cmDocumentation generatorDocs;
+ std::vector<cmDocumentationEntry> v;
+ for (auto const& g : generators.GetGeneratorsList()) {
+ cmDocumentationEntry e;
+ e.Name = g.first;
+ e.Brief = g.second;
+ v.push_back(std::move(e));
+ }
+ generatorDocs.SetSection("Generators", v);
+ std::cerr << "\n";
+ generatorDocs.PrintDocumentation(cmDocumentation::ListGenerators,
+ std::cerr);
+ parsed = 0;
+ }
+
+ if (parsed && !cpackGenerator->Initialize(gen, mf)) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Cannot initialize the generator " << gen
+ << std::endl);
+ parsed = 0;
+ }
+
+ if (!mf->GetDefinition("CPACK_INSTALL_COMMANDS") &&
+ !mf->GetDefinition("CPACK_INSTALL_SCRIPT") &&
+ !mf->GetDefinition("CPACK_INSTALLED_DIRECTORIES") &&
+ !mf->GetDefinition("CPACK_INSTALL_CMAKE_PROJECTS")) {
+ cmCPack_Log(
+ &log, cmCPackLog::LOG_ERROR,
+ "Please specify build tree of the project that uses CMake "
+ "using CPACK_INSTALL_CMAKE_PROJECTS, specify "
+ "CPACK_INSTALL_COMMANDS, CPACK_INSTALL_SCRIPT, or "
+ "CPACK_INSTALLED_DIRECTORIES."
+ << std::endl);
+ parsed = 0;
+ }
+ if (parsed) {
+ cmProp projName = mf->GetDefinition("CPACK_PACKAGE_NAME");
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
+ "Use generator: " << cpackGenerator->GetNameOfClass()
+ << std::endl);
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
+ "For project: " << *projName << std::endl);
+
+ cmProp projVersion = mf->GetDefinition("CPACK_PACKAGE_VERSION");
+ if (!projVersion) {
+ cmProp projVersionMajor =
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_MAJOR");
+ cmProp projVersionMinor =
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR");
+ cmProp projVersionPatch =
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH");
+ std::ostringstream ostr;
+ ostr << *projVersionMajor << "." << *projVersionMinor << "."
+ << *projVersionPatch;
+ mf->AddDefinition("CPACK_PACKAGE_VERSION", ostr.str());
+ }
+
+ int res = cpackGenerator->DoPackage();
+ if (!res) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Error when generating package: " << *projName
+ << std::endl);
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* In this case we are building the documentation object
+ * instance in order to create appropriate structure
+ * in order to satisfy the appropriate --help-xxx request
+ */
+ if (help) {
+ // Construct and print requested documentation.
+
+ doc.SetName("cpack");
+ doc.SetSection("Name", cmDocumentationName);
+ doc.SetSection("Usage", cmDocumentationUsage);
+ doc.PrependSection("Options", cmDocumentationOptions);
+
+ std::vector<cmDocumentationEntry> v;
+ for (auto const& g : generators.GetGeneratorsList()) {
+ cmDocumentationEntry e;
+ e.Name = g.first;
+ e.Brief = g.second;
+ v.push_back(std::move(e));
+ }
+ doc.SetSection("Generators", v);
+
+ return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
+ }
+
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx
new file mode 100644
index 0000000..a353435
--- /dev/null
+++ b/Source/CTest/cmCTestBZR.cxx
@@ -0,0 +1,478 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestBZR.h"
+
+#include <cstdlib>
+#include <list>
+#include <map>
+#include <ostream>
+#include <vector>
+
+#include <cmext/algorithm>
+
+#include <cm3p/expat.h>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCTest.h"
+#include "cmCTestVC.h"
+#include "cmProcessTools.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+
+extern "C" int cmBZRXMLParserUnknownEncodingHandler(void* /*unused*/,
+ const XML_Char* name,
+ XML_Encoding* info)
+{
+ static const int latin1[] = {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011,
+ 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A,
+ 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0021, 0x0022, 0x0023,
+ 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C,
+ 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035,
+ 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E,
+ 0x003F, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059,
+ 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060, 0x0061, 0x0062,
+ 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B,
+ 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074,
+ 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D,
+ 0x007E, 0x007F, 0x20AC, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020,
+ 0x2021, 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x017D, 0x008F,
+ 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC,
+ 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x017E, 0x0178, 0x00A0, 0x00A1,
+ 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA,
+ 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3,
+ 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC,
+ 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5,
+ 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE,
+ 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0,
+ 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9,
+ 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2,
+ 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB,
+ 0x00FC, 0x00FD, 0x00FE, 0x00FF
+ };
+
+ // The BZR xml output plugin can use some encodings that are not
+ // recognized by expat. This will lead to an error, e.g. "Error
+ // parsing bzr log xml: unknown encoding", the following is a
+ // workaround for these unknown encodings.
+ if (name == std::string("ascii") || name == std::string("cp1252") ||
+ name == std::string("ANSI_X3.4-1968")) {
+ for (unsigned int i = 0; i < 256; ++i) {
+ info->map[i] = latin1[i];
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+cmCTestBZR::cmCTestBZR(cmCTest* ct, std::ostream& log)
+ : cmCTestGlobalVC(ct, log)
+{
+ this->PriorRev = this->Unknown;
+ // Even though it is specified in the documentation, with bzr 1.13
+ // BZR_PROGRESS_BAR has no effect. In the future this bug might be fixed.
+ // Since it doesn't hurt, we specify this environment variable.
+ cmSystemTools::PutEnv("BZR_PROGRESS_BAR=none");
+}
+
+cmCTestBZR::~cmCTestBZR() = default;
+
+class cmCTestBZR::InfoParser : public cmCTestVC::LineParser
+{
+public:
+ InfoParser(cmCTestBZR* bzr, const char* prefix)
+ : BZR(bzr)
+ , CheckOutFound(false)
+ {
+ this->SetLog(&bzr->Log, prefix);
+ this->RegexCheckOut.compile("checkout of branch: *([^\t\r\n]+)$");
+ this->RegexParent.compile("parent branch: *([^\t\r\n]+)$");
+ }
+
+private:
+ cmCTestBZR* BZR;
+ bool CheckOutFound;
+ cmsys::RegularExpression RegexCheckOut;
+ cmsys::RegularExpression RegexParent;
+ bool ProcessLine() override
+ {
+ if (this->RegexCheckOut.find(this->Line)) {
+ this->BZR->URL = this->RegexCheckOut.match(1);
+ this->CheckOutFound = true;
+ } else if (!this->CheckOutFound && this->RegexParent.find(this->Line)) {
+ this->BZR->URL = this->RegexParent.match(1);
+ }
+ return true;
+ }
+};
+
+class cmCTestBZR::RevnoParser : public cmCTestVC::LineParser
+{
+public:
+ RevnoParser(cmCTestBZR* bzr, const char* prefix, std::string& rev)
+ : Rev(rev)
+ {
+ this->SetLog(&bzr->Log, prefix);
+ this->RegexRevno.compile("^([0-9]+)$");
+ }
+
+private:
+ std::string& Rev;
+ cmsys::RegularExpression RegexRevno;
+ bool ProcessLine() override
+ {
+ if (this->RegexRevno.find(this->Line)) {
+ this->Rev = this->RegexRevno.match(1);
+ }
+ return true;
+ }
+};
+
+std::string cmCTestBZR::LoadInfo()
+{
+ // Run "bzr info" to get the repository info from the work tree.
+ const char* bzr = this->CommandLineTool.c_str();
+ const char* bzr_info[] = { bzr, "info", nullptr };
+ InfoParser iout(this, "info-out> ");
+ OutputLogger ierr(this->Log, "info-err> ");
+ this->RunChild(bzr_info, &iout, &ierr);
+
+ // Run "bzr revno" to get the repository revision number from the work tree.
+ const char* bzr_revno[] = { bzr, "revno", nullptr };
+ std::string rev;
+ RevnoParser rout(this, "revno-out> ", rev);
+ OutputLogger rerr(this->Log, "revno-err> ");
+ this->RunChild(bzr_revno, &rout, &rerr);
+
+ return rev;
+}
+
+bool cmCTestBZR::NoteOldRevision()
+{
+ this->OldRevision = this->LoadInfo();
+ this->Log << "Revision before update: " << this->OldRevision << "\n";
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Old revision of repository is: " << this->OldRevision
+ << "\n");
+ this->PriorRev.Rev = this->OldRevision;
+ return true;
+}
+
+bool cmCTestBZR::NoteNewRevision()
+{
+ this->NewRevision = this->LoadInfo();
+ this->Log << "Revision after update: " << this->NewRevision << "\n";
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " New revision of repository is: " << this->NewRevision
+ << "\n");
+ this->Log << "URL = " << this->URL << "\n";
+ return true;
+}
+
+class cmCTestBZR::LogParser
+ : public cmCTestVC::OutputLogger
+ , private cmXMLParser
+{
+public:
+ LogParser(cmCTestBZR* bzr, const char* prefix)
+ : OutputLogger(bzr->Log, prefix)
+ , BZR(bzr)
+ , EmailRegex("(.*) <([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+)>")
+ {
+ this->InitializeParser();
+ }
+ ~LogParser() override { this->CleanupParser(); }
+
+ int InitializeParser() override
+ {
+ int res = this->cmXMLParser::InitializeParser();
+ if (res) {
+ XML_SetUnknownEncodingHandler(static_cast<XML_Parser>(this->Parser),
+ cmBZRXMLParserUnknownEncodingHandler,
+ nullptr);
+ }
+ return res;
+ }
+
+private:
+ cmCTestBZR* BZR;
+
+ using Revision = cmCTestBZR::Revision;
+ using Change = cmCTestBZR::Change;
+ Revision Rev;
+ std::vector<Change> Changes;
+ Change CurChange;
+ std::vector<char> CData;
+
+ cmsys::RegularExpression EmailRegex;
+
+ bool ProcessChunk(const char* data, int length) override
+ {
+ this->OutputLogger::ProcessChunk(data, length);
+ this->ParseChunk(data, length);
+ return true;
+ }
+
+ void StartElement(const std::string& name, const char** /*atts*/) override
+ {
+ this->CData.clear();
+ if (name == "log") {
+ this->Rev = Revision();
+ this->Changes.clear();
+ }
+ // affected-files can contain blocks of
+ // modified, unknown, renamed, kind-changed, removed, conflicts, added
+ else if (name == "modified" || name == "renamed" ||
+ name == "kind-changed") {
+ this->CurChange = Change();
+ this->CurChange.Action = 'M';
+ } else if (name == "added") {
+ this->CurChange = Change();
+ this->CurChange = 'A';
+ } else if (name == "removed") {
+ this->CurChange = Change();
+ this->CurChange = 'D';
+ } else if (name == "unknown" || name == "conflicts") {
+ // Should not happen here
+ this->CurChange = Change();
+ }
+ }
+
+ void CharacterDataHandler(const char* data, int length) override
+ {
+ cm::append(this->CData, data, data + length);
+ }
+
+ void EndElement(const std::string& name) override
+ {
+ if (name == "log") {
+ this->BZR->DoRevision(this->Rev, this->Changes);
+ } else if (!this->CData.empty() &&
+ (name == "file" || name == "directory")) {
+ this->CurChange.Path.assign(&this->CData[0], this->CData.size());
+ cmSystemTools::ConvertToUnixSlashes(this->CurChange.Path);
+ this->Changes.push_back(this->CurChange);
+ } else if (!this->CData.empty() && name == "symlink") {
+ // symlinks have an arobase at the end in the log
+ this->CurChange.Path.assign(&this->CData[0], this->CData.size() - 1);
+ cmSystemTools::ConvertToUnixSlashes(this->CurChange.Path);
+ this->Changes.push_back(this->CurChange);
+ } else if (!this->CData.empty() && name == "committer") {
+ this->Rev.Author.assign(&this->CData[0], this->CData.size());
+ if (this->EmailRegex.find(this->Rev.Author)) {
+ this->Rev.Author = this->EmailRegex.match(1);
+ this->Rev.EMail = this->EmailRegex.match(2);
+ }
+ } else if (!this->CData.empty() && name == "timestamp") {
+ this->Rev.Date.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "message") {
+ this->Rev.Log.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "revno") {
+ this->Rev.Rev.assign(&this->CData[0], this->CData.size());
+ }
+ this->CData.clear();
+ }
+
+ void ReportError(int /*line*/, int /*column*/, const char* msg) override
+ {
+ this->BZR->Log << "Error parsing bzr log xml: " << msg << "\n";
+ }
+};
+
+class cmCTestBZR::UpdateParser : public cmCTestVC::LineParser
+{
+public:
+ UpdateParser(cmCTestBZR* bzr, const char* prefix)
+ : BZR(bzr)
+ {
+ this->SetLog(&bzr->Log, prefix);
+ this->RegexUpdate.compile("^([-+R?XCP ])([NDKM ])([* ]) +(.+)$");
+ }
+
+private:
+ cmCTestBZR* BZR;
+ cmsys::RegularExpression RegexUpdate;
+
+ bool ProcessChunk(const char* first, int length) override
+ {
+ bool last_is_new_line = (*first == '\r' || *first == '\n');
+
+ const char* const last = first + length;
+ for (const char* c = first; c != last; ++c) {
+ if (*c == '\r' || *c == '\n') {
+ if (!last_is_new_line) {
+ // Log this line.
+ if (this->Log && this->Prefix) {
+ *this->Log << this->Prefix << this->Line << "\n";
+ }
+
+ // Hand this line to the subclass implementation.
+ if (!this->ProcessLine()) {
+ this->Line.clear();
+ return false;
+ }
+
+ this->Line.clear();
+ last_is_new_line = true;
+ }
+ } else {
+ // Append this character to the line under construction.
+ this->Line.append(1, *c);
+ last_is_new_line = false;
+ }
+ }
+ return true;
+ }
+
+ bool ProcessLine() override
+ {
+ if (this->RegexUpdate.find(this->Line)) {
+ this->DoPath(this->RegexUpdate.match(1)[0],
+ this->RegexUpdate.match(2)[0],
+ this->RegexUpdate.match(3)[0], this->RegexUpdate.match(4));
+ }
+ return true;
+ }
+
+ void DoPath(char c0, char c1, char c2, std::string path)
+ {
+ if (path.empty()) {
+ return;
+ }
+ cmSystemTools::ConvertToUnixSlashes(path);
+
+ const std::string dir = cmSystemTools::GetFilenamePath(path);
+ const std::string name = cmSystemTools::GetFilenameName(path);
+
+ if (c0 == 'C') {
+ this->BZR->Dirs[dir][name].Status = PathConflicting;
+ return;
+ }
+
+ if (c1 == 'M' || c1 == 'K' || c1 == 'N' || c1 == 'D' || c2 == '*') {
+ this->BZR->Dirs[dir][name].Status = PathUpdated;
+ return;
+ }
+ }
+};
+
+bool cmCTestBZR::UpdateImpl()
+{
+ // Get user-specified update options.
+ std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
+ if (opts.empty()) {
+ opts = this->CTest->GetCTestConfiguration("BZRUpdateOptions");
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
+
+ // TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
+
+ // Use "bzr pull" to update the working tree.
+ std::vector<char const*> bzr_update;
+ bzr_update.push_back(this->CommandLineTool.c_str());
+ bzr_update.push_back("pull");
+
+ for (std::string const& arg : args) {
+ bzr_update.push_back(arg.c_str());
+ }
+
+ bzr_update.push_back(this->URL.c_str());
+
+ bzr_update.push_back(nullptr);
+
+ // For some reason bzr uses stderr to display the update status.
+ OutputLogger out(this->Log, "pull-out> ");
+ UpdateParser err(this, "pull-err> ");
+ return this->RunUpdateCommand(&bzr_update[0], &out, &err);
+}
+
+bool cmCTestBZR::LoadRevisions()
+{
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Gathering version information (one . per revision):\n"
+ " "
+ << std::flush);
+
+ // We are interested in every revision included in the update.
+ this->Revisions.clear();
+ std::string revs;
+ if (atoi(this->OldRevision.c_str()) <= atoi(this->NewRevision.c_str())) {
+ // DoRevision takes care of discarding the information about OldRevision
+ revs = this->OldRevision + ".." + this->NewRevision;
+ } else {
+ return true;
+ }
+
+ // Run "bzr log" to get all global revisions of interest.
+ const char* bzr = this->CommandLineTool.c_str();
+ const char* bzr_log[] = {
+ bzr, "log", "-v", "-r", revs.c_str(), "--xml", this->URL.c_str(), nullptr
+ };
+ {
+ LogParser out(this, "log-out> ");
+ OutputLogger err(this->Log, "log-err> ");
+ this->RunChild(bzr_log, &out, &err);
+ }
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
+ return true;
+}
+
+class cmCTestBZR::StatusParser : public cmCTestVC::LineParser
+{
+public:
+ StatusParser(cmCTestBZR* bzr, const char* prefix)
+ : BZR(bzr)
+ {
+ this->SetLog(&bzr->Log, prefix);
+ this->RegexStatus.compile("^([-+R?XCP ])([NDKM ])([* ]) +(.+)$");
+ }
+
+private:
+ cmCTestBZR* BZR;
+ cmsys::RegularExpression RegexStatus;
+ bool ProcessLine() override
+ {
+ if (this->RegexStatus.find(this->Line)) {
+ this->DoPath(this->RegexStatus.match(1)[0],
+ this->RegexStatus.match(2)[0],
+ this->RegexStatus.match(3)[0], this->RegexStatus.match(4));
+ }
+ return true;
+ }
+
+ void DoPath(char c0, char c1, char c2, std::string path)
+ {
+ if (path.empty()) {
+ return;
+ }
+ cmSystemTools::ConvertToUnixSlashes(path);
+
+ if (c0 == 'C') {
+ this->BZR->DoModification(PathConflicting, path);
+ return;
+ }
+
+ if (c0 == '+' || c0 == 'R' || c0 == 'P' || c1 == 'M' || c1 == 'K' ||
+ c1 == 'N' || c1 == 'D' || c2 == '*') {
+ this->BZR->DoModification(PathModified, path);
+ return;
+ }
+ }
+};
+
+bool cmCTestBZR::LoadModifications()
+{
+ // Run "bzr status" which reports local modifications.
+ const char* bzr = this->CommandLineTool.c_str();
+ const char* bzr_status[] = { bzr, "status", "-SV", nullptr };
+ StatusParser out(this, "status-out> ");
+ OutputLogger err(this->Log, "status-err> ");
+ this->RunChild(bzr_status, &out, &err);
+ return true;
+}
diff --git a/Source/CTest/cmCTestBZR.h b/Source/CTest/cmCTestBZR.h
new file mode 100644
index 0000000..eb0dbbe
--- /dev/null
+++ b/Source/CTest/cmCTestBZR.h
@@ -0,0 +1,51 @@
+/* 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 <iosfwd>
+#include <string>
+
+#include "cmCTestGlobalVC.h"
+
+class cmCTest;
+
+/** \class cmCTestBZR
+ * \brief Interaction with bzr command-line tool
+ *
+ */
+class cmCTestBZR : public cmCTestGlobalVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestBZR(cmCTest* ctest, std::ostream& log);
+
+ ~cmCTestBZR() override;
+
+private:
+ // Implement cmCTestVC internal API.
+ bool NoteOldRevision() override;
+ bool NoteNewRevision() override;
+ bool UpdateImpl() override;
+
+ // URL of repository directory checked out in the working tree.
+ std::string URL;
+
+ std::string LoadInfo();
+ bool LoadModifications() override;
+ bool LoadRevisions() override;
+
+ // Parsing helper classes.
+ class InfoParser;
+ class LogParser;
+ class RevnoParser;
+ class StatusParser;
+ class UpdateParser;
+
+ friend class InfoParser;
+ friend class LogParser;
+ friend class RevnoParser;
+ friend class UpdateParser;
+ friend class StatusParser;
+};
diff --git a/Source/CTest/cmCTestBinPacker.cxx b/Source/CTest/cmCTestBinPacker.cxx
new file mode 100644
index 0000000..e21b14d
--- /dev/null
+++ b/Source/CTest/cmCTestBinPacker.cxx
@@ -0,0 +1,203 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestBinPacker.h"
+
+#include <algorithm>
+#include <utility>
+
+bool cmCTestBinPackerAllocation::operator==(
+ const cmCTestBinPackerAllocation& other) const
+{
+ return this->ProcessIndex == other.ProcessIndex &&
+ this->SlotsNeeded == other.SlotsNeeded && this->Id == other.Id;
+}
+
+bool cmCTestBinPackerAllocation::operator!=(
+ const cmCTestBinPackerAllocation& other) const
+{
+ return !(*this == other);
+}
+
+namespace {
+
+/*
+ * The following algorithm is used to do two things:
+ *
+ * 1) Determine if a test's resource requirements can fit within the resources
+ * present on the system, and
+ * 2) Do the actual allocation
+ *
+ * This algorithm performs a recursive search, looking for a bin pack that will
+ * fit the specified requirements. It has a template to specify different
+ * optimization strategies. If it ever runs out of room, it backtracks as far
+ * down the stack as it needs to and tries a different combination until no
+ * more combinations can be tried.
+ */
+template <typename AllocationStrategy>
+static bool AllocateCTestResources(
+ const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
+ const std::vector<std::string>& resourcesSorted, std::size_t currentIndex,
+ std::vector<cmCTestBinPackerAllocation*>& allocations)
+{
+ // Iterate through all large enough resources until we find a solution
+ std::size_t resourceIndex = 0;
+ while (resourceIndex < resourcesSorted.size()) {
+ auto const& resource = resources.at(resourcesSorted[resourceIndex]);
+ if (resource.Free() >=
+ static_cast<unsigned int>(allocations[currentIndex]->SlotsNeeded)) {
+ // Preemptively allocate the resource
+ allocations[currentIndex]->Id = resourcesSorted[resourceIndex];
+ if (currentIndex + 1 >= allocations.size()) {
+ // We have a solution
+ return true;
+ }
+
+ // Move the resource up the list until it is sorted again
+ auto resources2 = resources;
+ auto resourcesSorted2 = resourcesSorted;
+ resources2[resourcesSorted2[resourceIndex]].Locked +=
+ allocations[currentIndex]->SlotsNeeded;
+ AllocationStrategy::IncrementalSort(resources2, resourcesSorted2,
+ resourceIndex);
+
+ // Recurse one level deeper
+ if (AllocateCTestResources<AllocationStrategy>(
+ resources2, resourcesSorted2, currentIndex + 1, allocations)) {
+ return true;
+ }
+ }
+
+ // No solution found here, deallocate the resource and try the next one
+ allocations[currentIndex]->Id.clear();
+ auto freeSlots = resources.at(resourcesSorted.at(resourceIndex)).Free();
+ do {
+ ++resourceIndex;
+ } while (resourceIndex < resourcesSorted.size() &&
+ resources.at(resourcesSorted.at(resourceIndex)).Free() ==
+ freeSlots);
+ }
+
+ // No solution was found
+ return false;
+}
+
+template <typename AllocationStrategy>
+static bool AllocateCTestResources(
+ const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
+ std::vector<cmCTestBinPackerAllocation>& allocations)
+{
+ // Sort the resource requirements in descending order by slots needed
+ std::vector<cmCTestBinPackerAllocation*> allocationsPtr;
+ allocationsPtr.reserve(allocations.size());
+ for (auto& allocation : allocations) {
+ allocationsPtr.push_back(&allocation);
+ }
+ std::stable_sort(
+ allocationsPtr.rbegin(), allocationsPtr.rend(),
+ [](cmCTestBinPackerAllocation* a1, cmCTestBinPackerAllocation* a2) {
+ return a1->SlotsNeeded < a2->SlotsNeeded;
+ });
+
+ // Sort the resources according to sort strategy
+ std::vector<std::string> resourcesSorted;
+ resourcesSorted.reserve(resources.size());
+ for (auto const& res : resources) {
+ resourcesSorted.push_back(res.first);
+ }
+ AllocationStrategy::InitialSort(resources, resourcesSorted);
+
+ // Do the actual allocation
+ return AllocateCTestResources<AllocationStrategy>(
+ resources, resourcesSorted, std::size_t(0), allocationsPtr);
+}
+
+class RoundRobinAllocationStrategy
+{
+public:
+ static void InitialSort(
+ const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
+ std::vector<std::string>& resourcesSorted);
+
+ static void IncrementalSort(
+ const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
+ std::vector<std::string>& resourcesSorted, std::size_t lastAllocatedIndex);
+};
+
+void RoundRobinAllocationStrategy::InitialSort(
+ const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
+ std::vector<std::string>& resourcesSorted)
+{
+ std::stable_sort(
+ resourcesSorted.rbegin(), resourcesSorted.rend(),
+ [&resources](const std::string& id1, const std::string& id2) {
+ return resources.at(id1).Free() < resources.at(id2).Free();
+ });
+}
+
+void RoundRobinAllocationStrategy::IncrementalSort(
+ const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
+ std::vector<std::string>& resourcesSorted, std::size_t lastAllocatedIndex)
+{
+ auto tmp = resourcesSorted[lastAllocatedIndex];
+ std::size_t i = lastAllocatedIndex;
+ while (i < resourcesSorted.size() - 1 &&
+ resources.at(resourcesSorted[i + 1]).Free() >
+ resources.at(tmp).Free()) {
+ resourcesSorted[i] = resourcesSorted[i + 1];
+ ++i;
+ }
+ resourcesSorted[i] = tmp;
+}
+
+class BlockAllocationStrategy
+{
+public:
+ static void InitialSort(
+ const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
+ std::vector<std::string>& resourcesSorted);
+
+ static void IncrementalSort(
+ const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
+ std::vector<std::string>& resourcesSorted, std::size_t lastAllocatedIndex);
+};
+
+void BlockAllocationStrategy::InitialSort(
+ const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
+ std::vector<std::string>& resourcesSorted)
+{
+ std::stable_sort(
+ resourcesSorted.rbegin(), resourcesSorted.rend(),
+ [&resources](const std::string& id1, const std::string& id2) {
+ return resources.at(id1).Free() < resources.at(id2).Free();
+ });
+}
+
+void BlockAllocationStrategy::IncrementalSort(
+ const std::map<std::string, cmCTestResourceAllocator::Resource>&,
+ std::vector<std::string>& resourcesSorted, std::size_t lastAllocatedIndex)
+{
+ auto tmp = resourcesSorted[lastAllocatedIndex];
+ std::size_t i = lastAllocatedIndex;
+ while (i > 0) {
+ resourcesSorted[i] = resourcesSorted[i - 1];
+ --i;
+ }
+ resourcesSorted[i] = tmp;
+}
+}
+
+bool cmAllocateCTestResourcesRoundRobin(
+ const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
+ std::vector<cmCTestBinPackerAllocation>& allocations)
+{
+ return AllocateCTestResources<RoundRobinAllocationStrategy>(resources,
+ allocations);
+}
+
+bool cmAllocateCTestResourcesBlock(
+ const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
+ std::vector<cmCTestBinPackerAllocation>& allocations)
+{
+ return AllocateCTestResources<BlockAllocationStrategy>(resources,
+ allocations);
+}
diff --git a/Source/CTest/cmCTestBinPacker.h b/Source/CTest/cmCTestBinPacker.h
new file mode 100644
index 0000000..e56a437
--- /dev/null
+++ b/Source/CTest/cmCTestBinPacker.h
@@ -0,0 +1,28 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <cstddef>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "cmCTestResourceAllocator.h"
+
+struct cmCTestBinPackerAllocation
+{
+ std::size_t ProcessIndex;
+ int SlotsNeeded;
+ std::string Id;
+
+ bool operator==(const cmCTestBinPackerAllocation& other) const;
+ bool operator!=(const cmCTestBinPackerAllocation& other) const;
+};
+
+bool cmAllocateCTestResourcesRoundRobin(
+ const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
+ std::vector<cmCTestBinPackerAllocation>& allocations);
+
+bool cmAllocateCTestResourcesBlock(
+ const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
+ std::vector<cmCTestBinPackerAllocation>& allocations);
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
new file mode 100644
index 0000000..a18cbb4
--- /dev/null
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -0,0 +1,471 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestBuildAndTestHandler.h"
+
+#include <chrono>
+#include <cstdlib>
+#include <cstring>
+#include <ratio>
+
+#include "cmsys/Process.h"
+
+#include "cmCTest.h"
+#include "cmCTestTestHandler.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmWorkingDirectory.h"
+#include "cmake.h"
+
+cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler()
+{
+ this->BuildTwoConfig = false;
+ this->BuildNoClean = false;
+ this->BuildNoCMake = false;
+ this->Timeout = cmDuration::zero();
+}
+
+void cmCTestBuildAndTestHandler::Initialize()
+{
+ this->BuildTargets.clear();
+ this->Superclass::Initialize();
+}
+
+const char* cmCTestBuildAndTestHandler::GetOutput()
+{
+ return this->Output.c_str();
+}
+int cmCTestBuildAndTestHandler::ProcessHandler()
+{
+ this->Output.clear();
+ std::string output;
+ cmSystemTools::ResetErrorOccuredFlag();
+ int retv = this->RunCMakeAndTest(&this->Output);
+ cmSystemTools::ResetErrorOccuredFlag();
+ return retv;
+}
+
+int cmCTestBuildAndTestHandler::RunCMake(std::string* outstring,
+ std::ostringstream& out,
+ std::string& cmakeOutString,
+ cmake* cm)
+{
+ std::vector<std::string> args;
+ args.push_back(cmSystemTools::GetCMakeCommand());
+ args.push_back(this->SourceDir);
+ if (!this->BuildGenerator.empty()) {
+ args.push_back("-G" + this->BuildGenerator);
+ }
+ if (!this->BuildGeneratorPlatform.empty()) {
+ args.push_back("-A" + this->BuildGeneratorPlatform);
+ }
+ if (!this->BuildGeneratorToolset.empty()) {
+ args.push_back("-T" + this->BuildGeneratorToolset);
+ }
+
+ const char* config = nullptr;
+ if (!this->CTest->GetConfigType().empty()) {
+ config = this->CTest->GetConfigType().c_str();
+ }
+#ifdef CMAKE_INTDIR
+ if (!config) {
+ config = CMAKE_INTDIR;
+ }
+#endif
+
+ if (config) {
+ args.push_back("-DCMAKE_BUILD_TYPE:STRING=" + std::string(config));
+ }
+ if (!this->BuildMakeProgram.empty() &&
+ (this->BuildGenerator.find("Make") != std::string::npos ||
+ this->BuildGenerator.find("Ninja") != std::string::npos)) {
+ args.push_back("-DCMAKE_MAKE_PROGRAM:FILEPATH=" + this->BuildMakeProgram);
+ }
+
+ for (std::string const& opt : this->BuildOptions) {
+ args.push_back(opt);
+ }
+ if (cm->Run(args) != 0) {
+ out << "Error: cmake execution failed\n";
+ out << cmakeOutString << "\n";
+ if (outstring) {
+ *outstring = out.str();
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, out.str() << std::endl);
+ }
+ return 1;
+ }
+ // do another config?
+ if (this->BuildTwoConfig) {
+ if (cm->Run(args) != 0) {
+ out << "Error: cmake execution failed\n";
+ out << cmakeOutString << "\n";
+ if (outstring) {
+ *outstring = out.str();
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, out.str() << std::endl);
+ }
+ return 1;
+ }
+ }
+ out << "======== CMake output ======\n";
+ out << cmakeOutString;
+ out << "======== End CMake output ======\n";
+ return 0;
+}
+
+class cmCTestBuildAndTestCaptureRAII
+{
+ cmake& CM;
+
+public:
+ cmCTestBuildAndTestCaptureRAII(cmake& cm, std::string& s)
+ : CM(cm)
+ {
+ cmSystemTools::SetMessageCallback(
+ [&s](const std::string& msg, const char* /*unused*/) {
+ s += msg;
+ s += "\n";
+ });
+
+ cmSystemTools::SetStdoutCallback([&s](std::string const& m) { s += m; });
+ cmSystemTools::SetStderrCallback([&s](std::string const& m) { s += m; });
+
+ this->CM.SetProgressCallback([&s](const std::string& msg, float prog) {
+ if (prog < 0) {
+ s += msg;
+ s += "\n";
+ }
+ });
+ }
+
+ ~cmCTestBuildAndTestCaptureRAII()
+ {
+ this->CM.SetProgressCallback(nullptr);
+ cmSystemTools::SetStderrCallback(nullptr);
+ cmSystemTools::SetStdoutCallback(nullptr);
+ cmSystemTools::SetMessageCallback(nullptr);
+ }
+
+ cmCTestBuildAndTestCaptureRAII(const cmCTestBuildAndTestCaptureRAII&) =
+ delete;
+ cmCTestBuildAndTestCaptureRAII& operator=(
+ const cmCTestBuildAndTestCaptureRAII&) = delete;
+};
+
+int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
+{
+ // if the generator and make program are not specified then it is an error
+ if (this->BuildGenerator.empty()) {
+ if (outstring) {
+ *outstring = "--build-and-test requires that the generator "
+ "be provided using the --build-generator "
+ "command line option. ";
+ }
+ return 1;
+ }
+
+ cmake cm(cmake::RoleProject, cmState::Project);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ std::string cmakeOutString;
+ cmCTestBuildAndTestCaptureRAII captureRAII(cm, cmakeOutString);
+ static_cast<void>(captureRAII);
+ std::ostringstream out;
+
+ if (this->CTest->GetConfigType().empty() && !this->ConfigSample.empty()) {
+ // use the config sample to set the ConfigType
+ std::string fullPath;
+ std::string resultingConfig;
+ std::vector<std::string> extraPaths;
+ std::vector<std::string> failed;
+ fullPath = cmCTestTestHandler::FindExecutable(
+ this->CTest, this->ConfigSample, resultingConfig, extraPaths, failed);
+ if (!fullPath.empty() && !resultingConfig.empty()) {
+ this->CTest->SetConfigType(resultingConfig);
+ }
+ out << "Using config sample with results: " << fullPath << " and "
+ << resultingConfig << std::endl;
+ }
+
+ // we need to honor the timeout specified, the timeout include cmake, build
+ // and test time
+ auto clock_start = std::chrono::steady_clock::now();
+
+ // make sure the binary dir is there
+ out << "Internal cmake changing into directory: " << this->BinaryDir
+ << std::endl;
+ if (!cmSystemTools::FileIsDirectory(this->BinaryDir)) {
+ cmSystemTools::MakeDirectory(this->BinaryDir);
+ }
+ cmWorkingDirectory workdir(this->BinaryDir);
+ if (workdir.Failed()) {
+ auto msg = "Failed to change working directory to " + this->BinaryDir +
+ " : " + std::strerror(workdir.GetLastResult()) + "\n";
+ if (outstring) {
+ *outstring = msg;
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, msg);
+ }
+ return 1;
+ }
+
+ if (this->BuildNoCMake) {
+ // Make the generator available for the Build call below.
+ cm.SetGlobalGenerator(cm.CreateGlobalGenerator(this->BuildGenerator));
+ if (!this->BuildGeneratorPlatform.empty()) {
+ cmMakefile mf(cm.GetGlobalGenerator(), cm.GetCurrentSnapshot());
+ if (!cm.GetGlobalGenerator()->SetGeneratorPlatform(
+ this->BuildGeneratorPlatform, &mf)) {
+ return 1;
+ }
+ }
+
+ // Load the cache to make CMAKE_MAKE_PROGRAM available.
+ cm.LoadCache(this->BinaryDir);
+ } else {
+ // do the cmake step, no timeout here since it is not a sub process
+ if (this->RunCMake(outstring, out, cmakeOutString, &cm)) {
+ return 1;
+ }
+ }
+
+ // do the build
+ if (this->BuildTargets.empty()) {
+ this->BuildTargets.emplace_back();
+ }
+ for (std::string const& tar : this->BuildTargets) {
+ cmDuration remainingTime = std::chrono::seconds(0);
+ if (this->Timeout > cmDuration::zero()) {
+ remainingTime =
+ this->Timeout - (std::chrono::steady_clock::now() - clock_start);
+ if (remainingTime <= std::chrono::seconds(0)) {
+ if (outstring) {
+ *outstring = "--build-and-test timeout exceeded. ";
+ }
+ return 1;
+ }
+ }
+ std::string output;
+ const char* config = nullptr;
+ if (!this->CTest->GetConfigType().empty()) {
+ config = this->CTest->GetConfigType().c_str();
+ }
+#ifdef CMAKE_INTDIR
+ if (!config) {
+ config = CMAKE_INTDIR;
+ }
+#endif
+ if (!config) {
+ config = "Debug";
+ }
+ int retVal = cm.GetGlobalGenerator()->Build(
+ cmake::NO_BUILD_PARALLEL_LEVEL, this->SourceDir, this->BinaryDir,
+ this->BuildProject, { tar }, output, this->BuildMakeProgram, config,
+ !this->BuildNoClean, false, false, remainingTime);
+ out << output;
+ // if the build failed then return
+ if (retVal) {
+ if (outstring) {
+ *outstring = out.str();
+ }
+ return 1;
+ }
+ }
+ if (outstring) {
+ *outstring = out.str();
+ }
+
+ // if no test was specified then we are done
+ if (this->TestCommand.empty()) {
+ return 0;
+ }
+
+ // now run the compiled test if we can find it
+ // store the final location in fullPath
+ std::string fullPath;
+ std::string resultingConfig;
+ std::vector<std::string> extraPaths;
+ // if this->ExecutableDirectory is set try that as well
+ if (!this->ExecutableDirectory.empty()) {
+ std::string tempPath =
+ cmStrCat(this->ExecutableDirectory, '/', this->TestCommand);
+ extraPaths.push_back(tempPath);
+ }
+ std::vector<std::string> failed;
+ fullPath = cmCTestTestHandler::FindExecutable(
+ this->CTest, this->TestCommand, resultingConfig, extraPaths, failed);
+
+ if (!cmSystemTools::FileExists(fullPath)) {
+ out << "Could not find path to executable, perhaps it was not built: "
+ << this->TestCommand << "\n";
+ out << "tried to find it in these places:\n";
+ out << fullPath << "\n";
+ for (std::string const& fail : failed) {
+ out << fail << "\n";
+ }
+ if (outstring) {
+ *outstring = out.str();
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, out.str());
+ }
+ return 1;
+ }
+
+ std::vector<const char*> testCommand;
+ testCommand.push_back(fullPath.c_str());
+ for (std::string const& testCommandArg : this->TestCommandArgs) {
+ testCommand.push_back(testCommandArg.c_str());
+ }
+ testCommand.push_back(nullptr);
+ std::string outs;
+ int retval = 0;
+ // run the test from the this->BuildRunDir if set
+ if (!this->BuildRunDir.empty()) {
+ out << "Run test in directory: " << this->BuildRunDir << "\n";
+ if (!workdir.SetDirectory(this->BuildRunDir)) {
+ out << "Failed to change working directory : "
+ << std::strerror(workdir.GetLastResult()) << "\n";
+ if (outstring) {
+ *outstring = out.str();
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, out.str());
+ }
+ return 1;
+ }
+ }
+ out << "Running test command: \"" << fullPath << "\"";
+ for (std::string const& testCommandArg : this->TestCommandArgs) {
+ out << " \"" << testCommandArg << "\"";
+ }
+ out << "\n";
+
+ // how much time is remaining
+ cmDuration remainingTime = std::chrono::seconds(0);
+ if (this->Timeout > cmDuration::zero()) {
+ remainingTime =
+ this->Timeout - (std::chrono::steady_clock::now() - clock_start);
+ if (remainingTime <= std::chrono::seconds(0)) {
+ if (outstring) {
+ *outstring = "--build-and-test timeout exceeded. ";
+ }
+ return 1;
+ }
+ }
+
+ int runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr,
+ remainingTime, nullptr);
+
+ if (runTestRes != cmsysProcess_State_Exited || retval != 0) {
+ out << "Test command failed: " << testCommand[0] << "\n";
+ retval = 1;
+ }
+
+ out << outs << "\n";
+ if (outstring) {
+ *outstring = out.str();
+ } else {
+ cmCTestLog(this->CTest, OUTPUT, out.str() << std::endl);
+ }
+ return retval;
+}
+
+int cmCTestBuildAndTestHandler::ProcessCommandLineArguments(
+ const std::string& currentArg, size_t& idx,
+ const std::vector<std::string>& allArgs)
+{
+ // --build-and-test options
+ if (cmHasLiteralPrefix(currentArg, "--build-and-test") &&
+ idx < allArgs.size() - 1) {
+ if (idx + 2 < allArgs.size()) {
+ idx++;
+ this->SourceDir = allArgs[idx];
+ idx++;
+ this->BinaryDir = allArgs[idx];
+ // dir must exist before CollapseFullPath is called
+ cmSystemTools::MakeDirectory(this->BinaryDir);
+ this->BinaryDir = cmSystemTools::CollapseFullPath(this->BinaryDir);
+ this->SourceDir = cmSystemTools::CollapseFullPath(this->SourceDir);
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "--build-and-test must have source and binary dir"
+ << std::endl);
+ return 0;
+ }
+ }
+ if (cmHasLiteralPrefix(currentArg, "--build-target") &&
+ idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildTargets.push_back(allArgs[idx]);
+ }
+ if (cmHasLiteralPrefix(currentArg, "--build-nocmake")) {
+ this->BuildNoCMake = true;
+ }
+ if (cmHasLiteralPrefix(currentArg, "--build-run-dir") &&
+ idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildRunDir = allArgs[idx];
+ }
+ if (cmHasLiteralPrefix(currentArg, "--build-two-config")) {
+ this->BuildTwoConfig = true;
+ }
+ if (cmHasLiteralPrefix(currentArg, "--build-exe-dir") &&
+ idx < allArgs.size() - 1) {
+ idx++;
+ this->ExecutableDirectory = allArgs[idx];
+ }
+ if (cmHasLiteralPrefix(currentArg, "--test-timeout") &&
+ idx < allArgs.size() - 1) {
+ idx++;
+ this->Timeout = cmDuration(atof(allArgs[idx].c_str()));
+ }
+ if (currentArg == "--build-generator" && idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildGenerator = allArgs[idx];
+ }
+ if (currentArg == "--build-generator-platform" && idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildGeneratorPlatform = allArgs[idx];
+ }
+ if (currentArg == "--build-generator-toolset" && idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildGeneratorToolset = allArgs[idx];
+ }
+ if (cmHasLiteralPrefix(currentArg, "--build-project") &&
+ idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildProject = allArgs[idx];
+ }
+ if (cmHasLiteralPrefix(currentArg, "--build-makeprogram") &&
+ idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildMakeProgram = allArgs[idx];
+ }
+ if (cmHasLiteralPrefix(currentArg, "--build-config-sample") &&
+ idx < allArgs.size() - 1) {
+ idx++;
+ this->ConfigSample = allArgs[idx];
+ }
+ if (cmHasLiteralPrefix(currentArg, "--build-noclean")) {
+ this->BuildNoClean = true;
+ }
+ if (cmHasLiteralPrefix(currentArg, "--build-options")) {
+ while (idx + 1 < allArgs.size() && allArgs[idx + 1] != "--build-target" &&
+ allArgs[idx + 1] != "--test-command") {
+ ++idx;
+ this->BuildOptions.push_back(allArgs[idx]);
+ }
+ }
+ if (cmHasLiteralPrefix(currentArg, "--test-command") &&
+ idx < allArgs.size() - 1) {
+ ++idx;
+ this->TestCommand = allArgs[idx];
+ while (idx + 1 < allArgs.size()) {
+ ++idx;
+ this->TestCommandArgs.push_back(allArgs[idx]);
+ }
+ }
+ return 1;
+}
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.h b/Source/CTest/cmCTestBuildAndTestHandler.h
new file mode 100644
index 0000000..b9cc35c
--- /dev/null
+++ b/Source/CTest/cmCTestBuildAndTestHandler.h
@@ -0,0 +1,72 @@
+/* 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 <sstream>
+#include <string>
+#include <vector>
+
+#include <stddef.h>
+
+#include "cmCTestGenericHandler.h"
+#include "cmDuration.h"
+
+class cmake;
+
+/** \class cmCTestBuildAndTestHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ */
+class cmCTestBuildAndTestHandler : public cmCTestGenericHandler
+{
+public:
+ using Superclass = cmCTestGenericHandler;
+
+ /*
+ * The main entry point for this class
+ */
+ int ProcessHandler() override;
+
+ //! Set all the build and test arguments
+ int ProcessCommandLineArguments(
+ const std::string& currentArg, size_t& idx,
+ const std::vector<std::string>& allArgs) override;
+
+ /*
+ * Get the output variable
+ */
+ const char* GetOutput();
+
+ cmCTestBuildAndTestHandler();
+
+ void Initialize() override;
+
+protected:
+ //! Run CMake and build a test and then run it as a single test.
+ int RunCMakeAndTest(std::string* output);
+ int RunCMake(std::string* outstring, std::ostringstream& out,
+ std::string& cmakeOutString, cmake* cm);
+
+ std::string Output;
+
+ std::string BuildGenerator;
+ std::string BuildGeneratorPlatform;
+ std::string BuildGeneratorToolset;
+ std::vector<std::string> BuildOptions;
+ bool BuildTwoConfig;
+ std::string BuildMakeProgram;
+ std::string ConfigSample;
+ std::string SourceDir;
+ std::string BinaryDir;
+ std::string BuildProject;
+ std::string TestCommand;
+ bool BuildNoClean;
+ std::string BuildRunDir;
+ std::string ExecutableDirectory;
+ std::vector<std::string> TestCommandArgs;
+ std::vector<std::string> BuildTargets;
+ bool BuildNoCMake;
+ cmDuration Timeout;
+};
diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx
new file mode 100644
index 0000000..88e2871
--- /dev/null
+++ b/Source/CTest/cmCTestBuildCommand.cxx
@@ -0,0 +1,150 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestBuildCommand.h"
+
+#include <sstream>
+
+#include <cmext/string_view>
+
+#include "cmCTest.h"
+#include "cmCTestBuildHandler.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+class cmExecutionStatus;
+
+void cmCTestBuildCommand::BindArguments()
+{
+ this->cmCTestHandlerCommand::BindArguments();
+ this->Bind("NUMBER_ERRORS"_s, this->NumberErrors);
+ this->Bind("NUMBER_WARNINGS"_s, this->NumberWarnings);
+ this->Bind("TARGET"_s, this->Target);
+ this->Bind("CONFIGURATION"_s, this->Configuration);
+ this->Bind("FLAGS"_s, this->Flags);
+ this->Bind("PROJECT_NAME"_s, this->ProjectName);
+}
+
+cmCTestBuildCommand::~cmCTestBuildCommand() = default;
+
+cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
+{
+ cmCTestBuildHandler* handler = this->CTest->GetBuildHandler();
+ handler->Initialize();
+
+ this->Handler = handler;
+
+ cmProp ctestBuildCommand =
+ this->Makefile->GetDefinition("CTEST_BUILD_COMMAND");
+ if (cmNonempty(ctestBuildCommand)) {
+ this->CTest->SetCTestConfiguration("MakeCommand", *ctestBuildCommand,
+ this->Quiet);
+ } else {
+ cmProp cmakeGeneratorName =
+ this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR");
+
+ // Build configuration is determined by: CONFIGURATION argument,
+ // or CTEST_BUILD_CONFIGURATION script variable, or
+ // CTEST_CONFIGURATION_TYPE script variable, or ctest -C command
+ // line argument... in that order.
+ //
+ cmProp ctestBuildConfiguration =
+ this->Makefile->GetDefinition("CTEST_BUILD_CONFIGURATION");
+ std::string cmakeBuildConfiguration = cmNonempty(this->Configuration)
+ ? this->Configuration
+ : cmNonempty(ctestBuildConfiguration) ? *ctestBuildConfiguration
+ : this->CTest->GetConfigType();
+
+ const std::string& cmakeBuildAdditionalFlags = cmNonempty(this->Flags)
+ ? this->Flags
+ : this->Makefile->GetSafeDefinition("CTEST_BUILD_FLAGS");
+ const std::string& cmakeBuildTarget = cmNonempty(this->Target)
+ ? this->Target
+ : this->Makefile->GetSafeDefinition("CTEST_BUILD_TARGET");
+
+ if (cmNonempty(cmakeGeneratorName)) {
+ if (cmakeBuildConfiguration.empty()) {
+ cmakeBuildConfiguration = "Release";
+ }
+ if (this->GlobalGenerator) {
+ if (this->GlobalGenerator->GetName() != *cmakeGeneratorName) {
+ this->GlobalGenerator.reset();
+ }
+ }
+ if (!this->GlobalGenerator) {
+ this->GlobalGenerator =
+ this->Makefile->GetCMakeInstance()->CreateGlobalGenerator(
+ *cmakeGeneratorName);
+ if (!this->GlobalGenerator) {
+ std::string e = cmStrCat("could not create generator named \"",
+ *cmakeGeneratorName, '"');
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
+ cmSystemTools::SetFatalErrorOccured();
+ return nullptr;
+ }
+ }
+ if (cmakeBuildConfiguration.empty()) {
+#ifdef CMAKE_INTDIR
+ cmakeBuildConfiguration = CMAKE_INTDIR;
+#else
+ cmakeBuildConfiguration = "Debug";
+#endif
+ }
+
+ std::string dir = this->CTest->GetCTestConfiguration("BuildDirectory");
+ std::string buildCommand =
+ this->GlobalGenerator->GenerateCMakeBuildCommand(
+ cmakeBuildTarget, cmakeBuildConfiguration, cmakeBuildAdditionalFlags,
+ this->Makefile->IgnoreErrorsCMP0061());
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "SetMakeCommand:" << buildCommand << "\n",
+ this->Quiet);
+ this->CTest->SetCTestConfiguration("MakeCommand", buildCommand,
+ this->Quiet);
+ } else {
+ std::ostringstream ostr;
+ /* clang-format off */
+ ostr << "has no project to build. If this is a "
+ "\"built with CMake\" project, verify that CTEST_CMAKE_GENERATOR "
+ "is set. Otherwise, set CTEST_BUILD_COMMAND to build the project "
+ "with a custom command line.";
+ /* clang-format on */
+ this->SetError(ostr.str());
+ return nullptr;
+ }
+ }
+
+ if (cmProp useLaunchers =
+ this->Makefile->GetDefinition("CTEST_USE_LAUNCHERS")) {
+ this->CTest->SetCTestConfiguration("UseLaunchers", *useLaunchers,
+ this->Quiet);
+ }
+
+ if (cmProp labelsForSubprojects =
+ this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
+ this->CTest->SetCTestConfiguration("LabelsForSubprojects",
+ *labelsForSubprojects, this->Quiet);
+ }
+
+ handler->SetQuiet(this->Quiet);
+ return handler;
+}
+
+bool cmCTestBuildCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ bool ret = this->cmCTestHandlerCommand::InitialPass(args, status);
+ if (!this->NumberErrors.empty()) {
+ this->Makefile->AddDefinition(
+ this->NumberErrors, std::to_string(this->Handler->GetTotalErrors()));
+ }
+ if (!this->NumberWarnings.empty()) {
+ this->Makefile->AddDefinition(
+ this->NumberWarnings, std::to_string(this->Handler->GetTotalWarnings()));
+ }
+ return ret;
+}
diff --git a/Source/CTest/cmCTestBuildCommand.h b/Source/CTest/cmCTestBuildCommand.h
new file mode 100644
index 0000000..00dbcc4
--- /dev/null
+++ b/Source/CTest/cmCTestBuildCommand.h
@@ -0,0 +1,63 @@
+/* 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 <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmCTestHandlerCommand.h"
+#include "cmCommand.h"
+
+class cmCTestBuildHandler;
+class cmCTestGenericHandler;
+class cmExecutionStatus;
+class cmGlobalGenerator;
+
+/** \class cmCTestBuild
+ * \brief Run a ctest script
+ *
+ * cmCTestBuildCommand defineds the command to build the project.
+ */
+class cmCTestBuildCommand : public cmCTestHandlerCommand
+{
+public:
+ ~cmCTestBuildCommand() override;
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ auto ni = cm::make_unique<cmCTestBuildCommand>();
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return std::unique_ptr<cmCommand>(std::move(ni));
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const override { return "ctest_build"; }
+
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) override;
+
+ std::unique_ptr<cmGlobalGenerator> GlobalGenerator;
+
+protected:
+ cmCTestBuildHandler* Handler;
+ void BindArguments() override;
+ cmCTestGenericHandler* InitializeHandler() override;
+
+ std::string NumberErrors;
+ std::string NumberWarnings;
+ std::string Target;
+ std::string Configuration;
+ std::string Flags;
+ std::string ProjectName;
+};
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
new file mode 100644
index 0000000..103dc1e
--- /dev/null
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -0,0 +1,1177 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestBuildHandler.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <set>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+#include "cmsys/Process.h"
+
+#include "cmCTest.h"
+#include "cmCTestLaunchReporter.h"
+#include "cmDuration.h"
+#include "cmFileTimeCache.h"
+#include "cmGeneratedFileStream.h"
+#include "cmMakefile.h"
+#include "cmProcessOutput.h"
+#include "cmProperty.h"
+#include "cmStringAlgorithms.h"
+#include "cmStringReplaceHelper.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+
+static const char* cmCTestErrorMatches[] = {
+ "^[Bb]us [Ee]rror",
+ "^[Ss]egmentation [Vv]iolation",
+ "^[Ss]egmentation [Ff]ault",
+ ":.*[Pp]ermission [Dd]enied",
+ "([^ :]+):([0-9]+): ([^ \\t])",
+ "([^:]+): error[ \\t]*[0-9]+[ \\t]*:",
+ "^Error ([0-9]+):",
+ "^Fatal",
+ "^Error: ",
+ "^Error ",
+ "[0-9] ERROR: ",
+ R"(^"[^"]+", line [0-9]+: [^Ww])",
+ "^cc[^C]*CC: ERROR File = ([^,]+), Line = ([0-9]+)",
+ "^ld([^:])*:([ \\t])*ERROR([^:])*:",
+ R"(^ild:([ \t])*\(undefined symbol\))",
+ "([^ :]+) : (error|fatal error|catastrophic error)",
+ "([^:]+): (Error:|error|undefined reference|multiply defined)",
+ R"(([^:]+)\(([^\)]+)\) ?: (error|fatal error|catastrophic error))",
+ "^fatal error C[0-9]+:",
+ ": syntax error ",
+ "^collect2: ld returned 1 exit status",
+ "ld terminated with signal",
+ "Unsatisfied symbol",
+ "^Unresolved:",
+ "Undefined symbol",
+ "^Undefined[ \\t]+first referenced",
+ "^CMake Error.*:",
+ ":[ \\t]cannot find",
+ ":[ \\t]can't find",
+ R"(: \*\*\* No rule to make target [`'].*\'. Stop)",
+ R"(: \*\*\* No targets specified and no makefile found)",
+ ": Invalid loader fixup for symbol",
+ ": Invalid fixups exist",
+ ": Can't find library for",
+ ": internal link edit command failed",
+ ": Unrecognized option [`'].*\\'",
+ R"(", line [0-9]+\.[0-9]+: [0-9]+-[0-9]+ \([^WI]\))",
+ "ld: 0706-006 Cannot find or open library file: -l ",
+ "ild: \\(argument error\\) can't find library argument ::",
+ "^could not be found and will not be loaded.",
+ "s:616 string too big",
+ "make: Fatal error: ",
+ "ld: 0711-993 Error occurred while writing to the output file:",
+ "ld: fatal: ",
+ "final link failed:",
+ R"(make: \*\*\*.*Error)",
+ R"(make\[.*\]: \*\*\*.*Error)",
+ R"(\*\*\* Error code)",
+ "nternal error:",
+ R"(Makefile:[0-9]+: \*\*\* .* Stop\.)",
+ ": No such file or directory",
+ ": Invalid argument",
+ "^The project cannot be built\\.",
+ "^\\[ERROR\\]",
+ "^Command .* failed with exit code",
+ nullptr
+};
+
+static const char* cmCTestErrorExceptions[] = {
+ "instantiated from ",
+ "candidates are:",
+ ": warning",
+ ": WARNING",
+ ": \\(Warning\\)",
+ ": note",
+ "Note:",
+ "makefile:",
+ "Makefile:",
+ ":[ \\t]+Where:",
+ "([^ :]+):([0-9]+): Warning",
+ "------ Build started: .* ------",
+ nullptr
+};
+
+static const char* cmCTestWarningMatches[] = {
+ "([^ :]+):([0-9]+): warning:",
+ "([^ :]+):([0-9]+): note:",
+ "^cc[^C]*CC: WARNING File = ([^,]+), Line = ([0-9]+)",
+ "^ld([^:])*:([ \\t])*WARNING([^:])*:",
+ "([^:]+): warning ([0-9]+):",
+ R"(^"[^"]+", line [0-9]+: [Ww](arning|arnung))",
+ "([^:]+): warning[ \\t]*[0-9]+[ \\t]*:",
+ "^(Warning|Warnung) ([0-9]+):",
+ "^(Warning|Warnung)[ :]",
+ "WARNING: ",
+ "([^ :]+) : warning",
+ "([^:]+): warning",
+ R"(", line [0-9]+\.[0-9]+: [0-9]+-[0-9]+ \([WI]\))",
+ "^cxx: Warning:",
+ ".*file: .* has no symbols",
+ "([^ :]+):([0-9]+): (Warning|Warnung)",
+ "\\([0-9]*\\): remark #[0-9]*",
+ R"(".*", line [0-9]+: remark\([0-9]*\):)",
+ "cc-[0-9]* CC: REMARK File = .*, Line = [0-9]*",
+ "^CMake Warning.*:",
+ "^\\[WARNING\\]",
+ nullptr
+};
+
+static const char* cmCTestWarningExceptions[] = {
+ R"(/usr/.*/X11/Xlib\.h:[0-9]+: war.*: ANSI C\+\+ forbids declaration)",
+ R"(/usr/.*/X11/Xutil\.h:[0-9]+: war.*: ANSI C\+\+ forbids declaration)",
+ R"(/usr/.*/X11/XResource\.h:[0-9]+: war.*: ANSI C\+\+ forbids declaration)",
+ "WARNING 84 :",
+ "WARNING 47 :",
+ "makefile:",
+ "Makefile:",
+ "warning: Clock skew detected. Your build may be incomplete.",
+ "/usr/openwin/include/GL/[^:]+:",
+ "bind_at_load",
+ "XrmQGetResource",
+ "IceFlush",
+ "warning LNK4089: all references to [^ \\t]+ discarded by .OPT:REF",
+ "ld32: WARNING 85: definition of dataKey in",
+ "cc: warning 422: Unknown option \"\\+b",
+ "_with_warning_C",
+ nullptr
+};
+
+struct cmCTestBuildCompileErrorWarningRex
+{
+ const char* RegularExpressionString;
+ int FileIndex;
+ int LineIndex;
+};
+
+static cmCTestBuildCompileErrorWarningRex cmCTestWarningErrorFileLine[] = {
+ { "^Warning W[0-9]+ ([a-zA-Z.\\:/0-9_+ ~-]+) ([0-9]+):", 1, 2 },
+ { "^([a-zA-Z./0-9_+ ~-]+):([0-9]+):", 1, 2 },
+ { R"(^([a-zA-Z.\:/0-9_+ ~-]+)\(([0-9]+)\))", 1, 2 },
+ { R"(^[0-9]+>([a-zA-Z.\:/0-9_+ ~-]+)\(([0-9]+)\))", 1, 2 },
+ { "^([a-zA-Z./0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
+ { "\"([a-zA-Z./0-9_+ ~-]+)\", line ([0-9]+)", 1, 2 },
+ { "File = ([a-zA-Z./0-9_+ ~-]+), Line = ([0-9]+)", 1, 2 },
+ { nullptr, 0, 0 }
+};
+
+cmCTestBuildHandler::cmCTestBuildHandler()
+{
+ this->MaxPreContext = 10;
+ this->MaxPostContext = 10;
+
+ this->MaxErrors = 50;
+ this->MaxWarnings = 50;
+
+ this->LastErrorOrWarning = this->ErrorsAndWarnings.end();
+
+ this->UseCTestLaunch = false;
+}
+
+void cmCTestBuildHandler::Initialize()
+{
+ this->Superclass::Initialize();
+ this->StartBuild.clear();
+ this->EndBuild.clear();
+ this->CustomErrorMatches.clear();
+ this->CustomErrorExceptions.clear();
+ this->CustomWarningMatches.clear();
+ this->CustomWarningExceptions.clear();
+ this->ReallyCustomWarningMatches.clear();
+ this->ReallyCustomWarningExceptions.clear();
+ this->ErrorWarningFileLineRegex.clear();
+
+ this->ErrorMatchRegex.clear();
+ this->ErrorExceptionRegex.clear();
+ this->WarningMatchRegex.clear();
+ this->WarningExceptionRegex.clear();
+ this->BuildProcessingQueue.clear();
+ this->BuildProcessingErrorQueue.clear();
+ this->BuildOutputLogSize = 0;
+ this->CurrentProcessingLine.clear();
+
+ this->SimplifySourceDir.clear();
+ this->SimplifyBuildDir.clear();
+ this->OutputLineCounter = 0;
+ this->ErrorsAndWarnings.clear();
+ this->LastErrorOrWarning = this->ErrorsAndWarnings.end();
+ this->PostContextCount = 0;
+ this->MaxPreContext = 10;
+ this->MaxPostContext = 10;
+ this->PreContext.clear();
+
+ this->TotalErrors = 0;
+ this->TotalWarnings = 0;
+ this->LastTickChar = 0;
+
+ this->ErrorQuotaReached = false;
+ this->WarningQuotaReached = false;
+
+ this->MaxErrors = 50;
+ this->MaxWarnings = 50;
+
+ this->UseCTestLaunch = false;
+}
+
+void cmCTestBuildHandler::PopulateCustomVectors(cmMakefile* mf)
+{
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_ERROR_MATCH",
+ this->CustomErrorMatches);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_ERROR_EXCEPTION",
+ this->CustomErrorExceptions);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_WARNING_MATCH",
+ this->CustomWarningMatches);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_WARNING_EXCEPTION",
+ this->CustomWarningExceptions);
+ this->CTest->PopulateCustomInteger(
+ mf, "CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS", this->MaxErrors);
+ this->CTest->PopulateCustomInteger(
+ mf, "CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS", this->MaxWarnings);
+
+ int n = -1;
+ this->CTest->PopulateCustomInteger(mf, "CTEST_CUSTOM_ERROR_PRE_CONTEXT", n);
+ if (n != -1) {
+ this->MaxPreContext = static_cast<size_t>(n);
+ }
+
+ n = -1;
+ this->CTest->PopulateCustomInteger(mf, "CTEST_CUSTOM_ERROR_POST_CONTEXT", n);
+ if (n != -1) {
+ this->MaxPostContext = static_cast<size_t>(n);
+ }
+
+ // Record the user-specified custom warning rules.
+ if (cmProp customWarningMatchers =
+ mf->GetDefinition("CTEST_CUSTOM_WARNING_MATCH")) {
+ cmExpandList(*customWarningMatchers, this->ReallyCustomWarningMatches);
+ }
+ if (cmProp customWarningExceptions =
+ mf->GetDefinition("CTEST_CUSTOM_WARNING_EXCEPTION")) {
+ cmExpandList(*customWarningExceptions,
+ this->ReallyCustomWarningExceptions);
+ }
+}
+
+std::string cmCTestBuildHandler::GetMakeCommand()
+{
+ std::string makeCommand = this->CTest->GetCTestConfiguration("MakeCommand");
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "MakeCommand:" << makeCommand << "\n", this->Quiet);
+
+ std::string configType = this->CTest->GetConfigType();
+ if (configType.empty()) {
+ configType =
+ this->CTest->GetCTestConfiguration("DefaultCTestConfigurationType");
+ }
+ if (configType.empty()) {
+ configType = "Release";
+ }
+
+ cmSystemTools::ReplaceString(makeCommand, "${CTEST_CONFIGURATION_TYPE}",
+ configType.c_str());
+
+ return makeCommand;
+}
+
+// clearly it would be nice if this were broken up into a few smaller
+// functions and commented...
+int cmCTestBuildHandler::ProcessHandler()
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "Build project" << std::endl,
+ this->Quiet);
+
+ // do we have time for this
+ if (this->CTest->GetRemainingTimeAllowed() < std::chrono::minutes(2)) {
+ return 0;
+ }
+
+ int entry;
+ for (entry = 0; cmCTestWarningErrorFileLine[entry].RegularExpressionString;
+ ++entry) {
+ cmCTestBuildHandler::cmCTestCompileErrorWarningRex r;
+ if (r.RegularExpression.compile(
+ cmCTestWarningErrorFileLine[entry].RegularExpressionString)) {
+ r.FileIndex = cmCTestWarningErrorFileLine[entry].FileIndex;
+ r.LineIndex = cmCTestWarningErrorFileLine[entry].LineIndex;
+ this->ErrorWarningFileLineRegex.push_back(std::move(r));
+ } else {
+ cmCTestLog(
+ this->CTest, ERROR_MESSAGE,
+ "Problem Compiling regular expression: "
+ << cmCTestWarningErrorFileLine[entry].RegularExpressionString
+ << std::endl);
+ }
+ }
+
+ // Determine build command and build directory
+ std::string makeCommand = this->GetMakeCommand();
+ if (makeCommand.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find MakeCommand key in the DartConfiguration.tcl"
+ << std::endl);
+ return -1;
+ }
+
+ const std::string& buildDirectory =
+ this->CTest->GetCTestConfiguration("BuildDirectory");
+ if (buildDirectory.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find BuildDirectory key in the DartConfiguration.tcl"
+ << std::endl);
+ return -1;
+ }
+
+ std::string const& useLaunchers =
+ this->CTest->GetCTestConfiguration("UseLaunchers");
+ this->UseCTestLaunch = cmIsOn(useLaunchers);
+
+ // Create a last build log
+ cmGeneratedFileStream ofs;
+ auto elapsed_time_start = std::chrono::steady_clock::now();
+ if (!this->StartLogFile("Build", ofs)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create build log file" << std::endl);
+ }
+
+ // Create lists of regular expression strings for errors, error exceptions,
+ // warnings and warning exceptions.
+ std::vector<std::string>::size_type cc;
+ for (cc = 0; cmCTestErrorMatches[cc]; cc++) {
+ this->CustomErrorMatches.emplace_back(cmCTestErrorMatches[cc]);
+ }
+ for (cc = 0; cmCTestErrorExceptions[cc]; cc++) {
+ this->CustomErrorExceptions.emplace_back(cmCTestErrorExceptions[cc]);
+ }
+ for (cc = 0; cmCTestWarningMatches[cc]; cc++) {
+ this->CustomWarningMatches.emplace_back(cmCTestWarningMatches[cc]);
+ }
+
+ for (cc = 0; cmCTestWarningExceptions[cc]; cc++) {
+ this->CustomWarningExceptions.emplace_back(cmCTestWarningExceptions[cc]);
+ }
+
+ // Pre-compile regular expressions objects for all regular expressions
+
+#define cmCTestBuildHandlerPopulateRegexVector(strings, regexes) \
+ do { \
+ regexes.clear(); \
+ cmCTestOptionalLog(this->CTest, DEBUG, \
+ this << "Add " #regexes << std::endl, this->Quiet); \
+ for (std::string const& s : (strings)) { \
+ cmCTestOptionalLog(this->CTest, DEBUG, \
+ "Add " #strings ": " << s << std::endl, \
+ this->Quiet); \
+ (regexes).emplace_back(s); \
+ } \
+ } while (false)
+
+ cmCTestBuildHandlerPopulateRegexVector(this->CustomErrorMatches,
+ this->ErrorMatchRegex);
+ cmCTestBuildHandlerPopulateRegexVector(this->CustomErrorExceptions,
+ this->ErrorExceptionRegex);
+ cmCTestBuildHandlerPopulateRegexVector(this->CustomWarningMatches,
+ this->WarningMatchRegex);
+ cmCTestBuildHandlerPopulateRegexVector(this->CustomWarningExceptions,
+ this->WarningExceptionRegex);
+
+ // Determine source and binary tree substitutions to simplify the output.
+ this->SimplifySourceDir.clear();
+ this->SimplifyBuildDir.clear();
+ if (this->CTest->GetCTestConfiguration("SourceDirectory").size() > 20) {
+ std::string srcdir =
+ this->CTest->GetCTestConfiguration("SourceDirectory") + "/";
+ cc = srcdir.rfind('/', srcdir.size() - 2);
+ if (cc != std::string::npos) {
+ srcdir.resize(cc + 1);
+ this->SimplifySourceDir = std::move(srcdir);
+ }
+ }
+ if (this->CTest->GetCTestConfiguration("BuildDirectory").size() > 20) {
+ std::string bindir =
+ this->CTest->GetCTestConfiguration("BuildDirectory") + "/";
+ cc = bindir.rfind('/', bindir.size() - 2);
+ if (cc != std::string::npos) {
+ bindir.resize(cc + 1);
+ this->SimplifyBuildDir = std::move(bindir);
+ }
+ }
+
+ // Ok, let's do the build
+
+ // Remember start build time
+ this->StartBuild = this->CTest->CurrentTime();
+ this->StartBuildTime = std::chrono::system_clock::now();
+
+ cmStringReplaceHelper colorRemover("\x1b\\[[0-9;]*m", "", nullptr);
+ this->ColorRemover = &colorRemover;
+ int retVal = 0;
+ int res = cmsysProcess_State_Exited;
+ if (!this->CTest->GetShowOnly()) {
+ res = this->RunMakeCommand(makeCommand, &retVal, buildDirectory.c_str(), 0,
+ ofs);
+ } else {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Build with command: " << makeCommand << std::endl,
+ this->Quiet);
+ }
+
+ // Remember end build time and calculate elapsed time
+ this->EndBuild = this->CTest->CurrentTime();
+ this->EndBuildTime = std::chrono::system_clock::now();
+ auto elapsed_build_time =
+ std::chrono::steady_clock::now() - elapsed_time_start;
+
+ // Cleanups strings in the errors and warnings list.
+ if (!this->SimplifySourceDir.empty()) {
+ for (cmCTestBuildErrorWarning& evit : this->ErrorsAndWarnings) {
+ cmSystemTools::ReplaceString(evit.Text, this->SimplifySourceDir.c_str(),
+ "/.../");
+ cmSystemTools::ReplaceString(evit.PreContext,
+ this->SimplifySourceDir.c_str(), "/.../");
+ cmSystemTools::ReplaceString(evit.PostContext,
+ this->SimplifySourceDir.c_str(), "/.../");
+ }
+ }
+
+ if (!this->SimplifyBuildDir.empty()) {
+ for (cmCTestBuildErrorWarning& evit : this->ErrorsAndWarnings) {
+ cmSystemTools::ReplaceString(evit.Text, this->SimplifyBuildDir.c_str(),
+ "/.../");
+ cmSystemTools::ReplaceString(evit.PreContext,
+ this->SimplifyBuildDir.c_str(), "/.../");
+ cmSystemTools::ReplaceString(evit.PostContext,
+ this->SimplifyBuildDir.c_str(), "/.../");
+ }
+ }
+
+ // Generate XML output
+ cmGeneratedFileStream xofs;
+ if (!this->StartResultingXML(cmCTest::PartBuild, "Build", xofs)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create build XML file" << std::endl);
+ return -1;
+ }
+ cmXMLWriter xml(xofs);
+ this->GenerateXMLHeader(xml);
+ if (this->UseCTestLaunch) {
+ this->GenerateXMLLaunched(xml);
+ } else {
+ this->GenerateXMLLogScraped(xml);
+ }
+ this->GenerateXMLFooter(xml, elapsed_build_time);
+
+ if (res != cmsysProcess_State_Exited || retVal || this->TotalErrors > 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error(s) when building project" << std::endl);
+ }
+
+ // Display message about number of errors and warnings
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " " << this->TotalErrors
+ << (this->TotalErrors >= this->MaxErrors ? " or more" : "")
+ << " Compiler errors" << std::endl);
+ cmCTestLog(
+ this->CTest, HANDLER_OUTPUT,
+ " " << this->TotalWarnings
+ << (this->TotalWarnings >= this->MaxWarnings ? " or more" : "")
+ << " Compiler warnings" << std::endl);
+
+ return retVal;
+}
+
+void cmCTestBuildHandler::GenerateXMLHeader(cmXMLWriter& xml)
+{
+ this->CTest->StartXML(xml, this->AppendXML);
+ this->CTest->GenerateSubprojectsOutput(xml);
+ xml.StartElement("Build");
+ xml.Element("StartDateTime", this->StartBuild);
+ xml.Element("StartBuildTime", this->StartBuildTime);
+ xml.Element("BuildCommand", this->GetMakeCommand());
+}
+
+class cmCTestBuildHandler::FragmentCompare
+{
+public:
+ FragmentCompare(cmFileTimeCache* ftc)
+ : FTC(ftc)
+ {
+ }
+ FragmentCompare() = default;
+ bool operator()(std::string const& l, std::string const& r) const
+ {
+ // Order files by modification time. Use lexicographic order
+ // among files with the same time.
+ int result;
+ if (this->FTC->Compare(l, r, &result) && result != 0) {
+ return result < 0;
+ }
+ return l < r;
+ }
+
+private:
+ cmFileTimeCache* FTC = nullptr;
+};
+
+void cmCTestBuildHandler::GenerateXMLLaunched(cmXMLWriter& xml)
+{
+ if (this->CTestLaunchDir.empty()) {
+ return;
+ }
+
+ // Sort XML fragments in chronological order.
+ cmFileTimeCache ftc;
+ FragmentCompare fragmentCompare(&ftc);
+ using Fragments = std::set<std::string, FragmentCompare>;
+ Fragments fragments(fragmentCompare);
+
+ // only report the first 50 warnings and first 50 errors
+ int numErrorsAllowed = this->MaxErrors;
+ int numWarningsAllowed = this->MaxWarnings;
+ // Identify fragments on disk.
+ cmsys::Directory launchDir;
+ launchDir.Load(this->CTestLaunchDir);
+ unsigned long n = launchDir.GetNumberOfFiles();
+ for (unsigned long i = 0; i < n; ++i) {
+ const char* fname = launchDir.GetFile(i);
+ if (this->IsLaunchedErrorFile(fname) && numErrorsAllowed) {
+ numErrorsAllowed--;
+ fragments.insert(this->CTestLaunchDir + '/' + fname);
+ ++this->TotalErrors;
+ } else if (this->IsLaunchedWarningFile(fname) && numWarningsAllowed) {
+ numWarningsAllowed--;
+ fragments.insert(this->CTestLaunchDir + '/' + fname);
+ ++this->TotalWarnings;
+ }
+ }
+
+ // Copy the fragments into the final XML file.
+ for (std::string const& f : fragments) {
+ xml.FragmentFile(f.c_str());
+ }
+}
+
+void cmCTestBuildHandler::GenerateXMLLogScraped(cmXMLWriter& xml)
+{
+ std::vector<cmCTestBuildErrorWarning>& ew = this->ErrorsAndWarnings;
+ std::vector<cmCTestBuildErrorWarning>::iterator it;
+
+ // only report the first 50 warnings and first 50 errors
+ int numErrorsAllowed = this->MaxErrors;
+ int numWarningsAllowed = this->MaxWarnings;
+ std::string srcdir = this->CTest->GetCTestConfiguration("SourceDirectory");
+ // make sure the source dir is in the correct case on windows
+ // via a call to collapse full path.
+ srcdir = cmStrCat(cmSystemTools::CollapseFullPath(srcdir), '/');
+ for (it = ew.begin();
+ it != ew.end() && (numErrorsAllowed || numWarningsAllowed); it++) {
+ cmCTestBuildErrorWarning* cm = &(*it);
+ if ((cm->Error && numErrorsAllowed) ||
+ (!cm->Error && numWarningsAllowed)) {
+ if (cm->Error) {
+ numErrorsAllowed--;
+ } else {
+ numWarningsAllowed--;
+ }
+ xml.StartElement(cm->Error ? "Error" : "Warning");
+ xml.Element("BuildLogLine", cm->LogLine);
+ xml.Element("Text", cm->Text);
+ for (cmCTestCompileErrorWarningRex& rit :
+ this->ErrorWarningFileLineRegex) {
+ cmsys::RegularExpression* re = &rit.RegularExpression;
+ if (re->find(cm->Text)) {
+ cm->SourceFile = re->match(rit.FileIndex);
+ // At this point we need to make this->SourceFile relative to
+ // the source root of the project, so cvs links will work
+ cmSystemTools::ConvertToUnixSlashes(cm->SourceFile);
+ if (cm->SourceFile.find("/.../") != std::string::npos) {
+ cmSystemTools::ReplaceString(cm->SourceFile, "/.../", "");
+ std::string::size_type p = cm->SourceFile.find('/');
+ if (p != std::string::npos) {
+ cm->SourceFile =
+ cm->SourceFile.substr(p + 1, cm->SourceFile.size() - p);
+ }
+ } else {
+ // make sure it is a full path with the correct case
+ cm->SourceFile = cmSystemTools::CollapseFullPath(cm->SourceFile);
+ cmSystemTools::ReplaceString(cm->SourceFile, srcdir.c_str(), "");
+ }
+ cm->LineNumber = atoi(re->match(rit.LineIndex).c_str());
+ break;
+ }
+ }
+ if (!cm->SourceFile.empty() && cm->LineNumber >= 0) {
+ if (!cm->SourceFile.empty()) {
+ xml.Element("SourceFile", cm->SourceFile);
+ }
+ if (!cm->SourceFileTail.empty()) {
+ xml.Element("SourceFileTail", cm->SourceFileTail);
+ }
+ if (cm->LineNumber >= 0) {
+ xml.Element("SourceLineNumber", cm->LineNumber);
+ }
+ }
+ xml.Element("PreContext", cm->PreContext);
+ xml.StartElement("PostContext");
+ xml.Content(cm->PostContext);
+ // is this the last warning or error, if so notify
+ if ((cm->Error && !numErrorsAllowed) ||
+ (!cm->Error && !numWarningsAllowed)) {
+ xml.Content("\nThe maximum number of reported warnings or errors "
+ "has been reached!!!\n");
+ }
+ xml.EndElement(); // PostContext
+ xml.Element("RepeatCount", "0");
+ xml.EndElement(); // "Error" / "Warning"
+ }
+ }
+}
+
+void cmCTestBuildHandler::GenerateXMLFooter(cmXMLWriter& xml,
+ cmDuration elapsed_build_time)
+{
+ xml.StartElement("Log");
+ xml.Attribute("Encoding", "base64");
+ xml.Attribute("Compression", "bin/gzip");
+ xml.EndElement(); // Log
+
+ xml.Element("EndDateTime", this->EndBuild);
+ xml.Element("EndBuildTime", this->EndBuildTime);
+ xml.Element(
+ "ElapsedMinutes",
+ std::chrono::duration_cast<std::chrono::minutes>(elapsed_build_time)
+ .count());
+ xml.EndElement(); // Build
+ this->CTest->EndXML(xml);
+}
+
+bool cmCTestBuildHandler::IsLaunchedErrorFile(const char* fname)
+{
+ // error-{hash}.xml
+ return (cmHasLiteralPrefix(fname, "error-") &&
+ strcmp(fname + strlen(fname) - 4, ".xml") == 0);
+}
+
+bool cmCTestBuildHandler::IsLaunchedWarningFile(const char* fname)
+{
+ // warning-{hash}.xml
+ return (cmHasLiteralPrefix(fname, "warning-") &&
+ strcmp(fname + strlen(fname) - 4, ".xml") == 0);
+}
+
+//######################################################################
+//######################################################################
+//######################################################################
+//######################################################################
+
+class cmCTestBuildHandler::LaunchHelper
+{
+public:
+ LaunchHelper(cmCTestBuildHandler* handler);
+ ~LaunchHelper();
+ LaunchHelper(const LaunchHelper&) = delete;
+ LaunchHelper& operator=(const LaunchHelper&) = delete;
+
+private:
+ cmCTestBuildHandler* Handler;
+ cmCTest* CTest;
+
+ void WriteLauncherConfig();
+ void WriteScrapeMatchers(const char* purpose,
+ std::vector<std::string> const& matchers);
+};
+
+cmCTestBuildHandler::LaunchHelper::LaunchHelper(cmCTestBuildHandler* handler)
+ : Handler(handler)
+ , CTest(handler->CTest)
+{
+ std::string tag = this->CTest->GetCurrentTag();
+ if (tag.empty()) {
+ // This is not for a dashboard submission, so there is no XML.
+ // Skip enabling the launchers.
+ this->Handler->UseCTestLaunch = false;
+ } else {
+ // Compute a directory in which to store launcher fragments.
+ std::string& launchDir = this->Handler->CTestLaunchDir;
+ launchDir =
+ cmStrCat(this->CTest->GetBinaryDir(), "/Testing/", tag, "/Build");
+
+ // Clean out any existing launcher fragments.
+ cmSystemTools::RemoveADirectory(launchDir);
+
+ if (this->Handler->UseCTestLaunch) {
+ // Enable launcher fragments.
+ cmSystemTools::MakeDirectory(launchDir);
+ this->WriteLauncherConfig();
+ std::string launchEnv = cmStrCat("CTEST_LAUNCH_LOGS=", launchDir);
+ cmSystemTools::PutEnv(launchEnv);
+ }
+ }
+
+ // If not using launchers, make sure they passthru.
+ if (!this->Handler->UseCTestLaunch) {
+ cmSystemTools::UnsetEnv("CTEST_LAUNCH_LOGS");
+ }
+}
+
+cmCTestBuildHandler::LaunchHelper::~LaunchHelper()
+{
+ if (this->Handler->UseCTestLaunch) {
+ cmSystemTools::UnsetEnv("CTEST_LAUNCH_LOGS");
+ }
+}
+
+void cmCTestBuildHandler::LaunchHelper::WriteLauncherConfig()
+{
+ this->WriteScrapeMatchers("Warning",
+ this->Handler->ReallyCustomWarningMatches);
+ this->WriteScrapeMatchers("WarningSuppress",
+ this->Handler->ReallyCustomWarningExceptions);
+
+ // Give some testing configuration information to the launcher.
+ std::string fname =
+ cmStrCat(this->Handler->CTestLaunchDir, "/CTestLaunchConfig.cmake");
+ cmGeneratedFileStream fout(fname);
+ std::string srcdir = this->CTest->GetCTestConfiguration("SourceDirectory");
+ fout << "set(CTEST_SOURCE_DIRECTORY \"" << srcdir << "\")\n";
+}
+
+void cmCTestBuildHandler::LaunchHelper::WriteScrapeMatchers(
+ const char* purpose, std::vector<std::string> const& matchers)
+{
+ if (matchers.empty()) {
+ return;
+ }
+ std::string fname =
+ cmStrCat(this->Handler->CTestLaunchDir, "/Custom", purpose, ".txt");
+ cmGeneratedFileStream fout(fname);
+ for (std::string const& m : matchers) {
+ fout << m << "\n";
+ }
+}
+
+int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
+ int* retVal, const char* dir,
+ int timeout, std::ostream& ofs,
+ Encoding encoding)
+{
+ // First generate the command and arguments
+ std::vector<std::string> args = cmSystemTools::ParseArguments(command);
+
+ if (args.empty()) {
+ return false;
+ }
+
+ std::vector<const char*> argv;
+ argv.reserve(args.size() + 1);
+ for (std::string const& arg : args) {
+ argv.push_back(arg.c_str());
+ }
+ argv.push_back(nullptr);
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run command:", this->Quiet);
+ for (char const* arg : argv) {
+ if (!arg) {
+ break;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " \"" << arg << "\"", this->Quiet);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl,
+ this->Quiet);
+
+ // Optionally use make rule launchers to record errors and warnings.
+ LaunchHelper launchHelper(this);
+ static_cast<void>(launchHelper);
+
+ // Now create process object
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, argv.data());
+ cmsysProcess_SetWorkingDirectory(cp, dir);
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ cmsysProcess_SetTimeout(cp, timeout);
+ cmsysProcess_Execute(cp);
+
+ // Initialize tick's
+ std::string::size_type tick = 0;
+ const std::string::size_type tick_len = 1024;
+
+ char* data;
+ int length;
+ cmProcessOutput processOutput(encoding);
+ std::string strdata;
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_PROGRESS_OUTPUT,
+ " Each symbol represents "
+ << tick_len << " bytes of output." << std::endl
+ << (this->UseCTestLaunch
+ ? ""
+ : " '!' represents an error and '*' a warning.\n")
+ << " " << std::flush,
+ this->Quiet);
+
+ // Initialize building structures
+ this->BuildProcessingQueue.clear();
+ this->OutputLineCounter = 0;
+ this->ErrorsAndWarnings.clear();
+ this->TotalErrors = 0;
+ this->TotalWarnings = 0;
+ this->BuildOutputLogSize = 0;
+ this->LastTickChar = '.';
+ this->WarningQuotaReached = false;
+ this->ErrorQuotaReached = false;
+
+ // For every chunk of data
+ int res;
+ while ((res = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) {
+ // Replace '\0' with '\n', since '\0' does not really make sense. This is
+ // for Visual Studio output
+ for (int cc = 0; cc < length; ++cc) {
+ if (data[cc] == 0) {
+ data[cc] = '\n';
+ }
+ }
+
+ // Process the chunk of data
+ if (res == cmsysProcess_Pipe_STDERR) {
+ processOutput.DecodeText(data, length, strdata, 1);
+ this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs,
+ &this->BuildProcessingErrorQueue);
+ } else {
+ processOutput.DecodeText(data, length, strdata, 2);
+ this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs,
+ &this->BuildProcessingQueue);
+ }
+ }
+ processOutput.DecodeText(std::string(), strdata, 1);
+ if (!strdata.empty()) {
+ this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs,
+ &this->BuildProcessingErrorQueue);
+ }
+ processOutput.DecodeText(std::string(), strdata, 2);
+ if (!strdata.empty()) {
+ this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs,
+ &this->BuildProcessingQueue);
+ }
+
+ this->ProcessBuffer(nullptr, 0, tick, tick_len, ofs,
+ &this->BuildProcessingQueue);
+ this->ProcessBuffer(nullptr, 0, tick, tick_len, ofs,
+ &this->BuildProcessingErrorQueue);
+ cmCTestOptionalLog(this->CTest, HANDLER_PROGRESS_OUTPUT,
+ " Size of output: "
+ << ((this->BuildOutputLogSize + 512) / 1024) << "K"
+ << std::endl,
+ this->Quiet);
+
+ // Properly handle output of the build command
+ cmsysProcess_WaitForExit(cp, nullptr);
+ int result = cmsysProcess_GetState(cp);
+
+ if (result == cmsysProcess_State_Exited) {
+ if (retVal) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Command exited with the value: " << *retVal
+ << std::endl,
+ this->Quiet);
+ // if a non zero return value
+ if (*retVal) {
+ // If there was an error running command, report that on the
+ // dashboard.
+ if (this->UseCTestLaunch) {
+ cmCTestLaunchReporter reporter;
+ reporter.RealArgs = args;
+ reporter.ComputeFileNames();
+ reporter.ExitCode = *retVal;
+ reporter.Process = cp;
+ // Use temporary BuildLog file to populate this error for CDash.
+ ofs.flush();
+ reporter.LogOut = this->LogFileNames["Build"];
+ reporter.LogOut += ".tmp";
+ reporter.WriteXML();
+ } else {
+ cmCTestBuildErrorWarning errorwarning;
+ errorwarning.LineNumber = 0;
+ errorwarning.LogLine = 1;
+ errorwarning.Text = cmStrCat(
+ "*** WARNING non-zero return value in ctest from: ", argv[0]);
+ errorwarning.PreContext.clear();
+ errorwarning.PostContext.clear();
+ errorwarning.Error = false;
+ this->ErrorsAndWarnings.push_back(std::move(errorwarning));
+ this->TotalWarnings++;
+ }
+ }
+ }
+ } else if (result == cmsysProcess_State_Exception) {
+ if (retVal) {
+ *retVal = cmsysProcess_GetExitException(cp);
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "There was an exception: " << *retVal << std::endl,
+ this->Quiet);
+ }
+ } else if (result == cmsysProcess_State_Expired) {
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "There was a timeout" << std::endl, this->Quiet);
+ } else if (result == cmsysProcess_State_Error) {
+ // If there was an error running command, report that on the dashboard.
+ cmCTestBuildErrorWarning errorwarning;
+ errorwarning.LineNumber = 0;
+ errorwarning.LogLine = 1;
+ errorwarning.Text =
+ cmStrCat("*** ERROR executing: ", cmsysProcess_GetErrorString(cp));
+ errorwarning.PreContext.clear();
+ errorwarning.PostContext.clear();
+ errorwarning.Error = true;
+ this->ErrorsAndWarnings.push_back(std::move(errorwarning));
+ this->TotalErrors++;
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "There was an error: " << cmsysProcess_GetErrorString(cp)
+ << std::endl);
+ }
+
+ cmsysProcess_Delete(cp);
+ return result;
+}
+
+//######################################################################
+//######################################################################
+//######################################################################
+//######################################################################
+
+void cmCTestBuildHandler::ProcessBuffer(const char* data, size_t length,
+ size_t& tick, size_t tick_len,
+ std::ostream& ofs,
+ t_BuildProcessingQueueType* queue)
+{
+ const std::string::size_type tick_line_len = 50;
+ const char* ptr;
+ for (ptr = data; ptr < data + length; ptr++) {
+ queue->push_back(*ptr);
+ }
+ this->BuildOutputLogSize += length;
+
+ // until there are any lines left in the buffer
+ while (true) {
+ // Find the end of line
+ t_BuildProcessingQueueType::iterator it;
+ for (it = queue->begin(); it != queue->end(); ++it) {
+ if (*it == '\n') {
+ break;
+ }
+ }
+
+ // Once certain number of errors or warnings reached, ignore future errors
+ // or warnings.
+ if (this->TotalWarnings >= this->MaxWarnings) {
+ this->WarningQuotaReached = true;
+ }
+ if (this->TotalErrors >= this->MaxErrors) {
+ this->ErrorQuotaReached = true;
+ }
+
+ // If the end of line was found
+ if (it != queue->end()) {
+ // Create a contiguous array for the line
+ this->CurrentProcessingLine.clear();
+ cm::append(this->CurrentProcessingLine, queue->begin(), it);
+ this->CurrentProcessingLine.push_back(0);
+ const char* line = this->CurrentProcessingLine.data();
+
+ // Process the line
+ int lineType = this->ProcessSingleLine(line);
+
+ // Erase the line from the queue
+ queue->erase(queue->begin(), it + 1);
+
+ // Depending on the line type, produce error or warning, or nothing
+ cmCTestBuildErrorWarning errorwarning;
+ bool found = false;
+ switch (lineType) {
+ case b_WARNING_LINE:
+ this->LastTickChar = '*';
+ errorwarning.Error = false;
+ found = true;
+ this->TotalWarnings++;
+ break;
+ case b_ERROR_LINE:
+ this->LastTickChar = '!';
+ errorwarning.Error = true;
+ found = true;
+ this->TotalErrors++;
+ break;
+ }
+ if (found) {
+ // This is an error or warning, so generate report
+ errorwarning.LogLine = static_cast<int>(this->OutputLineCounter + 1);
+ errorwarning.Text = line;
+ errorwarning.PreContext.clear();
+ errorwarning.PostContext.clear();
+
+ // Copy pre-context to report
+ for (std::string const& pc : this->PreContext) {
+ errorwarning.PreContext += pc + "\n";
+ }
+ this->PreContext.clear();
+
+ // Store report
+ this->ErrorsAndWarnings.push_back(std::move(errorwarning));
+ this->LastErrorOrWarning = this->ErrorsAndWarnings.end() - 1;
+ this->PostContextCount = 0;
+ } else {
+ // This is not an error or warning.
+ // So, figure out if this is a post-context line
+ if (!this->ErrorsAndWarnings.empty() &&
+ this->LastErrorOrWarning != this->ErrorsAndWarnings.end() &&
+ this->PostContextCount < this->MaxPostContext) {
+ this->PostContextCount++;
+ this->LastErrorOrWarning->PostContext += line;
+ if (this->PostContextCount < this->MaxPostContext) {
+ this->LastErrorOrWarning->PostContext += "\n";
+ }
+ } else {
+ // Otherwise store pre-context for the next error
+ this->PreContext.emplace_back(line);
+ if (this->PreContext.size() > this->MaxPreContext) {
+ this->PreContext.erase(this->PreContext.begin(),
+ this->PreContext.end() -
+ this->MaxPreContext);
+ }
+ }
+ }
+ this->OutputLineCounter++;
+ } else {
+ break;
+ }
+ }
+
+ // Now that the buffer is processed, display missing ticks
+ int tickDisplayed = false;
+ while (this->BuildOutputLogSize > (tick * tick_len)) {
+ tick++;
+ cmCTestOptionalLog(this->CTest, HANDLER_PROGRESS_OUTPUT,
+ this->LastTickChar, this->Quiet);
+ tickDisplayed = true;
+ if (tick % tick_line_len == 0 && tick > 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_PROGRESS_OUTPUT,
+ " Size: "
+ << ((this->BuildOutputLogSize + 512) / 1024) << "K"
+ << std::endl
+ << " ",
+ this->Quiet);
+ }
+ }
+ if (tickDisplayed) {
+ this->LastTickChar = '.';
+ }
+
+ // And if this is verbose output, display the content of the chunk
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ cmCTestLogWrite(data, length));
+
+ // Always store the chunk to the file
+ ofs << cmCTestLogWrite(data, length);
+}
+
+int cmCTestBuildHandler::ProcessSingleLine(const char* data)
+{
+ if (this->UseCTestLaunch) {
+ // No log scraping when using launchers.
+ return b_REGULAR_LINE;
+ }
+
+ // Ignore ANSI color codes when checking for errors and warnings.
+ std::string input(data);
+ std::string line;
+ this->ColorRemover->Replace(input, line);
+
+ cmCTestOptionalLog(this->CTest, DEBUG, "Line: [" << line << "]" << std::endl,
+ this->Quiet);
+
+ int warningLine = 0;
+ int errorLine = 0;
+
+ // Check for regular expressions
+
+ if (!this->ErrorQuotaReached) {
+ // Errors
+ int wrxCnt = 0;
+ for (cmsys::RegularExpression& rx : this->ErrorMatchRegex) {
+ if (rx.find(line.c_str())) {
+ errorLine = 1;
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ " Error Line: " << line << " (matches: "
+ << this->CustomErrorMatches[wrxCnt]
+ << ")" << std::endl,
+ this->Quiet);
+ break;
+ }
+ wrxCnt++;
+ }
+ // Error exceptions
+ wrxCnt = 0;
+ for (cmsys::RegularExpression& rx : this->ErrorExceptionRegex) {
+ if (rx.find(line.c_str())) {
+ errorLine = 0;
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ " Not an error Line: "
+ << line << " (matches: "
+ << this->CustomErrorExceptions[wrxCnt] << ")"
+ << std::endl,
+ this->Quiet);
+ break;
+ }
+ wrxCnt++;
+ }
+ }
+ if (!this->WarningQuotaReached) {
+ // Warnings
+ int wrxCnt = 0;
+ for (cmsys::RegularExpression& rx : this->WarningMatchRegex) {
+ if (rx.find(line.c_str())) {
+ warningLine = 1;
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ " Warning Line: "
+ << line << " (matches: "
+ << this->CustomWarningMatches[wrxCnt] << ")"
+ << std::endl,
+ this->Quiet);
+ break;
+ }
+ wrxCnt++;
+ }
+
+ wrxCnt = 0;
+ // Warning exceptions
+ for (cmsys::RegularExpression& rx : this->WarningExceptionRegex) {
+ if (rx.find(line.c_str())) {
+ warningLine = 0;
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ " Not a warning Line: "
+ << line << " (matches: "
+ << this->CustomWarningExceptions[wrxCnt] << ")"
+ << std::endl,
+ this->Quiet);
+ break;
+ }
+ wrxCnt++;
+ }
+ }
+ if (errorLine) {
+ return b_ERROR_LINE;
+ }
+ if (warningLine) {
+ return b_WARNING_LINE;
+ }
+ return b_REGULAR_LINE;
+}
diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h
new file mode 100644
index 0000000..58e8d9c
--- /dev/null
+++ b/Source/CTest/cmCTestBuildHandler.h
@@ -0,0 +1,157 @@
+/* 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 <chrono>
+#include <deque>
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include <stddef.h>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCTestGenericHandler.h"
+#include "cmDuration.h"
+#include "cmProcessOutput.h"
+
+class cmMakefile;
+class cmStringReplaceHelper;
+class cmXMLWriter;
+
+/** \class cmCTestBuildHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ */
+class cmCTestBuildHandler : public cmCTestGenericHandler
+{
+public:
+ using Superclass = cmCTestGenericHandler;
+ using Encoding = cmProcessOutput::Encoding;
+
+ /*
+ * The main entry point for this class
+ */
+ int ProcessHandler() override;
+
+ cmCTestBuildHandler();
+
+ void PopulateCustomVectors(cmMakefile* mf) override;
+
+ /**
+ * Initialize handler
+ */
+ void Initialize() override;
+
+ int GetTotalErrors() { return this->TotalErrors; }
+ int GetTotalWarnings() { return this->TotalWarnings; }
+
+private:
+ std::string GetMakeCommand();
+
+ //! Run command specialized for make and configure. Returns process status
+ // and retVal is return value or exception.
+ int RunMakeCommand(const std::string& command, int* retVal, const char* dir,
+ int timeout, std::ostream& ofs,
+ Encoding encoding = cmProcessOutput::Auto);
+
+ enum
+ {
+ b_REGULAR_LINE,
+ b_WARNING_LINE,
+ b_ERROR_LINE
+ };
+
+ class cmCTestCompileErrorWarningRex
+ {
+ public:
+ cmCTestCompileErrorWarningRex() {}
+ int FileIndex;
+ int LineIndex;
+ cmsys::RegularExpression RegularExpression;
+ };
+
+ struct cmCTestBuildErrorWarning
+ {
+ bool Error;
+ int LogLine;
+ std::string Text;
+ std::string SourceFile;
+ std::string SourceFileTail;
+ int LineNumber;
+ std::string PreContext;
+ std::string PostContext;
+ };
+
+ // generate the XML output
+ void GenerateXMLHeader(cmXMLWriter& xml);
+ void GenerateXMLLaunched(cmXMLWriter& xml);
+ void GenerateXMLLogScraped(cmXMLWriter& xml);
+ void GenerateXMLFooter(cmXMLWriter& xml, cmDuration elapsed_build_time);
+ bool IsLaunchedErrorFile(const char* fname);
+ bool IsLaunchedWarningFile(const char* fname);
+
+ std::string StartBuild;
+ std::string EndBuild;
+ std::chrono::system_clock::time_point StartBuildTime;
+ std::chrono::system_clock::time_point EndBuildTime;
+
+ std::vector<std::string> CustomErrorMatches;
+ std::vector<std::string> CustomErrorExceptions;
+ std::vector<std::string> CustomWarningMatches;
+ std::vector<std::string> CustomWarningExceptions;
+ std::vector<std::string> ReallyCustomWarningMatches;
+ std::vector<std::string> ReallyCustomWarningExceptions;
+ std::vector<cmCTestCompileErrorWarningRex> ErrorWarningFileLineRegex;
+
+ std::vector<cmsys::RegularExpression> ErrorMatchRegex;
+ std::vector<cmsys::RegularExpression> ErrorExceptionRegex;
+ std::vector<cmsys::RegularExpression> WarningMatchRegex;
+ std::vector<cmsys::RegularExpression> WarningExceptionRegex;
+
+ using t_BuildProcessingQueueType = std::deque<char>;
+
+ void ProcessBuffer(const char* data, size_t length, size_t& tick,
+ size_t tick_len, std::ostream& ofs,
+ t_BuildProcessingQueueType* queue);
+ int ProcessSingleLine(const char* data);
+
+ t_BuildProcessingQueueType BuildProcessingQueue;
+ t_BuildProcessingQueueType BuildProcessingErrorQueue;
+ size_t BuildOutputLogSize;
+ std::vector<char> CurrentProcessingLine;
+
+ std::string SimplifySourceDir;
+ std::string SimplifyBuildDir;
+ size_t OutputLineCounter;
+ using t_ErrorsAndWarningsVector = std::vector<cmCTestBuildErrorWarning>;
+ t_ErrorsAndWarningsVector ErrorsAndWarnings;
+ t_ErrorsAndWarningsVector::iterator LastErrorOrWarning;
+ size_t PostContextCount;
+ size_t MaxPreContext;
+ size_t MaxPostContext;
+ std::deque<std::string> PreContext;
+
+ int TotalErrors;
+ int TotalWarnings;
+ char LastTickChar;
+
+ bool ErrorQuotaReached;
+ bool WarningQuotaReached;
+
+ int MaxErrors;
+ int MaxWarnings;
+
+ // Used to remove ANSI color codes before checking for errors and warnings.
+ cmStringReplaceHelper* ColorRemover;
+
+ bool UseCTestLaunch;
+ std::string CTestLaunchDir;
+ class LaunchHelper;
+
+ friend class LaunchHelper;
+ class FragmentCompare;
+};
diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx
new file mode 100644
index 0000000..1209e06
--- /dev/null
+++ b/Source/CTest/cmCTestCVS.cxx
@@ -0,0 +1,282 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestCVS.h"
+
+#include <utility>
+
+#include <cm/string_view>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCTest.h"
+#include "cmProcessTools.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+
+cmCTestCVS::cmCTestCVS(cmCTest* ct, std::ostream& log)
+ : cmCTestVC(ct, log)
+{
+}
+
+cmCTestCVS::~cmCTestCVS() = default;
+
+class cmCTestCVS::UpdateParser : public cmCTestVC::LineParser
+{
+public:
+ UpdateParser(cmCTestCVS* cvs, const char* prefix)
+ : CVS(cvs)
+ {
+ this->SetLog(&cvs->Log, prefix);
+ // See "man cvs", section "update output".
+ this->RegexFileUpdated.compile("^([UP]) *(.*)");
+ this->RegexFileModified.compile("^([MRA]) *(.*)");
+ this->RegexFileConflicting.compile("^([C]) *(.*)");
+ this->RegexFileRemoved1.compile(
+ "cvs[^ ]* update: `?([^']*)'? is no longer in the repository");
+ this->RegexFileRemoved2.compile(
+ "cvs[^ ]* update: "
+ "warning: `?([^']*)'? is not \\(any longer\\) pertinent");
+ }
+
+private:
+ cmCTestCVS* CVS;
+ cmsys::RegularExpression RegexFileUpdated;
+ cmsys::RegularExpression RegexFileModified;
+ cmsys::RegularExpression RegexFileConflicting;
+ cmsys::RegularExpression RegexFileRemoved1;
+ cmsys::RegularExpression RegexFileRemoved2;
+
+ bool ProcessLine() override
+ {
+ if (this->RegexFileUpdated.find(this->Line)) {
+ this->DoFile(PathUpdated, this->RegexFileUpdated.match(2));
+ } else if (this->RegexFileModified.find(this->Line)) {
+ this->DoFile(PathModified, this->RegexFileModified.match(2));
+ } else if (this->RegexFileConflicting.find(this->Line)) {
+ this->DoFile(PathConflicting, this->RegexFileConflicting.match(2));
+ } else if (this->RegexFileRemoved1.find(this->Line)) {
+ this->DoFile(PathUpdated, this->RegexFileRemoved1.match(1));
+ } else if (this->RegexFileRemoved2.find(this->Line)) {
+ this->DoFile(PathUpdated, this->RegexFileRemoved2.match(1));
+ }
+ return true;
+ }
+
+ void DoFile(PathStatus status, std::string const& file)
+ {
+ std::string dir = cmSystemTools::GetFilenamePath(file);
+ std::string name = cmSystemTools::GetFilenameName(file);
+ this->CVS->Dirs[dir][name] = status;
+ }
+};
+
+bool cmCTestCVS::UpdateImpl()
+{
+ // Get user-specified update options.
+ std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
+ if (opts.empty()) {
+ opts = this->CTest->GetCTestConfiguration("CVSUpdateOptions");
+ if (opts.empty()) {
+ opts = "-dP";
+ }
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
+
+ // Specify the start time for nightly testing.
+ if (this->CTest->GetTestModel() == cmCTest::NIGHTLY) {
+ args.push_back("-D" + this->GetNightlyTime() + " UTC");
+ }
+
+ // Run "cvs update" to update the work tree.
+ std::vector<char const*> cvs_update;
+ cvs_update.push_back(this->CommandLineTool.c_str());
+ cvs_update.push_back("-z3");
+ cvs_update.push_back("update");
+ for (std::string const& arg : args) {
+ cvs_update.push_back(arg.c_str());
+ }
+ cvs_update.push_back(nullptr);
+
+ UpdateParser out(this, "up-out> ");
+ UpdateParser err(this, "up-err> ");
+ return this->RunUpdateCommand(&cvs_update[0], &out, &err);
+}
+
+class cmCTestCVS::LogParser : public cmCTestVC::LineParser
+{
+public:
+ using Revision = cmCTestCVS::Revision;
+ LogParser(cmCTestCVS* cvs, const char* prefix, std::vector<Revision>& revs)
+ : CVS(cvs)
+ , Revisions(revs)
+ , Section(SectionHeader)
+ {
+ this->SetLog(&cvs->Log, prefix);
+ this->RegexRevision.compile("^revision +([^ ]*) *$");
+ this->RegexBranches.compile("^branches: .*$");
+ this->RegexPerson.compile("^date: +([^;]+); +author: +([^;]+);");
+ }
+
+private:
+ cmCTestCVS* CVS;
+ std::vector<Revision>& Revisions;
+ cmsys::RegularExpression RegexRevision;
+ cmsys::RegularExpression RegexBranches;
+ cmsys::RegularExpression RegexPerson;
+ enum SectionType
+ {
+ SectionHeader,
+ SectionRevisions,
+ SectionEnd
+ };
+ SectionType Section;
+ Revision Rev;
+
+ bool ProcessLine() override
+ {
+ if (this->Line ==
+ ("======================================="
+ "======================================")) {
+ // This line ends the revision list.
+ if (this->Section == SectionRevisions) {
+ this->FinishRevision();
+ }
+ this->Section = SectionEnd;
+ } else if (this->Line == "----------------------------") {
+ // This line divides revisions from the header and each other.
+ if (this->Section == SectionHeader) {
+ this->Section = SectionRevisions;
+ } else if (this->Section == SectionRevisions) {
+ this->FinishRevision();
+ }
+ } else if (this->Section == SectionRevisions) {
+ // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
+ // NOLINTNEXTLINE(bugprone-branch-clone)
+ if (!this->Rev.Log.empty()) {
+ // Continue the existing log.
+ this->Rev.Log += this->Line;
+ this->Rev.Log += '\n';
+ } else if (this->Rev.Rev.empty() &&
+ this->RegexRevision.find(this->Line)) {
+ this->Rev.Rev = this->RegexRevision.match(1);
+ } else if (this->Rev.Date.empty() &&
+ this->RegexPerson.find(this->Line)) {
+ this->Rev.Date = this->RegexPerson.match(1);
+ this->Rev.Author = this->RegexPerson.match(2);
+ } else if (!this->RegexBranches.find(this->Line)) {
+ // Start the log.
+ this->Rev.Log += this->Line;
+ this->Rev.Log += '\n';
+ }
+ }
+ return this->Section != SectionEnd;
+ }
+
+ void FinishRevision()
+ {
+ if (!this->Rev.Rev.empty()) {
+ // Record this revision.
+ /* clang-format off */
+ this->CVS->Log << "Found revision " << this->Rev.Rev << "\n"
+ << " author = " << this->Rev.Author << "\n"
+ << " date = " << this->Rev.Date << "\n";
+ /* clang-format on */
+ this->Revisions.push_back(this->Rev);
+
+ // We only need two revisions.
+ if (this->Revisions.size() >= 2) {
+ this->Section = SectionEnd;
+ }
+ }
+ this->Rev = Revision();
+ }
+};
+
+std::string cmCTestCVS::ComputeBranchFlag(std::string const& dir)
+{
+ // Compute the tag file location for this directory.
+ std::string tagFile = this->SourceDirectory;
+ if (!dir.empty()) {
+ tagFile += "/";
+ tagFile += dir;
+ }
+ tagFile += "/CVS/Tag";
+
+ // Lookup the branch in the tag file, if any.
+ std::string tagLine;
+ cmsys::ifstream tagStream(tagFile.c_str());
+ if (tagStream && cmSystemTools::GetLineFromStream(tagStream, tagLine) &&
+ tagLine.size() > 1 && tagLine[0] == 'T') {
+ // Use the branch specified in the tag file.
+ std::string flag = cmStrCat("-r", cm::string_view(tagLine).substr(1));
+ return flag;
+ }
+ // Use the default branch.
+ return "-b";
+}
+
+void cmCTestCVS::LoadRevisions(std::string const& file, const char* branchFlag,
+ std::vector<Revision>& revisions)
+{
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
+
+ // Run "cvs log" to get revisions of this file on this branch.
+ const char* cvs = this->CommandLineTool.c_str();
+ const char* cvs_log[] = {
+ cvs, "log", "-N", branchFlag, file.c_str(), nullptr
+ };
+
+ LogParser out(this, "log-out> ", revisions);
+ OutputLogger err(this->Log, "log-err> ");
+ this->RunChild(cvs_log, &out, &err);
+}
+
+void cmCTestCVS::WriteXMLDirectory(cmXMLWriter& xml, std::string const& path,
+ Directory const& dir)
+{
+ const char* slash = path.empty() ? "" : "/";
+ xml.StartElement("Directory");
+ xml.Element("Name", path);
+
+ // Lookup the branch checked out in the working tree.
+ std::string branchFlag = this->ComputeBranchFlag(path);
+
+ // Load revisions and write an entry for each file in this directory.
+ std::vector<Revision> revisions;
+ for (auto const& fi : dir) {
+ std::string full = path + slash + fi.first;
+
+ // Load two real or unknown revisions.
+ revisions.clear();
+ if (fi.second != PathUpdated) {
+ // For local modifications the current rev is unknown and the
+ // prior rev is the latest from cvs.
+ revisions.push_back(this->Unknown);
+ }
+ this->LoadRevisions(full, branchFlag.c_str(), revisions);
+ revisions.resize(2, this->Unknown);
+
+ // Write the entry for this file with these revisions.
+ File f(fi.second, &revisions[0], &revisions[1]);
+ this->WriteXMLEntry(xml, path, fi.first, full, f);
+ }
+ xml.EndElement(); // Directory
+}
+
+bool cmCTestCVS::WriteXMLUpdates(cmXMLWriter& xml)
+{
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Gathering version information (one . per updated file):\n"
+ " "
+ << std::flush);
+
+ for (auto const& d : this->Dirs) {
+ this->WriteXMLDirectory(xml, d.first, d.second);
+ }
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
+
+ return true;
+}
diff --git a/Source/CTest/cmCTestCVS.h b/Source/CTest/cmCTestCVS.h
new file mode 100644
index 0000000..d20239b
--- /dev/null
+++ b/Source/CTest/cmCTestCVS.h
@@ -0,0 +1,52 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "cmCTestVC.h"
+
+class cmCTest;
+class cmXMLWriter;
+
+/** \class cmCTestCVS
+ * \brief Interaction with cvs command-line tool
+ *
+ */
+class cmCTestCVS : public cmCTestVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestCVS(cmCTest* ctest, std::ostream& log);
+
+ ~cmCTestCVS() override;
+
+private:
+ // Implement cmCTestVC internal API.
+ bool UpdateImpl() override;
+ bool WriteXMLUpdates(cmXMLWriter& xml) override;
+
+ // Update status for files in each directory.
+ class Directory : public std::map<std::string, PathStatus>
+ {
+ };
+ std::map<std::string, Directory> Dirs;
+
+ std::string ComputeBranchFlag(std::string const& dir);
+ void LoadRevisions(std::string const& file, const char* branchFlag,
+ std::vector<Revision>& revisions);
+ void WriteXMLDirectory(cmXMLWriter& xml, std::string const& path,
+ Directory const& dir);
+
+ // Parsing helper classes.
+ class LogParser;
+ class UpdateParser;
+
+ friend class LogParser;
+ friend class UpdateParser;
+};
diff --git a/Source/CTest/cmCTestCommand.h b/Source/CTest/cmCTestCommand.h
new file mode 100644
index 0000000..007378d
--- /dev/null
+++ b/Source/CTest/cmCTestCommand.h
@@ -0,0 +1,28 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmCommand.h"
+
+class cmCTest;
+class cmCTestScriptHandler;
+
+/** \class cmCTestCommand
+ * \brief A superclass for all commands added to the CTestScriptHandler
+ *
+ * cmCTestCommand is the superclass for all commands that will be added to
+ * the ctest script handlers parser.
+ *
+ */
+class cmCTestCommand : public cmCommand
+{
+public:
+ cmCTestCommand()
+ {
+ this->CTest = nullptr;
+ this->CTestScriptHandler = nullptr;
+ }
+
+ cmCTest* CTest;
+ cmCTestScriptHandler* CTestScriptHandler;
+};
diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx
new file mode 100644
index 0000000..db9923e
--- /dev/null
+++ b/Source/CTest/cmCTestConfigureCommand.cxx
@@ -0,0 +1,150 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestConfigureCommand.h"
+
+#include <cstring>
+#include <sstream>
+#include <vector>
+
+#include <cmext/string_view>
+
+#include "cmCTest.h"
+#include "cmCTestConfigureHandler.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+void cmCTestConfigureCommand::BindArguments()
+{
+ this->cmCTestHandlerCommand::BindArguments();
+ this->Bind("OPTIONS"_s, this->Options);
+}
+
+cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
+{
+ std::vector<std::string> options;
+
+ if (!this->Options.empty()) {
+ cmExpandList(this->Options, options);
+ }
+
+ if (this->CTest->GetCTestConfiguration("BuildDirectory").empty()) {
+ this->SetError(
+ "Build directory not specified. Either use BUILD "
+ "argument to CTEST_CONFIGURE command or set CTEST_BINARY_DIRECTORY "
+ "variable");
+ return nullptr;
+ }
+
+ cmProp ctestConfigureCommand =
+ this->Makefile->GetDefinition("CTEST_CONFIGURE_COMMAND");
+
+ if (cmNonempty(ctestConfigureCommand)) {
+ this->CTest->SetCTestConfiguration("ConfigureCommand",
+ *ctestConfigureCommand, this->Quiet);
+ } else {
+ cmProp cmakeGeneratorName =
+ this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR");
+ if (cmNonempty(cmakeGeneratorName)) {
+ const std::string& source_dir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
+ if (source_dir.empty()) {
+ this->SetError(
+ "Source directory not specified. Either use SOURCE "
+ "argument to CTEST_CONFIGURE command or set CTEST_SOURCE_DIRECTORY "
+ "variable");
+ return nullptr;
+ }
+
+ const std::string cmakelists_file = source_dir + "/CMakeLists.txt";
+ if (!cmSystemTools::FileExists(cmakelists_file)) {
+ std::ostringstream e;
+ e << "CMakeLists.txt file does not exist [" << cmakelists_file << "]";
+ this->SetError(e.str());
+ return nullptr;
+ }
+
+ bool multiConfig = false;
+ bool cmakeBuildTypeInOptions = false;
+
+ auto gg = this->Makefile->GetCMakeInstance()->CreateGlobalGenerator(
+ *cmakeGeneratorName);
+ if (gg) {
+ multiConfig = gg->IsMultiConfig();
+ gg.reset();
+ }
+
+ std::string cmakeConfigureCommand =
+ cmStrCat('"', cmSystemTools::GetCMakeCommand(), '"');
+
+ for (std::string const& option : options) {
+ cmakeConfigureCommand += " \"";
+ cmakeConfigureCommand += option;
+ cmakeConfigureCommand += "\"";
+
+ if ((nullptr != strstr(option.c_str(), "CMAKE_BUILD_TYPE=")) ||
+ (nullptr != strstr(option.c_str(), "CMAKE_BUILD_TYPE:STRING="))) {
+ cmakeBuildTypeInOptions = true;
+ }
+ }
+
+ if (!multiConfig && !cmakeBuildTypeInOptions &&
+ !this->CTest->GetConfigType().empty()) {
+ cmakeConfigureCommand += " \"-DCMAKE_BUILD_TYPE:STRING=";
+ cmakeConfigureCommand += this->CTest->GetConfigType();
+ cmakeConfigureCommand += "\"";
+ }
+
+ if (this->Makefile->IsOn("CTEST_USE_LAUNCHERS")) {
+ cmakeConfigureCommand += " \"-DCTEST_USE_LAUNCHERS:BOOL=TRUE\"";
+ }
+
+ cmakeConfigureCommand += " \"-G";
+ cmakeConfigureCommand += *cmakeGeneratorName;
+ cmakeConfigureCommand += "\"";
+
+ cmProp cmakeGeneratorPlatform =
+ this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR_PLATFORM");
+ if (cmNonempty(cmakeGeneratorPlatform)) {
+ cmakeConfigureCommand += " \"-A";
+ cmakeConfigureCommand += *cmakeGeneratorPlatform;
+ cmakeConfigureCommand += "\"";
+ }
+
+ cmProp cmakeGeneratorToolset =
+ this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR_TOOLSET");
+ if (cmNonempty(cmakeGeneratorToolset)) {
+ cmakeConfigureCommand += " \"-T";
+ cmakeConfigureCommand += *cmakeGeneratorToolset;
+ cmakeConfigureCommand += "\"";
+ }
+
+ cmakeConfigureCommand += " \"";
+ cmakeConfigureCommand += source_dir;
+ cmakeConfigureCommand += "\"";
+
+ this->CTest->SetCTestConfiguration("ConfigureCommand",
+ cmakeConfigureCommand, this->Quiet);
+ } else {
+ this->SetError(
+ "Configure command is not specified. If this is a "
+ "\"built with CMake\" project, set CTEST_CMAKE_GENERATOR. If not, "
+ "set CTEST_CONFIGURE_COMMAND.");
+ return nullptr;
+ }
+ }
+
+ if (cmProp labelsForSubprojects =
+ this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
+ this->CTest->SetCTestConfiguration("LabelsForSubprojects",
+ *labelsForSubprojects, this->Quiet);
+ }
+
+ cmCTestConfigureHandler* handler = this->CTest->GetConfigureHandler();
+ handler->Initialize();
+ handler->SetQuiet(this->Quiet);
+ return handler;
+}
diff --git a/Source/CTest/cmCTestConfigureCommand.h b/Source/CTest/cmCTestConfigureCommand.h
new file mode 100644
index 0000000..f338637
--- /dev/null
+++ b/Source/CTest/cmCTestConfigureCommand.h
@@ -0,0 +1,46 @@
+/* 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 <string>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmCTestHandlerCommand.h"
+#include "cmCommand.h"
+
+class cmCTestGenericHandler;
+
+/** \class cmCTestConfigure
+ * \brief Run a ctest script
+ *
+ * cmCTestConfigureCommand defineds the command to configures the project.
+ */
+class cmCTestConfigureCommand : public cmCTestHandlerCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ auto ni = cm::make_unique<cmCTestConfigureCommand>();
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return std::unique_ptr<cmCommand>(std::move(ni));
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const override { return "ctest_configure"; }
+
+protected:
+ void BindArguments() override;
+ cmCTestGenericHandler* InitializeHandler() override;
+
+ std::string Options;
+};
diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx
new file mode 100644
index 0000000..914930e
--- /dev/null
+++ b/Source/CTest/cmCTestConfigureHandler.cxx
@@ -0,0 +1,103 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestConfigureHandler.h"
+
+#include <chrono>
+#include <ostream>
+#include <string>
+
+#include "cmCTest.h"
+#include "cmDuration.h"
+#include "cmGeneratedFileStream.h"
+#include "cmXMLWriter.h"
+
+cmCTestConfigureHandler::cmCTestConfigureHandler() = default;
+
+void cmCTestConfigureHandler::Initialize()
+{
+ this->Superclass::Initialize();
+}
+
+// clearly it would be nice if this were broken up into a few smaller
+// functions and commented...
+int cmCTestConfigureHandler::ProcessHandler()
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "Configure project" << std::endl, this->Quiet);
+ std::string cCommand =
+ this->CTest->GetCTestConfiguration("ConfigureCommand");
+ if (cCommand.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find ConfigureCommand key in the DartConfiguration.tcl"
+ << std::endl);
+ return -1;
+ }
+
+ std::string buildDirectory =
+ this->CTest->GetCTestConfiguration("BuildDirectory");
+ if (buildDirectory.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find BuildDirectory key in the DartConfiguration.tcl"
+ << std::endl);
+ return -1;
+ }
+
+ auto elapsed_time_start = std::chrono::steady_clock::now();
+ std::string output;
+ int retVal = 0;
+ int res = 0;
+ if (!this->CTest->GetShowOnly()) {
+ cmGeneratedFileStream os;
+ if (!this->StartResultingXML(cmCTest::PartConfigure, "Configure", os)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open configure file" << std::endl);
+ return 1;
+ }
+ std::string start_time = this->CTest->CurrentTime();
+ auto start_time_time = std::chrono::system_clock::now();
+
+ cmGeneratedFileStream ofs;
+ this->StartLogFile("Configure", ofs);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Configure with command: " << cCommand << std::endl,
+ this->Quiet);
+ res = this->CTest->RunMakeCommand(cCommand, output, &retVal,
+ buildDirectory.c_str(),
+ cmDuration::zero(), ofs);
+
+ if (ofs) {
+ ofs.close();
+ }
+
+ if (os) {
+ cmXMLWriter xml(os);
+ this->CTest->StartXML(xml, this->AppendXML);
+ this->CTest->GenerateSubprojectsOutput(xml);
+ xml.StartElement("Configure");
+ xml.Element("StartDateTime", start_time);
+ xml.Element("StartConfigureTime", start_time_time);
+ xml.Element("ConfigureCommand", cCommand);
+ cmCTestOptionalLog(this->CTest, DEBUG, "End" << std::endl, this->Quiet);
+ xml.Element("Log", output);
+ xml.Element("ConfigureStatus", retVal);
+ xml.Element("EndDateTime", this->CTest->CurrentTime());
+ xml.Element("EndConfigureTime", std::chrono::system_clock::now());
+ xml.Element("ElapsedMinutes",
+ std::chrono::duration_cast<std::chrono::minutes>(
+ std::chrono::steady_clock::now() - elapsed_time_start)
+ .count());
+ xml.EndElement(); // Configure
+ this->CTest->EndXML(xml);
+ }
+ } else {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Configure with command: " << cCommand << std::endl,
+ this->Quiet);
+ }
+ if (!res || retVal) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error(s) when configuring the project" << std::endl);
+ return -1;
+ }
+ return 0;
+}
diff --git a/Source/CTest/cmCTestConfigureHandler.h b/Source/CTest/cmCTestConfigureHandler.h
new file mode 100644
index 0000000..2aad98c
--- /dev/null
+++ b/Source/CTest/cmCTestConfigureHandler.h
@@ -0,0 +1,26 @@
+/* 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 "cmCTestGenericHandler.h"
+
+/** \class cmCTestConfigureHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ */
+class cmCTestConfigureHandler : public cmCTestGenericHandler
+{
+public:
+ using Superclass = cmCTestGenericHandler;
+
+ /*
+ * The main entry point for this class
+ */
+ int ProcessHandler() override;
+
+ cmCTestConfigureHandler();
+
+ void Initialize() override;
+};
diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx
new file mode 100644
index 0000000..7432d08
--- /dev/null
+++ b/Source/CTest/cmCTestCoverageCommand.cxx
@@ -0,0 +1,46 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestCoverageCommand.h"
+
+#include <set>
+
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+
+class cmCTestGenericHandler;
+
+void cmCTestCoverageCommand::BindArguments()
+{
+ this->cmCTestHandlerCommand::BindArguments();
+ this->Bind("LABELS"_s, this->Labels);
+}
+
+void cmCTestCoverageCommand::CheckArguments(
+ std::vector<std::string> const& keywords)
+{
+ this->LabelsMentioned =
+ !this->Labels.empty() || cm::contains(keywords, "LABELS");
+}
+
+cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler()
+{
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "CoverageCommand", "CTEST_COVERAGE_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "CoverageExtraFlags", "CTEST_COVERAGE_EXTRA_FLAGS",
+ this->Quiet);
+ cmCTestCoverageHandler* handler = this->CTest->GetCoverageHandler();
+ handler->Initialize();
+
+ // If a LABELS option was given, select only files with the labels.
+ if (this->LabelsMentioned) {
+ handler->SetLabelFilter(
+ std::set<std::string>(this->Labels.begin(), this->Labels.end()));
+ }
+
+ handler->SetQuiet(this->Quiet);
+ return handler;
+}
diff --git a/Source/CTest/cmCTestCoverageCommand.h b/Source/CTest/cmCTestCoverageCommand.h
new file mode 100644
index 0000000..9344852
--- /dev/null
+++ b/Source/CTest/cmCTestCoverageCommand.h
@@ -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. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmCTestHandlerCommand.h"
+#include "cmCommand.h"
+
+class cmCTestGenericHandler;
+
+/** \class cmCTestCoverage
+ * \brief Run a ctest script
+ *
+ * cmCTestCoverageCommand defineds the command to test the project.
+ */
+class cmCTestCoverageCommand : public cmCTestHandlerCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ auto ni = cm::make_unique<cmCTestCoverageCommand>();
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return std::unique_ptr<cmCommand>(std::move(ni));
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const override { return "ctest_coverage"; }
+
+protected:
+ void BindArguments() override;
+ void CheckArguments(std::vector<std::string> const& keywords) override;
+ cmCTestGenericHandler* InitializeHandler() override;
+
+ bool LabelsMentioned;
+ std::vector<std::string> Labels;
+};
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
new file mode 100644
index 0000000..3d7d031
--- /dev/null
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -0,0 +1,2356 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestCoverageHandler.h"
+
+#include <algorithm>
+#include <chrono>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iomanip>
+#include <iterator>
+#include <sstream>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+#include "cmsys/Process.h"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCTest.h"
+#include "cmDuration.h"
+#include "cmGeneratedFileStream.h"
+#include "cmParseBlanketJSCoverage.h"
+#include "cmParseCacheCoverage.h"
+#include "cmParseCoberturaCoverage.h"
+#include "cmParseDelphiCoverage.h"
+#include "cmParseGTMCoverage.h"
+#include "cmParseJacocoCoverage.h"
+#include "cmParsePHPCoverage.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmWorkingDirectory.h"
+#include "cmXMLWriter.h"
+
+class cmMakefile;
+
+#define SAFEDIV(x, y) (((y) != 0) ? ((x) / (y)) : (0))
+
+class cmCTestRunProcess
+{
+public:
+ cmCTestRunProcess()
+ {
+ this->Process = cmsysProcess_New();
+ this->PipeState = -1;
+ this->TimeOut = cmDuration(-1);
+ }
+ ~cmCTestRunProcess()
+ {
+ if (!(this->PipeState == -1) &&
+ !(this->PipeState == cmsysProcess_Pipe_None) &&
+ !(this->PipeState == cmsysProcess_Pipe_Timeout)) {
+ this->WaitForExit();
+ }
+ cmsysProcess_Delete(this->Process);
+ }
+ cmCTestRunProcess(const cmCTestRunProcess&) = delete;
+ cmCTestRunProcess& operator=(const cmCTestRunProcess&) = delete;
+ void SetCommand(const char* command)
+ {
+ this->CommandLineStrings.clear();
+ this->CommandLineStrings.emplace_back(command);
+ }
+ void AddArgument(const char* arg)
+ {
+ if (arg) {
+ this->CommandLineStrings.emplace_back(arg);
+ }
+ }
+ void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; }
+ void SetTimeout(cmDuration t) { this->TimeOut = t; }
+ bool StartProcess()
+ {
+ std::vector<const char*> args;
+ for (std::string const& cl : this->CommandLineStrings) {
+ args.push_back(cl.c_str());
+ }
+ args.push_back(nullptr); // null terminate
+ cmsysProcess_SetCommand(this->Process, args.data());
+ if (!this->WorkingDirectory.empty()) {
+ cmsysProcess_SetWorkingDirectory(this->Process,
+ this->WorkingDirectory.c_str());
+ }
+
+ cmsysProcess_SetOption(this->Process, cmsysProcess_Option_HideWindow, 1);
+ if (this->TimeOut >= cmDuration::zero()) {
+ cmsysProcess_SetTimeout(this->Process, this->TimeOut.count());
+ }
+ cmsysProcess_Execute(this->Process);
+ this->PipeState = cmsysProcess_GetState(this->Process);
+ // if the process is running or exited return true
+ return this->PipeState == cmsysProcess_State_Executing ||
+ this->PipeState == cmsysProcess_State_Exited;
+ }
+ void SetStdoutFile(const char* fname)
+ {
+ cmsysProcess_SetPipeFile(this->Process, cmsysProcess_Pipe_STDOUT, fname);
+ }
+ void SetStderrFile(const char* fname)
+ {
+ cmsysProcess_SetPipeFile(this->Process, cmsysProcess_Pipe_STDERR, fname);
+ }
+ int WaitForExit(double* timeout = nullptr)
+ {
+ this->PipeState = cmsysProcess_WaitForExit(this->Process, timeout);
+ return this->PipeState;
+ }
+ int GetProcessState() const { return this->PipeState; }
+
+private:
+ int PipeState;
+ cmsysProcess* Process;
+ std::vector<std::string> CommandLineStrings;
+ std::string WorkingDirectory;
+ cmDuration TimeOut;
+};
+
+cmCTestCoverageHandler::cmCTestCoverageHandler() = default;
+
+void cmCTestCoverageHandler::Initialize()
+{
+ this->Superclass::Initialize();
+ this->CustomCoverageExclude.clear();
+ this->SourceLabels.clear();
+ this->TargetDirs.clear();
+ this->LabelIdMap.clear();
+ this->Labels.clear();
+ this->LabelFilter.clear();
+}
+
+void cmCTestCoverageHandler::CleanCoverageLogFiles(std::ostream& log)
+{
+ std::string logGlob =
+ cmStrCat(this->CTest->GetCTestConfiguration("BuildDirectory"), "/Testing/",
+ this->CTest->GetCurrentTag(), "/CoverageLog*");
+ cmsys::Glob gl;
+ gl.FindFiles(logGlob);
+ std::vector<std::string> const& files = gl.GetFiles();
+ for (std::string const& f : files) {
+ log << "Removing old coverage log: " << f << "\n";
+ cmSystemTools::RemoveFile(f);
+ }
+}
+
+bool cmCTestCoverageHandler::StartCoverageLogFile(
+ cmGeneratedFileStream& covLogFile, int logFileCount)
+{
+ char covLogFilename[1024];
+ sprintf(covLogFilename, "CoverageLog-%d", logFileCount);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Open file: " << covLogFilename << std::endl,
+ this->Quiet);
+ if (!this->StartResultingXML(cmCTest::PartCoverage, covLogFilename,
+ covLogFile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open log file: " << covLogFilename << std::endl);
+ return false;
+ }
+ return true;
+}
+
+void cmCTestCoverageHandler::EndCoverageLogFile(cmGeneratedFileStream& ostr,
+ int logFileCount)
+{
+ char covLogFilename[1024];
+ sprintf(covLogFilename, "CoverageLog-%d.xml", logFileCount);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Close file: " << covLogFilename << std::endl,
+ this->Quiet);
+ ostr.Close();
+}
+
+void cmCTestCoverageHandler::StartCoverageLogXML(cmXMLWriter& xml)
+{
+ this->CTest->StartXML(xml, this->AppendXML);
+ xml.StartElement("CoverageLog");
+ xml.Element("StartDateTime", this->CTest->CurrentTime());
+ xml.Element("StartTime", std::chrono::system_clock::now());
+}
+
+void cmCTestCoverageHandler::EndCoverageLogXML(cmXMLWriter& xml)
+{
+ xml.Element("EndDateTime", this->CTest->CurrentTime());
+ xml.Element("EndTime", std::chrono::system_clock::now());
+ xml.EndElement(); // CoverageLog
+ this->CTest->EndXML(xml);
+}
+
+bool cmCTestCoverageHandler::ShouldIDoCoverage(std::string const& file,
+ std::string const& srcDir,
+ std::string const& binDir)
+{
+ if (this->IsFilteredOut(file)) {
+ return false;
+ }
+
+ for (cmsys::RegularExpression& rx : this->CustomCoverageExcludeRegex) {
+ if (rx.find(file)) {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " File " << file << " is excluded in CTestCustom.ctest" << std::endl;
+ , this->Quiet);
+ return false;
+ }
+ }
+
+ std::string fSrcDir = cmSystemTools::CollapseFullPath(srcDir);
+ std::string fBinDir = cmSystemTools::CollapseFullPath(binDir);
+ std::string fFile = cmSystemTools::CollapseFullPath(file);
+ bool sourceSubDir = cmSystemTools::IsSubDirectory(fFile, fSrcDir);
+ bool buildSubDir = cmSystemTools::IsSubDirectory(fFile, fBinDir);
+ // Always check parent directory of the file.
+ std::string fileDir = cmSystemTools::GetFilenamePath(fFile);
+ std::string checkDir;
+
+ // We also need to check the binary/source directory pair.
+ if (sourceSubDir && buildSubDir) {
+ if (fSrcDir.size() > fBinDir.size()) {
+ checkDir = fSrcDir;
+ } else {
+ checkDir = fBinDir;
+ }
+ } else if (sourceSubDir) {
+ checkDir = fSrcDir;
+ } else if (buildSubDir) {
+ checkDir = fBinDir;
+ }
+ std::string ndc = cmSystemTools::FileExistsInParentDirectories(
+ ".NoDartCoverage", fFile, checkDir);
+ if (!ndc.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found: " << ndc << " so skip coverage of " << file
+ << std::endl,
+ this->Quiet);
+ return false;
+ }
+
+ // By now checkDir should be set to parent directory of the file.
+ // Get the relative path to the file an apply it to the opposite directory.
+ // If it is the same as fileDir, then ignore, otherwise check.
+ std::string relPath;
+ if (!checkDir.empty()) {
+ relPath = cmSystemTools::RelativePath(checkDir, fFile);
+ } else {
+ relPath = fFile;
+ }
+ if (checkDir == fSrcDir) {
+ checkDir = fBinDir;
+ } else {
+ checkDir = fSrcDir;
+ }
+ fFile = checkDir + "/" + relPath;
+ fFile = cmSystemTools::GetFilenamePath(fFile);
+
+ if (fileDir == fFile) {
+ // This is in-source build, so we trust the previous check.
+ return true;
+ }
+
+ ndc = cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage", fFile,
+ checkDir);
+ if (!ndc.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found: " << ndc << " so skip coverage of: " << file
+ << std::endl,
+ this->Quiet);
+ return false;
+ }
+ // Ok, nothing in source tree, nothing in binary tree
+ return true;
+}
+
+// clearly it would be nice if this were broken up into a few smaller
+// functions and commented...
+int cmCTestCoverageHandler::ProcessHandler()
+{
+ this->CTest->ClearSubmitFiles(cmCTest::PartCoverage);
+ int error = 0;
+ // do we have time for this
+ if (this->CTest->GetRemainingTimeAllowed() < std::chrono::minutes(2)) {
+ return error;
+ }
+
+ std::string coverage_start_time = this->CTest->CurrentTime();
+ auto coverage_start_time_time = std::chrono::system_clock::now();
+ std::string sourceDir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
+ std::string binaryDir = this->CTest->GetCTestConfiguration("BuildDirectory");
+
+ this->LoadLabels();
+
+ cmGeneratedFileStream ofs;
+ auto elapsed_time_start = std::chrono::steady_clock::now();
+ if (!this->StartLogFile("Coverage", ofs)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create LastCoverage.log file" << std::endl);
+ }
+
+ ofs << "Performing coverage: "
+ << elapsed_time_start.time_since_epoch().count() << std::endl;
+ this->CleanCoverageLogFiles(ofs);
+
+ cmSystemTools::ConvertToUnixSlashes(sourceDir);
+ cmSystemTools::ConvertToUnixSlashes(binaryDir);
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "Performing coverage" << std::endl, this->Quiet);
+
+ cmCTestCoverageHandlerContainer cont;
+ cont.Error = error;
+ cont.SourceDir = sourceDir;
+ cont.BinaryDir = binaryDir;
+ cont.OFS = &ofs;
+ cont.Quiet = this->Quiet;
+
+ // setup the regex exclude stuff
+ this->CustomCoverageExcludeRegex.clear();
+ for (std::string const& rex : this->CustomCoverageExclude) {
+ this->CustomCoverageExcludeRegex.emplace_back(rex);
+ }
+
+ if (this->HandleBullseyeCoverage(&cont)) {
+ return cont.Error;
+ }
+ int file_count = 0;
+ file_count += this->HandleGCovCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+ file_count += this->HandleLCovCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+ file_count += this->HandleTracePyCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+ file_count += this->HandlePHPCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+ file_count += this->HandleCoberturaCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+
+ file_count += this->HandleMumpsCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+
+ file_count += this->HandleJacocoCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+
+ file_count += this->HandleBlanketJSCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+
+ file_count += this->HandleDelphiCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+ std::set<std::string> uncovered = this->FindUncoveredFiles(&cont);
+
+ if (file_count == 0 && this->ExtraCoverageGlobs.empty()) {
+ cmCTestOptionalLog(
+ this->CTest, WARNING,
+ " Cannot find any coverage files. Ignoring Coverage request."
+ << std::endl,
+ this->Quiet);
+ return error;
+ }
+ cmGeneratedFileStream covSumFile;
+ cmGeneratedFileStream covLogFile;
+ cmXMLWriter covSumXML(covSumFile);
+ cmXMLWriter covLogXML(covLogFile);
+
+ if (!this->StartResultingXML(cmCTest::PartCoverage, "Coverage",
+ covSumFile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open coverage summary file." << std::endl);
+ return -1;
+ }
+ covSumFile.setf(std::ios::fixed, std::ios::floatfield);
+ covSumFile.precision(2);
+
+ this->CTest->StartXML(covSumXML, this->AppendXML);
+ // Produce output xml files
+
+ covSumXML.StartElement("Coverage");
+ covSumXML.Element("StartDateTime", coverage_start_time);
+ covSumXML.Element("StartTime", coverage_start_time_time);
+ int logFileCount = 0;
+ if (!this->StartCoverageLogFile(covLogFile, logFileCount)) {
+ return -1;
+ }
+ this->StartCoverageLogXML(covLogXML);
+ int cnt = 0;
+ long total_tested = 0;
+ long total_untested = 0;
+ // std::string fullSourceDir = sourceDir + "/";
+ // std::string fullBinaryDir = binaryDir + "/";
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, std::endl, this->Quiet);
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ " Accumulating results (each . represents one file):" << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+
+ std::vector<std::string> errorsWhileAccumulating;
+
+ file_count = 0;
+ for (auto const& file : cont.TotalCoverage) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "." << std::flush,
+ this->Quiet);
+ file_count++;
+ if (file_count % 50 == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " processed: " << file_count << " out of "
+ << cont.TotalCoverage.size()
+ << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ }
+
+ const std::string fullFileName = file.first;
+ bool shouldIDoCoverage =
+ this->ShouldIDoCoverage(fullFileName, sourceDir, binaryDir);
+ if (!shouldIDoCoverage) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ ".NoDartCoverage found, so skip coverage check for: "
+ << fullFileName << std::endl,
+ this->Quiet);
+ continue;
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Process file: " << fullFileName << std::endl,
+ this->Quiet);
+
+ if (!cmSystemTools::FileExists(fullFileName)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find file: " << fullFileName << std::endl);
+ continue;
+ }
+
+ if (++cnt % 100 == 0) {
+ this->EndCoverageLogXML(covLogXML);
+ this->EndCoverageLogFile(covLogFile, logFileCount);
+ logFileCount++;
+ if (!this->StartCoverageLogFile(covLogFile, logFileCount)) {
+ return -1;
+ }
+ this->StartCoverageLogXML(covLogXML);
+ }
+
+ const std::string fileName = cmSystemTools::GetFilenameName(fullFileName);
+ const std::string shortFileName =
+ this->CTest->GetShortPathToFile(fullFileName);
+ const cmCTestCoverageHandlerContainer::SingleFileCoverageVector& fcov =
+ file.second;
+ covLogXML.StartElement("File");
+ covLogXML.Attribute("Name", fileName);
+ covLogXML.Attribute("FullPath", shortFileName);
+ covLogXML.StartElement("Report");
+
+ cmsys::ifstream ifs(fullFileName.c_str());
+ if (!ifs) {
+ std::ostringstream ostr;
+ ostr << "Cannot open source file: " << fullFileName;
+ errorsWhileAccumulating.push_back(ostr.str());
+ error++;
+ continue;
+ }
+
+ int tested = 0;
+ int untested = 0;
+
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector::size_type cc;
+ std::string line;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Actually performing coverage for: " << fullFileName
+ << std::endl,
+ this->Quiet);
+ for (cc = 0; cc < fcov.size(); cc++) {
+ if (!cmSystemTools::GetLineFromStream(ifs, line) &&
+ cc != fcov.size() - 1) {
+ std::ostringstream ostr;
+ ostr << "Problem reading source file: " << fullFileName
+ << " line:" << cc << " out total: " << fcov.size() - 1;
+ errorsWhileAccumulating.push_back(ostr.str());
+ error++;
+ break;
+ }
+ covLogXML.StartElement("Line");
+ covLogXML.Attribute("Number", cc);
+ covLogXML.Attribute("Count", fcov[cc]);
+ covLogXML.Content(line);
+ covLogXML.EndElement(); // Line
+ if (fcov[cc] == 0) {
+ untested++;
+ } else if (fcov[cc] > 0) {
+ tested++;
+ }
+ }
+ if (cmSystemTools::GetLineFromStream(ifs, line)) {
+ std::ostringstream ostr;
+ ostr << "Looks like there are more lines in the file: " << fullFileName;
+ errorsWhileAccumulating.push_back(ostr.str());
+ }
+ float cper = 0;
+ float cmet = 0;
+ if (tested + untested > 0) {
+ cper = (100 *
+ SAFEDIV(static_cast<float>(tested),
+ static_cast<float>(tested + untested)));
+ cmet = (SAFEDIV(static_cast<float>(tested + 10),
+ static_cast<float>(tested + untested + 10)));
+ }
+ total_tested += tested;
+ total_untested += untested;
+ covLogXML.EndElement(); // Report
+ covLogXML.EndElement(); // File
+ covSumXML.StartElement("File");
+ covSumXML.Attribute("Name", fileName);
+ covSumXML.Attribute("FullPath",
+ this->CTest->GetShortPathToFile(fullFileName));
+ covSumXML.Attribute("Covered", tested + untested > 0 ? "true" : "false");
+ covSumXML.Element("LOCTested", tested);
+ covSumXML.Element("LOCUnTested", untested);
+ covSumXML.Element("PercentCoverage", cper);
+ covSumXML.Element("CoverageMetric", cmet);
+ this->WriteXMLLabels(covSumXML, shortFileName);
+ covSumXML.EndElement(); // File
+ }
+
+ // Handle all the files in the extra coverage globs that have no cov data
+ for (std::string const& u : uncovered) {
+ std::string fileName = cmSystemTools::GetFilenameName(u);
+ std::string fullPath = cont.SourceDir + "/" + u;
+
+ covLogXML.StartElement("File");
+ covLogXML.Attribute("Name", fileName);
+ covLogXML.Attribute("FullPath", u);
+ covLogXML.StartElement("Report");
+
+ cmsys::ifstream ifs(fullPath.c_str());
+ if (!ifs) {
+ std::ostringstream ostr;
+ ostr << "Cannot open source file: " << fullPath;
+ errorsWhileAccumulating.push_back(ostr.str());
+ error++;
+ covLogXML.EndElement(); // Report
+ covLogXML.EndElement(); // File
+ continue;
+ }
+ int untested = 0;
+ std::string line;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Actually performing coverage for: " << u << std::endl,
+ this->Quiet);
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ covLogXML.StartElement("Line");
+ covLogXML.Attribute("Number", untested);
+ covLogXML.Attribute("Count", 0);
+ covLogXML.Content(line);
+ covLogXML.EndElement(); // Line
+ untested++;
+ }
+ covLogXML.EndElement(); // Report
+ covLogXML.EndElement(); // File
+
+ total_untested += untested;
+ covSumXML.StartElement("File");
+ covSumXML.Attribute("Name", fileName);
+ covSumXML.Attribute("FullPath", u);
+ covSumXML.Attribute("Covered", "true");
+ covSumXML.Element("LOCTested", 0);
+ covSumXML.Element("LOCUnTested", untested);
+ covSumXML.Element("PercentCoverage", 0);
+ covSumXML.Element("CoverageMetric", 0);
+ this->WriteXMLLabels(covSumXML, u);
+ covSumXML.EndElement(); // File
+ }
+
+ this->EndCoverageLogXML(covLogXML);
+ this->EndCoverageLogFile(covLogFile, logFileCount);
+
+ if (!errorsWhileAccumulating.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error(s) while accumulating results:" << std::endl);
+ for (std::string const& er : errorsWhileAccumulating) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, " " << er << std::endl);
+ }
+ }
+
+ long total_lines = total_tested + total_untested;
+ float percent_coverage = 100 *
+ SAFEDIV(static_cast<float>(total_tested), static_cast<float>(total_lines));
+ if (total_lines == 0) {
+ percent_coverage = 0;
+ }
+
+ std::string end_time = this->CTest->CurrentTime();
+
+ covSumXML.Element("LOCTested", total_tested);
+ covSumXML.Element("LOCUntested", total_untested);
+ covSumXML.Element("LOC", total_lines);
+ covSumXML.Element("PercentCoverage", percent_coverage);
+ covSumXML.Element("EndDateTime", end_time);
+ covSumXML.Element("EndTime", std::chrono::system_clock::now());
+ covSumXML.Element("ElapsedMinutes",
+ std::chrono::duration_cast<std::chrono::minutes>(
+ std::chrono::steady_clock::now() - elapsed_time_start)
+ .count());
+ covSumXML.EndElement(); // Coverage
+ this->CTest->EndXML(covSumXML);
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ "" << std::endl
+ << "\tCovered LOC: " << total_tested << std::endl
+ << "\tNot covered LOC: " << total_untested << std::endl
+ << "\tTotal LOC: " << total_lines << std::endl
+ << "\tPercentage Coverage: "
+ << std::setiosflags(std::ios::fixed) << std::setprecision(2)
+ << (percent_coverage) << "%" << std::endl);
+
+ ofs << "\tCovered LOC: " << total_tested << std::endl
+ << "\tNot covered LOC: " << total_untested << std::endl
+ << "\tTotal LOC: " << total_lines << std::endl
+ << "\tPercentage Coverage: " << std::setiosflags(std::ios::fixed)
+ << std::setprecision(2) << (percent_coverage) << "%" << std::endl;
+
+ if (error) {
+ return -1;
+ }
+ return 0;
+}
+
+void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile* mf)
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Add coverage exclude regular expressions." << std::endl,
+ this->Quiet);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_COVERAGE_EXCLUDE",
+ this->CustomCoverageExclude);
+ this->CTest->PopulateCustomVector(mf, "CTEST_EXTRA_COVERAGE_GLOB",
+ this->ExtraCoverageGlobs);
+ for (std::string const& cce : this->CustomCoverageExclude) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Add coverage exclude: " << cce << std::endl,
+ this->Quiet);
+ }
+ for (std::string const& ecg : this->ExtraCoverageGlobs) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Add coverage glob: " << ecg << std::endl,
+ this->Quiet);
+ }
+}
+
+// Fix for issue #4971 where the case of the drive letter component of
+// the filenames might be different when analyzing gcov output.
+//
+// Compare file names: fnc(fn1) == fnc(fn2) // fnc == file name compare
+//
+#ifdef _WIN32
+# define fnc(s) cmSystemTools::LowerCase(s)
+# define fnc_prefix(s, t) fnc(s.substr(0, t.size())) == fnc(t)
+#else
+# define fnc_prefix(s, t) cmHasPrefix(s, t)
+#endif
+
+bool IsFileInDir(const std::string& infile, const std::string& indir)
+{
+ std::string file = cmSystemTools::CollapseFullPath(infile);
+ std::string dir = cmSystemTools::CollapseFullPath(indir);
+
+ return file.size() > dir.size() && fnc_prefix(file, dir) &&
+ file[dir.size()] == '/';
+}
+
+int cmCTestCoverageHandler::HandlePHPCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParsePHPCoverage cov(*cont, this->CTest);
+ std::string coverageDir = this->CTest->GetBinaryDir() + "/xdebugCoverage";
+ if (cmSystemTools::FileIsDirectory(coverageDir)) {
+ cov.ReadPHPCoverageDirectory(coverageDir.c_str());
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+
+int cmCTestCoverageHandler::HandleCoberturaCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParseCoberturaCoverage cov(*cont, this->CTest);
+
+ // Assume the coverage.xml is in the binary directory
+ // check for the COBERTURADIR environment variable,
+ // if it doesn't exist or is empty, assume the
+ // binary directory is used.
+ std::string coverageXMLFile;
+ if (!cmSystemTools::GetEnv("COBERTURADIR", coverageXMLFile) ||
+ coverageXMLFile.empty()) {
+ coverageXMLFile = this->CTest->GetBinaryDir();
+ }
+ // build the find file string with the directory from above
+ coverageXMLFile += "/coverage.xml";
+
+ if (cmSystemTools::FileExists(coverageXMLFile)) {
+ // If file exists, parse it
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Parsing Cobertura XML file: " << coverageXMLFile
+ << std::endl,
+ this->Quiet);
+ cov.ReadCoverageXML(coverageXMLFile.c_str());
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find Cobertura XML file: " << coverageXMLFile
+ << std::endl,
+ this->Quiet);
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+
+int cmCTestCoverageHandler::HandleMumpsCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ // try gtm coverage
+ cmParseGTMCoverage cov(*cont, this->CTest);
+ std::string coverageFile =
+ this->CTest->GetBinaryDir() + "/gtm_coverage.mcov";
+ if (cmSystemTools::FileExists(coverageFile)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Parsing Cache Coverage: " << coverageFile << std::endl,
+ this->Quiet);
+ cov.ReadCoverageFile(coverageFile.c_str());
+ return static_cast<int>(cont->TotalCoverage.size());
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find GTM coverage file: " << coverageFile
+ << std::endl,
+ this->Quiet);
+ cmParseCacheCoverage ccov(*cont, this->CTest);
+ coverageFile = this->CTest->GetBinaryDir() + "/cache_coverage.cmcov";
+ if (cmSystemTools::FileExists(coverageFile)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Parsing Cache Coverage: " << coverageFile << std::endl,
+ this->Quiet);
+ ccov.ReadCoverageFile(coverageFile.c_str());
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find Cache coverage file: " << coverageFile
+ << std::endl,
+ this->Quiet);
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+
+struct cmCTestCoverageHandlerLocale
+{
+ cmCTestCoverageHandlerLocale()
+ {
+ std::string l;
+ if (cmSystemTools::GetEnv("LC_ALL", l)) {
+ this->lc_all = l;
+ }
+ if (this->lc_all != "C") {
+ cmSystemTools::PutEnv("LC_ALL=C");
+ }
+ }
+ ~cmCTestCoverageHandlerLocale()
+ {
+ if (!this->lc_all.empty()) {
+ cmSystemTools::PutEnv("LC_ALL=" + this->lc_all);
+ } else {
+ cmSystemTools::UnsetEnv("LC_ALL");
+ }
+ }
+ cmCTestCoverageHandlerLocale(const cmCTestCoverageHandlerLocale&) = delete;
+ cmCTestCoverageHandlerLocale& operator=(
+ const cmCTestCoverageHandlerLocale&) = delete;
+ std::string lc_all;
+};
+
+int cmCTestCoverageHandler::HandleJacocoCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParseJacocoCoverage cov = cmParseJacocoCoverage(*cont, this->CTest);
+
+ // Search in the source directory.
+ cmsys::Glob g1;
+ std::vector<std::string> files;
+ g1.SetRecurse(true);
+
+ std::string SourceDir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
+ std::string coverageFile = SourceDir + "/*jacoco.xml";
+
+ g1.FindFiles(coverageFile);
+ files = g1.GetFiles();
+
+ // ...and in the binary directory.
+ cmsys::Glob g2;
+ g2.SetRecurse(true);
+ std::string binaryDir = this->CTest->GetCTestConfiguration("BuildDirectory");
+ std::string binCoverageFile = binaryDir + "/*jacoco.xml";
+ g2.FindFiles(binCoverageFile);
+ cm::append(files, g2.GetFiles());
+
+ if (!files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found Jacoco Files, Performing Coverage" << std::endl,
+ this->Quiet);
+ cov.LoadCoverageData(files);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find Jacoco coverage files: " << coverageFile
+ << std::endl,
+ this->Quiet);
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+
+int cmCTestCoverageHandler::HandleDelphiCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParseDelphiCoverage cov = cmParseDelphiCoverage(*cont, this->CTest);
+ cmsys::Glob g;
+ std::vector<std::string> files;
+ g.SetRecurse(true);
+
+ std::string BinDir = this->CTest->GetBinaryDir();
+ std::string coverageFile = BinDir + "/*(*.pas).html";
+
+ g.FindFiles(coverageFile);
+ files = g.GetFiles();
+ if (!files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found Delphi HTML Files, Performing Coverage"
+ << std::endl,
+ this->Quiet);
+ cov.LoadCoverageData(files);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find Delphi coverage files: " << coverageFile
+ << std::endl,
+ this->Quiet);
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+
+static std::string joinCommandLine(const std::vector<std::string>& args)
+{
+ std::string ret;
+
+ for (std::string const& s : args) {
+ if (s.find(' ') == std::string::npos) {
+ ret += s + ' ';
+ } else {
+ ret += "\"" + s + "\" ";
+ }
+ }
+
+ // drop trailing whitespace
+ ret.erase(ret.size() - 1);
+
+ return ret;
+}
+
+int cmCTestCoverageHandler::HandleBlanketJSCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParseBlanketJSCoverage cov = cmParseBlanketJSCoverage(*cont, this->CTest);
+ std::string SourceDir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
+
+ // Look for something other than output.json, still JSON extension.
+ std::string coverageFile = SourceDir + "/*.json";
+ cmsys::Glob g;
+ std::vector<std::string> files;
+ std::vector<std::string> blanketFiles;
+ g.FindFiles(coverageFile);
+ files = g.GetFiles();
+ // Ensure that the JSON files found are the result of the
+ // Blanket.js output. Check for the "node-jscoverage"
+ // string on the second line
+ std::string line;
+ for (std::string const& fileEntry : files) {
+ cmsys::ifstream in(fileEntry.c_str());
+ cmSystemTools::GetLineFromStream(in, line);
+ cmSystemTools::GetLineFromStream(in, line);
+ if (line.find("node-jscoverage") != std::string::npos) {
+ blanketFiles.push_back(fileEntry);
+ }
+ }
+ // Take all files with the node-jscoverage string and parse those
+ if (!blanketFiles.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found BlanketJS output JSON, Performing Coverage"
+ << std::endl,
+ this->Quiet);
+ cov.LoadCoverageData(files);
+ } else {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find BlanketJS coverage files: " << coverageFile << std::endl,
+ this->Quiet);
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+int cmCTestCoverageHandler::HandleGCovCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ std::string gcovCommand =
+ this->CTest->GetCTestConfiguration("CoverageCommand");
+ if (gcovCommand.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Could not find gcov." << std::endl, this->Quiet);
+ return 0;
+ }
+ std::string gcovExtraFlags =
+ this->CTest->GetCTestConfiguration("CoverageExtraFlags");
+
+ // Immediately skip to next coverage option since codecov is only for Intel
+ // compiler
+ if (gcovCommand == "codecov") {
+ return 0;
+ }
+
+ // Style 1
+ std::string st1gcovOutputRex1 =
+ "[0-9]+\\.[0-9]+% of [0-9]+ (source |)lines executed in file (.*)$";
+ std::string st1gcovOutputRex2 = "^Creating (.*\\.gcov)\\.";
+ cmsys::RegularExpression st1re1(st1gcovOutputRex1.c_str());
+ cmsys::RegularExpression st1re2(st1gcovOutputRex2.c_str());
+
+ // Style 2
+ std::string st2gcovOutputRex1 = "^File *[`'](.*)'$";
+ std::string st2gcovOutputRex2 =
+ "Lines executed: *[0-9]+\\.[0-9]+% of [0-9]+$";
+ std::string st2gcovOutputRex3 = "^(.*)reating [`'](.*\\.gcov)'";
+ std::string st2gcovOutputRex4 = "^(.*):unexpected EOF *$";
+ std::string st2gcovOutputRex5 = "^(.*):cannot open source file*$";
+ std::string st2gcovOutputRex6 =
+ "^(.*):source file is newer than graph file `(.*)'$";
+ cmsys::RegularExpression st2re1(st2gcovOutputRex1.c_str());
+ cmsys::RegularExpression st2re2(st2gcovOutputRex2.c_str());
+ cmsys::RegularExpression st2re3(st2gcovOutputRex3.c_str());
+ cmsys::RegularExpression st2re4(st2gcovOutputRex4.c_str());
+ cmsys::RegularExpression st2re5(st2gcovOutputRex5.c_str());
+ cmsys::RegularExpression st2re6(st2gcovOutputRex6.c_str());
+
+ std::vector<std::string> files;
+ this->FindGCovFiles(files);
+
+ if (files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find any GCov coverage files." << std::endl,
+ this->Quiet);
+ // No coverage files is a valid thing, so the exit code is 0
+ return 0;
+ }
+
+ std::string testingDir = this->CTest->GetBinaryDir() + "/Testing";
+ std::string tempDir = testingDir + "/CoverageInfo";
+ if (!cmSystemTools::MakeDirectory(tempDir)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unable to make directory: " << tempDir << std::endl);
+ cont->Error++;
+ return 0;
+ }
+ cmWorkingDirectory workdir(tempDir);
+
+ int gcovStyle = 0;
+
+ std::set<std::string> missingFiles;
+
+ std::string actualSourceFile;
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ " Processing coverage (each . represents one file):" << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ int file_count = 0;
+
+ // make sure output from gcov is in English!
+ cmCTestCoverageHandlerLocale locale_C;
+ static_cast<void>(locale_C);
+
+ std::vector<std::string> basecovargs =
+ cmSystemTools::ParseArguments(gcovExtraFlags);
+ basecovargs.insert(basecovargs.begin(), gcovCommand);
+ basecovargs.emplace_back("-o");
+
+ // files is a list of *.da and *.gcda files with coverage data in them.
+ // These are binary files that you give as input to gcov so that it will
+ // give us text output we can analyze to summarize coverage.
+ //
+ for (std::string const& f : files) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "." << std::flush,
+ this->Quiet);
+
+ // Call gcov to get coverage data for this *.gcda file:
+ //
+ std::string fileDir = cmSystemTools::GetFilenamePath(f);
+ std::vector<std::string> covargs = basecovargs;
+ covargs.push_back(fileDir);
+ covargs.push_back(f);
+ const std::string command = joinCommandLine(covargs);
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ command << std::endl, this->Quiet);
+
+ std::string output;
+ std::string errors;
+ int retVal = 0;
+ *cont->OFS << "* Run coverage for: " << fileDir << std::endl;
+ *cont->OFS << " Command: " << command << std::endl;
+ int res = this->CTest->RunCommand(covargs, &output, &errors, &retVal,
+ tempDir.c_str(),
+ cmDuration::zero() /*this->TimeOut*/);
+
+ *cont->OFS << " Output: " << output << std::endl;
+ *cont->OFS << " Errors: " << errors << std::endl;
+ if (!res) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem running coverage on file: " << f << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Command produced error: " << errors << std::endl);
+ cont->Error++;
+ continue;
+ }
+ if (retVal != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Coverage command returned: "
+ << retVal << " while processing: " << f << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Command produced error: " << cont->Error << std::endl);
+ }
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "--------------------------------------------------------------"
+ << std::endl
+ << output << std::endl
+ << "--------------------------------------------------------------"
+ << std::endl,
+ this->Quiet);
+
+ std::vector<std::string> lines;
+ cmsys::SystemTools::Split(output, lines);
+
+ for (std::string const& line : lines) {
+ std::string sourceFile;
+ std::string gcovFile;
+
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Line: [" << line << "]" << std::endl, this->Quiet);
+
+ if (line.empty()) {
+ // Ignore empty line; probably style 2
+ } else if (st1re1.find(line)) {
+ if (gcovStyle == 0) {
+ gcovStyle = 1;
+ }
+ if (gcovStyle != 1) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unknown gcov output style e1" << std::endl);
+ cont->Error++;
+ break;
+ }
+
+ actualSourceFile.clear();
+ sourceFile = st1re1.match(2);
+ } else if (st1re2.find(line)) {
+ if (gcovStyle == 0) {
+ gcovStyle = 1;
+ }
+ if (gcovStyle != 1) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unknown gcov output style e2" << std::endl);
+ cont->Error++;
+ break;
+ }
+
+ gcovFile = st1re2.match(1);
+ } else if (st2re1.find(line)) {
+ if (gcovStyle == 0) {
+ gcovStyle = 2;
+ }
+ if (gcovStyle != 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unknown gcov output style e3" << std::endl);
+ cont->Error++;
+ break;
+ }
+
+ actualSourceFile.clear();
+ sourceFile = st2re1.match(1);
+ } else if (st2re2.find(line)) {
+ if (gcovStyle == 0) {
+ gcovStyle = 2;
+ }
+ if (gcovStyle != 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unknown gcov output style e4" << std::endl);
+ cont->Error++;
+ break;
+ }
+ } else if (st2re3.find(line)) {
+ if (gcovStyle == 0) {
+ gcovStyle = 2;
+ }
+ if (gcovStyle != 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unknown gcov output style e5" << std::endl);
+ cont->Error++;
+ break;
+ }
+
+ gcovFile = st2re3.match(2);
+ } else if (st2re4.find(line)) {
+ if (gcovStyle == 0) {
+ gcovStyle = 2;
+ }
+ if (gcovStyle != 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unknown gcov output style e6" << std::endl);
+ cont->Error++;
+ break;
+ }
+
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "Warning: " << st2re4.match(1)
+ << " had unexpected EOF" << std::endl,
+ this->Quiet);
+ } else if (st2re5.find(line)) {
+ if (gcovStyle == 0) {
+ gcovStyle = 2;
+ }
+ if (gcovStyle != 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unknown gcov output style e7" << std::endl);
+ cont->Error++;
+ break;
+ }
+
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "Warning: Cannot open file: " << st2re5.match(1)
+ << std::endl,
+ this->Quiet);
+ } else if (st2re6.find(line)) {
+ if (gcovStyle == 0) {
+ gcovStyle = 2;
+ }
+ if (gcovStyle != 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unknown gcov output style e8" << std::endl);
+ cont->Error++;
+ break;
+ }
+
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "Warning: File: " << st2re6.match(1)
+ << " is newer than "
+ << st2re6.match(2) << std::endl,
+ this->Quiet);
+ } else {
+ // gcov 4.7 can have output lines saying "No executable lines" and
+ // "Removing 'filename.gcov'"... Don't log those as "errors."
+ if (line != "No executable lines" &&
+ !cmHasLiteralPrefix(line, "Removing ")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unknown gcov output line: [" << line << "]"
+ << std::endl);
+ cont->Error++;
+ // abort();
+ }
+ }
+
+ // If the last line of gcov output gave us a valid value for gcovFile,
+ // and we have an actualSourceFile, then insert a (or add to existing)
+ // SingleFileCoverageVector for actualSourceFile:
+ //
+ if (!gcovFile.empty() && !actualSourceFile.empty()) {
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& vec =
+ cont->TotalCoverage[actualSourceFile];
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " in gcovFile: " << gcovFile << std::endl,
+ this->Quiet);
+
+ cmsys::ifstream ifile(gcovFile.c_str());
+ if (!ifile) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open file: " << gcovFile << std::endl);
+ } else {
+ long cnt = -1;
+ std::string nl;
+ while (cmSystemTools::GetLineFromStream(ifile, nl)) {
+ cnt++;
+
+ // Skip empty lines
+ if (nl.empty()) {
+ continue;
+ }
+
+ // Skip unused lines
+ if (nl.size() < 12) {
+ continue;
+ }
+
+ // Handle gcov 3.0 non-coverage lines
+ // non-coverage lines seem to always start with something not
+ // a space and don't have a ':' in the 9th position
+ // TODO: Verify that this is actually a robust metric
+ if (nl[0] != ' ' && nl[9] != ':') {
+ continue;
+ }
+
+ // Read the coverage count from the beginning of the gcov output
+ // line
+ std::string prefix = nl.substr(0, 12);
+ int cov = atoi(prefix.c_str());
+
+ // Read the line number starting at the 10th character of the gcov
+ // output line
+ std::string lineNumber = nl.substr(10, 5);
+
+ int lineIdx = atoi(lineNumber.c_str()) - 1;
+ if (lineIdx >= 0) {
+ while (vec.size() <= static_cast<size_t>(lineIdx)) {
+ vec.push_back(-1);
+ }
+
+ // Initially all entries are -1 (not used). If we get coverage
+ // information, increment it to 0 first.
+ if (vec[lineIdx] < 0) {
+ if (cov > 0 || prefix.find('#') != std::string::npos) {
+ vec[lineIdx] = 0;
+ }
+ }
+
+ vec[lineIdx] += cov;
+ }
+ }
+ }
+
+ actualSourceFile.clear();
+ }
+
+ if (!sourceFile.empty() && actualSourceFile.empty()) {
+ gcovFile.clear();
+
+ // Is it in the source dir or the binary dir?
+ //
+ if (IsFileInDir(sourceFile, cont->SourceDir)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " produced s: " << sourceFile << std::endl,
+ this->Quiet);
+ *cont->OFS << " produced in source dir: " << sourceFile
+ << std::endl;
+ actualSourceFile = cmSystemTools::CollapseFullPath(sourceFile);
+ } else if (IsFileInDir(sourceFile, cont->BinaryDir)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " produced b: " << sourceFile << std::endl,
+ this->Quiet);
+ *cont->OFS << " produced in binary dir: " << sourceFile
+ << std::endl;
+ actualSourceFile = cmSystemTools::CollapseFullPath(sourceFile);
+ }
+
+ if (actualSourceFile.empty()) {
+ if (missingFiles.find(sourceFile) == missingFiles.end()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Something went wrong" << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Cannot find file: [" << sourceFile << "]"
+ << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " in source dir: [" << cont->SourceDir << "]"
+ << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " or binary dir: [" << cont->BinaryDir.size()
+ << "]" << std::endl,
+ this->Quiet);
+ *cont->OFS << " Something went wrong. Cannot find file: "
+ << sourceFile << " in source dir: " << cont->SourceDir
+ << " or binary dir: " << cont->BinaryDir << std::endl;
+
+ missingFiles.insert(sourceFile);
+ }
+ }
+ }
+ }
+
+ file_count++;
+
+ if (file_count % 50 == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " processed: " << file_count << " out of "
+ << files.size() << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ }
+ }
+
+ return file_count;
+}
+
+int cmCTestCoverageHandler::HandleLCovCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ std::string lcovCommand =
+ this->CTest->GetCTestConfiguration("CoverageCommand");
+ std::string lcovExtraFlags =
+ this->CTest->GetCTestConfiguration("CoverageExtraFlags");
+ if (lcovCommand != "codecov") {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Not a valid Intel Coverage command." << std::endl,
+ this->Quiet);
+ return 0;
+ }
+ // There is only percentage completed output from LCOV
+ std::string st2lcovOutputRex3 = "[0-9]+%";
+ cmsys::RegularExpression st2re3(st2lcovOutputRex3.c_str());
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " This is coverage command: " << lcovCommand << std::endl,
+ this->Quiet);
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " These are coverage command flags: " << lcovExtraFlags
+ << std::endl,
+ this->Quiet);
+
+ std::vector<std::string> files;
+ if (!this->FindLCovFiles(files)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error while finding LCov files.\n");
+ return 0;
+ }
+
+ if (files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find any LCov coverage files." << std::endl,
+ this->Quiet);
+ // No coverage files is a valid thing, so the exit code is 0
+ return 0;
+ }
+ std::string testingDir = this->CTest->GetBinaryDir();
+
+ std::set<std::string> missingFiles;
+
+ std::string actualSourceFile;
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ " Processing coverage (each . represents one file):" << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ int file_count = 0;
+
+ // make sure output from lcov is in English!
+ cmCTestCoverageHandlerLocale locale_C;
+ static_cast<void>(locale_C);
+
+ std::vector<std::string> covargs =
+ cmSystemTools::ParseArguments(lcovExtraFlags);
+ covargs.insert(covargs.begin(), lcovCommand);
+ const std::string command = joinCommandLine(covargs);
+
+ // In intel compiler we have to call codecov only once in each executable
+ // directory. It collects all *.dyn files to generate .dpi file.
+ for (std::string const& f : files) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "." << std::flush,
+ this->Quiet);
+ std::string fileDir = cmSystemTools::GetFilenamePath(f);
+ cmWorkingDirectory workdir(fileDir);
+ if (workdir.Failed()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unable to change working directory to "
+ << fileDir << " : "
+ << std::strerror(workdir.GetLastResult()) << std::endl);
+ cont->Error++;
+ continue;
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Current coverage dir: " << fileDir << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ command << std::endl, this->Quiet);
+
+ std::string output;
+ std::string errors;
+ int retVal = 0;
+ *cont->OFS << "* Run coverage for: " << fileDir << std::endl;
+ *cont->OFS << " Command: " << command << std::endl;
+ int res = this->CTest->RunCommand(covargs, &output, &errors, &retVal,
+ fileDir.c_str(),
+ cmDuration::zero() /*this->TimeOut*/);
+
+ *cont->OFS << " Output: " << output << std::endl;
+ *cont->OFS << " Errors: " << errors << std::endl;
+ if (!res) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem running coverage on file: " << f << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Command produced error: " << errors << std::endl);
+ cont->Error++;
+ continue;
+ }
+ if (retVal != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Coverage command returned: "
+ << retVal << " while processing: " << f << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Command produced error: " << cont->Error << std::endl);
+ }
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "--------------------------------------------------------------"
+ << std::endl
+ << output << std::endl
+ << "--------------------------------------------------------------"
+ << std::endl,
+ this->Quiet);
+
+ std::vector<std::string> lines;
+ cmsys::SystemTools::Split(output, lines);
+
+ for (std::string const& line : lines) {
+ std::string sourceFile;
+ std::string lcovFile;
+
+ if (line.empty()) {
+ // Ignore empty line
+ }
+ // Look for LCOV files in binary directory
+ // Intel Compiler creates a CodeCoverage dir for each subfolder and
+ // each subfolder has LCOV files
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOff();
+ std::string dir;
+ std::vector<std::string> lcovFiles;
+ dir = this->CTest->GetBinaryDir();
+ std::string daGlob;
+ daGlob = cmStrCat(dir, "/*.LCOV");
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " looking for LCOV files in: " << daGlob << std::endl, this->Quiet);
+ gl.FindFiles(daGlob);
+ // Keep a list of all LCOV files
+ cm::append(lcovFiles, gl.GetFiles());
+
+ for (std::string const& file : lcovFiles) {
+ lcovFile = file;
+ cmsys::ifstream srcead(lcovFile.c_str());
+ if (!srcead) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open file: " << lcovFile << std::endl);
+ }
+ std::string srcname;
+
+ int success = cmSystemTools::GetLineFromStream(srcead, srcname);
+ if (!success) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error while parsing lcov file '"
+ << lcovFile << "':"
+ << " No source file name found!" << std::endl);
+ return 0;
+ }
+ srcname = srcname.substr(18);
+ // We can directly read found LCOV files to determine the source
+ // files
+ sourceFile = srcname;
+ actualSourceFile = srcname;
+
+ for (std::string const& t : lcovFiles) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found LCOV File: " << t << std::endl,
+ this->Quiet);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "SourceFile: " << sourceFile << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "lCovFile: " << lcovFile << std::endl, this->Quiet);
+
+ // If we have some LCOV files to process
+ if (!lcovFile.empty() && !actualSourceFile.empty()) {
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& vec =
+ cont->TotalCoverage[actualSourceFile];
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " in lcovFile: " << lcovFile << std::endl,
+ this->Quiet);
+
+ cmsys::ifstream ifile(lcovFile.c_str());
+ if (!ifile) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open file: " << lcovFile << std::endl);
+ } else {
+ long cnt = -1;
+ std::string nl;
+
+ // Skip the first line
+ cmSystemTools::GetLineFromStream(ifile, nl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "File is ready, start reading." << std::endl,
+ this->Quiet);
+ while (cmSystemTools::GetLineFromStream(ifile, nl)) {
+ cnt++;
+
+ // Skip empty lines
+ if (nl.empty()) {
+ continue;
+ }
+
+ // Skip unused lines
+ if (nl.size() < 12) {
+ continue;
+ }
+
+ // Read the coverage count from the beginning of the lcov
+ // output line
+ std::string prefix = nl.substr(0, 17);
+ int cov = atoi(prefix.c_str());
+
+ // Read the line number starting at the 17th character of the
+ // lcov output line
+ std::string lineNumber = nl.substr(17, 7);
+
+ int lineIdx = atoi(lineNumber.c_str()) - 1;
+ if (lineIdx >= 0) {
+ while (vec.size() <= static_cast<size_t>(lineIdx)) {
+ vec.push_back(-1);
+ }
+
+ // Initially all entries are -1 (not used). If we get coverage
+ // information, increment it to 0 first.
+ if (vec[lineIdx] < 0) {
+ if (cov > 0 || prefix.find('#') != std::string::npos) {
+ vec[lineIdx] = 0;
+ }
+ }
+
+ vec[lineIdx] += cov;
+ }
+ }
+ }
+
+ actualSourceFile.clear();
+ }
+ }
+ }
+
+ file_count++;
+
+ if (file_count % 50 == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " processed: " << file_count << " out of "
+ << files.size() << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ }
+ }
+
+ return file_count;
+}
+
+void cmCTestCoverageHandler::FindGCovFiles(std::vector<std::string>& files)
+{
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOff();
+
+ for (auto const& lm : this->TargetDirs) {
+ // Skip targets containing no interesting labels.
+ if (!this->IntersectsFilter(lm.second)) {
+ continue;
+ }
+
+ // Coverage files appear next to their object files in the target
+ // support directory.
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " globbing for coverage in: " << lm.first << std::endl, this->Quiet);
+ std::string daGlob = cmStrCat(lm.first, "/*.da");
+ gl.FindFiles(daGlob);
+ cm::append(files, gl.GetFiles());
+ daGlob = cmStrCat(lm.first, "/*.gcda");
+ gl.FindFiles(daGlob);
+ cm::append(files, gl.GetFiles());
+ }
+}
+
+bool cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files)
+{
+ cmsys::Glob gl;
+ gl.RecurseOff(); // No need of recurse if -prof_dir${BUILD_DIR} flag is
+ // used while compiling.
+ gl.RecurseThroughSymlinksOff();
+ std::string buildDir = this->CTest->GetCTestConfiguration("BuildDirectory");
+ cmWorkingDirectory workdir(buildDir);
+ if (workdir.Failed()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unable to change working directory to " << buildDir
+ << std::endl);
+ return false;
+ }
+
+ // Run profmerge to merge all *.dyn files into dpi files
+ if (!cmSystemTools::RunSingleCommand("profmerge")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Error while running profmerge.\n");
+ return false;
+ }
+
+ // DPI file should appear in build directory
+ std::string daGlob;
+ daGlob = cmStrCat(buildDir, "/*.dpi");
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " looking for dpi files in: " << daGlob << std::endl,
+ this->Quiet);
+ if (!gl.FindFiles(daGlob)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error while finding files matching " << daGlob << std::endl);
+ return false;
+ }
+ cm::append(files, gl.GetFiles());
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Now searching in: " << daGlob << std::endl, this->Quiet);
+ return true;
+}
+
+int cmCTestCoverageHandler::HandleTracePyCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOff();
+ std::string daGlob = cont->BinaryDir + "/*.cover";
+ gl.FindFiles(daGlob);
+ std::vector<std::string> files = gl.GetFiles();
+
+ if (files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find any Python Trace.py coverage files."
+ << std::endl,
+ this->Quiet);
+ // No coverage files is a valid thing, so the exit code is 0
+ return 0;
+ }
+
+ std::string testingDir = this->CTest->GetBinaryDir() + "/Testing";
+ std::string tempDir = testingDir + "/CoverageInfo";
+ cmSystemTools::MakeDirectory(tempDir);
+
+ int file_count = 0;
+ for (std::string const& file : files) {
+ std::string fileName = this->FindFile(cont, file);
+ if (fileName.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find source Python file corresponding to: "
+ << file << std::endl);
+ continue;
+ }
+
+ std::string actualSourceFile = cmSystemTools::CollapseFullPath(fileName);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Check coverage for file: " << actualSourceFile
+ << std::endl,
+ this->Quiet);
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector* vec =
+ &cont->TotalCoverage[actualSourceFile];
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " in file: " << file << std::endl, this->Quiet);
+ cmsys::ifstream ifile(file.c_str());
+ if (!ifile) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open file: " << file << std::endl);
+ } else {
+ long cnt = -1;
+ std::string nl;
+ while (cmSystemTools::GetLineFromStream(ifile, nl)) {
+ cnt++;
+
+ // Skip empty lines
+ if (nl.empty()) {
+ continue;
+ }
+
+ // Skip unused lines
+ if (nl.size() < 12) {
+ continue;
+ }
+
+ // Read the coverage count from the beginning of the Trace.py output
+ // line
+ std::string::size_type pos;
+ int cov = 0;
+ // This is a hack. We should really do something more elaborate
+ for (pos = 5; pos < 8; pos++) {
+ if (nl[pos] == ' ') {
+ // This line does not have ':' so no coverage here. That said,
+ // Trace.py does not handle not covered lines versus comments etc.
+ // So, this will be set to 0.
+ break;
+ }
+ if (nl[pos] == ':') {
+ cov = atoi(nl.substr(0, pos - 1).c_str());
+ break;
+ }
+ }
+ if (pos == 8) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Currently the limit is maximum coverage of 999999"
+ << std::endl);
+ }
+ // Read the line number starting at the 10th character of the gcov
+ // output line
+ long lineIdx = cnt;
+ if (lineIdx >= 0) {
+ while (vec->size() <= static_cast<size_t>(lineIdx)) {
+ vec->push_back(-1);
+ }
+ // Initially all entries are -1 (not used). If we get coverage
+ // information, increment it to 0 first.
+ if ((*vec)[lineIdx] < 0) {
+ if (cov >= 0) {
+ (*vec)[lineIdx] = 0;
+ }
+ }
+ (*vec)[lineIdx] += cov;
+ }
+ }
+ }
+ ++file_count;
+ }
+ return file_count;
+}
+
+std::string cmCTestCoverageHandler::FindFile(
+ cmCTestCoverageHandlerContainer* cont, std::string const& fileName)
+{
+ std::string fileNameNoE =
+ cmSystemTools::GetFilenameWithoutLastExtension(fileName);
+ // First check in source and binary directory
+ std::string fullName = cont->SourceDir + "/" + fileNameNoE + ".py";
+ if (cmSystemTools::FileExists(fullName)) {
+ return fullName;
+ }
+ fullName = cont->BinaryDir + "/" + fileNameNoE + ".py";
+ if (cmSystemTools::FileExists(fullName)) {
+ return fullName;
+ }
+ return "";
+}
+
+// This is a header put on each marked up source file
+namespace {
+const char* bullseyeHelp[] = {
+ " Coverage produced by bullseye covbr tool: ",
+ " www.bullseye.com/help/ref_covbr.html",
+ " * An arrow --> indicates incomplete coverage.",
+ " * An X indicates a function that was invoked, a switch label that ",
+ " was exercised, a try-block that finished, or an exception handler ",
+ " that was invoked.",
+ " * A T or F indicates a boolean decision that evaluated true or false,",
+ " respectively.",
+ " * A t or f indicates a boolean condition within a decision if the ",
+ " condition evaluated true or false, respectively.",
+ " * A k indicates a constant decision or condition.",
+ " * The slash / means this probe is excluded from summary results. ",
+ nullptr
+};
+}
+
+int cmCTestCoverageHandler::RunBullseyeCoverageBranch(
+ cmCTestCoverageHandlerContainer* cont,
+ std::set<std::string>& coveredFileNames, std::vector<std::string>& files,
+ std::vector<std::string>& filesFullPath)
+{
+ if (files.size() != filesFullPath.size()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Files and full path files not the same size?:\n");
+ return 0;
+ }
+ // create the output stream for the CoverageLog-N.xml file
+ cmGeneratedFileStream covLogFile;
+ cmXMLWriter covLogXML(covLogFile);
+ int logFileCount = 0;
+ if (!this->StartCoverageLogFile(covLogFile, logFileCount)) {
+ return -1;
+ }
+ this->StartCoverageLogXML(covLogXML);
+ // for each file run covbr on that file to get the coverage
+ // information for that file
+ std::string outputFile;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "run covbr: " << std::endl, this->Quiet);
+
+ if (!this->RunBullseyeCommand(cont, "covbr", nullptr, outputFile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "error running covbr for."
+ << "\n");
+ return -1;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "covbr output in " << outputFile << std::endl,
+ this->Quiet);
+ // open the output file
+ cmsys::ifstream fin(outputFile.c_str());
+ if (!fin) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open coverage file: " << outputFile << std::endl);
+ return 0;
+ }
+ std::map<std::string, std::string> fileMap;
+ auto fp = filesFullPath.begin();
+ for (auto f = files.begin(); f != files.end(); ++f, ++fp) {
+ fileMap[*f] = *fp;
+ }
+
+ int count = 0; // keep count of the number of files
+ // Now parse each line from the bullseye cov log file
+ std::string lineIn;
+ bool valid = false; // are we in a valid output file
+ int line = 0; // line of the current file
+ std::string file;
+ while (cmSystemTools::GetLineFromStream(fin, lineIn)) {
+ bool startFile = false;
+ if (lineIn.size() > 1 && lineIn[lineIn.size() - 1] == ':') {
+ file = lineIn.substr(0, lineIn.size() - 1);
+ if (coveredFileNames.find(file) != coveredFileNames.end()) {
+ startFile = true;
+ }
+ }
+ if (startFile) {
+ // if we are in a valid file close it because a new one started
+ if (valid) {
+ covLogXML.EndElement(); // Report
+ covLogXML.EndElement(); // File
+ }
+ // only allow 100 files in each log file
+ if (count != 0 && count % 100 == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "start a new log file: " << count << std::endl,
+ this->Quiet);
+ this->EndCoverageLogXML(covLogXML);
+ this->EndCoverageLogFile(covLogFile, logFileCount);
+ logFileCount++;
+ if (!this->StartCoverageLogFile(covLogFile, logFileCount)) {
+ return -1;
+ }
+ this->StartCoverageLogXML(covLogXML);
+ count++; // move on one
+ }
+ auto i = fileMap.find(file);
+ // if the file should be covered write out the header for that file
+ if (i != fileMap.end()) {
+ // we have a new file so count it in the output
+ count++;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Produce coverage for file: " << file << " "
+ << count << std::endl,
+ this->Quiet);
+ // start the file output
+ covLogXML.StartElement("File");
+ covLogXML.Attribute("Name", i->first);
+ covLogXML.Attribute("FullPath",
+ this->CTest->GetShortPathToFile(i->second));
+ covLogXML.StartElement("Report");
+ // write the bullseye header
+ line = 0;
+ for (int k = 0; bullseyeHelp[k] != nullptr; ++k) {
+ covLogXML.StartElement("Line");
+ covLogXML.Attribute("Number", line);
+ covLogXML.Attribute("Count", -1);
+ covLogXML.Content(bullseyeHelp[k]);
+ covLogXML.EndElement(); // Line
+ line++;
+ }
+ valid = true; // we are in a valid file section
+ } else {
+ // this is not a file that we want coverage for
+ valid = false;
+ }
+ }
+ // we are not at a start file, and we are in a valid file output the line
+ else if (valid) {
+ covLogXML.StartElement("Line");
+ covLogXML.Attribute("Number", line);
+ covLogXML.Attribute("Count", -1);
+ covLogXML.Content(lineIn);
+ covLogXML.EndElement(); // Line
+ line++;
+ }
+ }
+ // if we ran out of lines a valid file then close that file
+ if (valid) {
+ covLogXML.EndElement(); // Report
+ covLogXML.EndElement(); // File
+ }
+ this->EndCoverageLogXML(covLogXML);
+ this->EndCoverageLogFile(covLogFile, logFileCount);
+ return 1;
+}
+
+int cmCTestCoverageHandler::RunBullseyeCommand(
+ cmCTestCoverageHandlerContainer* cont, const char* cmd, const char* arg,
+ std::string& outputFile)
+{
+ std::string program = cmSystemTools::FindProgram(cmd);
+ if (program.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find :" << cmd << "\n");
+ return 0;
+ }
+ if (arg) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run : " << program << " " << arg << "\n", this->Quiet);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run : " << program << "\n", this->Quiet);
+ }
+ // create a process object and start it
+ cmCTestRunProcess runCoverageSrc;
+ runCoverageSrc.SetCommand(program.c_str());
+ runCoverageSrc.AddArgument(arg);
+ std::string stdoutFile =
+ cmStrCat(cont->BinaryDir, "/Testing/Temporary/",
+ this->GetCTestInstance()->GetCurrentTag(), '-', cmd);
+ std::string stderrFile = stdoutFile;
+ stdoutFile += ".stdout";
+ stderrFile += ".stderr";
+ runCoverageSrc.SetStdoutFile(stdoutFile.c_str());
+ runCoverageSrc.SetStderrFile(stderrFile.c_str());
+ if (!runCoverageSrc.StartProcess()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Could not run : " << program << " " << arg << "\n"
+ << "kwsys process state : "
+ << runCoverageSrc.GetProcessState());
+ return 0;
+ }
+ // since we set the output file names wait for it to end
+ runCoverageSrc.WaitForExit();
+ outputFile = stdoutFile;
+ return 1;
+}
+
+int cmCTestCoverageHandler::RunBullseyeSourceSummary(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ // Run the covsrc command and create a temp outputfile
+ std::string outputFile;
+ if (!this->RunBullseyeCommand(cont, "covsrc", "-c", outputFile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "error running covsrc:\n");
+ return 0;
+ }
+
+ std::ostream& tmpLog = *cont->OFS;
+ // copen the Coverage.xml file in the Testing directory
+ cmGeneratedFileStream covSumFile;
+ cmXMLWriter xml(covSumFile);
+ if (!this->StartResultingXML(cmCTest::PartCoverage, "Coverage",
+ covSumFile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open coverage summary file." << std::endl);
+ return 0;
+ }
+ this->CTest->StartXML(xml, this->AppendXML);
+ auto elapsed_time_start = std::chrono::steady_clock::now();
+ std::string coverage_start_time = this->CTest->CurrentTime();
+ xml.StartElement("Coverage");
+ xml.Element("StartDateTime", coverage_start_time);
+ xml.Element("StartTime", std::chrono::system_clock::now());
+ std::string stdline;
+ std::string errline;
+ // expected output:
+ // first line is:
+ // "Source","Function Coverage","out of","%","C/D Coverage","out of","%"
+ // after that data follows in that format
+ std::string sourceFile;
+ int functionsCalled = 0;
+ int totalFunctions = 0;
+ int percentFunction = 0;
+ int branchCovered = 0;
+ int totalBranches = 0;
+ int percentBranch = 0;
+ double total_tested = 0;
+ double total_untested = 0;
+ double total_functions = 0;
+ double percent_coverage = 0;
+ double number_files = 0;
+ std::vector<std::string> coveredFiles;
+ std::vector<std::string> coveredFilesFullPath;
+ // Read and parse the summary output file
+ cmsys::ifstream fin(outputFile.c_str());
+ if (!fin) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open coverage summary file: " << outputFile
+ << std::endl);
+ return 0;
+ }
+ std::set<std::string> coveredFileNames;
+ while (cmSystemTools::GetLineFromStream(fin, stdline)) {
+ // if we have a line of output from stdout
+ if (!stdline.empty()) {
+ // parse the comma separated output
+ this->ParseBullsEyeCovsrcLine(
+ stdline, sourceFile, functionsCalled, totalFunctions, percentFunction,
+ branchCovered, totalBranches, percentBranch);
+ // The first line is the header
+ if (sourceFile == "Source" || sourceFile == "Total") {
+ continue;
+ }
+ std::string file = sourceFile;
+ coveredFileNames.insert(file);
+ if (!cmSystemTools::FileIsFullPath(sourceFile)) {
+ // file will be relative to the binary dir
+ file = cmStrCat(cont->BinaryDir, '/', sourceFile);
+ }
+ file = cmSystemTools::CollapseFullPath(file);
+ bool shouldIDoCoverage =
+ this->ShouldIDoCoverage(file, cont->SourceDir, cont->BinaryDir);
+ if (!shouldIDoCoverage) {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ ".NoDartCoverage found, so skip coverage check for: " << file
+ << std::endl,
+ this->Quiet);
+ continue;
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Doing coverage for: " << file << std::endl,
+ this->Quiet);
+
+ coveredFiles.push_back(sourceFile);
+ coveredFilesFullPath.push_back(file);
+
+ number_files++;
+ total_functions += totalFunctions;
+ total_tested += functionsCalled;
+ total_untested += (totalFunctions - functionsCalled);
+
+ std::string fileName = cmSystemTools::GetFilenameName(file);
+ std::string shortFileName = this->CTest->GetShortPathToFile(file);
+
+ float cper = static_cast<float>(percentBranch + percentFunction);
+ if (totalBranches > 0) {
+ cper /= 2.0f;
+ }
+ percent_coverage += static_cast<double>(cper);
+ float cmet = static_cast<float>(percentFunction + percentBranch);
+ if (totalBranches > 0) {
+ cmet /= 2.0f;
+ }
+ cmet /= 100.0f;
+ tmpLog << stdline << "\n";
+ tmpLog << fileName << "\n";
+ tmpLog << "functionsCalled: " << functionsCalled / 100 << "\n";
+ tmpLog << "totalFunctions: " << totalFunctions / 100 << "\n";
+ tmpLog << "percentFunction: " << percentFunction << "\n";
+ tmpLog << "branchCovered: " << branchCovered << "\n";
+ tmpLog << "totalBranches: " << totalBranches << "\n";
+ tmpLog << "percentBranch: " << percentBranch << "\n";
+ tmpLog << "percentCoverage: " << percent_coverage << "\n";
+ tmpLog << "coverage metric: " << cmet << "\n";
+ xml.StartElement("File");
+ xml.Attribute("Name", sourceFile);
+ xml.Attribute("FullPath", shortFileName);
+ xml.Attribute("Covered", cmet > 0 ? "true" : "false");
+ xml.Element("BranchesTested", branchCovered);
+ xml.Element("BranchesUnTested", totalBranches - branchCovered);
+ xml.Element("FunctionsTested", functionsCalled);
+ xml.Element("FunctionsUnTested", totalFunctions - functionsCalled);
+ // Hack for conversion of function to loc assume a function
+ // has 100 lines of code
+ xml.Element("LOCTested", functionsCalled * 100);
+ xml.Element("LOCUnTested", (totalFunctions - functionsCalled) * 100);
+ xml.Element("PercentCoverage", cper);
+ xml.Element("CoverageMetric", cmet);
+ this->WriteXMLLabels(xml, shortFileName);
+ xml.EndElement(); // File
+ }
+ }
+ std::string end_time = this->CTest->CurrentTime();
+ xml.Element("LOCTested", total_tested);
+ xml.Element("LOCUntested", total_untested);
+ xml.Element("LOC", total_functions);
+ xml.Element("PercentCoverage", SAFEDIV(percent_coverage, number_files));
+ xml.Element("EndDateTime", end_time);
+ xml.Element("EndTime", std::chrono::system_clock::now());
+ xml.Element("ElapsedMinutes",
+ std::chrono::duration_cast<std::chrono::minutes>(
+ std::chrono::steady_clock::now() - elapsed_time_start)
+ .count());
+ xml.EndElement(); // Coverage
+ this->CTest->EndXML(xml);
+
+ // Now create the coverage information for each file
+ return this->RunBullseyeCoverageBranch(cont, coveredFileNames, coveredFiles,
+ coveredFilesFullPath);
+}
+
+int cmCTestCoverageHandler::HandleBullseyeCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ std::string covfile;
+ if (!cmSystemTools::GetEnv("COVFILE", covfile) || covfile.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " COVFILE environment variable not found, not running "
+ " bullseye\n",
+ this->Quiet);
+ return 0;
+ }
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " run covsrc with COVFILE=[" << covfile << "]" << std::endl, this->Quiet);
+ if (!this->RunBullseyeSourceSummary(cont)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error running bullseye summary.\n");
+ return 0;
+ }
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "HandleBullseyeCoverage return 1 " << std::endl,
+ this->Quiet);
+ return 1;
+}
+
+bool cmCTestCoverageHandler::GetNextInt(std::string const& inputLine,
+ std::string::size_type& pos,
+ int& value)
+{
+ std::string::size_type start = pos;
+ pos = inputLine.find(',', start);
+ value = atoi(inputLine.substr(start, pos).c_str());
+ if (pos == std::string::npos) {
+ return true;
+ }
+ pos++;
+ return true;
+}
+
+bool cmCTestCoverageHandler::ParseBullsEyeCovsrcLine(
+ std::string const& inputLine, std::string& sourceFile, int& functionsCalled,
+ int& totalFunctions, int& percentFunction, int& branchCovered,
+ int& totalBranches, int& percentBranch)
+{
+ // find the first comma
+ std::string::size_type pos = inputLine.find(',');
+ if (pos == std::string::npos) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error parsing string : " << inputLine << "\n");
+ return false;
+ }
+ // the source file has "" around it so extract out the file name
+ sourceFile = inputLine.substr(1, pos - 2);
+ pos++;
+ if (!this->GetNextInt(inputLine, pos, functionsCalled)) {
+ return false;
+ }
+ if (!this->GetNextInt(inputLine, pos, totalFunctions)) {
+ return false;
+ }
+ if (!this->GetNextInt(inputLine, pos, percentFunction)) {
+ return false;
+ }
+ if (!this->GetNextInt(inputLine, pos, branchCovered)) {
+ return false;
+ }
+ if (!this->GetNextInt(inputLine, pos, totalBranches)) {
+ return false;
+ }
+ if (!this->GetNextInt(inputLine, pos, percentBranch)) {
+ return false;
+ }
+ // should be at the end now
+ if (pos != std::string::npos) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error parsing input : "
+ << inputLine << " last pos not npos = " << pos << "\n");
+ }
+ return true;
+}
+
+int cmCTestCoverageHandler::GetLabelId(std::string const& label)
+{
+ auto i = this->LabelIdMap.find(label);
+ if (i == this->LabelIdMap.end()) {
+ int n = int(this->Labels.size());
+ this->Labels.push_back(label);
+ LabelIdMapType::value_type entry(label, n);
+ i = this->LabelIdMap.insert(entry).first;
+ }
+ return i->second;
+}
+
+void cmCTestCoverageHandler::LoadLabels()
+{
+ std::string fileList =
+ cmStrCat(this->CTest->GetBinaryDir(), "/CMakeFiles/TargetDirectories.txt");
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " target directory list [" << fileList << "]\n",
+ this->Quiet);
+ cmsys::ifstream finList(fileList.c_str());
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(finList, line)) {
+ this->LoadLabels(line.c_str());
+ }
+}
+
+void cmCTestCoverageHandler::LoadLabels(const char* dir)
+{
+ LabelSet& dirLabels = this->TargetDirs[dir];
+ std::string fname = cmStrCat(dir, "/Labels.txt");
+ cmsys::ifstream fin(fname.c_str());
+ if (!fin) {
+ return;
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " loading labels from [" << fname << "]\n", this->Quiet);
+ bool inTarget = true;
+ std::string source;
+ std::string line;
+ std::vector<int> targetLabels;
+ 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.
+ std::string label = line.substr(1);
+ int id = this->GetLabelId(label);
+ dirLabels.insert(id);
+ if (inTarget) {
+ targetLabels.push_back(id);
+ } else {
+ this->SourceLabels[source].insert(id);
+ }
+ } else {
+ // Non-indented lines specify a source file name. The first one
+ // is the end of the target-wide labels.
+ inTarget = false;
+
+ source = this->CTest->GetShortPathToFile(line);
+
+ // Label the source with the target labels.
+ LabelSet& labelSet = this->SourceLabels[source];
+ labelSet.insert(targetLabels.begin(), targetLabels.end());
+ }
+ }
+}
+
+void cmCTestCoverageHandler::WriteXMLLabels(cmXMLWriter& xml,
+ std::string const& source)
+{
+ auto li = this->SourceLabels.find(source);
+ if (li != this->SourceLabels.end() && !li->second.empty()) {
+ xml.StartElement("Labels");
+ for (auto const& ls : li->second) {
+ xml.Element("Label", this->Labels[ls]);
+ }
+ xml.EndElement(); // Labels
+ }
+}
+
+void cmCTestCoverageHandler::SetLabelFilter(
+ std::set<std::string> const& labels)
+{
+ this->LabelFilter.clear();
+ for (std::string const& l : labels) {
+ this->LabelFilter.insert(this->GetLabelId(l));
+ }
+}
+
+bool cmCTestCoverageHandler::IntersectsFilter(LabelSet const& labels)
+{
+ // If there is no label filter then nothing is filtered out.
+ if (this->LabelFilter.empty()) {
+ return true;
+ }
+
+ std::vector<int> ids;
+ std::set_intersection(labels.begin(), labels.end(),
+ this->LabelFilter.begin(), this->LabelFilter.end(),
+ std::back_inserter(ids));
+ return !ids.empty();
+}
+
+bool cmCTestCoverageHandler::IsFilteredOut(std::string const& source)
+{
+ // If there is no label filter then nothing is filtered out.
+ if (this->LabelFilter.empty()) {
+ return false;
+ }
+
+ // The source is filtered out if it does not have any labels in
+ // common with the filter set.
+ std::string shortSrc = this->CTest->GetShortPathToFile(source);
+ auto li = this->SourceLabels.find(shortSrc);
+ if (li != this->SourceLabels.end()) {
+ return !this->IntersectsFilter(li->second);
+ }
+ return true;
+}
+
+std::set<std::string> cmCTestCoverageHandler::FindUncoveredFiles(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ std::set<std::string> extraMatches;
+
+ for (std::string const& ecg : this->ExtraCoverageGlobs) {
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOff();
+ std::string glob = cont->SourceDir + "/" + ecg;
+ gl.FindFiles(glob);
+ std::vector<std::string> files = gl.GetFiles();
+ for (std::string const& f : files) {
+ if (this->ShouldIDoCoverage(f, cont->SourceDir, cont->BinaryDir)) {
+ extraMatches.insert(this->CTest->GetShortPathToFile(f));
+ }
+ }
+ }
+
+ if (!extraMatches.empty()) {
+ for (auto const& i : cont->TotalCoverage) {
+ std::string shortPath = this->CTest->GetShortPathToFile(i.first);
+ extraMatches.erase(shortPath);
+ }
+ }
+ return extraMatches;
+}
diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h
new file mode 100644
index 0000000..8732723
--- /dev/null
+++ b/Source/CTest/cmCTestCoverageHandler.h
@@ -0,0 +1,150 @@
+/* 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 <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCTestGenericHandler.h"
+
+class cmGeneratedFileStream;
+class cmMakefile;
+class cmXMLWriter;
+
+class cmCTestCoverageHandlerContainer
+{
+public:
+ int Error;
+ std::string SourceDir;
+ std::string BinaryDir;
+ using SingleFileCoverageVector = std::vector<int>;
+ using TotalCoverageMap = std::map<std::string, SingleFileCoverageVector>;
+ TotalCoverageMap TotalCoverage;
+ std::ostream* OFS;
+ bool Quiet;
+};
+/** \class cmCTestCoverageHandler
+ * \brief A class that handles coverage computation for ctest
+ *
+ */
+class cmCTestCoverageHandler : public cmCTestGenericHandler
+{
+public:
+ using Superclass = cmCTestGenericHandler;
+
+ /*
+ * The main entry point for this class
+ */
+ int ProcessHandler() override;
+
+ cmCTestCoverageHandler();
+
+ void Initialize() override;
+
+ /**
+ * This method is called when reading CTest custom file
+ */
+ void PopulateCustomVectors(cmMakefile* mf) override;
+
+ /** Report coverage only for sources with these labels. */
+ void SetLabelFilter(std::set<std::string> const& labels);
+
+private:
+ bool ShouldIDoCoverage(std::string const& file, std::string const& srcDir,
+ std::string const& binDir);
+ void CleanCoverageLogFiles(std::ostream& log);
+ bool StartCoverageLogFile(cmGeneratedFileStream& ostr, int logFileCount);
+ void EndCoverageLogFile(cmGeneratedFileStream& ostr, int logFileCount);
+
+ void StartCoverageLogXML(cmXMLWriter& xml);
+ void EndCoverageLogXML(cmXMLWriter& xml);
+
+ //! Handle coverage using GCC's GCov
+ int HandleGCovCoverage(cmCTestCoverageHandlerContainer* cont);
+ void FindGCovFiles(std::vector<std::string>& files);
+
+ //! Handle coverage using Intel's LCov
+ int HandleLCovCoverage(cmCTestCoverageHandlerContainer* cont);
+ bool FindLCovFiles(std::vector<std::string>& files);
+
+ //! Handle coverage using xdebug php coverage
+ int HandlePHPCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage for Python with coverage.py
+ int HandleCoberturaCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage for mumps
+ int HandleMumpsCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage for Jacoco
+ int HandleJacocoCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage for Delphi (Pascal)
+ int HandleDelphiCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage for Jacoco
+ int HandleBlanketJSCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage using Bullseye
+ int HandleBullseyeCoverage(cmCTestCoverageHandlerContainer* cont);
+ int RunBullseyeSourceSummary(cmCTestCoverageHandlerContainer* cont);
+ int RunBullseyeCoverageBranch(cmCTestCoverageHandlerContainer* cont,
+ std::set<std::string>& coveredFileNames,
+ std::vector<std::string>& files,
+ std::vector<std::string>& filesFullPath);
+
+ int RunBullseyeCommand(cmCTestCoverageHandlerContainer* cont,
+ const char* cmd, const char* arg,
+ std::string& outputFile);
+ bool ParseBullsEyeCovsrcLine(std::string const& inputLine,
+ std::string& sourceFile, int& functionsCalled,
+ int& totalFunctions, int& percentFunction,
+ int& branchCovered, int& totalBranches,
+ int& percentBranch);
+ bool GetNextInt(std::string const& inputLine, std::string::size_type& pos,
+ int& value);
+ //! Handle Python coverage using Python's Trace.py
+ int HandleTracePyCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ // Find the source file based on the source and build tree. This is used for
+ // Trace.py mode, since that one does not tell us where the source file is.
+ std::string FindFile(cmCTestCoverageHandlerContainer* cont,
+ std::string const& fileName);
+
+ std::set<std::string> FindUncoveredFiles(
+ cmCTestCoverageHandlerContainer* cont);
+ std::vector<std::string> CustomCoverageExclude;
+ std::vector<cmsys::RegularExpression> CustomCoverageExcludeRegex;
+ std::vector<std::string> ExtraCoverageGlobs;
+
+ // Map from source file to label ids.
+ class LabelSet : public std::set<int>
+ {
+ };
+ using LabelMapType = std::map<std::string, LabelSet>;
+ LabelMapType SourceLabels;
+ LabelMapType TargetDirs;
+
+ // Map from label name to label id.
+ using LabelIdMapType = std::map<std::string, int>;
+ LabelIdMapType LabelIdMap;
+ std::vector<std::string> Labels;
+ int GetLabelId(std::string const& label);
+
+ // Label reading and writing methods.
+ void LoadLabels();
+ void LoadLabels(const char* dir);
+ void WriteXMLLabels(cmXMLWriter& xml, std::string const& source);
+
+ // Label-based filtering.
+ std::set<int> LabelFilter;
+ bool IntersectsFilter(LabelSet const& labels);
+ bool IsFilteredOut(std::string const& source);
+};
diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx
new file mode 100644
index 0000000..69c5793
--- /dev/null
+++ b/Source/CTest/cmCTestCurl.cxx
@@ -0,0 +1,272 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestCurl.h"
+
+#include <cstdio>
+#include <ostream>
+
+#include <cmext/algorithm>
+
+#include "cmCTest.h"
+#include "cmCurl.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmCTestCurl::cmCTestCurl(cmCTest* ctest)
+{
+ this->CTest = ctest;
+ this->SetProxyType();
+ this->UseHttp10 = false;
+ // In windows, this will init the winsock stuff
+ ::curl_global_init(CURL_GLOBAL_ALL);
+ // default is to verify https
+ this->VerifyPeerOff = false;
+ this->VerifyHostOff = false;
+ this->Quiet = false;
+ this->TimeOutSeconds = 0;
+ this->Curl = curl_easy_init();
+}
+
+cmCTestCurl::~cmCTestCurl()
+{
+ ::curl_easy_cleanup(this->Curl);
+ ::curl_global_cleanup();
+}
+
+std::string cmCTestCurl::Escape(std::string const& source)
+{
+ char* data1 = curl_easy_escape(this->Curl, source.c_str(), 0);
+ std::string ret = data1;
+ curl_free(data1);
+ return ret;
+}
+
+namespace {
+size_t curlWriteMemoryCallback(void* ptr, size_t size, size_t nmemb,
+ void* data)
+{
+ int realsize = static_cast<int>(size * nmemb);
+ const char* chPtr = static_cast<char*>(ptr);
+ cm::append(*static_cast<std::vector<char>*>(data), chPtr, chPtr + realsize);
+ return realsize;
+}
+
+size_t curlDebugCallback(CURL* /*unused*/, curl_infotype /*unused*/,
+ char* chPtr, size_t size, void* data)
+{
+ cm::append(*static_cast<std::vector<char>*>(data), chPtr, chPtr + size);
+ return 0;
+}
+}
+
+void cmCTestCurl::SetCurlOptions(std::vector<std::string> const& args)
+{
+ for (std::string const& arg : args) {
+ if (arg == "CURLOPT_SSL_VERIFYPEER_OFF") {
+ this->VerifyPeerOff = true;
+ }
+ if (arg == "CURLOPT_SSL_VERIFYHOST_OFF") {
+ this->VerifyHostOff = true;
+ }
+ }
+}
+
+bool cmCTestCurl::InitCurl()
+{
+ if (!this->Curl) {
+ return false;
+ }
+ cmCurlSetCAInfo(this->Curl);
+ if (this->VerifyPeerOff) {
+ curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYPEER, 0);
+ }
+ if (this->VerifyHostOff) {
+ curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYHOST, 0);
+ }
+ if (!this->HTTPProxy.empty()) {
+ curl_easy_setopt(this->Curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
+ curl_easy_setopt(this->Curl, CURLOPT_PROXYTYPE, this->HTTPProxyType);
+ if (!this->HTTPProxyAuth.empty()) {
+ curl_easy_setopt(this->Curl, CURLOPT_PROXYUSERPWD,
+ this->HTTPProxyAuth.c_str());
+ }
+ }
+ if (this->UseHttp10) {
+ curl_easy_setopt(this->Curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ }
+ // enable HTTP ERROR parsing
+ curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+
+ // if there is little to no activity for too long stop submitting
+ if (this->TimeOutSeconds) {
+ curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_LIMIT, 1);
+ curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_TIME, this->TimeOutSeconds);
+ }
+
+ return true;
+}
+
+bool cmCTestCurl::UploadFile(std::string const& local_file,
+ std::string const& url, std::string const& fields,
+ std::string& response)
+{
+ response.clear();
+ if (!this->InitCurl()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
+ return false;
+ }
+ /* enable uploading */
+ curl_easy_setopt(this->Curl, CURLOPT_UPLOAD, 1);
+
+ /* HTTP PUT please */
+ ::curl_easy_setopt(this->Curl, CURLOPT_PUT, 1);
+ ::curl_easy_setopt(this->Curl, CURLOPT_VERBOSE, 1);
+
+ FILE* ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
+ if (!ftpfile) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Could not open file for upload: " << local_file << "\n");
+ return false;
+ }
+ // set the url
+ std::string upload_url = cmStrCat(url, '?', fields);
+ ::curl_easy_setopt(this->Curl, CURLOPT_URL, upload_url.c_str());
+ // now specify which file to upload
+ ::curl_easy_setopt(this->Curl, CURLOPT_INFILE, ftpfile);
+ unsigned long filelen = cmSystemTools::FileLength(local_file);
+ // and give the size of the upload (optional)
+ ::curl_easy_setopt(this->Curl, CURLOPT_INFILESIZE,
+ static_cast<long>(filelen));
+ ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,
+ curlWriteMemoryCallback);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION, curlDebugCallback);
+ // Set Content-Type to satisfy fussy modsecurity rules.
+ struct curl_slist* headers =
+ ::curl_slist_append(nullptr, "Content-Type: text/xml");
+ // Add any additional headers that the user specified.
+ for (std::string const& h : this->HttpHeaders) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ " Add HTTP Header: \"" << h << "\"" << std::endl,
+ this->Quiet);
+ headers = ::curl_slist_append(headers, h.c_str());
+ }
+ ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, headers);
+ std::vector<char> responseData;
+ std::vector<char> debugData;
+ ::curl_easy_setopt(this->Curl, CURLOPT_FILE, &responseData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, &debugData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+ // Now run off and do what you've been told!
+ ::curl_easy_perform(this->Curl);
+ ::fclose(ftpfile);
+ ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, NULL);
+ ::curl_slist_free_all(headers);
+
+ if (!responseData.empty()) {
+ response = std::string(responseData.begin(), responseData.end());
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Curl response: [" << response << "]\n", this->Quiet);
+ }
+ std::string curlDebug;
+ if (!debugData.empty()) {
+ curlDebug = std::string(debugData.begin(), debugData.end());
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Curl debug: [" << curlDebug << "]\n", this->Quiet);
+ }
+ if (response.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "No response from server.\n"
+ << curlDebug);
+ return false;
+ }
+ return true;
+}
+
+bool cmCTestCurl::HttpRequest(std::string const& url,
+ std::string const& fields, std::string& response)
+{
+ response.clear();
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "HttpRequest\n"
+ << "url: " << url << "\n"
+ << "fields " << fields << "\n",
+ this->Quiet);
+ if (!this->InitCurl()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
+ return false;
+ }
+ curl_easy_setopt(this->Curl, CURLOPT_POST, 1);
+ curl_easy_setopt(this->Curl, CURLOPT_POSTFIELDS, fields.c_str());
+ ::curl_easy_setopt(this->Curl, CURLOPT_URL, url.c_str());
+ ::curl_easy_setopt(this->Curl, CURLOPT_FOLLOWLOCATION, 1);
+ // set response options
+ ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,
+ curlWriteMemoryCallback);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION, curlDebugCallback);
+ std::vector<char> responseData;
+ std::vector<char> debugData;
+ ::curl_easy_setopt(this->Curl, CURLOPT_FILE, &responseData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, &debugData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+
+ // Add headers if any were specified.
+ struct curl_slist* headers = nullptr;
+ if (!this->HttpHeaders.empty()) {
+ for (std::string const& h : this->HttpHeaders) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ " Add HTTP Header: \"" << h << "\"" << std::endl,
+ this->Quiet);
+ headers = ::curl_slist_append(headers, h.c_str());
+ }
+ }
+
+ ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, headers);
+ CURLcode res = ::curl_easy_perform(this->Curl);
+ ::curl_slist_free_all(headers);
+
+ if (!responseData.empty()) {
+ response = std::string(responseData.begin(), responseData.end());
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Curl response: [" << response << "]\n", this->Quiet);
+ }
+ if (!debugData.empty()) {
+ std::string curlDebug = std::string(debugData.begin(), debugData.end());
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Curl debug: [" << curlDebug << "]\n", this->Quiet);
+ }
+ cmCTestOptionalLog(this->CTest, DEBUG, "Curl res: " << res << "\n",
+ this->Quiet);
+ return (res == 0);
+}
+
+void cmCTestCurl::SetProxyType()
+{
+ this->HTTPProxy.clear();
+ // this is the default
+ this->HTTPProxyType = CURLPROXY_HTTP;
+ this->HTTPProxyAuth.clear();
+ if (cmSystemTools::GetEnv("HTTP_PROXY", this->HTTPProxy)) {
+ std::string port;
+ if (cmSystemTools::GetEnv("HTTP_PROXY_PORT", port)) {
+ this->HTTPProxy += ":";
+ this->HTTPProxy += port;
+ }
+ std::string type;
+ if (cmSystemTools::GetEnv("HTTP_PROXY_TYPE", type)) {
+ // HTTP/SOCKS4/SOCKS5
+ if (type == "HTTP") {
+ this->HTTPProxyType = CURLPROXY_HTTP;
+ } else if (type == "SOCKS4") {
+ this->HTTPProxyType = CURLPROXY_SOCKS4;
+ } else if (type == "SOCKS5") {
+ this->HTTPProxyType = CURLPROXY_SOCKS5;
+ }
+ }
+ cmSystemTools::GetEnv("HTTP_PROXY_USER", this->HTTPProxyAuth);
+ std::string passwd;
+ if (cmSystemTools::GetEnv("HTTP_PROXY_PASSWD", passwd)) {
+ this->HTTPProxyAuth += ":";
+ this->HTTPProxyAuth += passwd;
+ }
+ }
+}
diff --git a/Source/CTest/cmCTestCurl.h b/Source/CTest/cmCTestCurl.h
new file mode 100644
index 0000000..d9aa916
--- /dev/null
+++ b/Source/CTest/cmCTestCurl.h
@@ -0,0 +1,53 @@
+/* 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 <string>
+#include <vector>
+
+#include <cm3p/curl/curl.h>
+
+class cmCTest;
+
+class cmCTestCurl
+{
+public:
+ cmCTestCurl(cmCTest*);
+ ~cmCTestCurl();
+ cmCTestCurl(const cmCTestCurl&) = delete;
+ cmCTestCurl& operator=(const cmCTestCurl&) = delete;
+ bool UploadFile(std::string const& local_file, std::string const& url,
+ std::string const& fields, std::string& response);
+ bool HttpRequest(std::string const& url, std::string const& fields,
+ std::string& response);
+ // currently only supports CURLOPT_SSL_VERIFYPEER_OFF
+ // and CURLOPT_SSL_VERIFYHOST_OFF
+ void SetCurlOptions(std::vector<std::string> const& args);
+ void SetHttpHeaders(std::vector<std::string> const& v)
+ {
+ this->HttpHeaders = v;
+ }
+ void SetUseHttp10On() { this->UseHttp10 = true; }
+ void SetTimeOutSeconds(int s) { this->TimeOutSeconds = s; }
+ void SetQuiet(bool b) { this->Quiet = b; }
+ std::string Escape(std::string const& source);
+
+protected:
+ void SetProxyType();
+ bool InitCurl();
+
+private:
+ cmCTest* CTest;
+ CURL* Curl;
+ std::vector<std::string> HttpHeaders;
+ std::string HTTPProxyAuth;
+ std::string HTTPProxy;
+ curl_proxytype HTTPProxyType;
+ bool VerifyHostOff;
+ bool VerifyPeerOff;
+ bool UseHttp10;
+ bool Quiet;
+ int TimeOutSeconds;
+};
diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
new file mode 100644
index 0000000..af495bb
--- /dev/null
+++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
@@ -0,0 +1,27 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestEmptyBinaryDirectoryCommand.h"
+
+#include <sstream>
+
+#include "cmCTestScriptHandler.h"
+
+class cmExecutionStatus;
+
+bool cmCTestEmptyBinaryDirectoryCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus& /*unused*/)
+{
+ if (args.size() != 1) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ if (!cmCTestScriptHandler::EmptyBinaryDirectory(args[0])) {
+ std::ostringstream ostr;
+ ostr << "problem removing the binary directory: " << args[0];
+ this->SetError(ostr.str());
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h
new file mode 100644
index 0000000..ba2b0eb
--- /dev/null
+++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h
@@ -0,0 +1,46 @@
+/* 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 <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmCTestCommand.h"
+#include "cmCommand.h"
+
+class cmExecutionStatus;
+
+/** \class cmCTestEmptyBinaryDirectory
+ * \brief Run a ctest script
+ *
+ * cmLibrarysCommand defines a list of executable (i.e., test)
+ * programs to create.
+ */
+class cmCTestEmptyBinaryDirectoryCommand : public cmCTestCommand
+{
+public:
+ cmCTestEmptyBinaryDirectoryCommand() {}
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ auto ni = cm::make_unique<cmCTestEmptyBinaryDirectoryCommand>();
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return std::unique_ptr<cmCommand>(std::move(ni));
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) override;
+};
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
new file mode 100644
index 0000000..568b091
--- /dev/null
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -0,0 +1,656 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestGIT.h"
+
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <ctime>
+#include <utility>
+#include <vector>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Process.h"
+
+#include "cmCTest.h"
+#include "cmCTestVC.h"
+#include "cmProcessOutput.h"
+#include "cmProcessTools.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+static unsigned int cmCTestGITVersion(unsigned int epic, unsigned int major,
+ unsigned int minor, unsigned int fix)
+{
+ // 1.6.5.0 maps to 10605000
+ return fix + minor * 1000 + major * 100000 + epic * 10000000;
+}
+
+cmCTestGIT::cmCTestGIT(cmCTest* ct, std::ostream& log)
+ : cmCTestGlobalVC(ct, log)
+{
+ this->PriorRev = this->Unknown;
+ this->CurrentGitVersion = 0;
+}
+
+cmCTestGIT::~cmCTestGIT() = default;
+
+class cmCTestGIT::OneLineParser : public cmCTestVC::LineParser
+{
+public:
+ OneLineParser(cmCTestGIT* git, const char* prefix, std::string& l)
+ : Line1(l)
+ {
+ this->SetLog(&git->Log, prefix);
+ }
+
+private:
+ std::string& Line1;
+ bool ProcessLine() override
+ {
+ // Only the first line is of interest.
+ this->Line1 = this->Line;
+ return false;
+ }
+};
+
+std::string cmCTestGIT::GetWorkingRevision()
+{
+ // Run plumbing "git rev-list" to get work tree revision.
+ const char* git = this->CommandLineTool.c_str();
+ const char* git_rev_list[] = { git, "rev-list", "-n", "1",
+ "HEAD", "--", nullptr };
+ std::string rev;
+ OneLineParser out(this, "rl-out> ", rev);
+ OutputLogger err(this->Log, "rl-err> ");
+ this->RunChild(git_rev_list, &out, &err);
+ return rev;
+}
+
+bool cmCTestGIT::NoteOldRevision()
+{
+ this->OldRevision = this->GetWorkingRevision();
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Old revision of repository is: " << this->OldRevision
+ << "\n");
+ this->PriorRev.Rev = this->OldRevision;
+ return true;
+}
+
+bool cmCTestGIT::NoteNewRevision()
+{
+ this->NewRevision = this->GetWorkingRevision();
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " New revision of repository is: " << this->NewRevision
+ << "\n");
+ return true;
+}
+
+std::string cmCTestGIT::FindGitDir()
+{
+ std::string git_dir;
+
+ // Run "git rev-parse --git-dir" to locate the real .git directory.
+ const char* git = this->CommandLineTool.c_str();
+ char const* git_rev_parse[] = { git, "rev-parse", "--git-dir", nullptr };
+ std::string git_dir_line;
+ OneLineParser rev_parse_out(this, "rev-parse-out> ", git_dir_line);
+ OutputLogger rev_parse_err(this->Log, "rev-parse-err> ");
+ if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, nullptr,
+ cmProcessOutput::UTF8)) {
+ git_dir = git_dir_line;
+ }
+ if (git_dir.empty()) {
+ git_dir = ".git";
+ }
+
+ // Git reports a relative path only when the .git directory is in
+ // the current directory.
+ if (git_dir[0] == '.') {
+ git_dir = this->SourceDirectory + "/" + git_dir;
+ }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ else if (git_dir[0] == '/') {
+ // Cygwin Git reports a full path that Cygwin understands, but we
+ // are a Windows application. Run "cygpath" to get Windows path.
+ std::string cygpath_exe =
+ cmStrCat(cmSystemTools::GetFilenamePath(git), "/cygpath.exe");
+ if (cmSystemTools::FileExists(cygpath_exe)) {
+ char const* cygpath[] = { cygpath_exe.c_str(), "-w", git_dir.c_str(),
+ 0 };
+ OneLineParser cygpath_out(this, "cygpath-out> ", git_dir_line);
+ OutputLogger cygpath_err(this->Log, "cygpath-err> ");
+ if (this->RunChild(cygpath, &cygpath_out, &cygpath_err, nullptr,
+ cmProcessOutput::UTF8)) {
+ git_dir = git_dir_line;
+ }
+ }
+ }
+#endif
+ return git_dir;
+}
+
+std::string cmCTestGIT::FindTopDir()
+{
+ std::string top_dir = this->SourceDirectory;
+
+ // Run "git rev-parse --show-cdup" to locate the top of the tree.
+ const char* git = this->CommandLineTool.c_str();
+ char const* git_rev_parse[] = { git, "rev-parse", "--show-cdup", nullptr };
+ std::string cdup;
+ OneLineParser rev_parse_out(this, "rev-parse-out> ", cdup);
+ OutputLogger rev_parse_err(this->Log, "rev-parse-err> ");
+ if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, nullptr,
+ cmProcessOutput::UTF8) &&
+ !cdup.empty()) {
+ top_dir += "/";
+ top_dir += cdup;
+ top_dir = cmSystemTools::CollapseFullPath(top_dir);
+ }
+ return top_dir;
+}
+
+bool cmCTestGIT::UpdateByFetchAndReset()
+{
+ const char* git = this->CommandLineTool.c_str();
+
+ // Use "git fetch" to get remote commits.
+ std::vector<char const*> git_fetch;
+ git_fetch.push_back(git);
+ git_fetch.push_back("fetch");
+
+ // Add user-specified update options.
+ std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
+ if (opts.empty()) {
+ opts = this->CTest->GetCTestConfiguration("GITUpdateOptions");
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
+ for (std::string const& arg : args) {
+ git_fetch.push_back(arg.c_str());
+ }
+
+ // Sentinel argument.
+ git_fetch.push_back(nullptr);
+
+ // Fetch upstream refs.
+ OutputLogger fetch_out(this->Log, "fetch-out> ");
+ OutputLogger fetch_err(this->Log, "fetch-err> ");
+ if (!this->RunUpdateCommand(&git_fetch[0], &fetch_out, &fetch_err)) {
+ return false;
+ }
+
+ // Identify the merge head that would be used by "git pull".
+ std::string sha1;
+ {
+ std::string fetch_head = this->FindGitDir() + "/FETCH_HEAD";
+ cmsys::ifstream fin(fetch_head.c_str(), std::ios::in | std::ios::binary);
+ if (!fin) {
+ this->Log << "Unable to open " << fetch_head << "\n";
+ return false;
+ }
+ std::string line;
+ while (sha1.empty() && cmSystemTools::GetLineFromStream(fin, line)) {
+ this->Log << "FETCH_HEAD> " << line << "\n";
+ if (line.find("\tnot-for-merge\t") == std::string::npos) {
+ std::string::size_type pos = line.find('\t');
+ if (pos != std::string::npos) {
+ sha1 = std::move(line);
+ sha1.resize(pos);
+ }
+ }
+ }
+ if (sha1.empty()) {
+ this->Log << "FETCH_HEAD has no upstream branch candidate!\n";
+ return false;
+ }
+ }
+
+ // Reset the local branch to point at that tracked from upstream.
+ char const* git_reset[] = { git, "reset", "--hard", sha1.c_str(), nullptr };
+ OutputLogger reset_out(this->Log, "reset-out> ");
+ OutputLogger reset_err(this->Log, "reset-err> ");
+ return this->RunChild(&git_reset[0], &reset_out, &reset_err);
+}
+
+bool cmCTestGIT::UpdateByCustom(std::string const& custom)
+{
+ std::vector<std::string> git_custom_command = cmExpandedList(custom, true);
+ std::vector<char const*> git_custom;
+ git_custom.reserve(git_custom_command.size() + 1);
+ for (std::string const& i : git_custom_command) {
+ git_custom.push_back(i.c_str());
+ }
+ git_custom.push_back(nullptr);
+
+ OutputLogger custom_out(this->Log, "custom-out> ");
+ OutputLogger custom_err(this->Log, "custom-err> ");
+ return this->RunUpdateCommand(&git_custom[0], &custom_out, &custom_err);
+}
+
+bool cmCTestGIT::UpdateInternal()
+{
+ std::string custom = this->CTest->GetCTestConfiguration("GITUpdateCustom");
+ if (!custom.empty()) {
+ return this->UpdateByCustom(custom);
+ }
+ return this->UpdateByFetchAndReset();
+}
+
+bool cmCTestGIT::UpdateImpl()
+{
+ if (!this->UpdateInternal()) {
+ return false;
+ }
+
+ std::string top_dir = this->FindTopDir();
+ const char* git = this->CommandLineTool.c_str();
+ const char* recursive = "--recursive";
+ const char* sync_recursive = "--recursive";
+
+ // Git < 1.6.5 did not support submodule --recursive
+ if (this->GetGitVersion() < cmCTestGITVersion(1, 6, 5, 0)) {
+ recursive = nullptr;
+ // No need to require >= 1.6.5 if there are no submodules.
+ if (cmSystemTools::FileExists(top_dir + "/.gitmodules")) {
+ this->Log << "Git < 1.6.5 cannot update submodules recursively\n";
+ }
+ }
+
+ // Git < 1.8.1 did not support sync --recursive
+ if (this->GetGitVersion() < cmCTestGITVersion(1, 8, 1, 0)) {
+ sync_recursive = nullptr;
+ // No need to require >= 1.8.1 if there are no submodules.
+ if (cmSystemTools::FileExists(top_dir + "/.gitmodules")) {
+ this->Log << "Git < 1.8.1 cannot synchronize submodules recursively\n";
+ }
+ }
+
+ OutputLogger submodule_out(this->Log, "submodule-out> ");
+ OutputLogger submodule_err(this->Log, "submodule-err> ");
+
+ bool ret;
+
+ std::string init_submodules =
+ this->CTest->GetCTestConfiguration("GITInitSubmodules");
+ if (cmIsOn(init_submodules)) {
+ char const* git_submodule_init[] = { git, "submodule", "init", nullptr };
+ ret = this->RunChild(git_submodule_init, &submodule_out, &submodule_err,
+ top_dir.c_str());
+
+ if (!ret) {
+ return false;
+ }
+ }
+
+ char const* git_submodule_sync[] = { git, "submodule", "sync",
+ sync_recursive, nullptr };
+ ret = this->RunChild(git_submodule_sync, &submodule_out, &submodule_err,
+ top_dir.c_str());
+
+ if (!ret) {
+ return false;
+ }
+
+ char const* git_submodule[] = { git, "submodule", "update", recursive,
+ nullptr };
+ return this->RunChild(git_submodule, &submodule_out, &submodule_err,
+ top_dir.c_str());
+}
+
+unsigned int cmCTestGIT::GetGitVersion()
+{
+ if (!this->CurrentGitVersion) {
+ const char* git = this->CommandLineTool.c_str();
+ char const* git_version[] = { git, "--version", nullptr };
+ std::string version;
+ OneLineParser version_out(this, "version-out> ", version);
+ OutputLogger version_err(this->Log, "version-err> ");
+ unsigned int v[4] = { 0, 0, 0, 0 };
+ if (this->RunChild(git_version, &version_out, &version_err) &&
+ sscanf(version.c_str(), "git version %u.%u.%u.%u", &v[0], &v[1], &v[2],
+ &v[3]) >= 3) {
+ this->CurrentGitVersion = cmCTestGITVersion(v[0], v[1], v[2], v[3]);
+ }
+ }
+ return this->CurrentGitVersion;
+}
+
+/* Diff format:
+
+ :src-mode dst-mode src-sha1 dst-sha1 status\0
+ src-path\0
+ [dst-path\0]
+
+ The format is repeated for every file changed. The [dst-path\0]
+ line appears only for lines with status 'C' or 'R'. See 'git help
+ diff-tree' for details.
+*/
+class cmCTestGIT::DiffParser : public cmCTestVC::LineParser
+{
+public:
+ DiffParser(cmCTestGIT* git, const char* prefix)
+ : LineParser('\0', false)
+ , GIT(git)
+ , DiffField(DiffFieldNone)
+ {
+ this->SetLog(&git->Log, prefix);
+ }
+
+ using Change = cmCTestGIT::Change;
+ std::vector<Change> Changes;
+
+protected:
+ cmCTestGIT* GIT;
+ enum DiffFieldType
+ {
+ DiffFieldNone,
+ DiffFieldChange,
+ DiffFieldSrc,
+ DiffFieldDst
+ };
+ DiffFieldType DiffField;
+ Change CurChange;
+
+ void DiffReset()
+ {
+ this->DiffField = DiffFieldNone;
+ this->Changes.clear();
+ }
+
+ bool ProcessLine() override
+ {
+ if (this->Line[0] == ':') {
+ this->DiffField = DiffFieldChange;
+ this->CurChange = Change();
+ }
+ if (this->DiffField == DiffFieldChange) {
+ // :src-mode dst-mode src-sha1 dst-sha1 status
+ if (this->Line[0] != ':') {
+ this->DiffField = DiffFieldNone;
+ return true;
+ }
+ const char* src_mode_first = this->Line.c_str() + 1;
+ const char* src_mode_last = this->ConsumeField(src_mode_first);
+ const char* dst_mode_first = this->ConsumeSpace(src_mode_last);
+ const char* dst_mode_last = this->ConsumeField(dst_mode_first);
+ const char* src_sha1_first = this->ConsumeSpace(dst_mode_last);
+ const char* src_sha1_last = this->ConsumeField(src_sha1_first);
+ const char* dst_sha1_first = this->ConsumeSpace(src_sha1_last);
+ const char* dst_sha1_last = this->ConsumeField(dst_sha1_first);
+ const char* status_first = this->ConsumeSpace(dst_sha1_last);
+ const char* status_last = this->ConsumeField(status_first);
+ if (status_first != status_last) {
+ this->CurChange.Action = *status_first;
+ this->DiffField = DiffFieldSrc;
+ } else {
+ this->DiffField = DiffFieldNone;
+ }
+ } else if (this->DiffField == DiffFieldSrc) {
+ // src-path
+ if (this->CurChange.Action == 'C') {
+ // Convert copy to addition of destination.
+ this->CurChange.Action = 'A';
+ this->DiffField = DiffFieldDst;
+ } else if (this->CurChange.Action == 'R') {
+ // Convert rename to deletion of source and addition of destination.
+ this->CurChange.Action = 'D';
+ this->CurChange.Path = this->Line;
+ this->Changes.push_back(this->CurChange);
+
+ this->CurChange = Change('A');
+ this->DiffField = DiffFieldDst;
+ } else {
+ this->CurChange.Path = this->Line;
+ this->Changes.push_back(this->CurChange);
+ this->DiffField = this->DiffFieldNone;
+ }
+ } else if (this->DiffField == DiffFieldDst) {
+ // dst-path
+ this->CurChange.Path = this->Line;
+ this->Changes.push_back(this->CurChange);
+ this->DiffField = this->DiffFieldNone;
+ }
+ return true;
+ }
+
+ const char* ConsumeSpace(const char* c)
+ {
+ while (*c && isspace(*c)) {
+ ++c;
+ }
+ return c;
+ }
+ const char* ConsumeField(const char* c)
+ {
+ while (*c && !isspace(*c)) {
+ ++c;
+ }
+ return c;
+ }
+};
+
+/* Commit format:
+
+ commit ...\n
+ tree ...\n
+ parent ...\n
+ author ...\n
+ committer ...\n
+ \n
+ Log message indented by (4) spaces\n
+ (even blank lines have the spaces)\n
+ [[
+ \n
+ [Diff format]
+ OR
+ \0
+ ]]
+
+ The header may have more fields. See 'git help diff-tree'.
+*/
+class cmCTestGIT::CommitParser : public cmCTestGIT::DiffParser
+{
+public:
+ CommitParser(cmCTestGIT* git, const char* prefix)
+ : DiffParser(git, prefix)
+ , Section(SectionHeader)
+ {
+ this->Separator = SectionSep[this->Section];
+ }
+
+private:
+ using Revision = cmCTestGIT::Revision;
+ enum SectionType
+ {
+ SectionHeader,
+ SectionBody,
+ SectionDiff,
+ SectionCount
+ };
+ static char const SectionSep[SectionCount];
+ SectionType Section;
+ Revision Rev;
+
+ struct Person
+ {
+ std::string Name;
+ std::string EMail;
+ unsigned long Time = 0;
+ long TimeZone = 0;
+ };
+
+ void ParsePerson(const char* str, Person& person)
+ {
+ // Person Name <person@domain.com> 1234567890 +0000
+ const char* c = str;
+ while (*c && isspace(*c)) {
+ ++c;
+ }
+
+ const char* name_first = c;
+ while (*c && *c != '<') {
+ ++c;
+ }
+ const char* name_last = c;
+ while (name_last != name_first && isspace(*(name_last - 1))) {
+ --name_last;
+ }
+ person.Name.assign(name_first, name_last - name_first);
+
+ const char* email_first = *c ? ++c : c;
+ while (*c && *c != '>') {
+ ++c;
+ }
+ const char* email_last = *c ? c++ : c;
+ person.EMail.assign(email_first, email_last - email_first);
+
+ person.Time = strtoul(c, const_cast<char**>(&c), 10);
+ person.TimeZone = strtol(c, const_cast<char**>(&c), 10);
+ }
+
+ bool ProcessLine() override
+ {
+ if (this->Line.empty()) {
+ if (this->Section == SectionBody && this->LineEnd == '\0') {
+ // Skip SectionDiff
+ this->NextSection();
+ }
+ this->NextSection();
+ } else {
+ switch (this->Section) {
+ case SectionHeader:
+ this->DoHeaderLine();
+ break;
+ case SectionBody:
+ this->DoBodyLine();
+ break;
+ case SectionDiff:
+ this->DiffParser::ProcessLine();
+ break;
+ case SectionCount:
+ break; // never happens
+ }
+ }
+ return true;
+ }
+
+ void NextSection()
+ {
+ this->Section = SectionType((this->Section + 1) % SectionCount);
+ this->Separator = SectionSep[this->Section];
+ if (this->Section == SectionHeader) {
+ this->GIT->DoRevision(this->Rev, this->Changes);
+ this->Rev = Revision();
+ this->DiffReset();
+ }
+ }
+
+ void DoHeaderLine()
+ {
+ // Look for header fields that we need.
+ if (cmHasLiteralPrefix(this->Line, "commit ")) {
+ this->Rev.Rev = this->Line.substr(7);
+ } else if (cmHasLiteralPrefix(this->Line, "author ")) {
+ Person author;
+ this->ParsePerson(this->Line.c_str() + 7, author);
+ this->Rev.Author = author.Name;
+ this->Rev.EMail = author.EMail;
+ this->Rev.Date = this->FormatDateTime(author);
+ } else if (cmHasLiteralPrefix(this->Line, "committer ")) {
+ Person committer;
+ this->ParsePerson(this->Line.c_str() + 10, committer);
+ this->Rev.Committer = committer.Name;
+ this->Rev.CommitterEMail = committer.EMail;
+ this->Rev.CommitDate = this->FormatDateTime(committer);
+ }
+ }
+
+ void DoBodyLine()
+ {
+ // Commit log lines are indented by 4 spaces.
+ if (this->Line.size() >= 4) {
+ this->Rev.Log += this->Line.substr(4);
+ }
+ this->Rev.Log += "\n";
+ }
+
+ std::string FormatDateTime(Person const& person)
+ {
+ // Convert the time to a human-readable format that is also easy
+ // to machine-parse: "CCYY-MM-DD hh:mm:ss".
+ time_t seconds = static_cast<time_t>(person.Time);
+ struct tm* t = gmtime(&seconds);
+ char dt[1024];
+ sprintf(dt, "%04d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900,
+ t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+ std::string out = dt;
+
+ // Add the time-zone field "+zone" or "-zone".
+ char tz[32];
+ if (person.TimeZone >= 0) {
+ sprintf(tz, " +%04ld", person.TimeZone);
+ } else {
+ sprintf(tz, " -%04ld", -person.TimeZone);
+ }
+ out += tz;
+ return out;
+ }
+};
+
+char const cmCTestGIT::CommitParser::SectionSep[SectionCount] = { '\n', '\n',
+ '\0' };
+
+bool cmCTestGIT::LoadRevisions()
+{
+ // Use 'git rev-list ... | git diff-tree ...' to get revisions.
+ std::string range = this->OldRevision + ".." + this->NewRevision;
+ const char* git = this->CommandLineTool.c_str();
+ const char* git_rev_list[] = { git, "rev-list", "--reverse",
+ range.c_str(), "--", nullptr };
+ const char* git_diff_tree[] = {
+ git, "diff-tree", "--stdin", "--always", "-z",
+ "-r", "--pretty=raw", "--encoding=utf-8", nullptr
+ };
+ this->Log << cmCTestGIT::ComputeCommandLine(git_rev_list) << " | "
+ << cmCTestGIT::ComputeCommandLine(git_diff_tree) << "\n";
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_AddCommand(cp, git_rev_list);
+ cmsysProcess_AddCommand(cp, git_diff_tree);
+ cmsysProcess_SetWorkingDirectory(cp, this->SourceDirectory.c_str());
+
+ CommitParser out(this, "dt-out> ");
+ OutputLogger err(this->Log, "dt-err> ");
+ cmCTestGIT::RunProcess(cp, &out, &err, cmProcessOutput::UTF8);
+
+ // Send one extra zero-byte to terminate the last record.
+ out.Process("", 1);
+
+ cmsysProcess_Delete(cp);
+ return true;
+}
+
+bool cmCTestGIT::LoadModifications()
+{
+ const char* git = this->CommandLineTool.c_str();
+
+ // Use 'git update-index' to refresh the index w.r.t. the work tree.
+ const char* git_update_index[] = { git, "update-index", "--refresh",
+ nullptr };
+ OutputLogger ui_out(this->Log, "ui-out> ");
+ OutputLogger ui_err(this->Log, "ui-err> ");
+ this->RunChild(git_update_index, &ui_out, &ui_err, nullptr,
+ cmProcessOutput::UTF8);
+
+ // Use 'git diff-index' to get modified files.
+ const char* git_diff_index[] = { git, "diff-index", "-z",
+ "HEAD", "--", nullptr };
+ DiffParser out(this, "di-out> ");
+ OutputLogger err(this->Log, "di-err> ");
+ this->RunChild(git_diff_index, &out, &err, nullptr, cmProcessOutput::UTF8);
+
+ for (Change const& c : out.Changes) {
+ this->DoModification(PathModified, c.Path);
+ }
+ return true;
+}
diff --git a/Source/CTest/cmCTestGIT.h b/Source/CTest/cmCTestGIT.h
new file mode 100644
index 0000000..a15aef5
--- /dev/null
+++ b/Source/CTest/cmCTestGIT.h
@@ -0,0 +1,54 @@
+/* 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 <iosfwd>
+#include <string>
+
+#include "cmCTestGlobalVC.h"
+
+class cmCTest;
+
+/** \class cmCTestGIT
+ * \brief Interaction with git command-line tool
+ *
+ */
+class cmCTestGIT : public cmCTestGlobalVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestGIT(cmCTest* ctest, std::ostream& log);
+
+ ~cmCTestGIT() override;
+
+private:
+ unsigned int CurrentGitVersion;
+ unsigned int GetGitVersion();
+ std::string GetWorkingRevision();
+ bool NoteOldRevision() override;
+ bool NoteNewRevision() override;
+ bool UpdateImpl() override;
+
+ std::string FindGitDir();
+ std::string FindTopDir();
+
+ bool UpdateByFetchAndReset();
+ bool UpdateByCustom(std::string const& custom);
+ bool UpdateInternal();
+
+ bool LoadRevisions() override;
+ bool LoadModifications() override;
+
+ // "public" needed by older Sun compilers
+public:
+ // Parsing helper classes.
+ class CommitParser;
+ class DiffParser;
+ class OneLineParser;
+
+ friend class CommitParser;
+ friend class DiffParser;
+ friend class OneLineParser;
+};
diff --git a/Source/CTest/cmCTestGenericHandler.cxx b/Source/CTest/cmCTestGenericHandler.cxx
new file mode 100644
index 0000000..cc756d7
--- /dev/null
+++ b/Source/CTest/cmCTestGenericHandler.cxx
@@ -0,0 +1,160 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestGenericHandler.h"
+
+#include <sstream>
+#include <utility>
+
+#include "cmCTest.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmCTestGenericHandler::cmCTestGenericHandler()
+{
+ this->HandlerVerbose = cmSystemTools::OUTPUT_NONE;
+ this->CTest = nullptr;
+ this->SubmitIndex = 0;
+ this->AppendXML = false;
+ this->Quiet = false;
+ this->TestLoad = 0;
+}
+
+cmCTestGenericHandler::~cmCTestGenericHandler() = default;
+
+/* Modify the given `map`, setting key `op` to `value` if `value`
+ * is non-null, otherwise removing key `op` (if it exists).
+ */
+static void SetMapValue(cmCTestGenericHandler::t_StringToString& map,
+ const std::string& op, const char* value)
+{
+ if (!value) {
+ map.erase(op);
+ return;
+ }
+
+ map[op] = value;
+}
+
+void cmCTestGenericHandler::SetOption(const std::string& op, const char* value)
+{
+ SetMapValue(this->Options, op, value);
+}
+
+void cmCTestGenericHandler::SetPersistentOption(const std::string& op,
+ const char* value)
+{
+ this->SetOption(op, value);
+ SetMapValue(this->PersistentOptions, op, value);
+}
+
+void cmCTestGenericHandler::AddMultiOption(const std::string& op,
+ const std::string& value)
+{
+ if (!value.empty()) {
+ this->MultiOptions[op].emplace_back(value);
+ }
+}
+
+void cmCTestGenericHandler::AddPersistentMultiOption(const std::string& op,
+ const std::string& value)
+{
+ if (!value.empty()) {
+ this->MultiOptions[op].emplace_back(value);
+ this->PersistentMultiOptions[op].emplace_back(value);
+ }
+}
+
+void cmCTestGenericHandler::Initialize()
+{
+ this->AppendXML = false;
+ this->TestLoad = 0;
+ this->Options.clear();
+ for (auto const& po : this->PersistentOptions) {
+ this->Options[po.first] = po.second;
+ }
+}
+
+const char* cmCTestGenericHandler::GetOption(const std::string& op)
+{
+ auto remit = this->Options.find(op);
+ if (remit == this->Options.end()) {
+ return nullptr;
+ }
+ return remit->second.c_str();
+}
+
+std::vector<std::string> cmCTestGenericHandler::GetMultiOption(
+ const std::string& optionName) const
+{
+ // Avoid inserting a key, which MultiOptions[op] would do.
+ auto remit = this->MultiOptions.find(optionName);
+ if (remit == this->MultiOptions.end()) {
+ return {};
+ }
+ return remit->second;
+}
+
+bool cmCTestGenericHandler::StartResultingXML(cmCTest::Part part,
+ const char* name,
+ cmGeneratedFileStream& xofs)
+{
+ if (!name) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create resulting XML file without providing the name"
+ << std::endl;);
+ return false;
+ }
+ std::ostringstream ostr;
+ ostr << name;
+ if (this->SubmitIndex > 0) {
+ ostr << "_" << this->SubmitIndex;
+ }
+ ostr << ".xml";
+ if (this->CTest->GetCurrentTag().empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Current Tag empty, this may mean NightlyStartTime / "
+ "CTEST_NIGHTLY_START_TIME was not set correctly. Or "
+ "maybe you forgot to call ctest_start() before calling "
+ "ctest_configure()."
+ << std::endl);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ if (!this->CTest->OpenOutputFile(this->CTest->GetCurrentTag(), ostr.str(),
+ xofs, true)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create resulting XML file: " << ostr.str()
+ << std::endl);
+ return false;
+ }
+ this->CTest->AddSubmitFile(part, ostr.str());
+ return true;
+}
+
+bool cmCTestGenericHandler::StartLogFile(const char* name,
+ cmGeneratedFileStream& xofs)
+{
+ if (!name) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create log file without providing the name"
+ << std::endl;);
+ return false;
+ }
+ std::ostringstream ostr;
+ ostr << "Last" << name;
+ if (this->SubmitIndex > 0) {
+ ostr << "_" << this->SubmitIndex;
+ }
+ if (!this->CTest->GetCurrentTag().empty()) {
+ 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);
+ return false;
+ }
+ return true;
+}
diff --git a/Source/CTest/cmCTestGenericHandler.h b/Source/CTest/cmCTestGenericHandler.h
new file mode 100644
index 0000000..6f44545
--- /dev/null
+++ b/Source/CTest/cmCTestGenericHandler.h
@@ -0,0 +1,139 @@
+/* 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 <map>
+#include <string>
+#include <vector>
+
+#include <stddef.h>
+
+#include "cmCTest.h"
+#include "cmSystemTools.h"
+
+class cmCTestCommand;
+class cmGeneratedFileStream;
+class cmMakefile;
+
+/** \class cmCTestGenericHandler
+ * \brief A superclass of all CTest Handlers
+ *
+ */
+class cmCTestGenericHandler
+{
+public:
+ /**
+ * If verbose then more information is printed out
+ */
+ void SetVerbose(bool val)
+ {
+ this->HandlerVerbose =
+ val ? cmSystemTools::OUTPUT_MERGE : cmSystemTools::OUTPUT_NONE;
+ }
+
+ /**
+ * Populate internals from CTest custom scripts
+ */
+ virtual void PopulateCustomVectors(cmMakefile*) {}
+
+ /**
+ * Do the actual processing. Subclass has to override it.
+ * Return < 0 if error.
+ */
+ virtual int ProcessHandler() = 0;
+
+ /**
+ * Process command line arguments that are applicable for the handler
+ */
+ virtual int ProcessCommandLineArguments(
+ const std::string& /*currentArg*/, size_t& /*idx*/,
+ const std::vector<std::string>& /*allArgs*/)
+ {
+ return 1;
+ }
+
+ /**
+ * Initialize handler
+ */
+ virtual void Initialize();
+
+ /**
+ * Set the CTest instance
+ */
+ void SetCTestInstance(cmCTest* ctest) { this->CTest = ctest; }
+ cmCTest* GetCTestInstance() { return this->CTest; }
+
+ /**
+ * Construct handler
+ */
+ cmCTestGenericHandler();
+ virtual ~cmCTestGenericHandler();
+
+ using t_StringToString = std::map<std::string, std::string>;
+ using t_StringToMultiString =
+ std::map<std::string, std::vector<std::string>>;
+
+ /**
+ * Options collect a single value from flags; passing the
+ * flag multiple times on the command-line *overwrites* values,
+ * and only the last one specified counts. Set an option to
+ * nullptr to "unset" it.
+ *
+ * The value is stored as a string. The values set for single
+ * and multi-options (see below) live in different spaces,
+ * so calling a single-getter for a key that has only been set
+ * as a multi-value will return nullptr.
+ */
+ void SetPersistentOption(const std::string& op, const char* value);
+ void SetOption(const std::string& op, const char* value);
+ const char* GetOption(const std::string& op);
+
+ /**
+ * Multi-Options collect one or more values from flags; passing
+ * the flag multiple times on the command-line *adds* values,
+ * rather than overwriting the previous values.
+ *
+ * Adding an empty value does nothing.
+ *
+ * The value is stored as a vector of strings. The values set for single
+ * (see above) and multi-options live in different spaces,
+ * so calling a multi-getter for a key that has only been set
+ * as a single-value will return an empty vector.
+ */
+ void AddPersistentMultiOption(const std::string& optionName,
+ const std::string& value);
+ void AddMultiOption(const std::string& optionName, const std::string& value);
+ std::vector<std::string> GetMultiOption(const std::string& op) const;
+
+ void SetCommand(cmCTestCommand* command) { this->Command = command; }
+
+ void SetSubmitIndex(int idx) { this->SubmitIndex = idx; }
+ int GetSubmitIndex() { return this->SubmitIndex; }
+
+ void SetAppendXML(bool b) { this->AppendXML = b; }
+ void SetQuiet(bool b) { this->Quiet = b; }
+ bool GetQuiet() { return this->Quiet; }
+ void SetTestLoad(unsigned long load) { this->TestLoad = load; }
+ unsigned long GetTestLoad() const { return this->TestLoad; }
+
+protected:
+ bool StartResultingXML(cmCTest::Part part, const char* name,
+ cmGeneratedFileStream& xofs);
+ bool StartLogFile(const char* name, cmGeneratedFileStream& xofs);
+
+ bool AppendXML;
+ bool Quiet;
+ unsigned long TestLoad;
+ cmSystemTools::OutputOption HandlerVerbose;
+ cmCTest* CTest;
+ t_StringToString Options;
+ t_StringToString PersistentOptions;
+ t_StringToMultiString MultiOptions;
+ t_StringToMultiString PersistentMultiOptions;
+ t_StringToString LogFileNames;
+
+ cmCTestCommand* Command;
+ int SubmitIndex;
+};
diff --git a/Source/CTest/cmCTestGlobalVC.cxx b/Source/CTest/cmCTestGlobalVC.cxx
new file mode 100644
index 0000000..5f05efb
--- /dev/null
+++ b/Source/CTest/cmCTestGlobalVC.cxx
@@ -0,0 +1,124 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestGlobalVC.h"
+
+#include <ostream>
+#include <utility>
+
+#include "cmCTest.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+
+cmCTestGlobalVC::cmCTestGlobalVC(cmCTest* ct, std::ostream& log)
+ : cmCTestVC(ct, log)
+{
+ this->PriorRev = this->Unknown;
+}
+
+cmCTestGlobalVC::~cmCTestGlobalVC() = default;
+
+const char* cmCTestGlobalVC::LocalPath(std::string const& path)
+{
+ return path.c_str();
+}
+
+void cmCTestGlobalVC::DoRevision(Revision const& revision,
+ std::vector<Change> const& changes)
+{
+ // Ignore changes in the old revision.
+ if (revision.Rev == this->OldRevision) {
+ this->PriorRev = revision;
+ return;
+ }
+
+ // Indicate we found a revision.
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
+
+ // Store the revision.
+ this->Revisions.push_back(revision);
+
+ // Report this revision.
+ Revision const& rev = this->Revisions.back();
+ /* clang-format off */
+ this->Log << "Found revision " << rev.Rev << "\n"
+ << " author = " << rev.Author << "\n"
+ << " date = " << rev.Date << "\n";
+ /* clang-format on */
+
+ // Update information about revisions of the changed files.
+ for (Change const& c : changes) {
+ if (const char* local = this->LocalPath(c.Path)) {
+ std::string dir = cmSystemTools::GetFilenamePath(local);
+ std::string name = cmSystemTools::GetFilenameName(local);
+ File& file = this->Dirs[dir][name];
+ file.PriorRev = file.Rev ? file.Rev : &this->PriorRev;
+ file.Rev = &rev;
+ this->Log << " " << c.Action << " " << local << " "
+ << "\n";
+ }
+ }
+}
+
+void cmCTestGlobalVC::DoModification(PathStatus status,
+ std::string const& path)
+{
+ std::string dir = cmSystemTools::GetFilenamePath(path);
+ std::string name = cmSystemTools::GetFilenameName(path);
+ File& file = this->Dirs[dir][name];
+ file.Status = status;
+ // For local modifications the current rev is unknown and the
+ // prior rev is the latest from svn.
+ if (!file.Rev && !file.PriorRev) {
+ file.PriorRev = &this->PriorRev;
+ }
+}
+
+void cmCTestGlobalVC::WriteXMLDirectory(cmXMLWriter& xml,
+ std::string const& path,
+ Directory const& dir)
+{
+ const char* slash = path.empty() ? "" : "/";
+ xml.StartElement("Directory");
+ xml.Element("Name", path);
+ for (auto const& f : dir) {
+ std::string const full = path + slash + f.first;
+ this->WriteXMLEntry(xml, path, f.first, full, f.second);
+ }
+ xml.EndElement(); // Directory
+}
+
+void cmCTestGlobalVC::WriteXMLGlobal(cmXMLWriter& xml)
+{
+ if (!this->NewRevision.empty()) {
+ xml.Element("Revision", this->NewRevision);
+ }
+ if (!this->OldRevision.empty() && this->OldRevision != this->NewRevision) {
+ xml.Element("PriorRevision", this->OldRevision);
+ }
+}
+
+bool cmCTestGlobalVC::WriteXMLUpdates(cmXMLWriter& xml)
+{
+ bool result = true;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Gathering version information (one . per revision):\n"
+ " "
+ << std::flush);
+ result = this->LoadRevisions() && result;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
+
+ result = this->LoadModifications() && result;
+
+ this->WriteXMLGlobal(xml);
+
+ for (auto const& d : this->Dirs) {
+ this->WriteXMLDirectory(xml, d.first, d.second);
+ }
+
+ return result;
+}
+
+void cmCTestGlobalVC::SetNewRevision(std::string const& revision)
+{
+ this->NewRevision = revision;
+}
diff --git a/Source/CTest/cmCTestGlobalVC.h b/Source/CTest/cmCTestGlobalVC.h
new file mode 100644
index 0000000..679b0e1
--- /dev/null
+++ b/Source/CTest/cmCTestGlobalVC.h
@@ -0,0 +1,74 @@
+/* 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 <iosfwd>
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "cmCTestVC.h"
+
+class cmCTest;
+class cmXMLWriter;
+
+/** \class cmCTestGlobalVC
+ * \brief Base class for handling globally-versioned trees
+ *
+ */
+class cmCTestGlobalVC : public cmCTestVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestGlobalVC(cmCTest* ctest, std::ostream& log);
+
+ ~cmCTestGlobalVC() override;
+
+protected:
+ // Implement cmCTestVC internal API.
+ bool WriteXMLUpdates(cmXMLWriter& xml) override;
+
+ void SetNewRevision(std::string const& revision) override;
+
+ /** Represent a vcs-reported action for one path in a revision. */
+ struct Change
+ {
+ char Action;
+ std::string Path;
+ Change(char a = '?')
+ : Action(a)
+ {
+ }
+ };
+
+ // Update status for files in each directory.
+ class Directory : public std::map<std::string, File>
+ {
+ };
+ std::map<std::string, Directory> Dirs;
+
+ // Old and new repository revisions.
+ std::string OldRevision;
+ std::string NewRevision;
+
+ // Information known about old revision.
+ Revision PriorRev;
+
+ // Information about revisions from a svn log.
+ std::list<Revision> Revisions;
+
+ virtual const char* LocalPath(std::string const& path);
+
+ virtual void DoRevision(Revision const& revision,
+ std::vector<Change> const& changes);
+ virtual void DoModification(PathStatus status, std::string const& path);
+ virtual bool LoadModifications() = 0;
+ virtual bool LoadRevisions() = 0;
+
+ virtual void WriteXMLGlobal(cmXMLWriter& xml);
+ void WriteXMLDirectory(cmXMLWriter& xml, std::string const& path,
+ Directory const& dir);
+};
diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx
new file mode 100644
index 0000000..5f4581e
--- /dev/null
+++ b/Source/CTest/cmCTestHG.cxx
@@ -0,0 +1,315 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestHG.h"
+
+#include <ostream>
+#include <vector>
+
+#include <cmext/algorithm>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCTest.h"
+#include "cmCTestVC.h"
+#include "cmProcessTools.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+
+cmCTestHG::cmCTestHG(cmCTest* ct, std::ostream& log)
+ : cmCTestGlobalVC(ct, log)
+{
+ this->PriorRev = this->Unknown;
+}
+
+cmCTestHG::~cmCTestHG() = default;
+
+class cmCTestHG::IdentifyParser : public cmCTestVC::LineParser
+{
+public:
+ IdentifyParser(cmCTestHG* hg, const char* prefix, std::string& rev)
+ : Rev(rev)
+ {
+ this->SetLog(&hg->Log, prefix);
+ this->RegexIdentify.compile("^([0-9a-f]+)");
+ }
+
+private:
+ std::string& Rev;
+ cmsys::RegularExpression RegexIdentify;
+
+ bool ProcessLine() override
+ {
+ if (this->RegexIdentify.find(this->Line)) {
+ this->Rev = this->RegexIdentify.match(1);
+ return false;
+ }
+ return true;
+ }
+};
+
+class cmCTestHG::StatusParser : public cmCTestVC::LineParser
+{
+public:
+ StatusParser(cmCTestHG* hg, const char* prefix)
+ : HG(hg)
+ {
+ this->SetLog(&hg->Log, prefix);
+ this->RegexStatus.compile("([MARC!?I]) (.*)");
+ }
+
+private:
+ cmCTestHG* HG;
+ cmsys::RegularExpression RegexStatus;
+
+ bool ProcessLine() override
+ {
+ if (this->RegexStatus.find(this->Line)) {
+ this->DoPath(this->RegexStatus.match(1)[0], this->RegexStatus.match(2));
+ }
+ return true;
+ }
+
+ void DoPath(char status, std::string const& path)
+ {
+ if (path.empty()) {
+ return;
+ }
+
+ // See "hg help status". Note that there is no 'conflict' status.
+ switch (status) {
+ case 'M':
+ case 'A':
+ case '!':
+ case 'R':
+ this->HG->DoModification(PathModified, path);
+ break;
+ case 'I':
+ case '?':
+ case 'C':
+ case ' ':
+ default:
+ break;
+ }
+ }
+};
+
+std::string cmCTestHG::GetWorkingRevision()
+{
+ // Run plumbing "hg identify" to get work tree revision.
+ const char* hg = this->CommandLineTool.c_str();
+ const char* hg_identify[] = { hg, "identify", "-i", nullptr };
+ std::string rev;
+ IdentifyParser out(this, "rev-out> ", rev);
+ OutputLogger err(this->Log, "rev-err> ");
+ this->RunChild(hg_identify, &out, &err);
+ return rev;
+}
+
+bool cmCTestHG::NoteOldRevision()
+{
+ this->OldRevision = this->GetWorkingRevision();
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Old revision of repository is: " << this->OldRevision
+ << "\n");
+ this->PriorRev.Rev = this->OldRevision;
+ return true;
+}
+
+bool cmCTestHG::NoteNewRevision()
+{
+ this->NewRevision = this->GetWorkingRevision();
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " New revision of repository is: " << this->NewRevision
+ << "\n");
+ return true;
+}
+
+bool cmCTestHG::UpdateImpl()
+{
+ // Use "hg pull" followed by "hg update" to update the working tree.
+ {
+ const char* hg = this->CommandLineTool.c_str();
+ const char* hg_pull[] = { hg, "pull", "-v", nullptr };
+ OutputLogger out(this->Log, "pull-out> ");
+ OutputLogger err(this->Log, "pull-err> ");
+ this->RunChild(&hg_pull[0], &out, &err);
+ }
+
+ // TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
+
+ std::vector<char const*> hg_update;
+ hg_update.push_back(this->CommandLineTool.c_str());
+ hg_update.push_back("update");
+ hg_update.push_back("-v");
+
+ // Add user-specified update options.
+ std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
+ if (opts.empty()) {
+ opts = this->CTest->GetCTestConfiguration("HGUpdateOptions");
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
+ for (std::string const& arg : args) {
+ hg_update.push_back(arg.c_str());
+ }
+
+ // Sentinel argument.
+ hg_update.push_back(nullptr);
+
+ OutputLogger out(this->Log, "update-out> ");
+ OutputLogger err(this->Log, "update-err> ");
+ return this->RunUpdateCommand(&hg_update[0], &out, &err);
+}
+
+class cmCTestHG::LogParser
+ : public cmCTestVC::OutputLogger
+ , private cmXMLParser
+{
+public:
+ LogParser(cmCTestHG* hg, const char* prefix)
+ : OutputLogger(hg->Log, prefix)
+ , HG(hg)
+ {
+ this->InitializeParser();
+ }
+ ~LogParser() override { this->CleanupParser(); }
+
+private:
+ cmCTestHG* HG;
+
+ using Revision = cmCTestHG::Revision;
+ using Change = cmCTestHG::Change;
+ Revision Rev;
+ std::vector<Change> Changes;
+ Change CurChange;
+ std::vector<char> CData;
+
+ bool ProcessChunk(const char* data, int length) override
+ {
+ this->OutputLogger::ProcessChunk(data, length);
+ this->ParseChunk(data, length);
+ return true;
+ }
+
+ void StartElement(const std::string& name, const char** atts) override
+ {
+ this->CData.clear();
+ if (name == "logentry") {
+ this->Rev = Revision();
+ if (const char* rev =
+ cmCTestHG::LogParser::FindAttribute(atts, "revision")) {
+ this->Rev.Rev = rev;
+ }
+ this->Changes.clear();
+ }
+ }
+
+ void CharacterDataHandler(const char* data, int length) override
+ {
+ cm::append(this->CData, data, data + length);
+ }
+
+ void EndElement(const std::string& name) override
+ {
+ if (name == "logentry") {
+ this->HG->DoRevision(this->Rev, this->Changes);
+ } else if (!this->CData.empty() && name == "author") {
+ this->Rev.Author.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "email") {
+ this->Rev.EMail.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "date") {
+ this->Rev.Date.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "msg") {
+ this->Rev.Log.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "files") {
+ std::vector<std::string> paths = this->SplitCData();
+ for (std::string const& path : paths) {
+ // Updated by default, will be modified using file_adds and
+ // file_dels.
+ this->CurChange = Change('U');
+ this->CurChange.Path = path;
+ this->Changes.push_back(this->CurChange);
+ }
+ } else if (!this->CData.empty() && name == "file_adds") {
+ std::string added_paths(this->CData.begin(), this->CData.end());
+ for (Change& change : this->Changes) {
+ if (added_paths.find(change.Path) != std::string::npos) {
+ change.Action = 'A';
+ }
+ }
+ } else if (!this->CData.empty() && name == "file_dels") {
+ std::string added_paths(this->CData.begin(), this->CData.end());
+ for (Change& change : this->Changes) {
+ if (added_paths.find(change.Path) != std::string::npos) {
+ change.Action = 'D';
+ }
+ }
+ }
+ this->CData.clear();
+ }
+
+ std::vector<std::string> SplitCData()
+ {
+ std::vector<std::string> output;
+ std::string currPath;
+ for (char i : this->CData) {
+ if (i != ' ') {
+ currPath += i;
+ } else {
+ output.push_back(currPath);
+ currPath.clear();
+ }
+ }
+ output.push_back(currPath);
+ return output;
+ }
+
+ void ReportError(int /*line*/, int /*column*/, const char* msg) override
+ {
+ this->HG->Log << "Error parsing hg log xml: " << msg << "\n";
+ }
+};
+
+bool cmCTestHG::LoadRevisions()
+{
+ // Use 'hg log' to get revisions in a xml format.
+ //
+ // TODO: This should use plumbing or python code to be more precise.
+ // The "list of strings" templates like {files} will not work when
+ // the project has spaces in the path. Also, they may not have
+ // proper XML escapes.
+ std::string range = this->OldRevision + ":" + this->NewRevision;
+ const char* hg = this->CommandLineTool.c_str();
+ const char* hgXMLTemplate = "<logentry\n"
+ " revision=\"{node|short}\">\n"
+ " <author>{author|person}</author>\n"
+ " <email>{author|email}</email>\n"
+ " <date>{date|isodate}</date>\n"
+ " <msg>{desc}</msg>\n"
+ " <files>{files}</files>\n"
+ " <file_adds>{file_adds}</file_adds>\n"
+ " <file_dels>{file_dels}</file_dels>\n"
+ "</logentry>\n";
+ const char* hg_log[] = {
+ hg, "log", "--removed", "-r", range.c_str(),
+ "--template", hgXMLTemplate, nullptr
+ };
+
+ LogParser out(this, "log-out> ");
+ out.Process("<?xml version=\"1.0\"?>\n"
+ "<log>\n");
+ OutputLogger err(this->Log, "log-err> ");
+ this->RunChild(hg_log, &out, &err);
+ out.Process("</log>\n");
+ return true;
+}
+
+bool cmCTestHG::LoadModifications()
+{
+ // Use 'hg status' to get modified files.
+ const char* hg = this->CommandLineTool.c_str();
+ const char* hg_status[] = { hg, "status", nullptr };
+ StatusParser out(this, "status-out> ");
+ OutputLogger err(this->Log, "status-err> ");
+ this->RunChild(hg_status, &out, &err);
+ return true;
+}
diff --git a/Source/CTest/cmCTestHG.h b/Source/CTest/cmCTestHG.h
new file mode 100644
index 0000000..b81f042
--- /dev/null
+++ b/Source/CTest/cmCTestHG.h
@@ -0,0 +1,43 @@
+/* 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 <iosfwd>
+#include <string>
+
+#include "cmCTestGlobalVC.h"
+
+class cmCTest;
+
+/** \class cmCTestHG
+ * \brief Interaction with Mercurial command-line tool
+ *
+ */
+class cmCTestHG : public cmCTestGlobalVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestHG(cmCTest* ctest, std::ostream& log);
+
+ ~cmCTestHG() override;
+
+private:
+ std::string GetWorkingRevision();
+ bool NoteOldRevision() override;
+ bool NoteNewRevision() override;
+ bool UpdateImpl() override;
+
+ bool LoadRevisions() override;
+ bool LoadModifications() override;
+
+ // Parsing helper classes.
+ class IdentifyParser;
+ class LogParser;
+ class StatusParser;
+
+ friend class IdentifyParser;
+ friend class LogParser;
+ friend class StatusParser;
+};
diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx
new file mode 100644
index 0000000..731932e
--- /dev/null
+++ b/Source/CTest/cmCTestHandlerCommand.cxx
@@ -0,0 +1,247 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestHandlerCommand.h"
+
+#include <algorithm>
+#include <cstdlib>
+#include <cstring>
+#include <sstream>
+
+#include <cmext/string_view>
+
+#include "cmCTest.h"
+#include "cmCTestGenericHandler.h"
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmWorkingDirectory.h"
+
+namespace {
+// class to save and restore the error state for ctest_* commands
+// if a ctest_* command has a CAPTURE_CMAKE_ERROR then put the error
+// state into there and restore the system wide error to what
+// it was before the command ran
+class SaveRestoreErrorState
+{
+public:
+ SaveRestoreErrorState()
+ {
+ this->InitialErrorState = cmSystemTools::GetErrorOccuredFlag();
+ cmSystemTools::ResetErrorOccuredFlag(); // rest the error state
+ this->CaptureCMakeErrorValue = false;
+ }
+ // if the function has a CAPTURE_CMAKE_ERROR then we should restore
+ // the error state to what it was before the function was run
+ // if not then let the error state be what it is
+ void CaptureCMakeError() { this->CaptureCMakeErrorValue = true; }
+ ~SaveRestoreErrorState()
+ {
+ // if we are not saving the return value then make sure
+ // if it was in error it goes back to being in error
+ // otherwise leave it be what it is
+ if (!this->CaptureCMakeErrorValue) {
+ if (this->InitialErrorState) {
+ cmSystemTools::SetErrorOccured();
+ }
+ return;
+ }
+ // if we have saved the error in a return variable
+ // then put things back exactly like they were
+ bool currentState = cmSystemTools::GetErrorOccuredFlag();
+ // if the state changed during this command we need
+ // to handle it, if not then nothing needs to be done
+ if (currentState != this->InitialErrorState) {
+ // restore the initial error state
+ if (this->InitialErrorState) {
+ cmSystemTools::SetErrorOccured();
+ } else {
+ cmSystemTools::ResetErrorOccuredFlag();
+ }
+ }
+ }
+ SaveRestoreErrorState(const SaveRestoreErrorState&) = delete;
+ SaveRestoreErrorState& operator=(const SaveRestoreErrorState&) = delete;
+
+private:
+ bool InitialErrorState;
+ bool CaptureCMakeErrorValue;
+};
+}
+
+bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // save error state and restore it if needed
+ SaveRestoreErrorState errorState;
+ // Allocate space for argument values.
+ this->BindArguments();
+
+ // Process input arguments.
+ std::vector<std::string> unparsedArguments;
+ std::vector<std::string> keywordsMissingValue;
+ std::vector<std::string> parsedKeywords;
+ this->Parse(args, &unparsedArguments, &keywordsMissingValue,
+ &parsedKeywords);
+ this->CheckArguments(keywordsMissingValue);
+
+ std::sort(parsedKeywords.begin(), parsedKeywords.end());
+ auto it = std::adjacent_find(parsedKeywords.begin(), parsedKeywords.end());
+ if (it != parsedKeywords.end()) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Called with more than one value for ", *it));
+ }
+
+ bool const foundBadArgument = !unparsedArguments.empty();
+ if (foundBadArgument) {
+ this->SetError(cmStrCat("called with unknown argument \"",
+ unparsedArguments.front(), "\"."));
+ }
+ bool const captureCMakeError = !this->CaptureCMakeError.empty();
+ // now that arguments are parsed check to see if there is a
+ // CAPTURE_CMAKE_ERROR specified let the errorState object know.
+ if (captureCMakeError) {
+ errorState.CaptureCMakeError();
+ }
+ // if we found a bad argument then exit before running command
+ if (foundBadArgument) {
+ // store the cmake error
+ if (captureCMakeError) {
+ this->Makefile->AddDefinition(this->CaptureCMakeError, "-1");
+ std::string const err = this->GetName() + " " + status.GetError();
+ if (!cmSystemTools::FindLastString(err.c_str(), "unknown error.")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, err << " error from command\n");
+ }
+ // return success because failure is recorded in CAPTURE_CMAKE_ERROR
+ return true;
+ }
+ // return failure because of bad argument
+ return false;
+ }
+
+ // Set the config type of this ctest to the current value of the
+ // CTEST_CONFIGURATION_TYPE script variable if it is defined.
+ // The current script value trumps the -C argument on the command
+ // line.
+ cmProp ctestConfigType =
+ this->Makefile->GetDefinition("CTEST_CONFIGURATION_TYPE");
+ if (ctestConfigType) {
+ this->CTest->SetConfigType(*ctestConfigType);
+ }
+
+ if (!this->Build.empty()) {
+ this->CTest->SetCTestConfiguration(
+ "BuildDirectory", cmSystemTools::CollapseFullPath(this->Build),
+ this->Quiet);
+ } else {
+ std::string const& bdir =
+ this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY");
+ if (!bdir.empty()) {
+ this->CTest->SetCTestConfiguration(
+ "BuildDirectory", cmSystemTools::CollapseFullPath(bdir), this->Quiet);
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "CTEST_BINARY_DIRECTORY not set" << std::endl;);
+ }
+ }
+ if (!this->Source.empty()) {
+ cmCTestLog(this->CTest, DEBUG,
+ "Set source directory to: " << this->Source << std::endl);
+ this->CTest->SetCTestConfiguration(
+ "SourceDirectory", cmSystemTools::CollapseFullPath(this->Source),
+ this->Quiet);
+ } else {
+ this->CTest->SetCTestConfiguration(
+ "SourceDirectory",
+ cmSystemTools::CollapseFullPath(
+ this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY")),
+ this->Quiet);
+ }
+
+ if (cmProp changeId = this->Makefile->GetDefinition("CTEST_CHANGE_ID")) {
+ this->CTest->SetCTestConfiguration("ChangeId", *changeId, this->Quiet);
+ }
+
+ cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl;);
+ cmCTestGenericHandler* handler = this->InitializeHandler();
+ if (!handler) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot instantiate test handler " << this->GetName()
+ << std::endl);
+ if (captureCMakeError) {
+ this->Makefile->AddDefinition(this->CaptureCMakeError, "-1");
+ std::string const& err = status.GetError();
+ if (!cmSystemTools::FindLastString(err.c_str(), "unknown error.")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, err << " error from command\n");
+ }
+ return true;
+ }
+ return false;
+ }
+
+ handler->SetAppendXML(this->Append);
+
+ handler->PopulateCustomVectors(this->Makefile);
+ if (!this->SubmitIndex.empty()) {
+ handler->SetSubmitIndex(atoi(this->SubmitIndex.c_str()));
+ }
+ cmWorkingDirectory workdir(
+ this->CTest->GetCTestConfiguration("BuildDirectory"));
+ if (workdir.Failed()) {
+ this->SetError("failed to change directory to " +
+ this->CTest->GetCTestConfiguration("BuildDirectory") +
+ " : " + std::strerror(workdir.GetLastResult()));
+ if (captureCMakeError) {
+ this->Makefile->AddDefinition(this->CaptureCMakeError, "-1");
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ this->GetName() << " " << status.GetError() << "\n");
+ // return success because failure is recorded in CAPTURE_CMAKE_ERROR
+ return true;
+ }
+ return false;
+ }
+
+ int res = handler->ProcessHandler();
+ if (!this->ReturnValue.empty()) {
+ this->Makefile->AddDefinition(this->ReturnValue, std::to_string(res));
+ }
+ this->ProcessAdditionalValues(handler);
+ // log the error message if there was an error
+ if (captureCMakeError) {
+ const char* returnString = "0";
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ returnString = "-1";
+ std::string const& err = status.GetError();
+ // print out the error if it is not "unknown error" which means
+ // there was no message
+ if (!cmSystemTools::FindLastString(err.c_str(), "unknown error.")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, err);
+ }
+ }
+ // store the captured cmake error state 0 or -1
+ this->Makefile->AddDefinition(this->CaptureCMakeError, returnString);
+ }
+ return true;
+}
+
+void cmCTestHandlerCommand::ProcessAdditionalValues(cmCTestGenericHandler*)
+{
+}
+
+void cmCTestHandlerCommand::BindArguments()
+{
+ this->Bind("APPEND"_s, this->Append);
+ this->Bind("QUIET"_s, this->Quiet);
+ this->Bind("RETURN_VALUE"_s, this->ReturnValue);
+ this->Bind("CAPTURE_CMAKE_ERROR"_s, this->CaptureCMakeError);
+ this->Bind("SOURCE"_s, this->Source);
+ this->Bind("BUILD"_s, this->Build);
+ this->Bind("SUBMIT_INDEX"_s, this->SubmitIndex);
+}
+
+void cmCTestHandlerCommand::CheckArguments(std::vector<std::string> const&)
+{
+}
diff --git a/Source/CTest/cmCTestHandlerCommand.h b/Source/CTest/cmCTestHandlerCommand.h
new file mode 100644
index 0000000..756952d
--- /dev/null
+++ b/Source/CTest/cmCTestHandlerCommand.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 "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+#include "cmArgumentParser.h"
+#include "cmCTestCommand.h"
+
+class cmCTestGenericHandler;
+class cmExecutionStatus;
+
+/** \class cmCTestHandler
+ * \brief Run a ctest script
+ *
+ * cmCTestHandlerCommand defineds the command to test the project.
+ */
+class cmCTestHandlerCommand
+ : public cmCTestCommand
+ , public cmArgumentParser<void>
+{
+public:
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ virtual std::string GetName() const = 0;
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) override;
+
+protected:
+ virtual cmCTestGenericHandler* InitializeHandler() = 0;
+
+ virtual void ProcessAdditionalValues(cmCTestGenericHandler* handler);
+
+ // Command argument handling.
+ virtual void BindArguments();
+ virtual void CheckArguments(std::vector<std::string> const& keywords);
+
+ bool Append = false;
+ bool Quiet = false;
+ std::string CaptureCMakeError;
+ std::string ReturnValue;
+ std::string Build;
+ std::string Source;
+ std::string SubmitIndex;
+};
+
+#define CTEST_COMMAND_APPEND_OPTION_DOCS \
+ "The APPEND option marks results for append to those previously " \
+ "submitted to a dashboard server since the last ctest_start. " \
+ "Append semantics are defined by the dashboard server in use."
diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
new file mode 100644
index 0000000..15c443a
--- /dev/null
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -0,0 +1,328 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestLaunch.h"
+
+#include <cstring>
+#include <iostream>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Process.h"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCTestLaunchReporter.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProcessOutput.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#ifdef _WIN32
+# include <fcntl.h> // for _O_BINARY
+# include <io.h> // for _setmode
+# include <stdio.h> // for std{out,err} and fileno
+#endif
+
+cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
+{
+ this->Process = nullptr;
+
+ if (!this->ParseArguments(argc, argv)) {
+ return;
+ }
+
+ this->Reporter.RealArgs = this->RealArgs;
+ this->Reporter.ComputeFileNames();
+
+ this->ScrapeRulesLoaded = false;
+ this->HaveOut = false;
+ this->HaveErr = false;
+ this->Process = cmsysProcess_New();
+}
+
+cmCTestLaunch::~cmCTestLaunch()
+{
+ cmsysProcess_Delete(this->Process);
+}
+
+bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
+{
+ // Launcher options occur first and are separated from the real
+ // command line by a '--' option.
+ enum Doing
+ {
+ DoingNone,
+ DoingOutput,
+ DoingSource,
+ DoingLanguage,
+ DoingTargetName,
+ DoingTargetType,
+ DoingBuildDir,
+ DoingCount,
+ DoingFilterPrefix
+ };
+ Doing doing = DoingNone;
+ int arg0 = 0;
+ for (int i = 1; !arg0 && i < argc; ++i) {
+ const char* arg = argv[i];
+ if (strcmp(arg, "--") == 0) {
+ arg0 = i + 1;
+ } else if (strcmp(arg, "--output") == 0) {
+ doing = DoingOutput;
+ } else if (strcmp(arg, "--source") == 0) {
+ doing = DoingSource;
+ } else if (strcmp(arg, "--language") == 0) {
+ doing = DoingLanguage;
+ } else if (strcmp(arg, "--target-name") == 0) {
+ doing = DoingTargetName;
+ } else if (strcmp(arg, "--target-type") == 0) {
+ doing = DoingTargetType;
+ } else if (strcmp(arg, "--build-dir") == 0) {
+ doing = DoingBuildDir;
+ } else if (strcmp(arg, "--filter-prefix") == 0) {
+ doing = DoingFilterPrefix;
+ } else if (doing == DoingOutput) {
+ this->Reporter.OptionOutput = arg;
+ doing = DoingNone;
+ } else if (doing == DoingSource) {
+ this->Reporter.OptionSource = arg;
+ doing = DoingNone;
+ } else if (doing == DoingLanguage) {
+ this->Reporter.OptionLanguage = arg;
+ if (this->Reporter.OptionLanguage == "CXX") {
+ this->Reporter.OptionLanguage = "C++";
+ }
+ doing = DoingNone;
+ } else if (doing == DoingTargetName) {
+ this->Reporter.OptionTargetName = arg;
+ doing = DoingNone;
+ } else if (doing == DoingTargetType) {
+ this->Reporter.OptionTargetType = arg;
+ doing = DoingNone;
+ } else if (doing == DoingBuildDir) {
+ this->Reporter.OptionBuildDir = arg;
+ doing = DoingNone;
+ } else if (doing == DoingFilterPrefix) {
+ this->Reporter.OptionFilterPrefix = arg;
+ doing = DoingNone;
+ }
+ }
+
+ // Extract the real command line.
+ if (arg0) {
+ this->RealArgC = argc - arg0;
+ this->RealArgV = argv + arg0;
+ for (int i = 0; i < this->RealArgC; ++i) {
+ this->HandleRealArg(this->RealArgV[i]);
+ }
+ return true;
+ }
+ this->RealArgC = 0;
+ this->RealArgV = nullptr;
+ std::cerr << "No launch/command separator ('--') found!\n";
+ return false;
+}
+
+void cmCTestLaunch::HandleRealArg(const char* arg)
+{
+#ifdef _WIN32
+ // Expand response file arguments.
+ if (arg[0] == '@' && cmSystemTools::FileExists(arg + 1)) {
+ cmsys::ifstream fin(arg + 1);
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ cmSystemTools::ParseWindowsCommandLine(line.c_str(), this->RealArgs);
+ }
+ return;
+ }
+#endif
+ this->RealArgs.emplace_back(arg);
+}
+
+void cmCTestLaunch::RunChild()
+{
+ // Ignore noopt make rules
+ if (this->RealArgs.empty() || this->RealArgs[0] == ":") {
+ this->Reporter.ExitCode = 0;
+ return;
+ }
+
+ // Prepare to run the real command.
+ cmsysProcess* cp = this->Process;
+ cmsysProcess_SetCommand(cp, this->RealArgV);
+
+ cmsys::ofstream fout;
+ cmsys::ofstream ferr;
+ if (this->Reporter.Passthru) {
+ // In passthru mode we just share the output pipes.
+ 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->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
+ // Do this so that newline transformation is not done when writing to cout
+ // and cerr below.
+ _setmode(fileno(stdout), _O_BINARY);
+ _setmode(fileno(stderr), _O_BINARY);
+#endif
+
+ // Run the real command.
+ cmsysProcess_Execute(cp);
+
+ // Record child stdout and stderr if necessary.
+ if (!this->Reporter.Passthru) {
+ char* data = nullptr;
+ int length = 0;
+ cmProcessOutput processOutput;
+ std::string strdata;
+ while (int p = cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
+ if (p == cmsysProcess_Pipe_STDOUT) {
+ processOutput.DecodeText(data, length, strdata, 1);
+ fout.write(strdata.c_str(), strdata.size());
+ std::cout.write(strdata.c_str(), strdata.size());
+ this->HaveOut = true;
+ } else if (p == cmsysProcess_Pipe_STDERR) {
+ processOutput.DecodeText(data, length, strdata, 2);
+ ferr.write(strdata.c_str(), strdata.size());
+ std::cerr.write(strdata.c_str(), strdata.size());
+ this->HaveErr = true;
+ }
+ }
+ processOutput.DecodeText(std::string(), strdata, 1);
+ if (!strdata.empty()) {
+ fout.write(strdata.c_str(), strdata.size());
+ std::cout.write(strdata.c_str(), strdata.size());
+ }
+ processOutput.DecodeText(std::string(), strdata, 2);
+ if (!strdata.empty()) {
+ ferr.write(strdata.c_str(), strdata.size());
+ std::cerr.write(strdata.c_str(), strdata.size());
+ }
+ }
+
+ // Wait for the real command to finish.
+ cmsysProcess_WaitForExit(cp, nullptr);
+ this->Reporter.ExitCode = cmsysProcess_GetExitValue(cp);
+}
+
+int cmCTestLaunch::Run()
+{
+ if (!this->Process) {
+ std::cerr << "Could not allocate cmsysProcess instance!\n";
+ return -1;
+ }
+
+ this->RunChild();
+
+ if (this->CheckResults()) {
+ return this->Reporter.ExitCode;
+ }
+
+ this->LoadConfig();
+ this->Reporter.Process = this->Process;
+ this->Reporter.WriteXML();
+
+ return this->Reporter.ExitCode;
+}
+
+bool cmCTestLaunch::CheckResults()
+{
+ // Skip XML in passthru mode.
+ if (this->Reporter.Passthru) {
+ return true;
+ }
+
+ // We always report failure for error conditions.
+ if (this->Reporter.IsError()) {
+ return false;
+ }
+
+ // Scrape the output logs to look for warnings.
+ if ((this->HaveErr && this->ScrapeLog(this->Reporter.LogErr)) ||
+ (this->HaveOut && this->ScrapeLog(this->Reporter.LogOut))) {
+ return false;
+ }
+ return true;
+}
+
+void cmCTestLaunch::LoadScrapeRules()
+{
+ if (this->ScrapeRulesLoaded) {
+ return;
+ }
+ this->ScrapeRulesLoaded = true;
+
+ // Load custom match rules given to us by CTest.
+ this->LoadScrapeRules("Warning", this->Reporter.RegexWarning);
+ this->LoadScrapeRules("WarningSuppress",
+ this->Reporter.RegexWarningSuppress);
+}
+
+void cmCTestLaunch::LoadScrapeRules(
+ const char* purpose, std::vector<cmsys::RegularExpression>& regexps) const
+{
+ 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;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (rex.compile(line)) {
+ regexps.push_back(rex);
+ }
+ }
+}
+
+bool cmCTestLaunch::ScrapeLog(std::string const& fname)
+{
+ this->LoadScrapeRules();
+
+ // Look for log file lines matching warning expressions but not
+ // suppression expressions.
+ cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (this->Reporter.MatchesFilterPrefix(line)) {
+ continue;
+ }
+
+ if (this->Reporter.Match(line, this->Reporter.RegexWarning) &&
+ !this->Reporter.Match(line, this->Reporter.RegexWarningSuppress)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+int cmCTestLaunch::Main(int argc, const char* const argv[])
+{
+ if (argc == 2) {
+ std::cerr << "ctest --launch: this mode is for internal CTest use only"
+ << std::endl;
+ return 1;
+ }
+ cmCTestLaunch self(argc, argv);
+ return self.Run();
+}
+
+void cmCTestLaunch::LoadConfig()
+{
+ cmake cm(cmake::RoleScript, cmState::CTest);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator gg(&cm);
+ cmMakefile mf(&gg, cm.GetCurrentSnapshot());
+ std::string fname =
+ cmStrCat(this->Reporter.LogDir, "CTestLaunchConfig.cmake");
+ if (cmSystemTools::FileExists(fname) && mf.ReadListFile(fname)) {
+ 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
new file mode 100644
index 0000000..eabb608
--- /dev/null
+++ b/Source/CTest/cmCTestLaunch.h
@@ -0,0 +1,71 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmCTestLaunchReporter.h"
+
+namespace cmsys {
+class RegularExpression;
+}
+
+/** \class cmCTestLaunch
+ * \brief Launcher for make rules to report results for ctest
+ *
+ * This implements the 'ctest --launch' tool.
+ */
+class cmCTestLaunch
+{
+public:
+ /** Entry point from ctest executable main(). */
+ static int Main(int argc, const char* const argv[]);
+
+private:
+ // Initialize the launcher from its command line.
+ cmCTestLaunch(int argc, const char* const* argv);
+ ~cmCTestLaunch();
+
+ cmCTestLaunch(const cmCTestLaunch&) = delete;
+ cmCTestLaunch& operator=(const cmCTestLaunch&) = delete;
+
+ // Run the real command.
+ int Run();
+ void RunChild();
+
+ // Method to check the result of the real command.
+ bool CheckResults();
+
+ // 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;
+
+ // The real command line after response file expansion.
+ std::vector<std::string> RealArgs;
+ void HandleRealArg(const char* arg);
+
+ struct cmsysProcess_s* Process;
+
+ // Whether or not any data have been written to stdout or stderr.
+ bool HaveOut;
+ bool HaveErr;
+
+ // Load custom rules to match warnings and their exceptions.
+ bool ScrapeRulesLoaded;
+ void LoadScrapeRules();
+ void LoadScrapeRules(const char* purpose,
+ std::vector<cmsys::RegularExpression>& regexps) const;
+ bool ScrapeLog(std::string const& fname);
+
+ // Helper class to generate the xml fragment.
+ cmCTestLaunchReporter Reporter;
+
+ // Configuration
+ void LoadConfig();
+};
diff --git a/Source/CTest/cmCTestLaunchReporter.cxx b/Source/CTest/cmCTestLaunchReporter.cxx
new file mode 100644
index 0000000..5334a93
--- /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) const
+{
+ 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 (this->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..4be0d9b
--- /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&) const;
+ 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/CTest/cmCTestMemCheckCommand.cxx b/Source/CTest/cmCTestMemCheckCommand.cxx
new file mode 100644
index 0000000..d0e2974
--- /dev/null
+++ b/Source/CTest/cmCTestMemCheckCommand.cxx
@@ -0,0 +1,50 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestMemCheckCommand.h"
+
+#include <cmext/string_view>
+
+#include "cmCTest.h"
+#include "cmCTestMemCheckHandler.h"
+#include "cmMakefile.h"
+
+void cmCTestMemCheckCommand::BindArguments()
+{
+ this->cmCTestTestCommand::BindArguments();
+ this->Bind("DEFECT_COUNT"_s, this->DefectCount);
+}
+
+cmCTestGenericHandler* cmCTestMemCheckCommand::InitializeActualHandler()
+{
+ cmCTestMemCheckHandler* handler = this->CTest->GetMemCheckHandler();
+ handler->Initialize();
+
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckType", "CTEST_MEMORYCHECK_TYPE", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckSanitizerOptions",
+ "CTEST_MEMORYCHECK_SANITIZER_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckCommand", "CTEST_MEMORYCHECK_COMMAND",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckCommandOptions",
+ "CTEST_MEMORYCHECK_COMMAND_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckSuppressionFile",
+ "CTEST_MEMORYCHECK_SUPPRESSIONS_FILE", this->Quiet);
+
+ handler->SetQuiet(this->Quiet);
+ return handler;
+}
+
+void cmCTestMemCheckCommand::ProcessAdditionalValues(
+ cmCTestGenericHandler* handler)
+{
+ if (!this->DefectCount.empty()) {
+ this->Makefile->AddDefinition(
+ this->DefectCount,
+ std::to_string(
+ static_cast<cmCTestMemCheckHandler*>(handler)->GetDefectCount()));
+ }
+}
diff --git a/Source/CTest/cmCTestMemCheckCommand.h b/Source/CTest/cmCTestMemCheckCommand.h
new file mode 100644
index 0000000..6544f16
--- /dev/null
+++ b/Source/CTest/cmCTestMemCheckCommand.h
@@ -0,0 +1,44 @@
+/* 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 <string>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmCTestTestCommand.h"
+#include "cmCommand.h"
+
+class cmCTestGenericHandler;
+
+/** \class cmCTestMemCheck
+ * \brief Run a ctest script
+ *
+ * cmCTestMemCheckCommand defineds the command to test the project.
+ */
+class cmCTestMemCheckCommand : public cmCTestTestCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ auto ni = cm::make_unique<cmCTestMemCheckCommand>();
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return std::unique_ptr<cmCommand>(std::move(ni));
+ }
+
+protected:
+ void BindArguments() override;
+
+ cmCTestGenericHandler* InitializeActualHandler() override;
+
+ void ProcessAdditionalValues(cmCTestGenericHandler* handler) override;
+
+ std::string DefectCount;
+};
diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx
new file mode 100644
index 0000000..125d003
--- /dev/null
+++ b/Source/CTest/cmCTestMemCheckHandler.cxx
@@ -0,0 +1,1404 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestMemCheckHandler.h"
+
+#include <algorithm>
+#include <chrono>
+#include <cstring>
+#include <iostream>
+#include <iterator>
+#include <sstream>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCTest.h"
+#include "cmDuration.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include "cmXMLWriter.h"
+
+struct CatToErrorType
+{
+ const char* ErrorCategory;
+ int ErrorCode;
+};
+
+static CatToErrorType cmCTestMemCheckBoundsChecker[] = {
+ // Error tags
+ { "Write Overrun", cmCTestMemCheckHandler::ABW },
+ { "Read Overrun", cmCTestMemCheckHandler::ABR },
+ { "Memory Overrun", cmCTestMemCheckHandler::ABW },
+ { "Allocation Conflict", cmCTestMemCheckHandler::FMM },
+ { "Bad Pointer Use", cmCTestMemCheckHandler::FMW },
+ { "Dangling Pointer", cmCTestMemCheckHandler::FMR },
+ { nullptr, 0 }
+};
+
+static void xmlReportError(int line, const char* msg, void* data)
+{
+ cmCTest* ctest = static_cast<cmCTest*>(data);
+ cmCTestLog(ctest, ERROR_MESSAGE,
+ "Error parsing XML in stream at line " << line << ": " << msg
+ << std::endl);
+}
+
+// parse the xml file containing the results of last BoundsChecker run
+class cmBoundsCheckerParser : public cmXMLParser
+{
+public:
+ cmBoundsCheckerParser(cmCTest* c)
+ {
+ this->CTest = c;
+ this->SetErrorCallback(xmlReportError, c);
+ }
+ void StartElement(const std::string& name, const char** atts) override
+ {
+ if (name == "MemoryLeak" || name == "ResourceLeak") {
+ this->Errors.push_back(cmCTestMemCheckHandler::MLK);
+ } else if (name == "Error" || name == "Dangling Pointer") {
+ this->ParseError(atts);
+ }
+ // Create the log
+ std::ostringstream ostr;
+ ostr << name << ":\n";
+ int i = 0;
+ for (; atts[i] != nullptr; i += 2) {
+ ostr << " " << atts[i] << " - " << atts[i + 1] << "\n";
+ }
+ ostr << "\n";
+ this->Log += ostr.str();
+ }
+ void EndElement(const std::string& /*name*/) override {}
+
+ const char* GetAttribute(const char* name, const char** atts)
+ {
+ int i = 0;
+ for (; atts[i] != nullptr; ++i) {
+ if (strcmp(name, atts[i]) == 0) {
+ return atts[i + 1];
+ }
+ }
+ return nullptr;
+ }
+ void ParseError(const char** atts)
+ {
+ CatToErrorType* ptr = cmCTestMemCheckBoundsChecker;
+ const char* cat = this->GetAttribute("ErrorCategory", atts);
+ if (!cat) {
+ this->Errors.push_back(cmCTestMemCheckHandler::ABW); // do not know
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "No Category found in Bounds checker XML\n");
+ return;
+ }
+ while (ptr->ErrorCategory && cat) {
+ if (strcmp(ptr->ErrorCategory, cat) == 0) {
+ this->Errors.push_back(ptr->ErrorCode);
+ return; // found it we are done
+ }
+ ptr++;
+ }
+ if (ptr->ErrorCategory) {
+ this->Errors.push_back(cmCTestMemCheckHandler::ABW); // do not know
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Found unknown Bounds Checker error " << ptr->ErrorCategory
+ << std::endl);
+ }
+ }
+ cmCTest* CTest;
+ std::vector<int> Errors;
+ std::string Log;
+};
+
+#define BOUNDS_CHECKER_MARKER \
+ "******######*****Begin BOUNDS CHECKER XML******######******"
+
+cmCTestMemCheckHandler::cmCTestMemCheckHandler()
+{
+ this->MemCheck = true;
+ this->CustomMaximumPassedTestOutputSize = 0;
+ this->CustomMaximumFailedTestOutputSize = 0;
+ this->LogWithPID = false;
+}
+
+void cmCTestMemCheckHandler::Initialize()
+{
+ this->Superclass::Initialize();
+ this->LogWithPID = false;
+ this->CustomMaximumPassedTestOutputSize = 0;
+ this->CustomMaximumFailedTestOutputSize = 0;
+ this->MemoryTester.clear();
+ this->MemoryTesterDynamicOptions.clear();
+ this->MemoryTesterOptions.clear();
+ this->MemoryTesterStyle = UNKNOWN;
+ this->MemoryTesterOutputFile.clear();
+ this->DefectCount = 0;
+}
+
+int cmCTestMemCheckHandler::PreProcessHandler()
+{
+ if (!this->InitializeMemoryChecking()) {
+ return 0;
+ }
+
+ if (!this->ExecuteCommands(this->CustomPreMemCheck)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem executing pre-memcheck command(s)." << std::endl);
+ return 0;
+ }
+ return 1;
+}
+
+int cmCTestMemCheckHandler::PostProcessHandler()
+{
+ if (!this->ExecuteCommands(this->CustomPostMemCheck)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem executing post-memcheck command(s)." << std::endl);
+ return 0;
+ }
+ return 1;
+}
+
+void cmCTestMemCheckHandler::GenerateTestCommand(
+ std::vector<std::string>& args, int test)
+{
+ std::string index = std::to_string(test);
+ std::string memcheckcommand =
+ cmSystemTools::ConvertToOutputPath(this->MemoryTester);
+
+ std::vector<std::string> dirs;
+ bool nextArgIsDir = false;
+
+ for (std::string arg : this->MemoryTesterDynamicOptions) {
+ std::string::size_type pos = arg.find("??");
+ if (pos != std::string::npos) {
+ arg.replace(pos, 2, index);
+ }
+ args.push_back(arg);
+ memcheckcommand += " \"";
+ memcheckcommand += arg;
+ memcheckcommand += "\"";
+
+ if (nextArgIsDir) {
+ nextArgIsDir = false;
+ dirs.push_back(arg);
+ }
+
+ if (this->MemoryTesterStyle == cmCTestMemCheckHandler::DRMEMORY &&
+ (arg == "-logdir" || arg == "-symcache_dir")) {
+ nextArgIsDir = true;
+ }
+ }
+ // Create a copy of the memory tester environment variable.
+ // This is used for memory testing programs that pass options
+ // via environment variables.
+ std::string memTesterEnvironmentVariable =
+ this->MemoryTesterEnvironmentVariable;
+ for (std::string const& arg : this->MemoryTesterOptions) {
+ if (!memTesterEnvironmentVariable.empty()) {
+ // If we are using env to pass options, append all the options to
+ // this string with space separation.
+ memTesterEnvironmentVariable += " " + arg;
+ }
+ // for regular options just add them to args and memcheckcommand
+ // which is just used for display
+ else {
+ args.push_back(arg);
+ memcheckcommand += " \"";
+ memcheckcommand += arg;
+ memcheckcommand += "\"";
+ }
+ }
+ // if this is an env option type, then add the env string as a single
+ // argument.
+ if (!memTesterEnvironmentVariable.empty()) {
+ std::string::size_type pos = memTesterEnvironmentVariable.find("??");
+ if (pos != std::string::npos) {
+ memTesterEnvironmentVariable.replace(pos, 2, index);
+ }
+ memcheckcommand += " " + memTesterEnvironmentVariable;
+ args.push_back(memTesterEnvironmentVariable);
+ }
+
+ for (std::string const& dir : dirs) {
+ cmSystemTools::MakeDirectory(dir);
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Memory check command: " << memcheckcommand << std::endl,
+ this->Quiet);
+}
+
+void cmCTestMemCheckHandler::InitializeResultsVectors()
+{
+ // fill these members
+ // cmsys::vector<std::string> ResultStrings;
+ // cmsys::vector<std::string> ResultStringsLong;
+ // cmsys::vector<int> GlobalResults;
+ this->ResultStringsLong.clear();
+ this->ResultStrings.clear();
+ this->GlobalResults.clear();
+ // If we are working with style checkers that dynamically fill
+ // the results strings then return.
+ if (this->MemoryTesterStyle > cmCTestMemCheckHandler::BOUNDS_CHECKER) {
+ return;
+ }
+
+ // define the standard set of errors
+ //----------------------------------------------------------------------
+ static const char* cmCTestMemCheckResultStrings[] = {
+ "ABR", "ABW", "ABWL", "COR", "EXU", "FFM", "FIM", "FMM",
+ "FMR", "FMW", "FUM", "IPR", "IPW", "MAF", "MLK", "MPK",
+ "NPR", "ODS", "PAR", "PLK", "UMC", "UMR", nullptr
+ };
+ static const char* cmCTestMemCheckResultLongStrings[] = {
+ "Threading Problem",
+ "ABW",
+ "ABWL",
+ "COR",
+ "EXU",
+ "FFM",
+ "FIM",
+ "Mismatched deallocation",
+ "FMR",
+ "FMW",
+ "FUM",
+ "IPR",
+ "IPW",
+ "MAF",
+ "Memory Leak",
+ "Potential Memory Leak",
+ "NPR",
+ "ODS",
+ "Invalid syscall param",
+ "PLK",
+ "Uninitialized Memory Conditional",
+ "Uninitialized Memory Read",
+ nullptr
+ };
+ this->GlobalResults.clear();
+ for (int i = 0; cmCTestMemCheckResultStrings[i] != nullptr; ++i) {
+ this->ResultStrings.emplace_back(cmCTestMemCheckResultStrings[i]);
+ this->ResultStringsLong.emplace_back(cmCTestMemCheckResultLongStrings[i]);
+ this->GlobalResults.push_back(0);
+ }
+}
+
+void cmCTestMemCheckHandler::PopulateCustomVectors(cmMakefile* mf)
+{
+ this->cmCTestTestHandler::PopulateCustomVectors(mf);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_PRE_MEMCHECK",
+ this->CustomPreMemCheck);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_POST_MEMCHECK",
+ this->CustomPostMemCheck);
+
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_MEMCHECK_IGNORE",
+ this->CustomTestsIgnore);
+}
+
+int cmCTestMemCheckHandler::GetDefectCount() const
+{
+ return this->DefectCount;
+}
+
+void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml)
+{
+ if (!this->CTest->GetProduceXML()) {
+ return;
+ }
+ this->CTest->StartXML(xml, this->AppendXML);
+ this->CTest->GenerateSubprojectsOutput(xml);
+ xml.StartElement("DynamicAnalysis");
+ switch (this->MemoryTesterStyle) {
+ case cmCTestMemCheckHandler::VALGRIND:
+ xml.Attribute("Checker", "Valgrind");
+ break;
+ case cmCTestMemCheckHandler::DRMEMORY:
+ xml.Attribute("Checker", "DrMemory");
+ break;
+ case cmCTestMemCheckHandler::PURIFY:
+ xml.Attribute("Checker", "Purify");
+ break;
+ case cmCTestMemCheckHandler::BOUNDS_CHECKER:
+ xml.Attribute("Checker", "BoundsChecker");
+ break;
+ case cmCTestMemCheckHandler::CUDA_SANITIZER:
+ xml.Attribute("Checker", "CudaSanitizer");
+ break;
+ case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
+ xml.Attribute("Checker", "AddressSanitizer");
+ break;
+ case cmCTestMemCheckHandler::LEAK_SANITIZER:
+ xml.Attribute("Checker", "LeakSanitizer");
+ break;
+ case cmCTestMemCheckHandler::THREAD_SANITIZER:
+ xml.Attribute("Checker", "ThreadSanitizer");
+ break;
+ case cmCTestMemCheckHandler::MEMORY_SANITIZER:
+ xml.Attribute("Checker", "MemorySanitizer");
+ break;
+ case cmCTestMemCheckHandler::UB_SANITIZER:
+ xml.Attribute("Checker", "UndefinedBehaviorSanitizer");
+ break;
+ default:
+ xml.Attribute("Checker", "Unknown");
+ }
+
+ xml.Element("StartDateTime", this->StartTest);
+ xml.Element("StartTestTime", this->StartTestTime);
+ xml.StartElement("TestList");
+ cmCTestMemCheckHandler::TestResultsVector::size_type cc;
+ for (cmCTestTestResult const& result : this->TestResults) {
+ std::string testPath = result.Path + "/" + result.Name;
+ xml.Element("Test", this->CTest->GetShortPathToFile(testPath));
+ }
+ xml.EndElement(); // TestList
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "-- Processing memory checking output:\n", this->Quiet);
+ size_t total = this->TestResults.size();
+ for (cc = 0; cc < this->TestResults.size(); cc++) {
+ cmCTestTestResult const& result = this->TestResults[cc];
+ std::string memcheckstr;
+ std::vector<int> memcheckresults(this->ResultStrings.size(), 0);
+ bool res =
+ this->ProcessMemCheckOutput(result.Output, memcheckstr, memcheckresults);
+ if (res && result.Status == cmCTestMemCheckHandler::COMPLETED) {
+ continue;
+ }
+ this->CleanTestOutput(
+ memcheckstr,
+ static_cast<size_t>(this->CustomMaximumFailedTestOutputSize));
+ this->WriteTestResultHeader(xml, result);
+ xml.StartElement("Results");
+ int memoryErrors = 0;
+ for (std::vector<int>::size_type kk = 0; kk < memcheckresults.size();
+ ++kk) {
+ if (memcheckresults[kk]) {
+ xml.StartElement("Defect");
+ xml.Attribute("type", this->ResultStringsLong[kk]);
+ xml.Content(memcheckresults[kk]);
+ memoryErrors += memcheckresults[kk];
+ xml.EndElement(); // Defect
+ }
+ this->GlobalResults[kk] += memcheckresults[kk];
+ }
+ xml.EndElement(); // Results
+ if (memoryErrors > 0) {
+ const int maxTestNameWidth = this->CTest->GetMaxTestNameWidth();
+ std::string outname = result.Name + " ";
+ outname.resize(maxTestNameWidth + 4, '.');
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ cc + 1 << "/" << total << " MemCheck: #"
+ << result.TestCount << ": " << outname
+ << " Defects: " << memoryErrors << std::endl,
+ this->Quiet);
+ }
+ xml.StartElement("Log");
+ if (this->CTest->ShouldCompressTestOutput()) {
+ this->CTest->CompressString(memcheckstr);
+ xml.Attribute("compression", "gzip");
+ xml.Attribute("encoding", "base64");
+ }
+ xml.Content(memcheckstr);
+ xml.EndElement(); // Log
+
+ this->WriteTestResultFooter(xml, result);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "MemCheck log files can be found here: "
+ "(<#> corresponds to test number)"
+ << std::endl,
+ this->Quiet);
+ std::string output = this->MemoryTesterOutputFile;
+ cmSystemTools::ReplaceString(output, "??", "<#>");
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, output << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "Memory checking results:" << std::endl, this->Quiet);
+ xml.StartElement("DefectList");
+ for (cc = 0; cc < this->GlobalResults.size(); cc++) {
+ if (this->GlobalResults[cc]) {
+ std::cerr.width(35);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ this->ResultStringsLong[cc]
+ << " - " << this->GlobalResults[cc] << std::endl,
+ this->Quiet);
+ xml.StartElement("Defect");
+ xml.Attribute("Type", this->ResultStringsLong[cc]);
+ xml.EndElement();
+ }
+ }
+ xml.EndElement(); // DefectList
+
+ xml.Element("EndDateTime", this->EndTest);
+ xml.Element("EndTestTime", this->EndTestTime);
+ xml.Element(
+ "ElapsedMinutes",
+ std::chrono::duration_cast<std::chrono::minutes>(this->ElapsedTestingTime)
+ .count());
+
+ xml.EndElement(); // DynamicAnalysis
+ this->CTest->EndXML(xml);
+}
+
+bool cmCTestMemCheckHandler::InitializeMemoryChecking()
+{
+ this->MemoryTesterEnvironmentVariable.clear();
+ this->MemoryTester.clear();
+ // Setup the command
+ if (cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("MemoryCheckCommand"))) {
+ this->MemoryTester =
+ this->CTest->GetCTestConfiguration("MemoryCheckCommand");
+ std::string testerName =
+ cmSystemTools::GetFilenameName(this->MemoryTester);
+ // determine the checker type
+ if (testerName.find("valgrind") != std::string::npos ||
+ this->CTest->GetCTestConfiguration("MemoryCheckType") == "Valgrind") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
+ } else if (testerName.find("drmemory") != std::string::npos ||
+ this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "DrMemory") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::DRMEMORY;
+ } else if (testerName.find("purify") != std::string::npos) {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
+ } else if (testerName.find("BC") != std::string::npos) {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
+ } else if (testerName.find("cuda-memcheck") != std::string::npos ||
+ testerName.find("compute-sanitizer") != std::string::npos) {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::CUDA_SANITIZER;
+ } else {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::UNKNOWN;
+ }
+ } else if (cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("PurifyCommand"))) {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("PurifyCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
+ } else if (cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("ValgrindCommand"))) {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("ValgrindCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
+ } else if (cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("DrMemoryCommand"))) {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("DrMemoryCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::DRMEMORY;
+ } else if (cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("BoundsCheckerCommand"))) {
+ this->MemoryTester =
+ this->CTest->GetCTestConfiguration("BoundsCheckerCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
+ } else if (cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("CudaSanitizerCommand"))) {
+ this->MemoryTester =
+ this->CTest->GetCTestConfiguration("CudaSanitizerCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::CUDA_SANITIZER;
+ }
+ if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "AddressSanitizer") {
+ this->MemoryTester = cmSystemTools::GetCMakeCommand();
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::ADDRESS_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "LeakSanitizer") {
+ this->MemoryTester = cmSystemTools::GetCMakeCommand();
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::LEAK_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "ThreadSanitizer") {
+ this->MemoryTester = cmSystemTools::GetCMakeCommand();
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::THREAD_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "MemorySanitizer") {
+ this->MemoryTester = cmSystemTools::GetCMakeCommand();
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::MEMORY_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "UndefinedBehaviorSanitizer") {
+ this->MemoryTester = cmSystemTools::GetCMakeCommand();
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::UB_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ // Check the MemoryCheckType
+ if (this->MemoryTesterStyle == cmCTestMemCheckHandler::UNKNOWN) {
+ std::string checkType =
+ this->CTest->GetCTestConfiguration("MemoryCheckType");
+ if (checkType == "Purify") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
+ } else if (checkType == "BoundsChecker") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
+ } else if (checkType == "Valgrind") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
+ } else if (checkType == "DrMemory") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::DRMEMORY;
+ } else if (checkType == "CudaSanitizer") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::CUDA_SANITIZER;
+ }
+ }
+ if (this->MemoryTester.empty()) {
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "Memory checker (MemoryCheckCommand) "
+ "not set, or cannot find the specified program."
+ << std::endl,
+ this->Quiet);
+ return false;
+ }
+
+ // Setup the options
+ std::string memoryTesterOptions;
+ if (!this->CTest->GetCTestConfiguration("MemoryCheckCommandOptions")
+ .empty()) {
+ memoryTesterOptions =
+ this->CTest->GetCTestConfiguration("MemoryCheckCommandOptions");
+ } else if (!this->CTest->GetCTestConfiguration("ValgrindCommandOptions")
+ .empty()) {
+ memoryTesterOptions =
+ this->CTest->GetCTestConfiguration("ValgrindCommandOptions");
+ } else if (!this->CTest->GetCTestConfiguration("DrMemoryCommandOptions")
+ .empty()) {
+ memoryTesterOptions =
+ this->CTest->GetCTestConfiguration("DrMemoryCommandOptions");
+ } else if (!this->CTest->GetCTestConfiguration("CudaSanitizerCommandOptions")
+ .empty()) {
+ memoryTesterOptions =
+ this->CTest->GetCTestConfiguration("CudaSanitizerCommandOptions");
+ }
+ this->MemoryTesterOptions =
+ cmSystemTools::ParseArguments(memoryTesterOptions);
+
+ this->MemoryTesterOutputFile =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/MemoryChecker.??.log";
+
+ switch (this->MemoryTesterStyle) {
+ case cmCTestMemCheckHandler::VALGRIND: {
+ if (this->MemoryTesterOptions.empty()) {
+ this->MemoryTesterOptions.emplace_back("-q");
+ this->MemoryTesterOptions.emplace_back("--tool=memcheck");
+ this->MemoryTesterOptions.emplace_back("--leak-check=yes");
+ this->MemoryTesterOptions.emplace_back("--show-reachable=yes");
+ this->MemoryTesterOptions.emplace_back("--num-callers=50");
+ }
+ if (!this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .empty()) {
+ if (!cmSystemTools::FileExists(this->CTest->GetCTestConfiguration(
+ "MemoryCheckSuppressionFile"))) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find memory checker suppression file: "
+ << this->CTest->GetCTestConfiguration(
+ "MemoryCheckSuppressionFile")
+ << std::endl);
+ return false;
+ }
+ this->MemoryTesterOptions.push_back(
+ "--suppressions=" +
+ this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile"));
+ }
+ this->MemoryTesterDynamicOptions.push_back("--log-file=" +
+ this->MemoryTesterOutputFile);
+ break;
+ }
+ case cmCTestMemCheckHandler::DRMEMORY: {
+ std::string tempDrMemoryDir =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/DrMemory";
+
+ if (!cm::contains(this->MemoryTesterOptions, "-quiet")) {
+ this->MemoryTesterOptions.emplace_back("-quiet");
+ }
+
+ if (!cm::contains(this->MemoryTesterOptions, "-batch")) {
+ this->MemoryTesterOptions.emplace_back("-batch");
+ }
+
+ this->MemoryTesterDynamicOptions.emplace_back("-logdir");
+ auto logdirOption =
+ std::find(this->MemoryTesterOptions.begin(),
+ this->MemoryTesterOptions.end(), "-logdir");
+ if (logdirOption == this->MemoryTesterOptions.end()) {
+ // No logdir found in memory tester options
+ std::string drMemoryLogDir = tempDrMemoryDir + "/??";
+ this->MemoryTesterDynamicOptions.push_back(drMemoryLogDir);
+ this->MemoryTesterOutputFile = drMemoryLogDir;
+ } else {
+ // Use logdir found in memory tester options
+ auto logdirLocation = std::next(logdirOption);
+ this->MemoryTesterOutputFile = *logdirLocation;
+ this->MemoryTesterDynamicOptions.push_back(*logdirLocation);
+ this->MemoryTesterOptions.erase(logdirOption, logdirLocation + 1);
+ }
+ this->MemoryTesterOutputFile += "/*/results.txt";
+
+ if (std::find(this->MemoryTesterOptions.begin(),
+ this->MemoryTesterOptions.end(),
+ "-symcache_dir") == this->MemoryTesterOptions.end()) {
+ this->MemoryTesterDynamicOptions.emplace_back("-symcache_dir");
+ std::string drMemoryCacheDir = tempDrMemoryDir + "/cache";
+ this->MemoryTesterDynamicOptions.push_back(drMemoryCacheDir);
+ }
+
+ if (!this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .empty()) {
+ if (!cmSystemTools::FileExists(this->CTest->GetCTestConfiguration(
+ "MemoryCheckSuppressionFile"))) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find memory checker suppression file: "
+ << this->CTest->GetCTestConfiguration(
+ "MemoryCheckSuppressionFile")
+ << std::endl);
+ return false;
+ }
+ this->MemoryTesterOptions.emplace_back("-suppress");
+ this->MemoryTesterOptions.push_back(
+ this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile"));
+ }
+
+ this->MemoryTesterOptions.emplace_back("--");
+
+ break;
+ }
+ case cmCTestMemCheckHandler::PURIFY: {
+ std::string outputFile;
+#ifdef _WIN32
+ if (this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .size()) {
+ if (!cmSystemTools::FileExists(this->CTest->GetCTestConfiguration(
+ "MemoryCheckSuppressionFile"))) {
+ cmCTestLog(
+ this->CTest, ERROR_MESSAGE,
+ "Cannot find memory checker suppression file: "
+ << this->CTest
+ ->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .c_str()
+ << std::endl);
+ return false;
+ }
+ std::string filterFiles = "/FilterFiles=" +
+ this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile");
+ this->MemoryTesterOptions.push_back(filterFiles);
+ }
+ outputFile = "/SAVETEXTDATA=";
+#else
+ outputFile = "-log-file=";
+#endif
+ outputFile += this->MemoryTesterOutputFile;
+ this->MemoryTesterDynamicOptions.push_back(outputFile);
+ break;
+ }
+ case cmCTestMemCheckHandler::BOUNDS_CHECKER: {
+ this->BoundsCheckerXMLFile = this->MemoryTesterOutputFile;
+ std::string dpbdFile = this->CTest->GetBinaryDir() +
+ "/Testing/Temporary/MemoryChecker.??.DPbd";
+ this->BoundsCheckerDPBDFile = dpbdFile;
+ this->MemoryTesterDynamicOptions.emplace_back("/B");
+ this->MemoryTesterDynamicOptions.push_back(std::move(dpbdFile));
+ this->MemoryTesterDynamicOptions.emplace_back("/X");
+ this->MemoryTesterDynamicOptions.push_back(this->MemoryTesterOutputFile);
+ this->MemoryTesterOptions.emplace_back("/M");
+ break;
+ }
+ case cmCTestMemCheckHandler::CUDA_SANITIZER: {
+ // cuda sanitizer separates flags from arguments by spaces
+ if (this->MemoryTesterOptions.empty()) {
+ this->MemoryTesterOptions.emplace_back("--tool");
+ this->MemoryTesterOptions.emplace_back("memcheck");
+ this->MemoryTesterOptions.emplace_back("--leak-check");
+ this->MemoryTesterOptions.emplace_back("full");
+ }
+ this->MemoryTesterDynamicOptions.emplace_back("--log-file");
+ this->MemoryTesterDynamicOptions.push_back(this->MemoryTesterOutputFile);
+ break;
+ }
+ // these are almost the same but the env var used is different
+ case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
+ case cmCTestMemCheckHandler::LEAK_SANITIZER:
+ case cmCTestMemCheckHandler::THREAD_SANITIZER:
+ case cmCTestMemCheckHandler::MEMORY_SANITIZER:
+ case cmCTestMemCheckHandler::UB_SANITIZER: {
+ // To pass arguments to ThreadSanitizer the environment variable
+ // TSAN_OPTIONS is used. This is done with the cmake -E env command.
+ // The MemoryTesterDynamicOptions is setup with the -E env
+ // Then the MemoryTesterEnvironmentVariable gets the
+ // TSAN_OPTIONS string with the log_path in it.
+ this->MemoryTesterDynamicOptions.emplace_back("-E");
+ this->MemoryTesterDynamicOptions.emplace_back("env");
+ std::string envVar;
+ std::string extraOptions;
+ std::string suppressionsOption;
+ if (!this->CTest->GetCTestConfiguration("MemoryCheckSanitizerOptions")
+ .empty()) {
+ extraOptions = ":" +
+ this->CTest->GetCTestConfiguration("MemoryCheckSanitizerOptions");
+ }
+ if (!this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .empty()) {
+ suppressionsOption = ":suppressions=" +
+ this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile");
+ }
+ if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::ADDRESS_SANITIZER) {
+ envVar = "ASAN_OPTIONS";
+ } else if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::LEAK_SANITIZER) {
+ envVar = "LSAN_OPTIONS";
+ } else if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::THREAD_SANITIZER) {
+ envVar = "TSAN_OPTIONS";
+ } else if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::MEMORY_SANITIZER) {
+ envVar = "MSAN_OPTIONS";
+ } else if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::UB_SANITIZER) {
+ envVar = "UBSAN_OPTIONS";
+ }
+ // Quote log_path with single quotes; see
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=467936
+ std::string outputFile =
+ envVar + "=log_path='" + this->MemoryTesterOutputFile + "'";
+ this->MemoryTesterEnvironmentVariable =
+ outputFile + suppressionsOption + extraOptions;
+ break;
+ }
+ default:
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Do not understand memory checker: " << this->MemoryTester
+ << std::endl);
+ return false;
+ }
+
+ this->InitializeResultsVectors();
+ // std::vector<std::string>::size_type cc;
+ // for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
+ // {
+ // this->MemoryTesterGlobalResults[cc] = 0;
+ // }
+ return true;
+}
+
+bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str,
+ std::string& log,
+ std::vector<int>& results)
+{
+ switch (this->MemoryTesterStyle) {
+ case cmCTestMemCheckHandler::VALGRIND:
+ return this->ProcessMemCheckValgrindOutput(str, log, results);
+ case cmCTestMemCheckHandler::DRMEMORY:
+ return this->ProcessMemCheckDrMemoryOutput(str, log, results);
+ case cmCTestMemCheckHandler::PURIFY:
+ return this->ProcessMemCheckPurifyOutput(str, log, results);
+ case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
+ case cmCTestMemCheckHandler::LEAK_SANITIZER:
+ case cmCTestMemCheckHandler::THREAD_SANITIZER:
+ case cmCTestMemCheckHandler::MEMORY_SANITIZER:
+ case cmCTestMemCheckHandler::UB_SANITIZER:
+ return this->ProcessMemCheckSanitizerOutput(str, log, results);
+ case cmCTestMemCheckHandler::BOUNDS_CHECKER:
+ return this->ProcessMemCheckBoundsCheckerOutput(str, log, results);
+ case cmCTestMemCheckHandler::CUDA_SANITIZER:
+ return this->ProcessMemCheckCudaOutput(str, log, results);
+ default:
+ log.append("\nMemory checking style used was: ");
+ log.append("None that I know");
+ log = str;
+ return true;
+ }
+}
+
+std::vector<int>::size_type cmCTestMemCheckHandler::FindOrAddWarning(
+ const std::string& warning)
+{
+ for (std::vector<std::string>::size_type i = 0;
+ i < this->ResultStrings.size(); ++i) {
+ if (this->ResultStrings[i] == warning) {
+ return i;
+ }
+ }
+ this->GlobalResults.push_back(0); // this must stay the same size
+ this->ResultStrings.push_back(warning);
+ this->ResultStringsLong.push_back(warning);
+ return this->ResultStrings.size() - 1;
+}
+bool cmCTestMemCheckHandler::ProcessMemCheckSanitizerOutput(
+ const std::string& str, std::string& log, std::vector<int>& result)
+{
+ std::string regex;
+ switch (this->MemoryTesterStyle) {
+ case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
+ regex = "ERROR: AddressSanitizer: (.*) on.*";
+ break;
+ case cmCTestMemCheckHandler::LEAK_SANITIZER:
+ // use leakWarning regex
+ break;
+ case cmCTestMemCheckHandler::THREAD_SANITIZER:
+ regex = "WARNING: ThreadSanitizer: (.*) \\(pid=.*\\)";
+ break;
+ case cmCTestMemCheckHandler::MEMORY_SANITIZER:
+ regex = "WARNING: MemorySanitizer: (.*)";
+ break;
+ case cmCTestMemCheckHandler::UB_SANITIZER:
+ regex = "runtime error: (.*)";
+ break;
+ default:
+ break;
+ }
+ cmsys::RegularExpression sanitizerWarning(regex);
+ cmsys::RegularExpression leakWarning("(Direct|Indirect) leak of .*");
+ int defects = 0;
+ std::vector<std::string> lines;
+ cmsys::SystemTools::Split(str, lines);
+ std::ostringstream ostr;
+ log.clear();
+ for (std::string const& l : lines) {
+ std::string resultFound;
+ if (leakWarning.find(l)) {
+ resultFound = leakWarning.match(1) + " leak";
+ } else if (sanitizerWarning.find(l)) {
+ resultFound = sanitizerWarning.match(1);
+ }
+ if (!resultFound.empty()) {
+ std::vector<int>::size_type idx = this->FindOrAddWarning(resultFound);
+ if (result.empty() || idx > result.size() - 1) {
+ result.push_back(1);
+ } else {
+ result[idx]++;
+ }
+ defects++;
+ ostr << "<b>" << this->ResultStrings[idx] << "</b> ";
+ }
+ ostr << l << std::endl;
+ }
+ log = ostr.str();
+ this->DefectCount += defects;
+ return defects == 0;
+}
+bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
+ const std::string& str, std::string& log, std::vector<int>& results)
+{
+ std::vector<std::string> lines;
+ cmsys::SystemTools::Split(str, lines);
+ std::ostringstream ostr;
+ log.clear();
+
+ cmsys::RegularExpression pfW("^\\[[WEI]\\] ([A-Z][A-Z][A-Z][A-Z]*): ");
+
+ int defects = 0;
+
+ for (std::string const& l : lines) {
+ std::vector<int>::size_type failure = this->ResultStrings.size();
+ if (pfW.find(l)) {
+ std::vector<int>::size_type cc;
+ for (cc = 0; cc < this->ResultStrings.size(); cc++) {
+ if (pfW.match(1) == this->ResultStrings[cc]) {
+ failure = cc;
+ break;
+ }
+ }
+ if (cc == this->ResultStrings.size()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unknown Purify memory fault: " << pfW.match(1)
+ << std::endl);
+ ostr << "*** Unknown Purify memory fault: " << pfW.match(1)
+ << std::endl;
+ }
+ }
+ if (failure != this->ResultStrings.size()) {
+ ostr << "<b>" << this->ResultStrings[failure] << "</b> ";
+ results[failure]++;
+ defects++;
+ }
+ ostr << l << std::endl;
+ }
+
+ log = ostr.str();
+ this->DefectCount += defects;
+ return defects == 0;
+}
+
+bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
+ const std::string& str, std::string& log, std::vector<int>& results)
+{
+ std::vector<std::string> lines;
+ cmsys::SystemTools::Split(str, lines);
+ bool unlimitedOutput = false;
+ if (str.find("CTEST_FULL_OUTPUT") != std::string::npos ||
+ this->CustomMaximumFailedTestOutputSize == 0) {
+ unlimitedOutput = true;
+ }
+
+ std::string::size_type cc;
+
+ std::ostringstream ostr;
+ log.clear();
+
+ int defects = 0;
+
+ cmsys::RegularExpression valgrindLine("^==[0-9][0-9]*==");
+
+ cmsys::RegularExpression vgFIM(
+ R"(== .*Invalid free\(\) / delete / delete\[\])");
+ cmsys::RegularExpression vgFMM(
+ R"(== .*Mismatched free\(\) / delete / delete \[\])");
+ cmsys::RegularExpression vgMLK1(
+ "== .*[0-9,]+ bytes in [0-9,]+ blocks are definitely lost"
+ " in loss record [0-9,]+ of [0-9,]+");
+ cmsys::RegularExpression vgMLK2(
+ "== .*[0-9,]+ \\([0-9,]+ direct, [0-9,]+ indirect\\)"
+ " bytes in [0-9,]+ blocks are definitely lost"
+ " in loss record [0-9,]+ of [0-9,]+");
+ cmsys::RegularExpression vgPAR(
+ "== .*Syscall param .* (contains|points to) unaddressable byte\\(s\\)");
+ cmsys::RegularExpression vgMPK1(
+ "== .*[0-9,]+ bytes in [0-9,]+ blocks are possibly lost in"
+ " loss record [0-9,]+ of [0-9,]+");
+ cmsys::RegularExpression vgMPK2(
+ "== .*[0-9,]+ bytes in [0-9,]+ blocks are still reachable"
+ " in loss record [0-9,]+ of [0-9,]+");
+ cmsys::RegularExpression vgUMC(
+ "== .*Conditional jump or move depends on uninitialised value\\(s\\)");
+ cmsys::RegularExpression vgUMR1(
+ "== .*Use of uninitialised value of size [0-9,]+");
+ cmsys::RegularExpression vgUMR2("== .*Invalid read of size [0-9,]+");
+ cmsys::RegularExpression vgUMR3("== .*Jump to the invalid address ");
+ cmsys::RegularExpression vgUMR4(
+ "== .*Syscall param .* contains "
+ "uninitialised or unaddressable byte\\(s\\)");
+ cmsys::RegularExpression vgUMR5("== .*Syscall param .* uninitialised");
+ cmsys::RegularExpression vgIPW("== .*Invalid write of size [0-9,]+");
+ cmsys::RegularExpression vgABR("== .*pthread_mutex_unlock: mutex is "
+ "locked by a different thread");
+ std::vector<std::string::size_type> nonValGrindOutput;
+ auto sttime = std::chrono::steady_clock::now();
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Start test: " << lines.size() << std::endl, this->Quiet);
+ std::string::size_type totalOutputSize = 0;
+ for (cc = 0; cc < lines.size(); cc++) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "test line " << lines[cc] << std::endl, this->Quiet);
+
+ if (valgrindLine.find(lines[cc])) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "valgrind line " << lines[cc] << std::endl,
+ this->Quiet);
+ int failure = cmCTestMemCheckHandler::NO_MEMORY_FAULT;
+ auto& line = lines[cc];
+ if (vgFIM.find(line)) {
+ failure = cmCTestMemCheckHandler::FIM;
+ } else if (vgFMM.find(line)) {
+ failure = cmCTestMemCheckHandler::FMM;
+ } else if (vgMLK1.find(line) || vgMLK2.find(line)) {
+ failure = cmCTestMemCheckHandler::MLK;
+ } else if (vgPAR.find(line)) {
+ failure = cmCTestMemCheckHandler::PAR;
+ } else if (vgMPK1.find(line) || vgMPK2.find(line)) {
+ failure = cmCTestMemCheckHandler::MPK;
+ } else if (vgUMC.find(line)) {
+ failure = cmCTestMemCheckHandler::UMC;
+ } else if (vgUMR1.find(line) || vgUMR2.find(line) || vgUMR3.find(line) ||
+ vgUMR4.find(line) || vgUMR5.find(line)) {
+ failure = cmCTestMemCheckHandler::UMR;
+ } else if (vgIPW.find(line)) {
+ failure = cmCTestMemCheckHandler::IPW;
+ } else if (vgABR.find(line)) {
+ failure = cmCTestMemCheckHandler::ABR;
+ }
+
+ if (failure != cmCTestMemCheckHandler::NO_MEMORY_FAULT) {
+ ostr << "<b>" << this->ResultStrings[failure] << "</b> ";
+ results[failure]++;
+ defects++;
+ }
+ totalOutputSize += lines[cc].size();
+ ostr << lines[cc] << std::endl;
+ } else {
+ nonValGrindOutput.push_back(cc);
+ }
+ }
+ // Now put all all the non valgrind output into the test output
+ // This should be last in case it gets truncated by the output
+ // limiting code
+ for (std::string::size_type i : nonValGrindOutput) {
+ totalOutputSize += lines[i].size();
+ ostr << lines[i] << std::endl;
+ if (!unlimitedOutput &&
+ totalOutputSize >
+ static_cast<size_t>(this->CustomMaximumFailedTestOutputSize)) {
+ ostr << "....\n";
+ ostr << "Test Output for this test has been truncated see testing"
+ " machine logs for full output,\n";
+ ostr << "or put CTEST_FULL_OUTPUT in the output of "
+ "this test program.\n";
+ break; // stop the copy of output if we are full
+ }
+ }
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "End test (elapsed: "
+ << cmDurationTo<unsigned int>(
+ std::chrono::steady_clock::now() - sttime)
+ << "s)" << std::endl,
+ this->Quiet);
+ log = ostr.str();
+ this->DefectCount += defects;
+ return defects == 0;
+}
+
+bool cmCTestMemCheckHandler::ProcessMemCheckDrMemoryOutput(
+ const std::string& str, std::string& log, std::vector<int>& results)
+{
+ std::vector<std::string> lines;
+ cmsys::SystemTools::Split(str, lines);
+
+ cmsys::RegularExpression drMemoryError("^Error #[0-9]+");
+
+ cmsys::RegularExpression unaddressableAccess("UNADDRESSABLE ACCESS");
+ cmsys::RegularExpression uninitializedRead("UNINITIALIZED READ");
+ cmsys::RegularExpression invalidHeapArgument("INVALID HEAP ARGUMENT");
+ cmsys::RegularExpression leak("LEAK");
+ cmsys::RegularExpression handleLeak("HANDLE LEAK");
+
+ int defects = 0;
+
+ std::ostringstream ostr;
+ for (const auto& l : lines) {
+ ostr << l << std::endl;
+ if (drMemoryError.find(l)) {
+ defects++;
+ if (unaddressableAccess.find(l) || uninitializedRead.find(l)) {
+ results[cmCTestMemCheckHandler::UMR]++;
+ } else if (leak.find(l) || handleLeak.find(l)) {
+ results[cmCTestMemCheckHandler::MLK]++;
+ } else if (invalidHeapArgument.find(l)) {
+ results[cmCTestMemCheckHandler::FMM]++;
+ }
+ }
+ }
+
+ log = ostr.str();
+
+ this->DefectCount += defects;
+ return defects == 0;
+}
+
+bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput(
+ const std::string& str, std::string& log, std::vector<int>& results)
+{
+ log.clear();
+ auto sttime = std::chrono::steady_clock::now();
+ std::vector<std::string> lines;
+ cmsys::SystemTools::Split(str, lines);
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Start test: " << lines.size() << std::endl, this->Quiet);
+ std::vector<std::string>::size_type cc;
+ for (cc = 0; cc < lines.size(); cc++) {
+ if (lines[cc] == BOUNDS_CHECKER_MARKER) {
+ break;
+ }
+ }
+ cmBoundsCheckerParser parser(this->CTest);
+ parser.InitializeParser();
+ if (cc < lines.size()) {
+ for (cc++; cc < lines.size(); ++cc) {
+ std::string& theLine = lines[cc];
+ // check for command line arguments that are not escaped
+ // correctly by BC
+ if (theLine.find("TargetArgs=") != std::string::npos) {
+ // skip this because BC gets it wrong and we can't parse it
+ } else if (!parser.ParseChunk(theLine.c_str(), theLine.size())) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error in ParseChunk: " << theLine << std::endl);
+ }
+ }
+ }
+ int defects = 0;
+ for (int err : parser.Errors) {
+ results[err]++;
+ defects++;
+ }
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "End test (elapsed: "
+ << cmDurationTo<unsigned int>(
+ std::chrono::steady_clock::now() - sttime)
+ << "s)" << std::endl,
+ this->Quiet);
+ if (defects) {
+ // only put the output of Bounds Checker if there were
+ // errors or leaks detected
+ log = parser.Log;
+ }
+ this->DefectCount += defects;
+ return defects == 0;
+}
+
+bool cmCTestMemCheckHandler::ProcessMemCheckCudaOutput(
+ const std::string& str, std::string& log, std::vector<int>& results)
+{
+ std::vector<std::string> lines;
+ cmsys::SystemTools::Split(str, lines);
+ bool unlimitedOutput = false;
+ if (str.find("CTEST_FULL_OUTPUT") != std::string::npos ||
+ this->CustomMaximumFailedTestOutputSize == 0) {
+ unlimitedOutput = true;
+ }
+
+ std::string::size_type cc;
+
+ std::ostringstream ostr;
+ log.clear();
+
+ int defects = 0;
+
+ cmsys::RegularExpression memcheckLine("^========");
+
+ cmsys::RegularExpression leakExpr("== Leaked [0-9,]+ bytes at");
+
+ // list of matchers for output messages that contain variable content
+ // (addresses, sizes, ...) or can be shortened in general. the first match is
+ // used as a error name.
+ std::vector<cmsys::RegularExpression> matchers{
+ // API errors
+ "== Malloc/Free error encountered: (.*)",
+ "== Program hit error ([^ ]*).* on CUDA API call to",
+ "== Program hit ([^ ]*).* on CUDA API call to",
+ // memcheck
+ "== (Invalid .*) of size [0-9,]+", "== (Fatal UVM [CG]PU fault)",
+ // racecheck
+ "== .* (Potential .* hazard detected)", "== .* (Race reported)",
+ // synccheck
+ "== (Barrier error)",
+ // initcheck
+ "== (Uninitialized .* memory read)", "== (Unused memory)",
+ "== (Host API memory access error)",
+ // generic error: ignore ERROR SUMMARY, CUDA-MEMCHECK and others
+ "== ([A-Z][a-z].*)"
+ };
+
+ std::vector<std::string::size_type> nonMemcheckOutput;
+ auto sttime = std::chrono::steady_clock::now();
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Start test: " << lines.size() << std::endl, this->Quiet);
+ std::string::size_type totalOutputSize = 0;
+ for (cc = 0; cc < lines.size(); cc++) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "test line " << lines[cc] << std::endl, this->Quiet);
+
+ if (memcheckLine.find(lines[cc])) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "cuda sanitizer line " << lines[cc] << std::endl,
+ this->Quiet);
+ int failure = -1;
+ auto& line = lines[cc];
+ if (leakExpr.find(line)) {
+ failure = static_cast<int>(this->FindOrAddWarning("Memory leak"));
+ } else {
+ for (auto& matcher : matchers) {
+ if (matcher.find(line)) {
+ failure =
+ static_cast<int>(this->FindOrAddWarning(matcher.match(1)));
+ break;
+ }
+ }
+ }
+
+ if (failure >= 0) {
+ ostr << "<b>" << this->ResultStrings[failure] << "</b> ";
+ if (results.empty() || unsigned(failure) > results.size() - 1) {
+ results.push_back(1);
+ } else {
+ results[failure]++;
+ }
+ defects++;
+ }
+ totalOutputSize += lines[cc].size();
+ ostr << lines[cc] << std::endl;
+ } else {
+ nonMemcheckOutput.push_back(cc);
+ }
+ }
+ // Now put all all the non cuda sanitizer output into the test output
+ // This should be last in case it gets truncated by the output
+ // limiting code
+ for (std::string::size_type i : nonMemcheckOutput) {
+ totalOutputSize += lines[i].size();
+ ostr << lines[i] << std::endl;
+ if (!unlimitedOutput &&
+ totalOutputSize >
+ static_cast<size_t>(this->CustomMaximumFailedTestOutputSize)) {
+ ostr << "....\n";
+ ostr << "Test Output for this test has been truncated see testing"
+ " machine logs for full output,\n";
+ ostr << "or put CTEST_FULL_OUTPUT in the output of "
+ "this test program.\n";
+ break; // stop the copy of output if we are full
+ }
+ }
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "End test (elapsed: "
+ << cmDurationTo<unsigned int>(
+ std::chrono::steady_clock::now() - sttime)
+ << "s)" << std::endl,
+ this->Quiet);
+ log = ostr.str();
+ this->DefectCount += defects;
+ return defects == 0;
+}
+
+// PostProcessTest memcheck results
+void cmCTestMemCheckHandler::PostProcessTest(cmCTestTestResult& res, int test)
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "PostProcessTest memcheck results for : " << res.Name
+ << std::endl,
+ this->Quiet);
+ if (this->MemoryTesterStyle == cmCTestMemCheckHandler::BOUNDS_CHECKER) {
+ this->PostProcessBoundsCheckerTest(res, test);
+ } else if (this->MemoryTesterStyle == cmCTestMemCheckHandler::DRMEMORY) {
+ this->PostProcessDrMemoryTest(res, test);
+ } else {
+ std::vector<std::string> files;
+ this->TestOutputFileNames(test, files);
+ for (std::string const& f : files) {
+ this->AppendMemTesterOutput(res, f);
+ }
+ }
+}
+
+// This method puts the bounds checker output file into the output
+// for the test
+void cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(
+ cmCTestTestResult& res, int test)
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "PostProcessBoundsCheckerTest for : " << res.Name
+ << std::endl,
+ this->Quiet);
+ std::vector<std::string> files;
+ this->TestOutputFileNames(test, files);
+ if (files.empty()) {
+ return;
+ }
+ std::string ofile = files[0];
+ if (ofile.empty()) {
+ return;
+ }
+ // put a scope around this to close ifs so the file can be removed
+ {
+ cmsys::ifstream ifs(ofile.c_str());
+ if (!ifs) {
+ std::string log = "Cannot read memory tester output file: " + ofile;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, log << std::endl);
+ return;
+ }
+ res.Output += BOUNDS_CHECKER_MARKER;
+ res.Output += "\n";
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ res.Output += line;
+ res.Output += "\n";
+ }
+ }
+ cmSystemTools::Delay(1000);
+ cmSystemTools::RemoveFile(this->BoundsCheckerDPBDFile);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Remove: " << this->BoundsCheckerDPBDFile << std::endl,
+ this->Quiet);
+ cmSystemTools::RemoveFile(this->BoundsCheckerXMLFile);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Remove: " << this->BoundsCheckerXMLFile << std::endl,
+ this->Quiet);
+}
+
+void cmCTestMemCheckHandler::PostProcessDrMemoryTest(
+ cmCTestTestHandler::cmCTestTestResult& res, int test)
+{
+ std::string drMemoryLogDir = this->MemoryTesterOutputFile.substr(
+ 0, this->MemoryTesterOutputFile.find("/*/results.txt"));
+
+ // replace placeholder of test
+ std::string::size_type pos = drMemoryLogDir.find("??");
+ if (pos != std::string::npos) {
+ drMemoryLogDir.replace(pos, 2, std::to_string(test));
+ }
+
+ cmsys::Glob g;
+ g.FindFiles(drMemoryLogDir + "/resfile.*");
+ const std::vector<std::string>& files = g.GetFiles();
+
+ for (const std::string& f : files) {
+ cmsys::ifstream ifs(f.c_str());
+ if (!ifs) {
+ std::string log = "Cannot read memory tester output file: " + f;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, log << std::endl);
+ return;
+ }
+ std::string resultFileLocation;
+ cmSystemTools::GetLineFromStream(ifs, resultFileLocation);
+ this->AppendMemTesterOutput(res, resultFileLocation);
+ ifs.close();
+ cmSystemTools::RemoveFile(f);
+ }
+}
+
+void cmCTestMemCheckHandler::AppendMemTesterOutput(cmCTestTestResult& res,
+ std::string const& ofile)
+{
+ if (ofile.empty()) {
+ return;
+ }
+ // put ifs in scope so file can be deleted if needed
+ {
+ cmsys::ifstream ifs(ofile.c_str());
+ if (!ifs) {
+ std::string log = "Cannot read memory tester output file: " + ofile;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, log << std::endl);
+ return;
+ }
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ res.Output += line;
+ res.Output += "\n";
+ }
+ }
+ if (this->LogWithPID) {
+ auto pos = ofile.find_last_of('.');
+ if (pos != std::string::npos) {
+ auto ofileWithoutPid = ofile.substr(0, pos);
+ cmSystemTools::RenameFile(ofile, ofileWithoutPid);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Renaming: " << ofile << " to: " << ofileWithoutPid
+ << "\n",
+ this->Quiet);
+ }
+ }
+}
+
+void cmCTestMemCheckHandler::TestOutputFileNames(
+ int test, std::vector<std::string>& files)
+{
+ std::string index = std::to_string(test);
+ std::string ofile = this->MemoryTesterOutputFile;
+ std::string::size_type pos = ofile.find("??");
+ ofile.replace(pos, 2, index);
+ if (this->LogWithPID) {
+ ofile += ".*";
+ cmsys::Glob g;
+ g.FindFiles(ofile);
+ if (g.GetFiles().empty()) {
+ std::string log = "Cannot find memory tester output file: " + ofile;
+ cmCTestLog(this->CTest, WARNING, log << std::endl);
+ ofile.clear();
+ } else {
+ files = g.GetFiles();
+ return;
+ }
+ } else if (!cmSystemTools::FileExists(ofile)) {
+ std::string log = "Cannot find memory tester output file: " + ofile;
+ cmCTestLog(this->CTest, WARNING, log << std::endl);
+ ofile.clear();
+ }
+ files.push_back(std::move(ofile));
+}
diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h
new file mode 100644
index 0000000..b200c43
--- /dev/null
+++ b/Source/CTest/cmCTestMemCheckHandler.h
@@ -0,0 +1,158 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmCTestTestHandler.h"
+
+class cmMakefile;
+class cmXMLWriter;
+
+/** \class cmCTestMemCheckHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ */
+class cmCTestMemCheckHandler : public cmCTestTestHandler
+{
+ friend class cmCTestRunTest;
+
+public:
+ using Superclass = cmCTestTestHandler;
+
+ void PopulateCustomVectors(cmMakefile* mf) override;
+
+ cmCTestMemCheckHandler();
+
+ void Initialize() override;
+
+ int GetDefectCount() const;
+
+protected:
+ int PreProcessHandler() override;
+ int PostProcessHandler() override;
+ void GenerateTestCommand(std::vector<std::string>& args, int test) override;
+
+private:
+ enum
+ { // Memory checkers
+ UNKNOWN = 0,
+ VALGRIND,
+ PURIFY,
+ DRMEMORY,
+ BOUNDS_CHECKER,
+ // checkers after here do not use the standard error list
+ CUDA_SANITIZER,
+ ADDRESS_SANITIZER,
+ LEAK_SANITIZER,
+ THREAD_SANITIZER,
+ MEMORY_SANITIZER,
+ UB_SANITIZER
+ };
+
+public:
+ enum
+ { // Memory faults
+ ABR = 0,
+ ABW,
+ ABWL,
+ COR,
+ EXU,
+ FFM,
+ FIM,
+ FMM,
+ FMR,
+ FMW,
+ FUM,
+ IPR,
+ IPW,
+ MAF,
+ MLK,
+ MPK,
+ NPR,
+ ODS,
+ PAR,
+ PLK,
+ UMC,
+ UMR,
+ NO_MEMORY_FAULT
+ };
+
+private:
+ enum
+ { // Program statuses
+ NOT_RUN = 0,
+ TIMEOUT,
+ SEGFAULT,
+ ILLEGAL,
+ INTERRUPT,
+ NUMERICAL,
+ OTHER_FAULT,
+ FAILED,
+ BAD_COMMAND,
+ COMPLETED
+ };
+ std::string BoundsCheckerDPBDFile;
+ std::string BoundsCheckerXMLFile;
+ std::string MemoryTester;
+ std::vector<std::string> MemoryTesterDynamicOptions;
+ std::vector<std::string> MemoryTesterOptions;
+ int MemoryTesterStyle;
+ std::string MemoryTesterOutputFile;
+ std::string MemoryTesterEnvironmentVariable;
+ // these are used to store the types of errors that can show up
+ std::vector<std::string> ResultStrings;
+ std::vector<std::string> ResultStringsLong;
+ std::vector<int> GlobalResults;
+ bool LogWithPID; // does log file add pid
+ int DefectCount;
+
+ std::vector<int>::size_type FindOrAddWarning(const std::string& warning);
+ // initialize the ResultStrings and ResultStringsLong for
+ // this type of checker
+ void InitializeResultsVectors();
+
+ //! Initialize memory checking subsystem.
+ bool InitializeMemoryChecking();
+
+ /**
+ * Generate the Dart compatible output
+ */
+ void GenerateDartOutput(cmXMLWriter& xml) override;
+
+ std::vector<std::string> CustomPreMemCheck;
+ std::vector<std::string> CustomPostMemCheck;
+
+ //! Parse Valgrind/Purify/Bounds Checker result out of the output
+ // string. After running, log holds the output and results hold the
+ // different memory errors.
+ bool ProcessMemCheckOutput(const std::string& str, std::string& log,
+ std::vector<int>& results);
+ bool ProcessMemCheckValgrindOutput(const std::string& str, std::string& log,
+ std::vector<int>& results);
+ bool ProcessMemCheckDrMemoryOutput(const std::string& str, std::string& log,
+ std::vector<int>& results);
+ bool ProcessMemCheckPurifyOutput(const std::string& str, std::string& log,
+ std::vector<int>& results);
+ bool ProcessMemCheckCudaOutput(const std::string& str, std::string& log,
+ std::vector<int>& results);
+ bool ProcessMemCheckSanitizerOutput(const std::string& str, std::string& log,
+ std::vector<int>& results);
+ bool ProcessMemCheckBoundsCheckerOutput(const std::string& str,
+ std::string& log,
+ std::vector<int>& results);
+
+ void PostProcessTest(cmCTestTestResult& res, int test);
+ void PostProcessBoundsCheckerTest(cmCTestTestResult& res, int test);
+ void PostProcessDrMemoryTest(cmCTestTestResult& res, int test);
+
+ //! append MemoryTesterOutputFile to the test log
+ void AppendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res,
+ std::string const& filename);
+
+ //! generate the output filename for the given test index
+ void TestOutputFileNames(int test, std::vector<std::string>& files);
+};
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
new file mode 100644
index 0000000..86a8e00
--- /dev/null
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -0,0 +1,1442 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestMultiProcessHandler.h"
+
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <cmath>
+#include <cstddef> // IWYU pragma: keep
+#include <cstdlib>
+#include <cstring>
+#include <iomanip>
+#include <iostream>
+#include <list>
+#include <sstream>
+#include <stack>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cmext/algorithm>
+
+#include <cm3p/json/value.h>
+#include <cm3p/json/writer.h>
+#include <cm3p/uv.h>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/SystemInformation.hxx"
+
+#include "cmAffinity.h"
+#include "cmCTest.h"
+#include "cmCTestBinPacker.h"
+#include "cmCTestRunTest.h"
+#include "cmCTestTestHandler.h"
+#include "cmDuration.h"
+#include "cmListFileCache.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmUVSignalHackRAII.h" // IWYU pragma: keep
+#include "cmWorkingDirectory.h"
+
+namespace cmsys {
+class RegularExpression;
+}
+
+class TestComparator
+{
+public:
+ TestComparator(cmCTestMultiProcessHandler* handler)
+ : Handler(handler)
+ {
+ }
+
+ // Sorts tests in descending order of cost
+ bool operator()(int index1, int index2) const
+ {
+ return this->Handler->Properties[index1]->Cost >
+ this->Handler->Properties[index2]->Cost;
+ }
+
+private:
+ cmCTestMultiProcessHandler* Handler;
+};
+
+cmCTestMultiProcessHandler::cmCTestMultiProcessHandler()
+{
+ this->ParallelLevel = 1;
+ this->TestLoad = 0;
+ this->FakeLoadForTesting = 0;
+ this->Completed = 0;
+ this->RunningCount = 0;
+ this->ProcessorsAvailable = cmAffinity::GetProcessorsAvailable();
+ this->HaveAffinity = this->ProcessorsAvailable.size();
+ this->HasCycles = false;
+ this->SerialTestRunning = false;
+}
+
+cmCTestMultiProcessHandler::~cmCTestMultiProcessHandler() = default;
+
+// Set the tests
+void cmCTestMultiProcessHandler::SetTests(TestMap& tests,
+ PropertiesMap& properties)
+{
+ this->Tests = tests;
+ this->Properties = properties;
+ this->Total = this->Tests.size();
+ // set test run map to false for all
+ for (auto const& t : this->Tests) {
+ this->TestRunningMap[t.first] = false;
+ this->TestFinishMap[t.first] = false;
+ }
+ if (!this->CTest->GetShowOnly()) {
+ this->ReadCostData();
+ this->HasCycles = !this->CheckCycles();
+ if (this->HasCycles) {
+ return;
+ }
+ this->CreateTestCostList();
+ }
+}
+
+// Set the max number of tests that can be run at the same time.
+void cmCTestMultiProcessHandler::SetParallelLevel(size_t level)
+{
+ this->ParallelLevel = level < 1 ? 1 : level;
+}
+
+void cmCTestMultiProcessHandler::SetTestLoad(unsigned long load)
+{
+ this->TestLoad = load;
+
+ std::string fake_load_value;
+ if (cmSystemTools::GetEnv("__CTEST_FAKE_LOAD_AVERAGE_FOR_TESTING",
+ fake_load_value)) {
+ if (!cmStrToULong(fake_load_value, &this->FakeLoadForTesting)) {
+ cmSystemTools::Error("Failed to parse fake load value: " +
+ fake_load_value);
+ }
+ }
+}
+
+void cmCTestMultiProcessHandler::RunTests()
+{
+ this->CheckResume();
+ if (this->HasCycles) {
+ return;
+ }
+#ifdef CMAKE_UV_SIGNAL_HACK
+ cmUVSignalHackRAII hackRAII;
+#endif
+ this->TestHandler->SetMaxIndex(this->FindMaxIndex());
+
+ uv_loop_init(&this->Loop);
+ this->StartNextTests();
+ uv_run(&this->Loop, UV_RUN_DEFAULT);
+ uv_loop_close(&this->Loop);
+
+ if (!this->StopTimePassed && !this->CheckStopOnFailure()) {
+ assert(this->Completed == this->Total);
+ assert(this->Tests.empty());
+ }
+ assert(this->AllResourcesAvailable());
+
+ this->MarkFinished();
+ this->UpdateCostData();
+}
+
+bool cmCTestMultiProcessHandler::StartTestProcess(int test)
+{
+ if (this->HaveAffinity && this->Properties[test]->WantAffinity) {
+ size_t needProcessors = this->GetProcessorsUsed(test);
+ if (needProcessors > this->ProcessorsAvailable.size()) {
+ return false;
+ }
+ std::vector<size_t> affinity;
+ affinity.reserve(needProcessors);
+ for (size_t i = 0; i < needProcessors; ++i) {
+ auto p = this->ProcessorsAvailable.begin();
+ affinity.push_back(*p);
+ this->ProcessorsAvailable.erase(p);
+ }
+ this->Properties[test]->Affinity = std::move(affinity);
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "test " << test << "\n", this->Quiet);
+ this->TestRunningMap[test] = true; // mark the test as running
+ // now remove the test itself
+ this->EraseTest(test);
+ this->RunningCount += this->GetProcessorsUsed(test);
+
+ auto testRun = cm::make_unique<cmCTestRunTest>(*this);
+
+ if (this->RepeatMode != cmCTest::Repeat::Never) {
+ testRun->SetRepeatMode(this->RepeatMode);
+ testRun->SetNumberOfRuns(this->RepeatCount);
+ }
+ testRun->SetIndex(test);
+ testRun->SetTestProperties(this->Properties[test]);
+ if (this->TestHandler->UseResourceSpec) {
+ testRun->SetUseAllocatedResources(true);
+ testRun->SetAllocatedResources(this->AllocatedResources[test]);
+ }
+
+ // Find any failed dependencies for this test. We assume the more common
+ // scenario has no failed tests, so make it the outer loop.
+ for (std::string const& f : *this->Failed) {
+ if (cm::contains(this->Properties[test]->RequireSuccessDepends, f)) {
+ testRun->AddFailedDependency(f);
+ }
+ }
+
+ // Always lock the resources we'll be using, even if we fail to set the
+ // working directory because FinishTestProcess() will try to unlock them
+ this->LockResources(test);
+
+ if (!this->ResourceAllocationErrors[test].empty()) {
+ std::ostringstream e;
+ e << "Insufficient resources for test " << this->Properties[test]->Name
+ << ":\n\n";
+ for (auto const& it : this->ResourceAllocationErrors[test]) {
+ switch (it.second) {
+ case ResourceAllocationError::NoResourceType:
+ e << " Test requested resources of type '" << it.first
+ << "' which does not exist\n";
+ break;
+
+ case ResourceAllocationError::InsufficientResources:
+ e << " Test requested resources of type '" << it.first
+ << "' in the following amounts:\n";
+ for (auto const& group : this->Properties[test]->ResourceGroups) {
+ for (auto const& requirement : group) {
+ if (requirement.ResourceType == it.first) {
+ e << " " << requirement.SlotsNeeded
+ << (requirement.SlotsNeeded == 1 ? " slot\n" : " slots\n");
+ }
+ }
+ }
+ e << " but only the following units were available:\n";
+ for (auto const& res :
+ this->ResourceAllocator.GetResources().at(it.first)) {
+ e << " '" << res.first << "': " << res.second.Total
+ << (res.second.Total == 1 ? " slot\n" : " slots\n");
+ }
+ break;
+ }
+ e << "\n";
+ }
+ e << "Resource spec file:\n\n " << this->TestHandler->ResourceSpecFile;
+ cmCTestRunTest::StartFailure(std::move(testRun), e.str(),
+ "Insufficient resources");
+ return false;
+ }
+
+ cmWorkingDirectory workdir(this->Properties[test]->Directory);
+ if (workdir.Failed()) {
+ cmCTestRunTest::StartFailure(std::move(testRun),
+ "Failed to change working directory to " +
+ this->Properties[test]->Directory + " : " +
+ std::strerror(workdir.GetLastResult()),
+ "Failed to change working directory");
+ return false;
+ }
+
+ // Ownership of 'testRun' has moved to another structure.
+ // When the test finishes, FinishTestProcess will be called.
+ return cmCTestRunTest::StartTest(std::move(testRun), this->Completed,
+ this->Total);
+}
+
+bool cmCTestMultiProcessHandler::AllocateResources(int index)
+{
+ if (!this->TestHandler->UseResourceSpec) {
+ return true;
+ }
+
+ std::map<std::string, std::vector<cmCTestBinPackerAllocation>> allocations;
+ if (!this->TryAllocateResources(index, allocations)) {
+ return false;
+ }
+
+ auto& allocatedResources = this->AllocatedResources[index];
+ allocatedResources.resize(this->Properties[index]->ResourceGroups.size());
+ for (auto const& it : allocations) {
+ for (auto const& alloc : it.second) {
+ bool result = this->ResourceAllocator.AllocateResource(
+ it.first, alloc.Id, alloc.SlotsNeeded);
+ (void)result;
+ assert(result);
+ allocatedResources[alloc.ProcessIndex][it.first].push_back(
+ { alloc.Id, static_cast<unsigned int>(alloc.SlotsNeeded) });
+ }
+ }
+
+ return true;
+}
+
+bool cmCTestMultiProcessHandler::TryAllocateResources(
+ int index,
+ std::map<std::string, std::vector<cmCTestBinPackerAllocation>>& allocations,
+ std::map<std::string, ResourceAllocationError>* errors)
+{
+ allocations.clear();
+
+ std::size_t processIndex = 0;
+ for (auto const& process : this->Properties[index]->ResourceGroups) {
+ for (auto const& requirement : process) {
+ for (int i = 0; i < requirement.UnitsNeeded; ++i) {
+ allocations[requirement.ResourceType].push_back(
+ { processIndex, requirement.SlotsNeeded, "" });
+ }
+ }
+ ++processIndex;
+ }
+
+ bool result = true;
+ auto const& availableResources = this->ResourceAllocator.GetResources();
+ for (auto& it : allocations) {
+ if (!availableResources.count(it.first)) {
+ if (errors) {
+ (*errors)[it.first] = ResourceAllocationError::NoResourceType;
+ result = false;
+ } else {
+ return false;
+ }
+ } else if (!cmAllocateCTestResourcesRoundRobin(
+ availableResources.at(it.first), it.second)) {
+ if (errors) {
+ (*errors)[it.first] = ResourceAllocationError::InsufficientResources;
+ result = false;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ return result;
+}
+
+void cmCTestMultiProcessHandler::DeallocateResources(int index)
+{
+ if (!this->TestHandler->UseResourceSpec) {
+ return;
+ }
+
+ {
+ auto& allocatedResources = this->AllocatedResources[index];
+ for (auto const& processAlloc : allocatedResources) {
+ for (auto const& it : processAlloc) {
+ auto resourceType = it.first;
+ for (auto const& it2 : it.second) {
+ bool success = this->ResourceAllocator.DeallocateResource(
+ resourceType, it2.Id, it2.Slots);
+ (void)success;
+ assert(success);
+ }
+ }
+ }
+ }
+ this->AllocatedResources.erase(index);
+}
+
+bool cmCTestMultiProcessHandler::AllResourcesAvailable()
+{
+ for (auto const& it : this->ResourceAllocator.GetResources()) {
+ for (auto const& it2 : it.second) {
+ if (it2.second.Locked != 0) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+void cmCTestMultiProcessHandler::CheckResourcesAvailable()
+{
+ if (this->TestHandler->UseResourceSpec) {
+ for (auto test : this->SortedTests) {
+ std::map<std::string, std::vector<cmCTestBinPackerAllocation>>
+ allocations;
+ this->TryAllocateResources(test, allocations,
+ &this->ResourceAllocationErrors[test]);
+ }
+ }
+}
+
+bool cmCTestMultiProcessHandler::CheckStopOnFailure()
+{
+ return this->CTest->GetStopOnFailure();
+}
+
+bool cmCTestMultiProcessHandler::CheckStopTimePassed()
+{
+ if (!this->StopTimePassed) {
+ std::chrono::system_clock::time_point stop_time =
+ this->CTest->GetStopTime();
+ if (stop_time != std::chrono::system_clock::time_point() &&
+ stop_time <= std::chrono::system_clock::now()) {
+ this->SetStopTimePassed();
+ }
+ }
+ return this->StopTimePassed;
+}
+
+void cmCTestMultiProcessHandler::SetStopTimePassed()
+{
+ if (!this->StopTimePassed) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "The stop time has been passed. "
+ "Stopping all tests."
+ << std::endl);
+ this->StopTimePassed = true;
+ }
+}
+
+void cmCTestMultiProcessHandler::LockResources(int index)
+{
+ this->LockedResources.insert(
+ this->Properties[index]->LockedResources.begin(),
+ this->Properties[index]->LockedResources.end());
+
+ if (this->Properties[index]->RunSerial) {
+ this->SerialTestRunning = true;
+ }
+}
+
+void cmCTestMultiProcessHandler::UnlockResources(int index)
+{
+ for (std::string const& i : this->Properties[index]->LockedResources) {
+ this->LockedResources.erase(i);
+ }
+ if (this->Properties[index]->RunSerial) {
+ this->SerialTestRunning = false;
+ }
+}
+
+void cmCTestMultiProcessHandler::EraseTest(int test)
+{
+ this->Tests.erase(test);
+ this->SortedTests.erase(
+ std::find(this->SortedTests.begin(), this->SortedTests.end(), test));
+}
+
+inline size_t cmCTestMultiProcessHandler::GetProcessorsUsed(int test)
+{
+ size_t processors = static_cast<int>(this->Properties[test]->Processors);
+ // If processors setting is set higher than the -j
+ // setting, we default to using all of the process slots.
+ if (processors > this->ParallelLevel) {
+ processors = this->ParallelLevel;
+ }
+ // Cap tests that want affinity to the maximum affinity available.
+ if (this->HaveAffinity && processors > this->HaveAffinity &&
+ this->Properties[test]->WantAffinity) {
+ processors = this->HaveAffinity;
+ }
+ return processors;
+}
+
+std::string cmCTestMultiProcessHandler::GetName(int test)
+{
+ return this->Properties[test]->Name;
+}
+
+bool cmCTestMultiProcessHandler::StartTest(int test)
+{
+ // Check for locked resources
+ for (std::string const& i : this->Properties[test]->LockedResources) {
+ if (cm::contains(this->LockedResources, i)) {
+ return false;
+ }
+ }
+
+ // Allocate resources
+ if (this->ResourceAllocationErrors[test].empty() &&
+ !this->AllocateResources(test)) {
+ this->DeallocateResources(test);
+ return false;
+ }
+
+ // if there are no depends left then run this test
+ if (this->Tests[test].empty()) {
+ return this->StartTestProcess(test);
+ }
+ // This test was not able to start because it is waiting
+ // on depends to run
+ this->DeallocateResources(test);
+ return false;
+}
+
+void cmCTestMultiProcessHandler::StartNextTests()
+{
+ if (this->TestLoadRetryTimer.get() != nullptr) {
+ // This timer may be waiting to call StartNextTests again.
+ // Since we have been called it is no longer needed.
+ uv_timer_stop(this->TestLoadRetryTimer);
+ }
+
+ if (this->Tests.empty()) {
+ this->TestLoadRetryTimer.reset();
+ return;
+ }
+
+ if (this->CheckStopTimePassed()) {
+ return;
+ }
+
+ if (this->CheckStopOnFailure() && !this->Failed->empty()) {
+ return;
+ }
+
+ size_t numToStart = 0;
+
+ if (this->RunningCount < this->ParallelLevel) {
+ numToStart = this->ParallelLevel - this->RunningCount;
+ }
+
+ if (numToStart == 0) {
+ return;
+ }
+
+ // Don't start any new tests if one with the RUN_SERIAL property
+ // is already running.
+ if (this->SerialTestRunning) {
+ return;
+ }
+
+ bool allTestsFailedTestLoadCheck = false;
+ size_t minProcessorsRequired = this->ParallelLevel;
+ std::string testWithMinProcessors;
+
+ cmsys::SystemInformation info;
+
+ unsigned long systemLoad = 0;
+ size_t spareLoad = 0;
+ if (this->TestLoad > 0) {
+ // Activate possible wait.
+ allTestsFailedTestLoadCheck = true;
+
+ // Check for a fake load average value used in testing.
+ if (this->FakeLoadForTesting > 0) {
+ systemLoad = this->FakeLoadForTesting;
+ // Drop the fake load for the next iteration to a value low enough
+ // that the next iteration will start tests.
+ this->FakeLoadForTesting = 1;
+ }
+ // If it's not set, look up the true load average.
+ else {
+ systemLoad = static_cast<unsigned long>(ceil(info.GetLoadAverage()));
+ }
+ spareLoad =
+ (this->TestLoad > systemLoad ? this->TestLoad - systemLoad : 0);
+
+ // Don't start more tests than the spare load can support.
+ if (numToStart > spareLoad) {
+ numToStart = spareLoad;
+ }
+ }
+
+ TestList copy = this->SortedTests;
+ for (auto const& test : copy) {
+ // Take a nap if we're currently performing a RUN_SERIAL test.
+ if (this->SerialTestRunning) {
+ break;
+ }
+ // We can only start a RUN_SERIAL test if no other tests are also
+ // running.
+ if (this->Properties[test]->RunSerial && this->RunningCount > 0) {
+ continue;
+ }
+
+ size_t processors = this->GetProcessorsUsed(test);
+ bool testLoadOk = true;
+ if (this->TestLoad > 0) {
+ if (processors <= spareLoad) {
+ cmCTestLog(this->CTest, DEBUG,
+ "OK to run " << this->GetName(test) << ", it requires "
+ << processors << " procs & system load is: "
+ << systemLoad << std::endl);
+ allTestsFailedTestLoadCheck = false;
+ } else {
+ testLoadOk = false;
+ }
+ }
+
+ if (processors <= minProcessorsRequired) {
+ minProcessorsRequired = processors;
+ testWithMinProcessors = this->GetName(test);
+ }
+
+ if (testLoadOk && processors <= numToStart && this->StartTest(test)) {
+ numToStart -= processors;
+ } else if (numToStart == 0) {
+ break;
+ }
+ }
+
+ if (allTestsFailedTestLoadCheck) {
+ // Find out whether there are any non RUN_SERIAL tests left, so that the
+ // correct warning may be displayed.
+ bool onlyRunSerialTestsLeft = true;
+ for (auto const& test : copy) {
+ if (!this->Properties[test]->RunSerial) {
+ onlyRunSerialTestsLeft = false;
+ }
+ }
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "***** WAITING, ");
+
+ if (this->SerialTestRunning) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Waiting for RUN_SERIAL test to finish.");
+ } else if (onlyRunSerialTestsLeft) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Only RUN_SERIAL tests remain, awaiting available slot.");
+ } else {
+ /* clang-format off */
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "System Load: " << systemLoad << ", "
+ "Max Allowed Load: " << this->TestLoad << ", "
+ "Smallest test " << testWithMinProcessors <<
+ " requires " << minProcessorsRequired);
+ /* clang-format on */
+ }
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "*****" << std::endl);
+
+ // Wait between 1 and 5 seconds before trying again.
+ unsigned int milliseconds = (cmSystemTools::RandomSeed() % 5 + 1) * 1000;
+ if (this->FakeLoadForTesting) {
+ milliseconds = 10;
+ }
+ if (this->TestLoadRetryTimer.get() == nullptr) {
+ this->TestLoadRetryTimer.init(this->Loop, this);
+ }
+ this->TestLoadRetryTimer.start(
+ &cmCTestMultiProcessHandler::OnTestLoadRetryCB, milliseconds, 0);
+ }
+}
+
+void cmCTestMultiProcessHandler::OnTestLoadRetryCB(uv_timer_t* timer)
+{
+ auto* self = static_cast<cmCTestMultiProcessHandler*>(timer->data);
+ self->StartNextTests();
+}
+
+void cmCTestMultiProcessHandler::FinishTestProcess(
+ std::unique_ptr<cmCTestRunTest> runner, bool started)
+{
+ this->Completed++;
+
+ int test = runner->GetIndex();
+ auto* properties = runner->GetTestProperties();
+
+ bool testResult = runner->EndTest(this->Completed, this->Total, started);
+ if (runner->TimedOutForStopTime()) {
+ this->SetStopTimePassed();
+ }
+ if (started) {
+ if (!this->StopTimePassed &&
+ cmCTestRunTest::StartAgain(std::move(runner), this->Completed)) {
+ this->Completed--; // remove the completed test because run again
+ return;
+ }
+ }
+
+ if (testResult) {
+ this->Passed->push_back(properties->Name);
+ } else if (!properties->Disabled) {
+ this->Failed->push_back(properties->Name);
+ }
+
+ for (auto& t : this->Tests) {
+ t.second.erase(test);
+ }
+
+ this->TestFinishMap[test] = true;
+ this->TestRunningMap[test] = false;
+ this->WriteCheckpoint(test);
+ this->DeallocateResources(test);
+ this->UnlockResources(test);
+ this->RunningCount -= this->GetProcessorsUsed(test);
+
+ for (auto p : properties->Affinity) {
+ this->ProcessorsAvailable.insert(p);
+ }
+ properties->Affinity.clear();
+
+ runner.reset();
+ if (started) {
+ this->StartNextTests();
+ }
+}
+
+void cmCTestMultiProcessHandler::UpdateCostData()
+{
+ std::string fname = this->CTest->GetCostDataFile();
+ std::string tmpout = fname + ".tmp";
+ cmsys::ofstream fout;
+ fout.open(tmpout.c_str());
+
+ PropertiesMap temp = this->Properties;
+
+ if (cmSystemTools::FileExists(fname)) {
+ cmsys::ifstream fin;
+ fin.open(fname.c_str());
+
+ std::string line;
+ while (std::getline(fin, line)) {
+ if (line == "---") {
+ break;
+ }
+ std::vector<std::string> parts = cmSystemTools::SplitString(line, ' ');
+ // Format: <name> <previous_runs> <avg_cost>
+ if (parts.size() < 3) {
+ break;
+ }
+
+ std::string name = parts[0];
+ int prev = atoi(parts[1].c_str());
+ float cost = static_cast<float>(atof(parts[2].c_str()));
+
+ int index = this->SearchByName(name);
+ if (index == -1) {
+ // This test is not in memory. We just rewrite the entry
+ fout << name << " " << prev << " " << cost << "\n";
+ } else {
+ // Update with our new average cost
+ fout << name << " " << this->Properties[index]->PreviousRuns << " "
+ << this->Properties[index]->Cost << "\n";
+ temp.erase(index);
+ }
+ }
+ fin.close();
+ cmSystemTools::RemoveFile(fname);
+ }
+
+ // Add all tests not previously listed in the file
+ for (auto const& i : temp) {
+ fout << i.second->Name << " " << i.second->PreviousRuns << " "
+ << i.second->Cost << "\n";
+ }
+
+ // Write list of failed tests
+ fout << "---\n";
+ for (std::string const& f : *this->Failed) {
+ fout << f << "\n";
+ }
+ fout.close();
+ cmSystemTools::RenameFile(tmpout, fname);
+}
+
+void cmCTestMultiProcessHandler::ReadCostData()
+{
+ std::string fname = this->CTest->GetCostDataFile();
+
+ if (cmSystemTools::FileExists(fname, true)) {
+ cmsys::ifstream fin;
+ fin.open(fname.c_str());
+ std::string line;
+ while (std::getline(fin, line)) {
+ if (line == "---") {
+ break;
+ }
+
+ std::vector<std::string> parts = cmSystemTools::SplitString(line, ' ');
+
+ // Probably an older version of the file, will be fixed next run
+ if (parts.size() < 3) {
+ fin.close();
+ return;
+ }
+
+ std::string name = parts[0];
+ int prev = atoi(parts[1].c_str());
+ float cost = static_cast<float>(atof(parts[2].c_str()));
+
+ int index = this->SearchByName(name);
+ if (index == -1) {
+ continue;
+ }
+
+ this->Properties[index]->PreviousRuns = prev;
+ // When not running in parallel mode, don't use cost data
+ if (this->ParallelLevel > 1 && this->Properties[index] &&
+ this->Properties[index]->Cost == 0) {
+ this->Properties[index]->Cost = cost;
+ }
+ }
+ // Next part of the file is the failed tests
+ while (std::getline(fin, line)) {
+ if (!line.empty()) {
+ this->LastTestsFailed.push_back(line);
+ }
+ }
+ fin.close();
+ }
+}
+
+int cmCTestMultiProcessHandler::SearchByName(std::string const& name)
+{
+ int index = -1;
+
+ for (auto const& p : this->Properties) {
+ if (p.second->Name == name) {
+ index = p.first;
+ }
+ }
+ return index;
+}
+
+void cmCTestMultiProcessHandler::CreateTestCostList()
+{
+ if (this->ParallelLevel > 1) {
+ this->CreateParallelTestCostList();
+ } else {
+ this->CreateSerialTestCostList();
+ }
+}
+
+void cmCTestMultiProcessHandler::CreateParallelTestCostList()
+{
+ TestSet alreadySortedTests;
+
+ std::list<TestSet> priorityStack;
+ priorityStack.emplace_back();
+ TestSet& topLevel = priorityStack.back();
+
+ // In parallel test runs add previously failed tests to the front
+ // of the cost list and queue other tests for further sorting
+ for (auto const& t : this->Tests) {
+ if (cm::contains(this->LastTestsFailed, this->Properties[t.first]->Name)) {
+ // If the test failed last time, it should be run first.
+ this->SortedTests.push_back(t.first);
+ alreadySortedTests.insert(t.first);
+ } else {
+ topLevel.insert(t.first);
+ }
+ }
+
+ // In parallel test runs repeatedly move dependencies of the tests on
+ // the current dependency level to the next level until no
+ // further dependencies exist.
+ while (!priorityStack.back().empty()) {
+ TestSet& previousSet = priorityStack.back();
+ priorityStack.emplace_back();
+ TestSet& currentSet = priorityStack.back();
+
+ for (auto const& i : previousSet) {
+ TestSet const& dependencies = this->Tests[i];
+ currentSet.insert(dependencies.begin(), dependencies.end());
+ }
+
+ for (auto const& i : currentSet) {
+ previousSet.erase(i);
+ }
+ }
+
+ // Remove the empty dependency level
+ priorityStack.pop_back();
+
+ // Reverse iterate over the different dependency levels (deepest first).
+ // Sort tests within each level by COST and append them to the cost list.
+ for (TestSet const& currentSet : cmReverseRange(priorityStack)) {
+ TestList sortedCopy;
+ cm::append(sortedCopy, currentSet);
+ std::stable_sort(sortedCopy.begin(), sortedCopy.end(),
+ TestComparator(this));
+
+ for (auto const& j : sortedCopy) {
+ if (!cm::contains(alreadySortedTests, j)) {
+ this->SortedTests.push_back(j);
+ alreadySortedTests.insert(j);
+ }
+ }
+ }
+}
+
+void cmCTestMultiProcessHandler::GetAllTestDependencies(int test,
+ TestList& dependencies)
+{
+ TestSet const& dependencySet = this->Tests[test];
+ for (int i : dependencySet) {
+ this->GetAllTestDependencies(i, dependencies);
+ dependencies.push_back(i);
+ }
+}
+
+void cmCTestMultiProcessHandler::CreateSerialTestCostList()
+{
+ TestList presortedList;
+
+ for (auto const& i : this->Tests) {
+ presortedList.push_back(i.first);
+ }
+
+ std::stable_sort(presortedList.begin(), presortedList.end(),
+ TestComparator(this));
+
+ TestSet alreadySortedTests;
+
+ for (int test : presortedList) {
+ if (cm::contains(alreadySortedTests, test)) {
+ continue;
+ }
+
+ TestList dependencies;
+ this->GetAllTestDependencies(test, dependencies);
+
+ for (int testDependency : dependencies) {
+ if (!cm::contains(alreadySortedTests, testDependency)) {
+ alreadySortedTests.insert(testDependency);
+ this->SortedTests.push_back(testDependency);
+ }
+ }
+
+ alreadySortedTests.insert(test);
+ this->SortedTests.push_back(test);
+ }
+}
+
+void cmCTestMultiProcessHandler::WriteCheckpoint(int index)
+{
+ std::string fname =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/CTestCheckpoint.txt";
+ cmsys::ofstream fout;
+ fout.open(fname.c_str(), std::ios::app);
+ fout << index << "\n";
+ fout.close();
+}
+
+void cmCTestMultiProcessHandler::MarkFinished()
+{
+ std::string fname =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/CTestCheckpoint.txt";
+ cmSystemTools::RemoveFile(fname);
+}
+
+static Json::Value DumpToJsonArray(const std::set<std::string>& values)
+{
+ Json::Value jsonArray = Json::arrayValue;
+ for (const auto& it : values) {
+ jsonArray.append(it);
+ }
+ return jsonArray;
+}
+
+static Json::Value DumpToJsonArray(const std::vector<std::string>& values)
+{
+ Json::Value jsonArray = Json::arrayValue;
+ for (const auto& it : values) {
+ jsonArray.append(it);
+ }
+ return jsonArray;
+}
+
+static Json::Value DumpRegExToJsonArray(
+ const std::vector<std::pair<cmsys::RegularExpression, std::string>>& values)
+{
+ Json::Value jsonArray = Json::arrayValue;
+ for (const auto& it : values) {
+ jsonArray.append(it.second);
+ }
+ return jsonArray;
+}
+
+static Json::Value DumpMeasurementToJsonArray(
+ const std::map<std::string, std::string>& values)
+{
+ Json::Value jsonArray = Json::arrayValue;
+ for (const auto& it : values) {
+ Json::Value measurement = Json::objectValue;
+ measurement["measurement"] = it.first;
+ measurement["value"] = it.second;
+ jsonArray.append(measurement);
+ }
+ return jsonArray;
+}
+
+static Json::Value DumpTimeoutAfterMatch(
+ cmCTestTestHandler::cmCTestTestProperties& testProperties)
+{
+ Json::Value timeoutAfterMatch = Json::objectValue;
+ timeoutAfterMatch["timeout"] = testProperties.AlternateTimeout.count();
+ timeoutAfterMatch["regex"] =
+ DumpRegExToJsonArray(testProperties.TimeoutRegularExpressions);
+ return timeoutAfterMatch;
+}
+
+static Json::Value DumpResourceGroupsToJsonArray(
+ const std::vector<
+ std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>&
+ resourceGroups)
+{
+ Json::Value jsonResourceGroups = Json::arrayValue;
+ for (auto const& it : resourceGroups) {
+ Json::Value jsonResourceGroup = Json::objectValue;
+ Json::Value requirements = Json::arrayValue;
+ for (auto const& it2 : it) {
+ Json::Value res = Json::objectValue;
+ res[".type"] = it2.ResourceType;
+ // res[".units"] = it2.UnitsNeeded; // Intentionally commented out
+ res["slots"] = it2.SlotsNeeded;
+ requirements.append(res);
+ }
+ jsonResourceGroup["requirements"] = requirements;
+ jsonResourceGroups.append(jsonResourceGroup);
+ }
+ return jsonResourceGroups;
+}
+
+static Json::Value DumpCTestProperty(std::string const& name,
+ Json::Value value)
+{
+ Json::Value property = Json::objectValue;
+ property["name"] = name;
+ property["value"] = std::move(value);
+ return property;
+}
+
+static Json::Value DumpCTestProperties(
+ cmCTestTestHandler::cmCTestTestProperties& testProperties)
+{
+ Json::Value properties = Json::arrayValue;
+ if (!testProperties.AttachOnFail.empty()) {
+ properties.append(DumpCTestProperty(
+ "ATTACHED_FILES_ON_FAIL", DumpToJsonArray(testProperties.AttachOnFail)));
+ }
+ if (!testProperties.AttachedFiles.empty()) {
+ properties.append(DumpCTestProperty(
+ "ATTACHED_FILES", DumpToJsonArray(testProperties.AttachedFiles)));
+ }
+ if (testProperties.Cost != 0.0f) {
+ properties.append(
+ DumpCTestProperty("COST", static_cast<double>(testProperties.Cost)));
+ }
+ if (!testProperties.Depends.empty()) {
+ properties.append(
+ DumpCTestProperty("DEPENDS", DumpToJsonArray(testProperties.Depends)));
+ }
+ if (testProperties.Disabled) {
+ properties.append(DumpCTestProperty("DISABLED", testProperties.Disabled));
+ }
+ if (!testProperties.Environment.empty()) {
+ properties.append(DumpCTestProperty(
+ "ENVIRONMENT", DumpToJsonArray(testProperties.Environment)));
+ }
+ if (!testProperties.ErrorRegularExpressions.empty()) {
+ properties.append(DumpCTestProperty(
+ "FAIL_REGULAR_EXPRESSION",
+ DumpRegExToJsonArray(testProperties.ErrorRegularExpressions)));
+ }
+ if (!testProperties.SkipRegularExpressions.empty()) {
+ properties.append(DumpCTestProperty(
+ "SKIP_REGULAR_EXPRESSION",
+ DumpRegExToJsonArray(testProperties.SkipRegularExpressions)));
+ }
+ if (!testProperties.FixturesCleanup.empty()) {
+ properties.append(DumpCTestProperty(
+ "FIXTURES_CLEANUP", DumpToJsonArray(testProperties.FixturesCleanup)));
+ }
+ if (!testProperties.FixturesRequired.empty()) {
+ properties.append(DumpCTestProperty(
+ "FIXTURES_REQUIRED", DumpToJsonArray(testProperties.FixturesRequired)));
+ }
+ if (!testProperties.FixturesSetup.empty()) {
+ properties.append(DumpCTestProperty(
+ "FIXTURES_SETUP", DumpToJsonArray(testProperties.FixturesSetup)));
+ }
+ if (!testProperties.Labels.empty()) {
+ properties.append(
+ DumpCTestProperty("LABELS", DumpToJsonArray(testProperties.Labels)));
+ }
+ if (!testProperties.Measurements.empty()) {
+ properties.append(DumpCTestProperty(
+ "MEASUREMENT", DumpMeasurementToJsonArray(testProperties.Measurements)));
+ }
+ if (!testProperties.RequiredRegularExpressions.empty()) {
+ properties.append(DumpCTestProperty(
+ "PASS_REGULAR_EXPRESSION",
+ DumpRegExToJsonArray(testProperties.RequiredRegularExpressions)));
+ }
+ if (!testProperties.ResourceGroups.empty()) {
+ properties.append(DumpCTestProperty(
+ "RESOURCE_GROUPS",
+ DumpResourceGroupsToJsonArray(testProperties.ResourceGroups)));
+ }
+ if (testProperties.WantAffinity) {
+ properties.append(
+ DumpCTestProperty("PROCESSOR_AFFINITY", testProperties.WantAffinity));
+ }
+ if (testProperties.Processors != 1) {
+ properties.append(
+ DumpCTestProperty("PROCESSORS", testProperties.Processors));
+ }
+ if (!testProperties.RequiredFiles.empty()) {
+ properties.append(DumpCTestProperty(
+ "REQUIRED_FILES", DumpToJsonArray(testProperties.RequiredFiles)));
+ }
+ if (!testProperties.LockedResources.empty()) {
+ properties.append(DumpCTestProperty(
+ "RESOURCE_LOCK", DumpToJsonArray(testProperties.LockedResources)));
+ }
+ if (testProperties.RunSerial) {
+ properties.append(
+ DumpCTestProperty("RUN_SERIAL", testProperties.RunSerial));
+ }
+ if (testProperties.SkipReturnCode != -1) {
+ properties.append(
+ DumpCTestProperty("SKIP_RETURN_CODE", testProperties.SkipReturnCode));
+ }
+ if (testProperties.ExplicitTimeout) {
+ properties.append(
+ DumpCTestProperty("TIMEOUT", testProperties.Timeout.count()));
+ }
+ if (!testProperties.TimeoutRegularExpressions.empty()) {
+ properties.append(DumpCTestProperty(
+ "TIMEOUT_AFTER_MATCH", DumpTimeoutAfterMatch(testProperties)));
+ }
+ if (testProperties.WillFail) {
+ properties.append(DumpCTestProperty("WILL_FAIL", testProperties.WillFail));
+ }
+ if (!testProperties.Directory.empty()) {
+ properties.append(
+ DumpCTestProperty("WORKING_DIRECTORY", testProperties.Directory));
+ }
+ return properties;
+}
+
+class BacktraceData
+{
+ std::unordered_map<std::string, Json::ArrayIndex> CommandMap;
+ std::unordered_map<std::string, Json::ArrayIndex> FileMap;
+ std::unordered_map<cmListFileContext const*, Json::ArrayIndex> NodeMap;
+ Json::Value Commands = Json::arrayValue;
+ Json::Value Files = Json::arrayValue;
+ Json::Value Nodes = Json::arrayValue;
+
+ Json::ArrayIndex AddCommand(std::string const& command)
+ {
+ auto i = this->CommandMap.find(command);
+ if (i == this->CommandMap.end()) {
+ i = this->CommandMap.emplace(command, this->Commands.size()).first;
+ this->Commands.append(command);
+ }
+ return i->second;
+ }
+
+ Json::ArrayIndex AddFile(std::string const& file)
+ {
+ auto i = this->FileMap.find(file);
+ if (i == this->FileMap.end()) {
+ i = this->FileMap.emplace(file, this->Files.size()).first;
+ this->Files.append(file);
+ }
+ return i->second;
+ }
+
+public:
+ bool Add(cmListFileBacktrace const& bt, Json::ArrayIndex& index);
+ Json::Value Dump();
+};
+
+bool BacktraceData::Add(cmListFileBacktrace const& bt, Json::ArrayIndex& index)
+{
+ if (bt.Empty()) {
+ return false;
+ }
+ cmListFileContext const* top = &bt.Top();
+ auto found = this->NodeMap.find(top);
+ if (found != this->NodeMap.end()) {
+ index = found->second;
+ return true;
+ }
+ Json::Value entry = Json::objectValue;
+ entry["file"] = this->AddFile(top->FilePath);
+ if (top->Line) {
+ entry["line"] = static_cast<int>(top->Line);
+ }
+ if (!top->Name.empty()) {
+ entry["command"] = this->AddCommand(top->Name);
+ }
+ Json::ArrayIndex parent;
+ if (this->Add(bt.Pop(), parent)) {
+ entry["parent"] = parent;
+ }
+ index = this->NodeMap[top] = this->Nodes.size();
+ this->Nodes.append(std::move(entry)); // NOLINT(*)
+ return true;
+}
+
+Json::Value BacktraceData::Dump()
+{
+ Json::Value backtraceGraph;
+ this->CommandMap.clear();
+ this->FileMap.clear();
+ this->NodeMap.clear();
+ backtraceGraph["commands"] = std::move(this->Commands);
+ backtraceGraph["files"] = std::move(this->Files);
+ backtraceGraph["nodes"] = std::move(this->Nodes);
+ return backtraceGraph;
+}
+
+static void AddBacktrace(BacktraceData& backtraceGraph, Json::Value& object,
+ cmListFileBacktrace const& bt)
+{
+ Json::ArrayIndex backtrace;
+ if (backtraceGraph.Add(bt, backtrace)) {
+ object["backtrace"] = backtrace;
+ }
+}
+
+static Json::Value DumpCTestInfo(
+ cmCTestRunTest& testRun,
+ cmCTestTestHandler::cmCTestTestProperties& testProperties,
+ BacktraceData& backtraceGraph)
+{
+ Json::Value testInfo = Json::objectValue;
+ // test name should always be present
+ testInfo["name"] = testProperties.Name;
+ std::string const& config = testRun.GetCTest()->GetConfigType();
+ if (!config.empty()) {
+ testInfo["config"] = config;
+ }
+ std::string const& command = testRun.GetActualCommand();
+ if (!command.empty()) {
+ std::vector<std::string> commandAndArgs;
+ commandAndArgs.push_back(command);
+ const std::vector<std::string>& args = testRun.GetArguments();
+ if (!args.empty()) {
+ commandAndArgs.reserve(args.size() + 1);
+ cm::append(commandAndArgs, args);
+ }
+ testInfo["command"] = DumpToJsonArray(commandAndArgs);
+ }
+ Json::Value properties = DumpCTestProperties(testProperties);
+ if (!properties.empty()) {
+ testInfo["properties"] = properties;
+ }
+ if (!testProperties.Backtrace.Empty()) {
+ AddBacktrace(backtraceGraph, testInfo, testProperties.Backtrace);
+ }
+ return testInfo;
+}
+
+static Json::Value DumpVersion(int major, int minor)
+{
+ Json::Value version = Json::objectValue;
+ version["major"] = major;
+ version["minor"] = minor;
+ return version;
+}
+
+void cmCTestMultiProcessHandler::PrintOutputAsJson()
+{
+ this->TestHandler->SetMaxIndex(this->FindMaxIndex());
+
+ Json::Value result = Json::objectValue;
+ result["kind"] = "ctestInfo";
+ result["version"] = DumpVersion(1, 0);
+
+ BacktraceData backtraceGraph;
+ Json::Value tests = Json::arrayValue;
+ for (auto& it : this->Properties) {
+ cmCTestTestHandler::cmCTestTestProperties& p = *it.second;
+
+ // Don't worry if this fails, we are only showing the test list, not
+ // running the tests
+ cmWorkingDirectory workdir(p.Directory);
+ cmCTestRunTest testRun(*this);
+ testRun.SetIndex(p.Index);
+ testRun.SetTestProperties(&p);
+ testRun.ComputeArguments();
+
+ // Skip tests not available in this configuration.
+ if (p.Args.size() >= 2 && p.Args[1] == "NOT_AVAILABLE") {
+ continue;
+ }
+
+ Json::Value testInfo = DumpCTestInfo(testRun, p, backtraceGraph);
+ tests.append(testInfo);
+ }
+ result["backtraceGraph"] = backtraceGraph.Dump();
+ result["tests"] = std::move(tests);
+
+ Json::StreamWriterBuilder builder;
+ builder["indentation"] = " ";
+ std::unique_ptr<Json::StreamWriter> jout(builder.newStreamWriter());
+ jout->write(result, &std::cout);
+}
+
+// For ShowOnly mode
+void cmCTestMultiProcessHandler::PrintTestList()
+{
+ if (this->CTest->GetOutputAsJson()) {
+ this->PrintOutputAsJson();
+ return;
+ }
+
+ this->TestHandler->SetMaxIndex(this->FindMaxIndex());
+ int count = 0;
+
+ for (auto& it : this->Properties) {
+ count++;
+ cmCTestTestHandler::cmCTestTestProperties& p = *it.second;
+
+ // Don't worry if this fails, we are only showing the test list, not
+ // running the tests
+ cmWorkingDirectory workdir(p.Directory);
+
+ cmCTestRunTest testRun(*this);
+ testRun.SetIndex(p.Index);
+ testRun.SetTestProperties(&p);
+ testRun.ComputeArguments(); // logs the command in verbose mode
+
+ if (!p.Labels.empty()) // print the labels
+ {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Labels:", this->Quiet);
+ }
+ for (std::string const& label : p.Labels) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " " << label,
+ this->Quiet);
+ }
+ if (!p.Labels.empty()) // print the labels
+ {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl,
+ this->Quiet);
+ }
+
+ if (this->TestHandler->MemCheck) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Memory Check",
+ this->Quiet);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Test", this->Quiet);
+ }
+ std::ostringstream indexStr;
+ indexStr << " #" << p.Index << ":";
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ std::setw(3 + getNumWidth(this->TestHandler->GetMaxIndex()))
+ << indexStr.str(),
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " " << p.Name,
+ this->Quiet);
+ if (p.Disabled) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " (Disabled)",
+ this->Quiet);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, std::endl, this->Quiet);
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ std::endl
+ << "Total Tests: " << this->Total << std::endl,
+ this->Quiet);
+}
+
+void cmCTestMultiProcessHandler::PrintLabels()
+{
+ std::set<std::string> allLabels;
+ for (auto& it : this->Properties) {
+ cmCTestTestHandler::cmCTestTestProperties& p = *it.second;
+ allLabels.insert(p.Labels.begin(), p.Labels.end());
+ }
+
+ if (!allLabels.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "All Labels:" << std::endl,
+ this->Quiet);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "No Labels Exist" << std::endl, this->Quiet);
+ }
+ for (std::string const& label : allLabels) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " " << label << std::endl,
+ this->Quiet);
+ }
+}
+
+void cmCTestMultiProcessHandler::CheckResume()
+{
+ std::string fname =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/CTestCheckpoint.txt";
+ if (this->CTest->GetFailover()) {
+ if (cmSystemTools::FileExists(fname, true)) {
+ *this->TestHandler->LogFile
+ << "Resuming previously interrupted test set" << std::endl
+ << "----------------------------------------------------------"
+ << std::endl;
+
+ cmsys::ifstream fin;
+ fin.open(fname.c_str());
+ std::string line;
+ while (std::getline(fin, line)) {
+ int index = atoi(line.c_str());
+ this->RemoveTest(index);
+ }
+ fin.close();
+ }
+ } else if (cmSystemTools::FileExists(fname, true)) {
+ cmSystemTools::RemoveFile(fname);
+ }
+}
+
+void cmCTestMultiProcessHandler::RemoveTest(int index)
+{
+ this->EraseTest(index);
+ this->Properties.erase(index);
+ this->TestRunningMap[index] = false;
+ this->TestFinishMap[index] = true;
+ this->Completed++;
+}
+
+int cmCTestMultiProcessHandler::FindMaxIndex()
+{
+ int max = 0;
+ for (auto const& i : this->Tests) {
+ if (i.first > max) {
+ max = i.first;
+ }
+ }
+ return max;
+}
+
+// Returns true if no cycles exist in the dependency graph
+bool cmCTestMultiProcessHandler::CheckCycles()
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Checking test dependency graph..." << std::endl,
+ this->Quiet);
+ for (auto const& it : this->Tests) {
+ // DFS from each element to itself
+ int root = it.first;
+ std::set<int> visited;
+ std::stack<int> s;
+ s.push(root);
+ while (!s.empty()) {
+ int test = s.top();
+ s.pop();
+ if (visited.insert(test).second) {
+ for (auto const& d : this->Tests[test]) {
+ if (d == root) {
+ // cycle exists
+ cmCTestLog(
+ this->CTest, ERROR_MESSAGE,
+ "Error: a cycle exists in the test dependency graph "
+ "for the test \""
+ << this->Properties[root]->Name
+ << "\".\nPlease fix the cycle and run ctest again.\n");
+ return false;
+ }
+ s.push(d);
+ }
+ }
+ }
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Checking test dependency graph end" << std::endl,
+ this->Quiet);
+ return true;
+}
diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h
new file mode 100644
index 0000000..5de42f9
--- /dev/null
+++ b/Source/CTest/cmCTestMultiProcessHandler.h
@@ -0,0 +1,201 @@
+/* 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 <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <cm3p/uv.h>
+#include <stddef.h>
+
+#include "cmCTest.h"
+#include "cmCTestResourceAllocator.h"
+#include "cmCTestTestHandler.h"
+#include "cmUVHandlePtr.h"
+
+struct cmCTestBinPackerAllocation;
+class cmCTestResourceSpec;
+class cmCTestRunTest;
+
+/** \class cmCTestMultiProcessHandler
+ * \brief run parallel ctest
+ *
+ * cmCTestMultiProcessHandler
+ */
+class cmCTestMultiProcessHandler
+{
+ friend class TestComparator;
+ friend class cmCTestRunTest;
+
+public:
+ struct TestSet : public std::set<int>
+ {
+ };
+ struct TestMap : public std::map<int, TestSet>
+ {
+ };
+ struct TestList : public std::vector<int>
+ {
+ };
+ struct PropertiesMap
+ : public std::map<int, cmCTestTestHandler::cmCTestTestProperties*>
+ {
+ };
+ struct ResourceAllocation
+ {
+ std::string Id;
+ unsigned int Slots;
+ };
+
+ cmCTestMultiProcessHandler();
+ virtual ~cmCTestMultiProcessHandler();
+ // Set the tests
+ void SetTests(TestMap& tests, PropertiesMap& properties);
+ // Set the max number of tests that can be run at the same time.
+ void SetParallelLevel(size_t);
+ void SetTestLoad(unsigned long load);
+ virtual void RunTests();
+ void PrintOutputAsJson();
+ void PrintTestList();
+ void PrintLabels();
+
+ void SetPassFailVectors(std::vector<std::string>* passed,
+ std::vector<std::string>* failed)
+ {
+ this->Passed = passed;
+ this->Failed = failed;
+ }
+ void SetTestResults(std::vector<cmCTestTestHandler::cmCTestTestResult>* r)
+ {
+ this->TestResults = r;
+ }
+
+ void SetCTest(cmCTest* ctest) { this->CTest = ctest; }
+
+ void SetTestHandler(cmCTestTestHandler* handler)
+ {
+ this->TestHandler = handler;
+ }
+
+ cmCTestTestHandler* GetTestHandler() { return this->TestHandler; }
+
+ void SetRepeatMode(cmCTest::Repeat mode, int count)
+ {
+ this->RepeatMode = mode;
+ this->RepeatCount = count;
+ }
+
+ void SetQuiet(bool b) { this->Quiet = b; }
+
+ void InitResourceAllocator(const cmCTestResourceSpec& spec)
+ {
+ this->ResourceAllocator.InitializeFromResourceSpec(spec);
+ }
+
+ void CheckResourcesAvailable();
+
+protected:
+ // Start the next test or tests as many as are allowed by
+ // ParallelLevel
+ void StartNextTests();
+ bool StartTestProcess(int test);
+ bool StartTest(int test);
+ // Mark the checkpoint for the given test
+ void WriteCheckpoint(int index);
+
+ void UpdateCostData();
+ void ReadCostData();
+ // Return index of a test based on its name
+ int SearchByName(std::string const& name);
+
+ void CreateTestCostList();
+
+ void GetAllTestDependencies(int test, TestList& dependencies);
+ void CreateSerialTestCostList();
+
+ void CreateParallelTestCostList();
+
+ // Removes the checkpoint file
+ void MarkFinished();
+ void EraseTest(int index);
+ void FinishTestProcess(std::unique_ptr<cmCTestRunTest> runner, bool started);
+
+ static void OnTestLoadRetryCB(uv_timer_t* timer);
+
+ void RemoveTest(int index);
+ // Check if we need to resume an interrupted test set
+ void CheckResume();
+ // Check if there are any circular dependencies
+ bool CheckCycles();
+ int FindMaxIndex();
+ inline size_t GetProcessorsUsed(int index);
+ std::string GetName(int index);
+
+ bool CheckStopOnFailure();
+
+ bool CheckStopTimePassed();
+ void SetStopTimePassed();
+
+ void LockResources(int index);
+ void UnlockResources(int index);
+
+ enum class ResourceAllocationError
+ {
+ NoResourceType,
+ InsufficientResources,
+ };
+
+ bool AllocateResources(int index);
+ bool TryAllocateResources(
+ int index,
+ std::map<std::string, std::vector<cmCTestBinPackerAllocation>>&
+ allocations,
+ std::map<std::string, ResourceAllocationError>* errors = nullptr);
+ void DeallocateResources(int index);
+ bool AllResourcesAvailable();
+
+ // map from test number to set of depend tests
+ TestMap Tests;
+ TestList SortedTests;
+ // Total number of tests we'll be running
+ size_t Total;
+ // Number of tests that are complete
+ size_t Completed;
+ size_t RunningCount;
+ std::set<size_t> ProcessorsAvailable;
+ size_t HaveAffinity;
+ bool StopTimePassed = false;
+ // list of test properties (indices concurrent to the test map)
+ PropertiesMap Properties;
+ std::map<int, bool> TestRunningMap;
+ std::map<int, bool> TestFinishMap;
+ std::map<int, std::string> TestOutput;
+ std::vector<std::string>* Passed;
+ std::vector<std::string>* Failed;
+ std::vector<std::string> LastTestsFailed;
+ std::set<std::string> LockedResources;
+ std::map<int,
+ std::vector<std::map<std::string, std::vector<ResourceAllocation>>>>
+ AllocatedResources;
+ std::map<int, std::map<std::string, ResourceAllocationError>>
+ ResourceAllocationErrors;
+ cmCTestResourceAllocator ResourceAllocator;
+ std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults;
+ size_t ParallelLevel; // max number of process that can be run at once
+ unsigned long TestLoad;
+ unsigned long FakeLoadForTesting;
+ uv_loop_t Loop;
+ cm::uv_timer_ptr TestLoadRetryTimer;
+ cmCTestTestHandler* TestHandler;
+ cmCTest* CTest;
+ bool HasCycles;
+ cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never;
+ int RepeatCount = 1;
+ bool Quiet;
+ bool SerialTestRunning;
+};
diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx
new file mode 100644
index 0000000..50c9c16
--- /dev/null
+++ b/Source/CTest/cmCTestP4.cxx
@@ -0,0 +1,527 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestP4.h"
+
+#include <algorithm>
+#include <ctime>
+#include <ostream>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCTest.h"
+#include "cmCTestVC.h"
+#include "cmProcessTools.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmCTestP4::cmCTestP4(cmCTest* ct, std::ostream& log)
+ : cmCTestGlobalVC(ct, log)
+{
+ this->PriorRev = this->Unknown;
+}
+
+cmCTestP4::~cmCTestP4() = default;
+
+class cmCTestP4::IdentifyParser : public cmCTestVC::LineParser
+{
+public:
+ IdentifyParser(cmCTestP4* p4, const char* prefix, std::string& rev)
+ : Rev(rev)
+ {
+ this->SetLog(&p4->Log, prefix);
+ this->RegexIdentify.compile("^Change ([0-9]+) on");
+ }
+
+private:
+ std::string& Rev;
+ cmsys::RegularExpression RegexIdentify;
+
+ bool ProcessLine() override
+ {
+ if (this->RegexIdentify.find(this->Line)) {
+ this->Rev = this->RegexIdentify.match(1);
+ return false;
+ }
+ return true;
+ }
+};
+
+class cmCTestP4::ChangesParser : public cmCTestVC::LineParser
+{
+public:
+ ChangesParser(cmCTestP4* p4, const char* prefix)
+ : P4(p4)
+ {
+ this->SetLog(&this->P4->Log, prefix);
+ this->RegexIdentify.compile("^Change ([0-9]+) on");
+ }
+
+private:
+ cmsys::RegularExpression RegexIdentify;
+ cmCTestP4* P4;
+
+ bool ProcessLine() override
+ {
+ if (this->RegexIdentify.find(this->Line)) {
+ this->P4->ChangeLists.push_back(this->RegexIdentify.match(1));
+ }
+ return true;
+ }
+};
+
+class cmCTestP4::UserParser : public cmCTestVC::LineParser
+{
+public:
+ UserParser(cmCTestP4* p4, const char* prefix)
+ : P4(p4)
+ {
+ this->SetLog(&this->P4->Log, prefix);
+ this->RegexUser.compile("^(.+) <(.*)> \\((.*)\\) accessed (.*)$");
+ }
+
+private:
+ cmsys::RegularExpression RegexUser;
+ cmCTestP4* P4;
+
+ bool ProcessLine() override
+ {
+ if (this->RegexUser.find(this->Line)) {
+ User NewUser;
+
+ NewUser.UserName = this->RegexUser.match(1);
+ NewUser.EMail = this->RegexUser.match(2);
+ NewUser.Name = this->RegexUser.match(3);
+ NewUser.AccessTime = this->RegexUser.match(4);
+ this->P4->Users[this->RegexUser.match(1)] = NewUser;
+
+ return false;
+ }
+ return true;
+ }
+};
+
+/* Diff format:
+==== //depot/file#rev - /absolute/path/to/file ====
+(diff data)
+==== //depot/file2#rev - /absolute/path/to/file2 ====
+(diff data)
+==== //depot/file3#rev - /absolute/path/to/file3 ====
+==== //depot/file4#rev - /absolute/path/to/file4 ====
+(diff data)
+*/
+class cmCTestP4::DiffParser : public cmCTestVC::LineParser
+{
+public:
+ DiffParser(cmCTestP4* p4, const char* prefix)
+ : P4(p4)
+ , AlreadyNotified(false)
+ {
+ this->SetLog(&this->P4->Log, prefix);
+ this->RegexDiff.compile("^==== (.*)#[0-9]+ - (.*)");
+ }
+
+private:
+ cmCTestP4* P4;
+ bool AlreadyNotified;
+ std::string CurrentPath;
+ cmsys::RegularExpression RegexDiff;
+
+ bool ProcessLine() override
+ {
+ if (!this->Line.empty() && this->Line[0] == '=' &&
+ this->RegexDiff.find(this->Line)) {
+ this->CurrentPath = this->RegexDiff.match(1);
+ this->AlreadyNotified = false;
+ } else {
+ if (!this->AlreadyNotified) {
+ this->P4->DoModification(PathModified, this->CurrentPath);
+ this->AlreadyNotified = true;
+ }
+ }
+ return true;
+ }
+};
+
+cmCTestP4::User cmCTestP4::GetUserData(const std::string& username)
+{
+ auto it = this->Users.find(username);
+
+ if (it == this->Users.end()) {
+ std::vector<char const*> p4_users;
+ this->SetP4Options(p4_users);
+ p4_users.push_back("users");
+ p4_users.push_back("-m");
+ p4_users.push_back("1");
+ p4_users.push_back(username.c_str());
+ p4_users.push_back(nullptr);
+
+ UserParser out(this, "users-out> ");
+ OutputLogger err(this->Log, "users-err> ");
+ this->RunChild(&p4_users[0], &out, &err);
+
+ // The user should now be added to the map. Search again.
+ it = this->Users.find(username);
+ if (it == this->Users.end()) {
+ return cmCTestP4::User();
+ }
+ }
+
+ return it->second;
+}
+
+/* Commit format:
+
+Change 1111111 by user@client on 2013/09/26 11:50:36
+
+ text
+ text
+
+Affected files ...
+
+... //path/to/file#rev edit
+... //path/to/file#rev add
+... //path/to/file#rev delete
+... //path/to/file#rev integrate
+*/
+class cmCTestP4::DescribeParser : public cmCTestVC::LineParser
+{
+public:
+ DescribeParser(cmCTestP4* p4, const char* prefix)
+ : LineParser('\n', false)
+ , P4(p4)
+ , Section(SectionHeader)
+ {
+ this->SetLog(&this->P4->Log, prefix);
+ this->RegexHeader.compile("^Change ([0-9]+) by (.+)@(.+) on (.*)$");
+ this->RegexDiff.compile(R"(^\.\.\. (.*)#[0-9]+ ([^ ]+)$)");
+ }
+
+private:
+ cmsys::RegularExpression RegexHeader;
+ cmsys::RegularExpression RegexDiff;
+ cmCTestP4* P4;
+
+ using Revision = cmCTestP4::Revision;
+ using Change = cmCTestP4::Change;
+ std::vector<Change> Changes;
+ enum SectionType
+ {
+ SectionHeader,
+ SectionBody,
+ SectionDiffHeader,
+ SectionDiff,
+ SectionCount
+ };
+ SectionType Section;
+ Revision Rev;
+
+ bool ProcessLine() override
+ {
+ if (this->Line.empty()) {
+ this->NextSection();
+ } else {
+ switch (this->Section) {
+ case SectionHeader:
+ this->DoHeaderLine();
+ break;
+ case SectionBody:
+ this->DoBodyLine();
+ break;
+ case SectionDiffHeader:
+ break; // nothing to do
+ case SectionDiff:
+ this->DoDiffLine();
+ break;
+ case SectionCount:
+ break; // never happens
+ }
+ }
+ return true;
+ }
+
+ void NextSection()
+ {
+ if (this->Section == SectionDiff) {
+ this->P4->DoRevision(this->Rev, this->Changes);
+ this->Rev = Revision();
+ }
+
+ this->Section = SectionType((this->Section + 1) % SectionCount);
+ }
+
+ void DoHeaderLine()
+ {
+ if (this->RegexHeader.find(this->Line)) {
+ this->Rev.Rev = this->RegexHeader.match(1);
+ this->Rev.Date = this->RegexHeader.match(4);
+
+ cmCTestP4::User user = this->P4->GetUserData(this->RegexHeader.match(2));
+ this->Rev.Author = user.Name;
+ this->Rev.EMail = user.EMail;
+
+ this->Rev.Committer = this->Rev.Author;
+ this->Rev.CommitterEMail = this->Rev.EMail;
+ this->Rev.CommitDate = this->Rev.Date;
+ }
+ }
+
+ void DoBodyLine()
+ {
+ if (this->Line[0] == '\t') {
+ this->Rev.Log += this->Line.substr(1);
+ }
+ this->Rev.Log += "\n";
+ }
+
+ void DoDiffLine()
+ {
+ if (this->RegexDiff.find(this->Line)) {
+ Change change;
+ std::string Path = this->RegexDiff.match(1);
+ if (Path.length() > 2 && Path[0] == '/' && Path[1] == '/') {
+ size_t found = Path.find('/', 2);
+ if (found != std::string::npos) {
+ Path = Path.substr(found + 1);
+ }
+ }
+
+ change.Path = Path;
+ std::string action = this->RegexDiff.match(2);
+
+ if (action == "add") {
+ change.Action = 'A';
+ } else if (action == "delete") {
+ change.Action = 'D';
+ } else if (action == "edit" || action == "integrate") {
+ change.Action = 'M';
+ }
+
+ this->Changes.push_back(change);
+ }
+ }
+};
+
+void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions)
+{
+ if (this->P4Options.empty()) {
+ const char* p4 = this->CommandLineTool.c_str();
+ this->P4Options.emplace_back(p4);
+
+ // The CTEST_P4_CLIENT variable sets the P4 client used when issuing
+ // Perforce commands, if it's different from the default one.
+ std::string client = this->CTest->GetCTestConfiguration("P4Client");
+ if (!client.empty()) {
+ this->P4Options.emplace_back("-c");
+ this->P4Options.push_back(client);
+ }
+
+ // Set the message language to be English, in case the P4 admin
+ // has localized them
+ this->P4Options.emplace_back("-L");
+ this->P4Options.emplace_back("en");
+
+ // The CTEST_P4_OPTIONS variable adds additional Perforce command line
+ // options before the main command
+ std::string opts = this->CTest->GetCTestConfiguration("P4Options");
+ cm::append(this->P4Options, cmSystemTools::ParseArguments(opts));
+ }
+
+ CommandOptions.clear();
+ for (std::string const& o : this->P4Options) {
+ CommandOptions.push_back(o.c_str());
+ }
+}
+
+std::string cmCTestP4::GetWorkingRevision()
+{
+ std::vector<char const*> p4_identify;
+ this->SetP4Options(p4_identify);
+
+ p4_identify.push_back("changes");
+ p4_identify.push_back("-m");
+ p4_identify.push_back("1");
+ p4_identify.push_back("-t");
+
+ std::string source = this->SourceDirectory + "/...#have";
+ p4_identify.push_back(source.c_str());
+ p4_identify.push_back(nullptr);
+
+ std::string rev;
+ IdentifyParser out(this, "p4_changes-out> ", rev);
+ OutputLogger err(this->Log, "p4_changes-err> ");
+
+ bool result = this->RunChild(&p4_identify[0], &out, &err);
+
+ // If there was a problem contacting the server return "<unknown>"
+ if (!result) {
+ return "<unknown>";
+ }
+
+ if (rev.empty()) {
+ return "0";
+ }
+ return rev;
+}
+
+bool cmCTestP4::NoteOldRevision()
+{
+ this->OldRevision = this->GetWorkingRevision();
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Old revision of repository is: " << this->OldRevision
+ << "\n");
+ this->PriorRev.Rev = this->OldRevision;
+ return true;
+}
+
+bool cmCTestP4::NoteNewRevision()
+{
+ this->NewRevision = this->GetWorkingRevision();
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " New revision of repository is: " << this->NewRevision
+ << "\n");
+ return true;
+}
+
+bool cmCTestP4::LoadRevisions()
+{
+ std::vector<char const*> p4_changes;
+ this->SetP4Options(p4_changes);
+
+ // Use 'p4 changes ...@old,new' to get a list of changelists
+ std::string range = this->SourceDirectory + "/...";
+
+ // If any revision is unknown it means we couldn't contact the server.
+ // Do not process updates
+ if (this->OldRevision == "<unknown>" || this->NewRevision == "<unknown>") {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " At least one of the revisions "
+ << "is unknown. No repository changes will be reported.\n");
+ return false;
+ }
+
+ range.append("@")
+ .append(this->OldRevision)
+ .append(",")
+ .append(this->NewRevision);
+
+ p4_changes.push_back("changes");
+ p4_changes.push_back(range.c_str());
+ p4_changes.push_back(nullptr);
+
+ ChangesParser out(this, "p4_changes-out> ");
+ OutputLogger err(this->Log, "p4_changes-err> ");
+
+ this->ChangeLists.clear();
+ this->RunChild(&p4_changes[0], &out, &err);
+
+ if (this->ChangeLists.empty()) {
+ return true;
+ }
+
+ // p4 describe -s ...@1111111,2222222
+ std::vector<char const*> p4_describe;
+ for (std::string const& i : cmReverseRange(this->ChangeLists)) {
+ this->SetP4Options(p4_describe);
+ p4_describe.push_back("describe");
+ p4_describe.push_back("-s");
+ p4_describe.push_back(i.c_str());
+ p4_describe.push_back(nullptr);
+
+ DescribeParser outDescribe(this, "p4_describe-out> ");
+ OutputLogger errDescribe(this->Log, "p4_describe-err> ");
+ this->RunChild(&p4_describe[0], &outDescribe, &errDescribe);
+ }
+ return true;
+}
+
+bool cmCTestP4::LoadModifications()
+{
+ std::vector<char const*> p4_diff;
+ this->SetP4Options(p4_diff);
+
+ p4_diff.push_back("diff");
+
+ // Ideally we would use -Od but not all clients support it
+ p4_diff.push_back("-dn");
+ std::string source = this->SourceDirectory + "/...";
+ p4_diff.push_back(source.c_str());
+ p4_diff.push_back(nullptr);
+
+ DiffParser out(this, "p4_diff-out> ");
+ OutputLogger err(this->Log, "p4_diff-err> ");
+ this->RunChild(&p4_diff[0], &out, &err);
+ return true;
+}
+
+bool cmCTestP4::UpdateCustom(const std::string& custom)
+{
+ std::vector<std::string> p4_custom_command = cmExpandedList(custom, true);
+
+ std::vector<char const*> p4_custom;
+ p4_custom.reserve(p4_custom_command.size() + 1);
+ for (std::string const& i : p4_custom_command) {
+ p4_custom.push_back(i.c_str());
+ }
+ p4_custom.push_back(nullptr);
+
+ OutputLogger custom_out(this->Log, "p4_customsync-out> ");
+ OutputLogger custom_err(this->Log, "p4_customsync-err> ");
+
+ return this->RunUpdateCommand(&p4_custom[0], &custom_out, &custom_err);
+}
+
+bool cmCTestP4::UpdateImpl()
+{
+ std::string custom = this->CTest->GetCTestConfiguration("P4UpdateCustom");
+ if (!custom.empty()) {
+ return this->UpdateCustom(custom);
+ }
+
+ // If we couldn't get a revision number before updating, abort.
+ if (this->OldRevision == "<unknown>") {
+ this->UpdateCommandLine = "Unknown current revision";
+ cmCTestLog(this->CTest, ERROR_MESSAGE, " Unknown current revision\n");
+ return false;
+ }
+
+ std::vector<char const*> p4_sync;
+ this->SetP4Options(p4_sync);
+
+ p4_sync.push_back("sync");
+
+ // Get user-specified update options.
+ std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
+ if (opts.empty()) {
+ opts = this->CTest->GetCTestConfiguration("P4UpdateOptions");
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
+ for (std::string const& arg : args) {
+ p4_sync.push_back(arg.c_str());
+ }
+
+ std::string source = this->SourceDirectory + "/...";
+
+ // Specify the start time for nightly testing.
+ if (this->CTest->GetTestModel() == cmCTest::NIGHTLY) {
+ std::string date = this->GetNightlyTime();
+ // CTest reports the date as YYYY-MM-DD, Perforce needs it as YYYY/MM/DD
+ std::replace(date.begin(), date.end(), '-', '/');
+
+ // Revision specification: /...@"YYYY/MM/DD HH:MM:SS"
+ source.append("@\"").append(date).append("\"");
+ }
+
+ p4_sync.push_back(source.c_str());
+ p4_sync.push_back(nullptr);
+
+ OutputLogger out(this->Log, "p4_sync-out> ");
+ OutputLogger err(this->Log, "p4_sync-err> ");
+
+ return this->RunUpdateCommand(&p4_sync[0], &out, &err);
+}
diff --git a/Source/CTest/cmCTestP4.h b/Source/CTest/cmCTestP4.h
new file mode 100644
index 0000000..d03f9cb
--- /dev/null
+++ b/Source/CTest/cmCTestP4.h
@@ -0,0 +1,73 @@
+/* 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 <iosfwd>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "cmCTestGlobalVC.h"
+
+class cmCTest;
+
+/** \class cmCTestP4
+ * \brief Interaction with the Perforce command-line tool
+ *
+ */
+class cmCTestP4 : public cmCTestGlobalVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestP4(cmCTest* ctest, std::ostream& log);
+
+ ~cmCTestP4() override;
+
+private:
+ std::vector<std::string> ChangeLists;
+
+ struct User
+ {
+ std::string UserName;
+ std::string Name;
+ std::string EMail;
+ std::string AccessTime;
+
+ User()
+ : UserName()
+ , Name()
+ , EMail()
+ , AccessTime()
+ {
+ }
+ };
+ std::map<std::string, User> Users;
+ std::vector<std::string> P4Options;
+
+ User GetUserData(const std::string& username);
+ void SetP4Options(std::vector<char const*>& options);
+
+ std::string GetWorkingRevision();
+ bool NoteOldRevision() override;
+ bool NoteNewRevision() override;
+ bool UpdateImpl() override;
+ bool UpdateCustom(const std::string& custom);
+
+ bool LoadRevisions() override;
+ bool LoadModifications() override;
+
+ class ChangesParser;
+ class DescribeParser;
+ class DiffParser;
+ // Parsing helper classes.
+ class IdentifyParser;
+ class UserParser;
+
+ friend class IdentifyParser;
+ friend class ChangesParser;
+ friend class UserParser;
+ friend class DescribeParser;
+ friend class DiffParser;
+};
diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.cxx b/Source/CTest/cmCTestReadCustomFilesCommand.cxx
new file mode 100644
index 0000000..a25cca4
--- /dev/null
+++ b/Source/CTest/cmCTestReadCustomFilesCommand.cxx
@@ -0,0 +1,22 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestReadCustomFilesCommand.h"
+
+#include "cmCTest.h"
+
+class cmExecutionStatus;
+
+bool cmCTestReadCustomFilesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus& /*unused*/)
+{
+ if (args.empty()) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ for (std::string const& arg : args) {
+ this->CTest->ReadCustomConfigurationFileTree(arg, this->Makefile);
+ }
+
+ return true;
+}
diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.h b/Source/CTest/cmCTestReadCustomFilesCommand.h
new file mode 100644
index 0000000..03714f6
--- /dev/null
+++ b/Source/CTest/cmCTestReadCustomFilesCommand.h
@@ -0,0 +1,45 @@
+/* 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 <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmCTestCommand.h"
+#include "cmCommand.h"
+
+class cmExecutionStatus;
+
+/** \class cmCTestReadCustomFiles
+ * \brief Run a ctest script
+ *
+ * cmLibrarysCommand defines a list of executable (i.e., test)
+ * programs to create.
+ */
+class cmCTestReadCustomFilesCommand : public cmCTestCommand
+{
+public:
+ cmCTestReadCustomFilesCommand() {}
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ auto ni = cm::make_unique<cmCTestReadCustomFilesCommand>();
+ ni->CTest = this->CTest;
+ return std::unique_ptr<cmCommand>(std::move(ni));
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) override;
+};
diff --git a/Source/CTest/cmCTestResourceAllocator.cxx b/Source/CTest/cmCTestResourceAllocator.cxx
new file mode 100644
index 0000000..9d468a7
--- /dev/null
+++ b/Source/CTest/cmCTestResourceAllocator.cxx
@@ -0,0 +1,86 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmCTestResourceAllocator.h"
+
+#include <utility>
+#include <vector>
+
+#include "cmCTestResourceSpec.h"
+
+void cmCTestResourceAllocator::InitializeFromResourceSpec(
+ const cmCTestResourceSpec& spec)
+{
+ this->Resources.clear();
+
+ for (auto const& it : spec.LocalSocket.Resources) {
+ auto& res = this->Resources[it.first];
+ for (auto const& specRes : it.second) {
+ res[specRes.Id].Total = specRes.Capacity;
+ res[specRes.Id].Locked = 0;
+ }
+ }
+}
+
+const std::map<std::string,
+ std::map<std::string, cmCTestResourceAllocator::Resource>>&
+cmCTestResourceAllocator::GetResources() const
+{
+ return this->Resources;
+}
+
+bool cmCTestResourceAllocator::AllocateResource(const std::string& name,
+ const std::string& id,
+ unsigned int slots)
+{
+ auto it = this->Resources.find(name);
+ if (it == this->Resources.end()) {
+ return false;
+ }
+
+ auto resIt = it->second.find(id);
+ if (resIt == it->second.end()) {
+ return false;
+ }
+
+ if (resIt->second.Total < resIt->second.Locked + slots) {
+ return false;
+ }
+
+ resIt->second.Locked += slots;
+ return true;
+}
+
+bool cmCTestResourceAllocator::DeallocateResource(const std::string& name,
+ const std::string& id,
+ unsigned int slots)
+{
+ auto it = this->Resources.find(name);
+ if (it == this->Resources.end()) {
+ return false;
+ }
+
+ auto resIt = it->second.find(id);
+ if (resIt == it->second.end()) {
+ return false;
+ }
+
+ if (resIt->second.Locked < slots) {
+ return false;
+ }
+
+ resIt->second.Locked -= slots;
+ return true;
+}
+
+bool cmCTestResourceAllocator::Resource::operator==(
+ const Resource& other) const
+{
+ return this->Total == other.Total && this->Locked == other.Locked;
+}
+
+bool cmCTestResourceAllocator::Resource::operator!=(
+ const Resource& other) const
+{
+ return !(*this == other);
+}
diff --git a/Source/CTest/cmCTestResourceAllocator.h b/Source/CTest/cmCTestResourceAllocator.h
new file mode 100644
index 0000000..129e64e
--- /dev/null
+++ b/Source/CTest/cmCTestResourceAllocator.h
@@ -0,0 +1,36 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <map>
+#include <string>
+
+class cmCTestResourceSpec;
+
+class cmCTestResourceAllocator
+{
+public:
+ struct Resource
+ {
+ unsigned int Total;
+ unsigned int Locked;
+
+ unsigned int Free() const { return this->Total - this->Locked; }
+
+ bool operator==(const Resource& other) const;
+ bool operator!=(const Resource& other) const;
+ };
+
+ void InitializeFromResourceSpec(const cmCTestResourceSpec& spec);
+
+ const std::map<std::string, std::map<std::string, Resource>>& GetResources()
+ const;
+
+ bool AllocateResource(const std::string& name, const std::string& id,
+ unsigned int slots);
+ bool DeallocateResource(const std::string& name, const std::string& id,
+ unsigned int slots);
+
+private:
+ std::map<std::string, std::map<std::string, Resource>> Resources;
+};
diff --git a/Source/CTest/cmCTestResourceGroupsLexerHelper.cxx b/Source/CTest/cmCTestResourceGroupsLexerHelper.cxx
new file mode 100644
index 0000000..4c26b3f
--- /dev/null
+++ b/Source/CTest/cmCTestResourceGroupsLexerHelper.cxx
@@ -0,0 +1,55 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestResourceGroupsLexerHelper.h"
+
+#include "cmCTestResourceGroupsLexer.h"
+#include "cmCTestTestHandler.h"
+
+cmCTestResourceGroupsLexerHelper::cmCTestResourceGroupsLexerHelper(
+ std::vector<std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>&
+ output)
+ : Output(output)
+{
+}
+
+bool cmCTestResourceGroupsLexerHelper::ParseString(const std::string& value)
+{
+ yyscan_t lexer;
+ cmCTestResourceGroups_yylex_init_extra(this, &lexer);
+
+ auto* state = cmCTestResourceGroups_yy_scan_string(value.c_str(), lexer);
+ int retval = cmCTestResourceGroups_yylex(lexer);
+ cmCTestResourceGroups_yy_delete_buffer(state, lexer);
+
+ cmCTestResourceGroups_yylex_destroy(lexer);
+ return retval == 0;
+}
+
+void cmCTestResourceGroupsLexerHelper::SetProcessCount(unsigned int count)
+{
+ this->ProcessCount = count;
+}
+
+void cmCTestResourceGroupsLexerHelper::SetResourceType(const std::string& type)
+{
+ this->ResourceType = type;
+}
+
+void cmCTestResourceGroupsLexerHelper::SetNeededSlots(int count)
+{
+ this->NeededSlots = count;
+}
+
+void cmCTestResourceGroupsLexerHelper::WriteRequirement()
+{
+ this->Process.push_back({ this->ResourceType, this->NeededSlots, 1 });
+}
+
+void cmCTestResourceGroupsLexerHelper::WriteProcess()
+{
+ for (unsigned int i = 0; i < this->ProcessCount; ++i) {
+ this->Output.push_back(this->Process);
+ }
+ this->Process.clear();
+ this->ProcessCount = 1;
+}
diff --git a/Source/CTest/cmCTestResourceGroupsLexerHelper.h b/Source/CTest/cmCTestResourceGroupsLexerHelper.h
new file mode 100644
index 0000000..ae4fa99
--- /dev/null
+++ b/Source/CTest/cmCTestResourceGroupsLexerHelper.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 <string>
+#include <vector>
+
+#include "cmCTestTestHandler.h"
+
+class cmCTestResourceGroupsLexerHelper
+{
+public:
+ struct ParserType
+ {
+ };
+
+ cmCTestResourceGroupsLexerHelper(
+ std::vector<
+ std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>&
+ output);
+ ~cmCTestResourceGroupsLexerHelper() = default;
+
+ bool ParseString(const std::string& value);
+
+ void SetProcessCount(unsigned int count);
+ void SetResourceType(const std::string& type);
+ void SetNeededSlots(int count);
+ void WriteRequirement();
+ void WriteProcess();
+
+private:
+ std::vector<std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>&
+ Output;
+
+ unsigned int ProcessCount = 1;
+ std::string ResourceType;
+ int NeededSlots;
+ std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement> Process;
+};
+
+#define YY_EXTRA_TYPE cmCTestResourceGroupsLexerHelper*
diff --git a/Source/CTest/cmCTestResourceSpec.cxx b/Source/CTest/cmCTestResourceSpec.cxx
new file mode 100644
index 0000000..101dc2c
--- /dev/null
+++ b/Source/CTest/cmCTestResourceSpec.cxx
@@ -0,0 +1,237 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestResourceSpec.h"
+
+#include <functional>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cmext/string_view>
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmJSONHelpers.h"
+
+namespace {
+const cmsys::RegularExpression IdentifierRegex{ "^[a-z_][a-z0-9_]*$" };
+const cmsys::RegularExpression IdRegex{ "^[a-z0-9_]+$" };
+
+struct Version
+{
+ int Major = 1;
+ int Minor = 0;
+};
+
+struct TopVersion
+{
+ struct Version Version;
+};
+
+auto const VersionFieldHelper =
+ cmJSONIntHelper<cmCTestResourceSpec::ReadFileResult>(
+ cmCTestResourceSpec::ReadFileResult::READ_OK,
+ cmCTestResourceSpec::ReadFileResult::INVALID_VERSION);
+
+auto const VersionHelper =
+ cmJSONRequiredHelper<Version, cmCTestResourceSpec::ReadFileResult>(
+ cmCTestResourceSpec::ReadFileResult::NO_VERSION,
+ cmJSONObjectHelper<Version, cmCTestResourceSpec::ReadFileResult>(
+ cmCTestResourceSpec::ReadFileResult::READ_OK,
+ cmCTestResourceSpec::ReadFileResult::INVALID_VERSION)
+ .Bind("major"_s, &Version::Major, VersionFieldHelper)
+ .Bind("minor"_s, &Version::Minor, VersionFieldHelper));
+
+auto const RootVersionHelper =
+ cmJSONObjectHelper<TopVersion, cmCTestResourceSpec::ReadFileResult>(
+ cmCTestResourceSpec::ReadFileResult::READ_OK,
+ cmCTestResourceSpec::ReadFileResult::INVALID_ROOT)
+ .Bind("version"_s, &TopVersion::Version, VersionHelper, false);
+
+cmCTestResourceSpec::ReadFileResult ResourceIdHelper(std::string& out,
+ const Json::Value* value)
+{
+ auto result = cmJSONStringHelper(
+ cmCTestResourceSpec::ReadFileResult::READ_OK,
+ cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE)(out, value);
+ if (result != cmCTestResourceSpec::ReadFileResult::READ_OK) {
+ return result;
+ }
+ cmsys::RegularExpressionMatch match;
+ if (!IdRegex.find(out.c_str(), match)) {
+ return cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE;
+ }
+ return cmCTestResourceSpec::ReadFileResult::READ_OK;
+}
+
+auto const ResourceHelper =
+ cmJSONObjectHelper<cmCTestResourceSpec::Resource,
+ cmCTestResourceSpec::ReadFileResult>(
+ cmCTestResourceSpec::ReadFileResult::READ_OK,
+ cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE)
+ .Bind("id"_s, &cmCTestResourceSpec::Resource::Id, ResourceIdHelper)
+ .Bind("slots"_s, &cmCTestResourceSpec::Resource::Capacity,
+ cmJSONUIntHelper(
+ cmCTestResourceSpec::ReadFileResult::READ_OK,
+ cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE, 1),
+ false);
+
+auto const ResourceListHelper =
+ cmJSONVectorHelper<cmCTestResourceSpec::Resource,
+ cmCTestResourceSpec::ReadFileResult>(
+ cmCTestResourceSpec::ReadFileResult::READ_OK,
+ cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE_TYPE,
+ ResourceHelper);
+
+auto const ResourceMapHelper =
+ cmJSONMapFilterHelper<std::vector<cmCTestResourceSpec::Resource>,
+ cmCTestResourceSpec::ReadFileResult>(
+ cmCTestResourceSpec::ReadFileResult::READ_OK,
+ cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC,
+ ResourceListHelper, [](const std::string& key) -> bool {
+ cmsys::RegularExpressionMatch match;
+ return IdentifierRegex.find(key.c_str(), match);
+ });
+
+auto const SocketSetHelper = cmJSONVectorHelper<
+ std::map<std::string, std::vector<cmCTestResourceSpec::Resource>>>(
+ cmCTestResourceSpec::ReadFileResult::READ_OK,
+ cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC, ResourceMapHelper);
+
+cmCTestResourceSpec::ReadFileResult SocketHelper(
+ cmCTestResourceSpec::Socket& out, const Json::Value* value)
+{
+ std::vector<
+ std::map<std::string, std::vector<cmCTestResourceSpec::Resource>>>
+ sockets;
+ cmCTestResourceSpec::ReadFileResult result = SocketSetHelper(sockets, value);
+ if (result != cmCTestResourceSpec::ReadFileResult::READ_OK) {
+ return result;
+ }
+ if (sockets.size() > 1) {
+ return cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC;
+ }
+ if (sockets.empty()) {
+ out.Resources.clear();
+ } else {
+ out.Resources = std::move(sockets[0]);
+ }
+ return cmCTestResourceSpec::ReadFileResult::READ_OK;
+}
+
+auto const LocalRequiredHelper =
+ cmJSONRequiredHelper<cmCTestResourceSpec::Socket,
+ cmCTestResourceSpec::ReadFileResult>(
+ cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC, SocketHelper);
+
+auto const RootHelper =
+ cmJSONObjectHelper<cmCTestResourceSpec, cmCTestResourceSpec::ReadFileResult>(
+ cmCTestResourceSpec::ReadFileResult::READ_OK,
+ cmCTestResourceSpec::ReadFileResult::INVALID_ROOT)
+ .Bind("local", &cmCTestResourceSpec::LocalSocket, LocalRequiredHelper,
+ false);
+}
+
+cmCTestResourceSpec::ReadFileResult cmCTestResourceSpec::ReadFromJSONFile(
+ const std::string& filename)
+{
+ cmsys::ifstream fin(filename.c_str());
+ if (!fin) {
+ return ReadFileResult::FILE_NOT_FOUND;
+ }
+
+ Json::Value root;
+ Json::CharReaderBuilder builder;
+ if (!Json::parseFromStream(builder, fin, &root, nullptr)) {
+ return ReadFileResult::JSON_PARSE_ERROR;
+ }
+
+ TopVersion version;
+ ReadFileResult result;
+ if ((result = RootVersionHelper(version, &root)) !=
+ ReadFileResult::READ_OK) {
+ return result;
+ }
+ if (version.Version.Major != 1 || version.Version.Minor != 0) {
+ return ReadFileResult::UNSUPPORTED_VERSION;
+ }
+
+ return RootHelper(*this, &root);
+}
+
+const char* cmCTestResourceSpec::ResultToString(ReadFileResult result)
+{
+ switch (result) {
+ case ReadFileResult::READ_OK:
+ return "OK";
+
+ case ReadFileResult::FILE_NOT_FOUND:
+ return "File not found";
+
+ case ReadFileResult::JSON_PARSE_ERROR:
+ return "JSON parse error";
+
+ case ReadFileResult::INVALID_ROOT:
+ return "Invalid root object";
+
+ case ReadFileResult::NO_VERSION:
+ return "No version specified";
+
+ case ReadFileResult::INVALID_VERSION:
+ return "Invalid version object";
+
+ case ReadFileResult::UNSUPPORTED_VERSION:
+ return "Unsupported version";
+
+ case ReadFileResult::INVALID_SOCKET_SPEC:
+ return "Invalid socket object";
+
+ case ReadFileResult::INVALID_RESOURCE_TYPE:
+ return "Invalid resource type object";
+
+ case ReadFileResult::INVALID_RESOURCE:
+ return "Invalid resource object";
+
+ default:
+ return "Unknown";
+ }
+}
+
+bool cmCTestResourceSpec::operator==(const cmCTestResourceSpec& other) const
+{
+ return this->LocalSocket == other.LocalSocket;
+}
+
+bool cmCTestResourceSpec::operator!=(const cmCTestResourceSpec& other) const
+{
+ return !(*this == other);
+}
+
+bool cmCTestResourceSpec::Socket::operator==(
+ const cmCTestResourceSpec::Socket& other) const
+{
+ return this->Resources == other.Resources;
+}
+
+bool cmCTestResourceSpec::Socket::operator!=(
+ const cmCTestResourceSpec::Socket& other) const
+{
+ return !(*this == other);
+}
+
+bool cmCTestResourceSpec::Resource::operator==(
+ const cmCTestResourceSpec::Resource& other) const
+{
+ return this->Id == other.Id && this->Capacity == other.Capacity;
+}
+
+bool cmCTestResourceSpec::Resource::operator!=(
+ const cmCTestResourceSpec::Resource& other) const
+{
+ return !(*this == other);
+}
diff --git a/Source/CTest/cmCTestResourceSpec.h b/Source/CTest/cmCTestResourceSpec.h
new file mode 100644
index 0000000..72628a3
--- /dev/null
+++ b/Source/CTest/cmCTestResourceSpec.h
@@ -0,0 +1,54 @@
+/* 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 <map>
+#include <string>
+#include <vector>
+
+class cmCTestResourceSpec
+{
+public:
+ class Resource
+ {
+ public:
+ std::string Id;
+ unsigned int Capacity;
+
+ bool operator==(const Resource& other) const;
+ bool operator!=(const Resource& other) const;
+ };
+
+ class Socket
+ {
+ public:
+ std::map<std::string, std::vector<Resource>> Resources;
+
+ bool operator==(const Socket& other) const;
+ bool operator!=(const Socket& other) const;
+ };
+
+ Socket LocalSocket;
+
+ enum class ReadFileResult
+ {
+ READ_OK,
+ FILE_NOT_FOUND,
+ JSON_PARSE_ERROR,
+ INVALID_ROOT,
+ NO_VERSION,
+ INVALID_VERSION,
+ UNSUPPORTED_VERSION,
+ INVALID_SOCKET_SPEC, // Can't be INVALID_SOCKET due to a Windows macro
+ INVALID_RESOURCE_TYPE,
+ INVALID_RESOURCE,
+ };
+
+ ReadFileResult ReadFromJSONFile(const std::string& filename);
+ static const char* ResultToString(ReadFileResult result);
+
+ bool operator==(const cmCTestResourceSpec& other) const;
+ bool operator!=(const cmCTestResourceSpec& other) const;
+};
diff --git a/Source/CTest/cmCTestRunScriptCommand.cxx b/Source/CTest/cmCTestRunScriptCommand.cxx
new file mode 100644
index 0000000..7661d4d
--- /dev/null
+++ b/Source/CTest/cmCTestRunScriptCommand.cxx
@@ -0,0 +1,46 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestRunScriptCommand.h"
+
+#include "cmCTestScriptHandler.h"
+#include "cmMakefile.h"
+
+class cmExecutionStatus;
+
+bool cmCTestRunScriptCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& /*unused*/)
+{
+ if (args.empty()) {
+ this->CTestScriptHandler->RunCurrentScript();
+ return true;
+ }
+
+ bool np = false;
+ unsigned int i = 0;
+ if (args[i] == "NEW_PROCESS") {
+ np = true;
+ i++;
+ }
+ int start = i;
+ // run each script
+ std::string returnVariable;
+ for (i = start; i < args.size(); ++i) {
+ if (args[i] == "RETURN_VALUE") {
+ ++i;
+ if (i < args.size()) {
+ returnVariable = args[i];
+ }
+ }
+ }
+ for (i = start; i < args.size(); ++i) {
+ if (args[i] == "RETURN_VALUE") {
+ ++i;
+ } else {
+ int ret;
+ cmCTestScriptHandler::RunScript(this->CTest, this->Makefile, args[i],
+ !np, &ret);
+ this->Makefile->AddDefinition(returnVariable, std::to_string(ret));
+ }
+ }
+ return true;
+}
diff --git a/Source/CTest/cmCTestRunScriptCommand.h b/Source/CTest/cmCTestRunScriptCommand.h
new file mode 100644
index 0000000..510b748
--- /dev/null
+++ b/Source/CTest/cmCTestRunScriptCommand.h
@@ -0,0 +1,46 @@
+/* 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 <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmCTestCommand.h"
+#include "cmCommand.h"
+
+class cmExecutionStatus;
+
+/** \class cmCTestRunScript
+ * \brief Run a ctest script
+ *
+ * cmLibrarysCommand defines a list of executable (i.e., test)
+ * programs to create.
+ */
+class cmCTestRunScriptCommand : public cmCTestCommand
+{
+public:
+ cmCTestRunScriptCommand() {}
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ auto ni = cm::make_unique<cmCTestRunScriptCommand>();
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return std::unique_ptr<cmCommand>(std::move(ni));
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) override;
+};
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
new file mode 100644
index 0000000..5a6c775
--- /dev/null
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -0,0 +1,883 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestRunTest.h"
+
+#include <chrono>
+#include <cstddef> // IWYU pragma: keep
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <iomanip>
+#include <ratio>
+#include <sstream>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCTest.h"
+#include "cmCTestMemCheckHandler.h"
+#include "cmCTestMultiProcessHandler.h"
+#include "cmProcess.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmWorkingDirectory.h"
+
+cmCTestRunTest::cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler)
+ : MultiTestHandler(multiHandler)
+{
+ this->CTest = multiHandler.CTest;
+ this->TestHandler = multiHandler.TestHandler;
+ this->TestResult.ExecutionTime = cmDuration::zero();
+ this->TestResult.ReturnValue = 0;
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ this->TestResult.TestCount = 0;
+ this->TestResult.Properties = nullptr;
+}
+
+void cmCTestRunTest::CheckOutput(std::string const& line)
+{
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ this->GetIndex() << ": " << line << std::endl);
+ this->ProcessOutput += line;
+ this->ProcessOutput += "\n";
+
+ // Check for TIMEOUT_AFTER_MATCH property.
+ if (!this->TestProperties->TimeoutRegularExpressions.empty()) {
+ for (auto& reg : this->TestProperties->TimeoutRegularExpressions) {
+ if (reg.first.find(this->ProcessOutput)) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ this->GetIndex()
+ << ": "
+ << "Test timeout changed to "
+ << std::chrono::duration_cast<std::chrono::seconds>(
+ this->TestProperties->AlternateTimeout)
+ .count()
+ << std::endl);
+ this->TestProcess->ResetStartTime();
+ this->TestProcess->ChangeTimeout(
+ this->TestProperties->AlternateTimeout);
+ this->TestProperties->TimeoutRegularExpressions.clear();
+ break;
+ }
+ }
+ }
+}
+
+bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
+{
+ this->WriteLogOutputTop(completed, total);
+ std::string reason;
+ bool passed = true;
+ cmProcess::State res =
+ started ? this->TestProcess->GetProcessStatus() : cmProcess::State::Error;
+ if (res != cmProcess::State::Expired) {
+ this->TimeoutIsForStopTime = false;
+ }
+ std::int64_t retVal = this->TestProcess->GetExitValue();
+ bool forceFail = false;
+ bool forceSkip = false;
+ bool skipped = false;
+ bool outputTestErrorsToConsole = false;
+ if (!this->TestProperties->RequiredRegularExpressions.empty() &&
+ this->FailedDependencies.empty()) {
+ bool found = false;
+ for (auto& pass : this->TestProperties->RequiredRegularExpressions) {
+ if (pass.first.find(this->ProcessOutput)) {
+ found = true;
+ reason = cmStrCat("Required regular expression found. Regex=[",
+ pass.second, ']');
+ break;
+ }
+ }
+ if (!found) {
+ reason = "Required regular expression not found. Regex=[";
+ for (auto& pass : this->TestProperties->RequiredRegularExpressions) {
+ reason += pass.second;
+ reason += "\n";
+ }
+ reason += "]";
+ forceFail = true;
+ }
+ }
+ if (!this->TestProperties->ErrorRegularExpressions.empty() &&
+ this->FailedDependencies.empty()) {
+ for (auto& fail : this->TestProperties->ErrorRegularExpressions) {
+ if (fail.first.find(this->ProcessOutput)) {
+ reason = cmStrCat("Error regular expression found in output. Regex=[",
+ fail.second, ']');
+ forceFail = true;
+ break;
+ }
+ }
+ }
+ if (!this->TestProperties->SkipRegularExpressions.empty() &&
+ this->FailedDependencies.empty()) {
+ for (auto& skip : this->TestProperties->SkipRegularExpressions) {
+ if (skip.first.find(this->ProcessOutput)) {
+ reason = cmStrCat("Skip regular expression found in output. Regex=[",
+ skip.second, ']');
+ forceSkip = true;
+ break;
+ }
+ }
+ }
+ std::ostringstream outputStream;
+ if (res == cmProcess::State::Exited) {
+ bool success = !forceFail &&
+ (retVal == 0 ||
+ !this->TestProperties->RequiredRegularExpressions.empty());
+ if ((this->TestProperties->SkipReturnCode >= 0 &&
+ this->TestProperties->SkipReturnCode == retVal) ||
+ forceSkip) {
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ std::ostringstream s;
+ if (forceSkip) {
+ s << "SKIP_REGULAR_EXPRESSION_MATCHED";
+ } else {
+ s << "SKIP_RETURN_CODE=" << this->TestProperties->SkipReturnCode;
+ }
+ this->TestResult.CompletionStatus = s.str();
+ outputStream << "***Skipped ";
+ skipped = true;
+ } else if (success != this->TestProperties->WillFail) {
+ this->TestResult.Status = cmCTestTestHandler::COMPLETED;
+ outputStream << " Passed ";
+ } else {
+ this->TestResult.Status = cmCTestTestHandler::FAILED;
+ outputStream << "***Failed " << reason;
+ outputTestErrorsToConsole =
+ this->CTest->GetOutputTestOutputOnTestFailure();
+ }
+ } else if (res == cmProcess::State::Expired) {
+ outputStream << "***Timeout ";
+ this->TestResult.Status = cmCTestTestHandler::TIMEOUT;
+ outputTestErrorsToConsole =
+ this->CTest->GetOutputTestOutputOnTestFailure();
+ } else if (res == cmProcess::State::Exception) {
+ outputTestErrorsToConsole =
+ this->CTest->GetOutputTestOutputOnTestFailure();
+ outputStream << "***Exception: ";
+ this->TestResult.ExceptionStatus =
+ this->TestProcess->GetExitExceptionString();
+ switch (this->TestProcess->GetExitException()) {
+ case cmProcess::Exception::Fault:
+ outputStream << "SegFault";
+ this->TestResult.Status = cmCTestTestHandler::SEGFAULT;
+ break;
+ case cmProcess::Exception::Illegal:
+ outputStream << "Illegal";
+ this->TestResult.Status = cmCTestTestHandler::ILLEGAL;
+ break;
+ case cmProcess::Exception::Interrupt:
+ outputStream << "Interrupt";
+ this->TestResult.Status = cmCTestTestHandler::INTERRUPT;
+ break;
+ case cmProcess::Exception::Numerical:
+ outputStream << "Numerical";
+ this->TestResult.Status = cmCTestTestHandler::NUMERICAL;
+ break;
+ default:
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ this->TestResult.ExceptionStatus);
+ this->TestResult.Status = cmCTestTestHandler::OTHER_FAULT;
+ }
+ } else if ("Disabled" == this->TestResult.CompletionStatus) {
+ outputStream << "***Not Run (Disabled) ";
+ } else // cmProcess::State::Error
+ {
+ outputStream << "***Not Run ";
+ }
+
+ passed = this->TestResult.Status == cmCTestTestHandler::COMPLETED;
+ char buf[1024];
+ sprintf(buf, "%6.2f sec", this->TestProcess->GetTotalTime().count());
+ outputStream << buf << "\n";
+
+ bool passedOrSkipped = passed || skipped;
+ if (this->CTest->GetTestProgressOutput()) {
+ if (!passedOrSkipped) {
+ // If the test did not pass, reprint test name and error
+ std::string output = this->GetTestPrefix(completed, total);
+ std::string testName = this->TestProperties->Name;
+ const int maxTestNameWidth = this->CTest->GetMaxTestNameWidth();
+ testName.resize(maxTestNameWidth + 4, '.');
+
+ output += testName;
+ output += outputStream.str();
+ outputStream.str("");
+ outputStream.clear();
+ outputStream << output;
+ cmCTestLog(this->CTest, HANDLER_TEST_PROGRESS_OUTPUT, "\n"); // flush
+ }
+ if (completed == total) {
+ std::string testName = this->GetTestPrefix(completed, total) +
+ this->TestProperties->Name + "\n";
+ cmCTestLog(this->CTest, HANDLER_TEST_PROGRESS_OUTPUT, testName);
+ }
+ }
+ if (!this->CTest->GetTestProgressOutput() || !passedOrSkipped) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, outputStream.str());
+ }
+
+ if (outputTestErrorsToConsole) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, this->ProcessOutput << std::endl);
+ }
+
+ if (this->TestHandler->LogFile) {
+ *this->TestHandler->LogFile << "Test time = " << buf << std::endl;
+ }
+
+ this->DartProcessing();
+
+ // if this is doing MemCheck then all the output needs to be put into
+ // Output since that is what is parsed by cmCTestMemCheckHandler
+ if (!this->TestHandler->MemCheck && started) {
+ this->TestHandler->CleanTestOutput(
+ this->ProcessOutput,
+ static_cast<size_t>(
+ this->TestResult.Status == cmCTestTestHandler::COMPLETED
+ ? this->TestHandler->CustomMaximumPassedTestOutputSize
+ : this->TestHandler->CustomMaximumFailedTestOutputSize));
+ }
+ this->TestResult.Reason = reason;
+ if (this->TestHandler->LogFile) {
+ bool pass = true;
+ const char* reasonType = "Test Pass Reason";
+ if (this->TestResult.Status != cmCTestTestHandler::COMPLETED &&
+ this->TestResult.Status != cmCTestTestHandler::NOT_RUN) {
+ reasonType = "Test Fail Reason";
+ pass = false;
+ }
+ auto ttime = this->TestProcess->GetTotalTime();
+ auto hours = std::chrono::duration_cast<std::chrono::hours>(ttime);
+ ttime -= hours;
+ auto minutes = std::chrono::duration_cast<std::chrono::minutes>(ttime);
+ ttime -= minutes;
+ auto seconds = std::chrono::duration_cast<std::chrono::seconds>(ttime);
+ char buffer[100];
+ sprintf(buffer, "%02d:%02d:%02d", static_cast<unsigned>(hours.count()),
+ static_cast<unsigned>(minutes.count()),
+ static_cast<unsigned>(seconds.count()));
+ *this->TestHandler->LogFile
+ << "----------------------------------------------------------"
+ << std::endl;
+ if (!this->TestResult.Reason.empty()) {
+ *this->TestHandler->LogFile << reasonType << ":\n"
+ << this->TestResult.Reason << "\n";
+ } else {
+ if (pass) {
+ *this->TestHandler->LogFile << "Test Passed.\n";
+ } else {
+ *this->TestHandler->LogFile << "Test Failed.\n";
+ }
+ }
+ *this->TestHandler->LogFile
+ << "\"" << this->TestProperties->Name
+ << "\" end time: " << this->CTest->CurrentTime() << std::endl
+ << "\"" << this->TestProperties->Name << "\" time elapsed: " << buffer
+ << std::endl
+ << "----------------------------------------------------------"
+ << std::endl
+ << std::endl;
+ }
+ // if the test actually started and ran
+ // record the results in TestResult
+ if (started) {
+ std::string compressedOutput;
+ if (!this->TestHandler->MemCheck &&
+ this->CTest->ShouldCompressTestOutput()) {
+ std::string str = this->ProcessOutput;
+ if (this->CTest->CompressString(str)) {
+ compressedOutput = std::move(str);
+ }
+ }
+ bool compress = !compressedOutput.empty() &&
+ compressedOutput.length() < this->ProcessOutput.length();
+ this->TestResult.Output =
+ compress ? compressedOutput : this->ProcessOutput;
+ this->TestResult.CompressOutput = compress;
+ this->TestResult.ReturnValue = this->TestProcess->GetExitValue();
+ if (!skipped) {
+ this->TestResult.CompletionStatus = "Completed";
+ }
+ this->TestResult.ExecutionTime = this->TestProcess->GetTotalTime();
+ this->MemCheckPostProcess();
+ this->ComputeWeightedCost();
+ }
+ // If the test does not need to rerun push the current TestResult onto the
+ // TestHandler vector
+ if (!this->NeedsToRepeat()) {
+ this->TestHandler->TestResults.push_back(this->TestResult);
+ }
+ this->TestProcess.reset();
+ return passed || skipped;
+}
+
+bool cmCTestRunTest::StartAgain(std::unique_ptr<cmCTestRunTest> runner,
+ size_t completed)
+{
+ auto* testRun = runner.get();
+
+ if (!testRun->RunAgain) {
+ return false;
+ }
+ testRun->RunAgain = false; // reset
+ testRun->TestProcess = cm::make_unique<cmProcess>(std::move(runner));
+ // change to tests directory
+ cmWorkingDirectory workdir(testRun->TestProperties->Directory);
+ if (workdir.Failed()) {
+ testRun->StartFailure("Failed to change working directory to " +
+ testRun->TestProperties->Directory + " : " +
+ std::strerror(workdir.GetLastResult()),
+ "Failed to change working directory");
+ return true;
+ }
+
+ testRun->StartTest(completed, testRun->TotalNumberOfTests);
+ return true;
+}
+
+bool cmCTestRunTest::NeedsToRepeat()
+{
+ this->NumberOfRunsLeft--;
+ if (this->NumberOfRunsLeft == 0) {
+ return false;
+ }
+ // If a test is marked as NOT_RUN it will not be repeated
+ // no matter the repeat settings, so just record it as-is.
+ if (this->TestResult.Status == cmCTestTestHandler::NOT_RUN) {
+ return false;
+ }
+ // if number of runs left is not 0, and we are running until
+ // we find a failed (or passed) test, then return true so the test can be
+ // restarted
+ if ((this->RepeatMode == cmCTest::Repeat::UntilFail &&
+ this->TestResult.Status == cmCTestTestHandler::COMPLETED) ||
+ (this->RepeatMode == cmCTest::Repeat::UntilPass &&
+ this->TestResult.Status != cmCTestTestHandler::COMPLETED) ||
+ (this->RepeatMode == cmCTest::Repeat::AfterTimeout &&
+ this->TestResult.Status == cmCTestTestHandler::TIMEOUT)) {
+ this->RunAgain = true;
+ return true;
+ }
+ return false;
+}
+void cmCTestRunTest::ComputeWeightedCost()
+{
+ double prev = static_cast<double>(this->TestProperties->PreviousRuns);
+ double avgcost = static_cast<double>(this->TestProperties->Cost);
+ double current = this->TestResult.ExecutionTime.count();
+
+ if (this->TestResult.Status == cmCTestTestHandler::COMPLETED) {
+ this->TestProperties->Cost =
+ static_cast<float>(((prev * avgcost) + current) / (prev + 1.0));
+ this->TestProperties->PreviousRuns++;
+ }
+}
+
+void cmCTestRunTest::MemCheckPostProcess()
+{
+ if (!this->TestHandler->MemCheck) {
+ return;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ this->Index << ": process test output now: "
+ << this->TestProperties->Name << " "
+ << this->TestResult.Name << std::endl,
+ this->TestHandler->GetQuiet());
+ cmCTestMemCheckHandler* handler =
+ static_cast<cmCTestMemCheckHandler*>(this->TestHandler);
+ handler->PostProcessTest(this->TestResult, this->Index);
+}
+
+void cmCTestRunTest::StartFailure(std::unique_ptr<cmCTestRunTest> runner,
+ std::string const& output,
+ std::string const& detail)
+{
+ auto* testRun = runner.get();
+
+ testRun->TestProcess = cm::make_unique<cmProcess>(std::move(runner));
+ testRun->StartFailure(output, detail);
+
+ testRun->FinalizeTest(false);
+}
+
+void cmCTestRunTest::StartFailure(std::string const& output,
+ std::string const& detail)
+{
+ // Still need to log the Start message so the test summary records our
+ // attempt to start this test
+ if (!this->CTest->GetTestProgressOutput()) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ std::setw(2 * getNumWidth(this->TotalNumberOfTests) + 8)
+ << "Start "
+ << std::setw(getNumWidth(this->TestHandler->GetMaxIndex()))
+ << this->TestProperties->Index << ": "
+ << this->TestProperties->Name << std::endl);
+ }
+
+ this->ProcessOutput.clear();
+ if (!output.empty()) {
+ *this->TestHandler->LogFile << output << std::endl;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, output << std::endl);
+ }
+
+ this->TestResult.Properties = this->TestProperties;
+ this->TestResult.ExecutionTime = cmDuration::zero();
+ this->TestResult.CompressOutput = false;
+ this->TestResult.ReturnValue = -1;
+ this->TestResult.CompletionStatus = detail;
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ this->TestResult.TestCount = this->TestProperties->Index;
+ this->TestResult.Name = this->TestProperties->Name;
+ this->TestResult.Path = this->TestProperties->Directory;
+ this->TestResult.Output = output;
+ this->TestResult.FullCommandLine.clear();
+ this->TestResult.Environment.clear();
+}
+
+std::string cmCTestRunTest::GetTestPrefix(size_t completed, size_t total) const
+{
+ std::ostringstream outputStream;
+ outputStream << std::setw(getNumWidth(total)) << completed << "/";
+ outputStream << std::setw(getNumWidth(total)) << total << " ";
+
+ if (this->TestHandler->MemCheck) {
+ outputStream << "MemCheck";
+ } else {
+ outputStream << "Test";
+ }
+
+ std::ostringstream indexStr;
+ indexStr << " #" << this->Index << ":";
+ outputStream << std::setw(3 + getNumWidth(this->TestHandler->GetMaxIndex()))
+ << indexStr.str();
+ outputStream << " ";
+
+ return outputStream.str();
+}
+
+bool cmCTestRunTest::StartTest(std::unique_ptr<cmCTestRunTest> runner,
+ size_t completed, size_t total)
+{
+ auto* testRun = runner.get();
+
+ testRun->TestProcess = cm::make_unique<cmProcess>(std::move(runner));
+
+ if (!testRun->StartTest(completed, total)) {
+ testRun->FinalizeTest(false);
+ return false;
+ }
+
+ return true;
+}
+
+// Starts the execution of a test. Returns once it has started
+bool cmCTestRunTest::StartTest(size_t completed, size_t total)
+{
+ this->TotalNumberOfTests = total; // save for rerun case
+ if (!this->CTest->GetTestProgressOutput()) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ std::setw(2 * getNumWidth(total) + 8)
+ << "Start "
+ << std::setw(getNumWidth(this->TestHandler->GetMaxIndex()))
+ << this->TestProperties->Index << ": "
+ << this->TestProperties->Name << std::endl);
+ } else {
+ std::string testName = this->GetTestPrefix(completed, total) +
+ this->TestProperties->Name + "\n";
+ cmCTestLog(this->CTest, HANDLER_TEST_PROGRESS_OUTPUT, testName);
+ }
+
+ this->ProcessOutput.clear();
+
+ this->TestResult.Properties = this->TestProperties;
+ this->TestResult.ExecutionTime = cmDuration::zero();
+ this->TestResult.CompressOutput = false;
+ this->TestResult.ReturnValue = -1;
+ this->TestResult.TestCount = this->TestProperties->Index;
+ this->TestResult.Name = this->TestProperties->Name;
+ this->TestResult.Path = this->TestProperties->Directory;
+
+ // Return immediately if test is disabled
+ if (this->TestProperties->Disabled) {
+ this->TestResult.CompletionStatus = "Disabled";
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ this->TestResult.Output = "Disabled";
+ this->TestResult.FullCommandLine.clear();
+ this->TestResult.Environment.clear();
+ return false;
+ }
+
+ this->TestResult.CompletionStatus = "Failed to start";
+ this->TestResult.Status = cmCTestTestHandler::BAD_COMMAND;
+
+ // Check for failed fixture dependencies before we even look at the command
+ // arguments because if we are not going to run the test, the command and
+ // its arguments are irrelevant. This matters for the case where a fixture
+ // dependency might be creating the executable we want to run.
+ if (!this->FailedDependencies.empty()) {
+ std::string msg = "Failed test dependencies:";
+ for (std::string const& failedDep : this->FailedDependencies) {
+ msg += " " + failedDep;
+ }
+ *this->TestHandler->LogFile << msg << std::endl;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, msg << std::endl);
+ this->TestResult.Output = msg;
+ this->TestResult.FullCommandLine.clear();
+ this->TestResult.Environment.clear();
+ this->TestResult.CompletionStatus = "Fixture dependency failed";
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ return false;
+ }
+
+ this->ComputeArguments();
+ std::vector<std::string>& args = this->TestProperties->Args;
+ if (args.size() >= 2 && args[1] == "NOT_AVAILABLE") {
+ std::string msg;
+ if (this->CTest->GetConfigType().empty()) {
+ msg = "Test not available without configuration. (Missing \"-C "
+ "<config>\"?)";
+ } else {
+ msg = cmStrCat("Test not available in configuration \"",
+ this->CTest->GetConfigType(), "\".");
+ }
+ *this->TestHandler->LogFile << msg << std::endl;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, msg << std::endl);
+ this->TestResult.Output = msg;
+ this->TestResult.FullCommandLine.clear();
+ this->TestResult.Environment.clear();
+ this->TestResult.CompletionStatus = "Missing Configuration";
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ return false;
+ }
+
+ // Check if all required files exist
+ for (std::string const& file : this->TestProperties->RequiredFiles) {
+ if (!cmSystemTools::FileExists(file)) {
+ // Required file was not found
+ *this->TestHandler->LogFile << "Unable to find required file: " << file
+ << std::endl;
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unable to find required file: " << file << std::endl);
+ this->TestResult.Output = "Unable to find required file: " + file;
+ this->TestResult.FullCommandLine.clear();
+ this->TestResult.Environment.clear();
+ this->TestResult.CompletionStatus = "Required Files Missing";
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ return false;
+ }
+ }
+ // log and return if we did not find the executable
+ if (this->ActualCommand.empty()) {
+ // if the command was not found create a TestResult object
+ // that has that information
+ *this->TestHandler->LogFile << "Unable to find executable: " << args[1]
+ << std::endl;
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unable to find executable: " << args[1] << std::endl);
+ this->TestResult.Output = "Unable to find executable: " + args[1];
+ this->TestResult.FullCommandLine.clear();
+ this->TestResult.Environment.clear();
+ this->TestResult.CompletionStatus = "Unable to find executable";
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ return false;
+ }
+ this->StartTime = this->CTest->CurrentTime();
+
+ auto timeout = this->TestProperties->Timeout;
+
+ this->TimeoutIsForStopTime = false;
+ std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime();
+ if (stop_time != std::chrono::system_clock::time_point()) {
+ std::chrono::duration<double> stop_timeout =
+ (stop_time - std::chrono::system_clock::now()) % std::chrono::hours(24);
+
+ if (stop_timeout <= std::chrono::duration<double>::zero()) {
+ stop_timeout = std::chrono::duration<double>::zero();
+ }
+ if (timeout == std::chrono::duration<double>::zero() ||
+ stop_timeout < timeout) {
+ this->TimeoutIsForStopTime = true;
+ timeout = stop_timeout;
+ }
+ }
+
+ return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout,
+ &this->TestProperties->Environment,
+ &this->TestProperties->Affinity);
+}
+
+void cmCTestRunTest::ComputeArguments()
+{
+ this->Arguments.clear(); // reset because this might be a rerun
+ auto j = this->TestProperties->Args.begin();
+ ++j; // skip test name
+ // find the test executable
+ if (this->TestHandler->MemCheck) {
+ cmCTestMemCheckHandler* handler =
+ static_cast<cmCTestMemCheckHandler*>(this->TestHandler);
+ this->ActualCommand = handler->MemoryTester;
+ this->TestProperties->Args[1] =
+ this->TestHandler->FindTheExecutable(this->TestProperties->Args[1]);
+ } else {
+ this->ActualCommand =
+ this->TestHandler->FindTheExecutable(this->TestProperties->Args[1]);
+ ++j; // skip the executable (it will be actualCommand)
+ }
+ std::string testCommand =
+ cmSystemTools::ConvertToOutputPath(this->ActualCommand);
+
+ // Prepends memcheck args to our command string
+ this->TestHandler->GenerateTestCommand(this->Arguments, this->Index);
+ for (std::string const& arg : this->Arguments) {
+ testCommand += " \"";
+ testCommand += arg;
+ testCommand += "\"";
+ }
+
+ for (; j != this->TestProperties->Args.end(); ++j) {
+ testCommand += " \"";
+ testCommand += *j;
+ testCommand += "\"";
+ this->Arguments.push_back(*j);
+ }
+ this->TestResult.FullCommandLine = testCommand;
+
+ // Print the test command in verbose mode
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ std::endl
+ << this->Index << ": "
+ << (this->TestHandler->MemCheck ? "MemCheck" : "Test")
+ << " command: " << testCommand << std::endl);
+
+ // Print any test-specific env vars in verbose mode
+ if (!this->TestProperties->Environment.empty()) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ this->Index << ": "
+ << "Environment variables: " << std::endl);
+ }
+ for (std::string const& env : this->TestProperties->Environment) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ this->Index << ": " << env << std::endl);
+ }
+}
+
+void cmCTestRunTest::DartProcessing()
+{
+ if (!this->ProcessOutput.empty() &&
+ this->ProcessOutput.find("<DartMeasurement") != std::string::npos) {
+ if (this->TestHandler->DartStuff.find(this->ProcessOutput)) {
+ this->TestResult.DartString = this->TestHandler->DartStuff.match(1);
+ // keep searching and replacing until none are left
+ while (this->TestHandler->DartStuff1.find(this->ProcessOutput)) {
+ // replace the exact match for the string
+ cmSystemTools::ReplaceString(
+ this->ProcessOutput, this->TestHandler->DartStuff1.match(1).c_str(),
+ "");
+ }
+ }
+ }
+}
+
+bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
+ std::vector<std::string>* environment,
+ std::vector<size_t>* affinity)
+{
+ this->TestProcess->SetId(this->Index);
+ this->TestProcess->SetWorkingDirectory(this->TestProperties->Directory);
+ this->TestProcess->SetCommand(this->ActualCommand);
+ this->TestProcess->SetCommandArguments(this->Arguments);
+
+ // determine how much time we have
+ cmDuration timeout = this->CTest->GetRemainingTimeAllowed();
+ if (timeout != cmCTest::MaxDuration()) {
+ timeout -= std::chrono::minutes(2);
+ }
+ if (this->CTest->GetTimeOut() > cmDuration::zero() &&
+ this->CTest->GetTimeOut() < timeout) {
+ timeout = this->CTest->GetTimeOut();
+ }
+ if (testTimeOut > cmDuration::zero() &&
+ testTimeOut < this->CTest->GetRemainingTimeAllowed()) {
+ timeout = testTimeOut;
+ }
+ // always have at least 1 second if we got to here
+ if (timeout <= cmDuration::zero()) {
+ timeout = std::chrono::seconds(1);
+ }
+ // handle timeout explicitly set to 0
+ if (testTimeOut == cmDuration::zero() && explicitTimeout) {
+ timeout = cmDuration::zero();
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ this->Index << ": "
+ << "Test timeout computed to be: "
+ << cmDurationTo<unsigned int>(timeout)
+ << "\n",
+ this->TestHandler->GetQuiet());
+
+ this->TestProcess->SetTimeout(timeout);
+
+#ifndef CMAKE_BOOTSTRAP
+ cmSystemTools::SaveRestoreEnvironment sre;
+#endif
+
+ std::ostringstream envMeasurement;
+ if (environment && !environment->empty()) {
+ cmSystemTools::AppendEnv(*environment);
+ for (auto const& var : *environment) {
+ envMeasurement << var << std::endl;
+ }
+ }
+
+ if (this->UseAllocatedResources) {
+ std::vector<std::string> envLog;
+ this->SetupResourcesEnvironment(&envLog);
+ for (auto const& var : envLog) {
+ envMeasurement << var << std::endl;
+ }
+ } else {
+ cmSystemTools::UnsetEnv("CTEST_RESOURCE_GROUP_COUNT");
+ // Signify that this variable is being actively unset
+ envMeasurement << "#CTEST_RESOURCE_GROUP_COUNT=" << std::endl;
+ }
+
+ this->TestResult.Environment = envMeasurement.str();
+ // Remove last newline
+ this->TestResult.Environment.erase(this->TestResult.Environment.length() -
+ 1);
+
+ return this->TestProcess->StartProcess(this->MultiTestHandler.Loop,
+ affinity);
+}
+
+void cmCTestRunTest::SetupResourcesEnvironment(std::vector<std::string>* log)
+{
+ std::string processCount = "CTEST_RESOURCE_GROUP_COUNT=";
+ processCount += std::to_string(this->AllocatedResources.size());
+ cmSystemTools::PutEnv(processCount);
+ if (log) {
+ log->push_back(processCount);
+ }
+
+ std::size_t i = 0;
+ for (auto const& process : this->AllocatedResources) {
+ std::string prefix = "CTEST_RESOURCE_GROUP_";
+ prefix += std::to_string(i);
+ std::string resourceList = prefix + '=';
+ prefix += '_';
+ bool firstType = true;
+ for (auto const& it : process) {
+ if (!firstType) {
+ resourceList += ',';
+ }
+ firstType = false;
+ auto resourceType = it.first;
+ resourceList += resourceType;
+ std::string var = prefix + cmSystemTools::UpperCase(resourceType) + '=';
+ bool firstName = true;
+ for (auto const& it2 : it.second) {
+ if (!firstName) {
+ var += ';';
+ }
+ firstName = false;
+ var += "id:" + it2.Id + ",slots:" + std::to_string(it2.Slots);
+ }
+ cmSystemTools::PutEnv(var);
+ if (log) {
+ log->push_back(var);
+ }
+ }
+ cmSystemTools::PutEnv(resourceList);
+ if (log) {
+ log->push_back(resourceList);
+ }
+ ++i;
+ }
+}
+
+void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total)
+{
+ std::ostringstream outputStream;
+
+ // If this is the last or only run of this test, or progress output is
+ // requested, then print out completed / total.
+ // Only issue is if a test fails and we are running until fail
+ // then it will never print out the completed / total, same would
+ // got for run until pass. Trick is when this is called we don't
+ // yet know if we are passing or failing.
+ bool const progressOnLast =
+ (this->RepeatMode != cmCTest::Repeat::UntilPass &&
+ this->RepeatMode != cmCTest::Repeat::AfterTimeout);
+ if ((progressOnLast && this->NumberOfRunsLeft == 1) ||
+ (!progressOnLast && this->NumberOfRunsLeft == this->NumberOfRunsTotal) ||
+ this->CTest->GetTestProgressOutput()) {
+ outputStream << std::setw(getNumWidth(total)) << completed << "/";
+ outputStream << std::setw(getNumWidth(total)) << total << " ";
+ }
+ // if this is one of several runs of a test just print blank space
+ // to keep things neat
+ else {
+ outputStream << std::setw(getNumWidth(total)) << " ";
+ outputStream << std::setw(getNumWidth(total)) << " ";
+ }
+
+ if (this->TestHandler->MemCheck) {
+ outputStream << "MemCheck";
+ } else {
+ outputStream << "Test";
+ }
+
+ std::ostringstream indexStr;
+ indexStr << " #" << this->Index << ":";
+ outputStream << std::setw(3 + getNumWidth(this->TestHandler->GetMaxIndex()))
+ << indexStr.str();
+ outputStream << " ";
+
+ const int maxTestNameWidth = this->CTest->GetMaxTestNameWidth();
+ std::string outname = this->TestProperties->Name + " ";
+ outname.resize(maxTestNameWidth + 4, '.');
+ outputStream << outname;
+
+ *this->TestHandler->LogFile << this->TestProperties->Index << "/"
+ << this->TestHandler->TotalNumberOfTests
+ << " Testing: " << this->TestProperties->Name
+ << std::endl;
+ *this->TestHandler->LogFile << this->TestProperties->Index << "/"
+ << this->TestHandler->TotalNumberOfTests
+ << " Test: " << this->TestProperties->Name
+ << std::endl;
+ *this->TestHandler->LogFile << "Command: \"" << this->ActualCommand << "\"";
+
+ for (std::string const& arg : this->Arguments) {
+ *this->TestHandler->LogFile << " \"" << arg << "\"";
+ }
+ *this->TestHandler->LogFile
+ << std::endl
+ << "Directory: " << this->TestProperties->Directory << std::endl
+ << "\"" << this->TestProperties->Name
+ << "\" start time: " << this->StartTime << std::endl;
+
+ *this->TestHandler->LogFile
+ << "Output:" << std::endl
+ << "----------------------------------------------------------"
+ << std::endl;
+ *this->TestHandler->LogFile << this->ProcessOutput << "<end of output>"
+ << std::endl;
+
+ if (!this->CTest->GetTestProgressOutput()) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, outputStream.str());
+ }
+
+ cmCTestLog(this->CTest, DEBUG,
+ "Testing " << this->TestProperties->Name << " ... ");
+}
+
+void cmCTestRunTest::FinalizeTest(bool started)
+{
+ this->MultiTestHandler.FinishTestProcess(this->TestProcess->GetRunner(),
+ started);
+}
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
new file mode 100644
index 0000000..863ac1b
--- /dev/null
+++ b/Source/CTest/cmCTestRunTest.h
@@ -0,0 +1,160 @@
+/* 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 <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <stddef.h>
+
+#include "cmCTest.h"
+#include "cmCTestMultiProcessHandler.h"
+#include "cmCTestTestHandler.h"
+#include "cmDuration.h"
+#include "cmProcess.h"
+
+/** \class cmRunTest
+ * \brief represents a single test to be run
+ *
+ * cmRunTest contains the information related to running a single test
+ */
+class cmCTestRunTest
+{
+public:
+ explicit cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler);
+
+ void SetNumberOfRuns(int n)
+ {
+ this->NumberOfRunsLeft = n;
+ this->NumberOfRunsTotal = n;
+ }
+
+ void SetRepeatMode(cmCTest::Repeat r) { this->RepeatMode = r; }
+ void SetTestProperties(cmCTestTestHandler::cmCTestTestProperties* prop)
+ {
+ this->TestProperties = prop;
+ }
+
+ cmCTestTestHandler::cmCTestTestProperties* GetTestProperties()
+ {
+ return this->TestProperties;
+ }
+
+ void SetIndex(int i) { this->Index = i; }
+
+ int GetIndex() { return this->Index; }
+
+ void AddFailedDependency(const std::string& failedTest)
+ {
+ this->FailedDependencies.insert(failedTest);
+ }
+
+ std::string GetProcessOutput() { return this->ProcessOutput; }
+
+ cmCTestTestHandler::cmCTestTestResult GetTestResults()
+ {
+ return this->TestResult;
+ }
+
+ // Read and store output. Returns true if it must be called again.
+ void CheckOutput(std::string const& line);
+
+ static bool StartTest(std::unique_ptr<cmCTestRunTest> runner,
+ size_t completed, size_t total);
+ static bool StartAgain(std::unique_ptr<cmCTestRunTest> runner,
+ size_t completed);
+
+ static void StartFailure(std::unique_ptr<cmCTestRunTest> runner,
+ std::string const& output,
+ std::string const& detail);
+
+ // launch the test process, return whether it started correctly
+ bool StartTest(size_t completed, size_t total);
+ // capture and report the test results
+ bool EndTest(size_t completed, size_t total, bool started);
+ // Called by ctest -N to log the command string
+ void ComputeArguments();
+
+ void ComputeWeightedCost();
+
+ void StartFailure(std::string const& output, std::string const& detail);
+
+ cmCTest* GetCTest() const { return this->CTest; }
+
+ std::string& GetActualCommand() { return this->ActualCommand; }
+
+ const std::vector<std::string>& GetArguments() { return this->Arguments; }
+
+ void FinalizeTest(bool started = true);
+
+ bool TimedOutForStopTime() const { return this->TimeoutIsForStopTime; }
+
+ void SetUseAllocatedResources(bool use)
+ {
+ this->UseAllocatedResources = use;
+ }
+ void SetAllocatedResources(
+ const std::vector<
+ std::map<std::string,
+ std::vector<cmCTestMultiProcessHandler::ResourceAllocation>>>&
+ resources)
+ {
+ this->AllocatedResources = resources;
+ }
+
+private:
+ bool NeedsToRepeat();
+ void DartProcessing();
+ void ExeNotFound(std::string exe);
+ bool ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
+ std::vector<std::string>* environment,
+ std::vector<size_t>* affinity);
+ void WriteLogOutputTop(size_t completed, size_t total);
+ // Run post processing of the process output for MemCheck
+ void MemCheckPostProcess();
+
+ void SetupResourcesEnvironment(std::vector<std::string>* log = nullptr);
+
+ // Returns "completed/total Test #Index: "
+ std::string GetTestPrefix(size_t completed, size_t total) const;
+
+ cmCTestTestHandler::cmCTestTestProperties* TestProperties;
+ bool TimeoutIsForStopTime = false;
+ // Pointer back to the "parent"; the handler that invoked this test run
+ cmCTestTestHandler* TestHandler;
+ cmCTest* CTest;
+ std::unique_ptr<cmProcess> TestProcess;
+ std::string ProcessOutput;
+ // The test results
+ cmCTestTestHandler::cmCTestTestResult TestResult;
+ cmCTestMultiProcessHandler& MultiTestHandler;
+ int Index;
+ std::set<std::string> FailedDependencies;
+ std::string StartTime;
+ std::string ActualCommand;
+ std::vector<std::string> Arguments;
+ bool UseAllocatedResources = false;
+ std::vector<std::map<
+ std::string, std::vector<cmCTestMultiProcessHandler::ResourceAllocation>>>
+ AllocatedResources;
+ cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never;
+ int NumberOfRunsLeft = 1; // default to 1 run of the test
+ int NumberOfRunsTotal = 1; // default to 1 run of the test
+ bool RunAgain = false; // default to not having to run again
+ size_t TotalNumberOfTests;
+};
+
+inline int getNumWidth(size_t n)
+{
+ int w = 1;
+ while (n >= 10) {
+ n /= 10;
+ ++w;
+ }
+ return w;
+}
diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx
new file mode 100644
index 0000000..4692dbd
--- /dev/null
+++ b/Source/CTest/cmCTestSVN.cxx
@@ -0,0 +1,564 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestSVN.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <map>
+#include <ostream>
+
+#include <cmext/algorithm>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCTest.h"
+#include "cmCTestVC.h"
+#include "cmProcessTools.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include "cmXMLWriter.h"
+
+struct cmCTestSVN::Revision : public cmCTestVC::Revision
+{
+ cmCTestSVN::SVNInfo* SVNInfo;
+};
+
+cmCTestSVN::cmCTestSVN(cmCTest* ct, std::ostream& log)
+ : cmCTestGlobalVC(ct, log)
+{
+ this->PriorRev = this->Unknown;
+}
+
+cmCTestSVN::~cmCTestSVN() = default;
+
+void cmCTestSVN::CleanupImpl()
+{
+ std::vector<const char*> svn_cleanup;
+ svn_cleanup.push_back("cleanup");
+ OutputLogger out(this->Log, "cleanup-out> ");
+ OutputLogger err(this->Log, "cleanup-err> ");
+ this->RunSVNCommand(svn_cleanup, &out, &err);
+}
+
+class cmCTestSVN::InfoParser : public cmCTestVC::LineParser
+{
+public:
+ InfoParser(cmCTestSVN* svn, const char* prefix, std::string& rev,
+ SVNInfo& svninfo)
+ : Rev(rev)
+ , SVNRepo(svninfo)
+ {
+ this->SetLog(&svn->Log, prefix);
+ this->RegexRev.compile("^Revision: ([0-9]+)");
+ this->RegexURL.compile("^URL: +([^ ]+) *$");
+ this->RegexRoot.compile("^Repository Root: +([^ ]+) *$");
+ }
+
+private:
+ std::string& Rev;
+ cmCTestSVN::SVNInfo& SVNRepo;
+ cmsys::RegularExpression RegexRev;
+ cmsys::RegularExpression RegexURL;
+ cmsys::RegularExpression RegexRoot;
+ bool ProcessLine() override
+ {
+ if (this->RegexRev.find(this->Line)) {
+ this->Rev = this->RegexRev.match(1);
+ } else if (this->RegexURL.find(this->Line)) {
+ this->SVNRepo.URL = this->RegexURL.match(1);
+ } else if (this->RegexRoot.find(this->Line)) {
+ this->SVNRepo.Root = this->RegexRoot.match(1);
+ }
+ return true;
+ }
+};
+
+static bool cmCTestSVNPathStarts(std::string const& p1, std::string const& p2)
+{
+ // Does path p1 start with path p2?
+ if (p1.size() == p2.size()) {
+ return p1 == p2;
+ }
+ if (p1.size() > p2.size() && p1[p2.size()] == '/') {
+ return strncmp(p1.c_str(), p2.c_str(), p2.size()) == 0;
+ }
+ return false;
+}
+
+std::string cmCTestSVN::LoadInfo(SVNInfo& svninfo)
+{
+ // Run "svn info" to get the repository info from the work tree.
+ std::vector<const char*> svn_info;
+ svn_info.push_back("info");
+ svn_info.push_back(svninfo.LocalPath.c_str());
+ std::string rev;
+ InfoParser out(this, "info-out> ", rev, svninfo);
+ OutputLogger err(this->Log, "info-err> ");
+ this->RunSVNCommand(svn_info, &out, &err);
+ return rev;
+}
+
+bool cmCTestSVN::NoteOldRevision()
+{
+ if (!this->LoadRepositories()) {
+ return false;
+ }
+
+ for (SVNInfo& svninfo : this->Repositories) {
+ svninfo.OldRevision = this->LoadInfo(svninfo);
+ this->Log << "Revision for repository '" << svninfo.LocalPath
+ << "' before update: " << svninfo.OldRevision << "\n";
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Old revision of external repository '"
+ << svninfo.LocalPath << "' is: " << svninfo.OldRevision
+ << "\n");
+ }
+
+ // Set the global old revision to the one of the root
+ this->OldRevision = this->RootInfo->OldRevision;
+ this->PriorRev.Rev = this->OldRevision;
+ return true;
+}
+
+bool cmCTestSVN::NoteNewRevision()
+{
+ if (!this->LoadRepositories()) {
+ return false;
+ }
+
+ for (SVNInfo& svninfo : this->Repositories) {
+ svninfo.NewRevision = this->LoadInfo(svninfo);
+ this->Log << "Revision for repository '" << svninfo.LocalPath
+ << "' after update: " << svninfo.NewRevision << "\n";
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " New revision of external repository '"
+ << svninfo.LocalPath << "' is: " << svninfo.NewRevision
+ << "\n");
+
+ // svninfo.Root = ""; // uncomment to test GuessBase
+ this->Log << "Repository '" << svninfo.LocalPath
+ << "' URL = " << svninfo.URL << "\n";
+ this->Log << "Repository '" << svninfo.LocalPath
+ << "' Root = " << svninfo.Root << "\n";
+
+ // Compute the base path the working tree has checked out under
+ // the repository root.
+ if (!svninfo.Root.empty() &&
+ cmCTestSVNPathStarts(svninfo.URL, svninfo.Root)) {
+ svninfo.Base = cmStrCat(
+ cmCTest::DecodeURL(svninfo.URL.substr(svninfo.Root.size())), '/');
+ }
+ this->Log << "Repository '" << svninfo.LocalPath
+ << "' Base = " << svninfo.Base << "\n";
+ }
+
+ // Set the global new revision to the one of the root
+ this->NewRevision = this->RootInfo->NewRevision;
+ return true;
+}
+
+void cmCTestSVN::GuessBase(SVNInfo& svninfo,
+ std::vector<Change> const& changes)
+{
+ // Subversion did not give us a good repository root so we need to
+ // guess the base path from the URL and the paths in a revision with
+ // changes under it.
+
+ // Consider each possible URL suffix from longest to shortest.
+ for (std::string::size_type slash = svninfo.URL.find('/');
+ svninfo.Base.empty() && slash != std::string::npos;
+ slash = svninfo.URL.find('/', slash + 1)) {
+ // If the URL suffix is a prefix of at least one path then it is the base.
+ std::string base = cmCTest::DecodeURL(svninfo.URL.substr(slash));
+ for (auto ci = changes.begin();
+ svninfo.Base.empty() && ci != changes.end(); ++ci) {
+ if (cmCTestSVNPathStarts(ci->Path, base)) {
+ svninfo.Base = base;
+ }
+ }
+ }
+
+ // We always append a slash so that we know paths beginning in the
+ // base lie under its path. If no base was found then the working
+ // tree must be a checkout of the entire repo and this will match
+ // the leading slash in all paths.
+ svninfo.Base += "/";
+
+ this->Log << "Guessed Base = " << svninfo.Base << "\n";
+}
+
+class cmCTestSVN::UpdateParser : public cmCTestVC::LineParser
+{
+public:
+ UpdateParser(cmCTestSVN* svn, const char* prefix)
+ : SVN(svn)
+ {
+ this->SetLog(&svn->Log, prefix);
+ this->RegexUpdate.compile("^([ADUCGE ])([ADUCGE ])[B ] +(.+)$");
+ }
+
+private:
+ cmCTestSVN* SVN;
+ cmsys::RegularExpression RegexUpdate;
+
+ bool ProcessLine() override
+ {
+ if (this->RegexUpdate.find(this->Line)) {
+ this->DoPath(this->RegexUpdate.match(1)[0],
+ this->RegexUpdate.match(2)[0], this->RegexUpdate.match(3));
+ }
+ return true;
+ }
+
+ void DoPath(char path_status, char prop_status, std::string const& path)
+ {
+ char status = (path_status != ' ') ? path_status : prop_status;
+ std::string dir = cmSystemTools::GetFilenamePath(path);
+ std::string name = cmSystemTools::GetFilenameName(path);
+ // See "svn help update".
+ switch (status) {
+ case 'G':
+ this->SVN->Dirs[dir][name].Status = PathModified;
+ break;
+ case 'C':
+ this->SVN->Dirs[dir][name].Status = PathConflicting;
+ break;
+ case 'A':
+ case 'D':
+ case 'U':
+ this->SVN->Dirs[dir][name].Status = PathUpdated;
+ break;
+ case 'E': // TODO?
+ case '?':
+ case ' ':
+ default:
+ break;
+ }
+ }
+};
+
+bool cmCTestSVN::UpdateImpl()
+{
+ // Get user-specified update options.
+ std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
+ if (opts.empty()) {
+ opts = this->CTest->GetCTestConfiguration("SVNUpdateOptions");
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
+
+ // Specify the start time for nightly testing.
+ if (this->CTest->GetTestModel() == cmCTest::NIGHTLY) {
+ args.push_back("-r{" + this->GetNightlyTime() + " +0000}");
+ }
+
+ std::vector<char const*> svn_update;
+ svn_update.push_back("update");
+ for (std::string const& arg : args) {
+ svn_update.push_back(arg.c_str());
+ }
+
+ UpdateParser out(this, "up-out> ");
+ OutputLogger err(this->Log, "up-err> ");
+ return this->RunSVNCommand(svn_update, &out, &err);
+}
+
+bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters,
+ OutputParser* out, OutputParser* err)
+{
+ if (parameters.empty()) {
+ return false;
+ }
+
+ std::vector<char const*> args;
+ args.push_back(this->CommandLineTool.c_str());
+ cm::append(args, parameters);
+ args.push_back("--non-interactive");
+
+ std::string userOptions = this->CTest->GetCTestConfiguration("SVNOptions");
+
+ std::vector<std::string> parsedUserOptions =
+ cmSystemTools::ParseArguments(userOptions);
+ for (std::string const& opt : parsedUserOptions) {
+ args.push_back(opt.c_str());
+ }
+
+ args.push_back(nullptr);
+
+ if (strcmp(parameters[0], "update") == 0) {
+ return this->RunUpdateCommand(&args[0], out, err);
+ }
+ return this->RunChild(&args[0], out, err);
+}
+
+class cmCTestSVN::LogParser
+ : public cmCTestVC::OutputLogger
+ , private cmXMLParser
+{
+public:
+ LogParser(cmCTestSVN* svn, const char* prefix, SVNInfo& svninfo)
+ : OutputLogger(svn->Log, prefix)
+ , SVN(svn)
+ , SVNRepo(svninfo)
+ {
+ this->InitializeParser();
+ }
+ ~LogParser() override { this->CleanupParser(); }
+
+private:
+ cmCTestSVN* SVN;
+ cmCTestSVN::SVNInfo& SVNRepo;
+
+ using Revision = cmCTestSVN::Revision;
+ using Change = cmCTestSVN::Change;
+ Revision Rev;
+ std::vector<Change> Changes;
+ Change CurChange;
+ std::vector<char> CData;
+
+ bool ProcessChunk(const char* data, int length) override
+ {
+ this->OutputLogger::ProcessChunk(data, length);
+ this->ParseChunk(data, length);
+ return true;
+ }
+
+ void StartElement(const std::string& name, const char** atts) override
+ {
+ this->CData.clear();
+ if (name == "logentry") {
+ this->Rev = Revision();
+ this->Rev.SVNInfo = &this->SVNRepo;
+ if (const char* rev =
+ cmCTestSVN::LogParser::FindAttribute(atts, "revision")) {
+ this->Rev.Rev = rev;
+ }
+ this->Changes.clear();
+ } else if (name == "path") {
+ this->CurChange = Change();
+ if (const char* action =
+ cmCTestSVN::LogParser::FindAttribute(atts, "action")) {
+ this->CurChange.Action = action[0];
+ }
+ }
+ }
+
+ void CharacterDataHandler(const char* data, int length) override
+ {
+ cm::append(this->CData, data, data + length);
+ }
+
+ void EndElement(const std::string& name) override
+ {
+ if (name == "logentry") {
+ this->SVN->DoRevisionSVN(this->Rev, this->Changes);
+ } else if (!this->CData.empty() && name == "path") {
+ std::string orig_path(&this->CData[0], this->CData.size());
+ std::string new_path = this->SVNRepo.BuildLocalPath(orig_path);
+ this->CurChange.Path.assign(new_path);
+ this->Changes.push_back(this->CurChange);
+ } else if (!this->CData.empty() && name == "author") {
+ this->Rev.Author.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "date") {
+ this->Rev.Date.assign(&this->CData[0], this->CData.size());
+ } else if (!this->CData.empty() && name == "msg") {
+ this->Rev.Log.assign(&this->CData[0], this->CData.size());
+ }
+ this->CData.clear();
+ }
+
+ void ReportError(int /*line*/, int /*column*/, const char* msg) override
+ {
+ this->SVN->Log << "Error parsing svn log xml: " << msg << "\n";
+ }
+};
+
+bool cmCTestSVN::LoadRevisions()
+{
+ bool result = true;
+ // Get revisions for all the external repositories
+ for (SVNInfo& svninfo : this->Repositories) {
+ result = this->LoadRevisions(svninfo) && result;
+ }
+ return result;
+}
+
+bool cmCTestSVN::LoadRevisions(SVNInfo& svninfo)
+{
+ // We are interested in every revision included in the update.
+ std::string revs;
+ if (atoi(svninfo.OldRevision.c_str()) < atoi(svninfo.NewRevision.c_str())) {
+ revs = "-r" + svninfo.OldRevision + ":" + svninfo.NewRevision;
+ } else {
+ revs = "-r" + svninfo.NewRevision;
+ }
+
+ // Run "svn log" to get all global revisions of interest.
+ std::vector<const char*> svn_log;
+ svn_log.push_back("log");
+ svn_log.push_back("--xml");
+ svn_log.push_back("-v");
+ svn_log.push_back(revs.c_str());
+ svn_log.push_back(svninfo.LocalPath.c_str());
+ LogParser out(this, "log-out> ", svninfo);
+ OutputLogger err(this->Log, "log-err> ");
+ return this->RunSVNCommand(svn_log, &out, &err);
+}
+
+void cmCTestSVN::DoRevisionSVN(Revision const& revision,
+ std::vector<Change> const& changes)
+{
+ // Guess the base checkout path from the changes if necessary.
+ if (this->RootInfo->Base.empty() && !changes.empty()) {
+ this->GuessBase(*this->RootInfo, changes);
+ }
+
+ // Ignore changes in the old revision for external repositories
+ if (revision.Rev == revision.SVNInfo->OldRevision &&
+ !revision.SVNInfo->LocalPath.empty()) {
+ return;
+ }
+
+ this->cmCTestGlobalVC::DoRevision(revision, changes);
+}
+
+class cmCTestSVN::StatusParser : public cmCTestVC::LineParser
+{
+public:
+ StatusParser(cmCTestSVN* svn, const char* prefix)
+ : SVN(svn)
+ {
+ this->SetLog(&svn->Log, prefix);
+ this->RegexStatus.compile("^([ACDIMRX?!~ ])([CM ])[ L]... +(.+)$");
+ }
+
+private:
+ cmCTestSVN* SVN;
+ cmsys::RegularExpression RegexStatus;
+ bool ProcessLine() override
+ {
+ if (this->RegexStatus.find(this->Line)) {
+ this->DoPath(this->RegexStatus.match(1)[0],
+ this->RegexStatus.match(2)[0], this->RegexStatus.match(3));
+ }
+ return true;
+ }
+
+ void DoPath(char path_status, char prop_status, std::string const& path)
+ {
+ char status = (path_status != ' ') ? path_status : prop_status;
+ // See "svn help status".
+ switch (status) {
+ case 'M':
+ case '!':
+ case 'A':
+ case 'D':
+ case 'R':
+ this->SVN->DoModification(PathModified, path);
+ break;
+ case 'C':
+ case '~':
+ this->SVN->DoModification(PathConflicting, path);
+ break;
+ case 'X':
+ case 'I':
+ case '?':
+ case ' ':
+ default:
+ break;
+ }
+ }
+};
+
+bool cmCTestSVN::LoadModifications()
+{
+ // Run "svn status" which reports local modifications.
+ std::vector<const char*> svn_status;
+ svn_status.push_back("status");
+ StatusParser out(this, "status-out> ");
+ OutputLogger err(this->Log, "status-err> ");
+ this->RunSVNCommand(svn_status, &out, &err);
+ return true;
+}
+
+void cmCTestSVN::WriteXMLGlobal(cmXMLWriter& xml)
+{
+ this->cmCTestGlobalVC::WriteXMLGlobal(xml);
+
+ xml.Element("SVNPath", this->RootInfo->Base);
+}
+
+class cmCTestSVN::ExternalParser : public cmCTestVC::LineParser
+{
+public:
+ ExternalParser(cmCTestSVN* svn, const char* prefix)
+ : SVN(svn)
+ {
+ this->SetLog(&svn->Log, prefix);
+ this->RegexExternal.compile("^X..... +(.+)$");
+ }
+
+private:
+ cmCTestSVN* SVN;
+ cmsys::RegularExpression RegexExternal;
+ bool ProcessLine() override
+ {
+ if (this->RegexExternal.find(this->Line)) {
+ this->DoPath(this->RegexExternal.match(1));
+ }
+ return true;
+ }
+
+ void DoPath(std::string const& path)
+ {
+ // Get local path relative to the source directory
+ std::string local_path;
+ if (path.size() > this->SVN->SourceDirectory.size() &&
+ strncmp(path.c_str(), this->SVN->SourceDirectory.c_str(),
+ this->SVN->SourceDirectory.size()) == 0) {
+ local_path = path.substr(this->SVN->SourceDirectory.size() + 1);
+ } else {
+ local_path = path;
+ }
+ this->SVN->Repositories.emplace_back(local_path);
+ }
+};
+
+bool cmCTestSVN::LoadRepositories()
+{
+ if (!this->Repositories.empty()) {
+ return true;
+ }
+
+ // Info for root repository
+ this->Repositories.emplace_back();
+ this->RootInfo = &(this->Repositories.back());
+
+ // Run "svn status" to get the list of external repositories
+ std::vector<const char*> svn_status;
+ svn_status.push_back("status");
+ ExternalParser out(this, "external-out> ");
+ OutputLogger err(this->Log, "external-err> ");
+ return this->RunSVNCommand(svn_status, &out, &err);
+}
+
+std::string cmCTestSVN::SVNInfo::BuildLocalPath(std::string const& path) const
+{
+ std::string local_path;
+
+ // Add local path prefix if not empty
+ if (!this->LocalPath.empty()) {
+ local_path += this->LocalPath;
+ local_path += "/";
+ }
+
+ // Add path with base prefix removed
+ if (path.size() > this->Base.size() &&
+ strncmp(path.c_str(), this->Base.c_str(), this->Base.size()) == 0) {
+ local_path += path.substr(this->Base.size());
+ } else {
+ local_path += path;
+ }
+
+ return local_path;
+}
diff --git a/Source/CTest/cmCTestSVN.h b/Source/CTest/cmCTestSVN.h
new file mode 100644
index 0000000..370d176
--- /dev/null
+++ b/Source/CTest/cmCTestSVN.h
@@ -0,0 +1,104 @@
+/* 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 <iosfwd>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "cmCTestGlobalVC.h"
+
+class cmCTest;
+class cmXMLWriter;
+
+/** \class cmCTestSVN
+ * \brief Interaction with subversion command-line tool
+ *
+ */
+class cmCTestSVN : public cmCTestGlobalVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestSVN(cmCTest* ctest, std::ostream& log);
+
+ ~cmCTestSVN() override;
+
+private:
+ // Implement cmCTestVC internal API.
+ void CleanupImpl() override;
+ bool NoteOldRevision() override;
+ bool NoteNewRevision() override;
+ bool UpdateImpl() override;
+
+ bool RunSVNCommand(std::vector<char const*> const& parameters,
+ OutputParser* out, OutputParser* err);
+
+ // Information about an SVN repository (root repository or external)
+ struct SVNInfo
+ {
+
+ SVNInfo(std::string const& path = std::string())
+ : LocalPath(path)
+ {
+ }
+ // Remove base from the filename
+ std::string BuildLocalPath(std::string const& path) const;
+
+ // LocalPath relative to the main source directory.
+ std::string LocalPath;
+
+ // URL of repository directory checked out in the working tree.
+ std::string URL;
+
+ // URL of repository root directory.
+ std::string Root;
+
+ // Directory under repository root checked out in working tree.
+ std::string Base;
+
+ // Old and new repository revisions.
+ std::string OldRevision;
+ std::string NewRevision;
+ };
+
+ // Extended revision structure to include info about external it refers to.
+ struct Revision;
+
+ friend struct Revision;
+
+ // Info of all the repositories (root, externals and nested ones).
+ // Use std::list so the elements don't move in memory.
+ std::list<SVNInfo> Repositories;
+
+ // Pointer to the infos of the root repository.
+ SVNInfo* RootInfo;
+
+ std::string LoadInfo(SVNInfo& svninfo);
+ bool LoadRepositories();
+ bool LoadModifications() override;
+ bool LoadRevisions() override;
+ bool LoadRevisions(SVNInfo& svninfo);
+
+ void GuessBase(SVNInfo& svninfo, std::vector<Change> const& changes);
+
+ void DoRevisionSVN(Revision const& revision,
+ std::vector<Change> const& changes);
+
+ void WriteXMLGlobal(cmXMLWriter& xml) override;
+
+ class ExternalParser;
+ // Parsing helper classes.
+ class InfoParser;
+ class LogParser;
+ class StatusParser;
+ class UpdateParser;
+
+ friend class InfoParser;
+ friend class LogParser;
+ friend class StatusParser;
+ friend class UpdateParser;
+ friend class ExternalParser;
+};
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
new file mode 100644
index 0000000..ff0b179
--- /dev/null
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -0,0 +1,949 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestScriptHandler.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <map>
+#include <ratio>
+#include <sstream>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/Process.h"
+
+#include "cmCTest.h"
+#include "cmCTestBuildCommand.h"
+#include "cmCTestCommand.h"
+#include "cmCTestConfigureCommand.h"
+#include "cmCTestCoverageCommand.h"
+#include "cmCTestEmptyBinaryDirectoryCommand.h"
+#include "cmCTestMemCheckCommand.h"
+#include "cmCTestReadCustomFilesCommand.h"
+#include "cmCTestRunScriptCommand.h"
+#include "cmCTestSleepCommand.h"
+#include "cmCTestStartCommand.h"
+#include "cmCTestSubmitCommand.h"
+#include "cmCTestTestCommand.h"
+#include "cmCTestUpdateCommand.h"
+#include "cmCTestUploadCommand.h"
+#include "cmCommand.h"
+#include "cmDuration.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#ifdef _WIN32
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+#define CTEST_INITIAL_CMAKE_OUTPUT_FILE_NAME "CTestInitialCMakeOutput.log"
+
+cmCTestScriptHandler::cmCTestScriptHandler() = default;
+
+void cmCTestScriptHandler::Initialize()
+{
+ this->Superclass::Initialize();
+ this->Backup = false;
+ this->EmptyBinDir = false;
+ this->EmptyBinDirOnce = false;
+
+ this->SourceDir.clear();
+ this->BinaryDir.clear();
+ this->BackupSourceDir.clear();
+ this->BackupBinaryDir.clear();
+ this->CTestRoot.clear();
+ this->CVSCheckOut.clear();
+ this->CTestCmd.clear();
+ this->UpdateCmd.clear();
+ this->CTestEnv.clear();
+ this->InitialCache.clear();
+ this->CMakeCmd.clear();
+ this->CMOutFile.clear();
+ this->ExtraUpdates.clear();
+
+ this->MinimumInterval = 20 * 60;
+ this->ContinuousDuration = -1;
+
+ // what time in seconds did this script start running
+ this->ScriptStartTime = std::chrono::steady_clock::time_point();
+
+ this->Makefile.reset();
+ this->ParentMakefile = nullptr;
+
+ this->GlobalGenerator.reset();
+
+ this->CMake.reset();
+}
+
+cmCTestScriptHandler::~cmCTestScriptHandler() = default;
+
+// just adds an argument to the vector
+void cmCTestScriptHandler::AddConfigurationScript(const std::string& script,
+ bool pscope)
+{
+ this->ConfigurationScripts.emplace_back(script);
+ this->ScriptProcessScope.push_back(pscope);
+}
+
+// the generic entry point for handling scripts, this routine will run all
+// the scripts provides a -S arguments
+int cmCTestScriptHandler::ProcessHandler()
+{
+ int res = 0;
+ for (size_t i = 0; i < this->ConfigurationScripts.size(); ++i) {
+ // for each script run it
+ res |= this->RunConfigurationScript(
+ cmSystemTools::CollapseFullPath(this->ConfigurationScripts[i]),
+ this->ScriptProcessScope[i]);
+ }
+ if (res) {
+ return -1;
+ }
+ return 0;
+}
+
+void cmCTestScriptHandler::UpdateElapsedTime()
+{
+ if (this->Makefile) {
+ // set the current elapsed time
+ auto itime = cmDurationTo<unsigned int>(std::chrono::steady_clock::now() -
+ this->ScriptStartTime);
+ auto timeString = std::to_string(itime);
+ this->Makefile->AddDefinition("CTEST_ELAPSED_TIME", timeString);
+ }
+}
+
+void cmCTestScriptHandler::AddCTestCommand(
+ std::string const& name, std::unique_ptr<cmCTestCommand> command)
+{
+ command->CTest = this->CTest;
+ command->CTestScriptHandler = this;
+ this->CMake->GetState()->AddBuiltinCommand(name, std::move(command));
+}
+
+int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
+{
+ // execute the script passing in the arguments to the script as well as the
+ // arguments from this invocation of cmake
+ std::vector<const char*> argv;
+ argv.push_back(cmSystemTools::GetCTestCommand().c_str());
+ argv.push_back("-SR");
+ argv.push_back(total_script_arg.c_str());
+
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Executable for CTest is: " << cmSystemTools::GetCTestCommand()
+ << "\n");
+
+ // now pass through all the other arguments
+ std::vector<std::string>& initArgs =
+ this->CTest->GetInitialCommandLineArguments();
+ //*** need to make sure this does not have the current script ***
+ for (size_t i = 1; i < initArgs.size(); ++i) {
+ argv.push_back(initArgs[i].c_str());
+ }
+ argv.push_back(nullptr);
+
+ // Now create process object
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, argv.data());
+ // cmsysProcess_SetWorkingDirectory(cp, dir);
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ // cmsysProcess_SetTimeout(cp, timeout);
+ cmsysProcess_Execute(cp);
+
+ std::vector<char> out;
+ std::vector<char> err;
+ std::string line;
+ int pipe =
+ cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, err);
+ while (pipe != cmsysProcess_Pipe_None) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Output: " << line << "\n");
+ if (pipe == cmsysProcess_Pipe_STDERR) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, line << "\n");
+ } else if (pipe == cmsysProcess_Pipe_STDOUT) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n");
+ }
+ pipe = cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out,
+ err);
+ }
+
+ // Properly handle output of the build command
+ cmsysProcess_WaitForExit(cp, nullptr);
+ int result = cmsysProcess_GetState(cp);
+ int retVal = 0;
+ bool failed = false;
+ if (result == cmsysProcess_State_Exited) {
+ retVal = cmsysProcess_GetExitValue(cp);
+ } else if (result == cmsysProcess_State_Exception) {
+ retVal = cmsysProcess_GetExitException(cp);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "\tThere was an exception: "
+ << cmsysProcess_GetExceptionString(cp) << " " << retVal
+ << std::endl);
+ failed = true;
+ } else if (result == cmsysProcess_State_Expired) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "\tThere was a timeout" << std::endl);
+ failed = true;
+ } else if (result == cmsysProcess_State_Error) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "\tError executing ctest: " << cmsysProcess_GetErrorString(cp)
+ << std::endl);
+ failed = true;
+ }
+ cmsysProcess_Delete(cp);
+ if (failed) {
+ std::ostringstream message;
+ message << "Error running command: [";
+ message << result << "] ";
+ for (const char* arg : argv) {
+ if (arg) {
+ message << arg << " ";
+ }
+ }
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ message.str() << argv[0] << std::endl);
+ return -1;
+ }
+ return retVal;
+}
+
+void cmCTestScriptHandler::CreateCMake()
+{
+ // create a cmake instance to read the configuration script
+ this->CMake = cm::make_unique<cmake>(cmake::RoleScript, cmState::CTest);
+ this->CMake->SetHomeDirectory("");
+ this->CMake->SetHomeOutputDirectory("");
+ this->CMake->GetCurrentSnapshot().SetDefaultDefinitions();
+ this->CMake->AddCMakePaths();
+ this->GlobalGenerator =
+ cm::make_unique<cmGlobalGenerator>(this->CMake.get());
+
+ cmStateSnapshot snapshot = this->CMake->GetCurrentSnapshot();
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ snapshot.GetDirectory().SetCurrentSource(cwd);
+ snapshot.GetDirectory().SetCurrentBinary(cwd);
+ this->Makefile =
+ cm::make_unique<cmMakefile>(this->GlobalGenerator.get(), snapshot);
+ if (this->ParentMakefile) {
+ this->Makefile->SetRecursionDepth(
+ this->ParentMakefile->GetRecursionDepth());
+ }
+
+ this->CMake->SetProgressCallback(
+ [this](const std::string& m, float /*unused*/) {
+ if (!m.empty()) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "-- " << m << std::endl);
+ }
+ });
+
+ this->AddCTestCommand("ctest_build", cm::make_unique<cmCTestBuildCommand>());
+ this->AddCTestCommand("ctest_configure",
+ cm::make_unique<cmCTestConfigureCommand>());
+ this->AddCTestCommand("ctest_coverage",
+ cm::make_unique<cmCTestCoverageCommand>());
+ this->AddCTestCommand("ctest_empty_binary_directory",
+ cm::make_unique<cmCTestEmptyBinaryDirectoryCommand>());
+ this->AddCTestCommand("ctest_memcheck",
+ cm::make_unique<cmCTestMemCheckCommand>());
+ this->AddCTestCommand("ctest_read_custom_files",
+ cm::make_unique<cmCTestReadCustomFilesCommand>());
+ this->AddCTestCommand("ctest_run_script",
+ cm::make_unique<cmCTestRunScriptCommand>());
+ this->AddCTestCommand("ctest_sleep", cm::make_unique<cmCTestSleepCommand>());
+ this->AddCTestCommand("ctest_start", cm::make_unique<cmCTestStartCommand>());
+ this->AddCTestCommand("ctest_submit",
+ cm::make_unique<cmCTestSubmitCommand>());
+ this->AddCTestCommand("ctest_test", cm::make_unique<cmCTestTestCommand>());
+ this->AddCTestCommand("ctest_update",
+ cm::make_unique<cmCTestUpdateCommand>());
+ this->AddCTestCommand("ctest_upload",
+ cm::make_unique<cmCTestUploadCommand>());
+}
+
+// this sets up some variables for the script to use, creates the required
+// cmake instance and generators, and then reads in the script
+int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
+{
+ // Reset the error flag so that the script is read in no matter what
+ cmSystemTools::ResetErrorOccuredFlag();
+
+ // if the argument has a , in it then it needs to be broken into the fist
+ // argument (which is the script) and the second argument which will be
+ // passed into the scripts as S_ARG
+ std::string script;
+ std::string script_arg;
+ const std::string::size_type comma_pos = total_script_arg.find(',');
+ if (comma_pos != std::string::npos) {
+ script = total_script_arg.substr(0, comma_pos);
+ script_arg = total_script_arg.substr(comma_pos + 1);
+ } else {
+ script = total_script_arg;
+ }
+ // make sure the file exists
+ if (!cmSystemTools::FileExists(script)) {
+ cmSystemTools::Error("Cannot find file: " + script);
+ return 1;
+ }
+
+ // read in the list file to fill the cache
+ // create a cmake instance to read the configuration script
+ this->CreateCMake();
+
+ // set a variable with the path to the current script
+ this->Makefile->AddDefinition("CTEST_SCRIPT_DIRECTORY",
+ cmSystemTools::GetFilenamePath(script));
+ this->Makefile->AddDefinition("CTEST_SCRIPT_NAME",
+ cmSystemTools::GetFilenameName(script));
+ this->Makefile->AddDefinition("CTEST_EXECUTABLE_NAME",
+ cmSystemTools::GetCTestCommand());
+ this->Makefile->AddDefinition("CMAKE_EXECUTABLE_NAME",
+ cmSystemTools::GetCMakeCommand());
+ this->Makefile->AddDefinitionBool("CTEST_RUN_CURRENT_SCRIPT", true);
+ this->SetRunCurrentScript(true);
+ this->UpdateElapsedTime();
+
+ // set the CTEST_CONFIGURATION_TYPE variable to the current value of the
+ // the -C argument on the command line.
+ if (!this->CTest->GetConfigType().empty()) {
+ this->Makefile->AddDefinition("CTEST_CONFIGURATION_TYPE",
+ this->CTest->GetConfigType());
+ }
+
+ // add the script arg if defined
+ if (!script_arg.empty()) {
+ this->Makefile->AddDefinition("CTEST_SCRIPT_ARG", script_arg);
+ }
+
+#if defined(__CYGWIN__)
+ this->Makefile->AddDefinition("CMAKE_LEGACY_CYGWIN_WIN32", "0");
+#endif
+
+ // set a callback function to update the elapsed time
+ this->Makefile->OnExecuteCommand([this] { this->UpdateElapsedTime(); });
+
+ /* Execute CTestScriptMode.cmake, which loads CMakeDetermineSystem and
+ CMakeSystemSpecificInformation, so
+ that variables like CMAKE_SYSTEM and also the search paths for libraries,
+ header and executables are set correctly and can be used. Makes new-style
+ ctest scripting easier. */
+ std::string systemFile =
+ this->Makefile->GetModulesFile("CTestScriptMode.cmake");
+ if (!this->Makefile->ReadListFile(systemFile) ||
+ cmSystemTools::GetErrorOccuredFlag()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error in read:" << systemFile << "\n");
+ return 2;
+ }
+
+ // Add definitions of variables passed in on the command line:
+ const std::map<std::string, std::string>& defs =
+ this->CTest->GetDefinitions();
+ for (auto const& d : defs) {
+ this->Makefile->AddDefinition(d.first, d.second);
+ }
+
+ // finally read in the script
+ if (!this->Makefile->ReadListFile(script) ||
+ cmSystemTools::GetErrorOccuredFlag()) {
+ // Reset the error flag so that it can run more than
+ // one script with an error when you use ctest_run_script.
+ cmSystemTools::ResetErrorOccuredFlag();
+ return 2;
+ }
+
+ return 0;
+}
+
+// extract variables from the script to set ivars
+int cmCTestScriptHandler::ExtractVariables()
+{
+ // Temporary variables
+ cmProp minInterval;
+ cmProp contDuration;
+
+ this->SourceDir =
+ this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
+ this->BinaryDir =
+ this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY");
+
+ // add in translations for src and bin
+ cmSystemTools::AddKeepPath(this->SourceDir);
+ cmSystemTools::AddKeepPath(this->BinaryDir);
+
+ this->CTestCmd = this->Makefile->GetSafeDefinition("CTEST_COMMAND");
+ this->CVSCheckOut = this->Makefile->GetSafeDefinition("CTEST_CVS_CHECKOUT");
+ this->CTestRoot = this->Makefile->GetSafeDefinition("CTEST_DASHBOARD_ROOT");
+ this->UpdateCmd = this->Makefile->GetSafeDefinition("CTEST_UPDATE_COMMAND");
+ if (this->UpdateCmd.empty()) {
+ this->UpdateCmd = this->Makefile->GetSafeDefinition("CTEST_CVS_COMMAND");
+ }
+ this->CTestEnv = this->Makefile->GetSafeDefinition("CTEST_ENVIRONMENT");
+ this->InitialCache =
+ this->Makefile->GetSafeDefinition("CTEST_INITIAL_CACHE");
+ this->CMakeCmd = this->Makefile->GetSafeDefinition("CTEST_CMAKE_COMMAND");
+ this->CMOutFile =
+ this->Makefile->GetSafeDefinition("CTEST_CMAKE_OUTPUT_FILE_NAME");
+
+ this->Backup = this->Makefile->IsOn("CTEST_BACKUP_AND_RESTORE");
+ this->EmptyBinDir =
+ this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY");
+ this->EmptyBinDirOnce =
+ this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY_ONCE");
+
+ minInterval =
+ this->Makefile->GetDefinition("CTEST_CONTINUOUS_MINIMUM_INTERVAL");
+ contDuration = this->Makefile->GetDefinition("CTEST_CONTINUOUS_DURATION");
+
+ char updateVar[40];
+ int i;
+ for (i = 1; i < 10; ++i) {
+ sprintf(updateVar, "CTEST_EXTRA_UPDATES_%i", i);
+ cmProp updateVal = this->Makefile->GetDefinition(updateVar);
+ if (updateVal) {
+ if (this->UpdateCmd.empty()) {
+ cmSystemTools::Error(
+ std::string(updateVar) +
+ " specified without specifying CTEST_CVS_COMMAND.");
+ return 12;
+ }
+ this->ExtraUpdates.emplace_back(*updateVal);
+ }
+ }
+
+ // in order to backup and restore we also must have the cvs root
+ if (this->Backup && this->CVSCheckOut.empty()) {
+ cmSystemTools::Error(
+ "Backup was requested without specifying CTEST_CVS_CHECKOUT.");
+ return 3;
+ }
+
+ // make sure the required info is here
+ if (this->SourceDir.empty() || this->BinaryDir.empty() ||
+ this->CTestCmd.empty()) {
+ std::string msg =
+ cmStrCat("CTEST_SOURCE_DIRECTORY = ",
+ (!this->SourceDir.empty()) ? this->SourceDir.c_str() : "(Null)",
+ "\nCTEST_BINARY_DIRECTORY = ",
+ (!this->BinaryDir.empty()) ? this->BinaryDir.c_str() : "(Null)",
+ "\nCTEST_COMMAND = ",
+ (!this->CTestCmd.empty()) ? this->CTestCmd.c_str() : "(Null)");
+ cmSystemTools::Error(
+ "Some required settings in the configuration file were missing:\n" +
+ msg);
+ return 4;
+ }
+
+ // if the dashboard root isn't specified then we can compute it from the
+ // this->SourceDir
+ if (this->CTestRoot.empty()) {
+ this->CTestRoot = cmSystemTools::GetFilenamePath(this->SourceDir);
+ }
+
+ // the script may override the minimum continuous interval
+ if (minInterval) {
+ this->MinimumInterval = 60 * atof(minInterval->c_str());
+ }
+ if (contDuration) {
+ this->ContinuousDuration = 60.0 * atof(contDuration->c_str());
+ }
+
+ this->UpdateElapsedTime();
+
+ return 0;
+}
+
+void cmCTestScriptHandler::SleepInSeconds(unsigned int secondsToWait)
+{
+#if defined(_WIN32)
+ Sleep(1000 * secondsToWait);
+#else
+ sleep(secondsToWait);
+#endif
+}
+
+// run a specific script
+int cmCTestScriptHandler::RunConfigurationScript(
+ const std::string& total_script_arg, bool pscope)
+{
+#ifndef CMAKE_BOOTSTRAP
+ cmSystemTools::SaveRestoreEnvironment sre;
+#endif
+
+ int result;
+
+ this->ScriptStartTime = std::chrono::steady_clock::now();
+
+ // read in the script
+ if (pscope) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading Script: " << total_script_arg << std::endl);
+ result = this->ReadInScript(total_script_arg);
+ } else {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Executing Script: " << total_script_arg << std::endl);
+ result = this->ExecuteScript(total_script_arg);
+ }
+ if (result) {
+ return result;
+ }
+
+ // only run the current script if we should
+ if (this->Makefile && this->Makefile->IsOn("CTEST_RUN_CURRENT_SCRIPT") &&
+ this->ShouldRunCurrentScript) {
+ return this->RunCurrentScript();
+ }
+ return result;
+}
+
+int cmCTestScriptHandler::RunCurrentScript()
+{
+ int result;
+
+ // do not run twice
+ this->SetRunCurrentScript(false);
+
+ // no popup widows
+ cmSystemTools::SetRunCommandHideConsole(true);
+
+ // extract the vars from the cache and store in ivars
+ result = this->ExtractVariables();
+ if (result) {
+ return result;
+ }
+
+ // set any environment variables
+ if (!this->CTestEnv.empty()) {
+ std::vector<std::string> envArgs = cmExpandedList(this->CTestEnv);
+ cmSystemTools::AppendEnv(envArgs);
+ }
+
+ // now that we have done most of the error checking finally run the
+ // dashboard, we may be asked to repeatedly run this dashboard, such as
+ // for a continuous, do we need to run it more than once?
+ if (this->ContinuousDuration >= 0) {
+ this->UpdateElapsedTime();
+ auto ending_time =
+ std::chrono::steady_clock::now() + cmDuration(this->ContinuousDuration);
+ if (this->EmptyBinDirOnce) {
+ this->EmptyBinDir = true;
+ }
+ do {
+ auto startOfInterval = std::chrono::steady_clock::now();
+ result = this->RunConfigurationDashboard();
+ auto interval = std::chrono::steady_clock::now() - startOfInterval;
+ auto minimumInterval = cmDuration(this->MinimumInterval);
+ if (interval < minimumInterval) {
+ auto sleepTime =
+ cmDurationTo<unsigned int>(minimumInterval - interval);
+ this->SleepInSeconds(sleepTime);
+ }
+ if (this->EmptyBinDirOnce) {
+ this->EmptyBinDir = false;
+ }
+ } while (std::chrono::steady_clock::now() < ending_time);
+ }
+ // otherwise just run it once
+ else {
+ result = this->RunConfigurationDashboard();
+ }
+
+ return result;
+}
+
+int cmCTestScriptHandler::CheckOutSourceDir()
+{
+ std::string command;
+ std::string output;
+ int retVal;
+ bool res;
+
+ if (!cmSystemTools::FileExists(this->SourceDir) &&
+ !this->CVSCheckOut.empty()) {
+ // we must now checkout the src dir
+ output.clear();
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run cvs: " << this->CVSCheckOut << std::endl);
+ res = cmSystemTools::RunSingleCommand(
+ this->CVSCheckOut, &output, &output, &retVal, this->CTestRoot.c_str(),
+ this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
+ if (!res || retVal != 0) {
+ cmSystemTools::Error("Unable to perform cvs checkout:\n" + output);
+ return 6;
+ }
+ }
+ return 0;
+}
+
+int cmCTestScriptHandler::BackupDirectories()
+{
+ int retVal;
+
+ // compute the backup names
+ this->BackupSourceDir = cmStrCat(this->SourceDir, "_CMakeBackup");
+ this->BackupBinaryDir = cmStrCat(this->BinaryDir, "_CMakeBackup");
+
+ // backup the binary and src directories if requested
+ if (this->Backup) {
+ // if for some reason those directories exist then first delete them
+ if (cmSystemTools::FileExists(this->BackupSourceDir)) {
+ cmSystemTools::RemoveADirectory(this->BackupSourceDir);
+ }
+ if (cmSystemTools::FileExists(this->BackupBinaryDir)) {
+ cmSystemTools::RemoveADirectory(this->BackupBinaryDir);
+ }
+
+ // first rename the src and binary directories
+ rename(this->SourceDir.c_str(), this->BackupSourceDir.c_str());
+ rename(this->BinaryDir.c_str(), this->BackupBinaryDir.c_str());
+
+ // we must now checkout the src dir
+ retVal = this->CheckOutSourceDir();
+ if (retVal) {
+ this->RestoreBackupDirectories();
+ return retVal;
+ }
+ }
+
+ return 0;
+}
+
+int cmCTestScriptHandler::PerformExtraUpdates()
+{
+ std::string command;
+ std::string output;
+ int retVal;
+ bool res;
+
+ // do an initial cvs update as required
+ command = this->UpdateCmd;
+ for (std::string const& eu : this->ExtraUpdates) {
+ std::vector<std::string> cvsArgs = cmExpandedList(eu);
+ if (cvsArgs.size() == 2) {
+ std::string fullCommand = cmStrCat(command, " update ", cvsArgs[1]);
+ output.clear();
+ retVal = 0;
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run Update: " << fullCommand << std::endl);
+ res = cmSystemTools::RunSingleCommand(
+ fullCommand, &output, &output, &retVal, cvsArgs[0].c_str(),
+ this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
+ if (!res || retVal != 0) {
+ cmSystemTools::Error(cmStrCat("Unable to perform extra updates:\n", eu,
+ "\nWith output:\n", output));
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+// run a single dashboard entry
+int cmCTestScriptHandler::RunConfigurationDashboard()
+{
+ // local variables
+ std::string command;
+ std::string output;
+ int retVal;
+ bool res;
+
+ // make sure the src directory is there, if it isn't then we might be able
+ // to check it out from cvs
+ retVal = this->CheckOutSourceDir();
+ if (retVal) {
+ return retVal;
+ }
+
+ // backup the dirs if requested
+ retVal = this->BackupDirectories();
+ if (retVal) {
+ return retVal;
+ }
+
+ // clear the binary directory?
+ if (this->EmptyBinDir) {
+ if (!cmCTestScriptHandler::EmptyBinaryDirectory(this->BinaryDir)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem removing the binary directory" << std::endl);
+ }
+ }
+
+ // make sure the binary directory exists if it isn't the srcdir
+ if (!cmSystemTools::FileExists(this->BinaryDir) &&
+ this->SourceDir != this->BinaryDir) {
+ if (!cmSystemTools::MakeDirectory(this->BinaryDir)) {
+ cmSystemTools::Error("Unable to create the binary directory:\n" +
+ this->BinaryDir);
+ this->RestoreBackupDirectories();
+ return 7;
+ }
+ }
+
+ // if the binary directory and the source directory are the same,
+ // and we are starting with an empty binary directory, then that means
+ // we must check out the source tree
+ if (this->EmptyBinDir && this->SourceDir == this->BinaryDir) {
+ // make sure we have the required info
+ if (this->CVSCheckOut.empty()) {
+ cmSystemTools::Error(
+ "You have specified the source and binary "
+ "directories to be the same (an in source build). You have also "
+ "specified that the binary directory is to be erased. This means "
+ "that the source will have to be checked out from CVS. But you have "
+ "not specified CTEST_CVS_CHECKOUT");
+ return 8;
+ }
+
+ // we must now checkout the src dir
+ retVal = this->CheckOutSourceDir();
+ if (retVal) {
+ this->RestoreBackupDirectories();
+ return retVal;
+ }
+ }
+
+ // backup the dirs if requested
+ retVal = this->PerformExtraUpdates();
+ if (retVal) {
+ return retVal;
+ }
+
+ // put the initial cache into the bin dir
+ if (!this->InitialCache.empty()) {
+ if (!cmCTestScriptHandler::WriteInitialCache(this->BinaryDir,
+ this->InitialCache)) {
+ this->RestoreBackupDirectories();
+ return 9;
+ }
+ }
+
+ // do an initial cmake to setup the DartConfig file
+ int cmakeFailed = 0;
+ std::string cmakeFailedOuput;
+ if (!this->CMakeCmd.empty()) {
+ command = cmStrCat(this->CMakeCmd, " \"", this->SourceDir);
+ output.clear();
+ command += "\"";
+ retVal = 0;
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run cmake command: " << command << std::endl);
+ res = cmSystemTools::RunSingleCommand(
+ command, &output, &output, &retVal, this->BinaryDir.c_str(),
+ this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
+
+ if (!this->CMOutFile.empty()) {
+ std::string cmakeOutputFile = this->CMOutFile;
+ if (!cmSystemTools::FileIsFullPath(cmakeOutputFile)) {
+ cmakeOutputFile = this->BinaryDir + "/" + cmakeOutputFile;
+ }
+
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Write CMake output to file: " << cmakeOutputFile
+ << std::endl);
+ cmGeneratedFileStream fout(cmakeOutputFile);
+ if (fout) {
+ fout << output.c_str();
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open CMake output file: "
+ << cmakeOutputFile << " for writing" << std::endl);
+ }
+ }
+ if (!res || retVal != 0) {
+ // even if this fails continue to the next step
+ cmakeFailed = 1;
+ cmakeFailedOuput = output;
+ }
+ }
+
+ // run ctest, it may be more than one command in here
+ std::vector<std::string> ctestCommands = cmExpandedList(this->CTestCmd);
+ // for each variable/argument do a putenv
+ for (std::string const& ctestCommand : ctestCommands) {
+ command = ctestCommand;
+ output.clear();
+ retVal = 0;
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run ctest command: " << command << std::endl);
+ res = cmSystemTools::RunSingleCommand(
+ command, &output, &output, &retVal, this->BinaryDir.c_str(),
+ this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
+
+ // did something critical fail in ctest
+ if (!res || cmakeFailed || retVal & cmCTest::BUILD_ERRORS) {
+ this->RestoreBackupDirectories();
+ if (cmakeFailed) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unable to run cmake:" << std::endl
+ << cmakeFailedOuput << std::endl);
+ return 10;
+ }
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unable to run ctest:" << std::endl
+ << "command: " << command << std::endl
+ << "output: " << output << std::endl);
+ if (!res) {
+ return 11;
+ }
+ return retVal * 100;
+ }
+ }
+
+ // if all was successful, delete the backup dirs to free up disk space
+ if (this->Backup) {
+ cmSystemTools::RemoveADirectory(this->BackupSourceDir);
+ cmSystemTools::RemoveADirectory(this->BackupBinaryDir);
+ }
+
+ return 0;
+}
+
+bool cmCTestScriptHandler::WriteInitialCache(const std::string& directory,
+ const std::string& text)
+{
+ std::string cacheFile = cmStrCat(directory, "/CMakeCache.txt");
+ cmGeneratedFileStream fout(cacheFile);
+ if (!fout) {
+ return false;
+ }
+
+ fout.write(text.data(), text.size());
+
+ // Make sure the operating system has finished writing the file
+ // before closing it. This will ensure the file is finished before
+ // the check below.
+ fout.flush();
+ fout.close();
+ return true;
+}
+
+void cmCTestScriptHandler::RestoreBackupDirectories()
+{
+ // if we backed up the dirs and the build failed, then restore
+ // the backed up dirs
+ if (this->Backup) {
+ // if for some reason those directories exist then first delete them
+ if (cmSystemTools::FileExists(this->SourceDir)) {
+ cmSystemTools::RemoveADirectory(this->SourceDir);
+ }
+ if (cmSystemTools::FileExists(this->BinaryDir)) {
+ cmSystemTools::RemoveADirectory(this->BinaryDir);
+ }
+ // rename the src and binary directories
+ rename(this->BackupSourceDir.c_str(), this->SourceDir.c_str());
+ rename(this->BackupBinaryDir.c_str(), this->BinaryDir.c_str());
+ }
+}
+
+bool cmCTestScriptHandler::RunScript(cmCTest* ctest, cmMakefile* mf,
+ const std::string& sname, bool InProcess,
+ int* returnValue)
+{
+ auto sh = cm::make_unique<cmCTestScriptHandler>();
+ sh->SetCTestInstance(ctest);
+ sh->ParentMakefile = mf;
+ sh->AddConfigurationScript(sname, InProcess);
+ int res = sh->ProcessHandler();
+ if (returnValue) {
+ *returnValue = res;
+ }
+ return true;
+}
+
+bool cmCTestScriptHandler::EmptyBinaryDirectory(const std::string& sname)
+{
+ // try to avoid deleting root
+ if (sname.size() < 2) {
+ return false;
+ }
+
+ // consider non existing target directory a success
+ if (!cmSystemTools::FileExists(sname)) {
+ return true;
+ }
+
+ // try to avoid deleting directories that we shouldn't
+ std::string check = cmStrCat(sname, "/CMakeCache.txt");
+
+ if (!cmSystemTools::FileExists(check)) {
+ return false;
+ }
+
+ for (int i = 0; i < 5; ++i) {
+ if (TryToRemoveBinaryDirectoryOnce(sname)) {
+ return true;
+ }
+ cmSystemTools::Delay(100);
+ }
+
+ return false;
+}
+
+bool cmCTestScriptHandler::TryToRemoveBinaryDirectoryOnce(
+ const std::string& directoryPath)
+{
+ cmsys::Directory directory;
+ directory.Load(directoryPath);
+
+ for (unsigned long i = 0; i < directory.GetNumberOfFiles(); ++i) {
+ std::string path = directory.GetFile(i);
+
+ if (path == "." || path == ".." || path == "CMakeCache.txt") {
+ continue;
+ }
+
+ std::string fullPath = cmStrCat(directoryPath, "/", path);
+
+ bool isDirectory = cmSystemTools::FileIsDirectory(fullPath) &&
+ !cmSystemTools::FileIsSymlink(fullPath);
+
+ if (isDirectory) {
+ if (!cmSystemTools::RemoveADirectory(fullPath)) {
+ return false;
+ }
+ } else {
+ if (!cmSystemTools::RemoveFile(fullPath)) {
+ return false;
+ }
+ }
+ }
+
+ return cmSystemTools::RemoveADirectory(directoryPath);
+}
+
+cmDuration cmCTestScriptHandler::GetRemainingTimeAllowed()
+{
+ if (!this->Makefile) {
+ return cmCTest::MaxDuration();
+ }
+
+ cmProp timelimitS = this->Makefile->GetDefinition("CTEST_TIME_LIMIT");
+
+ if (!timelimitS) {
+ return cmCTest::MaxDuration();
+ }
+
+ auto timelimit = cmDuration(atof(timelimitS->c_str()));
+
+ auto duration = std::chrono::duration_cast<cmDuration>(
+ std::chrono::steady_clock::now() - this->ScriptStartTime);
+ return (timelimit - duration);
+}
+
+void cmCTestScriptHandler::SetRunCurrentScript(bool value)
+{
+ this->ShouldRunCurrentScript = value;
+}
diff --git a/Source/CTest/cmCTestScriptHandler.h b/Source/CTest/cmCTestScriptHandler.h
new file mode 100644
index 0000000..b7764b2
--- /dev/null
+++ b/Source/CTest/cmCTestScriptHandler.h
@@ -0,0 +1,179 @@
+/* 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 <chrono>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "cmCTestGenericHandler.h"
+#include "cmDuration.h"
+
+class cmCTest;
+class cmCTestCommand;
+class cmGlobalGenerator;
+class cmMakefile;
+class cmake;
+
+/** \class cmCTestScriptHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ * CTest script is controlled using several variables that script has to
+ * specify and some optional ones. Required ones are:
+ * CTEST_SOURCE_DIRECTORY - Source directory of the project
+ * CTEST_BINARY_DIRECTORY - Binary directory of the project
+ * CTEST_COMMAND - Testing commands
+ *
+ * Optional variables are:
+ * CTEST_BACKUP_AND_RESTORE
+ * CTEST_CMAKE_COMMAND
+ * CTEST_CMAKE_OUTPUT_FILE_NAME
+ * CTEST_CONTINUOUS_DURATION
+ * CTEST_CONTINUOUS_MINIMUM_INTERVAL
+ * CTEST_CVS_CHECKOUT
+ * CTEST_CVS_COMMAND
+ * CTEST_UPDATE_COMMAND
+ * CTEST_DASHBOARD_ROOT
+ * CTEST_ENVIRONMENT
+ * CTEST_INITIAL_CACHE
+ * CTEST_START_WITH_EMPTY_BINARY_DIRECTORY
+ * CTEST_START_WITH_EMPTY_BINARY_DIRECTORY_ONCE
+ *
+ * In addition the following variables can be used. The number can be 1-10.
+ * CTEST_EXTRA_UPDATES_1
+ * CTEST_EXTRA_UPDATES_2
+ * ...
+ * CTEST_EXTRA_UPDATES_10
+ *
+ * CTest script can use the following arguments CTest provides:
+ * CTEST_SCRIPT_ARG
+ * CTEST_SCRIPT_DIRECTORY
+ * CTEST_SCRIPT_NAME
+ *
+ */
+class cmCTestScriptHandler : public cmCTestGenericHandler
+{
+public:
+ using Superclass = cmCTestGenericHandler;
+
+ /**
+ * Add a script to run, and if is should run in the current process
+ */
+ void AddConfigurationScript(const std::string&, bool pscope);
+
+ /**
+ * Run a dashboard using a specified confiuration script
+ */
+ int ProcessHandler() override;
+
+ /*
+ * Run a script
+ */
+ static bool RunScript(cmCTest* ctest, cmMakefile* mf,
+ const std::string& script, bool InProcess,
+ int* returnValue);
+ int RunCurrentScript();
+
+ /*
+ * Empty Binary Directory
+ */
+ static bool EmptyBinaryDirectory(const std::string& dir);
+
+ /*
+ * Write an initial CMakeCache.txt from the given contents.
+ */
+ static bool WriteInitialCache(const std::string& directory,
+ const std::string& text);
+
+ /*
+ * Some elapsed time handling functions
+ */
+ static void SleepInSeconds(unsigned int secondsToWait);
+ void UpdateElapsedTime();
+
+ /**
+ * Return the time remaianing that the script is allowed to run in
+ * seconds if the user has set the variable CTEST_TIME_LIMIT. If that has
+ * not been set it returns a very large value.
+ */
+ cmDuration GetRemainingTimeAllowed();
+
+ cmCTestScriptHandler();
+ cmCTestScriptHandler(const cmCTestScriptHandler&) = delete;
+ const cmCTestScriptHandler& operator=(const cmCTestScriptHandler&) = delete;
+ ~cmCTestScriptHandler() override;
+
+ void Initialize() override;
+
+ void CreateCMake();
+ cmake* GetCMake() { return this->CMake.get(); }
+
+ void SetRunCurrentScript(bool value);
+
+private:
+ // reads in a script
+ int ReadInScript(const std::string& total_script_arg);
+ int ExecuteScript(const std::string& total_script_arg);
+
+ // extract vars from the script to set ivars
+ int ExtractVariables();
+
+ // perform a CVS checkout of the source dir
+ int CheckOutSourceDir();
+
+ // perform any extra cvs updates that were requested
+ int PerformExtraUpdates();
+
+ // backup and restore dirs
+ int BackupDirectories();
+ void RestoreBackupDirectories();
+
+ int RunConfigurationScript(const std::string& script, bool pscope);
+ int RunConfigurationDashboard();
+
+ // Add ctest command
+ void AddCTestCommand(std::string const& name,
+ std::unique_ptr<cmCTestCommand> command);
+
+ // Try to remove the binary directory once
+ static bool TryToRemoveBinaryDirectoryOnce(const std::string& directoryPath);
+
+ std::vector<std::string> ConfigurationScripts;
+ std::vector<bool> ScriptProcessScope;
+
+ bool ShouldRunCurrentScript;
+
+ bool Backup = false;
+ bool EmptyBinDir = false;
+ bool EmptyBinDirOnce = false;
+
+ std::string SourceDir;
+ std::string BinaryDir;
+ std::string BackupSourceDir;
+ std::string BackupBinaryDir;
+ std::string CTestRoot;
+ std::string CVSCheckOut;
+ std::string CTestCmd;
+ std::string UpdateCmd;
+ std::string CTestEnv;
+ std::string InitialCache;
+ std::string CMakeCmd;
+ std::string CMOutFile;
+ std::vector<std::string> ExtraUpdates;
+
+ // the *60 is because the settings are in minutes but GetTime is seconds
+ double MinimumInterval = 30 * 60;
+ double ContinuousDuration = -1;
+
+ // what time in seconds did this script start running
+ std::chrono::steady_clock::time_point ScriptStartTime =
+ std::chrono::steady_clock::time_point();
+
+ std::unique_ptr<cmMakefile> Makefile;
+ cmMakefile* ParentMakefile = nullptr;
+ std::unique_ptr<cmGlobalGenerator> GlobalGenerator;
+ std::unique_ptr<cmake> CMake;
+};
diff --git a/Source/CTest/cmCTestSleepCommand.cxx b/Source/CTest/cmCTestSleepCommand.cxx
new file mode 100644
index 0000000..623d3b6
--- /dev/null
+++ b/Source/CTest/cmCTestSleepCommand.cxx
@@ -0,0 +1,43 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestSleepCommand.h"
+
+#include <cstdlib>
+
+#include "cmCTestScriptHandler.h"
+
+class cmExecutionStatus;
+
+bool cmCTestSleepCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& /*unused*/)
+{
+ if (args.empty()) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // sleep for specified seconds
+ unsigned int time1 = atoi(args[0].c_str());
+ if (args.size() == 1) {
+ cmCTestScriptHandler::SleepInSeconds(time1);
+ // update the elapsed time since it could have slept for a while
+ this->CTestScriptHandler->UpdateElapsedTime();
+ return true;
+ }
+
+ // sleep up to a duration
+ if (args.size() == 3) {
+ unsigned int duration = atoi(args[1].c_str());
+ unsigned int time2 = atoi(args[2].c_str());
+ if (time1 + duration > time2) {
+ duration = (time1 + duration - time2);
+ cmCTestScriptHandler::SleepInSeconds(duration);
+ // update the elapsed time since it could have slept for a while
+ this->CTestScriptHandler->UpdateElapsedTime();
+ }
+ return true;
+ }
+
+ this->SetError("called with incorrect number of arguments");
+ return false;
+}
diff --git a/Source/CTest/cmCTestSleepCommand.h b/Source/CTest/cmCTestSleepCommand.h
new file mode 100644
index 0000000..9425576
--- /dev/null
+++ b/Source/CTest/cmCTestSleepCommand.h
@@ -0,0 +1,46 @@
+/* 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 <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmCTestCommand.h"
+#include "cmCommand.h"
+
+class cmExecutionStatus;
+
+/** \class cmCTestSleep
+ * \brief Run a ctest script
+ *
+ * cmLibrarysCommand defines a list of executable (i.e., test)
+ * programs to create.
+ */
+class cmCTestSleepCommand : public cmCTestCommand
+{
+public:
+ cmCTestSleepCommand() {}
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ auto ni = cm::make_unique<cmCTestSleepCommand>();
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return std::unique_ptr<cmCommand>(std::move(ni));
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) override;
+};
diff --git a/Source/CTest/cmCTestStartCommand.cxx b/Source/CTest/cmCTestStartCommand.cxx
new file mode 100644
index 0000000..53e1b2f
--- /dev/null
+++ b/Source/CTest/cmCTestStartCommand.cxx
@@ -0,0 +1,180 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestStartCommand.h"
+
+#include <cstddef>
+#include <sstream>
+
+#include "cmCTest.h"
+#include "cmCTestVC.h"
+#include "cmGeneratedFileStream.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmSystemTools.h"
+
+class cmExecutionStatus;
+
+cmCTestStartCommand::cmCTestStartCommand()
+{
+ this->CreateNewTag = true;
+ this->Quiet = false;
+}
+
+bool cmCTestStartCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& /*unused*/)
+{
+ if (args.empty()) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ size_t cnt = 0;
+ const char* smodel = nullptr;
+ const std::string* src_dir = nullptr;
+ const std::string* bld_dir = nullptr;
+
+ while (cnt < args.size()) {
+ if (args[cnt] == "GROUP" || args[cnt] == "TRACK") {
+ cnt++;
+ if (cnt >= args.size() || args[cnt] == "APPEND" ||
+ args[cnt] == "QUIET") {
+ std::ostringstream e;
+ e << args[cnt - 1] << " argument missing group name";
+ this->SetError(e.str());
+ return false;
+ }
+ this->CTest->SetSpecificGroup(args[cnt].c_str());
+ cnt++;
+ } else if (args[cnt] == "APPEND") {
+ cnt++;
+ this->CreateNewTag = false;
+ } else if (args[cnt] == "QUIET") {
+ cnt++;
+ this->Quiet = true;
+ } else if (!smodel) {
+ smodel = args[cnt].c_str();
+ cnt++;
+ } else if (!src_dir) {
+ src_dir = &args[cnt];
+ cnt++;
+ } else if (!bld_dir) {
+ bld_dir = &args[cnt];
+ cnt++;
+ } else {
+ this->SetError("Too many arguments");
+ return false;
+ }
+ }
+
+ if (!src_dir) {
+ src_dir = this->Makefile->GetDefinition("CTEST_SOURCE_DIRECTORY");
+ }
+ if (!bld_dir) {
+ bld_dir = this->Makefile->GetDefinition("CTEST_BINARY_DIRECTORY");
+ }
+ if (!src_dir) {
+ this->SetError("source directory not specified. Specify source directory "
+ "as an argument or set CTEST_SOURCE_DIRECTORY");
+ return false;
+ }
+ if (!bld_dir) {
+ this->SetError("binary directory not specified. Specify binary directory "
+ "as an argument or set CTEST_BINARY_DIRECTORY");
+ return false;
+ }
+ if (!smodel && this->CreateNewTag) {
+ this->SetError("no test model specified and APPEND not specified. Specify "
+ "either a test model or the APPEND argument");
+ return false;
+ }
+
+ cmSystemTools::AddKeepPath(*src_dir);
+ cmSystemTools::AddKeepPath(*bld_dir);
+
+ this->CTest->EmptyCTestConfiguration();
+
+ std::string sourceDir = cmSystemTools::CollapseFullPath(*src_dir);
+ std::string binaryDir = cmSystemTools::CollapseFullPath(*bld_dir);
+ this->CTest->SetCTestConfiguration("SourceDirectory", sourceDir,
+ this->Quiet);
+ this->CTest->SetCTestConfiguration("BuildDirectory", binaryDir, this->Quiet);
+
+ if (smodel) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "Run dashboard with model "
+ << smodel << std::endl
+ << " Source directory: " << *src_dir << std::endl
+ << " Build directory: " << *bld_dir << std::endl,
+ this->Quiet);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "Run dashboard with "
+ "to-be-determined model"
+ << std::endl
+ << " Source directory: " << *src_dir << std::endl
+ << " Build directory: " << *bld_dir << std::endl,
+ this->Quiet);
+ }
+ const char* group = this->CTest->GetSpecificGroup();
+ if (group) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Group: " << group << std::endl, this->Quiet);
+ }
+
+ // Log startup actions.
+ std::string startLogFile = binaryDir + "/Testing/Temporary/LastStart.log";
+ cmGeneratedFileStream ofs(startLogFile);
+ if (!ofs) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create log file: LastStart.log" << std::endl);
+ return false;
+ }
+
+ // Make sure the source directory exists.
+ if (!this->InitialCheckout(ofs, sourceDir)) {
+ return false;
+ }
+ if (!cmSystemTools::FileIsDirectory(sourceDir)) {
+ std::ostringstream e;
+ e << "given source path\n"
+ << " " << sourceDir << "\n"
+ << "which is not an existing directory. "
+ << "Set CTEST_CHECKOUT_COMMAND to a command line to create it.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ this->CTest->SetRunCurrentScript(false);
+ this->CTest->SetSuppressUpdatingCTestConfiguration(true);
+ int model;
+ if (smodel) {
+ model = cmCTest::GetTestModelFromString(smodel);
+ } else {
+ model = cmCTest::UNKNOWN;
+ }
+ this->CTest->SetTestModel(model);
+ this->CTest->SetProduceXML(true);
+
+ return this->CTest->InitializeFromCommand(this);
+}
+
+bool cmCTestStartCommand::InitialCheckout(std::ostream& ofs,
+ std::string const& sourceDir)
+{
+ // Use the user-provided command to create the source tree.
+ cmProp initialCheckoutCommand =
+ this->Makefile->GetDefinition("CTEST_CHECKOUT_COMMAND");
+ if (!initialCheckoutCommand) {
+ initialCheckoutCommand =
+ this->Makefile->GetDefinition("CTEST_CVS_CHECKOUT");
+ }
+ if (initialCheckoutCommand) {
+ // Use a generic VC object to run and log the command.
+ cmCTestVC vc(this->CTest, ofs);
+ vc.SetSourceDirectory(sourceDir);
+ if (!vc.InitialCheckout(*initialCheckoutCommand)) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/Source/CTest/cmCTestStartCommand.h b/Source/CTest/cmCTestStartCommand.h
new file mode 100644
index 0000000..b3d06a7
--- /dev/null
+++ b/Source/CTest/cmCTestStartCommand.h
@@ -0,0 +1,63 @@
+/* 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 <iosfwd>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmCTestCommand.h"
+#include "cmCommand.h"
+
+class cmExecutionStatus;
+
+/** \class cmCTestStart
+ * \brief Run a ctest script
+ *
+ * cmCTestStartCommand defineds the command to start the nightly testing.
+ */
+class cmCTestStartCommand : public cmCTestCommand
+{
+public:
+ cmCTestStartCommand();
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ auto ni = cm::make_unique<cmCTestStartCommand>();
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ ni->CreateNewTag = this->CreateNewTag;
+ ni->Quiet = this->Quiet;
+ return std::unique_ptr<cmCommand>(std::move(ni));
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) override;
+
+ /**
+ * Will this invocation of ctest_start create a new TAG file?
+ */
+ bool ShouldCreateNewTag() { return this->CreateNewTag; }
+
+ /**
+ * Should this invocation of ctest_start output non-error messages?
+ */
+ bool ShouldBeQuiet() { return this->Quiet; }
+
+private:
+ bool InitialCheckout(std::ostream& ofs, std::string const& sourceDir);
+ bool CreateNewTag;
+ bool Quiet;
+};
diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx
new file mode 100644
index 0000000..bdba0e5
--- /dev/null
+++ b/Source/CTest/cmCTestSubmitCommand.cxx
@@ -0,0 +1,201 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestSubmitCommand.h"
+
+#include <set>
+#include <sstream>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/vector>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmCTest.h"
+#include "cmCTestSubmitHandler.h"
+#include "cmCommand.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+class cmExecutionStatus;
+
+/**
+ * This is a virtual constructor for the command.
+ */
+std::unique_ptr<cmCommand> cmCTestSubmitCommand::Clone()
+{
+ auto ni = cm::make_unique<cmCTestSubmitCommand>();
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return std::unique_ptr<cmCommand>(std::move(ni));
+}
+
+cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
+{
+ const std::string* submitURL = !this->SubmitURL.empty()
+ ? &this->SubmitURL
+ : this->Makefile->GetDefinition("CTEST_SUBMIT_URL");
+
+ if (submitURL) {
+ this->CTest->SetCTestConfiguration("SubmitURL", *submitURL, this->Quiet);
+ } else {
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "DropMethod", "CTEST_DROP_METHOD", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "DropSiteUser", "CTEST_DROP_SITE_USER", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "DropSitePassword", "CTEST_DROP_SITE_PASSWORD",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "DropSite", "CTEST_DROP_SITE", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "DropLocation", "CTEST_DROP_LOCATION", this->Quiet);
+ }
+
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "CurlOptions", "CTEST_CURL_OPTIONS", this->Quiet);
+
+ cmProp notesFilesVariable =
+ this->Makefile->GetDefinition("CTEST_NOTES_FILES");
+ if (notesFilesVariable) {
+ std::vector<std::string> notesFiles = cmExpandedList(*notesFilesVariable);
+ this->CTest->GenerateNotesFile(notesFiles);
+ }
+
+ cmProp extraFilesVariable =
+ this->Makefile->GetDefinition("CTEST_EXTRA_SUBMIT_FILES");
+ if (extraFilesVariable) {
+ std::vector<std::string> extraFiles = cmExpandedList(*extraFilesVariable);
+ if (!this->CTest->SubmitExtraFiles(extraFiles)) {
+ this->SetError("problem submitting extra files.");
+ return nullptr;
+ }
+ }
+
+ cmCTestSubmitHandler* handler = this->CTest->GetSubmitHandler();
+ handler->Initialize();
+
+ // If no FILES or PARTS given, *all* PARTS are submitted by default.
+ //
+ // If FILES are given, but not PARTS, only the FILES are submitted
+ // and *no* PARTS are submitted.
+ // (This is why we select the empty "noParts" set in the
+ // FilesMentioned block below...)
+ //
+ // If PARTS are given, only the selected PARTS are submitted.
+ //
+ // If both PARTS and FILES are given, only the selected PARTS *and*
+ // all the given FILES are submitted.
+
+ // If given explicit FILES to submit, pass them to the handler.
+ //
+ if (this->FilesMentioned) {
+ // Intentionally select *no* PARTS. (Pass an empty set.) If PARTS
+ // were also explicitly mentioned, they will be selected below...
+ // But FILES with no PARTS mentioned should just submit the FILES
+ // without any of the default parts.
+ //
+ handler->SelectParts(std::set<cmCTest::Part>());
+ handler->SelectFiles(
+ std::set<std::string>(this->Files.begin(), this->Files.end()));
+ }
+
+ // If a PARTS option was given, select only the named parts for submission.
+ //
+ if (this->PartsMentioned) {
+ auto parts =
+ cmMakeRange(this->Parts).transform([this](std::string const& arg) {
+ return this->CTest->GetPartFromName(arg);
+ });
+ handler->SelectParts(std::set<cmCTest::Part>(parts.begin(), parts.end()));
+ }
+
+ // Pass along any HTTPHEADER to the handler if this option was given.
+ if (!this->HttpHeaders.empty()) {
+ handler->SetHttpHeaders(this->HttpHeaders);
+ }
+
+ handler->SetOption("RetryDelay", this->RetryDelay.c_str());
+ handler->SetOption("RetryCount", this->RetryCount.c_str());
+ handler->SetOption("InternalTest", this->InternalTest ? "ON" : "OFF");
+
+ handler->SetQuiet(this->Quiet);
+
+ if (this->CDashUpload) {
+ handler->SetOption("CDashUploadFile", this->CDashUploadFile.c_str());
+ handler->SetOption("CDashUploadType", this->CDashUploadType.c_str());
+ }
+ return handler;
+}
+
+bool cmCTestSubmitCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ this->CDashUpload = !args.empty() && args[0] == "CDASH_UPLOAD";
+
+ bool ret = this->cmCTestHandlerCommand::InitialPass(args, status);
+
+ if (!this->BuildID.empty()) {
+ this->Makefile->AddDefinition(this->BuildID, this->CTest->GetBuildID());
+ }
+
+ return ret;
+}
+
+void cmCTestSubmitCommand::BindArguments()
+{
+ if (this->CDashUpload) {
+ // Arguments specific to the CDASH_UPLOAD signature.
+ this->Bind("CDASH_UPLOAD", this->CDashUploadFile);
+ this->Bind("CDASH_UPLOAD_TYPE", this->CDashUploadType);
+ } else {
+ // Arguments that cannot be used with CDASH_UPLOAD.
+ this->Bind("PARTS"_s, this->Parts);
+ this->Bind("FILES"_s, this->Files);
+ }
+ // Arguments used by both modes.
+ this->Bind("BUILD_ID"_s, this->BuildID);
+ this->Bind("HTTPHEADER"_s, this->HttpHeaders);
+ this->Bind("RETRY_COUNT"_s, this->RetryCount);
+ this->Bind("RETRY_DELAY"_s, this->RetryDelay);
+ this->Bind("SUBMIT_URL"_s, this->SubmitURL);
+ this->Bind("INTERNAL_TEST_CHECKSUM", this->InternalTest);
+
+ // Look for other arguments.
+ this->cmCTestHandlerCommand::BindArguments();
+}
+
+void cmCTestSubmitCommand::CheckArguments(
+ std::vector<std::string> const& keywords)
+{
+ this->PartsMentioned =
+ !this->Parts.empty() || cm::contains(keywords, "PARTS");
+ this->FilesMentioned =
+ !this->Files.empty() || cm::contains(keywords, "FILES");
+
+ cm::erase_if(this->Parts, [this](std::string const& arg) -> bool {
+ cmCTest::Part p = this->CTest->GetPartFromName(arg);
+ if (p == cmCTest::PartCount) {
+ std::ostringstream e;
+ e << "Part name \"" << arg << "\" is invalid.";
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return true;
+ }
+ return false;
+ });
+
+ cm::erase_if(this->Files, [this](std::string const& arg) -> bool {
+ if (!cmSystemTools::FileExists(arg)) {
+ std::ostringstream e;
+ e << "File \"" << arg << "\" does not exist. Cannot submit "
+ << "a non-existent file.";
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return true;
+ }
+ return false;
+ });
+}
diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h
new file mode 100644
index 0000000..c5d11df
--- /dev/null
+++ b/Source/CTest/cmCTestSubmitCommand.h
@@ -0,0 +1,56 @@
+/* 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 <memory>
+#include <string>
+#include <vector>
+
+#include "cmCTestHandlerCommand.h"
+
+class cmCommand;
+class cmCTestGenericHandler;
+class cmExecutionStatus;
+
+/** \class cmCTestSubmit
+ * \brief Run a ctest script
+ *
+ * cmCTestSubmitCommand defineds the command to submit the test results for
+ * the project.
+ */
+class cmCTestSubmitCommand : public cmCTestHandlerCommand
+{
+public:
+ std::unique_ptr<cmCommand> Clone() override;
+
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) override;
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const override { return "ctest_submit"; }
+
+protected:
+ void BindArguments() override;
+ void CheckArguments(std::vector<std::string> const& keywords) override;
+ cmCTestGenericHandler* InitializeHandler() override;
+
+ bool CDashUpload = false;
+ bool FilesMentioned = false;
+ bool InternalTest = false;
+ bool PartsMentioned = false;
+
+ std::string BuildID;
+ std::string CDashUploadFile;
+ std::string CDashUploadType;
+ std::string RetryCount;
+ std::string RetryDelay;
+ std::string SubmitURL;
+
+ std::vector<std::string> Files;
+ std::vector<std::string> HttpHeaders;
+ std::vector<std::string> Parts;
+};
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
new file mode 100644
index 0000000..5b54573
--- /dev/null
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -0,0 +1,906 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestSubmitHandler.h"
+
+#include <chrono>
+#include <cstdio>
+#include <cstdlib>
+#include <sstream>
+
+#include <cmext/algorithm>
+
+#include <cm3p/curl/curl.h>
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+
+#include "cmAlgorithms.h"
+#include "cmCTest.h"
+#include "cmCTestCurl.h"
+#include "cmCTestScriptHandler.h"
+#include "cmCryptoHash.h"
+#include "cmCurl.h"
+#include "cmDuration.h"
+#include "cmGeneratedFileStream.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include "cmake.h"
+
+#define SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT 120
+
+using cmCTestSubmitHandlerVectorOfChar = std::vector<char>;
+
+class cmCTestSubmitHandler::ResponseParser : public cmXMLParser
+{
+public:
+ enum StatusType
+ {
+ STATUS_OK,
+ STATUS_WARNING,
+ STATUS_ERROR
+ };
+
+ StatusType Status = STATUS_OK;
+ std::string Filename;
+ std::string MD5;
+ std::string Message;
+ std::string BuildID;
+
+private:
+ std::vector<char> CurrentValue;
+
+ std::string GetCurrentValue()
+ {
+ std::string val;
+ if (!this->CurrentValue.empty()) {
+ val.assign(&this->CurrentValue[0], this->CurrentValue.size());
+ }
+ return val;
+ }
+
+ void StartElement(const std::string& /*name*/,
+ const char** /*atts*/) override
+ {
+ this->CurrentValue.clear();
+ }
+
+ void CharacterDataHandler(const char* data, int length) override
+ {
+ cm::append(this->CurrentValue, data, data + length);
+ }
+
+ void EndElement(const std::string& name) override
+ {
+ if (name == "status") {
+ std::string status = cmSystemTools::UpperCase(this->GetCurrentValue());
+ if (status == "OK" || status == "SUCCESS") {
+ this->Status = STATUS_OK;
+ } else if (status == "WARNING") {
+ this->Status = STATUS_WARNING;
+ } else {
+ this->Status = STATUS_ERROR;
+ }
+ } else if (name == "filename") {
+ this->Filename = this->GetCurrentValue();
+ } else if (name == "md5") {
+ this->MD5 = this->GetCurrentValue();
+ } else if (name == "message") {
+ this->Message = this->GetCurrentValue();
+ } else if (name == "buildId") {
+ this->BuildID = this->GetCurrentValue();
+ }
+ }
+};
+
+static size_t cmCTestSubmitHandlerWriteMemoryCallback(void* ptr, size_t size,
+ size_t nmemb, void* data)
+{
+ int realsize = static_cast<int>(size * nmemb);
+ const char* chPtr = static_cast<char*>(ptr);
+ cm::append(*static_cast<cmCTestSubmitHandlerVectorOfChar*>(data), chPtr,
+ chPtr + realsize);
+ return realsize;
+}
+
+static size_t cmCTestSubmitHandlerCurlDebugCallback(CURL* /*unused*/,
+ curl_infotype /*unused*/,
+ char* chPtr, size_t size,
+ void* data)
+{
+ cm::append(*static_cast<cmCTestSubmitHandlerVectorOfChar*>(data), chPtr,
+ chPtr + size);
+ return 0;
+}
+
+cmCTestSubmitHandler::cmCTestSubmitHandler()
+{
+ this->Initialize();
+}
+
+void cmCTestSubmitHandler::Initialize()
+{
+ // We submit all available parts by default.
+ for (cmCTest::Part p = cmCTest::PartStart; p != cmCTest::PartCount;
+ p = cmCTest::Part(p + 1)) {
+ this->SubmitPart[p] = true;
+ }
+ this->HasWarnings = false;
+ this->HasErrors = false;
+ this->Superclass::Initialize();
+ this->HTTPProxy.clear();
+ this->HTTPProxyType = 0;
+ this->HTTPProxyAuth.clear();
+ this->LogFile = nullptr;
+ this->Files.clear();
+}
+
+bool cmCTestSubmitHandler::SubmitUsingHTTP(
+ const std::string& localprefix, const std::vector<std::string>& files,
+ const std::string& remoteprefix, const std::string& url)
+{
+ CURL* curl;
+ CURLcode res;
+ FILE* ftpfile;
+ char error_buffer[1024];
+ // Set Content-Type to satisfy fussy modsecurity rules.
+ struct curl_slist* headers =
+ ::curl_slist_append(nullptr, "Content-Type: text/xml");
+
+ // Add any additional headers that the user specified.
+ for (std::string const& h : this->HttpHeaders) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ " Add HTTP Header: \"" << h << "\"" << std::endl,
+ this->Quiet);
+ headers = ::curl_slist_append(headers, h.c_str());
+ }
+
+ /* In windows, this will init the winsock stuff */
+ ::curl_global_init(CURL_GLOBAL_ALL);
+ std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions"));
+ std::vector<std::string> args = cmExpandedList(curlopt);
+ bool verifyPeerOff = false;
+ bool verifyHostOff = false;
+ for (std::string const& arg : args) {
+ if (arg == "CURLOPT_SSL_VERIFYPEER_OFF") {
+ verifyPeerOff = true;
+ }
+ if (arg == "CURLOPT_SSL_VERIFYHOST_OFF") {
+ verifyHostOff = true;
+ }
+ }
+ for (std::string const& file : files) {
+ /* get a curl handle */
+ curl = curl_easy_init();
+ if (curl) {
+ cmCurlSetCAInfo(curl);
+ if (verifyPeerOff) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Set CURLOPT_SSL_VERIFYPEER to off\n",
+ this->Quiet);
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
+ }
+ if (verifyHostOff) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Set CURLOPT_SSL_VERIFYHOST to off\n",
+ this->Quiet);
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
+ }
+
+ // Using proxy
+ if (this->HTTPProxyType > 0) {
+ curl_easy_setopt(curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
+ switch (this->HTTPProxyType) {
+ case 2:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
+ break;
+ case 3:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
+ break;
+ default:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ if (!this->HTTPProxyAuth.empty()) {
+ curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
+ this->HTTPProxyAuth.c_str());
+ }
+ }
+ }
+ if (this->CTest->ShouldUseHTTP10()) {
+ curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ }
+ // enable HTTP ERROR parsing
+ curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
+ /* enable uploading */
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
+
+ // if there is little to no activity for too long stop submitting
+ ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
+ ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME,
+ SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
+
+ /* HTTP PUT please */
+ ::curl_easy_setopt(curl, CURLOPT_PUT, 1);
+ ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+
+ ::curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+
+ std::string local_file = file;
+ bool initialize_cdash_buildid = false;
+ if (!cmSystemTools::FileExists(local_file)) {
+ local_file = cmStrCat(localprefix, "/", file);
+ // If this file exists within the local Testing directory we assume
+ // that it will be associated with the current build in CDash.
+ initialize_cdash_buildid = true;
+ }
+ std::string remote_file =
+ remoteprefix + cmSystemTools::GetFilenameName(file);
+
+ *this->LogFile << "\tUpload file: " << local_file << " to "
+ << remote_file << std::endl;
+
+ std::string ofile = cmSystemTools::EncodeURL(remote_file);
+ std::string upload_as =
+ cmStrCat(url, ((url.find('?') == std::string::npos) ? '?' : '&'),
+ "FileName=", ofile);
+
+ if (initialize_cdash_buildid) {
+ // Provide extra arguments to CDash so that it can initialize and
+ // return a buildid.
+ cmCTestCurl ctest_curl(this->CTest);
+ upload_as += "&build=";
+ upload_as +=
+ ctest_curl.Escape(this->CTest->GetCTestConfiguration("BuildName"));
+ upload_as += "&site=";
+ upload_as +=
+ ctest_curl.Escape(this->CTest->GetCTestConfiguration("Site"));
+ upload_as += "&stamp=";
+ upload_as += ctest_curl.Escape(this->CTest->GetCurrentTag());
+ upload_as += "-";
+ upload_as += ctest_curl.Escape(this->CTest->GetTestModelString());
+ cmCTestScriptHandler* ch = this->CTest->GetScriptHandler();
+ cmake* cm = ch->GetCMake();
+ if (cm) {
+ cmProp subproject = cm->GetState()->GetGlobalProperty("SubProject");
+ if (subproject) {
+ upload_as += "&subproject=";
+ upload_as += ctest_curl.Escape(*subproject);
+ }
+ }
+ }
+
+ // Generate Done.xml right before it is submitted.
+ // The reason for this is two-fold:
+ // 1) It must be generated after some other part has been submitted
+ // so we have a buildId to refer to in its contents.
+ // 2) By generating Done.xml here its timestamp will be as late as
+ // possible. This gives us a more accurate record of how long the
+ // entire build took to complete.
+ if (file == "Done.xml") {
+ this->CTest->GenerateDoneFile();
+ }
+
+ upload_as += "&MD5=";
+
+ if (cmIsOn(this->GetOption("InternalTest"))) {
+ upload_as += "bad_md5sum";
+ } else {
+ upload_as +=
+ cmSystemTools::ComputeFileHash(local_file, cmCryptoHash::AlgoMD5);
+ }
+
+ if (!cmSystemTools::FileExists(local_file)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Cannot find file: " << local_file << std::endl);
+ ::curl_easy_cleanup(curl);
+ ::curl_slist_free_all(headers);
+ ::curl_global_cleanup();
+ return false;
+ }
+ unsigned long filelen = cmSystemTools::FileLength(local_file);
+
+ ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Upload file: " << local_file << " to "
+ << upload_as << " Size: "
+ << filelen << std::endl,
+ this->Quiet);
+
+ // specify target
+ ::curl_easy_setopt(curl, CURLOPT_URL, upload_as.c_str());
+
+ // CURLAUTH_BASIC is default, and here we allow additional methods,
+ // including more secure ones
+ ::curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
+
+ // now specify which file to upload
+ ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
+
+ // and give the size of the upload (optional)
+ ::curl_easy_setopt(curl, CURLOPT_INFILESIZE, static_cast<long>(filelen));
+
+ // and give curl the buffer for errors
+ ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
+
+ // specify handler for output
+ ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
+ cmCTestSubmitHandlerWriteMemoryCallback);
+ ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
+ cmCTestSubmitHandlerCurlDebugCallback);
+
+ /* we pass our 'chunk' struct to the callback function */
+ cmCTestSubmitHandlerVectorOfChar chunk;
+ cmCTestSubmitHandlerVectorOfChar chunkDebug;
+ ::curl_easy_setopt(curl, CURLOPT_FILE, &chunk);
+ ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &chunkDebug);
+
+ // Now run off and do what you've been told!
+ res = ::curl_easy_perform(curl);
+
+ if (!chunk.empty()) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "CURL output: ["
+ << cmCTestLogWrite(chunk.data(), chunk.size())
+ << "]" << std::endl,
+ this->Quiet);
+ this->ParseResponse(chunk);
+ }
+ if (!chunkDebug.empty()) {
+ cmCTestOptionalLog(
+ this->CTest, DEBUG,
+ "CURL debug output: ["
+ << cmCTestLogWrite(chunkDebug.data(), chunkDebug.size()) << "]"
+ << std::endl,
+ this->Quiet);
+ }
+
+ // If curl failed for any reason, or checksum fails, wait and retry
+ //
+ if (res != CURLE_OK || this->HasErrors) {
+ std::string retryDelay = this->GetOption("RetryDelay") == nullptr
+ ? ""
+ : this->GetOption("RetryDelay");
+ std::string retryCount = this->GetOption("RetryCount") == nullptr
+ ? ""
+ : this->GetOption("RetryCount");
+
+ auto delay = cmDuration(
+ retryDelay.empty()
+ ? atoi(this->CTest->GetCTestConfiguration("CTestSubmitRetryDelay")
+ .c_str())
+ : atoi(retryDelay.c_str()));
+ int count = retryCount.empty()
+ ? atoi(this->CTest->GetCTestConfiguration("CTestSubmitRetryCount")
+ .c_str())
+ : atoi(retryCount.c_str());
+
+ for (int i = 0; i < count; i++) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Submit failed, waiting " << delay.count()
+ << " seconds...\n",
+ this->Quiet);
+
+ auto stop = std::chrono::steady_clock::now() + delay;
+ while (std::chrono::steady_clock::now() < stop) {
+ cmSystemTools::Delay(100);
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Retry submission: Attempt "
+ << (i + 1) << " of " << count << std::endl,
+ this->Quiet);
+
+ ::fclose(ftpfile);
+ ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
+ ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
+
+ chunk.clear();
+ chunkDebug.clear();
+ this->HasErrors = false;
+
+ res = ::curl_easy_perform(curl);
+
+ if (!chunk.empty()) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "CURL output: ["
+ << cmCTestLogWrite(chunk.data(), chunk.size())
+ << "]" << std::endl,
+ this->Quiet);
+ this->ParseResponse(chunk);
+ }
+
+ if (res == CURLE_OK && !this->HasErrors) {
+ break;
+ }
+ }
+ }
+
+ fclose(ftpfile);
+ if (res) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Error when uploading file: " << local_file
+ << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Error message was: " << error_buffer << std::endl);
+ *this->LogFile << " Error when uploading file: " << local_file
+ << std::endl
+ << " Error message was: " << error_buffer
+ << std::endl;
+ // avoid deref of begin for zero size array
+ if (!chunk.empty()) {
+ *this->LogFile << " Curl output was: "
+ << cmCTestLogWrite(chunk.data(), chunk.size())
+ << std::endl;
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "CURL output: ["
+ << cmCTestLogWrite(chunk.data(), chunk.size()) << "]"
+ << std::endl);
+ }
+ ::curl_easy_cleanup(curl);
+ ::curl_slist_free_all(headers);
+ ::curl_global_cleanup();
+ return false;
+ }
+ // always cleanup
+ ::curl_easy_cleanup(curl);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Uploaded: " + local_file << std::endl,
+ this->Quiet);
+ }
+ }
+ ::curl_slist_free_all(headers);
+ ::curl_global_cleanup();
+ return true;
+}
+
+void cmCTestSubmitHandler::ParseResponse(
+ cmCTestSubmitHandlerVectorOfChar chunk)
+{
+ std::string output;
+ output.append(chunk.begin(), chunk.end());
+
+ if (output.find("<cdash") != std::string::npos) {
+ ResponseParser parser;
+ parser.Parse(output.c_str());
+
+ if (parser.Status != ResponseParser::STATUS_OK) {
+ this->HasErrors = true;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Submission failed: " << parser.Message << std::endl);
+ return;
+ }
+ this->CTest->SetBuildID(parser.BuildID);
+ }
+ output = cmSystemTools::UpperCase(output);
+ if (output.find("WARNING") != std::string::npos) {
+ this->HasWarnings = true;
+ }
+ if (output.find("ERROR") != std::string::npos) {
+ this->HasErrors = true;
+ }
+
+ if (this->HasWarnings || this->HasErrors) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Server Response:\n"
+ << cmCTestLogWrite(chunk.data(), chunk.size()) << "\n");
+ }
+}
+
+int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file,
+ std::string const& typeString)
+{
+ if (file.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Upload file not specified\n");
+ return -1;
+ }
+ if (!cmSystemTools::FileExists(file)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Upload file not found: '" << file << "'\n");
+ return -1;
+ }
+ cmCTestCurl curl(this->CTest);
+ curl.SetQuiet(this->Quiet);
+ std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions"));
+ std::vector<std::string> args = cmExpandedList(curlopt);
+ curl.SetCurlOptions(args);
+ curl.SetTimeOutSeconds(SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
+ curl.SetHttpHeaders(this->HttpHeaders);
+ std::string url = this->CTest->GetSubmitURL();
+ if (!cmHasLiteralPrefix(url, "http://") &&
+ !cmHasLiteralPrefix(url, "https://")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Only http and https are supported for CDASH_UPLOAD\n");
+ return -1;
+ }
+
+ std::string fields;
+ std::string::size_type pos = url.find('?');
+ if (pos != std::string::npos) {
+ fields = url.substr(pos + 1);
+ url.erase(pos);
+ }
+ bool internalTest = cmIsOn(this->GetOption("InternalTest"));
+
+ // Get RETRY_COUNT and RETRY_DELAY values if they were set.
+ std::string retryDelayString = this->GetOption("RetryDelay") == nullptr
+ ? ""
+ : this->GetOption("RetryDelay");
+ std::string retryCountString = this->GetOption("RetryCount") == nullptr
+ ? ""
+ : this->GetOption("RetryCount");
+ auto retryDelay = std::chrono::seconds(0);
+ if (!retryDelayString.empty()) {
+ unsigned long retryDelayValue = 0;
+ if (!cmStrToULong(retryDelayString, &retryDelayValue)) {
+ cmCTestLog(this->CTest, WARNING,
+ "Invalid value for 'RETRY_DELAY' : " << retryDelayString
+ << std::endl);
+ } else {
+ retryDelay = std::chrono::seconds(retryDelayValue);
+ }
+ }
+ unsigned long retryCount = 0;
+ if (!retryCountString.empty()) {
+ if (!cmStrToULong(retryCountString, &retryCount)) {
+ cmCTestLog(this->CTest, WARNING,
+ "Invalid value for 'RETRY_DELAY' : " << retryCountString
+ << std::endl);
+ }
+ }
+
+ std::string md5sum =
+ cmSystemTools::ComputeFileHash(file, cmCryptoHash::AlgoMD5);
+ // 1. request the buildid and check to see if the file
+ // has already been uploaded
+ // TODO I added support for subproject. You would need to add
+ // a "&subproject=subprojectname" to the first POST.
+ cmCTestScriptHandler* ch = this->CTest->GetScriptHandler();
+ cmake* cm = ch->GetCMake();
+ cmProp subproject = cm->GetState()->GetGlobalProperty("SubProject");
+ // TODO: Encode values for a URL instead of trusting caller.
+ std::ostringstream str;
+ if (subproject) {
+ str << "subproject=" << curl.Escape(*subproject) << "&";
+ }
+ auto timeNow =
+ std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+ str << "stamp=" << curl.Escape(this->CTest->GetCurrentTag()) << "-"
+ << curl.Escape(this->CTest->GetTestModelString()) << "&"
+ << "model=" << curl.Escape(this->CTest->GetTestModelString()) << "&"
+ << "build="
+ << curl.Escape(this->CTest->GetCTestConfiguration("BuildName")) << "&"
+ << "site=" << curl.Escape(this->CTest->GetCTestConfiguration("Site"))
+ << "&"
+ << "group=" << curl.Escape(this->CTest->GetTestModelString())
+ << "&"
+ // For now, we send both "track" and "group" to CDash in case we're
+ // submitting to an older instance that still expects the prior
+ // terminology.
+ << "track=" << curl.Escape(this->CTest->GetTestModelString()) << "&"
+ << "starttime=" << timeNow << "&"
+ << "endtime=" << timeNow << "&"
+ << "datafilesmd5[0]=" << md5sum << "&"
+ << "type=" << curl.Escape(typeString);
+ if (!fields.empty()) {
+ fields += '&';
+ }
+ fields += str.str();
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "fields: " << fields << "\nurl:" << url
+ << "\nfile: " << file << "\n",
+ this->Quiet);
+ std::string response;
+
+ bool requestSucceeded = curl.HttpRequest(url, fields, response);
+ if (!internalTest && !requestSucceeded) {
+ // If request failed, wait and retry.
+ for (unsigned long i = 0; i < retryCount; i++) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Request failed, waiting " << retryDelay.count()
+ << " seconds...\n",
+ this->Quiet);
+
+ auto stop = std::chrono::steady_clock::now() + retryDelay;
+ while (std::chrono::steady_clock::now() < stop) {
+ cmSystemTools::Delay(100);
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Retry request: Attempt "
+ << (i + 1) << " of " << retryCount << std::endl,
+ this->Quiet);
+
+ requestSucceeded = curl.HttpRequest(url, fields, response);
+ if (requestSucceeded) {
+ break;
+ }
+ }
+ }
+ if (!internalTest && !requestSucceeded) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error in HttpRequest\n"
+ << response);
+ return -1;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Request upload response: [" << response << "]\n",
+ this->Quiet);
+ Json::Value json;
+ Json::Reader reader;
+ if (!internalTest && !reader.parse(response, json)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "error parsing json string ["
+ << response << "]\n"
+ << reader.getFormattedErrorMessages() << "\n");
+ return -1;
+ }
+ if (!internalTest && json["status"].asInt() != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Bad status returned from CDash: " << json["status"].asInt());
+ return -1;
+ }
+ if (!internalTest) {
+ if (json["datafilesmd5"].isArray()) {
+ int datares = json["datafilesmd5"][0].asInt();
+ if (datares == 1) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "File already exists on CDash, skip upload "
+ << file << "\n",
+ this->Quiet);
+ return 0;
+ }
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "bad datafilesmd5 value in response " << response << "\n");
+ return -1;
+ }
+ }
+
+ std::string upload_as = cmSystemTools::GetFilenameName(file);
+ std::ostringstream fstr;
+ fstr << "type=" << curl.Escape(typeString) << "&"
+ << "md5=" << md5sum << "&"
+ << "filename=" << curl.Escape(upload_as) << "&"
+ << "buildid=" << json["buildid"].asString();
+
+ bool uploadSucceeded = false;
+ if (!internalTest) {
+ uploadSucceeded = curl.UploadFile(file, url, fstr.str(), response);
+ }
+
+ if (!uploadSucceeded) {
+ // If upload failed, wait and retry.
+ for (unsigned long i = 0; i < retryCount; i++) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Upload failed, waiting " << retryDelay.count()
+ << " seconds...\n",
+ this->Quiet);
+
+ auto stop = std::chrono::steady_clock::now() + retryDelay;
+ while (std::chrono::steady_clock::now() < stop) {
+ cmSystemTools::Delay(100);
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Retry upload: Attempt "
+ << (i + 1) << " of " << retryCount << std::endl,
+ this->Quiet);
+
+ if (!internalTest) {
+ uploadSucceeded = curl.UploadFile(file, url, fstr.str(), response);
+ }
+ if (uploadSucceeded) {
+ break;
+ }
+ }
+ }
+
+ if (!uploadSucceeded) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "error uploading to CDash. " << file << " " << url << " "
+ << fstr.str());
+ return -1;
+ }
+ if (!reader.parse(response, json)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "error parsing json string ["
+ << response << "]\n"
+ << reader.getFormattedErrorMessages() << "\n");
+ return -1;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Upload file response: [" << response << "]\n",
+ this->Quiet);
+ return 0;
+}
+
+int cmCTestSubmitHandler::ProcessHandler()
+{
+ const char* cdashUploadFile = this->GetOption("CDashUploadFile");
+ const char* cdashUploadType = this->GetOption("CDashUploadType");
+ if (cdashUploadFile && cdashUploadType) {
+ return this->HandleCDashUploadFile(cdashUploadFile, cdashUploadType);
+ }
+
+ const std::string& buildDirectory =
+ this->CTest->GetCTestConfiguration("BuildDirectory");
+ if (buildDirectory.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find BuildDirectory key in the DartConfiguration.tcl"
+ << std::endl);
+ return -1;
+ }
+
+ if (getenv("HTTP_PROXY")) {
+ this->HTTPProxyType = 1;
+ this->HTTPProxy = getenv("HTTP_PROXY");
+ if (getenv("HTTP_PROXY_PORT")) {
+ this->HTTPProxy += ":";
+ this->HTTPProxy += getenv("HTTP_PROXY_PORT");
+ }
+ if (getenv("HTTP_PROXY_TYPE")) {
+ std::string type = getenv("HTTP_PROXY_TYPE");
+ // HTTP/SOCKS4/SOCKS5
+ if (type == "HTTP") {
+ this->HTTPProxyType = 1;
+ } else if (type == "SOCKS4") {
+ this->HTTPProxyType = 2;
+ } else if (type == "SOCKS5") {
+ this->HTTPProxyType = 3;
+ }
+ }
+ if (getenv("HTTP_PROXY_USER")) {
+ this->HTTPProxyAuth = getenv("HTTP_PROXY_USER");
+ }
+ if (getenv("HTTP_PROXY_PASSWD")) {
+ this->HTTPProxyAuth += ":";
+ this->HTTPProxyAuth += getenv("HTTP_PROXY_PASSWD");
+ }
+ }
+
+ if (!this->HTTPProxy.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Use HTTP Proxy: " << this->HTTPProxy << std::endl,
+ this->Quiet);
+ }
+ cmGeneratedFileStream ofs;
+ this->StartLogFile("Submit", ofs);
+
+ std::vector<std::string> files;
+ std::string prefix = this->GetSubmitResultsPrefix();
+
+ if (!this->Files.empty()) {
+ // Submit the explicitly selected files:
+ cm::append(files, this->Files);
+ }
+
+ // Add to the list of files to submit from any selected, existing parts:
+ //
+
+ // TODO:
+ // Check if test is enabled
+
+ this->CTest->AddIfExists(cmCTest::PartUpdate, "Update.xml");
+ this->CTest->AddIfExists(cmCTest::PartConfigure, "Configure.xml");
+ this->CTest->AddIfExists(cmCTest::PartBuild, "Build.xml");
+ this->CTest->AddIfExists(cmCTest::PartTest, "Test.xml");
+ if (this->CTest->AddIfExists(cmCTest::PartCoverage, "Coverage.xml")) {
+ std::vector<std::string> gfiles;
+ std::string gpath =
+ buildDirectory + "/Testing/" + this->CTest->GetCurrentTag();
+ std::string::size_type glen = gpath.size() + 1;
+ gpath = gpath + "/CoverageLog*";
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Globbing for: " << gpath << std::endl, this->Quiet);
+ if (cmSystemTools::SimpleGlob(gpath, gfiles, 1)) {
+ for (std::string& gfile : gfiles) {
+ gfile = gfile.substr(glen);
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Glob file: " << gfile << std::endl, this->Quiet);
+ this->CTest->AddSubmitFile(cmCTest::PartCoverage, gfile);
+ }
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Problem globbing" << std::endl);
+ }
+ }
+ this->CTest->AddIfExists(cmCTest::PartMemCheck, "DynamicAnalysis.xml");
+ this->CTest->AddIfExists(cmCTest::PartMemCheck, "Purify.xml");
+ this->CTest->AddIfExists(cmCTest::PartNotes, "Notes.xml");
+ this->CTest->AddIfExists(cmCTest::PartUpload, "Upload.xml");
+
+ // Query parts for files to submit.
+ for (cmCTest::Part p = cmCTest::PartStart; p != cmCTest::PartCount;
+ p = cmCTest::Part(p + 1)) {
+ // Skip parts we are not submitting.
+ if (!this->SubmitPart[p]) {
+ continue;
+ }
+
+ // Submit files from this part.
+ cm::append(files, this->CTest->GetSubmitFiles(p));
+ }
+
+ // Make sure files are unique, but preserve order.
+ {
+ // This endPos intermediate is needed to work around non-conformant C++11
+ // standard libraries that have erase(iterator,iterator) instead of
+ // erase(const_iterator,const_iterator).
+ size_t endPos = cmRemoveDuplicates(files) - files.cbegin();
+ files.erase(files.begin() + endPos, files.end());
+ }
+
+ // Submit Done.xml last
+ if (this->SubmitPart[cmCTest::PartDone]) {
+ files.emplace_back("Done.xml");
+ }
+
+ if (ofs) {
+ ofs << "Upload files:" << std::endl;
+ int cnt = 0;
+ for (std::string const& file : files) {
+ ofs << cnt << "\t" << file << std::endl;
+ cnt++;
+ }
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "Submit files\n",
+ this->Quiet);
+ const char* specificGroup = this->CTest->GetSpecificGroup();
+ if (specificGroup) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Send to group: " << specificGroup << std::endl,
+ this->Quiet);
+ }
+ this->SetLogFile(&ofs);
+
+ std::string url = this->CTest->GetSubmitURL();
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " SubmitURL: " << url << '\n', this->Quiet);
+ if (!this->SubmitUsingHTTP(buildDirectory + "/Testing/" +
+ this->CTest->GetCurrentTag(),
+ files, prefix, url)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Problems when submitting via HTTP\n");
+ ofs << " Problems when submitting via HTTP\n";
+ return -1;
+ }
+ if (this->HasErrors) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Errors occurred during submission.\n");
+ ofs << " Errors occurred during submission.\n";
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Submission successful"
+ << (this->HasWarnings ? ", with warnings." : "")
+ << std::endl,
+ this->Quiet);
+ ofs << " Submission successful"
+ << (this->HasWarnings ? ", with warnings." : "") << std::endl;
+ }
+
+ return 0;
+}
+
+std::string cmCTestSubmitHandler::GetSubmitResultsPrefix()
+{
+ std::string buildname =
+ cmCTest::SafeBuildIdField(this->CTest->GetCTestConfiguration("BuildName"));
+ std::string name = this->CTest->GetCTestConfiguration("Site") + "___" +
+ buildname + "___" + this->CTest->GetCurrentTag() + "-" +
+ this->CTest->GetTestModelString() + "___XML___";
+ return name;
+}
+
+void cmCTestSubmitHandler::SelectParts(std::set<cmCTest::Part> const& parts)
+{
+ // Check whether each part is selected.
+ for (cmCTest::Part p = cmCTest::PartStart; p != cmCTest::PartCount;
+ p = cmCTest::Part(p + 1)) {
+ this->SubmitPart[p] =
+ (std::set<cmCTest::Part>::const_iterator(parts.find(p)) != parts.end());
+ }
+}
+
+void cmCTestSubmitHandler::SelectFiles(std::set<std::string> const& files)
+{
+ this->Files.insert(files.begin(), files.end());
+}
diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h
new file mode 100644
index 0000000..809c615
--- /dev/null
+++ b/Source/CTest/cmCTestSubmitHandler.h
@@ -0,0 +1,78 @@
+/* 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 <iosfwd>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmCTest.h"
+#include "cmCTestGenericHandler.h"
+
+/** \class cmCTestSubmitHandler
+ * \brief Helper class for CTest
+ *
+ * Submit testing results
+ *
+ */
+class cmCTestSubmitHandler : public cmCTestGenericHandler
+{
+public:
+ using Superclass = cmCTestGenericHandler;
+
+ cmCTestSubmitHandler();
+ ~cmCTestSubmitHandler() override { this->LogFile = nullptr; }
+
+ /*
+ * The main entry point for this class
+ */
+ int ProcessHandler() override;
+
+ void Initialize() override;
+
+ /** Specify a set of parts (by name) to submit. */
+ void SelectParts(std::set<cmCTest::Part> const& parts);
+
+ /** Specify a set of files to submit. */
+ void SelectFiles(std::set<std::string> const& files);
+
+ // handle the cdash file upload protocol
+ int HandleCDashUploadFile(std::string const& file, std::string const& type);
+
+ void SetHttpHeaders(std::vector<std::string> const& v)
+ {
+ this->HttpHeaders = v;
+ }
+
+private:
+ void SetLogFile(std::ostream* ost) { this->LogFile = ost; }
+
+ /**
+ * Submit file using various ways
+ */
+ bool SubmitUsingHTTP(const std::string& localprefix,
+ const std::vector<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url);
+
+ using cmCTestSubmitHandlerVectorOfChar = std::vector<char>;
+
+ void ParseResponse(cmCTestSubmitHandlerVectorOfChar chunk);
+
+ std::string GetSubmitResultsPrefix();
+
+ class ResponseParser;
+
+ std::string HTTPProxy;
+ int HTTPProxyType;
+ std::string HTTPProxyAuth;
+ std::ostream* LogFile;
+ bool SubmitPart[cmCTest::PartCount];
+ bool HasWarnings;
+ bool HasErrors;
+ std::set<std::string> Files;
+ std::vector<std::string> HttpHeaders;
+};
diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx
new file mode 100644
index 0000000..886c263
--- /dev/null
+++ b/Source/CTest/cmCTestTestCommand.cxx
@@ -0,0 +1,152 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestTestCommand.h"
+
+#include <chrono>
+#include <cstdlib>
+#include <sstream>
+
+#include <cmext/string_view>
+
+#include "cmCTest.h"
+#include "cmCTestGenericHandler.h"
+#include "cmCTestTestHandler.h"
+#include "cmDuration.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStringAlgorithms.h"
+
+void cmCTestTestCommand::BindArguments()
+{
+ this->cmCTestHandlerCommand::BindArguments();
+ this->Bind("START"_s, this->Start);
+ this->Bind("END"_s, this->End);
+ this->Bind("STRIDE"_s, this->Stride);
+ this->Bind("EXCLUDE"_s, this->Exclude);
+ this->Bind("INCLUDE"_s, this->Include);
+ this->Bind("EXCLUDE_LABEL"_s, this->ExcludeLabel);
+ this->Bind("INCLUDE_LABEL"_s, this->IncludeLabel);
+ this->Bind("EXCLUDE_FIXTURE"_s, this->ExcludeFixture);
+ this->Bind("EXCLUDE_FIXTURE_SETUP"_s, this->ExcludeFixtureSetup);
+ this->Bind("EXCLUDE_FIXTURE_CLEANUP"_s, this->ExcludeFixtureCleanup);
+ this->Bind("PARALLEL_LEVEL"_s, this->ParallelLevel);
+ this->Bind("REPEAT"_s, this->Repeat);
+ this->Bind("SCHEDULE_RANDOM"_s, this->ScheduleRandom);
+ this->Bind("STOP_TIME"_s, this->StopTime);
+ this->Bind("TEST_LOAD"_s, this->TestLoad);
+ this->Bind("RESOURCE_SPEC_FILE"_s, this->ResourceSpecFile);
+ this->Bind("STOP_ON_FAILURE"_s, this->StopOnFailure);
+}
+
+cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
+{
+ cmProp ctestTimeout = this->Makefile->GetDefinition("CTEST_TEST_TIMEOUT");
+
+ cmDuration timeout;
+ if (ctestTimeout) {
+ timeout = cmDuration(atof(ctestTimeout->c_str()));
+ } else {
+ timeout = this->CTest->GetTimeOut();
+ if (timeout <= cmDuration::zero()) {
+ // By default use timeout of 10 minutes
+ timeout = std::chrono::minutes(10);
+ }
+ }
+ this->CTest->SetTimeOut(timeout);
+
+ cmProp resourceSpecFile =
+ this->Makefile->GetDefinition("CTEST_RESOURCE_SPEC_FILE");
+ if (this->ResourceSpecFile.empty() && resourceSpecFile) {
+ this->ResourceSpecFile = *resourceSpecFile;
+ }
+
+ cmCTestGenericHandler* handler = this->InitializeActualHandler();
+ if (!this->Start.empty() || !this->End.empty() || !this->Stride.empty()) {
+ handler->SetOption(
+ "TestsToRunInformation",
+ cmStrCat(this->Start, ',', this->End, ',', this->Stride).c_str());
+ }
+ if (!this->Exclude.empty()) {
+ handler->SetOption("ExcludeRegularExpression", this->Exclude.c_str());
+ }
+ if (!this->Include.empty()) {
+ handler->SetOption("IncludeRegularExpression", this->Include.c_str());
+ }
+ if (!this->ExcludeLabel.empty()) {
+ handler->AddMultiOption("ExcludeLabelRegularExpression",
+ this->ExcludeLabel);
+ }
+ if (!this->IncludeLabel.empty()) {
+ handler->AddMultiOption("LabelRegularExpression", this->IncludeLabel);
+ }
+ if (!this->ExcludeFixture.empty()) {
+ handler->SetOption("ExcludeFixtureRegularExpression",
+ this->ExcludeFixture.c_str());
+ }
+ if (!this->ExcludeFixtureSetup.empty()) {
+ handler->SetOption("ExcludeFixtureSetupRegularExpression",
+ this->ExcludeFixtureSetup.c_str());
+ }
+ if (!this->ExcludeFixtureCleanup.empty()) {
+ handler->SetOption("ExcludeFixtureCleanupRegularExpression",
+ this->ExcludeFixtureCleanup.c_str());
+ }
+ if (this->StopOnFailure) {
+ handler->SetOption("StopOnFailure", "ON");
+ }
+ if (!this->ParallelLevel.empty()) {
+ handler->SetOption("ParallelLevel", this->ParallelLevel.c_str());
+ }
+ if (!this->Repeat.empty()) {
+ handler->SetOption("Repeat", this->Repeat.c_str());
+ }
+ if (!this->ScheduleRandom.empty()) {
+ handler->SetOption("ScheduleRandom", this->ScheduleRandom.c_str());
+ }
+ if (!this->ResourceSpecFile.empty()) {
+ handler->SetOption("ResourceSpecFile", this->ResourceSpecFile.c_str());
+ }
+ if (!this->StopTime.empty()) {
+ this->CTest->SetStopTime(this->StopTime);
+ }
+
+ // Test load is determined by: TEST_LOAD argument,
+ // or CTEST_TEST_LOAD script variable, or ctest --test-load
+ // command line argument... in that order.
+ unsigned long testLoad;
+ cmProp ctestTestLoad = this->Makefile->GetDefinition("CTEST_TEST_LOAD");
+ if (!this->TestLoad.empty()) {
+ if (!cmStrToULong(this->TestLoad, &testLoad)) {
+ testLoad = 0;
+ cmCTestLog(this->CTest, WARNING,
+ "Invalid value for 'TEST_LOAD' : " << this->TestLoad
+ << std::endl);
+ }
+ } else if (cmNonempty(ctestTestLoad)) {
+ if (!cmStrToULong(*ctestTestLoad, &testLoad)) {
+ testLoad = 0;
+ cmCTestLog(this->CTest, WARNING,
+ "Invalid value for 'CTEST_TEST_LOAD' : " << *ctestTestLoad
+ << std::endl);
+ }
+ } else {
+ testLoad = this->CTest->GetTestLoad();
+ }
+ handler->SetTestLoad(testLoad);
+
+ if (cmProp labelsForSubprojects =
+ this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
+ this->CTest->SetCTestConfiguration("LabelsForSubprojects",
+ *labelsForSubprojects, this->Quiet);
+ }
+
+ handler->SetQuiet(this->Quiet);
+ return handler;
+}
+
+cmCTestGenericHandler* cmCTestTestCommand::InitializeActualHandler()
+{
+ cmCTestTestHandler* handler = this->CTest->GetTestHandler();
+ handler->Initialize();
+ return handler;
+}
diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h
new file mode 100644
index 0000000..624cd91
--- /dev/null
+++ b/Source/CTest/cmCTestTestCommand.h
@@ -0,0 +1,63 @@
+/* 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 <string>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmCTestHandlerCommand.h"
+#include "cmCommand.h"
+
+class cmCTestGenericHandler;
+
+/** \class cmCTestTest
+ * \brief Run a ctest script
+ *
+ * cmCTestTestCommand defineds the command to test the project.
+ */
+class cmCTestTestCommand : public cmCTestHandlerCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ auto ni = cm::make_unique<cmCTestTestCommand>();
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return std::unique_ptr<cmCommand>(std::move(ni));
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const override { return "ctest_test"; }
+
+protected:
+ void BindArguments() override;
+ virtual cmCTestGenericHandler* InitializeActualHandler();
+ cmCTestGenericHandler* InitializeHandler() override;
+
+ std::string Start;
+ std::string End;
+ std::string Stride;
+ std::string Exclude;
+ std::string Include;
+ std::string ExcludeLabel;
+ std::string IncludeLabel;
+ std::string ExcludeFixture;
+ std::string ExcludeFixtureSetup;
+ std::string ExcludeFixtureCleanup;
+ std::string ParallelLevel;
+ std::string Repeat;
+ std::string ScheduleRandom;
+ std::string StopTime;
+ std::string TestLoad;
+ std::string ResourceSpecFile;
+ bool StopOnFailure = false;
+};
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
new file mode 100644
index 0000000..742e78a
--- /dev/null
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -0,0 +1,2459 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestTestHandler.h"
+
+#include <algorithm>
+#include <chrono>
+#include <cmath>
+#include <cstddef> // IWYU pragma: keep
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <functional>
+#include <iomanip>
+#include <iterator>
+#include <set>
+#include <sstream>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmsys/FStream.hxx"
+#include <cmsys/Base64.h>
+#include <cmsys/Directory.hxx>
+#include <cmsys/RegularExpression.hxx>
+
+#include "cm_utf8.h"
+
+#include "cmCTest.h"
+#include "cmCTestMultiProcessHandler.h"
+#include "cmCTestResourceGroupsLexerHelper.h"
+#include "cmDuration.h"
+#include "cmExecutionStatus.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmWorkingDirectory.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+namespace {
+
+class cmCTestCommand
+{
+public:
+ cmCTestCommand(cmCTestTestHandler* testHandler)
+ : TestHandler(testHandler)
+ {
+ }
+
+ virtual ~cmCTestCommand() = default;
+
+ bool operator()(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status)
+ {
+ cmMakefile& mf = status.GetMakefile();
+ std::vector<std::string> expandedArguments;
+ if (!mf.ExpandArguments(args, expandedArguments)) {
+ // There was an error expanding arguments. It was already
+ // reported, so we can skip this command without error.
+ return true;
+ }
+ return this->InitialPass(expandedArguments, status);
+ }
+
+ virtual bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) = 0;
+
+ cmCTestTestHandler* TestHandler;
+};
+
+bool cmCTestSubdirCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ for (std::string const& arg : args) {
+ std::string fname;
+
+ if (cmSystemTools::FileIsFullPath(arg)) {
+ fname = arg;
+ } else {
+ fname = cmStrCat(cwd, '/', arg);
+ }
+
+ if (!cmSystemTools::FileIsDirectory(fname)) {
+ // No subdirectory? So what...
+ continue;
+ }
+ bool readit = false;
+ {
+ cmWorkingDirectory workdir(fname);
+ if (workdir.Failed()) {
+ status.SetError("Failed to change directory to " + fname + " : " +
+ std::strerror(workdir.GetLastResult()));
+ return false;
+ }
+ const char* testFilename;
+ if (cmSystemTools::FileExists("CTestTestfile.cmake")) {
+ // does the CTestTestfile.cmake exist ?
+ testFilename = "CTestTestfile.cmake";
+ } else if (cmSystemTools::FileExists("DartTestfile.txt")) {
+ // does the DartTestfile.txt exist ?
+ testFilename = "DartTestfile.txt";
+ } else {
+ // No CTestTestfile? Who cares...
+ continue;
+ }
+ fname += "/";
+ fname += testFilename;
+ readit = status.GetMakefile().ReadDependentFile(fname);
+ }
+ if (!readit) {
+ status.SetError(cmStrCat("Could not load include file: ", fname));
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmCTestAddSubdirectoryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::string fname =
+ cmStrCat(cmSystemTools::GetCurrentWorkingDirectory(), '/', args[0]);
+
+ if (!cmSystemTools::FileExists(fname)) {
+ // No subdirectory? So what...
+ return true;
+ }
+ bool readit = false;
+ {
+ const char* testFilename;
+ if (cmSystemTools::FileExists("CTestTestfile.cmake")) {
+ // does the CTestTestfile.cmake exist ?
+ testFilename = "CTestTestfile.cmake";
+ } else if (cmSystemTools::FileExists("DartTestfile.txt")) {
+ // does the DartTestfile.txt exist ?
+ testFilename = "DartTestfile.txt";
+ } else {
+ // No CTestTestfile? Who cares...
+ return true;
+ }
+ fname += "/";
+ fname += testFilename;
+ readit = status.GetMakefile().ReadDependentFile(fname);
+ }
+ if (!readit) {
+ status.SetError(cmStrCat("Could not find include file: ", fname));
+ return false;
+ }
+ return true;
+}
+
+class cmCTestAddTestCommand : public cmCTestCommand
+{
+public:
+ using cmCTestCommand::cmCTestCommand;
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& /*args*/,
+ cmExecutionStatus& /*unused*/) override;
+};
+
+bool cmCTestAddTestCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ return this->TestHandler->AddTest(args);
+}
+
+class cmCTestSetTestsPropertiesCommand : public cmCTestCommand
+{
+public:
+ using cmCTestCommand::cmCTestCommand;
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& /*args*/,
+ cmExecutionStatus& /*unused*/) override;
+};
+
+bool cmCTestSetTestsPropertiesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus& /*unused*/)
+{
+ return this->TestHandler->SetTestsProperties(args);
+}
+
+class cmCTestSetDirectoryPropertiesCommand : public cmCTestCommand
+{
+public:
+ using cmCTestCommand::cmCTestCommand;
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& /*unused*/,
+ cmExecutionStatus& /*unused*/) override;
+};
+
+bool cmCTestSetDirectoryPropertiesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ return this->TestHandler->SetDirectoryProperties(args);
+}
+
+// get the next number in a string with numbers separated by ,
+// pos is the start of the search and pos2 is the end of the search
+// pos becomes pos2 after a call to GetNextNumber.
+// -1 is returned at the end of the list.
+inline int GetNextNumber(std::string const& in, int& val,
+ std::string::size_type& pos,
+ std::string::size_type& pos2)
+{
+ pos2 = in.find(',', pos);
+ if (pos2 != std::string::npos) {
+ if (pos2 - pos == 0) {
+ val = -1;
+ } else {
+ val = atoi(in.substr(pos, pos2 - pos).c_str());
+ }
+ pos = pos2 + 1;
+ return 1;
+ }
+ if (in.size() - pos == 0) {
+ val = -1;
+ } else {
+ val = atoi(in.substr(pos, in.size() - pos).c_str());
+ }
+ return 0;
+}
+
+// get the next number in a string with numbers separated by ,
+// pos is the start of the search and pos2 is the end of the search
+// pos becomes pos2 after a call to GetNextNumber.
+// -1 is returned at the end of the list.
+inline int GetNextRealNumber(std::string const& in, double& val,
+ std::string::size_type& pos,
+ std::string::size_type& pos2)
+{
+ pos2 = in.find(',', pos);
+ if (pos2 != std::string::npos) {
+ if (pos2 - pos == 0) {
+ val = -1;
+ } else {
+ val = atof(in.substr(pos, pos2 - pos).c_str());
+ }
+ pos = pos2 + 1;
+ return 1;
+ }
+ if (in.size() - pos == 0) {
+ val = -1;
+ } else {
+ val = atof(in.substr(pos, in.size() - pos).c_str());
+ }
+ return 0;
+}
+
+} // namespace
+
+cmCTestTestHandler::cmCTestTestHandler()
+{
+ this->UseUnion = false;
+
+ this->UseIncludeRegExpFlag = false;
+ this->UseExcludeRegExpFlag = false;
+ this->UseExcludeRegExpFirst = false;
+ this->UseResourceSpec = false;
+
+ this->CustomMaximumPassedTestOutputSize = 1 * 1024;
+ this->CustomMaximumFailedTestOutputSize = 300 * 1024;
+
+ this->MemCheck = false;
+
+ this->LogFile = nullptr;
+
+ // regex to detect <DartMeasurement>...</DartMeasurement>
+ this->DartStuff.compile("(<DartMeasurement.*/DartMeasurement[a-zA-Z]*>)");
+ // regex to detect each individual <DartMeasurement>...</DartMeasurement>
+ this->DartStuff1.compile(
+ "(<DartMeasurement[^<]*</DartMeasurement[a-zA-Z]*>)");
+}
+
+void cmCTestTestHandler::Initialize()
+{
+ this->Superclass::Initialize();
+
+ this->ElapsedTestingTime = cmDuration();
+
+ this->TestResults.clear();
+
+ this->CustomTestsIgnore.clear();
+ this->StartTest.clear();
+ this->EndTest.clear();
+
+ this->CustomPreTest.clear();
+ this->CustomPostTest.clear();
+ this->CustomMaximumPassedTestOutputSize = 1 * 1024;
+ this->CustomMaximumFailedTestOutputSize = 300 * 1024;
+
+ this->TestsToRun.clear();
+
+ this->UseIncludeRegExpFlag = false;
+ this->UseExcludeRegExpFlag = false;
+ this->UseExcludeRegExpFirst = false;
+ this->IncludeLabelRegularExpressions.clear();
+ this->ExcludeLabelRegularExpressions.clear();
+ this->IncludeRegExp.clear();
+ this->ExcludeRegExp.clear();
+ this->ExcludeFixtureRegExp.clear();
+ this->ExcludeFixtureSetupRegExp.clear();
+ this->ExcludeFixtureCleanupRegExp.clear();
+
+ this->TestsToRunString.clear();
+ this->UseUnion = false;
+ this->TestList.clear();
+}
+
+void cmCTestTestHandler::PopulateCustomVectors(cmMakefile* mf)
+{
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_PRE_TEST",
+ this->CustomPreTest);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_POST_TEST",
+ this->CustomPostTest);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_TESTS_IGNORE",
+ this->CustomTestsIgnore);
+ this->CTest->PopulateCustomInteger(
+ mf, "CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE",
+ this->CustomMaximumPassedTestOutputSize);
+ this->CTest->PopulateCustomInteger(
+ mf, "CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE",
+ this->CustomMaximumFailedTestOutputSize);
+}
+
+int cmCTestTestHandler::PreProcessHandler()
+{
+ if (!this->ExecuteCommands(this->CustomPreTest)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem executing pre-test command(s)." << std::endl);
+ return 0;
+ }
+ return 1;
+}
+
+int cmCTestTestHandler::PostProcessHandler()
+{
+ if (!this->ExecuteCommands(this->CustomPostTest)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem executing post-test command(s)." << std::endl);
+ return 0;
+ }
+ return 1;
+}
+
+int cmCTestTestHandler::ProcessHandler()
+{
+ if (!this->ProcessOptions()) {
+ return -1;
+ }
+
+ this->TestResults.clear();
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ (this->MemCheck ? "Memory check" : "Test")
+ << " project "
+ << cmSystemTools::GetCurrentWorkingDirectory()
+ << std::endl,
+ this->Quiet);
+ if (!this->PreProcessHandler()) {
+ return -1;
+ }
+
+ cmGeneratedFileStream mLogFile;
+ this->StartLogFile((this->MemCheck ? "DynamicAnalysis" : "Test"), mLogFile);
+ this->LogFile = &mLogFile;
+
+ std::vector<std::string> passed;
+ std::vector<std::string> failed;
+
+ // start the real time clock
+ auto clock_start = std::chrono::steady_clock::now();
+
+ if (!this->ProcessDirectory(passed, failed)) {
+ return -1;
+ }
+
+ auto clock_finish = std::chrono::steady_clock::now();
+
+ bool noTestsFoundError = false;
+ if (passed.size() + failed.size() == 0) {
+ if (!this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels() &&
+ this->CTest->GetNoTestsMode() != cmCTest::NoTests::Ignore) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "No tests were found!!!" << std::endl);
+ if (this->CTest->GetNoTestsMode() == cmCTest::NoTests::Error) {
+ noTestsFoundError = true;
+ }
+ }
+ } else {
+ if (this->HandlerVerbose && !passed.empty() &&
+ (this->UseIncludeRegExpFlag || this->UseExcludeRegExpFlag)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ std::endl
+ << "The following tests passed:" << std::endl,
+ this->Quiet);
+ for (std::string const& j : passed) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "\t" << j << std::endl, this->Quiet);
+ }
+ }
+
+ SetOfTests resultsSet(this->TestResults.begin(), this->TestResults.end());
+ std::vector<cmCTestTestHandler::cmCTestTestResult> disabledTests;
+
+ for (cmCTestTestResult const& ft : resultsSet) {
+ if (cmHasLiteralPrefix(ft.CompletionStatus, "SKIP_") ||
+ ft.CompletionStatus == "Disabled") {
+ disabledTests.push_back(ft);
+ }
+ }
+
+ cmDuration durationInSecs = clock_finish - clock_start;
+ this->LogTestSummary(passed, failed, durationInSecs);
+
+ this->LogDisabledTests(disabledTests);
+
+ this->LogFailedTests(failed, resultsSet);
+ }
+
+ if (!this->GenerateXML()) {
+ return 1;
+ }
+
+ if (!this->PostProcessHandler()) {
+ this->LogFile = nullptr;
+ return -1;
+ }
+
+ if (!failed.empty()) {
+ this->LogFile = nullptr;
+ return -1;
+ }
+
+ if (noTestsFoundError) {
+ this->LogFile = nullptr;
+ return -1;
+ }
+
+ this->LogFile = nullptr;
+ return 0;
+}
+
+/* Given a multi-option value `parts`, compile those parts into
+ * regular expressions in `expressions`. Skip empty values.
+ * Returns true if there were any expressions.
+ */
+static bool BuildLabelRE(const std::vector<std::string>& parts,
+ std::vector<cmsys::RegularExpression>& expressions)
+{
+ expressions.clear();
+ for (const auto& p : parts) {
+ if (!p.empty()) {
+ expressions.emplace_back(p);
+ }
+ }
+ return !expressions.empty();
+}
+
+bool cmCTestTestHandler::ProcessOptions()
+{
+ // Update internal data structure from generic one
+ this->SetTestsToRunInformation(this->GetOption("TestsToRunInformation"));
+ this->SetUseUnion(cmIsOn(this->GetOption("UseUnion")));
+ if (cmIsOn(this->GetOption("ScheduleRandom"))) {
+ this->CTest->SetScheduleType("Random");
+ }
+ if (const char* repeat = this->GetOption("Repeat")) {
+ cmsys::RegularExpression repeatRegex(
+ "^(UNTIL_FAIL|UNTIL_PASS|AFTER_TIMEOUT):([0-9]+)$");
+ if (repeatRegex.find(repeat)) {
+ std::string const& count = repeatRegex.match(2);
+ unsigned long n = 1;
+ cmStrToULong(count, &n); // regex guarantees success
+ this->RepeatCount = static_cast<int>(n);
+ if (this->RepeatCount > 1) {
+ std::string const& mode = repeatRegex.match(1);
+ if (mode == "UNTIL_FAIL") {
+ this->RepeatMode = cmCTest::Repeat::UntilFail;
+ } else if (mode == "UNTIL_PASS") {
+ this->RepeatMode = cmCTest::Repeat::UntilPass;
+ } else if (mode == "AFTER_TIMEOUT") {
+ this->RepeatMode = cmCTest::Repeat::AfterTimeout;
+ }
+ }
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Repeat option invalid value: " << repeat << std::endl);
+ return false;
+ }
+ }
+ if (this->GetOption("ParallelLevel")) {
+ this->CTest->SetParallelLevel(atoi(this->GetOption("ParallelLevel")));
+ }
+
+ if (this->GetOption("StopOnFailure")) {
+ this->CTest->SetStopOnFailure(true);
+ }
+
+ BuildLabelRE(this->GetMultiOption("LabelRegularExpression"),
+ this->IncludeLabelRegularExpressions);
+ BuildLabelRE(this->GetMultiOption("ExcludeLabelRegularExpression"),
+ this->ExcludeLabelRegularExpressions);
+ const char* val = this->GetOption("IncludeRegularExpression");
+ if (val) {
+ this->UseIncludeRegExp();
+ this->SetIncludeRegExp(val);
+ }
+ val = this->GetOption("ExcludeRegularExpression");
+ if (val) {
+ this->UseExcludeRegExp();
+ this->SetExcludeRegExp(val);
+ }
+ val = this->GetOption("ExcludeFixtureRegularExpression");
+ if (val) {
+ this->ExcludeFixtureRegExp = val;
+ }
+ val = this->GetOption("ExcludeFixtureSetupRegularExpression");
+ if (val) {
+ this->ExcludeFixtureSetupRegExp = val;
+ }
+ val = this->GetOption("ExcludeFixtureCleanupRegularExpression");
+ if (val) {
+ this->ExcludeFixtureCleanupRegExp = val;
+ }
+ val = this->GetOption("ResourceSpecFile");
+ if (val) {
+ this->ResourceSpecFile = val;
+ }
+ this->SetRerunFailed(cmIsOn(this->GetOption("RerunFailed")));
+
+ return true;
+}
+
+void cmCTestTestHandler::LogTestSummary(const std::vector<std::string>& passed,
+ const std::vector<std::string>& failed,
+ const cmDuration& durationInSecs)
+{
+ std::size_t total = passed.size() + failed.size();
+
+ float percent = float(passed.size()) * 100.0f / float(total);
+ if (!failed.empty() && percent > 99) {
+ percent = 99;
+ }
+
+ std::string passColorCode;
+ std::string failedColorCode;
+ if (failed.empty()) {
+ passColorCode = this->CTest->GetColorCode(cmCTest::Color::GREEN);
+ } else {
+ failedColorCode = this->CTest->GetColorCode(cmCTest::Color::RED);
+ }
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ std::endl
+ << passColorCode << std::lround(percent) << "% tests passed"
+ << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR)
+ << ", " << failedColorCode << failed.size() << " tests failed"
+ << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR)
+ << " out of " << total << std::endl);
+ if ((!this->CTest->GetLabelsForSubprojects().empty() &&
+ this->CTest->GetSubprojectSummary())) {
+ this->PrintLabelOrSubprojectSummary(true);
+ }
+ if (this->CTest->GetLabelSummary()) {
+ this->PrintLabelOrSubprojectSummary(false);
+ }
+ char realBuf[1024];
+ sprintf(realBuf, "%6.2f sec", durationInSecs.count());
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "\nTotal Test time (real) = " << realBuf << "\n",
+ this->Quiet);
+}
+
+void cmCTestTestHandler::LogDisabledTests(
+ const std::vector<cmCTestTestResult>& disabledTests)
+{
+ if (!disabledTests.empty()) {
+ cmGeneratedFileStream ofs;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ std::endl
+ << "The following tests did not run:" << std::endl);
+ this->StartLogFile("TestsDisabled", ofs);
+
+ const char* disabled_reason;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ this->CTest->GetColorCode(cmCTest::Color::BLUE));
+ for (cmCTestTestResult const& dt : disabledTests) {
+ ofs << dt.TestCount << ":" << dt.Name << std::endl;
+ if (dt.CompletionStatus == "Disabled") {
+ disabled_reason = "Disabled";
+ } else {
+ disabled_reason = "Skipped";
+ }
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ "\t" << std::setw(3) << dt.TestCount << " - " << dt.Name
+ << " (" << disabled_reason << ")" << std::endl);
+ }
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR));
+ }
+}
+
+void cmCTestTestHandler::LogFailedTests(const std::vector<std::string>& failed,
+ const SetOfTests& resultsSet)
+{
+ if (!failed.empty()) {
+ cmGeneratedFileStream ofs;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ std::endl
+ << "The following tests FAILED:" << std::endl);
+ this->StartLogFile("TestsFailed", ofs);
+
+ for (cmCTestTestResult const& ft : resultsSet) {
+ if (ft.Status != cmCTestTestHandler::COMPLETED &&
+ !cmHasLiteralPrefix(ft.CompletionStatus, "SKIP_") &&
+ ft.CompletionStatus != "Disabled") {
+ ofs << ft.TestCount << ":" << ft.Name << std::endl;
+ auto testColor = cmCTest::Color::RED;
+ if (this->GetTestStatus(ft) == "Not Run") {
+ testColor = cmCTest::Color::YELLOW;
+ }
+ cmCTestLog(
+ this->CTest, HANDLER_OUTPUT,
+ "\t" << this->CTest->GetColorCode(testColor) << std::setw(3)
+ << ft.TestCount << " - " << ft.Name << " ("
+ << this->GetTestStatus(ft) << ")"
+ << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR)
+ << std::endl);
+ }
+ }
+ }
+}
+
+bool cmCTestTestHandler::GenerateXML()
+{
+ if (this->CTest->GetProduceXML()) {
+ cmGeneratedFileStream xmlfile;
+ if (!this->StartResultingXML(
+ (this->MemCheck ? cmCTest::PartMemCheck : cmCTest::PartTest),
+ (this->MemCheck ? "DynamicAnalysis" : "Test"), xmlfile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create "
+ << (this->MemCheck ? "memory check" : "testing")
+ << " XML file" << std::endl);
+ this->LogFile = nullptr;
+ return false;
+ }
+ cmXMLWriter xml(xmlfile);
+ this->GenerateDartOutput(xml);
+ }
+
+ return true;
+}
+
+void cmCTestTestHandler::PrintLabelOrSubprojectSummary(bool doSubProject)
+{
+ // collect subproject labels
+ std::vector<std::string> subprojects =
+ this->CTest->GetLabelsForSubprojects();
+ std::map<std::string, double> labelTimes;
+ std::map<std::string, int> labelCounts;
+ std::set<std::string> labels;
+ std::string::size_type maxlen = 0;
+ // initialize maps
+ for (cmCTestTestProperties& p : this->TestList) {
+ for (std::string const& l : p.Labels) {
+ // first check to see if the current label is a subproject label
+ bool isSubprojectLabel = false;
+ auto subproject = std::find(subprojects.begin(), subprojects.end(), l);
+ if (subproject != subprojects.end()) {
+ isSubprojectLabel = true;
+ }
+ // if we are doing sub projects and this label is one, then use it
+ // if we are not doing sub projects and the label is not one use it
+ if (doSubProject == isSubprojectLabel) {
+ if (l.size() > maxlen) {
+ maxlen = l.size();
+ }
+ labels.insert(l);
+ labelTimes[l] = 0;
+ labelCounts[l] = 0;
+ }
+ }
+ }
+ // fill maps
+ for (cmCTestTestResult& result : this->TestResults) {
+ cmCTestTestProperties& p = *result.Properties;
+ for (std::string const& l : p.Labels) {
+ // only use labels found in labels
+ if (cm::contains(labels, l)) {
+ labelTimes[l] +=
+ result.ExecutionTime.count() * result.Properties->Processors;
+ ++labelCounts[l];
+ }
+ }
+ }
+ // if no labels are found return and print nothing
+ if (labels.empty()) {
+ return;
+ }
+ // now print times
+ if (doSubProject) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "\nSubproject Time Summary:", this->Quiet);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "\nLabel Time Summary:", this->Quiet);
+ }
+ for (std::string const& i : labels) {
+ std::string label = i;
+ label.resize(maxlen + 3, ' ');
+
+ char buf[1024];
+ sprintf(buf, "%6.2f sec*proc", labelTimes[i]);
+
+ std::ostringstream labelCountStr;
+ labelCountStr << "(" << labelCounts[i] << " test";
+ if (labelCounts[i] > 1) {
+ labelCountStr << "s";
+ }
+ labelCountStr << ")";
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "\n"
+ << label << " = " << buf << " "
+ << labelCountStr.str(),
+ this->Quiet);
+ if (this->LogFile) {
+ *this->LogFile << "\n" << i << " = " << buf << "\n";
+ }
+ }
+ if (this->LogFile) {
+ *this->LogFile << "\n";
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "\n", this->Quiet);
+}
+
+/**
+ * Check if the labels (from a test) match all the expressions.
+ *
+ * Each of the RE's must match at least one label
+ * (e.g. all of the REs must match **some** label,
+ * in order for the filter to apply to the test).
+ */
+static bool MatchLabelsAgainstFilterRE(
+ const std::vector<std::string>& labels,
+ const std::vector<cmsys::RegularExpression>& expressions)
+{
+ for (const auto& re : expressions) {
+ // check to see if the label regular expression matches
+ bool found = false; // assume it does not match
+ cmsys::RegularExpressionMatch match;
+ // loop over all labels and look for match
+ for (std::string const& l : labels) {
+ if (re.find(l.c_str(), match)) {
+ found = true;
+ break;
+ }
+ }
+ // if no match was found, exclude the test
+ if (!found) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void cmCTestTestHandler::CheckLabelFilterInclude(cmCTestTestProperties& it)
+{
+ // if not using Labels to filter then return
+ if (this->IncludeLabelRegularExpressions.empty()) {
+ return;
+ }
+ // if there are no labels and we are filtering by labels
+ // then exclude the test as it does not have the label
+ if (it.Labels.empty()) {
+ it.IsInBasedOnREOptions = false;
+ return;
+ }
+ // if no match was found, exclude the test
+ if (!MatchLabelsAgainstFilterRE(it.Labels,
+ this->IncludeLabelRegularExpressions)) {
+ it.IsInBasedOnREOptions = false;
+ }
+}
+
+void cmCTestTestHandler::CheckLabelFilterExclude(cmCTestTestProperties& it)
+{
+ // if not using Labels to filter then return
+ if (this->ExcludeLabelRegularExpressions.empty()) {
+ return;
+ }
+ // if there are no labels and we are excluding by labels
+ // then do nothing as a no label can not be a match
+ if (it.Labels.empty()) {
+ return;
+ }
+ // if match was found, exclude the test
+ if (MatchLabelsAgainstFilterRE(it.Labels,
+ this->ExcludeLabelRegularExpressions)) {
+ it.IsInBasedOnREOptions = false;
+ }
+}
+
+void cmCTestTestHandler::CheckLabelFilter(cmCTestTestProperties& it)
+{
+ this->CheckLabelFilterInclude(it);
+ this->CheckLabelFilterExclude(it);
+}
+
+bool cmCTestTestHandler::ComputeTestList()
+{
+ this->TestList.clear(); // clear list of test
+ if (!this->GetListOfTests()) {
+ return false;
+ }
+
+ if (this->RerunFailed) {
+ this->ComputeTestListForRerunFailed();
+ return true;
+ }
+
+ cmCTestTestHandler::ListOfTests::size_type tmsize = this->TestList.size();
+ // how many tests are in based on RegExp?
+ int inREcnt = 0;
+ for (cmCTestTestProperties& tp : this->TestList) {
+ this->CheckLabelFilter(tp);
+ if (tp.IsInBasedOnREOptions) {
+ inREcnt++;
+ }
+ }
+ // expand the test list based on the union flag
+ if (this->UseUnion) {
+ this->ExpandTestsToRunInformation(static_cast<int>(tmsize));
+ } else {
+ this->ExpandTestsToRunInformation(inREcnt);
+ }
+ // Now create a final list of tests to run
+ int cnt = 0;
+ inREcnt = 0;
+ std::string last_directory;
+ ListOfTests finalList;
+ for (cmCTestTestProperties& tp : this->TestList) {
+ cnt++;
+ if (tp.IsInBasedOnREOptions) {
+ inREcnt++;
+ }
+
+ if (this->UseUnion) {
+ // if it is not in the list and not in the regexp then skip
+ if ((!this->TestsToRun.empty() &&
+ !cm::contains(this->TestsToRun, cnt)) &&
+ !tp.IsInBasedOnREOptions) {
+ continue;
+ }
+ } else {
+ // is this test in the list of tests to run? If not then skip it
+ if ((!this->TestsToRun.empty() &&
+ !cm::contains(this->TestsToRun, inREcnt)) ||
+ !tp.IsInBasedOnREOptions) {
+ continue;
+ }
+ }
+ tp.Index = cnt; // save the index into the test list for this test
+ finalList.push_back(tp);
+ }
+
+ this->UpdateForFixtures(finalList);
+
+ // Save the total number of tests before exclusions
+ this->TotalNumberOfTests = this->TestList.size();
+ // Set the TestList to the final list of all test
+ this->TestList = finalList;
+
+ this->UpdateMaxTestNameWidth();
+ return true;
+}
+
+void cmCTestTestHandler::ComputeTestListForRerunFailed()
+{
+ this->ExpandTestsToRunInformationForRerunFailed();
+
+ ListOfTests finalList;
+ int cnt = 0;
+ for (cmCTestTestProperties& tp : this->TestList) {
+ cnt++;
+
+ // if this test is not in our list of tests to run, then skip it.
+ if (!this->TestsToRun.empty() && !cm::contains(this->TestsToRun, cnt)) {
+ continue;
+ }
+
+ tp.Index = cnt;
+ finalList.push_back(tp);
+ }
+
+ this->UpdateForFixtures(finalList);
+
+ // Save the total number of tests before exclusions
+ this->TotalNumberOfTests = this->TestList.size();
+
+ // Set the TestList to the list of failed tests to rerun
+ this->TestList = finalList;
+
+ this->UpdateMaxTestNameWidth();
+}
+
+void cmCTestTestHandler::UpdateForFixtures(ListOfTests& tests) const
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Updating test list for fixtures" << std::endl,
+ this->Quiet);
+
+ // Prepare regular expression evaluators
+ std::string setupRegExp(this->ExcludeFixtureRegExp);
+ std::string cleanupRegExp(this->ExcludeFixtureRegExp);
+ if (!this->ExcludeFixtureSetupRegExp.empty()) {
+ if (setupRegExp.empty()) {
+ setupRegExp = this->ExcludeFixtureSetupRegExp;
+ } else {
+ setupRegExp.append("(" + setupRegExp + ")|(" +
+ this->ExcludeFixtureSetupRegExp + ")");
+ }
+ }
+ if (!this->ExcludeFixtureCleanupRegExp.empty()) {
+ if (cleanupRegExp.empty()) {
+ cleanupRegExp = this->ExcludeFixtureCleanupRegExp;
+ } else {
+ cleanupRegExp.append("(" + cleanupRegExp + ")|(" +
+ this->ExcludeFixtureCleanupRegExp + ")");
+ }
+ }
+ cmsys::RegularExpression excludeSetupRegex(setupRegExp);
+ cmsys::RegularExpression excludeCleanupRegex(cleanupRegExp);
+
+ // Prepare some maps to help us find setup and cleanup tests for
+ // any given fixture
+ using TestIterator = ListOfTests::const_iterator;
+ using FixtureDependencies = std::multimap<std::string, TestIterator>;
+ using FixtureDepsIterator = FixtureDependencies::const_iterator;
+ FixtureDependencies fixtureSetups;
+ FixtureDependencies fixtureCleanups;
+
+ for (auto it = this->TestList.begin(); it != this->TestList.end(); ++it) {
+ const cmCTestTestProperties& p = *it;
+
+ for (std::string const& deps : p.FixturesSetup) {
+ fixtureSetups.insert(std::make_pair(deps, it));
+ }
+
+ for (std::string const& deps : p.FixturesCleanup) {
+ fixtureCleanups.insert(std::make_pair(deps, it));
+ }
+ }
+
+ // Prepare fast lookup of tests already included in our list of tests
+ std::set<std::string> addedTests;
+ for (cmCTestTestProperties const& p : tests) {
+ addedTests.insert(p.Name);
+ }
+
+ // These are lookups of fixture name to a list of indices into the final
+ // tests array for tests which require that fixture and tests which are
+ // setups for that fixture. They are needed at the end to populate
+ // dependencies of the cleanup tests in our final list of tests.
+ std::map<std::string, std::vector<size_t>> fixtureRequirements;
+ std::map<std::string, std::vector<size_t>> setupFixturesAdded;
+
+ // Use integer index for iteration because we append to
+ // the tests vector as we go
+ size_t fixtureTestsAdded = 0;
+ std::set<std::string> addedFixtures;
+ for (size_t i = 0; i < tests.size(); ++i) {
+ // Skip disabled tests
+ if (tests[i].Disabled) {
+ continue;
+ }
+
+ // There are two things to do for each test:
+ // 1. For every fixture required by this test, record that fixture as
+ // being required and create dependencies on that fixture's setup
+ // tests.
+ // 2. Record all setup tests in the final test list so we can later make
+ // cleanup tests in the test list depend on their associated setup
+ // tests to enforce correct ordering.
+
+ // 1. Handle fixture requirements
+ //
+ // Must copy the set of fixtures required because we may invalidate
+ // the tests array by appending to it
+ std::set<std::string> fixtures = tests[i].FixturesRequired;
+ for (std::string const& requiredFixtureName : fixtures) {
+ if (requiredFixtureName.empty()) {
+ continue;
+ }
+
+ fixtureRequirements[requiredFixtureName].push_back(i);
+
+ // Add dependencies to this test for all of the setup tests
+ // associated with the required fixture. If any of those setup
+ // tests fail, this test should not run. We make the fixture's
+ // cleanup tests depend on this test case later.
+ std::pair<FixtureDepsIterator, FixtureDepsIterator> setupRange =
+ fixtureSetups.equal_range(requiredFixtureName);
+ for (auto sIt = setupRange.first; sIt != setupRange.second; ++sIt) {
+ const std::string& setupTestName = sIt->second->Name;
+ tests[i].RequireSuccessDepends.insert(setupTestName);
+ if (!cm::contains(tests[i].Depends, setupTestName)) {
+ tests[i].Depends.push_back(setupTestName);
+ }
+ }
+
+ // Append any fixture setup/cleanup tests to our test list if they
+ // are not already in it (they could have been in the original
+ // set of tests passed to us at the outset or have already been
+ // added from a previously checked test). A fixture isn't required
+ // to have setup/cleanup tests.
+ if (!addedFixtures.insert(requiredFixtureName).second) {
+ // Already seen this fixture, no need to check it again
+ continue;
+ }
+
+ // Only add setup tests if this fixture has not been excluded
+ if (setupRegExp.empty() ||
+ !excludeSetupRegex.find(requiredFixtureName)) {
+ std::pair<FixtureDepsIterator, FixtureDepsIterator> fixtureRange =
+ fixtureSetups.equal_range(requiredFixtureName);
+ for (auto it = fixtureRange.first; it != fixtureRange.second; ++it) {
+ ListOfTests::const_iterator lotIt = it->second;
+ const cmCTestTestProperties& p = *lotIt;
+
+ if (!addedTests.insert(p.Name).second) {
+ // Already have p in our test list
+ continue;
+ }
+
+ // This is a test not yet in our list, so add it and
+ // update its index to reflect where it was in the original
+ // full list of all tests (needed to track individual tests
+ // across ctest runs for re-run failed, etc.)
+ tests.push_back(p);
+ tests.back().Index =
+ 1 + static_cast<int>(std::distance(this->TestList.begin(), lotIt));
+ ++fixtureTestsAdded;
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Added setup test "
+ << p.Name << " required by fixture "
+ << requiredFixtureName << std::endl,
+ this->Quiet);
+ }
+ }
+
+ // Only add cleanup tests if this fixture has not been excluded
+ if (cleanupRegExp.empty() ||
+ !excludeCleanupRegex.find(requiredFixtureName)) {
+ std::pair<FixtureDepsIterator, FixtureDepsIterator> fixtureRange =
+ fixtureCleanups.equal_range(requiredFixtureName);
+ for (auto it = fixtureRange.first; it != fixtureRange.second; ++it) {
+ ListOfTests::const_iterator lotIt = it->second;
+ const cmCTestTestProperties& p = *lotIt;
+
+ if (!addedTests.insert(p.Name).second) {
+ // Already have p in our test list
+ continue;
+ }
+
+ // This is a test not yet in our list, so add it and
+ // update its index to reflect where it was in the original
+ // full list of all tests (needed to track individual tests
+ // across ctest runs for re-run failed, etc.)
+ tests.push_back(p);
+ tests.back().Index =
+ 1 + static_cast<int>(std::distance(this->TestList.begin(), lotIt));
+ ++fixtureTestsAdded;
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Added cleanup test "
+ << p.Name << " required by fixture "
+ << requiredFixtureName << std::endl,
+ this->Quiet);
+ }
+ }
+ }
+
+ // 2. Record all setup fixtures included in the final list of tests
+ for (std::string const& setupFixtureName : tests[i].FixturesSetup) {
+ if (setupFixtureName.empty()) {
+ continue;
+ }
+
+ setupFixturesAdded[setupFixtureName].push_back(i);
+ }
+ }
+
+ // Now that we have the final list of tests, we can update all cleanup
+ // tests to depend on those tests which require that fixture and on any
+ // setup tests for that fixture. The latter is required to handle the
+ // pathological case where setup and cleanup tests are in the test set
+ // but no other test has that fixture as a requirement.
+ for (cmCTestTestProperties& p : tests) {
+ const std::set<std::string>& cleanups = p.FixturesCleanup;
+ for (std::string const& fixture : cleanups) {
+ // This cleanup test could be part of the original test list that was
+ // passed in. It is then possible that no other test requires the
+ // fIt fixture, so we have to check for this.
+ auto cIt = fixtureRequirements.find(fixture);
+ if (cIt != fixtureRequirements.end()) {
+ const std::vector<size_t>& indices = cIt->second;
+ for (size_t index : indices) {
+ const std::string& reqTestName = tests[index].Name;
+ if (!cm::contains(p.Depends, reqTestName)) {
+ p.Depends.push_back(reqTestName);
+ }
+ }
+ }
+
+ // Ensure fixture cleanup tests always run after their setup tests, even
+ // if no other test cases require the fixture
+ cIt = setupFixturesAdded.find(fixture);
+ if (cIt != setupFixturesAdded.end()) {
+ const std::vector<size_t>& indices = cIt->second;
+ for (size_t index : indices) {
+ const std::string& setupTestName = tests[index].Name;
+ if (!cm::contains(p.Depends, setupTestName)) {
+ p.Depends.push_back(setupTestName);
+ }
+ }
+ }
+ }
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Added " << fixtureTestsAdded
+ << " tests to meet fixture requirements"
+ << std::endl,
+ this->Quiet);
+}
+
+void cmCTestTestHandler::UpdateMaxTestNameWidth()
+{
+ std::string::size_type max = this->CTest->GetMaxTestNameWidth();
+ for (cmCTestTestProperties& p : this->TestList) {
+ if (max < p.Name.size()) {
+ max = p.Name.size();
+ }
+ }
+ if (static_cast<std::string::size_type>(
+ this->CTest->GetMaxTestNameWidth()) != max) {
+ this->CTest->SetMaxTestNameWidth(static_cast<int>(max));
+ }
+}
+
+bool cmCTestTestHandler::GetValue(const char* tag, int& value,
+ std::istream& fin)
+{
+ std::string line;
+ bool ret = true;
+ cmSystemTools::GetLineFromStream(fin, line);
+ if (line == tag) {
+ fin >> value;
+ ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "parse error: missing tag: " << tag << " found [" << line << "]"
+ << std::endl);
+ ret = false;
+ }
+ return ret;
+}
+
+bool cmCTestTestHandler::GetValue(const char* tag, double& value,
+ std::istream& fin)
+{
+ std::string line;
+ cmSystemTools::GetLineFromStream(fin, line);
+ bool ret = true;
+ if (line == tag) {
+ fin >> value;
+ ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "parse error: missing tag: " << tag << " found [" << line << "]"
+ << std::endl);
+ ret = false;
+ }
+ return ret;
+}
+
+bool cmCTestTestHandler::GetValue(const char* tag, bool& value,
+ std::istream& fin)
+{
+ std::string line;
+ cmSystemTools::GetLineFromStream(fin, line);
+ bool ret = true;
+ if (line == tag) {
+#ifdef __HAIKU__
+ int tmp = 0;
+ fin >> tmp;
+ value = false;
+ if (tmp) {
+ value = true;
+ }
+#else
+ fin >> value;
+#endif
+ ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "parse error: missing tag: " << tag << " found [" << line << "]"
+ << std::endl);
+ ret = false;
+ }
+ return ret;
+}
+
+bool cmCTestTestHandler::GetValue(const char* tag, size_t& value,
+ std::istream& fin)
+{
+ std::string line;
+ cmSystemTools::GetLineFromStream(fin, line);
+ bool ret = true;
+ if (line == tag) {
+ fin >> value;
+ ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "parse error: missing tag: " << tag << " found [" << line << "]"
+ << std::endl);
+ ret = false;
+ }
+ return ret;
+}
+
+bool cmCTestTestHandler::GetValue(const char* tag, std::string& value,
+ std::istream& fin)
+{
+ std::string line;
+ cmSystemTools::GetLineFromStream(fin, line);
+ bool ret = true;
+ if (line == tag) {
+ ret = cmSystemTools::GetLineFromStream(fin, value);
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "parse error: missing tag: " << tag << " found [" << line << "]"
+ << std::endl);
+ ret = false;
+ }
+ return ret;
+}
+
+bool cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed,
+ std::vector<std::string>& failed)
+{
+ if (!this->ComputeTestList()) {
+ return false;
+ }
+
+ this->StartTest = this->CTest->CurrentTime();
+ this->StartTestTime = std::chrono::system_clock::now();
+ auto elapsed_time_start = std::chrono::steady_clock::now();
+
+ auto parallel = cm::make_unique<cmCTestMultiProcessHandler>();
+ parallel->SetCTest(this->CTest);
+ parallel->SetParallelLevel(this->CTest->GetParallelLevel());
+ parallel->SetTestHandler(this);
+ if (this->RepeatMode != cmCTest::Repeat::Never) {
+ parallel->SetRepeatMode(this->RepeatMode, this->RepeatCount);
+ } else {
+ parallel->SetRepeatMode(this->CTest->GetRepeatMode(),
+ this->CTest->GetRepeatCount());
+ }
+ parallel->SetQuiet(this->Quiet);
+ if (this->TestLoad > 0) {
+ parallel->SetTestLoad(this->TestLoad);
+ } else {
+ parallel->SetTestLoad(this->CTest->GetTestLoad());
+ }
+ if (!this->ResourceSpecFile.empty()) {
+ this->UseResourceSpec = true;
+ auto result = this->ResourceSpec.ReadFromJSONFile(this->ResourceSpecFile);
+ if (result != cmCTestResourceSpec::ReadFileResult::READ_OK) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Could not read/parse resource spec file "
+ << this->ResourceSpecFile << ": "
+ << cmCTestResourceSpec::ResultToString(result)
+ << std::endl);
+ return false;
+ }
+ parallel->InitResourceAllocator(this->ResourceSpec);
+ }
+
+ *this->LogFile
+ << "Start testing: " << this->CTest->CurrentTime() << std::endl
+ << "----------------------------------------------------------"
+ << std::endl;
+
+ cmCTestMultiProcessHandler::TestMap tests;
+ cmCTestMultiProcessHandler::PropertiesMap properties;
+
+ bool randomSchedule = this->CTest->GetScheduleType() == "Random";
+ if (randomSchedule) {
+ srand(static_cast<unsigned>(time(nullptr)));
+ }
+
+ for (cmCTestTestProperties& p : this->TestList) {
+ cmCTestMultiProcessHandler::TestSet depends;
+
+ if (randomSchedule) {
+ p.Cost = static_cast<float>(rand());
+ }
+
+ if (p.Timeout == cmDuration::zero() &&
+ this->CTest->GetGlobalTimeout() != cmDuration::zero()) {
+ p.Timeout = this->CTest->GetGlobalTimeout();
+ }
+
+ if (!p.Depends.empty()) {
+ for (std::string const& i : p.Depends) {
+ for (cmCTestTestProperties const& it2 : this->TestList) {
+ if (it2.Name == i) {
+ depends.insert(it2.Index);
+ break; // break out of test loop as name can only match 1
+ }
+ }
+ }
+ }
+ tests[p.Index] = depends;
+ properties[p.Index] = &p;
+ }
+ parallel->SetTests(tests, properties);
+ parallel->SetPassFailVectors(&passed, &failed);
+ this->TestResults.clear();
+ parallel->SetTestResults(&this->TestResults);
+ parallel->CheckResourcesAvailable();
+
+ if (this->CTest->ShouldPrintLabels()) {
+ parallel->PrintLabels();
+ } else if (this->CTest->GetShowOnly()) {
+ parallel->PrintTestList();
+ } else {
+ parallel->RunTests();
+ }
+ this->EndTest = this->CTest->CurrentTime();
+ this->EndTestTime = std::chrono::system_clock::now();
+ this->ElapsedTestingTime =
+ std::chrono::steady_clock::now() - elapsed_time_start;
+ *this->LogFile << "End testing: " << this->CTest->CurrentTime() << std::endl;
+
+ return true;
+}
+
+void cmCTestTestHandler::GenerateTestCommand(
+ std::vector<std::string>& /*unused*/, int /*unused*/)
+{
+}
+
+void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml)
+{
+ if (!this->CTest->GetProduceXML()) {
+ return;
+ }
+
+ this->CTest->StartXML(xml, this->AppendXML);
+ this->CTest->GenerateSubprojectsOutput(xml);
+ xml.StartElement("Testing");
+ xml.Element("StartDateTime", this->StartTest);
+ xml.Element("StartTestTime", this->StartTestTime);
+ xml.StartElement("TestList");
+ for (cmCTestTestResult const& result : this->TestResults) {
+ std::string testPath = result.Path + "/" + result.Name;
+ xml.Element("Test", this->CTest->GetShortPathToFile(testPath));
+ }
+ xml.EndElement(); // TestList
+ for (cmCTestTestResult& result : this->TestResults) {
+ this->WriteTestResultHeader(xml, result);
+ xml.StartElement("Results");
+
+ if (result.Status != cmCTestTestHandler::NOT_RUN) {
+ if (result.Status != cmCTestTestHandler::COMPLETED ||
+ result.ReturnValue) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", "Exit Code");
+ xml.Element("Value", this->GetTestStatus(result));
+ xml.EndElement(); // NamedMeasurement
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", "Exit Value");
+ xml.Element("Value", result.ReturnValue);
+ xml.EndElement(); // NamedMeasurement
+ }
+ this->GenerateRegressionImages(xml, result.DartString);
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "numeric/double");
+ xml.Attribute("name", "Execution Time");
+ xml.Element("Value", result.ExecutionTime.count());
+ xml.EndElement(); // NamedMeasurement
+ if (!result.Reason.empty()) {
+ const char* reasonType = "Pass Reason";
+ if (result.Status != cmCTestTestHandler::COMPLETED) {
+ reasonType = "Fail Reason";
+ }
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", reasonType);
+ xml.Element("Value", result.Reason);
+ xml.EndElement(); // NamedMeasurement
+ }
+ }
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "numeric/double");
+ xml.Attribute("name", "Processors");
+ xml.Element("Value", result.Properties->Processors);
+ xml.EndElement(); // NamedMeasurement
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", "Completion Status");
+ xml.Element("Value", result.CompletionStatus);
+ xml.EndElement(); // NamedMeasurement
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", "Command Line");
+ xml.Element("Value", result.FullCommandLine);
+ xml.EndElement(); // NamedMeasurement
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", "Environment");
+ xml.Element("Value", result.Environment);
+ xml.EndElement(); // NamedMeasurement
+ for (auto const& measure : result.Properties->Measurements) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", measure.first);
+ xml.Element("Value", measure.second);
+ xml.EndElement(); // NamedMeasurement
+ }
+ xml.StartElement("Measurement");
+ xml.StartElement("Value");
+ if (result.CompressOutput) {
+ xml.Attribute("encoding", "base64");
+ xml.Attribute("compression", "gzip");
+ }
+ xml.Content(result.Output);
+ xml.EndElement(); // Value
+ xml.EndElement(); // Measurement
+ xml.EndElement(); // Results
+
+ this->AttachFiles(xml, result);
+ this->WriteTestResultFooter(xml, result);
+ }
+
+ xml.Element("EndDateTime", this->EndTest);
+ xml.Element("EndTestTime", this->EndTestTime);
+ xml.Element(
+ "ElapsedMinutes",
+ std::chrono::duration_cast<std::chrono::minutes>(this->ElapsedTestingTime)
+ .count());
+ xml.EndElement(); // Testing
+ this->CTest->EndXML(xml);
+}
+
+void cmCTestTestHandler::WriteTestResultHeader(cmXMLWriter& xml,
+ cmCTestTestResult const& result)
+{
+ xml.StartElement("Test");
+ if (result.Status == cmCTestTestHandler::COMPLETED) {
+ xml.Attribute("Status", "passed");
+ } else if (result.Status == cmCTestTestHandler::NOT_RUN) {
+ xml.Attribute("Status", "notrun");
+ } else {
+ xml.Attribute("Status", "failed");
+ }
+ std::string testPath = result.Path + "/" + result.Name;
+ xml.Element("Name", result.Name);
+ xml.Element("Path", this->CTest->GetShortPathToFile(result.Path));
+ xml.Element("FullName", this->CTest->GetShortPathToFile(testPath));
+ xml.Element("FullCommandLine", result.FullCommandLine);
+}
+
+void cmCTestTestHandler::WriteTestResultFooter(cmXMLWriter& xml,
+ cmCTestTestResult const& result)
+{
+ if (!result.Properties->Labels.empty()) {
+ xml.StartElement("Labels");
+ std::vector<std::string> const& labels = result.Properties->Labels;
+ for (std::string const& label : labels) {
+ xml.Element("Label", label);
+ }
+ xml.EndElement(); // Labels
+ }
+
+ xml.EndElement(); // Test
+}
+
+void cmCTestTestHandler::AttachFiles(cmXMLWriter& xml,
+ cmCTestTestResult& result)
+{
+ if (result.Status != cmCTestTestHandler::COMPLETED &&
+ !result.Properties->AttachOnFail.empty()) {
+ result.Properties->AttachedFiles.insert(
+ result.Properties->AttachedFiles.end(),
+ result.Properties->AttachOnFail.begin(),
+ result.Properties->AttachOnFail.end());
+ }
+ for (std::string const& file : result.Properties->AttachedFiles) {
+ const std::string& base64 = this->CTest->Base64GzipEncodeFile(file);
+ std::string const fname = cmSystemTools::GetFilenameName(file);
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("name", "Attached File");
+ xml.Attribute("encoding", "base64");
+ xml.Attribute("compression", "tar/gzip");
+ xml.Attribute("filename", fname);
+ xml.Attribute("type", "file");
+ xml.Element("Value", base64);
+ xml.EndElement(); // NamedMeasurement
+ }
+}
+
+int cmCTestTestHandler::ExecuteCommands(std::vector<std::string>& vec)
+{
+ for (std::string const& it : vec) {
+ int retVal = 0;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run command: " << it << std::endl, this->Quiet);
+ if (!cmSystemTools::RunSingleCommand(it, nullptr, nullptr, &retVal,
+ nullptr, cmSystemTools::OUTPUT_MERGE
+ /*this->Verbose*/) ||
+ retVal != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem running command: " << it << std::endl);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+// Find the appropriate executable to run for a test
+std::string cmCTestTestHandler::FindTheExecutable(const std::string& exe)
+{
+ std::string resConfig;
+ std::vector<std::string> extraPaths;
+ std::vector<std::string> failedPaths;
+ if (exe == "NOT_AVAILABLE") {
+ return exe;
+ }
+ return cmCTestTestHandler::FindExecutable(this->CTest, exe, resConfig,
+ extraPaths, failedPaths);
+}
+
+// add additional configurations to the search path
+void cmCTestTestHandler::AddConfigurations(
+ cmCTest* ctest, std::vector<std::string>& attempted,
+ std::vector<std::string>& attemptedConfigs, std::string filepath,
+ std::string& filename)
+{
+ std::string tempPath;
+
+ if (!filepath.empty() && filepath[filepath.size() - 1] != '/') {
+ filepath += "/";
+ }
+ tempPath = filepath + filename;
+ attempted.push_back(tempPath);
+ attemptedConfigs.emplace_back();
+
+ if (!ctest->GetConfigType().empty()) {
+ tempPath = cmStrCat(filepath, ctest->GetConfigType(), '/', filename);
+ attempted.push_back(tempPath);
+ attemptedConfigs.push_back(ctest->GetConfigType());
+ // If the file is an OSX bundle then the configtype
+ // will be at the start of the path
+ tempPath = cmStrCat(ctest->GetConfigType(), '/', filepath, filename);
+ attempted.push_back(tempPath);
+ attemptedConfigs.push_back(ctest->GetConfigType());
+ } else {
+ // no config specified - try some options...
+ tempPath = cmStrCat(filepath, "Release/", filename);
+ attempted.push_back(tempPath);
+ attemptedConfigs.emplace_back("Release");
+ tempPath = cmStrCat(filepath, "Debug/", filename);
+ attempted.push_back(tempPath);
+ attemptedConfigs.emplace_back("Debug");
+ tempPath = cmStrCat(filepath, "MinSizeRel/", filename);
+ attempted.push_back(tempPath);
+ attemptedConfigs.emplace_back("MinSizeRel");
+ tempPath = cmStrCat(filepath, "RelWithDebInfo/", filename);
+ attempted.push_back(tempPath);
+ attemptedConfigs.emplace_back("RelWithDebInfo");
+ tempPath = cmStrCat(filepath, "Deployment/", filename);
+ attempted.push_back(tempPath);
+ attemptedConfigs.emplace_back("Deployment");
+ tempPath = cmStrCat(filepath, "Development/", filename);
+ attempted.push_back(tempPath);
+ attemptedConfigs.emplace_back("Deployment");
+ }
+}
+
+// Find the appropriate executable to run for a test
+std::string cmCTestTestHandler::FindExecutable(
+ cmCTest* ctest, const std::string& testCommand, std::string& resultingConfig,
+ std::vector<std::string>& extraPaths, std::vector<std::string>& failed)
+{
+ // now run the compiled test if we can find it
+ std::vector<std::string> attempted;
+ std::vector<std::string> attemptedConfigs;
+ std::string tempPath;
+ std::string filepath = cmSystemTools::GetFilenamePath(testCommand);
+ std::string filename = cmSystemTools::GetFilenameName(testCommand);
+
+ cmCTestTestHandler::AddConfigurations(ctest, attempted, attemptedConfigs,
+ filepath, filename);
+
+ // even if a fullpath was specified also try it relative to the current
+ // directory
+ if (!filepath.empty() && filepath[0] == '/') {
+ std::string localfilepath = filepath.substr(1, filepath.size() - 1);
+ cmCTestTestHandler::AddConfigurations(ctest, attempted, attemptedConfigs,
+ localfilepath, filename);
+ }
+
+ // if extraPaths are provided and we were not passed a full path, try them,
+ // try any extra paths
+ if (filepath.empty()) {
+ for (std::string const& extraPath : extraPaths) {
+ std::string filepathExtra = cmSystemTools::GetFilenamePath(extraPath);
+ std::string filenameExtra = cmSystemTools::GetFilenameName(extraPath);
+ cmCTestTestHandler::AddConfigurations(ctest, attempted, attemptedConfigs,
+ filepathExtra, filenameExtra);
+ }
+ }
+
+ // store the final location in fullPath
+ std::string fullPath;
+
+ // now look in the paths we specified above
+ for (unsigned int ai = 0; ai < attempted.size() && fullPath.empty(); ++ai) {
+ // first check without exe extension
+ if (cmSystemTools::FileExists(attempted[ai]) &&
+ !cmSystemTools::FileIsDirectory(attempted[ai])) {
+ fullPath = cmSystemTools::CollapseFullPath(attempted[ai]);
+ resultingConfig = attemptedConfigs[ai];
+ }
+ // then try with the exe extension
+ else {
+ failed.push_back(attempted[ai]);
+ tempPath =
+ cmStrCat(attempted[ai], cmSystemTools::GetExecutableExtension());
+ if (cmSystemTools::FileExists(tempPath) &&
+ !cmSystemTools::FileIsDirectory(tempPath)) {
+ fullPath = cmSystemTools::CollapseFullPath(tempPath);
+ resultingConfig = attemptedConfigs[ai];
+ } else {
+ failed.push_back(tempPath);
+ }
+ }
+ }
+
+ // if everything else failed, check the users path, but only if a full path
+ // wasn't specified
+ if (fullPath.empty() && filepath.empty()) {
+ std::string path = cmSystemTools::FindProgram(filename.c_str());
+ if (!path.empty()) {
+ resultingConfig.clear();
+ return path;
+ }
+ }
+ if (fullPath.empty()) {
+ cmCTestLog(ctest, HANDLER_OUTPUT,
+ "Could not find executable "
+ << testCommand << "\n"
+ << "Looked in the following places:\n");
+ for (std::string const& f : failed) {
+ cmCTestLog(ctest, HANDLER_OUTPUT, f << "\n");
+ }
+ }
+
+ return fullPath;
+}
+
+bool cmCTestTestHandler::ParseResourceGroupsProperty(
+ const std::string& val,
+ std::vector<std::vector<cmCTestTestResourceRequirement>>& resourceGroups)
+{
+ cmCTestResourceGroupsLexerHelper lexer(resourceGroups);
+ return lexer.ParseString(val);
+}
+
+bool cmCTestTestHandler::GetListOfTests()
+{
+ if (!this->IncludeRegExp.empty()) {
+ this->IncludeTestsRegularExpression.compile(this->IncludeRegExp);
+ }
+ if (!this->ExcludeRegExp.empty()) {
+ this->ExcludeTestsRegularExpression.compile(this->ExcludeRegExp);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Constructing a list of tests" << std::endl, this->Quiet);
+ cmake cm(cmake::RoleScript, cmState::CTest);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator gg(&cm);
+ cmMakefile mf(&gg, cm.GetCurrentSnapshot());
+ mf.AddDefinition("CTEST_CONFIGURATION_TYPE", this->CTest->GetConfigType());
+
+ // Add handler for ADD_TEST
+ cm.GetState()->AddBuiltinCommand("add_test", cmCTestAddTestCommand(this));
+
+ // Add handler for SUBDIRS
+ cm.GetState()->AddBuiltinCommand("subdirs", cmCTestSubdirCommand);
+
+ // Add handler for ADD_SUBDIRECTORY
+ cm.GetState()->AddBuiltinCommand("add_subdirectory",
+ cmCTestAddSubdirectoryCommand);
+
+ // Add handler for SET_TESTS_PROPERTIES
+ cm.GetState()->AddBuiltinCommand("set_tests_properties",
+ cmCTestSetTestsPropertiesCommand(this));
+
+ // Add handler for SET_DIRECTORY_PROPERTIES
+ cm.GetState()->RemoveBuiltinCommand("set_directory_properties");
+ cm.GetState()->AddBuiltinCommand("set_directory_properties",
+ cmCTestSetDirectoryPropertiesCommand(this));
+
+ const char* testFilename;
+ if (cmSystemTools::FileExists("CTestTestfile.cmake")) {
+ // does the CTestTestfile.cmake exist ?
+ testFilename = "CTestTestfile.cmake";
+ } else if (cmSystemTools::FileExists("DartTestfile.txt")) {
+ // does the DartTestfile.txt exist ?
+ testFilename = "DartTestfile.txt";
+ } else {
+ return true;
+ }
+
+ if (!mf.ReadListFile(testFilename)) {
+ return false;
+ }
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ // SEND_ERROR or FATAL_ERROR in CTestTestfile or TEST_INCLUDE_FILES
+ return false;
+ }
+ cmProp specFile = mf.GetDefinition("CTEST_RESOURCE_SPEC_FILE");
+ if (this->ResourceSpecFile.empty() && specFile) {
+ this->ResourceSpecFile = *specFile;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Done constructing a list of tests" << std::endl,
+ this->Quiet);
+ return true;
+}
+
+void cmCTestTestHandler::UseIncludeRegExp()
+{
+ this->UseIncludeRegExpFlag = true;
+}
+
+void cmCTestTestHandler::UseExcludeRegExp()
+{
+ this->UseExcludeRegExpFlag = true;
+ this->UseExcludeRegExpFirst = !this->UseIncludeRegExpFlag;
+}
+
+std::string cmCTestTestHandler::GetTestStatus(cmCTestTestResult const& result)
+{
+ static const char* statuses[] = { "Not Run", "Timeout", "SEGFAULT",
+ "ILLEGAL", "INTERRUPT", "NUMERICAL",
+ "OTHER_FAULT", "Failed", "BAD_COMMAND",
+ "Completed" };
+ int status = result.Status;
+ if (status < cmCTestTestHandler::NOT_RUN ||
+ status > cmCTestTestHandler::COMPLETED) {
+ return "No Status";
+ }
+ if (status == cmCTestTestHandler::OTHER_FAULT) {
+ return result.ExceptionStatus;
+ }
+ return statuses[status];
+}
+
+void cmCTestTestHandler::ExpandTestsToRunInformation(size_t numTests)
+{
+ if (this->TestsToRunString.empty()) {
+ return;
+ }
+
+ int start;
+ int end = -1;
+ double stride = -1;
+ std::string::size_type pos = 0;
+ std::string::size_type pos2;
+ // read start
+ if (GetNextNumber(this->TestsToRunString, start, pos, pos2)) {
+ // read end
+ if (GetNextNumber(this->TestsToRunString, end, pos, pos2)) {
+ // read stride
+ if (GetNextRealNumber(this->TestsToRunString, stride, pos, pos2)) {
+ int val = 0;
+ // now read specific numbers
+ while (GetNextNumber(this->TestsToRunString, val, pos, pos2)) {
+ this->TestsToRun.push_back(val);
+ }
+ this->TestsToRun.push_back(val);
+ }
+ }
+ }
+
+ // if start is not specified then we assume we start at 1
+ if (start == -1) {
+ start = 1;
+ }
+
+ // if end isnot specified then we assume we end with the last test
+ if (end == -1) {
+ end = static_cast<int>(numTests);
+ }
+
+ // if the stride wasn't specified then it defaults to 1
+ if (stride == -1) {
+ stride = 1;
+ }
+
+ // if we have a range then add it
+ if (end != -1 && start != -1 && stride > 0) {
+ int i = 0;
+ while (i * stride + start <= end) {
+ this->TestsToRun.push_back(static_cast<int>(i * stride + start));
+ ++i;
+ }
+ }
+
+ // sort the array
+ std::sort(this->TestsToRun.begin(), this->TestsToRun.end(),
+ std::less<int>());
+ // remove duplicates
+ auto new_end = std::unique(this->TestsToRun.begin(), this->TestsToRun.end());
+ this->TestsToRun.erase(new_end, this->TestsToRun.end());
+}
+
+void cmCTestTestHandler::ExpandTestsToRunInformationForRerunFailed()
+{
+
+ std::string dirName = this->CTest->GetBinaryDir() + "/Testing/Temporary";
+
+ cmsys::Directory directory;
+ if (directory.Load(dirName) == 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unable to read the contents of " << dirName << std::endl);
+ return;
+ }
+
+ int numFiles =
+ static_cast<int>(cmsys::Directory::GetNumberOfFilesInDirectory(dirName));
+ std::string pattern = "LastTestsFailed";
+ std::string logName;
+
+ for (int i = 0; i < numFiles; ++i) {
+ std::string fileName = directory.GetFile(i);
+ // bcc crashes if we attempt a normal substring comparison,
+ // hence the following workaround
+ std::string fileNameSubstring = fileName.substr(0, pattern.length());
+ if (fileNameSubstring != pattern) {
+ continue;
+ }
+ if (logName.empty()) {
+ logName = fileName;
+ } else {
+ // if multiple matching logs were found we use the most recently
+ // modified one.
+ int res;
+ cmSystemTools::FileTimeCompare(logName, fileName, &res);
+ if (res == -1) {
+ logName = fileName;
+ }
+ }
+ }
+
+ std::string lastTestsFailedLog =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/" + logName;
+
+ if (!cmSystemTools::FileExists(lastTestsFailedLog)) {
+ if (!this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ lastTestsFailedLog << " does not exist!" << std::endl);
+ }
+ return;
+ }
+
+ // parse the list of tests to rerun from LastTestsFailed.log
+ cmsys::ifstream ifs(lastTestsFailedLog.c_str());
+ if (ifs) {
+ std::string line;
+ std::string::size_type pos;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ pos = line.find(':', 0);
+ if (pos == std::string::npos) {
+ continue;
+ }
+
+ line.erase(pos);
+ int val = atoi(line.c_str());
+ this->TestsToRun.push_back(val);
+ }
+ ifs.close();
+ } else if (!this->CTest->GetShowOnly() &&
+ !this->CTest->ShouldPrintLabels()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem reading file: "
+ << lastTestsFailedLog
+ << " while generating list of previously failed tests."
+ << std::endl);
+ }
+}
+
+// Just for convenience
+#define SPACE_REGEX "[ \t\r\n]"
+void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml,
+ const std::string& dart)
+{
+ cmsys::RegularExpression twoattributes(
+ "<DartMeasurement" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>([^<]*)</DartMeasurement>");
+ cmsys::RegularExpression threeattributes(
+ "<DartMeasurement" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>([^<]*)</DartMeasurement>");
+ cmsys::RegularExpression fourattributes(
+ "<DartMeasurement" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>([^<]*)</DartMeasurement>");
+ cmsys::RegularExpression cdatastart(
+ "<DartMeasurement" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>" SPACE_REGEX "*<!\\[CDATA\\[");
+ cmsys::RegularExpression cdataend("]]>" SPACE_REGEX "*</DartMeasurement>");
+ cmsys::RegularExpression measurementfile(
+ "<DartMeasurementFile" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>([^<]*)</DartMeasurementFile>");
+
+ bool done = false;
+ std::string cxml = dart;
+ while (!done) {
+ if (twoattributes.find(cxml)) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(twoattributes.match(1).c_str(), twoattributes.match(2));
+ xml.Attribute(twoattributes.match(3).c_str(), twoattributes.match(4));
+ xml.Element("Value", twoattributes.match(5));
+ xml.EndElement();
+ cxml.erase(twoattributes.start(),
+ twoattributes.end() - twoattributes.start());
+ } else if (threeattributes.find(cxml)) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(threeattributes.match(1).c_str(),
+ threeattributes.match(2));
+ xml.Attribute(threeattributes.match(3).c_str(),
+ threeattributes.match(4));
+ xml.Attribute(threeattributes.match(5).c_str(),
+ threeattributes.match(6));
+ xml.Element("Value", twoattributes.match(7));
+ xml.EndElement();
+ cxml.erase(threeattributes.start(),
+ threeattributes.end() - threeattributes.start());
+ } else if (fourattributes.find(cxml)) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(fourattributes.match(1).c_str(), fourattributes.match(2));
+ xml.Attribute(fourattributes.match(3).c_str(), fourattributes.match(4));
+ xml.Attribute(fourattributes.match(5).c_str(), fourattributes.match(6));
+ xml.Attribute(fourattributes.match(7).c_str(), fourattributes.match(8));
+ xml.Element("Value", twoattributes.match(9));
+ xml.EndElement();
+ cxml.erase(fourattributes.start(),
+ fourattributes.end() - fourattributes.start());
+ } else if (cdatastart.find(cxml) && cdataend.find(cxml)) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(cdatastart.match(1).c_str(), cdatastart.match(2));
+ xml.Attribute(cdatastart.match(3).c_str(), cdatastart.match(4));
+ xml.StartElement("Value");
+ xml.CData(
+ cxml.substr(cdatastart.end(), cdataend.start() - cdatastart.end()));
+ xml.EndElement(); // Value
+ xml.EndElement(); // NamedMeasurement
+ cxml.erase(cdatastart.start(), cdataend.end() - cdatastart.start());
+ } else if (measurementfile.find(cxml)) {
+ const std::string& filename =
+ cmCTest::CleanString(measurementfile.match(5));
+ if (cmSystemTools::FileExists(filename)) {
+ long len = cmSystemTools::FileLength(filename);
+ if (len == 0) {
+ std::string k1 = measurementfile.match(1);
+ std::string v1 = measurementfile.match(2);
+ std::string k2 = measurementfile.match(3);
+ std::string v2 = measurementfile.match(4);
+ if (cmSystemTools::LowerCase(k1) == "type") {
+ v1 = "text/string";
+ }
+ if (cmSystemTools::LowerCase(k2) == "type") {
+ v2 = "text/string";
+ }
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(k1.c_str(), v1);
+ xml.Attribute(k2.c_str(), v2);
+ xml.Attribute("encoding", "none");
+ xml.Element("Value", "Image " + filename + " is empty");
+ xml.EndElement();
+ } else {
+ cmsys::ifstream ifs(filename.c_str(),
+ std::ios::in
+#ifdef _WIN32
+ | std::ios::binary
+#endif
+ );
+ auto file_buffer = cm::make_unique<unsigned char[]>(len + 1);
+ ifs.read(reinterpret_cast<char*>(file_buffer.get()), len);
+ auto encoded_buffer = cm::make_unique<unsigned char[]>(
+ static_cast<int>(static_cast<double>(len) * 1.5 + 5.0));
+
+ size_t rlen = cmsysBase64_Encode(file_buffer.get(), len,
+ encoded_buffer.get(), 1);
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(measurementfile.match(1).c_str(),
+ measurementfile.match(2));
+ xml.Attribute(measurementfile.match(3).c_str(),
+ measurementfile.match(4));
+ xml.Attribute("encoding", "base64");
+ std::ostringstream ostr;
+ for (size_t cc = 0; cc < rlen; cc++) {
+ ostr << encoded_buffer[cc];
+ if (cc % 60 == 0 && cc) {
+ ostr << std::endl;
+ }
+ }
+ xml.Element("Value", ostr.str());
+ xml.EndElement(); // NamedMeasurement
+ }
+ } else {
+ int idx = 4;
+ if (measurementfile.match(1) == "name") {
+ idx = 2;
+ }
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("name", measurementfile.match(idx));
+ xml.Attribute("text", "text/string");
+ xml.Element("Value", "File " + filename + " not found");
+ xml.EndElement();
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ "File \"" << filename << "\" not found." << std::endl, this->Quiet);
+ }
+ cxml.erase(measurementfile.start(),
+ measurementfile.end() - measurementfile.start());
+ } else {
+ done = true;
+ }
+ }
+}
+
+void cmCTestTestHandler::SetIncludeRegExp(const char* arg)
+{
+ this->IncludeRegExp = arg;
+}
+
+void cmCTestTestHandler::SetExcludeRegExp(const char* arg)
+{
+ this->ExcludeRegExp = arg;
+}
+
+void cmCTestTestHandler::SetTestsToRunInformation(const char* in)
+{
+ if (!in) {
+ return;
+ }
+ this->TestsToRunString = in;
+ // if the argument is a file, then read it and use the contents as the
+ // string
+ if (cmSystemTools::FileExists(in)) {
+ cmsys::ifstream fin(in);
+ unsigned long filelen = cmSystemTools::FileLength(in);
+ auto buff = cm::make_unique<char[]>(filelen + 1);
+ fin.getline(buff.get(), filelen);
+ buff[fin.gcount()] = 0;
+ this->TestsToRunString = buff.get();
+ }
+}
+
+void cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length)
+{
+ if (!length || length >= output.size() ||
+ output.find("CTEST_FULL_OUTPUT") != std::string::npos) {
+ return;
+ }
+
+ // Truncate at given length but do not break in the middle of a multi-byte
+ // UTF-8 encoding.
+ char const* const begin = output.c_str();
+ char const* const end = begin + output.size();
+ char const* const truncate = begin + length;
+ char const* current = begin;
+ while (current < truncate) {
+ unsigned int ch;
+ if (const char* next = cm_utf8_decode_character(current, end, &ch)) {
+ if (next > truncate) {
+ break;
+ }
+ current = next;
+ } else // Bad byte will be handled by cmXMLWriter.
+ {
+ ++current;
+ }
+ }
+ output.erase(current - begin);
+
+ // Append truncation message.
+ std::ostringstream msg;
+ msg << "...\n"
+ "The rest of the test output was removed since it exceeds the "
+ "threshold "
+ "of "
+ << length << " bytes.\n";
+ output += msg.str();
+}
+
+bool cmCTestTestHandler::SetTestsProperties(
+ const std::vector<std::string>& args)
+{
+ std::vector<std::string>::const_iterator it;
+ std::vector<std::string> tests;
+ bool found = false;
+ for (it = args.begin(); it != args.end(); ++it) {
+ if (*it == "PROPERTIES") {
+ found = true;
+ break;
+ }
+ tests.push_back(*it);
+ }
+ if (!found) {
+ return false;
+ }
+ ++it; // skip PROPERTIES
+ for (; it != args.end(); ++it) {
+ std::string const& key = *it;
+ ++it;
+ if (it == args.end()) {
+ break;
+ }
+ std::string const& val = *it;
+ for (std::string const& t : tests) {
+ for (cmCTestTestProperties& rt : this->TestList) {
+ if (t == rt.Name) {
+ if (key == "_BACKTRACE_TRIPLES"_s) {
+ std::vector<std::string> triples;
+ // allow empty args in the triples
+ cmExpandList(val, triples, true);
+
+ // Ensure we have complete triples otherwise the data is corrupt.
+ if (triples.size() % 3 == 0) {
+ cmState state;
+ rt.Backtrace = cmListFileBacktrace(state.CreateBaseSnapshot());
+
+ // the first entry represents the top of the trace so we need to
+ // reconstruct the backtrace in reverse
+ for (size_t i = triples.size(); i >= 3; i -= 3) {
+ cmListFileContext fc;
+ fc.FilePath = triples[i - 3];
+ long line = 0;
+ if (!cmStrToLong(triples[i - 2], &line)) {
+ line = 0;
+ }
+ fc.Line = line;
+ fc.Name = triples[i - 1];
+ rt.Backtrace = rt.Backtrace.Push(fc);
+ }
+ }
+ } else if (key == "WILL_FAIL"_s) {
+ rt.WillFail = cmIsOn(val);
+ } else if (key == "DISABLED"_s) {
+ rt.Disabled = cmIsOn(val);
+ } else if (key == "ATTACHED_FILES"_s) {
+ cmExpandList(val, rt.AttachedFiles);
+ } else if (key == "ATTACHED_FILES_ON_FAIL"_s) {
+ cmExpandList(val, rt.AttachOnFail);
+ } else if (key == "RESOURCE_LOCK"_s) {
+ std::vector<std::string> lval = cmExpandedList(val);
+
+ rt.LockedResources.insert(lval.begin(), lval.end());
+ } else if (key == "FIXTURES_SETUP"_s) {
+ std::vector<std::string> lval = cmExpandedList(val);
+
+ rt.FixturesSetup.insert(lval.begin(), lval.end());
+ } else if (key == "FIXTURES_CLEANUP"_s) {
+ std::vector<std::string> lval = cmExpandedList(val);
+
+ rt.FixturesCleanup.insert(lval.begin(), lval.end());
+ } else if (key == "FIXTURES_REQUIRED"_s) {
+ std::vector<std::string> lval = cmExpandedList(val);
+
+ rt.FixturesRequired.insert(lval.begin(), lval.end());
+ } else if (key == "TIMEOUT"_s) {
+ rt.Timeout = cmDuration(atof(val.c_str()));
+ rt.ExplicitTimeout = true;
+ } else if (key == "COST"_s) {
+ rt.Cost = static_cast<float>(atof(val.c_str()));
+ } else if (key == "REQUIRED_FILES"_s) {
+ cmExpandList(val, rt.RequiredFiles);
+ } else if (key == "RUN_SERIAL"_s) {
+ rt.RunSerial = cmIsOn(val);
+ } else if (key == "FAIL_REGULAR_EXPRESSION"_s) {
+ std::vector<std::string> lval = cmExpandedList(val);
+ for (std::string const& cr : lval) {
+ rt.ErrorRegularExpressions.emplace_back(cr, cr);
+ }
+ } else if (key == "SKIP_REGULAR_EXPRESSION"_s) {
+ std::vector<std::string> lval = cmExpandedList(val);
+ for (std::string const& cr : lval) {
+ rt.SkipRegularExpressions.emplace_back(cr, cr);
+ }
+ } else if (key == "PROCESSORS"_s) {
+ rt.Processors = atoi(val.c_str());
+ if (rt.Processors < 1) {
+ rt.Processors = 1;
+ }
+ } else if (key == "PROCESSOR_AFFINITY"_s) {
+ rt.WantAffinity = cmIsOn(val);
+ } else if (key == "RESOURCE_GROUPS"_s) {
+ if (!ParseResourceGroupsProperty(val, rt.ResourceGroups)) {
+ return false;
+ }
+ } else if (key == "SKIP_RETURN_CODE"_s) {
+ rt.SkipReturnCode = atoi(val.c_str());
+ if (rt.SkipReturnCode < 0 || rt.SkipReturnCode > 255) {
+ rt.SkipReturnCode = -1;
+ }
+ } else if (key == "DEPENDS"_s) {
+ cmExpandList(val, rt.Depends);
+ } else if (key == "ENVIRONMENT"_s) {
+ cmExpandList(val, rt.Environment);
+ } else if (key == "LABELS"_s) {
+ std::vector<std::string> Labels = cmExpandedList(val);
+ rt.Labels.insert(rt.Labels.end(), Labels.begin(), Labels.end());
+ // sort the array
+ std::sort(rt.Labels.begin(), rt.Labels.end());
+ // remove duplicates
+ auto new_end = std::unique(rt.Labels.begin(), rt.Labels.end());
+ rt.Labels.erase(new_end, rt.Labels.end());
+ } else if (key == "MEASUREMENT"_s) {
+ size_t pos = val.find_first_of('=');
+ if (pos != std::string::npos) {
+ std::string mKey = val.substr(0, pos);
+ std::string mVal = val.substr(pos + 1);
+ rt.Measurements[mKey] = std::move(mVal);
+ } else {
+ rt.Measurements[val] = "1";
+ }
+ } else if (key == "PASS_REGULAR_EXPRESSION"_s) {
+ std::vector<std::string> lval = cmExpandedList(val);
+ for (std::string const& cr : lval) {
+ rt.RequiredRegularExpressions.emplace_back(cr, cr);
+ }
+ } else if (key == "WORKING_DIRECTORY"_s) {
+ rt.Directory = val;
+ } else if (key == "TIMEOUT_AFTER_MATCH"_s) {
+ std::vector<std::string> propArgs = cmExpandedList(val);
+ if (propArgs.size() != 2) {
+ cmCTestLog(this->CTest, WARNING,
+ "TIMEOUT_AFTER_MATCH expects two arguments, found "
+ << propArgs.size() << std::endl);
+ } else {
+ rt.AlternateTimeout = cmDuration(atof(propArgs[0].c_str()));
+ std::vector<std::string> lval = cmExpandedList(propArgs[1]);
+ for (std::string const& cr : lval) {
+ rt.TimeoutRegularExpressions.emplace_back(cr, cr);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool cmCTestTestHandler::SetDirectoryProperties(
+ const std::vector<std::string>& args)
+{
+ std::vector<std::string>::const_iterator it;
+ std::vector<std::string> tests;
+ bool found = false;
+ for (it = args.begin(); it != args.end(); ++it) {
+ if (*it == "PROPERTIES") {
+ found = true;
+ break;
+ }
+ tests.push_back(*it);
+ }
+
+ if (!found) {
+ return false;
+ }
+ ++it; // skip PROPERTIES
+ for (; it != args.end(); ++it) {
+ std::string const& key = *it;
+ ++it;
+ if (it == args.end()) {
+ break;
+ }
+ std::string const& val = *it;
+ for (cmCTestTestProperties& rt : this->TestList) {
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ if (cwd == rt.Directory) {
+ if (key == "LABELS"_s) {
+ std::vector<std::string> DirectoryLabels = cmExpandedList(val);
+ rt.Labels.insert(rt.Labels.end(), DirectoryLabels.begin(),
+ DirectoryLabels.end());
+
+ // sort the array
+ std::sort(rt.Labels.begin(), rt.Labels.end());
+ // remove duplicates
+ auto new_end = std::unique(rt.Labels.begin(), rt.Labels.end());
+ rt.Labels.erase(new_end, rt.Labels.end());
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args)
+{
+ const std::string& testname = args[0];
+ cmCTestOptionalLog(this->CTest, DEBUG, "Add test: " << args[0] << std::endl,
+ this->Quiet);
+
+ if (this->UseExcludeRegExpFlag && this->UseExcludeRegExpFirst &&
+ this->ExcludeTestsRegularExpression.find(testname)) {
+ return true;
+ }
+ if (this->MemCheck) {
+ std::vector<std::string>::iterator it;
+ bool found = false;
+ for (it = this->CustomTestsIgnore.begin();
+ it != this->CustomTestsIgnore.end(); ++it) {
+ if (*it == testname) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Ignore memcheck: " << *it << std::endl, this->Quiet);
+ return true;
+ }
+ } else {
+ std::vector<std::string>::iterator it;
+ bool found = false;
+ for (it = this->CustomTestsIgnore.begin();
+ it != this->CustomTestsIgnore.end(); ++it) {
+ if (*it == testname) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Ignore test: " << *it << std::endl, this->Quiet);
+ return true;
+ }
+ }
+
+ cmCTestTestProperties test;
+ test.Name = testname;
+ test.Args = args;
+ test.Directory = cmSystemTools::GetCurrentWorkingDirectory();
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Set test directory: " << test.Directory << std::endl,
+ this->Quiet);
+
+ test.IsInBasedOnREOptions = true;
+ test.WillFail = false;
+ test.Disabled = false;
+ test.RunSerial = false;
+ test.Timeout = cmDuration::zero();
+ test.ExplicitTimeout = false;
+ test.Cost = 0;
+ test.Processors = 1;
+ test.WantAffinity = false;
+ test.SkipReturnCode = -1;
+ test.PreviousRuns = 0;
+ if (this->UseIncludeRegExpFlag &&
+ (!this->IncludeTestsRegularExpression.find(testname) ||
+ (!this->UseExcludeRegExpFirst &&
+ this->ExcludeTestsRegularExpression.find(testname)))) {
+ test.IsInBasedOnREOptions = false;
+ }
+ this->TestList.push_back(test);
+ return true;
+}
+
+bool cmCTestTestHandler::cmCTestTestResourceRequirement::operator==(
+ const cmCTestTestResourceRequirement& other) const
+{
+ return this->ResourceType == other.ResourceType &&
+ this->SlotsNeeded == other.SlotsNeeded &&
+ this->UnitsNeeded == other.UnitsNeeded;
+}
+
+bool cmCTestTestHandler::cmCTestTestResourceRequirement::operator!=(
+ const cmCTestTestResourceRequirement& other) const
+{
+ return !(*this == other);
+}
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
new file mode 100644
index 0000000..6fa18a9
--- /dev/null
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -0,0 +1,357 @@
+/* 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 <chrono>
+#include <cstdint>
+#include <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <stddef.h>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCTest.h"
+#include "cmCTestGenericHandler.h"
+#include "cmCTestResourceSpec.h"
+#include "cmDuration.h"
+#include "cmListFileCache.h"
+
+class cmMakefile;
+class cmXMLWriter;
+
+/** \class cmCTestTestHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ */
+class cmCTestTestHandler : public cmCTestGenericHandler
+{
+ friend class cmCTestRunTest;
+ friend class cmCTestMultiProcessHandler;
+
+public:
+ using Superclass = cmCTestGenericHandler;
+
+ /**
+ * The main entry point for this class
+ */
+ int ProcessHandler() override;
+
+ /**
+ * When both -R and -I are used should the resulting test list be the
+ * intersection or the union of the lists. By default it is the
+ * intersection.
+ */
+ void SetUseUnion(bool val) { this->UseUnion = val; }
+
+ /**
+ * Set whether or not CTest should only execute the tests that failed
+ * on the previous run. By default this is false.
+ */
+ void SetRerunFailed(bool val) { this->RerunFailed = val; }
+
+ /**
+ * This method is called when reading CTest custom file
+ */
+ void PopulateCustomVectors(cmMakefile* mf) override;
+
+ //! Control the use of the regular expresisons, call these methods to turn
+ /// them on
+ void UseIncludeRegExp();
+ void UseExcludeRegExp();
+ void SetIncludeRegExp(const char*);
+ void SetExcludeRegExp(const char*);
+
+ void SetMaxIndex(int n) { this->MaxIndex = n; }
+ int GetMaxIndex() { return this->MaxIndex; }
+
+ void SetTestOutputSizePassed(int n)
+ {
+ this->CustomMaximumPassedTestOutputSize = n;
+ }
+ void SetTestOutputSizeFailed(int n)
+ {
+ this->CustomMaximumFailedTestOutputSize = n;
+ }
+
+ //! pass the -I argument down
+ void SetTestsToRunInformation(const char*);
+
+ cmCTestTestHandler();
+
+ /*
+ * Add the test to the list of tests to be executed
+ */
+ bool AddTest(const std::vector<std::string>& args);
+
+ /*
+ * Set tests properties
+ */
+ bool SetTestsProperties(const std::vector<std::string>& args);
+
+ /**
+ * Set directory properties
+ */
+ bool SetDirectoryProperties(const std::vector<std::string>& args);
+
+ void Initialize() override;
+
+ struct cmCTestTestResourceRequirement
+ {
+ std::string ResourceType;
+ int SlotsNeeded;
+ int UnitsNeeded;
+
+ bool operator==(const cmCTestTestResourceRequirement& other) const;
+ bool operator!=(const cmCTestTestResourceRequirement& other) const;
+ };
+
+ // NOTE: This struct is Saved/Restored
+ // in cmCTestTestHandler, if you add to this class
+ // then you must add the new members to that code or
+ // ctest -j N will break for that feature
+ struct cmCTestTestProperties
+ {
+ std::string Name;
+ std::string Directory;
+ std::vector<std::string> Args;
+ std::vector<std::string> RequiredFiles;
+ std::vector<std::string> Depends;
+ std::vector<std::string> AttachedFiles;
+ std::vector<std::string> AttachOnFail;
+ std::vector<std::pair<cmsys::RegularExpression, std::string>>
+ ErrorRegularExpressions;
+ std::vector<std::pair<cmsys::RegularExpression, std::string>>
+ RequiredRegularExpressions;
+ std::vector<std::pair<cmsys::RegularExpression, std::string>>
+ SkipRegularExpressions;
+ std::vector<std::pair<cmsys::RegularExpression, std::string>>
+ TimeoutRegularExpressions;
+ std::map<std::string, std::string> Measurements;
+ bool IsInBasedOnREOptions;
+ bool WillFail;
+ bool Disabled;
+ float Cost;
+ int PreviousRuns;
+ bool RunSerial;
+ cmDuration Timeout;
+ bool ExplicitTimeout;
+ cmDuration AlternateTimeout;
+ int Index;
+ // Requested number of process slots
+ int Processors;
+ bool WantAffinity;
+ std::vector<size_t> Affinity;
+ // return code of test which will mark test as "not run"
+ int SkipReturnCode;
+ std::vector<std::string> Environment;
+ std::vector<std::string> Labels;
+ std::set<std::string> LockedResources;
+ std::set<std::string> FixturesSetup;
+ std::set<std::string> FixturesCleanup;
+ std::set<std::string> FixturesRequired;
+ std::set<std::string> RequireSuccessDepends;
+ std::vector<std::vector<cmCTestTestResourceRequirement>> ResourceGroups;
+ // Private test generator properties used to track backtraces
+ cmListFileBacktrace Backtrace;
+ };
+
+ struct cmCTestTestResult
+ {
+ std::string Name;
+ std::string Path;
+ std::string Reason;
+ std::string FullCommandLine;
+ std::string Environment;
+ cmDuration ExecutionTime;
+ std::int64_t ReturnValue;
+ int Status;
+ std::string ExceptionStatus;
+ bool CompressOutput;
+ std::string CompletionStatus;
+ std::string Output;
+ std::string DartString;
+ int TestCount;
+ cmCTestTestProperties* Properties;
+ };
+
+ struct cmCTestTestResultLess
+ {
+ bool operator()(const cmCTestTestResult& lhs,
+ const cmCTestTestResult& rhs) const
+ {
+ return lhs.TestCount < rhs.TestCount;
+ }
+ };
+
+ // add configurations to a search path for an executable
+ static void AddConfigurations(cmCTest* ctest,
+ std::vector<std::string>& attempted,
+ std::vector<std::string>& attemptedConfigs,
+ std::string filepath, std::string& filename);
+
+ // full signature static method to find an executable
+ static std::string FindExecutable(cmCTest* ctest,
+ const std::string& testCommand,
+ std::string& resultingConfig,
+ std::vector<std::string>& extraPaths,
+ std::vector<std::string>& failed);
+
+ static bool ParseResourceGroupsProperty(
+ const std::string& val,
+ std::vector<std::vector<cmCTestTestResourceRequirement>>& resourceGroups);
+
+ using ListOfTests = std::vector<cmCTestTestProperties>;
+
+protected:
+ using SetOfTests =
+ std::set<cmCTestTestHandler::cmCTestTestResult, cmCTestTestResultLess>;
+
+ // compute a final test list
+ virtual int PreProcessHandler();
+ virtual int PostProcessHandler();
+ virtual void GenerateTestCommand(std::vector<std::string>& args, int test);
+ int ExecuteCommands(std::vector<std::string>& vec);
+
+ bool ProcessOptions();
+ void LogTestSummary(const std::vector<std::string>& passed,
+ const std::vector<std::string>& failed,
+ const cmDuration& durationInSecs);
+ void LogDisabledTests(const std::vector<cmCTestTestResult>& disabledTests);
+ void LogFailedTests(const std::vector<std::string>& failed,
+ const SetOfTests& resultsSet);
+ bool GenerateXML();
+
+ void WriteTestResultHeader(cmXMLWriter& xml,
+ cmCTestTestResult const& result);
+ void WriteTestResultFooter(cmXMLWriter& xml,
+ cmCTestTestResult const& result);
+ // Write attached test files into the xml
+ void AttachFiles(cmXMLWriter& xml, cmCTestTestResult& result);
+
+ //! Clean test output to specified length
+ void CleanTestOutput(std::string& output, size_t length);
+
+ cmDuration ElapsedTestingTime;
+
+ using TestResultsVector = std::vector<cmCTestTestResult>;
+ TestResultsVector TestResults;
+
+ std::vector<std::string> CustomTestsIgnore;
+ std::string StartTest;
+ std::string EndTest;
+ std::chrono::system_clock::time_point StartTestTime;
+ std::chrono::system_clock::time_point EndTestTime;
+ bool MemCheck;
+ int CustomMaximumPassedTestOutputSize;
+ int CustomMaximumFailedTestOutputSize;
+ int MaxIndex;
+
+public:
+ enum
+ { // Program statuses
+ NOT_RUN = 0,
+ TIMEOUT,
+ SEGFAULT,
+ ILLEGAL,
+ INTERRUPT,
+ NUMERICAL,
+ OTHER_FAULT,
+ FAILED,
+ BAD_COMMAND,
+ COMPLETED
+ };
+
+private:
+ /**
+ * Generate the Dart compatible output
+ */
+ virtual void GenerateDartOutput(cmXMLWriter& xml);
+
+ void PrintLabelOrSubprojectSummary(bool isSubProject);
+
+ /**
+ * Run the tests for a directory and any subdirectories
+ */
+ bool ProcessDirectory(std::vector<std::string>& passed,
+ std::vector<std::string>& failed);
+
+ /**
+ * Get the list of tests in directory and subdirectories.
+ */
+ bool GetListOfTests();
+ // compute the lists of tests that will actually run
+ // based on union regex and -I stuff
+ bool ComputeTestList();
+
+ // compute the lists of tests that will actually run
+ // based on LastTestFailed.log
+ void ComputeTestListForRerunFailed();
+
+ // add required setup/cleanup tests not already in the
+ // list of tests to be run and update dependencies between
+ // tests to account for fixture setup/cleanup
+ void UpdateForFixtures(ListOfTests& tests) const;
+
+ void UpdateMaxTestNameWidth();
+
+ bool GetValue(const char* tag, std::string& value, std::istream& fin);
+ bool GetValue(const char* tag, int& value, std::istream& fin);
+ bool GetValue(const char* tag, size_t& value, std::istream& fin);
+ bool GetValue(const char* tag, bool& value, std::istream& fin);
+ bool GetValue(const char* tag, double& value, std::istream& fin);
+ /**
+ * Find the executable for a test
+ */
+ std::string FindTheExecutable(const std::string& exe);
+
+ std::string GetTestStatus(cmCTestTestResult const&);
+ void ExpandTestsToRunInformation(size_t numPossibleTests);
+ void ExpandTestsToRunInformationForRerunFailed();
+
+ std::vector<std::string> CustomPreTest;
+ std::vector<std::string> CustomPostTest;
+
+ std::vector<int> TestsToRun;
+
+ bool UseIncludeRegExpFlag;
+ bool UseExcludeRegExpFlag;
+ bool UseExcludeRegExpFirst;
+ std::string IncludeRegExp;
+ std::string ExcludeRegExp;
+ std::string ExcludeFixtureRegExp;
+ std::string ExcludeFixtureSetupRegExp;
+ std::string ExcludeFixtureCleanupRegExp;
+ std::vector<cmsys::RegularExpression> IncludeLabelRegularExpressions;
+ std::vector<cmsys::RegularExpression> ExcludeLabelRegularExpressions;
+ cmsys::RegularExpression IncludeTestsRegularExpression;
+ cmsys::RegularExpression ExcludeTestsRegularExpression;
+
+ bool UseResourceSpec;
+ cmCTestResourceSpec ResourceSpec;
+ std::string ResourceSpecFile;
+
+ void GenerateRegressionImages(cmXMLWriter& xml, const std::string& dart);
+ cmsys::RegularExpression DartStuff1;
+ void CheckLabelFilter(cmCTestTestProperties& it);
+ void CheckLabelFilterExclude(cmCTestTestProperties& it);
+ void CheckLabelFilterInclude(cmCTestTestProperties& it);
+
+ std::string TestsToRunString;
+ bool UseUnion;
+ ListOfTests TestList;
+ size_t TotalNumberOfTests;
+ cmsys::RegularExpression DartStuff;
+
+ std::ostream* LogFile;
+
+ cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never;
+ int RepeatCount = 1;
+ bool RerunFailed;
+};
diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx
new file mode 100644
index 0000000..0ba2c41
--- /dev/null
+++ b/Source/CTest/cmCTestUpdateCommand.cxx
@@ -0,0 +1,86 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestUpdateCommand.h"
+
+#include "cmCTest.h"
+#include "cmCTestUpdateHandler.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler()
+{
+ if (!this->Source.empty()) {
+ this->CTest->SetCTestConfiguration(
+ "SourceDirectory", cmSystemTools::CollapseFullPath(this->Source),
+ this->Quiet);
+ } else {
+ this->CTest->SetCTestConfiguration(
+ "SourceDirectory",
+ cmSystemTools::CollapseFullPath(
+ this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY")),
+ this->Quiet);
+ }
+ std::string source_dir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
+
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "UpdateCommand", "CTEST_UPDATE_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "UpdateOptions", "CTEST_UPDATE_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "CVSCommand", "CTEST_CVS_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "CVSUpdateOptions", "CTEST_CVS_UPDATE_OPTIONS",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "SVNCommand", "CTEST_SVN_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "SVNUpdateOptions", "CTEST_SVN_UPDATE_OPTIONS",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "SVNOptions", "CTEST_SVN_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "BZRCommand", "CTEST_BZR_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "BZRUpdateOptions", "CTEST_BZR_UPDATE_OPTIONS",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "GITCommand", "CTEST_GIT_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "GITUpdateOptions", "CTEST_GIT_UPDATE_OPTIONS",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "GITInitSubmodules", "CTEST_GIT_INIT_SUBMODULES",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "GITUpdateCustom", "CTEST_GIT_UPDATE_CUSTOM", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "UpdateVersionOnly", "CTEST_UPDATE_VERSION_ONLY",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "UpdateVersionOverride", "CTEST_UPDATE_VERSION_OVERRIDE",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "HGCommand", "CTEST_HG_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "HGUpdateOptions", "CTEST_HG_UPDATE_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "P4Command", "CTEST_P4_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "P4UpdateOptions", "CTEST_P4_UPDATE_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "P4Client", "CTEST_P4_CLIENT", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "P4Options", "CTEST_P4_OPTIONS", this->Quiet);
+
+ cmCTestUpdateHandler* handler = this->CTest->GetUpdateHandler();
+ handler->Initialize();
+ handler->SetCommand(this);
+ if (source_dir.empty()) {
+ this->SetError("source directory not specified. Please use SOURCE tag");
+ return nullptr;
+ }
+ handler->SetOption("SourceDirectory", source_dir.c_str());
+ handler->SetQuiet(this->Quiet);
+ return handler;
+}
diff --git a/Source/CTest/cmCTestUpdateCommand.h b/Source/CTest/cmCTestUpdateCommand.h
new file mode 100644
index 0000000..e4c3453
--- /dev/null
+++ b/Source/CTest/cmCTestUpdateCommand.h
@@ -0,0 +1,43 @@
+/* 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 <string>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmCTestHandlerCommand.h"
+#include "cmCommand.h"
+
+class cmCTestGenericHandler;
+
+/** \class cmCTestUpdate
+ * \brief Run a ctest script
+ *
+ * cmCTestUpdateCommand defineds the command to updates the repository.
+ */
+class cmCTestUpdateCommand : public cmCTestHandlerCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ auto ni = cm::make_unique<cmCTestUpdateCommand>();
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return std::unique_ptr<cmCommand>(std::move(ni));
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const override { return "ctest_update"; }
+
+protected:
+ cmCTestGenericHandler* InitializeHandler() override;
+};
diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx
new file mode 100644
index 0000000..57cc024
--- /dev/null
+++ b/Source/CTest/cmCTestUpdateHandler.cxx
@@ -0,0 +1,353 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestUpdateHandler.h"
+
+#include <chrono>
+#include <sstream>
+
+#include <cm/memory>
+
+#include "cmCLocaleEnvironmentScope.h"
+#include "cmCTest.h"
+#include "cmCTestBZR.h"
+#include "cmCTestCVS.h"
+#include "cmCTestGIT.h"
+#include "cmCTestHG.h"
+#include "cmCTestP4.h"
+#include "cmCTestSVN.h"
+#include "cmCTestVC.h"
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+#include "cmXMLWriter.h"
+
+static const char* cmCTestUpdateHandlerUpdateStrings[] = {
+ "Unknown", "CVS", "SVN", "BZR", "GIT", "HG", "P4"
+};
+
+static const char* cmCTestUpdateHandlerUpdateToString(int type)
+{
+ if (type < cmCTestUpdateHandler::e_UNKNOWN ||
+ type >= cmCTestUpdateHandler::e_LAST) {
+ return cmCTestUpdateHandlerUpdateStrings[cmCTestUpdateHandler::e_UNKNOWN];
+ }
+ return cmCTestUpdateHandlerUpdateStrings[type];
+}
+
+cmCTestUpdateHandler::cmCTestUpdateHandler() = default;
+
+void cmCTestUpdateHandler::Initialize()
+{
+ this->Superclass::Initialize();
+ this->UpdateCommand.clear();
+ this->UpdateType = e_CVS;
+}
+
+int cmCTestUpdateHandler::DetermineType(const char* cmd, const char* type)
+{
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Determine update type from command: "
+ << cmd << " and type: " << type << std::endl,
+ this->Quiet);
+ if (type && *type) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Type specified: " << type << std::endl, this->Quiet);
+ std::string stype = cmSystemTools::LowerCase(type);
+ if (stype.find("cvs") != std::string::npos) {
+ return cmCTestUpdateHandler::e_CVS;
+ }
+ if (stype.find("svn") != std::string::npos) {
+ return cmCTestUpdateHandler::e_SVN;
+ }
+ if (stype.find("bzr") != std::string::npos) {
+ return cmCTestUpdateHandler::e_BZR;
+ }
+ if (stype.find("git") != std::string::npos) {
+ return cmCTestUpdateHandler::e_GIT;
+ }
+ if (stype.find("hg") != std::string::npos) {
+ return cmCTestUpdateHandler::e_HG;
+ }
+ if (stype.find("p4") != std::string::npos) {
+ return cmCTestUpdateHandler::e_P4;
+ }
+ } else {
+ cmCTestOptionalLog(
+ this->CTest, DEBUG,
+ "Type not specified, check command: " << cmd << std::endl, this->Quiet);
+ std::string stype = cmSystemTools::LowerCase(cmd);
+ if (stype.find("cvs") != std::string::npos) {
+ return cmCTestUpdateHandler::e_CVS;
+ }
+ if (stype.find("svn") != std::string::npos) {
+ return cmCTestUpdateHandler::e_SVN;
+ }
+ if (stype.find("bzr") != std::string::npos) {
+ return cmCTestUpdateHandler::e_BZR;
+ }
+ if (stype.find("git") != std::string::npos) {
+ return cmCTestUpdateHandler::e_GIT;
+ }
+ if (stype.find("hg") != std::string::npos) {
+ return cmCTestUpdateHandler::e_HG;
+ }
+ if (stype.find("p4") != std::string::npos) {
+ return cmCTestUpdateHandler::e_P4;
+ }
+ }
+ return cmCTestUpdateHandler::e_UNKNOWN;
+}
+
+// clearly it would be nice if this were broken up into a few smaller
+// functions and commented...
+int cmCTestUpdateHandler::ProcessHandler()
+{
+ // Make sure VCS tool messages are in English so we can parse them.
+ cmCLocaleEnvironmentScope fixLocale;
+ static_cast<void>(fixLocale);
+
+ // Get source dir
+ const char* sourceDirectory = this->GetOption("SourceDirectory");
+ if (!sourceDirectory) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find SourceDirectory key in the DartConfiguration.tcl"
+ << std::endl);
+ return -1;
+ }
+
+ cmGeneratedFileStream ofs;
+ if (!this->CTest->GetShowOnly()) {
+ this->StartLogFile("Update", ofs);
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Updating the repository: " << sourceDirectory
+ << std::endl,
+ this->Quiet);
+
+ if (!this->SelectVCS()) {
+ return -1;
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Use "
+ << cmCTestUpdateHandlerUpdateToString(this->UpdateType)
+ << " repository type" << std::endl;
+ , this->Quiet);
+
+ // Create an object to interact with the VCS tool.
+ std::unique_ptr<cmCTestVC> vc;
+ switch (this->UpdateType) {
+ case e_CVS:
+ vc = cm::make_unique<cmCTestCVS>(this->CTest, ofs);
+ break;
+ case e_SVN:
+ vc = cm::make_unique<cmCTestSVN>(this->CTest, ofs);
+ break;
+ case e_BZR:
+ vc = cm::make_unique<cmCTestBZR>(this->CTest, ofs);
+ break;
+ case e_GIT:
+ vc = cm::make_unique<cmCTestGIT>(this->CTest, ofs);
+ break;
+ case e_HG:
+ vc = cm::make_unique<cmCTestHG>(this->CTest, ofs);
+ break;
+ case e_P4:
+ vc = cm::make_unique<cmCTestP4>(this->CTest, ofs);
+ break;
+ default:
+ vc = cm::make_unique<cmCTestVC>(this->CTest, ofs);
+ break;
+ }
+ vc->SetCommandLineTool(this->UpdateCommand);
+ vc->SetSourceDirectory(sourceDirectory);
+
+ // Cleanup the working tree.
+ vc->Cleanup();
+
+ //
+ // Now update repository and remember what files were updated
+ //
+ cmGeneratedFileStream os;
+ if (!this->StartResultingXML(cmCTest::PartUpdate, "Update", os)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open log file" << std::endl);
+ return -1;
+ }
+ std::string start_time = this->CTest->CurrentTime();
+ auto start_time_time = std::chrono::system_clock::now();
+ auto elapsed_time_start = std::chrono::steady_clock::now();
+
+ bool updated = vc->Update();
+ std::string buildname =
+ cmCTest::SafeBuildIdField(this->CTest->GetCTestConfiguration("BuildName"));
+
+ cmXMLWriter xml(os);
+ xml.StartDocument();
+ xml.StartElement("Update");
+ xml.Attribute("mode", "Client");
+ xml.Attribute("Generator",
+ std::string("ctest-") + cmVersion::GetCMakeVersion());
+ xml.Element("Site", this->CTest->GetCTestConfiguration("Site"));
+ xml.Element("BuildName", buildname);
+ xml.Element("BuildStamp",
+ this->CTest->GetCurrentTag() + "-" +
+ this->CTest->GetTestModelString());
+ xml.Element("StartDateTime", start_time);
+ xml.Element("StartTime", start_time_time);
+ xml.Element("UpdateCommand", vc->GetUpdateCommandLine());
+ xml.Element("UpdateType",
+ cmCTestUpdateHandlerUpdateToString(this->UpdateType));
+ std::string changeId = this->CTest->GetCTestConfiguration("ChangeId");
+ if (!changeId.empty()) {
+ xml.Element("ChangeId", changeId);
+ }
+
+ bool loadedMods = vc->WriteXML(xml);
+
+ int localModifications = 0;
+ int numUpdated = vc->GetPathCount(cmCTestVC::PathUpdated);
+ if (numUpdated) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Found " << numUpdated << " updated files\n",
+ this->Quiet);
+ }
+ if (int numModified = vc->GetPathCount(cmCTestVC::PathModified)) {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ " Found " << numModified << " locally modified files\n", this->Quiet);
+ localModifications += numModified;
+ }
+ if (int numConflicting = vc->GetPathCount(cmCTestVC::PathConflicting)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Found " << numConflicting << " conflicting files\n",
+ this->Quiet);
+ localModifications += numConflicting;
+ }
+
+ cmCTestOptionalLog(this->CTest, DEBUG, "End" << std::endl, this->Quiet);
+ std::string end_time = this->CTest->CurrentTime();
+ xml.Element("EndDateTime", end_time);
+ xml.Element("EndTime", std::chrono::system_clock::now());
+ xml.Element("ElapsedMinutes",
+ std::chrono::duration_cast<std::chrono::minutes>(
+ std::chrono::steady_clock::now() - elapsed_time_start)
+ .count());
+
+ xml.StartElement("UpdateReturnStatus");
+ if (localModifications) {
+ xml.Content("Update error: "
+ "There are modified or conflicting files in the repository");
+ cmCTestLog(this->CTest, WARNING,
+ " There are modified or conflicting files in the repository"
+ << std::endl);
+ }
+ if (!updated) {
+ xml.Content("Update command failed:\n");
+ xml.Content(vc->GetUpdateCommandLine());
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Update command failed: " << vc->GetUpdateCommandLine()
+ << "\n");
+ }
+ xml.EndElement(); // UpdateReturnStatus
+ xml.EndElement(); // Update
+ xml.EndDocument();
+ return updated && loadedMods ? numUpdated : -1;
+}
+
+int cmCTestUpdateHandler::DetectVCS(const char* dir)
+{
+ std::string sourceDirectory = dir;
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Check directory: " << sourceDirectory << std::endl,
+ this->Quiet);
+ sourceDirectory += "/.svn";
+ if (cmSystemTools::FileExists(sourceDirectory)) {
+ return cmCTestUpdateHandler::e_SVN;
+ }
+ sourceDirectory = cmStrCat(dir, "/CVS");
+ if (cmSystemTools::FileExists(sourceDirectory)) {
+ return cmCTestUpdateHandler::e_CVS;
+ }
+ sourceDirectory = cmStrCat(dir, "/.bzr");
+ if (cmSystemTools::FileExists(sourceDirectory)) {
+ return cmCTestUpdateHandler::e_BZR;
+ }
+ sourceDirectory = cmStrCat(dir, "/.git");
+ if (cmSystemTools::FileExists(sourceDirectory)) {
+ return cmCTestUpdateHandler::e_GIT;
+ }
+ sourceDirectory = cmStrCat(dir, "/.hg");
+ if (cmSystemTools::FileExists(sourceDirectory)) {
+ return cmCTestUpdateHandler::e_HG;
+ }
+ sourceDirectory = cmStrCat(dir, "/.p4");
+ if (cmSystemTools::FileExists(sourceDirectory)) {
+ return cmCTestUpdateHandler::e_P4;
+ }
+ sourceDirectory = cmStrCat(dir, "/.p4config");
+ if (cmSystemTools::FileExists(sourceDirectory)) {
+ return cmCTestUpdateHandler::e_P4;
+ }
+ return cmCTestUpdateHandler::e_UNKNOWN;
+}
+
+bool cmCTestUpdateHandler::SelectVCS()
+{
+ // Get update command
+ this->UpdateCommand = this->CTest->GetCTestConfiguration("UpdateCommand");
+
+ // Detect the VCS managing the source tree.
+ this->UpdateType = this->DetectVCS(this->GetOption("SourceDirectory"));
+ if (this->UpdateType == e_UNKNOWN) {
+ // The source tree does not have a recognized VCS. Check the
+ // configuration value or command name.
+ this->UpdateType = this->DetermineType(
+ this->UpdateCommand.c_str(),
+ this->CTest->GetCTestConfiguration("UpdateType").c_str());
+ }
+
+ // If no update command was specified, lookup one for this VCS tool.
+ if (this->UpdateCommand.empty()) {
+ const char* key = nullptr;
+ switch (this->UpdateType) {
+ case e_CVS:
+ key = "CVSCommand";
+ break;
+ case e_SVN:
+ key = "SVNCommand";
+ break;
+ case e_BZR:
+ key = "BZRCommand";
+ break;
+ case e_GIT:
+ key = "GITCommand";
+ break;
+ case e_HG:
+ key = "HGCommand";
+ break;
+ case e_P4:
+ key = "P4Command";
+ break;
+ default:
+ break;
+ }
+ if (key) {
+ this->UpdateCommand = this->CTest->GetCTestConfiguration(key);
+ }
+ if (this->UpdateCommand.empty()) {
+ std::ostringstream e;
+ e << "Cannot find UpdateCommand ";
+ if (key) {
+ e << "or " << key;
+ }
+ e << " configuration key.";
+ cmCTestLog(this->CTest, ERROR_MESSAGE, e.str() << std::endl);
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/Source/CTest/cmCTestUpdateHandler.h b/Source/CTest/cmCTestUpdateHandler.h
new file mode 100644
index 0000000..25bbb2f
--- /dev/null
+++ b/Source/CTest/cmCTestUpdateHandler.h
@@ -0,0 +1,64 @@
+/* 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 <string>
+#include <utility>
+#include <vector>
+
+#include "cmCTestGenericHandler.h"
+
+/** \class cmCTestUpdateHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ */
+class cmCTestUpdateHandler : public cmCTestGenericHandler
+{
+public:
+ using Superclass = cmCTestGenericHandler;
+
+ /*
+ * The main entry point for this class
+ */
+ int ProcessHandler() override;
+
+ cmCTestUpdateHandler();
+
+ enum
+ {
+ e_UNKNOWN = 0,
+ e_CVS,
+ e_SVN,
+ e_BZR,
+ e_GIT,
+ e_HG,
+ e_P4,
+ e_LAST
+ };
+
+ /**
+ * Initialize handler
+ */
+ void Initialize() override;
+
+private:
+ // Some structures needed for update
+ struct StringPair : public std::pair<std::string, std::string>
+ {
+ };
+ struct UpdateFiles : public std::vector<StringPair>
+ {
+ };
+
+ // Determine the type of version control
+ int DetermineType(const char* cmd, const char* type);
+
+ // The VCS command to update the working tree.
+ std::string UpdateCommand;
+ int UpdateType;
+
+ int DetectVCS(const char* dir);
+ bool SelectVCS();
+};
diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx
new file mode 100644
index 0000000..f86ee0d
--- /dev/null
+++ b/Source/CTest/cmCTestUploadCommand.cxx
@@ -0,0 +1,46 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestUploadCommand.h"
+
+#include <set>
+#include <sstream>
+
+#include <cm/vector>
+#include <cmext/string_view>
+
+#include "cmCTest.h"
+#include "cmCTestUploadHandler.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmSystemTools.h"
+
+void cmCTestUploadCommand::BindArguments()
+{
+ this->Bind("FILES"_s, this->Files);
+ this->Bind("QUIET"_s, this->Quiet);
+ this->Bind("CAPTURE_CMAKE_ERROR"_s, this->CaptureCMakeError);
+}
+
+void cmCTestUploadCommand::CheckArguments(std::vector<std::string> const&)
+{
+ cm::erase_if(this->Files, [this](std::string const& arg) -> bool {
+ if (!cmSystemTools::FileExists(arg)) {
+ std::ostringstream e;
+ e << "File \"" << arg << "\" does not exist. Cannot submit "
+ << "a non-existent file.";
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return true;
+ }
+ return false;
+ });
+}
+
+cmCTestGenericHandler* cmCTestUploadCommand::InitializeHandler()
+{
+ cmCTestUploadHandler* handler = this->CTest->GetUploadHandler();
+ handler->Initialize();
+ handler->SetFiles(
+ std::set<std::string>(this->Files.begin(), this->Files.end()));
+ handler->SetQuiet(this->Quiet);
+ return handler;
+}
diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h
new file mode 100644
index 0000000..fe155f6
--- /dev/null
+++ b/Source/CTest/cmCTestUploadCommand.h
@@ -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. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmCTestHandlerCommand.h"
+#include "cmCommand.h"
+
+class cmCTestGenericHandler;
+
+/** \class cmCTestUpload
+ * \brief Run a ctest script
+ *
+ * cmCTestUploadCommand defines the command to upload result files for
+ * the project.
+ */
+class cmCTestUploadCommand : public cmCTestHandlerCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ auto ni = cm::make_unique<cmCTestUploadCommand>();
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return std::unique_ptr<cmCommand>(std::move(ni));
+ }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ std::string GetName() const override { return "ctest_upload"; }
+
+protected:
+ void BindArguments() override;
+ void CheckArguments(std::vector<std::string> const&) override;
+ cmCTestGenericHandler* InitializeHandler() override;
+
+ std::vector<std::string> Files;
+};
diff --git a/Source/CTest/cmCTestUploadHandler.cxx b/Source/CTest/cmCTestUploadHandler.cxx
new file mode 100644
index 0000000..9d92aad
--- /dev/null
+++ b/Source/CTest/cmCTestUploadHandler.cxx
@@ -0,0 +1,73 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestUploadHandler.h"
+
+#include <ostream>
+#include <string>
+
+#include "cmCTest.h"
+#include "cmGeneratedFileStream.h"
+#include "cmVersion.h"
+#include "cmXMLWriter.h"
+
+cmCTestUploadHandler::cmCTestUploadHandler()
+{
+ this->Initialize();
+}
+
+void cmCTestUploadHandler::Initialize()
+{
+ this->Superclass::Initialize();
+ this->Files.clear();
+}
+
+void cmCTestUploadHandler::SetFiles(std::set<std::string> const& files)
+{
+ this->Files = files;
+}
+
+int cmCTestUploadHandler::ProcessHandler()
+{
+ cmGeneratedFileStream ofs;
+ if (!this->CTest->OpenOutputFile(this->CTest->GetCurrentTag(), "Upload.xml",
+ ofs)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open Upload.xml file" << std::endl);
+ return -1;
+ }
+ std::string buildname =
+ cmCTest::SafeBuildIdField(this->CTest->GetCTestConfiguration("BuildName"));
+
+ cmXMLWriter xml(ofs);
+ xml.StartDocument();
+ xml.ProcessingInstruction("xml-stylesheet",
+ "type=\"text/xsl\" "
+ "href=\"Dart/Source/Server/XSL/Build.xsl "
+ "<file:///Dart/Source/Server/XSL/Build.xsl> \"");
+ xml.StartElement("Site");
+ xml.Attribute("BuildName", buildname);
+ xml.Attribute("BuildStamp",
+ this->CTest->GetCurrentTag() + "-" +
+ this->CTest->GetTestModelString());
+ xml.Attribute("Name", this->CTest->GetCTestConfiguration("Site"));
+ xml.Attribute("Generator",
+ std::string("ctest-") + cmVersion::GetCMakeVersion());
+ this->CTest->AddSiteProperties(xml);
+ xml.StartElement("Upload");
+
+ for (std::string const& file : this->Files) {
+ cmCTestOptionalLog(this->CTest, OUTPUT,
+ "\tUpload file: " << file << std::endl, this->Quiet);
+ xml.StartElement("File");
+ xml.Attribute("filename", file);
+ xml.StartElement("Content");
+ xml.Attribute("encoding", "base64");
+ xml.Content(this->CTest->Base64EncodeFile(file));
+ xml.EndElement(); // Content
+ xml.EndElement(); // File
+ }
+ xml.EndElement(); // Upload
+ xml.EndElement(); // Site
+ xml.EndDocument();
+ return 0;
+}
diff --git a/Source/CTest/cmCTestUploadHandler.h b/Source/CTest/cmCTestUploadHandler.h
new file mode 100644
index 0000000..55d21c1
--- /dev/null
+++ b/Source/CTest/cmCTestUploadHandler.h
@@ -0,0 +1,37 @@
+/* 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 "cmCTestGenericHandler.h"
+
+/** \class cmCTestUploadHandler
+ * \brief Helper class for CTest
+ *
+ * Submit arbitrary files
+ *
+ */
+class cmCTestUploadHandler : public cmCTestGenericHandler
+{
+public:
+ using Superclass = cmCTestGenericHandler;
+
+ cmCTestUploadHandler();
+
+ /*
+ * The main entry point for this class
+ */
+ int ProcessHandler() override;
+
+ void Initialize() override;
+
+ /** Specify a set of files to submit. */
+ void SetFiles(std::set<std::string> const& files);
+
+private:
+ std::set<std::string> Files;
+};
diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx
new file mode 100644
index 0000000..452d714
--- /dev/null
+++ b/Source/CTest/cmCTestVC.cxx
@@ -0,0 +1,228 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestVC.h"
+
+#include <cstdio>
+#include <ctime>
+#include <sstream>
+#include <vector>
+
+#include "cmsys/Process.h"
+
+#include "cmCTest.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+
+cmCTestVC::cmCTestVC(cmCTest* ct, std::ostream& log)
+ : CTest(ct)
+ , Log(log)
+{
+ this->PathCount[PathUpdated] = 0;
+ this->PathCount[PathModified] = 0;
+ this->PathCount[PathConflicting] = 0;
+ this->Unknown.Date = "Unknown";
+ this->Unknown.Author = "Unknown";
+ this->Unknown.Rev = "Unknown";
+}
+
+cmCTestVC::~cmCTestVC() = default;
+
+void cmCTestVC::SetCommandLineTool(std::string const& tool)
+{
+ this->CommandLineTool = tool;
+}
+
+void cmCTestVC::SetSourceDirectory(std::string const& dir)
+{
+ this->SourceDirectory = dir;
+}
+
+bool cmCTestVC::InitialCheckout(const std::string& command)
+{
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " First perform the initial checkout: " << command << "\n");
+
+ // Make the parent directory in which to perform the checkout.
+ std::string parent = cmSystemTools::GetFilenamePath(this->SourceDirectory);
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Perform checkout in directory: " << parent << "\n");
+ if (!cmSystemTools::MakeDirectory(parent)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create directory: " << parent << std::endl);
+ return false;
+ }
+
+ // Construct the initial checkout command line.
+ std::vector<std::string> args = cmSystemTools::ParseArguments(command);
+ std::vector<char const*> vc_co;
+ vc_co.reserve(args.size() + 1);
+ for (std::string const& arg : args) {
+ vc_co.push_back(arg.c_str());
+ }
+ vc_co.push_back(nullptr);
+
+ // Run the initial checkout command and log its output.
+ this->Log << "--- Begin Initial Checkout ---\n";
+ OutputLogger out(this->Log, "co-out> ");
+ OutputLogger err(this->Log, "co-err> ");
+ bool result = this->RunChild(&vc_co[0], &out, &err, parent.c_str());
+ this->Log << "--- End Initial Checkout ---\n";
+ if (!result) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Initial checkout failed!" << std::endl);
+ }
+ return result;
+}
+
+bool cmCTestVC::RunChild(char const* const* cmd, OutputParser* out,
+ OutputParser* err, const char* workDir,
+ Encoding encoding)
+{
+ this->Log << cmCTestVC::ComputeCommandLine(cmd) << "\n";
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, cmd);
+ workDir = workDir ? workDir : this->SourceDirectory.c_str();
+ cmsysProcess_SetWorkingDirectory(cp, workDir);
+ cmCTestVC::RunProcess(cp, out, err, encoding);
+ int result = cmsysProcess_GetExitValue(cp);
+ cmsysProcess_Delete(cp);
+ return result == 0;
+}
+
+std::string cmCTestVC::ComputeCommandLine(char const* const* cmd)
+{
+ std::ostringstream line;
+ const char* sep = "";
+ for (const char* const* arg = cmd; *arg; ++arg) {
+ line << sep << "\"" << *arg << "\"";
+ sep = " ";
+ }
+ return line.str();
+}
+
+bool cmCTestVC::RunUpdateCommand(char const* const* cmd, OutputParser* out,
+ OutputParser* err, Encoding encoding)
+{
+ // Report the command line.
+ this->UpdateCommandLine = this->ComputeCommandLine(cmd);
+ if (this->CTest->GetShowOnly()) {
+ this->Log << this->UpdateCommandLine << "\n";
+ return true;
+ }
+
+ // Run the command.
+ return this->RunChild(cmd, out, err, nullptr, encoding);
+}
+
+std::string cmCTestVC::GetNightlyTime()
+{
+ // Get the nightly start time corresponding to the current dau.
+ struct tm* t = this->CTest->GetNightlyTime(
+ this->CTest->GetCTestConfiguration("NightlyStartTime"),
+ this->CTest->GetTomorrowTag());
+ char current_time[1024];
+ sprintf(current_time, "%04d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900,
+ t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+ return std::string(current_time);
+}
+
+void cmCTestVC::Cleanup()
+{
+ this->Log << "--- Begin Cleanup ---\n";
+ this->CleanupImpl();
+ this->Log << "--- End Cleanup ---\n";
+}
+
+void cmCTestVC::CleanupImpl()
+{
+ // We do no cleanup by default.
+}
+
+bool cmCTestVC::Update()
+{
+ bool result = true;
+
+ // Use the explicitly specified version.
+ std::string versionOverride =
+ this->CTest->GetCTestConfiguration("UpdateVersionOverride");
+ if (!versionOverride.empty()) {
+ this->SetNewRevision(versionOverride);
+ return true;
+ }
+
+ // if update version only is on then do not actually update,
+ // just note the current version and finish
+ if (!cmIsOn(this->CTest->GetCTestConfiguration("UpdateVersionOnly"))) {
+ result = this->NoteOldRevision() && result;
+ this->Log << "--- Begin Update ---\n";
+ result = this->UpdateImpl() && result;
+ this->Log << "--- End Update ---\n";
+ }
+ result = this->NoteNewRevision() && result;
+ return result;
+}
+
+bool cmCTestVC::NoteOldRevision()
+{
+ // We do nothing by default.
+ return true;
+}
+
+bool cmCTestVC::NoteNewRevision()
+{
+ // We do nothing by default.
+ return true;
+}
+
+void cmCTestVC::SetNewRevision(std::string const& /*unused*/)
+{
+ // We do nothing by default.
+}
+
+bool cmCTestVC::UpdateImpl()
+{
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "* Unknown VCS tool, not updating!" << std::endl);
+ return true;
+}
+
+bool cmCTestVC::WriteXML(cmXMLWriter& xml)
+{
+ this->Log << "--- Begin Revisions ---\n";
+ bool result = this->WriteXMLUpdates(xml);
+ this->Log << "--- End Revisions ---\n";
+ return result;
+}
+
+bool cmCTestVC::WriteXMLUpdates(cmXMLWriter& /*unused*/)
+{
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "* CTest cannot extract updates for this VCS tool.\n");
+ return true;
+}
+
+void cmCTestVC::WriteXMLEntry(cmXMLWriter& xml, std::string const& path,
+ std::string const& name, std::string const& full,
+ File const& f)
+{
+ static const char* desc[3] = { "Updated", "Modified", "Conflicting" };
+ Revision const& rev = f.Rev ? *f.Rev : this->Unknown;
+ std::string prior = f.PriorRev ? f.PriorRev->Rev : std::string("Unknown");
+ xml.StartElement(desc[f.Status]);
+ xml.Element("File", name);
+ xml.Element("Directory", path);
+ xml.Element("FullName", full);
+ xml.Element("CheckinDate", rev.Date);
+ xml.Element("Author", rev.Author);
+ xml.Element("Email", rev.EMail);
+ xml.Element("Committer", rev.Committer);
+ xml.Element("CommitterEmail", rev.CommitterEMail);
+ xml.Element("CommitDate", rev.CommitDate);
+ xml.Element("Log", rev.Log);
+ xml.Element("Revision", rev.Rev);
+ xml.Element("PriorRevision", prior);
+ xml.EndElement();
+ ++this->PathCount[f.Status];
+}
diff --git a/Source/CTest/cmCTestVC.h b/Source/CTest/cmCTestVC.h
new file mode 100644
index 0000000..9bd7229
--- /dev/null
+++ b/Source/CTest/cmCTestVC.h
@@ -0,0 +1,151 @@
+/* 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 <iosfwd>
+#include <string>
+
+#include "cmProcessOutput.h"
+#include "cmProcessTools.h"
+
+class cmCTest;
+class cmXMLWriter;
+
+/** \class cmCTestVC
+ * \brief Base class for version control system handlers
+ *
+ */
+class cmCTestVC : public cmProcessTools
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestVC(cmCTest* ctest, std::ostream& log);
+
+ virtual ~cmCTestVC();
+
+ /** Command line tool to invoke. */
+ void SetCommandLineTool(std::string const& tool);
+
+ /** Top-level source directory. */
+ void SetSourceDirectory(std::string const& dir);
+
+ /** Get the date/time specification for the current nightly start time. */
+ std::string GetNightlyTime();
+
+ /** Prepare the work tree. */
+ bool InitialCheckout(const std::string& command);
+
+ /** Perform cleanup operations on the work tree. */
+ void Cleanup();
+
+ /** Update the working tree to the new revision. */
+ bool Update();
+
+ /** Get the command line used by the Update method. */
+ std::string const& GetUpdateCommandLine() const
+ {
+ return this->UpdateCommandLine;
+ }
+
+ /** Write Update.xml entries for the updates found. */
+ bool WriteXML(cmXMLWriter& xml);
+
+ /** Enumerate non-trivial working tree states during update. */
+ enum PathStatus
+ {
+ PathUpdated,
+ PathModified,
+ PathConflicting
+ };
+
+ /** Get the number of working tree paths in each state after update. */
+ int GetPathCount(PathStatus s) const { return this->PathCount[s]; }
+
+protected:
+ // Internal API to be implemented by subclasses.
+ virtual void CleanupImpl();
+ virtual bool NoteOldRevision();
+ virtual bool UpdateImpl();
+ virtual bool NoteNewRevision();
+ virtual void SetNewRevision(std::string const& revision);
+ virtual bool WriteXMLUpdates(cmXMLWriter& xml);
+
+#if defined(__SUNPRO_CC) && __SUNPRO_CC <= 0x510
+ // Sun CC 5.1 needs help to allow cmCTestSVN::Revision to see this
+public:
+#endif
+ /** Basic information about one revision of a tree or file. */
+ struct Revision
+ {
+ std::string Rev;
+ std::string Date;
+ std::string Author;
+ std::string EMail;
+ std::string Committer;
+ std::string CommitterEMail;
+ std::string CommitDate;
+ std::string Log;
+ };
+
+protected:
+ friend struct File;
+
+ /** Represent change to one file. */
+ struct File
+ {
+ PathStatus Status;
+ Revision const* Rev;
+ Revision const* PriorRev;
+ File()
+ : Status(PathUpdated)
+ , Rev(nullptr)
+ , PriorRev(nullptr)
+ {
+ }
+ File(PathStatus status, Revision const* rev, Revision const* priorRev)
+ : Status(status)
+ , Rev(rev)
+ , PriorRev(priorRev)
+ {
+ }
+ };
+
+ /** Convert a list of arguments to a human-readable command line. */
+ static std::string ComputeCommandLine(char const* const* cmd);
+
+ /** Run a command line and send output to given parsers. */
+ bool RunChild(char const* const* cmd, OutputParser* out, OutputParser* err,
+ const char* workDir = nullptr,
+ Encoding encoding = cmProcessOutput::Auto);
+
+ /** Run VC update command line and send output to given parsers. */
+ bool RunUpdateCommand(char const* const* cmd, OutputParser* out,
+ OutputParser* err = nullptr,
+ Encoding encoding = cmProcessOutput::Auto);
+
+ /** Write xml element for one file. */
+ void WriteXMLEntry(cmXMLWriter& xml, std::string const& path,
+ std::string const& name, std::string const& full,
+ File const& f);
+
+ // Instance of cmCTest running the script.
+ cmCTest* CTest;
+
+ // A stream to which we write log information.
+ std::ostream& Log;
+
+ // Basic information about the working tree.
+ std::string CommandLineTool;
+ std::string SourceDirectory;
+
+ // Record update command info.
+ std::string UpdateCommandLine;
+
+ // Placeholder for unknown revisions.
+ Revision Unknown;
+
+ // Count paths reported with each PathStatus value.
+ int PathCount[3];
+};
diff --git a/Source/CTest/cmParseBlanketJSCoverage.cxx b/Source/CTest/cmParseBlanketJSCoverage.cxx
new file mode 100644
index 0000000..3a6651f
--- /dev/null
+++ b/Source/CTest/cmParseBlanketJSCoverage.cxx
@@ -0,0 +1,139 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmParseBlanketJSCoverage.h"
+
+#include <cstdio>
+#include <cstdlib>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmSystemTools.h"
+
+class cmParseBlanketJSCoverage::JSONParser
+{
+public:
+ using FileLinesType =
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector;
+ JSONParser(cmCTestCoverageHandlerContainer& cont)
+ : Coverage(cont)
+ {
+ }
+
+ virtual ~JSONParser() = default;
+
+ std::string getValue(std::string const& line, int type)
+ {
+ size_t begIndex;
+ size_t endIndex;
+ endIndex = line.rfind(',');
+ begIndex = line.find_first_of(':');
+ if (type == 0) {
+ // A unique substring to remove the extra characters
+ // around the files name in the JSON (extra " and ,)
+ std::string foundFileName =
+ line.substr(begIndex + 3, endIndex - (begIndex + 4));
+ return foundFileName;
+ }
+ return line.substr(begIndex);
+ }
+ bool ParseFile(std::string const& file)
+ {
+ FileLinesType localCoverageVector;
+ std::string filename;
+ bool foundFile = false;
+ bool inSource = false;
+ std::string covResult;
+ std::string line;
+
+ cmsys::ifstream in(file.c_str());
+ if (!in) {
+ return false;
+ }
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ if (line.find("filename") != std::string::npos) {
+ if (foundFile) {
+ /*
+ * Upon finding a second file name, generate a
+ * vector within the total coverage to capture the
+ * information in the local vector
+ */
+ FileLinesType& CoverageVector =
+ this->Coverage.TotalCoverage[filename];
+ CoverageVector = localCoverageVector;
+ localCoverageVector.clear();
+ }
+ foundFile = true;
+ inSource = false;
+ filename = this->getValue(line, 0);
+ } else if ((line.find("coverage") != std::string::npos) && foundFile &&
+ inSource) {
+ /*
+ * two types of "coverage" in the JSON structure
+ *
+ * The coverage result over the file or set of files
+ * and the coverage for each individual line
+ *
+ * FoundFile and foundSource ensure that
+ * only the value of the line coverage is captured
+ */
+ std::string result = this->getValue(line, 1);
+ result = result.substr(2);
+ if (result == "\"\"") {
+ // Empty quotation marks indicate that the
+ // line is not executable
+ localCoverageVector.push_back(-1);
+ } else {
+ // Else, it contains the number of time executed
+ localCoverageVector.push_back(atoi(result.c_str()));
+ }
+ } else if (line.find("source") != std::string::npos) {
+ inSource = true;
+ }
+ }
+
+ // On exit, capture end of last file covered.
+ FileLinesType& CoverageVector = this->Coverage.TotalCoverage[filename];
+ CoverageVector = localCoverageVector;
+ localCoverageVector.clear();
+ return true;
+ }
+
+private:
+ cmCTestCoverageHandlerContainer& Coverage;
+};
+
+cmParseBlanketJSCoverage::cmParseBlanketJSCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+bool cmParseBlanketJSCoverage::LoadCoverageData(
+ std::vector<std::string> const& files)
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found " << files.size() << " Files" << std::endl,
+ this->Coverage.Quiet);
+ for (std::string const& file : files) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading JSON File " << file << std::endl,
+ this->Coverage.Quiet);
+
+ if (!this->ReadJSONFile(file)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmParseBlanketJSCoverage::ReadJSONFile(std::string const& file)
+{
+ cmParseBlanketJSCoverage::JSONParser parser(this->Coverage);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Parsing " << file << std::endl, this->Coverage.Quiet);
+ parser.ParseFile(file);
+ return true;
+}
diff --git a/Source/CTest/cmParseBlanketJSCoverage.h b/Source/CTest/cmParseBlanketJSCoverage.h
new file mode 100644
index 0000000..e107454
--- /dev/null
+++ b/Source/CTest/cmParseBlanketJSCoverage.h
@@ -0,0 +1,40 @@
+/* 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 <string>
+#include <vector>
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
+
+/** \class cmParseBlanketJSCoverage
+ * \brief Parse BlanketJS coverage information
+ *
+ * This class is used to parse BlanketJS(Pascal) coverage information
+ * generated by the Blanket.js library when used in conjunction with the
+ * test runner mocha.js, which is used to write out the JSON format.
+ *
+ * Blanket.js:
+ * http://blanketjs.org/
+ *
+ * Mocha.js
+ * http://visionmedia.github.io/mocha/
+ */
+class cmParseBlanketJSCoverage
+{
+public:
+ cmParseBlanketJSCoverage(cmCTestCoverageHandlerContainer& cont,
+ cmCTest* ctest);
+ bool LoadCoverageData(std::vector<std::string> const& files);
+ // Read the JSON output
+ bool ReadJSONFile(std::string const& file);
+
+protected:
+ class JSONParser;
+
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+};
diff --git a/Source/CTest/cmParseCacheCoverage.cxx b/Source/CTest/cmParseCacheCoverage.cxx
new file mode 100644
index 0000000..84d7de0
--- /dev/null
+++ b/Source/CTest/cmParseCacheCoverage.cxx
@@ -0,0 +1,178 @@
+#include "cmParseCacheCoverage.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmParseCacheCoverage::cmParseCacheCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : cmParseMumpsCoverage(cont, ctest)
+{
+}
+
+bool cmParseCacheCoverage::LoadCoverageData(std::string const& d)
+{
+ // load all the .mcov files in the specified directory
+ cmsys::Directory dir;
+ if (!dir.Load(d)) {
+ return false;
+ }
+ size_t numf;
+ unsigned int i;
+ numf = dir.GetNumberOfFiles();
+ for (i = 0; i < numf; i++) {
+ std::string file = dir.GetFile(i);
+ if (file != "." && file != ".." && !cmSystemTools::FileIsDirectory(file)) {
+ std::string path = cmStrCat(d, '/', file);
+ if (cmSystemTools::GetFilenameLastExtension(path) == ".cmcov") {
+ if (!this->ReadCMCovFile(path.c_str())) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+// not currently used, but leave it in case we want it in the future
+void cmParseCacheCoverage::RemoveUnCoveredFiles()
+{
+ // loop over the coverage data computed and remove all files
+ // that only have -1 or 0 for the lines.
+ auto ci = this->Coverage.TotalCoverage.begin();
+ while (ci != this->Coverage.TotalCoverage.end()) {
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& v = ci->second;
+ bool nothing = true;
+ for (int i : v) {
+ if (i > 0) {
+ nothing = false;
+ break;
+ }
+ }
+ if (nothing) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "No coverage found in: " << ci->first << std::endl,
+ this->Coverage.Quiet);
+ this->Coverage.TotalCoverage.erase(ci++);
+ } else {
+ ++ci;
+ }
+ }
+}
+
+bool cmParseCacheCoverage::ReadCMCovFile(const char* file)
+{
+ cmsys::ifstream in(file);
+ if (!in) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Can not open : " << file << "\n");
+ return false;
+ }
+ std::string line;
+ if (!cmSystemTools::GetLineFromStream(in, line)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Empty file : " << file
+ << " referenced in this line of cmcov data:\n"
+ "["
+ << line << "]\n");
+ return false;
+ }
+ std::vector<std::string> separateLine =
+ cmSystemTools::SplitString(line, ',');
+ if (separateLine.size() != 4 || separateLine[0] != "Routine" ||
+ separateLine[1] != "Line" || separateLine[2] != "RtnLine" ||
+ separateLine[3] != "Code") {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Bad first line of cmcov file : " << file
+ << " line:\n"
+ "["
+ << line << "]\n");
+ }
+ std::string routine;
+ std::string filepath;
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ // parse the comma separated line
+ separateLine = cmSystemTools::SplitString(line, ',');
+ // might have more because code could have a quoted , in it
+ // but we only care about the first 3 args anyway
+ if (separateLine.size() < 4) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Bad line of cmcov file expected at least 4 found: "
+ << separateLine.size() << " " << file
+ << " line:\n"
+ "["
+ << line << "]\n");
+ for (std::string::size_type i = 0; i < separateLine.size(); ++i) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "" << separateLine[1] << " ");
+ }
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "\n");
+ return false;
+ }
+ // if we do not have a routine yet, then it should be
+ // the first argument in the vector
+ if (routine.empty()) {
+ routine = separateLine[0];
+ // Find the full path to the file
+ if (!this->FindMumpsFile(routine, filepath)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Could not find mumps file for routine: " << routine
+ << "\n");
+ filepath.clear();
+ continue; // move to next line
+ }
+ }
+ // if we have a routine name, check for end of routine
+ else {
+ // Totals in arg 0 marks the end of a routine
+ if (cmHasLiteralPrefix(separateLine[0], "Totals")) {
+ routine.clear(); // at the end of this routine
+ filepath.clear();
+ continue; // move to next line
+ }
+ }
+ // if the file path was not found for the routine
+ // move to next line. We should have already warned
+ // after the call to FindMumpsFile that we did not find
+ // it, so don't report again to cut down on output
+ if (filepath.empty()) {
+ continue;
+ }
+ // now we are ready to set the coverage from the line of data
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector =
+ this->Coverage.TotalCoverage[filepath];
+ std::string::size_type linenumber = atoi(separateLine[1].c_str()) - 1;
+ int count = atoi(separateLine[2].c_str());
+ if (linenumber > coverageVector.size()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Parse error line is greater than number of lines in file: "
+ << linenumber << " " << filepath << "\n");
+ continue; // skip setting count to avoid crash
+ }
+ // now add to count for linenumber
+ // for some reason the cache coverage adds extra lines to the
+ // end of the file in some cases. Since they do not exist, we will
+ // mark them as non executable
+ while (linenumber >= coverageVector.size()) {
+ coverageVector.push_back(-1);
+ }
+ // Accounts for lines that were previously marked
+ // as non-executable code (-1). if the parser comes back with
+ // a non-zero count, increase the count by 1 to push the line
+ // into the executable code set in addition to the count found.
+ if (coverageVector[linenumber] == -1 && count > 0) {
+ coverageVector[linenumber] += count + 1;
+ } else {
+ coverageVector[linenumber] += count;
+ }
+ }
+ return true;
+}
diff --git a/Source/CTest/cmParseCacheCoverage.h b/Source/CTest/cmParseCacheCoverage.h
new file mode 100644
index 0000000..523f83b
--- /dev/null
+++ b/Source/CTest/cmParseCacheCoverage.h
@@ -0,0 +1,32 @@
+/* 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 <string>
+
+#include "cmParseMumpsCoverage.h"
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
+
+/** \class cmParseCacheCoverage
+ * \brief Parse Cache coverage information
+ *
+ * This class is used to parse Cache coverage information for
+ * mumps.
+ */
+class cmParseCacheCoverage : public cmParseMumpsCoverage
+{
+public:
+ cmParseCacheCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+
+protected:
+ // implement virtual from parent
+ bool LoadCoverageData(std::string const& dir) override;
+ // remove files with no coverage
+ void RemoveUnCoveredFiles();
+ // Read a single mcov file
+ bool ReadCMCovFile(const char* f);
+};
diff --git a/Source/CTest/cmParseCoberturaCoverage.cxx b/Source/CTest/cmParseCoberturaCoverage.cxx
new file mode 100644
index 0000000..9311769
--- /dev/null
+++ b/Source/CTest/cmParseCoberturaCoverage.cxx
@@ -0,0 +1,165 @@
+#include "cmParseCoberturaCoverage.h"
+
+#include <cstdlib>
+#include <cstring>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+
+class cmParseCoberturaCoverage::XMLParser : public cmXMLParser
+{
+public:
+ XMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont)
+ : FilePaths{ cont.SourceDir, cont.BinaryDir }
+ , CTest(ctest)
+ , Coverage(cont)
+ {
+ }
+
+protected:
+ void EndElement(const std::string& name) override
+ {
+ if (name == "source") {
+ this->InSource = false;
+ } else if (name == "sources") {
+ this->InSources = false;
+ } else if (name == "class") {
+ this->SkipThisClass = false;
+ }
+ }
+
+ void CharacterDataHandler(const char* data, int length) override
+ {
+ std::string tmp;
+ tmp.insert(0, data, length);
+ if (this->InSources && this->InSource) {
+ this->FilePaths.push_back(tmp);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Adding Source: " << tmp << std::endl,
+ this->Coverage.Quiet);
+ }
+ }
+
+ void StartElement(const std::string& name, const char** atts) override
+ {
+ std::string FoundSource;
+ std::string finalpath;
+ if (name == "source") {
+ this->InSource = true;
+ } else if (name == "sources") {
+ this->InSources = true;
+ } else if (name == "class") {
+ int tagCount = 0;
+ while (true) {
+ if (strcmp(atts[tagCount], "filename") == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading file: " << atts[tagCount + 1]
+ << std::endl,
+ this->Coverage.Quiet);
+ std::string filename = atts[tagCount + 1];
+ this->CurFileName.clear();
+
+ // Check if this is an absolute path that falls within our
+ // source or binary directories.
+ for (std::string const& filePath : this->FilePaths) {
+ if (cmHasPrefix(filename, filePath)) {
+ this->CurFileName = filename;
+ break;
+ }
+ }
+
+ if (this->CurFileName.empty()) {
+ // Check if this is a path that is relative to our source or
+ // binary directories.
+ for (std::string const& filePath : this->FilePaths) {
+ finalpath = cmStrCat(filePath, "/", filename);
+ if (cmSystemTools::FileExists(finalpath)) {
+ this->CurFileName = finalpath;
+ break;
+ }
+ }
+ }
+
+ cmsys::ifstream fin(this->CurFileName.c_str());
+ if (this->CurFileName.empty() || !fin) {
+ this->CurFileName =
+ cmStrCat(this->Coverage.BinaryDir, "/", atts[tagCount + 1]);
+ fin.open(this->CurFileName.c_str());
+ if (!fin) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Skipping system file " << filename
+ << std::endl,
+ this->Coverage.Quiet);
+
+ this->SkipThisClass = true;
+ break;
+ }
+ }
+ std::string line;
+ FileLinesType& curFileLines =
+ this->Coverage.TotalCoverage[this->CurFileName];
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ curFileLines.push_back(-1);
+ }
+
+ break;
+ }
+ ++tagCount;
+ }
+ } else if (name == "line") {
+ int tagCount = 0;
+ int curNumber = -1;
+ int curHits = -1;
+ while (true) {
+ if (this->SkipThisClass) {
+ break;
+ }
+ if (strcmp(atts[tagCount], "hits") == 0) {
+ curHits = atoi(atts[tagCount + 1]);
+ } else if (strcmp(atts[tagCount], "number") == 0) {
+ curNumber = atoi(atts[tagCount + 1]);
+ }
+
+ if (curHits > -1 && curNumber > 0) {
+ FileLinesType& curFileLines =
+ this->Coverage.TotalCoverage[this->CurFileName];
+ {
+ curFileLines[curNumber - 1] = curHits;
+ }
+ break;
+ }
+ ++tagCount;
+ }
+ }
+ }
+
+private:
+ bool InSources = false;
+ bool InSource = false;
+ bool SkipThisClass = false;
+ std::vector<std::string> FilePaths;
+ using FileLinesType =
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector;
+ cmCTest* CTest;
+ cmCTestCoverageHandlerContainer& Coverage;
+ std::string CurFileName;
+};
+
+cmParseCoberturaCoverage::cmParseCoberturaCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+bool cmParseCoberturaCoverage::ReadCoverageXML(const char* xmlFile)
+{
+ cmParseCoberturaCoverage::XMLParser parser(this->CTest, this->Coverage);
+ parser.ParseFile(xmlFile);
+ return true;
+}
diff --git a/Source/CTest/cmParseCoberturaCoverage.h b/Source/CTest/cmParseCoberturaCoverage.h
new file mode 100644
index 0000000..0340433
--- /dev/null
+++ b/Source/CTest/cmParseCoberturaCoverage.h
@@ -0,0 +1,42 @@
+/* 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 <string>
+#include <vector>
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
+
+/** \class cmParsePythonCoverage
+ * \brief Parse coverage.py Python coverage information
+ *
+ * This class is used to parse the output of the coverage.py tool that
+ * is currently maintained by Ned Batchelder. That tool has a command
+ * that produces xml output in the format typically output by the common
+ * Java-based Cobertura coverage application. This helper class parses
+ * that XML file to fill the coverage-handler container.
+ */
+class cmParseCoberturaCoverage
+{
+public:
+ //! Create the coverage parser by passing in the coverage handler
+ //! container and the cmCTest object
+ cmParseCoberturaCoverage(cmCTestCoverageHandlerContainer& cont,
+ cmCTest* ctest);
+
+ bool inSources;
+ bool inSource;
+ std::vector<std::string> filepaths;
+ //! Read the XML produced by running `coverage xml`
+ bool ReadCoverageXML(const char* xmlFile);
+
+private:
+ class XMLParser;
+
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+ std::string CurFileName;
+};
diff --git a/Source/CTest/cmParseDelphiCoverage.cxx b/Source/CTest/cmParseDelphiCoverage.cxx
new file mode 100644
index 0000000..640873e
--- /dev/null
+++ b/Source/CTest/cmParseDelphiCoverage.cxx
@@ -0,0 +1,232 @@
+#include "cmParseDelphiCoverage.h"
+
+#include <cstdio>
+#include <cstdlib>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmSystemTools.h"
+
+class cmParseDelphiCoverage::HTMLParser
+{
+public:
+ using FileLinesType =
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector;
+ HTMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont)
+ : CTest(ctest)
+ , Coverage(cont)
+ {
+ }
+
+ virtual ~HTMLParser() = default;
+
+ bool initializeDelphiFile(
+ std::string const& filename,
+ cmParseDelphiCoverage::HTMLParser::FileLinesType& coverageVector)
+ {
+ std::string line;
+ size_t comPos;
+ size_t semiPos;
+ bool blockComFlag = false;
+ bool lineComFlag = false;
+ std::vector<std::string> beginSet;
+ cmsys::ifstream in(filename.c_str());
+ if (!in) {
+ return false;
+ }
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ lineComFlag = false;
+ // Unique cases found in lines.
+ size_t beginPos = line.find("begin");
+
+ // Check that the begin is the first non-space string on the line
+ if ((beginPos == line.find_first_not_of(' ')) &&
+ beginPos != std::string::npos) {
+ beginSet.emplace_back("begin");
+ coverageVector.push_back(-1);
+ continue;
+ }
+ if (line.find('{') != std::string::npos) {
+ blockComFlag = true;
+ } else if (line.find('}') != std::string::npos) {
+ blockComFlag = false;
+ coverageVector.push_back(-1);
+ continue;
+ } else if ((line.find("end;") != std::string::npos) &&
+ !beginSet.empty()) {
+ beginSet.pop_back();
+ coverageVector.push_back(-1);
+ continue;
+ }
+
+ // This checks for comments after lines of code, finding the
+ // comment symbol after the ending semicolon.
+ comPos = line.find("//");
+ if (comPos != std::string::npos) {
+ semiPos = line.find(';');
+ if (comPos < semiPos) {
+ lineComFlag = true;
+ }
+ }
+ // Based up what was found, add a line to the coverageVector
+ if (!beginSet.empty() && !line.empty() && !blockComFlag &&
+ !lineComFlag) {
+ coverageVector.push_back(0);
+ } else {
+ coverageVector.push_back(-1);
+ }
+ }
+ return true;
+ }
+ bool ParseFile(const char* file)
+ {
+ std::string line = file;
+ std::string lineresult;
+ std::string lastroutine;
+ std::string filename;
+ std::string filelineoffset;
+ size_t afterLineNum = 0;
+ size_t lastoffset = 0;
+ size_t endcovpos = 0;
+ size_t endnamepos = 0;
+ size_t pos = 0;
+
+ /*
+ * This first 'while' section goes through the found HTML
+ * file name and attempts to capture the source file name
+ * which is set as part of the HTML file name: the name of
+ * the file is found in parenthesis '()'
+ *
+ * See test HTML file name: UTCovTest(UTCovTest.pas).html.
+ *
+ * Find the text inside each pair of parenthesis and check
+ * to see if it ends in '.pas'. If it can't be found,
+ * exit the function.
+ */
+ while (true) {
+ lastoffset = line.find('(', pos);
+ if (lastoffset == std::string::npos) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ endnamepos << "File not found " << lastoffset
+ << std::endl,
+ this->Coverage.Quiet);
+ return false;
+ }
+ endnamepos = line.find(')', lastoffset);
+ filename = line.substr(lastoffset + 1, (endnamepos - 1) - lastoffset);
+ if (filename.find(".pas") != std::string::npos) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Coverage found for file: " << filename
+ << std::endl,
+ this->Coverage.Quiet);
+ break;
+ }
+ pos = lastoffset + 1;
+ }
+ /*
+ * Glob through the source directory for the
+ * file found above
+ */
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOff();
+ std::string glob = this->Coverage.SourceDir + "*/" + filename;
+ gl.FindFiles(glob);
+ std::vector<std::string> const& files = gl.GetFiles();
+ if (files.empty()) {
+ /*
+ * If that doesn't find any matching files
+ * return a failure.
+ */
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Unable to find file matching" << glob << std::endl,
+ this->Coverage.Quiet);
+ return false;
+ }
+ FileLinesType& coverageVector = this->Coverage.TotalCoverage[files[0]];
+
+ /*
+ * Initialize the file to have all code between 'begin' and
+ * 'end' tags marked as executable
+ */
+
+ this->initializeDelphiFile(files[0], coverageVector);
+
+ cmsys::ifstream in(file);
+ if (!in) {
+ return false;
+ }
+
+ /*
+ * Now read the HTML file, looking for the lines that have an
+ * "inline" in it. Then parse out the "class" value of that
+ * line to determine if the line is executed or not.
+ *
+ * Sample HTML line:
+ *
+ * <tr class="covered"><td>47</td><td><pre style="display:inline;">
+ * &nbsp;CheckEquals(1,2-1);</pre></td></tr>
+ *
+ */
+
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ if (line.find("inline") == std::string::npos) {
+ continue;
+ }
+
+ lastoffset = line.find("class=");
+ endcovpos = line.find('>', lastoffset);
+ lineresult = line.substr(lastoffset + 7, (endcovpos - 8) - lastoffset);
+
+ if (lineresult == "covered") {
+ afterLineNum = line.find('<', endcovpos + 5);
+ filelineoffset =
+ line.substr(endcovpos + 5, afterLineNum - (endcovpos + 5));
+ coverageVector[atoi(filelineoffset.c_str()) - 1] = 1;
+ }
+ }
+ return true;
+ }
+
+private:
+ cmCTest* CTest;
+ cmCTestCoverageHandlerContainer& Coverage;
+};
+
+cmParseDelphiCoverage::cmParseDelphiCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+bool cmParseDelphiCoverage::LoadCoverageData(
+ std::vector<std::string> const& files)
+{
+ size_t i;
+ std::string path;
+ size_t numf = files.size();
+ for (i = 0; i < numf; i++) {
+ path = files[i];
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading HTML File " << path << std::endl,
+ this->Coverage.Quiet);
+ if (cmSystemTools::GetFilenameLastExtension(path) == ".html") {
+ if (!this->ReadDelphiHTML(path.c_str())) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool cmParseDelphiCoverage::ReadDelphiHTML(const char* file)
+{
+ cmParseDelphiCoverage::HTMLParser parser(this->CTest, this->Coverage);
+ parser.ParseFile(file);
+ return true;
+}
diff --git a/Source/CTest/cmParseDelphiCoverage.h b/Source/CTest/cmParseDelphiCoverage.h
new file mode 100644
index 0000000..2a014a1
--- /dev/null
+++ b/Source/CTest/cmParseDelphiCoverage.h
@@ -0,0 +1,36 @@
+/* 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 <string>
+#include <vector>
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
+
+/** \class cmParseDelphiCoverage
+ * \brief Parse Delphi coverage information
+ *
+ * This class is used to parse Delphi(Pascal) coverage information
+ * generated by the Delphi-Code-Coverage tool
+ *
+ * https://code.google.com/p/delphi-code-coverage/
+ */
+
+class cmParseDelphiCoverage
+{
+public:
+ cmParseDelphiCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+ bool LoadCoverageData(std::vector<std::string> const& files);
+ bool ReadDelphiHTML(const char* file);
+ // Read a single HTML file from output
+ bool ReadHTMLFile(const char* f);
+
+protected:
+ class HTMLParser;
+
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+};
diff --git a/Source/CTest/cmParseGTMCoverage.cxx b/Source/CTest/cmParseGTMCoverage.cxx
new file mode 100644
index 0000000..14417cc
--- /dev/null
+++ b/Source/CTest/cmParseGTMCoverage.cxx
@@ -0,0 +1,252 @@
+#include "cmParseGTMCoverage.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <map>
+#include <vector>
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmParseGTMCoverage::cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont,
+ cmCTest* ctest)
+ : cmParseMumpsCoverage(cont, ctest)
+{
+}
+
+bool cmParseGTMCoverage::LoadCoverageData(std::string const& d)
+{
+ // load all the .mcov files in the specified directory
+ cmsys::Directory dir;
+ if (!dir.Load(d)) {
+ return false;
+ }
+ size_t numf;
+ unsigned int i;
+ numf = dir.GetNumberOfFiles();
+ for (i = 0; i < numf; i++) {
+ std::string file = dir.GetFile(i);
+ if (file != "." && file != ".." && !cmSystemTools::FileIsDirectory(file)) {
+ std::string path = cmStrCat(d, '/', file);
+ if (cmSystemTools::GetFilenameLastExtension(path) == ".mcov") {
+ if (!this->ReadMCovFile(path.c_str())) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool cmParseGTMCoverage::ReadMCovFile(const char* file)
+{
+ cmsys::ifstream in(file);
+ if (!in) {
+ return false;
+ }
+ std::string line;
+ std::string lastfunction;
+ std::string lastroutine;
+ std::string lastpath;
+ int lastoffset = 0;
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ // only look at lines that have coverage data
+ if (line.find("^ZZCOVERAGE") == std::string::npos) {
+ continue;
+ }
+ std::string filepath;
+ std::string function;
+ std::string routine;
+ int linenumber = 0;
+ int count = 0;
+ this->ParseMCOVLine(line, routine, function, linenumber, count);
+ // skip this one
+ if (routine == "RSEL") {
+ continue;
+ }
+ // no need to search the file if we just did it
+ if (function == lastfunction && lastroutine == routine) {
+ if (!lastpath.empty()) {
+ this->Coverage.TotalCoverage[lastpath][lastoffset + linenumber] +=
+ count;
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Can not find mumps file : "
+ << lastroutine
+ << " referenced in this line of mcov data:\n"
+ "["
+ << line << "]\n");
+ }
+ continue;
+ }
+ // Find the full path to the file
+ bool found = this->FindMumpsFile(routine, filepath);
+ if (!found && cmHasLiteralSuffix(routine, "%")) {
+ routine.erase(0, 1);
+ found = this->FindMumpsFile(routine, filepath);
+ }
+ if (found) {
+ int lineoffset = 0;
+ if (this->FindFunctionInMumpsFile(filepath, function, lineoffset)) {
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector&
+ coverageVector = this->Coverage.TotalCoverage[filepath];
+ // This section accounts for lines that were previously marked
+ // as non-executable code (-1), if the parser comes back with
+ // a non-zero count, increase the count by 1 to push the line
+ // into the executable code set in addition to the count found.
+ if (coverageVector[lineoffset + linenumber] == -1 && count > 0) {
+ coverageVector[lineoffset + linenumber] += count + 1;
+ } else {
+ coverageVector[lineoffset + linenumber] += count;
+ }
+ lastoffset = lineoffset;
+ }
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Can not find mumps file : "
+ << routine
+ << " referenced in this line of mcov data:\n"
+ "["
+ << line << "]\n");
+ }
+ lastfunction = function;
+ lastroutine = routine;
+ lastpath = filepath;
+ }
+ return true;
+}
+
+bool cmParseGTMCoverage::FindFunctionInMumpsFile(std::string const& filepath,
+ std::string const& function,
+ int& lineoffset)
+{
+ cmsys::ifstream in(filepath.c_str());
+ if (!in) {
+ return false;
+ }
+ std::string line;
+ int linenum = 0;
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ std::string::size_type pos = line.find(function);
+ if (pos == 0) {
+ char nextchar = line[function.size()];
+ if (nextchar == ' ' || nextchar == '(' || nextchar == '\t') {
+ lineoffset = linenum;
+ return true;
+ }
+ }
+ if (pos == 1) {
+ char prevchar = line[0];
+ char nextchar = line[function.size() + 1];
+ if (prevchar == '%' && (nextchar == ' ' || nextchar == '(')) {
+ lineoffset = linenum;
+ return true;
+ }
+ }
+ linenum++; // move to next line count
+ }
+ lineoffset = 0;
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Could not find entry point : " << function << " in " << filepath
+ << "\n");
+ return false;
+}
+
+bool cmParseGTMCoverage::ParseMCOVLine(std::string const& line,
+ std::string& routine,
+ std::string& function, int& linenumber,
+ int& count)
+{
+ // this method parses lines from the .mcov file
+ // each line has ^COVERAGE(...) in it, and there
+ // are several variants of coverage lines:
+ //
+ // ^COVERAGE("DIC11","PR1",0)="2:0:0:0"
+ // ( file , entry, line ) = "number_executed:timing_info"
+ // ^COVERAGE("%RSEL","SRC")="1:0:0:0"
+ // ( file , entry ) = "number_executed:timing_info"
+ // ^COVERAGE("%RSEL","init",8,"FOR_LOOP",1)=1
+ // ( file , entry, line, IGNORE ) =number_executed
+ std::vector<std::string> args;
+ std::string::size_type pos = line.find('(', 0);
+ // if no ( is found, then return line has no coverage
+ if (pos == std::string::npos) {
+ return false;
+ }
+ std::string arg;
+ bool done = false;
+ // separate out all of the comma separated arguments found
+ // in the COVERAGE(...) line
+ while (line[pos] && !done) {
+ // save the char we are looking at
+ char cur = line[pos];
+ // , or ) means end of argument
+ if (cur == ',' || cur == ')') {
+ // save the argument into the argument vector
+ args.push_back(arg);
+ // start on a new argument
+ arg.clear();
+ // if we are at the end of the ), then finish while loop
+ if (cur == ')') {
+ done = true;
+ }
+ } else {
+ // all chars except " and ( get stored in the arg string
+ if (cur != '\"' && cur != '(') {
+ arg.append(1, line[pos]);
+ }
+ }
+ // move to next char
+ pos++;
+ }
+ // now parse the right hand side of the =
+ pos = line.find('=');
+ // no = found, this is an error
+ if (pos == std::string::npos) {
+ return false;
+ }
+ pos++; // move past =
+
+ // if the next positing is not a ", then this is a
+ // COVERAGE(..)=count line and turn the rest of the string
+ // past the = into an integer and set it to count
+ if (line[pos] != '\"') {
+ count = atoi(line.substr(pos).c_str());
+ } else {
+ // this means line[pos] is a ", and we have a
+ // COVERAGE(...)="1:0:0:0" type of line
+ pos++; // move past "
+ // find the first : past the "
+ std::string::size_type pos2 = line.find(':', pos);
+ // turn the string between the " and the first : into an integer
+ // and set it to count
+ count = atoi(line.substr(pos, pos2 - pos).c_str());
+ }
+ // less then two arguments is an error
+ if (args.size() < 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error parsing mcov line: [" << line << "]\n");
+ return false;
+ }
+ routine = args[0]; // the routine is the first argument
+ function = args[1]; // the function in the routine is the second
+ // in the two argument only format
+ // ^COVERAGE("%RSEL","SRC"), the line offset is 0
+ if (args.size() == 2) {
+ // To avoid double counting of line 0 of each entry point,
+ // Don't count the lines that do not give an explicit line
+ // number.
+ routine.clear();
+ function.clear();
+ } else {
+ // this is the format for this line
+ // ^COVERAGE("%RSEL","SRC",count)
+ linenumber = atoi(args[2].c_str());
+ }
+ return true;
+}
diff --git a/Source/CTest/cmParseGTMCoverage.h b/Source/CTest/cmParseGTMCoverage.h
new file mode 100644
index 0000000..c35bf6e
--- /dev/null
+++ b/Source/CTest/cmParseGTMCoverage.h
@@ -0,0 +1,38 @@
+/* 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 <string>
+
+#include "cmParseMumpsCoverage.h"
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
+
+/** \class cmParseGTMCoverage
+ * \brief Parse GTM coverage information
+ *
+ * This class is used to parse GTM coverage information for
+ * mumps.
+ */
+class cmParseGTMCoverage : public cmParseMumpsCoverage
+{
+public:
+ cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+
+protected:
+ // implement virtual from parent
+ bool LoadCoverageData(std::string const& dir) override;
+ // Read a single mcov file
+ bool ReadMCovFile(const char* f);
+ // find out what line in a mumps file (filepath) the given entry point
+ // or function is. lineoffset is set by this method.
+ bool FindFunctionInMumpsFile(std::string const& filepath,
+ std::string const& function, int& lineoffset);
+ // parse a line from a .mcov file, and fill in the
+ // routine, function, linenumber and coverage count
+ bool ParseMCOVLine(std::string const& line, std::string& routine,
+ std::string& function, int& linenumber, int& count);
+};
diff --git a/Source/CTest/cmParseJacocoCoverage.cxx b/Source/CTest/cmParseJacocoCoverage.cxx
new file mode 100644
index 0000000..9cf30df
--- /dev/null
+++ b/Source/CTest/cmParseJacocoCoverage.cxx
@@ -0,0 +1,178 @@
+#include "cmParseJacocoCoverage.h"
+
+#include <cstdlib>
+#include <cstring>
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+
+class cmParseJacocoCoverage::XMLParser : public cmXMLParser
+{
+public:
+ XMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont)
+ : CTest(ctest)
+ , Coverage(cont)
+ {
+ }
+
+protected:
+ void EndElement(const std::string& /*name*/) override {}
+
+ void StartElement(const std::string& name, const char** atts) override
+ {
+ if (name == "package") {
+ this->PackageName = atts[1];
+ this->PackagePath.clear();
+ } else if (name == "sourcefile") {
+ this->FilePath.clear();
+ std::string fileName = atts[1];
+
+ if (this->PackagePath.empty()) {
+ if (!this->FindPackagePath(fileName)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find file: " << this->PackageName << "/"
+ << fileName << std::endl);
+ this->Coverage.Error++;
+ return;
+ }
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading file: " << fileName << std::endl,
+ this->Coverage.Quiet);
+
+ this->FilePath = this->PackagePath + "/" + fileName;
+ cmsys::ifstream fin(this->FilePath.c_str());
+ if (!fin) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Jacoco Coverage: Error opening " << this->FilePath
+ << std::endl);
+ }
+ std::string line;
+ FileLinesType& curFileLines =
+ this->Coverage.TotalCoverage[this->FilePath];
+ if (fin) {
+ curFileLines.push_back(-1);
+ }
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ curFileLines.push_back(-1);
+ }
+ } else if (name == "line") {
+ int tagCount = 0;
+ int nr = -1;
+ int ci = -1;
+ while (true) {
+ if (strcmp(atts[tagCount], "ci") == 0) {
+ ci = atoi(atts[tagCount + 1]);
+ } else if (strcmp(atts[tagCount], "nr") == 0) {
+ nr = atoi(atts[tagCount + 1]);
+ }
+ if (ci > -1 && nr > 0) {
+ FileLinesType& curFileLines =
+ this->Coverage.TotalCoverage[this->FilePath];
+ if (!curFileLines.empty()) {
+ curFileLines[nr - 1] = ci;
+ }
+ break;
+ }
+ ++tagCount;
+ }
+ }
+ }
+
+ virtual bool FindPackagePath(std::string const& fileName)
+ {
+ // Search for the source file in the source directory.
+ if (this->PackagePathFound(fileName, this->Coverage.SourceDir)) {
+ return true;
+ }
+
+ // If not found there, check the binary directory.
+ if (this->PackagePathFound(fileName, this->Coverage.BinaryDir)) {
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool PackagePathFound(std::string const& fileName,
+ std::string const& baseDir)
+ {
+ // Search for the file in the baseDir and its subdirectories.
+ std::string packageGlob = cmStrCat(baseDir, '/', fileName);
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOn();
+ gl.FindFiles(packageGlob);
+ std::vector<std::string> const& files = gl.GetFiles();
+ if (files.empty()) {
+ return false;
+ }
+
+ // Check if any of the locations found match our package.
+ for (std::string const& f : files) {
+ std::string dir = cmsys::SystemTools::GetParentDirectory(f);
+ if (cmHasSuffix(dir, this->PackageName)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found package directory for " << fileName << ": "
+ << dir << std::endl,
+ this->Coverage.Quiet);
+ this->PackagePath = dir;
+ return true;
+ }
+ }
+ return false;
+ }
+
+private:
+ std::string FilePath;
+ std::string PackagePath;
+ std::string PackageName;
+ using FileLinesType =
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector;
+ cmCTest* CTest;
+ cmCTestCoverageHandlerContainer& Coverage;
+};
+
+cmParseJacocoCoverage::cmParseJacocoCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+bool cmParseJacocoCoverage::LoadCoverageData(
+ std::vector<std::string> const& files)
+{
+ // load all the jacoco.xml files in the source directory
+ cmsys::Directory dir;
+ size_t i;
+ std::string path;
+ size_t numf = files.size();
+ for (i = 0; i < numf; i++) {
+ path = files[i];
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading XML File " << path << std::endl,
+ this->Coverage.Quiet);
+ if (cmSystemTools::GetFilenameLastExtension(path) == ".xml") {
+ if (!this->ReadJacocoXML(path.c_str())) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool cmParseJacocoCoverage::ReadJacocoXML(const char* file)
+{
+ cmParseJacocoCoverage::XMLParser parser(this->CTest, this->Coverage);
+ parser.ParseFile(file);
+ return true;
+}
diff --git a/Source/CTest/cmParseJacocoCoverage.h b/Source/CTest/cmParseJacocoCoverage.h
new file mode 100644
index 0000000..3442dd0
--- /dev/null
+++ b/Source/CTest/cmParseJacocoCoverage.h
@@ -0,0 +1,50 @@
+/* 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 <map>
+#include <string>
+#include <vector>
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
+
+/** \class cmParseJacocoCoverage
+ * \brief Parse JaCoCO coverage information
+ *
+ * This class is used to parse coverage information for
+ * java using the JaCoCo tool:
+ *
+ * http://www.eclemma.org/jacoco/trunk/index.html
+ */
+class cmParseJacocoCoverage
+{
+public:
+ cmParseJacocoCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+ bool LoadCoverageData(std::vector<std::string> const& files);
+
+ std::string PackageName;
+ std::string FileName;
+ std::string ModuleName;
+ std::string CurFileName;
+
+private:
+ // implement virtual from parent
+ // remove files with no coverage
+ void RemoveUnCoveredFiles();
+ // Read a single mcov file
+ bool ReadJacocoXML(const char* f);
+ // split a string based on ,
+ bool SplitString(std::vector<std::string>& args, std::string const& line);
+ bool FindJavaFile(std::string const& routine, std::string& filepath);
+ void InitializeJavaFile(std::string& file);
+ bool LoadSource(std::string d);
+
+ class XMLParser;
+
+ std::map<std::string, std::string> RoutineToDirectory;
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+};
diff --git a/Source/CTest/cmParseMumpsCoverage.cxx b/Source/CTest/cmParseMumpsCoverage.cxx
new file mode 100644
index 0000000..dc3064d
--- /dev/null
+++ b/Source/CTest/cmParseMumpsCoverage.cxx
@@ -0,0 +1,144 @@
+#include "cmParseMumpsCoverage.h"
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmParseMumpsCoverage::cmParseMumpsCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+cmParseMumpsCoverage::~cmParseMumpsCoverage() = default;
+
+bool cmParseMumpsCoverage::ReadCoverageFile(const char* file)
+{
+ // Read the gtm_coverage.mcov file, that has two lines of data:
+ // packages:/full/path/to/Vista/Packages
+ // coverage_dir:/full/path/to/dir/with/*.mcov
+ cmsys::ifstream in(file);
+ if (!in) {
+ return false;
+ }
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ std::string::size_type pos = line.find(':', 0);
+ std::string packages;
+ if (pos != std::string::npos) {
+ std::string type = line.substr(0, pos);
+ std::string path = line.substr(pos + 1);
+ if (type == "packages") {
+ this->LoadPackages(path);
+ } else if (type == "coverage_dir") {
+ this->LoadCoverageData(path);
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Parse Error in Mumps coverage file :\n"
+ << file << "\ntype: [" << type << "]\npath:[" << path
+ << "]\n"
+ "input line: ["
+ << line << "]\n");
+ }
+ }
+ }
+ return true;
+}
+
+void cmParseMumpsCoverage::InitializeMumpsFile(std::string& file)
+{
+ // initialize the coverage information for a given mumps file
+ cmsys::ifstream in(file.c_str());
+ if (!in) {
+ return;
+ }
+ std::string line;
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector =
+ this->Coverage.TotalCoverage[file];
+ if (!cmSystemTools::GetLineFromStream(in, line)) {
+ return;
+ }
+ // first line of a .m file can never be run
+ coverageVector.push_back(-1);
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ // putting in a 0 for a line means it is executable code
+ // putting in a -1 for a line means it is not executable code
+ int val = -1; // assume line is not executable
+ bool found = false;
+ std::string::size_type i = 0;
+ // (1) Search for the first whitespace or semicolon character on a line.
+ // This will skip over labels if the line starts with one, or will simply
+ // be the first character on the line for non-label lines.
+ for (; i < line.size(); ++i) {
+ if (line[i] == ' ' || line[i] == '\t' || line[i] == ';') {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ // (2) If the first character found above is whitespace or a period
+ // then continue the search for the first following non-whitespace
+ // character.
+ if (line[i] == ' ' || line[i] == '\t') {
+ while (i < line.size() &&
+ (line[i] == ' ' || line[i] == '\t' || line[i] == '.')) {
+ i++;
+ }
+ }
+ // (3) If the character found is not a semicolon then the line counts for
+ // coverage.
+ if (i < line.size() && line[i] != ';') {
+ val = 0;
+ }
+ }
+ coverageVector.push_back(val);
+ }
+}
+
+bool cmParseMumpsCoverage::LoadPackages(std::string const& d)
+{
+ cmsys::Glob glob;
+ glob.RecurseOn();
+ std::string pat = cmStrCat(d, "/*.m");
+ glob.FindFiles(pat);
+ for (std::string& file : glob.GetFiles()) {
+ std::string name = cmSystemTools::GetFilenameName(file);
+ name.erase(name.size() - 2);
+ this->RoutineToDirectory[name] = file;
+ // initialize each file, this is left out until CDash is fixed
+ // to handle large numbers of files
+ this->InitializeMumpsFile(file);
+ }
+ return true;
+}
+
+bool cmParseMumpsCoverage::FindMumpsFile(std::string const& routine,
+ std::string& filepath)
+{
+ auto i = this->RoutineToDirectory.find(routine);
+ if (i != this->RoutineToDirectory.end()) {
+ filepath = i->second;
+ return true;
+ }
+ // try some alternate names
+ const char* tryname[] = { "GUX", "GTM", "ONT", nullptr };
+ for (int k = 0; tryname[k] != nullptr; k++) {
+ std::string routine2 = routine + tryname[k];
+ i = this->RoutineToDirectory.find(routine2);
+ if (i != this->RoutineToDirectory.end()) {
+ filepath = i->second;
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/Source/CTest/cmParseMumpsCoverage.h b/Source/CTest/cmParseMumpsCoverage.h
new file mode 100644
index 0000000..00a8431
--- /dev/null
+++ b/Source/CTest/cmParseMumpsCoverage.h
@@ -0,0 +1,44 @@
+/* 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 <map>
+#include <string>
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
+
+/** \class cmParseMumpsCoverage
+ * \brief Parse Mumps coverage information
+ *
+ * This class is used as the base class for Mumps coverage
+ * parsing.
+ */
+class cmParseMumpsCoverage
+{
+public:
+ cmParseMumpsCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+ virtual ~cmParseMumpsCoverage();
+ // This is the toplevel coverage file locating the coverage files
+ // and the mumps source code package tree.
+ bool ReadCoverageFile(const char* file);
+
+protected:
+ // sub classes will use this to
+ // load all coverage files found in the given directory
+ virtual bool LoadCoverageData(std::string const& d) = 0;
+ // search the package directory for mumps files and fill
+ // in the RoutineToDirectory map
+ bool LoadPackages(std::string const& dir);
+ // initialize the coverage information for a single mumps file
+ void InitializeMumpsFile(std::string& file);
+ // Find mumps file for routine
+ bool FindMumpsFile(std::string const& routine, std::string& filepath);
+
+protected:
+ std::map<std::string, std::string> RoutineToDirectory;
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+};
diff --git a/Source/CTest/cmParsePHPCoverage.cxx b/Source/CTest/cmParsePHPCoverage.cxx
new file mode 100644
index 0000000..044f518
--- /dev/null
+++ b/Source/CTest/cmParsePHPCoverage.cxx
@@ -0,0 +1,222 @@
+#include "cmParsePHPCoverage.h"
+
+#include <cstdlib>
+#include <cstring>
+
+#include <cm/memory>
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+/*
+ To setup coverage for php.
+
+ - edit php.ini to add auto prepend and append php files from phpunit
+ auto_prepend_file =
+ auto_append_file =
+ - run the tests
+ - run this program on all the files in c:/tmp
+
+*/
+
+cmParsePHPCoverage::cmParsePHPCoverage(cmCTestCoverageHandlerContainer& cont,
+ cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+bool cmParsePHPCoverage::ReadUntil(std::istream& in, char until)
+{
+ char c = 0;
+ while (in.get(c) && c != until) {
+ }
+ return c == until;
+}
+bool cmParsePHPCoverage::ReadCoverageArray(std::istream& in,
+ std::string const& fileName)
+{
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector =
+ this->Coverage.TotalCoverage[fileName];
+
+ char c;
+ char buf[4];
+ in.read(buf, 3);
+ buf[3] = 0;
+ if (strcmp(buf, ";a:") != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read start of coverage array, found : " << buf
+ << "\n");
+ return false;
+ }
+ int size = 0;
+ if (!this->ReadInt(in, size)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "failed to read size ");
+ return false;
+ }
+ if (!in.get(c) && c == '{') {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "failed to read open {\n");
+ return false;
+ }
+ for (int i = 0; i < size; i++) {
+ this->ReadUntil(in, ':');
+ int line = 0;
+ this->ReadInt(in, line);
+ // ok xdebug may have a bug here
+ // it seems to be 1 based but often times
+ // seems to have a 0'th line.
+ line--;
+ if (line < 0) {
+ line = 0;
+ }
+ this->ReadUntil(in, ':');
+ int value = 0;
+ this->ReadInt(in, value);
+ // make sure the vector is the right size and is
+ // initialized with -1 for each line
+ while (coverageVector.size() <= static_cast<size_t>(line)) {
+ coverageVector.push_back(-1);
+ }
+ // if value is less than 0, set it to zero
+ // TODO figure out the difference between
+ // -1 and -2 in xdebug coverage?? For now
+ // assume less than 0 is just not covered
+ // CDash expects -1 for non executable code (like comments)
+ // and 0 for uncovered code, and a positive value
+ // for number of times a line was executed
+ if (value < 0) {
+ value = 0;
+ }
+ // if unset then set it to value
+ if (coverageVector[line] == -1) {
+ coverageVector[line] = value;
+ }
+ // otherwise increment by value
+ else {
+ coverageVector[line] += value;
+ }
+ }
+ return true;
+}
+
+bool cmParsePHPCoverage::ReadInt(std::istream& in, int& v)
+{
+ std::string s;
+ char c = 0;
+ while (in.get(c) && c != ':' && c != ';') {
+ s += c;
+ }
+ v = atoi(s.c_str());
+ return true;
+}
+
+bool cmParsePHPCoverage::ReadArraySize(std::istream& in, int& size)
+{
+ char c = 0;
+ in.get(c);
+ if (c != 'a') {
+ return false;
+ }
+ if (in.get(c) && c == ':') {
+ if (this->ReadInt(in, size)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmParsePHPCoverage::ReadFileInformation(std::istream& in)
+{
+ char buf[4];
+ in.read(buf, 2);
+ buf[2] = 0;
+ if (strcmp(buf, "s:") != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read start of file info found: [" << buf << "]\n");
+ return false;
+ }
+ char c;
+ int size = 0;
+ if (this->ReadInt(in, size)) {
+ size++; // add one for null termination
+ auto s = cm::make_unique<char[]>(size + 1);
+ // read open quote
+ if (in.get(c) && c != '"') {
+ return false;
+ }
+ // read the string data
+ in.read(s.get(), size - 1);
+ s[size - 1] = 0;
+ std::string fileName = s.get();
+ // read close quote
+ if (in.get(c) && c != '"') {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read close quote\n"
+ << "read [" << c << "]\n");
+ return false;
+ }
+ if (!this->ReadCoverageArray(in, fileName)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read coverage array for file: " << fileName
+ << "\n");
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool cmParsePHPCoverage::ReadPHPData(const char* file)
+{
+ cmsys::ifstream in(file);
+ if (!in) {
+ return false;
+ }
+ int size = 0;
+ this->ReadArraySize(in, size);
+ char c = 0;
+ in.get(c);
+ if (c != '{') {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "failed to read open array\n");
+ return false;
+ }
+ for (int i = 0; i < size; i++) {
+ if (!this->ReadFileInformation(in)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Failed to read file #" << i << "\n");
+ return false;
+ }
+ in.get(c);
+ if (c != '}') {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "failed to read close array\n");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmParsePHPCoverage::ReadPHPCoverageDirectory(const char* d)
+{
+ cmsys::Directory dir;
+ if (!dir.Load(d)) {
+ return false;
+ }
+ size_t numf;
+ unsigned int i;
+ numf = dir.GetNumberOfFiles();
+ for (i = 0; i < numf; i++) {
+ std::string file = dir.GetFile(i);
+ if (file != "." && file != ".." && !cmSystemTools::FileIsDirectory(file)) {
+ std::string path = cmStrCat(d, '/', file);
+ if (!this->ReadPHPData(path.c_str())) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
diff --git a/Source/CTest/cmParsePHPCoverage.h b/Source/CTest/cmParsePHPCoverage.h
new file mode 100644
index 0000000..763a6bb
--- /dev/null
+++ b/Source/CTest/cmParsePHPCoverage.h
@@ -0,0 +1,36 @@
+/* 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 <iosfwd>
+#include <string>
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
+
+/** \class cmParsePHPCoverage
+ * \brief Parse xdebug PHP coverage information
+ *
+ * This class is used to parse php coverage information produced
+ * by xdebug. The data is stored as a php dump of the array
+ * return by xdebug coverage. It is an array of arrays.
+ */
+class cmParsePHPCoverage
+{
+public:
+ cmParsePHPCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+ bool ReadPHPCoverageDirectory(const char* dir);
+ void PrintCoverage();
+
+private:
+ bool ReadPHPData(const char* file);
+ bool ReadArraySize(std::istream& in, int& size);
+ bool ReadFileInformation(std::istream& in);
+ bool ReadInt(std::istream& in, int& v);
+ bool ReadCoverageArray(std::istream& in, std::string const&);
+ bool ReadUntil(std::istream& in, char until);
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+};
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
new file mode 100644
index 0000000..16bca01
--- /dev/null
+++ b/Source/CTest/cmProcess.cxx
@@ -0,0 +1,706 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmProcess.h"
+
+#include <csignal>
+#include <iostream>
+#include <string>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmsys/Process.h"
+
+#include "cmCTest.h"
+#include "cmCTestRunTest.h"
+#include "cmCTestTestHandler.h"
+#include "cmGetPipes.h"
+#include "cmStringAlgorithms.h"
+#if defined(_WIN32)
+# include <cm3p/kwiml/int.h>
+#endif
+
+#define CM_PROCESS_BUF_SIZE 65536
+
+cmProcess::cmProcess(std::unique_ptr<cmCTestRunTest> runner)
+ : Runner(std::move(runner))
+ , Conv(cmProcessOutput::UTF8, CM_PROCESS_BUF_SIZE)
+{
+ this->Timeout = cmDuration::zero();
+ this->TotalTime = cmDuration::zero();
+ this->ExitValue = 0;
+ this->Id = 0;
+ this->StartTime = std::chrono::steady_clock::time_point();
+}
+
+cmProcess::~cmProcess() = default;
+
+void cmProcess::SetCommand(std::string const& command)
+{
+ this->Command = command;
+}
+
+void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
+{
+ this->Arguments = args;
+}
+
+void cmProcess::SetWorkingDirectory(std::string const& dir)
+{
+ this->WorkingDirectory = dir;
+}
+
+bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity)
+{
+ this->ProcessState = cmProcess::State::Error;
+ if (this->Command.empty()) {
+ return false;
+ }
+ this->StartTime = std::chrono::steady_clock::now();
+ this->ProcessArgs.clear();
+ // put the command as arg0
+ this->ProcessArgs.push_back(this->Command.c_str());
+ // now put the command arguments in
+ for (std::string const& arg : this->Arguments) {
+ this->ProcessArgs.push_back(arg.c_str());
+ }
+ this->ProcessArgs.push_back(nullptr); // null terminate the list
+
+ cm::uv_timer_ptr timer;
+ int status = timer.init(loop, this);
+ if (status != 0) {
+ cmCTestLog(this->Runner->GetCTest(), ERROR_MESSAGE,
+ "Error initializing timer: " << uv_strerror(status)
+ << std::endl);
+ return false;
+ }
+
+ cm::uv_pipe_ptr pipe_writer;
+ cm::uv_pipe_ptr pipe_reader;
+
+ pipe_writer.init(loop, 0);
+ pipe_reader.init(loop, 0, this);
+
+ int fds[2] = { -1, -1 };
+ status = cmGetPipes(fds);
+ if (status != 0) {
+ cmCTestLog(this->Runner->GetCTest(), ERROR_MESSAGE,
+ "Error initializing pipe: " << uv_strerror(status)
+ << std::endl);
+ return false;
+ }
+
+ uv_pipe_open(pipe_reader, fds[0]);
+ uv_pipe_open(pipe_writer, fds[1]);
+
+ uv_stdio_container_t stdio[3];
+ stdio[0].flags = UV_INHERIT_FD;
+ stdio[0].data.fd = 0;
+ stdio[1].flags = UV_INHERIT_STREAM;
+ stdio[1].data.stream = pipe_writer;
+ stdio[2] = stdio[1];
+
+ uv_process_options_t options = uv_process_options_t();
+ options.file = this->Command.data();
+ options.args = const_cast<char**>(this->ProcessArgs.data());
+ options.stdio_count = 3; // in, out and err
+ options.exit_cb = &cmProcess::OnExitCB;
+ options.stdio = stdio;
+#if !defined(CMAKE_USE_SYSTEM_LIBUV)
+ std::vector<char> cpumask;
+ if (affinity && !affinity->empty()) {
+ cpumask.resize(static_cast<size_t>(uv_cpumask_size()), 0);
+ for (auto p : *affinity) {
+ cpumask[p] = 1;
+ }
+ options.cpumask = cpumask.data();
+ options.cpumask_size = cpumask.size();
+ } else {
+ options.cpumask = nullptr;
+ options.cpumask_size = 0;
+ }
+#else
+ static_cast<void>(affinity);
+#endif
+
+ status =
+ uv_read_start(pipe_reader, &cmProcess::OnAllocateCB, &cmProcess::OnReadCB);
+
+ if (status != 0) {
+ cmCTestLog(this->Runner->GetCTest(), ERROR_MESSAGE,
+ "Error starting read events: " << uv_strerror(status)
+ << std::endl);
+ return false;
+ }
+
+ status = this->Process.spawn(loop, options, this);
+ if (status != 0) {
+ cmCTestLog(this->Runner->GetCTest(), ERROR_MESSAGE,
+ "Process not started\n " << this->Command << "\n["
+ << uv_strerror(status) << "]\n");
+ return false;
+ }
+
+ this->PipeReader = std::move(pipe_reader);
+ this->Timer = std::move(timer);
+
+ this->StartTimer();
+
+ this->ProcessState = cmProcess::State::Executing;
+ return true;
+}
+
+void cmProcess::StartTimer()
+{
+ auto* properties = this->Runner->GetTestProperties();
+ auto msec =
+ std::chrono::duration_cast<std::chrono::milliseconds>(this->Timeout);
+
+ if (msec != std::chrono::milliseconds(0) || !properties->ExplicitTimeout) {
+ this->Timer.start(&cmProcess::OnTimeoutCB,
+ static_cast<uint64_t>(msec.count()), 0);
+ }
+}
+
+bool cmProcess::Buffer::GetLine(std::string& line)
+{
+ // Scan for the next newline.
+ for (size_type sz = this->size(); this->Last != sz; ++this->Last) {
+ if ((*this)[this->Last] == '\n' || (*this)[this->Last] == '\0') {
+ // Extract the range first..last as a line.
+ const char* text = this->data() + this->First;
+ size_type length = this->Last - this->First;
+ while (length && text[length - 1] == '\r') {
+ length--;
+ }
+ line.assign(text, length);
+
+ // Start a new range for the next line.
+ ++this->Last;
+ this->First = this->Last;
+
+ // Return the line extracted.
+ return true;
+ }
+ }
+
+ // Available data have been exhausted without a newline.
+ if (this->First != 0) {
+ // Move the partial line to the beginning of the buffer.
+ this->erase(this->begin(), this->begin() + this->First);
+ this->First = 0;
+ this->Last = this->size();
+ }
+ return false;
+}
+
+bool cmProcess::Buffer::GetLast(std::string& line)
+{
+ // Return the partial last line, if any.
+ if (!this->empty()) {
+ line.assign(this->data(), this->size());
+ this->First = this->Last = 0;
+ this->clear();
+ return true;
+ }
+ return false;
+}
+
+void cmProcess::OnReadCB(uv_stream_t* stream, ssize_t nread,
+ const uv_buf_t* buf)
+{
+ auto* self = static_cast<cmProcess*>(stream->data);
+ self->OnRead(nread, buf);
+}
+
+void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf)
+{
+ std::string line;
+ if (nread > 0) {
+ std::string strdata;
+ this->Conv.DecodeText(buf->base, static_cast<size_t>(nread), strdata);
+ cm::append(this->Output, strdata);
+
+ while (this->Output.GetLine(line)) {
+ this->Runner->CheckOutput(line);
+ line.clear();
+ }
+
+ return;
+ }
+
+ if (nread == 0) {
+ return;
+ }
+
+ // The process will provide no more data.
+ if (nread != UV_EOF) {
+ auto error = static_cast<int>(nread);
+ cmCTestLog(this->Runner->GetCTest(), ERROR_MESSAGE,
+ "Error reading stream: " << uv_strerror(error) << std::endl);
+ }
+
+ // Look for partial last lines.
+ if (this->Output.GetLast(line)) {
+ this->Runner->CheckOutput(line);
+ }
+
+ this->ReadHandleClosed = true;
+ this->PipeReader.reset();
+ if (this->ProcessHandleClosed) {
+ uv_timer_stop(this->Timer);
+ this->Finish();
+ }
+}
+
+void cmProcess::OnAllocateCB(uv_handle_t* handle, size_t suggested_size,
+ uv_buf_t* buf)
+{
+ auto* self = static_cast<cmProcess*>(handle->data);
+ self->OnAllocate(suggested_size, buf);
+}
+
+void cmProcess::OnAllocate(size_t /*suggested_size*/, uv_buf_t* buf)
+{
+ if (this->Buf.size() != CM_PROCESS_BUF_SIZE) {
+ this->Buf.resize(CM_PROCESS_BUF_SIZE);
+ }
+
+ *buf =
+ uv_buf_init(this->Buf.data(), static_cast<unsigned int>(this->Buf.size()));
+}
+
+void cmProcess::OnTimeoutCB(uv_timer_t* timer)
+{
+ auto* self = static_cast<cmProcess*>(timer->data);
+ self->OnTimeout();
+}
+
+void cmProcess::OnTimeout()
+{
+ this->ProcessState = cmProcess::State::Expired;
+ bool const was_still_reading = !this->ReadHandleClosed;
+ if (!this->ReadHandleClosed) {
+ this->ReadHandleClosed = true;
+ this->PipeReader.reset();
+ }
+ if (!this->ProcessHandleClosed) {
+ // Kill the child and let our on-exit handler finish the test.
+ cmsysProcess_KillPID(static_cast<unsigned long>(this->Process->pid));
+ } else if (was_still_reading) {
+ // Our on-exit handler already ran but did not finish the test
+ // because we were still reading output. We've just dropped
+ // our read handler, so we need to finish the test now.
+ this->Finish();
+ }
+}
+
+void cmProcess::OnExitCB(uv_process_t* process, int64_t exit_status,
+ int term_signal)
+{
+ auto* self = static_cast<cmProcess*>(process->data);
+ self->OnExit(exit_status, term_signal);
+}
+
+void cmProcess::OnExit(int64_t exit_status, int term_signal)
+{
+ if (this->ProcessState != cmProcess::State::Expired) {
+ if (
+#if defined(_WIN32)
+ ((DWORD)exit_status & 0xF0000000) == 0xC0000000
+#else
+ term_signal != 0
+#endif
+ ) {
+ this->ProcessState = cmProcess::State::Exception;
+ } else {
+ this->ProcessState = cmProcess::State::Exited;
+ }
+ }
+
+ // Record exit information.
+ this->ExitValue = exit_status;
+ this->Signal = term_signal;
+
+ this->ProcessHandleClosed = true;
+ if (this->ReadHandleClosed) {
+ uv_timer_stop(this->Timer);
+ this->Finish();
+ }
+}
+
+void cmProcess::Finish()
+{
+ this->TotalTime = std::chrono::steady_clock::now() - this->StartTime;
+ // Because of a processor clock scew the runtime may become slightly
+ // negative. If someone changed the system clock while the process was
+ // running this may be even more. Make sure not to report a negative
+ // duration here.
+ if (this->TotalTime <= cmDuration::zero()) {
+ this->TotalTime = cmDuration::zero();
+ }
+ this->Runner->FinalizeTest();
+}
+
+cmProcess::State cmProcess::GetProcessStatus()
+{
+ return this->ProcessState;
+}
+
+void cmProcess::ChangeTimeout(cmDuration t)
+{
+ this->Timeout = t;
+ this->StartTimer();
+}
+
+void cmProcess::ResetStartTime()
+{
+ this->StartTime = std::chrono::steady_clock::now();
+}
+
+cmProcess::Exception cmProcess::GetExitException() const
+{
+ auto exception = Exception::None;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ auto exit_code = (DWORD)this->ExitValue;
+ if ((exit_code & 0xF0000000) != 0xC0000000) {
+ return exception;
+ }
+
+ if (exit_code) {
+ switch (exit_code) {
+ case STATUS_DATATYPE_MISALIGNMENT:
+ case STATUS_ACCESS_VIOLATION:
+ case STATUS_IN_PAGE_ERROR:
+ case STATUS_INVALID_HANDLE:
+ case STATUS_NONCONTINUABLE_EXCEPTION:
+ case STATUS_INVALID_DISPOSITION:
+ case STATUS_ARRAY_BOUNDS_EXCEEDED:
+ case STATUS_STACK_OVERFLOW:
+ exception = Exception::Fault;
+ break;
+ case STATUS_FLOAT_DENORMAL_OPERAND:
+ case STATUS_FLOAT_DIVIDE_BY_ZERO:
+ case STATUS_FLOAT_INEXACT_RESULT:
+ case STATUS_FLOAT_INVALID_OPERATION:
+ case STATUS_FLOAT_OVERFLOW:
+ case STATUS_FLOAT_STACK_CHECK:
+ case STATUS_FLOAT_UNDERFLOW:
+# ifdef STATUS_FLOAT_MULTIPLE_FAULTS
+ case STATUS_FLOAT_MULTIPLE_FAULTS:
+# endif
+# ifdef STATUS_FLOAT_MULTIPLE_TRAPS
+ case STATUS_FLOAT_MULTIPLE_TRAPS:
+# endif
+ case STATUS_INTEGER_DIVIDE_BY_ZERO:
+ case STATUS_INTEGER_OVERFLOW:
+ exception = Exception::Numerical;
+ break;
+ case STATUS_CONTROL_C_EXIT:
+ exception = Exception::Interrupt;
+ break;
+ case STATUS_ILLEGAL_INSTRUCTION:
+ case STATUS_PRIVILEGED_INSTRUCTION:
+ exception = Exception::Illegal;
+ break;
+ default:
+ exception = Exception::Other;
+ }
+ }
+#else
+ if (this->Signal) {
+ switch (this->Signal) {
+ case SIGSEGV:
+ exception = Exception::Fault;
+ break;
+ case SIGFPE:
+ exception = Exception::Numerical;
+ break;
+ case SIGINT:
+ exception = Exception::Interrupt;
+ break;
+ case SIGILL:
+ exception = Exception::Illegal;
+ break;
+ default:
+ exception = Exception::Other;
+ }
+ }
+#endif
+ return exception;
+}
+
+std::string cmProcess::GetExitExceptionString() const
+{
+ std::string exception_str;
+#if defined(_WIN32)
+ switch (this->ExitValue) {
+ case STATUS_CONTROL_C_EXIT:
+ exception_str = "User interrupt";
+ break;
+ case STATUS_FLOAT_DENORMAL_OPERAND:
+ exception_str = "Floating-point exception (denormal operand)";
+ break;
+ case STATUS_FLOAT_DIVIDE_BY_ZERO:
+ exception_str = "Divide-by-zero";
+ break;
+ case STATUS_FLOAT_INEXACT_RESULT:
+ exception_str = "Floating-point exception (inexact result)";
+ break;
+ case STATUS_FLOAT_INVALID_OPERATION:
+ exception_str = "Invalid floating-point operation";
+ break;
+ case STATUS_FLOAT_OVERFLOW:
+ exception_str = "Floating-point overflow";
+ break;
+ case STATUS_FLOAT_STACK_CHECK:
+ exception_str = "Floating-point stack check failed";
+ break;
+ case STATUS_FLOAT_UNDERFLOW:
+ exception_str = "Floating-point underflow";
+ break;
+# ifdef STATUS_FLOAT_MULTIPLE_FAULTS
+ case STATUS_FLOAT_MULTIPLE_FAULTS:
+ exception_str = "Floating-point exception (multiple faults)";
+ break;
+# endif
+# ifdef STATUS_FLOAT_MULTIPLE_TRAPS
+ case STATUS_FLOAT_MULTIPLE_TRAPS:
+ exception_str = "Floating-point exception (multiple traps)";
+ break;
+# endif
+ case STATUS_INTEGER_DIVIDE_BY_ZERO:
+ exception_str = "Integer divide-by-zero";
+ break;
+ case STATUS_INTEGER_OVERFLOW:
+ exception_str = "Integer overflow";
+ break;
+
+ case STATUS_DATATYPE_MISALIGNMENT:
+ exception_str = "Datatype misalignment";
+ break;
+ case STATUS_ACCESS_VIOLATION:
+ exception_str = "Access violation";
+ break;
+ case STATUS_IN_PAGE_ERROR:
+ exception_str = "In-page error";
+ break;
+ case STATUS_INVALID_HANDLE:
+ exception_str = "Invalid handle";
+ break;
+ case STATUS_NONCONTINUABLE_EXCEPTION:
+ exception_str = "Noncontinuable exception";
+ break;
+ case STATUS_INVALID_DISPOSITION:
+ exception_str = "Invalid disposition";
+ break;
+ case STATUS_ARRAY_BOUNDS_EXCEEDED:
+ exception_str = "Array bounds exceeded";
+ break;
+ case STATUS_STACK_OVERFLOW:
+ exception_str = "Stack overflow";
+ break;
+
+ case STATUS_ILLEGAL_INSTRUCTION:
+ exception_str = "Illegal instruction";
+ break;
+ case STATUS_PRIVILEGED_INSTRUCTION:
+ exception_str = "Privileged instruction";
+ break;
+ case STATUS_NO_MEMORY:
+ default:
+ char buf[1024];
+ const char* fmt = "Exit code 0x%" KWIML_INT_PRIx64 "\n";
+ _snprintf(buf, 1024, fmt, this->ExitValue);
+ exception_str.assign(buf);
+ }
+#else
+ switch (this->Signal) {
+# ifdef SIGSEGV
+ case SIGSEGV:
+ exception_str = "Segmentation fault";
+ break;
+# endif
+# ifdef SIGBUS
+# if !defined(SIGSEGV) || SIGBUS != SIGSEGV
+ case SIGBUS:
+ exception_str = "Bus error";
+ break;
+# endif
+# endif
+# ifdef SIGFPE
+ case SIGFPE:
+ exception_str = "Floating-point exception";
+ break;
+# endif
+# ifdef SIGILL
+ case SIGILL:
+ exception_str = "Illegal instruction";
+ break;
+# endif
+# ifdef SIGINT
+ case SIGINT:
+ exception_str = "User interrupt";
+ break;
+# endif
+# ifdef SIGABRT
+ case SIGABRT:
+ exception_str = "Subprocess aborted";
+ break;
+# endif
+# ifdef SIGKILL
+ case SIGKILL:
+ exception_str = "Subprocess killed";
+ break;
+# endif
+# ifdef SIGTERM
+ case SIGTERM:
+ exception_str = "Subprocess terminated";
+ break;
+# endif
+# ifdef SIGHUP
+ case SIGHUP:
+ exception_str = "SIGHUP";
+ break;
+# endif
+# ifdef SIGQUIT
+ case SIGQUIT:
+ exception_str = "SIGQUIT";
+ break;
+# endif
+# ifdef SIGTRAP
+ case SIGTRAP:
+ exception_str = "SIGTRAP";
+ break;
+# endif
+# ifdef SIGIOT
+# if !defined(SIGABRT) || SIGIOT != SIGABRT
+ case SIGIOT:
+ exception_str = "SIGIOT";
+ break;
+# endif
+# endif
+# ifdef SIGUSR1
+ case SIGUSR1:
+ exception_str = "SIGUSR1";
+ break;
+# endif
+# ifdef SIGUSR2
+ case SIGUSR2:
+ exception_str = "SIGUSR2";
+ break;
+# endif
+# ifdef SIGPIPE
+ case SIGPIPE:
+ exception_str = "SIGPIPE";
+ break;
+# endif
+# ifdef SIGALRM
+ case SIGALRM:
+ exception_str = "SIGALRM";
+ break;
+# endif
+# ifdef SIGSTKFLT
+ case SIGSTKFLT:
+ exception_str = "SIGSTKFLT";
+ break;
+# endif
+# ifdef SIGCHLD
+ case SIGCHLD:
+ exception_str = "SIGCHLD";
+ break;
+# elif defined(SIGCLD)
+ case SIGCLD:
+ exception_str = "SIGCLD";
+ break;
+# endif
+# ifdef SIGCONT
+ case SIGCONT:
+ exception_str = "SIGCONT";
+ break;
+# endif
+# ifdef SIGSTOP
+ case SIGSTOP:
+ exception_str = "SIGSTOP";
+ break;
+# endif
+# ifdef SIGTSTP
+ case SIGTSTP:
+ exception_str = "SIGTSTP";
+ break;
+# endif
+# ifdef SIGTTIN
+ case SIGTTIN:
+ exception_str = "SIGTTIN";
+ break;
+# endif
+# ifdef SIGTTOU
+ case SIGTTOU:
+ exception_str = "SIGTTOU";
+ break;
+# endif
+# ifdef SIGURG
+ case SIGURG:
+ exception_str = "SIGURG";
+ break;
+# endif
+# ifdef SIGXCPU
+ case SIGXCPU:
+ exception_str = "SIGXCPU";
+ break;
+# endif
+# ifdef SIGXFSZ
+ case SIGXFSZ:
+ exception_str = "SIGXFSZ";
+ break;
+# endif
+# ifdef SIGVTALRM
+ case SIGVTALRM:
+ exception_str = "SIGVTALRM";
+ break;
+# endif
+# ifdef SIGPROF
+ case SIGPROF:
+ exception_str = "SIGPROF";
+ break;
+# endif
+# ifdef SIGWINCH
+ case SIGWINCH:
+ exception_str = "SIGWINCH";
+ break;
+# endif
+# ifdef SIGPOLL
+ case SIGPOLL:
+ exception_str = "SIGPOLL";
+ break;
+# endif
+# ifdef SIGIO
+# if !defined(SIGPOLL) || SIGIO != SIGPOLL
+ case SIGIO:
+ exception_str = "SIGIO";
+ break;
+# endif
+# endif
+# ifdef SIGPWR
+ case SIGPWR:
+ exception_str = "SIGPWR";
+ break;
+# endif
+# ifdef SIGSYS
+ case SIGSYS:
+ exception_str = "SIGSYS";
+ break;
+# endif
+# ifdef SIGUNUSED
+# if !defined(SIGSYS) || SIGUNUSED != SIGSYS
+ case SIGUNUSED:
+ exception_str = "SIGUNUSED";
+ break;
+# endif
+# endif
+ default:
+ exception_str = cmStrCat("Signal ", this->Signal);
+ }
+#endif
+ return exception_str;
+}
diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h
new file mode 100644
index 0000000..a44aeb0
--- /dev/null
+++ b/Source/CTest/cmProcess.h
@@ -0,0 +1,133 @@
+/* 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 <chrono>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm3p/uv.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "cmDuration.h"
+#include "cmProcessOutput.h"
+#include "cmUVHandlePtr.h"
+
+class cmCTestRunTest;
+
+/** \class cmProcess
+ * \brief run a process with c++
+ *
+ * cmProcess wraps the kwsys process stuff in a c++ class.
+ */
+class cmProcess
+{
+public:
+ explicit cmProcess(std::unique_ptr<cmCTestRunTest> runner);
+ ~cmProcess();
+ void SetCommand(std::string const& command);
+ void SetCommandArguments(std::vector<std::string> const& arg);
+ void SetWorkingDirectory(std::string const& dir);
+ void SetTimeout(cmDuration t) { this->Timeout = t; }
+ void ChangeTimeout(cmDuration t);
+ void ResetStartTime();
+ // Return true if the process starts
+ bool StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity);
+
+ enum class State
+ {
+ Starting,
+ Error,
+ Exception,
+ Executing,
+ Exited,
+ Expired,
+ Killed,
+ Disowned
+ };
+
+ State GetProcessStatus();
+ int GetId() { return this->Id; }
+ void SetId(int id) { this->Id = id; }
+ int64_t GetExitValue() { return this->ExitValue; }
+ cmDuration GetTotalTime() { return this->TotalTime; }
+
+ enum class Exception
+ {
+ None,
+ Fault,
+ Illegal,
+ Interrupt,
+ Numerical,
+ Other
+ };
+
+ Exception GetExitException() const;
+ std::string GetExitExceptionString() const;
+
+ std::unique_ptr<cmCTestRunTest> GetRunner()
+ {
+ return std::move(this->Runner);
+ }
+
+private:
+ cmDuration Timeout;
+ std::chrono::steady_clock::time_point StartTime;
+ cmDuration TotalTime;
+ bool ReadHandleClosed = false;
+ bool ProcessHandleClosed = false;
+
+ cm::uv_process_ptr Process;
+ cm::uv_pipe_ptr PipeReader;
+ cm::uv_timer_ptr Timer;
+ std::vector<char> Buf;
+
+ std::unique_ptr<cmCTestRunTest> Runner;
+ cmProcessOutput Conv;
+ int Signal = 0;
+ cmProcess::State ProcessState = cmProcess::State::Starting;
+
+ static void OnExitCB(uv_process_t* process, int64_t exit_status,
+ int term_signal);
+ static void OnTimeoutCB(uv_timer_t* timer);
+ static void OnReadCB(uv_stream_t* stream, ssize_t nread,
+ const uv_buf_t* buf);
+ static void OnAllocateCB(uv_handle_t* handle, size_t suggested_size,
+ uv_buf_t* buf);
+
+ void OnExit(int64_t exit_status, int term_signal);
+ void OnTimeout();
+ void OnRead(ssize_t nread, const uv_buf_t* buf);
+ void OnAllocate(size_t suggested_size, uv_buf_t* buf);
+
+ void StartTimer();
+ void Finish();
+
+ class Buffer : public std::vector<char>
+ {
+ // Half-open index range of partial line already scanned.
+ size_type First;
+ size_type Last;
+
+ public:
+ Buffer()
+ : First(0)
+ , Last(0)
+ {
+ }
+ bool GetLine(std::string& line);
+ bool GetLast(std::string& line);
+ };
+ Buffer Output;
+ std::string Command;
+ std::string WorkingDirectory;
+ std::vector<std::string> Arguments;
+ std::vector<const char*> ProcessArgs;
+ int Id;
+ int64_t ExitValue;
+};
diff --git a/Source/Checks/Curses.cmake b/Source/Checks/Curses.cmake
new file mode 100644
index 0000000..d35dd2a
--- /dev/null
+++ b/Source/Checks/Curses.cmake
@@ -0,0 +1,44 @@
+include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake)
+cm_message_checks_compat(
+ "Checking for curses support" __checkStart __checkPass __checkFail)
+message(${__checkStart})
+
+# Try compiling a simple project using curses.
+# Pass in any cache entries that the user may have set.
+set(CMakeCheckCurses_ARGS "")
+foreach(v
+ CURSES_INCLUDE_PATH
+ CURSES_CURSES_LIBRARY
+ CURSES_NCURSES_LIBRARY
+ CURSES_EXTRA_LIBRARY
+ CURSES_FORM_LIBRARY
+ )
+ if(${v})
+ list(APPEND CMakeCheckCurses_ARGS -D${v}=${${v}})
+ endif()
+endforeach()
+file(REMOVE_RECURSE "${CMake_BINARY_DIR}/Source/Checks/Curses-build")
+try_compile(CMakeCheckCurses_COMPILED
+ ${CMake_BINARY_DIR}/Source/Checks/Curses-build
+ ${CMake_SOURCE_DIR}/Source/Checks/Curses
+ CheckCurses # project name
+ CheckCurses # target name
+ CMAKE_FLAGS
+ "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}"
+ ${CMakeCheckCurses_ARGS}
+ OUTPUT_VARIABLE CMakeCheckCurses_OUTPUT
+ )
+
+# Convert result from cache entry to normal variable.
+set(CMakeCheckCurses_COMPILED "${CMakeCheckCurses_COMPILED}")
+unset(CMakeCheckCurses_COMPILED CACHE)
+
+if(CMakeCheckCurses_COMPILED)
+ message(${__checkPass} "Success")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Checking for curses support passed with the following output:\n${CMakeCheckCurses_OUTPUT}\n\n")
+else()
+ message(${__checkFail} "Failed")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Checking for curses support failed with the following output:\n${CMakeCheckCurses_OUTPUT}\n\n")
+endif()
diff --git a/Source/Checks/Curses/CMakeLists.txt b/Source/Checks/Curses/CMakeLists.txt
new file mode 100644
index 0000000..17318a3
--- /dev/null
+++ b/Source/Checks/Curses/CMakeLists.txt
@@ -0,0 +1,25 @@
+cmake_minimum_required(VERSION 3.1)
+if(POLICY CMP0060)
+ cmake_policy(SET CMP0060 NEW)
+endif()
+project(CheckCurses C)
+
+set(CURSES_NEED_NCURSES TRUE)
+find_package(Curses)
+if(NOT CURSES_FOUND)
+ return()
+endif()
+include_directories(${CURSES_INCLUDE_DIRS})
+add_executable(CheckCurses CheckCurses.c)
+target_link_libraries(CheckCurses ${CURSES_LIBRARIES})
+
+foreach(h
+ CURSES_HAVE_CURSES_H
+ CURSES_HAVE_NCURSES_H
+ CURSES_HAVE_NCURSES_NCURSES_H
+ CURSES_HAVE_NCURSES_CURSES_H
+ )
+ if(${h})
+ target_compile_definitions(CheckCurses PRIVATE ${h})
+ endif()
+endforeach()
diff --git a/Source/Checks/Curses/CheckCurses.c b/Source/Checks/Curses/CheckCurses.c
new file mode 100644
index 0000000..7d827e6
--- /dev/null
+++ b/Source/Checks/Curses/CheckCurses.c
@@ -0,0 +1,15 @@
+#if defined(CURSES_HAVE_NCURSES_H)
+# include <ncurses.h>
+#elif defined(CURSES_HAVE_NCURSES_NCURSES_H)
+# include <ncurses/ncurses.h>
+#elif defined(CURSES_HAVE_NCURSES_CURSES_H)
+# include <ncurses/curses.h>
+#else
+# include <curses.h>
+#endif
+
+int main()
+{
+ curses_version();
+ return 0;
+}
diff --git a/Source/Checks/cm_c11_thread_local.c b/Source/Checks/cm_c11_thread_local.c
new file mode 100644
index 0000000..bdf91aa
--- /dev/null
+++ b/Source/Checks/cm_c11_thread_local.c
@@ -0,0 +1,5 @@
+_Thread_local int i = 42;
+int main(void)
+{
+ return 0;
+}
diff --git a/Source/Checks/cm_c11_thread_local.cmake b/Source/Checks/cm_c11_thread_local.cmake
new file mode 100644
index 0000000..2263be3
--- /dev/null
+++ b/Source/Checks/cm_c11_thread_local.cmake
@@ -0,0 +1,37 @@
+set(CMake_C11_THREAD_LOCAL_BROKEN 0)
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_C11_STANDARD_COMPILE_OPTION)
+ if(NOT DEFINED CMake_C11_THREAD_LOCAL_WORKS)
+ include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake)
+ cm_message_checks_compat(
+ "Checking if compiler supports C11 _Thread_local"
+ __checkStart __checkPass __checkFail)
+ message(${__checkStart})
+ try_compile(CMake_C11_THREAD_LOCAL_WORKS
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_LIST_DIR}/cm_c11_thread_local.c
+ CMAKE_FLAGS -DCMAKE_C_STANDARD=11
+ OUTPUT_VARIABLE OUTPUT
+ )
+ if(CMake_C11_THREAD_LOCAL_WORKS AND "${OUTPUT}" MATCHES "error: expected '=', ',', ';', 'asm' or '__attribute__' before 'int'")
+ set_property(CACHE CMake_C11_THREAD_LOCAL_WORKS PROPERTY VALUE 0)
+ endif()
+ if(CMake_C11_THREAD_LOCAL_WORKS)
+ message(${__checkPass} "yes")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if compiler supports C11 _Thread_local passed with the following output:\n"
+ "${OUTPUT}\n"
+ "\n"
+ )
+ else()
+ message(${__checkFail} "no")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if compiler supports C11 _Thread_local failed with the following output:\n"
+ "${OUTPUT}\n"
+ "\n"
+ )
+ endif()
+ endif()
+ if(NOT CMake_C11_THREAD_LOCAL_WORKS)
+ set(CMake_C11_THREAD_LOCAL_BROKEN 1)
+ endif()
+endif()
diff --git a/Source/Checks/cm_cxx14_check.cmake b/Source/Checks/cm_cxx14_check.cmake
new file mode 100644
index 0000000..e5656bf
--- /dev/null
+++ b/Source/Checks/cm_cxx14_check.cmake
@@ -0,0 +1,40 @@
+set(CMake_CXX14_BROKEN 0)
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|PGI|Intel")
+ if(NOT CMAKE_CXX14_STANDARD_COMPILE_OPTION)
+ set(CMake_CXX14_WORKS 0)
+ endif()
+ if(NOT DEFINED CMake_CXX14_WORKS)
+ include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake)
+ cm_message_checks_compat(
+ "Checking if compiler supports needed C++14 constructs"
+ __checkStart __checkPass __checkFail)
+ message(${__checkStart})
+ try_compile(CMake_CXX14_WORKS
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_LIST_DIR}/cm_cxx14_check.cpp
+ CMAKE_FLAGS -DCMAKE_CXX_STANDARD=14
+ OUTPUT_VARIABLE OUTPUT
+ )
+ if(CMake_CXX14_WORKS AND "${OUTPUT}" MATCHES "error: no member named.*gets.*in the global namespace")
+ set_property(CACHE CMake_CXX14_WORKS PROPERTY VALUE 0)
+ endif()
+ if(CMake_CXX14_WORKS)
+ message(${__checkPass} "yes")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if compiler supports needed C++14 constructs passed with the following output:\n"
+ "${OUTPUT}\n"
+ "\n"
+ )
+ else()
+ message(${__checkFail} "no")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if compiler supports needed C++14 constructs failed with the following output:\n"
+ "${OUTPUT}\n"
+ "\n"
+ )
+ endif()
+ endif()
+ if(NOT CMake_CXX14_WORKS)
+ set(CMake_CXX14_BROKEN 1)
+ endif()
+endif()
diff --git a/Source/Checks/cm_cxx14_check.cpp b/Source/Checks/cm_cxx14_check.cpp
new file mode 100644
index 0000000..fff36c9
--- /dev/null
+++ b/Source/Checks/cm_cxx14_check.cpp
@@ -0,0 +1,15 @@
+#include <cstdio>
+#include <iterator>
+#include <memory>
+
+int main()
+{
+ int a[] = { 0, 1, 2 };
+ auto ai = std::cbegin(a);
+
+ int b[] = { 2, 1, 0 };
+ auto bi = std::cend(b);
+
+ std::unique_ptr<int> u(new int(0));
+ return *u + *ai + *(bi - 1);
+}
diff --git a/Source/Checks/cm_cxx17_check.cmake b/Source/Checks/cm_cxx17_check.cmake
new file mode 100644
index 0000000..dba3eaf
--- /dev/null
+++ b/Source/Checks/cm_cxx17_check.cmake
@@ -0,0 +1,40 @@
+set(CMake_CXX17_BROKEN 0)
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|PGI|Intel")
+ if(NOT CMAKE_CXX17_STANDARD_COMPILE_OPTION)
+ set(CMake_CXX17_WORKS 0)
+ endif()
+ if(NOT DEFINED CMake_CXX17_WORKS)
+ include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake)
+ cm_message_checks_compat(
+ "Checking if compiler supports needed C++17 constructs"
+ __checkStart __checkPass __checkFail)
+ message(${__checkStart})
+ try_compile(CMake_CXX17_WORKS
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_LIST_DIR}/cm_cxx17_check.cpp
+ CMAKE_FLAGS -DCMAKE_CXX_STANDARD=17
+ OUTPUT_VARIABLE OUTPUT
+ )
+ if(CMake_CXX17_WORKS AND "${OUTPUT}" MATCHES "error: no member named.*gets.*in the global namespace")
+ set_property(CACHE CMake_CXX17_WORKS PROPERTY VALUE 0)
+ endif()
+ if(CMake_CXX17_WORKS)
+ message(${__checkPass} "yes")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if compiler supports needed C++17 constructs passed with the following output:\n"
+ "${OUTPUT}\n"
+ "\n"
+ )
+ else()
+ message(${__checkFail} "no")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if compiler supports needed C++17 constructs failed with the following output:\n"
+ "${OUTPUT}\n"
+ "\n"
+ )
+ endif()
+ endif()
+ if(NOT CMake_CXX17_WORKS)
+ set(CMake_CXX17_BROKEN 1)
+ endif()
+endif()
diff --git a/Source/Checks/cm_cxx17_check.cpp b/Source/Checks/cm_cxx17_check.cpp
new file mode 100644
index 0000000..abbe22c
--- /dev/null
+++ b/Source/Checks/cm_cxx17_check.cpp
@@ -0,0 +1,44 @@
+#include <cstdio>
+#include <iterator>
+#include <memory>
+#include <optional>
+#include <unordered_map>
+
+#ifdef _MSC_VER
+# include <comdef.h>
+#endif
+
+template <typename T,
+ typename std::invoke_result<decltype(&T::get), T>::type = nullptr>
+typename T::pointer get_ptr(T& item)
+{
+ return item.get();
+}
+
+int main()
+{
+ int a[] = { 0, 1, 2 };
+ auto ai = std::cbegin(a);
+
+ int b[] = { 2, 1, 0 };
+ auto bi = std::cend(b);
+
+ auto ci = std::size(a);
+
+ std::unique_ptr<int> u(new int(0));
+
+ // Intel compiler do not handle correctly 'decltype' inside 'invoke_result'
+ get_ptr(u);
+
+#ifdef _MSC_VER
+ // clang-cl has problems instantiating this constructor in C++17 mode
+ // error: indirection requires pointer operand ('const _GUID' invalid)
+ // return *_IID;
+ IUnknownPtr ptr{};
+ IDispatchPtr disp(ptr);
+#endif
+
+ std::optional<int> oi = 0;
+
+ return *u + *ai + *(bi - 1) + (3 - static_cast<int>(ci)) + oi.value();
+}
diff --git a/Source/Checks/cm_cxx_features.cmake b/Source/Checks/cm_cxx_features.cmake
new file mode 100644
index 0000000..7917d41
--- /dev/null
+++ b/Source/Checks/cm_cxx_features.cmake
@@ -0,0 +1,93 @@
+include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake)
+
+function(cm_check_cxx_feature name)
+ set(TRY_RUN_FEATURE "${ARGN}")
+ string(TOUPPER ${name} FEATURE)
+ if(NOT DEFINED CMake_HAVE_CXX_${FEATURE})
+ cm_message_checks_compat(
+ "Checking if compiler supports C++ ${name}"
+ __checkStart __checkPass __checkFail)
+ message(${__checkStart})
+ if(CMAKE_CXX_STANDARD)
+ set(maybe_cxx_standard -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD})
+ else()
+ set(maybe_cxx_standard "")
+ endif()
+ if (TRY_RUN_FEATURE)
+ try_run(CMake_RUN_CXX_${FEATURE} CMake_COMPILE_CXX_${FEATURE}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_LIST_DIR}/cm_cxx_${name}.cxx
+ CMAKE_FLAGS ${maybe_cxx_standard}
+ OUTPUT_VARIABLE OUTPUT
+ )
+ if (CMake_RUN_CXX_${FEATURE} EQUAL "0" AND CMake_COMPILE_CXX_${FEATURE})
+ set(CMake_HAVE_CXX_${FEATURE} ON CACHE INTERNAL "TRY_RUN" FORCE)
+ else()
+ set(CMake_HAVE_CXX_${FEATURE} OFF CACHE INTERNAL "TRY_RUN" FORCE)
+ endif()
+ else()
+ try_compile(CMake_HAVE_CXX_${FEATURE}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_LIST_DIR}/cm_cxx_${name}.cxx
+ CMAKE_FLAGS ${maybe_cxx_standard}
+ OUTPUT_VARIABLE OUTPUT
+ )
+ endif()
+ set(check_output "${OUTPUT}")
+ # Filter out MSBuild output that looks like a warning.
+ string(REGEX REPLACE " +0 Warning\\(s\\)" "" check_output "${check_output}")
+ # Filter out MSBuild output that looks like a warning.
+ string(REGEX REPLACE "[^\n]*warning MSB[0-9][0-9][0-9][0-9][^\n]*" "" check_output "${check_output}")
+ # Filter out warnings caused by user flags.
+ string(REGEX REPLACE "[^\n]*warning:[^\n]*-Winvalid-command-line-argument[^\n]*" "" check_output "${check_output}")
+ # Filter out warnings caused by local configuration.
+ string(REGEX REPLACE "[^\n]*warning:[^\n]*directory not found for option[^\n]*" "" check_output "${check_output}")
+ string(REGEX REPLACE "[^\n]*warning:[^\n]*object file compiled with -mlong-branch which is no longer needed[^\n]*" "" check_output "${check_output}")
+ # Filter out other warnings unrelated to feature checks.
+ string(REGEX REPLACE "[^\n]*warning:[^\n]*sprintf\\(\\) is often misused, please use snprintf[^\n]*" "" check_output "${check_output}")
+ # Filter out libhugetlbfs warnings.
+ string(REGEX REPLACE "[^\n]*libhugetlbfs [^\n]*: WARNING[^\n]*" "" check_output "${check_output}")
+ # Filter out xcodebuild warnings.
+ string(REGEX REPLACE "[^\n]* xcodebuild\\[[0-9]*:[0-9]*\\] warning: [^\n]*" "" check_output "${check_output}")
+ # Filter out icpc warnings
+ string(REGEX REPLACE "[^\n]*icpc: command line warning #10121: overriding [^\n]*" "" check_output "${check_output}")
+ # Filter out ld warnings.
+ string(REGEX REPLACE "[^\n]*ld: warning: [^\n]*" "" check_output "${check_output}")
+ # If using the feature causes warnings, treat it as broken/unavailable.
+ if(check_output MATCHES "(^|[ :])[Ww][Aa][Rr][Nn][Ii][Nn][Gg]")
+ set(CMake_HAVE_CXX_${FEATURE} OFF CACHE INTERNAL "TRY_COMPILE" FORCE)
+ endif()
+ if(CMake_HAVE_CXX_${FEATURE})
+ message(${__checkPass} "yes")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if compiler supports C++ ${name} passed with the following output:\n"
+ "${OUTPUT}\n"
+ "\n"
+ )
+ else()
+ message(${__checkFail} "no")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if compiler supports C++ ${name} failed with the following output:\n"
+ "${OUTPUT}\n"
+ "\n"
+ )
+ endif()
+ endif()
+endfunction()
+
+cm_check_cxx_feature(make_unique)
+if(CMake_HAVE_CXX_MAKE_UNIQUE)
+ set(CMake_HAVE_CXX_UNIQUE_PTR 1)
+endif()
+cm_check_cxx_feature(unique_ptr)
+if (NOT CMAKE_CXX_STANDARD LESS "17")
+ if (NOT CMAKE_CROSSCOMPILING OR CMAKE_CROSSCOMPILING_EMULATOR)
+ cm_check_cxx_feature(filesystem TRY_RUN)
+ else()
+ # In cross-compiling mode, it is not possible to check implementation bugs
+ # so rely only on conformance done by compilation
+ cm_check_cxx_feature(filesystem)
+ endif()
+else()
+ set(CMake_HAVE_CXX_FILESYSTEM FALSE)
+endif()
diff --git a/Source/Checks/cm_cxx_filesystem.cxx b/Source/Checks/cm_cxx_filesystem.cxx
new file mode 100644
index 0000000..ae8acc5
--- /dev/null
+++ b/Source/Checks/cm_cxx_filesystem.cxx
@@ -0,0 +1,27 @@
+
+#include <filesystem>
+
+int main()
+{
+ std::filesystem::path p0(L"/a/b/c");
+
+ std::filesystem::path p1("/a/b/c");
+ std::filesystem::path p2("/a/b/c");
+ if (p1 != p2) {
+ return 1;
+ }
+
+#if defined(_WIN32)
+ std::filesystem::path p3("//host/a/b/../c");
+ if (p3.lexically_normal().generic_string() != "//host/a/c") {
+ return 1;
+ }
+
+ std::filesystem::path p4("c://a/.///b/../");
+ if (p4.lexically_normal().generic_string() != "c:/a/") {
+ return 1;
+ }
+#endif
+
+ return 0;
+}
diff --git a/Source/Checks/cm_cxx_make_unique.cxx b/Source/Checks/cm_cxx_make_unique.cxx
new file mode 100644
index 0000000..a3ff68f
--- /dev/null
+++ b/Source/Checks/cm_cxx_make_unique.cxx
@@ -0,0 +1,6 @@
+#include <memory>
+int main()
+{
+ std::unique_ptr<int> u = std::make_unique<int>(0);
+ return *u;
+}
diff --git a/Source/Checks/cm_cxx_unique_ptr.cxx b/Source/Checks/cm_cxx_unique_ptr.cxx
new file mode 100644
index 0000000..a9d4ce5
--- /dev/null
+++ b/Source/Checks/cm_cxx_unique_ptr.cxx
@@ -0,0 +1,6 @@
+#include <memory>
+int main()
+{
+ std::unique_ptr<int> u(new int(0));
+ return *u;
+}
diff --git a/Source/Checks/cm_message_checks_compat.cmake b/Source/Checks/cm_message_checks_compat.cmake
new file mode 100644
index 0000000..024c397
--- /dev/null
+++ b/Source/Checks/cm_message_checks_compat.cmake
@@ -0,0 +1,13 @@
+# Supporting using the CHECK_... message modes if available
+# and fall back to the older behavior if not
+macro(cm_message_checks_compat description startVar passVar failVar)
+ if(CMAKE_VERSION VERSION_GREATER 3.16.2019)
+ set(${startVar} CHECK_START "${description}")
+ set(${passVar} CHECK_PASS)
+ set(${failVar} CHECK_FAIL)
+ else()
+ set(${startVar} STATUS "${description}")
+ set(${passVar} STATUS "${description} - ")
+ set(${failVar} STATUS "${description} - ")
+ endif()
+endmacro()
diff --git a/Source/CursesDialog/.NoDartCoverage b/Source/CursesDialog/.NoDartCoverage
new file mode 100644
index 0000000..3c99729
--- /dev/null
+++ b/Source/CursesDialog/.NoDartCoverage
@@ -0,0 +1 @@
+# do not do coverage in this directory
diff --git a/Source/CursesDialog/CMakeLists.txt b/Source/CursesDialog/CMakeLists.txt
new file mode 100644
index 0000000..c24ee76
--- /dev/null
+++ b/Source/CursesDialog/CMakeLists.txt
@@ -0,0 +1,63 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+add_executable(ccmake
+ ccmake.cxx
+ cmCursesBoolWidget.cxx
+ cmCursesCacheEntryComposite.cxx
+ cmCursesColor.cxx
+ cmCursesDummyWidget.cxx
+ cmCursesFilePathWidget.cxx
+ cmCursesForm.cxx
+ cmCursesLabelWidget.cxx
+ cmCursesLongMessageForm.cxx
+ cmCursesMainForm.cxx
+ cmCursesOptionsWidget.cxx
+ cmCursesPathWidget.cxx
+ cmCursesStringWidget.cxx
+ cmCursesWidget.cxx
+ )
+target_include_directories(ccmake PRIVATE ${CURSES_INCLUDE_PATH})
+set(CMAKE_REQUIRED_INCLUDES ${CURSES_INCLUDE_PATH})
+target_link_libraries(ccmake CMakeLib)
+if(CMAKE_USE_SYSTEM_FORM)
+ find_path(CURSES_FORM_INCLUDE_DIR NAMES form.h HINTS ${CURSES_INCLUDE_PATH} ${CURSES_INCLUDE_PATH}/ncurses)
+ if(CURSES_FORM_INCLUDE_DIR)
+ target_include_directories(ccmake PRIVATE ${CURSES_FORM_INCLUDE_DIR})
+ list(APPEND CMAKE_REQUIRED_INCLUDES ${CURSES_FORM_INCLUDE_DIR})
+ endif()
+ target_link_libraries(ccmake
+ ${CURSES_FORM_LIBRARY}
+ ${CURSES_LIBRARY}
+ )
+ set(CMAKE_REQUIRED_LIBRARIES
+ ${CURSES_FORM_LIBRARY}
+ ${CURSES_LIBRARY}
+ )
+ if(CURSES_EXTRA_LIBRARY)
+ target_link_libraries(ccmake ${CURSES_EXTRA_LIBRARY})
+ list(APPEND CMAKE_REQUIRED_LIBRARIES ${CURSES_EXTRA_LIBRARY})
+ endif()
+else()
+ target_link_libraries(ccmake cmForm)
+ get_target_property(cmFormIncludeDirs cmForm INTERFACE_INCLUDE_DIRECTORIES)
+ list(APPEND CMAKE_REQUIRED_INCLUDES ${cmFormIncludeDirs})
+ get_target_property(cmFormLibraries cmForm INTERFACE_LINK_LIBRARIES)
+ set(CMAKE_REQUIRED_LIBRARIES ${cmFormLibraries})
+endif()
+
+include(CheckSymbolExists)
+check_symbol_exists(use_default_colors
+ "form.h"
+ HAVE_CURSES_USE_DEFAULT_COLORS)
+if(HAVE_CURSES_USE_DEFAULT_COLORS)
+ set_source_files_properties(cmCursesColor.cxx
+ PROPERTIES COMPILE_DEFINITIONS HAVE_CURSES_USE_DEFAULT_COLORS)
+endif()
+
+if(CMake_JOB_POOL_LINK_BIN)
+ set_property(TARGET ccmake PROPERTY JOB_POOL_LINK "link-bin")
+endif()
+
+CMake_OPTIONAL_COMPONENT(ccmake)
+install(TARGETS ccmake DESTINATION ${CMAKE_BIN_DIR} ${COMPONENT})
diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
new file mode 100644
index 0000000..85e256b
--- /dev/null
+++ b/Source/CursesDialog/ccmake.cxx
@@ -0,0 +1,212 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <csignal>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <unistd.h>
+
+#include "cmsys/Encoding.hxx"
+
+#include "cmCursesColor.h"
+#include "cmCursesForm.h"
+#include "cmCursesMainForm.h"
+#include "cmCursesStandardIncludes.h"
+#include "cmDocumentation.h"
+#include "cmDocumentationEntry.h" // IWYU pragma: keep
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+static const char* cmDocumentationName[][2] = {
+ { nullptr, " ccmake - Curses Interface for CMake." },
+ { nullptr, nullptr }
+};
+
+static const char* cmDocumentationUsage[][2] = {
+ { nullptr,
+ " ccmake <path-to-source>\n"
+ " ccmake <path-to-existing-build>" },
+ { nullptr,
+ "Specify a source directory to (re-)generate a build system for "
+ "it in the current working directory. Specify an existing build "
+ "directory to re-generate its build system." },
+ { nullptr, nullptr }
+};
+
+static const char* cmDocumentationUsageNote[][2] = {
+ { nullptr, "Run 'ccmake --help' for more information." },
+ { nullptr, nullptr }
+};
+
+static const char* cmDocumentationOptions[][2] = {
+ CMAKE_STANDARD_OPTIONS_TABLE,
+ { nullptr, nullptr }
+};
+
+cmCursesForm* cmCursesForm::CurrentForm = nullptr;
+
+extern "C" {
+
+void onsig(int /*unused*/)
+{
+ if (cmCursesForm::CurrentForm) {
+ endwin();
+ if (initscr() == nullptr) {
+ static const char errmsg[] = "Error: ncurses initialization failed\n";
+ auto r = write(STDERR_FILENO, errmsg, sizeof(errmsg) - 1);
+ static_cast<void>(r);
+ exit(1);
+ }
+ noecho(); /* Echo off */
+ cbreak(); /* nl- or cr not needed */
+ keypad(stdscr, true); /* Use key symbols as KEY_DOWN */
+ refresh();
+ int x;
+ int y;
+ getmaxyx(stdscr, y, x);
+ cmCursesForm::CurrentForm->Render(1, 1, x, y);
+ cmCursesForm::CurrentForm->UpdateStatusBar();
+ }
+ signal(SIGWINCH, onsig);
+}
+}
+
+int main(int argc, char const* const* argv)
+{
+ cmSystemTools::EnsureStdPipes();
+ cmsys::Encoding::CommandLineArguments encoding_args =
+ cmsys::Encoding::CommandLineArguments::Main(argc, argv);
+ argc = encoding_args.argc();
+ argv = encoding_args.argv();
+
+ cmSystemTools::InitializeLibUV();
+ cmSystemTools::FindCMakeResources(argv[0]);
+ cmDocumentation doc;
+ doc.addCMakeStandardDocSections();
+ if (doc.CheckOptions(argc, argv)) {
+ cmake hcm(cmake::RoleInternal, cmState::Unknown);
+ hcm.SetHomeDirectory("");
+ hcm.SetHomeOutputDirectory("");
+ hcm.AddCMakePaths();
+ auto generators = hcm.GetGeneratorsDocumentation();
+ doc.SetName("ccmake");
+ doc.SetSection("Name", cmDocumentationName);
+ doc.SetSection("Usage", cmDocumentationUsage);
+ if (argc == 1) {
+ doc.AppendSection("Usage", cmDocumentationUsageNote);
+ }
+ doc.AppendSection("Generators", generators);
+ doc.PrependSection("Options", cmDocumentationOptions);
+ return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
+ }
+
+ bool debug = false;
+ unsigned int i;
+ int j;
+ std::vector<std::string> args;
+ for (j = 0; j < argc; ++j) {
+ if (strcmp(argv[j], "-debug") == 0) {
+ debug = true;
+ } else {
+ args.emplace_back(argv[j]);
+ }
+ }
+
+ std::string cacheDir = cmSystemTools::GetCurrentWorkingDirectory();
+ for (i = 1; i < args.size(); ++i) {
+ std::string const& arg = args[i];
+ if (cmHasPrefix(arg, "-B")) {
+ cacheDir = arg.substr(2);
+ }
+ }
+
+ cmSystemTools::DisableRunCommandOutput();
+
+ if (debug) {
+ cmCursesForm::DebugStart();
+ }
+
+ if (initscr() == nullptr) {
+ fprintf(stderr, "Error: ncurses initialization failed\n");
+ exit(1);
+ }
+ noecho(); /* Echo off */
+ cbreak(); /* nl- or cr not needed */
+ keypad(stdscr, true); /* Use key symbols as KEY_DOWN */
+ cmCursesColor::InitColors();
+
+ signal(SIGWINCH, onsig);
+
+ int x;
+ int y;
+ getmaxyx(stdscr, y, x);
+ if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) {
+ endwin();
+ std::cerr << "Window is too small. A size of at least "
+ << cmCursesMainForm::MIN_WIDTH << " x "
+ << cmCursesMainForm::MIN_HEIGHT << " is required to run ccmake."
+ << std::endl;
+ return 1;
+ }
+
+ cmCursesMainForm* myform;
+
+ myform = new cmCursesMainForm(args, x);
+ if (myform->LoadCache(cacheDir.c_str())) {
+ curses_clear();
+ touchwin(stdscr);
+ endwin();
+ delete myform;
+ std::cerr << "Error running cmake::LoadCache(). Aborting.\n";
+ return 1;
+ }
+
+ /*
+ * The message is stored in a list by the form which will be
+ * joined by '\n' before display.
+ * Removing any trailing '\n' avoid extra empty lines in the final results
+ */
+ auto cleanMessage = [](const std::string& message) -> std::string {
+ auto msg = message;
+ if (!msg.empty() && msg.back() == '\n') {
+ msg.pop_back();
+ }
+ return msg;
+ };
+ cmSystemTools::SetMessageCallback(
+ [&](const std::string& message, const char* title) {
+ myform->AddError(cleanMessage(message), title);
+ });
+ cmSystemTools::SetStderrCallback([&](const std::string& message) {
+ myform->AddError(cleanMessage(message), "");
+ });
+ cmSystemTools::SetStdoutCallback([&](const std::string& message) {
+ myform->UpdateProgress(cleanMessage(message), -1);
+ });
+
+ cmCursesForm::CurrentForm = myform;
+
+ myform->InitializeUI();
+ if (myform->Configure(1) == 0) {
+ myform->Render(1, 1, x, y);
+ myform->HandleInput();
+ }
+
+ // Need to clean-up better
+ curses_clear();
+ touchwin(stdscr);
+ endwin();
+ delete cmCursesForm::CurrentForm;
+ cmCursesForm::CurrentForm = nullptr;
+
+ std::cout << std::endl << std::endl;
+
+ return 0;
+}
diff --git a/Source/CursesDialog/cmCursesBoolWidget.cxx b/Source/CursesDialog/cmCursesBoolWidget.cxx
new file mode 100644
index 0000000..c4dbed8
--- /dev/null
+++ b/Source/CursesDialog/cmCursesBoolWidget.cxx
@@ -0,0 +1,64 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCursesBoolWidget.h"
+
+#include <string>
+
+#include "cmCursesColor.h"
+#include "cmCursesWidget.h"
+#include "cmStateTypes.h"
+
+cmCursesBoolWidget::cmCursesBoolWidget(int width, int height, int left,
+ int top)
+ : cmCursesWidget(width, height, left, top)
+{
+ this->Type = cmStateEnums::BOOL;
+ if (!cmCursesColor::HasColors()) {
+ set_field_fore(this->Field, A_NORMAL);
+ set_field_back(this->Field, A_STANDOUT);
+ }
+ field_opts_off(this->Field, O_STATIC);
+ this->SetValueAsBool(false);
+}
+
+bool cmCursesBoolWidget::HandleInput(int& key, cmCursesMainForm* /*fm*/,
+ WINDOW* w)
+{
+
+ // toggle boolean values with enter or space
+ // 10 == enter
+ if (key == 10 || key == KEY_ENTER || key == ' ') {
+ if (this->GetValueAsBool()) {
+ this->SetValueAsBool(false);
+ } else {
+ this->SetValueAsBool(true);
+ }
+
+ touchwin(w);
+ wrefresh(w);
+ return true;
+ }
+ return false;
+}
+
+void cmCursesBoolWidget::SetValueAsBool(bool value)
+{
+ if (value) {
+ this->SetValue("ON");
+ if (cmCursesColor::HasColors()) {
+ set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::BoolOn));
+ set_field_back(this->Field, COLOR_PAIR(cmCursesColor::BoolOn));
+ }
+ } else {
+ this->SetValue("OFF");
+ if (cmCursesColor::HasColors()) {
+ set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::BoolOff));
+ set_field_back(this->Field, COLOR_PAIR(cmCursesColor::BoolOff));
+ }
+ }
+}
+
+bool cmCursesBoolWidget::GetValueAsBool()
+{
+ return this->Value == "ON";
+}
diff --git a/Source/CursesDialog/cmCursesBoolWidget.h b/Source/CursesDialog/cmCursesBoolWidget.h
new file mode 100644
index 0000000..746825b
--- /dev/null
+++ b/Source/CursesDialog/cmCursesBoolWidget.h
@@ -0,0 +1,30 @@
+/* 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 "cmCursesStandardIncludes.h"
+#include "cmCursesWidget.h"
+
+class cmCursesMainForm;
+
+class cmCursesBoolWidget : public cmCursesWidget
+{
+public:
+ cmCursesBoolWidget(int width, int height, int left, int top);
+
+ cmCursesBoolWidget(cmCursesBoolWidget const&) = delete;
+ cmCursesBoolWidget& operator=(cmCursesBoolWidget const&) = delete;
+
+ // Description:
+ // Handle user input. Called by the container of this widget
+ // when this widget has focus. Returns true if the input was
+ // handled.
+ bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) override;
+
+ // Description:
+ // Set/Get the value (on/off).
+ void SetValueAsBool(bool value);
+ bool GetValueAsBool();
+};
diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
new file mode 100644
index 0000000..35f09fd
--- /dev/null
+++ b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
@@ -0,0 +1,109 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCursesCacheEntryComposite.h"
+
+#include <cassert>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmCursesBoolWidget.h"
+#include "cmCursesFilePathWidget.h"
+#include "cmCursesLabelWidget.h"
+#include "cmCursesOptionsWidget.h"
+#include "cmCursesPathWidget.h"
+#include "cmCursesStringWidget.h"
+#include "cmCursesWidget.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmCursesCacheEntryComposite::cmCursesCacheEntryComposite(
+ const std::string& key, int labelwidth, int entrywidth)
+ : Key(key)
+ , LabelWidth(labelwidth)
+ , EntryWidth(entrywidth)
+{
+ this->Label =
+ cm::make_unique<cmCursesLabelWidget>(this->LabelWidth, 1, 1, 1, key);
+ this->IsNewLabel = cm::make_unique<cmCursesLabelWidget>(1, 1, 1, 1, " ");
+ this->Entry =
+ cm::make_unique<cmCursesStringWidget>(this->EntryWidth, 1, 1, 1);
+}
+
+cmCursesCacheEntryComposite::cmCursesCacheEntryComposite(
+ const std::string& key, cmState* state, bool isNew, int labelwidth,
+ int entrywidth)
+ : Key(key)
+ , LabelWidth(labelwidth)
+ , EntryWidth(entrywidth)
+{
+ this->Label =
+ cm::make_unique<cmCursesLabelWidget>(this->LabelWidth, 1, 1, 1, key);
+ if (isNew) {
+ this->IsNewLabel = cm::make_unique<cmCursesLabelWidget>(1, 1, 1, 1, "*");
+ } else {
+ this->IsNewLabel = cm::make_unique<cmCursesLabelWidget>(1, 1, 1, 1, " ");
+ }
+
+ cmProp value = state->GetCacheEntryValue(key);
+ assert(value);
+ switch (state->GetCacheEntryType(key)) {
+ case cmStateEnums::BOOL: {
+ auto bw = cm::make_unique<cmCursesBoolWidget>(this->EntryWidth, 1, 1, 1);
+ bw->SetValueAsBool(cmIsOn(*value));
+ this->Entry = std::move(bw);
+ break;
+ }
+ case cmStateEnums::PATH: {
+ auto pw = cm::make_unique<cmCursesPathWidget>(this->EntryWidth, 1, 1, 1);
+ pw->SetString(*value);
+ this->Entry = std::move(pw);
+ break;
+ }
+ case cmStateEnums::FILEPATH: {
+ auto fpw =
+ cm::make_unique<cmCursesFilePathWidget>(this->EntryWidth, 1, 1, 1);
+ fpw->SetString(*value);
+ this->Entry = std::move(fpw);
+ break;
+ }
+ case cmStateEnums::STRING: {
+ cmProp stringsProp = state->GetCacheEntryProperty(key, "STRINGS");
+ if (stringsProp) {
+ auto ow =
+ cm::make_unique<cmCursesOptionsWidget>(this->EntryWidth, 1, 1, 1);
+ for (std::string const& opt : cmExpandedList(*stringsProp)) {
+ ow->AddOption(opt);
+ }
+ ow->SetOption(*value);
+ this->Entry = std::move(ow);
+ } else {
+ auto sw =
+ cm::make_unique<cmCursesStringWidget>(this->EntryWidth, 1, 1, 1);
+ sw->SetString(*value);
+ this->Entry = std::move(sw);
+ }
+ break;
+ }
+ case cmStateEnums::UNINITIALIZED:
+ cmSystemTools::Error("Found an undefined variable: " + key);
+ break;
+ default:
+ // TODO : put warning message here
+ break;
+ }
+}
+
+cmCursesCacheEntryComposite::~cmCursesCacheEntryComposite() = default;
+
+const char* cmCursesCacheEntryComposite::GetValue()
+{
+ if (this->Label) {
+ return this->Label->GetValue();
+ }
+ return nullptr;
+}
diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.h b/Source/CursesDialog/cmCursesCacheEntryComposite.h
new file mode 100644
index 0000000..d414918
--- /dev/null
+++ b/Source/CursesDialog/cmCursesCacheEntryComposite.h
@@ -0,0 +1,42 @@
+/* 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 <memory>
+#include <string>
+
+class cmCursesLabelWidget;
+class cmCursesWidget;
+class cmState;
+
+class cmCursesCacheEntryComposite
+{
+public:
+ cmCursesCacheEntryComposite(const std::string& key, int labelwidth,
+ int entrywidth);
+ cmCursesCacheEntryComposite(const std::string& key, cmState* state,
+ bool isNew, int labelwidth, int entrywidth);
+ ~cmCursesCacheEntryComposite();
+
+ cmCursesCacheEntryComposite(cmCursesCacheEntryComposite const&) = delete;
+ cmCursesCacheEntryComposite& operator=(cmCursesCacheEntryComposite const&) =
+ delete;
+
+ cmCursesCacheEntryComposite(cmCursesCacheEntryComposite&&) = default;
+ cmCursesCacheEntryComposite& operator=(cmCursesCacheEntryComposite&&) =
+ default;
+
+ const char* GetValue();
+
+ friend class cmCursesMainForm;
+
+protected:
+ std::unique_ptr<cmCursesLabelWidget> Label;
+ std::unique_ptr<cmCursesLabelWidget> IsNewLabel;
+ std::unique_ptr<cmCursesWidget> Entry;
+ std::string Key;
+ int LabelWidth;
+ int EntryWidth;
+};
diff --git a/Source/CursesDialog/cmCursesColor.cxx b/Source/CursesDialog/cmCursesColor.cxx
new file mode 100644
index 0000000..c0b468b
--- /dev/null
+++ b/Source/CursesDialog/cmCursesColor.cxx
@@ -0,0 +1,78 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCursesColor.h"
+
+#include <cctype>
+#include <cstdlib>
+#include <cstring>
+#include <unordered_map>
+#include <utility>
+
+#include "cmCursesStandardIncludes.h"
+
+bool cmCursesColor::HasColors()
+{
+#ifdef HAVE_CURSES_USE_DEFAULT_COLORS
+ return has_colors();
+#else
+ return false;
+#endif
+}
+
+void cmCursesColor::InitColors()
+{
+#ifdef HAVE_CURSES_USE_DEFAULT_COLORS
+ if (HasColors()) {
+ start_color();
+ use_default_colors();
+ init_pair(BoolOff, GetColor('N', COLOR_RED), -1);
+ init_pair(BoolOn, GetColor('Y', COLOR_GREEN), -1);
+ init_pair(String, GetColor('S', COLOR_CYAN), -1);
+ init_pair(Path, GetColor('P', COLOR_YELLOW), -1);
+ init_pair(Choice, GetColor('C', COLOR_MAGENTA), -1);
+ }
+#endif
+}
+
+short cmCursesColor::GetColor(char id, short fallback)
+{
+ static bool initialized = false;
+ static std::unordered_map<char, short> env;
+
+ if (!initialized) {
+ if (auto* v = getenv("CCMAKE_COLORS")) {
+ while (v[0] && v[1] && v[1] == '=') {
+ auto const n = std::toupper(*v);
+
+ char buffer[12];
+ memset(buffer, 0, sizeof(buffer));
+
+ if (auto* const e = strchr(v, ':')) {
+ if (static_cast<size_t>(e - v) > sizeof(buffer)) {
+ break;
+ }
+
+ strncpy(buffer, v + 2, static_cast<size_t>(e - v - 2));
+ v = e + 1;
+ } else {
+ auto const l = strlen(v);
+ if (l > sizeof(buffer)) {
+ break;
+ }
+
+ strncpy(buffer, v + 2, l - 2);
+ v += l;
+ }
+
+ auto const c = atoi(buffer);
+ if (c && c < COLORS) {
+ env.emplace(n, static_cast<short>(c));
+ }
+ }
+ }
+ initialized = true;
+ }
+
+ auto const iter = env.find(id);
+ return (iter == env.end() ? fallback : iter->second);
+}
diff --git a/Source/CursesDialog/cmCursesColor.h b/Source/CursesDialog/cmCursesColor.h
new file mode 100644
index 0000000..4e8a1e4
--- /dev/null
+++ b/Source/CursesDialog/cmCursesColor.h
@@ -0,0 +1,24 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+class cmCursesColor
+{
+public:
+ enum Color
+ {
+ // Default color is pair 0
+ BoolOff = 1,
+ BoolOn,
+ String,
+ Path,
+ Choice
+ };
+
+ static bool HasColors();
+
+ static void InitColors();
+
+protected:
+ static short GetColor(char id, short fallback);
+};
diff --git a/Source/CursesDialog/cmCursesDummyWidget.cxx b/Source/CursesDialog/cmCursesDummyWidget.cxx
new file mode 100644
index 0000000..da0478a
--- /dev/null
+++ b/Source/CursesDialog/cmCursesDummyWidget.cxx
@@ -0,0 +1,19 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCursesDummyWidget.h"
+
+#include "cmCursesWidget.h"
+#include "cmStateTypes.h"
+
+cmCursesDummyWidget::cmCursesDummyWidget(int width, int height, int left,
+ int top)
+ : cmCursesWidget(width, height, left, top)
+{
+ this->Type = cmStateEnums::INTERNAL;
+}
+
+bool cmCursesDummyWidget::HandleInput(int& /*key*/, cmCursesMainForm* /*fm*/,
+ WINDOW* /*w*/)
+{
+ return false;
+}
diff --git a/Source/CursesDialog/cmCursesDummyWidget.h b/Source/CursesDialog/cmCursesDummyWidget.h
new file mode 100644
index 0000000..4347746
--- /dev/null
+++ b/Source/CursesDialog/cmCursesDummyWidget.h
@@ -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. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmCursesStandardIncludes.h"
+#include "cmCursesWidget.h"
+
+class cmCursesMainForm;
+
+class cmCursesDummyWidget : public cmCursesWidget
+{
+public:
+ cmCursesDummyWidget(int width, int height, int left, int top);
+
+ cmCursesDummyWidget(cmCursesDummyWidget const&) = delete;
+ cmCursesDummyWidget& operator=(cmCursesDummyWidget const&) = delete;
+
+ // Description:
+ // Handle user input. Called by the container of this widget
+ // when this widget has focus. Returns true if the input was
+ // handled.
+ bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) override;
+};
diff --git a/Source/CursesDialog/cmCursesFilePathWidget.cxx b/Source/CursesDialog/cmCursesFilePathWidget.cxx
new file mode 100644
index 0000000..518da4f
--- /dev/null
+++ b/Source/CursesDialog/cmCursesFilePathWidget.cxx
@@ -0,0 +1,13 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCursesFilePathWidget.h"
+
+#include "cmCursesPathWidget.h"
+#include "cmStateTypes.h"
+
+cmCursesFilePathWidget::cmCursesFilePathWidget(int width, int height, int left,
+ int top)
+ : cmCursesPathWidget(width, height, left, top)
+{
+ this->Type = cmStateEnums::FILEPATH;
+}
diff --git a/Source/CursesDialog/cmCursesFilePathWidget.h b/Source/CursesDialog/cmCursesFilePathWidget.h
new file mode 100644
index 0000000..2ae5d14
--- /dev/null
+++ b/Source/CursesDialog/cmCursesFilePathWidget.h
@@ -0,0 +1,16 @@
+/* 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 "cmCursesPathWidget.h"
+
+class cmCursesFilePathWidget : public cmCursesPathWidget
+{
+public:
+ cmCursesFilePathWidget(int width, int height, int left, int top);
+
+ cmCursesFilePathWidget(cmCursesFilePathWidget const&) = delete;
+ cmCursesFilePathWidget& operator=(cmCursesFilePathWidget const&) = delete;
+};
diff --git a/Source/CursesDialog/cmCursesForm.cxx b/Source/CursesDialog/cmCursesForm.cxx
new file mode 100644
index 0000000..bd65c4a
--- /dev/null
+++ b/Source/CursesDialog/cmCursesForm.cxx
@@ -0,0 +1,45 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCursesForm.h"
+
+cmsys::ofstream cmCursesForm::DebugFile;
+bool cmCursesForm::Debug = false;
+
+cmCursesForm::cmCursesForm()
+{
+ this->Form = nullptr;
+}
+
+cmCursesForm::~cmCursesForm()
+{
+ if (this->Form) {
+ unpost_form(this->Form);
+ free_form(this->Form);
+ this->Form = nullptr;
+ }
+}
+
+void cmCursesForm::DebugStart()
+{
+ cmCursesForm::Debug = true;
+ cmCursesForm::DebugFile.open("ccmakelog.txt");
+}
+
+void cmCursesForm::DebugEnd()
+{
+ if (!cmCursesForm::Debug) {
+ return;
+ }
+
+ cmCursesForm::Debug = false;
+ cmCursesForm::DebugFile.close();
+}
+
+void cmCursesForm::LogMessage(const char* msg)
+{
+ if (!cmCursesForm::Debug) {
+ return;
+ }
+
+ cmCursesForm::DebugFile << msg << std::endl;
+}
diff --git a/Source/CursesDialog/cmCursesForm.h b/Source/CursesDialog/cmCursesForm.h
new file mode 100644
index 0000000..93459b9
--- /dev/null
+++ b/Source/CursesDialog/cmCursesForm.h
@@ -0,0 +1,63 @@
+/* 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 <string>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmCursesStandardIncludes.h"
+
+class cmCursesForm
+{
+public:
+ cmCursesForm();
+ virtual ~cmCursesForm();
+
+ cmCursesForm(cmCursesForm const&) = delete;
+ cmCursesForm& operator=(cmCursesForm const&) = delete;
+
+ // Description:
+ // Handle user input.
+ virtual void HandleInput() = 0;
+
+ // Description:
+ // Display form.
+ virtual void Render(int left, int top, int width, int height) = 0;
+
+ // Description:
+ // This method should normally called only by the form.
+ // The only exception is during a resize.
+ virtual void UpdateStatusBar() = 0;
+
+ // Description:
+ // During a CMake run, an error handle should add errors
+ // to be displayed afterwards.
+ virtual void AddError(const std::string&, const char*) {}
+
+ // Description:
+ // Turn debugging on. This will create ccmakelog.txt.
+ static void DebugStart();
+
+ // Description:
+ // Turn debugging off. This will close ccmakelog.txt.
+ static void DebugEnd();
+
+ // Description:
+ // Write a debugging message.
+ static void LogMessage(const char* msg);
+
+ // Description:
+ // Return the FORM. Should be only used by low-level methods.
+ FORM* GetForm() { return this->Form; }
+
+ static cmCursesForm* CurrentForm;
+
+protected:
+ static cmsys::ofstream DebugFile;
+ static bool Debug;
+
+ FORM* Form;
+};
diff --git a/Source/CursesDialog/cmCursesLabelWidget.cxx b/Source/CursesDialog/cmCursesLabelWidget.cxx
new file mode 100644
index 0000000..83aea5a
--- /dev/null
+++ b/Source/CursesDialog/cmCursesLabelWidget.cxx
@@ -0,0 +1,24 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCursesLabelWidget.h"
+
+#include "cmCursesWidget.h"
+
+cmCursesLabelWidget::cmCursesLabelWidget(int width, int height, int left,
+ int top, const std::string& name)
+ : cmCursesWidget(width, height, left, top)
+{
+ field_opts_off(this->Field, O_EDIT);
+ field_opts_off(this->Field, O_ACTIVE);
+ field_opts_off(this->Field, O_STATIC);
+ this->SetValue(name);
+}
+
+cmCursesLabelWidget::~cmCursesLabelWidget() = default;
+
+bool cmCursesLabelWidget::HandleInput(int& /*key*/, cmCursesMainForm* /*fm*/,
+ WINDOW* /*w*/)
+{
+ // Static text. No input is handled here.
+ return false;
+}
diff --git a/Source/CursesDialog/cmCursesLabelWidget.h b/Source/CursesDialog/cmCursesLabelWidget.h
new file mode 100644
index 0000000..c10aa37
--- /dev/null
+++ b/Source/CursesDialog/cmCursesLabelWidget.h
@@ -0,0 +1,29 @@
+/* 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 <string>
+
+#include "cmCursesStandardIncludes.h"
+#include "cmCursesWidget.h"
+
+class cmCursesMainForm;
+
+class cmCursesLabelWidget : public cmCursesWidget
+{
+public:
+ cmCursesLabelWidget(int width, int height, int left, int top,
+ const std::string& name);
+ ~cmCursesLabelWidget() override;
+
+ cmCursesLabelWidget(cmCursesLabelWidget const&) = delete;
+ cmCursesLabelWidget& operator=(cmCursesLabelWidget const&) = delete;
+
+ // Description:
+ // Handle user input. Called by the container of this widget
+ // when this widget has focus. Returns true if the input was
+ // handled
+ bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) override;
+};
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx
new file mode 100644
index 0000000..591c546
--- /dev/null
+++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx
@@ -0,0 +1,200 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCursesLongMessageForm.h"
+
+#include <cstdio>
+#include <cstring>
+
+#include "cmCursesForm.h"
+#include "cmCursesMainForm.h"
+#include "cmCursesStandardIncludes.h"
+#include "cmStringAlgorithms.h"
+#include "cmVersion.h"
+
+inline int ctrl(int z)
+{
+ return (z & 037);
+}
+
+cmCursesLongMessageForm::cmCursesLongMessageForm(
+ std::vector<std::string> const& messages, const char* title,
+ ScrollBehavior scrollBehavior)
+ : Scrolling(scrollBehavior)
+{
+ // Append all messages into on big string
+ this->Messages = cmJoin(messages, "\n");
+ this->Title = title;
+ this->Fields[0] = nullptr;
+ this->Fields[1] = nullptr;
+}
+
+cmCursesLongMessageForm::~cmCursesLongMessageForm()
+{
+ if (this->Fields[0]) {
+ free_field(this->Fields[0]);
+ }
+}
+
+void cmCursesLongMessageForm::UpdateContent(std::string const& output,
+ std::string const& title)
+{
+ this->Title = title;
+
+ if (!output.empty() && this->Messages.size() < MAX_CONTENT_SIZE) {
+ this->Messages.push_back('\n');
+ this->Messages.append(output);
+ form_driver(this->Form, REQ_NEW_LINE);
+ this->DrawMessage(output.c_str());
+ }
+
+ this->UpdateStatusBar();
+ touchwin(stdscr);
+ refresh();
+}
+
+void cmCursesLongMessageForm::UpdateStatusBar()
+{
+ int x;
+ int y;
+ getmaxyx(stdscr, y, x);
+
+ char bar[cmCursesMainForm::MAX_WIDTH];
+ size_t size = this->Title.size();
+ if (size >= cmCursesMainForm::MAX_WIDTH) {
+ size = cmCursesMainForm::MAX_WIDTH - 1;
+ }
+ strncpy(bar, this->Title.c_str(), size);
+ for (size_t i = size; i < cmCursesMainForm::MAX_WIDTH; i++) {
+ bar[i] = ' ';
+ }
+ int width;
+ if (x >= 0 && x < cmCursesMainForm::MAX_WIDTH) {
+ width = x;
+ } else {
+ width = cmCursesMainForm::MAX_WIDTH - 1;
+ }
+
+ bar[width] = '\0';
+
+ char version[cmCursesMainForm::MAX_WIDTH];
+ char vertmp[128];
+ sprintf(vertmp, "CMake Version %s", cmVersion::GetCMakeVersion());
+ size_t sideSpace = (width - strlen(vertmp));
+ for (size_t i = 0; i < sideSpace; i++) {
+ version[i] = ' ';
+ }
+ sprintf(version + sideSpace, "%s", vertmp);
+ version[width] = '\0';
+
+ char fmt_s[] = "%s";
+ curses_move(y - 4, 0);
+ attron(A_STANDOUT);
+ printw(fmt_s, bar);
+ attroff(A_STANDOUT);
+ curses_move(y - 3, 0);
+ printw(fmt_s, version);
+ pos_form_cursor(this->Form);
+}
+
+void cmCursesLongMessageForm::PrintKeys()
+{
+ int x;
+ int y;
+ getmaxyx(stdscr, y, x);
+ if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) {
+ return;
+ }
+ char firstLine[512];
+ sprintf(firstLine, "Press [e] to exit screen");
+
+ char fmt_s[] = "%s";
+ curses_move(y - 2, 0);
+ printw(fmt_s, firstLine);
+ pos_form_cursor(this->Form);
+}
+
+void cmCursesLongMessageForm::Render(int /*left*/, int /*top*/, int /*width*/,
+ int /*height*/)
+{
+ int x;
+ int y;
+ getmaxyx(stdscr, y, x);
+
+ if (this->Form) {
+ unpost_form(this->Form);
+ free_form(this->Form);
+ this->Form = nullptr;
+ }
+
+ if (this->Fields[0]) {
+ free_field(this->Fields[0]);
+ this->Fields[0] = nullptr;
+ }
+
+ this->Fields[0] = new_field(y - 6, x - 2, 1, 1, 0, 0);
+
+ field_opts_off(this->Fields[0], O_STATIC);
+
+ this->Form = new_form(this->Fields);
+ post_form(this->Form);
+
+ form_driver(this->Form, REQ_BEG_FIELD);
+ this->DrawMessage(this->Messages.c_str());
+
+ this->UpdateStatusBar();
+ touchwin(stdscr);
+ refresh();
+}
+
+void cmCursesLongMessageForm::DrawMessage(const char* msg) const
+{
+ int i = 0;
+ while (msg[i] != '\0' && i < MAX_CONTENT_SIZE) {
+ if (msg[i] == '\n' && msg[i + 1] != '\0') {
+ form_driver(this->Form, REQ_NEW_LINE);
+ } else {
+ form_driver(this->Form, msg[i]);
+ }
+ i++;
+ }
+ if (this->Scrolling == ScrollBehavior::ScrollDown) {
+ form_driver(this->Form, REQ_END_FIELD);
+ } else {
+ form_driver(this->Form, REQ_BEG_FIELD);
+ }
+}
+
+void cmCursesLongMessageForm::HandleInput()
+{
+ if (!this->Form) {
+ return;
+ }
+
+ char debugMessage[128];
+
+ for (;;) {
+ this->PrintKeys();
+ int key = getch();
+
+ sprintf(debugMessage, "Message widget handling input, key: %d", key);
+ cmCursesForm::LogMessage(debugMessage);
+
+ // quit
+ if (key == 'o' || key == 'e') {
+ break;
+ }
+ if (key == KEY_DOWN || key == ctrl('n')) {
+ form_driver(this->Form, REQ_SCR_FLINE);
+ } else if (key == KEY_UP || key == ctrl('p')) {
+ form_driver(this->Form, REQ_SCR_BLINE);
+ } else if (key == KEY_NPAGE || key == ctrl('d')) {
+ form_driver(this->Form, REQ_SCR_FPAGE);
+ } else if (key == KEY_PPAGE || key == ctrl('u')) {
+ form_driver(this->Form, REQ_SCR_BPAGE);
+ }
+
+ this->UpdateStatusBar();
+ touchwin(stdscr);
+ wrefresh(stdscr);
+ }
+}
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.h b/Source/CursesDialog/cmCursesLongMessageForm.h
new file mode 100644
index 0000000..4f69cb1
--- /dev/null
+++ b/Source/CursesDialog/cmCursesLongMessageForm.h
@@ -0,0 +1,60 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+#include "cmCursesForm.h"
+#include "cmCursesStandardIncludes.h"
+
+class cmCursesLongMessageForm : public cmCursesForm
+{
+public:
+ enum class ScrollBehavior
+ {
+ NoScroll,
+ ScrollDown
+ };
+
+ cmCursesLongMessageForm(std::vector<std::string> const& messages,
+ const char* title, ScrollBehavior scrollBehavior);
+ ~cmCursesLongMessageForm() override;
+
+ cmCursesLongMessageForm(cmCursesLongMessageForm const&) = delete;
+ cmCursesLongMessageForm& operator=(cmCursesLongMessageForm const&) = delete;
+
+ void UpdateContent(std::string const& output, std::string const& title);
+
+ // Description:
+ // Handle user input.
+ void HandleInput() override;
+
+ // Description:
+ // Display form. Use a window of size width x height, starting
+ // at top, left.
+ void Render(int left, int top, int width, int height) override;
+
+ // Description:
+ // This method should normally called only by the form.
+ // The only exception is during a resize.
+ void PrintKeys();
+
+ // Description:
+ // This method should normally called only by the form.
+ // The only exception is during a resize.
+ void UpdateStatusBar() override;
+
+protected:
+ static constexpr int MAX_CONTENT_SIZE = 60000;
+
+ void DrawMessage(const char* msg) const;
+
+ std::string Messages;
+ std::string Title;
+ ScrollBehavior Scrolling;
+
+ FIELD* Fields[2];
+};
diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx
new file mode 100644
index 0000000..069c02e
--- /dev/null
+++ b/Source/CursesDialog/cmCursesMainForm.cxx
@@ -0,0 +1,1075 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCursesMainForm.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <cstring>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmCursesCacheEntryComposite.h"
+#include "cmCursesDummyWidget.h"
+#include "cmCursesForm.h"
+#include "cmCursesLabelWidget.h"
+#include "cmCursesLongMessageForm.h"
+#include "cmCursesStandardIncludes.h"
+#include "cmCursesStringWidget.h"
+#include "cmCursesWidget.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+#include "cmake.h"
+
+inline int ctrl(int z)
+{
+ return (z & 037);
+}
+
+cmCursesMainForm::cmCursesMainForm(std::vector<std::string> args,
+ int initWidth)
+ : Args(std::move(args))
+ , InitialWidth(initWidth)
+{
+ this->HasNonStatusOutputs = false;
+ this->NumberOfPages = 0;
+ this->AdvancedMode = false;
+ this->NumberOfVisibleEntries = 0;
+ this->OkToGenerate = false;
+ this->HelpMessage.emplace_back(
+ "Welcome to ccmake, curses based user interface for CMake.");
+ this->HelpMessage.emplace_back();
+ this->HelpMessage.emplace_back(s_ConstHelpMessage);
+ this->CMakeInstance =
+ cm::make_unique<cmake>(cmake::RoleProject, cmState::Project);
+ this->CMakeInstance->SetCMakeEditCommand(
+ cmSystemTools::GetCMakeCursesCommand());
+
+ // create the arguments for the cmake object
+ std::string whereCMake =
+ cmStrCat(cmSystemTools::GetProgramPath(this->Args[0]), "/cmake");
+ this->Args[0] = whereCMake;
+ this->CMakeInstance->SetArgs(this->Args);
+ this->SearchMode = false;
+}
+
+cmCursesMainForm::~cmCursesMainForm()
+{
+ if (this->Form) {
+ unpost_form(this->Form);
+ free_form(this->Form);
+ this->Form = nullptr;
+ }
+}
+
+// See if a cache entry is in the list of entries in the ui.
+bool cmCursesMainForm::LookForCacheEntry(const std::string& key)
+{
+ return std::any_of(this->Entries.begin(), this->Entries.end(),
+ [&key](cmCursesCacheEntryComposite const& entry) {
+ return key == entry.Key;
+ });
+}
+
+// Create new cmCursesCacheEntryComposite entries from the cache
+void cmCursesMainForm::InitializeUI()
+{
+ // Create a vector of cmCursesCacheEntryComposite's
+ // which contain labels, entries and new entry markers
+ std::vector<cmCursesCacheEntryComposite> newEntries;
+ std::vector<std::string> cacheKeys =
+ this->CMakeInstance->GetState()->GetCacheEntryKeys();
+ newEntries.reserve(cacheKeys.size());
+
+ // Count non-internal and non-static entries
+ int count = 0;
+
+ for (std::string const& key : cacheKeys) {
+ cmStateEnums::CacheEntryType t =
+ this->CMakeInstance->GetState()->GetCacheEntryType(key);
+ if (t != cmStateEnums::INTERNAL && t != cmStateEnums::STATIC &&
+ t != cmStateEnums::UNINITIALIZED) {
+ ++count;
+ }
+ }
+
+ int entrywidth = this->InitialWidth - 35;
+
+ if (count == 0) {
+ // If cache is empty, display a label saying so and a
+ // dummy entry widget (does not respond to input)
+ cmCursesCacheEntryComposite comp("EMPTY CACHE", 30, 30);
+ comp.Entry = cm::make_unique<cmCursesDummyWidget>(1, 1, 1, 1);
+ newEntries.emplace_back(std::move(comp));
+ } else {
+ // Create the composites.
+
+ // First add entries which are new
+ for (std::string const& key : cacheKeys) {
+ cmStateEnums::CacheEntryType t =
+ this->CMakeInstance->GetState()->GetCacheEntryType(key);
+ if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC ||
+ t == cmStateEnums::UNINITIALIZED) {
+ continue;
+ }
+
+ if (!this->LookForCacheEntry(key)) {
+ newEntries.emplace_back(key, this->CMakeInstance->GetState(), true, 30,
+ entrywidth);
+ this->OkToGenerate = false;
+ }
+ }
+
+ // then add entries which are old
+ for (std::string const& key : cacheKeys) {
+ cmStateEnums::CacheEntryType t =
+ this->CMakeInstance->GetState()->GetCacheEntryType(key);
+ if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC ||
+ t == cmStateEnums::UNINITIALIZED) {
+ continue;
+ }
+
+ if (this->LookForCacheEntry(key)) {
+ newEntries.emplace_back(key, this->CMakeInstance->GetState(), false,
+ 30, entrywidth);
+ }
+ }
+ }
+
+ // Replace old entries
+ this->Entries = std::move(newEntries);
+
+ // Compute fields from composites
+ this->RePost();
+}
+
+void cmCursesMainForm::RePost()
+{
+ // Create the fields to be passed to the form.
+ if (this->Form) {
+ unpost_form(this->Form);
+ free_form(this->Form);
+ this->Form = nullptr;
+ }
+ this->Fields.clear();
+ if (this->AdvancedMode) {
+ this->NumberOfVisibleEntries = this->Entries.size();
+ } else {
+ // If normal mode, count only non-advanced entries
+ this->NumberOfVisibleEntries = 0;
+ for (cmCursesCacheEntryComposite& entry : this->Entries) {
+ cmProp existingValue =
+ this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue());
+ bool advanced =
+ this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
+ entry.GetValue(), "ADVANCED");
+ if (!existingValue || (!this->AdvancedMode && advanced)) {
+ continue;
+ }
+ this->NumberOfVisibleEntries++;
+ }
+ }
+ // there is always one even if it is the dummy one
+ if (this->NumberOfVisibleEntries == 0) {
+ this->NumberOfVisibleEntries = 1;
+ }
+ // Assign the fields: 3 for each entry: label, new entry marker
+ // ('*' or ' ') and entry widget
+ this->Fields.reserve(3 * this->NumberOfVisibleEntries + 1);
+
+ // Assign fields
+ for (cmCursesCacheEntryComposite& entry : this->Entries) {
+ cmProp existingValue =
+ this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue());
+ bool advanced =
+ this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
+ entry.GetValue(), "ADVANCED");
+ if (!existingValue || (!this->AdvancedMode && advanced)) {
+ continue;
+ }
+ this->Fields.push_back(entry.Label->Field);
+ this->Fields.push_back(entry.IsNewLabel->Field);
+ this->Fields.push_back(entry.Entry->Field);
+ }
+ // if no cache entries there should still be one dummy field
+ if (this->Fields.empty()) {
+ const auto& front = this->Entries.front();
+ this->Fields.push_back(front.Label->Field);
+ this->Fields.push_back(front.IsNewLabel->Field);
+ this->Fields.push_back(front.Entry->Field);
+ this->NumberOfVisibleEntries = 1;
+ }
+ // Has to be null terminated.
+ this->Fields.push_back(nullptr);
+}
+
+void cmCursesMainForm::Render(int left, int top, int width, int height)
+{
+
+ if (this->Form) {
+ FIELD* currentField = current_field(this->Form);
+ cmCursesWidget* cw =
+ reinterpret_cast<cmCursesWidget*>(field_userptr(currentField));
+ // If in edit mode, get out of it
+ if (cw->GetType() == cmStateEnums::STRING ||
+ cw->GetType() == cmStateEnums::PATH ||
+ cw->GetType() == cmStateEnums::FILEPATH) {
+ cmCursesStringWidget* sw = static_cast<cmCursesStringWidget*>(cw);
+ sw->SetInEdit(false);
+ }
+ // Delete the previous form
+ unpost_form(this->Form);
+ free_form(this->Form);
+ this->Form = nullptr;
+ }
+
+ // Wrong window size
+ if (width < cmCursesMainForm::MIN_WIDTH || width < this->InitialWidth ||
+ height < cmCursesMainForm::MIN_HEIGHT) {
+ return;
+ }
+
+ // Leave room for toolbar
+ height -= 7;
+
+ if (this->AdvancedMode) {
+ this->NumberOfVisibleEntries = this->Entries.size();
+ } else {
+ // If normal, display only non-advanced entries
+ this->NumberOfVisibleEntries = 0;
+ for (cmCursesCacheEntryComposite& entry : this->Entries) {
+ cmProp existingValue =
+ this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue());
+ bool advanced =
+ this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
+ entry.GetValue(), "ADVANCED");
+ if (!existingValue || (!this->AdvancedMode && advanced)) {
+ continue;
+ }
+ this->NumberOfVisibleEntries++;
+ }
+ }
+
+ // Re-adjust the fields according to their place
+ this->NumberOfPages = 1;
+ if (height > 0) {
+ bool isNewPage;
+ int i = 0;
+ for (cmCursesCacheEntryComposite& entry : this->Entries) {
+ cmProp existingValue =
+ this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue());
+ bool advanced =
+ this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
+ entry.GetValue(), "ADVANCED");
+ if (!existingValue || (!this->AdvancedMode && advanced)) {
+ continue;
+ }
+ int row = (i % height) + 1;
+ int page = (i / height) + 1;
+ isNewPage = (page > 1) && (row == 1);
+
+ if (isNewPage) {
+ this->NumberOfPages++;
+ }
+ entry.Label->Move(left, top + row - 1, isNewPage);
+ entry.IsNewLabel->Move(left + 32, top + row - 1, false);
+ entry.Entry->Move(left + 33, top + row - 1, false);
+ entry.Entry->SetPage(this->NumberOfPages);
+ i++;
+ }
+ }
+
+ // Post the form
+ this->Form = new_form(this->Fields.data());
+ post_form(this->Form);
+ // Update toolbar
+ this->UpdateStatusBar();
+ this->PrintKeys();
+
+ touchwin(stdscr);
+ refresh();
+}
+
+void cmCursesMainForm::PrintKeys(int process /* = 0 */)
+{
+ int x;
+ int y;
+ getmaxyx(stdscr, y, x);
+ if (x < cmCursesMainForm::MIN_WIDTH || x < this->InitialWidth ||
+ y < cmCursesMainForm::MIN_HEIGHT) {
+ return;
+ }
+
+ // Give the current widget (if it exists), a chance to print keys
+ cmCursesWidget* cw = nullptr;
+ if (this->Form) {
+ FIELD* currentField = current_field(this->Form);
+ cw = reinterpret_cast<cmCursesWidget*>(field_userptr(currentField));
+ }
+
+ char fmt_s[] = "%s";
+ if (cw == nullptr || !cw->PrintKeys()) {
+ char firstLine[512] = "";
+ char secondLine[512] = "";
+ char thirdLine[512] = "";
+ if (process) {
+ memset(firstLine, ' ', 68);
+ memset(secondLine, ' ', 68);
+ memset(thirdLine, ' ', 68);
+ } else {
+ if (this->OkToGenerate) {
+ sprintf(firstLine,
+ " [l] Show log output [c] Configure"
+ " [g] Generate ");
+ } else {
+ sprintf(firstLine,
+ " [l] Show log output [c] Configure"
+ " ");
+ }
+ {
+ const char* toggleKeyInstruction =
+ " [t] Toggle advanced mode (currently %s)";
+ sprintf(thirdLine, toggleKeyInstruction,
+ this->AdvancedMode ? "on" : "off");
+ }
+ sprintf(secondLine,
+ " [h] Help [q] Quit without generating");
+ }
+
+ curses_move(y - 4, 0);
+ char fmt[512] = "Keys: [enter] Edit an entry [d] Delete an entry";
+ if (process) {
+ memset(fmt, ' ', 57);
+ }
+ printw(fmt_s, fmt);
+ curses_move(y - 3, 0);
+ printw(fmt_s, firstLine);
+ curses_move(y - 2, 0);
+ printw(fmt_s, secondLine);
+ curses_move(y - 1, 0);
+ printw(fmt_s, thirdLine);
+ }
+
+ if (cw) {
+ char pageLine[512] = "";
+ sprintf(pageLine, "Page %d of %d", cw->GetPage(), this->NumberOfPages);
+ curses_move(0, 65 - static_cast<unsigned int>(strlen(pageLine)) - 1);
+ printw(fmt_s, pageLine);
+ }
+
+ pos_form_cursor(this->Form);
+}
+
+// Print the key of the current entry and the CMake version
+// on the status bar. Designed for a width of 80 chars.
+void cmCursesMainForm::UpdateStatusBar(cm::optional<std::string> message)
+{
+ int x;
+ int y;
+ getmaxyx(stdscr, y, x);
+ // If window size is too small, display error and return
+ if (x < cmCursesMainForm::MIN_WIDTH || x < this->InitialWidth ||
+ y < cmCursesMainForm::MIN_HEIGHT) {
+ curses_clear();
+ curses_move(0, 0);
+ char fmt[] = "Window is too small. A size of at least %dx%d is required.";
+ printw(fmt,
+ (cmCursesMainForm::MIN_WIDTH < this->InitialWidth
+ ? this->InitialWidth
+ : cmCursesMainForm::MIN_WIDTH),
+ cmCursesMainForm::MIN_HEIGHT);
+ touchwin(stdscr);
+ wrefresh(stdscr);
+ return;
+ }
+
+ // Find the current label index
+ // Field are grouped by 3, the label should be 2 less than the current index
+ using size_type = decltype(this->Fields)::size_type;
+ size_type currentLabelIndex = field_index(current_field(this->Form)) - 2;
+
+ // Use the status message if any, otherwise join the key and help string
+ std::string bar;
+ if (message) {
+ bar = *message;
+ } else {
+ // Get the key of the current entry
+ cmCursesWidget* labelWidget = reinterpret_cast<cmCursesWidget*>(
+ field_userptr(this->Fields[currentLabelIndex]));
+ std::string labelValue = labelWidget->GetValue();
+ bar = labelValue + ": ";
+
+ // Get the help string of the current entry
+ // and add it to the help string
+ auto* cmakeState = this->CMakeInstance->GetState();
+ cmProp existingValue = cmakeState->GetCacheEntryValue(labelValue);
+ if (existingValue) {
+ cmProp help =
+ cmakeState->GetCacheEntryProperty(labelValue, "HELPSTRING");
+ if (help) {
+ bar += *help;
+ }
+ }
+ }
+ // Pad with spaces to erase any previous text,
+ // or truncate as necessary to fit the screen
+ bar.resize(x, ' ');
+ curses_move(y - 5, 0);
+ attron(A_STANDOUT);
+ char fmt_s[] = "%s";
+ printw(fmt_s, bar.c_str());
+ attroff(A_STANDOUT);
+
+ // Highlight the current label, reset others
+ // Fields are grouped by 3, the first one being the label
+ // so start at 0 and move up by 3 avoiding the last null entry
+ for (size_type index = 0; index < this->Fields.size() - 1; index += 3) {
+ bool currentLabel = index == currentLabelIndex;
+ set_field_fore(this->Fields[index], currentLabel ? A_STANDOUT : A_NORMAL);
+ }
+
+ // Display CMake version under the status bar
+ // We want to display this on the right
+ std::string version = "CMake Version ";
+ version += cmVersion::GetCMakeVersion();
+ version.resize(std::min<std::string::size_type>(x, version.size()));
+ curses_move(y - 4, x - static_cast<int>(version.size()));
+ printw(fmt_s, version.c_str());
+
+ pos_form_cursor(this->Form);
+}
+
+void cmCursesMainForm::UpdateProgress(const std::string& msg, float prog)
+{
+ if (prog >= 0) {
+ constexpr int progressBarWidth = 40;
+ int progressBarCompleted = static_cast<int>(progressBarWidth * prog);
+ int percentCompleted = static_cast<int>(100 * prog);
+ this->LastProgress = (percentCompleted < 100 ? " " : "");
+ this->LastProgress += (percentCompleted < 10 ? " " : "");
+ this->LastProgress += std::to_string(percentCompleted) + "% [";
+ this->LastProgress.append(progressBarCompleted, '#');
+ this->LastProgress.append(progressBarWidth - progressBarCompleted, ' ');
+ this->LastProgress += "] " + msg + "...";
+ this->DisplayOutputs(std::string());
+ } else {
+ this->Outputs.emplace_back(msg);
+ this->DisplayOutputs(msg);
+ }
+}
+
+int cmCursesMainForm::Configure(int noconfigure)
+{
+ this->ResetOutputs();
+
+ if (noconfigure == 0) {
+ this->UpdateProgress("Configuring", 0);
+ this->CMakeInstance->SetProgressCallback(
+ [this](const std::string& msg, float prog) {
+ this->UpdateProgress(msg, prog);
+ });
+ }
+
+ // always save the current gui values to disk
+ this->FillCacheManagerFromUI();
+ this->CMakeInstance->SaveCache(
+ this->CMakeInstance->GetHomeOutputDirectory());
+ this->LoadCache(nullptr);
+
+ // run the generate process
+ this->OkToGenerate = true;
+ int retVal;
+ if (noconfigure) {
+ retVal = this->CMakeInstance->DoPreConfigureChecks();
+ this->OkToGenerate = false;
+ if (retVal > 0) {
+ retVal = 0;
+ }
+ } else {
+ retVal = this->CMakeInstance->Configure();
+ }
+ this->CMakeInstance->SetProgressCallback(nullptr);
+
+ keypad(stdscr, true); /* Use key symbols as KEY_DOWN */
+
+ if (retVal != 0 || this->HasNonStatusOutputs) {
+ // see if there was an error
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ this->OkToGenerate = false;
+ }
+ int xx;
+ int yy;
+ getmaxyx(stdscr, yy, xx);
+ const char* title = "Configure produced the following output";
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ title = "Configure failed with the following output";
+ }
+ cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(
+ this->Outputs, title,
+ cmCursesLongMessageForm::ScrollBehavior::ScrollDown);
+ // reset error condition
+ cmSystemTools::ResetErrorOccuredFlag();
+ CurrentForm = msgs;
+ msgs->Render(1, 1, xx, yy);
+ msgs->HandleInput();
+ // If they typed the wrong source directory, we report
+ // an error and exit
+ if (retVal == -2) {
+ return retVal;
+ }
+ }
+
+ this->InitializeUI();
+ CurrentForm = this;
+ int xi;
+ int yi;
+ getmaxyx(stdscr, yi, xi);
+ this->Render(1, 1, xi, yi);
+
+ return 0;
+}
+
+int cmCursesMainForm::Generate()
+{
+ this->ResetOutputs();
+
+ this->UpdateProgress("Generating", 0);
+ this->CMakeInstance->SetProgressCallback(
+ [this](const std::string& msg, float prog) {
+ this->UpdateProgress(msg, prog);
+ });
+
+ // run the generate process
+ int retVal = this->CMakeInstance->Generate();
+
+ this->CMakeInstance->SetProgressCallback(nullptr);
+ keypad(stdscr, true); /* Use key symbols as KEY_DOWN */
+
+ if (retVal != 0 || this->HasNonStatusOutputs) {
+ // see if there was an error
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ this->OkToGenerate = false;
+ }
+ // reset error condition
+ cmSystemTools::ResetErrorOccuredFlag();
+ int xx;
+ int yy;
+ getmaxyx(stdscr, yy, xx);
+ const char* title = "Generate produced the following output";
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ title = "Generate failed with the following output";
+ }
+ cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(
+ this->Outputs, title,
+ cmCursesLongMessageForm::ScrollBehavior::ScrollDown);
+ CurrentForm = msgs;
+ msgs->Render(1, 1, xx, yy);
+ msgs->HandleInput();
+ // If they typed the wrong source directory, we report
+ // an error and exit
+ if (retVal == -2) {
+ return retVal;
+ }
+ }
+
+ this->InitializeUI();
+ CurrentForm = this;
+ int xi;
+ int yi;
+ getmaxyx(stdscr, yi, xi);
+ this->Render(1, 1, xi, yi);
+
+ return 0;
+}
+
+void cmCursesMainForm::AddError(const std::string& message,
+ const char* /*unused*/)
+{
+ this->Outputs.emplace_back(message);
+ this->HasNonStatusOutputs = true;
+ this->DisplayOutputs(message);
+}
+
+void cmCursesMainForm::RemoveEntry(const char* value)
+{
+ if (!value) {
+ return;
+ }
+
+ auto removeIt =
+ std::find_if(this->Entries.begin(), this->Entries.end(),
+ [value](cmCursesCacheEntryComposite& entry) -> bool {
+ const char* val = entry.GetValue();
+ return val != nullptr && !strcmp(value, val);
+ });
+
+ if (removeIt != this->Entries.end()) {
+ this->CMakeInstance->UnwatchUnusedCli(value);
+ this->Entries.erase(removeIt);
+ }
+}
+
+// copy from the list box to the cache manager
+void cmCursesMainForm::FillCacheManagerFromUI()
+{
+ for (cmCursesCacheEntryComposite& entry : this->Entries) {
+ const std::string& cacheKey = entry.Key;
+ cmProp existingValue =
+ this->CMakeInstance->GetState()->GetCacheEntryValue(cacheKey);
+ if (existingValue) {
+ std::string oldValue = *existingValue;
+ std::string newValue = entry.Entry->GetValue();
+ std::string fixedOldValue;
+ std::string fixedNewValue;
+ cmStateEnums::CacheEntryType t =
+ this->CMakeInstance->GetState()->GetCacheEntryType(cacheKey);
+ this->FixValue(t, oldValue, fixedOldValue);
+ this->FixValue(t, newValue, fixedNewValue);
+
+ if (!(fixedOldValue == fixedNewValue)) {
+ // The user has changed the value. Mark it as modified.
+ this->CMakeInstance->GetState()->SetCacheEntryBoolProperty(
+ cacheKey, "MODIFIED", true);
+ this->CMakeInstance->GetState()->SetCacheEntryValue(cacheKey,
+ fixedNewValue);
+ }
+ }
+ }
+}
+
+void cmCursesMainForm::FixValue(cmStateEnums::CacheEntryType type,
+ const std::string& in, std::string& out) const
+{
+ out = in.substr(0, in.find_last_not_of(' ') + 1);
+ if (type == cmStateEnums::PATH || type == cmStateEnums::FILEPATH) {
+ cmSystemTools::ConvertToUnixSlashes(out);
+ }
+ if (type == cmStateEnums::BOOL) {
+ if (cmIsOff(out)) {
+ out = "OFF";
+ } else {
+ out = "ON";
+ }
+ }
+}
+
+void cmCursesMainForm::HandleInput()
+{
+ int x = 0;
+ int y = 0;
+
+ if (!this->Form) {
+ return;
+ }
+
+ FIELD* currentField;
+ cmCursesWidget* currentWidget;
+
+ char debugMessage[128];
+
+ for (;;) {
+ this->UpdateStatusBar();
+ this->PrintKeys();
+ if (this->SearchMode) {
+ std::string searchstr = "Search: " + this->SearchString;
+ this->UpdateStatusBar(searchstr);
+ this->PrintKeys(1);
+ curses_move(y - 5, static_cast<unsigned int>(searchstr.size()));
+ // curses_move(1,1);
+ touchwin(stdscr);
+ refresh();
+ }
+ int key = getch();
+
+ getmaxyx(stdscr, y, x);
+ // If window too small, handle 'q' only
+ if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) {
+ // quit
+ if (key == 'q') {
+ break;
+ }
+ continue;
+ }
+
+ currentField = current_field(this->Form);
+ currentWidget =
+ reinterpret_cast<cmCursesWidget*>(field_userptr(currentField));
+
+ bool widgetHandled = false;
+
+ if (this->SearchMode) {
+ if (key == 10 || key == KEY_ENTER) {
+ this->SearchMode = false;
+ if (!this->SearchString.empty()) {
+ this->JumpToCacheEntry(this->SearchString.c_str());
+ this->OldSearchString = this->SearchString;
+ }
+ this->SearchString.clear();
+ }
+ /*
+ else if ( key == KEY_ESCAPE )
+ {
+ this->SearchMode = false;
+ }
+ */
+ else if ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z') ||
+ (key >= '0' && key <= '9') || (key == '_')) {
+ if (this->SearchString.size() <
+ static_cast<std::string::size_type>(x - 10)) {
+ this->SearchString += static_cast<char>(key);
+ }
+ } else if (key == ctrl('h') || key == KEY_BACKSPACE || key == KEY_DC) {
+ if (!this->SearchString.empty()) {
+ this->SearchString.pop_back();
+ }
+ }
+ } else if (currentWidget && !this->SearchMode) {
+ // Ask the current widget if it wants to handle input
+ widgetHandled = currentWidget->HandleInput(key, this, stdscr);
+ if (widgetHandled) {
+ this->OkToGenerate = false;
+ this->UpdateStatusBar();
+ this->PrintKeys();
+ }
+ }
+ if ((!currentWidget || !widgetHandled) && !this->SearchMode) {
+ // If the current widget does not want to handle input,
+ // we handle it.
+ sprintf(debugMessage, "Main form handling input, key: %d", key);
+ cmCursesForm::LogMessage(debugMessage);
+ // quit
+ if (key == 'q') {
+ break;
+ }
+ // if not end of page, next field otherwise next page
+ // each entry consists of fields: label, isnew, value
+ // therefore, the label field for the prev. entry is index-5
+ // and the label field for the next entry is index+1
+ // (index always corresponds to the value field)
+ // scroll down with arrow down, ctrl+n (emacs binding), or j (vim
+ // binding)
+ if (key == KEY_DOWN || key == ctrl('n') || key == 'j') {
+ FIELD* cur = current_field(this->Form);
+ size_t findex = field_index(cur);
+ if (findex == 3 * this->NumberOfVisibleEntries - 1) {
+ continue;
+ }
+ if (new_page(this->Fields[findex + 1])) {
+ form_driver(this->Form, REQ_NEXT_PAGE);
+ } else {
+ form_driver(this->Form, REQ_NEXT_FIELD);
+ }
+ }
+ // if not beginning of page, previous field, otherwise previous page
+ // each entry consists of fields: label, isnew, value
+ // therefore, the label field for the prev. entry is index-5
+ // and the label field for the next entry is index+1
+ // (index always corresponds to the value field)
+ // scroll down with arrow up, ctrl+p (emacs binding), or k (vim binding)
+ else if (key == KEY_UP || key == ctrl('p') || key == 'k') {
+ FIELD* cur = current_field(this->Form);
+ int findex = field_index(cur);
+ if (findex == 2) {
+ continue;
+ }
+ if (new_page(this->Fields[findex - 2])) {
+ form_driver(this->Form, REQ_PREV_PAGE);
+ set_current_field(this->Form, this->Fields[findex - 3]);
+ } else {
+ form_driver(this->Form, REQ_PREV_FIELD);
+ }
+ }
+ // pg down
+ else if (key == KEY_NPAGE || key == ctrl('d')) {
+ form_driver(this->Form, REQ_NEXT_PAGE);
+ }
+ // pg up
+ else if (key == KEY_PPAGE || key == ctrl('u')) {
+ form_driver(this->Form, REQ_PREV_PAGE);
+ }
+ // configure
+ else if (key == 'c') {
+ this->Configure();
+ }
+ // display help
+ else if (key == 'h') {
+ getmaxyx(stdscr, y, x);
+
+ FIELD* cur = current_field(this->Form);
+ int findex = field_index(cur);
+ cmCursesWidget* lbl = reinterpret_cast<cmCursesWidget*>(
+ field_userptr(this->Fields[findex - 2]));
+ const char* curField = lbl->GetValue();
+ cmProp helpString = nullptr;
+
+ cmProp existingValue =
+ this->CMakeInstance->GetState()->GetCacheEntryValue(curField);
+ if (existingValue) {
+ helpString = this->CMakeInstance->GetState()->GetCacheEntryProperty(
+ curField, "HELPSTRING");
+ }
+ if (helpString) {
+ this->HelpMessage[1] =
+ cmStrCat("Current option is: ", curField, '\n',
+ "Help string for this option is: ", *helpString, '\n');
+ } else {
+ this->HelpMessage[1] = "";
+ }
+
+ cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(
+ this->HelpMessage, "Help",
+ cmCursesLongMessageForm::ScrollBehavior::NoScroll);
+ CurrentForm = msgs;
+ msgs->Render(1, 1, x, y);
+ msgs->HandleInput();
+ CurrentForm = this;
+ this->Render(1, 1, x, y);
+ set_current_field(this->Form, cur);
+ }
+ // display last errors
+ else if (key == 'l') {
+ getmaxyx(stdscr, y, x);
+ cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(
+ this->Outputs, "CMake produced the following output",
+ cmCursesLongMessageForm::ScrollBehavior::NoScroll);
+ CurrentForm = msgs;
+ msgs->Render(1, 1, x, y);
+ msgs->HandleInput();
+ CurrentForm = this;
+ this->Render(1, 1, x, y);
+ } else if (key == '/') {
+ this->SearchMode = true;
+ this->UpdateStatusBar("Search");
+ this->PrintKeys(1);
+ touchwin(stdscr);
+ refresh();
+ } else if (key == 'n') {
+ if (!this->OldSearchString.empty()) {
+ this->JumpToCacheEntry(this->OldSearchString.c_str());
+ }
+ }
+ // switch advanced on/off
+ else if (key == 't') {
+ this->AdvancedMode = !this->AdvancedMode;
+ getmaxyx(stdscr, y, x);
+ this->RePost();
+ this->Render(1, 1, x, y);
+ }
+ // generate and exit
+ else if (key == 'g') {
+ if (this->OkToGenerate) {
+ this->Generate();
+ break;
+ }
+ }
+ // delete cache entry
+ else if (key == 'd' && this->NumberOfVisibleEntries) {
+ this->OkToGenerate = false;
+ FIELD* cur = current_field(this->Form);
+ size_t findex = field_index(cur);
+
+ // make the next or prev. current field after deletion
+ // each entry consists of fields: label, isnew, value
+ // therefore, the label field for the prev. entry is findex-5
+ // and the label field for the next entry is findex+1
+ // (findex always corresponds to the value field)
+ FIELD* nextCur;
+ if (findex == 2) {
+ nextCur = nullptr;
+ } else if (findex == 3 * this->NumberOfVisibleEntries - 1) {
+ nextCur = this->Fields[findex - 5];
+ } else {
+ nextCur = this->Fields[findex + 1];
+ }
+
+ // Get the label widget
+ // each entry consists of fields: label, isnew, value
+ // therefore, the label field for the is findex-2
+ // (findex always corresponds to the value field)
+ cmCursesWidget* lbl = reinterpret_cast<cmCursesWidget*>(
+ field_userptr(this->Fields[findex - 2]));
+ if (lbl) {
+ this->CMakeInstance->GetState()->RemoveCacheEntry(lbl->GetValue());
+
+ std::string nextVal;
+ if (nextCur) {
+ nextVal =
+ (reinterpret_cast<cmCursesWidget*>(field_userptr(nextCur))
+ ->GetValue());
+ }
+
+ getmaxyx(stdscr, y, x);
+ this->RemoveEntry(lbl->GetValue());
+ this->RePost();
+ this->Render(1, 1, x, y);
+
+ if (nextCur) {
+ // make the next or prev. current field after deletion
+ auto nextEntryIt = std::find_if(
+ this->Entries.begin(), this->Entries.end(),
+ [&nextVal](cmCursesCacheEntryComposite const& entry) {
+ return nextVal == entry.Key;
+ });
+
+ if (nextEntryIt != this->Entries.end()) {
+ set_current_field(this->Form, nextEntryIt->Entry->Field);
+ }
+ }
+ }
+ }
+ }
+
+ touchwin(stdscr);
+ wrefresh(stdscr);
+ }
+}
+
+int cmCursesMainForm::LoadCache(const char* /*unused*/)
+
+{
+ int r = this->CMakeInstance->LoadCache();
+ if (r < 0) {
+ return r;
+ }
+ this->CMakeInstance->SetCacheArgs(this->Args);
+ this->CMakeInstance->PreLoadCMakeFiles();
+ return r;
+}
+
+void cmCursesMainForm::JumpToCacheEntry(const char* astr)
+{
+ std::string str;
+ if (astr) {
+ str = cmSystemTools::LowerCase(astr);
+ }
+
+ if (str.empty()) {
+ return;
+ }
+ FIELD* cur = current_field(this->Form);
+ int start_index = field_index(cur);
+ int findex = start_index;
+ for (;;) {
+ if (!str.empty()) {
+ cmCursesWidget* lbl = nullptr;
+ if (findex >= 0) {
+ lbl = reinterpret_cast<cmCursesWidget*>(
+ field_userptr(this->Fields[findex - 2]));
+ }
+ if (lbl) {
+ const char* curField = lbl->GetValue();
+ if (curField) {
+ std::string cfld = cmSystemTools::LowerCase(curField);
+ if (cfld.find(str) != std::string::npos && findex != start_index) {
+ break;
+ }
+ }
+ }
+ }
+ if (size_t(findex) >= 3 * this->NumberOfVisibleEntries - 1) {
+ set_current_field(this->Form, this->Fields[2]);
+ } else if (new_page(this->Fields[findex + 1])) {
+ form_driver(this->Form, REQ_NEXT_PAGE);
+ } else {
+ form_driver(this->Form, REQ_NEXT_FIELD);
+ }
+ cur = current_field(this->Form);
+ findex = field_index(cur);
+ if (findex == start_index) {
+ break;
+ }
+ }
+}
+
+void cmCursesMainForm::ResetOutputs()
+{
+ this->LogForm.reset();
+ this->Outputs.clear();
+ this->HasNonStatusOutputs = false;
+ this->LastProgress.clear();
+}
+
+void cmCursesMainForm::DisplayOutputs(std::string const& newOutput)
+{
+ int xi;
+ int yi;
+ getmaxyx(stdscr, yi, xi);
+
+ if (CurrentForm != this->LogForm.get()) {
+ auto* newLogForm = new cmCursesLongMessageForm(
+ this->Outputs, this->LastProgress.c_str(),
+ cmCursesLongMessageForm::ScrollBehavior::ScrollDown);
+ CurrentForm = newLogForm;
+ this->LogForm.reset(newLogForm);
+ this->LogForm->Render(1, 1, xi, yi);
+ } else {
+ this->LogForm->UpdateContent(newOutput, this->LastProgress);
+ }
+}
+
+const char* cmCursesMainForm::s_ConstHelpMessage =
+ "CMake is used to configure and generate build files for software projects. "
+ "The basic steps for configuring a project with ccmake are as follows:\n\n"
+ "1. Run ccmake in the directory where you want the object and executable "
+ "files to be placed (build directory). If the source directory is not the "
+ "same as this build directory, you have to specify it as an argument on the "
+ "command line.\n\n"
+ "2. When ccmake is run, it will read the configuration files and display "
+ "the current build options. "
+ "If you have run CMake before and have updated the configuration files "
+ "since then, any new entries will be displayed on top and will be marked "
+ "with a *. "
+ "On the other hand, the first time you run ccmake, all build options will "
+ "be new and will be marked as such. "
+ "At this point, you can modify any options (see keys below) you want to "
+ "change. "
+ "When you are satisfied with your changes, press 'c' to have CMake process "
+ "the configuration files. "
+ "Please note that changing some options may cause new ones to appear. These "
+ "will be shown on top and will be marked with *. "
+ "Repeat this procedure until you are satisfied with all the options and "
+ "there are no new entries. "
+ "At this point, a new command will appear: G)enerate and Exit. You can now "
+ "hit 'g' to have CMake generate all the build files (i.e. makefiles or "
+ "project files) and exit. "
+ "At any point during the process, you can exit ccmake with 'q'. However, "
+ "this will not generate/change any build files.\n\n"
+ "ccmake KEYS:\n\n"
+ "Navigation: "
+ "You can use the arrow keys and page up, down to navigate the options. "
+ "Alternatively, you can use the following keys: \n"
+ " C-n or j : next option\n"
+ " C-p or k : previous options\n"
+ " C-d : down one page\n"
+ " C-u : up one page\n\n"
+ "Editing options: "
+ "To change an option press enter or return. If the current options is a "
+ "boolean, this will toggle its value. "
+ "Otherwise, ccmake will enter edit mode. Alternatively, you can toggle "
+ "a bool variable by pressing space, and enter edit mode with i."
+ "In this mode you can edit an option using arrow keys and backspace. "
+ "Alternatively, you can use the following keys:\n"
+ " C-b : back one character\n"
+ " C-f : forward one character\n"
+ " C-a : go to the beginning of the field\n"
+ " C-e : go to the end of the field\n"
+ " C-d : delete previous character\n"
+ " C-k : kill the rest of the field\n"
+ " Esc : Restore field (discard last changes)\n"
+ " Enter : Leave edit mode\n"
+ "Commands:\n"
+ " q : quit ccmake without generating build files\n"
+ " h : help, shows this screen\n"
+ " c : process the configuration files with the current options\n"
+ " g : generate build files and exit, only available when there are no "
+ "new options and no errors have been detected during last configuration.\n"
+ " l : shows cmake output\n"
+ " d : delete an option\n"
+ " t : toggles advanced mode. In normal mode, only the most important "
+ "options are shown. In advanced mode, all options are shown. We recommend "
+ "using normal mode unless you are an expert.\n"
+ " / : search for a variable name.\n";
diff --git a/Source/CursesDialog/cmCursesMainForm.h b/Source/CursesDialog/cmCursesMainForm.h
new file mode 100644
index 0000000..c6db66f
--- /dev/null
+++ b/Source/CursesDialog/cmCursesMainForm.h
@@ -0,0 +1,171 @@
+/* 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 <cstddef>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+
+#include "cmCursesCacheEntryComposite.h"
+#include "cmCursesForm.h"
+#include "cmCursesStandardIncludes.h"
+#include "cmStateTypes.h"
+
+class cmake;
+class cmCursesLongMessageForm;
+
+/** \class cmCursesMainForm
+ * \brief The main page of ccmake
+ *
+ * cmCursesMainForm is the main page of ccmake.
+ */
+class cmCursesMainForm : public cmCursesForm
+{
+public:
+ cmCursesMainForm(std::vector<std::string> args, int initwidth);
+ ~cmCursesMainForm() override;
+
+ cmCursesMainForm(cmCursesMainForm const&) = delete;
+ cmCursesMainForm& operator=(cmCursesMainForm const&) = delete;
+
+ /**
+ * Set the widgets which represent the cache entries.
+ */
+ void InitializeUI();
+
+ /**
+ * Handle user input.
+ */
+ void HandleInput() override;
+
+ /**
+ * Display form. Use a window of size width x height, starting
+ * at top, left.
+ */
+ void Render(int left, int top, int width, int height) override;
+
+ /**
+ * Returns true if an entry with the given key is in the
+ * list of current composites.
+ */
+ bool LookForCacheEntry(const std::string& key);
+
+ enum
+ {
+ MIN_WIDTH = 65,
+ MIN_HEIGHT = 6,
+ IDEAL_WIDTH = 80,
+ MAX_WIDTH = 512
+ };
+
+ /**
+ * This method should normally be called only by the form. The only
+ * exception is during a resize. The optional argument specifies the
+ * string to be displayed in the status bar.
+ */
+ void UpdateStatusBar() override { this->UpdateStatusBar(cm::nullopt); }
+ void UpdateStatusBar(cm::optional<std::string> message);
+
+ /**
+ * Display current commands and their keys on the toolbar. This
+ * method should normally called only by the form. The only
+ * exception is during a resize. If the optional argument process is
+ * specified and is either 1 (configure) or 2 (generate), then keys
+ * will be displayed accordingly.
+ */
+ void PrintKeys(int process = 0);
+
+ /**
+ * During a CMake run, an error handle should add errors
+ * to be displayed afterwards.
+ */
+ void AddError(const std::string& message, const char* title) override;
+
+ /**
+ * Used to do a configure. If argument is specified, it does only the check
+ * and not configure.
+ */
+ int Configure(int noconfigure = 0);
+
+ /**
+ * Used to generate
+ */
+ int Generate();
+
+ /**
+ * Used by main program
+ */
+ int LoadCache(const char* dir);
+
+ /**
+ * Progress callback
+ */
+ void UpdateProgress(const std::string& msg, float prog);
+
+protected:
+ // Copy the cache values from the user interface to the actual
+ // cache.
+ void FillCacheManagerFromUI();
+ // Fix formatting of values to a consistent form.
+ void FixValue(cmStateEnums::CacheEntryType type, const std::string& in,
+ std::string& out) const;
+ // Re-post the existing fields. Used to toggle between
+ // normal and advanced modes. Render() should be called
+ // afterwards.
+ void RePost();
+ // Remove an entry from the interface and the cache.
+ void RemoveEntry(const char* value);
+
+ // Jump to the cache entry whose name matches the string.
+ void JumpToCacheEntry(const char* str);
+
+ // Clear and reset the output log and state
+ void ResetOutputs();
+
+ // Display the current progress and output
+ void DisplayOutputs(std::string const& newOutput);
+
+ // Copies of cache entries stored in the user interface
+ std::vector<cmCursesCacheEntryComposite> Entries;
+
+ // The form used to display logs during processing
+ std::unique_ptr<cmCursesLongMessageForm> LogForm;
+ // Output produced by the last pass
+ std::vector<std::string> Outputs;
+ // Did the last pass produced outputs of interest (errors, warnings, ...)
+ bool HasNonStatusOutputs;
+ // Last progress bar
+ std::string LastProgress;
+
+ // Command line arguments to be passed to cmake each time
+ // it is run
+ std::vector<std::string> Args;
+ // Message displayed when user presses 'h'
+ // It is: Welcome + info about current entry + common help
+ std::vector<std::string> HelpMessage;
+
+ // Common help
+ static const char* s_ConstHelpMessage;
+
+ // Fields displayed. Includes labels, new entry markers, entries
+ std::vector<FIELD*> Fields;
+ // Number of entries shown (depends on mode -normal or advanced-)
+ size_t NumberOfVisibleEntries;
+ bool AdvancedMode;
+ // Did the iteration converge (no new entries) ?
+ bool OkToGenerate;
+ // Number of pages displayed
+ int NumberOfPages;
+
+ int InitialWidth;
+ std::unique_ptr<cmake> CMakeInstance;
+
+ std::string SearchString;
+ std::string OldSearchString;
+ bool SearchMode;
+};
diff --git a/Source/CursesDialog/cmCursesOptionsWidget.cxx b/Source/CursesDialog/cmCursesOptionsWidget.cxx
new file mode 100644
index 0000000..8df32e2
--- /dev/null
+++ b/Source/CursesDialog/cmCursesOptionsWidget.cxx
@@ -0,0 +1,93 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCursesOptionsWidget.h"
+
+#include "cmCursesColor.h"
+#include "cmCursesWidget.h"
+#include "cmStateTypes.h"
+
+#define ctrl(z) ((z)&037)
+
+cmCursesOptionsWidget::cmCursesOptionsWidget(int width, int height, int left,
+ int top)
+ : cmCursesWidget(width, height, left, top)
+{
+ this->Type = cmStateEnums::BOOL; // this is a bit of a hack
+ // there is no option type, and string type causes ccmake to cast
+ // the widget into a string widget at some point. BOOL is safe for
+ // now.
+ if (cmCursesColor::HasColors()) {
+ set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::Choice));
+ set_field_back(this->Field, COLOR_PAIR(cmCursesColor::Choice));
+ } else {
+ set_field_fore(this->Field, A_NORMAL);
+ set_field_back(this->Field, A_STANDOUT);
+ }
+ field_opts_off(this->Field, O_STATIC);
+}
+
+bool cmCursesOptionsWidget::HandleInput(int& key, cmCursesMainForm* /*fm*/,
+ WINDOW* w)
+{
+ if (this->Options.empty()) {
+ return false;
+ }
+ switch (key) {
+ case 10: // 10 == enter
+ case KEY_ENTER:
+ this->NextOption();
+ touchwin(w);
+ wrefresh(w);
+ return true;
+ case KEY_LEFT:
+ case ctrl('b'):
+ touchwin(w);
+ wrefresh(w);
+ this->PreviousOption();
+ return true;
+ case KEY_RIGHT:
+ case ctrl('f'):
+ this->NextOption();
+ touchwin(w);
+ wrefresh(w);
+ return true;
+ default:
+ return false;
+ }
+}
+
+void cmCursesOptionsWidget::AddOption(std::string const& option)
+{
+ this->Options.push_back(option);
+}
+
+void cmCursesOptionsWidget::NextOption()
+{
+ this->CurrentOption++;
+ if (this->CurrentOption > this->Options.size() - 1) {
+ this->CurrentOption = 0;
+ }
+ this->SetValue(this->Options[this->CurrentOption]);
+}
+void cmCursesOptionsWidget::PreviousOption()
+{
+ if (this->CurrentOption == 0) {
+ this->CurrentOption = this->Options.size() - 1;
+ } else {
+ this->CurrentOption--;
+ }
+ this->SetValue(this->Options[this->CurrentOption]);
+}
+
+void cmCursesOptionsWidget::SetOption(const std::string& value)
+{
+ this->CurrentOption = 0; // default to 0 index
+ this->SetValue(value);
+ int index = 0;
+ for (auto const& opt : this->Options) {
+ if (opt == value) {
+ this->CurrentOption = index;
+ }
+ index++;
+ }
+}
diff --git a/Source/CursesDialog/cmCursesOptionsWidget.h b/Source/CursesDialog/cmCursesOptionsWidget.h
new file mode 100644
index 0000000..cb06e4d
--- /dev/null
+++ b/Source/CursesDialog/cmCursesOptionsWidget.h
@@ -0,0 +1,36 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmCursesStandardIncludes.h"
+#include "cmCursesWidget.h"
+
+class cmCursesMainForm;
+
+class cmCursesOptionsWidget : public cmCursesWidget
+{
+public:
+ cmCursesOptionsWidget(int width, int height, int left, int top);
+
+ cmCursesOptionsWidget(cmCursesOptionsWidget const&) = delete;
+ cmCursesOptionsWidget& operator=(cmCursesOptionsWidget const&) = delete;
+
+ // Description:
+ // Handle user input. Called by the container of this widget
+ // when this widget has focus. Returns true if the input was
+ // handled.
+ bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) override;
+ void SetOption(const std::string&);
+ void AddOption(std::string const&);
+ void NextOption();
+ void PreviousOption();
+
+protected:
+ std::vector<std::string> Options;
+ std::vector<std::string>::size_type CurrentOption;
+};
diff --git a/Source/CursesDialog/cmCursesPathWidget.cxx b/Source/CursesDialog/cmCursesPathWidget.cxx
new file mode 100644
index 0000000..8ed42de
--- /dev/null
+++ b/Source/CursesDialog/cmCursesPathWidget.cxx
@@ -0,0 +1,89 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCursesPathWidget.h"
+
+#include <vector>
+
+#include "cmCursesColor.h"
+#include "cmCursesMainForm.h"
+#include "cmCursesStringWidget.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
+
+cmCursesPathWidget::cmCursesPathWidget(int width, int height, int left,
+ int top)
+ : cmCursesStringWidget(width, height, left, top)
+{
+ this->Type = cmStateEnums::PATH;
+ this->Cycle = false;
+ this->CurrentIndex = 0;
+ if (cmCursesColor::HasColors()) {
+ set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::Path));
+ set_field_back(this->Field, COLOR_PAIR(cmCursesColor::Path));
+ } else {
+ set_field_fore(this->Field, A_NORMAL);
+ set_field_back(this->Field, A_STANDOUT);
+ }
+}
+
+void cmCursesPathWidget::OnType(int& key, cmCursesMainForm* fm, WINDOW* w)
+{
+ this->Cycle = false;
+ this->CurrentIndex = 0;
+ this->LastGlob = "";
+ this->cmCursesStringWidget::OnType(key, fm, w);
+}
+
+void cmCursesPathWidget::OnTab(cmCursesMainForm* fm, WINDOW* w)
+{
+ if (!this->GetString()) {
+ return;
+ }
+ FORM* form = fm->GetForm();
+ form_driver(form, REQ_NEXT_FIELD);
+ form_driver(form, REQ_PREV_FIELD);
+ std::string cstr = this->GetString();
+ cstr = cstr.substr(0, cstr.find_last_not_of(" \t\n\r") + 1);
+ if (this->LastString != cstr) {
+ this->Cycle = false;
+ this->CurrentIndex = 0;
+ this->LastGlob = "";
+ }
+ std::string glob;
+ if (this->Cycle) {
+ glob = this->LastGlob;
+ } else {
+ glob = cstr + "*";
+ }
+ std::vector<std::string> dirs;
+
+ cmSystemTools::SimpleGlob(glob, dirs,
+ (this->Type == cmStateEnums::PATH ? -1 : 0));
+ if (this->CurrentIndex < dirs.size()) {
+ cstr = dirs[this->CurrentIndex];
+ }
+ if (cstr[cstr.size() - 1] == '*') {
+ cstr = cstr.substr(0, cstr.size() - 1);
+ }
+
+ if (cmSystemTools::FileIsDirectory(cstr)) {
+ cstr += "/";
+ }
+
+ this->SetString(cstr);
+ touchwin(w);
+ wrefresh(w);
+ form_driver(form, REQ_END_FIELD);
+ this->LastGlob = glob;
+ this->LastString = cstr;
+ this->Cycle = true;
+ this->CurrentIndex++;
+ if (this->CurrentIndex >= dirs.size()) {
+ this->CurrentIndex = 0;
+ }
+}
+
+void cmCursesPathWidget::OnReturn(cmCursesMainForm* fm, WINDOW* w)
+{
+ this->cmCursesStringWidget::OnReturn(fm, w);
+}
diff --git a/Source/CursesDialog/cmCursesPathWidget.h b/Source/CursesDialog/cmCursesPathWidget.h
new file mode 100644
index 0000000..79e342e
--- /dev/null
+++ b/Source/CursesDialog/cmCursesPathWidget.h
@@ -0,0 +1,35 @@
+/* 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 <string>
+
+#include "cmCursesStandardIncludes.h"
+#include "cmCursesStringWidget.h"
+
+class cmCursesMainForm;
+
+class cmCursesPathWidget : public cmCursesStringWidget
+{
+public:
+ cmCursesPathWidget(int width, int height, int left, int top);
+
+ cmCursesPathWidget(cmCursesPathWidget const&) = delete;
+ cmCursesPathWidget& operator=(cmCursesPathWidget const&) = delete;
+
+ /**
+ * This method is called when different keys are pressed. The
+ * subclass can have a special implementation handler for this.
+ */
+ void OnTab(cmCursesMainForm* fm, WINDOW* w) override;
+ void OnReturn(cmCursesMainForm* fm, WINDOW* w) override;
+ void OnType(int& key, cmCursesMainForm* fm, WINDOW* w) override;
+
+protected:
+ std::string LastString;
+ std::string LastGlob;
+ bool Cycle;
+ std::string::size_type CurrentIndex;
+};
diff --git a/Source/CursesDialog/cmCursesStandardIncludes.h b/Source/CursesDialog/cmCursesStandardIncludes.h
new file mode 100644
index 0000000..9745b97
--- /dev/null
+++ b/Source/CursesDialog/cmCursesStandardIncludes.h
@@ -0,0 +1,42 @@
+/* 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
+
+// Record whether __attribute__ is currently defined. See purpose below.
+#ifndef __attribute__
+# define cm_no__attribute__
+#endif
+
+#if defined(__hpux)
+# define _BOOL_DEFINED
+# include <sys/time.h>
+#endif
+
+#include <form.h>
+
+// on some machines move erase and clear conflict with stl
+// so remove them from the namespace
+inline void curses_move(unsigned int x, unsigned int y)
+{
+ move(x, y);
+}
+
+inline void curses_clear()
+{
+ erase();
+ clearok(stdscr, TRUE);
+}
+
+#undef move
+#undef erase
+#undef clear
+
+// The curses headers on some platforms (e.g. Solaris) may
+// define __attribute__ as a macro. This breaks C++ headers
+// in some cases, so undefine it now.
+#if defined(cm_no__attribute__) && defined(__attribute__)
+# undef __attribute__
+#endif
+#undef cm_no__attribute__
diff --git a/Source/CursesDialog/cmCursesStringWidget.cxx b/Source/CursesDialog/cmCursesStringWidget.cxx
new file mode 100644
index 0000000..4830d63
--- /dev/null
+++ b/Source/CursesDialog/cmCursesStringWidget.cxx
@@ -0,0 +1,207 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCursesStringWidget.h"
+
+#include <cstdio>
+
+#include "cmCursesColor.h"
+#include "cmCursesForm.h"
+#include "cmCursesMainForm.h"
+#include "cmCursesStandardIncludes.h"
+#include "cmCursesWidget.h"
+#include "cmStateTypes.h"
+
+inline int ctrl(int z)
+{
+ return (z & 037);
+}
+
+cmCursesStringWidget::cmCursesStringWidget(int width, int height, int left,
+ int top)
+ : cmCursesWidget(width, height, left, top)
+{
+ this->InEdit = false;
+ this->Type = cmStateEnums::STRING;
+ if (cmCursesColor::HasColors()) {
+ set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::String));
+ set_field_back(this->Field, COLOR_PAIR(cmCursesColor::String));
+ } else {
+ set_field_fore(this->Field, A_NORMAL);
+ set_field_back(this->Field, A_STANDOUT);
+ }
+ field_opts_off(this->Field, O_STATIC);
+}
+
+void cmCursesStringWidget::OnTab(cmCursesMainForm* /*unused*/,
+ WINDOW* /*unused*/)
+{
+ // FORM* form = fm->GetForm();
+}
+
+void cmCursesStringWidget::OnReturn(cmCursesMainForm* fm, WINDOW* /*unused*/)
+{
+ if (this->InEdit) {
+ cmCursesForm::LogMessage("String widget leaving edit.");
+ this->InEdit = false;
+ fm->PrintKeys();
+ this->OriginalString.clear();
+ // trick to force forms to update the field buffer
+ FORM* form = fm->GetForm();
+ form_driver(form, REQ_NEXT_FIELD);
+ form_driver(form, REQ_PREV_FIELD);
+ this->Done = true;
+ } else {
+ cmCursesForm::LogMessage("String widget entering edit.");
+ this->InEdit = true;
+ fm->PrintKeys();
+ this->OriginalString = field_buffer(this->Field, 0);
+ }
+}
+
+void cmCursesStringWidget::OnType(int& key, cmCursesMainForm* fm,
+ WINDOW* /*unused*/)
+{
+ form_driver(fm->GetForm(), key);
+}
+
+bool cmCursesStringWidget::HandleInput(int& key, cmCursesMainForm* fm,
+ WINDOW* w)
+{
+ int x;
+ int y;
+
+ FORM* form = fm->GetForm();
+ // when not in edit mode, edit mode is entered by pressing enter or i (vim
+ // binding)
+ // 10 == enter
+ if (!this->InEdit && (key != 10 && key != KEY_ENTER && key != 'i')) {
+ return false;
+ }
+
+ this->OriginalString.clear();
+ this->Done = false;
+
+ char debugMessage[128];
+
+ // <Enter> is used to change edit mode (like <Esc> in vi).
+ while (!this->Done) {
+ sprintf(debugMessage, "String widget handling input, key: %d", key);
+ cmCursesForm::LogMessage(debugMessage);
+
+ fm->PrintKeys();
+
+ getmaxyx(stdscr, y, x);
+ // If window too small, handle 'q' only
+ if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) {
+ // quit
+ if (key == 'q') {
+ return false;
+ }
+ key = getch();
+ continue;
+ }
+
+ // If resize occurred during edit, move out of edit mode
+ if (!this->InEdit && (key != 10 && key != KEY_ENTER && key != 'i')) {
+ return false;
+ }
+ // toggle edit with return
+ if ((key == 10 || key == KEY_ENTER)
+ // enter edit with i (and not-edit mode)
+ || (!this->InEdit && key == 'i')) {
+ this->OnReturn(fm, w);
+ } else if (key == KEY_DOWN || key == ctrl('n') || key == KEY_UP ||
+ key == ctrl('p') || key == KEY_NPAGE || key == ctrl('d') ||
+ key == KEY_PPAGE || key == ctrl('u')) {
+ this->InEdit = false;
+ this->OriginalString.clear();
+ // trick to force forms to update the field buffer
+ form_driver(form, REQ_NEXT_FIELD);
+ form_driver(form, REQ_PREV_FIELD);
+ return false;
+ }
+ // esc
+ else if (key == 27) {
+ if (this->InEdit) {
+ this->InEdit = false;
+ fm->PrintKeys();
+ this->SetString(this->OriginalString);
+ this->OriginalString.clear();
+ touchwin(w);
+ wrefresh(w);
+ return true;
+ }
+ } else if (key == 9) {
+ this->OnTab(fm, w);
+ } else if (key == KEY_LEFT || key == ctrl('b')) {
+ form_driver(form, REQ_PREV_CHAR);
+ } else if (key == KEY_RIGHT || key == ctrl('f')) {
+ form_driver(form, REQ_NEXT_CHAR);
+ } else if (key == ctrl('k')) {
+ form_driver(form, REQ_CLR_EOL);
+ } else if (key == ctrl('a') || key == KEY_HOME) {
+ form_driver(form, REQ_BEG_FIELD);
+ } else if (key == ctrl('e') || key == KEY_END) {
+ form_driver(form, REQ_END_FIELD);
+ } else if (key == 127 || key == KEY_BACKSPACE) {
+ FIELD* cur = current_field(form);
+ form_driver(form, REQ_DEL_PREV);
+ if (current_field(form) != cur) {
+ set_current_field(form, cur);
+ }
+ } else if (key == ctrl('d') || key == KEY_DC) {
+ form_driver(form, REQ_DEL_CHAR);
+ } else {
+ this->OnType(key, fm, w);
+ }
+ if (!this->Done) {
+ touchwin(w);
+ wrefresh(w);
+
+ key = getch();
+ }
+ }
+ return true;
+}
+
+void cmCursesStringWidget::SetString(const std::string& value)
+{
+ this->SetValue(value);
+}
+
+const char* cmCursesStringWidget::GetString()
+{
+ return this->GetValue();
+}
+
+const char* cmCursesStringWidget::GetValue()
+{
+ return field_buffer(this->Field, 0);
+}
+
+bool cmCursesStringWidget::PrintKeys()
+{
+ int x;
+ int y;
+ getmaxyx(stdscr, y, x);
+ if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) {
+ return false;
+ }
+ if (this->InEdit) {
+ char fmt_s[] = "%s";
+ // Clean the toolbar
+ curses_move(y - 4, 0);
+ clrtoeol();
+ curses_move(y - 3, 0);
+ printw(fmt_s, "Editing option, press [enter] to confirm");
+ clrtoeol();
+ curses_move(y - 2, 0);
+ printw(fmt_s, " press [esc] to cancel");
+ clrtoeol();
+ curses_move(y - 1, 0);
+ clrtoeol();
+
+ return true;
+ }
+ return false;
+}
diff --git a/Source/CursesDialog/cmCursesStringWidget.h b/Source/CursesDialog/cmCursesStringWidget.h
new file mode 100644
index 0000000..faa2ade
--- /dev/null
+++ b/Source/CursesDialog/cmCursesStringWidget.h
@@ -0,0 +1,66 @@
+/* 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 <string>
+
+#include "cmCursesStandardIncludes.h"
+#include "cmCursesWidget.h"
+
+class cmCursesMainForm;
+
+/** \class cmCursesStringWidget
+ * \brief A simple entry widget.
+ *
+ * cmCursesStringWdiget is a simple text entry widget.
+ */
+
+class cmCursesStringWidget : public cmCursesWidget
+{
+public:
+ cmCursesStringWidget(int width, int height, int left, int top);
+
+ /**
+ * Handle user input. Called by the container of this widget
+ * when this widget has focus. Returns true if the input was
+ * handled.
+ */
+ bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) override;
+
+ /**
+ * Set/Get the string.
+ */
+ void SetString(const std::string& value);
+ const char* GetString();
+ const char* GetValue() override;
+
+ /**
+ * Set/Get InEdit flag. Can be used to tell the widget to leave
+ * edit mode (in case of a resize for example).
+ */
+ void SetInEdit(bool inedit) { this->InEdit = inedit; }
+ bool GetInEdit() { return this->InEdit; }
+
+ /**
+ * This method is called when different keys are pressed. The
+ * subclass can have a special implementation handler for this.
+ */
+ virtual void OnTab(cmCursesMainForm* fm, WINDOW* w);
+ virtual void OnReturn(cmCursesMainForm* fm, WINDOW* w);
+ virtual void OnType(int& key, cmCursesMainForm* fm, WINDOW* w);
+
+ /**
+ * If there are any, print the widget specific commands
+ * in the toolbar and return true. Otherwise, return false
+ * and the parent widget will print.
+ */
+ bool PrintKeys() override;
+
+protected:
+ // true if the widget is in edit mode
+ bool InEdit;
+ std::string OriginalString;
+ bool Done;
+};
diff --git a/Source/CursesDialog/cmCursesWidget.cxx b/Source/CursesDialog/cmCursesWidget.cxx
new file mode 100644
index 0000000..cc07411
--- /dev/null
+++ b/Source/CursesDialog/cmCursesWidget.cxx
@@ -0,0 +1,44 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCursesWidget.h"
+
+cmCursesWidget::cmCursesWidget(int width, int height, int left, int top)
+{
+ this->Field = new_field(height, width, top, left, 0, 0);
+ set_field_userptr(this->Field, reinterpret_cast<char*>(this));
+ field_opts_off(this->Field, O_AUTOSKIP);
+ this->Page = 0;
+}
+
+cmCursesWidget::~cmCursesWidget()
+{
+ if (this->Field) {
+ free_field(this->Field);
+ this->Field = nullptr;
+ }
+}
+
+void cmCursesWidget::Move(int x, int y, bool isNewPage)
+{
+ if (!this->Field) {
+ return;
+ }
+
+ move_field(this->Field, y, x);
+ if (isNewPage) {
+ set_new_page(this->Field, true);
+ } else {
+ set_new_page(this->Field, false);
+ }
+}
+
+void cmCursesWidget::SetValue(const std::string& value)
+{
+ this->Value = value;
+ set_field_buffer(this->Field, 0, const_cast<char*>(value.c_str()));
+}
+
+const char* cmCursesWidget::GetValue()
+{
+ return this->Value.c_str();
+}
diff --git a/Source/CursesDialog/cmCursesWidget.h b/Source/CursesDialog/cmCursesWidget.h
new file mode 100644
index 0000000..29ec28b
--- /dev/null
+++ b/Source/CursesDialog/cmCursesWidget.h
@@ -0,0 +1,69 @@
+/* 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 <string>
+
+#include "cmCursesStandardIncludes.h"
+#include "cmStateTypes.h"
+
+class cmCursesMainForm;
+
+class cmCursesWidget
+{
+public:
+ cmCursesWidget(int width, int height, int left, int top);
+ virtual ~cmCursesWidget();
+
+ cmCursesWidget(cmCursesWidget const&) = delete;
+ cmCursesWidget& operator=(cmCursesWidget const&) = delete;
+
+ /**
+ * Handle user input. Called by the container of this widget
+ * when this widget has focus. Returns true if the input was
+ * handled
+ */
+ virtual bool HandleInput(int& key, cmCursesMainForm* fm, WINDOW* w) = 0;
+
+ /**
+ * Change the position of the widget. Set isNewPage to true
+ * if this widget marks the beginning of a new page.
+ */
+ virtual void Move(int x, int y, bool isNewPage);
+
+ /**
+ * Set/Get the value (setting the value also changes the contents
+ * of the field buffer).
+ */
+ virtual void SetValue(const std::string& value);
+ virtual const char* GetValue();
+
+ /**
+ * Get the type of the widget (STRING, PATH etc...)
+ */
+ cmStateEnums::CacheEntryType GetType() { return this->Type; }
+
+ /**
+ * If there are any, print the widget specific commands
+ * in the toolbar and return true. Otherwise, return false
+ * and the parent widget will print.
+ */
+ virtual bool PrintKeys() { return false; }
+
+ /**
+ * Set/Get the page this widget is in.
+ */
+ void SetPage(int page) { this->Page = page; }
+ int GetPage() { return this->Page; }
+
+ friend class cmCursesMainForm;
+
+protected:
+ cmStateEnums::CacheEntryType Type;
+ std::string Value;
+ FIELD* Field;
+ // The page in the main form this widget is in
+ int Page;
+};
diff --git a/Source/CursesDialog/form/.NoDartCoverage b/Source/CursesDialog/form/.NoDartCoverage
new file mode 100644
index 0000000..3c99729
--- /dev/null
+++ b/Source/CursesDialog/form/.NoDartCoverage
@@ -0,0 +1 @@
+# do not do coverage in this directory
diff --git a/Source/CursesDialog/form/.gitattributes b/Source/CursesDialog/form/.gitattributes
new file mode 100644
index 0000000..12ede74
--- /dev/null
+++ b/Source/CursesDialog/form/.gitattributes
@@ -0,0 +1 @@
+* -format.clang-format-6.0
diff --git a/Source/CursesDialog/form/CMakeLists.txt b/Source/CursesDialog/form/CMakeLists.txt
new file mode 100644
index 0000000..8f26b9a
--- /dev/null
+++ b/Source/CursesDialog/form/CMakeLists.txt
@@ -0,0 +1,69 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+project(CMAKE_FORM)
+
+# Disable warnings to avoid changing 3rd party code.
+if(CMAKE_C_COMPILER_ID MATCHES
+ "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM)$")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
+endif()
+
+configure_file(cmFormConfigure.h.in "${CMAKE_CURRENT_BINARY_DIR}/cmFormConfigure.h")
+
+add_library(cmForm
+ fld_arg.c
+ fld_attr.c
+ fld_current.c
+ fld_def.c
+ fld_dup.c
+ fld_ftchoice.c
+ fld_ftlink.c
+ fld_info.c
+ fld_just.c
+ fld_link.c
+ fld_max.c
+ fld_move.c
+ fld_newftyp.c
+ fld_opts.c
+ fld_pad.c
+ fld_page.c
+ fld_stat.c
+ fld_type.c
+ fld_user.c
+ frm_cursor.c
+ frm_data.c
+ frm_def.c
+ frm_driver.c
+ frm_hook.c
+ frm_opts.c
+ frm_page.c
+ frm_post.c
+ frm_req_name.c
+ frm_scale.c
+ frm_sub.c
+ frm_user.c
+ frm_win.c
+ fty_alnum.c
+ fty_alpha.c
+ fty_enum.c
+ fty_int.c
+ fty_ipv4.c
+ fty_num.c
+ fty_regex.c
+ )
+
+target_include_directories(cmForm
+ PUBLIC
+ ${CURSES_INCLUDE_PATH}
+ ${CMAKE_FORM_BINARY_DIR}
+ ${CMAKE_FORM_SOURCE_DIR}
+ )
+
+target_link_libraries(cmForm ${CURSES_LIBRARY})
+
+if(CURSES_EXTRA_LIBRARY)
+ target_link_libraries(cmForm ${CURSES_EXTRA_LIBRARY})
+endif()
diff --git a/Source/CursesDialog/form/READ.ME b/Source/CursesDialog/form/READ.ME
new file mode 100644
index 0000000..dd91693
--- /dev/null
+++ b/Source/CursesDialog/form/READ.ME
@@ -0,0 +1,15 @@
+This is a clone of the form library that is available with typical
+System V curses implementations (ETI).
+
+It is modelled after the documentation that comes for this library with
+a 386 based SVR4 implementation (ESIX).
+
+The development environment was and is an ELF based Linux system.
+
+For things that still need doing, see the TO-DO file in the top-level
+directory.
+
+Juergen Pfeifer
+
+eMail: juergen.pfeifer@gmx.net
+
diff --git a/Source/CursesDialog/form/cmFormConfigure.h.in b/Source/CursesDialog/form/cmFormConfigure.h.in
new file mode 100644
index 0000000..511c525
--- /dev/null
+++ b/Source/CursesDialog/form/cmFormConfigure.h.in
@@ -0,0 +1,11 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef CMFORMCONFIGURE_H
+#define CMFORMCONFIGURE_H
+
+#cmakedefine CURSES_HAVE_CURSES_H
+#cmakedefine CURSES_HAVE_NCURSES_H
+#cmakedefine CURSES_HAVE_NCURSES_NCURSES_H
+#cmakedefine CURSES_HAVE_NCURSES_CURSES_H
+
+#endif
diff --git a/Source/CursesDialog/form/eti.h b/Source/CursesDialog/form/eti.h
new file mode 100644
index 0000000..cc1c830
--- /dev/null
+++ b/Source/CursesDialog/form/eti.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#ifndef _ETI_ERRNO_H_
+#define _ETI_ERRNO_H_
+
+#define E_OK (0)
+#define E_SYSTEM_ERROR (-1)
+#define E_BAD_ARGUMENT (-2)
+#define E_POSTED (-3)
+#define E_CONNECTED (-4)
+#define E_BAD_STATE (-5)
+#define E_NO_ROOM (-6)
+#define E_NOT_POSTED (-7)
+#define E_UNKNOWN_COMMAND (-8)
+#define E_NO_MATCH (-9)
+#define E_NOT_SELECTABLE (-10)
+#define E_NOT_CONNECTED (-11)
+#define E_REQUEST_DENIED (-12)
+#define E_INVALID_FIELD (-13)
+#define E_CURRENT (-14)
+
+#endif
diff --git a/Source/CursesDialog/form/fld_arg.c b/Source/CursesDialog/form/fld_arg.c
new file mode 100644
index 0000000..91ad79f
--- /dev/null
+++ b/Source/CursesDialog/form/fld_arg.c
@@ -0,0 +1,91 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_fieldtype_arg(
+| FIELDTYPE *typ,
+| void * (* const make_arg)(va_list *),
+| void * (* const copy_arg)(const void *),
+| void (* const free_arg)(void *) )
+|
+| Description : Connects to the type additional arguments necessary
+| for a set_field_type call. The various function pointer
+| arguments are:
+| make_arg : allocates a structure for the field
+| specific parameters.
+| copy_arg : duplicate the structure created by
+| make_arg
+| free_arg : Release the memory allocated by make_arg
+| or copy_arg
+|
+| At least make_arg must be non-NULL.
+| You may pass NULL for copy_arg and free_arg if your
+| make_arg function doesn't allocate memory and your
+| arg fits into the storage for a (void*).
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid argument
++--------------------------------------------------------------------------*/
+int set_fieldtype_arg(FIELDTYPE * typ,
+ void * (* const make_arg)(va_list *),
+ void * (* const copy_arg)(const void *),
+ void (* const free_arg)(void *))
+{
+ if ( !typ || !make_arg )
+ RETURN(E_BAD_ARGUMENT);
+
+ typ->status |= _HAS_ARGS;
+ typ->makearg = make_arg;
+ typ->copyarg = copy_arg;
+ typ->freearg = free_arg;
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : void *field_arg(const FIELD *field)
+|
+| Description : Retrieve pointer to the fields argument structure.
+|
+| Return Values : Pointer to structure or NULL if none is defined.
++--------------------------------------------------------------------------*/
+void *field_arg(const FIELD * field)
+{
+ return Normalize_Field(field)->arg;
+}
+
+/* fld_arg.c ends here */
diff --git a/Source/CursesDialog/form/fld_attr.c b/Source/CursesDialog/form/fld_attr.c
new file mode 100644
index 0000000..35ea903
--- /dev/null
+++ b/Source/CursesDialog/form/fld_attr.c
@@ -0,0 +1,110 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+#include "form.priv.h"
+MODULE_ID("$Id$")
+
+/*----------------------------------------------------------------------------
+ Field-Attribute manipulation routines
+ --------------------------------------------------------------------------*/
+/* "Template" macro to generate a function to set a fields attribute */
+#define GEN_FIELD_ATTR_SET_FCT( name ) \
+int set_field_ ## name (FIELD * field, chtype attr)\
+{\
+ int res = E_BAD_ARGUMENT;\
+ if ( attr==A_NORMAL || ((attr & A_ATTRIBUTES)==attr) )\
+ {\
+ Normalize_Field( field );\
+ if ((field -> name) != attr)\
+ {\
+ field -> name = attr;\
+ res = _nc_Synchronize_Attributes( field );\
+ }\
+ else\
+ res = E_OK;\
+ }\
+ RETURN(res);\
+}
+
+/* "Template" macro to generate a function to get a fields attribute */
+#define GEN_FIELD_ATTR_GET_FCT( name ) \
+chtype field_ ## name (const FIELD * field)\
+{\
+ return ( A_ATTRIBUTES & (Normalize_Field( field ) -> name) );\
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_fore(FIELD *field, chtype attr)
+|
+| Description : Sets the foreground of the field used to display the
+| field contents.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid attributes
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+GEN_FIELD_ATTR_SET_FCT( fore )
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : chtype field_fore(const FIELD *)
+|
+| Description : Retrieve fields foreground attribute
+|
+| Return Values : The foreground attribute
++--------------------------------------------------------------------------*/
+GEN_FIELD_ATTR_GET_FCT( fore )
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_back(FIELD *field, chtype attr)
+|
+| Description : Sets the background of the field used to display the
+| fields extend.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid attributes
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+GEN_FIELD_ATTR_SET_FCT( back )
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : chtype field_back(const
+|
+| Description : Retrieve fields background attribute
+|
+| Return Values : The background attribute
++--------------------------------------------------------------------------*/
+GEN_FIELD_ATTR_GET_FCT( back )
+
+/* fld_attr.c ends here */
diff --git a/Source/CursesDialog/form/fld_current.c b/Source/CursesDialog/form/fld_current.c
new file mode 100644
index 0000000..d4b1254
--- /dev/null
+++ b/Source/CursesDialog/form/fld_current.c
@@ -0,0 +1,124 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_current_field(FORM * form,FIELD * field)
+|
+| Description : Set the current field of the form to the specified one.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid form or field pointer
+| E_REQUEST_DENIED - field not selectable
+| E_BAD_STATE - called from a hook routine
+| E_INVALID_FIELD - current field can't be left
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int set_current_field(FORM * form, FIELD * field)
+{
+ int err = E_OK;
+
+ if ( !form || !field )
+ RETURN(E_BAD_ARGUMENT);
+
+ if ( (form != field->form) || Field_Is_Not_Selectable(field) )
+ RETURN(E_REQUEST_DENIED);
+
+ if (!(form->status & _POSTED))
+ {
+ form->current = field;
+ form->curpage = field->page;
+ }
+ else
+ {
+ if (form->status & _IN_DRIVER)
+ err = E_BAD_STATE;
+ else
+ {
+ if (form->current != field)
+ {
+ if (!_nc_Internal_Validation(form))
+ err = E_INVALID_FIELD;
+ else
+ {
+ Call_Hook(form,fieldterm);
+ if (field->page != form->curpage)
+ {
+ Call_Hook(form,formterm);
+ err = _nc_Set_Form_Page(form,field->page,field);
+ Call_Hook(form,forminit);
+ }
+ else
+ {
+ err = _nc_Set_Current_Field(form,field);
+ }
+ Call_Hook(form,fieldinit);
+ _nc_Refresh_Current_Field(form);
+ }
+ }
+ }
+ }
+ RETURN(err);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELD *current_field(const FORM * form)
+|
+| Description : Return the current field.
+|
+| Return Values : Pointer to the current field.
++--------------------------------------------------------------------------*/
+FIELD *current_field(const FORM * form)
+{
+ return Normalize_Form(form)->current;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int field_index(const FIELD * field)
+|
+| Description : Return the index of the field in the field-array of
+| the form.
+|
+| Return Values : >= 0 : field index
+| -1 : fieldpointer invalid or field not connected
++--------------------------------------------------------------------------*/
+int field_index(const FIELD * field)
+{
+ return ( (field && field->form) ? field->index : -1 );
+}
+
+/* fld_current.c ends here */
diff --git a/Source/CursesDialog/form/fld_def.c b/Source/CursesDialog/form/fld_def.c
new file mode 100644
index 0000000..00da3b4
--- /dev/null
+++ b/Source/CursesDialog/form/fld_def.c
@@ -0,0 +1,346 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/* this can't be readonly */
+static FIELD default_field = {
+ 0, /* status */
+ 0, /* rows */
+ 0, /* cols */
+ 0, /* frow */
+ 0, /* fcol */
+ 0, /* drows */
+ 0, /* dcols */
+ 0, /* maxgrow*/
+ 0, /* nrow */
+ 0, /* nbuf */
+ NO_JUSTIFICATION, /* just */
+ 0, /* page */
+ 0, /* index */
+ (int)' ', /* pad */
+ A_NORMAL, /* fore */
+ A_NORMAL, /* back */
+ ALL_FIELD_OPTS, /* opts */
+ (FIELD *)0, /* snext */
+ (FIELD *)0, /* sprev */
+ (FIELD *)0, /* link */
+ (FORM *)0, /* form */
+ (FIELDTYPE *)0, /* type */
+ (char *)0, /* arg */
+ (char *)0, /* buf */
+ (char *)0 /* usrptr */
+};
+
+FIELD *_nc_Default_Field = &default_field;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : TypeArgument *_nc_Make_Argument(
+| const FIELDTYPE *typ,
+| va_list *ap,
+| int *err )
+|
+| Description : Create an argument structure for the specified type.
+| Use the type-dependent argument list to construct
+| it.
+|
+| Return Values : Pointer to argument structure. Maybe NULL.
+| In case of an error in *err an errorcounter is increased.
++--------------------------------------------------------------------------*/
+TypeArgument*
+_nc_Make_Argument(const FIELDTYPE *typ, va_list *ap, int *err)
+{
+ TypeArgument *res = (TypeArgument *)0;
+ TypeArgument *p;
+
+ if (typ && (typ->status & _HAS_ARGS))
+ {
+ assert(err && ap);
+ if (typ->status & _LINKED_TYPE)
+ {
+ p = (TypeArgument *)malloc(sizeof(TypeArgument));
+ if (p)
+ {
+ p->left = _nc_Make_Argument(typ->left ,ap,err);
+ p->right = _nc_Make_Argument(typ->right,ap,err);
+ return p;
+ }
+ else
+ *err += 1;
+ } else
+ {
+ assert(typ->makearg != 0);
+ if ( !(res=(TypeArgument *)typ->makearg(ap)) )
+ *err += 1;
+ }
+ }
+ return res;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : TypeArgument *_nc_Copy_Argument(const FIELDTYPE *typ,
+| const TypeArgument *argp,
+| int *err )
+|
+| Description : Create a copy of an argument structure for the specified
+| type.
+|
+| Return Values : Pointer to argument structure. Maybe NULL.
+| In case of an error in *err an errorcounter is increased.
++--------------------------------------------------------------------------*/
+TypeArgument*
+_nc_Copy_Argument(const FIELDTYPE *typ,
+ const TypeArgument *argp, int *err)
+{
+ TypeArgument *res = (TypeArgument *)0;
+ TypeArgument *p;
+
+ if ( typ && (typ->status & _HAS_ARGS) )
+ {
+ assert(err && argp);
+ if (typ->status & _LINKED_TYPE)
+ {
+ p = (TypeArgument *)malloc(sizeof(TypeArgument));
+ if (p)
+ {
+ p->left = _nc_Copy_Argument(typ,argp->left ,err);
+ p->right = _nc_Copy_Argument(typ,argp->right,err);
+ return p;
+ }
+ *err += 1;
+ }
+ else
+ {
+ if (typ->copyarg)
+ {
+ if (!(res = (TypeArgument *)(typ->copyarg((const void *)argp))))
+ *err += 1;
+ }
+ else
+ res = (TypeArgument *)argp;
+ }
+ }
+ return res;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : void _nc_Free_Argument(const FIELDTYPE *typ,
+| TypeArgument * argp )
+|
+| Description : Release memory associated with the argument structure
+| for the given fieldtype.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+void
+_nc_Free_Argument(const FIELDTYPE * typ, TypeArgument * argp)
+{
+ if (!typ || !(typ->status & _HAS_ARGS))
+ return;
+
+ if (typ->status & _LINKED_TYPE)
+ {
+ assert(argp != 0);
+ _nc_Free_Argument(typ->left ,argp->left );
+ _nc_Free_Argument(typ->right,argp->right);
+ free(argp);
+ }
+ else
+ {
+ if (typ->freearg)
+ typ->freearg((void *)argp);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : bool _nc_Copy_Type( FIELD *dst, FIELD const *src )
+|
+| Description : Copy argument structure of field src to field dst
+|
+| Return Values : TRUE - copy worked
+| FALSE - error occurred
++--------------------------------------------------------------------------*/
+bool
+_nc_Copy_Type(FIELD *dst, FIELD const *src)
+{
+ int err = 0;
+
+ assert(dst && src);
+
+ dst->type = src->type;
+ dst->arg = (void *)_nc_Copy_Argument(src->type,(TypeArgument *)(src->arg),&err);
+
+ if (err)
+ {
+ _nc_Free_Argument(dst->type,(TypeArgument *)(dst->arg));
+ dst->type = (FIELDTYPE *)0;
+ dst->arg = (void *)0;
+ return FALSE;
+ }
+ else
+ {
+ if (dst->type)
+ dst->type->ref++;
+ return TRUE;
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : void _nc_Free_Type( FIELD *field )
+|
+| Description : Release Argument structure for this field
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+void
+_nc_Free_Type(FIELD *field)
+{
+ assert(field != 0);
+ if (field->type)
+ field->type->ref--;
+ _nc_Free_Argument(field->type,(TypeArgument *)(field->arg));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELD *new_field( int rows, int cols,
+| int frow, int fcol,
+| int nrow, int nbuf )
+|
+| Description : Create a new field with this many 'rows' and 'cols',
+| starting at 'frow/fcol' in the subwindow of the form.
+| Allocate 'nrow' off-screen rows and 'nbuf' additional
+| buffers. If an error occurs, errno is set to
+|
+| E_BAD_ARGUMENT - invalid argument
+| E_SYSTEM_ERROR - system error
+|
+| Return Values : Pointer to the new field or NULL if failure.
++--------------------------------------------------------------------------*/
+FIELD *new_field(int rows, int cols, int frow, int fcol, int nrow, int nbuf)
+{
+ FIELD *New_Field = (FIELD *)0;
+ int err = E_BAD_ARGUMENT;
+
+ if (rows>0 &&
+ cols>0 &&
+ frow>=0 &&
+ fcol>=0 &&
+ nrow>=0 &&
+ nbuf>=0 &&
+ ((err = E_SYSTEM_ERROR) != 0) && /* trick: this resets the default error */
+ (New_Field=(FIELD *)malloc(sizeof(FIELD))) )
+ {
+ *New_Field = default_field;
+ New_Field->rows = rows;
+ New_Field->cols = cols;
+ New_Field->drows = rows + nrow;
+ New_Field->dcols = cols;
+ New_Field->frow = frow;
+ New_Field->fcol = fcol;
+ New_Field->nrow = nrow;
+ New_Field->nbuf = nbuf;
+ New_Field->link = New_Field;
+
+ if (_nc_Copy_Type(New_Field,&default_field))
+ {
+ size_t len;
+
+ len = Total_Buffer_Size(New_Field);
+ if ((New_Field->buf = (char *)malloc(len)))
+ {
+ /* Prefill buffers with blanks and insert terminating zeroes
+ between buffers */
+ int i;
+
+ memset(New_Field->buf,' ',len);
+ for(i=0;i<=New_Field->nbuf;i++)
+ {
+ New_Field->buf[(New_Field->drows*New_Field->cols+1)*(i+1)-1]
+ = '\0';
+ }
+ return New_Field;
+ }
+ }
+ }
+
+ if (New_Field)
+ free_field(New_Field);
+
+ SET_ERROR( err );
+ return (FIELD *)0;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int free_field( FIELD *field )
+|
+| Description : Frees the storage allocated for the field.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid field pointer
+| E_CONNECTED - field is connected
++--------------------------------------------------------------------------*/
+int free_field(FIELD * field)
+{
+ if (!field)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (field->form)
+ RETURN(E_CONNECTED);
+
+ if (field == field->link)
+ {
+ if (field->buf)
+ free(field->buf);
+ }
+ else
+ {
+ FIELD *f;
+
+ for(f=field;f->link != field;f = f->link)
+ {}
+ f->link = field->link;
+ }
+ _nc_Free_Type(field);
+ free(field);
+ RETURN(E_OK);
+}
+
+/* fld_def.c ends here */
diff --git a/Source/CursesDialog/form/fld_dup.c b/Source/CursesDialog/form/fld_dup.c
new file mode 100644
index 0000000..1c5301d
--- /dev/null
+++ b/Source/CursesDialog/form/fld_dup.c
@@ -0,0 +1,97 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELD *dup_field(FIELD *field, int frow, int fcol)
+|
+| Description : Duplicates the field at the specified position. All
+| field attributes and the buffers are copied.
+| If an error occurs, errno is set to
+|
+| E_BAD_ARGUMENT - invalid argument
+| E_SYSTEM_ERROR - system error
+|
+| Return Values : Pointer to the new field or NULL if failure
++--------------------------------------------------------------------------*/
+FIELD *dup_field(FIELD * field, int frow, int fcol)
+{
+ FIELD *New_Field = (FIELD *)0;
+ int err = E_BAD_ARGUMENT;
+
+ if (field && (frow>=0) && (fcol>=0) &&
+ ((err=E_SYSTEM_ERROR) != 0) && /* trick : this resets the default error */
+ (New_Field=(FIELD *)malloc(sizeof(FIELD))) )
+ {
+ *New_Field = *_nc_Default_Field;
+ New_Field->frow = frow;
+ New_Field->fcol = fcol;
+ New_Field->link = New_Field;
+ New_Field->rows = field->rows;
+ New_Field->cols = field->cols;
+ New_Field->nrow = field->nrow;
+ New_Field->drows = field->drows;
+ New_Field->dcols = field->dcols;
+ New_Field->maxgrow = field->maxgrow;
+ New_Field->nbuf = field->nbuf;
+ New_Field->just = field->just;
+ New_Field->fore = field->fore;
+ New_Field->back = field->back;
+ New_Field->pad = field->pad;
+ New_Field->opts = field->opts;
+ New_Field->usrptr = field->usrptr;
+
+ if (_nc_Copy_Type(New_Field,field))
+ {
+ size_t len;
+
+ len = Total_Buffer_Size(New_Field);
+ if ( (New_Field->buf=(char *)malloc(len)) )
+ {
+ memcpy(New_Field->buf,field->buf,len);
+ return New_Field;
+ }
+ }
+ }
+
+ if (New_Field)
+ free_field(New_Field);
+
+ SET_ERROR(err);
+ return (FIELD *)0;
+}
+
+/* fld_dup.c ends here */
diff --git a/Source/CursesDialog/form/fld_ftchoice.c b/Source/CursesDialog/form/fld_ftchoice.c
new file mode 100644
index 0000000..bb37073
--- /dev/null
+++ b/Source/CursesDialog/form/fld_ftchoice.c
@@ -0,0 +1,62 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_fieldtype_choice(
+| FIELDTYPE *typ,
+| bool (* const next_choice)(FIELD *,const void *),
+| bool (* const prev_choice)(FIELD *,const void *))
+|
+| Description : Define implementation of enumeration requests.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid arguments
++--------------------------------------------------------------------------*/
+int set_fieldtype_choice(FIELDTYPE * typ,
+ bool (* const next_choice) (FIELD *,const void *),
+ bool (* const prev_choice) (FIELD *,const void *))
+{
+ if ( !typ || !next_choice || !prev_choice )
+ RETURN(E_BAD_ARGUMENT);
+
+ typ->status |= _HAS_CHOICE;
+ typ->next = next_choice;
+ typ->prev = prev_choice;
+ RETURN(E_OK);
+}
+
+/* fld_ftchoice.c ends here */
diff --git a/Source/CursesDialog/form/fld_ftlink.c b/Source/CursesDialog/form/fld_ftlink.c
new file mode 100644
index 0000000..e98a4ca
--- /dev/null
+++ b/Source/CursesDialog/form/fld_ftlink.c
@@ -0,0 +1,83 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELDTYPE *link_fieldtype(
+| FIELDTYPE *type1,
+| FIELDTYPE *type2)
+|
+| Description : Create a new fieldtype built from the two given types.
+| They are connected by an logical 'OR'.
+| If an error occurs, errno is set to
+| E_BAD_ARGUMENT - invalid arguments
+| E_SYSTEM_ERROR - system error (no memory)
+|
+| Return Values : Fieldtype pointer or NULL if error occurred.
++--------------------------------------------------------------------------*/
+FIELDTYPE *link_fieldtype(FIELDTYPE * type1, FIELDTYPE * type2)
+{
+ FIELDTYPE *nftyp = (FIELDTYPE *)0;
+
+ if ( type1 && type2 )
+ {
+ nftyp = (FIELDTYPE *)malloc(sizeof(FIELDTYPE));
+ if (nftyp)
+ {
+ *nftyp = *_nc_Default_FieldType;
+ nftyp->status |= _LINKED_TYPE;
+ if ((type1->status & _HAS_ARGS) || (type2->status & _HAS_ARGS) )
+ nftyp->status |= _HAS_ARGS;
+ if ((type1->status & _HAS_CHOICE) || (type2->status & _HAS_CHOICE) )
+ nftyp->status |= _HAS_CHOICE;
+ nftyp->left = type1;
+ nftyp->right = type2;
+ type1->ref++;
+ type2->ref++;
+ }
+ else
+ {
+ SET_ERROR( E_SYSTEM_ERROR );
+ }
+ }
+ else
+ {
+ SET_ERROR( E_BAD_ARGUMENT );
+ }
+ return nftyp;
+}
+
+/* fld_ftlink.c ends here */
diff --git a/Source/CursesDialog/form/fld_info.c b/Source/CursesDialog/form/fld_info.c
new file mode 100644
index 0000000..1ba92c8
--- /dev/null
+++ b/Source/CursesDialog/form/fld_info.c
@@ -0,0 +1,91 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int field_info(const FIELD *field,
+| int *rows, int *cols,
+| int *frow, int *fcol,
+| int *nrow, int *nbuf)
+|
+| Description : Retrieve infos about the fields creation parameters.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid field pointer
++--------------------------------------------------------------------------*/
+int field_info(const FIELD *field,
+ int *rows, int *cols,
+ int *frow, int *fcol,
+ int *nrow, int *nbuf)
+{
+ if (!field)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (rows) *rows = field->rows;
+ if (cols) *cols = field->cols;
+ if (frow) *frow = field->frow;
+ if (fcol) *fcol = field->fcol;
+ if (nrow) *nrow = field->nrow;
+ if (nbuf) *nbuf = field->nbuf;
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int dynamic_field_info(const FIELD *field,
+| int *drows, int *dcols,
+| int *maxgrow)
+|
+| Description : Retrieve information about a dynamic fields current
+| dynamic parameters.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid argument
++--------------------------------------------------------------------------*/
+int dynamic_field_info(const FIELD *field,
+ int *drows, int *dcols, int *maxgrow)
+{
+ if (!field)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (drows) *drows = field->drows;
+ if (dcols) *dcols = field->dcols;
+ if (maxgrow) *maxgrow = field->maxgrow;
+
+ RETURN(E_OK);
+}
+
+/* fld_info.c ends here */
diff --git a/Source/CursesDialog/form/fld_just.c b/Source/CursesDialog/form/fld_just.c
new file mode 100644
index 0000000..7015654
--- /dev/null
+++ b/Source/CursesDialog/form/fld_just.c
@@ -0,0 +1,81 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_just(FIELD *field, int just)
+|
+| Description : Set the fields type of justification.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - one of the arguments was incorrect
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int set_field_just(FIELD * field, int just)
+{
+ int res = E_BAD_ARGUMENT;
+
+ if ((just==NO_JUSTIFICATION) ||
+ (just==JUSTIFY_LEFT) ||
+ (just==JUSTIFY_CENTER) ||
+ (just==JUSTIFY_RIGHT) )
+ {
+ Normalize_Field( field );
+ if (field->just != just)
+ {
+ field->just = just;
+ res = _nc_Synchronize_Attributes( field );
+ }
+ else
+ res = E_OK;
+ }
+ RETURN(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int field_just( const FIELD *field )
+|
+| Description : Retrieve the fields type of justification
+|
+| Return Values : The justification type.
++--------------------------------------------------------------------------*/
+int field_just(const FIELD * field)
+{
+ return Normalize_Field( field )->just;
+}
+
+/* fld_just.c ends here */
diff --git a/Source/CursesDialog/form/fld_link.c b/Source/CursesDialog/form/fld_link.c
new file mode 100644
index 0000000..164f51b
--- /dev/null
+++ b/Source/CursesDialog/form/fld_link.c
@@ -0,0 +1,90 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELD *link_field(FIELD *field, int frow, int fcol)
+|
+| Description : Duplicates the field at the specified position. The
+| new field shares its buffers with the original one,
+| the attributes are independent.
+| If an error occurs, errno is set to
+|
+| E_BAD_ARGUMENT - invalid argument
+| E_SYSTEM_ERROR - system error
+|
+| Return Values : Pointer to the new field or NULL if failure
++--------------------------------------------------------------------------*/
+FIELD *link_field(FIELD * field, int frow, int fcol)
+{
+ FIELD *New_Field = (FIELD *)0;
+ int err = E_BAD_ARGUMENT;
+
+ if (field && (frow>=0) && (fcol>=0) &&
+ ((err=E_SYSTEM_ERROR) != 0) && /* trick: this resets the default error */
+ (New_Field = (FIELD *)malloc(sizeof(FIELD))) )
+ {
+ *New_Field = *_nc_Default_Field;
+ New_Field->frow = frow;
+ New_Field->fcol = fcol;
+ New_Field->link = field->link;
+ field->link = New_Field;
+ New_Field->buf = field->buf;
+ New_Field->rows = field->rows;
+ New_Field->cols = field->cols;
+ New_Field->nrow = field->nrow;
+ New_Field->nbuf = field->nbuf;
+ New_Field->drows = field->drows;
+ New_Field->dcols = field->dcols;
+ New_Field->maxgrow= field->maxgrow;
+ New_Field->just = field->just;
+ New_Field->fore = field->fore;
+ New_Field->back = field->back;
+ New_Field->pad = field->pad;
+ New_Field->opts = field->opts;
+ New_Field->usrptr = field->usrptr;
+ if (_nc_Copy_Type(New_Field,field))
+ return New_Field;
+ }
+
+ if (New_Field)
+ free_field(New_Field);
+
+ SET_ERROR( err );
+ return (FIELD *)0;
+}
+
+/* fld_link.c ends here */
diff --git a/Source/CursesDialog/form/fld_max.c b/Source/CursesDialog/form/fld_max.c
new file mode 100644
index 0000000..cca8dc5
--- /dev/null
+++ b/Source/CursesDialog/form/fld_max.c
@@ -0,0 +1,74 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_max_field(FIELD *field, int maxgrow)
+|
+| Description : Set the maximum growth for a dynamic field. If maxgrow=0
+| the field may grow to any possible size.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid argument
++--------------------------------------------------------------------------*/
+int set_max_field(FIELD *field, int maxgrow)
+{
+ if (!field || (maxgrow<0))
+ RETURN(E_BAD_ARGUMENT);
+ else
+ {
+ bool single_line_field = Single_Line_Field(field);
+
+ if (maxgrow>0)
+ {
+ if (( single_line_field && (maxgrow < field->dcols)) ||
+ (!single_line_field && (maxgrow < field->drows)))
+ RETURN(E_BAD_ARGUMENT);
+ }
+ field->maxgrow = maxgrow;
+ field->status &= ~_MAY_GROW;
+ if (!(field->opts & O_STATIC))
+ {
+ if ((maxgrow==0) ||
+ ( single_line_field && (field->dcols < maxgrow)) ||
+ (!single_line_field && (field->drows < maxgrow)))
+ field->status |= _MAY_GROW;
+ }
+ }
+ RETURN(E_OK);
+}
+
+/* fld_max.c ends here */
diff --git a/Source/CursesDialog/form/fld_move.c b/Source/CursesDialog/form/fld_move.c
new file mode 100644
index 0000000..2293477
--- /dev/null
+++ b/Source/CursesDialog/form/fld_move.c
@@ -0,0 +1,62 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int move_field(FIELD *field,int frow, int fcol)
+|
+| Description : Moves the disconnected field to the new location in
+| the forms subwindow.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid argument passed
+| E_CONNECTED - field is connected
++--------------------------------------------------------------------------*/
+int move_field(FIELD *field, int frow, int fcol)
+{
+ if ( !field || (frow<0) || (fcol<0) )
+ RETURN(E_BAD_ARGUMENT);
+
+ if (field->form)
+ RETURN(E_CONNECTED);
+
+ field->frow = frow;
+ field->fcol = fcol;
+ RETURN(E_OK);
+}
+
+/* fld_move.c ends here */
+
diff --git a/Source/CursesDialog/form/fld_newftyp.c b/Source/CursesDialog/form/fld_newftyp.c
new file mode 100644
index 0000000..b839f19
--- /dev/null
+++ b/Source/CursesDialog/form/fld_newftyp.c
@@ -0,0 +1,125 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+static FIELDTYPE const default_fieldtype = {
+ 0, /* status */
+ 0L, /* reference count */
+ (FIELDTYPE *)0, /* pointer to left operand */
+ (FIELDTYPE *)0, /* pointer to right operand */
+ NULL, /* makearg function */
+ NULL, /* copyarg function */
+ NULL, /* freearg function */
+ NULL, /* field validation function */
+ NULL, /* Character check function */
+ NULL, /* enumerate next function */
+ NULL /* enumerate previous function */
+};
+
+const FIELDTYPE* _nc_Default_FieldType = &default_fieldtype;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELDTYPE *new_fieldtype(
+| bool (* const field_check)(FIELD *,const void *),
+| bool (* const char_check) (int, const void *) )
+|
+| Description : Create a new fieldtype. The application programmer must
+| write a field_check and a char_check function and give
+| them as input to this call.
+| If an error occurs, errno is set to
+| E_BAD_ARGUMENT - invalid arguments
+| E_SYSTEM_ERROR - system error (no memory)
+|
+| Return Values : Fieldtype pointer or NULL if error occurred
++--------------------------------------------------------------------------*/
+FIELDTYPE *new_fieldtype(
+ bool (* const field_check)(FIELD *,const void *),
+ bool (* const char_check) (int,const void *) )
+{
+ FIELDTYPE *nftyp = (FIELDTYPE *)0;
+
+ if ( (field_check) || (char_check) )
+ {
+ nftyp = (FIELDTYPE *)malloc(sizeof(FIELDTYPE));
+ if (nftyp)
+ {
+ *nftyp = default_fieldtype;
+ nftyp->fcheck = field_check;
+ nftyp->ccheck = char_check;
+ }
+ else
+ {
+ SET_ERROR( E_SYSTEM_ERROR );
+ }
+ }
+ else
+ {
+ SET_ERROR( E_BAD_ARGUMENT );
+ }
+ return nftyp;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int free_fieldtype(FIELDTYPE *typ)
+|
+| Description : Release the memory associated with this fieldtype.
+|
+| Return Values : E_OK - success
+| E_CONNECTED - there are fields referencing the type
+| E_BAD_ARGUMENT - invalid fieldtype pointer
++--------------------------------------------------------------------------*/
+int free_fieldtype(FIELDTYPE *typ)
+{
+ if (!typ)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (typ->ref!=0)
+ RETURN(E_CONNECTED);
+
+ if (typ->status & _RESIDENT)
+ RETURN(E_CONNECTED);
+
+ if (typ->status & _LINKED_TYPE)
+ {
+ if (typ->left ) typ->left->ref--;
+ if (typ->right) typ->right->ref--;
+ }
+ free(typ);
+ RETURN(E_OK);
+}
+
+/* fld_newftyp.c ends here */
diff --git a/Source/CursesDialog/form/fld_opts.c b/Source/CursesDialog/form/fld_opts.c
new file mode 100644
index 0000000..234634b
--- /dev/null
+++ b/Source/CursesDialog/form/fld_opts.c
@@ -0,0 +1,124 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*----------------------------------------------------------------------------
+ Field-Options manipulation routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_opts(FIELD *field, Field_Options opts)
+|
+| Description : Turns on the named options for this field and turns
+| off all the remaining options.
+|
+| Return Values : E_OK - success
+| E_CURRENT - the field is the current field
+| E_BAD_ARGUMENT - invalid options
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int set_field_opts(FIELD * field, Field_Options opts)
+{
+ int res = E_BAD_ARGUMENT;
+ opts &= ALL_FIELD_OPTS;
+ if (!(opts & ~ALL_FIELD_OPTS))
+ res = _nc_Synchronize_Options( Normalize_Field(field), opts );
+ RETURN(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : Field_Options field_opts(const FIELD *field)
+|
+| Description : Retrieve the fields options.
+|
+| Return Values : The options.
++--------------------------------------------------------------------------*/
+Field_Options field_opts(const FIELD * field)
+{
+ return ALL_FIELD_OPTS & Normalize_Field( field )->opts;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int field_opts_on(FIELD *field, Field_Options opts)
+|
+| Description : Turns on the named options for this field and all the
+| remaining options are unchanged.
+|
+| Return Values : E_OK - success
+| E_CURRENT - the field is the current field
+| E_BAD_ARGUMENT - invalid options
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int field_opts_on(FIELD * field, Field_Options opts)
+{
+ int res = E_BAD_ARGUMENT;
+
+ opts &= ALL_FIELD_OPTS;
+ if (!(opts & ~ALL_FIELD_OPTS))
+ {
+ Normalize_Field( field );
+ res = _nc_Synchronize_Options( field, field->opts | opts );
+ }
+ RETURN(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int field_opts_off(FIELD *field, Field_Options opts)
+|
+| Description : Turns off the named options for this field and all the
+| remaining options are unchanged.
+|
+| Return Values : E_OK - success
+| E_CURRENT - the field is the current field
+| E_BAD_ARGUMENT - invalid options
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int field_opts_off(FIELD * field, Field_Options opts)
+{
+ int res = E_BAD_ARGUMENT;
+
+ opts &= ALL_FIELD_OPTS;
+ if (!(opts & ~ALL_FIELD_OPTS))
+ {
+ Normalize_Field( field );
+ res = _nc_Synchronize_Options( field, field->opts & ~opts );
+ }
+ RETURN(res);
+}
+
+/* fld_opts.c ends here */
diff --git a/Source/CursesDialog/form/fld_pad.c b/Source/CursesDialog/form/fld_pad.c
new file mode 100644
index 0000000..4598340
--- /dev/null
+++ b/Source/CursesDialog/form/fld_pad.c
@@ -0,0 +1,78 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_pad(FIELD *field, int ch)
+|
+| Description : Set the pad character used to fill the field. This must
+| be a printable character.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid field pointer or pad character
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int set_field_pad(FIELD * field, int ch)
+{
+ int res = E_BAD_ARGUMENT;
+
+ Normalize_Field( field );
+ if (isprint((unsigned char)ch))
+ {
+ if (field->pad != ch)
+ {
+ field->pad = ch;
+ res = _nc_Synchronize_Attributes( field );
+ }
+ else
+ res = E_OK;
+ }
+ RETURN(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int field_pad(const FIELD *field)
+|
+| Description : Retrieve the fields pad character.
+|
+| Return Values : The pad character.
++--------------------------------------------------------------------------*/
+int field_pad(const FIELD * field)
+{
+ return Normalize_Field( field )->pad;
+}
+
+/* fld_pad.c ends here */
diff --git a/Source/CursesDialog/form/fld_page.c b/Source/CursesDialog/form/fld_page.c
new file mode 100644
index 0000000..408e712
--- /dev/null
+++ b/Source/CursesDialog/form/fld_page.c
@@ -0,0 +1,76 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_new_page(FIELD *field, bool new_page_flag)
+|
+| Description : Marks the field as the beginning of a new page of
+| the form.
+|
+| Return Values : E_OK - success
+| E_CONNECTED - field is connected
++--------------------------------------------------------------------------*/
+int set_new_page(FIELD * field, bool new_page_flag)
+{
+ Normalize_Field(field);
+ if (field->form)
+ RETURN(E_CONNECTED);
+
+ if (new_page_flag)
+ field->status |= _NEWPAGE;
+ else
+ field->status &= ~_NEWPAGE;
+
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : bool new_page(const FIELD *field)
+|
+| Description : Retrieve the info whether or not the field starts a
+| new page on the form.
+|
+| Return Values : TRUE - field starts a new page
+| FALSE - field doesn't start a new page
++--------------------------------------------------------------------------*/
+bool new_page(const FIELD * field)
+{
+ return (Normalize_Field(field)->status & _NEWPAGE) ? TRUE : FALSE;
+}
+
+/* fld_page.c ends here */
diff --git a/Source/CursesDialog/form/fld_stat.c b/Source/CursesDialog/form/fld_stat.c
new file mode 100644
index 0000000..ee6831b
--- /dev/null
+++ b/Source/CursesDialog/form/fld_stat.c
@@ -0,0 +1,73 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_status(FIELD *field, bool status)
+|
+| Description : Set or clear the 'changed' indication flag for that
+| fields primary buffer.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+int set_field_status(FIELD * field, bool status)
+{
+ Normalize_Field( field );
+
+ if (status)
+ field->status |= _CHANGED;
+ else
+ field->status &= ~_CHANGED;
+
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : bool field_status(const FIELD *field)
+|
+| Description : Retrieve the value of the 'changed' indication flag
+| for that fields primary buffer.
+|
+| Return Values : TRUE - buffer has been changed
+| FALSE - buffer has not been changed
++--------------------------------------------------------------------------*/
+bool field_status(const FIELD * field)
+{
+ return ((Normalize_Field(field)->status & _CHANGED) ? TRUE : FALSE);
+}
+
+/* fld_stat.c ends here */
diff --git a/Source/CursesDialog/form/fld_type.c b/Source/CursesDialog/form/fld_type.c
new file mode 100644
index 0000000..6c9def2
--- /dev/null
+++ b/Source/CursesDialog/form/fld_type.c
@@ -0,0 +1,51 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELDTYPE *field_type(const FIELD *field)
+|
+| Description : Retrieve the associated fieldtype for this field.
+|
+| Return Values : Pointer to fieldtype of NULL if none is defined.
++--------------------------------------------------------------------------*/
+FIELDTYPE *field_type(const FIELD * field)
+{
+ return Normalize_Field(field)->type;
+}
+
+/* fld_type.c ends here */
diff --git a/Source/CursesDialog/form/fld_user.c b/Source/CursesDialog/form/fld_user.c
new file mode 100644
index 0000000..3287b5b
--- /dev/null
+++ b/Source/CursesDialog/form/fld_user.c
@@ -0,0 +1,67 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_userptr(FIELD *field, void *usrptr)
+|
+| Description : Set the pointer that is reserved in any field to store
+| application relevant information
+|
+| Return Values : E_OK - on success
++--------------------------------------------------------------------------*/
+int set_field_userptr(FIELD * field, void *usrptr)
+{
+ Normalize_Field( field )->usrptr = usrptr;
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : void *field_userptr(const FIELD *field)
+|
+| Description : Return the pointer that is reserved in any field to
+| store application relevant information.
+|
+| Return Values : Value of pointer. If no such pointer has been set,
+| NULL is returned
++--------------------------------------------------------------------------*/
+void *field_userptr(const FIELD *field)
+{
+ return Normalize_Field( field )->usrptr;
+}
+
+/* fld_user.c ends here */
diff --git a/Source/CursesDialog/form/form.h b/Source/CursesDialog/form/form.h
new file mode 100644
index 0000000..39ed75a
--- /dev/null
+++ b/Source/CursesDialog/form/form.h
@@ -0,0 +1,407 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#ifndef FORM_H
+#define FORM_H
+
+#include "cmFormConfigure.h"
+
+/* figure out which curses.h to include */
+# if defined(CURSES_HAVE_NCURSES_H)
+# include <ncurses.h>
+# elif defined(CURSES_HAVE_NCURSES_NCURSES_H)
+# include <ncurses/ncurses.h>
+# elif defined(CURSES_HAVE_NCURSES_CURSES_H)
+# include <ncurses/curses.h>
+# else
+# if defined(__hpux)
+# if defined(_XOPEN_SOURCE_EXTENDED)
+# define HAVE__XOPEN_SOURCE_EXTENDED
+# else
+# define _XOPEN_SOURCE_EXTENDED
+# endif
+# endif
+# include <curses.h>
+# if defined(__hpux) && !defined(HAVE__XOPEN_SOURCE_EXTENDED)
+# undef _XOPEN_SOURCE_EXTENDED
+# endif
+# endif
+
+#include <eti.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+typedef int Form_Options;
+typedef int Field_Options;
+
+ /**********
+ * _PAGE *
+ **********/
+
+typedef struct {
+ short pmin; /* index of first field on page */
+ short pmax; /* index of last field on page */
+ short smin; /* index of top leftmost field on page */
+ short smax; /* index of bottom rightmost field on page */
+} _PAGE;
+
+ /**********
+ * FIELD *
+ **********/
+
+typedef struct fieldnode {
+ unsigned short status; /* flags */
+ short rows; /* size in rows */
+ short cols; /* size in cols */
+ short frow; /* first row */
+ short fcol; /* first col */
+ int drows; /* dynamic rows */
+ int dcols; /* dynamic cols */
+ int maxgrow; /* maximum field growth */
+ int nrow; /* offscreen rows */
+ short nbuf; /* additional buffers */
+ short just; /* justification */
+ short page; /* page on form */
+ short index; /* into form -> field */
+ int pad; /* pad character */
+ chtype fore; /* foreground attribute */
+ chtype back; /* background attribute */
+ Field_Options opts; /* options */
+ struct fieldnode * snext; /* sorted order pointer */
+ struct fieldnode * sprev; /* sorted order pointer */
+ struct fieldnode * link; /* linked field chain */
+ struct formnode * form; /* containing form */
+ struct typenode * type; /* field type */
+ void * arg; /* argument for type */
+ char * buf; /* field buffers */
+ void * usrptr; /* user pointer */
+} FIELD;
+
+ /**************
+ * FIELDTYPE *
+ **************/
+
+typedef struct typenode {
+ unsigned short status; /* flags */
+ long ref; /* reference count */
+ struct typenode * left; /* ptr to operand for | */
+ struct typenode * right; /* ptr to operand for | */
+
+ void* (*makearg)(va_list *); /* make fieldtype arg */
+ void* (*copyarg)(const void *); /* copy fieldtype arg */
+ void (*freearg)(void *); /* free fieldtype arg */
+
+ bool (*fcheck)(FIELD *,const void *); /* field validation */
+ bool (*ccheck)(int,const void *); /* character validation */
+
+ bool (*next)(FIELD *,const void *); /* enumerate next value */
+ bool (*prev)(FIELD *,const void *); /* enumerate prev value */
+
+} FIELDTYPE;
+
+ /*********
+ * FORM *
+ *********/
+
+typedef struct formnode {
+ unsigned short status; /* flags */
+ short rows; /* size in rows */
+ short cols; /* size in cols */
+ int currow; /* current row in field window*/
+ int curcol; /* current col in field window*/
+ int toprow; /* in scrollable field window */
+ int begincol; /* in horiz. scrollable field */
+ short maxfield; /* number of fields */
+ short maxpage; /* number of pages */
+ short curpage; /* index into page */
+ Form_Options opts; /* options */
+ WINDOW * win; /* window */
+ WINDOW * sub; /* subwindow */
+ WINDOW * w; /* window for current field */
+ FIELD ** field; /* field [maxfield] */
+ FIELD * current; /* current field */
+ _PAGE * page; /* page [maxpage] */
+ void * usrptr; /* user pointer */
+
+ void (*forminit)(struct formnode *);
+ void (*formterm)(struct formnode *);
+ void (*fieldinit)(struct formnode *);
+ void (*fieldterm)(struct formnode *);
+
+} FORM;
+
+typedef void (*Form_Hook)(FORM *);
+
+ /***************************
+ * miscellaneous #defines *
+ ***************************/
+
+/* field justification */
+#define NO_JUSTIFICATION (0)
+#define JUSTIFY_LEFT (1)
+#define JUSTIFY_CENTER (2)
+#define JUSTIFY_RIGHT (3)
+
+/* field options */
+#define O_VISIBLE (0x0001)
+#define O_ACTIVE (0x0002)
+#define O_PUBLIC (0x0004)
+#define O_EDIT (0x0008)
+#define O_WRAP (0x0010)
+#define O_BLANK (0x0020)
+#define O_AUTOSKIP (0x0040)
+#define O_NULLOK (0x0080)
+#define O_PASSOK (0x0100)
+#define O_STATIC (0x0200)
+
+/* form options */
+#define O_NL_OVERLOAD (0x0001)
+#define O_BS_OVERLOAD (0x0002)
+
+/* form driver commands */
+#define REQ_NEXT_PAGE (KEY_MAX + 1) /* move to next page */
+#define REQ_PREV_PAGE (KEY_MAX + 2) /* move to previous page */
+#define REQ_FIRST_PAGE (KEY_MAX + 3) /* move to first page */
+#define REQ_LAST_PAGE (KEY_MAX + 4) /* move to last page */
+
+#define REQ_NEXT_FIELD (KEY_MAX + 5) /* move to next field */
+#define REQ_PREV_FIELD (KEY_MAX + 6) /* move to previous field */
+#define REQ_FIRST_FIELD (KEY_MAX + 7) /* move to first field */
+#define REQ_LAST_FIELD (KEY_MAX + 8) /* move to last field */
+#define REQ_SNEXT_FIELD (KEY_MAX + 9) /* move to sorted next field */
+#define REQ_SPREV_FIELD (KEY_MAX + 10) /* move to sorted prev field */
+#define REQ_SFIRST_FIELD (KEY_MAX + 11) /* move to sorted first field */
+#define REQ_SLAST_FIELD (KEY_MAX + 12) /* move to sorted last field */
+#define REQ_LEFT_FIELD (KEY_MAX + 13) /* move to left to field */
+#define REQ_RIGHT_FIELD (KEY_MAX + 14) /* move to right to field */
+#define REQ_UP_FIELD (KEY_MAX + 15) /* move to up to field */
+#define REQ_DOWN_FIELD (KEY_MAX + 16) /* move to down to field */
+
+#define REQ_NEXT_CHAR (KEY_MAX + 17) /* move to next char in field */
+#define REQ_PREV_CHAR (KEY_MAX + 18) /* move to prev char in field */
+#define REQ_NEXT_LINE (KEY_MAX + 19) /* move to next line in field */
+#define REQ_PREV_LINE (KEY_MAX + 20) /* move to prev line in field */
+#define REQ_NEXT_WORD (KEY_MAX + 21) /* move to next word in field */
+#define REQ_PREV_WORD (KEY_MAX + 22) /* move to prev word in field */
+#define REQ_BEG_FIELD (KEY_MAX + 23) /* move to first char in field */
+#define REQ_END_FIELD (KEY_MAX + 24) /* move after last char in fld */
+#define REQ_BEG_LINE (KEY_MAX + 25) /* move to beginning of line */
+#define REQ_END_LINE (KEY_MAX + 26) /* move after last char in line */
+#define REQ_LEFT_CHAR (KEY_MAX + 27) /* move left in field */
+#define REQ_RIGHT_CHAR (KEY_MAX + 28) /* move right in field */
+#define REQ_UP_CHAR (KEY_MAX + 29) /* move up in field */
+#define REQ_DOWN_CHAR (KEY_MAX + 30) /* move down in field */
+
+#define REQ_NEW_LINE (KEY_MAX + 31) /* insert/overlay new line */
+#define REQ_INS_CHAR (KEY_MAX + 32) /* insert blank char at cursor */
+#define REQ_INS_LINE (KEY_MAX + 33) /* insert blank line at cursor */
+#define REQ_DEL_CHAR (KEY_MAX + 34) /* delete char at cursor */
+#define REQ_DEL_PREV (KEY_MAX + 35) /* delete char before cursor */
+#define REQ_DEL_LINE (KEY_MAX + 36) /* delete line at cursor */
+#define REQ_DEL_WORD (KEY_MAX + 37) /* delete line at cursor */
+#define REQ_CLR_EOL (KEY_MAX + 38) /* clear to end of line */
+#define REQ_CLR_EOF (KEY_MAX + 39) /* clear to end of field */
+#define REQ_CLR_FIELD (KEY_MAX + 40) /* clear entire field */
+#define REQ_OVL_MODE (KEY_MAX + 41) /* begin overlay mode */
+#define REQ_INS_MODE (KEY_MAX + 42) /* begin insert mode */
+#define REQ_SCR_FLINE (KEY_MAX + 43) /* scroll field forward a line */
+#define REQ_SCR_BLINE (KEY_MAX + 44) /* scroll field backward a line */
+#define REQ_SCR_FPAGE (KEY_MAX + 45) /* scroll field forward a page */
+#define REQ_SCR_BPAGE (KEY_MAX + 46) /* scroll field backward a page */
+#define REQ_SCR_FHPAGE (KEY_MAX + 47) /* scroll field forward half page */
+#define REQ_SCR_BHPAGE (KEY_MAX + 48) /* scroll field backward half page */
+#define REQ_SCR_FCHAR (KEY_MAX + 49) /* horizontal scroll char */
+#define REQ_SCR_BCHAR (KEY_MAX + 50) /* horizontal scroll char */
+#define REQ_SCR_HFLINE (KEY_MAX + 51) /* horizontal scroll line */
+#define REQ_SCR_HBLINE (KEY_MAX + 52) /* horizontal scroll line */
+#define REQ_SCR_HFHALF (KEY_MAX + 53) /* horizontal scroll half line */
+#define REQ_SCR_HBHALF (KEY_MAX + 54) /* horizontal scroll half line */
+
+#define REQ_VALIDATION (KEY_MAX + 55) /* validate field */
+#define REQ_NEXT_CHOICE (KEY_MAX + 56) /* display next field choice */
+#define REQ_PREV_CHOICE (KEY_MAX + 57) /* display prev field choice */
+
+#define MIN_FORM_COMMAND (KEY_MAX + 1) /* used by form_driver */
+#define MAX_FORM_COMMAND (KEY_MAX + 57) /* used by form_driver */
+
+#if defined(MAX_COMMAND)
+# if (MAX_FORM_COMMAND > MAX_COMMAND)
+# error Something is wrong -- MAX_FORM_COMMAND is greater than MAX_COMMAND
+# elif (MAX_COMMAND != (KEY_MAX + 128))
+# error Something is wrong -- MAX_COMMAND is already inconsistently defined.
+# endif
+#else
+# define MAX_COMMAND (KEY_MAX + 128)
+#endif
+
+ /*************************
+ * standard field types *
+ *************************/
+extern FIELDTYPE *TYPE_ALPHA,
+ *TYPE_ALNUM,
+ *TYPE_ENUM,
+ *TYPE_INTEGER,
+ *TYPE_NUMERIC,
+ *TYPE_REGEXP;
+
+ /************************************
+ * built-in additional field types *
+ * They are not defined in SVr4 *
+ ************************************/
+extern FIELDTYPE *TYPE_IPV4; /* Internet IP Version 4 address */
+
+ /***********************
+ * Default objects *
+ ***********************/
+extern FORM *_nc_Default_Form;
+extern FIELD *_nc_Default_Field;
+
+
+ /***********************
+ * FIELDTYPE routines *
+ ***********************/
+extern FIELDTYPE
+ *new_fieldtype(
+ bool (* const field_check)(FIELD *,const void *),
+ bool (* const char_check)(int,const void *)),
+ *link_fieldtype(FIELDTYPE *,FIELDTYPE *);
+
+extern int free_fieldtype(FIELDTYPE *),
+ set_fieldtype_choice (FIELDTYPE *,
+ bool (* const next_choice)(FIELD *,const void *),
+ bool (* const prev_choice)(FIELD *,const void *));
+
+ /*******************
+ * FIELD routines *
+ *******************/
+extern FIELD *new_field(int,int,int,int,int,int),
+ *dup_field(FIELD *,int,int),
+ *link_field(FIELD *,int,int);
+
+extern int free_field(FIELD *),
+ field_info(const FIELD *,int *,int *,int *,int *,int *,int *),
+ dynamic_field_info(const FIELD *,int *,int *,int *),
+ set_max_field( FIELD *,int),
+ move_field(FIELD *,int,int),
+ set_field_type(FIELD *,FIELDTYPE *,...),
+ set_new_page(FIELD *,bool),
+ set_field_just(FIELD *,int),
+ field_just(const FIELD *),
+ set_field_fore(FIELD *,chtype),
+ set_field_back(FIELD *,chtype),
+ set_field_pad(FIELD *,int),
+ field_pad(const FIELD *),
+ set_field_buffer(FIELD *,int,const char *),
+ set_field_status(FIELD *,bool),
+ set_field_userptr(FIELD *, void *),
+ set_field_opts(FIELD *,Field_Options),
+ field_opts_on(FIELD *,Field_Options),
+ field_opts_off(FIELD *,Field_Options);
+
+extern chtype field_fore(const FIELD *),
+ field_back(const FIELD *);
+
+extern bool new_page(const FIELD *),
+ field_status(const FIELD *);
+
+extern void *field_arg(const FIELD *);
+
+extern void *field_userptr(const FIELD *);
+
+extern FIELDTYPE
+ *field_type(const FIELD *);
+
+extern char* field_buffer(const FIELD *,int);
+
+extern Field_Options
+ field_opts(const FIELD *);
+
+ /******************
+ * FORM routines *
+ ******************/
+extern FORM *new_form(FIELD **);
+
+extern FIELD **form_fields(const FORM *),
+ *current_field(const FORM *);
+
+extern WINDOW *form_win(const FORM *),
+ *form_sub(const FORM *);
+
+extern Form_Hook
+ form_init(const FORM *),
+ form_term(const FORM *),
+ field_init(const FORM *),
+ field_term(const FORM *);
+
+extern int free_form(FORM *),
+ set_form_fields(FORM *,FIELD **),
+ field_count(const FORM *),
+ set_form_win(FORM *,WINDOW *),
+ set_form_sub(FORM *,WINDOW *),
+ set_current_field(FORM *,FIELD *),
+ field_index(const FIELD *),
+ set_form_page(FORM *,int),
+ form_page(const FORM *),
+ scale_form(const FORM *,int *,int *),
+ set_form_init(FORM *,Form_Hook),
+ set_form_term(FORM *,Form_Hook),
+ set_field_init(FORM *,Form_Hook),
+ set_field_term(FORM *,Form_Hook),
+ post_form(FORM *),
+ unpost_form(FORM *),
+ pos_form_cursor(FORM *),
+ form_driver(FORM *,int),
+ set_form_userptr(FORM *,void *),
+ set_form_opts(FORM *,Form_Options),
+ form_opts_on(FORM *,Form_Options),
+ form_opts_off(FORM *,Form_Options),
+ form_request_by_name(const char *);
+
+extern const char
+ *form_request_name(int);
+
+extern void *form_userptr(const FORM *);
+
+extern Form_Options
+ form_opts(const FORM *);
+
+extern bool data_ahead(const FORM *),
+ data_behind(const FORM *);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* FORM_H */
diff --git a/Source/CursesDialog/form/form.priv.h b/Source/CursesDialog/form/form.priv.h
new file mode 100644
index 0000000..6e00af6
--- /dev/null
+++ b/Source/CursesDialog/form/form.priv.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "mf_common.h"
+#include "form.h"
+
+/* form status values */
+#define _OVLMODE (0x04) /* Form is in overlay mode */
+#define _WINDOW_MODIFIED (0x10) /* Current field window has been modified */
+#define _FCHECK_REQUIRED (0x20) /* Current field needs validation */
+
+/* field status values */
+#define _CHANGED (0x01) /* Field has been changed */
+#define _NEWTOP (0x02) /* Vertical scrolling occurred */
+#define _NEWPAGE (0x04) /* field begins new page of form */
+#define _MAY_GROW (0x08) /* dynamic field may still grow */
+
+/* fieldtype status values */
+#define _LINKED_TYPE (0x01) /* Type is a linked type */
+#define _HAS_ARGS (0x02) /* Type has arguments */
+#define _HAS_CHOICE (0x04) /* Type has choice methods */
+#define _RESIDENT (0x08) /* Type is builtin */
+
+/* This are the field options required to be a selectable field in field
+ navigation requests */
+#define O_SELECTABLE (O_ACTIVE | O_VISIBLE)
+
+/* If form is NULL replace form argument by default-form */
+#define Normalize_Form(form) ((form)=(form)?(form):_nc_Default_Form)
+
+/* If field is NULL replace field argument by default-field */
+#define Normalize_Field(field) ((field)=(field)?(field):_nc_Default_Field)
+
+/* Retrieve forms window */
+#define Get_Form_Window(form) \
+ ((form)->sub?(form)->sub:((form)->win?(form)->win:stdscr))
+
+/* Calculate the size for a single buffer for this field */
+#define Buffer_Length(field) ((field)->drows * (field)->dcols)
+
+/* Calculate the total size of all buffers for this field */
+#define Total_Buffer_Size(field) \
+ ( (Buffer_Length(field) + 1) * (1+(field)->nbuf) )
+
+/* Logic to determine whether or not a field is single lined */
+#define Single_Line_Field(field) \
+ (((field)->rows + (field)->nrow) == 1)
+
+/* Logic to determine whether or not a field is selectable */
+#define Field_Is_Selectable(f) (((f)->opts & O_SELECTABLE)==O_SELECTABLE)
+#define Field_Is_Not_Selectable(f) (((f)->opts & O_SELECTABLE)!=O_SELECTABLE)
+
+typedef struct typearg {
+ struct typearg *left;
+ struct typearg *right;
+} TypeArgument;
+
+/* This is a dummy request code (normally invalid) to be used internally
+ with the form_driver() routine to position to the first active field
+ on the form
+*/
+#define FIRST_ACTIVE_MAGIC (-291056)
+
+#define ALL_FORM_OPTS ( \
+ O_NL_OVERLOAD |\
+ O_BS_OVERLOAD )
+
+#define ALL_FIELD_OPTS ( \
+ O_VISIBLE |\
+ O_ACTIVE |\
+ O_PUBLIC |\
+ O_EDIT |\
+ O_WRAP |\
+ O_BLANK |\
+ O_AUTOSKIP|\
+ O_NULLOK |\
+ O_PASSOK |\
+ O_STATIC )
+
+
+#define C_BLANK ' '
+#define is_blank(c) ((c)==C_BLANK)
+
+extern const FIELDTYPE* _nc_Default_FieldType;
+
+extern TypeArgument* _nc_Make_Argument(const FIELDTYPE*,va_list*,int*);
+extern TypeArgument *_nc_Copy_Argument(const FIELDTYPE*,const TypeArgument*, int*);
+extern void _nc_Free_Argument(const FIELDTYPE*,TypeArgument*);
+extern bool _nc_Copy_Type(FIELD*, FIELD const *);
+extern void _nc_Free_Type(FIELD *);
+
+extern int _nc_Synchronize_Attributes(FIELD*);
+extern int _nc_Synchronize_Options(FIELD*,Field_Options);
+extern int _nc_Set_Form_Page(FORM*,int,FIELD*);
+extern int _nc_Refresh_Current_Field(FORM*);
+extern FIELD* _nc_First_Active_Field(FORM*);
+extern bool _nc_Internal_Validation(FORM*);
+extern int _nc_Set_Current_Field(FORM*,FIELD*);
+extern int _nc_Position_Form_Cursor(FORM*);
diff --git a/Source/CursesDialog/form/frm_cursor.c b/Source/CursesDialog/form/frm_cursor.c
new file mode 100644
index 0000000..6c311fe
--- /dev/null
+++ b/Source/CursesDialog/form/frm_cursor.c
@@ -0,0 +1,66 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int pos_form_cursor(FORM * form)
+|
+| Description : Moves the form window cursor to the location required
+| by the form driver to resume form processing. This may
+| be needed after the application calls a curses library
+| I/O routine that modifies the cursor position.
+|
+| Return Values : E_OK - Success
+| E_SYSTEM_ERROR - System error.
+| E_BAD_ARGUMENT - Invalid form pointer
+| E_NOT_POSTED - Form is not posted
++--------------------------------------------------------------------------*/
+int pos_form_cursor(FORM * form)
+{
+ int res;
+
+ if (!form)
+ res = E_BAD_ARGUMENT;
+ else
+ {
+ if (!(form->status & _POSTED))
+ res = E_NOT_POSTED;
+ else
+ res = _nc_Position_Form_Cursor(form);
+ }
+ RETURN(res);
+}
+
+/* frm_cursor.c ends here */
diff --git a/Source/CursesDialog/form/frm_data.c b/Source/CursesDialog/form/frm_data.c
new file mode 100644
index 0000000..fb62ab8
--- /dev/null
+++ b/Source/CursesDialog/form/frm_data.c
@@ -0,0 +1,183 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+extern int winnstr(WINDOW *, char *, int);
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : bool data_behind(const FORM *form)
+|
+| Description : Check for off-screen data behind. This is nearly trivial
+| becose the begin of a field is fixed.
+|
+| Return Values : TRUE - there are off-screen data behind
+| FALSE - there are no off-screen data behind
++--------------------------------------------------------------------------*/
+bool data_behind(const FORM *form)
+{
+ bool result = FALSE;
+
+ if (form && (form->status & _POSTED) && form->current)
+ {
+ FIELD *field;
+
+ field = form->current;
+ if (!Single_Line_Field(field))
+ {
+ result = (form->toprow==0) ? FALSE : TRUE;
+ }
+ else
+ {
+ result = (form->begincol==0) ? FALSE : TRUE;
+ }
+ }
+ return(result);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static char * After_Last_Non_Pad_Position(
+| char *buffer,
+| int len,
+| int pad)
+|
+| Description : Find the last position in the buffer that doesn't
+| contain a padding character.
+|
+| Return Values : The pointer to this position
++--------------------------------------------------------------------------*/
+INLINE
+static char * After_Last_Non_Pad_Position(char *buffer, int len, int pad)
+{
+ char *end = buffer + len;
+
+ assert(buffer && len>=0);
+ while ( (buffer < end) && (*(end-1)==pad) )
+ end--;
+
+ return end;
+}
+
+#define SMALL_BUFFER_SIZE (80)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : bool data_ahead(const FORM *form)
+|
+| Description : Check for off-screen data ahead. This is more difficult
+| because a dynamic field has a variable end.
+|
+| Return Values : TRUE - there are off-screen data ahead
+| FALSE - there are no off-screen data ahead
++--------------------------------------------------------------------------*/
+bool data_ahead(const FORM *form)
+{
+ bool result = FALSE;
+
+ if (form && (form->status & _POSTED) && form->current)
+ {
+ static char buffer[SMALL_BUFFER_SIZE + 1];
+ FIELD *field;
+ bool large_buffer;
+ bool cursor_moved = FALSE;
+ char *bp;
+ char *found_content;
+ int pos;
+
+ field = form->current;
+ assert(form->w != 0);
+
+ large_buffer = (field->cols > SMALL_BUFFER_SIZE);
+ if (large_buffer)
+ bp = (char *)malloc((size_t)(field->cols) + 1);
+ else
+ bp = buffer;
+
+ assert(bp != 0);
+
+ if (Single_Line_Field(field))
+ {
+ int check_len;
+
+ pos = form->begincol + field->cols;
+ while (pos < field->dcols)
+ {
+ check_len = field->dcols - pos;
+ if ( check_len >= field->cols )
+ check_len = field->cols;
+ cursor_moved = TRUE;
+ wmove(form->w,0,pos);
+ winnstr(form->w,bp,check_len);
+ found_content =
+ After_Last_Non_Pad_Position(bp,check_len,field->pad);
+ if (found_content==bp)
+ pos += field->cols;
+ else
+ {
+ result = TRUE;
+ break;
+ }
+ }
+ }
+ else
+ {
+ pos = form->toprow + field->rows;
+ while (pos < field->drows)
+ {
+ cursor_moved = TRUE;
+ wmove(form->w,pos,0);
+ pos++;
+ winnstr(form->w,bp,field->cols);
+ found_content =
+ After_Last_Non_Pad_Position(bp,field->cols,field->pad);
+ if (found_content!=bp)
+ {
+ result = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (large_buffer)
+ free(bp);
+
+ if (cursor_moved)
+ wmove(form->w,form->currow,form->curcol);
+ }
+ return(result);
+}
+
+/* frm_data.c ends here */
diff --git a/Source/CursesDialog/form/frm_def.c b/Source/CursesDialog/form/frm_def.c
new file mode 100644
index 0000000..645b3ba
--- /dev/null
+++ b/Source/CursesDialog/form/frm_def.c
@@ -0,0 +1,376 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/* this can't be readonly */
+static FORM default_form = {
+ 0, /* status */
+ 0, /* rows */
+ 0, /* cols */
+ 0, /* currow */
+ 0, /* curcol */
+ 0, /* toprow */
+ 0, /* begincol */
+ -1, /* maxfield */
+ -1, /* maxpage */
+ -1, /* curpage */
+ ALL_FORM_OPTS, /* opts */
+ (WINDOW *)0, /* win */
+ (WINDOW *)0, /* sub */
+ (WINDOW *)0, /* w */
+ (FIELD **)0, /* field */
+ (FIELD *)0, /* current */
+ (_PAGE *)0, /* page */
+ (char *)0, /* usrptr */
+ NULL, /* forminit */
+ NULL, /* formterm */
+ NULL, /* fieldinit */
+ NULL /* fieldterm */
+};
+
+FORM *_nc_Default_Form = &default_form;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Insert_Field_By_Position(
+| FIELD *new_field,
+| FIELD *head )
+|
+| Description : Insert new_field into sorted fieldlist with head "head"
+| and return new head of sorted fieldlist. Sorting
+| criteria is (row,column). This is a circular list.
+|
+| Return Values : New head of sorted fieldlist
++--------------------------------------------------------------------------*/
+static FIELD *Insert_Field_By_Position(FIELD *newfield, FIELD *head)
+{
+ FIELD *current, *newhead;
+
+ assert(newfield != 0);
+
+ if (!head)
+ { /* empty list is trivial */
+ newhead = newfield->snext = newfield->sprev = newfield;
+ }
+ else
+ {
+ newhead = current = head;
+ while((current->frow < newfield->frow) ||
+ ((current->frow==newfield->frow) &&
+ (current->fcol < newfield->fcol)) )
+ {
+ current = current->snext;
+ if (current==head)
+ { /* We cycled through. Reset head to indicate that */
+ head = (FIELD *)0;
+ break;
+ }
+ }
+ /* we leave the loop with current pointing to the field after newfield*/
+ newfield->snext = current;
+ newfield->sprev = current->sprev;
+ newfield->snext->sprev = newfield;
+ newfield->sprev->snext = newfield;
+ if (current==head)
+ newhead = newfield;
+ }
+ return(newhead);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Disconnect_Fields(FORM *form)
+|
+| Description : Break association between form and array of fields.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Disconnect_Fields( FORM * form )
+{
+ if (form->field)
+ {
+ FIELD **fields;
+
+ for(fields=form->field;*fields;fields++)
+ {
+ if (form == (*fields)->form)
+ (*fields)->form = (FORM *)0;
+ }
+
+ form->rows = form->cols = 0;
+ form->maxfield = form->maxpage = -1;
+ form->field = (FIELD **)0;
+ if (form->page)
+ free(form->page);
+ form->page = (_PAGE *)0;
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Connect_Fields(FORM *form, FIELD **fields)
+|
+| Description : Set association between form and array of fields.
+|
+| Return Values : E_OK - no error
+| E_CONNECTED - a field is already connected
+| E_BAD_ARGUMENT - Invalid form pointer or field array
+| E_SYSTEM_ERROR - not enough memory
++--------------------------------------------------------------------------*/
+static int Connect_Fields(FORM * form, FIELD ** fields)
+{
+ int field_cnt, j;
+ int page_nr;
+ int maximum_row_in_field, maximum_col_in_field;
+ _PAGE *pg;
+
+ assert(form != 0);
+
+ form->field = fields;
+ form->maxfield = 0;
+ form->maxpage = 0;
+
+ if (!fields)
+ RETURN(E_OK);
+
+ page_nr = 0;
+ /* store formpointer in fields and count pages */
+ for(field_cnt=0;fields[field_cnt];field_cnt++)
+ {
+ if (fields[field_cnt]->form)
+ RETURN(E_CONNECTED);
+ if ( field_cnt==0 ||
+ (fields[field_cnt]->status & _NEWPAGE))
+ page_nr++;
+ fields[field_cnt]->form = form;
+ }
+ if (field_cnt==0)
+ RETURN(E_BAD_ARGUMENT);
+
+ /* allocate page structures */
+ if ( (pg = (_PAGE *)malloc(page_nr * sizeof(_PAGE))) != (_PAGE *)0 )
+ {
+ form->page = pg;
+ }
+ else
+ RETURN(E_SYSTEM_ERROR);
+
+ /* Cycle through fields and calculate page boundaries as well as
+ size of the form */
+ for(j=0;j<field_cnt;j++)
+ {
+ if (j==0)
+ pg->pmin = j;
+ else
+ {
+ if (fields[j]->status & _NEWPAGE)
+ {
+ pg->pmax = j-1;
+ pg++;
+ pg->pmin = j;
+ }
+ }
+
+ maximum_row_in_field = fields[j]->frow + fields[j]->rows;
+ maximum_col_in_field = fields[j]->fcol + fields[j]->cols;
+
+ if (form->rows < maximum_row_in_field)
+ form->rows = maximum_row_in_field;
+ if (form->cols < maximum_col_in_field)
+ form->cols = maximum_col_in_field;
+ }
+
+ pg->pmax = field_cnt-1;
+ form->maxfield = field_cnt;
+ form->maxpage = page_nr;
+
+ /* Sort fields on form pages */
+ for(page_nr = 0;page_nr < form->maxpage; page_nr++)
+ {
+ FIELD *fld = (FIELD *)0;
+ for(j = form->page[page_nr].pmin;j <= form->page[page_nr].pmax;j++)
+ {
+ fields[j]->index = j;
+ fields[j]->page = page_nr;
+ fld = Insert_Field_By_Position(fields[j],fld);
+ }
+ form->page[page_nr].smin = fld->index;
+ form->page[page_nr].smax = fld->sprev->index;
+ }
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Associate_Fields(FORM *form, FIELD **fields)
+|
+| Description : Set association between form and array of fields.
+| If there are fields, position to first active field.
+|
+| Return Values : E_OK - success
+| any other - error occurred
++--------------------------------------------------------------------------*/
+INLINE static int Associate_Fields(FORM *form, FIELD **fields)
+{
+ int res = Connect_Fields(form,fields);
+ if (res == E_OK)
+ {
+ if (form->maxpage>0)
+ {
+ form->curpage = 0;
+ form_driver(form,FIRST_ACTIVE_MAGIC);
+ }
+ else
+ {
+ form->curpage = -1;
+ form->current = (FIELD *)0;
+ }
+ }
+ return(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FORM *new_form( FIELD **fields )
+|
+| Description : Create new form with given array of fields.
+|
+| Return Values : Pointer to form. NULL if error occurred.
++--------------------------------------------------------------------------*/
+FORM *new_form(FIELD ** fields)
+{
+ int err = E_SYSTEM_ERROR;
+
+ FORM *form = (FORM *)malloc(sizeof(FORM));
+
+ if (form)
+ {
+ *form = *_nc_Default_Form;
+ if ((err=Associate_Fields(form,fields))!=E_OK)
+ {
+ free_form(form);
+ form = (FORM *)0;
+ }
+ }
+
+ if (!form)
+ SET_ERROR(err);
+
+ return(form);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int free_form( FORM *form )
+|
+| Description : Release internal memory associated with form.
+|
+| Return Values : E_OK - no error
+| E_BAD_ARGUMENT - invalid form pointer
+| E_POSTED - form is posted
++--------------------------------------------------------------------------*/
+int free_form(FORM * form)
+{
+ if ( !form )
+ RETURN(E_BAD_ARGUMENT);
+
+ if ( form->status & _POSTED)
+ RETURN(E_POSTED);
+
+ Disconnect_Fields( form );
+ if (form->page)
+ free(form->page);
+ free(form);
+
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_fields( FORM *form, FIELD **fields )
+|
+| Description : Set a new association of an array of fields to a form
+|
+| Return Values : E_OK - no error
+| E_BAD_ARGUMENT - invalid form pointer
+| E_POSTED - form is posted
++--------------------------------------------------------------------------*/
+int set_form_fields(FORM * form, FIELD ** fields)
+{
+ FIELD **old;
+ int res;
+
+ if ( !form )
+ RETURN(E_BAD_ARGUMENT);
+
+ if ( form->status & _POSTED )
+ RETURN(E_POSTED);
+
+ old = form->field;
+ Disconnect_Fields( form );
+
+ if( (res = Associate_Fields( form, fields )) != E_OK )
+ Connect_Fields( form, old );
+
+ RETURN(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELD **form_fields( const FORM *form )
+|
+| Description : Retrieve array of fields
+|
+| Return Values : Pointer to field array
++--------------------------------------------------------------------------*/
+FIELD **form_fields(const FORM * form)
+{
+ return (Normalize_Form( form )->field);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int field_count( const FORM *form )
+|
+| Description : Retrieve number of fields
+|
+| Return Values : Number of fields, -1 if none are defined
++--------------------------------------------------------------------------*/
+int field_count(const FORM * form)
+{
+ return (Normalize_Form( form )->maxfield);
+}
+
+/* frm_def.c ends here */
diff --git a/Source/CursesDialog/form/frm_driver.c b/Source/CursesDialog/form/frm_driver.c
new file mode 100644
index 0000000..112ab08
--- /dev/null
+++ b/Source/CursesDialog/form/frm_driver.c
@@ -0,0 +1,3883 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+#include "form.priv.h"
+
+/* AIX seems to define this */
+#undef lines
+#undef columns
+
+MODULE_ID("$Id$")
+
+/* These declarations are missing from curses.h on some platforms. */
+extern int winnstr(WINDOW *, char *, int);
+#if defined(__DECCXX_VER) || (defined(__GNUC__) && defined(__osf__))
+extern int waddnstr(WINDOW *,const char *const,int);
+extern void wbkgdset(WINDOW *,chtype);
+#ifndef untouchwin
+extern int untouchwin(WINDOW *);
+#endif
+extern void wcursyncup(WINDOW *);
+extern int copywin(const WINDOW*,WINDOW*,int,int,int,int,int,int,int);
+extern bool is_linetouched(WINDOW *,int);
+extern void wsyncup(WINDOW *);
+extern WINDOW *derwin(WINDOW *,int,int,int,int);
+extern int winsnstr(WINDOW *, const char *,int);
+extern int winsdelln(WINDOW *,int);
+#endif
+
+/*----------------------------------------------------------------------------
+ This is the core module of the form library. It contains the majority
+ of the driver routines as well as the form_driver function.
+
+ Essentially this module is nearly the whole library. This is because
+ all the functions in this module depends on some others in the module,
+ so it makes no sense to split them into separate files because they
+ will always be linked together. The only acceptable concern is turnaround
+ time for this module, but now we have all Pentiums or Riscs, so what!
+
+ The driver routines are grouped into nine generic categories:
+
+ a) Page Navigation ( all functions prefixed by PN_ )
+ The current page of the form is left and some new page is
+ entered.
+ b) Inter-Field Navigation ( all functions prefixed by FN_ )
+ The current field of the form is left and some new field is
+ entered.
+ c) Intra-Field Navigation ( all functions prefixed by IFN_ )
+ The current position in the current field is changed.
+ d) Vertical Scrolling ( all functions prefixed by VSC_ )
+ Esseantially this is a specialization of Intra-Field navigation.
+ It has to check for a multi-line field.
+ e) Horizontal Scrolling ( all functions prefixed by HSC_ )
+ Esseantially this is a specialization of Intra-Field navigation.
+ It has to check for a single-line field.
+ f) Field Editing ( all functions prefixed by FE_ )
+ The content of the current field is changed
+ g) Edit Mode requests ( all functions prefixed by EM_ )
+ Switching between insert and overlay mode
+ h) Field-Validation requests ( all functions prefixed by FV_ )
+ Perform verifications of the field.
+ i) Choice requests ( all functions prefixed by CR_ )
+ Requests to enumerate possible field values
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Some remarks on the placements of assert() macros :
+ I use them only on "strategic" places, i.e. top level entries where
+ I want to make sure that things are set correctly. Throughout subordinate
+ routines I omit them mostly.
+ --------------------------------------------------------------------------*/
+
+/*
+Some options that may effect compatibility in behavior to SVr4 forms,
+but they are here to allow a more intuitive and user friendly behaviour of
+our form implementation. This doesn't affect the API, so we feel it is
+uncritical.
+
+The initial implementation tries to stay very close with the behaviour
+of the original SVr4 implementation, although in some areas it is quite
+clear that this isn't the most appropriate way. As far as possible this
+sources will allow you to build a forms lib that behaves quite similar
+to SVr4, but now and in the future we will give you better options.
+Perhaps at some time we will make this configurable at runtime.
+*/
+
+/* Implement a more user-friendly previous/next word behaviour */
+#define FRIENDLY_PREV_NEXT_WORD (1)
+/* Fix the wrong behaviour for forms with all fields inactive */
+#define FIX_FORM_INACTIVE_BUG (1)
+/* Allow dynamic field growth also when navigating past the end */
+#define GROW_IF_NAVIGATE (1)
+
+/*----------------------------------------------------------------------------
+ Forward references to some internally used static functions
+ --------------------------------------------------------------------------*/
+static int Inter_Field_Navigation ( int (* const fct) (FORM *), FORM * form );
+static int FN_Next_Field (FORM * form);
+static int FN_Previous_Field (FORM * form);
+static int FE_New_Line(FORM *);
+static int FE_Delete_Previous(FORM *);
+
+/*----------------------------------------------------------------------------
+ Macro Definitions.
+
+ Some Remarks on that: I use the convention to use UPPERCASE for constants
+ defined by Macros. If I provide a macro as a kind of inline routine to
+ provide some logic, I use my Upper_Lower case style.
+ --------------------------------------------------------------------------*/
+
+/* Calculate the position of a single row in a field buffer */
+#define Position_Of_Row_In_Buffer(field,row) ((row)*(field)->dcols)
+
+/* Calculate start address for the fields buffer# N */
+#define Address_Of_Nth_Buffer(field,N) \
+ ((field)->buf + (N)*(1+Buffer_Length(field)))
+
+/* Calculate the start address of the row in the fields specified buffer# N */
+#define Address_Of_Row_In_Nth_Buffer(field,N,row) \
+ (Address_Of_Nth_Buffer(field,N) + Position_Of_Row_In_Buffer(field,row))
+
+/* Calculate the start address of the row in the fields primary buffer */
+#define Address_Of_Row_In_Buffer(field,row) \
+ Address_Of_Row_In_Nth_Buffer(field,0,row)
+
+/* Calculate the start address of the row in the forms current field
+ buffer# N */
+#define Address_Of_Current_Row_In_Nth_Buffer(form,N) \
+ Address_Of_Row_In_Nth_Buffer((form)->current,N,(form)->currow)
+
+/* Calculate the start address of the row in the forms current field
+ primary buffer */
+#define Address_Of_Current_Row_In_Buffer(form) \
+ Address_Of_Current_Row_In_Nth_Buffer(form,0)
+
+/* Calculate the address of the cursor in the forms current field
+ primary buffer */
+#define Address_Of_Current_Position_In_Nth_Buffer(form,N) \
+ (Address_Of_Current_Row_In_Nth_Buffer(form,N) + (form)->curcol)
+
+/* Calculate the address of the cursor in the forms current field
+ buffer# N */
+#define Address_Of_Current_Position_In_Buffer(form) \
+ Address_Of_Current_Position_In_Nth_Buffer(form,0)
+
+/* Logic to decide whether or not a field is actually a field with
+ vertical or horizontal scrolling */
+#define Is_Scroll_Field(field) \
+ (((field)->drows > (field)->rows) || \
+ ((field)->dcols > (field)->cols))
+
+/* Logic to decide whether or not a field needs to have an individual window
+ instead of a derived window because it contains invisible parts.
+ This is true for non-public fields and for scrollable fields. */
+#define Has_Invisible_Parts(field) \
+ (!((field)->opts & O_PUBLIC) || \
+ Is_Scroll_Field(field))
+
+/* Logic to decide whether or not a field needs justification */
+#define Justification_Allowed(field) \
+ (((field)->just != NO_JUSTIFICATION) && \
+ (Single_Line_Field(field)) && \
+ (((field)->dcols == (field)->cols) && \
+ ((field)->opts & O_STATIC)) )
+
+/* Logic to determine whether or not a dynamic field may still grow */
+#define Growable(field) ((field)->status & _MAY_GROW)
+
+/* Macro to set the attributes for a fields window */
+#define Set_Field_Window_Attributes(field,win) \
+( wbkgdset((win),(chtype)((field)->pad | (field)->back)), \
+ wattrset((win),(field)->fore) )
+
+/* Logic to decide whether or not a field really appears on the form */
+#define Field_Really_Appears(field) \
+ ((field->form) &&\
+ (field->form->status & _POSTED) &&\
+ (field->opts & O_VISIBLE) &&\
+ (field->page == field->form->curpage))
+
+/* Logic to determine whether or not we are on the first position in the
+ current field */
+#define First_Position_In_Current_Field(form) \
+ (((form)->currow==0) && ((form)->curcol==0))
+
+
+#define Minimum(a,b) (((a)<=(b)) ? (a) : (b))
+#define Maximum(a,b) (((a)>=(b)) ? (a) : (b))
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static char *Get_Start_Of_Data(char * buf, int blen)
+|
+| Description : Return pointer to first non-blank position in buffer.
+| If buffer is empty return pointer to buffer itself.
+|
+| Return Values : Pointer to first non-blank position in buffer
++--------------------------------------------------------------------------*/
+INLINE static char *Get_Start_Of_Data(char * buf, int blen)
+{
+ char *p = buf;
+ char *end = &buf[blen];
+
+ assert(buf && blen>=0);
+ while( (p < end) && is_blank(*p) )
+ p++;
+ return( (p==end) ? buf : p );
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static char *After_End_Of_Data(char * buf, int blen)
+|
+| Description : Return pointer after last non-blank position in buffer.
+| If buffer is empty, return pointer to buffer itself.
+|
+| Return Values : Pointer to position after last non-blank position in
+| buffer.
++--------------------------------------------------------------------------*/
+INLINE static char *After_End_Of_Data(char * buf,int blen)
+{
+ char *p = &buf[blen];
+
+ assert(buf && blen>=0);
+ while( (p>buf) && is_blank(p[-1]) )
+ p--;
+ return( p );
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static char *Get_First_Whitespace_Character(
+| char * buf, int blen)
+|
+| Description : Position to the first whitespace character.
+|
+| Return Values : Pointer to first whitespace character in buffer.
++--------------------------------------------------------------------------*/
+INLINE static char *Get_First_Whitespace_Character(char * buf, int blen)
+{
+ char *p = buf;
+ char *end = &p[blen];
+
+ assert(buf && blen>=0);
+ while( (p < end) && !is_blank(*p))
+ p++;
+ return( (p==end) ? buf : p );
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static char *After_Last_Whitespace_Character(
+| char * buf, int blen)
+|
+| Description : Get the position after the last whitespace character.
+|
+| Return Values : Pointer to position after last whitespace character in
+| buffer.
++--------------------------------------------------------------------------*/
+INLINE static char *After_Last_Whitespace_Character(char * buf, int blen)
+{
+ char *p = &buf[blen];
+
+ assert(buf && blen>=0);
+ while( (p>buf) && !is_blank(p[-1]) )
+ p--;
+ return( p );
+}
+
+/* Set this to 1 to use the div_t version. This is a good idea if your
+ compiler has an intrinsic div() support. Unfortunately GNU-C has it
+ not yet.
+ N.B.: This only works if form->curcol follows immediately form->currow
+ and both are of type int.
+*/
+#define USE_DIV_T (0)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Adjust_Cursor_Position(
+| FORM * form, const char * pos)
+|
+| Description : Set current row and column of the form to values
+| corresponding to the buffer position.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+INLINE static void Adjust_Cursor_Position(FORM * form, const char * pos)
+{
+ FIELD *field;
+ int idx;
+
+ field = form->current;
+ assert( pos >= field->buf && field->dcols > 0);
+ idx = (int)( pos - field->buf );
+#if USE_DIV_T
+ *((div_t *)&(form->currow)) = div(idx,field->dcols);
+#else
+ form->currow = idx / field->dcols;
+ form->curcol = idx - field->cols * form->currow;
+#endif
+ if ( field->drows < form->currow )
+ form->currow = 0;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Buffer_To_Window(
+| const FIELD * field,
+| WINDOW * win)
+|
+| Description : Copy the buffer to the window. If its a multiline
+| field, the buffer is split to the lines of the
+| window without any editing.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Buffer_To_Window(const FIELD * field, WINDOW * win)
+{
+ int width, height;
+ int len;
+ int row;
+ char *pBuffer;
+
+ assert(win && field);
+
+ getmaxyx(win, height, width);
+
+ for(row=0, pBuffer=field->buf;
+ row < height;
+ row++, pBuffer += width )
+ {
+ if ((len = (int)( After_End_Of_Data( pBuffer, width ) - pBuffer )) > 0)
+ {
+ wmove( win, row, 0 );
+ waddnstr( win, pBuffer, len );
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Window_To_Buffer(
+| WINDOW * win,
+| FIELD * field)
+|
+| Description : Copy the content of the window into the buffer.
+| The multiple lines of a window are simply
+| concatenated into the buffer. Pad characters in
+| the window will be replaced by blanks in the buffer.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Window_To_Buffer(WINDOW * win, FIELD * field)
+{
+ int pad;
+ int len = 0;
+ char *p;
+ int row, height, width;
+
+ assert(win && field && field->buf );
+
+ pad = field->pad;
+ p = field->buf;
+ getmaxyx(win, height, width);
+
+ for(row=0; (row < height) && (row < field->drows); row++ )
+ {
+ wmove( win, row, 0 );
+ len += winnstr( win, p+len, field->dcols );
+ }
+ p[len] = '\0';
+
+ /* replace visual padding character by blanks in buffer */
+ if (pad != C_BLANK)
+ {
+ int i;
+ for(i=0; i<len; i++, p++)
+ {
+ if (*p==pad)
+ *p = C_BLANK;
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Synchronize_Buffer(FORM * form)
+|
+| Description : If there was a change, copy the content of the
+| window into the buffer, so the buffer is synchronized
+| with the windows content. We have to indicate that the
+| buffer needs validation due to the change.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+INLINE static void Synchronize_Buffer(FORM * form)
+{
+ if (form->status & _WINDOW_MODIFIED)
+ {
+ form->status &= ~_WINDOW_MODIFIED;
+ form->status |= _FCHECK_REQUIRED;
+ Window_To_Buffer(form->w,form->current);
+ wmove(form->w,form->currow,form->curcol);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Field_Grown( FIELD *field, int amount)
+|
+| Description : This function is called for growable dynamic fields
+| only. It has to increase the buffers and to allocate
+| a new window for this field.
+| This function has the side effect to set a new
+| field-buffer pointer, the dcols and drows values
+| as well as a new current Window for the field.
+|
+| Return Values : TRUE - field successfully increased
+| FALSE - there was some error
++--------------------------------------------------------------------------*/
+static bool Field_Grown(FIELD * field, int amount)
+{
+ bool result = FALSE;
+
+ if (field && Growable(field))
+ {
+ bool single_line_field = Single_Line_Field(field);
+ int old_buflen = Buffer_Length(field);
+ int new_buflen;
+ int old_dcols = field->dcols;
+ int old_drows = field->drows;
+ char *oldbuf = field->buf;
+ char *newbuf;
+
+ int growth;
+ FORM *form = field->form;
+ bool need_visual_update = ((form != (FORM *)0) &&
+ (form->status & _POSTED) &&
+ (form->current==field));
+
+ if (need_visual_update)
+ Synchronize_Buffer(form);
+
+ if (single_line_field)
+ {
+ growth = field->cols * amount;
+ if (field->maxgrow)
+ growth = Minimum(field->maxgrow - field->dcols,growth);
+ field->dcols += growth;
+ if (field->dcols == field->maxgrow)
+ field->status &= ~_MAY_GROW;
+ }
+ else
+ {
+ growth = (field->rows + field->nrow) * amount;
+ if (field->maxgrow)
+ growth = Minimum(field->maxgrow - field->drows,growth);
+ field->drows += growth;
+ if (field->drows == field->maxgrow)
+ field->status &= ~_MAY_GROW;
+ }
+ /* drows, dcols changed, so we get really the new buffer length */
+ new_buflen = Buffer_Length(field);
+ newbuf=(char *)malloc((size_t)Total_Buffer_Size(field));
+ if (!newbuf)
+ { /* restore to previous state */
+ field->dcols = old_dcols;
+ field->drows = old_drows;
+ if (( single_line_field && (field->dcols!=field->maxgrow)) ||
+ (!single_line_field && (field->drows!=field->maxgrow)))
+ field->status |= _MAY_GROW;
+ return FALSE;
+ }
+ else
+ { /* Copy all the buffers. This is the reason why we can't
+ just use realloc().
+ */
+ int i;
+ char *old_bp;
+ char *new_bp;
+
+ field->buf = newbuf;
+ for(i=0;i<=field->nbuf;i++)
+ {
+ new_bp = Address_Of_Nth_Buffer(field,i);
+ old_bp = oldbuf + i*(1+old_buflen);
+ memcpy(new_bp,old_bp,(size_t)old_buflen);
+ if (new_buflen > old_buflen)
+ memset(new_bp + old_buflen,C_BLANK,
+ (size_t)(new_buflen - old_buflen));
+ *(new_bp + new_buflen) = '\0';
+ }
+
+ if (need_visual_update)
+ {
+ WINDOW *new_window = newpad(field->drows,field->dcols);
+ if (!new_window)
+ { /* restore old state */
+ field->dcols = old_dcols;
+ field->drows = old_drows;
+ field->buf = oldbuf;
+ if (( single_line_field &&
+ (field->dcols!=field->maxgrow)) ||
+ (!single_line_field &&
+ (field->drows!=field->maxgrow)))
+ field->status |= _MAY_GROW;
+ free( newbuf );
+ return FALSE;
+ }
+ assert(form!=(FORM *)0);
+ delwin(form->w);
+ form->w = new_window;
+ Set_Field_Window_Attributes(field,form->w);
+ werase(form->w);
+ Buffer_To_Window(field,form->w);
+ untouchwin(form->w);
+ wmove(form->w,form->currow,form->curcol);
+ }
+
+ free(oldbuf);
+ /* reflect changes in linked fields */
+ if (field != field->link)
+ {
+ FIELD *linked_field;
+ for(linked_field = field->link;
+ linked_field!= field;
+ linked_field = linked_field->link)
+ {
+ linked_field->buf = field->buf;
+ linked_field->drows = field->drows;
+ linked_field->dcols = field->dcols;
+ }
+ }
+ result = TRUE;
+ }
+ }
+ return(result);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int _nc_Position_Form_Cursor(FORM * form)
+|
+| Description : Position the cursor in the window for the current
+| field to be in sync. with the currow and curcol
+| values.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid form pointer
+| E_SYSTEM_ERROR - form has no current field or
+| field-window
++--------------------------------------------------------------------------*/
+int
+_nc_Position_Form_Cursor(FORM * form)
+{
+ FIELD *field;
+ WINDOW *formwin;
+
+ if (!form)
+ return(E_BAD_ARGUMENT);
+
+ if (!form->w || !form->current)
+ return(E_SYSTEM_ERROR);
+
+ field = form->current;
+ formwin = Get_Form_Window(form);
+
+ wmove( form->w, form->currow, form->curcol );
+ if ( Has_Invisible_Parts(field) )
+ {
+ /* in this case fieldwin isn't derived from formwin, so we have
+ to move the cursor in formwin by hand... */
+ wmove(formwin,
+ field->frow + form->currow - form->toprow,
+ field->fcol + form->curcol - form->begincol);
+ wcursyncup(formwin);
+ }
+ else
+ wcursyncup(form->w);
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int _nc_Refresh_Current_Field(FORM * form)
+|
+| Description : Propagate the changes in the fields window to the
+| window of the form.
+|
+| Return Values : E_OK - on success
+| E_BAD_ARGUMENT - invalid form pointer
+| E_SYSTEM_ERROR - general error
++--------------------------------------------------------------------------*/
+int
+_nc_Refresh_Current_Field(FORM * form)
+{
+ WINDOW *formwin;
+ FIELD *field;
+
+ if (!form)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (!form->w || !form->current)
+ RETURN(E_SYSTEM_ERROR);
+
+ field = form->current;
+ formwin = Get_Form_Window(form);
+
+ if (field->opts & O_PUBLIC)
+ {
+ if (Is_Scroll_Field(field))
+ {
+ /* Again, in this case the fieldwin isn't derived from formwin,
+ so we have to perform a copy operation. */
+ if (Single_Line_Field(field))
+ { /* horizontal scrolling */
+ if (form->curcol < form->begincol)
+ form->begincol = form->curcol;
+ else
+ {
+ if (form->curcol >= (form->begincol + field->cols))
+ form->begincol = form->curcol - field->cols + 1;
+ }
+ copywin(form->w,
+ formwin,
+ 0,
+ form->begincol,
+ field->frow,
+ field->fcol,
+ field->frow,
+ field->cols + field->fcol - 1,
+ 0);
+ }
+ else
+ { /* A multiline, i.e. vertical scrolling field */
+ int row_after_bottom,first_modified_row,first_unmodified_row;
+
+ if (field->drows > field->rows)
+ {
+ row_after_bottom = form->toprow + field->rows;
+ if (form->currow < form->toprow)
+ {
+ form->toprow = form->currow;
+ field->status |= _NEWTOP;
+ }
+ if (form->currow >= row_after_bottom)
+ {
+ form->toprow = form->currow - field->rows + 1;
+ field->status |= _NEWTOP;
+ }
+ if (field->status & _NEWTOP)
+ { /* means we have to copy whole range */
+ first_modified_row = form->toprow;
+ first_unmodified_row = first_modified_row + field->rows;
+ field->status &= ~_NEWTOP;
+ }
+ else
+ { /* we try to optimize : finding the range of touched
+ lines */
+ first_modified_row = form->toprow;
+ while(first_modified_row < row_after_bottom)
+ {
+ if (is_linetouched(form->w,first_modified_row))
+ break;
+ first_modified_row++;
+ }
+ first_unmodified_row = first_modified_row;
+ while(first_unmodified_row < row_after_bottom)
+ {
+ if (!is_linetouched(form->w,first_unmodified_row))
+ break;
+ first_unmodified_row++;
+ }
+ }
+ }
+ else
+ {
+ first_modified_row = form->toprow;
+ first_unmodified_row = first_modified_row + field->rows;
+ }
+ if (first_unmodified_row != first_modified_row)
+ copywin(form->w,
+ formwin,
+ first_modified_row,
+ 0,
+ field->frow + first_modified_row - form->toprow,
+ field->fcol,
+ field->frow + first_unmodified_row - form->toprow - 1,
+ field->cols + field->fcol - 1,
+ 0);
+ }
+ wsyncup(formwin);
+ }
+ else
+ { /* if the field-window is simply a derived window, i.e. contains
+ no invisible parts, the whole thing is trivial
+ */
+ wsyncup(form->w);
+ }
+ }
+ untouchwin(form->w);
+ return _nc_Position_Form_Cursor(form);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Perform_Justification(
+| FIELD * field,
+| WINDOW * win)
+|
+| Description : Output field with requested justification
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Perform_Justification(FIELD * field, WINDOW * win)
+{
+ char *bp;
+ int len;
+ int col = 0;
+
+ bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
+ len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field)) - bp);
+
+ if (len>0)
+ {
+ assert(win && (field->drows == 1) && (field->dcols == field->cols));
+
+ switch(field->just)
+ {
+ case JUSTIFY_LEFT:
+ break;
+ case JUSTIFY_CENTER:
+ col = (field->cols - len)/2;
+ break;
+ case JUSTIFY_RIGHT:
+ col = field->cols - len;
+ break;
+ default:
+ break;
+ }
+
+ wmove(win,0,col);
+ waddnstr(win,bp,len);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Undo_Justification(
+| FIELD * field,
+| WINDOW * win)
+|
+| Description : Display field without any justification, i.e.
+| left justified
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Undo_Justification(FIELD * field, WINDOW * win)
+{
+ char *bp;
+ int len;
+
+ bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
+ len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field))-bp);
+
+ if (len>0)
+ {
+ assert(win != 0);
+ wmove(win,0,0);
+ waddnstr(win,bp,len);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Char(
+| FIELDTYPE * typ,
+| int ch,
+| TypeArgument *argp)
+|
+| Description : Perform a single character check for character ch
+| according to the fieldtype instance.
+|
+| Return Values : TRUE - Character is valid
+| FALSE - Character is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Char(FIELDTYPE * typ, int ch, TypeArgument *argp)
+{
+ if (typ)
+ {
+ if (typ->status & _LINKED_TYPE)
+ {
+ assert(argp != 0);
+ return(
+ Check_Char(typ->left ,ch,argp->left ) ||
+ Check_Char(typ->right,ch,argp->right) );
+ }
+ else
+ {
+ if (typ->ccheck)
+ return typ->ccheck(ch,(void *)argp);
+ }
+ }
+ return (isprint((unsigned char)ch) ? TRUE : FALSE);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Display_Or_Erase_Field(
+| FIELD * field,
+| bool bEraseFlag)
+|
+| Description : Create a subwindow for the field and display the
+| buffer contents (apply justification if required)
+| or simply erase the field.
+|
+| Return Values : E_OK - on success
+| E_SYSTEM_ERROR - some error (typical no memory)
++--------------------------------------------------------------------------*/
+static int Display_Or_Erase_Field(FIELD * field, bool bEraseFlag)
+{
+ WINDOW *win;
+ WINDOW *fwin;
+
+ if (!field)
+ return E_SYSTEM_ERROR;
+
+ fwin = Get_Form_Window(field->form);
+ win = derwin(fwin,
+ field->rows,field->cols,field->frow,field->fcol);
+
+ if (!win)
+ return E_SYSTEM_ERROR;
+ else
+ {
+ if (field->opts & O_VISIBLE)
+ Set_Field_Window_Attributes(field,win);
+ else
+ {
+#if defined(__LSB_VERSION__)
+ /* getattrs() would be handy, but it is not part of LSB 4.0 */
+ attr_t fwinAttrs;
+ short fwinPair;
+ wattr_get(fwin, &fwinAttrs, &fwinPair, 0);
+ wattr_set(win, fwinAttrs, fwinPair, 0);
+#else
+ wattrset(win,getattrs(fwin));
+#endif
+ }
+ werase(win);
+ }
+
+ if (!bEraseFlag)
+ {
+ if (field->opts & O_PUBLIC)
+ {
+ if (Justification_Allowed(field))
+ Perform_Justification(field,win);
+ else
+ Buffer_To_Window(field,win);
+ }
+ field->status &= ~_NEWTOP;
+ }
+ wsyncup(win);
+ delwin(win);
+ return E_OK;
+}
+
+/* Macros to preset the bEraseFlag */
+#define Display_Field(field) Display_Or_Erase_Field(field,FALSE)
+#define Erase_Field(field) Display_Or_Erase_Field(field,TRUE)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Synchronize_Field(FIELD * field)
+|
+| Description : Synchronize the windows content with the value in
+| the buffer.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid field pointer
+| E_SYSTEM_ERROR - some severe basic error
++--------------------------------------------------------------------------*/
+static int Synchronize_Field(FIELD * field)
+{
+ FORM *form;
+ int res = E_OK;
+
+ if (!field)
+ return(E_BAD_ARGUMENT);
+
+ if (((form=field->form) != (FORM *)0)
+ && Field_Really_Appears(field))
+ {
+ if (field == form->current)
+ {
+ form->currow = form->curcol = form->toprow = form->begincol = 0;
+ werase(form->w);
+
+ if ( (field->opts & O_PUBLIC) && Justification_Allowed(field) )
+ Undo_Justification( field, form->w );
+ else
+ Buffer_To_Window( field, form->w );
+
+ field->status |= _NEWTOP;
+ res = _nc_Refresh_Current_Field( form );
+ }
+ else
+ res = Display_Field( field );
+ }
+ field->status |= _CHANGED;
+ return(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Synchronize_Linked_Fields(FIELD * field)
+|
+| Description : Propagate the Synchronize_Field function to all linked
+| fields. The first error that occurs in the sequence
+| of updates is the returnvalue.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid field pointer
+| E_SYSTEM_ERROR - some severe basic error
++--------------------------------------------------------------------------*/
+static int Synchronize_Linked_Fields(FIELD * field)
+{
+ FIELD *linked_field;
+ int res = E_OK;
+ int syncres;
+
+ if (!field)
+ return(E_BAD_ARGUMENT);
+
+ if (!field->link)
+ return(E_SYSTEM_ERROR);
+
+ for(linked_field = field->link;
+ linked_field!= field;
+ linked_field = linked_field->link )
+ {
+ if (((syncres=Synchronize_Field(linked_field)) != E_OK) &&
+ (res==E_OK))
+ res = syncres;
+ }
+ return(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int _nc_Synchronize_Attributes(FIELD * field)
+|
+| Description : If a fields visual attributes have changed, this
+| routine is called to propagate those changes to the
+| screen.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid field pointer
+| E_SYSTEM_ERROR - some severe basic error
++--------------------------------------------------------------------------*/
+int _nc_Synchronize_Attributes(FIELD * field)
+{
+ FORM *form;
+ int res = E_OK;
+ WINDOW *formwin;
+
+ if (!field)
+ return(E_BAD_ARGUMENT);
+
+ if (((form=field->form) != (FORM *)0)
+ && Field_Really_Appears(field))
+ {
+ if (form->current==field)
+ {
+ Synchronize_Buffer(form);
+ Set_Field_Window_Attributes(field,form->w);
+ werase(form->w);
+ if (field->opts & O_PUBLIC)
+ {
+ if (Justification_Allowed(field))
+ Undo_Justification(field,form->w);
+ else
+ Buffer_To_Window(field,form->w);
+ }
+ else
+ {
+ formwin = Get_Form_Window(form);
+ copywin(form->w,formwin,
+ 0,0,
+ field->frow,field->fcol,
+ field->rows-1,field->cols-1,0);
+ wsyncup(formwin);
+ Buffer_To_Window(field,form->w);
+ field->status |= _NEWTOP; /* fake refresh to paint all */
+ _nc_Refresh_Current_Field(form);
+ }
+ }
+ else
+ {
+ res = Display_Field(field);
+ }
+ }
+ return(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int _nc_Synchronize_Options(FIELD * field,
+| Field_Options newopts)
+|
+| Description : If a fields options have changed, this routine is
+| called to propagate these changes to the screen and
+| to really change the behaviour of the field.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid field pointer
+| E_SYSTEM_ERROR - some severe basic error
++--------------------------------------------------------------------------*/
+int
+_nc_Synchronize_Options(FIELD *field, Field_Options newopts)
+{
+ Field_Options oldopts;
+ Field_Options changed_opts;
+ FORM *form;
+ int res = E_OK;
+
+ if (!field)
+ return(E_BAD_ARGUMENT);
+
+ oldopts = field->opts;
+ changed_opts = oldopts ^ newopts;
+ field->opts = newopts;
+ form = field->form;
+
+ if (form)
+ {
+ if (form->current == field)
+ {
+ field->opts = oldopts;
+ return(E_CURRENT);
+ }
+
+ if (form->status & _POSTED)
+ {
+ if (form->curpage == field->page)
+ {
+ if (changed_opts & O_VISIBLE)
+ {
+ if (newopts & O_VISIBLE)
+ res = Display_Field(field);
+ else
+ res = Erase_Field(field);
+ }
+ else
+ {
+ if ((changed_opts & O_PUBLIC) &&
+ (newopts & O_VISIBLE))
+ res = Display_Field(field);
+ }
+ }
+ }
+ }
+
+ if (changed_opts & O_STATIC)
+ {
+ bool single_line_field = Single_Line_Field(field);
+ int res2 = E_OK;
+
+ if (newopts & O_STATIC)
+ { /* the field becomes now static */
+ field->status &= ~_MAY_GROW;
+ /* if actually we have no hidden columns, justification may
+ occur again */
+ if (single_line_field &&
+ (field->cols == field->dcols) &&
+ (field->just != NO_JUSTIFICATION) &&
+ Field_Really_Appears(field))
+ {
+ res2 = Display_Field(field);
+ }
+ }
+ else
+ { /* field is no longer static */
+ if ((field->maxgrow==0) ||
+ ( single_line_field && (field->dcols < field->maxgrow)) ||
+ (!single_line_field && (field->drows < field->maxgrow)))
+ {
+ field->status |= _MAY_GROW;
+ /* a field with justification now changes its behaviour,
+ so we must redisplay it */
+ if (single_line_field &&
+ (field->just != NO_JUSTIFICATION) &&
+ Field_Really_Appears(field))
+ {
+ res2 = Display_Field(field);
+ }
+ }
+ }
+ if (res2 != E_OK)
+ res = res2;
+ }
+
+ return(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int _nc_Set_Current_Field(FORM * form,
+| FIELD * newfield)
+|
+| Description : Make the newfield the new current field.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid form or field pointer
+| E_SYSTEM_ERROR - some severe basic error
++--------------------------------------------------------------------------*/
+int
+_nc_Set_Current_Field(FORM *form, FIELD *newfield)
+{
+ FIELD *field;
+ WINDOW *new_window;
+
+ if (!form || !newfield || !form->current || (newfield->form!=form))
+ return(E_BAD_ARGUMENT);
+
+ if ( (form->status & _IN_DRIVER) )
+ return(E_BAD_STATE);
+
+ if (!(form->field))
+ return(E_NOT_CONNECTED);
+
+ field = form->current;
+
+ if ((field!=newfield) ||
+ !(form->status & _POSTED))
+ {
+ if ((form->w) &&
+ (field->opts & O_VISIBLE) &&
+ (field->form->curpage == field->page))
+ {
+ _nc_Refresh_Current_Field(form);
+ if (field->opts & O_PUBLIC)
+ {
+ if (field->drows > field->rows)
+ {
+ if (form->toprow==0)
+ field->status &= ~_NEWTOP;
+ else
+ field->status |= _NEWTOP;
+ }
+ else
+ {
+ if (Justification_Allowed(field))
+ {
+ Window_To_Buffer(form->w,field);
+ werase(form->w);
+ Perform_Justification(field,form->w);
+ wsyncup(form->w);
+ }
+ }
+ }
+ delwin(form->w);
+ }
+
+ field = newfield;
+
+ if (Has_Invisible_Parts(field))
+ new_window = newpad(field->drows,field->dcols);
+ else
+ new_window = derwin(Get_Form_Window(form),
+ field->rows,field->cols,field->frow,field->fcol);
+
+ if (!new_window)
+ return(E_SYSTEM_ERROR);
+
+ form->current = field;
+ form->w = new_window;
+ form->status &= ~_WINDOW_MODIFIED;
+ Set_Field_Window_Attributes(field,form->w);
+
+ if (Has_Invisible_Parts(field))
+ {
+ werase(form->w);
+ Buffer_To_Window(field,form->w);
+ }
+ else
+ {
+ if (Justification_Allowed(field))
+ {
+ werase(form->w);
+ Undo_Justification(field,form->w);
+ wsyncup(form->w);
+ }
+ }
+
+ untouchwin(form->w);
+ }
+
+ form->currow = form->curcol = form->toprow = form->begincol = 0;
+ return(E_OK);
+}
+
+/*----------------------------------------------------------------------------
+ Intra-Field Navigation routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Next_Character(FORM * form)
+|
+| Description : Move to the next character in the field. In a multiline
+| field this wraps at the end of the line.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - at the rightmost position
++--------------------------------------------------------------------------*/
+static int IFN_Next_Character(FORM * form)
+{
+ FIELD *field = form->current;
+
+ if ((++(form->curcol))==field->dcols)
+ {
+ if ((++(form->currow))==field->drows)
+ {
+#if GROW_IF_NAVIGATE
+ if (!Single_Line_Field(field) && Field_Grown(field,1)) {
+ form->curcol = 0;
+ return(E_OK);
+ }
+#endif
+ form->currow--;
+#if GROW_IF_NAVIGATE
+ if (Single_Line_Field(field) && Field_Grown(field,1))
+ return(E_OK);
+#endif
+ form->curcol--;
+ return(E_REQUEST_DENIED);
+ }
+ form->curcol = 0;
+ }
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Previous_Character(FORM * form)
+|
+| Description : Move to the previous character in the field. In a
+| multiline field this wraps and the beginning of the
+| line.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - at the leftmost position
++--------------------------------------------------------------------------*/
+static int IFN_Previous_Character(FORM * form)
+{
+ if ((--(form->curcol))<0)
+ {
+ if ((--(form->currow))<0)
+ {
+ form->currow++;
+ form->curcol++;
+ return(E_REQUEST_DENIED);
+ }
+ form->curcol = form->current->dcols - 1;
+ }
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Next_Line(FORM * form)
+|
+| Description : Move to the beginning of the next line in the field
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - at the last line
++--------------------------------------------------------------------------*/
+static int IFN_Next_Line(FORM * form)
+{
+ FIELD *field = form->current;
+
+ if ((++(form->currow))==field->drows)
+ {
+#if GROW_IF_NAVIGATE
+ if (!Single_Line_Field(field) && Field_Grown(field,1))
+ return(E_OK);
+#endif
+ form->currow--;
+ return(E_REQUEST_DENIED);
+ }
+ form->curcol = 0;
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Previous_Line(FORM * form)
+|
+| Description : Move to the beginning of the previous line in the field
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - at the first line
++--------------------------------------------------------------------------*/
+static int IFN_Previous_Line(FORM * form)
+{
+ if ( (--(form->currow)) < 0 )
+ {
+ form->currow++;
+ return(E_REQUEST_DENIED);
+ }
+ form->curcol = 0;
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Next_Word(FORM * form)
+|
+| Description : Move to the beginning of the next word in the field.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - there is no next word
++--------------------------------------------------------------------------*/
+static int IFN_Next_Word(FORM * form)
+{
+ FIELD *field = form->current;
+ char *bp = Address_Of_Current_Position_In_Buffer(form);
+ char *s;
+ char *t;
+
+ /* We really need access to the data, so we have to synchronize */
+ Synchronize_Buffer(form);
+
+ /* Go to the first whitespace after the current position (including
+ current position). This is then the startpoint to look for the
+ next non-blank data */
+ s = Get_First_Whitespace_Character(bp,Buffer_Length(field) -
+ (int)(bp - field->buf));
+
+ /* Find the start of the next word */
+ t = Get_Start_Of_Data(s,Buffer_Length(field) -
+ (int)(s - field->buf));
+#if !FRIENDLY_PREV_NEXT_WORD
+ if (s==t)
+ return(E_REQUEST_DENIED);
+ else
+#endif
+ {
+ Adjust_Cursor_Position(form,t);
+ return(E_OK);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Previous_Word(FORM * form)
+|
+| Description : Move to the beginning of the previous word in the field.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - there is no previous word
++--------------------------------------------------------------------------*/
+static int IFN_Previous_Word(FORM * form)
+{
+ FIELD *field = form->current;
+ char *bp = Address_Of_Current_Position_In_Buffer(form);
+ char *s;
+ char *t;
+ bool again = FALSE;
+
+ /* We really need access to the data, so we have to synchronize */
+ Synchronize_Buffer(form);
+
+ s = After_End_Of_Data(field->buf,(int)(bp-field->buf));
+ /* s points now right after the last non-blank in the buffer before bp.
+ If bp was in a word, s equals bp. In this case we must find the last
+ whitespace in the buffer before bp and repeat the game to really find
+ the previous word! */
+ if (s==bp)
+ again = TRUE;
+
+ /* And next call now goes backward to look for the last whitespace
+ before that, pointing right after this, so it points to the begin
+ of the previous word.
+ */
+ t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
+#if !FRIENDLY_PREV_NEXT_WORD
+ if (s==t)
+ return(E_REQUEST_DENIED);
+#endif
+ if (again)
+ { /* and do it again, replacing bp by t */
+ s = After_End_Of_Data(field->buf,(int)(t - field->buf));
+ t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
+#if !FRIENDLY_PREV_NEXT_WORD
+ if (s==t)
+ return(E_REQUEST_DENIED);
+#endif
+ }
+ Adjust_Cursor_Position(form,t);
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Beginning_Of_Field(FORM * form)
+|
+| Description : Place the cursor at the first non-pad character in
+| the field.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int IFN_Beginning_Of_Field(FORM * form)
+{
+ FIELD *field = form->current;
+
+ Synchronize_Buffer(form);
+ Adjust_Cursor_Position(form,
+ Get_Start_Of_Data(field->buf,Buffer_Length(field)));
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_End_Of_Field(FORM * form)
+|
+| Description : Place the cursor after the last non-pad character in
+| the field. If the field occupies the last position in
+| the buffer, the cursos is positioned on the last
+| character.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int IFN_End_Of_Field(FORM * form)
+{
+ FIELD *field = form->current;
+ char *pos;
+
+ Synchronize_Buffer(form);
+ pos = After_End_Of_Data(field->buf,Buffer_Length(field));
+ if (pos==(field->buf + Buffer_Length(field)))
+ pos--;
+ Adjust_Cursor_Position(form,pos);
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Beginning_Of_Line(FORM * form)
+|
+| Description : Place the cursor on the first non-pad character in
+| the current line of the field.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int IFN_Beginning_Of_Line(FORM * form)
+{
+ FIELD *field = form->current;
+
+ Synchronize_Buffer(form);
+ Adjust_Cursor_Position(form,
+ Get_Start_Of_Data(Address_Of_Current_Row_In_Buffer(form),
+ field->dcols));
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_End_Of_Line(FORM * form)
+|
+| Description : Place the cursor after the last non-pad character in the
+| current line of the field. If the field occupies the
+| last column in the line, the cursor is positioned on the
+| last character of the line.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int IFN_End_Of_Line(FORM * form)
+{
+ FIELD *field = form->current;
+ char *pos;
+ char *bp;
+
+ Synchronize_Buffer(form);
+ bp = Address_Of_Current_Row_In_Buffer(form);
+ pos = After_End_Of_Data(bp,field->dcols);
+ if (pos == (bp + field->dcols))
+ pos--;
+ Adjust_Cursor_Position(form,pos);
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Left_Character(FORM * form)
+|
+| Description : Move one character to the left in the current line.
+| This doesn't cycle.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - already in first column
++--------------------------------------------------------------------------*/
+static int IFN_Left_Character(FORM * form)
+{
+ if ( (--(form->curcol)) < 0 )
+ {
+ form->curcol++;
+ return(E_REQUEST_DENIED);
+ }
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Right_Character(FORM * form)
+|
+| Description : Move one character to the right in the current line.
+| This doesn't cycle.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - already in last column
++--------------------------------------------------------------------------*/
+static int IFN_Right_Character(FORM * form)
+{
+ if ( (++(form->curcol)) == form->current->dcols )
+ {
+#if GROW_IF_NAVIGATE
+ FIELD *field = form->current;
+ if (Single_Line_Field(field) && Field_Grown(field,1))
+ return(E_OK);
+#endif
+ --(form->curcol);
+ return(E_REQUEST_DENIED);
+ }
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Up_Character(FORM * form)
+|
+| Description : Move one line up. This doesn't cycle through the lines
+| of the field.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - already in last column
++--------------------------------------------------------------------------*/
+static int IFN_Up_Character(FORM * form)
+{
+ if ( (--(form->currow)) < 0 )
+ {
+ form->currow++;
+ return(E_REQUEST_DENIED);
+ }
+ return(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int IFN_Down_Character(FORM * form)
+|
+| Description : Move one line down. This doesn't cycle through the
+| lines of the field.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - already in last column
++--------------------------------------------------------------------------*/
+static int IFN_Down_Character(FORM * form)
+{
+ FIELD *field = form->current;
+
+ if ( (++(form->currow)) == field->drows )
+ {
+#if GROW_IF_NAVIGATE
+ if (!Single_Line_Field(field) && Field_Grown(field,1))
+ return(E_OK);
+#endif
+ --(form->currow);
+ return(E_REQUEST_DENIED);
+ }
+ return(E_OK);
+}
+/*----------------------------------------------------------------------------
+ END of Intra-Field Navigation routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Vertical scrolling helper routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int VSC_Generic(FORM *form, int lines)
+|
+| Description : Scroll multi-line field forward (lines>0) or
+| backward (lines<0) this many lines.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - can't scroll
++--------------------------------------------------------------------------*/
+static int VSC_Generic(FORM *form, int lines)
+{
+ FIELD *field = form->current;
+ int res = E_REQUEST_DENIED;
+ int rows_to_go = (lines > 0 ? lines : -lines);
+
+ if (lines > 0)
+ {
+ if ( (rows_to_go + form->toprow) > (field->drows - field->rows) )
+ rows_to_go = (field->drows - field->rows - form->toprow);
+
+ if (rows_to_go > 0)
+ {
+ form->currow += rows_to_go;
+ form->toprow += rows_to_go;
+ res = E_OK;
+ }
+ }
+ else
+ {
+ if (rows_to_go > form->toprow)
+ rows_to_go = form->toprow;
+
+ if (rows_to_go > 0)
+ {
+ form->currow -= rows_to_go;
+ form->toprow -= rows_to_go;
+ res = E_OK;
+ }
+ }
+ return(res);
+}
+/*----------------------------------------------------------------------------
+ End of Vertical scrolling helper routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Vertical scrolling routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Vertical_Scrolling(
+| int (* const fct) (FORM *),
+| FORM * form)
+|
+| Description : Performs the generic vertical scrolling routines.
+| This has to check for a multi-line field and to set
+| the _NEWTOP flag if scrolling really occurred.
+|
+| Return Values : Propagated error code from low-level driver calls
++--------------------------------------------------------------------------*/
+static int Vertical_Scrolling(int (* const fct) (FORM *), FORM * form)
+{
+ int res = E_REQUEST_DENIED;
+
+ if (!Single_Line_Field(form->current))
+ {
+ res = fct(form);
+ if (res == E_OK)
+ form->current->status |= _NEWTOP;
+ }
+ return(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int VSC_Scroll_Line_Forward(FORM * form)
+|
+| Description : Scroll multi-line field forward a line
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data ahead
++--------------------------------------------------------------------------*/
+static int VSC_Scroll_Line_Forward(FORM * form)
+{
+ return VSC_Generic(form,1);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int VSC_Scroll_Line_Backward(FORM * form)
+|
+| Description : Scroll multi-line field backward a line
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data behind
++--------------------------------------------------------------------------*/
+static int VSC_Scroll_Line_Backward(FORM * form)
+{
+ return VSC_Generic(form,-1);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int VSC_Scroll_Page_Forward(FORM * form)
+|
+| Description : Scroll a multi-line field forward a page
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data ahead
++--------------------------------------------------------------------------*/
+static int VSC_Scroll_Page_Forward(FORM * form)
+{
+ return VSC_Generic(form,form->current->rows);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int VSC_Scroll_Half_Page_Forward(FORM * form)
+|
+| Description : Scroll a multi-line field forward half a page
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data ahead
++--------------------------------------------------------------------------*/
+static int VSC_Scroll_Half_Page_Forward(FORM * form)
+{
+ return VSC_Generic(form,(form->current->rows + 1)/2);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int VSC_Scroll_Page_Backward(FORM * form)
+|
+| Description : Scroll a multi-line field backward a page
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data behind
++--------------------------------------------------------------------------*/
+static int VSC_Scroll_Page_Backward(FORM * form)
+{
+ return VSC_Generic(form, -(form->current->rows));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int VSC_Scroll_Half_Page_Backward(FORM * form)
+|
+| Description : Scroll a multi-line field backward half a page
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data behind
++--------------------------------------------------------------------------*/
+static int VSC_Scroll_Half_Page_Backward(FORM * form)
+{
+ return VSC_Generic(form, -((form->current->rows + 1)/2));
+}
+/*----------------------------------------------------------------------------
+ End of Vertical scrolling routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Horizontal scrolling helper routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int HSC_Generic(FORM *form, int columns)
+|
+| Description : Scroll single-line field forward (columns>0) or
+| backward (columns<0) this many columns.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - can't scroll
++--------------------------------------------------------------------------*/
+static int HSC_Generic(FORM *form, int columns)
+{
+ FIELD *field = form->current;
+ int res = E_REQUEST_DENIED;
+ int cols_to_go = (columns > 0 ? columns : -columns);
+
+ if (columns > 0)
+ {
+ if ((cols_to_go + form->begincol) > (field->dcols - field->cols))
+ cols_to_go = field->dcols - field->cols - form->begincol;
+
+ if (cols_to_go > 0)
+ {
+ form->curcol += cols_to_go;
+ form->begincol += cols_to_go;
+ res = E_OK;
+ }
+ }
+ else
+ {
+ if ( cols_to_go > form->begincol )
+ cols_to_go = form->begincol;
+
+ if (cols_to_go > 0)
+ {
+ form->curcol -= cols_to_go;
+ form->begincol -= cols_to_go;
+ res = E_OK;
+ }
+ }
+ return(res);
+}
+/*----------------------------------------------------------------------------
+ End of Horizontal scrolling helper routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Horizontal scrolling routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Horizontal_Scrolling(
+| int (* const fct) (FORM *),
+| FORM * form)
+|
+| Description : Performs the generic horizontal scrolling routines.
+| This has to check for a single-line field.
+|
+| Return Values : Propagated error code from low-level driver calls
++--------------------------------------------------------------------------*/
+static int Horizontal_Scrolling(int (* const fct) (FORM *), FORM * form)
+{
+ if (Single_Line_Field(form->current))
+ return fct(form);
+ else
+ return(E_REQUEST_DENIED);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int HSC_Scroll_Char_Forward(FORM * form)
+|
+| Description : Scroll single-line field forward a character
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data ahead
++--------------------------------------------------------------------------*/
+static int HSC_Scroll_Char_Forward(FORM *form)
+{
+ return HSC_Generic(form,1);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int HSC_Scroll_Char_Backward(FORM * form)
+|
+| Description : Scroll single-line field backward a character
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data behind
++--------------------------------------------------------------------------*/
+static int HSC_Scroll_Char_Backward(FORM *form)
+{
+ return HSC_Generic(form,-1);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int HSC_Horizontal_Line_Forward(FORM* form)
+|
+| Description : Scroll single-line field forward a line
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data ahead
++--------------------------------------------------------------------------*/
+static int HSC_Horizontal_Line_Forward(FORM * form)
+{
+ return HSC_Generic(form,form->current->cols);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int HSC_Horizontal_Half_Line_Forward(FORM* form)
+|
+| Description : Scroll single-line field forward half a line
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data ahead
++--------------------------------------------------------------------------*/
+static int HSC_Horizontal_Half_Line_Forward(FORM * form)
+{
+ return HSC_Generic(form,(form->current->cols + 1)/2);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int HSC_Horizontal_Line_Backward(FORM* form)
+|
+| Description : Scroll single-line field backward a line
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data behind
++--------------------------------------------------------------------------*/
+static int HSC_Horizontal_Line_Backward(FORM * form)
+{
+ return HSC_Generic(form,-(form->current->cols));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int HSC_Horizontal_Half_Line_Backward(FORM* form)
+|
+| Description : Scroll single-line field backward half a line
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - no data behind
++--------------------------------------------------------------------------*/
+static int HSC_Horizontal_Half_Line_Backward(FORM * form)
+{
+ return HSC_Generic(form,-((form->current->cols + 1)/2));
+}
+
+/*----------------------------------------------------------------------------
+ End of Horizontal scrolling routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Helper routines for Field Editing
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Is_There_Room_For_A_Line(FORM * form)
+|
+| Description : Check whether or not there is enough room in the
+| buffer to enter a whole line.
+|
+| Return Values : TRUE - there is enough space
+| FALSE - there is not enough space
++--------------------------------------------------------------------------*/
+INLINE static bool Is_There_Room_For_A_Line(FORM * form)
+{
+ FIELD *field = form->current;
+ char *begin_of_last_line, *s;
+
+ Synchronize_Buffer(form);
+ begin_of_last_line = Address_Of_Row_In_Buffer(field,(field->drows-1));
+ s = After_End_Of_Data(begin_of_last_line,field->dcols);
+ return ((s==begin_of_last_line) ? TRUE : FALSE);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
+|
+| Description : Checks whether or not there is room for a new character
+| in the current line.
+|
+| Return Values : TRUE - there is room
+| FALSE - there is not enough room (line full)
++--------------------------------------------------------------------------*/
+INLINE static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
+{
+ int last_char_in_line;
+
+ wmove(form->w,form->currow,form->current->dcols-1);
+ last_char_in_line = (int)(winch(form->w) & A_CHARTEXT);
+ wmove(form->w,form->currow,form->curcol);
+ return (((last_char_in_line == form->current->pad) ||
+ is_blank(last_char_in_line)) ? TRUE : FALSE);
+}
+
+#define There_Is_No_Room_For_A_Char_In_Line(f) \
+ !Is_There_Room_For_A_Char_In_Line(f)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Insert_String(
+| FORM * form,
+| int row,
+| char *txt,
+| int len )
+|
+| Description : Insert the 'len' characters beginning at pointer 'txt'
+| into the 'row' of the 'form'. The insertion occurs
+| on the beginning of the row, all other characters are
+| moved to the right. After the text a pad character will
+| be inserted to separate the text from the rest. If
+| necessary the insertion moves characters on the next
+| line to make place for the requested insertion string.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED -
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+static int Insert_String(FORM *form, int row, char *txt, int len)
+{
+ FIELD *field = form->current;
+ char *bp = Address_Of_Row_In_Buffer(field,row);
+ int datalen = (int)(After_End_Of_Data(bp,field->dcols) - bp);
+ int freelen = field->dcols - datalen;
+ int requiredlen = len+1;
+ char *split;
+ int result = E_REQUEST_DENIED;
+ char *Space;
+
+ Space = (char*)malloc(2*sizeof(char));
+ strcpy(Space, " ");
+
+ if (freelen >= requiredlen)
+ {
+ wmove(form->w,row,0);
+ winsnstr(form->w,txt,len);
+ wmove(form->w,row,len);
+ winsnstr(form->w,Space,1);
+ free(Space);
+ return E_OK;
+ }
+ else
+ { /* we have to move characters on the next line. If we are on the
+ last line this may work, if the field is growable */
+ if ((row == (field->drows - 1)) && Growable(field))
+ {
+ if (!Field_Grown(field,1))
+ {
+ free(Space);
+ return(E_SYSTEM_ERROR);
+ }
+ /* !!!Side-Effect : might be changed due to growth!!! */
+ bp = Address_Of_Row_In_Buffer(field,row);
+ }
+
+ if (row < (field->drows - 1))
+ {
+ split = After_Last_Whitespace_Character(bp,
+ (int)(Get_Start_Of_Data(bp + field->dcols - requiredlen ,
+ requiredlen) - bp));
+ /* split points now to the first character of the portion of the
+ line that must be moved to the next line */
+ datalen = (int)(split-bp); /* + freelen has to stay on this line */
+ freelen = field->dcols - (datalen + freelen); /* for the next line */
+
+ if ((result=Insert_String(form,row+1,split,freelen))==E_OK)
+ {
+ wmove(form->w,row,datalen);
+ wclrtoeol(form->w);
+ wmove(form->w,row,0);
+ winsnstr(form->w,txt,len);
+ wmove(form->w,row,len);
+ winsnstr(form->w,Space,1);
+ free(Space);
+ return E_OK;
+ }
+ }
+ free(Space);
+ return(result);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Wrapping_Not_Necessary_Or_Wrapping_Ok(
+| FORM * form)
+|
+| Description : If a character has been entered into a field, it may
+| be that wrapping has to occur. This routine checks
+| whether or not wrapping is required and if so, performs
+| the wrapping.
+|
+| Return Values : E_OK - no wrapping required or wrapping
+| was successful
+| E_REQUEST_DENIED -
+| E_SYSTEM_ERROR - some system error
++--------------------------------------------------------------------------*/
+static int Wrapping_Not_Necessary_Or_Wrapping_Ok(FORM * form)
+{
+ FIELD *field = form->current;
+ int result = E_REQUEST_DENIED;
+ bool Last_Row = ((field->drows - 1) == form->currow);
+
+ if ( (field->opts & O_WRAP) && /* wrapping wanted */
+ (!Single_Line_Field(field)) && /* must be multi-line */
+ (There_Is_No_Room_For_A_Char_In_Line(form)) && /* line is full */
+ (!Last_Row || Growable(field)) ) /* there are more lines*/
+ {
+ char *bp;
+ char *split;
+ int chars_to_be_wrapped;
+ int chars_to_remain_on_line;
+ if (Last_Row)
+ { /* the above logic already ensures, that in this case the field
+ is growable */
+ if (!Field_Grown(field,1))
+ return E_SYSTEM_ERROR;
+ }
+ bp = Address_Of_Current_Row_In_Buffer(form);
+ Window_To_Buffer(form->w,field);
+ split = After_Last_Whitespace_Character(bp,field->dcols);
+ /* split points to the first character of the sequence to be brought
+ on the next line */
+ chars_to_remain_on_line = (int)(split - bp);
+ chars_to_be_wrapped = field->dcols - chars_to_remain_on_line;
+ if (chars_to_remain_on_line > 0)
+ {
+ if ((result=Insert_String(form,form->currow+1,split,
+ chars_to_be_wrapped)) == E_OK)
+ {
+ wmove(form->w,form->currow,chars_to_remain_on_line);
+ wclrtoeol(form->w);
+ if (form->curcol >= chars_to_remain_on_line)
+ {
+ form->currow++;
+ form->curcol -= chars_to_remain_on_line;
+ }
+ return E_OK;
+ }
+ }
+ else
+ return E_OK;
+ if (result!=E_OK)
+ {
+ wmove(form->w,form->currow,form->curcol);
+ wdelch(form->w);
+ Window_To_Buffer(form->w,field);
+ result = E_REQUEST_DENIED;
+ }
+ }
+ else
+ result = E_OK; /* wrapping was not necessary */
+ return(result);
+}
+
+/*----------------------------------------------------------------------------
+ Field Editing routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Field_Editing(
+| int (* const fct) (FORM *),
+| FORM * form)
+|
+| Description : Generic routine for field editing requests. The driver
+| routines are only called for editable fields, the
+| _WINDOW_MODIFIED flag is set if editing occurred.
+| This is somewhat special due to the overload semantics
+| of the NEW_LINE and DEL_PREV requests.
+|
+| Return Values : Error code from low level drivers.
++--------------------------------------------------------------------------*/
+static int Field_Editing(int (* const fct) (FORM *), FORM * form)
+{
+ int res = E_REQUEST_DENIED;
+
+ /* We have to deal here with the specific case of the overloaded
+ behaviour of New_Line and Delete_Previous requests.
+ They may end up in navigational requests if we are on the first
+ character in a field. But navigation is also allowed on non-
+ editable fields.
+ */
+ if ((fct==FE_Delete_Previous) &&
+ (form->opts & O_BS_OVERLOAD) &&
+ First_Position_In_Current_Field(form) )
+ {
+ res = Inter_Field_Navigation(FN_Previous_Field,form);
+ }
+ else
+ {
+ if (fct==FE_New_Line)
+ {
+ if ((form->opts & O_NL_OVERLOAD) &&
+ First_Position_In_Current_Field(form))
+ {
+ res = Inter_Field_Navigation(FN_Next_Field,form);
+ }
+ else
+ /* FE_New_Line deals itself with the _WINDOW_MODIFIED flag */
+ res = fct(form);
+ }
+ else
+ {
+ /* From now on, everything must be editable */
+ if (form->current->opts & O_EDIT)
+ {
+ res = fct(form);
+ if (res==E_OK)
+ form->status |= _WINDOW_MODIFIED;
+ }
+ }
+ }
+ return res;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_New_Line(FORM * form)
+|
+| Description : Perform a new line request. This is rather complex
+| compared to other routines in this code due to the
+| rather difficult to understand description in the
+| manuals.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - new line not allowed
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+static int FE_New_Line(FORM * form)
+{
+ FIELD *field = form->current;
+ char *bp, *t;
+ bool Last_Row = ((field->drows - 1)==form->currow);
+
+ if (form->status & _OVLMODE)
+ {
+ if (Last_Row &&
+ (!(Growable(field) && !Single_Line_Field(field))))
+ {
+ if (!(form->opts & O_NL_OVERLOAD))
+ return(E_REQUEST_DENIED);
+ wclrtoeol(form->w);
+ /* we have to set this here, although it is also
+ handled in the generic routine. The reason is,
+ that FN_Next_Field may fail, but the form is
+ definitively changed */
+ form->status |= _WINDOW_MODIFIED;
+ return Inter_Field_Navigation(FN_Next_Field,form);
+ }
+ else
+ {
+ if (Last_Row && !Field_Grown(field,1))
+ { /* N.B.: due to the logic in the 'if', LastRow==TRUE
+ means here that the field is growable and not
+ a single-line field */
+ return(E_SYSTEM_ERROR);
+ }
+ wclrtoeol(form->w);
+ form->currow++;
+ form->curcol = 0;
+ form->status |= _WINDOW_MODIFIED;
+ return(E_OK);
+ }
+ }
+ else
+ { /* Insert Mode */
+ if (Last_Row &&
+ !(Growable(field) && !Single_Line_Field(field)))
+ {
+ if (!(form->opts & O_NL_OVERLOAD))
+ return(E_REQUEST_DENIED);
+ return Inter_Field_Navigation(FN_Next_Field,form);
+ }
+ else
+ {
+ bool May_Do_It = !Last_Row && Is_There_Room_For_A_Line(form);
+
+ if (!(May_Do_It || Growable(field)))
+ return(E_REQUEST_DENIED);
+ if (!May_Do_It && !Field_Grown(field,1))
+ return(E_SYSTEM_ERROR);
+
+ bp= Address_Of_Current_Position_In_Buffer(form);
+ t = After_End_Of_Data(bp,field->dcols - form->curcol);
+ wclrtoeol(form->w);
+ form->currow++;
+ form->curcol=0;
+ wmove(form->w,form->currow,form->curcol);
+ winsertln(form->w);
+ waddnstr(form->w,bp,(int)(t-bp));
+ form->status |= _WINDOW_MODIFIED;
+ return E_OK;
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Insert_Character(FORM * form)
+|
+| Description : Insert blank character at the cursor position
+|
+| Return Values : E_OK
+| E_REQUEST_DENIED
++--------------------------------------------------------------------------*/
+static int FE_Insert_Character(FORM * form)
+{
+ FIELD *field = form->current;
+ int result = E_REQUEST_DENIED;
+
+ if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
+ {
+ bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
+
+ if (There_Is_Room ||
+ ((Single_Line_Field(field) && Growable(field))))
+ {
+ if (!There_Is_Room && !Field_Grown(field,1))
+ result = E_SYSTEM_ERROR;
+ else
+ {
+ winsch(form->w,(chtype)C_BLANK);
+ result = Wrapping_Not_Necessary_Or_Wrapping_Ok(form);
+ }
+ }
+ }
+ return result;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Insert_Line(FORM * form)
+|
+| Description : Insert a blank line at the cursor position
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - line can not be inserted
++--------------------------------------------------------------------------*/
+static int FE_Insert_Line(FORM * form)
+{
+ FIELD *field = form->current;
+ int result = E_REQUEST_DENIED;
+
+ if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
+ {
+ bool Maybe_Done = (form->currow!=(field->drows-1)) &&
+ Is_There_Room_For_A_Line(form);
+
+ if (!Single_Line_Field(field) &&
+ (Maybe_Done || Growable(field)))
+ {
+ if (!Maybe_Done && !Field_Grown(field,1))
+ result = E_SYSTEM_ERROR;
+ else
+ {
+ form->curcol = 0;
+ winsertln(form->w);
+ result = E_OK;
+ }
+ }
+ }
+ return result;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Delete_Character(FORM * form)
+|
+| Description : Delete character at the cursor position
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int FE_Delete_Character(FORM * form)
+{
+ wdelch(form->w);
+ return E_OK;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Delete_Previous(FORM * form)
+|
+| Description : Delete character before cursor. Again this is a rather
+| difficult piece compared to others due to the overloading
+| semantics of backspace.
+| N.B.: The case of overloaded BS on first field position
+| is already handled in the generic routine.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - Character can't be deleted
++--------------------------------------------------------------------------*/
+static int FE_Delete_Previous(FORM * form)
+{
+ FIELD *field = form->current;
+
+ if (First_Position_In_Current_Field(form))
+ return E_REQUEST_DENIED;
+
+ if ( (--(form->curcol))<0 )
+ {
+ char *this_line, *prev_line, *prev_end, *this_end;
+
+ form->curcol++;
+ if (form->status & _OVLMODE)
+ return E_REQUEST_DENIED;
+
+ prev_line = Address_Of_Row_In_Buffer(field,(form->currow-1));
+ this_line = Address_Of_Row_In_Buffer(field,(form->currow));
+ Synchronize_Buffer(form);
+ prev_end = After_End_Of_Data(prev_line,field->dcols);
+ this_end = After_End_Of_Data(this_line,field->dcols);
+ if ((int)(this_end-this_line) >
+ (field->cols-(int)(prev_end-prev_line)))
+ return E_REQUEST_DENIED;
+ wdeleteln(form->w);
+ Adjust_Cursor_Position(form,prev_end);
+ wmove(form->w,form->currow,form->curcol);
+ waddnstr(form->w,this_line,(int)(this_end-this_line));
+ }
+ else
+ {
+ wmove(form->w,form->currow,form->curcol);
+ wdelch(form->w);
+ }
+ return E_OK;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Delete_Line(FORM * form)
+|
+| Description : Delete line at cursor position.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int FE_Delete_Line(FORM * form)
+{
+ form->curcol = 0;
+ wdeleteln(form->w);
+ return E_OK;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Delete_Word(FORM * form)
+|
+| Description : Delete word at cursor position
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - failure
++--------------------------------------------------------------------------*/
+static int FE_Delete_Word(FORM * form)
+{
+ FIELD *field = form->current;
+ char *bp = Address_Of_Current_Row_In_Buffer(form);
+ char *ep = bp + field->dcols;
+ char *cp = bp + form->curcol;
+ char *s;
+
+ Synchronize_Buffer(form);
+ if (is_blank(*cp))
+ return E_REQUEST_DENIED; /* not in word */
+
+ /* move cursor to begin of word and erase to end of screen-line */
+ Adjust_Cursor_Position(form,
+ After_Last_Whitespace_Character(bp,form->curcol));
+ wmove(form->w,form->currow,form->curcol);
+ wclrtoeol(form->w);
+
+ /* skip over word in buffer */
+ s = Get_First_Whitespace_Character(cp,(int)(ep-cp));
+ /* to begin of next word */
+ s = Get_Start_Of_Data(s,(int)(ep - s));
+ if ( (s!=cp) && !is_blank(*s))
+ {
+ /* copy remaining line to window */
+ waddnstr(form->w,s,(int)(s - After_End_Of_Data(s,(int)(ep - s))));
+ }
+ return E_OK;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Clear_To_End_Of_Line(FORM * form)
+|
+| Description : Clear to end of current line.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int FE_Clear_To_End_Of_Line(FORM * form)
+{
+ wclrtoeol(form->w);
+ return E_OK;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Clear_To_End_Of_Form(FORM * form)
+|
+| Description : Clear to end of form.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int FE_Clear_To_End_Of_Form(FORM * form)
+{
+ wclrtobot(form->w);
+ return E_OK;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FE_Clear_Field(FORM * form)
+|
+| Description : Clear entire field.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int FE_Clear_Field(FORM * form)
+{
+ form->currow = form->curcol = 0;
+ werase(form->w);
+ return E_OK;
+}
+/*----------------------------------------------------------------------------
+ END of Field Editing routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Edit Mode routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int EM_Overlay_Mode(FORM * form)
+|
+| Description : Switch to overlay mode.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int EM_Overlay_Mode(FORM * form)
+{
+ form->status |= _OVLMODE;
+ return E_OK;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int EM_Insert_Mode(FORM * form)
+|
+| Description : Switch to insert mode
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+static int EM_Insert_Mode(FORM * form)
+{
+ form->status &= ~_OVLMODE;
+ return E_OK;
+}
+
+/*----------------------------------------------------------------------------
+ END of Edit Mode routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Helper routines for Choice Requests
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Next_Choice(
+| FIELDTYPE * typ,
+| FIELD * field,
+| TypeArgument *argp)
+|
+| Description : Get the next field choice. For linked types this is
+| done recursively.
+|
+| Return Values : TRUE - next choice successfully retrieved
+| FALSE - couldn't retrieve next choice
++--------------------------------------------------------------------------*/
+static bool Next_Choice(FIELDTYPE * typ, FIELD *field, TypeArgument *argp)
+{
+ if (!typ || !(typ->status & _HAS_CHOICE))
+ return FALSE;
+
+ if (typ->status & _LINKED_TYPE)
+ {
+ assert(argp != 0);
+ return(
+ Next_Choice(typ->left ,field,argp->left) ||
+ Next_Choice(typ->right,field,argp->right) );
+ }
+ else
+ {
+ assert(typ->next != 0);
+ return typ->next(field,(void *)argp);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Previous_Choice(
+| FIELDTYPE * typ,
+| FIELD * field,
+| TypeArgument *argp)
+|
+| Description : Get the previous field choice. For linked types this
+| is done recursively.
+|
+| Return Values : TRUE - previous choice successfully retrieved
+| FALSE - couldn't retrieve previous choice
++--------------------------------------------------------------------------*/
+static bool Previous_Choice(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
+{
+ if (!typ || !(typ->status & _HAS_CHOICE))
+ return FALSE;
+
+ if (typ->status & _LINKED_TYPE)
+ {
+ assert(argp != 0);
+ return(
+ Previous_Choice(typ->left ,field,argp->left) ||
+ Previous_Choice(typ->right,field,argp->right));
+ }
+ else
+ {
+ assert(typ->prev != 0);
+ return typ->prev(field,(void *)argp);
+ }
+}
+/*----------------------------------------------------------------------------
+ End of Helper routines for Choice Requests
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Routines for Choice Requests
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int CR_Next_Choice(FORM * form)
+|
+| Description : Get the next field choice.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - next choice couldn't be retrieved
++--------------------------------------------------------------------------*/
+static int CR_Next_Choice(FORM * form)
+{
+ FIELD *field = form->current;
+ Synchronize_Buffer(form);
+ return ((Next_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
+ E_OK : E_REQUEST_DENIED);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int CR_Previous_Choice(FORM * form)
+|
+| Description : Get the previous field choice.
+|
+| Return Values : E_OK - success
+| E_REQUEST_DENIED - prev. choice couldn't be retrieved
++--------------------------------------------------------------------------*/
+static int CR_Previous_Choice(FORM * form)
+{
+ FIELD *field = form->current;
+ Synchronize_Buffer(form);
+ return ((Previous_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
+ E_OK : E_REQUEST_DENIED);
+}
+/*----------------------------------------------------------------------------
+ End of Routines for Choice Requests
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Helper routines for Field Validations.
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Field(
+| FIELDTYPE * typ,
+| FIELD * field,
+| TypeArgument * argp)
+|
+| Description : Check the field according to its fieldtype and its
+| actual arguments. For linked fieldtypes this is done
+| recursively.
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid.
++--------------------------------------------------------------------------*/
+static bool Check_Field(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
+{
+ if (typ)
+ {
+ if (field->opts & O_NULLOK)
+ {
+ char *bp = field->buf;
+ assert(bp != 0);
+ while(is_blank(*bp))
+ { bp++; }
+ if (*bp == '\0')
+ return TRUE;
+ }
+
+ if (typ->status & _LINKED_TYPE)
+ {
+ assert(argp != 0);
+ return(
+ Check_Field(typ->left ,field,argp->left ) ||
+ Check_Field(typ->right,field,argp->right) );
+ }
+ else
+ {
+ if (typ->fcheck)
+ return typ->fcheck(field,(void *)argp);
+ }
+ }
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : bool _nc_Internal_Validation(FORM * form )
+|
+| Description : Validate the current field of the form.
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+bool
+_nc_Internal_Validation(FORM *form)
+{
+ FIELD *field;
+
+ field = form->current;
+
+ Synchronize_Buffer(form);
+ if ((form->status & _FCHECK_REQUIRED) ||
+ (!(field->opts & O_PASSOK)))
+ {
+ if (!Check_Field(field->type,field,(TypeArgument *)(field->arg)))
+ return FALSE;
+ form->status &= ~_FCHECK_REQUIRED;
+ field->status |= _CHANGED;
+ Synchronize_Linked_Fields(field);
+ }
+ return TRUE;
+}
+/*----------------------------------------------------------------------------
+ End of Helper routines for Field Validations.
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Routines for Field Validation.
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FV_Validation(FORM * form)
+|
+| Description : Validate the current field of the form.
+|
+| Return Values : E_OK - field valid
+| E_INVALID_FIELD - field not valid
++--------------------------------------------------------------------------*/
+static int FV_Validation(FORM * form)
+{
+ if (_nc_Internal_Validation(form))
+ return E_OK;
+ else
+ return E_INVALID_FIELD;
+}
+/*----------------------------------------------------------------------------
+ End of routines for Field Validation.
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Helper routines for Inter-Field Navigation
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Next_Field_On_Page(FIELD * field)
+|
+| Description : Get the next field after the given field on the current
+| page. The order of fields is the one defined by the
+| fields array. Only visible and active fields are
+| counted.
+|
+| Return Values : Pointer to the next field.
++--------------------------------------------------------------------------*/
+INLINE static FIELD *Next_Field_On_Page(FIELD * field)
+{
+ FORM *form = field->form;
+ FIELD **field_on_page = &form->field[field->index];
+ FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
+ FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
+
+ do
+ {
+ field_on_page =
+ (field_on_page==last_on_page) ? first_on_page : field_on_page + 1;
+ if (Field_Is_Selectable(*field_on_page))
+ break;
+ } while(field!=(*field_on_page));
+ return(*field_on_page);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : FIELD* _nc_First_Active_Field(FORM * form)
+|
+| Description : Get the first active field on the current page,
+| if there are such. If there are none, get the first
+| visible field on the page. If there are also none,
+| we return the first field on page and hope the best.
+|
+| Return Values : Pointer to calculated field.
++--------------------------------------------------------------------------*/
+FIELD*
+_nc_First_Active_Field(FORM * form)
+{
+ FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
+ FIELD *proposed = Next_Field_On_Page(*last_on_page);
+
+ if (proposed == *last_on_page)
+ { /* there might be the special situation, where there is no
+ active and visible field on the current page. We then select
+ the first visible field on this readonly page
+ */
+ if (Field_Is_Not_Selectable(proposed))
+ {
+ FIELD **field = &form->field[proposed->index];
+ FIELD **first = &form->field[form->page[form->curpage].pmin];
+
+ do
+ {
+ field = (field==last_on_page) ? first : field + 1;
+ if (((*field)->opts & O_VISIBLE))
+ break;
+ } while(proposed!=(*field));
+
+ proposed = *field;
+
+ if ((proposed == *last_on_page) && !(proposed->opts&O_VISIBLE))
+ { /* This means, there is also no visible field on the page.
+ So we propose the first one and hope the very best...
+ Some very clever user has designed a readonly and invisible
+ page on this form.
+ */
+ proposed = *first;
+ }
+ }
+ }
+ return(proposed);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Previous_Field_On_Page(FIELD * field)
+|
+| Description : Get the previous field before the given field on the
+| current page. The order of fields is the one defined by
+| the fields array. Only visible and active fields are
+| counted.
+|
+| Return Values : Pointer to the previous field.
++--------------------------------------------------------------------------*/
+INLINE static FIELD *Previous_Field_On_Page(FIELD * field)
+{
+ FORM *form = field->form;
+ FIELD **field_on_page = &form->field[field->index];
+ FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
+ FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
+
+ do
+ {
+ field_on_page =
+ (field_on_page==first_on_page) ? last_on_page : field_on_page - 1;
+ if (Field_Is_Selectable(*field_on_page))
+ break;
+ } while(field!=(*field_on_page));
+
+ return (*field_on_page);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Sorted_Next_Field(FIELD * field)
+|
+| Description : Get the next field after the given field on the current
+| page. The order of fields is the one defined by the
+| (row,column) geometry, rows are major.
+|
+| Return Values : Pointer to the next field.
++--------------------------------------------------------------------------*/
+INLINE static FIELD *Sorted_Next_Field(FIELD * field)
+{
+ FIELD *field_on_page = field;
+
+ do
+ {
+ field_on_page = field_on_page->snext;
+ if (Field_Is_Selectable(field_on_page))
+ break;
+ } while(field_on_page!=field);
+
+ return (field_on_page);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Sorted_Previous_Field(FIELD * field)
+|
+| Description : Get the previous field before the given field on the
+| current page. The order of fields is the one defined
+| by the (row,column) geometry, rows are major.
+|
+| Return Values : Pointer to the previous field.
++--------------------------------------------------------------------------*/
+INLINE static FIELD *Sorted_Previous_Field(FIELD * field)
+{
+ FIELD *field_on_page = field;
+
+ do
+ {
+ field_on_page = field_on_page->sprev;
+ if (Field_Is_Selectable(field_on_page))
+ break;
+ } while(field_on_page!=field);
+
+ return (field_on_page);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Left_Neighbour_Field(FIELD * field)
+|
+| Description : Get the left neighbour of the field on the same line
+| and the same page. Cycles through the line.
+|
+| Return Values : Pointer to left neighbour field.
++--------------------------------------------------------------------------*/
+INLINE static FIELD *Left_Neighbour_Field(FIELD * field)
+{
+ FIELD *field_on_page = field;
+
+ /* For a field that has really a left neighbour, the while clause
+ immediately fails and the loop is left, positioned at the right
+ neighbour. Otherwise we cycle backwards through the sorted fieldlist
+ until we enter the same line (from the right end).
+ */
+ do
+ {
+ field_on_page = Sorted_Previous_Field(field_on_page);
+ } while(field_on_page->frow != field->frow);
+
+ return (field_on_page);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Right_Neighbour_Field(FIELD * field)
+|
+| Description : Get the right neighbour of the field on the same line
+| and the same page.
+|
+| Return Values : Pointer to right neighbour field.
++--------------------------------------------------------------------------*/
+INLINE static FIELD *Right_Neighbour_Field(FIELD * field)
+{
+ FIELD *field_on_page = field;
+
+ /* See the comments on Left_Neighbour_Field to understand how it works */
+ do
+ {
+ field_on_page = Sorted_Next_Field(field_on_page);
+ } while(field_on_page->frow != field->frow);
+
+ return (field_on_page);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Upper_Neighbour_Field(FIELD * field)
+|
+| Description : Because of the row-major nature of sorting the fields,
+| its more difficult to define what's the upper neighbour
+| field really means. We define that it must be on a
+| 'previous' line (cyclic order!) and is the rightmost
+| field laying on the left side of the given field. If
+| this set is empty, we take the first field on the line.
+|
+| Return Values : Pointer to the upper neighbour field.
++--------------------------------------------------------------------------*/
+static FIELD *Upper_Neighbour_Field(FIELD * field)
+{
+ FIELD *field_on_page = field;
+ int frow = field->frow;
+ int fcol = field->fcol;
+
+ /* Walk back to the 'previous' line. The second term in the while clause
+ just guarantees that we stop if we cycled through the line because
+ there might be no 'previous' line if the page has just one line.
+ */
+ do
+ {
+ field_on_page = Sorted_Previous_Field(field_on_page);
+ } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
+
+ if (field_on_page->frow!=frow)
+ { /* We really found a 'previous' line. We are positioned at the
+ rightmost field on this line */
+ frow = field_on_page->frow;
+
+ /* We walk to the left as long as we are really right of the
+ field. */
+ while(field_on_page->frow==frow && field_on_page->fcol>fcol)
+ field_on_page = Sorted_Previous_Field(field_on_page);
+
+ /* If we wrapped, just go to the right which is the first field on
+ the row */
+ if (field_on_page->frow!=frow)
+ field_on_page = Sorted_Next_Field(field_on_page);
+ }
+
+ return (field_on_page);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static FIELD *Down_Neighbour_Field(FIELD * field)
+|
+| Description : Because of the row-major nature of sorting the fields,
+| its more difficult to define what's the down neighbour
+| field really means. We define that it must be on a
+| 'next' line (cyclic order!) and is the leftmost
+| field laying on the right side of the given field. If
+| this set is empty, we take the last field on the line.
+|
+| Return Values : Pointer to the upper neighbour field.
++--------------------------------------------------------------------------*/
+static FIELD *Down_Neighbour_Field(FIELD * field)
+{
+ FIELD *field_on_page = field;
+ int frow = field->frow;
+ int fcol = field->fcol;
+
+ /* Walk forward to the 'next' line. The second term in the while clause
+ just guarantees that we stop if we cycled through the line because
+ there might be no 'next' line if the page has just one line.
+ */
+ do
+ {
+ field_on_page = Sorted_Next_Field(field_on_page);
+ } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
+
+ if (field_on_page->frow!=frow)
+ { /* We really found a 'next' line. We are positioned at the rightmost
+ field on this line */
+ frow = field_on_page->frow;
+
+ /* We walk to the right as long as we are really left of the
+ field. */
+ while(field_on_page->frow==frow && field_on_page->fcol<fcol)
+ field_on_page = Sorted_Next_Field(field_on_page);
+
+ /* If we wrapped, just go to the left which is the last field on
+ the row */
+ if (field_on_page->frow!=frow)
+ field_on_page = Sorted_Previous_Field(field_on_page);
+ }
+
+ return(field_on_page);
+}
+
+/*----------------------------------------------------------------------------
+ Inter-Field Navigation routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Inter_Field_Navigation(
+| int (* const fct) (FORM *),
+| FORM * form)
+|
+| Description : Generic behaviour for changing the current field, the
+| field is left and a new field is entered. So the field
+| must be validated and the field init/term hooks must
+| be called.
+|
+| Return Values : E_OK - success
+| E_INVALID_FIELD - field is invalid
+| some other - error from subordinate call
++--------------------------------------------------------------------------*/
+static int Inter_Field_Navigation(int (* const fct) (FORM *),FORM *form)
+{
+ int res;
+
+ if (!_nc_Internal_Validation(form))
+ res = E_INVALID_FIELD;
+ else
+ {
+ Call_Hook(form,fieldterm);
+ res = fct(form);
+ Call_Hook(form,fieldinit);
+ }
+ return res;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Next_Field(FORM * form)
+|
+| Description : Move to the next field on the current page of the form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Next_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Next_Field_On_Page(form->current));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Previous_Field(FORM * form)
+|
+| Description : Move to the previous field on the current page of the
+| form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Previous_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Previous_Field_On_Page(form->current));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_First_Field(FORM * form)
+|
+| Description : Move to the first field on the current page of the form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_First_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Next_Field_On_Page(form->field[form->page[form->curpage].pmax]));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Last_Field(FORM * form)
+|
+| Description : Move to the last field on the current page of the form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Last_Field(FORM * form)
+{
+ return
+ _nc_Set_Current_Field(form,
+ Previous_Field_On_Page(form->field[form->page[form->curpage].pmin]));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Sorted_Next_Field(FORM * form)
+|
+| Description : Move to the sorted next field on the current page
+| of the form.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Sorted_Next_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Sorted_Next_Field(form->current));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Sorted_Previous_Field(FORM * form)
+|
+| Description : Move to the sorted previous field on the current page
+| of the form.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Sorted_Previous_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Sorted_Previous_Field(form->current));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Sorted_First_Field(FORM * form)
+|
+| Description : Move to the sorted first field on the current page
+| of the form.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Sorted_First_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Sorted_Next_Field(form->field[form->page[form->curpage].smax]));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Sorted_Last_Field(FORM * form)
+|
+| Description : Move to the sorted last field on the current page
+| of the form.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Sorted_Last_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Sorted_Previous_Field(form->field[form->page[form->curpage].smin]));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Left_Field(FORM * form)
+|
+| Description : Get the field on the left of the current field on the
+| same line and the same page. Cycles through the line.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Left_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Left_Neighbour_Field(form->current));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Right_Field(FORM * form)
+|
+| Description : Get the field on the right of the current field on the
+| same line and the same page. Cycles through the line.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Right_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Right_Neighbour_Field(form->current));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Up_Field(FORM * form)
+|
+| Description : Get the upper neighbour of the current field. This
+| cycles through the page. See the comments of the
+| Upper_Neighbour_Field function to understand how
+| 'upper' is defined.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Up_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Upper_Neighbour_Field(form->current));
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int FN_Down_Field(FORM * form)
+|
+| Description : Get the down neighbour of the current field. This
+| cycles through the page. See the comments of the
+| Down_Neighbour_Field function to understand how
+| 'down' is defined.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int FN_Down_Field(FORM * form)
+{
+ return _nc_Set_Current_Field(form,
+ Down_Neighbour_Field(form->current));
+}
+/*----------------------------------------------------------------------------
+ END of Field Navigation routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Helper routines for Page Navigation
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int _nc_Set_Form_Page(FORM * form,
+| int page,
+| FIELD * field)
+|
+| Description : Make the given page nr. the current page and make
+| the given field the current field on the page. If
+| for the field NULL is given, make the first field on
+| the page the current field. The routine acts only
+| if the requested page is not the current page.
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+int
+_nc_Set_Form_Page(FORM * form, int page, FIELD * field)
+{
+ int res = E_OK;
+
+ if ((form->curpage!=page))
+ {
+ FIELD *last_field, *field_on_page;
+
+ werase(Get_Form_Window(form));
+ form->curpage = page;
+ last_field = field_on_page = form->field[form->page[page].smin];
+ do
+ {
+ if (field_on_page->opts & O_VISIBLE)
+ if ((res=Display_Field(field_on_page))!=E_OK)
+ return(res);
+ field_on_page = field_on_page->snext;
+ } while(field_on_page != last_field);
+
+ if (field)
+ res = _nc_Set_Current_Field(form,field);
+ else
+ /* N.B.: we don't encapsulate this by Inter_Field_Navigation(),
+ because this is already executed in a page navigation
+ context that contains field navigation
+ */
+ res = FN_First_Field(form);
+ }
+ return(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Next_Page_Number(const FORM * form)
+|
+| Description : Calculate the page number following the current page
+| number. This cycles if the highest page number is
+| reached.
+|
+| Return Values : The next page number
++--------------------------------------------------------------------------*/
+INLINE static int Next_Page_Number(const FORM * form)
+{
+ return (form->curpage + 1) % form->maxpage;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Previous_Page_Number(const FORM * form)
+|
+| Description : Calculate the page number before the current page
+| number. This cycles if the first page number is
+| reached.
+|
+| Return Values : The previous page number
++--------------------------------------------------------------------------*/
+INLINE static int Previous_Page_Number(const FORM * form)
+{
+ return (form->curpage!=0 ? form->curpage - 1 : form->maxpage - 1);
+}
+
+/*----------------------------------------------------------------------------
+ Page Navigation routines
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Page_Navigation(
+| int (* const fct) (FORM *),
+| FORM * form)
+|
+| Description : Generic behaviour for changing a page. This means
+| that the field is left and a new field is entered.
+| So the field must be validated and the field init/term
+| hooks must be called. Because also the page is changed,
+| the forms init/term hooks must be called also.
+|
+| Return Values : E_OK - success
+| E_INVALID_FIELD - field is invalid
+| some other - error from subordinate call
++--------------------------------------------------------------------------*/
+static int Page_Navigation(int (* const fct) (FORM *), FORM * form)
+{
+ int res;
+
+ if (!_nc_Internal_Validation(form))
+ res = E_INVALID_FIELD;
+ else
+ {
+ Call_Hook(form,fieldterm);
+ Call_Hook(form,formterm);
+ res = fct(form);
+ Call_Hook(form,forminit);
+ Call_Hook(form,fieldinit);
+ }
+ return res;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int PN_Next_Page(FORM * form)
+|
+| Description : Move to the next page of the form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int PN_Next_Page(FORM * form)
+{
+ return _nc_Set_Form_Page(form,Next_Page_Number(form),(FIELD *)0);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int PN_Previous_Page(FORM * form)
+|
+| Description : Move to the previous page of the form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int PN_Previous_Page(FORM * form)
+{
+ return _nc_Set_Form_Page(form,Previous_Page_Number(form),(FIELD *)0);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int PN_First_Page(FORM * form)
+|
+| Description : Move to the first page of the form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int PN_First_Page(FORM * form)
+{
+ return _nc_Set_Form_Page(form,0,(FIELD *)0);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int PN_Last_Page(FORM * form)
+|
+| Description : Move to the last page of the form
+|
+| Return Values : E_OK - success
+| != E_OK - error from subordinate call
++--------------------------------------------------------------------------*/
+static int PN_Last_Page(FORM * form)
+{
+ return _nc_Set_Form_Page(form,form->maxpage-1,(FIELD *)0);
+}
+/*----------------------------------------------------------------------------
+ END of Field Navigation routines
+ --------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Helper routines for the core form driver.
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Data_Entry(FORM * form,int c)
+|
+| Description : Enter character c into at the current position of the
+| current field of the form.
+|
+| Return Values : E_OK -
+| E_REQUEST_DENIED -
+| E_SYSTEM_ERROR -
++--------------------------------------------------------------------------*/
+static int Data_Entry(FORM * form, int c)
+{
+ FIELD *field = form->current;
+ int result = E_REQUEST_DENIED;
+
+ if ( (field->opts & O_EDIT)
+#if FIX_FORM_INACTIVE_BUG
+ && (field->opts & O_ACTIVE)
+#endif
+ )
+ {
+ if ( (field->opts & O_BLANK) &&
+ First_Position_In_Current_Field(form) &&
+ !(form->status & _FCHECK_REQUIRED) &&
+ !(form->status & _WINDOW_MODIFIED) )
+ werase(form->w);
+
+ if (form->status & _OVLMODE)
+ {
+ waddch(form->w,(chtype)c);
+ }
+ else /* no _OVLMODE */
+ {
+ bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
+
+ if (!(There_Is_Room ||
+ ((Single_Line_Field(field) && Growable(field)))))
+ return E_REQUEST_DENIED;
+
+ if (!There_Is_Room && !Field_Grown(field,1))
+ return E_SYSTEM_ERROR;
+
+ winsch(form->w,(chtype)c);
+ }
+
+ if ((result=Wrapping_Not_Necessary_Or_Wrapping_Ok(form))==E_OK)
+ {
+ bool End_Of_Field= (((field->drows-1)==form->currow) &&
+ ((field->dcols-1)==form->curcol));
+ form->status |= _WINDOW_MODIFIED;
+ if (End_Of_Field && !Growable(field) && (field->opts & O_AUTOSKIP))
+ result = Inter_Field_Navigation(FN_Next_Field,form);
+ else
+ {
+ if (End_Of_Field && Growable(field) && !Field_Grown(field,1))
+ result = E_SYSTEM_ERROR;
+ else
+ {
+ IFN_Next_Character(form);
+ result = E_OK;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/* Structure to describe the binding of a request code to a function.
+ The member keycode codes the request value as well as the generic
+ routine to use for the request. The code for the generic routine
+ is coded in the upper 16 Bits while the request code is coded in
+ the lower 16 bits.
+
+ In terms of C++ you might think of a request as a class with a
+ virtual method "perform". The different types of request are
+ derived from this base class and overload (or not) the base class
+ implementation of perform.
+*/
+typedef struct {
+ int keycode; /* must be at least 32 bit: hi:mode, lo: key */
+ int (*cmd)(FORM *); /* low level driver routine for this key */
+} Binding_Info;
+
+/* You may see this is the class-id of the request type class */
+#define ID_PN (0x00000000) /* Page navigation */
+#define ID_FN (0x00010000) /* Inter-Field navigation */
+#define ID_IFN (0x00020000) /* Intra-Field navigation */
+#define ID_VSC (0x00030000) /* Vertical Scrolling */
+#define ID_HSC (0x00040000) /* Horizontal Scrolling */
+#define ID_FE (0x00050000) /* Field Editing */
+#define ID_EM (0x00060000) /* Edit Mode */
+#define ID_FV (0x00070000) /* Field Validation */
+#define ID_CH (0x00080000) /* Choice */
+#define ID_Mask (0xffff0000)
+#define Key_Mask (0x0000ffff)
+#define ID_Shft (16)
+
+/* This array holds all the Binding Infos */
+static const Binding_Info bindings[MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1] =
+{
+ { REQ_NEXT_PAGE |ID_PN ,PN_Next_Page},
+ { REQ_PREV_PAGE |ID_PN ,PN_Previous_Page},
+ { REQ_FIRST_PAGE |ID_PN ,PN_First_Page},
+ { REQ_LAST_PAGE |ID_PN ,PN_Last_Page},
+
+ { REQ_NEXT_FIELD |ID_FN ,FN_Next_Field},
+ { REQ_PREV_FIELD |ID_FN ,FN_Previous_Field},
+ { REQ_FIRST_FIELD |ID_FN ,FN_First_Field},
+ { REQ_LAST_FIELD |ID_FN ,FN_Last_Field},
+ { REQ_SNEXT_FIELD |ID_FN ,FN_Sorted_Next_Field},
+ { REQ_SPREV_FIELD |ID_FN ,FN_Sorted_Previous_Field},
+ { REQ_SFIRST_FIELD |ID_FN ,FN_Sorted_First_Field},
+ { REQ_SLAST_FIELD |ID_FN ,FN_Sorted_Last_Field},
+ { REQ_LEFT_FIELD |ID_FN ,FN_Left_Field},
+ { REQ_RIGHT_FIELD |ID_FN ,FN_Right_Field},
+ { REQ_UP_FIELD |ID_FN ,FN_Up_Field},
+ { REQ_DOWN_FIELD |ID_FN ,FN_Down_Field},
+
+ { REQ_NEXT_CHAR |ID_IFN ,IFN_Next_Character},
+ { REQ_PREV_CHAR |ID_IFN ,IFN_Previous_Character},
+ { REQ_NEXT_LINE |ID_IFN ,IFN_Next_Line},
+ { REQ_PREV_LINE |ID_IFN ,IFN_Previous_Line},
+ { REQ_NEXT_WORD |ID_IFN ,IFN_Next_Word},
+ { REQ_PREV_WORD |ID_IFN ,IFN_Previous_Word},
+ { REQ_BEG_FIELD |ID_IFN ,IFN_Beginning_Of_Field},
+ { REQ_END_FIELD |ID_IFN ,IFN_End_Of_Field},
+ { REQ_BEG_LINE |ID_IFN ,IFN_Beginning_Of_Line},
+ { REQ_END_LINE |ID_IFN ,IFN_End_Of_Line},
+ { REQ_LEFT_CHAR |ID_IFN ,IFN_Left_Character},
+ { REQ_RIGHT_CHAR |ID_IFN ,IFN_Right_Character},
+ { REQ_UP_CHAR |ID_IFN ,IFN_Up_Character},
+ { REQ_DOWN_CHAR |ID_IFN ,IFN_Down_Character},
+
+ { REQ_NEW_LINE |ID_FE ,FE_New_Line},
+ { REQ_INS_CHAR |ID_FE ,FE_Insert_Character},
+ { REQ_INS_LINE |ID_FE ,FE_Insert_Line},
+ { REQ_DEL_CHAR |ID_FE ,FE_Delete_Character},
+ { REQ_DEL_PREV |ID_FE ,FE_Delete_Previous},
+ { REQ_DEL_LINE |ID_FE ,FE_Delete_Line},
+ { REQ_DEL_WORD |ID_FE ,FE_Delete_Word},
+ { REQ_CLR_EOL |ID_FE ,FE_Clear_To_End_Of_Line},
+ { REQ_CLR_EOF |ID_FE ,FE_Clear_To_End_Of_Form},
+ { REQ_CLR_FIELD |ID_FE ,FE_Clear_Field},
+
+ { REQ_OVL_MODE |ID_EM ,EM_Overlay_Mode},
+ { REQ_INS_MODE |ID_EM ,EM_Insert_Mode},
+
+ { REQ_SCR_FLINE |ID_VSC ,VSC_Scroll_Line_Forward},
+ { REQ_SCR_BLINE |ID_VSC ,VSC_Scroll_Line_Backward},
+ { REQ_SCR_FPAGE |ID_VSC ,VSC_Scroll_Page_Forward},
+ { REQ_SCR_BPAGE |ID_VSC ,VSC_Scroll_Page_Backward},
+ { REQ_SCR_FHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Forward},
+ { REQ_SCR_BHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Backward},
+
+ { REQ_SCR_FCHAR |ID_HSC ,HSC_Scroll_Char_Forward},
+ { REQ_SCR_BCHAR |ID_HSC ,HSC_Scroll_Char_Backward},
+ { REQ_SCR_HFLINE |ID_HSC ,HSC_Horizontal_Line_Forward},
+ { REQ_SCR_HBLINE |ID_HSC ,HSC_Horizontal_Line_Backward},
+ { REQ_SCR_HFHALF |ID_HSC ,HSC_Horizontal_Half_Line_Forward},
+ { REQ_SCR_HBHALF |ID_HSC ,HSC_Horizontal_Half_Line_Backward},
+
+ { REQ_VALIDATION |ID_FV ,FV_Validation},
+
+ { REQ_NEXT_CHOICE |ID_CH ,CR_Next_Choice},
+ { REQ_PREV_CHOICE |ID_CH ,CR_Previous_Choice}
+};
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int form_driver(FORM * form,int c)
+|
+| Description : This is the workhorse of the forms system. It checks
+| to determine whether the character c is a request or
+| data. If it is a request, the form driver executes
+| the request and returns the result. If it is data
+| (printable character), it enters the data into the
+| current position in the current field. If it is not
+| recognized, the form driver assumes it is an application
+| defined command and returns E_UNKNOWN_COMMAND.
+| Application defined command should be defined relative
+| to MAX_FORM_COMMAND, the maximum value of a request.
+|
+| Return Values : E_OK - success
+| E_SYSTEM_ERROR - system error
+| E_BAD_ARGUMENT - an argument is incorrect
+| E_NOT_POSTED - form is not posted
+| E_INVALID_FIELD - field contents are invalid
+| E_BAD_STATE - called from inside a hook routine
+| E_REQUEST_DENIED - request failed
+| E_UNKNOWN_COMMAND - command not known
++--------------------------------------------------------------------------*/
+int form_driver(FORM * form, int c)
+{
+ const Binding_Info* BI = (Binding_Info *)0;
+ int res = E_UNKNOWN_COMMAND;
+
+ if (!form)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (!(form->field))
+ RETURN(E_NOT_CONNECTED);
+
+ assert(form->page != 0);
+
+ if (c==FIRST_ACTIVE_MAGIC)
+ {
+ form->current = _nc_First_Active_Field(form);
+ return E_OK;
+ }
+
+ assert(form->current &&
+ form->current->buf &&
+ (form->current->form == form)
+ );
+
+ if ( form->status & _IN_DRIVER )
+ RETURN(E_BAD_STATE);
+
+ if ( !( form->status & _POSTED ) )
+ RETURN(E_NOT_POSTED);
+
+ if ((c>=MIN_FORM_COMMAND && c<=MAX_FORM_COMMAND) &&
+ ((bindings[c-MIN_FORM_COMMAND].keycode & Key_Mask) == c))
+ BI = &(bindings[c-MIN_FORM_COMMAND]);
+
+ if (BI)
+ {
+ typedef int (*Generic_Method)(int (* const)(FORM *),FORM *);
+ static const Generic_Method Generic_Methods[] =
+ {
+ Page_Navigation, /* overloaded to call field&form hooks */
+ Inter_Field_Navigation, /* overloaded to call field hooks */
+ NULL, /* Intra-Field is generic */
+ Vertical_Scrolling, /* Overloaded to check multi-line */
+ Horizontal_Scrolling, /* Overloaded to check single-line */
+ Field_Editing, /* Overloaded to mark modification */
+ NULL, /* Edit Mode is generic */
+ NULL, /* Field Validation is generic */
+ NULL /* Choice Request is generic */
+ };
+ size_t nMethods = (sizeof(Generic_Methods)/sizeof(Generic_Methods[0]));
+ size_t method = ((BI->keycode & ID_Mask) >> ID_Shft) & 0xffff;
+
+ if ( (method >= nMethods) || !(BI->cmd) )
+ res = E_SYSTEM_ERROR;
+ else
+ {
+ Generic_Method fct = Generic_Methods[method];
+ if (fct)
+ res = fct(BI->cmd,form);
+ else
+ res = (BI->cmd)(form);
+ }
+ }
+ else
+ {
+ if (!(c & (~(int)MAX_REGULAR_CHARACTER)) &&
+ isprint((unsigned char)c) &&
+ Check_Char(form->current->type,c,
+ (TypeArgument *)(form->current->arg)))
+ res = Data_Entry(form,c);
+ }
+ _nc_Refresh_Current_Field(form);
+ RETURN(res);
+}
+
+/*----------------------------------------------------------------------------
+ Field-Buffer manipulation routines.
+ The effects of setting a buffer is tightly coupled to the core of the form
+ driver logic. This is especially true in the case of growable fields.
+ So I don't separate this into an own module.
+ --------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_buffer(FIELD *field,
+| int buffer, char *value)
+|
+| Description : Set the given buffer of the field to the given value.
+| Buffer 0 stores the displayed content of the field.
+| For dynamic fields this may grow the fieldbuffers if
+| the length of the value exceeds the current buffer
+| length. For buffer 0 only printable values are allowed.
+| For static fields, the value needs not to be zero ter-
+| minated. It is copied up to the length of the buffer.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid argument
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int set_field_buffer(FIELD * field, int buffer, const char * value)
+{
+ char *s, *p;
+ int res = E_OK;
+ unsigned int len;
+
+ if ( !field || !value || ((buffer < 0)||(buffer > field->nbuf)) )
+ RETURN(E_BAD_ARGUMENT);
+
+ len = Buffer_Length(field);
+
+ if (buffer==0)
+ {
+ const char *v;
+ unsigned int i = 0;
+
+ for(v=value; *v && (i<len); v++,i++)
+ {
+ if (!isprint((unsigned char)*v))
+ RETURN(E_BAD_ARGUMENT);
+ }
+ }
+
+ if (Growable(field))
+ {
+ /* for a growable field we must assume zero terminated strings, because
+ somehow we have to detect the length of what should be copied.
+ */
+ unsigned int vlen = strlen(value);
+ if (vlen > len)
+ {
+ if (!Field_Grown(field,
+ (int)(1 + (vlen-len)/((field->rows+field->nrow)*field->cols))))
+ RETURN(E_SYSTEM_ERROR);
+
+ /* in this case we also have to check, whether or not the remaining
+ characters in value are also printable for buffer 0. */
+ if (buffer==0)
+ {
+ unsigned int i;
+
+ for(i=len; i<vlen; i++)
+ if (!isprint((int)(value[i])))
+ RETURN(E_BAD_ARGUMENT);
+ }
+ len = vlen;
+ }
+ }
+
+ p = Address_Of_Nth_Buffer(field,buffer);
+
+#if HAVE_MEMCCPY
+ s = memccpy(p,value,0,len);
+#else
+ for(s=(char *)value; *s && (s < (value+len)); s++)
+ p[s-value] = *s;
+ if (s < (value+len))
+ {
+ int off = s-value;
+ p[off] = *s++;
+ s = p + (s-value);
+ }
+ else
+ s=(char *)0;
+#endif
+
+ if (s)
+ { /* this means, value was null terminated and not greater than the
+ buffer. We have to pad with blanks. Please note that due to memccpy
+ logic s points after the terminating null. */
+ s--; /* now we point to the terminator. */
+ assert(len >= (unsigned int)(s-p));
+ if (len > (unsigned int)(s-p))
+ memset(s,C_BLANK,len-(unsigned int)(s-p));
+ }
+
+ if (buffer==0)
+ {
+ int syncres;
+ if (((syncres=Synchronize_Field( field ))!=E_OK) &&
+ (res==E_OK))
+ res = syncres;
+ if (((syncres=Synchronize_Linked_Fields(field ))!=E_OK) &&
+ (res==E_OK))
+ res = syncres;
+ }
+ RETURN(res);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : char *field_buffer(const FIELD *field,int buffer)
+|
+| Description : Return the address of the buffer for the field.
+|
+| Return Values : Pointer to buffer or NULL if arguments were invalid.
++--------------------------------------------------------------------------*/
+char *field_buffer(const FIELD * field, int buffer)
+{
+ if (field && (buffer >= 0) && (buffer <= field->nbuf))
+ return Address_Of_Nth_Buffer(field,buffer);
+ else
+ return (char *)0;
+}
+
+/* frm_driver.c ends here */
diff --git a/Source/CursesDialog/form/frm_hook.c b/Source/CursesDialog/form/frm_hook.c
new file mode 100644
index 0000000..eb654c4
--- /dev/null
+++ b/Source/CursesDialog/form/frm_hook.c
@@ -0,0 +1,140 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/* "Template" macro to generate function to set application specific hook */
+#define GEN_HOOK_SET_FUNCTION( typ, name ) \
+int set_ ## typ ## _ ## name (FORM *form, Form_Hook func)\
+{\
+ (Normalize_Form( form ) -> typ ## name) = func ;\
+ RETURN(E_OK);\
+}
+
+/* "Template" macro to generate function to get application specific hook */
+#define GEN_HOOK_GET_FUNCTION( typ, name ) \
+Form_Hook typ ## _ ## name ( const FORM *form )\
+{\
+ return ( Normalize_Form( form ) -> typ ## name );\
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_init(FORM *form, Form_Hook f)
+|
+| Description : Assigns an application defined initialization function
+| to be called when the form is posted and just after
+| the current field changes.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+GEN_HOOK_SET_FUNCTION(field,init)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : Form_Hook field_init(const FORM *form)
+|
+| Description : Retrieve field initialization routine address.
+|
+| Return Values : The address or NULL if no hook defined.
++--------------------------------------------------------------------------*/
+GEN_HOOK_GET_FUNCTION(field,init)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_field_term(FORM *form, Form_Hook f)
+|
+| Description : Assigns an application defined finalization function
+| to be called when the form is unposted and just before
+| the current field changes.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+GEN_HOOK_SET_FUNCTION(field,term)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : Form_Hook field_term(const FORM *form)
+|
+| Description : Retrieve field finalization routine address.
+|
+| Return Values : The address or NULL if no hook defined.
++--------------------------------------------------------------------------*/
+GEN_HOOK_GET_FUNCTION(field,term)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_init(FORM *form, Form_Hook f)
+|
+| Description : Assigns an application defined initialization function
+| to be called when the form is posted and just after
+| a page change.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+GEN_HOOK_SET_FUNCTION(form,init)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : Form_Hook form_init(const FORM *form)
+|
+| Description : Retrieve form initialization routine address.
+|
+| Return Values : The address or NULL if no hook defined.
++--------------------------------------------------------------------------*/
+GEN_HOOK_GET_FUNCTION(form,init)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_term(FORM *form, Form_Hook f)
+|
+| Description : Assigns an application defined finalization function
+| to be called when the form is unposted and just before
+| a page change.
+|
+| Return Values : E_OK - success
++--------------------------------------------------------------------------*/
+GEN_HOOK_SET_FUNCTION(form,term)
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : Form_Hook form_term(const FORM *form)
+|
+| Description : Retrieve form finalization routine address.
+|
+| Return Values : The address or NULL if no hook defined.
++--------------------------------------------------------------------------*/
+GEN_HOOK_GET_FUNCTION(form,term)
+
+/* frm_hook.c ends here */
diff --git a/Source/CursesDialog/form/frm_opts.c b/Source/CursesDialog/form/frm_opts.c
new file mode 100644
index 0000000..7bbeaa1
--- /dev/null
+++ b/Source/CursesDialog/form/frm_opts.c
@@ -0,0 +1,116 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_opts(FORM *form, Form_Options opts)
+|
+| Description : Turns on the named options and turns off all the
+| remaining options for that form.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid options
++--------------------------------------------------------------------------*/
+int set_form_opts(FORM * form, Form_Options opts)
+{
+ opts &= ALL_FORM_OPTS;
+ if (opts & ~ALL_FORM_OPTS)
+ RETURN(E_BAD_ARGUMENT);
+ else
+ {
+ Normalize_Form( form )->opts = opts;
+ RETURN(E_OK);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : Form_Options form_opts(const FORM *)
+|
+| Description : Retrieves the current form options.
+|
+| Return Values : The option flags.
++--------------------------------------------------------------------------*/
+Form_Options form_opts(const FORM * form)
+{
+ return (Normalize_Form(form)->opts & ALL_FORM_OPTS);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int form_opts_on(FORM *form, Form_Options opts)
+|
+| Description : Turns on the named options; no other options are
+| changed.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid options
++--------------------------------------------------------------------------*/
+int form_opts_on(FORM * form, Form_Options opts)
+{
+ opts &= ALL_FORM_OPTS;
+ if (opts & ~ALL_FORM_OPTS)
+ RETURN(E_BAD_ARGUMENT);
+ else
+ {
+ Normalize_Form( form )->opts |= opts;
+ RETURN(E_OK);
+ }
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int form_opts_off(FORM *form, Form_Options opts)
+|
+| Description : Turns off the named options; no other options are
+| changed.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid options
++--------------------------------------------------------------------------*/
+int form_opts_off(FORM * form, Form_Options opts)
+{
+ opts &= ALL_FORM_OPTS;
+ if (opts & ~ALL_FORM_OPTS)
+ RETURN(E_BAD_ARGUMENT);
+ else
+ {
+ Normalize_Form(form)->opts &= ~opts;
+ RETURN(E_OK);
+ }
+}
+
+/* frm_opts.c ends here */
diff --git a/Source/CursesDialog/form/frm_page.c b/Source/CursesDialog/form/frm_page.c
new file mode 100644
index 0000000..842cbce
--- /dev/null
+++ b/Source/CursesDialog/form/frm_page.c
@@ -0,0 +1,100 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_page(FORM * form,int page)
+|
+| Description : Set the page number of the form.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid form pointer or page number
+| E_BAD_STATE - called from a hook routine
+| E_INVALID_FIELD - current field can't be left
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int set_form_page(FORM * form, int page)
+{
+ int err = E_OK;
+
+ if ( !form || (page<0) || (page>=form->maxpage) )
+ RETURN(E_BAD_ARGUMENT);
+
+ if (!(form->status & _POSTED))
+ {
+ form->curpage = page;
+ form->current = _nc_First_Active_Field(form);
+ }
+ else
+ {
+ if (form->status & _IN_DRIVER)
+ err = E_BAD_STATE;
+ else
+ {
+ if (form->curpage != page)
+ {
+ if (!_nc_Internal_Validation(form))
+ err = E_INVALID_FIELD;
+ else
+ {
+ Call_Hook(form,fieldterm);
+ Call_Hook(form,formterm);
+ err = _nc_Set_Form_Page(form,page,(FIELD *)0);
+ Call_Hook(form,forminit);
+ Call_Hook(form,fieldinit);
+ _nc_Refresh_Current_Field(form);
+ }
+ }
+ }
+ }
+ RETURN(err);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int form_page(const FORM * form)
+|
+| Description : Return the current page of the form.
+|
+| Return Values : >= 0 : current page number
+| -1 : invalid form pointer
++--------------------------------------------------------------------------*/
+int form_page(const FORM * form)
+{
+ return Normalize_Form(form)->curpage;
+}
+
+/* frm_page.c ends here */
diff --git a/Source/CursesDialog/form/frm_post.c b/Source/CursesDialog/form/frm_post.c
new file mode 100644
index 0000000..fc0a359
--- /dev/null
+++ b/Source/CursesDialog/form/frm_post.c
@@ -0,0 +1,119 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int post_form(FORM * form)
+|
+| Description : Writes the form into its associated subwindow.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid form pointer
+| E_POSTED - form already posted
+| E_NOT_CONNECTED - no fields connected to form
+| E_NO_ROOM - form doesn't fit into subwindow
+| E_SYSTEM_ERROR - system error
++--------------------------------------------------------------------------*/
+int post_form(FORM * form)
+{
+ WINDOW *formwin;
+ int err;
+ int page;
+ int height, width;
+
+ if (!form)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (form->status & _POSTED)
+ RETURN(E_POSTED);
+
+ if (!(form->field))
+ RETURN(E_NOT_CONNECTED);
+
+ formwin = Get_Form_Window(form);
+ getmaxyx(formwin, height, width);
+ if ((form->cols > width) || (form->rows > height))
+ RETURN(E_NO_ROOM);
+
+ /* reset form->curpage to an invalid value. This forces Set_Form_Page
+ to do the page initialization which is required by post_form.
+ */
+ page = form->curpage;
+ form->curpage = -1;
+ if ((err = _nc_Set_Form_Page(form,page,form->current))!=E_OK)
+ RETURN(err);
+
+ form->status |= _POSTED;
+
+ Call_Hook(form,forminit);
+ Call_Hook(form,fieldinit);
+
+ _nc_Refresh_Current_Field(form);
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int unpost_form(FORM * form)
+|
+| Description : Erase form from its associated subwindow.
+|
+| Return Values : E_OK - success
+| E_BAD_ARGUMENT - invalid form pointer
+| E_NOT_POSTED - form isn't posted
+| E_BAD_STATE - called from a hook routine
++--------------------------------------------------------------------------*/
+int unpost_form(FORM * form)
+{
+ if (!form)
+ RETURN(E_BAD_ARGUMENT);
+
+ if (!(form->status & _POSTED))
+ RETURN(E_NOT_POSTED);
+
+ if (form->status & _IN_DRIVER)
+ RETURN(E_BAD_STATE);
+
+ Call_Hook(form,fieldterm);
+ Call_Hook(form,formterm);
+
+ werase(Get_Form_Window(form));
+ delwin(form->w);
+ form->w = (WINDOW *)0;
+ form->status &= ~_POSTED;
+ RETURN(E_OK);
+}
+
+/* frm_post.c ends here */
diff --git a/Source/CursesDialog/form/frm_req_name.c b/Source/CursesDialog/form/frm_req_name.c
new file mode 100644
index 0000000..6fb9183
--- /dev/null
+++ b/Source/CursesDialog/form/frm_req_name.c
@@ -0,0 +1,163 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+/***************************************************************************
+* Module form_request_name *
+* Routines to handle external names of menu requests *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+static const char *request_names[ MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1 ] = {
+ "NEXT_PAGE" ,
+ "PREV_PAGE" ,
+ "FIRST_PAGE" ,
+ "LAST_PAGE" ,
+
+ "NEXT_FIELD" ,
+ "PREV_FIELD" ,
+ "FIRST_FIELD" ,
+ "LAST_FIELD" ,
+ "SNEXT_FIELD" ,
+ "SPREV_FIELD" ,
+ "SFIRST_FIELD" ,
+ "SLAST_FIELD" ,
+ "LEFT_FIELD" ,
+ "RIGHT_FIELD" ,
+ "UP_FIELD" ,
+ "DOWN_FIELD" ,
+
+ "NEXT_CHAR" ,
+ "PREV_CHAR" ,
+ "NEXT_LINE" ,
+ "PREV_LINE" ,
+ "NEXT_WORD" ,
+ "PREV_WORD" ,
+ "BEG_FIELD" ,
+ "END_FIELD" ,
+ "BEG_LINE" ,
+ "END_LINE" ,
+ "LEFT_CHAR" ,
+ "RIGHT_CHAR" ,
+ "UP_CHAR" ,
+ "DOWN_CHAR" ,
+
+ "NEW_LINE" ,
+ "INS_CHAR" ,
+ "INS_LINE" ,
+ "DEL_CHAR" ,
+ "DEL_PREV" ,
+ "DEL_LINE" ,
+ "DEL_WORD" ,
+ "CLR_EOL" ,
+ "CLR_EOF" ,
+ "CLR_FIELD" ,
+ "OVL_MODE" ,
+ "INS_MODE" ,
+ "SCR_FLINE" ,
+ "SCR_BLINE" ,
+ "SCR_FPAGE" ,
+ "SCR_BPAGE" ,
+ "SCR_FHPAGE" ,
+ "SCR_BHPAGE" ,
+ "SCR_FCHAR" ,
+ "SCR_BCHAR" ,
+ "SCR_HFLINE" ,
+ "SCR_HBLINE" ,
+ "SCR_HFHALF" ,
+ "SCR_HBHALF" ,
+
+ "VALIDATION" ,
+ "NEXT_CHOICE" ,
+ "PREV_CHOICE"
+};
+#define A_SIZE (sizeof(request_names)/sizeof(request_names[0]))
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : const char * form_request_name (int request);
+|
+| Description : Get the external name of a form request.
+|
+| Return Values : Pointer to name - on success
+| NULL - on invalid request code
++--------------------------------------------------------------------------*/
+const char *form_request_name( int request )
+{
+ if ( (request < MIN_FORM_COMMAND) || (request > MAX_FORM_COMMAND) )
+ {
+ SET_ERROR (E_BAD_ARGUMENT);
+ return (const char *)0;
+ }
+ else
+ return request_names[ request - MIN_FORM_COMMAND ];
+}
+
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int form_request_by_name (const char *str);
+|
+| Description : Search for a request with this name.
+|
+| Return Values : Request Id - on success
+| E_NO_MATCH - request not found
++--------------------------------------------------------------------------*/
+int form_request_by_name( const char *str )
+{
+ /* because the table is so small, it doesn't really hurt
+ to run sequentially through it.
+ */
+ unsigned int i = 0;
+ char buf[16];
+
+ if (str)
+ {
+ strncpy(buf,str,sizeof(buf));
+ while( (i<sizeof(buf)) && (buf[i] != '\0') )
+ {
+ buf[i] = toupper((int)(buf[i]));
+ i++;
+ }
+
+ for (i=0; i < A_SIZE; i++)
+ {
+ if (strncmp(request_names[i],buf,sizeof(buf))==0)
+ return MIN_FORM_COMMAND + i;
+ }
+ }
+ RETURN(E_NO_MATCH);
+}
+
+/* frm_req_name.c ends here */
diff --git a/Source/CursesDialog/form/frm_scale.c b/Source/CursesDialog/form/frm_scale.c
new file mode 100644
index 0000000..028e9e2
--- /dev/null
+++ b/Source/CursesDialog/form/frm_scale.c
@@ -0,0 +1,63 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int scale_form( const FORM *form, int *rows, int *cols )
+|
+| Description : Retrieve size of form
+|
+| Return Values : E_OK - no error
+| E_BAD_ARGUMENT - invalid form pointer
+| E_NOT_CONNECTED - no fields connected to form
++--------------------------------------------------------------------------*/
+int scale_form(const FORM * form, int * rows, int * cols)
+{
+ if ( !form )
+ RETURN(E_BAD_ARGUMENT);
+
+ if ( !(form->field) )
+ RETURN(E_NOT_CONNECTED);
+
+ if (rows)
+ *rows = form->rows;
+ if (cols)
+ *cols = form->cols;
+
+ RETURN(E_OK);
+}
+
+/* frm_scale.c ends here */
diff --git a/Source/CursesDialog/form/frm_sub.c b/Source/CursesDialog/form/frm_sub.c
new file mode 100644
index 0000000..62dc613
--- /dev/null
+++ b/Source/CursesDialog/form/frm_sub.c
@@ -0,0 +1,69 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_sub(FORM *form, WINDOW *win)
+|
+| Description : Set the subwindow of the form to win.
+|
+| Return Values : E_OK - success
+| E_POSTED - form is posted
++--------------------------------------------------------------------------*/
+int set_form_sub(FORM * form, WINDOW * win)
+{
+ if (form && (form->status & _POSTED))
+ RETURN(E_POSTED);
+
+ Normalize_Form( form )->sub = win;
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : WINDOW *form_sub(const FORM *)
+|
+| Description : Retrieve the window of the form.
+|
+| Return Values : The pointer to the Subwindow.
++--------------------------------------------------------------------------*/
+WINDOW *form_sub(const FORM * form)
+{
+ const FORM* f = Normalize_Form( form );
+ return Get_Form_Window(f);
+}
+
+/* frm_sub.c ends here */
diff --git a/Source/CursesDialog/form/frm_user.c b/Source/CursesDialog/form/frm_user.c
new file mode 100644
index 0000000..f38bbbb
--- /dev/null
+++ b/Source/CursesDialog/form/frm_user.c
@@ -0,0 +1,67 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_userptr(FORM *form, void *usrptr)
+|
+| Description : Set the pointer that is reserved in any form to store
+| application relevant information
+|
+| Return Values : E_OK - on success
++--------------------------------------------------------------------------*/
+int set_form_userptr(FORM * form, void *usrptr)
+{
+ Normalize_Form(form)->usrptr = usrptr;
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : void *form_userptr(const FORM *form)
+|
+| Description : Return the pointer that is reserved in any form to
+| store application relevant information.
+|
+| Return Values : Value of pointer. If no such pointer has been set,
+| NULL is returned
++--------------------------------------------------------------------------*/
+void *form_userptr(const FORM * form)
+{
+ return Normalize_Form(form)->usrptr;
+}
+
+/* frm_user.c ends here */
diff --git a/Source/CursesDialog/form/frm_win.c b/Source/CursesDialog/form/frm_win.c
new file mode 100644
index 0000000..82d716f
--- /dev/null
+++ b/Source/CursesDialog/form/frm_win.c
@@ -0,0 +1,70 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : int set_form_win(FORM *form,WINDOW *win)
+|
+| Description : Set the window of the form to win.
+|
+| Return Values : E_OK - success
+| E_POSTED - form is posted
++--------------------------------------------------------------------------*/
+int set_form_win(FORM * form, WINDOW * win)
+{
+ if (form && (form->status & _POSTED))
+ RETURN(E_POSTED);
+
+ Normalize_Form( form )->win = win;
+ RETURN(E_OK);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : WINDOW *form_win(const FORM *)
+|
+| Description : Retrieve the window of the form.
+|
+| Return Values : The pointer to the Window or stdscr if there is none.
++--------------------------------------------------------------------------*/
+WINDOW *form_win(const FORM * form)
+{
+ const FORM* f = Normalize_Form( form );
+ return (f->win ? f->win : stdscr);
+}
+
+/* frm_win.c ends here */
+
diff --git a/Source/CursesDialog/form/fty_alnum.c b/Source/CursesDialog/form/fty_alnum.c
new file mode 100644
index 0000000..6f3cfd4
--- /dev/null
+++ b/Source/CursesDialog/form/fty_alnum.c
@@ -0,0 +1,138 @@
+
+/*
+ * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
+ * You may freely copy it for use as a template for your own field types.
+ * If you develop a field type that might be of general use, please send
+ * it back to the ncurses maintainers for inclusion in the next version.
+ */
+/***************************************************************************
+* *
+* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net *
+* *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+typedef struct {
+ int width;
+} alnumARG;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Make_AlphaNumeric_Type(va_list *ap)
+|
+| Description : Allocate structure for alphanumeric type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error
++--------------------------------------------------------------------------*/
+static void *Make_AlphaNumeric_Type(va_list * ap)
+{
+ alnumARG *argp = (alnumARG *)malloc(sizeof(alnumARG));
+
+ if (argp)
+ argp->width = va_arg(*ap,int);
+
+ return ((void *)argp);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Copy_AlphaNumericType(const void *argp)
+|
+| Description : Copy structure for alphanumeric type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error.
++--------------------------------------------------------------------------*/
+static void *Copy_AlphaNumeric_Type(const void *argp)
+{
+ const alnumARG *ap = (const alnumARG *)argp;
+ alnumARG *result = (alnumARG *)malloc(sizeof(alnumARG));
+
+ if (result)
+ *result = *ap;
+
+ return ((void *)result);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Free_AlphaNumeric_Type(void *argp)
+|
+| Description : Free structure for alphanumeric type argument.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Free_AlphaNumeric_Type(void * argp)
+{
+ if (argp)
+ free(argp);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_AlphaNumeric_Field(
+| FIELD *field,
+| const void *argp)
+|
+| Description : Validate buffer content to be a valid alphanumeric value
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+static bool Check_AlphaNumeric_Field(FIELD * field, const void * argp)
+{
+ int width = ((const alnumARG *)argp)->width;
+ unsigned char *bp = (unsigned char *)field_buffer(field,0);
+ int l = -1;
+ unsigned char *s;
+
+ while(*bp && *bp==' ')
+ bp++;
+ if (*bp)
+ {
+ s = bp;
+ while(*bp && isalnum(*bp))
+ bp++;
+ l = (int)(bp-s);
+ while(*bp && *bp==' ')
+ bp++;
+ }
+ return ((*bp || (l < width)) ? FALSE : TRUE);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_AlphaNumeric_Character(
+| int c,
+| const void *argp )
+|
+| Description : Check a character for the alphanumeric type.
+|
+| Return Values : TRUE - character is valid
+| FALSE - character is invalid
++--------------------------------------------------------------------------*/
+static bool Check_AlphaNumeric_Character(int c, const void * argp)
+{
+ argp=0; /* Silence unused parameter warning. */
+ return (isalnum(c) ? TRUE : FALSE);
+}
+
+static FIELDTYPE typeALNUM = {
+ _HAS_ARGS | _RESIDENT,
+ 1, /* this is mutable, so we can't be const */
+ (FIELDTYPE *)0,
+ (FIELDTYPE *)0,
+ Make_AlphaNumeric_Type,
+ Copy_AlphaNumeric_Type,
+ Free_AlphaNumeric_Type,
+ Check_AlphaNumeric_Field,
+ Check_AlphaNumeric_Character,
+ NULL,
+ NULL
+};
+
+FIELDTYPE* TYPE_ALNUM = &typeALNUM;
+
+/* fty_alnum.c ends here */
diff --git a/Source/CursesDialog/form/fty_alpha.c b/Source/CursesDialog/form/fty_alpha.c
new file mode 100644
index 0000000..e4e9ceb
--- /dev/null
+++ b/Source/CursesDialog/form/fty_alpha.c
@@ -0,0 +1,139 @@
+
+/*
+ * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
+ * You may freely copy it for use as a template for your own field types.
+ * If you develop a field type that might be of general use, please send
+ * it back to the ncurses maintainers for inclusion in the next version.
+ */
+/***************************************************************************
+* *
+* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net *
+* *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+typedef struct {
+ int width;
+} alphaARG;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Make_Alpha_Type(va_list *ap)
+|
+| Description : Allocate structure for alpha type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error
++--------------------------------------------------------------------------*/
+static void *Make_Alpha_Type(va_list * ap)
+{
+ alphaARG *argp = (alphaARG *)malloc(sizeof(alphaARG));
+ if (argp)
+ {
+ argp->width = va_arg(*ap,int);
+ }
+ return ((void *)argp);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Copy_Alpha_Type(const void * argp)
+|
+| Description : Copy structure for alpha type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error.
++--------------------------------------------------------------------------*/
+static void *Copy_Alpha_Type(const void * argp)
+{
+ const alphaARG *ap = (const alphaARG *)argp;
+ alphaARG *result = (alphaARG *)malloc(sizeof(alphaARG));
+
+ if (result)
+ {
+ *result = *ap;
+ }
+ return ((void *)result);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Free_Alpha_Type( void * argp )
+|
+| Description : Free structure for alpha type argument.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Free_Alpha_Type(void * argp)
+{
+ if (argp)
+ free(argp);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Alpha_Field(
+| FIELD * field,
+| const void * argp)
+|
+| Description : Validate buffer content to be a valid alpha value
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Alpha_Field(FIELD * field, const void * argp)
+{
+ int width = ((const alphaARG *)argp)->width;
+ unsigned char *bp = (unsigned char *)field_buffer(field,0);
+ int l = -1;
+ unsigned char *s;
+
+ while(*bp && *bp==' ')
+ bp++;
+ if (*bp)
+ {
+ s = bp;
+ while(*bp && isalpha(*bp))
+ bp++;
+ l = (int)(bp-s);
+ while(*bp && *bp==' ')
+ bp++;
+ }
+ return ((*bp || (l < width)) ? FALSE : TRUE);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Alpha_Character(
+| int c,
+| const void * argp)
+|
+| Description : Check a character for the alpha type.
+|
+| Return Values : TRUE - character is valid
+| FALSE - character is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Alpha_Character(int c, const void * argp)
+{
+ argp=0; /* Silence unused parameter warning. */
+ return (isalpha(c) ? TRUE : FALSE);
+}
+
+static FIELDTYPE typeALPHA = {
+ _HAS_ARGS | _RESIDENT,
+ 1, /* this is mutable, so we can't be const */
+ (FIELDTYPE *)0,
+ (FIELDTYPE *)0,
+ Make_Alpha_Type,
+ Copy_Alpha_Type,
+ Free_Alpha_Type,
+ Check_Alpha_Field,
+ Check_Alpha_Character,
+ NULL,
+ NULL
+};
+
+FIELDTYPE* TYPE_ALPHA = &typeALPHA;
+
+/* fty_alpha.c ends here */
diff --git a/Source/CursesDialog/form/fty_enum.c b/Source/CursesDialog/form/fty_enum.c
new file mode 100644
index 0000000..59058a9
--- /dev/null
+++ b/Source/CursesDialog/form/fty_enum.c
@@ -0,0 +1,295 @@
+
+/*
+ * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
+ * You may freely copy it for use as a template for your own field types.
+ * If you develop a field type that might be of general use, please send
+ * it back to the ncurses maintainers for inclusion in the next version.
+ */
+/***************************************************************************
+* *
+* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net *
+* *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+typedef struct {
+ char **kwds;
+ int count;
+ bool checkcase;
+ bool checkunique;
+} enumARG;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Make_Enum_Type( va_list * ap )
+|
+| Description : Allocate structure for enumeration type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error
++--------------------------------------------------------------------------*/
+static void *Make_Enum_Type(va_list * ap)
+{
+ enumARG *argp = (enumARG *)malloc(sizeof(enumARG));
+
+ if (argp)
+ {
+ int cnt = 0;
+ char **kp = (char **)0;
+ int ccase, cunique;
+
+ argp->kwds = va_arg(*ap,char **);
+ ccase = va_arg(*ap,int);
+ cunique = va_arg(*ap,int);
+ argp->checkcase = ccase ? TRUE : FALSE;
+ argp->checkunique = cunique ? TRUE : FALSE;
+
+ kp = argp->kwds;
+ while( kp && (*kp++) ) cnt++;
+ argp->count = cnt;
+ }
+ return (void *)argp;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Copy_Enum_Type( const void * argp )
+|
+| Description : Copy structure for enumeration type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error.
++--------------------------------------------------------------------------*/
+static void *Copy_Enum_Type(const void * argp)
+{
+ enumARG *result = (enumARG *)0;
+
+ if (argp)
+ {
+ const enumARG *ap = (const enumARG *)argp;
+
+ result = (enumARG *)malloc(sizeof(enumARG));
+ if (result)
+ *result = *ap;
+ }
+ return (void *)result;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Free_Enum_Type( void * argp )
+|
+| Description : Free structure for enumeration type argument.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Free_Enum_Type(void * argp)
+{
+ if (argp)
+ free(argp);
+}
+
+#define SKIP_SPACE(x) while(((*(x))!='\0') && (is_blank(*(x)))) (x)++
+#define NOMATCH 0
+#define PARTIAL 1
+#define EXACT 2
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static int Compare(const unsigned char * s,
+| const unsigned char * buf,
+| bool ccase )
+|
+| Description : Check whether or not the text in 'buf' matches the
+| text in 's', at least partial.
+|
+| Return Values : NOMATCH - buffer doesn't match
+| PARTIAL - buffer matches partially
+| EXACT - buffer matches exactly
++--------------------------------------------------------------------------*/
+static int Compare(const unsigned char *s, const unsigned char *buf,
+ bool ccase)
+{
+ SKIP_SPACE(buf); /* Skip leading spaces in both texts */
+ SKIP_SPACE(s);
+
+ if (*buf=='\0')
+ {
+ return (((*s)!='\0') ? NOMATCH : EXACT);
+ }
+ else
+ {
+ if (ccase)
+ {
+ while(*s++ == *buf)
+ {
+ if (*buf++=='\0') return EXACT;
+ }
+ }
+ else
+ {
+ while(toupper(*s++)==toupper(*buf))
+ {
+ if (*buf++=='\0') return EXACT;
+ }
+ }
+ }
+ /* At this location buf points to the first character where it no longer
+ matches with s. So if only blanks are following, we have a partial
+ match otherwise there is no match */
+ SKIP_SPACE(buf);
+ if (*buf)
+ return NOMATCH;
+
+ /* If it happens that the reference buffer is at its end, the partial
+ match is actually an exact match. */
+ return ((s[-1]!='\0') ? PARTIAL : EXACT);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Enum_Field(
+| FIELD * field,
+| const void * argp)
+|
+| Description : Validate buffer content to be a valid enumeration value
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Enum_Field(FIELD * field, const void * argp)
+{
+ char **kwds = ((const enumARG *)argp)->kwds;
+ bool ccase = ((const enumARG *)argp)->checkcase;
+ bool unique = ((const enumARG *)argp)->checkunique;
+ unsigned char *bp = (unsigned char *)field_buffer(field,0);
+ char *s, *t, *p;
+ int res;
+
+ while( kwds && (s=(*kwds++)) )
+ {
+ if ((res=Compare((unsigned char *)s,bp,ccase))!=NOMATCH)
+ {
+ p=t=s; /* t is at least a partial match */
+ if ((unique && res!=EXACT))
+ {
+ while( kwds && (p = *kwds++) )
+ {
+ if ((res=Compare((unsigned char *)p,bp,ccase))!=NOMATCH)
+ {
+ if (res==EXACT)
+ {
+ t = p;
+ break;
+ }
+ else
+ t = (char *)0;
+ }
+ }
+ }
+ if (t)
+ {
+ set_field_buffer(field,0,t);
+ return TRUE;
+ }
+ if (!p)
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static const char *dummy[] = { (char *)0 };
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Next_Enum(FIELD * field,
+| const void * argp)
+|
+| Description : Check for the next enumeration value
+|
+| Return Values : TRUE - next value found and loaded
+| FALSE - no next value loaded
++--------------------------------------------------------------------------*/
+static bool Next_Enum(FIELD * field, const void * argp)
+{
+ const enumARG *args = (const enumARG *)argp;
+ char **kwds = args->kwds;
+ bool ccase = args->checkcase;
+ int cnt = args->count;
+ unsigned char *bp = (unsigned char *)field_buffer(field,0);
+
+ if (kwds) {
+ while(cnt--)
+ {
+ if (Compare((unsigned char *)(*kwds++),bp,ccase)==EXACT)
+ break;
+ }
+ if (cnt<=0)
+ kwds = args->kwds;
+ if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT))
+ {
+ set_field_buffer(field,0,*kwds);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Previous_Enum(
+| FIELD * field,
+| const void * argp)
+|
+| Description : Check for the previous enumeration value
+|
+| Return Values : TRUE - previous value found and loaded
+| FALSE - no previous value loaded
++--------------------------------------------------------------------------*/
+static bool Previous_Enum(FIELD * field, const void * argp)
+{
+ const enumARG *args = (const enumARG *)argp;
+ int cnt = args->count;
+ char **kwds = &args->kwds[cnt-1];
+ bool ccase = args->checkcase;
+ unsigned char *bp = (unsigned char *)field_buffer(field,0);
+
+ if (kwds) {
+ while(cnt--)
+ {
+ if (Compare((unsigned char *)(*kwds--),bp,ccase)==EXACT)
+ break;
+ }
+
+ if (cnt<=0)
+ kwds = &args->kwds[args->count-1];
+
+ if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT))
+ {
+ set_field_buffer(field,0,*kwds);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+static FIELDTYPE typeENUM = {
+ _HAS_ARGS | _HAS_CHOICE | _RESIDENT,
+ 1, /* this is mutable, so we can't be const */
+ (FIELDTYPE *)0,
+ (FIELDTYPE *)0,
+ Make_Enum_Type,
+ Copy_Enum_Type,
+ Free_Enum_Type,
+ Check_Enum_Field,
+ NULL,
+ Next_Enum,
+ Previous_Enum
+};
+
+FIELDTYPE* TYPE_ENUM = &typeENUM;
+
+/* fty_enum.c ends here */
diff --git a/Source/CursesDialog/form/fty_int.c b/Source/CursesDialog/form/fty_int.c
new file mode 100644
index 0000000..7107fcc
--- /dev/null
+++ b/Source/CursesDialog/form/fty_int.c
@@ -0,0 +1,161 @@
+
+/*
+ * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
+ * You may freely copy it for use as a template for your own field types.
+ * If you develop a field type that might be of general use, please send
+ * it back to the ncurses maintainers for inclusion in the next version.
+ */
+/***************************************************************************
+* *
+* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net *
+* *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+typedef struct {
+ int precision;
+ long low;
+ long high;
+} integerARG;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Make_Integer_Type( va_list * ap )
+|
+| Description : Allocate structure for integer type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error
++--------------------------------------------------------------------------*/
+static void *Make_Integer_Type(va_list * ap)
+{
+ integerARG *argp = (integerARG *)malloc(sizeof(integerARG));
+
+ if (argp)
+ {
+ argp->precision = va_arg(*ap,int);
+ argp->low = va_arg(*ap,long);
+ argp->high = va_arg(*ap,long);
+ }
+ return (void *)argp;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Copy_Integer_Type(const void * argp)
+|
+| Description : Copy structure for integer type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error.
++--------------------------------------------------------------------------*/
+static void *Copy_Integer_Type(const void * argp)
+{
+ const integerARG *ap = (const integerARG *)argp;
+ integerARG *result = (integerARG *)0;
+
+ if (argp)
+ {
+ result = (integerARG *)malloc(sizeof(integerARG));
+ if (result)
+ *result = *ap;
+ }
+ return (void *)result;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Free_Integer_Type(void * argp)
+|
+| Description : Free structure for integer type argument.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Free_Integer_Type(void * argp)
+{
+ if (argp)
+ free(argp);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Integer_Field(
+| FIELD * field,
+| const void * argp)
+|
+| Description : Validate buffer content to be a valid integer value
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Integer_Field(FIELD * field, const void * argp)
+{
+ const integerARG *argi = (const integerARG *)argp;
+ long low = argi->low;
+ long high = argi->high;
+ int prec = argi->precision;
+ unsigned char *bp = (unsigned char *)field_buffer(field,0);
+ char *s = (char *)bp;
+ long val;
+ char buf[100];
+
+ while( *bp && *bp==' ') bp++;
+ if (*bp)
+ {
+ if (*bp=='-') bp++;
+ while (*bp)
+ {
+ if (!isdigit(*bp)) break;
+ bp++;
+ }
+ while(*bp && *bp==' ') bp++;
+ if (*bp=='\0')
+ {
+ val = atol(s);
+ if (low<high)
+ {
+ if (val<low || val>high) return FALSE;
+ }
+ sprintf(buf,"%.*ld",(prec>0?prec:0),val);
+ set_field_buffer(field,0,buf);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Integer_Character(
+| int c,
+| const void * argp)
+|
+| Description : Check a character for the integer type.
+|
+| Return Values : TRUE - character is valid
+| FALSE - character is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Integer_Character(int c, const void * argp)
+{
+ argp=0; /* Silence unused parameter warning. */
+ return ((isdigit(c) || (c=='-')) ? TRUE : FALSE);
+}
+
+static FIELDTYPE typeINTEGER = {
+ _HAS_ARGS | _RESIDENT,
+ 1, /* this is mutable, so we can't be const */
+ (FIELDTYPE *)0,
+ (FIELDTYPE *)0,
+ Make_Integer_Type,
+ Copy_Integer_Type,
+ Free_Integer_Type,
+ Check_Integer_Field,
+ Check_Integer_Character,
+ NULL,
+ NULL
+};
+
+FIELDTYPE* TYPE_INTEGER = &typeINTEGER;
+
+/* fty_int.c ends here */
diff --git a/Source/CursesDialog/form/fty_ipv4.c b/Source/CursesDialog/form/fty_ipv4.c
new file mode 100644
index 0000000..c855af6
--- /dev/null
+++ b/Source/CursesDialog/form/fty_ipv4.c
@@ -0,0 +1,84 @@
+
+/*
+ * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
+ * You may freely copy it for use as a template for your own field types.
+ * If you develop a field type that might be of general use, please send
+ * it back to the ncurses maintainers for inclusion in the next version.
+ */
+/***************************************************************************
+* *
+* Author : Per Foreby, perf@efd.lth.se *
+* *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_IPV4_Field(
+| FIELD * field,
+| const void * argp)
+|
+| Description : Validate buffer content to be a valid IP number (Ver. 4)
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+static bool Check_IPV4_Field(FIELD * field, const void * argp)
+{
+ char *bp = field_buffer(field,0);
+ int num = 0, len;
+ unsigned int d1=256, d2=256, d3=256, d4=256;
+
+ argp=0; /* Silence unused parameter warning. */
+
+ if(isdigit((int)(*bp))) /* Must start with digit */
+ {
+ num = sscanf(bp, "%u.%u.%u.%u%n", &d1, &d2, &d3, &d4, &len);
+ if (num == 4)
+ {
+ bp += len; /* Make bp point to what sscanf() left */
+ while (*bp && isspace((int)(*bp)))
+ bp++; /* Allow trailing whitespace */
+ }
+ }
+ return ((num != 4 || *bp || d1 > 255 || d2 > 255
+ || d3 > 255 || d4 > 255) ? FALSE : TRUE);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_IPV4_Character(
+| int c,
+| const void *argp )
+|
+| Description : Check a character for unsigned type or period.
+|
+| Return Values : TRUE - character is valid
+| FALSE - character is invalid
++--------------------------------------------------------------------------*/
+static bool Check_IPV4_Character(int c, const void * argp)
+{
+ argp=0; /* Silence unused parameter warning. */
+ return ((isdigit(c) || (c=='.')) ? TRUE : FALSE);
+}
+
+static FIELDTYPE typeIPV4 = {
+ _RESIDENT,
+ 1, /* this is mutable, so we can't be const */
+ (FIELDTYPE *)0,
+ (FIELDTYPE *)0,
+ NULL,
+ NULL,
+ NULL,
+ Check_IPV4_Field,
+ Check_IPV4_Character,
+ NULL,
+ NULL
+};
+
+FIELDTYPE* TYPE_IPV4 = &typeIPV4;
+
+/* fty_ipv4.c ends here */
diff --git a/Source/CursesDialog/form/fty_num.c b/Source/CursesDialog/form/fty_num.c
new file mode 100644
index 0000000..7809599
--- /dev/null
+++ b/Source/CursesDialog/form/fty_num.c
@@ -0,0 +1,192 @@
+
+/*
+ * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
+ * You may freely copy it for use as a template for your own field types.
+ * If you develop a field type that might be of general use, please send
+ * it back to the ncurses maintainers for inclusion in the next version.
+ */
+/***************************************************************************
+* *
+* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net *
+* *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+typedef struct {
+ int precision;
+ double low;
+ double high;
+ struct lconv* L;
+} numericARG;
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Make_Numeric_Type(va_list * ap)
+|
+| Description : Allocate structure for numeric type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error
++--------------------------------------------------------------------------*/
+static void *Make_Numeric_Type(va_list * ap)
+{
+ numericARG *argn = (numericARG *)malloc(sizeof(numericARG));
+
+ if (argn)
+ {
+ argn->precision = va_arg(*ap,int);
+ argn->low = va_arg(*ap,double);
+ argn->high = va_arg(*ap,double);
+#if HAVE_LOCALE_H
+ argn->L = localeconv();
+#else
+ argn->L = NULL;
+#endif
+ }
+ return (void *)argn;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Copy_Numeric_Type(const void * argp)
+|
+| Description : Copy structure for numeric type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error.
++--------------------------------------------------------------------------*/
+static void *Copy_Numeric_Type(const void * argp)
+{
+ const numericARG *ap = (const numericARG *)argp;
+ numericARG *result = (numericARG *)0;
+
+ if (argp)
+ {
+ result = (numericARG *)malloc(sizeof(numericARG));
+ if (result)
+ *result = *ap;
+ }
+ return (void *)result;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Free_Numeric_Type(void * argp)
+|
+| Description : Free structure for numeric type argument.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Free_Numeric_Type(void * argp)
+{
+ if (argp)
+ free(argp);
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Numeric_Field(FIELD * field,
+| const void * argp)
+|
+| Description : Validate buffer content to be a valid numeric value
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Numeric_Field(FIELD * field, const void * argp)
+{
+ const numericARG *argn = (const numericARG *)argp;
+ double low = argn->low;
+ double high = argn->high;
+ int prec = argn->precision;
+ unsigned char *bp = (unsigned char *)field_buffer(field,0);
+ char *s = (char *)bp;
+ double val = 0.0;
+ char buf[64];
+
+ while(*bp && *bp==' ') bp++;
+ if (*bp)
+ {
+ if (*bp=='-' || *bp=='+')
+ bp++;
+ while(*bp)
+ {
+ if (!isdigit(*bp)) break;
+ bp++;
+ }
+ if (*bp==(
+#if HAVE_LOCALE_H
+ (L && L->decimal_point) ? *(L->decimal_point) :
+#endif
+ '.'))
+ {
+ bp++;
+ while(*bp)
+ {
+ if (!isdigit(*bp)) break;
+ bp++;
+ }
+ }
+ while(*bp && *bp==' ') bp++;
+ if (*bp=='\0')
+ {
+ val = atof(s);
+ if (low<high)
+ {
+ if (val<low || val>high) return FALSE;
+ }
+ sprintf(buf,"%.*f",(prec>0?prec:0),val);
+ set_field_buffer(field,0,buf);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_Numeric_Character(
+| int c,
+| const void * argp)
+|
+| Description : Check a character for the numeric type.
+|
+| Return Values : TRUE - character is valid
+| FALSE - character is invalid
++--------------------------------------------------------------------------*/
+static bool Check_Numeric_Character(int c, const void * argp)
+{
+ argp=0; /* Silence unused parameter warning. */
+ return (isdigit(c) ||
+ c == '+' ||
+ c == '-' ||
+ c == (
+#if HAVE_LOCALE_H
+ (L && L->decimal_point) ? *(L->decimal_point) :
+#endif
+ '.')
+ ) ? TRUE : FALSE;
+}
+
+static FIELDTYPE typeNUMERIC = {
+ _HAS_ARGS | _RESIDENT,
+ 1, /* this is mutable, so we can't be const */
+ (FIELDTYPE *)0,
+ (FIELDTYPE *)0,
+ Make_Numeric_Type,
+ Copy_Numeric_Type,
+ Free_Numeric_Type,
+ Check_Numeric_Field,
+ Check_Numeric_Character,
+ NULL,
+ NULL
+};
+
+FIELDTYPE* TYPE_NUMERIC = &typeNUMERIC;
+
+/* fty_num.c ends here */
diff --git a/Source/CursesDialog/form/fty_regex.c b/Source/CursesDialog/form/fty_regex.c
new file mode 100644
index 0000000..f90e0c1
--- /dev/null
+++ b/Source/CursesDialog/form/fty_regex.c
@@ -0,0 +1,264 @@
+
+/*
+ * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
+ * You may freely copy it for use as a template for your own field types.
+ * If you develop a field type that might be of general use, please send
+ * it back to the ncurses maintainers for inclusion in the next version.
+ */
+/***************************************************************************
+* *
+* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net *
+* *
+***************************************************************************/
+
+#include "form.priv.h"
+
+MODULE_ID("$Id$")
+
+#if HAVE_REGEX_H_FUNCS /* We prefer POSIX regex */
+#include <regex.h>
+
+typedef struct
+{
+ regex_t *pRegExp;
+ unsigned long *refCount;
+} RegExp_Arg;
+
+#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
+#undef RETURN
+static int reg_errno;
+
+static char *RegEx_Init(char *instring)
+{
+ reg_errno = 0;
+ return instring;
+}
+
+static char *RegEx_Error(int code)
+{
+ reg_errno = code;
+ return 0;
+}
+
+#define INIT char *sp = RegEx_Init(instring);
+#define GETC() (*sp++)
+#define PEEKC() (*sp)
+#define UNGETC(c) (--sp)
+#define RETURN(c) return(c)
+#define ERROR(c) return RegEx_Error(c)
+
+#if HAVE_REGEXP_H_FUNCS
+#include <regexp.h>
+#else
+#include <regexpr.h>
+#endif
+
+typedef struct
+{
+ char *compiled_expression;
+ unsigned long *refCount;
+} RegExp_Arg;
+
+/* Maximum Length we allow for a compiled regular expression */
+#define MAX_RX_LEN (2048)
+#define RX_INCREMENT (256)
+
+#endif
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Make_RegularExpression_Type(va_list * ap)
+|
+| Description : Allocate structure for regex type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error
++--------------------------------------------------------------------------*/
+static void *Make_RegularExpression_Type(va_list * ap)
+{
+#if HAVE_REGEX_H_FUNCS
+ char *rx = va_arg(*ap,char *);
+ RegExp_Arg *preg;
+
+ preg = (RegExp_Arg*)malloc(sizeof(RegExp_Arg));
+ if (preg)
+ {
+ if (((preg->pRegExp = (regex_t*)malloc(sizeof(regex_t))) != (regex_t*)0)
+ && !regcomp(preg->pRegExp,rx,
+ (REG_EXTENDED | REG_NOSUB | REG_NEWLINE) ))
+ {
+ preg->refCount = (unsigned long *)malloc(sizeof(unsigned long));
+ *(preg->refCount) = 1;
+ }
+ else
+ {
+ if (preg->pRegExp)
+ free(preg->pRegExp);
+ free(preg);
+ preg = (RegExp_Arg*)0;
+ }
+ }
+ return((void *)preg);
+#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
+ char *rx = va_arg(*ap,char *);
+ RegExp_Arg *pArg;
+
+ pArg = (RegExp_Arg *)malloc(sizeof(RegExp_Arg));
+
+ if (pArg)
+ {
+ int blen = RX_INCREMENT;
+ pArg->compiled_expression = NULL;
+ pArg->refCount = (unsigned long *)malloc(sizeof(unsigned long));
+ *(pArg->refCount) = 1;
+
+ do {
+ char *buf = (char *)malloc(blen);
+ if (buf)
+ {
+#if HAVE_REGEXP_H_FUNCS
+ char *last_pos = compile (rx, buf, &buf[blen], '\0');
+#else /* HAVE_REGEXPR_H_FUNCS */
+ char *last_pos = compile (rx, buf, &buf[blen]);
+#endif
+ if (reg_errno)
+ {
+ free(buf);
+ if (reg_errno==50)
+ blen += RX_INCREMENT;
+ else
+ {
+ free(pArg);
+ pArg = NULL;
+ break;
+ }
+ }
+ else
+ {
+ pArg->compiled_expression = buf;
+ break;
+ }
+ }
+ } while( blen <= MAX_RX_LEN );
+ }
+ if (pArg && !pArg->compiled_expression)
+ {
+ free(pArg);
+ pArg = NULL;
+ }
+ return (void *)pArg;
+#else
+ ap=0; /* Silence unused parameter warning. */
+ return 0;
+#endif
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void *Copy_RegularExpression_Type(
+| const void * argp)
+|
+| Description : Copy structure for regex type argument.
+|
+| Return Values : Pointer to argument structure or NULL on error.
++--------------------------------------------------------------------------*/
+static void *Copy_RegularExpression_Type(const void * argp)
+{
+#if (HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS)
+ const RegExp_Arg *ap = (const RegExp_Arg *)argp;
+ const RegExp_Arg *result = (const RegExp_Arg *)0;
+
+ if (ap)
+ {
+ *(ap->refCount) += 1;
+ result = ap;
+ }
+ return (void *)result;
+#else
+ argp=0; /* Silence unused parameter warning. */
+ return 0;
+#endif
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static void Free_RegularExpression_Type(void * argp)
+|
+| Description : Free structure for regex type argument.
+|
+| Return Values : -
++--------------------------------------------------------------------------*/
+static void Free_RegularExpression_Type(void * argp)
+{
+#if HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
+ RegExp_Arg *ap = (RegExp_Arg *)argp;
+ if (ap)
+ {
+ if (--(*(ap->refCount)) == 0)
+ {
+#if HAVE_REGEX_H_FUNCS
+ if (ap->pRegExp)
+ {
+ free(ap->refCount);
+ regfree(ap->pRegExp);
+ }
+#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
+ if (ap->compiled_expression)
+ {
+ free(ap->refCount);
+ free(ap->compiled_expression);
+ }
+#endif
+ free(ap);
+ }
+ }
+#else
+ argp=0; /* Silence unused parameter warning. */
+#endif
+}
+
+/*---------------------------------------------------------------------------
+| Facility : libnform
+| Function : static bool Check_RegularExpression_Field(
+| FIELD * field,
+| const void * argp)
+|
+| Description : Validate buffer content to be a valid regular expression
+|
+| Return Values : TRUE - field is valid
+| FALSE - field is invalid
++--------------------------------------------------------------------------*/
+static bool Check_RegularExpression_Field(FIELD * field, const void * argp)
+{
+ bool match = FALSE;
+#if HAVE_REGEX_H_FUNCS
+ const RegExp_Arg *ap = (const RegExp_Arg*)argp;
+ if (ap && ap->pRegExp)
+ match = (regexec(ap->pRegExp,field_buffer(field,0),0,NULL,0) ? FALSE:TRUE);
+#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
+ RegExp_Arg *ap = (RegExp_Arg *)argp;
+ if (ap && ap->compiled_expression)
+ match = (step(field_buffer(field,0),ap->compiled_expression) ? TRUE:FALSE);
+#else
+ argp=0; /* Silence unused parameter warning. */
+ field=0; /* Silence unused parameter warning. */
+#endif
+ return match;
+}
+
+static FIELDTYPE typeREGEXP = {
+ _HAS_ARGS | _RESIDENT,
+ 1, /* this is mutable, so we can't be const */
+ (FIELDTYPE *)0,
+ (FIELDTYPE *)0,
+ Make_RegularExpression_Type,
+ Copy_RegularExpression_Type,
+ Free_RegularExpression_Type,
+ Check_RegularExpression_Field,
+ NULL,
+ NULL,
+ NULL
+};
+
+FIELDTYPE* TYPE_REGEXP = &typeREGEXP;
+
+/* fty_regex.c ends here */
diff --git a/Source/CursesDialog/form/llib-lform b/Source/CursesDialog/form/llib-lform
new file mode 100644
index 0000000..ac2ba43
--- /dev/null
+++ b/Source/CursesDialog/form/llib-lform
@@ -0,0 +1,694 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Thomas E. Dickey <dickey@clark.net> 1996,1997 *
+ ****************************************************************************/
+/* LINTLIBRARY */
+
+/* ./fld_arg.c */
+
+#include "form.priv.h"
+
+#undef set_fieldtype_arg
+int set_fieldtype_arg(
+ FIELDTYPE *typ,
+ void *(*const make_arg)(
+ va_list *p1),
+ void *(*const copy_arg)(
+ const void *p1),
+ void (*const free_arg)(
+ void *p1))
+ { return(*(int *)0); }
+
+#undef field_arg
+void *field_arg(
+ const FIELD *field)
+ { return(*(void **)0); }
+
+/* ./fld_attr.c */
+
+#undef set_field_fore
+int set_field_fore(
+ FIELD *field,
+ chtype attr)
+ { return(*(int *)0); }
+
+#undef field_fore
+chtype field_fore(
+ const FIELD *field)
+ { return(*(chtype *)0); }
+
+#undef set_field_back
+int set_field_back(
+ FIELD *field,
+ chtype attr)
+ { return(*(int *)0); }
+
+#undef field_back
+chtype field_back(
+ const FIELD *field)
+ { return(*(chtype *)0); }
+
+/* ./fld_current.c */
+
+#undef set_current_field
+int set_current_field(
+ FORM *form,
+ FIELD *field)
+ { return(*(int *)0); }
+
+#undef current_field
+FIELD *current_field(
+ const FORM *form)
+ { return(*(FIELD **)0); }
+
+#undef field_index
+int field_index(
+ const FIELD *field)
+ { return(*(int *)0); }
+
+/* ./fld_def.c */
+
+#undef _nc_Default_Field
+FIELD *_nc_Default_Field;
+
+#undef _nc_Make_Argument
+TypeArgument *_nc_Make_Argument(
+ const FIELDTYPE *typ,
+ va_list *ap,
+ int *err)
+ { return(*(TypeArgument **)0); }
+
+#undef _nc_Copy_Argument
+TypeArgument *_nc_Copy_Argument(
+ const FIELDTYPE *typ,
+ const TypeArgument *argp,
+ int *err)
+ { return(*(TypeArgument **)0); }
+
+#undef _nc_Free_Argument
+void _nc_Free_Argument(
+ const FIELDTYPE *typ,
+ TypeArgument *argp)
+ { /* void */ }
+
+#undef _nc_Copy_Type
+bool _nc_Copy_Type(
+ FIELD *dst,
+ FIELD const *src)
+ { return(*(bool *)0); }
+
+#undef _nc_Free_Type
+void _nc_Free_Type(
+ FIELD *field)
+ { /* void */ }
+
+#undef new_field
+FIELD *new_field(
+ int rows,
+ int cols,
+ int frow,
+ int fcol,
+ int nrow,
+ int nbuf)
+ { return(*(FIELD **)0); }
+
+#undef free_field
+int free_field(
+ FIELD *field)
+ { return(*(int *)0); }
+
+/* ./fld_dup.c */
+
+#undef dup_field
+FIELD *dup_field(
+ FIELD *field,
+ int frow,
+ int fcol)
+ { return(*(FIELD **)0); }
+
+/* ./fld_ftchoice.c */
+
+#undef set_fieldtype_choice
+int set_fieldtype_choice(
+ FIELDTYPE *typ,
+ bool (*const next_choice)(
+ FIELD *p1,
+ const void *p2),
+ bool (*const prev_choice)(
+ FIELD *p1,
+ const void *p2))
+ { return(*(int *)0); }
+
+/* ./fld_ftlink.c */
+
+#undef link_fieldtype
+FIELDTYPE *link_fieldtype(
+ FIELDTYPE *type1,
+ FIELDTYPE *type2)
+ { return(*(FIELDTYPE **)0); }
+
+/* ./fld_info.c */
+
+#undef field_info
+int field_info(
+ const FIELD *field,
+ int *rows,
+ int *cols,
+ int *frow,
+ int *fcol,
+ int *nrow,
+ int *nbuf)
+ { return(*(int *)0); }
+
+#undef dynamic_field_info
+int dynamic_field_info(
+ const FIELD *field,
+ int *drows,
+ int *dcols,
+ int *maxgrow)
+ { return(*(int *)0); }
+
+/* ./fld_just.c */
+
+#undef set_field_just
+int set_field_just(
+ FIELD *field,
+ int just)
+ { return(*(int *)0); }
+
+#undef field_just
+int field_just(
+ const FIELD *field)
+ { return(*(int *)0); }
+
+/* ./fld_link.c */
+
+#undef link_field
+FIELD *link_field(
+ FIELD *field,
+ int frow,
+ int fcol)
+ { return(*(FIELD **)0); }
+
+/* ./fld_max.c */
+
+#undef set_max_field
+int set_max_field(
+ FIELD *field,
+ int maxgrow)
+ { return(*(int *)0); }
+
+/* ./fld_move.c */
+
+#undef move_field
+int move_field(
+ FIELD *field,
+ int frow,
+ int fcol)
+ { return(*(int *)0); }
+
+/* ./fld_newftyp.c */
+
+#undef _nc_Default_FieldType
+const FIELDTYPE *_nc_Default_FieldType = {0};
+
+#undef new_fieldtype
+FIELDTYPE *new_fieldtype(
+ bool (*const field_check)(
+ FIELD *p1,
+ const void *p2),
+ bool (*const char_check)(
+ int p1,
+ const void *p2))
+ { return(*(FIELDTYPE **)0); }
+
+#undef free_fieldtype
+int free_fieldtype(
+ FIELDTYPE *typ)
+ { return(*(int *)0); }
+
+/* ./fld_opts.c */
+
+#undef set_field_opts
+int set_field_opts(
+ FIELD *field,
+ Field_Options opts)
+ { return(*(int *)0); }
+
+#undef field_opts
+Field_Options field_opts(
+ const FIELD *field)
+ { return(*(Field_Options *)0); }
+
+#undef field_opts_on
+int field_opts_on(
+ FIELD *field,
+ Field_Options opts)
+ { return(*(int *)0); }
+
+#undef field_opts_off
+int field_opts_off(
+ FIELD *field,
+ Field_Options opts)
+ { return(*(int *)0); }
+
+/* ./fld_pad.c */
+
+#undef set_field_pad
+int set_field_pad(
+ FIELD *field,
+ int ch)
+ { return(*(int *)0); }
+
+#undef field_pad
+int field_pad(
+ const FIELD *field)
+ { return(*(int *)0); }
+
+/* ./fld_page.c */
+
+#undef set_new_page
+int set_new_page(
+ FIELD *field,
+ bool new_page_flag)
+ { return(*(int *)0); }
+
+#undef new_page
+bool new_page(
+ const FIELD *field)
+ { return(*(bool *)0); }
+
+/* ./fld_stat.c */
+
+#undef set_field_status
+int set_field_status(
+ FIELD *field,
+ bool status)
+ { return(*(int *)0); }
+
+#undef field_status
+bool field_status(
+ const FIELD *field)
+ { return(*(bool *)0); }
+
+/* ./fld_type.c */
+
+#undef set_field_type
+int set_field_type(
+ FIELD *field,
+ FIELDTYPE *type,
+ ...)
+ { return(*(int *)0); }
+
+#undef field_type
+FIELDTYPE *field_type(
+ const FIELD *field)
+ { return(*(FIELDTYPE **)0); }
+
+/* ./fld_user.c */
+
+#undef set_field_userptr
+int set_field_userptr(
+ FIELD *field,
+ void *usrptr)
+ { return(*(int *)0); }
+
+#undef field_userptr
+void *field_userptr(
+ const FIELD *field)
+ { return(*(void **)0); }
+
+/* ./frm_cursor.c */
+
+#undef pos_form_cursor
+int pos_form_cursor(
+ FORM *form)
+ { return(*(int *)0); }
+
+/* ./frm_data.c */
+
+#undef data_behind
+bool data_behind(
+ const FORM *form)
+ { return(*(bool *)0); }
+
+#undef data_ahead
+bool data_ahead(
+ const FORM *form)
+ { return(*(bool *)0); }
+
+/* ./frm_def.c */
+
+#undef _nc_Default_Form
+FORM *_nc_Default_Form;
+
+#undef new_form
+FORM *new_form(
+ FIELD **fields)
+ { return(*(FORM **)0); }
+
+#undef free_form
+int free_form(
+ FORM *form)
+ { return(*(int *)0); }
+
+#undef set_form_fields
+int set_form_fields(
+ FORM *form,
+ FIELD **fields)
+ { return(*(int *)0); }
+
+#undef form_fields
+FIELD **form_fields(
+ const FORM *form)
+ { return(*(FIELD ***)0); }
+
+#undef field_count
+int field_count(
+ const FORM *form)
+ { return(*(int *)0); }
+
+/* ./frm_driver.c */
+
+#undef _nc_Position_Form_Cursor
+int _nc_Position_Form_Cursor(
+ FORM *form)
+ { return(*(int *)0); }
+
+#undef _nc_Refresh_Current_Field
+int _nc_Refresh_Current_Field(
+ FORM *form)
+ { return(*(int *)0); }
+
+#undef _nc_Synchronize_Attributes
+int _nc_Synchronize_Attributes(
+ FIELD *field)
+ { return(*(int *)0); }
+
+#undef _nc_Synchronize_Options
+int _nc_Synchronize_Options(
+ FIELD *field,
+ Field_Options newopts)
+ { return(*(int *)0); }
+
+#undef _nc_Set_Current_Field
+int _nc_Set_Current_Field(
+ FORM *form,
+ FIELD *newfield)
+ { return(*(int *)0); }
+
+#undef _nc_Internal_Validation
+bool _nc_Internal_Validation(
+ FORM *form)
+ { return(*(bool *)0); }
+
+#undef _nc_First_Active_Field
+FIELD *_nc_First_Active_Field(
+ FORM *form)
+ { return(*(FIELD **)0); }
+
+#undef _nc_Set_Form_Page
+int _nc_Set_Form_Page(
+ FORM *form,
+ int page,
+ FIELD *field)
+ { return(*(int *)0); }
+
+typedef struct {
+ int keycode;
+ int (*cmd)(FORM *);
+} Binding_Info;
+
+#undef form_driver
+int form_driver(
+ FORM *form,
+ int c)
+ { return(*(int *)0); }
+
+#undef set_field_buffer
+int set_field_buffer(
+ FIELD *field,
+ int buffer,
+ const char *value)
+ { return(*(int *)0); }
+
+#undef field_buffer
+char *field_buffer(
+ const FIELD *field,
+ int buffer)
+ { return(*(char **)0); }
+
+/* ./frm_hook.c */
+
+#undef set_field_init
+int set_field_init(
+ FORM *form,
+ Form_Hook func)
+ { return(*(int *)0); }
+
+#undef field_init
+Form_Hook field_init(
+ const FORM *form)
+ { return(*(Form_Hook *)0); }
+
+#undef set_field_term
+int set_field_term(
+ FORM *form,
+ Form_Hook func)
+ { return(*(int *)0); }
+
+#undef field_term
+Form_Hook field_term(
+ const FORM *form)
+ { return(*(Form_Hook *)0); }
+
+#undef set_form_init
+int set_form_init(
+ FORM *form,
+ Form_Hook func)
+ { return(*(int *)0); }
+
+#undef form_init
+Form_Hook form_init(
+ const FORM *form)
+ { return(*(Form_Hook *)0); }
+
+#undef set_form_term
+int set_form_term(
+ FORM *form,
+ Form_Hook func)
+ { return(*(int *)0); }
+
+#undef form_term
+Form_Hook form_term(
+ const FORM *form)
+ { return(*(Form_Hook *)0); }
+
+/* ./frm_opts.c */
+
+#undef set_form_opts
+int set_form_opts(
+ FORM *form,
+ Form_Options opts)
+ { return(*(int *)0); }
+
+#undef form_opts
+Form_Options form_opts(
+ const FORM *form)
+ { return(*(Form_Options *)0); }
+
+#undef form_opts_on
+int form_opts_on(
+ FORM *form,
+ Form_Options opts)
+ { return(*(int *)0); }
+
+#undef form_opts_off
+int form_opts_off(
+ FORM *form,
+ Form_Options opts)
+ { return(*(int *)0); }
+
+/* ./frm_page.c */
+
+#undef set_form_page
+int set_form_page(
+ FORM *form,
+ int page)
+ { return(*(int *)0); }
+
+#undef form_page
+int form_page(
+ const FORM *form)
+ { return(*(int *)0); }
+
+/* ./frm_post.c */
+
+#undef post_form
+int post_form(
+ FORM *form)
+ { return(*(int *)0); }
+
+#undef unpost_form
+int unpost_form(
+ FORM *form)
+ { return(*(int *)0); }
+
+/* ./frm_req_name.c */
+
+#undef form_request_name
+const char *form_request_name(
+ int request)
+ { return(*(const char **)0); }
+
+#undef form_request_by_name
+int form_request_by_name(
+ const char *str)
+ { return(*(int *)0); }
+
+/* ./frm_scale.c */
+
+#undef scale_form
+int scale_form(
+ const FORM *form,
+ int *rows,
+ int *cols)
+ { return(*(int *)0); }
+
+/* ./frm_sub.c */
+
+#undef set_form_sub
+int set_form_sub(
+ FORM *form,
+ WINDOW *win)
+ { return(*(int *)0); }
+
+#undef form_sub
+WINDOW *form_sub(
+ const FORM *form)
+ { return(*(WINDOW **)0); }
+
+/* ./frm_user.c */
+
+#undef set_form_userptr
+int set_form_userptr(
+ FORM *form,
+ void *usrptr)
+ { return(*(int *)0); }
+
+#undef form_userptr
+void *form_userptr(
+ const FORM *form)
+ { return(*(void **)0); }
+
+/* ./frm_win.c */
+
+#undef set_form_win
+int set_form_win(
+ FORM *form,
+ WINDOW *win)
+ { return(*(int *)0); }
+
+#undef form_win
+WINDOW *form_win(
+ const FORM *form)
+ { return(*(WINDOW **)0); }
+
+/* ./fty_alnum.c */
+
+typedef struct {
+ int width;
+} alnumARG;
+
+#undef TYPE_ALNUM
+FIELDTYPE *TYPE_ALNUM;
+
+/* ./fty_alpha.c */
+
+typedef struct {
+ int width;
+} alphaARG;
+
+#undef TYPE_ALPHA
+FIELDTYPE *TYPE_ALPHA;
+
+/* ./fty_enum.c */
+
+typedef struct {
+ char **kwds;
+ int count;
+ bool checkcase;
+ bool checkunique;
+} enumARG;
+
+#undef TYPE_ENUM
+FIELDTYPE *TYPE_ENUM;
+
+/* ./fty_int.c */
+
+typedef struct {
+ int precision;
+ long low;
+ long high;
+} integerARG;
+
+#undef TYPE_INTEGER
+FIELDTYPE *TYPE_INTEGER;
+
+/* ./fty_ipv4.c */
+#undef TYPE_IPV4
+FIELDTYPE *TYPE_IPV4;
+
+/* ./fty_num.c */
+
+#include <locale.h>
+
+typedef struct {
+ int precision;
+ double low;
+ double high;
+ struct lconv* L;
+} numericARG;
+
+#undef TYPE_NUMERIC
+FIELDTYPE *TYPE_NUMERIC;
+
+/* ./fty_regex.c */
+
+#include <regex.h>
+
+typedef struct
+{
+ regex_t *pRegExp;
+ unsigned long *refCount;
+} RegExp_Arg;
+
+#undef TYPE_REGEXP
+FIELDTYPE *TYPE_REGEXP;
diff --git a/Source/CursesDialog/form/mf_common.h b/Source/CursesDialog/form/mf_common.h
new file mode 100644
index 0000000..6b1e8fe
--- /dev/null
+++ b/Source/CursesDialog/form/mf_common.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+ * Copyright (c) 1998,2000 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
+ ****************************************************************************/
+
+/* Common internal header for menu and form library */
+
+#if HAVE_CONFIG_H
+# include <ncurses_cfg.h>
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#if DECL_ERRNO
+extern int errno;
+#endif
+
+/* in case of debug version we ignore the suppression of assertions */
+#ifdef TRACE
+# ifdef NDEBUG
+# undef NDEBUG
+# endif
+#endif
+
+#include <nc_alloc.h>
+
+#if USE_RCS_IDS
+#define MODULE_ID(id) static const char Ident[] = id;
+#else
+#define MODULE_ID(id) /*nothing*/
+#endif
+
+
+/* Maximum regular 8-bit character code */
+#define MAX_REGULAR_CHARACTER (0xff)
+
+#define SET_ERROR(code) (errno=(code))
+#define GET_ERROR() (errno)
+#define RETURN(code) return( SET_ERROR(code) )
+
+/* The few common values in the status fields for menus and forms */
+#define _POSTED (0x01) /* menu or form is posted */
+#define _IN_DRIVER (0x02) /* menu or form is processing hook routine */
+
+/* Call object hook */
+#define Call_Hook( object, handler ) \
+ if ( (object) && ((object)->handler) )\
+ {\
+ (object)->status |= _IN_DRIVER;\
+ (object)->handler(object);\
+ (object)->status &= ~_IN_DRIVER;\
+ }
+
+#define INLINE
+
+#ifndef TRACE
+# if CC_HAS_INLINE_FUNCS
+# undef INLINE
+# define INLINE inline
+# endif
+#endif
diff --git a/Source/CursesDialog/form/nc_alloc.h b/Source/CursesDialog/form/nc_alloc.h
new file mode 100644
index 0000000..f49ea93
--- /dev/null
+++ b/Source/CursesDialog/form/nc_alloc.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Thomas E. Dickey <dickey@clark.net> 1996,1997 *
+ ****************************************************************************/
+/* $Id$ */
+
+#ifndef NC_ALLOC_included
+#define NC_ALLOC_included 1
+
+#if HAVE_LIBDMALLOC
+#include <dmalloc.h> /* Gray Watson's library */
+#else
+#undef HAVE_LIBDMALLOC
+#define HAVE_LIBDMALLOC 0
+#endif
+
+#if HAVE_LIBDBMALLOC
+#include <dbmalloc.h> /* Conor Cahill's library */
+#else
+#undef HAVE_LIBDBMALLOC
+#define HAVE_LIBDBMALLOC 0
+#endif
+
+#ifndef NO_LEAKS
+#define NO_LEAKS 0
+#endif
+
+#if HAVE_LIBDBMALLOC || HAVE_LIBDMALLOC || NO_LEAKS
+#define HAVE_NC_FREEALL 1
+struct termtype;
+extern void _nc_free_and_exit(int) GCC_NORETURN;
+extern void _nc_free_tparm(void);
+extern void _nc_leaks_dump_entry(void);
+#define ExitProgram(code) _nc_free_and_exit(code)
+#endif
+
+#ifndef HAVE_NC_FREEALL
+#define HAVE_NC_FREEALL 0
+#endif
+
+#ifndef ExitProgram
+#define ExitProgram(code) return code
+#endif
+
+/* doalloc.c */
+extern void *_nc_doalloc(void *, size_t);
+#if !HAVE_STRDUP
+/* #define strdup _nc_strdup */
+extern char *_nc_strdup(const char *);
+#endif
+
+#define typeMalloc(type,elts) (type *)malloc((elts)*sizeof(type))
+#define typeCalloc(type,elts) (type *)calloc((elts),sizeof(type))
+#define typeRealloc(type,elts,ptr) (type *)_nc_doalloc(ptr, (elts)*sizeof(type))
+
+#endif /* NC_ALLOC_included */
diff --git a/Source/LexerParser/.clang-tidy b/Source/LexerParser/.clang-tidy
new file mode 100644
index 0000000..52b11bf
--- /dev/null
+++ b/Source/LexerParser/.clang-tidy
@@ -0,0 +1,6 @@
+---
+# We want to disable all checks for generated code. However, clang-tidy will
+# assume we did not configure it correctly. Just add one check that will never
+# be found.
+Checks: '-*,llvm-twine-local'
+...
diff --git a/Source/LexerParser/.gitattributes b/Source/LexerParser/.gitattributes
new file mode 100644
index 0000000..63d9afb
--- /dev/null
+++ b/Source/LexerParser/.gitattributes
@@ -0,0 +1,21 @@
+/cmCommandArgumentLexer.cxx generated
+/cmCommandArgumentLexer.h generated
+/cmCommandArgumentParser.cxx generated
+/cmCommandArgumentParserTokens.h generated
+/cmCTestResourceGroupsLexer.cxx generated
+/cmCTestResourceGroupsLexer.h generated
+/cmDependsJavaLexer.cxx generated
+/cmDependsJavaLexer.h generated
+/cmDependsJavaParser.cxx generated
+/cmDependsJavaParserTokens.h generated
+/cmExprLexer.cxx generated
+/cmExprLexer.h generated
+/cmExprParser.cxx generated
+/cmExprParserTokens.h generated
+/cmFortranLexer.cxx generated
+/cmFortranLexer.h generated
+/cmFortranParser.cxx generated
+/cmFortranParserTokens.h generated
+/cmGccDepfileLexer.cxx generated
+/cmGccDepfileLexer.h generated
+/cmListFileLexer.c generated
diff --git a/Source/LexerParser/cmCTestResourceGroupsLexer.cxx b/Source/LexerParser/cmCTestResourceGroupsLexer.cxx
new file mode 100644
index 0000000..de07c46
--- /dev/null
+++ b/Source/LexerParser/cmCTestResourceGroupsLexer.cxx
@@ -0,0 +1,2224 @@
+#include "cmStandardLexer.h"
+
+#define FLEXINT_H 1
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmCTestResourceGroups_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmCTestResourceGroups_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmCTestResourceGroups_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmCTestResourceGroups_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmCTestResourceGroups_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmCTestResourceGroups_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmCTestResourceGroups_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmCTestResourceGroups_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmCTestResourceGroups_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmCTestResourceGroups_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmCTestResourceGroups_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmCTestResourceGroups_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmCTestResourceGroups_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmCTestResourceGroups_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmCTestResourceGroups_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmCTestResourceGroups_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmCTestResourceGroups_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmCTestResourceGroups_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmCTestResourceGroups_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmCTestResourceGroups_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmCTestResourceGroups_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmCTestResourceGroups_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmCTestResourceGroups_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmCTestResourceGroups_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmCTestResourceGroups_yylex_ALREADY_DEFINED
+#else
+#define yylex cmCTestResourceGroups_yylex
+#endif
+
+#ifdef yyrestart
+#define cmCTestResourceGroups_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmCTestResourceGroups_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmCTestResourceGroups_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmCTestResourceGroups_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmCTestResourceGroups_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmCTestResourceGroups_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmCTestResourceGroups_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmCTestResourceGroups_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmCTestResourceGroups_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmCTestResourceGroups_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmCTestResourceGroups_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmCTestResourceGroups_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmCTestResourceGroups_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmCTestResourceGroups_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmCTestResourceGroups_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmCTestResourceGroups_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmCTestResourceGroups_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmCTestResourceGroups_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmCTestResourceGroups_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmCTestResourceGroups_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmCTestResourceGroups_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmCTestResourceGroups_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmCTestResourceGroups_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmCTestResourceGroups_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmCTestResourceGroups_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmCTestResourceGroups_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmCTestResourceGroups_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmCTestResourceGroups_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmCTestResourceGroups_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmCTestResourceGroups_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmCTestResourceGroups_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmCTestResourceGroups_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmCTestResourceGroups_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmCTestResourceGroups_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmCTestResourceGroups_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmCTestResourceGroups_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmCTestResourceGroups_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmCTestResourceGroups_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmCTestResourceGroups_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmCTestResourceGroups_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmCTestResourceGroups_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmCTestResourceGroups_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmCTestResourceGroups_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmCTestResourceGroups_yyfree
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an
+ * integer in range [0..255] for use as an array index.
+ */
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin , yyscanner )
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+ #define YY_LINENO_REWIND_TO(ptr)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+static void yyensure_buffer_stack ( yyscan_t yyscanner );
+static void yy_load_buffer_state ( yyscan_t yyscanner );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner)
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+#define yy_new_buffer yy_create_buffer
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define cmCTestResourceGroups_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+typedef flex_uint8_t YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner);
+static int yy_get_next_buffer ( yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+#define YY_NUM_RULES 8
+#define YY_END_OF_BUFFER 9
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static const flex_int16_t yy_accept[29] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 9, 7, 2, 5, 7, 4, 6, 3,
+ 2, 5, 0, 1, 4, 6, 3, 0
+ } ;
+
+static const YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 3, 1, 1, 1, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 5, 6, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 7, 1, 7, 7, 7, 7,
+
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static const YY_CHAR yy_meta[8] =
+ { 0,
+ 1, 1, 1, 2, 2, 1, 2
+ } ;
+
+static const flex_int16_t yy_base[30] =
+ { 0,
+ 0, 0, 0, 0, 7, 0, 31, 12, 17, 0,
+ 0, 0, 34, 36, 29, 26, 26, 27, 23, 24,
+ 23, 20, 20, 36, 21, 16, 13, 36, 14
+ } ;
+
+static const flex_int16_t yy_def[30] =
+ { 0,
+ 28, 1, 1, 1, 28, 5, 1, 5, 5, 9,
+ 5, 5, 28, 28, 28, 28, 29, 28, 28, 28,
+ 28, 28, 29, 28, 28, 28, 28, 0, 28
+ } ;
+
+static const flex_int16_t yy_nxt[44] =
+ { 0,
+ 14, 14, 14, 15, 14, 16, 17, 14, 14, 18,
+ 14, 14, 19, 14, 14, 23, 27, 16, 17, 14,
+ 20, 26, 14, 25, 24, 22, 21, 27, 26, 25,
+ 24, 22, 21, 28, 14, 13, 28, 28, 28, 28,
+ 28, 28, 28
+ } ;
+
+static const flex_int16_t yy_chk[44] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 5, 5, 5,
+ 5, 5, 5, 5, 8, 29, 27, 8, 8, 9,
+ 9, 26, 9, 25, 23, 22, 21, 20, 19, 18,
+ 17, 16, 15, 13, 7, 28, 28, 28, 28, 28,
+ 28, 28, 28
+ } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C++ and modified to build everywhere.
+
+Run flex >= 2.6 like this:
+
+ flex --nounistd -DFLEXINT_H --noline --header-file=cmCTestResourceGroupsLexer.h -ocmCTestResourceGroupsLexer.cxx cmCTestResourceGroupsLexer.in.l
+
+Modify cmCTestResourceGroupsLexer.cxx:
+ - remove trailing whitespace: sed -i 's/\s*$//' cmCTestResourceGroupsLexer.h cmCTestResourceGroupsLexer.cxx
+ - remove blank lines at end of file: sed -i '${/^$/d;}' cmCTestResourceGroupsLexer.h cmCTestResourceGroupsLexer.cxx
+ - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmCTestResourceGroupsLexer.cxx
+
+*/
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
+
+#include "cmCTestResourceGroupsLexerHelper.h"
+
+#include <string>
+
+#include <cstddef>
+
+/*--------------------------------------------------------------------------*/
+
+#define INITIAL 0
+#define RESOURCE_GROUPS_START 1
+#define RESOURCE_GROUPS_END 2
+#define RESOURCE_START 3
+#define RESOURCE_COUNT 4
+#define RESOURCE_END 5
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals ( yyscan_t yyscanner );
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput ( int c, char *buf_ptr , yyscan_t yyscanner);
+
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput ( yyscan_t yyscanner );
+#else
+static int input ( yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ int n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK /*LINTED*/break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_load_buffer_state( yyscanner );
+ }
+
+ {
+
+ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 29 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 36 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+{
+ BEGIN(RESOURCE_COUNT);
+ yyextra->SetResourceType(std::string(yytext, yyleng - 1));
+}
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+{
+ BEGIN(RESOURCE_GROUPS_END);
+ std::size_t len = yyleng;
+ yyextra->SetProcessCount(std::stoll(yytext, &len, 10));
+}
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+{
+ BEGIN(RESOURCE_END);
+ std::size_t len = yyleng;
+ yyextra->SetNeededSlots(std::stoll(yytext, &len, 10));
+ yyextra->WriteRequirement();
+}
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+ BEGIN(RESOURCE_START);
+}
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+{
+ BEGIN(RESOURCE_GROUPS_START);
+}
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+{
+ BEGIN(RESOURCE_GROUPS_START);
+ yyextra->WriteProcess();
+}
+ YY_BREAK
+case YY_STATE_EOF(RESOURCE_START):
+case YY_STATE_EOF(RESOURCE_GROUPS_END):
+case YY_STATE_EOF(RESOURCE_END):
+{
+ yyextra->WriteProcess();
+ return 0;
+}
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(RESOURCE_GROUPS_START):
+{
+ return 0;
+}
+ YY_BREAK
+case YY_STATE_EOF(RESOURCE_COUNT):
+{
+ return 1;
+}
+ YY_BREAK
+case 7:
+/* rule 7 can match eol */
+YY_RULE_SETUP
+{
+ return 1;
+}
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+YY_FATAL_ERROR( "flex scanner jammed" );
+ YY_BREAK
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap( yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of user's declarations */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc( (void *) b->yy_ch_buf,
+ (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = NULL;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin , yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+ (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ /* "- 2" to take care of EOB's */
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 29 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ char *yy_cp = yyg->yy_c_buf_p;
+
+ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 29 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_is_jam = (yy_current_state == 28);
+
+ (void)yyg;
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput (int c, char * yy_bp , yyscan_t yyscanner)
+{
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yyg->yy_hold_char;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ int number_to_move = yyg->yy_n_chars + 2;
+ char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ yyg->yy_n_chars = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ yyg->yytext_ptr = yy_bp;
+ yyg->yy_hold_char = *yy_cp;
+ yyg->yy_c_buf_p = yy_cp;
+}
+
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin , yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( yyscanner ) )
+ return 0;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner);
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file , yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree( (void *) b->yy_ch_buf , yyscanner );
+
+ yyfree( (void *) b , yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_flush_buffer( b , yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return NULL;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = NULL;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b , yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner)
+{
+
+ return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = (yy_size_t) (_yybytes_len + 2);
+ buf = (char *) yyalloc( n , yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n , yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param _line_number line number
+ * @param yyscanner The scanner object.
+ */
+void yyset_lineno (int _line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
+
+ yylineno = _line_number;
+}
+
+/** Set the current column.
+ * @param _column_no column number
+ * @param yyscanner The scanner object.
+ */
+void yyset_column (int _column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_column called with no buffer" );
+
+ yycolumn = _column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param _in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * _in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = _in_str ;
+}
+
+void yyset_out (FILE * _out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = _out_str ;
+}
+
+int yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void yyset_debug (int _bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = _bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+/* User-visible API */
+
+/* yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+int yylex_init(yyscan_t* ptr_yy_globals)
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to yyalloc in
+ * the yyextra field.
+ */
+int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals )
+{
+ struct yyguts_t dummy_yyguts;
+
+ yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = NULL;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = NULL;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = NULL;
+ yyout = NULL;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ yyfree(yyg->yy_buffer_stack , yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ yyfree( yyg->yy_start_stack , yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ yyfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
+{
+ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ return malloc(size);
+}
+
+void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return realloc(ptr, size);
+}
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+/*--------------------------------------------------------------------------*/
+
+#endif /* __clang_analyzer__ */
diff --git a/Source/LexerParser/cmCTestResourceGroupsLexer.h b/Source/LexerParser/cmCTestResourceGroupsLexer.h
new file mode 100644
index 0000000..e323a50
--- /dev/null
+++ b/Source/LexerParser/cmCTestResourceGroupsLexer.h
@@ -0,0 +1,692 @@
+#ifndef cmCTestResourceGroups_yyHEADER_H
+#define cmCTestResourceGroups_yyHEADER_H 1
+#define cmCTestResourceGroups_yyIN_HEADER 1
+
+#define FLEXINT_H 1
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmCTestResourceGroups_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmCTestResourceGroups_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmCTestResourceGroups_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmCTestResourceGroups_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmCTestResourceGroups_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmCTestResourceGroups_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmCTestResourceGroups_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmCTestResourceGroups_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmCTestResourceGroups_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmCTestResourceGroups_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmCTestResourceGroups_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmCTestResourceGroups_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmCTestResourceGroups_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmCTestResourceGroups_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmCTestResourceGroups_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmCTestResourceGroups_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmCTestResourceGroups_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmCTestResourceGroups_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmCTestResourceGroups_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmCTestResourceGroups_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmCTestResourceGroups_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmCTestResourceGroups_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmCTestResourceGroups_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmCTestResourceGroups_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmCTestResourceGroups_yylex_ALREADY_DEFINED
+#else
+#define yylex cmCTestResourceGroups_yylex
+#endif
+
+#ifdef yyrestart
+#define cmCTestResourceGroups_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmCTestResourceGroups_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmCTestResourceGroups_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmCTestResourceGroups_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmCTestResourceGroups_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmCTestResourceGroups_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmCTestResourceGroups_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmCTestResourceGroups_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmCTestResourceGroups_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmCTestResourceGroups_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmCTestResourceGroups_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmCTestResourceGroups_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmCTestResourceGroups_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmCTestResourceGroups_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmCTestResourceGroups_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmCTestResourceGroups_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmCTestResourceGroups_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmCTestResourceGroups_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmCTestResourceGroups_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmCTestResourceGroups_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmCTestResourceGroups_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmCTestResourceGroups_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmCTestResourceGroups_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmCTestResourceGroups_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmCTestResourceGroups_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmCTestResourceGroups_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmCTestResourceGroups_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmCTestResourceGroups_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmCTestResourceGroups_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmCTestResourceGroups_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmCTestResourceGroups_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmCTestResourceGroups_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmCTestResourceGroups_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmCTestResourceGroups_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmCTestResourceGroups_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmCTestResourceGroups_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmCTestResourceGroups_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmCTestResourceGroups_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmCTestResourceGroups_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmCTestResourceGroups_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmCTestResourceGroups_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmCTestResourceGroups_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmCTestResourceGroups_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmCTestResourceGroups_yyfree
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+/* Begin user sect3 */
+
+#define cmCTestResourceGroups_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+#define RESOURCE_GROUPS_START 1
+#define RESOURCE_GROUPS_END 2
+#define RESOURCE_START 3
+#define RESOURCE_COUNT 4
+#define RESOURCE_END 5
+
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#ifndef cmCTestResourceGroups_yy_create_buffer_ALREADY_DEFINED
+#undef yy_create_buffer
+#endif
+#ifndef cmCTestResourceGroups_yy_delete_buffer_ALREADY_DEFINED
+#undef yy_delete_buffer
+#endif
+#ifndef cmCTestResourceGroups_yy_scan_buffer_ALREADY_DEFINED
+#undef yy_scan_buffer
+#endif
+#ifndef cmCTestResourceGroups_yy_scan_string_ALREADY_DEFINED
+#undef yy_scan_string
+#endif
+#ifndef cmCTestResourceGroups_yy_scan_bytes_ALREADY_DEFINED
+#undef yy_scan_bytes
+#endif
+#ifndef cmCTestResourceGroups_yy_init_buffer_ALREADY_DEFINED
+#undef yy_init_buffer
+#endif
+#ifndef cmCTestResourceGroups_yy_flush_buffer_ALREADY_DEFINED
+#undef yy_flush_buffer
+#endif
+#ifndef cmCTestResourceGroups_yy_load_buffer_state_ALREADY_DEFINED
+#undef yy_load_buffer_state
+#endif
+#ifndef cmCTestResourceGroups_yy_switch_to_buffer_ALREADY_DEFINED
+#undef yy_switch_to_buffer
+#endif
+#ifndef cmCTestResourceGroups_yypush_buffer_state_ALREADY_DEFINED
+#undef yypush_buffer_state
+#endif
+#ifndef cmCTestResourceGroups_yypop_buffer_state_ALREADY_DEFINED
+#undef yypop_buffer_state
+#endif
+#ifndef cmCTestResourceGroups_yyensure_buffer_stack_ALREADY_DEFINED
+#undef yyensure_buffer_stack
+#endif
+#ifndef cmCTestResourceGroups_yylex_ALREADY_DEFINED
+#undef yylex
+#endif
+#ifndef cmCTestResourceGroups_yyrestart_ALREADY_DEFINED
+#undef yyrestart
+#endif
+#ifndef cmCTestResourceGroups_yylex_init_ALREADY_DEFINED
+#undef yylex_init
+#endif
+#ifndef cmCTestResourceGroups_yylex_init_extra_ALREADY_DEFINED
+#undef yylex_init_extra
+#endif
+#ifndef cmCTestResourceGroups_yylex_destroy_ALREADY_DEFINED
+#undef yylex_destroy
+#endif
+#ifndef cmCTestResourceGroups_yyget_debug_ALREADY_DEFINED
+#undef yyget_debug
+#endif
+#ifndef cmCTestResourceGroups_yyset_debug_ALREADY_DEFINED
+#undef yyset_debug
+#endif
+#ifndef cmCTestResourceGroups_yyget_extra_ALREADY_DEFINED
+#undef yyget_extra
+#endif
+#ifndef cmCTestResourceGroups_yyset_extra_ALREADY_DEFINED
+#undef yyset_extra
+#endif
+#ifndef cmCTestResourceGroups_yyget_in_ALREADY_DEFINED
+#undef yyget_in
+#endif
+#ifndef cmCTestResourceGroups_yyset_in_ALREADY_DEFINED
+#undef yyset_in
+#endif
+#ifndef cmCTestResourceGroups_yyget_out_ALREADY_DEFINED
+#undef yyget_out
+#endif
+#ifndef cmCTestResourceGroups_yyset_out_ALREADY_DEFINED
+#undef yyset_out
+#endif
+#ifndef cmCTestResourceGroups_yyget_leng_ALREADY_DEFINED
+#undef yyget_leng
+#endif
+#ifndef cmCTestResourceGroups_yyget_text_ALREADY_DEFINED
+#undef yyget_text
+#endif
+#ifndef cmCTestResourceGroups_yyget_lineno_ALREADY_DEFINED
+#undef yyget_lineno
+#endif
+#ifndef cmCTestResourceGroups_yyset_lineno_ALREADY_DEFINED
+#undef yyset_lineno
+#endif
+#ifndef cmCTestResourceGroups_yyget_column_ALREADY_DEFINED
+#undef yyget_column
+#endif
+#ifndef cmCTestResourceGroups_yyset_column_ALREADY_DEFINED
+#undef yyset_column
+#endif
+#ifndef cmCTestResourceGroups_yywrap_ALREADY_DEFINED
+#undef yywrap
+#endif
+#ifndef cmCTestResourceGroups_yyget_lval_ALREADY_DEFINED
+#undef yyget_lval
+#endif
+#ifndef cmCTestResourceGroups_yyset_lval_ALREADY_DEFINED
+#undef yyset_lval
+#endif
+#ifndef cmCTestResourceGroups_yyget_lloc_ALREADY_DEFINED
+#undef yyget_lloc
+#endif
+#ifndef cmCTestResourceGroups_yyset_lloc_ALREADY_DEFINED
+#undef yyset_lloc
+#endif
+#ifndef cmCTestResourceGroups_yyalloc_ALREADY_DEFINED
+#undef yyalloc
+#endif
+#ifndef cmCTestResourceGroups_yyrealloc_ALREADY_DEFINED
+#undef yyrealloc
+#endif
+#ifndef cmCTestResourceGroups_yyfree_ALREADY_DEFINED
+#undef yyfree
+#endif
+#ifndef cmCTestResourceGroups_yytext_ALREADY_DEFINED
+#undef yytext
+#endif
+#ifndef cmCTestResourceGroups_yyleng_ALREADY_DEFINED
+#undef yyleng
+#endif
+#ifndef cmCTestResourceGroups_yyin_ALREADY_DEFINED
+#undef yyin
+#endif
+#ifndef cmCTestResourceGroups_yyout_ALREADY_DEFINED
+#undef yyout
+#endif
+#ifndef cmCTestResourceGroups_yy_flex_debug_ALREADY_DEFINED
+#undef yy_flex_debug
+#endif
+#ifndef cmCTestResourceGroups_yylineno_ALREADY_DEFINED
+#undef yylineno
+#endif
+#ifndef cmCTestResourceGroups_yytables_fload_ALREADY_DEFINED
+#undef yytables_fload
+#endif
+#ifndef cmCTestResourceGroups_yytables_destroy_ALREADY_DEFINED
+#undef yytables_destroy
+#endif
+#ifndef cmCTestResourceGroups_yyTABLES_NAME_ALREADY_DEFINED
+#undef yyTABLES_NAME
+#endif
+
+#undef cmCTestResourceGroups_yyIN_HEADER
+#endif /* cmCTestResourceGroups_yyHEADER_H */
diff --git a/Source/LexerParser/cmCTestResourceGroupsLexer.in.l b/Source/LexerParser/cmCTestResourceGroupsLexer.in.l
new file mode 100644
index 0000000..2aabea4
--- /dev/null
+++ b/Source/LexerParser/cmCTestResourceGroupsLexer.in.l
@@ -0,0 +1,102 @@
+%{
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C++ and modified to build everywhere.
+
+Run flex >= 2.6 like this:
+
+ flex --nounistd -DFLEXINT_H --noline --header-file=cmCTestResourceGroupsLexer.h -ocmCTestResourceGroupsLexer.cxx cmCTestResourceGroupsLexer.in.l
+
+Modify cmCTestResourceGroupsLexer.cxx:
+ - remove trailing whitespace: sed -i 's/\s*$//' cmCTestResourceGroupsLexer.h cmCTestResourceGroupsLexer.cxx
+ - remove blank lines at end of file: sed -i '${/^$/d;}' cmCTestResourceGroupsLexer.h cmCTestResourceGroupsLexer.cxx
+ - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmCTestResourceGroupsLexer.cxx
+
+*/
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
+
+#include "cmCTestResourceGroupsLexerHelper.h"
+
+#include <string>
+
+#include <cstddef>
+
+/*--------------------------------------------------------------------------*/
+%}
+
+%option prefix="cmCTestResourceGroups_yy"
+
+%option reentrant
+%option noyywrap
+%option nodefault
+%pointer
+
+%s RESOURCE_GROUPS_START
+%s RESOURCE_GROUPS_END
+%s RESOURCE_START
+%s RESOURCE_COUNT
+%s RESOURCE_END
+
+NUMBER [0-9]+
+IDENTIFIER [a-z_][a-z0-9_]*
+
+%%
+
+<INITIAL,RESOURCE_GROUPS_START,RESOURCE_START>{IDENTIFIER}: {
+ BEGIN(RESOURCE_COUNT);
+ yyextra->SetResourceType(std::string(yytext, yyleng - 1));
+}
+
+<INITIAL,RESOURCE_GROUPS_START>{NUMBER} {
+ BEGIN(RESOURCE_GROUPS_END);
+ std::size_t len = yyleng;
+ yyextra->SetProcessCount(std::stoll(yytext, &len, 10));
+}
+
+<RESOURCE_COUNT>{NUMBER} {
+ BEGIN(RESOURCE_END);
+ std::size_t len = yyleng;
+ yyextra->SetNeededSlots(std::stoll(yytext, &len, 10));
+ yyextra->WriteRequirement();
+}
+
+<RESOURCE_GROUPS_END,RESOURCE_END>,+ {
+ BEGIN(RESOURCE_START);
+}
+
+<INITIAL,RESOURCE_GROUPS_START,RESOURCE_START>;+ {
+ BEGIN(RESOURCE_GROUPS_START);
+}
+
+<RESOURCE_GROUPS_END,RESOURCE_END>;+ {
+ BEGIN(RESOURCE_GROUPS_START);
+ yyextra->WriteProcess();
+}
+
+<RESOURCE_START,RESOURCE_GROUPS_END,RESOURCE_END><<EOF>> {
+ yyextra->WriteProcess();
+ return 0;
+}
+
+<INITIAL,RESOURCE_GROUPS_START><<EOF>> {
+ return 0;
+}
+
+<<EOF>> {
+ return 1;
+}
+
+.|\n {
+ return 1;
+}
+
+%%
+
+/*--------------------------------------------------------------------------*/
+
+#endif /* __clang_analyzer__ */
diff --git a/Source/LexerParser/cmCommandArgumentLexer.cxx b/Source/LexerParser/cmCommandArgumentLexer.cxx
new file mode 100644
index 0000000..46220ff
--- /dev/null
+++ b/Source/LexerParser/cmCommandArgumentLexer.cxx
@@ -0,0 +1,2246 @@
+#include "cmStandardLexer.h"
+
+#define FLEXINT_H 1
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmCommandArgument_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmCommandArgument_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmCommandArgument_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmCommandArgument_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmCommandArgument_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmCommandArgument_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmCommandArgument_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmCommandArgument_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmCommandArgument_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmCommandArgument_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmCommandArgument_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmCommandArgument_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmCommandArgument_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmCommandArgument_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmCommandArgument_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmCommandArgument_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmCommandArgument_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmCommandArgument_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmCommandArgument_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmCommandArgument_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmCommandArgument_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmCommandArgument_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmCommandArgument_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmCommandArgument_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmCommandArgument_yylex_ALREADY_DEFINED
+#else
+#define yylex cmCommandArgument_yylex
+#endif
+
+#ifdef yyrestart
+#define cmCommandArgument_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmCommandArgument_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmCommandArgument_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmCommandArgument_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmCommandArgument_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmCommandArgument_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmCommandArgument_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmCommandArgument_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmCommandArgument_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmCommandArgument_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmCommandArgument_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmCommandArgument_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmCommandArgument_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmCommandArgument_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmCommandArgument_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmCommandArgument_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmCommandArgument_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmCommandArgument_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmCommandArgument_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmCommandArgument_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmCommandArgument_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmCommandArgument_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmCommandArgument_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmCommandArgument_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmCommandArgument_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmCommandArgument_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmCommandArgument_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmCommandArgument_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmCommandArgument_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmCommandArgument_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmCommandArgument_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmCommandArgument_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmCommandArgument_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmCommandArgument_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmCommandArgument_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmCommandArgument_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmCommandArgument_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmCommandArgument_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmCommandArgument_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmCommandArgument_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmCommandArgument_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmCommandArgument_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmCommandArgument_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmCommandArgument_yyfree
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an
+ * integer in range [0..255] for use as an array index.
+ */
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin , yyscanner )
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+ #define YY_LINENO_REWIND_TO(ptr)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+static void yyensure_buffer_stack ( yyscan_t yyscanner );
+static void yy_load_buffer_state ( yyscan_t yyscanner );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner)
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+#define yy_new_buffer yy_create_buffer
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define cmCommandArgument_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+typedef flex_uint8_t YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner);
+static int yy_get_next_buffer ( yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+#define YY_NUM_RULES 14
+#define YY_END_OF_BUFFER 15
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static const flex_int16_t yy_accept[30] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 15, 9, 10, 7,
+ 6, 14, 11, 5, 12, 13, 9, 0, 0, 4,
+ 7, 0, 8, 2, 0, 3, 0, 1, 0
+ } ;
+
+static const YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 3, 1, 1, 1, 1,
+ 1, 1, 4, 1, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 1, 1, 1,
+ 1, 1, 1, 5, 4, 4, 4, 4, 6, 4,
+ 4, 4, 4, 4, 4, 4, 4, 7, 4, 4,
+ 4, 4, 4, 4, 4, 8, 4, 4, 4, 4,
+ 1, 9, 1, 1, 4, 1, 4, 4, 4, 4,
+
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 10, 1, 11, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static const YY_CHAR yy_meta[12] =
+ { 0,
+ 1, 2, 3, 4, 3, 4, 4, 4, 3, 5,
+ 3
+ } ;
+
+static const flex_int16_t yy_base[35] =
+ { 0,
+ 0, 0, 31, 30, 29, 28, 36, 0, 6, 16,
+ 0, 41, 41, 41, 0, 41, 0, 22, 22, 41,
+ 18, 18, 41, 41, 7, 41, 4, 41, 41, 20,
+ 21, 26, 9, 30
+ } ;
+
+static const flex_int16_t yy_def[35] =
+ { 0,
+ 29, 1, 1, 1, 1, 1, 29, 30, 31, 32,
+ 33, 29, 29, 29, 34, 29, 30, 31, 18, 29,
+ 32, 33, 29, 29, 18, 29, 18, 29, 0, 29,
+ 29, 29, 29, 29
+ } ;
+
+static const flex_int16_t yy_nxt[53] =
+ { 0,
+ 8, 8, 9, 10, 11, 10, 10, 10, 12, 13,
+ 14, 19, 22, 28, 27, 20, 17, 17, 17, 17,
+ 17, 17, 26, 17, 18, 18, 21, 21, 25, 21,
+ 23, 24, 23, 23, 23, 29, 16, 16, 15, 15,
+ 7, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29
+ } ;
+
+static const flex_int16_t yy_chk[53] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 9, 33, 27, 25, 9, 10, 10, 21, 21,
+ 30, 30, 22, 30, 31, 31, 32, 32, 19, 32,
+ 34, 18, 34, 34, 34, 7, 6, 5, 4, 3,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29
+ } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C++ and modified to build everywhere.
+
+Run flex >= 2.6 like this:
+
+ flex --nounistd --never-interactive --batch -DFLEXINT_H --noline --header-file=cmCommandArgumentLexer.h -ocmCommandArgumentLexer.cxx cmCommandArgumentLexer.in.l
+
+Modify cmCommandArgumentLexer.cxx:
+ - remove trailing whitespace: sed -i 's/\s*$//' cmCommandArgumentLexer.h cmCommandArgumentLexer.cxx
+ - remove blank lines at end of file: sed -i '${/^$/d;}' cmCommandArgumentLexer.h cmCommandArgumentLexer.cxx
+ - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmCommandArgumentLexer.cxx
+
+*/
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
+
+#include "cmCommandArgumentParserHelper.h"
+
+#define YY_USER_ACTION yyextra->UpdateInputPosition(yyleng);
+
+/* Include the set of tokens from the parser. */
+#include "cmCommandArgumentParserTokens.h"
+
+static const char *DCURLYVariable = "${";
+static const char *RCURLYVariable = "}";
+static const char *ATVariable = "@";
+static const char *DOLLARVariable = "$";
+static const char *LCURLYVariable = "{";
+static const char *BSLASHVariable = "\\";
+
+/*--------------------------------------------------------------------------*/
+
+#define INITIAL 0
+#define ESCAPES 1
+#define NOESCAPES 2
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals ( yyscan_t yyscanner );
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput ( yyscan_t yyscanner );
+#else
+static int input ( yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ int n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK /*LINTED*/break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_load_buffer_state( yyscanner );
+ }
+
+ {
+
+ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 30 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ ++yy_cp;
+ }
+ while ( yy_current_state != 29 );
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext+1, strlen(yytext)-2);
+ return cal_ENVCURLY;
+}
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext+1, strlen(yytext)-2);
+ return cal_NCURLY;
+}
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext+1, strlen(yytext)-2);
+ return cal_ATNAME;
+}
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = DCURLYVariable;
+ return cal_DCURLY;
+}
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = RCURLYVariable;
+ return cal_RCURLY;
+}
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = ATVariable;
+ return cal_AT;
+}
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ return cal_NAME;
+}
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+{
+ if ( !yyextra->HandleEscapeSymbol(yylvalp, *(yytext+1)) )
+ {
+ return cal_ERROR;
+ }
+ return cal_SYMBOL;
+}
+ YY_BREAK
+case 9:
+/* rule 9 can match eol */
+YY_RULE_SETUP
+{
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ return cal_SYMBOL;
+}
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+{
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = DOLLARVariable;
+ return cal_DOLLAR;
+}
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+{
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = LCURLYVariable;
+ return cal_LCURLY;
+}
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+{
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = BSLASHVariable;
+ return cal_BSLASH;
+}
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+{
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = BSLASHVariable;
+ return cal_SYMBOL;
+}
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+ECHO;
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(ESCAPES):
+case YY_STATE_EOF(NOESCAPES):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap( yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of user's declarations */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc( (void *) b->yy_ch_buf,
+ (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = NULL;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin , yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+ (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ /* "- 2" to take care of EOB's */
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 30 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ char *yy_cp = yyg->yy_c_buf_p;
+
+ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 30 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_is_jam = (yy_current_state == 29);
+
+ (void)yyg;
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin , yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( yyscanner ) )
+ return 0;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner);
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file , yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree( (void *) b->yy_ch_buf , yyscanner );
+
+ yyfree( (void *) b , yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_flush_buffer( b , yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return NULL;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = NULL;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b , yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner)
+{
+
+ return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = (yy_size_t) (_yybytes_len + 2);
+ buf = (char *) yyalloc( n , yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n , yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param _line_number line number
+ * @param yyscanner The scanner object.
+ */
+void yyset_lineno (int _line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
+
+ yylineno = _line_number;
+}
+
+/** Set the current column.
+ * @param _column_no column number
+ * @param yyscanner The scanner object.
+ */
+void yyset_column (int _column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_column called with no buffer" );
+
+ yycolumn = _column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param _in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * _in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = _in_str ;
+}
+
+void yyset_out (FILE * _out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = _out_str ;
+}
+
+int yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void yyset_debug (int _bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = _bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+/* User-visible API */
+
+/* yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+int yylex_init(yyscan_t* ptr_yy_globals)
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to yyalloc in
+ * the yyextra field.
+ */
+int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals )
+{
+ struct yyguts_t dummy_yyguts;
+
+ yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = NULL;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = NULL;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = NULL;
+ yyout = NULL;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ yyfree(yyg->yy_buffer_stack , yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ yyfree( yyg->yy_start_stack , yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ yyfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
+{
+ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ return malloc(size);
+}
+
+void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return realloc(ptr, size);
+}
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+/*--------------------------------------------------------------------------*/
+void cmCommandArgument_SetupEscapes(yyscan_t yyscanner, bool noEscapes)
+{
+ /* Hack into the internal flex-generated scanner to set the state. */
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if(noEscapes) {
+ BEGIN(NOESCAPES);
+ } else {
+ BEGIN(ESCAPES);
+ }
+}
+
+#endif /* __clang_analyzer__ */
diff --git a/Source/LexerParser/cmCommandArgumentLexer.h b/Source/LexerParser/cmCommandArgumentLexer.h
new file mode 100644
index 0000000..5677513
--- /dev/null
+++ b/Source/LexerParser/cmCommandArgumentLexer.h
@@ -0,0 +1,689 @@
+#ifndef cmCommandArgument_yyHEADER_H
+#define cmCommandArgument_yyHEADER_H 1
+#define cmCommandArgument_yyIN_HEADER 1
+
+#define FLEXINT_H 1
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmCommandArgument_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmCommandArgument_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmCommandArgument_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmCommandArgument_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmCommandArgument_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmCommandArgument_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmCommandArgument_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmCommandArgument_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmCommandArgument_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmCommandArgument_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmCommandArgument_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmCommandArgument_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmCommandArgument_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmCommandArgument_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmCommandArgument_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmCommandArgument_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmCommandArgument_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmCommandArgument_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmCommandArgument_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmCommandArgument_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmCommandArgument_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmCommandArgument_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmCommandArgument_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmCommandArgument_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmCommandArgument_yylex_ALREADY_DEFINED
+#else
+#define yylex cmCommandArgument_yylex
+#endif
+
+#ifdef yyrestart
+#define cmCommandArgument_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmCommandArgument_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmCommandArgument_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmCommandArgument_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmCommandArgument_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmCommandArgument_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmCommandArgument_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmCommandArgument_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmCommandArgument_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmCommandArgument_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmCommandArgument_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmCommandArgument_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmCommandArgument_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmCommandArgument_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmCommandArgument_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmCommandArgument_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmCommandArgument_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmCommandArgument_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmCommandArgument_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmCommandArgument_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmCommandArgument_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmCommandArgument_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmCommandArgument_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmCommandArgument_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmCommandArgument_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmCommandArgument_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmCommandArgument_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmCommandArgument_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmCommandArgument_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmCommandArgument_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmCommandArgument_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmCommandArgument_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmCommandArgument_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmCommandArgument_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmCommandArgument_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmCommandArgument_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmCommandArgument_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmCommandArgument_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmCommandArgument_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmCommandArgument_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmCommandArgument_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmCommandArgument_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmCommandArgument_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmCommandArgument_yyfree
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+/* Begin user sect3 */
+
+#define cmCommandArgument_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+#define ESCAPES 1
+#define NOESCAPES 2
+
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#ifndef cmCommandArgument_yy_create_buffer_ALREADY_DEFINED
+#undef yy_create_buffer
+#endif
+#ifndef cmCommandArgument_yy_delete_buffer_ALREADY_DEFINED
+#undef yy_delete_buffer
+#endif
+#ifndef cmCommandArgument_yy_scan_buffer_ALREADY_DEFINED
+#undef yy_scan_buffer
+#endif
+#ifndef cmCommandArgument_yy_scan_string_ALREADY_DEFINED
+#undef yy_scan_string
+#endif
+#ifndef cmCommandArgument_yy_scan_bytes_ALREADY_DEFINED
+#undef yy_scan_bytes
+#endif
+#ifndef cmCommandArgument_yy_init_buffer_ALREADY_DEFINED
+#undef yy_init_buffer
+#endif
+#ifndef cmCommandArgument_yy_flush_buffer_ALREADY_DEFINED
+#undef yy_flush_buffer
+#endif
+#ifndef cmCommandArgument_yy_load_buffer_state_ALREADY_DEFINED
+#undef yy_load_buffer_state
+#endif
+#ifndef cmCommandArgument_yy_switch_to_buffer_ALREADY_DEFINED
+#undef yy_switch_to_buffer
+#endif
+#ifndef cmCommandArgument_yypush_buffer_state_ALREADY_DEFINED
+#undef yypush_buffer_state
+#endif
+#ifndef cmCommandArgument_yypop_buffer_state_ALREADY_DEFINED
+#undef yypop_buffer_state
+#endif
+#ifndef cmCommandArgument_yyensure_buffer_stack_ALREADY_DEFINED
+#undef yyensure_buffer_stack
+#endif
+#ifndef cmCommandArgument_yylex_ALREADY_DEFINED
+#undef yylex
+#endif
+#ifndef cmCommandArgument_yyrestart_ALREADY_DEFINED
+#undef yyrestart
+#endif
+#ifndef cmCommandArgument_yylex_init_ALREADY_DEFINED
+#undef yylex_init
+#endif
+#ifndef cmCommandArgument_yylex_init_extra_ALREADY_DEFINED
+#undef yylex_init_extra
+#endif
+#ifndef cmCommandArgument_yylex_destroy_ALREADY_DEFINED
+#undef yylex_destroy
+#endif
+#ifndef cmCommandArgument_yyget_debug_ALREADY_DEFINED
+#undef yyget_debug
+#endif
+#ifndef cmCommandArgument_yyset_debug_ALREADY_DEFINED
+#undef yyset_debug
+#endif
+#ifndef cmCommandArgument_yyget_extra_ALREADY_DEFINED
+#undef yyget_extra
+#endif
+#ifndef cmCommandArgument_yyset_extra_ALREADY_DEFINED
+#undef yyset_extra
+#endif
+#ifndef cmCommandArgument_yyget_in_ALREADY_DEFINED
+#undef yyget_in
+#endif
+#ifndef cmCommandArgument_yyset_in_ALREADY_DEFINED
+#undef yyset_in
+#endif
+#ifndef cmCommandArgument_yyget_out_ALREADY_DEFINED
+#undef yyget_out
+#endif
+#ifndef cmCommandArgument_yyset_out_ALREADY_DEFINED
+#undef yyset_out
+#endif
+#ifndef cmCommandArgument_yyget_leng_ALREADY_DEFINED
+#undef yyget_leng
+#endif
+#ifndef cmCommandArgument_yyget_text_ALREADY_DEFINED
+#undef yyget_text
+#endif
+#ifndef cmCommandArgument_yyget_lineno_ALREADY_DEFINED
+#undef yyget_lineno
+#endif
+#ifndef cmCommandArgument_yyset_lineno_ALREADY_DEFINED
+#undef yyset_lineno
+#endif
+#ifndef cmCommandArgument_yyget_column_ALREADY_DEFINED
+#undef yyget_column
+#endif
+#ifndef cmCommandArgument_yyset_column_ALREADY_DEFINED
+#undef yyset_column
+#endif
+#ifndef cmCommandArgument_yywrap_ALREADY_DEFINED
+#undef yywrap
+#endif
+#ifndef cmCommandArgument_yyget_lval_ALREADY_DEFINED
+#undef yyget_lval
+#endif
+#ifndef cmCommandArgument_yyset_lval_ALREADY_DEFINED
+#undef yyset_lval
+#endif
+#ifndef cmCommandArgument_yyget_lloc_ALREADY_DEFINED
+#undef yyget_lloc
+#endif
+#ifndef cmCommandArgument_yyset_lloc_ALREADY_DEFINED
+#undef yyset_lloc
+#endif
+#ifndef cmCommandArgument_yyalloc_ALREADY_DEFINED
+#undef yyalloc
+#endif
+#ifndef cmCommandArgument_yyrealloc_ALREADY_DEFINED
+#undef yyrealloc
+#endif
+#ifndef cmCommandArgument_yyfree_ALREADY_DEFINED
+#undef yyfree
+#endif
+#ifndef cmCommandArgument_yytext_ALREADY_DEFINED
+#undef yytext
+#endif
+#ifndef cmCommandArgument_yyleng_ALREADY_DEFINED
+#undef yyleng
+#endif
+#ifndef cmCommandArgument_yyin_ALREADY_DEFINED
+#undef yyin
+#endif
+#ifndef cmCommandArgument_yyout_ALREADY_DEFINED
+#undef yyout
+#endif
+#ifndef cmCommandArgument_yy_flex_debug_ALREADY_DEFINED
+#undef yy_flex_debug
+#endif
+#ifndef cmCommandArgument_yylineno_ALREADY_DEFINED
+#undef yylineno
+#endif
+#ifndef cmCommandArgument_yytables_fload_ALREADY_DEFINED
+#undef yytables_fload
+#endif
+#ifndef cmCommandArgument_yytables_destroy_ALREADY_DEFINED
+#undef yytables_destroy
+#endif
+#ifndef cmCommandArgument_yyTABLES_NAME_ALREADY_DEFINED
+#undef yyTABLES_NAME
+#endif
+
+#undef cmCommandArgument_yyIN_HEADER
+#endif /* cmCommandArgument_yyHEADER_H */
diff --git a/Source/LexerParser/cmCommandArgumentLexer.in.l b/Source/LexerParser/cmCommandArgumentLexer.in.l
new file mode 100644
index 0000000..8ad2335
--- /dev/null
+++ b/Source/LexerParser/cmCommandArgumentLexer.in.l
@@ -0,0 +1,148 @@
+%{
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C++ and modified to build everywhere.
+
+Run flex >= 2.6 like this:
+
+ flex --nounistd --never-interactive --batch -DFLEXINT_H --noline --header-file=cmCommandArgumentLexer.h -ocmCommandArgumentLexer.cxx cmCommandArgumentLexer.in.l
+
+Modify cmCommandArgumentLexer.cxx:
+ - remove trailing whitespace: sed -i 's/\s*$//' cmCommandArgumentLexer.h cmCommandArgumentLexer.cxx
+ - remove blank lines at end of file: sed -i '${/^$/d;}' cmCommandArgumentLexer.h cmCommandArgumentLexer.cxx
+ - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmCommandArgumentLexer.cxx
+
+*/
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
+
+#include "cmCommandArgumentParserHelper.h"
+
+#define YY_USER_ACTION yyextra->UpdateInputPosition(yyleng);
+
+/* Include the set of tokens from the parser. */
+#include "cmCommandArgumentParserTokens.h"
+
+static const char *DCURLYVariable = "${";
+static const char *RCURLYVariable = "}";
+static const char *ATVariable = "@";
+static const char *DOLLARVariable = "$";
+static const char *LCURLYVariable = "{";
+static const char *BSLASHVariable = "\\";
+
+/*--------------------------------------------------------------------------*/
+%}
+
+%option prefix="cmCommandArgument_yy"
+
+%option reentrant
+%option noyywrap
+%option nounput
+%pointer
+%s ESCAPES
+%s NOESCAPES
+
+%%
+
+\$ENV\{ {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext+1, strlen(yytext)-2);
+ return cal_ENVCURLY;
+}
+
+\$[A-Za-z0-9/_.+-]+\{ {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext+1, strlen(yytext)-2);
+ return cal_NCURLY;
+}
+
+@[A-Za-z0-9/_.+-]+@ {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext+1, strlen(yytext)-2);
+ return cal_ATNAME;
+}
+
+"${" {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = DCURLYVariable;
+ return cal_DCURLY;
+}
+
+"}" {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = RCURLYVariable;
+ return cal_RCURLY;
+}
+
+"@" {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = ATVariable;
+ return cal_AT;
+}
+
+[A-Za-z0-9/_.+-]+ {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ return cal_NAME;
+}
+
+<ESCAPES>\\. {
+ if ( !yyextra->HandleEscapeSymbol(yylvalp, *(yytext+1)) )
+ {
+ return cal_ERROR;
+ }
+ return cal_SYMBOL;
+}
+
+[^\${}\\@]+ {
+ //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl;
+ yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ return cal_SYMBOL;
+}
+
+"$" {
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = DOLLARVariable;
+ return cal_DOLLAR;
+}
+
+"{" {
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = LCURLYVariable;
+ return cal_LCURLY;
+}
+
+<ESCAPES>"\\" {
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = BSLASHVariable;
+ return cal_BSLASH;
+}
+
+<NOESCAPES>"\\" {
+ //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ yylvalp->str = BSLASHVariable;
+ return cal_SYMBOL;
+}
+
+%%
+
+/*--------------------------------------------------------------------------*/
+void cmCommandArgument_SetupEscapes(yyscan_t yyscanner, bool noEscapes)
+{
+ /* Hack into the internal flex-generated scanner to set the state. */
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if(noEscapes) {
+ BEGIN(NOESCAPES);
+ } else {
+ BEGIN(ESCAPES);
+ }
+}
+
+#endif /* __clang_analyzer__ */
diff --git a/Source/LexerParser/cmCommandArgumentParser.cxx b/Source/LexerParser/cmCommandArgumentParser.cxx
new file mode 100644
index 0000000..b8bc82c
--- /dev/null
+++ b/Source/LexerParser/cmCommandArgumentParser.cxx
@@ -0,0 +1,1849 @@
+/* A Bison parser, made by GNU Bison 3.7.4. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
+ Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+ especially those whose name start with YY_ or yy_. They are
+ private implementation details that can be changed or removed. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output, and Bison version. */
+#define YYBISON 30704
+
+/* Bison version string. */
+#define YYBISON_VERSION "3.7.4"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+/* Substitute the variable and function names. */
+#define yyparse cmCommandArgument_yyparse
+#define yylex cmCommandArgument_yylex
+#define yyerror cmCommandArgument_yyerror
+#define yydebug cmCommandArgument_yydebug
+#define yynerrs cmCommandArgument_yynerrs
+
+/* First part of user prologue. */
+#line 1 "cmCommandArgumentParser.y"
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --name-prefix=cmCommandArgument_yy --defines=cmCommandArgumentParserTokens.h -ocmCommandArgumentParser.cxx cmCommandArgumentParser.y
+
+*/
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string.h>
+
+#define yyGetParser (cmCommandArgument_yyget_extra(yyscanner))
+
+/* Make sure malloc and free are available on QNX. */
+#ifdef __QNX__
+# include <malloc.h>
+#endif
+
+#include <stdint.h>
+/* Make sure the parser uses standard memory allocation. The default
+ generated parser malloc/free declarations do not work on all
+ platforms. */
+#include <stdlib.h>
+#define YYMALLOC malloc
+#define YYFREE free
+
+/*-------------------------------------------------------------------------*/
+#include "cmCommandArgumentParserHelper.h" /* Interface to parser object. */
+#include "cmCommandArgumentLexer.h" /* Interface to lexer object. */
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Helper function to forward error callback from parser. */
+static void cmCommandArgument_yyerror(yyscan_t yyscanner, const char* message);
+
+/* Configure the parser to support large input. */
+#define YYMAXDEPTH 100000
+#define YYINITDEPTH 10000
+
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch statement contains default but no
+ case. */
+# pragma warning (disable: 4244) /* loss of precision */
+# pragma warning (disable: 4702) /* unreachable code */
+#endif
+#if defined(__GNUC__) && __GNUC__ >= 8
+# pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+#endif
+
+#line 136 "cmCommandArgumentParser.cxx"
+
+# ifndef YY_CAST
+# ifdef __cplusplus
+# define YY_CAST(Type, Val) static_cast<Type> (Val)
+# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+# else
+# define YY_CAST(Type, Val) ((Type) (Val))
+# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+# endif
+# endif
+# ifndef YY_NULLPTR
+# if defined __cplusplus
+# if 201103L <= __cplusplus
+# define YY_NULLPTR nullptr
+# else
+# define YY_NULLPTR 0
+# endif
+# else
+# define YY_NULLPTR ((void*)0)
+# endif
+# endif
+
+#include "cmCommandArgumentParserTokens.h"
+/* Symbol kind. */
+enum yysymbol_kind_t
+{
+ YYSYMBOL_YYEMPTY = -2,
+ YYSYMBOL_YYEOF = 0, /* "end of file" */
+ YYSYMBOL_YYerror = 1, /* error */
+ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */
+ YYSYMBOL_cal_ENVCURLY = 3, /* cal_ENVCURLY */
+ YYSYMBOL_cal_NCURLY = 4, /* cal_NCURLY */
+ YYSYMBOL_cal_DCURLY = 5, /* cal_DCURLY */
+ YYSYMBOL_cal_DOLLAR = 6, /* "$" */
+ YYSYMBOL_cal_LCURLY = 7, /* "{" */
+ YYSYMBOL_cal_RCURLY = 8, /* "}" */
+ YYSYMBOL_cal_NAME = 9, /* cal_NAME */
+ YYSYMBOL_cal_BSLASH = 10, /* "\\" */
+ YYSYMBOL_cal_SYMBOL = 11, /* cal_SYMBOL */
+ YYSYMBOL_cal_AT = 12, /* "@" */
+ YYSYMBOL_cal_ERROR = 13, /* cal_ERROR */
+ YYSYMBOL_cal_ATNAME = 14, /* cal_ATNAME */
+ YYSYMBOL_YYACCEPT = 15, /* $accept */
+ YYSYMBOL_Start = 16, /* Start */
+ YYSYMBOL_GoalWithOptionalBackSlash = 17, /* GoalWithOptionalBackSlash */
+ YYSYMBOL_Goal = 18, /* Goal */
+ YYSYMBOL_String = 19, /* String */
+ YYSYMBOL_OuterText = 20, /* OuterText */
+ YYSYMBOL_Variable = 21, /* Variable */
+ YYSYMBOL_EnvVarName = 22, /* EnvVarName */
+ YYSYMBOL_MultipleIds = 23, /* MultipleIds */
+ YYSYMBOL_ID = 24 /* ID */
+};
+typedef enum yysymbol_kind_t yysymbol_kind_t;
+
+
+
+
+#ifdef short
+# undef short
+#endif
+
+/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
+ <limits.h> and (if available) <stdint.h> are included
+ so that the code can choose integer types of a good width. */
+
+#ifndef __PTRDIFF_MAX__
+# include <limits.h> /* INFRINGES ON USER NAME SPACE */
+# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+# include <stdint.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_STDINT_H
+# endif
+#endif
+
+/* Narrow types that promote to a signed type and that can represent a
+ signed or unsigned integer of at least N bits. In tables they can
+ save space and decrease cache pressure. Promoting to a signed type
+ helps avoid bugs in integer arithmetic. */
+
+#ifdef __INT_LEAST8_MAX__
+typedef __INT_LEAST8_TYPE__ yytype_int8;
+#elif defined YY_STDINT_H
+typedef int_least8_t yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef __INT_LEAST16_MAX__
+typedef __INT_LEAST16_TYPE__ yytype_int16;
+#elif defined YY_STDINT_H
+typedef int_least16_t yytype_int16;
+#else
+typedef short yytype_int16;
+#endif
+
+#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST8_TYPE__ yytype_uint8;
+#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
+ && UINT_LEAST8_MAX <= INT_MAX)
+typedef uint_least8_t yytype_uint8;
+#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
+typedef unsigned char yytype_uint8;
+#else
+typedef short yytype_uint8;
+#endif
+
+#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST16_TYPE__ yytype_uint16;
+#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
+ && UINT_LEAST16_MAX <= INT_MAX)
+typedef uint_least16_t yytype_uint16;
+#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
+typedef unsigned short yytype_uint16;
+#else
+typedef int yytype_uint16;
+#endif
+
+#ifndef YYPTRDIFF_T
+# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
+# define YYPTRDIFF_T __PTRDIFF_TYPE__
+# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
+# elif defined PTRDIFF_MAX
+# ifndef ptrdiff_t
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# endif
+# define YYPTRDIFF_T ptrdiff_t
+# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
+# else
+# define YYPTRDIFF_T long
+# define YYPTRDIFF_MAXIMUM LONG_MAX
+# endif
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM \
+ YY_CAST (YYPTRDIFF_T, \
+ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \
+ ? YYPTRDIFF_MAXIMUM \
+ : YY_CAST (YYSIZE_T, -1)))
+
+#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
+
+
+/* Stored state numbers (used for stacks). */
+typedef yytype_int8 yy_state_t;
+
+/* State numbers in computations. */
+typedef int yy_state_fast_t;
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+
+#ifndef YY_ATTRIBUTE_PURE
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+# define YY_ATTRIBUTE_PURE
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+# define YY_ATTRIBUTE_UNUSED
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END \
+ _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
+
+#define YY_ASSERT(E) ((void) (0 && (E)))
+
+#if 1
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's 'empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* 1 */
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yy_state_t yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYPTRDIFF_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / YYSIZEOF (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYPTRDIFF_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 25
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 40
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 15
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 10
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 24
+/* YYNSTATES -- Number of states. */
+#define YYNSTATES 33
+
+/* YYMAXUTOK -- Last valid token kind. */
+#define YYMAXUTOK 269
+
+
+/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex, with out-of-bounds checking. */
+#define YYTRANSLATE(YYX) \
+ (0 <= (YYX) && (YYX) <= YYMAXUTOK \
+ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \
+ : YYSYMBOL_YYUNDEF)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex. */
+static const yytype_int8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+};
+
+#if YYDEBUG
+ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+static const yytype_uint8 yyrline[] =
+{
+ 0, 97, 97, 103, 106, 111, 114, 119, 122, 127,
+ 130, 133, 136, 139, 142, 147, 150, 153, 156, 161,
+ 164, 169, 172, 177, 180
+};
+#endif
+
+/** Accessing symbol of state STATE. */
+#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
+
+#if 1
+/* The user-facing name of the symbol whose (internal) number is
+ YYSYMBOL. No bounds checking. */
+static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
+
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "\"end of file\"", "error", "\"invalid token\"", "cal_ENVCURLY",
+ "cal_NCURLY", "cal_DCURLY", "\"$\"", "\"{\"", "\"}\"", "cal_NAME",
+ "\"\\\\\"", "cal_SYMBOL", "\"@\"", "cal_ERROR", "cal_ATNAME", "$accept",
+ "Start", "GoalWithOptionalBackSlash", "Goal", "String", "OuterText",
+ "Variable", "EnvVarName", "MultipleIds", "ID", YY_NULLPTR
+};
+
+static const char *
+yysymbol_name (yysymbol_kind_t yysymbol)
+{
+ return yytname[yysymbol];
+}
+#endif
+
+#ifdef YYPRINT
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+ (internal) symbol number NUM (which must be that of a token). */
+static const yytype_int16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269
+};
+#endif
+
+#define YYPACT_NINF (-3)
+
+#define yypact_value_is_default(Yyn) \
+ ((Yyn) == YYPACT_NINF)
+
+#define YYTABLE_NINF (-1)
+
+#define yytable_value_is_error(Yyn) \
+ 0
+
+ /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+static const yytype_int8 yypact[] =
+{
+ 0, 14, 26, 26, -3, -3, -3, -3, -3, -3,
+ -3, 10, -3, 3, 0, -3, -3, -3, 14, -3,
+ 7, -3, 26, 13, 16, -3, -3, -3, -3, -3,
+ -3, -3, -3
+};
+
+ /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE does not specify something else to do. Zero
+ means the default is an error. */
+static const yytype_int8 yydefact[] =
+{
+ 5, 21, 21, 21, 11, 12, 13, 9, 14, 10,
+ 18, 0, 2, 3, 5, 7, 8, 23, 21, 24,
+ 0, 19, 21, 0, 0, 1, 4, 6, 20, 15,
+ 22, 16, 17
+};
+
+ /* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -3, -3, -3, 8, -3, -3, 2, 9, -2, -3
+};
+
+ /* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 11, 12, 13, 14, 15, 19, 20, 21, 22
+};
+
+ /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule whose
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+static const yytype_int8 yytable[] =
+{
+ 23, 24, 16, 1, 2, 3, 4, 5, 6, 7,
+ 25, 8, 9, 26, 10, 29, 16, 1, 2, 3,
+ 30, 31, 27, 17, 32, 18, 0, 28, 10, 1,
+ 2, 3, 0, 0, 0, 17, 0, 0, 0, 0,
+ 10
+};
+
+static const yytype_int8 yycheck[] =
+{
+ 2, 3, 0, 3, 4, 5, 6, 7, 8, 9,
+ 0, 11, 12, 10, 14, 8, 14, 3, 4, 5,
+ 22, 8, 14, 9, 8, 11, -1, 18, 14, 3,
+ 4, 5, -1, -1, -1, 9, -1, -1, -1, -1,
+ 14
+};
+
+ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_int8 yystos[] =
+{
+ 0, 3, 4, 5, 6, 7, 8, 9, 11, 12,
+ 14, 16, 17, 18, 19, 20, 21, 9, 11, 21,
+ 22, 23, 24, 23, 23, 0, 10, 18, 22, 8,
+ 23, 8, 8
+};
+
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_int8 yyr1[] =
+{
+ 0, 15, 16, 17, 17, 18, 18, 19, 19, 20,
+ 20, 20, 20, 20, 20, 21, 21, 21, 21, 22,
+ 22, 23, 23, 24, 24
+};
+
+ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
+static const yytype_int8 yyr2[] =
+{
+ 0, 2, 1, 1, 2, 0, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 3, 3, 3, 1, 1,
+ 2, 0, 2, 1, 1
+};
+
+
+enum { YYENOMEM = -2 };
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+ do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (yyscanner, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+ while (0)
+
+/* Backward compatibility with an undocumented macro.
+ Use YYerror or YYUNDEF. */
+#define YYERRCODE YYUNDEF
+
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+/* This macro is provided for backward compatibility. */
+# ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+
+
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Kind, Value, yyscanner); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+
+/*-----------------------------------.
+| Print this symbol's value on YYO. |
+`-----------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyo,
+ yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+{
+ FILE *yyoutput = yyo;
+ YYUSE (yyoutput);
+ YYUSE (yyscanner);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yykind < YYNTOKENS)
+ YYPRINT (yyo, yytoknum[yykind], *yyvaluep);
+# endif
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ YYUSE (yykind);
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+/*---------------------------.
+| Print this symbol on YYO. |
+`---------------------------*/
+
+static void
+yy_symbol_print (FILE *yyo,
+ yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+{
+ YYFPRINTF (yyo, "%s %s (",
+ yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
+
+ yy_symbol_value_print (yyo, yykind, yyvaluep, yyscanner);
+ YYFPRINTF (yyo, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop)
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp,
+ int yyrule, yyscan_t yyscanner)
+{
+ int yylno = yyrline[yyrule];
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr,
+ YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
+ &yyvsp[(yyi + 1) - (yynrhs)], yyscanner);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyssp, yyvsp, Rule, yyscanner); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args) ((void) 0)
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+/* Context of a parse error. */
+typedef struct
+{
+ yy_state_t *yyssp;
+ yysymbol_kind_t yytoken;
+} yypcontext_t;
+
+/* Put in YYARG at most YYARGN of the expected tokens given the
+ current YYCTX, and return the number of tokens stored in YYARG. If
+ YYARG is null, return the number of expected tokens (guaranteed to
+ be less than YYNTOKENS). Return YYENOMEM on memory exhaustion.
+ Return 0 if there are more than YYARGN expected tokens, yet fill
+ YYARG up to YYARGN. */
+static int
+yypcontext_expected_tokens (const yypcontext_t *yyctx,
+ yysymbol_kind_t yyarg[], int yyargn)
+{
+ /* Actual size of YYARG. */
+ int yycount = 0;
+ int yyn = yypact[+*yyctx->yyssp];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (!yyarg)
+ ++yycount;
+ else if (yycount == yyargn)
+ return 0;
+ else
+ yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx);
+ }
+ }
+ if (yyarg && yycount == 0 && 0 < yyargn)
+ yyarg[0] = YYSYMBOL_YYEMPTY;
+ return yycount;
+}
+
+
+
+
+#ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S)))
+# else
+/* Return the length of YYSTR. */
+static YYPTRDIFF_T
+yystrlen (const char *yystr)
+{
+ YYPTRDIFF_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+#endif
+
+#ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+#endif
+
+#ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYPTRDIFF_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYPTRDIFF_T yyn = 0;
+ char const *yyp = yystr;
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ else
+ goto append;
+
+ append:
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (yyres)
+ return yystpcpy (yyres, yystr) - yyres;
+ else
+ return yystrlen (yystr);
+}
+#endif
+
+
+static int
+yy_syntax_error_arguments (const yypcontext_t *yyctx,
+ yysymbol_kind_t yyarg[], int yyargn)
+{
+ /* Actual size of YYARG. */
+ int yycount = 0;
+ /* There are many possibilities here to consider:
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yyctx->yytoken != YYSYMBOL_YYEMPTY)
+ {
+ int yyn;
+ if (yyarg)
+ yyarg[yycount] = yyctx->yytoken;
+ ++yycount;
+ yyn = yypcontext_expected_tokens (yyctx,
+ yyarg ? yyarg + 1 : yyarg, yyargn - 1);
+ if (yyn == YYENOMEM)
+ return YYENOMEM;
+ else
+ yycount += yyn;
+ }
+ return yycount;
+}
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg,
+ const yypcontext_t *yyctx)
+{
+ enum { YYARGS_MAX = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULLPTR;
+ /* Arguments of yyformat: reported tokens (one for the "unexpected",
+ one per "expected"). */
+ yysymbol_kind_t yyarg[YYARGS_MAX];
+ /* Cumulated lengths of YYARG. */
+ YYPTRDIFF_T yysize = 0;
+
+ /* Actual size of YYARG. */
+ int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX);
+ if (yycount == YYENOMEM)
+ return YYENOMEM;
+
+ switch (yycount)
+ {
+#define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ default: /* Avoid compiler warnings. */
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+#undef YYCASE_
+ }
+
+ /* Compute error message size. Don't count the "%s"s, but reserve
+ room for the terminator. */
+ yysize = yystrlen (yyformat) - 2 * yycount + 1;
+ {
+ int yyi;
+ for (yyi = 0; yyi < yycount; ++yyi)
+ {
+ YYPTRDIFF_T yysize1
+ = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]);
+ if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
+ yysize = yysize1;
+ else
+ return YYENOMEM;
+ }
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return -1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]);
+ yyformat += 2;
+ }
+ else
+ {
+ ++yyp;
+ ++yyformat;
+ }
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg,
+ yysymbol_kind_t yykind, YYSTYPE *yyvaluep, yyscan_t yyscanner)
+{
+ YYUSE (yyvaluep);
+ YYUSE (yyscanner);
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ YYUSE (yykind);
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+int
+yyparse (yyscan_t yyscanner)
+{
+/* Lookahead token kind. */
+int yychar;
+
+
+/* The semantic value of the lookahead symbol. */
+/* Default value used for initialization, for pacifying older GCCs
+ or non-GCC compilers. */
+YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
+YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
+
+ /* Number of syntax errors so far. */
+ int yynerrs = 0;
+
+ yy_state_fast_t yystate = 0;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus = 0;
+
+ /* Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* Their size. */
+ YYPTRDIFF_T yystacksize = YYINITDEPTH;
+
+ /* The state stack: array, bottom, top. */
+ yy_state_t yyssa[YYINITDEPTH];
+ yy_state_t *yyss = yyssa;
+ yy_state_t *yyssp = yyss;
+
+ /* The semantic value stack: array, bottom, top. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp = yyvs;
+
+ int yyn;
+ /* The return value of yyparse. */
+ int yyresult;
+ /* Lookahead symbol kind. */
+ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf;
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ goto yysetstate;
+
+
+/*------------------------------------------------------------.
+| yynewstate -- push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+
+/*--------------------------------------------------------------------.
+| yysetstate -- set current state (the top of the stack) to yystate. |
+`--------------------------------------------------------------------*/
+yysetstate:
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+ YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
+ YY_IGNORE_USELESS_CAST_BEGIN
+ *yyssp = YY_CAST (yy_state_t, yystate);
+ YY_IGNORE_USELESS_CAST_END
+ YY_STACK_PRINT (yyss, yyssp);
+
+ if (yyss + yystacksize - 1 <= yyssp)
+#if !defined yyoverflow && !defined YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+#else
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYPTRDIFF_T yysize = yyssp - yyss + 1;
+
+# if defined yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ yy_state_t *yyss1 = yyss;
+ YYSTYPE *yyvs1 = yyvs;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * YYSIZEOF (*yyssp),
+ &yyvs1, yysize * YYSIZEOF (*yyvsp),
+ &yystacksize);
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+# else /* defined YYSTACK_RELOCATE */
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yy_state_t *yyss1 = yyss;
+ union yyalloc *yyptr =
+ YY_CAST (union yyalloc *,
+ YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YY_IGNORE_USELESS_CAST_BEGIN
+ YYDPRINTF ((stderr, "Stack size increased to %ld\n",
+ YY_CAST (long, yystacksize)));
+ YY_IGNORE_USELESS_CAST_END
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token\n"));
+ yychar = yylex (&yylval, yyscanner);
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = YYEOF;
+ yytoken = YYSYMBOL_YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else if (yychar == YYerror)
+ {
+ /* The scanner already issued an error message, process directly
+ to error recovery. But do not keep the error token as
+ lookahead, it is too special and may lead us to an endless
+ loop in error recovery. */
+ yychar = YYUNDEF;
+ yytoken = YYSYMBOL_YYerror;
+ goto yyerrlab1;
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ '$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2: /* Start: GoalWithOptionalBackSlash */
+#line 97 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = 0;
+ yyGetParser->SetResult((yyvsp[0].str));
+ }
+#line 1437 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 3: /* GoalWithOptionalBackSlash: Goal */
+#line 103 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[0].str);
+ }
+#line 1445 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 4: /* GoalWithOptionalBackSlash: Goal "\\" */
+#line 106 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = yyGetParser->CombineUnions((yyvsp[-1].str), (yyvsp[0].str));
+ }
+#line 1453 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 5: /* Goal: %empty */
+#line 111 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = 0;
+ }
+#line 1461 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 6: /* Goal: String Goal */
+#line 114 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = yyGetParser->CombineUnions((yyvsp[-1].str), (yyvsp[0].str));
+ }
+#line 1469 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 7: /* String: OuterText */
+#line 119 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[0].str);
+ }
+#line 1477 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 8: /* String: Variable */
+#line 122 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[0].str);
+ }
+#line 1485 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 9: /* OuterText: cal_NAME */
+#line 127 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[0].str);
+ }
+#line 1493 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 10: /* OuterText: "@" */
+#line 130 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[0].str);
+ }
+#line 1501 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 11: /* OuterText: "$" */
+#line 133 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[0].str);
+ }
+#line 1509 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 12: /* OuterText: "{" */
+#line 136 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[0].str);
+ }
+#line 1517 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 13: /* OuterText: "}" */
+#line 139 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[0].str);
+ }
+#line 1525 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 14: /* OuterText: cal_SYMBOL */
+#line 142 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[0].str);
+ }
+#line 1533 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 15: /* Variable: cal_ENVCURLY EnvVarName "}" */
+#line 147 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = yyGetParser->ExpandSpecialVariable((yyvsp[-2].str), (yyvsp[-1].str));
+ }
+#line 1541 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 16: /* Variable: cal_NCURLY MultipleIds "}" */
+#line 150 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = yyGetParser->ExpandSpecialVariable((yyvsp[-2].str), (yyvsp[-1].str));
+ }
+#line 1549 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 17: /* Variable: cal_DCURLY MultipleIds "}" */
+#line 153 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = yyGetParser->ExpandVariable((yyvsp[-1].str));
+ }
+#line 1557 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 18: /* Variable: cal_ATNAME */
+#line 156 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = yyGetParser->ExpandVariableForAt((yyvsp[0].str));
+ }
+#line 1565 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 19: /* EnvVarName: MultipleIds */
+#line 161 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[0].str);
+ }
+#line 1573 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 20: /* EnvVarName: cal_SYMBOL EnvVarName */
+#line 164 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[-1].str);
+ }
+#line 1581 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 21: /* MultipleIds: %empty */
+#line 169 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = 0;
+ }
+#line 1589 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 22: /* MultipleIds: ID MultipleIds */
+#line 172 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = yyGetParser->CombineUnions((yyvsp[-1].str), (yyvsp[0].str));
+ }
+#line 1597 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 23: /* ID: cal_NAME */
+#line 177 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[0].str);
+ }
+#line 1605 "cmCommandArgumentParser.cxx"
+ break;
+
+ case 24: /* ID: Variable */
+#line 180 "cmCommandArgumentParser.y"
+ {
+ (yyval.str) = (yyvsp[0].str);
+ }
+#line 1613 "cmCommandArgumentParser.cxx"
+ break;
+
+
+#line 1617 "cmCommandArgumentParser.cxx"
+
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+
+ *++yyvsp = yyval;
+
+ /* Now 'shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+ {
+ const int yylhs = yyr1[yyn] - YYNTOKENS;
+ const int yyi = yypgoto[yylhs] + *yyssp;
+ yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp
+ ? yytable[yyi]
+ : yydefgoto[yylhs]);
+ }
+
+ goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error. |
+`--------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+ {
+ yypcontext_t yyctx
+ = {yyssp, yytoken};
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == -1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = YY_CAST (char *,
+ YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc)));
+ if (yymsg)
+ {
+ yysyntax_error_status
+ = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+ yymsgp = yymsg;
+ }
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = YYENOMEM;
+ }
+ }
+ yyerror (yyscanner, yymsgp);
+ if (yysyntax_error_status == YYENOMEM)
+ goto yyexhaustedlab;
+ }
+ }
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, yyscanner);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+ /* Pacify compilers when the user code never invokes YYERROR and the
+ label yyerrorlab therefore never appears in user code. */
+ if (0)
+ YYERROR;
+
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ /* Pop stack until we find a state that shifts the error token. */
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYSYMBOL_YYerror;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ YY_ACCESSING_SYMBOL (yystate), yyvsp, yyscanner);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+
+#if 1
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (yyscanner, YY_("memory exhausted"));
+ yyresult = 2;
+ goto yyreturn;
+#endif
+
+
+/*-------------------------------------------------------.
+| yyreturn -- parsing is finished, clean up and return. |
+`-------------------------------------------------------*/
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, yyscanner);
+ }
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yyscanner);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ return yyresult;
+}
+
+#line 185 "cmCommandArgumentParser.y"
+
+/* End of grammar */
+
+/*--------------------------------------------------------------------------*/
+void cmCommandArgument_yyerror(yyscan_t yyscanner, const char* message)
+{
+ yyGetParser->Error(message);
+}
diff --git a/Source/LexerParser/cmCommandArgumentParser.y b/Source/LexerParser/cmCommandArgumentParser.y
new file mode 100644
index 0000000..2689415
--- /dev/null
+++ b/Source/LexerParser/cmCommandArgumentParser.y
@@ -0,0 +1,192 @@
+%{
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --name-prefix=cmCommandArgument_yy --defines=cmCommandArgumentParserTokens.h -ocmCommandArgumentParser.cxx cmCommandArgumentParser.y
+
+*/
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string.h>
+
+#define yyGetParser (cmCommandArgument_yyget_extra(yyscanner))
+
+/* Make sure malloc and free are available on QNX. */
+#ifdef __QNX__
+# include <malloc.h>
+#endif
+
+#include <stdint.h>
+/* Make sure the parser uses standard memory allocation. The default
+ generated parser malloc/free declarations do not work on all
+ platforms. */
+#include <stdlib.h>
+#define YYMALLOC malloc
+#define YYFREE free
+
+/*-------------------------------------------------------------------------*/
+#include "cmCommandArgumentParserHelper.h" /* Interface to parser object. */
+#include "cmCommandArgumentLexer.h" /* Interface to lexer object. */
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Helper function to forward error callback from parser. */
+static void cmCommandArgument_yyerror(yyscan_t yyscanner, const char* message);
+
+/* Configure the parser to support large input. */
+#define YYMAXDEPTH 100000
+#define YYINITDEPTH 10000
+
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch statement contains default but no
+ case. */
+# pragma warning (disable: 4244) /* loss of precision */
+# pragma warning (disable: 4702) /* unreachable code */
+#endif
+#if defined(__GNUC__) && __GNUC__ >= 8
+# pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+#endif
+%}
+
+/* Generate a reentrant parser object. */
+%define api.pure
+
+/* Configure the parser to use a lexer object. */
+%lex-param {yyscan_t yyscanner}
+%parse-param {yyscan_t yyscanner}
+
+%define parse.error verbose
+
+/*
+%union {
+ char* string;
+}
+*/
+
+/*-------------------------------------------------------------------------*/
+/* Tokens */
+%token cal_ENVCURLY
+%token cal_NCURLY
+%token cal_DCURLY
+%token cal_DOLLAR "$"
+%token cal_LCURLY "{"
+%token cal_RCURLY "}"
+%token cal_NAME
+%token cal_BSLASH "\\"
+%token cal_SYMBOL
+%token cal_AT "@"
+%token cal_ERROR
+%token cal_ATNAME
+
+/*-------------------------------------------------------------------------*/
+/* grammar */
+%%
+
+
+Start:
+ GoalWithOptionalBackSlash {
+ $<str>$ = 0;
+ yyGetParser->SetResult($<str>1);
+ }
+
+GoalWithOptionalBackSlash:
+ Goal {
+ $<str>$ = $<str>1;
+ }
+| Goal cal_BSLASH {
+ $<str>$ = yyGetParser->CombineUnions($<str>1, $<str>2);
+ }
+
+Goal:
+ {
+ $<str>$ = 0;
+ }
+| String Goal {
+ $<str>$ = yyGetParser->CombineUnions($<str>1, $<str>2);
+ }
+
+String:
+ OuterText {
+ $<str>$ = $<str>1;
+ }
+| Variable {
+ $<str>$ = $<str>1;
+ }
+
+OuterText:
+ cal_NAME {
+ $<str>$ = $<str>1;
+ }
+| cal_AT {
+ $<str>$ = $<str>1;
+ }
+| cal_DOLLAR {
+ $<str>$ = $<str>1;
+ }
+| cal_LCURLY {
+ $<str>$ = $<str>1;
+ }
+| cal_RCURLY {
+ $<str>$ = $<str>1;
+ }
+| cal_SYMBOL {
+ $<str>$ = $<str>1;
+ }
+
+Variable:
+ cal_ENVCURLY EnvVarName cal_RCURLY {
+ $<str>$ = yyGetParser->ExpandSpecialVariable($<str>1, $<str>2);
+ }
+| cal_NCURLY MultipleIds cal_RCURLY {
+ $<str>$ = yyGetParser->ExpandSpecialVariable($<str>1, $<str>2);
+ }
+| cal_DCURLY MultipleIds cal_RCURLY {
+ $<str>$ = yyGetParser->ExpandVariable($<str>2);
+ }
+| cal_ATNAME {
+ $<str>$ = yyGetParser->ExpandVariableForAt($<str>1);
+ }
+
+EnvVarName:
+ MultipleIds {
+ $<str>$ = $<str>1;
+ }
+| cal_SYMBOL EnvVarName {
+ $<str>$ = $<str>1;
+ }
+
+MultipleIds:
+ {
+ $<str>$ = 0;
+ }
+| ID MultipleIds {
+ $<str>$ = yyGetParser->CombineUnions($<str>1, $<str>2);
+ }
+
+ID:
+ cal_NAME {
+ $<str>$ = $<str>1;
+ }
+| Variable {
+ $<str>$ = $<str>1;
+ }
+;
+
+%%
+/* End of grammar */
+
+/*--------------------------------------------------------------------------*/
+void cmCommandArgument_yyerror(yyscan_t yyscanner, const char* message)
+{
+ yyGetParser->Error(message);
+}
diff --git a/Source/LexerParser/cmCommandArgumentParserTokens.h b/Source/LexerParser/cmCommandArgumentParserTokens.h
new file mode 100644
index 0000000..578f793
--- /dev/null
+++ b/Source/LexerParser/cmCommandArgumentParserTokens.h
@@ -0,0 +1,79 @@
+/* A Bison parser, made by GNU Bison 3.7.4. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
+ Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+ especially those whose name start with YY_ or yy_. They are
+ private implementation details that can be changed or removed. */
+
+#ifndef YY_CMCOMMANDARGUMENT_YY_CMCOMMANDARGUMENTPARSERTOKENS_H_INCLUDED
+# define YY_CMCOMMANDARGUMENT_YY_CMCOMMANDARGUMENTPARSERTOKENS_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int cmCommandArgument_yydebug;
+#endif
+
+/* Token kinds. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ YYEMPTY = -2,
+ YYEOF = 0, /* "end of file" */
+ YYerror = 256, /* error */
+ YYUNDEF = 257, /* "invalid token" */
+ cal_ENVCURLY = 258, /* cal_ENVCURLY */
+ cal_NCURLY = 259, /* cal_NCURLY */
+ cal_DCURLY = 260, /* cal_DCURLY */
+ cal_DOLLAR = 261, /* "$" */
+ cal_LCURLY = 262, /* "{" */
+ cal_RCURLY = 263, /* "}" */
+ cal_NAME = 264, /* cal_NAME */
+ cal_BSLASH = 265, /* "\\" */
+ cal_SYMBOL = 266, /* cal_SYMBOL */
+ cal_AT = 267, /* "@" */
+ cal_ERROR = 268, /* cal_ERROR */
+ cal_ATNAME = 269 /* cal_ATNAME */
+ };
+ typedef enum yytokentype yytoken_kind_t;
+#endif
+
+/* Value type. */
+
+
+
+int cmCommandArgument_yyparse (yyscan_t yyscanner);
+
+#endif /* !YY_CMCOMMANDARGUMENT_YY_CMCOMMANDARGUMENTPARSERTOKENS_H_INCLUDED */
diff --git a/Source/LexerParser/cmDependsJavaLexer.cxx b/Source/LexerParser/cmDependsJavaLexer.cxx
new file mode 100644
index 0000000..d703e3c
--- /dev/null
+++ b/Source/LexerParser/cmDependsJavaLexer.cxx
@@ -0,0 +1,2819 @@
+#include "cmStandardLexer.h"
+
+#define FLEXINT_H 1
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmDependsJava_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmDependsJava_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmDependsJava_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmDependsJava_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmDependsJava_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmDependsJava_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmDependsJava_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmDependsJava_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmDependsJava_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmDependsJava_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmDependsJava_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmDependsJava_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmDependsJava_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmDependsJava_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmDependsJava_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmDependsJava_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmDependsJava_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmDependsJava_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmDependsJava_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmDependsJava_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmDependsJava_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmDependsJava_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmDependsJava_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmDependsJava_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmDependsJava_yylex_ALREADY_DEFINED
+#else
+#define yylex cmDependsJava_yylex
+#endif
+
+#ifdef yyrestart
+#define cmDependsJava_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmDependsJava_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmDependsJava_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmDependsJava_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmDependsJava_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmDependsJava_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmDependsJava_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmDependsJava_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmDependsJava_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmDependsJava_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmDependsJava_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmDependsJava_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmDependsJava_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmDependsJava_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmDependsJava_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmDependsJava_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmDependsJava_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmDependsJava_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmDependsJava_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmDependsJava_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmDependsJava_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmDependsJava_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmDependsJava_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmDependsJava_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmDependsJava_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmDependsJava_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmDependsJava_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmDependsJava_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmDependsJava_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmDependsJava_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmDependsJava_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmDependsJava_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmDependsJava_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmDependsJava_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmDependsJava_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmDependsJava_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmDependsJava_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmDependsJava_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmDependsJava_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmDependsJava_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmDependsJava_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmDependsJava_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmDependsJava_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmDependsJava_yyfree
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an
+ * integer in range [0..255] for use as an array index.
+ */
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin , yyscanner )
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+ #define YY_LINENO_REWIND_TO(ptr)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+static void yyensure_buffer_stack ( yyscan_t yyscanner );
+static void yy_load_buffer_state ( yyscan_t yyscanner );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner)
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+#define yy_new_buffer yy_create_buffer
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define cmDependsJava_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+typedef flex_uint8_t YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner);
+static int yy_get_next_buffer ( yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+#define YY_NUM_RULES 111
+#define YY_END_OF_BUFFER 112
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static const flex_int16_t yy_accept[327] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 112, 110, 109, 109,
+ 77, 4, 73, 94, 60, 110, 93, 92, 105, 99,
+ 68, 89, 74, 71, 56, 56, 67, 103, 86, 75,
+ 79, 102, 107, 64, 63, 65, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 70, 96, 69, 104, 3, 3, 6, 111, 5,
+ 78, 95, 61, 62, 0, 0, 106, 101, 100, 91,
+ 90, 57, 1, 0, 72, 57, 56, 57, 0, 56,
+ 0, 88, 87, 76, 80, 81, 107, 66, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 18, 107,
+
+ 107, 107, 107, 107, 107, 26, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 97, 98, 2, 55, 55,
+ 0, 0, 0, 108, 57, 0, 57, 58, 85, 82,
+ 83, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 25, 107,
+ 107, 30, 107, 107, 34, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 50, 107, 107, 107, 0, 0, 58, 84, 107,
+ 107, 107, 107, 11, 12, 107, 14, 107, 107, 107,
+
+ 107, 20, 107, 107, 107, 107, 107, 107, 107, 107,
+ 32, 107, 59, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 46, 107, 107, 54, 51, 107,
+ 107, 107, 107, 107, 10, 13, 15, 107, 107, 107,
+ 107, 22, 24, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 40, 107, 107, 43, 107, 107, 47,
+ 107, 107, 53, 107, 8, 107, 107, 107, 19, 107,
+ 107, 107, 28, 107, 107, 33, 107, 107, 107, 38,
+ 39, 41, 107, 44, 107, 48, 107, 107, 107, 9,
+ 107, 17, 21, 23, 107, 107, 107, 35, 36, 107,
+
+ 107, 107, 107, 107, 7, 16, 107, 107, 107, 107,
+ 42, 107, 107, 52, 107, 107, 31, 37, 107, 49,
+ 27, 29, 107, 107, 45, 0
+ } ;
+
+static const YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 5, 1, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 19,
+ 19, 19, 19, 19, 19, 20, 20, 21, 22, 23,
+ 24, 25, 26, 1, 27, 27, 27, 28, 29, 28,
+ 30, 30, 30, 30, 30, 31, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 32, 30, 30,
+ 33, 34, 35, 36, 30, 1, 37, 38, 39, 40,
+
+ 41, 42, 43, 44, 45, 30, 46, 47, 48, 49,
+ 50, 51, 30, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static const YY_CHAR yy_meta[65] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 3, 3, 3,
+ 1, 1, 1, 1, 1, 1, 3, 3, 3, 4,
+ 4, 4, 1, 1, 1, 1, 3, 3, 3, 3,
+ 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 1, 1, 1, 1
+ } ;
+
+static const flex_int16_t yy_base[334] =
+ { 0,
+ 0, 0, 401, 400, 62, 63, 411, 414, 414, 414,
+ 386, 414, 414, 385, 61, 374, 414, 414, 383, 57,
+ 414, 56, 54, 65, 74, 43, 414, 414, 55, 382,
+ 59, 414, 0, 414, 414, 381, 38, 36, 60, 46,
+ 51, 75, 69, 354, 82, 76, 362, 85, 56, 352,
+ 357, 414, 100, 414, 414, 414, 383, 414, 414, 414,
+ 414, 414, 414, 414, 390, 127, 414, 414, 414, 414,
+ 414, 129, 414, 395, 414, 132, 95, 414, 165, 414,
+ 0, 373, 414, 414, 414, 109, 0, 414, 343, 342,
+ 344, 352, 338, 101, 354, 353, 340, 346, 332, 333,
+
+ 331, 337, 334, 332, 329, 0, 329, 110, 330, 324,
+ 320, 329, 336, 93, 336, 319, 322, 89, 320, 325,
+ 320, 114, 131, 120, 323, 414, 414, 414, 414, 358,
+ 170, 357, 362, 414, 173, 157, 176, 150, 414, 414,
+ 340, 309, 321, 314, 323, 318, 317, 318, 304, 302,
+ 300, 316, 314, 310, 309, 296, 311, 310, 0, 153,
+ 292, 304, 301, 298, 0, 295, 295, 284, 285, 291,
+ 282, 284, 281, 289, 292, 278, 292, 277, 279, 279,
+ 286, 0, 286, 288, 277, 189, 314, 414, 414, 270,
+ 269, 279, 273, 0, 0, 274, 0, 264, 271, 260,
+
+ 267, 0, 264, 271, 264, 256, 268, 256, 270, 254,
+ 0, 249, 0, 267, 266, 261, 256, 248, 245, 253,
+ 258, 244, 256, 250, 0, 236, 239, 0, 0, 237,
+ 249, 252, 234, 250, 0, 0, 0, 237, 238, 243,
+ 243, 235, 0, 233, 226, 230, 236, 236, 233, 221,
+ 235, 234, 223, 0, 232, 216, 0, 225, 216, 214,
+ 221, 220, 0, 225, 0, 214, 207, 207, 0, 207,
+ 200, 217, 0, 218, 219, 0, 214, 213, 199, 0,
+ 0, 0, 210, 0, 201, 0, 209, 202, 194, 0,
+ 206, 0, 0, 0, 197, 204, 205, 0, 0, 202,
+
+ 191, 192, 191, 198, 0, 0, 163, 162, 170, 170,
+ 0, 164, 152, 0, 152, 157, 0, 0, 127, 0,
+ 0, 0, 115, 95, 0, 414, 218, 222, 226, 228,
+ 232, 96, 235
+ } ;
+
+static const flex_int16_t yy_def[334] =
+ { 0,
+ 326, 1, 327, 327, 328, 328, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 329, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 25, 326, 326, 326, 326,
+ 326, 326, 330, 326, 326, 326, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 329, 326, 326, 326, 326,
+ 326, 326, 326, 331, 326, 326, 25, 326, 326, 326,
+ 332, 326, 326, 326, 326, 326, 330, 326, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 326, 326, 326, 326, 326,
+ 326, 333, 331, 326, 326, 326, 326, 332, 326, 326,
+ 326, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 326, 333, 326, 326, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 0, 326, 326, 326, 326,
+ 326, 326, 326
+ } ;
+
+static const flex_int16_t yy_nxt[479] =
+ { 0,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 26,
+ 27, 28, 29, 30, 31, 32, 33, 33, 33, 33,
+ 33, 33, 34, 8, 35, 36, 37, 38, 39, 40,
+ 41, 42, 33, 33, 43, 33, 44, 33, 45, 33,
+ 46, 47, 48, 49, 33, 50, 51, 33, 33, 33,
+ 52, 53, 54, 55, 59, 59, 60, 60, 63, 68,
+ 70, 72, 72, 72, 326, 89, 73, 82, 83, 71,
+ 69, 74, 85, 86, 64, 91, 98, 92, 75, 76,
+ 90, 77, 77, 77, 93, 99, 94, 100, 138, 122,
+
+ 326, 78, 79, 95, 80, 81, 96, 123, 101, 97,
+ 106, 102, 113, 78, 79, 78, 107, 108, 110, 103,
+ 80, 104, 111, 126, 105, 173, 326, 114, 117, 326,
+ 115, 81, 140, 141, 325, 130, 112, 168, 118, 119,
+ 174, 120, 169, 121, 131, 131, 72, 72, 72, 135,
+ 135, 135, 326, 147, 148, 324, 78, 79, 178, 78,
+ 79, 127, 161, 162, 183, 179, 184, 180, 78, 79,
+ 78, 78, 79, 78, 137, 137, 137, 136, 129, 136,
+ 188, 132, 137, 137, 137, 181, 323, 186, 186, 182,
+ 135, 135, 135, 137, 137, 137, 188, 129, 322, 207,
+
+ 78, 79, 208, 78, 321, 320, 186, 186, 319, 318,
+ 317, 316, 78, 79, 78, 78, 315, 78, 56, 56,
+ 56, 56, 58, 58, 58, 58, 65, 65, 65, 65,
+ 87, 87, 133, 133, 133, 133, 187, 187, 314, 313,
+ 312, 311, 310, 309, 308, 307, 306, 305, 304, 303,
+ 302, 301, 300, 299, 298, 297, 296, 295, 294, 293,
+ 292, 291, 290, 289, 288, 287, 286, 285, 284, 283,
+ 282, 281, 280, 279, 278, 277, 276, 275, 274, 273,
+ 272, 271, 270, 269, 268, 267, 266, 265, 264, 263,
+ 262, 261, 260, 259, 258, 257, 256, 255, 254, 253,
+
+ 252, 251, 250, 249, 248, 247, 246, 245, 244, 243,
+ 242, 228, 241, 240, 239, 238, 237, 236, 235, 234,
+ 233, 232, 129, 231, 230, 229, 228, 227, 226, 225,
+ 224, 223, 222, 221, 220, 219, 218, 217, 216, 215,
+ 214, 213, 212, 211, 210, 209, 206, 205, 204, 203,
+ 202, 201, 200, 199, 198, 197, 196, 195, 194, 193,
+ 192, 191, 190, 189, 134, 129, 129, 185, 177, 176,
+ 175, 172, 171, 170, 167, 166, 165, 164, 163, 160,
+ 159, 158, 157, 156, 155, 154, 153, 152, 151, 150,
+ 149, 146, 145, 144, 143, 142, 139, 134, 129, 128,
+
+ 125, 124, 116, 109, 88, 84, 67, 66, 62, 61,
+ 326, 57, 57, 7, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326
+ } ;
+
+static const flex_int16_t yy_chk[479] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 5, 6, 5, 6, 15, 20,
+ 22, 23, 23, 23, 26, 37, 24, 29, 29, 22,
+ 20, 24, 31, 31, 15, 38, 40, 38, 24, 25,
+ 37, 25, 25, 25, 38, 40, 39, 41, 332, 49,
+
+ 26, 25, 25, 39, 25, 25, 39, 49, 41, 39,
+ 43, 42, 46, 25, 25, 25, 43, 43, 45, 42,
+ 25, 42, 45, 53, 42, 118, 77, 46, 48, 66,
+ 46, 25, 86, 86, 324, 66, 45, 114, 48, 48,
+ 118, 48, 114, 48, 66, 66, 72, 72, 72, 76,
+ 76, 76, 77, 94, 94, 323, 72, 72, 122, 76,
+ 76, 53, 108, 108, 124, 122, 124, 123, 72, 72,
+ 72, 76, 76, 76, 136, 136, 136, 79, 131, 79,
+ 138, 66, 79, 79, 79, 123, 319, 131, 131, 123,
+ 135, 135, 135, 137, 137, 137, 138, 186, 316, 160,
+
+ 135, 135, 160, 137, 315, 313, 186, 186, 312, 310,
+ 309, 308, 135, 135, 135, 137, 307, 137, 327, 327,
+ 327, 327, 328, 328, 328, 328, 329, 329, 329, 329,
+ 330, 330, 331, 331, 331, 331, 333, 333, 304, 303,
+ 302, 301, 300, 297, 296, 295, 291, 289, 288, 287,
+ 285, 283, 279, 278, 277, 275, 274, 272, 271, 270,
+ 268, 267, 266, 264, 262, 261, 260, 259, 258, 256,
+ 255, 253, 252, 251, 250, 249, 248, 247, 246, 245,
+ 244, 242, 241, 240, 239, 238, 234, 233, 232, 231,
+ 230, 227, 226, 224, 223, 222, 221, 220, 219, 218,
+
+ 217, 216, 215, 214, 212, 210, 209, 208, 207, 206,
+ 205, 204, 203, 201, 200, 199, 198, 196, 193, 192,
+ 191, 190, 187, 185, 184, 183, 181, 180, 179, 178,
+ 177, 176, 175, 174, 173, 172, 171, 170, 169, 168,
+ 167, 166, 164, 163, 162, 161, 158, 157, 156, 155,
+ 154, 153, 152, 151, 150, 149, 148, 147, 146, 145,
+ 144, 143, 142, 141, 133, 132, 130, 125, 121, 120,
+ 119, 117, 116, 115, 113, 112, 111, 110, 109, 107,
+ 105, 104, 103, 102, 101, 100, 99, 98, 97, 96,
+ 95, 93, 92, 91, 90, 89, 82, 74, 65, 57,
+
+ 51, 50, 47, 44, 36, 30, 19, 16, 14, 11,
+ 7, 4, 3, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 326, 326, 326
+ } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C++ and modified to build everywhere.
+
+Run flex >= 2.6 like this:
+
+ flex --nounistd -DFLEXINT_H --noline --header-file=cmDependsJavaLexer.h -ocmDependsJavaLexer.cxx cmDependsJavaLexer.in.l
+
+Modify cmDependsJavaLexer.cxx:
+ - remove trailing whitespace: sed -i 's/\s*$//' cmDependsJavaLexer.h cmDependsJavaLexer.cxx
+ - remove blank lines at end of file: sed -i '${/^$/d;}' cmDependsJavaLexer.h cmDependsJavaLexer.cxx
+ - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmDependsJavaLexer.cxx
+
+*/
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
+
+#include <iostream>
+
+#include "cmDependsJavaParserHelper.h"
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ do { result = yyextra->LexInput(buf, max_size); } while (0)
+
+/* Include the set of tokens from the parser. */
+#include "cmDependsJavaParserTokens.h"
+
+#define KEYWORD yylvalp->str = 0
+#define SYMBOL yylvalp->str = 0
+#define PRIMITIVE yylvalp->str = 0
+
+/*--------------------------------------------------------------------------*/
+
+#define INITIAL 0
+#define comment 1
+#define string 2
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals ( yyscan_t yyscanner );
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput ( int c, char *buf_ptr , yyscan_t yyscanner);
+
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput ( yyscan_t yyscanner );
+#else
+static int input ( yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ int n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK /*LINTED*/break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_load_buffer_state( yyscanner );
+ }
+
+ {
+
+ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 327 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 414 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+{ BEGIN(comment); }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+{ BEGIN(INITIAL); }
+ YY_BREAK
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+{}
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+{ BEGIN(string); }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+{ BEGIN(INITIAL); return jp_STRINGLITERAL; }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+{}
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+{ KEYWORD; return jp_ABSTRACT; }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+{ KEYWORD; return jp_ASSERT; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+{ KEYWORD; return jp_BOOLEAN_TYPE; }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+{ KEYWORD; return jp_BREAK; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+{ KEYWORD; return jp_BYTE_TYPE; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+{ KEYWORD; return jp_CASE; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+{ KEYWORD; return jp_CATCH; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+{ KEYWORD; return jp_CHAR_TYPE; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+{ KEYWORD; return jp_CLASS; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+{ KEYWORD; return jp_CONTINUE; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+{ KEYWORD; return jp_DEFAULT; }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+{ KEYWORD; return jp_DO; }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+{ KEYWORD; return jp_DOUBLE_TYPE; }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+{ KEYWORD; return jp_ELSE; }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+{ KEYWORD; return jp_EXTENDS; }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+{ KEYWORD; return jp_FINAL; }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+{ KEYWORD; return jp_FINALLY; }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+{ KEYWORD; return jp_FLOAT_TYPE; }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+{ KEYWORD; return jp_FOR; }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+{ KEYWORD; return jp_IF; }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+{ KEYWORD; return jp_IMPLEMENTS; }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+{ KEYWORD; return jp_IMPORT; }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+{ KEYWORD; return jp_INSTANCEOF; }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+{ KEYWORD; return jp_INT_TYPE; }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+{ KEYWORD; return jp_INTERFACE; }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+{ KEYWORD; return jp_LONG_TYPE; }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+{ KEYWORD; return jp_NATIVE; }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+{ KEYWORD; return jp_NEW; }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+{ KEYWORD; return jp_PACKAGE; }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+{ KEYWORD; return jp_PRIVATE; }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+{ KEYWORD; return jp_PROTECTED; }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+{ KEYWORD; return jp_PUBLIC; }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+{ KEYWORD; return jp_RETURN; }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+{ KEYWORD; return jp_SHORT_TYPE; }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+{ KEYWORD; return jp_STATIC; }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+{ KEYWORD; return jp_STRICTFP; }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+{ KEYWORD; return jp_SUPER; }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+{ KEYWORD; return jp_SWITCH; }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+{ KEYWORD; return jp_SYNCHRONIZED; }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+{ KEYWORD; return jp_THIS; }
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+{ KEYWORD; return jp_THROW; }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+{ KEYWORD; return jp_THROWS; }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+{ KEYWORD; return jp_TRANSIENT; }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+{ KEYWORD; return jp_TRY; }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+{ KEYWORD; return jp_VOID; }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+{ KEYWORD; return jp_VOLATILE; }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+{ KEYWORD; return jp_WHILE; }
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+{ PRIMITIVE; return jp_BOOLEANLITERAL; }
+ YY_BREAK
+case 55:
+/* rule 55 can match eol */
+YY_RULE_SETUP
+{ PRIMITIVE; return jp_CHARACTERLITERAL; }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+{ PRIMITIVE; return jp_DECIMALINTEGERLITERAL; }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+{ PRIMITIVE; return jp_FLOATINGPOINTLITERAL; }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+{ PRIMITIVE; return jp_HEXINTEGERLITERAL; }
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+{ PRIMITIVE; return jp_NULLLITERAL; }
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+{ SYMBOL; return jp_AND; }
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+{ SYMBOL; return jp_ANDAND; }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+{ SYMBOL; return jp_ANDEQUALS; }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+{ SYMBOL; return jp_BRACKETEND; }
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+{ SYMBOL; return jp_BRACKETSTART; }
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+{ SYMBOL; return jp_CARROT; }
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+{ SYMBOL; return jp_CARROTEQUALS; }
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+{ SYMBOL; return jp_COLON; }
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+{ SYMBOL; return jp_COMMA; }
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+{ SYMBOL; return jp_CURLYEND; }
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+{ SYMBOL; return jp_CURLYSTART; }
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+{ SYMBOL; return jp_DIVIDE; }
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+{ SYMBOL; return jp_DIVIDEEQUALS; }
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+{ SYMBOL; return jp_DOLLAR; }
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+{ SYMBOL; return jp_DOT; }
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+{ SYMBOL; return jp_EQUALS; }
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+{ SYMBOL; return jp_EQUALSEQUALS; }
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+{ SYMBOL; return jp_EXCLAMATION; }
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+{ SYMBOL; return jp_EXCLAMATIONEQUALS; }
+ YY_BREAK
+case 79:
+YY_RULE_SETUP
+{ SYMBOL; return jp_GREATER; }
+ YY_BREAK
+case 80:
+YY_RULE_SETUP
+{ SYMBOL; return jp_GTEQUALS; }
+ YY_BREAK
+case 81:
+YY_RULE_SETUP
+{ SYMBOL; return jp_GTGT; }
+ YY_BREAK
+case 82:
+YY_RULE_SETUP
+{ SYMBOL; return jp_GTGTEQUALS; }
+ YY_BREAK
+case 83:
+YY_RULE_SETUP
+{ SYMBOL; return jp_GTGTGT; }
+ YY_BREAK
+case 84:
+YY_RULE_SETUP
+{ SYMBOL; return jp_GTGTGTEQUALS; }
+ YY_BREAK
+case 85:
+YY_RULE_SETUP
+{ SYMBOL; return jp_LESLESEQUALS; }
+ YY_BREAK
+case 86:
+YY_RULE_SETUP
+{ SYMBOL; return jp_LESSTHAN; }
+ YY_BREAK
+case 87:
+YY_RULE_SETUP
+{ SYMBOL; return jp_LTEQUALS; }
+ YY_BREAK
+case 88:
+YY_RULE_SETUP
+{ SYMBOL; return jp_LTLT; }
+ YY_BREAK
+case 89:
+YY_RULE_SETUP
+{ SYMBOL; return jp_MINUS; }
+ YY_BREAK
+case 90:
+YY_RULE_SETUP
+{ SYMBOL; return jp_MINUSEQUALS; }
+ YY_BREAK
+case 91:
+YY_RULE_SETUP
+{ SYMBOL; return jp_MINUSMINUS; }
+ YY_BREAK
+case 92:
+YY_RULE_SETUP
+{ SYMBOL; return jp_PAREEND; }
+ YY_BREAK
+case 93:
+YY_RULE_SETUP
+{ SYMBOL; return jp_PARESTART; }
+ YY_BREAK
+case 94:
+YY_RULE_SETUP
+{ SYMBOL; return jp_PERCENT; }
+ YY_BREAK
+case 95:
+YY_RULE_SETUP
+{ SYMBOL; return jp_PERCENTEQUALS; }
+ YY_BREAK
+case 96:
+YY_RULE_SETUP
+{ SYMBOL; return jp_PIPE; }
+ YY_BREAK
+case 97:
+YY_RULE_SETUP
+{ SYMBOL; return jp_PIPEEQUALS; }
+ YY_BREAK
+case 98:
+YY_RULE_SETUP
+{ SYMBOL; return jp_PIPEPIPE; }
+ YY_BREAK
+case 99:
+YY_RULE_SETUP
+{ SYMBOL; return jp_PLUS; }
+ YY_BREAK
+case 100:
+YY_RULE_SETUP
+{ SYMBOL; return jp_PLUSEQUALS; }
+ YY_BREAK
+case 101:
+YY_RULE_SETUP
+{ SYMBOL; return jp_PLUSPLUS; }
+ YY_BREAK
+case 102:
+YY_RULE_SETUP
+{ SYMBOL; return jp_QUESTION; }
+ YY_BREAK
+case 103:
+YY_RULE_SETUP
+{ SYMBOL; return jp_SEMICOL; }
+ YY_BREAK
+case 104:
+YY_RULE_SETUP
+{ SYMBOL; return jp_TILDE; }
+ YY_BREAK
+case 105:
+YY_RULE_SETUP
+{ SYMBOL; return jp_TIMES; }
+ YY_BREAK
+case 106:
+YY_RULE_SETUP
+{ SYMBOL; return jp_TIMESEQUALS; }
+ YY_BREAK
+case 107:
+YY_RULE_SETUP
+{
+ yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ return jp_NAME;
+}
+ YY_BREAK
+case 108:
+/* rule 108 can match eol */
+YY_RULE_SETUP
+{ }
+ YY_BREAK
+case 109:
+/* rule 109 can match eol */
+YY_RULE_SETUP
+{ }
+ YY_BREAK
+case 110:
+YY_RULE_SETUP
+{
+ std::cerr << "Unknown character: " << yytext[0]
+ << " (" << (int)yytext[0] << ")" << std::endl;
+ yyextra->Error("Unknown character");
+ return jp_ERROR;
+}
+ YY_BREAK
+case 111:
+YY_RULE_SETUP
+ECHO;
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(comment):
+case YY_STATE_EOF(string):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap( yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of user's declarations */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc( (void *) b->yy_ch_buf,
+ (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = NULL;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin , yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+ (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ /* "- 2" to take care of EOB's */
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 327 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ char *yy_cp = yyg->yy_c_buf_p;
+
+ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 327 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_is_jam = (yy_current_state == 326);
+
+ (void)yyg;
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput (int c, char * yy_bp , yyscan_t yyscanner)
+{
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yyg->yy_hold_char;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ int number_to_move = yyg->yy_n_chars + 2;
+ char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ yyg->yy_n_chars = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ yyg->yytext_ptr = yy_bp;
+ yyg->yy_hold_char = *yy_cp;
+ yyg->yy_c_buf_p = yy_cp;
+}
+
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin , yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( yyscanner ) )
+ return 0;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner);
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file , yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree( (void *) b->yy_ch_buf , yyscanner );
+
+ yyfree( (void *) b , yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_flush_buffer( b , yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return NULL;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = NULL;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b , yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner)
+{
+
+ return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = (yy_size_t) (_yybytes_len + 2);
+ buf = (char *) yyalloc( n , yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n , yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param _line_number line number
+ * @param yyscanner The scanner object.
+ */
+void yyset_lineno (int _line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
+
+ yylineno = _line_number;
+}
+
+/** Set the current column.
+ * @param _column_no column number
+ * @param yyscanner The scanner object.
+ */
+void yyset_column (int _column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_column called with no buffer" );
+
+ yycolumn = _column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param _in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * _in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = _in_str ;
+}
+
+void yyset_out (FILE * _out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = _out_str ;
+}
+
+int yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void yyset_debug (int _bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = _bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+/* User-visible API */
+
+/* yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+int yylex_init(yyscan_t* ptr_yy_globals)
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to yyalloc in
+ * the yyextra field.
+ */
+int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals )
+{
+ struct yyguts_t dummy_yyguts;
+
+ yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = NULL;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = NULL;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = NULL;
+ yyout = NULL;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ yyfree(yyg->yy_buffer_stack , yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ yyfree( yyg->yy_start_stack , yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ yyfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
+{
+ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ return malloc(size);
+}
+
+void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return realloc(ptr, size);
+}
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+/*--------------------------------------------------------------------------*/
+
+#endif /* __clang_analyzer__ */
diff --git a/Source/LexerParser/cmDependsJavaLexer.h b/Source/LexerParser/cmDependsJavaLexer.h
new file mode 100644
index 0000000..f1e87d2
--- /dev/null
+++ b/Source/LexerParser/cmDependsJavaLexer.h
@@ -0,0 +1,689 @@
+#ifndef cmDependsJava_yyHEADER_H
+#define cmDependsJava_yyHEADER_H 1
+#define cmDependsJava_yyIN_HEADER 1
+
+#define FLEXINT_H 1
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmDependsJava_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmDependsJava_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmDependsJava_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmDependsJava_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmDependsJava_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmDependsJava_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmDependsJava_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmDependsJava_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmDependsJava_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmDependsJava_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmDependsJava_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmDependsJava_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmDependsJava_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmDependsJava_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmDependsJava_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmDependsJava_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmDependsJava_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmDependsJava_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmDependsJava_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmDependsJava_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmDependsJava_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmDependsJava_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmDependsJava_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmDependsJava_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmDependsJava_yylex_ALREADY_DEFINED
+#else
+#define yylex cmDependsJava_yylex
+#endif
+
+#ifdef yyrestart
+#define cmDependsJava_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmDependsJava_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmDependsJava_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmDependsJava_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmDependsJava_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmDependsJava_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmDependsJava_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmDependsJava_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmDependsJava_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmDependsJava_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmDependsJava_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmDependsJava_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmDependsJava_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmDependsJava_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmDependsJava_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmDependsJava_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmDependsJava_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmDependsJava_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmDependsJava_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmDependsJava_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmDependsJava_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmDependsJava_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmDependsJava_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmDependsJava_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmDependsJava_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmDependsJava_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmDependsJava_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmDependsJava_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmDependsJava_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmDependsJava_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmDependsJava_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmDependsJava_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmDependsJava_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmDependsJava_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmDependsJava_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmDependsJava_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmDependsJava_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmDependsJava_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmDependsJava_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmDependsJava_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmDependsJava_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmDependsJava_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmDependsJava_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmDependsJava_yyfree
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+/* Begin user sect3 */
+
+#define cmDependsJava_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+#define comment 1
+#define string 2
+
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#ifndef cmDependsJava_yy_create_buffer_ALREADY_DEFINED
+#undef yy_create_buffer
+#endif
+#ifndef cmDependsJava_yy_delete_buffer_ALREADY_DEFINED
+#undef yy_delete_buffer
+#endif
+#ifndef cmDependsJava_yy_scan_buffer_ALREADY_DEFINED
+#undef yy_scan_buffer
+#endif
+#ifndef cmDependsJava_yy_scan_string_ALREADY_DEFINED
+#undef yy_scan_string
+#endif
+#ifndef cmDependsJava_yy_scan_bytes_ALREADY_DEFINED
+#undef yy_scan_bytes
+#endif
+#ifndef cmDependsJava_yy_init_buffer_ALREADY_DEFINED
+#undef yy_init_buffer
+#endif
+#ifndef cmDependsJava_yy_flush_buffer_ALREADY_DEFINED
+#undef yy_flush_buffer
+#endif
+#ifndef cmDependsJava_yy_load_buffer_state_ALREADY_DEFINED
+#undef yy_load_buffer_state
+#endif
+#ifndef cmDependsJava_yy_switch_to_buffer_ALREADY_DEFINED
+#undef yy_switch_to_buffer
+#endif
+#ifndef cmDependsJava_yypush_buffer_state_ALREADY_DEFINED
+#undef yypush_buffer_state
+#endif
+#ifndef cmDependsJava_yypop_buffer_state_ALREADY_DEFINED
+#undef yypop_buffer_state
+#endif
+#ifndef cmDependsJava_yyensure_buffer_stack_ALREADY_DEFINED
+#undef yyensure_buffer_stack
+#endif
+#ifndef cmDependsJava_yylex_ALREADY_DEFINED
+#undef yylex
+#endif
+#ifndef cmDependsJava_yyrestart_ALREADY_DEFINED
+#undef yyrestart
+#endif
+#ifndef cmDependsJava_yylex_init_ALREADY_DEFINED
+#undef yylex_init
+#endif
+#ifndef cmDependsJava_yylex_init_extra_ALREADY_DEFINED
+#undef yylex_init_extra
+#endif
+#ifndef cmDependsJava_yylex_destroy_ALREADY_DEFINED
+#undef yylex_destroy
+#endif
+#ifndef cmDependsJava_yyget_debug_ALREADY_DEFINED
+#undef yyget_debug
+#endif
+#ifndef cmDependsJava_yyset_debug_ALREADY_DEFINED
+#undef yyset_debug
+#endif
+#ifndef cmDependsJava_yyget_extra_ALREADY_DEFINED
+#undef yyget_extra
+#endif
+#ifndef cmDependsJava_yyset_extra_ALREADY_DEFINED
+#undef yyset_extra
+#endif
+#ifndef cmDependsJava_yyget_in_ALREADY_DEFINED
+#undef yyget_in
+#endif
+#ifndef cmDependsJava_yyset_in_ALREADY_DEFINED
+#undef yyset_in
+#endif
+#ifndef cmDependsJava_yyget_out_ALREADY_DEFINED
+#undef yyget_out
+#endif
+#ifndef cmDependsJava_yyset_out_ALREADY_DEFINED
+#undef yyset_out
+#endif
+#ifndef cmDependsJava_yyget_leng_ALREADY_DEFINED
+#undef yyget_leng
+#endif
+#ifndef cmDependsJava_yyget_text_ALREADY_DEFINED
+#undef yyget_text
+#endif
+#ifndef cmDependsJava_yyget_lineno_ALREADY_DEFINED
+#undef yyget_lineno
+#endif
+#ifndef cmDependsJava_yyset_lineno_ALREADY_DEFINED
+#undef yyset_lineno
+#endif
+#ifndef cmDependsJava_yyget_column_ALREADY_DEFINED
+#undef yyget_column
+#endif
+#ifndef cmDependsJava_yyset_column_ALREADY_DEFINED
+#undef yyset_column
+#endif
+#ifndef cmDependsJava_yywrap_ALREADY_DEFINED
+#undef yywrap
+#endif
+#ifndef cmDependsJava_yyget_lval_ALREADY_DEFINED
+#undef yyget_lval
+#endif
+#ifndef cmDependsJava_yyset_lval_ALREADY_DEFINED
+#undef yyset_lval
+#endif
+#ifndef cmDependsJava_yyget_lloc_ALREADY_DEFINED
+#undef yyget_lloc
+#endif
+#ifndef cmDependsJava_yyset_lloc_ALREADY_DEFINED
+#undef yyset_lloc
+#endif
+#ifndef cmDependsJava_yyalloc_ALREADY_DEFINED
+#undef yyalloc
+#endif
+#ifndef cmDependsJava_yyrealloc_ALREADY_DEFINED
+#undef yyrealloc
+#endif
+#ifndef cmDependsJava_yyfree_ALREADY_DEFINED
+#undef yyfree
+#endif
+#ifndef cmDependsJava_yytext_ALREADY_DEFINED
+#undef yytext
+#endif
+#ifndef cmDependsJava_yyleng_ALREADY_DEFINED
+#undef yyleng
+#endif
+#ifndef cmDependsJava_yyin_ALREADY_DEFINED
+#undef yyin
+#endif
+#ifndef cmDependsJava_yyout_ALREADY_DEFINED
+#undef yyout
+#endif
+#ifndef cmDependsJava_yy_flex_debug_ALREADY_DEFINED
+#undef yy_flex_debug
+#endif
+#ifndef cmDependsJava_yylineno_ALREADY_DEFINED
+#undef yylineno
+#endif
+#ifndef cmDependsJava_yytables_fload_ALREADY_DEFINED
+#undef yytables_fload
+#endif
+#ifndef cmDependsJava_yytables_destroy_ALREADY_DEFINED
+#undef yytables_destroy
+#endif
+#ifndef cmDependsJava_yyTABLES_NAME_ALREADY_DEFINED
+#undef yyTABLES_NAME
+#endif
+
+#undef cmDependsJava_yyIN_HEADER
+#endif /* cmDependsJava_yyHEADER_H */
diff --git a/Source/LexerParser/cmDependsJavaLexer.in.l b/Source/LexerParser/cmDependsJavaLexer.in.l
new file mode 100644
index 0000000..3dd3c22
--- /dev/null
+++ b/Source/LexerParser/cmDependsJavaLexer.in.l
@@ -0,0 +1,181 @@
+%{
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C++ and modified to build everywhere.
+
+Run flex >= 2.6 like this:
+
+ flex --nounistd -DFLEXINT_H --noline --header-file=cmDependsJavaLexer.h -ocmDependsJavaLexer.cxx cmDependsJavaLexer.in.l
+
+Modify cmDependsJavaLexer.cxx:
+ - remove trailing whitespace: sed -i 's/\s*$//' cmDependsJavaLexer.h cmDependsJavaLexer.cxx
+ - remove blank lines at end of file: sed -i '${/^$/d;}' cmDependsJavaLexer.h cmDependsJavaLexer.cxx
+ - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmDependsJavaLexer.cxx
+
+*/
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
+
+#include <iostream>
+
+#include "cmDependsJavaParserHelper.h"
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ do { result = yyextra->LexInput(buf, max_size); } while (0)
+
+/* Include the set of tokens from the parser. */
+#include "cmDependsJavaParserTokens.h"
+
+#define KEYWORD yylvalp->str = 0
+#define SYMBOL yylvalp->str = 0
+#define PRIMITIVE yylvalp->str = 0
+
+/*--------------------------------------------------------------------------*/
+%}
+
+%option prefix="cmDependsJava_yy"
+
+%option reentrant
+%option noyywrap
+%pointer
+
+%x comment
+%x string
+
+%%
+"/*" { BEGIN(comment); }
+<comment>"*/" { BEGIN(INITIAL); }
+<comment>.|\n {}
+
+\" { BEGIN(string); }
+<string>\" { BEGIN(INITIAL); return jp_STRINGLITERAL; }
+<string>. {}
+
+abstract { KEYWORD; return jp_ABSTRACT; }
+assert { KEYWORD; return jp_ASSERT; }
+boolean { KEYWORD; return jp_BOOLEAN_TYPE; }
+break { KEYWORD; return jp_BREAK; }
+byte { KEYWORD; return jp_BYTE_TYPE; }
+case { KEYWORD; return jp_CASE; }
+catch { KEYWORD; return jp_CATCH; }
+char { KEYWORD; return jp_CHAR_TYPE; }
+class { KEYWORD; return jp_CLASS; }
+continue { KEYWORD; return jp_CONTINUE; }
+default { KEYWORD; return jp_DEFAULT; }
+do { KEYWORD; return jp_DO; }
+double { KEYWORD; return jp_DOUBLE_TYPE; }
+else { KEYWORD; return jp_ELSE; }
+extends { KEYWORD; return jp_EXTENDS; }
+final { KEYWORD; return jp_FINAL; }
+finally { KEYWORD; return jp_FINALLY; }
+float { KEYWORD; return jp_FLOAT_TYPE; }
+for { KEYWORD; return jp_FOR; }
+if { KEYWORD; return jp_IF; }
+implements { KEYWORD; return jp_IMPLEMENTS; }
+import { KEYWORD; return jp_IMPORT; }
+instanceof { KEYWORD; return jp_INSTANCEOF; }
+int { KEYWORD; return jp_INT_TYPE; }
+interface { KEYWORD; return jp_INTERFACE; }
+long { KEYWORD; return jp_LONG_TYPE; }
+native { KEYWORD; return jp_NATIVE; }
+new { KEYWORD; return jp_NEW; }
+package { KEYWORD; return jp_PACKAGE; }
+private { KEYWORD; return jp_PRIVATE; }
+protected { KEYWORD; return jp_PROTECTED; }
+public { KEYWORD; return jp_PUBLIC; }
+return { KEYWORD; return jp_RETURN; }
+short { KEYWORD; return jp_SHORT_TYPE; }
+static { KEYWORD; return jp_STATIC; }
+strictfp { KEYWORD; return jp_STRICTFP; }
+super { KEYWORD; return jp_SUPER; }
+switch { KEYWORD; return jp_SWITCH; }
+synchronized { KEYWORD; return jp_SYNCHRONIZED; }
+this { KEYWORD; return jp_THIS; }
+throw { KEYWORD; return jp_THROW; }
+throws { KEYWORD; return jp_THROWS; }
+transient { KEYWORD; return jp_TRANSIENT; }
+try { KEYWORD; return jp_TRY; }
+void { KEYWORD; return jp_VOID; }
+volatile { KEYWORD; return jp_VOLATILE; }
+while { KEYWORD; return jp_WHILE; }
+
+(true|false) { PRIMITIVE; return jp_BOOLEANLITERAL; }
+\'([^\\]|\\.|\\u[0-9a-fA-F]*|\\[0-7]*)\' { PRIMITIVE; return jp_CHARACTERLITERAL; }
+(0|[0-9]+)[lL]? { PRIMITIVE; return jp_DECIMALINTEGERLITERAL; }
+([0-9]+\.[0-9]*|\.[0-9]+|[0-9]+)([eE][+\-]?[0-9]+)?[fFdD]? { PRIMITIVE; return jp_FLOATINGPOINTLITERAL; }
+0[xX][0-9a-fA-F]+[lL]? { PRIMITIVE; return jp_HEXINTEGERLITERAL; }
+null { PRIMITIVE; return jp_NULLLITERAL; }
+
+"&" { SYMBOL; return jp_AND; }
+"&&" { SYMBOL; return jp_ANDAND; }
+"&=" { SYMBOL; return jp_ANDEQUALS; }
+"\]" { SYMBOL; return jp_BRACKETEND; }
+"\[" { SYMBOL; return jp_BRACKETSTART; }
+"\^" { SYMBOL; return jp_CARROT; }
+"\^=" { SYMBOL; return jp_CARROTEQUALS; }
+":" { SYMBOL; return jp_COLON; }
+"," { SYMBOL; return jp_COMMA; }
+"}" { SYMBOL; return jp_CURLYEND; }
+"{" { SYMBOL; return jp_CURLYSTART; }
+"/" { SYMBOL; return jp_DIVIDE; }
+"/=" { SYMBOL; return jp_DIVIDEEQUALS; }
+"\$" { SYMBOL; return jp_DOLLAR; }
+"\." { SYMBOL; return jp_DOT; }
+"=" { SYMBOL; return jp_EQUALS; }
+"==" { SYMBOL; return jp_EQUALSEQUALS; }
+"\!" { SYMBOL; return jp_EXCLAMATION; }
+"\!=" { SYMBOL; return jp_EXCLAMATIONEQUALS; }
+">" { SYMBOL; return jp_GREATER; }
+">=" { SYMBOL; return jp_GTEQUALS; }
+">>" { SYMBOL; return jp_GTGT; }
+">>=" { SYMBOL; return jp_GTGTEQUALS; }
+">>>" { SYMBOL; return jp_GTGTGT; }
+">>>=" { SYMBOL; return jp_GTGTGTEQUALS; }
+"<<=" { SYMBOL; return jp_LESLESEQUALS; }
+"<" { SYMBOL; return jp_LESSTHAN; }
+"<=" { SYMBOL; return jp_LTEQUALS; }
+"<<" { SYMBOL; return jp_LTLT; }
+"-" { SYMBOL; return jp_MINUS; }
+"-=" { SYMBOL; return jp_MINUSEQUALS; }
+"--" { SYMBOL; return jp_MINUSMINUS; }
+"\)" { SYMBOL; return jp_PAREEND; }
+"\(" { SYMBOL; return jp_PARESTART; }
+"%" { SYMBOL; return jp_PERCENT; }
+"%=" { SYMBOL; return jp_PERCENTEQUALS; }
+"\|" { SYMBOL; return jp_PIPE; }
+"\|=" { SYMBOL; return jp_PIPEEQUALS; }
+"\|\|" { SYMBOL; return jp_PIPEPIPE; }
+"\+" { SYMBOL; return jp_PLUS; }
+"\+=" { SYMBOL; return jp_PLUSEQUALS; }
+"\+\+" { SYMBOL; return jp_PLUSPLUS; }
+"\?" { SYMBOL; return jp_QUESTION; }
+";" { SYMBOL; return jp_SEMICOL; }
+"\~" { SYMBOL; return jp_TILDE; }
+"\*" { SYMBOL; return jp_TIMES; }
+"\*=" { SYMBOL; return jp_TIMESEQUALS; }
+
+[a-z_A-Z][a-z_0-9A-Z]* {
+ yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext));
+ return jp_NAME;
+}
+
+\/\/.*\n { }
+[ \f\t\n\r] { }
+. {
+ std::cerr << "Unknown character: " << yytext[0]
+ << " (" << (int)yytext[0] << ")" << std::endl;
+ yyextra->Error("Unknown character");
+ return jp_ERROR;
+}
+
+%%
+
+/*--------------------------------------------------------------------------*/
+
+#endif /* __clang_analyzer__ */
diff --git a/Source/LexerParser/cmDependsJavaParser.cxx b/Source/LexerParser/cmDependsJavaParser.cxx
new file mode 100644
index 0000000..27cc177
--- /dev/null
+++ b/Source/LexerParser/cmDependsJavaParser.cxx
@@ -0,0 +1,6604 @@
+/* A Bison parser, made by GNU Bison 3.7.4. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
+ Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+ especially those whose name start with YY_ or yy_. They are
+ private implementation details that can be changed or removed. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output, and Bison version. */
+#define YYBISON 30704
+
+/* Bison version string. */
+#define YYBISON_VERSION "3.7.4"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+/* Substitute the variable and function names. */
+#define yyparse cmDependsJava_yyparse
+#define yylex cmDependsJava_yylex
+#define yyerror cmDependsJava_yyerror
+#define yydebug cmDependsJava_yydebug
+#define yynerrs cmDependsJava_yynerrs
+
+/* First part of user prologue. */
+#line 1 "cmDependsJavaParser.y"
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --name-prefix=cmDependsJava_yy --defines=cmDependsJavaParserTokens.h -ocmDependsJavaParser.cxx cmDependsJavaParser.y
+
+*/
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+
+#define yyGetParser (cmDependsJava_yyget_extra(yyscanner))
+
+/*-------------------------------------------------------------------------*/
+#include "cmDependsJavaParserHelper.h" /* Interface to parser object. */
+#include "cmDependsJavaLexer.h" /* Interface to lexer object. */
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Helper function to forward error callback from parser. */
+static void cmDependsJava_yyerror(yyscan_t yyscanner, const char* message);
+
+#define YYMAXDEPTH 1000000
+
+
+#define jpCheckEmpty(cnt) yyGetParser->CheckEmpty(__LINE__, cnt, yyvsp)
+#define jpElementStart(cnt) yyGetParser->PrepareElement(&yyval)
+#define jpStoreClass(str) yyGetParser->AddClassFound(str); yyGetParser->DeallocateParserType(&(str))
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch statement contains default but no case. */
+#endif
+#if defined(__GNUC__) && __GNUC__ >= 8
+# pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+#endif
+
+#line 125 "cmDependsJavaParser.cxx"
+
+# ifndef YY_CAST
+# ifdef __cplusplus
+# define YY_CAST(Type, Val) static_cast<Type> (Val)
+# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+# else
+# define YY_CAST(Type, Val) ((Type) (Val))
+# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+# endif
+# endif
+# ifndef YY_NULLPTR
+# if defined __cplusplus
+# if 201103L <= __cplusplus
+# define YY_NULLPTR nullptr
+# else
+# define YY_NULLPTR 0
+# endif
+# else
+# define YY_NULLPTR ((void*)0)
+# endif
+# endif
+
+#include "cmDependsJavaParserTokens.h"
+/* Symbol kind. */
+enum yysymbol_kind_t
+{
+ YYSYMBOL_YYEMPTY = -2,
+ YYSYMBOL_YYEOF = 0, /* "end of file" */
+ YYSYMBOL_YYerror = 1, /* error */
+ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */
+ YYSYMBOL_jp_ABSTRACT = 3, /* jp_ABSTRACT */
+ YYSYMBOL_jp_ASSERT = 4, /* jp_ASSERT */
+ YYSYMBOL_jp_BOOLEAN_TYPE = 5, /* jp_BOOLEAN_TYPE */
+ YYSYMBOL_jp_BREAK = 6, /* jp_BREAK */
+ YYSYMBOL_jp_BYTE_TYPE = 7, /* jp_BYTE_TYPE */
+ YYSYMBOL_jp_CASE = 8, /* jp_CASE */
+ YYSYMBOL_jp_CATCH = 9, /* jp_CATCH */
+ YYSYMBOL_jp_CHAR_TYPE = 10, /* jp_CHAR_TYPE */
+ YYSYMBOL_jp_CLASS = 11, /* jp_CLASS */
+ YYSYMBOL_jp_CONTINUE = 12, /* jp_CONTINUE */
+ YYSYMBOL_jp_DEFAULT = 13, /* jp_DEFAULT */
+ YYSYMBOL_jp_DO = 14, /* jp_DO */
+ YYSYMBOL_jp_DOUBLE_TYPE = 15, /* jp_DOUBLE_TYPE */
+ YYSYMBOL_jp_ELSE = 16, /* jp_ELSE */
+ YYSYMBOL_jp_EXTENDS = 17, /* jp_EXTENDS */
+ YYSYMBOL_jp_FINAL = 18, /* jp_FINAL */
+ YYSYMBOL_jp_FINALLY = 19, /* jp_FINALLY */
+ YYSYMBOL_jp_FLOAT_TYPE = 20, /* jp_FLOAT_TYPE */
+ YYSYMBOL_jp_FOR = 21, /* jp_FOR */
+ YYSYMBOL_jp_IF = 22, /* jp_IF */
+ YYSYMBOL_jp_IMPLEMENTS = 23, /* jp_IMPLEMENTS */
+ YYSYMBOL_jp_IMPORT = 24, /* jp_IMPORT */
+ YYSYMBOL_jp_INSTANCEOF = 25, /* jp_INSTANCEOF */
+ YYSYMBOL_jp_INT_TYPE = 26, /* jp_INT_TYPE */
+ YYSYMBOL_jp_INTERFACE = 27, /* jp_INTERFACE */
+ YYSYMBOL_jp_LONG_TYPE = 28, /* jp_LONG_TYPE */
+ YYSYMBOL_jp_NATIVE = 29, /* jp_NATIVE */
+ YYSYMBOL_jp_NEW = 30, /* jp_NEW */
+ YYSYMBOL_jp_PACKAGE = 31, /* jp_PACKAGE */
+ YYSYMBOL_jp_PRIVATE = 32, /* jp_PRIVATE */
+ YYSYMBOL_jp_PROTECTED = 33, /* jp_PROTECTED */
+ YYSYMBOL_jp_PUBLIC = 34, /* jp_PUBLIC */
+ YYSYMBOL_jp_RETURN = 35, /* jp_RETURN */
+ YYSYMBOL_jp_SHORT_TYPE = 36, /* jp_SHORT_TYPE */
+ YYSYMBOL_jp_STATIC = 37, /* jp_STATIC */
+ YYSYMBOL_jp_STRICTFP = 38, /* jp_STRICTFP */
+ YYSYMBOL_jp_SUPER = 39, /* jp_SUPER */
+ YYSYMBOL_jp_SWITCH = 40, /* jp_SWITCH */
+ YYSYMBOL_jp_SYNCHRONIZED = 41, /* jp_SYNCHRONIZED */
+ YYSYMBOL_jp_THIS = 42, /* jp_THIS */
+ YYSYMBOL_jp_THROW = 43, /* jp_THROW */
+ YYSYMBOL_jp_THROWS = 44, /* jp_THROWS */
+ YYSYMBOL_jp_TRANSIENT = 45, /* jp_TRANSIENT */
+ YYSYMBOL_jp_TRY = 46, /* jp_TRY */
+ YYSYMBOL_jp_VOID = 47, /* jp_VOID */
+ YYSYMBOL_jp_VOLATILE = 48, /* jp_VOLATILE */
+ YYSYMBOL_jp_WHILE = 49, /* jp_WHILE */
+ YYSYMBOL_jp_BOOLEANLITERAL = 50, /* jp_BOOLEANLITERAL */
+ YYSYMBOL_jp_CHARACTERLITERAL = 51, /* jp_CHARACTERLITERAL */
+ YYSYMBOL_jp_DECIMALINTEGERLITERAL = 52, /* jp_DECIMALINTEGERLITERAL */
+ YYSYMBOL_jp_FLOATINGPOINTLITERAL = 53, /* jp_FLOATINGPOINTLITERAL */
+ YYSYMBOL_jp_HEXINTEGERLITERAL = 54, /* jp_HEXINTEGERLITERAL */
+ YYSYMBOL_jp_NULLLITERAL = 55, /* jp_NULLLITERAL */
+ YYSYMBOL_jp_STRINGLITERAL = 56, /* jp_STRINGLITERAL */
+ YYSYMBOL_jp_NAME = 57, /* jp_NAME */
+ YYSYMBOL_jp_AND = 58, /* jp_AND */
+ YYSYMBOL_jp_ANDAND = 59, /* jp_ANDAND */
+ YYSYMBOL_jp_ANDEQUALS = 60, /* jp_ANDEQUALS */
+ YYSYMBOL_jp_BRACKETEND = 61, /* jp_BRACKETEND */
+ YYSYMBOL_jp_BRACKETSTART = 62, /* jp_BRACKETSTART */
+ YYSYMBOL_jp_CARROT = 63, /* jp_CARROT */
+ YYSYMBOL_jp_CARROTEQUALS = 64, /* jp_CARROTEQUALS */
+ YYSYMBOL_jp_COLON = 65, /* jp_COLON */
+ YYSYMBOL_jp_COMMA = 66, /* jp_COMMA */
+ YYSYMBOL_jp_CURLYEND = 67, /* jp_CURLYEND */
+ YYSYMBOL_jp_CURLYSTART = 68, /* jp_CURLYSTART */
+ YYSYMBOL_jp_DIVIDE = 69, /* jp_DIVIDE */
+ YYSYMBOL_jp_DIVIDEEQUALS = 70, /* jp_DIVIDEEQUALS */
+ YYSYMBOL_jp_DOLLAR = 71, /* jp_DOLLAR */
+ YYSYMBOL_jp_DOT = 72, /* jp_DOT */
+ YYSYMBOL_jp_EQUALS = 73, /* jp_EQUALS */
+ YYSYMBOL_jp_EQUALSEQUALS = 74, /* jp_EQUALSEQUALS */
+ YYSYMBOL_jp_EXCLAMATION = 75, /* jp_EXCLAMATION */
+ YYSYMBOL_jp_EXCLAMATIONEQUALS = 76, /* jp_EXCLAMATIONEQUALS */
+ YYSYMBOL_jp_GREATER = 77, /* jp_GREATER */
+ YYSYMBOL_jp_GTEQUALS = 78, /* jp_GTEQUALS */
+ YYSYMBOL_jp_GTGT = 79, /* jp_GTGT */
+ YYSYMBOL_jp_GTGTEQUALS = 80, /* jp_GTGTEQUALS */
+ YYSYMBOL_jp_GTGTGT = 81, /* jp_GTGTGT */
+ YYSYMBOL_jp_GTGTGTEQUALS = 82, /* jp_GTGTGTEQUALS */
+ YYSYMBOL_jp_LESLESEQUALS = 83, /* jp_LESLESEQUALS */
+ YYSYMBOL_jp_LESSTHAN = 84, /* jp_LESSTHAN */
+ YYSYMBOL_jp_LTEQUALS = 85, /* jp_LTEQUALS */
+ YYSYMBOL_jp_LTLT = 86, /* jp_LTLT */
+ YYSYMBOL_jp_MINUS = 87, /* jp_MINUS */
+ YYSYMBOL_jp_MINUSEQUALS = 88, /* jp_MINUSEQUALS */
+ YYSYMBOL_jp_MINUSMINUS = 89, /* jp_MINUSMINUS */
+ YYSYMBOL_jp_PAREEND = 90, /* jp_PAREEND */
+ YYSYMBOL_jp_PARESTART = 91, /* jp_PARESTART */
+ YYSYMBOL_jp_PERCENT = 92, /* jp_PERCENT */
+ YYSYMBOL_jp_PERCENTEQUALS = 93, /* jp_PERCENTEQUALS */
+ YYSYMBOL_jp_PIPE = 94, /* jp_PIPE */
+ YYSYMBOL_jp_PIPEEQUALS = 95, /* jp_PIPEEQUALS */
+ YYSYMBOL_jp_PIPEPIPE = 96, /* jp_PIPEPIPE */
+ YYSYMBOL_jp_PLUS = 97, /* jp_PLUS */
+ YYSYMBOL_jp_PLUSEQUALS = 98, /* jp_PLUSEQUALS */
+ YYSYMBOL_jp_PLUSPLUS = 99, /* jp_PLUSPLUS */
+ YYSYMBOL_jp_QUESTION = 100, /* jp_QUESTION */
+ YYSYMBOL_jp_SEMICOL = 101, /* jp_SEMICOL */
+ YYSYMBOL_jp_TILDE = 102, /* jp_TILDE */
+ YYSYMBOL_jp_TIMES = 103, /* jp_TIMES */
+ YYSYMBOL_jp_TIMESEQUALS = 104, /* jp_TIMESEQUALS */
+ YYSYMBOL_jp_ERROR = 105, /* jp_ERROR */
+ YYSYMBOL_YYACCEPT = 106, /* $accept */
+ YYSYMBOL_Goal = 107, /* Goal */
+ YYSYMBOL_Literal = 108, /* Literal */
+ YYSYMBOL_IntegerLiteral = 109, /* IntegerLiteral */
+ YYSYMBOL_Type = 110, /* Type */
+ YYSYMBOL_PrimitiveType = 111, /* PrimitiveType */
+ YYSYMBOL_ReferenceType = 112, /* ReferenceType */
+ YYSYMBOL_ClassOrInterfaceType = 113, /* ClassOrInterfaceType */
+ YYSYMBOL_ClassType = 114, /* ClassType */
+ YYSYMBOL_InterfaceType = 115, /* InterfaceType */
+ YYSYMBOL_ArrayType = 116, /* ArrayType */
+ YYSYMBOL_Name = 117, /* Name */
+ YYSYMBOL_SimpleName = 118, /* SimpleName */
+ YYSYMBOL_Identifier = 119, /* Identifier */
+ YYSYMBOL_QualifiedName = 120, /* QualifiedName */
+ YYSYMBOL_SimpleType = 121, /* SimpleType */
+ YYSYMBOL_CompilationUnit = 122, /* CompilationUnit */
+ YYSYMBOL_PackageDeclarationopt = 123, /* PackageDeclarationopt */
+ YYSYMBOL_ImportDeclarations = 124, /* ImportDeclarations */
+ YYSYMBOL_TypeDeclarations = 125, /* TypeDeclarations */
+ YYSYMBOL_PackageDeclaration = 126, /* PackageDeclaration */
+ YYSYMBOL_ImportDeclaration = 127, /* ImportDeclaration */
+ YYSYMBOL_SingleTypeImportDeclaration = 128, /* SingleTypeImportDeclaration */
+ YYSYMBOL_TypeImportOnDemandDeclaration = 129, /* TypeImportOnDemandDeclaration */
+ YYSYMBOL_TypeDeclaration = 130, /* TypeDeclaration */
+ YYSYMBOL_Modifiers = 131, /* Modifiers */
+ YYSYMBOL_Modifier = 132, /* Modifier */
+ YYSYMBOL_ClassHeader = 133, /* ClassHeader */
+ YYSYMBOL_ClassDeclaration = 134, /* ClassDeclaration */
+ YYSYMBOL_Modifiersopt = 135, /* Modifiersopt */
+ YYSYMBOL_Super = 136, /* Super */
+ YYSYMBOL_Interfaces = 137, /* Interfaces */
+ YYSYMBOL_InterfaceTypeList = 138, /* InterfaceTypeList */
+ YYSYMBOL_ClassBody = 139, /* ClassBody */
+ YYSYMBOL_ClassBodyDeclarations = 140, /* ClassBodyDeclarations */
+ YYSYMBOL_ClassBodyDeclaration = 141, /* ClassBodyDeclaration */
+ YYSYMBOL_ClassMemberDeclaration = 142, /* ClassMemberDeclaration */
+ YYSYMBOL_FieldDeclaration = 143, /* FieldDeclaration */
+ YYSYMBOL_VariableDeclarators = 144, /* VariableDeclarators */
+ YYSYMBOL_VariableDeclarator = 145, /* VariableDeclarator */
+ YYSYMBOL_VariableDeclaratorId = 146, /* VariableDeclaratorId */
+ YYSYMBOL_VariableInitializer = 147, /* VariableInitializer */
+ YYSYMBOL_MethodDeclaration = 148, /* MethodDeclaration */
+ YYSYMBOL_MethodHeader = 149, /* MethodHeader */
+ YYSYMBOL_Throwsopt = 150, /* Throwsopt */
+ YYSYMBOL_MethodDeclarator = 151, /* MethodDeclarator */
+ YYSYMBOL_FormalParameterListopt = 152, /* FormalParameterListopt */
+ YYSYMBOL_FormalParameterList = 153, /* FormalParameterList */
+ YYSYMBOL_FormalParameter = 154, /* FormalParameter */
+ YYSYMBOL_Throws = 155, /* Throws */
+ YYSYMBOL_ClassTypeList = 156, /* ClassTypeList */
+ YYSYMBOL_MethodBody = 157, /* MethodBody */
+ YYSYMBOL_StaticInitializer = 158, /* StaticInitializer */
+ YYSYMBOL_ConstructorDeclaration = 159, /* ConstructorDeclaration */
+ YYSYMBOL_ConstructorDeclarator = 160, /* ConstructorDeclarator */
+ YYSYMBOL_ConstructorBody = 161, /* ConstructorBody */
+ YYSYMBOL_ExplicitConstructorInvocationopt = 162, /* ExplicitConstructorInvocationopt */
+ YYSYMBOL_ExplicitConstructorInvocation = 163, /* ExplicitConstructorInvocation */
+ YYSYMBOL_InterfaceHeader = 164, /* InterfaceHeader */
+ YYSYMBOL_InterfaceDeclaration = 165, /* InterfaceDeclaration */
+ YYSYMBOL_ExtendsInterfacesopt = 166, /* ExtendsInterfacesopt */
+ YYSYMBOL_ExtendsInterfaces = 167, /* ExtendsInterfaces */
+ YYSYMBOL_InterfaceBody = 168, /* InterfaceBody */
+ YYSYMBOL_InterfaceMemberDeclarations = 169, /* InterfaceMemberDeclarations */
+ YYSYMBOL_InterfaceMemberDeclaration = 170, /* InterfaceMemberDeclaration */
+ YYSYMBOL_ConstantDeclaration = 171, /* ConstantDeclaration */
+ YYSYMBOL_AbstractMethodDeclaration = 172, /* AbstractMethodDeclaration */
+ YYSYMBOL_Semicols = 173, /* Semicols */
+ YYSYMBOL_ArrayInitializer = 174, /* ArrayInitializer */
+ YYSYMBOL_VariableInitializersOptional = 175, /* VariableInitializersOptional */
+ YYSYMBOL_VariableInitializers = 176, /* VariableInitializers */
+ YYSYMBOL_Block = 177, /* Block */
+ YYSYMBOL_BlockStatementsopt = 178, /* BlockStatementsopt */
+ YYSYMBOL_BlockStatements = 179, /* BlockStatements */
+ YYSYMBOL_BlockStatement = 180, /* BlockStatement */
+ YYSYMBOL_LocalVariableDeclarationStatement = 181, /* LocalVariableDeclarationStatement */
+ YYSYMBOL_LocalVariableDeclaration = 182, /* LocalVariableDeclaration */
+ YYSYMBOL_Statement = 183, /* Statement */
+ YYSYMBOL_StatementNoShortIf = 184, /* StatementNoShortIf */
+ YYSYMBOL_StatementWithoutTrailingSubstatement = 185, /* StatementWithoutTrailingSubstatement */
+ YYSYMBOL_EmptyStatement = 186, /* EmptyStatement */
+ YYSYMBOL_LabeledStatement = 187, /* LabeledStatement */
+ YYSYMBOL_LabeledStatementNoShortIf = 188, /* LabeledStatementNoShortIf */
+ YYSYMBOL_ExpressionStatement = 189, /* ExpressionStatement */
+ YYSYMBOL_StatementExpression = 190, /* StatementExpression */
+ YYSYMBOL_IfThenStatement = 191, /* IfThenStatement */
+ YYSYMBOL_IfThenElseStatement = 192, /* IfThenElseStatement */
+ YYSYMBOL_IfThenElseStatementNoShortIf = 193, /* IfThenElseStatementNoShortIf */
+ YYSYMBOL_SwitchStatement = 194, /* SwitchStatement */
+ YYSYMBOL_SwitchBlock = 195, /* SwitchBlock */
+ YYSYMBOL_SwitchLabelsopt = 196, /* SwitchLabelsopt */
+ YYSYMBOL_SwitchBlockStatementGroups = 197, /* SwitchBlockStatementGroups */
+ YYSYMBOL_SwitchBlockStatementGroup = 198, /* SwitchBlockStatementGroup */
+ YYSYMBOL_SwitchLabels = 199, /* SwitchLabels */
+ YYSYMBOL_SwitchLabel = 200, /* SwitchLabel */
+ YYSYMBOL_WhileStatement = 201, /* WhileStatement */
+ YYSYMBOL_WhileStatementNoShortIf = 202, /* WhileStatementNoShortIf */
+ YYSYMBOL_DoStatement = 203, /* DoStatement */
+ YYSYMBOL_ForStatement = 204, /* ForStatement */
+ YYSYMBOL_ForUpdateopt = 205, /* ForUpdateopt */
+ YYSYMBOL_ForInitopt = 206, /* ForInitopt */
+ YYSYMBOL_ForStatementNoShortIf = 207, /* ForStatementNoShortIf */
+ YYSYMBOL_Expressionopt = 208, /* Expressionopt */
+ YYSYMBOL_ForInit = 209, /* ForInit */
+ YYSYMBOL_ForUpdate = 210, /* ForUpdate */
+ YYSYMBOL_StatementExpressionList = 211, /* StatementExpressionList */
+ YYSYMBOL_AssertStatement = 212, /* AssertStatement */
+ YYSYMBOL_BreakStatement = 213, /* BreakStatement */
+ YYSYMBOL_Identifieropt = 214, /* Identifieropt */
+ YYSYMBOL_ContinueStatement = 215, /* ContinueStatement */
+ YYSYMBOL_ReturnStatement = 216, /* ReturnStatement */
+ YYSYMBOL_ThrowStatement = 217, /* ThrowStatement */
+ YYSYMBOL_SynchronizedStatement = 218, /* SynchronizedStatement */
+ YYSYMBOL_TryStatement = 219, /* TryStatement */
+ YYSYMBOL_Catchesopt = 220, /* Catchesopt */
+ YYSYMBOL_Catches = 221, /* Catches */
+ YYSYMBOL_CatchClause = 222, /* CatchClause */
+ YYSYMBOL_Finally = 223, /* Finally */
+ YYSYMBOL_Primary = 224, /* Primary */
+ YYSYMBOL_PrimaryNoNewArray = 225, /* PrimaryNoNewArray */
+ YYSYMBOL_ClassInstanceCreationExpression = 226, /* ClassInstanceCreationExpression */
+ YYSYMBOL_ClassBodyOpt = 227, /* ClassBodyOpt */
+ YYSYMBOL_ArgumentListopt = 228, /* ArgumentListopt */
+ YYSYMBOL_ArgumentList = 229, /* ArgumentList */
+ YYSYMBOL_ArrayCreationExpression = 230, /* ArrayCreationExpression */
+ YYSYMBOL_Dimsopt = 231, /* Dimsopt */
+ YYSYMBOL_DimExprs = 232, /* DimExprs */
+ YYSYMBOL_DimExpr = 233, /* DimExpr */
+ YYSYMBOL_Dims = 234, /* Dims */
+ YYSYMBOL_FieldAccess = 235, /* FieldAccess */
+ YYSYMBOL_MethodInvocation = 236, /* MethodInvocation */
+ YYSYMBOL_ArrayAccess = 237, /* ArrayAccess */
+ YYSYMBOL_PostfixExpression = 238, /* PostfixExpression */
+ YYSYMBOL_PostIncrementExpression = 239, /* PostIncrementExpression */
+ YYSYMBOL_PostDecrementExpression = 240, /* PostDecrementExpression */
+ YYSYMBOL_UnaryExpression = 241, /* UnaryExpression */
+ YYSYMBOL_PreIncrementExpression = 242, /* PreIncrementExpression */
+ YYSYMBOL_PreDecrementExpression = 243, /* PreDecrementExpression */
+ YYSYMBOL_UnaryExpressionNotPlusMinus = 244, /* UnaryExpressionNotPlusMinus */
+ YYSYMBOL_CastExpression = 245, /* CastExpression */
+ YYSYMBOL_MultiplicativeExpression = 246, /* MultiplicativeExpression */
+ YYSYMBOL_AdditiveExpression = 247, /* AdditiveExpression */
+ YYSYMBOL_ShiftExpression = 248, /* ShiftExpression */
+ YYSYMBOL_RelationalExpression = 249, /* RelationalExpression */
+ YYSYMBOL_EqualityExpression = 250, /* EqualityExpression */
+ YYSYMBOL_AndExpression = 251, /* AndExpression */
+ YYSYMBOL_ExclusiveOrExpression = 252, /* ExclusiveOrExpression */
+ YYSYMBOL_InclusiveOrExpression = 253, /* InclusiveOrExpression */
+ YYSYMBOL_ConditionalAndExpression = 254, /* ConditionalAndExpression */
+ YYSYMBOL_ConditionalOrExpression = 255, /* ConditionalOrExpression */
+ YYSYMBOL_ConditionalExpression = 256, /* ConditionalExpression */
+ YYSYMBOL_AssignmentExpression = 257, /* AssignmentExpression */
+ YYSYMBOL_Assignment = 258, /* Assignment */
+ YYSYMBOL_LeftHandSide = 259, /* LeftHandSide */
+ YYSYMBOL_AssignmentOperator = 260, /* AssignmentOperator */
+ YYSYMBOL_Expression = 261, /* Expression */
+ YYSYMBOL_ConstantExpression = 262, /* ConstantExpression */
+ YYSYMBOL_New = 263 /* New */
+};
+typedef enum yysymbol_kind_t yysymbol_kind_t;
+
+
+
+
+#ifdef short
+# undef short
+#endif
+
+/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
+ <limits.h> and (if available) <stdint.h> are included
+ so that the code can choose integer types of a good width. */
+
+#ifndef __PTRDIFF_MAX__
+# include <limits.h> /* INFRINGES ON USER NAME SPACE */
+# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+# include <stdint.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_STDINT_H
+# endif
+#endif
+
+/* Narrow types that promote to a signed type and that can represent a
+ signed or unsigned integer of at least N bits. In tables they can
+ save space and decrease cache pressure. Promoting to a signed type
+ helps avoid bugs in integer arithmetic. */
+
+#ifdef __INT_LEAST8_MAX__
+typedef __INT_LEAST8_TYPE__ yytype_int8;
+#elif defined YY_STDINT_H
+typedef int_least8_t yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef __INT_LEAST16_MAX__
+typedef __INT_LEAST16_TYPE__ yytype_int16;
+#elif defined YY_STDINT_H
+typedef int_least16_t yytype_int16;
+#else
+typedef short yytype_int16;
+#endif
+
+#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST8_TYPE__ yytype_uint8;
+#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
+ && UINT_LEAST8_MAX <= INT_MAX)
+typedef uint_least8_t yytype_uint8;
+#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
+typedef unsigned char yytype_uint8;
+#else
+typedef short yytype_uint8;
+#endif
+
+#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST16_TYPE__ yytype_uint16;
+#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
+ && UINT_LEAST16_MAX <= INT_MAX)
+typedef uint_least16_t yytype_uint16;
+#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
+typedef unsigned short yytype_uint16;
+#else
+typedef int yytype_uint16;
+#endif
+
+#ifndef YYPTRDIFF_T
+# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
+# define YYPTRDIFF_T __PTRDIFF_TYPE__
+# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
+# elif defined PTRDIFF_MAX
+# ifndef ptrdiff_t
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# endif
+# define YYPTRDIFF_T ptrdiff_t
+# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
+# else
+# define YYPTRDIFF_T long
+# define YYPTRDIFF_MAXIMUM LONG_MAX
+# endif
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM \
+ YY_CAST (YYPTRDIFF_T, \
+ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \
+ ? YYPTRDIFF_MAXIMUM \
+ : YY_CAST (YYSIZE_T, -1)))
+
+#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
+
+
+/* Stored state numbers (used for stacks). */
+typedef yytype_int16 yy_state_t;
+
+/* State numbers in computations. */
+typedef int yy_state_fast_t;
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+
+#ifndef YY_ATTRIBUTE_PURE
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+# define YY_ATTRIBUTE_PURE
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+# define YY_ATTRIBUTE_UNUSED
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END \
+ _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
+
+#define YY_ASSERT(E) ((void) (0 && (E)))
+
+#if 1
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's 'empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* 1 */
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yy_state_t yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYPTRDIFF_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / YYSIZEOF (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYPTRDIFF_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 23
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 2215
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 106
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 158
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 351
+/* YYNSTATES -- Number of states. */
+#define YYNSTATES 575
+
+/* YYMAXUTOK -- Last valid token kind. */
+#define YYMAXUTOK 360
+
+
+/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex, with out-of-bounds checking. */
+#define YYTRANSLATE(YYX) \
+ (0 <= (YYX) && (YYX) <= YYMAXUTOK \
+ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \
+ : YYSYMBOL_YYUNDEF)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex. */
+static const yytype_int8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105
+};
+
+#if YYDEBUG
+ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+static const yytype_int16 yyrline[] =
+{
+ 0, 180, 180, 189, 197, 205, 213, 221, 229, 238,
+ 246, 255, 263, 272, 277, 282, 287, 292, 297, 302,
+ 307, 313, 321, 330, 340, 349, 358, 366, 376, 382,
+ 389, 396, 402, 409, 418, 428, 438, 447, 455, 464,
+ 473, 479, 488, 494, 503, 509, 518, 530, 538, 547,
+ 559, 572, 580, 588, 597, 605, 614, 614, 614, 615,
+ 616, 616, 616, 616, 616, 616, 617, 620, 630, 639,
+ 648, 657, 667, 673, 682, 691, 700, 708, 717, 726,
+ 732, 741, 749, 757, 765, 774, 782, 791, 797, 805,
+ 814, 822, 831, 840, 849, 857, 866, 874, 882, 891,
+ 900, 910, 917, 927, 937, 944, 951, 954, 960, 970,
+ 980, 990, 996, 1006, 1016, 1026, 1035, 1045, 1056, 1066,
+ 1073, 1083, 1092, 1102, 1111, 1121, 1127, 1137, 1146, 1156,
+ 1166, 1173, 1182, 1191, 1200, 1209, 1217, 1226, 1235, 1245,
+ 1255, 1264, 1274, 1284, 1291, 1300, 1310, 1319, 1329, 1338,
+ 1345, 1355, 1364, 1374, 1383, 1392, 1402, 1412, 1421, 1431,
+ 1440, 1449, 1458, 1467, 1476, 1486, 1495, 1504, 1513, 1522,
+ 1532, 1541, 1550, 1559, 1568, 1577, 1586, 1595, 1604, 1613,
+ 1622, 1631, 1641, 1651, 1662, 1672, 1682, 1691, 1700, 1709,
+ 1718, 1727, 1736, 1746, 1756, 1766, 1776, 1783, 1790, 1797,
+ 1807, 1814, 1824, 1834, 1843, 1853, 1862, 1872, 1879, 1886,
+ 1893, 1901, 1908, 1918, 1925, 1935, 1945, 1952, 1962, 1971,
+ 1981, 1991, 2000, 2010, 2019, 2029, 2040, 2047, 2054, 2065,
+ 2075, 2085, 2095, 2104, 2114, 2121, 2131, 2140, 2150, 2157,
+ 2167, 2176, 2186, 2195, 2201, 2210, 2219, 2228, 2237, 2247,
+ 2257, 2264, 2274, 2281, 2291, 2300, 2310, 2319, 2328, 2337,
+ 2347, 2354, 2364, 2373, 2383, 2393, 2399, 2406, 2416, 2426,
+ 2436, 2447, 2457, 2468, 2478, 2489, 2499, 2509, 2518, 2527,
+ 2536, 2545, 2555, 2565, 2575, 2584, 2593, 2602, 2611, 2621,
+ 2631, 2641, 2650, 2659, 2668, 2678, 2687, 2696, 2703, 2712,
+ 2721, 2730, 2740, 2749, 2758, 2768, 2777, 2786, 2795, 2805,
+ 2814, 2823, 2832, 2841, 2850, 2860, 2869, 2878, 2888, 2897,
+ 2907, 2916, 2926, 2935, 2945, 2954, 2964, 2973, 2983, 2992,
+ 3002, 3011, 3021, 3031, 3041, 3050, 3060, 3069, 3078, 3087,
+ 3096, 3105, 3114, 3123, 3132, 3141, 3150, 3159, 3169, 3179,
+ 3189, 3198
+};
+#endif
+
+/** Accessing symbol of state STATE. */
+#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
+
+#if 1
+/* The user-facing name of the symbol whose (internal) number is
+ YYSYMBOL. No bounds checking. */
+static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
+
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "\"end of file\"", "error", "\"invalid token\"", "jp_ABSTRACT",
+ "jp_ASSERT", "jp_BOOLEAN_TYPE", "jp_BREAK", "jp_BYTE_TYPE", "jp_CASE",
+ "jp_CATCH", "jp_CHAR_TYPE", "jp_CLASS", "jp_CONTINUE", "jp_DEFAULT",
+ "jp_DO", "jp_DOUBLE_TYPE", "jp_ELSE", "jp_EXTENDS", "jp_FINAL",
+ "jp_FINALLY", "jp_FLOAT_TYPE", "jp_FOR", "jp_IF", "jp_IMPLEMENTS",
+ "jp_IMPORT", "jp_INSTANCEOF", "jp_INT_TYPE", "jp_INTERFACE",
+ "jp_LONG_TYPE", "jp_NATIVE", "jp_NEW", "jp_PACKAGE", "jp_PRIVATE",
+ "jp_PROTECTED", "jp_PUBLIC", "jp_RETURN", "jp_SHORT_TYPE", "jp_STATIC",
+ "jp_STRICTFP", "jp_SUPER", "jp_SWITCH", "jp_SYNCHRONIZED", "jp_THIS",
+ "jp_THROW", "jp_THROWS", "jp_TRANSIENT", "jp_TRY", "jp_VOID",
+ "jp_VOLATILE", "jp_WHILE", "jp_BOOLEANLITERAL", "jp_CHARACTERLITERAL",
+ "jp_DECIMALINTEGERLITERAL", "jp_FLOATINGPOINTLITERAL",
+ "jp_HEXINTEGERLITERAL", "jp_NULLLITERAL", "jp_STRINGLITERAL", "jp_NAME",
+ "jp_AND", "jp_ANDAND", "jp_ANDEQUALS", "jp_BRACKETEND",
+ "jp_BRACKETSTART", "jp_CARROT", "jp_CARROTEQUALS", "jp_COLON",
+ "jp_COMMA", "jp_CURLYEND", "jp_CURLYSTART", "jp_DIVIDE",
+ "jp_DIVIDEEQUALS", "jp_DOLLAR", "jp_DOT", "jp_EQUALS", "jp_EQUALSEQUALS",
+ "jp_EXCLAMATION", "jp_EXCLAMATIONEQUALS", "jp_GREATER", "jp_GTEQUALS",
+ "jp_GTGT", "jp_GTGTEQUALS", "jp_GTGTGT", "jp_GTGTGTEQUALS",
+ "jp_LESLESEQUALS", "jp_LESSTHAN", "jp_LTEQUALS", "jp_LTLT", "jp_MINUS",
+ "jp_MINUSEQUALS", "jp_MINUSMINUS", "jp_PAREEND", "jp_PARESTART",
+ "jp_PERCENT", "jp_PERCENTEQUALS", "jp_PIPE", "jp_PIPEEQUALS",
+ "jp_PIPEPIPE", "jp_PLUS", "jp_PLUSEQUALS", "jp_PLUSPLUS", "jp_QUESTION",
+ "jp_SEMICOL", "jp_TILDE", "jp_TIMES", "jp_TIMESEQUALS", "jp_ERROR",
+ "$accept", "Goal", "Literal", "IntegerLiteral", "Type", "PrimitiveType",
+ "ReferenceType", "ClassOrInterfaceType", "ClassType", "InterfaceType",
+ "ArrayType", "Name", "SimpleName", "Identifier", "QualifiedName",
+ "SimpleType", "CompilationUnit", "PackageDeclarationopt",
+ "ImportDeclarations", "TypeDeclarations", "PackageDeclaration",
+ "ImportDeclaration", "SingleTypeImportDeclaration",
+ "TypeImportOnDemandDeclaration", "TypeDeclaration", "Modifiers",
+ "Modifier", "ClassHeader", "ClassDeclaration", "Modifiersopt", "Super",
+ "Interfaces", "InterfaceTypeList", "ClassBody", "ClassBodyDeclarations",
+ "ClassBodyDeclaration", "ClassMemberDeclaration", "FieldDeclaration",
+ "VariableDeclarators", "VariableDeclarator", "VariableDeclaratorId",
+ "VariableInitializer", "MethodDeclaration", "MethodHeader", "Throwsopt",
+ "MethodDeclarator", "FormalParameterListopt", "FormalParameterList",
+ "FormalParameter", "Throws", "ClassTypeList", "MethodBody",
+ "StaticInitializer", "ConstructorDeclaration", "ConstructorDeclarator",
+ "ConstructorBody", "ExplicitConstructorInvocationopt",
+ "ExplicitConstructorInvocation", "InterfaceHeader",
+ "InterfaceDeclaration", "ExtendsInterfacesopt", "ExtendsInterfaces",
+ "InterfaceBody", "InterfaceMemberDeclarations",
+ "InterfaceMemberDeclaration", "ConstantDeclaration",
+ "AbstractMethodDeclaration", "Semicols", "ArrayInitializer",
+ "VariableInitializersOptional", "VariableInitializers", "Block",
+ "BlockStatementsopt", "BlockStatements", "BlockStatement",
+ "LocalVariableDeclarationStatement", "LocalVariableDeclaration",
+ "Statement", "StatementNoShortIf",
+ "StatementWithoutTrailingSubstatement", "EmptyStatement",
+ "LabeledStatement", "LabeledStatementNoShortIf", "ExpressionStatement",
+ "StatementExpression", "IfThenStatement", "IfThenElseStatement",
+ "IfThenElseStatementNoShortIf", "SwitchStatement", "SwitchBlock",
+ "SwitchLabelsopt", "SwitchBlockStatementGroups",
+ "SwitchBlockStatementGroup", "SwitchLabels", "SwitchLabel",
+ "WhileStatement", "WhileStatementNoShortIf", "DoStatement",
+ "ForStatement", "ForUpdateopt", "ForInitopt", "ForStatementNoShortIf",
+ "Expressionopt", "ForInit", "ForUpdate", "StatementExpressionList",
+ "AssertStatement", "BreakStatement", "Identifieropt",
+ "ContinueStatement", "ReturnStatement", "ThrowStatement",
+ "SynchronizedStatement", "TryStatement", "Catchesopt", "Catches",
+ "CatchClause", "Finally", "Primary", "PrimaryNoNewArray",
+ "ClassInstanceCreationExpression", "ClassBodyOpt", "ArgumentListopt",
+ "ArgumentList", "ArrayCreationExpression", "Dimsopt", "DimExprs",
+ "DimExpr", "Dims", "FieldAccess", "MethodInvocation", "ArrayAccess",
+ "PostfixExpression", "PostIncrementExpression",
+ "PostDecrementExpression", "UnaryExpression", "PreIncrementExpression",
+ "PreDecrementExpression", "UnaryExpressionNotPlusMinus",
+ "CastExpression", "MultiplicativeExpression", "AdditiveExpression",
+ "ShiftExpression", "RelationalExpression", "EqualityExpression",
+ "AndExpression", "ExclusiveOrExpression", "InclusiveOrExpression",
+ "ConditionalAndExpression", "ConditionalOrExpression",
+ "ConditionalExpression", "AssignmentExpression", "Assignment",
+ "LeftHandSide", "AssignmentOperator", "Expression", "ConstantExpression",
+ "New", YY_NULLPTR
+};
+
+static const char *
+yysymbol_name (yysymbol_kind_t yysymbol)
+{
+ return yytname[yysymbol];
+}
+#endif
+
+#ifdef YYPRINT
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+ (internal) symbol number NUM (which must be that of a token). */
+static const yytype_int16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
+ 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
+ 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
+ 345, 346, 347, 348, 349, 350, 351, 352, 353, 354,
+ 355, 356, 357, 358, 359, 360
+};
+#endif
+
+#define YYPACT_NINF (-503)
+
+#define yypact_value_is_default(Yyn) \
+ ((Yyn) == YYPACT_NINF)
+
+#define YYTABLE_NINF (-336)
+
+#define yytable_value_is_error(Yyn) \
+ 0
+
+ /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+static const yytype_int16 yypact[] =
+{
+ 159, 1039, 236, -503, -503, -503, -503, -503, -503, -503,
+ -503, -503, -503, -503, -503, -503, 186, -503, 56, -503,
+ -503, -503, 178, -503, 35, -503, 21, -503, 248, 1039,
+ 273, -503, -503, -503, -503, -503, -503, -503, 78, -503,
+ -503, -503, -503, -503, -503, -503, -503, -503, -503, -503,
+ -503, -503, 2088, -503, 32, -503, 16, 245, -503, 28,
+ -503, -503, 1039, 1039, -503, 80, 206, -503, 129, 129,
+ 1039, 221, 228, 194, -503, -503, 225, -503, -503, 234,
+ 164, 206, -503, -503, -503, -503, -503, -503, -503, 1039,
+ -503, 1039, 233, -503, -503, 739, -503, -503, -503, -503,
+ -49, -503, -503, -503, 1116, -503, -503, 1276, -503, 129,
+ 129, 40, -503, -503, -503, 122, 212, 265, -503, 215,
+ -503, -503, 219, 739, -503, 222, 224, -503, -503, -503,
+ 1820, 129, 129, 1627, 237, 238, -503, 1820, 241, 239,
+ 242, 283, 1820, 233, 266, -503, -503, -503, -503, -503,
+ -503, -503, 1820, 1820, 1820, -503, -503, -503, 129, 284,
+ 476, 293, 2067, -503, 349, -503, 296, 1366, -503, -503,
+ 264, -503, -503, -503, -503, -503, 268, -503, -503, -503,
+ -503, -503, -503, -503, -503, -503, -503, -503, -503, -503,
+ 294, 305, 72, -503, 2070, 88, 2084, 121, 130, 148,
+ -503, -503, -503, 2111, 1039, 281, 133, 281, -25, -503,
+ 126, 133, 314, 315, 315, 921, 1039, 308, -503, -503,
+ -503, -503, 277, -503, 1820, 1820, 1820, 1820, 1820, 317,
+ 284, 545, -503, -503, 121, -503, -503, -503, -503, -503,
+ -503, -503, 73, 124, 163, 59, 196, 323, 319, 290,
+ 324, 18, -503, -503, -503, -30, -503, 285, 286, 242,
+ 342, 1941, 1820, 291, -503, 129, 1820, 1820, 129, 292,
+ 385, 1820, 96, -503, -503, -503, 310, -503, -503, 329,
+ 387, 1085, 3, 1820, 1627, 129, -503, -503, -503, -503,
+ 175, 1820, -503, -503, -503, -503, -503, -503, -503, -503,
+ -503, -503, -503, -503, -503, -503, 1820, 339, 339, 311,
+ 921, 343, -503, 129, -503, 344, 1766, -503, -503, 346,
+ 1039, 313, 347, -503, -503, 353, -503, 307, -503, -503,
+ -503, 6, 545, 326, -503, -503, 1820, 1820, 1820, 1820,
+ 1820, 1820, 1820, 1820, 1039, 1820, 1820, 1820, 1820, 1820,
+ 1820, 1820, 1820, 1820, 1820, 1820, 1820, 1820, -503, -503,
+ -503, 330, 2067, -503, -503, 327, -503, 354, 334, -503,
+ 345, 335, 340, 348, -503, 351, 416, 232, -503, 356,
+ -503, -503, 376, -503, 357, 377, -503, -503, 329, -503,
+ 358, 390, -503, 1085, 339, -503, 154, 339, 154, 1820,
+ 362, -503, -503, -503, 1766, -503, -503, -503, -503, 129,
+ -503, 2088, 1039, 1456, -503, 363, 70, 93, 1874, -503,
+ -503, -503, 73, 73, 124, 124, 124, -503, 163, 163,
+ 163, 163, 59, 59, 196, 323, 319, 290, 324, 383,
+ 360, 1820, 1820, 1995, 1699, 1820, 386, 233, 1820, 2088,
+ 233, -503, -503, 1627, -503, -503, 1820, 1820, -503, 394,
+ -503, -503, 315, -503, -503, -503, 369, -503, -503, 396,
+ 404, 410, -503, -503, 26, 113, -503, 407, 1820, 1874,
+ -503, 1820, -503, 391, 374, -503, 393, 395, 397, 411,
+ -503, 466, 471, -503, -503, -503, -503, 399, -503, -503,
+ -503, 400, 401, -503, -503, -503, 402, -503, 206, -503,
+ 1766, 1820, 1820, -503, -503, -503, -503, 403, 1995, 1941,
+ 1820, 1820, 1699, 1627, -503, 34, -503, 233, -503, -503,
+ -503, -503, 405, 412, -503, 413, -503, 354, 406, 418,
+ 421, -503, -503, 1820, 429, 430, -503, 1186, -503, -503,
+ 419, 422, 1627, 1820, 1699, 1699, -503, 447, -503, -503,
+ 1555, -503, -503, -503, -503, 423, 497, -503, -503, 1995,
+ 1699, 432, -503, 1699, -503
+};
+
+ /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE does not specify something else to do. Zero
+ means the default is an error. */
+static const yytype_int16 yydefact[] =
+{
+ 40, 0, 0, 2, 42, 41, 20, 13, 17, 19,
+ 18, 15, 16, 14, 38, 31, 0, 37, 0, 28,
+ 30, 29, 0, 1, 44, 32, 0, 46, 0, 0,
+ 72, 43, 47, 48, 34, 35, 33, 36, 0, 60,
+ 61, 62, 58, 57, 56, 59, 66, 63, 64, 65,
+ 53, 45, 73, 54, 0, 51, 0, 125, 52, 0,
+ 49, 55, 0, 0, 79, 0, 0, 68, 0, 0,
+ 0, 0, 126, 0, 24, 74, 23, 25, 76, 75,
+ 72, 0, 70, 69, 67, 123, 127, 130, 124, 0,
+ 50, 0, 59, 78, 84, 0, 80, 81, 85, 86,
+ 0, 82, 83, 71, 72, 128, 77, 72, 114, 38,
+ 0, 11, 12, 21, 22, 23, 28, 101, 96, 97,
+ 113, 129, 134, 0, 138, 0, 136, 131, 132, 133,
+ 0, 226, 226, 0, 0, 0, 350, 216, 0, 0,
+ 63, 243, 0, 0, 0, 5, 6, 9, 4, 10,
+ 8, 7, 0, 0, 0, 182, 242, 3, 0, 22,
+ 333, 30, 73, 155, 0, 170, 0, 72, 151, 153,
+ 0, 154, 159, 171, 160, 172, 0, 161, 162, 173,
+ 163, 174, 164, 181, 175, 176, 177, 179, 178, 180,
+ 277, 240, 245, 241, 246, 247, 248, 0, 189, 190,
+ 187, 188, 186, 0, 0, 0, 101, 92, 0, 88,
+ 90, 101, 0, 26, 27, 72, 0, 0, 102, 98,
+ 135, 140, 139, 137, 0, 0, 0, 0, 0, 37,
+ 0, 278, 245, 247, 291, 280, 281, 298, 284, 285,
+ 288, 294, 302, 305, 309, 315, 318, 320, 322, 324,
+ 326, 328, 330, 348, 331, 0, 227, 0, 0, 0,
+ 0, 213, 0, 0, 217, 0, 0, 0, 0, 0,
+ 234, 0, 278, 246, 248, 290, 0, 289, 92, 158,
+ 0, 0, 0, 252, 0, 0, 148, 152, 156, 185,
+ 0, 0, 283, 282, 345, 346, 338, 336, 343, 344,
+ 342, 341, 339, 347, 340, 337, 0, 37, 24, 0,
+ 72, 0, 100, 0, 87, 0, 0, 99, 265, 0,
+ 0, 0, 106, 107, 111, 110, 119, 115, 141, 293,
+ 287, 37, 278, 0, 286, 292, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 223, 225,
+ 228, 0, 0, 219, 221, 0, 214, 218, 0, 229,
+ 268, 0, 0, 269, 230, 0, 0, 232, 236, 0,
+ 244, 279, 0, 351, 0, 253, 254, 183, 157, 270,
+ 267, 0, 332, 0, 260, 262, 0, 260, 0, 252,
+ 0, 104, 89, 93, 143, 91, 95, 94, 266, 0,
+ 117, 72, 0, 72, 116, 0, 26, 27, 244, 300,
+ 301, 299, 304, 303, 307, 308, 306, 314, 311, 313,
+ 310, 312, 316, 317, 319, 321, 323, 325, 327, 0,
+ 0, 0, 216, 0, 0, 252, 0, 0, 252, 72,
+ 0, 233, 237, 0, 275, 271, 0, 252, 276, 0,
+ 256, 263, 261, 258, 257, 259, 0, 103, 146, 0,
+ 144, 109, 108, 112, 0, 243, 120, 0, 0, 0,
+ 296, 0, 224, 0, 0, 222, 0, 0, 0, 30,
+ 193, 0, 159, 166, 167, 168, 169, 0, 200, 196,
+ 231, 0, 0, 239, 207, 255, 0, 264, 250, 142,
+ 145, 252, 252, 118, 295, 297, 329, 0, 211, 213,
+ 0, 0, 0, 0, 273, 198, 274, 0, 272, 251,
+ 249, 147, 0, 0, 209, 0, 212, 220, 0, 0,
+ 0, 184, 194, 0, 0, 0, 201, 72, 203, 238,
+ 0, 0, 0, 216, 0, 0, 349, 0, 206, 197,
+ 202, 204, 122, 121, 210, 0, 0, 208, 205, 211,
+ 0, 0, 195, 0, 215
+};
+
+ /* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -503, -503, -503, -503, -85, 2, 181, -41, -198, -45,
+ -87, -1, 431, 14, -503, -503, -503, -503, -503, -503,
+ -503, -503, -503, -503, 448, -81, -47, -503, 7, -23,
+ -503, 462, -503, -64, -503, -503, -503, 425, -146, 217,
+ 123, -391, -503, 427, -101, 424, 230, -503, -360, -503,
+ -503, -503, -503, -503, -503, -503, -503, -503, -503, 439,
+ -503, -503, -503, -503, -503, -503, -503, -503, -110, -503,
+ -503, -77, 138, -12, -163, -503, -250, -13, -421, -414,
+ -503, -503, -503, -503, -252, -503, -503, -503, -503, -503,
+ -503, -503, -503, -503, 5, -503, -503, -503, -503, -16,
+ 36, -503, -418, -503, -503, -502, -503, -503, 440, -503,
+ -503, -503, -503, -503, -503, -503, 179, -503, -503, -503,
+ -54, -503, -341, -503, -503, -149, 255, -136, 102, 652,
+ 101, 688, 145, 157, 201, -98, 289, 338, -384, -503,
+ -59, -58, -92, -57, 213, 226, 218, 223, 227, -503,
+ 95, 274, 350, -503, -503, 660, -503, -503
+};
+
+ /* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 2, 156, 157, 158, 229, 112, 113, 75, 78,
+ 230, 231, 19, 20, 21, 22, 3, 4, 24, 30,
+ 5, 31, 32, 33, 51, 52, 53, 54, 163, 164,
+ 65, 66, 79, 67, 80, 96, 97, 98, 208, 209,
+ 210, 405, 99, 100, 217, 206, 321, 322, 323, 218,
+ 325, 119, 101, 102, 117, 327, 413, 476, 57, 58,
+ 71, 72, 88, 104, 127, 128, 129, 222, 406, 469,
+ 470, 165, 166, 167, 168, 169, 170, 171, 491, 172,
+ 173, 174, 493, 175, 176, 177, 178, 494, 179, 499,
+ 545, 525, 546, 547, 548, 180, 495, 181, 182, 535,
+ 365, 496, 263, 366, 536, 367, 183, 184, 257, 185,
+ 186, 187, 188, 189, 376, 377, 378, 451, 190, 191,
+ 232, 530, 384, 385, 193, 415, 394, 395, 214, 194,
+ 233, 196, 234, 235, 236, 237, 238, 239, 240, 241,
+ 242, 243, 244, 245, 246, 247, 248, 249, 250, 251,
+ 252, 253, 254, 203, 306, 386, 557, 204
+};
+
+ /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule whose
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+static const yytype_int16 yytable[] =
+{
+ 18, 82, 83, 17, 287, 61, 309, 56, 114, 364,
+ 110, 363, 279, 468, 34, 108, 537, 103, 324, 107,
+ 159, 74, 77, 120, 484, 86, 162, 68, 38, 77,
+ 492, 17, 34, 383, 480, 357, 114, 55, 110, 34,
+ 36, 313, 543, 69, 105, 35, 106, 544, 77, 62,
+ 77, 472, 118, 192, 275, 63, 277, 95, 466, 29,
+ 15, 76, 76, 35, 17, 17, 270, 537, 212, 76,
+ 35, 358, 17, 36, 16, 114, 314, 285, 15, 192,
+ 159, 123, 84, 85, 344, 15, 162, 55, 76, 502,
+ 76, 17, 16, 17, 115, 515, -260, 111, 265, 16,
+ 64, 541, 212, 63, 497, 312, 160, 501, 492, 111,
+ 317, 122, -37, 192, 355, 61, 506, 511, 356, 531,
+ 260, 161, 115, 205, 207, 111, 329, 330, 26, 334,
+ 335, 73, 319, 566, 567, 565, 345, 346, -192, 388,
+ 492, 492, 336, 347, 348, 256, 256, 161, 64, 572,
+ 59, 272, 574, 272, -191, 319, 492, 27, 281, 492,
+ -261, 115, -192, 308, 111, 337, 160, 39, 282, 111,
+ 532, 533, 278, -192, 159, 74, 338, 216, -191, 60,
+ 362, 161, 40, 479, 212, 268, 15, 283, 315, -191,
+ 1, 485, 320, 41, 26, 311, 42, 43, 44, 316,
+ 16, 92, 46, 76, 512, 47, 307, 192, 195, 48,
+ 292, 339, 49, 213, 473, 76, 319, 389, 17, -280,
+ 293, 340, 404, 272, 272, 332, 272, 272, 331, -280,
+ 192, 93, 15, 114, 195, 409, 23, -281, 419, 420,
+ 421, 375, 341, 25, 342, 460, 16, -281, 464, 343,
+ 28, -235, 197, 428, 429, 430, 431, 114, 461, 37,
+ 160, 461, 70, 111, 198, 50, 364, 364, 195, 363,
+ 349, 387, 350, -39, 64, 114, 39, 285, 197, 370,
+ 422, 423, 373, 424, 425, 426, 463, 320, 465, 87,
+ 198, 40, 432, 433, 89, 90, 36, 26, 161, 278,
+ 91, 107, 41, 215, 390, 42, 43, 44, 199, 216,
+ 45, 46, 197, 265, 47, 61, 219, 364, 48, 115,
+ 220, 49, 111, 221, 198, 223, 159, 278, 261, 262,
+ 266, 213, 162, 267, 199, 272, 272, 272, 272, 272,
+ 272, 272, 272, 115, 272, 272, 272, 272, 272, 272,
+ 272, 272, 272, 272, 272, 268, 280, 271, 284, 192,
+ 68, 115, 195, 286, 111, 288, 290, 291, 199, 289,
+ 500, 74, 310, 503, 50, 318, 326, 319, 328, 212,
+ 514, 351, 352, 354, 353, 195, 359, 360, 320, 192,
+ 192, 361, 369, 374, 375, 313, 200, 287, 381, 192,
+ 380, 393, 399, 410, 401, 403, 197, 408, 414, 396,
+ 398, 76, 160, 411, 17, 111, 418, 272, 198, 412,
+ 443, 441, 200, 278, 444, 446, 320, 161, 442, 197,
+ 447, 490, 159, 416, 417, 450, 445, 454, 362, 448,
+ 504, 198, 449, 456, 529, 201, 453, 455, 481, 457,
+ 549, 458, 467, 478, 498, 507, 200, 202, 489, 508,
+ 159, 482, 199, 509, 192, 192, 162, 161, 192, 192,
+ 510, 201, 315, 159, 513, 518, 522, 272, 272, 162,
+ 272, 517, 523, 202, 519, 199, 520, -165, 521, 524,
+ 526, 527, 528, 192, 558, 550, 462, 559, 192, 462,
+ 192, 192, 551, 552, 534, 201, 192, 553, 554, 387,
+ 542, 555, 568, 570, 195, 192, 192, 202, 160, 192,
+ 562, 111, 573, 563, 569, 427, 116, 81, 94, 124,
+ 402, 125, 471, -23, 211, 560, 489, 161, 281, 564,
+ 400, 490, 504, 126, 195, 195, 160, -23, 282, 111,
+ 200, 477, 561, 571, 195, 538, 452, 542, 197, 160,
+ 564, 161, 111, 397, 434, -278, 161, 283, 489, 489,
+ 198, 436, 258, 200, 161, -278, 516, 437, 435, 0,
+ 392, 0, 438, 0, 489, 0, 0, 489, 197, 197,
+ 0, 0, 0, 0, 0, 0, 0, 0, 197, 201,
+ 198, 198, 0, 0, 0, -333, 0, 281, 0, -333,
+ 198, 202, 0, 0, 199, -333, 0, 282, -333, 195,
+ 195, 0, 201, 195, 195, -333, 0, -333, -333, 0,
+ 0, 0, 0, -333, 202, 0, 283, 0, -333, 0,
+ -333, 0, 0, -333, 199, 199, 0, 0, 195, -333,
+ 0, 0, 0, 195, 199, 195, 195, 0, 0, 0,
+ 0, 195, 0, 197, 197, 0, 0, 197, 197, 0,
+ 195, 195, 0, 0, 195, 198, 198, 0, 0, 198,
+ 198, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 197, 0, 0, 0, 0, 197, 0, 197,
+ 197, 0, 200, 0, 198, 197, 0, 0, 0, 198,
+ 0, 198, 198, 0, 197, 197, 0, 198, 197, 199,
+ 199, 0, 0, 199, 199, 0, 198, 198, 0, 0,
+ 198, 0, 200, 200, 0, 0, 0, 0, 0, 0,
+ 0, 0, 200, 0, 6, 0, 7, 0, 199, 8,
+ 68, 201, 0, 199, 9, 199, 199, 0, 0, 10,
+ 0, 199, 0, 202, 0, 11, 69, 12, 0, 0,
+ 199, 199, 0, 0, 199, 13, 0, 0, 0, 0,
+ 0, 201, 201, 0, 0, 0, 109, 0, 0, 0,
+ 255, 201, 0, 202, 202, 0, 15, 264, 0, 0,
+ 0, 0, 269, 202, 273, 0, 273, 200, 200, 0,
+ 16, 200, 200, 276, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 200, 0, 0, 0,
+ 274, 200, 274, 200, 200, 0, 0, 0, 0, 200,
+ 0, 0, 0, 0, 0, 0, 201, 201, 200, 200,
+ 201, 201, 200, 0, 0, 0, 0, 0, 202, 202,
+ 0, 0, 202, 202, 0, 0, 273, 273, 0, 273,
+ 273, 0, 0, 0, 0, 201, 333, 0, 0, 0,
+ 201, 0, 201, 201, 0, 0, 0, 202, 201, 0,
+ 0, 0, 202, 0, 202, 202, 0, 201, 201, 0,
+ 202, 201, 274, 274, 0, 274, 274, 0, 0, 202,
+ 202, 0, 368, 202, 39, 0, 371, 372, 0, 0,
+ 0, 379, 0, 0, 0, 0, 0, 0, 0, 40,
+ 0, 382, 0, 0, 0, 0, 0, 0, 0, 0,
+ 41, 391, 0, 42, 43, 44, 0, 0, 45, 46,
+ 0, 0, 47, 0, 0, 0, 48, 0, 0, 49,
+ 0, 0, 0, 0, 0, 0, 407, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 273, 273,
+ 273, 273, 273, 273, 273, 273, 0, 273, 273, 273,
+ 273, 273, 273, 273, 273, 273, 273, 273, 0, 0,
+ 0, -105, 0, 0, 0, 0, 439, 440, 0, 0,
+ 0, 0, 0, 0, 274, 274, 274, 274, 274, 274,
+ 274, 274, 0, 274, 274, 274, 274, 274, 274, 274,
+ 274, 274, 274, 274, 6, 0, 7, 0, 0, 8,
+ 0, 0, 0, 459, 9, 0, 0, 0, 0, 10,
+ 0, 0, 0, 0, 407, 11, 0, 12, 0, 0,
+ 273, 0, 0, 0, 0, 13, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 14, 0, 0, 0,
+ 6, 0, 7, 0, 0, 8, 15, 0, 0, 0,
+ 9, 483, 264, 0, 0, 10, 274, 0, 0, 0,
+ 16, 11, 0, 12, 0, 136, 505, 0, 0, 39,
+ 0, 13, 0, 0, 138, 0, 0, 141, 0, 0,
+ 273, 273, 14, 273, 40, 145, 146, 147, 148, 149,
+ 150, 151, 15, 0, 0, 41, 318, 0, 42, 43,
+ 44, 0, 0, 45, 46, 0, 16, 47, 0, 0,
+ 224, 48, 0, 0, 49, 0, 274, 274, 0, 274,
+ 407, 0, 225, 0, 152, 0, 226, 0, 0, 0,
+ 539, 540, 227, 121, 154, 0, 0, 228, 0, 39,
+ 130, 6, 131, 7, 543, 0, 8, 0, 132, 544,
+ 133, 9, 0, 556, 40, 0, 10, 134, 135, 0,
+ 0, 0, 11, 264, 12, 41, 136, 0, 42, 43,
+ 44, 137, 13, 45, 46, 138, 139, 140, 141, 142,
+ 0, 48, 143, 14, 49, 144, 145, 146, 147, 148,
+ 149, 150, 151, 15, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, -199, 107, 0, 0, 16, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 152, 0, 153, 0, 39,
+ 130, 6, 131, 7, 0, 154, 8, 155, 132, 0,
+ 133, 9, 0, 0, 40, 0, 10, 134, 135, 0,
+ 0, 0, 11, 0, 12, 41, 136, 0, 42, 43,
+ 44, 137, 13, 45, 46, 138, 139, 140, 141, 142,
+ 0, 48, 143, 14, 49, 144, 145, 146, 147, 148,
+ 149, 150, 151, 15, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, -149, 107, 0, 0, 16, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 152, 0, 153, 0, 39,
+ 130, 6, 131, 7, 0, 154, 8, 155, 132, 0,
+ 133, 9, 0, 0, 40, 0, 10, 134, 135, 0,
+ 0, 0, 11, 0, 12, 41, 136, 0, 42, 43,
+ 44, 137, 13, 45, 46, 138, 139, 140, 141, 142,
+ 0, 48, 143, 14, 49, 144, 145, 146, 147, 148,
+ 149, 150, 151, 15, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, -150, 107, 0, 0, 16, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 152, 0, 153, 0, 39,
+ 130, 6, 131, 7, 0, 154, 8, 155, 132, 0,
+ 133, 9, 0, 0, 40, 0, 10, 134, 135, 0,
+ 0, 0, 11, 0, 12, 41, 136, 0, 42, 43,
+ 44, 137, 13, 45, 46, 474, 139, 140, 475, 142,
+ 0, 48, 143, 14, 49, 144, 145, 146, 147, 148,
+ 149, 150, 151, 15, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, -149, 107, 0, 0, 16, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 152, 0, 153, 0, 0,
+ 0, 0, 0, 0, 0, 154, 0, 155, 39, 130,
+ 6, 131, 7, 0, 0, 8, -72, 132, 0, 133,
+ 9, 0, 0, 40, 0, 10, 134, 135, 0, 0,
+ 0, 11, 0, 12, 41, 136, 0, 42, 43, 44,
+ 137, 13, 45, 46, 138, 139, 140, 141, 142, 0,
+ 48, 143, 14, 49, 144, 145, 146, 147, 148, 149,
+ 150, 151, 15, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 107, 0, 0, 16, 0, 0, 0,
+ 0, 130, 6, 131, 7, 0, 0, 8, 0, 132,
+ 0, 133, 9, 0, 152, 0, 153, 10, 134, 135,
+ 0, 0, 0, 11, 154, 12, 155, 136, 0, 0,
+ 0, 0, 137, 13, 0, 0, 138, 139, 259, 141,
+ 142, 0, 0, 143, 14, 0, 144, 145, 146, 147,
+ 148, 149, 150, 151, 15, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 107, 0, 0, 16, 0,
+ 0, 0, 0, 130, 6, 131, 7, 0, 0, 8,
+ 0, 132, 0, 133, 9, 0, 152, 0, 153, 10,
+ 486, 487, 0, 0, 0, 11, 154, 12, 155, 136,
+ 0, 0, 0, 0, 137, 13, 0, 0, 138, 139,
+ 259, 141, 142, 0, 0, 143, 14, 0, 488, 145,
+ 146, 147, 148, 149, 150, 151, 15, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 107, 0, 0,
+ 16, 6, 0, 7, 0, 0, 8, 0, 0, 0,
+ 0, 9, 0, 0, 0, 0, 10, 0, 152, 0,
+ 153, 0, 11, 0, 12, 0, 136, 0, 154, 0,
+ 155, 0, 13, 0, 0, 138, 0, 0, 141, 0,
+ 0, 0, 0, 14, 0, 0, 145, 146, 147, 148,
+ 149, 150, 151, 15, 0, 6, 0, 7, 0, 0,
+ 8, 0, 0, 0, 404, 9, 0, 16, 0, 0,
+ 10, 224, 0, 0, 0, 0, 11, 0, 12, 0,
+ 136, 0, 0, 225, 0, 152, 13, 226, 0, 138,
+ 0, 0, 141, 227, 0, 154, 0, 14, 228, 0,
+ 145, 146, 147, 148, 149, 150, 151, 15, 0, 6,
+ 0, 7, 0, 0, 8, 0, 0, 0, 0, 9,
+ 0, 16, 0, 0, 10, 224, 0, 0, 0, 0,
+ 11, 0, 12, 0, 136, 0, 0, 225, 0, 152,
+ 13, 226, 0, 138, 0, 0, 141, 227, 0, 154,
+ 0, 14, 228, 0, 145, 146, 147, 148, 149, 150,
+ 151, 15, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 39, 16, 6, 0, 7, 224,
+ 0, 8, 0, 0, 0, 0, 9, 0, 0, 40,
+ 0, 10, 0, 0, 0, 226, 0, 11, 0, 12,
+ 41, 136, 0, 42, 43, 44, 228, 13, 45, 46,
+ 138, 0, 47, 141, 0, 0, 48, 0, 14, 49,
+ 0, 145, 146, 147, 148, 149, 150, 151, 15, 0,
+ 6, 0, 7, 0, 0, 8, 0, 0, 0, 0,
+ 9, 0, 16, 0, 0, 10, 0, 0, 0, 0,
+ 0, 11, 0, 12, 0, 136, 0, 0, 0, 0,
+ 152, 13, 153, 0, 138, 0, 0, 141, 0, 0,
+ 154, 0, 14, 0, 0, 145, 146, 147, 148, 149,
+ 150, 151, 15, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 16, 0, 0, 0,
+ 39, 0, 6, 0, 7, 0, 0, 8, 0, 0,
+ 0, 0, 9, 0, 152, 40, 153, 10, 0, 0,
+ 0, 39, 0, 11, 154, 12, 41, 0, 0, 42,
+ 43, 44, 0, 13, 45, 46, 40, 0, 47, 0,
+ 0, 0, 48, 0, 14, 49, 0, 41, 0, 0,
+ 42, 43, 44, 0, 15, 45, 46, 0, 0, 47,
+ -334, 0, 0, 48, -334, 0, 49, 0, 16, 0,
+ -334, 0, 0, -334, -335, 0, 0, 0, -335, 0,
+ -334, 0, -334, -334, -335, 0, 0, -335, -334, 0,
+ 0, 0, 0, -334, -335, -334, -335, -335, -334, 0,
+ 0, 294, -335, 0, -334, 295, 0, -335, 0, -335,
+ 0, 296, -335, 0, 297, 0, 0, 0, -335, 0,
+ 0, 298, 0, 299, 300, 0, 0, 0, 0, 301,
+ 0, 0, 0, 0, 302, 0, 303, 0, 0, 304,
+ 0, 0, 0, 0, 0, 305
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 1, 65, 66, 1, 167, 52, 204, 30, 95, 261,
+ 95, 261, 158, 404, 11, 92, 518, 81, 216, 68,
+ 107, 62, 63, 100, 442, 70, 107, 11, 29, 70,
+ 444, 29, 11, 30, 418, 65, 123, 30, 123, 11,
+ 26, 66, 8, 27, 89, 42, 91, 13, 89, 17,
+ 91, 411, 101, 107, 152, 23, 154, 80, 399, 24,
+ 57, 62, 63, 42, 62, 63, 143, 569, 62, 70,
+ 42, 101, 70, 59, 71, 162, 101, 162, 57, 133,
+ 167, 104, 68, 69, 25, 57, 167, 80, 89, 449,
+ 91, 89, 71, 91, 95, 479, 90, 95, 72, 71,
+ 68, 522, 62, 23, 445, 206, 107, 448, 522, 107,
+ 211, 104, 72, 167, 96, 162, 457, 91, 100, 510,
+ 133, 107, 123, 109, 110, 123, 224, 225, 72, 227,
+ 228, 103, 62, 554, 555, 553, 77, 78, 66, 285,
+ 554, 555, 69, 84, 85, 131, 132, 133, 68, 570,
+ 72, 152, 573, 154, 66, 62, 570, 101, 62, 573,
+ 90, 162, 90, 204, 162, 92, 167, 3, 72, 167,
+ 511, 512, 158, 101, 261, 216, 103, 44, 90, 101,
+ 261, 167, 18, 90, 62, 72, 57, 91, 62, 101,
+ 31, 443, 215, 29, 72, 62, 32, 33, 34, 73,
+ 71, 37, 38, 204, 91, 41, 204, 261, 107, 45,
+ 89, 87, 48, 111, 412, 216, 62, 42, 216, 89,
+ 99, 97, 68, 224, 225, 226, 227, 228, 226, 99,
+ 284, 67, 57, 320, 133, 320, 0, 89, 336, 337,
+ 338, 9, 79, 57, 81, 394, 71, 99, 397, 86,
+ 72, 19, 107, 345, 346, 347, 348, 344, 394, 11,
+ 261, 397, 17, 261, 107, 101, 518, 519, 167, 519,
+ 74, 284, 76, 0, 68, 362, 3, 362, 133, 265,
+ 339, 340, 268, 341, 342, 343, 396, 310, 398, 68,
+ 133, 18, 349, 350, 66, 101, 282, 72, 284, 285,
+ 66, 68, 29, 91, 290, 32, 33, 34, 107, 44,
+ 37, 38, 167, 72, 41, 362, 101, 569, 45, 320,
+ 101, 48, 320, 101, 167, 101, 413, 313, 91, 91,
+ 91, 229, 413, 91, 133, 336, 337, 338, 339, 340,
+ 341, 342, 343, 344, 345, 346, 347, 348, 349, 350,
+ 351, 352, 353, 354, 355, 72, 72, 91, 65, 413,
+ 11, 362, 261, 67, 362, 101, 72, 62, 167, 101,
+ 447, 412, 91, 450, 101, 61, 68, 62, 101, 62,
+ 478, 58, 63, 59, 94, 284, 101, 101, 411, 443,
+ 444, 49, 101, 101, 9, 66, 107, 560, 11, 453,
+ 90, 62, 91, 90, 61, 61, 261, 61, 101, 307,
+ 308, 412, 413, 66, 412, 413, 90, 418, 261, 66,
+ 66, 91, 133, 409, 90, 90, 449, 413, 101, 284,
+ 90, 444, 519, 331, 332, 19, 91, 61, 519, 91,
+ 453, 284, 91, 66, 508, 107, 90, 90, 65, 91,
+ 527, 61, 90, 90, 68, 61, 167, 107, 444, 90,
+ 547, 101, 261, 67, 518, 519, 547, 453, 522, 523,
+ 66, 133, 62, 560, 67, 101, 65, 478, 479, 560,
+ 481, 90, 16, 133, 91, 284, 91, 16, 91, 90,
+ 90, 90, 90, 547, 65, 90, 394, 67, 552, 397,
+ 554, 555, 90, 90, 101, 167, 560, 101, 90, 522,
+ 523, 90, 65, 16, 413, 569, 570, 167, 519, 573,
+ 101, 519, 90, 101, 101, 344, 95, 65, 80, 104,
+ 313, 104, 409, 57, 110, 547, 522, 523, 62, 552,
+ 310, 554, 555, 104, 443, 444, 547, 71, 72, 547,
+ 261, 413, 547, 569, 453, 519, 377, 570, 413, 560,
+ 573, 547, 560, 308, 351, 89, 552, 91, 554, 555,
+ 413, 353, 132, 284, 560, 99, 481, 354, 352, -1,
+ 306, -1, 355, -1, 570, -1, -1, 573, 443, 444,
+ -1, -1, -1, -1, -1, -1, -1, -1, 453, 261,
+ 443, 444, -1, -1, -1, 60, -1, 62, -1, 64,
+ 453, 261, -1, -1, 413, 70, -1, 72, 73, 518,
+ 519, -1, 284, 522, 523, 80, -1, 82, 83, -1,
+ -1, -1, -1, 88, 284, -1, 91, -1, 93, -1,
+ 95, -1, -1, 98, 443, 444, -1, -1, 547, 104,
+ -1, -1, -1, 552, 453, 554, 555, -1, -1, -1,
+ -1, 560, -1, 518, 519, -1, -1, 522, 523, -1,
+ 569, 570, -1, -1, 573, 518, 519, -1, -1, 522,
+ 523, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 547, -1, -1, -1, -1, 552, -1, 554,
+ 555, -1, 413, -1, 547, 560, -1, -1, -1, 552,
+ -1, 554, 555, -1, 569, 570, -1, 560, 573, 518,
+ 519, -1, -1, 522, 523, -1, 569, 570, -1, -1,
+ 573, -1, 443, 444, -1, -1, -1, -1, -1, -1,
+ -1, -1, 453, -1, 5, -1, 7, -1, 547, 10,
+ 11, 413, -1, 552, 15, 554, 555, -1, -1, 20,
+ -1, 560, -1, 413, -1, 26, 27, 28, -1, -1,
+ 569, 570, -1, -1, 573, 36, -1, -1, -1, -1,
+ -1, 443, 444, -1, -1, -1, 47, -1, -1, -1,
+ 130, 453, -1, 443, 444, -1, 57, 137, -1, -1,
+ -1, -1, 142, 453, 152, -1, 154, 518, 519, -1,
+ 71, 522, 523, 153, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 547, -1, -1, -1,
+ 152, 552, 154, 554, 555, -1, -1, -1, -1, 560,
+ -1, -1, -1, -1, -1, -1, 518, 519, 569, 570,
+ 522, 523, 573, -1, -1, -1, -1, -1, 518, 519,
+ -1, -1, 522, 523, -1, -1, 224, 225, -1, 227,
+ 228, -1, -1, -1, -1, 547, 226, -1, -1, -1,
+ 552, -1, 554, 555, -1, -1, -1, 547, 560, -1,
+ -1, -1, 552, -1, 554, 555, -1, 569, 570, -1,
+ 560, 573, 224, 225, -1, 227, 228, -1, -1, 569,
+ 570, -1, 262, 573, 3, -1, 266, 267, -1, -1,
+ -1, 271, -1, -1, -1, -1, -1, -1, -1, 18,
+ -1, 281, -1, -1, -1, -1, -1, -1, -1, -1,
+ 29, 291, -1, 32, 33, 34, -1, -1, 37, 38,
+ -1, -1, 41, -1, -1, -1, 45, -1, -1, 48,
+ -1, -1, -1, -1, -1, -1, 316, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 336, 337,
+ 338, 339, 340, 341, 342, 343, -1, 345, 346, 347,
+ 348, 349, 350, 351, 352, 353, 354, 355, -1, -1,
+ -1, 90, -1, -1, -1, -1, 356, 357, -1, -1,
+ -1, -1, -1, -1, 336, 337, 338, 339, 340, 341,
+ 342, 343, -1, 345, 346, 347, 348, 349, 350, 351,
+ 352, 353, 354, 355, 5, -1, 7, -1, -1, 10,
+ -1, -1, -1, 393, 15, -1, -1, -1, -1, 20,
+ -1, -1, -1, -1, 404, 26, -1, 28, -1, -1,
+ 418, -1, -1, -1, -1, 36, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 47, -1, -1, -1,
+ 5, -1, 7, -1, -1, 10, 57, -1, -1, -1,
+ 15, 441, 442, -1, -1, 20, 418, -1, -1, -1,
+ 71, 26, -1, 28, -1, 30, 456, -1, -1, 3,
+ -1, 36, -1, -1, 39, -1, -1, 42, -1, -1,
+ 478, 479, 47, 481, 18, 50, 51, 52, 53, 54,
+ 55, 56, 57, -1, -1, 29, 61, -1, 32, 33,
+ 34, -1, -1, 37, 38, -1, 71, 41, -1, -1,
+ 75, 45, -1, -1, 48, -1, 478, 479, -1, 481,
+ 510, -1, 87, -1, 89, -1, 91, -1, -1, -1,
+ 520, 521, 97, 67, 99, -1, -1, 102, -1, 3,
+ 4, 5, 6, 7, 8, -1, 10, -1, 12, 13,
+ 14, 15, -1, 543, 18, -1, 20, 21, 22, -1,
+ -1, -1, 26, 553, 28, 29, 30, -1, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ -1, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 67, 68, -1, -1, 71, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 89, -1, 91, -1, 3,
+ 4, 5, 6, 7, -1, 99, 10, 101, 12, -1,
+ 14, 15, -1, -1, 18, -1, 20, 21, 22, -1,
+ -1, -1, 26, -1, 28, 29, 30, -1, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ -1, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 67, 68, -1, -1, 71, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 89, -1, 91, -1, 3,
+ 4, 5, 6, 7, -1, 99, 10, 101, 12, -1,
+ 14, 15, -1, -1, 18, -1, 20, 21, 22, -1,
+ -1, -1, 26, -1, 28, 29, 30, -1, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ -1, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 67, 68, -1, -1, 71, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 89, -1, 91, -1, 3,
+ 4, 5, 6, 7, -1, 99, 10, 101, 12, -1,
+ 14, 15, -1, -1, 18, -1, 20, 21, 22, -1,
+ -1, -1, 26, -1, 28, 29, 30, -1, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ -1, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 67, 68, -1, -1, 71, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 89, -1, 91, -1, -1,
+ -1, -1, -1, -1, -1, 99, -1, 101, 3, 4,
+ 5, 6, 7, -1, -1, 10, 11, 12, -1, 14,
+ 15, -1, -1, 18, -1, 20, 21, 22, -1, -1,
+ -1, 26, -1, 28, 29, 30, -1, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, -1,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 68, -1, -1, 71, -1, -1, -1,
+ -1, 4, 5, 6, 7, -1, -1, 10, -1, 12,
+ -1, 14, 15, -1, 89, -1, 91, 20, 21, 22,
+ -1, -1, -1, 26, 99, 28, 101, 30, -1, -1,
+ -1, -1, 35, 36, -1, -1, 39, 40, 41, 42,
+ 43, -1, -1, 46, 47, -1, 49, 50, 51, 52,
+ 53, 54, 55, 56, 57, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 68, -1, -1, 71, -1,
+ -1, -1, -1, 4, 5, 6, 7, -1, -1, 10,
+ -1, 12, -1, 14, 15, -1, 89, -1, 91, 20,
+ 21, 22, -1, -1, -1, 26, 99, 28, 101, 30,
+ -1, -1, -1, -1, 35, 36, -1, -1, 39, 40,
+ 41, 42, 43, -1, -1, 46, 47, -1, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 68, -1, -1,
+ 71, 5, -1, 7, -1, -1, 10, -1, -1, -1,
+ -1, 15, -1, -1, -1, -1, 20, -1, 89, -1,
+ 91, -1, 26, -1, 28, -1, 30, -1, 99, -1,
+ 101, -1, 36, -1, -1, 39, -1, -1, 42, -1,
+ -1, -1, -1, 47, -1, -1, 50, 51, 52, 53,
+ 54, 55, 56, 57, -1, 5, -1, 7, -1, -1,
+ 10, -1, -1, -1, 68, 15, -1, 71, -1, -1,
+ 20, 75, -1, -1, -1, -1, 26, -1, 28, -1,
+ 30, -1, -1, 87, -1, 89, 36, 91, -1, 39,
+ -1, -1, 42, 97, -1, 99, -1, 47, 102, -1,
+ 50, 51, 52, 53, 54, 55, 56, 57, -1, 5,
+ -1, 7, -1, -1, 10, -1, -1, -1, -1, 15,
+ -1, 71, -1, -1, 20, 75, -1, -1, -1, -1,
+ 26, -1, 28, -1, 30, -1, -1, 87, -1, 89,
+ 36, 91, -1, 39, -1, -1, 42, 97, -1, 99,
+ -1, 47, 102, -1, 50, 51, 52, 53, 54, 55,
+ 56, 57, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 3, 71, 5, -1, 7, 75,
+ -1, 10, -1, -1, -1, -1, 15, -1, -1, 18,
+ -1, 20, -1, -1, -1, 91, -1, 26, -1, 28,
+ 29, 30, -1, 32, 33, 34, 102, 36, 37, 38,
+ 39, -1, 41, 42, -1, -1, 45, -1, 47, 48,
+ -1, 50, 51, 52, 53, 54, 55, 56, 57, -1,
+ 5, -1, 7, -1, -1, 10, -1, -1, -1, -1,
+ 15, -1, 71, -1, -1, 20, -1, -1, -1, -1,
+ -1, 26, -1, 28, -1, 30, -1, -1, -1, -1,
+ 89, 36, 91, -1, 39, -1, -1, 42, -1, -1,
+ 99, -1, 47, -1, -1, 50, 51, 52, 53, 54,
+ 55, 56, 57, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 71, -1, -1, -1,
+ 3, -1, 5, -1, 7, -1, -1, 10, -1, -1,
+ -1, -1, 15, -1, 89, 18, 91, 20, -1, -1,
+ -1, 3, -1, 26, 99, 28, 29, -1, -1, 32,
+ 33, 34, -1, 36, 37, 38, 18, -1, 41, -1,
+ -1, -1, 45, -1, 47, 48, -1, 29, -1, -1,
+ 32, 33, 34, -1, 57, 37, 38, -1, -1, 41,
+ 60, -1, -1, 45, 64, -1, 48, -1, 71, -1,
+ 70, -1, -1, 73, 60, -1, -1, -1, 64, -1,
+ 80, -1, 82, 83, 70, -1, -1, 73, 88, -1,
+ -1, -1, -1, 93, 80, 95, 82, 83, 98, -1,
+ -1, 60, 88, -1, 104, 64, -1, 93, -1, 95,
+ -1, 70, 98, -1, 73, -1, -1, -1, 104, -1,
+ -1, 80, -1, 82, 83, -1, -1, -1, -1, 88,
+ -1, -1, -1, -1, 93, -1, 95, -1, -1, 98,
+ -1, -1, -1, -1, -1, 104
+};
+
+ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_int16 yystos[] =
+{
+ 0, 31, 107, 122, 123, 126, 5, 7, 10, 15,
+ 20, 26, 28, 36, 47, 57, 71, 111, 117, 118,
+ 119, 120, 121, 0, 124, 57, 72, 101, 72, 24,
+ 125, 127, 128, 129, 11, 42, 119, 11, 117, 3,
+ 18, 29, 32, 33, 34, 37, 38, 41, 45, 48,
+ 101, 130, 131, 132, 133, 134, 135, 164, 165, 72,
+ 101, 132, 17, 23, 68, 136, 137, 139, 11, 27,
+ 17, 166, 167, 103, 113, 114, 117, 113, 115, 138,
+ 140, 137, 139, 139, 119, 119, 115, 68, 168, 66,
+ 101, 66, 37, 67, 130, 135, 141, 142, 143, 148,
+ 149, 158, 159, 139, 169, 115, 115, 68, 177, 47,
+ 110, 111, 112, 113, 116, 117, 118, 160, 101, 157,
+ 177, 67, 134, 135, 143, 149, 165, 170, 171, 172,
+ 4, 6, 12, 14, 21, 22, 30, 35, 39, 40,
+ 41, 42, 43, 46, 49, 50, 51, 52, 53, 54,
+ 55, 56, 89, 91, 99, 101, 108, 109, 110, 116,
+ 117, 119, 131, 134, 135, 177, 178, 179, 180, 181,
+ 182, 183, 185, 186, 187, 189, 190, 191, 192, 194,
+ 201, 203, 204, 212, 213, 215, 216, 217, 218, 219,
+ 224, 225, 226, 230, 235, 236, 237, 238, 239, 240,
+ 242, 243, 258, 259, 263, 119, 151, 119, 144, 145,
+ 146, 151, 62, 234, 234, 91, 44, 150, 155, 101,
+ 101, 101, 173, 101, 75, 87, 91, 97, 102, 111,
+ 116, 117, 226, 236, 238, 239, 240, 241, 242, 243,
+ 244, 245, 246, 247, 248, 249, 250, 251, 252, 253,
+ 254, 255, 256, 257, 258, 261, 119, 214, 214, 41,
+ 183, 91, 91, 208, 261, 72, 91, 91, 72, 261,
+ 177, 91, 117, 235, 237, 241, 261, 241, 119, 144,
+ 72, 62, 72, 91, 65, 110, 67, 180, 101, 101,
+ 72, 62, 89, 99, 60, 64, 70, 73, 80, 82,
+ 83, 88, 93, 95, 98, 104, 260, 111, 113, 114,
+ 91, 62, 150, 66, 101, 62, 73, 150, 61, 62,
+ 135, 152, 153, 154, 114, 156, 68, 161, 101, 241,
+ 241, 111, 117, 261, 241, 241, 69, 92, 103, 87,
+ 97, 79, 81, 86, 25, 77, 78, 84, 85, 74,
+ 76, 58, 63, 94, 59, 96, 100, 65, 101, 101,
+ 101, 49, 131, 182, 190, 206, 209, 211, 261, 101,
+ 119, 261, 261, 119, 101, 9, 220, 221, 222, 261,
+ 90, 11, 261, 30, 228, 229, 261, 183, 144, 42,
+ 119, 261, 257, 62, 232, 233, 234, 232, 234, 91,
+ 152, 61, 145, 61, 68, 147, 174, 261, 61, 110,
+ 90, 66, 66, 162, 101, 231, 234, 234, 90, 241,
+ 241, 241, 246, 246, 247, 247, 247, 112, 248, 248,
+ 248, 248, 249, 249, 250, 251, 252, 253, 254, 261,
+ 261, 91, 101, 66, 90, 91, 90, 90, 91, 91,
+ 19, 223, 222, 90, 61, 90, 66, 91, 61, 261,
+ 231, 233, 234, 174, 231, 174, 228, 90, 147, 175,
+ 176, 146, 154, 114, 39, 42, 163, 178, 90, 90,
+ 244, 65, 101, 261, 208, 190, 21, 22, 49, 119,
+ 183, 184, 185, 188, 193, 202, 207, 228, 68, 195,
+ 177, 228, 154, 177, 183, 261, 228, 61, 90, 67,
+ 66, 91, 91, 67, 241, 244, 256, 90, 101, 91,
+ 91, 91, 65, 16, 90, 197, 90, 90, 90, 139,
+ 227, 147, 228, 228, 101, 205, 210, 211, 206, 261,
+ 261, 184, 183, 8, 13, 196, 198, 199, 200, 177,
+ 90, 90, 90, 101, 90, 90, 261, 262, 65, 67,
+ 179, 200, 101, 101, 183, 208, 184, 184, 65, 101,
+ 16, 205, 184, 90, 184
+};
+
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_int16 yyr1[] =
+{
+ 0, 106, 107, 108, 108, 108, 108, 108, 108, 109,
+ 109, 110, 110, 111, 111, 111, 111, 111, 111, 111,
+ 111, 112, 112, 113, 114, 115, 116, 116, 117, 117,
+ 118, 119, 119, 120, 120, 120, 120, 121, 121, 122,
+ 123, 123, 124, 124, 125, 125, 126, 127, 127, 128,
+ 129, 130, 130, 130, 131, 131, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 133, 134, 134,
+ 134, 134, 135, 135, 136, 137, 138, 138, 139, 140,
+ 140, 141, 141, 141, 141, 142, 142, 143, 144, 144,
+ 145, 145, 146, 146, 147, 147, 148, 148, 148, 149,
+ 149, 150, 150, 151, 151, 152, 152, 153, 153, 154,
+ 155, 156, 156, 157, 158, 159, 159, 160, 161, 162,
+ 162, 163, 163, 164, 165, 166, 166, 167, 167, 168,
+ 169, 169, 170, 170, 170, 170, 170, 170, 171, 172,
+ 173, 173, 174, 175, 175, 175, 176, 176, 177, 178,
+ 178, 179, 179, 180, 180, 180, 181, 182, 182, 183,
+ 183, 183, 183, 183, 183, 184, 184, 184, 184, 184,
+ 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
+ 185, 185, 186, 187, 188, 189, 190, 190, 190, 190,
+ 190, 190, 190, 191, 192, 193, 194, 195, 196, 196,
+ 197, 197, 198, 199, 199, 200, 200, 201, 202, 203,
+ 204, 205, 205, 206, 206, 207, 208, 208, 209, 209,
+ 210, 211, 211, 212, 212, 213, 214, 214, 215, 216,
+ 217, 218, 219, 219, 220, 220, 221, 221, 222, 223,
+ 224, 224, 225, 225, 225, 225, 225, 225, 225, 226,
+ 227, 227, 228, 228, 229, 229, 230, 230, 230, 230,
+ 231, 231, 232, 232, 233, 234, 234, 235, 235, 235,
+ 235, 236, 236, 236, 236, 237, 237, 238, 238, 238,
+ 238, 238, 239, 240, 241, 241, 241, 241, 241, 242,
+ 243, 244, 244, 244, 244, 245, 245, 245, 246, 246,
+ 246, 246, 247, 247, 247, 248, 248, 248, 248, 249,
+ 249, 249, 249, 249, 249, 250, 250, 250, 251, 251,
+ 252, 252, 253, 253, 254, 254, 255, 255, 256, 256,
+ 257, 257, 258, 259, 259, 259, 260, 260, 260, 260,
+ 260, 260, 260, 260, 260, 260, 260, 260, 261, 262,
+ 263, 263
+};
+
+ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
+static const yytype_int8 yyr2[] =
+{
+ 0, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 2, 1, 1,
+ 1, 1, 2, 3, 3, 3, 3, 1, 1, 3,
+ 0, 1, 0, 2, 0, 2, 3, 1, 1, 3,
+ 5, 1, 1, 1, 1, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 3, 2, 3,
+ 3, 4, 0, 1, 2, 2, 1, 3, 3, 0,
+ 2, 1, 1, 1, 1, 1, 1, 4, 1, 3,
+ 1, 3, 1, 3, 1, 1, 2, 2, 3, 4,
+ 4, 0, 1, 4, 3, 0, 1, 1, 3, 3,
+ 2, 1, 3, 1, 2, 4, 5, 4, 4, 0,
+ 2, 5, 5, 3, 3, 0, 1, 2, 3, 3,
+ 0, 2, 1, 1, 1, 2, 1, 2, 1, 2,
+ 1, 2, 3, 0, 1, 2, 1, 3, 3, 0,
+ 1, 1, 2, 1, 1, 1, 2, 3, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 3, 3, 2, 1, 1, 1, 1,
+ 1, 1, 1, 5, 7, 7, 5, 4, 0, 1,
+ 0, 2, 2, 1, 2, 3, 2, 5, 5, 7,
+ 9, 0, 1, 0, 1, 9, 0, 1, 1, 1,
+ 1, 1, 3, 3, 5, 3, 0, 1, 3, 3,
+ 3, 5, 3, 4, 0, 1, 1, 2, 5, 2,
+ 1, 1, 1, 1, 3, 1, 1, 1, 1, 6,
+ 0, 1, 0, 1, 1, 3, 4, 4, 4, 4,
+ 0, 1, 1, 2, 3, 2, 3, 3, 3, 3,
+ 3, 4, 6, 6, 6, 4, 4, 1, 1, 3,
+ 1, 1, 2, 2, 1, 1, 2, 2, 1, 2,
+ 2, 1, 2, 2, 1, 5, 4, 5, 1, 3,
+ 3, 3, 1, 3, 3, 1, 3, 3, 3, 1,
+ 3, 3, 3, 3, 3, 1, 3, 3, 1, 3,
+ 1, 3, 1, 3, 1, 3, 1, 3, 1, 5,
+ 1, 1, 3, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 3
+};
+
+
+enum { YYENOMEM = -2 };
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+ do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (yyscanner, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+ while (0)
+
+/* Backward compatibility with an undocumented macro.
+ Use YYerror or YYUNDEF. */
+#define YYERRCODE YYUNDEF
+
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+/* This macro is provided for backward compatibility. */
+# ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+
+
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Kind, Value, yyscanner); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+
+/*-----------------------------------.
+| Print this symbol's value on YYO. |
+`-----------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyo,
+ yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+{
+ FILE *yyoutput = yyo;
+ YYUSE (yyoutput);
+ YYUSE (yyscanner);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yykind < YYNTOKENS)
+ YYPRINT (yyo, yytoknum[yykind], *yyvaluep);
+# endif
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ YYUSE (yykind);
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+/*---------------------------.
+| Print this symbol on YYO. |
+`---------------------------*/
+
+static void
+yy_symbol_print (FILE *yyo,
+ yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+{
+ YYFPRINTF (yyo, "%s %s (",
+ yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
+
+ yy_symbol_value_print (yyo, yykind, yyvaluep, yyscanner);
+ YYFPRINTF (yyo, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop)
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp,
+ int yyrule, yyscan_t yyscanner)
+{
+ int yylno = yyrline[yyrule];
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr,
+ YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
+ &yyvsp[(yyi + 1) - (yynrhs)], yyscanner);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyssp, yyvsp, Rule, yyscanner); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args) ((void) 0)
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+/* Context of a parse error. */
+typedef struct
+{
+ yy_state_t *yyssp;
+ yysymbol_kind_t yytoken;
+} yypcontext_t;
+
+/* Put in YYARG at most YYARGN of the expected tokens given the
+ current YYCTX, and return the number of tokens stored in YYARG. If
+ YYARG is null, return the number of expected tokens (guaranteed to
+ be less than YYNTOKENS). Return YYENOMEM on memory exhaustion.
+ Return 0 if there are more than YYARGN expected tokens, yet fill
+ YYARG up to YYARGN. */
+static int
+yypcontext_expected_tokens (const yypcontext_t *yyctx,
+ yysymbol_kind_t yyarg[], int yyargn)
+{
+ /* Actual size of YYARG. */
+ int yycount = 0;
+ int yyn = yypact[+*yyctx->yyssp];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (!yyarg)
+ ++yycount;
+ else if (yycount == yyargn)
+ return 0;
+ else
+ yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx);
+ }
+ }
+ if (yyarg && yycount == 0 && 0 < yyargn)
+ yyarg[0] = YYSYMBOL_YYEMPTY;
+ return yycount;
+}
+
+
+
+
+#ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S)))
+# else
+/* Return the length of YYSTR. */
+static YYPTRDIFF_T
+yystrlen (const char *yystr)
+{
+ YYPTRDIFF_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+#endif
+
+#ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+#endif
+
+#ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYPTRDIFF_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYPTRDIFF_T yyn = 0;
+ char const *yyp = yystr;
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ else
+ goto append;
+
+ append:
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (yyres)
+ return yystpcpy (yyres, yystr) - yyres;
+ else
+ return yystrlen (yystr);
+}
+#endif
+
+
+static int
+yy_syntax_error_arguments (const yypcontext_t *yyctx,
+ yysymbol_kind_t yyarg[], int yyargn)
+{
+ /* Actual size of YYARG. */
+ int yycount = 0;
+ /* There are many possibilities here to consider:
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yyctx->yytoken != YYSYMBOL_YYEMPTY)
+ {
+ int yyn;
+ if (yyarg)
+ yyarg[yycount] = yyctx->yytoken;
+ ++yycount;
+ yyn = yypcontext_expected_tokens (yyctx,
+ yyarg ? yyarg + 1 : yyarg, yyargn - 1);
+ if (yyn == YYENOMEM)
+ return YYENOMEM;
+ else
+ yycount += yyn;
+ }
+ return yycount;
+}
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg,
+ const yypcontext_t *yyctx)
+{
+ enum { YYARGS_MAX = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULLPTR;
+ /* Arguments of yyformat: reported tokens (one for the "unexpected",
+ one per "expected"). */
+ yysymbol_kind_t yyarg[YYARGS_MAX];
+ /* Cumulated lengths of YYARG. */
+ YYPTRDIFF_T yysize = 0;
+
+ /* Actual size of YYARG. */
+ int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX);
+ if (yycount == YYENOMEM)
+ return YYENOMEM;
+
+ switch (yycount)
+ {
+#define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ default: /* Avoid compiler warnings. */
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+#undef YYCASE_
+ }
+
+ /* Compute error message size. Don't count the "%s"s, but reserve
+ room for the terminator. */
+ yysize = yystrlen (yyformat) - 2 * yycount + 1;
+ {
+ int yyi;
+ for (yyi = 0; yyi < yycount; ++yyi)
+ {
+ YYPTRDIFF_T yysize1
+ = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]);
+ if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
+ yysize = yysize1;
+ else
+ return YYENOMEM;
+ }
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return -1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]);
+ yyformat += 2;
+ }
+ else
+ {
+ ++yyp;
+ ++yyformat;
+ }
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg,
+ yysymbol_kind_t yykind, YYSTYPE *yyvaluep, yyscan_t yyscanner)
+{
+ YYUSE (yyvaluep);
+ YYUSE (yyscanner);
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ YYUSE (yykind);
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+int
+yyparse (yyscan_t yyscanner)
+{
+/* Lookahead token kind. */
+int yychar;
+
+
+/* The semantic value of the lookahead symbol. */
+/* Default value used for initialization, for pacifying older GCCs
+ or non-GCC compilers. */
+YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
+YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
+
+ /* Number of syntax errors so far. */
+ int yynerrs = 0;
+
+ yy_state_fast_t yystate = 0;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus = 0;
+
+ /* Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* Their size. */
+ YYPTRDIFF_T yystacksize = YYINITDEPTH;
+
+ /* The state stack: array, bottom, top. */
+ yy_state_t yyssa[YYINITDEPTH];
+ yy_state_t *yyss = yyssa;
+ yy_state_t *yyssp = yyss;
+
+ /* The semantic value stack: array, bottom, top. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp = yyvs;
+
+ int yyn;
+ /* The return value of yyparse. */
+ int yyresult;
+ /* Lookahead symbol kind. */
+ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf;
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ goto yysetstate;
+
+
+/*------------------------------------------------------------.
+| yynewstate -- push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+
+/*--------------------------------------------------------------------.
+| yysetstate -- set current state (the top of the stack) to yystate. |
+`--------------------------------------------------------------------*/
+yysetstate:
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+ YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
+ YY_IGNORE_USELESS_CAST_BEGIN
+ *yyssp = YY_CAST (yy_state_t, yystate);
+ YY_IGNORE_USELESS_CAST_END
+ YY_STACK_PRINT (yyss, yyssp);
+
+ if (yyss + yystacksize - 1 <= yyssp)
+#if !defined yyoverflow && !defined YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+#else
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYPTRDIFF_T yysize = yyssp - yyss + 1;
+
+# if defined yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ yy_state_t *yyss1 = yyss;
+ YYSTYPE *yyvs1 = yyvs;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * YYSIZEOF (*yyssp),
+ &yyvs1, yysize * YYSIZEOF (*yyvsp),
+ &yystacksize);
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+# else /* defined YYSTACK_RELOCATE */
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yy_state_t *yyss1 = yyss;
+ union yyalloc *yyptr =
+ YY_CAST (union yyalloc *,
+ YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YY_IGNORE_USELESS_CAST_BEGIN
+ YYDPRINTF ((stderr, "Stack size increased to %ld\n",
+ YY_CAST (long, yystacksize)));
+ YY_IGNORE_USELESS_CAST_END
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token\n"));
+ yychar = yylex (&yylval, yyscanner);
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = YYEOF;
+ yytoken = YYSYMBOL_YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else if (yychar == YYerror)
+ {
+ /* The scanner already issued an error message, process directly
+ to error recovery. But do not keep the error token as
+ lookahead, it is too special and may lead us to an endless
+ loop in error recovery. */
+ yychar = YYUNDEF;
+ yytoken = YYSYMBOL_YYerror;
+ goto yyerrlab1;
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ '$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2: /* Goal: CompilationUnit */
+#line 181 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2481 "cmDependsJavaParser.cxx"
+ break;
+
+ case 3: /* Literal: IntegerLiteral */
+#line 190 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2492 "cmDependsJavaParser.cxx"
+ break;
+
+ case 4: /* Literal: jp_FLOATINGPOINTLITERAL */
+#line 198 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2503 "cmDependsJavaParser.cxx"
+ break;
+
+ case 5: /* Literal: jp_BOOLEANLITERAL */
+#line 206 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2514 "cmDependsJavaParser.cxx"
+ break;
+
+ case 6: /* Literal: jp_CHARACTERLITERAL */
+#line 214 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2525 "cmDependsJavaParser.cxx"
+ break;
+
+ case 7: /* Literal: jp_STRINGLITERAL */
+#line 222 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2536 "cmDependsJavaParser.cxx"
+ break;
+
+ case 8: /* Literal: jp_NULLLITERAL */
+#line 230 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2547 "cmDependsJavaParser.cxx"
+ break;
+
+ case 9: /* IntegerLiteral: jp_DECIMALINTEGERLITERAL */
+#line 239 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2558 "cmDependsJavaParser.cxx"
+ break;
+
+ case 10: /* IntegerLiteral: jp_HEXINTEGERLITERAL */
+#line 247 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2569 "cmDependsJavaParser.cxx"
+ break;
+
+ case 11: /* Type: PrimitiveType */
+#line 256 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2580 "cmDependsJavaParser.cxx"
+ break;
+
+ case 12: /* Type: ReferenceType */
+#line 264 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2591 "cmDependsJavaParser.cxx"
+ break;
+
+ case 13: /* PrimitiveType: jp_BYTE_TYPE */
+#line 273 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+}
+#line 2599 "cmDependsJavaParser.cxx"
+ break;
+
+ case 14: /* PrimitiveType: jp_SHORT_TYPE */
+#line 278 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+}
+#line 2607 "cmDependsJavaParser.cxx"
+ break;
+
+ case 15: /* PrimitiveType: jp_INT_TYPE */
+#line 283 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+}
+#line 2615 "cmDependsJavaParser.cxx"
+ break;
+
+ case 16: /* PrimitiveType: jp_LONG_TYPE */
+#line 288 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+}
+#line 2623 "cmDependsJavaParser.cxx"
+ break;
+
+ case 17: /* PrimitiveType: jp_CHAR_TYPE */
+#line 293 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+}
+#line 2631 "cmDependsJavaParser.cxx"
+ break;
+
+ case 18: /* PrimitiveType: jp_FLOAT_TYPE */
+#line 298 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+}
+#line 2639 "cmDependsJavaParser.cxx"
+ break;
+
+ case 19: /* PrimitiveType: jp_DOUBLE_TYPE */
+#line 303 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+}
+#line 2647 "cmDependsJavaParser.cxx"
+ break;
+
+ case 20: /* PrimitiveType: jp_BOOLEAN_TYPE */
+#line 308 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+}
+#line 2655 "cmDependsJavaParser.cxx"
+ break;
+
+ case 21: /* ReferenceType: ClassOrInterfaceType */
+#line 314 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2666 "cmDependsJavaParser.cxx"
+ break;
+
+ case 22: /* ReferenceType: ArrayType */
+#line 322 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2677 "cmDependsJavaParser.cxx"
+ break;
+
+ case 23: /* ClassOrInterfaceType: Name */
+#line 331 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpStoreClass((yyvsp[0].str));
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2689 "cmDependsJavaParser.cxx"
+ break;
+
+ case 24: /* ClassType: ClassOrInterfaceType */
+#line 341 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2700 "cmDependsJavaParser.cxx"
+ break;
+
+ case 25: /* InterfaceType: ClassOrInterfaceType */
+#line 350 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2711 "cmDependsJavaParser.cxx"
+ break;
+
+ case 26: /* ArrayType: PrimitiveType Dims */
+#line 359 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2722 "cmDependsJavaParser.cxx"
+ break;
+
+ case 27: /* ArrayType: Name Dims */
+#line 367 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpStoreClass((yyvsp[-1].str));
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2734 "cmDependsJavaParser.cxx"
+ break;
+
+ case 28: /* Name: SimpleName */
+#line 377 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ (yyval.str) = (yyvsp[0].str);
+}
+#line 2743 "cmDependsJavaParser.cxx"
+ break;
+
+ case 29: /* Name: QualifiedName */
+#line 383 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ (yyval.str) = (yyvsp[0].str);
+}
+#line 2752 "cmDependsJavaParser.cxx"
+ break;
+
+ case 30: /* SimpleName: Identifier */
+#line 390 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ (yyval.str) = (yyvsp[0].str);
+}
+#line 2761 "cmDependsJavaParser.cxx"
+ break;
+
+ case 31: /* Identifier: jp_NAME */
+#line 397 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ (yyval.str) = (yyvsp[0].str);
+}
+#line 2770 "cmDependsJavaParser.cxx"
+ break;
+
+ case 32: /* Identifier: jp_DOLLAR jp_NAME */
+#line 403 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ (yyval.str) = (yyvsp[0].str);
+}
+#line 2779 "cmDependsJavaParser.cxx"
+ break;
+
+ case 33: /* QualifiedName: Name jp_DOT Identifier */
+#line 410 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ yyGetParser->AddClassFound((yyvsp[-2].str));
+ yyGetParser->UpdateCombine((yyvsp[-2].str), (yyvsp[0].str));
+ yyGetParser->DeallocateParserType(&((yyvsp[-2].str)));
+ (yyval.str) = const_cast<char*>(yyGetParser->GetCurrentCombine());
+}
+#line 2791 "cmDependsJavaParser.cxx"
+ break;
+
+ case 34: /* QualifiedName: Name jp_DOT jp_CLASS */
+#line 419 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpStoreClass((yyvsp[-2].str));
+ jpCheckEmpty(3);
+ yyGetParser->SetCurrentCombine("");
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2804 "cmDependsJavaParser.cxx"
+ break;
+
+ case 35: /* QualifiedName: Name jp_DOT jp_THIS */
+#line 429 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpStoreClass((yyvsp[-2].str));
+ yyGetParser->SetCurrentCombine("");
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2817 "cmDependsJavaParser.cxx"
+ break;
+
+ case 36: /* QualifiedName: SimpleType jp_DOT jp_CLASS */
+#line 439 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2828 "cmDependsJavaParser.cxx"
+ break;
+
+ case 37: /* SimpleType: PrimitiveType */
+#line 448 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2839 "cmDependsJavaParser.cxx"
+ break;
+
+ case 38: /* SimpleType: jp_VOID */
+#line 456 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2850 "cmDependsJavaParser.cxx"
+ break;
+
+ case 39: /* CompilationUnit: PackageDeclarationopt ImportDeclarations TypeDeclarations */
+#line 465 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2861 "cmDependsJavaParser.cxx"
+ break;
+
+ case 40: /* PackageDeclarationopt: %empty */
+#line 473 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2871 "cmDependsJavaParser.cxx"
+ break;
+
+ case 41: /* PackageDeclarationopt: PackageDeclaration */
+#line 480 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2882 "cmDependsJavaParser.cxx"
+ break;
+
+ case 42: /* ImportDeclarations: %empty */
+#line 488 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2892 "cmDependsJavaParser.cxx"
+ break;
+
+ case 43: /* ImportDeclarations: ImportDeclarations ImportDeclaration */
+#line 495 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2903 "cmDependsJavaParser.cxx"
+ break;
+
+ case 44: /* TypeDeclarations: %empty */
+#line 503 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2913 "cmDependsJavaParser.cxx"
+ break;
+
+ case 45: /* TypeDeclarations: TypeDeclarations TypeDeclaration */
+#line 510 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2924 "cmDependsJavaParser.cxx"
+ break;
+
+ case 46: /* PackageDeclaration: jp_PACKAGE Name jp_SEMICOL */
+#line 519 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ yyGetParser->SetCurrentPackage((yyvsp[-1].str));
+ yyGetParser->DeallocateParserType(&((yyvsp[-1].str)));
+ yyGetParser->SetCurrentCombine("");
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2938 "cmDependsJavaParser.cxx"
+ break;
+
+ case 47: /* ImportDeclaration: SingleTypeImportDeclaration */
+#line 531 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2949 "cmDependsJavaParser.cxx"
+ break;
+
+ case 48: /* ImportDeclaration: TypeImportOnDemandDeclaration */
+#line 539 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2960 "cmDependsJavaParser.cxx"
+ break;
+
+ case 49: /* SingleTypeImportDeclaration: jp_IMPORT Name jp_SEMICOL */
+#line 548 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ yyGetParser->AddPackagesImport((yyvsp[-1].str));
+ yyGetParser->DeallocateParserType(&((yyvsp[-1].str)));
+ yyGetParser->SetCurrentCombine("");
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2974 "cmDependsJavaParser.cxx"
+ break;
+
+ case 50: /* TypeImportOnDemandDeclaration: jp_IMPORT Name jp_DOT jp_TIMES jp_SEMICOL */
+#line 560 "cmDependsJavaParser.y"
+{
+ jpElementStart(5);
+ std::string str = (yyvsp[-3].str);
+ str += ".*";
+ yyGetParser->AddPackagesImport(str.c_str());
+ yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
+ yyGetParser->SetCurrentCombine("");
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 2989 "cmDependsJavaParser.cxx"
+ break;
+
+ case 51: /* TypeDeclaration: ClassDeclaration */
+#line 573 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3000 "cmDependsJavaParser.cxx"
+ break;
+
+ case 52: /* TypeDeclaration: InterfaceDeclaration */
+#line 581 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3011 "cmDependsJavaParser.cxx"
+ break;
+
+ case 53: /* TypeDeclaration: jp_SEMICOL */
+#line 589 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3022 "cmDependsJavaParser.cxx"
+ break;
+
+ case 54: /* Modifiers: Modifier */
+#line 598 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3033 "cmDependsJavaParser.cxx"
+ break;
+
+ case 55: /* Modifiers: Modifiers Modifier */
+#line 606 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3044 "cmDependsJavaParser.cxx"
+ break;
+
+ case 67: /* ClassHeader: Modifiersopt jp_CLASS Identifier */
+#line 621 "cmDependsJavaParser.y"
+{
+ yyGetParser->StartClass((yyvsp[0].str));
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
+ jpCheckEmpty(3);
+}
+#line 3055 "cmDependsJavaParser.cxx"
+ break;
+
+ case 68: /* ClassDeclaration: ClassHeader ClassBody */
+#line 631 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+#line 3067 "cmDependsJavaParser.cxx"
+ break;
+
+ case 69: /* ClassDeclaration: ClassHeader Interfaces ClassBody */
+#line 640 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+#line 3079 "cmDependsJavaParser.cxx"
+ break;
+
+ case 70: /* ClassDeclaration: ClassHeader Super ClassBody */
+#line 649 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+#line 3091 "cmDependsJavaParser.cxx"
+ break;
+
+ case 71: /* ClassDeclaration: ClassHeader Super Interfaces ClassBody */
+#line 658 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+#line 3103 "cmDependsJavaParser.cxx"
+ break;
+
+ case 72: /* Modifiersopt: %empty */
+#line 667 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3113 "cmDependsJavaParser.cxx"
+ break;
+
+ case 73: /* Modifiersopt: Modifiers */
+#line 674 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3124 "cmDependsJavaParser.cxx"
+ break;
+
+ case 74: /* Super: jp_EXTENDS ClassType */
+#line 683 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3135 "cmDependsJavaParser.cxx"
+ break;
+
+ case 75: /* Interfaces: jp_IMPLEMENTS InterfaceTypeList */
+#line 692 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3146 "cmDependsJavaParser.cxx"
+ break;
+
+ case 76: /* InterfaceTypeList: InterfaceType */
+#line 701 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3157 "cmDependsJavaParser.cxx"
+ break;
+
+ case 77: /* InterfaceTypeList: InterfaceTypeList jp_COMMA InterfaceType */
+#line 709 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3168 "cmDependsJavaParser.cxx"
+ break;
+
+ case 78: /* ClassBody: jp_CURLYSTART ClassBodyDeclarations jp_CURLYEND */
+#line 718 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3179 "cmDependsJavaParser.cxx"
+ break;
+
+ case 79: /* ClassBodyDeclarations: %empty */
+#line 726 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3189 "cmDependsJavaParser.cxx"
+ break;
+
+ case 80: /* ClassBodyDeclarations: ClassBodyDeclarations ClassBodyDeclaration */
+#line 733 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3200 "cmDependsJavaParser.cxx"
+ break;
+
+ case 81: /* ClassBodyDeclaration: ClassMemberDeclaration */
+#line 742 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3211 "cmDependsJavaParser.cxx"
+ break;
+
+ case 82: /* ClassBodyDeclaration: StaticInitializer */
+#line 750 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3222 "cmDependsJavaParser.cxx"
+ break;
+
+ case 83: /* ClassBodyDeclaration: ConstructorDeclaration */
+#line 758 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3233 "cmDependsJavaParser.cxx"
+ break;
+
+ case 84: /* ClassBodyDeclaration: TypeDeclaration */
+#line 766 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3244 "cmDependsJavaParser.cxx"
+ break;
+
+ case 85: /* ClassMemberDeclaration: FieldDeclaration */
+#line 775 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3255 "cmDependsJavaParser.cxx"
+ break;
+
+ case 86: /* ClassMemberDeclaration: MethodDeclaration */
+#line 783 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3266 "cmDependsJavaParser.cxx"
+ break;
+
+ case 87: /* FieldDeclaration: Modifiersopt Type VariableDeclarators jp_SEMICOL */
+#line 792 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+}
+#line 3274 "cmDependsJavaParser.cxx"
+ break;
+
+ case 88: /* VariableDeclarators: VariableDeclarator */
+#line 798 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3285 "cmDependsJavaParser.cxx"
+ break;
+
+ case 89: /* VariableDeclarators: VariableDeclarators jp_COMMA VariableDeclarator */
+#line 806 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3296 "cmDependsJavaParser.cxx"
+ break;
+
+ case 90: /* VariableDeclarator: VariableDeclaratorId */
+#line 815 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3307 "cmDependsJavaParser.cxx"
+ break;
+
+ case 91: /* VariableDeclarator: VariableDeclaratorId jp_EQUALS VariableInitializer */
+#line 823 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3318 "cmDependsJavaParser.cxx"
+ break;
+
+ case 92: /* VariableDeclaratorId: Identifier */
+#line 832 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3330 "cmDependsJavaParser.cxx"
+ break;
+
+ case 93: /* VariableDeclaratorId: VariableDeclaratorId jp_BRACKETSTART jp_BRACKETEND */
+#line 841 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3341 "cmDependsJavaParser.cxx"
+ break;
+
+ case 94: /* VariableInitializer: Expression */
+#line 850 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3352 "cmDependsJavaParser.cxx"
+ break;
+
+ case 95: /* VariableInitializer: ArrayInitializer */
+#line 858 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3363 "cmDependsJavaParser.cxx"
+ break;
+
+ case 96: /* MethodDeclaration: MethodHeader jp_SEMICOL */
+#line 867 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3374 "cmDependsJavaParser.cxx"
+ break;
+
+ case 97: /* MethodDeclaration: MethodHeader MethodBody */
+#line 875 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3385 "cmDependsJavaParser.cxx"
+ break;
+
+ case 98: /* MethodDeclaration: MethodHeader MethodBody jp_SEMICOL */
+#line 883 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3396 "cmDependsJavaParser.cxx"
+ break;
+
+ case 99: /* MethodHeader: Modifiersopt Type MethodDeclarator Throwsopt */
+#line 892 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3408 "cmDependsJavaParser.cxx"
+ break;
+
+ case 100: /* MethodHeader: Modifiersopt jp_VOID MethodDeclarator Throwsopt */
+#line 901 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3420 "cmDependsJavaParser.cxx"
+ break;
+
+ case 101: /* Throwsopt: %empty */
+#line 910 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3431 "cmDependsJavaParser.cxx"
+ break;
+
+ case 102: /* Throwsopt: Throws */
+#line 918 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3443 "cmDependsJavaParser.cxx"
+ break;
+
+ case 103: /* MethodDeclarator: Identifier jp_PARESTART FormalParameterListopt jp_PAREEND */
+#line 928 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3456 "cmDependsJavaParser.cxx"
+ break;
+
+ case 104: /* MethodDeclarator: MethodDeclarator jp_BRACKETSTART jp_BRACKETEND */
+#line 938 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+
+}
+#line 3465 "cmDependsJavaParser.cxx"
+ break;
+
+ case 105: /* FormalParameterListopt: %empty */
+#line 944 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3476 "cmDependsJavaParser.cxx"
+ break;
+
+ case 107: /* FormalParameterList: FormalParameter */
+#line 955 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+
+}
+#line 3485 "cmDependsJavaParser.cxx"
+ break;
+
+ case 108: /* FormalParameterList: FormalParameterList jp_COMMA FormalParameter */
+#line 961 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3497 "cmDependsJavaParser.cxx"
+ break;
+
+ case 109: /* FormalParameter: Modifiersopt Type VariableDeclaratorId */
+#line 971 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3509 "cmDependsJavaParser.cxx"
+ break;
+
+ case 110: /* Throws: jp_THROWS ClassTypeList */
+#line 981 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3521 "cmDependsJavaParser.cxx"
+ break;
+
+ case 111: /* ClassTypeList: ClassType */
+#line 991 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+
+}
+#line 3530 "cmDependsJavaParser.cxx"
+ break;
+
+ case 112: /* ClassTypeList: ClassTypeList jp_COMMA ClassType */
+#line 997 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3542 "cmDependsJavaParser.cxx"
+ break;
+
+ case 113: /* MethodBody: Block */
+#line 1007 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3554 "cmDependsJavaParser.cxx"
+ break;
+
+ case 114: /* StaticInitializer: jp_STATIC Block */
+#line 1017 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3566 "cmDependsJavaParser.cxx"
+ break;
+
+ case 115: /* ConstructorDeclaration: Modifiersopt ConstructorDeclarator Throwsopt ConstructorBody */
+#line 1027 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3578 "cmDependsJavaParser.cxx"
+ break;
+
+ case 116: /* ConstructorDeclaration: Modifiersopt ConstructorDeclarator Throwsopt ConstructorBody jp_SEMICOL */
+#line 1036 "cmDependsJavaParser.y"
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3590 "cmDependsJavaParser.cxx"
+ break;
+
+ case 117: /* ConstructorDeclarator: SimpleName jp_PARESTART FormalParameterListopt jp_PAREEND */
+#line 1046 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3603 "cmDependsJavaParser.cxx"
+ break;
+
+ case 118: /* ConstructorBody: jp_CURLYSTART ExplicitConstructorInvocationopt BlockStatementsopt jp_CURLYEND */
+#line 1057 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3615 "cmDependsJavaParser.cxx"
+ break;
+
+ case 119: /* ExplicitConstructorInvocationopt: %empty */
+#line 1066 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3626 "cmDependsJavaParser.cxx"
+ break;
+
+ case 120: /* ExplicitConstructorInvocationopt: ExplicitConstructorInvocationopt ExplicitConstructorInvocation */
+#line 1074 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3638 "cmDependsJavaParser.cxx"
+ break;
+
+ case 121: /* ExplicitConstructorInvocation: jp_THIS jp_PARESTART ArgumentListopt jp_PAREEND jp_SEMICOL */
+#line 1084 "cmDependsJavaParser.y"
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3650 "cmDependsJavaParser.cxx"
+ break;
+
+ case 122: /* ExplicitConstructorInvocation: jp_SUPER jp_PARESTART ArgumentListopt jp_PAREEND jp_SEMICOL */
+#line 1093 "cmDependsJavaParser.y"
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3662 "cmDependsJavaParser.cxx"
+ break;
+
+ case 123: /* InterfaceHeader: Modifiersopt jp_INTERFACE Identifier */
+#line 1103 "cmDependsJavaParser.y"
+{
+ yyGetParser->StartClass((yyvsp[0].str));
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
+ jpCheckEmpty(3);
+}
+#line 3673 "cmDependsJavaParser.cxx"
+ break;
+
+ case 124: /* InterfaceDeclaration: InterfaceHeader ExtendsInterfacesopt InterfaceBody */
+#line 1112 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+#line 3685 "cmDependsJavaParser.cxx"
+ break;
+
+ case 125: /* ExtendsInterfacesopt: %empty */
+#line 1121 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+#line 3695 "cmDependsJavaParser.cxx"
+ break;
+
+ case 126: /* ExtendsInterfacesopt: ExtendsInterfaces */
+#line 1128 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3707 "cmDependsJavaParser.cxx"
+ break;
+
+ case 127: /* ExtendsInterfaces: jp_EXTENDS InterfaceType */
+#line 1138 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3719 "cmDependsJavaParser.cxx"
+ break;
+
+ case 128: /* ExtendsInterfaces: ExtendsInterfaces jp_COMMA InterfaceType */
+#line 1147 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3731 "cmDependsJavaParser.cxx"
+ break;
+
+ case 129: /* InterfaceBody: jp_CURLYSTART InterfaceMemberDeclarations jp_CURLYEND */
+#line 1157 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3743 "cmDependsJavaParser.cxx"
+ break;
+
+ case 130: /* InterfaceMemberDeclarations: %empty */
+#line 1166 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3754 "cmDependsJavaParser.cxx"
+ break;
+
+ case 131: /* InterfaceMemberDeclarations: InterfaceMemberDeclarations InterfaceMemberDeclaration */
+#line 1174 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3765 "cmDependsJavaParser.cxx"
+ break;
+
+ case 132: /* InterfaceMemberDeclaration: ConstantDeclaration */
+#line 1183 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3777 "cmDependsJavaParser.cxx"
+ break;
+
+ case 133: /* InterfaceMemberDeclaration: AbstractMethodDeclaration */
+#line 1192 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3789 "cmDependsJavaParser.cxx"
+ break;
+
+ case 134: /* InterfaceMemberDeclaration: ClassDeclaration */
+#line 1201 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3801 "cmDependsJavaParser.cxx"
+ break;
+
+ case 135: /* InterfaceMemberDeclaration: ClassDeclaration jp_SEMICOL */
+#line 1210 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3812 "cmDependsJavaParser.cxx"
+ break;
+
+ case 136: /* InterfaceMemberDeclaration: InterfaceDeclaration */
+#line 1218 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3824 "cmDependsJavaParser.cxx"
+ break;
+
+ case 137: /* InterfaceMemberDeclaration: InterfaceDeclaration jp_SEMICOL */
+#line 1227 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3835 "cmDependsJavaParser.cxx"
+ break;
+
+ case 138: /* ConstantDeclaration: FieldDeclaration */
+#line 1236 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3847 "cmDependsJavaParser.cxx"
+ break;
+
+ case 139: /* AbstractMethodDeclaration: MethodHeader Semicols */
+#line 1246 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3859 "cmDependsJavaParser.cxx"
+ break;
+
+ case 140: /* Semicols: jp_SEMICOL */
+#line 1256 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3871 "cmDependsJavaParser.cxx"
+ break;
+
+ case 141: /* Semicols: Semicols jp_SEMICOL */
+#line 1265 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3883 "cmDependsJavaParser.cxx"
+ break;
+
+ case 142: /* ArrayInitializer: jp_CURLYSTART VariableInitializersOptional jp_CURLYEND */
+#line 1275 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3895 "cmDependsJavaParser.cxx"
+ break;
+
+ case 143: /* VariableInitializersOptional: %empty */
+#line 1284 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3906 "cmDependsJavaParser.cxx"
+ break;
+
+ case 144: /* VariableInitializersOptional: VariableInitializers */
+#line 1292 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3918 "cmDependsJavaParser.cxx"
+ break;
+
+ case 145: /* VariableInitializersOptional: VariableInitializers jp_COMMA */
+#line 1301 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3930 "cmDependsJavaParser.cxx"
+ break;
+
+ case 146: /* VariableInitializers: VariableInitializer */
+#line 1311 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3942 "cmDependsJavaParser.cxx"
+ break;
+
+ case 147: /* VariableInitializers: VariableInitializers jp_COMMA VariableInitializer */
+#line 1320 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3954 "cmDependsJavaParser.cxx"
+ break;
+
+ case 148: /* Block: jp_CURLYSTART BlockStatementsopt jp_CURLYEND */
+#line 1330 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3965 "cmDependsJavaParser.cxx"
+ break;
+
+ case 149: /* BlockStatementsopt: %empty */
+#line 1338 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3976 "cmDependsJavaParser.cxx"
+ break;
+
+ case 150: /* BlockStatementsopt: BlockStatements */
+#line 1346 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 3988 "cmDependsJavaParser.cxx"
+ break;
+
+ case 151: /* BlockStatements: BlockStatement */
+#line 1356 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4000 "cmDependsJavaParser.cxx"
+ break;
+
+ case 152: /* BlockStatements: BlockStatements BlockStatement */
+#line 1365 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4012 "cmDependsJavaParser.cxx"
+ break;
+
+ case 153: /* BlockStatement: LocalVariableDeclarationStatement */
+#line 1375 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4024 "cmDependsJavaParser.cxx"
+ break;
+
+ case 154: /* BlockStatement: Statement */
+#line 1384 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4036 "cmDependsJavaParser.cxx"
+ break;
+
+ case 155: /* BlockStatement: ClassDeclaration */
+#line 1393 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4048 "cmDependsJavaParser.cxx"
+ break;
+
+ case 156: /* LocalVariableDeclarationStatement: LocalVariableDeclaration jp_SEMICOL */
+#line 1403 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4060 "cmDependsJavaParser.cxx"
+ break;
+
+ case 157: /* LocalVariableDeclaration: Modifiers Type VariableDeclarators */
+#line 1413 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4072 "cmDependsJavaParser.cxx"
+ break;
+
+ case 158: /* LocalVariableDeclaration: Type VariableDeclarators */
+#line 1422 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4084 "cmDependsJavaParser.cxx"
+ break;
+
+ case 159: /* Statement: StatementWithoutTrailingSubstatement */
+#line 1432 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4096 "cmDependsJavaParser.cxx"
+ break;
+
+ case 160: /* Statement: LabeledStatement */
+#line 1441 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4108 "cmDependsJavaParser.cxx"
+ break;
+
+ case 161: /* Statement: IfThenStatement */
+#line 1450 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4120 "cmDependsJavaParser.cxx"
+ break;
+
+ case 162: /* Statement: IfThenElseStatement */
+#line 1459 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4132 "cmDependsJavaParser.cxx"
+ break;
+
+ case 163: /* Statement: WhileStatement */
+#line 1468 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4144 "cmDependsJavaParser.cxx"
+ break;
+
+ case 164: /* Statement: ForStatement */
+#line 1477 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4156 "cmDependsJavaParser.cxx"
+ break;
+
+ case 165: /* StatementNoShortIf: StatementWithoutTrailingSubstatement */
+#line 1487 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4168 "cmDependsJavaParser.cxx"
+ break;
+
+ case 166: /* StatementNoShortIf: LabeledStatementNoShortIf */
+#line 1496 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4180 "cmDependsJavaParser.cxx"
+ break;
+
+ case 167: /* StatementNoShortIf: IfThenElseStatementNoShortIf */
+#line 1505 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4192 "cmDependsJavaParser.cxx"
+ break;
+
+ case 168: /* StatementNoShortIf: WhileStatementNoShortIf */
+#line 1514 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4204 "cmDependsJavaParser.cxx"
+ break;
+
+ case 169: /* StatementNoShortIf: ForStatementNoShortIf */
+#line 1523 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4216 "cmDependsJavaParser.cxx"
+ break;
+
+ case 170: /* StatementWithoutTrailingSubstatement: Block */
+#line 1533 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4228 "cmDependsJavaParser.cxx"
+ break;
+
+ case 171: /* StatementWithoutTrailingSubstatement: EmptyStatement */
+#line 1542 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4240 "cmDependsJavaParser.cxx"
+ break;
+
+ case 172: /* StatementWithoutTrailingSubstatement: ExpressionStatement */
+#line 1551 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4252 "cmDependsJavaParser.cxx"
+ break;
+
+ case 173: /* StatementWithoutTrailingSubstatement: SwitchStatement */
+#line 1560 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4264 "cmDependsJavaParser.cxx"
+ break;
+
+ case 174: /* StatementWithoutTrailingSubstatement: DoStatement */
+#line 1569 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4276 "cmDependsJavaParser.cxx"
+ break;
+
+ case 175: /* StatementWithoutTrailingSubstatement: BreakStatement */
+#line 1578 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4288 "cmDependsJavaParser.cxx"
+ break;
+
+ case 176: /* StatementWithoutTrailingSubstatement: ContinueStatement */
+#line 1587 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4300 "cmDependsJavaParser.cxx"
+ break;
+
+ case 177: /* StatementWithoutTrailingSubstatement: ReturnStatement */
+#line 1596 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4312 "cmDependsJavaParser.cxx"
+ break;
+
+ case 178: /* StatementWithoutTrailingSubstatement: SynchronizedStatement */
+#line 1605 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4324 "cmDependsJavaParser.cxx"
+ break;
+
+ case 179: /* StatementWithoutTrailingSubstatement: ThrowStatement */
+#line 1614 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4336 "cmDependsJavaParser.cxx"
+ break;
+
+ case 180: /* StatementWithoutTrailingSubstatement: TryStatement */
+#line 1623 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4348 "cmDependsJavaParser.cxx"
+ break;
+
+ case 181: /* StatementWithoutTrailingSubstatement: AssertStatement */
+#line 1632 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4360 "cmDependsJavaParser.cxx"
+ break;
+
+ case 182: /* EmptyStatement: jp_SEMICOL */
+#line 1642 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4372 "cmDependsJavaParser.cxx"
+ break;
+
+ case 183: /* LabeledStatement: Identifier jp_COLON Statement */
+#line 1652 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&((yyvsp[-2].str)));
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4385 "cmDependsJavaParser.cxx"
+ break;
+
+ case 184: /* LabeledStatementNoShortIf: Identifier jp_COLON StatementNoShortIf */
+#line 1663 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4397 "cmDependsJavaParser.cxx"
+ break;
+
+ case 185: /* ExpressionStatement: StatementExpression jp_SEMICOL */
+#line 1673 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4409 "cmDependsJavaParser.cxx"
+ break;
+
+ case 186: /* StatementExpression: Assignment */
+#line 1683 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4421 "cmDependsJavaParser.cxx"
+ break;
+
+ case 187: /* StatementExpression: PreIncrementExpression */
+#line 1692 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4433 "cmDependsJavaParser.cxx"
+ break;
+
+ case 188: /* StatementExpression: PreDecrementExpression */
+#line 1701 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4445 "cmDependsJavaParser.cxx"
+ break;
+
+ case 189: /* StatementExpression: PostIncrementExpression */
+#line 1710 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4457 "cmDependsJavaParser.cxx"
+ break;
+
+ case 190: /* StatementExpression: PostDecrementExpression */
+#line 1719 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4469 "cmDependsJavaParser.cxx"
+ break;
+
+ case 191: /* StatementExpression: MethodInvocation */
+#line 1728 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4481 "cmDependsJavaParser.cxx"
+ break;
+
+ case 192: /* StatementExpression: ClassInstanceCreationExpression */
+#line 1737 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4493 "cmDependsJavaParser.cxx"
+ break;
+
+ case 193: /* IfThenStatement: jp_IF jp_PARESTART Expression jp_PAREEND Statement */
+#line 1747 "cmDependsJavaParser.y"
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4505 "cmDependsJavaParser.cxx"
+ break;
+
+ case 194: /* IfThenElseStatement: jp_IF jp_PARESTART Expression jp_PAREEND StatementNoShortIf jp_ELSE Statement */
+#line 1757 "cmDependsJavaParser.y"
+{
+ jpElementStart(7);
+ jpCheckEmpty(7);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4517 "cmDependsJavaParser.cxx"
+ break;
+
+ case 195: /* IfThenElseStatementNoShortIf: jp_IF jp_PARESTART Expression jp_PAREEND StatementNoShortIf jp_ELSE StatementNoShortIf */
+#line 1767 "cmDependsJavaParser.y"
+{
+ jpElementStart(7);
+ jpCheckEmpty(7);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4529 "cmDependsJavaParser.cxx"
+ break;
+
+ case 196: /* SwitchStatement: jp_SWITCH jp_PARESTART Expression jp_PAREEND SwitchBlock */
+#line 1777 "cmDependsJavaParser.y"
+{
+ jpElementStart(5);
+
+}
+#line 4538 "cmDependsJavaParser.cxx"
+ break;
+
+ case 197: /* SwitchBlock: jp_CURLYSTART SwitchBlockStatementGroups SwitchLabelsopt jp_CURLYEND */
+#line 1784 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+
+}
+#line 4547 "cmDependsJavaParser.cxx"
+ break;
+
+ case 198: /* SwitchLabelsopt: %empty */
+#line 1790 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4558 "cmDependsJavaParser.cxx"
+ break;
+
+ case 199: /* SwitchLabelsopt: SwitchLabels */
+#line 1798 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4570 "cmDependsJavaParser.cxx"
+ break;
+
+ case 200: /* SwitchBlockStatementGroups: %empty */
+#line 1807 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4581 "cmDependsJavaParser.cxx"
+ break;
+
+ case 201: /* SwitchBlockStatementGroups: SwitchBlockStatementGroups SwitchBlockStatementGroup */
+#line 1815 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4593 "cmDependsJavaParser.cxx"
+ break;
+
+ case 202: /* SwitchBlockStatementGroup: SwitchLabels BlockStatements */
+#line 1825 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4605 "cmDependsJavaParser.cxx"
+ break;
+
+ case 203: /* SwitchLabels: SwitchLabel */
+#line 1835 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4617 "cmDependsJavaParser.cxx"
+ break;
+
+ case 204: /* SwitchLabels: SwitchLabels SwitchLabel */
+#line 1844 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4629 "cmDependsJavaParser.cxx"
+ break;
+
+ case 205: /* SwitchLabel: jp_CASE ConstantExpression jp_COLON */
+#line 1854 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4641 "cmDependsJavaParser.cxx"
+ break;
+
+ case 206: /* SwitchLabel: jp_DEFAULT jp_COLON */
+#line 1863 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4653 "cmDependsJavaParser.cxx"
+ break;
+
+ case 207: /* WhileStatement: jp_WHILE jp_PARESTART Expression jp_PAREEND Statement */
+#line 1873 "cmDependsJavaParser.y"
+{
+ jpElementStart(5);
+
+}
+#line 4662 "cmDependsJavaParser.cxx"
+ break;
+
+ case 208: /* WhileStatementNoShortIf: jp_WHILE jp_PARESTART Expression jp_PAREEND StatementNoShortIf */
+#line 1880 "cmDependsJavaParser.y"
+{
+ jpElementStart(5);
+
+}
+#line 4671 "cmDependsJavaParser.cxx"
+ break;
+
+ case 209: /* DoStatement: jp_DO Statement jp_WHILE jp_PARESTART Expression jp_PAREEND jp_SEMICOL */
+#line 1887 "cmDependsJavaParser.y"
+{
+ jpElementStart(7);
+
+}
+#line 4680 "cmDependsJavaParser.cxx"
+ break;
+
+ case 210: /* ForStatement: jp_FOR jp_PARESTART ForInitopt jp_SEMICOL Expressionopt jp_SEMICOL ForUpdateopt jp_PAREEND Statement */
+#line 1895 "cmDependsJavaParser.y"
+{
+ jpElementStart(9);
+
+}
+#line 4689 "cmDependsJavaParser.cxx"
+ break;
+
+ case 211: /* ForUpdateopt: %empty */
+#line 1901 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4700 "cmDependsJavaParser.cxx"
+ break;
+
+ case 212: /* ForUpdateopt: ForUpdate */
+#line 1909 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4712 "cmDependsJavaParser.cxx"
+ break;
+
+ case 213: /* ForInitopt: %empty */
+#line 1918 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4723 "cmDependsJavaParser.cxx"
+ break;
+
+ case 214: /* ForInitopt: ForInit */
+#line 1926 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4735 "cmDependsJavaParser.cxx"
+ break;
+
+ case 215: /* ForStatementNoShortIf: jp_FOR jp_PARESTART ForInitopt jp_SEMICOL Expressionopt jp_SEMICOL ForUpdateopt jp_PAREEND StatementNoShortIf */
+#line 1937 "cmDependsJavaParser.y"
+{
+ jpElementStart(9);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4746 "cmDependsJavaParser.cxx"
+ break;
+
+ case 216: /* Expressionopt: %empty */
+#line 1945 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4757 "cmDependsJavaParser.cxx"
+ break;
+
+ case 217: /* Expressionopt: Expression */
+#line 1953 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4769 "cmDependsJavaParser.cxx"
+ break;
+
+ case 218: /* ForInit: StatementExpressionList */
+#line 1963 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4781 "cmDependsJavaParser.cxx"
+ break;
+
+ case 219: /* ForInit: LocalVariableDeclaration */
+#line 1972 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4793 "cmDependsJavaParser.cxx"
+ break;
+
+ case 220: /* ForUpdate: StatementExpressionList */
+#line 1982 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4805 "cmDependsJavaParser.cxx"
+ break;
+
+ case 221: /* StatementExpressionList: StatementExpression */
+#line 1992 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4817 "cmDependsJavaParser.cxx"
+ break;
+
+ case 222: /* StatementExpressionList: StatementExpressionList jp_COMMA StatementExpression */
+#line 2001 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4829 "cmDependsJavaParser.cxx"
+ break;
+
+ case 223: /* AssertStatement: jp_ASSERT Expression jp_SEMICOL */
+#line 2011 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4841 "cmDependsJavaParser.cxx"
+ break;
+
+ case 224: /* AssertStatement: jp_ASSERT Expression jp_COLON Expression jp_SEMICOL */
+#line 2020 "cmDependsJavaParser.y"
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4853 "cmDependsJavaParser.cxx"
+ break;
+
+ case 225: /* BreakStatement: jp_BREAK Identifieropt jp_SEMICOL */
+#line 2030 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&((yyvsp[-1].str)));
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4866 "cmDependsJavaParser.cxx"
+ break;
+
+ case 226: /* Identifieropt: %empty */
+#line 2040 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4877 "cmDependsJavaParser.cxx"
+ break;
+
+ case 227: /* Identifieropt: Identifier */
+#line 2048 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+
+}
+#line 4886 "cmDependsJavaParser.cxx"
+ break;
+
+ case 228: /* ContinueStatement: jp_CONTINUE Identifieropt jp_SEMICOL */
+#line 2055 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&((yyvsp[-1].str)));
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4899 "cmDependsJavaParser.cxx"
+ break;
+
+ case 229: /* ReturnStatement: jp_RETURN Expressionopt jp_SEMICOL */
+#line 2066 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4911 "cmDependsJavaParser.cxx"
+ break;
+
+ case 230: /* ThrowStatement: jp_THROW Expression jp_SEMICOL */
+#line 2076 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4923 "cmDependsJavaParser.cxx"
+ break;
+
+ case 231: /* SynchronizedStatement: jp_SYNCHRONIZED jp_PARESTART Expression jp_PAREEND Block */
+#line 2086 "cmDependsJavaParser.y"
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4935 "cmDependsJavaParser.cxx"
+ break;
+
+ case 232: /* TryStatement: jp_TRY Block Catches */
+#line 2096 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4947 "cmDependsJavaParser.cxx"
+ break;
+
+ case 233: /* TryStatement: jp_TRY Block Catchesopt Finally */
+#line 2105 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4959 "cmDependsJavaParser.cxx"
+ break;
+
+ case 234: /* Catchesopt: %empty */
+#line 2114 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4970 "cmDependsJavaParser.cxx"
+ break;
+
+ case 235: /* Catchesopt: Catches */
+#line 2122 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4982 "cmDependsJavaParser.cxx"
+ break;
+
+ case 236: /* Catches: CatchClause */
+#line 2132 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 4994 "cmDependsJavaParser.cxx"
+ break;
+
+ case 237: /* Catches: Catches CatchClause */
+#line 2141 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5006 "cmDependsJavaParser.cxx"
+ break;
+
+ case 238: /* CatchClause: jp_CATCH jp_PARESTART FormalParameter jp_PAREEND Block */
+#line 2151 "cmDependsJavaParser.y"
+{
+ jpElementStart(5);
+
+}
+#line 5015 "cmDependsJavaParser.cxx"
+ break;
+
+ case 239: /* Finally: jp_FINALLY Block */
+#line 2158 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5027 "cmDependsJavaParser.cxx"
+ break;
+
+ case 240: /* Primary: PrimaryNoNewArray */
+#line 2168 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5039 "cmDependsJavaParser.cxx"
+ break;
+
+ case 241: /* Primary: ArrayCreationExpression */
+#line 2177 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5051 "cmDependsJavaParser.cxx"
+ break;
+
+ case 242: /* PrimaryNoNewArray: Literal */
+#line 2187 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5063 "cmDependsJavaParser.cxx"
+ break;
+
+ case 243: /* PrimaryNoNewArray: jp_THIS */
+#line 2196 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+
+}
+#line 5072 "cmDependsJavaParser.cxx"
+ break;
+
+ case 244: /* PrimaryNoNewArray: jp_PARESTART Expression jp_PAREEND */
+#line 2202 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5084 "cmDependsJavaParser.cxx"
+ break;
+
+ case 245: /* PrimaryNoNewArray: ClassInstanceCreationExpression */
+#line 2211 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5096 "cmDependsJavaParser.cxx"
+ break;
+
+ case 246: /* PrimaryNoNewArray: FieldAccess */
+#line 2220 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5108 "cmDependsJavaParser.cxx"
+ break;
+
+ case 247: /* PrimaryNoNewArray: MethodInvocation */
+#line 2229 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5120 "cmDependsJavaParser.cxx"
+ break;
+
+ case 248: /* PrimaryNoNewArray: ArrayAccess */
+#line 2238 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5132 "cmDependsJavaParser.cxx"
+ break;
+
+ case 249: /* ClassInstanceCreationExpression: New ClassType jp_PARESTART ArgumentListopt jp_PAREEND ClassBodyOpt */
+#line 2248 "cmDependsJavaParser.y"
+{
+ jpElementStart(6);
+ jpCheckEmpty(6);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5144 "cmDependsJavaParser.cxx"
+ break;
+
+ case 250: /* ClassBodyOpt: %empty */
+#line 2257 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5155 "cmDependsJavaParser.cxx"
+ break;
+
+ case 251: /* ClassBodyOpt: ClassBody */
+#line 2265 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5167 "cmDependsJavaParser.cxx"
+ break;
+
+ case 252: /* ArgumentListopt: %empty */
+#line 2274 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5178 "cmDependsJavaParser.cxx"
+ break;
+
+ case 253: /* ArgumentListopt: ArgumentList */
+#line 2282 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5190 "cmDependsJavaParser.cxx"
+ break;
+
+ case 254: /* ArgumentList: Expression */
+#line 2292 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5202 "cmDependsJavaParser.cxx"
+ break;
+
+ case 255: /* ArgumentList: ArgumentList jp_COMMA Expression */
+#line 2301 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5214 "cmDependsJavaParser.cxx"
+ break;
+
+ case 256: /* ArrayCreationExpression: New PrimitiveType DimExprs Dimsopt */
+#line 2311 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5226 "cmDependsJavaParser.cxx"
+ break;
+
+ case 257: /* ArrayCreationExpression: New ClassOrInterfaceType DimExprs Dimsopt */
+#line 2320 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5238 "cmDependsJavaParser.cxx"
+ break;
+
+ case 258: /* ArrayCreationExpression: New PrimitiveType Dims ArrayInitializer */
+#line 2329 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5250 "cmDependsJavaParser.cxx"
+ break;
+
+ case 259: /* ArrayCreationExpression: New ClassOrInterfaceType Dims ArrayInitializer */
+#line 2338 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5262 "cmDependsJavaParser.cxx"
+ break;
+
+ case 260: /* Dimsopt: %empty */
+#line 2347 "cmDependsJavaParser.y"
+{
+ jpElementStart(0);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5273 "cmDependsJavaParser.cxx"
+ break;
+
+ case 261: /* Dimsopt: Dims */
+#line 2355 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5285 "cmDependsJavaParser.cxx"
+ break;
+
+ case 262: /* DimExprs: DimExpr */
+#line 2365 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5297 "cmDependsJavaParser.cxx"
+ break;
+
+ case 263: /* DimExprs: DimExprs DimExpr */
+#line 2374 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5309 "cmDependsJavaParser.cxx"
+ break;
+
+ case 264: /* DimExpr: jp_BRACKETSTART Expression jp_BRACKETEND */
+#line 2384 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5321 "cmDependsJavaParser.cxx"
+ break;
+
+ case 265: /* Dims: jp_BRACKETSTART jp_BRACKETEND */
+#line 2394 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+
+}
+#line 5330 "cmDependsJavaParser.cxx"
+ break;
+
+ case 266: /* Dims: Dims jp_BRACKETSTART jp_BRACKETEND */
+#line 2400 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+
+}
+#line 5339 "cmDependsJavaParser.cxx"
+ break;
+
+ case 267: /* FieldAccess: Primary jp_DOT Identifier */
+#line 2407 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5352 "cmDependsJavaParser.cxx"
+ break;
+
+ case 268: /* FieldAccess: jp_SUPER jp_DOT Identifier */
+#line 2417 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5365 "cmDependsJavaParser.cxx"
+ break;
+
+ case 269: /* FieldAccess: jp_THIS jp_DOT Identifier */
+#line 2427 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5378 "cmDependsJavaParser.cxx"
+ break;
+
+ case 270: /* FieldAccess: Primary jp_DOT jp_THIS */
+#line 2437 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5391 "cmDependsJavaParser.cxx"
+ break;
+
+ case 271: /* MethodInvocation: Name jp_PARESTART ArgumentListopt jp_PAREEND */
+#line 2448 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5404 "cmDependsJavaParser.cxx"
+ break;
+
+ case 272: /* MethodInvocation: Primary jp_DOT Identifier jp_PARESTART ArgumentListopt jp_PAREEND */
+#line 2458 "cmDependsJavaParser.y"
+{
+ jpElementStart(6);
+ yyGetParser->DeallocateParserType(&((yyvsp[-5].str)));
+ yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
+ jpCheckEmpty(6);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5418 "cmDependsJavaParser.cxx"
+ break;
+
+ case 273: /* MethodInvocation: jp_SUPER jp_DOT Identifier jp_PARESTART ArgumentListopt jp_PAREEND */
+#line 2469 "cmDependsJavaParser.y"
+{
+ jpElementStart(6);
+ yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
+ jpCheckEmpty(6);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5431 "cmDependsJavaParser.cxx"
+ break;
+
+ case 274: /* MethodInvocation: jp_THIS jp_DOT Identifier jp_PARESTART ArgumentListopt jp_PAREEND */
+#line 2479 "cmDependsJavaParser.y"
+{
+ jpElementStart(6);
+ yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
+ jpCheckEmpty(6);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5444 "cmDependsJavaParser.cxx"
+ break;
+
+ case 275: /* ArrayAccess: Name jp_BRACKETSTART Expression jp_BRACKETEND */
+#line 2490 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5457 "cmDependsJavaParser.cxx"
+ break;
+
+ case 276: /* ArrayAccess: PrimaryNoNewArray jp_BRACKETSTART Expression jp_BRACKETEND */
+#line 2500 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5469 "cmDependsJavaParser.cxx"
+ break;
+
+ case 277: /* PostfixExpression: Primary */
+#line 2510 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5481 "cmDependsJavaParser.cxx"
+ break;
+
+ case 278: /* PostfixExpression: Name */
+#line 2519 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5493 "cmDependsJavaParser.cxx"
+ break;
+
+ case 279: /* PostfixExpression: ArrayType jp_DOT jp_CLASS */
+#line 2528 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5505 "cmDependsJavaParser.cxx"
+ break;
+
+ case 280: /* PostfixExpression: PostIncrementExpression */
+#line 2537 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5517 "cmDependsJavaParser.cxx"
+ break;
+
+ case 281: /* PostfixExpression: PostDecrementExpression */
+#line 2546 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5529 "cmDependsJavaParser.cxx"
+ break;
+
+ case 282: /* PostIncrementExpression: PostfixExpression jp_PLUSPLUS */
+#line 2556 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5541 "cmDependsJavaParser.cxx"
+ break;
+
+ case 283: /* PostDecrementExpression: PostfixExpression jp_MINUSMINUS */
+#line 2566 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5553 "cmDependsJavaParser.cxx"
+ break;
+
+ case 284: /* UnaryExpression: PreIncrementExpression */
+#line 2576 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5565 "cmDependsJavaParser.cxx"
+ break;
+
+ case 285: /* UnaryExpression: PreDecrementExpression */
+#line 2585 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5577 "cmDependsJavaParser.cxx"
+ break;
+
+ case 286: /* UnaryExpression: jp_PLUS UnaryExpression */
+#line 2594 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5589 "cmDependsJavaParser.cxx"
+ break;
+
+ case 287: /* UnaryExpression: jp_MINUS UnaryExpression */
+#line 2603 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5601 "cmDependsJavaParser.cxx"
+ break;
+
+ case 288: /* UnaryExpression: UnaryExpressionNotPlusMinus */
+#line 2612 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5613 "cmDependsJavaParser.cxx"
+ break;
+
+ case 289: /* PreIncrementExpression: jp_PLUSPLUS UnaryExpression */
+#line 2622 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5625 "cmDependsJavaParser.cxx"
+ break;
+
+ case 290: /* PreDecrementExpression: jp_MINUSMINUS UnaryExpression */
+#line 2632 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5637 "cmDependsJavaParser.cxx"
+ break;
+
+ case 291: /* UnaryExpressionNotPlusMinus: PostfixExpression */
+#line 2642 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5649 "cmDependsJavaParser.cxx"
+ break;
+
+ case 292: /* UnaryExpressionNotPlusMinus: jp_TILDE UnaryExpression */
+#line 2651 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5661 "cmDependsJavaParser.cxx"
+ break;
+
+ case 293: /* UnaryExpressionNotPlusMinus: jp_EXCLAMATION UnaryExpression */
+#line 2660 "cmDependsJavaParser.y"
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5673 "cmDependsJavaParser.cxx"
+ break;
+
+ case 294: /* UnaryExpressionNotPlusMinus: CastExpression */
+#line 2669 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5685 "cmDependsJavaParser.cxx"
+ break;
+
+ case 295: /* CastExpression: jp_PARESTART PrimitiveType Dimsopt jp_PAREEND UnaryExpression */
+#line 2679 "cmDependsJavaParser.y"
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5697 "cmDependsJavaParser.cxx"
+ break;
+
+ case 296: /* CastExpression: jp_PARESTART Expression jp_PAREEND UnaryExpressionNotPlusMinus */
+#line 2688 "cmDependsJavaParser.y"
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5709 "cmDependsJavaParser.cxx"
+ break;
+
+ case 297: /* CastExpression: jp_PARESTART Name Dims jp_PAREEND UnaryExpressionNotPlusMinus */
+#line 2697 "cmDependsJavaParser.y"
+{
+ jpElementStart(5);
+
+}
+#line 5718 "cmDependsJavaParser.cxx"
+ break;
+
+ case 298: /* MultiplicativeExpression: UnaryExpression */
+#line 2704 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5730 "cmDependsJavaParser.cxx"
+ break;
+
+ case 299: /* MultiplicativeExpression: MultiplicativeExpression jp_TIMES UnaryExpression */
+#line 2713 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5742 "cmDependsJavaParser.cxx"
+ break;
+
+ case 300: /* MultiplicativeExpression: MultiplicativeExpression jp_DIVIDE UnaryExpression */
+#line 2722 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5754 "cmDependsJavaParser.cxx"
+ break;
+
+ case 301: /* MultiplicativeExpression: MultiplicativeExpression jp_PERCENT UnaryExpression */
+#line 2731 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5766 "cmDependsJavaParser.cxx"
+ break;
+
+ case 302: /* AdditiveExpression: MultiplicativeExpression */
+#line 2741 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5778 "cmDependsJavaParser.cxx"
+ break;
+
+ case 303: /* AdditiveExpression: AdditiveExpression jp_PLUS MultiplicativeExpression */
+#line 2750 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5790 "cmDependsJavaParser.cxx"
+ break;
+
+ case 304: /* AdditiveExpression: AdditiveExpression jp_MINUS MultiplicativeExpression */
+#line 2759 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5802 "cmDependsJavaParser.cxx"
+ break;
+
+ case 305: /* ShiftExpression: AdditiveExpression */
+#line 2769 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5814 "cmDependsJavaParser.cxx"
+ break;
+
+ case 306: /* ShiftExpression: ShiftExpression jp_LTLT AdditiveExpression */
+#line 2778 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5826 "cmDependsJavaParser.cxx"
+ break;
+
+ case 307: /* ShiftExpression: ShiftExpression jp_GTGT AdditiveExpression */
+#line 2787 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5838 "cmDependsJavaParser.cxx"
+ break;
+
+ case 308: /* ShiftExpression: ShiftExpression jp_GTGTGT AdditiveExpression */
+#line 2796 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5850 "cmDependsJavaParser.cxx"
+ break;
+
+ case 309: /* RelationalExpression: ShiftExpression */
+#line 2806 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5862 "cmDependsJavaParser.cxx"
+ break;
+
+ case 310: /* RelationalExpression: RelationalExpression jp_LESSTHAN ShiftExpression */
+#line 2815 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5874 "cmDependsJavaParser.cxx"
+ break;
+
+ case 311: /* RelationalExpression: RelationalExpression jp_GREATER ShiftExpression */
+#line 2824 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5886 "cmDependsJavaParser.cxx"
+ break;
+
+ case 312: /* RelationalExpression: RelationalExpression jp_LTEQUALS ShiftExpression */
+#line 2833 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5898 "cmDependsJavaParser.cxx"
+ break;
+
+ case 313: /* RelationalExpression: RelationalExpression jp_GTEQUALS ShiftExpression */
+#line 2842 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5910 "cmDependsJavaParser.cxx"
+ break;
+
+ case 314: /* RelationalExpression: RelationalExpression jp_INSTANCEOF ReferenceType */
+#line 2851 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5922 "cmDependsJavaParser.cxx"
+ break;
+
+ case 315: /* EqualityExpression: RelationalExpression */
+#line 2861 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5934 "cmDependsJavaParser.cxx"
+ break;
+
+ case 316: /* EqualityExpression: EqualityExpression jp_EQUALSEQUALS RelationalExpression */
+#line 2870 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5946 "cmDependsJavaParser.cxx"
+ break;
+
+ case 317: /* EqualityExpression: EqualityExpression jp_EXCLAMATIONEQUALS RelationalExpression */
+#line 2879 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5958 "cmDependsJavaParser.cxx"
+ break;
+
+ case 318: /* AndExpression: EqualityExpression */
+#line 2889 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5970 "cmDependsJavaParser.cxx"
+ break;
+
+ case 319: /* AndExpression: AndExpression jp_AND EqualityExpression */
+#line 2898 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5982 "cmDependsJavaParser.cxx"
+ break;
+
+ case 320: /* ExclusiveOrExpression: AndExpression */
+#line 2908 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 5994 "cmDependsJavaParser.cxx"
+ break;
+
+ case 321: /* ExclusiveOrExpression: ExclusiveOrExpression jp_CARROT AndExpression */
+#line 2917 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6006 "cmDependsJavaParser.cxx"
+ break;
+
+ case 322: /* InclusiveOrExpression: ExclusiveOrExpression */
+#line 2927 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6018 "cmDependsJavaParser.cxx"
+ break;
+
+ case 323: /* InclusiveOrExpression: InclusiveOrExpression jp_PIPE ExclusiveOrExpression */
+#line 2936 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6030 "cmDependsJavaParser.cxx"
+ break;
+
+ case 324: /* ConditionalAndExpression: InclusiveOrExpression */
+#line 2946 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6042 "cmDependsJavaParser.cxx"
+ break;
+
+ case 325: /* ConditionalAndExpression: ConditionalAndExpression jp_ANDAND InclusiveOrExpression */
+#line 2955 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6054 "cmDependsJavaParser.cxx"
+ break;
+
+ case 326: /* ConditionalOrExpression: ConditionalAndExpression */
+#line 2965 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6066 "cmDependsJavaParser.cxx"
+ break;
+
+ case 327: /* ConditionalOrExpression: ConditionalOrExpression jp_PIPEPIPE ConditionalAndExpression */
+#line 2974 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6078 "cmDependsJavaParser.cxx"
+ break;
+
+ case 328: /* ConditionalExpression: ConditionalOrExpression */
+#line 2984 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6090 "cmDependsJavaParser.cxx"
+ break;
+
+ case 329: /* ConditionalExpression: ConditionalOrExpression jp_QUESTION Expression jp_COLON ConditionalExpression */
+#line 2993 "cmDependsJavaParser.y"
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6102 "cmDependsJavaParser.cxx"
+ break;
+
+ case 330: /* AssignmentExpression: ConditionalExpression */
+#line 3003 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6114 "cmDependsJavaParser.cxx"
+ break;
+
+ case 331: /* AssignmentExpression: Assignment */
+#line 3012 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6126 "cmDependsJavaParser.cxx"
+ break;
+
+ case 332: /* Assignment: LeftHandSide AssignmentOperator AssignmentExpression */
+#line 3022 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6138 "cmDependsJavaParser.cxx"
+ break;
+
+ case 333: /* LeftHandSide: Name */
+#line 3032 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6151 "cmDependsJavaParser.cxx"
+ break;
+
+ case 334: /* LeftHandSide: FieldAccess */
+#line 3042 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6163 "cmDependsJavaParser.cxx"
+ break;
+
+ case 335: /* LeftHandSide: ArrayAccess */
+#line 3051 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6175 "cmDependsJavaParser.cxx"
+ break;
+
+ case 336: /* AssignmentOperator: jp_EQUALS */
+#line 3061 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6187 "cmDependsJavaParser.cxx"
+ break;
+
+ case 337: /* AssignmentOperator: jp_TIMESEQUALS */
+#line 3070 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6199 "cmDependsJavaParser.cxx"
+ break;
+
+ case 338: /* AssignmentOperator: jp_DIVIDEEQUALS */
+#line 3079 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6211 "cmDependsJavaParser.cxx"
+ break;
+
+ case 339: /* AssignmentOperator: jp_PERCENTEQUALS */
+#line 3088 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6223 "cmDependsJavaParser.cxx"
+ break;
+
+ case 340: /* AssignmentOperator: jp_PLUSEQUALS */
+#line 3097 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6235 "cmDependsJavaParser.cxx"
+ break;
+
+ case 341: /* AssignmentOperator: jp_MINUSEQUALS */
+#line 3106 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6247 "cmDependsJavaParser.cxx"
+ break;
+
+ case 342: /* AssignmentOperator: jp_LESLESEQUALS */
+#line 3115 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6259 "cmDependsJavaParser.cxx"
+ break;
+
+ case 343: /* AssignmentOperator: jp_GTGTEQUALS */
+#line 3124 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6271 "cmDependsJavaParser.cxx"
+ break;
+
+ case 344: /* AssignmentOperator: jp_GTGTGTEQUALS */
+#line 3133 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6283 "cmDependsJavaParser.cxx"
+ break;
+
+ case 345: /* AssignmentOperator: jp_ANDEQUALS */
+#line 3142 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6295 "cmDependsJavaParser.cxx"
+ break;
+
+ case 346: /* AssignmentOperator: jp_CARROTEQUALS */
+#line 3151 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6307 "cmDependsJavaParser.cxx"
+ break;
+
+ case 347: /* AssignmentOperator: jp_PIPEEQUALS */
+#line 3160 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6319 "cmDependsJavaParser.cxx"
+ break;
+
+ case 348: /* Expression: AssignmentExpression */
+#line 3170 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6331 "cmDependsJavaParser.cxx"
+ break;
+
+ case 349: /* ConstantExpression: Expression */
+#line 3180 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6343 "cmDependsJavaParser.cxx"
+ break;
+
+ case 350: /* New: jp_NEW */
+#line 3190 "cmDependsJavaParser.y"
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6355 "cmDependsJavaParser.cxx"
+ break;
+
+ case 351: /* New: Name jp_DOT jp_NEW */
+#line 3199 "cmDependsJavaParser.y"
+{
+ jpElementStart(3);
+ jpStoreClass((yyvsp[-2].str));
+ jpCheckEmpty(3);
+ (yyval.str) = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+#line 6368 "cmDependsJavaParser.cxx"
+ break;
+
+
+#line 6372 "cmDependsJavaParser.cxx"
+
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+
+ *++yyvsp = yyval;
+
+ /* Now 'shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+ {
+ const int yylhs = yyr1[yyn] - YYNTOKENS;
+ const int yyi = yypgoto[yylhs] + *yyssp;
+ yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp
+ ? yytable[yyi]
+ : yydefgoto[yylhs]);
+ }
+
+ goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error. |
+`--------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+ {
+ yypcontext_t yyctx
+ = {yyssp, yytoken};
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == -1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = YY_CAST (char *,
+ YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc)));
+ if (yymsg)
+ {
+ yysyntax_error_status
+ = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+ yymsgp = yymsg;
+ }
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = YYENOMEM;
+ }
+ }
+ yyerror (yyscanner, yymsgp);
+ if (yysyntax_error_status == YYENOMEM)
+ goto yyexhaustedlab;
+ }
+ }
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, yyscanner);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+ /* Pacify compilers when the user code never invokes YYERROR and the
+ label yyerrorlab therefore never appears in user code. */
+ if (0)
+ YYERROR;
+
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ /* Pop stack until we find a state that shifts the error token. */
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYSYMBOL_YYerror;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ YY_ACCESSING_SYMBOL (yystate), yyvsp, yyscanner);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+
+#if 1
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (yyscanner, YY_("memory exhausted"));
+ yyresult = 2;
+ goto yyreturn;
+#endif
+
+
+/*-------------------------------------------------------.
+| yyreturn -- parsing is finished, clean up and return. |
+`-------------------------------------------------------*/
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, yyscanner);
+ }
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yyscanner);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ return yyresult;
+}
+
+#line 3208 "cmDependsJavaParser.y"
+
+/* End of grammar */
+
+/*--------------------------------------------------------------------------*/
+void cmDependsJava_yyerror(yyscan_t yyscanner, const char* message)
+{
+ yyGetParser->Error(message);
+}
diff --git a/Source/LexerParser/cmDependsJavaParser.y b/Source/LexerParser/cmDependsJavaParser.y
new file mode 100644
index 0000000..a76ec50
--- /dev/null
+++ b/Source/LexerParser/cmDependsJavaParser.y
@@ -0,0 +1,3215 @@
+%{
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --name-prefix=cmDependsJava_yy --defines=cmDependsJavaParserTokens.h -ocmDependsJavaParser.cxx cmDependsJavaParser.y
+
+*/
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+
+#define yyGetParser (cmDependsJava_yyget_extra(yyscanner))
+
+/*-------------------------------------------------------------------------*/
+#include "cmDependsJavaParserHelper.h" /* Interface to parser object. */
+#include "cmDependsJavaLexer.h" /* Interface to lexer object. */
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Helper function to forward error callback from parser. */
+static void cmDependsJava_yyerror(yyscan_t yyscanner, const char* message);
+
+#define YYMAXDEPTH 1000000
+
+
+#define jpCheckEmpty(cnt) yyGetParser->CheckEmpty(__LINE__, cnt, yyvsp)
+#define jpElementStart(cnt) yyGetParser->PrepareElement(&yyval)
+#define jpStoreClass(str) yyGetParser->AddClassFound(str); yyGetParser->DeallocateParserType(&(str))
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch statement contains default but no case. */
+#endif
+#if defined(__GNUC__) && __GNUC__ >= 8
+# pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+#endif
+%}
+
+/* Generate a reentrant parser object. */
+%define api.pure
+
+/* Configure the parser to use a lexer object. */
+%lex-param {yyscan_t yyscanner}
+%parse-param {yyscan_t yyscanner}
+
+%define parse.error verbose
+
+/*
+%union {
+ char* string;
+}
+*/
+
+/*-------------------------------------------------------------------------*/
+/* Tokens */
+%token jp_ABSTRACT
+%token jp_ASSERT
+%token jp_BOOLEAN_TYPE
+%token jp_BREAK
+%token jp_BYTE_TYPE
+%token jp_CASE
+%token jp_CATCH
+%token jp_CHAR_TYPE
+%token jp_CLASS
+%token jp_CONTINUE
+%token jp_DEFAULT
+%token jp_DO
+%token jp_DOUBLE_TYPE
+%token jp_ELSE
+%token jp_EXTENDS
+%token jp_FINAL
+%token jp_FINALLY
+%token jp_FLOAT_TYPE
+%token jp_FOR
+%token jp_IF
+%token jp_IMPLEMENTS
+%token jp_IMPORT
+%token jp_INSTANCEOF
+%token jp_INT_TYPE
+%token jp_INTERFACE
+%token jp_LONG_TYPE
+%token jp_NATIVE
+%token jp_NEW
+%token jp_PACKAGE
+%token jp_PRIVATE
+%token jp_PROTECTED
+%token jp_PUBLIC
+%token jp_RETURN
+%token jp_SHORT_TYPE
+%token jp_STATIC
+%token jp_STRICTFP
+%token jp_SUPER
+%token jp_SWITCH
+%token jp_SYNCHRONIZED
+%token jp_THIS
+%token jp_THROW
+%token jp_THROWS
+%token jp_TRANSIENT
+%token jp_TRY
+%token jp_VOID
+%token jp_VOLATILE
+%token jp_WHILE
+
+%token jp_BOOLEANLITERAL
+%token jp_CHARACTERLITERAL
+%token jp_DECIMALINTEGERLITERAL
+%token jp_FLOATINGPOINTLITERAL
+%token jp_HEXINTEGERLITERAL
+%token jp_NULLLITERAL
+%token jp_STRINGLITERAL
+
+%token jp_NAME
+
+%token jp_AND
+%token jp_ANDAND
+%token jp_ANDEQUALS
+%token jp_BRACKETEND
+%token jp_BRACKETSTART
+%token jp_CARROT
+%token jp_CARROTEQUALS
+%token jp_COLON
+%token jp_COMMA
+%token jp_CURLYEND
+%token jp_CURLYSTART
+%token jp_DIVIDE
+%token jp_DIVIDEEQUALS
+%token jp_DOLLAR
+%token jp_DOT
+%token jp_EQUALS
+%token jp_EQUALSEQUALS
+%token jp_EXCLAMATION
+%token jp_EXCLAMATIONEQUALS
+%token jp_GREATER
+%token jp_GTEQUALS
+%token jp_GTGT
+%token jp_GTGTEQUALS
+%token jp_GTGTGT
+%token jp_GTGTGTEQUALS
+%token jp_LESLESEQUALS
+%token jp_LESSTHAN
+%token jp_LTEQUALS
+%token jp_LTLT
+%token jp_MINUS
+%token jp_MINUSEQUALS
+%token jp_MINUSMINUS
+%token jp_PAREEND
+%token jp_PARESTART
+%token jp_PERCENT
+%token jp_PERCENTEQUALS
+%token jp_PIPE
+%token jp_PIPEEQUALS
+%token jp_PIPEPIPE
+%token jp_PLUS
+%token jp_PLUSEQUALS
+%token jp_PLUSPLUS
+%token jp_QUESTION
+%token jp_SEMICOL
+%token jp_TILDE
+%token jp_TIMES
+%token jp_TIMESEQUALS
+
+%token jp_ERROR
+
+/*-------------------------------------------------------------------------*/
+/* grammar */
+%%
+
+Goal:
+CompilationUnit
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+Literal:
+IntegerLiteral
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_FLOATINGPOINTLITERAL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_BOOLEANLITERAL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_CHARACTERLITERAL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_STRINGLITERAL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_NULLLITERAL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+IntegerLiteral:
+jp_DECIMALINTEGERLITERAL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_HEXINTEGERLITERAL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+Type:
+PrimitiveType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+ReferenceType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+PrimitiveType:
+jp_BYTE_TYPE
+{
+ jpElementStart(0);
+}
+|
+jp_SHORT_TYPE
+{
+ jpElementStart(0);
+}
+|
+jp_INT_TYPE
+{
+ jpElementStart(0);
+}
+|
+jp_LONG_TYPE
+{
+ jpElementStart(0);
+}
+|
+jp_CHAR_TYPE
+{
+ jpElementStart(0);
+}
+|
+jp_FLOAT_TYPE
+{
+ jpElementStart(0);
+}
+|
+jp_DOUBLE_TYPE
+{
+ jpElementStart(0);
+}
+|
+jp_BOOLEAN_TYPE
+{
+ jpElementStart(0);
+}
+
+ReferenceType:
+ClassOrInterfaceType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+ArrayType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ClassOrInterfaceType:
+Name
+{
+ jpElementStart(1);
+ jpStoreClass($<str>1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ClassType:
+ClassOrInterfaceType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+InterfaceType:
+ClassOrInterfaceType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ArrayType:
+PrimitiveType Dims
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+Name Dims
+{
+ jpElementStart(2);
+ jpStoreClass($<str>1);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+Name:
+SimpleName
+{
+ jpElementStart(1);
+ $<str>$ = $<str>1;
+}
+|
+QualifiedName
+{
+ jpElementStart(1);
+ $<str>$ = $<str>1;
+}
+
+SimpleName:
+Identifier
+{
+ jpElementStart(1);
+ $<str>$ = $<str>1;
+}
+
+Identifier:
+jp_NAME
+{
+ jpElementStart(1);
+ $<str>$ = $<str>1;
+}
+|
+jp_DOLLAR jp_NAME
+{
+ jpElementStart(2);
+ $<str>$ = $<str>2;
+}
+
+QualifiedName:
+Name jp_DOT Identifier
+{
+ jpElementStart(3);
+ yyGetParser->AddClassFound($<str>1);
+ yyGetParser->UpdateCombine($<str>1, $<str>3);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ $<str>$ = const_cast<char*>(yyGetParser->GetCurrentCombine());
+}
+|
+Name jp_DOT jp_CLASS
+{
+ jpElementStart(3);
+ jpStoreClass($<str>1);
+ jpCheckEmpty(3);
+ yyGetParser->SetCurrentCombine("");
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+Name jp_DOT jp_THIS
+{
+ jpElementStart(3);
+ jpStoreClass($<str>1);
+ yyGetParser->SetCurrentCombine("");
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+SimpleType jp_DOT jp_CLASS
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+SimpleType:
+PrimitiveType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_VOID
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+CompilationUnit:
+PackageDeclarationopt ImportDeclarations TypeDeclarations
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+PackageDeclarationopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+PackageDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ImportDeclarations:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+ImportDeclarations ImportDeclaration
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+TypeDeclarations:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+TypeDeclarations TypeDeclaration
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+PackageDeclaration:
+jp_PACKAGE Name jp_SEMICOL
+{
+ jpElementStart(3);
+ yyGetParser->SetCurrentPackage($<str>2);
+ yyGetParser->DeallocateParserType(&($<str>2));
+ yyGetParser->SetCurrentCombine("");
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ImportDeclaration:
+SingleTypeImportDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+TypeImportOnDemandDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+SingleTypeImportDeclaration:
+jp_IMPORT Name jp_SEMICOL
+{
+ jpElementStart(3);
+ yyGetParser->AddPackagesImport($<str>2);
+ yyGetParser->DeallocateParserType(&($<str>2));
+ yyGetParser->SetCurrentCombine("");
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+TypeImportOnDemandDeclaration:
+jp_IMPORT Name jp_DOT jp_TIMES jp_SEMICOL
+{
+ jpElementStart(5);
+ std::string str = $<str>2;
+ str += ".*";
+ yyGetParser->AddPackagesImport(str.c_str());
+ yyGetParser->DeallocateParserType(&($<str>2));
+ yyGetParser->SetCurrentCombine("");
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+TypeDeclaration:
+ClassDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+InterfaceDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+jp_SEMICOL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+Modifiers:
+Modifier
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+Modifiers Modifier
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+Modifier:
+jp_PUBLIC | jp_PROTECTED | jp_PRIVATE |
+jp_STATIC |
+jp_ABSTRACT | jp_FINAL | jp_NATIVE | jp_SYNCHRONIZED | jp_TRANSIENT | jp_VOLATILE |
+jp_STRICTFP
+
+ClassHeader:
+Modifiersopt jp_CLASS Identifier
+{
+ yyGetParser->StartClass($<str>3);
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(3);
+}
+
+
+ClassDeclaration:
+ClassHeader ClassBody
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+|
+ClassHeader Interfaces ClassBody
+{
+ jpElementStart(3);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+|
+ClassHeader Super ClassBody
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+|
+ClassHeader Super Interfaces ClassBody
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+
+Modifiersopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+Modifiers
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+Super:
+jp_EXTENDS ClassType
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+Interfaces:
+jp_IMPLEMENTS InterfaceTypeList
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+InterfaceTypeList:
+InterfaceType
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+InterfaceTypeList jp_COMMA InterfaceType
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ClassBody:
+jp_CURLYSTART ClassBodyDeclarations jp_CURLYEND
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ClassBodyDeclarations:
+{
+ jpElementStart(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+ClassBodyDeclarations ClassBodyDeclaration
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ClassBodyDeclaration:
+ClassMemberDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+StaticInitializer
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+ConstructorDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+TypeDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+ClassMemberDeclaration:
+FieldDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+MethodDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+FieldDeclaration:
+Modifiersopt Type VariableDeclarators jp_SEMICOL
+{
+ jpElementStart(4);
+}
+
+VariableDeclarators:
+VariableDeclarator
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+VariableDeclarators jp_COMMA VariableDeclarator
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+VariableDeclarator:
+VariableDeclaratorId
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+VariableDeclaratorId jp_EQUALS VariableInitializer
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+VariableDeclaratorId:
+Identifier
+{
+ jpElementStart(1);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+VariableDeclaratorId jp_BRACKETSTART jp_BRACKETEND
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+VariableInitializer:
+Expression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+ArrayInitializer
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+MethodDeclaration:
+MethodHeader jp_SEMICOL
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+MethodHeader MethodBody
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+MethodHeader MethodBody jp_SEMICOL
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+
+MethodHeader:
+Modifiersopt Type MethodDeclarator Throwsopt
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Modifiersopt jp_VOID MethodDeclarator Throwsopt
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Throwsopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Throws
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+MethodDeclarator:
+Identifier jp_PARESTART FormalParameterListopt jp_PAREEND
+{
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+MethodDeclarator jp_BRACKETSTART jp_BRACKETEND
+{
+ jpElementStart(3);
+
+}
+
+FormalParameterListopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+FormalParameterList
+
+FormalParameterList:
+FormalParameter
+{
+ jpElementStart(1);
+
+}
+|
+FormalParameterList jp_COMMA FormalParameter
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+FormalParameter:
+Modifiersopt Type VariableDeclaratorId
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Throws:
+jp_THROWS ClassTypeList
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ClassTypeList:
+ClassType
+{
+ jpElementStart(1);
+
+}
+|
+ClassTypeList jp_COMMA ClassType
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+MethodBody:
+Block
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+StaticInitializer:
+jp_STATIC Block
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConstructorDeclaration:
+Modifiersopt ConstructorDeclarator Throwsopt ConstructorBody
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Modifiersopt ConstructorDeclarator Throwsopt ConstructorBody jp_SEMICOL
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConstructorDeclarator:
+SimpleName jp_PARESTART FormalParameterListopt jp_PAREEND
+{
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConstructorBody:
+jp_CURLYSTART ExplicitConstructorInvocationopt BlockStatementsopt jp_CURLYEND
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ExplicitConstructorInvocationopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ExplicitConstructorInvocationopt ExplicitConstructorInvocation
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ExplicitConstructorInvocation:
+jp_THIS jp_PARESTART ArgumentListopt jp_PAREEND jp_SEMICOL
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_SUPER jp_PARESTART ArgumentListopt jp_PAREEND jp_SEMICOL
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+InterfaceHeader:
+Modifiersopt jp_INTERFACE Identifier
+{
+ yyGetParser->StartClass($<str>3);
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(3);
+}
+
+InterfaceDeclaration:
+InterfaceHeader ExtendsInterfacesopt InterfaceBody
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+ yyGetParser->EndClass();
+}
+
+ExtendsInterfacesopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+}
+|
+ExtendsInterfaces
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ExtendsInterfaces:
+jp_EXTENDS InterfaceType
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ExtendsInterfaces jp_COMMA InterfaceType
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+InterfaceBody:
+jp_CURLYSTART InterfaceMemberDeclarations jp_CURLYEND
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+InterfaceMemberDeclarations:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+InterfaceMemberDeclarations InterfaceMemberDeclaration
+{
+ jpElementStart(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+InterfaceMemberDeclaration:
+ConstantDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+AbstractMethodDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ClassDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ClassDeclaration jp_SEMICOL
+{
+ jpElementStart(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+InterfaceDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+InterfaceDeclaration jp_SEMICOL
+{
+ jpElementStart(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConstantDeclaration:
+FieldDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+AbstractMethodDeclaration:
+MethodHeader Semicols
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Semicols:
+jp_SEMICOL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Semicols jp_SEMICOL
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ArrayInitializer:
+jp_CURLYSTART VariableInitializersOptional jp_CURLYEND
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+VariableInitializersOptional:
+{
+ jpElementStart(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+VariableInitializers
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+VariableInitializers jp_COMMA
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+VariableInitializers:
+VariableInitializer
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+VariableInitializers jp_COMMA VariableInitializer
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Block:
+jp_CURLYSTART BlockStatementsopt jp_CURLYEND
+{
+ jpElementStart(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+BlockStatementsopt:
+{
+ jpElementStart(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+BlockStatements
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+BlockStatements:
+BlockStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+BlockStatements BlockStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+BlockStatement:
+LocalVariableDeclarationStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Statement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ClassDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+LocalVariableDeclarationStatement:
+LocalVariableDeclaration jp_SEMICOL
+{
+ jpElementStart(1);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+LocalVariableDeclaration:
+Modifiers Type VariableDeclarators
+{
+ jpElementStart(1);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Type VariableDeclarators
+{
+ jpElementStart(1);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Statement:
+StatementWithoutTrailingSubstatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+LabeledStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+IfThenStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+IfThenElseStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+WhileStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ForStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+StatementNoShortIf:
+StatementWithoutTrailingSubstatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+LabeledStatementNoShortIf
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+IfThenElseStatementNoShortIf
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+WhileStatementNoShortIf
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ForStatementNoShortIf
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+StatementWithoutTrailingSubstatement:
+Block
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+EmptyStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ExpressionStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+SwitchStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+DoStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+BreakStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ContinueStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ReturnStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+SynchronizedStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ThrowStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+TryStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+AssertStatement
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+EmptyStatement:
+jp_SEMICOL
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+LabeledStatement:
+Identifier jp_COLON Statement
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+LabeledStatementNoShortIf:
+Identifier jp_COLON StatementNoShortIf
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ExpressionStatement:
+StatementExpression jp_SEMICOL
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+StatementExpression:
+Assignment
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PreIncrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PreDecrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PostIncrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PostDecrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+MethodInvocation
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ClassInstanceCreationExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+IfThenStatement:
+jp_IF jp_PARESTART Expression jp_PAREEND Statement
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+IfThenElseStatement:
+jp_IF jp_PARESTART Expression jp_PAREEND StatementNoShortIf jp_ELSE Statement
+{
+ jpElementStart(7);
+ jpCheckEmpty(7);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+IfThenElseStatementNoShortIf:
+jp_IF jp_PARESTART Expression jp_PAREEND StatementNoShortIf jp_ELSE StatementNoShortIf
+{
+ jpElementStart(7);
+ jpCheckEmpty(7);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+SwitchStatement:
+jp_SWITCH jp_PARESTART Expression jp_PAREEND SwitchBlock
+{
+ jpElementStart(5);
+
+}
+
+SwitchBlock:
+jp_CURLYSTART SwitchBlockStatementGroups SwitchLabelsopt jp_CURLYEND
+{
+ jpElementStart(4);
+
+}
+
+SwitchLabelsopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+SwitchLabels
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+SwitchBlockStatementGroups:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+SwitchBlockStatementGroups SwitchBlockStatementGroup
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+SwitchBlockStatementGroup:
+SwitchLabels BlockStatements
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+SwitchLabels:
+SwitchLabel
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+SwitchLabels SwitchLabel
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+SwitchLabel:
+jp_CASE ConstantExpression jp_COLON
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_DEFAULT jp_COLON
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+WhileStatement:
+jp_WHILE jp_PARESTART Expression jp_PAREEND Statement
+{
+ jpElementStart(5);
+
+}
+
+WhileStatementNoShortIf:
+jp_WHILE jp_PARESTART Expression jp_PAREEND StatementNoShortIf
+{
+ jpElementStart(5);
+
+}
+
+DoStatement:
+jp_DO Statement jp_WHILE jp_PARESTART Expression jp_PAREEND jp_SEMICOL
+{
+ jpElementStart(7);
+
+}
+
+ForStatement:
+jp_FOR jp_PARESTART ForInitopt jp_SEMICOL Expressionopt jp_SEMICOL ForUpdateopt jp_PAREEND
+Statement
+{
+ jpElementStart(9);
+
+}
+
+ForUpdateopt:
+{
+ jpElementStart(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ForUpdate
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ForInitopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ForInit
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ForStatementNoShortIf:
+jp_FOR jp_PARESTART ForInitopt jp_SEMICOL Expressionopt jp_SEMICOL ForUpdateopt jp_PAREEND
+StatementNoShortIf
+{
+ jpElementStart(9);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Expressionopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Expression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ForInit:
+StatementExpressionList
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+LocalVariableDeclaration
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ForUpdate:
+StatementExpressionList
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+StatementExpressionList:
+StatementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+StatementExpressionList jp_COMMA StatementExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+AssertStatement:
+jp_ASSERT Expression jp_SEMICOL
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_ASSERT Expression jp_COLON Expression jp_SEMICOL
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+BreakStatement:
+jp_BREAK Identifieropt jp_SEMICOL
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>2));
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Identifieropt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Identifier
+{
+ jpElementStart(1);
+
+}
+
+ContinueStatement:
+jp_CONTINUE Identifieropt jp_SEMICOL
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>2));
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ReturnStatement:
+jp_RETURN Expressionopt jp_SEMICOL
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ThrowStatement:
+jp_THROW Expression jp_SEMICOL
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+SynchronizedStatement:
+jp_SYNCHRONIZED jp_PARESTART Expression jp_PAREEND Block
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+TryStatement:
+jp_TRY Block Catches
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_TRY Block Catchesopt Finally
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Catchesopt:
+{
+ jpElementStart(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Catches
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Catches:
+CatchClause
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Catches CatchClause
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+CatchClause:
+jp_CATCH jp_PARESTART FormalParameter jp_PAREEND Block
+{
+ jpElementStart(5);
+
+}
+
+Finally:
+jp_FINALLY Block
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Primary:
+PrimaryNoNewArray
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ArrayCreationExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+PrimaryNoNewArray:
+Literal
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_THIS
+{
+ jpElementStart(1);
+
+}
+|
+jp_PARESTART Expression jp_PAREEND
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ClassInstanceCreationExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+FieldAccess
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+MethodInvocation
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ArrayAccess
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ClassInstanceCreationExpression:
+New ClassType jp_PARESTART ArgumentListopt jp_PAREEND ClassBodyOpt
+{
+ jpElementStart(6);
+ jpCheckEmpty(6);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ClassBodyOpt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ClassBody
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ArgumentListopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ArgumentList
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ArgumentList:
+Expression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ArgumentList jp_COMMA Expression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ArrayCreationExpression:
+New PrimitiveType DimExprs Dimsopt
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+New ClassOrInterfaceType DimExprs Dimsopt
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+New PrimitiveType Dims ArrayInitializer
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+New ClassOrInterfaceType Dims ArrayInitializer
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Dimsopt:
+{
+ jpElementStart(0);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Dims
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+DimExprs:
+DimExpr
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+DimExprs DimExpr
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+DimExpr:
+jp_BRACKETSTART Expression jp_BRACKETEND
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Dims:
+jp_BRACKETSTART jp_BRACKETEND
+{
+ jpElementStart(2);
+
+}
+|
+Dims jp_BRACKETSTART jp_BRACKETEND
+{
+ jpElementStart(3);
+
+}
+
+FieldAccess:
+Primary jp_DOT Identifier
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_SUPER jp_DOT Identifier
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_THIS jp_DOT Identifier
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Primary jp_DOT jp_THIS
+{
+ jpElementStart(3);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+MethodInvocation:
+Name jp_PARESTART ArgumentListopt jp_PAREEND
+{
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Primary jp_DOT Identifier jp_PARESTART ArgumentListopt jp_PAREEND
+{
+ jpElementStart(6);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(6);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_SUPER jp_DOT Identifier jp_PARESTART ArgumentListopt jp_PAREEND
+{
+ jpElementStart(6);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(6);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_THIS jp_DOT Identifier jp_PARESTART ArgumentListopt jp_PAREEND
+{
+ jpElementStart(6);
+ yyGetParser->DeallocateParserType(&($<str>3));
+ jpCheckEmpty(6);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ArrayAccess:
+Name jp_BRACKETSTART Expression jp_BRACKETEND
+{
+ jpElementStart(4);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PrimaryNoNewArray jp_BRACKETSTART Expression jp_BRACKETEND
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+PostfixExpression:
+Primary
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Name
+{
+ jpElementStart(1);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ArrayType jp_DOT jp_CLASS
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PostIncrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PostDecrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+PostIncrementExpression:
+PostfixExpression jp_PLUSPLUS
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+PostDecrementExpression:
+PostfixExpression jp_MINUSMINUS
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+UnaryExpression:
+PreIncrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+PreDecrementExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_PLUS UnaryExpression
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_MINUS UnaryExpression
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+UnaryExpressionNotPlusMinus
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+PreIncrementExpression:
+jp_PLUSPLUS UnaryExpression
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+PreDecrementExpression:
+jp_MINUSMINUS UnaryExpression
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+UnaryExpressionNotPlusMinus:
+PostfixExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_TILDE UnaryExpression
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_EXCLAMATION UnaryExpression
+{
+ jpElementStart(2);
+ jpCheckEmpty(2);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+CastExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+CastExpression:
+jp_PARESTART PrimitiveType Dimsopt jp_PAREEND UnaryExpression
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_PARESTART Expression jp_PAREEND UnaryExpressionNotPlusMinus
+{
+ jpElementStart(4);
+ jpCheckEmpty(4);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_PARESTART Name Dims jp_PAREEND UnaryExpressionNotPlusMinus
+{
+ jpElementStart(5);
+
+}
+
+MultiplicativeExpression:
+UnaryExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+MultiplicativeExpression jp_TIMES UnaryExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+MultiplicativeExpression jp_DIVIDE UnaryExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+MultiplicativeExpression jp_PERCENT UnaryExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+AdditiveExpression:
+MultiplicativeExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+AdditiveExpression jp_PLUS MultiplicativeExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+AdditiveExpression jp_MINUS MultiplicativeExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ShiftExpression:
+AdditiveExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ShiftExpression jp_LTLT AdditiveExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ShiftExpression jp_GTGT AdditiveExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ShiftExpression jp_GTGTGT AdditiveExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+RelationalExpression:
+ShiftExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+RelationalExpression jp_LESSTHAN ShiftExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+RelationalExpression jp_GREATER ShiftExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+RelationalExpression jp_LTEQUALS ShiftExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+RelationalExpression jp_GTEQUALS ShiftExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+RelationalExpression jp_INSTANCEOF ReferenceType
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+EqualityExpression:
+RelationalExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+EqualityExpression jp_EQUALSEQUALS RelationalExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+EqualityExpression jp_EXCLAMATIONEQUALS RelationalExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+AndExpression:
+EqualityExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+AndExpression jp_AND EqualityExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ExclusiveOrExpression:
+AndExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ExclusiveOrExpression jp_CARROT AndExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+InclusiveOrExpression:
+ExclusiveOrExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+InclusiveOrExpression jp_PIPE ExclusiveOrExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConditionalAndExpression:
+InclusiveOrExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ConditionalAndExpression jp_ANDAND InclusiveOrExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConditionalOrExpression:
+ConditionalAndExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ConditionalOrExpression jp_PIPEPIPE ConditionalAndExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConditionalExpression:
+ConditionalOrExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ConditionalOrExpression jp_QUESTION Expression jp_COLON ConditionalExpression
+{
+ jpElementStart(5);
+ jpCheckEmpty(5);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+AssignmentExpression:
+ConditionalExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Assignment
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Assignment:
+LeftHandSide AssignmentOperator AssignmentExpression
+{
+ jpElementStart(3);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+LeftHandSide:
+Name
+{
+ jpElementStart(1);
+ yyGetParser->DeallocateParserType(&($<str>1));
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+FieldAccess
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+ArrayAccess
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+AssignmentOperator:
+jp_EQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_TIMESEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_DIVIDEEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_PERCENTEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_PLUSEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_MINUSEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_LESLESEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_GTGTEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_GTGTGTEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_ANDEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_CARROTEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+jp_PIPEEQUALS
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+Expression:
+AssignmentExpression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+ConstantExpression:
+Expression
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+New:
+jp_NEW
+{
+ jpElementStart(1);
+ jpCheckEmpty(1);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+|
+Name jp_DOT jp_NEW
+{
+ jpElementStart(3);
+ jpStoreClass($<str>1);
+ jpCheckEmpty(3);
+ $<str>$ = 0;
+ yyGetParser->SetCurrentCombine("");
+
+}
+
+%%
+/* End of grammar */
+
+/*--------------------------------------------------------------------------*/
+void cmDependsJava_yyerror(yyscan_t yyscanner, const char* message)
+{
+ yyGetParser->Error(message);
+}
diff --git a/Source/LexerParser/cmDependsJavaParserTokens.h b/Source/LexerParser/cmDependsJavaParserTokens.h
new file mode 100644
index 0000000..4ae55fa
--- /dev/null
+++ b/Source/LexerParser/cmDependsJavaParserTokens.h
@@ -0,0 +1,170 @@
+/* A Bison parser, made by GNU Bison 3.7.4. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
+ Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+ especially those whose name start with YY_ or yy_. They are
+ private implementation details that can be changed or removed. */
+
+#ifndef YY_CMDEPENDSJAVA_YY_CMDEPENDSJAVAPARSERTOKENS_H_INCLUDED
+# define YY_CMDEPENDSJAVA_YY_CMDEPENDSJAVAPARSERTOKENS_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int cmDependsJava_yydebug;
+#endif
+
+/* Token kinds. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ YYEMPTY = -2,
+ YYEOF = 0, /* "end of file" */
+ YYerror = 256, /* error */
+ YYUNDEF = 257, /* "invalid token" */
+ jp_ABSTRACT = 258, /* jp_ABSTRACT */
+ jp_ASSERT = 259, /* jp_ASSERT */
+ jp_BOOLEAN_TYPE = 260, /* jp_BOOLEAN_TYPE */
+ jp_BREAK = 261, /* jp_BREAK */
+ jp_BYTE_TYPE = 262, /* jp_BYTE_TYPE */
+ jp_CASE = 263, /* jp_CASE */
+ jp_CATCH = 264, /* jp_CATCH */
+ jp_CHAR_TYPE = 265, /* jp_CHAR_TYPE */
+ jp_CLASS = 266, /* jp_CLASS */
+ jp_CONTINUE = 267, /* jp_CONTINUE */
+ jp_DEFAULT = 268, /* jp_DEFAULT */
+ jp_DO = 269, /* jp_DO */
+ jp_DOUBLE_TYPE = 270, /* jp_DOUBLE_TYPE */
+ jp_ELSE = 271, /* jp_ELSE */
+ jp_EXTENDS = 272, /* jp_EXTENDS */
+ jp_FINAL = 273, /* jp_FINAL */
+ jp_FINALLY = 274, /* jp_FINALLY */
+ jp_FLOAT_TYPE = 275, /* jp_FLOAT_TYPE */
+ jp_FOR = 276, /* jp_FOR */
+ jp_IF = 277, /* jp_IF */
+ jp_IMPLEMENTS = 278, /* jp_IMPLEMENTS */
+ jp_IMPORT = 279, /* jp_IMPORT */
+ jp_INSTANCEOF = 280, /* jp_INSTANCEOF */
+ jp_INT_TYPE = 281, /* jp_INT_TYPE */
+ jp_INTERFACE = 282, /* jp_INTERFACE */
+ jp_LONG_TYPE = 283, /* jp_LONG_TYPE */
+ jp_NATIVE = 284, /* jp_NATIVE */
+ jp_NEW = 285, /* jp_NEW */
+ jp_PACKAGE = 286, /* jp_PACKAGE */
+ jp_PRIVATE = 287, /* jp_PRIVATE */
+ jp_PROTECTED = 288, /* jp_PROTECTED */
+ jp_PUBLIC = 289, /* jp_PUBLIC */
+ jp_RETURN = 290, /* jp_RETURN */
+ jp_SHORT_TYPE = 291, /* jp_SHORT_TYPE */
+ jp_STATIC = 292, /* jp_STATIC */
+ jp_STRICTFP = 293, /* jp_STRICTFP */
+ jp_SUPER = 294, /* jp_SUPER */
+ jp_SWITCH = 295, /* jp_SWITCH */
+ jp_SYNCHRONIZED = 296, /* jp_SYNCHRONIZED */
+ jp_THIS = 297, /* jp_THIS */
+ jp_THROW = 298, /* jp_THROW */
+ jp_THROWS = 299, /* jp_THROWS */
+ jp_TRANSIENT = 300, /* jp_TRANSIENT */
+ jp_TRY = 301, /* jp_TRY */
+ jp_VOID = 302, /* jp_VOID */
+ jp_VOLATILE = 303, /* jp_VOLATILE */
+ jp_WHILE = 304, /* jp_WHILE */
+ jp_BOOLEANLITERAL = 305, /* jp_BOOLEANLITERAL */
+ jp_CHARACTERLITERAL = 306, /* jp_CHARACTERLITERAL */
+ jp_DECIMALINTEGERLITERAL = 307, /* jp_DECIMALINTEGERLITERAL */
+ jp_FLOATINGPOINTLITERAL = 308, /* jp_FLOATINGPOINTLITERAL */
+ jp_HEXINTEGERLITERAL = 309, /* jp_HEXINTEGERLITERAL */
+ jp_NULLLITERAL = 310, /* jp_NULLLITERAL */
+ jp_STRINGLITERAL = 311, /* jp_STRINGLITERAL */
+ jp_NAME = 312, /* jp_NAME */
+ jp_AND = 313, /* jp_AND */
+ jp_ANDAND = 314, /* jp_ANDAND */
+ jp_ANDEQUALS = 315, /* jp_ANDEQUALS */
+ jp_BRACKETEND = 316, /* jp_BRACKETEND */
+ jp_BRACKETSTART = 317, /* jp_BRACKETSTART */
+ jp_CARROT = 318, /* jp_CARROT */
+ jp_CARROTEQUALS = 319, /* jp_CARROTEQUALS */
+ jp_COLON = 320, /* jp_COLON */
+ jp_COMMA = 321, /* jp_COMMA */
+ jp_CURLYEND = 322, /* jp_CURLYEND */
+ jp_CURLYSTART = 323, /* jp_CURLYSTART */
+ jp_DIVIDE = 324, /* jp_DIVIDE */
+ jp_DIVIDEEQUALS = 325, /* jp_DIVIDEEQUALS */
+ jp_DOLLAR = 326, /* jp_DOLLAR */
+ jp_DOT = 327, /* jp_DOT */
+ jp_EQUALS = 328, /* jp_EQUALS */
+ jp_EQUALSEQUALS = 329, /* jp_EQUALSEQUALS */
+ jp_EXCLAMATION = 330, /* jp_EXCLAMATION */
+ jp_EXCLAMATIONEQUALS = 331, /* jp_EXCLAMATIONEQUALS */
+ jp_GREATER = 332, /* jp_GREATER */
+ jp_GTEQUALS = 333, /* jp_GTEQUALS */
+ jp_GTGT = 334, /* jp_GTGT */
+ jp_GTGTEQUALS = 335, /* jp_GTGTEQUALS */
+ jp_GTGTGT = 336, /* jp_GTGTGT */
+ jp_GTGTGTEQUALS = 337, /* jp_GTGTGTEQUALS */
+ jp_LESLESEQUALS = 338, /* jp_LESLESEQUALS */
+ jp_LESSTHAN = 339, /* jp_LESSTHAN */
+ jp_LTEQUALS = 340, /* jp_LTEQUALS */
+ jp_LTLT = 341, /* jp_LTLT */
+ jp_MINUS = 342, /* jp_MINUS */
+ jp_MINUSEQUALS = 343, /* jp_MINUSEQUALS */
+ jp_MINUSMINUS = 344, /* jp_MINUSMINUS */
+ jp_PAREEND = 345, /* jp_PAREEND */
+ jp_PARESTART = 346, /* jp_PARESTART */
+ jp_PERCENT = 347, /* jp_PERCENT */
+ jp_PERCENTEQUALS = 348, /* jp_PERCENTEQUALS */
+ jp_PIPE = 349, /* jp_PIPE */
+ jp_PIPEEQUALS = 350, /* jp_PIPEEQUALS */
+ jp_PIPEPIPE = 351, /* jp_PIPEPIPE */
+ jp_PLUS = 352, /* jp_PLUS */
+ jp_PLUSEQUALS = 353, /* jp_PLUSEQUALS */
+ jp_PLUSPLUS = 354, /* jp_PLUSPLUS */
+ jp_QUESTION = 355, /* jp_QUESTION */
+ jp_SEMICOL = 356, /* jp_SEMICOL */
+ jp_TILDE = 357, /* jp_TILDE */
+ jp_TIMES = 358, /* jp_TIMES */
+ jp_TIMESEQUALS = 359, /* jp_TIMESEQUALS */
+ jp_ERROR = 360 /* jp_ERROR */
+ };
+ typedef enum yytokentype yytoken_kind_t;
+#endif
+
+/* Value type. */
+
+
+
+int cmDependsJava_yyparse (yyscan_t yyscanner);
+
+#endif /* !YY_CMDEPENDSJAVA_YY_CMDEPENDSJAVAPARSERTOKENS_H_INCLUDED */
diff --git a/Source/LexerParser/cmExprLexer.cxx b/Source/LexerParser/cmExprLexer.cxx
new file mode 100644
index 0000000..72e59b6
--- /dev/null
+++ b/Source/LexerParser/cmExprLexer.cxx
@@ -0,0 +1,2231 @@
+#include "cmStandardLexer.h"
+
+#define FLEXINT_H 1
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmExpr_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmExpr_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmExpr_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmExpr_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmExpr_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmExpr_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmExpr_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmExpr_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmExpr_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmExpr_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmExpr_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmExpr_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmExpr_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmExpr_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmExpr_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmExpr_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmExpr_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmExpr_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmExpr_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmExpr_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmExpr_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmExpr_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmExpr_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmExpr_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmExpr_yylex_ALREADY_DEFINED
+#else
+#define yylex cmExpr_yylex
+#endif
+
+#ifdef yyrestart
+#define cmExpr_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmExpr_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmExpr_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmExpr_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmExpr_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmExpr_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmExpr_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmExpr_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmExpr_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmExpr_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmExpr_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmExpr_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmExpr_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmExpr_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmExpr_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmExpr_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmExpr_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmExpr_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmExpr_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmExpr_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmExpr_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmExpr_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmExpr_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmExpr_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmExpr_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmExpr_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmExpr_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmExpr_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmExpr_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmExpr_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmExpr_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmExpr_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmExpr_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmExpr_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmExpr_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmExpr_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmExpr_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmExpr_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmExpr_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmExpr_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmExpr_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmExpr_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmExpr_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmExpr_yyfree
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an
+ * integer in range [0..255] for use as an array index.
+ */
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin , yyscanner )
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+ #define YY_LINENO_REWIND_TO(ptr)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+static void yyensure_buffer_stack ( yyscan_t yyscanner );
+static void yy_load_buffer_state ( yyscan_t yyscanner );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner)
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+#define yy_new_buffer yy_create_buffer
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define cmExpr_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+typedef flex_uint8_t YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner);
+static int yy_get_next_buffer ( yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+#define YY_NUM_RULES 18
+#define YY_END_OF_BUFFER 19
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static const flex_int16_t yy_accept[29] =
+ { 0,
+ 0, 0, 19, 17, 1, 18, 8, 10, 15, 16,
+ 6, 4, 5, 7, 2, 2, 17, 17, 11, 9,
+ 12, 2, 0, 13, 14, 3, 3, 0
+ } ;
+
+static const YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 1, 1, 1, 4, 5, 1, 6,
+ 7, 8, 9, 1, 10, 1, 11, 12, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 1, 1, 14,
+ 1, 15, 1, 1, 16, 16, 16, 16, 16, 16,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 17, 1, 1,
+ 1, 1, 1, 18, 1, 1, 16, 16, 16, 16,
+
+ 16, 16, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 17,
+ 1, 1, 1, 19, 1, 20, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static const YY_CHAR yy_meta[21] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 1, 1, 3, 4, 1, 1, 1
+ } ;
+
+static const flex_int16_t yy_base[32] =
+ { 0,
+ 0, 0, 34, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 16, 9, 18, 11, 35, 35,
+ 35, 11, 0, 35, 35, 0, 0, 35, 23, 26,
+ 28
+ } ;
+
+static const flex_int16_t yy_def[32] =
+ { 0,
+ 28, 1, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 29, 28, 28, 28, 28, 28,
+ 28, 28, 30, 28, 28, 31, 31, 0, 28, 28,
+ 28
+ } ;
+
+static const flex_int16_t yy_nxt[56] =
+ { 0,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 4, 4, 19, 20, 21,
+ 22, 22, 22, 22, 22, 25, 22, 26, 26, 27,
+ 27, 24, 23, 28, 3, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28
+ } ;
+
+static const flex_int16_t yy_chk[56] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 16, 16, 22, 22, 29, 18, 29, 30, 30, 31,
+ 31, 17, 15, 3, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28
+ } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C++ and modified to build everywhere.
+
+Run flex >= 2.6 like this:
+
+ flex --nounistd -DFLEXINT_H --noline --header-file=cmExprLexer.h -ocmExprLexer.cxx cmExprLexer.in.l
+
+Modify cmExprLexer.cxx:
+ - remove trailing whitespace: sed -i 's/\s*$//' cmExprLexer.h cmExprLexer.cxx
+ - remove blank lines at end of file: sed -i '${/^$/d;}' cmExprLexer.h cmExprLexer.cxx
+ - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmExprLexer.cxx
+
+*/
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
+
+#include "cmExprParserHelper.h"
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ do { result = yyextra->LexInput(buf, max_size); } while (0)
+
+/* Include the set of tokens from the parser. */
+#include "cmExprParserTokens.h"
+
+#include <string>
+
+/*--------------------------------------------------------------------------*/
+
+#define INITIAL 0
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals ( yyscan_t yyscanner );
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput ( int c, char *buf_ptr , yyscan_t yyscanner);
+
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput ( yyscan_t yyscanner );
+#else
+static int input ( yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ int n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK /*LINTED*/break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_load_buffer_state( yyscanner );
+ }
+
+ {
+
+ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 29 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 35 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+{}
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+{ yylvalp->Number = std::stoll(yytext, nullptr, 10); return exp_NUMBER; }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+{ yylvalp->Number = std::stoll(yytext, nullptr, 16); return exp_NUMBER; }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+{ return exp_PLUS; }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+{ return exp_MINUS; }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+{ return exp_TIMES; }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+{ return exp_DIVIDE; }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+{ return exp_MOD; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+{ return exp_OR; }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+{ return exp_AND; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+{ return exp_XOR; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+{ return exp_NOT; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+{ return exp_SHIFTLEFT; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+{ return exp_SHIFTRIGHT; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+{ return exp_OPENPARENT; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+{ return exp_CLOSEPARENT; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+{ yyextra->UnexpectedChar(yytext[0]); }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+ECHO;
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap( yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of user's declarations */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc( (void *) b->yy_ch_buf,
+ (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = NULL;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin , yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+ (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ /* "- 2" to take care of EOB's */
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 29 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ char *yy_cp = yyg->yy_c_buf_p;
+
+ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 29 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_is_jam = (yy_current_state == 28);
+
+ (void)yyg;
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput (int c, char * yy_bp , yyscan_t yyscanner)
+{
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yyg->yy_hold_char;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ int number_to_move = yyg->yy_n_chars + 2;
+ char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ yyg->yy_n_chars = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ yyg->yytext_ptr = yy_bp;
+ yyg->yy_hold_char = *yy_cp;
+ yyg->yy_c_buf_p = yy_cp;
+}
+
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin , yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( yyscanner ) )
+ return 0;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner);
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file , yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree( (void *) b->yy_ch_buf , yyscanner );
+
+ yyfree( (void *) b , yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_flush_buffer( b , yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return NULL;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = NULL;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b , yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner)
+{
+
+ return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = (yy_size_t) (_yybytes_len + 2);
+ buf = (char *) yyalloc( n , yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n , yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param _line_number line number
+ * @param yyscanner The scanner object.
+ */
+void yyset_lineno (int _line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
+
+ yylineno = _line_number;
+}
+
+/** Set the current column.
+ * @param _column_no column number
+ * @param yyscanner The scanner object.
+ */
+void yyset_column (int _column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_column called with no buffer" );
+
+ yycolumn = _column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param _in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * _in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = _in_str ;
+}
+
+void yyset_out (FILE * _out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = _out_str ;
+}
+
+int yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void yyset_debug (int _bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = _bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+/* User-visible API */
+
+/* yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+int yylex_init(yyscan_t* ptr_yy_globals)
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to yyalloc in
+ * the yyextra field.
+ */
+int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals )
+{
+ struct yyguts_t dummy_yyguts;
+
+ yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = NULL;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = NULL;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = NULL;
+ yyout = NULL;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ yyfree(yyg->yy_buffer_stack , yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ yyfree( yyg->yy_start_stack , yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ yyfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
+{
+ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ return malloc(size);
+}
+
+void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return realloc(ptr, size);
+}
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+/*--------------------------------------------------------------------------*/
+
+#endif /* __clang_analyzer__ */
diff --git a/Source/LexerParser/cmExprLexer.h b/Source/LexerParser/cmExprLexer.h
new file mode 100644
index 0000000..b55ee92
--- /dev/null
+++ b/Source/LexerParser/cmExprLexer.h
@@ -0,0 +1,687 @@
+#ifndef cmExpr_yyHEADER_H
+#define cmExpr_yyHEADER_H 1
+#define cmExpr_yyIN_HEADER 1
+
+#define FLEXINT_H 1
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmExpr_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmExpr_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmExpr_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmExpr_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmExpr_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmExpr_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmExpr_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmExpr_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmExpr_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmExpr_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmExpr_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmExpr_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmExpr_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmExpr_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmExpr_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmExpr_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmExpr_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmExpr_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmExpr_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmExpr_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmExpr_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmExpr_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmExpr_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmExpr_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmExpr_yylex_ALREADY_DEFINED
+#else
+#define yylex cmExpr_yylex
+#endif
+
+#ifdef yyrestart
+#define cmExpr_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmExpr_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmExpr_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmExpr_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmExpr_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmExpr_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmExpr_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmExpr_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmExpr_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmExpr_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmExpr_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmExpr_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmExpr_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmExpr_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmExpr_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmExpr_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmExpr_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmExpr_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmExpr_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmExpr_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmExpr_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmExpr_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmExpr_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmExpr_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmExpr_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmExpr_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmExpr_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmExpr_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmExpr_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmExpr_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmExpr_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmExpr_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmExpr_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmExpr_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmExpr_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmExpr_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmExpr_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmExpr_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmExpr_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmExpr_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmExpr_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmExpr_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmExpr_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmExpr_yyfree
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+/* Begin user sect3 */
+
+#define cmExpr_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#ifndef cmExpr_yy_create_buffer_ALREADY_DEFINED
+#undef yy_create_buffer
+#endif
+#ifndef cmExpr_yy_delete_buffer_ALREADY_DEFINED
+#undef yy_delete_buffer
+#endif
+#ifndef cmExpr_yy_scan_buffer_ALREADY_DEFINED
+#undef yy_scan_buffer
+#endif
+#ifndef cmExpr_yy_scan_string_ALREADY_DEFINED
+#undef yy_scan_string
+#endif
+#ifndef cmExpr_yy_scan_bytes_ALREADY_DEFINED
+#undef yy_scan_bytes
+#endif
+#ifndef cmExpr_yy_init_buffer_ALREADY_DEFINED
+#undef yy_init_buffer
+#endif
+#ifndef cmExpr_yy_flush_buffer_ALREADY_DEFINED
+#undef yy_flush_buffer
+#endif
+#ifndef cmExpr_yy_load_buffer_state_ALREADY_DEFINED
+#undef yy_load_buffer_state
+#endif
+#ifndef cmExpr_yy_switch_to_buffer_ALREADY_DEFINED
+#undef yy_switch_to_buffer
+#endif
+#ifndef cmExpr_yypush_buffer_state_ALREADY_DEFINED
+#undef yypush_buffer_state
+#endif
+#ifndef cmExpr_yypop_buffer_state_ALREADY_DEFINED
+#undef yypop_buffer_state
+#endif
+#ifndef cmExpr_yyensure_buffer_stack_ALREADY_DEFINED
+#undef yyensure_buffer_stack
+#endif
+#ifndef cmExpr_yylex_ALREADY_DEFINED
+#undef yylex
+#endif
+#ifndef cmExpr_yyrestart_ALREADY_DEFINED
+#undef yyrestart
+#endif
+#ifndef cmExpr_yylex_init_ALREADY_DEFINED
+#undef yylex_init
+#endif
+#ifndef cmExpr_yylex_init_extra_ALREADY_DEFINED
+#undef yylex_init_extra
+#endif
+#ifndef cmExpr_yylex_destroy_ALREADY_DEFINED
+#undef yylex_destroy
+#endif
+#ifndef cmExpr_yyget_debug_ALREADY_DEFINED
+#undef yyget_debug
+#endif
+#ifndef cmExpr_yyset_debug_ALREADY_DEFINED
+#undef yyset_debug
+#endif
+#ifndef cmExpr_yyget_extra_ALREADY_DEFINED
+#undef yyget_extra
+#endif
+#ifndef cmExpr_yyset_extra_ALREADY_DEFINED
+#undef yyset_extra
+#endif
+#ifndef cmExpr_yyget_in_ALREADY_DEFINED
+#undef yyget_in
+#endif
+#ifndef cmExpr_yyset_in_ALREADY_DEFINED
+#undef yyset_in
+#endif
+#ifndef cmExpr_yyget_out_ALREADY_DEFINED
+#undef yyget_out
+#endif
+#ifndef cmExpr_yyset_out_ALREADY_DEFINED
+#undef yyset_out
+#endif
+#ifndef cmExpr_yyget_leng_ALREADY_DEFINED
+#undef yyget_leng
+#endif
+#ifndef cmExpr_yyget_text_ALREADY_DEFINED
+#undef yyget_text
+#endif
+#ifndef cmExpr_yyget_lineno_ALREADY_DEFINED
+#undef yyget_lineno
+#endif
+#ifndef cmExpr_yyset_lineno_ALREADY_DEFINED
+#undef yyset_lineno
+#endif
+#ifndef cmExpr_yyget_column_ALREADY_DEFINED
+#undef yyget_column
+#endif
+#ifndef cmExpr_yyset_column_ALREADY_DEFINED
+#undef yyset_column
+#endif
+#ifndef cmExpr_yywrap_ALREADY_DEFINED
+#undef yywrap
+#endif
+#ifndef cmExpr_yyget_lval_ALREADY_DEFINED
+#undef yyget_lval
+#endif
+#ifndef cmExpr_yyset_lval_ALREADY_DEFINED
+#undef yyset_lval
+#endif
+#ifndef cmExpr_yyget_lloc_ALREADY_DEFINED
+#undef yyget_lloc
+#endif
+#ifndef cmExpr_yyset_lloc_ALREADY_DEFINED
+#undef yyset_lloc
+#endif
+#ifndef cmExpr_yyalloc_ALREADY_DEFINED
+#undef yyalloc
+#endif
+#ifndef cmExpr_yyrealloc_ALREADY_DEFINED
+#undef yyrealloc
+#endif
+#ifndef cmExpr_yyfree_ALREADY_DEFINED
+#undef yyfree
+#endif
+#ifndef cmExpr_yytext_ALREADY_DEFINED
+#undef yytext
+#endif
+#ifndef cmExpr_yyleng_ALREADY_DEFINED
+#undef yyleng
+#endif
+#ifndef cmExpr_yyin_ALREADY_DEFINED
+#undef yyin
+#endif
+#ifndef cmExpr_yyout_ALREADY_DEFINED
+#undef yyout
+#endif
+#ifndef cmExpr_yy_flex_debug_ALREADY_DEFINED
+#undef yy_flex_debug
+#endif
+#ifndef cmExpr_yylineno_ALREADY_DEFINED
+#undef yylineno
+#endif
+#ifndef cmExpr_yytables_fload_ALREADY_DEFINED
+#undef yytables_fload
+#endif
+#ifndef cmExpr_yytables_destroy_ALREADY_DEFINED
+#undef yytables_destroy
+#endif
+#ifndef cmExpr_yyTABLES_NAME_ALREADY_DEFINED
+#undef yyTABLES_NAME
+#endif
+
+#undef cmExpr_yyIN_HEADER
+#endif /* cmExpr_yyHEADER_H */
diff --git a/Source/LexerParser/cmExprLexer.in.l b/Source/LexerParser/cmExprLexer.in.l
new file mode 100644
index 0000000..f8a4224
--- /dev/null
+++ b/Source/LexerParser/cmExprLexer.in.l
@@ -0,0 +1,69 @@
+%{
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C++ and modified to build everywhere.
+
+Run flex >= 2.6 like this:
+
+ flex --nounistd -DFLEXINT_H --noline --header-file=cmExprLexer.h -ocmExprLexer.cxx cmExprLexer.in.l
+
+Modify cmExprLexer.cxx:
+ - remove trailing whitespace: sed -i 's/\s*$//' cmExprLexer.h cmExprLexer.cxx
+ - remove blank lines at end of file: sed -i '${/^$/d;}' cmExprLexer.h cmExprLexer.cxx
+ - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmExprLexer.cxx
+
+*/
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
+
+#include "cmExprParserHelper.h"
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ do { result = yyextra->LexInput(buf, max_size); } while (0)
+
+/* Include the set of tokens from the parser. */
+#include "cmExprParserTokens.h"
+
+#include <string>
+
+/*--------------------------------------------------------------------------*/
+%}
+
+%option prefix="cmExpr_yy"
+
+%option reentrant
+%option noyywrap
+%pointer
+
+%%
+[ \t] {}
+
+[0-9][0-9]* { yylvalp->Number = std::stoll(yytext, nullptr, 10); return exp_NUMBER; }
+0[xX][0-9a-fA-F][0-9a-fA-F]* { yylvalp->Number = std::stoll(yytext, nullptr, 16); return exp_NUMBER; }
+
+"+" { return exp_PLUS; }
+"-" { return exp_MINUS; }
+"*" { return exp_TIMES; }
+"/" { return exp_DIVIDE; }
+"%" { return exp_MOD; }
+"\|" { return exp_OR; }
+"&" { return exp_AND; }
+"^" { return exp_XOR; }
+"~" { return exp_NOT; }
+"<<" { return exp_SHIFTLEFT; }
+">>" { return exp_SHIFTRIGHT; }
+"(" { return exp_OPENPARENT; }
+")" { return exp_CLOSEPARENT; }
+. { yyextra->UnexpectedChar(yytext[0]); }
+
+%%
+
+/*--------------------------------------------------------------------------*/
+
+#endif /* __clang_analyzer__ */
diff --git a/Source/LexerParser/cmExprParser.cxx b/Source/LexerParser/cmExprParser.cxx
new file mode 100644
index 0000000..b747d8b
--- /dev/null
+++ b/Source/LexerParser/cmExprParser.cxx
@@ -0,0 +1,1844 @@
+/* A Bison parser, made by GNU Bison 3.7.4. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
+ Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+ especially those whose name start with YY_ or yy_. They are
+ private implementation details that can be changed or removed. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output, and Bison version. */
+#define YYBISON 30704
+
+/* Bison version string. */
+#define YYBISON_VERSION "3.7.4"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+/* Substitute the variable and function names. */
+#define yyparse cmExpr_yyparse
+#define yylex cmExpr_yylex
+#define yyerror cmExpr_yyerror
+#define yydebug cmExpr_yydebug
+#define yynerrs cmExpr_yynerrs
+
+/* First part of user prologue. */
+#line 1 "cmExprParser.y"
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --name-prefix=cmExpr_yy --defines=cmExprParserTokens.h -ocmExprParser.cxx cmExprParser.y
+
+*/
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdexcept>
+
+/*-------------------------------------------------------------------------*/
+#define YYDEBUG 1
+#include "cmExprParserHelper.h" /* Interface to parser object. */
+#include "cmExprLexer.h" /* Interface to lexer object. */
+#include "cmExprParserTokens.h" /* Need YYSTYPE for YY_DECL. */
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Helper function to forward error callback from parser. */
+static void cmExpr_yyerror(yyscan_t yyscanner, const char* message);
+
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch statement contains default but no case. */
+#endif
+#if defined(__GNUC__) && __GNUC__ >= 8
+# pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+#endif
+#if defined(__clang__) && defined(__has_warning)
+# if __has_warning("-Wused-but-marked-unused")
+# pragma clang diagnostic ignored "-Wused-but-marked-unused"
+# endif
+#endif
+
+#line 124 "cmExprParser.cxx"
+
+# ifndef YY_CAST
+# ifdef __cplusplus
+# define YY_CAST(Type, Val) static_cast<Type> (Val)
+# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+# else
+# define YY_CAST(Type, Val) ((Type) (Val))
+# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+# endif
+# endif
+# ifndef YY_NULLPTR
+# if defined __cplusplus
+# if 201103L <= __cplusplus
+# define YY_NULLPTR nullptr
+# else
+# define YY_NULLPTR 0
+# endif
+# else
+# define YY_NULLPTR ((void*)0)
+# endif
+# endif
+
+#include "cmExprParserTokens.h"
+/* Symbol kind. */
+enum yysymbol_kind_t
+{
+ YYSYMBOL_YYEMPTY = -2,
+ YYSYMBOL_YYEOF = 0, /* "end of file" */
+ YYSYMBOL_YYerror = 1, /* error */
+ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */
+ YYSYMBOL_exp_PLUS = 3, /* exp_PLUS */
+ YYSYMBOL_exp_MINUS = 4, /* exp_MINUS */
+ YYSYMBOL_exp_TIMES = 5, /* exp_TIMES */
+ YYSYMBOL_exp_DIVIDE = 6, /* exp_DIVIDE */
+ YYSYMBOL_exp_MOD = 7, /* exp_MOD */
+ YYSYMBOL_exp_SHIFTLEFT = 8, /* exp_SHIFTLEFT */
+ YYSYMBOL_exp_SHIFTRIGHT = 9, /* exp_SHIFTRIGHT */
+ YYSYMBOL_exp_OPENPARENT = 10, /* exp_OPENPARENT */
+ YYSYMBOL_exp_CLOSEPARENT = 11, /* exp_CLOSEPARENT */
+ YYSYMBOL_exp_OR = 12, /* exp_OR */
+ YYSYMBOL_exp_AND = 13, /* exp_AND */
+ YYSYMBOL_exp_XOR = 14, /* exp_XOR */
+ YYSYMBOL_exp_NOT = 15, /* exp_NOT */
+ YYSYMBOL_exp_NUMBER = 16, /* exp_NUMBER */
+ YYSYMBOL_YYACCEPT = 17, /* $accept */
+ YYSYMBOL_start = 18, /* start */
+ YYSYMBOL_exp = 19, /* exp */
+ YYSYMBOL_bitwiseor = 20, /* bitwiseor */
+ YYSYMBOL_bitwisexor = 21, /* bitwisexor */
+ YYSYMBOL_bitwiseand = 22, /* bitwiseand */
+ YYSYMBOL_shift = 23, /* shift */
+ YYSYMBOL_term = 24, /* term */
+ YYSYMBOL_unary = 25, /* unary */
+ YYSYMBOL_factor = 26 /* factor */
+};
+typedef enum yysymbol_kind_t yysymbol_kind_t;
+
+
+
+
+#ifdef short
+# undef short
+#endif
+
+/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
+ <limits.h> and (if available) <stdint.h> are included
+ so that the code can choose integer types of a good width. */
+
+#ifndef __PTRDIFF_MAX__
+# include <limits.h> /* INFRINGES ON USER NAME SPACE */
+# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+# include <stdint.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_STDINT_H
+# endif
+#endif
+
+/* Narrow types that promote to a signed type and that can represent a
+ signed or unsigned integer of at least N bits. In tables they can
+ save space and decrease cache pressure. Promoting to a signed type
+ helps avoid bugs in integer arithmetic. */
+
+#ifdef __INT_LEAST8_MAX__
+typedef __INT_LEAST8_TYPE__ yytype_int8;
+#elif defined YY_STDINT_H
+typedef int_least8_t yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef __INT_LEAST16_MAX__
+typedef __INT_LEAST16_TYPE__ yytype_int16;
+#elif defined YY_STDINT_H
+typedef int_least16_t yytype_int16;
+#else
+typedef short yytype_int16;
+#endif
+
+#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST8_TYPE__ yytype_uint8;
+#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
+ && UINT_LEAST8_MAX <= INT_MAX)
+typedef uint_least8_t yytype_uint8;
+#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
+typedef unsigned char yytype_uint8;
+#else
+typedef short yytype_uint8;
+#endif
+
+#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST16_TYPE__ yytype_uint16;
+#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
+ && UINT_LEAST16_MAX <= INT_MAX)
+typedef uint_least16_t yytype_uint16;
+#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
+typedef unsigned short yytype_uint16;
+#else
+typedef int yytype_uint16;
+#endif
+
+#ifndef YYPTRDIFF_T
+# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
+# define YYPTRDIFF_T __PTRDIFF_TYPE__
+# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
+# elif defined PTRDIFF_MAX
+# ifndef ptrdiff_t
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# endif
+# define YYPTRDIFF_T ptrdiff_t
+# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
+# else
+# define YYPTRDIFF_T long
+# define YYPTRDIFF_MAXIMUM LONG_MAX
+# endif
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM \
+ YY_CAST (YYPTRDIFF_T, \
+ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \
+ ? YYPTRDIFF_MAXIMUM \
+ : YY_CAST (YYSIZE_T, -1)))
+
+#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
+
+
+/* Stored state numbers (used for stacks). */
+typedef yytype_int8 yy_state_t;
+
+/* State numbers in computations. */
+typedef int yy_state_fast_t;
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+
+#ifndef YY_ATTRIBUTE_PURE
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+# define YY_ATTRIBUTE_PURE
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+# define YY_ATTRIBUTE_UNUSED
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END \
+ _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
+
+#define YY_ASSERT(E) ((void) (0 && (E)))
+
+#if 1
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's 'empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* 1 */
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yy_state_t yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYPTRDIFF_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / YYSIZEOF (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYPTRDIFF_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 19
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 34
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 17
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 10
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 24
+/* YYNSTATES -- Number of states. */
+#define YYNSTATES 41
+
+/* YYMAXUTOK -- Last valid token kind. */
+#define YYMAXUTOK 271
+
+
+/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex, with out-of-bounds checking. */
+#define YYTRANSLATE(YYX) \
+ (0 <= (YYX) && (YYX) <= YYMAXUTOK \
+ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \
+ : YYSYMBOL_YYUNDEF)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex. */
+static const yytype_int8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16
+};
+
+#if YYDEBUG
+ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+static const yytype_uint8 yyrline[] =
+{
+ 0, 81, 81, 86, 89, 94, 97, 102, 105, 110,
+ 113, 116, 121, 124, 127, 132, 135, 138, 144, 149,
+ 152, 155, 158, 163, 166
+};
+#endif
+
+/** Accessing symbol of state STATE. */
+#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
+
+#if 1
+/* The user-facing name of the symbol whose (internal) number is
+ YYSYMBOL. No bounds checking. */
+static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
+
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "\"end of file\"", "error", "\"invalid token\"", "exp_PLUS",
+ "exp_MINUS", "exp_TIMES", "exp_DIVIDE", "exp_MOD", "exp_SHIFTLEFT",
+ "exp_SHIFTRIGHT", "exp_OPENPARENT", "exp_CLOSEPARENT", "exp_OR",
+ "exp_AND", "exp_XOR", "exp_NOT", "exp_NUMBER", "$accept", "start", "exp",
+ "bitwiseor", "bitwisexor", "bitwiseand", "shift", "term", "unary",
+ "factor", YY_NULLPTR
+};
+
+static const char *
+yysymbol_name (yysymbol_kind_t yysymbol)
+{
+ return yytname[yysymbol];
+}
+#endif
+
+#ifdef YYPRINT
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+ (internal) symbol number NUM (which must be that of a token). */
+static const yytype_int16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271
+};
+#endif
+
+#define YYPACT_NINF (-11)
+
+#define yypact_value_is_default(Yyn) \
+ ((Yyn) == YYPACT_NINF)
+
+#define YYTABLE_NINF (-1)
+
+#define yytable_value_is_error(Yyn) \
+ 0
+
+ /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+static const yytype_int8 yypact[] =
+{
+ 1, 1, 1, 1, 1, -11, 6, -10, -4, 9,
+ 4, 11, 2, -11, -11, -11, -11, 7, -11, -11,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ -11, -4, 9, 4, 11, 11, 2, 2, -11, -11,
+ -11
+};
+
+ /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE does not specify something else to do. Zero
+ means the default is an error. */
+static const yytype_int8 yydefact[] =
+{
+ 0, 0, 0, 0, 0, 23, 0, 2, 3, 5,
+ 7, 9, 12, 15, 19, 20, 21, 0, 22, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 24, 4, 6, 8, 10, 11, 13, 14, 16, 17,
+ 18
+};
+
+ /* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -11, -11, 22, 10, 8, 12, -3, -2, -1, -11
+};
+
+ /* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 6, 7, 8, 9, 10, 11, 12, 13, 14
+};
+
+ /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule whose
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+static const yytype_int8 yytable[] =
+{
+ 15, 16, 20, 18, 1, 2, 19, 27, 28, 29,
+ 21, 3, 23, 24, 25, 26, 4, 5, 30, 20,
+ 34, 35, 22, 36, 37, 17, 38, 39, 40, 32,
+ 31, 0, 0, 0, 33
+};
+
+static const yytype_int8 yycheck[] =
+{
+ 1, 2, 12, 4, 3, 4, 0, 5, 6, 7,
+ 14, 10, 8, 9, 3, 4, 15, 16, 11, 12,
+ 23, 24, 13, 25, 26, 3, 27, 28, 29, 21,
+ 20, -1, -1, -1, 22
+};
+
+ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_int8 yystos[] =
+{
+ 0, 3, 4, 10, 15, 16, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 25, 25, 19, 25, 0,
+ 12, 14, 13, 8, 9, 3, 4, 5, 6, 7,
+ 11, 20, 21, 22, 23, 23, 24, 24, 25, 25,
+ 25
+};
+
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_int8 yyr1[] =
+{
+ 0, 17, 18, 19, 19, 20, 20, 21, 21, 22,
+ 22, 22, 23, 23, 23, 24, 24, 24, 24, 25,
+ 25, 25, 25, 26, 26
+};
+
+ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
+static const yytype_int8 yyr2[] =
+{
+ 0, 2, 1, 1, 3, 1, 3, 1, 3, 1,
+ 3, 3, 1, 3, 3, 1, 3, 3, 3, 1,
+ 2, 2, 2, 1, 3
+};
+
+
+enum { YYENOMEM = -2 };
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+ do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (yyscanner, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+ while (0)
+
+/* Backward compatibility with an undocumented macro.
+ Use YYerror or YYUNDEF. */
+#define YYERRCODE YYUNDEF
+
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+/* This macro is provided for backward compatibility. */
+# ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+
+
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Kind, Value, yyscanner); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+
+/*-----------------------------------.
+| Print this symbol's value on YYO. |
+`-----------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyo,
+ yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+{
+ FILE *yyoutput = yyo;
+ YYUSE (yyoutput);
+ YYUSE (yyscanner);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yykind < YYNTOKENS)
+ YYPRINT (yyo, yytoknum[yykind], *yyvaluep);
+# endif
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ YYUSE (yykind);
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+/*---------------------------.
+| Print this symbol on YYO. |
+`---------------------------*/
+
+static void
+yy_symbol_print (FILE *yyo,
+ yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+{
+ YYFPRINTF (yyo, "%s %s (",
+ yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
+
+ yy_symbol_value_print (yyo, yykind, yyvaluep, yyscanner);
+ YYFPRINTF (yyo, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop)
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp,
+ int yyrule, yyscan_t yyscanner)
+{
+ int yylno = yyrline[yyrule];
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr,
+ YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
+ &yyvsp[(yyi + 1) - (yynrhs)], yyscanner);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyssp, yyvsp, Rule, yyscanner); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args) ((void) 0)
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+/* Context of a parse error. */
+typedef struct
+{
+ yy_state_t *yyssp;
+ yysymbol_kind_t yytoken;
+} yypcontext_t;
+
+/* Put in YYARG at most YYARGN of the expected tokens given the
+ current YYCTX, and return the number of tokens stored in YYARG. If
+ YYARG is null, return the number of expected tokens (guaranteed to
+ be less than YYNTOKENS). Return YYENOMEM on memory exhaustion.
+ Return 0 if there are more than YYARGN expected tokens, yet fill
+ YYARG up to YYARGN. */
+static int
+yypcontext_expected_tokens (const yypcontext_t *yyctx,
+ yysymbol_kind_t yyarg[], int yyargn)
+{
+ /* Actual size of YYARG. */
+ int yycount = 0;
+ int yyn = yypact[+*yyctx->yyssp];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (!yyarg)
+ ++yycount;
+ else if (yycount == yyargn)
+ return 0;
+ else
+ yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx);
+ }
+ }
+ if (yyarg && yycount == 0 && 0 < yyargn)
+ yyarg[0] = YYSYMBOL_YYEMPTY;
+ return yycount;
+}
+
+
+
+
+#ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S)))
+# else
+/* Return the length of YYSTR. */
+static YYPTRDIFF_T
+yystrlen (const char *yystr)
+{
+ YYPTRDIFF_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+#endif
+
+#ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+#endif
+
+#ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYPTRDIFF_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYPTRDIFF_T yyn = 0;
+ char const *yyp = yystr;
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ else
+ goto append;
+
+ append:
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (yyres)
+ return yystpcpy (yyres, yystr) - yyres;
+ else
+ return yystrlen (yystr);
+}
+#endif
+
+
+static int
+yy_syntax_error_arguments (const yypcontext_t *yyctx,
+ yysymbol_kind_t yyarg[], int yyargn)
+{
+ /* Actual size of YYARG. */
+ int yycount = 0;
+ /* There are many possibilities here to consider:
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yyctx->yytoken != YYSYMBOL_YYEMPTY)
+ {
+ int yyn;
+ if (yyarg)
+ yyarg[yycount] = yyctx->yytoken;
+ ++yycount;
+ yyn = yypcontext_expected_tokens (yyctx,
+ yyarg ? yyarg + 1 : yyarg, yyargn - 1);
+ if (yyn == YYENOMEM)
+ return YYENOMEM;
+ else
+ yycount += yyn;
+ }
+ return yycount;
+}
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg,
+ const yypcontext_t *yyctx)
+{
+ enum { YYARGS_MAX = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULLPTR;
+ /* Arguments of yyformat: reported tokens (one for the "unexpected",
+ one per "expected"). */
+ yysymbol_kind_t yyarg[YYARGS_MAX];
+ /* Cumulated lengths of YYARG. */
+ YYPTRDIFF_T yysize = 0;
+
+ /* Actual size of YYARG. */
+ int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX);
+ if (yycount == YYENOMEM)
+ return YYENOMEM;
+
+ switch (yycount)
+ {
+#define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ default: /* Avoid compiler warnings. */
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+#undef YYCASE_
+ }
+
+ /* Compute error message size. Don't count the "%s"s, but reserve
+ room for the terminator. */
+ yysize = yystrlen (yyformat) - 2 * yycount + 1;
+ {
+ int yyi;
+ for (yyi = 0; yyi < yycount; ++yyi)
+ {
+ YYPTRDIFF_T yysize1
+ = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]);
+ if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
+ yysize = yysize1;
+ else
+ return YYENOMEM;
+ }
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return -1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]);
+ yyformat += 2;
+ }
+ else
+ {
+ ++yyp;
+ ++yyformat;
+ }
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg,
+ yysymbol_kind_t yykind, YYSTYPE *yyvaluep, yyscan_t yyscanner)
+{
+ YYUSE (yyvaluep);
+ YYUSE (yyscanner);
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ YYUSE (yykind);
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+int
+yyparse (yyscan_t yyscanner)
+{
+/* Lookahead token kind. */
+int yychar;
+
+
+/* The semantic value of the lookahead symbol. */
+/* Default value used for initialization, for pacifying older GCCs
+ or non-GCC compilers. */
+YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
+YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
+
+ /* Number of syntax errors so far. */
+ int yynerrs = 0;
+
+ yy_state_fast_t yystate = 0;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus = 0;
+
+ /* Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* Their size. */
+ YYPTRDIFF_T yystacksize = YYINITDEPTH;
+
+ /* The state stack: array, bottom, top. */
+ yy_state_t yyssa[YYINITDEPTH];
+ yy_state_t *yyss = yyssa;
+ yy_state_t *yyssp = yyss;
+
+ /* The semantic value stack: array, bottom, top. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp = yyvs;
+
+ int yyn;
+ /* The return value of yyparse. */
+ int yyresult;
+ /* Lookahead symbol kind. */
+ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf;
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ goto yysetstate;
+
+
+/*------------------------------------------------------------.
+| yynewstate -- push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+
+/*--------------------------------------------------------------------.
+| yysetstate -- set current state (the top of the stack) to yystate. |
+`--------------------------------------------------------------------*/
+yysetstate:
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+ YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
+ YY_IGNORE_USELESS_CAST_BEGIN
+ *yyssp = YY_CAST (yy_state_t, yystate);
+ YY_IGNORE_USELESS_CAST_END
+ YY_STACK_PRINT (yyss, yyssp);
+
+ if (yyss + yystacksize - 1 <= yyssp)
+#if !defined yyoverflow && !defined YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+#else
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYPTRDIFF_T yysize = yyssp - yyss + 1;
+
+# if defined yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ yy_state_t *yyss1 = yyss;
+ YYSTYPE *yyvs1 = yyvs;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * YYSIZEOF (*yyssp),
+ &yyvs1, yysize * YYSIZEOF (*yyvsp),
+ &yystacksize);
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+# else /* defined YYSTACK_RELOCATE */
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yy_state_t *yyss1 = yyss;
+ union yyalloc *yyptr =
+ YY_CAST (union yyalloc *,
+ YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YY_IGNORE_USELESS_CAST_BEGIN
+ YYDPRINTF ((stderr, "Stack size increased to %ld\n",
+ YY_CAST (long, yystacksize)));
+ YY_IGNORE_USELESS_CAST_END
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token\n"));
+ yychar = yylex (&yylval, yyscanner);
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = YYEOF;
+ yytoken = YYSYMBOL_YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else if (yychar == YYerror)
+ {
+ /* The scanner already issued an error message, process directly
+ to error recovery. But do not keep the error token as
+ lookahead, it is too special and may lead us to an endless
+ loop in error recovery. */
+ yychar = YYUNDEF;
+ yytoken = YYSYMBOL_YYerror;
+ goto yyerrlab1;
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ '$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2: /* start: exp */
+#line 81 "cmExprParser.y"
+ {
+ cmExpr_yyget_extra(yyscanner)->SetResult((yyvsp[0].Number));
+ }
+#line 1429 "cmExprParser.cxx"
+ break;
+
+ case 3: /* exp: bitwiseor */
+#line 86 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[0].Number);
+ }
+#line 1437 "cmExprParser.cxx"
+ break;
+
+ case 4: /* exp: exp exp_OR bitwiseor */
+#line 89 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[-2].Number) | (yyvsp[0].Number);
+ }
+#line 1445 "cmExprParser.cxx"
+ break;
+
+ case 5: /* bitwiseor: bitwisexor */
+#line 94 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[0].Number);
+ }
+#line 1453 "cmExprParser.cxx"
+ break;
+
+ case 6: /* bitwiseor: bitwiseor exp_XOR bitwisexor */
+#line 97 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[-2].Number) ^ (yyvsp[0].Number);
+ }
+#line 1461 "cmExprParser.cxx"
+ break;
+
+ case 7: /* bitwisexor: bitwiseand */
+#line 102 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[0].Number);
+ }
+#line 1469 "cmExprParser.cxx"
+ break;
+
+ case 8: /* bitwisexor: bitwisexor exp_AND bitwiseand */
+#line 105 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[-2].Number) & (yyvsp[0].Number);
+ }
+#line 1477 "cmExprParser.cxx"
+ break;
+
+ case 9: /* bitwiseand: shift */
+#line 110 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[0].Number);
+ }
+#line 1485 "cmExprParser.cxx"
+ break;
+
+ case 10: /* bitwiseand: bitwiseand exp_SHIFTLEFT shift */
+#line 113 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[-2].Number) << (yyvsp[0].Number);
+ }
+#line 1493 "cmExprParser.cxx"
+ break;
+
+ case 11: /* bitwiseand: bitwiseand exp_SHIFTRIGHT shift */
+#line 116 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[-2].Number) >> (yyvsp[0].Number);
+ }
+#line 1501 "cmExprParser.cxx"
+ break;
+
+ case 12: /* shift: term */
+#line 121 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[0].Number);
+ }
+#line 1509 "cmExprParser.cxx"
+ break;
+
+ case 13: /* shift: shift exp_PLUS term */
+#line 124 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[-2].Number) + (yyvsp[0].Number);
+ }
+#line 1517 "cmExprParser.cxx"
+ break;
+
+ case 14: /* shift: shift exp_MINUS term */
+#line 127 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[-2].Number) - (yyvsp[0].Number);
+ }
+#line 1525 "cmExprParser.cxx"
+ break;
+
+ case 15: /* term: unary */
+#line 132 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[0].Number);
+ }
+#line 1533 "cmExprParser.cxx"
+ break;
+
+ case 16: /* term: term exp_TIMES unary */
+#line 135 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[-2].Number) * (yyvsp[0].Number);
+ }
+#line 1541 "cmExprParser.cxx"
+ break;
+
+ case 17: /* term: term exp_DIVIDE unary */
+#line 138 "cmExprParser.y"
+ {
+ if (yyvsp[0].Number == 0) {
+ throw std::overflow_error("divide by zero");
+ }
+ (yyval.Number) = (yyvsp[-2].Number) / (yyvsp[0].Number);
+ }
+#line 1552 "cmExprParser.cxx"
+ break;
+
+ case 18: /* term: term exp_MOD unary */
+#line 144 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[-2].Number) % (yyvsp[0].Number);
+ }
+#line 1560 "cmExprParser.cxx"
+ break;
+
+ case 19: /* unary: factor */
+#line 149 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[0].Number);
+ }
+#line 1568 "cmExprParser.cxx"
+ break;
+
+ case 20: /* unary: exp_PLUS unary */
+#line 152 "cmExprParser.y"
+ {
+ (yyval.Number) = + (yyvsp[0].Number);
+ }
+#line 1576 "cmExprParser.cxx"
+ break;
+
+ case 21: /* unary: exp_MINUS unary */
+#line 155 "cmExprParser.y"
+ {
+ (yyval.Number) = - (yyvsp[0].Number);
+ }
+#line 1584 "cmExprParser.cxx"
+ break;
+
+ case 22: /* unary: exp_NOT unary */
+#line 158 "cmExprParser.y"
+ {
+ (yyval.Number) = ~ (yyvsp[0].Number);
+ }
+#line 1592 "cmExprParser.cxx"
+ break;
+
+ case 23: /* factor: exp_NUMBER */
+#line 163 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[0].Number);
+ }
+#line 1600 "cmExprParser.cxx"
+ break;
+
+ case 24: /* factor: exp_OPENPARENT exp exp_CLOSEPARENT */
+#line 166 "cmExprParser.y"
+ {
+ (yyval.Number) = (yyvsp[-1].Number);
+ }
+#line 1608 "cmExprParser.cxx"
+ break;
+
+
+#line 1612 "cmExprParser.cxx"
+
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+
+ *++yyvsp = yyval;
+
+ /* Now 'shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+ {
+ const int yylhs = yyr1[yyn] - YYNTOKENS;
+ const int yyi = yypgoto[yylhs] + *yyssp;
+ yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp
+ ? yytable[yyi]
+ : yydefgoto[yylhs]);
+ }
+
+ goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error. |
+`--------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+ {
+ yypcontext_t yyctx
+ = {yyssp, yytoken};
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == -1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = YY_CAST (char *,
+ YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc)));
+ if (yymsg)
+ {
+ yysyntax_error_status
+ = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+ yymsgp = yymsg;
+ }
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = YYENOMEM;
+ }
+ }
+ yyerror (yyscanner, yymsgp);
+ if (yysyntax_error_status == YYENOMEM)
+ goto yyexhaustedlab;
+ }
+ }
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, yyscanner);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+ /* Pacify compilers when the user code never invokes YYERROR and the
+ label yyerrorlab therefore never appears in user code. */
+ if (0)
+ YYERROR;
+
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ /* Pop stack until we find a state that shifts the error token. */
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYSYMBOL_YYerror;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ YY_ACCESSING_SYMBOL (yystate), yyvsp, yyscanner);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+
+#if 1
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (yyscanner, YY_("memory exhausted"));
+ yyresult = 2;
+ goto yyreturn;
+#endif
+
+
+/*-------------------------------------------------------.
+| yyreturn -- parsing is finished, clean up and return. |
+`-------------------------------------------------------*/
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, yyscanner);
+ }
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yyscanner);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ return yyresult;
+}
+
+#line 171 "cmExprParser.y"
+
+/* End of grammar */
+
+/*--------------------------------------------------------------------------*/
+void cmExpr_yyerror(yyscan_t yyscanner, const char* message)
+{
+ cmExpr_yyget_extra(yyscanner)->Error(message);
+}
diff --git a/Source/LexerParser/cmExprParser.y b/Source/LexerParser/cmExprParser.y
new file mode 100644
index 0000000..b49f482
--- /dev/null
+++ b/Source/LexerParser/cmExprParser.y
@@ -0,0 +1,178 @@
+%{
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --name-prefix=cmExpr_yy --defines=cmExprParserTokens.h -ocmExprParser.cxx cmExprParser.y
+
+*/
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdexcept>
+
+/*-------------------------------------------------------------------------*/
+#define YYDEBUG 1
+#include "cmExprParserHelper.h" /* Interface to parser object. */
+#include "cmExprLexer.h" /* Interface to lexer object. */
+#include "cmExprParserTokens.h" /* Need YYSTYPE for YY_DECL. */
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Helper function to forward error callback from parser. */
+static void cmExpr_yyerror(yyscan_t yyscanner, const char* message);
+
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch statement contains default but no case. */
+#endif
+#if defined(__GNUC__) && __GNUC__ >= 8
+# pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+#endif
+#if defined(__clang__) && defined(__has_warning)
+# if __has_warning("-Wused-but-marked-unused")
+# pragma clang diagnostic ignored "-Wused-but-marked-unused"
+# endif
+#endif
+%}
+
+/* Generate a reentrant parser object. */
+%define api.pure
+
+/* Configure the parser to use a lexer object. */
+%lex-param {yyscan_t yyscanner}
+%parse-param {yyscan_t yyscanner}
+
+%define parse.error verbose
+
+/*-------------------------------------------------------------------------*/
+/* Tokens */
+%token exp_PLUS
+%token exp_MINUS
+%token exp_TIMES
+%token exp_DIVIDE
+%token exp_MOD
+%token exp_SHIFTLEFT
+%token exp_SHIFTRIGHT
+%token exp_OPENPARENT
+%token exp_CLOSEPARENT
+%token exp_OR;
+%token exp_AND;
+%token exp_XOR;
+%token exp_NOT;
+%token exp_NUMBER;
+
+/*-------------------------------------------------------------------------*/
+/* grammar */
+%%
+
+
+start:
+ exp {
+ cmExpr_yyget_extra(yyscanner)->SetResult($<Number>1);
+ }
+
+exp:
+ bitwiseor {
+ $<Number>$ = $<Number>1;
+ }
+| exp exp_OR bitwiseor {
+ $<Number>$ = $<Number>1 | $<Number>3;
+ }
+
+bitwiseor:
+ bitwisexor {
+ $<Number>$ = $<Number>1;
+ }
+| bitwiseor exp_XOR bitwisexor {
+ $<Number>$ = $<Number>1 ^ $<Number>3;
+ }
+
+bitwisexor:
+ bitwiseand {
+ $<Number>$ = $<Number>1;
+ }
+| bitwisexor exp_AND bitwiseand {
+ $<Number>$ = $<Number>1 & $<Number>3;
+ }
+
+bitwiseand:
+ shift {
+ $<Number>$ = $<Number>1;
+ }
+| bitwiseand exp_SHIFTLEFT shift {
+ $<Number>$ = $<Number>1 << $<Number>3;
+ }
+| bitwiseand exp_SHIFTRIGHT shift {
+ $<Number>$ = $<Number>1 >> $<Number>3;
+ }
+
+shift:
+ term {
+ $<Number>$ = $<Number>1;
+ }
+| shift exp_PLUS term {
+ $<Number>$ = $<Number>1 + $<Number>3;
+ }
+| shift exp_MINUS term {
+ $<Number>$ = $<Number>1 - $<Number>3;
+ }
+
+term:
+ unary {
+ $<Number>$ = $<Number>1;
+ }
+| term exp_TIMES unary {
+ $<Number>$ = $<Number>1 * $<Number>3;
+ }
+| term exp_DIVIDE unary {
+ if (yyvsp[0].Number == 0) {
+ throw std::overflow_error("divide by zero");
+ }
+ $<Number>$ = $<Number>1 / $<Number>3;
+ }
+| term exp_MOD unary {
+ $<Number>$ = $<Number>1 % $<Number>3;
+ }
+
+unary:
+ factor {
+ $<Number>$ = $<Number>1;
+ }
+| exp_PLUS unary {
+ $<Number>$ = + $<Number>2;
+ }
+| exp_MINUS unary {
+ $<Number>$ = - $<Number>2;
+ }
+| exp_NOT unary {
+ $<Number>$ = ~ $<Number>2;
+ }
+
+factor:
+ exp_NUMBER {
+ $<Number>$ = $<Number>1;
+ }
+| exp_OPENPARENT exp exp_CLOSEPARENT {
+ $<Number>$ = $<Number>2;
+ }
+;
+
+%%
+/* End of grammar */
+
+/*--------------------------------------------------------------------------*/
+void cmExpr_yyerror(yyscan_t yyscanner, const char* message)
+{
+ cmExpr_yyget_extra(yyscanner)->Error(message);
+}
diff --git a/Source/LexerParser/cmExprParserTokens.h b/Source/LexerParser/cmExprParserTokens.h
new file mode 100644
index 0000000..2eb1fe9
--- /dev/null
+++ b/Source/LexerParser/cmExprParserTokens.h
@@ -0,0 +1,81 @@
+/* A Bison parser, made by GNU Bison 3.7.4. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
+ Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+ especially those whose name start with YY_ or yy_. They are
+ private implementation details that can be changed or removed. */
+
+#ifndef YY_CMEXPR_YY_CMEXPRPARSERTOKENS_H_INCLUDED
+# define YY_CMEXPR_YY_CMEXPRPARSERTOKENS_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int cmExpr_yydebug;
+#endif
+
+/* Token kinds. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ YYEMPTY = -2,
+ YYEOF = 0, /* "end of file" */
+ YYerror = 256, /* error */
+ YYUNDEF = 257, /* "invalid token" */
+ exp_PLUS = 258, /* exp_PLUS */
+ exp_MINUS = 259, /* exp_MINUS */
+ exp_TIMES = 260, /* exp_TIMES */
+ exp_DIVIDE = 261, /* exp_DIVIDE */
+ exp_MOD = 262, /* exp_MOD */
+ exp_SHIFTLEFT = 263, /* exp_SHIFTLEFT */
+ exp_SHIFTRIGHT = 264, /* exp_SHIFTRIGHT */
+ exp_OPENPARENT = 265, /* exp_OPENPARENT */
+ exp_CLOSEPARENT = 266, /* exp_CLOSEPARENT */
+ exp_OR = 267, /* exp_OR */
+ exp_AND = 268, /* exp_AND */
+ exp_XOR = 269, /* exp_XOR */
+ exp_NOT = 270, /* exp_NOT */
+ exp_NUMBER = 271 /* exp_NUMBER */
+ };
+ typedef enum yytokentype yytoken_kind_t;
+#endif
+
+/* Value type. */
+
+
+
+int cmExpr_yyparse (yyscan_t yyscanner);
+
+#endif /* !YY_CMEXPR_YY_CMEXPRPARSERTOKENS_H_INCLUDED */
diff --git a/Source/LexerParser/cmFortranLexer.cxx b/Source/LexerParser/cmFortranLexer.cxx
new file mode 100644
index 0000000..bcda77c
--- /dev/null
+++ b/Source/LexerParser/cmFortranLexer.cxx
@@ -0,0 +1,2616 @@
+#include "cmStandardLexer.h"
+
+#define FLEXINT_H 1
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmFortran_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmFortran_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmFortran_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmFortran_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmFortran_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmFortran_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmFortran_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmFortran_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmFortran_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmFortran_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmFortran_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmFortran_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmFortran_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmFortran_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmFortran_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmFortran_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmFortran_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmFortran_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmFortran_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmFortran_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmFortran_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmFortran_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmFortran_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmFortran_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmFortran_yylex_ALREADY_DEFINED
+#else
+#define yylex cmFortran_yylex
+#endif
+
+#ifdef yyrestart
+#define cmFortran_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmFortran_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmFortran_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmFortran_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmFortran_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmFortran_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmFortran_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmFortran_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmFortran_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmFortran_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmFortran_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmFortran_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmFortran_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmFortran_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmFortran_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmFortran_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmFortran_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmFortran_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmFortran_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmFortran_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmFortran_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmFortran_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmFortran_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmFortran_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmFortran_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmFortran_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmFortran_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmFortran_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmFortran_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmFortran_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmFortran_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmFortran_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmFortran_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmFortran_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmFortran_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmFortran_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmFortran_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmFortran_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmFortran_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmFortran_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmFortran_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmFortran_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmFortran_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmFortran_yyfree
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an
+ * integer in range [0..255] for use as an array index.
+ */
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin , yyscanner )
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+ #define YY_LINENO_REWIND_TO(ptr)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+static void yyensure_buffer_stack ( yyscan_t yyscanner );
+static void yy_load_buffer_state ( yyscan_t yyscanner );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner)
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+#define yy_new_buffer yy_create_buffer
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define cmFortran_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+typedef flex_uint8_t YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner);
+static int yy_get_next_buffer ( yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+#define YY_NUM_RULES 54
+#define YY_END_OF_BUFFER 55
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static const flex_int16_t yy_accept[210] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 55, 49, 51, 50, 53, 1, 49, 33, 2, 47,
+ 48, 35, 37, 50, 39, 49, 46, 46, 46, 46,
+ 46, 46, 49, 46, 51, 49, 50, 49, 46, 9,
+ 8, 9, 4, 3, 49, 0, 10, 0, 0, 0,
+ 0, 0, 33, 33, 34, 36, 39, 49, 46, 46,
+ 46, 46, 46, 46, 0, 52, 46, 0, 0, 0,
+ 12, 0, 0, 0, 0, 0, 0, 49, 0, 11,
+ 46, 0, 0, 5, 0, 0, 0, 0, 29, 0,
+ 33, 33, 33, 33, 0, 0, 40, 46, 46, 46,
+
+ 46, 45, 12, 12, 0, 0, 0, 23, 0, 0,
+ 0, 0, 0, 0, 6, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 46, 46, 46, 46, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 30, 31, 0, 0, 0, 0, 0, 46, 46,
+ 46, 46, 0, 24, 25, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 20, 32, 27, 0, 0, 0,
+ 46, 46, 43, 46, 0, 26, 21, 0, 0, 0,
+ 19, 0, 0, 18, 28, 0, 0, 41, 46, 46,
+ 17, 22, 0, 7, 38, 7, 15, 0, 46, 46,
+
+ 14, 16, 42, 44, 0, 0, 0, 13, 0
+ } ;
+
+static const YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 5, 6, 7, 8, 9, 1, 10, 11, 12,
+ 13, 14, 1, 15, 1, 1, 1, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 17, 18, 19,
+ 20, 21, 22, 1, 23, 24, 25, 26, 27, 28,
+ 29, 29, 30, 29, 29, 31, 32, 33, 34, 29,
+ 29, 35, 36, 37, 38, 29, 29, 29, 29, 29,
+ 1, 39, 1, 1, 40, 1, 23, 24, 41, 42,
+
+ 43, 44, 29, 29, 45, 29, 29, 46, 32, 47,
+ 34, 29, 29, 35, 48, 37, 49, 29, 29, 29,
+ 29, 29, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static const YY_CHAR yy_meta[50] =
+ { 0,
+ 1, 2, 2, 3, 4, 3, 3, 1, 1, 3,
+ 3, 3, 3, 1, 3, 5, 3, 3, 1, 3,
+ 6, 1, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 1, 5,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7
+ } ;
+
+static const flex_int16_t yy_base[219] =
+ { 0,
+ 0, 48, 0, 49, 464, 56, 52, 57, 62, 68,
+ 466, 0, 468, 468, 462, 468, 74, 81, 468, 468,
+ 468, 468, 447, 468, 442, 440, 0, 19, 41, 427,
+ 47, 41, 90, 119, 97, 158, 455, 207, 247, 468,
+ 454, 101, 468, 468, 0, 455, 468, 105, 430, 423,
+ 62, 67, 119, 151, 468, 468, 468, 121, 0, 90,
+ 93, 110, 431, 112, 142, 468, 0, 160, 295, 0,
+ 162, 411, 123, 102, 408, 405, 446, 344, 447, 468,
+ 0, 444, 170, 174, 420, 421, 132, 404, 95, 404,
+ 180, 186, 192, 228, 297, 397, 0, 168, 144, 52,
+
+ 411, 0, 204, 217, 397, 179, 390, 170, 389, 378,
+ 364, 390, 389, 230, 468, 363, 355, 337, 337, 334,
+ 335, 335, 330, 334, 187, 339, 267, 339, 327, 327,
+ 327, 324, 325, 325, 318, 319, 318, 354, 352, 323,
+ 327, 468, 468, 310, 307, 305, 297, 297, 275, 275,
+ 277, 279, 287, 468, 468, 286, 283, 273, 196, 307,
+ 200, 238, 234, 210, 468, 468, 468, 174, 171, 162,
+ 279, 182, 0, 269, 150, 468, 468, 137, 109, 323,
+ 468, 239, 0, 468, 468, 72, 71, 0, 283, 283,
+ 468, 468, 51, 468, 468, 468, 468, 37, 283, 288,
+
+ 330, 468, 0, 0, 331, 0, 52, 468, 468, 384,
+ 391, 397, 400, 407, 414, 421, 428, 435
+ } ;
+
+static const flex_int16_t yy_def[219] =
+ { 0,
+ 209, 1, 1, 1, 1, 1, 210, 210, 210, 210,
+ 209, 211, 209, 209, 212, 209, 211, 209, 209, 209,
+ 209, 209, 209, 209, 209, 211, 213, 213, 213, 213,
+ 213, 213, 211, 213, 209, 211, 209, 214, 209, 209,
+ 209, 209, 209, 209, 211, 212, 209, 209, 209, 209,
+ 209, 209, 209, 215, 209, 209, 209, 211, 213, 213,
+ 213, 213, 213, 213, 209, 209, 34, 209, 209, 69,
+ 211, 209, 209, 209, 209, 209, 209, 214, 214, 209,
+ 39, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 215, 215, 215, 215, 209, 209, 213, 213, 213, 213,
+
+ 213, 213, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 213, 213, 213, 213, 209, 209,
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 209, 209, 209, 209, 213, 213,
+ 213, 213, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 213, 213, 213, 213, 209, 209, 209, 209, 209, 209,
+ 209, 216, 217, 209, 209, 209, 209, 213, 213, 213,
+ 209, 209, 209, 209, 209, 209, 209, 209, 213, 213,
+
+ 209, 209, 213, 213, 209, 218, 218, 209, 0, 209,
+ 209, 209, 209, 209, 209, 209, 209, 209
+ } ;
+
+static const flex_int16_t yy_nxt[518] =
+ { 0,
+ 12, 13, 14, 13, 13, 15, 16, 12, 17, 18,
+ 19, 20, 21, 12, 22, 12, 23, 24, 12, 25,
+ 12, 26, 27, 27, 27, 27, 28, 27, 27, 29,
+ 27, 30, 27, 27, 27, 31, 27, 32, 33, 34,
+ 27, 27, 28, 27, 29, 27, 27, 31, 32, 35,
+ 35, 60, 35, 35, 41, 36, 36, 35, 37, 41,
+ 35, 42, 43, 36, 41, 60, 42, 43, 44, 38,
+ 41, 42, 208, 61, 44, 48, 64, 42, 48, 202,
+ 39, 39, 53, 53, 63, 53, 54, 61, 64, 127,
+ 55, 65, 66, 201, 65, 63, 39, 39, 68, 49,
+
+ 127, 68, 83, 84, 69, 83, 48, 87, 88, 48,
+ 89, 50, 198, 90, 197, 97, 51, 98, 52, 45,
+ 53, 53, 95, 53, 54, 95, 45, 45, 55, 99,
+ 49, 97, 45, 98, 67, 100, 121, 45, 102, 45,
+ 45, 122, 50, 65, 66, 108, 65, 51, 109, 52,
+ 193, 100, 92, 53, 102, 92, 93, 45, 67, 70,
+ 94, 68, 70, 104, 68, 96, 104, 69, 106, 107,
+ 126, 83, 84, 71, 83, 114, 118, 71, 114, 119,
+ 192, 92, 53, 115, 92, 93, 126, 92, 53, 94,
+ 92, 93, 191, 92, 53, 94, 92, 93, 125, 72,
+
+ 73, 94, 74, 75, 189, 104, 76, 78, 104, 80,
+ 187, 133, 186, 125, 78, 78, 134, 185, 104, 103,
+ 78, 104, 78, 130, 149, 78, 131, 78, 78, 92,
+ 53, 114, 92, 93, 114, 149, 184, 94, 183, 115,
+ 195, 195, 182, 181, 179, 78, 78, 79, 79, 80,
+ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+ 79, 79, 81, 79, 79, 79, 79, 79, 79, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 79, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 70, 151, 95, 70,
+
+ 171, 95, 172, 173, 174, 188, 190, 199, 180, 203,
+ 103, 180, 151, 200, 204, 178, 171, 190, 172, 173,
+ 174, 188, 103, 199, 180, 203, 177, 180, 200, 176,
+ 204, 205, 205, 175, 205, 205, 72, 73, 103, 74,
+ 75, 96, 170, 76, 78, 169, 80, 168, 206, 206,
+ 167, 78, 78, 166, 165, 164, 163, 78, 162, 78,
+ 161, 160, 78, 159, 78, 78, 158, 157, 156, 155,
+ 154, 153, 152, 150, 148, 147, 146, 145, 144, 143,
+ 142, 141, 78, 78, 40, 40, 40, 40, 40, 40,
+ 40, 45, 140, 139, 138, 45, 45, 46, 46, 46,
+
+ 46, 46, 46, 46, 59, 137, 59, 79, 79, 79,
+ 79, 79, 79, 79, 91, 91, 91, 91, 91, 91,
+ 91, 194, 194, 194, 136, 194, 194, 194, 196, 135,
+ 196, 132, 196, 196, 196, 207, 207, 207, 207, 207,
+ 129, 207, 128, 124, 123, 120, 117, 116, 113, 80,
+ 112, 111, 110, 105, 101, 86, 85, 47, 82, 77,
+ 62, 58, 57, 56, 47, 209, 37, 11, 209, 209,
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 209, 209, 209
+ } ;
+
+static const flex_int16_t yy_chk[518] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 4, 28, 2, 4, 7, 2, 4, 6, 6, 8,
+ 6, 7, 7, 6, 9, 28, 8, 8, 9, 6,
+ 10, 9, 207, 29, 10, 17, 32, 10, 17, 198,
+ 6, 6, 18, 18, 31, 18, 18, 29, 32, 100,
+ 18, 33, 33, 193, 33, 31, 6, 6, 35, 17,
+
+ 100, 35, 42, 42, 35, 42, 48, 51, 51, 48,
+ 52, 17, 187, 52, 186, 60, 17, 61, 17, 34,
+ 53, 53, 58, 53, 53, 58, 34, 34, 53, 61,
+ 48, 60, 34, 61, 34, 62, 89, 34, 64, 34,
+ 34, 89, 48, 65, 65, 74, 65, 48, 74, 48,
+ 179, 62, 54, 54, 64, 54, 54, 34, 34, 36,
+ 54, 68, 36, 71, 68, 58, 71, 68, 73, 73,
+ 99, 83, 83, 36, 83, 84, 87, 71, 84, 87,
+ 178, 91, 91, 84, 91, 91, 99, 92, 92, 91,
+ 92, 92, 175, 93, 93, 92, 93, 93, 98, 36,
+
+ 36, 93, 36, 36, 172, 103, 36, 38, 103, 38,
+ 170, 108, 169, 98, 38, 38, 108, 168, 104, 103,
+ 38, 104, 38, 106, 125, 38, 106, 38, 38, 94,
+ 94, 114, 94, 94, 114, 125, 164, 94, 163, 114,
+ 182, 182, 162, 161, 159, 38, 38, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 69, 127, 95, 69,
+
+ 149, 95, 150, 151, 152, 171, 174, 189, 160, 199,
+ 69, 160, 127, 190, 200, 158, 149, 174, 150, 151,
+ 152, 171, 160, 189, 180, 199, 157, 180, 190, 156,
+ 200, 201, 205, 153, 201, 205, 69, 69, 180, 69,
+ 69, 95, 148, 69, 78, 147, 78, 146, 201, 205,
+ 145, 78, 78, 144, 141, 140, 139, 78, 138, 78,
+ 137, 136, 78, 135, 78, 78, 134, 133, 132, 131,
+ 130, 129, 128, 126, 124, 123, 122, 121, 120, 119,
+ 118, 117, 78, 78, 210, 210, 210, 210, 210, 210,
+ 210, 211, 116, 113, 112, 211, 211, 212, 212, 212,
+
+ 212, 212, 212, 212, 213, 111, 213, 214, 214, 214,
+ 214, 214, 214, 214, 215, 215, 215, 215, 215, 215,
+ 215, 216, 216, 216, 110, 216, 216, 216, 217, 109,
+ 217, 107, 217, 217, 217, 218, 218, 218, 218, 218,
+ 105, 218, 101, 96, 90, 88, 86, 85, 82, 79,
+ 77, 76, 75, 72, 63, 50, 49, 46, 41, 37,
+ 30, 26, 25, 23, 15, 11, 5, 209, 209, 209,
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 209, 209, 209
+ } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*-------------------------------------------------------------------------
+ Portions of this source have been derived from makedepf90 version 2.8.8,
+
+ Copyright (C) 2000--2006 Erik Edelmann <erik.edelmann@iki.fi>
+
+ The code was originally distributed under the GPL but permission
+ from the copyright holder has been obtained to distribute this
+ derived work under the CMake license.
+-------------------------------------------------------------------------*/
+
+/*
+
+This file must be translated to C++ and modified to build everywhere.
+
+Run flex >= 2.6 like this:
+
+ flex -i --nounistd -DFLEXINT_H --noline --header-file=cmFortranLexer.h -ocmFortranLexer.cxx cmFortranLexer.in.l
+
+Modify cmFortranLexer.cxx:
+ - remove trailing whitespace: sed -i 's/\s*$//' cmFortranLexer.h cmFortranLexer.cxx
+ - remove blank lines at end of file: sed -i '${/^$/d;}' cmFortranLexer.h cmFortranLexer.cxx
+ - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmFortranLexer.cxx
+*/
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
+
+#undef YY_NO_UNPUT
+
+#define cmFortranLexer_cxx
+#include "cmFortranParser.h" /* Interface to parser object. */
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ do { result = cmFortranParser_Input(yyextra, buf, max_size); } while (0)
+
+/* Include the set of tokens from the parser. */
+#include "cmFortranParserTokens.h"
+
+/*--------------------------------------------------------------------------*/
+
+#define INITIAL 0
+#define free_fmt 1
+#define fixed_fmt 2
+#define str_sq 3
+#define str_dq 4
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals ( yyscan_t yyscanner );
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput ( int c, char *buf_ptr , yyscan_t yyscanner);
+
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput ( yyscan_t yyscanner );
+#else
+static int input ( yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ int n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK /*LINTED*/break;
+#endif
+
+#define YY_RULE_SETUP \
+ if ( yyleng > 0 ) \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
+ (yytext[yyleng - 1] == '\n'); \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_load_buffer_state( yyscanner );
+ }
+
+ {
+
+ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+ yy_current_state += YY_AT_BOL();
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 210 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 468 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+{
+ cmFortranParser_StringStart(yyextra);
+ cmFortranParser_SetOldStartcond(yyextra, YY_START);
+ BEGIN(str_dq);
+}
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+{
+ cmFortranParser_StringStart(yyextra);
+ cmFortranParser_SetOldStartcond(yyextra, YY_START);
+ BEGIN(str_sq);
+}
+ YY_BREAK
+case 3:
+case 4:
+YY_RULE_SETUP
+{
+ BEGIN(cmFortranParser_GetOldStartcond(yyextra) );
+ yylvalp->string = strdup(cmFortranParser_StringEnd(yyextra));
+ return STRING;
+}
+ YY_BREAK
+case 5:
+/* rule 5 can match eol */
+case 6:
+/* rule 6 can match eol */
+YY_RULE_SETUP
+/* Ignore (continued strings, free fmt) */
+ YY_BREAK
+case 7:
+/* rule 7 can match eol */
+YY_RULE_SETUP
+{
+ if (cmFortranParser_GetOldStartcond(yyextra) == fixed_fmt)
+ ; /* Ignore (cont. strings, fixed fmt) */
+ else
+ {
+ unput(yytext[strlen(yytext)-1]);
+ }
+}
+ YY_BREAK
+case 8:
+/* rule 8 can match eol */
+YY_RULE_SETUP
+{
+ unput ('\n');
+ BEGIN(INITIAL);
+ return UNTERMINATED_STRING;
+}
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+{
+ cmFortranParser_StringAppend(yyextra, yytext[0]);
+}
+ YY_BREAK
+case 10:
+/* rule 10 can match eol */
+YY_RULE_SETUP
+{ return EOSTMT; } /* Treat comments like */
+ YY_BREAK
+case 11:
+/* rule 11 can match eol */
+YY_RULE_SETUP
+{ return EOSTMT; } /* empty lines */
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+{ return CPP_LINE_DIRECTIVE; }
+ YY_BREAK
+case 13:
+/* rule 13 can match eol */
+YY_RULE_SETUP
+{
+ yytext[yyleng-1] = 0;
+ yylvalp->string = strdup(strchr(yytext, '<')+1);
+ return CPP_INCLUDE_ANGLE;
+}
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+{ return CPP_INCLUDE; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+{ return F90PPR_INCLUDE; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+{ return COCO_INCLUDE; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+{ return CPP_DEFINE; }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+{ return F90PPR_DEFINE; }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+{ return CPP_UNDEF; }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+{ return F90PPR_UNDEF; }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+{ return CPP_IFDEF; }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+{ return CPP_IFNDEF; }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+{ return CPP_IF; }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+{ return CPP_ELIF; }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+{ return CPP_ELSE; }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+{ return CPP_ENDIF; }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+{ return F90PPR_IFDEF; }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+{ return F90PPR_IFNDEF; }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+{ return F90PPR_IF; }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+{ return F90PPR_ELIF; }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+{ return F90PPR_ELSE; }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+{ return F90PPR_ENDIF; }
+ YY_BREAK
+/* Line continuations, possible involving comments. */
+case 33:
+/* rule 33 can match eol */
+YY_RULE_SETUP
+
+ YY_BREAK
+case 34:
+/* rule 34 can match eol */
+YY_RULE_SETUP
+
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+{ return COMMA; }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+{ return DCOLON; }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+{ return COLON; }
+ YY_BREAK
+case 38:
+/* rule 38 can match eol */
+YY_RULE_SETUP
+{ return GARBAGE; }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+{ return ASSIGNMENT_OP; }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+{ return END; }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+{ return INCLUDE; }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+{ return INTERFACE; }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+{ return MODULE; }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+{ return SUBMODULE; }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+{ return USE; }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+{
+ yylvalp->string = strdup(yytext);
+ return WORD;
+}
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+{ return LPAREN; }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+{ return RPAREN; }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+{ return GARBAGE; }
+ YY_BREAK
+case 50:
+/* rule 50 can match eol */
+YY_RULE_SETUP
+{ return EOSTMT; }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+/* Ignore */
+ YY_BREAK
+case 52:
+/* rule 52 can match eol */
+YY_RULE_SETUP
+/* Ignore line-endings preceded by \ */
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+{ return *yytext; }
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(free_fmt):
+case YY_STATE_EOF(fixed_fmt):
+case YY_STATE_EOF(str_sq):
+case YY_STATE_EOF(str_dq):
+{
+ if(!cmFortranParser_FilePop(yyextra) )
+ {
+ return YY_NULL;
+ }
+}
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+ECHO;
+ YY_BREAK
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap( yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of user's declarations */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc( (void *) b->yy_ch_buf,
+ (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = NULL;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin , yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+ (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ /* "- 2" to take care of EOB's */
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+ yy_current_state += YY_AT_BOL();
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 210 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ char *yy_cp = yyg->yy_c_buf_p;
+
+ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 210 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_is_jam = (yy_current_state == 209);
+
+ (void)yyg;
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput (int c, char * yy_bp , yyscan_t yyscanner)
+{
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yyg->yy_hold_char;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ int number_to_move = yyg->yy_n_chars + 2;
+ char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ yyg->yy_n_chars = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ yyg->yytext_ptr = yy_bp;
+ yyg->yy_hold_char = *yy_cp;
+ yyg->yy_c_buf_p = yy_cp;
+}
+
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin , yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( yyscanner ) )
+ return 0;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner);
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file , yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree( (void *) b->yy_ch_buf , yyscanner );
+
+ yyfree( (void *) b , yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_flush_buffer( b , yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return NULL;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = NULL;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b , yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner)
+{
+
+ return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = (yy_size_t) (_yybytes_len + 2);
+ buf = (char *) yyalloc( n , yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n , yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param _line_number line number
+ * @param yyscanner The scanner object.
+ */
+void yyset_lineno (int _line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
+
+ yylineno = _line_number;
+}
+
+/** Set the current column.
+ * @param _column_no column number
+ * @param yyscanner The scanner object.
+ */
+void yyset_column (int _column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_column called with no buffer" );
+
+ yycolumn = _column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param _in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * _in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = _in_str ;
+}
+
+void yyset_out (FILE * _out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = _out_str ;
+}
+
+int yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void yyset_debug (int _bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = _bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+/* User-visible API */
+
+/* yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+int yylex_init(yyscan_t* ptr_yy_globals)
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to yyalloc in
+ * the yyextra field.
+ */
+int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals )
+{
+ struct yyguts_t dummy_yyguts;
+
+ yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = NULL;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = NULL;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = NULL;
+ yyout = NULL;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ yyfree(yyg->yy_buffer_stack , yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ yyfree( yyg->yy_start_stack , yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ yyfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
+{
+ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ return malloc(size);
+}
+
+void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return realloc(ptr, size);
+}
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+/*--------------------------------------------------------------------------*/
+YY_BUFFER_STATE cmFortranLexer_GetCurrentBuffer(yyscan_t yyscanner)
+{
+ /* Hack into the internal flex-generated scanner to get the buffer. */
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return YY_CURRENT_BUFFER;
+}
+
+#endif /* __clang_analyzer__ */
diff --git a/Source/LexerParser/cmFortranLexer.h b/Source/LexerParser/cmFortranLexer.h
new file mode 100644
index 0000000..7bb9b44
--- /dev/null
+++ b/Source/LexerParser/cmFortranLexer.h
@@ -0,0 +1,691 @@
+#ifndef cmFortran_yyHEADER_H
+#define cmFortran_yyHEADER_H 1
+#define cmFortran_yyIN_HEADER 1
+
+#define FLEXINT_H 1
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmFortran_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmFortran_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmFortran_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmFortran_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmFortran_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmFortran_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmFortran_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmFortran_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmFortran_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmFortran_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmFortran_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmFortran_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmFortran_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmFortran_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmFortran_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmFortran_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmFortran_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmFortran_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmFortran_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmFortran_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmFortran_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmFortran_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmFortran_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmFortran_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmFortran_yylex_ALREADY_DEFINED
+#else
+#define yylex cmFortran_yylex
+#endif
+
+#ifdef yyrestart
+#define cmFortran_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmFortran_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmFortran_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmFortran_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmFortran_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmFortran_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmFortran_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmFortran_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmFortran_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmFortran_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmFortran_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmFortran_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmFortran_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmFortran_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmFortran_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmFortran_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmFortran_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmFortran_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmFortran_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmFortran_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmFortran_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmFortran_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmFortran_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmFortran_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmFortran_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmFortran_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmFortran_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmFortran_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmFortran_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmFortran_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmFortran_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmFortran_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmFortran_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmFortran_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmFortran_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmFortran_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmFortran_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmFortran_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmFortran_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmFortran_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmFortran_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmFortran_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmFortran_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmFortran_yyfree
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+/* Begin user sect3 */
+
+#define cmFortran_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+#define free_fmt 1
+#define fixed_fmt 2
+#define str_sq 3
+#define str_dq 4
+
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#ifndef cmFortran_yy_create_buffer_ALREADY_DEFINED
+#undef yy_create_buffer
+#endif
+#ifndef cmFortran_yy_delete_buffer_ALREADY_DEFINED
+#undef yy_delete_buffer
+#endif
+#ifndef cmFortran_yy_scan_buffer_ALREADY_DEFINED
+#undef yy_scan_buffer
+#endif
+#ifndef cmFortran_yy_scan_string_ALREADY_DEFINED
+#undef yy_scan_string
+#endif
+#ifndef cmFortran_yy_scan_bytes_ALREADY_DEFINED
+#undef yy_scan_bytes
+#endif
+#ifndef cmFortran_yy_init_buffer_ALREADY_DEFINED
+#undef yy_init_buffer
+#endif
+#ifndef cmFortran_yy_flush_buffer_ALREADY_DEFINED
+#undef yy_flush_buffer
+#endif
+#ifndef cmFortran_yy_load_buffer_state_ALREADY_DEFINED
+#undef yy_load_buffer_state
+#endif
+#ifndef cmFortran_yy_switch_to_buffer_ALREADY_DEFINED
+#undef yy_switch_to_buffer
+#endif
+#ifndef cmFortran_yypush_buffer_state_ALREADY_DEFINED
+#undef yypush_buffer_state
+#endif
+#ifndef cmFortran_yypop_buffer_state_ALREADY_DEFINED
+#undef yypop_buffer_state
+#endif
+#ifndef cmFortran_yyensure_buffer_stack_ALREADY_DEFINED
+#undef yyensure_buffer_stack
+#endif
+#ifndef cmFortran_yylex_ALREADY_DEFINED
+#undef yylex
+#endif
+#ifndef cmFortran_yyrestart_ALREADY_DEFINED
+#undef yyrestart
+#endif
+#ifndef cmFortran_yylex_init_ALREADY_DEFINED
+#undef yylex_init
+#endif
+#ifndef cmFortran_yylex_init_extra_ALREADY_DEFINED
+#undef yylex_init_extra
+#endif
+#ifndef cmFortran_yylex_destroy_ALREADY_DEFINED
+#undef yylex_destroy
+#endif
+#ifndef cmFortran_yyget_debug_ALREADY_DEFINED
+#undef yyget_debug
+#endif
+#ifndef cmFortran_yyset_debug_ALREADY_DEFINED
+#undef yyset_debug
+#endif
+#ifndef cmFortran_yyget_extra_ALREADY_DEFINED
+#undef yyget_extra
+#endif
+#ifndef cmFortran_yyset_extra_ALREADY_DEFINED
+#undef yyset_extra
+#endif
+#ifndef cmFortran_yyget_in_ALREADY_DEFINED
+#undef yyget_in
+#endif
+#ifndef cmFortran_yyset_in_ALREADY_DEFINED
+#undef yyset_in
+#endif
+#ifndef cmFortran_yyget_out_ALREADY_DEFINED
+#undef yyget_out
+#endif
+#ifndef cmFortran_yyset_out_ALREADY_DEFINED
+#undef yyset_out
+#endif
+#ifndef cmFortran_yyget_leng_ALREADY_DEFINED
+#undef yyget_leng
+#endif
+#ifndef cmFortran_yyget_text_ALREADY_DEFINED
+#undef yyget_text
+#endif
+#ifndef cmFortran_yyget_lineno_ALREADY_DEFINED
+#undef yyget_lineno
+#endif
+#ifndef cmFortran_yyset_lineno_ALREADY_DEFINED
+#undef yyset_lineno
+#endif
+#ifndef cmFortran_yyget_column_ALREADY_DEFINED
+#undef yyget_column
+#endif
+#ifndef cmFortran_yyset_column_ALREADY_DEFINED
+#undef yyset_column
+#endif
+#ifndef cmFortran_yywrap_ALREADY_DEFINED
+#undef yywrap
+#endif
+#ifndef cmFortran_yyget_lval_ALREADY_DEFINED
+#undef yyget_lval
+#endif
+#ifndef cmFortran_yyset_lval_ALREADY_DEFINED
+#undef yyset_lval
+#endif
+#ifndef cmFortran_yyget_lloc_ALREADY_DEFINED
+#undef yyget_lloc
+#endif
+#ifndef cmFortran_yyset_lloc_ALREADY_DEFINED
+#undef yyset_lloc
+#endif
+#ifndef cmFortran_yyalloc_ALREADY_DEFINED
+#undef yyalloc
+#endif
+#ifndef cmFortran_yyrealloc_ALREADY_DEFINED
+#undef yyrealloc
+#endif
+#ifndef cmFortran_yyfree_ALREADY_DEFINED
+#undef yyfree
+#endif
+#ifndef cmFortran_yytext_ALREADY_DEFINED
+#undef yytext
+#endif
+#ifndef cmFortran_yyleng_ALREADY_DEFINED
+#undef yyleng
+#endif
+#ifndef cmFortran_yyin_ALREADY_DEFINED
+#undef yyin
+#endif
+#ifndef cmFortran_yyout_ALREADY_DEFINED
+#undef yyout
+#endif
+#ifndef cmFortran_yy_flex_debug_ALREADY_DEFINED
+#undef yy_flex_debug
+#endif
+#ifndef cmFortran_yylineno_ALREADY_DEFINED
+#undef yylineno
+#endif
+#ifndef cmFortran_yytables_fload_ALREADY_DEFINED
+#undef yytables_fload
+#endif
+#ifndef cmFortran_yytables_destroy_ALREADY_DEFINED
+#undef yytables_destroy
+#endif
+#ifndef cmFortran_yyTABLES_NAME_ALREADY_DEFINED
+#undef yyTABLES_NAME
+#endif
+
+#undef cmFortran_yyIN_HEADER
+#endif /* cmFortran_yyHEADER_H */
diff --git a/Source/LexerParser/cmFortranLexer.in.l b/Source/LexerParser/cmFortranLexer.in.l
new file mode 100644
index 0000000..3d38a7d
--- /dev/null
+++ b/Source/LexerParser/cmFortranLexer.in.l
@@ -0,0 +1,189 @@
+%{
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*-------------------------------------------------------------------------
+ Portions of this source have been derived from makedepf90 version 2.8.8,
+
+ Copyright (C) 2000--2006 Erik Edelmann <erik.edelmann@iki.fi>
+
+ The code was originally distributed under the GPL but permission
+ from the copyright holder has been obtained to distribute this
+ derived work under the CMake license.
+-------------------------------------------------------------------------*/
+
+/*
+
+This file must be translated to C++ and modified to build everywhere.
+
+Run flex >= 2.6 like this:
+
+ flex -i --nounistd -DFLEXINT_H --noline --header-file=cmFortranLexer.h -ocmFortranLexer.cxx cmFortranLexer.in.l
+
+Modify cmFortranLexer.cxx:
+ - remove trailing whitespace: sed -i 's/\s*$//' cmFortranLexer.h cmFortranLexer.cxx
+ - remove blank lines at end of file: sed -i '${/^$/d;}' cmFortranLexer.h cmFortranLexer.cxx
+ - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmFortranLexer.cxx
+*/
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
+
+#undef YY_NO_UNPUT
+
+#define cmFortranLexer_cxx
+#include "cmFortranParser.h" /* Interface to parser object. */
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ do { result = cmFortranParser_Input(yyextra, buf, max_size); } while (0)
+
+/* Include the set of tokens from the parser. */
+#include "cmFortranParserTokens.h"
+
+/*--------------------------------------------------------------------------*/
+%}
+
+%option prefix="cmFortran_yy"
+
+%option reentrant
+%option noyywrap
+%pointer
+
+%s free_fmt fixed_fmt
+%x str_sq str_dq
+
+%%
+
+\" {
+ cmFortranParser_StringStart(yyextra);
+ cmFortranParser_SetOldStartcond(yyextra, YY_START);
+ BEGIN(str_dq);
+}
+
+' {
+ cmFortranParser_StringStart(yyextra);
+ cmFortranParser_SetOldStartcond(yyextra, YY_START);
+ BEGIN(str_sq);
+}
+
+<str_dq>\" |
+<str_sq>' {
+ BEGIN(cmFortranParser_GetOldStartcond(yyextra) );
+ yylvalp->string = strdup(cmFortranParser_StringEnd(yyextra));
+ return STRING;
+}
+
+<str_dq,str_sq>&[ \t]*\n |
+<str_dq,str_sq>&[ \t]*\n[ \t]*& /* Ignore (continued strings, free fmt) */
+
+<fixed_fmt,str_dq,str_sq>\n[ ]{5}[^ \t\n] {
+ if (cmFortranParser_GetOldStartcond(yyextra) == fixed_fmt)
+ ; /* Ignore (cont. strings, fixed fmt) */
+ else
+ {
+ unput(yytext[strlen(yytext)-1]);
+ }
+}
+
+
+<str_dq,str_sq>\n {
+ unput ('\n');
+ BEGIN(INITIAL);
+ return UNTERMINATED_STRING;
+}
+
+<str_sq,str_dq>. {
+ cmFortranParser_StringAppend(yyextra, yytext[0]);
+}
+
+!.*\n { return EOSTMT; } /* Treat comments like */
+<fixed_fmt>^[cC*dD].*\n { return EOSTMT; } /* empty lines */
+
+^[ \t]*#([ \t]*line)?[ \t]*[0-9]+[ \t]* { return CPP_LINE_DIRECTIVE; }
+^[ \t]*#[ \t]*include[ \t]*<[^>]+> {
+ yytext[yyleng-1] = 0;
+ yylvalp->string = strdup(strchr(yytext, '<')+1);
+ return CPP_INCLUDE_ANGLE;
+}
+^[ \t]*#[ \t]*include { return CPP_INCLUDE; }
+\$[ \t]*include { return F90PPR_INCLUDE; }
+\?\?[ \t]*include { return COCO_INCLUDE; }
+
+^[ \t]*#[ \t]*define { return CPP_DEFINE; }
+\$[ \t]*DEFINE { return F90PPR_DEFINE; }
+
+^[ \t]*#[ \t]*undef { return CPP_UNDEF; }
+\$[ \t]*UNDEF { return F90PPR_UNDEF; }
+
+^[ \t]*#[ \t]*ifdef { return CPP_IFDEF; }
+^[ \t]*#[ \t]*ifndef { return CPP_IFNDEF; }
+^[ \t]*#[ \t]*if { return CPP_IF; }
+^[ \t]*#[ \t]*elif { return CPP_ELIF; }
+^[ \t]*#[ \t]*else { return CPP_ELSE; }
+^[ \t]*#[ \t]*endif { return CPP_ENDIF; }
+
+$[ \t]*ifdef { return F90PPR_IFDEF; }
+$[ \t]*ifndef { return F90PPR_IFNDEF; }
+$[ \t]*if { return F90PPR_IF; }
+$[ \t]*elif { return F90PPR_ELIF; }
+$[ \t]*else { return F90PPR_ELSE; }
+$[ \t]*endif { return F90PPR_ENDIF; }
+
+ /* Line continuations, possible involving comments. */
+&([ \t\n]*|!.*)*
+&([ \t\n]*|!.*)*&
+
+, { return COMMA; }
+
+:: { return DCOLON; }
+: { return COLON; }
+
+<fixed_fmt>\n[ ]{5}[^ ] { return GARBAGE; }
+
+=|=> { return ASSIGNMENT_OP; }
+
+[Ee][Nn][Dd] { return END; }
+[Ii][Nn][Cc][Ll][Uu][Dd][Ee] { return INCLUDE; }
+[Ii][Nn][Tt][Ee][Rr][Ff][Aa][Cc][Ee] { return INTERFACE; }
+[Mm][Oo][Dd][Uu][Ll][Ee] { return MODULE; }
+[Ss][Uu][Bb][Mm][Oo][Dd][Uu][Ll][Ee] { return SUBMODULE; }
+[Uu][Ss][Ee] { return USE; }
+
+[a-zA-Z_][a-zA-Z_0-9]* {
+ yylvalp->string = strdup(yytext);
+ return WORD;
+}
+
+\( { return LPAREN; }
+\) { return RPAREN; }
+
+[^ \t\n\r:;,!'"a-zA-Z=&()]+ { return GARBAGE; }
+
+;|\n { return EOSTMT; }
+
+
+[ \t\r,] /* Ignore */
+\\[ \t]*\n /* Ignore line-endings preceded by \ */
+
+. { return *yytext; }
+
+<<EOF>> {
+ if(!cmFortranParser_FilePop(yyextra) )
+ {
+ return YY_NULL;
+ }
+}
+
+%%
+
+/*--------------------------------------------------------------------------*/
+YY_BUFFER_STATE cmFortranLexer_GetCurrentBuffer(yyscan_t yyscanner)
+{
+ /* Hack into the internal flex-generated scanner to get the buffer. */
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return YY_CURRENT_BUFFER;
+}
+
+#endif /* __clang_analyzer__ */
diff --git a/Source/LexerParser/cmFortranParser.cxx b/Source/LexerParser/cmFortranParser.cxx
new file mode 100644
index 0000000..dba2cac
--- /dev/null
+++ b/Source/LexerParser/cmFortranParser.cxx
@@ -0,0 +1,2078 @@
+/* A Bison parser, made by GNU Bison 3.7.4. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
+ Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+ especially those whose name start with YY_ or yy_. They are
+ private implementation details that can be changed or removed. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output, and Bison version. */
+#define YYBISON 30704
+
+/* Bison version string. */
+#define YYBISON_VERSION "3.7.4"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+/* Substitute the variable and function names. */
+#define yyparse cmFortran_yyparse
+#define yylex cmFortran_yylex
+#define yyerror cmFortran_yyerror
+#define yydebug cmFortran_yydebug
+#define yynerrs cmFortran_yynerrs
+
+/* First part of user prologue. */
+#line 1 "cmFortranParser.y"
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*-------------------------------------------------------------------------
+ Portions of this source have been derived from makedepf90 version 2.8.8,
+
+ Copyright (C) 2000--2006 Erik Edelmann <erik.edelmann@iki.fi>
+
+ The code was originally distributed under the GPL but permission
+ from the copyright holder has been obtained to distribute this
+ derived work under the CMake license.
+-------------------------------------------------------------------------*/
+
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --name-prefix=cmFortran_yy
+ --defines=cmFortranParserTokens.h
+ -ocmFortranParser.cxx
+ cmFortranParser.y
+
+*/
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmsys/String.h"
+#include <stdlib.h>
+#include <string.h>
+
+/*-------------------------------------------------------------------------*/
+#define cmFortranParser_cxx
+#include "cmFortranParser.h" /* Interface to parser object. */
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Helper function to forward error callback from parser. */
+static void cmFortran_yyerror(yyscan_t yyscanner, const char* message)
+{
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_Error(parser, message);
+}
+
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch contains default but no case. */
+# pragma warning (disable: 4701) /* Local variable may not be initialized. */
+# pragma warning (disable: 4702) /* Unreachable code. */
+# pragma warning (disable: 4127) /* Conditional expression is constant. */
+# pragma warning (disable: 4244) /* Conversion to smaller type, data loss. */
+#endif
+#if defined(__GNUC__) && __GNUC__ >= 8
+# pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+#endif
+
+#line 137 "cmFortranParser.cxx"
+
+# ifndef YY_CAST
+# ifdef __cplusplus
+# define YY_CAST(Type, Val) static_cast<Type> (Val)
+# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+# else
+# define YY_CAST(Type, Val) ((Type) (Val))
+# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+# endif
+# endif
+# ifndef YY_NULLPTR
+# if defined __cplusplus
+# if 201103L <= __cplusplus
+# define YY_NULLPTR nullptr
+# else
+# define YY_NULLPTR 0
+# endif
+# else
+# define YY_NULLPTR ((void*)0)
+# endif
+# endif
+
+#include "cmFortranParserTokens.h"
+/* Symbol kind. */
+enum yysymbol_kind_t
+{
+ YYSYMBOL_YYEMPTY = -2,
+ YYSYMBOL_YYEOF = 0, /* "end of file" */
+ YYSYMBOL_YYerror = 1, /* error */
+ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */
+ YYSYMBOL_EOSTMT = 3, /* EOSTMT */
+ YYSYMBOL_ASSIGNMENT_OP = 4, /* ASSIGNMENT_OP */
+ YYSYMBOL_GARBAGE = 5, /* GARBAGE */
+ YYSYMBOL_CPP_LINE_DIRECTIVE = 6, /* CPP_LINE_DIRECTIVE */
+ YYSYMBOL_CPP_INCLUDE = 7, /* CPP_INCLUDE */
+ YYSYMBOL_F90PPR_INCLUDE = 8, /* F90PPR_INCLUDE */
+ YYSYMBOL_COCO_INCLUDE = 9, /* COCO_INCLUDE */
+ YYSYMBOL_F90PPR_DEFINE = 10, /* F90PPR_DEFINE */
+ YYSYMBOL_CPP_DEFINE = 11, /* CPP_DEFINE */
+ YYSYMBOL_F90PPR_UNDEF = 12, /* F90PPR_UNDEF */
+ YYSYMBOL_CPP_UNDEF = 13, /* CPP_UNDEF */
+ YYSYMBOL_CPP_IFDEF = 14, /* CPP_IFDEF */
+ YYSYMBOL_CPP_IFNDEF = 15, /* CPP_IFNDEF */
+ YYSYMBOL_CPP_IF = 16, /* CPP_IF */
+ YYSYMBOL_CPP_ELSE = 17, /* CPP_ELSE */
+ YYSYMBOL_CPP_ELIF = 18, /* CPP_ELIF */
+ YYSYMBOL_CPP_ENDIF = 19, /* CPP_ENDIF */
+ YYSYMBOL_F90PPR_IFDEF = 20, /* F90PPR_IFDEF */
+ YYSYMBOL_F90PPR_IFNDEF = 21, /* F90PPR_IFNDEF */
+ YYSYMBOL_F90PPR_IF = 22, /* F90PPR_IF */
+ YYSYMBOL_F90PPR_ELSE = 23, /* F90PPR_ELSE */
+ YYSYMBOL_F90PPR_ELIF = 24, /* F90PPR_ELIF */
+ YYSYMBOL_F90PPR_ENDIF = 25, /* F90PPR_ENDIF */
+ YYSYMBOL_COMMA = 26, /* COMMA */
+ YYSYMBOL_COLON = 27, /* COLON */
+ YYSYMBOL_DCOLON = 28, /* DCOLON */
+ YYSYMBOL_LPAREN = 29, /* LPAREN */
+ YYSYMBOL_RPAREN = 30, /* RPAREN */
+ YYSYMBOL_UNTERMINATED_STRING = 31, /* UNTERMINATED_STRING */
+ YYSYMBOL_STRING = 32, /* STRING */
+ YYSYMBOL_WORD = 33, /* WORD */
+ YYSYMBOL_CPP_INCLUDE_ANGLE = 34, /* CPP_INCLUDE_ANGLE */
+ YYSYMBOL_END = 35, /* END */
+ YYSYMBOL_INCLUDE = 36, /* INCLUDE */
+ YYSYMBOL_INTERFACE = 37, /* INTERFACE */
+ YYSYMBOL_MODULE = 38, /* MODULE */
+ YYSYMBOL_SUBMODULE = 39, /* SUBMODULE */
+ YYSYMBOL_USE = 40, /* USE */
+ YYSYMBOL_YYACCEPT = 41, /* $accept */
+ YYSYMBOL_code = 42, /* code */
+ YYSYMBOL_stmt = 43, /* stmt */
+ YYSYMBOL_include = 44, /* include */
+ YYSYMBOL_define = 45, /* define */
+ YYSYMBOL_undef = 46, /* undef */
+ YYSYMBOL_ifdef = 47, /* ifdef */
+ YYSYMBOL_ifndef = 48, /* ifndef */
+ YYSYMBOL_if = 49, /* if */
+ YYSYMBOL_elif = 50, /* elif */
+ YYSYMBOL_else = 51, /* else */
+ YYSYMBOL_endif = 52, /* endif */
+ YYSYMBOL_other = 53, /* other */
+ YYSYMBOL_misc_code = 54 /* misc_code */
+};
+typedef enum yysymbol_kind_t yysymbol_kind_t;
+
+
+
+
+#ifdef short
+# undef short
+#endif
+
+/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
+ <limits.h> and (if available) <stdint.h> are included
+ so that the code can choose integer types of a good width. */
+
+#ifndef __PTRDIFF_MAX__
+# include <limits.h> /* INFRINGES ON USER NAME SPACE */
+# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+# include <stdint.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_STDINT_H
+# endif
+#endif
+
+/* Narrow types that promote to a signed type and that can represent a
+ signed or unsigned integer of at least N bits. In tables they can
+ save space and decrease cache pressure. Promoting to a signed type
+ helps avoid bugs in integer arithmetic. */
+
+#ifdef __INT_LEAST8_MAX__
+typedef __INT_LEAST8_TYPE__ yytype_int8;
+#elif defined YY_STDINT_H
+typedef int_least8_t yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef __INT_LEAST16_MAX__
+typedef __INT_LEAST16_TYPE__ yytype_int16;
+#elif defined YY_STDINT_H
+typedef int_least16_t yytype_int16;
+#else
+typedef short yytype_int16;
+#endif
+
+#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST8_TYPE__ yytype_uint8;
+#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
+ && UINT_LEAST8_MAX <= INT_MAX)
+typedef uint_least8_t yytype_uint8;
+#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
+typedef unsigned char yytype_uint8;
+#else
+typedef short yytype_uint8;
+#endif
+
+#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST16_TYPE__ yytype_uint16;
+#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
+ && UINT_LEAST16_MAX <= INT_MAX)
+typedef uint_least16_t yytype_uint16;
+#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
+typedef unsigned short yytype_uint16;
+#else
+typedef int yytype_uint16;
+#endif
+
+#ifndef YYPTRDIFF_T
+# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
+# define YYPTRDIFF_T __PTRDIFF_TYPE__
+# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
+# elif defined PTRDIFF_MAX
+# ifndef ptrdiff_t
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# endif
+# define YYPTRDIFF_T ptrdiff_t
+# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
+# else
+# define YYPTRDIFF_T long
+# define YYPTRDIFF_MAXIMUM LONG_MAX
+# endif
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM \
+ YY_CAST (YYPTRDIFF_T, \
+ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \
+ ? YYPTRDIFF_MAXIMUM \
+ : YY_CAST (YYSIZE_T, -1)))
+
+#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
+
+
+/* Stored state numbers (used for stacks). */
+typedef yytype_int8 yy_state_t;
+
+/* State numbers in computations. */
+typedef int yy_state_fast_t;
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+
+#ifndef YY_ATTRIBUTE_PURE
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+# define YY_ATTRIBUTE_PURE
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+# define YY_ATTRIBUTE_UNUSED
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END \
+ _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
+
+#define YY_ASSERT(E) ((void) (0 && (E)))
+
+#if 1
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's 'empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* 1 */
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yy_state_t yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYPTRDIFF_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / YYSIZEOF (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYPTRDIFF_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 594
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 41
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 14
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 64
+/* YYNSTATES -- Number of states. */
+#define YYNSTATES 127
+
+/* YYMAXUTOK -- Last valid token kind. */
+#define YYMAXUTOK 295
+
+
+/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex, with out-of-bounds checking. */
+#define YYTRANSLATE(YYX) \
+ (0 <= (YYX) && (YYX) <= YYMAXUTOK \
+ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \
+ : YYSYMBOL_YYUNDEF)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex. */
+static const yytype_int8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40
+};
+
+#if YYDEBUG
+ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+static const yytype_uint8 yyrline[] =
+{
+ 0, 99, 99, 99, 102, 106, 111, 120, 126, 133,
+ 138, 142, 147, 155, 160, 165, 170, 175, 180, 185,
+ 190, 195, 199, 203, 207, 211, 212, 217, 217, 217,
+ 218, 218, 219, 219, 220, 220, 221, 221, 222, 222,
+ 223, 223, 224, 224, 225, 225, 226, 226, 229, 230,
+ 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
+ 241, 242, 243, 244, 245
+};
+#endif
+
+/** Accessing symbol of state STATE. */
+#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
+
+#if 1
+/* The user-facing name of the symbol whose (internal) number is
+ YYSYMBOL. No bounds checking. */
+static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
+
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "\"end of file\"", "error", "\"invalid token\"", "EOSTMT",
+ "ASSIGNMENT_OP", "GARBAGE", "CPP_LINE_DIRECTIVE", "CPP_INCLUDE",
+ "F90PPR_INCLUDE", "COCO_INCLUDE", "F90PPR_DEFINE", "CPP_DEFINE",
+ "F90PPR_UNDEF", "CPP_UNDEF", "CPP_IFDEF", "CPP_IFNDEF", "CPP_IF",
+ "CPP_ELSE", "CPP_ELIF", "CPP_ENDIF", "F90PPR_IFDEF", "F90PPR_IFNDEF",
+ "F90PPR_IF", "F90PPR_ELSE", "F90PPR_ELIF", "F90PPR_ENDIF", "COMMA",
+ "COLON", "DCOLON", "LPAREN", "RPAREN", "UNTERMINATED_STRING", "STRING",
+ "WORD", "CPP_INCLUDE_ANGLE", "END", "INCLUDE", "INTERFACE", "MODULE",
+ "SUBMODULE", "USE", "$accept", "code", "stmt", "include", "define",
+ "undef", "ifdef", "ifndef", "if", "elif", "else", "endif", "other",
+ "misc_code", YY_NULLPTR
+};
+
+static const char *
+yysymbol_name (yysymbol_kind_t yysymbol)
+{
+ return yytname[yysymbol];
+}
+#endif
+
+#ifdef YYPRINT
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+ (internal) symbol number NUM (which must be that of a token). */
+static const yytype_int16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295
+};
+#endif
+
+#define YYPACT_NINF (-39)
+
+#define yypact_value_is_default(Yyn) \
+ ((Yyn) == YYPACT_NINF)
+
+#define YYTABLE_NINF (-1)
+
+#define yytable_value_is_error(Yyn) \
+ 0
+
+ /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+static const yytype_int16 yypact[] =
+{
+ -39, 21, -39, 1, -39, -20, -39, -39, -39, -39,
+ -39, -39, -39, -39, -39, -39, -39, -39, -39, -39,
+ -39, -39, -39, -39, -39, -39, -24, -18, 20, -8,
+ -3, 40, -39, 15, 16, 17, 19, 34, -39, -39,
+ -39, -39, -39, -39, 59, -39, -39, -39, -39, -39,
+ 36, 37, 38, -39, -39, -39, -39, -39, -39, 77,
+ 115, 130, 168, 183, -39, -39, -39, -39, -39, -39,
+ -39, -39, -39, -39, -39, -39, -39, -39, -39, -39,
+ -39, -39, -39, 221, 236, 274, 289, -21, 26, -39,
+ 327, 342, 380, 395, 433, 448, -39, -39, -39, -39,
+ -39, -39, -39, -39, -39, 39, 41, 42, 486, -39,
+ -39, -39, -39, -39, -39, 18, -39, -39, -39, 43,
+ 501, 539, -39, -39, -39, 554, -39
+};
+
+ /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE does not specify something else to do. Zero
+ means the default is an error. */
+static const yytype_int8 yydefact[] =
+{
+ 2, 0, 1, 0, 25, 0, 27, 28, 29, 31,
+ 30, 33, 32, 34, 36, 38, 42, 40, 44, 35,
+ 37, 39, 43, 41, 45, 46, 0, 0, 0, 0,
+ 0, 0, 3, 0, 0, 0, 0, 0, 46, 46,
+ 46, 46, 26, 46, 0, 46, 46, 4, 46, 46,
+ 0, 0, 0, 46, 46, 46, 46, 46, 46, 0,
+ 0, 0, 0, 0, 15, 57, 56, 64, 62, 58,
+ 59, 60, 61, 63, 55, 48, 49, 50, 51, 52,
+ 53, 54, 47, 0, 0, 0, 0, 0, 0, 46,
+ 0, 0, 0, 0, 0, 0, 21, 22, 23, 24,
+ 14, 10, 13, 9, 6, 0, 0, 0, 0, 5,
+ 16, 17, 18, 19, 20, 0, 46, 46, 11, 0,
+ 0, 0, 46, 7, 12, 0, 8
+};
+
+ /* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -39, -39, -39, -39, -39, -39, -39, -39, -39, -39,
+ -39, -39, -38, -39
+};
+
+ /* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 1, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 44, 82
+};
+
+ /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule whose
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+static const yytype_int8 yytable[] =
+{
+ 59, 60, 61, 62, 42, 63, 105, 83, 84, 106,
+ 85, 86, 43, 45, 46, 90, 91, 92, 93, 94,
+ 95, 2, 3, 47, 4, 49, 50, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 54, 119, 55,
+ 56, 108, 57, 48, 107, 25, 26, 27, 28, 29,
+ 30, 31, 64, 65, 66, 67, 51, 58, 52, 87,
+ 88, 89, 115, 53, 116, 117, 122, 0, 120, 121,
+ 96, 65, 66, 67, 125, 68, 69, 70, 71, 72,
+ 73, 74, 75, 0, 76, 77, 78, 79, 80, 81,
+ 0, 0, 0, 68, 69, 70, 71, 72, 73, 74,
+ 75, 0, 76, 77, 78, 79, 80, 81, 97, 65,
+ 66, 67, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 98, 65, 66, 67, 0, 0, 0,
+ 0, 68, 69, 70, 71, 72, 73, 74, 75, 0,
+ 76, 77, 78, 79, 80, 81, 68, 69, 70, 71,
+ 72, 73, 74, 75, 0, 76, 77, 78, 79, 80,
+ 81, 99, 65, 66, 67, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 100, 65, 66, 67,
+ 0, 0, 0, 0, 68, 69, 70, 71, 72, 73,
+ 74, 75, 0, 76, 77, 78, 79, 80, 81, 68,
+ 69, 70, 71, 72, 73, 74, 75, 0, 76, 77,
+ 78, 79, 80, 81, 101, 65, 66, 67, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 102,
+ 65, 66, 67, 0, 0, 0, 0, 68, 69, 70,
+ 71, 72, 73, 74, 75, 0, 76, 77, 78, 79,
+ 80, 81, 68, 69, 70, 71, 72, 73, 74, 75,
+ 0, 76, 77, 78, 79, 80, 81, 103, 65, 66,
+ 67, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 104, 65, 66, 67, 0, 0, 0, 0,
+ 68, 69, 70, 71, 72, 73, 74, 75, 0, 76,
+ 77, 78, 79, 80, 81, 68, 69, 70, 71, 72,
+ 73, 74, 75, 0, 76, 77, 78, 79, 80, 81,
+ 109, 65, 66, 67, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 110, 65, 66, 67, 0,
+ 0, 0, 0, 68, 69, 70, 71, 72, 73, 74,
+ 75, 0, 76, 77, 78, 79, 80, 81, 68, 69,
+ 70, 71, 72, 73, 74, 75, 0, 76, 77, 78,
+ 79, 80, 81, 111, 65, 66, 67, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 112, 65,
+ 66, 67, 0, 0, 0, 0, 68, 69, 70, 71,
+ 72, 73, 74, 75, 0, 76, 77, 78, 79, 80,
+ 81, 68, 69, 70, 71, 72, 73, 74, 75, 0,
+ 76, 77, 78, 79, 80, 81, 113, 65, 66, 67,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 114, 65, 66, 67, 0, 0, 0, 0, 68,
+ 69, 70, 71, 72, 73, 74, 75, 0, 76, 77,
+ 78, 79, 80, 81, 68, 69, 70, 71, 72, 73,
+ 74, 75, 0, 76, 77, 78, 79, 80, 81, 118,
+ 65, 66, 67, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 123, 65, 66, 67, 0, 0,
+ 0, 0, 68, 69, 70, 71, 72, 73, 74, 75,
+ 0, 76, 77, 78, 79, 80, 81, 68, 69, 70,
+ 71, 72, 73, 74, 75, 0, 76, 77, 78, 79,
+ 80, 81, 124, 65, 66, 67, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 126, 65, 66,
+ 67, 0, 0, 0, 0, 68, 69, 70, 71, 72,
+ 73, 74, 75, 0, 76, 77, 78, 79, 80, 81,
+ 68, 69, 70, 71, 72, 73, 74, 75, 0, 76,
+ 77, 78, 79, 80, 81
+};
+
+static const yytype_int8 yycheck[] =
+{
+ 38, 39, 40, 41, 3, 43, 27, 45, 46, 30,
+ 48, 49, 32, 37, 32, 53, 54, 55, 56, 57,
+ 58, 0, 1, 3, 3, 33, 29, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 32, 30, 33,
+ 33, 89, 33, 33, 28, 34, 35, 36, 37, 38,
+ 39, 40, 3, 4, 5, 6, 26, 33, 28, 33,
+ 33, 33, 33, 33, 33, 33, 33, -1, 116, 117,
+ 3, 4, 5, 6, 122, 26, 27, 28, 29, 30,
+ 31, 32, 33, -1, 35, 36, 37, 38, 39, 40,
+ -1, -1, -1, 26, 27, 28, 29, 30, 31, 32,
+ 33, -1, 35, 36, 37, 38, 39, 40, 3, 4,
+ 5, 6, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 3, 4, 5, 6, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, -1,
+ 35, 36, 37, 38, 39, 40, 26, 27, 28, 29,
+ 30, 31, 32, 33, -1, 35, 36, 37, 38, 39,
+ 40, 3, 4, 5, 6, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 3, 4, 5, 6,
+ -1, -1, -1, -1, 26, 27, 28, 29, 30, 31,
+ 32, 33, -1, 35, 36, 37, 38, 39, 40, 26,
+ 27, 28, 29, 30, 31, 32, 33, -1, 35, 36,
+ 37, 38, 39, 40, 3, 4, 5, 6, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 3,
+ 4, 5, 6, -1, -1, -1, -1, 26, 27, 28,
+ 29, 30, 31, 32, 33, -1, 35, 36, 37, 38,
+ 39, 40, 26, 27, 28, 29, 30, 31, 32, 33,
+ -1, 35, 36, 37, 38, 39, 40, 3, 4, 5,
+ 6, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 3, 4, 5, 6, -1, -1, -1, -1,
+ 26, 27, 28, 29, 30, 31, 32, 33, -1, 35,
+ 36, 37, 38, 39, 40, 26, 27, 28, 29, 30,
+ 31, 32, 33, -1, 35, 36, 37, 38, 39, 40,
+ 3, 4, 5, 6, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 3, 4, 5, 6, -1,
+ -1, -1, -1, 26, 27, 28, 29, 30, 31, 32,
+ 33, -1, 35, 36, 37, 38, 39, 40, 26, 27,
+ 28, 29, 30, 31, 32, 33, -1, 35, 36, 37,
+ 38, 39, 40, 3, 4, 5, 6, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 3, 4,
+ 5, 6, -1, -1, -1, -1, 26, 27, 28, 29,
+ 30, 31, 32, 33, -1, 35, 36, 37, 38, 39,
+ 40, 26, 27, 28, 29, 30, 31, 32, 33, -1,
+ 35, 36, 37, 38, 39, 40, 3, 4, 5, 6,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 3, 4, 5, 6, -1, -1, -1, -1, 26,
+ 27, 28, 29, 30, 31, 32, 33, -1, 35, 36,
+ 37, 38, 39, 40, 26, 27, 28, 29, 30, 31,
+ 32, 33, -1, 35, 36, 37, 38, 39, 40, 3,
+ 4, 5, 6, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 3, 4, 5, 6, -1, -1,
+ -1, -1, 26, 27, 28, 29, 30, 31, 32, 33,
+ -1, 35, 36, 37, 38, 39, 40, 26, 27, 28,
+ 29, 30, 31, 32, 33, -1, 35, 36, 37, 38,
+ 39, 40, 3, 4, 5, 6, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 3, 4, 5,
+ 6, -1, -1, -1, -1, 26, 27, 28, 29, 30,
+ 31, 32, 33, -1, 35, 36, 37, 38, 39, 40,
+ 26, 27, 28, 29, 30, 31, 32, 33, -1, 35,
+ 36, 37, 38, 39, 40
+};
+
+ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_int8 yystos[] =
+{
+ 0, 42, 0, 1, 3, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 34, 35, 36, 37, 38,
+ 39, 40, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 3, 32, 53, 37, 32, 3, 33, 33,
+ 29, 26, 28, 33, 32, 33, 33, 33, 33, 53,
+ 53, 53, 53, 53, 3, 4, 5, 6, 26, 27,
+ 28, 29, 30, 31, 32, 33, 35, 36, 37, 38,
+ 39, 40, 54, 53, 53, 53, 53, 33, 33, 33,
+ 53, 53, 53, 53, 53, 53, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 27, 30, 28, 53, 3,
+ 3, 3, 3, 3, 3, 33, 33, 33, 3, 30,
+ 53, 53, 33, 3, 3, 53, 3
+};
+
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_int8 yyr1[] =
+{
+ 0, 41, 42, 42, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 44, 44, 44,
+ 45, 45, 46, 46, 47, 47, 48, 48, 49, 49,
+ 50, 50, 51, 51, 52, 52, 53, 53, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54
+};
+
+ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
+static const yytype_int8 yyr2[] =
+{
+ 0, 2, 0, 2, 2, 4, 4, 7, 9, 4,
+ 4, 5, 7, 4, 4, 3, 4, 4, 4, 4,
+ 4, 3, 3, 3, 3, 1, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 0, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+};
+
+
+enum { YYENOMEM = -2 };
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+ do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (yyscanner, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+ while (0)
+
+/* Backward compatibility with an undocumented macro.
+ Use YYerror or YYUNDEF. */
+#define YYERRCODE YYUNDEF
+
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+/* This macro is provided for backward compatibility. */
+# ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+
+
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Kind, Value, yyscanner); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+
+/*-----------------------------------.
+| Print this symbol's value on YYO. |
+`-----------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyo,
+ yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+{
+ FILE *yyoutput = yyo;
+ YYUSE (yyoutput);
+ YYUSE (yyscanner);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yykind < YYNTOKENS)
+ YYPRINT (yyo, yytoknum[yykind], *yyvaluep);
+# endif
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ YYUSE (yykind);
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+/*---------------------------.
+| Print this symbol on YYO. |
+`---------------------------*/
+
+static void
+yy_symbol_print (FILE *yyo,
+ yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+{
+ YYFPRINTF (yyo, "%s %s (",
+ yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
+
+ yy_symbol_value_print (yyo, yykind, yyvaluep, yyscanner);
+ YYFPRINTF (yyo, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop)
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp,
+ int yyrule, yyscan_t yyscanner)
+{
+ int yylno = yyrline[yyrule];
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr,
+ YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
+ &yyvsp[(yyi + 1) - (yynrhs)], yyscanner);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyssp, yyvsp, Rule, yyscanner); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args) ((void) 0)
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+/* Context of a parse error. */
+typedef struct
+{
+ yy_state_t *yyssp;
+ yysymbol_kind_t yytoken;
+} yypcontext_t;
+
+/* Put in YYARG at most YYARGN of the expected tokens given the
+ current YYCTX, and return the number of tokens stored in YYARG. If
+ YYARG is null, return the number of expected tokens (guaranteed to
+ be less than YYNTOKENS). Return YYENOMEM on memory exhaustion.
+ Return 0 if there are more than YYARGN expected tokens, yet fill
+ YYARG up to YYARGN. */
+static int
+yypcontext_expected_tokens (const yypcontext_t *yyctx,
+ yysymbol_kind_t yyarg[], int yyargn)
+{
+ /* Actual size of YYARG. */
+ int yycount = 0;
+ int yyn = yypact[+*yyctx->yyssp];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (!yyarg)
+ ++yycount;
+ else if (yycount == yyargn)
+ return 0;
+ else
+ yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx);
+ }
+ }
+ if (yyarg && yycount == 0 && 0 < yyargn)
+ yyarg[0] = YYSYMBOL_YYEMPTY;
+ return yycount;
+}
+
+
+
+
+#ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S)))
+# else
+/* Return the length of YYSTR. */
+static YYPTRDIFF_T
+yystrlen (const char *yystr)
+{
+ YYPTRDIFF_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+#endif
+
+#ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+#endif
+
+#ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYPTRDIFF_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYPTRDIFF_T yyn = 0;
+ char const *yyp = yystr;
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ else
+ goto append;
+
+ append:
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (yyres)
+ return yystpcpy (yyres, yystr) - yyres;
+ else
+ return yystrlen (yystr);
+}
+#endif
+
+
+static int
+yy_syntax_error_arguments (const yypcontext_t *yyctx,
+ yysymbol_kind_t yyarg[], int yyargn)
+{
+ /* Actual size of YYARG. */
+ int yycount = 0;
+ /* There are many possibilities here to consider:
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yyctx->yytoken != YYSYMBOL_YYEMPTY)
+ {
+ int yyn;
+ if (yyarg)
+ yyarg[yycount] = yyctx->yytoken;
+ ++yycount;
+ yyn = yypcontext_expected_tokens (yyctx,
+ yyarg ? yyarg + 1 : yyarg, yyargn - 1);
+ if (yyn == YYENOMEM)
+ return YYENOMEM;
+ else
+ yycount += yyn;
+ }
+ return yycount;
+}
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg,
+ const yypcontext_t *yyctx)
+{
+ enum { YYARGS_MAX = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULLPTR;
+ /* Arguments of yyformat: reported tokens (one for the "unexpected",
+ one per "expected"). */
+ yysymbol_kind_t yyarg[YYARGS_MAX];
+ /* Cumulated lengths of YYARG. */
+ YYPTRDIFF_T yysize = 0;
+
+ /* Actual size of YYARG. */
+ int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX);
+ if (yycount == YYENOMEM)
+ return YYENOMEM;
+
+ switch (yycount)
+ {
+#define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ default: /* Avoid compiler warnings. */
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+#undef YYCASE_
+ }
+
+ /* Compute error message size. Don't count the "%s"s, but reserve
+ room for the terminator. */
+ yysize = yystrlen (yyformat) - 2 * yycount + 1;
+ {
+ int yyi;
+ for (yyi = 0; yyi < yycount; ++yyi)
+ {
+ YYPTRDIFF_T yysize1
+ = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]);
+ if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
+ yysize = yysize1;
+ else
+ return YYENOMEM;
+ }
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return -1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]);
+ yyformat += 2;
+ }
+ else
+ {
+ ++yyp;
+ ++yyformat;
+ }
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg,
+ yysymbol_kind_t yykind, YYSTYPE *yyvaluep, yyscan_t yyscanner)
+{
+ YYUSE (yyvaluep);
+ YYUSE (yyscanner);
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ YYUSE (yykind);
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+int
+yyparse (yyscan_t yyscanner)
+{
+/* Lookahead token kind. */
+int yychar;
+
+
+/* The semantic value of the lookahead symbol. */
+/* Default value used for initialization, for pacifying older GCCs
+ or non-GCC compilers. */
+YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
+YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
+
+ /* Number of syntax errors so far. */
+ int yynerrs = 0;
+
+ yy_state_fast_t yystate = 0;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus = 0;
+
+ /* Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* Their size. */
+ YYPTRDIFF_T yystacksize = YYINITDEPTH;
+
+ /* The state stack: array, bottom, top. */
+ yy_state_t yyssa[YYINITDEPTH];
+ yy_state_t *yyss = yyssa;
+ yy_state_t *yyssp = yyss;
+
+ /* The semantic value stack: array, bottom, top. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp = yyvs;
+
+ int yyn;
+ /* The return value of yyparse. */
+ int yyresult;
+ /* Lookahead symbol kind. */
+ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf;
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ goto yysetstate;
+
+
+/*------------------------------------------------------------.
+| yynewstate -- push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+
+/*--------------------------------------------------------------------.
+| yysetstate -- set current state (the top of the stack) to yystate. |
+`--------------------------------------------------------------------*/
+yysetstate:
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+ YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
+ YY_IGNORE_USELESS_CAST_BEGIN
+ *yyssp = YY_CAST (yy_state_t, yystate);
+ YY_IGNORE_USELESS_CAST_END
+ YY_STACK_PRINT (yyss, yyssp);
+
+ if (yyss + yystacksize - 1 <= yyssp)
+#if !defined yyoverflow && !defined YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+#else
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYPTRDIFF_T yysize = yyssp - yyss + 1;
+
+# if defined yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ yy_state_t *yyss1 = yyss;
+ YYSTYPE *yyvs1 = yyvs;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * YYSIZEOF (*yyssp),
+ &yyvs1, yysize * YYSIZEOF (*yyvsp),
+ &yystacksize);
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+# else /* defined YYSTACK_RELOCATE */
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yy_state_t *yyss1 = yyss;
+ union yyalloc *yyptr =
+ YY_CAST (union yyalloc *,
+ YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YY_IGNORE_USELESS_CAST_BEGIN
+ YYDPRINTF ((stderr, "Stack size increased to %ld\n",
+ YY_CAST (long, yystacksize)));
+ YY_IGNORE_USELESS_CAST_END
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token\n"));
+ yychar = yylex (&yylval, yyscanner);
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = YYEOF;
+ yytoken = YYSYMBOL_YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else if (yychar == YYerror)
+ {
+ /* The scanner already issued an error message, process directly
+ to error recovery. But do not keep the error token as
+ lookahead, it is too special and may lead us to an endless
+ loop in error recovery. */
+ yychar = YYUNDEF;
+ yytoken = YYSYMBOL_YYerror;
+ goto yyerrlab1;
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ '$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4: /* stmt: INTERFACE EOSTMT */
+#line 102 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_SetInInterface(parser, true);
+ }
+#line 1631 "cmFortranParser.cxx"
+ break;
+
+ case 5: /* stmt: USE WORD other EOSTMT */
+#line 106 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1641 "cmFortranParser.cxx"
+ break;
+
+ case 6: /* stmt: MODULE WORD other EOSTMT */
+#line 111 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ if (cmsysString_strcasecmp((yyvsp[-2].string), "function") != 0 &&
+ cmsysString_strcasecmp((yyvsp[-2].string), "procedure") != 0 &&
+ cmsysString_strcasecmp((yyvsp[-2].string), "subroutine") != 0) {
+ cmFortranParser_RuleModule(parser, (yyvsp[-2].string));
+ }
+ free((yyvsp[-2].string));
+ }
+#line 1655 "cmFortranParser.cxx"
+ break;
+
+ case 7: /* stmt: SUBMODULE LPAREN WORD RPAREN WORD other EOSTMT */
+#line 120 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleSubmodule(parser, (yyvsp[-4].string), (yyvsp[-2].string));
+ free((yyvsp[-4].string));
+ free((yyvsp[-2].string));
+ }
+#line 1666 "cmFortranParser.cxx"
+ break;
+
+ case 8: /* stmt: SUBMODULE LPAREN WORD COLON WORD RPAREN WORD other EOSTMT */
+#line 126 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleSubmoduleNested(parser, (yyvsp[-6].string), (yyvsp[-4].string), (yyvsp[-2].string));
+ free((yyvsp[-6].string));
+ free((yyvsp[-4].string));
+ free((yyvsp[-2].string));
+ }
+#line 1678 "cmFortranParser.cxx"
+ break;
+
+ case 9: /* stmt: INTERFACE WORD other EOSTMT */
+#line 133 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_SetInInterface(parser, true);
+ free((yyvsp[-2].string));
+ }
+#line 1688 "cmFortranParser.cxx"
+ break;
+
+ case 10: /* stmt: END INTERFACE other EOSTMT */
+#line 138 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_SetInInterface(parser, false);
+ }
+#line 1697 "cmFortranParser.cxx"
+ break;
+
+ case 11: /* stmt: USE DCOLON WORD other EOSTMT */
+#line 142 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1707 "cmFortranParser.cxx"
+ break;
+
+ case 12: /* stmt: USE COMMA WORD DCOLON WORD other EOSTMT */
+#line 147 "cmFortranParser.y"
+ {
+ if (cmsysString_strcasecmp((yyvsp[-4].string), "non_intrinsic") == 0) {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
+ }
+ free((yyvsp[-4].string));
+ free((yyvsp[-2].string));
+ }
+#line 1720 "cmFortranParser.cxx"
+ break;
+
+ case 13: /* stmt: INCLUDE STRING other EOSTMT */
+#line 155 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1730 "cmFortranParser.cxx"
+ break;
+
+ case 14: /* stmt: CPP_LINE_DIRECTIVE STRING other EOSTMT */
+#line 160 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleLineDirective(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1740 "cmFortranParser.cxx"
+ break;
+
+ case 15: /* stmt: CPP_INCLUDE_ANGLE other EOSTMT */
+#line 165 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1750 "cmFortranParser.cxx"
+ break;
+
+ case 16: /* stmt: include STRING other EOSTMT */
+#line 170 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1760 "cmFortranParser.cxx"
+ break;
+
+ case 17: /* stmt: define WORD other EOSTMT */
+#line 175 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleDefine(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1770 "cmFortranParser.cxx"
+ break;
+
+ case 18: /* stmt: undef WORD other EOSTMT */
+#line 180 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUndef(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1780 "cmFortranParser.cxx"
+ break;
+
+ case 19: /* stmt: ifdef WORD other EOSTMT */
+#line 185 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleIfdef(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1790 "cmFortranParser.cxx"
+ break;
+
+ case 20: /* stmt: ifndef WORD other EOSTMT */
+#line 190 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleIfndef(parser, (yyvsp[-2].string));
+ free((yyvsp[-2].string));
+ }
+#line 1800 "cmFortranParser.cxx"
+ break;
+
+ case 21: /* stmt: if other EOSTMT */
+#line 195 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleIf(parser);
+ }
+#line 1809 "cmFortranParser.cxx"
+ break;
+
+ case 22: /* stmt: elif other EOSTMT */
+#line 199 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleElif(parser);
+ }
+#line 1818 "cmFortranParser.cxx"
+ break;
+
+ case 23: /* stmt: else other EOSTMT */
+#line 203 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleElse(parser);
+ }
+#line 1827 "cmFortranParser.cxx"
+ break;
+
+ case 24: /* stmt: endif other EOSTMT */
+#line 207 "cmFortranParser.y"
+ {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleEndif(parser);
+ }
+#line 1836 "cmFortranParser.cxx"
+ break;
+
+ case 48: /* misc_code: WORD */
+#line 229 "cmFortranParser.y"
+ { free ((yyvsp[0].string)); }
+#line 1842 "cmFortranParser.cxx"
+ break;
+
+ case 55: /* misc_code: STRING */
+#line 236 "cmFortranParser.y"
+ { free ((yyvsp[0].string)); }
+#line 1848 "cmFortranParser.cxx"
+ break;
+
+
+#line 1852 "cmFortranParser.cxx"
+
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+
+ *++yyvsp = yyval;
+
+ /* Now 'shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+ {
+ const int yylhs = yyr1[yyn] - YYNTOKENS;
+ const int yyi = yypgoto[yylhs] + *yyssp;
+ yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp
+ ? yytable[yyi]
+ : yydefgoto[yylhs]);
+ }
+
+ goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error. |
+`--------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+ {
+ yypcontext_t yyctx
+ = {yyssp, yytoken};
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == -1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = YY_CAST (char *,
+ YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc)));
+ if (yymsg)
+ {
+ yysyntax_error_status
+ = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+ yymsgp = yymsg;
+ }
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = YYENOMEM;
+ }
+ }
+ yyerror (yyscanner, yymsgp);
+ if (yysyntax_error_status == YYENOMEM)
+ goto yyexhaustedlab;
+ }
+ }
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, yyscanner);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+ /* Pacify compilers when the user code never invokes YYERROR and the
+ label yyerrorlab therefore never appears in user code. */
+ if (0)
+ YYERROR;
+
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ /* Pop stack until we find a state that shifts the error token. */
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYSYMBOL_YYerror;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ YY_ACCESSING_SYMBOL (yystate), yyvsp, yyscanner);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+
+#if 1
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (yyscanner, YY_("memory exhausted"));
+ yyresult = 2;
+ goto yyreturn;
+#endif
+
+
+/*-------------------------------------------------------.
+| yyreturn -- parsing is finished, clean up and return. |
+`-------------------------------------------------------*/
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, yyscanner);
+ }
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yyscanner);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ return yyresult;
+}
+
+#line 248 "cmFortranParser.y"
+
+/* End of grammar */
diff --git a/Source/LexerParser/cmFortranParser.y b/Source/LexerParser/cmFortranParser.y
new file mode 100644
index 0000000..e461160
--- /dev/null
+++ b/Source/LexerParser/cmFortranParser.y
@@ -0,0 +1,249 @@
+%{
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*-------------------------------------------------------------------------
+ Portions of this source have been derived from makedepf90 version 2.8.8,
+
+ Copyright (C) 2000--2006 Erik Edelmann <erik.edelmann@iki.fi>
+
+ The code was originally distributed under the GPL but permission
+ from the copyright holder has been obtained to distribute this
+ derived work under the CMake license.
+-------------------------------------------------------------------------*/
+
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run bison like this:
+
+ bison --name-prefix=cmFortran_yy
+ --defines=cmFortranParserTokens.h
+ -ocmFortranParser.cxx
+ cmFortranParser.y
+
+*/
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmsys/String.h"
+#include <stdlib.h>
+#include <string.h>
+
+/*-------------------------------------------------------------------------*/
+#define cmFortranParser_cxx
+#include "cmFortranParser.h" /* Interface to parser object. */
+
+/* Forward declare the lexer entry point. */
+YY_DECL;
+
+/* Helper function to forward error callback from parser. */
+static void cmFortran_yyerror(yyscan_t yyscanner, const char* message)
+{
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_Error(parser, message);
+}
+
+/* Disable some warnings in the generated code. */
+#ifdef _MSC_VER
+# pragma warning (disable: 4102) /* Unused goto label. */
+# pragma warning (disable: 4065) /* Switch contains default but no case. */
+# pragma warning (disable: 4701) /* Local variable may not be initialized. */
+# pragma warning (disable: 4702) /* Unreachable code. */
+# pragma warning (disable: 4127) /* Conditional expression is constant. */
+# pragma warning (disable: 4244) /* Conversion to smaller type, data loss. */
+#endif
+#if defined(__GNUC__) && __GNUC__ >= 8
+# pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+#endif
+%}
+
+/* Generate a reentrant parser object. */
+%define api.pure
+
+/* Configure the parser to use a lexer object. */
+%lex-param {yyscan_t yyscanner}
+%parse-param {yyscan_t yyscanner}
+
+%define parse.error verbose
+
+%union {
+ char* string;
+}
+
+/*-------------------------------------------------------------------------*/
+/* Tokens */
+%token EOSTMT ASSIGNMENT_OP GARBAGE
+%token CPP_LINE_DIRECTIVE
+%token CPP_INCLUDE F90PPR_INCLUDE COCO_INCLUDE
+%token F90PPR_DEFINE CPP_DEFINE F90PPR_UNDEF CPP_UNDEF
+%token CPP_IFDEF CPP_IFNDEF CPP_IF CPP_ELSE CPP_ELIF CPP_ENDIF
+%token F90PPR_IFDEF F90PPR_IFNDEF F90PPR_IF
+%token F90PPR_ELSE F90PPR_ELIF F90PPR_ENDIF
+%token COMMA COLON DCOLON LPAREN RPAREN
+%token <number> UNTERMINATED_STRING
+%token <string> STRING WORD
+%token <string> CPP_INCLUDE_ANGLE
+%token END
+%token INCLUDE
+%token INTERFACE
+%token MODULE
+%token SUBMODULE
+%token USE
+
+/*-------------------------------------------------------------------------*/
+/* grammar */
+%%
+
+code: /* empty */ | code stmt;
+
+stmt:
+ INTERFACE EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_SetInInterface(parser, true);
+ }
+| USE WORD other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUse(parser, $2);
+ free($2);
+ }
+| MODULE WORD other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ if (cmsysString_strcasecmp($2, "function") != 0 &&
+ cmsysString_strcasecmp($2, "procedure") != 0 &&
+ cmsysString_strcasecmp($2, "subroutine") != 0) {
+ cmFortranParser_RuleModule(parser, $2);
+ }
+ free($2);
+ }
+| SUBMODULE LPAREN WORD RPAREN WORD other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleSubmodule(parser, $3, $5);
+ free($3);
+ free($5);
+ }
+| SUBMODULE LPAREN WORD COLON WORD RPAREN WORD other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleSubmoduleNested(parser, $3, $5, $7);
+ free($3);
+ free($5);
+ free($7);
+ }
+| INTERFACE WORD other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_SetInInterface(parser, true);
+ free($2);
+ }
+| END INTERFACE other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_SetInInterface(parser, false);
+ }
+| USE DCOLON WORD other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUse(parser, $3);
+ free($3);
+ }
+| USE COMMA WORD DCOLON WORD other EOSTMT {
+ if (cmsysString_strcasecmp($3, "non_intrinsic") == 0) {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUse(parser, $5);
+ }
+ free($3);
+ free($5);
+ }
+| INCLUDE STRING other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleInclude(parser, $2);
+ free($2);
+ }
+| CPP_LINE_DIRECTIVE STRING other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleLineDirective(parser, $2);
+ free($2);
+ }
+| CPP_INCLUDE_ANGLE other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleInclude(parser, $1);
+ free($1);
+ }
+| include STRING other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleInclude(parser, $2);
+ free($2);
+ }
+| define WORD other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleDefine(parser, $2);
+ free($2);
+ }
+| undef WORD other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleUndef(parser, $2);
+ free($2);
+ }
+| ifdef WORD other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleIfdef(parser, $2);
+ free($2);
+ }
+| ifndef WORD other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleIfndef(parser, $2);
+ free($2);
+ }
+| if other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleIf(parser);
+ }
+| elif other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleElif(parser);
+ }
+| else other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleElse(parser);
+ }
+| endif other EOSTMT {
+ cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+ cmFortranParser_RuleEndif(parser);
+ }
+| EOSTMT
+| error EOSTMT /* tolerate unknown statements until their end */
+;
+
+
+
+include: CPP_INCLUDE | F90PPR_INCLUDE | COCO_INCLUDE ;
+define: CPP_DEFINE | F90PPR_DEFINE;
+undef: CPP_UNDEF | F90PPR_UNDEF ;
+ifdef: CPP_IFDEF | F90PPR_IFDEF ;
+ifndef: CPP_IFNDEF | F90PPR_IFNDEF ;
+if: CPP_IF | F90PPR_IF ;
+elif: CPP_ELIF | F90PPR_ELIF ;
+else: CPP_ELSE | F90PPR_ELSE ;
+endif: CPP_ENDIF | F90PPR_ENDIF ;
+other: /* empty */ | other misc_code ;
+
+misc_code:
+ WORD { free ($1); }
+| END
+| INCLUDE
+| INTERFACE
+| MODULE
+| SUBMODULE
+| USE
+| STRING { free ($1); }
+| GARBAGE
+| ASSIGNMENT_OP
+| COLON
+| DCOLON
+| LPAREN
+| RPAREN
+| COMMA
+| UNTERMINATED_STRING
+| CPP_LINE_DIRECTIVE
+;
+
+%%
+/* End of grammar */
diff --git a/Source/LexerParser/cmFortranParserTokens.h b/Source/LexerParser/cmFortranParserTokens.h
new file mode 100644
index 0000000..e250110
--- /dev/null
+++ b/Source/LexerParser/cmFortranParserTokens.h
@@ -0,0 +1,119 @@
+/* A Bison parser, made by GNU Bison 3.7.4. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
+ Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+ especially those whose name start with YY_ or yy_. They are
+ private implementation details that can be changed or removed. */
+
+#ifndef YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED
+# define YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int cmFortran_yydebug;
+#endif
+
+/* Token kinds. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ YYEMPTY = -2,
+ YYEOF = 0, /* "end of file" */
+ YYerror = 256, /* error */
+ YYUNDEF = 257, /* "invalid token" */
+ EOSTMT = 258, /* EOSTMT */
+ ASSIGNMENT_OP = 259, /* ASSIGNMENT_OP */
+ GARBAGE = 260, /* GARBAGE */
+ CPP_LINE_DIRECTIVE = 261, /* CPP_LINE_DIRECTIVE */
+ CPP_INCLUDE = 262, /* CPP_INCLUDE */
+ F90PPR_INCLUDE = 263, /* F90PPR_INCLUDE */
+ COCO_INCLUDE = 264, /* COCO_INCLUDE */
+ F90PPR_DEFINE = 265, /* F90PPR_DEFINE */
+ CPP_DEFINE = 266, /* CPP_DEFINE */
+ F90PPR_UNDEF = 267, /* F90PPR_UNDEF */
+ CPP_UNDEF = 268, /* CPP_UNDEF */
+ CPP_IFDEF = 269, /* CPP_IFDEF */
+ CPP_IFNDEF = 270, /* CPP_IFNDEF */
+ CPP_IF = 271, /* CPP_IF */
+ CPP_ELSE = 272, /* CPP_ELSE */
+ CPP_ELIF = 273, /* CPP_ELIF */
+ CPP_ENDIF = 274, /* CPP_ENDIF */
+ F90PPR_IFDEF = 275, /* F90PPR_IFDEF */
+ F90PPR_IFNDEF = 276, /* F90PPR_IFNDEF */
+ F90PPR_IF = 277, /* F90PPR_IF */
+ F90PPR_ELSE = 278, /* F90PPR_ELSE */
+ F90PPR_ELIF = 279, /* F90PPR_ELIF */
+ F90PPR_ENDIF = 280, /* F90PPR_ENDIF */
+ COMMA = 281, /* COMMA */
+ COLON = 282, /* COLON */
+ DCOLON = 283, /* DCOLON */
+ LPAREN = 284, /* LPAREN */
+ RPAREN = 285, /* RPAREN */
+ UNTERMINATED_STRING = 286, /* UNTERMINATED_STRING */
+ STRING = 287, /* STRING */
+ WORD = 288, /* WORD */
+ CPP_INCLUDE_ANGLE = 289, /* CPP_INCLUDE_ANGLE */
+ END = 290, /* END */
+ INCLUDE = 291, /* INCLUDE */
+ INTERFACE = 292, /* INTERFACE */
+ MODULE = 293, /* MODULE */
+ SUBMODULE = 294, /* SUBMODULE */
+ USE = 295 /* USE */
+ };
+ typedef enum yytokentype yytoken_kind_t;
+#endif
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+union YYSTYPE
+{
+#line 71 "cmFortranParser.y"
+
+ char* string;
+
+#line 108 "cmFortranParserTokens.h"
+
+};
+typedef union YYSTYPE YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+
+int cmFortran_yyparse (yyscan_t yyscanner);
+
+#endif /* !YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED */
diff --git a/Source/LexerParser/cmGccDepfileLexer.cxx b/Source/LexerParser/cmGccDepfileLexer.cxx
new file mode 100644
index 0000000..3630f4e
--- /dev/null
+++ b/Source/LexerParser/cmGccDepfileLexer.cxx
@@ -0,0 +1,2210 @@
+#include "cmStandardLexer.h"
+
+#define FLEXINT_H 1
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmGccDepfile_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmGccDepfile_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmGccDepfile_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmGccDepfile_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmGccDepfile_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmGccDepfile_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmGccDepfile_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmGccDepfile_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmGccDepfile_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmGccDepfile_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmGccDepfile_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmGccDepfile_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmGccDepfile_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmGccDepfile_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmGccDepfile_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmGccDepfile_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmGccDepfile_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmGccDepfile_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmGccDepfile_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmGccDepfile_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmGccDepfile_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmGccDepfile_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmGccDepfile_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmGccDepfile_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmGccDepfile_yylex_ALREADY_DEFINED
+#else
+#define yylex cmGccDepfile_yylex
+#endif
+
+#ifdef yyrestart
+#define cmGccDepfile_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmGccDepfile_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmGccDepfile_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmGccDepfile_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmGccDepfile_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmGccDepfile_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmGccDepfile_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmGccDepfile_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmGccDepfile_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmGccDepfile_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmGccDepfile_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmGccDepfile_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmGccDepfile_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmGccDepfile_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmGccDepfile_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmGccDepfile_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmGccDepfile_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmGccDepfile_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmGccDepfile_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmGccDepfile_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmGccDepfile_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmGccDepfile_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmGccDepfile_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmGccDepfile_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmGccDepfile_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmGccDepfile_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmGccDepfile_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmGccDepfile_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmGccDepfile_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmGccDepfile_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmGccDepfile_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmGccDepfile_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmGccDepfile_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmGccDepfile_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmGccDepfile_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmGccDepfile_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmGccDepfile_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmGccDepfile_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmGccDepfile_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmGccDepfile_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmGccDepfile_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmGccDepfile_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmGccDepfile_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmGccDepfile_yyfree
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an
+ * integer in range [0..255] for use as an array index.
+ */
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin , yyscanner )
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+ #define YY_LINENO_REWIND_TO(ptr)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+static void yyensure_buffer_stack ( yyscan_t yyscanner );
+static void yy_load_buffer_state ( yyscan_t yyscanner );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner)
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+#define yy_new_buffer yy_create_buffer
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define cmGccDepfile_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+typedef flex_uint8_t YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner);
+static int yy_get_next_buffer ( yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+#define YY_NUM_RULES 11
+#define YY_END_OF_BUFFER 12
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static const flex_int16_t yy_accept[26] =
+ { 0,
+ 0, 0, 12, 10, 8, 6, 10, 9, 10, 10,
+ 10, 8, 0, 6, 9, 1, 7, 5, 0, 3,
+ 2, 0, 4, 0, 0
+ } ;
+
+static const YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 5, 6, 1, 7, 8, 6, 1, 1, 6,
+ 6, 1, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 9, 1, 1,
+ 6, 1, 1, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 10, 6, 1, 6, 1, 6, 6, 6, 6,
+
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 1, 6, 6, 1, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6
+ } ;
+
+static const YY_CHAR yy_meta[11] =
+ { 0,
+ 1, 2, 1, 1, 2, 1, 1, 1, 1, 3
+ } ;
+
+static const flex_int16_t yy_base[28] =
+ { 0,
+ 0, 0, 29, 35, 18, 35, 22, 18, 15, 0,
+ 8, 12, 16, 35, 11, 35, 0, 35, 13, 35,
+ 35, 16, 35, 22, 35, 31, 12
+ } ;
+
+static const flex_int16_t yy_def[28] =
+ { 0,
+ 25, 1, 25, 25, 26, 25, 25, 25, 25, 27,
+ 25, 26, 25, 25, 25, 25, 27, 25, 25, 25,
+ 25, 25, 25, 25, 0, 25, 25
+ } ;
+
+static const flex_int16_t yy_nxt[46] =
+ { 0,
+ 4, 5, 6, 7, 5, 8, 4, 9, 10, 11,
+ 18, 19, 20, 17, 21, 18, 15, 22, 18, 19,
+ 23, 13, 16, 15, 14, 24, 20, 13, 25, 25,
+ 25, 22, 12, 12, 3, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25
+ } ;
+
+static const flex_int16_t yy_chk[46] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 11, 11, 11, 27, 11, 19, 15, 11, 13, 13,
+ 22, 12, 9, 8, 7, 22, 24, 5, 3, 0,
+ 0, 24, 26, 26, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25
+ } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
+
+#include <cmGccDepfileLexerHelper.h>
+#include <string>
+
+#define INITIAL 0
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals ( yyscan_t yyscanner );
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput ( int c, char *buf_ptr , yyscan_t yyscanner);
+
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput ( yyscan_t yyscanner );
+#else
+static int input ( yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ int n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK /*LINTED*/break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_load_buffer_state( yyscanner );
+ }
+
+ {
+
+ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 26 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 35 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+{
+ // Unescape the dollar sign.
+ yyextra->addToCurrentPath("$");
+ }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+{
+ // Unescape the hash.
+ yyextra->addToCurrentPath("#");
+ }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+{
+ // 2N+1 backslashes plus space -> N backslashes plus space.
+ size_t c = (strlen(yytext) - 1) / 2;
+ std::string s(c, '\\');
+ s.push_back(' ');
+ yyextra->addToCurrentPath(s.c_str());
+ }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+ // 2N backslashes plus space -> 2N backslashes, end of filename.
+ yytext[strlen(yytext) - 1] = 0;
+ yyextra->addToCurrentPath(yytext);
+ yyextra->newDependency();
+ }
+ YY_BREAK
+case 5:
+/* rule 5 can match eol */
+YY_RULE_SETUP
+{
+ // A line continuation ends the current file name.
+ yyextra->newRuleOrDependency();
+ }
+ YY_BREAK
+case 6:
+/* rule 6 can match eol */
+YY_RULE_SETUP
+{
+ // A newline ends the current file name and the current rule.
+ yyextra->newEntry();
+ }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+{
+ // A colon followed by space ends the rules and starts a new dependency.
+ yyextra->newDependency();
+ }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+{
+ // Rules and dependencies are separated by blocks of whitespace.
+ yyextra->newRuleOrDependency();
+ }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+{
+ // Got a span of plain text.
+ yyextra->addToCurrentPath(yytext);
+ }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+{
+ // Got an otherwise unmatched character.
+ yyextra->addToCurrentPath(yytext);
+ }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+ECHO;
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap( yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of user's declarations */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc( (void *) b->yy_ch_buf,
+ (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = NULL;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin , yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+ (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ /* "- 2" to take care of EOB's */
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 26 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ char *yy_cp = yyg->yy_c_buf_p;
+
+ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 26 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_is_jam = (yy_current_state == 25);
+
+ (void)yyg;
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput (int c, char * yy_bp , yyscan_t yyscanner)
+{
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yyg->yy_hold_char;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ int number_to_move = yyg->yy_n_chars + 2;
+ char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ yyg->yy_n_chars = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ yyg->yytext_ptr = yy_bp;
+ yyg->yy_hold_char = *yy_cp;
+ yyg->yy_c_buf_p = yy_cp;
+}
+
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin , yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( yyscanner ) )
+ return 0;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner);
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file , yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree( (void *) b->yy_ch_buf , yyscanner );
+
+ yyfree( (void *) b , yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_flush_buffer( b , yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return NULL;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = NULL;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b , yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner)
+{
+
+ return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = (yy_size_t) (_yybytes_len + 2);
+ buf = (char *) yyalloc( n , yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n , yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param _line_number line number
+ * @param yyscanner The scanner object.
+ */
+void yyset_lineno (int _line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
+
+ yylineno = _line_number;
+}
+
+/** Set the current column.
+ * @param _column_no column number
+ * @param yyscanner The scanner object.
+ */
+void yyset_column (int _column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_column called with no buffer" );
+
+ yycolumn = _column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param _in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * _in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = _in_str ;
+}
+
+void yyset_out (FILE * _out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = _out_str ;
+}
+
+int yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void yyset_debug (int _bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = _bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+/* User-visible API */
+
+/* yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+int yylex_init(yyscan_t* ptr_yy_globals)
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to yyalloc in
+ * the yyextra field.
+ */
+int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals )
+{
+ struct yyguts_t dummy_yyguts;
+
+ yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = NULL;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = NULL;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = NULL;
+ yyout = NULL;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ yyfree(yyg->yy_buffer_stack , yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ yyfree( yyg->yy_start_stack , yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ yyfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
+{
+ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ return malloc(size);
+}
+
+void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return realloc(ptr, size);
+}
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+/*--------------------------------------------------------------------------*/
+
+#endif /* __clang_analyzer__ */
diff --git a/Source/LexerParser/cmGccDepfileLexer.h b/Source/LexerParser/cmGccDepfileLexer.h
new file mode 100644
index 0000000..7d34060
--- /dev/null
+++ b/Source/LexerParser/cmGccDepfileLexer.h
@@ -0,0 +1,687 @@
+#ifndef cmGccDepfile_yyHEADER_H
+#define cmGccDepfile_yyHEADER_H 1
+#define cmGccDepfile_yyIN_HEADER 1
+
+#define FLEXINT_H 1
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmGccDepfile_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmGccDepfile_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmGccDepfile_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmGccDepfile_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmGccDepfile_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmGccDepfile_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmGccDepfile_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmGccDepfile_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmGccDepfile_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmGccDepfile_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmGccDepfile_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmGccDepfile_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmGccDepfile_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmGccDepfile_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmGccDepfile_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmGccDepfile_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmGccDepfile_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmGccDepfile_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmGccDepfile_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmGccDepfile_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmGccDepfile_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmGccDepfile_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmGccDepfile_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmGccDepfile_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmGccDepfile_yylex_ALREADY_DEFINED
+#else
+#define yylex cmGccDepfile_yylex
+#endif
+
+#ifdef yyrestart
+#define cmGccDepfile_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmGccDepfile_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmGccDepfile_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmGccDepfile_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmGccDepfile_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmGccDepfile_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmGccDepfile_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmGccDepfile_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmGccDepfile_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmGccDepfile_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmGccDepfile_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmGccDepfile_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmGccDepfile_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmGccDepfile_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmGccDepfile_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmGccDepfile_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmGccDepfile_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmGccDepfile_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmGccDepfile_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmGccDepfile_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmGccDepfile_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmGccDepfile_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmGccDepfile_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmGccDepfile_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmGccDepfile_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmGccDepfile_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmGccDepfile_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmGccDepfile_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmGccDepfile_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmGccDepfile_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmGccDepfile_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmGccDepfile_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmGccDepfile_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmGccDepfile_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmGccDepfile_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmGccDepfile_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmGccDepfile_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmGccDepfile_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmGccDepfile_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmGccDepfile_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmGccDepfile_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmGccDepfile_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmGccDepfile_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmGccDepfile_yyfree
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+/* Begin user sect3 */
+
+#define cmGccDepfile_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#ifndef cmGccDepfile_yy_create_buffer_ALREADY_DEFINED
+#undef yy_create_buffer
+#endif
+#ifndef cmGccDepfile_yy_delete_buffer_ALREADY_DEFINED
+#undef yy_delete_buffer
+#endif
+#ifndef cmGccDepfile_yy_scan_buffer_ALREADY_DEFINED
+#undef yy_scan_buffer
+#endif
+#ifndef cmGccDepfile_yy_scan_string_ALREADY_DEFINED
+#undef yy_scan_string
+#endif
+#ifndef cmGccDepfile_yy_scan_bytes_ALREADY_DEFINED
+#undef yy_scan_bytes
+#endif
+#ifndef cmGccDepfile_yy_init_buffer_ALREADY_DEFINED
+#undef yy_init_buffer
+#endif
+#ifndef cmGccDepfile_yy_flush_buffer_ALREADY_DEFINED
+#undef yy_flush_buffer
+#endif
+#ifndef cmGccDepfile_yy_load_buffer_state_ALREADY_DEFINED
+#undef yy_load_buffer_state
+#endif
+#ifndef cmGccDepfile_yy_switch_to_buffer_ALREADY_DEFINED
+#undef yy_switch_to_buffer
+#endif
+#ifndef cmGccDepfile_yypush_buffer_state_ALREADY_DEFINED
+#undef yypush_buffer_state
+#endif
+#ifndef cmGccDepfile_yypop_buffer_state_ALREADY_DEFINED
+#undef yypop_buffer_state
+#endif
+#ifndef cmGccDepfile_yyensure_buffer_stack_ALREADY_DEFINED
+#undef yyensure_buffer_stack
+#endif
+#ifndef cmGccDepfile_yylex_ALREADY_DEFINED
+#undef yylex
+#endif
+#ifndef cmGccDepfile_yyrestart_ALREADY_DEFINED
+#undef yyrestart
+#endif
+#ifndef cmGccDepfile_yylex_init_ALREADY_DEFINED
+#undef yylex_init
+#endif
+#ifndef cmGccDepfile_yylex_init_extra_ALREADY_DEFINED
+#undef yylex_init_extra
+#endif
+#ifndef cmGccDepfile_yylex_destroy_ALREADY_DEFINED
+#undef yylex_destroy
+#endif
+#ifndef cmGccDepfile_yyget_debug_ALREADY_DEFINED
+#undef yyget_debug
+#endif
+#ifndef cmGccDepfile_yyset_debug_ALREADY_DEFINED
+#undef yyset_debug
+#endif
+#ifndef cmGccDepfile_yyget_extra_ALREADY_DEFINED
+#undef yyget_extra
+#endif
+#ifndef cmGccDepfile_yyset_extra_ALREADY_DEFINED
+#undef yyset_extra
+#endif
+#ifndef cmGccDepfile_yyget_in_ALREADY_DEFINED
+#undef yyget_in
+#endif
+#ifndef cmGccDepfile_yyset_in_ALREADY_DEFINED
+#undef yyset_in
+#endif
+#ifndef cmGccDepfile_yyget_out_ALREADY_DEFINED
+#undef yyget_out
+#endif
+#ifndef cmGccDepfile_yyset_out_ALREADY_DEFINED
+#undef yyset_out
+#endif
+#ifndef cmGccDepfile_yyget_leng_ALREADY_DEFINED
+#undef yyget_leng
+#endif
+#ifndef cmGccDepfile_yyget_text_ALREADY_DEFINED
+#undef yyget_text
+#endif
+#ifndef cmGccDepfile_yyget_lineno_ALREADY_DEFINED
+#undef yyget_lineno
+#endif
+#ifndef cmGccDepfile_yyset_lineno_ALREADY_DEFINED
+#undef yyset_lineno
+#endif
+#ifndef cmGccDepfile_yyget_column_ALREADY_DEFINED
+#undef yyget_column
+#endif
+#ifndef cmGccDepfile_yyset_column_ALREADY_DEFINED
+#undef yyset_column
+#endif
+#ifndef cmGccDepfile_yywrap_ALREADY_DEFINED
+#undef yywrap
+#endif
+#ifndef cmGccDepfile_yyget_lval_ALREADY_DEFINED
+#undef yyget_lval
+#endif
+#ifndef cmGccDepfile_yyset_lval_ALREADY_DEFINED
+#undef yyset_lval
+#endif
+#ifndef cmGccDepfile_yyget_lloc_ALREADY_DEFINED
+#undef yyget_lloc
+#endif
+#ifndef cmGccDepfile_yyset_lloc_ALREADY_DEFINED
+#undef yyset_lloc
+#endif
+#ifndef cmGccDepfile_yyalloc_ALREADY_DEFINED
+#undef yyalloc
+#endif
+#ifndef cmGccDepfile_yyrealloc_ALREADY_DEFINED
+#undef yyrealloc
+#endif
+#ifndef cmGccDepfile_yyfree_ALREADY_DEFINED
+#undef yyfree
+#endif
+#ifndef cmGccDepfile_yytext_ALREADY_DEFINED
+#undef yytext
+#endif
+#ifndef cmGccDepfile_yyleng_ALREADY_DEFINED
+#undef yyleng
+#endif
+#ifndef cmGccDepfile_yyin_ALREADY_DEFINED
+#undef yyin
+#endif
+#ifndef cmGccDepfile_yyout_ALREADY_DEFINED
+#undef yyout
+#endif
+#ifndef cmGccDepfile_yy_flex_debug_ALREADY_DEFINED
+#undef yy_flex_debug
+#endif
+#ifndef cmGccDepfile_yylineno_ALREADY_DEFINED
+#undef yylineno
+#endif
+#ifndef cmGccDepfile_yytables_fload_ALREADY_DEFINED
+#undef yytables_fload
+#endif
+#ifndef cmGccDepfile_yytables_destroy_ALREADY_DEFINED
+#undef yytables_destroy
+#endif
+#ifndef cmGccDepfile_yyTABLES_NAME_ALREADY_DEFINED
+#undef yyTABLES_NAME
+#endif
+
+#undef cmGccDepfile_yyIN_HEADER
+#endif /* cmGccDepfile_yyHEADER_H */
diff --git a/Source/LexerParser/cmGccDepfileLexer.in.l b/Source/LexerParser/cmGccDepfileLexer.in.l
new file mode 100644
index 0000000..c83cb75
--- /dev/null
+++ b/Source/LexerParser/cmGccDepfileLexer.in.l
@@ -0,0 +1,72 @@
+%{
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
+
+#include <cmGccDepfileLexerHelper.h>
+#include <string>
+%}
+
+%option prefix="cmGccDepfile_yy"
+%option noyywrap
+%option reentrant
+%pointer
+
+WSPACE [ \t]
+NEWLINE \r?\n
+
+%%
+\${2} {
+ // Unescape the dollar sign.
+ yyextra->addToCurrentPath("$");
+ }
+\\# {
+ // Unescape the hash.
+ yyextra->addToCurrentPath("#");
+ }
+(\\\\)*\\[ ] {
+ // 2N+1 backslashes plus space -> N backslashes plus space.
+ size_t c = (strlen(yytext) - 1) / 2;
+ std::string s(c, '\\');
+ s.push_back(' ');
+ yyextra->addToCurrentPath(s.c_str());
+ }
+(\\\\)+[ ] {
+ // 2N backslashes plus space -> 2N backslashes, end of filename.
+ yytext[strlen(yytext) - 1] = 0;
+ yyextra->addToCurrentPath(yytext);
+ yyextra->newDependency();
+ }
+{WSPACE}*\\{NEWLINE} {
+ // A line continuation ends the current file name.
+ yyextra->newRuleOrDependency();
+ }
+{NEWLINE} {
+ // A newline ends the current file name and the current rule.
+ yyextra->newEntry();
+ }
+:{WSPACE}+ {
+ // A colon followed by space ends the rules and starts a new dependency.
+ yyextra->newDependency();
+ }
+{WSPACE}+ {
+ // Rules and dependencies are separated by blocks of whitespace.
+ yyextra->newRuleOrDependency();
+ }
+[a-zA-Z0-9+,/_.~()}{%=@\x5B\x5D!\x80-\xFF-]+ {
+ // Got a span of plain text.
+ yyextra->addToCurrentPath(yytext);
+ }
+. {
+ // Got an otherwise unmatched character.
+ yyextra->addToCurrentPath(yytext);
+ }
+
+%%
+
+/*--------------------------------------------------------------------------*/
+
+#endif /* __clang_analyzer__ */
diff --git a/Source/LexerParser/cmListFileLexer.c b/Source/LexerParser/cmListFileLexer.c
new file mode 100644
index 0000000..ec7424c
--- /dev/null
+++ b/Source/LexerParser/cmListFileLexer.c
@@ -0,0 +1,2847 @@
+#include "cmStandardLexer.h"
+
+#define FLEXINT_H 1
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmListFileLexer_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmListFileLexer_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmListFileLexer_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmListFileLexer_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmListFileLexer_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmListFileLexer_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmListFileLexer_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmListFileLexer_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmListFileLexer_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmListFileLexer_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmListFileLexer_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmListFileLexer_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmListFileLexer_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmListFileLexer_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmListFileLexer_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmListFileLexer_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmListFileLexer_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmListFileLexer_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmListFileLexer_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmListFileLexer_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmListFileLexer_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmListFileLexer_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmListFileLexer_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmListFileLexer_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmListFileLexer_yylex_ALREADY_DEFINED
+#else
+#define yylex cmListFileLexer_yylex
+#endif
+
+#ifdef yyrestart
+#define cmListFileLexer_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmListFileLexer_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmListFileLexer_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmListFileLexer_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmListFileLexer_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmListFileLexer_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmListFileLexer_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmListFileLexer_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmListFileLexer_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmListFileLexer_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmListFileLexer_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmListFileLexer_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmListFileLexer_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmListFileLexer_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmListFileLexer_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmListFileLexer_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmListFileLexer_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmListFileLexer_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmListFileLexer_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmListFileLexer_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmListFileLexer_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmListFileLexer_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmListFileLexer_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmListFileLexer_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmListFileLexer_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmListFileLexer_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmListFileLexer_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmListFileLexer_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmListFileLexer_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmListFileLexer_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmListFileLexer_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmListFileLexer_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmListFileLexer_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmListFileLexer_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmListFileLexer_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmListFileLexer_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmListFileLexer_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmListFileLexer_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmListFileLexer_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmListFileLexer_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmListFileLexer_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmListFileLexer_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmListFileLexer_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmListFileLexer_yyfree
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an
+ * integer in range [0..255] for use as an array index.
+ */
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin , yyscanner )
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+ * access to the local variable yy_act. Since yyless() is a macro, it would break
+ * existing scanners that call yyless() from OUTSIDE yylex.
+ * One obvious solution it to make yy_act a global. I tried that, and saw
+ * a 5% performance hit in a non-yylineno scanner, because yy_act is
+ * normally declared as a register variable-- so it is not worth it.
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+ int yyl;\
+ for ( yyl = n; yyl < yyleng; ++yyl )\
+ if ( yytext[yyl] == '\n' )\
+ --yylineno;\
+ }while(0)
+ #define YY_LINENO_REWIND_TO(dst) \
+ do {\
+ const char *p;\
+ for ( p = yy_cp-1; p >= (dst); --p)\
+ if ( *p == '\n' )\
+ --yylineno;\
+ }while(0)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+static void yyensure_buffer_stack ( yyscan_t yyscanner );
+static void yy_load_buffer_state ( yyscan_t yyscanner );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner)
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+#define yy_new_buffer yy_create_buffer
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define cmListFileLexer_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+typedef flex_uint8_t YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner);
+static int yy_get_next_buffer ( yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+#define YY_NUM_RULES 24
+#define YY_END_OF_BUFFER 25
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static const flex_int16_t yy_accept[79] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 4, 4,
+ 25, 13, 22, 1, 16, 3, 13, 5, 6, 7,
+ 15, 23, 23, 17, 19, 20, 21, 24, 10, 11,
+ 8, 12, 9, 4, 13, 0, 13, 0, 22, 0,
+ 0, 7, 13, 0, 13, 0, 2, 0, 13, 17,
+ 0, 18, 10, 8, 4, 0, 14, 0, 0, 0,
+ 0, 14, 0, 0, 14, 0, 0, 0, 2, 14,
+ 0, 0, 0, 0, 0, 0, 0, 0
+ } ;
+
+static const YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 5, 6, 7, 1, 1, 1, 8,
+ 9, 1, 1, 1, 1, 1, 1, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 1, 1, 1,
+ 11, 1, 1, 1, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 13, 14, 15, 1, 12, 1, 12, 12, 12, 12,
+
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static const YY_CHAR yy_meta[17] =
+ { 0,
+ 1, 1, 2, 3, 4, 3, 1, 3, 5, 6,
+ 1, 6, 1, 1, 7, 2
+ } ;
+
+static const flex_int16_t yy_base[97] =
+ { 0,
+ 0, 0, 14, 28, 42, 56, 70, 84, 18, 19,
+ 68, 100, 16, 298, 298, 54, 58, 298, 298, 13,
+ 115, 0, 298, 51, 298, 298, 21, 298, 0, 298,
+ 53, 298, 298, 0, 0, 126, 55, 0, 25, 25,
+ 53, 0, 0, 136, 53, 0, 57, 0, 0, 42,
+ 50, 298, 0, 43, 0, 146, 160, 45, 172, 43,
+ 26, 0, 42, 177, 0, 42, 188, 40, 298, 40,
+ 0, 38, 37, 34, 32, 31, 23, 298, 197, 204,
+ 211, 218, 225, 232, 239, 245, 252, 259, 262, 268,
+ 275, 278, 280, 286, 289, 291
+
+ } ;
+
+static const flex_int16_t yy_def[97] =
+ { 0,
+ 78, 1, 79, 79, 80, 80, 81, 81, 82, 82,
+ 78, 78, 78, 78, 78, 78, 12, 78, 78, 12,
+ 78, 83, 78, 84, 78, 78, 84, 78, 85, 78,
+ 78, 78, 78, 86, 12, 87, 12, 88, 78, 78,
+ 89, 20, 12, 90, 12, 21, 78, 91, 12, 84,
+ 84, 78, 85, 78, 86, 87, 78, 56, 87, 92,
+ 78, 57, 89, 90, 57, 64, 90, 93, 78, 57,
+ 94, 95, 92, 96, 93, 95, 96, 0, 78, 78,
+ 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
+ 78, 78, 78, 78, 78, 78
+
+ } ;
+
+static const flex_int16_t yy_nxt[315] =
+ { 0,
+ 12, 13, 14, 13, 15, 16, 17, 18, 19, 12,
+ 12, 20, 21, 22, 12, 23, 25, 39, 26, 39,
+ 14, 14, 42, 52, 42, 50, 39, 27, 39, 28,
+ 25, 64, 26, 28, 28, 61, 61, 47, 47, 56,
+ 65, 27, 64, 28, 30, 57, 56, 60, 65, 74,
+ 62, 57, 72, 54, 50, 51, 31, 28, 30, 69,
+ 68, 62, 60, 54, 51, 41, 40, 78, 78, 78,
+ 31, 28, 30, 78, 78, 78, 78, 78, 78, 78,
+ 78, 78, 78, 78, 33, 28, 30, 78, 78, 78,
+ 78, 78, 78, 78, 78, 78, 78, 78, 33, 28,
+
+ 35, 78, 78, 78, 36, 78, 37, 78, 78, 35,
+ 35, 35, 35, 38, 35, 43, 78, 78, 78, 44,
+ 78, 45, 78, 78, 43, 46, 43, 47, 48, 43,
+ 57, 78, 58, 78, 78, 78, 78, 78, 78, 59,
+ 65, 78, 66, 78, 78, 78, 78, 78, 78, 67,
+ 57, 78, 58, 78, 78, 78, 78, 78, 78, 59,
+ 57, 78, 78, 78, 36, 78, 70, 78, 78, 57,
+ 57, 57, 57, 71, 57, 56, 78, 56, 78, 56,
+ 56, 65, 78, 66, 78, 78, 78, 78, 78, 78,
+ 67, 64, 78, 64, 78, 64, 64, 24, 24, 24,
+
+ 24, 24, 24, 24, 29, 29, 29, 29, 29, 29,
+ 29, 32, 32, 32, 32, 32, 32, 32, 34, 34,
+ 34, 34, 34, 34, 34, 49, 78, 49, 49, 49,
+ 49, 49, 50, 78, 50, 78, 50, 50, 50, 53,
+ 78, 53, 53, 53, 53, 55, 78, 55, 55, 55,
+ 55, 55, 56, 78, 78, 56, 78, 56, 56, 35,
+ 78, 35, 35, 35, 35, 35, 63, 63, 64, 78,
+ 78, 64, 78, 64, 64, 43, 78, 43, 43, 43,
+ 43, 43, 73, 73, 75, 75, 57, 78, 57, 57,
+ 57, 57, 57, 76, 76, 77, 77, 11, 78, 78,
+
+ 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
+ 78, 78, 78, 78
+ } ;
+
+static const flex_int16_t yy_chk[315] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 3, 13, 3, 13,
+ 9, 10, 20, 27, 20, 27, 39, 3, 39, 3,
+ 4, 77, 4, 9, 10, 40, 61, 40, 61, 76,
+ 75, 4, 74, 4, 5, 73, 72, 70, 68, 66,
+ 63, 60, 58, 54, 51, 50, 5, 5, 6, 47,
+ 45, 41, 37, 31, 24, 17, 16, 11, 0, 0,
+ 6, 6, 7, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 7, 7, 8, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 8, 8,
+
+ 12, 0, 0, 0, 12, 0, 12, 0, 0, 12,
+ 12, 12, 12, 12, 12, 21, 0, 0, 0, 21,
+ 0, 21, 0, 0, 21, 21, 21, 21, 21, 21,
+ 36, 0, 36, 0, 0, 0, 0, 0, 0, 36,
+ 44, 0, 44, 0, 0, 0, 0, 0, 0, 44,
+ 56, 0, 56, 0, 0, 0, 0, 0, 0, 56,
+ 57, 0, 0, 0, 57, 0, 57, 0, 0, 57,
+ 57, 57, 57, 57, 57, 59, 0, 59, 0, 59,
+ 59, 64, 0, 64, 0, 0, 0, 0, 0, 0,
+ 64, 67, 0, 67, 0, 67, 67, 79, 79, 79,
+
+ 79, 79, 79, 79, 80, 80, 80, 80, 80, 80,
+ 80, 81, 81, 81, 81, 81, 81, 81, 82, 82,
+ 82, 82, 82, 82, 82, 83, 0, 83, 83, 83,
+ 83, 83, 84, 0, 84, 0, 84, 84, 84, 85,
+ 0, 85, 85, 85, 85, 86, 0, 86, 86, 86,
+ 86, 86, 87, 0, 0, 87, 0, 87, 87, 88,
+ 0, 88, 88, 88, 88, 88, 89, 89, 90, 0,
+ 0, 90, 0, 90, 90, 91, 0, 91, 91, 91,
+ 91, 91, 92, 92, 93, 93, 94, 0, 94, 94,
+ 94, 94, 94, 95, 95, 96, 96, 78, 78, 78,
+
+ 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
+ 78, 78, 78, 78
+ } ;
+
+/* Table of booleans, true if rule could match eol. */
+static const flex_int32_t yy_rule_can_match_eol[25] =
+ { 0,
+1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1,
+ 0, 0, 0, 0, 0, };
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run flex >= 2.6 like this:
+
+ flex --nounistd -DFLEXINT_H --noline -ocmListFileLexer.c cmListFileLexer.in.l
+
+Modify cmListFileLexer.c:
+ - remove trailing whitespace: sed -i 's/\s*$//' cmListFileLexer.c
+ - remove blank lines at end of file: sed -i '${/^$/d;}' cmListFileLexer.c
+ - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmListFileLexer.c
+
+*/
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifdef _WIN32
+#include "cmsys/Encoding.h"
+#endif
+
+/* Setup the proper cmListFileLexer_yylex declaration. */
+#define YY_EXTRA_TYPE cmListFileLexer*
+#define YY_DECL int cmListFileLexer_yylex (yyscan_t yyscanner, cmListFileLexer* lexer)
+
+#include "cmListFileLexer.h"
+
+/*--------------------------------------------------------------------------*/
+struct cmListFileLexer_s
+{
+ cmListFileLexer_Token token;
+ int bracket;
+ int comment;
+ int line;
+ int column;
+ int size;
+ FILE* file;
+ size_t cr;
+ char* string_buffer;
+ char* string_position;
+ int string_left;
+ yyscan_t scanner;
+};
+
+static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text,
+ int length);
+static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text,
+ int length);
+static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer,
+ size_t bufferSize);
+static void cmListFileLexerInit(cmListFileLexer* lexer);
+static void cmListFileLexerDestroy(cmListFileLexer* lexer);
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ do { result = cmListFileLexerInput(cmListFileLexer_yyget_extra(yyscanner), buf, max_size); } while (0)
+
+/*--------------------------------------------------------------------------*/
+
+#define INITIAL 0
+#define STRING 1
+#define BRACKET 2
+#define BRACKETEND 3
+#define COMMENT 4
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals ( yyscan_t yyscanner );
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput ( int c, char *buf_ptr , yyscan_t yyscanner);
+
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput ( yyscan_t yyscanner );
+#else
+static int input ( yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ int n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK /*LINTED*/break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_load_buffer_state( yyscanner );
+ }
+
+ {
+
+ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 79 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 298 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+ if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ {
+ int yyl;
+ for ( yyl = 0; yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+ }
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+/* rule 1 can match eol */
+YY_RULE_SETUP
+{
+ lexer->token.type = cmListFileLexer_Token_Newline;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ ++lexer->line;
+ lexer->column = 1;
+ BEGIN(INITIAL);
+ return 1;
+}
+ YY_BREAK
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+{
+ const char* bracket = yytext;
+ lexer->comment = yytext[0] == '#';
+ if (lexer->comment) {
+ lexer->token.type = cmListFileLexer_Token_CommentBracket;
+ bracket += 1;
+ } else {
+ lexer->token.type = cmListFileLexer_Token_ArgumentBracket;
+ }
+ cmListFileLexerSetToken(lexer, "", 0);
+ lexer->bracket = strchr(bracket+1, '[') - bracket;
+ if (yytext[yyleng-1] == '\n') {
+ ++lexer->line;
+ lexer->column = 1;
+ } else {
+ lexer->column += yyleng;
+ }
+ BEGIN(BRACKET);
+}
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+{
+ lexer->column += yyleng;
+ BEGIN(COMMENT);
+}
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+ lexer->column += yyleng;
+}
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+{
+ lexer->token.type = cmListFileLexer_Token_ParenLeft;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+{
+ lexer->token.type = cmListFileLexer_Token_ParenRight;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+{
+ lexer->token.type = cmListFileLexer_Token_Identifier;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+{
+ /* Handle ]]====]=======]*/
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ if (yyleng == lexer->bracket) {
+ BEGIN(BRACKETEND);
+ }
+}
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+{
+ lexer->column += yyleng;
+ /* Erase the partial bracket from the token. */
+ lexer->token.length -= lexer->bracket;
+ lexer->token.text[lexer->token.length] = 0;
+ BEGIN(INITIAL);
+ return 1;
+}
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+{
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+}
+ YY_BREAK
+case 11:
+/* rule 11 can match eol */
+YY_RULE_SETUP
+{
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ ++lexer->line;
+ lexer->column = 1;
+ BEGIN(BRACKET);
+}
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+{
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ BEGIN(BRACKET);
+}
+ YY_BREAK
+case YY_STATE_EOF(BRACKET):
+case YY_STATE_EOF(BRACKETEND):
+{
+ lexer->token.type = cmListFileLexer_Token_BadBracket;
+ BEGIN(INITIAL);
+ return 1;
+}
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+{
+ lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+{
+ lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+{
+ lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+{
+ lexer->token.type = cmListFileLexer_Token_ArgumentQuoted;
+ cmListFileLexerSetToken(lexer, "", 0);
+ lexer->column += yyleng;
+ BEGIN(STRING);
+}
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+{
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+}
+ YY_BREAK
+case 18:
+/* rule 18 can match eol */
+YY_RULE_SETUP
+{
+ /* Continuation: text is not part of string */
+ ++lexer->line;
+ lexer->column = 1;
+}
+ YY_BREAK
+case 19:
+/* rule 19 can match eol */
+YY_RULE_SETUP
+{
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ ++lexer->line;
+ lexer->column = 1;
+}
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+{
+ lexer->column += yyleng;
+ BEGIN(INITIAL);
+ return 1;
+}
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+{
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+}
+ YY_BREAK
+case YY_STATE_EOF(STRING):
+{
+ lexer->token.type = cmListFileLexer_Token_BadString;
+ BEGIN(INITIAL);
+ return 1;
+}
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+{
+ lexer->token.type = cmListFileLexer_Token_Space;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+{
+ lexer->token.type = cmListFileLexer_Token_BadCharacter;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMENT):
+{
+ lexer->token.type = cmListFileLexer_Token_None;
+ cmListFileLexerSetToken(lexer, 0, 0);
+ return 0;
+}
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+ECHO;
+ YY_BREAK
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap( yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of user's declarations */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc( (void *) b->yy_ch_buf,
+ (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = NULL;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin , yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+ (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ /* "- 2" to take care of EOB's */
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 16);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 79 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ char *yy_cp = yyg->yy_c_buf_p;
+
+ YY_CHAR yy_c = 16;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 79 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_is_jam = (yy_current_state == 78);
+
+ (void)yyg;
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+
+ static void yyunput (int c, char * yy_bp , yyscan_t yyscanner)
+{
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yyg->yy_hold_char;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ int number_to_move = yyg->yy_n_chars + 2;
+ char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ yyg->yy_n_chars = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ if ( c == '\n' ){
+ --yylineno;
+ }
+
+ yyg->yytext_ptr = yy_bp;
+ yyg->yy_hold_char = *yy_cp;
+ yyg->yy_c_buf_p = yy_cp;
+}
+
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin , yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( yyscanner ) )
+ return 0;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ if ( c == '\n' )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner);
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file , yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree( (void *) b->yy_ch_buf , yyscanner );
+
+ yyfree( (void *) b , yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_flush_buffer( b , yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return NULL;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = NULL;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b , yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner)
+{
+
+ return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = (yy_size_t) (_yybytes_len + 2);
+ buf = (char *) yyalloc( n , yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n , yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param _line_number line number
+ * @param yyscanner The scanner object.
+ */
+void yyset_lineno (int _line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
+
+ yylineno = _line_number;
+}
+
+/** Set the current column.
+ * @param _column_no column number
+ * @param yyscanner The scanner object.
+ */
+void yyset_column (int _column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_column called with no buffer" );
+
+ yycolumn = _column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param _in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * _in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = _in_str ;
+}
+
+void yyset_out (FILE * _out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = _out_str ;
+}
+
+int yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void yyset_debug (int _bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = _bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+/* User-visible API */
+
+/* yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+int yylex_init(yyscan_t* ptr_yy_globals)
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to yyalloc in
+ * the yyextra field.
+ */
+int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals )
+{
+ struct yyguts_t dummy_yyguts;
+
+ yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = NULL;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = NULL;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = NULL;
+ yyout = NULL;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ yyfree(yyg->yy_buffer_stack , yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ yyfree( yyg->yy_start_stack , yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ yyfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
+{
+ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ return malloc(size);
+}
+
+void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return realloc(ptr, size);
+}
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text,
+ int length)
+{
+ /* Set the token line and column number. */
+ lexer->token.line = lexer->line;
+ lexer->token.column = lexer->column;
+
+ /* Use the same buffer if possible. */
+ if (lexer->token.text) {
+ if (text && length < lexer->size) {
+ strcpy(lexer->token.text, text);
+ lexer->token.length = length;
+ return;
+ }
+ free(lexer->token.text);
+ lexer->token.text = 0;
+ lexer->size = 0;
+ }
+
+ /* Need to extend the buffer. */
+ if (text) {
+ lexer->token.text = strdup(text);
+ lexer->token.length = length;
+ lexer->size = length + 1;
+ } else {
+ lexer->token.length = 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text,
+ int length)
+{
+ char* temp;
+ int newSize;
+
+ /* If the appended text will fit in the buffer, do not reallocate. */
+ newSize = lexer->token.length + length + 1;
+ if (lexer->token.text && newSize <= lexer->size) {
+ strcpy(lexer->token.text + lexer->token.length, text);
+ lexer->token.length += length;
+ return;
+ }
+
+ /* We need to extend the buffer. */
+ temp = malloc(newSize);
+ if (lexer->token.text) {
+ memcpy(temp, lexer->token.text, lexer->token.length);
+ free(lexer->token.text);
+ }
+ memcpy(temp + lexer->token.length, text, length);
+ temp[lexer->token.length + length] = 0;
+ lexer->token.text = temp;
+ lexer->token.length += length;
+ lexer->size = newSize;
+}
+
+/*--------------------------------------------------------------------------*/
+static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer,
+ size_t bufferSize)
+{
+ if (lexer) {
+ if (lexer->file) {
+ /* Convert CRLF -> LF explicitly. The C FILE "t"ext mode
+ does not convert newlines on all platforms. Move any
+ trailing CR to the start of the buffer for the next read. */
+ size_t cr = lexer->cr;
+ size_t n;
+ buffer[0] = '\r';
+ n = fread(buffer + cr, 1, bufferSize - cr, lexer->file);
+ if (n) {
+ char* o = buffer;
+ const char* i = buffer;
+ const char* e;
+ n += cr;
+ cr = (buffer[n - 1] == '\r') ? 1 : 0;
+ e = buffer + n - cr;
+ while (i != e) {
+ if (i[0] == '\r' && i[1] == '\n') {
+ ++i;
+ }
+ *o++ = *i++;
+ }
+ n = o - buffer;
+ } else {
+ n = cr;
+ cr = 0;
+ }
+ lexer->cr = cr;
+ return n;
+ } else if (lexer->string_left) {
+ int length = lexer->string_left;
+ if ((int)bufferSize < length) {
+ length = (int)bufferSize;
+ }
+ memcpy(buffer, lexer->string_position, length);
+ lexer->string_position += length;
+ lexer->string_left -= length;
+ return length;
+ }
+ }
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerInit(cmListFileLexer* lexer)
+{
+ if (lexer->file || lexer->string_buffer) {
+ cmListFileLexer_yylex_init(&lexer->scanner);
+ cmListFileLexer_yyset_extra(lexer, lexer->scanner);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerDestroy(cmListFileLexer* lexer)
+{
+ cmListFileLexerSetToken(lexer, 0, 0);
+ if (lexer->file || lexer->string_buffer) {
+ cmListFileLexer_yylex_destroy(lexer->scanner);
+ if (lexer->file) {
+ fclose(lexer->file);
+ lexer->file = 0;
+ }
+ if (lexer->string_buffer) {
+ free(lexer->string_buffer);
+ lexer->string_buffer = 0;
+ lexer->string_left = 0;
+ lexer->string_position = 0;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+cmListFileLexer* cmListFileLexer_New(void)
+{
+ cmListFileLexer* lexer = (cmListFileLexer*)malloc(sizeof(cmListFileLexer));
+ if (!lexer) {
+ return 0;
+ }
+ memset(lexer, 0, sizeof(*lexer));
+ lexer->line = 1;
+ lexer->column = 1;
+ return lexer;
+}
+
+/*--------------------------------------------------------------------------*/
+void cmListFileLexer_Delete(cmListFileLexer* lexer)
+{
+ cmListFileLexer_SetFileName(lexer, 0, 0);
+ free(lexer);
+}
+
+/*--------------------------------------------------------------------------*/
+static cmListFileLexer_BOM cmListFileLexer_ReadBOM(FILE* f)
+{
+ unsigned char b[2];
+ if (fread(b, 1, 2, f) == 2) {
+ if (b[0] == 0xEF && b[1] == 0xBB) {
+ if (fread(b, 1, 1, f) == 1 && b[0] == 0xBF) {
+ return cmListFileLexer_BOM_UTF8;
+ }
+ } else if (b[0] == 0xFE && b[1] == 0xFF) {
+ /* UTF-16 BE */
+ return cmListFileLexer_BOM_UTF16BE;
+ } else if (b[0] == 0 && b[1] == 0) {
+ if (fread(b, 1, 2, f) == 2 && b[0] == 0xFE && b[1] == 0xFF) {
+ return cmListFileLexer_BOM_UTF32BE;
+ }
+ } else if (b[0] == 0xFF && b[1] == 0xFE) {
+ fpos_t p;
+ fgetpos(f, &p);
+ if (fread(b, 1, 2, f) == 2 && b[0] == 0 && b[1] == 0) {
+ return cmListFileLexer_BOM_UTF32LE;
+ }
+ if (fsetpos(f, &p) != 0) {
+ return cmListFileLexer_BOM_Broken;
+ }
+ return cmListFileLexer_BOM_UTF16LE;
+ }
+ }
+ if (fseek(f, 0, SEEK_SET) != 0) {
+ return cmListFileLexer_BOM_Broken;
+ }
+ return cmListFileLexer_BOM_None;
+}
+
+/*--------------------------------------------------------------------------*/
+int cmListFileLexer_SetFileName(cmListFileLexer* lexer, const char* name,
+ cmListFileLexer_BOM* bom)
+{
+ int result = 1;
+ cmListFileLexerDestroy(lexer);
+ if (name) {
+#ifdef _WIN32
+ wchar_t* wname = cmsysEncoding_DupToWide(name);
+ lexer->file = _wfopen(wname, L"rb");
+ free(wname);
+#else
+ lexer->file = fopen(name, "rb");
+#endif
+ if (lexer->file) {
+ if (bom) {
+ *bom = cmListFileLexer_ReadBOM(lexer->file);
+ }
+ } else {
+ result = 0;
+ }
+ }
+ cmListFileLexerInit(lexer);
+ return result;
+}
+
+/*--------------------------------------------------------------------------*/
+int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text)
+{
+ int result = 1;
+ cmListFileLexerDestroy(lexer);
+ if (text) {
+ int length = (int)strlen(text);
+ lexer->string_buffer = (char*)malloc(length + 1);
+ if (lexer->string_buffer) {
+ strcpy(lexer->string_buffer, text);
+ lexer->string_position = lexer->string_buffer;
+ lexer->string_left = length;
+ } else {
+ result = 0;
+ }
+ }
+ cmListFileLexerInit(lexer);
+ return result;
+}
+
+/*--------------------------------------------------------------------------*/
+cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
+{
+ if (!lexer->file && !lexer->string_buffer) {
+ return 0;
+ }
+ if (cmListFileLexer_yylex(lexer->scanner, lexer)) {
+ return &lexer->token;
+ } else {
+ cmListFileLexer_SetFileName(lexer, 0, 0);
+ return 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer)
+{
+ return lexer->line;
+}
+
+/*--------------------------------------------------------------------------*/
+long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer)
+{
+ return lexer->column;
+}
+
+/*--------------------------------------------------------------------------*/
+const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer,
+ cmListFileLexer_Type type)
+{
+ (void)lexer;
+ switch (type) {
+ case cmListFileLexer_Token_None:
+ return "nothing";
+ case cmListFileLexer_Token_Space:
+ return "space";
+ case cmListFileLexer_Token_Newline:
+ return "newline";
+ case cmListFileLexer_Token_Identifier:
+ return "identifier";
+ case cmListFileLexer_Token_ParenLeft:
+ return "left paren";
+ case cmListFileLexer_Token_ParenRight:
+ return "right paren";
+ case cmListFileLexer_Token_ArgumentUnquoted:
+ return "unquoted argument";
+ case cmListFileLexer_Token_ArgumentQuoted:
+ return "quoted argument";
+ case cmListFileLexer_Token_ArgumentBracket:
+ return "bracket argument";
+ case cmListFileLexer_Token_CommentBracket:
+ return "bracket comment";
+ case cmListFileLexer_Token_BadCharacter:
+ return "bad character";
+ case cmListFileLexer_Token_BadBracket:
+ return "unterminated bracket";
+ case cmListFileLexer_Token_BadString:
+ return "unterminated string";
+ }
+ return "unknown token";
+}
diff --git a/Source/LexerParser/cmListFileLexer.in.l b/Source/LexerParser/cmListFileLexer.in.l
new file mode 100644
index 0000000..94cf8a5
--- /dev/null
+++ b/Source/LexerParser/cmListFileLexer.in.l
@@ -0,0 +1,560 @@
+%{
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+
+This file must be translated to C and modified to build everywhere.
+
+Run flex >= 2.6 like this:
+
+ flex --nounistd -DFLEXINT_H --noline -ocmListFileLexer.c cmListFileLexer.in.l
+
+Modify cmListFileLexer.c:
+ - remove trailing whitespace: sed -i 's/\s*$//' cmListFileLexer.c
+ - remove blank lines at end of file: sed -i '${/^$/d;}' cmListFileLexer.c
+ - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmListFileLexer.c
+
+*/
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifdef _WIN32
+#include "cmsys/Encoding.h"
+#endif
+
+/* Setup the proper cmListFileLexer_yylex declaration. */
+#define YY_EXTRA_TYPE cmListFileLexer*
+#define YY_DECL int cmListFileLexer_yylex (yyscan_t yyscanner, cmListFileLexer* lexer)
+
+#include "cmListFileLexer.h"
+
+/*--------------------------------------------------------------------------*/
+struct cmListFileLexer_s
+{
+ cmListFileLexer_Token token;
+ int bracket;
+ int comment;
+ int line;
+ int column;
+ int size;
+ FILE* file;
+ size_t cr;
+ char* string_buffer;
+ char* string_position;
+ int string_left;
+ yyscan_t scanner;
+};
+
+static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text,
+ int length);
+static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text,
+ int length);
+static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer,
+ size_t bufferSize);
+static void cmListFileLexerInit(cmListFileLexer* lexer);
+static void cmListFileLexerDestroy(cmListFileLexer* lexer);
+
+/* Replace the lexer input function. */
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ do { result = cmListFileLexerInput(cmListFileLexer_yyget_extra(yyscanner), buf, max_size); } while (0)
+
+/*--------------------------------------------------------------------------*/
+%}
+
+%option prefix="cmListFileLexer_yy"
+
+%option reentrant
+%option yylineno
+%option noyywrap
+%pointer
+%x STRING
+%x BRACKET
+%x BRACKETEND
+%x COMMENT
+
+MAKEVAR \$\([A-Za-z0-9_]*\)
+UNQUOTED ([^ \0\t\r\n\(\)#\\\"[=]|\\[^\0\n])
+LEGACY {MAKEVAR}|{UNQUOTED}|\"({MAKEVAR}|{UNQUOTED}|[ \t[=])*\"
+
+%%
+
+<INITIAL,COMMENT>\n {
+ lexer->token.type = cmListFileLexer_Token_Newline;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ ++lexer->line;
+ lexer->column = 1;
+ BEGIN(INITIAL);
+ return 1;
+}
+
+#?\[=*\[\n? {
+ const char* bracket = yytext;
+ lexer->comment = yytext[0] == '#';
+ if (lexer->comment) {
+ lexer->token.type = cmListFileLexer_Token_CommentBracket;
+ bracket += 1;
+ } else {
+ lexer->token.type = cmListFileLexer_Token_ArgumentBracket;
+ }
+ cmListFileLexerSetToken(lexer, "", 0);
+ lexer->bracket = strchr(bracket+1, '[') - bracket;
+ if (yytext[yyleng-1] == '\n') {
+ ++lexer->line;
+ lexer->column = 1;
+ } else {
+ lexer->column += yyleng;
+ }
+ BEGIN(BRACKET);
+}
+
+# {
+ lexer->column += yyleng;
+ BEGIN(COMMENT);
+}
+
+<COMMENT>[^\0\n]* {
+ lexer->column += yyleng;
+}
+
+\( {
+ lexer->token.type = cmListFileLexer_Token_ParenLeft;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+\) {
+ lexer->token.type = cmListFileLexer_Token_ParenRight;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+[A-Za-z_][A-Za-z0-9_]* {
+ lexer->token.type = cmListFileLexer_Token_Identifier;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+<BRACKET>\]=* {
+ /* Handle ]]====]=======]*/
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ if (yyleng == lexer->bracket) {
+ BEGIN(BRACKETEND);
+ }
+}
+
+<BRACKETEND>\] {
+ lexer->column += yyleng;
+ /* Erase the partial bracket from the token. */
+ lexer->token.length -= lexer->bracket;
+ lexer->token.text[lexer->token.length] = 0;
+ BEGIN(INITIAL);
+ return 1;
+}
+
+<BRACKET>([^]\0\n])+ {
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+}
+
+<BRACKET,BRACKETEND>\n {
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ ++lexer->line;
+ lexer->column = 1;
+ BEGIN(BRACKET);
+}
+
+<BRACKET,BRACKETEND>[^\0\n] {
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ BEGIN(BRACKET);
+}
+
+<BRACKET,BRACKETEND><<EOF>> {
+ lexer->token.type = cmListFileLexer_Token_BadBracket;
+ BEGIN(INITIAL);
+ return 1;
+}
+
+({UNQUOTED}|=|\[=*{UNQUOTED})({UNQUOTED}|[[=])* {
+ lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+({MAKEVAR}|{UNQUOTED}|=|\[=*{LEGACY})({LEGACY}|[[=])* {
+ lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+\[ {
+ lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+\" {
+ lexer->token.type = cmListFileLexer_Token_ArgumentQuoted;
+ cmListFileLexerSetToken(lexer, "", 0);
+ lexer->column += yyleng;
+ BEGIN(STRING);
+}
+
+<STRING>([^\\\0\n\"]|\\[^\0\n])+ {
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+}
+
+<STRING>\\\n {
+ /* Continuation: text is not part of string */
+ ++lexer->line;
+ lexer->column = 1;
+}
+
+<STRING>\n {
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ ++lexer->line;
+ lexer->column = 1;
+}
+
+<STRING>\" {
+ lexer->column += yyleng;
+ BEGIN(INITIAL);
+ return 1;
+}
+
+<STRING>[^\0\n] {
+ cmListFileLexerAppend(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+}
+
+<STRING><<EOF>> {
+ lexer->token.type = cmListFileLexer_Token_BadString;
+ BEGIN(INITIAL);
+ return 1;
+}
+
+[ \t\r]+ {
+ lexer->token.type = cmListFileLexer_Token_Space;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+. {
+ lexer->token.type = cmListFileLexer_Token_BadCharacter;
+ cmListFileLexerSetToken(lexer, yytext, yyleng);
+ lexer->column += yyleng;
+ return 1;
+}
+
+<<EOF>> {
+ lexer->token.type = cmListFileLexer_Token_None;
+ cmListFileLexerSetToken(lexer, 0, 0);
+ return 0;
+}
+
+%%
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text,
+ int length)
+{
+ /* Set the token line and column number. */
+ lexer->token.line = lexer->line;
+ lexer->token.column = lexer->column;
+
+ /* Use the same buffer if possible. */
+ if (lexer->token.text) {
+ if (text && length < lexer->size) {
+ strcpy(lexer->token.text, text);
+ lexer->token.length = length;
+ return;
+ }
+ free(lexer->token.text);
+ lexer->token.text = 0;
+ lexer->size = 0;
+ }
+
+ /* Need to extend the buffer. */
+ if (text) {
+ lexer->token.text = strdup(text);
+ lexer->token.length = length;
+ lexer->size = length + 1;
+ } else {
+ lexer->token.length = 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text,
+ int length)
+{
+ char* temp;
+ int newSize;
+
+ /* If the appended text will fit in the buffer, do not reallocate. */
+ newSize = lexer->token.length + length + 1;
+ if (lexer->token.text && newSize <= lexer->size) {
+ strcpy(lexer->token.text + lexer->token.length, text);
+ lexer->token.length += length;
+ return;
+ }
+
+ /* We need to extend the buffer. */
+ temp = malloc(newSize);
+ if (lexer->token.text) {
+ memcpy(temp, lexer->token.text, lexer->token.length);
+ free(lexer->token.text);
+ }
+ memcpy(temp + lexer->token.length, text, length);
+ temp[lexer->token.length + length] = 0;
+ lexer->token.text = temp;
+ lexer->token.length += length;
+ lexer->size = newSize;
+}
+
+/*--------------------------------------------------------------------------*/
+static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer,
+ size_t bufferSize)
+{
+ if (lexer) {
+ if (lexer->file) {
+ /* Convert CRLF -> LF explicitly. The C FILE "t"ext mode
+ does not convert newlines on all platforms. Move any
+ trailing CR to the start of the buffer for the next read. */
+ size_t cr = lexer->cr;
+ size_t n;
+ buffer[0] = '\r';
+ n = fread(buffer + cr, 1, bufferSize - cr, lexer->file);
+ if (n) {
+ char* o = buffer;
+ const char* i = buffer;
+ const char* e;
+ n += cr;
+ cr = (buffer[n - 1] == '\r') ? 1 : 0;
+ e = buffer + n - cr;
+ while (i != e) {
+ if (i[0] == '\r' && i[1] == '\n') {
+ ++i;
+ }
+ *o++ = *i++;
+ }
+ n = o - buffer;
+ } else {
+ n = cr;
+ cr = 0;
+ }
+ lexer->cr = cr;
+ return n;
+ } else if (lexer->string_left) {
+ int length = lexer->string_left;
+ if ((int)bufferSize < length) {
+ length = (int)bufferSize;
+ }
+ memcpy(buffer, lexer->string_position, length);
+ lexer->string_position += length;
+ lexer->string_left -= length;
+ return length;
+ }
+ }
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerInit(cmListFileLexer* lexer)
+{
+ if (lexer->file || lexer->string_buffer) {
+ cmListFileLexer_yylex_init(&lexer->scanner);
+ cmListFileLexer_yyset_extra(lexer, lexer->scanner);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static void cmListFileLexerDestroy(cmListFileLexer* lexer)
+{
+ cmListFileLexerSetToken(lexer, 0, 0);
+ if (lexer->file || lexer->string_buffer) {
+ cmListFileLexer_yylex_destroy(lexer->scanner);
+ if (lexer->file) {
+ fclose(lexer->file);
+ lexer->file = 0;
+ }
+ if (lexer->string_buffer) {
+ free(lexer->string_buffer);
+ lexer->string_buffer = 0;
+ lexer->string_left = 0;
+ lexer->string_position = 0;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+cmListFileLexer* cmListFileLexer_New(void)
+{
+ cmListFileLexer* lexer = (cmListFileLexer*)malloc(sizeof(cmListFileLexer));
+ if (!lexer) {
+ return 0;
+ }
+ memset(lexer, 0, sizeof(*lexer));
+ lexer->line = 1;
+ lexer->column = 1;
+ return lexer;
+}
+
+/*--------------------------------------------------------------------------*/
+void cmListFileLexer_Delete(cmListFileLexer* lexer)
+{
+ cmListFileLexer_SetFileName(lexer, 0, 0);
+ free(lexer);
+}
+
+/*--------------------------------------------------------------------------*/
+static cmListFileLexer_BOM cmListFileLexer_ReadBOM(FILE* f)
+{
+ unsigned char b[2];
+ if (fread(b, 1, 2, f) == 2) {
+ if (b[0] == 0xEF && b[1] == 0xBB) {
+ if (fread(b, 1, 1, f) == 1 && b[0] == 0xBF) {
+ return cmListFileLexer_BOM_UTF8;
+ }
+ } else if (b[0] == 0xFE && b[1] == 0xFF) {
+ /* UTF-16 BE */
+ return cmListFileLexer_BOM_UTF16BE;
+ } else if (b[0] == 0 && b[1] == 0) {
+ if (fread(b, 1, 2, f) == 2 && b[0] == 0xFE && b[1] == 0xFF) {
+ return cmListFileLexer_BOM_UTF32BE;
+ }
+ } else if (b[0] == 0xFF && b[1] == 0xFE) {
+ fpos_t p;
+ fgetpos(f, &p);
+ if (fread(b, 1, 2, f) == 2 && b[0] == 0 && b[1] == 0) {
+ return cmListFileLexer_BOM_UTF32LE;
+ }
+ if (fsetpos(f, &p) != 0) {
+ return cmListFileLexer_BOM_Broken;
+ }
+ return cmListFileLexer_BOM_UTF16LE;
+ }
+ }
+ if (fseek(f, 0, SEEK_SET) != 0) {
+ return cmListFileLexer_BOM_Broken;
+ }
+ return cmListFileLexer_BOM_None;
+}
+
+/*--------------------------------------------------------------------------*/
+int cmListFileLexer_SetFileName(cmListFileLexer* lexer, const char* name,
+ cmListFileLexer_BOM* bom)
+{
+ int result = 1;
+ cmListFileLexerDestroy(lexer);
+ if (name) {
+#ifdef _WIN32
+ wchar_t* wname = cmsysEncoding_DupToWide(name);
+ lexer->file = _wfopen(wname, L"rb");
+ free(wname);
+#else
+ lexer->file = fopen(name, "rb");
+#endif
+ if (lexer->file) {
+ if (bom) {
+ *bom = cmListFileLexer_ReadBOM(lexer->file);
+ }
+ } else {
+ result = 0;
+ }
+ }
+ cmListFileLexerInit(lexer);
+ return result;
+}
+
+/*--------------------------------------------------------------------------*/
+int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text)
+{
+ int result = 1;
+ cmListFileLexerDestroy(lexer);
+ if (text) {
+ int length = (int)strlen(text);
+ lexer->string_buffer = (char*)malloc(length + 1);
+ if (lexer->string_buffer) {
+ strcpy(lexer->string_buffer, text);
+ lexer->string_position = lexer->string_buffer;
+ lexer->string_left = length;
+ } else {
+ result = 0;
+ }
+ }
+ cmListFileLexerInit(lexer);
+ return result;
+}
+
+/*--------------------------------------------------------------------------*/
+cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
+{
+ if (!lexer->file && !lexer->string_buffer) {
+ return 0;
+ }
+ if (cmListFileLexer_yylex(lexer->scanner, lexer)) {
+ return &lexer->token;
+ } else {
+ cmListFileLexer_SetFileName(lexer, 0, 0);
+ return 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer)
+{
+ return lexer->line;
+}
+
+/*--------------------------------------------------------------------------*/
+long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer)
+{
+ return lexer->column;
+}
+
+/*--------------------------------------------------------------------------*/
+const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer,
+ cmListFileLexer_Type type)
+{
+ (void)lexer;
+ switch (type) {
+ case cmListFileLexer_Token_None:
+ return "nothing";
+ case cmListFileLexer_Token_Space:
+ return "space";
+ case cmListFileLexer_Token_Newline:
+ return "newline";
+ case cmListFileLexer_Token_Identifier:
+ return "identifier";
+ case cmListFileLexer_Token_ParenLeft:
+ return "left paren";
+ case cmListFileLexer_Token_ParenRight:
+ return "right paren";
+ case cmListFileLexer_Token_ArgumentUnquoted:
+ return "unquoted argument";
+ case cmListFileLexer_Token_ArgumentQuoted:
+ return "quoted argument";
+ case cmListFileLexer_Token_ArgumentBracket:
+ return "bracket argument";
+ case cmListFileLexer_Token_CommentBracket:
+ return "bracket comment";
+ case cmListFileLexer_Token_BadCharacter:
+ return "bad character";
+ case cmListFileLexer_Token_BadBracket:
+ return "unterminated bracket";
+ case cmListFileLexer_Token_BadString:
+ return "unterminated string";
+ }
+ return "unknown token";
+}
diff --git a/Source/Modules/CheckCXXLinkerFlag.cmake b/Source/Modules/CheckCXXLinkerFlag.cmake
new file mode 100644
index 0000000..6cb1ba3
--- /dev/null
+++ b/Source/Modules/CheckCXXLinkerFlag.cmake
@@ -0,0 +1,29 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include_guard(GLOBAL)
+include(CheckCXXSourceCompiles)
+include(CMakeCheckCompilerFlagCommonPatterns)
+
+function(check_cxx_linker_flag _flag _var)
+ if(CMAKE_VERSION VERSION_LESS "3.14")
+ set(CMAKE_REQUIRED_LIBRARIES "${_flag}")
+ else()
+ set(CMAKE_REQUIRED_LINK_OPTIONS "${_flag}")
+ endif()
+
+ # 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}
+ ${_common_patterns}
+ )
+ foreach(v IN LISTS _locale_vars)
+ set(ENV{${v}} ${_locale_vars_saved_${v}})
+ endforeach()
+ set(${_var} "${${_var}}" PARENT_SCOPE)
+endfunction()
diff --git a/Source/Modules/FindJsonCpp.cmake b/Source/Modules/FindJsonCpp.cmake
new file mode 100644
index 0000000..1951b61
--- /dev/null
+++ b/Source/Modules/FindJsonCpp.cmake
@@ -0,0 +1,107 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindJsonCpp
+-----------
+
+Find JsonCpp includes and library.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+An :ref:`imported target <Imported targets>` named
+``JsonCpp::JsonCpp`` is provided if JsonCpp has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``JsonCpp_FOUND``
+ True if JsonCpp was found, false otherwise.
+``JsonCpp_INCLUDE_DIRS``
+ Include directories needed to include JsonCpp headers.
+``JsonCpp_LIBRARIES``
+ Libraries needed to link to JsonCpp.
+``JsonCpp_VERSION_STRING``
+ The version of JsonCpp found.
+ May not be set for JsonCpp versions prior to 1.0.
+``JsonCpp_VERSION_MAJOR``
+ The major version of JsonCpp.
+``JsonCpp_VERSION_MINOR``
+ The minor version of JsonCpp.
+``JsonCpp_VERSION_PATCH``
+ The patch version of JsonCpp.
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+This module uses the following cache variables:
+
+``JsonCpp_LIBRARY``
+ The location of the JsonCpp library file.
+``JsonCpp_INCLUDE_DIR``
+ The location of the JsonCpp include directory containing ``json/json.h``.
+
+The cache variables should not be used by project code.
+They may be set by end users to point at JsonCpp components.
+#]=======================================================================]
+
+#-----------------------------------------------------------------------------
+find_library(JsonCpp_LIBRARY
+ NAMES jsoncpp
+ )
+mark_as_advanced(JsonCpp_LIBRARY)
+
+find_path(JsonCpp_INCLUDE_DIR
+ NAMES json/json.h
+ PATH_SUFFIXES jsoncpp
+ )
+mark_as_advanced(JsonCpp_INCLUDE_DIR)
+
+#-----------------------------------------------------------------------------
+# Extract version number if possible.
+set(_JsonCpp_H_REGEX "^#[ \t]*define[ \t]+JSONCPP_VERSION_STRING[ \t]+\"(([0-9]+)\\.([0-9]+)\\.([0-9]+)[^\"]*)\".*$")
+if(JsonCpp_INCLUDE_DIR AND EXISTS "${JsonCpp_INCLUDE_DIR}/json/version.h")
+ file(STRINGS "${JsonCpp_INCLUDE_DIR}/json/version.h" _JsonCpp_H REGEX "${_JsonCpp_H_REGEX}")
+else()
+ set(_JsonCpp_H "")
+endif()
+if(_JsonCpp_H MATCHES "${_JsonCpp_H_REGEX}")
+ set(JsonCpp_VERSION_STRING "${CMAKE_MATCH_1}")
+ set(JsonCpp_VERSION_MAJOR "${CMAKE_MATCH_2}")
+ set(JsonCpp_VERSION_MINOR "${CMAKE_MATCH_3}")
+ set(JsonCpp_VERSION_PATCH "${CMAKE_MATCH_4}")
+else()
+ set(JsonCpp_VERSION_STRING "")
+ set(JsonCpp_VERSION_MAJOR "")
+ set(JsonCpp_VERSION_MINOR "")
+ set(JsonCpp_VERSION_PATCH "")
+endif()
+unset(_JsonCpp_H_REGEX)
+unset(_JsonCpp_H)
+
+#-----------------------------------------------------------------------------
+include(${CMAKE_CURRENT_LIST_DIR}/../../Modules/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(JsonCpp
+ FOUND_VAR JsonCpp_FOUND
+ REQUIRED_VARS JsonCpp_LIBRARY JsonCpp_INCLUDE_DIR
+ VERSION_VAR JsonCpp_VERSION_STRING
+ )
+set(JSONCPP_FOUND ${JsonCpp_FOUND})
+
+#-----------------------------------------------------------------------------
+# Provide documented result variables and targets.
+if(JsonCpp_FOUND)
+ set(JsonCpp_INCLUDE_DIRS ${JsonCpp_INCLUDE_DIR})
+ set(JsonCpp_LIBRARIES ${JsonCpp_LIBRARY})
+ if(NOT TARGET JsonCpp::JsonCpp)
+ add_library(JsonCpp::JsonCpp UNKNOWN IMPORTED)
+ set_target_properties(JsonCpp::JsonCpp PROPERTIES
+ IMPORTED_LOCATION "${JsonCpp_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${JsonCpp_INCLUDE_DIRS}"
+ IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
+ )
+ endif()
+endif()
diff --git a/Source/Modules/FindLibRHash.cmake b/Source/Modules/FindLibRHash.cmake
new file mode 100644
index 0000000..86c6189
--- /dev/null
+++ b/Source/Modules/FindLibRHash.cmake
@@ -0,0 +1,73 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLibRHash
+------------
+
+Find LibRHash include directory and library.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+An :ref:`imported target <Imported targets>` named
+``LibRHash::LibRHash`` is provided if LibRHash has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``LibRHash_FOUND``
+ True if LibRHash was found, false otherwise.
+``LibRHash_INCLUDE_DIRS``
+ Include directories needed to include LibRHash headers.
+``LibRHash_LIBRARIES``
+ Libraries needed to link to LibRHash.
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+This module uses the following cache variables:
+
+``LibRHash_LIBRARY``
+ The location of the LibRHash library file.
+``LibRHash_INCLUDE_DIR``
+ The location of the LibRHash include directory containing ``rhash.h``.
+
+The cache variables should not be used by project code.
+They may be set by end users to point at LibRHash components.
+#]=======================================================================]
+
+#-----------------------------------------------------------------------------
+find_library(LibRHash_LIBRARY
+ NAMES rhash
+ )
+mark_as_advanced(LibRHash_LIBRARY)
+
+find_path(LibRHash_INCLUDE_DIR
+ NAMES rhash.h
+ )
+mark_as_advanced(LibRHash_INCLUDE_DIR)
+
+#-----------------------------------------------------------------------------
+include(${CMAKE_CURRENT_LIST_DIR}/../../Modules/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibRHash
+ FOUND_VAR LibRHash_FOUND
+ REQUIRED_VARS LibRHash_LIBRARY LibRHash_INCLUDE_DIR
+ )
+set(LIBRHASH_FOUND ${LibRHash_FOUND})
+
+#-----------------------------------------------------------------------------
+# Provide documented result variables and targets.
+if(LibRHash_FOUND)
+ set(LibRHash_INCLUDE_DIRS ${LibRHash_INCLUDE_DIR})
+ set(LibRHash_LIBRARIES ${LibRHash_LIBRARY})
+ if(NOT TARGET LibRHash::LibRHash)
+ add_library(LibRHash::LibRHash UNKNOWN IMPORTED)
+ set_target_properties(LibRHash::LibRHash PROPERTIES
+ IMPORTED_LOCATION "${LibRHash_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${LibRHash_INCLUDE_DIRS}"
+ )
+ endif()
+endif()
diff --git a/Source/Modules/FindLibUUID.cmake b/Source/Modules/FindLibUUID.cmake
new file mode 100644
index 0000000..17f11c1
--- /dev/null
+++ b/Source/Modules/FindLibUUID.cmake
@@ -0,0 +1,85 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLibUUID
+------------
+
+Find LibUUID include directory and library.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+An :ref:`imported target <Imported targets>` named
+``LibUUID::LibUUID`` is provided if LibUUID has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``LibUUID_FOUND``
+ True if LibUUID was found, false otherwise.
+``LibUUID_INCLUDE_DIRS``
+ Include directories needed to include LibUUID headers.
+``LibUUID_LIBRARIES``
+ Libraries needed to link to LibUUID.
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+This module uses the following cache variables:
+
+``LibUUID_LIBRARY``
+ The location of the LibUUID library file.
+``LibUUID_INCLUDE_DIR``
+ The location of the LibUUID include directory containing ``uuid/uuid.h``.
+
+The cache variables should not be used by project code.
+They may be set by end users to point at LibUUID components.
+#]=======================================================================]
+
+#-----------------------------------------------------------------------------
+if(CYGWIN)
+ # Note: on current version of Cygwin, linking to libuuid.dll.a doesn't
+ # import the right symbols sometimes. Fix this by linking directly
+ # to the DLL that provides the symbols, instead.
+ set(old_suffixes ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .dll)
+ find_library(LibUUID_LIBRARY
+ NAMES cyguuid-1.dll
+ )
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ${old_suffixes})
+else()
+ find_library(LibUUID_LIBRARY
+ NAMES uuid
+ )
+endif()
+mark_as_advanced(LibUUID_LIBRARY)
+
+find_path(LibUUID_INCLUDE_DIR
+ NAMES uuid/uuid.h
+ )
+mark_as_advanced(LibUUID_INCLUDE_DIR)
+
+#-----------------------------------------------------------------------------
+include(${CMAKE_CURRENT_LIST_DIR}/../../Modules/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibUUID
+ FOUND_VAR LibUUID_FOUND
+ REQUIRED_VARS LibUUID_LIBRARY LibUUID_INCLUDE_DIR
+ )
+set(LIBUUID_FOUND ${LibUUID_FOUND})
+
+#-----------------------------------------------------------------------------
+# Provide documented result variables and targets.
+if(LibUUID_FOUND)
+ set(LibUUID_INCLUDE_DIRS ${LibUUID_INCLUDE_DIR})
+ set(LibUUID_LIBRARIES ${LibUUID_LIBRARY})
+ if(NOT TARGET LibUUID::LibUUID)
+ add_library(LibUUID::LibUUID UNKNOWN IMPORTED)
+ set_target_properties(LibUUID::LibUUID PROPERTIES
+ IMPORTED_LOCATION "${LibUUID_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${LibUUID_INCLUDE_DIRS}"
+ )
+ endif()
+endif()
diff --git a/Source/Modules/FindLibUV.cmake b/Source/Modules/FindLibUV.cmake
new file mode 100644
index 0000000..0554d62
--- /dev/null
+++ b/Source/Modules/FindLibUV.cmake
@@ -0,0 +1,123 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLibUV
+---------
+
+Find libuv includes and library.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+An :ref:`imported target <Imported targets>` named
+``LibUV::LibUV`` is provided if libuv has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``LibUV_FOUND``
+ True if libuv was found, false otherwise.
+``LibUV_INCLUDE_DIRS``
+ Include directories needed to include libuv headers.
+``LibUV_LIBRARIES``
+ Libraries needed to link to libuv.
+``LibUV_VERSION``
+ The version of libuv found.
+``LibUV_VERSION_MAJOR``
+ The major version of libuv.
+``LibUV_VERSION_MINOR``
+ The minor version of libuv.
+``LibUV_VERSION_PATCH``
+ The patch version of libuv.
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+This module uses the following cache variables:
+
+``LibUV_LIBRARY``
+ The location of the libuv library file.
+``LibUV_INCLUDE_DIR``
+ The location of the libuv include directory containing ``uv.h``.
+
+The cache variables should not be used by project code.
+They may be set by end users to point at libuv components.
+#]=======================================================================]
+
+#-----------------------------------------------------------------------------
+find_library(LibUV_LIBRARY
+ NAMES uv libuv
+ )
+mark_as_advanced(LibUV_LIBRARY)
+
+find_path(LibUV_INCLUDE_DIR
+ NAMES uv.h
+ )
+mark_as_advanced(LibUV_INCLUDE_DIR)
+
+#-----------------------------------------------------------------------------
+# Extract version number if possible.
+set(_LibUV_H_REGEX "#[ \t]*define[ \t]+UV_VERSION_(MAJOR|MINOR|PATCH)[ \t]+[0-9]+")
+if(LibUV_INCLUDE_DIR AND EXISTS "${LibUV_INCLUDE_DIR}/uv-version.h")
+ file(STRINGS "${LibUV_INCLUDE_DIR}/uv-version.h" _LibUV_H REGEX "${_LibUV_H_REGEX}")
+elseif(LibUV_INCLUDE_DIR AND EXISTS "${LibUV_INCLUDE_DIR}/uv/version.h")
+ file(STRINGS "${LibUV_INCLUDE_DIR}/uv/version.h" _LibUV_H REGEX "${_LibUV_H_REGEX}")
+elseif(LibUV_INCLUDE_DIR AND EXISTS "${LibUV_INCLUDE_DIR}/uv.h")
+ file(STRINGS "${LibUV_INCLUDE_DIR}/uv.h" _LibUV_H REGEX "${_LibUV_H_REGEX}")
+else()
+ set(_LibUV_H "")
+endif()
+foreach(c MAJOR MINOR PATCH)
+ if(_LibUV_H MATCHES "#[ \t]*define[ \t]+UV_VERSION_${c}[ \t]+([0-9]+)")
+ set(_LibUV_VERSION_${c} "${CMAKE_MATCH_1}")
+ else()
+ unset(_LibUV_VERSION_${c})
+ endif()
+endforeach()
+if(DEFINED _LibUV_VERSION_MAJOR AND DEFINED _LibUV_VERSION_MINOR)
+ set(LibUV_VERSION_MAJOR "${_LibUV_VERSION_MAJOR}")
+ set(LibUV_VERSION_MINOR "${_LibUV_VERSION_MINOR}")
+ set(LibUV_VERSION "${LibUV_VERSION_MAJOR}.${LibUV_VERSION_MINOR}")
+ if(DEFINED _LibUV_VERSION_PATCH)
+ set(LibUV_VERSION_PATCH "${_LibUV_VERSION_PATCH}")
+ set(LibUV_VERSION "${LibUV_VERSION}.${LibUV_VERSION_PATCH}")
+ else()
+ unset(LibUV_VERSION_PATCH)
+ endif()
+else()
+ set(LibUV_VERSION_MAJOR "")
+ set(LibUV_VERSION_MINOR "")
+ set(LibUV_VERSION_PATCH "")
+ set(LibUV_VERSION "")
+endif()
+unset(_LibUV_VERSION_MAJOR)
+unset(_LibUV_VERSION_MINOR)
+unset(_LibUV_VERSION_PATCH)
+unset(_LibUV_H_REGEX)
+unset(_LibUV_H)
+
+#-----------------------------------------------------------------------------
+include(${CMAKE_CURRENT_LIST_DIR}/../../Modules/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibUV
+ FOUND_VAR LibUV_FOUND
+ REQUIRED_VARS LibUV_LIBRARY LibUV_INCLUDE_DIR
+ VERSION_VAR LibUV_VERSION
+ )
+set(LIBUV_FOUND ${LibUV_FOUND})
+
+#-----------------------------------------------------------------------------
+# Provide documented result variables and targets.
+if(LibUV_FOUND)
+ set(LibUV_INCLUDE_DIRS ${LibUV_INCLUDE_DIR})
+ set(LibUV_LIBRARIES ${LibUV_LIBRARY})
+ if(NOT TARGET LibUV::LibUV)
+ add_library(LibUV::LibUV UNKNOWN IMPORTED)
+ set_target_properties(LibUV::LibUV PROPERTIES
+ IMPORTED_LOCATION "${LibUV_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${LibUV_INCLUDE_DIRS}"
+ )
+ endif()
+endif()
diff --git a/Source/Modules/OverrideC.cmake b/Source/Modules/OverrideC.cmake
new file mode 100644
index 0000000..f8299ad
--- /dev/null
+++ b/Source/Modules/OverrideC.cmake
@@ -0,0 +1,3 @@
+if("${CMAKE_SYSTEM_NAME};${CMAKE_C_COMPILER_ID}" STREQUAL "AIX;GNU")
+ string(APPEND CMAKE_C_FLAGS_INIT " -pthread")
+endif()
diff --git a/Source/Modules/OverrideCXX.cmake b/Source/Modules/OverrideCXX.cmake
new file mode 100644
index 0000000..13689e2
--- /dev/null
+++ b/Source/Modules/OverrideCXX.cmake
@@ -0,0 +1,3 @@
+if("${CMAKE_SYSTEM_NAME};${CMAKE_CXX_COMPILER_ID}" STREQUAL "AIX;GNU")
+ string(APPEND CMAKE_CXX_FLAGS_INIT " -pthread")
+endif()
diff --git a/Source/QtDialog/AddCacheEntry.cxx b/Source/QtDialog/AddCacheEntry.cxx
new file mode 100644
index 0000000..1075895
--- /dev/null
+++ b/Source/QtDialog/AddCacheEntry.cxx
@@ -0,0 +1,101 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "AddCacheEntry.h"
+
+#include <QCompleter>
+#include <QMetaProperty>
+
+static const int NumTypes = 4;
+static const int DefaultTypeIndex = 0;
+static const QByteArray TypeStrings[NumTypes] = { "BOOL", "PATH", "FILEPATH",
+ "STRING" };
+static const QCMakeProperty::PropertyType Types[NumTypes] = {
+ QCMakeProperty::BOOL, QCMakeProperty::PATH, QCMakeProperty::FILEPATH,
+ QCMakeProperty::STRING
+};
+
+AddCacheEntry::AddCacheEntry(QWidget* p, const QStringList& varNames,
+ const QStringList& varTypes)
+ : QWidget(p)
+ , VarNames(varNames)
+ , VarTypes(varTypes)
+{
+ this->setupUi(this);
+ for (auto const& elem : TypeStrings) {
+ this->Type->addItem(elem);
+ }
+ QWidget* cb = new QCheckBox();
+ QWidget* path = new QCMakePathEditor();
+ QWidget* filepath = new QCMakeFilePathEditor();
+ QWidget* string = new QLineEdit();
+ this->StackedWidget->addWidget(cb);
+ this->StackedWidget->addWidget(path);
+ this->StackedWidget->addWidget(filepath);
+ this->StackedWidget->addWidget(string);
+ AddCacheEntry::setTabOrder(this->Name, this->Type);
+ AddCacheEntry::setTabOrder(this->Type, cb);
+ AddCacheEntry::setTabOrder(cb, path);
+ AddCacheEntry::setTabOrder(path, filepath);
+ AddCacheEntry::setTabOrder(filepath, string);
+ AddCacheEntry::setTabOrder(string, this->Description);
+ QCompleter* completer = new QCompleter(this->VarNames, this);
+ this->Name->setCompleter(completer);
+ connect(
+ completer,
+ static_cast<void (QCompleter::*)(const QString&)>(&QCompleter::activated),
+ this, &AddCacheEntry::onCompletionActivated);
+}
+
+QString AddCacheEntry::name() const
+{
+ return this->Name->text().trimmed();
+}
+
+QVariant AddCacheEntry::value() const
+{
+ QWidget* w = this->StackedWidget->currentWidget();
+ if (qobject_cast<QLineEdit*>(w)) {
+ return static_cast<QLineEdit*>(w)->text();
+ }
+ if (qobject_cast<QCheckBox*>(w)) {
+ return static_cast<QCheckBox*>(w)->isChecked();
+ }
+ return QVariant();
+}
+
+QString AddCacheEntry::description() const
+{
+ return this->Description->text();
+}
+
+QCMakeProperty::PropertyType AddCacheEntry::type() const
+{
+ int idx = this->Type->currentIndex();
+ if (idx >= 0 && idx < NumTypes) {
+ return Types[idx];
+ }
+ return Types[DefaultTypeIndex];
+}
+
+QString AddCacheEntry::typeString() const
+{
+ int idx = this->Type->currentIndex();
+ if (idx >= 0 && idx < NumTypes) {
+ return TypeStrings[idx];
+ }
+ return TypeStrings[DefaultTypeIndex];
+}
+
+void AddCacheEntry::onCompletionActivated(const QString& text)
+{
+ int idx = this->VarNames.indexOf(text);
+ if (idx != -1) {
+ QString vartype = this->VarTypes[idx];
+ for (int i = 0; i < NumTypes; i++) {
+ if (TypeStrings[i] == vartype) {
+ this->Type->setCurrentIndex(i);
+ break;
+ }
+ }
+ }
+}
diff --git a/Source/QtDialog/AddCacheEntry.h b/Source/QtDialog/AddCacheEntry.h
new file mode 100644
index 0000000..35522c5
--- /dev/null
+++ b/Source/QtDialog/AddCacheEntry.h
@@ -0,0 +1,33 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "QCMake.h"
+#include <QCheckBox>
+#include <QStringList>
+#include <QWidget>
+
+#include "ui_AddCacheEntry.h"
+
+class AddCacheEntry
+ : public QWidget
+ , public Ui::AddCacheEntry
+{
+ Q_OBJECT
+public:
+ AddCacheEntry(QWidget* p, const QStringList& varNames,
+ const QStringList& varTypes);
+
+ QString name() const;
+ QVariant value() const;
+ QString description() const;
+ QCMakeProperty::PropertyType type() const;
+ QString typeString() const;
+
+private slots:
+ void onCompletionActivated(const QString& text);
+
+private:
+ const QStringList& VarNames;
+ const QStringList& VarTypes;
+};
diff --git a/Source/QtDialog/AddCacheEntry.ui b/Source/QtDialog/AddCacheEntry.ui
new file mode 100644
index 0000000..a815874
--- /dev/null
+++ b/Source/QtDialog/AddCacheEntry.ui
@@ -0,0 +1,97 @@
+<ui version="4.0" >
+ <class>AddCacheEntry</class>
+ <widget class="QWidget" name="AddCacheEntry" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>380</width>
+ <height>158</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="Name" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Type:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="Type" >
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>Value:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QStackedWidget" name="StackedWidget" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Description:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLineEdit" name="Description" />
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QCMakePathEditor</class>
+ <extends>QLineEdit</extends>
+ <header>QCMakeWidgets.h</header>
+ </customwidget>
+ <customwidget>
+ <class>QCMakeFilePathEditor</class>
+ <extends>QLineEdit</extends>
+ <header>QCMakeWidgets.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>Type</sender>
+ <signal>currentIndexChanged(int)</signal>
+ <receiver>StackedWidget</receiver>
+ <slot>setCurrentIndex(int)</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>229</x>
+ <y>34</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>287</x>
+ <y>65</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/Source/QtDialog/CMakeGUIExec.cxx b/Source/QtDialog/CMakeGUIExec.cxx
new file mode 100644
index 0000000..1572112
--- /dev/null
+++ b/Source/QtDialog/CMakeGUIExec.cxx
@@ -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. */
+
+#include <QApplication>
+
+class CMakeSetupDialog;
+
+void SetupDefaultQSettings()
+{
+}
+
+int CMakeGUIExec(CMakeSetupDialog* /*window*/)
+{
+ return QApplication::exec();
+}
diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt
new file mode 100644
index 0000000..0c263bb
--- /dev/null
+++ b/Source/QtDialog/CMakeLists.txt
@@ -0,0 +1,352 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+project(QtDialog)
+CMake_OPTIONAL_COMPONENT(cmake-gui)
+set (QT_COMPONENTS
+ Core
+ Widgets
+ Gui
+)
+
+set(CMake_QT_MAJOR_VERSION "A" CACHE
+ STRING "Expected Qt major version. Valid values are A (auto-select), 5, 6.")
+set(SUPPORTED_QT_VERSIONS "A" 5 6)
+set_property(CACHE CMake_QT_MAJOR_VERSION PROPERTY STRINGS ${SUPPORTED_QT_VERSIONS})
+if(NOT CMake_QT_MAJOR_VERSION STREQUAL "A")
+ if(NOT CMake_QT_MAJOR_VERSION IN_LIST SUPPORTED_QT_VERSIONS)
+ message(FATAL_ERROR "Supported Qt versions are \"${SUPPORTED_QT_VERSIONS}\"."
+ " But CMake_QT_MAJOR_VERSION is set to ${CMake_QT_MAJOR_VERSION}.")
+ endif()
+ set(INSTALLED_QT_VERSION ${CMake_QT_MAJOR_VERSION})
+else()
+ find_package(Qt6Widgets QUIET)
+ set(INSTALLED_QT_VERSION 6)
+ if(NOT Qt6Widgets_FOUND)
+ find_package(Qt5Widgets QUIET)
+ if(NOT Qt5Widgets_FOUND)
+ message(FATAL_ERROR "Could not find a valid Qt installation.")
+ endif()
+ set(INSTALLED_QT_VERSION 5)
+ endif()
+endif()
+
+find_package(Qt${INSTALLED_QT_VERSION}
+ COMPONENTS ${QT_COMPONENTS}
+ REQUIRED QUIET
+)
+
+set(CMake_QT_EXTRA_LIBRARIES)
+
+# Try to find the package WinExtras for the task bar progress
+if(WIN32)
+ find_package(Qt${INSTALLED_QT_VERSION}WinExtras QUIET)
+ if (Qt${INSTALLED_QT_VERSION}WinExtras_FOUND)
+ add_definitions(-DQT_WINEXTRAS)
+ list(APPEND CMake_QT_EXTRA_LIBRARIES Qt${INSTALLED_QT_VERSION}::WinExtras)
+ list(APPEND QT_COMPONENTS WinExtras)
+ endif()
+endif()
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt${INSTALLED_QT_VERSION}Widgets_EXECUTABLE_COMPILE_FLAGS}")
+
+if(CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES)
+ list(APPEND CMake_QT_EXTRA_LIBRARIES ${CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES})
+ set_property(SOURCE CMakeSetup.cxx
+ PROPERTY COMPILE_DEFINITIONS USE_QXcbIntegrationPlugin)
+endif()
+
+if(CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES)
+ list(APPEND CMake_QT_EXTRA_LIBRARIES ${CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES})
+ set_property(SOURCE CMakeSetup.cxx
+ PROPERTY COMPILE_DEFINITIONS USE_QWindowsIntegrationPlugin)
+endif()
+
+# We need to install platform plugin and add qt.conf for Qt5 on Mac and Windows.
+if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32))
+ function(_qt_get_plugin_name_with_version target out_var)
+ string(REGEX REPLACE "^Qt::(.+)" "Qt${INSTALLED_QT_VERSION}::\\1"
+ qt_plugin_with_version "${target}")
+ if(TARGET "${qt_plugin_with_version}")
+ set("${out_var}" "${qt_plugin_with_version}" PARENT_SCOPE)
+ else()
+ set("${out_var}" "" PARENT_SCOPE)
+ endif()
+ endfunction()
+ macro(install_qt_plugin _qt_plugin_name _qt_plugins_var)
+ if(TARGET "${_qt_plugin_name}")
+ get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION)
+ else()
+ _qt_get_plugin_name_with_version("Qt::${_qt_plugin_name}" _qt_plugin_with_version_name)
+ if(TARGET "${_qt_plugin_with_version_name}")
+ get_target_property(_qt_plugin_path "${_qt_plugin_with_version_name}" LOCATION)
+ endif()
+ endif()
+ if(EXISTS "${_qt_plugin_path}")
+ get_filename_component(_qt_plugin_file "${_qt_plugin_path}" NAME)
+ get_filename_component(_qt_plugin_type "${_qt_plugin_path}" PATH)
+ get_filename_component(_qt_plugin_type "${_qt_plugin_type}" NAME)
+ if(APPLE)
+ set(_qt_plugin_dir "PlugIns")
+ elseif(WIN32)
+ set(_qt_plugin_dir "plugins")
+ endif()
+ set(_qt_plugin_dest "${_qt_plugin_dir}/${_qt_plugin_type}")
+ install(FILES "${_qt_plugin_path}"
+ DESTINATION "${_qt_plugin_dest}"
+ ${COMPONENT})
+ set(${_qt_plugins_var}
+ "${${_qt_plugins_var}};\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${_qt_plugin_dest}/${_qt_plugin_file}")
+ endif()
+ endmacro()
+ macro(install_qt_plugins _comps _plugins_var)
+ foreach(_qt_comp ${${_comps}})
+ if (INSTALLED_QT_VERSION VERSION_LESS 6)
+ set(_qt_module_plugins ${Qt${INSTALLED_QT_VERSION}${_qt_comp}_PLUGINS})
+ else()
+ get_target_property(_qt_module_plugins Qt${INSTALLED_QT_VERSION}::${_qt_comp} QT_PLUGINS)
+ endif()
+ foreach(_qt_plugin ${_qt_module_plugins})
+ if (INSTALLED_QT_VERSION VERSION_GREATER_EQUAL 6)
+ # Qt6 provides the plugins as individual packages that need to be found.
+ find_package(Qt${INSTALLED_QT_VERSION}${_qt_plugin} QUIET
+ PATHS ${Qt${INSTALLED_QT_VERSION}${_qt_comp}_DIR})
+ endif()
+ install_qt_plugin("${_qt_plugin}" "${_plugins_var}")
+ endforeach()
+ endforeach()
+ endmacro()
+ if(APPLE)
+ if (INSTALLED_QT_VERSION VERSION_EQUAL 5)
+ install_qt_plugin("Qt5::QCocoaIntegrationPlugin" QT_PLUGINS)
+ if(TARGET Qt5::QMacStylePlugin)
+ install_qt_plugin("Qt5::QMacStylePlugin" QT_PLUGINS)
+ endif()
+ else()
+ # FIXME: Minimize plugins for Qt6.
+ install_qt_plugins(QT_COMPONENTS QT_PLUGINS)
+ endif()
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
+ "[Paths]\nPlugins = ${_qt_plugin_dir}\n")
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/Resources"
+ ${COMPONENT})
+ elseif(WIN32 AND NOT CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES)
+ if (INSTALLED_QT_VERSION VERSION_EQUAL 5)
+ install_qt_plugin("Qt5::QWindowsIntegrationPlugin" QT_PLUGINS)
+ else()
+ # FIXME: Minimize plugins for Qt6.
+ install_qt_plugins(QT_COMPONENTS QT_PLUGINS)
+ endif()
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
+ "[Paths]\nPlugins = ../${_qt_plugin_dir}\n")
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
+ DESTINATION bin
+ ${COMPONENT})
+ endif()
+endif()
+
+get_property(_Qt_Core_LOCATION TARGET Qt${INSTALLED_QT_VERSION}::Core PROPERTY LOCATION)
+get_filename_component(Qt_BIN_DIR "${_Qt_Core_LOCATION}" PATH)
+if(APPLE)
+ get_filename_component(Qt_BIN_DIR "${Qt_BIN_DIR}" PATH)
+endif()
+
+set(SRCS
+ AddCacheEntry.cxx
+ AddCacheEntry.h
+ CMakeSetupDialog.cxx
+ CMakeSetupDialog.h
+ Compilers.h
+ EnvironmentDialog.cxx
+ EnvironmentDialog.h
+ FirstConfigure.cxx
+ FirstConfigure.h
+ QCMake.cxx
+ QCMake.h
+ QCMakeCacheView.cxx
+ QCMakeCacheView.h
+ QCMakePreset.cxx
+ QCMakePreset.h
+ QCMakePresetComboBox.cxx
+ QCMakePresetComboBox.h
+ QCMakePresetItemModel.cxx
+ QCMakePresetItemModel.h
+ QCMakeWidgets.cxx
+ QCMakeWidgets.h
+ RegexExplorer.cxx
+ RegexExplorer.h
+ WarningMessagesDialog.cxx
+ WarningMessagesDialog.h
+ )
+set(UI_SRCS
+ CMakeSetupDialog.ui
+ Compilers.ui
+ CrossCompiler.ui
+ AddCacheEntry.ui
+ EnvironmentDialog.ui
+ RegexExplorer.ui
+ WarningMessagesDialog.ui
+ )
+set(MOC_SRCS
+ AddCacheEntry.h
+ Compilers.h
+ CMakeSetupDialog.h
+ EnvironmentDialog.h
+ FirstConfigure.h
+ QCMake.h
+ QCMakeCacheView.h
+ QCMakePresetComboBox.h
+ QCMakePresetItemModel.h
+ QCMakeWidgets.h
+ RegexExplorer.h
+ WarningMessagesDialog.h
+ )
+set(QRC_SRCS CMakeSetup.qrc)
+
+if (INSTALLED_QT_VERSION VERSION_LESS 6)
+ qt5_wrap_ui(UI_BUILT_SRCS ${UI_SRCS})
+ qt5_wrap_cpp(MOC_BUILT_SRCS ${MOC_SRCS})
+ qt5_add_resources(QRC_BUILT_SRCS ${QRC_SRCS})
+else()
+ qt_wrap_ui(UI_BUILT_SRCS ${UI_SRCS})
+ qt_wrap_cpp(MOC_BUILT_SRCS ${MOC_SRCS})
+ qt_add_resources(QRC_BUILT_SRCS ${QRC_SRCS})
+endif()
+add_library(CMakeGUIQRCLib OBJECT ${QRC_BUILT_SRCS})
+
+if (FALSE) # CMake's bootstrap binary does not support automoc
+ set(CMAKE_AUTOMOC 1)
+ set(CMAKE_AUTORCC 1)
+ set(CMAKE_AUTOUIC 1)
+else ()
+ list(APPEND SRCS
+ ${UI_BUILT_SRCS}
+ ${MOC_BUILT_SRCS})
+endif ()
+
+if(USE_LGPL)
+ install(FILES ${CMake_SOURCE_DIR}/Licenses/LGPLv${USE_LGPL}.txt
+ DESTINATION ${CMAKE_DATA_DIR}/Licenses
+ ${COMPONENT})
+ set_property(SOURCE CMakeSetupDialog.cxx
+ PROPERTY COMPILE_DEFINITIONS USE_LGPL="${USE_LGPL}")
+endif()
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_library(CMakeGUILib STATIC ${SRCS})
+# CMake_QT_EXTRA_LIBRARIES have to come before the main libraries on the link line
+target_link_libraries(CMakeGUILib PUBLIC CMakeLib ${CMake_QT_EXTRA_LIBRARIES}
+ Qt${INSTALLED_QT_VERSION}::Core Qt${INSTALLED_QT_VERSION}::Widgets)
+
+add_library(CMakeGUIMainLib STATIC CMakeSetup.cxx)
+target_link_libraries(CMakeGUIMainLib PUBLIC CMakeGUILib)
+
+add_executable(cmake-gui WIN32 MACOSX_BUNDLE CMakeGUIExec.cxx ${MANIFEST_FILE})
+target_link_libraries(cmake-gui CMakeGUIMainLib Qt${INSTALLED_QT_VERSION}::Core)
+
+target_sources(CMakeGUIMainLib INTERFACE $<TARGET_OBJECTS:CMakeGUIQRCLib>)
+if(WIN32)
+ target_sources(CMakeGUIMainLib INTERFACE $<TARGET_OBJECTS:CMakeVersion> CMakeSetup.rc)
+endif()
+if(APPLE)
+ target_sources(CMakeGUIMainLib INTERFACE CMakeSetup.icns)
+ set(MACOSX_BUNDLE_ICON_FILE CMakeSetup.icns)
+ set_source_files_properties(CMakeSetup.icns PROPERTIES
+ MACOSX_PACKAGE_LOCATION Resources)
+endif()
+
+if(CMake_JOB_POOL_LINK_BIN)
+ set_property(TARGET cmake-gui PROPERTY JOB_POOL_LINK "link-bin")
+endif()
+
+# cmake-gui has not been updated for `include-what-you-use`.
+# Block the tool until this is done.
+set_target_properties(CMakeGUILib CMakeGUIMainLib cmake-gui PROPERTIES
+ CXX_INCLUDE_WHAT_YOU_USE ""
+ )
+
+# Files generated by MOC, RCC, and UIC may produce clang-tidy warnings.
+# We generate a dummy .clang-tidy file in the binary directory that disables
+# all clang-tidy checks except one that will never match. This one check is
+# necessary; clang-tidy reports an error when no checks are enabled.
+# Since the Qt code generators will generate source files in the binary tree,
+# clang-tidy will load the configuration from this dummy file when the sources
+# are built.
+file(WRITE "${QtDialog_BINARY_DIR}/.clang-tidy" "
+---
+Checks: '-*,llvm-twine-local'
+...
+")
+
+if(APPLE)
+ file(STRINGS "${CMake_SOURCE_DIR}/Copyright.txt" copyright_line
+ LIMIT_COUNT 1 REGEX "^Copyright 2000-20[0-9][0-9] Kitware")
+
+ set_target_properties(cmake-gui PROPERTIES
+ OUTPUT_NAME CMake
+ MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in"
+ MACOSX_BUNDLE_SHORT_VERSION_STRING "${CMAKE_BUNDLE_VERSION}"
+ # TBD: MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_BUNDLE_VERSION}"
+ MACOSX_BUNDLE_COPYRIGHT "${copyright_line}"
+ MACOSX_BUNDLE_GUI_IDENTIFIER "org.cmake.cmake"
+ )
+
+ # Create a symlink in the build tree to provide a "cmake-gui" next
+ # to the "cmake" executable that refers to the application bundle.
+ add_custom_command(TARGET cmake-gui POST_BUILD
+ COMMAND ln -sf CMake.app/Contents/MacOS/CMake
+ $<TARGET_FILE_DIR:cmake>/cmake-gui
+ )
+endif()
+set(CMAKE_INSTALL_DESTINATION_ARGS
+ BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}" ${COMPONENT})
+
+install(TARGETS cmake-gui
+ RUNTIME DESTINATION bin ${COMPONENT}
+ ${CMAKE_INSTALL_DESTINATION_ARGS})
+
+if(UNIX AND NOT APPLE)
+ foreach (size IN ITEMS 32 128)
+ install(
+ FILES "${CMAKE_CURRENT_SOURCE_DIR}/CMakeSetup${size}.png"
+ DESTINATION "${CMAKE_XDGDATA_DIR}/icons/hicolor/${size}x${size}/apps"
+ ${COMPONENT}
+ RENAME "CMakeSetup.png")
+ endforeach ()
+
+ # install a desktop file so CMake appears in the application start menu
+ # with an icon
+ install(FILES cmake-gui.desktop
+ DESTINATION "${CMAKE_XDGDATA_DIR}/applications"
+ ${COMPONENT})
+ install(FILES cmakecache.xml
+ DESTINATION "${CMAKE_XDGDATA_DIR}/mime/packages"
+ ${COMPONENT})
+endif()
+
+if(APPLE)
+ install(CODE "
+ execute_process(COMMAND ln -s \"../MacOS/CMake\" cmake-gui
+ WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/bin)
+ " ${COMPONENT})
+endif()
+
+if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32))
+ # install rules for including 3rd party libs such as Qt
+ # if a system Qt is used (e.g. installed in /usr/lib/), it will not be included in the installation
+ set(fixup_exe "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/bin/cmake-gui${CMAKE_EXECUTABLE_SUFFIX}")
+ if(APPLE)
+ set(fixup_exe "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/MacOS/CMake")
+ endif()
+ install(CODE "
+ include(\"${CMake_SOURCE_DIR}/Modules/BundleUtilities.cmake\")
+ set(BU_CHMOD_BUNDLE_ITEMS ON)
+ fixup_bundle(\"${fixup_exe}\" \"${QT_PLUGINS}\" \"${Qt_BIN_DIR};${QT_LIBRARY_DIR};${QT_BINARY_DIR}\")
+ " ${COMPONENT})
+endif()
+
+set(CMAKE_PACKAGE_QTGUI TRUE)
+configure_file("${QtDialog_SOURCE_DIR}/QtDialogCPack.cmake.in"
+ "${QtDialog_BINARY_DIR}/QtDialogCPack.cmake" @ONLY)
diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx
new file mode 100644
index 0000000..5debdb8
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup.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 <iostream>
+
+#include "QCMake.h" // include to disable MS warnings
+#include <QApplication>
+#include <QDir>
+#include <QLocale>
+#include <QString>
+#include <QTranslator>
+#include <QtPlugin>
+
+#include "cmsys/CommandLineArguments.hxx"
+#include "cmsys/Encoding.hxx"
+#include "cmsys/SystemTools.hxx"
+
+#include "CMakeSetupDialog.h"
+#include "cmAlgorithms.h"
+#include "cmDocumentation.h"
+#include "cmDocumentationEntry.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h" // IWYU pragma: keep
+#include "cmake.h"
+
+static const char* cmDocumentationName[][2] = { { nullptr,
+ " cmake-gui - CMake GUI." },
+ { nullptr, nullptr } };
+
+static const char* cmDocumentationUsage[][2] = {
+ { nullptr,
+ " cmake-gui [options]\n"
+ " cmake-gui [options] <path-to-source>\n"
+ " cmake-gui [options] <path-to-existing-build>\n"
+ " cmake-gui [options] -S <path-to-source> -B <path-to-build>\n"
+ " cmake-gui [options] --browse-manual\n" },
+ { nullptr, nullptr }
+};
+
+static const char* cmDocumentationOptions[][2] = {
+ { "-S <path-to-source>", "Explicitly specify a source directory." },
+ { "-B <path-to-build>", "Explicitly specify a build directory." },
+ { "--preset=<preset>", "Specify a configure preset." },
+ { nullptr, nullptr }
+};
+
+#if defined(Q_OS_MAC)
+static int cmOSXInstall(std::string dir);
+static void cmAddPluginPath();
+#endif
+
+#if defined(USE_QXcbIntegrationPlugin)
+Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
+#endif
+
+#if defined(USE_QWindowsIntegrationPlugin)
+Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
+# if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
+Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin);
+# endif
+#endif
+
+int CMakeGUIExec(CMakeSetupDialog* window);
+void SetupDefaultQSettings();
+void OpenReferenceManual();
+
+int main(int argc, char** argv)
+{
+ cmSystemTools::EnsureStdPipes();
+ cmsys::Encoding::CommandLineArguments encoding_args =
+ cmsys::Encoding::CommandLineArguments::Main(argc, argv);
+ int argc2 = encoding_args.argc();
+ char const* const* argv2 = encoding_args.argv();
+
+ cmSystemTools::InitializeLibUV();
+ cmSystemTools::FindCMakeResources(argv2[0]);
+ // check docs first so that X is not need to get docs
+ // do docs, if args were given
+ cmDocumentation doc;
+ doc.addCMakeStandardDocSections();
+ if (argc2 > 1 && doc.CheckOptions(argc2, argv2)) {
+ // Construct and print requested documentation.
+ cmake hcm(cmake::RoleInternal, cmState::Unknown);
+ hcm.SetHomeDirectory("");
+ hcm.SetHomeOutputDirectory("");
+ hcm.AddCMakePaths();
+
+ auto generators = hcm.GetGeneratorsDocumentation();
+ doc.SetName("cmake");
+ doc.SetSection("Name", cmDocumentationName);
+ doc.SetSection("Usage", cmDocumentationUsage);
+ doc.AppendSection("Generators", generators);
+ doc.PrependSection("Options", cmDocumentationOptions);
+
+ return (doc.PrintRequestedDocumentation(std::cout) ? 0 : 1);
+ }
+
+#if defined(Q_OS_MAC)
+ if (argc2 == 2 && strcmp(argv2[1], "--install") == 0) {
+ return cmOSXInstall("/usr/local/bin");
+ }
+ if (argc2 == 2 && cmHasLiteralPrefix(argv2[1], "--install=")) {
+ return cmOSXInstall(argv2[1] + 10);
+ }
+#endif
+
+// When we are on OSX and we are launching cmake-gui from a symlink, the
+// application will fail to launch as it can't find the qt.conf file which
+// tells it what the name of the plugin folder is. We need to add this path
+// BEFORE the application is constructed as that is what triggers the
+// searching for the platform plugins
+#if defined(Q_OS_MAC)
+ cmAddPluginPath();
+#endif
+
+#if QT_VERSION >= 0x050600
+ QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+#endif
+
+ SetupDefaultQSettings();
+ QApplication app(argc, argv);
+
+ setlocale(LC_NUMERIC, "C");
+
+ // tell the cmake library where cmake is
+ QDir cmExecDir(QApplication::applicationDirPath());
+#if defined(Q_OS_MAC)
+ cmExecDir.cd("../../../");
+#endif
+
+ // pick up translation files if they exists in the data directory
+ QDir translationsDir = cmExecDir;
+ translationsDir.cd(QString::fromLocal8Bit(".." CMAKE_DATA_DIR));
+ translationsDir.cd("i18n");
+ QTranslator translator;
+ QString transfile = QString("cmake_%1").arg(QLocale::system().name());
+ translator.load(transfile, translationsDir.path());
+ QApplication::installTranslator(&translator);
+
+ // app setup
+ QApplication::setApplicationName("CMakeSetup");
+ QApplication::setOrganizationName("Kitware");
+ QIcon appIcon;
+ appIcon.addFile(":/Icons/CMakeSetup32.png");
+ appIcon.addFile(":/Icons/CMakeSetup128.png");
+ QApplication::setWindowIcon(QIcon::fromTheme("cmake-gui", appIcon));
+
+ CMakeSetupDialog dialog;
+ dialog.show();
+
+ QStringList args = QApplication::arguments();
+ std::string binaryDirectory;
+ std::string sourceDirectory;
+ std::string presetName;
+ for (int i = 1; i < args.size(); ++i) {
+ const QString& arg = args[i];
+ if (arg.startsWith("-S")) {
+ QString path = arg.mid(2);
+ if (path.isEmpty()) {
+ ++i;
+ if (i >= args.size()) {
+ std::cerr << "No source directory specified for -S" << std::endl;
+ return 1;
+ }
+ path = args[i];
+ if (path[0] == '-') {
+ std::cerr << "No source directory specified for -S" << std::endl;
+ return 1;
+ }
+ }
+
+ sourceDirectory =
+ cmSystemTools::CollapseFullPath(path.toLocal8Bit().data());
+ cmSystemTools::ConvertToUnixSlashes(sourceDirectory);
+ } else if (arg.startsWith("-B")) {
+ QString path = arg.mid(2);
+ if (path.isEmpty()) {
+ ++i;
+ if (i >= args.size()) {
+ std::cerr << "No build directory specified for -B" << std::endl;
+ return 1;
+ }
+ path = args[i];
+ if (path[0] == '-') {
+ std::cerr << "No build directory specified for -B" << std::endl;
+ return 1;
+ }
+ }
+
+ binaryDirectory =
+ cmSystemTools::CollapseFullPath(path.toLocal8Bit().data());
+ cmSystemTools::ConvertToUnixSlashes(binaryDirectory);
+ } else if (arg.startsWith("--preset=")) {
+ QString preset = arg.mid(cmStrLen("--preset="));
+ if (preset.isEmpty()) {
+ std::cerr << "No preset specified for --preset" << std::endl;
+ return 1;
+ }
+ presetName = preset.toLocal8Bit().data();
+ } else if (arg == "--browse-manual") {
+ OpenReferenceManual();
+ return 0;
+ }
+ }
+ if (!sourceDirectory.empty() &&
+ (!binaryDirectory.empty() || !presetName.empty())) {
+ dialog.setSourceDirectory(QString::fromLocal8Bit(sourceDirectory.c_str()));
+ if (!binaryDirectory.empty()) {
+ dialog.setBinaryDirectory(
+ QString::fromLocal8Bit(binaryDirectory.c_str()));
+ if (!presetName.empty()) {
+ dialog.setStartupBinaryDirectory(true);
+ }
+ }
+ if (!presetName.empty()) {
+ dialog.setDeferredPreset(QString::fromLocal8Bit(presetName.c_str()));
+ }
+ } else {
+ if (args.count() == 2) {
+ std::string filePath =
+ cmSystemTools::CollapseFullPath(args[1].toLocal8Bit().data());
+
+ // check if argument is a directory containing CMakeCache.txt
+ std::string buildFilePath = cmStrCat(filePath, "/CMakeCache.txt");
+
+ // check if argument is a CMakeCache.txt file
+ if (cmSystemTools::GetFilenameName(filePath) == "CMakeCache.txt" &&
+ cmSystemTools::FileExists(filePath.c_str())) {
+ buildFilePath = filePath;
+ }
+
+ // check if argument is a directory containing CMakeLists.txt
+ std::string srcFilePath = cmStrCat(filePath, "/CMakeLists.txt");
+
+ if (cmSystemTools::FileExists(buildFilePath.c_str())) {
+ dialog.setBinaryDirectory(QString::fromLocal8Bit(
+ cmSystemTools::GetFilenamePath(buildFilePath).c_str()));
+ } else if (cmSystemTools::FileExists(srcFilePath.c_str())) {
+ dialog.setSourceDirectory(QString::fromLocal8Bit(filePath.c_str()));
+ dialog.setBinaryDirectory(QString::fromLocal8Bit(
+ cmSystemTools::CollapseFullPath(".").c_str()));
+ }
+ }
+ }
+
+ return CMakeGUIExec(&dialog);
+}
+
+#if defined(Q_OS_MAC)
+# include <cerrno>
+# include <cstring>
+
+# include <unistd.h>
+
+# include "cm_sys_stat.h"
+static bool cmOSXInstall(std::string const& dir, std::string const& tool)
+{
+ if (tool.empty()) {
+ return true;
+ }
+ std::string link = dir + cmSystemTools::GetFilenameName(tool);
+ struct stat st;
+ if (lstat(link.c_str(), &st) == 0 && S_ISLNK(st.st_mode)) {
+ char buf[4096];
+ ssize_t s = readlink(link.c_str(), buf, sizeof(buf) - 1);
+ if (s >= 0 && std::string(buf, s) == tool) {
+ std::cerr << "Exists: '" << link << "' -> '" << tool << "'\n";
+ return true;
+ }
+ }
+ cmSystemTools::MakeDirectory(dir);
+ if (symlink(tool.c_str(), link.c_str()) == 0) {
+ std::cerr << "Linked: '" << link << "' -> '" << tool << "'\n";
+ return true;
+ }
+ int err = errno;
+ std::cerr << "Failed: '" << link << "' -> '" << tool
+ << "': " << strerror(err) << "\n";
+ return false;
+}
+static int cmOSXInstall(std::string dir)
+{
+ if (!cmHasLiteralSuffix(dir, "/")) {
+ dir += "/";
+ }
+ return (cmOSXInstall(dir, cmSystemTools::GetCMakeCommand()) &&
+ cmOSXInstall(dir, cmSystemTools::GetCTestCommand()) &&
+ cmOSXInstall(dir, cmSystemTools::GetCPackCommand()) &&
+ cmOSXInstall(dir, cmSystemTools::GetCMakeGUICommand()) &&
+ cmOSXInstall(dir, cmSystemTools::GetCMakeCursesCommand()))
+ ? 0
+ : 1;
+}
+
+// Locate the PlugIns directory and add it to the QApplication library paths.
+// We need to resolve all symlinks so we have a known relative path between
+// MacOS/CMake and the PlugIns directory.
+//
+// Note we are using cmSystemTools since Qt can't provide the path to the
+// executable before the QApplication is created, and that is when plugin
+// searching occurs.
+static void cmAddPluginPath()
+{
+ std::string const& path = cmSystemTools::GetCMakeGUICommand();
+ if (path.empty()) {
+ return;
+ }
+ std::string const& realPath = cmSystemTools::GetRealPath(path);
+ QFileInfo appPath(QString::fromLocal8Bit(realPath.c_str()));
+ QDir pluginDir = appPath.dir();
+ bool const foundPluginDir = pluginDir.cd("../PlugIns");
+ if (foundPluginDir) {
+ QApplication::addLibraryPath(pluginDir.path());
+ }
+}
+
+#endif
diff --git a/Source/QtDialog/CMakeSetup.icns b/Source/QtDialog/CMakeSetup.icns
new file mode 100644
index 0000000..e0bf8fd
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup.icns
Binary files differ
diff --git a/Source/QtDialog/CMakeSetup.ico b/Source/QtDialog/CMakeSetup.ico
new file mode 100644
index 0000000..1ac13c8
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup.ico
Binary files differ
diff --git a/Source/QtDialog/CMakeSetup.qrc b/Source/QtDialog/CMakeSetup.qrc
new file mode 100644
index 0000000..eaac192
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/Icons" >
+ <file>CMakeSetup128.png</file>
+ <file>CMakeSetup32.png</file>
+ <file>Delete16.png</file>
+ <file>Plus16.png</file>
+ </qresource>
+</RCC>
diff --git a/Source/QtDialog/CMakeSetup.rc b/Source/QtDialog/CMakeSetup.rc
new file mode 100644
index 0000000..fcc887d
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup.rc
@@ -0,0 +1 @@
+IDI_ICON1 ICON DISCARDABLE "CMakeSetup.ico"
diff --git a/Source/QtDialog/CMakeSetup128.png b/Source/QtDialog/CMakeSetup128.png
new file mode 100644
index 0000000..32984e1
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup128.png
Binary files differ
diff --git a/Source/QtDialog/CMakeSetup32.png b/Source/QtDialog/CMakeSetup32.png
new file mode 100644
index 0000000..78df82f
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup32.png
Binary files differ
diff --git a/Source/QtDialog/CMakeSetup64.png b/Source/QtDialog/CMakeSetup64.png
new file mode 100644
index 0000000..5c2dbf5
--- /dev/null
+++ b/Source/QtDialog/CMakeSetup64.png
Binary files differ
diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx
new file mode 100644
index 0000000..0313088
--- /dev/null
+++ b/Source/QtDialog/CMakeSetupDialog.cxx
@@ -0,0 +1,1481 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "CMakeSetupDialog.h"
+
+#include <cm/memory>
+
+#include <QCloseEvent>
+#include <QCoreApplication>
+#include <QDesktopServices>
+#include <QDialogButtonBox>
+#include <QDragEnterEvent>
+#include <QFileDialog>
+#include <QInputDialog>
+#include <QKeySequence>
+#include <QMenu>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QMimeData>
+#include <QProcessEnvironment>
+#include <QProgressBar>
+#include <QSettings>
+#include <QShortcut>
+#include <QStatusBar>
+#include <QString>
+#include <QUrl>
+#include <QVector>
+
+#ifdef QT_WINEXTRAS
+# include <QWinTaskbarButton>
+# include <QWinTaskbarProgress>
+#endif
+
+#include "QCMake.h"
+#include "QCMakeCacheView.h"
+
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+
+#include "AddCacheEntry.h"
+#include "EnvironmentDialog.h"
+#include "FirstConfigure.h"
+#include "RegexExplorer.h"
+#include "WarningMessagesDialog.h"
+
+void OpenReferenceManual()
+{
+ QString urlFormat("https://cmake.org/cmake/help/v%1.%2/");
+ QUrl url(urlFormat.arg(QString::number(cmVersion::GetMajorVersion()),
+ QString::number(cmVersion::GetMinorVersion())));
+
+ if (!cmSystemTools::GetHTMLDoc().empty()) {
+ url = QUrl::fromLocalFile(
+ QDir(QString::fromLocal8Bit(cmSystemTools::GetHTMLDoc().data()))
+ .filePath("index.html"));
+ }
+
+ QDesktopServices::openUrl(url);
+}
+
+namespace {
+const QString PRESETS_DISABLED_TOOLTIP =
+ "This option is disabled because there are no available presets in "
+ "CMakePresets.json or CMakeUserPresets.json.";
+}
+
+QCMakeThread::QCMakeThread(QObject* p)
+ : QThread(p)
+{
+}
+
+QCMake* QCMakeThread::cmakeInstance() const
+{
+ return this->CMakeInstance.get();
+}
+
+void QCMakeThread::run()
+{
+ this->CMakeInstance = cm::make_unique<QCMake>();
+ // emit that this cmake thread is ready for use
+ emit this->cmakeInitialized();
+ this->exec();
+ this->CMakeInstance.reset();
+}
+
+CMakeSetupDialog::CMakeSetupDialog()
+ : ExitAfterGenerate(true)
+ , CacheModified(false)
+ , ConfigureNeeded(true)
+ , CurrentState(Interrupting)
+{
+ QString title = QString(tr("CMake %1"));
+ title = title.arg(cmVersion::GetCMakeVersion());
+ this->setWindowTitle(title);
+
+ // create the GUI
+ QSettings settings;
+ settings.beginGroup("Settings/StartPath");
+ restoreGeometry(settings.value("geometry").toByteArray());
+ restoreState(settings.value("windowState").toByteArray());
+
+ this->AddVariableNames =
+ settings.value("AddVariableNames", QStringList("CMAKE_INSTALL_PREFIX"))
+ .toStringList();
+ this->AddVariableTypes =
+ settings.value("AddVariableTypes", QStringList("PATH")).toStringList();
+
+ QWidget* cont = new QWidget(this);
+ this->setupUi(cont);
+ this->Splitter->setStretchFactor(0, 3);
+ this->Splitter->setStretchFactor(1, 1);
+ this->setCentralWidget(cont);
+ this->ProgressBar->reset();
+ this->RemoveEntry->setEnabled(false);
+ this->AddEntry->setEnabled(false);
+ this->Preset->setStatusTip(PRESETS_DISABLED_TOOLTIP);
+
+ QByteArray p = settings.value("SplitterSizes").toByteArray();
+ this->Splitter->restoreState(p);
+
+ bool groupView = settings.value("GroupView", false).toBool();
+ this->setGroupedView(groupView);
+ this->groupedCheck->setCheckState(groupView ? Qt::Checked : Qt::Unchecked);
+
+ bool advancedView = settings.value("AdvancedView", false).toBool();
+ this->setAdvancedView(advancedView);
+ this->advancedCheck->setCheckState(advancedView ? Qt::Checked
+ : Qt::Unchecked);
+
+ QMenu* FileMenu = this->menuBar()->addMenu(tr("&File"));
+ this->ReloadCacheAction = FileMenu->addAction(tr("&Reload Cache"));
+ QObject::connect(this->ReloadCacheAction, &QAction::triggered, this,
+ &CMakeSetupDialog::doReloadCache);
+ this->DeleteCacheAction = FileMenu->addAction(tr("&Delete Cache"));
+ QObject::connect(this->DeleteCacheAction, &QAction::triggered, this,
+ &CMakeSetupDialog::doDeleteCache);
+ this->ExitAction = FileMenu->addAction(tr("E&xit"));
+ 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);
+ this->GenerateAction = ToolsMenu->addAction(tr("&Generate"));
+ 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, &QAction::triggered,
+ this, &CMakeSetupDialog::doInstallForCommandLine);
+#endif
+ ToolsMenu->addSeparator();
+ a = ToolsMenu->addAction(tr("Regular Expression Explorer..."));
+ QObject::connect(a, &QAction::triggered, this,
+ &CMakeSetupDialog::doRegexExplorerDialog);
+ ToolsMenu->addSeparator();
+ 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"));
+ 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, &QAction::toggled, this,
+ &CMakeSetupDialog::setDebugOutput);
+
+ OptionsMenu->addSeparator();
+ 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"));
+ a = HelpMenu->addAction(tr("Help"));
+ QObject::connect(a, &QAction::triggered, this, &CMakeSetupDialog::doHelp);
+ a->setShortcut(QKeySequence::HelpContents);
+ a = HelpMenu->addAction(tr("CMake Reference Manual"));
+ QObject::connect(a, &QAction::triggered, this, OpenReferenceManual);
+ a = HelpMenu->addAction(tr("About"));
+ QObject::connect(a, &QAction::triggered, this, &CMakeSetupDialog::doAbout);
+
+ this->setAcceptDrops(true);
+
+ // get the saved binary directories
+ QStringList buildPaths = this->loadBuildPaths();
+ this->BinaryDirectory->addItems(buildPaths);
+
+ this->BinaryDirectory->setCompleter(new QCMakeFileCompleter(this, true));
+ this->SourceDirectory->setCompleter(new QCMakeFileCompleter(this, true));
+
+ // fixed pitch font in output window
+ QFont outputFont("Courier");
+ this->Output->setFont(outputFont);
+ this->ErrorFormat.setForeground(QBrush(Qt::red));
+
+ this->Output->setContextMenuPolicy(Qt::CustomContextMenu);
+ 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, &QCMakeThread::cmakeInitialized, this,
+ &CMakeSetupDialog::initialize, Qt::QueuedConnection);
+ this->CMakeThread->start();
+
+ this->enterState(ReadyConfigure);
+
+ ProgressOffset = 0.0;
+ ProgressFactor = 1.0;
+}
+
+void CMakeSetupDialog::initialize()
+{
+ // now the cmake worker thread is running, lets make our connections to it
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ &QCMake::propertiesChanged, this->CacheValues->cacheModel(),
+ &QCMakeCacheModel::setProperties);
+
+ QObject::connect(this->ConfigureButton, &QAbstractButton::clicked, this,
+ &CMakeSetupDialog::doConfigure);
+
+ QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::configureDone,
+ this, &CMakeSetupDialog::exitLoop);
+ QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::generateDone,
+ this, &CMakeSetupDialog::exitLoop);
+
+ QObject::connect(this->GenerateButton, &QAbstractButton::clicked, this,
+ &CMakeSetupDialog::doGenerate);
+ QObject::connect(this->OpenProjectButton, &QAbstractButton::clicked, this,
+ &CMakeSetupDialog::doOpenProject);
+
+ QObject::connect(this->BrowseSourceDirectoryButton,
+ &QAbstractButton::clicked, this,
+ &CMakeSetupDialog::doSourceBrowse);
+ QObject::connect(this->BrowseBinaryDirectoryButton,
+ &QAbstractButton::clicked, this,
+ &CMakeSetupDialog::doBinaryBrowse);
+
+ QObject::connect(this->BinaryDirectory, &QComboBox::editTextChanged, this,
+ &CMakeSetupDialog::onBinaryDirectoryChanged);
+ QObject::connect(this->SourceDirectory, &QLineEdit::textChanged, this,
+ &CMakeSetupDialog::onSourceDirectoryChanged);
+ QObject::connect(this->Preset, &QCMakePresetComboBox::presetChanged, this,
+ &CMakeSetupDialog::onBuildPresetChanged);
+
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ &QCMake::sourceDirChanged, this,
+ &CMakeSetupDialog::updateSourceDirectory);
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ &QCMake::binaryDirChanged, this,
+ &CMakeSetupDialog::updateBinaryDirectory);
+ QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::presetsChanged,
+ this, &CMakeSetupDialog::updatePresets);
+ QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::presetChanged,
+ this, &CMakeSetupDialog::updatePreset);
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ &QCMake::presetLoadError, this,
+ &CMakeSetupDialog::showPresetLoadError);
+
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ &QCMake::progressChanged, this,
+ &CMakeSetupDialog::showProgress);
+
+ QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::errorMessage,
+ this, &CMakeSetupDialog::error);
+
+ QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::outputMessage,
+ this, &CMakeSetupDialog::message);
+
+ QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::openPossible,
+ this->OpenProjectButton, &CMakeSetupDialog::setEnabled);
+
+ 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(),
+ &QCMake::generatorChanged, this,
+ &CMakeSetupDialog::updateGeneratorLabel);
+ this->updateGeneratorLabel(QString());
+
+ QObject::connect(this->CacheValues->cacheModel(),
+ &QCMakeCacheModel::dataChanged, this,
+ &CMakeSetupDialog::setCacheModified);
+
+ QObject::connect(this->CacheValues->selectionModel(),
+ &QItemSelectionModel::selectionChanged, this,
+ &CMakeSetupDialog::selectionChanged);
+ QObject::connect(this->RemoveEntry, &QAbstractButton::clicked, this,
+ &CMakeSetupDialog::removeSelectedCacheEntries);
+ QObject::connect(this->AddEntry, &QAbstractButton::clicked, this,
+ &CMakeSetupDialog::addCacheEntry);
+
+ QObject::connect(this->Environment, &QAbstractButton::clicked, this,
+ &CMakeSetupDialog::editEnvironment);
+
+ QObject::connect(this->WarnUninitializedAction, &QAction::triggered,
+ this->CMakeThread->cmakeInstance(),
+ &QCMake::setWarnUninitializedMode);
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ &QCMake::warnUninitializedModeChanged,
+ this->WarnUninitializedAction, &QAction::setChecked);
+
+ if (!this->SourceDirectory->text().isEmpty() &&
+ !this->DeferredPreset.isNull()) {
+ this->onSourceDirectoryChanged(this->SourceDirectory->text());
+ } else if (!this->SourceDirectory->text().isEmpty() ||
+ !this->BinaryDirectory->lineEdit()->text().isEmpty()) {
+ this->onSourceDirectoryChanged(this->SourceDirectory->text());
+ this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
+ } else {
+ this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
+ }
+
+#ifdef QT_WINEXTRAS
+ this->TaskbarButton = new QWinTaskbarButton(this);
+ this->TaskbarButton->setWindow(this->windowHandle());
+#endif
+}
+
+CMakeSetupDialog::~CMakeSetupDialog()
+{
+ QSettings settings;
+ settings.beginGroup("Settings/StartPath");
+ settings.setValue("windowState", QVariant(saveState()));
+ settings.setValue("geometry", QVariant(saveGeometry()));
+ settings.setValue("SplitterSizes", this->Splitter->saveState());
+
+ // wait for thread to stop
+ this->CMakeThread->quit();
+ this->CMakeThread->wait();
+}
+
+bool CMakeSetupDialog::prepareConfigure()
+{
+ // make sure build directory exists
+ QString bindir = this->CMakeThread->cmakeInstance()->binaryDirectory();
+ QDir dir(bindir);
+ if (!dir.exists()) {
+ QString msg = tr("Build directory does not exist, "
+ "should I create it?\n\n"
+ "Directory: ");
+ msg += bindir;
+ QString title = tr("Create Directory");
+ QMessageBox::StandardButton btn;
+ btn = QMessageBox::information(this, title, msg,
+ QMessageBox::Yes | QMessageBox::No);
+ if (btn == QMessageBox::No) {
+ return false;
+ }
+ if (!dir.mkpath(".")) {
+ QMessageBox::information(
+ this, tr("Create Directory Failed"),
+ QString(tr("Failed to create directory %1")).arg(dir.path()),
+ QMessageBox::Ok);
+
+ return false;
+ }
+ }
+
+ // if no generator, prompt for it and other setup stuff
+ if (this->CMakeThread->cmakeInstance()->generator().isEmpty()) {
+ if (!this->setupFirstConfigure()) {
+ return false;
+ }
+ }
+
+ // remember path
+ this->addBinaryPath(dir.absolutePath());
+
+ return true;
+}
+
+void CMakeSetupDialog::exitLoop(int err)
+{
+ this->LocalLoop.exit(err);
+}
+
+void CMakeSetupDialog::doConfigure()
+{
+ if (this->CurrentState == Configuring) {
+ // stop configure
+ doInterrupt();
+ return;
+ }
+
+ if (!prepareConfigure()) {
+ return;
+ }
+
+ this->enterState(Configuring);
+
+ bool ret = doConfigureInternal();
+
+ if (ret) {
+ this->ConfigureNeeded = false;
+ }
+
+ if (ret && !this->CacheValues->cacheModel()->newPropertyCount()) {
+ this->enterState(ReadyGenerate);
+ } else {
+ this->enterState(ReadyConfigure);
+ this->CacheValues->scrollToTop();
+ }
+ this->ProgressBar->reset();
+
+#ifdef QT_WINEXTRAS
+ this->TaskbarButton->progress()->reset();
+#endif
+}
+
+bool CMakeSetupDialog::doConfigureInternal()
+{
+ this->Output->clear();
+ this->CacheValues->selectionModel()->clear();
+
+ QMetaObject::invokeMethod(
+ this->CMakeThread->cmakeInstance(), "setProperties", Qt::QueuedConnection,
+ Q_ARG(QCMakePropertyList, this->CacheValues->cacheModel()->properties()));
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "configure",
+ Qt::QueuedConnection);
+
+ int err = this->LocalLoop.exec();
+
+ if (err != 0) {
+ QMessageBox::critical(
+ this, tr("Error"),
+ tr("Error in configuration process, project files may be invalid"),
+ QMessageBox::Ok);
+ }
+
+ return 0 == err;
+}
+
+void CMakeSetupDialog::doInstallForCommandLine()
+{
+ QString title = tr("How to Install For Command Line Use");
+ QString msg = tr("One may add CMake to the PATH:\n"
+ "\n"
+ " PATH=\"%1\":\"$PATH\"\n"
+ "\n"
+ "Or, to install symlinks to '/usr/local/bin', run:\n"
+ "\n"
+ " sudo \"%2\" --install\n"
+ "\n"
+ "Or, to install symlinks to another directory, run:\n"
+ "\n"
+ " sudo \"%3\" --install=/path/to/bin\n");
+ msg = msg.arg(
+ cmSystemTools::GetFilenamePath(cmSystemTools::GetCMakeCommand()).c_str());
+ msg = msg.arg(cmSystemTools::GetCMakeGUICommand().c_str());
+ msg = msg.arg(cmSystemTools::GetCMakeGUICommand().c_str());
+
+ QDialog dialog;
+ dialog.setWindowTitle(title);
+ QVBoxLayout* l = new QVBoxLayout(&dialog);
+ QLabel* lab = new QLabel(&dialog);
+ l->addWidget(lab);
+ lab->setText(msg);
+ lab->setWordWrap(false);
+ lab->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ QDialogButtonBox* btns =
+ new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog);
+ QObject::connect(btns, &QDialogButtonBox::accepted, &dialog,
+ &QDialog::accept);
+ l->addWidget(btns);
+ dialog.exec();
+}
+
+bool CMakeSetupDialog::doGenerateInternal()
+{
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "generate",
+ Qt::QueuedConnection);
+
+ int err = this->LocalLoop.exec();
+
+ if (err != 0) {
+ QMessageBox::critical(
+ this, tr("Error"),
+ tr("Error in generation process, project files may be invalid"),
+ QMessageBox::Ok);
+ }
+
+ return 0 == err;
+}
+
+void CMakeSetupDialog::doGenerate()
+{
+ if (this->CurrentState == Generating) {
+ // stop generate
+ doInterrupt();
+ return;
+ }
+
+ // see if we need to configure
+ // we'll need to configure if:
+ // the configure step hasn't been done yet
+ // generate was the last step done
+ if (this->ConfigureNeeded) {
+ if (!prepareConfigure()) {
+ return;
+ }
+ }
+
+ this->enterState(Generating);
+
+ bool config_passed = true;
+ if (this->ConfigureNeeded) {
+ this->CacheValues->cacheModel()->setShowNewProperties(false);
+ this->ProgressFactor = 0.5;
+ config_passed = doConfigureInternal();
+ this->ProgressOffset = 0.5;
+ }
+
+ if (config_passed) {
+ doGenerateInternal();
+ }
+
+ this->ProgressOffset = 0.0;
+ this->ProgressFactor = 1.0;
+ this->CacheValues->cacheModel()->setShowNewProperties(true);
+
+ this->enterState(ReadyConfigure);
+ this->ProgressBar->reset();
+#ifdef QT_WINEXTRAS
+ this->TaskbarButton->progress()->reset();
+#endif
+
+ this->ConfigureNeeded = true;
+}
+
+void CMakeSetupDialog::doOpenProject()
+{
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "open",
+ Qt::QueuedConnection);
+}
+
+void CMakeSetupDialog::closeEvent(QCloseEvent* e)
+{
+ // prompt for close if there are unsaved changes, and we're not busy
+ if (this->CacheModified) {
+ QString msg = tr("You have changed options but not rebuilt, "
+ "are you sure you want to exit?");
+ QString title = tr("Confirm Exit");
+ QMessageBox::StandardButton btn;
+ btn = QMessageBox::critical(this, title, msg,
+ QMessageBox::Yes | QMessageBox::No);
+ if (btn == QMessageBox::No) {
+ e->ignore();
+ }
+ }
+
+ // don't close if we're busy, unless the user really wants to
+ if (this->CurrentState == Configuring) {
+ QString msg =
+ tr("You are in the middle of a Configure.\n"
+ "If you Exit now the configure information will be lost.\n"
+ "Are you sure you want to Exit?");
+ QString title = tr("Confirm Exit");
+ QMessageBox::StandardButton btn;
+ btn = QMessageBox::critical(this, title, msg,
+ QMessageBox::Yes | QMessageBox::No);
+ if (btn == QMessageBox::No) {
+ e->ignore();
+ } else {
+ this->doInterrupt();
+ }
+ }
+
+ // let the generate finish
+ if (this->CurrentState == Generating) {
+ e->ignore();
+ }
+}
+
+void CMakeSetupDialog::doHelp()
+{
+ QString msg = tr(
+ "CMake is used to configure and generate build files for "
+ "software projects. The basic steps for configuring a project are as "
+ "follows:\r\n\r\n1. Select the source directory for the project. This "
+ "should "
+ "contain the CMakeLists.txt files for the project.\r\n\r\n2. Select the "
+ "build "
+ "directory for the project. This is the directory where the project "
+ "will be "
+ "built. It can be the same or a different directory than the source "
+ "directory. For easy clean up, a separate build directory is "
+ "recommended. "
+ "CMake will create the directory if it does not exist.\r\n\r\n3. Once the "
+ "source and binary directories are selected, it is time to press the "
+ "Configure button. This will cause CMake to read all of the input files "
+ "and "
+ "discover all the variables used by the project. The first time a "
+ "variable "
+ "is displayed it will be in Red. Users should inspect red variables "
+ "making "
+ "sure the values are correct. For some projects the Configure process "
+ "can "
+ "be iterative, so continue to press the Configure button until there are "
+ "no "
+ "longer red entries.\r\n\r\n4. Once there are no longer red entries, you "
+ "should click the Generate button. This will write the build files to "
+ "the build "
+ "directory.");
+
+ QDialog dialog;
+ QFontMetrics met(this->font());
+#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
+ int msgWidth = met.horizontalAdvance(msg);
+#else
+ int msgWidth = met.width(msg);
+#endif
+ dialog.setMinimumSize(msgWidth / 15, 20);
+ dialog.setWindowTitle(tr("Help"));
+ QVBoxLayout* l = new QVBoxLayout(&dialog);
+ QLabel* lab = new QLabel(&dialog);
+ lab->setText(msg);
+ lab->setWordWrap(true);
+ QDialogButtonBox* btns =
+ new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog);
+ QObject::connect(btns, &QDialogButtonBox::accepted, &dialog,
+ &QDialog::accept);
+ l->addWidget(lab);
+ l->addWidget(btns);
+ dialog.exec();
+}
+
+void CMakeSetupDialog::doInterrupt()
+{
+ this->enterState(Interrupting);
+ this->CMakeThread->cmakeInstance()->interrupt();
+}
+
+void CMakeSetupDialog::doSourceBrowse()
+{
+ QString dir = QFileDialog::getExistingDirectory(
+ this, tr("Enter Path to Source"), this->SourceDirectory->text(),
+ QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
+ if (!dir.isEmpty()) {
+ this->setSourceDirectory(dir);
+ }
+}
+
+void CMakeSetupDialog::updateSourceDirectory(const QString& dir)
+{
+ if (this->SourceDirectory->text() != dir) {
+ this->SourceDirectory->blockSignals(true);
+ this->SourceDirectory->setText(dir);
+ this->SourceDirectory->blockSignals(false);
+ }
+}
+
+void CMakeSetupDialog::updateBinaryDirectory(const QString& dir)
+{
+ if (this->BinaryDirectory->currentText() != dir) {
+ this->BinaryDirectory->blockSignals(true);
+ this->BinaryDirectory->setEditText(dir);
+ this->BinaryDirectory->blockSignals(false);
+ }
+}
+
+void CMakeSetupDialog::updatePresets(const QVector<QCMakePreset>& presets)
+{
+ if (this->Preset->presets() != presets) {
+ this->Preset->blockSignals(true);
+ this->Preset->setPresets(presets);
+ this->Preset->blockSignals(false);
+ }
+
+ this->Preset->setDisabled(presets.isEmpty());
+ this->Preset->setToolTip(presets.isEmpty() ? PRESETS_DISABLED_TOOLTIP : "");
+
+ if (!this->DeferredPreset.isNull()) {
+ this->Preset->setPresetName(this->DeferredPreset);
+ this->DeferredPreset = QString{};
+ }
+}
+
+void CMakeSetupDialog::updatePreset(const QString& name)
+{
+ if (this->Preset->presetName() != name) {
+ this->Preset->blockSignals(true);
+ this->Preset->setPresetName(name);
+ this->Preset->blockSignals(false);
+ }
+}
+
+void CMakeSetupDialog::showPresetLoadError(
+ const QString& dir, cmCMakePresetsFile::ReadFileResult result)
+{
+ QMessageBox::warning(
+ this, "Error Reading CMake Presets",
+ QString::fromLocal8Bit("Could not read presets from %1: %2")
+ .arg(dir, cmCMakePresetsFile::ResultToString(result)));
+}
+
+void CMakeSetupDialog::doBinaryBrowse()
+{
+ QString dir = QFileDialog::getExistingDirectory(
+ this, tr("Enter Path to Build"), this->BinaryDirectory->currentText(),
+ QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
+ if (!dir.isEmpty() && dir != this->BinaryDirectory->currentText()) {
+ this->setBinaryDirectory(dir);
+ }
+}
+
+void CMakeSetupDialog::setBinaryDirectory(const QString& dir)
+{
+ this->BinaryDirectory->setEditText(dir);
+}
+
+void CMakeSetupDialog::setStartupBinaryDirectory(bool startup)
+{
+ this->StartupBinaryDirectory = startup;
+}
+
+void CMakeSetupDialog::onSourceDirectoryChanged(const QString& dir)
+{
+ this->Output->clear();
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
+ "setSourceDirectory", Qt::QueuedConnection,
+ Q_ARG(QString, dir));
+}
+
+void CMakeSetupDialog::onBinaryDirectoryChanged(const QString& dir)
+{
+ QString title = QString(tr("CMake %1 - %2"));
+ title = title.arg(cmVersion::GetCMakeVersion());
+ title = title.arg(dir);
+ this->setWindowTitle(title);
+
+ this->CacheModified = false;
+ this->CacheValues->cacheModel()->clear();
+ qobject_cast<QCMakeCacheModelDelegate*>(this->CacheValues->itemDelegate())
+ ->clearChanges();
+ this->Output->clear();
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
+ "setBinaryDirectory", Qt::QueuedConnection,
+ Q_ARG(QString, dir));
+}
+
+void CMakeSetupDialog::onBuildPresetChanged(const QString& name)
+{
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "setPreset",
+ Qt::QueuedConnection, Q_ARG(QString, name),
+ Q_ARG(bool, !this->StartupBinaryDirectory));
+ this->StartupBinaryDirectory = false;
+}
+
+void CMakeSetupDialog::setSourceDirectory(const QString& dir)
+{
+ this->SourceDirectory->setText(dir);
+}
+
+void CMakeSetupDialog::setDeferredPreset(const QString& preset)
+{
+ this->DeferredPreset = preset;
+}
+
+void CMakeSetupDialog::showProgress(const QString& /*msg*/, float percent)
+{
+ percent = (percent * ProgressFactor) + ProgressOffset;
+ this->ProgressBar->setValue(qRound(percent * 100));
+
+#ifdef QT_WINEXTRAS
+ QWinTaskbarProgress* progress = this->TaskbarButton->progress();
+ progress->setVisible(true);
+ progress->setValue(qRound(percent * 100));
+#endif
+}
+
+void CMakeSetupDialog::error(const QString& msg)
+{
+ this->Output->setCurrentCharFormat(this->ErrorFormat);
+ // QTextEdit will terminate the msg with a ParagraphSeparator, but it also
+ // replaces
+ // all newlines with ParagraphSeparators. By replacing the newlines by
+ // ourself, one
+ // error msg will be one paragraph.
+ QString paragraph(msg);
+ paragraph.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ this->Output->append(paragraph);
+}
+
+void CMakeSetupDialog::message(const QString& msg)
+{
+ this->Output->setCurrentCharFormat(this->MessageFormat);
+ this->Output->append(msg);
+}
+
+void CMakeSetupDialog::setEnabledState(bool enabled)
+{
+ // disable parts of the GUI during configure/generate
+ this->CacheValues->cacheModel()->setEditEnabled(enabled);
+ this->SourceDirectory->setEnabled(enabled);
+ this->BrowseSourceDirectoryButton->setEnabled(enabled);
+ this->Preset->setEnabled(enabled && !this->Preset->presets().isEmpty());
+ this->BinaryDirectory->setEnabled(enabled);
+ this->BrowseBinaryDirectoryButton->setEnabled(enabled);
+ this->ReloadCacheAction->setEnabled(enabled);
+ this->DeleteCacheAction->setEnabled(enabled);
+ this->ExitAction->setEnabled(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()
+{
+ FirstConfigure dialog;
+
+ // initialize dialog and restore saved settings
+
+ // add generators
+ dialog.setGenerators(
+ this->CMakeThread->cmakeInstance()->availableGenerators());
+
+ // restore from settings
+ dialog.loadFromSettings();
+
+ auto presetData = this->Preset->currentData();
+ if (presetData.isValid()) {
+ auto preset = presetData.value<QCMakePreset>();
+ dialog.setCurrentGenerator(preset.generator);
+ if (preset.setArchitecture) {
+ dialog.setPlatform(preset.architecture);
+ }
+ if (preset.setToolset) {
+ dialog.setToolset(preset.toolset);
+ }
+ dialog.setCompilerOption(CompilerOption::DefaultNative);
+ }
+
+ if (dialog.exec() == QDialog::Accepted) {
+ dialog.saveToSettings();
+ this->CMakeThread->cmakeInstance()->setGenerator(dialog.getGenerator());
+ this->CMakeThread->cmakeInstance()->setPlatform(dialog.getPlatform());
+ this->CMakeThread->cmakeInstance()->setToolset(dialog.getToolset());
+
+ QCMakeCacheModel* m = this->CacheValues->cacheModel();
+
+ if (dialog.compilerSetup()) {
+ QString fortranCompiler = dialog.getFortranCompiler();
+ if (!fortranCompiler.isEmpty()) {
+ m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
+ "Fortran compiler.", fortranCompiler, false);
+ }
+ QString cxxCompiler = dialog.getCXXCompiler();
+ if (!cxxCompiler.isEmpty()) {
+ m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
+ "CXX compiler.", cxxCompiler, false);
+ }
+
+ QString cCompiler = dialog.getCCompiler();
+ if (!cCompiler.isEmpty()) {
+ m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
+ "C compiler.", cCompiler, false);
+ }
+ } else if (dialog.crossCompilerSetup()) {
+ QString fortranCompiler = dialog.getFortranCompiler();
+ if (!fortranCompiler.isEmpty()) {
+ m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
+ "Fortran compiler.", fortranCompiler, false);
+ }
+
+ QString mode = dialog.getCrossIncludeMode();
+ m->insertProperty(QCMakeProperty::STRING,
+ "CMAKE_FIND_ROOT_PATH_MODE_INCLUDE",
+ tr("CMake Find Include Mode"), mode, false);
+ mode = dialog.getCrossLibraryMode();
+ m->insertProperty(QCMakeProperty::STRING,
+ "CMAKE_FIND_ROOT_PATH_MODE_LIBRARY",
+ tr("CMake Find Library Mode"), mode, false);
+ mode = dialog.getCrossProgramMode();
+ m->insertProperty(QCMakeProperty::STRING,
+ "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM",
+ tr("CMake Find Program Mode"), mode, false);
+
+ QString rootPath = dialog.getCrossRoot();
+ m->insertProperty(QCMakeProperty::PATH, "CMAKE_FIND_ROOT_PATH",
+ tr("CMake Find Root Path"), rootPath, false);
+
+ QString systemName = dialog.getSystemName();
+ m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_NAME",
+ tr("CMake System Name"), systemName, false);
+ QString systemVersion = dialog.getSystemVersion();
+ m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_VERSION",
+ tr("CMake System Version"), systemVersion, false);
+ QString systemProcessor = dialog.getSystemProcessor();
+ m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_PROCESSOR",
+ tr("CMake System Processor"), systemProcessor, false);
+ QString cxxCompiler = dialog.getCXXCompiler();
+ if (!cxxCompiler.isEmpty()) {
+ m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
+ tr("CXX compiler."), cxxCompiler, false);
+ }
+ QString cCompiler = dialog.getCCompiler();
+ if (!cCompiler.isEmpty()) {
+ m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
+ tr("C compiler."), cCompiler, false);
+ }
+ } else if (dialog.crossCompilerToolChainFile()) {
+ QString toolchainFile = dialog.getCrossCompilerToolChainFile();
+ m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_TOOLCHAIN_FILE",
+ tr("Cross Compile ToolChain File"), toolchainFile,
+ false);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void CMakeSetupDialog::updateGeneratorLabel(const QString& gen)
+{
+ QString str = tr("Current Generator: ");
+ if (gen.isEmpty()) {
+ str += tr("None");
+ } else {
+ str += gen;
+ }
+ this->Generator->setText(str);
+}
+
+void CMakeSetupDialog::doReloadCache()
+{
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "reloadCache",
+ Qt::QueuedConnection);
+}
+
+void CMakeSetupDialog::doDeleteCache()
+{
+ QString title = tr("Delete Cache");
+ QString msg = tr("Are you sure you want to delete the cache?");
+ QMessageBox::StandardButton btn;
+ btn = QMessageBox::information(this, title, msg,
+ QMessageBox::Yes | QMessageBox::No);
+ if (btn == QMessageBox::No) {
+ return;
+ }
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "deleteCache",
+ Qt::QueuedConnection);
+}
+
+void CMakeSetupDialog::doAbout()
+{
+ QString msg = tr(
+ "CMake %1 (cmake.org).\n"
+ "CMake suite maintained and supported by Kitware (kitware.com/cmake).\n"
+ "Distributed under terms of the BSD 3-Clause License.\n"
+ "\n"
+ "CMake GUI maintained by csimsoft,\n"
+ "built using Qt %2 (qt-project.org).\n"
+#ifdef USE_LGPL
+ "\n"
+ "The Qt Toolkit is Copyright (C) The Qt Company Ltd.\n"
+ "Qt is licensed under terms of the GNU LGPLv" USE_LGPL ", available at:\n"
+ " \"%3\""
+#endif
+ );
+ msg = msg.arg(cmVersion::GetCMakeVersion());
+ msg = msg.arg(qVersion());
+#ifdef USE_LGPL
+ std::string lgpl =
+ cmSystemTools::GetCMakeRoot() + "/Licenses/LGPLv" USE_LGPL ".txt";
+ msg = msg.arg(lgpl.c_str());
+#endif
+
+ QDialog dialog;
+ dialog.setWindowTitle(tr("About"));
+ QVBoxLayout* l = new QVBoxLayout(&dialog);
+ QLabel* lab = new QLabel(&dialog);
+ l->addWidget(lab);
+ lab->setText(msg);
+ lab->setWordWrap(true);
+ QDialogButtonBox* btns =
+ new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog);
+ QObject::connect(btns, &QDialogButtonBox::accepted, &dialog,
+ &QDialog::accept);
+ l->addWidget(btns);
+ dialog.exec();
+}
+
+void CMakeSetupDialog::setExitAfterGenerate(bool b)
+{
+ this->ExitAfterGenerate = b;
+}
+
+void CMakeSetupDialog::addBinaryPath(const QString& path)
+{
+ QString cleanpath = QDir::cleanPath(path);
+
+ // update UI
+ this->BinaryDirectory->blockSignals(true);
+ int idx = this->BinaryDirectory->findText(cleanpath);
+ if (idx != -1) {
+ this->BinaryDirectory->removeItem(idx);
+ }
+ this->BinaryDirectory->insertItem(0, cleanpath);
+ this->BinaryDirectory->setCurrentIndex(0);
+ this->BinaryDirectory->blockSignals(false);
+
+ // save to registry
+ QStringList buildPaths = this->loadBuildPaths();
+ buildPaths.removeAll(cleanpath);
+ buildPaths.prepend(cleanpath);
+ this->saveBuildPaths(buildPaths);
+}
+
+void CMakeSetupDialog::dragEnterEvent(QDragEnterEvent* e)
+{
+ if (!(this->CurrentState == ReadyConfigure ||
+ this->CurrentState == ReadyGenerate)) {
+ e->ignore();
+ return;
+ }
+
+ const QMimeData* dat = e->mimeData();
+ QList<QUrl> urls = dat->urls();
+ QString file = urls.count() ? urls[0].toLocalFile() : QString();
+ if (!file.isEmpty() &&
+ (file.endsWith("CMakeCache.txt", Qt::CaseInsensitive) ||
+ file.endsWith("CMakeLists.txt", Qt::CaseInsensitive))) {
+ e->accept();
+ } else {
+ e->ignore();
+ }
+}
+
+void CMakeSetupDialog::dropEvent(QDropEvent* e)
+{
+ if (!(this->CurrentState == ReadyConfigure ||
+ this->CurrentState == ReadyGenerate)) {
+ return;
+ }
+
+ const QMimeData* dat = e->mimeData();
+ QList<QUrl> urls = dat->urls();
+ QString file = urls.count() ? urls[0].toLocalFile() : QString();
+ if (file.endsWith("CMakeCache.txt", Qt::CaseInsensitive)) {
+ QFileInfo info(file);
+ if (this->CMakeThread->cmakeInstance()->binaryDirectory() !=
+ info.absolutePath()) {
+ this->setBinaryDirectory(info.absolutePath());
+ }
+ } else if (file.endsWith("CMakeLists.txt", Qt::CaseInsensitive)) {
+ QFileInfo info(file);
+ if (this->CMakeThread->cmakeInstance()->binaryDirectory() !=
+ info.absolutePath()) {
+ this->setSourceDirectory(info.absolutePath());
+ this->setBinaryDirectory(info.absolutePath());
+ }
+ }
+}
+
+QStringList CMakeSetupDialog::loadBuildPaths()
+{
+ QSettings settings;
+ settings.beginGroup("Settings/StartPath");
+
+ QStringList buildPaths;
+ for (int i = 0; i < 10; i++) {
+ QString p = settings.value(QString("WhereBuild%1").arg(i)).toString();
+ if (!p.isEmpty()) {
+ buildPaths.append(p);
+ }
+ }
+ return buildPaths;
+}
+
+void CMakeSetupDialog::saveBuildPaths(const QStringList& paths)
+{
+ QSettings settings;
+ settings.beginGroup("Settings/StartPath");
+
+ int num = paths.count();
+ if (num > 10) {
+ num = 10;
+ }
+
+ for (int i = 0; i < num; i++) {
+ settings.setValue(QString("WhereBuild%1").arg(i), paths[i]);
+ }
+}
+
+void CMakeSetupDialog::setCacheModified()
+{
+ this->CacheModified = true;
+ this->ConfigureNeeded = true;
+ this->enterState(ReadyConfigure);
+}
+
+void CMakeSetupDialog::removeSelectedCacheEntries()
+{
+ QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
+ QList<QPersistentModelIndex> pidxs;
+ foreach (QModelIndex const& i, idxs) {
+ pidxs.append(i);
+ }
+ foreach (QPersistentModelIndex const& pi, pidxs) {
+ this->CacheValues->model()->removeRow(pi.row(), pi.parent());
+ }
+}
+
+void CMakeSetupDialog::selectionChanged()
+{
+ QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
+ if (idxs.count() &&
+ (this->CurrentState == ReadyConfigure ||
+ this->CurrentState == ReadyGenerate)) {
+ this->RemoveEntry->setEnabled(true);
+ } else {
+ this->RemoveEntry->setEnabled(false);
+ }
+}
+
+void CMakeSetupDialog::enterState(CMakeSetupDialog::State s)
+{
+ if (s == this->CurrentState) {
+ return;
+ }
+
+ this->CurrentState = s;
+
+ if (s == Interrupting) {
+ this->ConfigureButton->setEnabled(false);
+ this->GenerateButton->setEnabled(false);
+ this->OpenProjectButton->setEnabled(false);
+ } else if (s == Configuring) {
+ this->setEnabledState(false);
+ this->GenerateButton->setEnabled(false);
+ this->GenerateAction->setEnabled(false);
+ this->OpenProjectButton->setEnabled(false);
+ this->ConfigureButton->setText(tr("&Stop"));
+ } else if (s == Generating) {
+ this->CacheModified = false;
+ this->setEnabledState(false);
+ this->ConfigureButton->setEnabled(false);
+ this->GenerateAction->setEnabled(false);
+ this->OpenProjectButton->setEnabled(false);
+ this->GenerateButton->setText(tr("&Stop"));
+ } else if (s == ReadyConfigure || s == ReadyGenerate) {
+ this->setEnabledState(true);
+ this->GenerateButton->setEnabled(true);
+ this->GenerateAction->setEnabled(true);
+ this->ConfigureButton->setEnabled(true);
+ this->ConfigureButton->setText(tr("&Configure"));
+ this->GenerateButton->setText(tr("&Generate"));
+ }
+}
+
+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);
+ dialog.resize(400, 200);
+ dialog.setWindowTitle(tr("Add Cache Entry"));
+ QVBoxLayout* l = new QVBoxLayout(&dialog);
+ AddCacheEntry* w =
+ new AddCacheEntry(&dialog, this->AddVariableNames, this->AddVariableTypes);
+ QDialogButtonBox* btns = new QDialogButtonBox(
+ QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);
+ QObject::connect(btns, &QDialogButtonBox::accepted, &dialog,
+ &QDialog::accept);
+ QObject::connect(btns, &QDialogButtonBox::rejected, &dialog,
+ &QDialog::reject);
+ l->addWidget(w);
+ l->addStretch();
+ l->addWidget(btns);
+ if (QDialog::Accepted == dialog.exec()) {
+ QCMakeCacheModel* m = this->CacheValues->cacheModel();
+ m->insertProperty(w->type(), w->name(), w->description(), w->value(),
+ false);
+
+ // only add variable names to the completion which are new
+ if (!this->AddVariableNames.contains(w->name())) {
+ this->AddVariableNames << w->name();
+ this->AddVariableTypes << w->typeString();
+ // limit to at most 100 completion items
+ if (this->AddVariableNames.size() > 100) {
+ this->AddVariableNames.removeFirst();
+ this->AddVariableTypes.removeFirst();
+ }
+ // make sure CMAKE_INSTALL_PREFIX is always there
+ if (!this->AddVariableNames.contains("CMAKE_INSTALL_PREFIX")) {
+ this->AddVariableNames << "CMAKE_INSTALL_PREFIX";
+ this->AddVariableTypes << "PATH";
+ }
+ QSettings settings;
+ settings.beginGroup("Settings/StartPath");
+ settings.setValue("AddVariableNames", this->AddVariableNames);
+ settings.setValue("AddVariableTypes", this->AddVariableTypes);
+ }
+ }
+}
+
+void CMakeSetupDialog::startSearch()
+{
+ this->Search->setFocus(Qt::OtherFocusReason);
+ this->Search->selectAll();
+}
+
+void CMakeSetupDialog::setDebugOutput(bool flag)
+{
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
+ "setDebugOutput", Qt::QueuedConnection,
+ Q_ARG(bool, flag));
+}
+
+void CMakeSetupDialog::setGroupedView(bool v)
+{
+ this->CacheValues->cacheModel()->setViewType(v ? QCMakeCacheModel::GroupView
+ : QCMakeCacheModel::FlatView);
+ this->CacheValues->setRootIsDecorated(v);
+
+ QSettings settings;
+ settings.beginGroup("Settings/StartPath");
+ settings.setValue("GroupView", v);
+}
+
+void CMakeSetupDialog::setAdvancedView(bool v)
+{
+ this->CacheValues->setShowAdvanced(v);
+ QSettings settings;
+ settings.beginGroup("Settings/StartPath");
+ settings.setValue("AdvancedView", v);
+}
+
+void CMakeSetupDialog::showUserChanges()
+{
+ QSet<QCMakeProperty> changes =
+ qobject_cast<QCMakeCacheModelDelegate*>(this->CacheValues->itemDelegate())
+ ->changes();
+
+ QDialog dialog(this);
+ dialog.setWindowTitle(tr("My Changes"));
+ dialog.resize(600, 400);
+ QVBoxLayout* l = new QVBoxLayout(&dialog);
+ QTextEdit* textedit = new QTextEdit(&dialog);
+ textedit->setReadOnly(true);
+ l->addWidget(textedit);
+ QDialogButtonBox* btns =
+ new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog);
+ QObject::connect(btns, &QDialogButtonBox::rejected, &dialog,
+ &QDialog::accept);
+ l->addWidget(btns);
+
+ QString command;
+ QString cache;
+
+ foreach (QCMakeProperty const& prop, changes) {
+ QString type;
+ switch (prop.Type) {
+ case QCMakeProperty::BOOL:
+ type = "BOOL";
+ break;
+ case QCMakeProperty::PATH:
+ type = "PATH";
+ break;
+ case QCMakeProperty::FILEPATH:
+ type = "FILEPATH";
+ break;
+ case QCMakeProperty::STRING:
+ type = "STRING";
+ break;
+ }
+ QString value;
+ if (prop.Type == QCMakeProperty::BOOL) {
+ value = prop.Value.toBool() ? "1" : "0";
+ } else {
+ value = prop.Value.toString();
+ }
+
+ QString const line = QString("%1:%2=").arg(prop.Key, type);
+ command += QString("-D%1\"%2\" ").arg(line, value);
+ cache += QString("%1%2\n").arg(line, value);
+ }
+
+ textedit->append(tr("Commandline options:"));
+ textedit->append(command);
+ textedit->append("\n");
+ textedit->append(tr("Cache file:"));
+ textedit->append(cache);
+
+ dialog.exec();
+}
+
+void CMakeSetupDialog::setSearchFilter(const QString& str)
+{
+ this->CacheValues->selectionModel()->clear();
+ this->CacheValues->setSearchFilter(str);
+}
+
+void CMakeSetupDialog::doOutputContextMenu(QPoint pt)
+{
+ std::unique_ptr<QMenu> menu(this->Output->createStandardContextMenu());
+
+ menu->addSeparator();
+ 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();
+ 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));
+}
+
+void CMakeSetupDialog::doOutputFindDialog()
+{
+ QStringList strings(this->FindHistory);
+
+ QString selection = this->Output->textCursor().selectedText();
+ if (!selection.isEmpty() && !selection.contains(QChar::ParagraphSeparator) &&
+ !selection.contains(QChar::LineSeparator)) {
+ strings.push_front(selection);
+ }
+
+ bool ok;
+ QString search = QInputDialog::getItem(this, tr("Find in Output"),
+ tr("Find:"), strings, 0, true, &ok);
+ if (ok && !search.isEmpty()) {
+ if (!this->FindHistory.contains(search)) {
+ this->FindHistory.push_front(search);
+ }
+ doOutputFindNext();
+ }
+}
+
+void CMakeSetupDialog::doRegexExplorerDialog()
+{
+ RegexExplorer dialog(this);
+ dialog.exec();
+}
+
+void CMakeSetupDialog::doOutputFindPrev()
+{
+ doOutputFindNext(false);
+}
+
+void CMakeSetupDialog::doOutputFindNext(bool directionForward)
+{
+ if (this->FindHistory.isEmpty()) {
+ doOutputFindDialog(); // will re-call this function again
+ return;
+ }
+
+ QString search = this->FindHistory.front();
+
+ QTextCursor textCursor = this->Output->textCursor();
+ QTextDocument* document = this->Output->document();
+ QTextDocument::FindFlags flags;
+ if (!directionForward) {
+ flags |= QTextDocument::FindBackward;
+ }
+
+ textCursor = document->find(search, textCursor, flags);
+
+ if (textCursor.isNull()) {
+ // first search found nothing, wrap around and search again
+ textCursor = this->Output->textCursor();
+ textCursor.movePosition(directionForward ? QTextCursor::Start
+ : QTextCursor::End);
+ textCursor = document->find(search, textCursor, flags);
+ }
+
+ if (textCursor.hasSelection()) {
+ this->Output->setTextCursor(textCursor);
+ }
+}
+
+void CMakeSetupDialog::doOutputErrorNext()
+{
+ QTextCursor textCursor = this->Output->textCursor();
+ bool atEnd = false;
+
+ // move cursor out of current error-block
+ if (textCursor.blockCharFormat() == this->ErrorFormat) {
+ atEnd = !textCursor.movePosition(QTextCursor::NextBlock);
+ }
+
+ // move cursor to next error-block
+ while (textCursor.blockCharFormat() != this->ErrorFormat && !atEnd) {
+ atEnd = !textCursor.movePosition(QTextCursor::NextBlock);
+ }
+
+ if (atEnd) {
+ // first search found nothing, wrap around and search again
+ atEnd = !textCursor.movePosition(QTextCursor::Start);
+
+ // move cursor to next error-block
+ while (textCursor.blockCharFormat() != this->ErrorFormat && !atEnd) {
+ atEnd = !textCursor.movePosition(QTextCursor::NextBlock);
+ }
+ }
+
+ if (!atEnd) {
+ textCursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+
+ QTextCharFormat selectionFormat;
+ selectionFormat.setBackground(Qt::yellow);
+ QTextEdit::ExtraSelection extraSelection = { textCursor, selectionFormat };
+ this->Output->setExtraSelections(QList<QTextEdit::ExtraSelection>()
+ << extraSelection);
+
+ // make the whole error-block visible
+ this->Output->setTextCursor(textCursor);
+
+ // remove the selection to see the extraSelection
+ textCursor.setPosition(textCursor.anchor());
+ this->Output->setTextCursor(textCursor);
+ }
+}
+
+void CMakeSetupDialog::doWarningMessagesDialog()
+{
+ WarningMessagesDialog dialog(this, this->CMakeThread->cmakeInstance());
+ dialog.exec();
+}
diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h
new file mode 100644
index 0000000..f0cc929
--- /dev/null
+++ b/Source/QtDialog/CMakeSetupDialog.h
@@ -0,0 +1,160 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <memory>
+
+#include "QCMake.h"
+#include "QCMakePreset.h"
+#include <QEventLoop>
+#include <QMainWindow>
+#include <QThread>
+#include <QVector>
+
+#include "ui_CMakeSetupDialog.h"
+
+class QCMakePresetItemModel;
+class QCMakeThread;
+class CMakeCacheModel;
+class QProgressBar;
+class QToolButton;
+
+#ifdef QT_WINEXTRAS
+class QWinTaskbarButton;
+#endif
+
+/// Qt user interface for CMake
+class CMakeSetupDialog
+ : public QMainWindow
+ , public Ui::CMakeSetupDialog
+{
+ Q_OBJECT
+public:
+ CMakeSetupDialog();
+ ~CMakeSetupDialog();
+
+public slots:
+ void setBinaryDirectory(const QString& dir);
+ void setSourceDirectory(const QString& dir);
+ void setDeferredPreset(const QString& preset);
+ void setStartupBinaryDirectory(bool startup);
+
+protected slots:
+ void initialize();
+ void doConfigure();
+ void doGenerate();
+ void doOpenProject();
+ void doInstallForCommandLine();
+ void doHelp();
+ void doAbout();
+ void doInterrupt();
+ void error(const QString& message);
+ void message(const QString& message);
+
+ void doSourceBrowse();
+ void doBinaryBrowse();
+ void doReloadCache();
+ void doDeleteCache();
+ void updateSourceDirectory(const QString& dir);
+ void updateBinaryDirectory(const QString& dir);
+ void updatePresets(const QVector<QCMakePreset>& presets);
+ void updatePreset(const QString& name);
+ void showPresetLoadError(const QString& dir,
+ cmCMakePresetsFile::ReadFileResult result);
+ void showProgress(const QString& msg, float percent);
+ void setEnabledState(bool);
+ bool setupFirstConfigure();
+ void updateGeneratorLabel(const QString& gen);
+ void setExitAfterGenerate(bool);
+ void addBinaryPath(const QString&);
+ QStringList loadBuildPaths();
+ void saveBuildPaths(const QStringList&);
+ void onBinaryDirectoryChanged(const QString& dir);
+ void onSourceDirectoryChanged(const QString& dir);
+ void onBuildPresetChanged(const QString& name);
+ void setCacheModified();
+ void removeSelectedCacheEntries();
+ void selectionChanged();
+ void editEnvironment();
+ void addCacheEntry();
+ void startSearch();
+ void setDebugOutput(bool);
+ void setAdvancedView(bool);
+ void setGroupedView(bool);
+ void showUserChanges();
+ void setSearchFilter(const QString& str);
+ bool prepareConfigure();
+ bool doConfigureInternal();
+ bool doGenerateInternal();
+ void exitLoop(int);
+ void doOutputContextMenu(QPoint pt);
+ void doOutputFindDialog();
+ void doOutputFindNext(bool directionForward = true);
+ void doOutputFindPrev();
+ void doOutputErrorNext();
+ void doRegexExplorerDialog();
+ /// display the modal warning messages dialog window
+ void doWarningMessagesDialog();
+
+protected:
+ enum State
+ {
+ Interrupting,
+ ReadyConfigure,
+ ReadyGenerate,
+ Configuring,
+ Generating
+ };
+ void enterState(State s);
+
+ void closeEvent(QCloseEvent*);
+ void dragEnterEvent(QDragEnterEvent*);
+ void dropEvent(QDropEvent*);
+
+ QCMakeThread* CMakeThread;
+ bool ExitAfterGenerate;
+ bool CacheModified;
+ bool ConfigureNeeded;
+ QAction* ReloadCacheAction;
+ QAction* DeleteCacheAction;
+ QAction* ExitAction;
+ QAction* ConfigureAction;
+ QAction* GenerateAction;
+ QAction* WarnUninitializedAction;
+ QAction* InstallForCommandLineAction;
+ State CurrentState;
+ QString DeferredPreset;
+ bool StartupBinaryDirectory = false;
+
+ QTextCharFormat ErrorFormat;
+ QTextCharFormat MessageFormat;
+
+ QStringList AddVariableNames;
+ QStringList AddVariableTypes;
+ QStringList FindHistory;
+
+ QEventLoop LocalLoop;
+
+#ifdef QT_WINEXTRAS
+ QWinTaskbarButton* TaskbarButton;
+#endif
+
+ float ProgressOffset;
+ float ProgressFactor;
+};
+
+// QCMake instance on a thread
+class QCMakeThread : public QThread
+{
+ Q_OBJECT
+public:
+ QCMakeThread(QObject* p);
+ QCMake* cmakeInstance() const;
+
+signals:
+ void cmakeInitialized();
+
+protected:
+ virtual void run();
+ std::unique_ptr<QCMake> CMakeInstance;
+};
diff --git a/Source/QtDialog/CMakeSetupDialog.ui b/Source/QtDialog/CMakeSetupDialog.ui
new file mode 100644
index 0000000..c17c414
--- /dev/null
+++ b/Source/QtDialog/CMakeSetupDialog.ui
@@ -0,0 +1,385 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CMakeSetupDialog</class>
+ <widget class="QWidget" name="CMakeSetupDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>707</width>
+ <height>582</height>
+ </rect>
+ </property>
+ <layout class="QGridLayout">
+ <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">
+ <number>6</number>
+ </property>
+ <item row="0" column="0">
+ <layout class="QGridLayout">
+ <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">
+ <number>6</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="SourceLabel">
+ <property name="text">
+ <string>Where is the source code:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="SourceDirectory"/>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="BrowseSourceDirectoryButton">
+ <property name="text">
+ <string>Browse &amp;Source...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="PresetLabel">
+ <property name="text">
+ <string>Preset:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QCMakePresetComboBox" name="Preset">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="BinaryLabel">
+ <property name="text">
+ <string>Where to build the binaries:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QComboBox" name="BinaryDirectory">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QPushButton" name="BrowseBinaryDirectoryButton">
+ <property name="text">
+ <string>Browse &amp;Build...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="QSplitter" name="Splitter">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <widget class="QFrame" name="frame">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <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>
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <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>
+ <widget class="QLabel" name="label_4">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>S&amp;earch:</string>
+ </property>
+ <property name="buddy">
+ <cstring>Search</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="Search">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <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>23</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="groupedCheck">
+ <property name="text">
+ <string>Grouped</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="advancedCheck">
+ <property name="text">
+ <string>Advanced</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="AddEntry">
+ <property name="toolTip">
+ <string>Add New Entry</string>
+ </property>
+ <property name="text">
+ <string>&amp;Add Entry</string>
+ </property>
+ <property name="icon">
+ <iconset theme="list-add" resource="CMakeSetup.qrc">
+ <normaloff>:/Icons/Plus16.png</normaloff>:/Icons/Plus16.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="RemoveEntry">
+ <property name="toolTip">
+ <string>Remove Selected Entries</string>
+ </property>
+ <property name="text">
+ <string>&amp;Remove Entry</string>
+ </property>
+ <property name="icon">
+ <iconset theme="list-remove" resource="CMakeSetup.qrc">
+ <normaloff>:/Icons/Delete16.png</normaloff>:/Icons/Delete16.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="Environment">
+ <property name="text">
+ <string>E&amp;nvironment...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCMakeCacheView" name="CacheValues">
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::ExtendedSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Press Configure to update and display new values in red, then press Generate to generate selected build files.</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <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>
+ <widget class="QPushButton" name="ConfigureButton">
+ <property name="text">
+ <string>&amp;Configure</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="GenerateButton">
+ <property name="text">
+ <string>&amp;Generate</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">
+ <string>Current Generator:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>121</width>
+ <height>27</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QProgressBar" name="ProgressBar">
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>0</number>
+ </property>
+ <property name="textVisible">
+ <bool>false</bool>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="textDirection">
+ <enum>QProgressBar::BottomToTop</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QTextEdit" name="Output">
+ <property name="lineWrapMode">
+ <enum>QTextEdit::NoWrap</enum>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QCMakeCacheView</class>
+ <extends>QTreeView</extends>
+ <header>QCMakeCacheView.h</header>
+ </customwidget>
+ <customwidget>
+ <class>QCMakePresetComboBox</class>
+ <extends>QComboBox</extends>
+ <header>QCMakePresetComboBox.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="CMakeSetup.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/Source/QtDialog/Compilers.h b/Source/QtDialog/Compilers.h
new file mode 100644
index 0000000..5da0781
--- /dev/null
+++ b/Source/QtDialog/Compilers.h
@@ -0,0 +1,22 @@
+
+
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <ui_Compilers.h>
+
+#include <QWidget>
+
+class Compilers
+ : public QWidget
+ , public Ui::Compilers
+{
+ Q_OBJECT
+public:
+ Compilers(QWidget* p = nullptr)
+ : QWidget(p)
+ {
+ this->setupUi(this);
+ }
+};
diff --git a/Source/QtDialog/Compilers.ui b/Source/QtDialog/Compilers.ui
new file mode 100644
index 0000000..41f70ac
--- /dev/null
+++ b/Source/QtDialog/Compilers.ui
@@ -0,0 +1,87 @@
+<ui version="4.0" >
+ <class>Compilers</class>
+ <widget class="QWidget" name="Compilers" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>506</width>
+ <height>115</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" >
+ <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 row="0" column="0" >
+ <widget class="QGroupBox" name="groupBox_4" >
+ <property name="title" >
+ <string>Compilers</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="leftMargin" >
+ <number>4</number>
+ </property>
+ <property name="topMargin" >
+ <number>4</number>
+ </property>
+ <property name="rightMargin" >
+ <number>4</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_16" >
+ <property name="text" >
+ <string>C</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QCMakeFilePathEditor" name="CCompiler" />
+ </item>
+ <item row="0" column="2" >
+ <widget class="QLabel" name="label_17" >
+ <property name="text" >
+ <string>C++</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3" >
+ <widget class="QCMakeFilePathEditor" name="CXXCompiler" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_18" >
+ <property name="text" >
+ <string>Fortran</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QCMakeFilePathEditor" name="FortranCompiler" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QCMakeFilePathEditor</class>
+ <extends>QLineEdit</extends>
+ <header>QCMakeWidgets.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Source/QtDialog/CrossCompiler.ui b/Source/QtDialog/CrossCompiler.ui
new file mode 100644
index 0000000..1fb1ebf
--- /dev/null
+++ b/Source/QtDialog/CrossCompiler.ui
@@ -0,0 +1,213 @@
+<ui version="4.0" >
+ <class>CrossCompiler</class>
+ <widget class="QWidget" name="CrossCompiler" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>433</width>
+ <height>319</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>CrossCompiler</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>Target System</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_6" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Operating System</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="systemName" />
+ </item>
+ <item row="0" column="2" colspan="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_10" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Version</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="systemVersion" />
+ </item>
+ <item row="1" column="2" >
+ <widget class="QLabel" name="label_11" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Processor</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3" >
+ <widget class="QLineEdit" name="systemProcessor" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QGroupBox" name="groupBox_2" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>Find Program/Library/Include</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_9" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Target Root</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QCMakePathEditor" name="crossFindRoot" />
+ </item>
+ <item row="0" column="2" >
+ <widget class="QLabel" name="label_12" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Program Mode</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3" >
+ <widget class="QComboBox" name="crossProgramMode" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_13" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Library Mode</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="crossLibraryMode" />
+ </item>
+ <item row="1" column="2" >
+ <widget class="QLabel" name="label_14" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Include Mode</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3" >
+ <widget class="QComboBox" name="crossIncludeMode" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="Compilers" native="1" name="CrossCompilers" >
+ <property name="focusPolicy" >
+ <enum>Qt::TabFocus</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QCMakePathEditor</class>
+ <extends>QLineEdit</extends>
+ <header>QCMakeWidgets.h</header>
+ </customwidget>
+ <customwidget>
+ <class>Compilers</class>
+ <extends>QWidget</extends>
+ <header>Compilers.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <tabstops>
+ <tabstop>systemVersion</tabstop>
+ <tabstop>systemProcessor</tabstop>
+ <tabstop>CrossCompilers</tabstop>
+ <tabstop>crossFindRoot</tabstop>
+ <tabstop>crossProgramMode</tabstop>
+ <tabstop>crossLibraryMode</tabstop>
+ <tabstop>crossIncludeMode</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Source/QtDialog/Delete16.png b/Source/QtDialog/Delete16.png
new file mode 100644
index 0000000..9d2f2b7
--- /dev/null
+++ b/Source/QtDialog/Delete16.png
Binary files differ
diff --git a/Source/QtDialog/EnvironmentDialog.cxx b/Source/QtDialog/EnvironmentDialog.cxx
new file mode 100644
index 0000000..bf89816
--- /dev/null
+++ b/Source/QtDialog/EnvironmentDialog.cxx
@@ -0,0 +1,204 @@
+/* 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();
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+ return key.contains(this->filterRegularExpression());
+#else
+ return key.contains(this->filterRegExp());
+#endif
+}
+
+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, &QAbstractButton::clicked, this,
+ &EnvironmentDialog::addEntry);
+ QObject::connect(this->RemoveEntry, &QAbstractButton::clicked, this,
+ &EnvironmentDialog::removeSelectedEntries);
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+ QObject::connect(this->Search, &QLineEdit::textChanged, this->m_filter,
+ QOverload<const QString&>::of(
+ &EnvironmentSearchFilter::setFilterRegularExpression));
+#else
+ QObject::connect(this->Search, &QLineEdit::textChanged, this->m_filter,
+ &EnvironmentSearchFilter::setFilterFixedString);
+#endif
+ 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..ed23c2c
--- /dev/null
+++ b/Source/QtDialog/EnvironmentDialog.ui
@@ -0,0 +1,124 @@
+<?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="QPushButton" name="AddEntry">
+ <property name="text">
+ <string>&amp;Add Entry</string>
+ </property>
+ <property name="icon">
+ <iconset theme="list-add" resource="CMakeSetup.qrc">
+ <normaloff>:/Icons/Plus16.png</normaloff>:/Icons/Plus16.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="RemoveEntry">
+ <property name="text">
+ <string>&amp;Remove Entry</string>
+ </property>
+ <property name="icon">
+ <iconset theme="list-remove" resource="CMakeSetup.qrc">
+ <normaloff>:/Icons/Delete16.png</normaloff>:/Icons/Delete16.png</iconset>
+ </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
new file mode 100644
index 0000000..10360bb
--- /dev/null
+++ b/Source/QtDialog/FirstConfigure.cxx
@@ -0,0 +1,744 @@
+
+#include "FirstConfigure.h"
+
+#include <QComboBox>
+#include <QRadioButton>
+#include <QSettings>
+#include <QVBoxLayout>
+
+#include "cmStringAlgorithms.h"
+
+#include "Compilers.h"
+
+StartCompilerSetup::StartCompilerSetup(QString defaultGeneratorPlatform,
+ QString defaultGeneratorToolset,
+ QWidget* p)
+ : QWizardPage(p)
+ , DefaultGeneratorPlatform(std::move(defaultGeneratorPlatform))
+ , DefaultGeneratorToolset(std::move(defaultGeneratorToolset))
+{
+ QVBoxLayout* l = new QVBoxLayout(this);
+ l->addWidget(new QLabel(tr("Specify the generator for this project")));
+ this->GeneratorOptions = new QComboBox(this);
+ l->addWidget(this->GeneratorOptions);
+
+ // Add the generator platform
+ this->PlatformFrame = CreatePlatformWidgets();
+ l->addWidget(PlatformFrame);
+
+ // Add the ability to specify toolset (-T parameter)
+ this->ToolsetFrame = CreateToolsetWidgets();
+ l->addWidget(ToolsetFrame);
+
+ l->addSpacing(6);
+
+ this->CompilerSetupOptions[0] =
+ new QRadioButton(tr("Use default native compilers"), this);
+ this->CompilerSetupOptions[1] =
+ new QRadioButton(tr("Specify native compilers"), this);
+ this->CompilerSetupOptions[2] =
+ new QRadioButton(tr("Specify toolchain file for cross-compiling"), this);
+ this->CompilerSetupOptions[3] =
+ new QRadioButton(tr("Specify options for cross-compiling"), this);
+ l->addWidget(this->CompilerSetupOptions[0]);
+ l->addWidget(this->CompilerSetupOptions[1]);
+ l->addWidget(this->CompilerSetupOptions[2]);
+ l->addWidget(this->CompilerSetupOptions[3]);
+
+ this->CompilerSetupOptions[0]->setChecked(true);
+
+ 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()
+{
+ QFrame* frame = new QFrame(this);
+ QVBoxLayout* l = new QVBoxLayout(frame);
+ l->setContentsMargins(0, 0, 0, 0);
+
+ ToolsetLabel = new QLabel(tr("Optional toolset to use (argument to -T)"));
+ l->addWidget(ToolsetLabel);
+
+ Toolset = new QLineEdit(frame);
+ l->addWidget(Toolset);
+
+ // Default to CMAKE_GENERATOR_TOOLSET env var if set
+ if (!DefaultGeneratorToolset.isEmpty()) {
+ this->Toolset->setText(DefaultGeneratorToolset);
+ }
+ return frame;
+}
+
+QFrame* StartCompilerSetup::CreatePlatformWidgets()
+{
+ QFrame* frame = new QFrame(this);
+ QVBoxLayout* l = new QVBoxLayout(frame);
+ l->setContentsMargins(0, 0, 0, 0);
+
+ this->PlatformLabel = new QLabel(tr("Optional platform for generator"));
+ l->addWidget(this->PlatformLabel);
+
+ this->PlatformOptions = new QComboBox(frame);
+ this->PlatformOptions->setEditable(true);
+
+ l->addWidget(this->PlatformOptions);
+
+ return frame;
+}
+
+StartCompilerSetup::~StartCompilerSetup() = default;
+
+void StartCompilerSetup::setGenerators(
+ std::vector<cmake::GeneratorInfo> const& gens)
+{
+ this->GeneratorOptions->clear();
+
+ QStringList generator_list;
+
+ for (cmake::GeneratorInfo const& gen : gens) {
+ generator_list.append(QString::fromLocal8Bit(gen.name.c_str()));
+
+ if (gen.supportsPlatform) {
+ this->GeneratorsSupportingPlatform.append(
+ QString::fromLocal8Bit(gen.name.c_str()));
+
+ this
+ ->GeneratorDefaultPlatform[QString::fromLocal8Bit(gen.name.c_str())] =
+ QString::fromLocal8Bit(gen.defaultPlatform.c_str());
+
+ auto platformIt = gen.supportedPlatforms.cbegin();
+ while (platformIt != gen.supportedPlatforms.cend()) {
+
+ this->GeneratorSupportedPlatforms.insert(
+ QString::fromLocal8Bit(gen.name.c_str()),
+ QString::fromLocal8Bit((*platformIt).c_str()));
+
+ platformIt++;
+ }
+ }
+
+ if (gen.supportsToolset) {
+ this->GeneratorsSupportingToolset.append(
+ QString::fromLocal8Bit(gen.name.c_str()));
+ }
+ }
+
+ this->GeneratorOptions->addItems(generator_list);
+}
+
+void StartCompilerSetup::setCurrentGenerator(const QString& gen)
+{
+ int idx = this->GeneratorOptions->findText(gen);
+ if (idx != -1) {
+ this->GeneratorOptions->setCurrentIndex(idx);
+ }
+}
+
+void StartCompilerSetup::setPlatform(const QString& platform)
+{
+ this->PlatformOptions->setCurrentText(platform);
+}
+
+void StartCompilerSetup::setToolset(const QString& toolset)
+{
+ this->Toolset->setText(toolset);
+}
+
+void StartCompilerSetup::setCompilerOption(CompilerOption option)
+{
+ std::size_t index = 0;
+ switch (option) {
+ case CompilerOption::DefaultNative:
+ index = 0;
+ break;
+ case CompilerOption::SpecifyNative:
+ index = 1;
+ break;
+ case CompilerOption::ToolchainFile:
+ index = 2;
+ break;
+ case CompilerOption::Options:
+ index = 3;
+ break;
+ }
+ this->CompilerSetupOptions[index]->setChecked(true);
+}
+
+QString StartCompilerSetup::getGenerator() const
+{
+ return this->GeneratorOptions->currentText();
+};
+
+QString StartCompilerSetup::getPlatform() const
+{
+ return this->PlatformOptions->currentText();
+};
+
+QString StartCompilerSetup::getToolset() const
+{
+ return this->Toolset->text();
+};
+
+bool StartCompilerSetup::defaultSetup() const
+{
+ return this->CompilerSetupOptions[0]->isChecked();
+}
+
+bool StartCompilerSetup::compilerSetup() const
+{
+ return this->CompilerSetupOptions[1]->isChecked();
+}
+
+bool StartCompilerSetup::crossCompilerToolChainFile() const
+{
+ return this->CompilerSetupOptions[2]->isChecked();
+}
+
+bool StartCompilerSetup::crossCompilerSetup() const
+{
+ return this->CompilerSetupOptions[3]->isChecked();
+}
+
+void StartCompilerSetup::onSelectionChanged(bool on)
+{
+ if (on) {
+ emit selectionChanged();
+ }
+}
+
+void StartCompilerSetup::onGeneratorChanged(int index)
+{
+ QString name = this->GeneratorOptions->itemText(index);
+
+ // Display the generator platform for the generators supporting it
+ if (GeneratorsSupportingPlatform.contains(name)) {
+
+ // Change the label title to include the default platform
+ std::string label =
+ cmStrCat("Optional platform for generator(if empty, generator uses: ",
+ this->GeneratorDefaultPlatform[name].toStdString(), ')');
+ this->PlatformLabel->setText(tr(label.c_str()));
+
+ // Regenerate the list of supported platform
+ this->PlatformOptions->clear();
+ QStringList platform_list;
+ platform_list.append("");
+
+ QList<QString> platforms = this->GeneratorSupportedPlatforms.values(name);
+ platform_list.append(platforms);
+
+ this->PlatformOptions->addItems(platform_list);
+ PlatformFrame->show();
+
+ // Default to generator platform from environment
+ if (!DefaultGeneratorPlatform.isEmpty()) {
+ int platform_index = platforms.indexOf(DefaultGeneratorPlatform);
+ if (platform_index != -1) {
+ this->PlatformOptions->setCurrentIndex(platform_index);
+ }
+ }
+ } else {
+ PlatformFrame->hide();
+ }
+
+ // Display the toolset box for the generators supporting it
+ if (GeneratorsSupportingToolset.contains(name)) {
+ ToolsetFrame->show();
+ } else {
+ ToolsetFrame->hide();
+ }
+}
+
+int StartCompilerSetup::nextId() const
+{
+ if (compilerSetup()) {
+ return NativeSetup;
+ }
+ if (crossCompilerSetup()) {
+ return CrossSetup;
+ }
+ if (crossCompilerToolChainFile()) {
+ return ToolchainSetup;
+ }
+ return -1;
+}
+
+NativeCompilerSetup::NativeCompilerSetup(QWidget* p)
+ : QWizardPage(p)
+{
+ QVBoxLayout* l = new QVBoxLayout(this);
+ QWidget* c = new QWidget(this);
+ l->addWidget(c);
+ this->setupUi(c);
+}
+
+NativeCompilerSetup::~NativeCompilerSetup() = default;
+
+QString NativeCompilerSetup::getCCompiler() const
+{
+ return this->CCompiler->text();
+}
+
+void NativeCompilerSetup::setCCompiler(const QString& s)
+{
+ this->CCompiler->setText(s);
+}
+
+QString NativeCompilerSetup::getCXXCompiler() const
+{
+ return this->CXXCompiler->text();
+}
+
+void NativeCompilerSetup::setCXXCompiler(const QString& s)
+{
+ this->CXXCompiler->setText(s);
+}
+
+QString NativeCompilerSetup::getFortranCompiler() const
+{
+ return this->FortranCompiler->text();
+}
+
+void NativeCompilerSetup::setFortranCompiler(const QString& s)
+{
+ this->FortranCompiler->setText(s);
+}
+
+CrossCompilerSetup::CrossCompilerSetup(QWidget* p)
+ : QWizardPage(p)
+{
+ this->setupUi(this);
+ QWidget::setTabOrder(systemName, systemVersion);
+ QWidget::setTabOrder(systemVersion, systemProcessor);
+ QWidget::setTabOrder(systemProcessor, CrossCompilers->CCompiler);
+ QWidget::setTabOrder(CrossCompilers->CCompiler, CrossCompilers->CXXCompiler);
+ QWidget::setTabOrder(CrossCompilers->CXXCompiler,
+ CrossCompilers->FortranCompiler);
+ QWidget::setTabOrder(CrossCompilers->FortranCompiler, crossFindRoot);
+ QWidget::setTabOrder(crossFindRoot, crossProgramMode);
+ QWidget::setTabOrder(crossProgramMode, crossLibraryMode);
+ QWidget::setTabOrder(crossLibraryMode, crossIncludeMode);
+
+ // fill in combo boxes
+ QStringList modes;
+ modes << tr("Search in Target Root, then native system");
+ modes << tr("Search only in Target Root");
+ modes << tr("Search only in native system");
+ crossProgramMode->addItems(modes);
+ crossLibraryMode->addItems(modes);
+ crossIncludeMode->addItems(modes);
+ crossProgramMode->setCurrentIndex(2);
+ crossLibraryMode->setCurrentIndex(1);
+ crossIncludeMode->setCurrentIndex(1);
+
+ this->registerField("systemName*", this->systemName);
+}
+
+CrossCompilerSetup::~CrossCompilerSetup() = default;
+
+QString CrossCompilerSetup::getCCompiler() const
+{
+ return this->CrossCompilers->CCompiler->text();
+}
+
+void CrossCompilerSetup::setCCompiler(const QString& s)
+{
+ this->CrossCompilers->CCompiler->setText(s);
+}
+
+QString CrossCompilerSetup::getCXXCompiler() const
+{
+ return this->CrossCompilers->CXXCompiler->text();
+}
+
+void CrossCompilerSetup::setCXXCompiler(const QString& s)
+{
+ this->CrossCompilers->CXXCompiler->setText(s);
+}
+
+QString CrossCompilerSetup::getFortranCompiler() const
+{
+ return this->CrossCompilers->FortranCompiler->text();
+}
+
+void CrossCompilerSetup::setFortranCompiler(const QString& s)
+{
+ this->CrossCompilers->FortranCompiler->setText(s);
+}
+
+QString CrossCompilerSetup::getSystem() const
+{
+ return this->systemName->text();
+}
+
+void CrossCompilerSetup::setSystem(const QString& t)
+{
+ this->systemName->setText(t);
+}
+
+QString CrossCompilerSetup::getVersion() const
+{
+ return this->systemVersion->text();
+}
+
+void CrossCompilerSetup::setVersion(const QString& t)
+{
+ this->systemVersion->setText(t);
+}
+
+QString CrossCompilerSetup::getProcessor() const
+{
+ return this->systemProcessor->text();
+}
+
+void CrossCompilerSetup::setProcessor(const QString& t)
+{
+ this->systemProcessor->setText(t);
+}
+
+QString CrossCompilerSetup::getFindRoot() const
+{
+ return this->crossFindRoot->text();
+}
+
+void CrossCompilerSetup::setFindRoot(const QString& t)
+{
+ this->crossFindRoot->setText(t);
+}
+
+int CrossCompilerSetup::getProgramMode() const
+{
+ return this->crossProgramMode->currentIndex();
+}
+
+int CrossCompilerSetup::getLibraryMode() const
+{
+ return this->crossLibraryMode->currentIndex();
+}
+
+int CrossCompilerSetup::getIncludeMode() const
+{
+ return this->crossIncludeMode->currentIndex();
+}
+
+void CrossCompilerSetup::setProgramMode(int m)
+{
+ this->crossProgramMode->setCurrentIndex(m);
+}
+
+void CrossCompilerSetup::setLibraryMode(int m)
+{
+ this->crossLibraryMode->setCurrentIndex(m);
+}
+
+void CrossCompilerSetup::setIncludeMode(int m)
+{
+ this->crossIncludeMode->setCurrentIndex(m);
+}
+
+ToolchainCompilerSetup::ToolchainCompilerSetup(QWidget* p)
+ : QWizardPage(p)
+{
+ QVBoxLayout* l = new QVBoxLayout(this);
+ l->addWidget(new QLabel(tr("Specify the Toolchain file")));
+ this->ToolchainFile = new QCMakeFilePathEditor(this);
+ l->addWidget(this->ToolchainFile);
+}
+
+ToolchainCompilerSetup::~ToolchainCompilerSetup() = default;
+
+QString ToolchainCompilerSetup::toolchainFile() const
+{
+ return this->ToolchainFile->text();
+}
+
+void ToolchainCompilerSetup::setToolchainFile(const QString& t)
+{
+ this->ToolchainFile->setText(t);
+}
+
+FirstConfigure::FirstConfigure()
+{
+ const char* env_generator = std::getenv("CMAKE_GENERATOR");
+ const char* env_generator_platform = nullptr;
+ const char* env_generator_toolset = nullptr;
+ if (env_generator && std::strlen(env_generator)) {
+ mDefaultGenerator = env_generator;
+ env_generator_platform = std::getenv("CMAKE_GENERATOR_PLATFORM");
+ env_generator_toolset = std::getenv("CMAKE_GENERATOR_TOOLSET");
+ }
+
+ if (!env_generator_platform) {
+ env_generator_platform = "";
+ }
+
+ if (!env_generator_toolset) {
+ env_generator_toolset = "";
+ }
+
+ // this->setOption(QWizard::HaveFinishButtonOnEarlyPages, true);
+ this->mStartCompilerSetupPage = new StartCompilerSetup(
+ env_generator_platform, env_generator_toolset, this);
+ this->setPage(Start, this->mStartCompilerSetupPage);
+ QObject::connect(this->mStartCompilerSetupPage,
+ &StartCompilerSetup::selectionChanged, this,
+ &FirstConfigure::restart);
+ this->mNativeCompilerSetupPage = new NativeCompilerSetup(this);
+ this->setPage(NativeSetup, this->mNativeCompilerSetupPage);
+
+ this->mCrossCompilerSetupPage = new CrossCompilerSetup(this);
+ this->setPage(CrossSetup, this->mCrossCompilerSetupPage);
+
+ this->mToolchainCompilerSetupPage = new ToolchainCompilerSetup(this);
+ this->setPage(ToolchainSetup, this->mToolchainCompilerSetupPage);
+}
+
+FirstConfigure::~FirstConfigure() = default;
+
+void FirstConfigure::setGenerators(
+ std::vector<cmake::GeneratorInfo> const& gens)
+{
+ this->mStartCompilerSetupPage->setGenerators(gens);
+}
+
+void FirstConfigure::setCurrentGenerator(const QString& gen)
+{
+ this->mStartCompilerSetupPage->setCurrentGenerator(gen);
+}
+
+void FirstConfigure::setPlatform(const QString& platform)
+{
+ this->mStartCompilerSetupPage->setPlatform(platform);
+}
+
+void FirstConfigure::setToolset(const QString& toolset)
+{
+ this->mStartCompilerSetupPage->setToolset(toolset);
+}
+
+void FirstConfigure::setCompilerOption(CompilerOption option)
+{
+ this->mStartCompilerSetupPage->setCompilerOption(option);
+}
+
+QString FirstConfigure::getGenerator() const
+{
+ return this->mStartCompilerSetupPage->getGenerator();
+}
+
+QString FirstConfigure::getPlatform() const
+{
+ return this->mStartCompilerSetupPage->getPlatform();
+}
+
+QString FirstConfigure::getToolset() const
+{
+ return this->mStartCompilerSetupPage->getToolset();
+}
+
+void FirstConfigure::loadFromSettings()
+{
+ QSettings settings;
+ // restore generator
+ settings.beginGroup("Settings/StartPath");
+ QString lastGen = settings.value("LastGenerator").toString();
+ this->setCurrentGenerator(lastGen);
+ settings.endGroup();
+
+ // restore compiler setup
+ settings.beginGroup("Settings/Compiler");
+ this->mNativeCompilerSetupPage->setCCompiler(
+ settings.value("CCompiler").toString());
+ this->mNativeCompilerSetupPage->setCXXCompiler(
+ settings.value("CXXCompiler").toString());
+ this->mNativeCompilerSetupPage->setFortranCompiler(
+ settings.value("FortranCompiler").toString());
+ settings.endGroup();
+
+ // restore cross compiler setup
+ settings.beginGroup("Settings/CrossCompiler");
+ this->mCrossCompilerSetupPage->setCCompiler(
+ settings.value("CCompiler").toString());
+ this->mCrossCompilerSetupPage->setCXXCompiler(
+ settings.value("CXXCompiler").toString());
+ this->mCrossCompilerSetupPage->setFortranCompiler(
+ settings.value("FortranCompiler").toString());
+ this->mToolchainCompilerSetupPage->setToolchainFile(
+ settings.value("ToolChainFile").toString());
+ this->mCrossCompilerSetupPage->setSystem(
+ settings.value("SystemName").toString());
+ this->mCrossCompilerSetupPage->setVersion(
+ settings.value("SystemVersion").toString());
+ this->mCrossCompilerSetupPage->setProcessor(
+ settings.value("SystemProcessor").toString());
+ this->mCrossCompilerSetupPage->setFindRoot(
+ settings.value("FindRoot").toString());
+ this->mCrossCompilerSetupPage->setProgramMode(
+ settings.value("ProgramMode", 0).toInt());
+ this->mCrossCompilerSetupPage->setLibraryMode(
+ settings.value("LibraryMode", 0).toInt());
+ this->mCrossCompilerSetupPage->setIncludeMode(
+ settings.value("IncludeMode", 0).toInt());
+ settings.endGroup();
+
+ // environment variables take precedence over application settings because...
+ // - they're harder to set
+ // - settings always exist after the program is run once, so the environment
+ // variables would never be used otherwise
+ // - platform and toolset are populated only from environment variables, so
+ // this prevents them from being taken from environment, while the
+ // generator is taken from application settings
+ if (!mDefaultGenerator.isEmpty()) {
+ this->setCurrentGenerator(mDefaultGenerator);
+ }
+}
+
+void FirstConfigure::saveToSettings()
+{
+ QSettings settings;
+
+ // save generator
+ settings.beginGroup("Settings/StartPath");
+ QString lastGen = this->mStartCompilerSetupPage->getGenerator();
+ settings.setValue("LastGenerator", lastGen);
+ settings.endGroup();
+
+ // save compiler setup
+ settings.beginGroup("Settings/Compiler");
+ settings.setValue("CCompiler",
+ this->mNativeCompilerSetupPage->getCCompiler());
+ settings.setValue("CXXCompiler",
+ this->mNativeCompilerSetupPage->getCXXCompiler());
+ settings.setValue("FortranCompiler",
+ this->mNativeCompilerSetupPage->getFortranCompiler());
+ settings.endGroup();
+
+ // save cross compiler setup
+ settings.beginGroup("Settings/CrossCompiler");
+ settings.setValue("CCompiler",
+ this->mCrossCompilerSetupPage->getCCompiler());
+ settings.setValue("CXXCompiler",
+ this->mCrossCompilerSetupPage->getCXXCompiler());
+ settings.setValue("FortranCompiler",
+ this->mCrossCompilerSetupPage->getFortranCompiler());
+ settings.setValue("ToolChainFile", this->getCrossCompilerToolChainFile());
+ settings.setValue("SystemName", this->mCrossCompilerSetupPage->getSystem());
+ settings.setValue("SystemVersion",
+ this->mCrossCompilerSetupPage->getVersion());
+ settings.setValue("SystemProcessor",
+ this->mCrossCompilerSetupPage->getProcessor());
+ settings.setValue("FindRoot", this->mCrossCompilerSetupPage->getFindRoot());
+ settings.setValue("ProgramMode",
+ this->mCrossCompilerSetupPage->getProgramMode());
+ settings.setValue("LibraryMode",
+ this->mCrossCompilerSetupPage->getLibraryMode());
+ settings.setValue("IncludeMode",
+ this->mCrossCompilerSetupPage->getIncludeMode());
+ settings.endGroup();
+}
+
+bool FirstConfigure::defaultSetup() const
+{
+ return this->mStartCompilerSetupPage->defaultSetup();
+}
+
+bool FirstConfigure::compilerSetup() const
+{
+ return this->mStartCompilerSetupPage->compilerSetup();
+}
+
+bool FirstConfigure::crossCompilerSetup() const
+{
+ return this->mStartCompilerSetupPage->crossCompilerSetup();
+}
+
+bool FirstConfigure::crossCompilerToolChainFile() const
+{
+ return this->mStartCompilerSetupPage->crossCompilerToolChainFile();
+}
+
+QString FirstConfigure::getCrossCompilerToolChainFile() const
+{
+ return this->mToolchainCompilerSetupPage->toolchainFile();
+}
+
+QString FirstConfigure::getSystemName() const
+{
+ return this->mCrossCompilerSetupPage->getSystem();
+}
+
+QString FirstConfigure::getCCompiler() const
+{
+ if (this->compilerSetup()) {
+ return this->mNativeCompilerSetupPage->getCCompiler();
+ }
+ if (this->crossCompilerSetup()) {
+ return this->mCrossCompilerSetupPage->getCCompiler();
+ }
+ return QString();
+}
+
+QString FirstConfigure::getCXXCompiler() const
+{
+ if (this->compilerSetup()) {
+ return this->mNativeCompilerSetupPage->getCXXCompiler();
+ }
+ if (this->crossCompilerSetup()) {
+ return this->mCrossCompilerSetupPage->getCXXCompiler();
+ }
+ return QString();
+}
+
+QString FirstConfigure::getFortranCompiler() const
+{
+ if (this->compilerSetup()) {
+ return this->mNativeCompilerSetupPage->getFortranCompiler();
+ }
+ if (this->crossCompilerSetup()) {
+ return this->mCrossCompilerSetupPage->getFortranCompiler();
+ }
+ return QString();
+}
+
+QString FirstConfigure::getSystemVersion() const
+{
+ return this->mCrossCompilerSetupPage->getVersion();
+}
+
+QString FirstConfigure::getSystemProcessor() const
+{
+ return this->mCrossCompilerSetupPage->getProcessor();
+}
+
+QString FirstConfigure::getCrossRoot() const
+{
+ return this->mCrossCompilerSetupPage->getFindRoot();
+}
+
+const QString CrossModes[] = { "BOTH", "ONLY", "NEVER" };
+
+QString FirstConfigure::getCrossProgramMode() const
+{
+ return CrossModes[this->mCrossCompilerSetupPage->getProgramMode()];
+}
+
+QString FirstConfigure::getCrossLibraryMode() const
+{
+ return CrossModes[this->mCrossCompilerSetupPage->getLibraryMode()];
+}
+
+QString FirstConfigure::getCrossIncludeMode() const
+{
+ return CrossModes[this->mCrossCompilerSetupPage->getIncludeMode()];
+}
diff --git a/Source/QtDialog/FirstConfigure.h b/Source/QtDialog/FirstConfigure.h
new file mode 100644
index 0000000..5844f3a
--- /dev/null
+++ b/Source/QtDialog/FirstConfigure.h
@@ -0,0 +1,217 @@
+
+#pragma once
+
+#include <QWizard>
+#include <QWizardPage>
+
+#include "cmake.h"
+
+#include "ui_Compilers.h"
+#include "ui_CrossCompiler.h"
+
+class QRadioButton;
+class QComboBox;
+
+//! the wizard pages we'll use for the first configure of a build
+enum FirstConfigurePages
+{
+ Start,
+ NativeSetup,
+ ToolchainSetup,
+ CrossSetup,
+ Done
+};
+
+enum class CompilerOption
+{
+ DefaultNative,
+ SpecifyNative,
+ ToolchainFile,
+ Options,
+};
+
+//! the first page that gives basic options for what compilers setup to choose
+//! from
+class StartCompilerSetup : public QWizardPage
+{
+ Q_OBJECT
+public:
+ StartCompilerSetup(QString defaultGeneratorPlatform,
+ QString defaultGeneratorToolset, QWidget* p);
+ ~StartCompilerSetup();
+ void setGenerators(std::vector<cmake::GeneratorInfo> const& gens);
+ void setCurrentGenerator(const QString& gen);
+ void setToolset(const QString& toolset);
+ void setPlatform(const QString& platform);
+ void setCompilerOption(CompilerOption option);
+ QString getGenerator() const;
+ QString getToolset() const;
+ QString getPlatform() const;
+
+ bool defaultSetup() const;
+ bool compilerSetup() const;
+ bool crossCompilerSetup() const;
+ bool crossCompilerToolChainFile() const;
+
+ int nextId() const;
+
+signals:
+ void selectionChanged();
+
+protected slots:
+ void onSelectionChanged(bool);
+ void onGeneratorChanged(int index);
+
+protected:
+ QComboBox* GeneratorOptions;
+ QRadioButton* CompilerSetupOptions[4];
+ QFrame* ToolsetFrame;
+ QLineEdit* Toolset;
+ QLabel* ToolsetLabel;
+ QFrame* PlatformFrame;
+ QComboBox* PlatformOptions;
+ QLabel* PlatformLabel;
+ QStringList GeneratorsSupportingToolset;
+ QStringList GeneratorsSupportingPlatform;
+ QMultiMap<QString, QString> GeneratorSupportedPlatforms;
+ QMap<QString, QString> GeneratorDefaultPlatform;
+ QString DefaultGeneratorPlatform, DefaultGeneratorToolset;
+
+private:
+ QFrame* CreateToolsetWidgets();
+ QFrame* CreatePlatformWidgets();
+};
+
+//! the page that gives basic options for native compilers
+class NativeCompilerSetup
+ : public QWizardPage
+ , protected Ui::Compilers
+{
+ Q_OBJECT
+public:
+ NativeCompilerSetup(QWidget* p);
+ ~NativeCompilerSetup();
+
+ QString getCCompiler() const;
+ void setCCompiler(const QString&);
+
+ QString getCXXCompiler() const;
+ void setCXXCompiler(const QString&);
+
+ QString getFortranCompiler() const;
+ void setFortranCompiler(const QString&);
+
+ int nextId() const { return -1; }
+};
+
+//! the page that gives options for cross compilers
+class CrossCompilerSetup
+ : public QWizardPage
+ , protected Ui::CrossCompiler
+{
+ Q_OBJECT
+public:
+ CrossCompilerSetup(QWidget* p);
+ ~CrossCompilerSetup();
+
+ QString getSystem() const;
+ void setSystem(const QString&);
+
+ QString getVersion() const;
+ void setVersion(const QString&);
+
+ QString getProcessor() const;
+ void setProcessor(const QString&);
+
+ QString getCCompiler() const;
+ void setCCompiler(const QString&);
+
+ QString getCXXCompiler() const;
+ void setCXXCompiler(const QString&);
+
+ QString getFortranCompiler() const;
+ void setFortranCompiler(const QString&);
+
+ QString getFindRoot() const;
+ void setFindRoot(const QString&);
+
+ enum CrossMode
+ {
+ BOTH,
+ ONLY,
+ NEVER
+ };
+
+ int getProgramMode() const;
+ void setProgramMode(int);
+ int getLibraryMode() const;
+ void setLibraryMode(int);
+ int getIncludeMode() const;
+ void setIncludeMode(int);
+
+ int nextId() const { return -1; }
+};
+
+//! the page that gives options for a toolchain file
+class ToolchainCompilerSetup : public QWizardPage
+{
+ Q_OBJECT
+public:
+ ToolchainCompilerSetup(QWidget* p);
+ ~ToolchainCompilerSetup();
+
+ QString toolchainFile() const;
+ void setToolchainFile(const QString&);
+
+ int nextId() const { return -1; }
+
+protected:
+ QCMakeFilePathEditor* ToolchainFile;
+};
+
+//! the wizard with the pages
+class FirstConfigure : public QWizard
+{
+ Q_OBJECT
+public:
+ FirstConfigure();
+ ~FirstConfigure();
+
+ void setGenerators(std::vector<cmake::GeneratorInfo> const& gens);
+ void setCurrentGenerator(const QString& gen);
+ void setToolset(const QString& toolset);
+ void setPlatform(const QString& platform);
+ void setCompilerOption(CompilerOption option);
+ QString getGenerator() const;
+ QString getPlatform() const;
+ QString getToolset() const;
+
+ bool defaultSetup() const;
+ bool compilerSetup() const;
+ bool crossCompilerSetup() const;
+ bool crossCompilerToolChainFile() const;
+
+ QString getCCompiler() const;
+ QString getCXXCompiler() const;
+ QString getFortranCompiler() const;
+
+ QString getSystemName() const;
+ QString getSystemVersion() const;
+ QString getSystemProcessor() const;
+ QString getCrossRoot() const;
+ QString getCrossProgramMode() const;
+ QString getCrossLibraryMode() const;
+ QString getCrossIncludeMode() const;
+
+ QString getCrossCompilerToolChainFile() const;
+
+ void loadFromSettings();
+ void saveToSettings();
+
+protected:
+ StartCompilerSetup* mStartCompilerSetupPage;
+ NativeCompilerSetup* mNativeCompilerSetupPage;
+ CrossCompilerSetup* mCrossCompilerSetupPage;
+ ToolchainCompilerSetup* mToolchainCompilerSetupPage;
+ QString mDefaultGenerator;
+};
diff --git a/Source/QtDialog/Info.plist.in b/Source/QtDialog/Info.plist.in
new file mode 100644
index 0000000..00a27c3
--- /dev/null
+++ b/Source/QtDialog/Info.plist.in
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+ <key>LSApplicationCategoryType</key>
+ <string>public.app-category.developer-tools</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+ <key>NSHighResolutionCapable</key>
+ <true/>
+</dict>
+</plist>
diff --git a/Source/QtDialog/Plus16.png b/Source/QtDialog/Plus16.png
new file mode 100644
index 0000000..1c33bc7
--- /dev/null
+++ b/Source/QtDialog/Plus16.png
Binary files differ
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
new file mode 100644
index 0000000..6796e25
--- /dev/null
+++ b/Source/QtDialog/QCMake.cxx
@@ -0,0 +1,684 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "QCMake.h"
+
+#include <algorithm>
+
+#include <cm/memory>
+
+#include <QCoreApplication>
+#include <QDir>
+#include <QString>
+#include <QVector>
+
+#include "cmExternalMakefileProjectGenerator.h"
+#include "cmGlobalGenerator.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+#ifdef Q_OS_WIN
+# include "qt_windows.h" // For SetErrorMode
+#endif
+
+QCMake::QCMake(QObject* p)
+ : QObject(p)
+ , StartEnvironment(QProcessEnvironment::systemEnvironment())
+ , Environment(QProcessEnvironment::systemEnvironment())
+{
+ this->WarnUninitializedMode = false;
+ qRegisterMetaType<QCMakeProperty>();
+ qRegisterMetaType<QCMakePropertyList>();
+ qRegisterMetaType<QProcessEnvironment>();
+ qRegisterMetaType<QVector<QCMakePreset>>();
+ qRegisterMetaType<cmCMakePresetsFile::ReadFileResult>();
+
+ cmSystemTools::DisableRunCommandOutput();
+ cmSystemTools::SetRunCommandHideConsole(true);
+
+ cmSystemTools::SetMessageCallback(
+ [this](std::string const& msg, const char* title) {
+ this->messageCallback(msg, title);
+ });
+ cmSystemTools::SetStdoutCallback(
+ [this](std::string const& msg) { this->stdoutCallback(msg); });
+ cmSystemTools::SetStderrCallback(
+ [this](std::string const& msg) { this->stderrCallback(msg); });
+
+ this->CMakeInstance =
+ cm::make_unique<cmake>(cmake::RoleProject, cmState::Project);
+ this->CMakeInstance->SetCMakeEditCommand(
+ cmSystemTools::GetCMakeGUICommand());
+ this->CMakeInstance->SetProgressCallback(
+ [this](const std::string& msg, float percent) {
+ this->progressCallback(msg, percent);
+ });
+
+ cmSystemTools::SetInterruptCallback(
+ [this] { return this->interruptCallback(); });
+
+ std::vector<cmake::GeneratorInfo> generators;
+ this->CMakeInstance->GetRegisteredGenerators(
+ generators, /*includeNamesWithPlatform=*/false);
+
+ for (cmake::GeneratorInfo const& gen : generators) {
+ this->AvailableGenerators.push_back(gen);
+ }
+
+ connect(&this->LoadPresetsTimer, &QTimer::timeout, this, [this]() {
+ this->loadPresets();
+ if (!this->PresetName.isEmpty() &&
+ this->CMakePresetsFile.ConfigurePresets.find(
+ std::string(this->PresetName.toLocal8Bit())) ==
+ this->CMakePresetsFile.ConfigurePresets.end()) {
+ this->setPreset(QString{});
+ }
+ });
+ this->LoadPresetsTimer.start(1000);
+}
+
+QCMake::~QCMake() = default;
+
+void QCMake::loadCache(const QString& dir)
+{
+ this->setBinaryDirectory(dir);
+}
+
+void QCMake::setSourceDirectory(const QString& _dir)
+{
+ QString dir = QString::fromLocal8Bit(
+ cmSystemTools::GetActualCaseForPath(_dir.toLocal8Bit().data()).c_str());
+ if (this->SourceDirectory != dir) {
+ this->SourceDirectory = QDir::fromNativeSeparators(dir);
+ emit this->sourceDirChanged(this->SourceDirectory);
+ this->loadPresets();
+ this->setPreset(QString{});
+ }
+}
+
+void QCMake::setBinaryDirectory(const QString& _dir)
+{
+ QString dir = QString::fromLocal8Bit(
+ cmSystemTools::GetActualCaseForPath(_dir.toLocal8Bit().data()).c_str());
+ if (this->BinaryDirectory != dir) {
+ this->BinaryDirectory = QDir::fromNativeSeparators(dir);
+ emit this->binaryDirChanged(this->BinaryDirectory);
+ cmState* state = this->CMakeInstance->GetState();
+ this->setGenerator(QString());
+ this->setToolset(QString());
+ this->setPlatform(QString());
+ if (!this->CMakeInstance->LoadCache(
+ this->BinaryDirectory.toLocal8Bit().data())) {
+ QDir testDir(this->BinaryDirectory);
+ if (testDir.exists("CMakeCache.txt")) {
+ cmSystemTools::Error(
+ "There is a CMakeCache.txt file for the current binary "
+ "tree but cmake does not have permission to read it. "
+ "Please check the permissions of the directory you are trying to "
+ "run CMake on.");
+ }
+ }
+
+ QCMakePropertyList props = this->properties();
+ emit this->propertiesChanged(props);
+ cmProp homeDir = state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY");
+ if (homeDir) {
+ setSourceDirectory(QString::fromLocal8Bit(homeDir->c_str()));
+ }
+ cmProp gen = state->GetCacheEntryValue("CMAKE_GENERATOR");
+ if (gen) {
+ const std::string* extraGen =
+ state->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
+ std::string curGen =
+ cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
+ *gen, extraGen ? *extraGen : "");
+ this->setGenerator(QString::fromLocal8Bit(curGen.c_str()));
+ }
+
+ cmProp platform = state->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM");
+ if (platform) {
+ this->setPlatform(QString::fromLocal8Bit(platform->c_str()));
+ }
+
+ cmProp toolset = state->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET");
+ if (toolset) {
+ this->setToolset(QString::fromLocal8Bit(toolset->c_str()));
+ }
+
+ checkOpenPossible();
+ }
+}
+
+void QCMake::setPreset(const QString& name, bool setBinary)
+{
+ if (this->PresetName != name) {
+ this->PresetName = name;
+ emit this->presetChanged(this->PresetName);
+
+ if (!name.isNull()) {
+ std::string presetName(name.toLocal8Bit());
+ auto const& expandedPreset =
+ this->CMakePresetsFile.ConfigurePresets[presetName].Expanded;
+ if (expandedPreset) {
+ if (setBinary && !expandedPreset->BinaryDir.empty()) {
+ QString binaryDir =
+ QString::fromLocal8Bit(expandedPreset->BinaryDir.data());
+ this->setBinaryDirectory(binaryDir);
+ }
+ if (expandedPreset->WarnDev) {
+ this->CMakeInstance->SetSuppressDevWarnings(
+ !*expandedPreset->WarnDev);
+ }
+ if (expandedPreset->ErrorDev) {
+ this->CMakeInstance->SetDevWarningsAsErrors(
+ *expandedPreset->ErrorDev);
+ }
+ if (expandedPreset->WarnDeprecated) {
+ this->CMakeInstance->SetSuppressDeprecatedWarnings(
+ !*expandedPreset->WarnDeprecated);
+ }
+ if (expandedPreset->ErrorDeprecated) {
+ this->CMakeInstance->SetDeprecatedWarningsAsErrors(
+ *expandedPreset->ErrorDeprecated);
+ }
+ if (expandedPreset->WarnUninitialized) {
+ this->WarnUninitializedMode = *expandedPreset->WarnUninitialized;
+ emit this->warnUninitializedModeChanged(
+ *expandedPreset->WarnUninitialized);
+ }
+ this->Environment = this->StartEnvironment;
+ for (auto const& v : expandedPreset->Environment) {
+ if (v.second) {
+ this->Environment.insert(QString::fromLocal8Bit(v.first.data()),
+ QString::fromLocal8Bit(v.second->data()));
+ }
+ }
+ }
+ }
+ emit this->propertiesChanged(this->properties());
+ }
+}
+
+void QCMake::setGenerator(const QString& gen)
+{
+ if (this->Generator != gen) {
+ this->Generator = gen;
+ emit this->generatorChanged(this->Generator);
+ }
+}
+
+void QCMake::setPlatform(const QString& platform)
+{
+ if (this->Platform != platform) {
+ this->Platform = platform;
+ emit this->platformChanged(this->Platform);
+ }
+}
+
+void QCMake::setToolset(const QString& toolset)
+{
+ if (this->Toolset != toolset) {
+ this->Toolset = toolset;
+ emit this->toolsetChanged(this->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);
+#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();
+
+ err = this->CMakeInstance->Configure();
+
+#ifdef Q_OS_WIN
+ SetErrorMode(lastErrorMode);
+#endif
+ }
+
+ emit this->propertiesChanged(this->properties());
+ emit this->configureDone(err);
+}
+
+void QCMake::generate()
+{
+ int err;
+ {
+ cmSystemTools::SaveRestoreEnvironment restoreEnv;
+ this->setUpEnvironment();
+
+#ifdef Q_OS_WIN
+ UINT lastErrorMode = SetErrorMode(0);
+#endif
+
+ InterruptFlag = 0;
+ cmSystemTools::ResetErrorOccuredFlag();
+
+ err = this->CMakeInstance->Generate();
+
+#ifdef Q_OS_WIN
+ SetErrorMode(lastErrorMode);
+#endif
+ }
+
+ emit this->generateDone(err);
+ checkOpenPossible();
+}
+
+void QCMake::open()
+{
+#ifdef Q_OS_WIN
+ UINT lastErrorMode = SetErrorMode(0);
+#endif
+
+ InterruptFlag = 0;
+ cmSystemTools::ResetErrorOccuredFlag();
+
+ auto successful = this->CMakeInstance->Open(
+ this->BinaryDirectory.toLocal8Bit().data(), false);
+
+#ifdef Q_OS_WIN
+ SetErrorMode(lastErrorMode);
+#endif
+
+ emit this->openDone(successful);
+}
+
+void QCMake::setProperties(const QCMakePropertyList& newProps)
+{
+ QCMakePropertyList props = newProps;
+
+ QStringList toremove;
+
+ // set the value of properties
+ cmState* state = this->CMakeInstance->GetState();
+ std::vector<std::string> cacheKeys = state->GetCacheEntryKeys();
+ for (std::string const& key : cacheKeys) {
+ cmStateEnums::CacheEntryType t = state->GetCacheEntryType(key);
+ if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC) {
+ continue;
+ }
+
+ QCMakeProperty prop;
+ prop.Key = QString::fromLocal8Bit(key.c_str());
+ int idx = props.indexOf(prop);
+ if (idx == -1) {
+ toremove.append(QString::fromLocal8Bit(key.c_str()));
+ } else {
+ prop = props[idx];
+ if (prop.Value.type() == QVariant::Bool) {
+ state->SetCacheEntryValue(key, prop.Value.toBool() ? "ON" : "OFF");
+ } else {
+ state->SetCacheEntryValue(key,
+ prop.Value.toString().toLocal8Bit().data());
+ }
+ props.removeAt(idx);
+ }
+ }
+
+ // remove some properties
+ foreach (QString const& s, toremove) {
+ this->CMakeInstance->UnwatchUnusedCli(s.toLocal8Bit().data());
+
+ state->RemoveCacheEntry(s.toLocal8Bit().data());
+ }
+
+ // add some new properties
+ foreach (QCMakeProperty const& s, props) {
+ this->CMakeInstance->WatchUnusedCli(s.Key.toLocal8Bit().data());
+
+ if (s.Type == QCMakeProperty::BOOL) {
+ this->CMakeInstance->AddCacheEntry(
+ s.Key.toLocal8Bit().data(), s.Value.toBool() ? "ON" : "OFF",
+ s.Help.toLocal8Bit().data(), cmStateEnums::BOOL);
+ } else if (s.Type == QCMakeProperty::STRING) {
+ this->CMakeInstance->AddCacheEntry(
+ s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(),
+ s.Help.toLocal8Bit().data(), cmStateEnums::STRING);
+ } else if (s.Type == QCMakeProperty::PATH) {
+ this->CMakeInstance->AddCacheEntry(
+ s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(),
+ s.Help.toLocal8Bit().data(), cmStateEnums::PATH);
+ } else if (s.Type == QCMakeProperty::FILEPATH) {
+ this->CMakeInstance->AddCacheEntry(
+ s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(),
+ s.Help.toLocal8Bit().data(), cmStateEnums::FILEPATH);
+ }
+ }
+
+ this->CMakeInstance->SaveCache(this->BinaryDirectory.toLocal8Bit().data());
+}
+
+QCMakePropertyList QCMake::properties() const
+{
+ QCMakePropertyList ret;
+
+ cmState* state = this->CMakeInstance->GetState();
+ std::vector<std::string> cacheKeys = state->GetCacheEntryKeys();
+ for (std::string const& key : cacheKeys) {
+ cmStateEnums::CacheEntryType t = state->GetCacheEntryType(key);
+ if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC ||
+ t == cmStateEnums::UNINITIALIZED) {
+ continue;
+ }
+
+ cmProp cachedValue = state->GetCacheEntryValue(key);
+
+ QCMakeProperty prop;
+ prop.Key = QString::fromLocal8Bit(key.c_str());
+ if (cmProp hs = state->GetCacheEntryProperty(key, "HELPSTRING")) {
+ prop.Help = QString::fromLocal8Bit(hs->c_str());
+ }
+ prop.Value = QString::fromLocal8Bit(cachedValue->c_str());
+ prop.Advanced = state->GetCacheEntryPropertyAsBool(key, "ADVANCED");
+ if (t == cmStateEnums::BOOL) {
+ prop.Type = QCMakeProperty::BOOL;
+ prop.Value = cmIsOn(*cachedValue);
+ } else if (t == cmStateEnums::PATH) {
+ prop.Type = QCMakeProperty::PATH;
+ } else if (t == cmStateEnums::FILEPATH) {
+ prop.Type = QCMakeProperty::FILEPATH;
+ } else if (t == cmStateEnums::STRING) {
+ prop.Type = QCMakeProperty::STRING;
+ cmProp stringsProperty = state->GetCacheEntryProperty(key, "STRINGS");
+ if (stringsProperty) {
+ prop.Strings =
+ QString::fromLocal8Bit(stringsProperty->c_str()).split(";");
+ }
+ }
+
+ ret.append(prop);
+ }
+
+ if (!this->PresetName.isNull()) {
+ std::string presetName(this->PresetName.toLocal8Bit());
+ auto const& p =
+ this->CMakePresetsFile.ConfigurePresets.at(presetName).Expanded;
+ if (p) {
+ for (auto const& v : p->CacheVariables) {
+ if (!v.second) {
+ continue;
+ }
+ QCMakeProperty prop;
+ prop.Key = QString::fromLocal8Bit(v.first.data());
+ prop.Value = QString::fromLocal8Bit(v.second->Value.data());
+ prop.Type = QCMakeProperty::STRING;
+ if (!v.second->Type.empty()) {
+ auto type = cmState::StringToCacheEntryType(v.second->Type);
+ switch (type) {
+ case cmStateEnums::BOOL:
+ prop.Type = QCMakeProperty::BOOL;
+ prop.Value = cmIsOn(v.second->Value);
+ break;
+ case cmStateEnums::PATH:
+ prop.Type = QCMakeProperty::PATH;
+ break;
+ case cmStateEnums::FILEPATH:
+ prop.Type = QCMakeProperty::FILEPATH;
+ break;
+ default:
+ prop.Type = QCMakeProperty::STRING;
+ break;
+ }
+ }
+
+ // QCMakeCacheModel prefers variables earlier in the list rather than
+ // later, so overwrite them if they already exist rather than simply
+ // appending
+ bool found = false;
+ for (auto& orig : ret) {
+ if (orig.Key == prop.Key) {
+ orig = prop;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ret.append(prop);
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+void QCMake::interrupt()
+{
+ this->InterruptFlag.ref();
+}
+
+bool QCMake::interruptCallback()
+{
+#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
+ return this->InterruptFlag.load();
+#else
+ return this->InterruptFlag.loadRelaxed();
+#endif
+}
+
+void QCMake::progressCallback(const std::string& msg, float percent)
+{
+ if (percent >= 0) {
+ emit this->progressChanged(QString::fromStdString(msg), percent);
+ } else {
+ emit this->outputMessage(QString::fromStdString(msg));
+ }
+ QCoreApplication::processEvents();
+}
+
+void QCMake::messageCallback(std::string const& msg, const char* /*title*/)
+{
+ emit this->errorMessage(QString::fromStdString(msg));
+ QCoreApplication::processEvents();
+}
+
+void QCMake::stdoutCallback(std::string const& msg)
+{
+ emit this->outputMessage(QString::fromStdString(msg));
+ QCoreApplication::processEvents();
+}
+
+void QCMake::stderrCallback(std::string const& msg)
+{
+ emit this->outputMessage(QString::fromStdString(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());
+ }
+}
+
+void QCMake::loadPresets()
+{
+ auto result = this->CMakePresetsFile.ReadProjectPresets(
+ this->SourceDirectory.toLocal8Bit().data(), true);
+ if (result != this->LastLoadPresetsResult &&
+ result != cmCMakePresetsFile::ReadFileResult::READ_OK) {
+ emit this->presetLoadError(this->SourceDirectory, result);
+ }
+ this->LastLoadPresetsResult = result;
+
+ QVector<QCMakePreset> presets;
+ for (auto const& name : this->CMakePresetsFile.ConfigurePresetOrder) {
+ auto const& it = this->CMakePresetsFile.ConfigurePresets[name];
+ auto const& p = it.Unexpanded;
+ if (p.Hidden) {
+ continue;
+ }
+
+ QCMakePreset preset;
+ preset.name = std::move(QString::fromLocal8Bit(p.Name.data()));
+ preset.displayName =
+ std::move(QString::fromLocal8Bit(p.DisplayName.data()));
+ preset.description =
+ std::move(QString::fromLocal8Bit(p.Description.data()));
+ preset.generator = std::move(QString::fromLocal8Bit(p.Generator.data()));
+ preset.architecture =
+ std::move(QString::fromLocal8Bit(p.Architecture.data()));
+ preset.setArchitecture = !p.ArchitectureStrategy ||
+ p.ArchitectureStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set;
+ preset.toolset = std::move(QString::fromLocal8Bit(p.Toolset.data()));
+ preset.setToolset = !p.ToolsetStrategy ||
+ p.ToolsetStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set;
+ preset.enabled = it.Expanded && it.Expanded->ConditionResult &&
+ std::find_if(this->AvailableGenerators.begin(),
+ this->AvailableGenerators.end(),
+ [&p](const cmake::GeneratorInfo& g) {
+ return g.name == p.Generator;
+ }) != this->AvailableGenerators.end();
+ presets.push_back(preset);
+ }
+ emit this->presetsChanged(presets);
+}
+
+QString QCMake::binaryDirectory() const
+{
+ return this->BinaryDirectory;
+}
+
+QString QCMake::sourceDirectory() const
+{
+ return this->SourceDirectory;
+}
+
+QString QCMake::generator() const
+{
+ return this->Generator;
+}
+
+QProcessEnvironment QCMake::environment() const
+{
+ return this->Environment;
+}
+
+std::vector<cmake::GeneratorInfo> const& QCMake::availableGenerators() const
+{
+ return AvailableGenerators;
+}
+
+void QCMake::deleteCache()
+{
+ // delete cache
+ this->CMakeInstance->DeleteCache(this->BinaryDirectory.toLocal8Bit().data());
+ // reload to make our cache empty
+ this->CMakeInstance->LoadCache(this->BinaryDirectory.toLocal8Bit().data());
+ // emit no generator and no properties
+ this->setGenerator(QString());
+ this->setToolset(QString());
+ QCMakePropertyList props = this->properties();
+ emit this->propertiesChanged(props);
+}
+
+void QCMake::reloadCache()
+{
+ // emit that the cache was cleaned out
+ QCMakePropertyList props;
+ emit this->propertiesChanged(props);
+ // reload
+ this->CMakeInstance->LoadCache(this->BinaryDirectory.toLocal8Bit().data());
+ // emit new cache properties
+ props = this->properties();
+ emit this->propertiesChanged(props);
+}
+
+void QCMake::setDebugOutput(bool flag)
+{
+ if (flag != this->CMakeInstance->GetDebugOutput()) {
+ this->CMakeInstance->SetDebugOutputOn(flag);
+ emit this->debugOutputChanged(flag);
+ }
+}
+
+bool QCMake::getDebugOutput() const
+{
+ return this->CMakeInstance->GetDebugOutput();
+}
+
+bool QCMake::getSuppressDevWarnings()
+{
+ return this->CMakeInstance->GetSuppressDevWarnings();
+}
+
+void QCMake::setSuppressDevWarnings(bool value)
+{
+ this->CMakeInstance->SetSuppressDevWarnings(value);
+}
+
+bool QCMake::getSuppressDeprecatedWarnings()
+{
+ return this->CMakeInstance->GetSuppressDeprecatedWarnings();
+}
+
+void QCMake::setSuppressDeprecatedWarnings(bool value)
+{
+ this->CMakeInstance->SetSuppressDeprecatedWarnings(value);
+}
+
+bool QCMake::getDevWarningsAsErrors()
+{
+ return this->CMakeInstance->GetDevWarningsAsErrors();
+}
+
+void QCMake::setDevWarningsAsErrors(bool value)
+{
+ this->CMakeInstance->SetDevWarningsAsErrors(value);
+}
+
+bool QCMake::getDeprecatedWarningsAsErrors()
+{
+ return this->CMakeInstance->GetDeprecatedWarningsAsErrors();
+}
+
+void QCMake::setDeprecatedWarningsAsErrors(bool value)
+{
+ this->CMakeInstance->SetDeprecatedWarningsAsErrors(value);
+}
+
+void QCMake::setWarnUninitializedMode(bool value)
+{
+ this->WarnUninitializedMode = value;
+}
+
+void QCMake::checkOpenPossible()
+{
+ std::string data = this->BinaryDirectory.toLocal8Bit().data();
+ auto possible = this->CMakeInstance->Open(data, true);
+ emit openPossible(possible);
+}
diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h
new file mode 100644
index 0000000..a6751b0
--- /dev/null
+++ b/Source/QtDialog/QCMake.h
@@ -0,0 +1,214 @@
+/* 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 "cmCMakePresetsFile.h"
+#include "cmake.h"
+
+#ifdef _MSC_VER
+# pragma warning(disable : 4127)
+# pragma warning(disable : 4512)
+#endif
+
+#include <memory>
+#include <vector>
+
+#include "QCMakePreset.h"
+#include <QAtomicInt>
+#include <QList>
+#include <QMetaType>
+#include <QObject>
+#include <QProcessEnvironment>
+#include <QString>
+#include <QStringList>
+#include <QTimer>
+#include <QVariant>
+
+/// struct to represent cmake properties in Qt
+/// Value is of type String or Bool
+struct QCMakeProperty
+{
+ enum PropertyType
+ {
+ BOOL,
+ PATH,
+ FILEPATH,
+ STRING
+ };
+ QString Key;
+ QVariant Value;
+ QStringList Strings;
+ QString Help;
+ PropertyType Type;
+ bool Advanced;
+ bool operator==(const QCMakeProperty& other) const
+ {
+ return this->Key == other.Key;
+ }
+ bool operator<(const QCMakeProperty& other) const
+ {
+ return this->Key < other.Key;
+ }
+};
+
+// list of properties
+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)
+Q_DECLARE_METATYPE(cmCMakePresetsFile::ReadFileResult)
+
+/// Qt API for CMake library.
+/// Wrapper like class allows for easier integration with
+/// Qt features such as, signal/slot connections, multi-threading, etc..
+class QCMake : public QObject
+{
+ Q_OBJECT
+public:
+ QCMake(QObject* p = nullptr);
+ ~QCMake();
+public slots:
+ /// load the cache file in a directory
+ void loadCache(const QString& dir);
+ /// set the source directory containing the source
+ void setSourceDirectory(const QString& dir);
+ /// set the binary directory to build in
+ void setBinaryDirectory(const QString& dir);
+ /// set the preset name to use
+ void setPreset(const QString& name, bool setBinary = true);
+ /// set the desired generator to use
+ void setGenerator(const QString& generator);
+ /// set the desired generator to use
+ 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
+ void generate();
+ /// open the project
+ void open();
+ /// set the property values
+ void setProperties(const QCMakePropertyList&);
+ /// interrupt the configure or generate process (if connecting, make a direct
+ /// connection)
+ void interrupt();
+ /// delete the cache in binary directory
+ void deleteCache();
+ /// reload the cache in binary directory
+ void reloadCache();
+ /// set whether to do debug output
+ void setDebugOutput(bool);
+ /// get whether to do suppress dev warnings
+ bool getSuppressDevWarnings();
+ /// set whether to do suppress dev warnings
+ void setSuppressDevWarnings(bool value);
+ /// get whether to do suppress deprecated warnings
+ bool getSuppressDeprecatedWarnings();
+ /// set whether to do suppress deprecated warnings
+ void setSuppressDeprecatedWarnings(bool value);
+ /// get whether to treat developer (author) warnings as errors
+ bool getDevWarningsAsErrors();
+ /// set whether to treat developer (author) warnings as errors
+ void setDevWarningsAsErrors(bool value);
+ /// get whether to treat deprecated warnings as errors
+ bool getDeprecatedWarningsAsErrors();
+ /// set whether to treat deprecated warnings as errors
+ void setDeprecatedWarningsAsErrors(bool value);
+ /// set whether to run cmake with warnings about uninitialized variables
+ void setWarnUninitializedMode(bool value);
+ /// check if project IDE open is possible and emit openPossible signal
+ void checkOpenPossible();
+
+public:
+ /// get the list of cache properties
+ QCMakePropertyList properties() const;
+ /// get the current binary directory
+ QString binaryDirectory() const;
+ /// get the current source directory
+ 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
+ bool getDebugOutput() const;
+
+signals:
+ /// signal when properties change (during read from disk or configure
+ /// process)
+ void propertiesChanged(const QCMakePropertyList& vars);
+ /// signal when the generator changes
+ void generatorChanged(const QString& gen);
+ /// signal when the source directory changes (binary directory already
+ /// containing a CMakeCache.txt file)
+ void sourceDirChanged(const QString& dir);
+ /// signal when the binary directory changes
+ void binaryDirChanged(const QString& dir);
+ /// signal when the preset list changes
+ void presetsChanged(const QVector<QCMakePreset>& presets);
+ /// signal when the selected preset changes
+ void presetChanged(const QString& name);
+ /// signal when there's an error reading the presets files
+ void presetLoadError(const QString& dir,
+ cmCMakePresetsFile::ReadFileResult error);
+ /// signal when uninitialized warning changes
+ void warnUninitializedModeChanged(bool value);
+ /// signal for progress events
+ void progressChanged(const QString& msg, float percent);
+ /// signal when configure is done
+ void configureDone(int error);
+ /// signal when generate is done
+ void generateDone(int error);
+ /// signal when there is an output message
+ void outputMessage(const QString& msg);
+ /// signal when there is an error message
+ void errorMessage(const QString& msg);
+ /// signal when debug output changes
+ void debugOutputChanged(bool);
+ /// signal when the toolset changes
+ void toolsetChanged(const QString& toolset);
+ /// signal when the platform changes
+ void platformChanged(const QString& platform);
+ /// signal when open is done
+ void openDone(bool successful);
+ /// signal when open is done
+ void openPossible(bool possible);
+
+protected:
+ std::unique_ptr<cmake> CMakeInstance;
+
+ bool interruptCallback();
+ void progressCallback(std::string const& msg, float percent);
+ void messageCallback(std::string const& msg, const char* title);
+ void stdoutCallback(std::string const& msg);
+ void stderrCallback(std::string const& msg);
+ void setUpEnvironment() const;
+
+ void loadPresets();
+
+ bool WarnUninitializedMode;
+ QString SourceDirectory;
+ QString BinaryDirectory;
+ QString Generator;
+ QString Platform;
+ QString Toolset;
+ std::vector<cmake::GeneratorInfo> AvailableGenerators;
+ cmCMakePresetsFile CMakePresetsFile;
+ cmCMakePresetsFile::ReadFileResult LastLoadPresetsResult =
+ cmCMakePresetsFile::ReadFileResult::READ_OK;
+ QString PresetName;
+ QString CMakeExecutable;
+ QAtomicInt InterruptFlag;
+ QProcessEnvironment StartEnvironment;
+ QProcessEnvironment Environment;
+ QTimer LoadPresetsTimer;
+};
diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx
new file mode 100644
index 0000000..994df78
--- /dev/null
+++ b/Source/QtDialog/QCMakeCacheView.cxx
@@ -0,0 +1,729 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "QCMakeCacheView.h"
+
+#include "QCMakeWidgets.h"
+#include <QApplication>
+#include <QEvent>
+#include <QHBoxLayout>
+#include <QHeaderView>
+#include <QKeyEvent>
+#include <QMetaProperty>
+#include <QSortFilterProxyModel>
+#include <QStyle>
+
+// filter for searches
+class QCMakeSearchFilter : public QSortFilterProxyModel
+{
+public:
+ QCMakeSearchFilter(QObject* o)
+ : QSortFilterProxyModel(o)
+ {
+ }
+
+protected:
+ bool filterAcceptsRow(int row, const QModelIndex& p) const override
+ {
+ QStringList strs;
+ const QAbstractItemModel* m = this->sourceModel();
+ QModelIndex idx = m->index(row, 0, p);
+
+ // if there are no children, get strings for column 0 and 1
+ if (!m->hasChildren(idx)) {
+ strs.append(m->data(idx).toString());
+ idx = m->index(row, 1, p);
+ strs.append(m->data(idx).toString());
+ } else {
+ // get strings for children entries to compare with
+ // instead of comparing with the parent
+ int num = m->rowCount(idx);
+ for (int i = 0; i < num; i++) {
+ QModelIndex tmpidx = m->index(i, 0, idx);
+ strs.append(m->data(tmpidx).toString());
+ tmpidx = m->index(i, 1, idx);
+ strs.append(m->data(tmpidx).toString());
+ }
+ }
+
+ // check all strings for a match
+ foreach (QString const& str, strs) {
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+ if (str.contains(this->filterRegularExpression())) {
+#else
+ if (str.contains(this->filterRegExp())) {
+#endif
+ return true;
+ }
+ }
+
+ return false;
+ }
+};
+
+// filter for searches
+class QCMakeAdvancedFilter : public QSortFilterProxyModel
+{
+public:
+ QCMakeAdvancedFilter(QObject* o)
+ : QSortFilterProxyModel(o)
+ , ShowAdvanced(false)
+ {
+ }
+
+ void setShowAdvanced(bool f)
+ {
+ this->ShowAdvanced = f;
+ this->invalidate();
+ }
+ bool showAdvanced() const { return this->ShowAdvanced; }
+
+protected:
+ bool ShowAdvanced;
+
+ bool filterAcceptsRow(int row, const QModelIndex& p) const override
+ {
+ const QAbstractItemModel* m = this->sourceModel();
+ QModelIndex idx = m->index(row, 0, p);
+
+ // if there are no children
+ if (!m->hasChildren(idx)) {
+ bool adv = m->data(idx, QCMakeCacheModel::AdvancedRole).toBool();
+ return !adv || this->ShowAdvanced;
+ }
+
+ // check children
+ int num = m->rowCount(idx);
+ for (int i = 0; i < num; i++) {
+ bool accept = this->filterAcceptsRow(i, idx);
+ if (accept) {
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+QCMakeCacheView::QCMakeCacheView(QWidget* p)
+ : QTreeView(p)
+{
+ // hook up our model and search/filter proxies
+ this->CacheModel = new QCMakeCacheModel(this);
+ this->AdvancedFilter = new QCMakeAdvancedFilter(this);
+ this->AdvancedFilter->setSourceModel(this->CacheModel);
+ this->AdvancedFilter->setDynamicSortFilter(true);
+ this->SearchFilter = new QCMakeSearchFilter(this);
+ this->SearchFilter->setSourceModel(this->AdvancedFilter);
+ this->SearchFilter->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ this->SearchFilter->setDynamicSortFilter(true);
+ this->setModel(this->SearchFilter);
+
+ // our delegate for creating our editors
+ QCMakeCacheModelDelegate* delegate = new QCMakeCacheModelDelegate(this);
+ this->setItemDelegate(delegate);
+
+ this->setUniformRowHeights(true);
+
+ this->setEditTriggers(QAbstractItemView::AllEditTriggers);
+
+ // tab, backtab doesn't step through items
+ this->setTabKeyNavigation(false);
+
+ this->setRootIsDecorated(false);
+}
+
+bool QCMakeCacheView::event(QEvent* e)
+{
+ if (e->type() == QEvent::Show) {
+ this->header()->setDefaultSectionSize(this->viewport()->width() / 2);
+ }
+ return QTreeView::event(e);
+}
+
+QCMakeCacheModel* QCMakeCacheView::cacheModel() const
+{
+ return this->CacheModel;
+}
+
+QModelIndex QCMakeCacheView::moveCursor(CursorAction act,
+ Qt::KeyboardModifiers mod)
+{
+ // want home/end to go to begin/end of rows, not columns
+ if (act == MoveHome) {
+ return this->model()->index(0, 1);
+ }
+ if (act == MoveEnd) {
+ return this->model()->index(this->model()->rowCount() - 1, 1);
+ }
+ return QTreeView::moveCursor(act, mod);
+}
+
+void QCMakeCacheView::setShowAdvanced(bool s)
+{
+ this->SearchFilter->invalidate();
+ this->AdvancedFilter->setShowAdvanced(s);
+}
+
+bool QCMakeCacheView::showAdvanced() const
+{
+ return this->AdvancedFilter->showAdvanced();
+}
+
+void QCMakeCacheView::setSearchFilter(const QString& s)
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+ this->SearchFilter->setFilterRegularExpression(s);
+#else
+ this->SearchFilter->setFilterFixedString(s);
+#endif
+}
+
+QCMakeCacheModel::QCMakeCacheModel(QObject* p)
+ : QStandardItemModel(p)
+ , EditEnabled(true)
+ , NewPropertyCount(0)
+ , View(FlatView)
+{
+ this->ShowNewProperties = true;
+ QStringList labels;
+ labels << tr("Name") << tr("Value");
+ this->setHorizontalHeaderLabels(labels);
+}
+
+QCMakeCacheModel::~QCMakeCacheModel() = default;
+
+static uint qHash(const QCMakeProperty& p)
+{
+ return qHash(p.Key);
+}
+
+void QCMakeCacheModel::setShowNewProperties(bool f)
+{
+ this->ShowNewProperties = f;
+}
+
+void QCMakeCacheModel::clear()
+{
+ this->QStandardItemModel::clear();
+ this->NewPropertyCount = 0;
+
+ QStringList labels;
+ labels << tr("Name") << tr("Value");
+ this->setHorizontalHeaderLabels(labels);
+}
+
+void QCMakeCacheModel::setProperties(const QCMakePropertyList& props)
+{
+ this->beginResetModel();
+
+ QSet<QCMakeProperty> newProps;
+ QSet<QCMakeProperty> newProps2;
+
+ if (this->ShowNewProperties) {
+#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
+ newProps = props.toSet();
+#else
+ newProps = QSet<QCMakeProperty>(props.begin(), props.end());
+#endif
+ newProps2 = newProps;
+#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
+ QSet<QCMakeProperty> oldProps = this->properties().toSet();
+#else
+ QCMakePropertyList const& oldPropsList = this->properties();
+ QSet<QCMakeProperty> oldProps =
+ QSet<QCMakeProperty>(oldPropsList.begin(), oldPropsList.end());
+#endif
+ oldProps.intersect(newProps);
+ newProps.subtract(oldProps);
+ newProps2.subtract(newProps);
+ } else {
+#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
+ newProps2 = props.toSet();
+#else
+ newProps2 = QSet<QCMakeProperty>(props.begin(), props.end());
+#endif
+ }
+
+ bool b = this->blockSignals(true);
+
+ this->clear();
+ this->NewPropertyCount = newProps.size();
+
+ if (View == FlatView) {
+ QCMakePropertyList newP = newProps.values();
+ QCMakePropertyList newP2 = newProps2.values();
+#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
+ std::sort(newP.begin(), newP.end());
+ std::sort(newP2.begin(), newP2.end());
+#else
+ qSort(newP);
+ qSort(newP2);
+#endif
+ int row_count = 0;
+ foreach (QCMakeProperty const& p, newP) {
+ this->insertRow(row_count);
+ this->setPropertyData(this->index(row_count, 0), p, true);
+ row_count++;
+ }
+ foreach (QCMakeProperty const& p, newP2) {
+ this->insertRow(row_count);
+ this->setPropertyData(this->index(row_count, 0), p, false);
+ row_count++;
+ }
+ } else if (this->View == GroupView) {
+ QMap<QString, QCMakePropertyList> newPropsTree;
+ QCMakeCacheModel::breakProperties(newProps, newPropsTree);
+ QMap<QString, QCMakePropertyList> newPropsTree2;
+ QCMakeCacheModel::breakProperties(newProps2, newPropsTree2);
+
+ QStandardItem* root = this->invisibleRootItem();
+
+ for (QMap<QString, QCMakePropertyList>::const_iterator iter =
+ newPropsTree.begin();
+ iter != newPropsTree.end(); ++iter) {
+ QString const& key = iter.key();
+ QCMakePropertyList const& props2 = iter.value();
+
+ QList<QStandardItem*> parentItems;
+ parentItems.append(
+ new QStandardItem(key.isEmpty() ? tr("Ungrouped Entries") : key));
+ parentItems.append(new QStandardItem());
+#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
+ parentItems[0]->setData(QBrush(QColor(255, 100, 100)),
+ Qt::BackgroundRole);
+ parentItems[1]->setData(QBrush(QColor(255, 100, 100)),
+ Qt::BackgroundRole);
+#else
+ parentItems[0]->setData(QBrush(QColor(255, 100, 100)),
+ Qt::BackgroundColorRole);
+ parentItems[1]->setData(QBrush(QColor(255, 100, 100)),
+ Qt::BackgroundColorRole);
+#endif
+ parentItems[0]->setData(1, GroupRole);
+ parentItems[1]->setData(1, GroupRole);
+ root->appendRow(parentItems);
+
+ int num = props2.size();
+ for (int i = 0; i < num; i++) {
+ QCMakeProperty prop = props2[i];
+ QList<QStandardItem*> items;
+ items.append(new QStandardItem());
+ items.append(new QStandardItem());
+ parentItems[0]->appendRow(items);
+ this->setPropertyData(this->indexFromItem(items[0]), prop, true);
+ }
+ }
+
+ for (QMap<QString, QCMakePropertyList>::const_iterator iter =
+ newPropsTree2.begin();
+ iter != newPropsTree2.end(); ++iter) {
+ QString const& key = iter.key();
+ QCMakePropertyList const& props2 = iter.value();
+
+ QStandardItem* parentItem =
+ new QStandardItem(key.isEmpty() ? tr("Ungrouped Entries") : key);
+ root->appendRow(parentItem);
+ parentItem->setData(1, GroupRole);
+
+ int num = props2.size();
+ for (int i = 0; i < num; i++) {
+ QCMakeProperty prop = props2[i];
+ QList<QStandardItem*> items;
+ items.append(new QStandardItem());
+ items.append(new QStandardItem());
+ parentItem->appendRow(items);
+ this->setPropertyData(this->indexFromItem(items[0]), prop, false);
+ }
+ }
+ }
+
+ this->blockSignals(b);
+ this->endResetModel();
+}
+
+QCMakeCacheModel::ViewType QCMakeCacheModel::viewType() const
+{
+ return this->View;
+}
+
+void QCMakeCacheModel::setViewType(QCMakeCacheModel::ViewType t)
+{
+ this->beginResetModel();
+
+ this->View = t;
+
+ QCMakePropertyList props = this->properties();
+ QCMakePropertyList oldProps;
+ int numNew = this->NewPropertyCount;
+ int numTotal = props.count();
+ for (int i = numNew; i < numTotal; i++) {
+ oldProps.append(props[i]);
+ }
+
+ bool b = this->blockSignals(true);
+ this->clear();
+ this->setProperties(oldProps);
+ this->setProperties(props);
+ this->blockSignals(b);
+ this->endResetModel();
+}
+
+void QCMakeCacheModel::setPropertyData(const QModelIndex& idx1,
+ const QCMakeProperty& prop, bool isNew)
+{
+ QModelIndex idx2 = idx1.sibling(idx1.row(), 1);
+
+ this->setData(idx1, prop.Key, Qt::DisplayRole);
+ this->setData(idx1, prop.Help, QCMakeCacheModel::HelpRole);
+ this->setData(idx1, prop.Type, QCMakeCacheModel::TypeRole);
+ this->setData(idx1, prop.Advanced, QCMakeCacheModel::AdvancedRole);
+
+ if (prop.Type == QCMakeProperty::BOOL) {
+ int check = prop.Value.toBool() ? Qt::Checked : Qt::Unchecked;
+ this->setData(idx2, check, Qt::CheckStateRole);
+ } else {
+ this->setData(idx2, prop.Value, Qt::DisplayRole);
+ }
+ this->setData(idx2, prop.Help, QCMakeCacheModel::HelpRole);
+
+ if (!prop.Strings.isEmpty()) {
+ this->setData(idx1, prop.Strings, QCMakeCacheModel::StringsRole);
+ }
+
+ if (isNew) {
+#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
+ this->setData(idx1, QBrush(QColor(255, 100, 100)), Qt::BackgroundRole);
+ this->setData(idx2, QBrush(QColor(255, 100, 100)), Qt::BackgroundRole);
+#else
+ this->setData(idx1, QBrush(QColor(255, 100, 100)),
+ Qt::BackgroundColorRole);
+ this->setData(idx2, QBrush(QColor(255, 100, 100)),
+ Qt::BackgroundColorRole);
+#endif
+ }
+}
+
+void QCMakeCacheModel::getPropertyData(const QModelIndex& idx1,
+ QCMakeProperty& prop) const
+{
+ QModelIndex idx2 = idx1.sibling(idx1.row(), 1);
+
+ prop.Key = this->data(idx1, Qt::DisplayRole).toString();
+ prop.Help = this->data(idx1, HelpRole).toString();
+ prop.Type = static_cast<QCMakeProperty::PropertyType>(
+ this->data(idx1, TypeRole).toInt());
+ prop.Advanced = this->data(idx1, AdvancedRole).toBool();
+ prop.Strings =
+ this->data(idx1, QCMakeCacheModel::StringsRole).toStringList();
+ if (prop.Type == QCMakeProperty::BOOL) {
+ int check = this->data(idx2, Qt::CheckStateRole).toInt();
+ prop.Value = check == Qt::Checked;
+ } else {
+ prop.Value = this->data(idx2, Qt::DisplayRole).toString();
+ }
+}
+
+QString QCMakeCacheModel::prefix(const QString& s)
+{
+ QString prefix = s.section('_', 0, 0);
+ if (prefix == s) {
+ prefix = QString();
+ }
+ return prefix;
+}
+
+void QCMakeCacheModel::breakProperties(
+ const QSet<QCMakeProperty>& props, QMap<QString, QCMakePropertyList>& result)
+{
+ QMap<QString, QCMakePropertyList> tmp;
+ // return a map of properties grouped by prefixes, and sorted
+ foreach (QCMakeProperty const& p, props) {
+ QString prefix = QCMakeCacheModel::prefix(p.Key);
+ tmp[prefix].append(p);
+ }
+ // sort it and re-org any properties with only one sub item
+ QCMakePropertyList reorgProps;
+ QMap<QString, QCMakePropertyList>::iterator iter;
+ for (iter = tmp.begin(); iter != tmp.end();) {
+ if (iter->count() == 1) {
+ reorgProps.append((*iter)[0]);
+ iter = tmp.erase(iter);
+ } else {
+#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
+ std::sort(iter->begin(), iter->end());
+#else
+ qSort(*iter);
+#endif
+ ++iter;
+ }
+ }
+ if (reorgProps.count()) {
+ tmp[QString()] += reorgProps;
+ }
+ result = tmp;
+}
+
+QCMakePropertyList QCMakeCacheModel::properties() const
+{
+ QCMakePropertyList props;
+
+ if (!this->rowCount()) {
+ return props;
+ }
+
+ QVector<QModelIndex> idxs;
+ idxs.append(this->index(0, 0));
+
+ // walk the entire model for property entries
+ // this works regardless of a flat view or a tree view
+ while (!idxs.isEmpty()) {
+ QModelIndex idx = idxs.last();
+ if (this->hasChildren(idx) && this->rowCount(idx)) {
+ idxs.append(this->index(0, 0, idx));
+ } else {
+ if (!data(idx, GroupRole).toInt()) {
+ // get data
+ QCMakeProperty prop;
+ this->getPropertyData(idx, prop);
+ props.append(prop);
+ }
+
+ // go to the next in the tree
+ while (!idxs.isEmpty() &&
+ (
+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
+ (idxs.last().row() + 1) >= rowCount(idxs.last().parent()) ||
+#endif
+ !idxs.last().sibling(idxs.last().row() + 1, 0).isValid())) {
+ idxs.remove(idxs.size() - 1);
+ }
+ if (!idxs.isEmpty()) {
+ idxs.last() = idxs.last().sibling(idxs.last().row() + 1, 0);
+ }
+ }
+ }
+
+ return props;
+}
+
+bool QCMakeCacheModel::insertProperty(QCMakeProperty::PropertyType t,
+ const QString& name,
+ const QString& description,
+ const QVariant& value, bool advanced)
+{
+ QCMakeProperty prop;
+ prop.Key = name;
+ prop.Value = value;
+ prop.Help = description;
+ prop.Type = t;
+ prop.Advanced = advanced;
+
+ // insert at beginning
+ this->insertRow(0);
+ this->setPropertyData(this->index(0, 0), prop, true);
+ this->NewPropertyCount++;
+ return true;
+}
+
+void QCMakeCacheModel::setEditEnabled(bool e)
+{
+ this->EditEnabled = e;
+}
+
+bool QCMakeCacheModel::editEnabled() const
+{
+ return this->EditEnabled;
+}
+
+int QCMakeCacheModel::newPropertyCount() const
+{
+ return this->NewPropertyCount;
+}
+
+Qt::ItemFlags QCMakeCacheModel::flags(const QModelIndex& idx) const
+{
+ Qt::ItemFlags f = QStandardItemModel::flags(idx);
+ if (!this->EditEnabled) {
+ f &= ~Qt::ItemIsEditable;
+ return f;
+ }
+ if (QCMakeProperty::BOOL == this->data(idx, TypeRole).toInt()) {
+ f |= Qt::ItemIsUserCheckable;
+ }
+ return f;
+}
+
+QModelIndex QCMakeCacheModel::buddy(const QModelIndex& idx) const
+{
+ if (!this->hasChildren(idx) &&
+ this->data(idx, TypeRole).toInt() != QCMakeProperty::BOOL) {
+ return this->index(idx.row(), 1, idx.parent());
+ }
+ return idx;
+}
+
+QCMakeCacheModelDelegate::QCMakeCacheModelDelegate(QObject* p)
+ : QItemDelegate(p)
+ , FileDialogFlag(false)
+{
+}
+
+void QCMakeCacheModelDelegate::setFileDialogFlag(bool f)
+{
+ this->FileDialogFlag = f;
+}
+
+QWidget* QCMakeCacheModelDelegate::createEditor(
+ QWidget* p, const QStyleOptionViewItem& /*option*/,
+ const QModelIndex& idx) const
+{
+ QModelIndex var = idx.sibling(idx.row(), 0);
+ int type = var.data(QCMakeCacheModel::TypeRole).toInt();
+ if (type == QCMakeProperty::BOOL) {
+ return nullptr;
+ }
+ if (type == QCMakeProperty::PATH) {
+ QCMakePathEditor* editor =
+ new QCMakePathEditor(p, var.data(Qt::DisplayRole).toString());
+ 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, &QCMakePathEditor::fileDialogExists, this,
+ &QCMakeCacheModelDelegate::setFileDialogFlag);
+ return editor;
+ }
+ if (type == QCMakeProperty::STRING &&
+ var.data(QCMakeCacheModel::StringsRole).isValid()) {
+ QCMakeComboBox* editor = new QCMakeComboBox(
+ p, var.data(QCMakeCacheModel::StringsRole).toStringList());
+ editor->setFrame(false);
+ return editor;
+ }
+
+ QLineEdit* editor = new QLineEdit(p);
+ editor->setFrame(false);
+ return editor;
+}
+
+bool QCMakeCacheModelDelegate::editorEvent(QEvent* e,
+ QAbstractItemModel* model,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index)
+{
+ Qt::ItemFlags flags = model->flags(index);
+ if (!(flags & Qt::ItemIsUserCheckable) ||
+ !(option.state & QStyle::State_Enabled) ||
+ !(flags & Qt::ItemIsEnabled)) {
+ return false;
+ }
+
+ QVariant value = index.data(Qt::CheckStateRole);
+ if (!value.isValid()) {
+ return false;
+ }
+
+ if ((e->type() == QEvent::MouseButtonRelease) ||
+ (e->type() == QEvent::MouseButtonDblClick)) {
+ // eat the double click events inside the check rect
+ if (e->type() == QEvent::MouseButtonDblClick) {
+ return true;
+ }
+ } else if (e->type() == QEvent::KeyPress) {
+ if (static_cast<QKeyEvent*>(e)->key() != Qt::Key_Space &&
+ static_cast<QKeyEvent*>(e)->key() != Qt::Key_Select) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ Qt::CheckState state =
+ (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked ? Qt::Unchecked
+ : Qt::Checked);
+ bool success = model->setData(index, state, Qt::CheckStateRole);
+ if (success) {
+ this->recordChange(model, index);
+ }
+ return success;
+}
+
+bool QCMakeCacheModelDelegate::eventFilter(QObject* object, QEvent* evt)
+{
+ // FIXME: This filter avoids a crash when opening a file dialog
+ // with the '...' button on a cache entry line in the GUI.
+ // Previously this filter was commented as a workaround for Qt issue 205903,
+ // but that was fixed in Qt 4.5.0 and the crash still occurs as of Qt 5.14
+ // without this filter. This needs further investigation.
+ if (evt->type() == QEvent::FocusOut && this->FileDialogFlag) {
+ return false;
+ }
+ return QItemDelegate::eventFilter(object, evt);
+}
+
+void QCMakeCacheModelDelegate::setModelData(QWidget* editor,
+ QAbstractItemModel* model,
+ const QModelIndex& index) const
+{
+ QItemDelegate::setModelData(editor, model, index);
+ const_cast<QCMakeCacheModelDelegate*>(this)->recordChange(model, index);
+}
+
+QSize QCMakeCacheModelDelegate::sizeHint(const QStyleOptionViewItem& option,
+ const QModelIndex& index) const
+{
+ QSize sz = QItemDelegate::sizeHint(option, index);
+ QStyle* style = QApplication::style();
+
+ // increase to checkbox size
+ QStyleOptionButton opt;
+ opt.QStyleOption::operator=(option);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
+ sz = sz.expandedTo(
+ style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &opt, nullptr)
+ .size());
+#else
+ sz = sz.expandedTo(
+ style->subElementRect(QStyle::SE_ViewItemCheckIndicator, &opt, nullptr)
+ .size());
+#endif
+
+ return sz;
+}
+
+QSet<QCMakeProperty> QCMakeCacheModelDelegate::changes() const
+{
+ return mChanges;
+}
+
+void QCMakeCacheModelDelegate::clearChanges()
+{
+ mChanges.clear();
+}
+
+void QCMakeCacheModelDelegate::recordChange(QAbstractItemModel* model,
+ const QModelIndex& index)
+{
+ QModelIndex idx = index;
+ QAbstractItemModel* mymodel = model;
+ while (qobject_cast<QAbstractProxyModel*>(mymodel)) {
+ idx = static_cast<QAbstractProxyModel*>(mymodel)->mapToSource(idx);
+ mymodel = static_cast<QAbstractProxyModel*>(mymodel)->sourceModel();
+ }
+ QCMakeCacheModel* cache_model = qobject_cast<QCMakeCacheModel*>(mymodel);
+ if (cache_model && idx.isValid()) {
+ QCMakeProperty prop;
+ idx = idx.sibling(idx.row(), 0);
+ cache_model->getPropertyData(idx, prop);
+
+ // clean out an old one
+ QSet<QCMakeProperty>::iterator iter = mChanges.find(prop);
+ if (iter != mChanges.end()) {
+ mChanges.erase(iter);
+ }
+ // now add the new item
+ mChanges.insert(prop);
+ }
+}
diff --git a/Source/QtDialog/QCMakeCacheView.h b/Source/QtDialog/QCMakeCacheView.h
new file mode 100644
index 0000000..c5e6dd4
--- /dev/null
+++ b/Source/QtDialog/QCMakeCacheView.h
@@ -0,0 +1,166 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "QCMake.h"
+#include <QItemDelegate>
+#include <QSet>
+#include <QStandardItemModel>
+#include <QTreeView>
+
+class QSortFilterProxyModel;
+class QCMakeCacheModel;
+class QCMakeAdvancedFilter;
+
+/// Qt view class for cache properties
+class QCMakeCacheView : public QTreeView
+{
+ Q_OBJECT
+public:
+ QCMakeCacheView(QWidget* p);
+
+ // retrieve the QCMakeCacheModel storing all the pointers
+ // this isn't necessarily the model one would get from model()
+ QCMakeCacheModel* cacheModel() const;
+
+ // get whether to show advanced entries
+ bool showAdvanced() const;
+
+ QSize sizeHint() const { return QSize(200, 200); }
+
+public slots:
+ // set whether to show advanced entries
+ void setShowAdvanced(bool);
+ // set the search filter string. any property key or value not matching will
+ // be filtered out
+ void setSearchFilter(const QString&);
+
+protected:
+ QModelIndex moveCursor(CursorAction, Qt::KeyboardModifiers);
+ bool event(QEvent* e);
+ QCMakeCacheModel* CacheModel;
+ QCMakeAdvancedFilter* AdvancedFilter;
+ QSortFilterProxyModel* SearchFilter;
+};
+
+/// Qt model class for cache properties
+class QCMakeCacheModel : public QStandardItemModel
+{
+ Q_OBJECT
+public:
+ QCMakeCacheModel(QObject* parent = nullptr);
+ ~QCMakeCacheModel();
+
+ // roles used to retrieve extra data such has help strings, types of
+ // properties, and the advanced flag
+ enum
+ {
+ HelpRole = Qt::ToolTipRole,
+ TypeRole = Qt::UserRole,
+ AdvancedRole,
+ StringsRole,
+ GroupRole
+ };
+
+ enum ViewType
+ {
+ FlatView,
+ GroupView
+ };
+
+public slots:
+ // set a list of properties. This list will be sorted and grouped according
+ // to prefix. Any property that existed already and which is found in this
+ // list of properties to set will become an old property. All others will
+ // become new properties and be marked red.
+ void setProperties(const QCMakePropertyList& props);
+
+ // set whether to show new properties in red
+ void setShowNewProperties(bool);
+
+ // clear everything from the model
+ void clear();
+
+ // set flag whether the model can currently be edited.
+ void setEditEnabled(bool);
+
+ // insert a new property at a row specifying all the information about the
+ // property
+ bool insertProperty(QCMakeProperty::PropertyType t, const QString& name,
+ const QString& description, const QVariant& value,
+ bool advanced);
+
+ // set the view type
+ void setViewType(ViewType t);
+ ViewType viewType() const;
+
+public:
+ // get the properties
+ QCMakePropertyList properties() const;
+
+ // editing enabled
+ bool editEnabled() const;
+
+ // returns how many new properties there are
+ int newPropertyCount() const;
+
+ // return flags (overloaded to modify flag based on EditEnabled flag)
+ Qt::ItemFlags flags(const QModelIndex& index) const;
+ QModelIndex buddy(const QModelIndex& idx) const;
+
+ // get the data in the model for this property
+ void getPropertyData(const QModelIndex& idx1, QCMakeProperty& prop) const;
+
+protected:
+ bool EditEnabled;
+ int NewPropertyCount;
+ bool ShowNewProperties;
+ ViewType View;
+
+ // set the data in the model for this property
+ void setPropertyData(const QModelIndex& idx1, const QCMakeProperty& p,
+ bool isNew);
+
+ // breaks up he property list into groups
+ // where each group has the same prefix up to the first underscore
+ static void breakProperties(const QSet<QCMakeProperty>& props,
+ QMap<QString, QCMakePropertyList>& result);
+
+ // gets the prefix of a string up to the first _
+ static QString prefix(const QString& s);
+};
+
+/// Qt delegate class for interaction (or other customization)
+/// with cache properties
+class QCMakeCacheModelDelegate : public QItemDelegate
+{
+ Q_OBJECT
+public:
+ QCMakeCacheModelDelegate(QObject* p);
+ /// create our own editors for cache properties
+ QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option,
+ const QModelIndex& index) const;
+ bool editorEvent(QEvent* event, QAbstractItemModel* model,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index);
+ bool eventFilter(QObject* object, QEvent* event);
+ void setModelData(QWidget* editor, QAbstractItemModel* model,
+ const QModelIndex& index) const;
+ QSize sizeHint(const QStyleOptionViewItem& option,
+ const QModelIndex& index) const;
+
+ QSet<QCMakeProperty> changes() const;
+ void clearChanges();
+
+protected slots:
+ void setFileDialogFlag(bool);
+
+protected:
+ bool FileDialogFlag;
+ // record a change to an item in the model.
+ // this simply saves the item in the set of changes
+ void recordChange(QAbstractItemModel* model, const QModelIndex& index);
+
+ // properties changed by user via this delegate
+ QSet<QCMakeProperty> mChanges;
+};
diff --git a/Source/QtDialog/QCMakePreset.cxx b/Source/QtDialog/QCMakePreset.cxx
new file mode 100644
index 0000000..176f532
--- /dev/null
+++ b/Source/QtDialog/QCMakePreset.cxx
@@ -0,0 +1,53 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "QCMakePreset.h"
+
+bool operator==(const QCMakePreset& lhs, const QCMakePreset& rhs)
+{
+ return lhs.name == rhs.name && lhs.displayName == rhs.displayName &&
+ lhs.description == rhs.description && lhs.generator == rhs.generator &&
+ lhs.architecture == rhs.architecture &&
+ lhs.setArchitecture == rhs.setArchitecture && lhs.toolset == rhs.toolset &&
+ lhs.setToolset == rhs.setToolset && lhs.enabled == rhs.enabled;
+}
+
+bool operator!=(const QCMakePreset& lhs, const QCMakePreset& rhs)
+{
+ return !(lhs == rhs);
+}
+
+bool operator<(const QCMakePreset& lhs, const QCMakePreset& rhs)
+{
+ return lhs.name < rhs.name ||
+ (lhs.name == rhs.name &&
+ (lhs.displayName < rhs.displayName ||
+ (lhs.displayName == rhs.displayName &&
+ (lhs.description < rhs.description ||
+ (lhs.description == rhs.description &&
+ (lhs.generator < rhs.generator ||
+ (lhs.generator == rhs.generator &&
+ (lhs.architecture < rhs.architecture ||
+ (lhs.architecture == rhs.architecture &&
+ (lhs.setArchitecture < rhs.setArchitecture ||
+ (lhs.setArchitecture == rhs.setArchitecture &&
+ (lhs.toolset < rhs.toolset ||
+ (lhs.toolset == rhs.toolset &&
+ (lhs.setToolset < rhs.setToolset ||
+ (lhs.setToolset == rhs.setToolset &&
+ (lhs.enabled < rhs.enabled))))))))))))))));
+}
+
+bool operator<=(const QCMakePreset& lhs, const QCMakePreset& rhs)
+{
+ return rhs >= lhs;
+}
+
+bool operator>(const QCMakePreset& lhs, const QCMakePreset& rhs)
+{
+ return rhs < lhs;
+}
+
+bool operator>=(const QCMakePreset& lhs, const QCMakePreset& rhs)
+{
+ return !(lhs < rhs);
+}
diff --git a/Source/QtDialog/QCMakePreset.h b/Source/QtDialog/QCMakePreset.h
new file mode 100644
index 0000000..1609fcb
--- /dev/null
+++ b/Source/QtDialog/QCMakePreset.h
@@ -0,0 +1,31 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <QString>
+#include <QVariant>
+
+#include "cmCMakePresetsFile.h"
+
+class QCMakePreset
+{
+public:
+ QString name;
+ QString displayName;
+ QString description;
+ QString generator;
+ QString architecture;
+ bool setArchitecture;
+ QString toolset;
+ bool setToolset;
+ bool enabled;
+};
+
+bool operator==(const QCMakePreset& lhs, const QCMakePreset& rhs);
+bool operator!=(const QCMakePreset& lhs, const QCMakePreset& rhs);
+bool operator<(const QCMakePreset& lhs, const QCMakePreset& rhs);
+bool operator<=(const QCMakePreset& lhs, const QCMakePreset& rhs);
+bool operator>(const QCMakePreset& lhs, const QCMakePreset& rhs);
+bool operator>=(const QCMakePreset& lhs, const QCMakePreset& rhs);
+
+Q_DECLARE_METATYPE(QCMakePreset)
diff --git a/Source/QtDialog/QCMakePresetComboBox.cxx b/Source/QtDialog/QCMakePresetComboBox.cxx
new file mode 100644
index 0000000..efadb73
--- /dev/null
+++ b/Source/QtDialog/QCMakePresetComboBox.cxx
@@ -0,0 +1,64 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "QCMakePresetComboBox.h"
+
+#include "QCMakePresetItemModel.h"
+
+QCMakePresetComboBox::QCMakePresetComboBox(QWidget* parent)
+ : QComboBox(parent)
+{
+ this->m_model = new QCMakePresetItemModel(this);
+ this->setModel(this->m_model);
+
+ QObject::connect(this->m_model, &QCMakePresetItemModel::modelAboutToBeReset,
+ this, [this]() { this->m_resetting = true; });
+ QObject::connect(this->m_model, &QCMakePresetItemModel::modelReset, this,
+ [this]() {
+ this->setPresetName(this->m_lastPreset);
+ this->m_resetting = false;
+ this->emitPresetChanged();
+ });
+ QObject::connect(
+ this,
+ static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ this, [this](int /*row*/) {
+ if (!this->m_resetting) {
+ this->emitPresetChanged();
+ }
+ });
+}
+
+const QVector<QCMakePreset>& QCMakePresetComboBox::presets() const
+{
+ return this->m_model->presets();
+}
+
+QString QCMakePresetComboBox::presetName() const
+{
+ auto preset = this->currentData();
+ if (preset.canConvert<QCMakePreset>()) {
+ return preset.value<QCMakePreset>().name;
+ }
+ return QString{};
+}
+
+void QCMakePresetComboBox::setPresets(const QVector<QCMakePreset>& presets)
+{
+ this->m_model->setPresets(presets);
+}
+
+void QCMakePresetComboBox::setPresetName(const QString& name)
+{
+ this->setCurrentIndex(this->m_model->presetNameToRow(name));
+ if (this->signalsBlocked()) {
+ this->m_lastPreset = this->presetName();
+ }
+}
+
+void QCMakePresetComboBox::emitPresetChanged()
+{
+ if (this->presetName() != this->m_lastPreset) {
+ emit this->presetChanged(this->presetName());
+ this->m_lastPreset = this->presetName();
+ }
+}
diff --git a/Source/QtDialog/QCMakePresetComboBox.h b/Source/QtDialog/QCMakePresetComboBox.h
new file mode 100644
index 0000000..d1eeffe
--- /dev/null
+++ b/Source/QtDialog/QCMakePresetComboBox.h
@@ -0,0 +1,35 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "QCMakePreset.h"
+#include <QComboBox>
+#include <QObject>
+#include <QString>
+#include <QVector>
+
+class QCMakePresetItemModel;
+
+class QCMakePresetComboBox : public QComboBox
+{
+ Q_OBJECT
+public:
+ QCMakePresetComboBox(QWidget* parent = nullptr);
+
+ const QVector<QCMakePreset>& presets() const;
+ QString presetName() const;
+
+public slots:
+ void setPresets(const QVector<QCMakePreset>& presets);
+ void setPresetName(const QString& name);
+
+signals:
+ void presetChanged(const QString& name);
+
+private:
+ QCMakePresetItemModel* m_model;
+ bool m_resetting = false;
+ QString m_lastPreset;
+
+ void emitPresetChanged();
+};
diff --git a/Source/QtDialog/QCMakePresetItemModel.cxx b/Source/QtDialog/QCMakePresetItemModel.cxx
new file mode 100644
index 0000000..00a4e18
--- /dev/null
+++ b/Source/QtDialog/QCMakePresetItemModel.cxx
@@ -0,0 +1,143 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "QCMakePresetItemModel.h"
+
+#include <QFont>
+
+QCMakePresetItemModel::QCMakePresetItemModel(QObject* parent)
+ : QAbstractItemModel(parent)
+{
+}
+
+QVariant QCMakePresetItemModel::data(const QModelIndex& index, int role) const
+{
+ switch (role) {
+ case Qt::AccessibleDescriptionRole:
+ // Separators have to return "separator" for the
+ // AccessibleDescriptionRole. This was determined by looking at
+ // QComboBoxDelegate::isSeparator() (located in qcombobox_p.h.)
+ if (index.internalId() == SEPARATOR_INDEX) {
+ return QString::fromLocal8Bit("separator");
+ }
+ return QString{};
+ case Qt::DisplayRole: {
+ if (index.internalId() == CUSTOM_INDEX) {
+ return QString::fromLocal8Bit("<custom>");
+ }
+ if (index.internalId() == SEPARATOR_INDEX) {
+ return QVariant{};
+ }
+ auto const& preset = this->m_presets[index.internalId()];
+ return preset.displayName.isEmpty() ? preset.name : preset.displayName;
+ }
+ case Qt::ToolTipRole:
+ if (index.internalId() == CUSTOM_INDEX) {
+ return QString::fromLocal8Bit("Specify all settings manually");
+ }
+ if (index.internalId() == SEPARATOR_INDEX) {
+ return QVariant{};
+ }
+ return this->m_presets[index.internalId()].description;
+ case Qt::UserRole:
+ if (index.internalId() == CUSTOM_INDEX) {
+ return QVariant{};
+ }
+ if (index.internalId() == SEPARATOR_INDEX) {
+ return QVariant{};
+ }
+ return QVariant::fromValue(this->m_presets[index.internalId()]);
+ case Qt::FontRole:
+ if (index.internalId() == CUSTOM_INDEX) {
+ QFont font;
+ font.setItalic(true);
+ return font;
+ }
+ return QFont{};
+ default:
+ return QVariant{};
+ }
+}
+
+Qt::ItemFlags QCMakePresetItemModel::flags(const QModelIndex& index) const
+{
+ Qt::ItemFlags flags =
+ Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
+ if (index.internalId() != SEPARATOR_INDEX &&
+ (index.internalId() == CUSTOM_INDEX ||
+ this->m_presets[index.internalId()].enabled)) {
+ flags |= Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+ }
+ return flags;
+}
+
+int QCMakePresetItemModel::rowCount(const QModelIndex& parent) const
+{
+ if (parent.isValid()) {
+ return 0;
+ }
+ if (this->m_presets.empty()) {
+ return 1;
+ }
+ return this->m_presets.size() + 2;
+}
+
+int QCMakePresetItemModel::columnCount(const QModelIndex& parent) const
+{
+ if (parent.isValid()) {
+ return 0;
+ }
+ return 1;
+}
+
+QModelIndex QCMakePresetItemModel::index(int row, int column,
+ const QModelIndex& parent) const
+{
+ if (parent.isValid() || column != 0 || row < 0 ||
+ row >= this->rowCount(QModelIndex{})) {
+ return QModelIndex{};
+ }
+
+ if (this->m_presets.empty() || row == this->m_presets.size() + 1) {
+ return this->createIndex(row, column, CUSTOM_INDEX);
+ }
+
+ if (row == this->m_presets.size()) {
+ return this->createIndex(row, column, SEPARATOR_INDEX);
+ }
+
+ return this->createIndex(row, column, static_cast<quintptr>(row));
+}
+
+QModelIndex QCMakePresetItemModel::parent(const QModelIndex& /*index*/) const
+{
+ return QModelIndex{};
+}
+
+QVector<QCMakePreset> const& QCMakePresetItemModel::presets() const
+{
+ return this->m_presets;
+}
+
+void QCMakePresetItemModel::setPresets(QVector<QCMakePreset> const& presets)
+{
+ this->beginResetModel();
+ this->m_presets = presets;
+ this->endResetModel();
+}
+
+int QCMakePresetItemModel::presetNameToRow(const QString& name) const
+{
+ if (this->m_presets.empty()) {
+ return 0;
+ }
+
+ int index = 0;
+ for (auto const& preset : this->m_presets) {
+ if (preset.name == name) {
+ return index;
+ }
+ index++;
+ }
+
+ return this->m_presets.size() + 1;
+}
diff --git a/Source/QtDialog/QCMakePresetItemModel.h b/Source/QtDialog/QCMakePresetItemModel.h
new file mode 100644
index 0000000..79fba29
--- /dev/null
+++ b/Source/QtDialog/QCMakePresetItemModel.h
@@ -0,0 +1,45 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <cm/optional>
+
+#include "QCMakePreset.h"
+#include <QAbstractItemModel>
+#include <QModelIndex>
+#include <QString>
+#include <QVariant>
+#include <QVector>
+#include <QtGlobal>
+
+class QObject;
+
+class QCMakePresetItemModel : public QAbstractItemModel
+{
+ Q_OBJECT
+public:
+ QCMakePresetItemModel(QObject* parent = nullptr);
+
+ QVariant data(const QModelIndex& index, int role) const override;
+ Qt::ItemFlags flags(const QModelIndex& index) const override;
+
+ int rowCount(const QModelIndex& parent = QModelIndex{}) const override;
+ int columnCount(const QModelIndex& parent = QModelIndex{}) const override;
+
+ QModelIndex index(int row, int column,
+ const QModelIndex& parent = QModelIndex{}) const override;
+ QModelIndex parent(const QModelIndex& index) const override;
+
+ QVector<QCMakePreset> const& presets() const;
+
+ int presetNameToRow(const QString& name) const;
+
+public slots:
+ void setPresets(QVector<QCMakePreset> const& presets);
+
+private:
+ QVector<QCMakePreset> m_presets;
+
+ static constexpr quintptr SEPARATOR_INDEX = static_cast<quintptr>(-2);
+ static constexpr quintptr CUSTOM_INDEX = static_cast<quintptr>(-1);
+};
diff --git a/Source/QtDialog/QCMakeWidgets.cxx b/Source/QtDialog/QCMakeWidgets.cxx
new file mode 100644
index 0000000..03d6ed1
--- /dev/null
+++ b/Source/QtDialog/QCMakeWidgets.cxx
@@ -0,0 +1,157 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#define QT_DEPRECATED_WARNINGS_SINCE QT_VERSION_CHECK(5, 14, 0)
+
+#include "QCMakeWidgets.h"
+
+#include <utility>
+
+#include <QFileDialog>
+#include <QFileInfo>
+#include <QResizeEvent>
+#include <QToolButton>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
+# include <QFileSystemModel>
+#else
+# include <QDirModel>
+#endif
+
+QCMakeFileEditor::QCMakeFileEditor(QWidget* p, QString var)
+ : QLineEdit(p)
+ , Variable(std::move(var))
+{
+ this->ToolButton = new QToolButton(this);
+ this->ToolButton->setText("...");
+ this->ToolButton->setCursor(QCursor(Qt::ArrowCursor));
+ QObject::connect(this->ToolButton, &QAbstractButton::clicked, this,
+ &QCMakeFileEditor::chooseFile);
+}
+
+QCMakeFilePathEditor::QCMakeFilePathEditor(QWidget* p, const QString& var)
+ : QCMakeFileEditor(p, var)
+{
+ this->setCompleter(new QCMakeFileCompleter(this, false));
+}
+
+QCMakePathEditor::QCMakePathEditor(QWidget* p, const QString& var)
+ : QCMakeFileEditor(p, var)
+{
+ this->setCompleter(new QCMakeFileCompleter(this, true));
+}
+
+void QCMakeFileEditor::resizeEvent(QResizeEvent* e)
+{
+ // make the tool button fit on the right side
+ int h = e->size().height();
+ // move the line edit to make room for the tool button
+ this->setContentsMargins(0, 0, h, 0);
+ // put the tool button in its place
+ this->ToolButton->resize(h, h);
+ this->ToolButton->move(this->width() - h, 0);
+}
+
+void QCMakeFilePathEditor::chooseFile()
+{
+ // choose a file and set it
+ QString path;
+ QFileInfo info(this->text());
+ QString title;
+ if (this->Variable.isEmpty()) {
+ title = tr("Select File");
+ } else {
+ title = tr("Select File for %1");
+ title = title.arg(this->Variable);
+ }
+ emit this->fileDialogExists(true);
+ path =
+ QFileDialog::getOpenFileName(this, title, info.absolutePath(), QString(),
+ nullptr, QFileDialog::DontResolveSymlinks);
+ emit this->fileDialogExists(false);
+
+ if (!path.isEmpty()) {
+ this->setText(QDir::fromNativeSeparators(path));
+ }
+}
+
+void QCMakePathEditor::chooseFile()
+{
+ // choose a file and set it
+ QString path;
+ QString title;
+ if (this->Variable.isEmpty()) {
+ title = tr("Select Path");
+ } else {
+ title = tr("Select Path for %1");
+ title = title.arg(this->Variable);
+ }
+ emit this->fileDialogExists(true);
+ path = QFileDialog::getExistingDirectory(this, title, this->text(),
+ QFileDialog::ShowDirsOnly |
+ QFileDialog::DontResolveSymlinks);
+ emit this->fileDialogExists(false);
+ if (!path.isEmpty()) {
+ this->setText(QDir::fromNativeSeparators(path));
+ }
+}
+
+#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
+// use same QFileSystemModel for all completers
+static QFileSystemModel* fileDirModel()
+
+{
+ static QFileSystemModel* m = nullptr;
+ if (!m) {
+ m = new QFileSystemModel();
+ }
+ return m;
+}
+static QFileSystemModel* pathDirModel()
+{
+ static QFileSystemModel* m = nullptr;
+ if (!m) {
+ m = new QFileSystemModel();
+ m->setFilter(QDir::AllDirs | QDir::Drives | QDir::NoDotAndDotDot);
+ }
+ return m;
+}
+#else
+// use same QDirModel for all completers
+static QDirModel* fileDirModel()
+
+{
+ static QDirModel* m = nullptr;
+ if (!m) {
+ m = new QDirModel();
+ }
+ return m;
+}
+static QDirModel* pathDirModel()
+{
+ static QDirModel* m = nullptr;
+ if (!m) {
+ m = new QDirModel();
+ m->setFilter(QDir::AllDirs | QDir::Drives | QDir::NoDotAndDotDot);
+ }
+ return m;
+}
+#endif
+
+QCMakeFileCompleter::QCMakeFileCompleter(QObject* o, bool dirs)
+ : QCompleter(o)
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
+ QFileSystemModel* m = dirs ? pathDirModel() : fileDirModel();
+ this->setModel(m);
+ m->setRootPath(QString());
+#else
+ QDirModel* m = dirs ? pathDirModel() : fileDirModel();
+ this->setModel(m);
+#endif
+}
+
+QString QCMakeFileCompleter::pathFromIndex(const QModelIndex& idx) const
+{
+ return QDir::fromNativeSeparators(QCompleter::pathFromIndex(idx));
+}
diff --git a/Source/QtDialog/QCMakeWidgets.h b/Source/QtDialog/QCMakeWidgets.h
new file mode 100644
index 0000000..9a2a27e
--- /dev/null
+++ b/Source/QtDialog/QCMakeWidgets.h
@@ -0,0 +1,78 @@
+/* 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 <QComboBox>
+#include <QCompleter>
+#include <QLineEdit>
+
+class QToolButton;
+
+// common widgets for Qt based CMake
+
+/// Editor widget for editing paths or file paths
+class QCMakeFileEditor : public QLineEdit
+{
+ Q_OBJECT
+public:
+ QCMakeFileEditor(QWidget* p, QString var);
+protected slots:
+ virtual void chooseFile() = 0;
+signals:
+ void fileDialogExists(bool);
+
+protected:
+ void resizeEvent(QResizeEvent* e);
+ QToolButton* ToolButton;
+ QString Variable;
+};
+
+/// editor widget for editing files
+class QCMakePathEditor : public QCMakeFileEditor
+{
+ Q_OBJECT
+public:
+ QCMakePathEditor(QWidget* p = nullptr, const QString& var = QString());
+ void chooseFile();
+};
+
+/// editor widget for editing paths
+class QCMakeFilePathEditor : public QCMakeFileEditor
+{
+ Q_OBJECT
+public:
+ QCMakeFilePathEditor(QWidget* p = nullptr, const QString& var = QString());
+ void chooseFile();
+};
+
+/// completer class that returns native cmake paths
+class QCMakeFileCompleter : public QCompleter
+{
+ Q_OBJECT
+public:
+ QCMakeFileCompleter(QObject* o, bool dirs);
+ virtual QString pathFromIndex(const QModelIndex& idx) const;
+};
+
+// editor for strings
+class QCMakeComboBox : public QComboBox
+{
+ Q_OBJECT
+ Q_PROPERTY(QString value READ currentText WRITE setValue USER true);
+
+public:
+ QCMakeComboBox(QWidget* p, QStringList strings)
+ : QComboBox(p)
+ {
+ this->addItems(strings);
+ }
+ void setValue(const QString& v)
+ {
+ int i = this->findText(v);
+ if (i != -1) {
+ this->setCurrentIndex(i);
+ }
+ }
+};
diff --git a/Source/QtDialog/QtDialogCPack.cmake.in b/Source/QtDialog/QtDialogCPack.cmake.in
new file mode 100644
index 0000000..7ae8605
--- /dev/null
+++ b/Source/QtDialog/QtDialogCPack.cmake.in
@@ -0,0 +1,15 @@
+set(IS_APPLE @APPLE@)
+set(CMAKE_PACKAGE_QTGUI @CMAKE_PACKAGE_QTGUI@)
+
+if(CMAKE_PACKAGE_QTGUI)
+ set(CPACK_PACKAGE_EXECUTABLES "cmake-gui" "CMake (cmake-gui)" ${CPACK_PACKAGE_EXECUTABLES})
+ set(CPACK_CREATE_DESKTOP_LINKS "cmake-gui" ${CPACK_CREATE_DESKTOP_LINKS})
+ if(IS_APPLE)
+ # for apple install we set the install prefix to
+ # / and then install
+ # cmake into the bundle for cmake-gui and must use DESTDIR
+ set(CPACK_SET_DESTDIR TRUE)
+ endif()
+endif()
+
+
diff --git a/Source/QtDialog/RegexExplorer.cxx b/Source/QtDialog/RegexExplorer.cxx
new file mode 100644
index 0000000..6194940
--- /dev/null
+++ b/Source/QtDialog/RegexExplorer.cxx
@@ -0,0 +1,163 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "RegexExplorer.h"
+
+RegexExplorer::RegexExplorer(QWidget* p)
+ : QDialog(p)
+ , m_matched(false)
+{
+ this->setupUi(this);
+
+ for (int i = 1; i < cmsys::RegularExpressionMatch::NSUBEXP; ++i) {
+ matchNumber->addItem(QString("Match %1").arg(QString::number(i)),
+ QVariant(i));
+ }
+ matchNumber->setCurrentIndex(0);
+}
+
+void RegexExplorer::setStatusColor(QWidget* widget, bool successful)
+{
+ QColor color = successful ? QColor(0, 127, 0) : Qt::red;
+
+ QPalette palette = widget->palette();
+ palette.setColor(QPalette::WindowText, color);
+ widget->setPalette(palette);
+}
+
+void RegexExplorer::on_regularExpression_textChanged(const QString& text)
+{
+#ifdef QT_NO_STL
+ m_regex = text.toAscii().constData();
+#else
+ m_regex = text.toStdString();
+#endif
+
+ bool validExpression =
+ stripEscapes(m_regex) && m_regexParser.compile(m_regex);
+ if (!validExpression) {
+ m_regexParser.set_invalid();
+ }
+
+ setStatusColor(labelRegexValid, validExpression);
+
+ on_inputText_textChanged();
+}
+
+void RegexExplorer::on_inputText_textChanged()
+{
+ if (m_regexParser.is_valid()) {
+ QString plainText = inputText->toPlainText();
+#ifdef QT_NO_STL
+ m_text = plainText.toAscii().constData();
+#else
+ m_text = plainText.toStdString();
+#endif
+ m_matched = m_regexParser.find(m_text);
+ } else {
+ m_matched = false;
+ }
+
+ setStatusColor(labelRegexMatch, m_matched);
+
+ if (!m_matched) {
+ clearMatch();
+ return;
+ }
+
+ std::string matchingText;
+
+ if (matchAll->isChecked()) {
+ const char* p = m_text.c_str();
+ while (m_regexParser.find(p)) {
+ std::string::size_type l = m_regexParser.start();
+ std::string::size_type r = m_regexParser.end();
+ if (r - l == 0) {
+ // matched empty string
+ clearMatch();
+ return;
+ }
+ if (!matchingText.empty()) {
+ matchingText += ";";
+ }
+ matchingText += std::string(p + l, r - l);
+ p += r;
+ }
+ } else {
+ matchingText = m_regexParser.match(0);
+ }
+
+#ifdef QT_NO_STL
+ QString matchText = matchingText.c_str();
+#else
+ QString matchText = QString::fromStdString(matchingText);
+#endif
+ match0->setPlainText(matchText);
+
+ on_matchNumber_currentIndexChanged(matchNumber->currentIndex());
+}
+
+void RegexExplorer::on_matchNumber_currentIndexChanged(int index)
+{
+ if (!m_matched) {
+ return;
+ }
+
+ QVariant itemData = matchNumber->itemData(index);
+ int idx = itemData.toInt();
+
+ if (idx < 1 || idx >= cmsys::RegularExpressionMatch::NSUBEXP) {
+ return;
+ }
+
+#ifdef QT_NO_STL
+ QString match = m_regexParser.match(idx).c_str();
+#else
+ QString match = QString::fromStdString(m_regexParser.match(idx));
+#endif
+ matchN->setPlainText(match);
+}
+
+void RegexExplorer::on_matchAll_toggled(bool checked)
+{
+ Q_UNUSED(checked);
+
+ on_inputText_textChanged();
+}
+
+void RegexExplorer::clearMatch()
+{
+ m_matched = false;
+ match0->clear();
+ matchN->clear();
+}
+
+bool RegexExplorer::stripEscapes(std::string& source)
+{
+ const char* in = source.c_str();
+
+ std::string result;
+ result.reserve(source.size());
+
+ for (char inc = *in; inc != '\0'; inc = *++in) {
+ if (inc == '\\') {
+ char nextc = in[1];
+ if (nextc == 't') {
+ result.append(1, '\t');
+ in++;
+ } else if (nextc == 'n') {
+ result.append(1, '\n');
+ in++;
+ } else if (isalnum(nextc) || nextc == '\0') {
+ return false;
+ } else {
+ result.append(1, nextc);
+ in++;
+ }
+ } else {
+ result.append(1, inc);
+ }
+ }
+
+ source = result;
+ return true;
+}
diff --git a/Source/QtDialog/RegexExplorer.h b/Source/QtDialog/RegexExplorer.h
new file mode 100644
index 0000000..9a42320
--- /dev/null
+++ b/Source/QtDialog/RegexExplorer.h
@@ -0,0 +1,40 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+
+#include <QDialog>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "ui_RegexExplorer.h"
+
+class QString;
+class QWidget;
+
+class RegexExplorer
+ : public QDialog
+ , public Ui::RegexExplorer
+{
+ Q_OBJECT
+public:
+ RegexExplorer(QWidget* p);
+
+private slots:
+ void on_regularExpression_textChanged(const QString& text);
+ void on_inputText_textChanged();
+ void on_matchNumber_currentIndexChanged(int index);
+ void on_matchAll_toggled(bool checked);
+
+private:
+ static void setStatusColor(QWidget* widget, bool successful);
+ static bool stripEscapes(std::string& regex);
+
+ void clearMatch();
+
+ cmsys::RegularExpression m_regexParser;
+ std::string m_text;
+ std::string m_regex;
+ bool m_matched;
+};
diff --git a/Source/QtDialog/RegexExplorer.ui b/Source/QtDialog/RegexExplorer.ui
new file mode 100644
index 0000000..0af6999
--- /dev/null
+++ b/Source/QtDialog/RegexExplorer.ui
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>RegexExplorer</class>
+ <widget class="QDialog" name="RegexExplorer">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>639</width>
+ <height>555</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Regular Expression Explorer</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Input Text</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPlainTextEdit" name="inputText"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Regular Expression</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelRegexValid">
+ <property name="text">
+ <string>Valid</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelRegexMatch">
+ <property name="text">
+ <string>Match</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="regularExpression"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Complete Match</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="matchAll">
+ <property name="text">
+ <string>Match All</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPlainTextEdit" name="match0">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QComboBox" name="matchNumber">
+ <property name="editable">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPlainTextEdit" name="matchN">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Source/QtDialog/WarningMessagesDialog.cxx b/Source/QtDialog/WarningMessagesDialog.cxx
new file mode 100644
index 0000000..1fcf2b1
--- /dev/null
+++ b/Source/QtDialog/WarningMessagesDialog.cxx
@@ -0,0 +1,90 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "WarningMessagesDialog.h"
+
+WarningMessagesDialog::WarningMessagesDialog(QWidget* prnt, QCMake* instance)
+ : QDialog(prnt)
+ , cmakeInstance(instance)
+{
+ this->setupUi(this);
+ this->setInitialValues();
+ this->setupSignals();
+}
+
+void WarningMessagesDialog::setInitialValues()
+{
+ this->suppressDeveloperWarnings->setChecked(
+ this->cmakeInstance->getSuppressDevWarnings());
+ this->suppressDeprecatedWarnings->setChecked(
+ this->cmakeInstance->getSuppressDeprecatedWarnings());
+
+ this->developerWarningsAsErrors->setChecked(
+ this->cmakeInstance->getDevWarningsAsErrors());
+ this->deprecatedWarningsAsErrors->setChecked(
+ this->cmakeInstance->getDeprecatedWarningsAsErrors());
+}
+
+void WarningMessagesDialog::setupSignals()
+{
+ QObject::connect(this->buttonBox, &QDialogButtonBox::accepted, this,
+ &WarningMessagesDialog::doAccept);
+
+ QObject::connect(this->suppressDeveloperWarnings, &QCheckBox::stateChanged,
+ this,
+ &WarningMessagesDialog::doSuppressDeveloperWarningsChanged);
+ QObject::connect(
+ this->suppressDeprecatedWarnings, &QCheckBox::stateChanged, this,
+ &WarningMessagesDialog::doSuppressDeprecatedWarningsChanged);
+
+ QObject::connect(this->developerWarningsAsErrors, &QCheckBox::stateChanged,
+ this,
+ &WarningMessagesDialog::doDeveloperWarningsAsErrorsChanged);
+ QObject::connect(
+ this->deprecatedWarningsAsErrors, &QCheckBox::stateChanged, this,
+ &WarningMessagesDialog::doDeprecatedWarningsAsErrorsChanged);
+}
+
+void WarningMessagesDialog::doAccept()
+{
+ this->cmakeInstance->setSuppressDevWarnings(
+ this->suppressDeveloperWarnings->isChecked());
+ this->cmakeInstance->setSuppressDeprecatedWarnings(
+ this->suppressDeprecatedWarnings->isChecked());
+
+ this->cmakeInstance->setDevWarningsAsErrors(
+ this->developerWarningsAsErrors->isChecked());
+ this->cmakeInstance->setDeprecatedWarningsAsErrors(
+ this->deprecatedWarningsAsErrors->isChecked());
+}
+
+void WarningMessagesDialog::doSuppressDeveloperWarningsChanged(int state)
+{
+ // no warnings implies no errors either
+ if (state) {
+ this->developerWarningsAsErrors->setChecked(false);
+ }
+}
+
+void WarningMessagesDialog::doSuppressDeprecatedWarningsChanged(int state)
+{
+ // no warnings implies no errors either
+ if (state) {
+ this->deprecatedWarningsAsErrors->setChecked(false);
+ }
+}
+
+void WarningMessagesDialog::doDeveloperWarningsAsErrorsChanged(int state)
+{
+ // warnings as errors implies warnings are not suppressed
+ if (state) {
+ this->suppressDeveloperWarnings->setChecked(false);
+ }
+}
+
+void WarningMessagesDialog::doDeprecatedWarningsAsErrorsChanged(int state)
+{
+ // warnings as errors implies warnings are not suppressed
+ if (state) {
+ this->suppressDeprecatedWarnings->setChecked(false);
+ }
+}
diff --git a/Source/QtDialog/WarningMessagesDialog.h b/Source/QtDialog/WarningMessagesDialog.h
new file mode 100644
index 0000000..bb01704
--- /dev/null
+++ b/Source/QtDialog/WarningMessagesDialog.h
@@ -0,0 +1,64 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "QCMake.h"
+#include <QDialog>
+#include <QWidget>
+
+#include "ui_WarningMessagesDialog.h"
+
+/**
+ * Dialog window for setting the warning message related options.
+ */
+class WarningMessagesDialog
+ : public QDialog
+ , public Ui_MessagesDialog
+{
+ Q_OBJECT
+
+public:
+ WarningMessagesDialog(QWidget* prnt, QCMake* instance);
+
+private slots:
+ /**
+ * Handler for the accept event of the ok/cancel button box.
+ */
+ void doAccept();
+
+ /**
+ * Handler for checked state changed event of the suppress developer warnings
+ * checkbox.
+ */
+ void doSuppressDeveloperWarningsChanged(int state);
+ /**
+ * Handler for checked state changed event of the suppress deprecated
+ * warnings checkbox.
+ */
+ void doSuppressDeprecatedWarningsChanged(int state);
+
+ /**
+ * Handler for checked state changed event of the developer warnings as
+ * errors checkbox.
+ */
+ void doDeveloperWarningsAsErrorsChanged(int state);
+ /**
+ * Handler for checked state changed event of the deprecated warnings as
+ * errors checkbox.
+ */
+ void doDeprecatedWarningsAsErrorsChanged(int state);
+
+private:
+ QCMake* cmakeInstance;
+
+ /**
+ * Set the initial values of the widgets on this dialog window, using the
+ * current state of the cache.
+ */
+ void setInitialValues();
+
+ /**
+ * Setup the signals for the widgets on this dialog window.
+ */
+ void setupSignals();
+};
diff --git a/Source/QtDialog/WarningMessagesDialog.ui b/Source/QtDialog/WarningMessagesDialog.ui
new file mode 100644
index 0000000..3b35cbc
--- /dev/null
+++ b/Source/QtDialog/WarningMessagesDialog.ui
@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MessagesDialog</class>
+ <widget class="QDialog" name="MessagesDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>300</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Warning Messages</string>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Suppress Warnings</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="suppressDeveloperWarnings">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Suppress developer (author) warnings.</string>
+ </property>
+ <property name="text">
+ <string>Developer Warnings</string>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="suppressDeprecatedWarnings">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Suppress deprecated warnings.</string>
+ </property>
+ <property name="text">
+ <string>Deprecated Warnings</string>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Warnings as Errors</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QCheckBox" name="developerWarningsAsErrors">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Treat developer (author) warnings as errors.</string>
+ </property>
+ <property name="text">
+ <string>Developer Warnings as Errors</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="deprecatedWarningsAsErrors">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Treat deprecated warnings as errors.</string>
+ </property>
+ <property name="text">
+ <string>Deprecated Warnings as Errors</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>MessagesDialog</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>MessagesDialog</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/cmake-gui.desktop b/Source/QtDialog/cmake-gui.desktop
new file mode 100644
index 0000000..842091f
--- /dev/null
+++ b/Source/QtDialog/cmake-gui.desktop
@@ -0,0 +1,12 @@
+[Desktop Entry]
+Version=1.0
+Name=CMake
+Comment=Cross-platform buildsystem
+Exec=cmake-gui %f
+Icon=CMakeSetup
+Terminal=false
+X-MultipleArgs=false
+Type=Application
+Categories=Development;
+StartupNotify=true
+MimeType=application/x-cmakecache;
diff --git a/Source/QtDialog/cmakecache.xml b/Source/QtDialog/cmakecache.xml
new file mode 100644
index 0000000..a13b5b1
--- /dev/null
+++ b/Source/QtDialog/cmakecache.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
+ <mime-type type="application/x-cmakecache">
+ <comment>CMake cache file</comment>
+ <glob pattern="CMakeCache.txt"/>
+ <sub-class-of type="text/plain"/>
+ </mime-type>
+</mime-info>
diff --git a/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in b/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in
new file mode 100644
index 0000000..8cc5835
--- /dev/null
+++ b/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in
@@ -0,0 +1,21 @@
+// Component: CMake.Reference.DoxygenHTML
+
+function Component()
+{
+ // Default constructor
+}
+
+Component.prototype.createOperations = function()
+{
+ // Create shortcut
+ if (installer.value("os") === "win") {
+
+ component.addOperation("CreateShortcut",
+ "@TargetDir@/%CMAKE_DOC_DIR%/developer-reference/html/index.html",
+ "@StartMenuDir@/CMake Developer Reference.lnk");
+
+ }
+
+ // Call default implementation
+ component.createOperations();
+}
diff --git a/Source/QtIFW/CMake.Dialogs.QtGUI.qs.in b/Source/QtIFW/CMake.Dialogs.QtGUI.qs.in
new file mode 100644
index 0000000..71f395a
--- /dev/null
+++ b/Source/QtIFW/CMake.Dialogs.QtGUI.qs.in
@@ -0,0 +1,21 @@
+// Component: CMake.Dialogs.QtGUI
+
+function Component()
+{
+ // Default constructor
+}
+
+Component.prototype.createOperations = function()
+{
+ // Create shortcut
+ if (installer.value("os") === "win") {
+
+ component.addOperation("CreateShortcut",
+ "@TargetDir@/%CMAKE_BIN_DIR%/cmake-gui.exe",
+ "@StartMenuDir@/CMake (cmake-gui).lnk");
+
+ }
+
+ // Call default implementation
+ component.createOperations();
+}
diff --git a/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in b/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in
new file mode 100644
index 0000000..54bc14a
--- /dev/null
+++ b/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in
@@ -0,0 +1,21 @@
+// Component: CMake.Documentation.SphinxHTML
+
+function Component()
+{
+ // Default constructor
+}
+
+Component.prototype.createOperations = function()
+{
+ // Create shortcut
+ if (installer.value("os") === "win") {
+
+ component.addOperation("CreateShortcut",
+ "@TargetDir@/%CMAKE_DOC_DIR%/html/index.html",
+ "@StartMenuDir@/CMake Documentation.lnk");
+
+ }
+
+ // Call default implementation
+ component.createOperations();
+}
diff --git a/Source/QtIFW/CMake.qs.in b/Source/QtIFW/CMake.qs.in
new file mode 100644
index 0000000..1f3166e
--- /dev/null
+++ b/Source/QtIFW/CMake.qs.in
@@ -0,0 +1,24 @@
+// Component: CMake
+
+function Component()
+{
+ // Default constructor
+}
+
+Component.prototype.createOperations = function()
+{
+ // Create shortcut
+ if (installer.value("os") === "win") {
+
+ component.addOperation("CreateShortcut",
+ "@TargetDir@/%CMAKE_DOC_DIR%/cmake.org.html",
+ "@StartMenuDir@/CMake Web Site.lnk");
+
+ component.addOperation("CreateShortcut",
+ "@TargetDir@/cmake-maintenance.exe",
+ "@StartMenuDir@/CMake Maintenance Tool.lnk");
+ }
+
+ // Call default implementation
+ component.createOperations();
+}
diff --git a/Source/QtIFW/cmake.org.html b/Source/QtIFW/cmake.org.html
new file mode 100644
index 0000000..001d634
--- /dev/null
+++ b/Source/QtIFW/cmake.org.html
@@ -0,0 +1,7 @@
+<html>
+<head>
+<meta http-equiv="Refresh" content="0; url=https://cmake.org/" />
+</head>
+<body>
+</body>
+</html>
diff --git a/Source/QtIFW/controlscript.qs b/Source/QtIFW/controlscript.qs
new file mode 100644
index 0000000..d1a9b10
--- /dev/null
+++ b/Source/QtIFW/controlscript.qs
@@ -0,0 +1,6 @@
+// controlscript.qs - CMake installation control script
+
+function Controller()
+{
+ // do nothing now
+}
diff --git a/Source/QtIFW/installscript.qs.in b/Source/QtIFW/installscript.qs.in
new file mode 100644
index 0000000..72d49e8
--- /dev/null
+++ b/Source/QtIFW/installscript.qs.in
@@ -0,0 +1,27 @@
+// Component: CMake
+
+function Component()
+{
+ // Do not show component selection page
+ installer.setDefaultPageVisible(QInstaller.ComponentSelection, false);
+}
+
+Component.prototype.createOperations = function()
+{
+ // Create shortcut
+ if (installer.value("os") === "win") {
+
+%_CPACK_IFW_SHORTCUT_OPTIONAL%
+
+ component.addOperation("CreateShortcut",
+ "@TargetDir@/%CMAKE_DOC_DIR%/cmake.org.html",
+ "@StartMenuDir@/CMake Web Site.lnk");
+
+ component.addOperation("CreateShortcut",
+ "@TargetDir@/cmake-maintenance.exe",
+ "@StartMenuDir@/CMake Maintenance Tool.lnk");
+ }
+
+ // Call default implementation
+ component.createOperations();
+}
diff --git a/Source/bindexplib.cxx b/Source/bindexplib.cxx
new file mode 100644
index 0000000..0dc954a
--- /dev/null
+++ b/Source/bindexplib.cxx
@@ -0,0 +1,515 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*-------------------------------------------------------------------------
+ Portions of this source have been derived from the 'bindexplib' tool
+ provided by the CERN ROOT Data Analysis Framework project (root.cern.ch).
+ Permission has been granted by Pere Mato <pere.mato@cern.ch> to distribute
+ this derived work under the CMake license.
+-------------------------------------------------------------------------*/
+
+/*
+ *----------------------------------------------------------------------
+ * Program: dumpexts.exe
+ * Author: Gordon Chaffee
+ *
+ * History: The real functionality of this file was written by
+ * Matt Pietrek in 1993 in his pedump utility. I've
+ * modified it to dump the externals in a bunch of object
+ * files to create a .def file.
+ *
+ * Notes: Visual C++ puts an underscore before each exported symbol.
+ * This file removes them. I don't know if this is a problem
+ * this other compilers. If _MSC_VER is defined,
+ * the underscore is removed. If not, it isn't. To get a
+ * full dump of an object file, use the -f option. This can
+ * help determine the something that may be different with a
+ * compiler other than Visual C++.
+ * ======================================
+ * Corrections (Axel 2006-04-04):
+ * Conversion to C++. Mostly.
+ *
+ * Extension (Axel 2006-03-15)
+ * As soon as an object file contains an /EXPORT directive (which
+ * is generated by the compiler when a symbol is declared as
+ * __declspec(dllexport) no to-be-exported symbols are printed,
+ * as the linker will see these directives, and if those directives
+ * are present we only export selectively (i.e. we trust the
+ * programmer).
+ *
+ * ======================================
+ * ======================================
+ * Corrections (Valery Fine 23/02/98):
+ *
+ * The "(vector) deleting destructor" MUST not be exported
+ * To recognize it the following test are introduced:
+ * "@@UAEPAXI@Z" scalar deleting dtor
+ * "@@QAEPAXI@Z" vector deleting dtor
+ * "AEPAXI@Z" vector deleting dtor with thunk adjustor
+ * ======================================
+ * Corrections (Valery Fine 12/02/97):
+ *
+ * It created a wrong EXPORTS for the global pointers and constants.
+ * The Section Header has been involved to discover the missing information
+ * Now the pointers are correctly supplied with "DATA" descriptor
+ * the constants with no extra descriptor.
+ *
+ * Corrections (Valery Fine 16/09/96):
+ *
+ * It didn't work for C++ code with global variables and class definitions
+ * The DumpExternalObject function has been introduced to generate .DEF
+ *file
+ *
+ * Author: Valery Fine 16/09/96 (E-mail: fine@vxcern.cern.ch)
+ *----------------------------------------------------------------------
+ */
+#include "bindexplib.h"
+
+#include <cstddef> // IWYU pragma: keep
+#include <sstream>
+#include <vector>
+
+#ifdef _WIN32
+# include <windows.h>
+
+# include "cmsys/Encoding.hxx"
+#endif
+
+#include "cmsys/FStream.hxx"
+
+#include "cmSystemTools.h"
+
+#ifdef _WIN32
+# ifndef IMAGE_FILE_MACHINE_ARM
+# define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
+# endif
+
+# ifndef IMAGE_FILE_MACHINE_THUMB
+# define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian
+# endif
+
+# ifndef IMAGE_FILE_MACHINE_ARMNT
+# define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian
+# endif
+
+# ifndef IMAGE_FILE_MACHINE_ARM64
+# define IMAGE_FILE_MACHINE_ARM64 0xaa64 // ARM64 Little-Endian
+# endif
+
+typedef struct cmANON_OBJECT_HEADER_BIGOBJ
+{
+ /* same as ANON_OBJECT_HEADER_V2 */
+ WORD Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN
+ WORD Sig2; // Must be 0xffff
+ WORD Version; // >= 2 (implies the Flags field is present)
+ WORD Machine; // Actual machine - IMAGE_FILE_MACHINE_xxx
+ DWORD TimeDateStamp;
+ CLSID ClassID; // {D1BAA1C7-BAEE-4ba9-AF20-FAF66AA4DCB8}
+ DWORD SizeOfData; // Size of data that follows the header
+ DWORD Flags; // 0x1 -> contains metadata
+ DWORD MetaDataSize; // Size of CLR metadata
+ DWORD MetaDataOffset; // Offset of CLR metadata
+
+ /* bigobj specifics */
+ DWORD NumberOfSections; // extended from WORD
+ DWORD PointerToSymbolTable;
+ DWORD NumberOfSymbols;
+} cmANON_OBJECT_HEADER_BIGOBJ;
+
+typedef struct _cmIMAGE_SYMBOL_EX
+{
+ union
+ {
+ BYTE ShortName[8];
+ struct
+ {
+ DWORD Short; // if 0, use LongName
+ DWORD Long; // offset into string table
+ } Name;
+ DWORD LongName[2]; // PBYTE [2]
+ } N;
+ DWORD Value;
+ LONG SectionNumber;
+ WORD Type;
+ BYTE StorageClass;
+ BYTE NumberOfAuxSymbols;
+} cmIMAGE_SYMBOL_EX;
+typedef cmIMAGE_SYMBOL_EX UNALIGNED* cmPIMAGE_SYMBOL_EX;
+
+PIMAGE_SECTION_HEADER GetSectionHeaderOffset(
+ PIMAGE_FILE_HEADER pImageFileHeader)
+{
+ return (PIMAGE_SECTION_HEADER)((DWORD_PTR)pImageFileHeader +
+ IMAGE_SIZEOF_FILE_HEADER +
+ pImageFileHeader->SizeOfOptionalHeader);
+}
+
+PIMAGE_SECTION_HEADER GetSectionHeaderOffset(
+ cmANON_OBJECT_HEADER_BIGOBJ* pImageFileHeader)
+{
+ return (PIMAGE_SECTION_HEADER)((DWORD_PTR)pImageFileHeader +
+ sizeof(cmANON_OBJECT_HEADER_BIGOBJ));
+}
+
+/*
++ * Utility func, strstr with size
++ */
+const char* StrNStr(const char* start, const char* find, size_t& size)
+{
+ size_t len;
+ const char* hint;
+
+ if (!start || !find || !size) {
+ size = 0;
+ return 0;
+ }
+ len = strlen(find);
+
+ while ((hint = (const char*)memchr(start, find[0], size - len + 1))) {
+ size -= (hint - start);
+ if (!strncmp(hint, find, len))
+ return hint;
+ start = hint + 1;
+ }
+
+ size = 0;
+ return 0;
+}
+
+template <
+ // cmANON_OBJECT_HEADER_BIGOBJ or IMAGE_FILE_HEADER
+ class ObjectHeaderType,
+ // cmPIMAGE_SYMBOL_EX or PIMAGE_SYMBOL
+ class SymbolTableType>
+class DumpSymbols
+{
+public:
+ /*
+ *----------------------------------------------------------------------
+ * Constructor --
+ *
+ * Initialize variables from pointer to object header.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ DumpSymbols(ObjectHeaderType* ih, std::set<std::string>& symbols,
+ std::set<std::string>& dataSymbols, bool isI386)
+ : Symbols(symbols)
+ , DataSymbols(dataSymbols)
+ {
+ this->ObjectImageHeader = ih;
+ this->SymbolTable =
+ (SymbolTableType*)((DWORD_PTR)this->ObjectImageHeader +
+ this->ObjectImageHeader->PointerToSymbolTable);
+ this->SectionHeaders = GetSectionHeaderOffset(this->ObjectImageHeader);
+ this->SymbolCount = this->ObjectImageHeader->NumberOfSymbols;
+ this->IsI386 = isI386;
+ }
+
+ /*
+ *----------------------------------------------------------------------
+ * DumpObjFile --
+ *
+ * Dump an object file's exported symbols.
+ *----------------------------------------------------------------------
+ */
+ void DumpObjFile() { this->DumpExternalsObjects(); }
+
+ /*
+ *----------------------------------------------------------------------
+ * DumpExternalsObjects --
+ *
+ * Dumps a COFF symbol table from an OBJ.
+ *----------------------------------------------------------------------
+ */
+ void DumpExternalsObjects()
+ {
+ unsigned i;
+ PSTR stringTable;
+ std::string symbol;
+ DWORD SectChar;
+ /*
+ * The string table apparently starts right after the symbol table
+ */
+ stringTable = (PSTR) & this->SymbolTable[this->SymbolCount];
+ SymbolTableType* pSymbolTable = this->SymbolTable;
+ for (i = 0; i < this->SymbolCount; i++) {
+ if (pSymbolTable->SectionNumber > 0 &&
+ (pSymbolTable->Type == 0x20 || pSymbolTable->Type == 0x0)) {
+ if (pSymbolTable->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) {
+ /*
+ * The name of the Function entry points
+ */
+ if (pSymbolTable->N.Name.Short != 0) {
+ symbol.clear();
+ symbol.insert(0, (const char*)pSymbolTable->N.ShortName, 8);
+ } else {
+ symbol = stringTable + pSymbolTable->N.Name.Long;
+ }
+
+ // clear out any leading spaces
+ while (isspace(symbol[0]))
+ symbol.erase(0, 1);
+ // if it starts with _ and has an @ then it is a __cdecl
+ // so remove the @ stuff for the export
+ if (symbol[0] == '_') {
+ std::string::size_type posAt = symbol.find('@');
+ if (posAt != std::string::npos) {
+ symbol.erase(posAt);
+ }
+ }
+ // For i386 builds we need to remove _
+ if (this->IsI386 && symbol[0] == '_') {
+ symbol.erase(0, 1);
+ }
+
+ // Check whether it is "Scalar deleting destructor" and "Vector
+ // deleting destructor"
+ // if scalarPrefix and vectorPrefix are not found then print
+ // the symbol
+ const char* scalarPrefix = "??_G";
+ const char* vectorPrefix = "??_E";
+ // The original code had a check for
+ // symbol.find("real@") == std::string::npos)
+ // but this disallows member functions with the name "real".
+ if (symbol.compare(0, 4, scalarPrefix) &&
+ symbol.compare(0, 4, vectorPrefix)) {
+ SectChar = this->SectionHeaders[pSymbolTable->SectionNumber - 1]
+ .Characteristics;
+ // skip symbols containing a dot or are from managed code
+ if (symbol.find('.') == std::string::npos &&
+ !SymbolIsFromManagedCode(symbol)) {
+ if (!pSymbolTable->Type && (SectChar & IMAGE_SCN_MEM_WRITE)) {
+ // Read only (i.e. constants) must be excluded
+ this->DataSymbols.insert(symbol);
+ } else {
+ if (pSymbolTable->Type || !(SectChar & IMAGE_SCN_MEM_READ) ||
+ (SectChar & IMAGE_SCN_MEM_EXECUTE)) {
+ this->Symbols.insert(symbol);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Take into account any aux symbols
+ */
+ i += pSymbolTable->NumberOfAuxSymbols;
+ pSymbolTable += pSymbolTable->NumberOfAuxSymbols;
+ pSymbolTable++;
+ }
+ }
+
+private:
+ bool SymbolIsFromManagedCode(std::string const& symbol)
+ {
+ return symbol == "__t2m" || symbol == "__m2mep" || symbol == "__mep" ||
+ symbol.find("$$F") != std::string::npos ||
+ symbol.find("$$J") != std::string::npos;
+ }
+
+ std::set<std::string>& Symbols;
+ std::set<std::string>& DataSymbols;
+ DWORD_PTR SymbolCount;
+ PIMAGE_SECTION_HEADER SectionHeaders;
+ ObjectHeaderType* ObjectImageHeader;
+ SymbolTableType* SymbolTable;
+ bool IsI386;
+};
+#endif
+
+bool DumpFileWithLlvmNm(std::string const& nmPath, const char* filename,
+ std::set<std::string>& symbols,
+ std::set<std::string>& dataSymbols)
+{
+ std::string output;
+ // break up command line into a vector
+ std::vector<std::string> command;
+ command.push_back(nmPath);
+ command.emplace_back("--no-weak");
+ command.emplace_back("--defined-only");
+ command.emplace_back("--format=posix");
+ command.emplace_back(filename);
+
+ // run the command
+ int exit_code = 0;
+ cmSystemTools::RunSingleCommand(command, &output, &output, &exit_code,
+ nullptr, cmSystemTools::OUTPUT_NONE);
+
+ if (exit_code != 0) {
+ fprintf(stderr, "llvm-nm returned an error: %s\n", output.c_str());
+ return false;
+ }
+
+ std::istringstream ss(output);
+ std::string line;
+ while (std::getline(ss, line)) {
+ if (line.empty()) { // last line
+ continue;
+ }
+ size_t sym_end = line.find(' ');
+ if (sym_end == std::string::npos) {
+ fprintf(stderr, "Couldn't parse llvm-nm output line: %s\n",
+ line.c_str());
+ return false;
+ }
+ if (line.size() < sym_end + 1) {
+ fprintf(stderr, "Couldn't parse llvm-nm output line: %s\n",
+ line.c_str());
+ return false;
+ }
+ const char sym_type = line[sym_end + 1];
+ line.resize(sym_end);
+ switch (sym_type) {
+ case 'D':
+ dataSymbols.insert(line);
+ break;
+ case 'T':
+ symbols.insert(line);
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool DumpFile(std::string const& nmPath, const char* filename,
+ std::set<std::string>& symbols,
+ std::set<std::string>& dataSymbols)
+{
+#ifndef _WIN32
+ return DumpFileWithLlvmNm(nmPath, filename, symbols, dataSymbols);
+#else
+ HANDLE hFile;
+ HANDLE hFileMapping;
+ LPVOID lpFileBase;
+
+ hFile = CreateFileW(cmsys::Encoding::ToWide(filename).c_str(), GENERIC_READ,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, 0);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "Couldn't open file '%s' with CreateFile()\n", filename);
+ return false;
+ }
+
+ hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (hFileMapping == 0) {
+ CloseHandle(hFile);
+ fprintf(stderr, "Couldn't open file mapping with CreateFileMapping()\n");
+ return false;
+ }
+
+ lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
+ if (lpFileBase == 0) {
+ CloseHandle(hFileMapping);
+ CloseHandle(hFile);
+ fprintf(stderr, "Couldn't map view of file with MapViewOfFile()\n");
+ return false;
+ }
+
+ const PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)lpFileBase;
+ if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) {
+ fprintf(stderr, "File is an executable. I don't dump those.\n");
+ return false;
+ } else {
+ const PIMAGE_FILE_HEADER imageHeader = (PIMAGE_FILE_HEADER)lpFileBase;
+ /* Does it look like a COFF OBJ file??? */
+ if (((imageHeader->Machine == IMAGE_FILE_MACHINE_I386) ||
+ (imageHeader->Machine == IMAGE_FILE_MACHINE_AMD64) ||
+ (imageHeader->Machine == IMAGE_FILE_MACHINE_ARM) ||
+ (imageHeader->Machine == IMAGE_FILE_MACHINE_ARMNT) ||
+ (imageHeader->Machine == IMAGE_FILE_MACHINE_ARM64)) &&
+ (imageHeader->Characteristics == 0)) {
+ /*
+ * The tests above are checking for IMAGE_FILE_HEADER.Machine
+ * if it contains supported machine formats (currently ARM and x86)
+ * and IMAGE_FILE_HEADER.Characteristics == 0 indicating that
+ * this is not linked COFF OBJ file;
+ */
+ DumpSymbols<IMAGE_FILE_HEADER, IMAGE_SYMBOL> symbolDumper(
+ (PIMAGE_FILE_HEADER)lpFileBase, symbols, dataSymbols,
+ (imageHeader->Machine == IMAGE_FILE_MACHINE_I386));
+ symbolDumper.DumpObjFile();
+ } else {
+ // check for /bigobj and llvm LTO format
+ cmANON_OBJECT_HEADER_BIGOBJ* h =
+ (cmANON_OBJECT_HEADER_BIGOBJ*)lpFileBase;
+ if (h->Sig1 == 0x0 && h->Sig2 == 0xffff) {
+ // bigobj
+ DumpSymbols<cmANON_OBJECT_HEADER_BIGOBJ, cmIMAGE_SYMBOL_EX>
+ symbolDumper((cmANON_OBJECT_HEADER_BIGOBJ*)lpFileBase, symbols,
+ dataSymbols, (h->Machine == IMAGE_FILE_MACHINE_I386));
+ symbolDumper.DumpObjFile();
+ } else if (
+ // BCexCODE - llvm bitcode
+ (h->Sig1 == 0x4342 && h->Sig2 == 0xDEC0) ||
+ // 0x0B17C0DE - llvm bitcode BC wrapper
+ (h->Sig1 == 0x0B17 && h->Sig2 == 0xC0DE)) {
+
+ return DumpFileWithLlvmNm(nmPath, filename, symbols, dataSymbols);
+
+ } else {
+ printf("unrecognized file format in '%s, %u'\n", filename,
+ imageHeader->Machine);
+ return false;
+ }
+ }
+ }
+ UnmapViewOfFile(lpFileBase);
+ CloseHandle(hFileMapping);
+ CloseHandle(hFile);
+ return true;
+#endif
+}
+
+bool bindexplib::AddObjectFile(const char* filename)
+{
+ return DumpFile(this->NmPath, filename, this->Symbols, this->DataSymbols);
+}
+
+bool bindexplib::AddDefinitionFile(const char* filename)
+{
+ cmsys::ifstream infile(filename);
+ if (!infile) {
+ fprintf(stderr, "Couldn't open definition file '%s'\n", filename);
+ return false;
+ }
+ std::string str;
+ while (std::getline(infile, str)) {
+ // skip the LIBRARY and EXPORTS lines (if any)
+ if ((str.compare(0, 7, "LIBRARY") == 0) ||
+ (str.compare(0, 7, "EXPORTS") == 0)) {
+ continue;
+ }
+ // remove leading tabs & spaces
+ str.erase(0, str.find_first_not_of(" \t"));
+ std::size_t found = str.find(" \t DATA");
+ if (found != std::string::npos) {
+ str.erase(found, std::string::npos);
+ this->DataSymbols.insert(str);
+ } else {
+ this->Symbols.insert(str);
+ }
+ }
+ infile.close();
+ return true;
+}
+
+void bindexplib::WriteFile(FILE* file)
+{
+ fprintf(file, "EXPORTS \n");
+ for (std::string const& ds : this->DataSymbols) {
+ fprintf(file, "\t%s \t DATA\n", ds.c_str());
+ }
+ for (std::string const& s : this->Symbols) {
+ fprintf(file, "\t%s\n", s.c_str());
+ }
+}
+
+void bindexplib::SetNmPath(std::string const& nm)
+{
+ this->NmPath = nm;
+}
diff --git a/Source/bindexplib.h b/Source/bindexplib.h
new file mode 100644
index 0000000..bd1398f
--- /dev/null
+++ b/Source/bindexplib.h
@@ -0,0 +1,26 @@
+/* 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 <stdio.h>
+
+class bindexplib
+{
+public:
+ bindexplib() { NmPath = "nm"; }
+ bool AddDefinitionFile(const char* filename);
+ bool AddObjectFile(const char* filename);
+ void WriteFile(FILE* file);
+
+ void SetNmPath(std::string const& nm);
+
+private:
+ std::set<std::string> Symbols;
+ std::set<std::string> DataSymbols;
+ std::string NmPath;
+};
diff --git a/Source/cmAddCompileDefinitionsCommand.cxx b/Source/cmAddCompileDefinitionsCommand.cxx
new file mode 100644
index 0000000..b00a4a7
--- /dev/null
+++ b/Source/cmAddCompileDefinitionsCommand.cxx
@@ -0,0 +1,16 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmAddCompileDefinitionsCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+
+bool cmAddCompileDefinitionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ cmMakefile& mf = status.GetMakefile();
+ for (std::string const& i : args) {
+ mf.AddCompileDefinition(i);
+ }
+ return true;
+}
diff --git a/Source/cmAddCompileDefinitionsCommand.h b/Source/cmAddCompileDefinitionsCommand.h
new file mode 100644
index 0000000..29282d6
--- /dev/null
+++ b/Source/cmAddCompileDefinitionsCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmAddCompileDefinitionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmAddCompileOptionsCommand.cxx b/Source/cmAddCompileOptionsCommand.cxx
new file mode 100644
index 0000000..8ccb512
--- /dev/null
+++ b/Source/cmAddCompileOptionsCommand.cxx
@@ -0,0 +1,16 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmAddCompileOptionsCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+
+bool cmAddCompileOptionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ cmMakefile& mf = status.GetMakefile();
+ for (std::string const& i : args) {
+ mf.AddCompileOption(i);
+ }
+ return true;
+}
diff --git a/Source/cmAddCompileOptionsCommand.h b/Source/cmAddCompileOptionsCommand.h
new file mode 100644
index 0000000..076a427
--- /dev/null
+++ b/Source/cmAddCompileOptionsCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmAddCompileOptionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
new file mode 100644
index 0000000..a7ce3a6
--- /dev/null
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -0,0 +1,374 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmAddCustomCommandCommand.h"
+
+#include <sstream>
+#include <unordered_set>
+
+#include "cmCustomCommand.h"
+#include "cmCustomCommandLines.h"
+#include "cmCustomCommandTypes.h"
+#include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ /* Let's complain at the end of this function about the lack of a particular
+ arg. For the moment, let's say that COMMAND, and either TARGET or SOURCE
+ are required.
+ */
+ if (args.size() < 4) {
+ status.SetError("called with wrong number of arguments.");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ std::string source;
+ std::string target;
+ std::string main_dependency;
+ std::string working;
+ std::string depfile;
+ std::string job_pool;
+ std::string comment_buffer;
+ const char* comment = nullptr;
+ std::vector<std::string> depends;
+ std::vector<std::string> outputs;
+ std::vector<std::string> output;
+ std::vector<std::string> byproducts;
+ bool verbatim = false;
+ bool append = false;
+ bool uses_terminal = false;
+ bool command_expand_lists = false;
+ std::string implicit_depends_lang;
+ cmImplicitDependsList implicit_depends;
+
+ // Accumulate one command line at a time.
+ cmCustomCommandLine currentLine;
+
+ // Save all command lines.
+ cmCustomCommandLines commandLines;
+
+ cmCustomCommandType cctype = cmCustomCommandType::POST_BUILD;
+
+ enum tdoing
+ {
+ doing_source,
+ doing_command,
+ doing_target,
+ doing_depends,
+ doing_implicit_depends_lang,
+ doing_implicit_depends_file,
+ doing_main_dependency,
+ doing_output,
+ doing_outputs,
+ doing_byproducts,
+ doing_comment,
+ doing_working_directory,
+ doing_depfile,
+ doing_job_pool,
+ doing_nothing
+ };
+
+ tdoing doing = doing_nothing;
+
+#define MAKE_STATIC_KEYWORD(KEYWORD) \
+ static const std::string key##KEYWORD = #KEYWORD
+ MAKE_STATIC_KEYWORD(APPEND);
+ MAKE_STATIC_KEYWORD(ARGS);
+ MAKE_STATIC_KEYWORD(BYPRODUCTS);
+ MAKE_STATIC_KEYWORD(COMMAND);
+ MAKE_STATIC_KEYWORD(COMMAND_EXPAND_LISTS);
+ MAKE_STATIC_KEYWORD(COMMENT);
+ MAKE_STATIC_KEYWORD(DEPENDS);
+ MAKE_STATIC_KEYWORD(DEPFILE);
+ MAKE_STATIC_KEYWORD(IMPLICIT_DEPENDS);
+ MAKE_STATIC_KEYWORD(JOB_POOL);
+ MAKE_STATIC_KEYWORD(MAIN_DEPENDENCY);
+ MAKE_STATIC_KEYWORD(OUTPUT);
+ MAKE_STATIC_KEYWORD(OUTPUTS);
+ MAKE_STATIC_KEYWORD(POST_BUILD);
+ MAKE_STATIC_KEYWORD(PRE_BUILD);
+ MAKE_STATIC_KEYWORD(PRE_LINK);
+ MAKE_STATIC_KEYWORD(SOURCE);
+ MAKE_STATIC_KEYWORD(TARGET);
+ MAKE_STATIC_KEYWORD(USES_TERMINAL);
+ MAKE_STATIC_KEYWORD(VERBATIM);
+ MAKE_STATIC_KEYWORD(WORKING_DIRECTORY);
+#undef MAKE_STATIC_KEYWORD
+ static std::unordered_set<std::string> const keywords{
+ keyAPPEND,
+ keyARGS,
+ keyBYPRODUCTS,
+ keyCOMMAND,
+ keyCOMMAND_EXPAND_LISTS,
+ keyCOMMENT,
+ keyDEPENDS,
+ keyDEPFILE,
+ keyIMPLICIT_DEPENDS,
+ keyJOB_POOL,
+ keyMAIN_DEPENDENCY,
+ keyOUTPUT,
+ keyOUTPUTS,
+ keyPOST_BUILD,
+ keyPRE_BUILD,
+ keyPRE_LINK,
+ keySOURCE,
+ keyTARGET,
+ keyUSES_TERMINAL,
+ keyVERBATIM,
+ keyWORKING_DIRECTORY
+ };
+
+ for (std::string const& copy : args) {
+ if (keywords.count(copy)) {
+ if (copy == keySOURCE) {
+ doing = doing_source;
+ } else if (copy == keyCOMMAND) {
+ doing = doing_command;
+
+ // Save the current command before starting the next command.
+ if (!currentLine.empty()) {
+ commandLines.push_back(currentLine);
+ currentLine.clear();
+ }
+ } else if (copy == keyPRE_BUILD) {
+ cctype = cmCustomCommandType::PRE_BUILD;
+ } else if (copy == keyPRE_LINK) {
+ cctype = cmCustomCommandType::PRE_LINK;
+ } else if (copy == keyPOST_BUILD) {
+ cctype = cmCustomCommandType::POST_BUILD;
+ } else if (copy == keyVERBATIM) {
+ verbatim = true;
+ } else if (copy == keyAPPEND) {
+ append = true;
+ } else if (copy == keyUSES_TERMINAL) {
+ uses_terminal = true;
+ } else if (copy == keyCOMMAND_EXPAND_LISTS) {
+ command_expand_lists = true;
+ } else if (copy == keyTARGET) {
+ doing = doing_target;
+ } else if (copy == keyARGS) {
+ // Ignore this old keyword.
+ } else if (copy == keyDEPENDS) {
+ doing = doing_depends;
+ } else if (copy == keyOUTPUTS) {
+ doing = doing_outputs;
+ } else if (copy == keyOUTPUT) {
+ doing = doing_output;
+ } else if (copy == keyBYPRODUCTS) {
+ doing = doing_byproducts;
+ } else if (copy == keyWORKING_DIRECTORY) {
+ doing = doing_working_directory;
+ } else if (copy == keyMAIN_DEPENDENCY) {
+ doing = doing_main_dependency;
+ } else if (copy == keyIMPLICIT_DEPENDS) {
+ doing = doing_implicit_depends_lang;
+ } else if (copy == keyCOMMENT) {
+ doing = doing_comment;
+ } else if (copy == keyDEPFILE) {
+ doing = doing_depfile;
+ if (!mf.GetGlobalGenerator()->SupportsCustomCommandDepfile()) {
+ status.SetError("Option DEPFILE not supported by " +
+ mf.GetGlobalGenerator()->GetName());
+ return false;
+ }
+ } else if (copy == keyJOB_POOL) {
+ doing = doing_job_pool;
+ }
+ } else {
+ std::string filename;
+ switch (doing) {
+ case doing_output:
+ case doing_outputs:
+ case doing_byproducts:
+ if (!cmSystemTools::FileIsFullPath(copy) &&
+ cmGeneratorExpression::Find(copy) != 0) {
+ // This is an output to be generated, so it should be
+ // under the build tree.
+ filename = cmStrCat(mf.GetCurrentBinaryDirectory(), '/');
+ }
+ filename += copy;
+ cmSystemTools::ConvertToUnixSlashes(filename);
+ break;
+ case doing_source:
+ // We do not want to convert the argument to SOURCE because
+ // that option is only available for backward compatibility.
+ // Old-style use of this command may use the SOURCE==TARGET
+ // trick which we must preserve. If we convert the source
+ // to a full path then it will no longer equal the target.
+ default:
+ break;
+ }
+
+ if (cmSystemTools::FileIsFullPath(filename)) {
+ filename = cmSystemTools::CollapseFullPath(filename);
+ }
+ switch (doing) {
+ case doing_depfile:
+ depfile = copy;
+ break;
+ case doing_job_pool:
+ job_pool = copy;
+ break;
+ case doing_working_directory:
+ working = copy;
+ break;
+ case doing_source:
+ source = copy;
+ break;
+ case doing_output:
+ output.push_back(filename);
+ break;
+ case doing_main_dependency:
+ main_dependency = copy;
+ break;
+ case doing_implicit_depends_lang:
+ implicit_depends_lang = copy;
+ doing = doing_implicit_depends_file;
+ break;
+ case doing_implicit_depends_file: {
+ // An implicit dependency starting point is also an
+ // explicit dependency.
+ std::string dep = copy;
+ // Upfront path conversion is correct because Genex
+ // are not supported.
+ cmSystemTools::ConvertToUnixSlashes(dep);
+ depends.push_back(dep);
+
+ // Add the implicit dependency language and file.
+ implicit_depends.emplace_back(implicit_depends_lang, dep);
+
+ // Switch back to looking for a language.
+ doing = doing_implicit_depends_lang;
+ } break;
+ case doing_command:
+ currentLine.push_back(copy);
+ break;
+ case doing_target:
+ target = copy;
+ break;
+ case doing_depends:
+ depends.push_back(copy);
+ break;
+ case doing_outputs:
+ outputs.push_back(filename);
+ break;
+ case doing_byproducts:
+ byproducts.push_back(filename);
+ break;
+ case doing_comment:
+ comment_buffer = copy;
+ comment = comment_buffer.c_str();
+ break;
+ default:
+ status.SetError("Wrong syntax. Unknown type of argument.");
+ return false;
+ }
+ }
+ }
+
+ // Store the last command line finished.
+ if (!currentLine.empty()) {
+ commandLines.push_back(currentLine);
+ currentLine.clear();
+ }
+
+ // At this point we could complain about the lack of arguments. For
+ // the moment, let's say that COMMAND, TARGET are always required.
+ if (output.empty() && target.empty()) {
+ status.SetError("Wrong syntax. A TARGET or OUTPUT must be specified.");
+ return false;
+ }
+
+ if (source.empty() && !target.empty() && !output.empty()) {
+ status.SetError(
+ "Wrong syntax. A TARGET and OUTPUT can not both be specified.");
+ return false;
+ }
+ if (append && output.empty()) {
+ status.SetError("given APPEND option with no OUTPUT.");
+ return false;
+ }
+ if (!implicit_depends.empty() && !depfile.empty() &&
+ mf.GetGlobalGenerator()->GetName() != "Ninja") {
+ // Makefiles generators does not support both at the same time
+ status.SetError("IMPLICIT_DEPENDS and DEPFILE can not both be specified.");
+ return false;
+ }
+
+ // Check for an append request.
+ if (append) {
+ mf.AppendCustomCommandToOutput(output[0], depends, implicit_depends,
+ commandLines);
+ return true;
+ }
+
+ if (uses_terminal && !job_pool.empty()) {
+ status.SetError("JOB_POOL is shadowed by USES_TERMINAL.");
+ return false;
+ }
+
+ // Choose which mode of the command to use.
+ bool escapeOldStyle = !verbatim;
+ if (source.empty() && output.empty()) {
+ // Source is empty, use the target.
+ std::vector<std::string> no_depends;
+ mf.AddCustomCommandToTarget(
+ target, byproducts, no_depends, commandLines, cctype, comment,
+ working.c_str(), mf.GetPolicyStatus(cmPolicies::CMP0116), escapeOldStyle,
+ uses_terminal, depfile, job_pool, command_expand_lists);
+ } else if (target.empty()) {
+ // Target is empty, use the output.
+ mf.AddCustomCommandToOutput(
+ output, byproducts, depends, main_dependency, implicit_depends,
+ commandLines, comment, working.c_str(),
+ mf.GetPolicyStatus(cmPolicies::CMP0116), nullptr, false, escapeOldStyle,
+ uses_terminal, command_expand_lists, depfile, job_pool);
+ } else if (!byproducts.empty()) {
+ status.SetError("BYPRODUCTS may not be specified with SOURCE signatures");
+ return false;
+ } else if (uses_terminal) {
+ status.SetError("USES_TERMINAL may not be used with SOURCE signatures");
+ return false;
+ } else {
+ bool issueMessage = true;
+ std::ostringstream e;
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+ switch (mf.GetPolicyStatus(cmPolicies::CMP0050)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0050) << "\n";
+ break;
+ case cmPolicies::OLD:
+ issueMessage = false;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ messageType = MessageType::FATAL_ERROR;
+ break;
+ }
+
+ if (issueMessage) {
+ e << "The SOURCE signatures of add_custom_command are no longer "
+ "supported.";
+ mf.IssueMessage(messageType, e.str());
+ if (messageType == MessageType::FATAL_ERROR) {
+ return false;
+ }
+ }
+
+ // Use the old-style mode for backward compatibility.
+ mf.AddCustomCommandOldStyle(target, outputs, depends, source, commandLines,
+ comment,
+ mf.GetPolicyStatus(cmPolicies::CMP0116));
+ }
+
+ return true;
+}
diff --git a/Source/cmAddCustomCommandCommand.h b/Source/cmAddCustomCommandCommand.h
new file mode 100644
index 0000000..383d116
--- /dev/null
+++ b/Source/cmAddCustomCommandCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx
new file mode 100644
index 0000000..2b19aad
--- /dev/null
+++ b/Source/cmAddCustomTargetCommand.cxx
@@ -0,0 +1,224 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmAddCustomTargetCommand.h"
+
+#include <utility>
+
+#include "cmCustomCommandLines.h"
+#include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+
+bool cmAddCustomTargetCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ std::string const& targetName = args[0];
+
+ // Check the target name.
+ if (targetName.find_first_of("/\\") != std::string::npos) {
+ status.SetError(cmStrCat("called with invalid target name \"", targetName,
+ "\". Target names may not contain a slash. "
+ "Use ADD_CUSTOM_COMMAND to generate files."));
+ return false;
+ }
+
+ // Accumulate one command line at a time.
+ cmCustomCommandLine currentLine;
+
+ // Save all command lines.
+ cmCustomCommandLines commandLines;
+
+ // Accumulate dependencies.
+ std::vector<std::string> depends;
+ std::vector<std::string> byproducts;
+ std::string working_directory;
+ bool verbatim = false;
+ bool uses_terminal = false;
+ bool command_expand_lists = false;
+ std::string comment_buffer;
+ const char* comment = nullptr;
+ std::vector<std::string> sources;
+ std::string job_pool;
+
+ // Keep track of parser state.
+ enum tdoing
+ {
+ doing_command,
+ doing_depends,
+ doing_byproducts,
+ doing_working_directory,
+ doing_comment,
+ doing_source,
+ doing_job_pool,
+ doing_nothing
+ };
+ tdoing doing = doing_command;
+
+ // Look for the ALL option.
+ bool excludeFromAll = true;
+ unsigned int start = 1;
+ if (args.size() > 1) {
+ if (args[1] == "ALL") {
+ excludeFromAll = false;
+ start = 2;
+ }
+ }
+
+ // Parse the rest of the arguments.
+ for (unsigned int j = start; j < args.size(); ++j) {
+ std::string const& copy = args[j];
+
+ if (copy == "DEPENDS") {
+ doing = doing_depends;
+ } else if (copy == "BYPRODUCTS") {
+ doing = doing_byproducts;
+ } else if (copy == "WORKING_DIRECTORY") {
+ doing = doing_working_directory;
+ } else if (copy == "VERBATIM") {
+ doing = doing_nothing;
+ verbatim = true;
+ } else if (copy == "USES_TERMINAL") {
+ doing = doing_nothing;
+ uses_terminal = true;
+ } else if (copy == "COMMAND_EXPAND_LISTS") {
+ doing = doing_nothing;
+ command_expand_lists = true;
+ } else if (copy == "COMMENT") {
+ doing = doing_comment;
+ } else if (copy == "JOB_POOL") {
+ doing = doing_job_pool;
+ } else if (copy == "COMMAND") {
+ doing = doing_command;
+
+ // Save the current command before starting the next command.
+ if (!currentLine.empty()) {
+ commandLines.push_back(currentLine);
+ currentLine.clear();
+ }
+ } else if (copy == "SOURCES") {
+ doing = doing_source;
+ } else {
+ switch (doing) {
+ case doing_working_directory:
+ working_directory = copy;
+ break;
+ case doing_command:
+ currentLine.push_back(copy);
+ break;
+ case doing_byproducts: {
+ std::string filename;
+ if (!cmSystemTools::FileIsFullPath(copy) &&
+ cmGeneratorExpression::Find(copy) != 0) {
+ filename = cmStrCat(mf.GetCurrentBinaryDirectory(), '/');
+ }
+ filename += copy;
+ cmSystemTools::ConvertToUnixSlashes(filename);
+ if (cmSystemTools::FileIsFullPath(filename)) {
+ filename = cmSystemTools::CollapseFullPath(filename);
+ }
+ byproducts.push_back(filename);
+ } break;
+ case doing_depends: {
+ std::string dep = copy;
+ cmSystemTools::ConvertToUnixSlashes(dep);
+ depends.push_back(std::move(dep));
+ } break;
+ case doing_comment:
+ comment_buffer = copy;
+ comment = comment_buffer.c_str();
+ break;
+ case doing_source:
+ sources.push_back(copy);
+ break;
+ case doing_job_pool:
+ job_pool = copy;
+ break;
+ default:
+ status.SetError("Wrong syntax. Unknown type of argument.");
+ return false;
+ }
+ }
+ }
+
+ std::string::size_type pos = targetName.find_first_of("#<>");
+ if (pos != std::string::npos) {
+ status.SetError(cmStrCat("called with target name containing a \"",
+ targetName[pos],
+ "\". This character is not allowed."));
+ return false;
+ }
+
+ // Some requirements on custom target names already exist
+ // and have been checked at this point.
+ // The following restrictions overlap but depend on policy CMP0037.
+ bool nameOk = cmGeneratorExpression::IsValidTargetName(targetName) &&
+ !cmGlobalGenerator::IsReservedTarget(targetName);
+ if (nameOk) {
+ nameOk = targetName.find(':') == std::string::npos;
+ }
+ if (!nameOk && !mf.CheckCMP0037(targetName, cmStateEnums::UTILITY)) {
+ return false;
+ }
+
+ // Store the last command line finished.
+ if (!currentLine.empty()) {
+ commandLines.push_back(currentLine);
+ currentLine.clear();
+ }
+
+ // Enforce name uniqueness.
+ {
+ std::string msg;
+ if (!mf.EnforceUniqueName(targetName, msg, true)) {
+ status.SetError(msg);
+ return false;
+ }
+ }
+
+ if (commandLines.empty() && !byproducts.empty()) {
+ mf.IssueMessage(MessageType::FATAL_ERROR,
+ "BYPRODUCTS may not be specified without any COMMAND");
+ return true;
+ }
+ if (commandLines.empty() && uses_terminal) {
+ mf.IssueMessage(MessageType::FATAL_ERROR,
+ "USES_TERMINAL may not be specified without any COMMAND");
+ return true;
+ }
+ if (commandLines.empty() && command_expand_lists) {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "COMMAND_EXPAND_LISTS may not be specified without any COMMAND");
+ return true;
+ }
+
+ if (uses_terminal && !job_pool.empty()) {
+ status.SetError("JOB_POOL is shadowed by USES_TERMINAL.");
+ return false;
+ }
+
+ // Add the utility target to the makefile.
+ bool escapeOldStyle = !verbatim;
+ cmTarget* target = mf.AddUtilityCommand(
+ targetName, excludeFromAll, working_directory.c_str(), byproducts, depends,
+ commandLines, mf.GetPolicyStatus(cmPolicies::CMP0116), escapeOldStyle,
+ comment, uses_terminal, command_expand_lists, job_pool);
+
+ // Add additional user-specified source files to the target.
+ target->AddSources(sources);
+
+ return true;
+}
diff --git a/Source/cmAddCustomTargetCommand.h b/Source/cmAddCustomTargetCommand.h
new file mode 100644
index 0000000..3b784cb
--- /dev/null
+++ b/Source/cmAddCustomTargetCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmAddCustomTargetCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmAddDefinitionsCommand.cxx b/Source/cmAddDefinitionsCommand.cxx
new file mode 100644
index 0000000..0b10aee
--- /dev/null
+++ b/Source/cmAddDefinitionsCommand.cxx
@@ -0,0 +1,16 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmAddDefinitionsCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+
+bool cmAddDefinitionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ cmMakefile& mf = status.GetMakefile();
+ for (std::string const& i : args) {
+ mf.AddDefineFlag(i);
+ }
+ return true;
+}
diff --git a/Source/cmAddDefinitionsCommand.h b/Source/cmAddDefinitionsCommand.h
new file mode 100644
index 0000000..45b4554
--- /dev/null
+++ b/Source/cmAddDefinitionsCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmAddDefinitionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmAddDependenciesCommand.cxx b/Source/cmAddDependenciesCommand.cxx
new file mode 100644
index 0000000..2d55a5a
--- /dev/null
+++ b/Source/cmAddDependenciesCommand.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 "cmAddDependenciesCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmTarget.h"
+
+bool cmAddDependenciesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ std::string const& target_name = args[0];
+ if (mf.IsAlias(target_name)) {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Cannot add target-level dependencies to alias target \"",
+ target_name, "\".\n"));
+ }
+ if (cmTarget* target = mf.FindTargetToUse(target_name)) {
+
+ // skip over target_name
+ for (std::string const& arg : cmMakeRange(args).advance(1)) {
+ target->AddUtility(arg, false, &mf);
+ }
+ } else {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(
+ "Cannot add target-level dependencies to non-existent "
+ "target \"",
+ target_name,
+ "\".\nThe add_dependencies works for "
+ "top-level logical targets created by the add_executable, "
+ "add_library, or add_custom_target commands. If you want to add "
+ "file-level dependencies see the DEPENDS option of the "
+ "add_custom_target and add_custom_command commands."));
+ }
+
+ return true;
+}
diff --git a/Source/cmAddDependenciesCommand.h b/Source/cmAddDependenciesCommand.h
new file mode 100644
index 0000000..a767550
--- /dev/null
+++ b/Source/cmAddDependenciesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmAddDependenciesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmAddExecutableCommand.cxx b/Source/cmAddExecutableCommand.cxx
new file mode 100644
index 0000000..9dd8a19
--- /dev/null
+++ b/Source/cmAddExecutableCommand.cxx
@@ -0,0 +1,160 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmAddExecutableCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmTarget.h"
+
+bool cmAddExecutableCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ auto s = args.begin();
+
+ std::string const& exename = *s;
+
+ ++s;
+ bool use_win32 = false;
+ bool use_macbundle = false;
+ bool excludeFromAll = false;
+ bool importTarget = false;
+ bool importGlobal = false;
+ bool isAlias = false;
+ while (s != args.end()) {
+ if (*s == "WIN32") {
+ ++s;
+ use_win32 = true;
+ } else if (*s == "MACOSX_BUNDLE") {
+ ++s;
+ use_macbundle = true;
+ } else if (*s == "EXCLUDE_FROM_ALL") {
+ ++s;
+ excludeFromAll = true;
+ } else if (*s == "IMPORTED") {
+ ++s;
+ importTarget = true;
+ } else if (importTarget && *s == "GLOBAL") {
+ ++s;
+ importGlobal = true;
+ } else if (*s == "ALIAS") {
+ ++s;
+ isAlias = true;
+ } else {
+ break;
+ }
+ }
+
+ bool nameOk = cmGeneratorExpression::IsValidTargetName(exename) &&
+ !cmGlobalGenerator::IsReservedTarget(exename);
+
+ if (nameOk && !importTarget && !isAlias) {
+ nameOk = exename.find(':') == std::string::npos;
+ }
+ if (!nameOk && !mf.CheckCMP0037(exename, cmStateEnums::EXECUTABLE)) {
+ return false;
+ }
+
+ // Special modifiers are not allowed with IMPORTED signature.
+ if (importTarget && (use_win32 || use_macbundle || excludeFromAll)) {
+ if (use_win32) {
+ status.SetError("may not be given WIN32 for an IMPORTED target.");
+ } else if (use_macbundle) {
+ status.SetError(
+ "may not be given MACOSX_BUNDLE for an IMPORTED target.");
+ } else // if(excludeFromAll)
+ {
+ status.SetError(
+ "may not be given EXCLUDE_FROM_ALL for an IMPORTED target.");
+ }
+ return false;
+ }
+ if (isAlias) {
+ if (!cmGeneratorExpression::IsValidTargetName(exename)) {
+ status.SetError("Invalid name for ALIAS: " + exename);
+ return false;
+ }
+ if (excludeFromAll) {
+ status.SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense.");
+ return false;
+ }
+ if (importTarget || importGlobal) {
+ status.SetError("IMPORTED with ALIAS is not allowed.");
+ return false;
+ }
+ if (args.size() != 3) {
+ status.SetError("ALIAS requires exactly one target argument.");
+ return false;
+ }
+
+ std::string const& aliasedName = *s;
+ if (mf.IsAlias(aliasedName)) {
+ status.SetError(cmStrCat("cannot create ALIAS target \"", exename,
+ "\" because target \"", aliasedName,
+ "\" is itself an ALIAS."));
+ return false;
+ }
+ cmTarget* aliasedTarget = mf.FindTargetToUse(aliasedName, true);
+ if (!aliasedTarget) {
+ status.SetError(cmStrCat("cannot create ALIAS target \"", exename,
+ "\" because target \"", aliasedName,
+ "\" does not already exist."));
+ return false;
+ }
+ cmStateEnums::TargetType type = aliasedTarget->GetType();
+ if (type != cmStateEnums::EXECUTABLE) {
+ status.SetError(cmStrCat("cannot create ALIAS target \"", exename,
+ "\" because target \"", aliasedName,
+ "\" is not an executable."));
+ return false;
+ }
+ mf.AddAlias(exename, aliasedName,
+ !aliasedTarget->IsImported() ||
+ aliasedTarget->IsImportedGloballyVisible());
+ return true;
+ }
+
+ // Handle imported target creation.
+ if (importTarget) {
+ // Make sure the target does not already exist.
+ if (mf.FindTargetToUse(exename)) {
+ status.SetError(cmStrCat(
+ "cannot create imported target \"", exename,
+ "\" because another target with the same name already exists."));
+ return false;
+ }
+
+ // Create the imported target.
+ mf.AddImportedTarget(exename, cmStateEnums::EXECUTABLE, importGlobal);
+ return true;
+ }
+
+ // Enforce name uniqueness.
+ {
+ std::string msg;
+ if (!mf.EnforceUniqueName(exename, msg)) {
+ status.SetError(msg);
+ return false;
+ }
+ }
+
+ std::vector<std::string> srclists(s, args.end());
+ cmTarget* tgt = mf.AddExecutable(exename, srclists, excludeFromAll);
+ if (use_win32) {
+ tgt->SetProperty("WIN32_EXECUTABLE", "ON");
+ }
+ if (use_macbundle) {
+ tgt->SetProperty("MACOSX_BUNDLE", "ON");
+ }
+
+ return true;
+}
diff --git a/Source/cmAddExecutableCommand.h b/Source/cmAddExecutableCommand.h
new file mode 100644
index 0000000..032c14d
--- /dev/null
+++ b/Source/cmAddExecutableCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmAddExecutableCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx
new file mode 100644
index 0000000..92e04e4
--- /dev/null
+++ b/Source/cmAddLibraryCommand.cxx
@@ -0,0 +1,292 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmAddLibraryCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmTarget.h"
+
+bool cmAddLibraryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ // Library type defaults to value of BUILD_SHARED_LIBS, if it exists,
+ // otherwise it defaults to static library.
+ cmStateEnums::TargetType type = cmStateEnums::SHARED_LIBRARY;
+ if (cmIsOff(mf.GetDefinition("BUILD_SHARED_LIBS"))) {
+ type = cmStateEnums::STATIC_LIBRARY;
+ }
+ bool excludeFromAll = false;
+ bool importTarget = false;
+ bool importGlobal = false;
+
+ auto s = args.begin();
+
+ std::string const& libName = *s;
+
+ ++s;
+
+ // If the second argument is "SHARED" or "STATIC", then it controls
+ // the type of library. Otherwise, it is treated as a source or
+ // source list name. There may be two keyword arguments, check for them
+ bool haveSpecifiedType = false;
+ bool isAlias = false;
+ while (s != args.end()) {
+ std::string libType = *s;
+ if (libType == "STATIC") {
+ if (type == cmStateEnums::INTERFACE_LIBRARY) {
+ status.SetError(
+ "INTERFACE library specified with conflicting STATIC type.");
+ return false;
+ }
+ ++s;
+ type = cmStateEnums::STATIC_LIBRARY;
+ haveSpecifiedType = true;
+ } else if (libType == "SHARED") {
+ if (type == cmStateEnums::INTERFACE_LIBRARY) {
+ status.SetError(
+ "INTERFACE library specified with conflicting SHARED type.");
+ return false;
+ }
+ ++s;
+ type = cmStateEnums::SHARED_LIBRARY;
+ haveSpecifiedType = true;
+ } else if (libType == "MODULE") {
+ if (type == cmStateEnums::INTERFACE_LIBRARY) {
+ status.SetError(
+ "INTERFACE library specified with conflicting MODULE type.");
+ return false;
+ }
+ ++s;
+ type = cmStateEnums::MODULE_LIBRARY;
+ haveSpecifiedType = true;
+ } else if (libType == "OBJECT") {
+ if (type == cmStateEnums::INTERFACE_LIBRARY) {
+ status.SetError(
+ "INTERFACE library specified with conflicting OBJECT type.");
+ return false;
+ }
+ ++s;
+ type = cmStateEnums::OBJECT_LIBRARY;
+ haveSpecifiedType = true;
+ } else if (libType == "UNKNOWN") {
+ if (type == cmStateEnums::INTERFACE_LIBRARY) {
+ status.SetError(
+ "INTERFACE library specified with conflicting UNKNOWN type.");
+ return false;
+ }
+ ++s;
+ type = cmStateEnums::UNKNOWN_LIBRARY;
+ haveSpecifiedType = true;
+ } else if (libType == "ALIAS") {
+ if (type == cmStateEnums::INTERFACE_LIBRARY) {
+ status.SetError(
+ "INTERFACE library specified with conflicting ALIAS type.");
+ return false;
+ }
+ ++s;
+ isAlias = true;
+ } else if (libType == "INTERFACE") {
+ if (haveSpecifiedType) {
+ status.SetError(
+ "INTERFACE library specified with conflicting/multiple types.");
+ return false;
+ }
+ if (isAlias) {
+ status.SetError(
+ "INTERFACE library specified with conflicting ALIAS type.");
+ return false;
+ }
+ ++s;
+ type = cmStateEnums::INTERFACE_LIBRARY;
+ haveSpecifiedType = true;
+ } else if (*s == "EXCLUDE_FROM_ALL") {
+ ++s;
+ excludeFromAll = true;
+ } else if (*s == "IMPORTED") {
+ ++s;
+ importTarget = true;
+ } else if (importTarget && *s == "GLOBAL") {
+ ++s;
+ importGlobal = true;
+ } else if (type == cmStateEnums::INTERFACE_LIBRARY && *s == "GLOBAL") {
+ status.SetError(
+ "GLOBAL option may only be used with IMPORTED libraries.");
+ return false;
+ } else {
+ break;
+ }
+ }
+
+ if (type == cmStateEnums::INTERFACE_LIBRARY) {
+ if (importGlobal && !importTarget) {
+ status.SetError(
+ "INTERFACE library specified as GLOBAL, but not as IMPORTED.");
+ return false;
+ }
+ }
+
+ bool nameOk = cmGeneratorExpression::IsValidTargetName(libName) &&
+ !cmGlobalGenerator::IsReservedTarget(libName);
+
+ if (nameOk && !importTarget && !isAlias) {
+ nameOk = libName.find(':') == std::string::npos;
+ }
+ if (!nameOk && !mf.CheckCMP0037(libName, type)) {
+ return false;
+ }
+
+ if (isAlias) {
+ if (!cmGeneratorExpression::IsValidTargetName(libName)) {
+ status.SetError("Invalid name for ALIAS: " + libName);
+ return false;
+ }
+ if (excludeFromAll) {
+ status.SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense.");
+ return false;
+ }
+ if (importTarget || importGlobal) {
+ status.SetError("IMPORTED with ALIAS is not allowed.");
+ return false;
+ }
+ if (args.size() != 3) {
+ status.SetError("ALIAS requires exactly one target argument.");
+ return false;
+ }
+
+ if (mf.GetPolicyStatus(cmPolicies::CMP0107) == cmPolicies::NEW) {
+ // Make sure the target does not already exist.
+ if (mf.FindTargetToUse(libName)) {
+ status.SetError(cmStrCat(
+ "cannot create ALIAS target \"", libName,
+ "\" because another target with the same name already exists."));
+ return false;
+ }
+ }
+
+ std::string const& aliasedName = *s;
+ if (mf.IsAlias(aliasedName)) {
+ status.SetError(cmStrCat("cannot create ALIAS target \"", libName,
+ "\" because target \"", aliasedName,
+ "\" is itself an ALIAS."));
+ return false;
+ }
+ cmTarget* aliasedTarget = mf.FindTargetToUse(aliasedName, true);
+ if (!aliasedTarget) {
+ status.SetError(cmStrCat("cannot create ALIAS target \"", libName,
+ "\" because target \"", aliasedName,
+ "\" does not already exist."));
+ return false;
+ }
+ cmStateEnums::TargetType aliasedType = aliasedTarget->GetType();
+ if (aliasedType != cmStateEnums::SHARED_LIBRARY &&
+ aliasedType != cmStateEnums::STATIC_LIBRARY &&
+ aliasedType != cmStateEnums::MODULE_LIBRARY &&
+ aliasedType != cmStateEnums::OBJECT_LIBRARY &&
+ aliasedType != cmStateEnums::INTERFACE_LIBRARY &&
+ !(aliasedType == cmStateEnums::UNKNOWN_LIBRARY &&
+ aliasedTarget->IsImported())) {
+ status.SetError(cmStrCat("cannot create ALIAS target \"", libName,
+ "\" because target \"", aliasedName,
+ "\" is not a library."));
+ return false;
+ }
+ mf.AddAlias(libName, aliasedName,
+ !aliasedTarget->IsImported() ||
+ aliasedTarget->IsImportedGloballyVisible());
+ return true;
+ }
+
+ if (importTarget && excludeFromAll) {
+ status.SetError("excludeFromAll with IMPORTED target makes no sense.");
+ return false;
+ }
+
+ /* ideally we should check whether for the linker language of the target
+ CMAKE_${LANG}_CREATE_SHARED_LIBRARY is defined and if not default to
+ STATIC. But at this point we know only the name of the target, but not
+ yet its linker language. */
+ if ((type == cmStateEnums::SHARED_LIBRARY ||
+ type == cmStateEnums::MODULE_LIBRARY) &&
+ !mf.GetState()->GetGlobalPropertyAsBool("TARGET_SUPPORTS_SHARED_LIBS")) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(
+ "ADD_LIBRARY called with ",
+ (type == cmStateEnums::SHARED_LIBRARY ? "SHARED" : "MODULE"),
+ " option but the target platform does not support dynamic linking. ",
+ "Building a STATIC library instead. This may lead to problems."));
+ type = cmStateEnums::STATIC_LIBRARY;
+ }
+
+ // Handle imported target creation.
+ if (importTarget) {
+ // The IMPORTED signature requires a type to be specified explicitly.
+ if (!haveSpecifiedType) {
+ status.SetError("called with IMPORTED argument but no library type.");
+ return false;
+ }
+ if (type == cmStateEnums::INTERFACE_LIBRARY) {
+ if (!cmGeneratorExpression::IsValidTargetName(libName)) {
+ status.SetError(cmStrCat(
+ "Invalid name for IMPORTED INTERFACE library target: ", libName));
+ return false;
+ }
+ }
+
+ // Make sure the target does not already exist.
+ if (mf.FindTargetToUse(libName)) {
+ status.SetError(cmStrCat(
+ "cannot create imported target \"", libName,
+ "\" because another target with the same name already exists."));
+ return false;
+ }
+
+ // Create the imported target.
+ mf.AddImportedTarget(libName, type, importGlobal);
+ return true;
+ }
+
+ // A non-imported target may not have UNKNOWN type.
+ if (type == cmStateEnums::UNKNOWN_LIBRARY) {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "The UNKNOWN library type may be used only for IMPORTED libraries.");
+ return true;
+ }
+
+ // Enforce name uniqueness.
+ {
+ std::string msg;
+ if (!mf.EnforceUniqueName(libName, msg)) {
+ status.SetError(msg);
+ return false;
+ }
+ }
+
+ if (type == cmStateEnums::INTERFACE_LIBRARY) {
+ if (!cmGeneratorExpression::IsValidTargetName(libName) ||
+ libName.find("::") != std::string::npos) {
+ status.SetError(
+ cmStrCat("Invalid name for INTERFACE library target: ", libName));
+ return false;
+ }
+ }
+
+ std::vector<std::string> srcs(s, args.end());
+ mf.AddLibrary(libName, type, srcs, excludeFromAll);
+
+ return true;
+}
diff --git a/Source/cmAddLibraryCommand.h b/Source/cmAddLibraryCommand.h
new file mode 100644
index 0000000..a4a0ea0
--- /dev/null
+++ b/Source/cmAddLibraryCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmAddLibraryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmAddLinkOptionsCommand.cxx b/Source/cmAddLinkOptionsCommand.cxx
new file mode 100644
index 0000000..7ed31bd
--- /dev/null
+++ b/Source/cmAddLinkOptionsCommand.cxx
@@ -0,0 +1,16 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmAddLinkOptionsCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+
+bool cmAddLinkOptionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ cmMakefile& mf = status.GetMakefile();
+ for (std::string const& i : args) {
+ mf.AddLinkOption(i);
+ }
+ return true;
+}
diff --git a/Source/cmAddLinkOptionsCommand.h b/Source/cmAddLinkOptionsCommand.h
new file mode 100644
index 0000000..5c9d5e4
--- /dev/null
+++ b/Source/cmAddLinkOptionsCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmAddLinkOptionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmAddSubDirectoryCommand.cxx b/Source/cmAddSubDirectoryCommand.cxx
new file mode 100644
index 0000000..83d6306
--- /dev/null
+++ b/Source/cmAddSubDirectoryCommand.cxx
@@ -0,0 +1,108 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmAddSubDirectoryCommand.h"
+
+#include <cstring>
+
+#include <cm/string_view>
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+bool cmAddSubDirectoryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ // store the binpath
+ std::string const& srcArg = args.front();
+ std::string binArg;
+
+ bool excludeFromAll = false;
+
+ // process the rest of the arguments looking for optional args
+ for (std::string const& arg : cmMakeRange(args).advance(1)) {
+ if (arg == "EXCLUDE_FROM_ALL") {
+ excludeFromAll = true;
+ continue;
+ }
+ if (binArg.empty()) {
+ binArg = arg;
+ } else {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ }
+
+ // Compute the full path to the specified source directory.
+ // Interpret a relative path with respect to the current source directory.
+ std::string srcPath;
+ if (cmSystemTools::FileIsFullPath(srcArg)) {
+ srcPath = srcArg;
+ } else {
+ srcPath = cmStrCat(mf.GetCurrentSourceDirectory(), '/', srcArg);
+ }
+ if (!cmSystemTools::FileIsDirectory(srcPath)) {
+ std::string error = cmStrCat("given source \"", srcArg,
+ "\" which is not an existing directory.");
+ status.SetError(error);
+ return false;
+ }
+ srcPath =
+ cmSystemTools::CollapseFullPath(srcPath, mf.GetHomeOutputDirectory());
+
+ // Compute the full path to the binary directory.
+ std::string binPath;
+ if (binArg.empty()) {
+ // No binary directory was specified. If the source directory is
+ // not a subdirectory of the current directory then it is an
+ // error.
+ if (!cmSystemTools::IsSubDirectory(srcPath,
+ mf.GetCurrentSourceDirectory())) {
+ status.SetError(
+ cmStrCat("not given a binary directory but the given source ",
+ "directory \"", srcPath, "\" is not a subdirectory of \"",
+ mf.GetCurrentSourceDirectory(),
+ "\". When specifying an "
+ "out-of-tree source a binary directory must be explicitly "
+ "specified."));
+ return false;
+ }
+
+ // Remove the CurrentDirectory from the srcPath and replace it
+ // with the CurrentOutputDirectory.
+ const std::string& src = mf.GetCurrentSourceDirectory();
+ const std::string& bin = mf.GetCurrentBinaryDirectory();
+ size_t srcLen = src.length();
+ size_t binLen = bin.length();
+ if (srcLen > 0 && src.back() == '/') {
+ --srcLen;
+ }
+ if (binLen > 0 && bin.back() == '/') {
+ --binLen;
+ }
+ binPath = cmStrCat(cm::string_view(bin).substr(0, binLen),
+ cm::string_view(srcPath).substr(srcLen));
+ } else {
+ // Use the binary directory specified.
+ // Interpret a relative path with respect to the current binary directory.
+ if (cmSystemTools::FileIsFullPath(binArg)) {
+ binPath = binArg;
+ } else {
+ binPath = cmStrCat(mf.GetCurrentBinaryDirectory(), '/', binArg);
+ }
+ }
+ binPath = cmSystemTools::CollapseFullPath(binPath);
+
+ // Add the subdirectory using the computed full paths.
+ mf.AddSubDirectory(srcPath, binPath, excludeFromAll, true);
+
+ return true;
+}
diff --git a/Source/cmAddSubDirectoryCommand.h b/Source/cmAddSubDirectoryCommand.h
new file mode 100644
index 0000000..ece3b27
--- /dev/null
+++ b/Source/cmAddSubDirectoryCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmAddSubDirectoryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmAddTestCommand.cxx b/Source/cmAddTestCommand.cxx
new file mode 100644
index 0000000..205c1c7
--- /dev/null
+++ b/Source/cmAddTestCommand.cxx
@@ -0,0 +1,149 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmAddTestCommand.h"
+
+#include <cm/memory>
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmTest.h"
+#include "cmTestGenerator.h"
+
+static bool cmAddTestCommandHandleNameMode(
+ std::vector<std::string> const& args, cmExecutionStatus& status);
+
+bool cmAddTestCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (!args.empty() && args[0] == "NAME") {
+ return cmAddTestCommandHandleNameMode(args, status);
+ }
+
+ // First argument is the name of the test Second argument is the name of
+ // the executable to run (a target or external program) Remaining arguments
+ // are the arguments to pass to the executable
+ if (args.size() < 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ // Collect the command with arguments.
+ std::vector<std::string> command(args.begin() + 1, args.end());
+
+ // Create the test but add a generator only the first time it is
+ // seen. This preserves behavior from before test generators.
+ cmTest* test = mf.GetTest(args[0]);
+ if (test) {
+ // If the test was already added by a new-style signature do not
+ // allow it to be duplicated.
+ if (!test->GetOldStyle()) {
+ status.SetError(cmStrCat(" given test name \"", args[0],
+ "\" which already exists in this directory."));
+ return false;
+ }
+ } else {
+ test = mf.CreateTest(args[0]);
+ test->SetOldStyle(true);
+ mf.AddTestGenerator(cm::make_unique<cmTestGenerator>(test));
+ }
+ test->SetCommand(command);
+
+ return true;
+}
+
+bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ std::string name;
+ std::vector<std::string> configurations;
+ std::string working_directory;
+ std::vector<std::string> command;
+ bool command_expand_lists = false;
+
+ // Read the arguments.
+ enum Doing
+ {
+ DoingName,
+ DoingCommand,
+ DoingConfigs,
+ DoingWorkingDirectory,
+ DoingNone
+ };
+ Doing doing = DoingName;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "COMMAND") {
+ if (!command.empty()) {
+ status.SetError(" may be given at most one COMMAND.");
+ return false;
+ }
+ doing = DoingCommand;
+ } else if (args[i] == "CONFIGURATIONS") {
+ if (!configurations.empty()) {
+ status.SetError(" may be given at most one set of CONFIGURATIONS.");
+ return false;
+ }
+ doing = DoingConfigs;
+ } else if (args[i] == "WORKING_DIRECTORY") {
+ if (!working_directory.empty()) {
+ status.SetError(" may be given at most one WORKING_DIRECTORY.");
+ return false;
+ }
+ doing = DoingWorkingDirectory;
+ } else if (args[i] == "COMMAND_EXPAND_LISTS") {
+ if (command_expand_lists) {
+ status.SetError(" may be given at most one COMMAND_EXPAND_LISTS.");
+ return false;
+ }
+ command_expand_lists = true;
+ doing = DoingNone;
+ } else if (doing == DoingName) {
+ name = args[i];
+ doing = DoingNone;
+ } else if (doing == DoingCommand) {
+ command.push_back(args[i]);
+ } else if (doing == DoingConfigs) {
+ configurations.push_back(args[i]);
+ } else if (doing == DoingWorkingDirectory) {
+ working_directory = args[i];
+ doing = DoingNone;
+ } else {
+ status.SetError(cmStrCat(" given unknown argument:\n ", args[i], "\n"));
+ return false;
+ }
+ }
+
+ // Require a test name.
+ if (name.empty()) {
+ status.SetError(" must be given non-empty NAME.");
+ return false;
+ }
+
+ // Require a command.
+ if (command.empty()) {
+ status.SetError(" must be given non-empty COMMAND.");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ // Require a unique test name within the directory.
+ if (mf.GetTest(name)) {
+ status.SetError(cmStrCat(" given test NAME \"", name,
+ "\" which already exists in this directory."));
+ return false;
+ }
+
+ // Add the test.
+ cmTest* test = mf.CreateTest(name);
+ test->SetOldStyle(false);
+ test->SetCommand(command);
+ if (!working_directory.empty()) {
+ test->SetProperty("WORKING_DIRECTORY", working_directory.c_str());
+ }
+ test->SetCommandExpandLists(command_expand_lists);
+ mf.AddTestGenerator(cm::make_unique<cmTestGenerator>(test, configurations));
+
+ return true;
+}
diff --git a/Source/cmAddTestCommand.h b/Source/cmAddTestCommand.h
new file mode 100644
index 0000000..8cba2b1
--- /dev/null
+++ b/Source/cmAddTestCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmAddTestCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmAffinity.cxx b/Source/cmAffinity.cxx
new file mode 100644
index 0000000..35443e7
--- /dev/null
+++ b/Source/cmAffinity.cxx
@@ -0,0 +1,65 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmAffinity.h"
+
+#include <cm3p/uv.h>
+
+#ifndef CMAKE_USE_SYSTEM_LIBUV
+# ifdef _WIN32
+# define CM_HAVE_CPU_AFFINITY
+# include <windows.h>
+# elif defined(__linux__) || defined(__FreeBSD__)
+# define CM_HAVE_CPU_AFFINITY
+# include <pthread.h>
+# include <sched.h>
+// On some platforms CPU_ZERO needs memset but sched.h forgets string.h
+# include <cstring> // IWYU pragma: keep
+# if defined(__FreeBSD__)
+# include <pthread_np.h>
+
+# include <sys/cpuset.h>
+# include <sys/param.h>
+# endif
+# if defined(__linux__)
+using cm_cpuset_t = cpu_set_t;
+# else
+using cm_cpuset_t = cpuset_t;
+# endif
+# endif
+#endif
+
+namespace cmAffinity {
+
+std::set<size_t> GetProcessorsAvailable()
+{
+ std::set<size_t> processorsAvailable;
+#ifdef CM_HAVE_CPU_AFFINITY
+ int cpumask_size = uv_cpumask_size();
+ if (cpumask_size > 0) {
+# ifdef _WIN32
+ DWORD_PTR procmask;
+ DWORD_PTR sysmask;
+ if (GetProcessAffinityMask(GetCurrentProcess(), &procmask, &sysmask) !=
+ 0) {
+ for (int i = 0; i < cpumask_size; ++i) {
+ if (procmask & (((DWORD_PTR)1) << i)) {
+ processorsAvailable.insert(i);
+ }
+ }
+ }
+# else
+ cm_cpuset_t cpuset;
+ CPU_ZERO(&cpuset); // NOLINT(clang-tidy)
+ if (pthread_getaffinity_np(pthread_self(), sizeof(cpuset), &cpuset) == 0) {
+ for (int i = 0; i < cpumask_size; ++i) {
+ if (CPU_ISSET(i, &cpuset)) {
+ processorsAvailable.insert(i);
+ }
+ }
+ }
+# endif
+ }
+#endif
+ return processorsAvailable;
+}
+}
diff --git a/Source/cmAffinity.h b/Source/cmAffinity.h
new file mode 100644
index 0000000..3775bae
--- /dev/null
+++ b/Source/cmAffinity.h
@@ -0,0 +1,12 @@
+/* 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 <cstddef>
+#include <set>
+
+namespace cmAffinity {
+
+std::set<size_t> GetProcessorsAvailable();
+}
diff --git a/Source/cmAlgorithms.h b/Source/cmAlgorithms.h
new file mode 100644
index 0000000..c192e2a
--- /dev/null
+++ b/Source/cmAlgorithms.h
@@ -0,0 +1,145 @@
+/* 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 <algorithm>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <cmext/algorithm>
+
+#include "cmRange.h"
+
+template <typename FwdIt>
+FwdIt cmRotate(FwdIt first, FwdIt middle, FwdIt last)
+{
+ const typename std::iterator_traits<FwdIt>::difference_type dist =
+ std::distance(middle, last);
+ std::rotate(first, middle, last);
+ std::advance(first, dist);
+ return first;
+}
+
+namespace ContainerAlgorithms {
+
+template <typename FwdIt>
+FwdIt RemoveN(FwdIt i1, FwdIt i2, size_t n)
+{
+ FwdIt m = i1;
+ std::advance(m, n);
+ return cmRotate(i1, m, i2);
+}
+
+template <typename Range>
+struct BinarySearcher
+{
+ using argument_type = typename Range::value_type;
+ BinarySearcher(Range const& r)
+ : m_range(r)
+ {
+ }
+
+ bool operator()(argument_type const& item) const
+ {
+ return std::binary_search(this->m_range.begin(), this->m_range.end(),
+ item);
+ }
+
+private:
+ Range const& m_range;
+};
+}
+
+class cmListFileBacktrace;
+using cmBacktraceRange =
+ cmRange<std::vector<cmListFileBacktrace>::const_iterator>;
+
+template <typename Range>
+typename Range::const_iterator cmRemoveN(Range& r, size_t n)
+{
+ return ContainerAlgorithms::RemoveN(r.begin(), r.end(), n);
+}
+
+template <typename Range, typename InputRange>
+typename Range::const_iterator cmRemoveIndices(Range& r, InputRange const& rem)
+{
+ typename InputRange::const_iterator remIt = rem.begin();
+ typename InputRange::const_iterator remEnd = rem.end();
+ const auto rangeEnd = r.end();
+ if (remIt == remEnd) {
+ return rangeEnd;
+ }
+
+ auto writer = r.begin();
+ std::advance(writer, *remIt);
+ auto pivot = writer;
+ typename InputRange::value_type prevRem = *remIt;
+ ++remIt;
+ size_t count = 1;
+ for (; writer != rangeEnd && remIt != remEnd; ++count, ++remIt) {
+ std::advance(pivot, *remIt - prevRem);
+ prevRem = *remIt;
+ writer = ContainerAlgorithms::RemoveN(writer, pivot, count);
+ }
+ return ContainerAlgorithms::RemoveN(writer, rangeEnd, count);
+}
+
+template <typename Range, typename MatchRange>
+typename Range::const_iterator cmRemoveMatching(Range& r, MatchRange const& m)
+{
+ return std::remove_if(r.begin(), r.end(),
+ ContainerAlgorithms::BinarySearcher<MatchRange>(m));
+}
+
+template <typename ForwardIterator>
+ForwardIterator cmRemoveDuplicates(ForwardIterator first, ForwardIterator last)
+{
+ using Value = typename std::iterator_traits<ForwardIterator>::value_type;
+ struct Hash
+ {
+ std::size_t operator()(ForwardIterator it) const
+ {
+ return std::hash<Value>{}(*it);
+ }
+ };
+
+ struct Equal
+ {
+ bool operator()(ForwardIterator it1, ForwardIterator it2) const
+ {
+ return *it1 == *it2;
+ }
+ };
+ std::unordered_set<ForwardIterator, Hash, Equal> uniq;
+
+ ForwardIterator result = first;
+ while (first != last) {
+ if (!cm::contains(uniq, first)) {
+ if (result != first) {
+ *result = std::move(*first);
+ }
+ uniq.insert(result);
+ ++result;
+ }
+ ++first;
+ }
+ return result;
+}
+
+template <typename Range>
+typename Range::const_iterator cmRemoveDuplicates(Range& r)
+{
+ return cmRemoveDuplicates(r.begin(), r.end());
+}
+
+template <typename Range, typename T>
+typename Range::const_iterator cmFindNot(Range const& r, T const& t)
+{
+ return std::find_if(r.begin(), r.end(), [&t](T const& i) { return i != t; });
+}
diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx
new file mode 100644
index 0000000..b685b73
--- /dev/null
+++ b/Source/cmArchiveWrite.cxx
@@ -0,0 +1,440 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmArchiveWrite.h"
+
+#include <cstdio>
+#include <cstring>
+#include <ctime>
+#include <iostream>
+#include <sstream>
+
+#include <cm3p/archive.h>
+#include <cm3p/archive_entry.h>
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/Encoding.hxx"
+#include "cmsys/FStream.hxx"
+
+#include "cm_get_date.h"
+
+#include "cmLocale.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+#ifndef __LA_SSIZE_T
+# define __LA_SSIZE_T la_ssize_t
+#endif
+
+static std::string cm_archive_error_string(struct archive* a)
+{
+ const char* e = archive_error_string(a);
+ return e ? e : "unknown error";
+}
+
+static void cm_archive_entry_copy_pathname(struct archive_entry* e,
+ const std::string& dest)
+{
+#if cmsys_STL_HAS_WSTRING
+ archive_entry_copy_pathname_w(e, cmsys::Encoding::ToWide(dest).c_str());
+#else
+ archive_entry_copy_pathname(e, dest.c_str());
+#endif
+}
+
+static void cm_archive_entry_copy_sourcepath(struct archive_entry* e,
+ const std::string& file)
+{
+#if cmsys_STL_HAS_WSTRING
+ archive_entry_copy_sourcepath_w(e, cmsys::Encoding::ToWide(file).c_str());
+#else
+ archive_entry_copy_sourcepath(e, file.c_str());
+#endif
+}
+
+class cmArchiveWrite::Entry
+{
+ struct archive_entry* Object;
+
+public:
+ Entry()
+ : Object(archive_entry_new())
+ {
+ }
+ ~Entry() { archive_entry_free(this->Object); }
+ Entry(const Entry&) = delete;
+ Entry& operator=(const Entry&) = delete;
+ operator struct archive_entry*() { return this->Object; }
+};
+
+struct cmArchiveWrite::Callback
+{
+ // archive_write_callback
+ static __LA_SSIZE_T Write(struct archive* /*unused*/, void* cd,
+ const void* b, size_t n)
+ {
+ cmArchiveWrite* self = static_cast<cmArchiveWrite*>(cd);
+ if (self->Stream.write(static_cast<const char*>(b),
+ static_cast<std::streamsize>(n))) {
+ return static_cast<__LA_SSIZE_T>(n);
+ }
+ return static_cast<__LA_SSIZE_T>(-1);
+ }
+};
+
+cmArchiveWrite::cmArchiveWrite(std::ostream& os, Compress c,
+ std::string const& format, int compressionLevel,
+ int numThreads)
+ : Stream(os)
+ , Archive(archive_write_new())
+ , Disk(archive_read_disk_new())
+ , Verbose(false)
+ , Format(format)
+{
+ switch (c) {
+ case CompressNone:
+ if (archive_write_add_filter_none(this->Archive) != ARCHIVE_OK) {
+ this->Error = cmStrCat("archive_write_add_filter_none: ",
+ cm_archive_error_string(this->Archive));
+ return;
+ }
+ break;
+ case CompressCompress:
+ if (archive_write_add_filter_compress(this->Archive) != ARCHIVE_OK) {
+ this->Error = cmStrCat("archive_write_add_filter_compress: ",
+ cm_archive_error_string(this->Archive));
+ return;
+ }
+ break;
+ case CompressGZip: {
+ if (archive_write_add_filter_gzip(this->Archive) != ARCHIVE_OK) {
+ this->Error = cmStrCat("archive_write_add_filter_gzip: ",
+ cm_archive_error_string(this->Archive));
+ return;
+ }
+ std::string source_date_epoch;
+ cmSystemTools::GetEnv("SOURCE_DATE_EPOCH", source_date_epoch);
+ if (!source_date_epoch.empty()) {
+ // We're not able to specify an arbitrary timestamp for gzip.
+ // The next best thing is to omit the timestamp entirely.
+ if (archive_write_set_filter_option(this->Archive, "gzip", "timestamp",
+ nullptr) != ARCHIVE_OK) {
+ this->Error = cmStrCat("archive_write_set_filter_option: ",
+ cm_archive_error_string(this->Archive));
+ return;
+ }
+ }
+ } break;
+ case CompressBZip2:
+ if (archive_write_add_filter_bzip2(this->Archive) != ARCHIVE_OK) {
+ this->Error = cmStrCat("archive_write_add_filter_bzip2: ",
+ cm_archive_error_string(this->Archive));
+ return;
+ }
+ break;
+ case CompressLZMA:
+ if (archive_write_add_filter_lzma(this->Archive) != ARCHIVE_OK) {
+ this->Error = cmStrCat("archive_write_add_filter_lzma: ",
+ cm_archive_error_string(this->Archive));
+ return;
+ }
+ break;
+ case CompressXZ:
+ if (archive_write_add_filter_xz(this->Archive) != ARCHIVE_OK) {
+ this->Error = cmStrCat("archive_write_add_filter_xz: ",
+ cm_archive_error_string(this->Archive));
+ return;
+ }
+ {
+ char sNumThreads[8];
+ snprintf(sNumThreads, sizeof(sNumThreads), "%d", numThreads);
+ sNumThreads[7] = '\0'; // for safety
+ if (archive_write_set_filter_option(this->Archive, "xz", "threads",
+ sNumThreads) != ARCHIVE_OK) {
+ this->Error = cmStrCat("archive_compressor_xz_options: ",
+ cm_archive_error_string(this->Archive));
+ return;
+ }
+ }
+
+ break;
+ case CompressZstd:
+ if (archive_write_add_filter_zstd(this->Archive) != ARCHIVE_OK) {
+ this->Error = cmStrCat("archive_write_add_filter_zstd: ",
+ cm_archive_error_string(this->Archive));
+ return;
+ }
+ break;
+ }
+
+ if (compressionLevel != 0) {
+ std::string compressionLevelStr = std::to_string(compressionLevel);
+ std::string archiveFilterName;
+ switch (c) {
+ case CompressNone:
+ case CompressCompress:
+ break;
+ case CompressGZip:
+ archiveFilterName = "gzip";
+ break;
+ case CompressBZip2:
+ archiveFilterName = "bzip2";
+ break;
+ case CompressLZMA:
+ archiveFilterName = "lzma";
+ break;
+ case CompressXZ:
+ archiveFilterName = "xz";
+ break;
+ case CompressZstd:
+ archiveFilterName = "zstd";
+ break;
+ }
+ if (!archiveFilterName.empty()) {
+ if (archive_write_set_filter_option(
+ this->Archive, archiveFilterName.c_str(), "compression-level",
+ compressionLevelStr.c_str()) != ARCHIVE_OK) {
+ this->Error = cmStrCat("archive_write_set_filter_option: ",
+ cm_archive_error_string(this->Archive));
+ return;
+ }
+ }
+ }
+
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ if (archive_read_disk_set_standard_lookup(this->Disk) != ARCHIVE_OK) {
+ this->Error = cmStrCat("archive_read_disk_set_standard_lookup: ",
+ cm_archive_error_string(this->Archive));
+ return;
+ }
+#endif
+
+ if (archive_write_set_format_by_name(this->Archive, format.c_str()) !=
+ ARCHIVE_OK) {
+ this->Error = cmStrCat("archive_write_set_format_by_name: ",
+ cm_archive_error_string(this->Archive));
+ return;
+ }
+
+ // do not pad the last block!!
+ if (archive_write_set_bytes_in_last_block(this->Archive, 1)) {
+ this->Error = cmStrCat("archive_write_set_bytes_in_last_block: ",
+ cm_archive_error_string(this->Archive));
+ return;
+ }
+}
+
+bool cmArchiveWrite::Open()
+{
+ if (archive_write_open(
+ this->Archive, this, nullptr,
+ reinterpret_cast<archive_write_callback*>(&Callback::Write),
+ nullptr) != ARCHIVE_OK) {
+ this->Error =
+ cmStrCat("archive_write_open: ", cm_archive_error_string(this->Archive));
+ return false;
+ }
+ return true;
+}
+
+cmArchiveWrite::~cmArchiveWrite()
+{
+ archive_read_free(this->Disk);
+ archive_write_free(this->Archive);
+}
+
+bool cmArchiveWrite::Add(std::string path, size_t skip, const char* prefix,
+ bool recursive)
+{
+ if (!path.empty() && path.back() == '/') {
+ path.erase(path.size() - 1);
+ }
+ this->AddPath(path.c_str(), skip, prefix, recursive);
+ return this->Okay();
+}
+
+bool cmArchiveWrite::AddPath(const char* path, size_t skip, const char* prefix,
+ bool recursive)
+{
+ if (strcmp(path, ".") != 0 ||
+ (this->Format != "zip" && this->Format != "7zip")) {
+ if (!this->AddFile(path, skip, prefix)) {
+ return false;
+ }
+ }
+ if ((!cmSystemTools::FileIsDirectory(path) || !recursive) ||
+ cmSystemTools::FileIsSymlink(path)) {
+ return true;
+ }
+ cmsys::Directory d;
+ if (d.Load(path)) {
+ std::string next = cmStrCat(path, '/');
+ if (next == "./" && (this->Format == "zip" || this->Format == "7zip")) {
+ next.clear();
+ }
+ std::string::size_type end = next.size();
+ unsigned long n = d.GetNumberOfFiles();
+ for (unsigned long i = 0; i < n; ++i) {
+ const char* file = d.GetFile(i);
+ if (strcmp(file, ".") != 0 && strcmp(file, "..") != 0) {
+ next.erase(end);
+ next += file;
+ if (!this->AddPath(next.c_str(), skip, prefix)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool cmArchiveWrite::AddFile(const char* file, size_t skip, const char* prefix)
+{
+ this->Error = "";
+ // Skip the file if we have no name for it. This may happen on a
+ // top-level directory, which does not need to be included anyway.
+ if (skip >= strlen(file)) {
+ return true;
+ }
+ const char* out = file + skip;
+
+ cmLocaleRAII localeRAII;
+ static_cast<void>(localeRAII);
+
+ // Meta-data.
+ std::string dest = cmStrCat(prefix ? prefix : "", out);
+ if (this->Verbose) {
+ std::cout << dest << "\n";
+ }
+ Entry e;
+ cm_archive_entry_copy_sourcepath(e, file);
+ cm_archive_entry_copy_pathname(e, dest);
+ if (archive_read_disk_entry_from_file(this->Disk, e, -1, nullptr) !=
+ ARCHIVE_OK) {
+ this->Error = cmStrCat("Unable to read from file '", file,
+ "': ", cm_archive_error_string(this->Disk));
+ return false;
+ }
+ if (!this->MTime.empty()) {
+ time_t now;
+ time(&now);
+ time_t t = cm_get_date(now, this->MTime.c_str());
+ if (t == -1) {
+ this->Error = cmStrCat("unable to parse mtime '", this->MTime, '\'');
+ return false;
+ }
+ archive_entry_set_mtime(e, t, 0);
+ } else {
+ std::string source_date_epoch;
+ cmSystemTools::GetEnv("SOURCE_DATE_EPOCH", source_date_epoch);
+ if (!source_date_epoch.empty()) {
+ std::istringstream iss(source_date_epoch);
+ time_t epochTime;
+ iss >> epochTime;
+ if (iss.eof() && !iss.fail()) {
+ // Set all of the file times to the epoch time to handle archive
+ // formats that include creation/access time.
+ archive_entry_set_mtime(e, epochTime, 0);
+ archive_entry_set_atime(e, epochTime, 0);
+ archive_entry_set_ctime(e, epochTime, 0);
+ archive_entry_set_birthtime(e, epochTime, 0);
+ }
+ }
+ }
+
+ // manages the uid/guid of the entry (if any)
+ if (this->Uid.IsSet() && this->Gid.IsSet()) {
+ archive_entry_set_uid(e, this->Uid.Get());
+ archive_entry_set_gid(e, this->Gid.Get());
+ }
+
+ if (!this->Uname.empty() && !this->Gname.empty()) {
+ archive_entry_set_uname(e, this->Uname.c_str());
+ archive_entry_set_gname(e, this->Gname.c_str());
+ }
+
+ // manages the permissions
+ if (this->Permissions.IsSet()) {
+ archive_entry_set_perm(e, this->Permissions.Get());
+ }
+
+ if (this->PermissionsMask.IsSet()) {
+ int perm = archive_entry_perm(e);
+ archive_entry_set_perm(e, perm & this->PermissionsMask.Get());
+ }
+
+ // Clear acl and xattr fields not useful for distribution.
+ archive_entry_acl_clear(e);
+ archive_entry_xattr_clear(e);
+ archive_entry_set_fflags(e, 0, 0);
+
+ if (this->Format == "pax" || this->Format == "paxr") {
+ // Sparse files are a GNU tar extension.
+ // Do not use them in standard tar files.
+ archive_entry_sparse_clear(e);
+ }
+
+ if (archive_write_header(this->Archive, e) != ARCHIVE_OK) {
+ this->Error = cmStrCat("archive_write_header: ",
+ cm_archive_error_string(this->Archive));
+ return false;
+ }
+
+ // do not copy content of symlink
+ if (!archive_entry_symlink(e)) {
+ // Content.
+ if (size_t size = static_cast<size_t>(archive_entry_size(e))) {
+ return this->AddData(file, size);
+ }
+ }
+ return true;
+}
+
+bool cmArchiveWrite::AddData(const char* file, size_t size)
+{
+ cmsys::ifstream fin(file, std::ios::in | std::ios::binary);
+ if (!fin) {
+ this->Error = cmStrCat("Error opening \"", file,
+ "\": ", cmSystemTools::GetLastSystemError());
+ return false;
+ }
+
+ char buffer[16384];
+ size_t nleft = size;
+ while (nleft > 0) {
+ using ssize_type = std::streamsize;
+ size_t const nnext = nleft > sizeof(buffer) ? sizeof(buffer) : nleft;
+ ssize_type const nnext_s = static_cast<ssize_type>(nnext);
+ fin.read(buffer, nnext_s);
+ // Some stream libraries (older HPUX) return failure at end of
+ // file on the last read even if some data were read. Check
+ // gcount instead of trusting the stream error status.
+ if (static_cast<size_t>(fin.gcount()) != nnext) {
+ break;
+ }
+ if (archive_write_data(this->Archive, buffer, nnext) != nnext_s) {
+ this->Error = cmStrCat("archive_write_data: ",
+ cm_archive_error_string(this->Archive));
+ return false;
+ }
+ nleft -= nnext;
+ }
+ if (nleft > 0) {
+ this->Error = cmStrCat("Error reading \"", file,
+ "\": ", cmSystemTools::GetLastSystemError());
+ return false;
+ }
+ return true;
+}
+
+bool cmArchiveWrite::SetFilterOption(const char* module, const char* key,
+ const char* value)
+{
+ if (archive_write_set_filter_option(this->Archive, module, key, value) !=
+ ARCHIVE_OK) {
+ this->Error = "archive_write_set_filter_option: ";
+ this->Error += cm_archive_error_string(this->Archive);
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h
new file mode 100644
index 0000000..34aafe9
--- /dev/null
+++ b/Source/cmArchiveWrite.h
@@ -0,0 +1,182 @@
+/* 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 <cstddef>
+#include <iosfwd>
+#include <string>
+
+#if defined(CMAKE_BOOTSTRAP)
+# error "cmArchiveWrite not allowed during bootstrap build!"
+#endif
+
+template <typename T>
+class cmArchiveWriteOptional
+{
+public:
+ cmArchiveWriteOptional() { this->Clear(); }
+ explicit cmArchiveWriteOptional(T val) { this->Set(val); }
+
+ void Set(T val)
+ {
+ this->IsValueSet = true;
+ this->Value = val;
+ }
+ void Clear() { this->IsValueSet = false; }
+ bool IsSet() const { return this->IsValueSet; }
+ T Get() const { return this->Value; }
+
+private:
+ T Value;
+ bool IsValueSet;
+};
+
+/** \class cmArchiveWrite
+ * \brief Wrapper around libarchive for writing.
+ *
+ */
+class cmArchiveWrite
+{
+public:
+ /** Compression type. */
+ enum Compress
+ {
+ CompressNone,
+ CompressCompress,
+ CompressGZip,
+ CompressBZip2,
+ CompressLZMA,
+ CompressXZ,
+ CompressZstd
+ };
+
+ /** Construct with output stream to which to write archive. */
+ cmArchiveWrite(std::ostream& os, Compress c = CompressNone,
+ std::string const& format = "paxr", int compressionLevel = 0,
+ int numThreads = 1);
+
+ ~cmArchiveWrite();
+
+ cmArchiveWrite(const cmArchiveWrite&) = delete;
+ cmArchiveWrite& operator=(const cmArchiveWrite&) = delete;
+
+ bool Open();
+
+ /**
+ * Add a path (file or directory) to the archive. Directories are
+ * added recursively. The "path" must be readable on disk, either
+ * full path or relative to current working directory. The "skip"
+ * value indicates how many leading bytes from the input path to
+ * skip. The remaining part of the input path is appended to the
+ * "prefix" value to construct the final name in the archive.
+ */
+ bool Add(std::string path, size_t skip = 0, const char* prefix = nullptr,
+ bool recursive = true);
+
+ /** Returns true if there has been no error. */
+ explicit operator bool() const { return this->Okay(); }
+
+ /** Returns true if there has been an error. */
+ bool operator!() const { return !this->Okay(); }
+
+ /** Return the error string; empty if none. */
+ std::string GetError() const { return this->Error; }
+
+ // TODO: More general callback instead of hard-coding calls to
+ // std::cout.
+ void SetVerbose(bool v) { this->Verbose = v; }
+
+ void SetMTime(std::string const& t) { this->MTime = t; }
+
+ //! Sets the permissions of the added files/folders
+ void SetPermissions(int permissions_)
+ {
+ this->Permissions.Set(permissions_);
+ }
+
+ //! Clears permissions - default is used instead
+ void ClearPermissions() { this->Permissions.Clear(); }
+
+ //! Sets the permissions mask of files/folders
+ //!
+ //! The permissions will be copied from the existing file
+ //! or folder. The mask will then be applied to unset
+ //! some of them
+ void SetPermissionsMask(int permissionsMask_)
+ {
+ this->PermissionsMask.Set(permissionsMask_);
+ }
+
+ //! Clears permissions mask - default is used instead
+ void ClearPermissionsMask() { this->PermissionsMask.Clear(); }
+
+ //! Sets UID and GID to be used in the tar file
+ void SetUIDAndGID(int uid_, int gid_)
+ {
+ this->Uid.Set(uid_);
+ this->Gid.Set(gid_);
+ }
+
+ //! Clears UID and GID to be used in the tar file - default is used instead
+ void ClearUIDAndGID()
+ {
+ this->Uid.Clear();
+ this->Gid.Clear();
+ }
+
+ //! Sets UNAME and GNAME to be used in the tar file
+ void SetUNAMEAndGNAME(const std::string& uname_, const std::string& gname_)
+ {
+ this->Uname = uname_;
+ this->Gname = gname_;
+ }
+
+ //! Clears UNAME and GNAME to be used in the tar file
+ //! default is used instead
+ void ClearUNAMEAndGNAME()
+ {
+ this->Uname = "";
+ this->Gname = "";
+ }
+
+ //! Set an option on a filter;
+ bool SetFilterOption(const char* module, const char* key, const char* value);
+
+private:
+ bool Okay() const { return this->Error.empty(); }
+ bool AddPath(const char* path, size_t skip, const char* prefix,
+ bool recursive = true);
+ bool AddFile(const char* file, size_t skip, const char* prefix);
+ bool AddData(const char* file, size_t size);
+
+ struct Callback;
+ friend struct Callback;
+
+ class Entry;
+
+ std::ostream& Stream;
+ struct archive* Archive;
+ struct archive* Disk;
+ bool Verbose;
+ std::string Format;
+ std::string Error;
+ std::string MTime;
+
+ //! UID of the user in the tar file
+ cmArchiveWriteOptional<int> Uid;
+
+ //! GUID of the user in the tar file
+ cmArchiveWriteOptional<int> Gid;
+
+ //! UNAME/GNAME of the user (does not override UID/GID)
+ //!@{
+ std::string Uname;
+ std::string Gname;
+ //!@}
+
+ //! Permissions on files/folders
+ cmArchiveWriteOptional<int> Permissions;
+ cmArchiveWriteOptional<int> PermissionsMask;
+};
diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx
new file mode 100644
index 0000000..4624f1c
--- /dev/null
+++ b/Source/cmArgumentParser.cxx
@@ -0,0 +1,96 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmArgumentParser.h"
+
+#include <algorithm>
+
+namespace ArgumentParser {
+
+auto ActionMap::Emplace(cm::string_view name, Action action)
+ -> std::pair<iterator, bool>
+{
+ auto const it =
+ std::lower_bound(this->begin(), this->end(), name,
+ [](value_type const& elem, cm::string_view const& k) {
+ return elem.first < k;
+ });
+ return (it != this->end() && it->first == name)
+ ? std::make_pair(it, false)
+ : std::make_pair(this->emplace(it, name, std::move(action)), true);
+}
+
+auto ActionMap::Find(cm::string_view name) const -> const_iterator
+{
+ auto const it =
+ std::lower_bound(this->begin(), this->end(), name,
+ [](value_type const& elem, cm::string_view const& k) {
+ return elem.first < k;
+ });
+ return (it != this->end() && it->first == name) ? it : this->end();
+}
+
+void Instance::Bind(bool& val)
+{
+ val = true;
+ this->CurrentString = nullptr;
+ this->CurrentList = nullptr;
+ this->ExpectValue = false;
+}
+
+void Instance::Bind(std::string& val)
+{
+ this->CurrentString = &val;
+ this->CurrentList = nullptr;
+ this->ExpectValue = true;
+}
+
+void Instance::Bind(StringList& val)
+{
+ this->CurrentString = nullptr;
+ this->CurrentList = &val;
+ this->ExpectValue = true;
+}
+
+void Instance::Bind(MultiStringList& val)
+{
+ this->CurrentString = nullptr;
+ this->CurrentList = (static_cast<void>(val.emplace_back()), &val.back());
+ this->ExpectValue = false;
+}
+
+void Instance::Consume(cm::string_view arg, void* result,
+ std::vector<std::string>* unparsedArguments,
+ std::vector<std::string>* keywordsMissingValue,
+ std::vector<std::string>* parsedKeywords)
+{
+ auto const it = this->Bindings.Find(arg);
+ if (it != this->Bindings.end()) {
+ if (parsedKeywords != nullptr) {
+ parsedKeywords->emplace_back(arg);
+ }
+ it->second(*this, result);
+ if (this->ExpectValue && keywordsMissingValue != nullptr) {
+ keywordsMissingValue->emplace_back(arg);
+ }
+ return;
+ }
+
+ if (this->CurrentString != nullptr) {
+ this->CurrentString->assign(std::string(arg));
+ this->CurrentString = nullptr;
+ this->CurrentList = nullptr;
+ } else if (this->CurrentList != nullptr) {
+ this->CurrentList->emplace_back(arg);
+ } else if (unparsedArguments != nullptr) {
+ unparsedArguments->emplace_back(arg);
+ }
+
+ if (this->ExpectValue) {
+ if (keywordsMissingValue != nullptr) {
+ keywordsMissingValue->pop_back();
+ }
+ this->ExpectValue = false;
+ }
+}
+
+} // namespace ArgumentParser
diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h
new file mode 100644
index 0000000..71ed844
--- /dev/null
+++ b/Source/cmArgumentParser.h
@@ -0,0 +1,147 @@
+/* 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 <cassert>
+#include <functional>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/string_view>
+#include <cmext/string_view>
+
+namespace ArgumentParser {
+
+using StringList = std::vector<std::string>;
+using MultiStringList = std::vector<StringList>;
+
+class Instance;
+using Action = std::function<void(Instance&, void*)>;
+
+// using ActionMap = cm::flat_map<cm::string_view, Action>;
+class ActionMap : public std::vector<std::pair<cm::string_view, Action>>
+{
+public:
+ std::pair<iterator, bool> Emplace(cm::string_view name, Action action);
+ const_iterator Find(cm::string_view name) const;
+};
+
+class Instance
+{
+public:
+ Instance(ActionMap const& bindings)
+ : Bindings(bindings)
+ {
+ }
+
+ void Bind(bool& val);
+ void Bind(std::string& val);
+ void Bind(StringList& val);
+ void Bind(MultiStringList& val);
+
+ void Consume(cm::string_view arg, void* result,
+ std::vector<std::string>* unparsedArguments,
+ std::vector<std::string>* keywordsMissingValue,
+ std::vector<std::string>* parsedKeywords);
+
+private:
+ ActionMap const& Bindings;
+ std::string* CurrentString = nullptr;
+ StringList* CurrentList = nullptr;
+ bool ExpectValue = false;
+};
+
+} // namespace ArgumentParser
+
+template <typename Result>
+class cmArgumentParser
+{
+public:
+ // I *think* this function could be made `constexpr` when the code is
+ // compiled as C++20. This would allow building a parser at compile time.
+ template <typename T>
+ cmArgumentParser& Bind(cm::static_string_view name, T Result::*member)
+ {
+ bool const inserted =
+ this->Bindings
+ .Emplace(name,
+ [member](ArgumentParser::Instance& instance, void* result) {
+ instance.Bind(static_cast<Result*>(result)->*member);
+ })
+ .second;
+ assert(inserted), (void)inserted;
+ return *this;
+ }
+
+ template <typename Range>
+ void Parse(Result& result, Range const& args,
+ std::vector<std::string>* unparsedArguments = nullptr,
+ std::vector<std::string>* keywordsMissingValue = nullptr,
+ std::vector<std::string>* parsedKeywords = nullptr) const
+ {
+ ArgumentParser::Instance instance(this->Bindings);
+ for (cm::string_view arg : args) {
+ instance.Consume(arg, &result, unparsedArguments, keywordsMissingValue,
+ parsedKeywords);
+ }
+ }
+
+ template <typename Range>
+ Result Parse(Range const& args,
+ std::vector<std::string>* unparsedArguments = nullptr,
+ std::vector<std::string>* keywordsMissingValue = nullptr,
+ std::vector<std::string>* parsedKeywords = nullptr) const
+ {
+ Result result;
+ this->Parse(result, args, unparsedArguments, keywordsMissingValue,
+ parsedKeywords);
+ return result;
+ }
+
+private:
+ ArgumentParser::ActionMap Bindings;
+};
+
+template <>
+class cmArgumentParser<void>
+{
+public:
+ template <typename T>
+ cmArgumentParser& Bind(cm::static_string_view name, T& ref)
+ {
+ bool const inserted = this->Bind(cm::string_view(name), ref);
+ assert(inserted), (void)inserted;
+ return *this;
+ }
+
+ template <typename Range>
+ void Parse(Range const& args,
+ std::vector<std::string>* unparsedArguments = nullptr,
+ std::vector<std::string>* keywordsMissingValue = nullptr,
+ std::vector<std::string>* parsedKeywords = nullptr) const
+ {
+ ArgumentParser::Instance instance(this->Bindings);
+ for (cm::string_view arg : args) {
+ instance.Consume(arg, nullptr, unparsedArguments, keywordsMissingValue,
+ parsedKeywords);
+ }
+ }
+
+protected:
+ template <typename T>
+ bool Bind(cm::string_view name, T& ref)
+ {
+ return this->Bindings
+ .Emplace(name,
+ [&ref](ArgumentParser::Instance& instance, void*) {
+ instance.Bind(ref);
+ })
+ .second;
+ }
+
+private:
+ ArgumentParser::ActionMap Bindings;
+};
diff --git a/Source/cmAuxSourceDirectoryCommand.cxx b/Source/cmAuxSourceDirectoryCommand.cxx
new file mode 100644
index 0000000..35f4c88
--- /dev/null
+++ b/Source/cmAuxSourceDirectoryCommand.cxx
@@ -0,0 +1,73 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmAuxSourceDirectoryCommand.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <utility>
+
+#include <cm/string_view>
+
+#include "cmsys/Directory.hxx"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+bool cmAuxSourceDirectoryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ std::string sourceListValue;
+ std::string const& templateDirectory = args[0];
+ std::string tdir;
+ if (!cmSystemTools::FileIsFullPath(templateDirectory)) {
+ tdir = cmStrCat(mf.GetCurrentSourceDirectory(), '/', templateDirectory);
+ } else {
+ tdir = templateDirectory;
+ }
+
+ // was the list already populated
+ sourceListValue = mf.GetSafeDefinition(args[1]);
+
+ std::vector<std::string> files;
+
+ // Load all the files in the directory
+ cmsys::Directory dir;
+ if (dir.Load(tdir)) {
+ size_t numfiles = dir.GetNumberOfFiles();
+ for (size_t i = 0; i < numfiles; ++i) {
+ std::string file = dir.GetFile(static_cast<unsigned long>(i));
+ // Split the filename into base and extension
+ std::string::size_type dotpos = file.rfind('.');
+ if (dotpos != std::string::npos) {
+ auto ext = cm::string_view(file).substr(dotpos + 1);
+ // Process only source files
+ auto* cm = mf.GetCMakeInstance();
+ if (dotpos > 0 && cm->IsACLikeSourceExtension(ext)) {
+ std::string fullname = cmStrCat(templateDirectory, '/', file);
+ // add the file as a class file so
+ // depends can be done
+ cmSourceFile* sf = mf.GetOrCreateSource(fullname);
+ sf->SetProperty("ABSTRACT", "0");
+ files.push_back(std::move(fullname));
+ }
+ }
+ }
+ }
+ std::sort(files.begin(), files.end());
+ if (!sourceListValue.empty()) {
+ sourceListValue += ";";
+ }
+ sourceListValue += cmJoin(files, ";");
+ mf.AddDefinition(args[1], sourceListValue);
+ return true;
+}
diff --git a/Source/cmAuxSourceDirectoryCommand.h b/Source/cmAuxSourceDirectoryCommand.h
new file mode 100644
index 0000000..29ee429
--- /dev/null
+++ b/Source/cmAuxSourceDirectoryCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmAuxSourceDirectoryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmBase32.cxx b/Source/cmBase32.cxx
new file mode 100644
index 0000000..a9c15c2
--- /dev/null
+++ b/Source/cmBase32.cxx
@@ -0,0 +1,93 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmBase32.h"
+
+// -- Static functions
+
+static const unsigned char Base32EncodeTable[33] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+
+inline unsigned char Base32EncodeChar(int schar)
+{
+ return Base32EncodeTable[schar];
+}
+
+void Base32Encode5(const unsigned char src[5], char dst[8])
+{
+ // [0]:5 bits
+ dst[0] = Base32EncodeChar((src[0] >> 3) & 0x1F);
+ // [0]:3 bits + [1]:2 bits
+ dst[1] = Base32EncodeChar(((src[0] << 2) & 0x1C) + ((src[1] >> 6) & 0x03));
+ // [1]:5 bits
+ dst[2] = Base32EncodeChar((src[1] >> 1) & 0x1F);
+ // [1]:1 bit + [2]:4 bits
+ dst[3] = Base32EncodeChar(((src[1] << 4) & 0x10) + ((src[2] >> 4) & 0x0F));
+ // [2]:4 bits + [3]:1 bit
+ dst[4] = Base32EncodeChar(((src[2] << 1) & 0x1E) + ((src[3] >> 7) & 0x01));
+ // [3]:5 bits
+ dst[5] = Base32EncodeChar((src[3] >> 2) & 0x1F);
+ // [3]:2 bits + [4]:3 bit
+ dst[6] = Base32EncodeChar(((src[3] << 3) & 0x18) + ((src[4] >> 5) & 0x07));
+ // [4]:5 bits
+ dst[7] = Base32EncodeChar((src[4] << 0) & 0x1F);
+}
+
+// -- Class methods
+
+cmBase32Encoder::cmBase32Encoder() = default;
+
+std::string cmBase32Encoder::encodeString(const unsigned char* input,
+ size_t len, bool padding)
+{
+ std::string res;
+
+ static const size_t blockSize = 5;
+ static const size_t bufferSize = 8;
+ char buffer[bufferSize];
+
+ const unsigned char* end = input + len;
+ while ((input + blockSize) <= end) {
+ Base32Encode5(input, buffer);
+ res.append(buffer, bufferSize);
+ input += blockSize;
+ }
+
+ size_t remain = static_cast<size_t>(end - input);
+ if (remain != 0) {
+ // Temporary source buffer filled up with 0s
+ unsigned char extended[blockSize];
+ for (size_t ii = 0; ii != remain; ++ii) {
+ extended[ii] = input[ii];
+ }
+ for (size_t ii = remain; ii != blockSize; ++ii) {
+ extended[ii] = 0;
+ }
+
+ Base32Encode5(extended, buffer);
+ size_t numPad(0);
+ switch (remain) {
+ case 1:
+ numPad = 6;
+ break;
+ case 2:
+ numPad = 4;
+ break;
+ case 3:
+ numPad = 3;
+ break;
+ case 4:
+ numPad = 1;
+ break;
+ default:
+ break;
+ }
+ res.append(buffer, bufferSize - numPad);
+ if (padding) {
+ for (size_t ii = 0; ii != numPad; ++ii) {
+ res.push_back(paddingChar);
+ }
+ }
+ }
+
+ return res;
+}
diff --git a/Source/cmBase32.h b/Source/cmBase32.h
new file mode 100644
index 0000000..d70a062
--- /dev/null
+++ b/Source/cmBase32.h
@@ -0,0 +1,29 @@
+/* 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 <cstddef>
+#include <string>
+
+/** \class cmBase32Encoder
+ * \brief Encodes a byte sequence to a Base32 byte sequence according to
+ * RFC4648
+ *
+ */
+class cmBase32Encoder
+{
+public:
+ static const char paddingChar = '=';
+
+ cmBase32Encoder();
+ ~cmBase32Encoder() = default;
+
+ // Encodes the given input byte sequence into a string
+ // @arg input Input data pointer
+ // @arg len Input data size
+ // @arg padding Flag to append "=" on demand
+ std::string encodeString(const unsigned char* input, size_t len,
+ bool padding = true);
+};
diff --git a/Source/cmBinUtilsLinker.cxx b/Source/cmBinUtilsLinker.cxx
new file mode 100644
index 0000000..a9f4d91
--- /dev/null
+++ b/Source/cmBinUtilsLinker.cxx
@@ -0,0 +1,16 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsLinker.h"
+
+#include "cmRuntimeDependencyArchive.h"
+
+cmBinUtilsLinker::cmBinUtilsLinker(cmRuntimeDependencyArchive* archive)
+ : Archive(archive)
+{
+}
+
+void cmBinUtilsLinker::SetError(const std::string& e)
+{
+ this->Archive->SetError(e);
+}
diff --git a/Source/cmBinUtilsLinker.h b/Source/cmBinUtilsLinker.h
new file mode 100644
index 0000000..5330070
--- /dev/null
+++ b/Source/cmBinUtilsLinker.h
@@ -0,0 +1,27 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include <string>
+
+#include "cmStateTypes.h"
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsLinker
+{
+public:
+ cmBinUtilsLinker(cmRuntimeDependencyArchive* archive);
+ virtual ~cmBinUtilsLinker() = default;
+
+ virtual bool Prepare() { return true; }
+
+ virtual bool ScanDependencies(std::string const& file,
+ cmStateEnums::TargetType type) = 0;
+
+protected:
+ cmRuntimeDependencyArchive* Archive;
+
+ void SetError(const std::string& e);
+};
diff --git a/Source/cmBinUtilsLinuxELFGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsLinuxELFGetRuntimeDependenciesTool.cxx
new file mode 100644
index 0000000..abd1209
--- /dev/null
+++ b/Source/cmBinUtilsLinuxELFGetRuntimeDependenciesTool.cxx
@@ -0,0 +1,19 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h"
+
+#include "cmRuntimeDependencyArchive.h"
+
+cmBinUtilsLinuxELFGetRuntimeDependenciesTool::
+ cmBinUtilsLinuxELFGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive)
+ : Archive(archive)
+{
+}
+
+void cmBinUtilsLinuxELFGetRuntimeDependenciesTool::SetError(
+ const std::string& error)
+{
+ this->Archive->SetError(error);
+}
diff --git a/Source/cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h b/Source/cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h
new file mode 100644
index 0000000..15216a4
--- /dev/null
+++ b/Source/cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h
@@ -0,0 +1,27 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsLinuxELFGetRuntimeDependenciesTool
+{
+public:
+ cmBinUtilsLinuxELFGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive);
+ virtual ~cmBinUtilsLinuxELFGetRuntimeDependenciesTool() = default;
+
+ virtual bool GetFileInfo(std::string const& file,
+ std::vector<std::string>& needed,
+ std::vector<std::string>& rpaths,
+ std::vector<std::string>& runpaths) = 0;
+
+protected:
+ cmRuntimeDependencyArchive* Archive;
+
+ void SetError(const std::string& e);
+};
diff --git a/Source/cmBinUtilsLinuxELFLinker.cxx b/Source/cmBinUtilsLinuxELFLinker.cxx
new file mode 100644
index 0000000..9ce403d
--- /dev/null
+++ b/Source/cmBinUtilsLinuxELFLinker.cxx
@@ -0,0 +1,182 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsLinuxELFLinker.h"
+
+#include <sstream>
+
+#include <cm/memory>
+#include <cm/string_view>
+
+#include <cmsys/RegularExpression.hxx>
+
+#include "cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h"
+#include "cmLDConfigLDConfigTool.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmRuntimeDependencyArchive.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+static std::string ReplaceOrigin(const std::string& rpath,
+ const std::string& origin)
+{
+ static const cmsys::RegularExpression originRegex(
+ "(\\$ORIGIN)([^a-zA-Z0-9_]|$)");
+ static const cmsys::RegularExpression originCurlyRegex("\\${ORIGIN}");
+
+ cmsys::RegularExpressionMatch match;
+ if (originRegex.find(rpath.c_str(), match)) {
+ cm::string_view pathv(rpath);
+ auto begin = pathv.substr(0, match.start(1));
+ auto end = pathv.substr(match.end(1));
+ return cmStrCat(begin, origin, end);
+ }
+ if (originCurlyRegex.find(rpath.c_str(), match)) {
+ cm::string_view pathv(rpath);
+ auto begin = pathv.substr(0, match.start());
+ auto end = pathv.substr(match.end());
+ return cmStrCat(begin, origin, end);
+ }
+ return rpath;
+}
+
+cmBinUtilsLinuxELFLinker::cmBinUtilsLinuxELFLinker(
+ cmRuntimeDependencyArchive* archive)
+ : cmBinUtilsLinker(archive)
+{
+}
+
+bool cmBinUtilsLinuxELFLinker::Prepare()
+{
+ std::string tool = this->Archive->GetGetRuntimeDependenciesTool();
+ if (tool.empty()) {
+ tool = "objdump";
+ }
+ if (tool == "objdump") {
+ this->Tool =
+ cm::make_unique<cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool>(
+ this->Archive);
+ } else {
+ std::ostringstream e;
+ e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: " << tool;
+ this->SetError(e.str());
+ return false;
+ }
+
+ std::string ldConfigTool =
+ this->Archive->GetMakefile()->GetSafeDefinition("CMAKE_LDCONFIG_TOOL");
+ if (ldConfigTool.empty()) {
+ ldConfigTool = "ldconfig";
+ }
+ if (ldConfigTool == "ldconfig") {
+ this->LDConfigTool =
+ cm::make_unique<cmLDConfigLDConfigTool>(this->Archive);
+ } else {
+ std::ostringstream e;
+ e << "Invalid value for CMAKE_LDCONFIG_TOOL: " << ldConfigTool;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+}
+
+bool cmBinUtilsLinuxELFLinker::ScanDependencies(
+ std::string const& file, cmStateEnums::TargetType /* unused */)
+{
+ std::vector<std::string> parentRpaths;
+ return this->ScanDependencies(file, parentRpaths);
+}
+
+bool cmBinUtilsLinuxELFLinker::ScanDependencies(
+ std::string const& file, std::vector<std::string> const& parentRpaths)
+{
+ std::string origin = cmSystemTools::GetFilenamePath(file);
+ std::vector<std::string> needed;
+ std::vector<std::string> rpaths;
+ std::vector<std::string> runpaths;
+ if (!this->Tool->GetFileInfo(file, needed, rpaths, runpaths)) {
+ return false;
+ }
+ for (auto& runpath : runpaths) {
+ runpath = ReplaceOrigin(runpath, origin);
+ }
+ for (auto& rpath : rpaths) {
+ rpath = ReplaceOrigin(rpath, origin);
+ }
+
+ std::vector<std::string> searchPaths;
+ if (!runpaths.empty()) {
+ searchPaths = runpaths;
+ } else {
+ searchPaths = rpaths;
+ searchPaths.insert(searchPaths.end(), parentRpaths.begin(),
+ parentRpaths.end());
+ }
+
+ std::vector<std::string> ldConfigPaths;
+ if (!this->LDConfigTool->GetLDConfigPaths(ldConfigPaths)) {
+ return false;
+ }
+ searchPaths.insert(searchPaths.end(), ldConfigPaths.begin(),
+ ldConfigPaths.end());
+
+ for (auto const& dep : needed) {
+ if (!this->Archive->IsPreExcluded(dep)) {
+ std::string path;
+ bool resolved = false;
+ if (dep.find('/') != std::string::npos) {
+ this->SetError("Paths to dependencies are not supported");
+ return false;
+ }
+ if (!this->ResolveDependency(dep, searchPaths, path, resolved)) {
+ return false;
+ }
+ if (resolved) {
+ if (!this->Archive->IsPostExcluded(path)) {
+ bool unique;
+ this->Archive->AddResolvedPath(dep, path, unique);
+ if (unique && !this->ScanDependencies(path, rpaths)) {
+ return false;
+ }
+ }
+ } else {
+ this->Archive->AddUnresolvedPath(dep);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool cmBinUtilsLinuxELFLinker::ResolveDependency(
+ std::string const& name, std::vector<std::string> const& searchPaths,
+ std::string& path, bool& resolved)
+{
+ for (auto const& searchPath : searchPaths) {
+ path = cmStrCat(searchPath, '/', name);
+ if (cmSystemTools::PathExists(path)) {
+ resolved = true;
+ return true;
+ }
+ }
+
+ for (auto const& searchPath : this->Archive->GetSearchDirectories()) {
+ path = cmStrCat(searchPath, '/', name);
+ if (cmSystemTools::PathExists(path)) {
+ std::ostringstream warning;
+ warning << "Dependency " << name << " found in search directory:\n "
+ << searchPath
+ << "\nSee file(GET_RUNTIME_DEPENDENCIES) documentation for "
+ << "more information.";
+ this->Archive->GetMakefile()->IssueMessage(MessageType::WARNING,
+ warning.str());
+ resolved = true;
+ return true;
+ }
+ }
+
+ resolved = false;
+ return true;
+}
diff --git a/Source/cmBinUtilsLinuxELFLinker.h b/Source/cmBinUtilsLinuxELFLinker.h
new file mode 100644
index 0000000..4e7e36d
--- /dev/null
+++ b/Source/cmBinUtilsLinuxELFLinker.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 <memory>
+#include <string>
+#include <vector>
+
+#include "cmBinUtilsLinker.h"
+#include "cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h"
+#include "cmLDConfigTool.h"
+#include "cmStateTypes.h"
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsLinuxELFLinker : public cmBinUtilsLinker
+{
+public:
+ cmBinUtilsLinuxELFLinker(cmRuntimeDependencyArchive* archive);
+
+ bool Prepare() override;
+
+ bool ScanDependencies(std::string const& file,
+ cmStateEnums::TargetType type) override;
+
+private:
+ std::unique_ptr<cmBinUtilsLinuxELFGetRuntimeDependenciesTool> Tool;
+ std::unique_ptr<cmLDConfigTool> LDConfigTool;
+ bool HaveLDConfigPaths = false;
+ std::vector<std::string> LDConfigPaths;
+
+ bool ScanDependencies(std::string const& file,
+ std::vector<std::string> const& parentRpaths);
+
+ bool ResolveDependency(std::string const& name,
+ std::vector<std::string> const& searchPaths,
+ std::string& path, bool& resolved);
+
+ bool GetLDConfigPaths();
+};
diff --git a/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx
new file mode 100644
index 0000000..566e4a4
--- /dev/null
+++ b/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx
@@ -0,0 +1,85 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h"
+
+#include <sstream>
+
+#include <cmsys/RegularExpression.hxx>
+
+#include "cmRuntimeDependencyArchive.h"
+#include "cmSystemTools.h"
+#include "cmUVProcessChain.h"
+
+cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool::
+ cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive)
+ : cmBinUtilsLinuxELFGetRuntimeDependenciesTool(archive)
+{
+}
+
+bool cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool::GetFileInfo(
+ std::string const& file, std::vector<std::string>& needed,
+ std::vector<std::string>& rpaths, std::vector<std::string>& runpaths)
+{
+ cmUVProcessChainBuilder builder;
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
+
+ std::vector<std::string> command;
+ if (!this->Archive->GetGetRuntimeDependenciesCommand("objdump", command)) {
+ this->SetError("Could not find objdump");
+ return false;
+ }
+ command.emplace_back("-p");
+ command.push_back(file);
+ builder.AddCommand(command);
+
+ auto process = builder.Start();
+ if (!process.Valid()) {
+ std::ostringstream e;
+ e << "Failed to start objdump process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ std::string line;
+ static const cmsys::RegularExpression neededRegex("^ *NEEDED *([^\n]*)$");
+ static const cmsys::RegularExpression rpathRegex("^ *RPATH *([^\n]*)$");
+ static const cmsys::RegularExpression runpathRegex("^ *RUNPATH *([^\n]*)$");
+ while (std::getline(*process.OutputStream(), line)) {
+ cmsys::RegularExpressionMatch match;
+ if (neededRegex.find(line.c_str(), match)) {
+ needed.push_back(match.match(1));
+ } else if (rpathRegex.find(line.c_str(), match)) {
+ std::vector<std::string> rpathSplit =
+ cmSystemTools::SplitString(match.match(1), ':');
+ rpaths.reserve(rpaths.size() + rpathSplit.size());
+ for (auto const& rpath : rpathSplit) {
+ rpaths.push_back(rpath);
+ }
+ } else if (runpathRegex.find(line.c_str(), match)) {
+ std::vector<std::string> runpathSplit =
+ cmSystemTools::SplitString(match.match(1), ':');
+ runpaths.reserve(runpaths.size() + runpathSplit.size());
+ for (auto const& runpath : runpathSplit) {
+ runpaths.push_back(runpath);
+ }
+ }
+ }
+
+ if (!process.Wait()) {
+ std::ostringstream e;
+ e << "Failed to wait on objdump process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+ auto status = process.GetStatus();
+ if (!status[0] || status[0]->ExitStatus != 0) {
+ std::ostringstream e;
+ e << "Failed to run objdump on:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h b/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h
new file mode 100644
index 0000000..def1dd0
--- /dev/null
+++ b/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h
@@ -0,0 +1,23 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h"
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool
+ : public cmBinUtilsLinuxELFGetRuntimeDependenciesTool
+{
+public:
+ cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive);
+
+ bool GetFileInfo(std::string const& file, std::vector<std::string>& needed,
+ std::vector<std::string>& rpaths,
+ std::vector<std::string>& runpaths) override;
+};
diff --git a/Source/cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.cxx
new file mode 100644
index 0000000..a296a47
--- /dev/null
+++ b/Source/cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.cxx
@@ -0,0 +1,19 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h"
+
+#include "cmRuntimeDependencyArchive.h"
+
+cmBinUtilsMacOSMachOGetRuntimeDependenciesTool::
+ cmBinUtilsMacOSMachOGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive)
+ : Archive(archive)
+{
+}
+
+void cmBinUtilsMacOSMachOGetRuntimeDependenciesTool::SetError(
+ const std::string& error)
+{
+ this->Archive->SetError(error);
+}
diff --git a/Source/cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h b/Source/cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h
new file mode 100644
index 0000000..60d34aa
--- /dev/null
+++ b/Source/cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h
@@ -0,0 +1,26 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsMacOSMachOGetRuntimeDependenciesTool
+{
+public:
+ cmBinUtilsMacOSMachOGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive);
+ virtual ~cmBinUtilsMacOSMachOGetRuntimeDependenciesTool() = default;
+
+ virtual bool GetFileInfo(std::string const& file,
+ std::vector<std::string>& libs,
+ std::vector<std::string>& rpaths) = 0;
+
+protected:
+ cmRuntimeDependencyArchive* Archive;
+
+ void SetError(const std::string& error);
+};
diff --git a/Source/cmBinUtilsMacOSMachOLinker.cxx b/Source/cmBinUtilsMacOSMachOLinker.cxx
new file mode 100644
index 0000000..0f47146
--- /dev/null
+++ b/Source/cmBinUtilsMacOSMachOLinker.cxx
@@ -0,0 +1,244 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsMacOSMachOLinker.h"
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h"
+#include "cmRuntimeDependencyArchive.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+bool IsMissingSystemDylib(std::string const& path)
+{
+ // Starting on macOS 11, the dynamic loader has a builtin cache of
+ // system-provided dylib files that do not exist on the filesystem.
+ // Tell our caller that these are expected to be missing.
+ return ((cmHasLiteralPrefix(path, "/System/Library/") ||
+ cmHasLiteralPrefix(path, "/usr/lib/")) &&
+ !cmSystemTools::PathExists(path));
+}
+}
+
+cmBinUtilsMacOSMachOLinker::cmBinUtilsMacOSMachOLinker(
+ cmRuntimeDependencyArchive* archive)
+ : cmBinUtilsLinker(archive)
+{
+}
+
+bool cmBinUtilsMacOSMachOLinker::Prepare()
+{
+ std::string tool = this->Archive->GetGetRuntimeDependenciesTool();
+ if (tool.empty()) {
+ tool = "otool";
+ }
+ if (tool == "otool") {
+ this->Tool =
+ cm::make_unique<cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool>(
+ this->Archive);
+ } else {
+ std::ostringstream e;
+ e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: " << tool;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+}
+
+bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
+ std::string const& file, cmStateEnums::TargetType type)
+{
+ std::string executableFile;
+ if (type == cmStateEnums::EXECUTABLE) {
+ executableFile = file;
+ } else {
+ executableFile = this->Archive->GetBundleExecutable();
+ }
+ std::string executablePath;
+ if (!executableFile.empty()) {
+ executablePath = cmSystemTools::GetFilenamePath(executableFile);
+ }
+ return this->ScanDependencies(file, executablePath);
+}
+
+bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
+ std::string const& file, std::string const& executablePath)
+{
+ std::vector<std::string> libs;
+ std::vector<std::string> rpaths;
+ if (!this->Tool->GetFileInfo(file, libs, rpaths)) {
+ return false;
+ }
+
+ std::string loaderPath = cmSystemTools::GetFilenamePath(file);
+ return this->GetFileDependencies(libs, executablePath, loaderPath, rpaths);
+}
+
+bool cmBinUtilsMacOSMachOLinker::GetFileDependencies(
+ std::vector<std::string> const& names, std::string const& executablePath,
+ std::string const& loaderPath, std::vector<std::string> const& rpaths)
+{
+ for (std::string const& name : names) {
+ if (!this->Archive->IsPreExcluded(name)) {
+ std::string path;
+ bool resolved;
+ if (!this->ResolveDependency(name, executablePath, loaderPath, rpaths,
+ path, resolved)) {
+ return false;
+ }
+ if (resolved) {
+ if (!this->Archive->IsPostExcluded(path) &&
+ !IsMissingSystemDylib(path)) {
+ auto filename = cmSystemTools::GetFilenameName(path);
+ bool unique;
+ this->Archive->AddResolvedPath(filename, path, unique);
+ if (unique && !this->ScanDependencies(path, executablePath)) {
+ return false;
+ }
+ }
+ } else {
+ this->Archive->AddUnresolvedPath(name);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool cmBinUtilsMacOSMachOLinker::ResolveDependency(
+ std::string const& name, std::string const& executablePath,
+ std::string const& loaderPath, std::vector<std::string> const& rpaths,
+ std::string& path, bool& resolved)
+{
+ resolved = false;
+ if (cmHasLiteralPrefix(name, "@rpath/")) {
+ if (!this->ResolveRPathDependency(name, executablePath, loaderPath, rpaths,
+ path, resolved)) {
+ return false;
+ }
+ } else if (cmHasLiteralPrefix(name, "@loader_path/")) {
+ if (!this->ResolveLoaderPathDependency(name, loaderPath, path, resolved)) {
+ return false;
+ }
+ } else if (cmHasLiteralPrefix(name, "@executable_path/")) {
+ if (!this->ResolveExecutablePathDependency(name, executablePath, path,
+ resolved)) {
+ return false;
+ }
+ } else {
+ resolved = true;
+ path = name;
+ }
+
+ if (resolved && !cmSystemTools::FileIsFullPath(path)) {
+ this->SetError("Resolved path is not absolute");
+ return false;
+ }
+
+ return true;
+}
+
+bool cmBinUtilsMacOSMachOLinker::ResolveExecutablePathDependency(
+ std::string const& name, std::string const& executablePath,
+ std::string& path, bool& resolved)
+{
+ if (executablePath.empty()) {
+ resolved = false;
+ return true;
+ }
+
+ // 16 is == "@executable_path".length()
+ path = name;
+ path.replace(0, 16, executablePath);
+
+ if (!cmSystemTools::PathExists(path)) {
+ resolved = false;
+ return true;
+ }
+
+ resolved = true;
+ return true;
+}
+
+bool cmBinUtilsMacOSMachOLinker::ResolveLoaderPathDependency(
+ std::string const& name, std::string const& loaderPath, std::string& path,
+ bool& resolved)
+{
+ if (loaderPath.empty()) {
+ resolved = false;
+ return true;
+ }
+
+ // 12 is "@loader_path".length();
+ path = name;
+ path.replace(0, 12, loaderPath);
+
+ if (!cmSystemTools::PathExists(path)) {
+ resolved = false;
+ return true;
+ }
+
+ resolved = true;
+ return true;
+}
+
+bool cmBinUtilsMacOSMachOLinker::ResolveRPathDependency(
+ std::string const& name, std::string const& executablePath,
+ std::string const& loaderPath, std::vector<std::string> const& rpaths,
+ std::string& path, bool& resolved)
+{
+ for (std::string const& rpath : rpaths) {
+ std::string searchFile = name;
+ searchFile.replace(0, 6, rpath);
+ if (cmHasLiteralPrefix(searchFile, "@loader_path/")) {
+ if (!this->ResolveLoaderPathDependency(searchFile, loaderPath, path,
+ resolved)) {
+ return false;
+ }
+ if (resolved) {
+ return true;
+ }
+ } else if (cmHasLiteralPrefix(searchFile, "@executable_path/")) {
+ if (!this->ResolveExecutablePathDependency(searchFile, executablePath,
+ path, resolved)) {
+ return false;
+ }
+ if (resolved) {
+ return true;
+ }
+ } else if (cmSystemTools::PathExists(searchFile)) {
+ /*
+ * paraphrasing @ben.boeckel:
+ * if /b/libB.dylib is supposed to be used,
+ * /a/libbB.dylib will be found first if it exists. CMake tries to
+ * sort rpath directories to avoid this, but sometimes there is no
+ * right answer.
+ *
+ * I believe it is possible to resolve this using otools -l
+ * then checking the LC_LOAD_DYLIB command whose name is
+ * equal to the value of search_file, UNLESS the build
+ * specifically sets the RPath to paths that will match
+ * duplicate libs; at this point can we just point to
+ * user error, or is there a reason why the advantages
+ * to this scenario outweigh its disadvantages?
+ *
+ * Also priority seems to be the order as passed in when compiled
+ * so as long as this method's resolution guarantees priority
+ * in that manner further checking should not be necessary?
+ */
+ path = searchFile;
+ resolved = true;
+ return true;
+ }
+ }
+
+ resolved = false;
+ return true;
+}
diff --git a/Source/cmBinUtilsMacOSMachOLinker.h b/Source/cmBinUtilsMacOSMachOLinker.h
new file mode 100644
index 0000000..1c4a5fc
--- /dev/null
+++ b/Source/cmBinUtilsMacOSMachOLinker.h
@@ -0,0 +1,56 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "cmBinUtilsLinker.h"
+#include "cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h"
+#include "cmStateTypes.h"
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsMacOSMachOLinker : public cmBinUtilsLinker
+{
+public:
+ cmBinUtilsMacOSMachOLinker(cmRuntimeDependencyArchive* archive);
+
+ bool Prepare() override;
+
+ bool ScanDependencies(std::string const& file,
+ cmStateEnums::TargetType type) override;
+
+private:
+ std::unique_ptr<cmBinUtilsMacOSMachOGetRuntimeDependenciesTool> Tool;
+
+ bool ScanDependencies(std::string const& file,
+ std::string const& executablePath);
+
+ bool GetFileDependencies(std::vector<std::string> const& names,
+ std::string const& executablePath,
+ std::string const& loaderPath,
+ std::vector<std::string> const& rpaths);
+
+ bool ResolveDependency(std::string const& name,
+ std::string const& executablePath,
+ std::string const& loaderPath,
+ std::vector<std::string> const& rpaths,
+ std::string& path, bool& resolved);
+
+ bool ResolveExecutablePathDependency(std::string const& name,
+ std::string const& executablePath,
+ std::string& path, bool& resolved);
+
+ bool ResolveLoaderPathDependency(std::string const& name,
+ std::string const& loaderPath,
+ std::string& path, bool& resolved);
+
+ bool ResolveRPathDependency(std::string const& name,
+ std::string const& executablePath,
+ std::string const& loaderPath,
+ std::vector<std::string> const& rpaths,
+ std::string& path, bool& resolved);
+};
diff --git a/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx
new file mode 100644
index 0000000..6d97720
--- /dev/null
+++ b/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx
@@ -0,0 +1,100 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h"
+
+#include <sstream>
+
+#include <cmsys/RegularExpression.hxx>
+
+#include "cmRuntimeDependencyArchive.h"
+#include "cmUVProcessChain.h"
+
+cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool::
+ cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive)
+ : cmBinUtilsMacOSMachOGetRuntimeDependenciesTool(archive)
+{
+}
+
+bool cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool::GetFileInfo(
+ std::string const& file, std::vector<std::string>& libs,
+ std::vector<std::string>& rpaths)
+{
+ std::vector<std::string> command;
+ if (!this->Archive->GetGetRuntimeDependenciesCommand("otool", command)) {
+ this->SetError("Could not find otool");
+ return false;
+ }
+ command.emplace_back("-l");
+ command.emplace_back(file);
+
+ cmUVProcessChainBuilder builder;
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
+ .AddCommand(command);
+
+ auto process = builder.Start();
+ if (!process.Valid()) {
+ std::ostringstream e;
+ e << "Failed to start otool process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ std::string line;
+ static const cmsys::RegularExpression rpathRegex("^ *cmd LC_RPATH$");
+ static const cmsys::RegularExpression loadDylibRegex(
+ "^ *cmd LC_LOAD(_WEAK)?_DYLIB$");
+ static const cmsys::RegularExpression pathRegex(
+ "^ *path (.*) \\(offset [0-9]+\\)$");
+ static const cmsys::RegularExpression nameRegex(
+ "^ *name (.*) \\(offset [0-9]+\\)$");
+ while (std::getline(*process.OutputStream(), line)) {
+ cmsys::RegularExpressionMatch cmdMatch;
+ if (rpathRegex.find(line.c_str(), cmdMatch)) {
+ if (!std::getline(*process.OutputStream(), line) ||
+ !std::getline(*process.OutputStream(), line)) {
+ this->SetError("Invalid output from otool");
+ return false;
+ }
+
+ cmsys::RegularExpressionMatch pathMatch;
+ if (pathRegex.find(line.c_str(), pathMatch)) {
+ rpaths.push_back(pathMatch.match(1));
+ } else {
+ this->SetError("Invalid output from otool");
+ return false;
+ }
+ } else if (loadDylibRegex.find(line.c_str(), cmdMatch)) {
+ if (!std::getline(*process.OutputStream(), line) ||
+ !std::getline(*process.OutputStream(), line)) {
+ this->SetError("Invalid output from otool");
+ return false;
+ }
+
+ cmsys::RegularExpressionMatch nameMatch;
+ if (nameRegex.find(line.c_str(), nameMatch)) {
+ libs.push_back(nameMatch.match(1));
+ } else {
+ this->SetError("Invalid output from otool");
+ return false;
+ }
+ }
+ }
+
+ if (!process.Wait()) {
+ std::ostringstream e;
+ e << "Failed to wait on otool process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+ auto status = process.GetStatus();
+ if (!status[0] || status[0]->ExitStatus != 0) {
+ std::ostringstream e;
+ e << "Failed to run otool on:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h b/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h
new file mode 100644
index 0000000..9d17450
--- /dev/null
+++ b/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h
@@ -0,0 +1,22 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h"
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool
+ : public cmBinUtilsMacOSMachOGetRuntimeDependenciesTool
+{
+public:
+ cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive);
+
+ bool GetFileInfo(std::string const& file, std::vector<std::string>& libs,
+ std::vector<std::string>& rpaths) override;
+};
diff --git a/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx
new file mode 100644
index 0000000..f342884
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx
@@ -0,0 +1,68 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h"
+
+#include <sstream>
+
+#include <cmsys/RegularExpression.hxx>
+
+#include "cmRuntimeDependencyArchive.h"
+#include "cmUVProcessChain.h"
+
+cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool::
+ cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive)
+ : cmBinUtilsWindowsPEGetRuntimeDependenciesTool(archive)
+{
+}
+
+bool cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool::GetFileInfo(
+ const std::string& file, std::vector<std::string>& needed)
+{
+ cmUVProcessChainBuilder builder;
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
+
+ std::vector<std::string> command;
+ if (!this->Archive->GetGetRuntimeDependenciesCommand("dumpbin", command)) {
+ this->SetError("Could not find dumpbin");
+ return false;
+ }
+ command.emplace_back("/dependents");
+ command.push_back(file);
+ builder.AddCommand(command);
+
+ auto process = builder.Start();
+ if (!process.Valid()) {
+ std::ostringstream e;
+ e << "Failed to start dumpbin process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ std::string line;
+ static const cmsys::RegularExpression regex(
+ "^ ([^\n]*\\.[Dd][Ll][Ll])\r$");
+ while (std::getline(*process.OutputStream(), line)) {
+ cmsys::RegularExpressionMatch match;
+ if (regex.find(line.c_str(), match)) {
+ needed.push_back(match.match(1));
+ }
+ }
+
+ if (!process.Wait()) {
+ std::ostringstream e;
+ e << "Failed to wait on dumpbin process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+ auto status = process.GetStatus();
+ if (!status[0] || status[0]->ExitStatus != 0) {
+ std::ostringstream e;
+ e << "Failed to run dumpbin on:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h b/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h
new file mode 100644
index 0000000..8609479
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h
@@ -0,0 +1,22 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h"
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool
+ : public cmBinUtilsWindowsPEGetRuntimeDependenciesTool
+{
+public:
+ cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive);
+
+ bool GetFileInfo(const std::string& file,
+ std::vector<std::string>& needed) override;
+};
diff --git a/Source/cmBinUtilsWindowsPEGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsWindowsPEGetRuntimeDependenciesTool.cxx
new file mode 100644
index 0000000..468a40c
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPEGetRuntimeDependenciesTool.cxx
@@ -0,0 +1,19 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h"
+
+#include "cmRuntimeDependencyArchive.h"
+
+cmBinUtilsWindowsPEGetRuntimeDependenciesTool::
+ cmBinUtilsWindowsPEGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive)
+ : Archive(archive)
+{
+}
+
+void cmBinUtilsWindowsPEGetRuntimeDependenciesTool::SetError(
+ const std::string& error)
+{
+ this->Archive->SetError(error);
+}
diff --git a/Source/cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h b/Source/cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h
new file mode 100644
index 0000000..da71aaa
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h
@@ -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. */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsWindowsPEGetRuntimeDependenciesTool
+{
+public:
+ cmBinUtilsWindowsPEGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive);
+ virtual ~cmBinUtilsWindowsPEGetRuntimeDependenciesTool() = default;
+
+ virtual bool GetFileInfo(const std::string& file,
+ std::vector<std::string>& needed) = 0;
+
+protected:
+ cmRuntimeDependencyArchive* Archive;
+
+ void SetError(const std::string& error);
+};
diff --git a/Source/cmBinUtilsWindowsPELinker.cxx b/Source/cmBinUtilsWindowsPELinker.cxx
new file mode 100644
index 0000000..79e39e9
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPELinker.cxx
@@ -0,0 +1,123 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsWindowsPELinker.h"
+
+#include <sstream>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h"
+#include "cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h"
+#include "cmRuntimeDependencyArchive.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+#ifdef _WIN32
+# include <windows.h>
+#endif
+
+cmBinUtilsWindowsPELinker::cmBinUtilsWindowsPELinker(
+ cmRuntimeDependencyArchive* archive)
+ : cmBinUtilsLinker(archive)
+{
+}
+
+bool cmBinUtilsWindowsPELinker::Prepare()
+{
+ std::string tool = this->Archive->GetGetRuntimeDependenciesTool();
+ if (tool.empty()) {
+ std::vector<std::string> command;
+ if (this->Archive->GetGetRuntimeDependenciesCommand("dumpbin", command)) {
+ tool = "dumpbin";
+ } else {
+ tool = "objdump";
+ }
+ }
+ if (tool == "dumpbin") {
+ this->Tool =
+ cm::make_unique<cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool>(
+ this->Archive);
+ } else if (tool == "objdump") {
+ this->Tool =
+ cm::make_unique<cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool>(
+ this->Archive);
+ } else {
+ std::ostringstream e;
+ e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: " << tool;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+}
+
+bool cmBinUtilsWindowsPELinker::ScanDependencies(
+ std::string const& file, cmStateEnums::TargetType /* unused */)
+{
+ std::vector<std::string> needed;
+ if (!this->Tool->GetFileInfo(file, needed)) {
+ return false;
+ }
+ for (auto& n : needed) {
+ n = cmSystemTools::LowerCase(n);
+ }
+ std::string origin = cmSystemTools::GetFilenamePath(file);
+
+ for (auto const& lib : needed) {
+ if (!this->Archive->IsPreExcluded(lib)) {
+ std::string path;
+ bool resolved = false;
+ if (!this->ResolveDependency(lib, origin, path, resolved)) {
+ return false;
+ }
+ if (resolved) {
+ if (!this->Archive->IsPostExcluded(path)) {
+ bool unique;
+ this->Archive->AddResolvedPath(lib, path, unique);
+ if (unique &&
+ !this->ScanDependencies(path, cmStateEnums::SHARED_LIBRARY)) {
+ return false;
+ }
+ }
+ } else {
+ this->Archive->AddUnresolvedPath(lib);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool cmBinUtilsWindowsPELinker::ResolveDependency(std::string const& name,
+ std::string const& origin,
+ std::string& path,
+ bool& resolved)
+{
+ auto dirs = this->Archive->GetSearchDirectories();
+
+#ifdef _WIN32
+ char buf[MAX_PATH];
+ unsigned int len;
+ if ((len = GetWindowsDirectoryA(buf, MAX_PATH)) > 0) {
+ dirs.insert(dirs.begin(), std::string(buf, len));
+ }
+ if ((len = GetSystemDirectoryA(buf, MAX_PATH)) > 0) {
+ dirs.insert(dirs.begin(), std::string(buf, len));
+ }
+#endif
+
+ dirs.insert(dirs.begin(), origin);
+
+ for (auto const& searchPath : dirs) {
+ path = cmStrCat(searchPath, '/', name);
+ if (cmSystemTools::PathExists(path)) {
+ resolved = true;
+ return true;
+ }
+ }
+
+ resolved = false;
+ return true;
+}
diff --git a/Source/cmBinUtilsWindowsPELinker.h b/Source/cmBinUtilsWindowsPELinker.h
new file mode 100644
index 0000000..6bb7875
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPELinker.h
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "cmBinUtilsLinker.h"
+#include "cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h"
+#include "cmStateTypes.h"
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsWindowsPELinker : public cmBinUtilsLinker
+{
+public:
+ cmBinUtilsWindowsPELinker(cmRuntimeDependencyArchive* archive);
+
+ bool Prepare() override;
+
+ bool ScanDependencies(std::string const& file,
+ cmStateEnums::TargetType type) override;
+
+private:
+ std::unique_ptr<cmBinUtilsWindowsPEGetRuntimeDependenciesTool> Tool;
+
+ bool ResolveDependency(std::string const& name, std::string const& origin,
+ std::string& path, bool& resolved);
+};
diff --git a/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
new file mode 100644
index 0000000..1effda0
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
@@ -0,0 +1,68 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h"
+
+#include <sstream>
+
+#include <cmsys/RegularExpression.hxx>
+
+#include "cmRuntimeDependencyArchive.h"
+#include "cmUVProcessChain.h"
+
+cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool::
+ cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive)
+ : cmBinUtilsWindowsPEGetRuntimeDependenciesTool(archive)
+{
+}
+
+bool cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool::GetFileInfo(
+ const std::string& file, std::vector<std::string>& needed)
+{
+ cmUVProcessChainBuilder builder;
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
+
+ std::vector<std::string> command;
+ if (!this->Archive->GetGetRuntimeDependenciesCommand("objdump", command)) {
+ this->SetError("Could not find objdump");
+ return false;
+ }
+ command.emplace_back("-p");
+ command.push_back(file);
+ builder.AddCommand(command);
+
+ auto process = builder.Start();
+ if (!process.Valid()) {
+ std::ostringstream e;
+ e << "Failed to start objdump process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ std::string line;
+ static const cmsys::RegularExpression regex(
+ "^\t*DLL Name: ([^\n]*\\.[Dd][Ll][Ll])\r$");
+ while (std::getline(*process.OutputStream(), line)) {
+ cmsys::RegularExpressionMatch match;
+ if (regex.find(line.c_str(), match)) {
+ needed.push_back(match.match(1));
+ }
+ }
+
+ if (!process.Wait()) {
+ std::ostringstream e;
+ e << "Failed to wait on objdump process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+ auto status = process.GetStatus();
+ if (!status[0] || status[0]->ExitStatus != 0) {
+ std::ostringstream e;
+ e << "Failed to run objdump on:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h b/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
new file mode 100644
index 0000000..fe89a2d
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
@@ -0,0 +1,22 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h"
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool
+ : public cmBinUtilsWindowsPEGetRuntimeDependenciesTool
+{
+public:
+ cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive);
+
+ bool GetFileInfo(const std::string& file,
+ std::vector<std::string>& needed) override;
+};
diff --git a/Source/cmBreakCommand.cxx b/Source/cmBreakCommand.cxx
new file mode 100644
index 0000000..95db689
--- /dev/null
+++ b/Source/cmBreakCommand.cxx
@@ -0,0 +1,74 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmBreakCommand.h"
+
+#include <sstream>
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+
+// cmBreakCommand
+bool cmBreakCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (!status.GetMakefile().IsLoopBlock()) {
+ bool issueMessage = true;
+ std::ostringstream e;
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+ switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0055)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0055) << "\n";
+ break;
+ case cmPolicies::OLD:
+ issueMessage = false;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ messageType = MessageType::FATAL_ERROR;
+ break;
+ }
+
+ if (issueMessage) {
+ e << "A BREAK command was found outside of a proper "
+ "FOREACH or WHILE loop scope.";
+ status.GetMakefile().IssueMessage(messageType, e.str());
+ if (messageType == MessageType::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+
+ status.SetBreakInvoked();
+
+ if (!args.empty()) {
+ bool issueMessage = true;
+ std::ostringstream e;
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+ switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0055)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0055) << "\n";
+ break;
+ case cmPolicies::OLD:
+ issueMessage = false;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ messageType = MessageType::FATAL_ERROR;
+ break;
+ }
+
+ if (issueMessage) {
+ e << "The BREAK command does not accept any arguments.";
+ status.GetMakefile().IssueMessage(messageType, e.str());
+ if (messageType == MessageType::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/Source/cmBreakCommand.h b/Source/cmBreakCommand.h
new file mode 100644
index 0000000..6241867
--- /dev/null
+++ b/Source/cmBreakCommand.h
@@ -0,0 +1,18 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Break from an enclosing foreach or while loop
+ *
+ * cmBreakCommand returns from an enclosing foreach or while loop
+ */
+bool cmBreakCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmBuildCommand.cxx b/Source/cmBuildCommand.cxx
new file mode 100644
index 0000000..2eaf315
--- /dev/null
+++ b/Source/cmBuildCommand.cxx
@@ -0,0 +1,130 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmBuildCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+
+bool MainSignature(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("requires at least one argument naming a CMake variable");
+ return false;
+ }
+
+ // The cmake variable in which to store the result.
+ std::string const& variable = args[0];
+
+ // Parse remaining arguments.
+ std::string configuration;
+ std::string project_name;
+ std::string target;
+ enum Doing
+ {
+ DoingNone,
+ DoingConfiguration,
+ DoingProjectName,
+ DoingTarget
+ };
+ Doing doing = DoingNone;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "CONFIGURATION") {
+ doing = DoingConfiguration;
+ } else if (args[i] == "PROJECT_NAME") {
+ doing = DoingProjectName;
+ } else if (args[i] == "TARGET") {
+ doing = DoingTarget;
+ } else if (doing == DoingConfiguration) {
+ doing = DoingNone;
+ configuration = args[i];
+ } else if (doing == DoingProjectName) {
+ doing = DoingNone;
+ project_name = args[i];
+ } else if (doing == DoingTarget) {
+ doing = DoingNone;
+ target = args[i];
+ } else {
+ status.SetError(cmStrCat("unknown argument \"", args[i], "\""));
+ return false;
+ }
+ }
+
+ // If null/empty CONFIGURATION argument, cmake --build uses 'Debug'
+ // in the currently implemented multi-configuration global generators...
+ // so we put this code here to end up with the same default configuration
+ // as the original 2-arg build_command signature:
+ //
+ if (configuration.empty()) {
+ cmSystemTools::GetEnv("CMAKE_CONFIG_TYPE", configuration);
+ }
+ if (configuration.empty()) {
+ configuration = "Release";
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ if (!project_name.empty()) {
+ mf.IssueMessage(MessageType::AUTHOR_WARNING,
+ "Ignoring PROJECT_NAME option because it has no effect.");
+ }
+
+ std::string makecommand = mf.GetGlobalGenerator()->GenerateCMakeBuildCommand(
+ target, configuration, "", mf.IgnoreErrorsCMP0061());
+
+ mf.AddDefinition(variable, makecommand);
+
+ return true;
+}
+
+bool TwoArgsSignature(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with less than two arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ std::string const& define = args[0];
+ cmProp cacheValue = mf.GetDefinition(define);
+
+ std::string configType;
+ if (!cmSystemTools::GetEnv("CMAKE_CONFIG_TYPE", configType) ||
+ configType.empty()) {
+ configType = "Release";
+ }
+
+ std::string makecommand = mf.GetGlobalGenerator()->GenerateCMakeBuildCommand(
+ "", configType, "", mf.IgnoreErrorsCMP0061());
+
+ if (cacheValue) {
+ return true;
+ }
+ mf.AddCacheDefinition(define, makecommand,
+ "Command used to build entire project "
+ "from the command line.",
+ cmStateEnums::STRING);
+ return true;
+}
+
+} // namespace
+
+bool cmBuildCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // Support the legacy signature of the command:
+ if (args.size() == 2) {
+ return TwoArgsSignature(args, status);
+ }
+
+ return MainSignature(args, status);
+}
diff --git a/Source/cmBuildCommand.h b/Source/cmBuildCommand.h
new file mode 100644
index 0000000..eafe185
--- /dev/null
+++ b/Source/cmBuildCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmBuildCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmBuildNameCommand.cxx b/Source/cmBuildNameCommand.cxx
new file mode 100644
index 0000000..f9b8f8f
--- /dev/null
+++ b/Source/cmBuildNameCommand.cxx
@@ -0,0 +1,61 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmBuildNameCommand.h"
+
+#include <algorithm>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
+
+bool cmBuildNameCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ cmMakefile& mf = status.GetMakefile();
+ cmProp cacheValue = mf.GetDefinition(args[0]);
+ if (cacheValue) {
+ // do we need to correct the value?
+ cmsys::RegularExpression reg("[()/]");
+ std::string cv = *cacheValue;
+ if (reg.find(cv)) {
+ std::replace(cv.begin(), cv.end(), '/', '_');
+ std::replace(cv.begin(), cv.end(), '(', '_');
+ std::replace(cv.begin(), cv.end(), ')', '_');
+ mf.AddCacheDefinition(args[0], cv, "Name of build.",
+ cmStateEnums::STRING);
+ }
+ return true;
+ }
+
+ std::string buildname = "WinNT";
+ if (mf.GetDefinition("UNIX")) {
+ buildname.clear();
+ cmSystemTools::RunSingleCommand("uname -a", &buildname, &buildname);
+ if (!buildname.empty()) {
+ std::string RegExp = "([^ ]*) [^ ]* ([^ ]*) ";
+ cmsys::RegularExpression reg(RegExp);
+ if (reg.find(buildname)) {
+ buildname = reg.match(1) + "-" + reg.match(2);
+ }
+ }
+ }
+ std::string compiler = "${CMAKE_CXX_COMPILER}";
+ mf.ExpandVariablesInString(compiler);
+ buildname += "-";
+ buildname += cmSystemTools::GetFilenameName(compiler);
+ std::replace(buildname.begin(), buildname.end(), '/', '_');
+ std::replace(buildname.begin(), buildname.end(), '(', '_');
+ std::replace(buildname.begin(), buildname.end(), ')', '_');
+
+ mf.AddCacheDefinition(args[0], buildname, "Name of build.",
+ cmStateEnums::STRING);
+ return true;
+}
diff --git a/Source/cmBuildNameCommand.h b/Source/cmBuildNameCommand.h
new file mode 100644
index 0000000..650dc74
--- /dev/null
+++ b/Source/cmBuildNameCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmBuildNameCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmCLocaleEnvironmentScope.cxx b/Source/cmCLocaleEnvironmentScope.cxx
new file mode 100644
index 0000000..c6c38f8
--- /dev/null
+++ b/Source/cmCLocaleEnvironmentScope.cxx
@@ -0,0 +1,53 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCLocaleEnvironmentScope.h"
+
+#include <sstream>
+#include <utility>
+
+#include "cmSystemTools.h"
+
+cmCLocaleEnvironmentScope::cmCLocaleEnvironmentScope()
+{
+ this->SetEnv("LANGUAGE", "");
+ this->SetEnv("LC_MESSAGES", "C");
+
+ std::string lcAll = this->GetEnv("LC_ALL");
+
+ if (!lcAll.empty()) {
+ this->SetEnv("LC_ALL", "");
+ this->SetEnv("LC_CTYPE", lcAll);
+ }
+}
+
+std::string cmCLocaleEnvironmentScope::GetEnv(std::string const& key)
+{
+ std::string value;
+ cmSystemTools::GetEnv(key, value);
+ return value;
+}
+
+void cmCLocaleEnvironmentScope::SetEnv(std::string const& key,
+ std::string const& value)
+{
+ std::string oldValue = this->GetEnv(key);
+
+ this->EnvironmentBackup.insert(std::make_pair(key, oldValue));
+
+ if (value.empty()) {
+ cmSystemTools::UnsetEnv(key.c_str());
+ } else {
+ std::ostringstream tmp;
+ tmp << key << "=" << value;
+ cmSystemTools::PutEnv(tmp.str());
+ }
+}
+
+cmCLocaleEnvironmentScope::~cmCLocaleEnvironmentScope()
+{
+ for (auto const& envb : this->EnvironmentBackup) {
+ std::ostringstream tmp;
+ tmp << envb.first << "=" << envb.second;
+ cmSystemTools::PutEnv(tmp.str());
+ }
+}
diff --git a/Source/cmCLocaleEnvironmentScope.h b/Source/cmCLocaleEnvironmentScope.h
new file mode 100644
index 0000000..0919acc
--- /dev/null
+++ b/Source/cmCLocaleEnvironmentScope.h
@@ -0,0 +1,26 @@
+/* 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 <map>
+#include <string>
+
+class cmCLocaleEnvironmentScope
+{
+public:
+ cmCLocaleEnvironmentScope();
+ ~cmCLocaleEnvironmentScope();
+
+ cmCLocaleEnvironmentScope(cmCLocaleEnvironmentScope const&) = delete;
+ cmCLocaleEnvironmentScope& operator=(cmCLocaleEnvironmentScope const&) =
+ delete;
+
+private:
+ std::string GetEnv(std::string const& key);
+ void SetEnv(std::string const& key, std::string const& value);
+
+ using backup_map_t = std::map<std::string, std::string>;
+ backup_map_t EnvironmentBackup;
+};
diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx
new file mode 100644
index 0000000..26e9af0
--- /dev/null
+++ b/Source/cmCMakeHostSystemInformationCommand.cxx
@@ -0,0 +1,199 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCMakeHostSystemInformationCommand.h"
+
+#include <cstddef>
+
+#include "cmsys/SystemInformation.hxx"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+
+#if defined(_WIN32)
+# include "cmAlgorithms.h"
+# include "cmGlobalGenerator.h"
+# include "cmGlobalVisualStudioVersionedGenerator.h"
+# include "cmSystemTools.h"
+# include "cmVSSetupHelper.h"
+# define HAVE_VS_SETUP_HELPER
+#endif
+
+namespace {
+bool GetValue(cmExecutionStatus& status, cmsys::SystemInformation& info,
+ std::string const& key, std::string& value);
+std::string ValueToString(size_t value);
+std::string ValueToString(const char* value);
+std::string ValueToString(std::string const& value);
+}
+
+// cmCMakeHostSystemInformation
+bool cmCMakeHostSystemInformationCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ size_t current_index = 0;
+
+ if (args.size() < (current_index + 2) || args[current_index] != "RESULT") {
+ status.SetError("missing RESULT specification.");
+ return false;
+ }
+
+ std::string const& variable = args[current_index + 1];
+ current_index += 2;
+
+ if (args.size() < (current_index + 2) || args[current_index] != "QUERY") {
+ status.SetError("missing QUERY specification");
+ return false;
+ }
+
+ cmsys::SystemInformation info;
+ info.RunCPUCheck();
+ info.RunOSCheck();
+ info.RunMemoryCheck();
+
+ std::string result_list;
+ for (size_t i = current_index + 1; i < args.size(); ++i) {
+ std::string const& key = args[i];
+ if (i != current_index + 1) {
+ result_list += ";";
+ }
+ std::string value;
+ if (!GetValue(status, info, key, value)) {
+ return false;
+ }
+ result_list += value;
+ }
+
+ status.GetMakefile().AddDefinition(variable, result_list);
+
+ return true;
+}
+
+namespace {
+
+bool GetValue(cmExecutionStatus& status, cmsys::SystemInformation& info,
+ std::string const& key, std::string& value)
+{
+ if (key == "NUMBER_OF_LOGICAL_CORES") {
+ value = ValueToString(info.GetNumberOfLogicalCPU());
+ } else if (key == "NUMBER_OF_PHYSICAL_CORES") {
+ value = ValueToString(info.GetNumberOfPhysicalCPU());
+ } else if (key == "HOSTNAME") {
+ value = ValueToString(info.GetHostname());
+ } else if (key == "FQDN") {
+ value = ValueToString(info.GetFullyQualifiedDomainName());
+ } else if (key == "TOTAL_VIRTUAL_MEMORY") {
+ value = ValueToString(info.GetTotalVirtualMemory());
+ } else if (key == "AVAILABLE_VIRTUAL_MEMORY") {
+ value = ValueToString(info.GetAvailableVirtualMemory());
+ } else if (key == "TOTAL_PHYSICAL_MEMORY") {
+ value = ValueToString(info.GetTotalPhysicalMemory());
+ } else if (key == "AVAILABLE_PHYSICAL_MEMORY") {
+ value = ValueToString(info.GetAvailablePhysicalMemory());
+ } else if (key == "IS_64BIT") {
+ value = ValueToString(info.Is64Bits());
+ } else if (key == "HAS_FPU") {
+ value = ValueToString(
+ info.DoesCPUSupportFeature(cmsys::SystemInformation::CPU_FEATURE_FPU));
+ } else if (key == "HAS_MMX") {
+ value = ValueToString(
+ info.DoesCPUSupportFeature(cmsys::SystemInformation::CPU_FEATURE_MMX));
+ } else if (key == "HAS_MMX_PLUS") {
+ value = ValueToString(info.DoesCPUSupportFeature(
+ cmsys::SystemInformation::CPU_FEATURE_MMX_PLUS));
+ } else if (key == "HAS_SSE") {
+ value = ValueToString(
+ info.DoesCPUSupportFeature(cmsys::SystemInformation::CPU_FEATURE_SSE));
+ } else if (key == "HAS_SSE2") {
+ value = ValueToString(
+ info.DoesCPUSupportFeature(cmsys::SystemInformation::CPU_FEATURE_SSE2));
+ } else if (key == "HAS_SSE_FP") {
+ value = ValueToString(info.DoesCPUSupportFeature(
+ cmsys::SystemInformation::CPU_FEATURE_SSE_FP));
+ } else if (key == "HAS_SSE_MMX") {
+ value = ValueToString(info.DoesCPUSupportFeature(
+ cmsys::SystemInformation::CPU_FEATURE_SSE_MMX));
+ } else if (key == "HAS_AMD_3DNOW") {
+ value = ValueToString(info.DoesCPUSupportFeature(
+ cmsys::SystemInformation::CPU_FEATURE_AMD_3DNOW));
+ } else if (key == "HAS_AMD_3DNOW_PLUS") {
+ value = ValueToString(info.DoesCPUSupportFeature(
+ cmsys::SystemInformation::CPU_FEATURE_AMD_3DNOW_PLUS));
+ } else if (key == "HAS_IA64") {
+ value = ValueToString(
+ info.DoesCPUSupportFeature(cmsys::SystemInformation::CPU_FEATURE_IA64));
+ } else if (key == "HAS_SERIAL_NUMBER") {
+ value = ValueToString(info.DoesCPUSupportFeature(
+ cmsys::SystemInformation::CPU_FEATURE_SERIALNUMBER));
+ } else if (key == "PROCESSOR_NAME") {
+ value = ValueToString(info.GetExtendedProcessorName());
+ } else if (key == "PROCESSOR_DESCRIPTION") {
+ value = info.GetCPUDescription();
+ } else if (key == "PROCESSOR_SERIAL_NUMBER") {
+ value = ValueToString(info.GetProcessorSerialNumber());
+ } else if (key == "OS_NAME") {
+ value = ValueToString(info.GetOSName());
+ } else if (key == "OS_RELEASE") {
+ value = ValueToString(info.GetOSRelease());
+ } else if (key == "OS_VERSION") {
+ value = ValueToString(info.GetOSVersion());
+ } else if (key == "OS_PLATFORM") {
+ value = ValueToString(info.GetOSPlatform());
+#ifdef HAVE_VS_SETUP_HELPER
+ } else if (key == "VS_15_DIR") {
+ // If generating for the VS 15 IDE, use the same instance.
+ cmGlobalGenerator* gg = status.GetMakefile().GetGlobalGenerator();
+ if (cmHasLiteralPrefix(gg->GetName(), "Visual Studio 15 ")) {
+ cmGlobalVisualStudioVersionedGenerator* vs15gen =
+ static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg);
+ if (vs15gen->GetVSInstance(value)) {
+ return true;
+ }
+ }
+
+ // Otherwise, find a VS 15 instance ourselves.
+ cmVSSetupAPIHelper vsSetupAPIHelper(15);
+ if (vsSetupAPIHelper.GetVSInstanceInfo(value)) {
+ cmSystemTools::ConvertToUnixSlashes(value);
+ }
+ } else if (key == "VS_16_DIR") {
+ // If generating for the VS 16 IDE, use the same instance.
+ cmGlobalGenerator* gg = status.GetMakefile().GetGlobalGenerator();
+ if (cmHasLiteralPrefix(gg->GetName(), "Visual Studio 16 ")) {
+ cmGlobalVisualStudioVersionedGenerator* vs16gen =
+ static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg);
+ if (vs16gen->GetVSInstance(value)) {
+ return true;
+ }
+ }
+
+ // Otherwise, find a VS 16 instance ourselves.
+ cmVSSetupAPIHelper vsSetupAPIHelper(16);
+ if (vsSetupAPIHelper.GetVSInstanceInfo(value)) {
+ cmSystemTools::ConvertToUnixSlashes(value);
+ }
+#endif
+ } else {
+ std::string e = "does not recognize <key> " + key;
+ status.SetError(e);
+ return false;
+ }
+
+ return true;
+}
+
+std::string ValueToString(size_t value)
+{
+ return std::to_string(value);
+}
+
+std::string ValueToString(const char* value)
+{
+ std::string safe_string = value ? value : "";
+ return safe_string;
+}
+
+std::string ValueToString(std::string const& value)
+{
+ return value;
+}
+}
diff --git a/Source/cmCMakeHostSystemInformationCommand.h b/Source/cmCMakeHostSystemInformationCommand.h
new file mode 100644
index 0000000..8a64f6a
--- /dev/null
+++ b/Source/cmCMakeHostSystemInformationCommand.h
@@ -0,0 +1,19 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Query host system specific information
+ *
+ * cmCMakeHostSystemInformationCommand queries system information of
+ * the system on which CMake runs.
+ */
+bool cmCMakeHostSystemInformationCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx
new file mode 100644
index 0000000..789c78d
--- /dev/null
+++ b/Source/cmCMakeLanguageCommand.cxx
@@ -0,0 +1,361 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCMakeLanguageCommand.h"
+
+#include <algorithm>
+#include <array>
+#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"
+#include "cmStringAlgorithms.h"
+#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,
+ "macro"_s, "endmacro"_s,
+ "if"_s, "elseif"_s, "else"_s, "endif"_s,
+ "while"_s, "endwhile"_s,
+ "foreach"_s, "endforeach"_s
+ } // clang-format on
+};
+
+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)
+{
+ // 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.GetBacktrace().Top();
+
+ std::vector<cmListFileArgument> funcArgs;
+ funcArgs.reserve(args.size() - startArg);
+
+ // The rest of the arguments are passed to the function call above
+ for (size_t i = startArg; i < args.size(); ++i) {
+ funcArgs.emplace_back(args[i].Value, args[i].Delim, context.Line);
+ }
+ cmListFileFunction func{ callCommand, context.Line, std::move(funcArgs) };
+
+ 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);
+}
+
+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]));
+}
+
+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 (expandedArgs.size() < 2) {
+ return FatalError(status, "called with incorrect number of arguments");
+ }
+
+ 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");
+ }
+
+ const std::string code =
+ cmJoin(cmMakeRange(expandedArgs.begin() + 2, expandedArgs.end()), " ");
+ return makefile.ReadListFileAsString(
+ code, cmStrCat(context.FilePath, ":", context.Line, ":EVAL"));
+}
+}
+
+bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status)
+{
+ std::vector<std::string> expArgs;
+ size_t rawArg = 0;
+ size_t expArg = 0;
+
+ // 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();
+ };
+
+ if (!moreArgs()) {
+ return FatalError(status, "called with incorrect number of arguments");
+ }
+
+ cm::optional<Defer> maybeDefer;
+ if (expArgs[expArg] == "DEFER"_s) {
+ ++expArg; // Consume "DEFER".
+
+ if (!moreArgs()) {
+ return FatalError(status, "DEFER requires at least one 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 {
+ return FatalError(
+ status, cmStrCat("DEFER unknown option:\n "_s, expArgs[expArg]));
+ }
+ }
+
+ 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 FatalError(status, "called with unknown meta-operation");
+}
diff --git a/Source/cmCMakeLanguageCommand.h b/Source/cmCMakeLanguageCommand.h
new file mode 100644
index 0000000..d45003a
--- /dev/null
+++ b/Source/cmCMakeLanguageCommand.h
@@ -0,0 +1,17 @@
+/* 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 <vector>
+
+class cmExecutionStatus;
+struct cmListFileArgument;
+
+/**
+ * \brief Calls a scripted or built-in command
+ *
+ */
+bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmCMakeMinimumRequired.cxx b/Source/cmCMakeMinimumRequired.cxx
new file mode 100644
index 0000000..1b03873
--- /dev/null
+++ b/Source/cmCMakeMinimumRequired.cxx
@@ -0,0 +1,165 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCMakeMinimumRequired.h"
+
+#include <cstdio>
+#include <sstream>
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+
+namespace {
+bool EnforceUnknownArguments(std::string const& version_max,
+ std::vector<std::string> const& unknown_arguments,
+ cmExecutionStatus& status);
+}
+
+// cmCMakeMinimumRequired
+bool cmCMakeMinimumRequired(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // Process arguments.
+ std::string version_string;
+ bool doing_version = false;
+ std::vector<std::string> unknown_arguments;
+ for (std::string const& arg : args) {
+ if (arg == "VERSION") {
+ doing_version = true;
+ } else if (arg == "FATAL_ERROR") {
+ if (doing_version) {
+ status.SetError("called with no value for VERSION.");
+ return false;
+ }
+ doing_version = false;
+ } else if (doing_version) {
+ doing_version = false;
+ version_string = arg;
+ } else {
+ unknown_arguments.push_back(arg);
+ }
+ }
+ if (doing_version) {
+ status.SetError("called with no value for VERSION.");
+ return false;
+ }
+
+ // Make sure there was a version to check.
+ if (version_string.empty()) {
+ return EnforceUnknownArguments(std::string(), unknown_arguments, status);
+ }
+
+ // Separate the <min> version and any trailing ...<max> component.
+ std::string::size_type const dd = version_string.find("...");
+ std::string const version_min = version_string.substr(0, dd);
+ std::string const version_max = dd != std::string::npos
+ ? version_string.substr(dd + 3, std::string::npos)
+ : std::string();
+ if (dd != std::string::npos &&
+ (version_min.empty() || version_max.empty())) {
+ std::ostringstream e;
+ e << "VERSION \"" << version_string
+ << R"(" does not have a version on both sides of "...".)";
+ status.SetError(e.str());
+ return false;
+ }
+
+ // Save the required version string.
+ status.GetMakefile().AddDefinition("CMAKE_MINIMUM_REQUIRED_VERSION",
+ version_min);
+
+ // Get the current version number.
+ unsigned int current_major = cmVersion::GetMajorVersion();
+ unsigned int current_minor = cmVersion::GetMinorVersion();
+ unsigned int current_patch = cmVersion::GetPatchVersion();
+ unsigned int current_tweak = cmVersion::GetTweakVersion();
+
+ // Parse at least two components of the version number.
+ // Use zero for those not specified.
+ unsigned int required_major = 0;
+ unsigned int required_minor = 0;
+ unsigned int required_patch = 0;
+ unsigned int required_tweak = 0;
+ if (sscanf(version_min.c_str(), "%u.%u.%u.%u", &required_major,
+ &required_minor, &required_patch, &required_tweak) < 2) {
+ std::ostringstream e;
+ e << "could not parse VERSION \"" << version_min << "\".";
+ status.SetError(e.str());
+ return false;
+ }
+
+ // Compare the version numbers.
+ if ((current_major < required_major) ||
+ (current_major == required_major && current_minor < required_minor) ||
+ (current_major == required_major && current_minor == required_minor &&
+ current_patch < required_patch) ||
+ (current_major == required_major && current_minor == required_minor &&
+ current_patch == required_patch && current_tweak < required_tweak)) {
+ // The current version is too low.
+ std::ostringstream e;
+ e << "CMake " << version_min
+ << " or higher is required. You are running version "
+ << cmVersion::GetCMakeVersion();
+ status.GetMakefile().IssueMessage(MessageType::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+
+ // The version is not from the future, so enforce unknown arguments.
+ if (!EnforceUnknownArguments(version_max, unknown_arguments, status)) {
+ return false;
+ }
+
+ if (required_major < 2 || (required_major == 2 && required_minor < 4)) {
+ status.GetMakefile().IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ "Compatibility with CMake < 2.4 is not supported by CMake >= 3.0.");
+ status.GetMakefile().SetPolicyVersion("2.4", version_max);
+ } else {
+ status.GetMakefile().SetPolicyVersion(version_min, version_max);
+ }
+
+ return true;
+}
+
+namespace {
+bool EnforceUnknownArguments(std::string const& version_max,
+ std::vector<std::string> const& unknown_arguments,
+ cmExecutionStatus& status)
+{
+ if (unknown_arguments.empty()) {
+ return true;
+ }
+
+ // Consider the max version if at least two components were given.
+ unsigned int max_major = 0;
+ unsigned int max_minor = 0;
+ unsigned int max_patch = 0;
+ unsigned int max_tweak = 0;
+ if (sscanf(version_max.c_str(), "%u.%u.%u.%u", &max_major, &max_minor,
+ &max_patch, &max_tweak) >= 2) {
+ unsigned int current_major = cmVersion::GetMajorVersion();
+ unsigned int current_minor = cmVersion::GetMinorVersion();
+ unsigned int current_patch = cmVersion::GetPatchVersion();
+ unsigned int current_tweak = cmVersion::GetTweakVersion();
+
+ if ((current_major < max_major) ||
+ (current_major == max_major && current_minor < max_minor) ||
+ (current_major == max_major && current_minor == max_minor &&
+ current_patch < max_patch) ||
+ (current_major == max_major && current_minor == max_minor &&
+ current_patch == max_patch && current_tweak < max_tweak)) {
+ // A ...<max> version was given that is larger than the current
+ // version of CMake, so tolerate unknown arguments.
+ return true;
+ }
+ }
+
+ std::ostringstream e;
+ e << "called with unknown argument \"" << unknown_arguments[0] << "\".";
+ status.SetError(e.str());
+ return false;
+}
+}
diff --git a/Source/cmCMakeMinimumRequired.h b/Source/cmCMakeMinimumRequired.h
new file mode 100644
index 0000000..712d6d6
--- /dev/null
+++ b/Source/cmCMakeMinimumRequired.h
@@ -0,0 +1,18 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief cmake_minimum_required command
+ *
+ * cmCMakeMinimumRequired implements the cmake_minimum_required CMake command
+ */
+bool cmCMakeMinimumRequired(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmCMakePath.cxx b/Source/cmCMakePath.cxx
new file mode 100644
index 0000000..73321c6
--- /dev/null
+++ b/Source/cmCMakePath.cxx
@@ -0,0 +1,147 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmCMakePath.h"
+
+#include <string>
+
+#if defined(_WIN32)
+# include <cstdlib>
+#endif
+
+#include <cm/filesystem>
+#include <cm/string_view>
+
+#if defined(_WIN32)
+# include "cmStringAlgorithms.h"
+#endif
+
+cmCMakePath& cmCMakePath::ReplaceWideExtension(cm::string_view extension)
+{
+ auto file = this->Path.filename().string();
+ if (!file.empty() && file != "." && file != "..") {
+ auto pos = file.find('.', file[0] == '.' ? 1 : 0);
+ if (pos != std::string::npos) {
+ file.erase(pos);
+ }
+ }
+ if (!extension.empty()) {
+ if (extension[0] != '.') {
+ file += '.';
+ }
+ file.append(std::string(extension));
+ }
+ this->Path.replace_filename(file);
+ return *this;
+}
+
+cmCMakePath cmCMakePath::GetWideExtension() const
+{
+ auto file = this->Path.filename().string();
+ if (file.empty() || file == "." || file == "..") {
+ return cmCMakePath{};
+ }
+
+ auto pos = file.find('.', file[0] == '.' ? 1 : 0);
+ if (pos != std::string::npos) {
+ return cm::string_view(file.data() + pos, file.length() - pos);
+ }
+
+ return cmCMakePath{};
+}
+
+cmCMakePath cmCMakePath::GetNarrowStem() const
+{
+ auto stem = this->Path.stem().string();
+ if (!stem.empty()) {
+ auto pos = stem.find('.', stem[0] == '.' ? 1 : 0);
+ if (pos != std::string::npos) {
+ return stem.substr(0, pos);
+ }
+ }
+ return stem;
+}
+
+cmCMakePath cmCMakePath::Absolute(const cm::filesystem::path& base) const
+{
+ if (this->Path.is_relative()) {
+ auto path = base;
+ path /= this->Path;
+ // filesystem::path::operator/= use preferred_separator ('\' on Windows)
+ // so converts back to '/'
+ return path.generic_string();
+ }
+ return *this;
+}
+
+bool cmCMakePath::IsPrefix(const cmCMakePath& path) const
+{
+ auto prefix_it = this->Path.begin();
+ auto prefix_end = this->Path.end();
+ auto path_it = path.Path.begin();
+ auto path_end = path.Path.end();
+
+ while (prefix_it != prefix_end && path_it != path_end &&
+ *prefix_it == *path_it) {
+ ++prefix_it;
+ ++path_it;
+ }
+ return (prefix_it == prefix_end) ||
+ (prefix_it->empty() && path_it != path_end);
+}
+
+std::string cmCMakePath::FormatPath(std::string path, format fmt)
+{
+#if defined(_WIN32)
+ if (fmt == auto_format || fmt == native_format) {
+ auto prefix = path.substr(0, 4);
+ for (auto& c : prefix) {
+ if (c == '\\') {
+ c = '/';
+ }
+ }
+ // remove Windows long filename marker
+ if (prefix == "//?/"_s) {
+ path.erase(0, 4);
+ }
+ if (cmHasPrefix(path, "UNC/"_s) || cmHasPrefix(path, "UNC\\"_s)) {
+ path.erase(0, 2);
+ path[0] = '/';
+ }
+ }
+#else
+ static_cast<void>(fmt);
+#endif
+ return path;
+}
+
+void cmCMakePath::GetNativePath(std::string& path) const
+{
+ cm::filesystem::path tmp(this->Path);
+ tmp.make_preferred();
+
+ path = tmp.string();
+}
+void cmCMakePath::GetNativePath(std::wstring& path) const
+{
+ cm::filesystem::path tmp(this->Path);
+ tmp.make_preferred();
+
+ path = tmp.wstring();
+
+#if defined(_WIN32)
+ // Windows long filename
+ static std::wstring UNC(L"\\\\?\\UNC");
+ static std::wstring PREFIX(L"\\\\?\\");
+
+ if (this->IsAbsolute() && path.length() > _MAX_PATH - 12) {
+ if (this->HasRootName() && path[0] == L'\\') {
+ path = UNC + path.substr(1);
+ } else {
+ path = PREFIX + path;
+ }
+ }
+#endif
+}
diff --git a/Source/cmCMakePath.h b/Source/cmCMakePath.h
new file mode 100644
index 0000000..15aa30c
--- /dev/null
+++ b/Source/cmCMakePath.h
@@ -0,0 +1,571 @@
+/* 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 <cstddef>
+#include <string>
+#include <utility>
+
+#include <cm/filesystem>
+#include <cm/string_view>
+#include <cm/type_traits>
+#include <cmext/string_view>
+
+namespace detail {
+#if defined(__SUNPRO_CC) && defined(__sparc)
+// Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
+// the full 'is_pathable' and 'is_move_pathable' checks. We use it only to
+// improve error messages via 'enable_if' when calling methods with incorrect
+// types. Just pretend all types are allowed so we can at least compile valid
+// code.
+template <typename T>
+struct is_pathable : std::true_type
+{
+};
+
+template <typename T>
+struct is_move_pathable : std::true_type
+{
+};
+
+#else
+template <typename T, typename = void>
+struct is_pathable : std::false_type
+{
+};
+
+template <>
+struct is_pathable<cm::filesystem::path> : std::true_type
+{
+};
+template <>
+struct is_pathable<std::string> : std::true_type
+{
+};
+template <>
+struct is_pathable<cm::string_view> : std::true_type
+{
+};
+template <>
+struct is_pathable<cm::static_string_view> : std::true_type
+{
+};
+template <typename T>
+struct is_pathable<
+ T,
+ cm::enable_if_t<std::is_same<char*, typename std::decay<T>::type>::value,
+ void>>
+ : cm::bool_constant<std::is_same<char*, typename std::decay<T>::type>::value>
+{
+};
+
+template <typename T>
+struct is_move_pathable : std::false_type
+{
+};
+
+template <>
+struct is_move_pathable<cm::filesystem::path> : std::true_type
+{
+};
+template <>
+struct is_move_pathable<std::string> : std::true_type
+{
+};
+#endif
+}
+
+class cmCMakePath
+{
+private:
+ template <typename Source>
+ using enable_if_move_pathable =
+ cm::enable_if_t<detail::is_move_pathable<Source>::value, cmCMakePath&>;
+
+ template <typename Source>
+ using enable_if_pathable =
+ cm::enable_if_t<detail::is_pathable<Source>::value, cmCMakePath&>;
+
+public:
+ using value_type = cm::filesystem::path::value_type;
+ using string_type = cm::filesystem::path::string_type;
+
+ enum format : unsigned char
+ {
+ auto_format =
+ static_cast<unsigned char>(cm::filesystem::path::format::auto_format),
+ native_format =
+ static_cast<unsigned char>(cm::filesystem::path::format::native_format),
+ generic_format =
+ static_cast<unsigned char>(cm::filesystem::path::format::generic_format)
+ };
+
+ class iterator;
+ using const_iterator = iterator;
+
+ cmCMakePath() noexcept = default;
+
+ cmCMakePath(const cmCMakePath&) = default;
+
+ cmCMakePath(cmCMakePath&& path) noexcept
+ : Path(std::forward<cm::filesystem::path>(path.Path))
+ {
+ }
+
+ cmCMakePath(cm::filesystem::path path) noexcept
+ : Path(std::move(path))
+ {
+ }
+ cmCMakePath(cm::string_view source, format fmt = generic_format) noexcept
+ : Path(FormatPath(source, fmt))
+ {
+ }
+ template <typename Source, typename = enable_if_move_pathable<Source>>
+ cmCMakePath(Source source, format fmt = generic_format)
+ : Path(FormatPath(std::move(source), fmt))
+ {
+ }
+
+ template <typename Source, typename = enable_if_move_pathable<Source>>
+ cmCMakePath& Assign(Source&& source)
+ {
+ this->Path = std::forward<Source>(source);
+ return *this;
+ }
+ template <typename Source, typename = enable_if_pathable<Source>>
+ cmCMakePath& Assign(const Source& source)
+ {
+ this->Path = source;
+ return *this;
+ }
+
+ cmCMakePath& operator=(const cmCMakePath& path)
+ {
+ if (this != &path) {
+ this->Path = path.Path;
+ }
+ return *this;
+ }
+ cmCMakePath& operator=(cmCMakePath&& path) noexcept
+ {
+ if (this != &path) {
+ this->Path = std::move(path.Path);
+ }
+ return *this;
+ }
+ template <typename Source, typename = enable_if_move_pathable<Source>>
+ cmCMakePath& operator=(Source&& source)
+ {
+ this->Assign(std::forward<Source>(source));
+ return *this;
+ }
+ template <typename Source, typename = enable_if_pathable<Source>>
+ cmCMakePath& operator=(const Source& source)
+ {
+ this->Assign(source);
+ return *this;
+ }
+
+ // Concatenation
+ cmCMakePath& Append(const cmCMakePath& path)
+ {
+ return this->Append(path.Path);
+ }
+ cmCMakePath& Append(const cm::filesystem::path& path)
+ {
+ this->Path /= path;
+ // filesystem::path::append use preferred_separator ('\' on Windows)
+ // so convert back to '/'
+ this->Path = this->Path.generic_string();
+ return *this;
+ }
+
+ template <typename Source, typename = enable_if_pathable<Source>>
+ cmCMakePath& Append(const Source& source)
+ {
+ return this->Append(cm::filesystem::path(source));
+ }
+
+ cmCMakePath& operator/=(const cmCMakePath& path)
+ {
+ return this->Append(path);
+ }
+ template <typename Source, typename = enable_if_pathable<Source>>
+ cmCMakePath& operator/=(const Source& source)
+ {
+ return this->Append(source);
+ }
+
+ cmCMakePath& Concat(const cmCMakePath& path)
+ {
+ this->Path += path.Path;
+ return *this;
+ }
+ cmCMakePath& Concat(cm::static_string_view source)
+ {
+ this->Path.concat(std::string(source));
+ return *this;
+ }
+ template <typename Source, typename = enable_if_pathable<Source>>
+ cmCMakePath& Concat(const Source& source)
+ {
+ this->Path.concat(source);
+ return *this;
+ }
+
+ cmCMakePath& operator+=(const cmCMakePath& path)
+ {
+ return this->Concat(path);
+ }
+ template <typename Source, typename = enable_if_pathable<Source>>
+ cmCMakePath& operator+=(const Source& source)
+ {
+ return this->Concat(source);
+ }
+
+ // Manipulation
+ void Clear() noexcept { this->Path.clear(); }
+
+ cmCMakePath& RemoveFileName()
+ {
+ this->Path.remove_filename();
+ return *this;
+ }
+
+ cmCMakePath& ReplaceFileName(const cmCMakePath& filename)
+ {
+ if (this->Path.has_filename()) {
+ this->Path.replace_filename(filename.Path);
+ }
+ return *this;
+ }
+ template <typename Source, typename = enable_if_pathable<Source>>
+ cmCMakePath& ReplaceFileName(const Source& filename)
+ {
+ if (this->Path.has_filename()) {
+ this->Path.replace_filename(filename);
+ }
+ return *this;
+ }
+
+ cmCMakePath& ReplaceExtension(const cmCMakePath& extension = cmCMakePath())
+ {
+ this->Path.replace_extension(extension.Path);
+ return *this;
+ }
+ template <typename Source, typename = enable_if_pathable<Source>>
+ cmCMakePath& ReplaceExtension(const Source& extension)
+ {
+ this->Path.replace_extension(extension);
+ return *this;
+ }
+
+ cmCMakePath& ReplaceWideExtension(
+ const cmCMakePath& extension = cmCMakePath())
+ {
+ return this->ReplaceWideExtension(
+ static_cast<cm::string_view>(extension.Path.string()));
+ }
+ template <typename Source, typename = enable_if_pathable<Source>>
+ cmCMakePath& ReplaceWideExtension(const Source& extension)
+ {
+ return this->ReplaceWideExtension(cm::string_view(extension));
+ }
+ cmCMakePath& ReplaceWideExtension(cm::string_view extension);
+
+ cmCMakePath& RemoveExtension()
+ {
+ if (this->Path.has_extension()) {
+ this->ReplaceExtension(cm::string_view(""));
+ }
+ return *this;
+ }
+
+ cmCMakePath& RemoveWideExtension()
+ {
+ if (this->Path.has_extension()) {
+ this->ReplaceWideExtension(cm::string_view(""));
+ }
+ return *this;
+ }
+
+ void swap(cmCMakePath& other) noexcept { this->Path.swap(other.Path); }
+
+ // Observers
+ std::string String() const { return this->Path.string(); }
+ std::wstring WString() const { return this->Path.wstring(); }
+
+ string_type Native() const
+ {
+ string_type path;
+ this->GetNativePath(path);
+
+ return path;
+ }
+ std::string NativeString() const
+ {
+ std::string path;
+ this->GetNativePath(path);
+
+ return path;
+ }
+ std::wstring NativeWString() const
+ {
+ std::wstring path;
+ this->GetNativePath(path);
+
+ return path;
+ }
+ std::string GenericString() const { return this->Path.generic_string(); }
+ std::wstring GenericWString() const { return this->Path.generic_wstring(); }
+
+ // Decomposition
+ cmCMakePath GetRootName() const { return this->Path.root_name(); }
+ cmCMakePath GetRootDirectory() const { return this->Path.root_directory(); }
+ cmCMakePath GetRootPath() const { return this->Path.root_path(); }
+ cmCMakePath GetFileName() const { return this->Path.filename(); }
+ cmCMakePath GetExtension() const { return this->Path.extension(); }
+ cmCMakePath GetWideExtension() const;
+ cmCMakePath GetStem() const { return this->Path.stem(); }
+ cmCMakePath GetNarrowStem() const;
+
+ cmCMakePath GetRelativePath() const { return this->Path.relative_path(); }
+ cmCMakePath GetParentPath() const { return this->Path.parent_path(); }
+
+ // Generation
+ cmCMakePath Normal() const
+ {
+ auto path = this->Path.lexically_normal();
+ // filesystem::path:lexically_normal use preferred_separator ('\') on
+ // Windows) so convert back to '/'
+ return path.generic_string();
+ }
+
+ cmCMakePath Relative(const cmCMakePath& base) const
+ {
+ return this->Relative(base.Path);
+ }
+ cmCMakePath Relative(const cm::filesystem::path& base) const
+ {
+ auto path = this->Path.lexically_relative(base);
+ // filesystem::path:lexically_relative use preferred_separator ('\') on
+ // Windows) so convert back to '/'
+ return path.generic_string();
+ }
+ template <typename Source, typename = enable_if_pathable<Source>>
+ cmCMakePath Relative(const Source& base) const
+ {
+ return this->Relative(cm::filesystem::path(base));
+ }
+
+ cmCMakePath Proximate(const cmCMakePath& base) const
+ {
+ return this->Proximate(base.Path);
+ }
+ cmCMakePath Proximate(const cm::filesystem::path& base) const
+ {
+ auto path = this->Path.lexically_proximate(base);
+ // filesystem::path::lexically_proximate use preferred_separator ('\') on
+ // Windows) so convert back to '/'
+ return path.generic_string();
+ }
+ template <typename Source, typename = enable_if_pathable<Source>>
+ cmCMakePath Proximate(const Source& base) const
+ {
+ return this->Proximate(cm::filesystem::path(base));
+ }
+
+ cmCMakePath Absolute(const cmCMakePath& base) const
+ {
+ return this->Absolute(base.Path);
+ }
+ template <typename Source, typename = enable_if_pathable<Source>>
+ cmCMakePath Absolute(const Source& base) const
+ {
+ return this->Absolute(cm::filesystem::path(base));
+ }
+ cmCMakePath Absolute(const cm::filesystem::path& base) const;
+
+ // Comparison
+ int Compare(const cmCMakePath& path) const noexcept
+ {
+ return this->Path.compare(path.Path);
+ }
+
+ // Query
+ bool IsEmpty() const noexcept { return this->Path.empty(); }
+
+ bool HasRootPath() const { return this->Path.has_root_path(); }
+ bool HasRootName() const { return this->Path.has_root_name(); }
+ bool HasRootDirectory() const { return this->Path.has_root_directory(); }
+ bool HasRelativePath() const { return this->Path.has_relative_path(); }
+ bool HasParentPath() const { return this->Path.has_parent_path(); }
+ bool HasFileName() const { return this->Path.has_filename(); }
+ bool HasStem() const { return this->Path.has_stem(); }
+ bool HasExtension() const { return this->Path.has_extension(); }
+
+ bool IsAbsolute() const { return this->Path.is_absolute(); }
+ bool IsRelative() const { return this->Path.is_relative(); }
+ bool IsPrefix(const cmCMakePath& path) const;
+
+ // Iterators
+ // =========
+ inline iterator begin() const;
+ inline iterator end() const;
+
+ // Non-members
+ // ===========
+ friend inline bool operator==(const cmCMakePath& lhs,
+ const cmCMakePath& rhs) noexcept
+ {
+ return lhs.Compare(rhs) == 0;
+ }
+ friend inline bool operator!=(const cmCMakePath& lhs,
+ const cmCMakePath& rhs) noexcept
+ {
+ return lhs.Compare(rhs) != 0;
+ }
+
+ friend inline cmCMakePath operator/(const cmCMakePath& lhs,
+ const cmCMakePath& rhs)
+ {
+ cmCMakePath result(lhs);
+ result /= rhs;
+
+ return result;
+ }
+
+private:
+ friend std::size_t hash_value(const cmCMakePath& path) noexcept;
+
+ static std::string FormatPath(std::string path, format fmt = generic_format);
+ static std::string FormatPath(cm::string_view path,
+ format fmt = generic_format)
+ {
+ return FormatPath(std::string(path), fmt);
+ }
+
+ void GetNativePath(std::string& path) const;
+ void GetNativePath(std::wstring& path) const;
+
+ cm::filesystem::path Path;
+};
+
+class cmCMakePath::iterator
+{
+public:
+ using iterator_category = cm::filesystem::path::iterator::iterator_category;
+
+ using value_type = cmCMakePath;
+ using difference_type = cm::filesystem::path::iterator::difference_type;
+ using pointer = const cmCMakePath*;
+ using reference = const cmCMakePath&;
+
+ iterator() = default;
+
+ iterator(const iterator& other)
+ : Iterator(other.Iterator)
+ , Path(other.Path)
+ , PathElement(*this->Iterator)
+ {
+ }
+
+ ~iterator() = default;
+
+ iterator& operator=(const iterator& other)
+ {
+ if (this != &other) {
+ this->Iterator = other.Iterator;
+ this->Path = other.Path;
+ this->PathElement = *this->Iterator;
+ }
+
+ return *this;
+ }
+
+ reference operator*() const { return this->PathElement; }
+
+ pointer operator->() const { return &this->PathElement; }
+
+ iterator& operator++()
+ {
+ ++this->Iterator;
+ this->PathElement = *this->Iterator;
+
+ return *this;
+ }
+
+ iterator operator++(int)
+ {
+ iterator it(*this);
+ this->operator++();
+ return it;
+ }
+
+ iterator& operator--()
+ {
+ --this->Iterator;
+ this->PathElement = *this->Iterator;
+
+ return *this;
+ }
+
+ iterator operator--(int)
+ {
+ iterator it(*this);
+ this->operator--();
+ return it;
+ }
+
+private:
+ friend class cmCMakePath;
+ friend bool operator==(const iterator&, const iterator&);
+
+ iterator(const cmCMakePath* path, const cm::filesystem::path::iterator& it)
+ : Iterator(it)
+ , Path(path)
+ , PathElement(*this->Iterator)
+ {
+ }
+
+ cm::filesystem::path::iterator Iterator;
+ const cmCMakePath* Path = nullptr;
+ cmCMakePath PathElement;
+};
+
+inline cmCMakePath::iterator cmCMakePath::begin() const
+{
+ return iterator(this, this->Path.begin());
+}
+inline cmCMakePath::iterator cmCMakePath::end() const
+{
+ return iterator(this, this->Path.end());
+}
+
+// Non-member functions
+// ====================
+inline bool operator==(const cmCMakePath::iterator& lhs,
+ const cmCMakePath::iterator& rhs)
+{
+ return lhs.Path == rhs.Path && lhs.Path != nullptr &&
+ lhs.Iterator == rhs.Iterator;
+}
+
+inline bool operator!=(const cmCMakePath::iterator& lhs,
+ const cmCMakePath::iterator& rhs)
+{
+ return !(lhs == rhs);
+}
+
+inline void swap(cmCMakePath& lhs, cmCMakePath& rhs) noexcept
+{
+ lhs.swap(rhs);
+}
+
+inline std::size_t hash_value(const cmCMakePath& path) noexcept
+{
+ return cm::filesystem::hash_value(path.Path);
+}
diff --git a/Source/cmCMakePathCommand.cxx b/Source/cmCMakePathCommand.cxx
new file mode 100644
index 0000000..962fdcc
--- /dev/null
+++ b/Source/cmCMakePathCommand.cxx
@@ -0,0 +1,998 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCMakePathCommand.h"
+
+#include <algorithm>
+#include <functional>
+#include <iomanip>
+#include <map>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmArgumentParser.h"
+#include "cmCMakePath.h"
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmSubcommandTable.h"
+#include "cmSystemTools.h"
+
+namespace {
+// Helper classes for argument parsing
+template <typename Result>
+class CMakePathArgumentParser : public cmArgumentParser<Result>
+{
+public:
+ CMakePathArgumentParser()
+ : cmArgumentParser<Result>()
+ {
+ }
+
+ template <typename T>
+ CMakePathArgumentParser& Bind(cm::static_string_view name, T Result::*member)
+ {
+ this->cmArgumentParser<Result>::Bind(name, member);
+ return *this;
+ }
+
+ template <int Advance = 2>
+ Result Parse(std::vector<std::string> const& args,
+ std::vector<std::string>* keywordsMissingValue = nullptr,
+ std::vector<std::string>* parsedKeywords = nullptr) const
+ {
+ this->Inputs.clear();
+
+ return this->cmArgumentParser<Result>::Parse(
+ cmMakeRange(args).advance(Advance), &this->Inputs, keywordsMissingValue,
+ parsedKeywords);
+ }
+
+ const std::vector<std::string>& GetInputs() const { return this->Inputs; }
+
+protected:
+ mutable std::vector<std::string> Inputs;
+};
+
+// OUTPUT_VARIABLE is expected
+template <typename Result>
+class ArgumentParserWithOutputVariable : public CMakePathArgumentParser<Result>
+{
+public:
+ ArgumentParserWithOutputVariable()
+ : CMakePathArgumentParser<Result>()
+ {
+ this->Bind("OUTPUT_VARIABLE"_s, &Result::Output);
+ }
+
+ template <typename T>
+ ArgumentParserWithOutputVariable& Bind(cm::static_string_view name,
+ T Result::*member)
+ {
+ this->cmArgumentParser<Result>::Bind(name, member);
+ return *this;
+ }
+
+ template <int Advance = 2>
+ Result Parse(std::vector<std::string> const& args) const
+ {
+ this->KeywordsMissingValue.clear();
+ this->ParsedKeywords.clear();
+
+ return this->CMakePathArgumentParser<Result>::template Parse<Advance>(
+ args, &this->KeywordsMissingValue, &this->ParsedKeywords);
+ }
+
+ const std::vector<std::string>& GetKeywordsMissingValue() const
+ {
+ return this->KeywordsMissingValue;
+ }
+ const std::vector<std::string>& GetParsedKeywords() const
+ {
+ return this->ParsedKeywords;
+ }
+
+ bool checkOutputVariable(const Result& arguments,
+ cmExecutionStatus& status) const
+ {
+ if (std::find(this->GetKeywordsMissingValue().begin(),
+ this->GetKeywordsMissingValue().end(),
+ "OUTPUT_VARIABLE"_s) !=
+ this->GetKeywordsMissingValue().end()) {
+ status.SetError("OUTPUT_VARIABLE requires an argument.");
+ return false;
+ }
+
+ if (std::find(this->GetParsedKeywords().begin(),
+ this->GetParsedKeywords().end(),
+ "OUTPUT_VARIABLE"_s) != this->GetParsedKeywords().end() &&
+ arguments.Output.empty()) {
+ status.SetError("Invalid name for output variable.");
+ return false;
+ }
+
+ return true;
+ }
+
+private:
+ mutable std::vector<std::string> KeywordsMissingValue;
+ mutable std::vector<std::string> ParsedKeywords;
+};
+
+struct OutputVariable
+{
+ std::string Output;
+};
+// Usable when OUTPUT_VARIABLE is the only option
+class OutputVariableParser
+ : public ArgumentParserWithOutputVariable<OutputVariable>
+{
+};
+
+struct NormalizeOption
+{
+ bool Normalize = false;
+};
+// Usable when NORMALIZE is the only option
+class NormalizeParser : public CMakePathArgumentParser<NormalizeOption>
+{
+public:
+ NormalizeParser() { this->Bind("NORMALIZE"_s, &NormalizeOption::Normalize); }
+};
+
+// retrieve value of input path from specified variable
+bool getInputPath(const std::string& arg, cmExecutionStatus& status,
+ std::string& path)
+{
+ const auto* def = status.GetMakefile().GetDefinition(arg);
+ if (def == nullptr) {
+ status.SetError("undefined variable for input path.");
+ return false;
+ }
+
+ path = *def;
+ return true;
+}
+
+bool HandleGetCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ static std::map<cm::string_view,
+ std::function<cmCMakePath(const cmCMakePath&, bool)>> const
+ actions{ { "ROOT_NAME"_s,
+ [](const cmCMakePath& path, bool) -> cmCMakePath {
+ return path.GetRootName();
+ } },
+ { "ROOT_DIRECTORY"_s,
+ [](const cmCMakePath& path, bool) -> cmCMakePath {
+ return path.GetRootDirectory();
+ } },
+ { "ROOT_PATH"_s,
+ [](const cmCMakePath& path, bool) -> cmCMakePath {
+ return path.GetRootPath();
+ } },
+ { "FILENAME"_s,
+ [](const cmCMakePath& path, bool) -> cmCMakePath {
+ return path.GetFileName();
+ } },
+ { "EXTENSION"_s,
+ [](const cmCMakePath& path, bool last_only) -> cmCMakePath {
+ if (last_only) {
+ return path.GetExtension();
+ }
+ return path.GetWideExtension();
+ } },
+ { "STEM"_s,
+ [](const cmCMakePath& path, bool last_only) -> cmCMakePath {
+ if (last_only) {
+ return path.GetStem();
+ }
+ return path.GetNarrowStem();
+ } },
+ { "RELATIVE_PART"_s,
+ [](const cmCMakePath& path, bool) -> cmCMakePath {
+ return path.GetRelativePath();
+ } },
+ { "PARENT_PATH"_s,
+ [](const cmCMakePath& path, bool) -> cmCMakePath {
+ return path.GetParentPath();
+ } } };
+
+ if (args.size() < 4) {
+ status.SetError("GET must be called with at least three arguments.");
+ return false;
+ }
+
+ const auto& action = args[2];
+
+ if (actions.find(action) == actions.end()) {
+ status.SetError(
+ cmStrCat("GET called with an unknown action: ", action, "."));
+ return false;
+ }
+
+ struct Arguments
+ {
+ bool LastOnly = false;
+ };
+
+ CMakePathArgumentParser<Arguments> parser;
+ if ((action == "EXTENSION"_s || action == "STEM"_s)) {
+ parser.Bind("LAST_ONLY"_s, &Arguments::LastOnly);
+ }
+
+ Arguments const arguments = parser.Parse<3>(args);
+
+ if (parser.GetInputs().size() != 1) {
+ status.SetError("GET called with unexpected arguments.");
+ return false;
+ }
+ if (parser.GetInputs().front().empty()) {
+ status.SetError("Invalid name for output variable.");
+ return false;
+ }
+
+ std::string path;
+ if (!getInputPath(args[1], status, path)) {
+ return false;
+ }
+
+ auto result = actions.at(action)(path, arguments.LastOnly);
+
+ status.GetMakefile().AddDefinition(parser.GetInputs().front(),
+ result.String());
+
+ return true;
+}
+
+bool HandleSetCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3 || args.size() > 4) {
+ status.SetError("SET must be called with two or three arguments.");
+ return false;
+ }
+
+ if (args[1].empty()) {
+ status.SetError("Invalid name for path variable.");
+ return false;
+ }
+
+ static NormalizeParser const parser;
+
+ const auto arguments = parser.Parse(args);
+
+ if (parser.GetInputs().size() != 1) {
+ status.SetError("SET called with unexpected arguments.");
+ return false;
+ }
+
+ auto path =
+ cmCMakePath(parser.GetInputs().front(), cmCMakePath::native_format);
+
+ if (arguments.Normalize) {
+ path = path.Normal();
+ }
+
+ status.GetMakefile().AddDefinition(args[1], path.GenericString());
+
+ return true;
+}
+
+bool HandleAppendCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args[1].empty()) {
+ status.SetError("Invalid name for path variable.");
+ return false;
+ }
+
+ static OutputVariableParser const parser{};
+
+ const auto arguments = parser.Parse(args);
+
+ if (!parser.checkOutputVariable(arguments, status)) {
+ return false;
+ }
+
+ cmCMakePath path(status.GetMakefile().GetSafeDefinition(args[1]));
+ for (const auto& input : parser.GetInputs()) {
+ path /= input;
+ }
+
+ status.GetMakefile().AddDefinition(
+ arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+
+ return true;
+}
+
+bool HandleAppendStringCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ static OutputVariableParser const parser{};
+
+ const auto arguments = parser.Parse(args);
+
+ if (!parser.checkOutputVariable(arguments, status)) {
+ return false;
+ }
+
+ std::string inputPath;
+ if (!getInputPath(args[1], status, inputPath)) {
+ return false;
+ }
+
+ cmCMakePath path(inputPath);
+ for (const auto& input : parser.GetInputs()) {
+ path += input;
+ }
+
+ status.GetMakefile().AddDefinition(
+ arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+
+ return true;
+}
+
+bool HandleRemoveFilenameCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ static OutputVariableParser const parser{};
+
+ const auto arguments = parser.Parse(args);
+
+ if (!parser.checkOutputVariable(arguments, status)) {
+ return false;
+ }
+
+ if (!parser.GetInputs().empty()) {
+ status.SetError("REMOVE_FILENAME called with unexpected arguments.");
+ return false;
+ }
+
+ std::string inputPath;
+ if (!getInputPath(args[1], status, inputPath)) {
+ return false;
+ }
+
+ cmCMakePath path(inputPath);
+ path.RemoveFileName();
+
+ status.GetMakefile().AddDefinition(
+ arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+
+ return true;
+}
+
+bool HandleReplaceFilenameCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ static OutputVariableParser const parser{};
+
+ const auto arguments = parser.Parse(args);
+
+ if (!parser.checkOutputVariable(arguments, status)) {
+ return false;
+ }
+
+ if (parser.GetInputs().size() > 1) {
+ status.SetError("REPLACE_FILENAME called with unexpected arguments.");
+ return false;
+ }
+
+ std::string inputPath;
+ if (!getInputPath(args[1], status, inputPath)) {
+ return false;
+ }
+
+ cmCMakePath path(inputPath);
+ path.ReplaceFileName(
+ parser.GetInputs().empty() ? "" : parser.GetInputs().front());
+
+ status.GetMakefile().AddDefinition(
+ arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+
+ return true;
+}
+
+bool HandleRemoveExtensionCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ struct Arguments
+ {
+ std::string Output;
+ bool LastOnly = false;
+ };
+
+ static auto const parser =
+ ArgumentParserWithOutputVariable<Arguments>{}.Bind("LAST_ONLY"_s,
+ &Arguments::LastOnly);
+
+ Arguments const arguments = parser.Parse(args);
+
+ if (!parser.checkOutputVariable(arguments, status)) {
+ return false;
+ }
+
+ if (!parser.GetInputs().empty()) {
+ status.SetError("REMOVE_EXTENSION called with unexpected arguments.");
+ return false;
+ }
+
+ std::string inputPath;
+ if (!getInputPath(args[1], status, inputPath)) {
+ return false;
+ }
+
+ cmCMakePath path(inputPath);
+
+ if (arguments.LastOnly) {
+ path.RemoveExtension();
+ } else {
+ path.RemoveWideExtension();
+ }
+
+ status.GetMakefile().AddDefinition(
+ arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+
+ return true;
+}
+
+bool HandleReplaceExtensionCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ struct Arguments
+ {
+ std::string Output;
+ bool LastOnly = false;
+ };
+
+ static auto const parser =
+ ArgumentParserWithOutputVariable<Arguments>{}.Bind("LAST_ONLY"_s,
+ &Arguments::LastOnly);
+
+ Arguments const arguments = parser.Parse(args);
+
+ if (!parser.checkOutputVariable(arguments, status)) {
+ return false;
+ }
+
+ if (parser.GetInputs().size() > 1) {
+ status.SetError("REPLACE_EXTENSION called with unexpected arguments.");
+ return false;
+ }
+
+ std::string inputPath;
+ if (!getInputPath(args[1], status, inputPath)) {
+ return false;
+ }
+
+ cmCMakePath path(inputPath);
+ cmCMakePath extension(
+ parser.GetInputs().empty() ? "" : parser.GetInputs().front());
+
+ if (arguments.LastOnly) {
+ path.ReplaceExtension(extension);
+ } else {
+ path.ReplaceWideExtension(extension);
+ }
+
+ status.GetMakefile().AddDefinition(
+ arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+
+ return true;
+}
+
+bool HandleNormalPathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ static OutputVariableParser const parser{};
+
+ const auto arguments = parser.Parse(args);
+
+ if (!parser.checkOutputVariable(arguments, status)) {
+ return false;
+ }
+
+ if (!parser.GetInputs().empty()) {
+ status.SetError("NORMAL_PATH called with unexpected arguments.");
+ return false;
+ }
+
+ std::string inputPath;
+ if (!getInputPath(args[1], status, inputPath)) {
+ return false;
+ }
+
+ auto path = cmCMakePath(inputPath).Normal();
+
+ status.GetMakefile().AddDefinition(
+ arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+
+ return true;
+}
+
+bool HandleTransformPathCommand(
+ std::vector<std::string> const& args, cmExecutionStatus& status,
+ const std::function<cmCMakePath(const cmCMakePath&,
+ const std::string& base)>& transform,
+ bool normalizeOption = false)
+{
+ struct Arguments
+ {
+ std::string Output;
+ std::string BaseDirectory;
+ bool Normalize = false;
+ };
+
+ auto parser = ArgumentParserWithOutputVariable<Arguments>{}.Bind(
+ "BASE_DIRECTORY"_s, &Arguments::BaseDirectory);
+ if (normalizeOption) {
+ parser.Bind("NORMALIZE"_s, &Arguments::Normalize);
+ }
+
+ Arguments arguments = parser.Parse(args);
+
+ if (!parser.checkOutputVariable(arguments, status)) {
+ return false;
+ }
+
+ if (!parser.GetInputs().empty()) {
+ status.SetError(cmStrCat(args[0], " called with unexpected arguments."));
+ return false;
+ }
+
+ if (std::find(parser.GetKeywordsMissingValue().begin(),
+ parser.GetKeywordsMissingValue().end(), "BASE_DIRECTORY"_s) !=
+ parser.GetKeywordsMissingValue().end()) {
+ status.SetError("BASE_DIRECTORY requires an argument.");
+ return false;
+ }
+
+ if (std::find(parser.GetParsedKeywords().begin(),
+ parser.GetParsedKeywords().end(),
+ "BASE_DIRECTORY"_s) == parser.GetParsedKeywords().end()) {
+ arguments.BaseDirectory = status.GetMakefile().GetCurrentSourceDirectory();
+ }
+
+ std::string inputPath;
+ if (!getInputPath(args[1], status, inputPath)) {
+ return false;
+ }
+
+ auto path = transform(cmCMakePath(inputPath), arguments.BaseDirectory);
+ if (arguments.Normalize) {
+ path = path.Normal();
+ }
+
+ status.GetMakefile().AddDefinition(
+ arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+
+ return true;
+}
+
+bool HandleRelativePathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleTransformPathCommand(
+ args, status,
+ [](const cmCMakePath& path, const std::string& base) -> cmCMakePath {
+ return path.Relative(base);
+ });
+}
+
+bool HandleAbsolutePathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleTransformPathCommand(
+ args, status,
+ [](const cmCMakePath& path, const std::string& base) -> cmCMakePath {
+ return path.Absolute(base);
+ },
+ true);
+}
+
+bool HandleNativePathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3 || args.size() > 4) {
+ status.SetError("NATIVE_PATH must be called with two or three arguments.");
+ return false;
+ }
+
+ static NormalizeParser const parser;
+
+ const auto arguments = parser.Parse(args);
+
+ if (parser.GetInputs().size() != 1) {
+ status.SetError("NATIVE_PATH called with unexpected arguments.");
+ return false;
+ }
+ if (parser.GetInputs().front().empty()) {
+ status.SetError("Invalid name for output variable.");
+ return false;
+ }
+
+ std::string inputPath;
+ if (!getInputPath(args[1], status, inputPath)) {
+ return false;
+ }
+
+ cmCMakePath path(inputPath);
+ if (arguments.Normalize) {
+ path = path.Normal();
+ }
+
+ status.GetMakefile().AddDefinition(parser.GetInputs().front(),
+ path.NativeString());
+
+ return true;
+}
+
+bool HandleConvertCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ const auto pathSep = ";"_s;
+#else
+ const auto pathSep = ":"_s;
+#endif
+ const auto cmakePath = "TO_CMAKE_PATH_LIST"_s;
+ const auto nativePath = "TO_NATIVE_PATH_LIST"_s;
+
+ if (args.size() < 4 || args.size() > 5) {
+ status.SetError("CONVERT must be called with three or four arguments.");
+ return false;
+ }
+
+ const auto& action = args[2];
+
+ if (action != cmakePath && action != nativePath) {
+ status.SetError(
+ cmStrCat("CONVERT called with an unknown action: ", action, "."));
+ return false;
+ }
+
+ if (args[3].empty()) {
+ status.SetError("Invalid name for output variable.");
+ return false;
+ }
+
+ static NormalizeParser const parser;
+
+ const auto arguments = parser.Parse<4>(args);
+
+ if (!parser.GetInputs().empty()) {
+ status.SetError("CONVERT called with unexpected arguments.");
+ return false;
+ }
+
+ std::vector<std::string> paths;
+
+ if (action == cmakePath) {
+ paths = cmSystemTools::SplitString(args[1], pathSep.front());
+ } else {
+ cmExpandList(args[1], paths);
+ }
+
+ for (auto& path : paths) {
+ auto p = cmCMakePath(path,
+ action == cmakePath ? cmCMakePath::native_format
+ : cmCMakePath::generic_format);
+ if (arguments.Normalize) {
+ p = p.Normal();
+ }
+ if (action == cmakePath) {
+ path = p.GenericString();
+ } else {
+ path = p.NativeString();
+ }
+ }
+
+ auto value = cmJoin(paths, action == cmakePath ? ";"_s : pathSep);
+ status.GetMakefile().AddDefinition(args[3], value);
+
+ return true;
+}
+
+bool HandleCompareCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 5) {
+ status.SetError("COMPARE must be called with four arguments.");
+ return false;
+ }
+
+ static std::map<cm::string_view,
+ std::function<bool(const cmCMakePath&,
+ const cmCMakePath&)>> const operators{
+ { "EQUAL"_s,
+ [](const cmCMakePath& path1, const cmCMakePath& path2) -> bool {
+ return path1 == path2;
+ } },
+ { "NOT_EQUAL"_s,
+ [](const cmCMakePath& path1, const cmCMakePath& path2) -> bool {
+ return path1 != path2;
+ } }
+ };
+
+ const auto op = operators.find(args[2]);
+ if (op == operators.end()) {
+ status.SetError(cmStrCat(
+ "COMPARE called with an unknown comparison operator: ", args[2], "."));
+ return false;
+ }
+
+ if (args[4].empty()) {
+ status.SetError("Invalid name for output variable.");
+ return false;
+ }
+
+ cmCMakePath path1(args[1]);
+ cmCMakePath path2(args[3]);
+ auto result = op->second(path1, path2);
+
+ status.GetMakefile().AddDefinitionBool(args[4], result);
+
+ return true;
+}
+
+bool HandleHasItemCommand(
+ std::vector<std::string> const& args, cmExecutionStatus& status,
+ const std::function<bool(const cmCMakePath&)>& has_item)
+{
+ if (args.size() != 3) {
+ status.SetError(
+ cmStrCat(args.front(), " must be called with two arguments."));
+ return false;
+ }
+
+ std::string inputPath;
+ if (!getInputPath(args[1], status, inputPath)) {
+ return false;
+ }
+
+ if (args[2].empty()) {
+ status.SetError("Invalid name for output variable.");
+ return false;
+ }
+
+ cmCMakePath path(inputPath);
+ auto result = has_item(path);
+
+ status.GetMakefile().AddDefinitionBool(args[2], result);
+
+ return true;
+}
+
+bool HandleHasRootNameCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleHasItemCommand(
+ args, status,
+ [](const cmCMakePath& path) -> bool { return path.HasRootName(); });
+}
+
+bool HandleHasRootDirectoryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleHasItemCommand(
+ args, status,
+ [](const cmCMakePath& path) -> bool { return path.HasRootDirectory(); });
+}
+
+bool HandleHasRootPathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleHasItemCommand(
+ args, status,
+ [](const cmCMakePath& path) -> bool { return path.HasRootPath(); });
+}
+
+bool HandleHasFilenameCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleHasItemCommand(
+ args, status,
+ [](const cmCMakePath& path) -> bool { return path.HasFileName(); });
+}
+
+bool HandleHasExtensionCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleHasItemCommand(
+ args, status,
+ [](const cmCMakePath& path) -> bool { return path.HasExtension(); });
+}
+
+bool HandleHasStemCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleHasItemCommand(
+ args, status,
+ [](const cmCMakePath& path) -> bool { return path.HasStem(); });
+}
+
+bool HandleHasRelativePartCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleHasItemCommand(
+ args, status,
+ [](const cmCMakePath& path) -> bool { return path.HasRelativePath(); });
+}
+
+bool HandleHasParentPathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleHasItemCommand(
+ args, status,
+ [](const cmCMakePath& path) -> bool { return path.HasParentPath(); });
+}
+
+bool HandleIsAbsoluteCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError("IS_ABSOLUTE must be called with two arguments.");
+ return false;
+ }
+
+ std::string inputPath;
+ if (!getInputPath(args[1], status, inputPath)) {
+ return false;
+ }
+
+ if (args[2].empty()) {
+ status.SetError("Invalid name for output variable.");
+ return false;
+ }
+
+ bool isAbsolute = cmCMakePath(inputPath).IsAbsolute();
+
+ status.GetMakefile().AddDefinitionBool(args[2], isAbsolute);
+
+ return true;
+}
+
+bool HandleIsRelativeCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError("IS_RELATIVE must be called with two arguments.");
+ return false;
+ }
+
+ std::string inputPath;
+ if (!getInputPath(args[1], status, inputPath)) {
+ return false;
+ }
+
+ if (args[2].empty()) {
+ status.SetError("Invalid name for output variable.");
+ return false;
+ }
+
+ bool isRelative = cmCMakePath(inputPath).IsRelative();
+
+ status.GetMakefile().AddDefinitionBool(args[2], isRelative);
+
+ return true;
+}
+
+bool HandleIsPrefixCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 4 || args.size() > 5) {
+ status.SetError("IS_PREFIX must be called with three or four arguments.");
+ return false;
+ }
+
+ static NormalizeParser const parser;
+
+ const auto arguments = parser.Parse(args);
+
+ if (parser.GetInputs().size() != 2) {
+ status.SetError("IS_PREFIX called with unexpected arguments.");
+ return false;
+ }
+
+ std::string inputPath;
+ if (!getInputPath(args[1], status, inputPath)) {
+ return false;
+ }
+
+ const auto& input = parser.GetInputs().front();
+ const auto& output = parser.GetInputs().back();
+
+ if (output.empty()) {
+ status.SetError("Invalid name for output variable.");
+ return false;
+ }
+
+ bool isPrefix;
+ if (arguments.Normalize) {
+ isPrefix =
+ cmCMakePath(inputPath).Normal().IsPrefix(cmCMakePath(input).Normal());
+ } else {
+ isPrefix = cmCMakePath(inputPath).IsPrefix(input);
+ }
+
+ status.GetMakefile().AddDefinitionBool(output, isPrefix);
+
+ return true;
+}
+
+bool HandleHashCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError("HASH must be called with two arguments.");
+ return false;
+ }
+
+ std::string inputPath;
+ if (!getInputPath(args[1], status, inputPath)) {
+ return false;
+ }
+
+ const auto& output = args[2];
+
+ if (output.empty()) {
+ status.SetError("Invalid name for output variable.");
+ return false;
+ }
+
+ auto hash = hash_value(cmCMakePath(inputPath).Normal());
+
+ std::ostringstream out;
+ out << std::setbase(16) << hash;
+
+ status.GetMakefile().AddDefinition(output, out.str());
+
+ return true;
+}
+} // anonymous namespace
+
+bool cmCMakePathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("must be called with at least two arguments.");
+ return false;
+ }
+
+ static cmSubcommandTable const subcommand{
+ { "GET"_s, HandleGetCommand },
+ { "SET"_s, HandleSetCommand },
+ { "APPEND"_s, HandleAppendCommand },
+ { "APPEND_STRING"_s, HandleAppendStringCommand },
+ { "REMOVE_FILENAME"_s, HandleRemoveFilenameCommand },
+ { "REPLACE_FILENAME"_s, HandleReplaceFilenameCommand },
+ { "REMOVE_EXTENSION"_s, HandleRemoveExtensionCommand },
+ { "REPLACE_EXTENSION"_s, HandleReplaceExtensionCommand },
+ { "NORMAL_PATH"_s, HandleNormalPathCommand },
+ { "RELATIVE_PATH"_s, HandleRelativePathCommand },
+ { "ABSOLUTE_PATH"_s, HandleAbsolutePathCommand },
+ { "NATIVE_PATH"_s, HandleNativePathCommand },
+ { "CONVERT"_s, HandleConvertCommand },
+ { "COMPARE"_s, HandleCompareCommand },
+ { "HAS_ROOT_NAME"_s, HandleHasRootNameCommand },
+ { "HAS_ROOT_DIRECTORY"_s, HandleHasRootDirectoryCommand },
+ { "HAS_ROOT_PATH"_s, HandleHasRootPathCommand },
+ { "HAS_FILENAME"_s, HandleHasFilenameCommand },
+ { "HAS_EXTENSION"_s, HandleHasExtensionCommand },
+ { "HAS_STEM"_s, HandleHasStemCommand },
+ { "HAS_RELATIVE_PART"_s, HandleHasRelativePartCommand },
+ { "HAS_PARENT_PATH"_s, HandleHasParentPathCommand },
+ { "IS_ABSOLUTE"_s, HandleIsAbsoluteCommand },
+ { "IS_RELATIVE"_s, HandleIsRelativeCommand },
+ { "IS_PREFIX"_s, HandleIsPrefixCommand },
+ { "HASH"_s, HandleHashCommand }
+ };
+
+ return subcommand(args[0], args, status);
+}
diff --git a/Source/cmCMakePathCommand.h b/Source/cmCMakePathCommand.h
new file mode 100644
index 0000000..49e9380
--- /dev/null
+++ b/Source/cmCMakePathCommand.h
@@ -0,0 +1,14 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmCMakePathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmCMakePolicyCommand.cxx b/Source/cmCMakePolicyCommand.cxx
new file mode 100644
index 0000000..1f99043
--- /dev/null
+++ b/Source/cmCMakePolicyCommand.cxx
@@ -0,0 +1,224 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCMakePolicyCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+
+namespace {
+bool HandleSetMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
+bool HandleGetMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
+bool HandleVersionMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
+bool HandleGetWarningMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
+}
+
+// cmCMakePolicyCommand
+bool cmCMakePolicyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("requires at least one argument.");
+ return false;
+ }
+
+ if (args[0] == "SET") {
+ return HandleSetMode(args, status);
+ }
+ if (args[0] == "GET") {
+ return HandleGetMode(args, status);
+ }
+ if (args[0] == "PUSH") {
+ if (args.size() > 1) {
+ status.SetError("PUSH may not be given additional arguments.");
+ return false;
+ }
+ status.GetMakefile().PushPolicy();
+ return true;
+ }
+ if (args[0] == "POP") {
+ if (args.size() > 1) {
+ status.SetError("POP may not be given additional arguments.");
+ return false;
+ }
+ status.GetMakefile().PopPolicy();
+ return true;
+ }
+ if (args[0] == "VERSION") {
+ return HandleVersionMode(args, status);
+ }
+ if (args[0] == "GET_WARNING") {
+ return HandleGetWarningMode(args, status);
+ }
+
+ status.SetError(cmStrCat("given unknown first argument \"", args[0], "\""));
+ return false;
+}
+
+namespace {
+
+bool HandleSetMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError("SET must be given exactly 2 additional arguments.");
+ return false;
+ }
+
+ cmPolicies::PolicyStatus policyStatus;
+ if (args[2] == "OLD") {
+ policyStatus = cmPolicies::OLD;
+ } else if (args[2] == "NEW") {
+ policyStatus = cmPolicies::NEW;
+ } else {
+ status.SetError(
+ cmStrCat("SET given unrecognized policy status \"", args[2], "\""));
+ return false;
+ }
+
+ if (!status.GetMakefile().SetPolicy(args[1].c_str(), policyStatus)) {
+ status.SetError("SET failed to set policy.");
+ return false;
+ }
+ if (args[1] == "CMP0001" &&
+ (policyStatus == cmPolicies::WARN || policyStatus == cmPolicies::OLD)) {
+ if (!(status.GetMakefile().GetState()->GetInitializedCacheValue(
+ "CMAKE_BACKWARDS_COMPATIBILITY"))) {
+ // Set it to 2.4 because that is the last version where the
+ // variable had meaning.
+ status.GetMakefile().AddCacheDefinition(
+ "CMAKE_BACKWARDS_COMPATIBILITY", "2.4",
+ "For backwards compatibility, what version of CMake "
+ "commands and "
+ "syntax should this version of CMake try to support.",
+ cmStateEnums::STRING);
+ }
+ }
+ return true;
+}
+
+bool HandleGetMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ bool parent_scope = false;
+ if (args.size() == 4 && args[3] == "PARENT_SCOPE") {
+ // Undocumented PARENT_SCOPE option for use within CMake.
+ parent_scope = true;
+ } else if (args.size() != 3) {
+ status.SetError("GET must be given exactly 2 additional arguments.");
+ return false;
+ }
+
+ // Get arguments.
+ std::string const& id = args[1];
+ std::string const& var = args[2];
+
+ // Lookup the policy number.
+ cmPolicies::PolicyID pid;
+ if (!cmPolicies::GetPolicyID(id.c_str(), pid)) {
+ status.SetError(
+ cmStrCat("GET given policy \"", id,
+ "\" which is not known to this version of CMake."));
+ return false;
+ }
+
+ // Lookup the policy setting.
+ cmPolicies::PolicyStatus policyStatus =
+ status.GetMakefile().GetPolicyStatus(pid, parent_scope);
+ switch (policyStatus) {
+ case cmPolicies::OLD:
+ // Report that the policy is set to OLD.
+ status.GetMakefile().AddDefinition(var, "OLD");
+ break;
+ case cmPolicies::WARN:
+ // Report that the policy is not set.
+ status.GetMakefile().AddDefinition(var, "");
+ break;
+ case cmPolicies::NEW:
+ // Report that the policy is set to NEW.
+ status.GetMakefile().AddDefinition(var, "NEW");
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ // The policy is required to be set before anything needs it.
+ {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(
+ cmPolicies::GetRequiredPolicyError(pid), "\n",
+ "The call to cmake_policy(GET ", id,
+ " ...) at which this "
+ "error appears requests the policy, and this version of CMake ",
+ "requires that the policy be set to NEW before it is checked."));
+ }
+ }
+
+ return true;
+}
+
+bool HandleVersionMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() <= 1) {
+ status.SetError("VERSION not given an argument");
+ return false;
+ }
+ if (args.size() >= 3) {
+ status.SetError("VERSION given too many arguments");
+ return false;
+ }
+ std::string const& version_string = args[1];
+
+ // Separate the <min> version and any trailing ...<max> component.
+ std::string::size_type const dd = version_string.find("...");
+ std::string const version_min = version_string.substr(0, dd);
+ std::string const version_max = dd != std::string::npos
+ ? version_string.substr(dd + 3, std::string::npos)
+ : std::string();
+ if (dd != std::string::npos &&
+ (version_min.empty() || version_max.empty())) {
+ status.SetError(
+ cmStrCat("VERSION \"", version_string,
+ R"(" does not have a version on both sides of "...".)"));
+ return false;
+ }
+
+ return status.GetMakefile().SetPolicyVersion(version_min, version_max);
+}
+
+bool HandleGetWarningMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError(
+ "GET_WARNING must be given exactly 2 additional arguments.");
+ return false;
+ }
+
+ // Get arguments.
+ std::string const& id = args[1];
+ std::string const& var = args[2];
+
+ // Lookup the policy number.
+ cmPolicies::PolicyID pid;
+ if (!cmPolicies::GetPolicyID(id.c_str(), pid)) {
+ status.SetError(
+ cmStrCat("GET_WARNING given policy \"", id,
+ "\" which is not known to this version of CMake."));
+ return false;
+ }
+
+ // Lookup the policy warning.
+ status.GetMakefile().AddDefinition(var, cmPolicies::GetPolicyWarning(pid));
+
+ return true;
+}
+}
diff --git a/Source/cmCMakePolicyCommand.h b/Source/cmCMakePolicyCommand.h
new file mode 100644
index 0000000..7346b66
--- /dev/null
+++ b/Source/cmCMakePolicyCommand.h
@@ -0,0 +1,19 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Set how CMake should handle policies
+ *
+ * cmCMakePolicyCommand sets how CMake should deal with backwards
+ * compatibility policies.
+ */
+bool cmCMakePolicyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmCMakePresetsFile.cxx b/Source/cmCMakePresetsFile.cxx
new file mode 100644
index 0000000..39cce98
--- /dev/null
+++ b/Source/cmCMakePresetsFile.cxx
@@ -0,0 +1,1103 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCMakePresetsFile.h"
+
+#include <algorithm>
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <iterator>
+#include <utility>
+
+#include <cm/string_view>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCMakePresetsFileInternal.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+#define CHECK_EXPAND(out, field, expanders, version) \
+ { \
+ switch (ExpandMacros(field, expanders, version)) { \
+ case ExpandMacroResult::Error: \
+ return false; \
+ case ExpandMacroResult::Ignore: \
+ out.reset(); \
+ return true; \
+ case ExpandMacroResult::Ok: \
+ break; \
+ } \
+ }
+
+namespace {
+enum class CycleStatus
+{
+ Unvisited,
+ InProgress,
+ Verified,
+};
+
+using ReadFileResult = cmCMakePresetsFile::ReadFileResult;
+using ConfigurePreset = cmCMakePresetsFile::ConfigurePreset;
+using BuildPreset = cmCMakePresetsFile::BuildPreset;
+using TestPreset = cmCMakePresetsFile::TestPreset;
+using ExpandMacroResult = cmCMakePresetsFileInternal::ExpandMacroResult;
+using MacroExpander = cmCMakePresetsFileInternal::MacroExpander;
+
+void InheritString(std::string& child, const std::string& parent)
+{
+ if (child.empty()) {
+ child = parent;
+ }
+}
+
+template <typename T>
+void InheritOptionalValue(cm::optional<T>& child,
+ const cm::optional<T>& parent)
+{
+ if (!child) {
+ child = parent;
+ }
+}
+
+template <typename T>
+void InheritVector(std::vector<T>& child, const std::vector<T>& parent)
+{
+ if (child.empty()) {
+ child = parent;
+ }
+}
+
+/**
+ * Check preset inheritance for cycles (using a DAG check algorithm) while
+ * also bubbling up fields through the inheritance hierarchy, then verify
+ * that each preset has the required fields, either directly or through
+ * inheritance.
+ */
+template <class T>
+ReadFileResult VisitPreset(
+ T& preset, std::map<std::string, cmCMakePresetsFile::PresetPair<T>>& presets,
+ std::map<std::string, CycleStatus> cycleStatus, int version)
+{
+ switch (cycleStatus[preset.Name]) {
+ case CycleStatus::InProgress:
+ return ReadFileResult::CYCLIC_PRESET_INHERITANCE;
+ case CycleStatus::Verified:
+ return ReadFileResult::READ_OK;
+ default:
+ break;
+ }
+
+ cycleStatus[preset.Name] = CycleStatus::InProgress;
+
+ if (preset.Environment.count("") != 0) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+
+ CHECK_OK(preset.VisitPresetBeforeInherit())
+
+ for (auto const& i : preset.Inherits) {
+ auto parent = presets.find(i);
+ if (parent == presets.end()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+
+ auto& parentPreset = parent->second.Unexpanded;
+ if (!preset.User && parentPreset.User) {
+ return ReadFileResult::USER_PRESET_INHERITANCE;
+ }
+
+ auto result = VisitPreset(parentPreset, presets, cycleStatus, version);
+ if (result != ReadFileResult::READ_OK) {
+ return result;
+ }
+
+ CHECK_OK(preset.VisitPresetInherit(parentPreset))
+
+ for (auto const& v : parentPreset.Environment) {
+ preset.Environment.insert(v);
+ }
+
+ if (!preset.ConditionEvaluator) {
+ preset.ConditionEvaluator = parentPreset.ConditionEvaluator;
+ }
+ }
+
+ if (preset.ConditionEvaluator && preset.ConditionEvaluator->IsNull()) {
+ preset.ConditionEvaluator.reset();
+ }
+
+ CHECK_OK(preset.VisitPresetAfterInherit(version))
+
+ cycleStatus[preset.Name] = CycleStatus::Verified;
+ return ReadFileResult::READ_OK;
+}
+
+template <class T>
+ReadFileResult ComputePresetInheritance(
+ std::map<std::string, cmCMakePresetsFile::PresetPair<T>>& presets,
+ const cmCMakePresetsFile& file)
+{
+ std::map<std::string, CycleStatus> cycleStatus;
+ for (auto const& it : presets) {
+ cycleStatus[it.first] = CycleStatus::Unvisited;
+ }
+
+ for (auto& it : presets) {
+ auto& preset = it.second.Unexpanded;
+ auto result =
+ VisitPreset<T>(preset, presets, cycleStatus, file.GetVersion(preset));
+ if (result != ReadFileResult::READ_OK) {
+ return result;
+ }
+ }
+
+ return ReadFileResult::READ_OK;
+}
+
+constexpr const char* ValidPrefixes[] = {
+ "",
+ "env",
+ "penv",
+ "vendor",
+};
+
+bool PrefixesValidMacroNamespace(const std::string& str)
+{
+ return std::any_of(
+ std::begin(ValidPrefixes), std::end(ValidPrefixes),
+ [&str](const char* prefix) -> bool { return cmHasPrefix(prefix, str); });
+}
+
+bool IsValidMacroNamespace(const std::string& str)
+{
+ return std::any_of(
+ std::begin(ValidPrefixes), std::end(ValidPrefixes),
+ [&str](const char* prefix) -> bool { return str == prefix; });
+}
+
+ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status,
+ const std::vector<MacroExpander>& macroExpanders,
+ int version);
+ExpandMacroResult ExpandMacros(
+ std::string& out, const std::vector<MacroExpander>& macroExpanders,
+ int version);
+ExpandMacroResult ExpandMacro(std::string& out,
+ const std::string& macroNamespace,
+ const std::string& macroName,
+ const std::vector<MacroExpander>& macroExpanders,
+ int version);
+
+bool ExpandMacros(const cmCMakePresetsFile& file,
+ const ConfigurePreset& preset,
+ cm::optional<ConfigurePreset>& out,
+ const std::vector<MacroExpander>& macroExpanders)
+{
+ std::string binaryDir = preset.BinaryDir;
+ CHECK_EXPAND(out, binaryDir, macroExpanders, file.GetVersion(preset))
+
+ if (!cmSystemTools::FileIsFullPath(binaryDir)) {
+ binaryDir = cmStrCat(file.SourceDir, '/', binaryDir);
+ }
+ out->BinaryDir = cmSystemTools::CollapseFullPath(binaryDir);
+ cmSystemTools::ConvertToUnixSlashes(out->BinaryDir);
+
+ if (!preset.InstallDir.empty()) {
+ std::string installDir = preset.InstallDir;
+ CHECK_EXPAND(out, installDir, macroExpanders, file.GetVersion(preset))
+
+ if (!cmSystemTools::FileIsFullPath(installDir)) {
+ installDir = cmStrCat(file.SourceDir, '/', installDir);
+ }
+ out->InstallDir = cmSystemTools::CollapseFullPath(installDir);
+ cmSystemTools::ConvertToUnixSlashes(out->InstallDir);
+ }
+
+ for (auto& variable : out->CacheVariables) {
+ if (variable.second) {
+ CHECK_EXPAND(out, variable.second->Value, macroExpanders,
+ file.GetVersion(preset))
+ }
+ }
+
+ return true;
+}
+
+bool ExpandMacros(const cmCMakePresetsFile& file, const BuildPreset& preset,
+ cm::optional<BuildPreset>& out,
+ const std::vector<MacroExpander>& macroExpanders)
+{
+ for (auto& target : out->Targets) {
+ CHECK_EXPAND(out, target, macroExpanders, file.GetVersion(preset))
+ }
+
+ for (auto& nativeToolOption : out->NativeToolOptions) {
+ CHECK_EXPAND(out, nativeToolOption, macroExpanders,
+ file.GetVersion(preset))
+ }
+
+ return true;
+}
+
+bool ExpandMacros(const cmCMakePresetsFile& file, const TestPreset& preset,
+ cm::optional<TestPreset>& out,
+ const std::vector<MacroExpander>& macroExpanders)
+{
+ for (auto& overwrite : out->OverwriteConfigurationFile) {
+ CHECK_EXPAND(out, overwrite, macroExpanders, file.GetVersion(preset));
+ }
+
+ if (out->Output) {
+ CHECK_EXPAND(out, out->Output->OutputLogFile, macroExpanders,
+ file.GetVersion(preset))
+ }
+
+ if (out->Filter) {
+ if (out->Filter->Include) {
+ CHECK_EXPAND(out, out->Filter->Include->Name, macroExpanders,
+ file.GetVersion(preset))
+ CHECK_EXPAND(out, out->Filter->Include->Label, macroExpanders,
+ file.GetVersion(preset))
+
+ if (out->Filter->Include->Index) {
+ CHECK_EXPAND(out, out->Filter->Include->Index->IndexFile,
+ macroExpanders, file.GetVersion(preset));
+ }
+ }
+
+ if (out->Filter->Exclude) {
+ CHECK_EXPAND(out, out->Filter->Exclude->Name, macroExpanders,
+ file.GetVersion(preset))
+ CHECK_EXPAND(out, out->Filter->Exclude->Label, macroExpanders,
+ file.GetVersion(preset))
+
+ if (out->Filter->Exclude->Fixtures) {
+ CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Any, macroExpanders,
+ file.GetVersion(preset))
+ CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Setup,
+ macroExpanders, file.GetVersion(preset))
+ CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Cleanup,
+ macroExpanders, file.GetVersion(preset))
+ }
+ }
+ }
+
+ if (out->Execution) {
+ CHECK_EXPAND(out, out->Execution->ResourceSpecFile, macroExpanders,
+ file.GetVersion(preset))
+ }
+
+ return true;
+}
+
+template <class T>
+bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset,
+ cm::optional<T>& out)
+{
+ out.emplace(preset);
+
+ std::map<std::string, CycleStatus> envCycles;
+ for (auto const& v : out->Environment) {
+ envCycles[v.first] = CycleStatus::Unvisited;
+ }
+
+ std::vector<MacroExpander> macroExpanders;
+
+ MacroExpander defaultMacroExpander =
+ [&file, &preset](const std::string& macroNamespace,
+ const std::string& macroName, std::string& macroOut,
+ int version) -> ExpandMacroResult {
+ if (macroNamespace.empty()) {
+ if (macroName == "sourceDir") {
+ macroOut += file.SourceDir;
+ return ExpandMacroResult::Ok;
+ }
+ if (macroName == "sourceParentDir") {
+ macroOut += cmSystemTools::GetParentDirectory(file.SourceDir);
+ return ExpandMacroResult::Ok;
+ }
+ if (macroName == "sourceDirName") {
+ macroOut += cmSystemTools::GetFilenameName(file.SourceDir);
+ return ExpandMacroResult::Ok;
+ }
+ if (macroName == "presetName") {
+ macroOut += preset.Name;
+ return ExpandMacroResult::Ok;
+ }
+ if (macroName == "generator") {
+ // Generator only makes sense if preset is not hidden.
+ if (!preset.Hidden) {
+ macroOut += file.GetGeneratorForPreset(preset.Name);
+ }
+ return ExpandMacroResult::Ok;
+ }
+ if (macroName == "dollar") {
+ macroOut += '$';
+ return ExpandMacroResult::Ok;
+ }
+ if (macroName == "hostSystemName") {
+ if (version < 3) {
+ return ExpandMacroResult::Error;
+ }
+ macroOut += cmSystemTools::GetSystemName();
+ return ExpandMacroResult::Ok;
+ }
+ }
+
+ return ExpandMacroResult::Ignore;
+ };
+
+ MacroExpander environmentMacroExpander =
+ [&macroExpanders, &out, &envCycles](
+ const std::string& macroNamespace, const std::string& macroName,
+ std::string& result, int version) -> ExpandMacroResult {
+ if (macroNamespace == "env" && !macroName.empty() && out) {
+ auto v = out->Environment.find(macroName);
+ if (v != out->Environment.end() && v->second) {
+ auto e =
+ VisitEnv(*v->second, envCycles[macroName], macroExpanders, version);
+ if (e != ExpandMacroResult::Ok) {
+ return e;
+ }
+ result += *v->second;
+ return ExpandMacroResult::Ok;
+ }
+ }
+
+ if (macroNamespace == "env" || macroNamespace == "penv") {
+ if (macroName.empty()) {
+ return ExpandMacroResult::Error;
+ }
+ const char* value = std::getenv(macroName.c_str());
+ if (value) {
+ result += value;
+ }
+ return ExpandMacroResult::Ok;
+ }
+
+ return ExpandMacroResult::Ignore;
+ };
+
+ macroExpanders.push_back(defaultMacroExpander);
+ macroExpanders.push_back(environmentMacroExpander);
+
+ for (auto& v : out->Environment) {
+ if (v.second) {
+ switch (VisitEnv(*v.second, envCycles[v.first], macroExpanders,
+ file.GetVersion(preset))) {
+ case ExpandMacroResult::Error:
+ return false;
+ case ExpandMacroResult::Ignore:
+ out.reset();
+ return true;
+ case ExpandMacroResult::Ok:
+ break;
+ }
+ }
+ }
+
+ if (preset.ConditionEvaluator) {
+ cm::optional<bool> result;
+ if (!preset.ConditionEvaluator->Evaluate(
+ macroExpanders, file.GetVersion(preset), result)) {
+ return false;
+ }
+ if (!result) {
+ out.reset();
+ return true;
+ }
+ out->ConditionResult = *result;
+ }
+
+ return ExpandMacros(file, preset, out, macroExpanders);
+}
+
+ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status,
+ const std::vector<MacroExpander>& macroExpanders,
+ int version)
+{
+ if (status == CycleStatus::Verified) {
+ return ExpandMacroResult::Ok;
+ }
+ if (status == CycleStatus::InProgress) {
+ return ExpandMacroResult::Error;
+ }
+
+ status = CycleStatus::InProgress;
+ auto e = ExpandMacros(value, macroExpanders, version);
+ if (e != ExpandMacroResult::Ok) {
+ return e;
+ }
+ status = CycleStatus::Verified;
+ return ExpandMacroResult::Ok;
+}
+
+ExpandMacroResult ExpandMacros(
+ std::string& out, const std::vector<MacroExpander>& macroExpanders,
+ int version)
+{
+ std::string result;
+ std::string macroNamespace;
+ std::string macroName;
+
+ enum class State
+ {
+ Default,
+ MacroNamespace,
+ MacroName,
+ } state = State::Default;
+
+ for (auto c : out) {
+ switch (state) {
+ case State::Default:
+ if (c == '$') {
+ state = State::MacroNamespace;
+ } else {
+ result += c;
+ }
+ break;
+
+ case State::MacroNamespace:
+ if (c == '{') {
+ if (IsValidMacroNamespace(macroNamespace)) {
+ state = State::MacroName;
+ } else {
+ result += '$';
+ result += macroNamespace;
+ result += '{';
+ macroNamespace.clear();
+ state = State::Default;
+ }
+ } else {
+ macroNamespace += c;
+ if (!PrefixesValidMacroNamespace(macroNamespace)) {
+ result += '$';
+ result += macroNamespace;
+ macroNamespace.clear();
+ state = State::Default;
+ }
+ }
+ break;
+
+ case State::MacroName:
+ if (c == '}') {
+ auto e = ExpandMacro(result, macroNamespace, macroName,
+ macroExpanders, version);
+ if (e != ExpandMacroResult::Ok) {
+ return e;
+ }
+ macroNamespace.clear();
+ macroName.clear();
+ state = State::Default;
+ } else {
+ macroName += c;
+ }
+ break;
+ }
+ }
+
+ switch (state) {
+ case State::Default:
+ break;
+ case State::MacroNamespace:
+ result += '$';
+ result += macroNamespace;
+ break;
+ case State::MacroName:
+ return ExpandMacroResult::Error;
+ }
+
+ out = std::move(result);
+ return ExpandMacroResult::Ok;
+}
+
+ExpandMacroResult ExpandMacro(std::string& out,
+ const std::string& macroNamespace,
+ const std::string& macroName,
+ const std::vector<MacroExpander>& macroExpanders,
+ int version)
+{
+ for (auto const& macroExpander : macroExpanders) {
+ auto result = macroExpander(macroNamespace, macroName, out, version);
+ if (result != ExpandMacroResult::Ignore) {
+ return result;
+ }
+ }
+
+ if (macroNamespace == "vendor") {
+ return ExpandMacroResult::Ignore;
+ }
+
+ return ExpandMacroResult::Error;
+}
+}
+
+bool cmCMakePresetsFileInternal::EqualsCondition::Evaluate(
+ const std::vector<MacroExpander>& expanders, int version,
+ cm::optional<bool>& out) const
+{
+ std::string lhs = this->Lhs;
+ CHECK_EXPAND(out, lhs, expanders, version);
+
+ std::string rhs = this->Rhs;
+ CHECK_EXPAND(out, rhs, expanders, version);
+
+ out = (lhs == rhs);
+ return true;
+}
+
+bool cmCMakePresetsFileInternal::InListCondition::Evaluate(
+ const std::vector<MacroExpander>& expanders, int version,
+ cm::optional<bool>& out) const
+{
+ std::string str = this->String;
+ CHECK_EXPAND(out, str, expanders, version);
+
+ for (auto item : this->List) {
+ CHECK_EXPAND(out, item, expanders, version);
+ if (str == item) {
+ out = true;
+ return true;
+ }
+ }
+
+ out = false;
+ return true;
+}
+
+bool cmCMakePresetsFileInternal::MatchesCondition::Evaluate(
+ const std::vector<MacroExpander>& expanders, int version,
+ cm::optional<bool>& out) const
+{
+ std::string str = this->String;
+ CHECK_EXPAND(out, str, expanders, version);
+ std::string regexStr = this->Regex;
+ CHECK_EXPAND(out, regexStr, expanders, version);
+
+ cmsys::RegularExpression regex;
+ if (!regex.compile(regexStr)) {
+ return false;
+ }
+
+ out = regex.find(str);
+ return true;
+}
+
+bool cmCMakePresetsFileInternal::AnyAllOfCondition::Evaluate(
+ const std::vector<MacroExpander>& expanders, int version,
+ cm::optional<bool>& out) const
+{
+ for (auto const& condition : this->Conditions) {
+ cm::optional<bool> result;
+ if (!condition->Evaluate(expanders, version, result)) {
+ out.reset();
+ return false;
+ }
+
+ if (!result) {
+ out.reset();
+ return true;
+ }
+
+ if (result == this->StopValue) {
+ out = result;
+ return true;
+ }
+ }
+
+ out = !this->StopValue;
+ return true;
+}
+
+bool cmCMakePresetsFileInternal::NotCondition::Evaluate(
+ const std::vector<MacroExpander>& expanders, int version,
+ cm::optional<bool>& out) const
+{
+ out.reset();
+ if (!this->SubCondition->Evaluate(expanders, version, out)) {
+ out.reset();
+ return false;
+ }
+ if (out) {
+ *out = !*out;
+ }
+ return true;
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::ConfigurePreset::VisitPresetInherit(
+ const cmCMakePresetsFile::Preset& parentPreset)
+{
+ auto& preset = *this;
+ const ConfigurePreset& parent =
+ static_cast<const ConfigurePreset&>(parentPreset);
+ InheritString(preset.Generator, parent.Generator);
+ InheritString(preset.Architecture, parent.Architecture);
+ InheritString(preset.Toolset, parent.Toolset);
+ if (!preset.ArchitectureStrategy) {
+ preset.ArchitectureStrategy = parent.ArchitectureStrategy;
+ }
+ if (!preset.ToolsetStrategy) {
+ preset.ToolsetStrategy = parent.ToolsetStrategy;
+ }
+ InheritString(preset.BinaryDir, parent.BinaryDir);
+ InheritString(preset.InstallDir, parent.InstallDir);
+ InheritOptionalValue(preset.WarnDev, parent.WarnDev);
+ InheritOptionalValue(preset.ErrorDev, parent.ErrorDev);
+ InheritOptionalValue(preset.WarnDeprecated, parent.WarnDeprecated);
+ InheritOptionalValue(preset.ErrorDeprecated, parent.ErrorDeprecated);
+ InheritOptionalValue(preset.WarnUninitialized, parent.WarnUninitialized);
+ InheritOptionalValue(preset.WarnUnusedCli, parent.WarnUnusedCli);
+ InheritOptionalValue(preset.WarnSystemVars, parent.WarnSystemVars);
+
+ for (auto const& v : parent.CacheVariables) {
+ preset.CacheVariables.insert(v);
+ }
+
+ return ReadFileResult::READ_OK;
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::ConfigurePreset::VisitPresetBeforeInherit()
+{
+ auto& preset = *this;
+ if (preset.Environment.count("") != 0) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+
+ return ReadFileResult::READ_OK;
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::ConfigurePreset::VisitPresetAfterInherit(int version)
+{
+ auto& preset = *this;
+ if (!preset.Hidden) {
+ if (version < 3) {
+ if (preset.Generator.empty()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+ if (preset.BinaryDir.empty()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+ }
+
+ if (preset.WarnDev == false && preset.ErrorDev == true) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+ if (preset.WarnDeprecated == false && preset.ErrorDeprecated == true) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+ if (preset.CacheVariables.count("") != 0) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+ }
+
+ return ReadFileResult::READ_OK;
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::BuildPreset::VisitPresetInherit(
+ const cmCMakePresetsFile::Preset& parentPreset)
+{
+ auto& preset = *this;
+ const BuildPreset& parent = static_cast<const BuildPreset&>(parentPreset);
+
+ InheritString(preset.ConfigurePreset, parent.ConfigurePreset);
+ InheritOptionalValue(preset.InheritConfigureEnvironment,
+ parent.InheritConfigureEnvironment);
+ InheritOptionalValue(preset.Jobs, parent.Jobs);
+ InheritVector(preset.Targets, parent.Targets);
+ InheritString(preset.Configuration, parent.Configuration);
+ InheritOptionalValue(preset.CleanFirst, parent.CleanFirst);
+ InheritOptionalValue(preset.Verbose, parent.Verbose);
+ InheritVector(preset.NativeToolOptions, parent.NativeToolOptions);
+
+ return ReadFileResult::READ_OK;
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::BuildPreset::VisitPresetAfterInherit(int /* version */)
+{
+ auto& preset = *this;
+ if (!preset.Hidden && preset.ConfigurePreset.empty()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+ return ReadFileResult::READ_OK;
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::TestPreset::VisitPresetInherit(
+ const cmCMakePresetsFile::Preset& parentPreset)
+{
+ auto& preset = *this;
+ const TestPreset& parent = static_cast<const TestPreset&>(parentPreset);
+
+ InheritString(preset.ConfigurePreset, parent.ConfigurePreset);
+ InheritOptionalValue(preset.InheritConfigureEnvironment,
+ parent.InheritConfigureEnvironment);
+ InheritString(preset.Configuration, parent.Configuration);
+ InheritVector(preset.OverwriteConfigurationFile,
+ parent.OverwriteConfigurationFile);
+
+ if (parent.Output) {
+ if (preset.Output) {
+ auto& output = preset.Output.value();
+ const auto& parentOutput = parent.Output.value();
+ InheritOptionalValue(output.ShortProgress, parentOutput.ShortProgress);
+ InheritOptionalValue(output.Verbosity, parentOutput.Verbosity);
+ InheritOptionalValue(output.Debug, parentOutput.Debug);
+ InheritOptionalValue(output.OutputOnFailure,
+ parentOutput.OutputOnFailure);
+ InheritOptionalValue(output.Quiet, parentOutput.Quiet);
+ InheritString(output.OutputLogFile, parentOutput.OutputLogFile);
+ InheritOptionalValue(output.LabelSummary, parentOutput.LabelSummary);
+ InheritOptionalValue(output.SubprojectSummary,
+ parentOutput.SubprojectSummary);
+ InheritOptionalValue(output.MaxPassedTestOutputSize,
+ parentOutput.MaxPassedTestOutputSize);
+ InheritOptionalValue(output.MaxFailedTestOutputSize,
+ parentOutput.MaxFailedTestOutputSize);
+ InheritOptionalValue(output.MaxTestNameWidth,
+ parentOutput.MaxTestNameWidth);
+ } else {
+ preset.Output = parent.Output;
+ }
+ }
+
+ if (parent.Filter) {
+ if (parent.Filter->Include) {
+ if (preset.Filter && preset.Filter->Include) {
+ auto& include = *preset.Filter->Include;
+ const auto& parentInclude = *parent.Filter->Include;
+ InheritString(include.Name, parentInclude.Name);
+ InheritString(include.Label, parentInclude.Label);
+ InheritOptionalValue(include.Index, parentInclude.Index);
+ } else {
+ if (!preset.Filter) {
+ preset.Filter.emplace();
+ }
+ preset.Filter->Include = parent.Filter->Include;
+ }
+ }
+
+ if (parent.Filter->Exclude) {
+ if (preset.Filter && preset.Filter->Exclude) {
+ auto& exclude = *preset.Filter->Exclude;
+ const auto& parentExclude = *parent.Filter->Exclude;
+ InheritString(exclude.Name, parentExclude.Name);
+ InheritString(exclude.Label, parentExclude.Label);
+ InheritOptionalValue(exclude.Fixtures, parentExclude.Fixtures);
+ } else {
+ if (!preset.Filter) {
+ preset.Filter.emplace();
+ }
+ preset.Filter->Exclude = parent.Filter->Exclude;
+ }
+ }
+ }
+
+ if (parent.Execution) {
+ if (preset.Execution) {
+ auto& execution = *preset.Execution;
+ const auto& parentExecution = *parent.Execution;
+ InheritOptionalValue(execution.StopOnFailure,
+ parentExecution.StopOnFailure);
+ InheritOptionalValue(execution.EnableFailover,
+ parentExecution.EnableFailover);
+ InheritOptionalValue(execution.Jobs, parentExecution.Jobs);
+ InheritString(execution.ResourceSpecFile,
+ parentExecution.ResourceSpecFile);
+ InheritOptionalValue(execution.TestLoad, parentExecution.TestLoad);
+ InheritOptionalValue(execution.ShowOnly, parentExecution.ShowOnly);
+ InheritOptionalValue(execution.Repeat, parentExecution.Repeat);
+ InheritOptionalValue(execution.InteractiveDebugging,
+ parentExecution.InteractiveDebugging);
+ InheritOptionalValue(execution.ScheduleRandom,
+ parentExecution.ScheduleRandom);
+ InheritOptionalValue(execution.Timeout, parentExecution.Timeout);
+ InheritOptionalValue(execution.NoTestsAction,
+ parentExecution.NoTestsAction);
+ } else {
+ preset.Execution = parent.Execution;
+ }
+ }
+
+ return ReadFileResult::READ_OK;
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::TestPreset::VisitPresetAfterInherit(int /* version */)
+{
+ auto& preset = *this;
+ if (!preset.Hidden && preset.ConfigurePreset.empty()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+ return ReadFileResult::READ_OK;
+}
+
+std::string cmCMakePresetsFile::GetFilename(const std::string& sourceDir)
+{
+ return cmStrCat(sourceDir, "/CMakePresets.json");
+}
+
+std::string cmCMakePresetsFile::GetUserFilename(const std::string& sourceDir)
+{
+ return cmStrCat(sourceDir, "/CMakeUserPresets.json");
+}
+
+cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadProjectPresets(
+ const std::string& sourceDir, bool allowNoFiles)
+{
+ this->SourceDir = sourceDir;
+ this->ClearPresets();
+
+ auto result = this->ReadProjectPresetsInternal(allowNoFiles);
+ if (result != ReadFileResult::READ_OK) {
+ this->ClearPresets();
+ }
+
+ return result;
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::ReadProjectPresetsInternal(bool allowNoFiles)
+{
+ bool haveOneFile = false;
+
+ std::string filename = GetUserFilename(this->SourceDir);
+ if (cmSystemTools::FileExists(filename)) {
+ auto result = this->ReadJSONFile(filename, true);
+ if (result != ReadFileResult::READ_OK) {
+ return result;
+ }
+ haveOneFile = true;
+ }
+
+ filename = GetFilename(this->SourceDir);
+ if (cmSystemTools::FileExists(filename)) {
+ auto result = this->ReadJSONFile(filename, false);
+ if (result != ReadFileResult::READ_OK) {
+ return result;
+ }
+ haveOneFile = true;
+ }
+
+ if (!haveOneFile) {
+ return allowNoFiles ? ReadFileResult::READ_OK
+ : ReadFileResult::FILE_NOT_FOUND;
+ }
+
+ CHECK_OK(ComputePresetInheritance(this->ConfigurePresets, *this))
+ CHECK_OK(ComputePresetInheritance(this->BuildPresets, *this))
+ CHECK_OK(ComputePresetInheritance(this->TestPresets, *this))
+
+ for (auto& it : this->ConfigurePresets) {
+ if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
+ return ReadFileResult::INVALID_MACRO_EXPANSION;
+ }
+ }
+
+ for (auto& it : this->BuildPresets) {
+ if (!it.second.Unexpanded.Hidden) {
+ const auto configurePreset =
+ this->ConfigurePresets.find(it.second.Unexpanded.ConfigurePreset);
+ if (configurePreset == this->ConfigurePresets.end()) {
+ return ReadFileResult::INVALID_CONFIGURE_PRESET;
+ }
+
+ if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true)) {
+ it.second.Unexpanded.Environment.insert(
+ configurePreset->second.Unexpanded.Environment.begin(),
+ configurePreset->second.Unexpanded.Environment.end());
+ }
+ }
+
+ if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
+ return ReadFileResult::INVALID_MACRO_EXPANSION;
+ }
+ }
+
+ for (auto& it : this->TestPresets) {
+ if (!it.second.Unexpanded.Hidden) {
+ const auto configurePreset =
+ this->ConfigurePresets.find(it.second.Unexpanded.ConfigurePreset);
+ if (configurePreset == this->ConfigurePresets.end()) {
+ return ReadFileResult::INVALID_CONFIGURE_PRESET;
+ }
+
+ if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true)) {
+ it.second.Unexpanded.Environment.insert(
+ configurePreset->second.Unexpanded.Environment.begin(),
+ configurePreset->second.Unexpanded.Environment.end());
+ }
+ }
+
+ if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
+ return ReadFileResult::INVALID_MACRO_EXPANSION;
+ }
+ }
+
+ return ReadFileResult::READ_OK;
+}
+
+const char* cmCMakePresetsFile::ResultToString(ReadFileResult result)
+{
+ switch (result) {
+ case ReadFileResult::READ_OK:
+ return "OK";
+ case ReadFileResult::FILE_NOT_FOUND:
+ return "File not found";
+ case ReadFileResult::JSON_PARSE_ERROR:
+ return "JSON parse error";
+ case ReadFileResult::INVALID_ROOT:
+ return "Invalid root object";
+ case ReadFileResult::NO_VERSION:
+ return "No \"version\" field";
+ case ReadFileResult::INVALID_VERSION:
+ return "Invalid \"version\" field";
+ case ReadFileResult::UNRECOGNIZED_VERSION:
+ return "Unrecognized \"version\" field";
+ case ReadFileResult::INVALID_CMAKE_VERSION:
+ return "Invalid \"cmakeMinimumRequired\" field";
+ case ReadFileResult::UNRECOGNIZED_CMAKE_VERSION:
+ return "\"cmakeMinimumRequired\" version too new";
+ case ReadFileResult::INVALID_PRESETS:
+ return "Invalid \"configurePresets\" field";
+ case ReadFileResult::INVALID_PRESET:
+ return "Invalid preset";
+ case ReadFileResult::INVALID_VARIABLE:
+ return "Invalid CMake variable definition";
+ case ReadFileResult::DUPLICATE_PRESETS:
+ return "Duplicate presets";
+ case ReadFileResult::CYCLIC_PRESET_INHERITANCE:
+ return "Cyclic preset inheritance";
+ case ReadFileResult::USER_PRESET_INHERITANCE:
+ return "Project preset inherits from user preset";
+ case ReadFileResult::INVALID_MACRO_EXPANSION:
+ return "Invalid macro expansion";
+ case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED:
+ return "File version must be 2 or higher for build and test preset "
+ "support.";
+ case ReadFileResult::INVALID_CONFIGURE_PRESET:
+ return "Invalid \"configurePreset\" field";
+ case ReadFileResult::INSTALL_PREFIX_UNSUPPORTED:
+ return "File version must be 3 or higher for installDir preset "
+ "support.";
+ case ReadFileResult::INVALID_CONDITION:
+ return "Invalid preset condition";
+ case ReadFileResult::CONDITION_UNSUPPORTED:
+ return "File version must be 3 or higher for condition support";
+ }
+
+ return "Unknown error";
+}
+
+void cmCMakePresetsFile::ClearPresets()
+{
+ this->ConfigurePresets.clear();
+ this->BuildPresets.clear();
+ this->TestPresets.clear();
+
+ this->ConfigurePresetOrder.clear();
+ this->BuildPresetOrder.clear();
+ this->TestPresetOrder.clear();
+}
+
+void cmCMakePresetsFile::PrintPresets(
+ const std::vector<const cmCMakePresetsFile::Preset*>& presets)
+{
+ if (presets.empty()) {
+ return;
+ }
+
+ auto longestPresetName =
+ std::max_element(presets.begin(), presets.end(),
+ [](const cmCMakePresetsFile::Preset* a,
+ const cmCMakePresetsFile::Preset* b) {
+ return a->Name.length() < b->Name.length();
+ });
+ auto longestLength = (*longestPresetName)->Name.length();
+
+ for (const auto* preset : presets) {
+ std::cout << " \"" << preset->Name << '"';
+ const auto& description = preset->DisplayName;
+ if (!description.empty()) {
+ for (std::size_t i = 0; i < longestLength - preset->Name.length(); ++i) {
+ std::cout << ' ';
+ }
+ std::cout << " - " << description;
+ }
+ std::cout << '\n';
+ }
+}
+
+void cmCMakePresetsFile::PrintConfigurePresetList() const
+{
+ PrintConfigurePresetList([](const ConfigurePreset&) { return true; });
+}
+
+void cmCMakePresetsFile::PrintConfigurePresetList(
+ const std::function<bool(const ConfigurePreset&)>& filter) const
+{
+ std::vector<const cmCMakePresetsFile::Preset*> presets;
+ for (auto const& p : this->ConfigurePresetOrder) {
+ auto const& preset = this->ConfigurePresets.at(p);
+ if (!preset.Unexpanded.Hidden && preset.Expanded &&
+ preset.Expanded->ConditionResult && filter(preset.Unexpanded)) {
+ presets.push_back(
+ static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
+ }
+ }
+
+ if (!presets.empty()) {
+ std::cout << "Available configure presets:\n\n";
+ cmCMakePresetsFile::PrintPresets(presets);
+ }
+}
+
+void cmCMakePresetsFile::PrintBuildPresetList() const
+{
+ std::vector<const cmCMakePresetsFile::Preset*> presets;
+ for (auto const& p : this->BuildPresetOrder) {
+ auto const& preset = this->BuildPresets.at(p);
+ if (!preset.Unexpanded.Hidden && preset.Expanded &&
+ preset.Expanded->ConditionResult) {
+ presets.push_back(
+ static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
+ }
+ }
+
+ if (!presets.empty()) {
+ std::cout << "Available build presets:\n\n";
+ cmCMakePresetsFile::PrintPresets(presets);
+ }
+}
+
+void cmCMakePresetsFile::PrintTestPresetList() const
+{
+ std::vector<const cmCMakePresetsFile::Preset*> presets;
+ for (auto const& p : this->TestPresetOrder) {
+ auto const& preset = this->TestPresets.at(p);
+ if (!preset.Unexpanded.Hidden && preset.Expanded &&
+ preset.Expanded->ConditionResult) {
+ presets.push_back(
+ static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
+ }
+ }
+
+ if (!presets.empty()) {
+ std::cout << "Available test presets:\n\n";
+ cmCMakePresetsFile::PrintPresets(presets);
+ }
+}
+
+void cmCMakePresetsFile::PrintAllPresets() const
+{
+ this->PrintConfigurePresetList();
+ std::cout << std::endl;
+ this->PrintBuildPresetList();
+ std::cout << std::endl;
+ this->PrintTestPresetList();
+}
diff --git a/Source/cmCMakePresetsFile.h b/Source/cmCMakePresetsFile.h
new file mode 100644
index 0000000..fc14830
--- /dev/null
+++ b/Source/cmCMakePresetsFile.h
@@ -0,0 +1,362 @@
+/* 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 <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+
+class cmCMakePresetsFile
+{
+public:
+ enum class ReadFileResult
+ {
+ READ_OK,
+ FILE_NOT_FOUND,
+ JSON_PARSE_ERROR,
+ INVALID_ROOT,
+ NO_VERSION,
+ INVALID_VERSION,
+ UNRECOGNIZED_VERSION,
+ INVALID_CMAKE_VERSION,
+ UNRECOGNIZED_CMAKE_VERSION,
+ INVALID_PRESETS,
+ INVALID_PRESET,
+ INVALID_VARIABLE,
+ DUPLICATE_PRESETS,
+ CYCLIC_PRESET_INHERITANCE,
+ USER_PRESET_INHERITANCE,
+ INVALID_MACRO_EXPANSION,
+ BUILD_TEST_PRESETS_UNSUPPORTED,
+ INVALID_CONFIGURE_PRESET,
+ INSTALL_PREFIX_UNSUPPORTED,
+ INVALID_CONDITION,
+ CONDITION_UNSUPPORTED,
+ };
+
+ enum class ArchToolsetStrategy
+ {
+ Set,
+ External,
+ };
+
+ class CacheVariable
+ {
+ public:
+ std::string Type;
+ std::string Value;
+ };
+
+ class Condition;
+
+ class Preset
+ {
+ public:
+#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
+ // The move assignment operators for several STL classes did not become
+ // noexcept until C++17, which causes some tools to warn about this move
+ // assignment operator throwing an exception when it shouldn't. Disable the
+ // move assignment operator until C++17 is enabled.
+ // Explicitly defining a copy assignment operator prevents the compiler
+ // from automatically generating a move assignment operator.
+ Preset& operator=(const Preset& /*other*/) = default;
+#endif
+
+ virtual ~Preset() = default;
+
+ std::string Name;
+ std::vector<std::string> Inherits;
+ bool Hidden;
+ bool User;
+ std::string DisplayName;
+ std::string Description;
+
+ std::shared_ptr<Condition> ConditionEvaluator;
+ bool ConditionResult = true;
+
+ std::map<std::string, cm::optional<std::string>> Environment;
+
+ virtual ReadFileResult VisitPresetInherit(const Preset& parent) = 0;
+ virtual ReadFileResult VisitPresetBeforeInherit()
+ {
+ return ReadFileResult::READ_OK;
+ }
+
+ virtual ReadFileResult VisitPresetAfterInherit(int /* version */)
+ {
+ return ReadFileResult::READ_OK;
+ }
+ };
+
+ class ConfigurePreset : public Preset
+ {
+ public:
+#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
+ // The move assignment operators for several STL classes did not become
+ // noexcept until C++17, which causes some tools to warn about this move
+ // assignment operator throwing an exception when it shouldn't. Disable the
+ // move assignment operator until C++17 is enabled.
+ // Explicitly defining a copy assignment operator prevents the compiler
+ // from automatically generating a move assignment operator.
+ ConfigurePreset& operator=(const ConfigurePreset& /*other*/) = default;
+#endif
+
+ std::string Generator;
+ std::string Architecture;
+ cm::optional<ArchToolsetStrategy> ArchitectureStrategy;
+ std::string Toolset;
+ cm::optional<ArchToolsetStrategy> ToolsetStrategy;
+ std::string BinaryDir;
+ std::string InstallDir;
+
+ std::map<std::string, cm::optional<CacheVariable>> CacheVariables;
+
+ cm::optional<bool> WarnDev;
+ cm::optional<bool> ErrorDev;
+ cm::optional<bool> WarnDeprecated;
+ cm::optional<bool> ErrorDeprecated;
+ cm::optional<bool> WarnUninitialized;
+ cm::optional<bool> WarnUnusedCli;
+ cm::optional<bool> WarnSystemVars;
+
+ cm::optional<bool> DebugOutput;
+ cm::optional<bool> DebugTryCompile;
+ cm::optional<bool> DebugFind;
+
+ ReadFileResult VisitPresetInherit(const Preset& parent) override;
+ ReadFileResult VisitPresetBeforeInherit() override;
+ ReadFileResult VisitPresetAfterInherit(int version) override;
+ };
+
+ class BuildPreset : public Preset
+ {
+ public:
+#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
+ // The move assignment operators for several STL classes did not become
+ // noexcept until C++17, which causes some tools to warn about this move
+ // assignment operator throwing an exception when it shouldn't. Disable the
+ // move assignment operator until C++17 is enabled.
+ // Explicitly defining a copy assignment operator prevents the compiler
+ // from automatically generating a move assignment operator.
+ BuildPreset& operator=(const BuildPreset& /*other*/) = default;
+#endif
+
+ std::string ConfigurePreset;
+ cm::optional<bool> InheritConfigureEnvironment;
+ cm::optional<int> Jobs;
+ std::vector<std::string> Targets;
+ std::string Configuration;
+ cm::optional<bool> CleanFirst;
+ cm::optional<bool> Verbose;
+ std::vector<std::string> NativeToolOptions;
+
+ ReadFileResult VisitPresetInherit(const Preset& parent) override;
+ ReadFileResult VisitPresetAfterInherit(int /* version */) override;
+ };
+
+ class TestPreset : public Preset
+ {
+ public:
+#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
+ // The move assignment operators for several STL classes did not become
+ // noexcept until C++17, which causes some tools to warn about this move
+ // assignment operator throwing an exception when it shouldn't. Disable the
+ // move assignment operator until C++17 is enabled.
+ // Explicitly defining a copy assignment operator prevents the compiler
+ // from automatically generating a move assignment operator.
+ TestPreset& operator=(const TestPreset& /*other*/) = default;
+#endif
+
+ struct OutputOptions
+ {
+ enum class VerbosityEnum
+ {
+ Default,
+ Verbose,
+ Extra
+ };
+
+ cm::optional<bool> ShortProgress;
+ cm::optional<VerbosityEnum> Verbosity;
+ cm::optional<bool> Debug;
+ cm::optional<bool> OutputOnFailure;
+ cm::optional<bool> Quiet;
+ std::string OutputLogFile;
+ cm::optional<bool> LabelSummary;
+ cm::optional<bool> SubprojectSummary;
+ cm::optional<int> MaxPassedTestOutputSize;
+ cm::optional<int> MaxFailedTestOutputSize;
+ cm::optional<int> MaxTestNameWidth;
+ };
+
+ struct IncludeOptions
+ {
+ struct IndexOptions
+ {
+ cm::optional<int> Start;
+ cm::optional<int> End;
+ cm::optional<int> Stride;
+ std::vector<int> SpecificTests;
+
+ std::string IndexFile;
+ };
+
+ std::string Name;
+ std::string Label;
+ cm::optional<IndexOptions> Index;
+ cm::optional<bool> UseUnion;
+ };
+
+ struct ExcludeOptions
+ {
+ struct FixturesOptions
+ {
+ std::string Any;
+ std::string Setup;
+ std::string Cleanup;
+ };
+
+ std::string Name;
+ std::string Label;
+ cm::optional<FixturesOptions> Fixtures;
+ };
+
+ struct FilterOptions
+ {
+ cm::optional<IncludeOptions> Include;
+ cm::optional<ExcludeOptions> Exclude;
+ };
+
+ struct ExecutionOptions
+ {
+ enum class ShowOnlyEnum
+ {
+ Human,
+ JsonV1
+ };
+
+ struct RepeatOptions
+ {
+ enum class ModeEnum
+ {
+ UntilFail,
+ UntilPass,
+ AfterTimeout
+ };
+
+ ModeEnum Mode;
+ int Count;
+ };
+
+ enum class NoTestsActionEnum
+ {
+ Default,
+ Error,
+ Ignore
+ };
+
+ cm::optional<bool> StopOnFailure;
+ cm::optional<bool> EnableFailover;
+ cm::optional<int> Jobs;
+ std::string ResourceSpecFile;
+ cm::optional<int> TestLoad;
+ cm::optional<ShowOnlyEnum> ShowOnly;
+
+ cm::optional<RepeatOptions> Repeat;
+ cm::optional<bool> InteractiveDebugging;
+ cm::optional<bool> ScheduleRandom;
+ cm::optional<int> Timeout;
+ cm::optional<NoTestsActionEnum> NoTestsAction;
+ };
+
+ std::string ConfigurePreset;
+ cm::optional<bool> InheritConfigureEnvironment;
+ std::string Configuration;
+ std::vector<std::string> OverwriteConfigurationFile;
+ cm::optional<OutputOptions> Output;
+ cm::optional<FilterOptions> Filter;
+ cm::optional<ExecutionOptions> Execution;
+
+ ReadFileResult VisitPresetInherit(const Preset& parent) override;
+ ReadFileResult VisitPresetAfterInherit(int /* version */) override;
+ };
+
+ template <class T>
+ class PresetPair
+ {
+ public:
+ T Unexpanded;
+ cm::optional<T> Expanded;
+ };
+
+ std::map<std::string, PresetPair<ConfigurePreset>> ConfigurePresets;
+ std::map<std::string, PresetPair<BuildPreset>> BuildPresets;
+ std::map<std::string, PresetPair<TestPreset>> TestPresets;
+
+ std::vector<std::string> ConfigurePresetOrder;
+ std::vector<std::string> BuildPresetOrder;
+ std::vector<std::string> TestPresetOrder;
+
+ std::string SourceDir;
+ int Version;
+ int UserVersion;
+
+ int GetVersion(const Preset& preset) const
+ {
+ return preset.User ? this->UserVersion : this->Version;
+ }
+
+ static std::string GetFilename(const std::string& sourceDir);
+ static std::string GetUserFilename(const std::string& sourceDir);
+ ReadFileResult ReadProjectPresets(const std::string& sourceDir,
+ bool allowNoFiles = false);
+ static const char* ResultToString(ReadFileResult result);
+
+ std::string GetGeneratorForPreset(const std::string& presetName) const
+ {
+ auto configurePresetName = presetName;
+
+ auto buildPresetIterator = this->BuildPresets.find(presetName);
+ if (buildPresetIterator != this->BuildPresets.end()) {
+ configurePresetName =
+ buildPresetIterator->second.Unexpanded.ConfigurePreset;
+ } else {
+ auto testPresetIterator = this->TestPresets.find(presetName);
+ if (testPresetIterator != this->TestPresets.end()) {
+ configurePresetName =
+ testPresetIterator->second.Unexpanded.ConfigurePreset;
+ }
+ }
+
+ auto configurePresetIterator =
+ this->ConfigurePresets.find(configurePresetName);
+ if (configurePresetIterator != this->ConfigurePresets.end()) {
+ return configurePresetIterator->second.Unexpanded.Generator;
+ }
+
+ // This should only happen if the preset is hidden
+ // or (for build or test presets) if ConfigurePreset is invalid.
+ return "";
+ }
+
+ static void PrintPresets(
+ const std::vector<const cmCMakePresetsFile::Preset*>& presets);
+ void PrintConfigurePresetList() const;
+ void PrintConfigurePresetList(
+ const std::function<bool(const ConfigurePreset&)>& filter) const;
+ void PrintBuildPresetList() const;
+ void PrintTestPresetList() const;
+ void PrintAllPresets() const;
+
+private:
+ ReadFileResult ReadProjectPresetsInternal(bool allowNoFiles);
+ ReadFileResult ReadJSONFile(const std::string& filename, bool user);
+ void ClearPresets();
+};
diff --git a/Source/cmCMakePresetsFileInternal.h b/Source/cmCMakePresetsFileInternal.h
new file mode 100644
index 0000000..3269276
--- /dev/null
+++ b/Source/cmCMakePresetsFileInternal.h
@@ -0,0 +1,112 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include <memory>
+
+#include "cmCMakePresetsFile.h"
+
+#define CHECK_OK(expr) \
+ { \
+ auto _result = expr; \
+ if (_result != ReadFileResult::READ_OK) \
+ return _result; \
+ }
+
+namespace cmCMakePresetsFileInternal {
+enum class ExpandMacroResult
+{
+ Ok,
+ Ignore,
+ Error,
+};
+
+using MacroExpander = std::function<ExpandMacroResult(
+ const std::string&, const std::string&, std::string&, int version)>;
+}
+
+class cmCMakePresetsFile::Condition
+{
+public:
+ virtual ~Condition() = default;
+
+ virtual bool Evaluate(
+ const std::vector<cmCMakePresetsFileInternal::MacroExpander>& expanders,
+ int version, cm::optional<bool>& out) const = 0;
+ virtual bool IsNull() const { return false; }
+};
+
+namespace cmCMakePresetsFileInternal {
+
+class NullCondition : public cmCMakePresetsFile::Condition
+{
+ bool Evaluate(const std::vector<MacroExpander>& /*expanders*/,
+ int /*version*/, cm::optional<bool>& out) const override
+ {
+ out = true;
+ return true;
+ }
+
+ bool IsNull() const override { return true; }
+};
+
+class ConstCondition : public cmCMakePresetsFile::Condition
+{
+public:
+ bool Evaluate(const std::vector<MacroExpander>& /*expanders*/,
+ int /*version*/, cm::optional<bool>& out) const override
+ {
+ out = this->Value;
+ return true;
+ }
+
+ bool Value;
+};
+
+class EqualsCondition : public cmCMakePresetsFile::Condition
+{
+public:
+ bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
+ cm::optional<bool>& out) const override;
+
+ std::string Lhs;
+ std::string Rhs;
+};
+
+class InListCondition : public cmCMakePresetsFile::Condition
+{
+public:
+ bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
+ cm::optional<bool>& out) const override;
+
+ std::string String;
+ std::vector<std::string> List;
+};
+
+class MatchesCondition : public cmCMakePresetsFile::Condition
+{
+public:
+ bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
+ cm::optional<bool>& out) const override;
+
+ std::string String;
+ std::string Regex;
+};
+
+class AnyAllOfCondition : public cmCMakePresetsFile::Condition
+{
+public:
+ bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
+ cm::optional<bool>& out) const override;
+
+ std::vector<std::unique_ptr<Condition>> Conditions;
+ bool StopValue;
+};
+
+class NotCondition : public cmCMakePresetsFile::Condition
+{
+public:
+ bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
+ cm::optional<bool>& out) const override;
+
+ std::unique_ptr<Condition> SubCondition;
+};
+}
diff --git a/Source/cmCMakePresetsFileReadJSON.cxx b/Source/cmCMakePresetsFileReadJSON.cxx
new file mode 100644
index 0000000..403fac6
--- /dev/null
+++ b/Source/cmCMakePresetsFileReadJSON.cxx
@@ -0,0 +1,1022 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include <functional>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cm/optional>
+#include <cmext/string_view>
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmCMakePresetsFile.h"
+#include "cmCMakePresetsFileInternal.h"
+#include "cmJSONHelpers.h"
+#include "cmVersion.h"
+
+namespace {
+using ReadFileResult = cmCMakePresetsFile::ReadFileResult;
+using CacheVariable = cmCMakePresetsFile::CacheVariable;
+using ConfigurePreset = cmCMakePresetsFile::ConfigurePreset;
+using BuildPreset = cmCMakePresetsFile::BuildPreset;
+using TestPreset = cmCMakePresetsFile::TestPreset;
+using ArchToolsetStrategy = cmCMakePresetsFile::ArchToolsetStrategy;
+
+constexpr int MIN_VERSION = 1;
+constexpr int MAX_VERSION = 3;
+
+struct CMakeVersion
+{
+ unsigned int Major = 0;
+ unsigned int Minor = 0;
+ unsigned int Patch = 0;
+};
+
+struct RootPresets
+{
+ CMakeVersion CMakeMinimumRequired;
+ std::vector<cmCMakePresetsFile::ConfigurePreset> ConfigurePresets;
+ std::vector<cmCMakePresetsFile::BuildPreset> BuildPresets;
+ std::vector<cmCMakePresetsFile::TestPreset> TestPresets;
+};
+
+std::unique_ptr<cmCMakePresetsFileInternal::NotCondition> InvertCondition(
+ std::unique_ptr<cmCMakePresetsFile::Condition> condition)
+{
+ auto retval = cm::make_unique<cmCMakePresetsFileInternal::NotCondition>();
+ retval->SubCondition = std::move(condition);
+ return retval;
+}
+
+auto const ConditionStringHelper = cmJSONStringHelper<ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION);
+
+auto const ConditionBoolHelper = cmJSONBoolHelper<ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION);
+
+auto const ConditionStringListHelper =
+ cmJSONVectorHelper<std::string, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION,
+ ConditionStringHelper);
+
+auto const ConstConditionHelper =
+ cmJSONObjectHelper<cmCMakePresetsFileInternal::ConstCondition,
+ ReadFileResult>(ReadFileResult::READ_OK,
+ ReadFileResult::INVALID_CONDITION, false)
+ .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
+ .Bind("value"_s, &cmCMakePresetsFileInternal::ConstCondition::Value,
+ ConditionBoolHelper, true);
+
+auto const EqualsConditionHelper =
+ cmJSONObjectHelper<cmCMakePresetsFileInternal::EqualsCondition,
+ ReadFileResult>(ReadFileResult::READ_OK,
+ ReadFileResult::INVALID_CONDITION, false)
+ .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
+ .Bind("lhs"_s, &cmCMakePresetsFileInternal::EqualsCondition::Lhs,
+ ConditionStringHelper, true)
+ .Bind("rhs"_s, &cmCMakePresetsFileInternal::EqualsCondition::Rhs,
+ ConditionStringHelper, true);
+
+auto const InListConditionHelper =
+ cmJSONObjectHelper<cmCMakePresetsFileInternal::InListCondition,
+ ReadFileResult>(ReadFileResult::READ_OK,
+ ReadFileResult::INVALID_CONDITION, false)
+ .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
+ .Bind("string"_s, &cmCMakePresetsFileInternal::InListCondition::String,
+ ConditionStringHelper, true)
+ .Bind("list"_s, &cmCMakePresetsFileInternal::InListCondition::List,
+ ConditionStringListHelper, true);
+
+auto const MatchesConditionHelper =
+ cmJSONObjectHelper<cmCMakePresetsFileInternal::MatchesCondition,
+ ReadFileResult>(ReadFileResult::READ_OK,
+ ReadFileResult::INVALID_CONDITION, false)
+ .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
+ .Bind("string"_s, &cmCMakePresetsFileInternal::MatchesCondition::String,
+ ConditionStringHelper, true)
+ .Bind("regex"_s, &cmCMakePresetsFileInternal::MatchesCondition::Regex,
+ ConditionStringHelper, true);
+
+ReadFileResult SubConditionHelper(
+ std::unique_ptr<cmCMakePresetsFile::Condition>& out,
+ const Json::Value* value);
+
+auto const ListConditionVectorHelper =
+ cmJSONVectorHelper<std::unique_ptr<cmCMakePresetsFile::Condition>,
+ ReadFileResult>(ReadFileResult::READ_OK,
+ ReadFileResult::INVALID_CONDITION,
+ SubConditionHelper);
+auto const AnyAllOfConditionHelper =
+ cmJSONObjectHelper<cmCMakePresetsFileInternal::AnyAllOfCondition,
+ ReadFileResult>(ReadFileResult::READ_OK,
+ ReadFileResult::INVALID_CONDITION, false)
+ .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
+ .Bind("conditions"_s,
+ &cmCMakePresetsFileInternal::AnyAllOfCondition::Conditions,
+ ListConditionVectorHelper);
+
+auto const NotConditionHelper =
+ cmJSONObjectHelper<cmCMakePresetsFileInternal::NotCondition, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false)
+ .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
+ .Bind("condition"_s,
+ &cmCMakePresetsFileInternal::NotCondition::SubCondition,
+ SubConditionHelper);
+
+ReadFileResult ConditionHelper(
+ std::unique_ptr<cmCMakePresetsFile::Condition>& out,
+ const Json::Value* value)
+{
+ if (!value) {
+ out.reset();
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->isBool()) {
+ auto c = cm::make_unique<cmCMakePresetsFileInternal::ConstCondition>();
+ c->Value = value->asBool();
+ out = std::move(c);
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->isNull()) {
+ out = cm::make_unique<cmCMakePresetsFileInternal::NullCondition>();
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->isObject()) {
+ if (!value->isMember("type")) {
+ return ReadFileResult::INVALID_CONDITION;
+ }
+
+ if (!(*value)["type"].isString()) {
+ return ReadFileResult::INVALID_CONDITION;
+ }
+ auto type = (*value)["type"].asString();
+
+ if (type == "const") {
+ auto c = cm::make_unique<cmCMakePresetsFileInternal::ConstCondition>();
+ CHECK_OK(ConstConditionHelper(*c, value));
+ out = std::move(c);
+ return ReadFileResult::READ_OK;
+ }
+
+ if (type == "equals" || type == "notEquals") {
+ auto c = cm::make_unique<cmCMakePresetsFileInternal::EqualsCondition>();
+ CHECK_OK(EqualsConditionHelper(*c, value));
+ out = std::move(c);
+ if (type == "notEquals") {
+ out = InvertCondition(std::move(out));
+ }
+ return ReadFileResult::READ_OK;
+ }
+
+ if (type == "inList" || type == "notInList") {
+ auto c = cm::make_unique<cmCMakePresetsFileInternal::InListCondition>();
+ CHECK_OK(InListConditionHelper(*c, value));
+ out = std::move(c);
+ if (type == "notInList") {
+ out = InvertCondition(std::move(out));
+ }
+ return ReadFileResult::READ_OK;
+ }
+
+ if (type == "matches" || type == "notMatches") {
+ auto c = cm::make_unique<cmCMakePresetsFileInternal::MatchesCondition>();
+ CHECK_OK(MatchesConditionHelper(*c, value));
+ out = std::move(c);
+ if (type == "notMatches") {
+ out = InvertCondition(std::move(out));
+ }
+ return ReadFileResult::READ_OK;
+ }
+
+ if (type == "anyOf" || type == "allOf") {
+ auto c =
+ cm::make_unique<cmCMakePresetsFileInternal::AnyAllOfCondition>();
+ c->StopValue = (type == "anyOf");
+ CHECK_OK(AnyAllOfConditionHelper(*c, value));
+ out = std::move(c);
+ return ReadFileResult::READ_OK;
+ }
+
+ if (type == "not") {
+ auto c = cm::make_unique<cmCMakePresetsFileInternal::NotCondition>();
+ CHECK_OK(NotConditionHelper(*c, value));
+ out = std::move(c);
+ return ReadFileResult::READ_OK;
+ }
+ }
+
+ return ReadFileResult::INVALID_CONDITION;
+}
+
+ReadFileResult PresetConditionHelper(
+ std::shared_ptr<cmCMakePresetsFile::Condition>& out,
+ const Json::Value* value)
+{
+ std::unique_ptr<cmCMakePresetsFile::Condition> ptr;
+ auto result = ConditionHelper(ptr, value);
+ out = std::move(ptr);
+ return result;
+}
+
+ReadFileResult SubConditionHelper(
+ std::unique_ptr<cmCMakePresetsFile::Condition>& out,
+ const Json::Value* value)
+{
+ std::unique_ptr<cmCMakePresetsFile::Condition> ptr;
+ auto result = ConditionHelper(ptr, value);
+ if (ptr && ptr->IsNull()) {
+ return ReadFileResult::INVALID_CONDITION;
+ }
+ out = std::move(ptr);
+ return result;
+}
+
+cmJSONHelper<std::nullptr_t, ReadFileResult> VendorHelper(ReadFileResult error)
+{
+ return [error](std::nullptr_t& /*out*/,
+ const Json::Value* value) -> ReadFileResult {
+ if (!value) {
+ return ReadFileResult::READ_OK;
+ }
+
+ if (!value->isObject()) {
+ return error;
+ }
+
+ return ReadFileResult::READ_OK;
+ };
+}
+
+auto const VersionIntHelper = cmJSONIntHelper<ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
+
+auto const VersionHelper = cmJSONRequiredHelper<int, ReadFileResult>(
+ ReadFileResult::NO_VERSION, VersionIntHelper);
+
+auto const RootVersionHelper =
+ cmJSONObjectHelper<int, ReadFileResult>(ReadFileResult::READ_OK,
+ ReadFileResult::INVALID_ROOT)
+ .Bind("version"_s, VersionHelper, false);
+
+auto const VariableStringHelper = cmJSONStringHelper<ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE);
+
+ReadFileResult VariableValueHelper(std::string& out, const Json::Value* value)
+{
+ if (!value) {
+ out.clear();
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->isBool()) {
+ out = value->asBool() ? "TRUE" : "FALSE";
+ return ReadFileResult::READ_OK;
+ }
+
+ return VariableStringHelper(out, value);
+}
+
+auto const VariableObjectHelper =
+ cmJSONObjectHelper<CacheVariable, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE, false)
+ .Bind("type"_s, &CacheVariable::Type, VariableStringHelper, false)
+ .Bind("value"_s, &CacheVariable::Value, VariableValueHelper);
+
+ReadFileResult VariableHelper(cm::optional<CacheVariable>& out,
+ const Json::Value* value)
+{
+ if (value->isBool()) {
+ out = CacheVariable{
+ /*Type=*/"BOOL",
+ /*Value=*/value->asBool() ? "TRUE" : "FALSE",
+ };
+ return ReadFileResult::READ_OK;
+ }
+ if (value->isString()) {
+ out = CacheVariable{
+ /*Type=*/"",
+ /*Value=*/value->asString(),
+ };
+ return ReadFileResult::READ_OK;
+ }
+ if (value->isObject()) {
+ out.emplace();
+ return VariableObjectHelper(*out, value);
+ }
+ if (value->isNull()) {
+ out = cm::nullopt;
+ return ReadFileResult::READ_OK;
+ }
+ return ReadFileResult::INVALID_VARIABLE;
+}
+
+auto const VariablesHelper =
+ cmJSONMapHelper<cm::optional<CacheVariable>, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, VariableHelper);
+
+auto const PresetStringHelper = cmJSONStringHelper<ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
+
+ReadFileResult EnvironmentHelper(cm::optional<std::string>& out,
+ const Json::Value* value)
+{
+ if (!value || value->isNull()) {
+ out = cm::nullopt;
+ return ReadFileResult::READ_OK;
+ }
+ if (value->isString()) {
+ out = value->asString();
+ return ReadFileResult::READ_OK;
+ }
+ return ReadFileResult::INVALID_PRESET;
+}
+
+auto const EnvironmentMapHelper =
+ cmJSONMapHelper<cm::optional<std::string>, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
+ EnvironmentHelper);
+
+auto const PresetVectorStringHelper =
+ cmJSONVectorHelper<std::string, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
+ PresetStringHelper);
+
+ReadFileResult PresetInheritsHelper(std::vector<std::string>& out,
+ const Json::Value* value)
+{
+ out.clear();
+ if (!value) {
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->isString()) {
+ out.push_back(value->asString());
+ return ReadFileResult::READ_OK;
+ }
+
+ return PresetVectorStringHelper(out, value);
+}
+
+auto const PresetBoolHelper = cmJSONBoolHelper<ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
+
+auto const PresetOptionalBoolHelper =
+ cmJSONOptionalHelper<bool, ReadFileResult>(ReadFileResult::READ_OK,
+ PresetBoolHelper);
+
+auto const PresetIntHelper = cmJSONIntHelper<ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
+
+auto const PresetOptionalIntHelper = cmJSONOptionalHelper<int, ReadFileResult>(
+ ReadFileResult::READ_OK, PresetIntHelper);
+
+auto const PresetVectorIntHelper = cmJSONVectorHelper<int, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper);
+
+auto const PresetWarningsHelper =
+ cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+ .Bind("dev"_s, &ConfigurePreset::WarnDev, PresetOptionalBoolHelper, false)
+ .Bind("deprecated"_s, &ConfigurePreset::WarnDeprecated,
+ PresetOptionalBoolHelper, false)
+ .Bind("uninitialized"_s, &ConfigurePreset::WarnUninitialized,
+ PresetOptionalBoolHelper, false)
+ .Bind("unusedCli"_s, &ConfigurePreset::WarnUnusedCli,
+ PresetOptionalBoolHelper, false)
+ .Bind("systemVars"_s, &ConfigurePreset::WarnSystemVars,
+ PresetOptionalBoolHelper, false);
+
+auto const PresetErrorsHelper =
+ cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+ .Bind("dev"_s, &ConfigurePreset::ErrorDev, PresetOptionalBoolHelper, false)
+ .Bind("deprecated"_s, &ConfigurePreset::ErrorDeprecated,
+ PresetOptionalBoolHelper, false);
+
+auto const PresetDebugHelper =
+ cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+ .Bind("output"_s, &ConfigurePreset::DebugOutput, PresetOptionalBoolHelper,
+ false)
+ .Bind("tryCompile"_s, &ConfigurePreset::DebugTryCompile,
+ PresetOptionalBoolHelper, false)
+ .Bind("find"_s, &ConfigurePreset::DebugFind, PresetOptionalBoolHelper,
+ false);
+
+ReadFileResult ArchToolsetStrategyHelper(
+ cm::optional<ArchToolsetStrategy>& out, const Json::Value* value)
+{
+ if (!value) {
+ out = cm::nullopt;
+ return ReadFileResult::READ_OK;
+ }
+
+ if (!value->isString()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+
+ if (value->asString() == "set") {
+ out = ArchToolsetStrategy::Set;
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->asString() == "external") {
+ out = ArchToolsetStrategy::External;
+ return ReadFileResult::READ_OK;
+ }
+
+ return ReadFileResult::INVALID_PRESET;
+}
+
+std::function<ReadFileResult(ConfigurePreset&, const Json::Value*)>
+ArchToolsetHelper(
+ std::string ConfigurePreset::*valueField,
+ cm::optional<ArchToolsetStrategy> ConfigurePreset::*strategyField)
+{
+ auto const objectHelper =
+ cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+ .Bind("value", valueField, PresetStringHelper, false)
+ .Bind("strategy", strategyField, ArchToolsetStrategyHelper, false);
+ return [valueField, strategyField, objectHelper](
+ ConfigurePreset& out, const Json::Value* value) -> ReadFileResult {
+ if (!value) {
+ (out.*valueField).clear();
+ out.*strategyField = cm::nullopt;
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->isString()) {
+ out.*valueField = value->asString();
+ out.*strategyField = cm::nullopt;
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->isObject()) {
+ return objectHelper(out, value);
+ }
+
+ return ReadFileResult::INVALID_PRESET;
+ };
+}
+
+auto const ArchitectureHelper = ArchToolsetHelper(
+ &ConfigurePreset::Architecture, &ConfigurePreset::ArchitectureStrategy);
+auto const ToolsetHelper = ArchToolsetHelper(
+ &ConfigurePreset::Toolset, &ConfigurePreset::ToolsetStrategy);
+
+auto const ConfigurePresetHelper =
+ cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+ .Bind("name"_s, &ConfigurePreset::Name, PresetStringHelper)
+ .Bind("inherits"_s, &ConfigurePreset::Inherits, PresetInheritsHelper,
+ false)
+ .Bind("hidden"_s, &ConfigurePreset::Hidden, PresetBoolHelper, false)
+ .Bind<std::nullptr_t>("vendor"_s, nullptr,
+ VendorHelper(ReadFileResult::INVALID_PRESET), false)
+ .Bind("displayName"_s, &ConfigurePreset::DisplayName, PresetStringHelper,
+ false)
+ .Bind("description"_s, &ConfigurePreset::Description, PresetStringHelper,
+ false)
+ .Bind("generator"_s, &ConfigurePreset::Generator, PresetStringHelper,
+ false)
+ .Bind("architecture"_s, ArchitectureHelper, false)
+ .Bind("toolset"_s, ToolsetHelper, false)
+ .Bind("binaryDir"_s, &ConfigurePreset::BinaryDir, PresetStringHelper,
+ false)
+ .Bind("installDir"_s, &ConfigurePreset::InstallDir, PresetStringHelper,
+ false)
+ .Bind<std::string>("cmakeExecutable"_s, nullptr, PresetStringHelper, false)
+ .Bind("cacheVariables"_s, &ConfigurePreset::CacheVariables,
+ VariablesHelper, false)
+ .Bind("environment"_s, &ConfigurePreset::Environment, EnvironmentMapHelper,
+ false)
+ .Bind("warnings"_s, PresetWarningsHelper, false)
+ .Bind("errors"_s, PresetErrorsHelper, false)
+ .Bind("debug"_s, PresetDebugHelper, false)
+ .Bind("condition"_s, &ConfigurePreset::ConditionEvaluator,
+ PresetConditionHelper, false);
+
+auto const BuildPresetHelper =
+ cmJSONObjectHelper<BuildPreset, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+ .Bind("name"_s, &BuildPreset::Name, PresetStringHelper)
+ .Bind("inherits"_s, &BuildPreset::Inherits, PresetInheritsHelper, false)
+ .Bind("hidden"_s, &BuildPreset::Hidden, PresetBoolHelper, false)
+ .Bind<std::nullptr_t>("vendor"_s, nullptr,
+ VendorHelper(ReadFileResult::INVALID_PRESET), false)
+ .Bind("displayName"_s, &BuildPreset::DisplayName, PresetStringHelper,
+ false)
+ .Bind("description"_s, &BuildPreset::Description, PresetStringHelper,
+ false)
+ .Bind("environment"_s, &BuildPreset::Environment, EnvironmentMapHelper,
+ false)
+ .Bind("configurePreset"_s, &BuildPreset::ConfigurePreset,
+ PresetStringHelper, false)
+ .Bind("inheritConfigureEnvironment"_s,
+ &BuildPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper,
+ false)
+ .Bind("jobs"_s, &BuildPreset::Jobs, PresetOptionalIntHelper, false)
+ .Bind("targets"_s, &BuildPreset::Targets, PresetVectorStringHelper, false)
+ .Bind("configuration"_s, &BuildPreset::Configuration, PresetStringHelper,
+ false)
+ .Bind("cleanFirst"_s, &BuildPreset::CleanFirst, PresetOptionalBoolHelper,
+ false)
+ .Bind("verbose"_s, &BuildPreset::Verbose, PresetOptionalBoolHelper, false)
+ .Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions,
+ PresetVectorStringHelper, false)
+ .Bind("condition"_s, &BuildPreset::ConditionEvaluator,
+ PresetConditionHelper, false);
+
+ReadFileResult TestPresetOutputVerbosityHelper(
+ TestPreset::OutputOptions::VerbosityEnum& out, const Json::Value* value)
+{
+ if (!value) {
+ out = TestPreset::OutputOptions::VerbosityEnum::Default;
+ return ReadFileResult::READ_OK;
+ }
+
+ if (!value->isString()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+
+ if (value->asString() == "default") {
+ out = TestPreset::OutputOptions::VerbosityEnum::Default;
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->asString() == "verbose") {
+ out = TestPreset::OutputOptions::VerbosityEnum::Verbose;
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->asString() == "extra") {
+ out = TestPreset::OutputOptions::VerbosityEnum::Extra;
+ return ReadFileResult::READ_OK;
+ }
+
+ return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalOutputVerbosityHelper =
+ cmJSONOptionalHelper<TestPreset::OutputOptions::VerbosityEnum,
+ ReadFileResult>(ReadFileResult::READ_OK,
+ TestPresetOutputVerbosityHelper);
+
+auto const TestPresetOptionalOutputHelper =
+ cmJSONOptionalHelper<TestPreset::OutputOptions, ReadFileResult>(
+ ReadFileResult::READ_OK,
+ cmJSONObjectHelper<TestPreset::OutputOptions, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+ .Bind("shortProgress"_s, &TestPreset::OutputOptions::ShortProgress,
+ PresetOptionalBoolHelper, false)
+ .Bind("verbosity"_s, &TestPreset::OutputOptions::Verbosity,
+ TestPresetOptionalOutputVerbosityHelper, false)
+ .Bind("debug"_s, &TestPreset::OutputOptions::Debug,
+ PresetOptionalBoolHelper, false)
+ .Bind("outputOnFailure"_s, &TestPreset::OutputOptions::OutputOnFailure,
+ PresetOptionalBoolHelper, false)
+ .Bind("quiet"_s, &TestPreset::OutputOptions::Quiet,
+ PresetOptionalBoolHelper, false)
+ .Bind("outputLogFile"_s, &TestPreset::OutputOptions::OutputLogFile,
+ PresetStringHelper, false)
+ .Bind("labelSummary"_s, &TestPreset::OutputOptions::LabelSummary,
+ PresetOptionalBoolHelper, false)
+ .Bind("subprojectSummary"_s,
+ &TestPreset::OutputOptions::SubprojectSummary,
+ PresetOptionalBoolHelper, false)
+ .Bind("maxPassedTestOutputSize"_s,
+ &TestPreset::OutputOptions::MaxPassedTestOutputSize,
+ PresetOptionalIntHelper, false)
+ .Bind("maxFailedTestOutputSize"_s,
+ &TestPreset::OutputOptions::MaxFailedTestOutputSize,
+ PresetOptionalIntHelper, false)
+ .Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth,
+ PresetOptionalIntHelper, false));
+
+auto const TestPresetOptionalFilterIncludeIndexObjectHelper =
+ cmJSONOptionalHelper<TestPreset::IncludeOptions::IndexOptions,
+ ReadFileResult>(
+ ReadFileResult::READ_OK,
+ cmJSONObjectHelper<TestPreset::IncludeOptions::IndexOptions,
+ ReadFileResult>(ReadFileResult::READ_OK,
+ ReadFileResult::INVALID_PRESET)
+ .Bind("start"_s, &TestPreset::IncludeOptions::IndexOptions::Start,
+ PresetOptionalIntHelper, false)
+ .Bind("end"_s, &TestPreset::IncludeOptions::IndexOptions::End,
+ PresetOptionalIntHelper, false)
+ .Bind("stride"_s, &TestPreset::IncludeOptions::IndexOptions::Stride,
+ PresetOptionalIntHelper, false)
+ .Bind("specificTests"_s,
+ &TestPreset::IncludeOptions::IndexOptions::SpecificTests,
+ PresetVectorIntHelper, false));
+
+ReadFileResult TestPresetOptionalFilterIncludeIndexHelper(
+ cm::optional<TestPreset::IncludeOptions::IndexOptions>& out,
+ const Json::Value* value)
+{
+ if (!value) {
+ out = cm::nullopt;
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->isString()) {
+ out.emplace();
+ out->IndexFile = value->asString();
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->isObject()) {
+ return TestPresetOptionalFilterIncludeIndexObjectHelper(out, value);
+ }
+
+ return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalFilterIncludeHelper =
+ cmJSONOptionalHelper<TestPreset::IncludeOptions, ReadFileResult>(
+ ReadFileResult::READ_OK,
+ cmJSONObjectHelper<TestPreset::IncludeOptions, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+ .Bind("name"_s, &TestPreset::IncludeOptions::Name, PresetStringHelper,
+ false)
+ .Bind("label"_s, &TestPreset::IncludeOptions::Label, PresetStringHelper,
+ false)
+ .Bind("index"_s, &TestPreset::IncludeOptions::Index,
+ TestPresetOptionalFilterIncludeIndexHelper, false)
+ .Bind("useUnion"_s, &TestPreset::IncludeOptions::UseUnion,
+ PresetOptionalBoolHelper, false));
+
+auto const TestPresetOptionalFilterExcludeFixturesHelper =
+ cmJSONOptionalHelper<TestPreset::ExcludeOptions::FixturesOptions,
+ ReadFileResult>(
+ ReadFileResult::READ_OK,
+ cmJSONObjectHelper<TestPreset::ExcludeOptions::FixturesOptions,
+ ReadFileResult>(ReadFileResult::READ_OK,
+ ReadFileResult::INVALID_PRESET)
+ .Bind("any"_s, &TestPreset::ExcludeOptions::FixturesOptions::Any,
+ PresetStringHelper, false)
+ .Bind("setup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Setup,
+ PresetStringHelper, false)
+ .Bind("cleanup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Cleanup,
+ PresetStringHelper, false));
+
+auto const TestPresetOptionalFilterExcludeHelper =
+ cmJSONOptionalHelper<TestPreset::ExcludeOptions, ReadFileResult>(
+ ReadFileResult::READ_OK,
+ cmJSONObjectHelper<TestPreset::ExcludeOptions, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+ .Bind("name"_s, &TestPreset::ExcludeOptions::Name, PresetStringHelper,
+ false)
+ .Bind("label"_s, &TestPreset::ExcludeOptions::Label, PresetStringHelper,
+ false)
+ .Bind("fixtures"_s, &TestPreset::ExcludeOptions::Fixtures,
+ TestPresetOptionalFilterExcludeFixturesHelper, false));
+
+ReadFileResult TestPresetExecutionShowOnlyHelper(
+ TestPreset::ExecutionOptions::ShowOnlyEnum& out, const Json::Value* value)
+{
+ if (!value || !value->isString()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+
+ if (value->asString() == "human") {
+ out = TestPreset::ExecutionOptions::ShowOnlyEnum::Human;
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->asString() == "json-v1") {
+ out = TestPreset::ExecutionOptions::ShowOnlyEnum::JsonV1;
+ return ReadFileResult::READ_OK;
+ }
+
+ return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalExecutionShowOnlyHelper =
+ cmJSONOptionalHelper<TestPreset::ExecutionOptions::ShowOnlyEnum,
+ ReadFileResult>(ReadFileResult::READ_OK,
+ TestPresetExecutionShowOnlyHelper);
+
+ReadFileResult TestPresetExecutionModeHelper(
+ TestPreset::ExecutionOptions::RepeatOptions::ModeEnum& out,
+ const Json::Value* value)
+{
+ if (!value) {
+ return ReadFileResult::READ_OK;
+ }
+
+ if (!value->isString()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+
+ if (value->asString() == "until-fail") {
+ out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilFail;
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->asString() == "until-pass") {
+ out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilPass;
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->asString() == "after-timeout") {
+ out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::AfterTimeout;
+ return ReadFileResult::READ_OK;
+ }
+
+ return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalExecutionRepeatHelper =
+ cmJSONOptionalHelper<TestPreset::ExecutionOptions::RepeatOptions,
+ ReadFileResult>(
+ ReadFileResult::READ_OK,
+ cmJSONObjectHelper<TestPreset::ExecutionOptions::RepeatOptions,
+ ReadFileResult>(ReadFileResult::READ_OK,
+ ReadFileResult::INVALID_PRESET)
+ .Bind("mode"_s, &TestPreset::ExecutionOptions::RepeatOptions::Mode,
+ TestPresetExecutionModeHelper, true)
+ .Bind("count"_s, &TestPreset::ExecutionOptions::RepeatOptions::Count,
+ PresetIntHelper, true));
+
+ReadFileResult TestPresetExecutionNoTestsActionHelper(
+ TestPreset::ExecutionOptions::NoTestsActionEnum& out,
+ const Json::Value* value)
+{
+ if (!value) {
+ out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
+ return ReadFileResult::READ_OK;
+ }
+
+ if (!value->isString()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+
+ if (value->asString() == "default") {
+ out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->asString() == "error") {
+ out = TestPreset::ExecutionOptions::NoTestsActionEnum::Error;
+ return ReadFileResult::READ_OK;
+ }
+
+ if (value->asString() == "ignore") {
+ out = TestPreset::ExecutionOptions::NoTestsActionEnum::Ignore;
+ return ReadFileResult::READ_OK;
+ }
+
+ return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalExecutionNoTestsActionHelper =
+ cmJSONOptionalHelper<TestPreset::ExecutionOptions::NoTestsActionEnum,
+ ReadFileResult>(ReadFileResult::READ_OK,
+ TestPresetExecutionNoTestsActionHelper);
+
+auto const TestPresetExecutionHelper =
+ cmJSONOptionalHelper<TestPreset::ExecutionOptions, ReadFileResult>(
+ ReadFileResult::READ_OK,
+ cmJSONObjectHelper<TestPreset::ExecutionOptions, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+ .Bind("stopOnFailure"_s, &TestPreset::ExecutionOptions::StopOnFailure,
+ PresetOptionalBoolHelper, false)
+ .Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover,
+ PresetOptionalBoolHelper, false)
+ .Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs,
+ PresetOptionalIntHelper, false)
+ .Bind("resourceSpecFile"_s,
+ &TestPreset::ExecutionOptions::ResourceSpecFile,
+ PresetStringHelper, false)
+ .Bind("testLoad"_s, &TestPreset::ExecutionOptions::TestLoad,
+ PresetOptionalIntHelper, false)
+ .Bind("showOnly"_s, &TestPreset::ExecutionOptions::ShowOnly,
+ TestPresetOptionalExecutionShowOnlyHelper, false)
+ .Bind("repeat"_s, &TestPreset::ExecutionOptions::Repeat,
+ TestPresetOptionalExecutionRepeatHelper, false)
+ .Bind("interactiveDebugging"_s,
+ &TestPreset::ExecutionOptions::InteractiveDebugging,
+ PresetOptionalBoolHelper, false)
+ .Bind("scheduleRandom"_s, &TestPreset::ExecutionOptions::ScheduleRandom,
+ PresetOptionalBoolHelper, false)
+ .Bind("timeout"_s, &TestPreset::ExecutionOptions::Timeout,
+ PresetOptionalIntHelper, false)
+ .Bind("noTestsAction"_s, &TestPreset::ExecutionOptions::NoTestsAction,
+ TestPresetOptionalExecutionNoTestsActionHelper, false));
+
+auto const TestPresetFilterHelper =
+ cmJSONOptionalHelper<TestPreset::FilterOptions, ReadFileResult>(
+ ReadFileResult::READ_OK,
+ cmJSONObjectHelper<TestPreset::FilterOptions, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+ .Bind("include"_s, &TestPreset::FilterOptions::Include,
+ TestPresetOptionalFilterIncludeHelper, false)
+ .Bind("exclude"_s, &TestPreset::FilterOptions::Exclude,
+ TestPresetOptionalFilterExcludeHelper, false));
+
+auto const TestPresetHelper =
+ cmJSONObjectHelper<TestPreset, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+ .Bind("name"_s, &TestPreset::Name, PresetStringHelper)
+ .Bind("inherits"_s, &TestPreset::Inherits, PresetInheritsHelper, false)
+ .Bind("hidden"_s, &TestPreset::Hidden, PresetBoolHelper, false)
+ .Bind<std::nullptr_t>("vendor"_s, nullptr,
+ VendorHelper(ReadFileResult::INVALID_PRESET), false)
+ .Bind("displayName"_s, &TestPreset::DisplayName, PresetStringHelper, false)
+ .Bind("description"_s, &TestPreset::Description, PresetStringHelper, false)
+ .Bind("environment"_s, &TestPreset::Environment, EnvironmentMapHelper,
+ false)
+ .Bind("configurePreset"_s, &TestPreset::ConfigurePreset,
+ PresetStringHelper, false)
+ .Bind("inheritConfigureEnvironment"_s,
+ &TestPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper,
+ false)
+ .Bind("configuration"_s, &TestPreset::Configuration, PresetStringHelper,
+ false)
+ .Bind("overwriteConfigurationFile"_s,
+ &TestPreset::OverwriteConfigurationFile, PresetVectorStringHelper,
+ false)
+ .Bind("output"_s, &TestPreset::Output, TestPresetOptionalOutputHelper,
+ false)
+ .Bind("filter"_s, &TestPreset::Filter, TestPresetFilterHelper, false)
+ .Bind("execution"_s, &TestPreset::Execution, TestPresetExecutionHelper,
+ false)
+ .Bind("condition"_s, &TestPreset::ConditionEvaluator,
+ PresetConditionHelper, false);
+
+auto const ConfigurePresetsHelper =
+ cmJSONVectorHelper<ConfigurePreset, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
+ ConfigurePresetHelper);
+
+auto const BuildPresetsHelper =
+ cmJSONVectorHelper<BuildPreset, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
+ BuildPresetHelper);
+
+auto const TestPresetsHelper = cmJSONVectorHelper<TestPreset, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, TestPresetHelper);
+
+auto const CMakeVersionUIntHelper = cmJSONUIntHelper<ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
+
+auto const CMakeVersionHelper =
+ cmJSONObjectHelper<CMakeVersion, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_CMAKE_VERSION, false)
+ .Bind("major"_s, &CMakeVersion::Major, CMakeVersionUIntHelper, false)
+ .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false)
+ .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false);
+
+auto const RootPresetsHelper =
+ cmJSONObjectHelper<RootPresets, ReadFileResult>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false)
+ .Bind<int>("version"_s, nullptr, VersionHelper)
+ .Bind("configurePresets"_s, &RootPresets::ConfigurePresets,
+ ConfigurePresetsHelper, false)
+ .Bind("buildPresets"_s, &RootPresets::BuildPresets, BuildPresetsHelper,
+ false)
+ .Bind("testPresets"_s, &RootPresets::TestPresets, TestPresetsHelper, false)
+ .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
+ CMakeVersionHelper, false)
+ .Bind<std::nullptr_t>("vendor"_s, nullptr,
+ VendorHelper(ReadFileResult::INVALID_ROOT), false);
+}
+
+cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadJSONFile(
+ const std::string& filename, bool user)
+{
+ cmsys::ifstream fin(filename.c_str());
+ if (!fin) {
+ return ReadFileResult::FILE_NOT_FOUND;
+ }
+ // If there's a BOM, toss it.
+ cmsys::FStream::ReadBOM(fin);
+
+ Json::Value root;
+ Json::CharReaderBuilder builder;
+ Json::CharReaderBuilder::strictMode(&builder.settings_);
+ if (!Json::parseFromStream(builder, fin, &root, nullptr)) {
+ return ReadFileResult::JSON_PARSE_ERROR;
+ }
+
+ int v = 0;
+ auto result = RootVersionHelper(v, &root);
+ if (result != ReadFileResult::READ_OK) {
+ return result;
+ }
+ if (v < MIN_VERSION || v > MAX_VERSION) {
+ return ReadFileResult::UNRECOGNIZED_VERSION;
+ }
+ if (user) {
+ this->UserVersion = v;
+ } else {
+ this->Version = v;
+ }
+
+ // Support for build and test presets added in version 2.
+ if (v < 2 &&
+ (root.isMember("buildPresets") || root.isMember("testPresets"))) {
+ return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED;
+ }
+
+ RootPresets presets;
+ if ((result = RootPresetsHelper(presets, &root)) !=
+ ReadFileResult::READ_OK) {
+ return result;
+ }
+
+ unsigned int currentMajor = cmVersion::GetMajorVersion();
+ unsigned int currentMinor = cmVersion::GetMinorVersion();
+ unsigned int currentPatch = cmVersion::GetPatchVersion();
+ auto const& required = presets.CMakeMinimumRequired;
+ if (required.Major > currentMajor ||
+ (required.Major == currentMajor &&
+ (required.Minor > currentMinor ||
+ (required.Minor == currentMinor &&
+ (required.Patch > currentPatch))))) {
+ return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION;
+ }
+
+ for (auto& preset : presets.ConfigurePresets) {
+ preset.User = user;
+ if (preset.Name.empty()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+
+ PresetPair<ConfigurePreset> presetPair;
+ presetPair.Unexpanded = preset;
+ presetPair.Expanded = cm::nullopt;
+ if (!this->ConfigurePresets
+ .emplace(std::make_pair(preset.Name, presetPair))
+ .second) {
+ return ReadFileResult::DUPLICATE_PRESETS;
+ }
+
+ // Support for installDir presets added in version 3.
+ if (v < 3 && !preset.InstallDir.empty()) {
+ return ReadFileResult::INSTALL_PREFIX_UNSUPPORTED;
+ }
+
+ // Support for conditions added in version 3.
+ if (v < 3 && preset.ConditionEvaluator) {
+ return ReadFileResult::CONDITION_UNSUPPORTED;
+ }
+
+ this->ConfigurePresetOrder.push_back(preset.Name);
+ }
+
+ for (auto& preset : presets.BuildPresets) {
+ preset.User = user;
+ if (preset.Name.empty()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+
+ PresetPair<BuildPreset> presetPair;
+ presetPair.Unexpanded = preset;
+ presetPair.Expanded = cm::nullopt;
+ if (!this->BuildPresets.emplace(preset.Name, presetPair).second) {
+ return ReadFileResult::DUPLICATE_PRESETS;
+ }
+
+ // Support for conditions added in version 3.
+ if (v < 3 && preset.ConditionEvaluator) {
+ return ReadFileResult::CONDITION_UNSUPPORTED;
+ }
+
+ this->BuildPresetOrder.push_back(preset.Name);
+ }
+
+ for (auto& preset : presets.TestPresets) {
+ preset.User = user;
+ if (preset.Name.empty()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+
+ PresetPair<TestPreset> presetPair;
+ presetPair.Unexpanded = preset;
+ presetPair.Expanded = cm::nullopt;
+ if (!this->TestPresets.emplace(preset.Name, presetPair).second) {
+ return ReadFileResult::DUPLICATE_PRESETS;
+ }
+
+ // Support for conditions added in version 3.
+ if (v < 3 && preset.ConditionEvaluator) {
+ return ReadFileResult::CONDITION_UNSUPPORTED;
+ }
+
+ this->TestPresetOrder.push_back(preset.Name);
+ }
+
+ return ReadFileResult::READ_OK;
+}
diff --git a/Source/cmCPackPropertiesGenerator.cxx b/Source/cmCPackPropertiesGenerator.cxx
new file mode 100644
index 0000000..cc9ad01
--- /dev/null
+++ b/Source/cmCPackPropertiesGenerator.cxx
@@ -0,0 +1,45 @@
+#include "cmCPackPropertiesGenerator.h"
+
+#include <map>
+#include <ostream>
+
+#include "cmGeneratorExpression.h"
+#include "cmInstalledFile.h"
+#include "cmOutputConverter.h"
+
+cmCPackPropertiesGenerator::cmCPackPropertiesGenerator(
+ cmLocalGenerator* lg, cmInstalledFile const& installedFile,
+ std::vector<std::string> const& configurations)
+ : cmScriptGenerator("CPACK_BUILD_CONFIG", configurations)
+ , LG(lg)
+ , InstalledFile(installedFile)
+{
+ this->ActionsPerConfig = true;
+}
+
+void cmCPackPropertiesGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent indent)
+{
+ std::string const& expandedFileName =
+ this->InstalledFile.GetNameExpression().Evaluate(this->LG, config);
+
+ cmInstalledFile::PropertyMapType const& properties =
+ this->InstalledFile.GetProperties();
+
+ for (cmInstalledFile::PropertyMapType::value_type const& i : properties) {
+ std::string const& name = i.first;
+ cmInstalledFile::Property const& property = i.second;
+
+ os << indent << "set_property(INSTALL "
+ << cmOutputConverter::EscapeForCMake(expandedFileName) << " PROPERTY "
+ << cmOutputConverter::EscapeForCMake(name);
+
+ for (cmInstalledFile::ExpressionVectorType::value_type const& j :
+ property.ValueExpressions) {
+ std::string value = j->Evaluate(this->LG, config);
+ os << " " << cmOutputConverter::EscapeForCMake(value);
+ }
+
+ os << ")\n";
+ }
+}
diff --git a/Source/cmCPackPropertiesGenerator.h b/Source/cmCPackPropertiesGenerator.h
new file mode 100644
index 0000000..63c469a
--- /dev/null
+++ b/Source/cmCPackPropertiesGenerator.h
@@ -0,0 +1,37 @@
+/* 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 <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmScriptGenerator.h"
+
+class cmInstalledFile;
+class cmLocalGenerator;
+
+/** \class cmCPackPropertiesGenerator
+ * \brief Support class for generating CPackProperties.cmake.
+ *
+ */
+class cmCPackPropertiesGenerator : public cmScriptGenerator
+{
+public:
+ cmCPackPropertiesGenerator(cmLocalGenerator* lg,
+ cmInstalledFile const& installedFile,
+ std::vector<std::string> const& configurations);
+
+ cmCPackPropertiesGenerator(cmCPackPropertiesGenerator const&) = delete;
+ cmCPackPropertiesGenerator& operator=(cmCPackPropertiesGenerator const&) =
+ delete;
+
+protected:
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent indent) override;
+
+ cmLocalGenerator* LG;
+ cmInstalledFile const& InstalledFile;
+};
diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx
new file mode 100644
index 0000000..438a077
--- /dev/null
+++ b/Source/cmCPluginAPI.cxx
@@ -0,0 +1,855 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/*
+ this file contains the implementation of the C API to CMake. Generally
+ these routines just manipulate arguments and then call the associated
+ methods on the CMake classes. */
+
+#include "cmCPluginAPI.h"
+
+#include <cstdlib>
+
+#include "cmExecutionStatus.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmVersion.h"
+
+#ifdef __QNX__
+# include <malloc.h> /* for malloc/free on QNX */
+#endif
+
+extern "C" {
+
+void CCONV* cmGetClientData(void* info)
+{
+ return ((cmLoadedCommandInfo*)info)->ClientData;
+}
+
+void CCONV cmSetClientData(void* info, void* cd)
+{
+ ((cmLoadedCommandInfo*)info)->ClientData = cd;
+}
+
+void CCONV cmSetError(void* info, const char* err)
+{
+ if (((cmLoadedCommandInfo*)info)->Error) {
+ free(((cmLoadedCommandInfo*)info)->Error);
+ }
+ ((cmLoadedCommandInfo*)info)->Error = strdup(err);
+}
+
+unsigned int CCONV cmGetCacheMajorVersion(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ cmState* state = mf->GetState();
+ return state->GetCacheMajorVersion();
+}
+unsigned int CCONV cmGetCacheMinorVersion(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ cmState* state = mf->GetState();
+ return state->GetCacheMinorVersion();
+}
+
+unsigned int CCONV cmGetMajorVersion(void*)
+{
+ return cmVersion::GetMajorVersion();
+}
+
+unsigned int CCONV cmGetMinorVersion(void*)
+{
+ return cmVersion::GetMinorVersion();
+}
+
+void CCONV cmAddDefinition(void* arg, const char* name, const char* value)
+{
+ if (value) {
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ mf->AddDefinition(name, value);
+ }
+}
+
+/* Add a definition to this makefile and the global cmake cache. */
+void CCONV cmAddCacheDefinition(void* arg, const char* name, const char* value,
+ const char* doc, int type)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+
+ switch (type) {
+ case CM_CACHE_BOOL:
+ mf->AddCacheDefinition(name, value, doc, cmStateEnums::BOOL);
+ break;
+ case CM_CACHE_PATH:
+ mf->AddCacheDefinition(name, value, doc, cmStateEnums::PATH);
+ break;
+ case CM_CACHE_FILEPATH:
+ mf->AddCacheDefinition(name, value, doc, cmStateEnums::FILEPATH);
+ break;
+ case CM_CACHE_STRING:
+ mf->AddCacheDefinition(name, value, doc, cmStateEnums::STRING);
+ break;
+ case CM_CACHE_INTERNAL:
+ mf->AddCacheDefinition(name, value, doc, cmStateEnums::INTERNAL);
+ break;
+ case CM_CACHE_STATIC:
+ mf->AddCacheDefinition(name, value, doc, cmStateEnums::STATIC);
+ break;
+ }
+}
+
+const char* CCONV cmGetProjectName(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ static std::string name;
+ name = mf->GetStateSnapshot().GetProjectName();
+ return name.c_str();
+}
+
+const char* CCONV cmGetHomeDirectory(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return mf->GetHomeDirectory().c_str();
+}
+const char* CCONV cmGetHomeOutputDirectory(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return mf->GetHomeOutputDirectory().c_str();
+}
+const char* CCONV cmGetStartDirectory(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return mf->GetCurrentSourceDirectory().c_str();
+}
+const char* CCONV cmGetStartOutputDirectory(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return mf->GetCurrentBinaryDirectory().c_str();
+}
+const char* CCONV cmGetCurrentDirectory(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return mf->GetCurrentSourceDirectory().c_str();
+}
+const char* CCONV cmGetCurrentOutputDirectory(void* arg)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return mf->GetCurrentBinaryDirectory().c_str();
+}
+const char* CCONV cmGetDefinition(void* arg, const char* def)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return cmToCStr(mf->GetDefinition(def));
+}
+
+int CCONV cmIsOn(void* arg, const char* name)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return static_cast<int>(mf->IsOn(name));
+}
+
+/** Check if a command exists. */
+int CCONV cmCommandExists(void* arg, const char* name)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ return static_cast<int>(mf->GetState()->GetCommand(name) ? 1 : 0);
+}
+
+void CCONV cmAddDefineFlag(void* arg, const char* definition)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ mf->AddDefineFlag(definition);
+}
+
+void CCONV cmAddLinkDirectoryForTarget(void* arg, const char* tgt,
+ const char* d)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ cmTarget* t = mf->FindLocalNonAliasTarget(tgt);
+ if (!t) {
+ cmSystemTools::Error(
+ "Attempt to add link directories to non-existent target: " +
+ std::string(tgt) + " for directory " + std::string(d));
+ return;
+ }
+ t->InsertLinkDirectory(d, mf->GetBacktrace());
+}
+
+void CCONV cmAddExecutable(void* arg, const char* exename, int numSrcs,
+ const char** srcs, int win32)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ std::vector<std::string> srcs2;
+ int i;
+ for (i = 0; i < numSrcs; ++i) {
+ srcs2.emplace_back(srcs[i]);
+ }
+ cmTarget* tg = mf->AddExecutable(exename, srcs2);
+ if (win32) {
+ tg->SetProperty("WIN32_EXECUTABLE", "ON");
+ }
+}
+
+void CCONV cmAddUtilityCommand(void* arg, const char* utilityName,
+ const char* command, const char* arguments,
+ int all, int numDepends, const char** depends,
+ int, const char**)
+{
+ // Get the makefile instance. Perform an extra variable expansion
+ // now because the API caller expects it.
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+
+ // Construct the command line for the command.
+ cmCustomCommandLine commandLine;
+ std::string expand = command;
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ if (arguments && arguments[0]) {
+ // TODO: Parse arguments!
+ expand = arguments;
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ }
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(commandLine);
+
+ // Accumulate the list of dependencies.
+ std::vector<std::string> depends2;
+ for (int i = 0; i < numDepends; ++i) {
+ expand = depends[i];
+ depends2.push_back(mf->ExpandVariablesInString(expand));
+ }
+
+ // Pass the call to the makefile instance.
+ std::vector<std::string> no_byproducts;
+ mf->AddUtilityCommand(utilityName, !all, nullptr, no_byproducts, depends2,
+ commandLines,
+ mf->GetPolicyStatus(cmPolicies::CMP0116));
+}
+
+void CCONV cmAddCustomCommand(void* arg, const char* source,
+ const char* command, int numArgs,
+ const char** args, int numDepends,
+ const char** depends, int numOutputs,
+ const char** outputs, const char* target)
+{
+ // Get the makefile instance. Perform an extra variable expansion
+ // now because the API caller expects it.
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+
+ // Construct the command line for the command.
+ cmCustomCommandLine commandLine;
+ std::string expand = command;
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ for (int i = 0; i < numArgs; ++i) {
+ expand = args[i];
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ }
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(commandLine);
+
+ // Accumulate the list of dependencies.
+ std::vector<std::string> depends2;
+ for (int i = 0; i < numDepends; ++i) {
+ expand = depends[i];
+ depends2.push_back(mf->ExpandVariablesInString(expand));
+ }
+
+ // Accumulate the list of outputs.
+ std::vector<std::string> outputs2;
+ for (int i = 0; i < numOutputs; ++i) {
+ expand = outputs[i];
+ outputs2.push_back(mf->ExpandVariablesInString(expand));
+ }
+
+ // Pass the call to the makefile instance.
+ const char* no_comment = nullptr;
+ mf->AddCustomCommandOldStyle(target, outputs2, depends2, source,
+ commandLines, no_comment,
+ mf->GetPolicyStatus(cmPolicies::CMP0116));
+}
+
+void CCONV cmAddCustomCommandToOutput(void* arg, const char* output,
+ const char* command, int numArgs,
+ const char** args,
+ const char* main_dependency,
+ int numDepends, const char** depends)
+{
+ // Get the makefile instance. Perform an extra variable expansion
+ // now because the API caller expects it.
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+
+ // Construct the command line for the command.
+ cmCustomCommandLine commandLine;
+ std::string expand = command;
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ for (int i = 0; i < numArgs; ++i) {
+ expand = args[i];
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ }
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(commandLine);
+
+ // Accumulate the list of dependencies.
+ std::vector<std::string> depends2;
+ for (int i = 0; i < numDepends; ++i) {
+ expand = depends[i];
+ depends2.push_back(mf->ExpandVariablesInString(expand));
+ }
+
+ // Pass the call to the makefile instance.
+ const char* no_comment = nullptr;
+ const char* no_working_dir = nullptr;
+ mf->AddCustomCommandToOutput(output, depends2, main_dependency, commandLines,
+ no_comment, no_working_dir,
+ mf->GetPolicyStatus(cmPolicies::CMP0116));
+}
+
+void CCONV cmAddCustomCommandToTarget(void* arg, const char* target,
+ const char* command, int numArgs,
+ const char** args, int commandType)
+{
+ // Get the makefile instance.
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+
+ // Construct the command line for the command. Perform an extra
+ // variable expansion now because the API caller expects it.
+ cmCustomCommandLine commandLine;
+ std::string expand = command;
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ for (int i = 0; i < numArgs; ++i) {
+ expand = args[i];
+ commandLine.push_back(mf->ExpandVariablesInString(expand));
+ }
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(commandLine);
+
+ // Select the command type.
+ cmCustomCommandType cctype = cmCustomCommandType::POST_BUILD;
+ switch (commandType) {
+ case CM_PRE_BUILD:
+ cctype = cmCustomCommandType::PRE_BUILD;
+ break;
+ case CM_PRE_LINK:
+ cctype = cmCustomCommandType::PRE_LINK;
+ break;
+ case CM_POST_BUILD:
+ cctype = cmCustomCommandType::POST_BUILD;
+ break;
+ }
+
+ // Pass the call to the makefile instance.
+ std::vector<std::string> no_byproducts;
+ std::vector<std::string> no_depends;
+ const char* no_comment = nullptr;
+ const char* no_working_dir = nullptr;
+ mf->AddCustomCommandToTarget(target, no_byproducts, no_depends, commandLines,
+ cctype, no_comment, no_working_dir,
+ mf->GetPolicyStatus(cmPolicies::CMP0116));
+}
+
+static void addLinkLibrary(cmMakefile* mf, std::string const& target,
+ std::string const& lib, cmTargetLinkLibraryType llt)
+{
+ cmTarget* t = mf->FindLocalNonAliasTarget(target);
+ if (!t) {
+ std::ostringstream e;
+ e << "Attempt to add link library \"" << lib << "\" to target \"" << target
+ << "\" which is not built in this directory.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+
+ cmTarget* tgt = mf->GetGlobalGenerator()->FindTarget(lib);
+ if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) &&
+ (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) &&
+ (tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) &&
+ !tgt->IsExecutableWithExports()) {
+ std::ostringstream e;
+ e << "Target \"" << lib << "\" of type "
+ << cmState::GetTargetTypeName(tgt->GetType())
+ << " may not be linked into another target. "
+ << "One may link only to STATIC or SHARED libraries, or "
+ << "to executables with the ENABLE_EXPORTS property set.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ }
+
+ t->AddLinkLibrary(*mf, lib, llt);
+}
+
+void CCONV cmAddLinkLibraryForTarget(void* arg, const char* tgt,
+ const char* value, int libtype)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+
+ switch (libtype) {
+ case CM_LIBRARY_GENERAL:
+ addLinkLibrary(mf, tgt, value, GENERAL_LibraryType);
+ break;
+ case CM_LIBRARY_DEBUG:
+ addLinkLibrary(mf, tgt, value, DEBUG_LibraryType);
+ break;
+ case CM_LIBRARY_OPTIMIZED:
+ addLinkLibrary(mf, tgt, value, OPTIMIZED_LibraryType);
+ break;
+ }
+}
+
+void CCONV cmAddLibrary(void* arg, const char* libname, int shared,
+ int numSrcs, const char** srcs)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ std::vector<std::string> srcs2;
+ int i;
+ for (i = 0; i < numSrcs; ++i) {
+ srcs2.emplace_back(srcs[i]);
+ }
+ mf->AddLibrary(
+ libname,
+ (shared ? cmStateEnums::SHARED_LIBRARY : cmStateEnums::STATIC_LIBRARY),
+ srcs2);
+}
+
+char CCONV* cmExpandVariablesInString(void* arg, const char* source,
+ int escapeQuotes, int atOnly)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ std::string barf = source;
+ std::string const& result =
+ mf->ExpandVariablesInString(barf, escapeQuotes != 0, atOnly != 0);
+ return strdup(result.c_str());
+}
+
+int CCONV cmExecuteCommand(void* arg, const char* name, int numArgs,
+ const char** args)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+
+ std::vector<cmListFileArgument> lffArgs;
+ lffArgs.reserve(numArgs);
+ for (int i = 0; i < numArgs; ++i) {
+ // Assume all arguments are quoted.
+ lffArgs.emplace_back(args[i], cmListFileArgument::Quoted, 0);
+ }
+
+ cmListFileFunction lff{ name, 0, std::move(lffArgs) };
+ cmExecutionStatus status(*mf);
+ return mf->ExecuteCommand(lff, status);
+}
+
+void CCONV cmExpandSourceListArguments(void* arg, int numArgs,
+ const char** args, int* resArgc,
+ char*** resArgv,
+ unsigned int startArgumentIndex)
+{
+ (void)arg;
+ (void)startArgumentIndex;
+ std::vector<std::string> result;
+ int i;
+ for (i = 0; i < numArgs; ++i) {
+ result.emplace_back(args[i]);
+ }
+ int resargc = static_cast<int>(result.size());
+ char** resargv = nullptr;
+ if (resargc) {
+ resargv = (char**)malloc(resargc * sizeof(char*));
+ }
+ for (i = 0; i < resargc; ++i) {
+ resargv[i] = strdup(result[i].c_str());
+ }
+ *resArgc = resargc;
+ *resArgv = resargv;
+}
+
+void CCONV cmFreeArguments(int argc, char** argv)
+{
+ int i;
+ for (i = 0; i < argc; ++i) {
+ free(argv[i]);
+ }
+ free(argv);
+}
+
+int CCONV cmGetTotalArgumentSize(int argc, char** argv)
+{
+ int i;
+ int result = 0;
+ for (i = 0; i < argc; ++i) {
+ if (argv[i]) {
+ result = result + static_cast<int>(strlen(argv[i]));
+ }
+ }
+ return result;
+}
+
+// Source file proxy object to support the old cmSourceFile/cmMakefile
+// API for source files.
+struct cmCPluginAPISourceFile
+{
+ cmSourceFile* RealSourceFile = nullptr;
+ std::string SourceName;
+ std::string SourceExtension;
+ std::string FullPath;
+ std::vector<std::string> Depends;
+ cmPropertyMap Properties;
+};
+
+// Keep a map from real cmSourceFile instances stored in a makefile to
+// the CPluginAPI proxy source file.
+using cmCPluginAPISourceFileMap =
+ std::map<cmSourceFile*, std::unique_ptr<cmCPluginAPISourceFile>>;
+cmCPluginAPISourceFileMap cmCPluginAPISourceFiles;
+
+void* CCONV cmCreateSourceFile(void)
+{
+ return new cmCPluginAPISourceFile;
+}
+
+void* CCONV cmCreateNewSourceFile(void*)
+{
+ return new cmCPluginAPISourceFile;
+}
+
+void CCONV cmDestroySourceFile(void* arg)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ // Only delete if it was created by cmCreateSourceFile or
+ // cmCreateNewSourceFile and is therefore not in the map.
+ if (!sf->RealSourceFile) {
+ delete sf;
+ }
+}
+
+void CCONV* cmGetSource(void* arg, const char* name)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ if (cmSourceFile* rsf = mf->GetSource(name)) {
+ // Lookup the proxy source file object for this source.
+ auto i = cmCPluginAPISourceFiles.find(rsf);
+ if (i == cmCPluginAPISourceFiles.end()) {
+ // Create a proxy source file object for this source.
+ auto sf = cm::make_unique<cmCPluginAPISourceFile>();
+ sf->RealSourceFile = rsf;
+ sf->FullPath = rsf->ResolveFullPath();
+ sf->SourceName =
+ cmSystemTools::GetFilenameWithoutLastExtension(sf->FullPath);
+ sf->SourceExtension =
+ cmSystemTools::GetFilenameLastExtension(sf->FullPath);
+
+ // Store the proxy in the map so it can be re-used and deleted later.
+ i = cmCPluginAPISourceFiles.emplace(rsf, std::move(sf)).first;
+ }
+ return i->second.get();
+ }
+ return nullptr;
+}
+
+void* CCONV cmAddSource(void* arg, void* arg2)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ cmCPluginAPISourceFile* osf = static_cast<cmCPluginAPISourceFile*>(arg2);
+ if (osf->FullPath.empty()) {
+ return nullptr;
+ }
+
+ // Create the real cmSourceFile instance and copy over saved information.
+ cmSourceFile* rsf = mf->GetOrCreateSource(osf->FullPath);
+ rsf->SetProperties(osf->Properties);
+ // In case the properties contain the GENERATED property,
+ // mark the real cmSourceFile as generated.
+ if (rsf->GetIsGenerated()) {
+ rsf->MarkAsGenerated();
+ }
+ for (std::string const& d : osf->Depends) {
+ rsf->AddDepend(d);
+ }
+
+ // Create the proxy for the real source file.
+ auto sf = cm::make_unique<cmCPluginAPISourceFile>();
+ sf->RealSourceFile = rsf;
+ sf->FullPath = osf->FullPath;
+ sf->SourceName = osf->SourceName;
+ sf->SourceExtension = osf->SourceExtension;
+
+ // Store the proxy in the map so it can be re-used and deleted later.
+ auto* value = sf.get();
+ cmCPluginAPISourceFiles[rsf] = std::move(sf);
+ return value;
+}
+
+const char* CCONV cmSourceFileGetSourceName(void* arg)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ return sf->SourceName.c_str();
+}
+
+const char* CCONV cmSourceFileGetFullPath(void* arg)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ return sf->FullPath.c_str();
+}
+
+const char* CCONV cmSourceFileGetProperty(void* arg, const char* prop)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ if (cmSourceFile* rsf = sf->RealSourceFile) {
+ return cmToCStr(rsf->GetProperty(prop));
+ }
+ if (!strcmp(prop, "LOCATION")) {
+ return sf->FullPath.c_str();
+ }
+ return cmToCStr(sf->Properties.GetPropertyValue(prop));
+}
+
+int CCONV cmSourceFileGetPropertyAsBool(void* arg, const char* prop)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ if (cmSourceFile* rsf = sf->RealSourceFile) {
+ return rsf->GetPropertyAsBool(prop) ? 1 : 0;
+ }
+ return cmIsOn(cmSourceFileGetProperty(arg, prop)) ? 1 : 0;
+}
+
+void CCONV cmSourceFileSetProperty(void* arg, const char* prop,
+ const char* value)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ if (cmSourceFile* rsf = sf->RealSourceFile) {
+ rsf->SetProperty(prop, value);
+ } else if (prop) {
+ if (!value) {
+ value = "NOTFOUND";
+ }
+ sf->Properties.SetProperty(prop, value);
+ }
+}
+
+void CCONV cmSourceFileAddDepend(void* arg, const char* depend)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ if (cmSourceFile* rsf = sf->RealSourceFile) {
+ rsf->AddDepend(depend);
+ } else {
+ sf->Depends.emplace_back(depend);
+ }
+}
+
+void CCONV cmSourceFileSetName(void* arg, const char* name, const char* dir,
+ int numSourceExtensions,
+ const char** sourceExtensions,
+ int numHeaderExtensions,
+ const char** headerExtensions)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ if (sf->RealSourceFile) {
+ // SetName is allowed only on temporary source files created by
+ // the command for building and passing to AddSource.
+ return;
+ }
+ std::vector<std::string> sourceExts;
+ std::vector<std::string> headerExts;
+ int i;
+ for (i = 0; i < numSourceExtensions; ++i) {
+ sourceExts.emplace_back(sourceExtensions[i]);
+ }
+ for (i = 0; i < numHeaderExtensions; ++i) {
+ headerExts.emplace_back(headerExtensions[i]);
+ }
+
+ // Save the original name given.
+ sf->SourceName = name;
+
+ // Convert the name to a full path in case the given name is a
+ // relative path.
+ std::string pathname = cmSystemTools::CollapseFullPath(name, dir);
+
+ // First try and see whether the listed file can be found
+ // as is without extensions added on.
+ std::string hname = pathname;
+ if (cmSystemTools::FileExists(hname)) {
+ sf->SourceName = cmSystemTools::GetFilenamePath(name);
+ if (!sf->SourceName.empty()) {
+ sf->SourceName += "/";
+ }
+ sf->SourceName += cmSystemTools::GetFilenameWithoutLastExtension(name);
+ std::string::size_type pos = hname.rfind('.');
+ if (pos != std::string::npos) {
+ sf->SourceExtension = hname.substr(pos + 1, hname.size() - pos);
+ if (cmSystemTools::FileIsFullPath(name)) {
+ std::string::size_type pos2 = hname.rfind('/');
+ if (pos2 != std::string::npos) {
+ sf->SourceName = hname.substr(pos2 + 1, pos - pos2 - 1);
+ }
+ }
+ }
+
+ sf->FullPath = hname;
+ return;
+ }
+
+ // Next, try the various source extensions
+ for (std::string const& ext : sourceExts) {
+ hname = cmStrCat(pathname, '.', ext);
+ if (cmSystemTools::FileExists(hname)) {
+ sf->SourceExtension = ext;
+ sf->FullPath = hname;
+ return;
+ }
+ }
+
+ // Finally, try the various header extensions
+ for (std::string const& ext : headerExts) {
+ hname = cmStrCat(pathname, '.', ext);
+ if (cmSystemTools::FileExists(hname)) {
+ sf->SourceExtension = ext;
+ sf->FullPath = hname;
+ return;
+ }
+ }
+
+ std::ostringstream e;
+ e << "Cannot find source file \"" << pathname << "\"";
+ e << "\n\nTried extensions";
+ for (std::string const& ext : sourceExts) {
+ e << " ." << ext;
+ }
+ for (std::string const& ext : headerExts) {
+ e << " ." << ext;
+ }
+ cmSystemTools::Error(e.str());
+}
+
+void CCONV cmSourceFileSetName2(void* arg, const char* name, const char* dir,
+ const char* ext, int headerFileOnly)
+{
+ cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
+ if (sf->RealSourceFile) {
+ // SetName is allowed only on temporary source files created by
+ // the command for building and passing to AddSource.
+ return;
+ }
+
+ // Implement the old SetName method code here.
+ if (headerFileOnly) {
+ sf->Properties.SetProperty("HEADER_FILE_ONLY", "1");
+ }
+ sf->SourceName = name;
+ std::string fname = sf->SourceName;
+ if (ext && strlen(ext)) {
+ fname += ".";
+ fname += ext;
+ }
+ sf->FullPath = cmSystemTools::CollapseFullPath(fname, dir);
+ cmSystemTools::ConvertToUnixSlashes(sf->FullPath);
+ sf->SourceExtension = ext;
+}
+
+char* CCONV cmGetFilenameWithoutExtension(const char* name)
+{
+ std::string sres = cmSystemTools::GetFilenameWithoutExtension(name);
+ return strdup(sres.c_str());
+}
+
+char* CCONV cmGetFilenamePath(const char* name)
+{
+ std::string sres = cmSystemTools::GetFilenamePath(name);
+ return strdup(sres.c_str());
+}
+
+char* CCONV cmCapitalized(const char* name)
+{
+ std::string sres = cmSystemTools::Capitalized(name);
+ return strdup(sres.c_str());
+}
+
+void CCONV cmCopyFileIfDifferent(const char* name1, const char* name2)
+{
+ cmSystemTools::CopyFileIfDifferent(name1, name2);
+}
+
+void CCONV cmRemoveFile(const char* name)
+{
+ cmSystemTools::RemoveFile(name);
+}
+
+void CCONV cmDisplayStatus(void* arg, const char* message)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ mf->DisplayStatus(message, -1);
+}
+
+void CCONV cmFree(void* data)
+{
+ free(data);
+}
+
+void CCONV DefineSourceFileProperty(void* arg, const char* name,
+ const char* briefDocs,
+ const char* longDocs, int chained)
+{
+ cmMakefile* mf = static_cast<cmMakefile*>(arg);
+ mf->GetState()->DefineProperty(name, cmProperty::SOURCE_FILE,
+ briefDocs ? briefDocs : "",
+ longDocs ? longDocs : "", chained != 0);
+}
+
+} // close the extern "C" scope
+
+cmCAPI cmStaticCAPI = {
+ cmGetClientData,
+ cmGetTotalArgumentSize,
+ cmFreeArguments,
+ cmSetClientData,
+ cmSetError,
+ cmAddCacheDefinition,
+ cmAddCustomCommand,
+ cmAddDefineFlag,
+ cmAddDefinition,
+ cmAddExecutable,
+ cmAddLibrary,
+ cmAddLinkDirectoryForTarget,
+ cmAddLinkLibraryForTarget,
+ cmAddUtilityCommand,
+ cmCommandExists,
+ cmExecuteCommand,
+ cmExpandSourceListArguments,
+ cmExpandVariablesInString,
+ cmGetCacheMajorVersion,
+ cmGetCacheMinorVersion,
+ cmGetCurrentDirectory,
+ cmGetCurrentOutputDirectory,
+ cmGetDefinition,
+ cmGetHomeDirectory,
+ cmGetHomeOutputDirectory,
+ cmGetMajorVersion,
+ cmGetMinorVersion,
+ cmGetProjectName,
+ cmGetStartDirectory,
+ cmGetStartOutputDirectory,
+ cmIsOn,
+
+ cmAddSource,
+ cmCreateSourceFile,
+ cmDestroySourceFile,
+ cmGetSource,
+ cmSourceFileAddDepend,
+ cmSourceFileGetProperty,
+ cmSourceFileGetPropertyAsBool,
+ cmSourceFileGetSourceName,
+ cmSourceFileGetFullPath,
+ cmSourceFileSetName,
+ cmSourceFileSetName2,
+ cmSourceFileSetProperty,
+
+ cmCapitalized,
+ cmCopyFileIfDifferent,
+ cmGetFilenameWithoutExtension,
+ cmGetFilenamePath,
+ cmRemoveFile,
+ cmFree,
+
+ cmAddCustomCommandToOutput,
+ cmAddCustomCommandToTarget,
+ cmDisplayStatus,
+ cmCreateNewSourceFile,
+ DefineSourceFileProperty,
+};
diff --git a/Source/cmCPluginAPI.h b/Source/cmCPluginAPI.h
new file mode 100644
index 0000000..19626f0
--- /dev/null
+++ b/Source/cmCPluginAPI.h
@@ -0,0 +1,236 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+/* This header file defines the API that loadable commands can use. In many
+ of these commands C++ instances of cmMakefile of cmSourceFile are passed
+ in as arguments or returned. In these cases they are passed as a void *
+ argument. In the function prototypes mf is used to represent a makefile
+ and sf is used to represent a source file. The functions are grouped
+ loosely into four groups 1) Utility 2) cmMakefile 3) cmSourceFile 4)
+ cmSystemTools. Within each grouping functions are listed alphabetically */
+/*=========================================================================*/
+#ifndef cmCPluginAPI_h
+#define cmCPluginAPI_h
+
+#define CMAKE_VERSION_MAJOR 2
+#define CMAKE_VERSION_MINOR 5
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __WATCOMC__
+# define CCONV __cdecl
+#else
+# define CCONV
+#endif
+/*=========================================================================
+this is the structure of function entry points that a plugin may call. This
+structure must be kept in sync with the static decaled at the bottom of
+cmCPLuginAPI.cxx
+=========================================================================*/
+/* NOLINTNEXTLINE(modernize-use-using) */
+typedef struct
+{
+ /*=========================================================================
+ Here we define the set of functions that a plugin may call. The first goup
+ of functions are utility functions that are specific to the plugin API
+ =========================================================================*/
+ /* set/Get the ClientData in the cmLoadedCommandInfo structure, this is how
+ information is passed from the InitialPass to FinalPass for commands
+ that need a FinalPass and need information from the InitialPass */
+ void*(CCONV* GetClientData)(void* info);
+ /* return the summed size in characters of all the arguments */
+ int(CCONV* GetTotalArgumentSize)(int argc, char** argv);
+ /* free all the memory associated with an argc, argv pair */
+ void(CCONV* FreeArguments)(int argc, char** argv);
+ /* set/Get the ClientData in the cmLoadedCommandInfo structure, this is how
+ information is passed from the InitialPass to FinalPass for commands
+ that need a FinalPass and need information from the InitialPass */
+ void(CCONV* SetClientData)(void* info, void* cd);
+ /* when an error occurs, call this function to set the error string */
+ void(CCONV* SetError)(void* info, const char* err);
+
+ /*=========================================================================
+ The following functions all directly map to methods in the cmMakefile
+ class. See cmMakefile.h for descriptions of what each method does. All of
+ these methods take the void * makefile pointer as their first argument.
+ =========================================================================*/
+ void(CCONV* AddCacheDefinition)(void* mf, const char* name,
+ const char* value, const char* doc,
+ int cachetype);
+ void(CCONV* AddCustomCommand)(void* mf, const char* source,
+ const char* command, int numArgs,
+ const char** args, int numDepends,
+ const char** depends, int numOutputs,
+ const char** outputs, const char* target);
+ void(CCONV* AddDefineFlag)(void* mf, const char* definition);
+ void(CCONV* AddDefinition)(void* mf, const char* name, const char* value);
+ void(CCONV* AddExecutable)(void* mf, const char* exename, int numSrcs,
+ const char** srcs, int win32);
+ void(CCONV* AddLibrary)(void* mf, const char* libname, int shared,
+ int numSrcs, const char** srcs);
+ void(CCONV* AddLinkDirectoryForTarget)(void* mf, const char* tgt,
+ const char* d);
+ void(CCONV* AddLinkLibraryForTarget)(void* mf, const char* tgt,
+ const char* libname, int libtype);
+ void(CCONV* AddUtilityCommand)(void* mf, const char* utilityName,
+ const char* command, const char* arguments,
+ int all, int numDepends, const char** depends,
+ int numOutputs, const char** outputs);
+ int(CCONV* CommandExists)(void* mf, const char* name);
+ int(CCONV* ExecuteCommand)(void* mf, const char* name, int numArgs,
+ const char** args);
+ void(CCONV* ExpandSourceListArguments)(void* mf, int argc, const char** argv,
+ int* resArgc, char*** resArgv,
+ unsigned int startArgumentIndex);
+ char*(CCONV* ExpandVariablesInString)(void* mf, const char* source,
+ int escapeQuotes, int atOnly);
+ unsigned int(CCONV* GetCacheMajorVersion)(void* mf);
+ unsigned int(CCONV* GetCacheMinorVersion)(void* mf);
+ const char*(CCONV* GetCurrentDirectory)(void* mf);
+ const char*(CCONV* GetCurrentOutputDirectory)(void* mf);
+ const char*(CCONV* GetDefinition)(void* mf, const char* def);
+ const char*(CCONV* GetHomeDirectory)(void* mf);
+ const char*(CCONV* GetHomeOutputDirectory)(void* mf);
+ unsigned int(CCONV* GetMajorVersion)(void* mf);
+ unsigned int(CCONV* GetMinorVersion)(void* mf);
+ const char*(CCONV* GetProjectName)(void* mf);
+ const char*(CCONV* GetStartDirectory)(void* mf);
+ const char*(CCONV* GetStartOutputDirectory)(void* mf);
+ int(CCONV* IsOn)(void* mf, const char* name);
+
+ /*=========================================================================
+ The following functions are designed to operate or manipulate
+ cmSourceFiles. Please see cmSourceFile.h for additional information on many
+ of these methods. Some of these methods are in cmMakefile.h.
+ =========================================================================*/
+ void*(CCONV* AddSource)(void* mf, void* sf);
+ void*(CCONV* CreateSourceFile)();
+ void(CCONV* DestroySourceFile)(void* sf);
+ void*(CCONV* GetSource)(void* mf, const char* sourceName);
+ void(CCONV* SourceFileAddDepend)(void* sf, const char* depend);
+ const char*(CCONV* SourceFileGetProperty)(void* sf, const char* prop);
+ int(CCONV* SourceFileGetPropertyAsBool)(void* sf, const char* prop);
+ const char*(CCONV* SourceFileGetSourceName)(void* sf);
+ const char*(CCONV* SourceFileGetFullPath)(void* sf);
+ void(CCONV* SourceFileSetName)(void* sf, const char* name, const char* dir,
+ int numSourceExtensions,
+ const char** sourceExtensions,
+ int numHeaderExtensions,
+ const char** headerExtensions);
+ void(CCONV* SourceFileSetName2)(void* sf, const char* name, const char* dir,
+ const char* ext, int headerFileOnly);
+ void(CCONV* SourceFileSetProperty)(void* sf, const char* prop,
+ const char* value);
+
+ /*=========================================================================
+ The following methods are from cmSystemTools.h see that file for specific
+ documentation on each method.
+ =========================================================================*/
+ char*(CCONV* Capitalized)(const char*);
+ void(CCONV* CopyFileIfDifferent)(const char* f1, const char* f2);
+ char*(CCONV* GetFilenameWithoutExtension)(const char*);
+ char*(CCONV* GetFilenamePath)(const char*);
+ void(CCONV* RemoveFile)(const char* f1);
+ void(CCONV* Free)(void*);
+
+ /*=========================================================================
+ The following are new functions added after 1.6
+ =========================================================================*/
+ void(CCONV* AddCustomCommandToOutput)(void* mf, const char* output,
+ const char* command, int numArgs,
+ const char** args,
+ const char* main_dependency,
+ int numDepends, const char** depends);
+ void(CCONV* AddCustomCommandToTarget)(void* mf, const char* target,
+ const char* command, int numArgs,
+ const char** args, int commandType);
+
+ /* display status information */
+ void(CCONV* DisplaySatus)(void* info, const char* message);
+
+ /* new functions added after 2.4 */
+ void*(CCONV* CreateNewSourceFile)(void* mf);
+ void(CCONV* DefineSourceFileProperty)(void* mf, const char* name,
+ const char* briefDocs,
+ const char* longDocs, int chained);
+
+ /* this is the end of the C function stub API structure */
+} cmCAPI;
+
+/*=========================================================================
+CM_PLUGIN_EXPORT should be used by plugins
+=========================================================================*/
+#ifdef _WIN32
+# define CM_PLUGIN_EXPORT __declspec(dllexport)
+#else
+# define CM_PLUGIN_EXPORT
+#endif
+
+/*=========================================================================
+define the different types of cache entries, see cmCacheManager.h for more
+information
+=========================================================================*/
+#define CM_CACHE_BOOL 0
+#define CM_CACHE_PATH 1
+#define CM_CACHE_FILEPATH 2
+#define CM_CACHE_STRING 3
+#define CM_CACHE_INTERNAL 4
+#define CM_CACHE_STATIC 5
+
+/*=========================================================================
+define the different types of compiles a library may be
+=========================================================================*/
+#define CM_LIBRARY_GENERAL 0
+#define CM_LIBRARY_DEBUG 1
+#define CM_LIBRARY_OPTIMIZED 2
+
+/*=========================================================================
+define the different types of custom commands for a target
+=========================================================================*/
+#define CM_PRE_BUILD 0
+#define CM_PRE_LINK 1
+#define CM_POST_BUILD 2
+
+/*=========================================================================
+Finally we define the key data structures and function prototypes
+=========================================================================*/
+
+/* NOLINTNEXTLINE(modernize-use-using) */
+typedef const char*(CCONV* CM_DOC_FUNCTION)();
+
+/* NOLINTNEXTLINE(modernize-use-using) */
+typedef int(CCONV* CM_INITIAL_PASS_FUNCTION)(void* info, void* mf, int argc,
+ char* []);
+
+/* NOLINTNEXTLINE(modernize-use-using) */
+typedef void(CCONV* CM_FINAL_PASS_FUNCTION)(void* info, void* mf);
+
+/* NOLINTNEXTLINE(modernize-use-using) */
+typedef void(CCONV* CM_DESTRUCTOR_FUNCTION)(void* info);
+
+/* NOLINTNEXTLINE(modernize-use-using) */
+typedef struct
+{
+ unsigned long reserved1; /* Reserved for future use. DO NOT USE. */
+ unsigned long reserved2; /* Reserved for future use. DO NOT USE. */
+ cmCAPI* CAPI;
+ int m_Inherited; /* this ivar is no longer used in CMake 2.2 or later */
+ CM_INITIAL_PASS_FUNCTION InitialPass;
+ CM_FINAL_PASS_FUNCTION FinalPass;
+ CM_DESTRUCTOR_FUNCTION Destructor;
+ CM_DOC_FUNCTION GetTerseDocumentation;
+ CM_DOC_FUNCTION GetFullDocumentation;
+ const char* Name;
+ char* Error;
+ void* ClientData;
+} cmLoadedCommandInfo;
+
+/* NOLINTNEXTLINE(modernize-use-using) */
+typedef void(CCONV* CM_INIT_FUNCTION)(cmLoadedCommandInfo*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
new file mode 100644
index 0000000..0dfd1bd
--- /dev/null
+++ b/Source/cmCTest.cxx
@@ -0,0 +1,3700 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTest.h"
+
+#include <algorithm>
+#include <cctype>
+#include <cerrno>
+#include <chrono>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include <cm3p/curl/curl.h>
+#include <cm3p/zlib.h>
+
+#include "cmsys/Base64.h"
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+#include "cmsys/Process.h"
+#include "cmsys/RegularExpression.hxx"
+#include "cmsys/SystemInformation.hxx"
+#if defined(_WIN32)
+# include <windows.h> // IWYU pragma: keep
+#else
+# include <unistd.h> // IWYU pragma: keep
+#endif
+
+#include "cmCMakePresetsFile.h"
+#include "cmCTestBuildAndTestHandler.h"
+#include "cmCTestBuildHandler.h"
+#include "cmCTestConfigureHandler.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmCTestGenericHandler.h"
+#include "cmCTestMemCheckHandler.h"
+#include "cmCTestScriptHandler.h"
+#include "cmCTestStartCommand.h"
+#include "cmCTestSubmitHandler.h"
+#include "cmCTestTestHandler.h"
+#include "cmCTestUpdateHandler.h"
+#include "cmCTestUploadHandler.h"
+#include "cmDynamicLoader.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProcessOutput.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+#include "cmVersionConfig.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+#if defined(__BEOS__) || defined(__HAIKU__)
+# include <be/kernel/OS.h> /* disable_debugger() API. */
+#endif
+
+struct cmCTest::Private
+{
+ /** Representation of one part. */
+ struct PartInfo
+ {
+ void SetName(const std::string& name) { this->Name = name; }
+ const std::string& GetName() const { return this->Name; }
+
+ void Enable() { this->Enabled = true; }
+ explicit operator bool() const { return this->Enabled; }
+
+ std::vector<std::string> SubmitFiles;
+
+ private:
+ bool Enabled = false;
+ std::string Name;
+ };
+
+ int RepeatCount = 1; // default to run each test once
+ cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never;
+ std::string ConfigType;
+ std::string ScheduleType;
+ std::chrono::system_clock::time_point StopTime;
+ bool StopOnFailure = false;
+ bool TestProgressOutput = false;
+ bool Verbose = false;
+ bool ExtraVerbose = false;
+ bool ProduceXML = false;
+ bool LabelSummary = true;
+ bool SubprojectSummary = true;
+ bool UseHTTP10 = false;
+ bool PrintLabels = false;
+ bool Failover = false;
+
+ bool FlushTestProgressLine = false;
+
+ bool ForceNewCTestProcess = false;
+
+ bool RunConfigurationScript = false;
+
+ // these are helper classes
+ cmCTestBuildHandler BuildHandler;
+ cmCTestBuildAndTestHandler BuildAndTestHandler;
+ cmCTestCoverageHandler CoverageHandler;
+ cmCTestScriptHandler ScriptHandler;
+ cmCTestTestHandler TestHandler;
+ cmCTestUpdateHandler UpdateHandler;
+ cmCTestConfigureHandler ConfigureHandler;
+ cmCTestMemCheckHandler MemCheckHandler;
+ cmCTestSubmitHandler SubmitHandler;
+ cmCTestUploadHandler UploadHandler;
+
+ std::vector<cmCTestGenericHandler*> GetTestingHandlers()
+ {
+ return { &this->BuildHandler, &this->BuildAndTestHandler,
+ &this->CoverageHandler, &this->ScriptHandler,
+ &this->TestHandler, &this->UpdateHandler,
+ &this->ConfigureHandler, &this->MemCheckHandler,
+ &this->SubmitHandler, &this->UploadHandler };
+ }
+
+ std::map<std::string, cmCTestGenericHandler*> GetNamedTestingHandlers()
+ {
+ return { { "build", &this->BuildHandler },
+ { "buildtest", &this->BuildAndTestHandler },
+ { "coverage", &this->CoverageHandler },
+ { "script", &this->ScriptHandler },
+ { "test", &this->TestHandler },
+ { "update", &this->UpdateHandler },
+ { "configure", &this->ConfigureHandler },
+ { "memcheck", &this->MemCheckHandler },
+ { "submit", &this->SubmitHandler },
+ { "upload", &this->UploadHandler } };
+ }
+
+ bool ShowOnly = false;
+ bool OutputAsJson = false;
+ int OutputAsJsonVersion = 1;
+
+ // TODO: The ctest configuration should be a hierarchy of
+ // configuration option sources: command-line, script, ini file.
+ // Then the ini file can get re-loaded whenever it changes without
+ // affecting any higher-precedence settings.
+ std::map<std::string, std::string> CTestConfiguration;
+ std::map<std::string, std::string> CTestConfigurationOverwrites;
+
+ PartInfo Parts[PartCount];
+ std::map<std::string, Part> PartMap;
+
+ std::string CurrentTag;
+ bool TomorrowTag = false;
+
+ int TestModel = cmCTest::EXPERIMENTAL;
+ std::string SpecificGroup;
+
+ cmDuration TimeOut = cmDuration::zero();
+
+ cmDuration GlobalTimeout = cmDuration::zero();
+
+ int MaxTestNameWidth = 30;
+
+ int ParallelLevel = 1;
+ bool ParallelLevelSetInCli = false;
+
+ unsigned long TestLoad = 0;
+
+ int CompatibilityMode;
+
+ // information for the --build-and-test options
+ std::string BinaryDir;
+ std::string TestDir;
+
+ std::string NotesFiles;
+
+ bool InteractiveDebugMode = true;
+
+ bool ShortDateFormat = true;
+
+ bool CompressXMLFiles = false;
+ bool CompressTestOutput = true;
+
+ // By default we write output to the process output streams.
+ std::ostream* StreamOut = &std::cout;
+ std::ostream* StreamErr = &std::cerr;
+
+ bool SuppressUpdatingCTestConfiguration = false;
+
+ bool Debug = false;
+ bool ShowLineNumbers = false;
+ bool Quiet = false;
+
+ std::string BuildID;
+
+ std::vector<std::string> InitialCommandLineArguments;
+
+ int SubmitIndex = 0;
+
+ std::unique_ptr<cmGeneratedFileStream> OutputLogFile;
+ int OutputLogFileLastTag = -1;
+
+ bool OutputTestOutputOnTestFailure = false;
+ bool OutputColorCode = cmCTest::ColoredOutputSupportedByConsole();
+
+ std::map<std::string, std::string> Definitions;
+
+ cmCTest::NoTests NoTestsMode = cmCTest::NoTests::Legacy;
+};
+
+struct tm* cmCTest::GetNightlyTime(std::string const& str, bool tomorrowtag)
+{
+ struct tm* lctime;
+ time_t tctime = time(nullptr);
+ lctime = gmtime(&tctime);
+ char buf[1024];
+ // add todays year day and month to the time in str because
+ // curl_getdate no longer assumes the day is today
+ sprintf(buf, "%d%02d%02d %s", lctime->tm_year + 1900, lctime->tm_mon + 1,
+ lctime->tm_mday, str.c_str());
+ cmCTestLog(this, OUTPUT,
+ "Determine Nightly Start Time" << std::endl
+ << " Specified time: " << str
+ << std::endl);
+ // Convert the nightly start time to seconds. Since we are
+ // providing only a time and a timezone, the current date of
+ // the local machine is assumed. Consequently, nightlySeconds
+ // is the time at which the nightly dashboard was opened or
+ // will be opened on the date of the current client machine.
+ // As such, this time may be in the past or in the future.
+ time_t ntime = curl_getdate(buf, &tctime);
+ cmCTestLog(this, DEBUG, " Get curl time: " << ntime << std::endl);
+ tctime = time(nullptr);
+ cmCTestLog(this, DEBUG, " Get the current time: " << tctime << std::endl);
+
+ const int dayLength = 24 * 60 * 60;
+ cmCTestLog(this, DEBUG, "Seconds: " << tctime << std::endl);
+ while (ntime > tctime) {
+ // If nightlySeconds is in the past, this is the current
+ // open dashboard, then return nightlySeconds. If
+ // nightlySeconds is in the future, this is the next
+ // dashboard to be opened, so subtract 24 hours to get the
+ // time of the current open dashboard
+ ntime -= dayLength;
+ cmCTestLog(this, DEBUG, "Pick yesterday" << std::endl);
+ cmCTestLog(this, DEBUG,
+ " Future time, subtract day: " << ntime << std::endl);
+ }
+ while (tctime > (ntime + dayLength)) {
+ ntime += dayLength;
+ cmCTestLog(this, DEBUG, " Past time, add day: " << ntime << std::endl);
+ }
+ cmCTestLog(this, DEBUG, "nightlySeconds: " << ntime << std::endl);
+ cmCTestLog(this, DEBUG,
+ " Current time: " << tctime << " Nightly time: " << ntime
+ << std::endl);
+ if (tomorrowtag) {
+ cmCTestLog(this, OUTPUT, " Use future tag, Add a day" << std::endl);
+ ntime += dayLength;
+ }
+ lctime = gmtime(&ntime);
+ return lctime;
+}
+
+bool cmCTest::GetTomorrowTag() const
+{
+ return this->Impl->TomorrowTag;
+}
+
+std::string cmCTest::CleanString(const std::string& str,
+ std::string::size_type spos)
+{
+ spos = str.find_first_not_of(" \n\t\r\f\v", spos);
+ std::string::size_type epos = str.find_last_not_of(" \n\t\r\f\v");
+ if (spos == std::string::npos) {
+ return std::string();
+ }
+ if (epos != std::string::npos) {
+ epos = epos - spos + 1;
+ }
+ return str.substr(spos, epos);
+}
+
+std::string cmCTest::CurrentTime()
+{
+ time_t currenttime = time(nullptr);
+ struct tm* t = localtime(&currenttime);
+ // return ::CleanString(ctime(&currenttime));
+ char current_time[1024];
+ if (this->Impl->ShortDateFormat) {
+ strftime(current_time, 1000, "%b %d %H:%M %Z", t);
+ } else {
+ strftime(current_time, 1000, "%a %b %d %H:%M:%S %Z %Y", t);
+ }
+ cmCTestLog(this, DEBUG, " Current_Time: " << current_time << std::endl);
+ return cmCTest::CleanString(current_time);
+}
+
+std::string cmCTest::GetCostDataFile()
+{
+ std::string fname = this->GetCTestConfiguration("CostDataFile");
+ if (fname.empty()) {
+ fname = this->GetBinaryDir() + "/Testing/Temporary/CTestCostData.txt";
+ }
+ return fname;
+}
+
+std::string cmCTest::DecodeURL(const std::string& in)
+{
+ std::string out;
+ for (const char* c = in.c_str(); *c; ++c) {
+ if (*c == '%' && isxdigit(*(c + 1)) && isxdigit(*(c + 2))) {
+ char buf[3] = { *(c + 1), *(c + 2), 0 };
+ out.append(1, char(strtoul(buf, nullptr, 16)));
+ c += 2;
+ } else {
+ out.append(1, *c);
+ }
+ }
+ return out;
+}
+
+cmCTest::cmCTest()
+ : Impl(new Private)
+{
+ std::string envValue;
+ if (cmSystemTools::GetEnv("CTEST_OUTPUT_ON_FAILURE", envValue)) {
+ this->Impl->OutputTestOutputOnTestFailure = !cmIsOff(envValue);
+ }
+ envValue.clear();
+ if (cmSystemTools::GetEnv("CTEST_PROGRESS_OUTPUT", envValue)) {
+ this->Impl->TestProgressOutput = !cmIsOff(envValue);
+ }
+
+ this->Impl->Parts[PartStart].SetName("Start");
+ this->Impl->Parts[PartUpdate].SetName("Update");
+ this->Impl->Parts[PartConfigure].SetName("Configure");
+ this->Impl->Parts[PartBuild].SetName("Build");
+ this->Impl->Parts[PartTest].SetName("Test");
+ this->Impl->Parts[PartCoverage].SetName("Coverage");
+ this->Impl->Parts[PartMemCheck].SetName("MemCheck");
+ this->Impl->Parts[PartSubmit].SetName("Submit");
+ this->Impl->Parts[PartNotes].SetName("Notes");
+ this->Impl->Parts[PartExtraFiles].SetName("ExtraFiles");
+ this->Impl->Parts[PartUpload].SetName("Upload");
+ this->Impl->Parts[PartDone].SetName("Done");
+
+ // Fill the part name-to-id map.
+ for (Part p = PartStart; p != PartCount; p = Part(p + 1)) {
+ this->Impl
+ ->PartMap[cmSystemTools::LowerCase(this->Impl->Parts[p].GetName())] = p;
+ }
+
+ for (auto& handler : this->Impl->GetTestingHandlers()) {
+ handler->SetCTestInstance(this);
+ }
+
+ // Make sure we can capture the build tool output.
+ cmSystemTools::EnableVSConsoleOutput();
+}
+
+cmCTest::~cmCTest() = default;
+
+int cmCTest::GetParallelLevel() const
+{
+ return this->Impl->ParallelLevel;
+}
+
+void cmCTest::SetParallelLevel(int level)
+{
+ this->Impl->ParallelLevel = level < 1 ? 1 : level;
+}
+
+unsigned long cmCTest::GetTestLoad() const
+{
+ return this->Impl->TestLoad;
+}
+
+void cmCTest::SetTestLoad(unsigned long load)
+{
+ this->Impl->TestLoad = load;
+}
+
+bool cmCTest::ShouldCompressTestOutput()
+{
+ return this->Impl->CompressTestOutput;
+}
+
+cmCTest::Part cmCTest::GetPartFromName(const std::string& name)
+{
+ // Look up by lower-case to make names case-insensitive.
+ std::string lower_name = cmSystemTools::LowerCase(name);
+ auto const i = this->Impl->PartMap.find(lower_name);
+ if (i != this->Impl->PartMap.end()) {
+ return i->second;
+ }
+
+ // The string does not name a valid part.
+ return PartCount;
+}
+
+int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
+{
+ bool quiet = false;
+ if (command && command->ShouldBeQuiet()) {
+ quiet = true;
+ }
+
+ cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
+ if (!this->Impl->InteractiveDebugMode) {
+ this->BlockTestErrorDiagnostics();
+ } else {
+ cmSystemTools::PutEnv("CTEST_INTERACTIVE_DEBUG_MODE=1");
+ }
+
+ this->Impl->BinaryDir = binary_dir;
+ cmSystemTools::ConvertToUnixSlashes(this->Impl->BinaryDir);
+
+ this->UpdateCTestConfiguration();
+
+ cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
+ if (this->Impl->ProduceXML) {
+ cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
+ cmCTestOptionalLog(this, OUTPUT,
+ " Site: "
+ << this->GetCTestConfiguration("Site") << std::endl
+ << " Build name: "
+ << cmCTest::SafeBuildIdField(
+ this->GetCTestConfiguration("BuildName"))
+ << std::endl,
+ quiet);
+ cmCTestOptionalLog(this, DEBUG, "Produce XML is on" << std::endl, quiet);
+ if (this->Impl->TestModel == cmCTest::NIGHTLY &&
+ this->GetCTestConfiguration("NightlyStartTime").empty()) {
+ cmCTestOptionalLog(
+ this, WARNING,
+ "WARNING: No nightly start time found please set in CTestConfig.cmake"
+ " or DartConfig.cmake"
+ << std::endl,
+ quiet);
+ cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl,
+ quiet);
+ return 0;
+ }
+ }
+
+ cmake cm(cmake::RoleScript, cmState::CTest);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator gg(&cm);
+ cmMakefile mf(&gg, cm.GetCurrentSnapshot());
+ if (!this->ReadCustomConfigurationFileTree(this->Impl->BinaryDir, &mf)) {
+ cmCTestOptionalLog(
+ this, DEBUG, "Cannot find custom configuration file tree" << std::endl,
+ quiet);
+ return 0;
+ }
+
+ if (this->Impl->ProduceXML) {
+ // Verify "Testing" directory exists:
+ //
+ std::string testingDir = this->Impl->BinaryDir + "/Testing";
+ if (cmSystemTools::FileExists(testingDir)) {
+ if (!cmSystemTools::FileIsDirectory(testingDir)) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "File " << testingDir
+ << " is in the place of the testing directory"
+ << std::endl);
+ return 0;
+ }
+ } else {
+ if (!cmSystemTools::MakeDirectory(testingDir)) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Cannot create directory " << testingDir << std::endl);
+ return 0;
+ }
+ }
+
+ // Create new "TAG" file or read existing one:
+ //
+ bool createNewTag = true;
+ if (command) {
+ createNewTag = command->ShouldCreateNewTag();
+ }
+
+ std::string tagfile = testingDir + "/TAG";
+ cmsys::ifstream tfin(tagfile.c_str());
+ std::string tag;
+
+ if (createNewTag) {
+ time_t tctime = time(nullptr);
+ if (this->Impl->TomorrowTag) {
+ tctime += (24 * 60 * 60);
+ }
+ struct tm* lctime = gmtime(&tctime);
+ if (tfin && cmSystemTools::GetLineFromStream(tfin, tag)) {
+ int year = 0;
+ int mon = 0;
+ int day = 0;
+ int hour = 0;
+ int min = 0;
+ sscanf(tag.c_str(), "%04d%02d%02d-%02d%02d", &year, &mon, &day, &hour,
+ &min);
+ if (year != lctime->tm_year + 1900 || mon != lctime->tm_mon + 1 ||
+ day != lctime->tm_mday) {
+ tag.clear();
+ }
+ std::string group;
+ if (cmSystemTools::GetLineFromStream(tfin, group) &&
+ !this->Impl->Parts[PartStart] && !command) {
+ this->Impl->SpecificGroup = group;
+ }
+ std::string model;
+ if (cmSystemTools::GetLineFromStream(tfin, model) &&
+ !this->Impl->Parts[PartStart] && !command) {
+ this->Impl->TestModel = GetTestModelFromString(model);
+ }
+ tfin.close();
+ }
+ if (tag.empty() || (nullptr != command) ||
+ this->Impl->Parts[PartStart]) {
+ cmCTestOptionalLog(
+ this, DEBUG,
+ "TestModel: " << this->GetTestModelString() << std::endl, quiet);
+ cmCTestOptionalLog(this, DEBUG,
+ "TestModel: " << this->Impl->TestModel << std::endl,
+ quiet);
+ if (this->Impl->TestModel == cmCTest::NIGHTLY) {
+ lctime = this->GetNightlyTime(
+ this->GetCTestConfiguration("NightlyStartTime"),
+ this->Impl->TomorrowTag);
+ }
+ char datestring[100];
+ sprintf(datestring, "%04d%02d%02d-%02d%02d", lctime->tm_year + 1900,
+ lctime->tm_mon + 1, lctime->tm_mday, lctime->tm_hour,
+ lctime->tm_min);
+ tag = datestring;
+ cmsys::ofstream ofs(tagfile.c_str());
+ if (ofs) {
+ ofs << tag << std::endl;
+ ofs << this->GetTestModelString() << std::endl;
+ switch (this->Impl->TestModel) {
+ case cmCTest::EXPERIMENTAL:
+ ofs << "Experimental" << std::endl;
+ break;
+ case cmCTest::NIGHTLY:
+ ofs << "Nightly" << std::endl;
+ break;
+ case cmCTest::CONTINUOUS:
+ ofs << "Continuous" << std::endl;
+ break;
+ }
+ }
+ ofs.close();
+ if (nullptr == command) {
+ cmCTestOptionalLog(this, OUTPUT,
+ "Create new tag: " << tag << " - "
+ << this->GetTestModelString()
+ << std::endl,
+ quiet);
+ }
+ }
+ } else {
+ std::string group;
+ std::string modelStr;
+ int model = cmCTest::UNKNOWN;
+
+ if (tfin) {
+ cmSystemTools::GetLineFromStream(tfin, tag);
+ cmSystemTools::GetLineFromStream(tfin, group);
+ if (cmSystemTools::GetLineFromStream(tfin, modelStr)) {
+ model = GetTestModelFromString(modelStr);
+ }
+ tfin.close();
+ }
+
+ if (tag.empty()) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Cannot read existing TAG file in " << testingDir
+ << std::endl);
+ return 0;
+ }
+
+ if (this->Impl->TestModel == cmCTest::UNKNOWN) {
+ if (model == cmCTest::UNKNOWN) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "TAG file does not contain model and "
+ "no model specified in start command"
+ << std::endl);
+ return 0;
+ }
+
+ this->SetTestModel(model);
+ }
+
+ if (model != this->Impl->TestModel && model != cmCTest::UNKNOWN &&
+ this->Impl->TestModel != cmCTest::UNKNOWN) {
+ cmCTestOptionalLog(this, WARNING,
+ "Model given in TAG does not match "
+ "model given in ctest_start()"
+ << std::endl,
+ quiet);
+ }
+
+ if (!this->Impl->SpecificGroup.empty() &&
+ group != this->Impl->SpecificGroup) {
+ cmCTestOptionalLog(this, WARNING,
+ "Group given in TAG does not match "
+ "group given in ctest_start()"
+ << std::endl,
+ quiet);
+ } else {
+ this->Impl->SpecificGroup = group;
+ }
+
+ cmCTestOptionalLog(this, OUTPUT,
+ " Use existing tag: " << tag << " - "
+ << this->GetTestModelString()
+ << std::endl,
+ quiet);
+ }
+
+ this->Impl->CurrentTag = tag;
+ }
+
+ return 1;
+}
+
+bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command)
+{
+ std::string src_dir = this->GetCTestConfiguration("SourceDirectory");
+ std::string bld_dir = this->GetCTestConfiguration("BuildDirectory");
+ this->Impl->BuildID = "";
+ for (Part p = PartStart; p != PartCount; p = Part(p + 1)) {
+ this->Impl->Parts[p].SubmitFiles.clear();
+ }
+
+ cmMakefile* mf = command->GetMakefile();
+ std::string fname;
+
+ std::string src_dir_fname = cmStrCat(src_dir, "/CTestConfig.cmake");
+ cmSystemTools::ConvertToUnixSlashes(src_dir_fname);
+
+ std::string bld_dir_fname = cmStrCat(bld_dir, "/CTestConfig.cmake");
+ cmSystemTools::ConvertToUnixSlashes(bld_dir_fname);
+
+ if (cmSystemTools::FileExists(bld_dir_fname)) {
+ fname = bld_dir_fname;
+ } else if (cmSystemTools::FileExists(src_dir_fname)) {
+ fname = src_dir_fname;
+ }
+
+ if (!fname.empty()) {
+ cmCTestOptionalLog(this, OUTPUT,
+ " Reading ctest configuration file: " << fname
+ << std::endl,
+ command->ShouldBeQuiet());
+ bool readit = mf->ReadDependentFile(fname);
+ if (!readit) {
+ std::string m = cmStrCat("Could not find include file: ", fname);
+ command->SetError(m);
+ return false;
+ }
+ }
+
+ this->SetCTestConfigurationFromCMakeVariable(mf, "NightlyStartTime",
+ "CTEST_NIGHTLY_START_TIME",
+ command->ShouldBeQuiet());
+ this->SetCTestConfigurationFromCMakeVariable(mf, "Site", "CTEST_SITE",
+ command->ShouldBeQuiet());
+ this->SetCTestConfigurationFromCMakeVariable(
+ mf, "BuildName", "CTEST_BUILD_NAME", command->ShouldBeQuiet());
+
+ if (!this->Initialize(bld_dir.c_str(), command)) {
+ return false;
+ }
+ cmCTestOptionalLog(this, OUTPUT,
+ " Use " << this->GetTestModelString() << " tag: "
+ << this->GetCurrentTag() << std::endl,
+ command->ShouldBeQuiet());
+ return true;
+}
+
+bool cmCTest::UpdateCTestConfiguration()
+{
+ if (this->Impl->SuppressUpdatingCTestConfiguration) {
+ return true;
+ }
+ std::string fileName = this->Impl->BinaryDir + "/CTestConfiguration.ini";
+ if (!cmSystemTools::FileExists(fileName)) {
+ fileName = this->Impl->BinaryDir + "/DartConfiguration.tcl";
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ "UpdateCTestConfiguration from :" << fileName << "\n");
+ if (!cmSystemTools::FileExists(fileName)) {
+ // No need to exit if we are not producing XML
+ if (this->Impl->ProduceXML) {
+ cmCTestLog(this, WARNING, "Cannot find file: " << fileName << std::endl);
+ return false;
+ }
+ } else {
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ "Parse Config file:" << fileName << "\n");
+ // parse the dart test file
+ cmsys::ifstream fin(fileName.c_str());
+
+ if (!fin) {
+ return false;
+ }
+
+ char buffer[1024];
+ while (fin) {
+ buffer[0] = 0;
+ fin.getline(buffer, 1023);
+ buffer[1023] = 0;
+ std::string line = cmCTest::CleanString(buffer);
+ if (line.empty()) {
+ continue;
+ }
+ while (fin && (line.back() == '\\')) {
+ line.resize(line.size() - 1);
+ buffer[0] = 0;
+ fin.getline(buffer, 1023);
+ buffer[1023] = 0;
+ line += cmCTest::CleanString(buffer);
+ }
+ if (line[0] == '#') {
+ continue;
+ }
+ std::string::size_type cpos = line.find_first_of(':');
+ if (cpos == std::string::npos) {
+ continue;
+ }
+ std::string key = line.substr(0, cpos);
+ std::string value = cmCTest::CleanString(line, cpos + 1);
+ this->Impl->CTestConfiguration[key] = value;
+ }
+ fin.close();
+ }
+ if (!this->GetCTestConfiguration("BuildDirectory").empty()) {
+ this->Impl->BinaryDir = this->GetCTestConfiguration("BuildDirectory");
+ cmSystemTools::ChangeDirectory(this->Impl->BinaryDir);
+ }
+ this->Impl->TimeOut =
+ std::chrono::seconds(atoi(this->GetCTestConfiguration("TimeOut").c_str()));
+ std::string const& testLoad = this->GetCTestConfiguration("TestLoad");
+ if (!testLoad.empty()) {
+ unsigned long load;
+ if (cmStrToULong(testLoad, &load)) {
+ this->SetTestLoad(load);
+ } else {
+ cmCTestLog(this, WARNING,
+ "Invalid value for 'Test Load' : " << testLoad << std::endl);
+ }
+ }
+ if (this->Impl->ProduceXML) {
+ this->Impl->CompressXMLFiles =
+ cmIsOn(this->GetCTestConfiguration("CompressSubmission"));
+ }
+ return true;
+}
+
+void cmCTest::BlockTestErrorDiagnostics()
+{
+ cmSystemTools::PutEnv("DART_TEST_FROM_DART=1");
+ cmSystemTools::PutEnv("DASHBOARD_TEST_FROM_CTEST=" CMake_VERSION);
+#if defined(_WIN32)
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+#elif defined(__BEOS__) || defined(__HAIKU__)
+ disable_debugger(1);
+#endif
+}
+
+void cmCTest::SetTestModel(int mode)
+{
+ this->Impl->InteractiveDebugMode = false;
+ this->Impl->TestModel = mode;
+}
+
+int cmCTest::GetTestModel() const
+{
+ return this->Impl->TestModel;
+}
+
+bool cmCTest::SetTest(const std::string& ttype, bool report)
+{
+ if (cmSystemTools::LowerCase(ttype) == "all") {
+ for (Part p = PartStart; p != PartCount; p = Part(p + 1)) {
+ this->Impl->Parts[p].Enable();
+ }
+ return true;
+ }
+ Part p = this->GetPartFromName(ttype);
+ if (p != PartCount) {
+ this->Impl->Parts[p].Enable();
+ return true;
+ }
+ if (report) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Don't know about test \"" << ttype << "\" yet..."
+ << std::endl);
+ }
+ return false;
+}
+
+void cmCTest::Finalize()
+{
+}
+
+bool cmCTest::OpenOutputFile(const std::string& path, const std::string& name,
+ cmGeneratedFileStream& stream, bool compress)
+{
+ std::string testingDir = this->Impl->BinaryDir + "/Testing";
+ if (!path.empty()) {
+ testingDir += "/" + path;
+ }
+ if (cmSystemTools::FileExists(testingDir)) {
+ if (!cmSystemTools::FileIsDirectory(testingDir)) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "File " << testingDir
+ << " is in the place of the testing directory"
+ << std::endl);
+ return false;
+ }
+ } else {
+ if (!cmSystemTools::MakeDirectory(testingDir)) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Cannot create directory " << testingDir << std::endl);
+ return false;
+ }
+ }
+ std::string filename = testingDir + "/" + name;
+ stream.SetTempExt("tmp");
+ stream.Open(filename);
+ if (!stream) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Problem opening file: " << filename << std::endl);
+ return false;
+ }
+ if (compress) {
+ if (this->Impl->CompressXMLFiles) {
+ stream.SetCompression(true);
+ }
+ }
+ return true;
+}
+
+bool cmCTest::AddIfExists(Part part, const std::string& file)
+{
+ if (this->CTestFileExists(file)) {
+ this->AddSubmitFile(part, file);
+ } else {
+ std::string name = cmStrCat(file, ".gz");
+ if (this->CTestFileExists(name)) {
+ this->AddSubmitFile(part, file);
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmCTest::CTestFileExists(const std::string& filename)
+{
+ std::string testingDir = this->Impl->BinaryDir + "/Testing/" +
+ this->Impl->CurrentTag + "/" + filename;
+ return cmSystemTools::FileExists(testingDir);
+}
+
+cmCTestBuildHandler* cmCTest::GetBuildHandler()
+{
+ return &this->Impl->BuildHandler;
+}
+
+cmCTestBuildAndTestHandler* cmCTest::GetBuildAndTestHandler()
+{
+ return &this->Impl->BuildAndTestHandler;
+}
+
+cmCTestCoverageHandler* cmCTest::GetCoverageHandler()
+{
+ return &this->Impl->CoverageHandler;
+}
+
+cmCTestScriptHandler* cmCTest::GetScriptHandler()
+{
+ return &this->Impl->ScriptHandler;
+}
+
+cmCTestTestHandler* cmCTest::GetTestHandler()
+{
+ return &this->Impl->TestHandler;
+}
+
+cmCTestUpdateHandler* cmCTest::GetUpdateHandler()
+{
+ return &this->Impl->UpdateHandler;
+}
+
+cmCTestConfigureHandler* cmCTest::GetConfigureHandler()
+{
+ return &this->Impl->ConfigureHandler;
+}
+
+cmCTestMemCheckHandler* cmCTest::GetMemCheckHandler()
+{
+ return &this->Impl->MemCheckHandler;
+}
+
+cmCTestSubmitHandler* cmCTest::GetSubmitHandler()
+{
+ return &this->Impl->SubmitHandler;
+}
+
+cmCTestUploadHandler* cmCTest::GetUploadHandler()
+{
+ return &this->Impl->UploadHandler;
+}
+
+int cmCTest::ProcessSteps()
+{
+ int res = 0;
+ bool notest = true;
+ int update_count = 0;
+
+ for (Part p = PartStart; notest && p != PartCount; p = Part(p + 1)) {
+ notest = !this->Impl->Parts[p];
+ }
+ if (this->Impl->Parts[PartUpdate] &&
+ (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
+ cmCTestUpdateHandler* uphandler = this->GetUpdateHandler();
+ uphandler->SetPersistentOption(
+ "SourceDirectory",
+ this->GetCTestConfiguration("SourceDirectory").c_str());
+ update_count = uphandler->ProcessHandler();
+ if (update_count < 0) {
+ res |= cmCTest::UPDATE_ERRORS;
+ }
+ }
+ if (this->Impl->TestModel == cmCTest::CONTINUOUS && !update_count) {
+ return 0;
+ }
+ if (this->Impl->Parts[PartConfigure] &&
+ (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
+ if (this->GetConfigureHandler()->ProcessHandler() < 0) {
+ res |= cmCTest::CONFIGURE_ERRORS;
+ }
+ }
+ if (this->Impl->Parts[PartBuild] &&
+ (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
+ this->UpdateCTestConfiguration();
+ if (this->GetBuildHandler()->ProcessHandler() < 0) {
+ res |= cmCTest::BUILD_ERRORS;
+ }
+ }
+ if ((this->Impl->Parts[PartTest] || notest) &&
+ (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
+ this->UpdateCTestConfiguration();
+ if (this->GetTestHandler()->ProcessHandler() < 0) {
+ res |= cmCTest::TEST_ERRORS;
+ }
+ }
+ if (this->Impl->Parts[PartCoverage] &&
+ (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
+ this->UpdateCTestConfiguration();
+ if (this->GetCoverageHandler()->ProcessHandler() < 0) {
+ res |= cmCTest::COVERAGE_ERRORS;
+ }
+ }
+ if (this->Impl->Parts[PartMemCheck] &&
+ (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
+ this->UpdateCTestConfiguration();
+ if (this->GetMemCheckHandler()->ProcessHandler() < 0) {
+ res |= cmCTest::MEMORY_ERRORS;
+ }
+ }
+ if (!notest) {
+ std::string notes_dir = this->Impl->BinaryDir + "/Testing/Notes";
+ if (cmSystemTools::FileIsDirectory(notes_dir)) {
+ cmsys::Directory d;
+ d.Load(notes_dir);
+ unsigned long kk;
+ for (kk = 0; kk < d.GetNumberOfFiles(); kk++) {
+ const char* file = d.GetFile(kk);
+ std::string fullname = notes_dir + "/" + file;
+ if (cmSystemTools::FileExists(fullname) &&
+ !cmSystemTools::FileIsDirectory(fullname)) {
+ if (!this->Impl->NotesFiles.empty()) {
+ this->Impl->NotesFiles += ";";
+ }
+ this->Impl->NotesFiles += fullname;
+ this->Impl->Parts[PartNotes].Enable();
+ }
+ }
+ }
+ }
+ if (this->Impl->Parts[PartNotes]) {
+ this->UpdateCTestConfiguration();
+ if (!this->Impl->NotesFiles.empty()) {
+ this->GenerateNotesFile(this->Impl->NotesFiles);
+ }
+ }
+ if (this->Impl->Parts[PartSubmit]) {
+ this->UpdateCTestConfiguration();
+ if (this->GetSubmitHandler()->ProcessHandler() < 0) {
+ res |= cmCTest::SUBMIT_ERRORS;
+ }
+ }
+ if (res != 0) {
+ cmCTestLog(this, ERROR_MESSAGE, "Errors while running CTest" << std::endl);
+ if (!this->Impl->OutputTestOutputOnTestFailure) {
+ const std::string lastTestLog =
+ this->GetBinaryDir() + "/Testing/Temporary/LastTest.log";
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Output from these tests are in: " << lastTestLog
+ << std::endl);
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Use \"--rerun-failed --output-on-failure\" to re-run the "
+ "failed cases verbosely."
+ << std::endl);
+ }
+ }
+ return res;
+}
+
+std::string cmCTest::GetTestModelString()
+{
+ if (!this->Impl->SpecificGroup.empty()) {
+ return this->Impl->SpecificGroup;
+ }
+ switch (this->Impl->TestModel) {
+ case cmCTest::NIGHTLY:
+ return "Nightly";
+ case cmCTest::CONTINUOUS:
+ return "Continuous";
+ }
+ return "Experimental";
+}
+
+int cmCTest::GetTestModelFromString(const std::string& str)
+{
+ if (str.empty()) {
+ return cmCTest::EXPERIMENTAL;
+ }
+ std::string rstr = cmSystemTools::LowerCase(str);
+ if (cmHasLiteralPrefix(rstr, "cont")) {
+ return cmCTest::CONTINUOUS;
+ }
+ if (cmHasLiteralPrefix(rstr, "nigh")) {
+ return cmCTest::NIGHTLY;
+ }
+ return cmCTest::EXPERIMENTAL;
+}
+
+//######################################################################
+//######################################################################
+//######################################################################
+//######################################################################
+
+int cmCTest::RunMakeCommand(const std::string& command, std::string& output,
+ int* retVal, const char* dir, cmDuration timeout,
+ std::ostream& ofs, Encoding encoding)
+{
+ // First generate the command and arguments
+ std::vector<std::string> args = cmSystemTools::ParseArguments(command);
+
+ if (args.empty()) {
+ return false;
+ }
+
+ std::vector<const char*> argv;
+ argv.reserve(args.size() + 1);
+ for (std::string const& a : args) {
+ argv.push_back(a.c_str());
+ }
+ argv.push_back(nullptr);
+
+ output.clear();
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Run command:");
+ for (char const* arg : argv) {
+ if (!arg) {
+ break;
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, " \"" << arg << "\"");
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, std::endl);
+
+ // Now create process object
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, argv.data());
+ cmsysProcess_SetWorkingDirectory(cp, dir);
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ cmsysProcess_SetTimeout(cp, timeout.count());
+ cmsysProcess_Execute(cp);
+
+ // Initialize tick's
+ std::string::size_type tick = 0;
+ std::string::size_type tick_len = 1024;
+ std::string::size_type tick_line_len = 50;
+
+ char* data;
+ int length;
+ cmProcessOutput processOutput(encoding);
+ std::string strdata;
+ cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
+ " Each . represents " << tick_len
+ << " bytes of output\n"
+ " "
+ << std::flush);
+ while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
+ processOutput.DecodeText(data, length, strdata);
+ for (char& cc : strdata) {
+ if (cc == 0) {
+ cc = '\n';
+ }
+ }
+ output.append(strdata);
+ while (output.size() > (tick * tick_len)) {
+ tick++;
+ cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, "." << std::flush);
+ if (tick % tick_line_len == 0 && tick > 0) {
+ cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
+ " Size: " << int((double(output.size()) / 1024.0) + 1)
+ << "K\n " << std::flush);
+ }
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ cmCTestLogWrite(strdata.c_str(), strdata.size()));
+ if (ofs) {
+ ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
+ }
+ }
+ processOutput.DecodeText(std::string(), strdata);
+ if (!strdata.empty()) {
+ output.append(strdata);
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ cmCTestLogWrite(strdata.c_str(), strdata.size()));
+ if (ofs) {
+ ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
+ }
+ }
+ cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
+ " Size of output: " << int(double(output.size()) / 1024.0) << "K"
+ << std::endl);
+
+ cmsysProcess_WaitForExit(cp, nullptr);
+
+ int result = cmsysProcess_GetState(cp);
+
+ if (result == cmsysProcess_State_Exited) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ "Command exited with the value: " << *retVal << std::endl);
+ } else if (result == cmsysProcess_State_Exception) {
+ *retVal = cmsysProcess_GetExitException(cp);
+ cmCTestLog(this, WARNING,
+ "There was an exception: " << *retVal << std::endl);
+ } else if (result == cmsysProcess_State_Expired) {
+ cmCTestLog(this, WARNING, "There was a timeout" << std::endl);
+ } else if (result == cmsysProcess_State_Error) {
+ output += "\n*** ERROR executing: ";
+ output += cmsysProcess_GetErrorString(cp);
+ output += "\n***The build process failed.";
+ cmCTestLog(this, ERROR_MESSAGE,
+ "There was an error: " << cmsysProcess_GetErrorString(cp)
+ << std::endl);
+ }
+
+ cmsysProcess_Delete(cp);
+
+ return result;
+}
+
+//######################################################################
+//######################################################################
+//######################################################################
+//######################################################################
+
+int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
+ int* retVal, std::ostream* log, cmDuration testTimeOut,
+ std::vector<std::string>* environment, Encoding encoding)
+{
+ bool modifyEnv = (environment && !environment->empty());
+
+ // determine how much time we have
+ cmDuration timeout = this->GetRemainingTimeAllowed();
+ if (timeout != cmCTest::MaxDuration()) {
+ timeout -= std::chrono::minutes(2);
+ }
+ if (this->Impl->TimeOut > cmDuration::zero() &&
+ this->Impl->TimeOut < timeout) {
+ timeout = this->Impl->TimeOut;
+ }
+ if (testTimeOut > cmDuration::zero() &&
+ testTimeOut < this->GetRemainingTimeAllowed()) {
+ timeout = testTimeOut;
+ }
+
+ // always have at least 1 second if we got to here
+ if (timeout <= cmDuration::zero()) {
+ timeout = std::chrono::seconds(1);
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ "Test timeout computed to be: "
+ << (timeout == cmCTest::MaxDuration()
+ ? std::string("infinite")
+ : std::to_string(cmDurationTo<unsigned int>(timeout)))
+ << "\n");
+ if (cmSystemTools::SameFile(argv[0], cmSystemTools::GetCTestCommand()) &&
+ !this->Impl->ForceNewCTestProcess) {
+ cmCTest inst;
+ inst.Impl->ConfigType = this->Impl->ConfigType;
+ inst.Impl->TimeOut = timeout;
+
+ // Capture output of the child ctest.
+ std::ostringstream oss;
+ inst.SetStreams(&oss, &oss);
+
+ std::vector<std::string> args;
+ for (char const* i : argv) {
+ if (i) {
+ // make sure we pass the timeout in for any build and test
+ // invocations. Since --build-generator is required this is a
+ // good place to check for it, and to add the arguments in
+ if (strcmp(i, "--build-generator") == 0 &&
+ timeout != cmCTest::MaxDuration() &&
+ timeout > cmDuration::zero()) {
+ args.emplace_back("--test-timeout");
+ args.push_back(std::to_string(cmDurationTo<unsigned int>(timeout)));
+ }
+ args.emplace_back(i);
+ }
+ }
+ if (log) {
+ *log << "* Run internal CTest" << std::endl;
+ }
+
+ std::unique_ptr<cmSystemTools::SaveRestoreEnvironment> saveEnv;
+ if (modifyEnv) {
+ saveEnv = cm::make_unique<cmSystemTools::SaveRestoreEnvironment>();
+ cmSystemTools::AppendEnv(*environment);
+ }
+
+ *retVal = inst.Run(args, output);
+ if (output) {
+ *output += oss.str();
+ }
+ if (log && output) {
+ *log << *output;
+ }
+ if (output) {
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ "Internal cmCTest object used to run test." << std::endl
+ << *output
+ << std::endl);
+ }
+
+ return cmsysProcess_State_Exited;
+ }
+ std::vector<char> tempOutput;
+ if (output) {
+ output->clear();
+ }
+
+ std::unique_ptr<cmSystemTools::SaveRestoreEnvironment> saveEnv;
+ if (modifyEnv) {
+ saveEnv = cm::make_unique<cmSystemTools::SaveRestoreEnvironment>();
+ cmSystemTools::AppendEnv(*environment);
+ }
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, argv.data());
+ cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
+ if (cmSystemTools::GetRunCommandHideConsole()) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ }
+
+ cmsysProcess_SetTimeout(cp, timeout.count());
+ cmsysProcess_Execute(cp);
+
+ char* data;
+ int length;
+ cmProcessOutput processOutput(encoding);
+ std::string strdata;
+ while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
+ processOutput.DecodeText(data, length, strdata);
+ if (output) {
+ cm::append(tempOutput, data, data + length);
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ cmCTestLogWrite(strdata.c_str(), strdata.size()));
+ if (log) {
+ log->write(strdata.c_str(), strdata.size());
+ }
+ }
+ processOutput.DecodeText(std::string(), strdata);
+ if (!strdata.empty()) {
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ cmCTestLogWrite(strdata.c_str(), strdata.size()));
+ if (log) {
+ log->write(strdata.c_str(), strdata.size());
+ }
+ }
+
+ cmsysProcess_WaitForExit(cp, nullptr);
+ processOutput.DecodeText(tempOutput, tempOutput);
+ if (output && tempOutput.begin() != tempOutput.end()) {
+ output->append(tempOutput.data(), tempOutput.size());
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ "-- Process completed" << std::endl);
+
+ int result = cmsysProcess_GetState(cp);
+
+ if (result == cmsysProcess_State_Exited) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ if (*retVal != 0 && this->Impl->OutputTestOutputOnTestFailure) {
+ this->OutputTestErrors(tempOutput);
+ }
+ } else if (result == cmsysProcess_State_Exception) {
+ if (this->Impl->OutputTestOutputOnTestFailure) {
+ this->OutputTestErrors(tempOutput);
+ }
+ *retVal = cmsysProcess_GetExitException(cp);
+ std::string outerr = cmStrCat("\n*** Exception executing: ",
+ cmsysProcess_GetExceptionString(cp));
+ if (output) {
+ *output += outerr;
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl);
+ } else if (result == cmsysProcess_State_Error) {
+ std::string outerr =
+ cmStrCat("\n*** ERROR executing: ", cmsysProcess_GetErrorString(cp));
+ if (output) {
+ *output += outerr;
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl);
+ }
+ cmsysProcess_Delete(cp);
+
+ return result;
+}
+
+std::string cmCTest::SafeBuildIdField(const std::string& value)
+{
+ std::string safevalue(value);
+
+ if (!safevalue.empty()) {
+ // Disallow non-filename and non-space whitespace characters.
+ // If they occur, replace them with ""
+ //
+ const char* disallowed = "\\:*?\"<>|\n\r\t\f\v";
+
+ if (safevalue.find_first_of(disallowed) != std::string::npos) {
+ std::string::size_type i = 0;
+ std::string::size_type n = strlen(disallowed);
+ char replace[2];
+ replace[1] = 0;
+
+ for (i = 0; i < n; ++i) {
+ replace[0] = disallowed[i];
+ cmSystemTools::ReplaceString(safevalue, replace, "");
+ }
+ }
+ }
+
+ if (safevalue.empty()) {
+ safevalue = "(empty)";
+ }
+
+ return safevalue;
+}
+
+void cmCTest::StartXML(cmXMLWriter& xml, bool append)
+{
+ if (this->Impl->CurrentTag.empty()) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Current Tag empty, this may mean"
+ " NightlStartTime was not set correctly."
+ << std::endl);
+ cmSystemTools::SetFatalErrorOccured();
+ }
+
+ // find out about the system
+ cmsys::SystemInformation info;
+ info.RunCPUCheck();
+ info.RunOSCheck();
+ info.RunMemoryCheck();
+
+ std::string buildname =
+ cmCTest::SafeBuildIdField(this->GetCTestConfiguration("BuildName"));
+ std::string stamp = cmCTest::SafeBuildIdField(this->Impl->CurrentTag + "-" +
+ this->GetTestModelString());
+ std::string site =
+ cmCTest::SafeBuildIdField(this->GetCTestConfiguration("Site"));
+
+ xml.StartDocument();
+ xml.StartElement("Site");
+ xml.Attribute("BuildName", buildname);
+ xml.BreakAttributes();
+ xml.Attribute("BuildStamp", stamp);
+ xml.Attribute("Name", site);
+ xml.Attribute("Generator",
+ std::string("ctest-") + cmVersion::GetCMakeVersion());
+ if (append) {
+ xml.Attribute("Append", "true");
+ }
+ xml.Attribute("CompilerName", this->GetCTestConfiguration("Compiler"));
+ xml.Attribute("CompilerVersion",
+ this->GetCTestConfiguration("CompilerVersion"));
+ xml.Attribute("OSName", info.GetOSName());
+ xml.Attribute("Hostname", info.GetHostname());
+ xml.Attribute("OSRelease", info.GetOSRelease());
+ xml.Attribute("OSVersion", info.GetOSVersion());
+ xml.Attribute("OSPlatform", info.GetOSPlatform());
+ xml.Attribute("Is64Bits", info.Is64Bits());
+ xml.Attribute("VendorString", info.GetVendorString());
+ xml.Attribute("VendorID", info.GetVendorID());
+ xml.Attribute("FamilyID", info.GetFamilyID());
+ xml.Attribute("ModelID", info.GetModelID());
+ xml.Attribute("ProcessorCacheSize", info.GetProcessorCacheSize());
+ xml.Attribute("NumberOfLogicalCPU", info.GetNumberOfLogicalCPU());
+ xml.Attribute("NumberOfPhysicalCPU", info.GetNumberOfPhysicalCPU());
+ xml.Attribute("TotalVirtualMemory", info.GetTotalVirtualMemory());
+ xml.Attribute("TotalPhysicalMemory", info.GetTotalPhysicalMemory());
+ xml.Attribute("LogicalProcessorsPerPhysical",
+ info.GetLogicalProcessorsPerPhysical());
+ xml.Attribute("ProcessorClockFrequency", info.GetProcessorClockFrequency());
+
+ std::string changeId = this->GetCTestConfiguration("ChangeId");
+ if (!changeId.empty()) {
+ xml.Attribute("ChangeId", changeId);
+ }
+
+ this->AddSiteProperties(xml);
+}
+
+void cmCTest::AddSiteProperties(cmXMLWriter& xml)
+{
+ cmCTestScriptHandler* ch = this->GetScriptHandler();
+ cmake* cm = ch->GetCMake();
+ // if no CMake then this is the old style script and props like
+ // this will not work anyway.
+ if (!cm) {
+ return;
+ }
+ // This code should go when cdash is changed to use labels only
+ cmProp subproject = cm->GetState()->GetGlobalProperty("SubProject");
+ if (subproject) {
+ xml.StartElement("Subproject");
+ xml.Attribute("name", *subproject);
+ cmProp labels =
+ ch->GetCMake()->GetState()->GetGlobalProperty("SubProjectLabels");
+ if (labels) {
+ xml.StartElement("Labels");
+ std::vector<std::string> args = cmExpandedList(*labels);
+ for (std::string const& i : args) {
+ xml.Element("Label", i);
+ }
+ xml.EndElement();
+ }
+ xml.EndElement();
+ }
+
+ // This code should stay when cdash only does label based sub-projects
+ cmProp label = cm->GetState()->GetGlobalProperty("Label");
+ if (label) {
+ xml.StartElement("Labels");
+ xml.Element("Label", *label);
+ xml.EndElement();
+ }
+}
+
+void cmCTest::GenerateSubprojectsOutput(cmXMLWriter& xml)
+{
+ for (std::string const& subproj : this->GetLabelsForSubprojects()) {
+ xml.StartElement("Subproject");
+ xml.Attribute("name", subproj);
+ xml.Element("Label", subproj);
+ xml.EndElement(); // Subproject
+ }
+}
+
+std::vector<std::string> cmCTest::GetLabelsForSubprojects()
+{
+ std::string labelsForSubprojects =
+ this->GetCTestConfiguration("LabelsForSubprojects");
+ std::vector<std::string> subprojects = cmExpandedList(labelsForSubprojects);
+
+ // sort the array
+ std::sort(subprojects.begin(), subprojects.end());
+ // remove duplicates
+ auto new_end = std::unique(subprojects.begin(), subprojects.end());
+ subprojects.erase(new_end, subprojects.end());
+
+ return subprojects;
+}
+
+void cmCTest::EndXML(cmXMLWriter& xml)
+{
+ xml.EndElement(); // Site
+ xml.EndDocument();
+}
+
+int cmCTest::GenerateCTestNotesOutput(cmXMLWriter& xml,
+ std::vector<std::string> const& files)
+{
+ std::string buildname =
+ cmCTest::SafeBuildIdField(this->GetCTestConfiguration("BuildName"));
+ xml.StartDocument();
+ xml.ProcessingInstruction("xml-stylesheet",
+ "type=\"text/xsl\" "
+ "href=\"Dart/Source/Server/XSL/Build.xsl "
+ "<file:///Dart/Source/Server/XSL/Build.xsl> \"");
+ xml.StartElement("Site");
+ xml.Attribute("BuildName", buildname);
+ xml.Attribute("BuildStamp",
+ this->Impl->CurrentTag + "-" + this->GetTestModelString());
+ xml.Attribute("Name", this->GetCTestConfiguration("Site"));
+ xml.Attribute("Generator",
+ std::string("ctest-") + cmVersion::GetCMakeVersion());
+ this->AddSiteProperties(xml);
+ xml.StartElement("Notes");
+
+ for (std::string const& file : files) {
+ cmCTestLog(this, OUTPUT, "\tAdd file: " << file << std::endl);
+ std::string note_time = this->CurrentTime();
+ xml.StartElement("Note");
+ xml.Attribute("Name", file);
+ xml.Element("Time", std::chrono::system_clock::now());
+ xml.Element("DateTime", note_time);
+ xml.StartElement("Text");
+ cmsys::ifstream ifs(file.c_str());
+ if (ifs) {
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ xml.Content(line);
+ xml.Content("\n");
+ }
+ ifs.close();
+ } else {
+ xml.Content("Problem reading file: " + file + "\n");
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Problem reading file: " << file << " while creating notes"
+ << std::endl);
+ }
+ xml.EndElement(); // Text
+ xml.EndElement(); // Note
+ }
+ xml.EndElement(); // Notes
+ xml.EndElement(); // Site
+ xml.EndDocument();
+ return 1;
+}
+
+int cmCTest::GenerateNotesFile(std::vector<std::string> const& files)
+{
+ cmGeneratedFileStream ofs;
+ if (!this->OpenOutputFile(this->Impl->CurrentTag, "Notes.xml", ofs)) {
+ cmCTestLog(this, ERROR_MESSAGE, "Cannot open notes file" << std::endl);
+ return 1;
+ }
+ cmXMLWriter xml(ofs);
+ this->GenerateCTestNotesOutput(xml, files);
+ return 0;
+}
+
+int cmCTest::GenerateNotesFile(const std::string& cfiles)
+{
+ if (cfiles.empty()) {
+ return 1;
+ }
+
+ cmCTestLog(this, OUTPUT, "Create notes file" << std::endl);
+
+ std::vector<std::string> const files =
+ cmSystemTools::SplitString(cfiles, ';');
+ if (files.empty()) {
+ return 1;
+ }
+
+ return this->GenerateNotesFile(files);
+}
+
+int cmCTest::GenerateDoneFile()
+{
+ cmGeneratedFileStream ofs;
+ if (!this->OpenOutputFile(this->Impl->CurrentTag, "Done.xml", ofs)) {
+ cmCTestLog(this, ERROR_MESSAGE, "Cannot open done file" << std::endl);
+ return 1;
+ }
+ cmXMLWriter xml(ofs);
+ xml.StartDocument();
+ xml.StartElement("Done");
+ xml.Element("buildId", this->Impl->BuildID);
+ xml.Element("time", std::chrono::system_clock::now());
+ xml.EndElement(); // Done
+ xml.EndDocument();
+
+ return 0;
+}
+
+std::string cmCTest::Base64GzipEncodeFile(std::string const& file)
+{
+ std::string tarFile = file + "_temp.tar.gz";
+ std::vector<std::string> files;
+ files.push_back(file);
+
+ if (!cmSystemTools::CreateTar(tarFile, files, cmSystemTools::TarCompressGZip,
+ false)) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Error creating tar while "
+ "encoding file: "
+ << file << std::endl);
+ return "";
+ }
+ std::string base64 = this->Base64EncodeFile(tarFile);
+ cmSystemTools::RemoveFile(tarFile);
+ return base64;
+}
+
+std::string cmCTest::Base64EncodeFile(std::string const& file)
+{
+ size_t const len = cmSystemTools::FileLength(file);
+ cmsys::ifstream ifs(file.c_str(),
+ std::ios::in
+#ifdef _WIN32
+ | std::ios::binary
+#endif
+ );
+ std::vector<char> file_buffer(len + 1);
+ ifs.read(&file_buffer[0], len);
+ ifs.close();
+
+ std::vector<char> encoded_buffer((len * 3) / 2 + 5);
+
+ size_t const rlen = cmsysBase64_Encode(
+ reinterpret_cast<unsigned char*>(&file_buffer[0]), len,
+ reinterpret_cast<unsigned char*>(&encoded_buffer[0]), 1);
+
+ return std::string(&encoded_buffer[0], rlen);
+}
+
+bool cmCTest::SubmitExtraFiles(std::vector<std::string> const& files)
+{
+ for (std::string const& file : files) {
+ if (!cmSystemTools::FileExists(file)) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Cannot find extra file: " << file << " to submit."
+ << std::endl;);
+ return false;
+ }
+ this->AddSubmitFile(PartExtraFiles, file);
+ }
+ return true;
+}
+
+bool cmCTest::SubmitExtraFiles(const std::string& cfiles)
+{
+ if (cfiles.empty()) {
+ return true;
+ }
+
+ cmCTestLog(this, OUTPUT, "Submit extra files" << std::endl);
+
+ std::vector<std::string> const files =
+ cmSystemTools::SplitString(cfiles, ';');
+ if (files.empty()) {
+ return true;
+ }
+
+ return this->SubmitExtraFiles(files);
+}
+
+// for a -D argument convert the next argument into
+// the proper list of dashboard steps via SetTest
+bool cmCTest::AddTestsForDashboardType(std::string& targ)
+{
+ if (targ == "Experimental") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Start");
+ this->SetTest("Configure");
+ this->SetTest("Build");
+ this->SetTest("Test");
+ this->SetTest("Coverage");
+ this->SetTest("Submit");
+ } else if (targ == "ExperimentalStart") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Start");
+ } else if (targ == "ExperimentalUpdate") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Update");
+ } else if (targ == "ExperimentalConfigure") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Configure");
+ } else if (targ == "ExperimentalBuild") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Build");
+ } else if (targ == "ExperimentalTest") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Test");
+ } else if (targ == "ExperimentalMemCheck" || targ == "ExperimentalPurify") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("MemCheck");
+ } else if (targ == "ExperimentalCoverage") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Coverage");
+ } else if (targ == "ExperimentalSubmit") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Submit");
+ } else if (targ == "Continuous") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Start");
+ this->SetTest("Update");
+ this->SetTest("Configure");
+ this->SetTest("Build");
+ this->SetTest("Test");
+ this->SetTest("Coverage");
+ this->SetTest("Submit");
+ } else if (targ == "ContinuousStart") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Start");
+ } else if (targ == "ContinuousUpdate") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Update");
+ } else if (targ == "ContinuousConfigure") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Configure");
+ } else if (targ == "ContinuousBuild") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Build");
+ } else if (targ == "ContinuousTest") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Test");
+ } else if (targ == "ContinuousMemCheck" || targ == "ContinuousPurify") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("MemCheck");
+ } else if (targ == "ContinuousCoverage") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Coverage");
+ } else if (targ == "ContinuousSubmit") {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ this->SetTest("Submit");
+ } else if (targ == "Nightly") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Start");
+ this->SetTest("Update");
+ this->SetTest("Configure");
+ this->SetTest("Build");
+ this->SetTest("Test");
+ this->SetTest("Coverage");
+ this->SetTest("Submit");
+ } else if (targ == "NightlyStart") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Start");
+ } else if (targ == "NightlyUpdate") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Update");
+ } else if (targ == "NightlyConfigure") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Configure");
+ } else if (targ == "NightlyBuild") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Build");
+ } else if (targ == "NightlyTest") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Test");
+ } else if (targ == "NightlyMemCheck" || targ == "NightlyPurify") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("MemCheck");
+ } else if (targ == "NightlyCoverage") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Coverage");
+ } else if (targ == "NightlySubmit") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Submit");
+ } else if (targ == "MemoryCheck") {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ this->SetTest("Start");
+ this->SetTest("Configure");
+ this->SetTest("Build");
+ this->SetTest("MemCheck");
+ this->SetTest("Coverage");
+ this->SetTest("Submit");
+ } else if (targ == "NightlyMemoryCheck") {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ this->SetTest("Start");
+ this->SetTest("Update");
+ this->SetTest("Configure");
+ this->SetTest("Build");
+ this->SetTest("MemCheck");
+ this->SetTest("Coverage");
+ this->SetTest("Submit");
+ } else {
+ return false;
+ }
+ return true;
+}
+
+void cmCTest::ErrorMessageUnknownDashDValue(std::string& val)
+{
+ cmCTestLog(this, ERROR_MESSAGE,
+ "CTest -D called with incorrect option: " << val << std::endl);
+
+ cmCTestLog(
+ this, ERROR_MESSAGE,
+ "Available options are:"
+ << std::endl
+ << " ctest -D Continuous" << std::endl
+ << " ctest -D Continuous(Start|Update|Configure|Build)" << std::endl
+ << " ctest -D Continuous(Test|Coverage|MemCheck|Submit)" << std::endl
+ << " ctest -D Experimental" << std::endl
+ << " ctest -D Experimental(Start|Update|Configure|Build)" << std::endl
+ << " ctest -D Experimental(Test|Coverage|MemCheck|Submit)" << std::endl
+ << " ctest -D Nightly" << std::endl
+ << " ctest -D Nightly(Start|Update|Configure|Build)" << std::endl
+ << " ctest -D Nightly(Test|Coverage|MemCheck|Submit)" << std::endl
+ << " ctest -D NightlyMemoryCheck" << std::endl);
+}
+
+bool cmCTest::CheckArgument(const std::string& arg, cm::string_view varg1,
+ const char* varg2)
+{
+ return (arg == varg1) || (varg2 && arg == varg2);
+}
+
+// Processes one command line argument (and its arguments if any)
+// for many simple options and then returns
+bool cmCTest::HandleCommandLineArguments(size_t& i,
+ std::vector<std::string>& args,
+ std::string& errormsg)
+{
+ std::string arg = args[i];
+ if (this->CheckArgument(arg, "-F"_s)) {
+ this->Impl->Failover = true;
+ } else if (this->CheckArgument(arg, "-j"_s, "--parallel") &&
+ i < args.size() - 1) {
+ i++;
+ int plevel = atoi(args[i].c_str());
+ this->SetParallelLevel(plevel);
+ this->Impl->ParallelLevelSetInCli = true;
+ } else if (cmHasPrefix(arg, "-j")) {
+ int plevel = atoi(arg.substr(2).c_str());
+ this->SetParallelLevel(plevel);
+ this->Impl->ParallelLevelSetInCli = true;
+ }
+
+ else if (this->CheckArgument(arg, "--repeat-until-fail"_s)) {
+ if (i >= args.size() - 1) {
+ errormsg = "'--repeat-until-fail' requires an argument";
+ return false;
+ }
+ if (this->Impl->RepeatMode != cmCTest::Repeat::Never) {
+ errormsg = "At most one '--repeat' option may be used.";
+ return false;
+ }
+ i++;
+ long repeat = 1;
+ if (!cmStrToLong(args[i], &repeat)) {
+ errormsg = cmStrCat("'--repeat-until-fail' given non-integer value '",
+ args[i], "'");
+ return false;
+ }
+ this->Impl->RepeatCount = static_cast<int>(repeat);
+ if (repeat > 1) {
+ this->Impl->RepeatMode = cmCTest::Repeat::UntilFail;
+ }
+ }
+
+ else if (this->CheckArgument(arg, "--repeat"_s)) {
+ if (i >= args.size() - 1) {
+ errormsg = "'--repeat' requires an argument";
+ return false;
+ }
+ if (this->Impl->RepeatMode != cmCTest::Repeat::Never) {
+ errormsg = "At most one '--repeat' option may be used.";
+ return false;
+ }
+ i++;
+ cmsys::RegularExpression repeatRegex(
+ "^(until-fail|until-pass|after-timeout):([0-9]+)$");
+ if (repeatRegex.find(args[i])) {
+ std::string const& count = repeatRegex.match(2);
+ unsigned long n = 1;
+ cmStrToULong(count, &n); // regex guarantees success
+ this->Impl->RepeatCount = static_cast<int>(n);
+ if (this->Impl->RepeatCount > 1) {
+ std::string const& mode = repeatRegex.match(1);
+ if (mode == "until-fail") {
+ this->Impl->RepeatMode = cmCTest::Repeat::UntilFail;
+ } else if (mode == "until-pass") {
+ this->Impl->RepeatMode = cmCTest::Repeat::UntilPass;
+ } else if (mode == "after-timeout") {
+ this->Impl->RepeatMode = cmCTest::Repeat::AfterTimeout;
+ }
+ }
+ } else {
+ errormsg = cmStrCat("'--repeat' given invalid value '", args[i], "'");
+ return false;
+ }
+ }
+
+ else if (this->CheckArgument(arg, "--test-load"_s) && i < args.size() - 1) {
+ i++;
+ unsigned long load;
+ if (cmStrToULong(args[i], &load)) {
+ this->SetTestLoad(load);
+ } else {
+ cmCTestLog(this, WARNING,
+ "Invalid value for 'Test Load' : " << args[i] << std::endl);
+ }
+ }
+
+ else if (this->CheckArgument(arg, "--no-compress-output"_s)) {
+ this->Impl->CompressTestOutput = false;
+ }
+
+ else if (this->CheckArgument(arg, "--print-labels"_s)) {
+ this->Impl->PrintLabels = true;
+ }
+
+ else if (this->CheckArgument(arg, "--http1.0"_s)) {
+ this->Impl->UseHTTP10 = true;
+ }
+
+ else if (this->CheckArgument(arg, "--timeout"_s) && i < args.size() - 1) {
+ i++;
+ auto timeout = cmDuration(atof(args[i].c_str()));
+ this->Impl->GlobalTimeout = timeout;
+ }
+
+ else if (this->CheckArgument(arg, "--stop-time"_s) && i < args.size() - 1) {
+ i++;
+ this->SetStopTime(args[i]);
+ }
+
+ else if (this->CheckArgument(arg, "--stop-on-failure"_s)) {
+ this->Impl->StopOnFailure = true;
+ }
+
+ else if (this->CheckArgument(arg, "-C"_s, "--build-config") &&
+ i < args.size() - 1) {
+ i++;
+ this->SetConfigType(args[i]);
+ }
+
+ else if (this->CheckArgument(arg, "--debug"_s)) {
+ this->Impl->Debug = true;
+ this->Impl->ShowLineNumbers = true;
+ } else if ((this->CheckArgument(arg, "--group"_s) ||
+ // This is an undocumented / deprecated option.
+ // "Track" has been renamed to "Group".
+ this->CheckArgument(arg, "--track"_s)) &&
+ i < args.size() - 1) {
+ i++;
+ this->Impl->SpecificGroup = args[i];
+ } else if (this->CheckArgument(arg, "--show-line-numbers"_s)) {
+ this->Impl->ShowLineNumbers = true;
+ } else if (this->CheckArgument(arg, "--no-label-summary"_s)) {
+ this->Impl->LabelSummary = false;
+ } else if (this->CheckArgument(arg, "--no-subproject-summary"_s)) {
+ this->Impl->SubprojectSummary = false;
+ } else if (this->CheckArgument(arg, "-Q"_s, "--quiet")) {
+ this->Impl->Quiet = true;
+ } else if (this->CheckArgument(arg, "--progress"_s)) {
+ this->Impl->TestProgressOutput = true;
+ } else if (this->CheckArgument(arg, "-V"_s, "--verbose")) {
+ this->Impl->Verbose = true;
+ } else if (this->CheckArgument(arg, "-VV"_s, "--extra-verbose")) {
+ this->Impl->ExtraVerbose = true;
+ this->Impl->Verbose = true;
+ } else if (this->CheckArgument(arg, "--output-on-failure"_s)) {
+ this->Impl->OutputTestOutputOnTestFailure = true;
+ } else if (this->CheckArgument(arg, "--test-output-size-passed"_s) &&
+ i < args.size() - 1) {
+ i++;
+ long outputSize;
+ if (cmStrToLong(args[i], &outputSize)) {
+ this->Impl->TestHandler.SetTestOutputSizePassed(int(outputSize));
+ } else {
+ cmCTestLog(this, WARNING,
+ "Invalid value for '--test-output-size-passed': " << args[i]
+ << "\n");
+ }
+ } else if (this->CheckArgument(arg, "--test-output-size-failed"_s) &&
+ i < args.size() - 1) {
+ i++;
+ long outputSize;
+ if (cmStrToLong(args[i], &outputSize)) {
+ this->Impl->TestHandler.SetTestOutputSizeFailed(int(outputSize));
+ } else {
+ cmCTestLog(this, WARNING,
+ "Invalid value for '--test-output-size-failed': " << args[i]
+ << "\n");
+ }
+ } else if (this->CheckArgument(arg, "-N"_s, "--show-only")) {
+ this->Impl->ShowOnly = true;
+ } else if (cmHasLiteralPrefix(arg, "--show-only=")) {
+ this->Impl->ShowOnly = true;
+
+ // Check if a specific format is requested. Defaults to human readable
+ // text.
+ std::string argWithFormat = "--show-only=";
+ std::string format = arg.substr(argWithFormat.length());
+ if (format == "json-v1") {
+ // Force quiet mode so the only output is the json object model.
+ this->Impl->Quiet = true;
+ this->Impl->OutputAsJson = true;
+ this->Impl->OutputAsJsonVersion = 1;
+ } else if (format != "human") {
+ errormsg = "'--show-only=' given unknown value '" + format + "'";
+ return false;
+ }
+ }
+
+ else if (this->CheckArgument(arg, "-O"_s, "--output-log") &&
+ i < args.size() - 1) {
+ i++;
+ this->SetOutputLogFileName(args[i]);
+ }
+
+ else if (this->CheckArgument(arg, "--tomorrow-tag"_s)) {
+ this->Impl->TomorrowTag = true;
+ } else if (this->CheckArgument(arg, "--force-new-ctest-process"_s)) {
+ this->Impl->ForceNewCTestProcess = true;
+ } else if (this->CheckArgument(arg, "-W"_s, "--max-width") &&
+ i < args.size() - 1) {
+ i++;
+ this->Impl->MaxTestNameWidth = atoi(args[i].c_str());
+ } else if (this->CheckArgument(arg, "--interactive-debug-mode"_s) &&
+ i < args.size() - 1) {
+ i++;
+ this->Impl->InteractiveDebugMode = cmIsOn(args[i]);
+ } else if (this->CheckArgument(arg, "--submit-index"_s) &&
+ i < args.size() - 1) {
+ i++;
+ this->Impl->SubmitIndex = atoi(args[i].c_str());
+ if (this->Impl->SubmitIndex < 0) {
+ this->Impl->SubmitIndex = 0;
+ }
+ }
+
+ else if (this->CheckArgument(arg, "--overwrite"_s) && i < args.size() - 1) {
+ i++;
+ this->AddCTestConfigurationOverwrite(args[i]);
+ } else if (this->CheckArgument(arg, "-A"_s, "--add-notes") &&
+ i < args.size() - 1) {
+ this->Impl->ProduceXML = true;
+ this->SetTest("Notes");
+ i++;
+ this->SetNotesFiles(args[i]);
+ return true;
+ } else if (this->CheckArgument(arg, "--test-dir"_s)) {
+ if (i >= args.size() - 1) {
+ errormsg = "'--test-dir' requires an argument";
+ return false;
+ }
+ i++;
+ this->Impl->TestDir = std::string(args[i]);
+ }
+
+ cm::string_view noTestsPrefix = "--no-tests=";
+ if (cmHasPrefix(arg, noTestsPrefix)) {
+ cm::string_view noTestsMode =
+ cm::string_view(arg).substr(noTestsPrefix.length());
+ if (noTestsMode == "error") {
+ this->Impl->NoTestsMode = cmCTest::NoTests::Error;
+ } else if (noTestsMode != "ignore") {
+ errormsg =
+ cmStrCat("'--no-tests=' given unknown value '", noTestsMode, '\'');
+ return false;
+ } else {
+ this->Impl->NoTestsMode = cmCTest::NoTests::Ignore;
+ }
+ }
+
+ // options that control what tests are run
+ else if (this->CheckArgument(arg, "-I"_s, "--tests-information") &&
+ i < args.size() - 1) {
+ i++;
+ this->GetTestHandler()->SetPersistentOption("TestsToRunInformation",
+ args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption("TestsToRunInformation",
+ args[i].c_str());
+ } else if (this->CheckArgument(arg, "-U"_s, "--union")) {
+ this->GetTestHandler()->SetPersistentOption("UseUnion", "true");
+ this->GetMemCheckHandler()->SetPersistentOption("UseUnion", "true");
+ } else if (this->CheckArgument(arg, "-R"_s, "--tests-regex") &&
+ i < args.size() - 1) {
+ i++;
+ this->GetTestHandler()->SetPersistentOption("IncludeRegularExpression",
+ args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption("IncludeRegularExpression",
+ args[i].c_str());
+ } else if (this->CheckArgument(arg, "-L"_s, "--label-regex") &&
+ i < args.size() - 1) {
+ i++;
+ this->GetTestHandler()->AddPersistentMultiOption("LabelRegularExpression",
+ args[i]);
+ this->GetMemCheckHandler()->AddPersistentMultiOption(
+ "LabelRegularExpression", args[i]);
+ } else if (this->CheckArgument(arg, "-LE"_s, "--label-exclude") &&
+ i < args.size() - 1) {
+ i++;
+ this->GetTestHandler()->AddPersistentMultiOption(
+ "ExcludeLabelRegularExpression", args[i]);
+ this->GetMemCheckHandler()->AddPersistentMultiOption(
+ "ExcludeLabelRegularExpression", args[i]);
+ }
+
+ else if (this->CheckArgument(arg, "-E"_s, "--exclude-regex") &&
+ i < args.size() - 1) {
+ i++;
+ this->GetTestHandler()->SetPersistentOption("ExcludeRegularExpression",
+ args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption("ExcludeRegularExpression",
+ args[i].c_str());
+ }
+
+ else if (this->CheckArgument(arg, "-FA"_s, "--fixture-exclude-any") &&
+ i < args.size() - 1) {
+ i++;
+ this->GetTestHandler()->SetPersistentOption(
+ "ExcludeFixtureRegularExpression", args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption(
+ "ExcludeFixtureRegularExpression", args[i].c_str());
+ } else if (this->CheckArgument(arg, "-FS"_s, "--fixture-exclude-setup") &&
+ i < args.size() - 1) {
+ i++;
+ this->GetTestHandler()->SetPersistentOption(
+ "ExcludeFixtureSetupRegularExpression", args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption(
+ "ExcludeFixtureSetupRegularExpression", args[i].c_str());
+ } else if (this->CheckArgument(arg, "-FC"_s, "--fixture-exclude-cleanup") &&
+ i < args.size() - 1) {
+ i++;
+ this->GetTestHandler()->SetPersistentOption(
+ "ExcludeFixtureCleanupRegularExpression", args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption(
+ "ExcludeFixtureCleanupRegularExpression", args[i].c_str());
+ }
+
+ else if (this->CheckArgument(arg, "--resource-spec-file"_s) &&
+ i < args.size() - 1) {
+ i++;
+ this->GetTestHandler()->SetPersistentOption("ResourceSpecFile",
+ args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption("ResourceSpecFile",
+ args[i].c_str());
+ }
+
+ else if (this->CheckArgument(arg, "--rerun-failed"_s)) {
+ this->GetTestHandler()->SetPersistentOption("RerunFailed", "true");
+ this->GetMemCheckHandler()->SetPersistentOption("RerunFailed", "true");
+ }
+ return true;
+}
+
+#if !defined(_WIN32)
+bool cmCTest::ConsoleIsNotDumb()
+{
+ std::string term_env_variable;
+ if (cmSystemTools::GetEnv("TERM", term_env_variable)) {
+ return isatty(1) && term_env_variable != "dumb";
+ }
+ return false;
+}
+#endif
+
+bool cmCTest::ProgressOutputSupportedByConsole()
+{
+#if defined(_WIN32)
+ // On Windows we need a console buffer.
+ void* console = GetStdHandle(STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ return GetConsoleScreenBufferInfo(console, &csbi);
+#else
+ // On UNIX we need a non-dumb tty.
+ return ConsoleIsNotDumb();
+#endif
+}
+
+bool cmCTest::ColoredOutputSupportedByConsole()
+{
+#if defined(_WIN32)
+ // Not supported on Windows
+ return false;
+#else
+ // On UNIX we need a non-dumb tty.
+ std::string clicolor_force;
+ if (cmSystemTools::GetEnv("CLICOLOR_FORCE", clicolor_force) &&
+ !clicolor_force.empty() && clicolor_force != "0") {
+ return true;
+ }
+ return ConsoleIsNotDumb();
+#endif
+}
+
+// handle the -S -SR and -SP arguments
+void cmCTest::HandleScriptArguments(size_t& i, std::vector<std::string>& args,
+ bool& SRArgumentSpecified)
+{
+ std::string arg = args[i];
+ if (this->CheckArgument(arg, "-SP"_s, "--script-new-process") &&
+ i < args.size() - 1) {
+ this->Impl->RunConfigurationScript = true;
+ i++;
+ cmCTestScriptHandler* ch = this->GetScriptHandler();
+ // -SR is an internal argument, -SP should be ignored when it is passed
+ if (!SRArgumentSpecified) {
+ ch->AddConfigurationScript(args[i], false);
+ }
+ }
+
+ if (this->CheckArgument(arg, "-SR"_s, "--script-run") &&
+ i < args.size() - 1) {
+ SRArgumentSpecified = true;
+ this->Impl->RunConfigurationScript = true;
+ i++;
+ cmCTestScriptHandler* ch = this->GetScriptHandler();
+ ch->AddConfigurationScript(args[i], true);
+ }
+
+ if (this->CheckArgument(arg, "-S"_s, "--script") && i < args.size() - 1) {
+ this->Impl->RunConfigurationScript = true;
+ i++;
+ cmCTestScriptHandler* ch = this->GetScriptHandler();
+ // -SR is an internal argument, -S should be ignored when it is passed
+ if (!SRArgumentSpecified) {
+ ch->AddConfigurationScript(args[i], true);
+ }
+ }
+}
+
+bool cmCTest::AddVariableDefinition(const std::string& arg)
+{
+ std::string name;
+ std::string value;
+ cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
+
+ if (cmake::ParseCacheEntry(arg, name, value, type)) {
+ this->Impl->Definitions[name] = value;
+ return true;
+ }
+
+ return false;
+}
+
+void cmCTest::SetPersistentOptionIfNotEmpty(const std::string& value,
+ const std::string& optionName)
+{
+ if (!value.empty()) {
+ this->GetTestHandler()->SetPersistentOption(optionName, value.c_str());
+ this->GetMemCheckHandler()->SetPersistentOption(optionName, value.c_str());
+ }
+}
+
+void cmCTest::AddPersistentMultiOptionIfNotEmpty(const std::string& value,
+ const std::string& optionName)
+{
+ if (!value.empty()) {
+ this->GetTestHandler()->AddPersistentMultiOption(optionName, value);
+ this->GetMemCheckHandler()->AddPersistentMultiOption(optionName, value);
+ }
+}
+
+bool cmCTest::SetArgsFromPreset(const std::string& presetName,
+ bool listPresets)
+{
+ const auto workingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
+
+ cmCMakePresetsFile settingsFile;
+ auto result = settingsFile.ReadProjectPresets(workingDirectory);
+ if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) {
+ cmSystemTools::Error(cmStrCat("Could not read presets from ",
+ workingDirectory, ": ",
+ cmCMakePresetsFile::ResultToString(result)));
+ return false;
+ }
+
+ if (listPresets) {
+ settingsFile.PrintTestPresetList();
+ return true;
+ }
+
+ auto presetPair = settingsFile.TestPresets.find(presetName);
+ if (presetPair == settingsFile.TestPresets.end()) {
+ cmSystemTools::Error(cmStrCat("No such test preset in ", workingDirectory,
+ ": \"", presetName, '"'));
+ settingsFile.PrintTestPresetList();
+ return false;
+ }
+
+ if (presetPair->second.Unexpanded.Hidden) {
+ cmSystemTools::Error(cmStrCat("Cannot use hidden test preset in ",
+ workingDirectory, ": \"", presetName, '"'));
+ settingsFile.PrintTestPresetList();
+ return false;
+ }
+
+ auto const& expandedPreset = presetPair->second.Expanded;
+ if (!expandedPreset) {
+ cmSystemTools::Error(cmStrCat("Could not evaluate test preset \"",
+ presetName, "\": Invalid macro expansion"));
+ settingsFile.PrintTestPresetList();
+ return false;
+ }
+
+ if (!expandedPreset->ConditionResult) {
+ cmSystemTools::Error(cmStrCat("Cannot use disabled test preset in ",
+ workingDirectory, ": \"", presetName, '"'));
+ settingsFile.PrintTestPresetList();
+ return false;
+ }
+
+ auto configurePresetPair =
+ settingsFile.ConfigurePresets.find(expandedPreset->ConfigurePreset);
+ if (configurePresetPair == settingsFile.ConfigurePresets.end()) {
+ cmSystemTools::Error(cmStrCat("No such configure preset in ",
+ workingDirectory, ": \"",
+ expandedPreset->ConfigurePreset, '"'));
+ settingsFile.PrintConfigurePresetList();
+ return false;
+ }
+
+ if (configurePresetPair->second.Unexpanded.Hidden) {
+ cmSystemTools::Error(cmStrCat("Cannot use hidden configure preset in ",
+ workingDirectory, ": \"",
+ expandedPreset->ConfigurePreset, '"'));
+ settingsFile.PrintConfigurePresetList();
+ return false;
+ }
+
+ auto const& expandedConfigurePreset = configurePresetPair->second.Expanded;
+ if (!expandedConfigurePreset) {
+ cmSystemTools::Error(cmStrCat("Could not evaluate configure preset \"",
+ expandedPreset->ConfigurePreset,
+ "\": Invalid macro expansion"));
+ return false;
+ }
+
+ auto presetEnvironment = expandedPreset->Environment;
+ for (auto const& var : presetEnvironment) {
+ if (var.second) {
+ cmSystemTools::PutEnv(cmStrCat(var.first, '=', *var.second));
+ }
+ }
+
+ if (!expandedPreset->Configuration.empty()) {
+ this->SetConfigType(expandedPreset->Configuration);
+ }
+
+ // Set build directory to value specified by the configure preset.
+ this->AddCTestConfigurationOverwrite(
+ cmStrCat("BuildDirectory=", expandedConfigurePreset->BinaryDir));
+ for (const auto& kvp : expandedPreset->OverwriteConfigurationFile) {
+ this->AddCTestConfigurationOverwrite(kvp);
+ }
+
+ if (expandedPreset->Output) {
+ this->Impl->TestProgressOutput =
+ expandedPreset->Output->ShortProgress.value_or(false);
+
+ if (expandedPreset->Output->Verbosity) {
+ const auto& verbosity = *expandedPreset->Output->Verbosity;
+ switch (verbosity) {
+ case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum::
+ Extra:
+ this->Impl->ExtraVerbose = true;
+ // intentional fallthrough
+ case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum::
+ Verbose:
+ this->Impl->Verbose = true;
+ break;
+ case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum::
+ Default:
+ default:
+ // leave default settings
+ break;
+ }
+ }
+
+ this->Impl->Debug = expandedPreset->Output->Debug.value_or(false);
+ this->Impl->ShowLineNumbers =
+ expandedPreset->Output->Debug.value_or(false);
+ this->Impl->OutputTestOutputOnTestFailure =
+ expandedPreset->Output->OutputOnFailure.value_or(false);
+ this->Impl->Quiet = expandedPreset->Output->Quiet.value_or(false);
+
+ if (!expandedPreset->Output->OutputLogFile.empty()) {
+ this->SetOutputLogFileName(expandedPreset->Output->OutputLogFile);
+ }
+
+ this->Impl->LabelSummary =
+ expandedPreset->Output->LabelSummary.value_or(true);
+ this->Impl->SubprojectSummary =
+ expandedPreset->Output->SubprojectSummary.value_or(true);
+
+ if (expandedPreset->Output->MaxPassedTestOutputSize) {
+ this->Impl->TestHandler.SetTestOutputSizePassed(
+ *expandedPreset->Output->MaxPassedTestOutputSize);
+ }
+
+ if (expandedPreset->Output->MaxFailedTestOutputSize) {
+ this->Impl->TestHandler.SetTestOutputSizeFailed(
+ *expandedPreset->Output->MaxFailedTestOutputSize);
+ }
+
+ if (expandedPreset->Output->MaxTestNameWidth) {
+ this->Impl->MaxTestNameWidth = *expandedPreset->Output->MaxTestNameWidth;
+ }
+ }
+
+ if (expandedPreset->Filter) {
+ if (expandedPreset->Filter->Include) {
+ this->SetPersistentOptionIfNotEmpty(
+ expandedPreset->Filter->Include->Name, "IncludeRegularExpression");
+ this->AddPersistentMultiOptionIfNotEmpty(
+ expandedPreset->Filter->Include->Label, "LabelRegularExpression");
+
+ if (expandedPreset->Filter->Include->Index) {
+ if (expandedPreset->Filter->Include->Index->IndexFile.empty()) {
+ const auto& start = expandedPreset->Filter->Include->Index->Start;
+ const auto& end = expandedPreset->Filter->Include->Index->End;
+ const auto& stride = expandedPreset->Filter->Include->Index->Stride;
+ std::string indexOptions;
+ indexOptions += (start ? std::to_string(*start) : "") + ",";
+ indexOptions += (end ? std::to_string(*end) : "") + ",";
+ indexOptions += (stride ? std::to_string(*stride) : "") + ",";
+ indexOptions +=
+ cmJoin(expandedPreset->Filter->Include->Index->SpecificTests, ",");
+
+ this->SetPersistentOptionIfNotEmpty(indexOptions,
+ "TestsToRunInformation");
+ } else {
+ this->SetPersistentOptionIfNotEmpty(
+ expandedPreset->Filter->Include->Index->IndexFile,
+ "TestsToRunInformation");
+ }
+ }
+
+ if (expandedPreset->Filter->Include->UseUnion.value_or(false)) {
+ this->GetTestHandler()->SetPersistentOption("UseUnion", "true");
+ this->GetMemCheckHandler()->SetPersistentOption("UseUnion", "true");
+ }
+ }
+
+ if (expandedPreset->Filter->Exclude) {
+ this->SetPersistentOptionIfNotEmpty(
+ expandedPreset->Filter->Exclude->Name, "ExcludeRegularExpression");
+ this->AddPersistentMultiOptionIfNotEmpty(
+ expandedPreset->Filter->Exclude->Label,
+ "ExcludeLabelRegularExpression");
+
+ if (expandedPreset->Filter->Exclude->Fixtures) {
+ this->SetPersistentOptionIfNotEmpty(
+ expandedPreset->Filter->Exclude->Fixtures->Any,
+ "ExcludeFixtureRegularExpression");
+ this->SetPersistentOptionIfNotEmpty(
+ expandedPreset->Filter->Exclude->Fixtures->Setup,
+ "ExcludeFixtureSetupRegularExpression");
+ this->SetPersistentOptionIfNotEmpty(
+ expandedPreset->Filter->Exclude->Fixtures->Cleanup,
+ "ExcludeFixtureCleanupRegularExpression");
+ }
+ }
+ }
+
+ if (expandedPreset->Execution) {
+ this->Impl->StopOnFailure =
+ expandedPreset->Execution->StopOnFailure.value_or(false);
+ this->Impl->Failover =
+ expandedPreset->Execution->EnableFailover.value_or(false);
+
+ if (expandedPreset->Execution->Jobs) {
+ auto jobs = *expandedPreset->Execution->Jobs;
+ this->SetParallelLevel(jobs);
+ this->Impl->ParallelLevelSetInCli = true;
+ }
+
+ this->SetPersistentOptionIfNotEmpty(
+ expandedPreset->Execution->ResourceSpecFile, "ResourceSpecFile");
+
+ if (expandedPreset->Execution->TestLoad) {
+ auto testLoad = *expandedPreset->Execution->TestLoad;
+ this->SetTestLoad(testLoad);
+ }
+
+ if (expandedPreset->Execution->ShowOnly) {
+ this->Impl->ShowOnly = true;
+
+ switch (*expandedPreset->Execution->ShowOnly) {
+ case cmCMakePresetsFile::TestPreset::ExecutionOptions::ShowOnlyEnum::
+ JsonV1:
+ this->Impl->Quiet = true;
+ this->Impl->OutputAsJson = true;
+ this->Impl->OutputAsJsonVersion = 1;
+ break;
+ case cmCMakePresetsFile::TestPreset::ExecutionOptions::ShowOnlyEnum::
+ Human:
+ // intentional fallthrough (human is the default)
+ default:
+ break;
+ }
+ }
+
+ if (expandedPreset->Execution->Repeat) {
+ this->Impl->RepeatCount = expandedPreset->Execution->Repeat->Count;
+ switch (expandedPreset->Execution->Repeat->Mode) {
+ case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions::
+ ModeEnum::UntilFail:
+ this->Impl->RepeatMode = cmCTest::Repeat::UntilFail;
+ break;
+ case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions::
+ ModeEnum::UntilPass:
+ this->Impl->RepeatMode = cmCTest::Repeat::UntilPass;
+ break;
+ case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions::
+ ModeEnum::AfterTimeout:
+ this->Impl->RepeatMode = cmCTest::Repeat::AfterTimeout;
+ break;
+ default:
+ // should never default since mode is required
+ return false;
+ }
+ }
+
+ if (expandedPreset->Execution->InteractiveDebugging) {
+ this->Impl->InteractiveDebugMode =
+ *expandedPreset->Execution->InteractiveDebugging;
+ }
+
+ if (expandedPreset->Execution->ScheduleRandom.value_or(false)) {
+ this->Impl->ScheduleType = "Random";
+ }
+
+ if (expandedPreset->Execution->Timeout) {
+ this->Impl->GlobalTimeout =
+ cmDuration(*expandedPreset->Execution->Timeout);
+ }
+
+ if (expandedPreset->Execution->NoTestsAction) {
+ switch (*expandedPreset->Execution->NoTestsAction) {
+ case cmCMakePresetsFile::TestPreset::ExecutionOptions::
+ NoTestsActionEnum::Error:
+ this->Impl->NoTestsMode = cmCTest::NoTests::Error;
+ break;
+ case cmCMakePresetsFile::TestPreset::ExecutionOptions::
+ NoTestsActionEnum::Ignore:
+ this->Impl->NoTestsMode = cmCTest::NoTests::Ignore;
+ break;
+ case cmCMakePresetsFile::TestPreset::ExecutionOptions::
+ NoTestsActionEnum::Default:
+ break;
+ default:
+ // should never default
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+// the main entry point of ctest, called from main
+int cmCTest::Run(std::vector<std::string>& args, std::string* output)
+{
+ const char* ctestExec = "ctest";
+ bool cmakeAndTest = false;
+ bool executeTests = true;
+ bool SRArgumentSpecified = false;
+
+ // copy the command line
+ cm::append(this->Impl->InitialCommandLineArguments, args);
+
+ // check if a test preset was specified
+
+ bool listPresets =
+ find(args.begin(), args.end(), "--list-presets") != args.end();
+ auto it =
+ std::find_if(args.begin(), args.end(), [](std::string const& arg) -> bool {
+ return arg == "--preset" || cmHasLiteralPrefix(arg, "--preset=");
+ });
+ if (listPresets || it != args.end()) {
+ std::string errormsg;
+ bool success;
+
+ if (listPresets) {
+ // If listing presets we don't need a presetName
+ success = this->SetArgsFromPreset("", listPresets);
+ } else {
+ if (cmHasLiteralPrefix(*it, "--preset=")) {
+ auto presetName = it->substr(9);
+ success = this->SetArgsFromPreset(presetName, listPresets);
+ } else if (++it != args.end()) {
+ auto presetName = *it;
+ success = this->SetArgsFromPreset(presetName, listPresets);
+ } else {
+ cmSystemTools::Error("'--preset' requires an argument");
+ success = false;
+ }
+ }
+
+ if (listPresets) {
+ return success ? 0 : 1;
+ }
+
+ if (!success) {
+ return 1;
+ }
+ }
+
+ // process the command line arguments
+ for (size_t i = 1; i < args.size(); ++i) {
+ // handle the simple commandline arguments
+ std::string errormsg;
+ if (!this->HandleCommandLineArguments(i, args, errormsg)) {
+ cmSystemTools::Error(errormsg);
+ return 1;
+ }
+
+ // handle the script arguments -S -SR -SP
+ this->HandleScriptArguments(i, args, SRArgumentSpecified);
+
+ // --dashboard: handle a request for a dashboard
+ std::string arg = args[i];
+ if (this->CheckArgument(arg, "-D"_s, "--dashboard") &&
+ i < args.size() - 1) {
+ this->Impl->ProduceXML = true;
+ i++;
+ std::string targ = args[i];
+ // AddTestsForDashboard parses the dashboard type and converts it
+ // into the separate stages
+ if (!this->AddTestsForDashboardType(targ)) {
+ if (!this->AddVariableDefinition(targ)) {
+ this->ErrorMessageUnknownDashDValue(targ);
+ executeTests = false;
+ }
+ }
+ }
+
+ // If it's not exactly -D, but it starts with -D, then try to parse out
+ // a variable definition from it, same as CMake does. Unsuccessful
+ // attempts are simply ignored since previous ctest versions ignore
+ // this too. (As well as many other unknown command line args.)
+ //
+ if (arg != "-D" && cmHasLiteralPrefix(arg, "-D")) {
+ std::string input = arg.substr(2);
+ this->AddVariableDefinition(input);
+ }
+
+ // --test-action: calls SetTest(<stage>, /*report=*/ false) to enable
+ // the corresponding stage
+ if (!this->HandleTestActionArgument(ctestExec, i, args)) {
+ executeTests = false;
+ }
+
+ // --test-model: what type of test model
+ if (!this->HandleTestModelArgument(ctestExec, i, args)) {
+ executeTests = false;
+ }
+
+ // --extra-submit
+ if (this->CheckArgument(arg, "--extra-submit"_s) && i < args.size() - 1) {
+ this->Impl->ProduceXML = true;
+ this->SetTest("Submit");
+ i++;
+ if (!this->SubmitExtraFiles(args[i])) {
+ return 0;
+ }
+ }
+
+ // --build-and-test options
+ if (this->CheckArgument(arg, "--build-and-test"_s) &&
+ i < args.size() - 1) {
+ cmakeAndTest = true;
+ }
+
+ // --schedule-random
+ if (this->CheckArgument(arg, "--schedule-random"_s)) {
+ this->Impl->ScheduleType = "Random";
+ }
+
+ // pass the argument to all the handlers as well, but it may no longer be
+ // set to what it was originally so I'm not sure this is working as
+ // intended
+ for (auto& handler : this->Impl->GetTestingHandlers()) {
+ if (!handler->ProcessCommandLineArguments(arg, i, args)) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Problem parsing command line arguments within a handler");
+ return 0;
+ }
+ }
+ } // the close of the for argument loop
+
+ // handle CTEST_PARALLEL_LEVEL environment variable
+ if (!this->Impl->ParallelLevelSetInCli) {
+ std::string parallel;
+ if (cmSystemTools::GetEnv("CTEST_PARALLEL_LEVEL", parallel)) {
+ int plevel = atoi(parallel.c_str());
+ this->SetParallelLevel(plevel);
+ }
+ }
+
+ // TestProgressOutput only supported if console supports it and not logging
+ // to a file
+ this->Impl->TestProgressOutput = this->Impl->TestProgressOutput &&
+ !this->Impl->OutputLogFile && this->ProgressOutputSupportedByConsole();
+#ifdef _WIN32
+ if (this->Impl->TestProgressOutput) {
+ // Disable output line buffering so we can print content without
+ // a newline.
+ std::setvbuf(stdout, nullptr, _IONBF, 0);
+ }
+#endif
+
+ // now what should cmake do? if --build-and-test was specified then
+ // we run the build and test handler and return
+ if (cmakeAndTest) {
+ return this->RunCMakeAndTest(output);
+ }
+
+ if (executeTests) {
+ return this->ExecuteTests();
+ }
+
+ return 1;
+}
+
+bool cmCTest::HandleTestActionArgument(const char* ctestExec, size_t& i,
+ const std::vector<std::string>& args)
+{
+ bool success = true;
+ std::string arg = args[i];
+ if (this->CheckArgument(arg, "-T"_s, "--test-action") &&
+ (i < args.size() - 1)) {
+ this->Impl->ProduceXML = true;
+ i++;
+ if (!this->SetTest(args[i], false)) {
+ success = false;
+ cmCTestLog(this, ERROR_MESSAGE,
+ "CTest -T called with incorrect option: " << args[i]
+ << std::endl);
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Available options are:"
+ << std::endl
+ << " " << ctestExec << " -T all" << std::endl
+ << " " << ctestExec << " -T start" << std::endl
+ << " " << ctestExec << " -T update" << std::endl
+ << " " << ctestExec << " -T configure" << std::endl
+ << " " << ctestExec << " -T build" << std::endl
+ << " " << ctestExec << " -T test" << std::endl
+ << " " << ctestExec << " -T coverage" << std::endl
+ << " " << ctestExec << " -T memcheck" << std::endl
+ << " " << ctestExec << " -T notes" << std::endl
+ << " " << ctestExec << " -T submit" << std::endl);
+ }
+ }
+ return success;
+}
+
+bool cmCTest::HandleTestModelArgument(const char* ctestExec, size_t& i,
+ const std::vector<std::string>& args)
+{
+ bool success = true;
+ std::string arg = args[i];
+ if (this->CheckArgument(arg, "-M"_s, "--test-model") &&
+ (i < args.size() - 1)) {
+ i++;
+ std::string const& str = args[i];
+ if (cmSystemTools::LowerCase(str) == "nightly"_s) {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ } else if (cmSystemTools::LowerCase(str) == "continuous"_s) {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ } else if (cmSystemTools::LowerCase(str) == "experimental"_s) {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ } else {
+ success = false;
+ cmCTestLog(this, ERROR_MESSAGE,
+ "CTest -M called with incorrect option: " << str
+ << std::endl);
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Available options are:"
+ << std::endl
+ << " " << ctestExec << " -M Continuous" << std::endl
+ << " " << ctestExec << " -M Experimental" << std::endl
+ << " " << ctestExec << " -M Nightly" << std::endl);
+ }
+ }
+ return success;
+}
+
+int cmCTest::ExecuteTests()
+{
+ int res;
+ // call process directory
+ if (this->Impl->RunConfigurationScript) {
+ if (this->Impl->ExtraVerbose) {
+ cmCTestLog(this, OUTPUT, "* Extra verbosity turned on" << std::endl);
+ }
+ for (auto& handler : this->Impl->GetTestingHandlers()) {
+ handler->SetVerbose(this->Impl->ExtraVerbose);
+ handler->SetSubmitIndex(this->Impl->SubmitIndex);
+ }
+ this->GetScriptHandler()->SetVerbose(this->Impl->Verbose);
+ res = this->GetScriptHandler()->ProcessHandler();
+ if (res != 0) {
+ cmCTestLog(this, DEBUG,
+ "running script failing returning: " << res << std::endl);
+ }
+
+ } else {
+ // What is this? -V seems to be the same as -VV,
+ // and Verbose is always on in this case
+ this->Impl->ExtraVerbose = this->Impl->Verbose;
+ this->Impl->Verbose = true;
+ for (auto& handler : this->Impl->GetTestingHandlers()) {
+ handler->SetVerbose(this->Impl->Verbose);
+ handler->SetSubmitIndex(this->Impl->SubmitIndex);
+ }
+
+ const std::string currDir = cmSystemTools::GetCurrentWorkingDirectory();
+ std::string workDir = currDir;
+ if (!this->Impl->TestDir.empty()) {
+ workDir = cmSystemTools::CollapseFullPath(this->Impl->TestDir);
+ }
+
+ if (currDir != workDir) {
+ cmCTestLog(this, OUTPUT,
+ "Internal ctest changing into directory: " << workDir
+ << std::endl);
+ if (cmSystemTools::ChangeDirectory(workDir) != 0) {
+ auto msg = "Failed to change working directory to \"" + workDir +
+ "\" : " + std::strerror(errno) + "\n";
+ cmCTestLog(this, ERROR_MESSAGE, msg);
+ return 1;
+ }
+ }
+
+ if (!this->Initialize(workDir.c_str(), nullptr)) {
+ res = 12;
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Problem initializing the dashboard." << std::endl);
+ } else {
+ res = this->ProcessSteps();
+ }
+ this->Finalize();
+
+ if (currDir != workDir) {
+ cmSystemTools::ChangeDirectory(currDir);
+ }
+ }
+ if (res != 0) {
+ cmCTestLog(this, DEBUG,
+ "Running a test(s) failed returning : " << res << std::endl);
+ }
+ return res;
+}
+
+int cmCTest::RunCMakeAndTest(std::string* output)
+{
+ this->Impl->Verbose = true;
+ cmCTestBuildAndTestHandler* handler = this->GetBuildAndTestHandler();
+ int retv = handler->ProcessHandler();
+ *output = handler->GetOutput();
+#ifndef CMAKE_BOOTSTRAP
+ cmDynamicLoader::FlushCache();
+#endif
+ if (retv != 0) {
+ cmCTestLog(this, DEBUG,
+ "build and test failing returning: " << retv << std::endl);
+ }
+ return retv;
+}
+
+void cmCTest::SetNotesFiles(const std::string& notes)
+{
+ this->Impl->NotesFiles = notes;
+}
+
+bool cmCTest::GetStopOnFailure() const
+{
+ return this->Impl->StopOnFailure;
+}
+
+void cmCTest::SetStopOnFailure(bool stop)
+{
+ this->Impl->StopOnFailure = stop;
+}
+
+std::chrono::system_clock::time_point cmCTest::GetStopTime() const
+{
+ return this->Impl->StopTime;
+}
+
+void cmCTest::SetStopTime(std::string const& time_str)
+{
+
+ struct tm* lctime;
+ time_t current_time = time(nullptr);
+ lctime = gmtime(&current_time);
+ int gm_hour = lctime->tm_hour;
+ time_t gm_time = mktime(lctime);
+ lctime = localtime(&current_time);
+ int local_hour = lctime->tm_hour;
+
+ int tzone_offset = local_hour - gm_hour;
+ if (gm_time > current_time && gm_hour < local_hour) {
+ // this means gm_time is on the next day
+ tzone_offset -= 24;
+ } else if (gm_time < current_time && gm_hour > local_hour) {
+ // this means gm_time is on the previous day
+ tzone_offset += 24;
+ }
+
+ tzone_offset *= 100;
+ char buf[1024];
+ sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900,
+ lctime->tm_mon + 1, lctime->tm_mday, time_str.c_str(), tzone_offset);
+
+ time_t stop_time = curl_getdate(buf, &current_time);
+ if (stop_time == -1) {
+ this->Impl->StopTime = std::chrono::system_clock::time_point();
+ return;
+ }
+ this->Impl->StopTime = std::chrono::system_clock::from_time_t(stop_time);
+
+ if (stop_time < current_time) {
+ this->Impl->StopTime += std::chrono::hours(24);
+ }
+}
+
+std::string cmCTest::GetScheduleType() const
+{
+ return this->Impl->ScheduleType;
+}
+
+void cmCTest::SetScheduleType(std::string const& type)
+{
+ this->Impl->ScheduleType = type;
+}
+
+int cmCTest::ReadCustomConfigurationFileTree(const std::string& dir,
+ cmMakefile* mf)
+{
+ bool found = false;
+ cmCTestLog(this, DEBUG,
+ "* Read custom CTest configuration directory: " << dir
+ << std::endl);
+
+ std::string fname = cmStrCat(dir, "/CTestCustom.cmake");
+ cmCTestLog(this, DEBUG, "* Check for file: " << fname << std::endl);
+ if (cmSystemTools::FileExists(fname)) {
+ cmCTestLog(this, DEBUG,
+ "* Read custom CTest configuration file: " << fname
+ << std::endl);
+ bool erroroc = cmSystemTools::GetErrorOccuredFlag();
+ cmSystemTools::ResetErrorOccuredFlag();
+
+ if (!mf->ReadListFile(fname) || cmSystemTools::GetErrorOccuredFlag()) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Problem reading custom configuration: " << fname
+ << std::endl);
+ }
+ found = true;
+ if (erroroc) {
+ cmSystemTools::SetErrorOccured();
+ }
+ }
+
+ std::string rexpr = cmStrCat(dir, "/CTestCustom.ctest");
+ cmCTestLog(this, DEBUG, "* Check for file: " << rexpr << std::endl);
+ if (!found && cmSystemTools::FileExists(rexpr)) {
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.FindFiles(rexpr);
+ std::vector<std::string>& files = gl.GetFiles();
+ for (const std::string& file : files) {
+ cmCTestLog(this, DEBUG,
+ "* Read custom CTest configuration file: " << file
+ << std::endl);
+ if (!mf->ReadListFile(file) || cmSystemTools::GetErrorOccuredFlag()) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Problem reading custom configuration: " << file
+ << std::endl);
+ }
+ }
+ found = true;
+ }
+
+ if (found) {
+ for (auto& handler : this->Impl->GetNamedTestingHandlers()) {
+ cmCTestLog(this, DEBUG,
+ "* Read custom CTest configuration vectors for handler: "
+ << handler.first << " (" << handler.second << ")"
+ << std::endl);
+ handler.second->PopulateCustomVectors(mf);
+ }
+ }
+
+ return 1;
+}
+
+void cmCTest::PopulateCustomVector(cmMakefile* mf, const std::string& def,
+ std::vector<std::string>& vec)
+{
+ cmProp dval = mf->GetDefinition(def);
+ if (!dval) {
+ return;
+ }
+ cmCTestLog(this, DEBUG, "PopulateCustomVector: " << def << std::endl);
+
+ vec.clear();
+ cmExpandList(*dval, vec);
+
+ for (std::string const& it : vec) {
+ cmCTestLog(this, DEBUG, " -- " << it << std::endl);
+ }
+}
+
+void cmCTest::PopulateCustomInteger(cmMakefile* mf, const std::string& def,
+ int& val)
+{
+ cmProp dval = mf->GetDefinition(def);
+ if (!dval) {
+ return;
+ }
+ val = atoi(dval->c_str());
+}
+
+std::string cmCTest::GetShortPathToFile(const std::string& cfname)
+{
+ const std::string& sourceDir = cmSystemTools::CollapseFullPath(
+ this->GetCTestConfiguration("SourceDirectory"));
+ const std::string& buildDir = cmSystemTools::CollapseFullPath(
+ this->GetCTestConfiguration("BuildDirectory"));
+ std::string fname = cmSystemTools::CollapseFullPath(cfname);
+
+ // Find relative paths to both directories
+ std::string srcRelpath = cmSystemTools::RelativePath(sourceDir, fname);
+ std::string bldRelpath = cmSystemTools::RelativePath(buildDir, fname);
+
+ // If any contains "." it is not parent directory
+ bool inSrc = srcRelpath.find("..") == std::string::npos;
+ bool inBld = bldRelpath.find("..") == std::string::npos;
+ // TODO: Handle files with .. in their name
+
+ std::string* res = nullptr;
+
+ if (inSrc && inBld) {
+ // If both have relative path with no dots, pick the shorter one
+ if (srcRelpath.size() < bldRelpath.size()) {
+ res = &srcRelpath;
+ } else {
+ res = &bldRelpath;
+ }
+ } else if (inSrc) {
+ res = &srcRelpath;
+ } else if (inBld) {
+ res = &bldRelpath;
+ }
+
+ std::string path;
+
+ if (!res) {
+ path = fname;
+ } else {
+ cmSystemTools::ConvertToUnixSlashes(*res);
+
+ path = "./" + *res;
+ if (path.back() == '/') {
+ path.resize(path.size() - 1);
+ }
+ }
+
+ cmsys::SystemTools::ReplaceString(path, ":", "_");
+ cmsys::SystemTools::ReplaceString(path, " ", "_");
+ return path;
+}
+
+std::string cmCTest::GetCTestConfiguration(const std::string& name)
+{
+ if (this->Impl->CTestConfigurationOverwrites.find(name) !=
+ this->Impl->CTestConfigurationOverwrites.end()) {
+ return this->Impl->CTestConfigurationOverwrites[name];
+ }
+ return this->Impl->CTestConfiguration[name];
+}
+
+void cmCTest::EmptyCTestConfiguration()
+{
+ this->Impl->CTestConfiguration.clear();
+}
+
+void cmCTest::SetCTestConfiguration(const char* name, const std::string& value,
+ bool suppress)
+{
+ cmCTestOptionalLog(this, HANDLER_VERBOSE_OUTPUT,
+ "SetCTestConfiguration:" << name << ":" << value << "\n",
+ suppress);
+
+ if (!name) {
+ return;
+ }
+ if (value.empty()) {
+ this->Impl->CTestConfiguration.erase(name);
+ return;
+ }
+ this->Impl->CTestConfiguration[name] = value;
+}
+
+std::string cmCTest::GetSubmitURL()
+{
+ std::string url = this->GetCTestConfiguration("SubmitURL");
+ if (url.empty()) {
+ std::string method = this->GetCTestConfiguration("DropMethod");
+ std::string user = this->GetCTestConfiguration("DropSiteUser");
+ std::string password = this->GetCTestConfiguration("DropSitePassword");
+ std::string site = this->GetCTestConfiguration("DropSite");
+ std::string location = this->GetCTestConfiguration("DropLocation");
+
+ url = cmStrCat(method.empty() ? "http" : method, "://"_s);
+ if (!user.empty()) {
+ url += user;
+ if (!password.empty()) {
+ url += ':';
+ url += password;
+ }
+ url += '@';
+ }
+ url += site;
+ url += location;
+ }
+ return url;
+}
+
+std::string cmCTest::GetCurrentTag()
+{
+ return this->Impl->CurrentTag;
+}
+
+std::string cmCTest::GetBinaryDir()
+{
+ return this->Impl->BinaryDir;
+}
+
+std::string const& cmCTest::GetConfigType()
+{
+ return this->Impl->ConfigType;
+}
+
+cmDuration cmCTest::GetTimeOut() const
+{
+ return this->Impl->TimeOut;
+}
+
+void cmCTest::SetTimeOut(cmDuration t)
+{
+ this->Impl->TimeOut = t;
+}
+
+cmDuration cmCTest::GetGlobalTimeout() const
+{
+ return this->Impl->GlobalTimeout;
+}
+
+bool cmCTest::GetShowOnly()
+{
+ return this->Impl->ShowOnly;
+}
+
+bool cmCTest::GetOutputAsJson()
+{
+ return this->Impl->OutputAsJson;
+}
+
+int cmCTest::GetOutputAsJsonVersion()
+{
+ return this->Impl->OutputAsJsonVersion;
+}
+
+bool cmCTest::ShouldUseHTTP10() const
+{
+ return this->Impl->UseHTTP10;
+}
+
+bool cmCTest::ShouldPrintLabels() const
+{
+ return this->Impl->PrintLabels;
+}
+
+int cmCTest::GetMaxTestNameWidth() const
+{
+ return this->Impl->MaxTestNameWidth;
+}
+
+void cmCTest::SetMaxTestNameWidth(int w)
+{
+ this->Impl->MaxTestNameWidth = w;
+}
+
+void cmCTest::SetProduceXML(bool v)
+{
+ this->Impl->ProduceXML = v;
+}
+
+bool cmCTest::GetProduceXML()
+{
+ return this->Impl->ProduceXML;
+}
+
+std::vector<std::string>& cmCTest::GetInitialCommandLineArguments()
+{
+ return this->Impl->InitialCommandLineArguments;
+}
+
+const char* cmCTest::GetSpecificGroup()
+{
+ if (this->Impl->SpecificGroup.empty()) {
+ return nullptr;
+ }
+ return this->Impl->SpecificGroup.c_str();
+}
+
+void cmCTest::SetSpecificGroup(const char* group)
+{
+ if (!group) {
+ this->Impl->SpecificGroup.clear();
+ return;
+ }
+ this->Impl->SpecificGroup = group;
+}
+
+void cmCTest::SetFailover(bool failover)
+{
+ this->Impl->Failover = failover;
+}
+
+bool cmCTest::GetFailover() const
+{
+ return this->Impl->Failover;
+}
+
+bool cmCTest::GetTestProgressOutput() const
+{
+ return this->Impl->TestProgressOutput && !GetExtraVerbose();
+}
+
+bool cmCTest::GetVerbose() const
+{
+ return this->Impl->Verbose;
+}
+
+bool cmCTest::GetExtraVerbose() const
+{
+ return this->Impl->ExtraVerbose;
+}
+
+void cmCTest::SetStreams(std::ostream* out, std::ostream* err)
+{
+ this->Impl->StreamOut = out;
+ this->Impl->StreamErr = err;
+}
+
+bool cmCTest::GetLabelSummary() const
+{
+ return this->Impl->LabelSummary;
+}
+
+bool cmCTest::GetSubprojectSummary() const
+{
+ return this->Impl->SubprojectSummary;
+}
+
+bool cmCTest::GetOutputTestOutputOnTestFailure() const
+{
+ return this->Impl->OutputTestOutputOnTestFailure;
+}
+
+const std::map<std::string, std::string>& cmCTest::GetDefinitions() const
+{
+ return this->Impl->Definitions;
+}
+
+int cmCTest::GetRepeatCount() const
+{
+ return this->Impl->RepeatCount;
+}
+
+cmCTest::Repeat cmCTest::GetRepeatMode() const
+{
+ return this->Impl->RepeatMode;
+}
+
+cmCTest::NoTests cmCTest::GetNoTestsMode() const
+{
+ return this->Impl->NoTestsMode;
+}
+
+void cmCTest::SetBuildID(const std::string& id)
+{
+ this->Impl->BuildID = id;
+}
+
+std::string cmCTest::GetBuildID() const
+{
+ return this->Impl->BuildID;
+}
+
+void cmCTest::AddSubmitFile(Part part, const std::string& name)
+{
+ this->Impl->Parts[part].SubmitFiles.emplace_back(name);
+}
+
+std::vector<std::string> const& cmCTest::GetSubmitFiles(Part part) const
+{
+ return this->Impl->Parts[part].SubmitFiles;
+}
+
+void cmCTest::ClearSubmitFiles(Part part)
+{
+ this->Impl->Parts[part].SubmitFiles.clear();
+}
+
+void cmCTest::SetSuppressUpdatingCTestConfiguration(bool val)
+{
+ this->Impl->SuppressUpdatingCTestConfiguration = val;
+}
+
+void cmCTest::AddCTestConfigurationOverwrite(const std::string& overStr)
+{
+ size_t epos = overStr.find('=');
+ if (epos == std::string::npos) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "CTest configuration overwrite specified in the wrong format."
+ << std::endl
+ << "Valid format is: --overwrite key=value" << std::endl
+ << "The specified was: --overwrite " << overStr << std::endl);
+ return;
+ }
+ std::string key = overStr.substr(0, epos);
+ std::string value = overStr.substr(epos + 1);
+ this->Impl->CTestConfigurationOverwrites[key] = value;
+}
+
+void cmCTest::SetConfigType(const std::string& ct)
+{
+ this->Impl->ConfigType = ct;
+ cmSystemTools::ReplaceString(this->Impl->ConfigType, ".\\", "");
+ std::string confTypeEnv = "CMAKE_CONFIG_TYPE=" + this->Impl->ConfigType;
+ cmSystemTools::PutEnv(confTypeEnv);
+}
+
+bool cmCTest::SetCTestConfigurationFromCMakeVariable(
+ cmMakefile* mf, const char* dconfig, const std::string& cmake_var,
+ bool suppress)
+{
+ cmProp ctvar = mf->GetDefinition(cmake_var);
+ if (!ctvar) {
+ return false;
+ }
+ cmCTestOptionalLog(this, HANDLER_VERBOSE_OUTPUT,
+ "SetCTestConfigurationFromCMakeVariable:"
+ << dconfig << ":" << cmake_var << std::endl,
+ suppress);
+ this->SetCTestConfiguration(dconfig, *ctvar, suppress);
+ return true;
+}
+
+bool cmCTest::RunCommand(std::vector<std::string> const& args,
+ std::string* stdOut, std::string* stdErr, int* retVal,
+ const char* dir, cmDuration timeout,
+ Encoding encoding)
+{
+ std::vector<const char*> argv;
+ argv.reserve(args.size() + 1);
+ for (std::string const& a : args) {
+ argv.push_back(a.c_str());
+ }
+ argv.push_back(nullptr);
+
+ stdOut->clear();
+ stdErr->clear();
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, argv.data());
+ cmsysProcess_SetWorkingDirectory(cp, dir);
+ if (cmSystemTools::GetRunCommandHideConsole()) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ }
+ cmsysProcess_SetTimeout(cp, timeout.count());
+ cmsysProcess_Execute(cp);
+
+ std::vector<char> tempOutput;
+ std::vector<char> tempError;
+ char* data;
+ int length;
+ cmProcessOutput processOutput(encoding);
+ std::string strdata;
+ int res;
+ bool done = false;
+ while (!done) {
+ res = cmsysProcess_WaitForData(cp, &data, &length, nullptr);
+ switch (res) {
+ case cmsysProcess_Pipe_STDOUT:
+ cm::append(tempOutput, data, data + length);
+ break;
+ case cmsysProcess_Pipe_STDERR:
+ cm::append(tempError, data, data + length);
+ break;
+ default:
+ done = true;
+ }
+ if ((res == cmsysProcess_Pipe_STDOUT || res == cmsysProcess_Pipe_STDERR) &&
+ this->Impl->ExtraVerbose) {
+ processOutput.DecodeText(data, length, strdata);
+ cmSystemTools::Stdout(strdata);
+ }
+ }
+ if (this->Impl->ExtraVerbose) {
+ processOutput.DecodeText(std::string(), strdata);
+ if (!strdata.empty()) {
+ cmSystemTools::Stdout(strdata);
+ }
+ }
+
+ cmsysProcess_WaitForExit(cp, nullptr);
+ if (!tempOutput.empty()) {
+ processOutput.DecodeText(tempOutput, tempOutput);
+ stdOut->append(tempOutput.data(), tempOutput.size());
+ }
+ if (!tempError.empty()) {
+ processOutput.DecodeText(tempError, tempError);
+ stdErr->append(tempError.data(), tempError.size());
+ }
+
+ bool result = true;
+ if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
+ if (retVal) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ } else {
+ if (cmsysProcess_GetExitValue(cp) != 0) {
+ result = false;
+ }
+ }
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) {
+ const char* exception_str = cmsysProcess_GetExceptionString(cp);
+ cmCTestLog(this, ERROR_MESSAGE, exception_str << std::endl);
+ stdErr->append(exception_str, strlen(exception_str));
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
+ const char* error_str = cmsysProcess_GetErrorString(cp);
+ cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
+ stdErr->append(error_str, strlen(error_str));
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) {
+ const char* error_str = "Process terminated due to timeout\n";
+ cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
+ stdErr->append(error_str, strlen(error_str));
+ result = false;
+ }
+
+ cmsysProcess_Delete(cp);
+ return result;
+}
+
+void cmCTest::SetOutputLogFileName(const std::string& name)
+{
+ if (!name.empty()) {
+ this->Impl->OutputLogFile = cm::make_unique<cmGeneratedFileStream>(name);
+ } else {
+ this->Impl->OutputLogFile.reset();
+ }
+}
+
+static const char* cmCTestStringLogType[] = { "DEBUG",
+ "OUTPUT",
+ "HANDLER_OUTPUT",
+ "HANDLER_PROGRESS_OUTPUT",
+ "HANDLER_TEST_PROGRESS_OUTPUT",
+ "HANDLER_VERBOSE_OUTPUT",
+ "WARNING",
+ "ERROR_MESSAGE",
+ nullptr };
+
+#define cmCTestLogOutputFileLine(stream) \
+ do { \
+ if (this->Impl->ShowLineNumbers) { \
+ (stream) << std::endl << file << ":" << line << " "; \
+ } \
+ } while (false)
+
+void cmCTest::Log(int logType, const char* file, int line, const char* msg,
+ bool suppress)
+{
+ if (!msg || !*msg) {
+ return;
+ }
+ if (suppress && logType != cmCTest::ERROR_MESSAGE) {
+ return;
+ }
+ if (logType == cmCTest::HANDLER_PROGRESS_OUTPUT &&
+ (this->Impl->Debug || this->Impl->ExtraVerbose)) {
+ return;
+ }
+ if (this->Impl->OutputLogFile) {
+ bool display = true;
+ if (logType == cmCTest::DEBUG && !this->Impl->Debug) {
+ display = false;
+ }
+ if (logType == cmCTest::HANDLER_VERBOSE_OUTPUT && !this->Impl->Debug &&
+ !this->Impl->ExtraVerbose) {
+ display = false;
+ }
+ if (display) {
+ cmCTestLogOutputFileLine(*this->Impl->OutputLogFile);
+ if (logType != this->Impl->OutputLogFileLastTag) {
+ *this->Impl->OutputLogFile << "[";
+ if (logType >= OTHER || logType < 0) {
+ *this->Impl->OutputLogFile << "OTHER";
+ } else {
+ *this->Impl->OutputLogFile << cmCTestStringLogType[logType];
+ }
+ *this->Impl->OutputLogFile << "] " << std::endl;
+ }
+ *this->Impl->OutputLogFile << msg << std::flush;
+ if (logType != this->Impl->OutputLogFileLastTag) {
+ *this->Impl->OutputLogFile << std::endl;
+ this->Impl->OutputLogFileLastTag = logType;
+ }
+ }
+ }
+ if (!this->Impl->Quiet) {
+ std::ostream& out = *this->Impl->StreamOut;
+ std::ostream& err = *this->Impl->StreamErr;
+
+ if (logType == HANDLER_TEST_PROGRESS_OUTPUT) {
+ if (this->Impl->TestProgressOutput) {
+ cmCTestLogOutputFileLine(out);
+ if (this->Impl->FlushTestProgressLine) {
+ printf("\r");
+ this->Impl->FlushTestProgressLine = false;
+ out.flush();
+ }
+
+ std::string msg_str{ msg };
+ auto const lineBreakIt = msg_str.find('\n');
+ if (lineBreakIt != std::string::npos) {
+ this->Impl->FlushTestProgressLine = true;
+ msg_str.erase(std::remove(msg_str.begin(), msg_str.end(), '\n'),
+ msg_str.end());
+ }
+
+ out << msg_str;
+#ifndef _WIN32
+ printf("\x1B[K"); // move caret to end
+#endif
+ out.flush();
+ return;
+ }
+ logType = HANDLER_OUTPUT;
+ }
+
+ switch (logType) {
+ case DEBUG:
+ if (this->Impl->Debug) {
+ cmCTestLogOutputFileLine(out);
+ out << msg;
+ out.flush();
+ }
+ break;
+ case OUTPUT:
+ case HANDLER_OUTPUT:
+ if (this->Impl->Debug || this->Impl->Verbose) {
+ cmCTestLogOutputFileLine(out);
+ out << msg;
+ out.flush();
+ }
+ break;
+ case HANDLER_VERBOSE_OUTPUT:
+ if (this->Impl->Debug || this->Impl->ExtraVerbose) {
+ cmCTestLogOutputFileLine(out);
+ out << msg;
+ out.flush();
+ }
+ break;
+ case WARNING:
+ cmCTestLogOutputFileLine(err);
+ err << msg;
+ err.flush();
+ break;
+ case ERROR_MESSAGE:
+ cmCTestLogOutputFileLine(err);
+ err << msg;
+ err.flush();
+ cmSystemTools::SetErrorOccured();
+ break;
+ default:
+ cmCTestLogOutputFileLine(out);
+ out << msg;
+ out.flush();
+ }
+ }
+}
+
+std::string cmCTest::GetColorCode(Color color) const
+{
+ if (this->Impl->OutputColorCode) {
+#if defined(_WIN32)
+ // Not supported on Windows
+ static_cast<void>(color);
+#else
+ return "\033[0;" + std::to_string(static_cast<int>(color)) + "m";
+#endif
+ }
+
+ return "";
+}
+
+cmDuration cmCTest::GetRemainingTimeAllowed()
+{
+ return this->GetScriptHandler()->GetRemainingTimeAllowed();
+}
+
+cmDuration cmCTest::MaxDuration()
+{
+ return cmDuration(1.0e7);
+}
+
+void cmCTest::SetRunCurrentScript(bool value)
+{
+ this->GetScriptHandler()->SetRunCurrentScript(value);
+}
+
+void cmCTest::OutputTestErrors(std::vector<char> const& process_output)
+{
+ std::string test_outputs("\n*** Test Failed:\n");
+ if (!process_output.empty()) {
+ test_outputs.append(process_output.data(), process_output.size());
+ }
+ cmCTestLog(this, HANDLER_OUTPUT, test_outputs << std::endl);
+}
+
+bool cmCTest::CompressString(std::string& str)
+{
+ int ret;
+ z_stream strm;
+
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ ret = deflateInit(&strm, -1); // default compression level
+ if (ret != Z_OK) {
+ return false;
+ }
+
+ unsigned char* in =
+ reinterpret_cast<unsigned char*>(const_cast<char*>(str.c_str()));
+ // zlib makes the guarantee that this is the maximum output size
+ int outSize =
+ static_cast<int>(static_cast<double>(str.size()) * 1.001 + 13.0);
+ std::vector<unsigned char> out(outSize);
+
+ strm.avail_in = static_cast<uInt>(str.size());
+ strm.next_in = in;
+ strm.avail_out = outSize;
+ strm.next_out = &out[0];
+ ret = deflate(&strm, Z_FINISH);
+
+ if (ret != Z_STREAM_END) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Error during gzip compression." << std::endl);
+ return false;
+ }
+
+ (void)deflateEnd(&strm);
+
+ // Now base64 encode the resulting binary string
+ std::vector<unsigned char> base64EncodedBuffer((outSize * 3) / 2);
+
+ size_t rlen =
+ cmsysBase64_Encode(&out[0], strm.total_out, &base64EncodedBuffer[0], 1);
+
+ str.assign(reinterpret_cast<char*>(&base64EncodedBuffer[0]), rlen);
+
+ return true;
+}
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
new file mode 100644
index 0000000..392eb1c
--- /dev/null
+++ b/Source/cmCTest.h
@@ -0,0 +1,580 @@
+/* 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 <chrono>
+#include <ctime>
+#include <map>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmDuration.h"
+#include "cmProcessOutput.h"
+
+class cmCTestBuildHandler;
+class cmCTestBuildAndTestHandler;
+class cmCTestCoverageHandler;
+class cmCTestScriptHandler;
+class cmCTestTestHandler;
+class cmCTestUpdateHandler;
+class cmCTestConfigureHandler;
+class cmCTestMemCheckHandler;
+class cmCTestSubmitHandler;
+class cmCTestUploadHandler;
+class cmCTestStartCommand;
+class cmGeneratedFileStream;
+class cmMakefile;
+class cmXMLWriter;
+
+/** \class cmCTest
+ * \brief Represents a ctest invocation.
+ *
+ * This class represents a ctest invocation. It is the top level class when
+ * running ctest.
+ *
+ */
+class cmCTest
+{
+public:
+ using Encoding = cmProcessOutput::Encoding;
+ /** Enumerate parts of the testing and submission process. */
+ enum Part
+ {
+ PartStart,
+ PartUpdate,
+ PartConfigure,
+ PartBuild,
+ PartTest,
+ PartCoverage,
+ PartMemCheck,
+ PartSubmit,
+ PartNotes,
+ PartExtraFiles,
+ PartUpload,
+ PartDone,
+ PartCount // Update names in constructor when adding a part
+ };
+
+ /** Get a testing part id from its string name. Returns PartCount
+ if the string does not name a valid part. */
+ Part GetPartFromName(const std::string& name);
+
+ /** Process Command line arguments */
+ int Run(std::vector<std::string>&, std::string* output = nullptr);
+
+ /**
+ * Initialize and finalize testing
+ */
+ bool InitializeFromCommand(cmCTestStartCommand* command);
+ void Finalize();
+
+ /**
+ * Process the dashboard client steps.
+ *
+ * Steps are enabled using SetTest()
+ *
+ * The execution of the steps (or #Part) should look like this:
+ *
+ * /code
+ * ctest foo;
+ * foo.Initialize();
+ * // Set some things on foo
+ * foo.ProcessSteps();
+ * foo.Finalize();
+ * /endcode
+ *
+ * \sa Initialize(), Finalize(), Part, PartInfo, SetTest()
+ */
+ int ProcessSteps();
+
+ /**
+ * A utility function that returns the nightly time
+ */
+ struct tm* GetNightlyTime(std::string const& str, bool tomorrowtag);
+
+ /**
+ * Is the tomorrow tag set?
+ */
+ bool GetTomorrowTag() const;
+
+ /**
+ * Try to run tests of the project
+ */
+ int TestDirectory(bool memcheck);
+
+ /** what is the configuration type, e.g. Debug, Release etc. */
+ std::string const& GetConfigType();
+ cmDuration GetTimeOut() const;
+ void SetTimeOut(cmDuration t);
+
+ cmDuration GetGlobalTimeout() const;
+
+ /** how many test to run at the same time */
+ int GetParallelLevel() const;
+ void SetParallelLevel(int);
+
+ unsigned long GetTestLoad() const;
+ void SetTestLoad(unsigned long);
+
+ /**
+ * Check if CTest file exists
+ */
+ bool CTestFileExists(const std::string& filename);
+ bool AddIfExists(Part part, const std::string& file);
+
+ /**
+ * Set the cmake test
+ */
+ bool SetTest(const std::string&, bool report = true);
+
+ /**
+ * Set the cmake test mode (experimental, nightly, continuous).
+ */
+ void SetTestModel(int mode);
+ int GetTestModel() const;
+
+ std::string GetTestModelString();
+ static int GetTestModelFromString(const std::string& str);
+ static std::string CleanString(const std::string& str,
+ std::string::size_type spos = 0);
+ std::string GetCTestConfiguration(const std::string& name);
+ void SetCTestConfiguration(const char* name, const std::string& value,
+ bool suppress = false);
+ void EmptyCTestConfiguration();
+
+ std::string GetSubmitURL();
+
+ /**
+ * constructor and destructor
+ */
+ cmCTest();
+ ~cmCTest();
+
+ cmCTest(const cmCTest&) = delete;
+ cmCTest& operator=(const cmCTest&) = delete;
+
+ /** Set the notes files to be created. */
+ void SetNotesFiles(const std::string& notes);
+
+ void PopulateCustomVector(cmMakefile* mf, const std::string& definition,
+ std::vector<std::string>& vec);
+ void PopulateCustomInteger(cmMakefile* mf, const std::string& def, int& val);
+
+ /** Get the current time as string */
+ std::string CurrentTime();
+
+ /** tar/gzip and then base 64 encode a file */
+ std::string Base64GzipEncodeFile(std::string const& file);
+ /** base64 encode a file */
+ std::string Base64EncodeFile(std::string const& file);
+
+ /**
+ * Return the time remaining that the script is allowed to run in
+ * seconds if the user has set the variable CTEST_TIME_LIMIT. If that has
+ * not been set it returns a very large duration.
+ */
+ cmDuration GetRemainingTimeAllowed();
+
+ static cmDuration MaxDuration();
+
+ /**
+ * Open file in the output directory and set the stream
+ */
+ bool OpenOutputFile(const std::string& path, const std::string& name,
+ cmGeneratedFileStream& stream, bool compress = false);
+
+ /** Should we only show what we would do? */
+ bool GetShowOnly();
+
+ bool GetOutputAsJson();
+
+ int GetOutputAsJsonVersion();
+
+ bool ShouldUseHTTP10() const;
+
+ bool ShouldPrintLabels() const;
+
+ bool ShouldCompressTestOutput();
+ bool CompressString(std::string& str);
+
+ bool GetStopOnFailure() const;
+ void SetStopOnFailure(bool stop);
+
+ std::chrono::system_clock::time_point GetStopTime() const;
+ void SetStopTime(std::string const& time);
+
+ /** Used for parallel ctest job scheduling */
+ std::string GetScheduleType() const;
+ void SetScheduleType(std::string const& type);
+
+ /** The max output width */
+ int GetMaxTestNameWidth() const;
+ void SetMaxTestNameWidth(int w);
+
+ /**
+ * Run a single executable command and put the stdout and stderr
+ * in output.
+ *
+ * If verbose is false, no user-viewable output from the program
+ * being run will be generated.
+ *
+ * If timeout is specified, the command will be terminated after
+ * timeout expires. Timeout is specified in seconds.
+ *
+ * Argument retVal should be a pointer to the location where the
+ * exit code will be stored. If the retVal is not specified and
+ * the program exits with a code other than 0, then the this
+ * function will return false.
+ */
+ bool RunCommand(std::vector<std::string> const& args, std::string* stdOut,
+ std::string* stdErr, int* retVal = nullptr,
+ const char* dir = nullptr,
+ cmDuration timeout = cmDuration::zero(),
+ Encoding encoding = cmProcessOutput::Auto);
+
+ /**
+ * Clean/make safe for xml the given value such that it may be used as
+ * one of the key fields by CDash when computing the buildid.
+ */
+ static std::string SafeBuildIdField(const std::string& value);
+
+ /** Start CTest XML output file */
+ void StartXML(cmXMLWriter& xml, bool append);
+
+ /** End CTest XML output file */
+ void EndXML(cmXMLWriter& xml);
+
+ /**
+ * Run command specialized for make and configure. Returns process status
+ * and retVal is return value or exception.
+ */
+ int RunMakeCommand(const std::string& command, std::string& output,
+ int* retVal, const char* dir, cmDuration timeout,
+ std::ostream& ofs,
+ Encoding encoding = cmProcessOutput::Auto);
+
+ /** Return the current tag */
+ std::string GetCurrentTag();
+
+ /** Get the path to the build tree */
+ std::string GetBinaryDir();
+
+ /**
+ * Get the short path to the file.
+ *
+ * This means if the file is in binary or
+ * source directory, it will become /.../relative/path/to/file
+ */
+ std::string GetShortPathToFile(const std::string& fname);
+
+ enum
+ {
+ UNKNOWN = -1,
+ EXPERIMENTAL = 0,
+ NIGHTLY = 1,
+ CONTINUOUS = 2,
+ };
+
+ /** provide some more detailed info on the return code for ctest */
+ enum
+ {
+ UPDATE_ERRORS = 0x01,
+ CONFIGURE_ERRORS = 0x02,
+ BUILD_ERRORS = 0x04,
+ TEST_ERRORS = 0x08,
+ MEMORY_ERRORS = 0x10,
+ COVERAGE_ERRORS = 0x20,
+ SUBMIT_ERRORS = 0x40
+ };
+
+ /** Are we producing XML */
+ bool GetProduceXML();
+ void SetProduceXML(bool v);
+
+ /**
+ * Run command specialized for tests. Returns process status and retVal is
+ * return value or exception. If environment is non-null, it is used to set
+ * environment variables prior to running the test. After running the test,
+ * environment variables are restored to their previous values.
+ */
+ int RunTest(std::vector<const char*> args, std::string* output, int* retVal,
+ std::ostream* logfile, cmDuration testTimeOut,
+ std::vector<std::string>* environment,
+ Encoding encoding = cmProcessOutput::Auto);
+
+ /**
+ * Get the handler object
+ */
+ cmCTestBuildHandler* GetBuildHandler();
+ cmCTestBuildAndTestHandler* GetBuildAndTestHandler();
+ cmCTestCoverageHandler* GetCoverageHandler();
+ cmCTestScriptHandler* GetScriptHandler();
+ cmCTestTestHandler* GetTestHandler();
+ cmCTestUpdateHandler* GetUpdateHandler();
+ cmCTestConfigureHandler* GetConfigureHandler();
+ cmCTestMemCheckHandler* GetMemCheckHandler();
+ cmCTestSubmitHandler* GetSubmitHandler();
+ cmCTestUploadHandler* GetUploadHandler();
+
+ /**
+ * Set the CTest variable from CMake variable
+ */
+ bool SetCTestConfigurationFromCMakeVariable(cmMakefile* mf,
+ const char* dconfig,
+ const std::string& cmake_var,
+ bool suppress = false);
+
+ /** Decode a URL to the original string. */
+ static std::string DecodeURL(const std::string&);
+
+ /**
+ * Should ctect configuration be updated. When using new style ctest
+ * script, this should be true.
+ */
+ void SetSuppressUpdatingCTestConfiguration(bool val);
+
+ /**
+ * Add overwrite to ctest configuration.
+ *
+ * The format is key=value
+ */
+ void AddCTestConfigurationOverwrite(const std::string& encstr);
+
+ /** Create XML file that contains all the notes specified */
+ int GenerateNotesFile(std::vector<std::string> const& files);
+
+ /** Create XML file to indicate that build is complete */
+ int GenerateDoneFile();
+
+ /** Submit extra files to the server */
+ bool SubmitExtraFiles(const std::string& files);
+ bool SubmitExtraFiles(std::vector<std::string> const& files);
+
+ /** Set the output log file name */
+ void SetOutputLogFileName(const std::string& name);
+
+ /** Set the visual studio or Xcode config type */
+ void SetConfigType(const std::string& ct);
+
+ /** Various log types */
+ enum
+ {
+ DEBUG = 0,
+ OUTPUT,
+ HANDLER_OUTPUT,
+ HANDLER_PROGRESS_OUTPUT,
+ HANDLER_TEST_PROGRESS_OUTPUT,
+ HANDLER_VERBOSE_OUTPUT,
+ WARNING,
+ ERROR_MESSAGE,
+ OTHER
+ };
+
+ /** Add log to the output */
+ void Log(int logType, const char* file, int line, const char* msg,
+ bool suppress = false);
+
+ /** Color values */
+ enum class Color
+ {
+ CLEAR_COLOR = 0,
+ RED = 31,
+ GREEN = 32,
+ YELLOW = 33,
+ BLUE = 34
+ };
+
+ /** Get color code characters for a specific color */
+ std::string GetColorCode(Color color) const;
+
+ /** The Build ID is assigned by CDash */
+ void SetBuildID(const std::string& id);
+ std::string GetBuildID() const;
+
+ /** Add file to be submitted */
+ void AddSubmitFile(Part part, const std::string& name);
+ std::vector<std::string> const& GetSubmitFiles(Part part) const;
+ void ClearSubmitFiles(Part part);
+
+ /**
+ * Read the custom configuration files and apply them to the current ctest
+ */
+ int ReadCustomConfigurationFileTree(const std::string& dir, cmMakefile* mf);
+
+ std::vector<std::string>& GetInitialCommandLineArguments();
+
+ /** Set the group to submit to */
+ void SetSpecificGroup(const char* group);
+ const char* GetSpecificGroup();
+
+ void SetFailover(bool failover);
+ bool GetFailover() const;
+
+ bool GetTestProgressOutput() const;
+
+ bool GetVerbose() const;
+ bool GetExtraVerbose() const;
+
+ /** Direct process output to given streams. */
+ void SetStreams(std::ostream* out, std::ostream* err);
+
+ void AddSiteProperties(cmXMLWriter& xml);
+
+ bool GetLabelSummary() const;
+ bool GetSubprojectSummary() const;
+
+ std::string GetCostDataFile();
+
+ bool GetOutputTestOutputOnTestFailure() const;
+
+ const std::map<std::string, std::string>& GetDefinitions() const;
+
+ /** Return the number of times a test should be run */
+ int GetRepeatCount() const;
+
+ enum class Repeat
+ {
+ Never,
+ UntilFail,
+ UntilPass,
+ AfterTimeout,
+ };
+ Repeat GetRepeatMode() const;
+
+ enum class NoTests
+ {
+ Legacy,
+ Error,
+ Ignore
+ };
+ NoTests GetNoTestsMode() const;
+
+ void GenerateSubprojectsOutput(cmXMLWriter& xml);
+ std::vector<std::string> GetLabelsForSubprojects();
+
+ void SetRunCurrentScript(bool value);
+
+private:
+ void SetPersistentOptionIfNotEmpty(const std::string& value,
+ const std::string& optionName);
+ void AddPersistentMultiOptionIfNotEmpty(const std::string& value,
+ const std::string& optionName);
+
+ int GenerateNotesFile(const std::string& files);
+
+ void BlockTestErrorDiagnostics();
+
+ /**
+ * Initialize a dashboard run in the given build tree. The "command"
+ * argument is non-NULL when running from a command-driven (ctest_start)
+ * dashboard script, and NULL when running from the CTest command
+ * line. Note that a declarative dashboard script does not actually
+ * call this method because it sets CTEST_COMMAND to drive a build
+ * through the ctest command line.
+ */
+ int Initialize(const char* binary_dir, cmCTestStartCommand* command);
+
+ /** parse the option after -D and convert it into the appropriate steps */
+ bool AddTestsForDashboardType(std::string& targ);
+
+ /** read as "emit an error message for an unknown -D value" */
+ void ErrorMessageUnknownDashDValue(std::string& val);
+
+ /** add a variable definition from a command line -D value */
+ bool AddVariableDefinition(const std::string& arg);
+
+ /** set command line arguments read from a test preset */
+ bool SetArgsFromPreset(const std::string& presetName, bool listPresets);
+
+ /** parse and process most common command line arguments */
+ bool HandleCommandLineArguments(size_t& i, std::vector<std::string>& args,
+ std::string& errormsg);
+
+#if !defined(_WIN32)
+ /** returns true iff the console supports progress output */
+ static bool ConsoleIsNotDumb();
+#endif
+
+ /** returns true iff the console supports progress output */
+ static bool ProgressOutputSupportedByConsole();
+
+ /** returns true iff the console supports colored output */
+ static bool ColoredOutputSupportedByConsole();
+
+ /** handle the -S -SP and -SR arguments */
+ void HandleScriptArguments(size_t& i, std::vector<std::string>& args,
+ bool& SRArgumentSpecified);
+
+ /** Reread the configuration file */
+ bool UpdateCTestConfiguration();
+
+ /** Create note from files. */
+ int GenerateCTestNotesOutput(cmXMLWriter& xml,
+ std::vector<std::string> const& files);
+
+ /** Check if the argument is the one specified */
+ static bool CheckArgument(const std::string& arg, cm::string_view varg1,
+ const char* varg2 = nullptr);
+
+ /** Output errors from a test */
+ void OutputTestErrors(std::vector<char> const& process_output);
+
+ /** Handle the --test-action command line argument */
+ bool HandleTestActionArgument(const char* ctestExec, size_t& i,
+ const std::vector<std::string>& args);
+
+ /** Handle the --test-model command line argument */
+ bool HandleTestModelArgument(const char* ctestExec, size_t& i,
+ const std::vector<std::string>& args);
+
+ int RunCMakeAndTest(std::string* output);
+ int ExecuteTests();
+
+ struct Private;
+ std::unique_ptr<Private> Impl;
+};
+
+class cmCTestLogWrite
+{
+public:
+ cmCTestLogWrite(const char* data, size_t length)
+ : Data(data)
+ , Length(length)
+ {
+ }
+
+ const char* Data;
+ size_t Length;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const cmCTestLogWrite& c)
+{
+ if (!c.Length) {
+ return os;
+ }
+ os.write(c.Data, c.Length);
+ os.flush();
+ return os;
+}
+
+#define cmCTestLog(ctSelf, logType, msg) \
+ do { \
+ std::ostringstream cmCTestLog_msg; \
+ cmCTestLog_msg << msg; \
+ (ctSelf)->Log(cmCTest::logType, __FILE__, __LINE__, \
+ cmCTestLog_msg.str().c_str()); \
+ } while (false)
+
+#define cmCTestOptionalLog(ctSelf, logType, msg, suppress) \
+ do { \
+ std::ostringstream cmCTestLog_msg; \
+ cmCTestLog_msg << msg; \
+ (ctSelf)->Log(cmCTest::logType, __FILE__, __LINE__, \
+ cmCTestLog_msg.str().c_str(), suppress); \
+ } while (false)
diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx
new file mode 100644
index 0000000..1a950df
--- /dev/null
+++ b/Source/cmCacheManager.cxx
@@ -0,0 +1,619 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCacheManager.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <cstring>
+#include <sstream>
+#include <string>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+
+#include "cmGeneratedFileStream.h"
+#include "cmMessageType.h"
+#include "cmMessenger.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+
+void cmCacheManager::CleanCMakeFiles(const std::string& path)
+{
+ std::string glob = cmStrCat(path, "/CMakeFiles/*.cmake");
+ cmsys::Glob globIt;
+ globIt.FindFiles(glob);
+ std::vector<std::string> files = globIt.GetFiles();
+ std::for_each(files.begin(), files.end(), cmSystemTools::RemoveFile);
+}
+
+bool cmCacheManager::LoadCache(const std::string& path, bool internal,
+ std::set<std::string>& excludes,
+ std::set<std::string>& includes)
+{
+ std::string cacheFile = cmStrCat(path, "/CMakeCache.txt");
+ // clear the old cache, if we are reading in internal values
+ if (internal) {
+ this->Cache.clear();
+ }
+ if (!cmSystemTools::FileExists(cacheFile)) {
+ this->CleanCMakeFiles(path);
+ return false;
+ }
+
+ cmsys::ifstream fin(cacheFile.c_str());
+ if (!fin) {
+ return false;
+ }
+ const char* realbuffer;
+ std::string buffer;
+ std::string entryKey;
+ unsigned int lineno = 0;
+ while (fin) {
+ // Format is key:type=value
+ std::string helpString;
+ CacheEntry e;
+ cmSystemTools::GetLineFromStream(fin, buffer);
+ lineno++;
+ realbuffer = buffer.c_str();
+ while (*realbuffer != '0' &&
+ (*realbuffer == ' ' || *realbuffer == '\t' || *realbuffer == '\r' ||
+ *realbuffer == '\n')) {
+ if (*realbuffer == '\n') {
+ lineno++;
+ }
+ realbuffer++;
+ }
+ // skip blank lines and comment lines
+ if (realbuffer[0] == '#' || realbuffer[0] == 0) {
+ continue;
+ }
+ while (realbuffer[0] == '/' && realbuffer[1] == '/') {
+ if ((realbuffer[2] == '\\') && (realbuffer[3] == 'n')) {
+ helpString += '\n';
+ helpString += &realbuffer[4];
+ } else {
+ helpString += &realbuffer[2];
+ }
+ cmSystemTools::GetLineFromStream(fin, buffer);
+ lineno++;
+ realbuffer = buffer.c_str();
+ if (!fin) {
+ continue;
+ }
+ }
+ e.SetProperty("HELPSTRING", helpString.c_str());
+ if (cmState::ParseCacheEntry(realbuffer, entryKey, e.Value, e.Type)) {
+ if (excludes.find(entryKey) == excludes.end()) {
+ // Load internal values if internal is set.
+ // If the entry is not internal to the cache being loaded
+ // or if it is in the list of internal entries to be
+ // imported, load it.
+ if (internal || (e.Type != cmStateEnums::INTERNAL) ||
+ (includes.find(entryKey) != includes.end())) {
+ // If we are loading the cache from another project,
+ // make all loaded entries internal so that it is
+ // not visible in the gui
+ if (!internal) {
+ e.Type = cmStateEnums::INTERNAL;
+ helpString = cmStrCat("DO NOT EDIT, ", entryKey,
+ " loaded from external file. "
+ "To change this value edit this file: ",
+ path, "/CMakeCache.txt");
+ e.SetProperty("HELPSTRING", helpString.c_str());
+ }
+ if (!this->ReadPropertyEntry(entryKey, e)) {
+ e.Initialized = true;
+ this->Cache[entryKey] = e;
+ }
+ }
+ }
+ } else {
+ std::ostringstream error;
+ error << "Parse error in cache file " << cacheFile << " on line "
+ << lineno << ". Offending entry: " << realbuffer;
+ cmSystemTools::Error(error.str());
+ }
+ }
+ this->CacheMajorVersion = 0;
+ this->CacheMinorVersion = 0;
+ if (cmProp cmajor =
+ this->GetInitializedCacheValue("CMAKE_CACHE_MAJOR_VERSION")) {
+ unsigned int v = 0;
+ if (sscanf(cmajor->c_str(), "%u", &v) == 1) {
+ this->CacheMajorVersion = v;
+ }
+ if (cmProp cminor =
+ this->GetInitializedCacheValue("CMAKE_CACHE_MINOR_VERSION")) {
+ if (sscanf(cminor->c_str(), "%u", &v) == 1) {
+ this->CacheMinorVersion = v;
+ }
+ }
+ } else {
+ // CMake version not found in the list file.
+ // Set as version 0.0
+ this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION", "0",
+ "Minor version of cmake used to create the "
+ "current loaded cache",
+ cmStateEnums::INTERNAL);
+ this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION", "0",
+ "Major version of cmake used to create the "
+ "current loaded cache",
+ cmStateEnums::INTERNAL);
+ }
+ // check to make sure the cache directory has not
+ // been moved
+ cmProp oldDir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
+ if (internal && oldDir) {
+ std::string currentcwd = path;
+ std::string oldcwd = *oldDir;
+ cmSystemTools::ConvertToUnixSlashes(currentcwd);
+ currentcwd += "/CMakeCache.txt";
+ oldcwd += "/CMakeCache.txt";
+ if (!cmSystemTools::SameFile(oldcwd, currentcwd)) {
+ cmProp dir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
+ std::ostringstream message;
+ message << "The current CMakeCache.txt directory " << currentcwd
+ << " is different than the directory " << (dir ? *dir : "")
+ << " where CMakeCache.txt was created. This may result "
+ "in binaries being created in the wrong place. If you "
+ "are not sure, reedit the CMakeCache.txt";
+ cmSystemTools::Error(message.str());
+ }
+ }
+ this->CacheLoaded = true;
+ return true;
+}
+
+const char* cmCacheManager::PersistentProperties[] = { "ADVANCED", "MODIFIED",
+ "STRINGS" };
+
+bool cmCacheManager::ReadPropertyEntry(const std::string& entryKey,
+ const CacheEntry& e)
+{
+ // All property entries are internal.
+ if (e.Type != cmStateEnums::INTERNAL) {
+ return false;
+ }
+
+ const char* end = entryKey.c_str() + entryKey.size();
+ for (const char* p : cmCacheManager::PersistentProperties) {
+ std::string::size_type plen = strlen(p) + 1;
+ if (entryKey.size() > plen && *(end - plen) == '-' &&
+ strcmp(end - plen + 1, p) == 0) {
+ std::string key = entryKey.substr(0, entryKey.size() - plen);
+ if (auto* entry = this->GetCacheEntry(key)) {
+ // Store this property on its entry.
+ entry->SetProperty(p, e.Value.c_str());
+ } else {
+ // Create an entry and store the property.
+ CacheEntry& ne = this->Cache[key];
+ ne.SetProperty(p, e.Value.c_str());
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void cmCacheManager::WritePropertyEntries(std::ostream& os,
+ const std::string& entryKey,
+ const CacheEntry& e,
+ cmMessenger* messenger) const
+{
+ for (const char* p : cmCacheManager::PersistentProperties) {
+ if (cmProp value = e.GetProperty(p)) {
+ std::string helpstring =
+ cmStrCat(p, " property for variable: ", entryKey);
+ cmCacheManager::OutputHelpString(os, helpstring);
+
+ std::string key = cmStrCat(entryKey, '-', p);
+ cmCacheManager::OutputKey(os, key);
+ os << ":INTERNAL=";
+ cmCacheManager::OutputValue(os, *value);
+ os << '\n';
+ cmCacheManager::OutputNewlineTruncationWarning(os, key, *value,
+ messenger);
+ }
+ }
+}
+
+bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger)
+{
+ std::string cacheFile = cmStrCat(path, "/CMakeCache.txt");
+ cmGeneratedFileStream fout(cacheFile);
+ fout.SetCopyIfDifferent(true);
+ if (!fout) {
+ cmSystemTools::Error("Unable to open cache file for save. " + cacheFile);
+ cmSystemTools::ReportLastSystemError("");
+ return false;
+ }
+ // before writing the cache, update the version numbers
+ // to the
+ this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION",
+ std::to_string(cmVersion::GetMajorVersion()).c_str(),
+ "Major version of cmake used to create the "
+ "current loaded cache",
+ cmStateEnums::INTERNAL);
+ this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION",
+ std::to_string(cmVersion::GetMinorVersion()).c_str(),
+ "Minor version of cmake used to create the "
+ "current loaded cache",
+ cmStateEnums::INTERNAL);
+ this->AddCacheEntry("CMAKE_CACHE_PATCH_VERSION",
+ std::to_string(cmVersion::GetPatchVersion()).c_str(),
+ "Patch version of cmake used to create the "
+ "current loaded cache",
+ cmStateEnums::INTERNAL);
+
+ // Let us store the current working directory so that if somebody
+ // Copies it, he will not be surprised
+ std::string currentcwd = path;
+ if (currentcwd[0] >= 'A' && currentcwd[0] <= 'Z' && currentcwd[1] == ':') {
+ // Cast added to avoid compiler warning. Cast is ok because
+ // value is guaranteed to fit in char by the above if...
+ currentcwd[0] = static_cast<char>(currentcwd[0] - 'A' + 'a');
+ }
+ cmSystemTools::ConvertToUnixSlashes(currentcwd);
+ this->AddCacheEntry("CMAKE_CACHEFILE_DIR", currentcwd.c_str(),
+ "This is the directory where this CMakeCache.txt"
+ " was created",
+ cmStateEnums::INTERNAL);
+
+ /* clang-format off */
+ fout << "# This is the CMakeCache file.\n"
+ "# For build in directory: " << currentcwd << "\n"
+ "# It was generated by CMake: "
+ << cmSystemTools::GetCMakeCommand()
+ << "\n"
+ "# You can edit this file to change values found and used by cmake."
+ "\n"
+ "# If you do not want to change any of the values, simply exit the "
+ "editor.\n"
+ "# If you do want to change a value, simply edit, save, and exit "
+ "the editor.\n"
+ "# The syntax for the file is as follows:\n"
+ "# KEY:TYPE=VALUE\n"
+ "# KEY is the name of a variable in the cache.\n"
+ "# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!."
+ "\n"
+ "# VALUE is the current value for the KEY.\n"
+ "\n"
+ "########################\n"
+ "# EXTERNAL cache entries\n"
+ "########################\n"
+ "\n";
+ /* clang-format on */
+
+ for (auto const& i : this->Cache) {
+ CacheEntry const& ce = i.second;
+ cmStateEnums::CacheEntryType t = ce.Type;
+ if (!ce.Initialized) {
+ /*
+ // This should be added in, but is not for now.
+ cmSystemTools::Error("Cache entry \"" + i.first + "\" is uninitialized");
+ */
+ } else if (t != cmStateEnums::INTERNAL) {
+ // Format is key:type=value
+ if (cmProp help = ce.GetProperty("HELPSTRING")) {
+ cmCacheManager::OutputHelpString(fout, *help);
+ } else {
+ cmCacheManager::OutputHelpString(fout, "Missing description");
+ }
+ cmCacheManager::OutputKey(fout, i.first);
+ fout << ':' << cmState::CacheEntryTypeToString(t) << '=';
+ cmCacheManager::OutputValue(fout, ce.Value);
+ fout << '\n';
+ cmCacheManager::OutputNewlineTruncationWarning(fout, i.first, ce.Value,
+ messenger);
+ fout << '\n';
+ }
+ }
+
+ fout << "\n"
+ "########################\n"
+ "# INTERNAL cache entries\n"
+ "########################\n"
+ "\n";
+
+ for (auto const& i : this->Cache) {
+ if (!i.second.Initialized) {
+ continue;
+ }
+
+ cmStateEnums::CacheEntryType t = i.second.GetType();
+ this->WritePropertyEntries(fout, i.first, i.second, messenger);
+ if (t == cmStateEnums::INTERNAL) {
+ // Format is key:type=value
+ if (cmProp help = i.second.GetProperty("HELPSTRING")) {
+ cmCacheManager::OutputHelpString(fout, *help);
+ }
+ cmCacheManager::OutputKey(fout, i.first);
+ fout << ':' << cmState::CacheEntryTypeToString(t) << '=';
+ cmCacheManager::OutputValue(fout, i.second.GetValue());
+ fout << '\n';
+ cmCacheManager::OutputNewlineTruncationWarning(
+ fout, i.first, i.second.GetValue(), messenger);
+ }
+ }
+ fout << '\n';
+ fout.Close();
+ std::string checkCacheFile = cmStrCat(path, "/CMakeFiles");
+ cmSystemTools::MakeDirectory(checkCacheFile);
+ checkCacheFile += "/cmake.check_cache";
+ cmsys::ofstream checkCache(checkCacheFile.c_str());
+ if (!checkCache) {
+ cmSystemTools::Error("Unable to open check cache file for write. " +
+ checkCacheFile);
+ return false;
+ }
+ checkCache << "# This file is generated by cmake for dependency checking "
+ "of the CMakeCache.txt file\n";
+ return true;
+}
+
+bool cmCacheManager::DeleteCache(const std::string& path)
+{
+ std::string cacheFile = path;
+ cmSystemTools::ConvertToUnixSlashes(cacheFile);
+ std::string cmakeFiles = cacheFile;
+ cacheFile += "/CMakeCache.txt";
+ if (cmSystemTools::FileExists(cacheFile)) {
+ cmSystemTools::RemoveFile(cacheFile);
+ // now remove the files in the CMakeFiles directory
+ // this cleans up language cache files
+ cmakeFiles += "/CMakeFiles";
+ if (cmSystemTools::FileIsDirectory(cmakeFiles)) {
+ cmSystemTools::RemoveADirectory(cmakeFiles);
+ }
+ }
+ return true;
+}
+
+void cmCacheManager::OutputKey(std::ostream& fout, std::string const& key)
+{
+ // support : in key name by double quoting
+ const char* q =
+ (key.find(':') != std::string::npos || cmHasLiteralPrefix(key, "//"))
+ ? "\""
+ : "";
+ fout << q << key << q;
+}
+
+void cmCacheManager::OutputValue(std::ostream& fout, std::string const& value)
+{
+ // look for and truncate newlines
+ std::string::size_type newline = value.find('\n');
+ if (newline != std::string::npos) {
+ std::string truncated = value.substr(0, newline);
+ OutputValueNoNewlines(fout, truncated);
+ } else {
+ OutputValueNoNewlines(fout, value);
+ }
+}
+
+void cmCacheManager::OutputValueNoNewlines(std::ostream& fout,
+ std::string const& value)
+{
+ // if value has trailing space or tab, enclose it in single quotes
+ if (!value.empty() && (value.back() == ' ' || value.back() == '\t')) {
+ fout << '\'' << value << '\'';
+ } else {
+ fout << value;
+ }
+}
+
+void cmCacheManager::OutputHelpString(std::ostream& fout,
+ const std::string& helpString)
+{
+ std::string::size_type end = helpString.size();
+ if (end == 0) {
+ return;
+ }
+ std::string oneLine;
+ std::string::size_type pos = 0;
+ for (std::string::size_type i = 0; i <= end; i++) {
+ if ((i == end) || (helpString[i] == '\n') ||
+ ((i - pos >= 60) && (helpString[i] == ' '))) {
+ fout << "//";
+ if (helpString[pos] == '\n') {
+ pos++;
+ fout << "\\n";
+ }
+ oneLine = helpString.substr(pos, i - pos);
+ fout << oneLine << '\n';
+ pos = i;
+ }
+ }
+}
+
+void cmCacheManager::OutputWarningComment(std::ostream& fout,
+ std::string const& message,
+ bool wrapSpaces)
+{
+ std::string::size_type end = message.size();
+ std::string oneLine;
+ std::string::size_type pos = 0;
+ for (std::string::size_type i = 0; i <= end; i++) {
+ if ((i == end) || (message[i] == '\n') ||
+ ((i - pos >= 60) && (message[i] == ' ') && wrapSpaces)) {
+ fout << "# ";
+ if (message[pos] == '\n') {
+ pos++;
+ fout << "\\n";
+ }
+ oneLine = message.substr(pos, i - pos);
+ fout << oneLine << '\n';
+ pos = i;
+ }
+ }
+}
+
+void cmCacheManager::OutputNewlineTruncationWarning(std::ostream& fout,
+ std::string const& key,
+ std::string const& value,
+ cmMessenger* messenger)
+{
+ if (value.find('\n') != std::string::npos) {
+ if (messenger) {
+ std::string message =
+ cmStrCat("Value of ", key, " contained a newline; truncating");
+ messenger->IssueMessage(MessageType::WARNING, message);
+ }
+
+ std::string comment =
+ cmStrCat("WARNING: Value of ", key,
+ " contained a newline and was truncated. Original value:");
+
+ OutputWarningComment(fout, comment, true);
+ OutputWarningComment(fout, value, false);
+ }
+}
+
+void cmCacheManager::RemoveCacheEntry(const std::string& key)
+{
+ this->Cache.erase(key);
+}
+
+cmCacheManager::CacheEntry* cmCacheManager::GetCacheEntry(
+ const std::string& key)
+{
+ auto i = this->Cache.find(key);
+ if (i != this->Cache.end()) {
+ return &i->second;
+ }
+ return nullptr;
+}
+
+const cmCacheManager::CacheEntry* cmCacheManager::GetCacheEntry(
+ const std::string& key) const
+{
+ auto i = this->Cache.find(key);
+ if (i != this->Cache.end()) {
+ return &i->second;
+ }
+ return nullptr;
+}
+
+cmProp cmCacheManager::GetInitializedCacheValue(const std::string& key) const
+{
+ if (const auto* entry = this->GetCacheEntry(key)) {
+ if (entry->Initialized) {
+ return &entry->GetValue();
+ }
+ }
+ return nullptr;
+}
+
+void cmCacheManager::PrintCache(std::ostream& out) const
+{
+ out << "=================================================\n"
+ "CMakeCache Contents:\n";
+ for (auto const& i : this->Cache) {
+ if (i.second.Type != cmStateEnums::INTERNAL) {
+ out << i.first << " = " << i.second.Value << '\n';
+ }
+ }
+ out << "\n\n"
+ "To change values in the CMakeCache, \n"
+ "edit CMakeCache.txt in your output directory.\n"
+ "=================================================\n";
+}
+
+void cmCacheManager::AddCacheEntry(const std::string& key, const char* value,
+ const char* helpString,
+ cmStateEnums::CacheEntryType type)
+{
+ CacheEntry& e = this->Cache[key];
+ e.SetValue(value);
+ e.Type = type;
+ // make sure we only use unix style paths
+ if (type == cmStateEnums::FILEPATH || type == cmStateEnums::PATH) {
+ if (e.Value.find(';') != std::string::npos) {
+ std::vector<std::string> paths = cmExpandedList(e.Value);
+ const char* sep = "";
+ e.Value = "";
+ for (std::string& i : paths) {
+ cmSystemTools::ConvertToUnixSlashes(i);
+ e.Value += sep;
+ e.Value += i;
+ sep = ";";
+ }
+ } else {
+ cmSystemTools::ConvertToUnixSlashes(e.Value);
+ }
+ }
+ e.SetProperty("HELPSTRING",
+ helpString
+ ? helpString
+ : "(This variable does not exist and should not be used)");
+}
+
+void cmCacheManager::CacheEntry::SetValue(const char* value)
+{
+ if (value) {
+ this->Value = value;
+ this->Initialized = true;
+ } else {
+ this->Value.clear();
+ }
+}
+
+std::vector<std::string> cmCacheManager::CacheEntry::GetPropertyList() const
+{
+ return this->Properties.GetKeys();
+}
+
+cmProp cmCacheManager::CacheEntry::GetProperty(const std::string& prop) const
+{
+ if (prop == "TYPE") {
+ return &cmState::CacheEntryTypeToString(this->Type);
+ }
+ if (prop == "VALUE") {
+ return &this->Value;
+ }
+ return this->Properties.GetPropertyValue(prop);
+}
+
+bool cmCacheManager::CacheEntry::GetPropertyAsBool(
+ const std::string& prop) const
+{
+ return cmIsOn(this->GetProperty(prop));
+}
+
+void cmCacheManager::CacheEntry::SetProperty(const std::string& prop,
+ const char* value)
+{
+ if (prop == "TYPE") {
+ this->Type = cmState::StringToCacheEntryType(value ? value : "STRING");
+ } else if (prop == "VALUE") {
+ this->Value = value ? value : "";
+ } else {
+ this->Properties.SetProperty(prop, value);
+ }
+}
+
+void cmCacheManager::CacheEntry::SetProperty(const std::string& p, bool v)
+{
+ this->SetProperty(p, v ? "ON" : "OFF");
+}
+
+void cmCacheManager::CacheEntry::AppendProperty(const std::string& prop,
+ const std::string& value,
+ bool asString)
+{
+ if (prop == "TYPE") {
+ this->Type =
+ cmState::StringToCacheEntryType(!value.empty() ? value : "STRING");
+ } else if (prop == "VALUE") {
+ if (!value.empty()) {
+ if (!this->Value.empty() && !asString) {
+ this->Value += ";";
+ }
+ this->Value += value;
+ }
+ } else {
+ this->Properties.AppendProperty(prop, value, asString);
+ }
+}
diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h
new file mode 100644
index 0000000..7a9a7dc
--- /dev/null
+++ b/Source/cmCacheManager.h
@@ -0,0 +1,215 @@
+/* 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 <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmProperty.h"
+#include "cmPropertyMap.h"
+#include "cmStateTypes.h"
+
+class cmMessenger;
+
+/** \class cmCacheManager
+ * \brief Control class for cmake's cache
+ *
+ * Load and Save CMake cache files.
+ *
+ */
+class cmCacheManager
+{
+ class CacheEntry
+ {
+ friend class cmCacheManager;
+
+ public:
+ const std::string& GetValue() const { return this->Value; }
+ void SetValue(const char*);
+
+ cmStateEnums::CacheEntryType GetType() const { return this->Type; }
+ void SetType(cmStateEnums::CacheEntryType ty) { this->Type = ty; }
+
+ std::vector<std::string> GetPropertyList() const;
+ cmProp GetProperty(const std::string& property) const;
+ bool GetPropertyAsBool(const std::string& property) const;
+ void SetProperty(const std::string& property, const char* value);
+ void SetProperty(const std::string& property, bool value);
+ void AppendProperty(const std::string& property, const std::string& value,
+ bool asString = false);
+
+ private:
+ std::string Value;
+ cmStateEnums::CacheEntryType Type = cmStateEnums::UNINITIALIZED;
+ cmPropertyMap Properties;
+ bool Initialized = false;
+ };
+
+public:
+ //! Load a cache for given makefile. Loads from path/CMakeCache.txt.
+ bool LoadCache(const std::string& path, bool internal,
+ std::set<std::string>& excludes,
+ std::set<std::string>& includes);
+
+ //! Save cache for given makefile. Saves to output path/CMakeCache.txt
+ bool SaveCache(const std::string& path, cmMessenger* messenger);
+
+ //! Delete the cache given
+ bool DeleteCache(const std::string& path);
+
+ //! Print the cache to a stream
+ void PrintCache(std::ostream&) const;
+
+ //! Get whether or not cache is loaded
+ bool IsCacheLoaded() const { return this->CacheLoaded; }
+
+ //! Get a value from the cache given a key
+ cmProp GetInitializedCacheValue(const std::string& key) const;
+
+ cmProp GetCacheEntryValue(const std::string& key) const
+ {
+ if (const auto* entry = this->GetCacheEntry(key)) {
+ return &entry->GetValue();
+ }
+ return nullptr;
+ }
+
+ void SetCacheEntryValue(std::string const& key, std::string const& value)
+ {
+ if (auto* entry = this->GetCacheEntry(key)) {
+ entry->SetValue(value.c_str());
+ }
+ }
+
+ cmStateEnums::CacheEntryType GetCacheEntryType(std::string const& key) const
+ {
+ if (const auto* entry = this->GetCacheEntry(key)) {
+ return entry->GetType();
+ }
+ return cmStateEnums::UNINITIALIZED;
+ }
+
+ std::vector<std::string> GetCacheEntryPropertyList(
+ std::string const& key) const
+ {
+ if (const auto* entry = this->GetCacheEntry(key)) {
+ return entry->GetPropertyList();
+ }
+ return {};
+ }
+
+ cmProp GetCacheEntryProperty(std::string const& key,
+ std::string const& propName) const
+ {
+ if (const auto* entry = this->GetCacheEntry(key)) {
+ return entry->GetProperty(propName);
+ }
+ return nullptr;
+ }
+
+ bool GetCacheEntryPropertyAsBool(std::string const& key,
+ std::string const& propName) const
+ {
+ if (const auto* entry = this->GetCacheEntry(key)) {
+ return entry->GetPropertyAsBool(propName);
+ }
+ return false;
+ }
+
+ void SetCacheEntryProperty(std::string const& key,
+ std::string const& propName,
+ std::string const& value)
+ {
+ if (auto* entry = this->GetCacheEntry(key)) {
+ entry->SetProperty(propName, value.c_str());
+ }
+ }
+
+ void SetCacheEntryBoolProperty(std::string const& key,
+ std::string const& propName, bool value)
+ {
+ if (auto* entry = this->GetCacheEntry(key)) {
+ entry->SetProperty(propName, value);
+ }
+ }
+
+ void RemoveCacheEntryProperty(std::string const& key,
+ std::string const& propName)
+ {
+ if (auto* entry = this->GetCacheEntry(key)) {
+ entry->SetProperty(propName, nullptr);
+ }
+ }
+
+ void AppendCacheEntryProperty(std::string const& key,
+ std::string const& propName,
+ std::string const& value,
+ bool asString = false)
+ {
+ if (auto* entry = this->GetCacheEntry(key)) {
+ entry->AppendProperty(propName, value, asString);
+ }
+ }
+
+ std::vector<std::string> GetCacheEntryKeys() const
+ {
+ std::vector<std::string> definitions;
+ definitions.reserve(this->Cache.size());
+ for (auto const& i : this->Cache) {
+ definitions.push_back(i.first);
+ }
+ return definitions;
+ }
+
+ /** Get the version of CMake that wrote the cache. */
+ unsigned int GetCacheMajorVersion() const { return this->CacheMajorVersion; }
+ unsigned int GetCacheMinorVersion() const { return this->CacheMinorVersion; }
+
+ //! Add an entry into the cache
+ void AddCacheEntry(const std::string& key, const char* value,
+ const char* helpString,
+ cmStateEnums::CacheEntryType type);
+
+ //! Remove an entry from the cache
+ void RemoveCacheEntry(const std::string& key);
+
+private:
+ //! Get a cache entry object for a key
+ CacheEntry* GetCacheEntry(const std::string& key);
+ const CacheEntry* GetCacheEntry(const std::string& key) const;
+
+ //! Clean out the CMakeFiles directory if no CMakeCache.txt
+ void CleanCMakeFiles(const std::string& path);
+
+ static void OutputHelpString(std::ostream& fout,
+ const std::string& helpString);
+ static void OutputWarningComment(std::ostream& fout,
+ std::string const& message,
+ bool wrapSpaces);
+ static void OutputNewlineTruncationWarning(std::ostream& fout,
+ std::string const& key,
+ std::string const& value,
+ cmMessenger* messenger);
+ static void OutputKey(std::ostream& fout, std::string const& key);
+ static void OutputValue(std::ostream& fout, std::string const& value);
+ static void OutputValueNoNewlines(std::ostream& fout,
+ std::string const& value);
+
+ static const char* PersistentProperties[];
+ bool ReadPropertyEntry(const std::string& key, const CacheEntry& e);
+ void WritePropertyEntries(std::ostream& os, const std::string& entryKey,
+ const CacheEntry& e, cmMessenger* messenger) const;
+
+ std::map<std::string, CacheEntry> Cache;
+ bool CacheLoaded = false;
+
+ // Cache version info
+ unsigned int CacheMajorVersion = 0;
+ unsigned int CacheMinorVersion = 0;
+};
diff --git a/Source/cmCallVisualStudioMacro.cxx b/Source/cmCallVisualStudioMacro.cxx
new file mode 100644
index 0000000..94b6e18
--- /dev/null
+++ b/Source/cmCallVisualStudioMacro.cxx
@@ -0,0 +1,461 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCallVisualStudioMacro.h"
+
+#include <sstream>
+
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+#if defined(_MSC_VER)
+# define HAVE_COMDEF_H
+#endif
+
+// Just for this file:
+//
+static bool LogErrorsAsMessages;
+
+#if defined(HAVE_COMDEF_H)
+
+# include <comdef.h>
+
+// Copied from a correct comdef.h to avoid problems with deficient versions
+// of comdef.h that exist in the wild... Fixes issue #7533.
+//
+# ifdef _NATIVE_WCHAR_T_DEFINED
+# ifdef _DEBUG
+# pragma comment(lib, "comsuppwd.lib")
+# else
+# pragma comment(lib, "comsuppw.lib")
+# endif
+# else
+# ifdef _DEBUG
+# pragma comment(lib, "comsuppd.lib")
+# else
+# pragma comment(lib, "comsupp.lib")
+# endif
+# endif
+
+//! Use ReportHRESULT to make a cmSystemTools::Message after calling
+//! a COM method that may have failed.
+# define ReportHRESULT(hr, context) \
+ if (FAILED(hr)) { \
+ if (LogErrorsAsMessages) { \
+ std::ostringstream _hresult_oss; \
+ _hresult_oss.flags(std::ios::hex); \
+ _hresult_oss << context << " failed HRESULT, hr = 0x" << hr << '\n'; \
+ _hresult_oss.flags(std::ios::dec); \
+ _hresult_oss << __FILE__ << "(" << __LINE__ << ")"; \
+ cmSystemTools::Message(_hresult_oss.str()); \
+ } \
+ }
+
+//! Using the given instance of Visual Studio, call the named macro
+HRESULT InstanceCallMacro(IDispatch* vsIDE, const std::string& macro,
+ const std::string& args)
+{
+ HRESULT hr = E_POINTER;
+
+ _bstr_t macroName(macro.c_str());
+ _bstr_t macroArgs(args.c_str());
+
+ if (0 != vsIDE) {
+ DISPID dispid = (DISPID)-1;
+ wchar_t execute_command[] = L"ExecuteCommand";
+ OLECHAR* name = execute_command;
+
+ hr =
+ vsIDE->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
+ ReportHRESULT(hr, "GetIDsOfNames(ExecuteCommand)");
+
+ if (SUCCEEDED(hr)) {
+ VARIANTARG vargs[2];
+ DISPPARAMS params;
+ VARIANT result;
+ EXCEPINFO excep;
+ UINT arg = (UINT)-1;
+
+ // No VariantInit or VariantClear calls are necessary for
+ // these two vargs. They are both local _bstr_t variables
+ // that remain in scope for the duration of the Invoke call.
+ //
+ V_VT(&vargs[1]) = VT_BSTR;
+ V_BSTR(&vargs[1]) = macroName;
+ V_VT(&vargs[0]) = VT_BSTR;
+ V_BSTR(&vargs[0]) = macroArgs;
+
+ params.rgvarg = &vargs[0];
+ params.rgdispidNamedArgs = 0;
+ params.cArgs = sizeof(vargs) / sizeof(vargs[0]);
+ params.cNamedArgs = 0;
+
+ VariantInit(&result);
+
+ memset(&excep, 0, sizeof(excep));
+
+ hr = vsIDE->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
+ DISPATCH_METHOD, &params, &result, &excep, &arg);
+
+ std::ostringstream oss;
+ /* clang-format off */
+ oss << "\nInvoke(ExecuteCommand)\n"
+ " Macro: " << macro << "\n"
+ " Args: " << args << '\n';
+ /* clang-format on */
+
+ if (DISP_E_EXCEPTION == hr) {
+ /* clang-format off */
+ oss << "DISP_E_EXCEPTION EXCEPINFO:" << excep.wCode << "\n"
+ " wCode: " << excep.wCode << "\n"
+ " wReserved: " << excep.wReserved << '\n';
+ /* clang-format on */
+ if (excep.bstrSource) {
+ oss << " bstrSource: " << (const char*)(_bstr_t)excep.bstrSource
+ << '\n';
+ }
+ if (excep.bstrDescription) {
+ oss << " bstrDescription: "
+ << (const char*)(_bstr_t)excep.bstrDescription << '\n';
+ }
+ if (excep.bstrHelpFile) {
+ oss << " bstrHelpFile: " << (const char*)(_bstr_t)excep.bstrHelpFile
+ << '\n';
+ }
+ /* clang-format off */
+ oss << " dwHelpContext: " << excep.dwHelpContext << "\n"
+ " pvReserved: " << excep.pvReserved << "\n"
+ " pfnDeferredFillIn: "
+ << reinterpret_cast<void*>(excep.pfnDeferredFillIn) << "\n"
+ " scode: " << excep.scode << '\n';
+ /* clang-format on */
+ }
+
+ std::string exstr(oss.str());
+ ReportHRESULT(hr, exstr.c_str());
+
+ VariantClear(&result);
+ }
+ }
+
+ return hr;
+}
+
+//! Get the Solution object from the IDE object
+HRESULT GetSolutionObject(IDispatch* vsIDE, IDispatchPtr& vsSolution)
+{
+ HRESULT hr = E_POINTER;
+
+ if (0 != vsIDE) {
+ DISPID dispid = (DISPID)-1;
+ wchar_t solution[] = L"Solution";
+ OLECHAR* name = solution;
+
+ hr =
+ vsIDE->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
+ ReportHRESULT(hr, "GetIDsOfNames(Solution)");
+
+ if (SUCCEEDED(hr)) {
+ DISPPARAMS params;
+ VARIANT result;
+ EXCEPINFO excep;
+ UINT arg = (UINT)-1;
+
+ params.rgvarg = 0;
+ params.rgdispidNamedArgs = 0;
+ params.cArgs = 0;
+ params.cNamedArgs = 0;
+
+ VariantInit(&result);
+
+ memset(&excep, 0, sizeof(excep));
+
+ hr = vsIDE->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
+ DISPATCH_PROPERTYGET, &params, &result, &excep, &arg);
+ ReportHRESULT(hr, "Invoke(Solution)");
+
+ if (SUCCEEDED(hr)) {
+ vsSolution = V_DISPATCH(&result);
+ }
+
+ VariantClear(&result);
+ }
+ }
+
+ return hr;
+}
+
+//! Get the FullName property from the Solution object
+HRESULT GetSolutionFullName(IDispatch* vsSolution, std::string& fullName)
+{
+ HRESULT hr = E_POINTER;
+
+ if (0 != vsSolution) {
+ DISPID dispid = (DISPID)-1;
+ wchar_t full_name[] = L"FullName";
+ OLECHAR* name = full_name;
+
+ hr = vsSolution->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT,
+ &dispid);
+ ReportHRESULT(hr, "GetIDsOfNames(FullName)");
+
+ if (SUCCEEDED(hr)) {
+ DISPPARAMS params;
+ VARIANT result;
+ EXCEPINFO excep;
+ UINT arg = (UINT)-1;
+
+ params.rgvarg = 0;
+ params.rgdispidNamedArgs = 0;
+ params.cArgs = 0;
+ params.cNamedArgs = 0;
+
+ VariantInit(&result);
+
+ memset(&excep, 0, sizeof(excep));
+
+ hr = vsSolution->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
+ DISPATCH_PROPERTYGET, &params, &result, &excep,
+ &arg);
+ ReportHRESULT(hr, "Invoke(FullName)");
+
+ if (SUCCEEDED(hr)) {
+ fullName = (std::string)(_bstr_t)V_BSTR(&result);
+ }
+
+ VariantClear(&result);
+ }
+ }
+
+ return hr;
+}
+
+//! Get the FullName property from the Solution object, given the IDE object
+HRESULT GetIDESolutionFullName(IDispatch* vsIDE, std::string& fullName)
+{
+ IDispatchPtr vsSolution;
+ HRESULT hr = GetSolutionObject(vsIDE, vsSolution);
+ ReportHRESULT(hr, "GetSolutionObject");
+
+ if (SUCCEEDED(hr)) {
+ GetSolutionFullName(vsSolution, fullName);
+ ReportHRESULT(hr, "GetSolutionFullName");
+ }
+
+ return hr;
+}
+
+//! Get all running objects from the Windows running object table.
+//! Save them in a map by their display names.
+HRESULT GetRunningInstances(std::map<std::string, IUnknownPtr>& mrot)
+{
+ // mrot == Map of the Running Object Table
+
+ IRunningObjectTablePtr runningObjectTable;
+ IEnumMonikerPtr monikerEnumerator;
+ IMonikerPtr moniker;
+ ULONG numFetched = 0;
+
+ HRESULT hr = GetRunningObjectTable(0, &runningObjectTable);
+ ReportHRESULT(hr, "GetRunningObjectTable");
+
+ if (SUCCEEDED(hr)) {
+ hr = runningObjectTable->EnumRunning(&monikerEnumerator);
+ ReportHRESULT(hr, "EnumRunning");
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = monikerEnumerator->Reset();
+ ReportHRESULT(hr, "Reset");
+ }
+
+ if (SUCCEEDED(hr)) {
+ while (S_OK == monikerEnumerator->Next(1, &moniker, &numFetched)) {
+ std::string runningObjectName;
+ IUnknownPtr runningObjectVal;
+ IBindCtxPtr ctx;
+
+ hr = CreateBindCtx(0, &ctx);
+ ReportHRESULT(hr, "CreateBindCtx");
+
+ if (SUCCEEDED(hr)) {
+ LPOLESTR displayName = 0;
+ hr = moniker->GetDisplayName(ctx, 0, &displayName);
+ ReportHRESULT(hr, "GetDisplayName");
+ if (displayName) {
+ runningObjectName = (std::string)(_bstr_t)displayName;
+ CoTaskMemFree(displayName);
+ }
+
+ hr = runningObjectTable->GetObject(moniker, &runningObjectVal);
+ ReportHRESULT(hr, "GetObject");
+ if (SUCCEEDED(hr)) {
+ mrot.insert(std::make_pair(runningObjectName, runningObjectVal));
+ }
+ }
+
+ numFetched = 0;
+ moniker = 0;
+ }
+ }
+
+ return hr;
+}
+
+//! Do the two file names refer to the same Visual Studio solution? Or are
+//! we perhaps looking for any and all solutions?
+bool FilesSameSolution(const std::string& slnFile, const std::string& slnName)
+{
+ if (slnFile == "ALL" || slnName == "ALL") {
+ return true;
+ }
+
+ // Otherwise, make lowercase local copies, convert to Unix slashes, and
+ // see if the resulting strings are the same:
+ std::string s1 = cmSystemTools::LowerCase(slnFile);
+ std::string s2 = cmSystemTools::LowerCase(slnName);
+ cmSystemTools::ConvertToUnixSlashes(s1);
+ cmSystemTools::ConvertToUnixSlashes(s2);
+
+ return s1 == s2;
+}
+
+//! Find instances of Visual Studio with the given solution file
+//! open. Pass "ALL" for slnFile to gather all running instances
+//! of Visual Studio.
+HRESULT FindVisualStudioInstances(const std::string& slnFile,
+ std::vector<IDispatchPtr>& instances)
+{
+ std::map<std::string, IUnknownPtr> mrot;
+
+ HRESULT hr = GetRunningInstances(mrot);
+ ReportHRESULT(hr, "GetRunningInstances");
+
+ if (SUCCEEDED(hr)) {
+ std::map<std::string, IUnknownPtr>::iterator it;
+ for (it = mrot.begin(); it != mrot.end(); ++it) {
+ if (cmHasLiteralPrefix(it->first, "!VisualStudio.DTE.")) {
+ IDispatchPtr disp(it->second);
+ if (disp != (IDispatch*)0) {
+ std::string slnName;
+ hr = GetIDESolutionFullName(disp, slnName);
+ ReportHRESULT(hr, "GetIDESolutionFullName");
+
+ if (FilesSameSolution(slnFile, slnName)) {
+ instances.push_back(disp);
+
+ // std::cout << "Found Visual Studio instance." << std::endl;
+ // std::cout << " ROT entry name: " << it->first << std::endl;
+ // std::cout << " ROT entry object: "
+ // << (IUnknown*) it->second << std::endl;
+ // std::cout << " slnFile: " << slnFile << std::endl;
+ // std::cout << " slnName: " << slnName << std::endl;
+ }
+ }
+ }
+ }
+ }
+
+ return hr;
+}
+
+#endif // defined(HAVE_COMDEF_H)
+
+int cmCallVisualStudioMacro::GetNumberOfRunningVisualStudioInstances(
+ const std::string& slnFile)
+{
+ int count = 0;
+
+ LogErrorsAsMessages = false;
+
+#if defined(HAVE_COMDEF_H)
+ HRESULT hr = CoInitialize(0);
+ ReportHRESULT(hr, "CoInitialize");
+
+ if (SUCCEEDED(hr)) {
+ std::vector<IDispatchPtr> instances;
+ hr = FindVisualStudioInstances(slnFile, instances);
+ ReportHRESULT(hr, "FindVisualStudioInstances");
+
+ if (SUCCEEDED(hr)) {
+ count = static_cast<int>(instances.size());
+ }
+
+ // Force release all COM pointers before CoUninitialize:
+ instances.clear();
+
+ CoUninitialize();
+ }
+#else
+ (void)slnFile;
+#endif
+
+ return count;
+}
+
+//! Get all running objects from the Windows running object table.
+//! Save them in a map by their display names.
+int cmCallVisualStudioMacro::CallMacro(const std::string& slnFile,
+ const std::string& macro,
+ const std::string& args,
+ const bool logErrorsAsMessages)
+{
+ int err = 1; // no comdef.h
+
+ LogErrorsAsMessages = logErrorsAsMessages;
+
+#if defined(HAVE_COMDEF_H)
+ err = 2; // error initializing
+
+ HRESULT hr = CoInitialize(0);
+ ReportHRESULT(hr, "CoInitialize");
+
+ if (SUCCEEDED(hr)) {
+ std::vector<IDispatchPtr> instances;
+ hr = FindVisualStudioInstances(slnFile, instances);
+ ReportHRESULT(hr, "FindVisualStudioInstances");
+
+ if (SUCCEEDED(hr)) {
+ err = 0; // no error
+
+ std::vector<IDispatchPtr>::iterator it;
+ for (it = instances.begin(); it != instances.end(); ++it) {
+ hr = InstanceCallMacro(*it, macro, args);
+ ReportHRESULT(hr, "InstanceCallMacro");
+
+ if (FAILED(hr)) {
+ err = 3; // error attempting to call the macro
+ }
+ }
+
+ if (instances.empty()) {
+ // no instances to call
+
+ // cmSystemTools::Message(
+ // "cmCallVisualStudioMacro::CallMacro no instances found to call",
+ // "Warning");
+ }
+ }
+
+ // Force release all COM pointers before CoUninitialize:
+ instances.clear();
+
+ CoUninitialize();
+ }
+#else
+ (void)slnFile;
+ (void)macro;
+ (void)args;
+ if (LogErrorsAsMessages) {
+ cmSystemTools::Message("cmCallVisualStudioMacro::CallMacro is not "
+ "supported on this platform");
+ }
+#endif
+
+ if (err && LogErrorsAsMessages) {
+ std::ostringstream oss;
+ oss << "cmCallVisualStudioMacro::CallMacro failed, err = " << err;
+ cmSystemTools::Message(oss.str());
+ }
+
+ return 0;
+}
diff --git a/Source/cmCallVisualStudioMacro.h b/Source/cmCallVisualStudioMacro.h
new file mode 100644
index 0000000..795b863
--- /dev/null
+++ b/Source/cmCallVisualStudioMacro.h
@@ -0,0 +1,33 @@
+/* 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 <string>
+
+/** \class cmCallVisualStudioMacro
+ * \brief Control class for communicating with CMake's Visual Studio macros
+ *
+ * Find running instances of Visual Studio by full path solution name.
+ * Call a Visual Studio IDE macro in any of those instances.
+ */
+class cmCallVisualStudioMacro
+{
+public:
+ //! Call the named macro in instances of Visual Studio with the
+ //! given solution file open. Pass "ALL" for slnFile to call the
+ //! macro in each Visual Studio instance.
+ static int CallMacro(const std::string& slnFile, const std::string& macro,
+ const std::string& args,
+ const bool logErrorsAsMessages);
+
+ //! Count the number of running instances of Visual Studio with the
+ //! given solution file open. Pass "ALL" for slnFile to count all
+ //! running Visual Studio instances.
+ static int GetNumberOfRunningVisualStudioInstances(
+ const std::string& slnFile);
+
+protected:
+private:
+};
diff --git a/Source/cmCommand.cxx b/Source/cmCommand.cxx
new file mode 100644
index 0000000..0c2734e
--- /dev/null
+++ b/Source/cmCommand.cxx
@@ -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. */
+#include "cmCommand.h"
+
+#include <utility>
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+
+struct cmListFileArgument;
+
+void cmCommand::SetExecutionStatus(cmExecutionStatus* status)
+{
+ this->Status = status;
+ this->Makefile = &status->GetMakefile();
+}
+
+bool cmCommand::InvokeInitialPass(const std::vector<cmListFileArgument>& args,
+ cmExecutionStatus& status)
+{
+ std::vector<std::string> expandedArguments;
+ if (!this->Makefile->ExpandArguments(args, expandedArguments)) {
+ // There was an error expanding arguments. It was already
+ // reported, so we can skip this command without error.
+ return true;
+ }
+ return this->InitialPass(expandedArguments, status);
+}
+
+void cmCommand::SetError(const std::string& e)
+{
+ this->Status->SetError(e);
+}
+
+cmLegacyCommandWrapper::cmLegacyCommandWrapper(std::unique_ptr<cmCommand> cmd)
+ : Command(std::move(cmd))
+{
+}
+
+cmLegacyCommandWrapper::cmLegacyCommandWrapper(
+ cmLegacyCommandWrapper const& other)
+ : Command(other.Command->Clone())
+{
+}
+
+cmLegacyCommandWrapper& cmLegacyCommandWrapper::operator=(
+ cmLegacyCommandWrapper const& other)
+{
+ this->Command = other.Command->Clone();
+ return *this;
+}
+
+bool cmLegacyCommandWrapper::operator()(
+ std::vector<cmListFileArgument> const& args, cmExecutionStatus& status) const
+{
+ auto cmd = this->Command->Clone();
+ cmd->SetExecutionStatus(&status);
+ return cmd->InvokeInitialPass(args, status);
+}
diff --git a/Source/cmCommand.h b/Source/cmCommand.h
new file mode 100644
index 0000000..68c56d9
--- /dev/null
+++ b/Source/cmCommand.h
@@ -0,0 +1,97 @@
+/* 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 <memory>
+#include <string>
+#include <vector>
+
+class cmExecutionStatus;
+class cmMakefile;
+struct cmListFileArgument;
+
+/** \class cmCommand
+ * \brief Superclass for all commands in CMake.
+ *
+ * cmCommand is the base class for all commands in CMake. A command
+ * manifests as an entry in CMakeLists.txt and produces one or
+ * more makefile rules. Commands are associated with a particular
+ * makefile. This base class cmCommand defines the API for commands
+ * to support such features as enable/disable, inheritance,
+ * documentation, and construction.
+ */
+class cmCommand
+{
+public:
+ /**
+ * Construct the command. By default it has no makefile.
+ */
+ cmCommand() = default;
+
+ /**
+ * Need virtual destructor to destroy real command type.
+ */
+ virtual ~cmCommand() = default;
+
+ cmCommand(cmCommand const&) = delete;
+ cmCommand& operator=(cmCommand const&) = delete;
+
+ /**
+ * Specify the makefile.
+ */
+ cmMakefile* GetMakefile() { return this->Makefile; }
+
+ void SetExecutionStatus(cmExecutionStatus* s);
+ cmExecutionStatus* GetExecutionStatus() { return this->Status; };
+
+ /**
+ * This is called by the cmMakefile when the command is first
+ * encountered in the CMakeLists.txt file. It expands the command's
+ * arguments and then invokes the InitialPass.
+ */
+ bool InvokeInitialPass(const std::vector<cmListFileArgument>& args,
+ cmExecutionStatus& status);
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ virtual bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&) = 0;
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ virtual std::unique_ptr<cmCommand> Clone() = 0;
+
+ /**
+ * Set the error message
+ */
+ void SetError(const std::string& e);
+
+protected:
+ cmMakefile* Makefile = nullptr;
+
+private:
+ cmExecutionStatus* Status = nullptr;
+};
+
+class cmLegacyCommandWrapper
+{
+public:
+ explicit cmLegacyCommandWrapper(std::unique_ptr<cmCommand> cmd);
+
+ cmLegacyCommandWrapper(cmLegacyCommandWrapper const& other);
+ cmLegacyCommandWrapper& operator=(cmLegacyCommandWrapper const& other);
+
+ cmLegacyCommandWrapper(cmLegacyCommandWrapper&&) = default;
+ cmLegacyCommandWrapper& operator=(cmLegacyCommandWrapper&&) = default;
+
+ bool operator()(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status) const;
+
+private:
+ std::unique_ptr<cmCommand> Command;
+};
diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx
new file mode 100644
index 0000000..deddba8
--- /dev/null
+++ b/Source/cmCommandArgumentParserHelper.cxx
@@ -0,0 +1,294 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCommandArgumentParserHelper.h"
+
+#include <cstring>
+#include <iostream>
+#include <sstream>
+#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"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+int cmCommandArgument_yyparse(yyscan_t yyscanner);
+//
+cmCommandArgumentParserHelper::cmCommandArgumentParserHelper()
+{
+ this->FileLine = -1;
+ this->FileName = nullptr;
+ this->RemoveEmpty = true;
+
+ this->NoEscapeMode = false;
+ this->ReplaceAtSyntax = false;
+}
+
+cmCommandArgumentParserHelper::~cmCommandArgumentParserHelper()
+{
+ this->CleanupParser();
+}
+
+void cmCommandArgumentParserHelper::SetLineFile(long line, const char* file)
+{
+ this->FileLine = line;
+ this->FileName = file;
+}
+
+const char* cmCommandArgumentParserHelper::AddString(const std::string& str)
+{
+ if (str.empty()) {
+ return "";
+ }
+ auto stVal = cm::make_unique<char[]>(str.size() + 1);
+ strcpy(stVal.get(), str.c_str());
+ this->Variables.push_back(std::move(stVal));
+ return this->Variables.back().get();
+}
+
+const char* cmCommandArgumentParserHelper::ExpandSpecialVariable(
+ const char* key, const char* var)
+{
+ if (!key) {
+ return this->ExpandVariable(var);
+ }
+ if (!var) {
+ return "";
+ }
+ if (strcmp(key, "ENV") == 0) {
+ std::string str;
+ if (cmSystemTools::GetEnv(var, str)) {
+ if (this->EscapeQuotes) {
+ return this->AddString(cmEscapeQuotes(str));
+ }
+ return this->AddString(str);
+ }
+ return "";
+ }
+ if (strcmp(key, "CACHE") == 0) {
+ if (cmProp c = this->Makefile->GetState()->GetInitializedCacheValue(var)) {
+ if (this->EscapeQuotes) {
+ return this->AddString(cmEscapeQuotes(*c));
+ }
+ return this->AddString(*c);
+ }
+ return "";
+ }
+ std::ostringstream e;
+ e << "Syntax $" << key << "{} is not supported. "
+ << "Only ${}, $ENV{}, and $CACHE{} are allowed.";
+ this->SetError(e.str());
+ return nullptr;
+}
+
+const char* cmCommandArgumentParserHelper::ExpandVariable(const char* var)
+{
+ if (!var) {
+ return nullptr;
+ }
+ if (this->FileLine >= 0 && strcmp(var, "CMAKE_CURRENT_LIST_LINE") == 0) {
+ 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) {
+ this->Makefile->MaybeWarnUninitialized(var, this->FileName);
+ if (!this->RemoveEmpty) {
+ return nullptr;
+ }
+ }
+ if (this->EscapeQuotes && value) {
+ return this->AddString(cmEscapeQuotes(*value));
+ }
+ return this->AddString(cmToCStrSafe(value));
+}
+
+const char* cmCommandArgumentParserHelper::ExpandVariableForAt(const char* var)
+{
+ if (this->ReplaceAtSyntax) {
+ // try to expand the variable
+ const char* ret = this->ExpandVariable(var);
+ // if the return was 0 and we want to replace empty strings
+ // then return an empty string
+ if (!ret && this->RemoveEmpty) {
+ return this->AddString("");
+ }
+ // if the ret was not 0, then return it
+ if (ret) {
+ return ret;
+ }
+ }
+ // at this point we want to put it back because of one of these cases:
+ // - this->ReplaceAtSyntax is false
+ // - this->ReplaceAtSyntax is true, but this->RemoveEmpty is false,
+ // and the variable was not defined
+ std::string ref = cmStrCat('@', var, '@');
+ return this->AddString(ref);
+}
+
+const char* cmCommandArgumentParserHelper::CombineUnions(const char* in1,
+ const char* in2)
+{
+ if (!in1) {
+ return in2;
+ }
+ if (!in2) {
+ return in1;
+ }
+ size_t len = strlen(in1) + strlen(in2) + 1;
+ auto out = cm::make_unique<char[]>(len);
+ strcpy(out.get(), in1);
+ strcat(out.get(), in2);
+ this->Variables.push_back(std::move(out));
+ return this->Variables.back().get();
+}
+
+void cmCommandArgumentParserHelper::AllocateParserType(
+ cmCommandArgumentParserHelper::ParserType* pt, const char* str, int len)
+{
+ pt->str = nullptr;
+ if (len == 0) {
+ len = static_cast<int>(strlen(str));
+ }
+ if (len == 0) {
+ return;
+ }
+ auto out = cm::make_unique<char[]>(len + 1);
+ memcpy(out.get(), str, len);
+ out.get()[len] = 0;
+ pt->str = out.get();
+ this->Variables.push_back(std::move(out));
+}
+
+bool cmCommandArgumentParserHelper::HandleEscapeSymbol(
+ cmCommandArgumentParserHelper::ParserType* pt, char symbol)
+{
+ switch (symbol) {
+ case '\\':
+ case '"':
+ case ' ':
+ case '#':
+ case '(':
+ case ')':
+ case '$':
+ case '@':
+ case '^':
+ this->AllocateParserType(pt, &symbol, 1);
+ break;
+ case ';':
+ this->AllocateParserType(pt, "\\;", 2);
+ break;
+ case 't':
+ this->AllocateParserType(pt, "\t", 1);
+ break;
+ case 'n':
+ this->AllocateParserType(pt, "\n", 1);
+ break;
+ case 'r':
+ this->AllocateParserType(pt, "\r", 1);
+ break;
+ case '0':
+ this->AllocateParserType(pt, "\0", 1);
+ break;
+ default: {
+ std::ostringstream e;
+ e << "Invalid escape sequence \\" << symbol;
+ this->SetError(e.str());
+ }
+ return false;
+ }
+ return true;
+}
+
+void cmCommandArgument_SetupEscapes(yyscan_t yyscanner, bool noEscapes);
+
+int cmCommandArgumentParserHelper::ParseString(std::string const& str,
+ int verb)
+{
+ if (str.empty()) {
+ return 0;
+ }
+ this->InputSize = str.size();
+ this->Verbose = verb;
+
+ this->Result.clear();
+
+ yyscan_t yyscanner;
+ cmCommandArgument_yylex_init(&yyscanner);
+ auto* scanBuf = cmCommandArgument_yy_scan_string(str.c_str(), yyscanner);
+ cmCommandArgument_yyset_extra(this, yyscanner);
+ cmCommandArgument_SetupEscapes(yyscanner, this->NoEscapeMode);
+ int res = cmCommandArgument_yyparse(yyscanner);
+ cmCommandArgument_yy_delete_buffer(scanBuf, yyscanner);
+ cmCommandArgument_yylex_destroy(yyscanner);
+ if (res != 0) {
+ return 0;
+ }
+
+ this->CleanupParser();
+
+ if (this->Verbose) {
+ std::cerr << "Expanding [" << str << "] produced: [" << this->Result << "]"
+ << std::endl;
+ }
+ return 1;
+}
+
+void cmCommandArgumentParserHelper::CleanupParser()
+{
+ this->Variables.clear();
+}
+
+void cmCommandArgumentParserHelper::Error(const char* str)
+{
+ auto pos = this->InputBufferPos;
+ auto const isEof = (this->InputSize < this->InputBufferPos);
+ if (!isEof) {
+ pos -= this->LastTokenLength;
+ }
+
+ std::ostringstream ostr;
+ ostr << str << " (" << pos << ")";
+ this->SetError(ostr.str());
+}
+
+void cmCommandArgumentParserHelper::SetMakefile(const cmMakefile* mf)
+{
+ this->Makefile = mf;
+}
+
+void cmCommandArgumentParserHelper::SetResult(const char* value)
+{
+ if (!value) {
+ this->Result.clear();
+ return;
+ }
+ this->Result = value;
+}
+
+void cmCommandArgumentParserHelper::SetError(std::string const& msg)
+{
+ // Keep only the first error.
+ if (this->ErrorString.empty()) {
+ this->ErrorString = msg;
+ }
+}
+
+void cmCommandArgumentParserHelper::UpdateInputPosition(int const tokenLength)
+{
+ this->InputBufferPos += tokenLength;
+ this->LastTokenLength = tokenLength;
+}
diff --git a/Source/cmCommandArgumentParserHelper.h b/Source/cmCommandArgumentParserHelper.h
new file mode 100644
index 0000000..f79ca2c
--- /dev/null
+++ b/Source/cmCommandArgumentParserHelper.h
@@ -0,0 +1,91 @@
+/* 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 <memory>
+#include <string>
+#include <vector>
+
+class cmMakefile;
+
+class cmCommandArgumentParserHelper
+{
+public:
+ struct ParserType
+ {
+ const char* str;
+ };
+
+ cmCommandArgumentParserHelper();
+ ~cmCommandArgumentParserHelper();
+
+ cmCommandArgumentParserHelper(cmCommandArgumentParserHelper const&) = delete;
+ cmCommandArgumentParserHelper& operator=(
+ cmCommandArgumentParserHelper const&) = delete;
+
+ int ParseString(std::string const& str, int verb);
+
+ // For the lexer:
+ void AllocateParserType(cmCommandArgumentParserHelper::ParserType* pt,
+ const char* str, int len = 0);
+ bool HandleEscapeSymbol(cmCommandArgumentParserHelper::ParserType* pt,
+ char symbol);
+
+ void Error(const char* str);
+
+ // For yacc
+ const char* CombineUnions(const char* in1, const char* in2);
+
+ const char* ExpandSpecialVariable(const char* key, const char* var);
+ const char* ExpandVariable(const char* var);
+ const char* ExpandVariableForAt(const char* var);
+ void SetResult(const char* value);
+
+ void SetMakefile(const cmMakefile* mf);
+
+ void UpdateInputPosition(int tokenLength);
+
+ std::string& GetResult() { return this->Result; }
+
+ void SetLineFile(long line, const char* file);
+ void SetEscapeQuotes(bool b) { this->EscapeQuotes = b; }
+ void SetNoEscapeMode(bool b) { this->NoEscapeMode = b; }
+ void SetReplaceAtSyntax(bool b) { this->ReplaceAtSyntax = b; }
+ void SetRemoveEmpty(bool b) { this->RemoveEmpty = b; }
+
+ const char* GetError() { return this->ErrorString.c_str(); }
+
+private:
+ std::string::size_type InputBufferPos{ 1 };
+ std::string::size_type LastTokenLength{};
+ std::string::size_type InputSize{};
+ std::vector<char> OutputBuffer;
+
+ void Print(const char* place, const char* str);
+ void SafePrintMissing(const char* str, int line, int cnt);
+
+ const char* AddString(const std::string& str);
+
+ void CleanupParser();
+ void SetError(std::string const& msg);
+
+ std::vector<std::unique_ptr<char[]>> Variables;
+ const cmMakefile* Makefile;
+ std::string Result;
+ std::string ErrorString;
+ const char* FileName;
+ long FileLine;
+ int Verbose;
+ bool EscapeQuotes;
+ bool NoEscapeMode;
+ bool ReplaceAtSyntax;
+ bool RemoveEmpty;
+};
+
+#define YYSTYPE cmCommandArgumentParserHelper::ParserType
+#define YYSTYPE_IS_DECLARED
+#define YY_EXTRA_TYPE cmCommandArgumentParserHelper*
+#define YY_DECL \
+ int cmCommandArgument_yylex(YYSTYPE* yylvalp, yyscan_t yyscanner)
diff --git a/Source/cmCommandLineArgument.h b/Source/cmCommandLineArgument.h
new file mode 100644
index 0000000..b14cfc2
--- /dev/null
+++ b/Source/cmCommandLineArgument.h
@@ -0,0 +1,167 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+template <typename FunctionSignature>
+struct cmCommandLineArgument
+{
+ enum class Values
+ {
+ Zero,
+ One,
+ Two,
+ ZeroOrOne,
+ OneOrMore
+ };
+
+ std::string InvalidSyntaxMessage;
+ std::string InvalidValueMessage;
+ std::string Name;
+ Values Type;
+ std::function<FunctionSignature> StoreCall;
+
+ template <typename FunctionType>
+ cmCommandLineArgument(std::string n, Values t, FunctionType&& func)
+ : InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
+ , InvalidValueMessage(cmStrCat("Invalid value used with ", n))
+ , Name(std::move(n))
+ , Type(t)
+ , StoreCall(std::forward<FunctionType>(func))
+ {
+ }
+
+ template <typename FunctionType>
+ cmCommandLineArgument(std::string n, std::string failedMsg, Values t,
+ FunctionType&& func)
+ : InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
+ , InvalidValueMessage(std::move(failedMsg))
+ , Name(std::move(n))
+ , Type(t)
+ , StoreCall(std::forward<FunctionType>(func))
+ {
+ }
+
+ bool matches(std::string const& input) const
+ {
+ return (this->Type == Values::Zero) ? (input == this->Name)
+ : cmHasPrefix(input, this->Name);
+ }
+
+ template <typename T, typename... CallState>
+ bool parse(std::string const& input, T& index,
+ std::vector<std::string> const& allArgs,
+ CallState&&... state) const
+ {
+ enum class ParseMode
+ {
+ Valid,
+ Invalid,
+ SyntaxError,
+ ValueError
+ };
+ ParseMode parseState = ParseMode::Valid;
+
+ if (this->Type == Values::Zero) {
+ if (input.size() == this->Name.size()) {
+ parseState =
+ this->StoreCall(std::string{}, std::forward<CallState>(state)...)
+ ? ParseMode::Valid
+ : ParseMode::Invalid;
+ } else {
+ parseState = ParseMode::SyntaxError;
+ }
+
+ } else if (this->Type == Values::One || this->Type == Values::ZeroOrOne) {
+ if (input.size() == this->Name.size()) {
+ auto nextValueIndex = index + 1;
+ if (nextValueIndex >= allArgs.size() ||
+ allArgs[nextValueIndex][0] == '-') {
+ if (this->Type == Values::ZeroOrOne) {
+ parseState =
+ this->StoreCall(std::string{}, std::forward<CallState>(state)...)
+ ? ParseMode::Valid
+ : ParseMode::Invalid;
+ } else {
+ parseState = ParseMode::ValueError;
+ }
+ } else {
+ parseState = this->StoreCall(allArgs[nextValueIndex],
+ std::forward<CallState>(state)...)
+ ? ParseMode::Valid
+ : ParseMode::Invalid;
+ index = nextValueIndex;
+ }
+ } else {
+ // parse the string to get the value
+ auto possible_value = cm::string_view(input).substr(this->Name.size());
+ if (possible_value.empty()) {
+ parseState = ParseMode::SyntaxError;
+ parseState = ParseMode::ValueError;
+ } else if (possible_value[0] == '=') {
+ possible_value.remove_prefix(1);
+ if (possible_value.empty()) {
+ parseState = ParseMode::ValueError;
+ } else {
+ parseState = this->StoreCall(std::string(possible_value),
+ std::forward<CallState>(state)...)
+ ? ParseMode::Valid
+ : ParseMode::Invalid;
+ }
+ }
+ if (parseState == ParseMode::Valid) {
+ if (possible_value[0] == ' ') {
+ possible_value.remove_prefix(1);
+ }
+
+ parseState = this->StoreCall(std::string(possible_value),
+ std::forward<CallState>(state)...)
+ ? ParseMode::Valid
+ : ParseMode::Invalid;
+ }
+ }
+ } else if (this->Type == Values::Two) {
+ if (input.size() == this->Name.size()) {
+ if (index + 2 >= allArgs.size() || allArgs[index + 1][0] == '-' ||
+ allArgs[index + 2][0] == '-') {
+ parseState = ParseMode::ValueError;
+ } else {
+ index += 2;
+ parseState =
+ this->StoreCall(cmStrCat(allArgs[index - 1], ";", allArgs[index]),
+ std::forward<CallState>(state)...)
+ ? ParseMode::Valid
+ : ParseMode::Invalid;
+ }
+ }
+ } else if (this->Type == Values::OneOrMore) {
+ if (input.size() == this->Name.size()) {
+ auto nextValueIndex = index + 1;
+ if (nextValueIndex >= allArgs.size() ||
+ allArgs[nextValueIndex][0] == '-') {
+ parseState = ParseMode::ValueError;
+ } else {
+ std::string buffer = allArgs[nextValueIndex++];
+ while (nextValueIndex < allArgs.size() &&
+ allArgs[nextValueIndex][0] != '-') {
+ buffer = cmStrCat(buffer, ";", allArgs[nextValueIndex++]);
+ }
+ parseState =
+ this->StoreCall(buffer, std::forward<CallState>(state)...)
+ ? ParseMode::Valid
+ : ParseMode::Invalid;
+ index = (nextValueIndex - 1);
+ }
+ }
+ }
+
+ if (parseState == ParseMode::SyntaxError) {
+ cmSystemTools::Error(this->InvalidSyntaxMessage);
+ } else if (parseState == ParseMode::ValueError) {
+ cmSystemTools::Error(this->InvalidValueMessage);
+ }
+ return (parseState == ParseMode::Valid);
+ }
+};
diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx
new file mode 100644
index 0000000..9e5b783
--- /dev/null
+++ b/Source/cmCommands.cxx
@@ -0,0 +1,373 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmCommands.h"
+
+#include <cm/memory>
+
+#include "cmAddCompileDefinitionsCommand.h"
+#include "cmAddCustomCommandCommand.h"
+#include "cmAddCustomTargetCommand.h"
+#include "cmAddDefinitionsCommand.h"
+#include "cmAddDependenciesCommand.h"
+#include "cmAddExecutableCommand.h"
+#include "cmAddLibraryCommand.h"
+#include "cmAddSubDirectoryCommand.h"
+#include "cmAddTestCommand.h"
+#include "cmBreakCommand.h"
+#include "cmBuildCommand.h"
+#include "cmCMakeMinimumRequired.h"
+#include "cmCMakePathCommand.h"
+#include "cmCMakePolicyCommand.h"
+#include "cmCommand.h"
+#include "cmConfigureFileCommand.h"
+#include "cmContinueCommand.h"
+#include "cmCreateTestSourceList.h"
+#include "cmDefinePropertyCommand.h"
+#include "cmEnableLanguageCommand.h"
+#include "cmEnableTestingCommand.h"
+#include "cmExecProgramCommand.h"
+#include "cmExecuteProcessCommand.h"
+#include "cmFileCommand.h"
+#include "cmFindFileCommand.h"
+#include "cmFindLibraryCommand.h"
+#include "cmFindPackageCommand.h"
+#include "cmFindPathCommand.h"
+#include "cmFindProgramCommand.h"
+#include "cmForEachCommand.h"
+#include "cmFunctionCommand.h"
+#include "cmGetCMakePropertyCommand.h"
+#include "cmGetDirectoryPropertyCommand.h"
+#include "cmGetFilenameComponentCommand.h"
+#include "cmGetPropertyCommand.h"
+#include "cmGetSourceFilePropertyCommand.h"
+#include "cmGetTargetPropertyCommand.h"
+#include "cmGetTestPropertyCommand.h"
+#include "cmIfCommand.h"
+#include "cmIncludeCommand.h"
+#include "cmIncludeDirectoryCommand.h"
+#include "cmIncludeGuardCommand.h"
+#include "cmIncludeRegularExpressionCommand.h"
+#include "cmInstallCommand.h"
+#include "cmInstallFilesCommand.h"
+#include "cmInstallTargetsCommand.h"
+#include "cmLinkDirectoriesCommand.h"
+#include "cmListCommand.h"
+#include "cmMacroCommand.h"
+#include "cmMakeDirectoryCommand.h"
+#include "cmMarkAsAdvancedCommand.h"
+#include "cmMathCommand.h"
+#include "cmMessageCommand.h"
+#include "cmOptionCommand.h"
+#include "cmParseArgumentsCommand.h"
+#include "cmPolicies.h"
+#include "cmProjectCommand.h"
+#include "cmReturnCommand.h"
+#include "cmSeparateArgumentsCommand.h"
+#include "cmSetCommand.h"
+#include "cmSetDirectoryPropertiesCommand.h"
+#include "cmSetPropertyCommand.h"
+#include "cmSetSourceFilesPropertiesCommand.h"
+#include "cmSetTargetPropertiesCommand.h"
+#include "cmSetTestsPropertiesCommand.h"
+#include "cmSiteNameCommand.h"
+#include "cmState.h"
+#include "cmStringCommand.h"
+#include "cmSubdirCommand.h"
+#include "cmTargetCompileDefinitionsCommand.h"
+#include "cmTargetCompileFeaturesCommand.h"
+#include "cmTargetCompileOptionsCommand.h"
+#include "cmTargetIncludeDirectoriesCommand.h"
+#include "cmTargetLinkLibrariesCommand.h"
+#include "cmTargetLinkOptionsCommand.h"
+#include "cmTargetPrecompileHeadersCommand.h"
+#include "cmTargetSourcesCommand.h"
+#include "cmTryCompileCommand.h"
+#include "cmTryRunCommand.h"
+#include "cmUnsetCommand.h"
+#include "cmWhileCommand.h"
+
+#if !defined(CMAKE_BOOTSTRAP)
+# include "cmAddCompileOptionsCommand.h"
+# include "cmAddLinkOptionsCommand.h"
+# include "cmAuxSourceDirectoryCommand.h"
+# include "cmBuildNameCommand.h"
+# include "cmCMakeHostSystemInformationCommand.h"
+# include "cmCMakeLanguageCommand.h"
+# include "cmExportCommand.h"
+# include "cmExportLibraryDependenciesCommand.h"
+# include "cmFLTKWrapUICommand.h"
+# include "cmIncludeExternalMSProjectCommand.h"
+# include "cmInstallProgramsCommand.h"
+# include "cmLinkLibrariesCommand.h"
+# include "cmLoadCacheCommand.h"
+# include "cmLoadCommandCommand.h"
+# include "cmOutputRequiredFilesCommand.h"
+# include "cmQTWrapCPPCommand.h"
+# include "cmQTWrapUICommand.h"
+# include "cmRemoveCommand.h"
+# include "cmRemoveDefinitionsCommand.h"
+# include "cmSourceGroupCommand.h"
+# include "cmSubdirDependsCommand.h"
+# include "cmTargetLinkDirectoriesCommand.h"
+# include "cmUseMangledMesaCommand.h"
+# include "cmUtilitySourceCommand.h"
+# include "cmVariableRequiresCommand.h"
+# include "cmVariableWatchCommand.h"
+# include "cmWriteFileCommand.h"
+#endif
+
+void GetScriptingCommands(cmState* state)
+{
+ state->AddFlowControlCommand("break", cmBreakCommand);
+ state->AddFlowControlCommand("continue", cmContinueCommand);
+ state->AddFlowControlCommand("foreach", cmForEachCommand);
+ state->AddFlowControlCommand("function", cmFunctionCommand);
+ state->AddFlowControlCommand("if", cmIfCommand);
+ state->AddFlowControlCommand("macro", cmMacroCommand);
+ state->AddFlowControlCommand("return", cmReturnCommand);
+ state->AddFlowControlCommand("while", cmWhileCommand);
+
+ state->AddBuiltinCommand("cmake_minimum_required", cmCMakeMinimumRequired);
+ state->AddBuiltinCommand("cmake_path", cmCMakePathCommand);
+ state->AddBuiltinCommand("cmake_policy", cmCMakePolicyCommand);
+ state->AddBuiltinCommand("configure_file", cmConfigureFileCommand);
+ state->AddBuiltinCommand("exec_program", cmExecProgramCommand);
+ state->AddBuiltinCommand("execute_process", cmExecuteProcessCommand);
+ state->AddBuiltinCommand("file", cmFileCommand);
+ state->AddBuiltinCommand("find_file", cmFindFile);
+ state->AddBuiltinCommand("find_library", cmFindLibrary);
+ state->AddBuiltinCommand("find_package", cmFindPackage);
+ state->AddBuiltinCommand("find_path", cmFindPath);
+ state->AddBuiltinCommand("find_program", cmFindProgram);
+ state->AddBuiltinCommand("get_cmake_property", cmGetCMakePropertyCommand);
+ state->AddBuiltinCommand("get_directory_property",
+ cmGetDirectoryPropertyCommand);
+ state->AddBuiltinCommand("get_filename_component",
+ cmGetFilenameComponentCommand);
+ state->AddBuiltinCommand("get_property", cmGetPropertyCommand);
+ state->AddBuiltinCommand("include", cmIncludeCommand);
+ state->AddBuiltinCommand("include_guard", cmIncludeGuardCommand);
+ state->AddBuiltinCommand("list", cmListCommand);
+ state->AddBuiltinCommand("make_directory", cmMakeDirectoryCommand);
+ state->AddBuiltinCommand("mark_as_advanced", cmMarkAsAdvancedCommand);
+ state->AddBuiltinCommand("math", cmMathCommand);
+ state->AddBuiltinCommand("message", cmMessageCommand);
+ state->AddBuiltinCommand("option", cmOptionCommand);
+ state->AddBuiltinCommand("cmake_parse_arguments", cmParseArgumentsCommand);
+ state->AddBuiltinCommand("separate_arguments", cmSeparateArgumentsCommand);
+ state->AddBuiltinCommand("set", cmSetCommand);
+ state->AddBuiltinCommand("set_directory_properties",
+ cmSetDirectoryPropertiesCommand);
+ state->AddBuiltinCommand("set_property", cmSetPropertyCommand);
+ state->AddBuiltinCommand("site_name", cmSiteNameCommand);
+ state->AddBuiltinCommand("string", cmStringCommand);
+ state->AddBuiltinCommand("unset", cmUnsetCommand);
+
+ state->AddUnexpectedCommand(
+ "else",
+ "An ELSE command was found outside of a proper "
+ "IF ENDIF structure. Or its arguments did not match "
+ "the opening IF command.");
+ state->AddUnexpectedCommand(
+ "elseif",
+ "An ELSEIF command was found outside of a proper "
+ "IF ENDIF structure.");
+ state->AddUnexpectedCommand(
+ "endforeach",
+ "An ENDFOREACH command was found outside of a proper "
+ "FOREACH ENDFOREACH structure. Or its arguments did "
+ "not match the opening FOREACH command.");
+ state->AddUnexpectedCommand(
+ "endfunction",
+ "An ENDFUNCTION command was found outside of a proper "
+ "FUNCTION ENDFUNCTION structure. Or its arguments did not "
+ "match the opening FUNCTION command.");
+ state->AddUnexpectedCommand(
+ "endif",
+ "An ENDIF command was found outside of a proper "
+ "IF ENDIF structure. Or its arguments did not match "
+ "the opening IF command.");
+ state->AddUnexpectedCommand(
+ "endmacro",
+ "An ENDMACRO command was found outside of a proper "
+ "MACRO ENDMACRO structure. Or its arguments did not "
+ "match the opening MACRO command.");
+ state->AddUnexpectedCommand(
+ "endwhile",
+ "An ENDWHILE command was found outside of a proper "
+ "WHILE ENDWHILE structure. Or its arguments did not "
+ "match the opening WHILE command.");
+
+#if !defined(CMAKE_BOOTSTRAP)
+ state->AddBuiltinCommand("cmake_host_system_information",
+ cmCMakeHostSystemInformationCommand);
+ state->AddBuiltinCommand("cmake_language", cmCMakeLanguageCommand);
+ state->AddBuiltinCommand("load_cache", cmLoadCacheCommand);
+ state->AddBuiltinCommand("remove", cmRemoveCommand);
+ state->AddBuiltinCommand("variable_watch", cmVariableWatchCommand);
+ state->AddBuiltinCommand("write_file", cmWriteFileCommand);
+
+ state->AddDisallowedCommand(
+ "build_name", cmBuildNameCommand, cmPolicies::CMP0036,
+ "The build_name command should not be called; see CMP0036.");
+ state->AddDisallowedCommand(
+ "use_mangled_mesa", cmUseMangledMesaCommand, cmPolicies::CMP0030,
+ "The use_mangled_mesa command should not be called; see CMP0030.");
+
+#endif
+}
+
+void GetProjectCommands(cmState* state)
+{
+ state->AddBuiltinCommand("add_custom_command", cmAddCustomCommandCommand);
+ state->AddBuiltinCommand("add_custom_target", cmAddCustomTargetCommand);
+ state->AddBuiltinCommand("add_definitions", cmAddDefinitionsCommand);
+ state->AddBuiltinCommand("add_dependencies", cmAddDependenciesCommand);
+ state->AddBuiltinCommand("add_executable", cmAddExecutableCommand);
+ state->AddBuiltinCommand("add_library", cmAddLibraryCommand);
+ state->AddBuiltinCommand("add_subdirectory", cmAddSubDirectoryCommand);
+ state->AddBuiltinCommand("add_test", cmAddTestCommand);
+ state->AddBuiltinCommand("build_command", cmBuildCommand);
+ state->AddBuiltinCommand("create_test_sourcelist", cmCreateTestSourceList);
+ state->AddBuiltinCommand("define_property", cmDefinePropertyCommand);
+ state->AddBuiltinCommand("enable_language", cmEnableLanguageCommand);
+ state->AddBuiltinCommand("enable_testing", cmEnableTestingCommand);
+ state->AddBuiltinCommand("get_source_file_property",
+ cmGetSourceFilePropertyCommand);
+ state->AddBuiltinCommand("get_target_property", cmGetTargetPropertyCommand);
+ state->AddBuiltinCommand("get_test_property", cmGetTestPropertyCommand);
+ state->AddBuiltinCommand("include_directories", cmIncludeDirectoryCommand);
+ state->AddBuiltinCommand("include_regular_expression",
+ cmIncludeRegularExpressionCommand);
+ state->AddBuiltinCommand("install", cmInstallCommand);
+ state->AddBuiltinCommand("install_files", cmInstallFilesCommand);
+ state->AddBuiltinCommand("install_targets", cmInstallTargetsCommand);
+ state->AddBuiltinCommand("link_directories", cmLinkDirectoriesCommand);
+ state->AddBuiltinCommand("project", cmProjectCommand);
+ state->AddBuiltinCommand("set_source_files_properties",
+ cmSetSourceFilesPropertiesCommand);
+ state->AddBuiltinCommand("set_target_properties",
+ cmSetTargetPropertiesCommand);
+ state->AddBuiltinCommand("set_tests_properties",
+ cmSetTestsPropertiesCommand);
+ state->AddBuiltinCommand("subdirs", cmSubdirCommand);
+ state->AddBuiltinCommand("target_compile_definitions",
+ cmTargetCompileDefinitionsCommand);
+ state->AddBuiltinCommand("target_compile_features",
+ cmTargetCompileFeaturesCommand);
+ state->AddBuiltinCommand("target_compile_options",
+ cmTargetCompileOptionsCommand);
+ state->AddBuiltinCommand("target_include_directories",
+ cmTargetIncludeDirectoriesCommand);
+ state->AddBuiltinCommand("target_link_libraries",
+ cmTargetLinkLibrariesCommand);
+ state->AddBuiltinCommand("target_link_options", cmTargetLinkOptionsCommand);
+ state->AddBuiltinCommand("target_sources", cmTargetSourcesCommand);
+ state->AddBuiltinCommand("try_compile",
+ cm::make_unique<cmTryCompileCommand>());
+ state->AddBuiltinCommand("try_run", cm::make_unique<cmTryRunCommand>());
+ state->AddBuiltinCommand("target_precompile_headers",
+ cmTargetPrecompileHeadersCommand);
+
+#if !defined(CMAKE_BOOTSTRAP)
+ state->AddBuiltinCommand("add_compile_definitions",
+ cmAddCompileDefinitionsCommand);
+ state->AddBuiltinCommand("add_compile_options", cmAddCompileOptionsCommand);
+ state->AddBuiltinCommand("aux_source_directory",
+ cmAuxSourceDirectoryCommand);
+ state->AddBuiltinCommand("export", cmExportCommand);
+ state->AddBuiltinCommand("fltk_wrap_ui", cmFLTKWrapUICommand);
+ state->AddBuiltinCommand("include_external_msproject",
+ cmIncludeExternalMSProjectCommand);
+ state->AddBuiltinCommand("install_programs", cmInstallProgramsCommand);
+ state->AddBuiltinCommand("add_link_options", cmAddLinkOptionsCommand);
+ state->AddBuiltinCommand("link_libraries", cmLinkLibrariesCommand);
+ state->AddBuiltinCommand("target_link_directories",
+ cmTargetLinkDirectoriesCommand);
+ state->AddBuiltinCommand("qt_wrap_cpp", cmQTWrapCPPCommand);
+ state->AddBuiltinCommand("qt_wrap_ui", cmQTWrapUICommand);
+ state->AddBuiltinCommand("remove_definitions", cmRemoveDefinitionsCommand);
+ state->AddBuiltinCommand("source_group", cmSourceGroupCommand);
+
+ state->AddDisallowedCommand(
+ "export_library_dependencies", cmExportLibraryDependenciesCommand,
+ cmPolicies::CMP0033,
+ "The export_library_dependencies command should not be called; "
+ "see CMP0033.");
+ state->AddDisallowedCommand(
+ "load_command", cmLoadCommandCommand, cmPolicies::CMP0031,
+ "The load_command command should not be called; see CMP0031.");
+ state->AddDisallowedCommand(
+ "output_required_files", cmOutputRequiredFilesCommand, cmPolicies::CMP0032,
+ "The output_required_files command should not be called; see CMP0032.");
+ state->AddDisallowedCommand(
+ "subdir_depends", cmSubdirDependsCommand, cmPolicies::CMP0029,
+ "The subdir_depends command should not be called; see CMP0029.");
+ state->AddDisallowedCommand(
+ "utility_source", cmUtilitySourceCommand, cmPolicies::CMP0034,
+ "The utility_source command should not be called; see CMP0034.");
+ state->AddDisallowedCommand(
+ "variable_requires", cmVariableRequiresCommand, cmPolicies::CMP0035,
+ "The variable_requires command should not be called; see CMP0035.");
+#endif
+}
+
+void GetProjectCommandsInScriptMode(cmState* state)
+{
+#define CM_UNEXPECTED_PROJECT_COMMAND(NAME) \
+ state->AddUnexpectedCommand(NAME, "command is not scriptable")
+
+ CM_UNEXPECTED_PROJECT_COMMAND("add_compile_options");
+ CM_UNEXPECTED_PROJECT_COMMAND("add_custom_command");
+ CM_UNEXPECTED_PROJECT_COMMAND("add_custom_target");
+ CM_UNEXPECTED_PROJECT_COMMAND("add_definitions");
+ CM_UNEXPECTED_PROJECT_COMMAND("add_dependencies");
+ CM_UNEXPECTED_PROJECT_COMMAND("add_executable");
+ CM_UNEXPECTED_PROJECT_COMMAND("add_library");
+ CM_UNEXPECTED_PROJECT_COMMAND("add_subdirectory");
+ CM_UNEXPECTED_PROJECT_COMMAND("add_test");
+ CM_UNEXPECTED_PROJECT_COMMAND("aux_source_directory");
+ CM_UNEXPECTED_PROJECT_COMMAND("build_command");
+ CM_UNEXPECTED_PROJECT_COMMAND("create_test_sourcelist");
+ CM_UNEXPECTED_PROJECT_COMMAND("define_property");
+ CM_UNEXPECTED_PROJECT_COMMAND("enable_language");
+ CM_UNEXPECTED_PROJECT_COMMAND("enable_testing");
+ CM_UNEXPECTED_PROJECT_COMMAND("export");
+ CM_UNEXPECTED_PROJECT_COMMAND("fltk_wrap_ui");
+ CM_UNEXPECTED_PROJECT_COMMAND("get_source_file_property");
+ CM_UNEXPECTED_PROJECT_COMMAND("get_target_property");
+ CM_UNEXPECTED_PROJECT_COMMAND("get_test_property");
+ CM_UNEXPECTED_PROJECT_COMMAND("include_directories");
+ CM_UNEXPECTED_PROJECT_COMMAND("include_external_msproject");
+ CM_UNEXPECTED_PROJECT_COMMAND("include_regular_expression");
+ CM_UNEXPECTED_PROJECT_COMMAND("install");
+ CM_UNEXPECTED_PROJECT_COMMAND("link_directories");
+ CM_UNEXPECTED_PROJECT_COMMAND("link_libraries");
+ CM_UNEXPECTED_PROJECT_COMMAND("project");
+ CM_UNEXPECTED_PROJECT_COMMAND("qt_wrap_cpp");
+ CM_UNEXPECTED_PROJECT_COMMAND("qt_wrap_ui");
+ CM_UNEXPECTED_PROJECT_COMMAND("remove_definitions");
+ CM_UNEXPECTED_PROJECT_COMMAND("set_source_files_properties");
+ CM_UNEXPECTED_PROJECT_COMMAND("set_target_properties");
+ CM_UNEXPECTED_PROJECT_COMMAND("set_tests_properties");
+ CM_UNEXPECTED_PROJECT_COMMAND("source_group");
+ CM_UNEXPECTED_PROJECT_COMMAND("target_compile_definitions");
+ CM_UNEXPECTED_PROJECT_COMMAND("target_compile_features");
+ CM_UNEXPECTED_PROJECT_COMMAND("target_compile_options");
+ CM_UNEXPECTED_PROJECT_COMMAND("target_include_directories");
+ CM_UNEXPECTED_PROJECT_COMMAND("target_link_libraries");
+ CM_UNEXPECTED_PROJECT_COMMAND("target_sources");
+ CM_UNEXPECTED_PROJECT_COMMAND("try_compile");
+ CM_UNEXPECTED_PROJECT_COMMAND("try_run");
+
+ // deprecated commands
+ CM_UNEXPECTED_PROJECT_COMMAND("export_library_dependencies");
+ CM_UNEXPECTED_PROJECT_COMMAND("load_command");
+ CM_UNEXPECTED_PROJECT_COMMAND("output_required_files");
+ CM_UNEXPECTED_PROJECT_COMMAND("subdir_depends");
+ CM_UNEXPECTED_PROJECT_COMMAND("utility_source");
+ CM_UNEXPECTED_PROJECT_COMMAND("variable_requires");
+
+#undef CM_UNEXPECTED_PROJECT_COMMAND
+}
diff --git a/Source/cmCommands.h b/Source/cmCommands.h
new file mode 100644
index 0000000..5605430
--- /dev/null
+++ b/Source/cmCommands.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+class cmState;
+
+/**
+ * Global function to register all compiled in commands.
+ * To add a new command edit cmCommands.cxx and add your command.
+ * It is up to the caller to delete the commands created by this call.
+ */
+void GetScriptingCommands(cmState* state);
+void GetProjectCommands(cmState* state);
+void GetProjectCommandsInScriptMode(cmState* state);
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
new file mode 100644
index 0000000..228cff7
--- /dev/null
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -0,0 +1,294 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCommonTargetGenerator.h"
+
+#include <set>
+#include <sstream>
+#include <utility>
+
+#include "cmComputeLinkInformation.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalCommonGenerator.h"
+#include "cmLinkLineComputer.h"
+#include "cmLocalCommonGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmProperty.h"
+#include "cmSourceFile.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmTarget.h"
+
+cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt)
+ : GeneratorTarget(gt)
+ , Makefile(gt->Makefile)
+ , LocalCommonGenerator(
+ static_cast<cmLocalCommonGenerator*>(gt->LocalGenerator))
+ , GlobalCommonGenerator(static_cast<cmGlobalCommonGenerator*>(
+ gt->LocalGenerator->GetGlobalGenerator()))
+ , ConfigNames(this->LocalCommonGenerator->GetConfigNames())
+{
+}
+
+cmCommonTargetGenerator::~cmCommonTargetGenerator() = default;
+
+std::vector<std::string> const& cmCommonTargetGenerator::GetConfigNames() const
+{
+ return this->ConfigNames;
+}
+
+const char* cmCommonTargetGenerator::GetFeature(const std::string& feature,
+ const std::string& config)
+{
+ return this->GeneratorTarget->GetFeature(feature, config)->c_str();
+}
+
+void cmCommonTargetGenerator::AddModuleDefinitionFlag(
+ cmLinkLineComputer* linkLineComputer, std::string& flags,
+ const std::string& config)
+{
+ cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
+ this->GeneratorTarget->GetModuleDefinitionInfo(config);
+ if (!mdi || mdi->DefFile.empty()) {
+ return;
+ }
+
+ // TODO: Create a per-language flag variable.
+ cmProp defFileFlag =
+ this->Makefile->GetDefinition("CMAKE_LINK_DEF_FILE_FLAG");
+ if (!defFileFlag) {
+ return;
+ }
+
+ // Append the flag and value. Use ConvertToLinkReference to help
+ // vs6's "cl -link" pass it to the linker.
+ std::string flag =
+ cmStrCat(*defFileFlag,
+ this->LocalCommonGenerator->ConvertToOutputFormat(
+ linkLineComputer->ConvertToLinkReference(mdi->DefFile),
+ cmOutputConverter::SHELL));
+ this->LocalCommonGenerator->AppendFlags(flags, flag);
+}
+
+void cmCommonTargetGenerator::AppendFortranFormatFlags(
+ std::string& flags, cmSourceFile const& source)
+{
+ const std::string srcfmt = source.GetSafeProperty("Fortran_FORMAT");
+ cmOutputConverter::FortranFormat format =
+ cmOutputConverter::GetFortranFormat(srcfmt);
+ if (format == cmOutputConverter::FortranFormatNone) {
+ std::string const& tgtfmt =
+ this->GeneratorTarget->GetSafeProperty("Fortran_FORMAT");
+ format = cmOutputConverter::GetFortranFormat(tgtfmt);
+ }
+ const char* var = nullptr;
+ switch (format) {
+ case cmOutputConverter::FortranFormatFixed:
+ var = "CMAKE_Fortran_FORMAT_FIXED_FLAG";
+ break;
+ case cmOutputConverter::FortranFormatFree:
+ var = "CMAKE_Fortran_FORMAT_FREE_FLAG";
+ break;
+ default:
+ break;
+ }
+ if (var) {
+ this->LocalCommonGenerator->AppendFlags(
+ flags, this->Makefile->GetSafeDefinition(var));
+ }
+}
+
+void cmCommonTargetGenerator::AppendFortranPreprocessFlags(
+ std::string& flags, cmSourceFile const& source)
+{
+ const std::string srcpp = source.GetSafeProperty("Fortran_PREPROCESS");
+ cmOutputConverter::FortranPreprocess preprocess =
+ cmOutputConverter::GetFortranPreprocess(srcpp);
+ if (preprocess == cmOutputConverter::FortranPreprocess::Unset) {
+ std::string const& tgtpp =
+ this->GeneratorTarget->GetSafeProperty("Fortran_PREPROCESS");
+ preprocess = cmOutputConverter::GetFortranPreprocess(tgtpp);
+ }
+ const char* var = nullptr;
+ switch (preprocess) {
+ case cmOutputConverter::FortranPreprocess::Needed:
+ var = "CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON";
+ break;
+ case cmOutputConverter::FortranPreprocess::NotNeeded:
+ var = "CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF";
+ break;
+ default:
+ break;
+ }
+ if (var) {
+ this->LocalCommonGenerator->AppendCompileOptions(
+ flags, this->Makefile->GetSafeDefinition(var));
+ }
+}
+
+std::string cmCommonTargetGenerator::GetFlags(const std::string& l,
+ const std::string& config,
+ const std::string& arch)
+{
+ const std::string key = config + arch;
+
+ auto i = this->Configs[key].FlagsByLanguage.find(l);
+ if (i == this->Configs[key].FlagsByLanguage.end()) {
+ std::string flags;
+
+ this->LocalCommonGenerator->GetTargetCompileFlags(this->GeneratorTarget,
+ config, l, flags, arch);
+
+ ByLanguageMap::value_type entry(l, flags);
+ i = this->Configs[key].FlagsByLanguage.insert(entry).first;
+ }
+ return i->second;
+}
+
+std::string cmCommonTargetGenerator::GetDefines(const std::string& l,
+ const std::string& config)
+{
+ auto i = this->Configs[config].DefinesByLanguage.find(l);
+ if (i == this->Configs[config].DefinesByLanguage.end()) {
+ std::set<std::string> defines;
+ this->LocalCommonGenerator->GetTargetDefines(this->GeneratorTarget, config,
+ l, defines);
+
+ std::string definesString;
+ this->LocalCommonGenerator->JoinDefines(defines, definesString, l);
+
+ ByLanguageMap::value_type entry(l, definesString);
+ i = this->Configs[config].DefinesByLanguage.insert(entry).first;
+ }
+ return i->second;
+}
+
+std::string cmCommonTargetGenerator::GetIncludes(std::string const& l,
+ const std::string& config)
+{
+ auto i = this->Configs[config].IncludesByLanguage.find(l);
+ if (i == this->Configs[config].IncludesByLanguage.end()) {
+ std::string includes;
+ this->AddIncludeFlags(includes, l, config);
+ ByLanguageMap::value_type entry(l, includes);
+ i = this->Configs[config].IncludesByLanguage.insert(entry).first;
+ }
+ return i->second;
+}
+
+std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories(
+ const std::string& config) const
+{
+ std::vector<std::string> dirs;
+ std::set<cmGeneratorTarget const*> emitted;
+ if (cmComputeLinkInformation* cli =
+ this->GeneratorTarget->GetLinkInformation(config)) {
+ cmComputeLinkInformation::ItemVector const& items = cli->GetItems();
+ for (auto const& item : items) {
+ cmGeneratorTarget const* linkee = item.Target;
+ if (linkee &&
+ !linkee->IsImported()
+ // We can ignore the INTERFACE_LIBRARY items because
+ // Target->GetLinkInformation already processed their
+ // link interface and they don't have any output themselves.
+ && linkee->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
+ emitted.insert(linkee).second) {
+ cmLocalGenerator* lg = linkee->GetLocalGenerator();
+ std::string di = cmStrCat(lg->GetCurrentBinaryDirectory(), '/',
+ lg->GetTargetDirectory(linkee));
+ dirs.push_back(std::move(di));
+ }
+ }
+ }
+ return dirs;
+}
+
+std::string cmCommonTargetGenerator::ComputeTargetCompilePDB(
+ const std::string& config) const
+{
+ std::string compilePdbPath;
+ if (this->GeneratorTarget->GetType() > cmStateEnums::OBJECT_LIBRARY) {
+ return compilePdbPath;
+ }
+
+ compilePdbPath = this->GeneratorTarget->GetCompilePDBPath(config);
+ if (compilePdbPath.empty()) {
+ // Match VS default: `$(IntDir)vc$(PlatformToolsetVersion).pdb`.
+ // A trailing slash tells the toolchain to add its default file name.
+ compilePdbPath = this->GeneratorTarget->GetSupportDirectory();
+ if (this->GlobalCommonGenerator->IsMultiConfig()) {
+ compilePdbPath += "/";
+ compilePdbPath += config;
+ }
+ compilePdbPath += "/";
+ if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ // Match VS default for static libs: `$(IntDir)$(ProjectName).pdb`.
+ compilePdbPath += this->GeneratorTarget->GetName();
+ compilePdbPath += ".pdb";
+ }
+ }
+
+ return compilePdbPath;
+}
+
+std::string cmCommonTargetGenerator::GetManifests(const std::string& config)
+{
+ std::vector<cmSourceFile const*> manifest_srcs;
+ this->GeneratorTarget->GetManifests(manifest_srcs, config);
+
+ std::vector<std::string> manifests;
+ manifests.reserve(manifest_srcs.size());
+ for (cmSourceFile const* manifest_src : manifest_srcs) {
+ manifests.push_back(this->LocalCommonGenerator->ConvertToOutputFormat(
+ this->LocalCommonGenerator->MaybeConvertToRelativePath(
+ this->LocalCommonGenerator->GetWorkingDirectory(),
+ manifest_src->GetFullPath()),
+ cmOutputConverter::SHELL));
+ }
+
+ return cmJoin(manifests, " ");
+}
+
+std::string cmCommonTargetGenerator::GetAIXExports(std::string const&)
+{
+ std::string aixExports;
+ if (this->GeneratorTarget->Target->IsAIX()) {
+ if (cmProp exportAll =
+ this->GeneratorTarget->GetProperty("AIX_EXPORT_ALL_SYMBOLS")) {
+ if (cmIsOff(*exportAll)) {
+ aixExports = "-n";
+ }
+ }
+ }
+ return aixExports;
+}
+
+void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags,
+ const std::string& lang,
+ const char* name, bool so)
+{
+ // Lookup the flag to specify the version.
+ std::string fvar = cmStrCat("CMAKE_", lang, "_OSX_", name, "_VERSION_FLAG");
+ cmProp flag = this->Makefile->GetDefinition(fvar);
+
+ // Skip if no such flag.
+ if (!flag) {
+ return;
+ }
+
+ // Lookup the target version information.
+ int major;
+ int minor;
+ int patch;
+ std::string prop = cmStrCat("MACHO_", name, "_VERSION");
+ std::string fallback_prop = so ? "SOVERSION" : "VERSION";
+ this->GeneratorTarget->GetTargetVersionFallback(prop, fallback_prop, major,
+ minor, patch);
+ if (major > 0 || minor > 0 || patch > 0) {
+ // Append the flag since a non-zero version is specified.
+ std::ostringstream vflag;
+ vflag << *flag << major << "." << minor << "." << patch;
+ this->LocalCommonGenerator->AppendFlags(flags, vflag.str());
+ }
+}
diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h
new file mode 100644
index 0000000..fba6b0a
--- /dev/null
+++ b/Source/cmCommonTargetGenerator.h
@@ -0,0 +1,76 @@
+/* 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 <map>
+#include <string>
+#include <vector>
+
+class cmGeneratorTarget;
+class cmGlobalCommonGenerator;
+class cmLinkLineComputer;
+class cmLocalCommonGenerator;
+class cmMakefile;
+class cmSourceFile;
+
+/** \class cmCommonTargetGenerator
+ * \brief Common infrastructure for Makefile and Ninja per-target generators
+ */
+class cmCommonTargetGenerator
+{
+public:
+ cmCommonTargetGenerator(cmGeneratorTarget* gt);
+ virtual ~cmCommonTargetGenerator();
+
+ std::vector<std::string> const& GetConfigNames() const;
+
+protected:
+ // Feature query methods.
+ const char* GetFeature(const std::string& feature,
+ const std::string& config);
+
+ // Helper to add flag for windows .def file.
+ void AddModuleDefinitionFlag(cmLinkLineComputer* linkLineComputer,
+ std::string& flags, const std::string& config);
+
+ cmGeneratorTarget* GeneratorTarget;
+ cmMakefile* Makefile;
+ cmLocalCommonGenerator* LocalCommonGenerator;
+ cmGlobalCommonGenerator* GlobalCommonGenerator;
+ std::vector<std::string> ConfigNames;
+
+ void AppendFortranFormatFlags(std::string& flags,
+ cmSourceFile const& source);
+
+ void AppendFortranPreprocessFlags(std::string& flags,
+ cmSourceFile const& source);
+
+ virtual void AddIncludeFlags(std::string& flags, std::string const& lang,
+ const std::string& config) = 0;
+
+ void AppendOSXVerFlag(std::string& flags, const std::string& lang,
+ const char* name, bool so);
+
+ std::string GetFlags(const std::string& l, const std::string& config,
+ const std::string& arch = std::string());
+ std::string GetDefines(const std::string& l, const std::string& config);
+ std::string GetIncludes(std::string const& l, const std::string& config);
+ std::string GetManifests(const std::string& config);
+ std::string GetAIXExports(std::string const& config);
+
+ std::vector<std::string> GetLinkedTargetDirectories(
+ const std::string& config) const;
+ std::string ComputeTargetCompilePDB(const std::string& config) const;
+
+private:
+ using ByLanguageMap = std::map<std::string, std::string>;
+ struct ByConfig
+ {
+ ByLanguageMap FlagsByLanguage;
+ ByLanguageMap DefinesByLanguage;
+ ByLanguageMap IncludesByLanguage;
+ };
+ std::map<std::string, ByConfig> Configs;
+};
diff --git a/Source/cmComputeComponentGraph.cxx b/Source/cmComputeComponentGraph.cxx
new file mode 100644
index 0000000..6591fb1
--- /dev/null
+++ b/Source/cmComputeComponentGraph.cxx
@@ -0,0 +1,134 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmComputeComponentGraph.h"
+
+#include <algorithm>
+#include <cassert>
+
+cmComputeComponentGraph::cmComputeComponentGraph(Graph const& input)
+ : InputGraph(input)
+{
+}
+
+cmComputeComponentGraph::~cmComputeComponentGraph() = default;
+
+void cmComputeComponentGraph::Compute()
+{
+ // Identify components.
+ this->Tarjan();
+
+ // Compute the component graph.
+ this->ComponentGraph.resize(0);
+ this->ComponentGraph.resize(this->Components.size());
+ this->TransferEdges();
+}
+
+void cmComputeComponentGraph::Tarjan()
+{
+ int n = static_cast<int>(this->InputGraph.size());
+ TarjanEntry entry = { 0, 0 };
+ this->TarjanEntries.resize(0);
+ this->TarjanEntries.resize(n, entry);
+ this->TarjanComponents.resize(0);
+ this->TarjanComponents.resize(n, -1);
+ this->TarjanWalkId = 0;
+ this->TarjanVisited.resize(0);
+ this->TarjanVisited.resize(n, 0);
+ for (int i = 0; i < n; ++i) {
+ // Start a new DFS from this node if it has never been visited.
+ if (!this->TarjanVisited[i]) {
+ assert(this->TarjanStack.empty());
+ ++this->TarjanWalkId;
+ this->TarjanIndex = 0;
+ this->TarjanVisit(i);
+ }
+ }
+}
+
+void cmComputeComponentGraph::TarjanVisit(int i)
+{
+ // We are now visiting this node.
+ this->TarjanVisited[i] = this->TarjanWalkId;
+
+ // Initialize the entry.
+ this->TarjanEntries[i].Root = i;
+ this->TarjanComponents[i] = -1;
+ this->TarjanEntries[i].VisitIndex = ++this->TarjanIndex;
+ this->TarjanStack.push(i);
+
+ // Follow outgoing edges.
+ EdgeList const& nl = this->InputGraph[i];
+ for (cmGraphEdge const& ni : nl) {
+ int j = ni;
+
+ // Ignore edges to nodes that have been reached by a previous DFS
+ // walk. Since we did not reach the current node from that walk
+ // it must not belong to the same component and it has already
+ // been assigned to a component.
+ if (this->TarjanVisited[j] > 0 &&
+ this->TarjanVisited[j] < this->TarjanWalkId) {
+ continue;
+ }
+
+ // Visit the destination if it has not yet been visited.
+ if (!this->TarjanVisited[j]) {
+ this->TarjanVisit(j);
+ }
+
+ // If the destination has not yet been assigned to a component,
+ // check if it has a better root for the current object.
+ if (this->TarjanComponents[j] < 0) {
+ if (this->TarjanEntries[this->TarjanEntries[j].Root].VisitIndex <
+ this->TarjanEntries[this->TarjanEntries[i].Root].VisitIndex) {
+ this->TarjanEntries[i].Root = this->TarjanEntries[j].Root;
+ }
+ }
+ }
+
+ // Check if we have found a component.
+ if (this->TarjanEntries[i].Root == i) {
+ // Yes. Create it.
+ int c = static_cast<int>(this->Components.size());
+ this->Components.emplace_back();
+ NodeList& component = this->Components[c];
+
+ // Populate the component list.
+ int j;
+ do {
+ // Get the next member of the component.
+ j = this->TarjanStack.top();
+ this->TarjanStack.pop();
+
+ // Assign the member to the component.
+ this->TarjanComponents[j] = c;
+ this->TarjanEntries[j].Root = i;
+
+ // Store the node in its component.
+ component.push_back(j);
+ } while (j != i);
+
+ // Sort the component members for clarity.
+ std::sort(component.begin(), component.end());
+ }
+}
+
+void cmComputeComponentGraph::TransferEdges()
+{
+ // Map inter-component edges in the original graph to edges in the
+ // component graph.
+ int n = static_cast<int>(this->InputGraph.size());
+ for (int i = 0; i < n; ++i) {
+ int i_component = this->TarjanComponents[i];
+ EdgeList const& nl = this->InputGraph[i];
+ for (cmGraphEdge const& ni : nl) {
+ int j = ni;
+ int j_component = this->TarjanComponents[j];
+ if (i_component != j_component) {
+ // We do not attempt to combine duplicate edges, but instead
+ // store the inter-component edges with suitable multiplicity.
+ this->ComponentGraph[i_component].emplace_back(
+ j_component, ni.IsStrong(), ni.IsCross(), ni.GetBacktrace());
+ }
+ }
+ }
+}
diff --git a/Source/cmComputeComponentGraph.h b/Source/cmComputeComponentGraph.h
new file mode 100644
index 0000000..1d1d134
--- /dev/null
+++ b/Source/cmComputeComponentGraph.h
@@ -0,0 +1,79 @@
+/* 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 <stack>
+#include <vector>
+
+#include "cmGraphAdjacencyList.h"
+
+/** \class cmComputeComponentGraph
+ * \brief Analyze a graph to determine strongly connected components.
+ *
+ * Convert a directed graph into a directed acyclic graph whose nodes
+ * correspond to strongly connected components of the original graph.
+ *
+ * We use Tarjan's algorithm to enumerate the components efficiently.
+ * An advantage of this approach is that the components are identified
+ * in a topologically sorted order.
+ */
+class cmComputeComponentGraph
+{
+public:
+ // Represent the graph with an adjacency list.
+ using NodeList = cmGraphNodeList;
+ using EdgeList = cmGraphEdgeList;
+ using Graph = cmGraphAdjacencyList;
+
+ cmComputeComponentGraph(Graph const& input);
+ ~cmComputeComponentGraph();
+
+ /** Run the computation. */
+ void Compute();
+
+ /** Get the adjacency list of the component graph. */
+ Graph const& GetComponentGraph() const { return this->ComponentGraph; }
+ EdgeList const& GetComponentGraphEdges(int c) const
+ {
+ return this->ComponentGraph[c];
+ }
+
+ /** Get map from component index to original node indices. */
+ std::vector<NodeList> const& GetComponents() const
+ {
+ return this->Components;
+ }
+ NodeList const& GetComponent(int c) const { return this->Components[c]; }
+
+ /** Get map from original node index to component index. */
+ std::vector<int> const& GetComponentMap() const
+ {
+ return this->TarjanComponents;
+ }
+
+private:
+ void TransferEdges();
+
+ Graph const& InputGraph;
+ Graph ComponentGraph;
+
+ // Tarjan's algorithm.
+ struct TarjanEntry
+ {
+ int Root;
+ int VisitIndex;
+ };
+ std::vector<int> TarjanVisited;
+ std::vector<int> TarjanComponents;
+ std::vector<TarjanEntry> TarjanEntries;
+ std::vector<NodeList> Components;
+ std::stack<int> TarjanStack;
+ int TarjanWalkId;
+ int TarjanIndex;
+ void Tarjan();
+ void TarjanVisit(int i);
+
+ // Connected components.
+};
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
new file mode 100644
index 0000000..5341e8d
--- /dev/null
+++ b/Source/cmComputeLinkDepends.cxx
@@ -0,0 +1,842 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmComputeLinkDepends.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <iterator>
+#include <sstream>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmComputeComponentGraph.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmTarget.h"
+#include "cmake.h"
+
+/*
+
+This file computes an ordered list of link items to use when linking a
+single target in one configuration. Each link item is identified by
+the string naming it. A graph of dependencies is created in which
+each node corresponds to one item and directed edges lead from nodes to
+those which must *follow* them on the link line. For example, the
+graph
+
+ A -> B -> C
+
+will lead to the link line order
+
+ A B C
+
+The set of items placed in the graph is formed with a breadth-first
+search of the link dependencies starting from the main target.
+
+There are two types of items: those with known direct dependencies and
+those without known dependencies. We will call the two types "known
+items" and "unknown items", respectively. Known items are those whose
+names correspond to targets (built or imported) and those for which an
+old-style <item>_LIB_DEPENDS variable is defined. All other items are
+unknown and we must infer dependencies for them. For items that look
+like flags (beginning with '-') we trivially infer no dependencies,
+and do not include them in the dependencies of other items.
+
+Known items have dependency lists ordered based on how the user
+specified them. We can use this order to infer potential dependencies
+of unknown items. For example, if link items A and B are unknown and
+items X and Y are known, then we might have the following dependency
+lists:
+
+ X: Y A B
+ Y: A B
+
+The explicitly known dependencies form graph edges
+
+ X -> Y , X -> A , X -> B , Y -> A , Y -> B
+
+We can also infer the edge
+
+ A -> B
+
+because *every* time A appears B is seen on its right. We do not know
+whether A really needs symbols from B to link, but it *might* so we
+must preserve their order. This is the case also for the following
+explicit lists:
+
+ X: A B Y
+ Y: A B
+
+Here, A is followed by the set {B,Y} in one list, and {B} in the other
+list. The intersection of these sets is {B}, so we can infer that A
+depends on at most B. Meanwhile B is followed by the set {Y} in one
+list and {} in the other. The intersection is {} so we can infer that
+B has no dependencies.
+
+Let's make a more complex example by adding unknown item C and
+considering these dependency lists:
+
+ X: A B Y C
+ Y: A C B
+
+The explicit edges are
+
+ X -> Y , X -> A , X -> B , X -> C , Y -> A , Y -> B , Y -> C
+
+For the unknown items, we infer dependencies by looking at the
+"follow" sets:
+
+ A: intersect( {B,Y,C} , {C,B} ) = {B,C} ; infer edges A -> B , A -> C
+ B: intersect( {Y,C} , {} ) = {} ; infer no edges
+ C: intersect( {} , {B} ) = {} ; infer no edges
+
+Note that targets are never inferred as dependees because outside
+libraries should not depend on them.
+
+------------------------------------------------------------------------------
+
+The initial exploration of dependencies using a BFS associates an
+integer index with each link item. When the graph is built outgoing
+edges are sorted by this index.
+
+After the initial exploration of the link interface tree, any
+transitive (dependent) shared libraries that were encountered and not
+included in the interface are processed in their own BFS. This BFS
+follows only the dependent library lists and not the link interfaces.
+They are added to the link items with a mark indicating that the are
+transitive dependencies. Then cmComputeLinkInformation deals with
+them on a per-platform basis.
+
+The complete graph formed from all known and inferred dependencies may
+not be acyclic, so an acyclic version must be created.
+The original graph is converted to a directed acyclic graph in which
+each node corresponds to a strongly connected component of the
+original graph. For example, the dependency graph
+
+ X -> A -> B -> C -> A -> Y
+
+contains strongly connected components {X}, {A,B,C}, and {Y}. The
+implied directed acyclic graph (DAG) is
+
+ {X} -> {A,B,C} -> {Y}
+
+We then compute a topological order for the DAG nodes to serve as a
+reference for satisfying dependencies efficiently. We perform the DFS
+in reverse order and assign topological order indices counting down so
+that the result is as close to the original BFS order as possible
+without violating dependencies.
+
+------------------------------------------------------------------------------
+
+The final link entry order is constructed as follows. We first walk
+through and emit the *original* link line as specified by the user.
+As each item is emitted, a set of pending nodes in the component DAG
+is maintained. When a pending component has been completely seen, it
+is removed from the pending set and its dependencies (following edges
+of the DAG) are added. A trivial component (those with one item) is
+complete as soon as its item is seen. A non-trivial component (one
+with more than one item; assumed to be static libraries) is complete
+when *all* its entries have been seen *twice* (all entries seen once,
+then all entries seen again, not just each entry twice). A pending
+component tracks which items have been seen and a count of how many
+times the component needs to be seen (once for trivial components,
+twice for non-trivial). If at any time another component finishes and
+re-adds an already pending component, the pending component is reset
+so that it needs to be seen in its entirety again. This ensures that
+all dependencies of a component are satisfied no matter where it
+appears.
+
+After the original link line has been completed, we append to it the
+remaining pending components and their dependencies. This is done by
+repeatedly emitting the first item from the first pending component
+and following the same update rules as when traversing the original
+link line. Since the pending components are kept in topological order
+they are emitted with minimal repeats (we do not want to emit a
+component just to have it added again when another component is
+completed later). This process continues until no pending components
+remain. We know it will terminate because the component graph is
+guaranteed to be acyclic.
+
+The final list of items produced by this procedure consists of the
+original user link line followed by minimal additional items needed to
+satisfy dependencies. The final list is then filtered to de-duplicate
+items that we know the linker will re-use automatically (shared libs).
+
+*/
+
+cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target,
+ const std::string& config)
+{
+ // Store context information.
+ this->Target = target;
+ this->Makefile = this->Target->Target->GetMakefile();
+ this->GlobalGenerator =
+ this->Target->GetLocalGenerator()->GetGlobalGenerator();
+ this->CMakeInstance = this->GlobalGenerator->GetCMakeInstance();
+
+ // The configuration being linked.
+ this->HasConfig = !config.empty();
+ this->Config = (this->HasConfig) ? config : std::string();
+ std::vector<std::string> debugConfigs =
+ this->Makefile->GetCMakeInstance()->GetDebugConfigs();
+ this->LinkType = CMP0003_ComputeLinkType(this->Config, debugConfigs);
+
+ // Enable debug mode if requested.
+ this->DebugMode = this->Makefile->IsOn("CMAKE_LINK_DEPENDS_DEBUG_MODE");
+
+ // Assume no compatibility until set.
+ this->OldLinkDirMode = false;
+
+ // No computation has been done.
+ this->CCG = nullptr;
+}
+
+cmComputeLinkDepends::~cmComputeLinkDepends() = default;
+
+void cmComputeLinkDepends::SetOldLinkDirMode(bool b)
+{
+ this->OldLinkDirMode = b;
+}
+
+std::vector<cmComputeLinkDepends::LinkEntry> const&
+cmComputeLinkDepends::Compute()
+{
+ // Follow the link dependencies of the target to be linked.
+ this->AddDirectLinkEntries();
+
+ // Complete the breadth-first search of dependencies.
+ while (!this->BFSQueue.empty()) {
+ // Get the next entry.
+ BFSEntry qe = this->BFSQueue.front();
+ this->BFSQueue.pop();
+
+ // Follow the entry's dependencies.
+ this->FollowLinkEntry(qe);
+ }
+
+ // Complete the search of shared library dependencies.
+ while (!this->SharedDepQueue.empty()) {
+ // Handle the next entry.
+ this->HandleSharedDependency(this->SharedDepQueue.front());
+ this->SharedDepQueue.pop();
+ }
+
+ // Infer dependencies of targets for which they were not known.
+ this->InferDependencies();
+
+ // Cleanup the constraint graph.
+ this->CleanConstraintGraph();
+
+ // Display the constraint graph.
+ if (this->DebugMode) {
+ fprintf(stderr,
+ "---------------------------------------"
+ "---------------------------------------\n");
+ fprintf(stderr, "Link dependency analysis for target %s, config %s\n",
+ this->Target->GetName().c_str(),
+ this->HasConfig ? this->Config.c_str() : "noconfig");
+ this->DisplayConstraintGraph();
+ }
+
+ // Compute the final ordering.
+ this->OrderLinkEntires();
+
+ // Compute the final set of link entries.
+ // Iterate in reverse order so we can keep only the last occurrence
+ // of a shared library.
+ std::set<int> emitted;
+ for (int i : cmReverseRange(this->FinalLinkOrder)) {
+ LinkEntry const& e = this->EntryList[i];
+ cmGeneratorTarget const* t = e.Target;
+ // Entries that we know the linker will re-use do not need to be repeated.
+ bool uniquify = t && t->GetType() == cmStateEnums::SHARED_LIBRARY;
+ if (!uniquify || emitted.insert(i).second) {
+ this->FinalLinkEntries.push_back(e);
+ }
+ }
+ // Reverse the resulting order since we iterated in reverse.
+ std::reverse(this->FinalLinkEntries.begin(), this->FinalLinkEntries.end());
+
+ // Display the final set.
+ if (this->DebugMode) {
+ this->DisplayFinalEntries();
+ }
+
+ return this->FinalLinkEntries;
+}
+
+std::map<cmLinkItem, int>::iterator cmComputeLinkDepends::AllocateLinkEntry(
+ cmLinkItem const& item)
+{
+ std::map<cmLinkItem, int>::value_type index_entry(
+ item, static_cast<int>(this->EntryList.size()));
+ auto lei = this->LinkEntryIndex.insert(index_entry).first;
+ this->EntryList.emplace_back();
+ this->InferredDependSets.emplace_back();
+ this->EntryConstraintGraph.emplace_back();
+ return lei;
+}
+
+int cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item)
+{
+ // Check if the item entry has already been added.
+ auto lei = this->LinkEntryIndex.find(item);
+ if (lei != this->LinkEntryIndex.end()) {
+ // Yes. We do not need to follow the item's dependencies again.
+ return lei->second;
+ }
+
+ // Allocate a spot for the item entry.
+ lei = this->AllocateLinkEntry(item);
+
+ // Initialize the item entry.
+ int index = lei->second;
+ LinkEntry& entry = this->EntryList[index];
+ entry.Item = BT<std::string>(item.AsStr(), item.Backtrace);
+ entry.Target = item.Target;
+ entry.IsFlag = (!entry.Target && entry.Item.Value[0] == '-' &&
+ entry.Item.Value[1] != 'l' &&
+ entry.Item.Value.substr(0, 10) != "-framework");
+
+ // If the item has dependencies queue it to follow them.
+ if (entry.Target) {
+ // Target dependencies are always known. Follow them.
+ BFSEntry qe = { index, nullptr };
+ this->BFSQueue.push(qe);
+ } else {
+ // Look for an old-style <item>_LIB_DEPENDS variable.
+ std::string var = cmStrCat(entry.Item.Value, "_LIB_DEPENDS");
+ if (cmProp val = this->Makefile->GetDefinition(var)) {
+ // The item dependencies are known. Follow them.
+ BFSEntry qe = { index, val->c_str() };
+ this->BFSQueue.push(qe);
+ } else if (!entry.IsFlag) {
+ // The item dependencies are not known. We need to infer them.
+ this->InferredDependSets[index].Initialized = true;
+ }
+ }
+
+ return index;
+}
+
+void cmComputeLinkDepends::FollowLinkEntry(BFSEntry qe)
+{
+ // Get this entry representation.
+ int depender_index = qe.Index;
+ LinkEntry const& entry = this->EntryList[depender_index];
+
+ // Follow the item's dependencies.
+ if (entry.Target) {
+ // Follow the target dependencies.
+ if (cmLinkInterface const* iface =
+ entry.Target->GetLinkInterface(this->Config, this->Target)) {
+ const bool isIface =
+ entry.Target->GetType() == cmStateEnums::INTERFACE_LIBRARY;
+ // This target provides its own link interface information.
+ this->AddLinkEntries(depender_index, iface->Libraries);
+
+ if (isIface) {
+ return;
+ }
+
+ // Handle dependent shared libraries.
+ this->FollowSharedDeps(depender_index, iface);
+
+ // Support for CMP0003.
+ for (cmLinkItem const& oi : iface->WrongConfigLibraries) {
+ this->CheckWrongConfigItem(oi);
+ }
+ }
+ } else {
+ // Follow the old-style dependency list.
+ this->AddVarLinkEntries(depender_index, qe.LibDepends);
+ }
+}
+
+void cmComputeLinkDepends::FollowSharedDeps(int depender_index,
+ cmLinkInterface const* iface,
+ bool follow_interface)
+{
+ // Follow dependencies if we have not followed them already.
+ if (this->SharedDepFollowed.insert(depender_index).second) {
+ if (follow_interface) {
+ this->QueueSharedDependencies(depender_index, iface->Libraries);
+ }
+ this->QueueSharedDependencies(depender_index, iface->SharedDeps);
+ }
+}
+
+void cmComputeLinkDepends::QueueSharedDependencies(
+ int depender_index, std::vector<cmLinkItem> const& deps)
+{
+ for (cmLinkItem const& li : deps) {
+ SharedDepEntry qe;
+ qe.Item = li;
+ qe.DependerIndex = depender_index;
+ this->SharedDepQueue.push(qe);
+ }
+}
+
+void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep)
+{
+ // Check if the target already has an entry.
+ auto lei = this->LinkEntryIndex.find(dep.Item);
+ if (lei == this->LinkEntryIndex.end()) {
+ // Allocate a spot for the item entry.
+ lei = this->AllocateLinkEntry(dep.Item);
+
+ // Initialize the item entry.
+ LinkEntry& entry = this->EntryList[lei->second];
+ entry.Item = BT<std::string>(dep.Item.AsStr(), dep.Item.Backtrace);
+ entry.Target = dep.Item.Target;
+
+ // This item was added specifically because it is a dependent
+ // shared library. It may get special treatment
+ // in cmComputeLinkInformation.
+ entry.IsSharedDep = true;
+ }
+
+ // Get the link entry for this target.
+ int index = lei->second;
+ LinkEntry& entry = this->EntryList[index];
+
+ // This shared library dependency must follow the item that listed
+ // it.
+ this->EntryConstraintGraph[dep.DependerIndex].emplace_back(
+ index, true, false, cmListFileBacktrace());
+
+ // Target items may have their own dependencies.
+ if (entry.Target) {
+ if (cmLinkInterface const* iface =
+ entry.Target->GetLinkInterface(this->Config, this->Target)) {
+ // Follow public and private dependencies transitively.
+ this->FollowSharedDeps(index, iface, true);
+ }
+ }
+}
+
+void cmComputeLinkDepends::AddVarLinkEntries(int depender_index,
+ const char* value)
+{
+ // This is called to add the dependencies named by
+ // <item>_LIB_DEPENDS. The variable contains a semicolon-separated
+ // list. The list contains link-type;item pairs and just items.
+ std::vector<std::string> deplist = cmExpandedList(value);
+
+ // Look for entries meant for this configuration.
+ std::vector<cmLinkItem> actual_libs;
+ cmTargetLinkLibraryType llt = GENERAL_LibraryType;
+ bool haveLLT = false;
+ for (std::string const& d : deplist) {
+ if (d == "debug") {
+ llt = DEBUG_LibraryType;
+ haveLLT = true;
+ } else if (d == "optimized") {
+ llt = OPTIMIZED_LibraryType;
+ haveLLT = true;
+ } else if (d == "general") {
+ llt = GENERAL_LibraryType;
+ haveLLT = true;
+ } else if (!d.empty()) {
+ // If no explicit link type was given prior to this entry then
+ // check if the entry has its own link type variable. This is
+ // needed for compatibility with dependency files generated by
+ // the export_library_dependencies command from CMake 2.4 and
+ // lower.
+ if (!haveLLT) {
+ std::string var = cmStrCat(d, "_LINK_TYPE");
+ if (cmProp val = this->Makefile->GetDefinition(var)) {
+ if (*val == "debug") {
+ llt = DEBUG_LibraryType;
+ } else if (*val == "optimized") {
+ llt = OPTIMIZED_LibraryType;
+ }
+ }
+ }
+
+ // If the library is meant for this link type then use it.
+ if (llt == GENERAL_LibraryType || llt == this->LinkType) {
+ actual_libs.emplace_back(this->ResolveLinkItem(depender_index, d));
+ } else if (this->OldLinkDirMode) {
+ cmLinkItem item = this->ResolveLinkItem(depender_index, d);
+ this->CheckWrongConfigItem(item);
+ }
+
+ // Reset the link type until another explicit type is given.
+ llt = GENERAL_LibraryType;
+ haveLLT = false;
+ }
+ }
+
+ // Add the entries from this list.
+ this->AddLinkEntries(depender_index, actual_libs);
+}
+
+void cmComputeLinkDepends::AddDirectLinkEntries()
+{
+ // Add direct link dependencies in this configuration.
+ cmLinkImplementation const* impl =
+ this->Target->GetLinkImplementation(this->Config);
+ this->AddLinkEntries(-1, impl->Libraries);
+ for (cmLinkItem const& wi : impl->WrongConfigLibraries) {
+ this->CheckWrongConfigItem(wi);
+ }
+}
+
+template <typename T>
+void cmComputeLinkDepends::AddLinkEntries(int depender_index,
+ std::vector<T> const& libs)
+{
+ // Track inferred dependency sets implied by this list.
+ std::map<int, DependSet> dependSets;
+
+ // Loop over the libraries linked directly by the depender.
+ for (T const& l : libs) {
+ // Skip entries that will resolve to the target getting linked or
+ // are empty.
+ cmLinkItem const& item = l;
+ if (item.AsStr() == this->Target->GetName() || item.AsStr().empty()) {
+ continue;
+ }
+
+ // Add a link entry for this item.
+ int dependee_index = this->AddLinkEntry(l);
+
+ // The dependee must come after the depender.
+ if (depender_index >= 0) {
+ this->EntryConstraintGraph[depender_index].emplace_back(
+ dependee_index, false, false, cmListFileBacktrace());
+ } else {
+ // This is a direct dependency of the target being linked.
+ this->OriginalEntries.push_back(dependee_index);
+ }
+
+ // Update the inferred dependencies for earlier items.
+ for (auto& dependSet : dependSets) {
+ // Add this item to the inferred dependencies of other items.
+ // Target items are never inferred dependees because unknown
+ // items are outside libraries that should not be depending on
+ // targets.
+ if (!this->EntryList[dependee_index].Target &&
+ !this->EntryList[dependee_index].IsFlag &&
+ dependee_index != dependSet.first) {
+ dependSet.second.insert(dependee_index);
+ }
+ }
+
+ // If this item needs to have dependencies inferred, do so.
+ if (this->InferredDependSets[dependee_index].Initialized) {
+ // Make sure an entry exists to hold the set for the item.
+ dependSets[dependee_index];
+ }
+ }
+
+ // Store the inferred dependency sets discovered for this list.
+ for (auto const& dependSet : dependSets) {
+ this->InferredDependSets[dependSet.first].push_back(dependSet.second);
+ }
+}
+
+cmLinkItem cmComputeLinkDepends::ResolveLinkItem(int depender_index,
+ const std::string& name)
+{
+ // Look for a target in the scope of the depender.
+ cmGeneratorTarget const* from = this->Target;
+ if (depender_index >= 0) {
+ if (cmGeneratorTarget const* depender =
+ this->EntryList[depender_index].Target) {
+ from = depender;
+ }
+ }
+ return from->ResolveLinkItem(name, cmListFileBacktrace());
+}
+
+void cmComputeLinkDepends::InferDependencies()
+{
+ // The inferred dependency sets for each item list the possible
+ // dependencies. The intersection of the sets for one item form its
+ // inferred dependencies.
+ for (unsigned int depender_index = 0;
+ depender_index < this->InferredDependSets.size(); ++depender_index) {
+ // Skip items for which dependencies do not need to be inferred or
+ // for which the inferred dependency sets are empty.
+ DependSetList& sets = this->InferredDependSets[depender_index];
+ if (!sets.Initialized || sets.empty()) {
+ continue;
+ }
+
+ // Intersect the sets for this item.
+ DependSet common = sets.front();
+ for (DependSet const& i : cmMakeRange(sets).advance(1)) {
+ DependSet intersection;
+ std::set_intersection(common.begin(), common.end(), i.begin(), i.end(),
+ std::inserter(intersection, intersection.begin()));
+ common = intersection;
+ }
+
+ // Add the inferred dependencies to the graph.
+ cmGraphEdgeList& edges = this->EntryConstraintGraph[depender_index];
+ edges.reserve(edges.size() + common.size());
+ for (auto const& c : common) {
+ edges.emplace_back(c, true, false, cmListFileBacktrace());
+ }
+ }
+}
+
+void cmComputeLinkDepends::CleanConstraintGraph()
+{
+ for (cmGraphEdgeList& edgeList : this->EntryConstraintGraph) {
+ // Sort the outgoing edges for each graph node so that the
+ // original order will be preserved as much as possible.
+ std::sort(edgeList.begin(), edgeList.end());
+
+ // Make the edge list unique.
+ edgeList.erase(std::unique(edgeList.begin(), edgeList.end()),
+ edgeList.end());
+ }
+}
+
+void cmComputeLinkDepends::DisplayConstraintGraph()
+{
+ // Display the graph nodes and their edges.
+ std::ostringstream e;
+ for (unsigned int i = 0; i < this->EntryConstraintGraph.size(); ++i) {
+ EdgeList const& nl = this->EntryConstraintGraph[i];
+ e << "item " << i << " is [" << this->EntryList[i].Item << "]\n";
+ e << cmWrap(" item ", nl, " must follow it", "\n") << "\n";
+ }
+ fprintf(stderr, "%s\n", e.str().c_str());
+}
+
+void cmComputeLinkDepends::OrderLinkEntires()
+{
+ // Compute the DAG of strongly connected components. The algorithm
+ // used by cmComputeComponentGraph should identify the components in
+ // the same order in which the items were originally discovered in
+ // the BFS. This should preserve the original order when no
+ // constraints disallow it.
+ this->CCG =
+ cm::make_unique<cmComputeComponentGraph>(this->EntryConstraintGraph);
+ this->CCG->Compute();
+
+ // The component graph is guaranteed to be acyclic. Start a DFS
+ // from every entry to compute a topological order for the
+ // components.
+ Graph const& cgraph = this->CCG->GetComponentGraph();
+ int n = static_cast<int>(cgraph.size());
+ this->ComponentVisited.resize(cgraph.size(), 0);
+ this->ComponentOrder.resize(cgraph.size(), n);
+ this->ComponentOrderId = n;
+ // Run in reverse order so the topological order will preserve the
+ // original order where there are no constraints.
+ for (int c = n - 1; c >= 0; --c) {
+ this->VisitComponent(c);
+ }
+
+ // Display the component graph.
+ if (this->DebugMode) {
+ this->DisplayComponents();
+ }
+
+ // Start with the original link line.
+ for (int originalEntry : this->OriginalEntries) {
+ this->VisitEntry(originalEntry);
+ }
+
+ // Now explore anything left pending. Since the component graph is
+ // guaranteed to be acyclic we know this will terminate.
+ while (!this->PendingComponents.empty()) {
+ // Visit one entry from the first pending component. The visit
+ // logic will update the pending components accordingly. Since
+ // the pending components are kept in topological order this will
+ // not repeat one.
+ int e = *this->PendingComponents.begin()->second.Entries.begin();
+ this->VisitEntry(e);
+ }
+}
+
+void cmComputeLinkDepends::DisplayComponents()
+{
+ fprintf(stderr, "The strongly connected components are:\n");
+ std::vector<NodeList> const& components = this->CCG->GetComponents();
+ for (unsigned int c = 0; c < components.size(); ++c) {
+ fprintf(stderr, "Component (%u):\n", c);
+ NodeList const& nl = components[c];
+ for (int i : nl) {
+ fprintf(stderr, " item %d [%s]\n", i,
+ this->EntryList[i].Item.Value.c_str());
+ }
+ EdgeList const& ol = this->CCG->GetComponentGraphEdges(c);
+ for (cmGraphEdge const& oi : ol) {
+ int i = oi;
+ fprintf(stderr, " followed by Component (%d)\n", i);
+ }
+ fprintf(stderr, " topo order index %d\n", this->ComponentOrder[c]);
+ }
+ fprintf(stderr, "\n");
+}
+
+void cmComputeLinkDepends::VisitComponent(unsigned int c)
+{
+ // Check if the node has already been visited.
+ if (this->ComponentVisited[c]) {
+ return;
+ }
+
+ // We are now visiting this component so mark it.
+ this->ComponentVisited[c] = 1;
+
+ // Visit the neighbors of the component first.
+ // Run in reverse order so the topological order will preserve the
+ // original order where there are no constraints.
+ EdgeList const& nl = this->CCG->GetComponentGraphEdges(c);
+ for (cmGraphEdge const& edge : cmReverseRange(nl)) {
+ this->VisitComponent(edge);
+ }
+
+ // Assign an ordering id to this component.
+ this->ComponentOrder[c] = --this->ComponentOrderId;
+}
+
+void cmComputeLinkDepends::VisitEntry(int index)
+{
+ // Include this entry on the link line.
+ this->FinalLinkOrder.push_back(index);
+
+ // This entry has now been seen. Update its component.
+ bool completed = false;
+ int component = this->CCG->GetComponentMap()[index];
+ auto mi = this->PendingComponents.find(this->ComponentOrder[component]);
+ if (mi != this->PendingComponents.end()) {
+ // The entry is in an already pending component.
+ PendingComponent& pc = mi->second;
+
+ // Remove the entry from those pending in its component.
+ pc.Entries.erase(index);
+ if (pc.Entries.empty()) {
+ // The complete component has been seen since it was last needed.
+ --pc.Count;
+
+ if (pc.Count == 0) {
+ // The component has been completed.
+ this->PendingComponents.erase(mi);
+ completed = true;
+ } else {
+ // The whole component needs to be seen again.
+ NodeList const& nl = this->CCG->GetComponent(component);
+ assert(nl.size() > 1);
+ pc.Entries.insert(nl.begin(), nl.end());
+ }
+ }
+ } else {
+ // The entry is not in an already pending component.
+ NodeList const& nl = this->CCG->GetComponent(component);
+ if (nl.size() > 1) {
+ // This is a non-trivial component. It is now pending.
+ PendingComponent& pc = this->MakePendingComponent(component);
+
+ // The starting entry has already been seen.
+ pc.Entries.erase(index);
+ } else {
+ // This is a trivial component, so it is already complete.
+ completed = true;
+ }
+ }
+
+ // If the entry completed a component, the component's dependencies
+ // are now pending.
+ if (completed) {
+ EdgeList const& ol = this->CCG->GetComponentGraphEdges(component);
+ for (cmGraphEdge const& oi : ol) {
+ // This entire component is now pending no matter whether it has
+ // been partially seen already.
+ this->MakePendingComponent(oi);
+ }
+ }
+}
+
+cmComputeLinkDepends::PendingComponent&
+cmComputeLinkDepends::MakePendingComponent(unsigned int component)
+{
+ // Create an entry (in topological order) for the component.
+ PendingComponent& pc =
+ this->PendingComponents[this->ComponentOrder[component]];
+ pc.Id = component;
+ NodeList const& nl = this->CCG->GetComponent(component);
+
+ if (nl.size() == 1) {
+ // Trivial components need be seen only once.
+ pc.Count = 1;
+ } else {
+ // This is a non-trivial strongly connected component of the
+ // original graph. It consists of two or more libraries
+ // (archives) that mutually require objects from one another. In
+ // the worst case we may have to repeat the list of libraries as
+ // many times as there are object files in the biggest archive.
+ // For now we just list them twice.
+ //
+ // The list of items in the component has been sorted by the order
+ // of discovery in the original BFS of dependencies. This has the
+ // advantage that the item directly linked by a target requiring
+ // this component will come first which minimizes the number of
+ // repeats needed.
+ pc.Count = this->ComputeComponentCount(nl);
+ }
+
+ // Store the entries to be seen.
+ pc.Entries.insert(nl.begin(), nl.end());
+
+ return pc;
+}
+
+int cmComputeLinkDepends::ComputeComponentCount(NodeList const& nl)
+{
+ unsigned int count = 2;
+ for (int ni : nl) {
+ if (cmGeneratorTarget const* target = this->EntryList[ni].Target) {
+ if (cmLinkInterface const* iface =
+ target->GetLinkInterface(this->Config, this->Target)) {
+ if (iface->Multiplicity > count) {
+ count = iface->Multiplicity;
+ }
+ }
+ }
+ }
+ return count;
+}
+
+void cmComputeLinkDepends::DisplayFinalEntries()
+{
+ fprintf(stderr, "target [%s] links to:\n", this->Target->GetName().c_str());
+ for (LinkEntry const& lei : this->FinalLinkEntries) {
+ if (lei.Target) {
+ fprintf(stderr, " target [%s]\n", lei.Target->GetName().c_str());
+ } else {
+ fprintf(stderr, " item [%s]\n", lei.Item.Value.c_str());
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
+void cmComputeLinkDepends::CheckWrongConfigItem(cmLinkItem const& item)
+{
+ if (!this->OldLinkDirMode) {
+ return;
+ }
+
+ // For CMake 2.4 bug-compatibility we need to consider the output
+ // directories of targets linked in another configuration as link
+ // directories.
+ if (item.Target && !item.Target->IsImported()) {
+ this->OldWrongConfigItems.insert(item.Target);
+ }
+}
diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h
new file mode 100644
index 0000000..902500a
--- /dev/null
+++ b/Source/cmComputeLinkDepends.h
@@ -0,0 +1,161 @@
+/* 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 <map>
+#include <memory>
+#include <queue>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmGraphAdjacencyList.h"
+#include "cmLinkItem.h"
+#include "cmListFileCache.h"
+#include "cmTargetLinkLibraryType.h"
+
+class cmComputeComponentGraph;
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmMakefile;
+class cmake;
+
+/** \class cmComputeLinkDepends
+ * \brief Compute link dependencies for targets.
+ */
+class cmComputeLinkDepends
+{
+public:
+ cmComputeLinkDepends(cmGeneratorTarget const* target,
+ const std::string& config);
+ ~cmComputeLinkDepends();
+
+ cmComputeLinkDepends(const cmComputeLinkDepends&) = delete;
+ cmComputeLinkDepends& operator=(const cmComputeLinkDepends&) = delete;
+
+ // Basic information about each link item.
+ struct LinkEntry
+ {
+ BT<std::string> Item;
+ cmGeneratorTarget const* Target = nullptr;
+ bool IsSharedDep = false;
+ bool IsFlag = false;
+ };
+
+ using EntryVector = std::vector<LinkEntry>;
+ EntryVector const& Compute();
+
+ void SetOldLinkDirMode(bool b);
+ std::set<cmGeneratorTarget const*> const& GetOldWrongConfigItems() const
+ {
+ return this->OldWrongConfigItems;
+ }
+
+private:
+ // Context information.
+ cmGeneratorTarget const* Target;
+ cmMakefile* Makefile;
+ cmGlobalGenerator const* GlobalGenerator;
+ cmake* CMakeInstance;
+ std::string Config;
+ EntryVector FinalLinkEntries;
+
+ std::map<cmLinkItem, int>::iterator AllocateLinkEntry(
+ cmLinkItem const& item);
+ int AddLinkEntry(cmLinkItem const& item);
+ void AddVarLinkEntries(int depender_index, const char* value);
+ void AddDirectLinkEntries();
+ template <typename T>
+ void AddLinkEntries(int depender_index, std::vector<T> const& libs);
+ cmLinkItem ResolveLinkItem(int depender_index, const std::string& name);
+
+ // One entry for each unique item.
+ std::vector<LinkEntry> EntryList;
+ std::map<cmLinkItem, int> LinkEntryIndex;
+
+ // BFS of initial dependencies.
+ struct BFSEntry
+ {
+ int Index;
+ const char* LibDepends;
+ };
+ std::queue<BFSEntry> BFSQueue;
+ void FollowLinkEntry(BFSEntry qe);
+
+ // Shared libraries that are included only because they are
+ // dependencies of other shared libraries, not because they are part
+ // of the interface.
+ struct SharedDepEntry
+ {
+ cmLinkItem Item;
+ int DependerIndex;
+ };
+ std::queue<SharedDepEntry> SharedDepQueue;
+ std::set<int> SharedDepFollowed;
+ void FollowSharedDeps(int depender_index, cmLinkInterface const* iface,
+ bool follow_interface = false);
+ void QueueSharedDependencies(int depender_index,
+ std::vector<cmLinkItem> const& deps);
+ void HandleSharedDependency(SharedDepEntry const& dep);
+
+ // Dependency inferral for each link item.
+ struct DependSet : public std::set<int>
+ {
+ };
+ struct DependSetList : public std::vector<DependSet>
+ {
+ bool Initialized = false;
+ };
+ std::vector<DependSetList> InferredDependSets;
+ void InferDependencies();
+
+ // Ordering constraint graph adjacency list.
+ using NodeList = cmGraphNodeList;
+ using EdgeList = cmGraphEdgeList;
+ using Graph = cmGraphAdjacencyList;
+ Graph EntryConstraintGraph;
+ void CleanConstraintGraph();
+ void DisplayConstraintGraph();
+
+ // Ordering algorithm.
+ void OrderLinkEntires();
+ std::vector<char> ComponentVisited;
+ std::vector<int> ComponentOrder;
+
+ struct PendingComponent
+ {
+ // The real component id. Needed because the map is indexed by
+ // component topological index.
+ int Id;
+
+ // The number of times the component needs to be seen. This is
+ // always 1 for trivial components and is initially 2 for
+ // non-trivial components.
+ int Count;
+
+ // The entries yet to be seen to complete the component.
+ std::set<int> Entries;
+ };
+ std::map<int, PendingComponent> PendingComponents;
+ std::unique_ptr<cmComputeComponentGraph> CCG;
+ std::vector<int> FinalLinkOrder;
+ void DisplayComponents();
+ void VisitComponent(unsigned int c);
+ void VisitEntry(int index);
+ PendingComponent& MakePendingComponent(unsigned int component);
+ int ComputeComponentCount(NodeList const& nl);
+ void DisplayFinalEntries();
+
+ // Record of the original link line.
+ std::vector<int> OriginalEntries;
+ std::set<cmGeneratorTarget const*> OldWrongConfigItems;
+ void CheckWrongConfigItem(cmLinkItem const& item);
+
+ int ComponentOrderId;
+ cmTargetLinkLibraryType LinkType;
+ bool HasConfig;
+ bool DebugMode;
+ bool OldLinkDirMode;
+};
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
new file mode 100644
index 0000000..5473316
--- /dev/null
+++ b/Source/cmComputeLinkInformation.cxx
@@ -0,0 +1,1897 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmComputeLinkInformation.h"
+
+#include <algorithm>
+#include <cctype>
+#include <sstream>
+#include <utility>
+
+#include <cm/memory>
+#include <cmext/algorithm>
+
+#include "cmComputeLinkDepends.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOrderDirectories.h"
+#include "cmOutputConverter.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmake.h"
+
+//#define CM_COMPUTE_LINK_INFO_DEBUG
+
+/*
+Notes about linking on various platforms:
+
+------------------------------------------------------------------------------
+
+Linux, FreeBSD, macOS, Sun, Windows:
+
+Linking to libraries using the full path works fine.
+
+------------------------------------------------------------------------------
+
+On AIX, more work is needed.
+
+ The "-bnoipath" option is needed. From "man ld":
+
+ Note: If you specify a shared object, or an archive file
+ containing a shared object, with an absolute or relative path
+ name, instead of with the -lName flag, the path name is
+ included in the import file ID string in the loader section of
+ the output file. You can override this behavior with the
+ -bnoipath option.
+
+ noipath
+
+ For shared objects listed on the command-line, rather than
+ specified with the -l flag, use a null path component when
+ listing the shared object in the loader section of the
+ output file. A null path component is always used for
+ shared objects specified with the -l flag. This option
+ does not affect the specification of a path component by
+ using a line beginning with #! in an import file. The
+ default is the ipath option.
+
+ This prevents the full path specified on the compile line from being
+ compiled directly into the binary.
+
+ By default the linker places -L paths in the embedded runtime path.
+ In order to implement CMake's RPATH interface correctly, we need the
+ -blibpath:Path option. From "man ld":
+
+ libpath:Path
+
+ Uses Path as the library path when writing the loader section
+ of the output file. Path is neither checked for validity nor
+ used when searching for libraries specified by the -l flag.
+ Path overrides any library paths generated when the -L flag is
+ used.
+
+ If you do not specify any -L flags, or if you specify the
+ nolibpath option, the default library path information is
+ written in the loader section of the output file. The default
+ library path information is the value of the LIBPATH
+ environment variable if it is defined, and /usr/lib:/lib,
+ otherwise.
+
+ We can pass -Wl,-blibpath:/usr/lib:/lib always to avoid the -L stuff
+ and not break when the user sets LIBPATH. Then if we want to add an
+ rpath we insert it into the option before /usr/lib.
+
+------------------------------------------------------------------------------
+
+On HP-UX, more work is needed. There are differences between
+versions.
+
+ld: 92453-07 linker linker ld B.10.33 990520
+
+ Linking with a full path works okay for static and shared libraries.
+ The linker seems to always put the full path to where the library
+ was found in the binary whether using a full path or -lfoo syntax.
+ Transitive link dependencies work just fine due to the full paths.
+
+ It has the "-l:libfoo.sl" option. The +nodefaultrpath is accepted
+ but not documented and does not seem to do anything. There is no
+ +forceload option.
+
+ld: 92453-07 linker ld HP Itanium(R) B.12.41 IPF/IPF
+
+ Linking with a full path works okay for static libraries.
+
+ Linking with a full path works okay for shared libraries. However
+ dependent (transitive) libraries of those linked directly must be
+ either found with an rpath stored in the direct dependencies or
+ found in -L paths as if they were specified with "-l:libfoo.sl"
+ (really "-l:<soname>"). The search matches that of the dynamic
+ loader but only with -L paths. In other words, if we have an
+ executable that links to shared library bar which links to shared
+ library foo, the link line for the exe must contain
+
+ /dir/with/bar/libbar.sl -L/dir/with/foo
+
+ It does not matter whether the exe wants to link to foo directly or
+ whether /dir/with/foo/libfoo.sl is listed. The -L path must still
+ be present. It should match the runtime path computed for the
+ executable taking all directly and transitively linked libraries
+ into account.
+
+ The "+nodefaultrpath" option should be used to avoid getting -L
+ paths in the rpath unless we add our own rpath with +b. This means
+ that skip-build-rpath should use this option.
+
+ See documentation in "man ld", "man dld.so", and
+ http://docs.hp.com/en/B2355-90968/creatingandusinglibraries.htm
+
+ +[no]defaultrpath
+ +defaultrpath is the default. Include any paths that are
+ specified with -L in the embedded path, unless you specify the
+ +b option. If you use +b, only the path list specified by +b is
+ in the embedded path.
+
+ The +nodefaultrpath option removes all library paths that were
+ specified with the -L option from the embedded path. The linker
+ searches the library paths specified by the -L option at link
+ time. At run time, the only library paths searched are those
+ specified by the environment variables LD_LIBRARY_PATH and
+ SHLIB_PATH, library paths specified by the +b linker option, and
+ finally the default library paths.
+
+ +rpathfirst
+ This option will cause the paths specified in RPATH (embedded
+ path) to be used before the paths specified in LD_LIBRARY_PATH
+ or SHLIB_PATH, in searching for shared libraries. This changes
+ the default search order of LD_LIBRARY_PATH, SHLIB_PATH, and
+ RPATH (embedded path).
+
+------------------------------------------------------------------------------
+Notes about dependent (transitive) shared libraries:
+
+On non-Windows systems shared libraries may have transitive
+dependencies. In order to support LINK_INTERFACE_LIBRARIES we must
+support linking to a shared library without listing all the libraries
+to which it links. Some linkers want to be able to find the
+transitive dependencies (dependent libraries) of shared libraries
+listed on the command line.
+
+ - On Windows, DLLs are not directly linked, and the import libraries
+ have no transitive dependencies.
+
+ - On Mac OS X 10.5 and above transitive dependencies are not needed.
+
+ - On Mac OS X 10.4 and below we need to actually list the dependencies.
+ Otherwise when using -isysroot for universal binaries it cannot
+ find the dependent libraries. Listing them on the command line
+ tells the linker where to find them, but unfortunately also links
+ the library.
+
+ - On HP-UX, the linker wants to find the transitive dependencies of
+ shared libraries in the -L paths even if the dependent libraries
+ are given on the link line.
+
+ - On AIX the transitive dependencies are not needed.
+
+ - On SGI, the linker wants to find the transitive dependencies of
+ shared libraries in the -L paths if they are not given on the link
+ line. Transitive linking can be disabled using the options
+
+ -no_transitive_link -Wl,-no_transitive_link
+
+ which disable it. Both options must be given when invoking the
+ linker through the compiler.
+
+ - On Sun, the linker wants to find the transitive dependencies of
+ shared libraries in the -L paths if they are not given on the link
+ line.
+
+ - On Linux, FreeBSD, and QNX:
+
+ The linker wants to find the transitive dependencies of shared
+ libraries in the "-rpath-link" paths option if they have not been
+ given on the link line. The option is like rpath but just for
+ link time:
+
+ -Wl,-rpath-link,"/path1:/path2"
+
+For -rpath-link, we need a separate runtime path ordering pass
+including just the dependent libraries that are not linked.
+
+For -L paths on non-HP, we can do the same thing as with rpath-link
+but put the results in -L paths. The paths should be listed at the
+end to avoid conflicting with user search paths (?).
+
+For -L paths on HP, we should do a runtime path ordering pass with
+all libraries, both linked and non-linked. Even dependent
+libraries that are also linked need to be listed in -L paths.
+
+In our implementation we add all dependent libraries to the runtime
+path computation. Then the auto-generated RPATH will find everything.
+
+------------------------------------------------------------------------------
+Notes about shared libraries with not builtin soname:
+
+Some UNIX shared libraries may be created with no builtin soname. On
+some platforms such libraries cannot be linked using the path to their
+location because the linker will copy the path into the field used to
+find the library at runtime.
+
+ Apple: ../libfoo.dylib ==> libfoo.dylib # ok, uses install_name
+ SGI: ../libfoo.so ==> libfoo.so # ok
+ AIX: ../libfoo.so ==> libfoo.so # ok
+ Linux: ../libfoo.so ==> ../libfoo.so # bad
+ HP-UX: ../libfoo.so ==> ../libfoo.so # bad
+ Sun: ../libfoo.so ==> ../libfoo.so # bad
+ FreeBSD: ../libfoo.so ==> ../libfoo.so # bad
+
+In order to link these libraries we need to use the old-style split
+into -L.. and -lfoo options. This should be fairly safe because most
+problems with -lfoo options were related to selecting shared libraries
+instead of static but in this case we want the shared lib. Link
+directory ordering needs to be done to make sure these shared
+libraries are found first. There should be very few restrictions
+because this need be done only for shared libraries without soname-s.
+
+*/
+
+cmComputeLinkInformation::cmComputeLinkInformation(
+ const cmGeneratorTarget* target, const std::string& config)
+ // Store context information.
+ : Target(target)
+ , Makefile(target->Target->GetMakefile())
+ , GlobalGenerator(target->GetLocalGenerator()->GetGlobalGenerator())
+ , CMakeInstance(this->GlobalGenerator->GetCMakeInstance())
+ // The configuration being linked.
+ , Config(config)
+{
+ // Check whether to recognize OpenBSD-style library versioned names.
+ this->OpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "FIND_LIBRARY_USE_OPENBSD_VERSIONING");
+
+ // Allocate internals.
+ this->OrderLinkerSearchPath = cm::make_unique<cmOrderDirectories>(
+ this->GlobalGenerator, target, "linker search path");
+ this->OrderRuntimeSearchPath = cm::make_unique<cmOrderDirectories>(
+ this->GlobalGenerator, target, "runtime search path");
+
+ // Get the language used for linking this target.
+ this->LinkLanguage = this->Target->GetLinkerLanguage(config);
+ if (this->LinkLanguage.empty()) {
+ // The Compute method will do nothing, so skip the rest of the
+ // initialization.
+ return;
+ }
+
+ // Check whether we should skip dependencies on shared library files.
+ this->LinkDependsNoShared =
+ this->Target->GetPropertyAsBool("LINK_DEPENDS_NO_SHARED");
+
+ // On platforms without import libraries there may be a special flag
+ // to use when creating a plugin (module) that obtains symbols from
+ // the program that will load it.
+ this->LoaderFlag = nullptr;
+ if (!this->Target->IsDLLPlatform() &&
+ this->Target->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ std::string loader_flag_var =
+ cmStrCat("CMAKE_SHARED_MODULE_LOADER_", this->LinkLanguage, "_FLAG");
+ this->LoaderFlag =
+ cmToCStr(this->Makefile->GetDefinition(loader_flag_var));
+ }
+
+ // Get options needed to link libraries.
+ if (cmProp flag = this->Makefile->GetDefinition(
+ "CMAKE_" + this->LinkLanguage + "_LINK_LIBRARY_FLAG")) {
+ this->LibLinkFlag = *flag;
+ } else {
+ this->LibLinkFlag =
+ this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG");
+ }
+ if (cmProp flag = this->Makefile->GetDefinition(
+ "CMAKE_" + this->LinkLanguage + "_LINK_LIBRARY_FILE_FLAG")) {
+ this->LibLinkFileFlag = *flag;
+ } else {
+ this->LibLinkFileFlag =
+ this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FILE_FLAG");
+ }
+ if (cmProp suffix = this->Makefile->GetDefinition(
+ "CMAKE_" + this->LinkLanguage + "_LINK_LIBRARY_SUFFIX")) {
+ this->LibLinkSuffix = *suffix;
+ } else {
+ this->LibLinkSuffix =
+ this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
+ }
+
+ // Get options needed to specify RPATHs.
+ this->RuntimeUseChrpath = false;
+ if (this->Target->GetType() != cmStateEnums::STATIC_LIBRARY) {
+ const char* tType = ((this->Target->GetType() == cmStateEnums::EXECUTABLE)
+ ? "EXECUTABLE"
+ : "SHARED_LIBRARY");
+ std::string rtVar =
+ cmStrCat("CMAKE_", tType, "_RUNTIME_", this->LinkLanguage, "_FLAG");
+ std::string rtSepVar = rtVar + "_SEP";
+ this->RuntimeFlag = this->Makefile->GetSafeDefinition(rtVar);
+ this->RuntimeSep = this->Makefile->GetSafeDefinition(rtSepVar);
+ this->RuntimeAlways = (this->Makefile->GetSafeDefinition(
+ "CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH"));
+
+ this->RuntimeUseChrpath = this->Target->IsChrpathUsed(config);
+
+ // Get options needed to help find dependent libraries.
+ std::string rlVar =
+ cmStrCat("CMAKE_", tType, "_RPATH_LINK_", this->LinkLanguage, "_FLAG");
+ this->RPathLinkFlag = this->Makefile->GetSafeDefinition(rlVar);
+ }
+
+ // Check if we need to include the runtime search path at link time.
+ {
+ std::string var = cmStrCat("CMAKE_SHARED_LIBRARY_LINK_",
+ this->LinkLanguage, "_WITH_RUNTIME_PATH");
+ this->LinkWithRuntimePath = this->Makefile->IsOn(var);
+ }
+
+ // Check the platform policy for missing soname case.
+ this->NoSONameUsesPath =
+ this->Makefile->IsOn("CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME");
+
+ // Get link type information.
+ this->ComputeLinkTypeInfo();
+
+ // Setup the link item parser.
+ this->ComputeItemParserInfo();
+
+ // Setup framework support.
+ this->ComputeFrameworkInfo();
+
+ // Choose a mode for dealing with shared library dependencies.
+ this->SharedDependencyMode = SharedDepModeNone;
+ if (this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_FILES")) {
+ this->SharedDependencyMode = SharedDepModeLink;
+ } else if (this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_DIRS")) {
+ this->SharedDependencyMode = SharedDepModeLibDir;
+ } else if (!this->RPathLinkFlag.empty()) {
+ this->SharedDependencyMode = SharedDepModeDir;
+ this->OrderDependentRPath = cm::make_unique<cmOrderDirectories>(
+ this->GlobalGenerator, target, "dependent library path");
+ }
+
+ // Add the search path entries requested by the user to path ordering.
+ std::vector<std::string> directories;
+ this->Target->GetLinkDirectories(directories, config, this->LinkLanguage);
+ this->OrderLinkerSearchPath->AddUserDirectories(directories);
+ this->OrderRuntimeSearchPath->AddUserDirectories(directories);
+
+ // Set up the implicit link directories.
+ this->LoadImplicitLinkInfo();
+ this->OrderLinkerSearchPath->SetImplicitDirectories(this->ImplicitLinkDirs);
+ this->OrderRuntimeSearchPath->SetImplicitDirectories(this->ImplicitLinkDirs);
+ if (this->OrderDependentRPath) {
+ this->OrderDependentRPath->SetImplicitDirectories(this->ImplicitLinkDirs);
+ this->OrderDependentRPath->AddLanguageDirectories(this->RuntimeLinkDirs);
+ }
+
+ // Decide whether to enable compatible library search path mode.
+ // There exists code that effectively does
+ //
+ // /path/to/libA.so -lB
+ //
+ // where -lB is meant to link to /path/to/libB.so. This is broken
+ // because it specified -lB without specifying a link directory (-L)
+ // in which to search for B. This worked in CMake 2.4 and below
+ // because -L/path/to would be added by the -L/-l split for A. In
+ // order to support such projects we need to add the directories
+ // containing libraries linked with a full path to the -L path.
+ this->OldLinkDirMode =
+ this->Target->GetPolicyStatusCMP0003() != cmPolicies::NEW;
+ if (this->OldLinkDirMode) {
+ // Construct a mask to not bother with this behavior for link
+ // directories already specified by the user.
+ this->OldLinkDirMask.insert(directories.begin(), directories.end());
+ }
+
+ this->CMP0060Warn = this->Makefile->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0060");
+}
+
+cmComputeLinkInformation::~cmComputeLinkInformation() = default;
+
+void cmComputeLinkInformation::AppendValues(
+ std::string& result, std::vector<BT<std::string>>& values)
+{
+ for (BT<std::string>& p : values) {
+ if (result.empty()) {
+ result.append(" ");
+ }
+
+ result.append(p.Value);
+ }
+}
+
+cmComputeLinkInformation::ItemVector const&
+cmComputeLinkInformation::GetItems() const
+{
+ return this->Items;
+}
+
+std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
+ const
+{
+ return this->OrderLinkerSearchPath->GetOrderedDirectories();
+}
+
+std::vector<BT<std::string>>
+cmComputeLinkInformation::GetDirectoriesWithBacktraces()
+{
+ std::vector<BT<std::string>> directoriesWithBacktraces;
+
+ std::vector<BT<std::string>> targetLinkDirectores =
+ this->Target->GetLinkDirectories(this->Config, this->LinkLanguage);
+
+ const std::vector<std::string>& orderedDirectories = this->GetDirectories();
+ for (const std::string& dir : orderedDirectories) {
+ auto result =
+ std::find(targetLinkDirectores.begin(), targetLinkDirectores.end(), dir);
+ if (result != targetLinkDirectores.end()) {
+ directoriesWithBacktraces.emplace_back(std::move(*result));
+ } else {
+ directoriesWithBacktraces.emplace_back(dir);
+ }
+ }
+
+ return directoriesWithBacktraces;
+}
+
+std::string cmComputeLinkInformation::GetRPathLinkString() const
+{
+ // If there is no separate linker runtime search flag (-rpath-link)
+ // there is no reason to compute a string.
+ if (!this->OrderDependentRPath) {
+ return "";
+ }
+
+ // Construct the linker runtime search path. These MUST NOT contain tokens
+ // such as $ORIGIN, see https://sourceware.org/bugzilla/show_bug.cgi?id=16936
+ return cmJoin(this->OrderDependentRPath->GetOrderedDirectories(), ":");
+}
+
+std::vector<std::string> const& cmComputeLinkInformation::GetDepends() const
+{
+ return this->Depends;
+}
+
+std::vector<std::string> const& cmComputeLinkInformation::GetFrameworkPaths()
+ const
+{
+ return this->FrameworkPaths;
+}
+
+std::set<std::string> const&
+cmComputeLinkInformation::GetFrameworkPathsEmitted() const
+{
+ return this->FrameworkPathsEmitted;
+}
+
+const std::set<const cmGeneratorTarget*>&
+cmComputeLinkInformation::GetSharedLibrariesLinked() const
+{
+ return this->SharedLibrariesLinked;
+}
+
+bool cmComputeLinkInformation::Compute()
+{
+ // Skip targets that do not link.
+ if (!(this->Target->GetType() == cmStateEnums::EXECUTABLE ||
+ this->Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->Target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ this->Target->GetType() == cmStateEnums::STATIC_LIBRARY)) {
+ return false;
+ }
+
+ // We require a link language for the target.
+ if (this->LinkLanguage.empty()) {
+ cmSystemTools::Error(
+ "CMake can not determine linker language for target: " +
+ this->Target->GetName());
+ return false;
+ }
+
+ // Compute the ordered link line items.
+ cmComputeLinkDepends cld(this->Target, this->Config);
+ cld.SetOldLinkDirMode(this->OldLinkDirMode);
+ cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute();
+
+ // Add the link line items.
+ for (cmComputeLinkDepends::LinkEntry const& linkEntry : linkEntries) {
+ if (linkEntry.IsSharedDep) {
+ this->AddSharedDepItem(linkEntry.Item, linkEntry.Target);
+ } else {
+ this->AddItem(linkEntry.Item, linkEntry.Target);
+ }
+ }
+
+ // Restore the target link type so the correct system runtime
+ // libraries are found.
+ cmProp lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC");
+ if (cmIsOn(lss)) {
+ this->SetCurrentLinkType(LinkStatic);
+ } else {
+ this->SetCurrentLinkType(this->StartLinkType);
+ }
+
+ // Finish listing compatibility paths.
+ if (this->OldLinkDirMode) {
+ // For CMake 2.4 bug-compatibility we need to consider the output
+ // directories of targets linked in another configuration as link
+ // directories.
+ std::set<cmGeneratorTarget const*> const& wrongItems =
+ cld.GetOldWrongConfigItems();
+ for (cmGeneratorTarget const* tgt : wrongItems) {
+ cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(this->Config)
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+ this->OldLinkDirItems.push_back(
+ tgt->GetFullPath(this->Config, artifact, true));
+ }
+ }
+
+ // Finish setting up linker search directories.
+ if (!this->FinishLinkerSearchDirectories()) {
+ return false;
+ }
+
+ // Add implicit language runtime libraries and directories.
+ this->AddImplicitLinkInfo();
+
+ if (!this->CMP0060WarnItems.empty()) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0060) << "\n"
+ "Some library files are in directories implicitly searched by "
+ "the linker when invoked for " << this->LinkLanguage << ":\n"
+ " " << cmJoin(this->CMP0060WarnItems, "\n ") << "\n"
+ "For compatibility with older versions of CMake, the generated "
+ "link line will ask the linker to search for these by library "
+ "name."
+ ;
+ /* clang-format on */
+ this->CMakeInstance->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
+ this->Target->GetBacktrace());
+ }
+
+ return true;
+}
+
+void cmComputeLinkInformation::AddImplicitLinkInfo()
+{
+ // The link closure lists all languages whose implicit info is needed.
+ cmGeneratorTarget::LinkClosure const* lc =
+ this->Target->GetLinkClosure(this->Config);
+ for (std::string const& li : lc->Languages) {
+
+ if (li == "CUDA") {
+ // These need to go before the other implicit link information
+ // as they could require symbols from those other library
+ // Currently restricted to CUDA as it is the only language
+ // we have documented runtime behavior controls for
+ this->AddRuntimeLinkLibrary(li);
+ }
+
+ // Skip those of the linker language. They are implicit.
+ if (li != this->LinkLanguage) {
+ this->AddImplicitLinkInfo(li);
+ }
+ }
+}
+
+void cmComputeLinkInformation::AddRuntimeLinkLibrary(std::string const& lang)
+{
+ std::string const& runtimeLibrary =
+ this->Target->GetRuntimeLinkLibrary(lang, this->Config);
+ if (runtimeLibrary.empty()) {
+ return;
+ }
+ if (cmProp runtimeLinkOptions = this->Makefile->GetDefinition(
+ "CMAKE_" + lang + "_RUNTIME_LIBRARY_LINK_OPTIONS_" + runtimeLibrary)) {
+ std::vector<std::string> libsVec = cmExpandedList(*runtimeLinkOptions);
+ for (std::string const& i : libsVec) {
+ if (!cm::contains(this->ImplicitLinkLibs, i)) {
+ this->AddItem(i, nullptr);
+ }
+ }
+ }
+}
+
+void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang)
+{
+ // Add libraries for this language that are not implied by the
+ // linker language.
+ std::string libVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_LIBRARIES");
+ if (cmProp libs = this->Makefile->GetDefinition(libVar)) {
+ std::vector<std::string> libsVec = cmExpandedList(*libs);
+ for (std::string const& i : libsVec) {
+ if (!cm::contains(this->ImplicitLinkLibs, i)) {
+ this->AddItem(i, nullptr);
+ }
+ }
+ }
+
+ // Add linker search paths for this language that are not
+ // implied by the linker language.
+ std::string dirVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_DIRECTORIES");
+ if (cmProp dirs = this->Makefile->GetDefinition(dirVar)) {
+ std::vector<std::string> dirsVec = cmExpandedList(*dirs);
+ this->OrderLinkerSearchPath->AddLanguageDirectories(dirsVec);
+ }
+}
+
+void cmComputeLinkInformation::AddItem(BT<std::string> const& item,
+ cmGeneratorTarget const* tgt)
+{
+ // Compute the proper name to use to link this library.
+ const std::string& config = this->Config;
+ bool impexe = (tgt && tgt->IsExecutableWithExports());
+ if (impexe && !tgt->HasImportLibrary(config) && !this->LoaderFlag) {
+ // Skip linking to executables on platforms with no import
+ // libraries or loader flags.
+ return;
+ }
+
+ if (tgt && tgt->IsLinkable()) {
+ // This is a CMake target. Ask the target for its real name.
+ if (impexe && this->LoaderFlag) {
+ // This link item is an executable that may provide symbols
+ // used by this target. A special flag is needed on this
+ // platform. Add it now.
+ std::string linkItem;
+ linkItem = this->LoaderFlag;
+ cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config)
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+
+ std::string exe = tgt->GetFullPath(config, artifact, true);
+ linkItem += exe;
+ this->Items.emplace_back(BT<std::string>(linkItem, item.Backtrace), true,
+ tgt);
+ this->Depends.push_back(std::move(exe));
+ } else if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ // Add the interface library as an item so it can be considered as part
+ // of COMPATIBLE_INTERFACE_ enforcement. The generators will ignore
+ // this for the actual link line.
+ this->Items.emplace_back(std::string(), false, tgt);
+
+ // Also add the item the interface specifies to be used in its place.
+ std::string const& libName = tgt->GetImportedLibName(config);
+ if (!libName.empty()) {
+ this->AddItem(BT<std::string>(libName, item.Backtrace), nullptr);
+ }
+ } else if (tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ // Ignore object library!
+ // Its object-files should already have been extracted for linking.
+ } else {
+ // Decide whether to use an import library.
+ cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config)
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+
+ // Pass the full path to the target file.
+ BT<std::string> lib = BT<std::string>(
+ tgt->GetFullPath(config, artifact, true), item.Backtrace);
+ if (tgt->Target->IsAIX() && cmHasLiteralSuffix(lib.Value, "-NOTFOUND") &&
+ artifact == cmStateEnums::ImportLibraryArtifact) {
+ // This is an imported executable on AIX that has ENABLE_EXPORTS
+ // but not IMPORTED_IMPLIB. CMake used to produce and accept such
+ // imported executables on AIX before we taught it to use linker
+ // import files. For compatibility, simply skip linking to this
+ // executable as we did before. It works with runtime linking.
+ return;
+ }
+ if (!this->LinkDependsNoShared ||
+ tgt->GetType() != cmStateEnums::SHARED_LIBRARY) {
+ this->Depends.push_back(lib.Value);
+ }
+
+ this->AddTargetItem(lib, tgt);
+ this->AddLibraryRuntimeInfo(lib.Value, tgt);
+ if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY &&
+ this->Target->IsDLLPlatform()) {
+ this->AddRuntimeDLL(tgt);
+ }
+ }
+ } else {
+ // This is not a CMake target. Use the name given.
+ if (cmSystemTools::FileIsFullPath(item.Value)) {
+ if (cmSystemTools::IsPathToFramework(item.Value) &&
+ this->Makefile->IsOn("APPLE")) {
+ // This is a framework.
+ this->AddFrameworkItem(item.Value);
+ } else if (cmSystemTools::FileIsDirectory(item.Value)) {
+ // This is a directory.
+ this->DropDirectoryItem(item.Value);
+ } else {
+ // Use the full path given to the library file.
+ this->Depends.push_back(item.Value);
+ this->AddFullItem(item);
+ this->AddLibraryRuntimeInfo(item.Value);
+ }
+ } else {
+ // This is a library or option specified by the user.
+ this->AddUserItem(item, true);
+ }
+ }
+}
+
+void cmComputeLinkInformation::AddSharedDepItem(BT<std::string> const& item,
+ const cmGeneratorTarget* tgt)
+{
+ // Record dependencies on DLLs.
+ if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY &&
+ this->Target->IsDLLPlatform() &&
+ this->SharedDependencyMode != SharedDepModeLink) {
+ this->AddRuntimeDLL(tgt);
+ }
+
+ // If dropping shared library dependencies, ignore them.
+ if (this->SharedDependencyMode == SharedDepModeNone) {
+ return;
+ }
+
+ // The user may have incorrectly named an item. Skip items that are
+ // not full paths to shared libraries.
+ if (tgt) {
+ // The target will provide a full path. Make sure it is a shared
+ // library.
+ if (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) {
+ return;
+ }
+ } else {
+ // Skip items that are not full paths. We will not be able to
+ // reliably specify them.
+ if (!cmSystemTools::FileIsFullPath(item.Value)) {
+ return;
+ }
+
+ // Get the name of the library from the file name.
+ std::string file = cmSystemTools::GetFilenameName(item.Value);
+ if (!this->ExtractSharedLibraryName.find(file)) {
+ // This is not the name of a shared library.
+ return;
+ }
+ }
+
+ // If in linking mode, just link to the shared library.
+ if (this->SharedDependencyMode == SharedDepModeLink) {
+ this->AddItem(item, tgt);
+ return;
+ }
+
+ // Get a full path to the dependent shared library.
+ // Add it to the runtime path computation so that the target being
+ // linked will be able to find it.
+ std::string lib;
+ if (tgt) {
+ cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(this->Config)
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+ lib = tgt->GetFullPath(this->Config, artifact);
+ this->AddLibraryRuntimeInfo(lib, tgt);
+ } else {
+ lib = item.Value;
+ this->AddLibraryRuntimeInfo(lib);
+ }
+
+ // Check if we need to include the dependent shared library in other
+ // path ordering.
+ cmOrderDirectories* order = nullptr;
+ if (this->SharedDependencyMode == SharedDepModeLibDir &&
+ !this->LinkWithRuntimePath /* AddLibraryRuntimeInfo adds it */) {
+ // Add the item to the linker search path.
+ order = this->OrderLinkerSearchPath.get();
+ } else if (this->SharedDependencyMode == SharedDepModeDir) {
+ // Add the item to the separate dependent library search path.
+ order = this->OrderDependentRPath.get();
+ }
+ if (order) {
+ if (tgt) {
+ std::string soName = tgt->GetSOName(this->Config);
+ const char* soname = soName.empty() ? nullptr : soName.c_str();
+ order->AddRuntimeLibrary(lib, soname);
+ } else {
+ order->AddRuntimeLibrary(lib);
+ }
+ }
+}
+
+void cmComputeLinkInformation::AddRuntimeDLL(cmGeneratorTarget const* tgt)
+{
+ if (std::find(this->RuntimeDLLs.begin(), this->RuntimeDLLs.end(), tgt) ==
+ this->RuntimeDLLs.end()) {
+ this->RuntimeDLLs.emplace_back(tgt);
+ }
+}
+
+void cmComputeLinkInformation::ComputeLinkTypeInfo()
+{
+ // Check whether archives may actually be shared libraries.
+ this->ArchivesMayBeShared =
+ this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
+ "TARGET_ARCHIVES_MAY_BE_SHARED_LIBS");
+
+ // First assume we cannot do link type stuff.
+ this->LinkTypeEnabled = false;
+
+ // Lookup link type selection flags.
+ cmProp static_link_type_flag = nullptr;
+ cmProp shared_link_type_flag = nullptr;
+ const char* target_type_str = nullptr;
+ switch (this->Target->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ target_type_str = "EXE";
+ break;
+ case cmStateEnums::SHARED_LIBRARY:
+ target_type_str = "SHARED_LIBRARY";
+ break;
+ case cmStateEnums::MODULE_LIBRARY:
+ target_type_str = "SHARED_MODULE";
+ break;
+ default:
+ break;
+ }
+ if (target_type_str) {
+ std::string static_link_type_flag_var =
+ cmStrCat("CMAKE_", target_type_str, "_LINK_STATIC_", this->LinkLanguage,
+ "_FLAGS");
+ static_link_type_flag =
+ this->Makefile->GetDefinition(static_link_type_flag_var);
+
+ std::string shared_link_type_flag_var =
+ cmStrCat("CMAKE_", target_type_str, "_LINK_DYNAMIC_", this->LinkLanguage,
+ "_FLAGS");
+ shared_link_type_flag =
+ this->Makefile->GetDefinition(shared_link_type_flag_var);
+ }
+
+ // We can support link type switching only if all needed flags are
+ // known.
+ if (cmNonempty(static_link_type_flag) && cmNonempty(shared_link_type_flag)) {
+ this->LinkTypeEnabled = true;
+ this->StaticLinkTypeFlag = *static_link_type_flag;
+ this->SharedLinkTypeFlag = *shared_link_type_flag;
+ }
+
+ // Lookup the starting link type from the target (linked statically?).
+ cmProp lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC");
+ this->StartLinkType = cmIsOn(lss) ? LinkStatic : LinkShared;
+ this->CurrentLinkType = this->StartLinkType;
+}
+
+void cmComputeLinkInformation::ComputeItemParserInfo()
+{
+ // Get possible library name prefixes.
+ cmMakefile* mf = this->Makefile;
+ this->AddLinkPrefix(mf->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX"));
+ this->AddLinkPrefix(mf->GetSafeDefinition("CMAKE_SHARED_LIBRARY_PREFIX"));
+
+ // Import library names should be matched and treated as shared
+ // libraries for the purposes of linking.
+ this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"),
+ LinkShared);
+ this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"),
+ LinkStatic);
+ this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"),
+ LinkShared);
+ this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX"),
+ LinkUnknown);
+ if (cmProp linkSuffixes = mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS")) {
+ std::vector<std::string> linkSuffixVec = cmExpandedList(*linkSuffixes);
+ for (std::string const& i : linkSuffixVec) {
+ this->AddLinkExtension(i, LinkUnknown);
+ }
+ }
+ if (cmProp sharedSuffixes =
+ mf->GetDefinition("CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES")) {
+ std::vector<std::string> sharedSuffixVec = cmExpandedList(*sharedSuffixes);
+ for (std::string const& i : sharedSuffixVec) {
+ this->AddLinkExtension(i, LinkShared);
+ }
+ }
+
+ // Compute a regex to match link extensions.
+ std::string libext =
+ this->CreateExtensionRegex(this->LinkExtensions, LinkUnknown);
+
+ // Create regex to remove any library extension.
+ std::string reg("(.*)");
+ reg += libext;
+ this->OrderLinkerSearchPath->SetLinkExtensionInfo(this->LinkExtensions, reg);
+
+ // Create a regex to match a library name. Match index 1 will be
+ // the prefix if it exists and empty otherwise. Match index 2 will
+ // be the library name. Match index 3 will be the library
+ // extension.
+ reg = "^(";
+ for (std::string const& p : this->LinkPrefixes) {
+ reg += p;
+ reg += "|";
+ }
+ reg += ")";
+ reg += "([^/:]*)";
+
+ // Create a regex to match any library name.
+ std::string reg_any = cmStrCat(reg, libext);
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "any regex [%s]\n", reg_any.c_str());
+#endif
+ this->ExtractAnyLibraryName.compile(reg_any);
+
+ // Create a regex to match static library names.
+ if (!this->StaticLinkExtensions.empty()) {
+ std::string reg_static = cmStrCat(
+ reg, this->CreateExtensionRegex(this->StaticLinkExtensions, LinkStatic));
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "static regex [%s]\n", reg_static.c_str());
+#endif
+ this->ExtractStaticLibraryName.compile(reg_static);
+ }
+
+ // Create a regex to match shared library names.
+ if (!this->SharedLinkExtensions.empty()) {
+ std::string reg_shared = reg;
+ this->SharedRegexString =
+ this->CreateExtensionRegex(this->SharedLinkExtensions, LinkShared);
+ reg_shared += this->SharedRegexString;
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "shared regex [%s]\n", reg_shared.c_str());
+#endif
+ this->ExtractSharedLibraryName.compile(reg_shared);
+ }
+}
+
+void cmComputeLinkInformation::AddLinkPrefix(std::string const& p)
+{
+ if (!p.empty()) {
+ this->LinkPrefixes.insert(p);
+ }
+}
+
+void cmComputeLinkInformation::AddLinkExtension(std::string const& e,
+ LinkType type)
+{
+ if (!e.empty()) {
+ if (type == LinkStatic) {
+ this->StaticLinkExtensions.emplace_back(e);
+ }
+ if (type == LinkShared) {
+ this->SharedLinkExtensions.emplace_back(e);
+ }
+ this->LinkExtensions.emplace_back(e);
+ }
+}
+
+// XXX(clang-tidy): This method's const-ness is platform dependent, so we
+// cannot make it `const` as `clang-tidy` wants us to.
+// NOLINTNEXTLINE(readability-make-member-function-const)
+std::string cmComputeLinkInformation::CreateExtensionRegex(
+ std::vector<std::string> const& exts, LinkType type)
+{
+ // Build a list of extension choices.
+ std::string libext = "(";
+ const char* sep = "";
+ for (std::string const& i : exts) {
+ // Separate this choice from the previous one.
+ libext += sep;
+ sep = "|";
+
+ // Store this extension choice with the "." escaped.
+ libext += "\\";
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ libext += this->NoCaseExpression(i);
+#else
+ libext += i;
+#endif
+ }
+
+ // Finish the list.
+ libext += ")";
+
+ // Add an optional OpenBSD-style version or major.minor.version component.
+ if (this->OpenBSD || type == LinkShared) {
+ libext += "(\\.[0-9]+)*";
+ }
+
+ libext += "$";
+ return libext;
+}
+
+std::string cmComputeLinkInformation::NoCaseExpression(std::string const& str)
+{
+ std::string ret;
+ ret.reserve(str.size() * 4);
+ for (char c : str) {
+ if (c == '.') {
+ ret += c;
+ } else {
+ ret += '[';
+ ret += static_cast<char>(tolower(c));
+ ret += static_cast<char>(toupper(c));
+ ret += ']';
+ }
+ }
+ return ret;
+}
+
+void cmComputeLinkInformation::SetCurrentLinkType(LinkType lt)
+{
+ // If we are changing the current link type add the flag to tell the
+ // linker about it.
+ if (this->CurrentLinkType != lt) {
+ this->CurrentLinkType = lt;
+
+ if (this->LinkTypeEnabled) {
+ switch (this->CurrentLinkType) {
+ case LinkStatic:
+ this->Items.emplace_back(this->StaticLinkTypeFlag, false);
+ break;
+ case LinkShared:
+ this->Items.emplace_back(this->SharedLinkTypeFlag, false);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void cmComputeLinkInformation::AddTargetItem(BT<std::string> const& item,
+ cmGeneratorTarget const* target)
+{
+ // This is called to handle a link item that is a full path to a target.
+ // If the target is not a static library make sure the link type is
+ // shared. This is because dynamic-mode linking can handle both
+ // shared and static libraries but static-mode can handle only
+ // static libraries. If a previous user item changed the link type
+ // to static we need to make sure it is back to shared.
+ if (target->GetType() != cmStateEnums::STATIC_LIBRARY) {
+ this->SetCurrentLinkType(LinkShared);
+ }
+
+ // Keep track of shared library targets linked.
+ if (target->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ this->SharedLibrariesLinked.insert(target);
+ }
+
+ // Handle case of an imported shared library with no soname.
+ if (this->NoSONameUsesPath &&
+ target->IsImportedSharedLibWithoutSOName(this->Config)) {
+ this->AddSharedLibNoSOName(item.Value);
+ return;
+ }
+
+ // For compatibility with CMake 2.4 include the item's directory in
+ // the linker search path.
+ if (this->OldLinkDirMode && !target->IsFrameworkOnApple() &&
+ !cm::contains(this->OldLinkDirMask,
+ cmSystemTools::GetFilenamePath(item.Value))) {
+ this->OldLinkDirItems.push_back(item.Value);
+ }
+
+ // Now add the full path to the library.
+ this->Items.emplace_back(item, true, target);
+}
+
+void cmComputeLinkInformation::AddFullItem(BT<std::string> const& item)
+{
+ // Check for the implicit link directory special case.
+ if (this->CheckImplicitDirItem(item.Value)) {
+ return;
+ }
+
+ // Check for case of shared library with no builtin soname.
+ if (this->NoSONameUsesPath && this->CheckSharedLibNoSOName(item.Value)) {
+ return;
+ }
+
+ // Full path libraries should specify a valid library file name.
+ // See documentation of CMP0008.
+ std::string generator = this->GlobalGenerator->GetName();
+ if (this->Target->GetPolicyStatusCMP0008() != cmPolicies::NEW &&
+ (generator.find("Visual Studio") != std::string::npos ||
+ generator.find("Xcode") != std::string::npos)) {
+ std::string file = cmSystemTools::GetFilenameName(item.Value);
+ if (!this->ExtractAnyLibraryName.find(file)) {
+ this->HandleBadFullItem(item.Value, file);
+ return;
+ }
+ }
+
+ // This is called to handle a link item that is a full path.
+ // If the target is not a static library make sure the link type is
+ // shared. This is because dynamic-mode linking can handle both
+ // shared and static libraries but static-mode can handle only
+ // static libraries. If a previous user item changed the link type
+ // to static we need to make sure it is back to shared.
+ if (this->LinkTypeEnabled) {
+ std::string name = cmSystemTools::GetFilenameName(item.Value);
+ if (this->ExtractSharedLibraryName.find(name)) {
+ this->SetCurrentLinkType(LinkShared);
+ } else if (!this->ExtractStaticLibraryName.find(item.Value)) {
+ // We cannot determine the type. Assume it is the target's
+ // default type.
+ this->SetCurrentLinkType(this->StartLinkType);
+ }
+ }
+
+ // For compatibility with CMake 2.4 include the item's directory in
+ // the linker search path.
+ if (this->OldLinkDirMode &&
+ !cm::contains(this->OldLinkDirMask,
+ cmSystemTools::GetFilenamePath(item.Value))) {
+ this->OldLinkDirItems.push_back(item.Value);
+ }
+
+ // Now add the full path to the library.
+ this->Items.emplace_back(item, true);
+}
+
+bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item)
+{
+ // We only switch to a pathless item if the link type may be
+ // enforced. Fortunately only platforms that support link types
+ // seem to have magic per-architecture implicit link directories.
+ if (!this->LinkTypeEnabled) {
+ return false;
+ }
+
+ // Check if this item is in an implicit link directory.
+ std::string dir = cmSystemTools::GetFilenamePath(item);
+ if (!cm::contains(this->ImplicitLinkDirs, dir)) {
+ // Only libraries in implicit link directories are converted to
+ // pathless items.
+ return false;
+ }
+
+ // Only apply the policy below if the library file is one that can
+ // be found by the linker.
+ std::string file = cmSystemTools::GetFilenameName(item);
+ if (!this->ExtractAnyLibraryName.find(file)) {
+ return false;
+ }
+
+ // Check the policy for whether we should use the approach below.
+ switch (this->Target->GetPolicyStatusCMP0060()) {
+ case cmPolicies::WARN:
+ if (this->CMP0060Warn) {
+ // Print the warning at most once for this item.
+ std::string const& wid = "CMP0060-WARNING-GIVEN-" + item;
+ if (!this->CMakeInstance->GetPropertyAsBool(wid)) {
+ this->CMakeInstance->SetProperty(wid, "1");
+ this->CMP0060WarnItems.insert(item);
+ }
+ }
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ return false;
+ }
+
+ // Many system linkers support multiple architectures by
+ // automatically selecting the implicit linker search path for the
+ // current architecture. If the library appears in an implicit link
+ // directory then just report the file name without the directory
+ // portion. This will allow the system linker to locate the proper
+ // library for the architecture at link time.
+ this->AddUserItem(file, false);
+
+ // Make sure the link directory ordering will find the library.
+ this->OrderLinkerSearchPath->AddLinkLibrary(item);
+
+ return true;
+}
+
+void cmComputeLinkInformation::AddUserItem(BT<std::string> const& item,
+ bool pathNotKnown)
+{
+ // This is called to handle a link item that does not match a CMake
+ // target and is not a full path. We check here if it looks like a
+ // library file name to automatically request the proper link type
+ // from the linker. For example:
+ //
+ // foo ==> -lfoo
+ // libfoo.a ==> -Wl,-Bstatic -lfoo
+
+ // Pass flags through untouched.
+ if (item.Value[0] == '-' || item.Value[0] == '$' || item.Value[0] == '`') {
+ // if this is a -l option then we might need to warn about
+ // CMP0003 so put it in OldUserFlagItems, if it is not a -l
+ // or -Wl,-l (-framework -pthread), then allow it without a
+ // CMP0003 as -L will not affect those other linker flags
+ if (cmHasLiteralPrefix(item.Value, "-l") ||
+ cmHasLiteralPrefix(item.Value, "-Wl,-l")) {
+ // This is a linker option provided by the user.
+ this->OldUserFlagItems.push_back(item.Value);
+ }
+
+ // Restore the target link type since this item does not specify
+ // one.
+ this->SetCurrentLinkType(this->StartLinkType);
+
+ // Use the item verbatim.
+ this->Items.emplace_back(item, false);
+ return;
+ }
+
+ // Parse out the prefix, base, and suffix components of the
+ // library name. If the name matches that of a shared or static
+ // library then set the link type accordingly.
+ //
+ // Search for shared library names first because some platforms
+ // have shared libraries with names that match the static library
+ // pattern. For example cygwin and msys use the convention
+ // libfoo.dll.a for import libraries and libfoo.a for static
+ // libraries. On AIX a library with the name libfoo.a can be
+ // shared!
+ std::string lib;
+ if (this->ExtractSharedLibraryName.find(item.Value)) {
+// This matches a shared library file name.
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "shared regex matched [%s] [%s] [%s]\n",
+ this->ExtractSharedLibraryName.match(1).c_str(),
+ this->ExtractSharedLibraryName.match(2).c_str(),
+ this->ExtractSharedLibraryName.match(3).c_str());
+#endif
+ // Set the link type to shared.
+ this->SetCurrentLinkType(LinkShared);
+
+ // Use just the library name so the linker will search.
+ lib = this->ExtractSharedLibraryName.match(2);
+ } else if (this->ExtractStaticLibraryName.find(item.Value)) {
+// This matches a static library file name.
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "static regex matched [%s] [%s] [%s]\n",
+ this->ExtractStaticLibraryName.match(1).c_str(),
+ this->ExtractStaticLibraryName.match(2).c_str(),
+ this->ExtractStaticLibraryName.match(3).c_str());
+#endif
+ // Set the link type to static.
+ this->SetCurrentLinkType(LinkStatic);
+
+ // Use just the library name so the linker will search.
+ lib = this->ExtractStaticLibraryName.match(2);
+ } else if (this->ExtractAnyLibraryName.find(item.Value)) {
+// This matches a library file name.
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "any regex matched [%s] [%s] [%s]\n",
+ this->ExtractAnyLibraryName.match(1).c_str(),
+ this->ExtractAnyLibraryName.match(2).c_str(),
+ this->ExtractAnyLibraryName.match(3).c_str());
+#endif
+ // Restore the target link type since this item does not specify
+ // one.
+ this->SetCurrentLinkType(this->StartLinkType);
+
+ // Use just the library name so the linker will search.
+ lib = this->ExtractAnyLibraryName.match(2);
+ } else {
+ // This is a name specified by the user.
+ if (pathNotKnown) {
+ this->OldUserFlagItems.push_back(item.Value);
+ }
+
+ // We must ask the linker to search for a library with this name.
+ // Restore the target link type since this item does not specify
+ // one.
+ this->SetCurrentLinkType(this->StartLinkType);
+ lib = item.Value;
+ }
+
+ // Create an option to ask the linker to search for the library.
+ std::string out = cmStrCat(this->LibLinkFlag, lib, this->LibLinkSuffix);
+ this->Items.emplace_back(BT<std::string>(out, item.Backtrace), false);
+
+ // Here we could try to find the library the linker will find and
+ // add a runtime information entry for it. It would probably not be
+ // reliable and we want to encourage use of full paths for library
+ // specification.
+}
+
+void cmComputeLinkInformation::AddFrameworkItem(std::string const& item)
+{
+ // Try to separate the framework name and path.
+ if (!this->SplitFramework.find(item)) {
+ std::ostringstream e;
+ e << "Could not parse framework path \"" << item << "\" "
+ << "linked by target " << this->Target->GetName() << ".";
+ cmSystemTools::Error(e.str());
+ return;
+ }
+
+ std::string fw_path = this->SplitFramework.match(1);
+ std::string fw = this->SplitFramework.match(2);
+ std::string full_fw = cmStrCat(fw_path, '/', fw, ".framework/", fw);
+
+ // Add the directory portion to the framework search path.
+ this->AddFrameworkPath(fw_path);
+
+ // add runtime information
+ this->AddLibraryRuntimeInfo(full_fw);
+
+ if (this->GlobalGenerator->IsXcode()) {
+ // Add framework path - it will be handled by Xcode after it's added to
+ // "Link Binary With Libraries" build phase
+ this->Items.emplace_back(item, true);
+ } else {
+ // Add the item using the -framework option.
+ this->Items.emplace_back(std::string("-framework"), false);
+ cmOutputConverter converter(this->Makefile->GetStateSnapshot());
+ fw = converter.EscapeForShell(fw);
+ this->Items.emplace_back(fw, false);
+ }
+}
+
+void cmComputeLinkInformation::DropDirectoryItem(std::string const& item)
+{
+ // A full path to a directory was found as a link item. Warn the
+ // user.
+ std::ostringstream e;
+ e << "WARNING: Target \"" << this->Target->GetName()
+ << "\" requests linking to directory \"" << item << "\". "
+ << "Targets may link only to libraries. "
+ << "CMake is dropping the item.";
+ cmSystemTools::Message(e.str());
+}
+
+void cmComputeLinkInformation::ComputeFrameworkInfo()
+{
+ // Avoid adding implicit framework paths.
+ std::vector<std::string> implicitDirVec;
+
+ // Get platform-wide implicit directories.
+ this->Makefile->GetDefExpandList(
+ "CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES", implicitDirVec);
+
+ // Get language-specific implicit directories.
+ std::string implicitDirVar = cmStrCat(
+ "CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES");
+ this->Makefile->GetDefExpandList(implicitDirVar, implicitDirVec);
+
+ this->FrameworkPathsEmitted.insert(implicitDirVec.begin(),
+ implicitDirVec.end());
+
+ // Regular expression to extract a framework path and name.
+ this->SplitFramework.compile("(.*)/(.*)\\.framework$");
+}
+
+void cmComputeLinkInformation::AddFrameworkPath(std::string const& p)
+{
+ if (this->FrameworkPathsEmitted.insert(p).second) {
+ this->FrameworkPaths.push_back(p);
+ }
+}
+
+bool cmComputeLinkInformation::CheckSharedLibNoSOName(std::string const& item)
+{
+ // This platform will use the path to a library as its soname if the
+ // library is given via path and was not built with an soname. If
+ // this is a shared library that might be the case.
+ std::string file = cmSystemTools::GetFilenameName(item);
+ if (this->ExtractSharedLibraryName.find(file)) {
+ // If we can guess the soname fairly reliably then assume the
+ // library has one. Otherwise assume the library has no builtin
+ // soname.
+ std::string soname;
+ if (!cmSystemTools::GuessLibrarySOName(item, soname)) {
+ this->AddSharedLibNoSOName(item);
+ return true;
+ }
+ }
+ return false;
+}
+
+void cmComputeLinkInformation::AddSharedLibNoSOName(std::string const& item)
+{
+ // We have a full path to a shared library with no soname. We need
+ // to ask the linker to locate the item because otherwise the path
+ // we give to it will be embedded in the target linked. Then at
+ // runtime the dynamic linker will search for the library using the
+ // path instead of just the name.
+ std::string file = cmSystemTools::GetFilenameName(item);
+ this->AddUserItem(file, false);
+
+ // Make sure the link directory ordering will find the library.
+ this->OrderLinkerSearchPath->AddLinkLibrary(item);
+}
+
+void cmComputeLinkInformation::HandleBadFullItem(std::string const& item,
+ std::string const& file)
+{
+ // Do not depend on things that do not exist.
+ auto i = std::find(this->Depends.begin(), this->Depends.end(), item);
+ if (i != this->Depends.end()) {
+ this->Depends.erase(i);
+ }
+
+ // Tell the linker to search for the item and provide the proper
+ // path for it. Do not contribute to any CMP0003 warning (do not
+ // put in OldLinkDirItems or OldUserFlagItems).
+ this->AddUserItem(file, false);
+ this->OrderLinkerSearchPath->AddLinkLibrary(item);
+
+ // Produce any needed message.
+ switch (this->Target->GetPolicyStatusCMP0008()) {
+ case cmPolicies::WARN: {
+ // Print the warning at most once for this item.
+ std::string wid = cmStrCat("CMP0008-WARNING-GIVEN-", item);
+ if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(wid)) {
+ this->CMakeInstance->GetState()->SetGlobalProperty(wid, "1");
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0008) << "\n"
+ << "Target \"" << this->Target->GetName() << "\" links to item\n"
+ << " " << item << "\n"
+ << "which is a full-path but not a valid library file name.";
+ /* clang-format on */
+ this->CMakeInstance->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
+ this->Target->GetBacktrace());
+ }
+ }
+ case cmPolicies::OLD:
+ // OLD behavior does not warn.
+ case cmPolicies::NEW:
+ // NEW behavior will not get here.
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS: {
+ std::ostringstream e;
+ /* clang-format off */
+ e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0008) << "\n"
+ << "Target \"" << this->Target->GetName() << "\" links to item\n"
+ << " " << item << "\n"
+ << "which is a full-path but not a valid library file name.";
+ /* clang-format on */
+ this->CMakeInstance->IssueMessage(MessageType::FATAL_ERROR, e.str(),
+ this->Target->GetBacktrace());
+ } break;
+ }
+}
+
+bool cmComputeLinkInformation::FinishLinkerSearchDirectories()
+{
+ // Support broken projects if necessary.
+ if (this->OldLinkDirItems.empty() || this->OldUserFlagItems.empty() ||
+ !this->OldLinkDirMode) {
+ return true;
+ }
+
+ // Enforce policy constraints.
+ switch (this->Target->GetPolicyStatusCMP0003()) {
+ case cmPolicies::WARN:
+ if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
+ "CMP0003-WARNING-GIVEN")) {
+ this->CMakeInstance->GetState()->SetGlobalProperty(
+ "CMP0003-WARNING-GIVEN", "1");
+ std::ostringstream w;
+ this->PrintLinkPolicyDiagnosis(w);
+ this->CMakeInstance->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
+ this->Target->GetBacktrace());
+ }
+ case cmPolicies::OLD:
+ // OLD behavior is to add the paths containing libraries with
+ // known full paths as link directories.
+ break;
+ case cmPolicies::NEW:
+ // Should never happen due to assignment of OldLinkDirMode
+ return true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS: {
+ std::ostringstream e;
+ e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0003) << "\n";
+ this->PrintLinkPolicyDiagnosis(e);
+ this->CMakeInstance->IssueMessage(MessageType::FATAL_ERROR, e.str(),
+ this->Target->GetBacktrace());
+ return false;
+ }
+ }
+
+ // Add the link directories for full path items.
+ for (std::string const& i : this->OldLinkDirItems) {
+ this->OrderLinkerSearchPath->AddLinkLibrary(i);
+ }
+ return true;
+}
+
+void cmComputeLinkInformation::PrintLinkPolicyDiagnosis(std::ostream& os)
+{
+ // Tell the user what to do.
+ /* clang-format off */
+ os << "Policy CMP0003 should be set before this line. "
+ << "Add code such as\n"
+ << " if(COMMAND cmake_policy)\n"
+ << " cmake_policy(SET CMP0003 NEW)\n"
+ << " endif(COMMAND cmake_policy)\n"
+ << "as early as possible but after the most recent call to "
+ << "cmake_minimum_required or cmake_policy(VERSION). ";
+ /* clang-format on */
+
+ // List the items that might need the old-style paths.
+ os << "This warning appears because target \"" << this->Target->GetName()
+ << "\" "
+ << "links to some libraries for which the linker must search:\n";
+ {
+ // Format the list of unknown items to be as short as possible while
+ // still fitting in the allowed width (a true solution would be the
+ // bin packing problem if we were allowed to change the order).
+ std::string::size_type max_size = 76;
+ std::string line;
+ const char* sep = " ";
+ for (std::string const& i : this->OldUserFlagItems) {
+ // If the addition of another item will exceed the limit then
+ // output the current line and reset it. Note that the separator
+ // is either " " or ", " which is always 2 characters.
+ if (!line.empty() && (line.size() + i.size() + 2) > max_size) {
+ os << line << "\n";
+ sep = " ";
+ line.clear();
+ }
+ line += sep;
+ line += i;
+ // Convert to the other separator.
+ sep = ", ";
+ }
+ if (!line.empty()) {
+ os << line << "\n";
+ }
+ }
+
+ // List the paths old behavior is adding.
+ os << "and other libraries with known full path:\n";
+ std::set<std::string> emitted;
+ for (std::string const& i : this->OldLinkDirItems) {
+ if (emitted.insert(cmSystemTools::GetFilenamePath(i)).second) {
+ os << " " << i << "\n";
+ }
+ }
+
+ // Explain.
+ os << "CMake is adding directories in the second list to the linker "
+ << "search path in case they are needed to find libraries from the "
+ << "first list (for backwards compatibility with CMake 2.4). "
+ << "Set policy CMP0003 to OLD or NEW to enable or disable this "
+ << "behavior explicitly. "
+ << "Run \"cmake --help-policy CMP0003\" for more information.";
+}
+
+void cmComputeLinkInformation::LoadImplicitLinkInfo()
+{
+ std::vector<std::string> implicitDirVec;
+
+ // Get platform-wide implicit directories.
+ this->Makefile->GetDefExpandList("CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES",
+ implicitDirVec);
+
+ // Append library architecture to all implicit platform directories
+ // and add them to the set
+ if (cmProp libraryArch =
+ this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE")) {
+ for (std::string const& i : implicitDirVec) {
+ this->ImplicitLinkDirs.insert(i + "/" + *libraryArch);
+ }
+ }
+
+ // Get language-specific implicit directories.
+ std::string implicitDirVar =
+ cmStrCat("CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_DIRECTORIES");
+ this->Makefile->GetDefExpandList(implicitDirVar, implicitDirVec);
+
+ // Store implicit link directories.
+ this->ImplicitLinkDirs.insert(implicitDirVec.begin(), implicitDirVec.end());
+
+ // Get language-specific implicit libraries.
+ std::vector<std::string> implicitLibVec;
+ std::string implicitLibVar =
+ cmStrCat("CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_LIBRARIES");
+ this->Makefile->GetDefExpandList(implicitLibVar, implicitLibVec);
+
+ // Store implicit link libraries.
+ for (std::string const& item : implicitLibVec) {
+ // Items starting in '-' but not '-l' are flags, not libraries,
+ // and should not be filtered by this implicit list.
+ if (item[0] != '-' || item[1] == 'l') {
+ this->ImplicitLinkLibs.insert(item);
+ }
+ }
+
+ // Get platform specific rpath link directories
+ this->Makefile->GetDefExpandList("CMAKE_PLATFORM_RUNTIME_PATH",
+ this->RuntimeLinkDirs);
+}
+
+std::vector<std::string> const&
+cmComputeLinkInformation::GetRuntimeSearchPath() const
+{
+ return this->OrderRuntimeSearchPath->GetOrderedDirectories();
+}
+
+void cmComputeLinkInformation::AddLibraryRuntimeInfo(
+ std::string const& fullPath, cmGeneratorTarget const* target)
+{
+ // Ignore targets on Apple where install_name is not @rpath.
+ // The dependenty library can be found with other means such as
+ // @loader_path or full paths.
+ if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ if (!target->HasMacOSXRpathInstallNameDir(this->Config)) {
+ return;
+ }
+ }
+
+ // Libraries with unknown type must be handled using just the file
+ // on disk.
+ if (target->GetType() == cmStateEnums::UNKNOWN_LIBRARY) {
+ this->AddLibraryRuntimeInfo(fullPath);
+ return;
+ }
+
+ // Skip targets that are not shared libraries (modules cannot be linked).
+ if (target->GetType() != cmStateEnums::SHARED_LIBRARY) {
+ return;
+ }
+
+ // Try to get the soname of the library. Only files with this name
+ // could possibly conflict.
+ std::string soName = target->GetSOName(this->Config);
+ const char* soname = soName.empty() ? nullptr : soName.c_str();
+
+ // Include this library in the runtime path ordering.
+ this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath, soname);
+ if (this->LinkWithRuntimePath) {
+ this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath, soname);
+ }
+}
+
+void cmComputeLinkInformation::AddLibraryRuntimeInfo(
+ std::string const& fullPath)
+{
+ // Get the name of the library from the file name.
+ bool is_shared_library = false;
+ std::string file = cmSystemTools::GetFilenameName(fullPath);
+
+ if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ // Check that @rpath is part of the install name.
+ // If it isn't, return.
+ std::string soname;
+ if (!cmSystemTools::GuessLibraryInstallName(fullPath, soname)) {
+ return;
+ }
+
+ if (soname.find("@rpath") == std::string::npos) {
+ return;
+ }
+ }
+
+ is_shared_library = this->ExtractSharedLibraryName.find(file);
+
+ if (!is_shared_library) {
+ // On some platforms (AIX) a shared library may look static.
+ if (this->ArchivesMayBeShared) {
+ if (this->ExtractStaticLibraryName.find(file)) {
+ // This is the name of a shared library or archive.
+ is_shared_library = true;
+ }
+ }
+ }
+
+ // It could be an Apple framework
+ if (!is_shared_library) {
+ if (fullPath.find(".framework") != std::string::npos) {
+ static cmsys::RegularExpression splitFramework(
+ "^(.*)/(.*).framework/(.*)$");
+ if (splitFramework.find(fullPath) &&
+ (std::string::npos !=
+ splitFramework.match(3).find(splitFramework.match(2)))) {
+ is_shared_library = true;
+ }
+ }
+ }
+
+ if (!is_shared_library) {
+ return;
+ }
+
+ // Include this library in the runtime path ordering.
+ this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath);
+ if (this->LinkWithRuntimePath) {
+ this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath);
+ }
+}
+
+static void cmCLI_ExpandListUnique(std::string const& str,
+ std::vector<std::string>& out,
+ std::set<std::string>& emitted)
+{
+ std::vector<std::string> tmp = cmExpandedList(str);
+ for (std::string const& i : tmp) {
+ if (emitted.insert(i).second) {
+ out.push_back(i);
+ }
+ }
+}
+
+void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
+ bool for_install) const
+{
+ // Select whether to generate runtime search directories.
+ bool outputRuntime =
+ !this->Makefile->IsOn("CMAKE_SKIP_RPATH") && !this->RuntimeFlag.empty();
+
+ // Select whether to generate an rpath for the install tree or the
+ // build tree.
+ bool linking_for_install =
+ (for_install ||
+ this->Target->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"));
+ bool use_install_rpath =
+ (outputRuntime && this->Target->HaveInstallTreeRPATH(this->Config) &&
+ linking_for_install);
+ bool use_build_rpath =
+ (outputRuntime && this->Target->HaveBuildTreeRPATH(this->Config) &&
+ !linking_for_install);
+ bool use_link_rpath = outputRuntime && linking_for_install &&
+ !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH") &&
+ this->Target->GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH");
+
+ // Select whether to use $ORIGIN in RPATHs for artifacts in the build tree.
+ std::string const& originToken = this->Makefile->GetSafeDefinition(
+ "CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN");
+ std::string targetOutputDir = this->Target->GetDirectory(this->Config);
+ bool use_relative_build_rpath =
+ this->Target->GetPropertyAsBool("BUILD_RPATH_USE_ORIGIN") &&
+ !originToken.empty() && !targetOutputDir.empty();
+
+ // Construct the RPATH.
+ std::set<std::string> emitted;
+ if (use_install_rpath) {
+ std::string install_rpath;
+ this->Target->GetInstallRPATH(this->Config, install_rpath);
+ cmCLI_ExpandListUnique(install_rpath, runtimeDirs, emitted);
+ }
+ if (use_build_rpath) {
+ // Add directories explicitly specified by user
+ std::string build_rpath;
+ if (this->Target->GetBuildRPATH(this->Config, build_rpath)) {
+ // This will not resolve entries to use $ORIGIN, the user is expected to
+ // do that if necessary.
+ cmCLI_ExpandListUnique(build_rpath, runtimeDirs, emitted);
+ }
+ }
+ if (use_build_rpath || use_link_rpath) {
+ std::string rootPath;
+ if (cmProp sysrootLink =
+ this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
+ rootPath = *sysrootLink;
+ } else {
+ rootPath = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
+ }
+ cmProp stagePath = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
+ std::string const& installPrefix =
+ this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
+ cmSystemTools::ConvertToUnixSlashes(rootPath);
+ std::vector<std::string> const& rdirs = this->GetRuntimeSearchPath();
+ std::string const& topBinaryDir =
+ this->CMakeInstance->GetHomeOutputDirectory();
+ for (std::string const& ri : rdirs) {
+ // Put this directory in the rpath if using build-tree rpath
+ // support or if using the link path as an rpath.
+ if (use_build_rpath) {
+ std::string d = ri;
+ if (!rootPath.empty() && cmHasPrefix(d, rootPath)) {
+ d.erase(0, rootPath.size());
+ } else if (cmNonempty(stagePath) && cmHasPrefix(d, *stagePath)) {
+ d.erase(0, (*stagePath).size());
+ d = cmStrCat(installPrefix, '/', d);
+ cmSystemTools::ConvertToUnixSlashes(d);
+ } else if (use_relative_build_rpath) {
+ // If expansion of the $ORIGIN token is supported and permitted per
+ // policy, use relative paths in the RPATH.
+ if (cmSystemTools::ComparePath(d, topBinaryDir) ||
+ cmSystemTools::IsSubDirectory(d, topBinaryDir)) {
+ d = cmSystemTools::RelativePath(targetOutputDir, d);
+ if (!d.empty()) {
+ d = cmStrCat(originToken, "/", d);
+ } else {
+ d = originToken;
+ }
+ }
+ }
+ if (emitted.insert(d).second) {
+ runtimeDirs.push_back(std::move(d));
+ }
+ } else if (use_link_rpath) {
+ // Do not add any path inside the source or build tree.
+ std::string const& topSourceDir =
+ this->CMakeInstance->GetHomeDirectory();
+ if (!cmSystemTools::ComparePath(ri, topSourceDir) &&
+ !cmSystemTools::ComparePath(ri, topBinaryDir) &&
+ !cmSystemTools::IsSubDirectory(ri, topSourceDir) &&
+ !cmSystemTools::IsSubDirectory(ri, topBinaryDir)) {
+ std::string d = ri;
+ if (!rootPath.empty() && cmHasPrefix(d, rootPath)) {
+ d.erase(0, rootPath.size());
+ } else if (cmNonempty(stagePath) && cmHasPrefix(d, *stagePath)) {
+ d.erase(0, (*stagePath).size());
+ d = cmStrCat(installPrefix, '/', d);
+ cmSystemTools::ConvertToUnixSlashes(d);
+ }
+ if (emitted.insert(d).second) {
+ runtimeDirs.push_back(std::move(d));
+ }
+ }
+ }
+ }
+ }
+
+ // Add runtime paths required by the languages to always be
+ // present. This is done even when skipping rpath support.
+ {
+ cmGeneratorTarget::LinkClosure const* lc =
+ this->Target->GetLinkClosure(this->Config);
+ for (std::string const& li : lc->Languages) {
+ std::string useVar =
+ "CMAKE_" + li + "_USE_IMPLICIT_LINK_DIRECTORIES_IN_RUNTIME_PATH";
+ if (this->Makefile->IsOn(useVar)) {
+ std::string dirVar = "CMAKE_" + li + "_IMPLICIT_LINK_DIRECTORIES";
+ if (cmProp dirs = this->Makefile->GetDefinition(dirVar)) {
+ cmCLI_ExpandListUnique(*dirs, runtimeDirs, emitted);
+ }
+ }
+ }
+ }
+
+ // Add runtime paths required by the platform to always be
+ // present. This is done even when skipping rpath support.
+ cmCLI_ExpandListUnique(this->RuntimeAlways, runtimeDirs, emitted);
+}
+
+std::string cmComputeLinkInformation::GetRPathString(bool for_install) const
+{
+ // Get the directories to use.
+ std::vector<std::string> runtimeDirs;
+ this->GetRPath(runtimeDirs, for_install);
+
+ // Concatenate the paths.
+ std::string rpath = cmJoin(runtimeDirs, this->GetRuntimeSep());
+
+ // If the rpath will be replaced at install time, prepare space.
+ if (!for_install && this->RuntimeUseChrpath) {
+ if (!rpath.empty()) {
+ // Add one trailing separator so the linker does not re-use the
+ // rpath .dynstr entry for a symbol name that happens to match
+ // the end of the rpath string.
+ rpath += this->GetRuntimeSep();
+ }
+
+ // Make sure it is long enough to hold the replacement value.
+ std::string::size_type minLength = this->GetChrpathString().length();
+ while (rpath.length() < minLength) {
+ rpath += this->GetRuntimeSep();
+ }
+ }
+
+ return rpath;
+}
+
+std::string cmComputeLinkInformation::GetChrpathString() const
+{
+ if (!this->RuntimeUseChrpath) {
+ return "";
+ }
+
+ return this->GetRPathString(true);
+}
diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h
new file mode 100644
index 0000000..4acb99f
--- /dev/null
+++ b/Source/cmComputeLinkInformation.h
@@ -0,0 +1,216 @@
+/* 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 <iosfwd>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmListFileCache.h"
+
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmMakefile;
+class cmOrderDirectories;
+class cmake;
+
+/** \class cmComputeLinkInformation
+ * \brief Compute link information for a target in one configuration.
+ */
+class cmComputeLinkInformation
+{
+public:
+ cmComputeLinkInformation(cmGeneratorTarget const* target,
+ const std::string& config);
+ cmComputeLinkInformation(const cmComputeLinkInformation&) = delete;
+ cmComputeLinkInformation& operator=(const cmComputeLinkInformation&) =
+ delete;
+ ~cmComputeLinkInformation();
+ bool Compute();
+
+ struct Item
+ {
+ Item() = default;
+ Item(BT<std::string> v, bool p, cmGeneratorTarget const* target = nullptr)
+ : Value(std::move(v))
+ , IsPath(p)
+ , Target(target)
+ {
+ }
+ BT<std::string> Value;
+ bool IsPath = true;
+ cmGeneratorTarget const* Target = nullptr;
+ };
+ using ItemVector = std::vector<Item>;
+ void AppendValues(std::string& result, std::vector<BT<std::string>>& values);
+ ItemVector const& GetItems() const;
+ std::vector<std::string> const& GetDirectories() const;
+ std::vector<BT<std::string>> GetDirectoriesWithBacktraces();
+ std::vector<std::string> const& GetDepends() const;
+ std::vector<std::string> const& GetFrameworkPaths() const;
+ std::set<std::string> const& GetFrameworkPathsEmitted() const;
+ std::string GetLinkLanguage() const { return this->LinkLanguage; }
+ std::vector<std::string> const& GetRuntimeSearchPath() const;
+ std::string const& GetRuntimeFlag() const { return this->RuntimeFlag; }
+ std::string const& GetRuntimeSep() const { return this->RuntimeSep; }
+ void GetRPath(std::vector<std::string>& runtimeDirs, bool for_install) const;
+ std::string GetRPathString(bool for_install) const;
+ std::string GetChrpathString() const;
+ std::set<cmGeneratorTarget const*> const& GetSharedLibrariesLinked() const;
+ std::vector<cmGeneratorTarget const*> const& GetRuntimeDLLs() const
+ {
+ return this->RuntimeDLLs;
+ }
+
+ std::string const& GetLibLinkFileFlag() const
+ {
+ return this->LibLinkFileFlag;
+ }
+
+ std::string const& GetRPathLinkFlag() const { return this->RPathLinkFlag; }
+ std::string GetRPathLinkString() const;
+
+ std::string GetConfig() const { return this->Config; }
+
+ const cmGeneratorTarget* GetTarget() { return this->Target; }
+
+private:
+ void AddItem(BT<std::string> const& item, const cmGeneratorTarget* tgt);
+ void AddSharedDepItem(BT<std::string> const& item,
+ cmGeneratorTarget const* tgt);
+ void AddRuntimeDLL(cmGeneratorTarget const* tgt);
+
+ // Output information.
+ ItemVector Items;
+ std::vector<std::string> Directories;
+ std::vector<std::string> Depends;
+ std::vector<std::string> FrameworkPaths;
+ std::vector<std::string> RuntimeSearchPath;
+ std::set<cmGeneratorTarget const*> SharedLibrariesLinked;
+ std::vector<cmGeneratorTarget const*> RuntimeDLLs;
+
+ // Context information.
+ cmGeneratorTarget const* const Target;
+ cmMakefile* const Makefile;
+ cmGlobalGenerator* const GlobalGenerator;
+ cmake* const CMakeInstance;
+
+ // Configuration information.
+ std::string const Config;
+ std::string LinkLanguage;
+
+ // Modes for dealing with dependent shared libraries.
+ enum SharedDepMode
+ {
+ SharedDepModeNone, // Drop
+ SharedDepModeDir, // List dir in -rpath-link flag
+ SharedDepModeLibDir, // List dir in linker search path
+ SharedDepModeLink // List file on link line
+ };
+
+ const char* LoaderFlag;
+ std::string LibLinkFlag;
+ std::string LibLinkFileFlag;
+ std::string LibLinkSuffix;
+ std::string RuntimeFlag;
+ std::string RuntimeSep;
+ std::string RuntimeAlways;
+ std::string RPathLinkFlag;
+ SharedDepMode SharedDependencyMode;
+
+ enum LinkType
+ {
+ LinkUnknown,
+ LinkStatic,
+ LinkShared
+ };
+ void SetCurrentLinkType(LinkType lt);
+
+ // Link type adjustment.
+ void ComputeLinkTypeInfo();
+ LinkType StartLinkType;
+ LinkType CurrentLinkType;
+ std::string StaticLinkTypeFlag;
+ std::string SharedLinkTypeFlag;
+
+ // Link item parsing.
+ void ComputeItemParserInfo();
+ std::vector<std::string> StaticLinkExtensions;
+ std::vector<std::string> SharedLinkExtensions;
+ std::vector<std::string> LinkExtensions;
+ std::set<std::string> LinkPrefixes;
+ cmsys::RegularExpression ExtractStaticLibraryName;
+ cmsys::RegularExpression ExtractSharedLibraryName;
+ cmsys::RegularExpression ExtractAnyLibraryName;
+ std::string SharedRegexString;
+ void AddLinkPrefix(std::string const& p);
+ void AddLinkExtension(std::string const& e, LinkType type);
+ std::string CreateExtensionRegex(std::vector<std::string> const& exts,
+ LinkType type);
+ std::string NoCaseExpression(std::string const& str);
+
+ // Handling of link items.
+ void AddTargetItem(BT<std::string> const& item,
+ const cmGeneratorTarget* target);
+ void AddFullItem(BT<std::string> const& item);
+ bool CheckImplicitDirItem(std::string const& item);
+ void AddUserItem(BT<std::string> const& item, bool pathNotKnown);
+ void AddFrameworkItem(std::string const& item);
+ void DropDirectoryItem(std::string const& item);
+ bool CheckSharedLibNoSOName(std::string const& item);
+ void AddSharedLibNoSOName(std::string const& item);
+ void HandleBadFullItem(std::string const& item, std::string const& file);
+
+ // Framework info.
+ void ComputeFrameworkInfo();
+ void AddFrameworkPath(std::string const& p);
+ std::set<std::string> FrameworkPathsEmitted;
+ cmsys::RegularExpression SplitFramework;
+
+ // Linker search path computation.
+ std::unique_ptr<cmOrderDirectories> OrderLinkerSearchPath;
+ bool FinishLinkerSearchDirectories();
+ void PrintLinkPolicyDiagnosis(std::ostream&);
+
+ // Implicit link libraries and directories for linker language.
+ void LoadImplicitLinkInfo();
+ void AddImplicitLinkInfo();
+ void AddImplicitLinkInfo(std::string const& lang);
+ void AddRuntimeLinkLibrary(std::string const& lang);
+ std::set<std::string> ImplicitLinkDirs;
+ std::set<std::string> ImplicitLinkLibs;
+
+ // Additional paths configured by the runtime linker
+ std::vector<std::string> RuntimeLinkDirs;
+
+ // Linker search path compatibility mode.
+ std::set<std::string> OldLinkDirMask;
+ std::vector<std::string> OldLinkDirItems;
+ std::vector<std::string> OldUserFlagItems;
+ std::set<std::string> CMP0060WarnItems;
+ // Dependent library path computation.
+ std::unique_ptr<cmOrderDirectories> OrderDependentRPath;
+ // Runtime path computation.
+ std::unique_ptr<cmOrderDirectories> OrderRuntimeSearchPath;
+
+ bool OldLinkDirMode;
+ bool OpenBSD;
+ bool LinkDependsNoShared;
+ bool RuntimeUseChrpath;
+ bool NoSONameUsesPath;
+ bool LinkWithRuntimePath;
+ bool LinkTypeEnabled;
+ bool ArchivesMayBeShared;
+ bool CMP0060Warn;
+
+ void AddLibraryRuntimeInfo(std::string const& fullPath,
+ const cmGeneratorTarget* target);
+ void AddLibraryRuntimeInfo(std::string const& fullPath);
+};
diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx
new file mode 100644
index 0000000..85a9d9c
--- /dev/null
+++ b/Source/cmComputeTargetDepends.cxx
@@ -0,0 +1,730 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmComputeTargetDepends.h"
+
+#include <cassert>
+#include <cstdio>
+#include <memory>
+#include <sstream>
+#include <utility>
+
+#include "cmComputeComponentGraph.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLinkItem.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetDepend.h"
+#include "cmake.h"
+
+/*
+
+This class is meant to analyze inter-target dependencies globally
+during the generation step. The goal is to produce a set of direct
+dependencies for each target such that no cycles are left and the
+build order is safe.
+
+For most target types cyclic dependencies are not allowed. However
+STATIC libraries may depend on each other in a cyclic fashion. In
+general the directed dependency graph forms a directed-acyclic-graph
+of strongly connected components. All strongly connected components
+should consist of only STATIC_LIBRARY targets.
+
+In order to safely break dependency cycles we must preserve all other
+dependencies passing through the corresponding strongly connected component.
+The approach taken by this class is as follows:
+
+ - Collect all targets and form the original dependency graph
+ - Run Tarjan's algorithm to extract the strongly connected components
+ (error if any member of a non-trivial component is not STATIC)
+ - The original dependencies imply a DAG on the components.
+ Use the implied DAG to construct a final safe set of dependencies.
+
+The final dependency set is constructed as follows:
+
+ - For each connected component targets are placed in an arbitrary
+ order. Each target depends on the target following it in the order.
+ The first target is designated the head and the last target the tail.
+ (most components will be just 1 target anyway)
+
+ - Original dependencies between targets in different components are
+ converted to connect the depender's component tail to the
+ dependee's component head.
+
+In most cases this will reproduce the original dependencies. However
+when there are cycles of static libraries they will be broken in a
+safe manner.
+
+For example, consider targets A0, A1, A2, B0, B1, B2, and C with these
+dependencies:
+
+ A0 -> A1 -> A2 -> A0 , B0 -> B1 -> B2 -> B0 -> A0 , C -> B0
+
+Components may be identified as
+
+ Component 0: A0, A1, A2
+ Component 1: B0, B1, B2
+ Component 2: C
+
+Intra-component dependencies are:
+
+ 0: A0 -> A1 -> A2 , head=A0, tail=A2
+ 1: B0 -> B1 -> B2 , head=B0, tail=B2
+ 2: head=C, tail=C
+
+The inter-component dependencies are converted as:
+
+ B0 -> A0 is component 1->0 and becomes B2 -> A0
+ C -> B0 is component 2->1 and becomes C -> B0
+
+This leads to the final target dependencies:
+
+ C -> B0 -> B1 -> B2 -> A0 -> A1 -> A2
+
+These produce a safe build order since C depends directly or
+transitively on all the static libraries it links.
+
+*/
+
+cmComputeTargetDepends::cmComputeTargetDepends(cmGlobalGenerator* gg)
+{
+ this->GlobalGenerator = gg;
+ cmake* cm = this->GlobalGenerator->GetCMakeInstance();
+ this->DebugMode =
+ cm->GetState()->GetGlobalPropertyAsBool("GLOBAL_DEPENDS_DEBUG_MODE");
+ this->NoCycles =
+ cm->GetState()->GetGlobalPropertyAsBool("GLOBAL_DEPENDS_NO_CYCLES");
+}
+
+cmComputeTargetDepends::~cmComputeTargetDepends() = default;
+
+bool cmComputeTargetDepends::Compute()
+{
+ // Build the original graph.
+ this->CollectTargets();
+ this->CollectDepends();
+ if (this->DebugMode) {
+ this->DisplayGraph(this->InitialGraph, "initial");
+ }
+ cmComputeComponentGraph ccg1(this->InitialGraph);
+ ccg1.Compute();
+ if (!this->CheckComponents(ccg1)) {
+ return false;
+ }
+
+ // Compute the intermediate graph.
+ this->CollectSideEffects();
+ this->ComputeIntermediateGraph();
+ if (this->DebugMode) {
+ this->DisplaySideEffects();
+ this->DisplayGraph(this->IntermediateGraph, "intermediate");
+ }
+
+ // Identify components.
+ cmComputeComponentGraph ccg2(this->IntermediateGraph);
+ ccg2.Compute();
+ if (this->DebugMode) {
+ this->DisplayComponents(ccg2, "intermediate");
+ }
+ if (!this->CheckComponents(ccg2)) {
+ return false;
+ }
+
+ // Compute the final dependency graph.
+ if (!this->ComputeFinalDepends(ccg2)) {
+ return false;
+ }
+ if (this->DebugMode) {
+ this->DisplayGraph(this->FinalGraph, "final");
+ }
+
+ return true;
+}
+
+void cmComputeTargetDepends::GetTargetDirectDepends(cmGeneratorTarget const* t,
+ cmTargetDependSet& deps)
+{
+ // Lookup the index for this target. All targets should be known by
+ // this point.
+ auto tii = this->TargetIndex.find(t);
+ assert(tii != this->TargetIndex.end());
+ int i = tii->second;
+
+ // Get its final dependencies.
+ EdgeList const& nl = this->FinalGraph[i];
+ for (cmGraphEdge const& ni : nl) {
+ cmGeneratorTarget const* dep = this->Targets[ni];
+ auto di = deps.insert(dep).first;
+ di->SetType(ni.IsStrong());
+ di->SetCross(ni.IsCross());
+ di->SetBacktrace(ni.GetBacktrace());
+ }
+}
+
+void cmComputeTargetDepends::CollectTargets()
+{
+ // Collect all targets from all generators.
+ auto const& lgens = this->GlobalGenerator->GetLocalGenerators();
+ for (const auto& lgen : lgens) {
+ for (const auto& ti : lgen->GetGeneratorTargets()) {
+ int index = static_cast<int>(this->Targets.size());
+ this->TargetIndex[ti.get()] = index;
+ this->Targets.push_back(ti.get());
+ }
+ }
+}
+
+void cmComputeTargetDepends::CollectDepends()
+{
+ // Allocate the dependency graph adjacency lists.
+ this->InitialGraph.resize(this->Targets.size());
+
+ // Compute each dependency list.
+ for (unsigned int i = 0; i < this->Targets.size(); ++i) {
+ this->CollectTargetDepends(i);
+ }
+}
+
+void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
+{
+ // Get the depender.
+ cmGeneratorTarget const* depender = this->Targets[depender_index];
+ if (!depender->IsInBuildSystem()) {
+ return;
+ }
+
+ // Loop over all targets linked directly in all configs.
+ // We need to make targets depend on the union of all config-specific
+ // dependencies in all targets, because the generated build-systems can't
+ // deal with config-specific dependencies.
+ {
+ std::set<cmLinkItem> emitted;
+
+ std::vector<std::string> const& configs =
+ depender->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ for (std::string const& it : configs) {
+ // A target should not depend on itself.
+ emitted.insert(cmLinkItem(depender, false, cmListFileBacktrace()));
+ emitted.insert(cmLinkItem(depender, true, cmListFileBacktrace()));
+
+ if (cmLinkImplementation const* impl =
+ depender->GetLinkImplementation(it)) {
+ for (cmLinkImplItem const& lib : impl->Libraries) {
+ // Don't emit the same library twice for this target.
+ if (emitted.insert(lib).second) {
+ this->AddTargetDepend(depender_index, lib, true, false);
+ this->AddInterfaceDepends(depender_index, lib, it, emitted);
+ }
+ }
+ }
+
+ // Add dependencies on object libraries not otherwise handled above.
+ std::vector<cmSourceFile const*> objectFiles;
+ depender->GetExternalObjects(objectFiles, it);
+ for (cmSourceFile const* o : objectFiles) {
+ std::string const& objLib = o->GetObjectLibrary();
+ if (!objLib.empty()) {
+ cmLinkItem const& objItem =
+ depender->ResolveLinkItem(objLib, cmListFileBacktrace());
+ if (emitted.insert(objItem).second) {
+ if (depender->GetType() != cmStateEnums::EXECUTABLE &&
+ depender->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ depender->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ depender->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ depender->GetType() != cmStateEnums::OBJECT_LIBRARY) {
+ this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Only executables and libraries may reference target objects.",
+ depender->GetBacktrace());
+ return;
+ }
+ const_cast<cmGeneratorTarget*>(depender)->Target->AddUtility(
+ objLib, false);
+ }
+ }
+ }
+ }
+ }
+
+ // Loop over all utility dependencies.
+ {
+ std::set<cmLinkItem> const& tutils = depender->GetUtilityItems();
+ std::set<cmLinkItem> emitted;
+ // A target should not depend on itself.
+ emitted.insert(cmLinkItem(depender, false, cmListFileBacktrace()));
+ emitted.insert(cmLinkItem(depender, true, cmListFileBacktrace()));
+ for (cmLinkItem const& litem : tutils) {
+ // Don't emit the same utility twice for this target.
+ if (emitted.insert(litem).second) {
+ this->AddTargetDepend(depender_index, litem, false, litem.Cross);
+ }
+ }
+ }
+}
+
+void cmComputeTargetDepends::AddInterfaceDepends(
+ int depender_index, const cmGeneratorTarget* dependee,
+ cmListFileBacktrace const& dependee_backtrace, const std::string& config,
+ std::set<cmLinkItem>& emitted)
+{
+ cmGeneratorTarget const* depender = this->Targets[depender_index];
+ if (cmLinkInterface const* iface =
+ dependee->GetLinkInterface(config, depender)) {
+ for (cmLinkItem const& lib : iface->Libraries) {
+ // Don't emit the same library twice for this target.
+ if (emitted.insert(lib).second) {
+ // Inject the backtrace of the original link dependency whose
+ // link interface we are adding. This indicates the line of
+ // code in the project that caused this dependency to be added.
+ cmLinkItem libBT = lib;
+ libBT.Backtrace = dependee_backtrace;
+ this->AddTargetDepend(depender_index, libBT, true, false);
+ this->AddInterfaceDepends(depender_index, libBT, config, emitted);
+ }
+ }
+ }
+}
+
+void cmComputeTargetDepends::AddInterfaceDepends(
+ int depender_index, cmLinkItem const& dependee_name,
+ const std::string& config, std::set<cmLinkItem>& emitted)
+{
+ cmGeneratorTarget const* depender = this->Targets[depender_index];
+ cmGeneratorTarget const* dependee = dependee_name.Target;
+ // Skip targets that will not really be linked. This is probably a
+ // name conflict between an external library and an executable
+ // within the project.
+ if (dependee && dependee->GetType() == cmStateEnums::EXECUTABLE &&
+ !dependee->IsExecutableWithExports()) {
+ dependee = nullptr;
+ }
+
+ if (dependee) {
+ // A target should not depend on itself.
+ emitted.insert(cmLinkItem(depender, false, cmListFileBacktrace()));
+ emitted.insert(cmLinkItem(depender, true, cmListFileBacktrace()));
+ this->AddInterfaceDepends(depender_index, dependee,
+ dependee_name.Backtrace, config, emitted);
+ }
+}
+
+void cmComputeTargetDepends::AddTargetDepend(int depender_index,
+ cmLinkItem const& dependee_name,
+ bool linking, bool cross)
+{
+ // Get the depender.
+ cmGeneratorTarget const* depender = this->Targets[depender_index];
+
+ // Check the target's makefile first.
+ cmGeneratorTarget const* dependee = dependee_name.Target;
+
+ if (!dependee && !linking &&
+ (depender->GetType() != cmStateEnums::GLOBAL_TARGET)) {
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+ bool issueMessage = false;
+ std::ostringstream e;
+ switch (depender->GetPolicyStatusCMP0046()) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0046) << "\n";
+ issueMessage = true;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ issueMessage = true;
+ messageType = MessageType::FATAL_ERROR;
+ }
+ if (issueMessage) {
+ cmake* cm = this->GlobalGenerator->GetCMakeInstance();
+
+ e << "The dependency target \"" << dependee_name << "\" of target \""
+ << depender->GetName() << "\" does not exist.";
+
+ cm->IssueMessage(messageType, e.str(), dependee_name.Backtrace);
+ }
+ }
+
+ // Skip targets that will not really be linked. This is probably a
+ // name conflict between an external library and an executable
+ // within the project.
+ if (linking && dependee && dependee->GetType() == cmStateEnums::EXECUTABLE &&
+ !dependee->IsExecutableWithExports()) {
+ dependee = nullptr;
+ }
+
+ if (dependee) {
+ this->AddTargetDepend(depender_index, dependee, dependee_name.Backtrace,
+ linking, cross);
+ }
+}
+
+void cmComputeTargetDepends::AddTargetDepend(
+ int depender_index, cmGeneratorTarget const* dependee,
+ cmListFileBacktrace const& dependee_backtrace, bool linking, bool cross)
+{
+ if (!dependee->IsInBuildSystem()) {
+ // Skip targets that are not in the buildsystem but follow their
+ // utility dependencies.
+ std::set<cmLinkItem> const& utils = dependee->GetUtilityItems();
+ for (cmLinkItem const& i : utils) {
+ if (cmGeneratorTarget const* transitive_dependee = i.Target) {
+ this->AddTargetDepend(depender_index, transitive_dependee, i.Backtrace,
+ false, i.Cross);
+ }
+ }
+ } else {
+ // Lookup the index for this target. All targets should be known by
+ // this point.
+ auto tii = this->TargetIndex.find(dependee);
+ assert(tii != this->TargetIndex.end());
+ int dependee_index = tii->second;
+
+ // Add this entry to the dependency graph.
+ this->InitialGraph[depender_index].emplace_back(dependee_index, !linking,
+ cross, dependee_backtrace);
+ }
+}
+
+void cmComputeTargetDepends::CollectSideEffects()
+{
+ this->SideEffects.resize(0);
+ this->SideEffects.resize(this->InitialGraph.size());
+
+ int n = static_cast<int>(this->InitialGraph.size());
+ std::set<int> visited;
+ for (int i = 0; i < n; ++i) {
+ this->CollectSideEffectsForTarget(visited, i);
+ }
+}
+
+void cmComputeTargetDepends::CollectSideEffectsForTarget(
+ std::set<int>& visited, int depender_index)
+{
+ if (!visited.count(depender_index)) {
+ auto& se = this->SideEffects[depender_index];
+ visited.insert(depender_index);
+ this->Targets[depender_index]->AppendCustomCommandSideEffects(
+ se.CustomCommandSideEffects);
+ this->Targets[depender_index]->AppendLanguageSideEffects(
+ se.LanguageSideEffects);
+
+ for (auto const& edge : this->InitialGraph[depender_index]) {
+ this->CollectSideEffectsForTarget(visited, edge);
+ auto const& dse = this->SideEffects[edge];
+ se.CustomCommandSideEffects.insert(dse.CustomCommandSideEffects.cbegin(),
+ dse.CustomCommandSideEffects.cend());
+ for (auto const& it : dse.LanguageSideEffects) {
+ se.LanguageSideEffects[it.first].insert(it.second.cbegin(),
+ it.second.cend());
+ }
+ }
+ }
+}
+
+void cmComputeTargetDepends::ComputeIntermediateGraph()
+{
+ this->IntermediateGraph.resize(0);
+ this->IntermediateGraph.resize(this->InitialGraph.size());
+
+ int n = static_cast<int>(this->InitialGraph.size());
+ for (int i = 0; i < n; ++i) {
+ auto const& initialEdges = this->InitialGraph[i];
+ auto& intermediateEdges = this->IntermediateGraph[i];
+ cmGeneratorTarget const* gt = this->Targets[i];
+ if (gt->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ gt->GetType() != cmStateEnums::OBJECT_LIBRARY) {
+ intermediateEdges = initialEdges;
+ } else {
+ if (cmProp optimizeDependencies =
+ gt->GetProperty("OPTIMIZE_DEPENDENCIES")) {
+ if (cmIsOn(optimizeDependencies)) {
+ this->OptimizeLinkDependencies(gt, intermediateEdges, initialEdges);
+ } else {
+ intermediateEdges = initialEdges;
+ }
+ } else {
+ intermediateEdges = initialEdges;
+ }
+ }
+ }
+}
+
+void cmComputeTargetDepends::OptimizeLinkDependencies(
+ cmGeneratorTarget const* gt, cmGraphEdgeList& outputEdges,
+ cmGraphEdgeList const& inputEdges)
+{
+ std::set<int> emitted;
+ for (auto const& edge : inputEdges) {
+ if (edge.IsStrong()) {
+ // Preserve strong edges
+ outputEdges.push_back(edge);
+ } else {
+ auto const& dse = this->SideEffects[edge];
+
+ // Add edges that have custom command side effects
+ for (cmGeneratorTarget const* dep : dse.CustomCommandSideEffects) {
+ auto index = this->TargetIndex[dep];
+ if (!emitted.count(index)) {
+ emitted.insert(index);
+ outputEdges.push_back(
+ cmGraphEdge(index, false, edge.IsCross(), edge.GetBacktrace()));
+ }
+ }
+
+ // Add edges that have language side effects for languages we
+ // care about
+ for (auto const& lang : gt->GetAllConfigCompileLanguages()) {
+ auto it = dse.LanguageSideEffects.find(lang);
+ if (it != dse.LanguageSideEffects.end()) {
+ for (cmGeneratorTarget const* dep : it->second) {
+ auto index = this->TargetIndex[dep];
+ if (!emitted.count(index)) {
+ emitted.insert(index);
+ outputEdges.push_back(cmGraphEdge(index, false, edge.IsCross(),
+ edge.GetBacktrace()));
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void cmComputeTargetDepends::DisplayGraph(Graph const& graph,
+ const std::string& name)
+{
+ fprintf(stderr, "The %s target dependency graph is:\n", name.c_str());
+ int n = static_cast<int>(graph.size());
+ for (int depender_index = 0; depender_index < n; ++depender_index) {
+ EdgeList const& nl = graph[depender_index];
+ cmGeneratorTarget const* depender = this->Targets[depender_index];
+ fprintf(stderr, "target %d is [%s]\n", depender_index,
+ depender->GetName().c_str());
+ for (cmGraphEdge const& ni : nl) {
+ int dependee_index = ni;
+ cmGeneratorTarget const* dependee = this->Targets[dependee_index];
+ fprintf(stderr, " depends on target %d [%s] (%s)\n", dependee_index,
+ dependee->GetName().c_str(), ni.IsStrong() ? "strong" : "weak");
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
+void cmComputeTargetDepends::DisplaySideEffects()
+{
+ fprintf(stderr, "The side effects are:\n");
+ int n = static_cast<int>(this->SideEffects.size());
+ for (int depender_index = 0; depender_index < n; ++depender_index) {
+ cmGeneratorTarget const* depender = this->Targets[depender_index];
+ fprintf(stderr, "target %d is [%s]\n", depender_index,
+ depender->GetName().c_str());
+ if (!this->SideEffects[depender_index].CustomCommandSideEffects.empty()) {
+ fprintf(stderr, " custom commands\n");
+ for (auto const* gt :
+ this->SideEffects[depender_index].CustomCommandSideEffects) {
+ fprintf(stderr, " from target %d [%s]\n", this->TargetIndex[gt],
+ gt->GetName().c_str());
+ }
+ }
+ for (auto const& it :
+ this->SideEffects[depender_index].LanguageSideEffects) {
+ fprintf(stderr, " language %s\n", it.first.c_str());
+ for (auto const* gt : it.second) {
+ fprintf(stderr, " from target %d [%s]\n", this->TargetIndex[gt],
+ gt->GetName().c_str());
+ }
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
+void cmComputeTargetDepends::DisplayComponents(
+ cmComputeComponentGraph const& ccg, const std::string& name)
+{
+ fprintf(stderr, "The strongly connected components for the %s graph are:\n",
+ name.c_str());
+ std::vector<NodeList> const& components = ccg.GetComponents();
+ int n = static_cast<int>(components.size());
+ for (int c = 0; c < n; ++c) {
+ NodeList const& nl = components[c];
+ fprintf(stderr, "Component (%d):\n", c);
+ for (int i : nl) {
+ fprintf(stderr, " contains target %d [%s]\n", i,
+ this->Targets[i]->GetName().c_str());
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
+bool cmComputeTargetDepends::CheckComponents(
+ cmComputeComponentGraph const& ccg)
+{
+ // All non-trivial components should consist only of static
+ // libraries.
+ std::vector<NodeList> const& components = ccg.GetComponents();
+ int nc = static_cast<int>(components.size());
+ for (int c = 0; c < nc; ++c) {
+ // Get the current component.
+ NodeList const& nl = components[c];
+
+ // Skip trivial components.
+ if (nl.size() < 2) {
+ continue;
+ }
+
+ // Immediately complain if no cycles are allowed at all.
+ if (this->NoCycles) {
+ this->ComplainAboutBadComponent(ccg, c);
+ return false;
+ }
+
+ // Make sure the component is all STATIC_LIBRARY targets.
+ for (int ni : nl) {
+ if (this->Targets[ni]->GetType() != cmStateEnums::STATIC_LIBRARY) {
+ this->ComplainAboutBadComponent(ccg, c);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void cmComputeTargetDepends::ComplainAboutBadComponent(
+ cmComputeComponentGraph const& ccg, int c, bool strong)
+{
+ // Construct the error message.
+ std::ostringstream e;
+ e << "The inter-target dependency graph contains the following "
+ << "strongly connected component (cycle):\n";
+ std::vector<NodeList> const& components = ccg.GetComponents();
+ std::vector<int> const& cmap = ccg.GetComponentMap();
+ NodeList const& cl = components[c];
+ for (int i : cl) {
+ // Get the depender.
+ cmGeneratorTarget const* depender = this->Targets[i];
+
+ // Describe the depender.
+ e << " \"" << depender->GetName() << "\" of type "
+ << cmState::GetTargetTypeName(depender->GetType()) << "\n";
+
+ // List its dependencies that are inside the component.
+ EdgeList const& nl = this->InitialGraph[i];
+ for (cmGraphEdge const& ni : nl) {
+ int j = ni;
+ if (cmap[j] == c) {
+ cmGeneratorTarget const* dependee = this->Targets[j];
+ e << " depends on \"" << dependee->GetName() << "\""
+ << " (" << (ni.IsStrong() ? "strong" : "weak") << ")\n";
+ }
+ }
+ }
+ if (strong) {
+ // Custom command executable dependencies cannot occur within a
+ // component of static libraries. The cycle must appear in calls
+ // to add_dependencies.
+ e << "The component contains at least one cycle consisting of strong "
+ << "dependencies (created by add_dependencies) that cannot be broken.";
+ } else if (this->NoCycles) {
+ e << "The GLOBAL_DEPENDS_NO_CYCLES global property is enabled, so "
+ << "cyclic dependencies are not allowed even among static libraries.";
+ } else {
+ e << "At least one of these targets is not a STATIC_LIBRARY. "
+ << "Cyclic dependencies are allowed only among static libraries.";
+ }
+ cmSystemTools::Error(e.str());
+}
+
+bool cmComputeTargetDepends::IntraComponent(std::vector<int> const& cmap,
+ int c, int i, int* head,
+ std::set<int>& emitted,
+ std::set<int>& visited)
+{
+ if (!visited.insert(i).second) {
+ // Cycle in utility depends!
+ return false;
+ }
+ if (emitted.insert(i).second) {
+ // Honor strong intra-component edges in the final order.
+ EdgeList const& el = this->InitialGraph[i];
+ for (cmGraphEdge const& edge : el) {
+ int j = edge;
+ if (cmap[j] == c && edge.IsStrong()) {
+ this->FinalGraph[i].emplace_back(j, true, edge.IsCross(),
+ edge.GetBacktrace());
+ if (!this->IntraComponent(cmap, c, j, head, emitted, visited)) {
+ return false;
+ }
+ }
+ }
+
+ // Prepend to a linear linked-list of intra-component edges.
+ if (*head >= 0) {
+ this->FinalGraph[i].emplace_back(*head, false, false,
+ cmListFileBacktrace());
+ } else {
+ this->ComponentTail[c] = i;
+ }
+ *head = i;
+ }
+ return true;
+}
+
+bool cmComputeTargetDepends::ComputeFinalDepends(
+ cmComputeComponentGraph const& ccg)
+{
+ // Get the component graph information.
+ std::vector<NodeList> const& components = ccg.GetComponents();
+ Graph const& cgraph = ccg.GetComponentGraph();
+
+ // Allocate the final graph.
+ this->FinalGraph.resize(0);
+ this->FinalGraph.resize(this->InitialGraph.size());
+
+ // Choose intra-component edges to linearize dependencies.
+ std::vector<int> const& cmap = ccg.GetComponentMap();
+ this->ComponentHead.resize(components.size());
+ this->ComponentTail.resize(components.size());
+ int nc = static_cast<int>(components.size());
+ for (int c = 0; c < nc; ++c) {
+ int head = -1;
+ std::set<int> emitted;
+ NodeList const& nl = components[c];
+ for (int ni : cmReverseRange(nl)) {
+ std::set<int> visited;
+ if (!this->IntraComponent(cmap, c, ni, &head, emitted, visited)) {
+ // Cycle in add_dependencies within component!
+ this->ComplainAboutBadComponent(ccg, c, true);
+ return false;
+ }
+ }
+ this->ComponentHead[c] = head;
+ }
+
+ // Convert inter-component edges to connect component tails to heads.
+ int n = static_cast<int>(cgraph.size());
+ for (int depender_component = 0; depender_component < n;
+ ++depender_component) {
+ int depender_component_tail = this->ComponentTail[depender_component];
+ EdgeList const& nl = cgraph[depender_component];
+ for (cmGraphEdge const& ni : nl) {
+ int dependee_component = ni;
+ int dependee_component_head = this->ComponentHead[dependee_component];
+ this->FinalGraph[depender_component_tail].emplace_back(
+ dependee_component_head, ni.IsStrong(), ni.IsCross(),
+ ni.GetBacktrace());
+ }
+ }
+ return true;
+}
diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h
new file mode 100644
index 0000000..3517844
--- /dev/null
+++ b/Source/cmComputeTargetDepends.h
@@ -0,0 +1,106 @@
+/* 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 <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmGraphAdjacencyList.h"
+#include "cmListFileCache.h"
+
+class cmComputeComponentGraph;
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmLinkItem;
+class cmTargetDependSet;
+
+/** \class cmComputeTargetDepends
+ * \brief Compute global interdependencies among targets.
+ *
+ * Static libraries may form cycles in the target dependency graph.
+ * This class evaluates target dependencies globally and adjusts them
+ * to remove cycles while preserving a safe build order.
+ */
+class cmComputeTargetDepends
+{
+public:
+ cmComputeTargetDepends(cmGlobalGenerator* gg);
+ ~cmComputeTargetDepends();
+
+ bool Compute();
+
+ std::vector<cmGeneratorTarget const*> const& GetTargets() const
+ {
+ return this->Targets;
+ }
+ void GetTargetDirectDepends(cmGeneratorTarget const* t,
+ cmTargetDependSet& deps);
+
+private:
+ struct TargetSideEffects
+ {
+ std::set<cmGeneratorTarget const*> CustomCommandSideEffects;
+ std::map<std::string, std::set<cmGeneratorTarget const*>>
+ LanguageSideEffects;
+ };
+
+ void CollectTargets();
+ void CollectDepends();
+ void CollectTargetDepends(int depender_index);
+ void AddTargetDepend(int depender_index, cmLinkItem const& dependee_name,
+ bool linking, bool cross);
+ void AddTargetDepend(int depender_index, cmGeneratorTarget const* dependee,
+ cmListFileBacktrace const& dependee_backtrace,
+ bool linking, bool cross);
+ void CollectSideEffects();
+ void CollectSideEffectsForTarget(std::set<int>& visited, int depender_index);
+ void ComputeIntermediateGraph();
+ void OptimizeLinkDependencies(cmGeneratorTarget const* gt,
+ cmGraphEdgeList& outputEdges,
+ cmGraphEdgeList const& inputEdges);
+ bool ComputeFinalDepends(cmComputeComponentGraph const& ccg);
+ void AddInterfaceDepends(int depender_index, cmLinkItem const& dependee_name,
+ const std::string& config,
+ std::set<cmLinkItem>& emitted);
+ void AddInterfaceDepends(int depender_index,
+ cmGeneratorTarget const* dependee,
+ cmListFileBacktrace const& dependee_backtrace,
+ const std::string& config,
+ std::set<cmLinkItem>& emitted);
+ cmGlobalGenerator* GlobalGenerator;
+ bool DebugMode;
+ bool NoCycles;
+
+ // Collect all targets.
+ std::vector<cmGeneratorTarget const*> Targets;
+ std::map<cmGeneratorTarget const*, int> TargetIndex;
+
+ // Represent the target dependency graph. The entry at each
+ // top-level index corresponds to a depender whose dependencies are
+ // listed.
+ using NodeList = cmGraphNodeList;
+ using EdgeList = cmGraphEdgeList;
+ using Graph = cmGraphAdjacencyList;
+ Graph InitialGraph;
+ Graph IntermediateGraph;
+ Graph FinalGraph;
+ std::vector<TargetSideEffects> SideEffects;
+ void DisplayGraph(Graph const& graph, const std::string& name);
+ void DisplaySideEffects();
+
+ // Deal with connected components.
+ void DisplayComponents(cmComputeComponentGraph const& ccg,
+ const std::string& name);
+ bool CheckComponents(cmComputeComponentGraph const& ccg);
+ void ComplainAboutBadComponent(cmComputeComponentGraph const& ccg, int c,
+ bool strong = false);
+
+ std::vector<int> ComponentHead;
+ std::vector<int> ComponentTail;
+ bool IntraComponent(std::vector<int> const& cmap, int c, int i, int* head,
+ std::set<int>& emitted, std::set<int>& visited);
+};
diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx
new file mode 100644
index 0000000..62bc526
--- /dev/null
+++ b/Source/cmConditionEvaluator.cxx
@@ -0,0 +1,762 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmConditionEvaluator.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <functional>
+#include <sstream>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+class cmTest;
+
+static std::string const keyAND = "AND";
+static std::string const keyCOMMAND = "COMMAND";
+static std::string const keyDEFINED = "DEFINED";
+static std::string const keyEQUAL = "EQUAL";
+static std::string const keyEXISTS = "EXISTS";
+static std::string const keyGREATER = "GREATER";
+static std::string const keyGREATER_EQUAL = "GREATER_EQUAL";
+static std::string const keyIN_LIST = "IN_LIST";
+static std::string const keyIS_ABSOLUTE = "IS_ABSOLUTE";
+static std::string const keyIS_DIRECTORY = "IS_DIRECTORY";
+static std::string const keyIS_NEWER_THAN = "IS_NEWER_THAN";
+static std::string const keyIS_SYMLINK = "IS_SYMLINK";
+static std::string const keyLESS = "LESS";
+static std::string const keyLESS_EQUAL = "LESS_EQUAL";
+static std::string const keyMATCHES = "MATCHES";
+static std::string const keyNOT = "NOT";
+static std::string const keyOR = "OR";
+static std::string const keyParenL = "(";
+static std::string const keyParenR = ")";
+static std::string const keyPOLICY = "POLICY";
+static std::string const keySTREQUAL = "STREQUAL";
+static std::string const keySTRGREATER = "STRGREATER";
+static std::string const keySTRGREATER_EQUAL = "STRGREATER_EQUAL";
+static std::string const keySTRLESS = "STRLESS";
+static std::string const keySTRLESS_EQUAL = "STRLESS_EQUAL";
+static std::string const keyTARGET = "TARGET";
+static std::string const keyTEST = "TEST";
+static std::string const keyVERSION_EQUAL = "VERSION_EQUAL";
+static std::string const keyVERSION_GREATER = "VERSION_GREATER";
+static std::string const keyVERSION_GREATER_EQUAL = "VERSION_GREATER_EQUAL";
+static std::string const keyVERSION_LESS = "VERSION_LESS";
+static std::string const keyVERSION_LESS_EQUAL = "VERSION_LESS_EQUAL";
+
+cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile,
+ cmListFileBacktrace bt)
+ : Makefile(makefile)
+ , Backtrace(std::move(bt))
+ , Policy12Status(makefile.GetPolicyStatus(cmPolicies::CMP0012))
+ , Policy54Status(makefile.GetPolicyStatus(cmPolicies::CMP0054))
+ , Policy57Status(makefile.GetPolicyStatus(cmPolicies::CMP0057))
+ , Policy64Status(makefile.GetPolicyStatus(cmPolicies::CMP0064))
+{
+}
+
+//=========================================================================
+// order of operations,
+// 1. ( ) -- parenthetical groups
+// 2. IS_DIRECTORY EXISTS COMMAND DEFINED etc predicates
+// 3. MATCHES LESS GREATER EQUAL STRLESS STRGREATER STREQUAL etc binary ops
+// 4. NOT
+// 5. AND OR
+//
+// There is an issue on whether the arguments should be values of references,
+// for example IF (FOO AND BAR) should that compare the strings FOO and BAR
+// or should it really do IF (${FOO} AND ${BAR}) Currently IS_DIRECTORY
+// EXISTS COMMAND and DEFINED all take values. EQUAL, LESS and GREATER can
+// take numeric values or variable names. STRLESS and STRGREATER take
+// variable names but if the variable name is not found it will use the name
+// directly. AND OR take variables or the values 0 or 1.
+
+bool cmConditionEvaluator::IsTrue(
+ const std::vector<cmExpandedCommandArgument>& args, std::string& errorString,
+ MessageType& status)
+{
+ errorString.clear();
+
+ // handle empty invocation
+ if (args.empty()) {
+ return false;
+ }
+
+ // store the reduced args in this vector
+ cmArgumentList newArgs(args.begin(), args.end());
+
+ // now loop through the arguments and see if we can reduce any of them
+ // we do this multiple times. Once for each level of precedence
+ // parens
+ if (!this->HandleLevel0(newArgs, errorString, status)) {
+ return false;
+ }
+ // predicates
+ if (!this->HandleLevel1(newArgs, errorString, status)) {
+ return false;
+ }
+ // binary ops
+ if (!this->HandleLevel2(newArgs, errorString, status)) {
+ return false;
+ }
+
+ // NOT
+ if (!this->HandleLevel3(newArgs, errorString, status)) {
+ return false;
+ }
+ // AND OR
+ if (!this->HandleLevel4(newArgs, errorString, status)) {
+ return false;
+ }
+
+ // now at the end there should only be one argument left
+ if (newArgs.size() != 1) {
+ errorString = "Unknown arguments specified";
+ status = MessageType::FATAL_ERROR;
+ return false;
+ }
+
+ return this->GetBooleanValueWithAutoDereference(newArgs.front(), errorString,
+ status, true);
+}
+
+//=========================================================================
+cmProp cmConditionEvaluator::GetDefinitionIfUnquoted(
+ cmExpandedCommandArgument const& argument) const
+{
+ if ((this->Policy54Status != cmPolicies::WARN &&
+ this->Policy54Status != cmPolicies::OLD) &&
+ argument.WasQuoted()) {
+ return nullptr;
+ }
+
+ cmProp def = this->Makefile.GetDefinition(argument.GetValue());
+
+ if (def && argument.WasQuoted() &&
+ this->Policy54Status == cmPolicies::WARN) {
+ if (!this->Makefile.HasCMP0054AlreadyBeenReported(this->Backtrace.Top())) {
+ std::ostringstream e;
+ e << (cmPolicies::GetPolicyWarning(cmPolicies::CMP0054)) << "\n";
+ e << "Quoted variables like \"" << argument.GetValue()
+ << "\" will no longer be dereferenced "
+ "when the policy is set to NEW. "
+ "Since the policy is not set the OLD behavior will be used.";
+
+ this->Makefile.GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING, e.str(), this->Backtrace);
+ }
+ }
+
+ return def;
+}
+
+//=========================================================================
+cmProp cmConditionEvaluator::GetVariableOrString(
+ const cmExpandedCommandArgument& argument) const
+{
+ cmProp def = this->GetDefinitionIfUnquoted(argument);
+
+ if (!def) {
+ def = &argument.GetValue();
+ }
+
+ return def;
+}
+
+//=========================================================================
+bool cmConditionEvaluator::IsKeyword(std::string const& keyword,
+ cmExpandedCommandArgument& argument) const
+{
+ if ((this->Policy54Status != cmPolicies::WARN &&
+ this->Policy54Status != cmPolicies::OLD) &&
+ argument.WasQuoted()) {
+ return false;
+ }
+
+ bool isKeyword = argument.GetValue() == keyword;
+
+ if (isKeyword && argument.WasQuoted() &&
+ this->Policy54Status == cmPolicies::WARN) {
+ if (!this->Makefile.HasCMP0054AlreadyBeenReported(this->Backtrace.Top())) {
+ std::ostringstream e;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0054) << "\n";
+ e << "Quoted keywords like \"" << argument.GetValue()
+ << "\" will no longer be interpreted as keywords "
+ "when the policy is set to NEW. "
+ "Since the policy is not set the OLD behavior will be used.";
+
+ this->Makefile.GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING, e.str(), this->Backtrace);
+ }
+ }
+
+ return isKeyword;
+}
+
+//=========================================================================
+bool cmConditionEvaluator::GetBooleanValue(
+ cmExpandedCommandArgument& arg) const
+{
+ // Check basic constants.
+ if (arg == "0") {
+ return false;
+ }
+ if (arg == "1") {
+ return true;
+ }
+
+ // Check named constants.
+ if (cmIsOn(arg.GetValue())) {
+ return true;
+ }
+ if (cmIsOff(arg.GetValue())) {
+ return false;
+ }
+
+ // Check for numbers.
+ if (!arg.empty()) {
+ char* end;
+ double d = strtod(arg.GetValue().c_str(), &end);
+ if (*end == '\0') {
+ // The whole string is a number. Use C conversion to bool.
+ return static_cast<bool>(d);
+ }
+ }
+
+ // Check definition.
+ cmProp def = this->GetDefinitionIfUnquoted(arg);
+ return !cmIsOff(def);
+}
+
+//=========================================================================
+// Boolean value behavior from CMake 2.6.4 and below.
+bool cmConditionEvaluator::GetBooleanValueOld(
+ cmExpandedCommandArgument const& arg, bool one) const
+{
+ if (one) {
+ // Old IsTrue behavior for single argument.
+ if (arg == "0") {
+ return false;
+ }
+ if (arg == "1") {
+ return true;
+ }
+ cmProp def = this->GetDefinitionIfUnquoted(arg);
+ return !cmIsOff(def);
+ }
+ // Old GetVariableOrNumber behavior.
+ cmProp def = this->GetDefinitionIfUnquoted(arg);
+ if (!def && atoi(arg.GetValue().c_str())) {
+ def = &arg.GetValue();
+ }
+ return !cmIsOff(def);
+}
+
+//=========================================================================
+// returns the resulting boolean value
+bool cmConditionEvaluator::GetBooleanValueWithAutoDereference(
+ cmExpandedCommandArgument& newArg, std::string& errorString,
+ MessageType& status, bool oneArg) const
+{
+ // Use the policy if it is set.
+ if (this->Policy12Status == cmPolicies::NEW) {
+ return this->GetBooleanValue(newArg);
+ }
+ if (this->Policy12Status == cmPolicies::OLD) {
+ return this->GetBooleanValueOld(newArg, oneArg);
+ }
+
+ // Check policy only if old and new results differ.
+ bool newResult = this->GetBooleanValue(newArg);
+ bool oldResult = this->GetBooleanValueOld(newArg, oneArg);
+ if (newResult != oldResult) {
+ switch (this->Policy12Status) {
+ case cmPolicies::WARN:
+ errorString = "An argument named \"" + newArg.GetValue() +
+ "\" appears in a conditional statement. " +
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0012);
+ status = MessageType::AUTHOR_WARNING;
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ return oldResult;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS: {
+ errorString = "An argument named \"" + newArg.GetValue() +
+ "\" appears in a conditional statement. " +
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0012);
+ status = MessageType::FATAL_ERROR;
+ }
+ case cmPolicies::NEW:
+ break;
+ }
+ }
+ return newResult;
+}
+
+//=========================================================================
+void cmConditionEvaluator::IncrementArguments(
+ cmArgumentList& newArgs, cmArgumentList::iterator& argP1,
+ cmArgumentList::iterator& argP2) const
+{
+ if (argP1 != newArgs.end()) {
+ argP1++;
+ argP2 = argP1;
+ if (argP1 != newArgs.end()) {
+ argP2++;
+ }
+ }
+}
+
+//=========================================================================
+// helper function to reduce code duplication
+void cmConditionEvaluator::HandlePredicate(
+ bool value, int& reducible, cmArgumentList::iterator& arg,
+ cmArgumentList& newArgs, cmArgumentList::iterator& argP1,
+ cmArgumentList::iterator& argP2) const
+{
+ if (value) {
+ *arg = cmExpandedCommandArgument("1", true);
+ } else {
+ *arg = cmExpandedCommandArgument("0", true);
+ }
+ newArgs.erase(argP1);
+ argP1 = arg;
+ this->IncrementArguments(newArgs, argP1, argP2);
+ reducible = 1;
+}
+
+//=========================================================================
+// helper function to reduce code duplication
+void cmConditionEvaluator::HandleBinaryOp(bool value, int& reducible,
+ cmArgumentList::iterator& arg,
+ cmArgumentList& newArgs,
+ cmArgumentList::iterator& argP1,
+ cmArgumentList::iterator& argP2)
+{
+ if (value) {
+ *arg = cmExpandedCommandArgument("1", true);
+ } else {
+ *arg = cmExpandedCommandArgument("0", true);
+ }
+ newArgs.erase(argP2);
+ newArgs.erase(argP1);
+ argP1 = arg;
+ this->IncrementArguments(newArgs, argP1, argP2);
+ reducible = 1;
+}
+
+//=========================================================================
+// level 0 processes parenthetical expressions
+bool cmConditionEvaluator::HandleLevel0(cmArgumentList& newArgs,
+ std::string& errorString,
+ MessageType& status)
+{
+ int reducible;
+ do {
+ reducible = 0;
+ auto arg = newArgs.begin();
+ while (arg != newArgs.end()) {
+ if (this->IsKeyword(keyParenL, *arg)) {
+ // search for the closing paren for this opening one
+ cmArgumentList::iterator argClose;
+ argClose = arg;
+ argClose++;
+ unsigned int depth = 1;
+ while (argClose != newArgs.end() && depth) {
+ if (this->IsKeyword(keyParenL, *argClose)) {
+ depth++;
+ }
+ if (this->IsKeyword(keyParenR, *argClose)) {
+ depth--;
+ }
+ argClose++;
+ }
+ if (depth) {
+ errorString = "mismatched parenthesis in condition";
+ status = MessageType::FATAL_ERROR;
+ return false;
+ }
+ // store the reduced args in this vector
+ std::vector<cmExpandedCommandArgument> newArgs2;
+
+ // copy to the list structure
+ auto argP1 = arg;
+ argP1++;
+ cm::append(newArgs2, argP1, argClose);
+ newArgs2.pop_back();
+ // now recursively invoke IsTrue to handle the values inside the
+ // parenthetical expression
+ bool value = this->IsTrue(newArgs2, errorString, status);
+ if (value) {
+ *arg = cmExpandedCommandArgument("1", true);
+ } else {
+ *arg = cmExpandedCommandArgument("0", true);
+ }
+ argP1 = arg;
+ argP1++;
+ // remove the now evaluated parenthetical expression
+ newArgs.erase(argP1, argClose);
+ }
+ ++arg;
+ }
+ } while (reducible);
+ return true;
+}
+
+//=========================================================================
+// level one handles most predicates except for NOT
+bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&,
+ MessageType&)
+{
+ int reducible;
+ do {
+ reducible = 0;
+ auto arg = newArgs.begin();
+ cmArgumentList::iterator argP1;
+ cmArgumentList::iterator argP2;
+ while (arg != newArgs.end()) {
+ argP1 = arg;
+ this->IncrementArguments(newArgs, argP1, argP2);
+ // does a file exist
+ if (this->IsKeyword(keyEXISTS, *arg) && argP1 != newArgs.end()) {
+ this->HandlePredicate(cmSystemTools::FileExists(argP1->GetValue()),
+ reducible, arg, newArgs, argP1, argP2);
+ }
+ // does a directory with this name exist
+ if (this->IsKeyword(keyIS_DIRECTORY, *arg) && argP1 != newArgs.end()) {
+ this->HandlePredicate(
+ cmSystemTools::FileIsDirectory(argP1->GetValue()), reducible, arg,
+ newArgs, argP1, argP2);
+ }
+ // does a symlink with this name exist
+ if (this->IsKeyword(keyIS_SYMLINK, *arg) && argP1 != newArgs.end()) {
+ this->HandlePredicate(cmSystemTools::FileIsSymlink(argP1->GetValue()),
+ reducible, arg, newArgs, argP1, argP2);
+ }
+ // is the given path an absolute path ?
+ if (this->IsKeyword(keyIS_ABSOLUTE, *arg) && argP1 != newArgs.end()) {
+ this->HandlePredicate(cmSystemTools::FileIsFullPath(argP1->GetValue()),
+ reducible, arg, newArgs, argP1, argP2);
+ }
+ // does a command exist
+ if (this->IsKeyword(keyCOMMAND, *arg) && argP1 != newArgs.end()) {
+ cmState::Command command =
+ this->Makefile.GetState()->GetCommand(argP1->GetValue());
+ this->HandlePredicate(command != nullptr, reducible, arg, newArgs,
+ argP1, argP2);
+ }
+ // does a policy exist
+ if (this->IsKeyword(keyPOLICY, *arg) && argP1 != newArgs.end()) {
+ cmPolicies::PolicyID pid;
+ this->HandlePredicate(
+ cmPolicies::GetPolicyID(argP1->GetValue().c_str(), pid), reducible,
+ arg, newArgs, argP1, argP2);
+ }
+ // does a target exist
+ if (this->IsKeyword(keyTARGET, *arg) && argP1 != newArgs.end()) {
+ this->HandlePredicate(
+ this->Makefile.FindTargetToUse(argP1->GetValue()) != nullptr,
+ reducible, arg, newArgs, argP1, argP2);
+ }
+ // does a test exist
+ if (this->Policy64Status != cmPolicies::OLD &&
+ this->Policy64Status != cmPolicies::WARN) {
+ if (this->IsKeyword(keyTEST, *arg) && argP1 != newArgs.end()) {
+ const cmTest* haveTest = this->Makefile.GetTest(argP1->GetValue());
+ this->HandlePredicate(haveTest != nullptr, reducible, arg, newArgs,
+ argP1, argP2);
+ }
+ } else if (this->Policy64Status == cmPolicies::WARN &&
+ this->IsKeyword(keyTEST, *arg)) {
+ std::ostringstream e;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0064) << "\n";
+ e << "TEST will be interpreted as an operator "
+ "when the policy is set to NEW. "
+ "Since the policy is not set the OLD behavior will be used.";
+
+ this->Makefile.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+ }
+ // is a variable defined
+ if (this->IsKeyword(keyDEFINED, *arg) && argP1 != newArgs.end()) {
+ size_t argP1len = argP1->GetValue().size();
+ bool bdef = false;
+ if (argP1len > 4 && cmHasLiteralPrefix(argP1->GetValue(), "ENV{") &&
+ argP1->GetValue().operator[](argP1len - 1) == '}') {
+ std::string env = argP1->GetValue().substr(4, argP1len - 5);
+ bdef = cmSystemTools::HasEnv(env);
+ } else if (argP1len > 6 &&
+ cmHasLiteralPrefix(argP1->GetValue(), "CACHE{") &&
+ argP1->GetValue().operator[](argP1len - 1) == '}') {
+ std::string cache = argP1->GetValue().substr(6, argP1len - 7);
+ bdef =
+ this->Makefile.GetState()->GetCacheEntryValue(cache) != nullptr;
+ } else {
+ bdef = this->Makefile.IsDefinitionSet(argP1->GetValue());
+ }
+ this->HandlePredicate(bdef, reducible, arg, newArgs, argP1, argP2);
+ }
+ ++arg;
+ }
+ } while (reducible);
+ return true;
+}
+
+//=========================================================================
+// level two handles most binary operations except for AND OR
+bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs,
+ std::string& errorString,
+ MessageType& status)
+{
+ int reducible;
+ std::string def_buf;
+ cmProp def;
+ cmProp def2;
+ do {
+ reducible = 0;
+ auto arg = newArgs.begin();
+ cmArgumentList::iterator argP1;
+ cmArgumentList::iterator argP2;
+ while (arg != newArgs.end()) {
+ argP1 = arg;
+ this->IncrementArguments(newArgs, argP1, argP2);
+ if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
+ this->IsKeyword(keyMATCHES, *argP1)) {
+ def = this->GetDefinitionIfUnquoted(*arg);
+ if (!def) {
+ def = &arg->GetValue();
+ } else if (cmHasLiteralPrefix(arg->GetValue(), "CMAKE_MATCH_")) {
+ // The string to match is owned by our match result variables.
+ // Move it to our own buffer before clearing them.
+ def_buf = *def;
+ def = &def_buf;
+ }
+ const std::string& rex = argP2->GetValue();
+ this->Makefile.ClearMatches();
+ cmsys::RegularExpression regEntry;
+ if (!regEntry.compile(rex)) {
+ std::ostringstream error;
+ error << "Regular expression \"" << rex << "\" cannot compile";
+ errorString = error.str();
+ status = MessageType::FATAL_ERROR;
+ return false;
+ }
+ if (regEntry.find(*def)) {
+ this->Makefile.StoreMatches(regEntry);
+ *arg = cmExpandedCommandArgument("1", true);
+ } else {
+ *arg = cmExpandedCommandArgument("0", true);
+ }
+ newArgs.erase(argP2);
+ newArgs.erase(argP1);
+ argP1 = arg;
+ this->IncrementArguments(newArgs, argP1, argP2);
+ reducible = 1;
+ }
+
+ if (argP1 != newArgs.end() && this->IsKeyword(keyMATCHES, *arg)) {
+ *arg = cmExpandedCommandArgument("0", true);
+ newArgs.erase(argP1);
+ argP1 = arg;
+ this->IncrementArguments(newArgs, argP1, argP2);
+ reducible = 1;
+ }
+
+ if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
+ (this->IsKeyword(keyLESS, *argP1) ||
+ this->IsKeyword(keyLESS_EQUAL, *argP1) ||
+ this->IsKeyword(keyGREATER, *argP1) ||
+ this->IsKeyword(keyGREATER_EQUAL, *argP1) ||
+ this->IsKeyword(keyEQUAL, *argP1))) {
+ def = this->GetVariableOrString(*arg);
+ def2 = this->GetVariableOrString(*argP2);
+ double lhs;
+ double rhs;
+ bool result;
+ if (sscanf(def->c_str(), "%lg", &lhs) != 1 ||
+ sscanf(def2->c_str(), "%lg", &rhs) != 1) {
+ result = false;
+ } else if (*(argP1) == keyLESS) {
+ result = (lhs < rhs);
+ } else if (*(argP1) == keyLESS_EQUAL) {
+ result = (lhs <= rhs);
+ } else if (*(argP1) == keyGREATER) {
+ result = (lhs > rhs);
+ } else if (*(argP1) == keyGREATER_EQUAL) {
+ result = (lhs >= rhs);
+ } else {
+ result = (lhs == rhs);
+ }
+ this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
+ }
+
+ if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
+ (this->IsKeyword(keySTRLESS, *argP1) ||
+ this->IsKeyword(keySTRLESS_EQUAL, *argP1) ||
+ this->IsKeyword(keySTRGREATER, *argP1) ||
+ this->IsKeyword(keySTRGREATER_EQUAL, *argP1) ||
+ this->IsKeyword(keySTREQUAL, *argP1))) {
+ def = this->GetVariableOrString(*arg);
+ def2 = this->GetVariableOrString(*argP2);
+ int val = (*def).compare(*def2);
+ bool result;
+ if (*(argP1) == keySTRLESS) {
+ result = (val < 0);
+ } else if (*(argP1) == keySTRLESS_EQUAL) {
+ result = (val <= 0);
+ } else if (*(argP1) == keySTRGREATER) {
+ result = (val > 0);
+ } else if (*(argP1) == keySTRGREATER_EQUAL) {
+ result = (val >= 0);
+ } else // strequal
+ {
+ result = (val == 0);
+ }
+ this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
+ }
+
+ if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
+ (this->IsKeyword(keyVERSION_LESS, *argP1) ||
+ this->IsKeyword(keyVERSION_LESS_EQUAL, *argP1) ||
+ this->IsKeyword(keyVERSION_GREATER, *argP1) ||
+ this->IsKeyword(keyVERSION_GREATER_EQUAL, *argP1) ||
+ this->IsKeyword(keyVERSION_EQUAL, *argP1))) {
+ def = this->GetVariableOrString(*arg);
+ def2 = this->GetVariableOrString(*argP2);
+ cmSystemTools::CompareOp op;
+ if (*argP1 == keyVERSION_LESS) {
+ op = cmSystemTools::OP_LESS;
+ } else if (*argP1 == keyVERSION_LESS_EQUAL) {
+ op = cmSystemTools::OP_LESS_EQUAL;
+ } else if (*argP1 == keyVERSION_GREATER) {
+ op = cmSystemTools::OP_GREATER;
+ } else if (*argP1 == keyVERSION_GREATER_EQUAL) {
+ op = cmSystemTools::OP_GREATER_EQUAL;
+ } else { // version_equal
+ op = cmSystemTools::OP_EQUAL;
+ }
+ bool result =
+ cmSystemTools::VersionCompare(op, def->c_str(), def2->c_str());
+ this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
+ }
+
+ // is file A newer than file B
+ if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
+ this->IsKeyword(keyIS_NEWER_THAN, *argP1)) {
+ int fileIsNewer = 0;
+ bool success = cmSystemTools::FileTimeCompare(
+ arg->GetValue(), (argP2)->GetValue(), &fileIsNewer);
+ this->HandleBinaryOp(
+ (!success || fileIsNewer == 1 || fileIsNewer == 0), reducible, arg,
+ newArgs, argP1, argP2);
+ }
+
+ if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
+ this->IsKeyword(keyIN_LIST, *argP1)) {
+ if (this->Policy57Status != cmPolicies::OLD &&
+ this->Policy57Status != cmPolicies::WARN) {
+ bool result = false;
+
+ def = this->GetVariableOrString(*arg);
+ def2 = this->Makefile.GetDefinition(argP2->GetValue());
+
+ if (def2) {
+ std::vector<std::string> list = cmExpandedList(*def2, true);
+ result = cm::contains(list, *def);
+ }
+
+ this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
+ } else if (this->Policy57Status == cmPolicies::WARN) {
+ std::ostringstream e;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0057) << "\n";
+ e << "IN_LIST will be interpreted as an operator "
+ "when the policy is set to NEW. "
+ "Since the policy is not set the OLD behavior will be used.";
+
+ this->Makefile.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+ }
+ }
+
+ ++arg;
+ }
+ } while (reducible);
+ return true;
+}
+
+//=========================================================================
+// level 3 handles NOT
+bool cmConditionEvaluator::HandleLevel3(cmArgumentList& newArgs,
+ std::string& errorString,
+ MessageType& status)
+{
+ int reducible;
+ do {
+ reducible = 0;
+ auto arg = newArgs.begin();
+ cmArgumentList::iterator argP1;
+ cmArgumentList::iterator argP2;
+ while (arg != newArgs.end()) {
+ argP1 = arg;
+ this->IncrementArguments(newArgs, argP1, argP2);
+ if (argP1 != newArgs.end() && this->IsKeyword(keyNOT, *arg)) {
+ bool rhs = this->GetBooleanValueWithAutoDereference(
+ *argP1, errorString, status);
+ this->HandlePredicate(!rhs, reducible, arg, newArgs, argP1, argP2);
+ }
+ ++arg;
+ }
+ } while (reducible);
+ return true;
+}
+
+//=========================================================================
+// level 4 handles AND OR
+bool cmConditionEvaluator::HandleLevel4(cmArgumentList& newArgs,
+ std::string& errorString,
+ MessageType& status)
+{
+ int reducible;
+ bool lhs;
+ bool rhs;
+ do {
+ reducible = 0;
+ auto arg = newArgs.begin();
+ cmArgumentList::iterator argP1;
+ cmArgumentList::iterator argP2;
+ while (arg != newArgs.end()) {
+ argP1 = arg;
+ this->IncrementArguments(newArgs, argP1, argP2);
+ if (argP1 != newArgs.end() && this->IsKeyword(keyAND, *argP1) &&
+ argP2 != newArgs.end()) {
+ lhs =
+ this->GetBooleanValueWithAutoDereference(*arg, errorString, status);
+ rhs = this->GetBooleanValueWithAutoDereference(*argP2, errorString,
+ status);
+ this->HandleBinaryOp((lhs && rhs), reducible, arg, newArgs, argP1,
+ argP2);
+ }
+
+ if (argP1 != newArgs.end() && this->IsKeyword(keyOR, *argP1) &&
+ argP2 != newArgs.end()) {
+ lhs =
+ this->GetBooleanValueWithAutoDereference(*arg, errorString, status);
+ rhs = this->GetBooleanValueWithAutoDereference(*argP2, errorString,
+ status);
+ this->HandleBinaryOp((lhs || rhs), reducible, arg, newArgs, argP1,
+ argP2);
+ }
+ ++arg;
+ }
+ } while (reducible);
+ return true;
+}
diff --git a/Source/cmConditionEvaluator.h b/Source/cmConditionEvaluator.h
new file mode 100644
index 0000000..cf00ede
--- /dev/null
+++ b/Source/cmConditionEvaluator.h
@@ -0,0 +1,86 @@
+/* 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 <list>
+#include <string>
+#include <vector>
+
+#include "cmExpandedCommandArgument.h"
+#include "cmListFileCache.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+
+class cmMakefile;
+
+class cmConditionEvaluator
+{
+public:
+ using cmArgumentList = std::list<cmExpandedCommandArgument>;
+
+ 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
+ // an error, the errorString will be set.
+ bool IsTrue(const std::vector<cmExpandedCommandArgument>& args,
+ std::string& errorString, MessageType& status);
+
+private:
+ // Filter the given variable definition based on policy CMP0054.
+ cmProp GetDefinitionIfUnquoted(
+ const cmExpandedCommandArgument& argument) const;
+
+ cmProp GetVariableOrString(const cmExpandedCommandArgument& argument) const;
+
+ bool IsKeyword(std::string const& keyword,
+ cmExpandedCommandArgument& argument) const;
+
+ bool GetBooleanValue(cmExpandedCommandArgument& arg) const;
+
+ bool GetBooleanValueOld(cmExpandedCommandArgument const& arg,
+ bool one) const;
+
+ bool GetBooleanValueWithAutoDereference(cmExpandedCommandArgument& newArg,
+ std::string& errorString,
+ MessageType& status,
+ bool oneArg = false) const;
+
+ void IncrementArguments(cmArgumentList& newArgs,
+ cmArgumentList::iterator& argP1,
+ cmArgumentList::iterator& argP2) const;
+
+ void HandlePredicate(bool value, int& reducible,
+ cmArgumentList::iterator& arg, cmArgumentList& newArgs,
+ cmArgumentList::iterator& argP1,
+ cmArgumentList::iterator& argP2) const;
+
+ void HandleBinaryOp(bool value, int& reducible,
+ cmArgumentList::iterator& arg, cmArgumentList& newArgs,
+ cmArgumentList::iterator& argP1,
+ cmArgumentList::iterator& argP2);
+
+ bool HandleLevel0(cmArgumentList& newArgs, std::string& errorString,
+ MessageType& status);
+
+ bool HandleLevel1(cmArgumentList& newArgs, std::string&, MessageType&);
+
+ bool HandleLevel2(cmArgumentList& newArgs, std::string& errorString,
+ MessageType& status);
+
+ bool HandleLevel3(cmArgumentList& newArgs, std::string& errorString,
+ MessageType& status);
+
+ bool HandleLevel4(cmArgumentList& newArgs, std::string& errorString,
+ MessageType& status);
+
+ cmMakefile& Makefile;
+ cmListFileBacktrace Backtrace;
+ cmPolicies::PolicyStatus Policy12Status;
+ cmPolicies::PolicyStatus Policy54Status;
+ cmPolicies::PolicyStatus Policy57Status;
+ cmPolicies::PolicyStatus Policy64Status;
+};
diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in
new file mode 100644
index 0000000..aeca6b4
--- /dev/null
+++ b/Source/cmConfigure.cmake.h.in
@@ -0,0 +1,31 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmsys/Configure.hxx" // IWYU pragma: export
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4786)
+#pragma warning(disable : 4503)
+#endif
+
+#ifdef __ICL
+#pragma warning(disable : 985)
+#pragma warning(disable : 1572) /* floating-point equality test */
+#endif
+
+#cmakedefine HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE
+#cmakedefine HAVE_UNSETENV
+#cmakedefine CMake_USE_ELF_PARSER
+#cmakedefine CMake_USE_MACH_PARSER
+#cmakedefine CMake_USE_XCOFF_PARSER
+#define CMake_DEFAULT_RECURSION_LIMIT @CMake_DEFAULT_RECURSION_LIMIT@
+#define CMAKE_BIN_DIR "/@CMAKE_BIN_DIR@"
+#define CMAKE_DATA_DIR "/@CMAKE_DATA_DIR@"
+#define CMAKE_DOC_DIR "/@CMAKE_DOC_DIR@"
+
+#define CM_FALLTHROUGH cmsys_FALLTHROUGH
+
+#if defined(_WIN32) && !defined(NOMINMAX)
+# define NOMINMAX
+#endif
diff --git a/Source/cmConfigureFileCommand.cxx b/Source/cmConfigureFileCommand.cxx
new file mode 100644
index 0000000..12b2925
--- /dev/null
+++ b/Source/cmConfigureFileCommand.cxx
@@ -0,0 +1,214 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmConfigureFileCommand.h"
+
+#include <set>
+#include <sstream>
+
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include <sys/types.h>
+
+#include "cmExecutionStatus.h"
+#include "cmFSPermissions.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmNewLineStyle.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+// cmConfigureFileCommand
+bool cmConfigureFileCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with incorrect number of arguments, expected 2");
+ return false;
+ }
+
+ std::string const& inFile = args[0];
+ const std::string inputFile = cmSystemTools::CollapseFullPath(
+ inFile, status.GetMakefile().GetCurrentSourceDirectory());
+
+ // If the input location is a directory, error out.
+ if (cmSystemTools::FileIsDirectory(inputFile)) {
+ status.SetError(cmStrCat("input location\n ", inputFile,
+ "\n"
+ "is a directory but a file was expected."));
+ return false;
+ }
+
+ std::string const& outFile = args[1];
+ std::string outputFile = cmSystemTools::CollapseFullPath(
+ outFile, status.GetMakefile().GetCurrentBinaryDirectory());
+
+ // If the output location is already a directory put the file in it.
+ if (cmSystemTools::FileIsDirectory(outputFile)) {
+ outputFile += "/";
+ outputFile += cmSystemTools::GetFilenameName(inFile);
+ }
+
+ if (!status.GetMakefile().CanIWriteThisFile(outputFile)) {
+ std::string e = "attempted to configure a file: " + outputFile +
+ " into a source directory.";
+ status.SetError(e);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ std::string errorMessage;
+ cmNewLineStyle newLineStyle;
+ if (!newLineStyle.ReadFromArguments(args, errorMessage)) {
+ status.SetError(errorMessage);
+ return false;
+ }
+ bool copyOnly = false;
+ bool escapeQuotes = false;
+ bool useSourcePermissions = false;
+ bool noSourcePermissions = false;
+ bool filePermissions = false;
+ std::vector<std::string> filePermissionOptions;
+
+ enum class Doing
+ {
+ DoingNone,
+ DoingFilePermissions,
+ DoneFilePermissions
+ };
+
+ Doing doing = Doing::DoingNone;
+
+ static std::set<cm::string_view> noopOptions = {
+ /* Legacy. */
+ "IMMEDIATE"_s,
+ /* Handled by NewLineStyle member. */
+ "NEWLINE_STYLE"_s,
+ "LF"_s,
+ "UNIX"_s,
+ "CRLF"_s,
+ "WIN32"_s,
+ "DOS"_s,
+ };
+
+ std::string unknown_args;
+ bool atOnly = false;
+ for (unsigned int i = 2; i < args.size(); ++i) {
+ if (args[i] == "COPYONLY") {
+ if (doing == Doing::DoingFilePermissions) {
+ doing = Doing::DoneFilePermissions;
+ }
+ copyOnly = true;
+ if (newLineStyle.IsValid()) {
+ status.SetError("COPYONLY could not be used in combination "
+ "with NEWLINE_STYLE");
+ return false;
+ }
+ } else if (args[i] == "ESCAPE_QUOTES") {
+ if (doing == Doing::DoingFilePermissions) {
+ doing = Doing::DoneFilePermissions;
+ }
+ escapeQuotes = true;
+ } else if (args[i] == "@ONLY") {
+ if (doing == Doing::DoingFilePermissions) {
+ doing = Doing::DoneFilePermissions;
+ }
+ atOnly = true;
+ } else if (args[i] == "NO_SOURCE_PERMISSIONS") {
+ if (doing == Doing::DoingFilePermissions) {
+ status.SetError(" given both FILE_PERMISSIONS and "
+ "NO_SOURCE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+ noSourcePermissions = true;
+ } else if (args[i] == "USE_SOURCE_PERMISSIONS") {
+ if (doing == Doing::DoingFilePermissions) {
+ status.SetError(" given both FILE_PERMISSIONS and "
+ "USE_SOURCE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+ useSourcePermissions = true;
+ } else if (args[i] == "FILE_PERMISSIONS") {
+ if (useSourcePermissions) {
+ status.SetError(" given both FILE_PERMISSIONS and "
+ "USE_SOURCE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+ if (noSourcePermissions) {
+ status.SetError(" given both FILE_PERMISSIONS and "
+ "NO_SOURCE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+
+ if (doing == Doing::DoingNone) {
+ doing = Doing::DoingFilePermissions;
+ filePermissions = true;
+ }
+ } else if (noopOptions.find(args[i]) != noopOptions.end()) {
+ /* Ignore no-op options. */
+ } else if (doing == Doing::DoingFilePermissions) {
+ filePermissionOptions.push_back(args[i]);
+ } else {
+ unknown_args += " ";
+ unknown_args += args[i];
+ unknown_args += "\n";
+ }
+ }
+ if (!unknown_args.empty()) {
+ std::string msg = cmStrCat(
+ "configure_file called with unknown argument(s):\n", unknown_args);
+ status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, msg);
+ }
+
+ if (useSourcePermissions && noSourcePermissions) {
+ status.SetError(" given both USE_SOURCE_PERMISSIONS and "
+ "NO_SOURCE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+
+ mode_t permissions = 0;
+
+ if (filePermissions) {
+ if (filePermissionOptions.empty()) {
+ status.SetError(" given FILE_PERMISSIONS without any options.");
+ return false;
+ }
+
+ std::vector<std::string> invalidOptions;
+ for (auto const& e : filePermissionOptions) {
+ if (!cmFSPermissions::stringToModeT(e, permissions)) {
+ invalidOptions.push_back(e);
+ }
+ }
+
+ if (!invalidOptions.empty()) {
+ std::ostringstream oss;
+ oss << " given invalid permission ";
+ for (auto i = 0u; i < invalidOptions.size(); i++) {
+ if (i == 0u) {
+ oss << "\"" << invalidOptions[i] << "\"";
+ } else {
+ oss << ",\"" << invalidOptions[i] << "\"";
+ }
+ }
+ oss << ".";
+ status.SetError(oss.str());
+ return false;
+ }
+ }
+
+ if (noSourcePermissions) {
+ permissions |= cmFSPermissions::mode_owner_read;
+ permissions |= cmFSPermissions::mode_owner_write;
+ permissions |= cmFSPermissions::mode_group_read;
+ permissions |= cmFSPermissions::mode_world_read;
+ }
+
+ if (!status.GetMakefile().ConfigureFile(inputFile, outputFile, copyOnly,
+ atOnly, escapeQuotes, permissions,
+ newLineStyle)) {
+ status.SetError("Problem configuring file");
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmConfigureFileCommand.h b/Source/cmConfigureFileCommand.h
new file mode 100644
index 0000000..009c145
--- /dev/null
+++ b/Source/cmConfigureFileCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmConfigureFileCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmConsoleBuf.cxx b/Source/cmConsoleBuf.cxx
new file mode 100644
index 0000000..8ce9ebc
--- /dev/null
+++ b/Source/cmConsoleBuf.cxx
@@ -0,0 +1,21 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmConsoleBuf.h"
+
+#if defined(_WIN32) && !defined(CMAKE_BOOTSTRAP)
+cmConsoleBuf::cmConsoleBuf()
+ : m_ConsoleOut(std::cout)
+ , m_ConsoleErr(std::cerr, true)
+{
+}
+#else
+cmConsoleBuf::cmConsoleBuf() = default;
+#endif
+
+void cmConsoleBuf::SetUTF8Pipes()
+{
+#if defined(_WIN32) && !defined(CMAKE_BOOTSTRAP)
+ m_ConsoleOut.SetUTF8Pipes();
+ m_ConsoleErr.SetUTF8Pipes();
+#endif
+}
diff --git a/Source/cmConsoleBuf.h b/Source/cmConsoleBuf.h
new file mode 100644
index 0000000..0a6d3b5
--- /dev/null
+++ b/Source/cmConsoleBuf.h
@@ -0,0 +1,23 @@
+/* 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
+
+#if defined(_WIN32) && !defined(CMAKE_BOOTSTRAP)
+# include "cmsys/ConsoleBuf.hxx"
+#endif
+
+class cmConsoleBuf
+{
+#if defined(_WIN32) && !defined(CMAKE_BOOTSTRAP)
+ cmsys::ConsoleBuf::Manager m_ConsoleOut;
+ cmsys::ConsoleBuf::Manager m_ConsoleErr;
+#endif
+public:
+ cmConsoleBuf();
+ ~cmConsoleBuf() = default;
+ cmConsoleBuf(cmConsoleBuf const&) = delete;
+ cmConsoleBuf& operator=(cmConsoleBuf const&) = delete;
+ void SetUTF8Pipes();
+};
diff --git a/Source/cmContinueCommand.cxx b/Source/cmContinueCommand.cxx
new file mode 100644
index 0000000..bb63dff
--- /dev/null
+++ b/Source/cmContinueCommand.cxx
@@ -0,0 +1,35 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmContinueCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmSystemTools.h"
+
+// cmContinueCommand
+bool cmContinueCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (!status.GetMakefile().IsLoopBlock()) {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ "A CONTINUE command was found outside of a "
+ "proper FOREACH or WHILE loop scope.");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+
+ status.SetContinueInvoked();
+
+ if (!args.empty()) {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ "The CONTINUE command does not accept any "
+ "arguments.");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+
+ return true;
+}
diff --git a/Source/cmContinueCommand.h b/Source/cmContinueCommand.h
new file mode 100644
index 0000000..29a219f
--- /dev/null
+++ b/Source/cmContinueCommand.h
@@ -0,0 +1,18 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Continue from an enclosing foreach or while loop
+ *
+ * cmContinueCommand returns from an enclosing foreach or while loop
+ */
+bool cmContinueCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmConvertMSBuildXMLToJSON.py b/Source/cmConvertMSBuildXMLToJSON.py
new file mode 100644
index 0000000..2be3781
--- /dev/null
+++ b/Source/cmConvertMSBuildXMLToJSON.py
@@ -0,0 +1,471 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+import argparse
+import codecs
+import copy
+import logging
+import json
+import os
+
+from collections import OrderedDict
+from xml.dom.minidom import parse, parseString, Element
+
+
+class VSFlags:
+ """Flags corresponding to cmIDEFlagTable."""
+ UserValue = "UserValue" # (1 << 0)
+ UserIgnored = "UserIgnored" # (1 << 1)
+ UserRequired = "UserRequired" # (1 << 2)
+ Continue = "Continue" #(1 << 3)
+ SemicolonAppendable = "SemicolonAppendable" # (1 << 4)
+ UserFollowing = "UserFollowing" # (1 << 5)
+ CaseInsensitive = "CaseInsensitive" # (1 << 6)
+ UserValueIgnored = [UserValue, UserIgnored]
+ UserValueRequired = [UserValue, UserRequired]
+
+
+def vsflags(*args):
+ """Combines the flags."""
+ values = []
+
+ for arg in args:
+ __append_list(values, arg)
+
+ return values
+
+
+def read_msbuild_xml(path, values=None):
+ """Reads the MS Build XML file at the path and returns its contents.
+
+ Keyword arguments:
+ values -- The map to append the contents to (default {})
+ """
+ if values is None:
+ values = {}
+
+ # Attempt to read the file contents
+ try:
+ document = parse(path)
+ except Exception as e:
+ logging.exception('Could not read MS Build XML file at %s', path)
+ return values
+
+ # Convert the XML to JSON format
+ logging.info('Processing MS Build XML file at %s', path)
+
+ # Get the rule node
+ rule = document.getElementsByTagName('Rule')[0]
+
+ rule_name = rule.attributes['Name'].value
+
+ logging.info('Found rules for %s', rule_name)
+
+ # Proprocess Argument values
+ __preprocess_arguments(rule)
+
+ # Get all the values
+ converted_values = []
+ __convert(rule, 'EnumProperty', converted_values, __convert_enum)
+ __convert(rule, 'BoolProperty', converted_values, __convert_bool)
+ __convert(rule, 'StringListProperty', converted_values,
+ __convert_string_list)
+ __convert(rule, 'StringProperty', converted_values, __convert_string)
+ __convert(rule, 'IntProperty', converted_values, __convert_string)
+
+ values[rule_name] = converted_values
+
+ return values
+
+
+def read_msbuild_json(path, values=None):
+ """Reads the MS Build JSON file at the path and returns its contents.
+
+ Keyword arguments:
+ values -- The list to append the contents to (default [])
+ """
+ if values is None:
+ values = []
+
+ if not os.path.exists(path):
+ logging.info('Could not find MS Build JSON file at %s', path)
+ return values
+
+ try:
+ values.extend(__read_json_file(path))
+ except Exception as e:
+ logging.exception('Could not read MS Build JSON file at %s', path)
+ return values
+
+ logging.info('Processing MS Build JSON file at %s', path)
+
+ return values
+
+def main():
+ """Script entrypoint."""
+ # Parse the arguments
+ parser = argparse.ArgumentParser(
+ description='Convert MSBuild XML to JSON format')
+
+ parser.add_argument(
+ '-t', '--toolchain', help='The name of the toolchain', required=True)
+ parser.add_argument(
+ '-o', '--output', help='The output directory', default='')
+ parser.add_argument(
+ '-r',
+ '--overwrite',
+ help='Whether previously output should be overwritten',
+ dest='overwrite',
+ action='store_true')
+ parser.set_defaults(overwrite=False)
+ parser.add_argument(
+ '-d',
+ '--debug',
+ help="Debug tool output",
+ action="store_const",
+ dest="loglevel",
+ const=logging.DEBUG,
+ default=logging.WARNING)
+ parser.add_argument(
+ '-v',
+ '--verbose',
+ help="Verbose output",
+ action="store_const",
+ dest="loglevel",
+ const=logging.INFO)
+ parser.add_argument('input', help='The input files', nargs='+')
+
+ args = parser.parse_args()
+
+ toolchain = args.toolchain
+
+ logging.basicConfig(level=args.loglevel)
+ logging.info('Creating %s toolchain files', toolchain)
+
+ values = {}
+
+ # Iterate through the inputs
+ for input in args.input:
+ input = __get_path(input)
+
+ read_msbuild_xml(input, values)
+
+ # Determine if the output directory needs to be created
+ output_dir = __get_path(args.output)
+
+ if not os.path.exists(output_dir):
+ os.mkdir(output_dir)
+ logging.info('Created output directory %s', output_dir)
+
+ for key, value in values.items():
+ output_path = __output_path(toolchain, key, output_dir)
+
+ if os.path.exists(output_path) and not args.overwrite:
+ logging.info('Comparing previous output to current')
+
+ __merge_json_values(value, read_msbuild_json(output_path))
+ else:
+ logging.info('Original output will be overwritten')
+
+ logging.info('Writing MS Build JSON file at %s', output_path)
+
+ __write_json_file(output_path, value)
+
+
+###########################################################################################
+# private joining functions
+def __merge_json_values(current, previous):
+ """Merges the values between the current and previous run of the script."""
+ for value in current:
+ name = value['name']
+
+ # Find the previous value
+ previous_value = __find_and_remove_value(previous, value)
+
+ if previous_value is not None:
+ flags = value['flags']
+ previous_flags = previous_value['flags']
+
+ if flags != previous_flags:
+ logging.warning(
+ 'Flags for %s are different. Using previous value.', name)
+
+ value['flags'] = previous_flags
+ else:
+ logging.warning('Value %s is a new value', name)
+
+ for value in previous:
+ name = value['name']
+ logging.warning(
+ 'Value %s not present in current run. Appending value.', name)
+
+ current.append(value)
+
+
+def __find_and_remove_value(list, compare):
+ """Finds the value in the list that corresponds with the value of compare."""
+ # next throws if there are no matches
+ try:
+ found = next(value for value in list
+ if value['name'] == compare['name'] and value['switch'] ==
+ compare['switch'])
+ except:
+ return None
+
+ list.remove(found)
+
+ return found
+
+
+def __normalize_switch(switch, separator):
+ new = switch
+ if switch.startswith("/") or switch.startswith("-"):
+ new = switch[1:]
+ if new and separator:
+ new = new + separator
+ return new
+
+###########################################################################################
+# private xml functions
+def __convert(root, tag, values, func):
+ """Converts the tag type found in the root and converts them using the func
+ and appends them to the values.
+ """
+ elements = root.getElementsByTagName(tag)
+
+ for element in elements:
+ converted = func(element)
+
+ # Append to the list
+ __append_list(values, converted)
+
+
+def __convert_enum(node):
+ """Converts an EnumProperty node to JSON format."""
+ name = __get_attribute(node, 'Name')
+ logging.debug('Found EnumProperty named %s', name)
+
+ converted_values = []
+
+ for value in node.getElementsByTagName('EnumValue'):
+ converted = __convert_node(value)
+
+ converted['value'] = converted['name']
+ converted['name'] = name
+
+ # Modify flags when there is an argument child
+ __with_argument(value, converted)
+
+ converted_values.append(converted)
+
+ return converted_values
+
+
+def __convert_bool(node):
+ """Converts an BoolProperty node to JSON format."""
+ converted = __convert_node(node, default_value='true')
+
+ # Check for a switch for reversing the value
+ reverse_switch = __get_attribute(node, 'ReverseSwitch')
+
+ if reverse_switch:
+ __with_argument(node, converted)
+
+ converted_reverse = copy.deepcopy(converted)
+
+ converted_reverse['switch'] = reverse_switch
+ converted_reverse['value'] = 'false'
+
+ return [converted_reverse, converted]
+
+ # Modify flags when there is an argument child
+ __with_argument(node, converted)
+
+ return __check_for_flag(converted)
+
+
+def __convert_string_list(node):
+ """Converts a StringListProperty node to JSON format."""
+ converted = __convert_node(node)
+
+ # Determine flags for the string list
+ flags = vsflags(VSFlags.UserValue)
+
+ # Check for a separator to determine if it is semicolon appendable
+ # If not present assume the value should be ;
+ separator = __get_attribute(node, 'Separator', default_value=';')
+
+ if separator == ';':
+ flags = vsflags(flags, VSFlags.SemicolonAppendable)
+
+ converted['flags'] = flags
+
+ return __check_for_flag(converted)
+
+
+def __convert_string(node):
+ """Converts a StringProperty node to JSON format."""
+ converted = __convert_node(node, default_flags=vsflags(VSFlags.UserValue))
+
+ return __check_for_flag(converted)
+
+
+def __convert_node(node, default_value='', default_flags=vsflags()):
+ """Converts a XML node to a JSON equivalent."""
+ name = __get_attribute(node, 'Name')
+ logging.debug('Found %s named %s', node.tagName, name)
+
+ converted = {}
+ converted['name'] = name
+
+ switch = __get_attribute(node, 'Switch')
+ separator = __get_attribute(node, 'Separator')
+ converted['switch'] = __normalize_switch(switch, separator)
+
+ converted['comment'] = __get_attribute(node, 'DisplayName')
+ converted['value'] = default_value
+
+ # Check for the Flags attribute in case it was created during preprocessing
+ flags = __get_attribute(node, 'Flags')
+
+ if flags:
+ flags = flags.split(',')
+ else:
+ flags = default_flags
+
+ converted['flags'] = flags
+
+ return converted
+
+
+def __check_for_flag(value):
+ """Checks whether the value has a switch value.
+
+ If not then returns None as it should not be added.
+ """
+ if value['switch']:
+ return value
+ else:
+ logging.warning('Skipping %s which has no command line switch',
+ value['name'])
+ return None
+
+
+def __with_argument(node, value):
+ """Modifies the flags in value if the node contains an Argument."""
+ arguments = node.getElementsByTagName('Argument')
+
+ if arguments:
+ logging.debug('Found argument within %s', value['name'])
+ value['flags'] = vsflags(VSFlags.UserValueIgnored, VSFlags.Continue)
+
+
+def __preprocess_arguments(root):
+ """Preprocesses occurrences of Argument within the root.
+
+ Argument XML values reference other values within the document by name. The
+ referenced value does not contain a switch. This function will add the
+ switch associated with the argument.
+ """
+ # Set the flags to require a value
+ flags = ','.join(vsflags(VSFlags.UserValueRequired))
+
+ # Search through the arguments
+ arguments = root.getElementsByTagName('Argument')
+
+ for argument in arguments:
+ reference = __get_attribute(argument, 'Property')
+ found = None
+
+ # Look for the argument within the root's children
+ for child in root.childNodes:
+ # Ignore Text nodes
+ if isinstance(child, Element):
+ name = __get_attribute(child, 'Name')
+
+ if name == reference:
+ found = child
+ break
+
+ if found is not None:
+ logging.info('Found property named %s', reference)
+ # Get the associated switch
+ switch = __get_attribute(argument.parentNode, 'Switch')
+
+ # See if there is already a switch associated with the element.
+ if __get_attribute(found, 'Switch'):
+ logging.debug('Copying node %s', reference)
+ clone = found.cloneNode(True)
+ root.insertBefore(clone, found)
+ found = clone
+
+ found.setAttribute('Switch', switch)
+ found.setAttribute('Flags', flags)
+ else:
+ logging.warning('Could not find property named %s', reference)
+
+
+def __get_attribute(node, name, default_value=''):
+ """Retrieves the attribute of the given name from the node.
+
+ If not present then the default_value is used.
+ """
+ if node.hasAttribute(name):
+ return node.attributes[name].value.strip()
+ else:
+ return default_value
+
+
+###########################################################################################
+# private path functions
+def __get_path(path):
+ """Gets the path to the file."""
+ if not os.path.isabs(path):
+ path = os.path.join(os.getcwd(), path)
+
+ return os.path.normpath(path)
+
+
+def __output_path(toolchain, rule, output_dir):
+ """Gets the output path for a file given the toolchain, rule and output_dir"""
+ filename = '%s_%s.json' % (toolchain, rule)
+ return os.path.join(output_dir, filename)
+
+
+###########################################################################################
+# private JSON file functions
+def __read_json_file(path):
+ """Reads a JSON file at the path."""
+ with open(path, 'r') as f:
+ return json.load(f)
+
+
+def __write_json_file(path, values):
+ """Writes a JSON file at the path with the values provided."""
+ # Sort the keys to ensure ordering
+ sort_order = ['name', 'switch', 'comment', 'value', 'flags']
+ sorted_values = [
+ OrderedDict(
+ sorted(
+ value.items(), key=lambda value: sort_order.index(value[0])))
+ for value in values
+ ]
+
+ with open(path, 'w') as f:
+ json.dump(sorted_values, f, indent=2, separators=(',', ': '))
+ f.write("\n")
+
+###########################################################################################
+# private list helpers
+def __append_list(append_to, value):
+ """Appends the value to the list."""
+ if value is not None:
+ if isinstance(value, list):
+ append_to.extend(value)
+ else:
+ append_to.append(value)
+
+###########################################################################################
+# main entry point
+if __name__ == "__main__":
+ main()
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
new file mode 100644
index 0000000..6672aa6
--- /dev/null
+++ b/Source/cmCoreTryCompile.cxx
@@ -0,0 +1,1093 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCoreTryCompile.h"
+
+#include <cstdio>
+#include <cstring>
+#include <set>
+#include <sstream>
+#include <utility>
+
+#include <cmext/string_view>
+
+#include "cmsys/Directory.hxx"
+
+#include "cmExportTryCompileFileGenerator.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmVersion.h"
+#include "cmake.h"
+
+namespace {
+class LanguageStandardState
+{
+public:
+ LanguageStandardState(std::string&& lang)
+ : IsEnabled(false)
+ , DidStandard(false)
+ , DidStandardRequired(false)
+ , DidExtensions(false)
+ , StandardFlag(lang + "_STANDARD")
+ , RequiredFlag(lang + "_STANDARD_REQUIRED")
+ , ExtensionFlag(lang + "_EXTENSIONS")
+ {
+ }
+
+ void Enabled(bool isEnabled) { this->IsEnabled = isEnabled; }
+
+ bool UpdateIfMatches(std::vector<std::string> const& argv, size_t& index)
+ {
+ bool updated = false;
+ if (argv[index] == this->StandardFlag) {
+ this->DidStandard = true;
+ this->StandardValue = argv[++index];
+ updated = true;
+ } else if (argv[index] == this->RequiredFlag) {
+ this->DidStandardRequired = true;
+ this->RequiredValue = argv[++index];
+ updated = true;
+ } else if (argv[index] == this->ExtensionFlag) {
+ this->DidExtensions = true;
+ this->ExtensionValue = argv[++index];
+ updated = true;
+ }
+ return updated;
+ }
+
+ bool Validate(cmMakefile* const makefile) const
+ {
+ if (this->DidStandard) {
+ makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(this->StandardFlag,
+ " allowed only in source file signature."));
+ return false;
+ }
+ if (this->DidStandardRequired) {
+ makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(this->RequiredFlag,
+ " allowed only in source file signature."));
+ return false;
+ }
+ if (this->DidExtensions) {
+ makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(this->ExtensionFlag,
+ " allowed only in source file signature."));
+ return false;
+ }
+
+ return true;
+ }
+
+ bool DidNone() const
+ {
+ return !this->DidStandard && !this->DidStandardRequired &&
+ !this->DidExtensions;
+ }
+
+ void LoadUnsetPropertyValues(cmMakefile* const makefile, bool honorStandard,
+ bool warnCMP0067,
+ std::vector<std::string>& warnCMP0067Variables)
+ {
+ if (!this->IsEnabled) {
+ return;
+ }
+
+ auto lookupStdVar = [&](std::string const& var) -> std::string {
+ std::string value = makefile->GetSafeDefinition(var);
+ if (warnCMP0067 && !value.empty()) {
+ value.clear();
+ warnCMP0067Variables.push_back(var);
+ }
+ return value;
+ };
+
+ if (honorStandard || warnCMP0067) {
+ if (!this->DidStandard) {
+ this->StandardValue =
+ lookupStdVar(cmStrCat("CMAKE_", this->StandardFlag));
+ }
+ if (!this->DidStandardRequired) {
+ this->RequiredValue =
+ lookupStdVar(cmStrCat("CMAKE_", this->RequiredFlag));
+ }
+ if (!this->DidExtensions) {
+ this->ExtensionValue =
+ lookupStdVar(cmStrCat("CMAKE_", this->ExtensionFlag));
+ }
+ }
+ }
+
+ void WriteProperties(FILE* fout, std::string const& targetName) const
+ {
+ if (!this->IsEnabled) {
+ return;
+ }
+
+ auto writeProp = [&](std::string const& prop, std::string const& value) {
+ fprintf(fout, "set_property(TARGET %s PROPERTY %s %s)\n",
+ targetName.c_str(),
+ cmOutputConverter::EscapeForCMake(prop).c_str(),
+ cmOutputConverter::EscapeForCMake(value).c_str());
+ };
+
+ if (!this->StandardValue.empty()) {
+ writeProp(this->StandardFlag, this->StandardValue);
+ }
+ if (!this->RequiredValue.empty()) {
+ writeProp(this->RequiredFlag, this->RequiredValue);
+ }
+ if (!this->ExtensionValue.empty()) {
+ writeProp(this->ExtensionFlag, this->ExtensionValue);
+ }
+ }
+
+private:
+ bool IsEnabled;
+ bool DidStandard;
+ bool DidStandardRequired;
+ bool DidExtensions;
+
+ std::string StandardFlag;
+ std::string RequiredFlag;
+ std::string ExtensionFlag;
+
+ std::string StandardValue;
+ std::string RequiredValue;
+ std::string ExtensionValue;
+};
+
+constexpr size_t lang_property_start = 0;
+constexpr size_t lang_property_size = 4;
+constexpr size_t pie_property_start = 4;
+constexpr size_t pie_property_size = 2;
+#define SETUP_LANGUAGE(name, lang) \
+ static const std::string name[lang_property_size + pie_property_size + 1] = \
+ { "CMAKE_" #lang "_COMPILER_EXTERNAL_TOOLCHAIN", \
+ "CMAKE_" #lang "_COMPILER_TARGET", \
+ "CMAKE_" #lang "_LINK_NO_PIE_SUPPORTED", \
+ "CMAKE_" #lang "_PIE_SUPPORTED", "" }
+
+// NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
+SETUP_LANGUAGE(c_properties, C);
+// NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
+SETUP_LANGUAGE(cxx_properties, CXX);
+
+// NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
+SETUP_LANGUAGE(cuda_properties, CUDA);
+// NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
+SETUP_LANGUAGE(fortran_properties, Fortran);
+// NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
+SETUP_LANGUAGE(objc_properties, OBJC);
+// NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
+SETUP_LANGUAGE(objcxx_properties, OBJCXX);
+// NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
+SETUP_LANGUAGE(ispc_properties, ISPC);
+// NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
+SETUP_LANGUAGE(swift_properties, Swift);
+#undef SETUP_LANGUAGE
+
+std::string const kCMAKE_CUDA_ARCHITECTURES = "CMAKE_CUDA_ARCHITECTURES";
+std::string const kCMAKE_CUDA_RUNTIME_LIBRARY = "CMAKE_CUDA_RUNTIME_LIBRARY";
+std::string const kCMAKE_ENABLE_EXPORTS = "CMAKE_ENABLE_EXPORTS";
+std::string const kCMAKE_ISPC_INSTRUCTION_SETS = "CMAKE_ISPC_INSTRUCTION_SETS";
+std::string const kCMAKE_ISPC_HEADER_SUFFIX = "CMAKE_ISPC_HEADER_SUFFIX";
+std::string const kCMAKE_LINK_SEARCH_END_STATIC =
+ "CMAKE_LINK_SEARCH_END_STATIC";
+std::string const kCMAKE_LINK_SEARCH_START_STATIC =
+ "CMAKE_LINK_SEARCH_START_STATIC";
+std::string const kCMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT =
+ "CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT";
+std::string const kCMAKE_OSX_ARCHITECTURES = "CMAKE_OSX_ARCHITECTURES";
+std::string const kCMAKE_OSX_DEPLOYMENT_TARGET = "CMAKE_OSX_DEPLOYMENT_TARGET";
+std::string const kCMAKE_OSX_SYSROOT = "CMAKE_OSX_SYSROOT";
+std::string const kCMAKE_APPLE_ARCH_SYSROOTS = "CMAKE_APPLE_ARCH_SYSROOTS";
+std::string const kCMAKE_POSITION_INDEPENDENT_CODE =
+ "CMAKE_POSITION_INDEPENDENT_CODE";
+std::string const kCMAKE_SYSROOT = "CMAKE_SYSROOT";
+std::string const kCMAKE_SYSROOT_COMPILE = "CMAKE_SYSROOT_COMPILE";
+std::string const kCMAKE_SYSROOT_LINK = "CMAKE_SYSROOT_LINK";
+std::string const kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES =
+ "CMAKE_TRY_COMPILE_OSX_ARCHITECTURES";
+std::string const kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES =
+ "CMAKE_TRY_COMPILE_PLATFORM_VARIABLES";
+std::string const kCMAKE_WARN_DEPRECATED = "CMAKE_WARN_DEPRECATED";
+
+/* GHS Multi platform variables */
+std::set<std::string> const ghs_platform_vars{
+ "GHS_TARGET_PLATFORM", "GHS_PRIMARY_TARGET", "GHS_TOOLSET_ROOT",
+ "GHS_OS_ROOT", "GHS_OS_DIR", "GHS_BSP_NAME",
+ "GHS_OS_DIR_OPTION"
+};
+}
+
+int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
+ bool isTryRun)
+{
+ this->BinaryDirectory = argv[1];
+ this->OutputFile.clear();
+ // which signature were we called with ?
+ this->SrcFileSignature = true;
+
+ cmStateEnums::TargetType targetType = cmStateEnums::EXECUTABLE;
+ cmProp tt = this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_TARGET_TYPE");
+ if (!isTryRun && cmNonempty(tt)) {
+ if (*tt == cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE)) {
+ targetType = cmStateEnums::EXECUTABLE;
+ } else if (*tt ==
+ cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY)) {
+ targetType = cmStateEnums::STATIC_LIBRARY;
+ } else {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Invalid value '", *tt,
+ "' for CMAKE_TRY_COMPILE_TARGET_TYPE. Only '",
+ cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE),
+ "' and '",
+ cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY),
+ "' are allowed."));
+ return -1;
+ }
+ }
+
+ std::string sourceDirectory = argv[2];
+ std::string projectName;
+ std::string targetName;
+ std::vector<std::string> cmakeFlags(1, "CMAKE_FLAGS"); // fake argv[0]
+ std::vector<std::string> compileDefs;
+ std::string cmakeInternal;
+ std::string outputVariable;
+ std::string copyFile;
+ std::string copyFileError;
+ LanguageStandardState cState("C");
+ LanguageStandardState cudaState("CUDA");
+ LanguageStandardState cxxState("CXX");
+ LanguageStandardState objcState("OBJC");
+ LanguageStandardState objcxxState("OBJCXX");
+ std::vector<std::string> targets;
+ std::vector<std::string> linkOptions;
+ std::string libsToLink = " ";
+ bool useOldLinkLibs = true;
+ char targetNameBuf[64];
+ bool didOutputVariable = false;
+ bool didCopyFile = false;
+ bool didCopyFileError = false;
+ bool useSources = argv[2] == "SOURCES";
+ std::vector<std::string> sources;
+
+ enum Doing
+ {
+ DoingNone,
+ DoingCMakeFlags,
+ DoingCompileDefinitions,
+ DoingLinkOptions,
+ DoingLinkLibraries,
+ DoingOutputVariable,
+ DoingCopyFile,
+ DoingCopyFileError,
+ DoingSources,
+ DoingCMakeInternal
+ };
+ Doing doing = useSources ? DoingSources : DoingNone;
+ for (size_t i = 3; i < argv.size(); ++i) {
+ if (argv[i] == "CMAKE_FLAGS") {
+ doing = DoingCMakeFlags;
+ } else if (argv[i] == "COMPILE_DEFINITIONS") {
+ doing = DoingCompileDefinitions;
+ } else if (argv[i] == "LINK_OPTIONS") {
+ doing = DoingLinkOptions;
+ } else if (argv[i] == "LINK_LIBRARIES") {
+ doing = DoingLinkLibraries;
+ useOldLinkLibs = false;
+ } else if (argv[i] == "OUTPUT_VARIABLE") {
+ doing = DoingOutputVariable;
+ didOutputVariable = true;
+ } else if (argv[i] == "COPY_FILE") {
+ doing = DoingCopyFile;
+ didCopyFile = true;
+ } else if (argv[i] == "COPY_FILE_ERROR") {
+ doing = DoingCopyFileError;
+ didCopyFileError = true;
+ } else if (cState.UpdateIfMatches(argv, i) ||
+ cxxState.UpdateIfMatches(argv, i) ||
+ cudaState.UpdateIfMatches(argv, i) ||
+ objcState.UpdateIfMatches(argv, i) ||
+ objcxxState.UpdateIfMatches(argv, i)) {
+ continue;
+ } else if (argv[i] == "__CMAKE_INTERNAL") {
+ doing = DoingCMakeInternal;
+ } else if (doing == DoingCMakeFlags) {
+ cmakeFlags.push_back(argv[i]);
+ } else if (doing == DoingCompileDefinitions) {
+ cmExpandList(argv[i], compileDefs);
+ } else if (doing == DoingLinkOptions) {
+ linkOptions.push_back(argv[i]);
+ } else if (doing == DoingLinkLibraries) {
+ libsToLink += "\"" + cmTrimWhitespace(argv[i]) + "\" ";
+ if (cmTarget* tgt = this->Makefile->FindTargetToUse(argv[i])) {
+ switch (tgt->GetType()) {
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ break;
+ case cmStateEnums::EXECUTABLE:
+ if (tgt->IsExecutableWithExports()) {
+ break;
+ }
+ CM_FALLTHROUGH;
+ default:
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Only libraries may be used as try_compile or try_run "
+ "IMPORTED LINK_LIBRARIES. Got ",
+ tgt->GetName(), " of type ",
+ cmState::GetTargetTypeName(tgt->GetType()), "."));
+ return -1;
+ }
+ if (tgt->IsImported()) {
+ targets.push_back(argv[i]);
+ }
+ }
+ } else if (doing == DoingOutputVariable) {
+ outputVariable = argv[i];
+ doing = DoingNone;
+ } else if (doing == DoingCopyFile) {
+ copyFile = argv[i];
+ doing = DoingNone;
+ } else if (doing == DoingCopyFileError) {
+ copyFileError = argv[i];
+ doing = DoingNone;
+ } else if (doing == DoingSources) {
+ sources.push_back(argv[i]);
+ } else if (doing == DoingCMakeInternal) {
+ cmakeInternal = argv[i];
+ doing = DoingNone;
+ } else if (i == 3) {
+ this->SrcFileSignature = false;
+ projectName = argv[i];
+ } else if (i == 4 && !this->SrcFileSignature) {
+ targetName = argv[i];
+ } else {
+ std::ostringstream m;
+ m << "try_compile given unknown argument \"" << argv[i] << "\".";
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, m.str());
+ }
+ }
+
+ if (didCopyFile && copyFile.empty()) {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ "COPY_FILE must be followed by a file path");
+ return -1;
+ }
+
+ if (didCopyFileError && copyFileError.empty()) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "COPY_FILE_ERROR must be followed by a variable name");
+ return -1;
+ }
+
+ if (didCopyFileError && !didCopyFile) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "COPY_FILE_ERROR may be used only with COPY_FILE");
+ return -1;
+ }
+
+ if (didOutputVariable && outputVariable.empty()) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "OUTPUT_VARIABLE must be followed by a variable name");
+ return -1;
+ }
+
+ if (useSources && sources.empty()) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "SOURCES must be followed by at least one source file");
+ return -1;
+ }
+
+ if (!this->SrcFileSignature) {
+ if (!cState.Validate(this->Makefile)) {
+ return -1;
+ }
+ if (!cudaState.Validate(this->Makefile)) {
+ return -1;
+ }
+ if (!cxxState.Validate(this->Makefile)) {
+ return -1;
+ }
+ if (!objcState.Validate(this->Makefile)) {
+ return -1;
+ }
+ if (!objcxxState.Validate(this->Makefile)) {
+ return -1;
+ }
+ }
+
+ // compute the binary dir when TRY_COMPILE is called with a src file
+ // signature
+ if (this->SrcFileSignature) {
+ this->BinaryDirectory += "/CMakeFiles/CMakeTmp";
+ } else {
+ // only valid for srcfile signatures
+ if (!compileDefs.empty()) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "COMPILE_DEFINITIONS specified on a srcdir type TRY_COMPILE");
+ return -1;
+ }
+ if (!copyFile.empty()) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "COPY_FILE specified on a srcdir type TRY_COMPILE");
+ return -1;
+ }
+ }
+ // make sure the binary directory exists
+ cmSystemTools::MakeDirectory(this->BinaryDirectory);
+
+ // do not allow recursive try Compiles
+ if (this->BinaryDirectory == this->Makefile->GetHomeOutputDirectory()) {
+ std::ostringstream e;
+ e << "Attempt at a recursive or nested TRY_COMPILE in directory\n"
+ << " " << this->BinaryDirectory << "\n";
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return -1;
+ }
+
+ std::string outFileName = this->BinaryDirectory + "/CMakeLists.txt";
+ // which signature are we using? If we are using var srcfile bindir
+ if (this->SrcFileSignature) {
+ // remove any CMakeCache.txt files so we will have a clean test
+ std::string ccFile = this->BinaryDirectory + "/CMakeCache.txt";
+ cmSystemTools::RemoveFile(ccFile);
+
+ // Choose sources.
+ if (!useSources) {
+ sources.push_back(argv[2]);
+ }
+
+ // Detect languages to enable.
+ cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+ std::set<std::string> testLangs;
+ for (std::string const& si : sources) {
+ std::string ext = cmSystemTools::GetFilenameLastExtension(si);
+ std::string lang = gg->GetLanguageFromExtension(ext.c_str());
+ if (!lang.empty()) {
+ testLangs.insert(lang);
+ } else {
+ std::ostringstream err;
+ err << "Unknown extension \"" << ext << "\" for file\n"
+ << " " << si << "\n"
+ << "try_compile() works only for enabled languages. "
+ << "Currently these are:\n ";
+ std::vector<std::string> langs;
+ gg->GetEnabledLanguages(langs);
+ err << cmJoin(langs, " ");
+ err << "\nSee project() command to enable other languages.";
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, err.str());
+ return -1;
+ }
+ }
+
+ // when the only language is ISPC we know that the output
+ // type must by a static library
+ if (testLangs.size() == 1 && testLangs.count("ISPC") == 1) {
+ targetType = cmStateEnums::STATIC_LIBRARY;
+ }
+
+ std::string const tcConfig =
+ this->Makefile->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
+
+ // we need to create a directory and CMakeLists file etc...
+ // first create the directories
+ sourceDirectory = this->BinaryDirectory;
+
+ // now create a CMakeLists.txt file in that directory
+ FILE* fout = cmsys::SystemTools::Fopen(outFileName, "w");
+ if (!fout) {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "Failed to open\n"
+ << " " << outFileName << "\n"
+ << cmSystemTools::GetLastSystemError();
+ /* clang-format on */
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return -1;
+ }
+
+ cmProp def = this->Makefile->GetDefinition("CMAKE_MODULE_PATH");
+ fprintf(fout, "cmake_minimum_required(VERSION %u.%u.%u.%u)\n",
+ cmVersion::GetMajorVersion(), cmVersion::GetMinorVersion(),
+ cmVersion::GetPatchVersion(), cmVersion::GetTweakVersion());
+ if (def) {
+ fprintf(fout, "set(CMAKE_MODULE_PATH \"%s\")\n", def->c_str());
+ }
+
+ /* Set MSVC runtime library policy to match our selection. */
+ if (cmProp msvcRuntimeLibraryDefault =
+ this->Makefile->GetDefinition(kCMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)) {
+ fprintf(fout, "cmake_policy(SET CMP0091 %s)\n",
+ !msvcRuntimeLibraryDefault->empty() ? "NEW" : "OLD");
+ }
+
+ /* Set CUDA architectures policy to match outer project. */
+ if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0104) !=
+ cmPolicies::NEW &&
+ testLangs.find("CUDA") != testLangs.end() &&
+ this->Makefile->GetSafeDefinition(kCMAKE_CUDA_ARCHITECTURES).empty()) {
+ fprintf(fout, "cmake_policy(SET CMP0104 OLD)\n");
+ }
+
+ std::string projectLangs;
+ for (std::string const& li : testLangs) {
+ projectLangs += " " + li;
+ std::string rulesOverrideBase = "CMAKE_USER_MAKE_RULES_OVERRIDE";
+ std::string rulesOverrideLang = cmStrCat(rulesOverrideBase, "_", li);
+ if (cmProp rulesOverridePath =
+ this->Makefile->GetDefinition(rulesOverrideLang)) {
+ fprintf(fout, "set(%s \"%s\")\n", rulesOverrideLang.c_str(),
+ rulesOverridePath->c_str());
+ } else if (cmProp rulesOverridePath2 =
+ this->Makefile->GetDefinition(rulesOverrideBase)) {
+ fprintf(fout, "set(%s \"%s\")\n", rulesOverrideBase.c_str(),
+ rulesOverridePath2->c_str());
+ }
+ }
+ fprintf(fout, "project(CMAKE_TRY_COMPILE%s)\n", projectLangs.c_str());
+ if (cmakeInternal == "ABI") {
+ // This is the ABI detection step, also used for implicit includes.
+ // Erase any include_directories() calls from the toolchain file so
+ // that we do not see them as implicit. Our ABI detection source
+ // does not include any system headers anyway.
+ fprintf(fout,
+ "set_property(DIRECTORY PROPERTY INCLUDE_DIRECTORIES \"\")\n");
+ }
+ fprintf(fout, "set(CMAKE_VERBOSE_MAKEFILE 1)\n");
+ for (std::string const& li : testLangs) {
+ std::string langFlags = "CMAKE_" + li + "_FLAGS";
+ cmProp flags = this->Makefile->GetDefinition(langFlags);
+ fprintf(fout, "set(CMAKE_%s_FLAGS %s)\n", li.c_str(),
+ cmOutputConverter::EscapeForCMake(cmToCStrSafe(flags)).c_str());
+ fprintf(fout,
+ "set(CMAKE_%s_FLAGS \"${CMAKE_%s_FLAGS}"
+ " ${COMPILE_DEFINITIONS}\")\n",
+ li.c_str(), li.c_str());
+ }
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0066)) {
+ case cmPolicies::WARN:
+ if (this->Makefile->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0066")) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0066) << "\n"
+ "For compatibility with older versions of CMake, try_compile "
+ "is not honoring caller config-specific compiler flags "
+ "(e.g. CMAKE_C_FLAGS_DEBUG) in the test project."
+ ;
+ /* clang-format on */
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+ case cmPolicies::OLD:
+ // OLD behavior is to do nothing.
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0066));
+ CM_FALLTHROUGH;
+ case cmPolicies::NEW: {
+ // NEW behavior is to pass config-specific compiler flags.
+ static std::string const cfgDefault = "DEBUG";
+ std::string const cfg =
+ !tcConfig.empty() ? cmSystemTools::UpperCase(tcConfig) : cfgDefault;
+ for (std::string const& li : testLangs) {
+ std::string const langFlagsCfg =
+ cmStrCat("CMAKE_", li, "_FLAGS_", cfg);
+ cmProp flagsCfg = this->Makefile->GetDefinition(langFlagsCfg);
+ fprintf(
+ fout, "set(%s %s)\n", langFlagsCfg.c_str(),
+ cmOutputConverter::EscapeForCMake(cmToCStrSafe(flagsCfg)).c_str());
+ }
+ } break;
+ }
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0056)) {
+ case cmPolicies::WARN:
+ if (this->Makefile->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0056")) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0056) << "\n"
+ "For compatibility with older versions of CMake, try_compile "
+ "is not honoring caller link flags (e.g. CMAKE_EXE_LINKER_FLAGS) "
+ "in the test project."
+ ;
+ /* clang-format on */
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+ case cmPolicies::OLD:
+ // OLD behavior is to do nothing.
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0056));
+ CM_FALLTHROUGH;
+ case cmPolicies::NEW:
+ // NEW behavior is to pass linker flags.
+ {
+ cmProp exeLinkFlags =
+ this->Makefile->GetDefinition("CMAKE_EXE_LINKER_FLAGS");
+ fprintf(fout, "set(CMAKE_EXE_LINKER_FLAGS %s)\n",
+ cmOutputConverter::EscapeForCMake(cmToCStrSafe(exeLinkFlags))
+ .c_str());
+ }
+ break;
+ }
+ fprintf(fout,
+ "set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS}"
+ " ${EXE_LINKER_FLAGS}\")\n");
+ fprintf(fout, "include_directories(${INCLUDE_DIRECTORIES})\n");
+ fprintf(fout, "set(CMAKE_SUPPRESS_REGENERATION 1)\n");
+ fprintf(fout, "link_directories(${LINK_DIRECTORIES})\n");
+ // handle any compile flags we need to pass on
+ if (!compileDefs.empty()) {
+ // Pass using bracket arguments to preserve content.
+ fprintf(fout, "add_definitions([==[%s]==])\n",
+ cmJoin(compileDefs, "]==] [==[").c_str());
+ }
+
+ /* Use a random file name to avoid rapid creation and deletion
+ of the same executable name (some filesystems fail on that). */
+ sprintf(targetNameBuf, "cmTC_%05x", cmSystemTools::RandomSeed() & 0xFFFFF);
+ targetName = targetNameBuf;
+
+ if (!targets.empty()) {
+ std::string fname = "/" + std::string(targetName) + "Targets.cmake";
+ cmExportTryCompileFileGenerator tcfg(gg, targets, this->Makefile,
+ testLangs);
+ tcfg.SetExportFile((this->BinaryDirectory + fname).c_str());
+ tcfg.SetConfig(tcConfig);
+
+ if (!tcfg.GenerateImportFile()) {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ "could not write export file.");
+ fclose(fout);
+ return -1;
+ }
+ fprintf(fout, "\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/%s\")\n\n",
+ fname.c_str());
+ }
+
+ // Forward a set of variables to the inner project cache.
+ {
+ std::set<std::string> vars;
+ vars.insert(&c_properties[lang_property_start],
+ &c_properties[lang_property_start + lang_property_size]);
+ vars.insert(&cxx_properties[lang_property_start],
+ &cxx_properties[lang_property_start + lang_property_size]);
+ vars.insert(&cuda_properties[lang_property_start],
+ &cuda_properties[lang_property_start + lang_property_size]);
+ vars.insert(
+ &fortran_properties[lang_property_start],
+ &fortran_properties[lang_property_start + lang_property_size]);
+ vars.insert(&objc_properties[lang_property_start],
+ &objc_properties[lang_property_start + lang_property_size]);
+ vars.insert(
+ &objcxx_properties[lang_property_start],
+ &objcxx_properties[lang_property_start + lang_property_size]);
+ vars.insert(&ispc_properties[lang_property_start],
+ &ispc_properties[lang_property_start + lang_property_size]);
+ vars.insert(&swift_properties[lang_property_start],
+ &swift_properties[lang_property_start + lang_property_size]);
+ vars.insert(kCMAKE_CUDA_ARCHITECTURES);
+ vars.insert(kCMAKE_CUDA_RUNTIME_LIBRARY);
+ vars.insert(kCMAKE_ENABLE_EXPORTS);
+ vars.insert(kCMAKE_ISPC_INSTRUCTION_SETS);
+ vars.insert(kCMAKE_ISPC_HEADER_SUFFIX);
+ vars.insert(kCMAKE_LINK_SEARCH_END_STATIC);
+ vars.insert(kCMAKE_LINK_SEARCH_START_STATIC);
+ vars.insert(kCMAKE_OSX_ARCHITECTURES);
+ vars.insert(kCMAKE_OSX_DEPLOYMENT_TARGET);
+ vars.insert(kCMAKE_OSX_SYSROOT);
+ vars.insert(kCMAKE_APPLE_ARCH_SYSROOTS);
+ vars.insert(kCMAKE_POSITION_INDEPENDENT_CODE);
+ vars.insert(kCMAKE_SYSROOT);
+ vars.insert(kCMAKE_SYSROOT_COMPILE);
+ vars.insert(kCMAKE_SYSROOT_LINK);
+ vars.insert(kCMAKE_WARN_DEPRECATED);
+ vars.emplace("CMAKE_MSVC_RUNTIME_LIBRARY"_s);
+
+ if (cmProp varListStr = this->Makefile->GetDefinition(
+ kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) {
+ std::vector<std::string> varList = cmExpandedList(*varListStr);
+ vars.insert(varList.begin(), varList.end());
+ }
+
+ if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0083) ==
+ cmPolicies::NEW) {
+ // To ensure full support of PIE, propagate cache variables
+ // driving the link options
+ vars.insert(&c_properties[pie_property_start],
+ &c_properties[pie_property_start + pie_property_size]);
+ vars.insert(&cxx_properties[pie_property_start],
+ &cxx_properties[pie_property_start + pie_property_size]);
+ vars.insert(&cuda_properties[pie_property_start],
+ &cuda_properties[pie_property_start + pie_property_size]);
+ vars.insert(
+ &fortran_properties[pie_property_start],
+ &fortran_properties[pie_property_start + pie_property_size]);
+ vars.insert(&objc_properties[pie_property_start],
+ &objc_properties[pie_property_start + pie_property_size]);
+ vars.insert(
+ &objcxx_properties[pie_property_start],
+ &objcxx_properties[pie_property_start + pie_property_size]);
+ vars.insert(&ispc_properties[pie_property_start],
+ &ispc_properties[pie_property_start + pie_property_size]);
+ vars.insert(&swift_properties[pie_property_start],
+ &swift_properties[pie_property_start + pie_property_size]);
+ }
+
+ /* for the TRY_COMPILEs we want to be able to specify the architecture.
+ So the user can set CMAKE_OSX_ARCHITECTURES to i386;ppc and then set
+ CMAKE_TRY_COMPILE_OSX_ARCHITECTURES first to i386 and then to ppc to
+ have the tests run for each specific architecture. Since
+ cmLocalGenerator doesn't allow building for "the other"
+ architecture only via CMAKE_OSX_ARCHITECTURES.
+ */
+ if (cmProp tcArchs = this->Makefile->GetDefinition(
+ kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES)) {
+ vars.erase(kCMAKE_OSX_ARCHITECTURES);
+ std::string flag = "-DCMAKE_OSX_ARCHITECTURES=" + *tcArchs;
+ cmakeFlags.push_back(std::move(flag));
+ }
+
+ for (std::string const& var : vars) {
+ if (cmProp val = this->Makefile->GetDefinition(var)) {
+ std::string flag = "-D" + var + "=" + *val;
+ cmakeFlags.push_back(std::move(flag));
+ }
+ }
+ }
+
+ /* Set the appropriate policy information for ENABLE_EXPORTS */
+ fprintf(fout, "cmake_policy(SET CMP0065 %s)\n",
+ this->Makefile->GetPolicyStatus(cmPolicies::CMP0065) ==
+ cmPolicies::NEW
+ ? "NEW"
+ : "OLD");
+
+ /* Set the appropriate policy information for PIE link flags */
+ fprintf(fout, "cmake_policy(SET CMP0083 %s)\n",
+ this->Makefile->GetPolicyStatus(cmPolicies::CMP0083) ==
+ cmPolicies::NEW
+ ? "NEW"
+ : "OLD");
+
+ if (targetType == cmStateEnums::EXECUTABLE) {
+ /* Put the executable at a known location (for COPY_FILE). */
+ fprintf(fout, "set(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"%s\")\n",
+ this->BinaryDirectory.c_str());
+ /* Create the actual executable. */
+ fprintf(fout, "add_executable(%s", targetName.c_str());
+ } else // if (targetType == cmStateEnums::STATIC_LIBRARY)
+ {
+ /* Put the static library at a known location (for COPY_FILE). */
+ fprintf(fout, "set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY \"%s\")\n",
+ this->BinaryDirectory.c_str());
+ /* Create the actual static library. */
+ fprintf(fout, "add_library(%s STATIC", targetName.c_str());
+ }
+ for (std::string const& si : sources) {
+ fprintf(fout, " \"%s\"", si.c_str());
+
+ // Add dependencies on any non-temporary sources.
+ if (si.find("CMakeTmp") == std::string::npos) {
+ this->Makefile->AddCMakeDependFile(si);
+ }
+ }
+ fprintf(fout, ")\n");
+
+ cState.Enabled(testLangs.find("C") != testLangs.end());
+ cxxState.Enabled(testLangs.find("CXX") != testLangs.end());
+ cudaState.Enabled(testLangs.find("CUDA") != testLangs.end());
+ objcState.Enabled(testLangs.find("OBJC") != testLangs.end());
+ objcxxState.Enabled(testLangs.find("OBJCXX") != testLangs.end());
+
+ bool warnCMP0067 = false;
+ bool honorStandard = true;
+
+ if (cState.DidNone() && cxxState.DidNone() && objcState.DidNone() &&
+ objcxxState.DidNone() && cudaState.DidNone()) {
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0067)) {
+ case cmPolicies::WARN:
+ warnCMP0067 = this->Makefile->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0067");
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior is to not honor the language standard variables.
+ honorStandard = false;
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0067));
+ case cmPolicies::NEW:
+ // NEW behavior is to honor the language standard variables.
+ // We already initialized honorStandard to true.
+ break;
+ }
+ }
+
+ std::vector<std::string> warnCMP0067Variables;
+
+ cState.LoadUnsetPropertyValues(this->Makefile, honorStandard, warnCMP0067,
+ warnCMP0067Variables);
+ cxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
+ warnCMP0067, warnCMP0067Variables);
+ cudaState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
+ warnCMP0067, warnCMP0067Variables);
+ objcState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
+ warnCMP0067, warnCMP0067Variables);
+ objcxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
+ warnCMP0067, warnCMP0067Variables);
+
+ if (!warnCMP0067Variables.empty()) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0067) << "\n"
+ "For compatibility with older versions of CMake, try_compile "
+ "is not honoring language standard variables in the test project:\n"
+ ;
+ /* clang-format on */
+ for (std::string const& vi : warnCMP0067Variables) {
+ w << " " << vi << "\n";
+ }
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+
+ cState.WriteProperties(fout, targetName);
+ cxxState.WriteProperties(fout, targetName);
+ cudaState.WriteProperties(fout, targetName);
+ objcState.WriteProperties(fout, targetName);
+ objcxxState.WriteProperties(fout, targetName);
+
+ if (!linkOptions.empty()) {
+ std::vector<std::string> options;
+ options.reserve(linkOptions.size());
+ for (const auto& option : linkOptions) {
+ options.emplace_back(cmOutputConverter::EscapeForCMake(option));
+ }
+
+ if (targetType == cmStateEnums::STATIC_LIBRARY) {
+ fprintf(fout,
+ "set_property(TARGET %s PROPERTY STATIC_LIBRARY_OPTIONS %s)\n",
+ targetName.c_str(), cmJoin(options, " ").c_str());
+ } else {
+ fprintf(fout, "target_link_options(%s PRIVATE %s)\n",
+ targetName.c_str(), cmJoin(options, " ").c_str());
+ }
+ }
+
+ if (useOldLinkLibs) {
+ fprintf(fout, "target_link_libraries(%s ${LINK_LIBRARIES})\n",
+ targetName.c_str());
+ } else {
+ fprintf(fout, "target_link_libraries(%s %s)\n", targetName.c_str(),
+ libsToLink.c_str());
+ }
+ fclose(fout);
+ projectName = "CMAKE_TRY_COMPILE";
+ }
+
+ if (this->Makefile->GetState()->UseGhsMultiIDE()) {
+ // Forward the GHS variables to the inner project cache.
+ for (std::string const& var : ghs_platform_vars) {
+ if (cmProp val = this->Makefile->GetDefinition(var)) {
+ std::string flag = "-D" + var + "=" + "'" + *val + "'";
+ cmakeFlags.push_back(std::move(flag));
+ }
+ }
+ }
+
+ bool erroroc = cmSystemTools::GetErrorOccuredFlag();
+ cmSystemTools::ResetErrorOccuredFlag();
+ std::string output;
+ // actually do the try compile now that everything is setup
+ int res = this->Makefile->TryCompile(
+ sourceDirectory, this->BinaryDirectory, projectName, targetName,
+ this->SrcFileSignature, cmake::NO_BUILD_PARALLEL_LEVEL, &cmakeFlags,
+ output);
+ if (erroroc) {
+ cmSystemTools::SetErrorOccured();
+ }
+
+ // set the result var to the return value to indicate success or failure
+ this->Makefile->AddCacheDefinition(argv[0], (res == 0 ? "TRUE" : "FALSE"),
+ "Result of TRY_COMPILE",
+ cmStateEnums::INTERNAL);
+
+ if (!outputVariable.empty()) {
+ this->Makefile->AddDefinition(outputVariable, output);
+ }
+
+ if (this->SrcFileSignature) {
+ std::string copyFileErrorMessage;
+ this->FindOutputFile(targetName, targetType);
+
+ if ((res == 0) && !copyFile.empty()) {
+ if (this->OutputFile.empty() ||
+ !cmSystemTools::CopyFileAlways(this->OutputFile, copyFile)) {
+ std::ostringstream emsg;
+ /* clang-format off */
+ emsg << "Cannot copy output executable\n"
+ << " '" << this->OutputFile << "'\n"
+ << "to destination specified by COPY_FILE:\n"
+ << " '" << copyFile << "'\n";
+ /* clang-format on */
+ if (!this->FindErrorMessage.empty()) {
+ emsg << this->FindErrorMessage;
+ }
+ if (copyFileError.empty()) {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, emsg.str());
+ return -1;
+ }
+ copyFileErrorMessage = emsg.str();
+ }
+ }
+
+ if (!copyFileError.empty()) {
+ this->Makefile->AddDefinition(copyFileError, copyFileErrorMessage);
+ }
+ }
+ return res;
+}
+
+void cmCoreTryCompile::CleanupFiles(std::string const& binDir)
+{
+ if (binDir.empty()) {
+ return;
+ }
+
+ if (binDir.find("CMakeTmp") == std::string::npos) {
+ cmSystemTools::Error(
+ "TRY_COMPILE attempt to remove -rf directory that does not contain "
+ "CMakeTmp:" +
+ binDir);
+ return;
+ }
+
+ cmsys::Directory dir;
+ dir.Load(binDir);
+ std::set<std::string> deletedFiles;
+ for (unsigned long i = 0; i < dir.GetNumberOfFiles(); ++i) {
+ const char* fileName = dir.GetFile(i);
+ if (strcmp(fileName, ".") != 0 && strcmp(fileName, "..") != 0 &&
+ // Do not delete NFS temporary files.
+ !cmHasPrefix(fileName, ".nfs")) {
+ if (deletedFiles.insert(fileName).second) {
+ std::string const fullPath =
+ std::string(binDir).append("/").append(fileName);
+ if (cmSystemTools::FileIsSymlink(fullPath)) {
+ cmSystemTools::RemoveFile(fullPath);
+ } else if (cmSystemTools::FileIsDirectory(fullPath)) {
+ this->CleanupFiles(fullPath);
+ cmSystemTools::RemoveADirectory(fullPath);
+ } else {
+#ifdef _WIN32
+ // Sometimes anti-virus software hangs on to new files so we
+ // cannot delete them immediately. Try a few times.
+ cmSystemTools::WindowsFileRetry retry =
+ cmSystemTools::GetWindowsFileRetry();
+ while (!cmSystemTools::RemoveFile(fullPath) && --retry.Count &&
+ cmSystemTools::FileExists(fullPath)) {
+ cmSystemTools::Delay(retry.Delay);
+ }
+ if (retry.Count == 0)
+#else
+ if (!cmSystemTools::RemoveFile(fullPath))
+#endif
+ {
+ std::string m = "Remove failed on file: " + fullPath;
+ cmSystemTools::ReportLastSystemError(m.c_str());
+ }
+ }
+ }
+ }
+ }
+}
+
+void cmCoreTryCompile::FindOutputFile(const std::string& targetName,
+ cmStateEnums::TargetType targetType)
+{
+ this->FindErrorMessage.clear();
+ this->OutputFile.clear();
+ std::string tmpOutputFile = "/";
+ if (targetType == cmStateEnums::EXECUTABLE) {
+ tmpOutputFile += targetName;
+ tmpOutputFile +=
+ this->Makefile->GetSafeDefinition("CMAKE_EXECUTABLE_SUFFIX");
+ } else // if (targetType == cmStateEnums::STATIC_LIBRARY)
+ {
+ tmpOutputFile +=
+ this->Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX");
+ tmpOutputFile += targetName;
+ tmpOutputFile +=
+ this->Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX");
+ }
+
+ // a list of directories where to search for the compilation result
+ // at first directly in the binary dir
+ std::vector<std::string> searchDirs;
+ searchDirs.emplace_back();
+
+ cmProp config =
+ this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
+ // if a config was specified try that first
+ if (cmNonempty(config)) {
+ std::string tmp = cmStrCat('/', *config);
+ searchDirs.push_back(std::move(tmp));
+ }
+ searchDirs.emplace_back("/Debug");
+#if defined(__APPLE__)
+ std::string app = "/" + targetName + ".app";
+ if (cmNonempty(config)) {
+ std::string tmp = cmStrCat('/', *config, app);
+ searchDirs.push_back(std::move(tmp));
+ }
+ std::string tmp = "/Debug" + app;
+ searchDirs.emplace_back(std::move(tmp));
+ searchDirs.push_back(std::move(app));
+#endif
+ searchDirs.emplace_back("/Development");
+
+ for (std::string const& sdir : searchDirs) {
+ std::string command = cmStrCat(this->BinaryDirectory, sdir, tmpOutputFile);
+ if (cmSystemTools::FileExists(command)) {
+ this->OutputFile = cmSystemTools::CollapseFullPath(command);
+ return;
+ }
+ }
+
+ std::ostringstream emsg;
+ emsg << "Unable to find the executable at any of:\n";
+ emsg << cmWrap(" " + this->BinaryDirectory, searchDirs, tmpOutputFile, "\n")
+ << "\n";
+ this->FindErrorMessage = emsg.str();
+}
diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h
new file mode 100644
index 0000000..594fd7f
--- /dev/null
+++ b/Source/cmCoreTryCompile.h
@@ -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. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+#include "cmCommand.h"
+#include "cmStateTypes.h"
+
+/** \class cmCoreTryCompile
+ * \brief Base class for cmTryCompileCommand and cmTryRunCommand
+ *
+ * cmCoreTryCompile implements the functionality to build a program.
+ * It is the base class for cmTryCompileCommand and cmTryRunCommand.
+ */
+class cmCoreTryCompile : public cmCommand
+{
+public:
+protected:
+ /**
+ * This is the core code for try compile. It is here so that other
+ * commands, such as TryRun can access the same logic without
+ * duplication.
+ */
+ int TryCompileCode(std::vector<std::string> const& argv, bool isTryRun);
+
+ /**
+ * This deletes all the files created by TryCompileCode.
+ * This way we do not have to rely on the timing and
+ * dependencies of makefiles.
+ */
+ void CleanupFiles(std::string const& binDir);
+
+ /**
+ * This tries to find the (executable) file created by
+ TryCompileCode. The result is stored in OutputFile. If nothing is found,
+ the error message is stored in FindErrorMessage.
+ */
+ void FindOutputFile(const std::string& targetName,
+ cmStateEnums::TargetType targetType);
+
+ std::string BinaryDirectory;
+ std::string OutputFile;
+ std::string FindErrorMessage;
+ bool SrcFileSignature = false;
+};
diff --git a/Source/cmCreateTestSourceList.cxx b/Source/cmCreateTestSourceList.cxx
new file mode 100644
index 0000000..a2fac73
--- /dev/null
+++ b/Source/cmCreateTestSourceList.cxx
@@ -0,0 +1,155 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCreateTestSourceList.h"
+
+#include <algorithm>
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+bool cmCreateTestSourceList(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("called with wrong number of arguments.");
+ return false;
+ }
+
+ auto i = args.begin();
+ std::string extraInclude;
+ std::string function;
+ std::vector<std::string> tests;
+ // extract extra include and function ot
+ for (; i != args.end(); i++) {
+ if (*i == "EXTRA_INCLUDE") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("incorrect arguments to EXTRA_INCLUDE");
+ return false;
+ }
+ extraInclude = cmStrCat("#include \"", *i, "\"\n");
+ } else if (*i == "FUNCTION") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("incorrect arguments to FUNCTION");
+ return false;
+ }
+ function = cmStrCat(*i, "(&ac, &av);\n");
+ } else {
+ tests.push_back(*i);
+ }
+ }
+ i = tests.begin();
+
+ // Name of the source list
+
+ const char* sourceList = i->c_str();
+ ++i;
+
+ // Name of the test driver
+ // make sure they specified an extension
+ if (cmSystemTools::GetFilenameExtension(*i).size() < 2) {
+ status.SetError(
+ "You must specify a file extension for the test driver file.");
+ return false;
+ }
+ cmMakefile& mf = status.GetMakefile();
+ std::string driver = cmStrCat(mf.GetCurrentBinaryDirectory(), '/', *i);
+ ++i;
+
+ std::string configFile = cmSystemTools::GetCMakeRoot();
+
+ configFile += "/Templates/TestDriver.cxx.in";
+ // Create the test driver file
+
+ auto testsBegin = i;
+ std::vector<std::string> tests_func_name;
+
+ // The rest of the arguments consist of a list of test source files.
+ // Sadly, they can be in directories. Let's find a unique function
+ // name for the corresponding test, and push it to the tests_func_name
+ // list.
+ // For the moment:
+ // - replace spaces ' ', ':' and '/' with underscores '_'
+ std::string forwardDeclareCode;
+ for (i = testsBegin; i != tests.end(); ++i) {
+ if (*i == "EXTRA_INCLUDE") {
+ break;
+ }
+ std::string func_name;
+ if (!cmSystemTools::GetFilenamePath(*i).empty()) {
+ func_name = cmSystemTools::GetFilenamePath(*i) + "/" +
+ cmSystemTools::GetFilenameWithoutLastExtension(*i);
+ } else {
+ func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
+ }
+ cmSystemTools::ConvertToUnixSlashes(func_name);
+ std::replace(func_name.begin(), func_name.end(), ' ', '_');
+ std::replace(func_name.begin(), func_name.end(), '/', '_');
+ std::replace(func_name.begin(), func_name.end(), ':', '_');
+ bool already_declared =
+ std::find(tests_func_name.begin(), tests_func_name.end(), func_name) !=
+ tests_func_name.end();
+ tests_func_name.push_back(func_name);
+ if (!already_declared) {
+ forwardDeclareCode += "int ";
+ forwardDeclareCode += func_name;
+ forwardDeclareCode += "(int, char*[]);\n";
+ }
+ }
+
+ std::string functionMapCode;
+ int numTests = 0;
+ std::vector<std::string>::iterator j;
+ for (i = testsBegin, j = tests_func_name.begin(); i != tests.end();
+ ++i, ++j) {
+ std::string func_name;
+ if (!cmSystemTools::GetFilenamePath(*i).empty()) {
+ func_name = cmSystemTools::GetFilenamePath(*i) + "/" +
+ cmSystemTools::GetFilenameWithoutLastExtension(*i);
+ } else {
+ func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
+ }
+ functionMapCode += " {\n"
+ " \"";
+ functionMapCode += func_name;
+ functionMapCode += "\",\n"
+ " ";
+ functionMapCode += *j;
+ functionMapCode += "\n"
+ " },\n";
+ numTests++;
+ }
+ if (!extraInclude.empty()) {
+ mf.AddDefinition("CMAKE_TESTDRIVER_EXTRA_INCLUDES", extraInclude);
+ }
+ if (!function.empty()) {
+ mf.AddDefinition("CMAKE_TESTDRIVER_ARGVC_FUNCTION", function);
+ }
+ mf.AddDefinition("CMAKE_FORWARD_DECLARE_TESTS", forwardDeclareCode);
+ mf.AddDefinition("CMAKE_FUNCTION_TABLE_ENTRIES", functionMapCode);
+ bool res = true;
+ if (!mf.ConfigureFile(configFile, driver, false, true, false)) {
+ res = false;
+ }
+
+ // Construct the source list.
+ std::string sourceListValue;
+ {
+ cmSourceFile* sf = mf.GetOrCreateSource(driver);
+ sf->SetProperty("ABSTRACT", "0");
+ sourceListValue = args[1];
+ }
+ for (i = testsBegin; i != tests.end(); ++i) {
+ cmSourceFile* sf = mf.GetOrCreateSource(*i);
+ sf->SetProperty("ABSTRACT", "0");
+ sourceListValue += ";";
+ sourceListValue += *i;
+ }
+
+ mf.AddDefinition(sourceList, sourceListValue);
+ return res;
+}
diff --git a/Source/cmCreateTestSourceList.h b/Source/cmCreateTestSourceList.h
new file mode 100644
index 0000000..a7f11a6
--- /dev/null
+++ b/Source/cmCreateTestSourceList.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmCreateTestSourceList(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx
new file mode 100644
index 0000000..b331862
--- /dev/null
+++ b/Source/cmCryptoHash.cxx
@@ -0,0 +1,192 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCryptoHash.h"
+
+#include <cm/memory>
+
+#include <cm3p/kwiml/int.h>
+#include <cm3p/rhash.h>
+
+#include "cmsys/FStream.hxx"
+
+static unsigned int const cmCryptoHashAlgoToId[] = {
+ /* clang-format needs this comment to break after the opening brace */
+ RHASH_MD5, //
+ RHASH_SHA1, //
+ RHASH_SHA224, //
+ RHASH_SHA256, //
+ RHASH_SHA384, //
+ RHASH_SHA512, //
+ RHASH_SHA3_224, //
+ RHASH_SHA3_256, //
+ RHASH_SHA3_384, //
+ RHASH_SHA3_512
+};
+
+static int cmCryptoHash_rhash_library_initialized;
+
+static rhash cmCryptoHash_rhash_init(unsigned int id)
+{
+ if (!cmCryptoHash_rhash_library_initialized) {
+ cmCryptoHash_rhash_library_initialized = 1;
+ rhash_library_init();
+ }
+ return rhash_init(id);
+}
+
+cmCryptoHash::cmCryptoHash(Algo algo)
+ : Id(cmCryptoHashAlgoToId[algo])
+ , CTX(cmCryptoHash_rhash_init(this->Id))
+{
+}
+
+cmCryptoHash::~cmCryptoHash()
+{
+ rhash_free(this->CTX);
+}
+
+std::unique_ptr<cmCryptoHash> cmCryptoHash::New(cm::string_view algo)
+{
+ if (algo == "MD5") {
+ return cm::make_unique<cmCryptoHash>(AlgoMD5);
+ }
+ if (algo == "SHA1") {
+ return cm::make_unique<cmCryptoHash>(AlgoSHA1);
+ }
+ if (algo == "SHA224") {
+ return cm::make_unique<cmCryptoHash>(AlgoSHA224);
+ }
+ if (algo == "SHA256") {
+ return cm::make_unique<cmCryptoHash>(AlgoSHA256);
+ }
+ if (algo == "SHA384") {
+ return cm::make_unique<cmCryptoHash>(AlgoSHA384);
+ }
+ if (algo == "SHA512") {
+ return cm::make_unique<cmCryptoHash>(AlgoSHA512);
+ }
+ if (algo == "SHA3_224") {
+ return cm::make_unique<cmCryptoHash>(AlgoSHA3_224);
+ }
+ if (algo == "SHA3_256") {
+ return cm::make_unique<cmCryptoHash>(AlgoSHA3_256);
+ }
+ if (algo == "SHA3_384") {
+ return cm::make_unique<cmCryptoHash>(AlgoSHA3_384);
+ }
+ if (algo == "SHA3_512") {
+ return cm::make_unique<cmCryptoHash>(AlgoSHA3_512);
+ }
+ return std::unique_ptr<cmCryptoHash>(nullptr);
+}
+
+bool cmCryptoHash::IntFromHexDigit(char input, char& output)
+{
+ if (input >= '0' && input <= '9') {
+ output = char(input - '0');
+ return true;
+ }
+ if (input >= 'a' && input <= 'f') {
+ output = char(input - 'a' + 0xA);
+ return true;
+ }
+ if (input >= 'A' && input <= 'F') {
+ output = char(input - 'A' + 0xA);
+ return true;
+ }
+ return false;
+}
+
+std::string cmCryptoHash::ByteHashToString(
+ const std::vector<unsigned char>& hash)
+{
+ // Map from 4-bit index to hexadecimal representation.
+ static char const hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ std::string res;
+ res.reserve(hash.size() * 2);
+ for (unsigned char v : hash) {
+ res.push_back(hex[v >> 4]);
+ res.push_back(hex[v & 0xF]);
+ }
+ return res;
+}
+
+std::vector<unsigned char> cmCryptoHash::ByteHashString(cm::string_view input)
+{
+ this->Initialize();
+ this->Append(input);
+ return this->Finalize();
+}
+
+std::vector<unsigned char> cmCryptoHash::ByteHashFile(const std::string& file)
+{
+ cmsys::ifstream fin(file.c_str(), std::ios::in | std::ios::binary);
+ if (fin) {
+ this->Initialize();
+ {
+ // Should be efficient enough on most system:
+ KWIML_INT_uint64_t buffer[512];
+ char* buffer_c = reinterpret_cast<char*>(buffer);
+ unsigned char const* buffer_uc =
+ reinterpret_cast<unsigned char const*>(buffer);
+ // This copy loop is very sensitive on certain platforms with
+ // slightly broken stream libraries (like HPUX). Normally, it is
+ // incorrect to not check the error condition on the fin.read()
+ // before using the data, but the fin.gcount() will be zero if an
+ // error occurred. Therefore, the loop should be safe everywhere.
+ while (fin) {
+ fin.read(buffer_c, sizeof(buffer));
+ if (int gcount = static_cast<int>(fin.gcount())) {
+ this->Append(buffer_uc, gcount);
+ }
+ }
+ }
+ if (fin.eof()) {
+ // Success
+ return this->Finalize();
+ }
+ // Finalize anyway
+ this->Finalize();
+ }
+ // Return without success
+ return std::vector<unsigned char>();
+}
+
+std::string cmCryptoHash::HashString(cm::string_view input)
+{
+ return ByteHashToString(this->ByteHashString(input));
+}
+
+std::string cmCryptoHash::HashFile(const std::string& file)
+{
+ return ByteHashToString(this->ByteHashFile(file));
+}
+
+void cmCryptoHash::Initialize()
+{
+ rhash_reset(this->CTX);
+}
+
+void cmCryptoHash::Append(void const* buf, size_t sz)
+{
+ rhash_update(this->CTX, buf, sz);
+}
+
+void cmCryptoHash::Append(cm::string_view input)
+{
+ rhash_update(this->CTX, input.data(), input.size());
+}
+
+std::vector<unsigned char> cmCryptoHash::Finalize()
+{
+ std::vector<unsigned char> hash(rhash_get_digest_size(this->Id), 0);
+ rhash_final(this->CTX, &hash[0]);
+ return hash;
+}
+
+std::string cmCryptoHash::FinalizeHex()
+{
+ return cmCryptoHash::ByteHashToString(this->Finalize());
+}
diff --git a/Source/cmCryptoHash.h b/Source/cmCryptoHash.h
new file mode 100644
index 0000000..a2d45e7
--- /dev/null
+++ b/Source/cmCryptoHash.h
@@ -0,0 +1,86 @@
+/* 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 <cstddef>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm/string_view>
+
+/**
+ * @brief Abstract base class for cryptographic hash generators
+ */
+class cmCryptoHash
+{
+public:
+ enum Algo
+ {
+ AlgoMD5,
+ AlgoSHA1,
+ AlgoSHA224,
+ AlgoSHA256,
+ AlgoSHA384,
+ AlgoSHA512,
+ AlgoSHA3_224,
+ AlgoSHA3_256,
+ AlgoSHA3_384,
+ AlgoSHA3_512
+ };
+
+ cmCryptoHash(Algo algo);
+ ~cmCryptoHash();
+
+ cmCryptoHash(cmCryptoHash const&) = delete;
+ cmCryptoHash& operator=(cmCryptoHash const&) = delete;
+
+ /// @brief Returns a new hash generator of the requested type
+ /// @arg algo Hash type name. Supported hash types are
+ /// MD5, SHA1, SHA224, SHA256, SHA384, SHA512,
+ /// SHA3_224, SHA3_256, SHA3_384, SHA3_512
+ /// @return A valid auto pointer if algo is supported or
+ /// an invalid/NULL pointer otherwise
+ static std::unique_ptr<cmCryptoHash> New(cm::string_view algo);
+
+ /// @brief Converts a hex character to its binary value (4 bits)
+ /// @arg input Hex character [0-9a-fA-F].
+ /// @arg output Binary value of the input character (4 bits)
+ /// @return True if input was a valid hex character
+ static bool IntFromHexDigit(char input, char& output);
+
+ /// @brief Converts a byte hash to a sequence of hex character pairs
+ static std::string ByteHashToString(const std::vector<unsigned char>& hash);
+
+ /// @brief Calculates a binary hash from string input data
+ /// @return Binary hash vector
+ std::vector<unsigned char> ByteHashString(cm::string_view input);
+
+ /// @brief Calculates a binary hash from file content
+ /// @see ByteHashString()
+ /// @return Non empty binary hash vector if the file was read successfully.
+ /// An empty vector otherwise.
+ std::vector<unsigned char> ByteHashFile(const std::string& file);
+
+ /// @brief Calculates a hash string from string input data
+ /// @return Sequence of hex characters pairs for each byte of the binary hash
+ std::string HashString(cm::string_view input);
+
+ /// @brief Calculates a hash string from file content
+ /// @see HashString()
+ /// @return Non empty hash string if the file was read successfully.
+ /// An empty string otherwise.
+ std::string HashFile(const std::string& file);
+
+ void Initialize();
+ void Append(void const*, size_t);
+ void Append(cm::string_view input);
+ std::vector<unsigned char> Finalize();
+ std::string FinalizeHex();
+
+private:
+ unsigned int Id;
+ struct rhash_context* CTX;
+};
diff --git a/Source/cmCurl.cxx b/Source/cmCurl.cxx
new file mode 100644
index 0000000..233790e
--- /dev/null
+++ b/Source/cmCurl.cxx
@@ -0,0 +1,97 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCurl.h"
+
+#if !defined(CMAKE_USE_SYSTEM_CURL) && !defined(_WIN32) && \
+ !defined(__APPLE__) && !defined(CURL_CA_BUNDLE) && !defined(CURL_CA_PATH)
+# define CMAKE_FIND_CAFILE
+# include "cmSystemTools.h"
+#endif
+#include "cmStringAlgorithms.h"
+
+// curl versions before 7.21.5 did not provide this error code
+#if defined(LIBCURL_VERSION_NUM) && LIBCURL_VERSION_NUM < 0x071505
+# define CURLE_NOT_BUILT_IN 4
+#endif
+
+#define check_curl_result(result, errstr) \
+ do { \
+ if ((result) != CURLE_OK && (result) != CURLE_NOT_BUILT_IN) { \
+ e += e.empty() ? "" : "\n"; \
+ e += (errstr); \
+ e += ::curl_easy_strerror(result); \
+ } \
+ } while (false)
+
+std::string cmCurlSetCAInfo(::CURL* curl, const char* cafile)
+{
+ std::string e;
+ if (cafile && *cafile) {
+ ::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_CAINFO, cafile);
+ check_curl_result(res, "Unable to set TLS/SSL Verify CAINFO: ");
+ }
+#ifdef CMAKE_FIND_CAFILE
+# define CMAKE_CAFILE_FEDORA "/etc/pki/tls/certs/ca-bundle.crt"
+ else if (cmSystemTools::FileExists(CMAKE_CAFILE_FEDORA, true)) {
+ ::CURLcode res =
+ ::curl_easy_setopt(curl, CURLOPT_CAINFO, CMAKE_CAFILE_FEDORA);
+ check_curl_result(res, "Unable to set TLS/SSL Verify CAINFO: ");
+ }
+# undef CMAKE_CAFILE_FEDORA
+ else {
+# define CMAKE_CAFILE_COMMON "/etc/ssl/certs/ca-certificates.crt"
+ if (cmSystemTools::FileExists(CMAKE_CAFILE_COMMON, true)) {
+ ::CURLcode res =
+ ::curl_easy_setopt(curl, CURLOPT_CAINFO, CMAKE_CAFILE_COMMON);
+ check_curl_result(res, "Unable to set TLS/SSL Verify CAINFO: ");
+ }
+# undef CMAKE_CAFILE_COMMON
+# define CMAKE_CAPATH_COMMON "/etc/ssl/certs"
+ if (cmSystemTools::FileIsDirectory(CMAKE_CAPATH_COMMON)) {
+ ::CURLcode res =
+ ::curl_easy_setopt(curl, CURLOPT_CAPATH, CMAKE_CAPATH_COMMON);
+ check_curl_result(res, "Unable to set TLS/SSL Verify CAPATH: ");
+ }
+# undef CMAKE_CAPATH_COMMON
+ }
+#endif
+ return e;
+}
+
+std::string cmCurlSetNETRCOption(::CURL* curl, const std::string& netrc_level,
+ const std::string& netrc_file)
+{
+ std::string e;
+ CURL_NETRC_OPTION curl_netrc_level = CURL_NETRC_LAST;
+ ::CURLcode res;
+
+ if (!netrc_level.empty()) {
+ if (netrc_level == "OPTIONAL") {
+ curl_netrc_level = CURL_NETRC_OPTIONAL;
+ } else if (netrc_level == "REQUIRED") {
+ curl_netrc_level = CURL_NETRC_REQUIRED;
+ } else if (netrc_level == "IGNORED") {
+ curl_netrc_level = CURL_NETRC_IGNORED;
+ } else {
+ e = cmStrCat("NETRC accepts OPTIONAL, IGNORED or REQUIRED but got: ",
+ netrc_level);
+ return e;
+ }
+ }
+
+ if (curl_netrc_level != CURL_NETRC_LAST &&
+ curl_netrc_level != CURL_NETRC_IGNORED) {
+ res = ::curl_easy_setopt(curl, CURLOPT_NETRC, curl_netrc_level);
+ check_curl_result(res, "Unable to set netrc level: ");
+ if (!e.empty()) {
+ return e;
+ }
+
+ // check to see if a .netrc file has been specified
+ if (!netrc_file.empty()) {
+ res = ::curl_easy_setopt(curl, CURLOPT_NETRC_FILE, netrc_file.c_str());
+ check_curl_result(res, "Unable to set .netrc file path : ");
+ }
+ }
+ return e;
+}
diff --git a/Source/cmCurl.h b/Source/cmCurl.h
new file mode 100644
index 0000000..fb716f8
--- /dev/null
+++ b/Source/cmCurl.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+
+#include <cm3p/curl/curl.h>
+
+std::string cmCurlSetCAInfo(::CURL* curl, const char* cafile = nullptr);
+std::string cmCurlSetNETRCOption(::CURL* curl, const std::string& netrc_level,
+ const std::string& netrc_file);
diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx
new file mode 100644
index 0000000..f6b9989
--- /dev/null
+++ b/Source/cmCustomCommand.cxx
@@ -0,0 +1,152 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCustomCommand.h"
+
+#include <utility>
+
+#include <cmext/algorithm>
+
+cmCustomCommand::cmCustomCommand(std::vector<std::string> outputs,
+ std::vector<std::string> byproducts,
+ std::vector<std::string> depends,
+ cmCustomCommandLines commandLines,
+ cmListFileBacktrace lfbt, const char* comment,
+ const char* workingDirectory,
+ bool stdPipesUTF8)
+ : Outputs(std::move(outputs))
+ , Byproducts(std::move(byproducts))
+ , Depends(std::move(depends))
+ , CommandLines(std::move(commandLines))
+ , Backtrace(std::move(lfbt))
+ , Comment(comment ? comment : "")
+ , WorkingDirectory(workingDirectory ? workingDirectory : "")
+ , HaveComment(comment != nullptr)
+ , StdPipesUTF8(stdPipesUTF8)
+{
+}
+
+const std::vector<std::string>& cmCustomCommand::GetOutputs() const
+{
+ return this->Outputs;
+}
+
+const std::vector<std::string>& cmCustomCommand::GetByproducts() const
+{
+ return this->Byproducts;
+}
+
+const std::vector<std::string>& cmCustomCommand::GetDepends() const
+{
+ return this->Depends;
+}
+
+const cmCustomCommandLines& cmCustomCommand::GetCommandLines() const
+{
+ return this->CommandLines;
+}
+
+const char* cmCustomCommand::GetComment() const
+{
+ const char* no_comment = nullptr;
+ return this->HaveComment ? this->Comment.c_str() : no_comment;
+}
+
+void cmCustomCommand::AppendCommands(const cmCustomCommandLines& commandLines)
+{
+ cm::append(this->CommandLines, commandLines);
+}
+
+void cmCustomCommand::AppendDepends(const std::vector<std::string>& depends)
+{
+ cm::append(this->Depends, depends);
+}
+
+bool cmCustomCommand::GetEscapeOldStyle() const
+{
+ return this->EscapeOldStyle;
+}
+
+void cmCustomCommand::SetEscapeOldStyle(bool b)
+{
+ this->EscapeOldStyle = b;
+}
+
+bool cmCustomCommand::GetEscapeAllowMakeVars() const
+{
+ return this->EscapeAllowMakeVars;
+}
+
+void cmCustomCommand::SetEscapeAllowMakeVars(bool b)
+{
+ this->EscapeAllowMakeVars = b;
+}
+
+cmListFileBacktrace const& cmCustomCommand::GetBacktrace() const
+{
+ return this->Backtrace;
+}
+
+cmImplicitDependsList const& cmCustomCommand::GetImplicitDepends() const
+{
+ return this->ImplicitDepends;
+}
+
+void cmCustomCommand::SetImplicitDepends(cmImplicitDependsList const& l)
+{
+ this->ImplicitDepends = l;
+}
+
+void cmCustomCommand::AppendImplicitDepends(cmImplicitDependsList const& l)
+{
+ cm::append(this->ImplicitDepends, l);
+}
+
+bool cmCustomCommand::GetUsesTerminal() const
+{
+ return this->UsesTerminal;
+}
+
+void cmCustomCommand::SetUsesTerminal(bool b)
+{
+ this->UsesTerminal = b;
+}
+
+bool cmCustomCommand::GetCommandExpandLists() const
+{
+ return this->CommandExpandLists;
+}
+
+void cmCustomCommand::SetCommandExpandLists(bool b)
+{
+ this->CommandExpandLists = b;
+}
+
+const std::string& cmCustomCommand::GetDepfile() const
+{
+ return this->Depfile;
+}
+
+void cmCustomCommand::SetDepfile(const std::string& depfile)
+{
+ this->Depfile = depfile;
+}
+
+const std::string& cmCustomCommand::GetJobPool() const
+{
+ return this->JobPool;
+}
+
+void cmCustomCommand::SetJobPool(const std::string& job_pool)
+{
+ this->JobPool = job_pool;
+}
+
+cmPolicies::PolicyStatus cmCustomCommand::GetCMP0116Status() const
+{
+ return this->CMP0116Status;
+}
+
+void cmCustomCommand::SetCMP0116Status(cmPolicies::PolicyStatus cmp0116)
+{
+ this->CMP0116Status = cmp0116;
+}
diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h
new file mode 100644
index 0000000..e22c7a4
--- /dev/null
+++ b/Source/cmCustomCommand.h
@@ -0,0 +1,121 @@
+/* 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 <string>
+#include <utility>
+#include <vector>
+
+#include "cmCustomCommandLines.h"
+#include "cmListFileCache.h"
+#include "cmPolicies.h"
+
+class cmImplicitDependsList
+ : public std::vector<std::pair<std::string, std::string>>
+{
+};
+
+/** \class cmCustomCommand
+ * \brief A class to encapsulate a custom command
+ *
+ * cmCustomCommand encapsulates the properties of a custom command
+ */
+class cmCustomCommand
+{
+public:
+ /** Main constructor specifies all information for the command. */
+ cmCustomCommand(std::vector<std::string> outputs,
+ std::vector<std::string> byproducts,
+ std::vector<std::string> depends,
+ cmCustomCommandLines commandLines, cmListFileBacktrace lfbt,
+ const char* comment, const char* workingDirectory,
+ bool stdPipesUTF8);
+
+ /** Get the output file produced by the command. */
+ const std::vector<std::string>& GetOutputs() const;
+
+ /** Get the extra files produced by the command. */
+ const std::vector<std::string>& GetByproducts() const;
+
+ /** Get the vector that holds the list of dependencies. */
+ const std::vector<std::string>& GetDepends() const;
+
+ /** Get the working directory. */
+ std::string const& GetWorkingDirectory() const
+ {
+ return this->WorkingDirectory;
+ }
+
+ /** Get the list of command lines. */
+ const cmCustomCommandLines& GetCommandLines() const;
+
+ /** Get the comment string for the command. */
+ const char* GetComment() const;
+
+ /** Get a value indicating if the command uses UTF-8 output pipes. */
+ bool GetStdPipesUTF8() const { return this->StdPipesUTF8; }
+
+ /** Append to the list of command lines. */
+ void AppendCommands(const cmCustomCommandLines& commandLines);
+
+ /** Append to the list of dependencies. */
+ void AppendDepends(const std::vector<std::string>& depends);
+
+ /** Set/Get whether old-style escaping should be used. */
+ bool GetEscapeOldStyle() const;
+ void SetEscapeOldStyle(bool b);
+
+ /** Set/Get whether the build tool can replace variables in
+ arguments to the command. */
+ bool GetEscapeAllowMakeVars() const;
+ void SetEscapeAllowMakeVars(bool b);
+
+ /** Backtrace of the command that created this custom command. */
+ cmListFileBacktrace const& GetBacktrace() const;
+
+ void SetImplicitDepends(cmImplicitDependsList const&);
+ void AppendImplicitDepends(cmImplicitDependsList const&);
+ cmImplicitDependsList const& GetImplicitDepends() const;
+
+ /** Set/Get whether this custom command should be given access to the
+ real console (if possible). */
+ bool GetUsesTerminal() const;
+ void SetUsesTerminal(bool b);
+
+ /** Set/Get whether lists in command lines should be expanded. */
+ bool GetCommandExpandLists() const;
+ void SetCommandExpandLists(bool b);
+
+ /** Set/Get the depfile (used by the Ninja generator) */
+ const std::string& GetDepfile() const;
+ void SetDepfile(const std::string& depfile);
+
+ /** Set/Get the job_pool (used by the Ninja generator) */
+ const std::string& GetJobPool() const;
+ void SetJobPool(const std::string& job_pool);
+
+ /** Set/Get the CMP0116 status (used by the Ninja generator) */
+ cmPolicies::PolicyStatus GetCMP0116Status() const;
+ void SetCMP0116Status(cmPolicies::PolicyStatus cmp0116);
+
+private:
+ std::vector<std::string> Outputs;
+ std::vector<std::string> Byproducts;
+ std::vector<std::string> Depends;
+ cmCustomCommandLines CommandLines;
+ cmListFileBacktrace Backtrace;
+ cmImplicitDependsList ImplicitDepends;
+ std::string Comment;
+ std::string WorkingDirectory;
+ std::string Depfile;
+ std::string JobPool;
+ bool HaveComment = false;
+ bool EscapeAllowMakeVars = false;
+ bool EscapeOldStyle = true;
+ bool UsesTerminal = false;
+ bool CommandExpandLists = false;
+ bool StdPipesUTF8 = false;
+ cmPolicies::PolicyStatus CMP0116Status = cmPolicies::WARN;
+};
diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
new file mode 100644
index 0000000..4705443
--- /dev/null
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -0,0 +1,466 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCustomCommandGenerator.h"
+
+#include <cstddef>
+#include <memory>
+#include <utility>
+
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmCryptoHash.h"
+#include "cmCustomCommand.h"
+#include "cmCustomCommandLines.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTransformDepfile.h"
+
+namespace {
+std::string EvaluateSplitConfigGenex(
+ cm::string_view input, cmGeneratorExpression const& ge, cmLocalGenerator* lg,
+ bool useOutputConfig, std::string const& outputConfig,
+ std::string const& commandConfig,
+ std::set<BT<std::pair<std::string, bool>>>* utils = nullptr)
+{
+ std::string result;
+
+ while (!input.empty()) {
+ // Copy non-genex content directly to the result.
+ std::string::size_type pos = input.find("$<");
+ result += input.substr(0, pos);
+ if (pos == std::string::npos) {
+ break;
+ }
+ input = input.substr(pos);
+
+ // Find the balanced end of this regex.
+ size_t nestingLevel = 1;
+ for (pos = 2; pos < input.size(); ++pos) {
+ cm::string_view cur = input.substr(pos);
+ if (cmHasLiteralPrefix(cur, "$<")) {
+ ++nestingLevel;
+ ++pos;
+ continue;
+ }
+ if (cmHasLiteralPrefix(cur, ">")) {
+ --nestingLevel;
+ if (nestingLevel == 0) {
+ ++pos;
+ break;
+ }
+ }
+ }
+
+ // Split this genex from following input.
+ cm::string_view genex = input.substr(0, pos);
+ input = input.substr(pos);
+
+ // Convert an outer COMMAND_CONFIG or OUTPUT_CONFIG to the matching config.
+ std::string const* config =
+ useOutputConfig ? &outputConfig : &commandConfig;
+ if (nestingLevel == 0) {
+ static cm::string_view const COMMAND_CONFIG = "$<COMMAND_CONFIG:"_s;
+ static cm::string_view const OUTPUT_CONFIG = "$<OUTPUT_CONFIG:"_s;
+ if (cmHasPrefix(genex, COMMAND_CONFIG)) {
+ genex.remove_prefix(COMMAND_CONFIG.size());
+ genex.remove_suffix(1);
+ useOutputConfig = false;
+ config = &commandConfig;
+ } else if (cmHasPrefix(genex, OUTPUT_CONFIG)) {
+ genex.remove_prefix(OUTPUT_CONFIG.size());
+ genex.remove_suffix(1);
+ useOutputConfig = true;
+ config = &outputConfig;
+ }
+ }
+
+ // Evaluate this genex in the selected configuration.
+ std::unique_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(std::string(genex));
+ result += cge->Evaluate(lg, *config);
+
+ // Record targets referenced by the genex.
+ if (utils) {
+ // FIXME: What is the proper condition for a cross-dependency?
+ bool const cross = !useOutputConfig;
+ for (cmGeneratorTarget* gt : cge->GetTargets()) {
+ utils->emplace(BT<std::pair<std::string, bool>>(
+ { gt->GetName(), cross }, cge->GetBacktrace()));
+ }
+ }
+ }
+
+ return result;
+}
+
+std::vector<std::string> EvaluateDepends(std::vector<std::string> const& paths,
+ cmGeneratorExpression const& ge,
+ cmLocalGenerator* lg,
+ std::string const& outputConfig,
+ std::string const& commandConfig)
+{
+ std::vector<std::string> depends;
+ for (std::string const& p : paths) {
+ std::string const& ep =
+ EvaluateSplitConfigGenex(p, ge, lg, /*useOutputConfig=*/true,
+ /*outputConfig=*/outputConfig,
+ /*commandConfig=*/commandConfig);
+ cm::append(depends, cmExpandedList(ep));
+ }
+ for (std::string& p : depends) {
+ if (cmSystemTools::FileIsFullPath(p)) {
+ p = cmSystemTools::CollapseFullPath(p);
+ } else {
+ cmSystemTools::ConvertToUnixSlashes(p);
+ }
+ }
+ return depends;
+}
+
+std::vector<std::string> EvaluateOutputs(std::vector<std::string> const& paths,
+ cmGeneratorExpression const& ge,
+ cmLocalGenerator* lg,
+ std::string const& config)
+{
+ std::vector<std::string> outputs;
+ for (std::string const& p : paths) {
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(p);
+ cm::append(outputs, lg->ExpandCustomCommandOutputPaths(*cge, config));
+ }
+ return outputs;
+}
+
+std::string EvaluateDepfile(std::string const& path,
+ cmGeneratorExpression const& ge,
+ cmLocalGenerator* lg, std::string const& config)
+{
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(path);
+ return cge->Evaluate(lg, config);
+}
+}
+
+cmCustomCommandGenerator::cmCustomCommandGenerator(
+ cmCustomCommand const& cc, std::string config, cmLocalGenerator* lg,
+ bool transformDepfile, cm::optional<std::string> crossConfig)
+ : CC(&cc)
+ , OutputConfig(crossConfig ? *crossConfig : config)
+ , CommandConfig(std::move(config))
+ , LG(lg)
+ , OldStyle(cc.GetEscapeOldStyle())
+ , MakeVars(cc.GetEscapeAllowMakeVars())
+ , EmulatorsWithArguments(cc.GetCommandLines().size())
+{
+ cmGeneratorExpression ge(cc.GetBacktrace());
+
+ const cmCustomCommandLines& cmdlines = this->CC->GetCommandLines();
+ for (cmCustomCommandLine const& cmdline : cmdlines) {
+ cmCustomCommandLine argv;
+ // For the command itself, we default to the COMMAND_CONFIG.
+ bool useOutputConfig = false;
+ for (std::string const& clarg : cmdline) {
+ std::string parsed_arg = EvaluateSplitConfigGenex(
+ clarg, ge, this->LG, useOutputConfig, this->OutputConfig,
+ this->CommandConfig, &this->Utilities);
+ if (this->CC->GetCommandExpandLists()) {
+ cm::append(argv, cmExpandedList(parsed_arg));
+ } else {
+ argv.push_back(std::move(parsed_arg));
+ }
+
+ // For remaining arguments, we default to the OUTPUT_CONFIG.
+ useOutputConfig = true;
+ }
+
+ if (!argv.empty()) {
+ // If the command references an executable target by name,
+ // collect the target to add a target-level dependency on it.
+ cmGeneratorTarget* gt = this->LG->FindGeneratorTargetToUse(argv.front());
+ if (gt && gt->GetType() == cmStateEnums::EXECUTABLE) {
+ // FIXME: What is the proper condition for a cross-dependency?
+ bool const cross = true;
+ this->Utilities.emplace(BT<std::pair<std::string, bool>>(
+ { gt->GetName(), cross }, cc.GetBacktrace()));
+ }
+ } else {
+ // Later code assumes at least one entry exists, but expanding
+ // lists on an empty command may have left this empty.
+ // FIXME: Should we define behavior for removing empty commands?
+ argv.emplace_back();
+ }
+
+ this->CommandLines.push_back(std::move(argv));
+ }
+
+ if (transformDepfile && !this->CommandLines.empty() &&
+ !cc.GetDepfile().empty() &&
+ this->LG->GetGlobalGenerator()->DepfileFormat()) {
+ cmCustomCommandLine argv;
+ argv.push_back(cmSystemTools::GetCMakeCommand());
+ argv.emplace_back("-E");
+ argv.emplace_back("cmake_transform_depfile");
+ argv.push_back(this->LG->GetGlobalGenerator()->GetName());
+ switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) {
+ case cmDepfileFormat::GccDepfile:
+ argv.emplace_back("gccdepfile");
+ break;
+ case cmDepfileFormat::VsTlog:
+ argv.emplace_back("vstlog");
+ break;
+ }
+ argv.push_back(this->LG->GetSourceDirectory());
+ argv.push_back(this->LG->GetCurrentSourceDirectory());
+ argv.push_back(this->LG->GetBinaryDirectory());
+ argv.push_back(this->LG->GetCurrentBinaryDirectory());
+ argv.push_back(this->GetFullDepfile());
+ argv.push_back(this->GetInternalDepfile());
+
+ this->CommandLines.push_back(std::move(argv));
+ }
+
+ this->Outputs =
+ EvaluateOutputs(cc.GetOutputs(), ge, this->LG, this->OutputConfig);
+ this->Byproducts =
+ EvaluateOutputs(cc.GetByproducts(), ge, this->LG, this->OutputConfig);
+ this->Depends = EvaluateDepends(cc.GetDepends(), ge, this->LG,
+ this->OutputConfig, this->CommandConfig);
+
+ const std::string& workingdirectory = this->CC->GetWorkingDirectory();
+ if (!workingdirectory.empty()) {
+ this->WorkingDirectory =
+ EvaluateSplitConfigGenex(workingdirectory, ge, this->LG, true,
+ this->OutputConfig, this->CommandConfig);
+ // Convert working directory to a full path.
+ if (!this->WorkingDirectory.empty()) {
+ std::string const& build_dir = this->LG->GetCurrentBinaryDirectory();
+ this->WorkingDirectory =
+ cmSystemTools::CollapseFullPath(this->WorkingDirectory, build_dir);
+ }
+ }
+
+ this->FillEmulatorsWithArguments();
+}
+
+unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const
+{
+ return static_cast<unsigned int>(this->CommandLines.size());
+}
+
+void cmCustomCommandGenerator::FillEmulatorsWithArguments()
+{
+ if (!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING")) {
+ return;
+ }
+
+ for (unsigned int c = 0; c < this->GetNumberOfCommands(); ++c) {
+ std::string const& argv0 = this->CommandLines[c][0];
+ cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
+ if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
+ !target->IsImported()) {
+
+ cmProp emulator_property =
+ target->GetProperty("CROSSCOMPILING_EMULATOR");
+ if (!emulator_property) {
+ continue;
+ }
+
+ cmExpandList(*emulator_property, this->EmulatorsWithArguments[c]);
+ }
+ }
+}
+
+std::vector<std::string> cmCustomCommandGenerator::GetCrossCompilingEmulator(
+ unsigned int c) const
+{
+ if (c >= this->EmulatorsWithArguments.size()) {
+ return std::vector<std::string>();
+ }
+ return this->EmulatorsWithArguments[c];
+}
+
+const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const
+{
+ std::string const& argv0 = this->CommandLines[c][0];
+ cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
+ if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
+ (target->IsImported() ||
+ target->GetProperty("CROSSCOMPILING_EMULATOR") ||
+ !this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING"))) {
+ return target->GetLocation(this->CommandConfig).c_str();
+ }
+ return nullptr;
+}
+
+bool cmCustomCommandGenerator::HasOnlyEmptyCommandLines() const
+{
+ for (size_t i = 0; i < this->CommandLines.size(); ++i) {
+ for (size_t j = 0; j < this->CommandLines[i].size(); ++j) {
+ if (!this->CommandLines[i][j].empty()) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
+{
+ std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c);
+ if (!emulator.empty()) {
+ return emulator[0];
+ }
+ if (const char* location = this->GetArgv0Location(c)) {
+ return std::string(location);
+ }
+
+ return this->CommandLines[c][0];
+}
+
+std::string escapeForShellOldStyle(const std::string& str)
+{
+ std::string result;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // if there are spaces
+ std::string temp = str;
+ if (temp.find(" ") != std::string::npos &&
+ temp.find("\"") == std::string::npos) {
+ result = cmStrCat('"', str, '"');
+ return result;
+ }
+ return str;
+#else
+ for (const char* ch = str.c_str(); *ch != '\0'; ++ch) {
+ if (*ch == ' ') {
+ result += '\\';
+ }
+ result += *ch;
+ }
+ return result;
+#endif
+}
+
+void cmCustomCommandGenerator::AppendArguments(unsigned int c,
+ std::string& cmd) const
+{
+ unsigned int offset = 1;
+ std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c);
+ if (!emulator.empty()) {
+ for (unsigned j = 1; j < emulator.size(); ++j) {
+ cmd += " ";
+ if (this->OldStyle) {
+ cmd += escapeForShellOldStyle(emulator[j]);
+ } else {
+ cmd +=
+ this->LG->EscapeForShell(emulator[j], this->MakeVars, false, false,
+ this->MakeVars && this->LG->IsNinjaMulti());
+ }
+ }
+
+ offset = 0;
+ }
+
+ cmCustomCommandLine const& commandLine = this->CommandLines[c];
+ for (unsigned int j = offset; j < commandLine.size(); ++j) {
+ std::string arg;
+ if (const char* location = j == 0 ? this->GetArgv0Location(c) : nullptr) {
+ // GetCommand returned the emulator instead of the argv0 location,
+ // so transform the latter now.
+ arg = location;
+ } else {
+ arg = commandLine[j];
+ }
+ cmd += " ";
+ if (this->OldStyle) {
+ cmd += escapeForShellOldStyle(arg);
+ } else {
+ cmd +=
+ this->LG->EscapeForShell(arg, this->MakeVars, false, false,
+ this->MakeVars && this->LG->IsNinjaMulti());
+ }
+ }
+}
+
+std::string cmCustomCommandGenerator::GetDepfile() const
+{
+ const auto& depfile = this->CC->GetDepfile();
+ if (depfile.empty()) {
+ return "";
+ }
+
+ cmGeneratorExpression ge(this->CC->GetBacktrace());
+ return EvaluateDepfile(depfile, ge, this->LG, this->OutputConfig);
+}
+
+std::string cmCustomCommandGenerator::GetFullDepfile() const
+{
+ std::string depfile = this->GetDepfile();
+ if (depfile.empty()) {
+ return "";
+ }
+
+ if (!cmSystemTools::FileIsFullPath(depfile)) {
+ depfile = cmStrCat(this->LG->GetCurrentBinaryDirectory(), '/', depfile);
+ }
+ return cmSystemTools::CollapseFullPath(depfile);
+}
+
+std::string cmCustomCommandGenerator::GetInternalDepfile() const
+{
+ std::string depfile = this->GetFullDepfile();
+ if (depfile.empty()) {
+ return "";
+ }
+
+ cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
+ std::string extension;
+ switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) {
+ case cmDepfileFormat::GccDepfile:
+ extension = ".d";
+ break;
+ case cmDepfileFormat::VsTlog:
+ extension = ".tlog";
+ break;
+ }
+ return cmStrCat(this->LG->GetBinaryDirectory(), "/CMakeFiles/d/",
+ hash.HashString(depfile), extension);
+}
+
+const char* cmCustomCommandGenerator::GetComment() const
+{
+ return this->CC->GetComment();
+}
+
+std::string cmCustomCommandGenerator::GetWorkingDirectory() const
+{
+ return this->WorkingDirectory;
+}
+
+std::vector<std::string> const& cmCustomCommandGenerator::GetOutputs() const
+{
+ return this->Outputs;
+}
+
+std::vector<std::string> const& cmCustomCommandGenerator::GetByproducts() const
+{
+ return this->Byproducts;
+}
+
+std::vector<std::string> const& cmCustomCommandGenerator::GetDepends() const
+{
+ return this->Depends;
+}
+
+std::set<BT<std::pair<std::string, bool>>> const&
+cmCustomCommandGenerator::GetUtilities() const
+{
+ return this->Utilities;
+}
diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h
new file mode 100644
index 0000000..53e5573
--- /dev/null
+++ b/Source/cmCustomCommandGenerator.h
@@ -0,0 +1,66 @@
+/* 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 <utility>
+#include <vector>
+
+#include <cm/optional>
+
+#include "cmCustomCommandLines.h"
+#include "cmListFileCache.h"
+
+class cmCustomCommand;
+class cmLocalGenerator;
+
+class cmCustomCommandGenerator
+{
+ cmCustomCommand const* CC;
+ std::string OutputConfig;
+ std::string CommandConfig;
+ cmLocalGenerator* LG;
+ bool OldStyle;
+ bool MakeVars;
+ cmCustomCommandLines CommandLines;
+ std::vector<std::vector<std::string>> EmulatorsWithArguments;
+ std::vector<std::string> Outputs;
+ std::vector<std::string> Byproducts;
+ std::vector<std::string> Depends;
+ std::string WorkingDirectory;
+ std::set<BT<std::pair<std::string, bool>>> Utilities;
+
+ void FillEmulatorsWithArguments();
+ std::vector<std::string> GetCrossCompilingEmulator(unsigned int c) const;
+ const char* GetArgv0Location(unsigned int c) const;
+
+public:
+ cmCustomCommandGenerator(cmCustomCommand const& cc, std::string config,
+ cmLocalGenerator* lg, bool transformDepfile = true,
+ cm::optional<std::string> crossConfig = {});
+ cmCustomCommandGenerator(const cmCustomCommandGenerator&) = delete;
+ cmCustomCommandGenerator(cmCustomCommandGenerator&&) = default;
+ cmCustomCommandGenerator& operator=(const cmCustomCommandGenerator&) =
+ delete;
+ cmCustomCommandGenerator& operator=(cmCustomCommandGenerator&&) = default;
+ cmCustomCommand const& GetCC() const { return *(this->CC); }
+ unsigned int GetNumberOfCommands() const;
+ std::string GetCommand(unsigned int c) const;
+ void AppendArguments(unsigned int c, std::string& cmd) const;
+ const char* GetComment() const;
+ std::string GetWorkingDirectory() const;
+ std::vector<std::string> const& GetOutputs() const;
+ std::vector<std::string> const& GetByproducts() const;
+ std::vector<std::string> const& GetDepends() const;
+ std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const;
+ bool HasOnlyEmptyCommandLines() const;
+ std::string GetDepfile() const;
+ std::string GetFullDepfile() const;
+ std::string GetInternalDepfile() const;
+
+ const std::string& GetOutputConfig() const { return this->OutputConfig; }
+ const std::string& GetCommandConfig() const { return this->CommandConfig; }
+};
diff --git a/Source/cmCustomCommandLines.cxx b/Source/cmCustomCommandLines.cxx
new file mode 100644
index 0000000..37ad75b
--- /dev/null
+++ b/Source/cmCustomCommandLines.cxx
@@ -0,0 +1,22 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCustomCommandLines.h"
+
+cmCustomCommandLine cmMakeCommandLine(
+ std::initializer_list<cm::string_view> ilist)
+{
+ cmCustomCommandLine commandLine;
+ commandLine.reserve(ilist.size());
+ for (cm::string_view cmd : ilist) {
+ commandLine.emplace_back(cmd);
+ }
+ return commandLine;
+}
+
+cmCustomCommandLines cmMakeSingleCommandLine(
+ std::initializer_list<cm::string_view> ilist)
+{
+ cmCustomCommandLines commandLines;
+ commandLines.push_back(cmMakeCommandLine(ilist));
+ return commandLines;
+}
diff --git a/Source/cmCustomCommandLines.h b/Source/cmCustomCommandLines.h
new file mode 100644
index 0000000..ee8d080
--- /dev/null
+++ b/Source/cmCustomCommandLines.h
@@ -0,0 +1,29 @@
+/* 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 <initializer_list>
+#include <string>
+#include <vector>
+
+#include <cm/string_view> // IWYU pragma: keep
+
+/** Data structure to represent a single command line. */
+class cmCustomCommandLine : public std::vector<std::string>
+{
+};
+
+/** Data structure to represent a list of command lines. */
+class cmCustomCommandLines : public std::vector<cmCustomCommandLine>
+{
+};
+
+/** Return a command line from a list of command line parts. */
+cmCustomCommandLine cmMakeCommandLine(
+ std::initializer_list<cm::string_view> ilist);
+
+/** Return a command line vector with a single command line. */
+cmCustomCommandLines cmMakeSingleCommandLine(
+ std::initializer_list<cm::string_view> ilist);
diff --git a/Source/cmCustomCommandTypes.h b/Source/cmCustomCommandTypes.h
new file mode 100644
index 0000000..324da9e
--- /dev/null
+++ b/Source/cmCustomCommandTypes.h
@@ -0,0 +1,29 @@
+/* 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 <string>
+
+/** Target custom command type */
+enum class cmCustomCommandType
+{
+ PRE_BUILD,
+ PRE_LINK,
+ POST_BUILD
+};
+
+/** Where the command originated from. */
+enum class cmCommandOrigin
+{
+ Project,
+ Generator
+};
+
+/** How to handle custom commands for object libraries */
+enum class cmObjectLibraryCommands
+{
+ Reject,
+ Accept
+};
diff --git a/Source/cmDefinePropertyCommand.cxx b/Source/cmDefinePropertyCommand.cxx
new file mode 100644
index 0000000..4e2d9b0
--- /dev/null
+++ b/Source/cmDefinePropertyCommand.cxx
@@ -0,0 +1,101 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmDefinePropertyCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+
+bool cmDefinePropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Get the scope in which to define the property.
+ cmProperty::ScopeType scope;
+ std::string const& scope_arg = args[0];
+
+ if (scope_arg == "GLOBAL") {
+ scope = cmProperty::GLOBAL;
+ } else if (scope_arg == "DIRECTORY") {
+ scope = cmProperty::DIRECTORY;
+ } else if (scope_arg == "TARGET") {
+ scope = cmProperty::TARGET;
+ } else if (scope_arg == "SOURCE") {
+ scope = cmProperty::SOURCE_FILE;
+ } else if (scope_arg == "TEST") {
+ scope = cmProperty::TEST;
+ } else if (scope_arg == "VARIABLE") {
+ scope = cmProperty::VARIABLE;
+ } else if (scope_arg == "CACHED_VARIABLE") {
+ scope = cmProperty::CACHED_VARIABLE;
+ } else {
+ status.SetError(cmStrCat("given invalid scope ", scope_arg,
+ ". Valid scopes are GLOBAL, DIRECTORY, TARGET, "
+ "SOURCE, TEST, VARIABLE, CACHED_VARIABLE."));
+ return false;
+ }
+
+ // Parse remaining arguments.
+ bool inherited = false;
+ std::string PropertyName;
+ std::string BriefDocs;
+ std::string FullDocs;
+ enum Doing
+ {
+ DoingNone,
+ DoingProperty,
+ DoingBrief,
+ DoingFull
+ };
+ Doing doing = DoingNone;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "PROPERTY") {
+ doing = DoingProperty;
+ } else if (args[i] == "BRIEF_DOCS") {
+ doing = DoingBrief;
+ } else if (args[i] == "FULL_DOCS") {
+ doing = DoingFull;
+ } else if (args[i] == "INHERITED") {
+ doing = DoingNone;
+ inherited = true;
+ } else if (doing == DoingProperty) {
+ doing = DoingNone;
+ PropertyName = args[i];
+ } else if (doing == DoingBrief) {
+ BriefDocs += args[i];
+ } else if (doing == DoingFull) {
+ FullDocs += args[i];
+ } else {
+ status.SetError(cmStrCat("given invalid argument \"", args[i], "\"."));
+ return false;
+ }
+ }
+
+ // Make sure a property name was found.
+ if (PropertyName.empty()) {
+ status.SetError("not given a PROPERTY <name> argument.");
+ return false;
+ }
+
+ // Make sure documentation was given.
+ if (BriefDocs.empty()) {
+ status.SetError("not given a BRIEF_DOCS <brief-doc> argument.");
+ return false;
+ }
+ if (FullDocs.empty()) {
+ status.SetError("not given a FULL_DOCS <full-doc> argument.");
+ return false;
+ }
+
+ // Actually define the property.
+ status.GetMakefile().GetState()->DefineProperty(
+ PropertyName, scope, BriefDocs, FullDocs, inherited);
+
+ return true;
+}
diff --git a/Source/cmDefinePropertyCommand.h b/Source/cmDefinePropertyCommand.h
new file mode 100644
index 0000000..3c478b3
--- /dev/null
+++ b/Source/cmDefinePropertyCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmDefinePropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmDefinitions.cxx b/Source/cmDefinitions.cxx
new file mode 100644
index 0000000..4a4f87d
--- /dev/null
+++ b/Source/cmDefinitions.cxx
@@ -0,0 +1,109 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmDefinitions.h"
+
+#include <cassert>
+#include <functional>
+#include <unordered_set>
+#include <utility>
+
+#include <cm/string_view>
+
+cmDefinitions::Def cmDefinitions::NoDef;
+
+cmDefinitions::Def const& cmDefinitions::GetInternal(const std::string& key,
+ StackIter begin,
+ StackIter end, bool raise)
+{
+ assert(begin != end);
+ {
+ auto it = begin->Map.find(cm::String::borrow(key));
+ if (it != begin->Map.end()) {
+ return it->second;
+ }
+ }
+ StackIter it = begin;
+ ++it;
+ if (it == end) {
+ return cmDefinitions::NoDef;
+ }
+ Def const& def = cmDefinitions::GetInternal(key, it, end, raise);
+ if (!raise) {
+ return def;
+ }
+ return begin->Map.emplace(key, def).first->second;
+}
+
+const std::string* cmDefinitions::Get(const std::string& key, StackIter begin,
+ StackIter end)
+{
+ Def const& def = cmDefinitions::GetInternal(key, begin, end, false);
+ return def.Value ? def.Value.str_if_stable() : nullptr;
+}
+
+void cmDefinitions::Raise(const std::string& key, StackIter begin,
+ StackIter end)
+{
+ cmDefinitions::GetInternal(key, begin, end, true);
+}
+
+bool cmDefinitions::HasKey(const std::string& key, StackIter begin,
+ StackIter end)
+{
+ for (StackIter it = begin; it != end; ++it) {
+ if (it->Map.find(cm::String::borrow(key)) != it->Map.end()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+cmDefinitions cmDefinitions::MakeClosure(StackIter begin, StackIter end)
+{
+ cmDefinitions closure;
+ std::unordered_set<cm::string_view> undefined;
+ for (StackIter it = begin; it != end; ++it) {
+ // Consider local definitions.
+ for (auto const& mi : it->Map) {
+ // Use this key if it is not already set or unset.
+ if (closure.Map.find(mi.first) == closure.Map.end() &&
+ undefined.find(mi.first.view()) == undefined.end()) {
+ if (mi.second.Value) {
+ closure.Map.insert(mi);
+ } else {
+ undefined.emplace(mi.first.view());
+ }
+ }
+ }
+ }
+ return closure;
+}
+
+std::vector<std::string> cmDefinitions::ClosureKeys(StackIter begin,
+ StackIter end)
+{
+ std::vector<std::string> defined;
+ std::unordered_set<cm::string_view> bound;
+
+ for (StackIter it = begin; it != end; ++it) {
+ defined.reserve(defined.size() + it->Map.size());
+ for (auto const& mi : it->Map) {
+ // Use this key if it is not already set or unset.
+ if (bound.emplace(mi.first.view()).second && mi.second.Value) {
+ defined.push_back(*mi.first.str_if_stable());
+ }
+ }
+ }
+
+ return defined;
+}
+
+void cmDefinitions::Set(const std::string& key, cm::string_view value)
+{
+ this->Map[key] = Def(value);
+}
+
+void cmDefinitions::Unset(const std::string& key)
+{
+ this->Map[key] = Def();
+}
diff --git a/Source/cmDefinitions.h b/Source/cmDefinitions.h
new file mode 100644
index 0000000..b650aa8
--- /dev/null
+++ b/Source/cmDefinitions.h
@@ -0,0 +1,68 @@
+/* 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 <functional>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmLinkedTree.h"
+#include "cmString.hxx"
+
+/** \class cmDefinitions
+ * \brief Store a scope of variable definitions for CMake language.
+ *
+ * This stores the state of variable definitions (set or unset) for
+ * one scope. Sets are always local. Gets search parent scopes
+ * transitively and save results locally.
+ */
+class cmDefinitions
+{
+ using StackIter = cmLinkedTree<cmDefinitions>::iterator;
+
+public:
+ // -- Static member functions
+
+ static const std::string* Get(const std::string& key, StackIter begin,
+ StackIter end);
+
+ static void Raise(const std::string& key, StackIter begin, StackIter end);
+
+ static bool HasKey(const std::string& key, StackIter begin, StackIter end);
+
+ static std::vector<std::string> ClosureKeys(StackIter begin, StackIter end);
+
+ static cmDefinitions MakeClosure(StackIter begin, StackIter end);
+
+ // -- Member functions
+
+ /** Set a value associated with a key. */
+ void Set(const std::string& key, cm::string_view value);
+
+ /** Unset a definition. */
+ void Unset(const std::string& key);
+
+private:
+ /** String with existence boolean. */
+ struct Def
+ {
+ public:
+ Def() = default;
+ Def(cm::string_view value)
+ : Value(value)
+ {
+ }
+ cm::String Value;
+ };
+ static Def NoDef;
+
+ std::unordered_map<cm::String, Def> Map;
+
+ static Def const& GetInternal(const std::string& key, StackIter begin,
+ StackIter end, bool raise);
+};
diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx
new file mode 100644
index 0000000..566c3bf
--- /dev/null
+++ b/Source/cmDepends.cxx
@@ -0,0 +1,247 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmDepends.h"
+
+#include <utility>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmFileTime.h"
+#include "cmFileTimeCache.h"
+#include "cmGeneratedFileStream.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmDepends::cmDepends(cmLocalUnixMakefileGenerator3* lg, std::string targetDir)
+ : LocalGenerator(lg)
+ , TargetDirectory(std::move(targetDir))
+{
+}
+
+cmDepends::~cmDepends() = default;
+
+bool cmDepends::Write(std::ostream& makeDepends, std::ostream& internalDepends)
+{
+ std::map<std::string, std::set<std::string>> dependencies;
+ {
+ // Lookup the set of sources to scan.
+ std::vector<std::string> pairs;
+ {
+ std::string const srcLang = "CMAKE_DEPENDS_CHECK_" + this->Language;
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ cmExpandList(mf->GetSafeDefinition(srcLang), pairs);
+ }
+ for (auto si = pairs.begin(); si != pairs.end();) {
+ // Get the source and object file.
+ std::string const& src = *si++;
+ if (si == pairs.end()) {
+ break;
+ }
+ std::string const& obj = *si++;
+ dependencies[obj].insert(src);
+ }
+ }
+ for (auto const& d : dependencies) {
+ // Write the dependencies for this pair.
+ if (!this->WriteDependencies(d.second, d.first, makeDepends,
+ internalDepends)) {
+ return false;
+ }
+ }
+
+ return this->Finalize(makeDepends, internalDepends);
+}
+
+bool cmDepends::Finalize(std::ostream& /*unused*/, std::ostream& /*unused*/)
+{
+ return true;
+}
+
+bool cmDepends::Check(const std::string& makeFile,
+ const std::string& internalFile,
+ DependencyMap& validDeps)
+{
+ // Check whether dependencies must be regenerated.
+ bool okay = true;
+ cmsys::ifstream fin(internalFile.c_str());
+ if (!(fin && this->CheckDependencies(fin, internalFile, validDeps))) {
+ // Clear all dependencies so they will be regenerated.
+ this->Clear(makeFile);
+ cmSystemTools::RemoveFile(internalFile);
+ this->FileTimeCache->Remove(internalFile);
+ okay = false;
+ }
+ return okay;
+}
+
+void cmDepends::Clear(const std::string& file) const
+{
+ // Print verbose output.
+ if (this->Verbose) {
+ cmSystemTools::Stdout(
+ cmStrCat("Clearing dependencies in \"", file, "\".\n"));
+ }
+
+ // Write an empty dependency file.
+ cmGeneratedFileStream depFileStream(file);
+ depFileStream << "# Empty dependencies file\n"
+ "# This may be replaced when dependencies are built.\n";
+}
+
+bool cmDepends::WriteDependencies(const std::set<std::string>& /*unused*/,
+ const std::string& /*unused*/,
+ std::ostream& /*unused*/,
+ std::ostream& /*unused*/)
+{
+ // This should be implemented by the subclass.
+ return false;
+}
+
+bool cmDepends::CheckDependencies(std::istream& internalDepends,
+ const std::string& internalDependsFileName,
+ DependencyMap& validDeps)
+{
+ // Read internal depends file time
+ cmFileTime internalDependsTime;
+ if (!this->FileTimeCache->Load(internalDependsFileName,
+ internalDependsTime)) {
+ return false;
+ }
+
+ // Parse dependencies from the stream. If any dependee is missing
+ // or newer than the depender then dependencies should be
+ // regenerated.
+ bool okay = true;
+ bool dependerExists = false;
+
+ std::string line;
+ line.reserve(1024);
+ std::string depender;
+ std::string dependee;
+ cmFileTime dependerTime;
+ cmFileTime dependeeTime;
+ std::vector<std::string>* currentDependencies = nullptr;
+
+ while (std::getline(internalDepends, line)) {
+ // Check if this an empty or a comment line
+ if (line.empty() || line.front() == '#') {
+ continue;
+ }
+ // Drop carriage return character at the end
+ if (line.back() == '\r') {
+ line.pop_back();
+ if (line.empty()) {
+ continue;
+ }
+ }
+ // Check if this a depender line
+ if (line.front() != ' ') {
+ depender = line;
+ dependerExists = this->FileTimeCache->Load(depender, dependerTime);
+ // If we erase validDeps[this->Depender] by overwriting it with an empty
+ // vector, we lose dependencies for dependers that have multiple
+ // entries. No need to initialize the entry, std::map will do so on first
+ // access.
+ currentDependencies = &validDeps[depender];
+ continue;
+ }
+
+ // This is a dependee line
+ dependee = line.substr(1);
+
+ // Add dependee to depender's list
+ if (currentDependencies != nullptr) {
+ currentDependencies->push_back(dependee);
+ }
+
+ // Dependencies must be regenerated
+ // * if the dependee does not exist
+ // * if the depender exists and is older than the dependee.
+ // * if the depender does not exist, but the dependee is newer than the
+ // depends file
+ bool regenerate = false;
+ bool dependeeExists = this->FileTimeCache->Load(dependee, dependeeTime);
+ if (!dependeeExists) {
+ // The dependee does not exist.
+ regenerate = true;
+
+ // Print verbose output.
+ if (this->Verbose) {
+ cmSystemTools::Stdout(cmStrCat("Dependee \"", dependee,
+ "\" does not exist for depender \"",
+ depender, "\".\n"));
+ }
+ } else if (dependerExists) {
+ // The dependee and depender both exist. Compare file times.
+ if (dependerTime.Older(dependeeTime)) {
+ // The depender is older than the dependee.
+ regenerate = true;
+
+ // Print verbose output.
+ if (this->Verbose) {
+ cmSystemTools::Stdout(cmStrCat("Dependee \"", dependee,
+ "\" is newer than depender \"",
+ depender, "\".\n"));
+ }
+ }
+ } else {
+ // The dependee exists, but the depender doesn't. Regenerate if the
+ // internalDepends file is older than the dependee.
+ if (internalDependsTime.Older(dependeeTime)) {
+ // The depends-file is older than the dependee.
+ regenerate = true;
+
+ // Print verbose output.
+ if (this->Verbose) {
+ cmSystemTools::Stdout(cmStrCat("Dependee \"", dependee,
+ "\" is newer than depends file \"",
+ internalDependsFileName, "\".\n"));
+ }
+ }
+ }
+
+ if (regenerate) {
+ // Dependencies must be regenerated.
+ okay = false;
+
+ // Remove the information of this depender from the map, it needs
+ // to be rescanned
+ if (currentDependencies != nullptr) {
+ validDeps.erase(depender);
+ currentDependencies = nullptr;
+ }
+
+ // Remove the depender to be sure it is rebuilt.
+ if (dependerExists) {
+ cmSystemTools::RemoveFile(depender);
+ this->FileTimeCache->Remove(depender);
+ dependerExists = false;
+ }
+ }
+ }
+
+ return okay;
+}
+
+void cmDepends::SetIncludePathFromLanguage(const std::string& lang)
+{
+ // Look for the new per "TARGET_" variant first:
+ cmProp includePath = nullptr;
+ std::string includePathVar =
+ cmStrCat("CMAKE_", lang, "_TARGET_INCLUDE_PATH");
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ includePath = mf->GetDefinition(includePathVar);
+ if (includePath) {
+ cmExpandList(*includePath, this->IncludePath);
+ } else {
+ // Fallback to the old directory level variable if no per-target var:
+ includePathVar = cmStrCat("CMAKE_", lang, "_INCLUDE_PATH");
+ includePath = mf->GetDefinition(includePathVar);
+ if (includePath) {
+ cmExpandList(*includePath, this->IncludePath);
+ }
+ }
+}
diff --git a/Source/cmDepends.h b/Source/cmDepends.h
new file mode 100644
index 0000000..76af4db
--- /dev/null
+++ b/Source/cmDepends.h
@@ -0,0 +1,112 @@
+/* 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 <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+class cmFileTimeCache;
+class cmLocalUnixMakefileGenerator3;
+
+/** \class cmDepends
+ * \brief Dependency scanner superclass.
+ *
+ * This class is responsible for maintaining a .depends.make file in
+ * the build tree corresponding to an object file. Subclasses help it
+ * maintain dependencies for particular languages.
+ */
+class cmDepends
+{
+public:
+ using DependencyMap = std::map<std::string, std::vector<std::string>>;
+
+ /** Instances need to know the build directory name and the relative
+ path from the build directory to the target file. */
+ cmDepends(cmLocalUnixMakefileGenerator3* lg = nullptr,
+ std::string targetDir = "");
+
+ cmDepends(cmDepends const&) = delete;
+ cmDepends& operator=(cmDepends const&) = delete;
+
+ /** Set the local generator for the directory in which we are
+ scanning dependencies. This is not a full local generator; it
+ has been setup to do relative path conversions for the current
+ directory. */
+ void SetLocalGenerator(cmLocalUnixMakefileGenerator3* lg)
+ {
+ this->LocalGenerator = lg;
+ }
+
+ /** Set the specific language to be scanned. */
+ void SetLanguage(const std::string& lang) { this->Language = lang; }
+
+ /** Set the target build directory. */
+ void SetTargetDirectory(const std::string& dir)
+ {
+ this->TargetDirectory = dir;
+ }
+
+ /** should this be verbose in its output */
+ void SetVerbose(bool verb) { this->Verbose = verb; }
+
+ /** Virtual destructor to cleanup subclasses properly. */
+ virtual ~cmDepends();
+
+ /** Write dependencies for the target file. */
+ bool Write(std::ostream& makeDepends, std::ostream& internalDepends);
+
+ /** Check dependencies for the target file. Returns true if
+ dependencies are okay and false if they must be generated. If
+ they must be generated Clear has already been called to wipe out
+ the old dependencies.
+ Dependencies which are still valid will be stored in validDeps. */
+ bool Check(const std::string& makeFile, const std::string& internalFile,
+ DependencyMap& validDeps);
+
+ /** Clear dependencies for the target file so they will be regenerated. */
+ void Clear(const std::string& file) const;
+
+ /** Set the file comparison object */
+ void SetFileTimeCache(cmFileTimeCache* fc) { this->FileTimeCache = fc; }
+
+protected:
+ // Write dependencies for the target file to the given stream.
+ // Return true for success and false for failure.
+ virtual bool WriteDependencies(const std::set<std::string>& sources,
+ const std::string& obj,
+ std::ostream& makeDepends,
+ std::ostream& internalDepends);
+
+ // Check dependencies for the target file in the given stream.
+ // Return false if dependencies must be regenerated and true
+ // otherwise.
+ virtual bool CheckDependencies(std::istream& internalDepends,
+ const std::string& internalDependsFileName,
+ DependencyMap& validDeps);
+
+ // Finalize the dependency information for the target.
+ virtual bool Finalize(std::ostream& makeDepends,
+ std::ostream& internalDepends);
+
+ // The local generator.
+ cmLocalUnixMakefileGenerator3* LocalGenerator;
+
+ // Flag for verbose output.
+ bool Verbose = false;
+ cmFileTimeCache* FileTimeCache = nullptr;
+
+ std::string Language;
+
+ // The full path to the target's build directory.
+ std::string TargetDirectory;
+
+ // The include file search path.
+ std::vector<std::string> IncludePath;
+
+ void SetIncludePathFromLanguage(const std::string& lang);
+};
diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx
new file mode 100644
index 0000000..60e8cbf
--- /dev/null
+++ b/Source/cmDependsC.cxx
@@ -0,0 +1,469 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmDependsC.h"
+
+#include <utility>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmFileTime.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+#define INCLUDE_REGEX_LINE \
+ "^[ \t]*[#%][ \t]*(include|import)[ \t]*[<\"]([^\">]+)([\">])"
+
+#define INCLUDE_REGEX_LINE_MARKER "#IncludeRegexLine: "
+#define INCLUDE_REGEX_SCAN_MARKER "#IncludeRegexScan: "
+#define INCLUDE_REGEX_COMPLAIN_MARKER "#IncludeRegexComplain: "
+#define INCLUDE_REGEX_TRANSFORM_MARKER "#IncludeRegexTransform: "
+
+cmDependsC::cmDependsC() = default;
+
+cmDependsC::cmDependsC(cmLocalUnixMakefileGenerator3* lg,
+ const std::string& targetDir, const std::string& lang,
+ const DependencyMap* validDeps)
+ : cmDepends(lg, targetDir)
+ , ValidDeps(validDeps)
+{
+ cmMakefile* mf = lg->GetMakefile();
+
+ // Configure the include file search path.
+ this->SetIncludePathFromLanguage(lang);
+
+ // Configure regular expressions.
+ std::string scanRegex = "^.*$";
+ std::string complainRegex = "^$";
+ {
+ std::string scanRegexVar = cmStrCat("CMAKE_", lang, "_INCLUDE_REGEX_SCAN");
+ if (cmProp sr = mf->GetDefinition(scanRegexVar)) {
+ scanRegex = *sr;
+ }
+ std::string complainRegexVar =
+ cmStrCat("CMAKE_", lang, "_INCLUDE_REGEX_COMPLAIN");
+ if (cmProp cr = mf->GetDefinition(complainRegexVar)) {
+ complainRegex = *cr;
+ }
+ }
+
+ this->IncludeRegexLine.compile(INCLUDE_REGEX_LINE);
+ this->IncludeRegexScan.compile(scanRegex);
+ this->IncludeRegexComplain.compile(complainRegex);
+ this->IncludeRegexLineString = INCLUDE_REGEX_LINE_MARKER INCLUDE_REGEX_LINE;
+ this->IncludeRegexScanString =
+ cmStrCat(INCLUDE_REGEX_SCAN_MARKER, scanRegex);
+ this->IncludeRegexComplainString =
+ cmStrCat(INCLUDE_REGEX_COMPLAIN_MARKER, complainRegex);
+
+ this->SetupTransforms();
+
+ this->CacheFileName =
+ cmStrCat(this->TargetDirectory, '/', lang, ".includecache");
+
+ this->ReadCacheFile();
+}
+
+cmDependsC::~cmDependsC()
+{
+ this->WriteCacheFile();
+}
+
+bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
+ const std::string& obj,
+ std::ostream& makeDepends,
+ std::ostream& internalDepends)
+{
+ // Make sure this is a scanning instance.
+ if (sources.empty() || sources.begin()->empty()) {
+ cmSystemTools::Error("Cannot scan dependencies without a source file.");
+ return false;
+ }
+ if (obj.empty()) {
+ cmSystemTools::Error("Cannot scan dependencies without an object file.");
+ return false;
+ }
+
+ std::set<std::string> dependencies;
+ bool haveDeps = false;
+
+ std::string binDir = this->LocalGenerator->GetBinaryDirectory();
+
+ // Compute a path to the object file to write to the internal depend file.
+ // Any existing content of the internal depend file has already been
+ // loaded in ValidDeps with this path as a key.
+ std::string obj_i =
+ this->LocalGenerator->MaybeConvertToRelativePath(binDir, obj);
+
+ if (this->ValidDeps != nullptr) {
+ auto const tmpIt = this->ValidDeps->find(obj_i);
+ if (tmpIt != this->ValidDeps->end()) {
+ dependencies.insert(tmpIt->second.begin(), tmpIt->second.end());
+ haveDeps = true;
+ }
+ }
+
+ if (!haveDeps) {
+ // Walk the dependency graph starting with the source file.
+ int srcFiles = static_cast<int>(sources.size());
+ this->Encountered.clear();
+
+ for (std::string const& src : sources) {
+ UnscannedEntry root;
+ root.FileName = src;
+ this->Unscanned.push(root);
+ this->Encountered.insert(src);
+ }
+
+ std::set<std::string> scanned;
+ while (!this->Unscanned.empty()) {
+ // Get the next file to scan.
+ UnscannedEntry current = this->Unscanned.front();
+ this->Unscanned.pop();
+
+ // If not a full path, find the file in the include path.
+ std::string fullName;
+ if ((srcFiles > 0) || cmSystemTools::FileIsFullPath(current.FileName)) {
+ if (cmSystemTools::FileExists(current.FileName, true)) {
+ fullName = current.FileName;
+ }
+ } else if (!current.QuotedLocation.empty() &&
+ cmSystemTools::FileExists(current.QuotedLocation, true)) {
+ // The include statement producing this entry was a double-quote
+ // include and the included file is present in the directory of
+ // the source containing the include statement.
+ fullName = current.QuotedLocation;
+ } else {
+ auto headerLocationIt =
+ this->HeaderLocationCache.find(current.FileName);
+ if (headerLocationIt != this->HeaderLocationCache.end()) {
+ fullName = headerLocationIt->second;
+ } else {
+ for (std::string const& iPath : this->IncludePath) {
+ // Construct the name of the file as if it were in the current
+ // include directory. Avoid using a leading "./".
+ std::string tmpPath =
+ cmSystemTools::CollapseFullPath(current.FileName, iPath);
+
+ // Look for the file in this location.
+ if (cmSystemTools::FileExists(tmpPath, true)) {
+ fullName = tmpPath;
+ this->HeaderLocationCache[current.FileName] = std::move(tmpPath);
+ break;
+ }
+ }
+ }
+ }
+
+ // Complain if the file cannot be found and matches the complain
+ // regex.
+ if (fullName.empty() &&
+ this->IncludeRegexComplain.find(current.FileName)) {
+ cmSystemTools::Error("Cannot find file \"" + current.FileName + "\".");
+ return false;
+ }
+
+ // Scan the file if it was found and has not been scanned already.
+ if (!fullName.empty() && (scanned.find(fullName) == scanned.end())) {
+ // Record scanned files.
+ scanned.insert(fullName);
+
+ // Check whether this file is already in the cache
+ auto fileIt = this->FileCache.find(fullName);
+ if (fileIt != this->FileCache.end()) {
+ fileIt->second.Used = true;
+ dependencies.insert(fullName);
+ for (UnscannedEntry const& inc : fileIt->second.UnscannedEntries) {
+ if (this->Encountered.find(inc.FileName) ==
+ this->Encountered.end()) {
+ this->Encountered.insert(inc.FileName);
+ this->Unscanned.push(inc);
+ }
+ }
+ } else {
+
+ // Try to scan the file. Just leave it out if we cannot find
+ // it.
+ cmsys::ifstream fin(fullName.c_str());
+ if (fin) {
+ cmsys::FStream::BOM bom = cmsys::FStream::ReadBOM(fin);
+ if (bom == cmsys::FStream::BOM_None ||
+ bom == cmsys::FStream::BOM_UTF8) {
+ // Add this file as a dependency.
+ dependencies.insert(fullName);
+
+ // Scan this file for new dependencies. Pass the directory
+ // containing the file to handle double-quote includes.
+ std::string dir = cmSystemTools::GetFilenamePath(fullName);
+ this->Scan(fin, dir, fullName);
+ } else {
+ // Skip file with encoding we do not implement.
+ }
+ }
+ }
+ }
+
+ srcFiles--;
+ }
+ }
+
+ // Write the dependencies to the output stream. Makefile rules
+ // written by the original local generator for this directory
+ // convert the dependencies to paths relative to the home output
+ // directory. We must do the same here.
+ std::string obj_m = this->LocalGenerator->ConvertToMakefilePath(obj_i);
+ internalDepends << obj_i << '\n';
+ if (!dependencies.empty()) {
+ const auto& lineContinue = static_cast<cmGlobalUnixMakefileGenerator3*>(
+ this->LocalGenerator->GetGlobalGenerator())
+ ->LineContinueDirective;
+ bool supportLongLineDepend = static_cast<cmGlobalUnixMakefileGenerator3*>(
+ this->LocalGenerator->GetGlobalGenerator())
+ ->SupportsLongLineDependencies();
+ if (supportLongLineDepend) {
+ makeDepends << obj_m << ':';
+ }
+ for (std::string const& dep : dependencies) {
+ std::string dependee = this->LocalGenerator->ConvertToMakefilePath(
+ this->LocalGenerator->MaybeConvertToRelativePath(binDir, dep));
+ if (supportLongLineDepend) {
+ makeDepends << ' ' << lineContinue << ' ' << dependee;
+ } else {
+ makeDepends << obj_m << ": " << dependee << '\n';
+ }
+ internalDepends << ' ' << dep << '\n';
+ }
+ makeDepends << '\n';
+ }
+
+ return true;
+}
+
+void cmDependsC::ReadCacheFile()
+{
+ if (this->CacheFileName.empty()) {
+ return;
+ }
+ cmsys::ifstream fin(this->CacheFileName.c_str());
+ if (!fin) {
+ return;
+ }
+
+ std::string line;
+ cmIncludeLines* cacheEntry = nullptr;
+ bool haveFileName = false;
+
+ cmFileTime cacheFileTime;
+ bool const cacheFileTimeGood = cacheFileTime.Load(this->CacheFileName);
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (line.empty()) {
+ cacheEntry = nullptr;
+ haveFileName = false;
+ continue;
+ }
+ // the first line after an empty line is the name of the parsed file
+ if (!haveFileName) {
+ haveFileName = true;
+
+ cmFileTime fileTime;
+ bool const res = cacheFileTimeGood && fileTime.Load(line);
+ bool const newer = res && cacheFileTime.Newer(fileTime);
+
+ if (res && newer) // cache is newer than the parsed file
+ {
+ cacheEntry = &this->FileCache[line];
+ }
+ // file doesn't exist, check that the regular expressions
+ // haven't changed
+ else if (!res) {
+ if (cmHasLiteralPrefix(line, INCLUDE_REGEX_LINE_MARKER)) {
+ if (line != this->IncludeRegexLineString) {
+ return;
+ }
+ } else if (cmHasLiteralPrefix(line, INCLUDE_REGEX_SCAN_MARKER)) {
+ if (line != this->IncludeRegexScanString) {
+ return;
+ }
+ } else if (cmHasLiteralPrefix(line, INCLUDE_REGEX_COMPLAIN_MARKER)) {
+ if (line != this->IncludeRegexComplainString) {
+ return;
+ }
+ } else if (cmHasLiteralPrefix(line, INCLUDE_REGEX_TRANSFORM_MARKER)) {
+ if (line != this->IncludeRegexTransformString) {
+ return;
+ }
+ }
+ }
+ } else if (cacheEntry != nullptr) {
+ UnscannedEntry entry;
+ entry.FileName = line;
+ if (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (line != "-") {
+ entry.QuotedLocation = line;
+ }
+ cacheEntry->UnscannedEntries.push_back(std::move(entry));
+ }
+ }
+ }
+}
+
+void cmDependsC::WriteCacheFile() const
+{
+ if (this->CacheFileName.empty()) {
+ return;
+ }
+ cmsys::ofstream cacheOut(this->CacheFileName.c_str());
+ if (!cacheOut) {
+ return;
+ }
+
+ cacheOut << this->IncludeRegexLineString << "\n\n";
+ cacheOut << this->IncludeRegexScanString << "\n\n";
+ cacheOut << this->IncludeRegexComplainString << "\n\n";
+ cacheOut << this->IncludeRegexTransformString << "\n\n";
+
+ for (auto const& fileIt : this->FileCache) {
+ if (fileIt.second.Used) {
+ cacheOut << fileIt.first << '\n';
+
+ for (UnscannedEntry const& inc : fileIt.second.UnscannedEntries) {
+ cacheOut << inc.FileName << '\n';
+ if (inc.QuotedLocation.empty()) {
+ cacheOut << '-' << '\n';
+ } else {
+ cacheOut << inc.QuotedLocation << '\n';
+ }
+ }
+ cacheOut << '\n';
+ }
+ }
+}
+
+void cmDependsC::Scan(std::istream& is, const std::string& directory,
+ const std::string& fullName)
+{
+ cmIncludeLines& newCacheEntry = this->FileCache[fullName];
+ newCacheEntry.Used = true;
+
+ // Read one line at a time.
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(is, line)) {
+ // Transform the line content first.
+ if (!this->TransformRules.empty()) {
+ this->TransformLine(line);
+ }
+
+ // Match include directives.
+ if (this->IncludeRegexLine.find(line)) {
+ // Get the file being included.
+ UnscannedEntry entry;
+ entry.FileName = this->IncludeRegexLine.match(2);
+ cmSystemTools::ConvertToUnixSlashes(entry.FileName);
+ if (this->IncludeRegexLine.match(3) == "\"" &&
+ !cmSystemTools::FileIsFullPath(entry.FileName)) {
+ // This was a double-quoted include with a relative path. We
+ // must check for the file in the directory containing the
+ // file we are scanning.
+ entry.QuotedLocation =
+ cmSystemTools::CollapseFullPath(entry.FileName, directory);
+ }
+
+ // Queue the file if it has not yet been encountered and it
+ // matches the regular expression for recursive scanning. Note
+ // that this check does not account for the possibility of two
+ // headers with the same name in different directories when one
+ // is included by double-quotes and the other by angle brackets.
+ // It also does not work properly if two header files with the same
+ // name exist in different directories, and both are included from a
+ // file their own directory by simply using "filename.h" (#12619)
+ // This kind of problem will be fixed when a more
+ // preprocessor-like implementation of this scanner is created.
+ if (this->IncludeRegexScan.find(entry.FileName)) {
+ newCacheEntry.UnscannedEntries.push_back(entry);
+ if (this->Encountered.find(entry.FileName) ==
+ this->Encountered.end()) {
+ this->Encountered.insert(entry.FileName);
+ this->Unscanned.push(entry);
+ }
+ }
+ }
+ }
+}
+
+void cmDependsC::SetupTransforms()
+{
+ // Get the transformation rules.
+ std::vector<std::string> transformRules;
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ mf->GetDefExpandList("CMAKE_INCLUDE_TRANSFORMS", transformRules, true);
+ for (std::string const& tr : transformRules) {
+ this->ParseTransform(tr);
+ }
+
+ this->IncludeRegexTransformString = INCLUDE_REGEX_TRANSFORM_MARKER;
+ if (!this->TransformRules.empty()) {
+ // Construct the regular expression to match lines to be
+ // transformed.
+ std::string xform = "^([ \t]*[#%][ \t]*(include|import)[ \t]*)(";
+ const char* sep = "";
+ for (auto const& tr : this->TransformRules) {
+ xform += sep;
+ xform += tr.first;
+ sep = "|";
+ }
+ xform += ")[ \t]*\\(([^),]*)\\)";
+ this->IncludeRegexTransform.compile(xform);
+
+ // Build a string that encodes all transformation rules and will
+ // change when rules are changed.
+ this->IncludeRegexTransformString += xform;
+ for (auto const& tr : this->TransformRules) {
+ this->IncludeRegexTransformString += " ";
+ this->IncludeRegexTransformString += tr.first;
+ this->IncludeRegexTransformString += "(%)=";
+ this->IncludeRegexTransformString += tr.second;
+ }
+ }
+}
+
+void cmDependsC::ParseTransform(std::string const& xform)
+{
+ // A transform rule is of the form SOME_MACRO(%)=value-with-%
+ // We can simply separate with "(%)=".
+ std::string::size_type pos = xform.find("(%)=");
+ if (pos == std::string::npos || pos == 0) {
+ return;
+ }
+ std::string name = xform.substr(0, pos);
+ std::string value = xform.substr(pos + 4);
+ this->TransformRules[name] = value;
+}
+
+void cmDependsC::TransformLine(std::string& line)
+{
+ // Check for a transform rule match. Return if none.
+ if (!this->IncludeRegexTransform.find(line)) {
+ return;
+ }
+ auto tri = this->TransformRules.find(this->IncludeRegexTransform.match(3));
+ if (tri == this->TransformRules.end()) {
+ return;
+ }
+
+ // Construct the transformed line.
+ std::string newline = this->IncludeRegexTransform.match(1);
+ std::string arg = this->IncludeRegexTransform.match(4);
+ for (char c : tri->second) {
+ if (c == '%') {
+ newline += arg;
+ } else {
+ newline += c;
+ }
+ }
+
+ // Return the transformed line.
+ line = newline;
+}
diff --git a/Source/cmDependsC.h b/Source/cmDependsC.h
new file mode 100644
index 0000000..c79da1a
--- /dev/null
+++ b/Source/cmDependsC.h
@@ -0,0 +1,94 @@
+/* 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 <iosfwd>
+#include <map>
+#include <queue>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmDepends.h"
+
+class cmLocalUnixMakefileGenerator3;
+
+/** \class cmDependsC
+ * \brief Dependency scanner for C and C++ object files.
+ */
+class cmDependsC : public cmDepends
+{
+public:
+ /** Checking instances need to know the build directory name and the
+ relative path from the build directory to the target file. */
+ cmDependsC();
+ cmDependsC(cmLocalUnixMakefileGenerator3* lg, const std::string& targetDir,
+ const std::string& lang, const DependencyMap* validDeps);
+
+ /** Virtual destructor to cleanup subclasses properly. */
+ ~cmDependsC() override;
+
+ cmDependsC(cmDependsC const&) = delete;
+ cmDependsC& operator=(cmDependsC const&) = delete;
+
+protected:
+ // Implement writing/checking methods required by superclass.
+ bool WriteDependencies(const std::set<std::string>& sources,
+ const std::string& obj, std::ostream& makeDepends,
+ std::ostream& internalDepends) override;
+
+ // Method to scan a single file.
+ void Scan(std::istream& is, const std::string& directory,
+ const std::string& fullName);
+
+ // Regular expression to identify C preprocessor include directives.
+ cmsys::RegularExpression IncludeRegexLine;
+
+ // Regular expressions to choose which include files to scan
+ // recursively and which to complain about not finding.
+ cmsys::RegularExpression IncludeRegexScan;
+ cmsys::RegularExpression IncludeRegexComplain;
+ std::string IncludeRegexLineString;
+ std::string IncludeRegexScanString;
+ std::string IncludeRegexComplainString;
+
+ // Regex to transform #include lines.
+ std::string IncludeRegexTransformString;
+ cmsys::RegularExpression IncludeRegexTransform;
+ using TransformRulesType = std::map<std::string, std::string>;
+ TransformRulesType TransformRules;
+ void SetupTransforms();
+ void ParseTransform(std::string const& xform);
+ void TransformLine(std::string& line);
+
+public:
+ // Data structures for dependency graph walk.
+ struct UnscannedEntry
+ {
+ std::string FileName;
+ std::string QuotedLocation;
+ };
+
+ struct cmIncludeLines
+ {
+ std::vector<UnscannedEntry> UnscannedEntries;
+ bool Used = false;
+ };
+
+protected:
+ const DependencyMap* ValidDeps = nullptr;
+ std::set<std::string> Encountered;
+ std::queue<UnscannedEntry> Unscanned;
+
+ std::map<std::string, cmIncludeLines> FileCache;
+ std::map<std::string, std::string> HeaderLocationCache;
+
+ std::string CacheFileName;
+
+ void WriteCacheFile() const;
+ void ReadCacheFile();
+};
diff --git a/Source/cmDependsCompiler.cxx b/Source/cmDependsCompiler.cxx
new file mode 100644
index 0000000..2b48df9
--- /dev/null
+++ b/Source/cmDependsCompiler.cxx
@@ -0,0 +1,252 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmDependsCompiler.h"
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <string>
+#include <unordered_set>
+#include <utility>
+
+#include <cm/optional>
+#include <cm/string_view>
+#include <cm/vector>
+#include <cmext/string_view>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmFileTime.h"
+#include "cmGccDepfileReader.h"
+#include "cmGccDepfileReaderTypes.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+bool cmDependsCompiler::CheckDependencies(
+ const std::string& internalDepFile, const std::vector<std::string>& depFiles,
+ cmDepends::DependencyMap& dependencies,
+ const std::function<bool(const std::string&)>& isValidPath)
+{
+ bool status = true;
+ bool forceReadDeps = true;
+
+ cmFileTime internalDepFileTime;
+ // read cached dependencies stored in internal file
+ if (cmSystemTools::FileExists(internalDepFile)) {
+ internalDepFileTime.Load(internalDepFile);
+ forceReadDeps = false;
+
+ // read current dependencies
+ cmsys::ifstream fin(internalDepFile.c_str());
+ if (fin) {
+ std::string line;
+ std::string depender;
+ std::vector<std::string>* currentDependencies = nullptr;
+ while (std::getline(fin, line)) {
+ if (line.empty() || line.front() == '#') {
+ continue;
+ }
+ // Drop carriage return character at the end
+ if (line.back() == '\r') {
+ line.pop_back();
+ if (line.empty()) {
+ continue;
+ }
+ }
+ // Check if this a depender line
+ if (line.front() != ' ') {
+ depender = std::move(line);
+ currentDependencies = &dependencies[depender];
+ continue;
+ }
+ // This is a dependee line
+ if (currentDependencies != nullptr) {
+ currentDependencies->emplace_back(line.substr(1));
+ }
+ }
+ fin.close();
+ }
+ }
+
+ // Now, update dependencies map with all new compiler generated
+ // dependencies files
+ cmFileTime depFileTime;
+ for (auto dep = depFiles.begin(); dep != depFiles.end(); dep++) {
+ const auto& source = *dep++;
+ const auto& target = *dep++;
+ const auto& format = *dep++;
+ const auto& depFile = *dep;
+
+ if (!cmSystemTools::FileExists(depFile)) {
+ continue;
+ }
+
+ if (!forceReadDeps) {
+ depFileTime.Load(depFile);
+ }
+ if (forceReadDeps || depFileTime.Compare(internalDepFileTime) >= 0) {
+ status = false;
+ if (this->Verbose) {
+ cmSystemTools::Stdout(cmStrCat("Dependencies file \"", depFile,
+ "\" is newer than depends file \"",
+ internalDepFile, "\".\n"));
+ }
+
+ std::vector<std::string> depends;
+ if (format == "custom"_s) {
+ auto deps = cmReadGccDepfile(
+ depFile.c_str(), this->LocalGenerator->GetCurrentBinaryDirectory());
+ if (!deps) {
+ continue;
+ }
+
+ for (auto& entry : *deps) {
+ depends = std::move(entry.paths);
+ if (isValidPath) {
+ cm::erase_if(depends, isValidPath);
+ }
+ // copy depends for each target, except first one, which can be
+ // moved
+ for (auto index = entry.rules.size() - 1; index > 0; --index) {
+ dependencies[entry.rules[index]] = depends;
+ }
+ dependencies[entry.rules.front()] = std::move(depends);
+ }
+ } else {
+ if (format == "msvc"_s) {
+ cmsys::ifstream fin(depFile.c_str());
+ if (!fin) {
+ continue;
+ }
+
+ std::string line;
+ if (!isValidPath) {
+ // insert source as first dependency
+ depends.push_back(source);
+ }
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ depends.emplace_back(std::move(line));
+ }
+ } else if (format == "gcc"_s) {
+ auto deps = cmReadGccDepfile(depFile.c_str());
+ if (!deps) {
+ continue;
+ }
+
+ // dependencies generated by the compiler contains only one target
+ depends = std::move(deps->front().paths);
+ if (depends.empty()) {
+ // unexpectedly empty, ignore it and continue
+ continue;
+ }
+
+ // depending of the effective format of the dependencies file
+ // generated by the compiler, the target can be wrongly identified
+ // as a dependency so remove it from the list
+ if (depends.front() == target) {
+ depends.erase(depends.begin());
+ }
+
+ // ensure source file is the first dependency
+ if (depends.front() != source) {
+ cm::erase(depends, source);
+ if (!isValidPath) {
+ depends.insert(depends.begin(), source);
+ }
+ } else if (isValidPath) {
+ // remove first dependency because it must not be filtered out
+ depends.erase(depends.begin());
+ }
+ } else {
+ // unknown format, ignore it
+ continue;
+ }
+
+ if (isValidPath) {
+ cm::erase_if(depends, isValidPath);
+ // insert source as first dependency
+ depends.insert(depends.begin(), source);
+ }
+
+ dependencies[target] = std::move(depends);
+ }
+ }
+ }
+
+ return status;
+}
+
+void cmDependsCompiler::WriteDependencies(
+ const cmDepends::DependencyMap& dependencies, std::ostream& makeDepends,
+ std::ostream& internalDepends)
+{
+ // dependencies file consumed by make tool
+ const auto& lineContinue = static_cast<cmGlobalUnixMakefileGenerator3*>(
+ this->LocalGenerator->GetGlobalGenerator())
+ ->LineContinueDirective;
+ bool supportLongLineDepend = static_cast<cmGlobalUnixMakefileGenerator3*>(
+ this->LocalGenerator->GetGlobalGenerator())
+ ->SupportsLongLineDependencies();
+ const auto& binDir = this->LocalGenerator->GetBinaryDirectory();
+ cmDepends::DependencyMap makeDependencies(dependencies);
+ std::unordered_set<cm::string_view> phonyTargets;
+
+ // external dependencies file
+ for (auto& node : makeDependencies) {
+ auto target = this->LocalGenerator->ConvertToMakefilePath(
+ this->LocalGenerator->MaybeConvertToRelativePath(binDir, node.first));
+ auto& deps = node.second;
+ std::transform(
+ deps.cbegin(), deps.cend(), deps.begin(),
+ [this, &binDir](const std::string& dep) {
+ return this->LocalGenerator->ConvertToMakefilePath(
+ this->LocalGenerator->MaybeConvertToRelativePath(binDir, dep));
+ });
+
+ bool first_dep = true;
+ if (supportLongLineDepend) {
+ makeDepends << target << ": ";
+ }
+ for (const auto& dep : deps) {
+ if (supportLongLineDepend) {
+ if (first_dep) {
+ first_dep = false;
+ makeDepends << dep;
+ } else {
+ makeDepends << ' ' << lineContinue << " " << dep;
+ }
+ } else {
+ makeDepends << target << ": " << dep << std::endl;
+ }
+
+ phonyTargets.emplace(dep.data(), dep.length());
+ }
+ makeDepends << std::endl << std::endl;
+ }
+
+ // add phony targets
+ for (const auto& target : phonyTargets) {
+ makeDepends << std::endl << target << ':' << std::endl;
+ }
+
+ // internal dependencies file
+ for (const auto& node : dependencies) {
+ internalDepends << node.first << std::endl;
+ for (const auto& dep : node.second) {
+ internalDepends << ' ' << dep << std::endl;
+ }
+ internalDepends << std::endl;
+ }
+}
+
+void cmDependsCompiler::ClearDependencies(
+ const std::vector<std::string>& depFiles)
+{
+ for (auto dep = depFiles.begin(); dep != depFiles.end(); dep++) {
+ dep += 3;
+ cmSystemTools::RemoveFile(*dep);
+ }
+}
diff --git a/Source/cmDependsCompiler.h b/Source/cmDependsCompiler.h
new file mode 100644
index 0000000..838156d
--- /dev/null
+++ b/Source/cmDependsCompiler.h
@@ -0,0 +1,60 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <functional>
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmDepends.h"
+
+class cmLocalUnixMakefileGenerator3;
+
+/** \class cmDepends
+ * \brief Dependencies files manager.
+ *
+ * This class is responsible for maintaining a compiler_depends.make file in
+ * the build tree corresponding to an object file.
+ */
+class cmDependsCompiler
+{
+public:
+ cmDependsCompiler() = default;
+ ~cmDependsCompiler() = default;
+
+ /** should this be verbose in its output */
+ void SetVerbose(bool verb) { this->Verbose = verb; }
+
+ /** Set the local generator for the directory in which we are
+ scanning dependencies. This is not a full local generator; it
+ has been setup to do relative path conversions for the current
+ directory. */
+ void SetLocalGenerator(cmLocalUnixMakefileGenerator3* lg)
+ {
+ this->LocalGenerator = lg;
+ }
+
+ /** Read dependencies for the target file. Return true if
+ dependencies didn't changed and false if not.
+ Up-to-date Dependencies will be stored in deps. */
+ bool CheckDependencies(
+ const std::string& internalDepFile,
+ const std::vector<std::string>& depFiles,
+ cmDepends::DependencyMap& dependencies,
+ const std::function<bool(const std::string&)>& isValidPath);
+
+ /** Write dependencies for the target file. */
+ void WriteDependencies(const cmDepends::DependencyMap& dependencies,
+ std::ostream& makeDepends,
+ std::ostream& internalDepends);
+
+ /** Clear dependencies for the target so they will be regenerated. */
+ void ClearDependencies(const std::vector<std::string>& depFiles);
+
+private:
+ bool Verbose = false;
+ cmLocalUnixMakefileGenerator3* LocalGenerator = nullptr;
+};
diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx
new file mode 100644
index 0000000..1a06f31
--- /dev/null
+++ b/Source/cmDependsFortran.cxx
@@ -0,0 +1,693 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmDependsFortran.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <iostream>
+#include <map>
+#include <utility>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmFortranParser.h" /* Interface to parser object. */
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmProperty.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+// TODO: Test compiler for the case of the mod file. Some always
+// use lower case and some always use upper case. I do not know if any
+// use the case from the source code.
+
+static void cmFortranModuleAppendUpperLower(std::string const& mod,
+ std::string& mod_upper,
+ std::string& mod_lower)
+{
+ std::string::size_type ext_len = 0;
+ if (cmHasLiteralSuffix(mod, ".mod") || cmHasLiteralSuffix(mod, ".sub")) {
+ ext_len = 4;
+ } else if (cmHasLiteralSuffix(mod, ".smod")) {
+ ext_len = 5;
+ }
+ std::string const& name = mod.substr(0, mod.size() - ext_len);
+ std::string const& ext = mod.substr(mod.size() - ext_len);
+ mod_upper += cmSystemTools::UpperCase(name) + ext;
+ mod_lower += mod;
+}
+
+class cmDependsFortranInternals
+{
+public:
+ // The set of modules provided by this target.
+ std::set<std::string> TargetProvides;
+
+ // Map modules required by this target to locations.
+ using TargetRequiresMap = std::map<std::string, std::string>;
+ TargetRequiresMap TargetRequires;
+
+ // Information about each object file.
+ using ObjectInfoMap = std::map<std::string, cmFortranSourceInfo>;
+ ObjectInfoMap ObjectInfo;
+
+ cmFortranSourceInfo& CreateObjectInfo(const std::string& obj,
+ const std::string& src)
+ {
+ auto i = this->ObjectInfo.find(obj);
+ if (i == this->ObjectInfo.end()) {
+ std::map<std::string, cmFortranSourceInfo>::value_type entry(
+ obj, cmFortranSourceInfo());
+ i = this->ObjectInfo.insert(entry).first;
+ i->second.Source = src;
+ }
+ return i->second;
+ }
+};
+
+cmDependsFortran::cmDependsFortran() = default;
+
+cmDependsFortran::cmDependsFortran(cmLocalUnixMakefileGenerator3* lg)
+ : cmDepends(lg)
+ , Internal(new cmDependsFortranInternals)
+{
+ // Configure the include file search path.
+ this->SetIncludePathFromLanguage("Fortran");
+
+ // Get the list of definitions.
+ std::vector<std::string> definitions;
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ mf->GetDefExpandList("CMAKE_TARGET_DEFINITIONS_Fortran", definitions);
+
+ // translate i.e. FOO=BAR to FOO and add it to the list of defined
+ // preprocessor symbols
+ for (std::string def : definitions) {
+ std::string::size_type assignment = def.find('=');
+ if (assignment != std::string::npos) {
+ def = def.substr(0, assignment);
+ }
+ this->PPDefinitions.insert(def);
+ }
+
+ this->CompilerId = mf->GetSafeDefinition("CMAKE_Fortran_COMPILER_ID");
+ this->SModSep = mf->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP");
+ this->SModExt = mf->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT");
+}
+
+cmDependsFortran::~cmDependsFortran() = default;
+
+bool cmDependsFortran::WriteDependencies(const std::set<std::string>& sources,
+ const std::string& obj,
+ std::ostream& /*makeDepends*/,
+ std::ostream& /*internalDepends*/)
+{
+ // Make sure this is a scanning instance.
+ if (sources.empty() || sources.begin()->empty()) {
+ cmSystemTools::Error("Cannot scan dependencies without a source file.");
+ return false;
+ }
+ if (obj.empty()) {
+ cmSystemTools::Error("Cannot scan dependencies without an object file.");
+ return false;
+ }
+
+ cmFortranCompiler fc;
+ fc.Id = this->CompilerId;
+ fc.SModSep = this->SModSep;
+ fc.SModExt = this->SModExt;
+
+ bool okay = true;
+ for (std::string const& src : sources) {
+ // Get the information object for this source.
+ cmFortranSourceInfo& info = this->Internal->CreateObjectInfo(obj, src);
+
+ // Create the parser object. The constructor takes info by reference,
+ // so we may look into the resulting objects later.
+ cmFortranParser parser(fc, this->IncludePath, this->PPDefinitions, info);
+
+ // Push on the starting file.
+ cmFortranParser_FilePush(&parser, src.c_str());
+
+ // Parse the translation unit.
+ if (cmFortran_yyparse(parser.Scanner) != 0) {
+ // Failed to parse the file. Report failure to write dependencies.
+ okay = false;
+ /* clang-format off */
+ std::cerr <<
+ "warning: failed to parse dependencies from Fortran source "
+ "'" << src << "': " << parser.Error << std::endl
+ ;
+ /* clang-format on */
+ }
+ }
+ return okay;
+}
+
+bool cmDependsFortran::Finalize(std::ostream& makeDepends,
+ std::ostream& internalDepends)
+{
+ // Prepare the module search process.
+ this->LocateModules();
+
+ // Get the directory in which stamp files will be stored.
+ const std::string& stamp_dir = this->TargetDirectory;
+
+ // Get the directory in which module files will be created.
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ std::string mod_dir =
+ mf->GetSafeDefinition("CMAKE_Fortran_TARGET_MODULE_DIR");
+ if (mod_dir.empty()) {
+ mod_dir = this->LocalGenerator->GetCurrentBinaryDirectory();
+ }
+
+ // Actually write dependencies to the streams.
+ using ObjectInfoMap = cmDependsFortranInternals::ObjectInfoMap;
+ ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
+ for (auto const& i : objInfo) {
+ if (!this->WriteDependenciesReal(i.first, i.second, mod_dir, stamp_dir,
+ makeDepends, internalDepends)) {
+ return false;
+ }
+ }
+
+ // Store the list of modules provided by this target.
+ std::string fiName = cmStrCat(this->TargetDirectory, "/fortran.internal");
+ cmGeneratedFileStream fiStream(fiName);
+ fiStream << "# The fortran modules provided by this target.\n";
+ fiStream << "provides\n";
+ std::set<std::string> const& provides = this->Internal->TargetProvides;
+ for (std::string const& i : provides) {
+ fiStream << ' ' << i << '\n';
+ }
+
+ // Create a script to clean the modules.
+ if (!provides.empty()) {
+ std::string fcName =
+ cmStrCat(this->TargetDirectory, "/cmake_clean_Fortran.cmake");
+ cmGeneratedFileStream fcStream(fcName);
+ fcStream << "# Remove fortran modules provided by this target.\n";
+ fcStream << "FILE(REMOVE";
+ std::string currentBinDir =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+ for (std::string const& i : provides) {
+ std::string mod_upper = cmStrCat(mod_dir, '/');
+ std::string mod_lower = cmStrCat(mod_dir, '/');
+ cmFortranModuleAppendUpperLower(i, mod_upper, mod_lower);
+ std::string stamp = cmStrCat(stamp_dir, '/', i, ".stamp");
+ fcStream << "\n"
+ " \""
+ << this->MaybeConvertToRelativePath(currentBinDir, mod_lower)
+ << "\"\n"
+ " \""
+ << this->MaybeConvertToRelativePath(currentBinDir, mod_upper)
+ << "\"\n"
+ " \""
+ << this->MaybeConvertToRelativePath(currentBinDir, stamp)
+ << "\"\n";
+ }
+ fcStream << " )\n";
+ }
+ return true;
+}
+
+void cmDependsFortran::LocateModules()
+{
+ // Collect the set of modules provided and required by all sources.
+ using ObjectInfoMap = cmDependsFortranInternals::ObjectInfoMap;
+ ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
+ for (auto const& infoI : objInfo) {
+ cmFortranSourceInfo const& info = infoI.second;
+ // Include this module in the set provided by this target.
+ this->Internal->TargetProvides.insert(info.Provides.begin(),
+ info.Provides.end());
+
+ for (std::string const& r : info.Requires) {
+ this->Internal->TargetRequires[r].clear();
+ }
+ }
+
+ // Short-circuit for simple targets.
+ if (this->Internal->TargetRequires.empty()) {
+ return;
+ }
+
+ // Match modules provided by this target to those it requires.
+ this->MatchLocalModules();
+
+ // Load information about other targets.
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ std::vector<std::string> infoFiles;
+ mf->GetDefExpandList("CMAKE_TARGET_LINKED_INFO_FILES", infoFiles);
+ for (std::string const& i : infoFiles) {
+ std::string targetDir = cmSystemTools::GetFilenamePath(i);
+ std::string fname = targetDir + "/fortran.internal";
+ cmsys::ifstream fin(fname.c_str());
+ if (fin) {
+ this->MatchRemoteModules(fin, targetDir);
+ }
+ }
+}
+
+void cmDependsFortran::MatchLocalModules()
+{
+ std::string const& stampDir = this->TargetDirectory;
+ std::set<std::string> const& provides = this->Internal->TargetProvides;
+ for (std::string const& i : provides) {
+ this->ConsiderModule(i, stampDir);
+ }
+}
+
+void cmDependsFortran::MatchRemoteModules(std::istream& fin,
+ const std::string& stampDir)
+{
+ std::string line;
+ bool doing_provides = false;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ // Ignore comments and empty lines.
+ if (line.empty() || line[0] == '#' || line[0] == '\r') {
+ continue;
+ }
+
+ if (line[0] == ' ') {
+ if (doing_provides) {
+ std::string mod = line;
+ if (!cmHasLiteralSuffix(mod, ".mod") &&
+ !cmHasLiteralSuffix(mod, ".smod") &&
+ !cmHasLiteralSuffix(mod, ".sub")) {
+ // Support fortran.internal files left by older versions of CMake.
+ // They do not include the ".mod" extension.
+ mod += ".mod";
+ }
+ this->ConsiderModule(mod.substr(1), stampDir);
+ }
+ } else if (line == "provides") {
+ doing_provides = true;
+ } else {
+ doing_provides = false;
+ }
+ }
+}
+
+void cmDependsFortran::ConsiderModule(const std::string& name,
+ const std::string& stampDir)
+{
+ // Locate each required module.
+ auto required = this->Internal->TargetRequires.find(name);
+ if (required != this->Internal->TargetRequires.end() &&
+ required->second.empty()) {
+ // The module is provided by a CMake target. It will have a stamp file.
+ std::string stampFile = cmStrCat(stampDir, '/', name, ".stamp");
+ required->second = stampFile;
+ }
+}
+
+bool cmDependsFortran::WriteDependenciesReal(std::string const& obj,
+ cmFortranSourceInfo const& info,
+ std::string const& mod_dir,
+ std::string const& stamp_dir,
+ std::ostream& makeDepends,
+ std::ostream& internalDepends)
+{
+ // Get the source file for this object.
+ std::string const& src = info.Source;
+
+ // Write the include dependencies to the output stream.
+ std::string binDir = this->LocalGenerator->GetBinaryDirectory();
+ std::string obj_i = this->MaybeConvertToRelativePath(binDir, obj);
+ std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i);
+ internalDepends << obj_i << "\n " << src << '\n';
+ if (!info.Includes.empty()) {
+ const auto& lineContinue = static_cast<cmGlobalUnixMakefileGenerator3*>(
+ this->LocalGenerator->GetGlobalGenerator())
+ ->LineContinueDirective;
+ bool supportLongLineDepend = static_cast<cmGlobalUnixMakefileGenerator3*>(
+ this->LocalGenerator->GetGlobalGenerator())
+ ->SupportsLongLineDependencies();
+ if (supportLongLineDepend) {
+ makeDepends << obj_m << ':';
+ }
+ for (std::string const& i : info.Includes) {
+ std::string dependee = cmSystemTools::ConvertToOutputPath(
+ this->MaybeConvertToRelativePath(binDir, i));
+ if (supportLongLineDepend) {
+ makeDepends << ' ' << lineContinue << ' ' << dependee;
+ } else {
+ makeDepends << obj_m << ": " << dependee << '\n';
+ }
+ internalDepends << ' ' << i << '\n';
+ }
+ makeDepends << '\n';
+ }
+
+ // Write module requirements to the output stream.
+ for (std::string const& i : info.Requires) {
+ // Require only modules not provided in the same source.
+ if (info.Provides.find(i) != info.Provides.cend()) {
+ continue;
+ }
+
+ // The object file should depend on timestamped files for the
+ // modules it uses.
+ auto required = this->Internal->TargetRequires.find(i);
+ if (required == this->Internal->TargetRequires.end()) {
+ abort();
+ }
+ if (!required->second.empty()) {
+ // This module is known. Depend on its timestamp file.
+ std::string stampFile = cmSystemTools::ConvertToOutputPath(
+ this->MaybeConvertToRelativePath(binDir, required->second));
+ makeDepends << obj_m << ": " << stampFile << '\n';
+ } else {
+ // This module is not known to CMake. Try to locate it where
+ // the compiler will and depend on that.
+ std::string module;
+ if (this->FindModule(i, module)) {
+ module = cmSystemTools::ConvertToOutputPath(
+ this->MaybeConvertToRelativePath(binDir, module));
+ makeDepends << obj_m << ": " << module << '\n';
+ }
+ }
+ }
+
+ // If any modules are provided then they must be converted to stamp files.
+ if (!info.Provides.empty()) {
+ // Create a target to copy the module after the object file
+ // changes.
+ for (std::string const& i : info.Provides) {
+ // Include this module in the set provided by this target.
+ this->Internal->TargetProvides.insert(i);
+
+ // Always use lower case for the mod stamp file name. The
+ // cmake_copy_f90_mod will call back to this class, which will
+ // try various cases for the real mod file name.
+ std::string modFile = cmStrCat(mod_dir, '/', i);
+ modFile = this->LocalGenerator->ConvertToOutputFormat(
+ this->MaybeConvertToRelativePath(binDir, modFile),
+ cmOutputConverter::SHELL);
+ std::string stampFile = cmStrCat(stamp_dir, '/', i, ".stamp");
+ stampFile = this->MaybeConvertToRelativePath(binDir, stampFile);
+ std::string const stampFileForShell =
+ this->LocalGenerator->ConvertToOutputFormat(stampFile,
+ cmOutputConverter::SHELL);
+ std::string const stampFileForMake =
+ cmSystemTools::ConvertToOutputPath(stampFile);
+
+ makeDepends << obj_m << ".provides.build"
+ << ": " << stampFileForMake << '\n';
+ // Note that when cmake_copy_f90_mod finds that a module file
+ // and the corresponding stamp file have no differences, the stamp
+ // file is not updated. In such case the stamp file will be always
+ // older than its prerequisite and trigger cmake_copy_f90_mod
+ // on each new build. This is expected behavior for incremental
+ // builds and can not be changed without preforming recursive make
+ // calls that would considerably slow down the building process.
+ makeDepends << stampFileForMake << ": " << obj_m << '\n';
+ makeDepends << "\t$(CMAKE_COMMAND) -E cmake_copy_f90_mod " << modFile
+ << ' ' << stampFileForShell;
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ cmProp cid = mf->GetDefinition("CMAKE_Fortran_COMPILER_ID");
+ if (cmNonempty(cid)) {
+ makeDepends << ' ' << *cid;
+ }
+ makeDepends << '\n';
+ }
+ makeDepends << obj_m << ".provides.build:\n";
+ // After copying the modules update the timestamp file.
+ makeDepends << "\t$(CMAKE_COMMAND) -E touch " << obj_m
+ << ".provides.build\n";
+
+ // Make sure the module timestamp rule is evaluated by the time
+ // the target finishes building.
+ std::string driver = cmStrCat(this->TargetDirectory, "/build");
+ driver = cmSystemTools::ConvertToOutputPath(
+ this->MaybeConvertToRelativePath(binDir, driver));
+ makeDepends << driver << ": " << obj_m << ".provides.build\n";
+ }
+
+ return true;
+}
+
+bool cmDependsFortran::FindModule(std::string const& name, std::string& module)
+{
+ // Construct possible names for the module file.
+ std::string mod_upper;
+ std::string mod_lower;
+ cmFortranModuleAppendUpperLower(name, mod_upper, mod_lower);
+
+ // Search the include path for the module.
+ std::string fullName;
+ for (std::string const& ip : this->IncludePath) {
+ // Try the lower-case name.
+ fullName = cmStrCat(ip, '/', mod_lower);
+ if (cmSystemTools::FileExists(fullName, true)) {
+ module = fullName;
+ return true;
+ }
+
+ // Try the upper-case name.
+ fullName = cmStrCat(ip, '/', mod_upper);
+ if (cmSystemTools::FileExists(fullName, true)) {
+ module = fullName;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmDependsFortran::CopyModule(const std::vector<std::string>& args)
+{
+ // Implements
+ //
+ // $(CMAKE_COMMAND) -E cmake_copy_f90_mod input.mod output.mod.stamp
+ // [compiler-id]
+ //
+ // Note that the case of the .mod file depends on the compiler. In
+ // the future this copy could also account for the fact that some
+ // compilers include a timestamp in the .mod file so it changes even
+ // when the interface described in the module does not.
+
+ std::string mod = args[2];
+ std::string stamp = args[3];
+ std::string compilerId;
+ if (args.size() >= 5) {
+ compilerId = args[4];
+ }
+ if (!cmHasLiteralSuffix(mod, ".mod") && !cmHasLiteralSuffix(mod, ".smod") &&
+ !cmHasLiteralSuffix(mod, ".sub")) {
+ // Support depend.make files left by older versions of CMake.
+ // They do not include the ".mod" extension.
+ mod += ".mod";
+ }
+ std::string mod_dir = cmSystemTools::GetFilenamePath(mod);
+ if (!mod_dir.empty()) {
+ mod_dir += "/";
+ }
+ std::string mod_upper = mod_dir;
+ std::string mod_lower = mod_dir;
+ cmFortranModuleAppendUpperLower(cmSystemTools::GetFilenameName(mod),
+ mod_upper, mod_lower);
+ if (cmSystemTools::FileExists(mod_upper, true)) {
+ if (cmDependsFortran::ModulesDiffer(mod_upper, stamp, compilerId)) {
+ if (!cmSystemTools::CopyFileAlways(mod_upper, stamp)) {
+ std::cerr << "Error copying Fortran module from \"" << mod_upper
+ << "\" to \"" << stamp << "\".\n";
+ return false;
+ }
+ }
+ return true;
+ }
+ if (cmSystemTools::FileExists(mod_lower, true)) {
+ if (cmDependsFortran::ModulesDiffer(mod_lower, stamp, compilerId)) {
+ if (!cmSystemTools::CopyFileAlways(mod_lower, stamp)) {
+ std::cerr << "Error copying Fortran module from \"" << mod_lower
+ << "\" to \"" << stamp << "\".\n";
+ return false;
+ }
+ }
+ return true;
+ }
+
+ std::cerr << "Error copying Fortran module \"" << args[2] << "\". Tried \""
+ << mod_upper << "\" and \"" << mod_lower << "\".\n";
+ return false;
+}
+
+// Helper function to look for a short sequence in a stream. If this
+// is later used for longer sequences it should be re-written using an
+// efficient string search algorithm such as Boyer-Moore.
+static bool cmFortranStreamContainsSequence(std::istream& ifs, const char* seq,
+ int len)
+{
+ assert(len > 0);
+
+ int cur = 0;
+ while (cur < len) {
+ // Get the next character.
+ int token = ifs.get();
+ if (!ifs) {
+ return false;
+ }
+
+ // Check the character.
+ if (token == static_cast<int>(seq[cur])) {
+ ++cur;
+ } else {
+ // Assume the sequence has no repeating subsequence.
+ cur = 0;
+ }
+ }
+
+ // The entire sequence was matched.
+ return true;
+}
+
+// Helper function to compare the remaining content in two streams.
+static bool cmFortranStreamsDiffer(std::istream& ifs1, std::istream& ifs2)
+{
+ // Compare the remaining content.
+ for (;;) {
+ int ifs1_c = ifs1.get();
+ int ifs2_c = ifs2.get();
+ if (!ifs1 && !ifs2) {
+ // We have reached the end of both streams simultaneously.
+ // The streams are identical.
+ return false;
+ }
+
+ if (!ifs1 || !ifs2 || ifs1_c != ifs2_c) {
+ // We have reached the end of one stream before the other or
+ // found differing content. The streams are different.
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool cmDependsFortran::ModulesDiffer(const std::string& modFile,
+ const std::string& stampFile,
+ const std::string& compilerId)
+{
+ /*
+ gnu >= 4.9:
+ A mod file is an ascii file compressed with gzip.
+ Compiling twice produces identical modules.
+
+ gnu < 4.9:
+ A mod file is an ascii file.
+ <bar.mod>
+ FORTRAN module created from /path/to/foo.f90 on Sun Dec 30 22:47:58 2007
+ If you edit this, you'll get what you deserve.
+ ...
+ </bar.mod>
+ As you can see the first line contains the date.
+
+ intel:
+ A mod file is a binary file.
+ However, looking into both generated bar.mod files with a hex editor
+ shows that they differ only before a sequence linefeed-zero (0x0A 0x00)
+ which is located some bytes in front of the absolute path to the source
+ file.
+
+ sun:
+ A mod file is a binary file. Compiling twice produces identical modules.
+
+ others:
+ TODO ...
+ */
+
+ /* Compilers which do _not_ produce different mod content when the same
+ * source is compiled twice
+ * -SunPro
+ */
+ if (compilerId == "SunPro") {
+ return cmSystemTools::FilesDiffer(modFile, stampFile);
+ }
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+ cmsys::ifstream finModFile(modFile.c_str(), std::ios::in | std::ios::binary);
+ cmsys::ifstream finStampFile(stampFile.c_str(),
+ std::ios::in | std::ios::binary);
+#else
+ cmsys::ifstream finModFile(modFile.c_str());
+ cmsys::ifstream finStampFile(stampFile.c_str());
+#endif
+ if (!finModFile || !finStampFile) {
+ // At least one of the files does not exist. The modules differ.
+ return true;
+ }
+
+ /* Compilers which _do_ produce different mod content when the same
+ * source is compiled twice
+ * -GNU
+ * -Intel
+ *
+ * Eat the stream content until all recompile only related changes
+ * are left behind.
+ */
+ if (compilerId == "GNU") {
+ // GNU Fortran 4.9 and later compress .mod files with gzip
+ // but also do not include a date so we can fall through to
+ // compare them without skipping any prefix.
+ unsigned char hdr[2];
+ bool okay = !finModFile.read(reinterpret_cast<char*>(hdr), 2).fail();
+ finModFile.seekg(0);
+ if (!okay || hdr[0] != 0x1f || hdr[1] != 0x8b) {
+ const char seq[1] = { '\n' };
+ const int seqlen = 1;
+
+ if (!cmFortranStreamContainsSequence(finModFile, seq, seqlen)) {
+ // The module is of unexpected format. Assume it is different.
+ std::cerr << compilerId << " fortran module " << modFile
+ << " has unexpected format." << std::endl;
+ return true;
+ }
+
+ if (!cmFortranStreamContainsSequence(finStampFile, seq, seqlen)) {
+ // The stamp must differ if the sequence is not contained.
+ return true;
+ }
+ }
+ } else if (compilerId == "Intel") {
+ const char seq[2] = { '\n', '\0' };
+ const int seqlen = 2;
+
+ // Skip the leading byte which appears to be a version number.
+ // We do not need to check for an error because the sequence search
+ // below will fail in that case.
+ finModFile.get();
+ finStampFile.get();
+
+ if (!cmFortranStreamContainsSequence(finModFile, seq, seqlen)) {
+ // The module is of unexpected format. Assume it is different.
+ std::cerr << compilerId << " fortran module " << modFile
+ << " has unexpected format." << std::endl;
+ return true;
+ }
+
+ if (!cmFortranStreamContainsSequence(finStampFile, seq, seqlen)) {
+ // The stamp must differ if the sequence is not contained.
+ return true;
+ }
+ }
+
+ // Compare the remaining content. If no compiler id matched above,
+ // including the case none was given, this will compare the whole
+ // content.
+ return cmFortranStreamsDiffer(finModFile, finStampFile);
+}
+
+std::string cmDependsFortran::MaybeConvertToRelativePath(
+ std::string const& base, std::string const& path)
+{
+ if (!this->LocalGenerator->GetStateSnapshot().GetDirectory().ContainsBoth(
+ base, path)) {
+ return path;
+ }
+ return cmSystemTools::ForceToRelativePath(base, path);
+}
diff --git a/Source/cmDependsFortran.h b/Source/cmDependsFortran.h
new file mode 100644
index 0000000..e377a2c
--- /dev/null
+++ b/Source/cmDependsFortran.h
@@ -0,0 +1,92 @@
+/* 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 <iosfwd>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmDepends.h"
+
+class cmDependsFortranInternals;
+class cmFortranSourceInfo;
+class cmLocalUnixMakefileGenerator3;
+
+/** \class cmDependsFortran
+ * \brief Dependency scanner for Fortran object files.
+ */
+class cmDependsFortran : public cmDepends
+{
+public:
+ /** Checking instances need to know the build directory name and the
+ relative path from the build directory to the target file. */
+ cmDependsFortran();
+
+ /** Scanning need to know the build directory name, the relative
+ path from the build directory to the target file, the source
+ file from which to start scanning, the include file search
+ path, and the target directory. */
+ cmDependsFortran(cmLocalUnixMakefileGenerator3* lg);
+
+ /** Virtual destructor to cleanup subclasses properly. */
+ ~cmDependsFortran() override;
+
+ cmDependsFortran(cmDependsFortran const&) = delete;
+ cmDependsFortran& operator=(cmDependsFortran const&) = delete;
+
+ /** Callback from build system after a .mod file has been generated
+ by a Fortran90 compiler to copy the .mod file to the
+ corresponding stamp file. */
+ static bool CopyModule(const std::vector<std::string>& args);
+
+ /** Determine if a mod file and the corresponding mod.stamp file
+ are representing different module information. */
+ static bool ModulesDiffer(const std::string& modFile,
+ const std::string& stampFile,
+ const std::string& compilerId);
+
+protected:
+ // Finalize the dependency information for the target.
+ bool Finalize(std::ostream& makeDepends,
+ std::ostream& internalDepends) override;
+
+ // Find all the modules required by the target.
+ void LocateModules();
+ void MatchLocalModules();
+ void MatchRemoteModules(std::istream& fin, const std::string& stampDir);
+ void ConsiderModule(const std::string& name, const std::string& stampDir);
+ bool FindModule(std::string const& name, std::string& module);
+
+ // Implement writing/checking methods required by superclass.
+ bool WriteDependencies(const std::set<std::string>& sources,
+ const std::string& file, std::ostream& makeDepends,
+ std::ostream& internalDepends) override;
+
+ // Actually write the dependencies to the streams.
+ bool WriteDependenciesReal(std::string const& obj,
+ cmFortranSourceInfo const& info,
+ std::string const& mod_dir,
+ std::string const& stamp_dir,
+ std::ostream& makeDepends,
+ std::ostream& internalDepends);
+
+ // The source file from which to start scanning.
+ std::string SourceFile;
+
+ std::string CompilerId;
+ std::string SModSep;
+ std::string SModExt;
+
+ std::set<std::string> PPDefinitions;
+
+ // Internal implementation details.
+ std::unique_ptr<cmDependsFortranInternals> Internal;
+
+private:
+ std::string MaybeConvertToRelativePath(std::string const& base,
+ std::string const& path);
+};
diff --git a/Source/cmDependsJava.cxx b/Source/cmDependsJava.cxx
new file mode 100644
index 0000000..b17b2ba
--- /dev/null
+++ b/Source/cmDependsJava.cxx
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmDependsJava.h"
+
+#include "cmSystemTools.h"
+
+cmDependsJava::cmDependsJava() = default;
+
+cmDependsJava::~cmDependsJava() = default;
+
+bool cmDependsJava::WriteDependencies(const std::set<std::string>& sources,
+ const std::string& /*obj*/,
+ std::ostream& /*makeDepends*/,
+ std::ostream& /*internalDepends*/)
+{
+ // Make sure this is a scanning instance.
+ if (sources.empty() || sources.begin()->empty()) {
+ cmSystemTools::Error("Cannot scan dependencies without an source file.");
+ return false;
+ }
+
+ return true;
+}
+
+bool cmDependsJava::CheckDependencies(
+ std::istream& /*internalDepends*/,
+ const std::string& /*internalDependsFileName*/, DependencyMap& /*validDeps*/)
+{
+ return true;
+}
diff --git a/Source/cmDependsJava.h b/Source/cmDependsJava.h
new file mode 100644
index 0000000..1db7ce1
--- /dev/null
+++ b/Source/cmDependsJava.h
@@ -0,0 +1,37 @@
+/* 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 <iosfwd>
+#include <set>
+#include <string>
+
+#include "cmDepends.h"
+
+/** \class cmDependsJava
+ * \brief Dependency scanner for Java class files.
+ */
+class cmDependsJava : public cmDepends
+{
+public:
+ /** Checking instances need to know the build directory name and the
+ relative path from the build directory to the target file. */
+ cmDependsJava();
+
+ /** Virtual destructor to cleanup subclasses properly. */
+ ~cmDependsJava() override;
+
+ cmDependsJava(cmDependsJava const&) = delete;
+ cmDependsJava& operator=(cmDependsJava const&) = delete;
+
+protected:
+ // Implement writing/checking methods required by superclass.
+ bool WriteDependencies(const std::set<std::string>& sources,
+ const std::string& file, std::ostream& makeDepends,
+ std::ostream& internalDepends) override;
+ bool CheckDependencies(std::istream& internalDepends,
+ const std::string& internalDependsFileName,
+ DependencyMap& validDeps) override;
+};
diff --git a/Source/cmDependsJavaParserHelper.cxx b/Source/cmDependsJavaParserHelper.cxx
new file mode 100644
index 0000000..0c5d310
--- /dev/null
+++ b/Source/cmDependsJavaParserHelper.cxx
@@ -0,0 +1,335 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmDependsJavaParserHelper.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/string_view>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmDependsJavaLexer.h"
+#include "cmSystemTools.h"
+
+int cmDependsJava_yyparse(yyscan_t yyscanner);
+
+cmDependsJavaParserHelper::cmDependsJavaParserHelper()
+{
+ this->CurrentDepth = 0;
+
+ this->UnionsAvailable = 0;
+ this->LastClassId = 0;
+
+ CurrentClass tl;
+ tl.Name = "*";
+ this->ClassStack.push_back(std::move(tl));
+}
+
+cmDependsJavaParserHelper::~cmDependsJavaParserHelper()
+{
+ this->CleanupParser();
+}
+
+void cmDependsJavaParserHelper::CurrentClass::AddFileNamesForPrinting(
+ std::vector<std::string>* files, const char* prefix, const char* sep) const
+{
+ std::string rname;
+ if (prefix) {
+ rname += prefix;
+ rname += sep;
+ }
+ rname += this->Name;
+ files->push_back(rname);
+ for (CurrentClass const& nc : this->NestedClasses) {
+ nc.AddFileNamesForPrinting(files, rname.c_str(), sep);
+ }
+}
+
+void cmDependsJavaParserHelper::DeallocateParserType(char** pt)
+{
+ if (!pt) {
+ return;
+ }
+ if (!*pt) {
+ return;
+ }
+ *pt = nullptr;
+ this->UnionsAvailable--;
+}
+
+void cmDependsJavaParserHelper::AddClassFound(const char* sclass)
+{
+ if (!sclass) {
+ return;
+ }
+ for (std::string const& cf : this->ClassesFound) {
+ if (cf == sclass) {
+ return;
+ }
+ }
+ this->ClassesFound.emplace_back(sclass);
+}
+
+void cmDependsJavaParserHelper::AddPackagesImport(const char* sclass)
+{
+ for (std::string const& pi : this->PackagesImport) {
+ if (pi == sclass) {
+ return;
+ }
+ }
+ this->PackagesImport.emplace_back(sclass);
+}
+
+void cmDependsJavaParserHelper::SafePrintMissing(const char* str, int line,
+ int cnt)
+{
+ if (str) {
+ std::cout << line << " String " << cnt << " exists: ";
+ unsigned int cc;
+ for (cc = 0; cc < strlen(str); cc++) {
+ unsigned char ch = str[cc];
+ if (ch >= 32 && ch <= 126) {
+ std::cout << static_cast<char>(ch);
+ } else {
+ std::cout << "<" << static_cast<int>(ch) << ">";
+ break;
+ }
+ }
+ std::cout << "- " << strlen(str) << std::endl;
+ }
+}
+void cmDependsJavaParserHelper::Print(const char* place, const char* str) const
+{
+ if (this->Verbose) {
+ std::cout << "[" << place << "=" << str << "]" << std::endl;
+ }
+}
+
+void cmDependsJavaParserHelper::CombineUnions(char** out, const char* in1,
+ char** in2, const char* sep)
+{
+ size_t len = 1;
+ if (in1) {
+ len += strlen(in1);
+ }
+ if (*in2) {
+ len += strlen(*in2);
+ }
+ if (sep) {
+ len += strlen(sep);
+ }
+ *out = new char[len];
+ *out[0] = 0;
+ if (in1) {
+ strcat(*out, in1);
+ }
+ if (sep) {
+ strcat(*out, sep);
+ }
+ if (*in2) {
+ strcat(*out, *in2);
+ }
+ if (*in2) {
+ this->DeallocateParserType(in2);
+ }
+ this->UnionsAvailable++;
+}
+
+void cmDependsJavaParserHelper::CheckEmpty(
+ int line, int cnt, cmDependsJavaParserHelper::ParserType* pt)
+{
+ int cc;
+ int kk = -cnt + 1;
+ for (cc = 1; cc <= cnt; cc++) {
+ cmDependsJavaParserHelper::ParserType* cpt = pt + kk;
+ this->SafePrintMissing(cpt->str, line, cc);
+ kk++;
+ }
+}
+
+void cmDependsJavaParserHelper::PrepareElement(
+ cmDependsJavaParserHelper::ParserType* me)
+{
+ // Inititalize self
+ me->str = nullptr;
+}
+
+void cmDependsJavaParserHelper::AllocateParserType(
+ cmDependsJavaParserHelper::ParserType* pt, const char* str, int len)
+{
+ pt->str = nullptr;
+ if (len == 0) {
+ len = static_cast<int>(strlen(str));
+ }
+ if (len == 0) {
+ return;
+ }
+ this->UnionsAvailable++;
+ auto up = cm::make_unique<char[]>(len + 1);
+ pt->str = up.get();
+ strncpy(pt->str, str, len);
+ pt->str[len] = 0;
+ this->Allocates.push_back(std::move(up));
+}
+
+void cmDependsJavaParserHelper::StartClass(const char* cls)
+{
+ CurrentClass cl;
+ cl.Name = cls;
+ this->ClassStack.push_back(std::move(cl));
+
+ this->CurrentDepth++;
+}
+
+void cmDependsJavaParserHelper::EndClass()
+{
+ if (this->ClassStack.empty()) {
+ std::cerr << "Error when parsing. Current class is null" << std::endl;
+ abort();
+ }
+ if (this->ClassStack.size() <= 1) {
+ std::cerr << "Error when parsing. Parent class is null" << std::endl;
+ abort();
+ }
+ CurrentClass& current = this->ClassStack.back();
+ CurrentClass& parent = this->ClassStack[this->ClassStack.size() - 2];
+ this->CurrentDepth--;
+ parent.NestedClasses.push_back(current);
+ this->ClassStack.pop_back();
+}
+
+void cmDependsJavaParserHelper::PrintClasses()
+{
+ if (this->ClassStack.empty()) {
+ std::cerr << "Error when parsing. No classes on class stack" << std::endl;
+ abort();
+ }
+ for (std::string const& f : this->GetFilesProduced()) {
+ std::cout << " " << f << ".class" << std::endl;
+ }
+}
+
+std::vector<std::string> cmDependsJavaParserHelper::GetFilesProduced()
+{
+ std::vector<std::string> files;
+ CurrentClass const& toplevel = this->ClassStack.front();
+ for (CurrentClass const& nc : toplevel.NestedClasses) {
+ nc.AddFileNamesForPrinting(&files, nullptr, "$");
+ }
+ return files;
+}
+
+int cmDependsJavaParserHelper::ParseString(const char* str, int verb)
+{
+ if (!str) {
+ return 0;
+ }
+ this->Verbose = verb;
+ this->InputBuffer = str;
+ this->InputBufferPos = 0;
+ this->CurrentLine = 0;
+
+ yyscan_t yyscanner;
+ cmDependsJava_yylex_init(&yyscanner);
+ cmDependsJava_yyset_extra(this, yyscanner);
+ int res = cmDependsJava_yyparse(yyscanner);
+ cmDependsJava_yylex_destroy(yyscanner);
+ if (res != 0) {
+ std::cout << "JP_Parse returned: " << res << std::endl;
+ return 0;
+ }
+
+ if (verb) {
+ if (!this->CurrentPackage.empty()) {
+ std::cout << "Current package is: " << this->CurrentPackage << std::endl;
+ }
+ std::cout << "Imports packages:";
+ if (!this->PackagesImport.empty()) {
+ std::vector<std::string>::iterator it;
+ for (it = this->PackagesImport.begin(); it != this->PackagesImport.end();
+ ++it) {
+ std::cout << " " << *it;
+ }
+ }
+ std::cout << std::endl;
+ std::cout << "Depends on:";
+ if (!this->ClassesFound.empty()) {
+ for (std::string const& cf : this->ClassesFound) {
+ std::cout << " " << cf;
+ }
+ }
+ std::cout << std::endl;
+ std::cout << "Generated files:" << std::endl;
+ this->PrintClasses();
+ if (this->UnionsAvailable != 0) {
+ std::cout << "There are still " << this->UnionsAvailable
+ << " unions available" << std::endl;
+ }
+ }
+ this->CleanupParser();
+ return 1;
+}
+
+void cmDependsJavaParserHelper::CleanupParser()
+{
+ this->Allocates.clear();
+}
+
+int cmDependsJavaParserHelper::LexInput(char* buf, int maxlen)
+{
+ if (maxlen < 1) {
+ return 0;
+ }
+ if (this->InputBufferPos < this->InputBuffer.size()) {
+ buf[0] = this->InputBuffer[this->InputBufferPos++];
+ if (buf[0] == '\n') {
+ this->CurrentLine++;
+ }
+ return 1;
+ }
+ buf[0] = '\n';
+ return 0;
+}
+void cmDependsJavaParserHelper::Error(const char* str)
+{
+ unsigned long pos = static_cast<unsigned long>(this->InputBufferPos);
+ fprintf(stderr, "JPError: %s (%lu / Line: %d)\n", str, pos,
+ this->CurrentLine);
+ std::cerr << "String: ["
+ << cm::string_view{ this->InputBuffer }.substr(
+ this->InputBufferPos, 30)
+ << "]" << std::endl;
+}
+
+void cmDependsJavaParserHelper::UpdateCombine(const char* str1,
+ const char* str2)
+{
+ if (this->CurrentCombine.empty() && str1 != nullptr) {
+ this->CurrentCombine = str1;
+ }
+ this->CurrentCombine += ".";
+ this->CurrentCombine += str2;
+}
+
+int cmDependsJavaParserHelper::ParseFile(const char* file)
+{
+ if (!cmSystemTools::FileExists(file)) {
+ return 0;
+ }
+ cmsys::ifstream ifs(file);
+ if (!ifs) {
+ return 0;
+ }
+
+ std::string fullfile;
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ fullfile += line + "\n";
+ }
+ return this->ParseString(fullfile.c_str(), 0);
+}
diff --git a/Source/cmDependsJavaParserHelper.h b/Source/cmDependsJavaParserHelper.h
new file mode 100644
index 0000000..4057bb7
--- /dev/null
+++ b/Source/cmDependsJavaParserHelper.h
@@ -0,0 +1,98 @@
+/* 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 <memory>
+#include <string>
+#include <vector>
+
+/** \class cmDependsJavaParserHelper
+ * \brief Helper class for parsing java source files
+ *
+ * Finds dependencies for java file and list of outputs
+ */
+class cmDependsJavaParserHelper
+{
+public:
+ struct ParserType
+ {
+ char* str;
+ };
+
+ cmDependsJavaParserHelper();
+ ~cmDependsJavaParserHelper();
+
+ cmDependsJavaParserHelper(const cmDependsJavaParserHelper&) = delete;
+ cmDependsJavaParserHelper& operator=(const cmDependsJavaParserHelper&) =
+ delete;
+
+ int ParseString(const char* str, int verb);
+ int ParseFile(const char* file);
+
+ // For the lexer:
+ void AllocateParserType(cmDependsJavaParserHelper::ParserType* pt,
+ const char* str, int len = 0);
+
+ int LexInput(char* buf, int maxlen);
+ void Error(const char* str);
+
+ // For yacc
+ void AddClassFound(const char* sclass);
+ void PrepareElement(ParserType* me);
+ void DeallocateParserType(char** pt);
+ void CheckEmpty(int line, int cnt, ParserType* pt);
+ void StartClass(const char* cls);
+ void EndClass();
+ void AddPackagesImport(const char* sclass);
+ void SetCurrentPackage(const char* pkg) { this->CurrentPackage = pkg; }
+ const char* GetCurrentPackage() { return this->CurrentPackage.c_str(); }
+ void SetCurrentCombine(const char* cmb) { this->CurrentCombine = cmb; }
+ const char* GetCurrentCombine() { return this->CurrentCombine.c_str(); }
+ void UpdateCombine(const char* str1, const char* str2);
+
+ std::vector<std::string>& GetClassesFound() { return this->ClassesFound; }
+
+ std::vector<std::string> GetFilesProduced();
+
+private:
+ class CurrentClass
+ {
+ public:
+ std::string Name;
+ std::vector<CurrentClass> NestedClasses;
+ void AddFileNamesForPrinting(std::vector<std::string>* files,
+ const char* prefix, const char* sep) const;
+ };
+ std::string CurrentPackage;
+ std::string::size_type InputBufferPos;
+ std::string InputBuffer;
+ std::vector<char> OutputBuffer;
+ std::vector<std::string> ClassesFound;
+ std::vector<std::string> PackagesImport;
+ std::string CurrentCombine;
+
+ std::vector<CurrentClass> ClassStack;
+
+ int CurrentLine;
+ int UnionsAvailable;
+ int LastClassId;
+ int CurrentDepth;
+ int Verbose;
+
+ std::vector<std::unique_ptr<char[]>> Allocates;
+
+ void PrintClasses();
+
+ void Print(const char* place, const char* str) const;
+ void CombineUnions(char** out, const char* in1, char** in2, const char* sep);
+ void SafePrintMissing(const char* str, int line, int cnt);
+
+ void CleanupParser();
+};
+
+#define YYSTYPE cmDependsJavaParserHelper::ParserType
+#define YYSTYPE_IS_DECLARED
+#define YY_EXTRA_TYPE cmDependsJavaParserHelper*
+#define YY_DECL int cmDependsJava_yylex(YYSTYPE* yylvalp, yyscan_t yyscanner)
diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx
new file mode 100644
index 0000000..3619ade
--- /dev/null
+++ b/Source/cmDocumentation.cxx
@@ -0,0 +1,708 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmDocumentation.h"
+
+#include <algorithm>
+#include <cctype>
+#include <cstring>
+#include <utility>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+
+#include "cmDocumentationEntry.h"
+#include "cmDocumentationSection.h"
+#include "cmRST.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+
+static const char* cmDocumentationStandardOptions[][2] = {
+ { "--help,-help,-usage,-h,-H,/?", "Print usage information and exit." },
+ { "--version,-version,/V [<f>]", "Print version number and exit." },
+ { "--help-full [<f>]", "Print all help manuals and exit." },
+ { "--help-manual <man> [<f>]", "Print one help manual and exit." },
+ { "--help-manual-list [<f>]", "List help manuals available and exit." },
+ { "--help-command <cmd> [<f>]", "Print help for one command and exit." },
+ { "--help-command-list [<f>]",
+ "List commands with help available and exit." },
+ { "--help-commands [<f>]", "Print cmake-commands manual and exit." },
+ { "--help-module <mod> [<f>]", "Print help for one module and exit." },
+ { "--help-module-list [<f>]", "List modules with help available and exit." },
+ { "--help-modules [<f>]", "Print cmake-modules manual and exit." },
+ { "--help-policy <cmp> [<f>]", "Print help for one policy and exit." },
+ { "--help-policy-list [<f>]",
+ "List policies with help available and exit." },
+ { "--help-policies [<f>]", "Print cmake-policies manual and exit." },
+ { "--help-property <prop> [<f>]", "Print help for one property and exit." },
+ { "--help-property-list [<f>]",
+ "List properties with help available and exit." },
+ { "--help-properties [<f>]", "Print cmake-properties manual and exit." },
+ { "--help-variable var [<f>]", "Print help for one variable and exit." },
+ { "--help-variable-list [<f>]",
+ "List variables with help available and exit." },
+ { "--help-variables [<f>]", "Print cmake-variables manual and exit." },
+ { nullptr, nullptr }
+};
+
+static const char* cmDocumentationCPackGeneratorsHeader[][2] = {
+ { nullptr, "The following generators are available on this platform:" },
+ { nullptr, nullptr }
+};
+
+static const char* cmDocumentationCMakeGeneratorsHeader[][2] = {
+ { nullptr,
+ "The following generators are available on this platform (* marks "
+ "default):" },
+ { nullptr, nullptr }
+};
+
+cmDocumentation::cmDocumentation()
+{
+ this->addCommonStandardDocSections();
+ this->ShowGenerators = true;
+}
+
+bool cmDocumentation::PrintVersion(std::ostream& os)
+{
+ /* clang-format off */
+ os <<
+ this->GetNameString() <<
+ " version " << cmVersion::GetCMakeVersion() << "\n"
+ "\n"
+ "CMake suite maintained and supported by Kitware (kitware.com/cmake).\n"
+ ;
+ /* clang-format on */
+ return true;
+}
+
+bool cmDocumentation::PrintDocumentation(Type ht, std::ostream& os)
+{
+ switch (ht) {
+ case cmDocumentation::Usage:
+ return this->PrintUsage(os);
+ case cmDocumentation::Help:
+ return this->PrintHelp(os);
+ case cmDocumentation::Full:
+ return this->PrintHelpFull(os);
+ case cmDocumentation::OneManual:
+ return this->PrintHelpOneManual(os);
+ case cmDocumentation::OneCommand:
+ return this->PrintHelpOneCommand(os);
+ case cmDocumentation::OneModule:
+ return this->PrintHelpOneModule(os);
+ case cmDocumentation::OnePolicy:
+ return this->PrintHelpOnePolicy(os);
+ case cmDocumentation::OneProperty:
+ return this->PrintHelpOneProperty(os);
+ case cmDocumentation::OneVariable:
+ return this->PrintHelpOneVariable(os);
+ case cmDocumentation::ListManuals:
+ return this->PrintHelpListManuals(os);
+ case cmDocumentation::ListCommands:
+ return this->PrintHelpListCommands(os);
+ case cmDocumentation::ListModules:
+ return this->PrintHelpListModules(os);
+ case cmDocumentation::ListProperties:
+ return this->PrintHelpListProperties(os);
+ case cmDocumentation::ListVariables:
+ return this->PrintHelpListVariables(os);
+ case cmDocumentation::ListPolicies:
+ return this->PrintHelpListPolicies(os);
+ case cmDocumentation::ListGenerators:
+ return this->PrintHelpListGenerators(os);
+ case cmDocumentation::Version:
+ return this->PrintVersion(os);
+ case cmDocumentation::OldCustomModules:
+ return this->PrintOldCustomModules(os);
+ default:
+ return false;
+ }
+}
+
+bool cmDocumentation::PrintRequestedDocumentation(std::ostream& os)
+{
+ int count = 0;
+ bool result = true;
+
+ // Loop over requested documentation types.
+ for (RequestedHelpItem const& rhi : this->RequestedHelpItems) {
+ this->CurrentArgument = rhi.Argument;
+ // If a file name was given, use it. Otherwise, default to the
+ // given stream.
+ cmsys::ofstream fout;
+ std::ostream* s = &os;
+ if (!rhi.Filename.empty()) {
+ fout.open(rhi.Filename.c_str());
+ s = &fout;
+ } else if (++count > 1) {
+ os << "\n\n";
+ }
+
+ // Print this documentation type to the stream.
+ if (!this->PrintDocumentation(rhi.HelpType, *s) || s->fail()) {
+ result = false;
+ }
+ }
+ return result;
+}
+
+#define GET_OPT_ARGUMENT(target) \
+ do { \
+ if ((i + 1 < argc) && !this->IsOption(argv[i + 1])) { \
+ (target) = argv[i + 1]; \
+ i = i + 1; \
+ }; \
+ } while (false)
+
+void cmDocumentation::WarnFormFromFilename(
+ cmDocumentation::RequestedHelpItem& request, bool& result)
+{
+ std::string ext = cmSystemTools::GetFilenameLastExtension(request.Filename);
+ ext = cmSystemTools::UpperCase(ext);
+ if ((ext == ".HTM") || (ext == ".HTML")) {
+ request.HelpType = cmDocumentation::None;
+ result = true;
+ cmSystemTools::Message("Warning: HTML help format no longer supported");
+ } else if (ext == ".DOCBOOK") {
+ request.HelpType = cmDocumentation::None;
+ result = true;
+ cmSystemTools::Message("Warning: Docbook help format no longer supported");
+ }
+ // ".1" to ".9" should be manpages
+ else if ((ext.length() == 2) && (ext[1] >= '1') && (ext[1] <= '9')) {
+ request.HelpType = cmDocumentation::None;
+ result = true;
+ cmSystemTools::Message("Warning: Man help format no longer supported");
+ }
+}
+
+void cmDocumentation::addCommonStandardDocSections()
+{
+ cmDocumentationSection sec{ "Options" };
+ sec.Append(cmDocumentationStandardOptions);
+ this->AllSections.emplace("Options", std::move(sec));
+}
+
+void cmDocumentation::addCMakeStandardDocSections()
+{
+ cmDocumentationSection sec{ "Generators" };
+ sec.Append(cmDocumentationCMakeGeneratorsHeader);
+ this->AllSections.emplace("Generators", std::move(sec));
+}
+
+void cmDocumentation::addCTestStandardDocSections()
+{
+ // This is currently done for backward compatibility reason
+ // We may suppress some of these.
+ this->addCMakeStandardDocSections();
+}
+
+void cmDocumentation::addCPackStandardDocSections()
+{
+ cmDocumentationSection sec{ "Generators" };
+ sec.Append(cmDocumentationCPackGeneratorsHeader);
+ this->AllSections.emplace("Generators", std::move(sec));
+}
+
+bool cmDocumentation::CheckOptions(int argc, const char* const* argv,
+ const char* exitOpt)
+{
+ // Providing zero arguments gives usage information.
+ if (argc == 1) {
+ RequestedHelpItem help;
+ help.HelpType = cmDocumentation::Usage;
+ this->RequestedHelpItems.push_back(std::move(help));
+ return true;
+ }
+
+ // Search for supported help options.
+
+ bool result = false;
+ for (int i = 1; i < argc; ++i) {
+ if (exitOpt && strcmp(argv[i], exitOpt) == 0) {
+ return result;
+ }
+ RequestedHelpItem help;
+ // Check if this is a supported help option.
+ if ((strcmp(argv[i], "-help") == 0) || (strcmp(argv[i], "--help") == 0) ||
+ (strcmp(argv[i], "/?") == 0) || (strcmp(argv[i], "-usage") == 0) ||
+ (strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "-H") == 0)) {
+ help.HelpType = cmDocumentation::Help;
+ GET_OPT_ARGUMENT(help.Argument);
+ help.Argument = cmSystemTools::LowerCase(help.Argument);
+ // special case for single command
+ if (!help.Argument.empty()) {
+ help.HelpType = cmDocumentation::OneCommand;
+ }
+ } else if (strcmp(argv[i], "--help-properties") == 0) {
+ help.HelpType = cmDocumentation::OneManual;
+ help.Argument = "cmake-properties.7";
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-policies") == 0) {
+ help.HelpType = cmDocumentation::OneManual;
+ help.Argument = "cmake-policies.7";
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-variables") == 0) {
+ help.HelpType = cmDocumentation::OneManual;
+ help.Argument = "cmake-variables.7";
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-modules") == 0) {
+ help.HelpType = cmDocumentation::OneManual;
+ help.Argument = "cmake-modules.7";
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-custom-modules") == 0) {
+ GET_OPT_ARGUMENT(help.Filename);
+ cmSystemTools::Message(
+ "Warning: --help-custom-modules no longer supported");
+ if (help.Filename.empty()) {
+ return true;
+ }
+ // Avoid breaking old project builds completely by at least generating
+ // the output file. Abuse help.Argument to give the file name to
+ // PrintOldCustomModules without disrupting our internal API.
+ help.HelpType = cmDocumentation::OldCustomModules;
+ help.Argument = cmSystemTools::GetFilenameName(help.Filename);
+ } else if (strcmp(argv[i], "--help-commands") == 0) {
+ help.HelpType = cmDocumentation::OneManual;
+ help.Argument = "cmake-commands.7";
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-compatcommands") == 0) {
+ GET_OPT_ARGUMENT(help.Filename);
+ cmSystemTools::Message(
+ "Warning: --help-compatcommands no longer supported");
+ return true;
+ } else if (strcmp(argv[i], "--help-full") == 0) {
+ help.HelpType = cmDocumentation::Full;
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-html") == 0) {
+ GET_OPT_ARGUMENT(help.Filename);
+ cmSystemTools::Message("Warning: --help-html no longer supported");
+ return true;
+ } else if (strcmp(argv[i], "--help-man") == 0) {
+ GET_OPT_ARGUMENT(help.Filename);
+ cmSystemTools::Message("Warning: --help-man no longer supported");
+ return true;
+ } else if (strcmp(argv[i], "--help-command") == 0) {
+ help.HelpType = cmDocumentation::OneCommand;
+ GET_OPT_ARGUMENT(help.Argument);
+ GET_OPT_ARGUMENT(help.Filename);
+ help.Argument = cmSystemTools::LowerCase(help.Argument);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-module") == 0) {
+ help.HelpType = cmDocumentation::OneModule;
+ GET_OPT_ARGUMENT(help.Argument);
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-property") == 0) {
+ help.HelpType = cmDocumentation::OneProperty;
+ GET_OPT_ARGUMENT(help.Argument);
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-policy") == 0) {
+ help.HelpType = cmDocumentation::OnePolicy;
+ GET_OPT_ARGUMENT(help.Argument);
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-variable") == 0) {
+ help.HelpType = cmDocumentation::OneVariable;
+ GET_OPT_ARGUMENT(help.Argument);
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-manual") == 0) {
+ help.HelpType = cmDocumentation::OneManual;
+ GET_OPT_ARGUMENT(help.Argument);
+ GET_OPT_ARGUMENT(help.Filename);
+ this->WarnFormFromFilename(help, result);
+ } else if (strcmp(argv[i], "--help-command-list") == 0) {
+ help.HelpType = cmDocumentation::ListCommands;
+ GET_OPT_ARGUMENT(help.Filename);
+ } else if (strcmp(argv[i], "--help-module-list") == 0) {
+ help.HelpType = cmDocumentation::ListModules;
+ GET_OPT_ARGUMENT(help.Filename);
+ } else if (strcmp(argv[i], "--help-property-list") == 0) {
+ help.HelpType = cmDocumentation::ListProperties;
+ GET_OPT_ARGUMENT(help.Filename);
+ } else if (strcmp(argv[i], "--help-variable-list") == 0) {
+ help.HelpType = cmDocumentation::ListVariables;
+ GET_OPT_ARGUMENT(help.Filename);
+ } else if (strcmp(argv[i], "--help-policy-list") == 0) {
+ help.HelpType = cmDocumentation::ListPolicies;
+ GET_OPT_ARGUMENT(help.Filename);
+ } else if (strcmp(argv[i], "--help-manual-list") == 0) {
+ help.HelpType = cmDocumentation::ListManuals;
+ GET_OPT_ARGUMENT(help.Filename);
+ } else if (strcmp(argv[i], "--copyright") == 0) {
+ GET_OPT_ARGUMENT(help.Filename);
+ cmSystemTools::Message("Warning: --copyright no longer supported");
+ return true;
+ } else if ((strcmp(argv[i], "--version") == 0) ||
+ (strcmp(argv[i], "-version") == 0) ||
+ (strcmp(argv[i], "/V") == 0)) {
+ help.HelpType = cmDocumentation::Version;
+ GET_OPT_ARGUMENT(help.Filename);
+ }
+ if (help.HelpType != None) {
+ // This is a help option. See if there is a file name given.
+ result = true;
+ this->RequestedHelpItems.push_back(std::move(help));
+ }
+ }
+ return result;
+}
+
+void cmDocumentation::SetName(const std::string& name)
+{
+ this->NameString = name;
+}
+
+void cmDocumentation::SetSection(const char* name,
+ cmDocumentationSection section)
+{
+ this->SectionAtName(name) = std::move(section);
+}
+
+void cmDocumentation::SetSection(const char* name,
+ std::vector<cmDocumentationEntry>& docs)
+{
+ cmDocumentationSection sec{ name };
+ sec.Append(docs);
+ this->SetSection(name, std::move(sec));
+}
+
+void cmDocumentation::SetSection(const char* name, const char* docs[][2])
+{
+ cmDocumentationSection sec{ name };
+ sec.Append(docs);
+ this->SetSection(name, std::move(sec));
+}
+
+void cmDocumentation::SetSections(
+ std::map<std::string, cmDocumentationSection> sections)
+{
+ for (auto& s : sections) {
+ this->SetSection(s.first.c_str(), std::move(s.second));
+ }
+}
+cmDocumentationSection& cmDocumentation::SectionAtName(const char* name)
+{
+ return this->AllSections.emplace(name, cmDocumentationSection{ name })
+ .first->second;
+}
+
+void cmDocumentation::PrependSection(const char* name, const char* docs[][2])
+{
+ this->SectionAtName(name).Prepend(docs);
+}
+
+void cmDocumentation::PrependSection(const char* name,
+ std::vector<cmDocumentationEntry>& docs)
+{
+ this->SectionAtName(name).Prepend(docs);
+}
+
+void cmDocumentation::AppendSection(const char* name, const char* docs[][2])
+{
+ this->SectionAtName(name).Append(docs);
+}
+
+void cmDocumentation::AppendSection(const char* name,
+ std::vector<cmDocumentationEntry>& docs)
+{
+ this->SectionAtName(name).Append(docs);
+}
+
+void cmDocumentation::AppendSection(const char* name,
+ cmDocumentationEntry& docs)
+{
+
+ std::vector<cmDocumentationEntry> docsVec;
+ docsVec.push_back(docs);
+ this->AppendSection(name, docsVec);
+}
+
+void cmDocumentation::PrependSection(const char* name,
+ cmDocumentationEntry& docs)
+{
+
+ std::vector<cmDocumentationEntry> docsVec;
+ docsVec.push_back(docs);
+ this->PrependSection(name, docsVec);
+}
+
+void cmDocumentation::GlobHelp(std::vector<std::string>& files,
+ std::string const& pattern)
+{
+ cmsys::Glob gl;
+ std::string findExpr =
+ cmSystemTools::GetCMakeRoot() + "/Help/" + pattern + ".rst";
+ if (gl.FindFiles(findExpr)) {
+ files = gl.GetFiles();
+ }
+}
+
+void cmDocumentation::PrintNames(std::ostream& os, std::string const& pattern)
+{
+ std::vector<std::string> files;
+ this->GlobHelp(files, pattern);
+ std::vector<std::string> names;
+ for (std::string const& f : files) {
+ std::string line;
+ cmsys::ifstream fin(f.c_str());
+ while (fin && cmSystemTools::GetLineFromStream(fin, line)) {
+ if (!line.empty() && (isalnum(line[0]) || line[0] == '<')) {
+ names.push_back(line);
+ break;
+ }
+ }
+ }
+ std::sort(names.begin(), names.end());
+ for (std::string const& n : names) {
+ os << n << "\n";
+ }
+}
+
+bool cmDocumentation::PrintFiles(std::ostream& os, std::string const& pattern)
+{
+ bool found = false;
+ std::vector<std::string> files;
+ this->GlobHelp(files, pattern);
+ std::sort(files.begin(), files.end());
+ cmRST r(os, cmSystemTools::GetCMakeRoot() + "/Help");
+ for (std::string const& f : files) {
+ found = r.ProcessFile(f) || found;
+ }
+ return found;
+}
+
+bool cmDocumentation::PrintHelpFull(std::ostream& os)
+{
+ return this->PrintFiles(os, "index");
+}
+
+bool cmDocumentation::PrintHelpOneManual(std::ostream& os)
+{
+ std::string mname = this->CurrentArgument;
+ std::string::size_type mlen = mname.length();
+ if (mlen > 3 && mname[mlen - 3] == '(' && mname[mlen - 1] == ')') {
+ mname = mname.substr(0, mlen - 3) + "." + mname[mlen - 2];
+ }
+ if (this->PrintFiles(os, "manual/" + mname) ||
+ this->PrintFiles(os, "manual/" + mname + ".[0-9]")) {
+ return true;
+ }
+ // Argument was not a manual. Complain.
+ os << "Argument \"" << this->CurrentArgument
+ << "\" to --help-manual is not an available manual. "
+ << "Use --help-manual-list to see all available manuals.\n";
+ return false;
+}
+
+bool cmDocumentation::PrintHelpListManuals(std::ostream& os)
+{
+ this->PrintNames(os, "manual/*");
+ return true;
+}
+
+bool cmDocumentation::PrintHelpOneCommand(std::ostream& os)
+{
+ std::string cname = cmSystemTools::LowerCase(this->CurrentArgument);
+ if (this->PrintFiles(os, "command/" + cname)) {
+ return true;
+ }
+ // Argument was not a command. Complain.
+ os << "Argument \"" << this->CurrentArgument
+ << "\" to --help-command is not a CMake command. "
+ << "Use --help-command-list to see all commands.\n";
+ return false;
+}
+
+bool cmDocumentation::PrintHelpListCommands(std::ostream& os)
+{
+ this->PrintNames(os, "command/*");
+ return true;
+}
+
+bool cmDocumentation::PrintHelpOneModule(std::ostream& os)
+{
+ std::string mname = this->CurrentArgument;
+ if (this->PrintFiles(os, "module/" + mname)) {
+ return true;
+ }
+ // Argument was not a module. Complain.
+ os << "Argument \"" << this->CurrentArgument
+ << "\" to --help-module is not a CMake module.\n";
+ return false;
+}
+
+bool cmDocumentation::PrintHelpListModules(std::ostream& os)
+{
+ std::vector<std::string> files;
+ this->GlobHelp(files, "module/*");
+ std::vector<std::string> modules;
+ for (std::string const& f : files) {
+ std::string module = cmSystemTools::GetFilenameName(f);
+ modules.push_back(module.substr(0, module.size() - 4));
+ }
+ std::sort(modules.begin(), modules.end());
+ for (std::string const& m : modules) {
+ os << m << "\n";
+ }
+ return true;
+}
+
+bool cmDocumentation::PrintHelpOneProperty(std::ostream& os)
+{
+ std::string pname = cmSystemTools::HelpFileName(this->CurrentArgument);
+ if (this->PrintFiles(os, "prop_*/" + pname)) {
+ return true;
+ }
+ // Argument was not a property. Complain.
+ os << "Argument \"" << this->CurrentArgument
+ << "\" to --help-property is not a CMake property. "
+ << "Use --help-property-list to see all properties.\n";
+ return false;
+}
+
+bool cmDocumentation::PrintHelpListProperties(std::ostream& os)
+{
+ this->PrintNames(os, "prop_*/*");
+ return true;
+}
+
+bool cmDocumentation::PrintHelpOnePolicy(std::ostream& os)
+{
+ std::string pname = this->CurrentArgument;
+ std::vector<std::string> files;
+ if (this->PrintFiles(os, "policy/" + pname)) {
+ return true;
+ }
+
+ // Argument was not a policy. Complain.
+ os << "Argument \"" << this->CurrentArgument
+ << "\" to --help-policy is not a CMake policy.\n";
+ return false;
+}
+
+bool cmDocumentation::PrintHelpListPolicies(std::ostream& os)
+{
+ this->PrintNames(os, "policy/*");
+ return true;
+}
+
+bool cmDocumentation::PrintHelpListGenerators(std::ostream& os)
+{
+ const auto si = this->AllSections.find("Generators");
+ if (si != this->AllSections.end()) {
+ this->Formatter.SetIndent(" ");
+ this->Formatter.PrintSection(os, si->second);
+ }
+ return true;
+}
+
+bool cmDocumentation::PrintHelpOneVariable(std::ostream& os)
+{
+ std::string vname = cmSystemTools::HelpFileName(this->CurrentArgument);
+ if (this->PrintFiles(os, "variable/" + vname)) {
+ return true;
+ }
+ // Argument was not a variable. Complain.
+ os << "Argument \"" << this->CurrentArgument
+ << "\" to --help-variable is not a defined variable. "
+ << "Use --help-variable-list to see all defined variables.\n";
+ return false;
+}
+
+bool cmDocumentation::PrintHelpListVariables(std::ostream& os)
+{
+ this->PrintNames(os, "variable/*");
+ return true;
+}
+
+bool cmDocumentation::PrintUsage(std::ostream& os)
+{
+ const auto si = this->AllSections.find("Usage");
+ if (si != this->AllSections.end()) {
+ this->Formatter.PrintSection(os, si->second);
+ }
+ return true;
+}
+
+bool cmDocumentation::PrintHelp(std::ostream& os)
+{
+ auto si = this->AllSections.find("Usage");
+ if (si != this->AllSections.end()) {
+ this->Formatter.PrintSection(os, si->second);
+ }
+ si = this->AllSections.find("Options");
+ if (si != this->AllSections.end()) {
+ this->Formatter.PrintSection(os, si->second);
+ }
+ if (this->ShowGenerators) {
+ si = this->AllSections.find("Generators");
+ if (si != this->AllSections.end()) {
+ this->Formatter.PrintSection(os, si->second);
+ }
+ }
+ return true;
+}
+
+const char* cmDocumentation::GetNameString() const
+{
+ if (!this->NameString.empty()) {
+ return this->NameString.c_str();
+ }
+ return "CMake";
+}
+
+bool cmDocumentation::IsOption(const char* arg) const
+{
+ return ((arg[0] == '-') || (strcmp(arg, "/V") == 0) ||
+ (strcmp(arg, "/?") == 0));
+}
+
+bool cmDocumentation::PrintOldCustomModules(std::ostream& os)
+{
+ // CheckOptions abuses the Argument field to give us the file name.
+ std::string filename = this->CurrentArgument;
+ std::string ext = cmSystemTools::UpperCase(
+ cmSystemTools::GetFilenameLastExtension(filename));
+ std::string name = cmSystemTools::GetFilenameWithoutLastExtension(filename);
+
+ const char* summary = "cmake --help-custom-modules no longer supported\n";
+ const char* detail =
+ "CMake versions prior to 3.0 exposed their internal module help page\n"
+ "generation functionality through the --help-custom-modules option.\n"
+ "CMake versions 3.0 and above use other means to generate their module\n"
+ "help pages so this functionality is no longer available to be exposed.\n"
+ "\n"
+ "This file was generated as a placeholder to provide this information.\n";
+ if ((ext == ".HTM") || (ext == ".HTML")) {
+ os << "<html><title>" << name << "</title><body>\n"
+ << summary << "<p/>\n"
+ << detail << "</body></html>\n";
+ } else if ((ext.length() == 2) && (ext[1] >= '1') && (ext[1] <= '9')) {
+ /* clang-format off */
+ os <<
+ ".TH " << name << " " << ext[1] << " \"" <<
+ cmSystemTools::GetCurrentDateTime("%B %d, %Y") <<
+ "\" \"cmake " << cmVersion::GetCMakeVersion() << "\"\n"
+ ".SH NAME\n"
+ ".PP\n" <<
+ name << " \\- " << summary <<
+ "\n"
+ ".SH DESCRIPTION\n"
+ ".PP\n" <<
+ detail
+ ;
+ /* clang-format on */
+ } else {
+ os << name << "\n\n" << summary << "\n" << detail;
+ }
+ return true;
+}
diff --git a/Source/cmDocumentation.h b/Source/cmDocumentation.h
new file mode 100644
index 0000000..313be32
--- /dev/null
+++ b/Source/cmDocumentation.h
@@ -0,0 +1,126 @@
+/* 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 <iosfwd>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "cmDocumentationFormatter.h"
+#include "cmDocumentationSection.h"
+
+struct cmDocumentationEntry;
+
+/** Class to generate documentation. */
+class cmDocumentation : public cmDocumentationEnums
+{
+public:
+ cmDocumentation();
+
+ /**
+ * Check command line arguments for documentation options. Returns
+ * true if documentation options are found, and false otherwise.
+ * When true is returned, PrintRequestedDocumentation should be
+ * called. exitOpt can be used for things like cmake -E, so that
+ * all arguments after the -E are ignored and not searched for
+ * help arguments.
+ */
+ bool CheckOptions(int argc, const char* const* argv,
+ const char* exitOpt = nullptr);
+
+ /**
+ * Print help requested on the command line. Call after
+ * CheckOptions returns true. Returns true on success, and false
+ * otherwise. Failure can occur when output files specified on the
+ * command line cannot be written.
+ */
+ bool PrintRequestedDocumentation(std::ostream& os);
+
+ /** Print help of the given type. */
+ bool PrintDocumentation(Type ht, std::ostream& os);
+
+ void SetShowGenerators(bool showGen) { this->ShowGenerators = showGen; }
+
+ /** Set the program name for standard document generation. */
+ void SetName(const std::string& name);
+
+ /** Set a section of the documentation. Typical sections include Name,
+ Usage, Description, Options */
+ void SetSection(const char* sectionName, cmDocumentationSection section);
+ void SetSection(const char* sectionName,
+ std::vector<cmDocumentationEntry>& docs);
+ void SetSection(const char* sectionName, const char* docs[][2]);
+ void SetSections(std::map<std::string, cmDocumentationSection> sections);
+
+ /** Add the documentation to the beginning/end of the section */
+ void PrependSection(const char* sectionName, const char* docs[][2]);
+ void PrependSection(const char* sectionName,
+ std::vector<cmDocumentationEntry>& docs);
+ void PrependSection(const char* sectionName, cmDocumentationEntry& docs);
+ void AppendSection(const char* sectionName, const char* docs[][2]);
+ void AppendSection(const char* sectionName,
+ std::vector<cmDocumentationEntry>& docs);
+ void AppendSection(const char* sectionName, cmDocumentationEntry& docs);
+
+ /** Add common (to all tools) documentation section(s) */
+ void addCommonStandardDocSections();
+
+ /** Add the CMake standard documentation section(s) */
+ void addCMakeStandardDocSections();
+
+ /** Add the CTest standard documentation section(s) */
+ void addCTestStandardDocSections();
+
+ /** Add the CPack standard documentation section(s) */
+ void addCPackStandardDocSections();
+
+private:
+ void GlobHelp(std::vector<std::string>& files, std::string const& pattern);
+ void PrintNames(std::ostream& os, std::string const& pattern);
+ bool PrintFiles(std::ostream& os, std::string const& pattern);
+
+ bool PrintVersion(std::ostream& os);
+ bool PrintUsage(std::ostream& os);
+ bool PrintHelp(std::ostream& os);
+ bool PrintHelpFull(std::ostream& os);
+ bool PrintHelpOneManual(std::ostream& os);
+ bool PrintHelpOneCommand(std::ostream& os);
+ bool PrintHelpOneModule(std::ostream& os);
+ bool PrintHelpOnePolicy(std::ostream& os);
+ bool PrintHelpOneProperty(std::ostream& os);
+ bool PrintHelpOneVariable(std::ostream& os);
+ bool PrintHelpListManuals(std::ostream& os);
+ bool PrintHelpListCommands(std::ostream& os);
+ bool PrintHelpListModules(std::ostream& os);
+ bool PrintHelpListProperties(std::ostream& os);
+ bool PrintHelpListVariables(std::ostream& os);
+ bool PrintHelpListPolicies(std::ostream& os);
+ bool PrintHelpListGenerators(std::ostream& os);
+ bool PrintOldCustomModules(std::ostream& os);
+
+ const char* GetNameString() const;
+ bool IsOption(const char* arg) const;
+
+ bool ShowGenerators;
+
+ std::string NameString;
+ std::map<std::string, cmDocumentationSection> AllSections;
+ cmDocumentationSection& SectionAtName(const char* name);
+
+ std::string CurrentArgument;
+
+ struct RequestedHelpItem
+ {
+ cmDocumentationEnums::Type HelpType = None;
+ std::string Filename;
+ std::string Argument;
+ };
+
+ std::vector<RequestedHelpItem> RequestedHelpItems;
+ cmDocumentationFormatter Formatter;
+
+ static void WarnFormFromFilename(RequestedHelpItem& request, bool& result);
+};
diff --git a/Source/cmDocumentationEntry.h b/Source/cmDocumentationEntry.h
new file mode 100644
index 0000000..89a2899
--- /dev/null
+++ b/Source/cmDocumentationEntry.h
@@ -0,0 +1,34 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+
+/** Standard documentation entry for cmDocumentation's formatting. */
+struct cmDocumentationEntry
+{
+ std::string Name;
+ std::string Brief;
+ char CustomNamePrefix = ' ';
+ cmDocumentationEntry() = default;
+ cmDocumentationEntry(const char* doc[2])
+ {
+ if (doc[0]) {
+ this->Name = doc[0];
+ }
+ if (doc[1]) {
+ this->Brief = doc[1];
+ }
+ }
+ cmDocumentationEntry(const char* n, const char* b)
+ {
+ if (n) {
+ this->Name = n;
+ }
+ if (b) {
+ this->Brief = b;
+ }
+ }
+};
diff --git a/Source/cmDocumentationFormatter.cxx b/Source/cmDocumentationFormatter.cxx
new file mode 100644
index 0000000..732637e
--- /dev/null
+++ b/Source/cmDocumentationFormatter.cxx
@@ -0,0 +1,188 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmDocumentationFormatter.h"
+
+#include <cstring>
+#include <iomanip>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "cmDocumentationEntry.h"
+#include "cmDocumentationSection.h"
+
+cmDocumentationFormatter::cmDocumentationFormatter() = default;
+
+cmDocumentationFormatter::~cmDocumentationFormatter() = default;
+
+void cmDocumentationFormatter::PrintFormatted(std::ostream& os,
+ const char* text)
+{
+ if (!text) {
+ return;
+ }
+ const char* ptr = text;
+ while (*ptr) {
+ // Any ptrs starting in a space are treated as preformatted text.
+ std::string preformatted;
+ while (*ptr == ' ') {
+ for (char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) {
+ preformatted.append(1, ch);
+ }
+ if (*ptr) {
+ ++ptr;
+ preformatted.append(1, '\n');
+ }
+ }
+ if (!preformatted.empty()) {
+ this->PrintPreformatted(os, preformatted.c_str());
+ }
+
+ // Other ptrs are treated as paragraphs.
+ std::string paragraph;
+ for (char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) {
+ paragraph.append(1, ch);
+ }
+ if (*ptr) {
+ ++ptr;
+ paragraph.append(1, '\n');
+ }
+ if (!paragraph.empty()) {
+ this->PrintParagraph(os, paragraph.c_str());
+ }
+ }
+}
+
+void cmDocumentationFormatter::PrintPreformatted(std::ostream& os,
+ const char* text)
+{
+ bool newline = true;
+ for (const char* ptr = text; *ptr; ++ptr) {
+ if (newline && *ptr != '\n') {
+ os << this->TextIndent;
+ newline = false;
+ }
+ os << *ptr;
+ if (*ptr == '\n') {
+ newline = true;
+ }
+ }
+ os << "\n";
+}
+
+void cmDocumentationFormatter::PrintParagraph(std::ostream& os,
+ const char* text)
+{
+ os << this->TextIndent;
+ this->PrintColumn(os, text);
+ os << "\n";
+}
+
+void cmDocumentationFormatter::SetIndent(const char* indent)
+{
+ this->TextIndent = indent;
+}
+
+void cmDocumentationFormatter::PrintColumn(std::ostream& os, const char* text)
+{
+ // Print text arranged in an indented column of fixed width.
+ const char* l = text;
+ long column = 0;
+ bool newSentence = false;
+ bool firstLine = true;
+ int width = this->TextWidth - static_cast<int>(strlen(this->TextIndent));
+
+ // Loop until the end of the text.
+ while (*l) {
+ // Parse the next word.
+ const char* r = l;
+ while (*r && (*r != '\n') && (*r != ' ')) {
+ ++r;
+ }
+
+ // Does it fit on this line?
+ if (r - l < (width - column - (newSentence ? 1 : 0))) {
+ // Word fits on this line.
+ if (r > l) {
+ if (column) {
+ // Not first word on line. Separate from the previous word
+ // by a space, or two if this is a new sentence.
+ if (newSentence) {
+ os << " ";
+ column += 2;
+ } else {
+ os << " ";
+ column += 1;
+ }
+ } else {
+ // First word on line. Print indentation unless this is the
+ // first line.
+ os << (firstLine ? "" : this->TextIndent);
+ }
+
+ // Print the word.
+ os.write(l, static_cast<long>(r - l));
+ newSentence = (*(r - 1) == '.');
+ }
+
+ if (*r == '\n') {
+ // Text provided a newline. Start a new line.
+ os << "\n";
+ ++r;
+ column = 0;
+ firstLine = false;
+ } else {
+ // No provided newline. Continue this line.
+ column += static_cast<long>(r - l);
+ }
+ } else {
+ // Word does not fit on this line. Start a new line.
+ os << "\n";
+ firstLine = false;
+ if (r > l) {
+ os << this->TextIndent;
+ os.write(l, static_cast<long>(r - l));
+ column = static_cast<long>(r - l);
+ newSentence = (*(r - 1) == '.');
+ } else {
+ column = 0;
+ }
+ }
+
+ // Move to beginning of next word. Skip over whitespace.
+ l = r;
+ while (*l == ' ') {
+ ++l;
+ }
+ }
+}
+
+void cmDocumentationFormatter::PrintSection(
+ std::ostream& os, cmDocumentationSection const& section)
+{
+ os << section.GetName() << "\n";
+
+ const std::vector<cmDocumentationEntry>& entries = section.GetEntries();
+ for (cmDocumentationEntry const& entry : entries) {
+ if (!entry.Name.empty()) {
+ os << std::setw(2) << std::left << entry.CustomNamePrefix << entry.Name;
+ this->TextIndent = " ";
+ int align = static_cast<int>(strlen(this->TextIndent)) - 4;
+ for (int i = static_cast<int>(entry.Name.size()); i < align; ++i) {
+ os << " ";
+ }
+ if (entry.Name.size() > strlen(this->TextIndent) - 4) {
+ os << "\n";
+ os.write(this->TextIndent, strlen(this->TextIndent) - 2);
+ }
+ os << "= ";
+ this->PrintColumn(os, entry.Brief.c_str());
+ os << "\n";
+ } else {
+ os << "\n";
+ this->TextIndent = "";
+ this->PrintFormatted(os, entry.Brief.c_str());
+ }
+ }
+ os << "\n";
+}
diff --git a/Source/cmDocumentationFormatter.h b/Source/cmDocumentationFormatter.h
new file mode 100644
index 0000000..cb3038a
--- /dev/null
+++ b/Source/cmDocumentationFormatter.h
@@ -0,0 +1,63 @@
+/* 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 <iosfwd>
+
+/** This is just a helper class to make it build with MSVC 6.0.
+Actually the enums and internal classes could directly go into
+cmDocumentation, but then MSVC6 complains in RequestedHelpItem that
+cmDocumentation is an undefined type and so it doesn't know the enums.
+Moving the enums to a class which is then already completely parsed helps
+against this. */
+class cmDocumentationEnums
+{
+public:
+ /** Types of help provided. */
+ enum Type
+ {
+ None,
+ Version,
+ Usage,
+ Help,
+ Full,
+ ListManuals,
+ ListCommands,
+ ListModules,
+ ListProperties,
+ ListVariables,
+ ListPolicies,
+ ListGenerators,
+ OneManual,
+ OneCommand,
+ OneModule,
+ OneProperty,
+ OneVariable,
+ OnePolicy,
+ OldCustomModules
+ };
+};
+
+class cmDocumentationSection;
+
+/** Print documentation in a simple text format. */
+class cmDocumentationFormatter
+{
+public:
+ cmDocumentationFormatter();
+ virtual ~cmDocumentationFormatter();
+ void PrintFormatted(std::ostream& os, const char* text);
+
+ virtual void PrintSection(std::ostream& os,
+ cmDocumentationSection const& section);
+ virtual void PrintPreformatted(std::ostream& os, const char* text);
+ virtual void PrintParagraph(std::ostream& os, const char* text);
+ void PrintColumn(std::ostream& os, const char* text);
+ void SetIndent(const char* indent);
+
+private:
+ int TextWidth = 77;
+ const char* TextIndent = "";
+};
diff --git a/Source/cmDocumentationSection.cxx b/Source/cmDocumentationSection.cxx
new file mode 100644
index 0000000..439da1b
--- /dev/null
+++ b/Source/cmDocumentationSection.cxx
@@ -0,0 +1,28 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmDocumentationSection.h"
+
+void cmDocumentationSection::Append(const char* data[][2])
+{
+ int i = 0;
+ while (data[i][1]) {
+ this->Entries.emplace_back(data[i][0], data[i][1]);
+ data += 1;
+ }
+}
+
+void cmDocumentationSection::Prepend(const char* data[][2])
+{
+ std::vector<cmDocumentationEntry> tmp;
+ int i = 0;
+ while (data[i][1]) {
+ tmp.emplace_back(data[i][0], data[i][1]);
+ data += 1;
+ }
+ this->Entries.insert(this->Entries.begin(), tmp.begin(), tmp.end());
+}
+
+void cmDocumentationSection::Append(const char* n, const char* b)
+{
+ this->Entries.emplace_back(n, b);
+}
diff --git a/Source/cmDocumentationSection.h b/Source/cmDocumentationSection.h
new file mode 100644
index 0000000..276e520
--- /dev/null
+++ b/Source/cmDocumentationSection.h
@@ -0,0 +1,68 @@
+/* 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 <string>
+#include <vector>
+
+#include <cmext/algorithm>
+
+#include "cmDocumentationEntry.h"
+
+// Low-level interface for custom documents:
+/** Internal class representing a section of the documentation.
+ * Cares e.g. for the different section titles in the different
+ * output formats.
+ */
+class cmDocumentationSection
+{
+public:
+ /** Create a cmSection, with a special name for man-output mode. */
+ explicit cmDocumentationSection(const char* name)
+ : Name(name)
+ {
+ }
+
+ /** Has any content been added to this section or is it empty ? */
+ bool IsEmpty() const { return this->Entries.empty(); }
+
+ /** Clear contents. */
+ void Clear() { this->Entries.clear(); }
+
+ /** Return the name of this section. */
+ std::string GetName() const { return this->Name; }
+
+ /** Return a pointer to the first entry of this section. */
+ const std::vector<cmDocumentationEntry>& GetEntries() const
+ {
+ return this->Entries;
+ }
+
+ /** Append an entry to this section. */
+ void Append(const cmDocumentationEntry& entry)
+ {
+ this->Entries.push_back(entry);
+ }
+ void Append(const std::vector<cmDocumentationEntry>& entries)
+ {
+ cm::append(this->Entries, entries);
+ }
+
+ /** Append an entry to this section using NULL terminated chars */
+ void Append(const char* [][2]);
+ void Append(const char* n, const char* b);
+
+ /** prepend some documentation to this section */
+ void Prepend(const char* [][2]);
+ void Prepend(const std::vector<cmDocumentationEntry>& entries)
+ {
+ this->Entries.insert(this->Entries.begin(), entries.begin(),
+ entries.end());
+ }
+
+private:
+ std::string Name;
+ std::vector<cmDocumentationEntry> Entries;
+};
diff --git a/Source/cmDuration.cxx b/Source/cmDuration.cxx
new file mode 100644
index 0000000..8ca5d8d
--- /dev/null
+++ b/Source/cmDuration.cxx
@@ -0,0 +1,27 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#define CMDURATION_CPP
+#include "cmDuration.h"
+
+template <typename T>
+T cmDurationTo(const cmDuration& duration)
+{
+ /* This works because the comparison operators for duration rely on
+ * std::common_type.
+ * So for example duration<int>::max() gets promoted to a duration<double>,
+ * which can then be safely compared.
+ */
+ if (duration >= std::chrono::duration<T>::max()) {
+ return std::chrono::duration<T>::max().count();
+ }
+ if (duration <= std::chrono::duration<T>::min()) {
+ return std::chrono::duration<T>::min().count();
+ }
+ // Ensure number of seconds by defining ratio<1>
+ return std::chrono::duration_cast<std::chrono::duration<T, std::ratio<1>>>(
+ duration)
+ .count();
+}
+
+template int cmDurationTo<int>(const cmDuration&);
+template unsigned int cmDurationTo<unsigned int>(const cmDuration&);
diff --git a/Source/cmDuration.h b/Source/cmDuration.h
new file mode 100644
index 0000000..ccd1cc1
--- /dev/null
+++ b/Source/cmDuration.h
@@ -0,0 +1,24 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <chrono>
+#include <ratio>
+
+using cmDuration = std::chrono::duration<double, std::ratio<1>>;
+
+/*
+ * This function will return number of seconds in the requested type T.
+ *
+ * A duration_cast from duration<double> to duration<T> will not yield what
+ * one might expect if the double representation does not fit into type T.
+ * This function aims to safely convert, by clamping the double value between
+ * the permissible valid values for T.
+ */
+template <typename T>
+T cmDurationTo(const cmDuration& duration);
+
+#ifndef CMDURATION_CPP
+extern template int cmDurationTo<int>(const cmDuration&);
+extern template unsigned int cmDurationTo<unsigned int>(const cmDuration&);
+#endif
diff --git a/Source/cmDynamicLoader.cxx b/Source/cmDynamicLoader.cxx
new file mode 100644
index 0000000..a3731c1
--- /dev/null
+++ b/Source/cmDynamicLoader.cxx
@@ -0,0 +1,92 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmDynamicLoader.h"
+
+#include <map>
+#include <string>
+#include <utility>
+
+namespace {
+class cmDynamicLoaderCache
+{
+public:
+ ~cmDynamicLoaderCache();
+ void CacheFile(const char* path, cmsys::DynamicLoader::LibraryHandle /*p*/);
+ bool GetCacheFile(const char* path,
+ cmsys::DynamicLoader::LibraryHandle& /*p*/);
+ bool FlushCache(const char* path);
+ void FlushCache();
+ static cmDynamicLoaderCache& GetInstance();
+
+private:
+ std::map<std::string, cmsys::DynamicLoader::LibraryHandle> CacheMap;
+ static cmDynamicLoaderCache Instance;
+};
+
+cmDynamicLoaderCache cmDynamicLoaderCache::Instance;
+}
+
+cmDynamicLoaderCache::~cmDynamicLoaderCache() = default;
+
+void cmDynamicLoaderCache::CacheFile(const char* path,
+ cmsys::DynamicLoader::LibraryHandle p)
+{
+ cmsys::DynamicLoader::LibraryHandle h;
+ if (this->GetCacheFile(path, h)) {
+ this->FlushCache(path);
+ }
+ this->CacheMap[path] = p;
+}
+
+bool cmDynamicLoaderCache::GetCacheFile(const char* path,
+ cmsys::DynamicLoader::LibraryHandle& p)
+{
+ auto it = this->CacheMap.find(path);
+ if (it != this->CacheMap.end()) {
+ p = it->second;
+ return true;
+ }
+ return false;
+}
+
+bool cmDynamicLoaderCache::FlushCache(const char* path)
+{
+ auto it = this->CacheMap.find(path);
+ bool ret = false;
+ if (it != this->CacheMap.end()) {
+ cmsys::DynamicLoader::CloseLibrary(it->second);
+ this->CacheMap.erase(it);
+ ret = true;
+ }
+ return ret;
+}
+
+void cmDynamicLoaderCache::FlushCache()
+{
+ for (auto const& it : this->CacheMap) {
+ cmsys::DynamicLoader::CloseLibrary(it.second);
+ }
+ this->CacheMap.clear();
+}
+
+cmDynamicLoaderCache& cmDynamicLoaderCache::GetInstance()
+{
+ return cmDynamicLoaderCache::Instance;
+}
+
+cmsys::DynamicLoader::LibraryHandle cmDynamicLoader::OpenLibrary(
+ const char* libname)
+{
+ cmsys::DynamicLoader::LibraryHandle lh;
+ if (cmDynamicLoaderCache::GetInstance().GetCacheFile(libname, lh)) {
+ return lh;
+ }
+ lh = cmsys::DynamicLoader::OpenLibrary(libname);
+ cmDynamicLoaderCache::GetInstance().CacheFile(libname, lh);
+ return lh;
+}
+
+void cmDynamicLoader::FlushCache()
+{
+ cmDynamicLoaderCache::GetInstance().FlushCache();
+}
diff --git a/Source/cmDynamicLoader.h b/Source/cmDynamicLoader.h
new file mode 100644
index 0000000..53ea5cb
--- /dev/null
+++ b/Source/cmDynamicLoader.h
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+// .NAME cmDynamicLoader - class interface to system dynamic libraries
+// .SECTION Description
+// cmDynamicLoader provides a portable interface to loading dynamic
+// libraries into a process.
+
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmsys/DynamicLoader.hxx" // IWYU pragma: export
+
+class cmDynamicLoader
+{
+public:
+ // Description:
+ // Load a dynamic library into the current process.
+ // The returned cmsys::DynamicLoader::LibraryHandle can be used to access
+ // the symbols in the library.
+ static cmsys::DynamicLoader::LibraryHandle OpenLibrary(const char*);
+
+ // Description:
+ // Flush the cache of dynamic loader.
+ static void FlushCache();
+
+protected:
+ cmDynamicLoader() = default;
+ ~cmDynamicLoader() = default;
+};
diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx
new file mode 100644
index 0000000..deffdb6
--- /dev/null
+++ b/Source/cmELF.cxx
@@ -0,0 +1,840 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmELF.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cmext/algorithm>
+
+#include <cm3p/kwiml/abi.h>
+
+#include "cmsys/FStream.hxx"
+
+// Include the ELF format information system header.
+#if defined(__OpenBSD__)
+# include <elf_abi.h>
+#elif defined(__HAIKU__)
+# include <elf32.h>
+# include <elf64.h>
+using Elf32_Ehdr = struct Elf32_Ehdr;
+using Elf32_Shdr = struct Elf32_Shdr;
+using Elf32_Sym = struct Elf32_Sym;
+using Elf32_Rel = struct Elf32_Rel;
+using Elf32_Rela = struct Elf32_Rela;
+# define ELFMAG0 0x7F
+# define ELFMAG1 'E'
+# define ELFMAG2 'L'
+# define ELFMAG3 'F'
+# define ET_NONE 0
+# define ET_REL 1
+# define ET_EXEC 2
+# define ET_DYN 3
+# define ET_CORE 4
+# define EM_386 3
+# define EM_SPARC 2
+# define EM_PPC 20
+#else
+# include <elf.h>
+#endif
+#if defined(__sun)
+# include <sys/link.h> // For dynamic section information
+#endif
+#ifdef _SCO_DS
+# include <link.h> // For DT_SONAME etc.
+#endif
+#ifndef DT_RUNPATH
+# define DT_RUNPATH 29
+#endif
+
+// Low-level byte swapping implementation.
+template <size_t s>
+struct cmELFByteSwapSize
+{
+};
+void cmELFByteSwap(char* /*unused*/, cmELFByteSwapSize<1> /*unused*/)
+{
+}
+void cmELFByteSwap(char* data, cmELFByteSwapSize<2> /*unused*/)
+{
+ char one_byte;
+ one_byte = data[0];
+ data[0] = data[1];
+ data[1] = one_byte;
+}
+void cmELFByteSwap(char* data, cmELFByteSwapSize<4> /*unused*/)
+{
+ char one_byte;
+ one_byte = data[0];
+ data[0] = data[3];
+ data[3] = one_byte;
+ one_byte = data[1];
+ data[1] = data[2];
+ data[2] = one_byte;
+}
+void cmELFByteSwap(char* data, cmELFByteSwapSize<8> /*unused*/)
+{
+ char one_byte;
+ one_byte = data[0];
+ data[0] = data[7];
+ data[7] = one_byte;
+ one_byte = data[1];
+ data[1] = data[6];
+ data[6] = one_byte;
+ one_byte = data[2];
+ data[2] = data[5];
+ data[5] = one_byte;
+ one_byte = data[3];
+ data[3] = data[4];
+ data[4] = one_byte;
+}
+
+// Low-level byte swapping interface.
+template <typename T>
+void cmELFByteSwap(T& x)
+{
+ cmELFByteSwap(reinterpret_cast<char*>(&x), cmELFByteSwapSize<sizeof(T)>());
+}
+
+class cmELFInternal
+{
+public:
+ using StringEntry = cmELF::StringEntry;
+ enum ByteOrderType
+ {
+ ByteOrderMSB,
+ ByteOrderLSB
+ };
+
+ // Construct and take ownership of the file stream object.
+ cmELFInternal(cmELF* external, std::unique_ptr<std::istream> fin,
+ ByteOrderType order)
+ : External(external)
+ , Stream(std::move(fin))
+ , ByteOrder(order)
+ , ELFType(cmELF::FileTypeInvalid)
+ {
+// In most cases the processor-specific byte order will match that
+// of the target execution environment. If we choose wrong here
+// it is fixed when the header is read.
+#if KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_LITTLE
+ this->NeedSwap = (this->ByteOrder == ByteOrderMSB);
+#elif KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_BIG
+ this->NeedSwap = (this->ByteOrder == ByteOrderLSB);
+#else
+ this->NeedSwap = false; // Final decision is at runtime anyway.
+#endif
+
+ // We have not yet loaded the section info.
+ this->DynamicSectionIndex = -1;
+ }
+
+ // Destruct and delete the file stream object.
+ virtual ~cmELFInternal() = default;
+
+ // Forward to the per-class implementation.
+ virtual unsigned int GetNumberOfSections() const = 0;
+ virtual unsigned long GetDynamicEntryPosition(int j) = 0;
+ virtual cmELF::DynamicEntryList GetDynamicEntries() = 0;
+ virtual std::vector<char> EncodeDynamicEntries(
+ const cmELF::DynamicEntryList&) = 0;
+ virtual StringEntry const* GetDynamicSectionString(unsigned int tag) = 0;
+ virtual void PrintInfo(std::ostream& os) const = 0;
+
+ // Lookup the SONAME in the DYNAMIC section.
+ StringEntry const* GetSOName()
+ {
+ return this->GetDynamicSectionString(DT_SONAME);
+ }
+
+ // Lookup the RPATH in the DYNAMIC section.
+ StringEntry const* GetRPath()
+ {
+ return this->GetDynamicSectionString(DT_RPATH);
+ }
+
+ // Lookup the RUNPATH in the DYNAMIC section.
+ StringEntry const* GetRunPath()
+ {
+ return this->GetDynamicSectionString(DT_RUNPATH);
+ }
+
+ // Return the recorded ELF type.
+ cmELF::FileType GetFileType() const { return this->ELFType; }
+
+protected:
+ // Data common to all ELF class implementations.
+
+ // The external cmELF object.
+ cmELF* External;
+
+ // The stream from which to read.
+ std::unique_ptr<std::istream> Stream;
+
+ // The byte order of the ELF file.
+ ByteOrderType ByteOrder;
+
+ // The ELF file type.
+ cmELF::FileType ELFType;
+
+ // Whether we need to byte-swap structures read from the stream.
+ bool NeedSwap;
+
+ // The section header index of the DYNAMIC section (-1 if none).
+ int DynamicSectionIndex;
+
+ // Helper methods for subclasses.
+ void SetErrorMessage(const char* msg)
+ {
+ this->External->ErrorMessage = msg;
+ this->ELFType = cmELF::FileTypeInvalid;
+ }
+
+ // Store string table entry states.
+ std::map<unsigned int, StringEntry> DynamicSectionStrings;
+};
+
+// Configure the implementation template for 32-bit ELF files.
+struct cmELFTypes32
+{
+ using ELF_Ehdr = Elf32_Ehdr;
+ using ELF_Shdr = Elf32_Shdr;
+ using ELF_Dyn = Elf32_Dyn;
+ using ELF_Half = Elf32_Half;
+ using tagtype = ::uint32_t;
+ static const char* GetName() { return "32-bit"; }
+};
+
+// Configure the implementation template for 64-bit ELF files.
+#ifndef _SCO_DS
+struct cmELFTypes64
+{
+ using ELF_Ehdr = Elf64_Ehdr;
+ using ELF_Shdr = Elf64_Shdr;
+ using ELF_Dyn = Elf64_Dyn;
+ using ELF_Half = Elf64_Half;
+ using tagtype = ::uint64_t;
+ static const char* GetName() { return "64-bit"; }
+};
+#endif
+
+// Parser implementation template.
+template <class Types>
+class cmELFInternalImpl : public cmELFInternal
+{
+public:
+ // Copy the ELF file format types from our configuration parameter.
+ using ELF_Ehdr = typename Types::ELF_Ehdr;
+ using ELF_Shdr = typename Types::ELF_Shdr;
+ using ELF_Dyn = typename Types::ELF_Dyn;
+ using ELF_Half = typename Types::ELF_Half;
+ using tagtype = typename Types::tagtype;
+
+ // Construct with a stream and byte swap indicator.
+ cmELFInternalImpl(cmELF* external, std::unique_ptr<std::istream> fin,
+ ByteOrderType order);
+
+ // Return the number of sections as specified by the ELF header.
+ unsigned int GetNumberOfSections() const override
+ {
+ return static_cast<unsigned int>(this->ELFHeader.e_shnum);
+ }
+
+ // Get the file position of a dynamic section entry.
+ unsigned long GetDynamicEntryPosition(int j) override;
+
+ cmELF::DynamicEntryList GetDynamicEntries() override;
+ std::vector<char> EncodeDynamicEntries(
+ const cmELF::DynamicEntryList&) override;
+
+ // Lookup a string from the dynamic section with the given tag.
+ StringEntry const* GetDynamicSectionString(unsigned int tag) override;
+
+ // Print information about the ELF file.
+ void PrintInfo(std::ostream& os) const override
+ {
+ os << "ELF " << Types::GetName();
+ if (this->ByteOrder == ByteOrderMSB) {
+ os << " MSB";
+ } else if (this->ByteOrder == ByteOrderLSB) {
+ os << " LSB";
+ }
+ switch (this->ELFType) {
+ case cmELF::FileTypeInvalid:
+ os << " invalid file";
+ break;
+ case cmELF::FileTypeRelocatableObject:
+ os << " relocatable object";
+ break;
+ case cmELF::FileTypeExecutable:
+ os << " executable";
+ break;
+ case cmELF::FileTypeSharedLibrary:
+ os << " shared library";
+ break;
+ case cmELF::FileTypeCore:
+ os << " core file";
+ break;
+ case cmELF::FileTypeSpecificOS:
+ os << " os-specific type";
+ break;
+ case cmELF::FileTypeSpecificProc:
+ os << " processor-specific type";
+ break;
+ }
+ os << "\n";
+ }
+
+private:
+ static_assert(sizeof(ELF_Dyn().d_un.d_val) == sizeof(ELF_Dyn().d_un.d_ptr),
+ "ByteSwap(ELF_Dyn) assumes d_val and d_ptr are the same size");
+
+ void ByteSwap(ELF_Ehdr& elf_header)
+ {
+ cmELFByteSwap(elf_header.e_type);
+ cmELFByteSwap(elf_header.e_machine);
+ cmELFByteSwap(elf_header.e_version);
+ cmELFByteSwap(elf_header.e_entry);
+ cmELFByteSwap(elf_header.e_phoff);
+ cmELFByteSwap(elf_header.e_shoff);
+ cmELFByteSwap(elf_header.e_flags);
+ cmELFByteSwap(elf_header.e_ehsize);
+ cmELFByteSwap(elf_header.e_phentsize);
+ cmELFByteSwap(elf_header.e_phnum);
+ cmELFByteSwap(elf_header.e_shentsize);
+ cmELFByteSwap(elf_header.e_shnum);
+ cmELFByteSwap(elf_header.e_shstrndx);
+ }
+
+ void ByteSwap(ELF_Shdr& sec_header)
+ {
+ cmELFByteSwap(sec_header.sh_name);
+ cmELFByteSwap(sec_header.sh_type);
+ cmELFByteSwap(sec_header.sh_flags);
+ cmELFByteSwap(sec_header.sh_addr);
+ cmELFByteSwap(sec_header.sh_offset);
+ cmELFByteSwap(sec_header.sh_size);
+ cmELFByteSwap(sec_header.sh_link);
+ cmELFByteSwap(sec_header.sh_info);
+ cmELFByteSwap(sec_header.sh_addralign);
+ cmELFByteSwap(sec_header.sh_entsize);
+ }
+
+ void ByteSwap(ELF_Dyn& dyn)
+ {
+ cmELFByteSwap(dyn.d_tag);
+ cmELFByteSwap(dyn.d_un.d_val);
+ }
+
+ bool FileTypeValid(ELF_Half et)
+ {
+ unsigned int eti = static_cast<unsigned int>(et);
+ if (eti == ET_NONE || eti == ET_REL || eti == ET_EXEC || eti == ET_DYN ||
+ eti == ET_CORE) {
+ return true;
+ }
+#if defined(ET_LOOS) && defined(ET_HIOS)
+ if (eti >= ET_LOOS && eti <= ET_HIOS) {
+ return true;
+ }
+#endif
+#if defined(ET_LOPROC) && defined(ET_HIPROC)
+ if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
+ return true;
+ }
+#endif
+ return false;
+ }
+
+ bool Read(ELF_Ehdr& x)
+ {
+ // Read the header from the file.
+ if (!this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x))) {
+ return false;
+ }
+
+ // The byte order of ELF header fields may not match that of the
+ // processor-specific data. The header fields are ordered to
+ // match the target execution environment, so we may need to
+ // memorize the order of all platforms based on the e_machine
+ // value. As a heuristic, if the type is invalid but its
+ // swapped value is okay then flip our swap mode.
+ ELF_Half et = x.e_type;
+ if (this->NeedSwap) {
+ cmELFByteSwap(et);
+ }
+ if (!this->FileTypeValid(et)) {
+ cmELFByteSwap(et);
+ if (this->FileTypeValid(et)) {
+ // The previous byte order guess was wrong. Flip it.
+ this->NeedSwap = !this->NeedSwap;
+ }
+ }
+
+ // Fix the byte order of the header.
+ if (this->NeedSwap) {
+ this->ByteSwap(x);
+ }
+ return true;
+ }
+ bool Read(ELF_Shdr& x)
+ {
+ if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
+ this->NeedSwap) {
+ this->ByteSwap(x);
+ }
+ return !this->Stream->fail();
+ }
+ bool Read(ELF_Dyn& x)
+ {
+ if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
+ this->NeedSwap) {
+ this->ByteSwap(x);
+ }
+ return !this->Stream->fail();
+ }
+
+ bool LoadSectionHeader(ELF_Half i)
+ {
+ // Read the section header from the file.
+ this->Stream->seekg(this->ELFHeader.e_shoff +
+ this->ELFHeader.e_shentsize * i);
+ if (!this->Read(this->SectionHeaders[i])) {
+ return false;
+ }
+
+ // Identify some important sections.
+ if (this->SectionHeaders[i].sh_type == SHT_DYNAMIC) {
+ this->DynamicSectionIndex = i;
+ }
+ return true;
+ }
+
+ bool LoadDynamicSection();
+
+ // Store the main ELF header.
+ ELF_Ehdr ELFHeader;
+
+ // Store all the section headers.
+ std::vector<ELF_Shdr> SectionHeaders;
+
+ // Store all entries of the DYNAMIC section.
+ std::vector<ELF_Dyn> DynamicSectionEntries;
+};
+
+template <class Types>
+cmELFInternalImpl<Types>::cmELFInternalImpl(cmELF* external,
+ std::unique_ptr<std::istream> fin,
+ ByteOrderType order)
+ : cmELFInternal(external, std::move(fin), order)
+{
+ // Read the main header.
+ if (!this->Read(this->ELFHeader)) {
+ this->SetErrorMessage("Failed to read main ELF header.");
+ return;
+ }
+
+ // Determine the ELF file type.
+ switch (this->ELFHeader.e_type) {
+ case ET_NONE:
+ this->SetErrorMessage("ELF file type is NONE.");
+ return;
+ case ET_REL:
+ this->ELFType = cmELF::FileTypeRelocatableObject;
+ break;
+ case ET_EXEC:
+ this->ELFType = cmELF::FileTypeExecutable;
+ break;
+ case ET_DYN:
+ this->ELFType = cmELF::FileTypeSharedLibrary;
+ break;
+ case ET_CORE:
+ this->ELFType = cmELF::FileTypeCore;
+ break;
+ default: {
+ unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type);
+#if defined(ET_LOOS) && defined(ET_HIOS)
+ if (eti >= ET_LOOS && eti <= ET_HIOS) {
+ this->ELFType = cmELF::FileTypeSpecificOS;
+ break;
+ }
+#endif
+#if defined(ET_LOPROC) && defined(ET_HIPROC)
+ if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
+ this->ELFType = cmELF::FileTypeSpecificProc;
+ break;
+ }
+#endif
+ std::ostringstream e;
+ e << "Unknown ELF file type " << eti;
+ this->SetErrorMessage(e.str().c_str());
+ return;
+ }
+ }
+
+ // Load the section headers.
+ this->SectionHeaders.resize(this->ELFHeader.e_shnum);
+ for (ELF_Half i = 0; i < this->ELFHeader.e_shnum; ++i) {
+ if (!this->LoadSectionHeader(i)) {
+ this->SetErrorMessage("Failed to load section headers.");
+ return;
+ }
+ }
+}
+
+template <class Types>
+bool cmELFInternalImpl<Types>::LoadDynamicSection()
+{
+ // If there is no dynamic section we are done.
+ if (this->DynamicSectionIndex < 0) {
+ return false;
+ }
+
+ // If the section was already loaded we are done.
+ if (!this->DynamicSectionEntries.empty()) {
+ return true;
+ }
+
+ // If there are no entries we are done.
+ ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
+ if (sec.sh_entsize == 0) {
+ return false;
+ }
+
+ // Allocate the dynamic section entries.
+ int n = static_cast<int>(sec.sh_size / sec.sh_entsize);
+ this->DynamicSectionEntries.resize(n);
+
+ // Read each entry.
+ for (int j = 0; j < n; ++j) {
+ // Seek to the beginning of the section entry.
+ this->Stream->seekg(sec.sh_offset + sec.sh_entsize * j);
+ ELF_Dyn& dyn = this->DynamicSectionEntries[j];
+
+ // Try reading the entry.
+ if (!this->Read(dyn)) {
+ this->SetErrorMessage("Error reading entry from DYNAMIC section.");
+ this->DynamicSectionIndex = -1;
+ return false;
+ }
+ }
+ return true;
+}
+
+template <class Types>
+unsigned long cmELFInternalImpl<Types>::GetDynamicEntryPosition(int j)
+{
+ if (!this->LoadDynamicSection()) {
+ return 0;
+ }
+ if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) {
+ return 0;
+ }
+ ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
+ return static_cast<unsigned long>(sec.sh_offset + sec.sh_entsize * j);
+}
+
+template <class Types>
+cmELF::DynamicEntryList cmELFInternalImpl<Types>::GetDynamicEntries()
+{
+ cmELF::DynamicEntryList result;
+
+ // Ensure entries have been read from file
+ if (!this->LoadDynamicSection()) {
+ return result;
+ }
+
+ // Copy into public array
+ result.reserve(this->DynamicSectionEntries.size());
+ for (ELF_Dyn& dyn : this->DynamicSectionEntries) {
+ result.emplace_back(dyn.d_tag, dyn.d_un.d_val);
+ }
+
+ return result;
+}
+
+template <class Types>
+std::vector<char> cmELFInternalImpl<Types>::EncodeDynamicEntries(
+ const cmELF::DynamicEntryList& entries)
+{
+ std::vector<char> result;
+ result.reserve(sizeof(ELF_Dyn) * entries.size());
+
+ for (auto const& entry : entries) {
+ // Store the entry in an ELF_Dyn, byteswap it, then serialize to chars
+ ELF_Dyn dyn;
+ dyn.d_tag = static_cast<tagtype>(entry.first);
+ dyn.d_un.d_val = static_cast<tagtype>(entry.second);
+
+ if (this->NeedSwap) {
+ this->ByteSwap(dyn);
+ }
+
+ char* pdyn = reinterpret_cast<char*>(&dyn);
+ cm::append(result, pdyn, pdyn + sizeof(ELF_Dyn));
+ }
+
+ return result;
+}
+
+template <class Types>
+cmELF::StringEntry const* cmELFInternalImpl<Types>::GetDynamicSectionString(
+ unsigned int tag)
+{
+ // Short-circuit if already checked.
+ auto dssi = this->DynamicSectionStrings.find(tag);
+ if (dssi != this->DynamicSectionStrings.end()) {
+ if (dssi->second.Position > 0) {
+ return &dssi->second;
+ }
+ return nullptr;
+ }
+
+ // Create an entry for this tag. Assume it is missing until found.
+ StringEntry& se = this->DynamicSectionStrings[tag];
+ se.Position = 0;
+ se.Size = 0;
+ se.IndexInSection = -1;
+
+ // Try reading the dynamic section.
+ if (!this->LoadDynamicSection()) {
+ return nullptr;
+ }
+
+ // Get the string table referenced by the DYNAMIC section.
+ ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
+ if (sec.sh_link >= this->SectionHeaders.size()) {
+ this->SetErrorMessage("Section DYNAMIC has invalid string table index.");
+ return nullptr;
+ }
+ ELF_Shdr const& strtab = this->SectionHeaders[sec.sh_link];
+
+ // Look for the requested entry.
+ for (auto di = this->DynamicSectionEntries.begin();
+ di != this->DynamicSectionEntries.end(); ++di) {
+ ELF_Dyn& dyn = *di;
+ if (static_cast<tagtype>(dyn.d_tag) == static_cast<tagtype>(tag)) {
+ // We found the tag requested.
+ // Make sure the position given is within the string section.
+ if (dyn.d_un.d_val >= strtab.sh_size) {
+ this->SetErrorMessage("Section DYNAMIC references string beyond "
+ "the end of its string section.");
+ return nullptr;
+ }
+
+ // Seek to the position reported by the entry.
+ unsigned long first = static_cast<unsigned long>(dyn.d_un.d_val);
+ unsigned long last = first;
+ unsigned long end = static_cast<unsigned long>(strtab.sh_size);
+ this->Stream->seekg(strtab.sh_offset + first);
+
+ // Read the string. It may be followed by more than one NULL
+ // terminator. Count the total size of the region allocated to
+ // the string. This assumes that the next string in the table
+ // is non-empty, but the "chrpath" tool makes the same
+ // assumption.
+ bool terminated = false;
+ char c;
+ while (last != end && this->Stream->get(c) && !(terminated && c)) {
+ ++last;
+ if (c) {
+ se.Value += c;
+ } else {
+ terminated = true;
+ }
+ }
+
+ // Make sure the whole value was read.
+ if (!(*this->Stream)) {
+ this->SetErrorMessage("Dynamic section specifies unreadable RPATH.");
+ se.Value = "";
+ return nullptr;
+ }
+
+ // The value has been read successfully. Report it.
+ se.Position = static_cast<unsigned long>(strtab.sh_offset + first);
+ se.Size = last - first;
+ se.IndexInSection =
+ static_cast<int>(di - this->DynamicSectionEntries.begin());
+ return &se;
+ }
+ }
+ return nullptr;
+}
+
+//============================================================================
+// External class implementation.
+
+const long cmELF::TagRPath = DT_RPATH;
+const long cmELF::TagRunPath = DT_RUNPATH;
+
+#ifdef DT_MIPS_RLD_MAP_REL
+const long cmELF::TagMipsRldMapRel = DT_MIPS_RLD_MAP_REL;
+#else
+const long cmELF::TagMipsRldMapRel = 0;
+#endif
+
+cmELF::cmELF(const char* fname)
+{
+ // Try to open the file.
+ auto fin = cm::make_unique<cmsys::ifstream>(fname);
+
+ // Quit now if the file could not be opened.
+ if (!fin || !*fin) {
+ this->ErrorMessage = "Error opening input file.";
+ return;
+ }
+
+ // Read the ELF identification block.
+ char ident[EI_NIDENT];
+ if (!fin->read(ident, EI_NIDENT)) {
+ this->ErrorMessage = "Error reading ELF identification.";
+ return;
+ }
+ if (!fin->seekg(0)) {
+ this->ErrorMessage = "Error seeking to beginning of file.";
+ return;
+ }
+
+ // Verify the ELF identification.
+ if (!(ident[EI_MAG0] == ELFMAG0 && ident[EI_MAG1] == ELFMAG1 &&
+ ident[EI_MAG2] == ELFMAG2 && ident[EI_MAG3] == ELFMAG3)) {
+ this->ErrorMessage = "File does not have a valid ELF identification.";
+ return;
+ }
+
+ // Check the byte order in which the rest of the file is encoded.
+ cmELFInternal::ByteOrderType order;
+ if (ident[EI_DATA] == ELFDATA2LSB) {
+ // File is LSB.
+ order = cmELFInternal::ByteOrderLSB;
+ } else if (ident[EI_DATA] == ELFDATA2MSB) {
+ // File is MSB.
+ order = cmELFInternal::ByteOrderMSB;
+ } else {
+ this->ErrorMessage = "ELF file is not LSB or MSB encoded.";
+ return;
+ }
+
+ // Check the class of the file and construct the corresponding
+ // parser implementation.
+ if (ident[EI_CLASS] == ELFCLASS32) {
+ // 32-bit ELF
+ this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes32>>(
+ this, std::move(fin), order);
+ }
+#ifndef _SCO_DS
+ else if (ident[EI_CLASS] == ELFCLASS64) {
+ // 64-bit ELF
+ this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes64>>(
+ this, std::move(fin), order);
+ }
+#endif
+ else {
+ this->ErrorMessage = "ELF file class is not 32-bit or 64-bit.";
+ return;
+ }
+}
+
+cmELF::~cmELF() = default;
+
+bool cmELF::Valid() const
+{
+ return this->Internal && this->Internal->GetFileType() != FileTypeInvalid;
+}
+
+cmELF::FileType cmELF::GetFileType() const
+{
+ if (this->Valid()) {
+ return this->Internal->GetFileType();
+ }
+ return FileTypeInvalid;
+}
+
+unsigned int cmELF::GetNumberOfSections() const
+{
+ if (this->Valid()) {
+ return this->Internal->GetNumberOfSections();
+ }
+ return 0;
+}
+
+unsigned long cmELF::GetDynamicEntryPosition(int index) const
+{
+ if (this->Valid()) {
+ return this->Internal->GetDynamicEntryPosition(index);
+ }
+ return 0;
+}
+
+cmELF::DynamicEntryList cmELF::GetDynamicEntries() const
+{
+ if (this->Valid()) {
+ return this->Internal->GetDynamicEntries();
+ }
+
+ return cmELF::DynamicEntryList();
+}
+
+std::vector<char> cmELF::EncodeDynamicEntries(
+ const cmELF::DynamicEntryList& dentries) const
+{
+ if (this->Valid()) {
+ return this->Internal->EncodeDynamicEntries(dentries);
+ }
+
+ return std::vector<char>();
+}
+
+bool cmELF::GetSOName(std::string& soname)
+{
+ if (StringEntry const* se = this->GetSOName()) {
+ soname = se->Value;
+ return true;
+ }
+ return false;
+}
+
+cmELF::StringEntry const* cmELF::GetSOName()
+{
+ if (this->Valid() &&
+ this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary) {
+ return this->Internal->GetSOName();
+ }
+ return nullptr;
+}
+
+cmELF::StringEntry const* cmELF::GetRPath()
+{
+ if (this->Valid() &&
+ (this->Internal->GetFileType() == cmELF::FileTypeExecutable ||
+ this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) {
+ return this->Internal->GetRPath();
+ }
+ return nullptr;
+}
+
+cmELF::StringEntry const* cmELF::GetRunPath()
+{
+ if (this->Valid() &&
+ (this->Internal->GetFileType() == cmELF::FileTypeExecutable ||
+ this->Internal->GetFileType() == cmELF::FileTypeSharedLibrary)) {
+ return this->Internal->GetRunPath();
+ }
+ return nullptr;
+}
+
+void cmELF::PrintInfo(std::ostream& os) const
+{
+ if (this->Valid()) {
+ this->Internal->PrintInfo(os);
+ } else {
+ os << "Not a valid ELF file.\n";
+ }
+}
diff --git a/Source/cmELF.h b/Source/cmELF.h
new file mode 100644
index 0000000..c479e2b
--- /dev/null
+++ b/Source/cmELF.h
@@ -0,0 +1,113 @@
+/* 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 <iosfwd>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#if !defined(CMake_USE_ELF_PARSER)
+# error "This file may be included only if CMake_USE_ELF_PARSER is enabled."
+#endif
+
+class cmELFInternal;
+
+/** \class cmELF
+ * \brief Executable and Link Format (ELF) parser.
+ */
+class cmELF
+{
+public:
+ /** Construct with the name of the ELF input file to parse. */
+ cmELF(const char* fname);
+
+ /** Destruct. */
+ ~cmELF();
+
+ cmELF(const cmELF&) = delete;
+ cmELF& operator=(const cmELF&) = delete;
+
+ /** Get the error message if any. */
+ std::string const& GetErrorMessage() const { return this->ErrorMessage; }
+
+ /** Boolean conversion. True if the ELF file is valid. */
+ explicit operator bool() const { return this->Valid(); }
+
+ /** Enumeration of ELF file types. */
+ enum FileType
+ {
+ FileTypeInvalid,
+ FileTypeRelocatableObject,
+ FileTypeExecutable,
+ FileTypeSharedLibrary,
+ FileTypeCore,
+ FileTypeSpecificOS,
+ FileTypeSpecificProc
+ };
+
+ /** Represent string table entries. */
+ struct StringEntry
+ {
+ // The string value itself.
+ std::string Value;
+
+ // The position in the file at which the string appears.
+ unsigned long Position;
+
+ // The size of the string table entry. This includes the space
+ // allocated for one or more null terminators.
+ unsigned long Size;
+
+ // The index of the section entry referencing the string.
+ int IndexInSection;
+ };
+
+ /** Represent entire dynamic section header */
+ using DynamicEntryList = std::vector<std::pair<long, unsigned long>>;
+
+ /** Get the type of the file opened. */
+ FileType GetFileType() const;
+
+ /** Get the number of ELF sections present. */
+ unsigned int GetNumberOfSections() const;
+
+ /** Get the position of a DYNAMIC section header entry. Returns
+ zero on error. */
+ unsigned long GetDynamicEntryPosition(int index) const;
+
+ /** Get a copy of all the DYNAMIC section header entries.
+ Returns an empty vector on error */
+ DynamicEntryList GetDynamicEntries() const;
+
+ /** Encodes a DYNAMIC section header entry list into a char vector according
+ to the type of ELF file this is */
+ std::vector<char> EncodeDynamicEntries(
+ const DynamicEntryList& entries) const;
+
+ /** Get the SONAME field if any. */
+ bool GetSOName(std::string& soname);
+ StringEntry const* GetSOName();
+
+ /** Get the RPATH field if any. */
+ StringEntry const* GetRPath();
+
+ /** Get the RUNPATH field if any. */
+ StringEntry const* GetRunPath();
+
+ /** Print human-readable information about the ELF file. */
+ void PrintInfo(std::ostream& os) const;
+
+ /** Interesting dynamic tags.
+ If the tag is 0, it does not exist in the host ELF implementation */
+ static const long TagRPath, TagRunPath, TagMipsRldMapRel;
+
+private:
+ friend class cmELFInternal;
+ bool Valid() const;
+ std::unique_ptr<cmELFInternal> Internal;
+ std::string ErrorMessage;
+};
diff --git a/Source/cmEnableLanguageCommand.cxx b/Source/cmEnableLanguageCommand.cxx
new file mode 100644
index 0000000..59522c0
--- /dev/null
+++ b/Source/cmEnableLanguageCommand.cxx
@@ -0,0 +1,28 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmEnableLanguageCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+
+bool cmEnableLanguageCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ bool optional = false;
+ std::vector<std::string> languages;
+ for (std::string const& it : args) {
+ if (it == "OPTIONAL") {
+ optional = true;
+ } else {
+ languages.push_back(it);
+ }
+ }
+
+ status.GetMakefile().EnableLanguage(languages, optional);
+ return true;
+}
diff --git a/Source/cmEnableLanguageCommand.h b/Source/cmEnableLanguageCommand.h
new file mode 100644
index 0000000..730ba65
--- /dev/null
+++ b/Source/cmEnableLanguageCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmEnableLanguageCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmEnableTestingCommand.cxx b/Source/cmEnableTestingCommand.cxx
new file mode 100644
index 0000000..89212c8
--- /dev/null
+++ b/Source/cmEnableTestingCommand.cxx
@@ -0,0 +1,13 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmEnableTestingCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+
+bool cmEnableTestingCommand(std::vector<std::string> const&,
+ cmExecutionStatus& status)
+{
+ status.GetMakefile().AddDefinition("CMAKE_TESTING_ENABLED", "1");
+ return true;
+}
diff --git a/Source/cmEnableTestingCommand.h b/Source/cmEnableTestingCommand.h
new file mode 100644
index 0000000..1722511
--- /dev/null
+++ b/Source/cmEnableTestingCommand.h
@@ -0,0 +1,26 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Enable testing for this directory and below.
+ *
+ * Produce the output testfile. This produces a file in the build directory
+ * called CMakeTestfile with a syntax similar to CMakeLists.txt. It contains
+ * the SUBDIRS() and ADD_TEST() commands from the source CMakeLists.txt
+ * file with CMake variables expanded. Only the subdirs and tests
+ * within the valid control structures are replicated in Testfile
+ * (i.e. SUBDIRS() and ADD_TEST() commands within IF() commands that are
+ * not entered by CMake are not replicated in Testfile).
+ * Note that CTest expects to find this file in the build directory root;
+ * therefore, this command should be in the source directory root too.
+ */
+bool cmEnableTestingCommand(std::vector<std::string> const&,
+ cmExecutionStatus&);
diff --git a/Source/cmExecProgramCommand.cxx b/Source/cmExecProgramCommand.cxx
new file mode 100644
index 0000000..51fb219
--- /dev/null
+++ b/Source/cmExecProgramCommand.cxx
@@ -0,0 +1,290 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExecProgramCommand.h"
+
+#include <cstdio>
+
+#include "cmsys/Process.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmProcessOutput.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+using Encoding = cmProcessOutput::Encoding;
+
+namespace {
+bool RunCommand(std::string command, std::string& output, int& retVal,
+ const char* directory = nullptr, bool verbose = true,
+ Encoding encoding = cmProcessOutput::Auto);
+}
+
+// cmExecProgramCommand
+bool cmExecProgramCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ std::string arguments;
+ bool doingargs = false;
+ int count = 0;
+ std::string output_variable;
+ bool haveoutput_variable = false;
+ std::string return_variable;
+ bool havereturn_variable = false;
+ for (std::string const& arg : args) {
+ if (arg == "OUTPUT_VARIABLE") {
+ count++;
+ doingargs = false;
+ havereturn_variable = false;
+ haveoutput_variable = true;
+ } else if (haveoutput_variable) {
+ if (!output_variable.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ output_variable = arg;
+ haveoutput_variable = false;
+ count++;
+ } else if (arg == "RETURN_VALUE") {
+ count++;
+ doingargs = false;
+ haveoutput_variable = false;
+ havereturn_variable = true;
+ } else if (havereturn_variable) {
+ if (!return_variable.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ return_variable = arg;
+ havereturn_variable = false;
+ count++;
+ } else if (arg == "ARGS") {
+ count++;
+ havereturn_variable = false;
+ haveoutput_variable = false;
+ doingargs = true;
+ } else if (doingargs) {
+ arguments += arg;
+ arguments += " ";
+ count++;
+ }
+ }
+
+ std::string command;
+ if (!arguments.empty()) {
+ command = cmStrCat(cmSystemTools::ConvertToRunCommandPath(args[0]), ' ',
+ arguments);
+ } else {
+ command = args[0];
+ }
+ bool verbose = true;
+ if (!output_variable.empty()) {
+ verbose = false;
+ }
+ int retVal = 0;
+ std::string output;
+ bool result = true;
+ if (args.size() - count == 2) {
+ cmSystemTools::MakeDirectory(args[1]);
+ result = RunCommand(command, output, retVal, args[1].c_str(), verbose);
+ } else {
+ result = RunCommand(command, output, retVal, nullptr, verbose);
+ }
+ if (!result) {
+ retVal = -1;
+ }
+
+ if (!output_variable.empty()) {
+ std::string::size_type first = output.find_first_not_of(" \n\t\r");
+ std::string::size_type last = output.find_last_not_of(" \n\t\r");
+ if (first == std::string::npos) {
+ first = 0;
+ }
+ if (last == std::string::npos) {
+ last = output.size() - 1;
+ }
+
+ std::string coutput = std::string(output, first, last - first + 1);
+ status.GetMakefile().AddDefinition(output_variable, coutput);
+ }
+
+ if (!return_variable.empty()) {
+ char buffer[100];
+ sprintf(buffer, "%d", retVal);
+ status.GetMakefile().AddDefinition(return_variable, buffer);
+ }
+
+ return true;
+}
+
+namespace {
+bool RunCommand(std::string command, std::string& output, int& retVal,
+ const char* dir, bool verbose, Encoding encoding)
+{
+ if (cmSystemTools::GetRunCommandOutput()) {
+ verbose = false;
+ }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // if the command does not start with a quote, then
+ // try to find the program, and if the program can not be
+ // found use system to run the command as it must be a built in
+ // shell command like echo or dir
+ if (!command.empty() && command[0] == '\"') {
+ // count the number of quotes
+ int count = 0;
+ for (char c : command) {
+ if (c == '\"') {
+ count++;
+ if (count > 2) {
+ break;
+ }
+ }
+ }
+ // if there are more than two double quotes use
+ // GetShortPathName, the cmd.exe program in windows which
+ // is used by system fails to execute if there are more than
+ // one set of quotes in the arguments
+ if (count > 2) {
+ cmsys::RegularExpression quoted("^\"([^\"]*)\"[ \t](.*)");
+ if (quoted.find(command)) {
+ std::string shortCmd;
+ std::string cmd = quoted.match(1);
+ std::string args = quoted.match(2);
+ if (!cmSystemTools::FileExists(cmd)) {
+ shortCmd = cmd;
+ } else if (!cmSystemTools::GetShortPath(cmd, shortCmd)) {
+ cmSystemTools::Error("GetShortPath failed for " + cmd);
+ return false;
+ }
+ shortCmd += " ";
+ shortCmd += args;
+
+ command = shortCmd;
+ } else {
+ cmSystemTools::Error("Could not parse command line with quotes " +
+ command);
+ }
+ }
+ }
+#endif
+
+ // Allocate a process instance.
+ cmsysProcess* cp = cmsysProcess_New();
+ if (!cp) {
+ cmSystemTools::Error("Error allocating process instance.");
+ return false;
+ }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (dir) {
+ cmsysProcess_SetWorkingDirectory(cp, dir);
+ }
+ if (cmSystemTools::GetRunCommandHideConsole()) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ }
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);
+ const char* cmd[] = { command.c_str(), nullptr };
+ cmsysProcess_SetCommand(cp, cmd);
+#else
+ std::string commandInDir;
+ if (dir) {
+ commandInDir = cmStrCat("cd \"", dir, "\" && ", command);
+ } else {
+ commandInDir = command;
+ }
+# ifndef __VMS
+ commandInDir += " 2>&1";
+# endif
+ command = commandInDir;
+ if (verbose) {
+ cmSystemTools::Stdout("running ");
+ cmSystemTools::Stdout(command);
+ cmSystemTools::Stdout("\n");
+ }
+ fflush(stdout);
+ fflush(stderr);
+ const char* cmd[] = { "/bin/sh", "-c", command.c_str(), nullptr };
+ cmsysProcess_SetCommand(cp, cmd);
+#endif
+
+ cmsysProcess_Execute(cp);
+
+ // Read the process output.
+ int length;
+ char* data;
+ int p;
+ cmProcessOutput processOutput(encoding);
+ std::string strdata;
+ while ((p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) {
+ if (p == cmsysProcess_Pipe_STDOUT || p == cmsysProcess_Pipe_STDERR) {
+ if (verbose) {
+ processOutput.DecodeText(data, length, strdata);
+ cmSystemTools::Stdout(strdata);
+ }
+ output.append(data, length);
+ }
+ }
+
+ if (verbose) {
+ processOutput.DecodeText(std::string(), strdata);
+ if (!strdata.empty()) {
+ cmSystemTools::Stdout(strdata);
+ }
+ }
+
+ // All output has been read. Wait for the process to exit.
+ cmsysProcess_WaitForExit(cp, nullptr);
+ processOutput.DecodeText(output, output);
+
+ // Check the result of running the process.
+ std::string msg;
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Exited:
+ retVal = cmsysProcess_GetExitValue(cp);
+ break;
+ case cmsysProcess_State_Exception:
+ retVal = -1;
+ msg += "\nProcess terminated due to: ";
+ msg += cmsysProcess_GetExceptionString(cp);
+ break;
+ case cmsysProcess_State_Error:
+ retVal = -1;
+ msg += "\nProcess failed because: ";
+ msg += cmsysProcess_GetErrorString(cp);
+ break;
+ case cmsysProcess_State_Expired:
+ retVal = -1;
+ msg += "\nProcess terminated due to timeout.";
+ break;
+ }
+ if (!msg.empty()) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // Old Windows process execution printed this info.
+ msg += "\n\nfor command: ";
+ msg += command;
+ if (dir) {
+ msg += "\nin dir: ";
+ msg += dir;
+ }
+ msg += "\n";
+ if (verbose) {
+ cmSystemTools::Stdout(msg);
+ }
+ output += msg;
+#else
+ // Old UNIX process execution only put message in output.
+ output += msg;
+#endif
+ }
+
+ // Delete the process instance.
+ cmsysProcess_Delete(cp);
+
+ return true;
+}
+}
diff --git a/Source/cmExecProgramCommand.h b/Source/cmExecProgramCommand.h
new file mode 100644
index 0000000..111a56e
--- /dev/null
+++ b/Source/cmExecProgramCommand.h
@@ -0,0 +1,20 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Command that adds a target to the build system.
+ *
+ * cmExecProgramCommand adds an extra target to the build system.
+ * This is useful when you would like to add special
+ * targets like "install,", "clean," and so on.
+ */
+bool cmExecProgramCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
new file mode 100644
index 0000000..ffcc415
--- /dev/null
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -0,0 +1,527 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExecuteProcessCommand.h"
+
+#include <algorithm>
+#include <cctype> /* isspace */
+#include <cstdio>
+#include <iostream>
+#include <map>
+#include <memory>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include <cm/string_view>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmsys/Process.h"
+
+#include "cmArgumentParser.h"
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProcessOutput.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+bool cmExecuteProcessCommandIsWhitespace(char c)
+{
+ return (isspace(static_cast<int>(c)) || c == '\n' || c == '\r');
+}
+
+void cmExecuteProcessCommandFixText(std::vector<char>& output,
+ bool strip_trailing_whitespace);
+void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data,
+ int length);
+}
+
+// cmExecuteProcessCommand
+bool cmExecuteProcessCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ struct Arguments
+ {
+ std::vector<std::vector<std::string>> Commands;
+ std::string OutputVariable;
+ std::string ErrorVariable;
+ std::string ResultVariable;
+ std::string ResultsVariable;
+ std::string WorkingDirectory;
+ std::string InputFile;
+ std::string OutputFile;
+ std::string ErrorFile;
+ std::string Timeout;
+ std::string CommandEcho;
+ bool OutputQuiet = false;
+ bool ErrorQuiet = false;
+ bool OutputStripTrailingWhitespace = false;
+ bool ErrorStripTrailingWhitespace = false;
+ bool EchoOutputVariable = false;
+ bool EchoErrorVariable = false;
+ std::string Encoding;
+ std::string CommandErrorIsFatal;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("COMMAND"_s, &Arguments::Commands)
+ .Bind("COMMAND_ECHO"_s, &Arguments::CommandEcho)
+ .Bind("OUTPUT_VARIABLE"_s, &Arguments::OutputVariable)
+ .Bind("ERROR_VARIABLE"_s, &Arguments::ErrorVariable)
+ .Bind("RESULT_VARIABLE"_s, &Arguments::ResultVariable)
+ .Bind("RESULTS_VARIABLE"_s, &Arguments::ResultsVariable)
+ .Bind("WORKING_DIRECTORY"_s, &Arguments::WorkingDirectory)
+ .Bind("INPUT_FILE"_s, &Arguments::InputFile)
+ .Bind("OUTPUT_FILE"_s, &Arguments::OutputFile)
+ .Bind("ERROR_FILE"_s, &Arguments::ErrorFile)
+ .Bind("TIMEOUT"_s, &Arguments::Timeout)
+ .Bind("OUTPUT_QUIET"_s, &Arguments::OutputQuiet)
+ .Bind("ERROR_QUIET"_s, &Arguments::ErrorQuiet)
+ .Bind("OUTPUT_STRIP_TRAILING_WHITESPACE"_s,
+ &Arguments::OutputStripTrailingWhitespace)
+ .Bind("ERROR_STRIP_TRAILING_WHITESPACE"_s,
+ &Arguments::ErrorStripTrailingWhitespace)
+ .Bind("ENCODING"_s, &Arguments::Encoding)
+ .Bind("ECHO_OUTPUT_VARIABLE"_s, &Arguments::EchoOutputVariable)
+ .Bind("ECHO_ERROR_VARIABLE"_s, &Arguments::EchoErrorVariable)
+ .Bind("COMMAND_ERROR_IS_FATAL"_s, &Arguments::CommandErrorIsFatal);
+
+ std::vector<std::string> unparsedArguments;
+ std::vector<std::string> keywordsMissingValue;
+ Arguments const arguments =
+ parser.Parse(args, &unparsedArguments, &keywordsMissingValue);
+
+ if (!keywordsMissingValue.empty()) {
+ status.SetError(" called with no value for " +
+ keywordsMissingValue.front() + ".");
+ return false;
+ }
+ if (!unparsedArguments.empty()) {
+ status.SetError(" given unknown argument \"" + unparsedArguments.front() +
+ "\".");
+ return false;
+ }
+
+ if (!status.GetMakefile().CanIWriteThisFile(arguments.OutputFile)) {
+ status.SetError("attempted to output into a file: " +
+ arguments.OutputFile + " into a source directory.");
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ // Check for commands given.
+ if (arguments.Commands.empty()) {
+ status.SetError(" called with no COMMAND argument.");
+ return false;
+ }
+ for (std::vector<std::string> const& cmd : arguments.Commands) {
+ if (cmd.empty()) {
+ status.SetError(" given COMMAND argument with no value.");
+ return false;
+ }
+ }
+
+ // Parse the timeout string.
+ double timeout = -1;
+ if (!arguments.Timeout.empty()) {
+ if (sscanf(arguments.Timeout.c_str(), "%lg", &timeout) != 1) {
+ status.SetError(" called with TIMEOUT value that could not be parsed.");
+ return false;
+ }
+ }
+
+ if (!arguments.CommandErrorIsFatal.empty()) {
+ if (arguments.CommandErrorIsFatal != "ANY"_s &&
+ arguments.CommandErrorIsFatal != "LAST"_s) {
+ status.SetError("COMMAND_ERROR_IS_FATAL option can be ANY or LAST");
+ return false;
+ }
+ }
+ // Create a process instance.
+ std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp_ptr(
+ cmsysProcess_New(), cmsysProcess_Delete);
+ cmsysProcess* cp = cp_ptr.get();
+
+ // Set the command sequence.
+ for (std::vector<std::string> const& cmd : arguments.Commands) {
+ std::vector<const char*> argv(cmd.size() + 1);
+ std::transform(cmd.begin(), cmd.end(), argv.begin(),
+ [](std::string const& s) { return s.c_str(); });
+ argv.back() = nullptr;
+ cmsysProcess_AddCommand(cp, argv.data());
+ }
+
+ // Set the process working directory.
+ if (!arguments.WorkingDirectory.empty()) {
+ cmsysProcess_SetWorkingDirectory(cp, arguments.WorkingDirectory.c_str());
+ }
+
+ // Always hide the process window.
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+
+ // Check the output variables.
+ bool merge_output = false;
+ if (!arguments.InputFile.empty()) {
+ cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN,
+ arguments.InputFile.c_str());
+ }
+ if (!arguments.OutputFile.empty()) {
+ cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDOUT,
+ arguments.OutputFile.c_str());
+ }
+ if (!arguments.ErrorFile.empty()) {
+ if (arguments.ErrorFile == arguments.OutputFile) {
+ merge_output = true;
+ } else {
+ cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR,
+ arguments.ErrorFile.c_str());
+ }
+ }
+ if (!arguments.OutputVariable.empty() &&
+ arguments.OutputVariable == arguments.ErrorVariable) {
+ merge_output = true;
+ }
+ if (merge_output) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_MergeOutput, 1);
+ }
+
+ // Set the timeout if any.
+ if (timeout >= 0) {
+ cmsysProcess_SetTimeout(cp, timeout);
+ }
+
+ bool echo_stdout = false;
+ bool echo_stderr = false;
+ bool echo_output_from_variable = true;
+ std::string echo_output = status.GetMakefile().GetSafeDefinition(
+ "CMAKE_EXECUTE_PROCESS_COMMAND_ECHO");
+ if (!arguments.CommandEcho.empty()) {
+ echo_output_from_variable = false;
+ echo_output = arguments.CommandEcho;
+ }
+
+ if (!echo_output.empty()) {
+ if (echo_output == "STDERR") {
+ echo_stderr = true;
+ } else if (echo_output == "STDOUT") {
+ echo_stdout = true;
+ } else if (echo_output != "NONE") {
+ std::string error;
+ if (echo_output_from_variable) {
+ error = "CMAKE_EXECUTE_PROCESS_COMMAND_ECHO set to '";
+ } else {
+ error = " called with '";
+ }
+ error += echo_output;
+ error += "' expected STDERR|STDOUT|NONE";
+ if (!echo_output_from_variable) {
+ error += " for COMMAND_ECHO.";
+ }
+ status.GetMakefile().IssueMessage(MessageType::FATAL_ERROR, error);
+ return true;
+ }
+ }
+ if (echo_stdout || echo_stderr) {
+ std::string command;
+ for (const auto& cmd : arguments.Commands) {
+ command += "'";
+ command += cmJoin(cmd, "' '");
+ command += "'";
+ command += "\n";
+ }
+ if (echo_stdout) {
+ std::cout << command;
+ } else if (echo_stderr) {
+ std::cerr << command;
+ }
+ }
+ // Start the process.
+ cmsysProcess_Execute(cp);
+
+ // Read the process output.
+ std::vector<char> tempOutput;
+ std::vector<char> tempError;
+ int length;
+ char* data;
+ int p;
+ cmProcessOutput processOutput(
+ cmProcessOutput::FindEncoding(arguments.Encoding));
+ std::string strdata;
+ while ((p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) {
+ // Put the output in the right place.
+ if (p == cmsysProcess_Pipe_STDOUT && !arguments.OutputQuiet) {
+ if (arguments.OutputVariable.empty() || arguments.EchoOutputVariable) {
+ processOutput.DecodeText(data, length, strdata, 1);
+ cmSystemTools::Stdout(strdata);
+ }
+ if (!arguments.OutputVariable.empty()) {
+ cmExecuteProcessCommandAppend(tempOutput, data, length);
+ }
+ } else if (p == cmsysProcess_Pipe_STDERR && !arguments.ErrorQuiet) {
+ if (arguments.ErrorVariable.empty() || arguments.EchoErrorVariable) {
+ processOutput.DecodeText(data, length, strdata, 2);
+ cmSystemTools::Stderr(strdata);
+ }
+ if (!arguments.ErrorVariable.empty()) {
+ cmExecuteProcessCommandAppend(tempError, data, length);
+ }
+ }
+ }
+ if (!arguments.OutputQuiet &&
+ (arguments.OutputVariable.empty() || arguments.EchoOutputVariable)) {
+ processOutput.DecodeText(std::string(), strdata, 1);
+ if (!strdata.empty()) {
+ cmSystemTools::Stdout(strdata);
+ }
+ }
+ if (!arguments.ErrorQuiet &&
+ (arguments.ErrorVariable.empty() || arguments.EchoErrorVariable)) {
+ processOutput.DecodeText(std::string(), strdata, 2);
+ if (!strdata.empty()) {
+ cmSystemTools::Stderr(strdata);
+ }
+ }
+
+ // All output has been read. Wait for the process to exit.
+ cmsysProcess_WaitForExit(cp, nullptr);
+ processOutput.DecodeText(tempOutput, tempOutput);
+ processOutput.DecodeText(tempError, tempError);
+
+ // Fix the text in the output strings.
+ cmExecuteProcessCommandFixText(tempOutput,
+ arguments.OutputStripTrailingWhitespace);
+ cmExecuteProcessCommandFixText(tempError,
+ arguments.ErrorStripTrailingWhitespace);
+
+ // Store the output obtained.
+ if (!arguments.OutputVariable.empty() && !tempOutput.empty()) {
+ status.GetMakefile().AddDefinition(arguments.OutputVariable,
+ tempOutput.data());
+ }
+ if (!merge_output && !arguments.ErrorVariable.empty() &&
+ !tempError.empty()) {
+ status.GetMakefile().AddDefinition(arguments.ErrorVariable,
+ tempError.data());
+ }
+
+ // Store the result of running the process.
+ if (!arguments.ResultVariable.empty()) {
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Exited: {
+ int v = cmsysProcess_GetExitValue(cp);
+ char buf[16];
+ sprintf(buf, "%d", v);
+ status.GetMakefile().AddDefinition(arguments.ResultVariable, buf);
+ } break;
+ case cmsysProcess_State_Exception:
+ status.GetMakefile().AddDefinition(
+ arguments.ResultVariable, cmsysProcess_GetExceptionString(cp));
+ break;
+ case cmsysProcess_State_Error:
+ status.GetMakefile().AddDefinition(arguments.ResultVariable,
+ cmsysProcess_GetErrorString(cp));
+ break;
+ case cmsysProcess_State_Expired:
+ status.GetMakefile().AddDefinition(
+ arguments.ResultVariable, "Process terminated due to timeout");
+ break;
+ }
+ }
+ // Store the result of running the processes.
+ if (!arguments.ResultsVariable.empty()) {
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Exited: {
+ std::vector<std::string> res;
+ for (size_t i = 0; i < arguments.Commands.size(); ++i) {
+ switch (cmsysProcess_GetStateByIndex(cp, static_cast<int>(i))) {
+ case kwsysProcess_StateByIndex_Exited: {
+ int exitCode =
+ cmsysProcess_GetExitValueByIndex(cp, static_cast<int>(i));
+ char buf[16];
+ sprintf(buf, "%d", exitCode);
+ res.emplace_back(buf);
+ } break;
+ case kwsysProcess_StateByIndex_Exception:
+ res.emplace_back(cmsysProcess_GetExceptionStringByIndex(
+ cp, static_cast<int>(i)));
+ break;
+ case kwsysProcess_StateByIndex_Error:
+ default:
+ res.emplace_back("Error getting the child return code");
+ break;
+ }
+ }
+ status.GetMakefile().AddDefinition(arguments.ResultsVariable,
+ cmJoin(res, ";"));
+ } break;
+ case cmsysProcess_State_Exception:
+ status.GetMakefile().AddDefinition(
+ arguments.ResultsVariable, cmsysProcess_GetExceptionString(cp));
+ break;
+ case cmsysProcess_State_Error:
+ status.GetMakefile().AddDefinition(arguments.ResultsVariable,
+ cmsysProcess_GetErrorString(cp));
+ break;
+ case cmsysProcess_State_Expired:
+ status.GetMakefile().AddDefinition(
+ arguments.ResultsVariable, "Process terminated due to timeout");
+ break;
+ }
+ }
+
+ auto queryProcessStatusByIndex = [&cp](int index) -> std::string {
+ std::string processStatus;
+ switch (cmsysProcess_GetStateByIndex(cp, static_cast<int>(index))) {
+ case kwsysProcess_StateByIndex_Exited: {
+ int exitCode = cmsysProcess_GetExitValueByIndex(cp, index);
+ if (exitCode) {
+ processStatus = "Child return code: " + std::to_string(exitCode);
+ }
+ } break;
+ case kwsysProcess_StateByIndex_Exception: {
+ processStatus = cmStrCat(
+ "Abnormal exit with child return code: ",
+ cmsysProcess_GetExceptionStringByIndex(cp, static_cast<int>(index)));
+ break;
+ }
+ case kwsysProcess_StateByIndex_Error:
+ default:
+ processStatus = "Error getting the child return code";
+ break;
+ }
+ return processStatus;
+ };
+
+ if (arguments.CommandErrorIsFatal == "ANY"_s) {
+ bool ret = true;
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Exited: {
+ std::map<int, std::string> failureIndices;
+ for (int i = 0; i < static_cast<int>(arguments.Commands.size()); ++i) {
+ std::string processStatus = queryProcessStatusByIndex(i);
+ if (!processStatus.empty()) {
+ failureIndices[i] = processStatus;
+ }
+ if (!failureIndices.empty()) {
+ std::ostringstream oss;
+ oss << "failed command indexes:\n";
+ for (auto const& e : failureIndices) {
+ oss << " " << e.first + 1 << ": \"" << e.second << "\"\n";
+ }
+ status.SetError(oss.str());
+ ret = false;
+ }
+ }
+ } break;
+ case cmsysProcess_State_Exception:
+ status.SetError(
+ cmStrCat("abnormal exit: ", cmsysProcess_GetExceptionString(cp)));
+ ret = false;
+ break;
+ case cmsysProcess_State_Error:
+ status.SetError(cmStrCat("error getting child return code: ",
+ cmsysProcess_GetErrorString(cp)));
+ ret = false;
+ break;
+ case cmsysProcess_State_Expired:
+ status.SetError("Process terminated due to timeout");
+ ret = false;
+ break;
+ }
+
+ if (!ret) {
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+
+ if (arguments.CommandErrorIsFatal == "LAST"_s) {
+ bool ret = true;
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Exited: {
+ int lastIndex = static_cast<int>(arguments.Commands.size() - 1);
+ const std::string processStatus = queryProcessStatusByIndex(lastIndex);
+ if (!processStatus.empty()) {
+ status.SetError("last command failed");
+ ret = false;
+ }
+ } break;
+ case cmsysProcess_State_Exception:
+ status.SetError(
+ cmStrCat("Abnormal exit: ", cmsysProcess_GetExceptionString(cp)));
+ ret = false;
+ break;
+ case cmsysProcess_State_Error:
+ status.SetError(cmStrCat("Error getting child return code: ",
+ cmsysProcess_GetErrorString(cp)));
+ ret = false;
+ break;
+ case cmsysProcess_State_Expired:
+ status.SetError("Process terminated due to timeout");
+ ret = false;
+ break;
+ }
+ if (!ret) {
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+
+ return true;
+}
+
+namespace {
+void cmExecuteProcessCommandFixText(std::vector<char>& output,
+ bool strip_trailing_whitespace)
+{
+ // Remove \0 characters and the \r part of \r\n pairs.
+ unsigned int in_index = 0;
+ unsigned int out_index = 0;
+ while (in_index < output.size()) {
+ char c = output[in_index++];
+ if ((c != '\r' ||
+ !(in_index < output.size() && output[in_index] == '\n')) &&
+ c != '\0') {
+ output[out_index++] = c;
+ }
+ }
+
+ // Remove trailing whitespace if requested.
+ if (strip_trailing_whitespace) {
+ while (out_index > 0 &&
+ cmExecuteProcessCommandIsWhitespace(output[out_index - 1])) {
+ --out_index;
+ }
+ }
+
+ // Shrink the vector to the size needed.
+ output.resize(out_index);
+
+ // Put a terminator on the text string.
+ output.push_back('\0');
+}
+
+void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data,
+ int length)
+{
+#if defined(__APPLE__)
+ // HACK on Apple to work around bug with inserting at the
+ // end of an empty vector. This resulted in random failures
+ // that were hard to reproduce.
+ if (output.empty() && length > 0) {
+ output.push_back(data[0]);
+ ++data;
+ --length;
+ }
+#endif
+ cm::append(output, data, data + length);
+}
+}
diff --git a/Source/cmExecuteProcessCommand.h b/Source/cmExecuteProcessCommand.h
new file mode 100644
index 0000000..cc8cc38
--- /dev/null
+++ b/Source/cmExecuteProcessCommand.h
@@ -0,0 +1,19 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Command that adds a target to the build system.
+ *
+ * cmExecuteProcessCommand is a CMake language interface to the KWSys
+ * Process Execution implementation.
+ */
+bool cmExecuteProcessCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmExecutionStatus.h b/Source/cmExecutionStatus.h
new file mode 100644
index 0000000..0feaedf
--- /dev/null
+++ b/Source/cmExecutionStatus.h
@@ -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. */
+#pragma once
+
+#include <cmConfigure.h> // IWYU pragma: keep
+
+#include <string>
+
+class cmMakefile;
+
+/** \class cmExecutionStatus
+ * \brief Superclass for all command status classes
+ *
+ * when a command is involked it may set values on a command status instance
+ */
+class cmExecutionStatus
+{
+public:
+ cmExecutionStatus(cmMakefile& makefile)
+ : Makefile(makefile)
+ , Error("unknown error.")
+ {
+ }
+
+ cmMakefile& GetMakefile() { return this->Makefile; }
+
+ void SetError(std::string const& e) { this->Error = e; }
+ std::string const& GetError() const { return this->Error; }
+
+ void SetReturnInvoked() { this->ReturnInvoked = true; }
+ bool GetReturnInvoked() const { return this->ReturnInvoked; }
+
+ void SetBreakInvoked() { this->BreakInvoked = true; }
+ bool GetBreakInvoked() const { return this->BreakInvoked; }
+
+ void SetContinueInvoked() { this->ContinueInvoked = true; }
+ bool GetContinueInvoked() const { return this->ContinueInvoked; }
+
+ void SetNestedError() { this->NestedError = true; }
+ bool GetNestedError() const { return this->NestedError; }
+
+private:
+ cmMakefile& Makefile;
+ std::string Error;
+ bool ReturnInvoked = false;
+ bool BreakInvoked = false;
+ bool ContinueInvoked = false;
+ bool NestedError = false;
+};
diff --git a/Source/cmExpandedCommandArgument.cxx b/Source/cmExpandedCommandArgument.cxx
new file mode 100644
index 0000000..1f14fc4
--- /dev/null
+++ b/Source/cmExpandedCommandArgument.cxx
@@ -0,0 +1,39 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExpandedCommandArgument.h"
+
+#include <utility>
+
+cmExpandedCommandArgument::cmExpandedCommandArgument() = default;
+
+cmExpandedCommandArgument::cmExpandedCommandArgument(std::string value,
+ bool quoted)
+ : Value(std::move(value))
+ , Quoted(quoted)
+{
+}
+
+std::string const& cmExpandedCommandArgument::GetValue() const
+{
+ return this->Value;
+}
+
+bool cmExpandedCommandArgument::WasQuoted() const
+{
+ return this->Quoted;
+}
+
+bool cmExpandedCommandArgument::operator==(const char* value) const
+{
+ return this->Value == value;
+}
+
+bool cmExpandedCommandArgument::operator==(std::string const& value) const
+{
+ return this->Value == value;
+}
+
+bool cmExpandedCommandArgument::empty() const
+{
+ return this->Value.empty();
+}
diff --git a/Source/cmExpandedCommandArgument.h b/Source/cmExpandedCommandArgument.h
new file mode 100644
index 0000000..1ff6ed1
--- /dev/null
+++ b/Source/cmExpandedCommandArgument.h
@@ -0,0 +1,34 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+
+/** \class cmExpandedCommandArgument
+ * \brief Represents an expanded command argument
+ *
+ * cmCommandArgument stores a string representing an expanded
+ * command argument and context information.
+ */
+
+class cmExpandedCommandArgument
+{
+public:
+ cmExpandedCommandArgument();
+ cmExpandedCommandArgument(std::string value, bool quoted);
+
+ std::string const& GetValue() const;
+
+ bool WasQuoted() const;
+
+ bool operator==(const char* value) const;
+ bool operator==(std::string const& value) const;
+
+ bool empty() const;
+
+private:
+ std::string Value;
+ bool Quoted = false;
+};
diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx
new file mode 100644
index 0000000..3641cb2
--- /dev/null
+++ b/Source/cmExportBuildAndroidMKGenerator.cxx
@@ -0,0 +1,193 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExportBuildAndroidMKGenerator.h"
+
+#include <sstream>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmGeneratorTarget.h"
+#include "cmLinkItem.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+
+cmExportBuildAndroidMKGenerator::cmExportBuildAndroidMKGenerator()
+{
+ this->LG = nullptr;
+ this->ExportSet = nullptr;
+}
+
+void cmExportBuildAndroidMKGenerator::GenerateImportHeaderCode(
+ std::ostream& os, const std::string&)
+{
+ os << "LOCAL_PATH := $(call my-dir)\n\n";
+}
+
+void cmExportBuildAndroidMKGenerator::GenerateImportFooterCode(std::ostream&)
+{
+}
+
+void cmExportBuildAndroidMKGenerator::GenerateExpectedTargetsCode(
+ std::ostream&, const std::string&)
+{
+}
+
+void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode(
+ std::ostream& os, cmGeneratorTarget const* target,
+ cmStateEnums::TargetType /*targetType*/)
+{
+ std::string targetName = cmStrCat(this->Namespace, target->GetExportName());
+ os << "include $(CLEAR_VARS)\n";
+ os << "LOCAL_MODULE := ";
+ os << targetName << "\n";
+ os << "LOCAL_SRC_FILES := ";
+ std::string const noConfig; // FIXME: What config to use here?
+ std::string path =
+ cmSystemTools::ConvertToOutputPath(target->GetFullPath(noConfig));
+ os << path << "\n";
+}
+
+void cmExportBuildAndroidMKGenerator::GenerateImportPropertyCode(
+ std::ostream&, const std::string&, cmGeneratorTarget const*,
+ ImportPropertyMap const&)
+{
+}
+
+void cmExportBuildAndroidMKGenerator::GenerateMissingTargetsCheckCode(
+ std::ostream&, const std::vector<std::string>&)
+{
+}
+
+void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
+ const cmGeneratorTarget* target, std::ostream& os,
+ const ImportPropertyMap& properties)
+{
+ std::string config;
+ if (!this->Configurations.empty()) {
+ config = this->Configurations[0];
+ }
+ cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
+ target, os, properties, cmExportBuildAndroidMKGenerator::BUILD, config);
+}
+
+void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
+ const cmGeneratorTarget* target, std::ostream& os,
+ const ImportPropertyMap& properties, GenerateType type,
+ std::string const& config)
+{
+ const bool newCMP0022Behavior =
+ target->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
+ target->GetPolicyStatusCMP0022() != cmPolicies::OLD;
+ if (!newCMP0022Behavior) {
+ std::ostringstream w;
+ if (type == cmExportBuildAndroidMKGenerator::BUILD) {
+ w << "export(TARGETS ... ANDROID_MK) called with policy CMP0022";
+ } else {
+ w << "install( EXPORT_ANDROID_MK ...) called with policy CMP0022";
+ }
+ w << " set to OLD for target " << target->Target->GetName() << ". "
+ << "The export will only work with CMP0022 set to NEW.";
+ target->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+ if (!properties.empty()) {
+ os << "LOCAL_CPP_FEATURES := rtti exceptions\n";
+ for (auto const& property : properties) {
+ if (property.first == "INTERFACE_COMPILE_OPTIONS") {
+ os << "LOCAL_CPP_FEATURES += ";
+ os << (property.second) << "\n";
+ } else if (property.first == "INTERFACE_LINK_LIBRARIES") {
+ std::string staticLibs;
+ std::string sharedLibs;
+ std::string ldlibs;
+ cmLinkInterfaceLibraries const* linkIFace =
+ target->GetLinkInterfaceLibraries(config, target, false);
+ for (cmLinkItem const& item : linkIFace->Libraries) {
+ cmGeneratorTarget const* gt = item.Target;
+ std::string const& lib = item.AsStr();
+ if (gt) {
+
+ if (gt->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ gt->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ sharedLibs += " " + lib;
+ } else {
+ staticLibs += " " + lib;
+ }
+ } else {
+ bool relpath = false;
+ if (type == cmExportBuildAndroidMKGenerator::INSTALL) {
+ relpath = cmHasLiteralPrefix(lib, "../");
+ }
+ // check for full path or if it already has a -l, or
+ // in the case of an install check for relative paths
+ // if it is full or a link library then use string directly
+ if (cmSystemTools::FileIsFullPath(lib) ||
+ cmHasLiteralPrefix(lib, "-l") || relpath) {
+ ldlibs += " " + lib;
+ // if it is not a path and does not have a -l then add -l
+ } else if (!lib.empty()) {
+ ldlibs += " -l" + lib;
+ }
+ }
+ }
+ if (!sharedLibs.empty()) {
+ os << "LOCAL_SHARED_LIBRARIES :=" << sharedLibs << "\n";
+ }
+ if (!staticLibs.empty()) {
+ os << "LOCAL_STATIC_LIBRARIES :=" << staticLibs << "\n";
+ }
+ if (!ldlibs.empty()) {
+ os << "LOCAL_EXPORT_LDLIBS :=" << ldlibs << "\n";
+ }
+ } else if (property.first == "INTERFACE_INCLUDE_DIRECTORIES") {
+ std::string includes = property.second;
+ std::vector<std::string> includeList = cmExpandedList(includes);
+ os << "LOCAL_EXPORT_C_INCLUDES := ";
+ std::string end;
+ for (std::string const& i : includeList) {
+ os << end << i;
+ end = "\\\n";
+ }
+ os << "\n";
+ } else if (property.first == "INTERFACE_LINK_OPTIONS") {
+ os << "LOCAL_EXPORT_LDFLAGS := ";
+ std::vector<std::string> linkFlagsList =
+ cmExpandedList(property.second);
+ os << cmJoin(linkFlagsList, " ") << "\n";
+ } else {
+ os << "# " << property.first << " " << (property.second) << "\n";
+ }
+ }
+ }
+
+ // Tell the NDK build system if prebuilt static libraries use C++.
+ if (target->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ cmLinkImplementation const* li = target->GetLinkImplementation(config);
+ if (cm::contains(li->Languages, "CXX")) {
+ os << "LOCAL_HAS_CPP := true\n";
+ }
+ }
+
+ switch (target->GetType()) {
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ os << "include $(PREBUILT_SHARED_LIBRARY)\n";
+ break;
+ case cmStateEnums::STATIC_LIBRARY:
+ os << "include $(PREBUILT_STATIC_LIBRARY)\n";
+ break;
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::UTILITY:
+ case cmStateEnums::OBJECT_LIBRARY:
+ case cmStateEnums::GLOBAL_TARGET:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ break;
+ }
+ os << "\n";
+}
diff --git a/Source/cmExportBuildAndroidMKGenerator.h b/Source/cmExportBuildAndroidMKGenerator.h
new file mode 100644
index 0000000..250564f
--- /dev/null
+++ b/Source/cmExportBuildAndroidMKGenerator.h
@@ -0,0 +1,64 @@
+/* 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 <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmExportBuildFileGenerator.h"
+#include "cmExportFileGenerator.h"
+#include "cmStateTypes.h"
+
+class cmGeneratorTarget;
+
+/** \class cmExportBuildAndroidMKGenerator
+ * \brief Generate a file exporting targets from a build tree.
+ *
+ * cmExportBuildAndroidMKGenerator generates a file exporting targets from
+ * a build tree. This exports the targets to the Android ndk build tool
+ * makefile format for prebuilt libraries.
+ *
+ * This is used to implement the EXPORT() command.
+ */
+class cmExportBuildAndroidMKGenerator : public cmExportBuildFileGenerator
+{
+public:
+ cmExportBuildAndroidMKGenerator();
+ // this is so cmExportInstallAndroidMKGenerator can share this
+ // function as they are almost the same
+ enum GenerateType
+ {
+ BUILD,
+ INSTALL
+ };
+ static void GenerateInterfaceProperties(cmGeneratorTarget const* target,
+ std::ostream& os,
+ const ImportPropertyMap& properties,
+ GenerateType type,
+ std::string const& config);
+
+protected:
+ // Implement virtual methods from the superclass.
+ void GeneratePolicyHeaderCode(std::ostream&) override {}
+ void GeneratePolicyFooterCode(std::ostream&) override {}
+ void GenerateImportHeaderCode(std::ostream& os,
+ const std::string& config = "") override;
+ void GenerateImportFooterCode(std::ostream& os) override;
+ void GenerateImportTargetCode(
+ std::ostream& os, cmGeneratorTarget const* target,
+ cmStateEnums::TargetType /*targetType*/) override;
+ void GenerateExpectedTargetsCode(
+ std::ostream& os, const std::string& expectedTargets) override;
+ void GenerateImportPropertyCode(
+ std::ostream& os, const std::string& config,
+ cmGeneratorTarget const* target,
+ ImportPropertyMap const& properties) override;
+ void GenerateMissingTargetsCheckCode(
+ std::ostream& os, const std::vector<std::string>& missingTargets) override;
+ void GenerateInterfaceProperties(
+ cmGeneratorTarget const* target, std::ostream& os,
+ const ImportPropertyMap& properties) override;
+};
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
new file mode 100644
index 0000000..1a31ae4
--- /dev/null
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -0,0 +1,357 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExportBuildFileGenerator.h"
+
+#include <map>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmExportSet.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmTarget.h"
+#include "cmTargetExport.h"
+#include "cmake.h"
+
+class cmSourceFile;
+
+cmExportBuildFileGenerator::cmExportBuildFileGenerator()
+{
+ this->LG = nullptr;
+ this->ExportSet = nullptr;
+}
+
+void cmExportBuildFileGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LG = lg;
+ if (this->ExportSet) {
+ this->ExportSet->Compute(lg);
+ }
+}
+
+bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
+{
+ {
+ std::string expectedTargets;
+ std::string sep;
+ std::vector<std::string> targets;
+ bool generatedInterfaceRequired = false;
+ this->GetTargets(targets);
+ for (std::string const& tei : targets) {
+ cmGeneratorTarget* te = this->LG->FindGeneratorTargetToUse(tei);
+ expectedTargets += sep + this->Namespace + te->GetExportName();
+ sep = " ";
+ if (this->ExportedTargets.insert(te).second) {
+ this->Exports.push_back(te);
+ } else {
+ std::ostringstream e;
+ e << "given target \"" << te->GetName() << "\" more than once.";
+ this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR, e.str(),
+ this->LG->GetMakefile()->GetBacktrace());
+ return false;
+ }
+ generatedInterfaceRequired |=
+ this->GetExportTargetType(te) == cmStateEnums::INTERFACE_LIBRARY;
+ }
+
+ if (generatedInterfaceRequired) {
+ this->GenerateRequiredCMakeVersion(os, "3.0.0");
+ }
+ this->GenerateExpectedTargetsCode(os, expectedTargets);
+ }
+
+ std::vector<std::string> missingTargets;
+
+ // Create all the imported targets.
+ for (cmGeneratorTarget* gte : this->Exports) {
+ this->GenerateImportTargetCode(os, gte, this->GetExportTargetType(gte));
+
+ gte->Target->AppendBuildInterfaceIncludes();
+
+ ImportPropertyMap properties;
+
+ this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_SOURCES", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_LINK_DIRECTORIES", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte,
+ properties);
+
+ std::string errorMessage;
+ if (!this->PopulateExportProperties(gte, properties, errorMessage)) {
+ this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR, errorMessage,
+ this->LG->GetMakefile()->GetBacktrace());
+ return false;
+ }
+
+ const bool newCMP0022Behavior =
+ gte->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
+ gte->GetPolicyStatusCMP0022() != cmPolicies::OLD;
+ if (newCMP0022Behavior) {
+ this->PopulateInterfaceLinkLibrariesProperty(
+ gte, cmGeneratorExpression::BuildInterface, properties,
+ missingTargets);
+ }
+ this->PopulateCompatibleInterfaceProperties(gte, properties);
+
+ this->GenerateInterfaceProperties(gte, os, properties);
+ }
+
+ // Generate import file content for each configuration.
+ for (std::string const& c : this->Configurations) {
+ this->GenerateImportConfig(os, c, missingTargets);
+ }
+
+ this->GenerateMissingTargetsCheckCode(os, missingTargets);
+
+ return true;
+}
+
+void cmExportBuildFileGenerator::GenerateImportTargetsConfig(
+ std::ostream& os, const std::string& config, std::string const& suffix,
+ std::vector<std::string>& missingTargets)
+{
+ for (cmGeneratorTarget* target : this->Exports) {
+ // Collect import properties for this target.
+ ImportPropertyMap properties;
+
+ if (this->GetExportTargetType(target) != cmStateEnums::INTERFACE_LIBRARY) {
+ this->SetImportLocationProperty(config, suffix, target, properties);
+ }
+ if (!properties.empty()) {
+ // Get the rest of the target details.
+ if (this->GetExportTargetType(target) !=
+ cmStateEnums::INTERFACE_LIBRARY) {
+ this->SetImportDetailProperties(config, suffix, target, properties,
+ missingTargets);
+ this->SetImportLinkInterface(config, suffix,
+ cmGeneratorExpression::BuildInterface,
+ target, properties, missingTargets);
+ }
+
+ // TODO: PUBLIC_HEADER_LOCATION
+ // This should wait until the build feature propagation stuff
+ // is done. Then this can be a propagated include directory.
+ // this->GenerateImportProperty(config, te->HeaderGenerator,
+ // properties);
+
+ // Generate code in the export file.
+ this->GenerateImportPropertyCode(os, config, target, properties);
+ }
+ }
+}
+
+cmStateEnums::TargetType cmExportBuildFileGenerator::GetExportTargetType(
+ cmGeneratorTarget const* target) const
+{
+ cmStateEnums::TargetType targetType = target->GetType();
+ // An object library exports as an interface library if we cannot
+ // tell clients where to find the objects. This is sufficient
+ // to support transitive usage requirements on other targets that
+ // use the object library.
+ if (targetType == cmStateEnums::OBJECT_LIBRARY &&
+ !this->LG->GetGlobalGenerator()->HasKnownObjectFileLocation(nullptr)) {
+ targetType = cmStateEnums::INTERFACE_LIBRARY;
+ }
+ return targetType;
+}
+
+void cmExportBuildFileGenerator::SetExportSet(cmExportSet* exportSet)
+{
+ this->ExportSet = exportSet;
+}
+
+void cmExportBuildFileGenerator::SetImportLocationProperty(
+ const std::string& config, std::string const& suffix,
+ cmGeneratorTarget* target, ImportPropertyMap& properties)
+{
+ // Get the makefile in which to lookup target information.
+ cmMakefile* mf = target->Makefile;
+
+ if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ std::string prop = cmStrCat("IMPORTED_OBJECTS", suffix);
+
+ // Compute all the object files inside this target and setup
+ // IMPORTED_OBJECTS as a list of object files
+ std::vector<cmSourceFile const*> objectSources;
+ target->GetObjectSources(objectSources, config);
+ std::string const obj_dir = target->GetObjectDirectory(config);
+ std::vector<std::string> objects;
+ for (cmSourceFile const* sf : objectSources) {
+ const std::string& obj = target->GetObjectName(sf);
+ objects.push_back(obj_dir + obj);
+ }
+
+ // Store the property.
+ properties[prop] = cmJoin(objects, ";");
+ } else {
+ // Add the main target file.
+ {
+ std::string prop = cmStrCat("IMPORTED_LOCATION", suffix);
+ std::string value;
+ if (target->IsAppBundleOnApple()) {
+ value =
+ target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
+ } else {
+ value = target->GetFullPath(config,
+ cmStateEnums::RuntimeBinaryArtifact, true);
+ }
+ properties[prop] = value;
+ }
+
+ // Add the import library for windows DLLs.
+ if (target->HasImportLibrary(config)) {
+ std::string prop = cmStrCat("IMPORTED_IMPLIB", suffix);
+ std::string value =
+ target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact);
+ if (mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
+ target->GetImplibGNUtoMS(config, value, value,
+ "${CMAKE_IMPORT_LIBRARY_SUFFIX}");
+ }
+ properties[prop] = value;
+ }
+ }
+}
+
+void cmExportBuildFileGenerator::HandleMissingTarget(
+ std::string& link_libs, std::vector<std::string>& missingTargets,
+ cmGeneratorTarget* depender, cmGeneratorTarget* dependee)
+{
+ // The target is not in the export.
+ if (!this->AppendMode) {
+ const std::string name = dependee->GetName();
+ cmGlobalGenerator* gg =
+ dependee->GetLocalGenerator()->GetGlobalGenerator();
+ auto exportInfo = this->FindBuildExportInfo(gg, name);
+ std::vector<std::string> const& exportFiles = exportInfo.first;
+
+ if (exportFiles.size() == 1) {
+ std::string missingTarget = exportInfo.second;
+
+ missingTarget += dependee->GetExportName();
+ link_libs += missingTarget;
+ missingTargets.push_back(std::move(missingTarget));
+ return;
+ }
+ // We are not appending, so all exported targets should be
+ // known here. This is probably user-error.
+ this->ComplainAboutMissingTarget(depender, dependee, exportFiles);
+ }
+ // Assume the target will be exported by another command.
+ // Append it with the export namespace.
+ link_libs += this->Namespace;
+ link_libs += dependee->GetExportName();
+}
+
+void cmExportBuildFileGenerator::GetTargets(
+ std::vector<std::string>& targets) const
+{
+ if (this->ExportSet) {
+ for (std::unique_ptr<cmTargetExport> const& te :
+ this->ExportSet->GetTargetExports()) {
+ if (te->NamelinkOnly) {
+ continue;
+ }
+ targets.push_back(te->TargetName);
+ }
+ return;
+ }
+ targets = this->Targets;
+}
+
+std::pair<std::vector<std::string>, std::string>
+cmExportBuildFileGenerator::FindBuildExportInfo(cmGlobalGenerator* gg,
+ const std::string& name)
+{
+ std::vector<std::string> exportFiles;
+ std::string ns;
+
+ auto& exportSets = gg->GetBuildExportSets();
+
+ for (auto const& exp : exportSets) {
+ const auto& exportSet = exp.second;
+ std::vector<std::string> targets;
+ exportSet->GetTargets(targets);
+ if (cm::contains(targets, name)) {
+ exportFiles.push_back(exp.first);
+ ns = exportSet->GetNamespace();
+ }
+ }
+
+ return { exportFiles, ns };
+}
+
+void cmExportBuildFileGenerator::ComplainAboutMissingTarget(
+ cmGeneratorTarget* depender, cmGeneratorTarget* dependee,
+ std::vector<std::string> const& exportFiles)
+{
+ std::ostringstream e;
+ e << "export called with target \"" << depender->GetName()
+ << "\" which requires target \"" << dependee->GetName() << "\" ";
+ if (exportFiles.empty()) {
+ e << "that is not in any export set.";
+ } else {
+ e << "that is not in this export set, but in multiple other export sets: "
+ << cmJoin(exportFiles, ", ") << ".\n";
+ e << "An exported target cannot depend upon another target which is "
+ "exported multiple times. Consider consolidating the exports of the "
+ "\""
+ << dependee->GetName() << "\" target to a single export.";
+ }
+
+ this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR, e.str(),
+ this->LG->GetMakefile()->GetBacktrace());
+}
+
+std::string cmExportBuildFileGenerator::InstallNameDir(
+ cmGeneratorTarget* target, const std::string& config)
+{
+ std::string install_name_dir;
+
+ cmMakefile* mf = target->Target->GetMakefile();
+ if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ install_name_dir = target->GetInstallNameDirForBuildTree(config);
+ }
+
+ return install_name_dir;
+}
diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h
new file mode 100644
index 0000000..264494d
--- /dev/null
+++ b/Source/cmExportBuildFileGenerator.h
@@ -0,0 +1,86 @@
+/* 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 <iosfwd>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cmext/algorithm>
+
+#include "cmExportFileGenerator.h"
+#include "cmStateTypes.h"
+
+class cmExportSet;
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmLocalGenerator;
+
+/** \class cmExportBuildFileGenerator
+ * \brief Generate a file exporting targets from a build tree.
+ *
+ * cmExportBuildFileGenerator generates a file exporting targets from
+ * a build tree. A single file exports information for all
+ * configurations built.
+ *
+ * This is used to implement the EXPORT() command.
+ */
+class cmExportBuildFileGenerator : public cmExportFileGenerator
+{
+public:
+ cmExportBuildFileGenerator();
+
+ /** Set the list of targets to export. */
+ void SetTargets(std::vector<std::string> const& targets)
+ {
+ this->Targets = targets;
+ }
+ void GetTargets(std::vector<std::string>& targets) const;
+ void AppendTargets(std::vector<std::string> const& targets)
+ {
+ cm::append(this->Targets, targets);
+ }
+ void SetExportSet(cmExportSet*);
+
+ /** Set whether to append generated code to the output file. */
+ void SetAppendMode(bool append) { this->AppendMode = append; }
+
+ void Compute(cmLocalGenerator* lg);
+
+protected:
+ // Implement virtual methods from the superclass.
+ bool GenerateMainFile(std::ostream& os) override;
+ void GenerateImportTargetsConfig(
+ std::ostream& os, const std::string& config, std::string const& suffix,
+ std::vector<std::string>& missingTargets) override;
+ cmStateEnums::TargetType GetExportTargetType(
+ cmGeneratorTarget const* target) const;
+ void HandleMissingTarget(std::string& link_libs,
+ std::vector<std::string>& missingTargets,
+ cmGeneratorTarget* depender,
+ cmGeneratorTarget* dependee) override;
+
+ void ComplainAboutMissingTarget(cmGeneratorTarget* depender,
+ cmGeneratorTarget* dependee,
+ std::vector<std::string> const& namespaces);
+
+ /** Fill in properties indicating built file locations. */
+ void SetImportLocationProperty(const std::string& config,
+ std::string const& suffix,
+ cmGeneratorTarget* target,
+ ImportPropertyMap& properties);
+
+ std::string InstallNameDir(cmGeneratorTarget* target,
+ const std::string& config) override;
+
+ std::pair<std::vector<std::string>, std::string> FindBuildExportInfo(
+ cmGlobalGenerator* gg, const std::string& name);
+
+ std::vector<std::string> Targets;
+ cmExportSet* ExportSet;
+ std::vector<cmGeneratorTarget*> Exports;
+ cmLocalGenerator* LG;
+};
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
new file mode 100644
index 0000000..352eaf2
--- /dev/null
+++ b/Source/cmExportCommand.cxx
@@ -0,0 +1,393 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExportCommand.h"
+
+#include <map>
+#include <sstream>
+#include <utility>
+
+#include <cm/memory>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmArgumentParser.h"
+#include "cmExecutionStatus.h"
+#include "cmExportBuildAndroidMKGenerator.h"
+#include "cmExportBuildFileGenerator.h"
+#include "cmExportSet.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+
+#if defined(__HAIKU__)
+# include <FindDirectory.h>
+# include <StorageDefs.h>
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <windows.h>
+#endif
+
+static bool HandlePackage(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
+
+static void StorePackageRegistry(cmMakefile& mf, std::string const& package,
+ const char* content, const char* hash);
+
+bool cmExportCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with too few arguments");
+ return false;
+ }
+
+ if (args[0] == "PACKAGE") {
+ return HandlePackage(args, status);
+ }
+
+ struct Arguments
+ {
+ std::string ExportSetName;
+ std::vector<std::string> Targets;
+ std::string Namespace;
+ std::string Filename;
+ std::string AndroidMKFile;
+ bool Append = false;
+ bool ExportOld = false;
+ };
+
+ auto parser = cmArgumentParser<Arguments>{}
+ .Bind("NAMESPACE"_s, &Arguments::Namespace)
+ .Bind("FILE"_s, &Arguments::Filename);
+
+ if (args[0] == "EXPORT") {
+ parser.Bind("EXPORT"_s, &Arguments::ExportSetName);
+ } else {
+ parser.Bind("TARGETS"_s, &Arguments::Targets);
+ parser.Bind("ANDROID_MK"_s, &Arguments::AndroidMKFile);
+ parser.Bind("APPEND"_s, &Arguments::Append);
+ parser.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, &Arguments::ExportOld);
+ }
+
+ std::vector<std::string> unknownArgs;
+ std::vector<std::string> keywordsMissingValue;
+ Arguments const arguments =
+ parser.Parse(args, &unknownArgs, &keywordsMissingValue);
+
+ if (!unknownArgs.empty()) {
+ status.SetError("Unknown argument: \"" + unknownArgs.front() + "\".");
+ return false;
+ }
+
+ std::string fname;
+ bool android = false;
+ if (!arguments.AndroidMKFile.empty()) {
+ fname = arguments.AndroidMKFile;
+ android = true;
+ }
+ if (arguments.Filename.empty() && fname.empty()) {
+ if (args[0] != "EXPORT") {
+ status.SetError("FILE <filename> option missing.");
+ return false;
+ }
+ fname = arguments.ExportSetName + ".cmake";
+ } else if (fname.empty()) {
+ // Make sure the file has a .cmake extension.
+ if (cmSystemTools::GetFilenameLastExtension(arguments.Filename) !=
+ ".cmake") {
+ std::ostringstream e;
+ e << "FILE option given filename \"" << arguments.Filename
+ << "\" which does not have an extension of \".cmake\".\n";
+ status.SetError(e.str());
+ return false;
+ }
+ fname = arguments.Filename;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ // Get the file to write.
+ if (cmSystemTools::FileIsFullPath(fname)) {
+ if (!mf.CanIWriteThisFile(fname)) {
+ std::ostringstream e;
+ e << "FILE option given filename \"" << fname
+ << "\" which is in the source tree.\n";
+ status.SetError(e.str());
+ return false;
+ }
+ } else {
+ // Interpret relative paths with respect to the current build dir.
+ std::string const& dir = mf.GetCurrentBinaryDirectory();
+ fname = dir + "/" + fname;
+ }
+
+ std::vector<std::string> targets;
+
+ cmGlobalGenerator* gg = mf.GetGlobalGenerator();
+
+ cmExportSet* exportSet = nullptr;
+ if (args[0] == "EXPORT") {
+ cmExportSetMap& setMap = gg->GetExportSets();
+ auto const it = setMap.find(arguments.ExportSetName);
+ if (it == setMap.end()) {
+ std::ostringstream e;
+ e << "Export set \"" << arguments.ExportSetName << "\" not found.";
+ status.SetError(e.str());
+ return false;
+ }
+ exportSet = &it->second;
+ } else if (!arguments.Targets.empty() ||
+ cm::contains(keywordsMissingValue, "TARGETS")) {
+ for (std::string const& currentTarget : arguments.Targets) {
+ if (mf.IsAlias(currentTarget)) {
+ std::ostringstream e;
+ e << "given ALIAS target \"" << currentTarget
+ << "\" which may not be exported.";
+ status.SetError(e.str());
+ return false;
+ }
+
+ if (cmTarget* target = gg->FindTarget(currentTarget)) {
+ if (target->GetType() == cmStateEnums::UTILITY) {
+ status.SetError("given custom target \"" + currentTarget +
+ "\" which may not be exported.");
+ return false;
+ }
+ } else {
+ std::ostringstream e;
+ e << "given target \"" << currentTarget
+ << "\" which is not built by this project.";
+ status.SetError(e.str());
+ return false;
+ }
+ targets.push_back(currentTarget);
+ }
+ if (arguments.Append) {
+ if (cmExportBuildFileGenerator* ebfg =
+ gg->GetExportedTargetsFile(fname)) {
+ ebfg->AppendTargets(targets);
+ return true;
+ }
+ }
+ } else {
+ status.SetError("EXPORT or TARGETS specifier missing.");
+ return false;
+ }
+
+ // if cmExportBuildFileGenerator is already defined for the file
+ // and APPEND is not specified, if CMP0103 is OLD ignore previous definition
+ // else raise an error
+ if (gg->GetExportedTargetsFile(fname) != nullptr) {
+ switch (mf.GetPolicyStatus(cmPolicies::CMP0103)) {
+ case cmPolicies::WARN:
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0103), '\n',
+ "export() command already specified for the file\n ",
+ arguments.Filename, "\nDid you miss 'APPEND' keyword?"));
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ break;
+ default:
+ status.SetError(cmStrCat("command already specified for the file\n ",
+ arguments.Filename,
+ "\nDid you miss 'APPEND' keyword?"));
+ return false;
+ }
+ }
+
+ // Setup export file generation.
+ std::unique_ptr<cmExportBuildFileGenerator> ebfg = nullptr;
+ if (android) {
+ ebfg = cm::make_unique<cmExportBuildAndroidMKGenerator>();
+ } else {
+ ebfg = cm::make_unique<cmExportBuildFileGenerator>();
+ }
+ ebfg->SetExportFile(fname.c_str());
+ ebfg->SetNamespace(arguments.Namespace);
+ ebfg->SetAppendMode(arguments.Append);
+ if (exportSet != nullptr) {
+ ebfg->SetExportSet(exportSet);
+ } else {
+ ebfg->SetTargets(targets);
+ }
+ ebfg->SetExportOld(arguments.ExportOld);
+
+ // Compute the set of configurations exported.
+ std::vector<std::string> configurationTypes =
+ mf.GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+ for (std::string const& ct : configurationTypes) {
+ ebfg->AddConfiguration(ct);
+ }
+ if (exportSet != nullptr) {
+ gg->AddBuildExportExportSet(ebfg.get());
+ } else {
+ gg->AddBuildExportSet(ebfg.get());
+ }
+ mf.AddExportBuildFileGenerator(std::move(ebfg));
+
+ return true;
+}
+
+static bool HandlePackage(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // Parse PACKAGE mode arguments.
+ enum Doing
+ {
+ DoingNone,
+ DoingPackage
+ };
+ Doing doing = DoingPackage;
+ std::string package;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (doing == DoingPackage) {
+ package = args[i];
+ doing = DoingNone;
+ } else {
+ std::ostringstream e;
+ e << "PACKAGE given unknown argument: " << args[i];
+ status.SetError(e.str());
+ return false;
+ }
+ }
+
+ // Verify the package name.
+ if (package.empty()) {
+ status.SetError("PACKAGE must be given a package name.");
+ return false;
+ }
+ const char* packageExpr = "^[A-Za-z0-9_.-]+$";
+ cmsys::RegularExpression packageRegex(packageExpr);
+ if (!packageRegex.find(package)) {
+ std::ostringstream e;
+ e << "PACKAGE given invalid package name \"" << package << "\". "
+ << "Package names must match \"" << packageExpr << "\".";
+ status.SetError(e.str());
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ // CMP0090 decides both the default and what variable changes it.
+ switch (mf.GetPolicyStatus(cmPolicies::CMP0090)) {
+ case cmPolicies::WARN:
+ case cmPolicies::OLD:
+ // Default is to export, but can be disabled.
+ if (mf.IsOn("CMAKE_EXPORT_NO_PACKAGE_REGISTRY")) {
+ return true;
+ }
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Default is to not export, but can be enabled.
+ if (!mf.IsOn("CMAKE_EXPORT_PACKAGE_REGISTRY")) {
+ return true;
+ }
+ break;
+ }
+
+ // We store the current build directory in the registry as a value
+ // named by a hash of its own content. This is deterministic and is
+ // unique with high probability.
+ const std::string& outDir = mf.GetCurrentBinaryDirectory();
+ std::string hash = cmSystemTools::ComputeStringMD5(outDir);
+ StorePackageRegistry(mf, package, outDir.c_str(), hash.c_str());
+
+ return true;
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+
+static void ReportRegistryError(cmMakefile& mf, std::string const& msg,
+ std::string const& key, long err)
+{
+ std::ostringstream e;
+ e << msg << "\n"
+ << " HKEY_CURRENT_USER\\" << key << "\n";
+ wchar_t winmsg[1024];
+ if (FormatMessageW(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), winmsg, 1024, 0) > 0) {
+ e << "Windows reported:\n"
+ << " " << cmsys::Encoding::ToNarrow(winmsg);
+ }
+ mf.IssueMessage(MessageType::WARNING, e.str());
+}
+
+static void StorePackageRegistry(cmMakefile& mf, std::string const& package,
+ const char* content, const char* hash)
+{
+ std::string key = cmStrCat("Software\\Kitware\\CMake\\Packages\\", package);
+ HKEY hKey;
+ LONG err =
+ RegCreateKeyExW(HKEY_CURRENT_USER, cmsys::Encoding::ToWide(key).c_str(), 0,
+ 0, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, 0, &hKey, 0);
+ if (err != ERROR_SUCCESS) {
+ ReportRegistryError(mf, "Cannot create/open registry key", key, err);
+ return;
+ }
+
+ std::wstring wcontent = cmsys::Encoding::ToWide(content);
+ err =
+ RegSetValueExW(hKey, cmsys::Encoding::ToWide(hash).c_str(), 0, REG_SZ,
+ (BYTE const*)wcontent.c_str(),
+ static_cast<DWORD>(wcontent.size() + 1) * sizeof(wchar_t));
+ RegCloseKey(hKey);
+ if (err != ERROR_SUCCESS) {
+ std::ostringstream msg;
+ msg << "Cannot set registry value \"" << hash << "\" under key";
+ ReportRegistryError(mf, msg.str(), key, err);
+ return;
+ }
+}
+#else
+static void StorePackageRegistry(cmMakefile& mf, std::string const& package,
+ const char* content, const char* hash)
+{
+# if defined(__HAIKU__)
+ char dir[B_PATH_NAME_LENGTH];
+ if (find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, dir, sizeof(dir)) !=
+ B_OK) {
+ return;
+ }
+ std::string fname = cmStrCat(dir, "/cmake/packages/", package);
+# else
+ std::string fname;
+ if (!cmSystemTools::GetEnv("HOME", fname)) {
+ return;
+ }
+ cmSystemTools::ConvertToUnixSlashes(fname);
+ fname += "/.cmake/packages/";
+ fname += package;
+# endif
+ cmSystemTools::MakeDirectory(fname);
+ fname += "/";
+ fname += hash;
+ if (!cmSystemTools::FileExists(fname)) {
+ cmGeneratedFileStream entry(fname, true);
+ if (entry) {
+ entry << content << "\n";
+ } else {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "Cannot create package registry file:\n"
+ << " " << fname << "\n"
+ << cmSystemTools::GetLastSystemError() << "\n";
+ /* clang-format on */
+ mf.IssueMessage(MessageType::WARNING, e.str());
+ }
+ }
+}
+#endif
diff --git a/Source/cmExportCommand.h b/Source/cmExportCommand.h
new file mode 100644
index 0000000..3f87bcf
--- /dev/null
+++ b/Source/cmExportCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmExportCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
new file mode 100644
index 0000000..0409f97
--- /dev/null
+++ b/Source/cmExportFileGenerator.cxx
@@ -0,0 +1,1251 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExportFileGenerator.h"
+
+#include <cassert>
+#include <cstring>
+#include <sstream>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmComputeLinkInformation.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLinkItem.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmPropertyMap.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetExport.h"
+
+static std::string cmExportFileGeneratorEscape(std::string const& str)
+{
+ // Escape a property value for writing into a .cmake file.
+ std::string result = cmOutputConverter::EscapeForCMake(str);
+ // Un-escape variable references generated by our own export code.
+ cmSystemTools::ReplaceString(result, "\\${_IMPORT_PREFIX}",
+ "${_IMPORT_PREFIX}");
+ cmSystemTools::ReplaceString(result, "\\${CMAKE_IMPORT_LIBRARY_SUFFIX}",
+ "${CMAKE_IMPORT_LIBRARY_SUFFIX}");
+ return result;
+}
+
+cmExportFileGenerator::cmExportFileGenerator()
+{
+ this->AppendMode = false;
+ this->ExportOld = false;
+}
+
+void cmExportFileGenerator::AddConfiguration(const std::string& config)
+{
+ this->Configurations.push_back(config);
+}
+
+void cmExportFileGenerator::SetExportFile(const char* mainFile)
+{
+ this->MainImportFile = mainFile;
+ this->FileDir = cmSystemTools::GetFilenamePath(this->MainImportFile);
+ this->FileBase =
+ cmSystemTools::GetFilenameWithoutLastExtension(this->MainImportFile);
+ this->FileExt =
+ cmSystemTools::GetFilenameLastExtension(this->MainImportFile);
+}
+
+const std::string& cmExportFileGenerator::GetMainExportFileName() const
+{
+ return this->MainImportFile;
+}
+
+bool cmExportFileGenerator::GenerateImportFile()
+{
+ // Open the output file to generate it.
+ std::unique_ptr<cmsys::ofstream> foutPtr;
+ if (this->AppendMode) {
+ // Open for append.
+ auto openmodeApp = std::ios::app;
+ foutPtr = cm::make_unique<cmsys::ofstream>(this->MainImportFile.c_str(),
+ openmodeApp);
+ } else {
+ // Generate atomically and with copy-if-different.
+ std::unique_ptr<cmGeneratedFileStream> ap(
+ new cmGeneratedFileStream(this->MainImportFile, true));
+ ap->SetCopyIfDifferent(true);
+ foutPtr = std::move(ap);
+ }
+ if (!foutPtr || !*foutPtr) {
+ std::string se = cmSystemTools::GetLastSystemError();
+ std::ostringstream e;
+ e << "cannot write to file \"" << this->MainImportFile << "\": " << se;
+ cmSystemTools::Error(e.str());
+ return false;
+ }
+ std::ostream& os = *foutPtr;
+
+ // Start with the import file header.
+ this->GeneratePolicyHeaderCode(os);
+ this->GenerateImportHeaderCode(os);
+
+ // Create all the imported targets.
+ bool result = this->GenerateMainFile(os);
+
+ // End with the import file footer.
+ this->GenerateImportFooterCode(os);
+ this->GeneratePolicyFooterCode(os);
+
+ return result;
+}
+
+void cmExportFileGenerator::GenerateImportConfig(
+ std::ostream& os, const std::string& config,
+ std::vector<std::string>& missingTargets)
+{
+ // Construct the property configuration suffix.
+ std::string suffix = "_";
+ if (!config.empty()) {
+ suffix += cmSystemTools::UpperCase(config);
+ } else {
+ suffix += "NOCONFIG";
+ }
+
+ // Generate the per-config target information.
+ this->GenerateImportTargetsConfig(os, config, suffix, missingTargets);
+}
+
+void cmExportFileGenerator::PopulateInterfaceProperty(
+ const std::string& propName, cmGeneratorTarget* target,
+ ImportPropertyMap& properties)
+{
+ cmProp input = target->GetProperty(propName);
+ if (input) {
+ properties[propName] = *input;
+ }
+}
+
+void cmExportFileGenerator::PopulateInterfaceProperty(
+ const std::string& propName, const std::string& outputName,
+ cmGeneratorTarget* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ cmProp input = target->GetProperty(propName);
+ if (input) {
+ if (input->empty()) {
+ // Set to empty
+ properties[outputName].clear();
+ return;
+ }
+
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(*input, preprocessRule);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(prepro, target,
+ missingTargets);
+ properties[outputName] = prepro;
+ }
+ }
+}
+
+void cmExportFileGenerator::GenerateRequiredCMakeVersion(
+ std::ostream& os, const char* versionString)
+{
+ /* clang-format off */
+ os << "if(CMAKE_VERSION VERSION_LESS " << versionString << ")\n"
+ " message(FATAL_ERROR \"This file relies on consumers using "
+ "CMake " << versionString << " or greater.\")\n"
+ "endif()\n\n";
+ /* clang-format on */
+}
+
+bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty(
+ cmGeneratorTarget* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ if (!target->IsLinkable()) {
+ return false;
+ }
+ cmProp input = target->GetProperty("INTERFACE_LINK_LIBRARIES");
+ if (input) {
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(*input, preprocessRule);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(
+ prepro, target, missingTargets, ReplaceFreeTargets);
+ properties["INTERFACE_LINK_LIBRARIES"] = prepro;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool isSubDirectory(std::string const& a, std::string const& b)
+{
+ return (cmSystemTools::ComparePath(a, b) ||
+ cmSystemTools::IsSubDirectory(a, b));
+}
+
+static bool checkInterfaceDirs(const std::string& prepro,
+ cmGeneratorTarget* target,
+ const std::string& prop)
+{
+ std::string const& installDir =
+ target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
+ std::string const& topSourceDir =
+ target->GetLocalGenerator()->GetSourceDirectory();
+ std::string const& topBinaryDir =
+ target->GetLocalGenerator()->GetBinaryDirectory();
+
+ std::vector<std::string> parts;
+ cmGeneratorExpression::Split(prepro, parts);
+
+ const bool inSourceBuild = topSourceDir == topBinaryDir;
+
+ bool hadFatalError = false;
+
+ for (std::string const& li : parts) {
+ size_t genexPos = cmGeneratorExpression::Find(li);
+ if (genexPos == 0) {
+ continue;
+ }
+ if (cmHasLiteralPrefix(li, "${_IMPORT_PREFIX}")) {
+ continue;
+ }
+ MessageType messageType = MessageType::FATAL_ERROR;
+ std::ostringstream e;
+ if (genexPos != std::string::npos) {
+ if (prop == "INTERFACE_INCLUDE_DIRECTORIES") {
+ switch (target->GetPolicyStatusCMP0041()) {
+ case cmPolicies::WARN:
+ messageType = MessageType::WARNING;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0041) << "\n";
+ break;
+ case cmPolicies::OLD:
+ continue;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ hadFatalError = true;
+ break; // Issue fatal message.
+ }
+ } else {
+ hadFatalError = true;
+ }
+ }
+ if (!cmSystemTools::FileIsFullPath(li)) {
+ /* clang-format off */
+ e << "Target \"" << target->GetName() << "\" " << prop <<
+ " property contains relative path:\n"
+ " \"" << li << "\"";
+ /* clang-format on */
+ target->GetLocalGenerator()->IssueMessage(messageType, e.str());
+ }
+ bool inBinary = isSubDirectory(li, topBinaryDir);
+ bool inSource = isSubDirectory(li, topSourceDir);
+ if (isSubDirectory(li, installDir)) {
+ // The include directory is inside the install tree. If the
+ // install tree is not inside the source tree or build tree then
+ // fall through to the checks below that the include directory is not
+ // also inside the source tree or build tree.
+ bool shouldContinue =
+ (!inBinary || isSubDirectory(installDir, topBinaryDir)) &&
+ (!inSource || isSubDirectory(installDir, topSourceDir));
+
+ if (prop == "INTERFACE_INCLUDE_DIRECTORIES") {
+ if (!shouldContinue) {
+ switch (target->GetPolicyStatusCMP0052()) {
+ case cmPolicies::WARN: {
+ std::ostringstream s;
+ s << cmPolicies::GetPolicyWarning(cmPolicies::CMP0052) << "\n";
+ s << "Directory:\n \"" << li
+ << "\"\nin "
+ "INTERFACE_INCLUDE_DIRECTORIES of target \""
+ << target->GetName()
+ << "\" is a subdirectory of the install "
+ "directory:\n \""
+ << installDir
+ << "\"\nhowever it is also "
+ "a subdirectory of the "
+ << (inBinary ? "build" : "source") << " tree:\n \""
+ << (inBinary ? topBinaryDir : topSourceDir) << "\"\n";
+ target->GetLocalGenerator()->IssueMessage(
+ MessageType::AUTHOR_WARNING, s.str());
+ CM_FALLTHROUGH;
+ }
+ case cmPolicies::OLD:
+ shouldContinue = true;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ break;
+ }
+ }
+ }
+ if (shouldContinue) {
+ continue;
+ }
+ }
+ if (inBinary) {
+ /* clang-format off */
+ e << "Target \"" << target->GetName() << "\" " << prop <<
+ " property contains path:\n"
+ " \"" << li << "\"\nwhich is prefixed in the build directory.";
+ /* clang-format on */
+ target->GetLocalGenerator()->IssueMessage(messageType, e.str());
+ }
+ if (!inSourceBuild) {
+ if (inSource) {
+ e << "Target \"" << target->GetName() << "\" " << prop
+ << " property contains path:\n"
+ " \""
+ << li << "\"\nwhich is prefixed in the source directory.";
+ target->GetLocalGenerator()->IssueMessage(messageType, e.str());
+ }
+ }
+ }
+ return !hadFatalError;
+}
+
+static void prefixItems(std::string& exportDirs)
+{
+ std::vector<std::string> entries;
+ cmGeneratorExpression::Split(exportDirs, entries);
+ exportDirs.clear();
+ const char* sep = "";
+ for (std::string const& e : entries) {
+ exportDirs += sep;
+ sep = ";";
+ if (!cmSystemTools::FileIsFullPath(e) &&
+ e.find("${_IMPORT_PREFIX}") == std::string::npos) {
+ exportDirs += "${_IMPORT_PREFIX}/";
+ }
+ exportDirs += e;
+ }
+}
+
+void cmExportFileGenerator::PopulateSourcesInterface(
+ cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ cmGeneratorTarget* gt = tei->Target;
+ assert(preprocessRule == cmGeneratorExpression::InstallInterface);
+
+ const char* propName = "INTERFACE_SOURCES";
+ cmProp input = gt->GetProperty(propName);
+
+ if (!input) {
+ return;
+ }
+
+ if (input->empty()) {
+ properties[propName].clear();
+ return;
+ }
+
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(*input, preprocessRule, true);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(prepro, gt, missingTargets);
+
+ if (!checkInterfaceDirs(prepro, gt, propName)) {
+ return;
+ }
+ properties[propName] = prepro;
+ }
+}
+
+void cmExportFileGenerator::PopulateIncludeDirectoriesInterface(
+ cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ cmGeneratorTarget* target = tei->Target;
+ assert(preprocessRule == cmGeneratorExpression::InstallInterface);
+
+ const char* propName = "INTERFACE_INCLUDE_DIRECTORIES";
+ cmProp input = target->GetProperty(propName);
+
+ cmGeneratorExpression ge;
+
+ std::string dirs = cmGeneratorExpression::Preprocess(
+ tei->InterfaceIncludeDirectories, preprocessRule, true);
+ this->ReplaceInstallPrefix(dirs);
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(dirs);
+ std::string exportDirs =
+ cge->Evaluate(target->GetLocalGenerator(), "", target);
+
+ if (cge->GetHadContextSensitiveCondition()) {
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ std::ostringstream e;
+ e << "Target \"" << target->GetName()
+ << "\" is installed with "
+ "INCLUDES DESTINATION set to a context sensitive path. Paths which "
+ "depend on the configuration, policy values or the link interface "
+ "are "
+ "not supported. Consider using target_include_directories instead.";
+ lg->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+
+ if (!input && exportDirs.empty()) {
+ return;
+ }
+ if ((input && input->empty()) && exportDirs.empty()) {
+ // Set to empty
+ properties[propName].clear();
+ return;
+ }
+
+ prefixItems(exportDirs);
+
+ std::string includes = (input ? *input : "");
+ const char* sep = input ? ";" : "";
+ includes += sep + exportDirs;
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(includes, preprocessRule, true);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(prepro, target, missingTargets);
+
+ if (!checkInterfaceDirs(prepro, target, propName)) {
+ return;
+ }
+ properties[propName] = prepro;
+ }
+}
+
+void cmExportFileGenerator::PopulateLinkDependsInterface(
+ cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ cmGeneratorTarget* gt = tei->Target;
+ assert(preprocessRule == cmGeneratorExpression::InstallInterface);
+
+ const char* propName = "INTERFACE_LINK_DEPENDS";
+ cmProp input = gt->GetProperty(propName);
+
+ if (!input) {
+ return;
+ }
+
+ if (input->empty()) {
+ properties[propName].clear();
+ return;
+ }
+
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(*input, preprocessRule, true);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(prepro, gt, missingTargets);
+
+ if (!checkInterfaceDirs(prepro, gt, propName)) {
+ return;
+ }
+ properties[propName] = prepro;
+ }
+}
+
+void cmExportFileGenerator::PopulateLinkDirectoriesInterface(
+ cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ cmGeneratorTarget* gt = tei->Target;
+ assert(preprocessRule == cmGeneratorExpression::InstallInterface);
+
+ const char* propName = "INTERFACE_LINK_DIRECTORIES";
+ cmProp input = gt->GetProperty(propName);
+
+ if (!input) {
+ return;
+ }
+
+ if (input->empty()) {
+ properties[propName].clear();
+ return;
+ }
+
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(*input, preprocessRule, true);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(prepro, gt, missingTargets);
+
+ if (!checkInterfaceDirs(prepro, gt, propName)) {
+ return;
+ }
+ properties[propName] = prepro;
+ }
+}
+
+void cmExportFileGenerator::PopulateInterfaceProperty(
+ const std::string& propName, cmGeneratorTarget* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ this->PopulateInterfaceProperty(propName, propName, target, preprocessRule,
+ properties, missingTargets);
+}
+
+void getPropertyContents(cmGeneratorTarget const* tgt, const std::string& prop,
+ std::set<std::string>& ifaceProperties)
+{
+ cmProp p = tgt->GetProperty(prop);
+ if (!p) {
+ return;
+ }
+ std::vector<std::string> content = cmExpandedList(*p);
+ ifaceProperties.insert(content.begin(), content.end());
+}
+
+void getCompatibleInterfaceProperties(cmGeneratorTarget* target,
+ std::set<std::string>& ifaceProperties,
+ const std::string& config)
+{
+ if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ // object libraries have no link information, so nothing to compute
+ return;
+ }
+
+ cmComputeLinkInformation* info = target->GetLinkInformation(config);
+
+ if (!info) {
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ std::ostringstream e;
+ e << "Exporting the target \"" << target->GetName()
+ << "\" is not "
+ "allowed since its linker language cannot be determined";
+ lg->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+
+ const cmComputeLinkInformation::ItemVector& deps = info->GetItems();
+
+ for (auto const& dep : deps) {
+ if (!dep.Target) {
+ continue;
+ }
+ getPropertyContents(dep.Target, "COMPATIBLE_INTERFACE_BOOL",
+ ifaceProperties);
+ getPropertyContents(dep.Target, "COMPATIBLE_INTERFACE_STRING",
+ ifaceProperties);
+ getPropertyContents(dep.Target, "COMPATIBLE_INTERFACE_NUMBER_MIN",
+ ifaceProperties);
+ getPropertyContents(dep.Target, "COMPATIBLE_INTERFACE_NUMBER_MAX",
+ ifaceProperties);
+ }
+}
+
+void cmExportFileGenerator::PopulateCompatibleInterfaceProperties(
+ cmGeneratorTarget* gtarget, ImportPropertyMap& properties)
+{
+ this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_BOOL", gtarget,
+ properties);
+ this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_STRING", gtarget,
+ properties);
+ this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_NUMBER_MIN", gtarget,
+ properties);
+ this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_NUMBER_MAX", gtarget,
+ properties);
+
+ std::set<std::string> ifaceProperties;
+
+ getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_BOOL", ifaceProperties);
+ getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_STRING", ifaceProperties);
+ getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_NUMBER_MIN",
+ ifaceProperties);
+ getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_NUMBER_MAX",
+ ifaceProperties);
+
+ if (gtarget->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+ std::vector<std::string> configNames =
+ gtarget->Target->GetMakefile()->GetGeneratorConfigs(
+ cmMakefile::IncludeEmptyConfig);
+
+ for (std::string const& cn : configNames) {
+ getCompatibleInterfaceProperties(gtarget, ifaceProperties, cn);
+ }
+ }
+
+ for (std::string const& ip : ifaceProperties) {
+ this->PopulateInterfaceProperty("INTERFACE_" + ip, gtarget, properties);
+ }
+}
+
+void cmExportFileGenerator::GenerateInterfaceProperties(
+ const cmGeneratorTarget* target, std::ostream& os,
+ const ImportPropertyMap& properties)
+{
+ if (!properties.empty()) {
+ std::string targetName =
+ cmStrCat(this->Namespace, target->GetExportName());
+ os << "set_target_properties(" << targetName << " PROPERTIES\n";
+ for (auto const& property : properties) {
+ os << " " << property.first << " "
+ << cmExportFileGeneratorEscape(property.second) << "\n";
+ }
+ os << ")\n\n";
+ }
+}
+
+bool cmExportFileGenerator::AddTargetNamespace(
+ std::string& input, cmGeneratorTarget* target,
+ std::vector<std::string>& missingTargets)
+{
+ cmGeneratorTarget::TargetOrString resolved =
+ target->ResolveTargetReference(input);
+
+ cmGeneratorTarget* tgt = resolved.Target;
+ if (!tgt) {
+ input = resolved.String;
+ return false;
+ }
+
+ if (tgt->IsImported()) {
+ input = tgt->GetName();
+ return true;
+ }
+ if (this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) {
+ input = this->Namespace + tgt->GetExportName();
+ } else {
+ std::string namespacedTarget;
+ this->HandleMissingTarget(namespacedTarget, missingTargets, target, tgt);
+ if (!namespacedTarget.empty()) {
+ input = namespacedTarget;
+ } else {
+ input = tgt->GetName();
+ }
+ }
+ return true;
+}
+
+void cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
+ std::string& input, cmGeneratorTarget* target,
+ std::vector<std::string>& missingTargets, FreeTargetsReplace replace)
+{
+ if (replace == NoReplaceFreeTargets) {
+ this->ResolveTargetsInGeneratorExpression(input, target, missingTargets);
+ return;
+ }
+ std::vector<std::string> parts;
+ cmGeneratorExpression::Split(input, parts);
+
+ std::string sep;
+ input.clear();
+ for (std::string& li : parts) {
+ if (cmHasLiteralPrefix(li, CMAKE_DIRECTORY_ID_SEP)) {
+ continue;
+ }
+ if (cmGeneratorExpression::Find(li) == std::string::npos) {
+ this->AddTargetNamespace(li, target, missingTargets);
+ } else {
+ this->ResolveTargetsInGeneratorExpression(li, target, missingTargets);
+ }
+ input += sep + li;
+ sep = ";";
+ }
+}
+
+void cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
+ std::string& input, cmGeneratorTarget* target,
+ std::vector<std::string>& missingTargets)
+{
+ std::string::size_type pos = 0;
+ std::string::size_type lastPos = pos;
+
+ while ((pos = input.find("$<TARGET_PROPERTY:", lastPos)) !=
+ std::string::npos) {
+ std::string::size_type nameStartPos =
+ pos + sizeof("$<TARGET_PROPERTY:") - 1;
+ std::string::size_type closePos = input.find('>', nameStartPos);
+ std::string::size_type commaPos = input.find(',', nameStartPos);
+ std::string::size_type nextOpenPos = input.find("$<", nameStartPos);
+ if (commaPos == std::string::npos // Implied 'this' target
+ || closePos == std::string::npos // Incomplete expression.
+ || closePos < commaPos // Implied 'this' target
+ || nextOpenPos < commaPos) // Non-literal
+ {
+ lastPos = nameStartPos;
+ continue;
+ }
+
+ std::string targetName =
+ input.substr(nameStartPos, commaPos - nameStartPos);
+
+ if (this->AddTargetNamespace(targetName, target, missingTargets)) {
+ input.replace(nameStartPos, commaPos - nameStartPos, targetName);
+ }
+ lastPos = nameStartPos + targetName.size() + 1;
+ }
+
+ std::string errorString;
+ pos = 0;
+ lastPos = pos;
+ while ((pos = input.find("$<TARGET_NAME:", lastPos)) != std::string::npos) {
+ std::string::size_type nameStartPos = pos + sizeof("$<TARGET_NAME:") - 1;
+ std::string::size_type endPos = input.find('>', nameStartPos);
+ if (endPos == std::string::npos) {
+ errorString = "$<TARGET_NAME:...> expression incomplete";
+ break;
+ }
+ std::string targetName = input.substr(nameStartPos, endPos - nameStartPos);
+ if (targetName.find("$<") != std::string::npos) {
+ errorString = "$<TARGET_NAME:...> requires its parameter to be a "
+ "literal.";
+ break;
+ }
+ if (!this->AddTargetNamespace(targetName, target, missingTargets)) {
+ errorString = "$<TARGET_NAME:...> requires its parameter to be a "
+ "reachable target.";
+ break;
+ }
+ input.replace(pos, endPos - pos + 1, targetName);
+ lastPos = pos + targetName.size();
+ }
+
+ pos = 0;
+ lastPos = pos;
+ while (errorString.empty() &&
+ (pos = input.find("$<LINK_ONLY:", lastPos)) != std::string::npos) {
+ std::string::size_type nameStartPos = pos + sizeof("$<LINK_ONLY:") - 1;
+ std::string::size_type endPos = input.find('>', nameStartPos);
+ if (endPos == std::string::npos) {
+ errorString = "$<LINK_ONLY:...> expression incomplete";
+ break;
+ }
+ std::string libName = input.substr(nameStartPos, endPos - nameStartPos);
+ if (cmGeneratorExpression::IsValidTargetName(libName) &&
+ this->AddTargetNamespace(libName, target, missingTargets)) {
+ input.replace(nameStartPos, endPos - nameStartPos, libName);
+ }
+ lastPos = nameStartPos + libName.size() + 1;
+ }
+
+ this->ReplaceInstallPrefix(input);
+
+ if (!errorString.empty()) {
+ target->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
+ errorString);
+ }
+}
+
+void cmExportFileGenerator::ReplaceInstallPrefix(std::string& /*unused*/)
+{
+ // Do nothing
+}
+
+void cmExportFileGenerator::SetImportLinkInterface(
+ const std::string& config, std::string const& suffix,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ cmGeneratorTarget* target, ImportPropertyMap& properties,
+ std::vector<std::string>& missingTargets)
+{
+ // Add the transitive link dependencies for this configuration.
+ cmLinkInterface const* iface = target->GetLinkInterface(config, target);
+ if (!iface) {
+ return;
+ }
+
+ if (iface->ImplementationIsInterface) {
+ // Policy CMP0022 must not be NEW.
+ this->SetImportLinkProperty(
+ suffix, target, "IMPORTED_LINK_INTERFACE_LIBRARIES", iface->Libraries,
+ properties, missingTargets, ImportLinkPropertyTargetNames::Yes);
+ return;
+ }
+
+ cmProp propContent;
+
+ if (cmProp prop_suffixed =
+ target->GetProperty("LINK_INTERFACE_LIBRARIES" + suffix)) {
+ propContent = prop_suffixed;
+ } else if (cmProp prop = target->GetProperty("LINK_INTERFACE_LIBRARIES")) {
+ propContent = prop;
+ } else {
+ return;
+ }
+
+ const bool newCMP0022Behavior =
+ target->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
+ target->GetPolicyStatusCMP0022() != cmPolicies::OLD;
+
+ if (newCMP0022Behavior && !this->ExportOld) {
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ std::ostringstream e;
+ e << "Target \"" << target->GetName()
+ << "\" has policy CMP0022 enabled, "
+ "but also has old-style LINK_INTERFACE_LIBRARIES properties "
+ "populated, but it was exported without the "
+ "EXPORT_LINK_INTERFACE_LIBRARIES to export the old-style properties";
+ lg->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+
+ if (propContent->empty()) {
+ properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix].clear();
+ return;
+ }
+
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(*propContent, preprocessRule);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(prepro, target, missingTargets,
+ ReplaceFreeTargets);
+ properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro;
+ }
+}
+
+void cmExportFileGenerator::SetImportDetailProperties(
+ const std::string& config, std::string const& suffix,
+ cmGeneratorTarget* target, ImportPropertyMap& properties,
+ std::vector<std::string>& missingTargets)
+{
+ // Get the makefile in which to lookup target information.
+ cmMakefile* mf = target->Makefile;
+
+ // Add the soname for unix shared libraries.
+ if (target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ target->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ if (!target->IsDLLPlatform()) {
+ std::string prop;
+ std::string value;
+ if (target->HasSOName(config)) {
+ if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ value = this->InstallNameDir(target, config);
+ }
+ prop = "IMPORTED_SONAME";
+ value += target->GetSOName(config);
+ } else {
+ prop = "IMPORTED_NO_SONAME";
+ value = "TRUE";
+ }
+ prop += suffix;
+ properties[prop] = value;
+ }
+ }
+
+ // Add the transitive link dependencies for this configuration.
+ if (cmLinkInterface const* iface =
+ target->GetLinkInterface(config, target)) {
+ this->SetImportLinkProperty(
+ suffix, target, "IMPORTED_LINK_INTERFACE_LANGUAGES", iface->Languages,
+ properties, missingTargets, ImportLinkPropertyTargetNames::No);
+
+ std::vector<std::string> dummy;
+ this->SetImportLinkProperty(
+ suffix, target, "IMPORTED_LINK_DEPENDENT_LIBRARIES", iface->SharedDeps,
+ properties, dummy, ImportLinkPropertyTargetNames::Yes);
+ if (iface->Multiplicity > 0) {
+ std::string prop =
+ cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix);
+ properties[prop] = std::to_string(iface->Multiplicity);
+ }
+ }
+
+ // Add information if this target is a managed target
+ if (target->GetManagedType(config) !=
+ cmGeneratorTarget::ManagedType::Native) {
+ std::string prop = cmStrCat("IMPORTED_COMMON_LANGUAGE_RUNTIME", suffix);
+ std::string propval;
+ if (cmProp p = target->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
+ propval = *p;
+ } else if (target->IsCSharpOnly()) {
+ // C# projects do not have the /clr flag, so we set the property
+ // here to mark the target as (only) managed (i.e. no .lib file
+ // to link to). Otherwise the COMMON_LANGUAGE_RUNTIME target
+ // property would have to be set manually for C# targets to make
+ // exporting/importing work.
+ propval = "CSharp";
+ }
+ properties[prop] = propval;
+ }
+}
+
+static std::string const& asString(std::string const& l)
+{
+ return l;
+}
+
+static std::string const& asString(cmLinkItem const& l)
+{
+ return l.AsStr();
+}
+
+template <typename T>
+void cmExportFileGenerator::SetImportLinkProperty(
+ std::string const& suffix, cmGeneratorTarget* target,
+ const std::string& propName, std::vector<T> const& entries,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets,
+ ImportLinkPropertyTargetNames targetNames)
+{
+ // Skip the property if there are no entries.
+ if (entries.empty()) {
+ return;
+ }
+
+ // Construct the property value.
+ std::string link_entries;
+ const char* sep = "";
+ for (T const& l : entries) {
+ // Separate this from the previous entry.
+ link_entries += sep;
+ sep = ";";
+
+ if (targetNames == ImportLinkPropertyTargetNames::Yes) {
+ std::string temp = asString(l);
+ this->AddTargetNamespace(temp, target, missingTargets);
+ link_entries += temp;
+ } else {
+ link_entries += asString(l);
+ }
+ }
+
+ // Store the property.
+ std::string prop = cmStrCat(propName, suffix);
+ properties[prop] = link_entries;
+}
+
+void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os)
+{
+ // Protect that file against use with older CMake versions.
+ /* clang-format off */
+ os << "# Generated by CMake\n\n";
+ os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.5)\n"
+ << " message(FATAL_ERROR \"CMake >= 2.6.0 required\")\n"
+ << "endif()\n";
+ /* clang-format on */
+
+ // Isolate the file policy level.
+ // Support CMake versions as far back as 2.6 but also support using NEW
+ // policy settings for up to CMake 3.19 (this upper limit may be reviewed
+ // and increased from time to time). This reduces the opportunity for CMake
+ // warnings when an older export file is later used with newer CMake
+ // versions.
+ /* clang-format off */
+ os << "cmake_policy(PUSH)\n"
+ << "cmake_policy(VERSION 2.6...3.19)\n";
+ /* clang-format on */
+}
+
+void cmExportFileGenerator::GeneratePolicyFooterCode(std::ostream& os)
+{
+ os << "cmake_policy(POP)\n";
+}
+
+void cmExportFileGenerator::GenerateImportHeaderCode(std::ostream& os,
+ const std::string& config)
+{
+ os << "#----------------------------------------------------------------\n"
+ << "# Generated CMake target import file";
+ if (!config.empty()) {
+ os << " for configuration \"" << config << "\".\n";
+ } else {
+ os << ".\n";
+ }
+ os << "#----------------------------------------------------------------\n"
+ << "\n";
+ this->GenerateImportVersionCode(os);
+}
+
+void cmExportFileGenerator::GenerateImportFooterCode(std::ostream& os)
+{
+ os << "# Commands beyond this point should not need to know the version.\n"
+ << "set(CMAKE_IMPORT_FILE_VERSION)\n";
+}
+
+void cmExportFileGenerator::GenerateImportVersionCode(std::ostream& os)
+{
+ // Store an import file format version. This will let us change the
+ // format later while still allowing old import files to work.
+ /* clang-format off */
+ os << "# Commands may need to know the format version.\n"
+ << "set(CMAKE_IMPORT_FILE_VERSION 1)\n"
+ << "\n";
+ /* clang-format on */
+}
+
+void cmExportFileGenerator::GenerateExpectedTargetsCode(
+ std::ostream& os, const std::string& expectedTargets)
+{
+ /* clang-format off */
+ os << "# Protect against multiple inclusion, which would fail when already "
+ "imported targets are added once more.\n"
+ "set(_targetsDefined)\n"
+ "set(_targetsNotDefined)\n"
+ "set(_expectedTargets)\n"
+ "foreach(_expectedTarget " << expectedTargets << ")\n"
+ " list(APPEND _expectedTargets ${_expectedTarget})\n"
+ " if(NOT TARGET ${_expectedTarget})\n"
+ " list(APPEND _targetsNotDefined ${_expectedTarget})\n"
+ " endif()\n"
+ " if(TARGET ${_expectedTarget})\n"
+ " list(APPEND _targetsDefined ${_expectedTarget})\n"
+ " endif()\n"
+ "endforeach()\n"
+ "if(\"${_targetsDefined}\" STREQUAL \"${_expectedTargets}\")\n"
+ " unset(_targetsDefined)\n"
+ " unset(_targetsNotDefined)\n"
+ " unset(_expectedTargets)\n"
+ " set(CMAKE_IMPORT_FILE_VERSION)\n"
+ " cmake_policy(POP)\n"
+ " return()\n"
+ "endif()\n"
+ "if(NOT \"${_targetsDefined}\" STREQUAL \"\")\n"
+ " message(FATAL_ERROR \"Some (but not all) targets in this export "
+ "set were already defined.\\nTargets Defined: ${_targetsDefined}\\n"
+ "Targets not yet defined: ${_targetsNotDefined}\\n\")\n"
+ "endif()\n"
+ "unset(_targetsDefined)\n"
+ "unset(_targetsNotDefined)\n"
+ "unset(_expectedTargets)\n"
+ "\n\n";
+ /* clang-format on */
+}
+
+void cmExportFileGenerator::GenerateImportTargetCode(
+ std::ostream& os, cmGeneratorTarget const* target,
+ cmStateEnums::TargetType targetType)
+{
+ // Construct the imported target name.
+ std::string targetName = this->Namespace;
+
+ targetName += target->GetExportName();
+
+ // Create the imported target.
+ os << "# Create imported target " << targetName << "\n";
+ switch (targetType) {
+ case cmStateEnums::EXECUTABLE:
+ os << "add_executable(" << targetName << " IMPORTED)\n";
+ break;
+ case cmStateEnums::STATIC_LIBRARY:
+ os << "add_library(" << targetName << " STATIC IMPORTED)\n";
+ break;
+ case cmStateEnums::SHARED_LIBRARY:
+ os << "add_library(" << targetName << " SHARED IMPORTED)\n";
+ break;
+ case cmStateEnums::MODULE_LIBRARY:
+ os << "add_library(" << targetName << " MODULE IMPORTED)\n";
+ break;
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ os << "add_library(" << targetName << " UNKNOWN IMPORTED)\n";
+ break;
+ case cmStateEnums::OBJECT_LIBRARY:
+ os << "add_library(" << targetName << " OBJECT IMPORTED)\n";
+ break;
+ case cmStateEnums::INTERFACE_LIBRARY:
+ os << "add_library(" << targetName << " INTERFACE IMPORTED)\n";
+ break;
+ default: // should never happen
+ break;
+ }
+
+ // Mark the imported executable if it has exports.
+ if (target->IsExecutableWithExports()) {
+ os << "set_property(TARGET " << targetName
+ << " PROPERTY ENABLE_EXPORTS 1)\n";
+ }
+
+ // Mark the imported library if it is a framework.
+ if (target->IsFrameworkOnApple()) {
+ os << "set_property(TARGET " << targetName << " PROPERTY FRAMEWORK 1)\n";
+ }
+
+ // Mark the imported executable if it is an application bundle.
+ if (target->IsAppBundleOnApple()) {
+ os << "set_property(TARGET " << targetName
+ << " PROPERTY MACOSX_BUNDLE 1)\n";
+ }
+
+ if (target->IsCFBundleOnApple()) {
+ os << "set_property(TARGET " << targetName << " PROPERTY BUNDLE 1)\n";
+ }
+
+ // generate DEPRECATION
+ if (target->IsDeprecated()) {
+ os << "set_property(TARGET " << targetName << " PROPERTY DEPRECATION "
+ << cmExportFileGeneratorEscape(target->GetDeprecation()) << ")\n";
+ }
+ os << "\n";
+}
+
+void cmExportFileGenerator::GenerateImportPropertyCode(
+ std::ostream& os, const std::string& config, cmGeneratorTarget const* target,
+ ImportPropertyMap const& properties)
+{
+ // Construct the imported target name.
+ std::string targetName = this->Namespace;
+
+ targetName += target->GetExportName();
+
+ // Set the import properties.
+ os << "# Import target \"" << targetName << "\" for configuration \""
+ << config << "\"\n";
+ os << "set_property(TARGET " << targetName
+ << " APPEND PROPERTY IMPORTED_CONFIGURATIONS ";
+ if (!config.empty()) {
+ os << cmSystemTools::UpperCase(config);
+ } else {
+ os << "NOCONFIG";
+ }
+ os << ")\n";
+ os << "set_target_properties(" << targetName << " PROPERTIES\n";
+ for (auto const& property : properties) {
+ os << " " << property.first << " "
+ << cmExportFileGeneratorEscape(property.second) << "\n";
+ }
+ os << " )\n"
+ << "\n";
+}
+
+void cmExportFileGenerator::GenerateMissingTargetsCheckCode(
+ std::ostream& os, const std::vector<std::string>& missingTargets)
+{
+ if (missingTargets.empty()) {
+ /* clang-format off */
+ os << "# This file does not depend on other imported targets which have\n"
+ "# been exported from the same project but in a separate "
+ "export set.\n\n";
+ /* clang-format on */
+ return;
+ }
+ /* clang-format off */
+ os << "# Make sure the targets which have been exported in some other\n"
+ "# export set exist.\n"
+ "unset(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)\n"
+ "foreach(_target ";
+ /* clang-format on */
+ std::set<std::string> emitted;
+ for (std::string const& missingTarget : missingTargets) {
+ if (emitted.insert(missingTarget).second) {
+ os << "\"" << missingTarget << "\" ";
+ }
+ }
+ /* clang-format off */
+ os << ")\n"
+ " if(NOT TARGET \"${_target}\" )\n"
+ " set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets \""
+ "${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets} ${_target}\")"
+ "\n"
+ " endif()\n"
+ "endforeach()\n"
+ "\n"
+ "if(DEFINED ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)\n"
+ " if(CMAKE_FIND_PACKAGE_NAME)\n"
+ " set( ${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)\n"
+ " set( ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "
+ "\"The following imported targets are "
+ "referenced, but are missing: "
+ "${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets}\")\n"
+ " else()\n"
+ " message(FATAL_ERROR \"The following imported targets are "
+ "referenced, but are missing: "
+ "${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets}\")\n"
+ " endif()\n"
+ "endif()\n"
+ "unset(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)\n"
+ "\n";
+ /* clang-format on */
+}
+
+void cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os)
+{
+ // Add code which verifies at cmake time that the file which is being
+ // imported actually exists on disk. This should in theory always be theory
+ // case, but still when packages are split into normal and development
+ // packages this might get broken (e.g. the Config.cmake could be part of
+ // the non-development package, something similar happened to me without
+ // on SUSE with a mysql pkg-config file, which claimed everything is fine,
+ // but the development package was not installed.).
+ /* clang-format off */
+ os << "# Loop over all imported files and verify that they actually exist\n"
+ "foreach(target ${_IMPORT_CHECK_TARGETS} )\n"
+ " foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )\n"
+ " if(NOT EXISTS \"${file}\" )\n"
+ " message(FATAL_ERROR \"The imported target \\\"${target}\\\""
+ " references the file\n"
+ " \\\"${file}\\\"\n"
+ "but this file does not exist. Possible reasons include:\n"
+ "* The file was deleted, renamed, or moved to another location.\n"
+ "* An install or uninstall procedure did not complete successfully.\n"
+ "* The installation package was faulty and contained\n"
+ " \\\"${CMAKE_CURRENT_LIST_FILE}\\\"\n"
+ "but not all the files it references.\n"
+ "\")\n"
+ " endif()\n"
+ " endforeach()\n"
+ " unset(_IMPORT_CHECK_FILES_FOR_${target})\n"
+ "endforeach()\n"
+ "unset(_IMPORT_CHECK_TARGETS)\n"
+ "\n";
+ /* clang-format on */
+}
+
+void cmExportFileGenerator::GenerateImportedFileChecksCode(
+ std::ostream& os, cmGeneratorTarget* target,
+ ImportPropertyMap const& properties,
+ const std::set<std::string>& importedLocations)
+{
+ // Construct the imported target name.
+ std::string targetName = cmStrCat(this->Namespace, target->GetExportName());
+
+ os << "list(APPEND _IMPORT_CHECK_TARGETS " << targetName
+ << " )\n"
+ "list(APPEND _IMPORT_CHECK_FILES_FOR_"
+ << targetName << " ";
+
+ for (std::string const& li : importedLocations) {
+ auto pi = properties.find(li);
+ if (pi != properties.end()) {
+ os << cmExportFileGeneratorEscape(pi->second) << " ";
+ }
+ }
+
+ os << ")\n\n";
+}
+
+bool cmExportFileGenerator::PopulateExportProperties(
+ cmGeneratorTarget* gte, ImportPropertyMap& properties,
+ std::string& errorMessage)
+{
+ const auto& targetProperties = gte->Target->GetProperties();
+ if (cmProp exportProperties =
+ targetProperties.GetPropertyValue("EXPORT_PROPERTIES")) {
+ for (auto& prop : cmExpandedList(*exportProperties)) {
+ /* Black list reserved properties */
+ if (cmHasLiteralPrefix(prop, "IMPORTED_") ||
+ cmHasLiteralPrefix(prop, "INTERFACE_")) {
+ std::ostringstream e;
+ e << "Target \"" << gte->Target->GetName() << "\" contains property \""
+ << prop << "\" in EXPORT_PROPERTIES but IMPORTED_* and INTERFACE_* "
+ << "properties are reserved.";
+ errorMessage = e.str();
+ return false;
+ }
+ cmProp propertyValue = targetProperties.GetPropertyValue(prop);
+ if (propertyValue == nullptr) {
+ // Asked to export a property that isn't defined on the target. Do not
+ // consider this an error, there's just nothing to export.
+ continue;
+ }
+ std::string evaluatedValue = cmGeneratorExpression::Preprocess(
+ *propertyValue, cmGeneratorExpression::StripAllGeneratorExpressions);
+ if (evaluatedValue != *propertyValue) {
+ std::ostringstream e;
+ e << "Target \"" << gte->Target->GetName() << "\" contains property \""
+ << prop << "\" in EXPORT_PROPERTIES but this property contains a "
+ << "generator expression. This is not allowed.";
+ errorMessage = e.str();
+ return false;
+ }
+ properties[prop] = *propertyValue;
+ }
+ }
+ return true;
+}
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
new file mode 100644
index 0000000..45eaed0
--- /dev/null
+++ b/Source/cmExportFileGenerator.h
@@ -0,0 +1,224 @@
+/* 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 <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmGeneratorExpression.h"
+#include "cmStateTypes.h"
+#include "cmVersion.h"
+#include "cmVersionConfig.h"
+
+class cmGeneratorTarget;
+
+#define STRINGIFY_HELPER(X) #X
+#define STRINGIFY(X) STRINGIFY_HELPER(X)
+
+#define DEVEL_CMAKE_VERSION(major, minor) \
+ (CMake_VERSION_ENCODE(major, minor, 0) > \
+ CMake_VERSION_ENCODE(CMake_VERSION_MAJOR, CMake_VERSION_MINOR, 0) \
+ ? STRINGIFY(CMake_VERSION_MAJOR) "." STRINGIFY( \
+ CMake_VERSION_MINOR) "." STRINGIFY(CMake_VERSION_PATCH) \
+ : #major "." #minor ".0")
+
+class cmTargetExport;
+
+/** \class cmExportFileGenerator
+ * \brief Generate a file exporting targets from a build or install tree.
+ *
+ * cmExportFileGenerator is the superclass for
+ * cmExportBuildFileGenerator and cmExportInstallFileGenerator. It
+ * contains common code generation routines for the two kinds of
+ * export implementations.
+ */
+class cmExportFileGenerator
+{
+public:
+ cmExportFileGenerator();
+ virtual ~cmExportFileGenerator() = default;
+
+ /** Set the full path to the export file to generate. */
+ void SetExportFile(const char* mainFile);
+ const std::string& GetMainExportFileName() const;
+
+ /** Set the namespace in which to place exported target names. */
+ void SetNamespace(const std::string& ns) { this->Namespace = ns; }
+ std::string GetNamespace() const { return this->Namespace; }
+
+ void SetExportOld(bool exportOld) { this->ExportOld = exportOld; }
+
+ /** Add a configuration to be exported. */
+ void AddConfiguration(const std::string& config);
+
+ /** Actually generate the export file. Returns whether there was an
+ error. */
+ bool GenerateImportFile();
+
+protected:
+ using ImportPropertyMap = std::map<std::string, std::string>;
+
+ // Generate per-configuration target information to the given output
+ // stream.
+ void GenerateImportConfig(std::ostream& os, const std::string& config,
+ std::vector<std::string>& missingTargets);
+
+ // Methods to implement export file code generation.
+ virtual void GeneratePolicyHeaderCode(std::ostream& os);
+ virtual void GeneratePolicyFooterCode(std::ostream& os);
+ virtual void GenerateImportHeaderCode(std::ostream& os,
+ const std::string& config = "");
+ virtual void GenerateImportFooterCode(std::ostream& os);
+ void GenerateImportVersionCode(std::ostream& os);
+ virtual void GenerateImportTargetCode(std::ostream& os,
+ cmGeneratorTarget const* target,
+ cmStateEnums::TargetType targetType);
+ virtual void GenerateImportPropertyCode(std::ostream& os,
+ const std::string& config,
+ cmGeneratorTarget const* target,
+ ImportPropertyMap const& properties);
+ virtual void GenerateImportedFileChecksCode(
+ std::ostream& os, cmGeneratorTarget* target,
+ ImportPropertyMap const& properties,
+ const std::set<std::string>& importedLocations);
+ virtual void GenerateImportedFileCheckLoop(std::ostream& os);
+ virtual void GenerateMissingTargetsCheckCode(
+ std::ostream& os, const std::vector<std::string>& missingTargets);
+
+ virtual void GenerateExpectedTargetsCode(std::ostream& os,
+ const std::string& expectedTargets);
+
+ // Collect properties with detailed information about targets beyond
+ // their location on disk.
+ void SetImportDetailProperties(const std::string& config,
+ std::string const& suffix,
+ cmGeneratorTarget* target,
+ ImportPropertyMap& properties,
+ std::vector<std::string>& missingTargets);
+
+ enum class ImportLinkPropertyTargetNames
+ {
+ Yes,
+ No,
+ };
+ template <typename T>
+ void SetImportLinkProperty(std::string const& suffix,
+ cmGeneratorTarget* target,
+ const std::string& propName,
+ std::vector<T> const& entries,
+ ImportPropertyMap& properties,
+ std::vector<std::string>& missingTargets,
+ ImportLinkPropertyTargetNames targetNames);
+
+ /** Each subclass knows how to generate its kind of export file. */
+ virtual bool GenerateMainFile(std::ostream& os) = 0;
+
+ /** Each subclass knows where the target files are located. */
+ virtual void GenerateImportTargetsConfig(
+ std::ostream& os, const std::string& config, std::string const& suffix,
+ std::vector<std::string>& missingTargets) = 0;
+
+ /** Each subclass knows how to deal with a target that is missing from an
+ * export set. */
+ virtual void HandleMissingTarget(std::string& link_libs,
+ std::vector<std::string>& missingTargets,
+ cmGeneratorTarget* depender,
+ cmGeneratorTarget* dependee) = 0;
+ void PopulateInterfaceProperty(const std::string&, cmGeneratorTarget* target,
+ cmGeneratorExpression::PreprocessContext,
+ ImportPropertyMap& properties,
+ std::vector<std::string>& missingTargets);
+ bool PopulateInterfaceLinkLibrariesProperty(
+ cmGeneratorTarget* target, cmGeneratorExpression::PreprocessContext,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
+ void PopulateInterfaceProperty(const std::string& propName,
+ cmGeneratorTarget* target,
+ ImportPropertyMap& properties);
+ void PopulateCompatibleInterfaceProperties(cmGeneratorTarget* target,
+ ImportPropertyMap& properties);
+ virtual void GenerateInterfaceProperties(
+ cmGeneratorTarget const* target, std::ostream& os,
+ const ImportPropertyMap& properties);
+ void PopulateIncludeDirectoriesInterface(
+ cmTargetExport* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
+ void PopulateSourcesInterface(
+ cmTargetExport* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
+ void PopulateLinkDirectoriesInterface(
+ cmTargetExport* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
+ void PopulateLinkDependsInterface(
+ cmTargetExport* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
+
+ void SetImportLinkInterface(
+ const std::string& config, std::string const& suffix,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ cmGeneratorTarget* target, ImportPropertyMap& properties,
+ std::vector<std::string>& missingTargets);
+
+ enum FreeTargetsReplace
+ {
+ ReplaceFreeTargets,
+ NoReplaceFreeTargets
+ };
+
+ void ResolveTargetsInGeneratorExpressions(
+ std::string& input, cmGeneratorTarget* target,
+ std::vector<std::string>& missingTargets,
+ FreeTargetsReplace replace = NoReplaceFreeTargets);
+
+ virtual void GenerateRequiredCMakeVersion(std::ostream& os,
+ const char* versionString);
+
+ bool PopulateExportProperties(cmGeneratorTarget* gte,
+ ImportPropertyMap& properties,
+ std::string& errorMessage);
+
+ // The namespace in which the exports are placed in the generated file.
+ std::string Namespace;
+
+ bool ExportOld;
+
+ // The set of configurations to export.
+ std::vector<std::string> Configurations;
+
+ // The file to generate.
+ std::string MainImportFile;
+ std::string FileDir;
+ std::string FileBase;
+ std::string FileExt;
+ bool AppendMode;
+
+ // The set of targets included in the export.
+ std::set<cmGeneratorTarget*> ExportedTargets;
+
+private:
+ void PopulateInterfaceProperty(const std::string&, const std::string&,
+ cmGeneratorTarget* target,
+ cmGeneratorExpression::PreprocessContext,
+ ImportPropertyMap& properties,
+ std::vector<std::string>& missingTargets);
+
+ bool AddTargetNamespace(std::string& input, cmGeneratorTarget* target,
+ std::vector<std::string>& missingTargets);
+
+ void ResolveTargetsInGeneratorExpression(
+ std::string& input, cmGeneratorTarget* target,
+ std::vector<std::string>& missingTargets);
+
+ virtual void ReplaceInstallPrefix(std::string& input);
+
+ virtual std::string InstallNameDir(cmGeneratorTarget* target,
+ const std::string& config) = 0;
+};
diff --git a/Source/cmExportInstallAndroidMKGenerator.cxx b/Source/cmExportInstallAndroidMKGenerator.cxx
new file mode 100644
index 0000000..80f776e
--- /dev/null
+++ b/Source/cmExportInstallAndroidMKGenerator.cxx
@@ -0,0 +1,138 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExportInstallAndroidMKGenerator.h"
+
+#include <cstddef>
+#include <memory>
+#include <ostream>
+
+#include "cmExportBuildAndroidMKGenerator.h"
+#include "cmExportSet.h"
+#include "cmGeneratorTarget.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallTargetGenerator.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetExport.h"
+
+cmExportInstallAndroidMKGenerator::cmExportInstallAndroidMKGenerator(
+ cmInstallExportGenerator* iegen)
+ : cmExportInstallFileGenerator(iegen)
+{
+}
+
+void cmExportInstallAndroidMKGenerator::GenerateImportHeaderCode(
+ std::ostream& os, const std::string&)
+{
+ std::string installDir = this->IEGen->GetDestination();
+ os << "LOCAL_PATH := $(call my-dir)\n";
+ size_t numDotDot = cmSystemTools::CountChar(installDir.c_str(), '/');
+ numDotDot += installDir.empty() ? 0 : 1;
+ std::string path;
+ for (size_t n = 0; n < numDotDot; n++) {
+ path += "/..";
+ }
+ os << "_IMPORT_PREFIX := "
+ << "$(LOCAL_PATH)" << path << "\n\n";
+ for (std::unique_ptr<cmTargetExport> const& te :
+ this->IEGen->GetExportSet()->GetTargetExports()) {
+ // Collect import properties for this target.
+ if (te->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ continue;
+ }
+ std::string dest;
+ if (te->LibraryGenerator) {
+ dest = te->LibraryGenerator->GetDestination("");
+ }
+ if (te->ArchiveGenerator) {
+ dest = te->ArchiveGenerator->GetDestination("");
+ }
+ te->Target->Target->SetProperty("__dest", dest);
+ }
+}
+
+void cmExportInstallAndroidMKGenerator::GenerateImportFooterCode(std::ostream&)
+{
+}
+
+void cmExportInstallAndroidMKGenerator::GenerateImportTargetCode(
+ std::ostream& os, cmGeneratorTarget const* target,
+ cmStateEnums::TargetType /*targetType*/)
+{
+ std::string targetName = cmStrCat(this->Namespace, target->GetExportName());
+ os << "include $(CLEAR_VARS)\n";
+ os << "LOCAL_MODULE := ";
+ os << targetName << "\n";
+ os << "LOCAL_SRC_FILES := $(_IMPORT_PREFIX)/";
+ os << target->Target->GetSafeProperty("__dest") << "/";
+ std::string config;
+ if (!this->Configurations.empty()) {
+ config = this->Configurations[0];
+ }
+ os << target->GetFullName(config) << "\n";
+}
+
+void cmExportInstallAndroidMKGenerator::GenerateExpectedTargetsCode(
+ std::ostream&, const std::string&)
+{
+}
+
+void cmExportInstallAndroidMKGenerator::GenerateImportPropertyCode(
+ std::ostream&, const std::string&, cmGeneratorTarget const*,
+ ImportPropertyMap const&)
+{
+}
+
+void cmExportInstallAndroidMKGenerator::GenerateMissingTargetsCheckCode(
+ std::ostream&, const std::vector<std::string>&)
+{
+}
+
+void cmExportInstallAndroidMKGenerator::GenerateInterfaceProperties(
+ cmGeneratorTarget const* target, std::ostream& os,
+ const ImportPropertyMap& properties)
+{
+ std::string config;
+ if (!this->Configurations.empty()) {
+ config = this->Configurations[0];
+ }
+ cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
+ target, os, properties, cmExportBuildAndroidMKGenerator::INSTALL, config);
+}
+
+void cmExportInstallAndroidMKGenerator::LoadConfigFiles(std::ostream&)
+{
+}
+
+void cmExportInstallAndroidMKGenerator::GenerateImportPrefix(std::ostream&)
+{
+}
+
+void cmExportInstallAndroidMKGenerator::GenerateRequiredCMakeVersion(
+ std::ostream&, const char*)
+{
+}
+
+void cmExportInstallAndroidMKGenerator::CleanupTemporaryVariables(
+ std::ostream&)
+{
+}
+
+void cmExportInstallAndroidMKGenerator::GenerateImportedFileCheckLoop(
+ std::ostream&)
+{
+}
+
+void cmExportInstallAndroidMKGenerator::GenerateImportedFileChecksCode(
+ std::ostream&, cmGeneratorTarget*, ImportPropertyMap const&,
+ const std::set<std::string>&)
+{
+}
+
+bool cmExportInstallAndroidMKGenerator::GenerateImportFileConfig(
+ const std::string&, std::vector<std::string>&)
+{
+ return true;
+}
diff --git a/Source/cmExportInstallAndroidMKGenerator.h b/Source/cmExportInstallAndroidMKGenerator.h
new file mode 100644
index 0000000..40978e0
--- /dev/null
+++ b/Source/cmExportInstallAndroidMKGenerator.h
@@ -0,0 +1,70 @@
+/* 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 <iosfwd>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmExportFileGenerator.h"
+#include "cmExportInstallFileGenerator.h"
+#include "cmStateTypes.h"
+
+class cmGeneratorTarget;
+class cmInstallExportGenerator;
+
+/** \class cmExportInstallAndroidMKGenerator
+ * \brief Generate a file exporting targets from an install tree.
+ *
+ * cmExportInstallAndroidMKGenerator generates files exporting targets from
+ * install an installation tree. The files are placed in a temporary
+ * location for installation by cmInstallExportGenerator. The file format
+ * is for the ndk build system and is a makefile fragment specifying prebuilt
+ * libraries to the ndk build system.
+ *
+ * This is used to implement the INSTALL(EXPORT_ANDROID_MK) command.
+ */
+class cmExportInstallAndroidMKGenerator : public cmExportInstallFileGenerator
+{
+public:
+ /** Construct with the export installer that will install the
+ files. */
+ cmExportInstallAndroidMKGenerator(cmInstallExportGenerator* iegen);
+
+protected:
+ // Implement virtual methods from the superclass.
+ void GeneratePolicyHeaderCode(std::ostream&) override {}
+ void GeneratePolicyFooterCode(std::ostream&) override {}
+ void GenerateImportHeaderCode(std::ostream& os,
+ const std::string& config = "") override;
+ void GenerateImportFooterCode(std::ostream& os) override;
+ void GenerateImportTargetCode(
+ std::ostream& os, cmGeneratorTarget const* target,
+ cmStateEnums::TargetType /*targetType*/) override;
+ void GenerateExpectedTargetsCode(
+ std::ostream& os, const std::string& expectedTargets) override;
+ void GenerateImportPropertyCode(
+ std::ostream& os, const std::string& config,
+ cmGeneratorTarget const* target,
+ ImportPropertyMap const& properties) override;
+ void GenerateMissingTargetsCheckCode(
+ std::ostream& os, const std::vector<std::string>& missingTargets) override;
+ void GenerateInterfaceProperties(
+ cmGeneratorTarget const* target, std::ostream& os,
+ const ImportPropertyMap& properties) override;
+ void GenerateImportPrefix(std::ostream& os) override;
+ void LoadConfigFiles(std::ostream&) override;
+ void GenerateRequiredCMakeVersion(std::ostream& os,
+ const char* versionString) override;
+ void CleanupTemporaryVariables(std::ostream&) override;
+ void GenerateImportedFileCheckLoop(std::ostream& os) override;
+ void GenerateImportedFileChecksCode(
+ std::ostream& os, cmGeneratorTarget* target,
+ ImportPropertyMap const& properties,
+ const std::set<std::string>& importedLocations) override;
+ bool GenerateImportFileConfig(const std::string& config,
+ std::vector<std::string>&) override;
+};
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
new file mode 100644
index 0000000..3c69c50
--- /dev/null
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -0,0 +1,535 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExportInstallFileGenerator.h"
+
+#include <memory>
+#include <sstream>
+#include <utility>
+
+#include "cmExportSet.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallTargetGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmPolicies.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetExport.h"
+
+cmExportInstallFileGenerator::cmExportInstallFileGenerator(
+ cmInstallExportGenerator* iegen)
+ : IEGen(iegen)
+{
+}
+
+std::string cmExportInstallFileGenerator::GetConfigImportFileGlob()
+{
+ std::string glob = cmStrCat(this->FileBase, "-*", this->FileExt);
+ return glob;
+}
+
+bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
+{
+ std::vector<cmTargetExport*> allTargets;
+ {
+ std::string expectedTargets;
+ std::string sep;
+ for (std::unique_ptr<cmTargetExport> const& te :
+ this->IEGen->GetExportSet()->GetTargetExports()) {
+ if (te->NamelinkOnly) {
+ continue;
+ }
+ expectedTargets += sep + this->Namespace + te->Target->GetExportName();
+ sep = " ";
+ if (this->ExportedTargets.insert(te->Target).second) {
+ allTargets.push_back(te.get());
+ } else {
+ std::ostringstream e;
+ e << "install(EXPORT \"" << this->IEGen->GetExportSet()->GetName()
+ << "\" ...) "
+ << "includes target \"" << te->Target->GetName()
+ << "\" more than once in the export set.";
+ cmSystemTools::Error(e.str());
+ return false;
+ }
+ }
+
+ this->GenerateExpectedTargetsCode(os, expectedTargets);
+ }
+
+ // Compute the relative import prefix for the file
+ this->GenerateImportPrefix(os);
+
+ std::vector<std::string> missingTargets;
+
+ bool require2_8_12 = false;
+ bool require3_0_0 = false;
+ bool require3_1_0 = false;
+ bool requiresConfigFiles = false;
+ // Create all the imported targets.
+ for (cmTargetExport* te : allTargets) {
+ cmGeneratorTarget* gt = te->Target;
+ cmStateEnums::TargetType targetType = this->GetExportTargetType(te);
+
+ requiresConfigFiles =
+ requiresConfigFiles || targetType != cmStateEnums::INTERFACE_LIBRARY;
+
+ this->GenerateImportTargetCode(os, gt, targetType);
+
+ ImportPropertyMap properties;
+
+ this->PopulateIncludeDirectoriesInterface(
+ te, cmGeneratorExpression::InstallInterface, properties, missingTargets);
+ this->PopulateSourcesInterface(te, cmGeneratorExpression::InstallInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", gt,
+ cmGeneratorExpression::InstallInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gt,
+ cmGeneratorExpression::InstallInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gt,
+ cmGeneratorExpression::InstallInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gt,
+ cmGeneratorExpression::InstallInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gt,
+ cmGeneratorExpression::InstallInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gt,
+ cmGeneratorExpression::InstallInterface,
+ properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt,
+ cmGeneratorExpression::InstallInterface,
+ properties, missingTargets);
+ this->PopulateLinkDirectoriesInterface(
+ te, cmGeneratorExpression::InstallInterface, properties, missingTargets);
+ this->PopulateLinkDependsInterface(
+ te, cmGeneratorExpression::InstallInterface, properties, missingTargets);
+
+ std::string errorMessage;
+ if (!this->PopulateExportProperties(gt, properties, errorMessage)) {
+ cmSystemTools::Error(errorMessage);
+ return false;
+ }
+
+ const bool newCMP0022Behavior =
+ gt->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
+ gt->GetPolicyStatusCMP0022() != cmPolicies::OLD;
+ if (newCMP0022Behavior) {
+ if (this->PopulateInterfaceLinkLibrariesProperty(
+ gt, cmGeneratorExpression::InstallInterface, properties,
+ missingTargets) &&
+ !this->ExportOld) {
+ require2_8_12 = true;
+ }
+ }
+ if (targetType == cmStateEnums::INTERFACE_LIBRARY) {
+ require3_0_0 = true;
+ }
+ if (gt->GetProperty("INTERFACE_SOURCES")) {
+ // We can only generate INTERFACE_SOURCES in CMake 3.3, but CMake 3.1
+ // can consume them.
+ require3_1_0 = true;
+ }
+
+ this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gt,
+ properties);
+
+ this->PopulateCompatibleInterfaceProperties(gt, properties);
+
+ this->GenerateInterfaceProperties(gt, os, properties);
+ }
+
+ if (require3_1_0) {
+ this->GenerateRequiredCMakeVersion(os, "3.1.0");
+ } else if (require3_0_0) {
+ this->GenerateRequiredCMakeVersion(os, "3.0.0");
+ } else if (require2_8_12) {
+ this->GenerateRequiredCMakeVersion(os, "2.8.12");
+ }
+
+ this->LoadConfigFiles(os);
+
+ this->CleanupTemporaryVariables(os);
+ this->GenerateImportedFileCheckLoop(os);
+
+ bool result = true;
+ // Generate an import file for each configuration.
+ // Don't do this if we only export INTERFACE_LIBRARY targets.
+ if (requiresConfigFiles) {
+ for (std::string const& c : this->Configurations) {
+ if (!this->GenerateImportFileConfig(c, missingTargets)) {
+ result = false;
+ }
+ }
+ }
+
+ this->GenerateMissingTargetsCheckCode(os, missingTargets);
+
+ return result;
+}
+
+void cmExportInstallFileGenerator::GenerateImportPrefix(std::ostream& os)
+{
+ // Set an _IMPORT_PREFIX variable for import location properties
+ // to reference if they are relative to the install prefix.
+ std::string installPrefix =
+ this->IEGen->GetLocalGenerator()->GetMakefile()->GetSafeDefinition(
+ "CMAKE_INSTALL_PREFIX");
+ std::string const& expDest = this->IEGen->GetDestination();
+ if (cmSystemTools::FileIsFullPath(expDest)) {
+ // The export file is being installed to an absolute path so the
+ // package is not relocatable. Use the configured install prefix.
+ /* clang-format off */
+ os <<
+ "# The installation prefix configured by this project.\n"
+ "set(_IMPORT_PREFIX \"" << installPrefix << "\")\n"
+ "\n";
+ /* clang-format on */
+ } else {
+ // Add code to compute the installation prefix relative to the
+ // import file location.
+ std::string absDest = installPrefix + "/" + expDest;
+ std::string absDestS = absDest + "/";
+ os << "# Compute the installation prefix relative to this file.\n"
+ << "get_filename_component(_IMPORT_PREFIX"
+ << " \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
+ if (cmHasLiteralPrefix(absDestS, "/lib/") ||
+ cmHasLiteralPrefix(absDestS, "/lib64/") ||
+ cmHasLiteralPrefix(absDestS, "/libx32/") ||
+ cmHasLiteralPrefix(absDestS, "/usr/lib/") ||
+ cmHasLiteralPrefix(absDestS, "/usr/lib64/") ||
+ cmHasLiteralPrefix(absDestS, "/usr/libx32/")) {
+ // Handle "/usr move" symlinks created by some Linux distros.
+ /* clang-format off */
+ os <<
+ "# Use original install prefix when loaded through a\n"
+ "# cross-prefix symbolic link such as /lib -> /usr/lib.\n"
+ "get_filename_component(_realCurr \"${_IMPORT_PREFIX}\" REALPATH)\n"
+ "get_filename_component(_realOrig \"" << absDest << "\" REALPATH)\n"
+ "if(_realCurr STREQUAL _realOrig)\n"
+ " set(_IMPORT_PREFIX \"" << absDest << "\")\n"
+ "endif()\n"
+ "unset(_realOrig)\n"
+ "unset(_realCurr)\n";
+ /* clang-format on */
+ }
+ std::string dest = expDest;
+ while (!dest.empty()) {
+ os << "get_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" "
+ "PATH)\n";
+ dest = cmSystemTools::GetFilenamePath(dest);
+ }
+ os << "if(_IMPORT_PREFIX STREQUAL \"/\")\n"
+ << " set(_IMPORT_PREFIX \"\")\n"
+ << "endif()\n"
+ << "\n";
+ }
+}
+
+void cmExportInstallFileGenerator::CleanupTemporaryVariables(std::ostream& os)
+{
+ /* clang-format off */
+ os << "# Cleanup temporary variables.\n"
+ << "set(_IMPORT_PREFIX)\n"
+ << "\n";
+ /* clang-format on */
+}
+
+void cmExportInstallFileGenerator::LoadConfigFiles(std::ostream& os)
+{
+ // Now load per-configuration properties for them.
+ /* clang-format off */
+ os << "# Load information for each installed configuration.\n"
+ << "get_filename_component(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"
+ << "file(GLOB CONFIG_FILES \"${_DIR}/"
+ << this->GetConfigImportFileGlob() << "\")\n"
+ << "foreach(f ${CONFIG_FILES})\n"
+ << " include(${f})\n"
+ << "endforeach()\n"
+ << "\n";
+ /* clang-format on */
+}
+
+void cmExportInstallFileGenerator::ReplaceInstallPrefix(std::string& input)
+{
+ cmGeneratorExpression::ReplaceInstallPrefix(input, "${_IMPORT_PREFIX}");
+}
+
+bool cmExportInstallFileGenerator::GenerateImportFileConfig(
+ const std::string& config, std::vector<std::string>& missingTargets)
+{
+ // Skip configurations not enabled for this export.
+ if (!this->IEGen->InstallsForConfig(config)) {
+ return true;
+ }
+
+ // Construct the name of the file to generate.
+ std::string fileName = cmStrCat(this->FileDir, '/', this->FileBase, '-');
+ if (!config.empty()) {
+ fileName += cmSystemTools::LowerCase(config);
+ } else {
+ fileName += "noconfig";
+ }
+ fileName += this->FileExt;
+
+ // Open the output file to generate it.
+ cmGeneratedFileStream exportFileStream(fileName, true);
+ if (!exportFileStream) {
+ std::string se = cmSystemTools::GetLastSystemError();
+ std::ostringstream e;
+ e << "cannot write to file \"" << fileName << "\": " << se;
+ cmSystemTools::Error(e.str());
+ return false;
+ }
+ exportFileStream.SetCopyIfDifferent(true);
+ std::ostream& os = exportFileStream;
+
+ // Start with the import file header.
+ this->GenerateImportHeaderCode(os, config);
+
+ // Generate the per-config target information.
+ this->GenerateImportConfig(os, config, missingTargets);
+
+ // End with the import file footer.
+ this->GenerateImportFooterCode(os);
+
+ // Record this per-config import file.
+ this->ConfigImportFiles[config] = fileName;
+
+ return true;
+}
+
+void cmExportInstallFileGenerator::GenerateImportTargetsConfig(
+ std::ostream& os, const std::string& config, std::string const& suffix,
+ std::vector<std::string>& missingTargets)
+{
+ // Add each target in the set to the export.
+ for (std::unique_ptr<cmTargetExport> const& te :
+ this->IEGen->GetExportSet()->GetTargetExports()) {
+ // Collect import properties for this target.
+ if (this->GetExportTargetType(te.get()) ==
+ cmStateEnums::INTERFACE_LIBRARY) {
+ continue;
+ }
+
+ ImportPropertyMap properties;
+ std::set<std::string> importedLocations;
+
+ this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator,
+ properties, importedLocations);
+ this->SetImportLocationProperty(config, suffix, te->LibraryGenerator,
+ properties, importedLocations);
+ this->SetImportLocationProperty(config, suffix, te->RuntimeGenerator,
+ properties, importedLocations);
+ this->SetImportLocationProperty(config, suffix, te->ObjectsGenerator,
+ properties, importedLocations);
+ this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator,
+ properties, importedLocations);
+ this->SetImportLocationProperty(config, suffix, te->BundleGenerator,
+ properties, importedLocations);
+
+ // If any file location was set for the target add it to the
+ // import file.
+ if (!properties.empty()) {
+ // Get the rest of the target details.
+ cmGeneratorTarget* gtgt = te->Target;
+ this->SetImportDetailProperties(config, suffix, gtgt, properties,
+ missingTargets);
+
+ this->SetImportLinkInterface(config, suffix,
+ cmGeneratorExpression::InstallInterface,
+ gtgt, properties, missingTargets);
+
+ // TODO: PUBLIC_HEADER_LOCATION
+ // This should wait until the build feature propagation stuff
+ // is done. Then this can be a propagated include directory.
+ // this->GenerateImportProperty(config, te->HeaderGenerator,
+ // properties);
+
+ // Generate code in the export file.
+ this->GenerateImportPropertyCode(os, config, gtgt, properties);
+ this->GenerateImportedFileChecksCode(os, gtgt, properties,
+ importedLocations);
+ }
+ }
+}
+
+void cmExportInstallFileGenerator::SetImportLocationProperty(
+ const std::string& config, std::string const& suffix,
+ cmInstallTargetGenerator* itgen, ImportPropertyMap& properties,
+ std::set<std::string>& importedLocations)
+{
+ // Skip rules that do not match this configuration.
+ if (!(itgen && itgen->InstallsForConfig(config))) {
+ return;
+ }
+
+ // Get the target to be installed.
+ cmGeneratorTarget* target = itgen->GetTarget();
+
+ // Construct the installed location of the target.
+ std::string dest = itgen->GetDestination(config);
+ std::string value;
+ if (!cmSystemTools::FileIsFullPath(dest)) {
+ // The target is installed relative to the installation prefix.
+ value = "${_IMPORT_PREFIX}/";
+ }
+ value += dest;
+ value += "/";
+
+ if (itgen->IsImportLibrary()) {
+ // Construct the property name.
+ std::string prop = cmStrCat("IMPORTED_IMPLIB", suffix);
+
+ // Append the installed file name.
+ value += cmInstallTargetGenerator::GetInstallFilename(
+ target, config, cmInstallTargetGenerator::NameImplib);
+
+ // Store the property.
+ properties[prop] = value;
+ importedLocations.insert(prop);
+ } else if (itgen->GetTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ // Construct the property name.
+ std::string prop = cmStrCat("IMPORTED_OBJECTS", suffix);
+
+ // Compute all the object files inside this target and setup
+ // IMPORTED_OBJECTS as a list of object files
+ std::vector<std::string> objects;
+ itgen->GetInstallObjectNames(config, objects);
+ for (std::string& obj : objects) {
+ obj = cmStrCat(value, obj);
+ }
+
+ // Store the property.
+ properties[prop] = cmJoin(objects, ";");
+ importedLocations.insert(prop);
+ } else {
+ // Construct the property name.
+ std::string prop = cmStrCat("IMPORTED_LOCATION", suffix);
+
+ // Append the installed file name.
+ if (target->IsAppBundleOnApple()) {
+ value += cmInstallTargetGenerator::GetInstallFilename(target, config);
+ value += ".app/Contents/MacOS/";
+ value += cmInstallTargetGenerator::GetInstallFilename(target, config);
+ } else {
+ value += cmInstallTargetGenerator::GetInstallFilename(
+ target, config, cmInstallTargetGenerator::NameReal);
+ }
+
+ // Store the property.
+ properties[prop] = value;
+ importedLocations.insert(prop);
+ }
+}
+
+cmStateEnums::TargetType cmExportInstallFileGenerator::GetExportTargetType(
+ cmTargetExport const* targetExport) const
+{
+ cmStateEnums::TargetType targetType = targetExport->Target->GetType();
+ // An OBJECT library installed with no OBJECTS DESTINATION
+ // is transformed to an INTERFACE library.
+ if (targetType == cmStateEnums::OBJECT_LIBRARY &&
+ targetExport->ObjectsGenerator == nullptr) {
+ targetType = cmStateEnums::INTERFACE_LIBRARY;
+ }
+ return targetType;
+}
+
+void cmExportInstallFileGenerator::HandleMissingTarget(
+ std::string& link_libs, std::vector<std::string>& missingTargets,
+ cmGeneratorTarget* depender, cmGeneratorTarget* dependee)
+{
+ const std::string name = dependee->GetName();
+ cmGlobalGenerator* gg = dependee->GetLocalGenerator()->GetGlobalGenerator();
+ auto exportInfo = this->FindNamespaces(gg, name);
+ std::vector<std::string> const& exportFiles = exportInfo.first;
+ if (exportFiles.size() == 1) {
+ std::string missingTarget = exportInfo.second;
+
+ missingTarget += dependee->GetExportName();
+ link_libs += missingTarget;
+ missingTargets.push_back(std::move(missingTarget));
+ } else {
+ // All exported targets should be known here and should be unique.
+ // This is probably user-error.
+ this->ComplainAboutMissingTarget(depender, dependee, exportFiles);
+ }
+}
+
+std::pair<std::vector<std::string>, std::string>
+cmExportInstallFileGenerator::FindNamespaces(cmGlobalGenerator* gg,
+ const std::string& name)
+{
+ std::vector<std::string> exportFiles;
+ std::string ns;
+ const cmExportSetMap& exportSets = gg->GetExportSets();
+
+ for (auto const& expIt : exportSets) {
+ const cmExportSet& exportSet = expIt.second;
+
+ bool containsTarget = false;
+ for (auto const& target : exportSet.GetTargetExports()) {
+ if (name == target->TargetName) {
+ containsTarget = true;
+ break;
+ }
+ }
+
+ if (containsTarget) {
+ std::vector<cmInstallExportGenerator const*> const* installs =
+ exportSet.GetInstallations();
+ for (cmInstallExportGenerator const* install : *installs) {
+ exportFiles.push_back(install->GetDestinationFile());
+ ns = install->GetNamespace();
+ }
+ }
+ }
+
+ return { exportFiles, ns };
+}
+
+void cmExportInstallFileGenerator::ComplainAboutMissingTarget(
+ cmGeneratorTarget* depender, cmGeneratorTarget* dependee,
+ std::vector<std::string> const& exportFiles)
+{
+ std::ostringstream e;
+ e << "install(EXPORT \"" << this->IEGen->GetExportSet()->GetName()
+ << "\" ...) "
+ << "includes target \"" << depender->GetName()
+ << "\" which requires target \"" << dependee->GetName() << "\" ";
+ if (exportFiles.empty()) {
+ e << "that is not in any export set.";
+ } else {
+ e << "that is not in this export set, but in multiple other export sets: "
+ << cmJoin(exportFiles, ", ") << ".\n";
+ e << "An exported target cannot depend upon another target which is "
+ "exported multiple times. Consider consolidating the exports of the "
+ "\""
+ << dependee->GetName() << "\" target to a single export.";
+ }
+ cmSystemTools::Error(e.str());
+}
+
+std::string cmExportInstallFileGenerator::InstallNameDir(
+ cmGeneratorTarget* target, const std::string& config)
+{
+ std::string install_name_dir;
+
+ cmMakefile* mf = target->Target->GetMakefile();
+ if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ install_name_dir =
+ target->GetInstallNameDirForInstallTree(config, "${_IMPORT_PREFIX}");
+ }
+
+ return install_name_dir;
+}
diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h
new file mode 100644
index 0000000..2d8de9d
--- /dev/null
+++ b/Source/cmExportInstallFileGenerator.h
@@ -0,0 +1,104 @@
+/* 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 <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmExportFileGenerator.h"
+#include "cmStateTypes.h"
+
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmInstallExportGenerator;
+class cmInstallTargetGenerator;
+class cmTargetExport;
+
+/** \class cmExportInstallFileGenerator
+ * \brief Generate a file exporting targets from an install tree.
+ *
+ * cmExportInstallFileGenerator generates files exporting targets from
+ * install an installation tree. The files are placed in a temporary
+ * location for installation by cmInstallExportGenerator. One main
+ * file is generated that creates the imported targets and loads
+ * per-configuration files. Target locations and settings for each
+ * configuration are written to these per-configuration files. After
+ * installation the main file loads the configurations that have been
+ * installed.
+ *
+ * This is used to implement the INSTALL(EXPORT) command.
+ */
+class cmExportInstallFileGenerator : public cmExportFileGenerator
+{
+public:
+ /** Construct with the export installer that will install the
+ files. */
+ cmExportInstallFileGenerator(cmInstallExportGenerator* iegen);
+
+ /** Get the per-config file generated for each configuration. This
+ maps from the configuration name to the file temporary location
+ for installation. */
+ std::map<std::string, std::string> const& GetConfigImportFiles()
+ {
+ return this->ConfigImportFiles;
+ }
+
+ /** Compute the globbing expression used to load per-config import
+ files from the main file. */
+ std::string GetConfigImportFileGlob();
+
+protected:
+ // Implement virtual methods from the superclass.
+ bool GenerateMainFile(std::ostream& os) override;
+ void GenerateImportTargetsConfig(
+ std::ostream& os, const std::string& config, std::string const& suffix,
+ std::vector<std::string>& missingTargets) override;
+ cmStateEnums::TargetType GetExportTargetType(
+ cmTargetExport const* targetExport) const;
+ void HandleMissingTarget(std::string& link_libs,
+ std::vector<std::string>& missingTargets,
+ cmGeneratorTarget* depender,
+ cmGeneratorTarget* dependee) override;
+
+ void ReplaceInstallPrefix(std::string& input) override;
+
+ void ComplainAboutMissingTarget(cmGeneratorTarget* depender,
+ cmGeneratorTarget* dependee,
+ std::vector<std::string> const& exportFiles);
+
+ std::pair<std::vector<std::string>, std::string> FindNamespaces(
+ cmGlobalGenerator* gg, const std::string& name);
+
+ /** Generate the relative import prefix. */
+ virtual void GenerateImportPrefix(std::ostream&);
+
+ /** Generate the relative import prefix. */
+ virtual void LoadConfigFiles(std::ostream&);
+
+ virtual void CleanupTemporaryVariables(std::ostream&);
+
+ /** Generate a per-configuration file for the targets. */
+ virtual bool GenerateImportFileConfig(
+ const std::string& config, std::vector<std::string>& missingTargets);
+
+ /** Fill in properties indicating installed file locations. */
+ void SetImportLocationProperty(const std::string& config,
+ std::string const& suffix,
+ cmInstallTargetGenerator* itgen,
+ ImportPropertyMap& properties,
+ std::set<std::string>& importedLocations);
+
+ std::string InstallNameDir(cmGeneratorTarget* target,
+ const std::string& config) override;
+
+ cmInstallExportGenerator* IEGen;
+
+ // The import file generated for each configuration.
+ std::map<std::string, std::string> ConfigImportFiles;
+};
diff --git a/Source/cmExportLibraryDependenciesCommand.cxx b/Source/cmExportLibraryDependenciesCommand.cxx
new file mode 100644
index 0000000..7f31dd2
--- /dev/null
+++ b/Source/cmExportLibraryDependenciesCommand.cxx
@@ -0,0 +1,163 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExportLibraryDependenciesCommand.h"
+
+#include <map>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmExecutionStatus.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetLinkLibraryType.h"
+#include "cmake.h"
+
+class cmListFileBacktrace;
+
+static void FinalAction(cmMakefile& makefile, std::string const& filename,
+ bool append)
+{
+ // Use copy-if-different if not appending.
+ std::unique_ptr<cmsys::ofstream> foutPtr;
+ if (append) {
+ const auto openmodeApp = std::ios::app;
+ foutPtr = cm::make_unique<cmsys::ofstream>(filename.c_str(), openmodeApp);
+ } else {
+ std::unique_ptr<cmGeneratedFileStream> ap(
+ new cmGeneratedFileStream(filename, true));
+ ap->SetCopyIfDifferent(true);
+ foutPtr = std::move(ap);
+ }
+ std::ostream& fout = *foutPtr;
+
+ if (!fout) {
+ cmSystemTools::Error("Error Writing " + filename);
+ cmSystemTools::ReportLastSystemError("");
+ return;
+ }
+
+ // Collect dependency information about all library targets built in
+ // the project.
+ cmake* cm = makefile.GetCMakeInstance();
+ cmGlobalGenerator* global = cm->GetGlobalGenerator();
+ const auto& locals = global->GetMakefiles();
+ std::map<std::string, std::string> libDepsOld;
+ std::map<std::string, std::string> libDepsNew;
+ std::map<std::string, std::string> libTypes;
+ for (const auto& local : locals) {
+ for (auto const& tgt : local->GetTargets()) {
+ // Get the current target.
+ cmTarget const& target = tgt.second;
+
+ // Skip non-library targets.
+ if (target.GetType() < cmStateEnums::STATIC_LIBRARY ||
+ target.GetType() > cmStateEnums::MODULE_LIBRARY) {
+ continue;
+ }
+
+ // Construct the dependency variable name.
+ std::string targetEntry = cmStrCat(target.GetName(), "_LIB_DEPENDS");
+
+ // Construct the dependency variable value with the direct link
+ // dependencies.
+ std::string valueOld;
+ std::string valueNew;
+ cmTarget::LinkLibraryVectorType const& libs =
+ target.GetOriginalLinkLibraries();
+ for (cmTarget::LibraryID const& li : libs) {
+ std::string ltVar = cmStrCat(li.first, "_LINK_TYPE");
+ std::string ltValue;
+ switch (li.second) {
+ case GENERAL_LibraryType:
+ valueNew += "general;";
+ ltValue = "general";
+ break;
+ case DEBUG_LibraryType:
+ valueNew += "debug;";
+ ltValue = "debug";
+ break;
+ case OPTIMIZED_LibraryType:
+ valueNew += "optimized;";
+ ltValue = "optimized";
+ break;
+ }
+ std::string lib = li.first;
+ if (cmTarget* libtgt = global->FindTarget(lib)) {
+ // Handle simple output name changes. This command is
+ // deprecated so we do not support full target name
+ // translation (which requires per-configuration info).
+ if (cmProp outname = libtgt->GetProperty("OUTPUT_NAME")) {
+ lib = *outname;
+ }
+ }
+ valueOld += lib;
+ valueOld += ";";
+ valueNew += lib;
+ valueNew += ";";
+
+ std::string& ltEntry = libTypes[ltVar];
+ if (ltEntry.empty()) {
+ ltEntry = ltValue;
+ } else if (ltEntry != ltValue) {
+ ltEntry = "general";
+ }
+ }
+ libDepsNew[targetEntry] = valueNew;
+ libDepsOld[targetEntry] = valueOld;
+ }
+ }
+
+ // Generate dependency information for both old and new style CMake
+ // versions.
+ const char* vertest =
+ "\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" GREATER 2.4";
+ fout << "# Generated by CMake\n\n";
+ fout << "if(" << vertest << ")\n";
+ fout << " # Information for CMake 2.6 and above.\n";
+ for (auto const& i : libDepsNew) {
+ if (!i.second.empty()) {
+ fout << " set(\"" << i.first << "\" \"" << i.second << "\")\n";
+ }
+ }
+ fout << "else()\n";
+ fout << " # Information for CMake 2.4 and lower.\n";
+ for (auto const& i : libDepsOld) {
+ if (!i.second.empty()) {
+ fout << " set(\"" << i.first << "\" \"" << i.second << "\")\n";
+ }
+ }
+ for (auto const& i : libTypes) {
+ if (i.second != "general") {
+ fout << " set(\"" << i.first << "\" \"" << i.second << "\")\n";
+ }
+ }
+ fout << "endif()\n";
+}
+
+bool cmExportLibraryDependenciesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::string const& filename = args[0];
+ bool const append = args.size() > 1 && args[1] == "APPEND";
+ status.GetMakefile().AddGeneratorAction(
+ [filename, append](cmLocalGenerator& lg, const cmListFileBacktrace&) {
+ FinalAction(*lg.GetMakefile(), filename, append);
+ });
+
+ return true;
+}
diff --git a/Source/cmExportLibraryDependenciesCommand.h b/Source/cmExportLibraryDependenciesCommand.h
new file mode 100644
index 0000000..1834bfa
--- /dev/null
+++ b/Source/cmExportLibraryDependenciesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmExportLibraryDependenciesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmExportSet.cxx b/Source/cmExportSet.cxx
new file mode 100644
index 0000000..a20aa9a
--- /dev/null
+++ b/Source/cmExportSet.cxx
@@ -0,0 +1,44 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExportSet.h"
+
+#include <tuple>
+#include <utility>
+
+#include "cmLocalGenerator.h"
+#include "cmTargetExport.h"
+
+cmExportSet::cmExportSet(std::string name)
+ : Name(std::move(name))
+{
+}
+
+cmExportSet::~cmExportSet() = default;
+
+void cmExportSet::Compute(cmLocalGenerator* lg)
+{
+ for (std::unique_ptr<cmTargetExport>& tgtExport : this->TargetExports) {
+ tgtExport->Target = lg->FindGeneratorTargetToUse(tgtExport->TargetName);
+ }
+}
+
+void cmExportSet::AddTargetExport(std::unique_ptr<cmTargetExport> te)
+{
+ this->TargetExports.emplace_back(std::move(te));
+}
+
+void cmExportSet::AddInstallation(cmInstallExportGenerator const* installation)
+{
+ this->Installations.push_back(installation);
+}
+
+cmExportSet& cmExportSetMap::operator[](const std::string& name)
+{
+ auto it = this->find(name);
+ if (it == this->end()) // Export set not found
+ {
+ auto tup_name = std::make_tuple(name);
+ it = this->emplace(std::piecewise_construct, tup_name, tup_name).first;
+ }
+ return it->second;
+}
diff --git a/Source/cmExportSet.h b/Source/cmExportSet.h
new file mode 100644
index 0000000..07deb11
--- /dev/null
+++ b/Source/cmExportSet.h
@@ -0,0 +1,62 @@
+/* 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 <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+class cmInstallExportGenerator;
+class cmLocalGenerator;
+class cmTargetExport;
+
+/// A set of targets that were installed with the same EXPORT parameter.
+class cmExportSet
+{
+public:
+ /// Construct an empty export set named \a name
+ cmExportSet(std::string name);
+ /// Destructor
+ ~cmExportSet();
+
+ cmExportSet(const cmExportSet&) = delete;
+ cmExportSet& operator=(const cmExportSet&) = delete;
+
+ void Compute(cmLocalGenerator* lg);
+
+ void AddTargetExport(std::unique_ptr<cmTargetExport> tgt);
+
+ void AddInstallation(cmInstallExportGenerator const* installation);
+
+ std::string const& GetName() const { return this->Name; }
+
+ std::vector<std::unique_ptr<cmTargetExport>> const& GetTargetExports() const
+ {
+ return this->TargetExports;
+ }
+
+ std::vector<cmInstallExportGenerator const*> const* GetInstallations() const
+ {
+ return &this->Installations;
+ }
+
+private:
+ std::vector<std::unique_ptr<cmTargetExport>> TargetExports;
+ std::string Name;
+ std::vector<cmInstallExportGenerator const*> Installations;
+};
+
+/// A name -> cmExportSet map with overloaded operator[].
+class cmExportSetMap : public std::map<std::string, cmExportSet>
+{
+public:
+ /** \brief Overloaded operator[].
+ *
+ * The operator is overloaded because cmExportSet has no default constructor:
+ * we do not want unnamed export sets.
+ */
+ cmExportSet& operator[](const std::string& name);
+};
diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx
new file mode 100644
index 0000000..cac60e1
--- /dev/null
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -0,0 +1,139 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExportTryCompileFileGenerator.h"
+
+#include <map>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionDAGChecker.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmTarget.h"
+
+cmExportTryCompileFileGenerator::cmExportTryCompileFileGenerator(
+ cmGlobalGenerator* gg, const std::vector<std::string>& targets,
+ cmMakefile* mf, std::set<std::string> const& langs)
+ : Languages(langs.begin(), langs.end())
+{
+ gg->CreateImportedGenerationObjects(mf, targets, this->Exports);
+}
+
+bool cmExportTryCompileFileGenerator::GenerateMainFile(std::ostream& os)
+{
+ std::set<cmGeneratorTarget const*> emitted;
+ std::set<cmGeneratorTarget const*> emittedDeps;
+ while (!this->Exports.empty()) {
+ cmGeneratorTarget const* te = this->Exports.back();
+ this->Exports.pop_back();
+ if (emitted.insert(te).second) {
+ emittedDeps.insert(te);
+ this->GenerateImportTargetCode(os, te, te->GetType());
+
+ ImportPropertyMap properties;
+
+ for (std::string const& lang : this->Languages) {
+#define FIND_TARGETS(PROPERTY) \
+ this->FindTargets("INTERFACE_" #PROPERTY, te, lang, emittedDeps);
+
+ CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(FIND_TARGETS)
+
+#undef FIND_TARGETS
+ }
+
+ this->PopulateProperties(te, properties, emittedDeps);
+
+ this->GenerateInterfaceProperties(te, os, properties);
+ }
+ }
+ return true;
+}
+
+std::string cmExportTryCompileFileGenerator::FindTargets(
+ const std::string& propName, cmGeneratorTarget const* tgt,
+ std::string const& language, std::set<cmGeneratorTarget const*>& emitted)
+{
+ cmProp prop = tgt->GetProperty(propName);
+ if (!prop) {
+ return std::string();
+ }
+
+ cmGeneratorExpression ge;
+
+ std::unique_ptr<cmGeneratorExpressionDAGChecker> parentDagChecker;
+ if (propName == "INTERFACE_LINK_OPTIONS") {
+ // To please constraint checks of DAGChecker, this property must have
+ // LINK_OPTIONS property as parent
+ parentDagChecker = cm::make_unique<cmGeneratorExpressionDAGChecker>(
+ tgt, "LINK_OPTIONS", nullptr, nullptr);
+ }
+ cmGeneratorExpressionDAGChecker dagChecker(tgt, propName, nullptr,
+ parentDagChecker.get());
+
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*prop);
+
+ cmTarget dummyHead("try_compile_dummy_exe", cmStateEnums::EXECUTABLE,
+ cmTarget::VisibilityNormal, tgt->Target->GetMakefile(),
+ cmTarget::PerConfig::Yes);
+
+ cmGeneratorTarget gDummyHead(&dummyHead, tgt->GetLocalGenerator());
+
+ std::string result = cge->Evaluate(tgt->GetLocalGenerator(), this->Config,
+ &gDummyHead, &dagChecker, tgt, language);
+
+ const std::set<cmGeneratorTarget const*>& allTargets =
+ cge->GetAllTargetsSeen();
+ for (cmGeneratorTarget const* target : allTargets) {
+ if (emitted.insert(target).second) {
+ this->Exports.push_back(target);
+ }
+ }
+ return result;
+}
+
+void cmExportTryCompileFileGenerator::PopulateProperties(
+ const cmGeneratorTarget* target, ImportPropertyMap& properties,
+ std::set<cmGeneratorTarget const*>& emitted)
+{
+ std::vector<std::string> props = target->GetPropertyKeys();
+ for (std::string const& p : props) {
+
+ properties[p] = *target->GetProperty(p);
+
+ if (cmHasLiteralPrefix(p, "IMPORTED_LINK_INTERFACE_LIBRARIES") ||
+ cmHasLiteralPrefix(p, "IMPORTED_LINK_DEPENDENT_LIBRARIES") ||
+ cmHasLiteralPrefix(p, "INTERFACE_LINK_LIBRARIES")) {
+ std::string evalResult =
+ this->FindTargets(p, target, std::string(), emitted);
+
+ std::vector<std::string> depends = cmExpandedList(evalResult);
+ for (std::string const& li : depends) {
+ cmGeneratorTarget* tgt =
+ target->GetLocalGenerator()->FindGeneratorTargetToUse(li);
+ if (tgt && emitted.insert(tgt).second) {
+ this->Exports.push_back(tgt);
+ }
+ }
+ }
+ }
+}
+
+std::string cmExportTryCompileFileGenerator::InstallNameDir(
+ cmGeneratorTarget* target, const std::string& config)
+{
+ std::string install_name_dir;
+
+ cmMakefile* mf = target->Target->GetMakefile();
+ if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ install_name_dir = target->GetInstallNameDirForBuildTree(config);
+ }
+
+ return install_name_dir;
+}
diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h
new file mode 100644
index 0000000..6bf5781
--- /dev/null
+++ b/Source/cmExportTryCompileFileGenerator.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 "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmExportFileGenerator.h"
+
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmMakefile;
+
+class cmExportTryCompileFileGenerator : public cmExportFileGenerator
+{
+public:
+ cmExportTryCompileFileGenerator(cmGlobalGenerator* gg,
+ std::vector<std::string> const& targets,
+ cmMakefile* mf,
+ std::set<std::string> const& langs);
+
+ /** Set the list of targets to export. */
+ void SetConfig(const std::string& config) { this->Config = config; }
+
+protected:
+ // Implement virtual methods from the superclass.
+ bool GenerateMainFile(std::ostream& os) override;
+
+ void GenerateImportTargetsConfig(std::ostream&, const std::string&,
+ std::string const&,
+ std::vector<std::string>&) override
+ {
+ }
+ void HandleMissingTarget(std::string&, std::vector<std::string>&,
+ cmGeneratorTarget*, cmGeneratorTarget*) override
+ {
+ }
+
+ void PopulateProperties(cmGeneratorTarget const* target,
+ ImportPropertyMap& properties,
+ std::set<const cmGeneratorTarget*>& emitted);
+
+ std::string InstallNameDir(cmGeneratorTarget* target,
+ const std::string& config) override;
+
+private:
+ std::string FindTargets(const std::string& prop,
+ const cmGeneratorTarget* tgt,
+ std::string const& language,
+ std::set<const cmGeneratorTarget*>& emitted);
+
+ std::vector<cmGeneratorTarget const*> Exports;
+ std::string Config;
+ std::vector<std::string> Languages;
+};
diff --git a/Source/cmExprParserHelper.cxx b/Source/cmExprParserHelper.cxx
new file mode 100644
index 0000000..cc8b8b7
--- /dev/null
+++ b/Source/cmExprParserHelper.cxx
@@ -0,0 +1,119 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExprParserHelper.h"
+
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <utility>
+
+#include "cmExprLexer.h"
+#include "cmStringAlgorithms.h"
+
+int cmExpr_yyparse(yyscan_t yyscanner);
+//
+cmExprParserHelper::cmExprParserHelper()
+{
+ this->FileLine = -1;
+ this->FileName = nullptr;
+ this->Result = 0;
+}
+
+cmExprParserHelper::~cmExprParserHelper() = default;
+
+int cmExprParserHelper::ParseString(const char* str, int verb)
+{
+ if (!str) {
+ return 0;
+ }
+ // printf("Do some parsing: %s\n", str);
+
+ this->Verbose = verb;
+ this->InputBuffer = str;
+ this->InputBufferPos = 0;
+ this->CurrentLine = 0;
+
+ this->Result = 0;
+
+ yyscan_t yyscanner;
+ cmExpr_yylex_init(&yyscanner);
+ cmExpr_yyset_extra(this, yyscanner);
+
+ try {
+ int res = cmExpr_yyparse(yyscanner);
+ if (res != 0) {
+ std::string e =
+ cmStrCat("cannot parse the expression: \"", this->InputBuffer,
+ "\": ", this->ErrorString, '.');
+ this->SetError(std::move(e));
+ }
+ } catch (std::runtime_error const& fail) {
+ std::string e = cmStrCat("cannot evaluate the expression: \"",
+ this->InputBuffer, "\": ", fail.what(), '.');
+ this->SetError(std::move(e));
+ } catch (std::out_of_range const&) {
+ std::string e = "cannot evaluate the expression: \"" + this->InputBuffer +
+ "\": a numeric value is out of range.";
+ this->SetError(std::move(e));
+ } catch (...) {
+ std::string e =
+ "cannot parse the expression: \"" + this->InputBuffer + "\".";
+ this->SetError(std::move(e));
+ }
+ cmExpr_yylex_destroy(yyscanner);
+ if (!this->ErrorString.empty()) {
+ return 0;
+ }
+
+ if (this->Verbose) {
+ std::cerr << "Expanding [" << str << "] produced: [" << this->Result << "]"
+ << std::endl;
+ }
+ return 1;
+}
+
+int cmExprParserHelper::LexInput(char* buf, int maxlen)
+{
+ // std::cout << "JPLexInput ";
+ // std::cout.write(buf, maxlen);
+ // std::cout << std::endl;
+ if (maxlen < 1) {
+ return 0;
+ }
+ if (this->InputBufferPos < this->InputBuffer.size()) {
+ buf[0] = this->InputBuffer[this->InputBufferPos++];
+ if (buf[0] == '\n') {
+ this->CurrentLine++;
+ }
+ return (1);
+ }
+ buf[0] = '\n';
+ return (0);
+}
+
+void cmExprParserHelper::Error(const char* str)
+{
+ unsigned long pos = static_cast<unsigned long>(this->InputBufferPos);
+ std::ostringstream ostr;
+ ostr << str << " (" << pos << ")";
+ this->ErrorString = ostr.str();
+}
+
+void cmExprParserHelper::UnexpectedChar(char c)
+{
+ unsigned long pos = static_cast<unsigned long>(this->InputBufferPos);
+ std::ostringstream ostr;
+ ostr << "Unexpected character in expression at position " << pos << ": " << c
+ << "\n";
+ this->WarningString += ostr.str();
+}
+
+void cmExprParserHelper::SetResult(KWIML_INT_int64_t value)
+{
+ this->Result = value;
+}
+
+void cmExprParserHelper::SetError(std::string errorString)
+{
+ this->ErrorString = std::move(errorString);
+}
diff --git a/Source/cmExprParserHelper.h b/Source/cmExprParserHelper.h
new file mode 100644
index 0000000..919e492
--- /dev/null
+++ b/Source/cmExprParserHelper.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 "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+#include <cm3p/kwiml/int.h>
+
+class cmExprParserHelper
+{
+public:
+ struct ParserType
+ {
+ KWIML_INT_int64_t Number;
+ };
+
+ cmExprParserHelper();
+ ~cmExprParserHelper();
+
+ int ParseString(const char* str, int verb);
+
+ int LexInput(char* buf, int maxlen);
+ void Error(const char* str);
+
+ void SetResult(KWIML_INT_int64_t value);
+
+ KWIML_INT_int64_t GetResult() const { return this->Result; }
+
+ const char* GetError() { return this->ErrorString.c_str(); }
+
+ void UnexpectedChar(char c);
+
+ std::string const& GetWarning() const { return this->WarningString; }
+
+private:
+ std::string::size_type InputBufferPos;
+ std::string InputBuffer;
+ std::vector<char> OutputBuffer;
+ int CurrentLine;
+ int Verbose;
+
+ void Print(const char* place, const char* str);
+
+ void SetError(std::string errorString);
+
+ KWIML_INT_int64_t Result;
+ const char* FileName;
+ long FileLine;
+ std::string ErrorString;
+ std::string WarningString;
+};
+
+#define YYSTYPE cmExprParserHelper::ParserType
+#define YYSTYPE_IS_DECLARED
+#define YY_EXTRA_TYPE cmExprParserHelper*
+#define YY_DECL int cmExpr_yylex(YYSTYPE* yylvalp, yyscan_t yyscanner)
diff --git a/Source/cmExternalMakefileProjectGenerator.cxx b/Source/cmExternalMakefileProjectGenerator.cxx
new file mode 100644
index 0000000..5895d66
--- /dev/null
+++ b/Source/cmExternalMakefileProjectGenerator.cxx
@@ -0,0 +1,67 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExternalMakefileProjectGenerator.h"
+
+#include <utility>
+
+#include "cmStringAlgorithms.h"
+
+class cmMakefile;
+
+void cmExternalMakefileProjectGenerator::EnableLanguage(
+ std::vector<std::string> const& /*unused*/, cmMakefile* /*unused*/,
+ bool /*unused*/)
+{
+}
+
+std::string cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
+ const std::string& globalGenerator, const std::string& extraGenerator)
+{
+ std::string fullName;
+ if (!globalGenerator.empty()) {
+ if (!extraGenerator.empty()) {
+ fullName = cmStrCat(extraGenerator, " - ");
+ }
+ fullName += globalGenerator;
+ }
+ return fullName;
+}
+
+bool cmExternalMakefileProjectGenerator::Open(
+ const std::string& /*bindir*/, const std::string& /*projectName*/,
+ bool /*dryRun*/)
+{
+ return false;
+}
+
+cmExternalMakefileProjectGeneratorFactory::
+ cmExternalMakefileProjectGeneratorFactory(std::string n, std::string doc)
+ : Name(std::move(n))
+ , Documentation(std::move(doc))
+{
+}
+
+cmExternalMakefileProjectGeneratorFactory::
+ ~cmExternalMakefileProjectGeneratorFactory() = default;
+
+std::string cmExternalMakefileProjectGeneratorFactory::GetName() const
+{
+ return this->Name;
+}
+
+std::string cmExternalMakefileProjectGeneratorFactory::GetDocumentation() const
+{
+ return this->Documentation;
+}
+
+std::vector<std::string>
+cmExternalMakefileProjectGeneratorFactory::GetSupportedGlobalGenerators() const
+{
+ return this->SupportedGlobalGenerators;
+}
+
+void cmExternalMakefileProjectGeneratorFactory::AddSupportedGlobalGenerator(
+ const std::string& base)
+{
+ this->SupportedGlobalGenerators.push_back(base);
+}
diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h
new file mode 100644
index 0000000..311a2ef
--- /dev/null
+++ b/Source/cmExternalMakefileProjectGenerator.h
@@ -0,0 +1,110 @@
+/* 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 <memory>
+#include <string>
+#include <vector>
+
+class cmGlobalGenerator;
+class cmMakefile;
+
+/** \class cmExternalMakefileProjectGenerator
+ * \brief Base class for generators for "External Makefile based IDE projects".
+ *
+ * cmExternalMakefileProjectGenerator is a base class for generators
+ * for "external makefile based projects", i.e. IDE projects which work
+ * an already existing makefiles.
+ * See cmExtraEclipseCDT4Generator as an example.
+ * After the makefiles have been generated by one of the Makefile
+ * generators, the Generate() method is called and this generator
+ * can iterate over the local generators and/or projects to produce the
+ * project files for the IDE.
+ */
+class cmExternalMakefileProjectGenerator
+{
+public:
+ virtual ~cmExternalMakefileProjectGenerator() = default;
+
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+
+ //! set the global generator which will generate the makefiles
+ virtual void SetGlobalGenerator(cmGlobalGenerator* generator)
+ {
+ this->GlobalGenerator = generator;
+ }
+
+ //! Return the list of global generators supported by this extra generator
+ const std::vector<std::string>& GetSupportedGlobalGenerators() const
+ {
+ return this->SupportedGlobalGenerators;
+ }
+
+ /** Create a full name from the given global generator name and the
+ * extra generator name
+ */
+ static std::string CreateFullGeneratorName(
+ const std::string& globalGenerator, const std::string& extraGenerator);
+
+ //! Generate the project files, the Makefiles have already been generated
+ virtual void Generate() = 0;
+
+ void SetName(const std::string& n) { this->Name = n; }
+ std::string GetName() const { return this->Name; }
+
+ virtual bool Open(const std::string& bindir, const std::string& projectName,
+ bool dryRun);
+
+protected:
+ //! Contains the names of the global generators support by this generator.
+ std::vector<std::string> SupportedGlobalGenerators;
+ //! the global generator which creates the makefiles
+ const cmGlobalGenerator* GlobalGenerator = nullptr;
+
+ std::string Name;
+};
+
+class cmExternalMakefileProjectGeneratorFactory
+{
+public:
+ cmExternalMakefileProjectGeneratorFactory(std::string n, std::string doc);
+ virtual ~cmExternalMakefileProjectGeneratorFactory();
+
+ std::string GetName() const;
+ std::string GetDocumentation() const;
+ std::vector<std::string> GetSupportedGlobalGenerators() const;
+ std::vector<std::string> Aliases;
+
+ virtual std::unique_ptr<cmExternalMakefileProjectGenerator>
+ CreateExternalMakefileProjectGenerator() const = 0;
+
+ void AddSupportedGlobalGenerator(const std::string& base);
+
+private:
+ std::string Name;
+ std::string Documentation;
+ std::vector<std::string> SupportedGlobalGenerators;
+};
+
+template <class T>
+class cmExternalMakefileProjectGeneratorSimpleFactory
+ : public cmExternalMakefileProjectGeneratorFactory
+{
+public:
+ cmExternalMakefileProjectGeneratorSimpleFactory(const std::string& n,
+ const std::string& doc)
+ : cmExternalMakefileProjectGeneratorFactory(n, doc)
+ {
+ }
+
+ std::unique_ptr<cmExternalMakefileProjectGenerator>
+ CreateExternalMakefileProjectGenerator() const override
+ {
+ std::unique_ptr<cmExternalMakefileProjectGenerator> p(new T);
+ p->SetName(this->GetName());
+ return p;
+ }
+};
diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx
new file mode 100644
index 0000000..f217201
--- /dev/null
+++ b/Source/cmExtraCodeBlocksGenerator.cxx
@@ -0,0 +1,754 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExtraCodeBlocksGenerator.h"
+
+#include <map>
+#include <memory>
+#include <ostream>
+#include <set>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmAlgorithms.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmSourceFile.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+/* Some useful URLs:
+Homepage:
+http://www.codeblocks.org
+
+File format docs:
+http://wiki.codeblocks.org/index.php?title=File_formats_description
+http://wiki.codeblocks.org/index.php?title=Workspace_file
+http://wiki.codeblocks.org/index.php?title=Project_file
+
+Discussion:
+http://forums.codeblocks.org/index.php/topic,6789.0.html
+*/
+
+cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator() = default;
+
+cmExternalMakefileProjectGeneratorFactory*
+cmExtraCodeBlocksGenerator::GetFactory()
+{
+ static cmExternalMakefileProjectGeneratorSimpleFactory<
+ cmExtraCodeBlocksGenerator>
+ factory("CodeBlocks", "Generates CodeBlocks project files.");
+
+ if (factory.GetSupportedGlobalGenerators().empty()) {
+#if defined(_WIN32)
+ factory.AddSupportedGlobalGenerator("MinGW Makefiles");
+ factory.AddSupportedGlobalGenerator("NMake Makefiles");
+ factory.AddSupportedGlobalGenerator("NMake Makefiles JOM");
+// disable until somebody actually tests it:
+// this->AddSupportedGlobalGenerator("MSYS Makefiles");
+#endif
+ factory.AddSupportedGlobalGenerator("Ninja");
+ factory.AddSupportedGlobalGenerator("Unix Makefiles");
+ }
+
+ return &factory;
+}
+
+void cmExtraCodeBlocksGenerator::Generate()
+{
+ // for each sub project in the project create a codeblocks project
+ for (auto const& it : this->GlobalGenerator->GetProjectMap()) {
+ // create a project file
+ this->CreateProjectFile(it.second);
+ }
+}
+
+/* create the project file */
+void cmExtraCodeBlocksGenerator::CreateProjectFile(
+ const std::vector<cmLocalGenerator*>& lgs)
+{
+ std::string outputDir = lgs[0]->GetCurrentBinaryDirectory();
+ std::string projectName = lgs[0]->GetProjectName();
+
+ std::string filename = cmStrCat(outputDir, '/', projectName, ".cbp");
+ std::string sessionFilename =
+ cmStrCat(outputDir, '/', projectName, ".layout");
+
+ this->CreateNewProjectFile(lgs, filename);
+}
+
+/* Tree is used to create a "Virtual Folder" in CodeBlocks, in which all
+ CMake files this project depends on will be put. This means additionally
+ to the "Sources" and "Headers" virtual folders of CodeBlocks, there will
+ now also be a "CMake Files" virtual folder.
+ Patch by Daniel Teske <daniel.teske AT nokia.com> (which use C::B project
+ files in QtCreator).*/
+struct Tree
+{
+ std::string path; // only one component of the path
+ std::vector<Tree> folders;
+ std::set<std::string> files;
+ void InsertPath(const std::vector<std::string>& split,
+ std::vector<std::string>::size_type start,
+ const std::string& fileName);
+ void BuildVirtualFolder(cmXMLWriter& xml) const;
+ void BuildVirtualFolderImpl(std::string& virtualFolders,
+ const std::string& prefix) const;
+ void BuildUnit(cmXMLWriter& xml, const std::string& fsPath) const;
+ void BuildUnitImpl(cmXMLWriter& xml, const std::string& virtualFolderPath,
+ const std::string& fsPath) const;
+};
+
+void Tree::InsertPath(const std::vector<std::string>& split,
+ std::vector<std::string>::size_type start,
+ const std::string& fileName)
+{
+ if (start == split.size()) {
+ this->files.insert(fileName);
+ return;
+ }
+ for (Tree& folder : this->folders) {
+ if (folder.path == split[start]) {
+ if (start + 1 < split.size()) {
+ folder.InsertPath(split, start + 1, fileName);
+ return;
+ }
+ // last part of split
+ folder.files.insert(fileName);
+ return;
+ }
+ }
+ // Not found in folders, thus insert
+ Tree newFolder;
+ newFolder.path = split[start];
+ if (start + 1 < split.size()) {
+ newFolder.InsertPath(split, start + 1, fileName);
+ this->folders.push_back(newFolder);
+ return;
+ }
+ // last part of split
+ newFolder.files.insert(fileName);
+ this->folders.push_back(newFolder);
+}
+
+void Tree::BuildVirtualFolder(cmXMLWriter& xml) const
+{
+ xml.StartElement("Option");
+ std::string virtualFolders = "CMake Files\\;";
+ for (Tree const& folder : this->folders) {
+ folder.BuildVirtualFolderImpl(virtualFolders, "");
+ }
+ xml.Attribute("virtualFolders", virtualFolders);
+ xml.EndElement();
+}
+
+void Tree::BuildVirtualFolderImpl(std::string& virtualFolders,
+ const std::string& prefix) const
+{
+ virtualFolders += "CMake Files\\" + prefix + this->path + "\\;";
+ for (Tree const& folder : this->folders) {
+ folder.BuildVirtualFolderImpl(virtualFolders, prefix + this->path + "\\");
+ }
+}
+
+void Tree::BuildUnit(cmXMLWriter& xml, const std::string& fsPath) const
+{
+ for (std::string const& f : this->files) {
+ xml.StartElement("Unit");
+ xml.Attribute("filename", fsPath + f);
+
+ xml.StartElement("Option");
+ xml.Attribute("virtualFolder", "CMake Files\\");
+ xml.EndElement();
+
+ xml.EndElement();
+ }
+ for (Tree const& folder : this->folders) {
+ folder.BuildUnitImpl(xml, "", fsPath);
+ }
+}
+
+void Tree::BuildUnitImpl(cmXMLWriter& xml,
+ const std::string& virtualFolderPath,
+ const std::string& fsPath) const
+{
+ for (std::string const& f : this->files) {
+ xml.StartElement("Unit");
+ xml.Attribute("filename", cmStrCat(fsPath, this->path, "/", f));
+
+ xml.StartElement("Option");
+ xml.Attribute(
+ "virtualFolder",
+ cmStrCat("CMake Files\\", virtualFolderPath, this->path, "\\"));
+ xml.EndElement();
+
+ xml.EndElement();
+ }
+ for (Tree const& folder : this->folders) {
+ folder.BuildUnitImpl(xml, cmStrCat(virtualFolderPath, this->path, "\\"),
+ cmStrCat(fsPath, this->path, "/"));
+ }
+}
+
+void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
+ const std::vector<cmLocalGenerator*>& lgs, const std::string& filename)
+{
+ const cmMakefile* mf = lgs[0]->GetMakefile();
+ cmGeneratedFileStream fout(filename);
+ if (!fout) {
+ return;
+ }
+
+ Tree tree;
+
+ // build tree of virtual folders
+ for (auto const& it : this->GlobalGenerator->GetProjectMap()) {
+ // Collect all files
+ std::vector<std::string> listFiles;
+ for (cmLocalGenerator* lg : it.second) {
+ cm::append(listFiles, lg->GetMakefile()->GetListFiles());
+ }
+
+ // Convert
+ for (std::string const& listFile : listFiles) {
+ // don't put cmake's own files into the project (#12110):
+ if (cmHasPrefix(listFile, cmSystemTools::GetCMakeRoot())) {
+ continue;
+ }
+
+ const std::string& relative = cmSystemTools::RelativePath(
+ it.second[0]->GetSourceDirectory(), listFile);
+ std::vector<std::string> split;
+ cmSystemTools::SplitPath(relative, split, false);
+ // Split filename from path
+ std::string fileName = *(split.end() - 1);
+ split.erase(split.end() - 1, split.end());
+
+ // We don't want paths with CMakeFiles in them
+ // or do we?
+ // In speedcrunch those where purely internal
+ //
+ // Also we can disable external (outside the project) files by setting ON
+ // CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable.
+ const bool excludeExternal = it.second[0]->GetMakefile()->IsOn(
+ "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES");
+ if (!split.empty() &&
+ (!excludeExternal || (relative.find("..") == std::string::npos)) &&
+ relative.find("CMakeFiles") == std::string::npos) {
+ tree.InsertPath(split, 1, fileName);
+ }
+ }
+ }
+
+ // figure out the compiler
+ std::string compiler = this->GetCBCompilerId(mf);
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& makeArgs =
+ mf->GetSafeDefinition("CMAKE_CODEBLOCKS_MAKE_ARGUMENTS");
+
+ cmXMLWriter xml(fout);
+ xml.StartDocument();
+ xml.StartElement("CodeBlocks_project_file");
+
+ xml.StartElement("FileVersion");
+ xml.Attribute("major", 1);
+ xml.Attribute("minor", 6);
+ xml.EndElement();
+
+ xml.StartElement("Project");
+
+ xml.StartElement("Option");
+ xml.Attribute("title", lgs[0]->GetProjectName());
+ xml.EndElement();
+
+ xml.StartElement("Option");
+ xml.Attribute("makefile_is_custom", 1);
+ xml.EndElement();
+
+ xml.StartElement("Option");
+ xml.Attribute("compiler", compiler);
+ xml.EndElement();
+
+ // Now build a virtual tree
+ tree.BuildVirtualFolder(xml);
+
+ xml.StartElement("Build");
+
+ this->AppendTarget(xml, "all", nullptr, make, lgs[0], compiler, makeArgs);
+
+ // add all executable and library targets and some of the GLOBAL
+ // and UTILITY targets
+ for (cmLocalGenerator* lg : lgs) {
+ const auto& targets = lg->GetGeneratorTargets();
+ for (const auto& target : targets) {
+ std::string targetName = target->GetName();
+ switch (target->GetType()) {
+ case cmStateEnums::GLOBAL_TARGET: {
+ // Only add the global targets from CMAKE_BINARY_DIR,
+ // not from the subdirs
+ if (lg->GetCurrentBinaryDirectory() == lg->GetBinaryDirectory()) {
+ this->AppendTarget(xml, targetName, nullptr, make, lg, compiler,
+ makeArgs);
+ }
+ } break;
+ case cmStateEnums::UTILITY:
+ // Add all utility targets, except the Nightly/Continuous/
+ // Experimental-"sub"targets as e.g. NightlyStart
+ if ((cmHasLiteralPrefix(targetName, "Nightly") &&
+ (targetName != "Nightly")) ||
+ (cmHasLiteralPrefix(targetName, "Continuous") &&
+ (targetName != "Continuous")) ||
+ (cmHasLiteralPrefix(targetName, "Experimental") &&
+ (targetName != "Experimental"))) {
+ break;
+ }
+
+ this->AppendTarget(xml, targetName, nullptr, make, lg, compiler,
+ makeArgs);
+ break;
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::OBJECT_LIBRARY: {
+ cmGeneratorTarget* gt = target.get();
+ this->AppendTarget(xml, targetName, gt, make, lg, compiler,
+ makeArgs);
+ std::string fastTarget = cmStrCat(targetName, "/fast");
+ this->AppendTarget(xml, fastTarget, gt, make, lg, compiler,
+ makeArgs);
+ } break;
+ default:
+ break;
+ }
+ }
+ }
+
+ xml.EndElement(); // Build
+
+ // Collect all used source files in the project.
+ // Keep a list of C/C++ source files which might have an accompanying header
+ // that should be looked for.
+ using all_files_map_t = std::map<std::string, CbpUnit>;
+ all_files_map_t allFiles;
+ std::vector<std::string> cFiles;
+
+ auto* cm = this->GlobalGenerator->GetCMakeInstance();
+
+ for (cmLocalGenerator* lg : lgs) {
+ cmMakefile* makefile = lg->GetMakefile();
+ const auto& targets = lg->GetGeneratorTargets();
+ for (const auto& target : targets) {
+ switch (target->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::OBJECT_LIBRARY:
+ case cmStateEnums::UTILITY: // can have sources since 2.6.3
+ {
+ std::vector<cmSourceFile*> sources;
+ target->GetSourceFiles(
+ sources, makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ for (cmSourceFile* s : sources) {
+ // don't add source files from UTILITY target which have the
+ // GENERATED property set:
+ if (target->GetType() == cmStateEnums::UTILITY &&
+ s->GetIsGenerated()) {
+ continue;
+ }
+
+ // check whether it is a C/C++/CUDA implementation file
+ bool isCFile = false;
+ std::string lang = s->GetOrDetermineLanguage();
+ if (lang == "C" || lang == "CXX" || lang == "CUDA") {
+ std::string const& srcext = s->GetExtension();
+ isCFile = cm->IsACLikeSourceExtension(srcext);
+ }
+
+ std::string const& fullPath = s->ResolveFullPath();
+
+ // Check file position relative to project root dir.
+ const std::string relative =
+ cmSystemTools::RelativePath(lg->GetSourceDirectory(), fullPath);
+ // Do not add this file if it has ".." in relative path and
+ // if CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable is on.
+ const bool excludeExternal = lg->GetMakefile()->IsOn(
+ "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES");
+ if (excludeExternal &&
+ (relative.find("..") != std::string::npos)) {
+ continue;
+ }
+
+ if (isCFile) {
+ cFiles.push_back(fullPath);
+ }
+
+ CbpUnit& cbpUnit = allFiles[fullPath];
+ cbpUnit.Targets.push_back(target.get());
+ }
+ }
+ default: // intended fallthrough
+ break;
+ }
+ }
+ }
+
+ std::vector<std::string> const& headerExts =
+ this->GlobalGenerator->GetCMakeInstance()->GetHeaderExtensions();
+
+ // The following loop tries to add header files matching to implementation
+ // files to the project. It does that by iterating over all
+ // C/C++ source files,
+ // replacing the file name extension with ".h" and checks whether such a
+ // file exists. If it does, it is inserted into the map of files.
+ // A very similar version of that code exists also in the CodeLite
+ // project generator.
+ for (std::string const& fileName : cFiles) {
+ std::string headerBasename =
+ cmStrCat(cmSystemTools::GetFilenamePath(fileName), '/',
+ cmSystemTools::GetFilenameWithoutExtension(fileName));
+
+ // check if there's a matching header around
+ for (std::string const& ext : headerExts) {
+ std::string hname = cmStrCat(headerBasename, '.', ext);
+ // if it's already in the set, don't check if it exists on disk
+ if (allFiles.find(hname) != allFiles.end()) {
+ break;
+ }
+
+ if (cmSystemTools::FileExists(hname)) {
+ allFiles[hname].Targets = allFiles[fileName].Targets;
+ break;
+ }
+ }
+ }
+
+ // insert all source files in the CodeBlocks project
+ for (auto const& s : allFiles) {
+ std::string const& unitFilename = s.first;
+ CbpUnit const& unit = s.second;
+
+ xml.StartElement("Unit");
+ xml.Attribute("filename", unitFilename);
+
+ for (cmGeneratorTarget const* tgt : unit.Targets) {
+ xml.StartElement("Option");
+ xml.Attribute("target", tgt->GetName());
+ xml.EndElement();
+ }
+
+ xml.EndElement();
+ }
+
+ // Add CMakeLists.txt
+ tree.BuildUnit(xml, mf->GetHomeDirectory() + "/");
+
+ xml.EndElement(); // Project
+ xml.EndElement(); // CodeBlocks_project_file
+ xml.EndDocument();
+}
+
+// Write a dummy file for OBJECT libraries, so C::B can reference some file
+std::string cmExtraCodeBlocksGenerator::CreateDummyTargetFile(
+ cmLocalGenerator* lg, cmGeneratorTarget* target) const
+{
+ // this file doesn't seem to be used by C::B in custom makefile mode,
+ // but we generate a unique file for each OBJECT library so in case
+ // C::B uses it in some way, the targets don't interfere with each other.
+ std::string filename = cmStrCat(lg->GetCurrentBinaryDirectory(), '/',
+ lg->GetTargetDirectory(target), '/',
+ target->GetName(), ".objlib");
+ cmGeneratedFileStream fout(filename);
+ if (fout) {
+ /* clang-format off */
+ fout << "# This is a dummy file for the OBJECT library "
+ << target->GetName()
+ << " for the CMake CodeBlocks project generator.\n"
+ << "# Don't edit, this file will be overwritten.\n";
+ /* clang-format on */
+ }
+ return filename;
+}
+
+// Generate the xml code for one target.
+void cmExtraCodeBlocksGenerator::AppendTarget(
+ cmXMLWriter& xml, const std::string& targetName, cmGeneratorTarget* target,
+ const std::string& make, const cmLocalGenerator* lg,
+ const std::string& compiler, const std::string& makeFlags)
+{
+ cmMakefile const* makefile = lg->GetMakefile();
+ std::string makefileName =
+ cmStrCat(lg->GetCurrentBinaryDirectory(), "/Makefile");
+
+ xml.StartElement("Target");
+ xml.Attribute("title", targetName);
+
+ if (target != nullptr) {
+ int cbTargetType = this->GetCBTargetType(target);
+ std::string workingDir = lg->GetCurrentBinaryDirectory();
+ if (target->GetType() == cmStateEnums::EXECUTABLE) {
+ // Determine the directory where the executable target is created, and
+ // set the working directory to this dir.
+ cmProp runtimeOutputDir =
+ makefile->GetDefinition("CMAKE_RUNTIME_OUTPUT_DIRECTORY");
+ if (runtimeOutputDir) {
+ workingDir = *runtimeOutputDir;
+ } else {
+ cmProp executableOutputDir =
+ makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
+ if (executableOutputDir) {
+ workingDir = *executableOutputDir;
+ }
+ }
+ }
+
+ std::string buildType = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ std::string location;
+ if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ location =
+ this->CreateDummyTargetFile(const_cast<cmLocalGenerator*>(lg), target);
+ } else {
+ location = target->GetLocation(buildType);
+ }
+
+ xml.StartElement("Option");
+ xml.Attribute("output", location);
+ xml.Attribute("prefix_auto", 0);
+ xml.Attribute("extension_auto", 0);
+ xml.EndElement();
+
+ xml.StartElement("Option");
+ xml.Attribute("working_dir", workingDir);
+ xml.EndElement();
+
+ xml.StartElement("Option");
+ xml.Attribute("object_output", "./");
+ xml.EndElement();
+
+ xml.StartElement("Option");
+ xml.Attribute("type", cbTargetType);
+ xml.EndElement();
+
+ xml.StartElement("Option");
+ xml.Attribute("compiler", compiler);
+ xml.EndElement();
+
+ xml.StartElement("Compiler");
+
+ // the compilerdefines for this target
+ std::vector<std::string> cdefs;
+ target->GetCompileDefinitions(cdefs, buildType, "C");
+
+ // Expand the list.
+ for (std::string const& d : cdefs) {
+ xml.StartElement("Add");
+ xml.Attribute("option", "-D" + d);
+ xml.EndElement();
+ }
+
+ // the include directories for this target
+ std::vector<std::string> allIncludeDirs;
+ {
+ std::vector<std::string> includes;
+ lg->GetIncludeDirectories(includes, target, "C", buildType);
+ cm::append(allIncludeDirs, includes);
+ }
+
+ std::string systemIncludeDirs = makefile->GetSafeDefinition(
+ "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
+ if (!systemIncludeDirs.empty()) {
+ cm::append(allIncludeDirs, cmExpandedList(systemIncludeDirs));
+ }
+
+ systemIncludeDirs = makefile->GetSafeDefinition(
+ "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
+ if (!systemIncludeDirs.empty()) {
+ cm::append(allIncludeDirs, cmExpandedList(systemIncludeDirs));
+ }
+
+ auto end = cmRemoveDuplicates(allIncludeDirs);
+
+ for (std::string const& str : cmMakeRange(allIncludeDirs.cbegin(), end)) {
+ xml.StartElement("Add");
+ xml.Attribute("directory", str);
+ xml.EndElement();
+ }
+
+ xml.EndElement(); // Compiler
+ } else // e.g. all and the GLOBAL and UTILITY targets
+ {
+ xml.StartElement("Option");
+ xml.Attribute("working_dir", lg->GetCurrentBinaryDirectory());
+ xml.EndElement();
+
+ xml.StartElement("Option");
+ xml.Attribute("type", 4);
+ xml.EndElement();
+ }
+
+ xml.StartElement("MakeCommands");
+
+ xml.StartElement("Build");
+ xml.Attribute(
+ "command",
+ this->BuildMakeCommand(make, makefileName, targetName, makeFlags));
+ xml.EndElement();
+
+ xml.StartElement("CompileFile");
+ xml.Attribute(
+ "command",
+ this->BuildMakeCommand(make, makefileName, "\"$file\"", makeFlags));
+ xml.EndElement();
+
+ xml.StartElement("Clean");
+ xml.Attribute(
+ "command", this->BuildMakeCommand(make, makefileName, "clean", makeFlags));
+ xml.EndElement();
+
+ xml.StartElement("DistClean");
+ xml.Attribute(
+ "command", this->BuildMakeCommand(make, makefileName, "clean", makeFlags));
+ xml.EndElement();
+
+ xml.EndElement(); // MakeCommands
+ xml.EndElement(); // Target
+}
+
+// Translate the cmake compiler id into the CodeBlocks compiler id
+std::string cmExtraCodeBlocksGenerator::GetCBCompilerId(const cmMakefile* mf)
+{
+ // allow the user to overwrite the detected compiler
+ std::string userCompiler =
+ mf->GetSafeDefinition("CMAKE_CODEBLOCKS_COMPILER_ID");
+ if (!userCompiler.empty()) {
+ return userCompiler;
+ }
+
+ // figure out which language to use
+ // for now care only for C, C++, and Fortran
+
+ // projects with C/C++ and Fortran are handled as C/C++ projects
+ bool pureFortran = false;
+ std::string compilerIdVar;
+ if (this->GlobalGenerator->GetLanguageEnabled("CXX")) {
+ compilerIdVar = "CMAKE_CXX_COMPILER_ID";
+ } else if (this->GlobalGenerator->GetLanguageEnabled("C")) {
+ compilerIdVar = "CMAKE_C_COMPILER_ID";
+ } else if (this->GlobalGenerator->GetLanguageEnabled("Fortran")) {
+ compilerIdVar = "CMAKE_Fortran_COMPILER_ID";
+ pureFortran = true;
+ }
+
+ std::string const& compilerId = mf->GetSafeDefinition(compilerIdVar);
+ std::string compiler = "gcc"; // default to gcc
+ if (compilerId == "MSVC") {
+ if (mf->IsDefinitionSet("MSVC10")) {
+ compiler = "msvc10";
+ } else {
+ compiler = "msvc8";
+ }
+ } else if (compilerId == "Borland") {
+ compiler = "bcc";
+ } else if (compilerId == "SDCC") {
+ compiler = "sdcc";
+ } else if (compilerId == "Intel") {
+ if (pureFortran && mf->IsDefinitionSet("WIN32")) {
+ compiler = "ifcwin"; // Intel Fortran for Windows (known by cbFortran)
+ } else {
+ compiler = "icc";
+ }
+ } else if (compilerId == "Watcom" || compilerId == "OpenWatcom") {
+ compiler = "ow";
+ } else if (compilerId == "Clang") {
+ compiler = "clang";
+ } else if (compilerId == "PGI") {
+ if (pureFortran) {
+ compiler = "pgifortran";
+ } else {
+ compiler = "pgi"; // does not exist as default in CodeBlocks 16.01
+ }
+ } else if (compilerId == "GNU") {
+ if (pureFortran) {
+ compiler = "gfortran";
+ } else {
+ compiler = "gcc";
+ }
+ }
+ return compiler;
+}
+
+// Translate the cmake target type into the CodeBlocks target type id
+int cmExtraCodeBlocksGenerator::GetCBTargetType(cmGeneratorTarget* target)
+{
+ switch (target->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ if ((target->IsWin32Executable(
+ target->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"))) ||
+ (target->GetPropertyAsBool("MACOSX_BUNDLE"))) {
+ return 0;
+ }
+ return 1;
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::OBJECT_LIBRARY:
+ return 2;
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ return 3;
+ default:
+ return 4;
+ }
+}
+
+// Create the command line for building the given target using the selected
+// make
+std::string cmExtraCodeBlocksGenerator::BuildMakeCommand(
+ const std::string& make, const std::string& makefile,
+ const std::string& target, const std::string& makeFlags)
+{
+ std::string command = make;
+ if (!makeFlags.empty()) {
+ command += " ";
+ command += makeFlags;
+ }
+
+ std::string generator = this->GlobalGenerator->GetName();
+ if (generator == "NMake Makefiles" || generator == "NMake Makefiles JOM") {
+ // For Windows ConvertToOutputPath already adds quotes when required.
+ // These need to be escaped, see
+ // https://gitlab.kitware.com/cmake/cmake/-/issues/13952
+ std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
+ command += " /NOLOGO /f ";
+ command += makefileName;
+ command += " VERBOSE=1 ";
+ command += target;
+ } else if (generator == "MinGW Makefiles") {
+ // no escaping of spaces in this case, see
+ // https://gitlab.kitware.com/cmake/cmake/-/issues/10014
+ std::string const& makefileName = makefile;
+ command += " -f \"";
+ command += makefileName;
+ command += "\" ";
+ command += " VERBOSE=1 ";
+ command += target;
+ } else if (generator == "Ninja") {
+ command += " -v ";
+ command += target;
+ } else {
+ std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
+ command += " -f \"";
+ command += makefileName;
+ command += "\" ";
+ command += " VERBOSE=1 ";
+ command += target;
+ }
+ return command;
+}
diff --git a/Source/cmExtraCodeBlocksGenerator.h b/Source/cmExtraCodeBlocksGenerator.h
new file mode 100644
index 0000000..cada5dd
--- /dev/null
+++ b/Source/cmExtraCodeBlocksGenerator.h
@@ -0,0 +1,52 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+#include "cmExternalMakefileProjectGenerator.h"
+
+class cmGeneratorTarget;
+class cmLocalGenerator;
+class cmMakefile;
+class cmXMLWriter;
+
+/** \class cmExtraCodeBlocksGenerator
+ * \brief Write CodeBlocks project files for Makefile based projects
+ */
+class cmExtraCodeBlocksGenerator : public cmExternalMakefileProjectGenerator
+{
+public:
+ cmExtraCodeBlocksGenerator();
+
+ static cmExternalMakefileProjectGeneratorFactory* GetFactory();
+
+ void Generate() override;
+
+private:
+ struct CbpUnit
+ {
+ std::vector<const cmGeneratorTarget*> Targets;
+ };
+
+ void CreateProjectFile(const std::vector<cmLocalGenerator*>& lgs);
+
+ void CreateNewProjectFile(const std::vector<cmLocalGenerator*>& lgs,
+ const std::string& filename);
+ std::string CreateDummyTargetFile(cmLocalGenerator* lg,
+ cmGeneratorTarget* target) const;
+
+ std::string GetCBCompilerId(const cmMakefile* mf);
+ int GetCBTargetType(cmGeneratorTarget* target);
+ std::string BuildMakeCommand(const std::string& make,
+ const std::string& makefile,
+ const std::string& target,
+ const std::string& makeFlags);
+ void AppendTarget(cmXMLWriter& xml, const std::string& targetName,
+ cmGeneratorTarget* target, const std::string& make,
+ const cmLocalGenerator* lg, const std::string& compiler,
+ const std::string& makeFlags);
+};
diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx
new file mode 100644
index 0000000..549b08b
--- /dev/null
+++ b/Source/cmExtraCodeLiteGenerator.cxx
@@ -0,0 +1,683 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExtraCodeLiteGenerator.h"
+
+#include <cstring>
+#include <map>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <utility>
+
+#include "cmsys/SystemInformation.hxx"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+cmExtraCodeLiteGenerator::cmExtraCodeLiteGenerator()
+ : ConfigName("NoConfig")
+{
+}
+
+cmExternalMakefileProjectGeneratorFactory*
+cmExtraCodeLiteGenerator::GetFactory()
+{
+ static cmExternalMakefileProjectGeneratorSimpleFactory<
+ cmExtraCodeLiteGenerator>
+ factory("CodeLite", "Generates CodeLite project files.");
+
+ if (factory.GetSupportedGlobalGenerators().empty()) {
+#if defined(_WIN32)
+ factory.AddSupportedGlobalGenerator("MinGW Makefiles");
+ factory.AddSupportedGlobalGenerator("NMake Makefiles");
+#endif
+ factory.AddSupportedGlobalGenerator("Ninja");
+ factory.AddSupportedGlobalGenerator("Unix Makefiles");
+ }
+
+ return &factory;
+}
+
+void cmExtraCodeLiteGenerator::Generate()
+{
+ // Hold root tree information for creating the workspace
+ std::string workspaceProjectName;
+ std::string workspaceOutputDir;
+ std::string workspaceFileName;
+ std::string workspaceSourcePath;
+
+ const std::map<std::string, std::vector<cmLocalGenerator*>>& projectMap =
+ this->GlobalGenerator->GetProjectMap();
+
+ // loop projects and locate the root project.
+ // and extract the information for creating the worspace
+ // root makefile
+ for (auto const& it : projectMap) {
+ cmLocalGenerator* lg = it.second[0];
+ const cmMakefile* mf = lg->GetMakefile();
+ this->ConfigName = this->GetConfigurationName(mf);
+
+ if (lg->GetCurrentBinaryDirectory() == lg->GetBinaryDirectory()) {
+ workspaceOutputDir = lg->GetCurrentBinaryDirectory();
+ workspaceProjectName = lg->GetProjectName();
+ workspaceSourcePath = lg->GetSourceDirectory();
+ workspaceFileName =
+ cmStrCat(workspaceOutputDir, '/', workspaceProjectName, ".workspace");
+ this->WorkspacePath = lg->GetCurrentBinaryDirectory();
+ break;
+ }
+ }
+
+ cmGeneratedFileStream fout(workspaceFileName);
+ cmXMLWriter xml(fout);
+
+ xml.StartDocument("utf-8");
+ xml.StartElement("CodeLite_Workspace");
+ xml.Attribute("Name", workspaceProjectName);
+
+ bool const targetsAreProjects =
+ this->GlobalGenerator->GlobalSettingIsOn("CMAKE_CODELITE_USE_TARGETS");
+
+ std::vector<std::string> ProjectNames;
+ if (targetsAreProjects) {
+ ProjectNames = this->CreateProjectsByTarget(&xml);
+ } else {
+ ProjectNames = this->CreateProjectsByProjectMaps(&xml);
+ }
+
+ xml.StartElement("BuildMatrix");
+ xml.StartElement("WorkspaceConfiguration");
+ xml.Attribute("Name", this->ConfigName);
+ xml.Attribute("Selected", "yes");
+
+ for (std::string const& it : ProjectNames) {
+ xml.StartElement("Project");
+ xml.Attribute("Name", it);
+ xml.Attribute("ConfigName", this->ConfigName);
+ xml.EndElement();
+ }
+
+ xml.EndElement(); // WorkspaceConfiguration
+ xml.EndElement(); // BuildMatrix
+ xml.EndElement(); // CodeLite_Workspace
+}
+
+// Create projects where targets are the projects
+std::vector<std::string> cmExtraCodeLiteGenerator::CreateProjectsByTarget(
+ cmXMLWriter* xml)
+{
+ std::vector<std::string> retval;
+ // for each target in the workspace create a codelite project
+ const auto& lgs = this->GlobalGenerator->GetLocalGenerators();
+ for (const auto& lg : lgs) {
+ for (const auto& lt : lg->GetGeneratorTargets()) {
+ cmStateEnums::TargetType type = lt->GetType();
+ std::string const& outputDir = lg->GetCurrentBinaryDirectory();
+ std::string targetName = lt->GetName();
+ std::string filename = cmStrCat(outputDir, "/", targetName, ".project");
+ retval.push_back(targetName);
+ // Make the project file relative to the workspace
+ std::string relafilename =
+ cmSystemTools::RelativePath(this->WorkspacePath, filename);
+ std::string visualname = targetName;
+ switch (type) {
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ visualname = cmStrCat("lib", visualname);
+ CM_FALLTHROUGH;
+ case cmStateEnums::EXECUTABLE:
+ xml->StartElement("Project");
+ xml->Attribute("Name", visualname);
+ xml->Attribute("Path", relafilename);
+ xml->Attribute("Active", "No");
+ xml->EndElement();
+
+ this->CreateNewProjectFile(lt.get(), filename);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return retval;
+}
+
+// The "older way of doing it.
+std::vector<std::string> cmExtraCodeLiteGenerator::CreateProjectsByProjectMaps(
+ cmXMLWriter* xml)
+{
+ std::vector<std::string> retval;
+ // for each sub project in the workspace create a codelite project
+ for (auto const& it : this->GlobalGenerator->GetProjectMap()) {
+
+ std::string const& outputDir = it.second[0]->GetCurrentBinaryDirectory();
+ std::string projectName = it.second[0]->GetProjectName();
+ retval.push_back(projectName);
+ std::string filename = cmStrCat(outputDir, "/", projectName, ".project");
+
+ // Make the project file relative to the workspace
+ filename = cmSystemTools::RelativePath(this->WorkspacePath, filename);
+
+ // create a project file
+ this->CreateProjectFile(it.second);
+ xml->StartElement("Project");
+ xml->Attribute("Name", projectName);
+ xml->Attribute("Path", filename);
+ xml->Attribute("Active", "No");
+ xml->EndElement();
+ }
+ return retval;
+}
+
+/* create the project file */
+void cmExtraCodeLiteGenerator::CreateProjectFile(
+ const std::vector<cmLocalGenerator*>& lgs)
+{
+ std::string const& outputDir = lgs[0]->GetCurrentBinaryDirectory();
+ std::string projectName = lgs[0]->GetProjectName();
+ std::string filename = outputDir + "/";
+
+ filename += projectName + ".project";
+ this->CreateNewProjectFile(lgs, filename);
+}
+
+std::string cmExtraCodeLiteGenerator::CollectSourceFiles(
+ const cmMakefile* makefile, const cmGeneratorTarget* gt,
+ std::map<std::string, cmSourceFile*>& cFiles,
+ std::set<std::string>& otherFiles)
+{
+ std::string projectType;
+ switch (gt->GetType()) {
+ case cmStateEnums::EXECUTABLE: {
+ projectType = "Executable";
+ } break;
+ case cmStateEnums::STATIC_LIBRARY: {
+ projectType = "Static Library";
+ } break;
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY: {
+ projectType = "Dynamic Library";
+ } break;
+ default: // intended fallthrough
+ break;
+ }
+
+ switch (gt->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY: {
+ cmake const* cm = makefile->GetCMakeInstance();
+ std::vector<cmSourceFile*> sources;
+ gt->GetSourceFiles(sources,
+ makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ for (cmSourceFile* s : sources) {
+ std::string const& fullPath = s->ResolveFullPath();
+ std::string const& extLower =
+ cmSystemTools::LowerCase(s->GetExtension());
+ // check whether it is a source or a include file
+ // then put it accordingly into one of the two containers
+ if (cm->IsAKnownSourceExtension(extLower)) {
+ cFiles[fullPath] = s;
+ } else {
+ otherFiles.insert(fullPath);
+ }
+ }
+ }
+ default: // intended fallthrough
+ break;
+ }
+ return projectType;
+}
+
+void cmExtraCodeLiteGenerator::CreateNewProjectFile(
+ const std::vector<cmLocalGenerator*>& lgs, const std::string& filename)
+{
+ const cmMakefile* mf = lgs[0]->GetMakefile();
+ cmGeneratedFileStream fout(filename);
+ if (!fout) {
+ return;
+ }
+ cmXMLWriter xml(fout);
+
+ ////////////////////////////////////
+ xml.StartDocument("utf-8");
+ xml.StartElement("CodeLite_Project");
+ xml.Attribute("Name", lgs[0]->GetProjectName());
+ xml.Attribute("InternalType", "");
+
+ std::string projectType;
+
+ // Collect all used source files in the project
+ // Sort them into two containers, one for C/C++ implementation files
+ // which may have an accompanying header, one for all other files
+ std::map<std::string, cmSourceFile*> cFiles;
+ std::set<std::string> otherFiles;
+
+ for (cmLocalGenerator* lg : lgs) {
+ cmMakefile* makefile = lg->GetMakefile();
+ for (const auto& target : lg->GetGeneratorTargets()) {
+ projectType =
+ this->CollectSourceFiles(makefile, target.get(), cFiles, otherFiles);
+ }
+ }
+
+ // Get the project path ( we need it later to convert files to
+ // their relative path)
+ std::string projectPath = cmSystemTools::GetFilenamePath(filename);
+
+ this->CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf,
+ projectType, "");
+
+ xml.EndElement(); // CodeLite_Project
+}
+
+void cmExtraCodeLiteGenerator::FindMatchingHeaderfiles(
+ std::map<std::string, cmSourceFile*>& cFiles,
+ std::set<std::string>& otherFiles)
+{
+
+ const std::vector<std::string>& headerExts =
+ this->GlobalGenerator->GetCMakeInstance()->GetHeaderExtensions();
+
+ // The following loop tries to add header files matching to implementation
+ // files to the project. It does that by iterating over all source files,
+ // replacing the file name extension with ".h" and checks whether such a
+ // file exists. If it does, it is inserted into the map of files.
+ // A very similar version of that code exists also in the CodeBlocks
+ // project generator.
+ for (auto const& sit : cFiles) {
+ std::string headerBasename =
+ cmStrCat(cmSystemTools::GetFilenamePath(sit.first), '/',
+ cmSystemTools::GetFilenameWithoutExtension(sit.first));
+
+ // check if there's a matching header around
+ for (std::string const& ext : headerExts) {
+ std::string hname = cmStrCat(headerBasename, '.', ext);
+ // if it's already in the set, don't check if it exists on disk
+ auto headerIt = otherFiles.find(hname);
+ if (headerIt != otherFiles.end()) {
+ break;
+ }
+
+ if (cmSystemTools::FileExists(hname)) {
+ otherFiles.insert(hname);
+ break;
+ }
+ }
+ }
+}
+
+void cmExtraCodeLiteGenerator::CreateFoldersAndFiles(
+ std::set<std::string>& cFiles, cmXMLWriter& xml,
+ const std::string& projectPath)
+{
+ std::vector<std::string> tmp_path;
+ std::vector<std::string> components;
+ size_t numOfEndEl = 0;
+
+ for (std::string const& cFile : cFiles) {
+ std::string frelapath = cmSystemTools::RelativePath(projectPath, cFile);
+ cmsys::SystemTools::SplitPath(frelapath, components, false);
+ components.pop_back(); // erase last member -> it is file, not folder
+ components.erase(components.begin()); // erase "root"
+
+ size_t sizeOfSkip = 0;
+
+ for (size_t i = 0; i < components.size(); ++i) {
+ // skip relative path
+ if (components[i] == ".." || components[i] == ".") {
+ sizeOfSkip++;
+ continue;
+ }
+
+ // same folder
+ if (tmp_path.size() > i - sizeOfSkip &&
+ tmp_path[i - sizeOfSkip] == components[i]) {
+ continue;
+ }
+
+ // delete "old" subfolders
+ if (tmp_path.size() > i - sizeOfSkip) {
+ numOfEndEl = tmp_path.size() - i + sizeOfSkip;
+ tmp_path.erase(tmp_path.end() - numOfEndEl, tmp_path.end());
+ for (; numOfEndEl--;) {
+ xml.EndElement();
+ }
+ }
+
+ // add folder
+ xml.StartElement("VirtualDirectory");
+ xml.Attribute("Name", components[i]);
+ tmp_path.push_back(components[i]);
+ }
+
+ // delete "old" subfolders
+ numOfEndEl = tmp_path.size() - components.size() + sizeOfSkip;
+ if (numOfEndEl) {
+ tmp_path.erase(tmp_path.end() - numOfEndEl, tmp_path.end());
+ for (; numOfEndEl--;) {
+ xml.EndElement();
+ }
+ }
+
+ // add file
+ xml.StartElement("File");
+ xml.Attribute("Name", frelapath);
+ xml.EndElement();
+ }
+
+ // end of folders
+ numOfEndEl = tmp_path.size();
+ for (; numOfEndEl--;) {
+ xml.EndElement();
+ }
+}
+
+void cmExtraCodeLiteGenerator::CreateFoldersAndFiles(
+ std::map<std::string, cmSourceFile*>& cFiles, cmXMLWriter& xml,
+ const std::string& projectPath)
+{
+ std::set<std::string> s;
+ for (auto const& it : cFiles) {
+ s.insert(it.first);
+ }
+ this->CreateFoldersAndFiles(s, xml, projectPath);
+}
+
+void cmExtraCodeLiteGenerator::CreateProjectSourceEntries(
+ std::map<std::string, cmSourceFile*>& cFiles,
+ std::set<std::string>& otherFiles, cmXMLWriter* _xml,
+ const std::string& projectPath, const cmMakefile* mf,
+ const std::string& projectType, const std::string& targetName)
+{
+ cmXMLWriter& xml(*_xml);
+ this->FindMatchingHeaderfiles(cFiles, otherFiles);
+ // Create 2 virtual folders: src and include
+ // and place all the implementation files into the src
+ // folder, the rest goes to the include folder
+ xml.StartElement("VirtualDirectory");
+ xml.Attribute("Name", "src");
+
+ // insert all source files in the codelite project
+ // first the C/C++ implementation files, then all others
+ this->CreateFoldersAndFiles(cFiles, xml, projectPath);
+ xml.EndElement(); // VirtualDirectory
+
+ xml.StartElement("VirtualDirectory");
+ xml.Attribute("Name", "include");
+ this->CreateFoldersAndFiles(otherFiles, xml, projectPath);
+ xml.EndElement(); // VirtualDirectory
+
+ // Get the number of CPUs. We use this information for the make -jN
+ // command
+ cmsys::SystemInformation info;
+ info.RunCPUCheck();
+
+ this->CpuCount =
+ info.GetNumberOfLogicalCPU() * info.GetNumberOfPhysicalCPU();
+
+ std::string codeliteCompilerName = this->GetCodeLiteCompilerName(mf);
+
+ xml.StartElement("Settings");
+ xml.Attribute("Type", projectType);
+
+ xml.StartElement("Configuration");
+ xml.Attribute("Name", this->ConfigName);
+ xml.Attribute("CompilerType", this->GetCodeLiteCompilerName(mf));
+ xml.Attribute("DebuggerType", "GNU gdb debugger");
+ xml.Attribute("Type", projectType);
+ xml.Attribute("BuildCmpWithGlobalSettings", "append");
+ xml.Attribute("BuildLnkWithGlobalSettings", "append");
+ xml.Attribute("BuildResWithGlobalSettings", "append");
+
+ xml.StartElement("Compiler");
+ xml.Attribute("Options", "-g");
+ xml.Attribute("Required", "yes");
+ xml.Attribute("PreCompiledHeader", "");
+ xml.StartElement("IncludePath");
+ xml.Attribute("Value", ".");
+ xml.EndElement(); // IncludePath
+ xml.EndElement(); // Compiler
+
+ xml.StartElement("Linker");
+ xml.Attribute("Options", "");
+ xml.Attribute("Required", "yes");
+ xml.EndElement(); // Linker
+
+ xml.StartElement("ResourceCompiler");
+ xml.Attribute("Options", "");
+ xml.Attribute("Required", "no");
+ xml.EndElement(); // ResourceCompiler
+
+ xml.StartElement("General");
+ std::string outputPath =
+ mf->GetSafeDefinition("CMAKE_RUNTIME_OUTPUT_DIRECTORY");
+ if (outputPath.empty()) {
+ outputPath = mf->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
+ }
+ std::string relapath;
+ if (!outputPath.empty()) {
+ relapath = cmSystemTools::RelativePath(projectPath, outputPath);
+ xml.Attribute("OutputFile", relapath + "/$(ProjectName)");
+ } else {
+ xml.Attribute("OutputFile", "$(IntermediateDirectory)/$(ProjectName)");
+ }
+ xml.Attribute("IntermediateDirectory", "./");
+ xml.Attribute("Command", "./$(ProjectName)");
+ xml.Attribute("CommandArguments", "");
+ if (!outputPath.empty()) {
+ xml.Attribute("WorkingDirectory", relapath);
+ } else {
+ xml.Attribute("WorkingDirectory", "$(IntermediateDirectory)");
+ }
+ xml.Attribute("PauseExecWhenProcTerminates", "yes");
+ xml.EndElement(); // General
+
+ xml.StartElement("Debugger");
+ xml.Attribute("IsRemote", "no");
+ xml.Attribute("RemoteHostName", "");
+ xml.Attribute("RemoteHostPort", "");
+ xml.Attribute("DebuggerPath", "");
+ xml.Element("PostConnectCommands");
+ xml.Element("StartupCommands");
+ xml.EndElement(); // Debugger
+
+ xml.Element("PreBuild");
+ xml.Element("PostBuild");
+
+ xml.StartElement("CustomBuild");
+ xml.Attribute("Enabled", "yes");
+ xml.Element("RebuildCommand", this->GetRebuildCommand(mf, targetName));
+ xml.Element("CleanCommand", this->GetCleanCommand(mf, targetName));
+ xml.Element("BuildCommand", this->GetBuildCommand(mf, targetName));
+ xml.Element("SingleFileCommand", this->GetSingleFileBuildCommand(mf));
+ xml.Element("PreprocessFileCommand");
+ xml.Element("WorkingDirectory", "$(WorkspacePath)");
+ xml.EndElement(); // CustomBuild
+
+ xml.StartElement("AdditionalRules");
+ xml.Element("CustomPostBuild");
+ xml.Element("CustomPreBuild");
+ xml.EndElement(); // AdditionalRules
+
+ xml.EndElement(); // Configuration
+ xml.StartElement("GlobalSettings");
+
+ xml.StartElement("Compiler");
+ xml.Attribute("Options", "");
+ xml.StartElement("IncludePath");
+ xml.Attribute("Value", ".");
+ xml.EndElement(); // IncludePath
+ xml.EndElement(); // Compiler
+
+ xml.StartElement("Linker");
+ xml.Attribute("Options", "");
+ xml.StartElement("LibraryPath");
+ xml.Attribute("Value", ".");
+ xml.EndElement(); // LibraryPath
+ xml.EndElement(); // Linker
+
+ xml.StartElement("ResourceCompiler");
+ xml.Attribute("Options", "");
+ xml.EndElement(); // ResourceCompiler
+
+ xml.EndElement(); // GlobalSettings
+ xml.EndElement(); // Settings
+}
+
+void cmExtraCodeLiteGenerator::CreateNewProjectFile(
+ const cmGeneratorTarget* gt, const std::string& filename)
+{
+ const cmMakefile* mf = gt->Makefile;
+ cmGeneratedFileStream fout(filename);
+ if (!fout) {
+ return;
+ }
+ cmXMLWriter xml(fout);
+
+ ////////////////////////////////////
+ xml.StartDocument("utf-8");
+ xml.StartElement("CodeLite_Project");
+ std::string targetName = gt->GetName();
+ std::string visualname = targetName;
+ switch (gt->GetType()) {
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ visualname = "lib" + targetName;
+ default: // intended fallthrough
+ break;
+ }
+ xml.Attribute("Name", visualname);
+ xml.Attribute("InternalType", "");
+
+ // Collect all used source files in the project
+ // Sort them into two containers, one for C/C++ implementation files
+ // which may have an accompanying header, one for all other files
+ std::string projectType;
+
+ std::map<std::string, cmSourceFile*> cFiles;
+ std::set<std::string> otherFiles;
+
+ projectType = this->CollectSourceFiles(mf, gt, cFiles, otherFiles);
+
+ // Get the project path ( we need it later to convert files to
+ // their relative path)
+ std::string projectPath = cmSystemTools::GetFilenamePath(filename);
+
+ this->CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf,
+ projectType, targetName);
+
+ xml.EndElement(); // CodeLite_Project
+}
+
+std::string cmExtraCodeLiteGenerator::GetCodeLiteCompilerName(
+ const cmMakefile* mf) const
+{
+ // figure out which language to use
+ // for now care only for C and C++
+ std::string compilerIdVar = "CMAKE_CXX_COMPILER_ID";
+ if (!this->GlobalGenerator->GetLanguageEnabled("CXX")) {
+ compilerIdVar = "CMAKE_C_COMPILER_ID";
+ }
+
+ std::string const& compilerId = mf->GetSafeDefinition(compilerIdVar);
+ std::string compiler = "gnu g++"; // default to g++
+
+ // Since we need the compiler for parsing purposes only
+ // it does not matter if we use clang or clang++, same as
+ // "gnu gcc" vs "gnu g++"
+ if (compilerId == "MSVC") {
+ compiler = "VC++";
+ } else if (compilerId == "Clang") {
+ compiler = "clang++";
+ } else if (compilerId == "GNU") {
+ compiler = "gnu g++";
+ }
+ return compiler;
+}
+
+std::string cmExtraCodeLiteGenerator::GetConfigurationName(
+ const cmMakefile* mf) const
+{
+ std::string confName = mf->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ // Trim the configuration name from whitespaces (left and right)
+ confName.erase(0, confName.find_first_not_of(" \t\r\v\n"));
+ confName.erase(confName.find_last_not_of(" \t\r\v\n") + 1);
+ if (confName.empty()) {
+ confName = "NoConfig";
+ }
+ return confName;
+}
+
+std::string cmExtraCodeLiteGenerator::GetBuildCommand(
+ const cmMakefile* mf, const std::string& targetName) const
+{
+ const std::string& generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ std::string buildCommand = make; // Default
+ std::ostringstream ss;
+ if (generator == "NMake Makefiles" || generator == "Ninja") {
+ ss << make;
+ } else if (generator == "MinGW Makefiles" || generator == "Unix Makefiles") {
+ ss << make << " -f$(ProjectPath)/Makefile";
+ if (this->CpuCount > 0) {
+ ss << " -j " << this->CpuCount;
+ }
+ }
+ if (!targetName.empty()) {
+ ss << " " << targetName;
+ }
+ buildCommand = ss.str();
+ return buildCommand;
+}
+
+std::string cmExtraCodeLiteGenerator::GetCleanCommand(
+ const cmMakefile* mf, const std::string& targetName) const
+{
+ std::string generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
+ std::ostringstream ss;
+ std::string buildcommand = this->GetBuildCommand(mf, "");
+ if (!targetName.empty() && generator == "Ninja") {
+ ss << buildcommand << " -t clean " << targetName;
+ } else {
+ ss << buildcommand << " clean";
+ }
+ return ss.str();
+}
+
+std::string cmExtraCodeLiteGenerator::GetRebuildCommand(
+ const cmMakefile* mf, const std::string& targetName) const
+{
+ return this->GetCleanCommand(mf, targetName) + " && " +
+ this->GetBuildCommand(mf, targetName);
+}
+
+std::string cmExtraCodeLiteGenerator::GetSingleFileBuildCommand(
+ const cmMakefile* mf) const
+{
+ std::string buildCommand;
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
+ if (generator == "Unix Makefiles" || generator == "MinGW Makefiles") {
+ std::ostringstream ss;
+#if defined(_WIN32)
+ ss << make << " -f$(ProjectPath)/Makefile -B $(CurrentFileFullName).obj";
+#else
+ ss << make << " -f$(ProjectPath)/Makefile -B $(CurrentFileFullName).o";
+#endif
+ buildCommand = ss.str();
+ }
+ return buildCommand;
+}
diff --git a/Source/cmExtraCodeLiteGenerator.h b/Source/cmExtraCodeLiteGenerator.h
new file mode 100644
index 0000000..2bb1c04
--- /dev/null
+++ b/Source/cmExtraCodeLiteGenerator.h
@@ -0,0 +1,68 @@
+/* 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 <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmExternalMakefileProjectGenerator.h"
+
+class cmLocalGenerator;
+class cmMakefile;
+class cmGeneratorTarget;
+class cmXMLWriter;
+class cmSourceFile;
+
+class cmExtraCodeLiteGenerator : public cmExternalMakefileProjectGenerator
+{
+protected:
+ std::string ConfigName;
+ std::string WorkspacePath;
+ unsigned int CpuCount = 2;
+
+ std::string GetCodeLiteCompilerName(const cmMakefile* mf) const;
+ std::string GetConfigurationName(const cmMakefile* mf) const;
+ std::string GetBuildCommand(const cmMakefile* mf,
+ const std::string& targetName) const;
+ std::string GetCleanCommand(const cmMakefile* mf,
+ const std::string& targetName) const;
+ std::string GetRebuildCommand(const cmMakefile* mf,
+ const std::string& targetName) const;
+ std::string GetSingleFileBuildCommand(const cmMakefile* mf) const;
+ std::vector<std::string> CreateProjectsByTarget(cmXMLWriter* xml);
+ std::vector<std::string> CreateProjectsByProjectMaps(cmXMLWriter* xml);
+ std::string CollectSourceFiles(const cmMakefile* makefile,
+ const cmGeneratorTarget* gt,
+ std::map<std::string, cmSourceFile*>& cFiles,
+ std::set<std::string>& otherFiles);
+ void FindMatchingHeaderfiles(std::map<std::string, cmSourceFile*>& cFiles,
+ std::set<std::string>& otherFiles);
+ void CreateProjectSourceEntries(std::map<std::string, cmSourceFile*>& cFiles,
+ std::set<std::string>& otherFiles,
+ cmXMLWriter* xml,
+ const std::string& projectPath,
+ const cmMakefile* mf,
+ const std::string& projectType,
+ const std::string& targetName);
+ void CreateFoldersAndFiles(std::set<std::string>& cFiles, cmXMLWriter& xml,
+ const std::string& projectPath);
+ void CreateFoldersAndFiles(std::map<std::string, cmSourceFile*>& cFiles,
+ cmXMLWriter& xml, const std::string& projectPath);
+
+public:
+ cmExtraCodeLiteGenerator();
+
+ static cmExternalMakefileProjectGeneratorFactory* GetFactory();
+
+ void Generate() override;
+ void CreateProjectFile(const std::vector<cmLocalGenerator*>& lgs);
+
+ void CreateNewProjectFile(const std::vector<cmLocalGenerator*>& lgs,
+ const std::string& filename);
+ void CreateNewProjectFile(const cmGeneratorTarget* lg,
+ const std::string& filename);
+};
diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx
new file mode 100644
index 0000000..ccfd727
--- /dev/null
+++ b/Source/cmExtraEclipseCDT4Generator.cxx
@@ -0,0 +1,1209 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExtraEclipseCDT4Generator.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <map>
+#include <memory>
+#include <sstream>
+#include <utility>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmSourceFile.h"
+#include "cmSourceGroup.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+static void AppendAttribute(cmXMLWriter& xml, const char* keyval)
+{
+ xml.StartElement("attribute");
+ xml.Attribute("key", keyval);
+ xml.Attribute("value", keyval);
+ xml.EndElement();
+}
+
+template <typename T>
+void AppendDictionary(cmXMLWriter& xml, const char* key, T const& value)
+{
+ xml.StartElement("dictionary");
+ xml.Element("key", key);
+ xml.Element("value", value);
+ xml.EndElement();
+}
+
+cmExtraEclipseCDT4Generator::cmExtraEclipseCDT4Generator()
+{
+ this->IsOutOfSourceBuild = false;
+ this->GenerateSourceProject = false;
+ this->SupportsVirtualFolders = true;
+ this->GenerateLinkedResources = true;
+ this->SupportsGmakeErrorParser = true;
+ this->SupportsMachO64Parser = true;
+ this->CEnabled = false;
+ this->CXXEnabled = false;
+}
+
+cmExternalMakefileProjectGeneratorFactory*
+cmExtraEclipseCDT4Generator::GetFactory()
+{
+ static cmExternalMakefileProjectGeneratorSimpleFactory<
+ cmExtraEclipseCDT4Generator>
+ factory("Eclipse CDT4", "Generates Eclipse CDT 4.0 project files.");
+
+ if (factory.GetSupportedGlobalGenerators().empty()) {
+// TODO: Verify if __CYGWIN__ should be checked.
+//#if defined(_WIN32) && !defined(__CYGWIN__)
+#if defined(_WIN32)
+ factory.AddSupportedGlobalGenerator("NMake Makefiles");
+ factory.AddSupportedGlobalGenerator("MinGW Makefiles");
+// factory.AddSupportedGlobalGenerator("MSYS Makefiles");
+#endif
+ factory.AddSupportedGlobalGenerator("Ninja");
+ factory.AddSupportedGlobalGenerator("Unix Makefiles");
+ }
+
+ return &factory;
+}
+
+void cmExtraEclipseCDT4Generator::EnableLanguage(
+ std::vector<std::string> const& languages, cmMakefile* /*unused*/,
+ bool /*optional*/)
+{
+ for (std::string const& l : languages) {
+ if (l == "CXX") {
+ this->Natures.insert("org.eclipse.cdt.core.ccnature");
+ this->Natures.insert("org.eclipse.cdt.core.cnature");
+ this->CXXEnabled = true;
+ } else if (l == "C") {
+ this->Natures.insert("org.eclipse.cdt.core.cnature");
+ this->CEnabled = true;
+ } else if (l == "Java") {
+ this->Natures.insert("org.eclipse.jdt.core.javanature");
+ }
+ }
+}
+
+void cmExtraEclipseCDT4Generator::Generate()
+{
+ const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0];
+ const cmMakefile* mf = lg->GetMakefile();
+
+ std::string eclipseVersion = mf->GetSafeDefinition("CMAKE_ECLIPSE_VERSION");
+ cmsys::RegularExpression regex(".*([0-9]+\\.[0-9]+).*");
+ if (regex.find(eclipseVersion)) {
+ unsigned int majorVersion = 0;
+ unsigned int minorVersion = 0;
+ int res =
+ sscanf(regex.match(1).c_str(), "%u.%u", &majorVersion, &minorVersion);
+ if (res == 2) {
+ int version = majorVersion * 1000 + minorVersion;
+ if (version < 3006) // 3.6 is Helios
+ {
+ this->SupportsVirtualFolders = false;
+ this->SupportsMachO64Parser = false;
+ }
+ if (version < 3007) // 3.7 is Indigo
+ {
+ this->SupportsGmakeErrorParser = false;
+ }
+ }
+ }
+
+ // TODO: Decide if these are local or member variables
+ this->HomeDirectory = lg->GetSourceDirectory();
+ this->HomeOutputDirectory = lg->GetBinaryDirectory();
+
+ this->GenerateLinkedResources =
+ mf->IsOn("CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES");
+
+ this->IsOutOfSourceBuild =
+ (this->HomeDirectory != this->HomeOutputDirectory);
+
+ this->GenerateSourceProject =
+ (this->IsOutOfSourceBuild &&
+ mf->IsOn("CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT"));
+
+ if (!this->GenerateSourceProject &&
+ (mf->IsOn("ECLIPSE_CDT4_GENERATE_SOURCE_PROJECT"))) {
+ mf->IssueMessage(
+ MessageType::WARNING,
+ "ECLIPSE_CDT4_GENERATE_SOURCE_PROJECT is set to TRUE, "
+ "but this variable is not supported anymore since CMake 2.8.7.\n"
+ "Enable CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT instead.");
+ }
+
+ if (cmSystemTools::IsSubDirectory(this->HomeOutputDirectory,
+ this->HomeDirectory)) {
+ mf->IssueMessage(MessageType::WARNING,
+ "The build directory is a subdirectory "
+ "of the source directory.\n"
+ "This is not supported well by Eclipse. It is strongly "
+ "recommended to use a build directory which is a "
+ "sibling of the source directory.");
+ }
+
+ // NOTE: This is not good, since it pollutes the source tree. However,
+ // Eclipse doesn't allow CVS/SVN to work when the .project is not in
+ // the cvs/svn root directory. Hence, this is provided as an option.
+ if (this->GenerateSourceProject) {
+ // create .project file in the source tree
+ this->CreateSourceProjectFile();
+ }
+
+ // create a .project file
+ this->CreateProjectFile();
+
+ // create a .cproject file
+ this->CreateCProjectFile();
+
+ // create resource settings
+ this->CreateSettingsResourcePrefsFile();
+}
+
+void cmExtraEclipseCDT4Generator::CreateSettingsResourcePrefsFile()
+{
+ const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0];
+ cmMakefile* mf = lg->GetMakefile();
+
+ const std::string filename =
+ this->HomeOutputDirectory + "/.settings/org.eclipse.core.resources.prefs";
+
+ cmGeneratedFileStream fout(filename);
+ if (!fout) {
+ return;
+ }
+
+ fout << "eclipse.preferences.version=1\n";
+ cmProp encoding = mf->GetDefinition("CMAKE_ECLIPSE_RESOURCE_ENCODING");
+ if (encoding) {
+ fout << "encoding/<project>=" << *encoding << '\n';
+ }
+}
+
+void cmExtraEclipseCDT4Generator::CreateSourceProjectFile()
+{
+ assert(this->HomeDirectory != this->HomeOutputDirectory);
+
+ // set up the project name: <project>-Source@<baseSourcePathName>
+ const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0];
+ std::string name = cmExtraEclipseCDT4Generator::GenerateProjectName(
+ lg->GetProjectName(), "Source",
+ cmExtraEclipseCDT4Generator::GetPathBasename(this->HomeDirectory));
+
+ const std::string filename = this->HomeDirectory + "/.project";
+ cmGeneratedFileStream fout(filename);
+ if (!fout) {
+ return;
+ }
+
+ cmXMLWriter xml(fout);
+ xml.StartDocument("UTF-8");
+ xml.StartElement("projectDescription");
+ xml.Element("name", name);
+ xml.Element("comment", "");
+ xml.Element("projects", "");
+ xml.Element("buildSpec", "");
+ xml.Element("natures", "");
+ xml.StartElement("linkedResources");
+
+ if (this->SupportsVirtualFolders) {
+ this->CreateLinksToSubprojects(xml, this->HomeDirectory);
+ this->SrcLinkedResources.clear();
+ }
+
+ xml.EndElement(); // linkedResources
+ xml.EndElement(); // projectDescription
+ xml.EndDocument();
+}
+
+void cmExtraEclipseCDT4Generator::AddEnvVar(std::ostream& out,
+ const char* envVar,
+ cmLocalGenerator& lg)
+{
+ cmMakefile* mf = lg.GetMakefile();
+
+ // get the variables from the environment and from the cache and then
+ // figure out which one to use:
+
+ std::string envVarValue;
+ const bool envVarSet = cmSystemTools::GetEnv(envVar, envVarValue);
+
+ std::string cacheEntryName = cmStrCat("CMAKE_ECLIPSE_ENVVAR_", envVar);
+ cmProp cacheValue = lg.GetState()->GetInitializedCacheValue(cacheEntryName);
+
+ // now we have both, decide which one to use
+ std::string valueToUse;
+ if (!envVarSet && cacheValue == nullptr) {
+ // nothing known, do nothing
+ valueToUse.clear();
+ } else if (envVarSet && cacheValue == nullptr) {
+ // The variable is in the env, but not in the cache. Use it and put it
+ // in the cache
+ valueToUse = envVarValue;
+ mf->AddCacheDefinition(cacheEntryName, valueToUse, cacheEntryName.c_str(),
+ cmStateEnums::STRING, true);
+ mf->GetCMakeInstance()->SaveCache(lg.GetBinaryDirectory());
+ } else if (!envVarSet && cacheValue != nullptr) {
+ // It is already in the cache, but not in the env, so use it from the cache
+ valueToUse = *cacheValue;
+ } else {
+ // It is both in the cache and in the env.
+ // Use the version from the env. except if the value from the env is
+ // completely contained in the value from the cache (for the case that we
+ // now have a PATH without MSVC dirs in the env. but had the full PATH with
+ // all MSVC dirs during the cmake run which stored the var in the cache:
+ valueToUse = *cacheValue;
+ if (valueToUse.find(envVarValue) == std::string::npos) {
+ valueToUse = envVarValue;
+ mf->AddCacheDefinition(cacheEntryName, valueToUse,
+ cacheEntryName.c_str(), cmStateEnums::STRING,
+ true);
+ mf->GetCMakeInstance()->SaveCache(lg.GetBinaryDirectory());
+ }
+ }
+
+ if (!valueToUse.empty()) {
+ out << envVar << "=" << valueToUse << "|";
+ }
+}
+
+void cmExtraEclipseCDT4Generator::CreateProjectFile()
+{
+ const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0];
+ cmMakefile* mf = lg->GetMakefile();
+
+ const std::string filename = this->HomeOutputDirectory + "/.project";
+
+ cmGeneratedFileStream fout(filename);
+ if (!fout) {
+ return;
+ }
+
+ std::string compilerId = mf->GetSafeDefinition("CMAKE_C_COMPILER_ID");
+ if (compilerId.empty()) // no C compiler, try the C++ compiler:
+ {
+ compilerId = mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID");
+ }
+
+ cmXMLWriter xml(fout);
+
+ xml.StartDocument("UTF-8");
+ xml.StartElement("projectDescription");
+
+ xml.Element("name",
+ cmExtraEclipseCDT4Generator::GenerateProjectName(
+ lg->GetProjectName(),
+ mf->GetSafeDefinition("CMAKE_BUILD_TYPE"),
+ cmExtraEclipseCDT4Generator::GetPathBasename(
+ this->HomeOutputDirectory)));
+
+ xml.Element("comment", "");
+ xml.Element("projects", "");
+
+ xml.StartElement("buildSpec");
+ xml.StartElement("buildCommand");
+ xml.Element("name", "org.eclipse.cdt.make.core.makeBuilder");
+ xml.Element("triggers", "clean,full,incremental,");
+ xml.StartElement("arguments");
+
+ // use clean target
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.cleanBuildTarget", "clean");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.enableCleanBuild", "true");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.append_environment",
+ "true");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.stopOnError", "true");
+
+ // set the make command
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.enabledIncrementalBuild",
+ "true");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.build.command",
+ cmExtraEclipseCDT4Generator::GetEclipsePath(
+ mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM")));
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.contents",
+ "org.eclipse.cdt.make.core.activeConfigSettings");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.build.target.inc", "all");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.build.arguments",
+ mf->GetSafeDefinition("CMAKE_ECLIPSE_MAKE_ARGUMENTS"));
+ AppendDictionary(
+ xml, "org.eclipse.cdt.make.core.buildLocation",
+ cmExtraEclipseCDT4Generator::GetEclipsePath(this->HomeOutputDirectory));
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.useDefaultBuildCmd",
+ "false");
+
+ // set project specific environment
+ std::ostringstream environment;
+ environment << "VERBOSE=1|CMAKE_NO_VERBOSE=1|"; // verbose Makefile output
+ // set vsvars32.bat environment available at CMake time,
+ // but not necessarily when eclipse is open
+ if (compilerId == "MSVC") {
+ AddEnvVar(environment, "PATH", *lg);
+ AddEnvVar(environment, "INCLUDE", *lg);
+ AddEnvVar(environment, "LIB", *lg);
+ AddEnvVar(environment, "LIBPATH", *lg);
+ } else if (compilerId == "Intel") {
+ // if the env.var is set, use this one and put it in the cache
+ // if the env.var is not set, but the value is in the cache,
+ // use it from the cache:
+ AddEnvVar(environment, "INTEL_LICENSE_FILE", *lg);
+ }
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.environment",
+ environment.str());
+
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.enableFullBuild", "true");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.build.target.auto", "all");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.enableAutoBuild", "false");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.build.target.clean",
+ "clean");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.fullBuildTarget", "all");
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.buildArguments", "");
+ AppendDictionary(
+ xml, "org.eclipse.cdt.make.core.build.location",
+ cmExtraEclipseCDT4Generator::GetEclipsePath(this->HomeOutputDirectory));
+ AppendDictionary(xml, "org.eclipse.cdt.make.core.autoBuildTarget", "all");
+
+ // set error parsers
+ std::ostringstream errorOutputParser;
+
+ if (compilerId == "MSVC") {
+ errorOutputParser << "org.eclipse.cdt.core.VCErrorParser;";
+ } else if (compilerId == "Intel") {
+ errorOutputParser << "org.eclipse.cdt.core.ICCErrorParser;";
+ }
+
+ if (this->SupportsGmakeErrorParser) {
+ errorOutputParser << "org.eclipse.cdt.core.GmakeErrorParser;";
+ } else {
+ errorOutputParser << "org.eclipse.cdt.core.MakeErrorParser;";
+ }
+
+ errorOutputParser << "org.eclipse.cdt.core.GCCErrorParser;"
+ "org.eclipse.cdt.core.GASErrorParser;"
+ "org.eclipse.cdt.core.GLDErrorParser;";
+ AppendDictionary(xml, "org.eclipse.cdt.core.errorOutputParser",
+ errorOutputParser.str());
+
+ xml.EndElement(); // arguments
+ xml.EndElement(); // buildCommand
+ xml.StartElement("buildCommand");
+ xml.Element("name", "org.eclipse.cdt.make.core.ScannerConfigBuilder");
+ xml.StartElement("arguments");
+ xml.EndElement(); // arguments
+ xml.EndElement(); // buildCommand
+ xml.EndElement(); // buildSpec
+
+ // set natures for c/c++ projects
+ xml.StartElement("natures");
+ xml.Element("nature", "org.eclipse.cdt.make.core.makeNature");
+ xml.Element("nature", "org.eclipse.cdt.make.core.ScannerConfigNature");
+
+ for (std::string const& n : this->Natures) {
+ xml.Element("nature", n);
+ }
+
+ if (cmProp extraNaturesProp =
+ mf->GetState()->GetGlobalProperty("ECLIPSE_EXTRA_NATURES")) {
+ std::vector<std::string> extraNatures = cmExpandedList(*extraNaturesProp);
+ for (std::string const& n : extraNatures) {
+ xml.Element("nature", n);
+ }
+ }
+
+ xml.EndElement(); // natures
+
+ xml.StartElement("linkedResources");
+ // create linked resources
+ if (this->IsOutOfSourceBuild) {
+ // create a linked resource to CMAKE_SOURCE_DIR
+ // (this is not done anymore for each project because of
+ // https://gitlab.kitware.com/cmake/cmake/-/issues/9978 and because I found
+ // it actually quite confusing in bigger projects with many directories and
+ // projects, Alex
+
+ std::string sourceLinkedResourceName = "[Source directory]";
+ std::string linkSourceDirectory =
+ cmExtraEclipseCDT4Generator::GetEclipsePath(
+ lg->GetCurrentSourceDirectory());
+ // .project dir can't be subdir of a linked resource dir
+ if (!cmSystemTools::IsSubDirectory(this->HomeOutputDirectory,
+ linkSourceDirectory)) {
+ cmExtraEclipseCDT4Generator::AppendLinkedResource(
+ xml, sourceLinkedResourceName,
+ cmExtraEclipseCDT4Generator::GetEclipsePath(linkSourceDirectory),
+ LinkToFolder);
+ this->SrcLinkedResources.push_back(std::move(sourceLinkedResourceName));
+ }
+ }
+
+ if (this->SupportsVirtualFolders) {
+ this->CreateLinksToSubprojects(xml, this->HomeOutputDirectory);
+
+ this->CreateLinksForTargets(xml);
+ }
+
+ xml.EndElement(); // linkedResources
+ xml.EndElement(); // projectDescription
+}
+
+void cmExtraEclipseCDT4Generator::WriteGroups(
+ std::vector<cmSourceGroup> const& sourceGroups, std::string& linkName,
+ cmXMLWriter& xml)
+{
+ for (cmSourceGroup const& sg : sourceGroups) {
+ std::string linkName3 = cmStrCat(linkName, '/', sg.GetFullName());
+
+ std::replace(linkName3.begin(), linkName3.end(), '\\', '/');
+
+ cmExtraEclipseCDT4Generator::AppendLinkedResource(
+ xml, linkName3, "virtual:/virtual", VirtualFolder);
+ std::vector<cmSourceGroup> const& children = sg.GetGroupChildren();
+ if (!children.empty()) {
+ this->WriteGroups(children, linkName, xml);
+ }
+ std::vector<const cmSourceFile*> sFiles = sg.GetSourceFiles();
+ for (cmSourceFile const* file : sFiles) {
+ std::string const& fullPath = file->GetFullPath();
+
+ if (!cmSystemTools::FileIsDirectory(fullPath)) {
+ std::string linkName4 =
+ cmStrCat(linkName3, '/', cmSystemTools::GetFilenameName(fullPath));
+ cmExtraEclipseCDT4Generator::AppendLinkedResource(
+ xml, linkName4,
+ cmExtraEclipseCDT4Generator::GetEclipsePath(fullPath), LinkToFile);
+ }
+ }
+ }
+}
+
+void cmExtraEclipseCDT4Generator::CreateLinksForTargets(cmXMLWriter& xml)
+{
+ std::string linkName = "[Targets]";
+ cmExtraEclipseCDT4Generator::AppendLinkedResource(
+ xml, linkName, "virtual:/virtual", VirtualFolder);
+
+ for (const auto& lg : this->GlobalGenerator->GetLocalGenerators()) {
+ cmMakefile* makefile = lg->GetMakefile();
+ const auto& targets = lg->GetGeneratorTargets();
+
+ for (const auto& target : targets) {
+ std::string linkName2 = cmStrCat(linkName, '/');
+ switch (target->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::OBJECT_LIBRARY: {
+ const char* prefix =
+ (target->GetType() == cmStateEnums::EXECUTABLE ? "[exe] "
+ : "[lib] ");
+ linkName2 += prefix;
+ linkName2 += target->GetName();
+ cmExtraEclipseCDT4Generator::AppendLinkedResource(
+ xml, linkName2, "virtual:/virtual", VirtualFolder);
+ if (!this->GenerateLinkedResources) {
+ break; // skip generating the linked resources to the source files
+ }
+ std::vector<cmSourceGroup> sourceGroups =
+ makefile->GetSourceGroups();
+ // get the files from the source lists then add them to the groups
+ std::vector<cmSourceFile*> files;
+ target->GetSourceFiles(
+ files, makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ for (cmSourceFile* sf : files) {
+ // Add the file to the list of sources.
+ std::string const& source = sf->ResolveFullPath();
+ cmSourceGroup* sourceGroup =
+ makefile->FindSourceGroup(source, sourceGroups);
+ sourceGroup->AssignSource(sf);
+ }
+
+ this->WriteGroups(sourceGroups, linkName2, xml);
+ } break;
+ // ignore all others:
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void cmExtraEclipseCDT4Generator::CreateLinksToSubprojects(
+ cmXMLWriter& xml, const std::string& baseDir)
+{
+ if (!this->GenerateLinkedResources) {
+ return;
+ }
+
+ // for each sub project create a linked resource to the source dir
+ // - only if it is an out-of-source build
+ cmExtraEclipseCDT4Generator::AppendLinkedResource(
+ xml, "[Subprojects]", "virtual:/virtual", VirtualFolder);
+
+ for (auto const& it : this->GlobalGenerator->GetProjectMap()) {
+ std::string linkSourceDirectory =
+ cmExtraEclipseCDT4Generator::GetEclipsePath(
+ it.second[0]->GetCurrentSourceDirectory());
+ // a linked resource must not point to a parent directory of .project or
+ // .project itself
+ if ((baseDir != linkSourceDirectory) &&
+ !cmSystemTools::IsSubDirectory(baseDir, linkSourceDirectory)) {
+ std::string linkName = cmStrCat("[Subprojects]/", it.first);
+ cmExtraEclipseCDT4Generator::AppendLinkedResource(
+ xml, linkName,
+ cmExtraEclipseCDT4Generator::GetEclipsePath(linkSourceDirectory),
+ LinkToFolder);
+ // Don't add it to the srcLinkedResources, because listing multiple
+ // directories confuses the Eclipse indexer (#13596).
+ }
+ }
+}
+
+void cmExtraEclipseCDT4Generator::AppendIncludeDirectories(
+ cmXMLWriter& xml, const std::vector<std::string>& includeDirs,
+ std::set<std::string>& emittedDirs)
+{
+ for (std::string const& inc : includeDirs) {
+ if (!inc.empty()) {
+ std::string dir = cmSystemTools::CollapseFullPath(inc);
+
+ // handle framework include dirs on OSX, the remainder after the
+ // Frameworks/ part has to be stripped
+ // /System/Library/Frameworks/GLUT.framework/Headers
+ cmsys::RegularExpression frameworkRx("(.+/Frameworks)/.+\\.framework/");
+ if (frameworkRx.find(dir)) {
+ dir = frameworkRx.match(1);
+ }
+
+ if (emittedDirs.find(dir) == emittedDirs.end()) {
+ emittedDirs.insert(dir);
+ xml.StartElement("pathentry");
+ xml.Attribute("include",
+ cmExtraEclipseCDT4Generator::GetEclipsePath(dir));
+ xml.Attribute("kind", "inc");
+ xml.Attribute("path", "");
+ xml.Attribute("system", "true");
+ xml.EndElement();
+ }
+ }
+ }
+}
+
+void cmExtraEclipseCDT4Generator::CreateCProjectFile() const
+{
+ std::set<std::string> emitted;
+
+ const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0];
+ const cmMakefile* mf = lg->GetMakefile();
+
+ const std::string filename = this->HomeOutputDirectory + "/.cproject";
+
+ cmGeneratedFileStream fout(filename);
+ if (!fout) {
+ return;
+ }
+
+ cmXMLWriter xml(fout);
+
+ // add header
+ xml.StartDocument("UTF-8");
+ xml.ProcessingInstruction("fileVersion", "4.0.0");
+ xml.StartElement("cproject");
+ xml.StartElement("storageModule");
+ xml.Attribute("moduleId", "org.eclipse.cdt.core.settings");
+
+ xml.StartElement("cconfiguration");
+ xml.Attribute("id", "org.eclipse.cdt.core.default.config.1");
+
+ // Configuration settings...
+ xml.StartElement("storageModule");
+ xml.Attribute("buildSystemId",
+ "org.eclipse.cdt.core.defaultConfigDataProvider");
+ xml.Attribute("id", "org.eclipse.cdt.core.default.config.1");
+ xml.Attribute("moduleId", "org.eclipse.cdt.core.settings");
+ xml.Attribute("name", "Configuration");
+ xml.Element("externalSettings");
+ xml.StartElement("extensions");
+
+ // TODO: refactor this out...
+ std::string executableFormat =
+ mf->GetSafeDefinition("CMAKE_EXECUTABLE_FORMAT");
+ if (executableFormat == "ELF") {
+ xml.StartElement("extension");
+ xml.Attribute("id", "org.eclipse.cdt.core.ELF");
+ xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
+ xml.EndElement(); // extension
+
+ xml.StartElement("extension");
+ xml.Attribute("id", "org.eclipse.cdt.core.GNU_ELF");
+ xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
+ AppendAttribute(xml, "addr2line");
+ AppendAttribute(xml, "c++filt");
+ xml.EndElement(); // extension
+ } else {
+ std::string systemName = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME");
+ if (systemName == "CYGWIN") {
+ xml.StartElement("extension");
+ xml.Attribute("id", "org.eclipse.cdt.core.Cygwin_PE");
+ xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
+ AppendAttribute(xml, "addr2line");
+ AppendAttribute(xml, "c++filt");
+ AppendAttribute(xml, "cygpath");
+ AppendAttribute(xml, "nm");
+ xml.EndElement(); // extension
+ } else if (systemName == "Windows") {
+ xml.StartElement("extension");
+ xml.Attribute("id", "org.eclipse.cdt.core.PE");
+ xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
+ xml.EndElement(); // extension
+ } else if (systemName == "Darwin") {
+ xml.StartElement("extension");
+ xml.Attribute("id",
+ this->SupportsMachO64Parser
+ ? "org.eclipse.cdt.core.MachO64"
+ : "org.eclipse.cdt.core.MachO");
+ xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
+ AppendAttribute(xml, "c++filt");
+ xml.EndElement(); // extension
+ } else {
+ // *** Should never get here ***
+ xml.Element("error_toolchain_type");
+ }
+ }
+
+ xml.EndElement(); // extensions
+ xml.EndElement(); // storageModule
+
+ // ???
+ xml.StartElement("storageModule");
+ xml.Attribute("moduleId", "org.eclipse.cdt.core.language.mapping");
+ xml.Element("project-mappings");
+ xml.EndElement(); // storageModule
+
+ // ???
+ xml.StartElement("storageModule");
+ xml.Attribute("moduleId", "org.eclipse.cdt.core.externalSettings");
+ xml.EndElement(); // storageModule
+
+ // set the path entries (includes, libs, source dirs, etc.)
+ xml.StartElement("storageModule");
+ xml.Attribute("moduleId", "org.eclipse.cdt.core.pathentry");
+
+ // for each sub project with a linked resource to the source dir:
+ // - make it type 'src'
+ // - and exclude it from type 'out'
+ std::string excludeFromOut;
+ /* I don't know what the pathentry kind="src" are good for, e.g.
+ * autocompletion
+ * works also without them. Done wrong, the indexer complains, see #12417
+ * and #12213.
+ * According to #13596, this entry at least limits the directories the
+ * indexer is searching for files. So now the "src" entry contains only
+ * the linked resource to CMAKE_SOURCE_DIR.
+ * The CDT documentation is very terse on that:
+ * "CDT_SOURCE: Entry kind constant describing a path entry identifying a
+ * folder containing source code to be compiled."
+ * Also on the cdt-dev list didn't bring any information:
+ * http://web.archiveorange.com/archive/v/B4NlJDNIpYoOS1SbxFNy
+ * Alex */
+ // include subprojects directory to the src pathentry
+ // eclipse cdt indexer uses this entries as reference to index source files
+ if (this->GenerateLinkedResources) {
+ xml.StartElement("pathentry");
+ xml.Attribute("kind", "src");
+ xml.Attribute("path", "[Subprojects]");
+ xml.EndElement();
+ }
+
+ for (std::string const& p : this->SrcLinkedResources) {
+ xml.StartElement("pathentry");
+ xml.Attribute("kind", "src");
+ xml.Attribute("path", p);
+ xml.EndElement();
+
+ // exclude source directory from output search path
+ // - only if not named the same as an output directory
+ if (!cmSystemTools::FileIsDirectory(
+ std::string(this->HomeOutputDirectory + "/" + p))) {
+ excludeFromOut += p + "/|";
+ }
+ }
+
+ excludeFromOut += "**/CMakeFiles/";
+
+ xml.StartElement("pathentry");
+ xml.Attribute("excluding", excludeFromOut);
+ xml.Attribute("kind", "out");
+ xml.Attribute("path", "");
+ xml.EndElement();
+
+ // add pre-processor definitions to allow eclipse to gray out sections
+ emitted.clear();
+ for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) {
+
+ if (cmProp cdefs =
+ lgen->GetMakefile()->GetProperty("COMPILE_DEFINITIONS")) {
+ // Expand the list.
+ std::vector<std::string> defs;
+ cmGeneratorExpression::Split(*cdefs, defs);
+
+ for (std::string const& d : defs) {
+ if (cmGeneratorExpression::Find(d) != std::string::npos) {
+ continue;
+ }
+
+ std::string::size_type equals = d.find('=', 0);
+ std::string::size_type enddef = d.length();
+
+ std::string def;
+ std::string val;
+ if (equals != std::string::npos && equals < enddef) {
+ // we have -DFOO=BAR
+ def = d.substr(0, equals);
+ val = d.substr(equals + 1, enddef - equals + 1);
+ } else {
+ // we have -DFOO
+ def = d;
+ }
+
+ // insert the definition if not already added.
+ if (emitted.find(def) == emitted.end()) {
+ emitted.insert(def);
+ xml.StartElement("pathentry");
+ xml.Attribute("kind", "mac");
+ xml.Attribute("name", def);
+ xml.Attribute("path", "");
+ xml.Attribute("value", val);
+ xml.EndElement();
+ }
+ }
+ }
+ }
+ // add system defined c macros
+ cmProp cDefs =
+ mf->GetDefinition("CMAKE_EXTRA_GENERATOR_C_SYSTEM_DEFINED_MACROS");
+ if (this->CEnabled && cDefs) {
+ // Expand the list.
+ std::vector<std::string> defs = cmExpandedList(*cDefs, true);
+
+ // the list must contain only definition-value pairs:
+ if ((defs.size() % 2) == 0) {
+ auto di = defs.begin();
+ while (di != defs.end()) {
+ std::string def = *di;
+ ++di;
+ std::string val;
+ if (di != defs.end()) {
+ val = *di;
+ ++di;
+ }
+
+ // insert the definition if not already added.
+ if (emitted.find(def) == emitted.end()) {
+ emitted.insert(def);
+ xml.StartElement("pathentry");
+ xml.Attribute("kind", "mac");
+ xml.Attribute("name", def);
+ xml.Attribute("path", "");
+ xml.Attribute("value", val);
+ xml.EndElement();
+ }
+ }
+ }
+ }
+ // add system defined c++ macros
+ cmProp cxxDefs =
+ mf->GetDefinition("CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_DEFINED_MACROS");
+ if (this->CXXEnabled && cxxDefs) {
+ // Expand the list.
+ std::vector<std::string> defs = cmExpandedList(*cxxDefs, true);
+
+ // the list must contain only definition-value pairs:
+ if ((defs.size() % 2) == 0) {
+ auto di = defs.begin();
+ while (di != defs.end()) {
+ std::string def = *di;
+ ++di;
+ std::string val;
+ if (di != defs.end()) {
+ val = *di;
+ ++di;
+ }
+
+ // insert the definition if not already added.
+ if (emitted.find(def) == emitted.end()) {
+ emitted.insert(def);
+ xml.StartElement("pathentry");
+ xml.Attribute("kind", "mac");
+ xml.Attribute("name", def);
+ xml.Attribute("path", "");
+ xml.Attribute("value", val);
+ xml.EndElement();
+ }
+ }
+ }
+ }
+
+ // include dirs
+ emitted.clear();
+ for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) {
+ const auto& targets = lgen->GetGeneratorTargets();
+ for (const auto& target : targets) {
+ if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ continue;
+ }
+ std::vector<std::string> includeDirs;
+ std::string config = mf->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ lgen->GetIncludeDirectories(includeDirs, target.get(), "C", config);
+ this->AppendIncludeDirectories(xml, includeDirs, emitted);
+ }
+ }
+ // now also the system include directories, in case we found them in
+ // CMakeSystemSpecificInformation.cmake. This makes Eclipse find the
+ // standard headers.
+ std::string compiler = mf->GetSafeDefinition("CMAKE_C_COMPILER");
+ if (this->CEnabled && !compiler.empty()) {
+ std::string systemIncludeDirs =
+ mf->GetSafeDefinition("CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
+ std::vector<std::string> dirs = cmExpandedList(systemIncludeDirs);
+ this->AppendIncludeDirectories(xml, dirs, emitted);
+ }
+ compiler = mf->GetSafeDefinition("CMAKE_CXX_COMPILER");
+ if (this->CXXEnabled && !compiler.empty()) {
+ std::string systemIncludeDirs =
+ mf->GetSafeDefinition("CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
+ std::vector<std::string> dirs = cmExpandedList(systemIncludeDirs);
+ this->AppendIncludeDirectories(xml, dirs, emitted);
+ }
+
+ xml.EndElement(); // storageModule
+
+ // add build targets
+ xml.StartElement("storageModule");
+ xml.Attribute("moduleId", "org.eclipse.cdt.make.core.buildtargets");
+ xml.StartElement("buildTargets");
+ emitted.clear();
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& makeArgs =
+ mf->GetSafeDefinition("CMAKE_ECLIPSE_MAKE_ARGUMENTS");
+
+ cmGlobalGenerator* generator =
+ const_cast<cmGlobalGenerator*>(this->GlobalGenerator);
+
+ std::string allTarget;
+ std::string cleanTarget;
+ if (generator->GetAllTargetName()) {
+ allTarget = generator->GetAllTargetName();
+ }
+ if (generator->GetCleanTargetName()) {
+ cleanTarget = generator->GetCleanTargetName();
+ }
+
+ // add all executable and library targets and some of the GLOBAL
+ // and UTILITY targets
+ for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) {
+ const auto& targets = lgen->GetGeneratorTargets();
+ std::string subdir = lgen->MaybeConvertToRelativePath(
+ this->HomeOutputDirectory, lgen->GetCurrentBinaryDirectory());
+ if (subdir == ".") {
+ subdir.clear();
+ }
+
+ for (const auto& target : targets) {
+ std::string targetName = target->GetName();
+ switch (target->GetType()) {
+ case cmStateEnums::GLOBAL_TARGET: {
+ // Only add the global targets from CMAKE_BINARY_DIR,
+ // not from the subdirs
+ if (subdir.empty()) {
+ cmExtraEclipseCDT4Generator::AppendTarget(xml, targetName, make,
+ makeArgs, subdir, ": ");
+ }
+ } break;
+ case cmStateEnums::UTILITY:
+ // Add all utility targets, except the Nightly/Continuous/
+ // Experimental-"sub"targets as e.g. NightlyStart
+ if ((cmHasLiteralPrefix(targetName, "Nightly") &&
+ (targetName != "Nightly")) ||
+ (cmHasLiteralPrefix(targetName, "Continuous") &&
+ (targetName != "Continuous")) ||
+ (cmHasLiteralPrefix(targetName, "Experimental") &&
+ (targetName != "Experimental"))) {
+ break;
+ }
+
+ cmExtraEclipseCDT4Generator::AppendTarget(xml, targetName, make,
+ makeArgs, subdir, ": ");
+ break;
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::OBJECT_LIBRARY: {
+ const char* prefix =
+ (target->GetType() == cmStateEnums::EXECUTABLE ? "[exe] "
+ : "[lib] ");
+ cmExtraEclipseCDT4Generator::AppendTarget(xml, targetName, make,
+ makeArgs, subdir, prefix);
+ std::string fastTarget = cmStrCat(targetName, "/fast");
+ cmExtraEclipseCDT4Generator::AppendTarget(xml, fastTarget, make,
+ makeArgs, subdir, prefix);
+
+ // Add Build and Clean targets in the virtual folder of targets:
+ if (this->SupportsVirtualFolders) {
+ std::string virtDir = cmStrCat("[Targets]/", prefix, targetName);
+ std::string buildArgs =
+ cmStrCat("-C \"", lgen->GetBinaryDirectory(), "\" ", makeArgs);
+ cmExtraEclipseCDT4Generator::AppendTarget(
+ xml, "Build", make, buildArgs, virtDir, "", targetName.c_str());
+
+ std::string cleanArgs =
+ cmStrCat("-E chdir \"", lgen->GetCurrentBinaryDirectory(),
+ "\" \"", cmSystemTools::GetCMakeCommand(), "\" -P \"");
+ cleanArgs += lgen->GetTargetDirectory(target.get());
+ cleanArgs += "/cmake_clean.cmake\"";
+ cmExtraEclipseCDT4Generator::AppendTarget(
+ xml, "Clean", cmSystemTools::GetCMakeCommand(), cleanArgs,
+ virtDir, "", "");
+ }
+ } break;
+ case cmStateEnums::INTERFACE_LIBRARY:
+ default:
+ break;
+ }
+ }
+
+ // insert the all and clean targets in every subdir
+ if (!allTarget.empty()) {
+ cmExtraEclipseCDT4Generator::AppendTarget(xml, allTarget, make, makeArgs,
+ subdir, ": ");
+ }
+ if (!cleanTarget.empty()) {
+ cmExtraEclipseCDT4Generator::AppendTarget(xml, cleanTarget, make,
+ makeArgs, subdir, ": ");
+ }
+
+ // insert rules for compiling, preprocessing and assembling individual
+ // files
+ std::vector<std::string> objectFileTargets;
+ lg->GetIndividualFileTargets(objectFileTargets);
+ for (std::string const& f : objectFileTargets) {
+ const char* prefix = "[obj] ";
+ if (f.back() == 's') {
+ prefix = "[to asm] ";
+ } else if (f.back() == 'i') {
+ prefix = "[pre] ";
+ }
+ cmExtraEclipseCDT4Generator::AppendTarget(xml, f, make, makeArgs, subdir,
+ prefix);
+ }
+ }
+
+ xml.EndElement(); // buildTargets
+ xml.EndElement(); // storageModule
+
+ cmExtraEclipseCDT4Generator::AppendStorageScanners(xml, *mf);
+
+ xml.EndElement(); // cconfiguration
+ xml.EndElement(); // storageModule
+
+ xml.StartElement("storageModule");
+ xml.Attribute("moduleId", "cdtBuildSystem");
+ xml.Attribute("version", "4.0.0");
+
+ xml.StartElement("project");
+ xml.Attribute("id", std::string(lg->GetProjectName()) + ".null.1");
+ xml.Attribute("name", lg->GetProjectName());
+ xml.EndElement(); // project
+
+ xml.EndElement(); // storageModule
+
+ // Append additional cproject contents without applying any XML formatting
+ if (cmProp extraCProjectContents =
+ mf->GetState()->GetGlobalProperty("ECLIPSE_EXTRA_CPROJECT_CONTENTS")) {
+ fout << *extraCProjectContents;
+ }
+
+ xml.EndElement(); // cproject
+}
+
+std::string cmExtraEclipseCDT4Generator::GetEclipsePath(
+ const std::string& path)
+{
+#if defined(__CYGWIN__)
+ std::string cmd = "cygpath -m " + path;
+ std::string out;
+ if (!cmSystemTools::RunSingleCommand(cmd.c_str(), &out, &out)) {
+ return path;
+ } else {
+ out.erase(out.find_last_of('\n'));
+ return out;
+ }
+#else
+ return path;
+#endif
+}
+
+std::string cmExtraEclipseCDT4Generator::GetPathBasename(
+ const std::string& path)
+{
+ std::string outputBasename = path;
+ while (!outputBasename.empty() &&
+ (outputBasename.back() == '/' || outputBasename.back() == '\\')) {
+ outputBasename.resize(outputBasename.size() - 1);
+ }
+ std::string::size_type loc = outputBasename.find_last_of("/\\");
+ if (loc != std::string::npos) {
+ outputBasename = outputBasename.substr(loc + 1);
+ }
+
+ return outputBasename;
+}
+
+std::string cmExtraEclipseCDT4Generator::GenerateProjectName(
+ const std::string& name, const std::string& type, const std::string& path)
+{
+ return name + (type.empty() ? "" : "-") + type + "@" + path;
+}
+
+// Helper functions
+void cmExtraEclipseCDT4Generator::AppendStorageScanners(
+ cmXMLWriter& xml, const cmMakefile& makefile)
+{
+ // we need the "make" and the C (or C++) compiler which are used, Alex
+ const std::string& make =
+ makefile.GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ std::string compiler = makefile.GetSafeDefinition("CMAKE_C_COMPILER");
+ std::string arg1 = makefile.GetSafeDefinition("CMAKE_C_COMPILER_ARG1");
+ if (compiler.empty()) {
+ compiler = makefile.GetSafeDefinition("CMAKE_CXX_COMPILER");
+ arg1 = makefile.GetSafeDefinition("CMAKE_CXX_COMPILER_ARG1");
+ }
+ if (compiler.empty()) // Hmm, what to do now ?
+ {
+ compiler = "gcc";
+ }
+
+ // the following right now hardcodes gcc behaviour :-/
+ std::string compilerArgs =
+ "-E -P -v -dD ${plugin_state_location}/${specs_file}";
+ if (!arg1.empty()) {
+ arg1 += " ";
+ compilerArgs = arg1 + compilerArgs;
+ }
+
+ xml.StartElement("storageModule");
+ xml.Attribute("moduleId", "scannerConfiguration");
+
+ xml.StartElement("autodiscovery");
+ xml.Attribute("enabled", "true");
+ xml.Attribute("problemReportingEnabled", "true");
+ xml.Attribute("selectedProfileId",
+ "org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile");
+ xml.EndElement(); // autodiscovery
+
+ cmExtraEclipseCDT4Generator::AppendScannerProfile(
+ xml, "org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile", true,
+ "", true, "specsFile", compilerArgs, compiler, true, true);
+ cmExtraEclipseCDT4Generator::AppendScannerProfile(
+ xml, "org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile", true, "",
+ true, "makefileGenerator", "-f ${project_name}_scd.mk", make, true, true);
+
+ xml.EndElement(); // storageModule
+}
+
+// The prefix is prepended before the actual name of the target. The purpose
+// of that is to sort the targets in the view of Eclipse, so that at first
+// the global/utility/all/clean targets appear ": ", then the executable
+// targets "[exe] ", then the libraries "[lib]", then the rules for the
+// object files "[obj]", then for preprocessing only "[pre] " and
+// finally the assembly files "[to asm] ". Note the "to" in "to asm",
+// without it, "asm" would be the first targets in the list, with the "to"
+// they are the last targets, which makes more sense.
+void cmExtraEclipseCDT4Generator::AppendTarget(
+ cmXMLWriter& xml, const std::string& target, const std::string& make,
+ const std::string& makeArgs, const std::string& path, const char* prefix,
+ const char* makeTarget)
+{
+ xml.StartElement("target");
+ xml.Attribute("name", prefix + target);
+ xml.Attribute("path", path);
+ xml.Attribute("targetID", "org.eclipse.cdt.make.MakeTargetBuilder");
+ xml.Element("buildCommand",
+ cmExtraEclipseCDT4Generator::GetEclipsePath(make));
+ xml.Element("buildArguments", makeArgs);
+ xml.Element("buildTarget", makeTarget ? makeTarget : target.c_str());
+ xml.Element("stopOnError", "true");
+ xml.Element("useDefaultCommand", "false");
+ xml.EndElement();
+}
+
+void cmExtraEclipseCDT4Generator::AppendScannerProfile(
+ cmXMLWriter& xml, const std::string& profileID, bool openActionEnabled,
+ const std::string& openActionFilePath, bool pParserEnabled,
+ const std::string& scannerInfoProviderID,
+ const std::string& runActionArguments, const std::string& runActionCommand,
+ bool runActionUseDefault, bool sipParserEnabled)
+{
+ xml.StartElement("profile");
+ xml.Attribute("id", profileID);
+
+ xml.StartElement("buildOutputProvider");
+ xml.StartElement("openAction");
+ xml.Attribute("enabled", openActionEnabled ? "true" : "false");
+ xml.Attribute("filePath", openActionFilePath);
+ xml.EndElement(); // openAction
+ xml.StartElement("parser");
+ xml.Attribute("enabled", pParserEnabled ? "true" : "false");
+ xml.EndElement(); // parser
+ xml.EndElement(); // buildOutputProvider
+
+ xml.StartElement("scannerInfoProvider");
+ xml.Attribute("id", scannerInfoProviderID);
+ xml.StartElement("runAction");
+ xml.Attribute("arguments", runActionArguments);
+ xml.Attribute("command", runActionCommand);
+ xml.Attribute("useDefault", runActionUseDefault ? "true" : "false");
+ xml.EndElement(); // runAction
+ xml.StartElement("parser");
+ xml.Attribute("enabled", sipParserEnabled ? "true" : "false");
+ xml.EndElement(); // parser
+ xml.EndElement(); // scannerInfoProvider
+
+ xml.EndElement(); // profile
+}
+
+void cmExtraEclipseCDT4Generator::AppendLinkedResource(cmXMLWriter& xml,
+ const std::string& name,
+ const std::string& path,
+ LinkType linkType)
+{
+ const char* locationTag = "location";
+ int typeTag = 2;
+ if (linkType == VirtualFolder) // ... and not a linked folder
+ {
+ locationTag = "locationURI";
+ }
+ if (linkType == LinkToFile) {
+ typeTag = 1;
+ }
+
+ xml.StartElement("link");
+ xml.Element("name", name);
+ xml.Element("type", typeTag);
+ xml.Element(locationTag, path);
+ xml.EndElement();
+}
diff --git a/Source/cmExtraEclipseCDT4Generator.h b/Source/cmExtraEclipseCDT4Generator.h
new file mode 100644
index 0000000..c4ed577
--- /dev/null
+++ b/Source/cmExtraEclipseCDT4Generator.h
@@ -0,0 +1,107 @@
+/* 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 <iosfwd>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmExternalMakefileProjectGenerator.h"
+
+class cmLocalGenerator;
+class cmMakefile;
+class cmSourceGroup;
+class cmXMLWriter;
+
+/** \class cmExtraEclipseCDT4Generator
+ * \brief Write Eclipse project files for Makefile based projects
+ */
+class cmExtraEclipseCDT4Generator : public cmExternalMakefileProjectGenerator
+{
+public:
+ enum LinkType
+ {
+ VirtualFolder,
+ LinkToFolder,
+ LinkToFile
+ };
+
+ cmExtraEclipseCDT4Generator();
+
+ static cmExternalMakefileProjectGeneratorFactory* GetFactory();
+
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) override;
+
+ void Generate() override;
+
+private:
+ // create .project file in the source tree
+ void CreateSourceProjectFile();
+
+ // create .settings/org.eclipse.core.resources.prefs
+ void CreateSettingsResourcePrefsFile();
+
+ // create .project file
+ void CreateProjectFile();
+
+ // create .cproject file
+ void CreateCProjectFile() const;
+
+ // If built with cygwin cmake, convert posix to windows path.
+ static std::string GetEclipsePath(const std::string& path);
+
+ // Extract basename.
+ static std::string GetPathBasename(const std::string& path);
+
+ // Generate the project name as: <name>-<type>@<path>
+ static std::string GenerateProjectName(const std::string& name,
+ const std::string& type,
+ const std::string& path);
+
+ // Helper functions
+ static void AppendStorageScanners(cmXMLWriter& xml,
+ const cmMakefile& makefile);
+ static void AppendTarget(cmXMLWriter& xml, const std::string& target,
+ const std::string& make,
+ const std::string& makeArguments,
+ const std::string& path, const char* prefix = "",
+ const char* makeTarget = nullptr);
+ static void AppendScannerProfile(
+ cmXMLWriter& xml, const std::string& profileID, bool openActionEnabled,
+ const std::string& openActionFilePath, bool pParserEnabled,
+ const std::string& scannerInfoProviderID,
+ const std::string& runActionArguments, const std::string& runActionCommand,
+ bool runActionUseDefault, bool sipParserEnabled);
+
+ static void AppendLinkedResource(cmXMLWriter& xml, const std::string& name,
+ const std::string& path, LinkType linkType);
+
+ static void AppendIncludeDirectories(
+ cmXMLWriter& xml, const std::vector<std::string>& includeDirs,
+ std::set<std::string>& emittedDirs);
+
+ static void AddEnvVar(std::ostream& out, const char* envVar,
+ cmLocalGenerator& lg);
+
+ void WriteGroups(std::vector<cmSourceGroup> const& sourceGroups,
+ std::string& linkName, cmXMLWriter& xml);
+ void CreateLinksToSubprojects(cmXMLWriter& xml, const std::string& baseDir);
+ void CreateLinksForTargets(cmXMLWriter& xml);
+
+ std::vector<std::string> SrcLinkedResources;
+ std::set<std::string> Natures;
+ std::string HomeDirectory;
+ std::string HomeOutputDirectory;
+ bool IsOutOfSourceBuild;
+ bool GenerateSourceProject;
+ bool GenerateLinkedResources;
+ bool SupportsVirtualFolders;
+ bool SupportsGmakeErrorParser;
+ bool SupportsMachO64Parser;
+ bool CEnabled;
+ bool CXXEnabled;
+};
diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx
new file mode 100644
index 0000000..54c3114
--- /dev/null
+++ b/Source/cmExtraKateGenerator.cxx
@@ -0,0 +1,294 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExtraKateGenerator.h"
+
+#include <cstring>
+#include <memory>
+#include <ostream>
+#include <set>
+#include <vector>
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmSourceFile.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmExtraKateGenerator::cmExtraKateGenerator() = default;
+
+cmExternalMakefileProjectGeneratorFactory* cmExtraKateGenerator::GetFactory()
+{
+ static cmExternalMakefileProjectGeneratorSimpleFactory<cmExtraKateGenerator>
+ factory("Kate", "Generates Kate project files.");
+
+ if (factory.GetSupportedGlobalGenerators().empty()) {
+#if defined(_WIN32)
+ factory.AddSupportedGlobalGenerator("MinGW Makefiles");
+ factory.AddSupportedGlobalGenerator("NMake Makefiles");
+// disable until somebody actually tests it:
+// factory.AddSupportedGlobalGenerator("MSYS Makefiles");
+#endif
+ factory.AddSupportedGlobalGenerator("Ninja");
+ factory.AddSupportedGlobalGenerator("Unix Makefiles");
+ }
+
+ return &factory;
+}
+
+void cmExtraKateGenerator::Generate()
+{
+ const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0];
+ const cmMakefile* mf = lg->GetMakefile();
+ this->ProjectName = this->GenerateProjectName(
+ lg->GetProjectName(), mf->GetSafeDefinition("CMAKE_BUILD_TYPE"),
+ this->GetPathBasename(lg->GetBinaryDirectory()));
+ this->UseNinja = (this->GlobalGenerator->GetName() == "Ninja");
+
+ this->CreateKateProjectFile(*lg);
+ this->CreateDummyKateProjectFile(*lg);
+}
+
+void cmExtraKateGenerator::CreateKateProjectFile(
+ const cmLocalGenerator& lg) const
+{
+ std::string filename = cmStrCat(lg.GetBinaryDirectory(), "/.kateproject");
+ cmGeneratedFileStream fout(filename);
+ if (!fout) {
+ return;
+ }
+
+ /* clang-format off */
+ fout <<
+ "{\n"
+ "\t\"name\": \"" << this->ProjectName << "\",\n"
+ "\t\"directory\": \"" << lg.GetSourceDirectory() << "\",\n"
+ "\t\"files\": [ { " << this->GenerateFilesString(lg) << "} ],\n";
+ /* clang-format on */
+ this->WriteTargets(lg, fout);
+ fout << "}\n";
+}
+
+void cmExtraKateGenerator::WriteTargets(const cmLocalGenerator& lg,
+ cmGeneratedFileStream& fout) const
+{
+ cmMakefile const* mf = lg.GetMakefile();
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& makeArgs =
+ mf->GetSafeDefinition("CMAKE_KATE_MAKE_ARGUMENTS");
+ std::string const& homeOutputDir = lg.GetBinaryDirectory();
+
+ /* clang-format off */
+ fout <<
+ "\t\"build\": {\n"
+ "\t\t\"directory\": \"" << homeOutputDir << "\",\n"
+ "\t\t\"default_target\": \"all\",\n"
+ "\t\t\"clean_target\": \"clean\",\n";
+ /* clang-format on */
+
+ // build, clean and quick are for the build plugin kate <= 4.12:
+ fout << "\t\t\"build\": \"" << make << " -C \\\"" << homeOutputDir << "\\\" "
+ << makeArgs << " "
+ << "all\",\n";
+ fout << "\t\t\"clean\": \"" << make << " -C \\\"" << homeOutputDir << "\\\" "
+ << makeArgs << " "
+ << "clean\",\n";
+ fout << "\t\t\"quick\": \"" << make << " -C \\\"" << homeOutputDir << "\\\" "
+ << makeArgs << " "
+ << "install\",\n";
+
+ // this is for kate >= 4.13:
+ fout << "\t\t\"targets\":[\n";
+
+ this->AppendTarget(fout, "all", make, makeArgs, homeOutputDir,
+ homeOutputDir);
+ this->AppendTarget(fout, "clean", make, makeArgs, homeOutputDir,
+ homeOutputDir);
+
+ // add all executable and library targets and some of the GLOBAL
+ // and UTILITY targets
+ for (const auto& localGen : this->GlobalGenerator->GetLocalGenerators()) {
+ const auto& targets = localGen->GetGeneratorTargets();
+ std::string currentDir = localGen->GetCurrentBinaryDirectory();
+ bool topLevel = (currentDir == localGen->GetBinaryDirectory());
+
+ for (const auto& target : targets) {
+ std::string const& targetName = target->GetName();
+ switch (target->GetType()) {
+ case cmStateEnums::GLOBAL_TARGET: {
+ bool insertTarget = false;
+ // Only add the global targets from CMAKE_BINARY_DIR,
+ // not from the subdirs
+ if (topLevel) {
+ insertTarget = true;
+ // only add the "edit_cache" target if it's not ccmake, because
+ // this will not work within the IDE
+ if (targetName == "edit_cache") {
+ cmProp editCommand =
+ localGen->GetMakefile()->GetDefinition("CMAKE_EDIT_COMMAND");
+ if (editCommand == nullptr ||
+ strstr(editCommand->c_str(), "ccmake") != nullptr) {
+ insertTarget = false;
+ }
+ }
+ }
+ if (insertTarget) {
+ this->AppendTarget(fout, targetName, make, makeArgs, currentDir,
+ homeOutputDir);
+ }
+ } break;
+ case cmStateEnums::UTILITY:
+ // Add all utility targets, except the Nightly/Continuous/
+ // Experimental-"sub"targets as e.g. NightlyStart
+ if ((cmHasLiteralPrefix(targetName, "Nightly") &&
+ (targetName != "Nightly")) ||
+ (cmHasLiteralPrefix(targetName, "Continuous") &&
+ (targetName != "Continuous")) ||
+ (cmHasLiteralPrefix(targetName, "Experimental") &&
+ (targetName != "Experimental"))) {
+ break;
+ }
+
+ this->AppendTarget(fout, targetName, make, makeArgs, currentDir,
+ homeOutputDir);
+ break;
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::OBJECT_LIBRARY: {
+ this->AppendTarget(fout, targetName, make, makeArgs, currentDir,
+ homeOutputDir);
+ std::string fastTarget = cmStrCat(targetName, "/fast");
+ this->AppendTarget(fout, fastTarget, make, makeArgs, currentDir,
+ homeOutputDir);
+
+ } break;
+ default:
+ break;
+ }
+ }
+
+ // insert rules for compiling, preprocessing and assembling individual
+ // files
+ std::vector<std::string> objectFileTargets;
+ localGen->GetIndividualFileTargets(objectFileTargets);
+ for (std::string const& f : objectFileTargets) {
+ this->AppendTarget(fout, f, make, makeArgs, currentDir, homeOutputDir);
+ }
+ }
+
+ fout << "\t] }\n";
+}
+
+void cmExtraKateGenerator::AppendTarget(cmGeneratedFileStream& fout,
+ const std::string& target,
+ const std::string& make,
+ const std::string& makeArgs,
+ const std::string& path,
+ const std::string& homeOutputDir) const
+{
+ static char JsonSep = ' ';
+
+ fout << "\t\t\t" << JsonSep << R"({"name":")" << target
+ << "\", "
+ "\"build_cmd\":\""
+ << make << " -C \\\"" << (this->UseNinja ? homeOutputDir : path)
+ << "\\\" " << makeArgs << " " << target << "\"}\n";
+
+ JsonSep = ',';
+}
+
+void cmExtraKateGenerator::CreateDummyKateProjectFile(
+ const cmLocalGenerator& lg) const
+{
+ std::string filename =
+ cmStrCat(lg.GetBinaryDirectory(), '/', this->ProjectName, ".kateproject");
+ cmGeneratedFileStream fout(filename);
+ if (!fout) {
+ return;
+ }
+
+ fout << "#Generated by " << cmSystemTools::GetCMakeCommand()
+ << ", do not edit.\n";
+}
+
+std::string cmExtraKateGenerator::GenerateFilesString(
+ const cmLocalGenerator& lg) const
+{
+ std::string s = cmStrCat(lg.GetSourceDirectory(), "/.git");
+ if (cmSystemTools::FileExists(s)) {
+ return "\"git\": 1 ";
+ }
+
+ s = cmStrCat(lg.GetSourceDirectory(), "/.svn");
+ if (cmSystemTools::FileExists(s)) {
+ return "\"svn\": 1 ";
+ }
+
+ s = cmStrCat(lg.GetSourceDirectory(), '/');
+
+ std::set<std::string> files;
+ std::string tmp;
+ const auto& lgs = this->GlobalGenerator->GetLocalGenerators();
+
+ for (const auto& lgen : lgs) {
+ cmMakefile* makefile = lgen->GetMakefile();
+ const std::vector<std::string>& listFiles = makefile->GetListFiles();
+ for (std::string const& listFile : listFiles) {
+ tmp = listFile;
+ {
+ files.insert(tmp);
+ }
+ }
+
+ for (const auto& sf : makefile->GetSourceFiles()) {
+ if (sf->GetIsGenerated()) {
+ continue;
+ }
+
+ tmp = sf->ResolveFullPath();
+ files.insert(tmp);
+ }
+ }
+
+ const char* sep = "";
+ tmp = "\"list\": [";
+ for (std::string const& f : files) {
+ tmp += sep;
+ tmp += " \"";
+ tmp += f;
+ tmp += "\"";
+ sep = ",";
+ }
+ tmp += "] ";
+
+ return tmp;
+}
+
+std::string cmExtraKateGenerator::GenerateProjectName(
+ const std::string& name, const std::string& type,
+ const std::string& path) const
+{
+ return name + (type.empty() ? "" : "-") + type + '@' + path;
+}
+
+std::string cmExtraKateGenerator::GetPathBasename(
+ const std::string& path) const
+{
+ std::string outputBasename = path;
+ while (!outputBasename.empty() &&
+ (outputBasename.back() == '/' || outputBasename.back() == '\\')) {
+ outputBasename.resize(outputBasename.size() - 1);
+ }
+ std::string::size_type loc = outputBasename.find_last_of("/\\");
+ if (loc != std::string::npos) {
+ outputBasename = outputBasename.substr(loc + 1);
+ }
+
+ return outputBasename;
+}
diff --git a/Source/cmExtraKateGenerator.h b/Source/cmExtraKateGenerator.h
new file mode 100644
index 0000000..c66ddbf
--- /dev/null
+++ b/Source/cmExtraKateGenerator.h
@@ -0,0 +1,44 @@
+/* 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 <string>
+
+#include "cmExternalMakefileProjectGenerator.h"
+
+class cmGeneratedFileStream;
+class cmLocalGenerator;
+
+/** \class cmExtraKateGenerator
+ * \brief Write Kate project files for Makefile or ninja based projects
+ */
+class cmExtraKateGenerator : public cmExternalMakefileProjectGenerator
+{
+public:
+ cmExtraKateGenerator();
+
+ static cmExternalMakefileProjectGeneratorFactory* GetFactory();
+
+ void Generate() override;
+
+private:
+ void CreateKateProjectFile(const cmLocalGenerator& lg) const;
+ void CreateDummyKateProjectFile(const cmLocalGenerator& lg) const;
+ void WriteTargets(const cmLocalGenerator& lg,
+ cmGeneratedFileStream& fout) const;
+ void AppendTarget(cmGeneratedFileStream& fout, const std::string& target,
+ const std::string& make, const std::string& makeArgs,
+ const std::string& path,
+ const std::string& homeOutputDir) const;
+
+ std::string GenerateFilesString(const cmLocalGenerator& lg) const;
+ std::string GetPathBasename(const std::string& path) const;
+ std::string GenerateProjectName(const std::string& name,
+ const std::string& type,
+ const std::string& path) const;
+
+ std::string ProjectName;
+ bool UseNinja;
+};
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
new file mode 100644
index 0000000..52965bb
--- /dev/null
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -0,0 +1,465 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmExtraSublimeTextGenerator.h"
+
+#include <cstring>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <utility>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmSourceFile.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+/*
+Sublime Text 2 Generator
+Author: Morné Chamberlain
+This generator was initially based off of the CodeBlocks generator.
+
+Some useful URLs:
+Homepage:
+http://www.sublimetext.com/
+
+File format docs:
+http://www.sublimetext.com/docs/2/projects.html
+http://sublimetext.info/docs/en/reference/build_systems.html
+*/
+
+cmExternalMakefileProjectGeneratorFactory*
+cmExtraSublimeTextGenerator::GetFactory()
+{
+ static cmExternalMakefileProjectGeneratorSimpleFactory<
+ cmExtraSublimeTextGenerator>
+ factory("Sublime Text 2", "Generates Sublime Text 2 project files.");
+
+ if (factory.GetSupportedGlobalGenerators().empty()) {
+#if defined(_WIN32)
+ factory.AddSupportedGlobalGenerator("MinGW Makefiles");
+ factory.AddSupportedGlobalGenerator("NMake Makefiles");
+// disable until somebody actually tests it:
+// factory.AddSupportedGlobalGenerator("MSYS Makefiles");
+#endif
+ factory.AddSupportedGlobalGenerator("Ninja");
+ factory.AddSupportedGlobalGenerator("Unix Makefiles");
+ }
+
+ return &factory;
+}
+
+cmExtraSublimeTextGenerator::cmExtraSublimeTextGenerator()
+{
+ this->ExcludeBuildFolder = false;
+}
+
+void cmExtraSublimeTextGenerator::Generate()
+{
+ this->ExcludeBuildFolder = this->GlobalGenerator->GlobalSettingIsOn(
+ "CMAKE_SUBLIME_TEXT_2_EXCLUDE_BUILD_TREE");
+ this->EnvSettings = this->GlobalGenerator->GetSafeGlobalSetting(
+ "CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS");
+
+ // for each sub project in the project create a sublime text 2 project
+ for (auto const& it : this->GlobalGenerator->GetProjectMap()) {
+ // create a project file
+ this->CreateProjectFile(it.second);
+ }
+}
+
+void cmExtraSublimeTextGenerator::CreateProjectFile(
+ const std::vector<cmLocalGenerator*>& lgs)
+{
+ std::string outputDir = lgs[0]->GetCurrentBinaryDirectory();
+ std::string projectName = lgs[0]->GetProjectName();
+
+ const std::string filename =
+ outputDir + "/" + projectName + ".sublime-project";
+
+ this->CreateNewProjectFile(lgs, filename);
+}
+
+void cmExtraSublimeTextGenerator::CreateNewProjectFile(
+ const std::vector<cmLocalGenerator*>& lgs, const std::string& filename)
+{
+ const cmMakefile* mf = lgs[0]->GetMakefile();
+
+ cmGeneratedFileStream fout(filename);
+ if (!fout) {
+ return;
+ }
+
+ const std::string& sourceRootRelativeToOutput = cmSystemTools::RelativePath(
+ lgs[0]->GetBinaryDirectory(), lgs[0]->GetSourceDirectory());
+ // Write the folder entries to the project file
+ fout << "{\n";
+ fout << "\t\"folders\":\n\t[\n\t";
+ if (!sourceRootRelativeToOutput.empty()) {
+ fout << "\t{\n\t\t\t\"path\": \"" << sourceRootRelativeToOutput << "\"";
+ const std::string& outputRelativeToSourceRoot =
+ cmSystemTools::RelativePath(lgs[0]->GetSourceDirectory(),
+ lgs[0]->GetBinaryDirectory());
+ if ((!outputRelativeToSourceRoot.empty()) &&
+ ((outputRelativeToSourceRoot.length() < 3) ||
+ (outputRelativeToSourceRoot.substr(0, 3) != "../"))) {
+ if (this->ExcludeBuildFolder) {
+ fout << ",\n\t\t\t\"folder_exclude_patterns\": [\""
+ << outputRelativeToSourceRoot << "\"]";
+ }
+ }
+ } else {
+ fout << "\t{\n\t\t\t\"path\": \"./\"";
+ }
+ fout << "\n\t\t}";
+ // End of the folders section
+ fout << "\n\t]";
+
+ // Write the beginning of the build systems section to the project file
+ fout << ",\n\t\"build_systems\":\n\t[\n\t";
+
+ // Set of include directories over all targets (sublime text/sublimeclang
+ // doesn't currently support these settings per build system, only project
+ // wide
+ MapSourceFileFlags sourceFileFlags;
+ this->AppendAllTargets(lgs, mf, fout, sourceFileFlags);
+
+ // End of build_systems
+ fout << "\n\t]";
+ std::string systemName = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME");
+ std::vector<std::string> tokens = cmExpandedList(this->EnvSettings);
+
+ if (!this->EnvSettings.empty()) {
+ fout << ",";
+ fout << "\n\t\"env\":";
+ fout << "\n\t{";
+ fout << "\n\t\t" << systemName << ":";
+ fout << "\n\t\t{";
+ for (std::string const& t : tokens) {
+ size_t const pos = t.find_first_of('=');
+
+ if (pos != std::string::npos) {
+ std::string varName = t.substr(0, pos);
+ std::string varValue = t.substr(pos + 1);
+
+ fout << "\n\t\t\t\"" << varName << "\":\"" << varValue << "\"";
+ } else {
+ std::ostringstream e;
+ e << "Could not parse Env Vars specified in "
+ "\"CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS\""
+ << ", corrupted string " << t;
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ }
+ }
+ fout << "\n\t\t}";
+ fout << "\n\t}";
+ }
+ fout << "\n}";
+}
+
+void cmExtraSublimeTextGenerator::AppendAllTargets(
+ const std::vector<cmLocalGenerator*>& lgs, const cmMakefile* mf,
+ cmGeneratedFileStream& fout, MapSourceFileFlags& sourceFileFlags)
+{
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ std::string compiler;
+ if (!lgs.empty()) {
+ this->AppendTarget(fout, "all", lgs[0], nullptr, make.c_str(), mf,
+ compiler.c_str(), sourceFileFlags, true);
+ this->AppendTarget(fout, "clean", lgs[0], nullptr, make.c_str(), mf,
+ compiler.c_str(), sourceFileFlags, false);
+ }
+
+ // add all executable and library targets and some of the GLOBAL
+ // and UTILITY targets
+ for (cmLocalGenerator* lg : lgs) {
+ cmMakefile* makefile = lg->GetMakefile();
+ const auto& targets = lg->GetGeneratorTargets();
+ for (const auto& target : targets) {
+ std::string targetName = target->GetName();
+ switch (target->GetType()) {
+ case cmStateEnums::GLOBAL_TARGET: {
+ // Only add the global targets from CMAKE_BINARY_DIR,
+ // not from the subdirs
+ if (lg->GetCurrentBinaryDirectory() == lg->GetBinaryDirectory()) {
+ this->AppendTarget(fout, targetName, lg, nullptr, make.c_str(),
+ makefile, compiler.c_str(), sourceFileFlags,
+ false);
+ }
+ } break;
+ case cmStateEnums::UTILITY:
+ // Add all utility targets, except the Nightly/Continuous/
+ // Experimental-"sub"targets as e.g. NightlyStart
+ if ((cmHasLiteralPrefix(targetName, "Nightly") &&
+ (targetName != "Nightly")) ||
+ (cmHasLiteralPrefix(targetName, "Continuous") &&
+ (targetName != "Continuous")) ||
+ (cmHasLiteralPrefix(targetName, "Experimental") &&
+ (targetName != "Experimental"))) {
+ break;
+ }
+
+ this->AppendTarget(fout, targetName, lg, nullptr, make.c_str(),
+ makefile, compiler.c_str(), sourceFileFlags,
+ false);
+ break;
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::OBJECT_LIBRARY: {
+ this->AppendTarget(fout, targetName, lg, target.get(), make.c_str(),
+ makefile, compiler.c_str(), sourceFileFlags,
+ false);
+ std::string fastTarget = cmStrCat(targetName, "/fast");
+ this->AppendTarget(fout, fastTarget, lg, target.get(), make.c_str(),
+ makefile, compiler.c_str(), sourceFileFlags,
+ false);
+ } break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void cmExtraSublimeTextGenerator::AppendTarget(
+ cmGeneratedFileStream& fout, const std::string& targetName,
+ cmLocalGenerator* lg, cmGeneratorTarget* target, const char* make,
+ const cmMakefile* makefile, const char* /*compiler*/,
+ MapSourceFileFlags& sourceFileFlags, bool firstTarget)
+{
+
+ if (target != nullptr) {
+ std::vector<cmSourceFile*> sourceFiles;
+ target->GetSourceFiles(sourceFiles,
+ makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ for (cmSourceFile* sourceFile : sourceFiles) {
+ auto sourceFileFlagsIter =
+ sourceFileFlags.find(sourceFile->ResolveFullPath());
+ if (sourceFileFlagsIter == sourceFileFlags.end()) {
+ sourceFileFlagsIter =
+ sourceFileFlags
+ .insert(MapSourceFileFlags::value_type(
+ sourceFile->ResolveFullPath(), std::vector<std::string>()))
+ .first;
+ }
+ std::vector<std::string>& flags = sourceFileFlagsIter->second;
+ std::string flagsString =
+ this->ComputeFlagsForObject(sourceFile, lg, target);
+ std::string definesString = this->ComputeDefines(sourceFile, lg, target);
+ std::string includesString =
+ this->ComputeIncludes(sourceFile, lg, target);
+ flags.clear();
+ cmsys::RegularExpression flagRegex;
+ // Regular expression to extract compiler flags from a string
+ // https://gist.github.com/3944250
+ const char* regexString =
+ R"((^|[ ])-[DIOUWfgs][^= ]+(=\"[^"]+\"|=[^"][^ ]+)?)";
+ flagRegex.compile(regexString);
+ std::string workString =
+ cmStrCat(flagsString, " ", definesString, " ", includesString);
+ while (flagRegex.find(workString)) {
+ std::string::size_type start = flagRegex.start();
+ if (workString[start] == ' ') {
+ start++;
+ }
+ flags.push_back(workString.substr(start, flagRegex.end() - start));
+ if (flagRegex.end() < workString.size()) {
+ workString = workString.substr(flagRegex.end());
+ } else {
+ workString.clear();
+ }
+ }
+ }
+ }
+
+ // Ninja uses ninja.build files (look for a way to get the output file name
+ // from cmMakefile or something)
+ std::string makefileName;
+ if (this->GlobalGenerator->GetName() == "Ninja") {
+ makefileName = "build.ninja";
+ } else {
+ makefileName = "Makefile";
+ }
+ if (!firstTarget) {
+ fout << ",\n\t";
+ }
+ fout << "\t{\n\t\t\t\"name\": \"" << lg->GetProjectName() << " - "
+ << targetName << "\",\n";
+ fout << "\t\t\t\"cmd\": ["
+ << this->BuildMakeCommand(make, makefileName, targetName) << "],\n";
+ fout << "\t\t\t\"working_dir\": \"${project_path}\",\n";
+ fout << "\t\t\t\"file_regex\": \""
+ "^(..[^:]*)(?::|\\\\()([0-9]+)(?::|\\\\))(?:([0-9]+):)?\\\\s*(.*)"
+ "\"\n";
+ fout << "\t\t}";
+}
+
+// Create the command line for building the given target using the selected
+// make
+std::string cmExtraSublimeTextGenerator::BuildMakeCommand(
+ const std::string& make, const std::string& makefile,
+ const std::string& target)
+{
+ std::string command = cmStrCat('"', make, '"');
+ std::string generator = this->GlobalGenerator->GetName();
+ if (generator == "NMake Makefiles") {
+ std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
+ command += R"(, "/NOLOGO", "/f", ")";
+ command += makefileName + "\"";
+ command += ", \"" + target + "\"";
+ } else if (generator == "Ninja") {
+ std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
+ command += R"(, "-f", ")";
+ command += makefileName + "\"";
+ command += ", \"" + target + "\"";
+ } else {
+ std::string makefileName;
+ if (generator == "MinGW Makefiles") {
+ // no escaping of spaces in this case, see
+ // https://gitlab.kitware.com/cmake/cmake/-/issues/10014
+ makefileName = makefile;
+ } else {
+ makefileName = cmSystemTools::ConvertToOutputPath(makefile);
+ }
+ command += R"(, "-f", ")";
+ command += makefileName + "\"";
+ command += ", \"" + target + "\"";
+ }
+ return command;
+}
+
+// TODO: Most of the code is picked up from the Ninja generator, refactor it.
+std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject(
+ cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* gtgt)
+{
+ std::string flags;
+ std::string language = source->GetOrDetermineLanguage();
+ if (language.empty()) {
+ language = "C";
+ }
+
+ // Explicitly add the explicit language flag before any other flag
+ // so user flags can override it.
+ gtgt->AddExplicitLanguageFlags(flags, *source);
+
+ std::string const& config =
+ lg->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
+
+ lg->GetTargetCompileFlags(gtgt, config, language, flags);
+
+ // Add source file specific flags.
+ cmGeneratorExpressionInterpreter genexInterpreter(lg, config, gtgt,
+ language);
+
+ const std::string COMPILE_FLAGS("COMPILE_FLAGS");
+ if (cmProp cflags = source->GetProperty(COMPILE_FLAGS)) {
+ lg->AppendFlags(flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));
+ }
+
+ const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
+ if (cmProp coptions = source->GetProperty(COMPILE_OPTIONS)) {
+ lg->AppendCompileOptions(
+ flags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
+ }
+
+ return flags;
+}
+
+// TODO: Refactor with
+// void cmMakefileTargetGenerator::WriteTargetLanguageFlags().
+std::string cmExtraSublimeTextGenerator::ComputeDefines(
+ cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* target)
+
+{
+ std::set<std::string> defines;
+ cmMakefile* makefile = lg->GetMakefile();
+ const std::string& language = source->GetOrDetermineLanguage();
+ const std::string& config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target,
+ language);
+
+ // Add preprocessor definitions for this target and configuration.
+ lg->GetTargetDefines(target, config, language, defines);
+ const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
+ if (cmProp compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) {
+ lg->AppendDefines(
+ defines, genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS));
+ }
+
+ std::string defPropName =
+ cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(config));
+ if (cmProp config_compile_defs = source->GetProperty(defPropName)) {
+ lg->AppendDefines(
+ defines,
+ genexInterpreter.Evaluate(*config_compile_defs, COMPILE_DEFINITIONS));
+ }
+
+ std::string definesString;
+ lg->JoinDefines(defines, definesString, language);
+
+ return definesString;
+}
+
+std::string cmExtraSublimeTextGenerator::ComputeIncludes(
+ cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* target)
+
+{
+ std::vector<std::string> includes;
+ cmMakefile* makefile = lg->GetMakefile();
+ const std::string& language = source->GetOrDetermineLanguage();
+ const std::string& config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target,
+ language);
+
+ // Add include directories for this source file
+ const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
+ if (cmProp cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) {
+ lg->AppendIncludeDirectories(
+ includes, genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES),
+ *source);
+ }
+
+ // Add include directory flags.
+ lg->GetIncludeDirectories(includes, target, language, config);
+
+ std::string includesString =
+ lg->GetIncludeFlags(includes, target, language, config, false,
+ cmLocalGenerator::IncludePathStyle::Absolute);
+
+ return includesString;
+}
+
+bool cmExtraSublimeTextGenerator::Open(const std::string& bindir,
+ const std::string& projectName,
+ bool dryRun)
+{
+ cmProp sublExecutable =
+ this->GlobalGenerator->GetCMakeInstance()->GetCacheDefinition(
+ "CMAKE_SUBLIMETEXT_EXECUTABLE");
+ if (!sublExecutable) {
+ return false;
+ }
+ if (cmIsNOTFOUND(*sublExecutable)) {
+ return false;
+ }
+
+ std::string filename = bindir + "/" + projectName + ".sublime-project";
+ if (dryRun) {
+ return cmSystemTools::FileExists(filename, true);
+ }
+
+ return cmSystemTools::RunSingleCommand(
+ { *sublExecutable, "--project", filename });
+}
diff --git a/Source/cmExtraSublimeTextGenerator.h b/Source/cmExtraSublimeTextGenerator.h
new file mode 100644
index 0000000..671b65a
--- /dev/null
+++ b/Source/cmExtraSublimeTextGenerator.h
@@ -0,0 +1,76 @@
+/* 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 <map>
+#include <string>
+#include <vector>
+
+#include "cmExternalMakefileProjectGenerator.h"
+
+class cmGeneratedFileStream;
+class cmGeneratorTarget;
+class cmLocalGenerator;
+class cmMakefile;
+class cmSourceFile;
+
+/** \class cmExtraSublimeTextGenerator
+ * \brief Write Sublime Text 2 project files for Makefile based projects
+ */
+class cmExtraSublimeTextGenerator : public cmExternalMakefileProjectGenerator
+{
+public:
+ static cmExternalMakefileProjectGeneratorFactory* GetFactory();
+ using MapSourceFileFlags = std::map<std::string, std::vector<std::string>>;
+ cmExtraSublimeTextGenerator();
+
+ void Generate() override;
+
+private:
+ void CreateProjectFile(const std::vector<cmLocalGenerator*>& lgs);
+
+ void CreateNewProjectFile(const std::vector<cmLocalGenerator*>& lgs,
+ const std::string& filename);
+
+ /** Appends all targets as build systems to the project file and get all
+ * include directories and compiler definitions used.
+ */
+ void AppendAllTargets(const std::vector<cmLocalGenerator*>& lgs,
+ const cmMakefile* mf, cmGeneratedFileStream& fout,
+ MapSourceFileFlags& sourceFileFlags);
+ /** Returns the build command that needs to be executed to build the
+ * specified target.
+ */
+ std::string BuildMakeCommand(const std::string& make,
+ const std::string& makefile,
+ const std::string& target);
+ /** Appends the specified target to the generated project file as a Sublime
+ * Text build system.
+ */
+ void AppendTarget(cmGeneratedFileStream& fout, const std::string& targetName,
+ cmLocalGenerator* lg, cmGeneratorTarget* target,
+ const char* make, const cmMakefile* makefile,
+ const char* compiler, MapSourceFileFlags& sourceFileFlags,
+ bool firstTarget);
+ /**
+ * Compute the flags for compilation of object files for a given @a language.
+ * @note Generally it is the value of the variable whose name is computed
+ * by LanguageFlagsVarName().
+ */
+ std::string ComputeFlagsForObject(cmSourceFile* source, cmLocalGenerator* lg,
+ cmGeneratorTarget* gtgt);
+
+ std::string ComputeDefines(cmSourceFile* source, cmLocalGenerator* lg,
+ cmGeneratorTarget* gtgt);
+
+ std::string ComputeIncludes(cmSourceFile* source, cmLocalGenerator* lg,
+ cmGeneratorTarget* gtgt);
+
+ bool Open(const std::string& bindir, const std::string& projectName,
+ bool dryRun) override;
+
+ bool ExcludeBuildFolder;
+ std::string EnvSettings;
+};
diff --git a/Source/cmFLTKWrapUICommand.cxx b/Source/cmFLTKWrapUICommand.cxx
new file mode 100644
index 0000000..77d5795
--- /dev/null
+++ b/Source/cmFLTKWrapUICommand.cxx
@@ -0,0 +1,133 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFLTKWrapUICommand.h"
+
+#include <cstddef>
+
+#include "cmCustomCommandLines.h"
+#include "cmExecutionStatus.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmRange.h"
+#include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+class cmTarget;
+
+static void FinalAction(cmMakefile& makefile, std::string const& name,
+ const cmListFileBacktrace& lfbt)
+{
+ // people should add the srcs to the target themselves, but the old command
+ // didn't support that, so check and see if they added the files in and if
+ // they didn;t then print a warning and add then anyhow
+ cmTarget* target = makefile.FindLocalNonAliasTarget(name);
+ if (!target) {
+ std::string msg = cmStrCat(
+ "FLTK_WRAP_UI was called with a target that was never created: ", name,
+ ". The problem was found while processing the source directory: ",
+ makefile.GetCurrentSourceDirectory(),
+ ". This FLTK_WRAP_UI call will be ignored.");
+ makefile.GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_ERROR, msg,
+ lfbt);
+ }
+}
+
+bool cmFLTKWrapUICommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ // what is the current source dir
+ std::string cdir = mf.GetCurrentSourceDirectory();
+ std::string const& fluid_exe =
+ mf.GetRequiredDefinition("FLTK_FLUID_EXECUTABLE");
+
+ // Target that will use the generated files
+ std::string const& target = args[0];
+
+ // get the list of GUI files from which .cxx and .h will be generated
+ std::string outputDirectory = mf.GetCurrentBinaryDirectory();
+
+ {
+ // Some of the generated files are *.h so the directory "GUI"
+ // where they are created have to be added to the include path
+ std::vector<std::string> outputDirectories;
+ outputDirectories.push_back(outputDirectory);
+ mf.AddIncludeDirectories(outputDirectories);
+ }
+
+ // List of produced files.
+ std::vector<cmSourceFile*> generatedSourcesClasses;
+
+ for (std::string const& arg : cmMakeRange(args).advance(1)) {
+ cmSourceFile* curr = mf.GetSource(arg);
+ // if we should use the source GUI
+ // to generate .cxx and .h files
+ if (!curr || !curr->GetPropertyAsBool("WRAP_EXCLUDE")) {
+ std::string outName = cmStrCat(
+ outputDirectory, "/", cmSystemTools::GetFilenameWithoutExtension(arg));
+ std::string hname = cmStrCat(outName, ".h");
+ std::string origname = cmStrCat(cdir, "/", arg);
+ // add starting depends
+ std::vector<std::string> depends;
+ depends.push_back(origname);
+ depends.push_back(fluid_exe);
+ std::string cxxres = cmStrCat(outName, ".cxx");
+
+ cmCustomCommandLines commandLines = cmMakeSingleCommandLine({
+ fluid_exe,
+ "-c", // instructs Fluid to run in command line
+ "-h", // optionally rename .h files
+ hname,
+ "-o", // optionally rename .cxx files
+ cxxres,
+ origname // name of the GUI fluid file
+ });
+
+ // Add command for generating the .h and .cxx files
+ std::string no_main_dependency;
+ const char* no_comment = nullptr;
+ const char* no_working_dir = nullptr;
+ mf.AddCustomCommandToOutput(cxxres, depends, no_main_dependency,
+ commandLines, no_comment, no_working_dir,
+ mf.GetPolicyStatus(cmPolicies::CMP0116));
+ mf.AddCustomCommandToOutput(hname, depends, no_main_dependency,
+ commandLines, no_comment, no_working_dir,
+ mf.GetPolicyStatus(cmPolicies::CMP0116));
+
+ cmSourceFile* sf = mf.GetSource(cxxres);
+ sf->AddDepend(hname);
+ sf->AddDepend(origname);
+ generatedSourcesClasses.push_back(sf);
+ }
+ }
+
+ // create the variable with the list of sources in it
+ size_t lastHeadersClass = generatedSourcesClasses.size();
+ std::string sourceListValue;
+ for (size_t classNum = 0; classNum < lastHeadersClass; classNum++) {
+ if (classNum) {
+ sourceListValue += ";";
+ }
+ sourceListValue += generatedSourcesClasses[classNum]->ResolveFullPath();
+ }
+
+ std::string const varName = target + "_FLTK_UI_SRCS";
+ mf.AddDefinition(varName, sourceListValue);
+
+ mf.AddGeneratorAction(
+ [target](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
+ FinalAction(*lg.GetMakefile(), target, lfbt);
+ });
+ return true;
+}
diff --git a/Source/cmFLTKWrapUICommand.h b/Source/cmFLTKWrapUICommand.h
new file mode 100644
index 0000000..7c1fc52
--- /dev/null
+++ b/Source/cmFLTKWrapUICommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmFLTKWrapUICommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmFSPermissions.cxx b/Source/cmFSPermissions.cxx
new file mode 100644
index 0000000..4015a51
--- /dev/null
+++ b/Source/cmFSPermissions.cxx
@@ -0,0 +1,34 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFSPermissions.h"
+
+bool cmFSPermissions::stringToModeT(std::string const& arg,
+ mode_t& permissions)
+{
+ if (arg == "OWNER_READ") {
+ permissions |= mode_owner_read;
+ } else if (arg == "OWNER_WRITE") {
+ permissions |= mode_owner_write;
+ } else if (arg == "OWNER_EXECUTE") {
+ permissions |= mode_owner_execute;
+ } else if (arg == "GROUP_READ") {
+ permissions |= mode_group_read;
+ } else if (arg == "GROUP_WRITE") {
+ permissions |= mode_group_write;
+ } else if (arg == "GROUP_EXECUTE") {
+ permissions |= mode_group_execute;
+ } else if (arg == "WORLD_READ") {
+ permissions |= mode_world_read;
+ } else if (arg == "WORLD_WRITE") {
+ permissions |= mode_world_write;
+ } else if (arg == "WORLD_EXECUTE") {
+ permissions |= mode_world_execute;
+ } else if (arg == "SETUID") {
+ permissions |= mode_setuid;
+ } else if (arg == "SETGID") {
+ permissions |= mode_setgid;
+ } else {
+ return false;
+ }
+ return true;
+}
diff --git a/Source/cmFSPermissions.h b/Source/cmFSPermissions.h
new file mode 100644
index 0000000..78f2240
--- /dev/null
+++ b/Source/cmFSPermissions.h
@@ -0,0 +1,42 @@
+/* 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 <string>
+
+#include "cm_sys_stat.h"
+
+namespace cmFSPermissions {
+
+// Table of permissions flags.
+#if defined(_WIN32) && !defined(__CYGWIN__)
+static const mode_t mode_owner_read = S_IREAD;
+static const mode_t mode_owner_write = S_IWRITE;
+static const mode_t mode_owner_execute = S_IEXEC;
+static const mode_t mode_group_read = 040;
+static const mode_t mode_group_write = 020;
+static const mode_t mode_group_execute = 010;
+static const mode_t mode_world_read = 04;
+static const mode_t mode_world_write = 02;
+static const mode_t mode_world_execute = 01;
+static const mode_t mode_setuid = 04000;
+static const mode_t mode_setgid = 02000;
+#else
+static const mode_t mode_owner_read = S_IRUSR;
+static const mode_t mode_owner_write = S_IWUSR;
+static const mode_t mode_owner_execute = S_IXUSR;
+static const mode_t mode_group_read = S_IRGRP;
+static const mode_t mode_group_write = S_IWGRP;
+static const mode_t mode_group_execute = S_IXGRP;
+static const mode_t mode_world_read = S_IROTH;
+static const mode_t mode_world_write = S_IWOTH;
+static const mode_t mode_world_execute = S_IXOTH;
+static const mode_t mode_setuid = S_ISUID;
+static const mode_t mode_setgid = S_ISGID;
+#endif
+
+bool stringToModeT(std::string const& arg, mode_t& permissions);
+
+} // ns
diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx
new file mode 100644
index 0000000..d529f52
--- /dev/null
+++ b/Source/cmFileAPI.cxx
@@ -0,0 +1,895 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileAPI.h"
+
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <cstddef>
+#include <ctime>
+#include <iomanip>
+#include <sstream>
+#include <utility>
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+
+#include "cmCryptoHash.h"
+#include "cmFileAPICMakeFiles.h"
+#include "cmFileAPICache.h"
+#include "cmFileAPICodemodel.h"
+#include "cmFileAPIToolchains.h"
+#include "cmGlobalGenerator.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTimestamp.h"
+#include "cmake.h"
+
+cmFileAPI::cmFileAPI(cmake* cm)
+ : CMakeInstance(cm)
+{
+ this->APIv1 =
+ this->CMakeInstance->GetHomeOutputDirectory() + "/.cmake/api/v1";
+
+ Json::CharReaderBuilder rbuilder;
+ rbuilder["collectComments"] = false;
+ rbuilder["failIfExtra"] = true;
+ rbuilder["rejectDupKeys"] = false;
+ rbuilder["strictRoot"] = true;
+ this->JsonReader =
+ std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
+
+ Json::StreamWriterBuilder wbuilder;
+ wbuilder["indentation"] = "\t";
+ this->JsonWriter =
+ std::unique_ptr<Json::StreamWriter>(wbuilder.newStreamWriter());
+}
+
+void cmFileAPI::ReadQueries()
+{
+ std::string const query_dir = this->APIv1 + "/query";
+ this->QueryExists = cmSystemTools::FileIsDirectory(query_dir);
+ if (!this->QueryExists) {
+ return;
+ }
+
+ // Load queries at the top level.
+ std::vector<std::string> queries = cmFileAPI::LoadDir(query_dir);
+
+ // Read the queries and save for later.
+ for (std::string& query : queries) {
+ if (cmHasLiteralPrefix(query, "client-")) {
+ this->ReadClient(query);
+ } else if (!cmFileAPI::ReadQuery(query, this->TopQuery.Known)) {
+ this->TopQuery.Unknown.push_back(std::move(query));
+ }
+ }
+}
+
+void cmFileAPI::WriteReplies()
+{
+ if (this->QueryExists) {
+ cmSystemTools::MakeDirectory(this->APIv1 + "/reply");
+ this->WriteJsonFile(this->BuildReplyIndex(), "index", ComputeSuffixTime);
+ }
+
+ this->RemoveOldReplyFiles();
+}
+
+std::vector<std::string> cmFileAPI::LoadDir(std::string const& dir)
+{
+ std::vector<std::string> files;
+ cmsys::Directory d;
+ d.Load(dir);
+ for (unsigned long i = 0; i < d.GetNumberOfFiles(); ++i) {
+ std::string f = d.GetFile(i);
+ if (f != "." && f != "..") {
+ files.push_back(std::move(f));
+ }
+ }
+ std::sort(files.begin(), files.end());
+ return files;
+}
+
+void cmFileAPI::RemoveOldReplyFiles()
+{
+ std::string const reply_dir = this->APIv1 + "/reply";
+ std::vector<std::string> files = this->LoadDir(reply_dir);
+ for (std::string const& f : files) {
+ if (this->ReplyFiles.find(f) == this->ReplyFiles.end()) {
+ std::string file = cmStrCat(reply_dir, "/", f);
+ cmSystemTools::RemoveFile(file);
+ }
+ }
+}
+
+bool cmFileAPI::ReadJsonFile(std::string const& file, Json::Value& value,
+ std::string& error)
+{
+ std::vector<char> content;
+
+ cmsys::ifstream fin;
+ if (!cmSystemTools::FileIsDirectory(file)) {
+ fin.open(file.c_str(), std::ios::binary);
+ }
+ auto finEnd = fin.rdbuf()->pubseekoff(0, std::ios::end);
+ if (finEnd > 0) {
+ size_t finSize = finEnd;
+ try {
+ // Allocate a buffer to read the whole file.
+ content.resize(finSize);
+
+ // Now read the file from the beginning.
+ fin.seekg(0, std::ios::beg);
+ fin.read(content.data(), finSize);
+ } catch (...) {
+ fin.setstate(std::ios::failbit);
+ }
+ }
+ fin.close();
+ if (!fin) {
+ value = Json::Value();
+ error = "failed to read from file";
+ return false;
+ }
+
+ // Parse our buffer as json.
+ if (!this->JsonReader->parse(content.data(), content.data() + content.size(),
+ &value, &error)) {
+ value = Json::Value();
+ return false;
+ }
+
+ return true;
+}
+
+std::string cmFileAPI::WriteJsonFile(
+ Json::Value const& value, std::string const& prefix,
+ std::string (*computeSuffix)(std::string const&))
+{
+ std::string fileName;
+
+ // Write the json file with a temporary name.
+ std::string const& tmpFile = this->APIv1 + "/tmp.json";
+ cmsys::ofstream ftmp(tmpFile.c_str());
+ this->JsonWriter->write(value, &ftmp);
+ ftmp << "\n";
+ ftmp.close();
+ if (!ftmp) {
+ cmSystemTools::RemoveFile(tmpFile);
+ return fileName;
+ }
+
+ // Compute the final name for the file.
+ fileName = prefix + "-" + computeSuffix(tmpFile) + ".json";
+
+ // Create the destination.
+ std::string file = this->APIv1 + "/reply";
+ cmSystemTools::MakeDirectory(file);
+ file += "/";
+ file += fileName;
+
+ // If the final name already exists then assume it has proper content.
+ // Otherwise, atomically place the reply file at its final name
+ if (cmSystemTools::FileExists(file, true) ||
+ !cmSystemTools::RenameFile(tmpFile, file)) {
+ cmSystemTools::RemoveFile(tmpFile);
+ }
+
+ // Record this among files we have just written.
+ this->ReplyFiles.insert(fileName);
+
+ return fileName;
+}
+
+Json::Value cmFileAPI::MaybeJsonFile(Json::Value in, std::string const& prefix)
+{
+ Json::Value out;
+ if (in.isObject() || in.isArray()) {
+ out = Json::objectValue;
+ out["jsonFile"] = this->WriteJsonFile(in, prefix);
+ } else {
+ out = std::move(in);
+ }
+ return out;
+}
+
+std::string cmFileAPI::ComputeSuffixHash(std::string const& file)
+{
+ cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_256);
+ std::string hash = hasher.HashFile(file);
+ hash.resize(20, '0');
+ return hash;
+}
+
+std::string cmFileAPI::ComputeSuffixTime(std::string const&)
+{
+ std::chrono::milliseconds ms =
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::system_clock::now().time_since_epoch());
+ std::chrono::seconds s =
+ std::chrono::duration_cast<std::chrono::seconds>(ms);
+
+ std::time_t ts = s.count();
+ std::size_t tms = ms.count() % 1000;
+
+ cmTimestamp cmts;
+ std::ostringstream ss;
+ ss << cmts.CreateTimestampFromTimeT(ts, "%Y-%m-%dT%H-%M-%S", true) << '-'
+ << std::setfill('0') << std::setw(4) << tms;
+ return ss.str();
+}
+
+bool cmFileAPI::ReadQuery(std::string const& query,
+ std::vector<Object>& objects)
+{
+ // Parse the "<kind>-" syntax.
+ std::string::size_type sep_pos = query.find('-');
+ if (sep_pos == std::string::npos) {
+ return false;
+ }
+ std::string kindName = query.substr(0, sep_pos);
+ std::string verStr = query.substr(sep_pos + 1);
+ if (kindName == ObjectKindName(ObjectKind::CodeModel)) {
+ Object o;
+ o.Kind = ObjectKind::CodeModel;
+ if (verStr == "v2") {
+ o.Version = 2;
+ } else {
+ return false;
+ }
+ objects.push_back(o);
+ return true;
+ }
+ if (kindName == ObjectKindName(ObjectKind::Cache)) {
+ Object o;
+ o.Kind = ObjectKind::Cache;
+ if (verStr == "v2") {
+ o.Version = 2;
+ } else {
+ return false;
+ }
+ objects.push_back(o);
+ return true;
+ }
+ if (kindName == ObjectKindName(ObjectKind::CMakeFiles)) {
+ Object o;
+ o.Kind = ObjectKind::CMakeFiles;
+ if (verStr == "v1") {
+ o.Version = 1;
+ } else {
+ return false;
+ }
+ objects.push_back(o);
+ return true;
+ }
+ if (kindName == ObjectKindName(ObjectKind::Toolchains)) {
+ Object o;
+ o.Kind = ObjectKind::Toolchains;
+ if (verStr == "v1") {
+ o.Version = 1;
+ } else {
+ return false;
+ }
+ objects.push_back(o);
+ return true;
+ }
+ if (kindName == ObjectKindName(ObjectKind::InternalTest)) {
+ Object o;
+ o.Kind = ObjectKind::InternalTest;
+ if (verStr == "v1") {
+ o.Version = 1;
+ } else if (verStr == "v2") {
+ o.Version = 2;
+ } else {
+ return false;
+ }
+ objects.push_back(o);
+ return true;
+ }
+ return false;
+}
+
+void cmFileAPI::ReadClient(std::string const& client)
+{
+ // Load queries for the client.
+ std::string clientDir = this->APIv1 + "/query/" + client;
+ std::vector<std::string> queries = this->LoadDir(clientDir);
+
+ // Read the queries and save for later.
+ ClientQuery& clientQuery = this->ClientQueries[client];
+ for (std::string& query : queries) {
+ if (query == "query.json") {
+ clientQuery.HaveQueryJson = true;
+ this->ReadClientQuery(client, clientQuery.QueryJson);
+ } else if (!this->ReadQuery(query, clientQuery.DirQuery.Known)) {
+ clientQuery.DirQuery.Unknown.push_back(std::move(query));
+ }
+ }
+}
+
+void cmFileAPI::ReadClientQuery(std::string const& client, ClientQueryJson& q)
+{
+ // Read the query.json file.
+ std::string queryFile = this->APIv1 + "/query/" + client + "/query.json";
+ Json::Value query;
+ if (!this->ReadJsonFile(queryFile, query, q.Error)) {
+ return;
+ }
+ if (!query.isObject()) {
+ q.Error = "query root is not an object";
+ return;
+ }
+
+ Json::Value const& clientValue = query["client"];
+ if (!clientValue.isNull()) {
+ q.ClientValue = clientValue;
+ }
+ q.RequestsValue = std::move(query["requests"]);
+ q.Requests = this->BuildClientRequests(q.RequestsValue);
+}
+
+Json::Value cmFileAPI::BuildReplyIndex()
+{
+ Json::Value index(Json::objectValue);
+
+ // Report information about this version of CMake.
+ index["cmake"] = this->BuildCMake();
+
+ // Reply to all queries that we loaded.
+ Json::Value& reply = index["reply"] = this->BuildReply(this->TopQuery);
+ for (auto const& client : this->ClientQueries) {
+ std::string const& clientName = client.first;
+ ClientQuery const& clientQuery = client.second;
+ reply[clientName] = this->BuildClientReply(clientQuery);
+ }
+
+ // Move our index of generated objects into its field.
+ Json::Value& objects = index["objects"] = Json::arrayValue;
+ for (auto& entry : this->ReplyIndexObjects) {
+ objects.append(std::move(entry.second)); // NOLINT(*)
+ }
+
+ return index;
+}
+
+Json::Value cmFileAPI::BuildCMake()
+{
+ Json::Value cmake = Json::objectValue;
+ cmake["version"] = this->CMakeInstance->ReportVersionJson();
+ Json::Value& cmake_paths = cmake["paths"] = Json::objectValue;
+ cmake_paths["cmake"] = cmSystemTools::GetCMakeCommand();
+ cmake_paths["ctest"] = cmSystemTools::GetCTestCommand();
+ cmake_paths["cpack"] = cmSystemTools::GetCPackCommand();
+ cmake_paths["root"] = cmSystemTools::GetCMakeRoot();
+ cmake["generator"] = this->CMakeInstance->GetGlobalGenerator()->GetJson();
+ return cmake;
+}
+
+Json::Value cmFileAPI::BuildReply(Query const& q)
+{
+ Json::Value reply = Json::objectValue;
+ for (Object const& o : q.Known) {
+ std::string const& name = ObjectName(o);
+ reply[name] = this->AddReplyIndexObject(o);
+ }
+
+ for (std::string const& name : q.Unknown) {
+ reply[name] = cmFileAPI::BuildReplyError("unknown query file");
+ }
+ return reply;
+}
+
+Json::Value cmFileAPI::BuildReplyError(std::string const& error)
+{
+ Json::Value e = Json::objectValue;
+ e["error"] = error;
+ return e;
+}
+
+Json::Value const& cmFileAPI::AddReplyIndexObject(Object const& o)
+{
+ Json::Value& indexEntry = this->ReplyIndexObjects[o];
+ if (!indexEntry.isNull()) {
+ // The reply object has already been generated.
+ return indexEntry;
+ }
+
+ // Generate this reply object.
+ Json::Value const& object = this->BuildObject(o);
+ assert(object.isObject());
+
+ // Populate this index entry.
+ indexEntry = Json::objectValue;
+ indexEntry["kind"] = object["kind"];
+ indexEntry["version"] = object["version"];
+ indexEntry["jsonFile"] = this->WriteJsonFile(object, ObjectName(o));
+ return indexEntry;
+}
+
+const char* cmFileAPI::ObjectKindName(ObjectKind kind)
+{
+ // Keep in sync with ObjectKind enum.
+ static const char* objectKindNames[] = {
+ "codemodel", //
+ "cache", //
+ "cmakeFiles", //
+ "toolchains", //
+ "__test" //
+ };
+ return objectKindNames[size_t(kind)];
+}
+
+std::string cmFileAPI::ObjectName(Object const& o)
+{
+ std::string name = cmStrCat(ObjectKindName(o.Kind), "-v", o.Version);
+ return name;
+}
+
+Json::Value cmFileAPI::BuildVersion(unsigned int major, unsigned int minor)
+{
+ Json::Value version;
+ version["major"] = major;
+ version["minor"] = minor;
+ return version;
+}
+
+Json::Value cmFileAPI::BuildObject(Object const& object)
+{
+ Json::Value value;
+
+ switch (object.Kind) {
+ case ObjectKind::CodeModel:
+ value = this->BuildCodeModel(object);
+ break;
+ case ObjectKind::Cache:
+ value = this->BuildCache(object);
+ break;
+ case ObjectKind::CMakeFiles:
+ value = this->BuildCMakeFiles(object);
+ break;
+ case ObjectKind::Toolchains:
+ value = this->BuildToolchains(object);
+ break;
+ case ObjectKind::InternalTest:
+ value = this->BuildInternalTest(object);
+ break;
+ }
+
+ return value;
+}
+
+cmFileAPI::ClientRequests cmFileAPI::BuildClientRequests(
+ Json::Value const& requests)
+{
+ ClientRequests result;
+ if (requests.isNull()) {
+ result.Error = "'requests' member missing";
+ return result;
+ }
+ if (!requests.isArray()) {
+ result.Error = "'requests' member is not an array";
+ return result;
+ }
+
+ result.reserve(requests.size());
+ for (Json::Value const& request : requests) {
+ result.emplace_back(this->BuildClientRequest(request));
+ }
+
+ return result;
+}
+
+cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
+ Json::Value const& request)
+{
+ ClientRequest r;
+
+ if (!request.isObject()) {
+ r.Error = "request is not an object";
+ return r;
+ }
+
+ Json::Value const& kind = request["kind"];
+ if (kind.isNull()) {
+ r.Error = "'kind' member missing";
+ return r;
+ }
+ if (!kind.isString()) {
+ r.Error = "'kind' member is not a string";
+ return r;
+ }
+ std::string const& kindName = kind.asString();
+
+ if (kindName == this->ObjectKindName(ObjectKind::CodeModel)) {
+ r.Kind = ObjectKind::CodeModel;
+ } else if (kindName == this->ObjectKindName(ObjectKind::Cache)) {
+ r.Kind = ObjectKind::Cache;
+ } else if (kindName == this->ObjectKindName(ObjectKind::CMakeFiles)) {
+ r.Kind = ObjectKind::CMakeFiles;
+ } else if (kindName == this->ObjectKindName(ObjectKind::Toolchains)) {
+ r.Kind = ObjectKind::Toolchains;
+ } else if (kindName == this->ObjectKindName(ObjectKind::InternalTest)) {
+ r.Kind = ObjectKind::InternalTest;
+ } else {
+ r.Error = "unknown request kind '" + kindName + "'";
+ return r;
+ }
+
+ Json::Value const& version = request["version"];
+ if (version.isNull()) {
+ r.Error = "'version' member missing";
+ return r;
+ }
+ std::vector<RequestVersion> versions;
+ if (!cmFileAPI::ReadRequestVersions(version, versions, r.Error)) {
+ return r;
+ }
+
+ switch (r.Kind) {
+ case ObjectKind::CodeModel:
+ this->BuildClientRequestCodeModel(r, versions);
+ break;
+ case ObjectKind::Cache:
+ this->BuildClientRequestCache(r, versions);
+ break;
+ case ObjectKind::CMakeFiles:
+ this->BuildClientRequestCMakeFiles(r, versions);
+ break;
+ case ObjectKind::Toolchains:
+ this->BuildClientRequestToolchains(r, versions);
+ break;
+ case ObjectKind::InternalTest:
+ this->BuildClientRequestInternalTest(r, versions);
+ break;
+ }
+
+ return r;
+}
+
+Json::Value cmFileAPI::BuildClientReply(ClientQuery const& q)
+{
+ Json::Value reply = this->BuildReply(q.DirQuery);
+
+ if (!q.HaveQueryJson) {
+ return reply;
+ }
+
+ Json::Value& reply_query_json = reply["query.json"];
+ ClientQueryJson const& qj = q.QueryJson;
+
+ if (!qj.Error.empty()) {
+ reply_query_json = this->BuildReplyError(qj.Error);
+ return reply;
+ }
+
+ if (!qj.ClientValue.isNull()) {
+ reply_query_json["client"] = qj.ClientValue;
+ }
+
+ if (!qj.RequestsValue.isNull()) {
+ reply_query_json["requests"] = qj.RequestsValue;
+ }
+
+ reply_query_json["responses"] = this->BuildClientReplyResponses(qj.Requests);
+
+ return reply;
+}
+
+Json::Value cmFileAPI::BuildClientReplyResponses(
+ ClientRequests const& requests)
+{
+ Json::Value responses;
+
+ if (!requests.Error.empty()) {
+ responses = this->BuildReplyError(requests.Error);
+ return responses;
+ }
+
+ responses = Json::arrayValue;
+ for (ClientRequest const& request : requests) {
+ responses.append(this->BuildClientReplyResponse(request));
+ }
+
+ return responses;
+}
+
+Json::Value cmFileAPI::BuildClientReplyResponse(ClientRequest const& request)
+{
+ Json::Value response;
+ if (!request.Error.empty()) {
+ response = this->BuildReplyError(request.Error);
+ return response;
+ }
+ response = this->AddReplyIndexObject(request);
+ return response;
+}
+
+bool cmFileAPI::ReadRequestVersions(Json::Value const& version,
+ std::vector<RequestVersion>& versions,
+ std::string& error)
+{
+ if (version.isArray()) {
+ for (Json::Value const& v : version) {
+ if (!ReadRequestVersion(v, /*inArray=*/true, versions, error)) {
+ return false;
+ }
+ }
+ } else {
+ if (!ReadRequestVersion(version, /*inArray=*/false, versions, error)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmFileAPI::ReadRequestVersion(Json::Value const& version, bool inArray,
+ std::vector<RequestVersion>& result,
+ std::string& error)
+{
+ if (version.isUInt()) {
+ RequestVersion v;
+ v.Major = version.asUInt();
+ result.push_back(v);
+ return true;
+ }
+
+ if (!version.isObject()) {
+ if (inArray) {
+ error = "'version' array entry is not a non-negative integer or object";
+ } else {
+ error =
+ "'version' member is not a non-negative integer, object, or array";
+ }
+ return false;
+ }
+
+ Json::Value const& major = version["major"];
+ if (major.isNull()) {
+ error = "'version' object 'major' member missing";
+ return false;
+ }
+ if (!major.isUInt()) {
+ error = "'version' object 'major' member is not a non-negative integer";
+ return false;
+ }
+
+ RequestVersion v;
+ v.Major = major.asUInt();
+
+ Json::Value const& minor = version["minor"];
+ if (minor.isUInt()) {
+ v.Minor = minor.asUInt();
+ } else if (!minor.isNull()) {
+ error = "'version' object 'minor' member is not a non-negative integer";
+ return false;
+ }
+
+ result.push_back(v);
+
+ return true;
+}
+
+std::string cmFileAPI::NoSupportedVersion(
+ std::vector<RequestVersion> const& versions)
+{
+ std::ostringstream msg;
+ msg << "no supported version specified";
+ if (!versions.empty()) {
+ msg << " among:";
+ for (RequestVersion const& v : versions) {
+ msg << " " << v.Major << "." << v.Minor;
+ }
+ }
+ return msg.str();
+}
+
+// The "codemodel" object kind.
+
+static unsigned int const CodeModelV2Minor = 3;
+
+void cmFileAPI::BuildClientRequestCodeModel(
+ ClientRequest& r, std::vector<RequestVersion> const& versions)
+{
+ // Select a known version from those requested.
+ for (RequestVersion const& v : versions) {
+ if ((v.Major == 2 && v.Minor <= CodeModelV2Minor)) {
+ r.Version = v.Major;
+ break;
+ }
+ }
+ if (!r.Version) {
+ r.Error = NoSupportedVersion(versions);
+ }
+}
+
+Json::Value cmFileAPI::BuildCodeModel(Object const& object)
+{
+ Json::Value codemodel = cmFileAPICodemodelDump(*this, object.Version);
+ codemodel["kind"] = this->ObjectKindName(object.Kind);
+
+ Json::Value& version = codemodel["version"];
+ if (object.Version == 2) {
+ version = BuildVersion(2, CodeModelV2Minor);
+ } else {
+ return codemodel; // should be unreachable
+ }
+
+ return codemodel;
+}
+
+// The "cache" object kind.
+
+static unsigned int const CacheV2Minor = 0;
+
+void cmFileAPI::BuildClientRequestCache(
+ ClientRequest& r, std::vector<RequestVersion> const& versions)
+{
+ // Select a known version from those requested.
+ for (RequestVersion const& v : versions) {
+ if ((v.Major == 2 && v.Minor <= CacheV2Minor)) {
+ r.Version = v.Major;
+ break;
+ }
+ }
+ if (!r.Version) {
+ r.Error = NoSupportedVersion(versions);
+ }
+}
+
+Json::Value cmFileAPI::BuildCache(Object const& object)
+{
+ Json::Value cache = cmFileAPICacheDump(*this, object.Version);
+ cache["kind"] = this->ObjectKindName(object.Kind);
+
+ Json::Value& version = cache["version"];
+ if (object.Version == 2) {
+ version = BuildVersion(2, CacheV2Minor);
+ } else {
+ return cache; // should be unreachable
+ }
+
+ return cache;
+}
+
+// The "cmakeFiles" object kind.
+
+static unsigned int const CMakeFilesV1Minor = 0;
+
+void cmFileAPI::BuildClientRequestCMakeFiles(
+ ClientRequest& r, std::vector<RequestVersion> const& versions)
+{
+ // Select a known version from those requested.
+ for (RequestVersion const& v : versions) {
+ if ((v.Major == 1 && v.Minor <= CMakeFilesV1Minor)) {
+ r.Version = v.Major;
+ break;
+ }
+ }
+ if (!r.Version) {
+ r.Error = NoSupportedVersion(versions);
+ }
+}
+
+Json::Value cmFileAPI::BuildCMakeFiles(Object const& object)
+{
+ Json::Value cmakeFiles = cmFileAPICMakeFilesDump(*this, object.Version);
+ cmakeFiles["kind"] = this->ObjectKindName(object.Kind);
+
+ Json::Value& version = cmakeFiles["version"];
+ if (object.Version == 1) {
+ version = BuildVersion(1, CMakeFilesV1Minor);
+ } else {
+ return cmakeFiles; // should be unreachable
+ }
+
+ return cmakeFiles;
+}
+
+// The "toolchains" object kind.
+
+static unsigned int const ToolchainsV1Minor = 0;
+
+void cmFileAPI::BuildClientRequestToolchains(
+ ClientRequest& r, std::vector<RequestVersion> const& versions)
+{
+ // Select a known version from those requested.
+ for (RequestVersion const& v : versions) {
+ if ((v.Major == 1 && v.Minor <= ToolchainsV1Minor)) {
+ r.Version = v.Major;
+ break;
+ }
+ }
+ if (!r.Version) {
+ r.Error = NoSupportedVersion(versions);
+ }
+}
+
+Json::Value cmFileAPI::BuildToolchains(Object const& object)
+{
+ Json::Value toolchains = cmFileAPIToolchainsDump(*this, object.Version);
+ toolchains["kind"] = this->ObjectKindName(object.Kind);
+
+ Json::Value& version = toolchains["version"];
+ if (object.Version == 1) {
+ version = BuildVersion(1, ToolchainsV1Minor);
+ } else {
+ return toolchains; // should be unreachable
+ }
+
+ return toolchains;
+}
+
+// The "__test" object kind is for internal testing of CMake.
+
+static unsigned int const InternalTestV1Minor = 3;
+static unsigned int const InternalTestV2Minor = 0;
+
+void cmFileAPI::BuildClientRequestInternalTest(
+ ClientRequest& r, std::vector<RequestVersion> const& versions)
+{
+ // Select a known version from those requested.
+ for (RequestVersion const& v : versions) {
+ if ((v.Major == 1 && v.Minor <= InternalTestV1Minor) || //
+ (v.Major == 2 && v.Minor <= InternalTestV2Minor)) {
+ r.Version = v.Major;
+ break;
+ }
+ }
+ if (!r.Version) {
+ r.Error = NoSupportedVersion(versions);
+ }
+}
+
+Json::Value cmFileAPI::BuildInternalTest(Object const& object)
+{
+ Json::Value test = Json::objectValue;
+ test["kind"] = this->ObjectKindName(object.Kind);
+ Json::Value& version = test["version"];
+ if (object.Version == 2) {
+ version = BuildVersion(2, InternalTestV2Minor);
+ } else {
+ version = BuildVersion(1, InternalTestV1Minor);
+ }
+ return test;
+}
+
+Json::Value cmFileAPI::ReportCapabilities()
+{
+ Json::Value capabilities = Json::objectValue;
+ Json::Value& requests = capabilities["requests"] = Json::arrayValue;
+
+ {
+ Json::Value request = Json::objectValue;
+ request["kind"] = ObjectKindName(ObjectKind::CodeModel);
+ Json::Value& versions = request["version"] = Json::arrayValue;
+ versions.append(BuildVersion(2, CodeModelV2Minor));
+ requests.append(std::move(request)); // NOLINT(*)
+ }
+
+ {
+ Json::Value request = Json::objectValue;
+ request["kind"] = ObjectKindName(ObjectKind::Cache);
+ Json::Value& versions = request["version"] = Json::arrayValue;
+ versions.append(BuildVersion(2, CacheV2Minor));
+ requests.append(std::move(request)); // NOLINT(*)
+ }
+
+ {
+ Json::Value request = Json::objectValue;
+ request["kind"] = ObjectKindName(ObjectKind::CMakeFiles);
+ Json::Value& versions = request["version"] = Json::arrayValue;
+ versions.append(BuildVersion(1, CMakeFilesV1Minor));
+ requests.append(std::move(request)); // NOLINT(*)
+ }
+
+ {
+ Json::Value request = Json::objectValue;
+ request["kind"] = ObjectKindName(ObjectKind::Toolchains);
+ Json::Value& versions = request["version"] = Json::arrayValue;
+ versions.append(BuildVersion(1, ToolchainsV1Minor));
+ requests.append(std::move(request)); // NOLINT(*)
+ }
+
+ return capabilities;
+}
diff --git a/Source/cmFileAPI.h b/Source/cmFileAPI.h
new file mode 100644
index 0000000..22302b4
--- /dev/null
+++ b/Source/cmFileAPI.h
@@ -0,0 +1,211 @@
+/* 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 <map>
+#include <memory>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+#include <cm3p/json/writer.h>
+
+class cmake;
+
+class cmFileAPI
+{
+public:
+ cmFileAPI(cmake* cm);
+
+ /** Read fileapi queries from disk. */
+ void ReadQueries();
+
+ /** Write fileapi replies to disk. */
+ void WriteReplies();
+
+ /** Get the "cmake" instance with which this was constructed. */
+ cmake* GetCMakeInstance() const { return this->CMakeInstance; }
+
+ /** Convert a JSON object or array into an object with a single
+ "jsonFile" member specifying a file named with the given prefix
+ and holding the original object. Other JSON types are unchanged. */
+ Json::Value MaybeJsonFile(Json::Value in, std::string const& prefix);
+
+ /** Report file-api capabilities for cmake -E capabilities. */
+ static Json::Value ReportCapabilities();
+
+private:
+ cmake* CMakeInstance;
+
+ /** The api/v1 directory location. */
+ std::string APIv1;
+
+ /** The set of files we have just written to the reply directory. */
+ std::unordered_set<std::string> ReplyFiles;
+
+ static std::vector<std::string> LoadDir(std::string const& dir);
+ void RemoveOldReplyFiles();
+
+ // Keep in sync with ObjectKindName.
+ enum class ObjectKind
+ {
+ CodeModel,
+ Cache,
+ CMakeFiles,
+ Toolchains,
+ InternalTest
+ };
+
+ /** Identify one object kind and major version. */
+ struct Object
+ {
+ ObjectKind Kind;
+ unsigned long Version = 0;
+ friend bool operator<(Object const& l, Object const& r)
+ {
+ if (l.Kind != r.Kind) {
+ return l.Kind < r.Kind;
+ }
+ return l.Version < r.Version;
+ }
+ };
+
+ /** Represent content of a query directory. */
+ struct Query
+ {
+ /** Known object kind-version pairs. */
+ std::vector<Object> Known;
+ /** Unknown object kind names. */
+ std::vector<std::string> Unknown;
+ };
+
+ /** Represent one request in a client 'query.json'. */
+ struct ClientRequest : public Object
+ {
+ /** Empty if request is valid, else the error string. */
+ std::string Error;
+ };
+
+ /** Represent the "requests" in a client 'query.json'. */
+ struct ClientRequests : public std::vector<ClientRequest>
+ {
+ /** Empty if requests field is valid, else the error string. */
+ std::string Error;
+ };
+
+ /** Represent the content of a client query.json file. */
+ struct ClientQueryJson
+ {
+ /** The error string if parsing failed, else empty. */
+ std::string Error;
+
+ /** The 'query.json' object "client" member if it exists, else null. */
+ Json::Value ClientValue;
+
+ /** The 'query.json' object "requests" member if it exists, else null. */
+ Json::Value RequestsValue;
+
+ /** Requests extracted from 'query.json'. */
+ ClientRequests Requests;
+ };
+
+ /** Represent content of a client query directory. */
+ struct ClientQuery
+ {
+ /** The content of the client query directory except 'query.json'. */
+ Query DirQuery;
+
+ /** True if 'query.json' exists. */
+ bool HaveQueryJson = false;
+
+ /** The 'query.json' content. */
+ ClientQueryJson QueryJson;
+ };
+
+ /** Whether the top-level query directory exists at all. */
+ bool QueryExists = false;
+
+ /** The content of the top-level query directory. */
+ Query TopQuery;
+
+ /** The content of each "client-$client" query directory. */
+ std::map<std::string, ClientQuery> ClientQueries;
+
+ /** Reply index object generated for object kind/version.
+ This populates the "objects" field of the reply index. */
+ std::map<Object, Json::Value> ReplyIndexObjects;
+
+ std::unique_ptr<Json::CharReader> JsonReader;
+ std::unique_ptr<Json::StreamWriter> JsonWriter;
+
+ bool ReadJsonFile(std::string const& file, Json::Value& value,
+ std::string& error);
+
+ std::string WriteJsonFile(
+ Json::Value const& value, std::string const& prefix,
+ std::string (*computeSuffix)(std::string const&) = ComputeSuffixHash);
+ static std::string ComputeSuffixHash(std::string const&);
+ static std::string ComputeSuffixTime(std::string const&);
+
+ static bool ReadQuery(std::string const& query,
+ std::vector<Object>& objects);
+ void ReadClient(std::string const& client);
+ void ReadClientQuery(std::string const& client, ClientQueryJson& q);
+
+ Json::Value BuildReplyIndex();
+ Json::Value BuildCMake();
+ Json::Value BuildReply(Query const& q);
+ static Json::Value BuildReplyError(std::string const& error);
+ Json::Value const& AddReplyIndexObject(Object const& o);
+
+ static const char* ObjectKindName(ObjectKind kind);
+ static std::string ObjectName(Object const& o);
+
+ static Json::Value BuildVersion(unsigned int major, unsigned int minor);
+
+ Json::Value BuildObject(Object const& object);
+
+ ClientRequests BuildClientRequests(Json::Value const& requests);
+ ClientRequest BuildClientRequest(Json::Value const& request);
+ Json::Value BuildClientReply(ClientQuery const& q);
+ Json::Value BuildClientReplyResponses(ClientRequests const& requests);
+ Json::Value BuildClientReplyResponse(ClientRequest const& request);
+
+ struct RequestVersion
+ {
+ unsigned int Major = 0;
+ unsigned int Minor = 0;
+ };
+ static bool ReadRequestVersions(Json::Value const& version,
+ std::vector<RequestVersion>& versions,
+ std::string& error);
+ static bool ReadRequestVersion(Json::Value const& version, bool inArray,
+ std::vector<RequestVersion>& result,
+ std::string& error);
+ static std::string NoSupportedVersion(
+ std::vector<RequestVersion> const& versions);
+
+ void BuildClientRequestCodeModel(
+ ClientRequest& r, std::vector<RequestVersion> const& versions);
+ Json::Value BuildCodeModel(Object const& object);
+
+ void BuildClientRequestCache(ClientRequest& r,
+ std::vector<RequestVersion> const& versions);
+ Json::Value BuildCache(Object const& object);
+
+ void BuildClientRequestCMakeFiles(
+ ClientRequest& r, std::vector<RequestVersion> const& versions);
+ Json::Value BuildCMakeFiles(Object const& object);
+
+ void BuildClientRequestToolchains(
+ ClientRequest& r, std::vector<RequestVersion> const& versions);
+ Json::Value BuildToolchains(Object const& object);
+
+ void BuildClientRequestInternalTest(
+ ClientRequest& r, std::vector<RequestVersion> const& versions);
+ Json::Value BuildInternalTest(Object const& object);
+};
diff --git a/Source/cmFileAPICMakeFiles.cxx b/Source/cmFileAPICMakeFiles.cxx
new file mode 100644
index 0000000..e208ca8
--- /dev/null
+++ b/Source/cmFileAPICMakeFiles.cxx
@@ -0,0 +1,115 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileAPICMakeFiles.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm3p/json/value.h>
+
+#include "cmFileAPI.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+namespace {
+
+class CMakeFiles
+{
+ cmFileAPI& FileAPI;
+ unsigned long Version;
+ std::string CMakeModules;
+ std::string const& TopSource;
+ std::string const& TopBuild;
+ bool OutOfSource;
+
+ Json::Value DumpPaths();
+ Json::Value DumpInputs();
+ Json::Value DumpInput(std::string const& file);
+
+public:
+ CMakeFiles(cmFileAPI& fileAPI, unsigned long version);
+ Json::Value Dump();
+};
+
+CMakeFiles::CMakeFiles(cmFileAPI& fileAPI, unsigned long version)
+ : FileAPI(fileAPI)
+ , Version(version)
+ , CMakeModules(cmSystemTools::GetCMakeRoot() + "/Modules")
+ , TopSource(this->FileAPI.GetCMakeInstance()->GetHomeDirectory())
+ , TopBuild(this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory())
+ , OutOfSource(this->TopBuild != this->TopSource)
+{
+ static_cast<void>(this->Version);
+}
+
+Json::Value CMakeFiles::Dump()
+{
+ Json::Value cmakeFiles = Json::objectValue;
+ cmakeFiles["paths"] = this->DumpPaths();
+ cmakeFiles["inputs"] = this->DumpInputs();
+ return cmakeFiles;
+}
+
+Json::Value CMakeFiles::DumpPaths()
+{
+ Json::Value paths = Json::objectValue;
+ paths["source"] = this->TopSource;
+ paths["build"] = this->TopBuild;
+ return paths;
+}
+
+Json::Value CMakeFiles::DumpInputs()
+{
+ Json::Value inputs = Json::arrayValue;
+
+ cmGlobalGenerator* gg =
+ this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
+ for (const auto& lg : gg->GetLocalGenerators()) {
+ cmMakefile const* mf = lg->GetMakefile();
+ for (std::string const& file : mf->GetListFiles()) {
+ inputs.append(this->DumpInput(file));
+ }
+ }
+
+ return inputs;
+}
+
+Json::Value CMakeFiles::DumpInput(std::string const& file)
+{
+ Json::Value input = Json::objectValue;
+
+ bool const isCMake = cmSystemTools::IsSubDirectory(file, this->CMakeModules);
+ if (isCMake) {
+ input["isCMake"] = true;
+ }
+
+ if (!cmSystemTools::IsSubDirectory(file, this->TopSource) &&
+ !cmSystemTools::IsSubDirectory(file, this->TopBuild)) {
+ input["isExternal"] = true;
+ }
+
+ if (this->OutOfSource &&
+ cmSystemTools::IsSubDirectory(file, this->TopBuild)) {
+ input["isGenerated"] = true;
+ }
+
+ std::string path = file;
+ if (!isCMake && cmSystemTools::IsSubDirectory(path, this->TopSource)) {
+ // Use a relative path within the source directory.
+ path = cmSystemTools::RelativePath(this->TopSource, path);
+ }
+ input["path"] = path;
+
+ return input;
+}
+}
+
+Json::Value cmFileAPICMakeFilesDump(cmFileAPI& fileAPI, unsigned long version)
+{
+ CMakeFiles cmakeFiles(fileAPI, version);
+ return cmakeFiles.Dump();
+}
diff --git a/Source/cmFileAPICMakeFiles.h b/Source/cmFileAPICMakeFiles.h
new file mode 100644
index 0000000..5b48ed3
--- /dev/null
+++ b/Source/cmFileAPICMakeFiles.h
@@ -0,0 +1,12 @@
+/* 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 <cm3p/json/value.h>
+
+class cmFileAPI;
+
+extern Json::Value cmFileAPICMakeFilesDump(cmFileAPI& fileAPI,
+ unsigned long version);
diff --git a/Source/cmFileAPICache.cxx b/Source/cmFileAPICache.cxx
new file mode 100644
index 0000000..ddae527
--- /dev/null
+++ b/Source/cmFileAPICache.cxx
@@ -0,0 +1,108 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileAPICache.h"
+
+#include <algorithm>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm3p/json/value.h>
+
+#include "cmFileAPI.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmake.h"
+
+namespace {
+
+class Cache
+{
+ cmFileAPI& FileAPI;
+ unsigned long Version;
+ cmState* State;
+
+ Json::Value DumpEntries();
+ Json::Value DumpEntry(std::string const& name);
+ Json::Value DumpEntryProperties(std::string const& name);
+ Json::Value DumpEntryProperty(std::string const& name,
+ std::string const& prop);
+
+public:
+ Cache(cmFileAPI& fileAPI, unsigned long version);
+ Json::Value Dump();
+};
+
+Cache::Cache(cmFileAPI& fileAPI, unsigned long version)
+ : FileAPI(fileAPI)
+ , Version(version)
+ , State(this->FileAPI.GetCMakeInstance()->GetState())
+{
+ static_cast<void>(this->Version);
+}
+
+Json::Value Cache::Dump()
+{
+ Json::Value cache = Json::objectValue;
+ cache["entries"] = this->DumpEntries();
+ return cache;
+}
+
+Json::Value Cache::DumpEntries()
+{
+ Json::Value entries = Json::arrayValue;
+
+ std::vector<std::string> names = this->State->GetCacheEntryKeys();
+ std::sort(names.begin(), names.end());
+
+ for (std::string const& name : names) {
+ entries.append(this->DumpEntry(name));
+ }
+
+ return entries;
+}
+
+Json::Value Cache::DumpEntry(std::string const& name)
+{
+ Json::Value entry = Json::objectValue;
+ entry["name"] = name;
+ entry["type"] =
+ cmState::CacheEntryTypeToString(this->State->GetCacheEntryType(name));
+ entry["value"] = this->State->GetSafeCacheEntryValue(name);
+
+ Json::Value properties = this->DumpEntryProperties(name);
+ if (!properties.empty()) {
+ entry["properties"] = std::move(properties);
+ }
+
+ return entry;
+}
+
+Json::Value Cache::DumpEntryProperties(std::string const& name)
+{
+ Json::Value properties = Json::arrayValue;
+ std::vector<std::string> props =
+ this->State->GetCacheEntryPropertyList(name);
+ std::sort(props.begin(), props.end());
+ for (std::string const& prop : props) {
+ properties.append(this->DumpEntryProperty(name, prop));
+ }
+ return properties;
+}
+
+Json::Value Cache::DumpEntryProperty(std::string const& name,
+ std::string const& prop)
+{
+ Json::Value property = Json::objectValue;
+ property["name"] = prop;
+ cmProp p = this->State->GetCacheEntryProperty(name, prop);
+ property["value"] = p ? *p : "";
+ return property;
+}
+}
+
+Json::Value cmFileAPICacheDump(cmFileAPI& fileAPI, unsigned long version)
+{
+ Cache cache(fileAPI, version);
+ return cache.Dump();
+}
diff --git a/Source/cmFileAPICache.h b/Source/cmFileAPICache.h
new file mode 100644
index 0000000..bd9feeb
--- /dev/null
+++ b/Source/cmFileAPICache.h
@@ -0,0 +1,12 @@
+/* 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 <cm3p/json/value.h>
+
+class cmFileAPI;
+
+extern Json::Value cmFileAPICacheDump(cmFileAPI& fileAPI,
+ unsigned long version);
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
new file mode 100644
index 0000000..6b8757c
--- /dev/null
+++ b/Source/cmFileAPICodemodel.cxx
@@ -0,0 +1,1851 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileAPICodemodel.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <functional>
+#include <limits>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <cmext/algorithm>
+
+#include <cm3p/json/value.h>
+
+#include "cmCryptoHash.h"
+#include "cmExportSet.h"
+#include "cmFileAPI.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallDirectoryGenerator.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallFilesGenerator.h"
+#include "cmInstallGenerator.h"
+#include "cmInstallScriptGenerator.h"
+#include "cmInstallSubdirectoryGenerator.h"
+#include "cmInstallTargetGenerator.h"
+#include "cmLinkLineComputer.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmSourceFile.h"
+#include "cmSourceGroup.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetDepend.h"
+#include "cmTargetExport.h"
+#include "cmake.h"
+
+namespace {
+
+using TargetIndexMapType =
+ std::unordered_map<cmGeneratorTarget const*, Json::ArrayIndex>;
+
+std::string RelativeIfUnder(std::string const& top, std::string const& in)
+{
+ std::string out;
+ if (in == top) {
+ out = ".";
+ } else if (cmSystemTools::IsSubDirectory(in, top)) {
+ out = in.substr(top.size() + 1);
+ } else {
+ out = in;
+ }
+ return out;
+}
+
+class JBTIndex
+{
+public:
+ JBTIndex() = default;
+ explicit operator bool() const { return this->Index != None; }
+ Json::ArrayIndex Index = None;
+ static Json::ArrayIndex const None = static_cast<Json::ArrayIndex>(-1);
+};
+
+template <typename T>
+class JBT
+{
+public:
+ JBT(T v = T(), JBTIndex bt = JBTIndex())
+ : Value(std::move(v))
+ , Backtrace(bt)
+ {
+ }
+ T Value;
+ JBTIndex Backtrace;
+ friend bool operator==(JBT<T> const& l, JBT<T> const& r)
+ {
+ return l.Value == r.Value && l.Backtrace.Index == r.Backtrace.Index;
+ }
+ static bool ValueEq(JBT<T> const& l, JBT<T> const& r)
+ {
+ return l.Value == r.Value;
+ }
+ static bool ValueLess(JBT<T> const& l, JBT<T> const& r)
+ {
+ return l.Value < r.Value;
+ }
+};
+
+template <typename T>
+class JBTs
+{
+public:
+ JBTs(T v = T(), std::vector<JBTIndex> ids = std::vector<JBTIndex>())
+ : Value(std::move(v))
+ , Backtraces(std::move(ids))
+ {
+ }
+ T Value;
+ std::vector<JBTIndex> Backtraces;
+ friend bool operator==(JBTs<T> const& l, JBTs<T> const& r)
+ {
+ if ((l.Value == r.Value) && (l.Backtraces.size() == r.Backtraces.size())) {
+ for (size_t i = 0; i < l.Backtraces.size(); i++) {
+ if (l.Backtraces[i].Index != r.Backtraces[i].Index) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ static bool ValueEq(JBTs<T> const& l, JBTs<T> const& r)
+ {
+ return l.Value == r.Value;
+ }
+ static bool ValueLess(JBTs<T> const& l, JBTs<T> const& r)
+ {
+ return l.Value < r.Value;
+ }
+};
+
+class BacktraceData
+{
+ std::string TopSource;
+ std::unordered_map<std::string, Json::ArrayIndex> CommandMap;
+ std::unordered_map<std::string, Json::ArrayIndex> FileMap;
+ std::unordered_map<cmListFileContext const*, Json::ArrayIndex> NodeMap;
+ Json::Value Commands = Json::arrayValue;
+ Json::Value Files = Json::arrayValue;
+ Json::Value Nodes = Json::arrayValue;
+
+ Json::ArrayIndex AddCommand(std::string const& command)
+ {
+ auto i = this->CommandMap.find(command);
+ if (i == this->CommandMap.end()) {
+ auto cmdIndex = static_cast<Json::ArrayIndex>(this->Commands.size());
+ i = this->CommandMap.emplace(command, cmdIndex).first;
+ this->Commands.append(command);
+ }
+ return i->second;
+ }
+
+ Json::ArrayIndex AddFile(std::string const& file)
+ {
+ auto i = this->FileMap.find(file);
+ if (i == this->FileMap.end()) {
+ auto fileIndex = static_cast<Json::ArrayIndex>(this->Files.size());
+ i = this->FileMap.emplace(file, fileIndex).first;
+ this->Files.append(RelativeIfUnder(this->TopSource, file));
+ }
+ return i->second;
+ }
+
+public:
+ BacktraceData(std::string topSource);
+ JBTIndex Add(cmListFileBacktrace const& bt);
+ Json::Value Dump();
+};
+
+BacktraceData::BacktraceData(std::string topSource)
+ : TopSource(std::move(topSource))
+{
+}
+
+JBTIndex BacktraceData::Add(cmListFileBacktrace const& bt)
+{
+ JBTIndex index;
+ if (bt.Empty()) {
+ return index;
+ }
+ cmListFileContext const* top = &bt.Top();
+ auto found = this->NodeMap.find(top);
+ if (found != this->NodeMap.end()) {
+ index.Index = found->second;
+ return index;
+ }
+ Json::Value entry = Json::objectValue;
+ entry["file"] = this->AddFile(top->FilePath);
+ if (top->Line) {
+ entry["line"] = static_cast<int>(top->Line);
+ }
+ if (!top->Name.empty()) {
+ entry["command"] = this->AddCommand(top->Name);
+ }
+ if (JBTIndex parent = this->Add(bt.Pop())) {
+ entry["parent"] = parent.Index;
+ }
+ index.Index = this->NodeMap[top] = this->Nodes.size();
+ this->Nodes.append(std::move(entry)); // NOLINT(*)
+ return index;
+}
+
+Json::Value BacktraceData::Dump()
+{
+ Json::Value backtraceGraph;
+ this->CommandMap.clear();
+ this->FileMap.clear();
+ this->NodeMap.clear();
+ backtraceGraph["commands"] = std::move(this->Commands);
+ backtraceGraph["files"] = std::move(this->Files);
+ backtraceGraph["nodes"] = std::move(this->Nodes);
+ return backtraceGraph;
+}
+
+class Codemodel
+{
+ cmFileAPI& FileAPI;
+ unsigned long Version;
+
+ Json::Value DumpPaths();
+ Json::Value DumpConfigurations();
+ Json::Value DumpConfiguration(std::string const& config);
+
+public:
+ Codemodel(cmFileAPI& fileAPI, unsigned long version);
+ Json::Value Dump();
+};
+
+class CodemodelConfig
+{
+ cmFileAPI& FileAPI;
+ unsigned long Version;
+ std::string const& Config;
+ std::string TopSource;
+ std::string TopBuild;
+
+ struct Directory
+ {
+ cmStateSnapshot Snapshot;
+ cmLocalGenerator const* LocalGenerator = nullptr;
+ Json::Value TargetIndexes = Json::arrayValue;
+ Json::ArrayIndex ProjectIndex;
+ bool HasInstallRule = false;
+ };
+ std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
+ DirectoryMap;
+ std::vector<Directory> Directories;
+
+ struct Project
+ {
+ cmStateSnapshot Snapshot;
+ static const Json::ArrayIndex NoParentIndex =
+ static_cast<Json::ArrayIndex>(-1);
+ Json::ArrayIndex ParentIndex = NoParentIndex;
+ Json::Value ChildIndexes = Json::arrayValue;
+ Json::Value DirectoryIndexes = Json::arrayValue;
+ Json::Value TargetIndexes = Json::arrayValue;
+ };
+ std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
+ ProjectMap;
+ std::vector<Project> Projects;
+
+ TargetIndexMapType TargetIndexMap;
+
+ void ProcessDirectories();
+
+ Json::ArrayIndex GetDirectoryIndex(cmLocalGenerator const* lg);
+ Json::ArrayIndex GetDirectoryIndex(cmStateSnapshot s);
+
+ Json::ArrayIndex AddProject(cmStateSnapshot s);
+
+ Json::Value DumpTargets();
+ Json::Value DumpTarget(cmGeneratorTarget* gt, Json::ArrayIndex ti);
+
+ Json::Value DumpDirectories();
+ Json::Value DumpDirectory(Directory& d);
+ Json::Value DumpDirectoryObject(Directory& d);
+
+ Json::Value DumpProjects();
+ Json::Value DumpProject(Project& p);
+
+ Json::Value DumpMinimumCMakeVersion(cmStateSnapshot s);
+
+public:
+ CodemodelConfig(cmFileAPI& fileAPI, unsigned long version,
+ std::string const& config);
+ Json::Value Dump();
+};
+
+std::string TargetId(cmGeneratorTarget const* gt, std::string const& topBuild)
+{
+ cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_256);
+ std::string path = RelativeIfUnder(
+ topBuild, gt->GetLocalGenerator()->GetCurrentBinaryDirectory());
+ std::string hash = hasher.HashString(path);
+ hash.resize(20, '0');
+ return gt->GetName() + CMAKE_DIRECTORY_ID_SEP + hash;
+}
+
+struct CompileData
+{
+ struct IncludeEntry
+ {
+ JBT<std::string> Path;
+ bool IsSystem = false;
+ IncludeEntry(JBT<std::string> path, bool isSystem)
+ : Path(std::move(path))
+ , IsSystem(isSystem)
+ {
+ }
+ friend bool operator==(IncludeEntry const& l, IncludeEntry const& r)
+ {
+ return l.Path == r.Path && l.IsSystem == r.IsSystem;
+ }
+ };
+
+ std::string Language;
+ std::string Sysroot;
+ JBTs<std::string> LanguageStandard;
+ std::vector<JBT<std::string>> Flags;
+ std::vector<JBT<std::string>> Defines;
+ std::vector<JBT<std::string>> PrecompileHeaders;
+ std::vector<IncludeEntry> Includes;
+
+ friend bool operator==(CompileData const& l, CompileData const& r)
+ {
+ return (l.Language == r.Language && l.Sysroot == r.Sysroot &&
+ l.Flags == r.Flags && l.Defines == r.Defines &&
+ l.PrecompileHeaders == r.PrecompileHeaders &&
+ l.LanguageStandard == r.LanguageStandard &&
+ l.Includes == r.Includes);
+ }
+};
+}
+
+namespace std {
+
+template <>
+struct hash<CompileData>
+{
+ std::size_t operator()(CompileData const& in) const
+ {
+ using std::hash;
+ size_t result =
+ hash<std::string>()(in.Language) ^ hash<std::string>()(in.Sysroot);
+ for (auto const& i : in.Includes) {
+ result = result ^
+ (hash<std::string>()(i.Path.Value) ^
+ hash<Json::ArrayIndex>()(i.Path.Backtrace.Index) ^
+ (i.IsSystem ? std::numeric_limits<size_t>::max() : 0));
+ }
+ for (auto const& i : in.Flags) {
+ result = result ^ hash<std::string>()(i.Value) ^
+ hash<Json::ArrayIndex>()(i.Backtrace.Index);
+ }
+ for (auto const& i : in.Defines) {
+ result = result ^ hash<std::string>()(i.Value) ^
+ hash<Json::ArrayIndex>()(i.Backtrace.Index);
+ }
+ for (auto const& i : in.PrecompileHeaders) {
+ result = result ^ hash<std::string>()(i.Value) ^
+ hash<Json::ArrayIndex>()(i.Backtrace.Index);
+ }
+ if (!in.LanguageStandard.Value.empty()) {
+ result = result ^ hash<std::string>()(in.LanguageStandard.Value);
+ for (JBTIndex backtrace : in.LanguageStandard.Backtraces) {
+ result = result ^ hash<Json::ArrayIndex>()(backtrace.Index);
+ }
+ }
+ return result;
+ }
+};
+
+} // namespace std
+
+namespace {
+class DirectoryObject
+{
+ cmLocalGenerator const* LG = nullptr;
+ std::string const& Config;
+ TargetIndexMapType& TargetIndexMap;
+ std::string TopSource;
+ std::string TopBuild;
+ BacktraceData Backtraces;
+
+ void AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt);
+
+ Json::Value DumpPaths();
+ Json::Value DumpInstallers();
+ Json::Value DumpInstaller(cmInstallGenerator* gen);
+ Json::Value DumpInstallerExportTargets(cmExportSet* exp);
+ Json::Value DumpInstallerPath(std::string const& top,
+ std::string const& fromPathIn,
+ std::string const& toPath);
+
+public:
+ DirectoryObject(cmLocalGenerator const* lg, std::string const& config,
+ TargetIndexMapType& targetIndexMap);
+ Json::Value Dump();
+};
+
+class Target
+{
+ cmGeneratorTarget* GT;
+ std::string const& Config;
+ std::string TopSource;
+ std::string TopBuild;
+ std::vector<cmSourceGroup> SourceGroupsLocal;
+ BacktraceData Backtraces;
+
+ std::map<std::string, CompileData> CompileDataMap;
+
+ std::unordered_map<cmSourceFile const*, Json::ArrayIndex> SourceMap;
+ Json::Value Sources = Json::arrayValue;
+
+ struct SourceGroup
+ {
+ std::string Name;
+ Json::Value SourceIndexes = Json::arrayValue;
+ };
+ std::unordered_map<cmSourceGroup const*, Json::ArrayIndex> SourceGroupsMap;
+ std::vector<SourceGroup> SourceGroups;
+
+ struct CompileGroup
+ {
+ std::unordered_map<CompileData, Json::ArrayIndex>::iterator Entry;
+ Json::Value SourceIndexes = Json::arrayValue;
+ };
+ std::unordered_map<CompileData, Json::ArrayIndex> CompileGroupMap;
+ std::vector<CompileGroup> CompileGroups;
+
+ template <typename T>
+ JBT<T> ToJBT(BT<T> const& bt)
+ {
+ return JBT<T>(bt.Value, this->Backtraces.Add(bt.Backtrace));
+ }
+
+ template <typename T>
+ JBTs<T> ToJBTs(BTs<T> const& bts)
+ {
+ std::vector<JBTIndex> ids;
+ for (cmListFileBacktrace const& backtrace : bts.Backtraces) {
+ ids.emplace_back(this->Backtraces.Add(backtrace));
+ }
+ return JBTs<T>(bts.Value, ids);
+ }
+
+ void ProcessLanguages();
+ void ProcessLanguage(std::string const& lang);
+
+ Json::ArrayIndex AddSourceGroup(cmSourceGroup* sg, Json::ArrayIndex si);
+ CompileData BuildCompileData(cmSourceFile* sf);
+ CompileData MergeCompileData(CompileData const& fd);
+ Json::ArrayIndex AddSourceCompileGroup(cmSourceFile* sf,
+ Json::ArrayIndex si);
+ void AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt);
+ void AddBacktrace(Json::Value& object, JBTIndex bt);
+ Json::Value DumpPaths();
+ Json::Value DumpCompileData(CompileData const& cd);
+ Json::Value DumpInclude(CompileData::IncludeEntry const& inc);
+ Json::Value DumpPrecompileHeader(JBT<std::string> const& header);
+ Json::Value DumpLanguageStandard(JBTs<std::string> const& standard);
+ Json::Value DumpDefine(JBT<std::string> const& def);
+ Json::Value DumpSources();
+ Json::Value DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
+ Json::ArrayIndex si);
+ Json::Value DumpSourceGroups();
+ Json::Value DumpSourceGroup(SourceGroup& sg);
+ Json::Value DumpCompileGroups();
+ Json::Value DumpCompileGroup(CompileGroup& cg);
+ Json::Value DumpSysroot(std::string const& path);
+ Json::Value DumpInstall();
+ Json::Value DumpInstallPrefix();
+ Json::Value DumpInstallDestinations();
+ Json::Value DumpInstallDestination(cmInstallTargetGenerator* itGen);
+ Json::Value DumpArtifacts();
+ Json::Value DumpLink();
+ Json::Value DumpArchive();
+ Json::Value DumpLinkCommandFragments();
+ Json::Value DumpCommandFragments(std::vector<JBT<std::string>> const& frags);
+ Json::Value DumpCommandFragment(JBT<std::string> const& frag,
+ std::string const& role = std::string());
+ Json::Value DumpDependencies();
+ Json::Value DumpDependency(cmTargetDepend const& td);
+ Json::Value DumpFolder();
+
+public:
+ Target(cmGeneratorTarget* gt, std::string const& config);
+ Json::Value Dump();
+};
+
+Codemodel::Codemodel(cmFileAPI& fileAPI, unsigned long version)
+ : FileAPI(fileAPI)
+ , Version(version)
+{
+}
+
+Json::Value Codemodel::Dump()
+{
+ Json::Value codemodel = Json::objectValue;
+
+ codemodel["paths"] = this->DumpPaths();
+ codemodel["configurations"] = this->DumpConfigurations();
+
+ return codemodel;
+}
+
+Json::Value Codemodel::DumpPaths()
+{
+ Json::Value paths = Json::objectValue;
+ paths["source"] = this->FileAPI.GetCMakeInstance()->GetHomeDirectory();
+ paths["build"] = this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory();
+ return paths;
+}
+
+Json::Value Codemodel::DumpConfigurations()
+{
+ Json::Value configurations = Json::arrayValue;
+ cmGlobalGenerator* gg =
+ this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
+ const auto& makefiles = gg->GetMakefiles();
+ if (!makefiles.empty()) {
+ std::vector<std::string> const& configs =
+ makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ for (std::string const& config : configs) {
+ configurations.append(this->DumpConfiguration(config));
+ }
+ }
+ return configurations;
+}
+
+Json::Value Codemodel::DumpConfiguration(std::string const& config)
+{
+ CodemodelConfig configuration(this->FileAPI, this->Version, config);
+ return configuration.Dump();
+}
+
+CodemodelConfig::CodemodelConfig(cmFileAPI& fileAPI, unsigned long version,
+ std::string const& config)
+ : FileAPI(fileAPI)
+ , Version(version)
+ , Config(config)
+ , TopSource(this->FileAPI.GetCMakeInstance()->GetHomeDirectory())
+ , TopBuild(this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory())
+{
+ static_cast<void>(this->Version);
+}
+
+Json::Value CodemodelConfig::Dump()
+{
+ Json::Value configuration = Json::objectValue;
+ configuration["name"] = this->Config;
+ this->ProcessDirectories();
+ configuration["targets"] = this->DumpTargets();
+ configuration["directories"] = this->DumpDirectories();
+ configuration["projects"] = this->DumpProjects();
+ return configuration;
+}
+
+void CodemodelConfig::ProcessDirectories()
+{
+ cmGlobalGenerator* gg =
+ this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
+ auto const& localGens = gg->GetLocalGenerators();
+
+ // Add directories in forward order to process parents before children.
+ this->Directories.reserve(localGens.size());
+ for (const auto& lg : localGens) {
+ auto directoryIndex =
+ static_cast<Json::ArrayIndex>(this->Directories.size());
+ this->Directories.emplace_back();
+ Directory& d = this->Directories[directoryIndex];
+ d.Snapshot = lg->GetStateSnapshot().GetBuildsystemDirectory();
+ d.LocalGenerator = lg.get();
+ this->DirectoryMap[d.Snapshot] = directoryIndex;
+
+ d.ProjectIndex = this->AddProject(d.Snapshot);
+ this->Projects[d.ProjectIndex].DirectoryIndexes.append(directoryIndex);
+ }
+
+ // Update directories in reverse order to process children before parents.
+ for (auto di = this->Directories.rbegin(); di != this->Directories.rend();
+ ++di) {
+ Directory& d = *di;
+
+ // Accumulate the presence of install rules on the way up.
+ for (const auto& gen :
+ d.LocalGenerator->GetMakefile()->GetInstallGenerators()) {
+ if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(gen.get())) {
+ d.HasInstallRule = true;
+ break;
+ }
+ }
+ if (!d.HasInstallRule) {
+ for (cmStateSnapshot const& child : d.Snapshot.GetChildren()) {
+ cmStateSnapshot childDir = child.GetBuildsystemDirectory();
+ Json::ArrayIndex const childIndex = this->GetDirectoryIndex(childDir);
+ if (this->Directories[childIndex].HasInstallRule) {
+ d.HasInstallRule = true;
+ break;
+ }
+ }
+ }
+ }
+}
+
+Json::ArrayIndex CodemodelConfig::GetDirectoryIndex(cmLocalGenerator const* lg)
+{
+ return this->GetDirectoryIndex(
+ lg->GetStateSnapshot().GetBuildsystemDirectory());
+}
+
+Json::ArrayIndex CodemodelConfig::GetDirectoryIndex(cmStateSnapshot s)
+{
+ auto i = this->DirectoryMap.find(s);
+ assert(i != this->DirectoryMap.end());
+ return i->second;
+}
+
+Json::ArrayIndex CodemodelConfig::AddProject(cmStateSnapshot s)
+{
+ cmStateSnapshot ps = s.GetBuildsystemDirectoryParent();
+ if (ps.IsValid() && ps.GetProjectName() == s.GetProjectName()) {
+ // This directory is part of its parent directory project.
+ Json::ArrayIndex const parentDirIndex = this->GetDirectoryIndex(ps);
+ return this->Directories[parentDirIndex].ProjectIndex;
+ }
+
+ // This directory starts a new project.
+ auto projectIndex = static_cast<Json::ArrayIndex>(this->Projects.size());
+ this->Projects.emplace_back();
+ Project& p = this->Projects[projectIndex];
+ p.Snapshot = s;
+ this->ProjectMap[s] = projectIndex;
+ if (ps.IsValid()) {
+ Json::ArrayIndex const parentDirIndex = this->GetDirectoryIndex(ps);
+ p.ParentIndex = this->Directories[parentDirIndex].ProjectIndex;
+ this->Projects[p.ParentIndex].ChildIndexes.append(projectIndex);
+ }
+ return projectIndex;
+}
+
+Json::Value CodemodelConfig::DumpTargets()
+{
+ Json::Value targets = Json::arrayValue;
+
+ std::vector<cmGeneratorTarget*> targetList;
+ cmGlobalGenerator* gg =
+ this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
+ for (const auto& lg : gg->GetLocalGenerators()) {
+ cm::append(targetList, lg->GetGeneratorTargets());
+ }
+ std::sort(targetList.begin(), targetList.end(),
+ [](cmGeneratorTarget* l, cmGeneratorTarget* r) {
+ return l->GetName() < r->GetName();
+ });
+
+ for (cmGeneratorTarget* gt : targetList) {
+ if (gt->GetType() == cmStateEnums::GLOBAL_TARGET ||
+ !gt->IsInBuildSystem()) {
+ continue;
+ }
+
+ targets.append(this->DumpTarget(gt, targets.size()));
+ }
+
+ return targets;
+}
+
+Json::Value CodemodelConfig::DumpTarget(cmGeneratorTarget* gt,
+ Json::ArrayIndex ti)
+{
+ Target t(gt, this->Config);
+ std::string prefix = "target-" + gt->GetName();
+ for (char& c : prefix) {
+ // CMP0037 OLD behavior allows slashes in target names. Remove them.
+ if (c == '/' || c == '\\') {
+ c = '_';
+ }
+ }
+ if (!this->Config.empty()) {
+ prefix += "-" + this->Config;
+ }
+ Json::Value target = this->FileAPI.MaybeJsonFile(t.Dump(), prefix);
+ target["name"] = gt->GetName();
+ target["id"] = TargetId(gt, this->TopBuild);
+
+ // Cross-reference directory containing target.
+ Json::ArrayIndex di = this->GetDirectoryIndex(gt->GetLocalGenerator());
+ target["directoryIndex"] = di;
+ this->Directories[di].TargetIndexes.append(ti);
+
+ // Cross-reference project containing target.
+ Json::ArrayIndex pi = this->Directories[di].ProjectIndex;
+ target["projectIndex"] = pi;
+ this->Projects[pi].TargetIndexes.append(ti);
+
+ this->TargetIndexMap[gt] = ti;
+
+ return target;
+}
+
+Json::Value CodemodelConfig::DumpDirectories()
+{
+ Json::Value directories = Json::arrayValue;
+ for (Directory& d : this->Directories) {
+ directories.append(this->DumpDirectory(d));
+ }
+ return directories;
+}
+
+Json::Value CodemodelConfig::DumpDirectory(Directory& d)
+{
+ Json::Value directory = this->DumpDirectoryObject(d);
+
+ std::string sourceDir = d.Snapshot.GetDirectory().GetCurrentSource();
+ directory["source"] = RelativeIfUnder(this->TopSource, sourceDir);
+
+ std::string buildDir = d.Snapshot.GetDirectory().GetCurrentBinary();
+ directory["build"] = RelativeIfUnder(this->TopBuild, buildDir);
+
+ cmStateSnapshot parentDir = d.Snapshot.GetBuildsystemDirectoryParent();
+ if (parentDir.IsValid()) {
+ directory["parentIndex"] = this->GetDirectoryIndex(parentDir);
+ }
+
+ Json::Value childIndexes = Json::arrayValue;
+ for (cmStateSnapshot const& child : d.Snapshot.GetChildren()) {
+ childIndexes.append(
+ this->GetDirectoryIndex(child.GetBuildsystemDirectory()));
+ }
+ if (!childIndexes.empty()) {
+ directory["childIndexes"] = std::move(childIndexes);
+ }
+
+ directory["projectIndex"] = d.ProjectIndex;
+
+ if (!d.TargetIndexes.empty()) {
+ directory["targetIndexes"] = std::move(d.TargetIndexes);
+ }
+
+ Json::Value minimumCMakeVersion = this->DumpMinimumCMakeVersion(d.Snapshot);
+ if (!minimumCMakeVersion.isNull()) {
+ directory["minimumCMakeVersion"] = std::move(minimumCMakeVersion);
+ }
+
+ if (d.HasInstallRule) {
+ directory["hasInstallRule"] = true;
+ }
+
+ return directory;
+}
+
+Json::Value CodemodelConfig::DumpDirectoryObject(Directory& d)
+{
+ std::string prefix = "directory";
+ std::string sourceDirRel = RelativeIfUnder(
+ this->TopSource, d.Snapshot.GetDirectory().GetCurrentSource());
+ std::string buildDirRel = RelativeIfUnder(
+ this->TopBuild, d.Snapshot.GetDirectory().GetCurrentBinary());
+ if (!cmSystemTools::FileIsFullPath(buildDirRel)) {
+ prefix = cmStrCat(prefix, '-', buildDirRel);
+ } else if (!cmSystemTools::FileIsFullPath(sourceDirRel)) {
+ prefix = cmStrCat(prefix, '-', sourceDirRel);
+ }
+ for (char& c : prefix) {
+ if (c == '/' || c == '\\') {
+ c = '.';
+ }
+ }
+ if (!this->Config.empty()) {
+ prefix += "-" + this->Config;
+ }
+
+ DirectoryObject dir(d.LocalGenerator, this->Config, this->TargetIndexMap);
+ return this->FileAPI.MaybeJsonFile(dir.Dump(), prefix);
+}
+
+Json::Value CodemodelConfig::DumpProjects()
+{
+ Json::Value projects = Json::arrayValue;
+ for (Project& p : this->Projects) {
+ projects.append(this->DumpProject(p));
+ }
+ return projects;
+}
+
+Json::Value CodemodelConfig::DumpProject(Project& p)
+{
+ Json::Value project = Json::objectValue;
+
+ project["name"] = p.Snapshot.GetProjectName();
+
+ if (p.ParentIndex != Project::NoParentIndex) {
+ project["parentIndex"] = p.ParentIndex;
+ }
+
+ if (!p.ChildIndexes.empty()) {
+ project["childIndexes"] = std::move(p.ChildIndexes);
+ }
+
+ project["directoryIndexes"] = std::move(p.DirectoryIndexes);
+
+ if (!p.TargetIndexes.empty()) {
+ project["targetIndexes"] = std::move(p.TargetIndexes);
+ }
+
+ return project;
+}
+
+Json::Value CodemodelConfig::DumpMinimumCMakeVersion(cmStateSnapshot s)
+{
+ Json::Value minimumCMakeVersion;
+ if (std::string const* def =
+ s.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
+ minimumCMakeVersion = Json::objectValue;
+ minimumCMakeVersion["string"] = *def;
+ }
+ return minimumCMakeVersion;
+}
+
+DirectoryObject::DirectoryObject(cmLocalGenerator const* lg,
+ std::string const& config,
+ TargetIndexMapType& targetIndexMap)
+ : LG(lg)
+ , Config(config)
+ , TargetIndexMap(targetIndexMap)
+ , TopSource(lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
+ , TopBuild(
+ lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeOutputDirectory())
+ , Backtraces(this->TopSource)
+{
+}
+
+Json::Value DirectoryObject::Dump()
+{
+ Json::Value directoryObject = Json::objectValue;
+ directoryObject["paths"] = this->DumpPaths();
+ directoryObject["installers"] = this->DumpInstallers();
+ directoryObject["backtraceGraph"] = this->Backtraces.Dump();
+ return directoryObject;
+}
+
+void DirectoryObject::AddBacktrace(Json::Value& object,
+ cmListFileBacktrace const& bt)
+{
+ if (JBTIndex backtrace = this->Backtraces.Add(bt)) {
+ object["backtrace"] = backtrace.Index;
+ }
+}
+
+Json::Value DirectoryObject::DumpPaths()
+{
+ Json::Value paths = Json::objectValue;
+
+ std::string const& sourceDir = this->LG->GetCurrentSourceDirectory();
+ paths["source"] = RelativeIfUnder(this->TopSource, sourceDir);
+
+ std::string const& buildDir = this->LG->GetCurrentBinaryDirectory();
+ paths["build"] = RelativeIfUnder(this->TopBuild, buildDir);
+
+ return paths;
+}
+
+Json::Value DirectoryObject::DumpInstallers()
+{
+ Json::Value installers = Json::arrayValue;
+ for (const auto& gen : this->LG->GetMakefile()->GetInstallGenerators()) {
+ Json::Value installer = this->DumpInstaller(gen.get());
+ if (!installer.empty()) {
+ installers.append(std::move(installer)); // NOLINT(*)
+ }
+ }
+ return installers;
+}
+
+Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen)
+{
+ Json::Value installer = Json::objectValue;
+
+ // Exclude subdirectory installers. They are implementation details.
+ if (dynamic_cast<cmInstallSubdirectoryGenerator*>(gen)) {
+ return installer;
+ }
+
+ // Exclude installers not used in this configuration.
+ if (!gen->InstallsForConfig(this->Config)) {
+ return installer;
+ }
+
+ // Add fields specific to each kind of install generator.
+ if (auto* installTarget = dynamic_cast<cmInstallTargetGenerator*>(gen)) {
+ cmInstallTargetGenerator::Files const& files =
+ installTarget->GetFiles(this->Config);
+ if (files.From.empty()) {
+ return installer;
+ }
+
+ installer["type"] = "target";
+ installer["destination"] = installTarget->GetDestination(this->Config);
+ installer["targetId"] =
+ TargetId(installTarget->GetTarget(), this->TopBuild);
+ installer["targetIndex"] =
+ this->TargetIndexMap[installTarget->GetTarget()];
+
+ std::string fromDir = files.FromDir;
+ if (!fromDir.empty()) {
+ fromDir.push_back('/');
+ }
+
+ std::string toDir = files.ToDir;
+ if (!toDir.empty()) {
+ toDir.push_back('/');
+ }
+
+ Json::Value paths = Json::arrayValue;
+ for (size_t i = 0; i < files.From.size(); ++i) {
+ std::string const& fromPath = cmStrCat(fromDir, files.From[i]);
+ std::string const& toPath = cmStrCat(toDir, files.To[i]);
+ paths.append(this->DumpInstallerPath(this->TopBuild, fromPath, toPath));
+ }
+ installer["paths"] = std::move(paths);
+
+ if (installTarget->GetOptional()) {
+ installer["isOptional"] = true;
+ }
+
+ if (installTarget->IsImportLibrary()) {
+ installer["targetIsImportLibrary"] = true;
+ }
+
+ switch (files.NamelinkMode) {
+ case cmInstallTargetGenerator::NamelinkModeNone:
+ break;
+ case cmInstallTargetGenerator::NamelinkModeOnly:
+ installer["targetInstallNamelink"] = "only";
+ break;
+ case cmInstallTargetGenerator::NamelinkModeSkip:
+ installer["targetInstallNamelink"] = "skip";
+ break;
+ }
+
+ // FIXME: Parse FilePermissions to provide structured information.
+ // FIXME: Thread EXPORT name through from install() call.
+ } else if (auto* installFiles =
+ dynamic_cast<cmInstallFilesGenerator*>(gen)) {
+ std::vector<std::string> const& files =
+ installFiles->GetFiles(this->Config);
+ if (files.empty()) {
+ return installer;
+ }
+
+ installer["type"] = "file";
+ installer["destination"] = installFiles->GetDestination(this->Config);
+ Json::Value paths = Json::arrayValue;
+ std::string const& rename = installFiles->GetRename(this->Config);
+ if (!rename.empty() && files.size() == 1) {
+ paths.append(this->DumpInstallerPath(this->TopSource, files[0], rename));
+ } else {
+ for (std::string const& file : installFiles->GetFiles(this->Config)) {
+ paths.append(RelativeIfUnder(this->TopSource, file));
+ }
+ }
+ installer["paths"] = std::move(paths);
+ if (installFiles->GetOptional()) {
+ installer["isOptional"] = true;
+ }
+ // FIXME: Parse FilePermissions to provide structured information.
+ } else if (auto* installDir =
+ dynamic_cast<cmInstallDirectoryGenerator*>(gen)) {
+ std::vector<std::string> const& dirs =
+ installDir->GetDirectories(this->Config);
+ if (dirs.empty()) {
+ return installer;
+ }
+
+ installer["type"] = "directory";
+ installer["destination"] = installDir->GetDestination(this->Config);
+ Json::Value paths = Json::arrayValue;
+ for (std::string const& dir : dirs) {
+ if (cmHasLiteralSuffix(dir, "/")) {
+ paths.append(this->DumpInstallerPath(
+ this->TopSource, dir.substr(0, dir.size() - 1), "."));
+ } else {
+ paths.append(this->DumpInstallerPath(
+ this->TopSource, dir, cmSystemTools::GetFilenameName(dir)));
+ }
+ }
+ installer["paths"] = std::move(paths);
+ if (installDir->GetOptional()) {
+ installer["isOptional"] = true;
+ }
+ // FIXME: Parse FilePermissions, DirPermissions, and LiteralArguments.
+ // to provide structured information.
+ } else if (auto* installExport =
+ dynamic_cast<cmInstallExportGenerator*>(gen)) {
+ installer["type"] = "export";
+ installer["destination"] = installExport->GetDestination();
+ cmExportSet* exportSet = installExport->GetExportSet();
+ installer["exportName"] = exportSet->GetName();
+ installer["exportTargets"] = this->DumpInstallerExportTargets(exportSet);
+ Json::Value paths = Json::arrayValue;
+ paths.append(
+ RelativeIfUnder(this->TopBuild, installExport->GetMainImportFile()));
+ installer["paths"] = std::move(paths);
+ } else if (auto* installScript =
+ dynamic_cast<cmInstallScriptGenerator*>(gen)) {
+ if (installScript->IsCode()) {
+ installer["type"] = "code";
+ } else {
+ installer["type"] = "script";
+ installer["scriptFile"] = RelativeIfUnder(
+ this->TopSource, installScript->GetScript(this->Config));
+ }
+ }
+
+ // Add fields common to all install generators.
+ installer["component"] = gen->GetComponent();
+ if (gen->GetExcludeFromAll()) {
+ installer["isExcludeFromAll"] = true;
+ }
+ this->AddBacktrace(installer, gen->GetBacktrace());
+
+ return installer;
+}
+
+Json::Value DirectoryObject::DumpInstallerExportTargets(cmExportSet* exp)
+{
+ Json::Value targets = Json::arrayValue;
+ for (auto const& targetExport : exp->GetTargetExports()) {
+ Json::Value target = Json::objectValue;
+ target["id"] = TargetId(targetExport->Target, this->TopBuild);
+ target["index"] = this->TargetIndexMap[targetExport->Target];
+ targets.append(std::move(target)); // NOLINT(*)
+ }
+ return targets;
+}
+
+Json::Value DirectoryObject::DumpInstallerPath(std::string const& top,
+ std::string const& fromPathIn,
+ std::string const& toPath)
+{
+ Json::Value installPath;
+
+ std::string fromPath = RelativeIfUnder(top, fromPathIn);
+
+ // If toPath is the last component of fromPath, use just fromPath.
+ if (toPath.find_first_of('/') == std::string::npos &&
+ cmHasSuffix(fromPath, toPath) &&
+ (fromPath.size() == toPath.size() ||
+ fromPath[fromPath.size() - toPath.size() - 1] == '/')) {
+ installPath = fromPath;
+ } else {
+ installPath = Json::objectValue;
+ installPath["from"] = fromPath;
+ installPath["to"] = toPath;
+ }
+
+ return installPath;
+}
+
+Target::Target(cmGeneratorTarget* gt, std::string const& config)
+ : GT(gt)
+ , Config(config)
+ , TopSource(gt->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
+ , TopBuild(
+ gt->GetGlobalGenerator()->GetCMakeInstance()->GetHomeOutputDirectory())
+ , SourceGroupsLocal(this->GT->Makefile->GetSourceGroups())
+ , Backtraces(this->TopSource)
+{
+}
+
+Json::Value Target::Dump()
+{
+ Json::Value target = Json::objectValue;
+
+ cmStateEnums::TargetType const type = this->GT->GetType();
+
+ target["name"] = this->GT->GetName();
+ target["type"] = cmState::GetTargetTypeName(type);
+ target["id"] = TargetId(this->GT, this->TopBuild);
+ target["paths"] = this->DumpPaths();
+ if (this->GT->Target->GetIsGeneratorProvided()) {
+ target["isGeneratorProvided"] = true;
+ }
+
+ this->AddBacktrace(target, this->GT->GetBacktrace());
+
+ if (this->GT->Target->GetHaveInstallRule()) {
+ target["install"] = this->DumpInstall();
+ }
+
+ if (this->GT->HaveWellDefinedOutputFiles()) {
+ Json::Value artifacts = this->DumpArtifacts();
+ if (!artifacts.empty()) {
+ target["artifacts"] = std::move(artifacts);
+ }
+ }
+
+ if (type == cmStateEnums::EXECUTABLE ||
+ type == cmStateEnums::SHARED_LIBRARY ||
+ type == cmStateEnums::MODULE_LIBRARY) {
+ target["nameOnDisk"] = this->GT->GetFullName(this->Config);
+ target["link"] = this->DumpLink();
+ } else if (type == cmStateEnums::STATIC_LIBRARY) {
+ target["nameOnDisk"] = this->GT->GetFullName(this->Config);
+ target["archive"] = this->DumpArchive();
+ }
+
+ Json::Value dependencies = this->DumpDependencies();
+ if (!dependencies.empty()) {
+ target["dependencies"] = dependencies;
+ }
+
+ {
+ this->ProcessLanguages();
+
+ target["sources"] = this->DumpSources();
+
+ Json::Value folder = this->DumpFolder();
+ if (!folder.isNull()) {
+ target["folder"] = std::move(folder);
+ }
+
+ Json::Value sourceGroups = this->DumpSourceGroups();
+ if (!sourceGroups.empty()) {
+ target["sourceGroups"] = std::move(sourceGroups);
+ }
+
+ Json::Value compileGroups = this->DumpCompileGroups();
+ if (!compileGroups.empty()) {
+ target["compileGroups"] = std::move(compileGroups);
+ }
+ }
+
+ target["backtraceGraph"] = this->Backtraces.Dump();
+
+ return target;
+}
+
+void Target::ProcessLanguages()
+{
+ std::set<std::string> languages;
+ this->GT->GetLanguages(languages, this->Config);
+ for (std::string const& lang : languages) {
+ this->ProcessLanguage(lang);
+ }
+}
+
+void Target::ProcessLanguage(std::string const& lang)
+{
+ CompileData& cd = this->CompileDataMap[lang];
+ cd.Language = lang;
+ if (cmProp sysrootCompile =
+ this->GT->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE")) {
+ cd.Sysroot = *sysrootCompile;
+ } else if (cmProp sysroot =
+ this->GT->Makefile->GetDefinition("CMAKE_SYSROOT")) {
+ cd.Sysroot = *sysroot;
+ }
+ cmLocalGenerator* lg = this->GT->GetLocalGenerator();
+ {
+ // FIXME: Add flags from end section of ExpandRuleVariable,
+ // which may need to be factored out.
+ std::vector<BT<std::string>> flags =
+ lg->GetTargetCompileFlags(this->GT, this->Config, lang);
+
+ cd.Flags.reserve(flags.size());
+ for (const BT<std::string>& f : flags) {
+ cd.Flags.emplace_back(this->ToJBT(f));
+ }
+ }
+ std::set<BT<std::string>> defines =
+ lg->GetTargetDefines(this->GT, this->Config, lang);
+ cd.Defines.reserve(defines.size());
+ for (BT<std::string> const& d : defines) {
+ cd.Defines.emplace_back(this->ToJBT(d));
+ }
+ std::vector<BT<std::string>> includePathList =
+ lg->GetIncludeDirectories(this->GT, lang, this->Config);
+ for (BT<std::string> const& i : includePathList) {
+ cd.Includes.emplace_back(
+ this->ToJBT(i),
+ this->GT->IsSystemIncludeDirectory(i.Value, this->Config, lang));
+ }
+ std::vector<BT<std::string>> precompileHeaders =
+ this->GT->GetPrecompileHeaders(this->Config, lang);
+ for (BT<std::string> const& pch : precompileHeaders) {
+ cd.PrecompileHeaders.emplace_back(this->ToJBT(pch));
+ }
+ BTs<std::string> const* languageStandard =
+ this->GT->GetLanguageStandardProperty(lang, this->Config);
+ if (languageStandard) {
+ cd.LanguageStandard = this->ToJBTs(*languageStandard);
+ }
+}
+
+Json::ArrayIndex Target::AddSourceGroup(cmSourceGroup* sg, Json::ArrayIndex si)
+{
+ auto i = this->SourceGroupsMap.find(sg);
+ if (i == this->SourceGroupsMap.end()) {
+ auto sgIndex = static_cast<Json::ArrayIndex>(this->SourceGroups.size());
+ i = this->SourceGroupsMap.emplace(sg, sgIndex).first;
+ SourceGroup g;
+ g.Name = sg->GetFullName();
+ this->SourceGroups.push_back(std::move(g));
+ }
+ this->SourceGroups[i->second].SourceIndexes.append(si);
+ return i->second;
+}
+
+CompileData Target::BuildCompileData(cmSourceFile* sf)
+{
+ CompileData fd;
+
+ fd.Language = sf->GetOrDetermineLanguage();
+ if (fd.Language.empty()) {
+ return fd;
+ }
+
+ cmLocalGenerator* lg = this->GT->GetLocalGenerator();
+ cmGeneratorExpressionInterpreter genexInterpreter(lg, this->Config, this->GT,
+ fd.Language);
+
+ const std::string COMPILE_FLAGS("COMPILE_FLAGS");
+ if (cmProp cflags = sf->GetProperty(COMPILE_FLAGS)) {
+ std::string flags = genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS);
+ fd.Flags.emplace_back(std::move(flags), JBTIndex());
+ }
+ const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
+ for (BT<std::string> tmpOpt : sf->GetCompileOptions()) {
+ tmpOpt.Value = genexInterpreter.Evaluate(tmpOpt.Value, COMPILE_OPTIONS);
+ // After generator evaluation we need to use the AppendCompileOptions
+ // method so we handle situations where backtrace entries have lists
+ // and properly escape flags.
+ std::string tmp;
+ lg->AppendCompileOptions(tmp, tmpOpt.Value);
+ BT<std::string> opt(tmp, tmpOpt.Backtrace);
+ fd.Flags.emplace_back(this->ToJBT(opt));
+ }
+
+ // Add precompile headers compile options.
+ std::vector<std::string> architectures;
+ this->GT->GetAppleArchs(this->Config, architectures);
+ if (architectures.empty()) {
+ architectures.emplace_back();
+ }
+
+ std::unordered_map<std::string, std::string> pchSources;
+ for (const std::string& arch : architectures) {
+ const std::string pchSource =
+ this->GT->GetPchSource(this->Config, fd.Language, arch);
+ if (!pchSource.empty()) {
+ pchSources.insert(std::make_pair(pchSource, arch));
+ }
+ }
+
+ if (!pchSources.empty() && !sf->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
+ std::string pchOptions;
+ auto pchIt = pchSources.find(sf->ResolveFullPath());
+ if (pchIt != pchSources.end()) {
+ pchOptions = this->GT->GetPchCreateCompileOptions(
+ this->Config, fd.Language, pchIt->second);
+ } else {
+ pchOptions =
+ this->GT->GetPchUseCompileOptions(this->Config, fd.Language);
+ }
+
+ BT<std::string> tmpOpt(pchOptions);
+ tmpOpt.Value = genexInterpreter.Evaluate(tmpOpt.Value, COMPILE_OPTIONS);
+
+ // After generator evaluation we need to use the AppendCompileOptions
+ // method so we handle situations where backtrace entries have lists
+ // and properly escape flags.
+ std::string tmp;
+ lg->AppendCompileOptions(tmp, tmpOpt.Value);
+ BT<std::string> opt(tmp, tmpOpt.Backtrace);
+ fd.Flags.emplace_back(this->ToJBT(opt));
+ }
+
+ // Add include directories from source file properties.
+ {
+ const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
+ for (BT<std::string> tmpInclude : sf->GetIncludeDirectories()) {
+ tmpInclude.Value =
+ genexInterpreter.Evaluate(tmpInclude.Value, INCLUDE_DIRECTORIES);
+
+ // After generator evaluation we need to use the AppendIncludeDirectories
+ // method so we handle situations where backtrace entries have lists.
+ std::vector<std::string> tmp;
+ lg->AppendIncludeDirectories(tmp, tmpInclude.Value, *sf);
+ for (std::string& i : tmp) {
+ bool const isSystemInclude =
+ this->GT->IsSystemIncludeDirectory(i, this->Config, fd.Language);
+ BT<std::string> include(i, tmpInclude.Backtrace);
+ fd.Includes.emplace_back(this->ToJBT(include), isSystemInclude);
+ }
+ }
+ }
+
+ const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
+ std::set<BT<std::string>> fileDefines;
+ for (BT<std::string> tmpDef : sf->GetCompileDefinitions()) {
+ tmpDef.Value =
+ genexInterpreter.Evaluate(tmpDef.Value, COMPILE_DEFINITIONS);
+
+ // After generator evaluation we need to use the AppendDefines method
+ // so we handle situations where backtrace entries have lists.
+ std::set<std::string> tmp;
+ lg->AppendDefines(tmp, tmpDef.Value);
+ for (const std::string& i : tmp) {
+ BT<std::string> def(i, tmpDef.Backtrace);
+ fileDefines.insert(def);
+ }
+ }
+
+ std::set<std::string> configFileDefines;
+ const std::string defPropName =
+ "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(this->Config);
+ if (cmProp config_defs = sf->GetProperty(defPropName)) {
+ lg->AppendDefines(
+ configFileDefines,
+ genexInterpreter.Evaluate(*config_defs, COMPILE_DEFINITIONS));
+ }
+
+ fd.Defines.reserve(fileDefines.size() + configFileDefines.size());
+
+ for (BT<std::string> const& def : fileDefines) {
+ fd.Defines.emplace_back(this->ToJBT(def));
+ }
+
+ for (std::string const& d : configFileDefines) {
+ fd.Defines.emplace_back(d, JBTIndex());
+ }
+
+ return fd;
+}
+
+CompileData Target::MergeCompileData(CompileData const& fd)
+{
+ CompileData cd;
+ cd.Language = fd.Language;
+ if (cd.Language.empty()) {
+ return cd;
+ }
+ CompileData const& td = this->CompileDataMap.at(cd.Language);
+
+ // All compile groups share the sysroot of the target.
+ cd.Sysroot = td.Sysroot;
+
+ // All compile groups share the precompile headers of the target.
+ cd.PrecompileHeaders = td.PrecompileHeaders;
+
+ // All compile groups share the language standard of the target.
+ cd.LanguageStandard = td.LanguageStandard;
+
+ // Use target-wide flags followed by source-specific flags.
+ cd.Flags.reserve(td.Flags.size() + fd.Flags.size());
+ cd.Flags.insert(cd.Flags.end(), td.Flags.begin(), td.Flags.end());
+ cd.Flags.insert(cd.Flags.end(), fd.Flags.begin(), fd.Flags.end());
+
+ // Use source-specific includes followed by target-wide includes.
+ cd.Includes.reserve(fd.Includes.size() + td.Includes.size());
+ cd.Includes.insert(cd.Includes.end(), fd.Includes.begin(),
+ fd.Includes.end());
+ cd.Includes.insert(cd.Includes.end(), td.Includes.begin(),
+ td.Includes.end());
+
+ // Use target-wide defines followed by source-specific defines.
+ cd.Defines.reserve(td.Defines.size() + fd.Defines.size());
+ cd.Defines.insert(cd.Defines.end(), td.Defines.begin(), td.Defines.end());
+ cd.Defines.insert(cd.Defines.end(), fd.Defines.begin(), fd.Defines.end());
+
+ // De-duplicate defines.
+ std::stable_sort(cd.Defines.begin(), cd.Defines.end(),
+ JBT<std::string>::ValueLess);
+ auto end = std::unique(cd.Defines.begin(), cd.Defines.end(),
+ JBT<std::string>::ValueEq);
+ cd.Defines.erase(end, cd.Defines.end());
+
+ return cd;
+}
+
+Json::ArrayIndex Target::AddSourceCompileGroup(cmSourceFile* sf,
+ Json::ArrayIndex si)
+{
+ CompileData compileData = this->BuildCompileData(sf);
+ auto i = this->CompileGroupMap.find(compileData);
+ if (i == this->CompileGroupMap.end()) {
+ Json::ArrayIndex cgIndex =
+ static_cast<Json::ArrayIndex>(this->CompileGroups.size());
+ i = this->CompileGroupMap.emplace(std::move(compileData), cgIndex).first;
+ CompileGroup g;
+ g.Entry = i;
+ this->CompileGroups.push_back(std::move(g));
+ }
+ this->CompileGroups[i->second].SourceIndexes.append(si);
+ return i->second;
+}
+
+void Target::AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt)
+{
+ if (JBTIndex backtrace = this->Backtraces.Add(bt)) {
+ object["backtrace"] = backtrace.Index;
+ }
+}
+
+void Target::AddBacktrace(Json::Value& object, JBTIndex bt)
+{
+ if (bt) {
+ object["backtrace"] = bt.Index;
+ }
+}
+
+Json::Value Target::DumpPaths()
+{
+ Json::Value paths = Json::objectValue;
+ cmLocalGenerator* lg = this->GT->GetLocalGenerator();
+
+ std::string const& sourceDir = lg->GetCurrentSourceDirectory();
+ paths["source"] = RelativeIfUnder(this->TopSource, sourceDir);
+
+ std::string const& buildDir = lg->GetCurrentBinaryDirectory();
+ paths["build"] = RelativeIfUnder(this->TopBuild, buildDir);
+
+ return paths;
+}
+
+Json::Value Target::DumpSources()
+{
+ Json::Value sources = Json::arrayValue;
+ cmGeneratorTarget::KindedSources const& kinded =
+ this->GT->GetKindedSources(this->Config);
+ for (cmGeneratorTarget::SourceAndKind const& sk : kinded.Sources) {
+ sources.append(this->DumpSource(sk, sources.size()));
+ }
+ return sources;
+}
+
+Json::Value Target::DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
+ Json::ArrayIndex si)
+{
+ Json::Value source = Json::objectValue;
+
+ std::string const path = sk.Source.Value->ResolveFullPath();
+ source["path"] = RelativeIfUnder(this->TopSource, path);
+ if (sk.Source.Value->GetIsGenerated()) {
+ source["isGenerated"] = true;
+ }
+ this->AddBacktrace(source, sk.Source.Backtrace);
+
+ if (cmSourceGroup* sg =
+ this->GT->Makefile->FindSourceGroup(path, this->SourceGroupsLocal)) {
+ source["sourceGroupIndex"] = this->AddSourceGroup(sg, si);
+ }
+
+ switch (sk.Kind) {
+ case cmGeneratorTarget::SourceKindObjectSource: {
+ source["compileGroupIndex"] =
+ this->AddSourceCompileGroup(sk.Source.Value, si);
+ } break;
+ case cmGeneratorTarget::SourceKindAppManifest:
+ case cmGeneratorTarget::SourceKindCertificate:
+ case cmGeneratorTarget::SourceKindCustomCommand:
+ case cmGeneratorTarget::SourceKindExternalObject:
+ case cmGeneratorTarget::SourceKindExtra:
+ case cmGeneratorTarget::SourceKindHeader:
+ case cmGeneratorTarget::SourceKindIDL:
+ case cmGeneratorTarget::SourceKindManifest:
+ case cmGeneratorTarget::SourceKindModuleDefinition:
+ case cmGeneratorTarget::SourceKindResx:
+ case cmGeneratorTarget::SourceKindXaml:
+ case cmGeneratorTarget::SourceKindUnityBatched:
+ break;
+ }
+
+ return source;
+}
+
+Json::Value Target::DumpCompileData(CompileData const& cd)
+{
+ Json::Value result = Json::objectValue;
+
+ if (!cd.Language.empty()) {
+ result["language"] = cd.Language;
+ }
+ if (!cd.Sysroot.empty()) {
+ result["sysroot"] = this->DumpSysroot(cd.Sysroot);
+ }
+ if (!cd.Flags.empty()) {
+ result["compileCommandFragments"] = this->DumpCommandFragments(cd.Flags);
+ }
+ if (!cd.Includes.empty()) {
+ Json::Value includes = Json::arrayValue;
+ for (auto const& i : cd.Includes) {
+ includes.append(this->DumpInclude(i));
+ }
+ result["includes"] = includes;
+ }
+ if (!cd.Defines.empty()) {
+ Json::Value defines = Json::arrayValue;
+ for (JBT<std::string> const& d : cd.Defines) {
+ defines.append(this->DumpDefine(d));
+ }
+ result["defines"] = std::move(defines);
+ }
+ if (!cd.PrecompileHeaders.empty()) {
+ Json::Value precompileHeaders = Json::arrayValue;
+ for (JBT<std::string> const& pch : cd.PrecompileHeaders) {
+ precompileHeaders.append(this->DumpPrecompileHeader(pch));
+ }
+ result["precompileHeaders"] = std::move(precompileHeaders);
+ }
+ if (!cd.LanguageStandard.Value.empty()) {
+ result["languageStandard"] =
+ this->DumpLanguageStandard(cd.LanguageStandard);
+ }
+
+ return result;
+}
+
+Json::Value Target::DumpInclude(CompileData::IncludeEntry const& inc)
+{
+ Json::Value include = Json::objectValue;
+ include["path"] = inc.Path.Value;
+ if (inc.IsSystem) {
+ include["isSystem"] = true;
+ }
+ this->AddBacktrace(include, inc.Path.Backtrace);
+ return include;
+}
+
+Json::Value Target::DumpPrecompileHeader(JBT<std::string> const& header)
+{
+ Json::Value precompileHeader = Json::objectValue;
+ precompileHeader["header"] = header.Value;
+ this->AddBacktrace(precompileHeader, header.Backtrace);
+ return precompileHeader;
+}
+
+Json::Value Target::DumpLanguageStandard(JBTs<std::string> const& standard)
+{
+ Json::Value languageStandard = Json::objectValue;
+ languageStandard["standard"] = standard.Value;
+ if (!standard.Backtraces.empty()) {
+ Json::Value backtraces = Json::arrayValue;
+ for (JBTIndex backtrace : standard.Backtraces) {
+ backtraces.append(backtrace.Index);
+ }
+ languageStandard["backtraces"] = backtraces;
+ }
+ return languageStandard;
+}
+
+Json::Value Target::DumpDefine(JBT<std::string> const& def)
+{
+ Json::Value define = Json::objectValue;
+ define["define"] = def.Value;
+ this->AddBacktrace(define, def.Backtrace);
+ return define;
+}
+
+Json::Value Target::DumpSourceGroups()
+{
+ Json::Value sourceGroups = Json::arrayValue;
+ for (auto& sg : this->SourceGroups) {
+ sourceGroups.append(this->DumpSourceGroup(sg));
+ }
+ return sourceGroups;
+}
+
+Json::Value Target::DumpSourceGroup(SourceGroup& sg)
+{
+ Json::Value group = Json::objectValue;
+ group["name"] = sg.Name;
+ group["sourceIndexes"] = std::move(sg.SourceIndexes);
+ return group;
+}
+
+Json::Value Target::DumpCompileGroups()
+{
+ Json::Value compileGroups = Json::arrayValue;
+ for (auto& cg : this->CompileGroups) {
+ compileGroups.append(this->DumpCompileGroup(cg));
+ }
+ return compileGroups;
+}
+
+Json::Value Target::DumpCompileGroup(CompileGroup& cg)
+{
+ Json::Value group =
+ this->DumpCompileData(this->MergeCompileData(cg.Entry->first));
+ group["sourceIndexes"] = std::move(cg.SourceIndexes);
+ return group;
+}
+
+Json::Value Target::DumpSysroot(std::string const& path)
+{
+ Json::Value sysroot = Json::objectValue;
+ sysroot["path"] = path;
+ return sysroot;
+}
+
+Json::Value Target::DumpInstall()
+{
+ Json::Value install = Json::objectValue;
+ install["prefix"] = this->DumpInstallPrefix();
+ install["destinations"] = this->DumpInstallDestinations();
+ return install;
+}
+
+Json::Value Target::DumpInstallPrefix()
+{
+ Json::Value prefix = Json::objectValue;
+ std::string p =
+ this->GT->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
+ cmSystemTools::ConvertToUnixSlashes(p);
+ prefix["path"] = p;
+ return prefix;
+}
+
+Json::Value Target::DumpInstallDestinations()
+{
+ Json::Value destinations = Json::arrayValue;
+ auto installGens = this->GT->Target->GetInstallGenerators();
+ for (auto* itGen : installGens) {
+ destinations.append(this->DumpInstallDestination(itGen));
+ }
+ return destinations;
+}
+
+Json::Value Target::DumpInstallDestination(cmInstallTargetGenerator* itGen)
+{
+ Json::Value destination = Json::objectValue;
+ destination["path"] = itGen->GetDestination(this->Config);
+ this->AddBacktrace(destination, itGen->GetBacktrace());
+ return destination;
+}
+
+Json::Value Target::DumpArtifacts()
+{
+ Json::Value artifacts = Json::arrayValue;
+
+ // Object libraries have only object files as artifacts.
+ if (this->GT->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ if (!this->GT->GetGlobalGenerator()->HasKnownObjectFileLocation(nullptr)) {
+ return artifacts;
+ }
+ std::vector<cmSourceFile const*> objectSources;
+ this->GT->GetObjectSources(objectSources, this->Config);
+ std::string const obj_dir = this->GT->GetObjectDirectory(this->Config);
+ for (cmSourceFile const* sf : objectSources) {
+ const std::string& obj = this->GT->GetObjectName(sf);
+ Json::Value artifact = Json::objectValue;
+ artifact["path"] = RelativeIfUnder(this->TopBuild, obj_dir + obj);
+ artifacts.append(std::move(artifact)); // NOLINT(*)
+ }
+ return artifacts;
+ }
+
+ // Other target types always have a "main" artifact.
+ {
+ Json::Value artifact = Json::objectValue;
+ artifact["path"] =
+ RelativeIfUnder(this->TopBuild,
+ this->GT->GetFullPath(
+ this->Config, cmStateEnums::RuntimeBinaryArtifact));
+ artifacts.append(std::move(artifact)); // NOLINT(*)
+ }
+
+ // Add Windows-specific artifacts produced by the linker.
+ if (this->GT->HasImportLibrary(this->Config)) {
+ Json::Value artifact = Json::objectValue;
+ artifact["path"] =
+ RelativeIfUnder(this->TopBuild,
+ this->GT->GetFullPath(
+ this->Config, cmStateEnums::ImportLibraryArtifact));
+ artifacts.append(std::move(artifact)); // NOLINT(*)
+ }
+ if (this->GT->IsDLLPlatform() &&
+ this->GT->GetType() != cmStateEnums::STATIC_LIBRARY) {
+ cmGeneratorTarget::OutputInfo const* output =
+ this->GT->GetOutputInfo(this->Config);
+ if (output && !output->PdbDir.empty()) {
+ Json::Value artifact = Json::objectValue;
+ artifact["path"] = RelativeIfUnder(this->TopBuild,
+ output->PdbDir + '/' +
+ this->GT->GetPDBName(this->Config));
+ artifacts.append(std::move(artifact)); // NOLINT(*)
+ }
+ }
+ return artifacts;
+}
+
+Json::Value Target::DumpLink()
+{
+ Json::Value link = Json::objectValue;
+ std::string lang = this->GT->GetLinkerLanguage(this->Config);
+ link["language"] = lang;
+ {
+ Json::Value commandFragments = this->DumpLinkCommandFragments();
+ if (!commandFragments.empty()) {
+ link["commandFragments"] = std::move(commandFragments);
+ }
+ }
+ if (cmProp sysrootLink =
+ this->GT->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
+ link["sysroot"] = this->DumpSysroot(*sysrootLink);
+ } else if (cmProp sysroot =
+ this->GT->Makefile->GetDefinition("CMAKE_SYSROOT")) {
+ link["sysroot"] = this->DumpSysroot(*sysroot);
+ }
+ if (this->GT->IsIPOEnabled(lang, this->Config)) {
+ link["lto"] = true;
+ }
+ return link;
+}
+
+Json::Value Target::DumpArchive()
+{
+ Json::Value archive = Json::objectValue;
+ {
+ // The "link" fragments not relevant to static libraries are empty.
+ Json::Value commandFragments = this->DumpLinkCommandFragments();
+ if (!commandFragments.empty()) {
+ archive["commandFragments"] = std::move(commandFragments);
+ }
+ }
+ std::string lang = this->GT->GetLinkerLanguage(this->Config);
+ if (this->GT->IsIPOEnabled(lang, this->Config)) {
+ archive["lto"] = true;
+ }
+ return archive;
+}
+
+Json::Value Target::DumpLinkCommandFragments()
+{
+ Json::Value linkFragments = Json::arrayValue;
+
+ std::string linkLanguageFlags;
+ std::vector<BT<std::string>> linkFlags;
+ std::string frameworkPath;
+ std::vector<BT<std::string>> linkPath;
+ std::vector<BT<std::string>> linkLibs;
+ cmLocalGenerator* lg = this->GT->GetLocalGenerator();
+ cmLinkLineComputer linkLineComputer(lg,
+ lg->GetStateSnapshot().GetDirectory());
+ lg->GetTargetFlags(&linkLineComputer, this->Config, linkLibs,
+ linkLanguageFlags, linkFlags, frameworkPath, linkPath,
+ this->GT);
+ linkLanguageFlags = cmTrimWhitespace(linkLanguageFlags);
+ frameworkPath = cmTrimWhitespace(frameworkPath);
+
+ if (!linkLanguageFlags.empty()) {
+ linkFragments.append(
+ this->DumpCommandFragment(std::move(linkLanguageFlags), "flags"));
+ }
+
+ if (!linkFlags.empty()) {
+ for (BT<std::string> frag : linkFlags) {
+ frag.Value = cmTrimWhitespace(frag.Value);
+ linkFragments.append(
+ this->DumpCommandFragment(this->ToJBT(frag), "flags"));
+ }
+ }
+
+ if (!frameworkPath.empty()) {
+ linkFragments.append(
+ this->DumpCommandFragment(std::move(frameworkPath), "frameworkPath"));
+ }
+
+ if (!linkPath.empty()) {
+ for (BT<std::string> frag : linkPath) {
+ frag.Value = cmTrimWhitespace(frag.Value);
+ linkFragments.append(
+ this->DumpCommandFragment(this->ToJBT(frag), "libraryPath"));
+ }
+ }
+
+ if (!linkLibs.empty()) {
+ for (BT<std::string> frag : linkLibs) {
+ frag.Value = cmTrimWhitespace(frag.Value);
+ linkFragments.append(
+ this->DumpCommandFragment(this->ToJBT(frag), "libraries"));
+ }
+ }
+
+ return linkFragments;
+}
+
+Json::Value Target::DumpCommandFragments(
+ std::vector<JBT<std::string>> const& frags)
+{
+ Json::Value commandFragments = Json::arrayValue;
+ for (JBT<std::string> const& f : frags) {
+ commandFragments.append(this->DumpCommandFragment(f));
+ }
+ return commandFragments;
+}
+
+Json::Value Target::DumpCommandFragment(JBT<std::string> const& frag,
+ std::string const& role)
+{
+ Json::Value fragment = Json::objectValue;
+ fragment["fragment"] = frag.Value;
+ if (!role.empty()) {
+ fragment["role"] = role;
+ }
+ this->AddBacktrace(fragment, frag.Backtrace);
+ return fragment;
+}
+
+Json::Value Target::DumpDependencies()
+{
+ Json::Value dependencies = Json::arrayValue;
+ cmGlobalGenerator* gg = this->GT->GetGlobalGenerator();
+ for (cmTargetDepend const& td : gg->GetTargetDirectDepends(this->GT)) {
+ dependencies.append(this->DumpDependency(td));
+ }
+ return dependencies;
+}
+
+Json::Value Target::DumpDependency(cmTargetDepend const& td)
+{
+ Json::Value dependency = Json::objectValue;
+ dependency["id"] = TargetId(td, this->TopBuild);
+ this->AddBacktrace(dependency, td.GetBacktrace());
+ return dependency;
+}
+
+Json::Value Target::DumpFolder()
+{
+ Json::Value folder;
+ if (cmProp f = this->GT->GetProperty("FOLDER")) {
+ folder = Json::objectValue;
+ folder["name"] = *f;
+ }
+ return folder;
+}
+}
+
+Json::Value cmFileAPICodemodelDump(cmFileAPI& fileAPI, unsigned long version)
+{
+ Codemodel codemodel(fileAPI, version);
+ return codemodel.Dump();
+}
diff --git a/Source/cmFileAPICodemodel.h b/Source/cmFileAPICodemodel.h
new file mode 100644
index 0000000..263f675
--- /dev/null
+++ b/Source/cmFileAPICodemodel.h
@@ -0,0 +1,12 @@
+/* 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 <cm3p/json/value.h>
+
+class cmFileAPI;
+
+extern Json::Value cmFileAPICodemodelDump(cmFileAPI& fileAPI,
+ unsigned long version);
diff --git a/Source/cmFileAPIToolchains.cxx b/Source/cmFileAPIToolchains.cxx
new file mode 100644
index 0000000..722c114
--- /dev/null
+++ b/Source/cmFileAPIToolchains.cxx
@@ -0,0 +1,151 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileAPIToolchains.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm3p/json/value.h>
+
+#include "cmFileAPI.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmake.h"
+
+namespace {
+
+struct ToolchainVariable
+{
+ std::string ObjectKey;
+ std::string VariableSuffix;
+ bool IsList;
+};
+
+class Toolchains
+{
+ cmFileAPI& FileAPI;
+ unsigned long Version;
+
+ static const std::vector<ToolchainVariable> CompilerVariables;
+ static const std::vector<ToolchainVariable> CompilerImplicitVariables;
+ static const ToolchainVariable SourceFileExtensionsVariable;
+
+ Json::Value DumpToolchains();
+ Json::Value DumpToolchain(std::string const& lang);
+ Json::Value DumpToolchainVariables(
+ cmMakefile const* mf, std::string const& lang,
+ std::vector<ToolchainVariable> const& variables);
+ void DumpToolchainVariable(cmMakefile const* mf, Json::Value& object,
+ std::string const& lang,
+ ToolchainVariable const& variable);
+
+public:
+ Toolchains(cmFileAPI& fileAPI, unsigned long version);
+ Json::Value Dump();
+};
+
+const std::vector<ToolchainVariable> Toolchains::CompilerVariables{
+ { "path", "COMPILER", false },
+ { "id", "COMPILER_ID", false },
+ { "version", "COMPILER_VERSION", false },
+ { "target", "COMPILER_TARGET", false },
+};
+
+const std::vector<ToolchainVariable> Toolchains::CompilerImplicitVariables{
+ { "includeDirectories", "IMPLICIT_INCLUDE_DIRECTORIES", true },
+ { "linkDirectories", "IMPLICIT_LINK_DIRECTORIES", true },
+ { "linkFrameworkDirectories", "IMPLICIT_LINK_FRAMEWORK_DIRECTORIES", true },
+ { "linkLibraries", "IMPLICIT_LINK_LIBRARIES", true },
+};
+
+const ToolchainVariable Toolchains::SourceFileExtensionsVariable{
+ "sourceFileExtensions", "SOURCE_FILE_EXTENSIONS", true
+};
+
+Toolchains::Toolchains(cmFileAPI& fileAPI, unsigned long version)
+ : FileAPI(fileAPI)
+ , Version(version)
+{
+ static_cast<void>(this->Version);
+}
+
+Json::Value Toolchains::Dump()
+{
+ Json::Value toolchains = Json::objectValue;
+ toolchains["toolchains"] = this->DumpToolchains();
+ return toolchains;
+}
+
+Json::Value Toolchains::DumpToolchains()
+{
+ Json::Value toolchains = Json::arrayValue;
+
+ for (std::string const& lang :
+ this->FileAPI.GetCMakeInstance()->GetState()->GetEnabledLanguages()) {
+ toolchains.append(this->DumpToolchain(lang));
+ }
+
+ return toolchains;
+}
+
+Json::Value Toolchains::DumpToolchain(std::string const& lang)
+{
+ const auto& mf =
+ this->FileAPI.GetCMakeInstance()->GetGlobalGenerator()->GetMakefiles()[0];
+ Json::Value toolchain = Json::objectValue;
+ toolchain["language"] = lang;
+ toolchain["compiler"] =
+ this->DumpToolchainVariables(mf.get(), lang, CompilerVariables);
+ toolchain["compiler"]["implicit"] =
+ this->DumpToolchainVariables(mf.get(), lang, CompilerImplicitVariables);
+ this->DumpToolchainVariable(mf.get(), toolchain, lang,
+ SourceFileExtensionsVariable);
+ return toolchain;
+}
+
+Json::Value Toolchains::DumpToolchainVariables(
+ cmMakefile const* mf, std::string const& lang,
+ std::vector<ToolchainVariable> const& variables)
+{
+ Json::Value object = Json::objectValue;
+ for (const auto& variable : variables) {
+ this->DumpToolchainVariable(mf, object, lang, variable);
+ }
+ return object;
+}
+
+void Toolchains::DumpToolchainVariable(cmMakefile const* mf,
+ Json::Value& object,
+ std::string const& lang,
+ ToolchainVariable const& variable)
+{
+ std::string const variableName =
+ cmStrCat("CMAKE_", lang, "_", variable.VariableSuffix);
+
+ if (variable.IsList) {
+ std::vector<std::string> values;
+ if (mf->GetDefExpandList(variableName, values)) {
+ Json::Value jsonArray = Json::arrayValue;
+ for (std::string const& value : values) {
+ jsonArray.append(value);
+ }
+ object[variable.ObjectKey] = jsonArray;
+ }
+ } else {
+ cmProp def = mf->GetDefinition(variableName);
+ if (def) {
+ object[variable.ObjectKey] = *def;
+ }
+ }
+}
+}
+
+Json::Value cmFileAPIToolchainsDump(cmFileAPI& fileAPI, unsigned long version)
+{
+ Toolchains toolchains(fileAPI, version);
+ return toolchains.Dump();
+}
diff --git a/Source/cmFileAPIToolchains.h b/Source/cmFileAPIToolchains.h
new file mode 100644
index 0000000..c188807
--- /dev/null
+++ b/Source/cmFileAPIToolchains.h
@@ -0,0 +1,12 @@
+/* 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 <cm3p/json/value.h>
+
+class cmFileAPI;
+
+extern Json::Value cmFileAPIToolchainsDump(cmFileAPI& fileAPI,
+ unsigned long version);
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
new file mode 100644
index 0000000..a06ed48
--- /dev/null
+++ b/Source/cmFileCommand.cxx
@@ -0,0 +1,3735 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileCommand.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <map>
+#include <set>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include <cm3p/kwiml/int.h>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cm_sys_stat.h"
+
+#include "cmAlgorithms.h"
+#include "cmArgumentParser.h"
+#include "cmCMakePath.h"
+#include "cmCryptoHash.h"
+#include "cmExecutionStatus.h"
+#include "cmFSPermissions.h"
+#include "cmFileCopier.h"
+#include "cmFileInstaller.h"
+#include "cmFileLockPool.h"
+#include "cmFileTimes.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGlobalGenerator.h"
+#include "cmHexFileConverter.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmNewLineStyle.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmRuntimeDependencyArchive.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSubcommandTable.h"
+#include "cmSystemTools.h"
+#include "cmTimestamp.h"
+#include "cmWorkingDirectory.h"
+#include "cmake.h"
+
+#if !defined(CMAKE_BOOTSTRAP)
+# include <cm3p/curl/curl.h>
+
+# include "cmCurl.h"
+# include "cmFileLockResult.h"
+#endif
+
+#if defined(CMake_USE_ELF_PARSER)
+# include "cmELF.h"
+#endif
+
+#if defined(_WIN32)
+# include <windows.h>
+#endif
+
+namespace {
+
+#if defined(_WIN32)
+// libcurl doesn't support file:// urls for unicode filenames on Windows.
+// Convert string from UTF-8 to ACP if this is a file:// URL.
+std::string fix_file_url_windows(const std::string& url)
+{
+ std::string ret = url;
+ if (strncmp(url.c_str(), "file://", 7) == 0) {
+ std::wstring wurl = cmsys::Encoding::ToWide(url);
+ if (!wurl.empty()) {
+ int mblen =
+ WideCharToMultiByte(CP_ACP, 0, wurl.c_str(), -1, NULL, 0, NULL, NULL);
+ if (mblen > 0) {
+ std::vector<char> chars(mblen);
+ mblen = WideCharToMultiByte(CP_ACP, 0, wurl.c_str(), -1, &chars[0],
+ mblen, NULL, NULL);
+ if (mblen > 0) {
+ ret = &chars[0];
+ }
+ }
+ }
+ }
+ return ret;
+}
+#endif
+
+bool HandleWriteImpl(std::vector<std::string> const& args, bool append,
+ cmExecutionStatus& status)
+{
+ auto i = args.begin();
+
+ i++; // Get rid of subcommand
+
+ std::string fileName = *i;
+ if (!cmsys::SystemTools::FileIsFullPath(*i)) {
+ fileName =
+ cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', *i);
+ }
+
+ i++;
+
+ if (!status.GetMakefile().CanIWriteThisFile(fileName)) {
+ std::string e =
+ "attempted to write a file: " + fileName + " into a source directory.";
+ status.SetError(e);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ std::string dir = cmSystemTools::GetFilenamePath(fileName);
+ cmSystemTools::MakeDirectory(dir);
+
+ mode_t mode = 0;
+ bool writable = false;
+
+ // Set permissions to writable
+ if (cmSystemTools::GetPermissions(fileName, mode)) {
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ writable = (mode & S_IWRITE) != 0;
+ mode_t newMode = mode | S_IWRITE;
+#else
+ writable = mode & S_IWUSR;
+ mode_t newMode = mode | S_IWUSR | S_IWGRP;
+#endif
+ if (!writable) {
+ cmSystemTools::SetPermissions(fileName, newMode);
+ }
+ }
+ // If GetPermissions fails, pretend like it is ok. File open will fail if
+ // the file is not writable
+ cmsys::ofstream file(fileName.c_str(),
+ append ? std::ios::app : std::ios::out);
+ if (!file) {
+ std::string error =
+ cmStrCat("failed to open for writing (",
+ cmSystemTools::GetLastSystemError(), "):\n ", fileName);
+ status.SetError(error);
+ return false;
+ }
+ std::string message = cmJoin(cmMakeRange(i, args.end()), std::string());
+ file << message;
+ if (!file) {
+ std::string error =
+ cmStrCat("write failed (", cmSystemTools::GetLastSystemError(), "):\n ",
+ fileName);
+ status.SetError(error);
+ return false;
+ }
+ file.close();
+ if (mode && !writable) {
+ cmSystemTools::SetPermissions(fileName, mode);
+ }
+ return true;
+}
+
+bool HandleWriteCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleWriteImpl(args, false, status);
+}
+
+bool HandleAppendCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleWriteImpl(args, true, status);
+}
+
+bool HandleReadCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("READ must be called with at least two additional "
+ "arguments");
+ return false;
+ }
+
+ std::string const& fileNameArg = args[1];
+ std::string const& variable = args[2];
+
+ struct Arguments
+ {
+ std::string Offset;
+ std::string Limit;
+ bool Hex = false;
+ };
+
+ static auto const parser = cmArgumentParser<Arguments>{}
+ .Bind("OFFSET"_s, &Arguments::Offset)
+ .Bind("LIMIT"_s, &Arguments::Limit)
+ .Bind("HEX"_s, &Arguments::Hex);
+
+ Arguments const arguments = parser.Parse(cmMakeRange(args).advance(3));
+
+ std::string fileName = fileNameArg;
+ if (!cmsys::SystemTools::FileIsFullPath(fileName)) {
+ fileName = cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/',
+ fileNameArg);
+ }
+
+// Open the specified file.
+#if defined(_WIN32) || defined(__CYGWIN__)
+ cmsys::ifstream file(fileName.c_str(),
+ arguments.Hex ? (std::ios::binary | std::ios::in)
+ : std::ios::in);
+#else
+ cmsys::ifstream file(fileName.c_str());
+#endif
+
+ if (!file) {
+ std::string error =
+ cmStrCat("failed to open for reading (",
+ cmSystemTools::GetLastSystemError(), "):\n ", fileName);
+ status.SetError(error);
+ return false;
+ }
+
+ // is there a limit?
+ long sizeLimit = -1;
+ if (!arguments.Limit.empty()) {
+ sizeLimit = atoi(arguments.Limit.c_str());
+ }
+
+ // is there an offset?
+ long offset = 0;
+ if (!arguments.Offset.empty()) {
+ offset = atoi(arguments.Offset.c_str());
+ }
+
+ file.seekg(offset, std::ios::beg); // explicit ios::beg for IBM VisualAge 6
+
+ std::string output;
+
+ if (arguments.Hex) {
+ // Convert part of the file into hex code
+ char c;
+ while ((sizeLimit != 0) && (file.get(c))) {
+ char hex[4];
+ sprintf(hex, "%.2x", c & 0xff);
+ output += hex;
+ if (sizeLimit > 0) {
+ sizeLimit--;
+ }
+ }
+ } else {
+ std::string line;
+ bool has_newline = false;
+ while (
+ sizeLimit != 0 &&
+ cmSystemTools::GetLineFromStream(file, line, &has_newline, sizeLimit)) {
+ if (sizeLimit > 0) {
+ sizeLimit = sizeLimit - static_cast<long>(line.size());
+ if (has_newline) {
+ sizeLimit--;
+ }
+ if (sizeLimit < 0) {
+ sizeLimit = 0;
+ }
+ }
+ output += line;
+ if (has_newline) {
+ output += "\n";
+ }
+ }
+ }
+ status.GetMakefile().AddDefinition(variable, output);
+ return true;
+}
+
+bool HandleHashCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ if (args.size() != 3) {
+ status.SetError(
+ cmStrCat(args[0], " requires a file name and output variable"));
+ return false;
+ }
+
+ std::unique_ptr<cmCryptoHash> hash(cmCryptoHash::New(args[0]));
+ if (hash) {
+ std::string out = hash->HashFile(args[1]);
+ if (!out.empty()) {
+ status.GetMakefile().AddDefinition(args[2], out);
+ return true;
+ }
+ status.SetError(cmStrCat(args[0], " failed to read file \"", args[1],
+ "\": ", cmSystemTools::GetLastSystemError()));
+ }
+ return false;
+#else
+ status.SetError(cmStrCat(args[0], " not available during bootstrap"));
+ return false;
+#endif
+}
+
+bool HandleStringsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("STRINGS requires a file name and output variable");
+ return false;
+ }
+
+ // Get the file to read.
+ std::string fileName = args[1];
+ if (!cmsys::SystemTools::FileIsFullPath(fileName)) {
+ fileName =
+ cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', args[1]);
+ }
+
+ // Get the variable in which to store the results.
+ std::string outVar = args[2];
+
+ // Parse the options.
+ enum
+ {
+ arg_none,
+ arg_limit_input,
+ arg_limit_output,
+ arg_limit_count,
+ arg_length_minimum,
+ arg_length_maximum,
+ arg_maximum,
+ arg_regex,
+ arg_encoding
+ };
+ unsigned int minlen = 0;
+ unsigned int maxlen = 0;
+ int limit_input = -1;
+ int limit_output = -1;
+ unsigned int limit_count = 0;
+ cmsys::RegularExpression regex;
+ bool have_regex = false;
+ bool newline_consume = false;
+ bool hex_conversion_enabled = true;
+ enum
+ {
+ encoding_none = cmsys::FStream::BOM_None,
+ encoding_utf8 = cmsys::FStream::BOM_UTF8,
+ encoding_utf16le = cmsys::FStream::BOM_UTF16LE,
+ encoding_utf16be = cmsys::FStream::BOM_UTF16BE,
+ encoding_utf32le = cmsys::FStream::BOM_UTF32LE,
+ encoding_utf32be = cmsys::FStream::BOM_UTF32BE
+ };
+ int encoding = encoding_none;
+ int arg_mode = arg_none;
+ for (unsigned int i = 3; i < args.size(); ++i) {
+ if (args[i] == "LIMIT_INPUT") {
+ arg_mode = arg_limit_input;
+ } else if (args[i] == "LIMIT_OUTPUT") {
+ arg_mode = arg_limit_output;
+ } else if (args[i] == "LIMIT_COUNT") {
+ arg_mode = arg_limit_count;
+ } else if (args[i] == "LENGTH_MINIMUM") {
+ arg_mode = arg_length_minimum;
+ } else if (args[i] == "LENGTH_MAXIMUM") {
+ arg_mode = arg_length_maximum;
+ } else if (args[i] == "REGEX") {
+ arg_mode = arg_regex;
+ } else if (args[i] == "NEWLINE_CONSUME") {
+ newline_consume = true;
+ arg_mode = arg_none;
+ } else if (args[i] == "NO_HEX_CONVERSION") {
+ hex_conversion_enabled = false;
+ arg_mode = arg_none;
+ } else if (args[i] == "ENCODING") {
+ arg_mode = arg_encoding;
+ } else if (arg_mode == arg_limit_input) {
+ if (sscanf(args[i].c_str(), "%d", &limit_input) != 1 ||
+ limit_input < 0) {
+ status.SetError(cmStrCat("STRINGS option LIMIT_INPUT value \"",
+ args[i], "\" is not an unsigned integer."));
+ return false;
+ }
+ arg_mode = arg_none;
+ } else if (arg_mode == arg_limit_output) {
+ if (sscanf(args[i].c_str(), "%d", &limit_output) != 1 ||
+ limit_output < 0) {
+ status.SetError(cmStrCat("STRINGS option LIMIT_OUTPUT value \"",
+ args[i], "\" is not an unsigned integer."));
+ return false;
+ }
+ arg_mode = arg_none;
+ } else if (arg_mode == arg_limit_count) {
+ int count;
+ if (sscanf(args[i].c_str(), "%d", &count) != 1 || count < 0) {
+ status.SetError(cmStrCat("STRINGS option LIMIT_COUNT value \"",
+ args[i], "\" is not an unsigned integer."));
+ return false;
+ }
+ limit_count = count;
+ arg_mode = arg_none;
+ } else if (arg_mode == arg_length_minimum) {
+ int len;
+ if (sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0) {
+ status.SetError(cmStrCat("STRINGS option LENGTH_MINIMUM value \"",
+ args[i], "\" is not an unsigned integer."));
+ return false;
+ }
+ minlen = len;
+ arg_mode = arg_none;
+ } else if (arg_mode == arg_length_maximum) {
+ int len;
+ if (sscanf(args[i].c_str(), "%d", &len) != 1 || len < 0) {
+ status.SetError(cmStrCat("STRINGS option LENGTH_MAXIMUM value \"",
+ args[i], "\" is not an unsigned integer."));
+ return false;
+ }
+ maxlen = len;
+ arg_mode = arg_none;
+ } else if (arg_mode == arg_regex) {
+ if (!regex.compile(args[i])) {
+ status.SetError(cmStrCat("STRINGS option REGEX value \"", args[i],
+ "\" could not be compiled."));
+ return false;
+ }
+ have_regex = true;
+ arg_mode = arg_none;
+ } else if (arg_mode == arg_encoding) {
+ if (args[i] == "UTF-8") {
+ encoding = encoding_utf8;
+ } else if (args[i] == "UTF-16LE") {
+ encoding = encoding_utf16le;
+ } else if (args[i] == "UTF-16BE") {
+ encoding = encoding_utf16be;
+ } else if (args[i] == "UTF-32LE") {
+ encoding = encoding_utf32le;
+ } else if (args[i] == "UTF-32BE") {
+ encoding = encoding_utf32be;
+ } else {
+ status.SetError(cmStrCat("STRINGS option ENCODING \"", args[i],
+ "\" not recognized."));
+ return false;
+ }
+ arg_mode = arg_none;
+ } else {
+ status.SetError(
+ cmStrCat("STRINGS given unknown argument \"", args[i], "\""));
+ return false;
+ }
+ }
+
+ if (hex_conversion_enabled) {
+ // TODO: should work without temp file, but just on a memory buffer
+ std::string binaryFileName =
+ cmStrCat(status.GetMakefile().GetCurrentBinaryDirectory(),
+ "/CMakeFiles/FileCommandStringsBinaryFile");
+ if (cmHexFileConverter::TryConvert(fileName, binaryFileName)) {
+ fileName = binaryFileName;
+ }
+ }
+
+// Open the specified file.
+#if defined(_WIN32) || defined(__CYGWIN__)
+ cmsys::ifstream fin(fileName.c_str(), std::ios::in | std::ios::binary);
+#else
+ cmsys::ifstream fin(fileName.c_str());
+#endif
+ if (!fin) {
+ status.SetError(
+ cmStrCat("STRINGS file \"", fileName, "\" cannot be read."));
+ return false;
+ }
+
+ // If BOM is found and encoding was not specified, use the BOM
+ int bom_found = cmsys::FStream::ReadBOM(fin);
+ if (encoding == encoding_none && bom_found != cmsys::FStream::BOM_None) {
+ encoding = bom_found;
+ }
+
+ unsigned int bytes_rem = 0;
+ if (encoding == encoding_utf16le || encoding == encoding_utf16be) {
+ bytes_rem = 1;
+ }
+ if (encoding == encoding_utf32le || encoding == encoding_utf32be) {
+ bytes_rem = 3;
+ }
+
+ // Parse strings out of the file.
+ int output_size = 0;
+ std::vector<std::string> strings;
+ std::string s;
+ while ((!limit_count || strings.size() < limit_count) &&
+ (limit_input < 0 || static_cast<int>(fin.tellg()) < limit_input) &&
+ fin) {
+ std::string current_str;
+
+ int c = fin.get();
+ for (unsigned int i = 0; i < bytes_rem; ++i) {
+ int c1 = fin.get();
+ if (!fin) {
+ fin.putback(static_cast<char>(c1));
+ break;
+ }
+ c = (c << 8) | c1;
+ }
+ if (encoding == encoding_utf16le) {
+ c = ((c & 0xFF) << 8) | ((c & 0xFF00) >> 8);
+ } else if (encoding == encoding_utf32le) {
+ c = (((c & 0xFF) << 24) | ((c & 0xFF00) << 8) | ((c & 0xFF0000) >> 8) |
+ ((c & 0xFF000000) >> 24));
+ }
+
+ if (c == '\r') {
+ // Ignore CR character to make output always have UNIX newlines.
+ continue;
+ }
+
+ if (c >= 0 && c <= 0xFF &&
+ (isprint(c) || c == '\t' || (c == '\n' && newline_consume))) {
+ // This is an ASCII character that may be part of a string.
+ // Cast added to avoid compiler warning. Cast is ok because
+ // c is guaranteed to fit in char by the above if...
+ current_str += static_cast<char>(c);
+ } else if (encoding == encoding_utf8) {
+ // Check for UTF-8 encoded string (up to 4 octets)
+ static const unsigned char utf8_check_table[3][2] = {
+ { 0xE0, 0xC0 },
+ { 0xF0, 0xE0 },
+ { 0xF8, 0xF0 },
+ };
+
+ // how many octets are there?
+ unsigned int num_utf8_bytes = 0;
+ for (unsigned int j = 0; num_utf8_bytes == 0 && j < 3; j++) {
+ if ((c & utf8_check_table[j][0]) == utf8_check_table[j][1]) {
+ num_utf8_bytes = j + 2;
+ }
+ }
+
+ // get subsequent octets and check that they are valid
+ for (unsigned int j = 0; j < num_utf8_bytes; j++) {
+ if (j != 0) {
+ c = fin.get();
+ if (!fin || (c & 0xC0) != 0x80) {
+ fin.putback(static_cast<char>(c));
+ break;
+ }
+ }
+ current_str += static_cast<char>(c);
+ }
+
+ // if this was an invalid utf8 sequence, discard the data, and put
+ // back subsequent characters
+ if ((current_str.length() != num_utf8_bytes)) {
+ for (unsigned int j = 0; j < current_str.size() - 1; j++) {
+ fin.putback(current_str[current_str.size() - 1 - j]);
+ }
+ current_str.clear();
+ }
+ }
+
+ if (c == '\n' && !newline_consume) {
+ // The current line has been terminated. Check if the current
+ // string matches the requirements. The length may now be as
+ // low as zero since blank lines are allowed.
+ if (s.length() >= minlen && (!have_regex || regex.find(s))) {
+ output_size += static_cast<int>(s.size()) + 1;
+ if (limit_output >= 0 && output_size >= limit_output) {
+ s.clear();
+ break;
+ }
+ strings.push_back(s);
+ }
+
+ // Reset the string to empty.
+ s.clear();
+ } else if (current_str.empty()) {
+ // A non-string character has been found. Check if the current
+ // string matches the requirements. We require that the length
+ // be at least one no matter what the user specified.
+ if (s.length() >= minlen && !s.empty() &&
+ (!have_regex || regex.find(s))) {
+ output_size += static_cast<int>(s.size()) + 1;
+ if (limit_output >= 0 && output_size >= limit_output) {
+ s.clear();
+ break;
+ }
+ strings.push_back(s);
+ }
+
+ // Reset the string to empty.
+ s.clear();
+ } else {
+ s += current_str;
+ }
+
+ if (maxlen > 0 && s.size() == maxlen) {
+ // Terminate a string if the maximum length is reached.
+ if (s.length() >= minlen && (!have_regex || regex.find(s))) {
+ output_size += static_cast<int>(s.size()) + 1;
+ if (limit_output >= 0 && output_size >= limit_output) {
+ s.clear();
+ break;
+ }
+ strings.push_back(s);
+ }
+ s.clear();
+ }
+ }
+
+ // If there is a non-empty current string we have hit the end of the
+ // input file or the input size limit. Check if the current string
+ // matches the requirements.
+ if ((!limit_count || strings.size() < limit_count) && !s.empty() &&
+ s.length() >= minlen && (!have_regex || regex.find(s))) {
+ output_size += static_cast<int>(s.size()) + 1;
+ if (limit_output < 0 || output_size < limit_output) {
+ strings.push_back(s);
+ }
+ }
+
+ // Encode the result in a CMake list.
+ const char* sep = "";
+ std::string output;
+ for (std::string const& sr : strings) {
+ // Separate the strings in the output to make it a list.
+ output += sep;
+ sep = ";";
+
+ // Store the string in the output, but escape semicolons to
+ // make sure it is a list.
+ for (char i : sr) {
+ if (i == ';') {
+ output += '\\';
+ }
+ output += i;
+ }
+ }
+
+ // Save the output in a makefile variable.
+ status.GetMakefile().AddDefinition(outVar, output);
+ return true;
+}
+
+bool HandleGlobImpl(std::vector<std::string> const& args, bool recurse,
+ cmExecutionStatus& status)
+{
+ // File commands has at least one argument
+ assert(args.size() > 1);
+
+ auto i = args.begin();
+
+ i++; // Get rid of subcommand
+
+ std::string variable = *i;
+ i++;
+ cmsys::Glob g;
+ g.SetRecurse(recurse);
+
+ bool explicitFollowSymlinks = false;
+ cmPolicies::PolicyStatus policyStatus =
+ status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0009);
+ if (recurse) {
+ switch (policyStatus) {
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ g.RecurseThroughSymlinksOff();
+ break;
+ case cmPolicies::OLD:
+ case cmPolicies::WARN:
+ g.RecurseThroughSymlinksOn();
+ break;
+ }
+ }
+
+ cmake* cm = status.GetMakefile().GetCMakeInstance();
+ std::vector<std::string> files;
+ bool configureDepends = false;
+ bool warnConfigureLate = false;
+ bool warnFollowedSymlinks = false;
+ const cmake::WorkingMode workingMode = cm->GetWorkingMode();
+ while (i != args.end()) {
+ if (*i == "LIST_DIRECTORIES") {
+ ++i; // skip LIST_DIRECTORIES
+ if (i != args.end()) {
+ if (cmIsOn(*i)) {
+ g.SetListDirs(true);
+ g.SetRecurseListDirs(true);
+ } else if (cmIsOff(*i)) {
+ g.SetListDirs(false);
+ g.SetRecurseListDirs(false);
+ } else {
+ status.SetError("LIST_DIRECTORIES missing bool value.");
+ return false;
+ }
+ ++i;
+ } else {
+ status.SetError("LIST_DIRECTORIES missing bool value.");
+ return false;
+ }
+ } else if (*i == "FOLLOW_SYMLINKS") {
+ ++i; // skip FOLLOW_SYMLINKS
+ if (recurse) {
+ explicitFollowSymlinks = true;
+ g.RecurseThroughSymlinksOn();
+ if (i == args.end()) {
+ status.SetError(
+ "GLOB_RECURSE requires a glob expression after FOLLOW_SYMLINKS.");
+ return false;
+ }
+ }
+ } else if (*i == "RELATIVE") {
+ ++i; // skip RELATIVE
+ if (i == args.end()) {
+ status.SetError("GLOB requires a directory after the RELATIVE tag.");
+ return false;
+ }
+ g.SetRelative(i->c_str());
+ ++i;
+ if (i == args.end()) {
+ status.SetError(
+ "GLOB requires a glob expression after the directory.");
+ return false;
+ }
+ } else if (*i == "CONFIGURE_DEPENDS") {
+ // Generated build system depends on glob results
+ if (!configureDepends && warnConfigureLate) {
+ status.GetMakefile().IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ "CONFIGURE_DEPENDS flag was given after a glob expression was "
+ "already evaluated.");
+ }
+ if (workingMode != cmake::NORMAL_MODE) {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ "CONFIGURE_DEPENDS is invalid for script and find package modes.");
+ return false;
+ }
+ configureDepends = true;
+ ++i;
+ if (i == args.end()) {
+ status.SetError(
+ "GLOB requires a glob expression after CONFIGURE_DEPENDS.");
+ return false;
+ }
+ } else {
+ std::string expr = *i;
+ if (!cmsys::SystemTools::FileIsFullPath(*i)) {
+ expr = status.GetMakefile().GetCurrentSourceDirectory();
+ // Handle script mode
+ if (!expr.empty()) {
+ expr += "/" + *i;
+ } else {
+ expr = *i;
+ }
+ }
+
+ cmsys::Glob::GlobMessages globMessages;
+ g.FindFiles(expr, &globMessages);
+
+ if (!globMessages.empty()) {
+ bool shouldExit = false;
+ for (cmsys::Glob::Message const& globMessage : globMessages) {
+ if (globMessage.type == cmsys::Glob::cyclicRecursion) {
+ status.GetMakefile().IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ "Cyclic recursion detected while globbing for '" + *i + "':\n" +
+ globMessage.content);
+ } else if (globMessage.type == cmsys::Glob::error) {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Error has occurred while globbing for '" + *i + "' - " +
+ globMessage.content);
+ shouldExit = true;
+ } else if (cm->GetDebugOutput() || cm->GetTrace()) {
+ status.GetMakefile().IssueMessage(
+ MessageType::LOG,
+ cmStrCat("Globbing for\n ", *i, "\nEncountered an error:\n ",
+ globMessage.content));
+ }
+ }
+ if (shouldExit) {
+ return false;
+ }
+ }
+
+ if (recurse && !explicitFollowSymlinks &&
+ g.GetFollowedSymlinkCount() != 0) {
+ warnFollowedSymlinks = true;
+ }
+
+ std::vector<std::string>& foundFiles = g.GetFiles();
+ cm::append(files, foundFiles);
+
+ if (configureDepends) {
+ std::sort(foundFiles.begin(), foundFiles.end());
+ foundFiles.erase(std::unique(foundFiles.begin(), foundFiles.end()),
+ foundFiles.end());
+ cm->AddGlobCacheEntry(
+ recurse, (recurse ? g.GetRecurseListDirs() : g.GetListDirs()),
+ (recurse ? g.GetRecurseThroughSymlinks() : false),
+ (g.GetRelative() ? g.GetRelative() : ""), expr, foundFiles, variable,
+ status.GetMakefile().GetBacktrace());
+ } else {
+ warnConfigureLate = true;
+ }
+ ++i;
+ }
+ }
+
+ switch (policyStatus) {
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Correct behavior, yay!
+ break;
+ case cmPolicies::OLD:
+ // Probably not really the expected behavior, but the author explicitly
+ // asked for the old behavior... no warning.
+ case cmPolicies::WARN:
+ // Possibly unexpected old behavior *and* we actually traversed
+ // symlinks without being explicitly asked to: warn the author.
+ if (warnFollowedSymlinks) {
+ status.GetMakefile().IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0009));
+ }
+ break;
+ }
+
+ std::sort(files.begin(), files.end());
+ files.erase(std::unique(files.begin(), files.end()), files.end());
+ status.GetMakefile().AddDefinition(variable, cmJoin(files, ";"));
+ return true;
+}
+
+bool HandleGlobCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleGlobImpl(args, false, status);
+}
+
+bool HandleGlobRecurseCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleGlobImpl(args, true, status);
+}
+
+bool HandleMakeDirectoryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // File command has at least one argument
+ assert(args.size() > 1);
+
+ std::string expr;
+ for (std::string const& arg :
+ cmMakeRange(args).advance(1)) // Get rid of subcommand
+ {
+ const std::string* cdir = &arg;
+ if (!cmsys::SystemTools::FileIsFullPath(arg)) {
+ expr =
+ cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', arg);
+ cdir = &expr;
+ }
+ if (!status.GetMakefile().CanIWriteThisFile(*cdir)) {
+ std::string e = "attempted to create a directory: " + *cdir +
+ " into a source directory.";
+ status.SetError(e);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ if (!cmSystemTools::MakeDirectory(*cdir)) {
+ std::string error = "problem creating directory: " + *cdir;
+ status.SetError(error);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool HandleTouchImpl(std::vector<std::string> const& args, bool create,
+ cmExecutionStatus& status)
+{
+ // File command has at least one argument
+ assert(args.size() > 1);
+
+ for (std::string const& arg :
+ cmMakeRange(args).advance(1)) // Get rid of subcommand
+ {
+ std::string tfile = arg;
+ if (!cmsys::SystemTools::FileIsFullPath(tfile)) {
+ tfile =
+ cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', arg);
+ }
+ if (!status.GetMakefile().CanIWriteThisFile(tfile)) {
+ std::string e =
+ "attempted to touch a file: " + tfile + " in a source directory.";
+ status.SetError(e);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ if (!cmSystemTools::Touch(tfile, create)) {
+ std::string error = "problem touching file: " + tfile;
+ status.SetError(error);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool HandleTouchCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleTouchImpl(args, true, status);
+}
+
+bool HandleTouchNocreateCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleTouchImpl(args, false, status);
+}
+
+bool HandleDifferentCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ /*
+ FILE(DIFFERENT <variable> FILES <lhs> <rhs>)
+ */
+
+ // Evaluate arguments.
+ const char* file_lhs = nullptr;
+ const char* file_rhs = nullptr;
+ const char* var = nullptr;
+ enum Doing
+ {
+ DoingNone,
+ DoingVar,
+ DoingFileLHS,
+ DoingFileRHS
+ };
+ Doing doing = DoingVar;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "FILES") {
+ doing = DoingFileLHS;
+ } else if (doing == DoingVar) {
+ var = args[i].c_str();
+ doing = DoingNone;
+ } else if (doing == DoingFileLHS) {
+ file_lhs = args[i].c_str();
+ doing = DoingFileRHS;
+ } else if (doing == DoingFileRHS) {
+ file_rhs = args[i].c_str();
+ doing = DoingNone;
+ } else {
+ status.SetError(cmStrCat("DIFFERENT given unknown argument ", args[i]));
+ return false;
+ }
+ }
+ if (!var) {
+ status.SetError("DIFFERENT not given result variable name.");
+ return false;
+ }
+ if (!file_lhs || !file_rhs) {
+ status.SetError("DIFFERENT not given FILES option with two file names.");
+ return false;
+ }
+
+ // Compare the files.
+ const char* result =
+ cmSystemTools::FilesDiffer(file_lhs, file_rhs) ? "1" : "0";
+ status.GetMakefile().AddDefinition(var, result);
+ return true;
+}
+
+bool HandleCopyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ cmFileCopier copier(status);
+ return copier.Run(args);
+}
+
+bool HandleRPathChangeCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // Evaluate arguments.
+ std::string file;
+ const char* oldRPath = nullptr;
+ const char* newRPath = nullptr;
+ bool removeEnvironmentRPath = false;
+ enum Doing
+ {
+ DoingNone,
+ DoingFile,
+ DoingOld,
+ DoingNew
+ };
+ Doing doing = DoingNone;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "OLD_RPATH") {
+ doing = DoingOld;
+ } else if (args[i] == "NEW_RPATH") {
+ doing = DoingNew;
+ } else if (args[i] == "FILE") {
+ doing = DoingFile;
+ } else if (args[i] == "INSTALL_REMOVE_ENVIRONMENT_RPATH") {
+ removeEnvironmentRPath = true;
+ } else if (doing == DoingFile) {
+ file = args[i];
+ doing = DoingNone;
+ } else if (doing == DoingOld) {
+ oldRPath = args[i].c_str();
+ doing = DoingNone;
+ } else if (doing == DoingNew) {
+ newRPath = args[i].c_str();
+ doing = DoingNone;
+ } else {
+ status.SetError(
+ cmStrCat("RPATH_CHANGE given unknown argument ", args[i]));
+ return false;
+ }
+ }
+ if (file.empty()) {
+ status.SetError("RPATH_CHANGE not given FILE option.");
+ return false;
+ }
+ if (!oldRPath) {
+ status.SetError("RPATH_CHANGE not given OLD_RPATH option.");
+ return false;
+ }
+ if (!newRPath) {
+ status.SetError("RPATH_CHANGE not given NEW_RPATH option.");
+ return false;
+ }
+ if (!cmSystemTools::FileExists(file, true)) {
+ status.SetError(
+ cmStrCat("RPATH_CHANGE given FILE \"", file, "\" that does not exist."));
+ return false;
+ }
+ bool success = true;
+ cmFileTimes const ft(file);
+ std::string emsg;
+ bool changed;
+
+ if (!cmSystemTools::ChangeRPath(file, oldRPath, newRPath,
+ removeEnvironmentRPath, &emsg, &changed)) {
+ status.SetError(cmStrCat("RPATH_CHANGE could not write new RPATH:\n ",
+ newRPath, "\nto the file:\n ", file, "\n",
+ emsg));
+ success = false;
+ }
+ if (success) {
+ if (changed) {
+ std::string message =
+ cmStrCat("Set runtime path of \"", file, "\" to \"", newRPath, '"');
+ status.GetMakefile().DisplayStatus(message, -1);
+ }
+ ft.Store(file);
+ }
+ return success;
+}
+
+bool HandleRPathRemoveCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // Evaluate arguments.
+ std::string file;
+ enum Doing
+ {
+ DoingNone,
+ DoingFile
+ };
+ Doing doing = DoingNone;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "FILE") {
+ doing = DoingFile;
+ } else if (doing == DoingFile) {
+ file = args[i];
+ doing = DoingNone;
+ } else {
+ status.SetError(
+ cmStrCat("RPATH_REMOVE given unknown argument ", args[i]));
+ return false;
+ }
+ }
+ if (file.empty()) {
+ status.SetError("RPATH_REMOVE not given FILE option.");
+ return false;
+ }
+ if (!cmSystemTools::FileExists(file, true)) {
+ status.SetError(
+ cmStrCat("RPATH_REMOVE given FILE \"", file, "\" that does not exist."));
+ return false;
+ }
+ bool success = true;
+ cmFileTimes const ft(file);
+ std::string emsg;
+ bool removed;
+ if (!cmSystemTools::RemoveRPath(file, &emsg, &removed)) {
+ status.SetError(
+ cmStrCat("RPATH_REMOVE could not remove RPATH from file: \n ", file,
+ "\n", emsg));
+ success = false;
+ }
+ if (success) {
+ if (removed) {
+ std::string message =
+ cmStrCat("Removed runtime path from \"", file, '"');
+ status.GetMakefile().DisplayStatus(message, -1);
+ }
+ ft.Store(file);
+ }
+ return success;
+}
+
+bool HandleRPathCheckCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // Evaluate arguments.
+ std::string file;
+ const char* rpath = nullptr;
+ enum Doing
+ {
+ DoingNone,
+ DoingFile,
+ DoingRPath
+ };
+ Doing doing = DoingNone;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "RPATH") {
+ doing = DoingRPath;
+ } else if (args[i] == "FILE") {
+ doing = DoingFile;
+ } else if (doing == DoingFile) {
+ file = args[i];
+ doing = DoingNone;
+ } else if (doing == DoingRPath) {
+ rpath = args[i].c_str();
+ doing = DoingNone;
+ } else {
+ status.SetError(
+ cmStrCat("RPATH_CHECK given unknown argument ", args[i]));
+ return false;
+ }
+ }
+ if (file.empty()) {
+ status.SetError("RPATH_CHECK not given FILE option.");
+ return false;
+ }
+ if (!rpath) {
+ status.SetError("RPATH_CHECK not given RPATH option.");
+ return false;
+ }
+
+ // If the file exists but does not have the desired RPath then
+ // delete it. This is used during installation to re-install a file
+ // if its RPath will change.
+ if (cmSystemTools::FileExists(file, true) &&
+ !cmSystemTools::CheckRPath(file, rpath)) {
+ cmSystemTools::RemoveFile(file);
+ }
+
+ return true;
+}
+
+bool HandleReadElfCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 4) {
+ status.SetError("READ_ELF must be called with at least three additional "
+ "arguments.");
+ return false;
+ }
+
+ std::string const& fileNameArg = args[1];
+
+ struct Arguments
+ {
+ std::string RPath;
+ std::string RunPath;
+ std::string Error;
+ };
+
+ static auto const parser = cmArgumentParser<Arguments>{}
+ .Bind("RPATH"_s, &Arguments::RPath)
+ .Bind("RUNPATH"_s, &Arguments::RunPath)
+ .Bind("CAPTURE_ERROR"_s, &Arguments::Error);
+ Arguments const arguments = parser.Parse(cmMakeRange(args).advance(2));
+
+ if (!cmSystemTools::FileExists(fileNameArg, true)) {
+ status.SetError(cmStrCat("READ_ELF given FILE \"", fileNameArg,
+ "\" that does not exist."));
+ return false;
+ }
+
+#if defined(CMake_USE_ELF_PARSER)
+ cmELF elf(fileNameArg.c_str());
+
+ if (!arguments.RPath.empty()) {
+ if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) {
+ std::string rpath(se_rpath->Value);
+ std::replace(rpath.begin(), rpath.end(), ':', ';');
+ status.GetMakefile().AddDefinition(arguments.RPath, rpath);
+ }
+ }
+ if (!arguments.RunPath.empty()) {
+ if (cmELF::StringEntry const* se_runpath = elf.GetRunPath()) {
+ std::string runpath(se_runpath->Value);
+ std::replace(runpath.begin(), runpath.end(), ':', ';');
+ status.GetMakefile().AddDefinition(arguments.RunPath, runpath);
+ }
+ }
+
+ return true;
+#else
+ std::string error = "ELF parser not available on this platform.";
+ if (arguments.Error.empty()) {
+ status.SetError(error);
+ return false;
+ }
+ status.GetMakefile().AddDefinition(arguments.Error, error);
+ return true;
+#endif
+}
+
+bool HandleInstallCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ cmFileInstaller installer(status);
+ return installer.Run(args);
+}
+
+bool HandleRealPathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("REAL_PATH requires a path and an output variable");
+ return false;
+ }
+
+ struct Arguments
+ {
+ std::string BaseDirectory;
+ };
+ static auto const parser = cmArgumentParser<Arguments>{}.Bind(
+ "BASE_DIRECTORY"_s, &Arguments::BaseDirectory);
+
+ std::vector<std::string> unparsedArguments;
+ std::vector<std::string> keywordsMissingValue;
+ std::vector<std::string> parsedKeywords;
+ auto arguments =
+ parser.Parse(cmMakeRange(args).advance(3), &unparsedArguments,
+ &keywordsMissingValue, &parsedKeywords);
+
+ if (!unparsedArguments.empty()) {
+ status.SetError("REAL_PATH called with unexpected arguments");
+ return false;
+ }
+ if (!keywordsMissingValue.empty()) {
+ status.SetError("BASE_DIRECTORY requires a value");
+ return false;
+ }
+
+ if (parsedKeywords.empty()) {
+ arguments.BaseDirectory = status.GetMakefile().GetCurrentSourceDirectory();
+ }
+
+ cmCMakePath path(args[1]);
+ path = path.Absolute(arguments.BaseDirectory).Normal();
+ auto realPath = cmSystemTools::GetRealPath(path.GenericString());
+
+ status.GetMakefile().AddDefinition(args[2], realPath);
+
+ return true;
+}
+
+bool HandleRelativePathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 4) {
+ status.SetError("RELATIVE_PATH called with incorrect number of arguments");
+ return false;
+ }
+
+ const std::string& outVar = args[1];
+ const std::string& directoryName = args[2];
+ const std::string& fileName = args[3];
+
+ if (!cmSystemTools::FileIsFullPath(directoryName)) {
+ std::string errstring =
+ "RELATIVE_PATH must be passed a full path to the directory: " +
+ directoryName;
+ status.SetError(errstring);
+ return false;
+ }
+ if (!cmSystemTools::FileIsFullPath(fileName)) {
+ std::string errstring =
+ "RELATIVE_PATH must be passed a full path to the file: " + fileName;
+ status.SetError(errstring);
+ return false;
+ }
+
+ std::string res = cmSystemTools::RelativePath(directoryName, fileName);
+ status.GetMakefile().AddDefinition(outVar, res);
+ return true;
+}
+
+bool HandleRename(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("RENAME must be called with at least two additional "
+ "arguments");
+ return false;
+ }
+
+ // Compute full path for old and new names.
+ std::string oldname = args[1];
+ if (!cmsys::SystemTools::FileIsFullPath(oldname)) {
+ oldname =
+ cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', args[1]);
+ }
+ std::string newname = args[2];
+ if (!cmsys::SystemTools::FileIsFullPath(newname)) {
+ newname =
+ cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', args[2]);
+ }
+
+ struct Arguments
+ {
+ bool NoReplace = false;
+ std::string Result;
+ };
+
+ static auto const parser = cmArgumentParser<Arguments>{}
+ .Bind("NO_REPLACE"_s, &Arguments::NoReplace)
+ .Bind("RESULT"_s, &Arguments::Result);
+
+ std::vector<std::string> unconsumedArgs;
+ Arguments const arguments =
+ parser.Parse(cmMakeRange(args).advance(3), &unconsumedArgs);
+ if (!unconsumedArgs.empty()) {
+ status.SetError("RENAME unknown argument:\n " + unconsumedArgs.front());
+ return false;
+ }
+
+ std::string err;
+ switch (cmSystemTools::RenameFile(oldname, newname,
+ arguments.NoReplace
+ ? cmSystemTools::Replace::No
+ : cmSystemTools::Replace::Yes,
+ &err)) {
+ case cmSystemTools::RenameResult::Success:
+ if (!arguments.Result.empty()) {
+ status.GetMakefile().AddDefinition(arguments.Result, "0");
+ }
+ return true;
+ case cmSystemTools::RenameResult::NoReplace:
+ if (!arguments.Result.empty()) {
+ err = "NO_REPLACE";
+ } else {
+ err = "path not replaced";
+ }
+ CM_FALLTHROUGH;
+ case cmSystemTools::RenameResult::Failure:
+ if (!arguments.Result.empty()) {
+ status.GetMakefile().AddDefinition(arguments.Result, err);
+ return true;
+ }
+ break;
+ }
+ status.SetError(cmStrCat("RENAME failed to rename\n ", oldname, "\nto\n ",
+ newname, "\nbecause: ", err, "\n"));
+ return false;
+}
+
+bool HandleCopyFile(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("COPY_FILE must be called with at least two additional "
+ "arguments");
+ return false;
+ }
+
+ // Compute full path for old and new names.
+ std::string oldname = args[1];
+ if (!cmsys::SystemTools::FileIsFullPath(oldname)) {
+ oldname =
+ cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', args[1]);
+ }
+ std::string newname = args[2];
+ if (!cmsys::SystemTools::FileIsFullPath(newname)) {
+ newname =
+ cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', args[2]);
+ }
+
+ struct Arguments
+ {
+ bool OnlyIfDifferent = false;
+ std::string Result;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("ONLY_IF_DIFFERENT"_s, &Arguments::OnlyIfDifferent)
+ .Bind("RESULT"_s, &Arguments::Result);
+
+ std::vector<std::string> unconsumedArgs;
+ Arguments const arguments =
+ parser.Parse(cmMakeRange(args).advance(3), &unconsumedArgs);
+ if (!unconsumedArgs.empty()) {
+ status.SetError("COPY_FILE unknown argument:\n " +
+ unconsumedArgs.front());
+ return false;
+ }
+
+ bool result = true;
+ if (cmsys::SystemTools::FileIsDirectory(oldname)) {
+ if (!arguments.Result.empty()) {
+ status.GetMakefile().AddDefinition(arguments.Result,
+ "cannot copy a directory");
+ } else {
+ status.SetError(
+ cmStrCat("COPY_FILE cannot copy a directory\n ", oldname));
+ result = false;
+ }
+ return result;
+ }
+ if (cmsys::SystemTools::FileIsDirectory(newname)) {
+ if (!arguments.Result.empty()) {
+ status.GetMakefile().AddDefinition(arguments.Result,
+ "cannot copy to a directory");
+ } else {
+ status.SetError(
+ cmStrCat("COPY_FILE cannot copy to a directory\n ", newname));
+ result = false;
+ }
+ return result;
+ }
+
+ cmSystemTools::CopyWhen when;
+ if (arguments.OnlyIfDifferent) {
+ when = cmSystemTools::CopyWhen::OnlyIfDifferent;
+ } else {
+ when = cmSystemTools::CopyWhen::Always;
+ }
+
+ std::string err;
+ if (cmSystemTools::CopySingleFile(oldname, newname, when, &err) ==
+ cmSystemTools::CopyResult::Success) {
+ if (!arguments.Result.empty()) {
+ status.GetMakefile().AddDefinition(arguments.Result, "0");
+ }
+ } else {
+ if (!arguments.Result.empty()) {
+ status.GetMakefile().AddDefinition(arguments.Result, err);
+ } else {
+ status.SetError(cmStrCat("COPY_FILE failed to copy\n ", oldname,
+ "\nto\n ", newname, "\nbecause: ", err, "\n"));
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+bool HandleRemoveImpl(std::vector<std::string> const& args, bool recurse,
+ cmExecutionStatus& status)
+{
+
+ std::string message;
+
+ for (std::string const& arg :
+ cmMakeRange(args).advance(1)) // Get rid of subcommand
+ {
+ std::string fileName = arg;
+ if (fileName.empty()) {
+ std::string const r = recurse ? "REMOVE_RECURSE" : "REMOVE";
+ status.GetMakefile().IssueMessage(
+ MessageType::AUTHOR_WARNING, "Ignoring empty file name in " + r + ".");
+ continue;
+ }
+ if (!cmsys::SystemTools::FileIsFullPath(fileName)) {
+ fileName =
+ cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', arg);
+ }
+
+ if (cmSystemTools::FileIsDirectory(fileName) &&
+ !cmSystemTools::FileIsSymlink(fileName) && recurse) {
+ cmSystemTools::RepeatedRemoveDirectory(fileName);
+ } else {
+ cmSystemTools::RemoveFile(fileName);
+ }
+ }
+ return true;
+}
+
+bool HandleRemove(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleRemoveImpl(args, false, status);
+}
+
+bool HandleRemoveRecurse(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleRemoveImpl(args, true, status);
+}
+
+std::string ToNativePath(const std::string& path)
+{
+ const auto& outPath = cmSystemTools::ConvertToOutputPath(path);
+ if (outPath.size() > 1 && outPath.front() == '\"' &&
+ outPath.back() == '\"') {
+ return outPath.substr(1, outPath.size() - 2);
+ }
+ return outPath;
+}
+
+std::string ToCMakePath(const std::string& path)
+{
+ auto temp = path;
+ cmSystemTools::ConvertToUnixSlashes(temp);
+ return temp;
+}
+
+bool HandlePathCommand(std::vector<std::string> const& args,
+ std::string (*convert)(std::string const&),
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError("FILE([TO_CMAKE_PATH|TO_NATIVE_PATH] path result) must be "
+ "called with exactly three arguments.");
+ return false;
+ }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ char pathSep = ';';
+#else
+ char pathSep = ':';
+#endif
+ std::vector<std::string> path = cmSystemTools::SplitString(args[1], pathSep);
+
+ std::string value = cmJoin(cmMakeRange(path).transform(convert), ";");
+ status.GetMakefile().AddDefinition(args[2], value);
+ return true;
+}
+
+bool HandleCMakePathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandlePathCommand(args, ToCMakePath, status);
+}
+
+bool HandleNativePathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandlePathCommand(args, ToNativePath, status);
+}
+
+#if !defined(CMAKE_BOOTSTRAP)
+
+// Stuff for curl download/upload
+using cmFileCommandVectorOfChar = std::vector<char>;
+
+size_t cmWriteToFileCallback(void* ptr, size_t size, size_t nmemb, void* data)
+{
+ int realsize = static_cast<int>(size * nmemb);
+ cmsys::ofstream* fout = static_cast<cmsys::ofstream*>(data);
+ if (fout) {
+ const char* chPtr = static_cast<char*>(ptr);
+ fout->write(chPtr, realsize);
+ }
+ return realsize;
+}
+
+size_t cmWriteToMemoryCallback(void* ptr, size_t size, size_t nmemb,
+ void* data)
+{
+ int realsize = static_cast<int>(size * nmemb);
+ const char* chPtr = static_cast<char*>(ptr);
+ cm::append(*static_cast<cmFileCommandVectorOfChar*>(data), chPtr,
+ chPtr + realsize);
+ return realsize;
+}
+
+size_t cmFileCommandCurlDebugCallback(CURL*, curl_infotype type, char* chPtr,
+ size_t size, void* data)
+{
+ cmFileCommandVectorOfChar& vec =
+ *static_cast<cmFileCommandVectorOfChar*>(data);
+ switch (type) {
+ case CURLINFO_TEXT:
+ case CURLINFO_HEADER_IN:
+ case CURLINFO_HEADER_OUT:
+ cm::append(vec, chPtr, chPtr + size);
+ break;
+ case CURLINFO_DATA_IN:
+ case CURLINFO_DATA_OUT:
+ case CURLINFO_SSL_DATA_IN:
+ case CURLINFO_SSL_DATA_OUT: {
+ char buf[128];
+ int n = sprintf(buf, "[%" KWIML_INT_PRIu64 " bytes data]\n",
+ static_cast<KWIML_INT_uint64_t>(size));
+ if (n > 0) {
+ cm::append(vec, buf, buf + n);
+ }
+ } break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+class cURLProgressHelper
+{
+public:
+ cURLProgressHelper(cmMakefile* mf, const char* text)
+ : Makefile(mf)
+ , Text(text)
+ {
+ }
+
+ bool UpdatePercentage(double value, double total, std::string& status)
+ {
+ long OldPercentage = this->CurrentPercentage;
+
+ if (total > 0.0) {
+ this->CurrentPercentage = std::lround(value / total * 100.0);
+ if (this->CurrentPercentage > 100) {
+ // Avoid extra progress reports for unexpected data beyond total.
+ this->CurrentPercentage = 100;
+ }
+ }
+
+ bool updated = (OldPercentage != this->CurrentPercentage);
+
+ if (updated) {
+ status =
+ cmStrCat("[", this->Text, " ", this->CurrentPercentage, "% complete]");
+ }
+
+ return updated;
+ }
+
+ cmMakefile* GetMakefile() { return this->Makefile; }
+
+private:
+ long CurrentPercentage = -1;
+ cmMakefile* Makefile;
+ std::string Text;
+};
+
+int cmFileDownloadProgressCallback(void* clientp, double dltotal, double dlnow,
+ double ultotal, double ulnow)
+{
+ cURLProgressHelper* helper = reinterpret_cast<cURLProgressHelper*>(clientp);
+
+ static_cast<void>(ultotal);
+ static_cast<void>(ulnow);
+
+ std::string status;
+ if (helper->UpdatePercentage(dlnow, dltotal, status)) {
+ cmMakefile* mf = helper->GetMakefile();
+ mf->DisplayStatus(status, -1);
+ }
+
+ return 0;
+}
+
+int cmFileUploadProgressCallback(void* clientp, double dltotal, double dlnow,
+ double ultotal, double ulnow)
+{
+ cURLProgressHelper* helper = reinterpret_cast<cURLProgressHelper*>(clientp);
+
+ static_cast<void>(dltotal);
+ static_cast<void>(dlnow);
+
+ std::string status;
+ if (helper->UpdatePercentage(ulnow, ultotal, status)) {
+ cmMakefile* mf = helper->GetMakefile();
+ mf->DisplayStatus(status, -1);
+ }
+
+ return 0;
+}
+
+class cURLEasyGuard
+{
+public:
+ cURLEasyGuard(CURL* easy)
+ : Easy(easy)
+ {
+ }
+
+ ~cURLEasyGuard()
+ {
+ if (this->Easy) {
+ ::curl_easy_cleanup(this->Easy);
+ }
+ }
+
+ cURLEasyGuard(const cURLEasyGuard&) = delete;
+ cURLEasyGuard& operator=(const cURLEasyGuard&) = delete;
+
+ void release() { this->Easy = nullptr; }
+
+private:
+ ::CURL* Easy;
+};
+
+#endif
+
+#define check_curl_result(result, errstr) \
+ do { \
+ if (result != CURLE_OK) { \
+ std::string e(errstr); \
+ e += ::curl_easy_strerror(result); \
+ status.SetError(e); \
+ return false; \
+ } \
+ } while (false)
+
+bool HandleDownloadCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ auto i = args.begin();
+ if (args.size() < 2) {
+ status.SetError("DOWNLOAD must be called with at least two arguments.");
+ return false;
+ }
+ ++i; // Get rid of subcommand
+ std::string url = *i;
+ ++i;
+ std::string file;
+
+ long timeout = 0;
+ long inactivity_timeout = 0;
+ std::string logVar;
+ std::string statusVar;
+ bool tls_verify = status.GetMakefile().IsOn("CMAKE_TLS_VERIFY");
+ cmProp cainfo = status.GetMakefile().GetDefinition("CMAKE_TLS_CAINFO");
+ std::string netrc_level =
+ status.GetMakefile().GetSafeDefinition("CMAKE_NETRC");
+ std::string netrc_file =
+ status.GetMakefile().GetSafeDefinition("CMAKE_NETRC_FILE");
+ std::string expectedHash;
+ std::string hashMatchMSG;
+ std::unique_ptr<cmCryptoHash> hash;
+ bool showProgress = false;
+ std::string userpwd;
+
+ std::vector<std::string> curl_headers;
+
+ while (i != args.end()) {
+ if (*i == "TIMEOUT") {
+ ++i;
+ if (i != args.end()) {
+ timeout = atol(i->c_str());
+ } else {
+ status.SetError("DOWNLOAD missing time for TIMEOUT.");
+ return false;
+ }
+ } else if (*i == "INACTIVITY_TIMEOUT") {
+ ++i;
+ if (i != args.end()) {
+ inactivity_timeout = atol(i->c_str());
+ } else {
+ status.SetError("DOWNLOAD missing time for INACTIVITY_TIMEOUT.");
+ return false;
+ }
+ } else if (*i == "LOG") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("DOWNLOAD missing VAR for LOG.");
+ return false;
+ }
+ logVar = *i;
+ } else if (*i == "STATUS") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("DOWNLOAD missing VAR for STATUS.");
+ return false;
+ }
+ statusVar = *i;
+ } else if (*i == "TLS_VERIFY") {
+ ++i;
+ if (i != args.end()) {
+ tls_verify = cmIsOn(*i);
+ } else {
+ status.SetError("DOWNLOAD missing bool value for TLS_VERIFY.");
+ return false;
+ }
+ } else if (*i == "TLS_CAINFO") {
+ ++i;
+ if (i != args.end()) {
+ cainfo = &(*i);
+ } else {
+ status.SetError("DOWNLOAD missing file value for TLS_CAINFO.");
+ return false;
+ }
+ } else if (*i == "NETRC_FILE") {
+ ++i;
+ if (i != args.end()) {
+ netrc_file = *i;
+ } else {
+ status.SetError("DOWNLOAD missing file value for NETRC_FILE.");
+ return false;
+ }
+ } else if (*i == "NETRC") {
+ ++i;
+ if (i != args.end()) {
+ netrc_level = *i;
+ } else {
+ status.SetError("DOWNLOAD missing level value for NETRC.");
+ return false;
+ }
+ } else if (*i == "EXPECTED_MD5") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("DOWNLOAD missing sum value for EXPECTED_MD5.");
+ return false;
+ }
+ hash = cm::make_unique<cmCryptoHash>(cmCryptoHash::AlgoMD5);
+ hashMatchMSG = "MD5 sum";
+ expectedHash = cmSystemTools::LowerCase(*i);
+ } else if (*i == "SHOW_PROGRESS") {
+ showProgress = true;
+ } else if (*i == "EXPECTED_HASH") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("DOWNLOAD missing ALGO=value for EXPECTED_HASH.");
+ return false;
+ }
+ std::string::size_type pos = i->find("=");
+ if (pos == std::string::npos) {
+ std::string err =
+ cmStrCat("DOWNLOAD EXPECTED_HASH expects ALGO=value but got: ", *i);
+ status.SetError(err);
+ return false;
+ }
+ std::string algo = i->substr(0, pos);
+ expectedHash = cmSystemTools::LowerCase(i->substr(pos + 1));
+ hash = std::unique_ptr<cmCryptoHash>(cmCryptoHash::New(algo));
+ if (!hash) {
+ std::string err =
+ cmStrCat("DOWNLOAD EXPECTED_HASH given unknown ALGO: ", algo);
+ status.SetError(err);
+ return false;
+ }
+ hashMatchMSG = algo + " hash";
+ } else if (*i == "USERPWD") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("DOWNLOAD missing string for USERPWD.");
+ return false;
+ }
+ userpwd = *i;
+ } else if (*i == "HTTPHEADER") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("DOWNLOAD missing string for HTTPHEADER.");
+ return false;
+ }
+ curl_headers.push_back(*i);
+ } else if (file.empty()) {
+ file = *i;
+ } else {
+ // Do not return error for compatibility reason.
+ std::string err = cmStrCat("Unexpected argument: ", *i);
+ status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, err);
+ }
+ ++i;
+ }
+ // Can't calculate hash if we don't save the file.
+ // TODO Incrementally calculate hash in the write callback as the file is
+ // being downloaded so this check can be relaxed.
+ if (file.empty() && hash) {
+ status.SetError("DOWNLOAD cannot calculate hash if file is not saved.");
+ return false;
+ }
+ // If file exists already, and caller specified an expected md5 or sha,
+ // and the existing file already has the expected hash, then simply
+ // return.
+ //
+ if (!file.empty() && cmSystemTools::FileExists(file) && hash.get()) {
+ std::string msg;
+ std::string actualHash = hash->HashFile(file);
+ if (actualHash == expectedHash) {
+ msg = cmStrCat("returning early; file already exists with expected ",
+ hashMatchMSG, '"');
+ if (!statusVar.empty()) {
+ status.GetMakefile().AddDefinition(statusVar, cmStrCat(0, ";\"", msg));
+ }
+ return true;
+ }
+ }
+ // Make sure parent directory exists so we can write to the file
+ // as we receive downloaded bits from curl...
+ //
+ if (!file.empty()) {
+ std::string dir = cmSystemTools::GetFilenamePath(file);
+ if (!dir.empty() && !cmSystemTools::FileExists(dir) &&
+ !cmSystemTools::MakeDirectory(dir)) {
+ std::string errstring = "DOWNLOAD error: cannot create directory '" +
+ dir +
+ "' - Specify file by full path name and verify that you "
+ "have directory creation and file write privileges.";
+ status.SetError(errstring);
+ return false;
+ }
+ }
+
+ cmsys::ofstream fout;
+ if (!file.empty()) {
+ fout.open(file.c_str(), std::ios::binary);
+ if (!fout) {
+ status.SetError("DOWNLOAD cannot open file for write.");
+ return false;
+ }
+ }
+
+# if defined(_WIN32)
+ url = fix_file_url_windows(url);
+# endif
+
+ ::CURL* curl;
+ ::curl_global_init(CURL_GLOBAL_DEFAULT);
+ curl = ::curl_easy_init();
+ if (!curl) {
+ status.SetError("DOWNLOAD error initializing curl.");
+ return false;
+ }
+
+ cURLEasyGuard g_curl(curl);
+ ::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+ check_curl_result(res, "DOWNLOAD cannot set url: ");
+
+ // enable HTTP ERROR parsing
+ res = ::curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
+ check_curl_result(res, "DOWNLOAD cannot set http failure option: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/" LIBCURL_VERSION);
+ check_curl_result(res, "DOWNLOAD cannot set user agent option: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cmWriteToFileCallback);
+ check_curl_result(res, "DOWNLOAD cannot set write function: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
+ cmFileCommandCurlDebugCallback);
+ check_curl_result(res, "DOWNLOAD cannot set debug function: ");
+
+ // check to see if TLS verification is requested
+ if (tls_verify) {
+ res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
+ check_curl_result(res, "DOWNLOAD cannot set TLS/SSL Verify on: ");
+ } else {
+ res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
+ check_curl_result(res, "DOWNLOAD cannot set TLS/SSL Verify off: ");
+ }
+
+ // check to see if a CAINFO file has been specified
+ // command arg comes first
+ std::string const& cainfo_err = cmCurlSetCAInfo(curl, cmToCStr(cainfo));
+ if (!cainfo_err.empty()) {
+ status.SetError(cainfo_err);
+ return false;
+ }
+
+ // check to see if netrc parameters have been specified
+ // local command args takes precedence over CMAKE_NETRC*
+ netrc_level = cmSystemTools::UpperCase(netrc_level);
+ std::string const& netrc_option_err =
+ cmCurlSetNETRCOption(curl, netrc_level, netrc_file);
+ if (!netrc_option_err.empty()) {
+ status.SetError(netrc_option_err);
+ return false;
+ }
+
+ cmFileCommandVectorOfChar chunkDebug;
+
+ res = ::curl_easy_setopt(curl, CURLOPT_WRITEDATA,
+ file.empty() ? nullptr : &fout);
+ check_curl_result(res, "DOWNLOAD cannot set write data: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &chunkDebug);
+ check_curl_result(res, "DOWNLOAD cannot set debug data: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+ check_curl_result(res, "DOWNLOAD cannot set follow-redirect option: ");
+
+ if (!logVar.empty()) {
+ res = ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+ check_curl_result(res, "DOWNLOAD cannot set verbose: ");
+ }
+
+ if (timeout > 0) {
+ res = ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
+ check_curl_result(res, "DOWNLOAD cannot set timeout: ");
+ }
+
+ if (inactivity_timeout > 0) {
+ // Give up if there is no progress for a long time.
+ ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
+ ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, inactivity_timeout);
+ }
+
+ // Need the progress helper's scope to last through the duration of
+ // the curl_easy_perform call... so this object is declared at function
+ // scope intentionally, rather than inside the "if(showProgress)"
+ // block...
+ //
+ cURLProgressHelper helper(&status.GetMakefile(), "download");
+
+ if (showProgress) {
+ res = ::curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
+ check_curl_result(res, "DOWNLOAD cannot set noprogress value: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,
+ cmFileDownloadProgressCallback);
+ check_curl_result(res, "DOWNLOAD cannot set progress function: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_PROGRESSDATA,
+ reinterpret_cast<void*>(&helper));
+ check_curl_result(res, "DOWNLOAD cannot set progress data: ");
+ }
+
+ if (!userpwd.empty()) {
+ res = ::curl_easy_setopt(curl, CURLOPT_USERPWD, userpwd.c_str());
+ check_curl_result(res, "DOWNLOAD cannot set user password: ");
+ }
+
+ struct curl_slist* headers = nullptr;
+ for (std::string const& h : curl_headers) {
+ headers = ::curl_slist_append(headers, h.c_str());
+ }
+ ::curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+
+ res = ::curl_easy_perform(curl);
+
+ ::curl_slist_free_all(headers);
+
+ /* always cleanup */
+ g_curl.release();
+ ::curl_easy_cleanup(curl);
+
+ if (!statusVar.empty()) {
+ status.GetMakefile().AddDefinition(
+ statusVar,
+ cmStrCat(static_cast<int>(res), ";\"", ::curl_easy_strerror(res), "\""));
+ }
+
+ ::curl_global_cleanup();
+
+ // Explicitly flush/close so we can measure the md5 accurately.
+ //
+ if (!file.empty()) {
+ fout.flush();
+ fout.close();
+ }
+
+ // Verify MD5 sum if requested:
+ //
+ if (hash) {
+ std::string actualHash = hash->HashFile(file);
+ if (actualHash.empty()) {
+ status.SetError("DOWNLOAD cannot compute hash on downloaded file");
+ return false;
+ }
+
+ if (expectedHash != actualHash) {
+ if (!statusVar.empty() && res == 0) {
+ status.GetMakefile().AddDefinition(statusVar,
+ "1;HASH mismatch: "
+ "expected: " +
+ expectedHash +
+ " actual: " + actualHash);
+ }
+
+ status.SetError(cmStrCat("DOWNLOAD HASH mismatch\n"
+ " for file: [",
+ file,
+ "]\n"
+ " expected hash: [",
+ expectedHash,
+ "]\n"
+ " actual hash: [",
+ actualHash,
+ "]\n"
+ " status: [",
+ static_cast<int>(res), ";\"",
+ ::curl_easy_strerror(res), "\"]\n"));
+ return false;
+ }
+ }
+
+ if (!logVar.empty()) {
+ chunkDebug.push_back(0);
+ status.GetMakefile().AddDefinition(logVar, chunkDebug.data());
+ }
+
+ return true;
+#else
+ status.SetError("DOWNLOAD not supported by bootstrap cmake.");
+ return false;
+#endif
+}
+
+bool HandleUploadCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ if (args.size() < 3) {
+ status.SetError("UPLOAD must be called with at least three arguments.");
+ return false;
+ }
+ auto i = args.begin();
+ ++i;
+ std::string filename = *i;
+ ++i;
+ std::string url = *i;
+ ++i;
+
+ long timeout = 0;
+ long inactivity_timeout = 0;
+ std::string logVar;
+ std::string statusVar;
+ bool showProgress = false;
+ bool tls_verify = status.GetMakefile().IsOn("CMAKE_TLS_VERIFY");
+ cmProp cainfo = status.GetMakefile().GetDefinition("CMAKE_TLS_CAINFO");
+ std::string userpwd;
+ std::string netrc_level =
+ status.GetMakefile().GetSafeDefinition("CMAKE_NETRC");
+ std::string netrc_file =
+ status.GetMakefile().GetSafeDefinition("CMAKE_NETRC_FILE");
+
+ std::vector<std::string> curl_headers;
+
+ while (i != args.end()) {
+ if (*i == "TIMEOUT") {
+ ++i;
+ if (i != args.end()) {
+ timeout = atol(i->c_str());
+ } else {
+ status.SetError("UPLOAD missing time for TIMEOUT.");
+ return false;
+ }
+ } else if (*i == "INACTIVITY_TIMEOUT") {
+ ++i;
+ if (i != args.end()) {
+ inactivity_timeout = atol(i->c_str());
+ } else {
+ status.SetError("UPLOAD missing time for INACTIVITY_TIMEOUT.");
+ return false;
+ }
+ } else if (*i == "LOG") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("UPLOAD missing VAR for LOG.");
+ return false;
+ }
+ logVar = *i;
+ } else if (*i == "STATUS") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("UPLOAD missing VAR for STATUS.");
+ return false;
+ }
+ statusVar = *i;
+ } else if (*i == "SHOW_PROGRESS") {
+ showProgress = true;
+ } else if (*i == "TLS_VERIFY") {
+ ++i;
+ if (i != args.end()) {
+ tls_verify = cmIsOn(*i);
+ } else {
+ status.SetError("UPLOAD missing bool value for TLS_VERIFY.");
+ return false;
+ }
+ } else if (*i == "TLS_CAINFO") {
+ ++i;
+ if (i != args.end()) {
+ cainfo = &(*i);
+ } else {
+ status.SetError("UPLOAD missing file value for TLS_CAINFO.");
+ return false;
+ }
+ } else if (*i == "NETRC_FILE") {
+ ++i;
+ if (i != args.end()) {
+ netrc_file = *i;
+ } else {
+ status.SetError("UPLOAD missing file value for NETRC_FILE.");
+ return false;
+ }
+ } else if (*i == "NETRC") {
+ ++i;
+ if (i != args.end()) {
+ netrc_level = *i;
+ } else {
+ status.SetError("UPLOAD missing level value for NETRC.");
+ return false;
+ }
+ } else if (*i == "USERPWD") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("UPLOAD missing string for USERPWD.");
+ return false;
+ }
+ userpwd = *i;
+ } else if (*i == "HTTPHEADER") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("UPLOAD missing string for HTTPHEADER.");
+ return false;
+ }
+ curl_headers.push_back(*i);
+ } else {
+ // Do not return error for compatibility reason.
+ std::string err = cmStrCat("Unexpected argument: ", *i);
+ status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, err);
+ }
+
+ ++i;
+ }
+
+ // Open file for reading:
+ //
+ FILE* fin = cmsys::SystemTools::Fopen(filename, "rb");
+ if (!fin) {
+ std::string errStr =
+ cmStrCat("UPLOAD cannot open file '", filename, "' for reading.");
+ status.SetError(errStr);
+ return false;
+ }
+
+ unsigned long file_size = cmsys::SystemTools::FileLength(filename);
+
+# if defined(_WIN32)
+ url = fix_file_url_windows(url);
+# endif
+
+ ::CURL* curl;
+ ::curl_global_init(CURL_GLOBAL_DEFAULT);
+ curl = ::curl_easy_init();
+ if (!curl) {
+ status.SetError("UPLOAD error initializing curl.");
+ fclose(fin);
+ return false;
+ }
+
+ cURLEasyGuard g_curl(curl);
+
+ // enable HTTP ERROR parsing
+ ::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
+ check_curl_result(res, "UPLOAD cannot set fail on error flag: ");
+
+ // enable uploading
+ res = ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
+ check_curl_result(res, "UPLOAD cannot set upload flag: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+ check_curl_result(res, "UPLOAD cannot set url: ");
+
+ res =
+ ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cmWriteToMemoryCallback);
+ check_curl_result(res, "UPLOAD cannot set write function: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
+ cmFileCommandCurlDebugCallback);
+ check_curl_result(res, "UPLOAD cannot set debug function: ");
+
+ // check to see if TLS verification is requested
+ if (tls_verify) {
+ res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
+ check_curl_result(res, "UPLOAD cannot set TLS/SSL Verify on: ");
+ } else {
+ res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
+ check_curl_result(res, "UPLOAD cannot set TLS/SSL Verify off: ");
+ }
+
+ // check to see if a CAINFO file has been specified
+ // command arg comes first
+ std::string const& cainfo_err = cmCurlSetCAInfo(curl, cmToCStr(cainfo));
+ if (!cainfo_err.empty()) {
+ status.SetError(cainfo_err);
+ return false;
+ }
+
+ cmFileCommandVectorOfChar chunkResponse;
+ cmFileCommandVectorOfChar chunkDebug;
+
+ res = ::curl_easy_setopt(curl, CURLOPT_WRITEDATA, &chunkResponse);
+ check_curl_result(res, "UPLOAD cannot set write data: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &chunkDebug);
+ check_curl_result(res, "UPLOAD cannot set debug data: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+ check_curl_result(res, "UPLOAD cannot set follow-redirect option: ");
+
+ if (!logVar.empty()) {
+ res = ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+ check_curl_result(res, "UPLOAD cannot set verbose: ");
+ }
+
+ if (timeout > 0) {
+ res = ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
+ check_curl_result(res, "UPLOAD cannot set timeout: ");
+ }
+
+ if (inactivity_timeout > 0) {
+ // Give up if there is no progress for a long time.
+ ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
+ ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, inactivity_timeout);
+ }
+
+ // Need the progress helper's scope to last through the duration of
+ // the curl_easy_perform call... so this object is declared at function
+ // scope intentionally, rather than inside the "if(showProgress)"
+ // block...
+ //
+ cURLProgressHelper helper(&status.GetMakefile(), "upload");
+
+ if (showProgress) {
+ res = ::curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
+ check_curl_result(res, "UPLOAD cannot set noprogress value: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,
+ cmFileUploadProgressCallback);
+ check_curl_result(res, "UPLOAD cannot set progress function: ");
+
+ res = ::curl_easy_setopt(curl, CURLOPT_PROGRESSDATA,
+ reinterpret_cast<void*>(&helper));
+ check_curl_result(res, "UPLOAD cannot set progress data: ");
+ }
+
+ // now specify which file to upload
+ res = ::curl_easy_setopt(curl, CURLOPT_INFILE, fin);
+ check_curl_result(res, "UPLOAD cannot set input file: ");
+
+ // and give the size of the upload (optional)
+ res =
+ ::curl_easy_setopt(curl, CURLOPT_INFILESIZE, static_cast<long>(file_size));
+ check_curl_result(res, "UPLOAD cannot set input file size: ");
+
+ if (!userpwd.empty()) {
+ res = ::curl_easy_setopt(curl, CURLOPT_USERPWD, userpwd.c_str());
+ check_curl_result(res, "UPLOAD cannot set user password: ");
+ }
+
+ // check to see if netrc parameters have been specified
+ // local command args takes precedence over CMAKE_NETRC*
+ netrc_level = cmSystemTools::UpperCase(netrc_level);
+ std::string const& netrc_option_err =
+ cmCurlSetNETRCOption(curl, netrc_level, netrc_file);
+ if (!netrc_option_err.empty()) {
+ status.SetError(netrc_option_err);
+ return false;
+ }
+
+ struct curl_slist* headers = nullptr;
+ for (std::string const& h : curl_headers) {
+ headers = ::curl_slist_append(headers, h.c_str());
+ }
+ ::curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+
+ res = ::curl_easy_perform(curl);
+
+ ::curl_slist_free_all(headers);
+
+ /* always cleanup */
+ g_curl.release();
+ ::curl_easy_cleanup(curl);
+
+ if (!statusVar.empty()) {
+ status.GetMakefile().AddDefinition(
+ statusVar,
+ cmStrCat(static_cast<int>(res), ";\"", ::curl_easy_strerror(res), "\""));
+ }
+
+ ::curl_global_cleanup();
+
+ fclose(fin);
+ fin = nullptr;
+
+ if (!logVar.empty()) {
+ std::string log;
+
+ if (!chunkResponse.empty()) {
+ chunkResponse.push_back(0);
+ log += "Response:\n";
+ log += chunkResponse.data();
+ log += "\n";
+ }
+
+ if (!chunkDebug.empty()) {
+ chunkDebug.push_back(0);
+ log += "Debug:\n";
+ log += chunkDebug.data();
+ log += "\n";
+ }
+
+ status.GetMakefile().AddDefinition(logVar, log);
+ }
+
+ return true;
+#else
+ status.SetError("UPLOAD not supported by bootstrap cmake.");
+ return false;
+#endif
+}
+
+void AddEvaluationFile(const std::string& inputName,
+ const std::string& targetName,
+ const std::string& outputExpr,
+ const std::string& condition, bool inputIsContent,
+ const std::string& newLineCharacter, mode_t permissions,
+ cmExecutionStatus& status)
+{
+ cmListFileBacktrace lfbt = status.GetMakefile().GetBacktrace();
+
+ cmGeneratorExpression outputGe(lfbt);
+ std::unique_ptr<cmCompiledGeneratorExpression> outputCge =
+ outputGe.Parse(outputExpr);
+
+ cmGeneratorExpression conditionGe(lfbt);
+ std::unique_ptr<cmCompiledGeneratorExpression> conditionCge =
+ conditionGe.Parse(condition);
+
+ status.GetMakefile().AddEvaluationFile(
+ inputName, targetName, std::move(outputCge), std::move(conditionCge),
+ newLineCharacter, permissions, inputIsContent);
+}
+
+bool HandleGenerateCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 5) {
+ status.SetError("Incorrect arguments to GENERATE subcommand.");
+ return false;
+ }
+
+ struct Arguments
+ {
+ std::string Output;
+ std::string Input;
+ std::string Content;
+ std::string Condition;
+ std::string Target;
+ std::string NewLineStyle;
+ bool NoSourcePermissions = false;
+ bool UseSourcePermissions = false;
+ std::vector<std::string> FilePermissions;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("OUTPUT"_s, &Arguments::Output)
+ .Bind("INPUT"_s, &Arguments::Input)
+ .Bind("CONTENT"_s, &Arguments::Content)
+ .Bind("CONDITION"_s, &Arguments::Condition)
+ .Bind("TARGET"_s, &Arguments::Target)
+ .Bind("NO_SOURCE_PERMISSIONS"_s, &Arguments::NoSourcePermissions)
+ .Bind("USE_SOURCE_PERMISSIONS"_s, &Arguments::UseSourcePermissions)
+ .Bind("FILE_PERMISSIONS"_s, &Arguments::FilePermissions)
+ .Bind("NEWLINE_STYLE"_s, &Arguments::NewLineStyle);
+
+ std::vector<std::string> unparsedArguments;
+ std::vector<std::string> keywordsMissingValues;
+ std::vector<std::string> parsedKeywords;
+ Arguments const arguments =
+ parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments,
+ &keywordsMissingValues, &parsedKeywords);
+
+ if (!keywordsMissingValues.empty()) {
+ status.SetError("Incorrect arguments to GENERATE subcommand.");
+ return false;
+ }
+
+ if (!unparsedArguments.empty()) {
+ status.SetError("Unknown argument to GENERATE subcommand.");
+ return false;
+ }
+
+ bool mandatoryOptionsSpecified = false;
+ if (parsedKeywords.size() > 1) {
+ const bool outputOprionSpecified = parsedKeywords[0] == "OUTPUT"_s;
+ const bool inputOrContentSpecified =
+ parsedKeywords[1] == "INPUT"_s || parsedKeywords[1] == "CONTENT"_s;
+ if (outputOprionSpecified && inputOrContentSpecified) {
+ mandatoryOptionsSpecified = true;
+ }
+ }
+ if (!mandatoryOptionsSpecified) {
+ status.SetError("Incorrect arguments to GENERATE subcommand.");
+ return false;
+ }
+
+ const bool conditionOptionSpecified =
+ std::find(parsedKeywords.begin(), parsedKeywords.end(), "CONDITION"_s) !=
+ parsedKeywords.end();
+ if (conditionOptionSpecified && arguments.Condition.empty()) {
+ status.SetError("CONDITION of sub-command GENERATE must not be empty "
+ "if specified.");
+ return false;
+ }
+
+ const bool targetOptionSpecified =
+ std::find(parsedKeywords.begin(), parsedKeywords.end(), "TARGET"_s) !=
+ parsedKeywords.end();
+ if (targetOptionSpecified && arguments.Target.empty()) {
+ status.SetError("TARGET of sub-command GENERATE must not be empty "
+ "if specified.");
+ return false;
+ }
+
+ const bool outputOptionSpecified =
+ std::find(parsedKeywords.begin(), parsedKeywords.end(), "OUTPUT"_s) !=
+ parsedKeywords.end();
+ if (outputOptionSpecified && parsedKeywords[0] != "OUTPUT"_s) {
+ status.SetError("Incorrect arguments to GENERATE subcommand.");
+ return false;
+ }
+
+ const bool inputIsContent = parsedKeywords[1] != "INPUT"_s;
+ if (inputIsContent && parsedKeywords[1] != "CONTENT") {
+ status.SetError("Unknown argument to GENERATE subcommand.");
+ }
+
+ const bool newLineStyleSpecified =
+ std::find(parsedKeywords.begin(), parsedKeywords.end(),
+ "NEWLINE_STYLE"_s) != parsedKeywords.end();
+ cmNewLineStyle newLineStyle;
+ if (newLineStyleSpecified) {
+ std::string errorMessage;
+ if (!newLineStyle.ReadFromArguments(args, errorMessage)) {
+ status.SetError(cmStrCat("GENERATE ", errorMessage));
+ return false;
+ }
+ }
+
+ std::string input = arguments.Input;
+ if (inputIsContent) {
+ input = arguments.Content;
+ }
+
+ if (arguments.NoSourcePermissions && arguments.UseSourcePermissions) {
+ status.SetError("given both NO_SOURCE_PERMISSIONS and "
+ "USE_SOURCE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+
+ if (!arguments.FilePermissions.empty()) {
+ if (arguments.NoSourcePermissions) {
+ status.SetError("given both NO_SOURCE_PERMISSIONS and "
+ "FILE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+ if (arguments.UseSourcePermissions) {
+ status.SetError("given both USE_SOURCE_PERMISSIONS and "
+ "FILE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+ }
+
+ if (arguments.UseSourcePermissions) {
+ if (inputIsContent) {
+ status.SetError("given USE_SOURCE_PERMISSIONS without a file INPUT.");
+ return false;
+ }
+ }
+
+ mode_t permissions = 0;
+ if (arguments.NoSourcePermissions) {
+ permissions |= cmFSPermissions::mode_owner_read;
+ permissions |= cmFSPermissions::mode_owner_write;
+ permissions |= cmFSPermissions::mode_group_read;
+ permissions |= cmFSPermissions::mode_world_read;
+ }
+
+ if (!arguments.FilePermissions.empty()) {
+ std::vector<std::string> invalidOptions;
+ for (auto const& e : arguments.FilePermissions) {
+ if (!cmFSPermissions::stringToModeT(e, permissions)) {
+ invalidOptions.push_back(e);
+ }
+ }
+ if (!invalidOptions.empty()) {
+ std::ostringstream oss;
+ oss << "given invalid permission ";
+ for (auto i = 0u; i < invalidOptions.size(); i++) {
+ if (i == 0u) {
+ oss << "\"" << invalidOptions[i] << "\"";
+ } else {
+ oss << ",\"" << invalidOptions[i] << "\"";
+ }
+ }
+ oss << ".";
+ status.SetError(oss.str());
+ return false;
+ }
+ }
+
+ AddEvaluationFile(input, arguments.Target, arguments.Output,
+ arguments.Condition, inputIsContent,
+ newLineStyle.GetCharacters(), permissions, status);
+ return true;
+}
+
+bool HandleLockCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ // Default values
+ bool directory = false;
+ bool release = false;
+ enum Guard
+ {
+ GUARD_FUNCTION,
+ GUARD_FILE,
+ GUARD_PROCESS
+ };
+ Guard guard = GUARD_PROCESS;
+ std::string resultVariable;
+ unsigned long timeout = static_cast<unsigned long>(-1);
+
+ // Parse arguments
+ if (args.size() < 2) {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ "sub-command LOCK requires at least two arguments.");
+ return false;
+ }
+
+ std::string path = args[1];
+ for (unsigned i = 2; i < args.size(); ++i) {
+ if (args[i] == "DIRECTORY") {
+ directory = true;
+ } else if (args[i] == "RELEASE") {
+ release = true;
+ } else if (args[i] == "GUARD") {
+ ++i;
+ const char* merr = "expected FUNCTION, FILE or PROCESS after GUARD";
+ if (i >= args.size()) {
+ status.GetMakefile().IssueMessage(MessageType::FATAL_ERROR, merr);
+ return false;
+ }
+ if (args[i] == "FUNCTION") {
+ guard = GUARD_FUNCTION;
+ } else if (args[i] == "FILE") {
+ guard = GUARD_FILE;
+ } else if (args[i] == "PROCESS") {
+ guard = GUARD_PROCESS;
+ } else {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(merr, ", but got:\n \"", args[i], "\"."));
+ return false;
+ }
+
+ } else if (args[i] == "RESULT_VARIABLE") {
+ ++i;
+ if (i >= args.size()) {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ "expected variable name after RESULT_VARIABLE");
+ return false;
+ }
+ resultVariable = args[i];
+ } else if (args[i] == "TIMEOUT") {
+ ++i;
+ if (i >= args.size()) {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR, "expected timeout value after TIMEOUT");
+ return false;
+ }
+ long scanned;
+ if (!cmStrToLong(args[i], &scanned) || scanned < 0) {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("TIMEOUT value \"", args[i],
+ "\" is not an unsigned integer."));
+ return false;
+ }
+ timeout = static_cast<unsigned long>(scanned);
+ } else {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("expected DIRECTORY, RELEASE, GUARD, RESULT_VARIABLE or ",
+ "TIMEOUT\nbut got: \"", args[i], "\"."));
+ return false;
+ }
+ }
+
+ if (directory) {
+ path += "/cmake.lock";
+ }
+
+ // Unify path (remove '//', '/../', ...)
+ path = cmSystemTools::CollapseFullPath(
+ path, status.GetMakefile().GetCurrentSourceDirectory());
+
+ // Create file and directories if needed
+ std::string parentDir = cmSystemTools::GetParentDirectory(path);
+ if (!cmSystemTools::MakeDirectory(parentDir)) {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("directory\n \"", parentDir,
+ "\"\ncreation failed (check permissions)."));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ FILE* file = cmsys::SystemTools::Fopen(path, "w");
+ if (!file) {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("file\n \"", path,
+ "\"\ncreation failed (check permissions)."));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ fclose(file);
+
+ // Actual lock/unlock
+ cmFileLockPool& lockPool =
+ status.GetMakefile().GetGlobalGenerator()->GetFileLockPool();
+
+ cmFileLockResult fileLockResult(cmFileLockResult::MakeOk());
+ if (release) {
+ fileLockResult = lockPool.Release(path);
+ } else {
+ switch (guard) {
+ case GUARD_FUNCTION:
+ fileLockResult = lockPool.LockFunctionScope(path, timeout);
+ break;
+ case GUARD_FILE:
+ fileLockResult = lockPool.LockFileScope(path, timeout);
+ break;
+ case GUARD_PROCESS:
+ fileLockResult = lockPool.LockProcessScope(path, timeout);
+ break;
+ default:
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+
+ const std::string result = fileLockResult.GetOutputMessage();
+
+ if (resultVariable.empty() && !fileLockResult.IsOk()) {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("error locking file\n \"", path, "\"\n", result, "."));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!resultVariable.empty()) {
+ status.GetMakefile().AddDefinition(resultVariable, result);
+ }
+
+ return true;
+#else
+ static_cast<void>(args);
+ status.SetError("sub-command LOCK not implemented in bootstrap cmake");
+ return false;
+#endif
+}
+
+bool HandleTimestampCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("sub-command TIMESTAMP requires at least two arguments.");
+ return false;
+ }
+ if (args.size() > 5) {
+ status.SetError("sub-command TIMESTAMP takes at most four arguments.");
+ return false;
+ }
+
+ unsigned int argsIndex = 1;
+
+ const std::string& filename = args[argsIndex++];
+
+ const std::string& outputVariable = args[argsIndex++];
+
+ std::string formatString;
+ if (args.size() > argsIndex && args[argsIndex] != "UTC") {
+ formatString = args[argsIndex++];
+ }
+
+ bool utcFlag = false;
+ if (args.size() > argsIndex) {
+ if (args[argsIndex] == "UTC") {
+ utcFlag = true;
+ } else {
+ std::string e = " TIMESTAMP sub-command does not recognize option " +
+ args[argsIndex] + ".";
+ status.SetError(e);
+ return false;
+ }
+ }
+
+ cmTimestamp timestamp;
+ std::string result =
+ timestamp.FileModificationTime(filename.c_str(), formatString, utcFlag);
+ status.GetMakefile().AddDefinition(outputVariable, result);
+
+ return true;
+}
+
+bool HandleSizeCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError(
+ cmStrCat(args[0], " requires a file name and output variable"));
+ return false;
+ }
+
+ unsigned int argsIndex = 1;
+
+ const std::string& filename = args[argsIndex++];
+
+ const std::string& outputVariable = args[argsIndex++];
+
+ if (!cmSystemTools::FileExists(filename, true)) {
+ status.SetError(
+ cmStrCat("SIZE requested of path that is not readable:\n ", filename));
+ return false;
+ }
+
+ status.GetMakefile().AddDefinition(
+ outputVariable, std::to_string(cmSystemTools::FileLength(filename)));
+
+ return true;
+}
+
+bool HandleReadSymlinkCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError(
+ cmStrCat(args[0], " requires a file name and output variable"));
+ return false;
+ }
+
+ const std::string& filename = args[1];
+ const std::string& outputVariable = args[2];
+
+ std::string result;
+ if (!cmSystemTools::ReadSymlink(filename, result)) {
+ status.SetError(cmStrCat(
+ "READ_SYMLINK requested of path that is not a symlink:\n ", filename));
+ return false;
+ }
+
+ status.GetMakefile().AddDefinition(outputVariable, result);
+
+ return true;
+}
+
+bool HandleCreateLinkCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("CREATE_LINK must be called with at least two additional "
+ "arguments");
+ return false;
+ }
+
+ std::string const& fileName = args[1];
+ std::string const& newFileName = args[2];
+
+ struct Arguments
+ {
+ std::string Result;
+ bool CopyOnError = false;
+ bool Symbolic = false;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("RESULT"_s, &Arguments::Result)
+ .Bind("COPY_ON_ERROR"_s, &Arguments::CopyOnError)
+ .Bind("SYMBOLIC"_s, &Arguments::Symbolic);
+
+ std::vector<std::string> unconsumedArgs;
+ Arguments const arguments =
+ parser.Parse(cmMakeRange(args).advance(3), &unconsumedArgs);
+
+ if (!unconsumedArgs.empty()) {
+ status.SetError("unknown argument: \"" + unconsumedArgs.front() + '\"');
+ return false;
+ }
+
+ // The system error message generated in the operation.
+ std::string result;
+
+ // Check if the paths are distinct.
+ if (fileName == newFileName) {
+ result = "CREATE_LINK cannot use same file and newfile";
+ if (!arguments.Result.empty()) {
+ status.GetMakefile().AddDefinition(arguments.Result, result);
+ return true;
+ }
+ status.SetError(result);
+ return false;
+ }
+
+ // Hard link requires original file to exist.
+ if (!arguments.Symbolic && !cmSystemTools::FileExists(fileName)) {
+ result = "Cannot hard link \'" + fileName + "\' as it does not exist.";
+ if (!arguments.Result.empty()) {
+ status.GetMakefile().AddDefinition(arguments.Result, result);
+ return true;
+ }
+ status.SetError(result);
+ return false;
+ }
+
+ // Check if the new file already exists and remove it.
+ if ((cmSystemTools::FileExists(newFileName) ||
+ cmSystemTools::FileIsSymlink(newFileName)) &&
+ !cmSystemTools::RemoveFile(newFileName)) {
+ std::ostringstream e;
+ e << "Failed to create link '" << newFileName
+ << "' because existing path cannot be removed: "
+ << cmSystemTools::GetLastSystemError() << "\n";
+
+ if (!arguments.Result.empty()) {
+ status.GetMakefile().AddDefinition(arguments.Result, e.str());
+ return true;
+ }
+ status.SetError(e.str());
+ return false;
+ }
+
+ // Whether the operation completed successfully.
+ bool completed = false;
+
+ // Check if the command requires a symbolic link.
+ if (arguments.Symbolic) {
+ completed = cmSystemTools::CreateSymlink(fileName, newFileName, &result);
+ } else {
+ completed = cmSystemTools::CreateLink(fileName, newFileName, &result);
+ }
+
+ // Check if copy-on-error is enabled in the arguments.
+ if (!completed && arguments.CopyOnError) {
+ completed = cmsys::SystemTools::CopyFileAlways(fileName, newFileName);
+ if (!completed) {
+ result = "Copy failed: " + cmSystemTools::GetLastSystemError();
+ }
+ }
+
+ // Check if the operation was successful.
+ if (completed) {
+ result = "0";
+ } else if (arguments.Result.empty()) {
+ // The operation failed and the result is not reported in a variable.
+ status.SetError(result);
+ return false;
+ }
+
+ if (!arguments.Result.empty()) {
+ status.GetMakefile().AddDefinition(arguments.Result, result);
+ }
+
+ return true;
+}
+
+bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ static const std::set<std::string> supportedPlatforms = { "Windows", "Linux",
+ "Darwin" };
+ std::string platform =
+ status.GetMakefile().GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
+ if (!supportedPlatforms.count(platform)) {
+ status.SetError(
+ cmStrCat("GET_RUNTIME_DEPENDENCIES is not supported on system \"",
+ platform, "\""));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (status.GetMakefile().GetState()->GetMode() == cmState::Project) {
+ status.GetMakefile().IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ "You have used file(GET_RUNTIME_DEPENDENCIES)"
+ " in project mode. This is probably not what "
+ "you intended to do. Instead, please consider"
+ " using it in an install(CODE) or "
+ "install(SCRIPT) command. For example:"
+ "\n install(CODE [["
+ "\n file(GET_RUNTIME_DEPENDENCIES"
+ "\n # ..."
+ "\n )"
+ "\n ]])");
+ }
+
+ struct Arguments
+ {
+ std::string ResolvedDependenciesVar;
+ std::string UnresolvedDependenciesVar;
+ std::string ConflictingDependenciesPrefix;
+ std::string BundleExecutable;
+ std::vector<std::string> Executables;
+ std::vector<std::string> Libraries;
+ std::vector<std::string> Directories;
+ std::vector<std::string> Modules;
+ std::vector<std::string> PreIncludeRegexes;
+ std::vector<std::string> PreExcludeRegexes;
+ std::vector<std::string> PostIncludeRegexes;
+ std::vector<std::string> PostExcludeRegexes;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("RESOLVED_DEPENDENCIES_VAR"_s, &Arguments::ResolvedDependenciesVar)
+ .Bind("UNRESOLVED_DEPENDENCIES_VAR"_s,
+ &Arguments::UnresolvedDependenciesVar)
+ .Bind("CONFLICTING_DEPENDENCIES_PREFIX"_s,
+ &Arguments::ConflictingDependenciesPrefix)
+ .Bind("BUNDLE_EXECUTABLE"_s, &Arguments::BundleExecutable)
+ .Bind("EXECUTABLES"_s, &Arguments::Executables)
+ .Bind("LIBRARIES"_s, &Arguments::Libraries)
+ .Bind("MODULES"_s, &Arguments::Modules)
+ .Bind("DIRECTORIES"_s, &Arguments::Directories)
+ .Bind("PRE_INCLUDE_REGEXES"_s, &Arguments::PreIncludeRegexes)
+ .Bind("PRE_EXCLUDE_REGEXES"_s, &Arguments::PreExcludeRegexes)
+ .Bind("POST_INCLUDE_REGEXES"_s, &Arguments::PostIncludeRegexes)
+ .Bind("POST_EXCLUDE_REGEXES"_s, &Arguments::PostExcludeRegexes);
+
+ std::vector<std::string> unrecognizedArguments;
+ std::vector<std::string> keywordsMissingValues;
+ auto parsedArgs =
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
+ &keywordsMissingValues);
+ auto argIt = unrecognizedArguments.begin();
+ if (argIt != unrecognizedArguments.end()) {
+ status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\""));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ const std::vector<std::string> LIST_ARGS = { "DIRECTORIES",
+ "EXECUTABLES",
+ "LIBRARIES",
+ "MODULES",
+ "POST_EXCLUDE_REGEXES",
+ "POST_INCLUDE_REGEXES",
+ "PRE_EXCLUDE_REGEXES",
+ "PRE_INCLUDE_REGEXES" };
+ auto kwbegin = keywordsMissingValues.cbegin();
+ auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS);
+ if (kwend != kwbegin) {
+ status.SetError(cmStrCat("Keywords missing values:\n ",
+ cmJoin(cmMakeRange(kwbegin, kwend), "\n ")));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ cmRuntimeDependencyArchive archive(
+ status, parsedArgs.Directories, parsedArgs.BundleExecutable,
+ parsedArgs.PreIncludeRegexes, parsedArgs.PreExcludeRegexes,
+ parsedArgs.PostIncludeRegexes, parsedArgs.PostExcludeRegexes);
+ if (!archive.Prepare()) {
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!archive.GetRuntimeDependencies(
+ parsedArgs.Executables, parsedArgs.Libraries, parsedArgs.Modules)) {
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ std::vector<std::string> deps;
+ std::vector<std::string> unresolvedDeps;
+ std::vector<std::string> conflictingDeps;
+ for (auto const& val : archive.GetResolvedPaths()) {
+ bool unique = true;
+ auto it = val.second.begin();
+ assert(it != val.second.end());
+ auto const& firstPath = *it;
+ while (++it != val.second.end()) {
+ if (!cmSystemTools::SameFile(firstPath, *it)) {
+ unique = false;
+ break;
+ }
+ }
+
+ if (unique) {
+ deps.push_back(firstPath);
+ } else if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
+ conflictingDeps.push_back(val.first);
+ std::vector<std::string> paths;
+ paths.insert(paths.begin(), val.second.begin(), val.second.end());
+ std::string varName =
+ parsedArgs.ConflictingDependenciesPrefix + "_" + val.first;
+ std::string pathsStr = cmJoin(paths, ";");
+ status.GetMakefile().AddDefinition(varName, pathsStr);
+ } else {
+ std::ostringstream e;
+ e << "Multiple conflicting paths found for " << val.first << ":";
+ for (auto const& path : val.second) {
+ e << "\n " << path;
+ }
+ status.SetError(e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+ if (!archive.GetUnresolvedPaths().empty()) {
+ if (!parsedArgs.UnresolvedDependenciesVar.empty()) {
+ unresolvedDeps.insert(unresolvedDeps.begin(),
+ archive.GetUnresolvedPaths().begin(),
+ archive.GetUnresolvedPaths().end());
+ } else {
+ auto it = archive.GetUnresolvedPaths().begin();
+ assert(it != archive.GetUnresolvedPaths().end());
+ status.SetError(cmStrCat("Could not resolve file ", *it));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+
+ if (!parsedArgs.ResolvedDependenciesVar.empty()) {
+ std::string val = cmJoin(deps, ";");
+ status.GetMakefile().AddDefinition(parsedArgs.ResolvedDependenciesVar,
+ val);
+ }
+ if (!parsedArgs.UnresolvedDependenciesVar.empty()) {
+ std::string val = cmJoin(unresolvedDeps, ";");
+ status.GetMakefile().AddDefinition(parsedArgs.UnresolvedDependenciesVar,
+ val);
+ }
+ if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
+ std::string val = cmJoin(conflictingDeps, ";");
+ status.GetMakefile().AddDefinition(
+ parsedArgs.ConflictingDependenciesPrefix + "_FILENAMES", val);
+ }
+ return true;
+}
+
+bool HandleConfigureCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ struct Arguments
+ {
+ std::string Output;
+ std::string Content;
+ bool EscapeQuotes = false;
+ bool AtOnly = false;
+ std::string NewlineStyle;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("OUTPUT"_s, &Arguments::Output)
+ .Bind("CONTENT"_s, &Arguments::Content)
+ .Bind("ESCAPE_QUOTES"_s, &Arguments::EscapeQuotes)
+ .Bind("@ONLY"_s, &Arguments::AtOnly)
+ .Bind("NEWLINE_STYLE"_s, &Arguments::NewlineStyle);
+
+ std::vector<std::string> unrecognizedArguments;
+ std::vector<std::string> keywordsMissingArguments;
+ std::vector<std::string> parsedKeywords;
+ auto parsedArgs =
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
+ &keywordsMissingArguments, &parsedKeywords);
+
+ auto argIt = unrecognizedArguments.begin();
+ if (argIt != unrecognizedArguments.end()) {
+ status.SetError(
+ cmStrCat("CONFIGURE Unrecognized argument: \"", *argIt, "\""));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ std::vector<std::string> mandatoryOptions{ "OUTPUT", "CONTENT" };
+ for (auto const& e : mandatoryOptions) {
+ const bool optionHasNoValue =
+ std::find(keywordsMissingArguments.begin(),
+ keywordsMissingArguments.end(),
+ e) != keywordsMissingArguments.end();
+ if (optionHasNoValue) {
+ status.SetError(cmStrCat("CONFIGURE ", e, " option needs a value."));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+
+ for (auto const& e : mandatoryOptions) {
+ const bool optionGiven =
+ std::find(parsedKeywords.begin(), parsedKeywords.end(), e) !=
+ parsedKeywords.end();
+ if (!optionGiven) {
+ status.SetError(cmStrCat("CONFIGURE ", e, " option is mandatory."));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+
+ std::string errorMessage;
+ cmNewLineStyle newLineStyle;
+ if (!newLineStyle.ReadFromArguments(args, errorMessage)) {
+ status.SetError(cmStrCat("CONFIGURE ", errorMessage));
+ return false;
+ }
+
+ // Check for generator expressions
+ std::string outputFile = cmSystemTools::CollapseFullPath(
+ parsedArgs.Output, status.GetMakefile().GetCurrentBinaryDirectory());
+
+ std::string::size_type pos = outputFile.find_first_of("<>");
+ if (pos != std::string::npos) {
+ status.SetError(cmStrCat("CONFIGURE called with OUTPUT containing a \"",
+ outputFile[pos],
+ "\". This character is not allowed."));
+ return false;
+ }
+
+ cmMakefile& makeFile = status.GetMakefile();
+ if (!makeFile.CanIWriteThisFile(outputFile)) {
+ cmSystemTools::Error("Attempt to write file: " + outputFile +
+ " into a source directory.");
+ return false;
+ }
+
+ cmSystemTools::ConvertToUnixSlashes(outputFile);
+
+ // Re-generate if non-temporary outputs are missing.
+ // when we finalize the configuration we will remove all
+ // output files that now don't exist.
+ makeFile.AddCMakeOutputFile(outputFile);
+
+ // Create output directory
+ const std::string::size_type slashPos = outputFile.rfind('/');
+ if (slashPos != std::string::npos) {
+ const std::string path = outputFile.substr(0, slashPos);
+ cmSystemTools::MakeDirectory(path);
+ }
+
+ std::string newLineCharacters = "\n";
+ bool open_with_binary_flag = false;
+ if (newLineStyle.IsValid()) {
+ newLineCharacters = newLineStyle.GetCharacters();
+ open_with_binary_flag = true;
+ }
+
+ cmGeneratedFileStream fout;
+ fout.Open(outputFile, false, open_with_binary_flag);
+ if (!fout) {
+ cmSystemTools::Error("Could not open file for write in copy operation " +
+ outputFile);
+ cmSystemTools::ReportLastSystemError("");
+ return false;
+ }
+ fout.SetCopyIfDifferent(true);
+
+ // copy input to output and expand variables from input at the same time
+ std::stringstream sin(parsedArgs.Content, std::ios::in);
+ std::string inLine;
+ std::string outLine;
+ bool hasNewLine = false;
+ while (cmSystemTools::GetLineFromStream(sin, inLine, &hasNewLine)) {
+ outLine.clear();
+ makeFile.ConfigureString(inLine, outLine, parsedArgs.AtOnly,
+ parsedArgs.EscapeQuotes);
+ fout << outLine;
+ if (hasNewLine || newLineStyle.IsValid()) {
+ fout << newLineCharacters;
+ }
+ }
+
+ // close file before attempting to copy
+ fout.close();
+
+ return true;
+}
+
+bool HandleArchiveCreateCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ struct Arguments
+ {
+ std::string Output;
+ std::string Format;
+ std::string Compression;
+ std::string CompressionLevel;
+ std::string MTime;
+ bool Verbose = false;
+ std::vector<std::string> Paths;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("OUTPUT"_s, &Arguments::Output)
+ .Bind("FORMAT"_s, &Arguments::Format)
+ .Bind("COMPRESSION"_s, &Arguments::Compression)
+ .Bind("COMPRESSION_LEVEL"_s, &Arguments::CompressionLevel)
+ .Bind("MTIME"_s, &Arguments::MTime)
+ .Bind("VERBOSE"_s, &Arguments::Verbose)
+ .Bind("PATHS"_s, &Arguments::Paths);
+
+ std::vector<std::string> unrecognizedArguments;
+ std::vector<std::string> keywordsMissingValues;
+ auto parsedArgs =
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
+ &keywordsMissingValues);
+ auto argIt = unrecognizedArguments.begin();
+ if (argIt != unrecognizedArguments.end()) {
+ status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\""));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ const std::vector<std::string> LIST_ARGS = {
+ "OUTPUT", "FORMAT", "COMPRESSION", "COMPRESSION_LEVEL", "MTIME", "PATHS"
+ };
+ auto kwbegin = keywordsMissingValues.cbegin();
+ auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS);
+ if (kwend != kwbegin) {
+ status.SetError(cmStrCat("Keywords missing values:\n ",
+ cmJoin(cmMakeRange(kwbegin, kwend), "\n ")));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ const char* knownFormats[] = {
+ "7zip", "gnutar", "pax", "paxr", "raw", "zip"
+ };
+
+ if (!parsedArgs.Format.empty() &&
+ !cm::contains(knownFormats, parsedArgs.Format)) {
+ status.SetError(
+ cmStrCat("archive format ", parsedArgs.Format, " not supported"));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ const char* zipFileFormats[] = { "7zip", "zip" };
+ if (!parsedArgs.Compression.empty() &&
+ cm::contains(zipFileFormats, parsedArgs.Format)) {
+ status.SetError(cmStrCat("archive format ", parsedArgs.Format,
+ " does not support COMPRESSION arguments"));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ static std::map<std::string, cmSystemTools::cmTarCompression>
+ compressionTypeMap = { { "None", cmSystemTools::TarCompressNone },
+ { "BZip2", cmSystemTools::TarCompressBZip2 },
+ { "GZip", cmSystemTools::TarCompressGZip },
+ { "XZ", cmSystemTools::TarCompressXZ },
+ { "Zstd", cmSystemTools::TarCompressZstd } };
+
+ cmSystemTools::cmTarCompression compress = cmSystemTools::TarCompressNone;
+ auto typeIt = compressionTypeMap.find(parsedArgs.Compression);
+ if (typeIt != compressionTypeMap.end()) {
+ compress = typeIt->second;
+ } else if (!parsedArgs.Compression.empty()) {
+ status.SetError(cmStrCat("compression type ", parsedArgs.Compression,
+ " is not supported"));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ int compressionLevel = 0;
+ if (!parsedArgs.CompressionLevel.empty()) {
+ if (parsedArgs.CompressionLevel.size() != 1 &&
+ !std::isdigit(parsedArgs.CompressionLevel[0])) {
+ status.SetError(cmStrCat("compression level ",
+ parsedArgs.CompressionLevel,
+ " should be in range 0 to 9"));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ compressionLevel = std::stoi(parsedArgs.CompressionLevel);
+ if (compressionLevel < 0 || compressionLevel > 9) {
+ status.SetError(cmStrCat("compression level ",
+ parsedArgs.CompressionLevel,
+ " should be in range 0 to 9"));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ if (compress == cmSystemTools::TarCompressNone) {
+ status.SetError(cmStrCat("compression level is not supported for "
+ "compression \"None\"",
+ parsedArgs.Compression));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+
+ if (parsedArgs.Paths.empty()) {
+ status.SetError("ARCHIVE_CREATE requires a non-empty list of PATHS");
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!cmSystemTools::CreateTar(parsedArgs.Output, parsedArgs.Paths, compress,
+ parsedArgs.Verbose, parsedArgs.MTime,
+ parsedArgs.Format, compressionLevel)) {
+ status.SetError(cmStrCat("failed to compress: ", parsedArgs.Output));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ return true;
+}
+
+bool HandleArchiveExtractCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ struct Arguments
+ {
+ std::string Input;
+ bool Verbose = false;
+ bool ListOnly = false;
+ std::string Destination;
+ std::vector<std::string> Patterns;
+ };
+
+ static auto const parser = cmArgumentParser<Arguments>{}
+ .Bind("INPUT"_s, &Arguments::Input)
+ .Bind("VERBOSE"_s, &Arguments::Verbose)
+ .Bind("LIST_ONLY"_s, &Arguments::ListOnly)
+ .Bind("DESTINATION"_s, &Arguments::Destination)
+ .Bind("PATTERNS"_s, &Arguments::Patterns);
+
+ std::vector<std::string> unrecognizedArguments;
+ std::vector<std::string> keywordsMissingValues;
+ auto parsedArgs =
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
+ &keywordsMissingValues);
+ auto argIt = unrecognizedArguments.begin();
+ if (argIt != unrecognizedArguments.end()) {
+ status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\""));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ const std::vector<std::string> LIST_ARGS = { "INPUT", "DESTINATION",
+ "PATTERNS" };
+ auto kwbegin = keywordsMissingValues.cbegin();
+ auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS);
+ if (kwend != kwbegin) {
+ status.SetError(cmStrCat("Keywords missing values:\n ",
+ cmJoin(cmMakeRange(kwbegin, kwend), "\n ")));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ std::string inFile = parsedArgs.Input;
+
+ if (parsedArgs.ListOnly) {
+ if (!cmSystemTools::ListTar(inFile, parsedArgs.Patterns,
+ parsedArgs.Verbose)) {
+ status.SetError(cmStrCat("failed to list: ", inFile));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ } else {
+ std::string destDir = status.GetMakefile().GetCurrentBinaryDirectory();
+ if (!parsedArgs.Destination.empty()) {
+ if (cmSystemTools::FileIsFullPath(parsedArgs.Destination)) {
+ destDir = parsedArgs.Destination;
+ } else {
+ destDir = cmStrCat(destDir, "/", parsedArgs.Destination);
+ }
+
+ if (!cmSystemTools::MakeDirectory(destDir)) {
+ status.SetError(cmStrCat("failed to create directory: ", destDir));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!cmSystemTools::FileIsFullPath(inFile)) {
+ inFile =
+ cmStrCat(cmSystemTools::GetCurrentWorkingDirectory(), "/", inFile);
+ }
+ }
+
+ cmWorkingDirectory workdir(destDir);
+ if (workdir.Failed()) {
+ status.SetError(
+ cmStrCat("failed to change working directory to: ", destDir));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!cmSystemTools::ExtractTar(inFile, parsedArgs.Patterns,
+ parsedArgs.Verbose)) {
+ status.SetError(cmStrCat("failed to extract: ", inFile));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ValidateAndConvertPermissions(const std::vector<std::string>& permissions,
+ mode_t& perms, cmExecutionStatus& status)
+{
+ for (const auto& i : permissions) {
+ if (!cmFSPermissions::stringToModeT(i, perms)) {
+ status.SetError(i + " is an invalid permission specifier");
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool SetPermissions(const std::string& filename, const mode_t& perms,
+ cmExecutionStatus& status)
+{
+ if (!cmSystemTools::SetPermissions(filename, perms)) {
+ status.SetError("Failed to set permissions for " + filename);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ return true;
+}
+
+bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse,
+ cmExecutionStatus& status)
+{
+ mode_t perms = 0;
+ mode_t fperms = 0;
+ mode_t dperms = 0;
+ cmsys::Glob globber;
+
+ globber.SetRecurse(recurse);
+ globber.SetRecurseListDirs(recurse);
+
+ struct Arguments
+ {
+ std::vector<std::string> Permissions;
+ std::vector<std::string> FilePermissions;
+ std::vector<std::string> DirectoryPermissions;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("PERMISSIONS"_s, &Arguments::Permissions)
+ .Bind("FILE_PERMISSIONS"_s, &Arguments::FilePermissions)
+ .Bind("DIRECTORY_PERMISSIONS"_s, &Arguments::DirectoryPermissions);
+
+ std::vector<std::string> pathEntries;
+ std::vector<std::string> keywordsMissingValues;
+ Arguments parsedArgs = parser.Parse(cmMakeRange(args).advance(1),
+ &pathEntries, &keywordsMissingValues);
+
+ // check validity of arguments
+ if (parsedArgs.Permissions.empty() && parsedArgs.FilePermissions.empty() &&
+ parsedArgs.DirectoryPermissions.empty()) // no permissions given
+ {
+ status.SetError("No permissions given");
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!parsedArgs.Permissions.empty() && !parsedArgs.FilePermissions.empty() &&
+ !parsedArgs.DirectoryPermissions.empty()) // all keywords are used
+ {
+ status.SetError("Remove either PERMISSIONS or FILE_PERMISSIONS or "
+ "DIRECTORY_PERMISSIONS from the invocation");
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!keywordsMissingValues.empty()) {
+ for (const auto& i : keywordsMissingValues) {
+ status.SetError(i + " is not given any arguments");
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ return false;
+ }
+
+ // validate permissions
+ bool validatePermissions =
+ ValidateAndConvertPermissions(parsedArgs.Permissions, perms, status) &&
+ ValidateAndConvertPermissions(parsedArgs.FilePermissions, fperms,
+ status) &&
+ ValidateAndConvertPermissions(parsedArgs.DirectoryPermissions, dperms,
+ status);
+ if (!validatePermissions) {
+ return false;
+ }
+
+ std::vector<std::string> allPathEntries;
+
+ if (recurse) {
+ std::vector<std::string> tempPathEntries;
+ for (const auto& i : pathEntries) {
+ if (cmSystemTools::FileIsDirectory(i)) {
+ globber.FindFiles(i + "/*");
+ tempPathEntries = globber.GetFiles();
+ allPathEntries.insert(allPathEntries.end(), tempPathEntries.begin(),
+ tempPathEntries.end());
+ allPathEntries.emplace_back(i);
+ } else {
+ allPathEntries.emplace_back(i); // We validate path entries below
+ }
+ }
+ } else {
+ allPathEntries = std::move(pathEntries);
+ }
+
+ // chmod
+ for (const auto& i : allPathEntries) {
+ if (!(cmSystemTools::FileExists(i) || cmSystemTools::FileIsDirectory(i))) {
+ status.SetError(cmStrCat("does not exist:\n ", i));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (cmSystemTools::FileExists(i, true)) {
+ bool success = true;
+ const mode_t& filePermissions =
+ parsedArgs.FilePermissions.empty() ? perms : fperms;
+ if (filePermissions) {
+ success = SetPermissions(i, filePermissions, status);
+ }
+ if (!success) {
+ return false;
+ }
+ }
+
+ else if (cmSystemTools::FileIsDirectory(i)) {
+ bool success = true;
+ const mode_t& directoryPermissions =
+ parsedArgs.DirectoryPermissions.empty() ? perms : dperms;
+ if (directoryPermissions) {
+ success = SetPermissions(i, directoryPermissions, status);
+ }
+ if (!success) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool HandleChmodCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleChmodCommandImpl(args, false, status);
+}
+
+bool HandleChmodRecurseCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleChmodCommandImpl(args, true, status);
+}
+
+} // namespace
+
+bool cmFileCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("must be called with at least two arguments.");
+ return false;
+ }
+
+ static cmSubcommandTable const subcommand{
+ { "WRITE"_s, HandleWriteCommand },
+ { "APPEND"_s, HandleAppendCommand },
+ { "DOWNLOAD"_s, HandleDownloadCommand },
+ { "UPLOAD"_s, HandleUploadCommand },
+ { "READ"_s, HandleReadCommand },
+ { "MD5"_s, HandleHashCommand },
+ { "SHA1"_s, HandleHashCommand },
+ { "SHA224"_s, HandleHashCommand },
+ { "SHA256"_s, HandleHashCommand },
+ { "SHA384"_s, HandleHashCommand },
+ { "SHA512"_s, HandleHashCommand },
+ { "SHA3_224"_s, HandleHashCommand },
+ { "SHA3_256"_s, HandleHashCommand },
+ { "SHA3_384"_s, HandleHashCommand },
+ { "SHA3_512"_s, HandleHashCommand },
+ { "STRINGS"_s, HandleStringsCommand },
+ { "GLOB"_s, HandleGlobCommand },
+ { "GLOB_RECURSE"_s, HandleGlobRecurseCommand },
+ { "MAKE_DIRECTORY"_s, HandleMakeDirectoryCommand },
+ { "RENAME"_s, HandleRename },
+ { "COPY_FILE"_s, HandleCopyFile },
+ { "REMOVE"_s, HandleRemove },
+ { "REMOVE_RECURSE"_s, HandleRemoveRecurse },
+ { "COPY"_s, HandleCopyCommand },
+ { "INSTALL"_s, HandleInstallCommand },
+ { "DIFFERENT"_s, HandleDifferentCommand },
+ { "RPATH_CHANGE"_s, HandleRPathChangeCommand },
+ { "CHRPATH"_s, HandleRPathChangeCommand },
+ { "RPATH_CHECK"_s, HandleRPathCheckCommand },
+ { "RPATH_REMOVE"_s, HandleRPathRemoveCommand },
+ { "READ_ELF"_s, HandleReadElfCommand },
+ { "REAL_PATH"_s, HandleRealPathCommand },
+ { "RELATIVE_PATH"_s, HandleRelativePathCommand },
+ { "TO_CMAKE_PATH"_s, HandleCMakePathCommand },
+ { "TO_NATIVE_PATH"_s, HandleNativePathCommand },
+ { "TOUCH"_s, HandleTouchCommand },
+ { "TOUCH_NOCREATE"_s, HandleTouchNocreateCommand },
+ { "TIMESTAMP"_s, HandleTimestampCommand },
+ { "GENERATE"_s, HandleGenerateCommand },
+ { "LOCK"_s, HandleLockCommand },
+ { "SIZE"_s, HandleSizeCommand },
+ { "READ_SYMLINK"_s, HandleReadSymlinkCommand },
+ { "CREATE_LINK"_s, HandleCreateLinkCommand },
+ { "GET_RUNTIME_DEPENDENCIES"_s, HandleGetRuntimeDependenciesCommand },
+ { "CONFIGURE"_s, HandleConfigureCommand },
+ { "ARCHIVE_CREATE"_s, HandleArchiveCreateCommand },
+ { "ARCHIVE_EXTRACT"_s, HandleArchiveExtractCommand },
+ { "CHMOD"_s, HandleChmodCommand },
+ { "CHMOD_RECURSE"_s, HandleChmodRecurseCommand },
+ };
+
+ return subcommand(args[0], args, status);
+}
diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h
new file mode 100644
index 0000000..ec9ee47
--- /dev/null
+++ b/Source/cmFileCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmFileCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmFileCopier.cxx b/Source/cmFileCopier.cxx
new file mode 100644
index 0000000..48fc286
--- /dev/null
+++ b/Source/cmFileCopier.cxx
@@ -0,0 +1,712 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmFileCopier.h"
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/Glob.hxx"
+
+#include "cmExecutionStatus.h"
+#include "cmFSPermissions.h"
+#include "cmFileTimes.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+#ifdef _WIN32
+# include "cmsys/FStream.hxx"
+#endif
+
+#include <cstring>
+#include <sstream>
+
+using namespace cmFSPermissions;
+
+cmFileCopier::cmFileCopier(cmExecutionStatus& status, const char* name)
+ : Status(status)
+ , Makefile(&status.GetMakefile())
+ , Name(name)
+ , Always(false)
+ , MatchlessFiles(true)
+ , FilePermissions(0)
+ , DirPermissions(0)
+ , CurrentMatchRule(nullptr)
+ , UseGivenPermissionsFile(false)
+ , UseGivenPermissionsDir(false)
+ , UseSourcePermissions(true)
+ , FollowSymlinkChain(false)
+ , Doing(DoingNone)
+{
+}
+
+cmFileCopier::~cmFileCopier() = default;
+
+cmFileCopier::MatchProperties cmFileCopier::CollectMatchProperties(
+ const std::string& file)
+{
+ // Match rules are case-insensitive on some platforms.
+#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
+ const std::string file_to_match = cmSystemTools::LowerCase(file);
+#else
+ const std::string& file_to_match = file;
+#endif
+
+ // Collect properties from all matching rules.
+ bool matched = false;
+ MatchProperties result;
+ for (MatchRule& mr : this->MatchRules) {
+ if (mr.Regex.find(file_to_match)) {
+ matched = true;
+ result.Exclude |= mr.Properties.Exclude;
+ result.Permissions |= mr.Properties.Permissions;
+ }
+ }
+ if (!matched && !this->MatchlessFiles) {
+ result.Exclude = !cmSystemTools::FileIsDirectory(file);
+ }
+ return result;
+}
+
+bool cmFileCopier::SetPermissions(const std::string& toFile,
+ mode_t permissions)
+{
+ if (permissions) {
+#ifdef WIN32
+ if (Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
+ // Store the mode in an NTFS alternate stream.
+ std::string mode_t_adt_filename = toFile + ":cmake_mode_t";
+
+ // Writing to an NTFS alternate stream changes the modification
+ // time, so we need to save and restore its original value.
+ cmFileTimes file_time_orig(toFile);
+ {
+ cmsys::ofstream permissionStream(mode_t_adt_filename.c_str());
+ if (permissionStream) {
+ permissionStream << std::oct << permissions << std::endl;
+ }
+ permissionStream.close();
+ }
+ file_time_orig.Store(toFile);
+ }
+#endif
+
+ if (!cmSystemTools::SetPermissions(toFile, permissions)) {
+ std::ostringstream e;
+ e << this->Name << " cannot set permissions on \"" << toFile
+ << "\": " << cmSystemTools::GetLastSystemError() << ".";
+ this->Status.SetError(e.str());
+ return false;
+ }
+ }
+ return true;
+}
+
+// Translate an argument to a permissions bit.
+bool cmFileCopier::CheckPermissions(std::string const& arg,
+ mode_t& permissions)
+{
+ if (!cmFSPermissions::stringToModeT(arg, permissions)) {
+ std::ostringstream e;
+ e << this->Name << " given invalid permission \"" << arg << "\".";
+ this->Status.SetError(e.str());
+ return false;
+ }
+ return true;
+}
+
+std::string const& cmFileCopier::ToName(std::string const& fromName)
+{
+ return fromName;
+}
+
+bool cmFileCopier::ReportMissing(const std::string& fromFile)
+{
+ // The input file does not exist and installation is not optional.
+ std::ostringstream e;
+ e << this->Name << " cannot find \"" << fromFile
+ << "\": " << cmSystemTools::GetLastSystemError() << ".";
+ this->Status.SetError(e.str());
+ return false;
+}
+
+void cmFileCopier::NotBeforeMatch(std::string const& arg)
+{
+ std::ostringstream e;
+ e << "option " << arg << " may not appear before PATTERN or REGEX.";
+ this->Status.SetError(e.str());
+ this->Doing = DoingError;
+}
+
+void cmFileCopier::NotAfterMatch(std::string const& arg)
+{
+ std::ostringstream e;
+ e << "option " << arg << " may not appear after PATTERN or REGEX.";
+ this->Status.SetError(e.str());
+ this->Doing = DoingError;
+}
+
+void cmFileCopier::DefaultFilePermissions()
+{
+ // Use read/write permissions.
+ this->FilePermissions = 0;
+ this->FilePermissions |= mode_owner_read;
+ this->FilePermissions |= mode_owner_write;
+ this->FilePermissions |= mode_group_read;
+ this->FilePermissions |= mode_world_read;
+}
+
+void cmFileCopier::DefaultDirectoryPermissions()
+{
+ // Use read/write/executable permissions.
+ this->DirPermissions = 0;
+ this->DirPermissions |= mode_owner_read;
+ this->DirPermissions |= mode_owner_write;
+ this->DirPermissions |= mode_owner_execute;
+ this->DirPermissions |= mode_group_read;
+ this->DirPermissions |= mode_group_execute;
+ this->DirPermissions |= mode_world_read;
+ this->DirPermissions |= mode_world_execute;
+}
+
+bool cmFileCopier::GetDefaultDirectoryPermissions(mode_t** mode)
+{
+ // check if default dir creation permissions were set
+ cmProp default_dir_install_permissions = this->Makefile->GetDefinition(
+ "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
+ if (cmNonempty(default_dir_install_permissions)) {
+ std::vector<std::string> items =
+ cmExpandedList(*default_dir_install_permissions);
+ for (const auto& arg : items) {
+ if (!this->CheckPermissions(arg, **mode)) {
+ this->Status.SetError(
+ " Set with CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS variable.");
+ return false;
+ }
+ }
+ } else {
+ *mode = nullptr;
+ }
+
+ return true;
+}
+
+bool cmFileCopier::Parse(std::vector<std::string> const& args)
+{
+ this->Doing = DoingFiles;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ // Check this argument.
+ if (!this->CheckKeyword(args[i]) && !this->CheckValue(args[i])) {
+ std::ostringstream e;
+ e << "called with unknown argument \"" << args[i] << "\".";
+ this->Status.SetError(e.str());
+ return false;
+ }
+
+ // Quit if an argument is invalid.
+ if (this->Doing == DoingError) {
+ return false;
+ }
+ }
+
+ // Require a destination.
+ if (this->Destination.empty()) {
+ std::ostringstream e;
+ e << this->Name << " given no DESTINATION";
+ this->Status.SetError(e.str());
+ return false;
+ }
+
+ // If file permissions were not specified set default permissions.
+ if (!this->UseGivenPermissionsFile && !this->UseSourcePermissions) {
+ this->DefaultFilePermissions();
+ }
+
+ // If directory permissions were not specified set default permissions.
+ if (!this->UseGivenPermissionsDir && !this->UseSourcePermissions) {
+ this->DefaultDirectoryPermissions();
+ }
+
+ return true;
+}
+
+bool cmFileCopier::CheckKeyword(std::string const& arg)
+{
+ if (arg == "DESTINATION") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingDestination;
+ }
+ } else if (arg == "FILES_FROM_DIR") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingFilesFromDir;
+ }
+ } else if (arg == "PATTERN") {
+ this->Doing = DoingPattern;
+ } else if (arg == "REGEX") {
+ this->Doing = DoingRegex;
+ } else if (arg == "FOLLOW_SYMLINK_CHAIN") {
+ this->FollowSymlinkChain = true;
+ this->Doing = DoingNone;
+ } else if (arg == "EXCLUDE") {
+ // Add this property to the current match rule.
+ if (this->CurrentMatchRule) {
+ this->CurrentMatchRule->Properties.Exclude = true;
+ this->Doing = DoingNone;
+ } else {
+ this->NotBeforeMatch(arg);
+ }
+ } else if (arg == "PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->Doing = DoingPermissionsMatch;
+ } else {
+ this->NotBeforeMatch(arg);
+ }
+ } else if (arg == "FILE_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingPermissionsFile;
+ this->UseGivenPermissionsFile = true;
+ }
+ } else if (arg == "DIRECTORY_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingPermissionsDir;
+ this->UseGivenPermissionsDir = true;
+ }
+ } else if (arg == "USE_SOURCE_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->UseSourcePermissions = true;
+ }
+ } else if (arg == "NO_SOURCE_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->UseSourcePermissions = false;
+ }
+ } else if (arg == "FILES_MATCHING") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->MatchlessFiles = false;
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool cmFileCopier::CheckValue(std::string const& arg)
+{
+ switch (this->Doing) {
+ case DoingFiles:
+ this->Files.push_back(arg);
+ break;
+ case DoingDestination:
+ if (arg.empty() || cmSystemTools::FileIsFullPath(arg)) {
+ this->Destination = arg;
+ } else {
+ this->Destination =
+ cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', arg);
+ }
+ this->Doing = DoingNone;
+ break;
+ case DoingFilesFromDir:
+ if (cmSystemTools::FileIsFullPath(arg)) {
+ this->FilesFromDir = arg;
+ } else {
+ this->FilesFromDir =
+ cmStrCat(this->Makefile->GetCurrentSourceDirectory(), '/', arg);
+ }
+ cmSystemTools::ConvertToUnixSlashes(this->FilesFromDir);
+ this->Doing = DoingNone;
+ break;
+ case DoingPattern: {
+ // Convert the pattern to a regular expression. Require a
+ // leading slash and trailing end-of-string in the matched
+ // string to make sure the pattern matches only whole file
+ // names.
+ std::string regex =
+ cmStrCat('/', cmsys::Glob::PatternToRegex(arg, false), '$');
+ this->MatchRules.emplace_back(regex);
+ this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
+ if (this->CurrentMatchRule->Regex.is_valid()) {
+ this->Doing = DoingNone;
+ } else {
+ std::ostringstream e;
+ e << "could not compile PATTERN \"" << arg << "\".";
+ this->Status.SetError(e.str());
+ this->Doing = DoingError;
+ }
+ } break;
+ case DoingRegex:
+ this->MatchRules.emplace_back(arg);
+ this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
+ if (this->CurrentMatchRule->Regex.is_valid()) {
+ this->Doing = DoingNone;
+ } else {
+ std::ostringstream e;
+ e << "could not compile REGEX \"" << arg << "\".";
+ this->Status.SetError(e.str());
+ this->Doing = DoingError;
+ }
+ break;
+ case DoingPermissionsFile:
+ if (!this->CheckPermissions(arg, this->FilePermissions)) {
+ this->Doing = DoingError;
+ }
+ break;
+ case DoingPermissionsDir:
+ if (!this->CheckPermissions(arg, this->DirPermissions)) {
+ this->Doing = DoingError;
+ }
+ break;
+ case DoingPermissionsMatch:
+ if (!this->CheckPermissions(
+ arg, this->CurrentMatchRule->Properties.Permissions)) {
+ this->Doing = DoingError;
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool cmFileCopier::Run(std::vector<std::string> const& args)
+{
+ if (!this->Parse(args)) {
+ return false;
+ }
+
+ for (std::string const& f : this->Files) {
+ std::string file;
+ if (!f.empty() && !cmSystemTools::FileIsFullPath(f)) {
+ if (!this->FilesFromDir.empty()) {
+ file = this->FilesFromDir;
+ } else {
+ file = this->Makefile->GetCurrentSourceDirectory();
+ }
+ file += "/";
+ file += f;
+ } else if (!this->FilesFromDir.empty()) {
+ this->Status.SetError("option FILES_FROM_DIR requires all files "
+ "to be specified as relative paths.");
+ return false;
+ } else {
+ file = f;
+ }
+
+ // Split the input file into its directory and name components.
+ std::vector<std::string> fromPathComponents;
+ cmSystemTools::SplitPath(file, fromPathComponents);
+ std::string fromName = *(fromPathComponents.end() - 1);
+ std::string fromDir = cmSystemTools::JoinPath(
+ fromPathComponents.begin(), fromPathComponents.end() - 1);
+
+ // Compute the full path to the destination file.
+ std::string toFile = this->Destination;
+ if (!this->FilesFromDir.empty()) {
+ std::string dir = cmSystemTools::GetFilenamePath(f);
+ if (!dir.empty()) {
+ toFile += "/";
+ toFile += dir;
+ }
+ }
+ std::string const& toName = this->ToName(fromName);
+ if (!toName.empty()) {
+ toFile += "/";
+ toFile += toName;
+ }
+
+ // Construct the full path to the source file. The file name may
+ // have been changed above.
+ std::string fromFile = fromDir;
+ if (!fromName.empty()) {
+ fromFile += "/";
+ fromFile += fromName;
+ }
+
+ if (!this->Install(fromFile, toFile)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmFileCopier::Install(const std::string& fromFile,
+ const std::string& toFile)
+{
+ if (fromFile.empty()) {
+ this->Status.SetError(
+ "INSTALL encountered an empty string input file name.");
+ return false;
+ }
+
+ // Collect any properties matching this file name.
+ MatchProperties match_properties = this->CollectMatchProperties(fromFile);
+
+ // Skip the file if it is excluded.
+ if (match_properties.Exclude) {
+ return true;
+ }
+
+ if (cmSystemTools::SameFile(fromFile, toFile)) {
+ return true;
+ }
+
+ std::string newFromFile = fromFile;
+ std::string newToFile = toFile;
+
+ if (this->FollowSymlinkChain &&
+ !this->InstallSymlinkChain(newFromFile, newToFile)) {
+ return false;
+ }
+
+ if (cmSystemTools::FileIsSymlink(newFromFile)) {
+ return this->InstallSymlink(newFromFile, newToFile);
+ }
+ if (cmSystemTools::FileIsDirectory(newFromFile)) {
+ return this->InstallDirectory(newFromFile, newToFile, match_properties);
+ }
+ if (cmSystemTools::FileExists(newFromFile)) {
+ return this->InstallFile(newFromFile, newToFile, match_properties);
+ }
+ return this->ReportMissing(newFromFile);
+}
+
+bool cmFileCopier::InstallSymlinkChain(std::string& fromFile,
+ std::string& toFile)
+{
+ std::string newFromFile;
+ std::string toFilePath = cmSystemTools::GetFilenamePath(toFile);
+ while (cmSystemTools::ReadSymlink(fromFile, newFromFile)) {
+ if (!cmSystemTools::FileIsFullPath(newFromFile)) {
+ std::string fromFilePath = cmSystemTools::GetFilenamePath(fromFile);
+ newFromFile = cmStrCat(fromFilePath, "/", newFromFile);
+ }
+
+ std::string symlinkTarget = cmSystemTools::GetFilenameName(newFromFile);
+
+ bool copy = true;
+ if (!this->Always) {
+ std::string oldSymlinkTarget;
+ if (cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget)) {
+ if (symlinkTarget == oldSymlinkTarget) {
+ copy = false;
+ }
+ }
+ }
+
+ this->ReportCopy(toFile, TypeLink, copy);
+
+ if (copy) {
+ cmSystemTools::RemoveFile(toFile);
+ cmSystemTools::MakeDirectory(toFilePath);
+
+ if (!cmSystemTools::CreateSymlink(symlinkTarget, toFile)) {
+ std::ostringstream e;
+ e << this->Name << " cannot create symlink \"" << toFile
+ << "\": " << cmSystemTools::GetLastSystemError() << ".";
+ this->Status.SetError(e.str());
+ return false;
+ }
+ }
+
+ fromFile = newFromFile;
+ toFile = cmStrCat(toFilePath, "/", symlinkTarget);
+ }
+
+ return true;
+}
+
+bool cmFileCopier::InstallSymlink(const std::string& fromFile,
+ const std::string& toFile)
+{
+ // Read the original symlink.
+ std::string symlinkTarget;
+ if (!cmSystemTools::ReadSymlink(fromFile, symlinkTarget)) {
+ std::ostringstream e;
+ e << this->Name << " cannot read symlink \"" << fromFile
+ << "\" to duplicate at \"" << toFile
+ << "\": " << cmSystemTools::GetLastSystemError() << ".";
+ this->Status.SetError(e.str());
+ return false;
+ }
+
+ // Compare the symlink value to that at the destination if not
+ // always installing.
+ bool copy = true;
+ if (!this->Always) {
+ std::string oldSymlinkTarget;
+ if (cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget)) {
+ if (symlinkTarget == oldSymlinkTarget) {
+ copy = false;
+ }
+ }
+ }
+
+ // Inform the user about this file installation.
+ this->ReportCopy(toFile, TypeLink, copy);
+
+ if (copy) {
+ // Remove the destination file so we can always create the symlink.
+ cmSystemTools::RemoveFile(toFile);
+
+ // Create destination directory if it doesn't exist
+ cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(toFile));
+
+ // Create the symlink.
+ if (!cmSystemTools::CreateSymlink(symlinkTarget, toFile)) {
+ std::ostringstream e;
+ e << this->Name << " cannot duplicate symlink \"" << fromFile
+ << "\" at \"" << toFile
+ << "\": " << cmSystemTools::GetLastSystemError() << ".";
+ this->Status.SetError(e.str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool cmFileCopier::InstallFile(const std::string& fromFile,
+ const std::string& toFile,
+ MatchProperties match_properties)
+{
+ // Determine whether we will copy the file.
+ bool copy = true;
+ if (!this->Always) {
+ // If both files exist with the same time do not copy.
+ if (!this->FileTimes.DifferS(fromFile, toFile)) {
+ copy = false;
+ }
+ }
+
+ // Inform the user about this file installation.
+ this->ReportCopy(toFile, TypeFile, copy);
+
+ // Copy the file.
+ if (copy && !cmSystemTools::CopyAFile(fromFile, toFile, true)) {
+ std::ostringstream e;
+ e << this->Name << " cannot copy file \"" << fromFile << "\" to \""
+ << toFile << "\": " << cmSystemTools::GetLastSystemError() << ".";
+ this->Status.SetError(e.str());
+ return false;
+ }
+
+ // Set the file modification time of the destination file.
+ if (copy && !this->Always) {
+ // Add write permission so we can set the file time.
+ // Permissions are set unconditionally below anyway.
+ mode_t perm = 0;
+ if (cmSystemTools::GetPermissions(toFile, perm)) {
+ cmSystemTools::SetPermissions(toFile, perm | mode_owner_write);
+ }
+ if (!cmFileTimes::Copy(fromFile, toFile)) {
+ std::ostringstream e;
+ e << this->Name << " cannot set modification time on \"" << toFile
+ << "\": " << cmSystemTools::GetLastSystemError() << ".";
+ this->Status.SetError(e.str());
+ return false;
+ }
+ }
+
+ // Set permissions of the destination file.
+ mode_t permissions =
+ (match_properties.Permissions ? match_properties.Permissions
+ : this->FilePermissions);
+ if (!permissions) {
+ // No permissions were explicitly provided but the user requested
+ // that the source file permissions be used.
+ cmSystemTools::GetPermissions(fromFile, permissions);
+ }
+ return this->SetPermissions(toFile, permissions);
+}
+
+bool cmFileCopier::InstallDirectory(const std::string& source,
+ const std::string& destination,
+ MatchProperties match_properties)
+{
+ // Inform the user about this directory installation.
+ this->ReportCopy(destination, TypeDir,
+ !cmSystemTools::FileIsDirectory(destination));
+
+ // check if default dir creation permissions were set
+ mode_t default_dir_mode_v = 0;
+ mode_t* default_dir_mode = &default_dir_mode_v;
+ if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
+ return false;
+ }
+
+ // Make sure the destination directory exists.
+ if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
+ std::ostringstream e;
+ e << this->Name << " cannot make directory \"" << destination
+ << "\": " << cmSystemTools::GetLastSystemError() << ".";
+ this->Status.SetError(e.str());
+ return false;
+ }
+
+ // Compute the requested permissions for the destination directory.
+ mode_t permissions =
+ (match_properties.Permissions ? match_properties.Permissions
+ : this->DirPermissions);
+ if (!permissions) {
+ // No permissions were explicitly provided but the user requested
+ // that the source directory permissions be used.
+ cmSystemTools::GetPermissions(source, permissions);
+ }
+
+ // Compute the set of permissions required on this directory to
+ // recursively install files and subdirectories safely.
+ mode_t required_permissions =
+ mode_owner_read | mode_owner_write | mode_owner_execute;
+
+ // If the required permissions are specified it is safe to set the
+ // final permissions now. Otherwise we must add the required
+ // permissions temporarily during file installation.
+ mode_t permissions_before = 0;
+ mode_t permissions_after = 0;
+ if ((permissions & required_permissions) == required_permissions) {
+ permissions_before = permissions;
+ } else {
+ permissions_before = permissions | required_permissions;
+ permissions_after = permissions;
+ }
+
+ // Set the required permissions of the destination directory.
+ if (!this->SetPermissions(destination, permissions_before)) {
+ return false;
+ }
+
+ // Load the directory contents to traverse it recursively.
+ cmsys::Directory dir;
+ if (!source.empty()) {
+ dir.Load(source);
+ }
+ unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
+ for (unsigned long fileNum = 0; fileNum < numFiles; ++fileNum) {
+ if (!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
+ strcmp(dir.GetFile(fileNum), "..") == 0)) {
+ std::string fromPath = cmStrCat(source, '/', dir.GetFile(fileNum));
+ std::string toPath = cmStrCat(destination, '/', dir.GetFile(fileNum));
+ if (!this->Install(fromPath, toPath)) {
+ return false;
+ }
+ }
+ }
+
+ // Set the requested permissions of the destination directory.
+ return this->SetPermissions(destination, permissions_after);
+}
diff --git a/Source/cmFileCopier.h b/Source/cmFileCopier.h
new file mode 100644
index 0000000..217d58d
--- /dev/null
+++ b/Source/cmFileCopier.h
@@ -0,0 +1,121 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cm_sys_stat.h"
+
+#include "cmFileTimeCache.h"
+
+class cmExecutionStatus;
+class cmMakefile;
+
+// File installation helper class.
+struct cmFileCopier
+{
+ cmFileCopier(cmExecutionStatus& status, const char* name = "COPY");
+ virtual ~cmFileCopier();
+
+ bool Run(std::vector<std::string> const& args);
+
+protected:
+ cmExecutionStatus& Status;
+ cmMakefile* Makefile;
+ const char* Name;
+ bool Always;
+ cmFileTimeCache FileTimes;
+
+ // Whether to install a file not matching any expression.
+ bool MatchlessFiles;
+
+ // Permissions for files and directories installed by this object.
+ mode_t FilePermissions;
+ mode_t DirPermissions;
+
+ // Properties set by pattern and regex match rules.
+ struct MatchProperties
+ {
+ bool Exclude = false;
+ mode_t Permissions = 0;
+ };
+ struct MatchRule
+ {
+ cmsys::RegularExpression Regex;
+ MatchProperties Properties;
+ std::string RegexString;
+ MatchRule(std::string const& regex)
+ : Regex(regex)
+ , RegexString(regex)
+ {
+ }
+ };
+ std::vector<MatchRule> MatchRules;
+
+ // Get the properties from rules matching this input file.
+ MatchProperties CollectMatchProperties(const std::string& file);
+
+ bool SetPermissions(const std::string& toFile, mode_t permissions);
+
+ // Translate an argument to a permissions bit.
+ bool CheckPermissions(std::string const& arg, mode_t& permissions);
+
+ bool InstallSymlinkChain(std::string& fromFile, std::string& toFile);
+ bool InstallSymlink(const std::string& fromFile, const std::string& toFile);
+ bool InstallFile(const std::string& fromFile, const std::string& toFile,
+ MatchProperties match_properties);
+ bool InstallDirectory(const std::string& source,
+ const std::string& destination,
+ MatchProperties match_properties);
+ virtual bool Install(const std::string& fromFile, const std::string& toFile);
+ virtual std::string const& ToName(std::string const& fromName);
+
+ enum Type
+ {
+ TypeFile,
+ TypeDir,
+ TypeLink
+ };
+ virtual void ReportCopy(const std::string&, Type, bool) {}
+ virtual bool ReportMissing(const std::string& fromFile);
+
+ MatchRule* CurrentMatchRule;
+ bool UseGivenPermissionsFile;
+ bool UseGivenPermissionsDir;
+ bool UseSourcePermissions;
+ bool FollowSymlinkChain;
+ std::string Destination;
+ std::string FilesFromDir;
+ std::vector<std::string> Files;
+ int Doing;
+
+ virtual bool Parse(std::vector<std::string> const& args);
+ enum
+ {
+ DoingNone,
+ DoingError,
+ DoingDestination,
+ DoingFilesFromDir,
+ DoingFiles,
+ DoingPattern,
+ DoingRegex,
+ DoingPermissionsFile,
+ DoingPermissionsDir,
+ DoingPermissionsMatch,
+ DoingLast1
+ };
+ virtual bool CheckKeyword(std::string const& arg);
+ virtual bool CheckValue(std::string const& arg);
+
+ void NotBeforeMatch(std::string const& arg);
+ void NotAfterMatch(std::string const& arg);
+ virtual void DefaultFilePermissions();
+ virtual void DefaultDirectoryPermissions();
+
+ bool GetDefaultDirectoryPermissions(mode_t** mode);
+};
diff --git a/Source/cmFileInstaller.cxx b/Source/cmFileInstaller.cxx
new file mode 100644
index 0000000..c89be96
--- /dev/null
+++ b/Source/cmFileInstaller.cxx
@@ -0,0 +1,351 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmFileInstaller.h"
+
+#include <sstream>
+
+#include "cm_sys_stat.h"
+
+#include "cmExecutionStatus.h"
+#include "cmFSPermissions.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+using namespace cmFSPermissions;
+
+cmFileInstaller::cmFileInstaller(cmExecutionStatus& status)
+ : cmFileCopier(status, "INSTALL")
+ , InstallType(cmInstallType_FILES)
+ , Optional(false)
+ , MessageAlways(false)
+ , MessageLazy(false)
+ , MessageNever(false)
+ , DestDirLength(0)
+{
+ // Installation does not use source permissions by default.
+ this->UseSourcePermissions = false;
+ // Check whether to copy files always or only if they have changed.
+ std::string install_always;
+ if (cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS", install_always)) {
+ this->Always = cmIsOn(install_always);
+ }
+ // Get the current manifest.
+ this->Manifest =
+ this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
+}
+cmFileInstaller::~cmFileInstaller()
+{
+ // Save the updated install manifest.
+ this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
+ this->Manifest);
+}
+
+void cmFileInstaller::ManifestAppend(std::string const& file)
+{
+ if (!this->Manifest.empty()) {
+ this->Manifest += ";";
+ }
+ this->Manifest += file.substr(this->DestDirLength);
+}
+
+std::string const& cmFileInstaller::ToName(std::string const& fromName)
+{
+ return this->Rename.empty() ? fromName : this->Rename;
+}
+
+void cmFileInstaller::ReportCopy(const std::string& toFile, Type type,
+ bool copy)
+{
+ if (!this->MessageNever && (copy || !this->MessageLazy)) {
+ std::string message =
+ cmStrCat((copy ? "Installing: " : "Up-to-date: "), toFile);
+ this->Makefile->DisplayStatus(message, -1);
+ }
+ if (type != TypeDir) {
+ // Add the file to the manifest.
+ this->ManifestAppend(toFile);
+ }
+}
+bool cmFileInstaller::ReportMissing(const std::string& fromFile)
+{
+ return (this->Optional || this->cmFileCopier::ReportMissing(fromFile));
+}
+bool cmFileInstaller::Install(const std::string& fromFile,
+ const std::string& toFile)
+{
+ // Support installing from empty source to make a directory.
+ if (this->InstallType == cmInstallType_DIRECTORY && fromFile.empty()) {
+ return this->InstallDirectory(fromFile, toFile, MatchProperties());
+ }
+ return this->cmFileCopier::Install(fromFile, toFile);
+}
+
+void cmFileInstaller::DefaultFilePermissions()
+{
+ this->cmFileCopier::DefaultFilePermissions();
+ // Add execute permissions based on the target type.
+ switch (this->InstallType) {
+ case cmInstallType_SHARED_LIBRARY:
+ case cmInstallType_MODULE_LIBRARY:
+ if (this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE")) {
+ break;
+ }
+ CM_FALLTHROUGH;
+ case cmInstallType_EXECUTABLE:
+ case cmInstallType_PROGRAMS:
+ this->FilePermissions |= mode_owner_execute;
+ this->FilePermissions |= mode_group_execute;
+ this->FilePermissions |= mode_world_execute;
+ break;
+ default:
+ break;
+ }
+}
+
+bool cmFileInstaller::Parse(std::vector<std::string> const& args)
+{
+ if (!this->cmFileCopier::Parse(args)) {
+ return false;
+ }
+
+ if (!this->Rename.empty()) {
+ if (!this->FilesFromDir.empty()) {
+ this->Status.SetError("INSTALL option RENAME may not be "
+ "combined with FILES_FROM_DIR.");
+ return false;
+ }
+ if (this->InstallType != cmInstallType_FILES &&
+ this->InstallType != cmInstallType_PROGRAMS) {
+ this->Status.SetError("INSTALL option RENAME may be used "
+ "only with FILES or PROGRAMS.");
+ return false;
+ }
+ if (this->Files.size() > 1) {
+ this->Status.SetError("INSTALL option RENAME may be used "
+ "only with one file.");
+ return false;
+ }
+ }
+
+ if (!this->HandleInstallDestination()) {
+ return false;
+ }
+
+ if (((this->MessageAlways ? 1 : 0) + (this->MessageLazy ? 1 : 0) +
+ (this->MessageNever ? 1 : 0)) > 1) {
+ this->Status.SetError("INSTALL options MESSAGE_ALWAYS, "
+ "MESSAGE_LAZY, and MESSAGE_NEVER "
+ "are mutually exclusive.");
+ return false;
+ }
+
+ return true;
+}
+
+bool cmFileInstaller::CheckKeyword(std::string const& arg)
+{
+ if (arg == "TYPE") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingType;
+ }
+ } else if (arg == "FILES") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingFiles;
+ }
+ } else if (arg == "RENAME") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingRename;
+ }
+ } else if (arg == "OPTIONAL") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->Optional = true;
+ }
+ } else if (arg == "MESSAGE_ALWAYS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->MessageAlways = true;
+ }
+ } else if (arg == "MESSAGE_LAZY") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->MessageLazy = true;
+ }
+ } else if (arg == "MESSAGE_NEVER") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->MessageNever = true;
+ }
+ } else if (arg == "PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->Doing = DoingPermissionsMatch;
+ } else {
+ // file(INSTALL) aliases PERMISSIONS to FILE_PERMISSIONS
+ this->Doing = DoingPermissionsFile;
+ this->UseGivenPermissionsFile = true;
+ }
+ } else if (arg == "DIR_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ // file(INSTALL) aliases DIR_PERMISSIONS to DIRECTORY_PERMISSIONS
+ this->Doing = DoingPermissionsDir;
+ this->UseGivenPermissionsDir = true;
+ }
+ } else if (arg == "COMPONENTS" || arg == "CONFIGURATIONS" ||
+ arg == "PROPERTIES") {
+ std::ostringstream e;
+ e << "INSTALL called with old-style " << arg << " argument. "
+ << "This script was generated with an older version of CMake. "
+ << "Re-run this cmake version on your build tree.";
+ this->Status.SetError(e.str());
+ this->Doing = DoingError;
+ } else {
+ return this->cmFileCopier::CheckKeyword(arg);
+ }
+ return true;
+}
+
+bool cmFileInstaller::CheckValue(std::string const& arg)
+{
+ switch (this->Doing) {
+ case DoingType:
+ if (!this->GetTargetTypeFromString(arg)) {
+ this->Doing = DoingError;
+ }
+ break;
+ case DoingRename:
+ this->Rename = arg;
+ break;
+ default:
+ return this->cmFileCopier::CheckValue(arg);
+ }
+ return true;
+}
+
+bool cmFileInstaller::GetTargetTypeFromString(const std::string& stype)
+{
+ if (stype == "EXECUTABLE") {
+ this->InstallType = cmInstallType_EXECUTABLE;
+ } else if (stype == "FILE") {
+ this->InstallType = cmInstallType_FILES;
+ } else if (stype == "PROGRAM") {
+ this->InstallType = cmInstallType_PROGRAMS;
+ } else if (stype == "STATIC_LIBRARY") {
+ this->InstallType = cmInstallType_STATIC_LIBRARY;
+ } else if (stype == "SHARED_LIBRARY") {
+ this->InstallType = cmInstallType_SHARED_LIBRARY;
+ } else if (stype == "MODULE") {
+ this->InstallType = cmInstallType_MODULE_LIBRARY;
+ } else if (stype == "DIRECTORY") {
+ this->InstallType = cmInstallType_DIRECTORY;
+ } else {
+ std::ostringstream e;
+ e << "Option TYPE given unknown value \"" << stype << "\".";
+ this->Status.SetError(e.str());
+ return false;
+ }
+ return true;
+}
+
+bool cmFileInstaller::HandleInstallDestination()
+{
+ std::string& destination = this->Destination;
+
+ // allow for / to be a valid destination
+ if (destination.size() < 2 && destination != "/") {
+ this->Status.SetError("called with inappropriate arguments. "
+ "No DESTINATION provided or .");
+ return false;
+ }
+
+ std::string sdestdir;
+ if (cmSystemTools::GetEnv("DESTDIR", sdestdir) && !sdestdir.empty()) {
+ cmSystemTools::ConvertToUnixSlashes(sdestdir);
+ char ch1 = destination[0];
+ char ch2 = destination[1];
+ char ch3 = 0;
+ if (destination.size() > 2) {
+ ch3 = destination[2];
+ }
+ int skip = 0;
+ if (ch1 != '/') {
+ int relative = 0;
+ if (((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z')) &&
+ ch2 == ':') {
+ // Assume windows
+ // let's do some destdir magic:
+ skip = 2;
+ if (ch3 != '/') {
+ relative = 1;
+ }
+ } else {
+ relative = 1;
+ }
+ if (relative) {
+ // This is relative path on unix or windows. Since we are doing
+ // destdir, this case does not make sense.
+ this->Status.SetError(
+ "called with relative DESTINATION. This "
+ "does not make sense when using DESTDIR. Specify "
+ "absolute path or remove DESTDIR environment variable.");
+ return false;
+ }
+ } else {
+ if (ch2 == '/') {
+ // looks like a network path.
+ std::string message =
+ cmStrCat("called with network path DESTINATION. This "
+ "does not make sense when using DESTDIR. Specify local "
+ "absolute path or remove DESTDIR environment variable."
+ "\nDESTINATION=\n",
+ destination);
+ this->Status.SetError(message);
+ return false;
+ }
+ }
+ destination = sdestdir + destination.substr(skip);
+ this->DestDirLength = int(sdestdir.size());
+ }
+
+ // check if default dir creation permissions were set
+ mode_t default_dir_mode_v = 0;
+ mode_t* default_dir_mode = &default_dir_mode_v;
+ if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
+ return false;
+ }
+
+ if (this->InstallType != cmInstallType_DIRECTORY) {
+ if (!cmSystemTools::FileExists(destination)) {
+ if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
+ std::string errstring = "cannot create directory: " + destination +
+ ". Maybe need administrative privileges.";
+ this->Status.SetError(errstring);
+ return false;
+ }
+ }
+ if (!cmSystemTools::FileIsDirectory(destination)) {
+ std::string errstring =
+ "INSTALL destination: " + destination + " is not a directory.";
+ this->Status.SetError(errstring);
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/Source/cmFileInstaller.h b/Source/cmFileInstaller.h
new file mode 100644
index 0000000..3a905d3
--- /dev/null
+++ b/Source/cmFileInstaller.h
@@ -0,0 +1,51 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmFileCopier.h"
+#include "cmInstallType.h"
+
+class cmExecutionStatus;
+
+struct cmFileInstaller : public cmFileCopier
+{
+ cmFileInstaller(cmExecutionStatus& status);
+ ~cmFileInstaller() override;
+
+protected:
+ cmInstallType InstallType;
+ bool Optional;
+ bool MessageAlways;
+ bool MessageLazy;
+ bool MessageNever;
+ int DestDirLength;
+ std::string Rename;
+
+ std::string Manifest;
+ void ManifestAppend(std::string const& file);
+
+ std::string const& ToName(std::string const& fromName) override;
+
+ void ReportCopy(const std::string& toFile, Type type, bool copy) override;
+ bool ReportMissing(const std::string& fromFile) override;
+ bool Install(const std::string& fromFile,
+ const std::string& toFile) override;
+
+ bool Parse(std::vector<std::string> const& args) override;
+ enum
+ {
+ DoingType = DoingLast1,
+ DoingRename,
+ DoingLast2
+ };
+ bool CheckKeyword(std::string const& arg) override;
+ bool CheckValue(std::string const& arg) override;
+ void DefaultFilePermissions() override;
+ bool GetTargetTypeFromString(const std::string& stype);
+ bool HandleInstallDestination();
+};
diff --git a/Source/cmFileLock.cxx b/Source/cmFileLock.cxx
new file mode 100644
index 0000000..5d197d2
--- /dev/null
+++ b/Source/cmFileLock.cxx
@@ -0,0 +1,88 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileLock.h"
+
+#include <cassert>
+#include <utility>
+
+#include "cmFileLockResult.h"
+
+// Common implementation
+
+cmFileLock::cmFileLock(cmFileLock&& other) noexcept
+{
+ this->File = other.File;
+#if defined(_WIN32)
+ other.File = INVALID_HANDLE_VALUE;
+#else
+ other.File = -1;
+#endif
+ this->Filename = std::move(other.Filename);
+}
+
+cmFileLock::~cmFileLock()
+{
+ if (!this->Filename.empty()) {
+ const cmFileLockResult result = this->Release();
+ static_cast<void>(result);
+ assert(result.IsOk());
+ }
+}
+
+cmFileLock& cmFileLock::operator=(cmFileLock&& other) noexcept
+{
+ this->File = other.File;
+#if defined(_WIN32)
+ other.File = INVALID_HANDLE_VALUE;
+#else
+ other.File = -1;
+#endif
+ this->Filename = std::move(other.Filename);
+
+ return *this;
+}
+
+cmFileLockResult cmFileLock::Lock(const std::string& filename,
+ unsigned long timeout)
+{
+ if (filename.empty()) {
+ // Error is internal since all the directories and file must be created
+ // before actual lock called.
+ return cmFileLockResult::MakeInternal();
+ }
+
+ if (!this->Filename.empty()) {
+ // Error is internal since double-lock must be checked in class
+ // cmFileLockPool by the cmFileLock::IsLocked method.
+ return cmFileLockResult::MakeInternal();
+ }
+
+ this->Filename = filename;
+ cmFileLockResult result = this->OpenFile();
+ if (result.IsOk()) {
+ if (timeout == static_cast<unsigned long>(-1)) {
+ result = this->LockWithoutTimeout();
+ } else {
+ result = this->LockWithTimeout(timeout);
+ }
+ }
+
+ if (!result.IsOk()) {
+ this->Filename.clear();
+ }
+
+ return result;
+}
+
+bool cmFileLock::IsLocked(const std::string& filename) const
+{
+ return filename == this->Filename;
+}
+
+#if defined(_WIN32)
+// NOLINTNEXTLINE(bugprone-suspicious-include)
+# include "cmFileLockWin32.cxx"
+#else
+// NOLINTNEXTLINE(bugprone-suspicious-include)
+# include "cmFileLockUnix.cxx"
+#endif
diff --git a/Source/cmFileLock.h b/Source/cmFileLock.h
new file mode 100644
index 0000000..94baea1
--- /dev/null
+++ b/Source/cmFileLock.h
@@ -0,0 +1,64 @@
+/* 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 <string>
+
+#if defined(_WIN32)
+# include <windows.h> // HANDLE
+#endif
+
+class cmFileLockResult;
+
+/**
+ * @brief Cross-platform file locking.
+ * @details Under the hood this class use 'fcntl' for Unix-like platforms and
+ * 'LockFileEx'/'UnlockFileEx' for Win32 platform. Locks are exclusive and
+ * advisory.
+ */
+class cmFileLock
+{
+public:
+ cmFileLock();
+ ~cmFileLock();
+
+ cmFileLock(cmFileLock const&) = delete;
+ cmFileLock(cmFileLock&&) noexcept;
+ cmFileLock& operator=(cmFileLock const&) = delete;
+ cmFileLock& operator=(cmFileLock&&) noexcept;
+
+ /**
+ * @brief Lock the file.
+ * @param timeoutSec Lock timeout. If -1 try until success or fatal error.
+ */
+ cmFileLockResult Lock(const std::string& filename, unsigned long timeoutSec);
+
+ /**
+ * @brief Unlock the file.
+ */
+ cmFileLockResult Release();
+
+ /**
+ * @brief Check file is locked by this class.
+ * @details This function helps to find double locks (deadlocks) and to do
+ * explicit unlocks.
+ */
+ bool IsLocked(const std::string& filename) const;
+
+private:
+ cmFileLockResult OpenFile();
+ cmFileLockResult LockWithoutTimeout();
+ cmFileLockResult LockWithTimeout(unsigned long timeoutSec);
+
+#if defined(_WIN32)
+ HANDLE File = INVALID_HANDLE_VALUE;
+ BOOL LockFile(DWORD flags);
+#else
+ int File = -1;
+ int LockFile(int cmd, int type) const;
+#endif
+
+ std::string Filename;
+};
diff --git a/Source/cmFileLockPool.cxx b/Source/cmFileLockPool.cxx
new file mode 100644
index 0000000..99f6885
--- /dev/null
+++ b/Source/cmFileLockPool.cxx
@@ -0,0 +1,153 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileLockPool.h"
+
+#include <algorithm>
+#include <cassert>
+#include <utility>
+
+#include "cmFileLock.h"
+#include "cmFileLockResult.h"
+
+cmFileLockPool::cmFileLockPool() = default;
+
+cmFileLockPool::~cmFileLockPool() = default;
+
+void cmFileLockPool::PushFunctionScope()
+{
+ this->FunctionScopes.push_back(ScopePool());
+}
+
+void cmFileLockPool::PopFunctionScope()
+{
+ assert(!this->FunctionScopes.empty());
+ this->FunctionScopes.pop_back();
+}
+
+void cmFileLockPool::PushFileScope()
+{
+ this->FileScopes.push_back(ScopePool());
+}
+
+void cmFileLockPool::PopFileScope()
+{
+ assert(!this->FileScopes.empty());
+ this->FileScopes.pop_back();
+}
+
+cmFileLockResult cmFileLockPool::LockFunctionScope(const std::string& filename,
+ unsigned long timeoutSec)
+{
+ if (this->IsAlreadyLocked(filename)) {
+ return cmFileLockResult::MakeAlreadyLocked();
+ }
+ if (this->FunctionScopes.empty()) {
+ return cmFileLockResult::MakeNoFunction();
+ }
+ return this->FunctionScopes.back().Lock(filename, timeoutSec);
+}
+
+cmFileLockResult cmFileLockPool::LockFileScope(const std::string& filename,
+ unsigned long timeoutSec)
+{
+ if (this->IsAlreadyLocked(filename)) {
+ return cmFileLockResult::MakeAlreadyLocked();
+ }
+ assert(!this->FileScopes.empty());
+ return this->FileScopes.back().Lock(filename, timeoutSec);
+}
+
+cmFileLockResult cmFileLockPool::LockProcessScope(const std::string& filename,
+ unsigned long timeoutSec)
+{
+ if (this->IsAlreadyLocked(filename)) {
+ return cmFileLockResult::MakeAlreadyLocked();
+ }
+ return this->ProcessScope.Lock(filename, timeoutSec);
+}
+
+cmFileLockResult cmFileLockPool::Release(const std::string& filename)
+{
+ for (auto& funcScope : this->FunctionScopes) {
+ const cmFileLockResult result = funcScope.Release(filename);
+ if (!result.IsOk()) {
+ return result;
+ }
+ }
+
+ for (auto& fileScope : this->FileScopes) {
+ const cmFileLockResult result = fileScope.Release(filename);
+ if (!result.IsOk()) {
+ return result;
+ }
+ }
+
+ return this->ProcessScope.Release(filename);
+}
+
+bool cmFileLockPool::IsAlreadyLocked(const std::string& filename) const
+{
+ for (auto const& funcScope : this->FunctionScopes) {
+ const bool result = funcScope.IsAlreadyLocked(filename);
+ if (result) {
+ return true;
+ }
+ }
+
+ for (auto const& fileScope : this->FileScopes) {
+ const bool result = fileScope.IsAlreadyLocked(filename);
+ if (result) {
+ return true;
+ }
+ }
+
+ return this->ProcessScope.IsAlreadyLocked(filename);
+}
+
+cmFileLockPool::ScopePool::ScopePool() = default;
+
+cmFileLockPool::ScopePool::~ScopePool() = default;
+
+cmFileLockPool::ScopePool::ScopePool(ScopePool&&) noexcept = default;
+
+cmFileLockPool::ScopePool& cmFileLockPool::ScopePool::operator=(
+ ScopePool&& other) noexcept
+{
+ if (this != &other) {
+ this->Locks = std::move(other.Locks);
+ }
+
+ return *this;
+}
+
+cmFileLockResult cmFileLockPool::ScopePool::Lock(const std::string& filename,
+ unsigned long timeoutSec)
+{
+ cmFileLock lock;
+ const cmFileLockResult result = lock.Lock(filename, timeoutSec);
+ if (result.IsOk()) {
+ this->Locks.push_back(std::move(lock));
+ return cmFileLockResult::MakeOk();
+ }
+ return result;
+}
+
+cmFileLockResult cmFileLockPool::ScopePool::Release(
+ const std::string& filename)
+{
+ for (auto& lock : this->Locks) {
+ if (lock.IsLocked(filename)) {
+ return lock.Release();
+ }
+ }
+ return cmFileLockResult::MakeOk();
+}
+
+bool cmFileLockPool::ScopePool::IsAlreadyLocked(
+ const std::string& filename) const
+{
+ return std::any_of(this->Locks.begin(), this->Locks.end(),
+ [&filename](cmFileLock const& lock) -> bool {
+ return lock.IsLocked(filename);
+ });
+}
diff --git a/Source/cmFileLockPool.h b/Source/cmFileLockPool.h
new file mode 100644
index 0000000..f2f9f23
--- /dev/null
+++ b/Source/cmFileLockPool.h
@@ -0,0 +1,87 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmFileLock.h"
+
+class cmFileLockResult;
+
+class cmFileLockPool
+{
+public:
+ cmFileLockPool();
+ ~cmFileLockPool();
+
+ cmFileLockPool(cmFileLockPool const&) = delete;
+ cmFileLockPool& operator=(cmFileLockPool const&) = delete;
+
+ //@{
+ /**
+ * @brief Function scope control.
+ */
+ void PushFunctionScope();
+ void PopFunctionScope();
+ //@}
+
+ //@{
+ /**
+ * @brief File scope control.
+ */
+ void PushFileScope();
+ void PopFileScope();
+ //@}
+
+ //@{
+ /**
+ * @brief Lock the file in given scope.
+ * @param timeoutSec Lock timeout. If -1 try until success or fatal error.
+ */
+ cmFileLockResult LockFunctionScope(const std::string& filename,
+ unsigned long timeoutSec);
+ cmFileLockResult LockFileScope(const std::string& filename,
+ unsigned long timeoutSec);
+ cmFileLockResult LockProcessScope(const std::string& filename,
+ unsigned long timeoutSec);
+ //@}
+
+ /**
+ * @brief Unlock the file explicitly.
+ */
+ cmFileLockResult Release(const std::string& filename);
+
+private:
+ bool IsAlreadyLocked(const std::string& filename) const;
+
+ class ScopePool
+ {
+ public:
+ ScopePool();
+ ~ScopePool();
+
+ ScopePool(ScopePool const&) = delete;
+ ScopePool(ScopePool&&) noexcept;
+ ScopePool& operator=(ScopePool const&) = delete;
+ ScopePool& operator=(ScopePool&&) noexcept;
+
+ cmFileLockResult Lock(const std::string& filename,
+ unsigned long timeoutSec);
+ cmFileLockResult Release(const std::string& filename);
+ bool IsAlreadyLocked(const std::string& filename) const;
+
+ private:
+ using List = std::vector<cmFileLock>;
+
+ List Locks;
+ };
+
+ using List = std::vector<ScopePool>;
+
+ List FunctionScopes;
+ List FileScopes;
+ ScopePool ProcessScope;
+};
diff --git a/Source/cmFileLockResult.cxx b/Source/cmFileLockResult.cxx
new file mode 100644
index 0000000..9d5a6c6
--- /dev/null
+++ b/Source/cmFileLockResult.cxx
@@ -0,0 +1,87 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileLockResult.h"
+
+#include <cerrno>
+#include <cstring>
+
+#define WINMSG_BUF_LEN (1024)
+cmFileLockResult cmFileLockResult::MakeOk()
+{
+ return { OK, 0 };
+}
+
+cmFileLockResult cmFileLockResult::MakeSystem()
+{
+#if defined(_WIN32)
+ const Error lastError = GetLastError();
+#else
+ const Error lastError = errno;
+#endif
+ return { SYSTEM, lastError };
+}
+
+cmFileLockResult cmFileLockResult::MakeTimeout()
+{
+ return { TIMEOUT, 0 };
+}
+
+cmFileLockResult cmFileLockResult::MakeAlreadyLocked()
+{
+ return { ALREADY_LOCKED, 0 };
+}
+
+cmFileLockResult cmFileLockResult::MakeInternal()
+{
+ return { INTERNAL, 0 };
+}
+
+cmFileLockResult cmFileLockResult::MakeNoFunction()
+{
+ return { NO_FUNCTION, 0 };
+}
+
+bool cmFileLockResult::IsOk() const
+{
+ return this->Type == OK;
+}
+
+std::string cmFileLockResult::GetOutputMessage() const
+{
+ switch (this->Type) {
+ case OK:
+ return "0";
+ case SYSTEM:
+#if defined(_WIN32)
+ {
+ char winmsg[WINMSG_BUF_LEN];
+ DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
+ if (FormatMessageA(flags, NULL, this->ErrorValue,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)winmsg, WINMSG_BUF_LEN, NULL)) {
+ const std::string message = winmsg;
+ return message;
+ } else {
+ return "Internal error (FormatMessageA failed)";
+ }
+ }
+#else
+ return strerror(this->ErrorValue);
+#endif
+ case TIMEOUT:
+ return "Timeout reached";
+ case ALREADY_LOCKED:
+ return "File already locked";
+ case NO_FUNCTION:
+ return "'GUARD FUNCTION' not used in function definition";
+ case INTERNAL:
+ default:
+ return "Internal error";
+ }
+}
+
+cmFileLockResult::cmFileLockResult(ErrorType typeValue, Error errorValue)
+ : Type(typeValue)
+ , ErrorValue(errorValue)
+{
+}
diff --git a/Source/cmFileLockResult.h b/Source/cmFileLockResult.h
new file mode 100644
index 0000000..8a58d1f
--- /dev/null
+++ b/Source/cmFileLockResult.h
@@ -0,0 +1,74 @@
+/* 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 <string>
+
+#if defined(_WIN32)
+# include <windows.h> // DWORD
+#endif
+
+/**
+ * @brief Result of the locking/unlocking file.
+ * @note See @c cmFileLock
+ */
+class cmFileLockResult
+{
+public:
+#if defined(_WIN32)
+ using Error = DWORD;
+#else
+ using Error = int;
+#endif
+
+ /**
+ * @brief Successful lock/unlock.
+ */
+ static cmFileLockResult MakeOk();
+
+ /**
+ * @brief Lock/Unlock failed. Read error/GetLastError.
+ */
+ static cmFileLockResult MakeSystem();
+
+ /**
+ * @brief Lock/Unlock failed. Timeout reached.
+ */
+ static cmFileLockResult MakeTimeout();
+
+ /**
+ * @brief File already locked.
+ */
+ static cmFileLockResult MakeAlreadyLocked();
+
+ /**
+ * @brief Internal error.
+ */
+ static cmFileLockResult MakeInternal();
+
+ /**
+ * @brief Try to lock with function guard outside of the function
+ */
+ static cmFileLockResult MakeNoFunction();
+
+ bool IsOk() const;
+ std::string GetOutputMessage() const;
+
+private:
+ enum ErrorType
+ {
+ OK,
+ SYSTEM,
+ TIMEOUT,
+ ALREADY_LOCKED,
+ INTERNAL,
+ NO_FUNCTION
+ };
+
+ cmFileLockResult(ErrorType type, Error errorValue);
+
+ ErrorType Type;
+ Error ErrorValue;
+};
diff --git a/Source/cmFileLockUnix.cxx b/Source/cmFileLockUnix.cxx
new file mode 100644
index 0000000..613c6ee
--- /dev/null
+++ b/Source/cmFileLockUnix.cxx
@@ -0,0 +1,76 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include <cerrno> // errno
+#include <cstdio> // SEEK_SET
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "cmFileLock.h"
+#include "cmSystemTools.h"
+
+cmFileLock::cmFileLock() = default;
+
+cmFileLockResult cmFileLock::Release()
+{
+ if (this->Filename.empty()) {
+ return cmFileLockResult::MakeOk();
+ }
+ const int lockResult = this->LockFile(F_SETLK, F_UNLCK);
+
+ this->Filename = "";
+
+ ::close(this->File);
+ this->File = -1;
+
+ if (lockResult == 0) {
+ return cmFileLockResult::MakeOk();
+ }
+ return cmFileLockResult::MakeSystem();
+}
+
+cmFileLockResult cmFileLock::OpenFile()
+{
+ this->File = ::open(this->Filename.c_str(), O_RDWR);
+ if (this->File == -1) {
+ return cmFileLockResult::MakeSystem();
+ }
+ return cmFileLockResult::MakeOk();
+}
+
+cmFileLockResult cmFileLock::LockWithoutTimeout()
+{
+ if (this->LockFile(F_SETLKW, F_WRLCK) == -1) {
+ return cmFileLockResult::MakeSystem();
+ }
+ return cmFileLockResult::MakeOk();
+}
+
+cmFileLockResult cmFileLock::LockWithTimeout(unsigned long seconds)
+{
+ while (true) {
+ if (this->LockFile(F_SETLK, F_WRLCK) == -1) {
+ if (errno != EACCES && errno != EAGAIN) {
+ return cmFileLockResult::MakeSystem();
+ }
+ } else {
+ return cmFileLockResult::MakeOk();
+ }
+ if (seconds == 0) {
+ return cmFileLockResult::MakeTimeout();
+ }
+ --seconds;
+ cmSystemTools::Delay(1000);
+ }
+}
+
+int cmFileLock::LockFile(int cmd, int type) const
+{
+ struct ::flock lock;
+ lock.l_start = 0;
+ lock.l_len = 0; // lock all bytes
+ lock.l_pid = 0; // unused (for F_GETLK only)
+ lock.l_type = static_cast<short>(type); // exclusive lock
+ lock.l_whence = SEEK_SET;
+ return ::fcntl(this->File, cmd, &lock);
+}
diff --git a/Source/cmFileLockWin32.cxx b/Source/cmFileLockWin32.cxx
new file mode 100644
index 0000000..b8e435a
--- /dev/null
+++ b/Source/cmFileLockWin32.cxx
@@ -0,0 +1,87 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include <windows.h> // CreateFileW
+
+#include "cmFileLock.h"
+#include "cmSystemTools.h"
+
+cmFileLock::cmFileLock()
+{
+}
+
+cmFileLockResult cmFileLock::Release()
+{
+ if (this->Filename.empty()) {
+ return cmFileLockResult::MakeOk();
+ }
+ const unsigned long len = static_cast<unsigned long>(-1);
+ static OVERLAPPED overlapped;
+ const DWORD reserved = 0;
+ const BOOL unlockResult =
+ UnlockFileEx(File, reserved, len, len, &overlapped);
+
+ this->Filename = "";
+
+ CloseHandle(this->File);
+ this->File = INVALID_HANDLE_VALUE;
+
+ if (unlockResult) {
+ return cmFileLockResult::MakeOk();
+ } else {
+ return cmFileLockResult::MakeSystem();
+ }
+}
+
+cmFileLockResult cmFileLock::OpenFile()
+{
+ const DWORD access = GENERIC_READ | GENERIC_WRITE;
+ const DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ const PSECURITY_ATTRIBUTES security = NULL;
+ const DWORD attr = 0;
+ const HANDLE templ = NULL;
+ this->File = CreateFileW(
+ cmSystemTools::ConvertToWindowsExtendedPath(this->Filename).c_str(),
+ access, shareMode, security, OPEN_EXISTING, attr, templ);
+ if (this->File == INVALID_HANDLE_VALUE) {
+ return cmFileLockResult::MakeSystem();
+ } else {
+ return cmFileLockResult::MakeOk();
+ }
+}
+
+cmFileLockResult cmFileLock::LockWithoutTimeout()
+{
+ if (!this->LockFile(LOCKFILE_EXCLUSIVE_LOCK)) {
+ return cmFileLockResult::MakeSystem();
+ } else {
+ return cmFileLockResult::MakeOk();
+ }
+}
+
+cmFileLockResult cmFileLock::LockWithTimeout(unsigned long seconds)
+{
+ const DWORD flags = LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY;
+ while (true) {
+ const BOOL result = this->LockFile(flags);
+ if (result) {
+ return cmFileLockResult::MakeOk();
+ }
+ const DWORD error = GetLastError();
+ if (error != ERROR_LOCK_VIOLATION) {
+ return cmFileLockResult::MakeSystem();
+ }
+ if (seconds == 0) {
+ return cmFileLockResult::MakeTimeout();
+ }
+ --seconds;
+ cmSystemTools::Delay(1000);
+ }
+}
+
+BOOL cmFileLock::LockFile(DWORD flags)
+{
+ const DWORD reserved = 0;
+ const unsigned long len = static_cast<unsigned long>(-1);
+ static OVERLAPPED overlapped;
+ return LockFileEx(this->File, flags, reserved, len, len, &overlapped);
+}
diff --git a/Source/cmFilePathChecksum.cxx b/Source/cmFilePathChecksum.cxx
new file mode 100644
index 0000000..6b52230
--- /dev/null
+++ b/Source/cmFilePathChecksum.cxx
@@ -0,0 +1,86 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFilePathChecksum.h"
+
+#include <vector>
+
+#include "cmBase32.h"
+#include "cmCryptoHash.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+cmFilePathChecksum::cmFilePathChecksum() = default;
+
+cmFilePathChecksum::cmFilePathChecksum(std::string const& currentSrcDir,
+ std::string const& currentBinDir,
+ std::string const& projectSrcDir,
+ std::string const& projectBinDir)
+{
+ this->setupParentDirs(currentSrcDir, currentBinDir, projectSrcDir,
+ projectBinDir);
+}
+
+cmFilePathChecksum::cmFilePathChecksum(cmMakefile* makefile)
+{
+ this->setupParentDirs(makefile->GetCurrentSourceDirectory(),
+ makefile->GetCurrentBinaryDirectory(),
+ makefile->GetHomeDirectory(),
+ makefile->GetHomeOutputDirectory());
+}
+
+void cmFilePathChecksum::setupParentDirs(std::string const& currentSrcDir,
+ std::string const& currentBinDir,
+ std::string const& projectSrcDir,
+ std::string const& projectBinDir)
+{
+ this->parentDirs[0].first = cmSystemTools::GetRealPath(currentSrcDir);
+ this->parentDirs[1].first = cmSystemTools::GetRealPath(currentBinDir);
+ this->parentDirs[2].first = cmSystemTools::GetRealPath(projectSrcDir);
+ this->parentDirs[3].first = cmSystemTools::GetRealPath(projectBinDir);
+
+ this->parentDirs[0].second = "CurrentSource";
+ this->parentDirs[1].second = "CurrentBinary";
+ this->parentDirs[2].second = "ProjectSource";
+ this->parentDirs[3].second = "ProjectBinary";
+}
+
+std::string cmFilePathChecksum::get(std::string const& filePath) const
+{
+ std::string relPath;
+ std::string relSeed;
+ {
+ std::string const fileReal = cmSystemTools::GetRealPath(filePath);
+ std::string parentDir;
+ // Find closest project parent directory
+ for (auto const& pDir : this->parentDirs) {
+ if (!pDir.first.empty() &&
+ cmsys::SystemTools::IsSubDirectory(fileReal, pDir.first)) {
+ parentDir = pDir.first;
+ relSeed = pDir.second;
+ break;
+ }
+ }
+ // Use file system root as fallback parent directory
+ if (parentDir.empty()) {
+ relSeed = "FileSystemRoot";
+ cmsys::SystemTools::SplitPathRootComponent(fileReal, &parentDir);
+ }
+ // Calculate relative path from project parent directory
+ relPath = cmsys::SystemTools::RelativePath(
+ parentDir, cmsys::SystemTools::GetParentDirectory(fileReal));
+ }
+
+ // Calculate the file ( seed + relative path ) binary checksum
+ std::vector<unsigned char> hashBytes =
+ cmCryptoHash(cmCryptoHash::AlgoSHA256).ByteHashString(relSeed + relPath);
+
+ // Convert binary checksum to string
+ return cmBase32Encoder().encodeString(hashBytes.data(), hashBytes.size(),
+ false);
+}
+
+std::string cmFilePathChecksum::getPart(std::string const& filePath,
+ size_t length) const
+{
+ return this->get(filePath).substr(0, length);
+}
diff --git a/Source/cmFilePathChecksum.h b/Source/cmFilePathChecksum.h
new file mode 100644
index 0000000..a6f7bd3
--- /dev/null
+++ b/Source/cmFilePathChecksum.h
@@ -0,0 +1,61 @@
+/* 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 <array>
+#include <cstddef>
+#include <string>
+#include <utility>
+
+class cmMakefile;
+
+/** \class cmFilePathChecksum
+ * @brief Generates a checksum for the parent directory of a file
+ *
+ * The checksum is calculated from the relative file path to the
+ * closest known project directory. This guarantees reproducibility
+ * when source and build directory differ e.g. for different project
+ * build directories.
+ */
+class cmFilePathChecksum
+{
+public:
+ /// Maximum number of characters to use from the path checksum
+ static const size_t partLengthDefault = 10;
+
+ /// @brief Parent directories are empty
+ cmFilePathChecksum();
+
+ /// @brief Initializes the parent directories manually
+ cmFilePathChecksum(std::string const& currentSrcDir,
+ std::string const& currentBinDir,
+ std::string const& projectSrcDir,
+ std::string const& projectBinDir);
+
+ /// @brief Initializes the parent directories from a makefile
+ cmFilePathChecksum(cmMakefile* makefile);
+
+ /// @brief Allows parent directories setup after construction
+ ///
+ void setupParentDirs(std::string const& currentSrcDir,
+ std::string const& currentBinDir,
+ std::string const& projectSrcDir,
+ std::string const& projectBinDir);
+
+ /* @brief Calculates the path checksum for the parent directory of a file
+ *
+ */
+ std::string get(std::string const& filePath) const;
+
+ /* @brief Same as get() but returns only the first length characters
+ *
+ */
+ std::string getPart(std::string const& filePath,
+ size_t length = partLengthDefault) const;
+
+private:
+ /// List of (directory name, seed name) pairs
+ std::array<std::pair<std::string, std::string>, 4> parentDirs;
+};
diff --git a/Source/cmFileTime.cxx b/Source/cmFileTime.cxx
new file mode 100644
index 0000000..0606baf
--- /dev/null
+++ b/Source/cmFileTime.cxx
@@ -0,0 +1,51 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileTime.h"
+
+#include <ctime>
+#include <string>
+
+// Use a platform-specific API to get file times efficiently.
+#if !defined(_WIN32) || defined(__CYGWIN__)
+# include "cm_sys_stat.h"
+#else
+# include <windows.h>
+
+# include "cmsys/Encoding.hxx"
+#endif
+
+bool cmFileTime::Load(std::string const& fileName)
+{
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ // POSIX version. Use the stat function.
+ struct stat fst;
+ if (::stat(fileName.c_str(), &fst) != 0) {
+ return false;
+ }
+# if CMake_STAT_HAS_ST_MTIM
+ // Nanosecond resolution
+ this->Time = fst.st_mtim.tv_sec * UtPerS + fst.st_mtim.tv_nsec;
+# elif CMake_STAT_HAS_ST_MTIMESPEC
+ // Nanosecond resolution
+ this->Time = fst.st_mtimespec.tv_sec * UtPerS + fst.st_mtimespec.tv_nsec;
+# else
+ // Second resolution
+ this->Time = fst.st_mtime * UtPerS;
+# endif
+#else
+ // Windows version. Get the modification time from extended file attributes.
+ WIN32_FILE_ATTRIBUTE_DATA fdata;
+ if (!GetFileAttributesExW(cmsys::Encoding::ToWide(fileName).c_str(),
+ GetFileExInfoStandard, &fdata)) {
+ return false;
+ }
+
+ // Copy the file time to the output location.
+ using uint64 = unsigned long long;
+
+ this->Time = static_cast<TimeType>(
+ (uint64(fdata.ftLastWriteTime.dwHighDateTime) << 32) +
+ fdata.ftLastWriteTime.dwLowDateTime);
+#endif
+ return true;
+}
diff --git a/Source/cmFileTime.h b/Source/cmFileTime.h
new file mode 100644
index 0000000..4419880
--- /dev/null
+++ b/Source/cmFileTime.h
@@ -0,0 +1,139 @@
+/* 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 <string>
+
+/** \class cmFileTime
+ * \brief Abstract file modification time with support for comparison with
+ * other file modification times.
+ */
+class cmFileTime
+{
+public:
+ using TimeType = long long;
+ // unit time per second
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ // unit time is one nanosecond
+ static constexpr TimeType UtPerS = 1000000000;
+#else
+ // unit time is 100 nanosecond
+ static constexpr TimeType UtPerS = 10000000;
+#endif
+ cmFileTime() = default;
+ ~cmFileTime() = default;
+
+ /**
+ * @brief Loads the file time of fileName from the file system
+ * @return true on success
+ */
+ bool Load(std::string const& fileName);
+
+ /**
+ * @brief Return true if this is older than ftm
+ */
+ bool Older(cmFileTime const& ftm) const
+ {
+ return (this->Time - ftm.Time) < 0;
+ }
+
+ /**
+ * @brief Return true if this is newer than ftm
+ */
+ bool Newer(cmFileTime const& ftm) const
+ {
+ return (ftm.Time - this->Time) < 0;
+ }
+
+ /**
+ * @brief Return true if this is the same as ftm
+ */
+ bool Equal(cmFileTime const& ftm) const { return this->Time == ftm.Time; }
+
+ /**
+ * @brief Return true if this is not the same as ftm
+ */
+ bool Differ(cmFileTime const& ftm) const { return this->Time != ftm.Time; }
+
+ /**
+ * @brief Compare file modification times.
+ * @return -1, 0, +1 for this older, same, or newer than ftm.
+ */
+ int Compare(cmFileTime const& ftm) const
+ {
+ TimeType const diff = this->Time - ftm.Time;
+ if (diff == 0) {
+ return 0;
+ }
+ return (diff < 0) ? -1 : 1;
+ }
+
+ // -- Comparison in second resolution
+
+ /**
+ * @brief Return true if this is at least a second older than ftm
+ */
+ bool OlderS(cmFileTime const& ftm) const
+ {
+ return (ftm.Time - this->Time) >= cmFileTime::UtPerS;
+ }
+
+ /**
+ * @brief Return true if this is at least a second newer than ftm
+ */
+ bool NewerS(cmFileTime const& ftm) const
+ {
+ return (this->Time - ftm.Time) >= cmFileTime::UtPerS;
+ }
+
+ /**
+ * @brief Return true if this is within the same second as ftm
+ */
+ bool EqualS(cmFileTime const& ftm) const
+ {
+ TimeType diff = this->Time - ftm.Time;
+ if (diff < 0) {
+ diff = -diff;
+ }
+ return (diff < cmFileTime::UtPerS);
+ }
+
+ /**
+ * @brief Return true if this is older or newer than ftm by at least a second
+ */
+ bool DifferS(cmFileTime const& ftm) const
+ {
+ TimeType diff = this->Time - ftm.Time;
+ if (diff < 0) {
+ diff = -diff;
+ }
+ return (diff >= cmFileTime::UtPerS);
+ }
+
+ /**
+ * @brief Compare file modification times.
+ * @return -1: this at least a second older, 0: this within the same second
+ * as ftm, +1: this at least a second newer than ftm.
+ */
+ int CompareS(cmFileTime const& ftm) const
+ {
+ TimeType const diff = this->Time - ftm.Time;
+ if (diff <= -cmFileTime::UtPerS) {
+ return -1;
+ }
+ if (diff >= cmFileTime::UtPerS) {
+ return 1;
+ }
+ return 0;
+ }
+
+ /**
+ * @brief The file modification time in unit time per second
+ */
+ TimeType GetTime() const { return this->Time; }
+
+private:
+ TimeType Time = 0;
+};
diff --git a/Source/cmFileTimeCache.cxx b/Source/cmFileTimeCache.cxx
new file mode 100644
index 0000000..0d1dae5
--- /dev/null
+++ b/Source/cmFileTimeCache.cxx
@@ -0,0 +1,64 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileTimeCache.h"
+
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+cmFileTimeCache::cmFileTimeCache() = default;
+
+cmFileTimeCache::~cmFileTimeCache() = default;
+
+bool cmFileTimeCache::Load(std::string const& fileName, cmFileTime& fileTime)
+{
+ // Use the stored time if available.
+ {
+ auto fit = this->Cache.find(fileName);
+ if (fit != this->Cache.end()) {
+ fileTime = fit->second;
+ return true;
+ }
+ }
+ // Read file time from OS
+ if (!fileTime.Load(fileName)) {
+ return false;
+ }
+ // Store file time in cache
+ this->Cache[fileName] = fileTime;
+ return true;
+}
+
+bool cmFileTimeCache::Remove(std::string const& fileName)
+{
+ return (this->Cache.erase(fileName) != 0);
+}
+
+bool cmFileTimeCache::Compare(std::string const& f1, std::string const& f2,
+ int* result)
+{
+ // Get the modification time for each file.
+ cmFileTime ft1;
+ cmFileTime ft2;
+ if (this->Load(f1, ft1) && this->Load(f2, ft2)) {
+ // Compare the two modification times.
+ *result = ft1.Compare(ft2);
+ return true;
+ }
+ // No comparison available. Default to the same time.
+ *result = 0;
+ return false;
+}
+
+bool cmFileTimeCache::DifferS(std::string const& f1, std::string const& f2)
+{
+ // Get the modification time for each file.
+ cmFileTime ft1;
+ cmFileTime ft2;
+ if (this->Load(f1, ft1) && this->Load(f2, ft2)) {
+ // Compare the two modification times.
+ return ft1.DifferS(ft2);
+ }
+ // No comparison available. Default to different times.
+ return true;
+}
diff --git a/Source/cmFileTimeCache.h b/Source/cmFileTimeCache.h
new file mode 100644
index 0000000..336136e
--- /dev/null
+++ b/Source/cmFileTimeCache.h
@@ -0,0 +1,54 @@
+/* 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 <string>
+#include <unordered_map>
+
+#include "cmFileTime.h" // IWYU pragma: keep
+
+/** \class cmFileTimeCache
+ * \brief Caches file modification times in an internal map for fast lookups.
+ */
+class cmFileTimeCache
+{
+public:
+ cmFileTimeCache();
+ ~cmFileTimeCache();
+
+ cmFileTimeCache(const cmFileTimeCache&) = delete;
+ cmFileTimeCache& operator=(const cmFileTimeCache&) = delete;
+
+ /**
+ * @brief Loads the file time from the cache or the file system.
+ * @return true on success
+ */
+ bool Load(std::string const& fileName, cmFileTime& fileTime);
+
+ /**
+ * @brief Removes a file time from the cache
+ * @return true if the file was found in the cache and removed
+ */
+ bool Remove(std::string const& fileName);
+
+ /**
+ * @brief Compare file modification times.
+ * @return true for successful comparison and false for error.
+ *
+ * When true is returned, result has -1, 0, +1 for
+ * f1 older, same, or newer than f2.
+ */
+ bool Compare(std::string const& f1, std::string const& f2, int* result);
+
+ /**
+ * @brief Compare file modification times.
+ * @return true unless both files exist and have modification times less
+ * than 1 second apart.
+ */
+ bool DifferS(std::string const& f1, std::string const& f2);
+
+private:
+ std::unordered_map<std::string, cmFileTime> Cache;
+};
diff --git a/Source/cmFileTimes.cxx b/Source/cmFileTimes.cxx
new file mode 100644
index 0000000..bd896f5
--- /dev/null
+++ b/Source/cmFileTimes.cxx
@@ -0,0 +1,129 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileTimes.h"
+
+#include <utility>
+
+#include <cm/memory>
+
+#include "cm_sys_stat.h"
+
+#if defined(_WIN32)
+# include <windows.h>
+
+# include "cmSystemTools.h"
+#else
+# include <utime.h>
+#endif
+
+#if defined(_WIN32) && \
+ (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__MINGW32__))
+# include <io.h>
+#endif
+
+#ifdef _WIN32
+class cmFileTimes::WindowsHandle
+{
+public:
+ WindowsHandle(HANDLE h)
+ : handle_(h)
+ {
+ }
+ ~WindowsHandle()
+ {
+ if (this->handle_ != INVALID_HANDLE_VALUE) {
+ CloseHandle(this->handle_);
+ }
+ }
+ explicit operator bool() const
+ {
+ return this->handle_ != INVALID_HANDLE_VALUE;
+ }
+ bool operator!() const { return this->handle_ == INVALID_HANDLE_VALUE; }
+ operator HANDLE() const { return this->handle_; }
+
+private:
+ HANDLE handle_;
+};
+#endif
+
+class cmFileTimes::Times
+{
+public:
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ FILETIME timeCreation;
+ FILETIME timeLastAccess;
+ FILETIME timeLastWrite;
+#else
+ struct utimbuf timeBuf;
+#endif
+};
+
+cmFileTimes::cmFileTimes() = default;
+cmFileTimes::cmFileTimes(std::string const& fileName)
+{
+ this->Load(fileName);
+}
+cmFileTimes::~cmFileTimes() = default;
+
+bool cmFileTimes::Load(std::string const& fileName)
+{
+ std::unique_ptr<Times> ptr;
+ if (this->IsValid()) {
+ // Invalidate this and re-use times
+ ptr.swap(this->times);
+ } else {
+ ptr = cm::make_unique<Times>();
+ }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ cmFileTimes::WindowsHandle handle =
+ CreateFileW(cmSystemTools::ConvertToWindowsExtendedPath(fileName).c_str(),
+ GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, 0);
+ if (!handle) {
+ return false;
+ }
+ if (!GetFileTime(handle, &ptr->timeCreation, &ptr->timeLastAccess,
+ &ptr->timeLastWrite)) {
+ return false;
+ }
+#else
+ struct stat st;
+ if (stat(fileName.c_str(), &st) < 0) {
+ return false;
+ }
+ ptr->timeBuf.actime = st.st_atime;
+ ptr->timeBuf.modtime = st.st_mtime;
+#endif
+ // Accept times
+ this->times = std::move(ptr);
+ return true;
+}
+
+bool cmFileTimes::Store(std::string const& fileName) const
+{
+ if (!this->IsValid()) {
+ return false;
+ }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ cmFileTimes::WindowsHandle handle = CreateFileW(
+ cmSystemTools::ConvertToWindowsExtendedPath(fileName).c_str(),
+ FILE_WRITE_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
+ if (!handle) {
+ return false;
+ }
+ return SetFileTime(handle, &this->times->timeCreation,
+ &this->times->timeLastAccess,
+ &this->times->timeLastWrite) != 0;
+#else
+ return utime(fileName.c_str(), &this->times->timeBuf) >= 0;
+#endif
+}
+
+bool cmFileTimes::Copy(std::string const& fromFile, std::string const& toFile)
+{
+ cmFileTimes fileTimes;
+ return (fileTimes.Load(fromFile) && fileTimes.Store(toFile));
+}
diff --git a/Source/cmFileTimes.h b/Source/cmFileTimes.h
new file mode 100644
index 0000000..50d64fd
--- /dev/null
+++ b/Source/cmFileTimes.h
@@ -0,0 +1,37 @@
+/* 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 <memory>
+#include <string>
+
+/** \class cmFileTimes
+ * \brief Loads and stores file times.
+ */
+class cmFileTimes
+{
+public:
+ cmFileTimes();
+ //! Calls Load()
+ cmFileTimes(std::string const& fileName);
+ ~cmFileTimes();
+
+ //! @return true, if file times were loaded successfully
+ bool IsValid() const { return (this->times != nullptr); }
+ //! Try to load the file times from @a fileName and @return IsValid()
+ bool Load(std::string const& fileName);
+ //! Stores the file times at @a fileName (if IsValid())
+ bool Store(std::string const& fileName) const;
+
+ //! Copies the file times of @a fromFile to @a toFile
+ static bool Copy(std::string const& fromFile, std::string const& toFile);
+
+private:
+#ifdef _WIN32
+ class WindowsHandle;
+#endif
+ class Times;
+ std::unique_ptr<Times> times;
+};
diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx
new file mode 100644
index 0000000..bf52d75
--- /dev/null
+++ b/Source/cmFindBase.cxx
@@ -0,0 +1,405 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFindBase.h"
+
+#include <cstddef>
+#include <deque>
+#include <map>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmSearchPath.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+class cmExecutionStatus;
+
+cmFindBase::cmFindBase(cmExecutionStatus& status)
+ : cmFindCommon(status)
+{
+}
+
+bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
+{
+ if (argsIn.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // copy argsIn into args so it can be modified,
+ // in the process extract the DOC "documentation"
+ size_t size = argsIn.size();
+ std::vector<std::string> args;
+ bool foundDoc = false;
+ for (unsigned int j = 0; j < size; ++j) {
+ if (foundDoc || argsIn[j] != "DOC") {
+ if (argsIn[j] == "ENV") {
+ if (j + 1 < size) {
+ j++;
+ cmSystemTools::GetPath(args, argsIn[j].c_str());
+ }
+ } else {
+ args.push_back(argsIn[j]);
+ }
+ } else {
+ if (j + 1 < size) {
+ foundDoc = true;
+ this->VariableDocumentation = argsIn[j + 1];
+ j++;
+ if (j >= size) {
+ break;
+ }
+ }
+ }
+ }
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ this->VariableName = args[0];
+ if (this->CheckForVariableInCache()) {
+ this->AlreadyInCache = true;
+ return true;
+ }
+ this->AlreadyInCache = false;
+
+ // Find what search path locations have been enabled/disable
+ this->SelectDefaultSearchModes();
+
+ // Find the current root path mode.
+ this->SelectDefaultRootPathMode();
+
+ // Find the current bundle/framework search policy.
+ this->SelectDefaultMacMode();
+
+ bool newStyle = false;
+ enum Doing
+ {
+ DoingNone,
+ DoingNames,
+ DoingPaths,
+ DoingPathSuffixes,
+ DoingHints
+ };
+ Doing doing = DoingNames; // assume it starts with a name
+ for (unsigned int j = 1; j < args.size(); ++j) {
+ if (args[j] == "NAMES") {
+ doing = DoingNames;
+ newStyle = true;
+ } else if (args[j] == "PATHS") {
+ doing = DoingPaths;
+ newStyle = true;
+ } else if (args[j] == "HINTS") {
+ doing = DoingHints;
+ newStyle = true;
+ } else if (args[j] == "PATH_SUFFIXES") {
+ doing = DoingPathSuffixes;
+ newStyle = true;
+ } else if (args[j] == "NAMES_PER_DIR") {
+ doing = DoingNone;
+ if (this->NamesPerDirAllowed) {
+ this->NamesPerDir = true;
+ } else {
+ this->SetError("does not support NAMES_PER_DIR");
+ return false;
+ }
+ } else if (args[j] == "NO_SYSTEM_PATH") {
+ doing = DoingNone;
+ this->NoDefaultPath = true;
+ } else if (args[j] == "REQUIRED") {
+ doing = DoingNone;
+ this->Required = true;
+ newStyle = true;
+ } else if (this->CheckCommonArgument(args[j])) {
+ doing = DoingNone;
+ } else {
+ // Some common arguments were accidentally supported by CMake
+ // 2.4 and 2.6.0 in the short-hand form of the command, so we
+ // must support it even though it is not documented.
+ if (doing == DoingNames) {
+ this->Names.push_back(args[j]);
+ } else if (doing == DoingPaths) {
+ this->UserGuessArgs.push_back(args[j]);
+ } else if (doing == DoingHints) {
+ this->UserHintsArgs.push_back(args[j]);
+ } else if (doing == DoingPathSuffixes) {
+ this->AddPathSuffix(args[j]);
+ }
+ }
+ }
+
+ if (this->VariableDocumentation.empty()) {
+ this->VariableDocumentation = "Where can ";
+ if (this->Names.empty()) {
+ this->VariableDocumentation += "the (unknown) library be found";
+ } else if (this->Names.size() == 1) {
+ this->VariableDocumentation +=
+ "the " + this->Names.front() + " library be found";
+ } else {
+ this->VariableDocumentation += "one of the ";
+ this->VariableDocumentation +=
+ cmJoin(cmMakeRange(this->Names).retreat(1), ", ");
+ this->VariableDocumentation +=
+ " or " + this->Names.back() + " libraries be found";
+ }
+ }
+
+ // look for old style
+ // FIND_*(VAR name path1 path2 ...)
+ if (!newStyle && !this->Names.empty()) {
+ // All the short-hand arguments have been recorded as names.
+ std::vector<std::string> shortArgs = this->Names;
+ this->Names.clear(); // clear out any values in Names
+ this->Names.push_back(shortArgs[0]);
+ cm::append(this->UserGuessArgs, shortArgs.begin() + 1, shortArgs.end());
+ }
+ this->ExpandPaths();
+
+ this->ComputeFinalPaths();
+
+ return true;
+}
+
+void cmFindBase::ExpandPaths()
+{
+ if (!this->NoDefaultPath) {
+ if (!this->NoPackageRootPath) {
+ this->FillPackageRootPath();
+ }
+ if (!this->NoCMakePath) {
+ this->FillCMakeVariablePath();
+ }
+ if (!this->NoCMakeEnvironmentPath) {
+ this->FillCMakeEnvironmentPath();
+ }
+ }
+ this->FillUserHintsPath();
+ if (!this->NoDefaultPath) {
+ if (!this->NoSystemEnvironmentPath) {
+ this->FillSystemEnvironmentPath();
+ }
+ if (!this->NoCMakeSystemPath) {
+ this->FillCMakeSystemVariablePath();
+ }
+ }
+ this->FillUserGuessPath();
+}
+
+void cmFindBase::FillCMakeEnvironmentPath()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::CMakeEnvironment];
+
+ // Add CMAKE_*_PATH environment variables
+ std::string var = cmStrCat("CMAKE_", this->CMakePathName, "_PATH");
+ paths.AddEnvPrefixPath("CMAKE_PREFIX_PATH");
+ paths.AddEnvPath(var);
+
+ if (this->CMakePathName == "PROGRAM") {
+ paths.AddEnvPath("CMAKE_APPBUNDLE_PATH");
+ } else {
+ paths.AddEnvPath("CMAKE_FRAMEWORK_PATH");
+ }
+ paths.AddSuffixes(this->SearchPathSuffixes);
+}
+
+void cmFindBase::FillPackageRootPath()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::PackageRoot];
+
+ // Add the PACKAGE_ROOT_PATH from each enclosing find_package call.
+ for (std::vector<std::string> const& pkgPaths :
+ cmReverseRange(this->Makefile->FindPackageRootPathStack)) {
+ paths.AddPrefixPaths(pkgPaths);
+ }
+
+ paths.AddSuffixes(this->SearchPathSuffixes);
+}
+
+void cmFindBase::FillCMakeVariablePath()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::CMake];
+
+ // Add CMake variables of the same name as the previous environment
+ // variables CMAKE_*_PATH to be used most of the time with -D
+ // command line options
+ std::string var = cmStrCat("CMAKE_", this->CMakePathName, "_PATH");
+ paths.AddCMakePrefixPath("CMAKE_PREFIX_PATH");
+ paths.AddCMakePath(var);
+
+ if (this->CMakePathName == "PROGRAM") {
+ paths.AddCMakePath("CMAKE_APPBUNDLE_PATH");
+ } else {
+ paths.AddCMakePath("CMAKE_FRAMEWORK_PATH");
+ }
+ paths.AddSuffixes(this->SearchPathSuffixes);
+}
+
+void cmFindBase::FillSystemEnvironmentPath()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::SystemEnvironment];
+
+ // Add LIB or INCLUDE
+ if (!this->EnvironmentPath.empty()) {
+ paths.AddEnvPath(this->EnvironmentPath);
+#if defined(_WIN32) || defined(__CYGWIN__)
+ paths.AddEnvPrefixPath("PATH", true);
+#endif
+ }
+ // Add PATH
+ paths.AddEnvPath("PATH");
+ paths.AddSuffixes(this->SearchPathSuffixes);
+}
+
+void cmFindBase::FillCMakeSystemVariablePath()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::CMakeSystem];
+
+ std::string var = cmStrCat("CMAKE_SYSTEM_", this->CMakePathName, "_PATH");
+ paths.AddCMakePrefixPath("CMAKE_SYSTEM_PREFIX_PATH");
+ paths.AddCMakePath(var);
+
+ if (this->CMakePathName == "PROGRAM") {
+ paths.AddCMakePath("CMAKE_SYSTEM_APPBUNDLE_PATH");
+ } else {
+ paths.AddCMakePath("CMAKE_SYSTEM_FRAMEWORK_PATH");
+ }
+ paths.AddSuffixes(this->SearchPathSuffixes);
+}
+
+void cmFindBase::FillUserHintsPath()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::Hints];
+
+ for (std::string const& p : this->UserHintsArgs) {
+ paths.AddUserPath(p);
+ }
+ paths.AddSuffixes(this->SearchPathSuffixes);
+}
+
+void cmFindBase::FillUserGuessPath()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::Guess];
+
+ for (std::string const& p : this->UserGuessArgs) {
+ paths.AddUserPath(p);
+ }
+ paths.AddSuffixes(this->SearchPathSuffixes);
+}
+
+bool cmFindBase::CheckForVariableInCache()
+{
+ if (cmProp cacheValue = this->Makefile->GetDefinition(this->VariableName)) {
+ cmState* state = this->Makefile->GetState();
+ cmProp cacheEntry = state->GetCacheEntryValue(this->VariableName);
+ bool found = !cmIsNOTFOUND(*cacheValue);
+ bool cached = cacheEntry != nullptr;
+ if (found) {
+ // If the user specifies the entry on the command line without a
+ // type we should add the type and docstring but keep the
+ // original value. Tell the subclass implementations to do
+ // this.
+ if (cached &&
+ state->GetCacheEntryType(this->VariableName) ==
+ cmStateEnums::UNINITIALIZED) {
+ this->AlreadyInCacheWithoutMetaInfo = true;
+ }
+ return true;
+ }
+ if (cached) {
+ cmProp hs =
+ state->GetCacheEntryProperty(this->VariableName, "HELPSTRING");
+ this->VariableDocumentation = hs ? *hs : "(none)";
+ }
+ }
+ return false;
+}
+
+cmFindBaseDebugState::cmFindBaseDebugState(std::string commandName,
+ cmFindBase const* findBase)
+ : FindCommand(findBase)
+ , CommandName(std::move(commandName))
+{
+}
+
+cmFindBaseDebugState::~cmFindBaseDebugState()
+{
+ if (this->FindCommand->DebugMode) {
+ std::string buffer =
+ cmStrCat(this->CommandName, " called with the following settings:\n");
+ buffer += cmStrCat(" VAR: ", this->FindCommand->VariableName, "\n");
+ buffer += cmStrCat(
+ " NAMES: ", cmWrap("\"", this->FindCommand->Names, "\"", "\n "),
+ "\n");
+ buffer += cmStrCat(
+ " Documentation: ", this->FindCommand->VariableDocumentation, "\n");
+ buffer += " Framework\n";
+ buffer += cmStrCat(" Only Search Frameworks: ",
+ this->FindCommand->SearchFrameworkOnly, "\n");
+
+ buffer += cmStrCat(" Search Frameworks Last: ",
+ this->FindCommand->SearchFrameworkLast, "\n");
+ buffer += cmStrCat(" Search Frameworks First: ",
+ this->FindCommand->SearchFrameworkFirst, "\n");
+ buffer += " AppBundle\n";
+ buffer += cmStrCat(" Only Search AppBundle: ",
+ this->FindCommand->SearchAppBundleOnly, "\n");
+ buffer += cmStrCat(" Search AppBundle Last: ",
+ this->FindCommand->SearchAppBundleLast, "\n");
+ buffer += cmStrCat(" Search AppBundle First: ",
+ this->FindCommand->SearchAppBundleFirst, "\n");
+
+ if (this->FindCommand->NoDefaultPath) {
+ buffer += " NO_DEFAULT_PATH Enabled\n";
+ } else {
+ buffer += cmStrCat(
+ " CMAKE_FIND_USE_CMAKE_PATH: ", !this->FindCommand->NoCMakePath, "\n",
+ " CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH: ",
+ !this->FindCommand->NoCMakeEnvironmentPath, "\n",
+ " CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: ",
+ !this->FindCommand->NoSystemEnvironmentPath, "\n",
+ " CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: ",
+ !this->FindCommand->NoCMakeSystemPath, "\n");
+ }
+
+ buffer +=
+ cmStrCat(this->CommandName, " considered the following locations:\n");
+ for (auto const& state : this->FailedSearchLocations) {
+ std::string path = cmStrCat(" ", state.path);
+ if (!state.regexName.empty()) {
+ path = cmStrCat(path, "/", state.regexName);
+ }
+ buffer += cmStrCat(path, "\n");
+ }
+
+ if (!this->FoundSearchLocation.path.empty()) {
+ buffer += cmStrCat("The item was found at\n ",
+ this->FoundSearchLocation.path, "\n");
+ } else {
+ buffer += "The item was not found.\n";
+ }
+
+ this->FindCommand->DebugMessage(buffer);
+ }
+}
+
+void cmFindBaseDebugState::FoundAt(std::string const& path,
+ std::string regexName)
+{
+ if (this->FindCommand->DebugMode) {
+ this->FoundSearchLocation = DebugLibState{ std::move(regexName), path };
+ }
+}
+
+void cmFindBaseDebugState::FailedAt(std::string const& path,
+ std::string regexName)
+{
+ if (this->FindCommand->DebugMode) {
+ this->FailedSearchLocations.emplace_back(std::move(regexName), path);
+ }
+}
diff --git a/Source/cmFindBase.h b/Source/cmFindBase.h
new file mode 100644
index 0000000..57a40be
--- /dev/null
+++ b/Source/cmFindBase.h
@@ -0,0 +1,95 @@
+/* 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 <string>
+#include <utility>
+#include <vector>
+
+#include "cmFindCommon.h"
+
+class cmExecutionStatus;
+
+/** \class cmFindBase
+ * \brief Base class for most FIND_XXX commands.
+ *
+ * cmFindBase is a parent class for cmFindProgramCommand, cmFindPathCommand,
+ * and cmFindLibraryCommand, cmFindFileCommand
+ */
+class cmFindBase : public cmFindCommon
+{
+public:
+ cmFindBase(cmExecutionStatus& status);
+ virtual ~cmFindBase() = default;
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ virtual bool ParseArguments(std::vector<std::string> const& args);
+
+protected:
+ friend class cmFindBaseDebugState;
+ void ExpandPaths();
+
+ // see if the VariableName is already set in the cache,
+ // also copy the documentation from the cache to VariableDocumentation
+ // if it has documentation in the cache
+ bool CheckForVariableInCache();
+
+ // use by command during find
+ std::string VariableDocumentation;
+ std::string VariableName;
+ std::vector<std::string> Names;
+ bool NamesPerDir = false;
+ bool NamesPerDirAllowed = false;
+
+ // CMAKE_*_PATH CMAKE_SYSTEM_*_PATH FRAMEWORK|LIBRARY|INCLUDE|PROGRAM
+ std::string EnvironmentPath; // LIB,INCLUDE
+
+ bool AlreadyInCache = false;
+ bool AlreadyInCacheWithoutMetaInfo = false;
+
+ bool Required = false;
+
+private:
+ // Add pieces of the search.
+ void FillPackageRootPath();
+ void FillCMakeVariablePath();
+ void FillCMakeEnvironmentPath();
+ void FillUserHintsPath();
+ void FillSystemEnvironmentPath();
+ void FillCMakeSystemVariablePath();
+ void FillUserGuessPath();
+};
+
+class cmFindBaseDebugState
+{
+public:
+ explicit cmFindBaseDebugState(std::string name, cmFindBase const* findBase);
+ ~cmFindBaseDebugState();
+
+ void FoundAt(std::string const& path, std::string regexName = std::string());
+ void FailedAt(std::string const& path,
+ std::string regexName = std::string());
+
+private:
+ struct DebugLibState
+ {
+ DebugLibState() = default;
+ DebugLibState(std::string&& n, std::string p)
+ : regexName(n)
+ , path(std::move(p))
+ {
+ }
+ std::string regexName;
+ std::string path;
+ };
+
+ cmFindBase const* FindCommand;
+ std::string CommandName;
+ std::vector<DebugLibState> FailedSearchLocations;
+ DebugLibState FoundSearchLocation;
+};
diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx
new file mode 100644
index 0000000..d2f9619
--- /dev/null
+++ b/Source/cmFindCommon.cxx
@@ -0,0 +1,375 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFindCommon.h"
+
+#include <algorithm>
+#include <array>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+cmFindCommon::PathGroup cmFindCommon::PathGroup::All("ALL");
+cmFindCommon::PathLabel cmFindCommon::PathLabel::PackageRoot(
+ "PackageName_ROOT");
+cmFindCommon::PathLabel cmFindCommon::PathLabel::CMake("CMAKE");
+cmFindCommon::PathLabel cmFindCommon::PathLabel::CMakeEnvironment(
+ "CMAKE_ENVIRONMENT");
+cmFindCommon::PathLabel cmFindCommon::PathLabel::Hints("HINTS");
+cmFindCommon::PathLabel cmFindCommon::PathLabel::SystemEnvironment(
+ "SYSTM_ENVIRONMENT");
+cmFindCommon::PathLabel cmFindCommon::PathLabel::CMakeSystem("CMAKE_SYSTEM");
+cmFindCommon::PathLabel cmFindCommon::PathLabel::Guess("GUESS");
+
+cmFindCommon::cmFindCommon(cmExecutionStatus& status)
+ : Makefile(&status.GetMakefile())
+ , Status(status)
+{
+ this->FindRootPathMode = RootPathModeBoth;
+ this->NoDefaultPath = false;
+ this->NoPackageRootPath = false;
+ this->NoCMakePath = false;
+ this->NoCMakeEnvironmentPath = false;
+ this->NoSystemEnvironmentPath = false;
+ this->NoCMakeSystemPath = false;
+
+// OS X Bundle and Framework search policy. The default is to
+// search frameworks first on apple.
+#if defined(__APPLE__)
+ this->SearchFrameworkFirst = true;
+ this->SearchAppBundleFirst = true;
+#else
+ this->SearchFrameworkFirst = false;
+ this->SearchAppBundleFirst = false;
+#endif
+ this->SearchFrameworkOnly = false;
+ this->SearchFrameworkLast = false;
+ this->SearchAppBundleOnly = false;
+ this->SearchAppBundleLast = false;
+
+ this->InitializeSearchPathGroups();
+
+ this->DebugMode = false;
+}
+
+void cmFindCommon::SetError(std::string const& e)
+{
+ this->Status.SetError(e);
+}
+
+void cmFindCommon::DebugMessage(std::string const& msg) const
+{
+ if (this->Makefile) {
+ this->Makefile->IssueMessage(MessageType::LOG, msg);
+ }
+}
+
+bool cmFindCommon::ComputeIfDebugModeWanted()
+{
+ return this->Makefile->IsOn("CMAKE_FIND_DEBUG_MODE") ||
+ this->Makefile->GetCMakeInstance()->GetDebugFindOutput();
+}
+
+void cmFindCommon::InitializeSearchPathGroups()
+{
+ std::vector<PathLabel>* labels;
+
+ // Define the various different groups of path types
+
+ // All search paths
+ labels = &this->PathGroupLabelMap[PathGroup::All];
+ labels->push_back(PathLabel::PackageRoot);
+ labels->push_back(PathLabel::CMake);
+ labels->push_back(PathLabel::CMakeEnvironment);
+ labels->push_back(PathLabel::Hints);
+ labels->push_back(PathLabel::SystemEnvironment);
+ labels->push_back(PathLabel::CMakeSystem);
+ labels->push_back(PathLabel::Guess);
+
+ // Define the search group order
+ this->PathGroupOrder.push_back(PathGroup::All);
+
+ // Create the individual labeled search paths
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::PackageRoot, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::CMake, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::CMakeEnvironment, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::Hints, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::SystemEnvironment, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::CMakeSystem, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::Guess, cmSearchPath(this)));
+}
+
+void cmFindCommon::SelectDefaultRootPathMode()
+{
+ // Check the policy variable for this find command type.
+ std::string findRootPathVar =
+ cmStrCat("CMAKE_FIND_ROOT_PATH_MODE_", this->CMakePathName);
+ std::string rootPathMode =
+ this->Makefile->GetSafeDefinition(findRootPathVar);
+ if (rootPathMode == "NEVER") {
+ this->FindRootPathMode = RootPathModeNever;
+ } else if (rootPathMode == "ONLY") {
+ this->FindRootPathMode = RootPathModeOnly;
+ } else if (rootPathMode == "BOTH") {
+ this->FindRootPathMode = RootPathModeBoth;
+ }
+}
+
+void cmFindCommon::SelectDefaultMacMode()
+{
+ std::string ff = this->Makefile->GetSafeDefinition("CMAKE_FIND_FRAMEWORK");
+ if (ff == "NEVER") {
+ this->SearchFrameworkLast = false;
+ this->SearchFrameworkFirst = false;
+ this->SearchFrameworkOnly = false;
+ } else if (ff == "ONLY") {
+ this->SearchFrameworkLast = false;
+ this->SearchFrameworkFirst = false;
+ this->SearchFrameworkOnly = true;
+ } else if (ff == "FIRST") {
+ this->SearchFrameworkLast = false;
+ this->SearchFrameworkFirst = true;
+ this->SearchFrameworkOnly = false;
+ } else if (ff == "LAST") {
+ this->SearchFrameworkLast = true;
+ this->SearchFrameworkFirst = false;
+ this->SearchFrameworkOnly = false;
+ }
+
+ std::string fab = this->Makefile->GetSafeDefinition("CMAKE_FIND_APPBUNDLE");
+ if (fab == "NEVER") {
+ this->SearchAppBundleLast = false;
+ this->SearchAppBundleFirst = false;
+ this->SearchAppBundleOnly = false;
+ } else if (fab == "ONLY") {
+ this->SearchAppBundleLast = false;
+ this->SearchAppBundleFirst = false;
+ this->SearchAppBundleOnly = true;
+ } else if (fab == "FIRST") {
+ this->SearchAppBundleLast = false;
+ this->SearchAppBundleFirst = true;
+ this->SearchAppBundleOnly = false;
+ } else if (fab == "LAST") {
+ this->SearchAppBundleLast = true;
+ this->SearchAppBundleFirst = false;
+ this->SearchAppBundleOnly = false;
+ }
+}
+
+void cmFindCommon::SelectDefaultSearchModes()
+{
+ const std::array<std::pair<bool&, std::string>, 5> search_paths = {
+ { { this->NoPackageRootPath, "CMAKE_FIND_USE_PACKAGE_ROOT_PATH" },
+ { this->NoCMakePath, "CMAKE_FIND_USE_CMAKE_PATH" },
+ { this->NoCMakeEnvironmentPath,
+ "CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH" },
+ { this->NoSystemEnvironmentPath,
+ "CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH" },
+ { this->NoCMakeSystemPath, "CMAKE_FIND_USE_CMAKE_SYSTEM_PATH" } }
+ };
+
+ for (auto const& path : search_paths) {
+ cmProp def = this->Makefile->GetDefinition(path.second);
+ if (def) {
+ path.first = !cmIsOn(*def);
+ }
+ }
+}
+
+void cmFindCommon::RerootPaths(std::vector<std::string>& paths)
+{
+#if 0
+ for(std::string const& p : paths)
+ {
+ fprintf(stderr, "[%s]\n", p.c_str());
+ }
+#endif
+ // Short-circuit if there is nothing to do.
+ if (this->FindRootPathMode == RootPathModeNever) {
+ return;
+ }
+
+ cmProp sysroot = this->Makefile->GetDefinition("CMAKE_SYSROOT");
+ cmProp sysrootCompile =
+ this->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE");
+ cmProp sysrootLink = this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK");
+ cmProp rootPath = this->Makefile->GetDefinition("CMAKE_FIND_ROOT_PATH");
+ const bool noSysroot = !cmNonempty(sysroot);
+ const bool noCompileSysroot = !cmNonempty(sysrootCompile);
+ const bool noLinkSysroot = !cmNonempty(sysrootLink);
+ const bool noRootPath = !cmNonempty(rootPath);
+ if (noSysroot && noCompileSysroot && noLinkSysroot && noRootPath) {
+ return;
+ }
+
+ // Construct the list of path roots with no trailing slashes.
+ std::vector<std::string> roots;
+ if (rootPath) {
+ cmExpandList(*rootPath, roots);
+ }
+ if (sysrootCompile) {
+ roots.emplace_back(*sysrootCompile);
+ }
+ if (sysrootLink) {
+ roots.emplace_back(*sysrootLink);
+ }
+ if (sysroot) {
+ roots.emplace_back(*sysroot);
+ }
+ for (std::string& r : roots) {
+ cmSystemTools::ConvertToUnixSlashes(r);
+ }
+
+ cmProp stagePrefix = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
+
+ // Copy the original set of unrooted paths.
+ std::vector<std::string> unrootedPaths = paths;
+ paths.clear();
+
+ for (std::string const& r : roots) {
+ for (std::string const& up : unrootedPaths) {
+ // Place the unrooted path under the current root if it is not
+ // already inside. Skip the unrooted path if it is relative to
+ // a user home directory or is empty.
+ std::string rootedDir;
+ if (cmSystemTools::IsSubDirectory(up, r) ||
+ (stagePrefix && cmSystemTools::IsSubDirectory(up, *stagePrefix))) {
+ rootedDir = up;
+ } else if (!up.empty() && up[0] != '~') {
+ // Start with the new root.
+ rootedDir = cmStrCat(r, '/');
+
+ // Append the original path with its old root removed.
+ rootedDir += cmSystemTools::SplitPathRootComponent(up);
+ }
+
+ // Store the new path.
+ paths.push_back(rootedDir);
+ }
+ }
+
+ // If searching both rooted and unrooted paths add the original
+ // paths again.
+ if (this->FindRootPathMode == RootPathModeBoth) {
+ cm::append(paths, unrootedPaths);
+ }
+}
+
+void cmFindCommon::GetIgnoredPaths(std::vector<std::string>& ignore)
+{
+ // null-terminated list of paths.
+ static const char* paths[] = { "CMAKE_SYSTEM_IGNORE_PATH",
+ "CMAKE_IGNORE_PATH", nullptr };
+
+ // Construct the list of path roots with no trailing slashes.
+ for (const char** pathName = paths; *pathName; ++pathName) {
+ // Get the list of paths to ignore from the variable.
+ this->Makefile->GetDefExpandList(*pathName, ignore);
+ }
+
+ for (std::string& i : ignore) {
+ cmSystemTools::ConvertToUnixSlashes(i);
+ }
+}
+
+void cmFindCommon::GetIgnoredPaths(std::set<std::string>& ignore)
+{
+ std::vector<std::string> ignoreVec;
+ this->GetIgnoredPaths(ignoreVec);
+ ignore.insert(ignoreVec.begin(), ignoreVec.end());
+}
+
+bool cmFindCommon::CheckCommonArgument(std::string const& arg)
+{
+ if (arg == "NO_DEFAULT_PATH") {
+ this->NoDefaultPath = true;
+ } else if (arg == "NO_PACKAGE_ROOT_PATH") {
+ this->NoPackageRootPath = true;
+ } else if (arg == "NO_CMAKE_PATH") {
+ this->NoCMakePath = true;
+ } else if (arg == "NO_CMAKE_ENVIRONMENT_PATH") {
+ this->NoCMakeEnvironmentPath = true;
+ } else if (arg == "NO_SYSTEM_ENVIRONMENT_PATH") {
+ this->NoSystemEnvironmentPath = true;
+ } else if (arg == "NO_CMAKE_SYSTEM_PATH") {
+ this->NoCMakeSystemPath = true;
+ } else if (arg == "NO_CMAKE_FIND_ROOT_PATH") {
+ this->FindRootPathMode = RootPathModeNever;
+ } else if (arg == "ONLY_CMAKE_FIND_ROOT_PATH") {
+ this->FindRootPathMode = RootPathModeOnly;
+ } else if (arg == "CMAKE_FIND_ROOT_PATH_BOTH") {
+ this->FindRootPathMode = RootPathModeBoth;
+ } else {
+ // The argument is not one of the above.
+ return false;
+ }
+
+ // The argument is one of the above.
+ return true;
+}
+
+void cmFindCommon::AddPathSuffix(std::string const& arg)
+{
+ std::string suffix = arg;
+
+ // Strip leading and trailing slashes.
+ if (suffix.empty()) {
+ return;
+ }
+ if (suffix.front() == '/') {
+ suffix = suffix.substr(1);
+ }
+ if (suffix.empty()) {
+ return;
+ }
+ if (suffix.back() == '/') {
+ suffix = suffix.substr(0, suffix.size() - 1);
+ }
+ if (suffix.empty()) {
+ return;
+ }
+
+ // Store the suffix.
+ this->SearchPathSuffixes.push_back(std::move(suffix));
+}
+
+void AddTrailingSlash(std::string& s)
+{
+ if (!s.empty() && s.back() != '/') {
+ s += '/';
+ }
+}
+void cmFindCommon::ComputeFinalPaths()
+{
+ // Filter out ignored paths from the prefix list
+ std::set<std::string> ignored;
+ this->GetIgnoredPaths(ignored);
+
+ // Combine the separate path types, filtering out ignores
+ this->SearchPaths.clear();
+ std::vector<PathLabel>& allLabels = this->PathGroupLabelMap[PathGroup::All];
+ for (PathLabel const& l : allLabels) {
+ this->LabeledPaths[l].ExtractWithout(ignored, this->SearchPaths);
+ }
+
+ // Expand list of paths inside all search roots.
+ this->RerootPaths(this->SearchPaths);
+
+ // Add a trailing slash to all paths to aid the search process.
+ std::for_each(this->SearchPaths.begin(), this->SearchPaths.end(),
+ &AddTrailingSlash);
+}
diff --git a/Source/cmFindCommon.h b/Source/cmFindCommon.h
new file mode 100644
index 0000000..f84242e
--- /dev/null
+++ b/Source/cmFindCommon.h
@@ -0,0 +1,144 @@
+/* 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 <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmPathLabel.h"
+#include "cmSearchPath.h"
+
+class cmExecutionStatus;
+class cmMakefile;
+
+/** \class cmFindCommon
+ * \brief Base class for FIND_XXX implementations.
+ *
+ * cmFindCommon is a parent class for cmFindBase,
+ * cmFindProgramCommand, cmFindPathCommand, cmFindLibraryCommand,
+ * cmFindFileCommand, and cmFindPackageCommand.
+ */
+class cmFindCommon
+{
+public:
+ cmFindCommon(cmExecutionStatus& status);
+
+ void SetError(std::string const& e);
+
+ bool DebugModeEnabled() const { return this->DebugMode; }
+
+protected:
+ friend class cmSearchPath;
+ friend class cmFindBaseDebugState;
+
+ /** Used to define groups of path labels */
+ class PathGroup : public cmPathLabel
+ {
+ protected:
+ PathGroup();
+
+ public:
+ PathGroup(const std::string& label)
+ : cmPathLabel(label)
+ {
+ }
+ static PathGroup All;
+ };
+
+ /* Individual path types */
+ class PathLabel : public cmPathLabel
+ {
+ protected:
+ PathLabel();
+
+ public:
+ PathLabel(const std::string& label)
+ : cmPathLabel(label)
+ {
+ }
+ static PathLabel PackageRoot;
+ static PathLabel CMake;
+ static PathLabel CMakeEnvironment;
+ static PathLabel Hints;
+ static PathLabel SystemEnvironment;
+ static PathLabel CMakeSystem;
+ static PathLabel Guess;
+ };
+
+ enum RootPathMode
+ {
+ RootPathModeNever,
+ RootPathModeOnly,
+ RootPathModeBoth
+ };
+
+ /** Construct the various path groups and labels */
+ void InitializeSearchPathGroups();
+
+ /** Place a set of search paths under the search roots. */
+ void RerootPaths(std::vector<std::string>& paths);
+
+ /** Get ignored paths from CMAKE_[SYSTEM_]IGNORE_path variables. */
+ void GetIgnoredPaths(std::vector<std::string>& ignore);
+ void GetIgnoredPaths(std::set<std::string>& ignore);
+
+ /** Compute final search path list (reroot + trailing slash). */
+ void ComputeFinalPaths();
+
+ /** Compute the current default root path mode. */
+ void SelectDefaultRootPathMode();
+
+ /** Compute the current default bundle/framework search policy. */
+ void SelectDefaultMacMode();
+
+ /** Compute the current default search modes based on global variables. */
+ void SelectDefaultSearchModes();
+
+ /** The `InitialPass` functions of the child classes should set
+ this->DebugMode to the result of this. */
+ bool ComputeIfDebugModeWanted();
+
+ // Path arguments prior to path manipulation routines
+ std::vector<std::string> UserHintsArgs;
+ std::vector<std::string> UserGuessArgs;
+
+ std::string CMakePathName;
+ RootPathMode FindRootPathMode;
+
+ bool CheckCommonArgument(std::string const& arg);
+ void AddPathSuffix(std::string const& arg);
+
+ void DebugMessage(std::string const& msg) const;
+ bool DebugMode;
+ bool NoDefaultPath;
+ bool NoPackageRootPath;
+ bool NoCMakePath;
+ bool NoCMakeEnvironmentPath;
+ bool NoSystemEnvironmentPath;
+ bool NoCMakeSystemPath;
+
+ std::vector<std::string> SearchPathSuffixes;
+
+ std::map<PathGroup, std::vector<PathLabel>> PathGroupLabelMap;
+ std::vector<PathGroup> PathGroupOrder;
+ std::map<std::string, PathLabel> PathLabelStringMap;
+ std::map<PathLabel, cmSearchPath> LabeledPaths;
+
+ std::vector<std::string> SearchPaths;
+ std::set<std::string> SearchPathsEmitted;
+
+ bool SearchFrameworkFirst;
+ bool SearchFrameworkOnly;
+ bool SearchFrameworkLast;
+
+ bool SearchAppBundleFirst;
+ bool SearchAppBundleOnly;
+ bool SearchAppBundleLast;
+
+ cmMakefile* Makefile;
+ cmExecutionStatus& Status;
+};
diff --git a/Source/cmFindFileCommand.cxx b/Source/cmFindFileCommand.cxx
new file mode 100644
index 0000000..29a2bc4
--- /dev/null
+++ b/Source/cmFindFileCommand.cxx
@@ -0,0 +1,17 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFindFileCommand.h"
+
+class cmExecutionStatus;
+
+cmFindFileCommand::cmFindFileCommand(cmExecutionStatus& status)
+ : cmFindPathCommand(status)
+{
+ this->IncludeFileInPath = true;
+}
+
+bool cmFindFile(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return cmFindFileCommand(status).InitialPass(args);
+}
diff --git a/Source/cmFindFileCommand.h b/Source/cmFindFileCommand.h
new file mode 100644
index 0000000..368a7c9
--- /dev/null
+++ b/Source/cmFindFileCommand.h
@@ -0,0 +1,29 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmFindPathCommand.h"
+
+class cmExecutionStatus;
+
+/** \class cmFindFileCommand
+ * \brief Define a command to search for an executable program.
+ *
+ * cmFindFileCommand is used to define a CMake variable
+ * that specifies an executable program. The command searches
+ * in the current path (e.g., PATH environment variable) for
+ * an executable that matches one of the supplied names.
+ */
+class cmFindFileCommand : public cmFindPathCommand
+{
+public:
+ cmFindFileCommand(cmExecutionStatus& status);
+};
+
+bool cmFindFile(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx
new file mode 100644
index 0000000..d85ba8f
--- /dev/null
+++ b/Source/cmFindLibraryCommand.cxx
@@ -0,0 +1,567 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFindLibraryCommand.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <cstring>
+#include <set>
+#include <utility>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+class cmExecutionStatus;
+
+cmFindLibraryCommand::cmFindLibraryCommand(cmExecutionStatus& status)
+ : cmFindBase(status)
+{
+ this->EnvironmentPath = "LIB";
+ this->NamesPerDirAllowed = true;
+}
+
+// cmFindLibraryCommand
+bool cmFindLibraryCommand::InitialPass(std::vector<std::string> const& argsIn)
+{
+ this->DebugMode = this->ComputeIfDebugModeWanted();
+ this->VariableDocumentation = "Path to a library.";
+ this->CMakePathName = "LIBRARY";
+ if (!this->ParseArguments(argsIn)) {
+ return false;
+ }
+ if (this->AlreadyInCache) {
+ // If the user specifies the entry on the command line without a
+ // type we should add the type and docstring but keep the original
+ // value.
+ if (this->AlreadyInCacheWithoutMetaInfo) {
+ this->Makefile->AddCacheDefinition(this->VariableName, "",
+ this->VariableDocumentation.c_str(),
+ cmStateEnums::FILEPATH);
+ }
+ return true;
+ }
+
+ // add custom lib<qual> paths instead of using fixed lib32, lib64 or
+ // libx32
+ if (cmProp customLib = this->Makefile->GetDefinition(
+ "CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX")) {
+ this->AddArchitecturePaths(customLib->c_str());
+ }
+ // add special 32 bit paths if this is a 32 bit compile.
+ else if (this->Makefile->PlatformIs32Bit() &&
+ this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "FIND_LIBRARY_USE_LIB32_PATHS")) {
+ this->AddArchitecturePaths("32");
+ }
+ // add special 64 bit paths if this is a 64 bit compile.
+ else if (this->Makefile->PlatformIs64Bit() &&
+ this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "FIND_LIBRARY_USE_LIB64_PATHS")) {
+ this->AddArchitecturePaths("64");
+ }
+ // add special 32 bit paths if this is an x32 compile.
+ else if (this->Makefile->PlatformIsx32() &&
+ this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "FIND_LIBRARY_USE_LIBX32_PATHS")) {
+ this->AddArchitecturePaths("x32");
+ }
+
+ std::string const library = this->FindLibrary();
+ if (!library.empty()) {
+ // Save the value in the cache
+ this->Makefile->AddCacheDefinition(this->VariableName, library,
+ this->VariableDocumentation.c_str(),
+ cmStateEnums::FILEPATH);
+ return true;
+ }
+ std::string notfound = this->VariableName + "-NOTFOUND";
+ this->Makefile->AddCacheDefinition(this->VariableName, notfound,
+ this->VariableDocumentation.c_str(),
+ cmStateEnums::FILEPATH);
+ if (this->Required) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Could not find " + this->VariableName +
+ " using the following names: " + cmJoin(this->Names, ", "));
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ return true;
+}
+
+void cmFindLibraryCommand::AddArchitecturePaths(const char* suffix)
+{
+ std::vector<std::string> original;
+ original.swap(this->SearchPaths);
+ for (std::string const& o : original) {
+ this->AddArchitecturePath(o, 0, suffix);
+ if (this->DebugMode) {
+ std::string msg = cmStrCat(
+ "find_library(", this->VariableName, ") removed original suffix ", o,
+ " from PATH_SUFFIXES while adding architecture paths for suffix '",
+ suffix, "'");
+ this->DebugMessage(msg);
+ }
+ }
+}
+
+static bool cmLibDirsLinked(std::string const& l, std::string const& r)
+{
+ // Compare the real paths of the two directories.
+ // Since our caller only changed the trailing component of each
+ // directory, the real paths can be the same only if at least one of
+ // the trailing components is a symlink. Use this as an optimization
+ // to avoid excessive realpath calls.
+ return (cmSystemTools::FileIsSymlink(l) ||
+ cmSystemTools::FileIsSymlink(r)) &&
+ cmSystemTools::GetRealPath(l) == cmSystemTools::GetRealPath(r);
+}
+
+void cmFindLibraryCommand::AddArchitecturePath(
+ std::string const& dir, std::string::size_type start_pos, const char* suffix,
+ bool fresh)
+{
+ std::string::size_type pos = dir.find("lib/", start_pos);
+
+ if (pos != std::string::npos) {
+ // Check for "lib".
+ std::string lib = dir.substr(0, pos + 3);
+ bool use_lib = cmSystemTools::FileIsDirectory(lib);
+
+ // Check for "lib<suffix>" and use it first.
+ std::string libX = lib + suffix;
+ bool use_libX = cmSystemTools::FileIsDirectory(libX);
+
+ // Avoid copies of the same directory due to symlinks.
+ if (use_libX && use_lib && cmLibDirsLinked(libX, lib)) {
+ use_libX = false;
+ }
+
+ if (use_libX) {
+ libX += dir.substr(pos + 3);
+ std::string::size_type libX_pos = pos + 3 + strlen(suffix) + 1;
+ this->AddArchitecturePath(libX, libX_pos, suffix);
+ }
+
+ if (use_lib) {
+ this->AddArchitecturePath(dir, pos + 3 + 1, suffix, false);
+ }
+ }
+
+ if (fresh) {
+ // Check for the original unchanged path.
+ bool use_dir = cmSystemTools::FileIsDirectory(dir);
+
+ // Check for <dir><suffix>/ and use it first.
+ std::string dirX = dir + suffix;
+ bool use_dirX = cmSystemTools::FileIsDirectory(dirX);
+
+ // Avoid copies of the same directory due to symlinks.
+ if (use_dirX && use_dir && cmLibDirsLinked(dirX, dir)) {
+ use_dirX = false;
+ }
+
+ if (use_dirX) {
+ dirX += "/";
+ if (this->DebugMode) {
+ std::string msg = cmStrCat(
+ "find_library(", this->VariableName, ") added replacement path ",
+ dirX, " to PATH_SUFFIXES for architecture suffix '", suffix, "'");
+ this->DebugMessage(msg);
+ }
+ this->SearchPaths.push_back(std::move(dirX));
+ }
+
+ if (use_dir) {
+ this->SearchPaths.push_back(dir);
+ if (this->DebugMode) {
+ std::string msg = cmStrCat(
+ "find_library(", this->VariableName, ") added replacement path ",
+ dir, " to PATH_SUFFIXES for architecture suffix '", suffix, "'");
+ this->DebugMessage(msg);
+ }
+ }
+ }
+}
+
+std::string cmFindLibraryCommand::FindLibrary()
+{
+ std::string library;
+ if (this->SearchFrameworkFirst || this->SearchFrameworkOnly) {
+ library = this->FindFrameworkLibrary();
+ }
+ if (library.empty() && !this->SearchFrameworkOnly) {
+ library = this->FindNormalLibrary();
+ }
+ if (library.empty() && this->SearchFrameworkLast) {
+ library = this->FindFrameworkLibrary();
+ }
+ return library;
+}
+
+struct cmFindLibraryHelper
+{
+ cmFindLibraryHelper(cmMakefile* mf, cmFindBase const* findBase);
+
+ // Context information.
+ cmMakefile* Makefile;
+ cmGlobalGenerator* GG;
+
+ // List of valid prefixes and suffixes.
+ std::vector<std::string> Prefixes;
+ std::vector<std::string> Suffixes;
+ std::string PrefixRegexStr;
+ std::string SuffixRegexStr;
+
+ // Keep track of the best library file found so far.
+ using size_type = std::vector<std::string>::size_type;
+ std::string BestPath;
+
+ // Support for OpenBSD shared library naming: lib<name>.so.<major>.<minor>
+ bool OpenBSD;
+
+ bool DebugMode;
+
+ // Current names under consideration.
+ struct Name
+ {
+ bool TryRaw = false;
+ std::string Raw;
+ cmsys::RegularExpression Regex;
+ };
+ std::vector<Name> Names;
+
+ // Current full path under consideration.
+ std::string TestPath;
+
+ void RegexFromLiteral(std::string& out, std::string const& in);
+ void RegexFromList(std::string& out, std::vector<std::string> const& in);
+ size_type GetPrefixIndex(std::string const& prefix)
+ {
+ return std::find(this->Prefixes.begin(), this->Prefixes.end(), prefix) -
+ this->Prefixes.begin();
+ }
+ size_type GetSuffixIndex(std::string const& suffix)
+ {
+ return std::find(this->Suffixes.begin(), this->Suffixes.end(), suffix) -
+ this->Suffixes.begin();
+ }
+ bool HasValidSuffix(std::string const& name);
+ void AddName(std::string const& name);
+ void SetName(std::string const& name);
+ bool CheckDirectory(std::string const& path);
+ bool CheckDirectoryForName(std::string const& path, Name& name);
+
+ cmFindBaseDebugState DebugSearches;
+
+ void DebugLibraryFailed(std::string const& name, std::string const& path)
+ {
+ if (this->DebugMode) {
+ auto regexName =
+ cmStrCat(this->PrefixRegexStr, name, this->SuffixRegexStr);
+ this->DebugSearches.FailedAt(path, regexName);
+ }
+ };
+
+ void DebugLibraryFound(std::string const& name, std::string const& path)
+ {
+ if (this->DebugMode) {
+ auto regexName =
+ cmStrCat(this->PrefixRegexStr, name, this->SuffixRegexStr);
+ this->DebugSearches.FoundAt(path, regexName);
+ }
+ };
+};
+
+cmFindLibraryHelper::cmFindLibraryHelper(cmMakefile* mf,
+ cmFindBase const* base)
+ : Makefile(mf)
+ , DebugMode(base->DebugModeEnabled())
+ , DebugSearches("find_library", base)
+{
+ this->GG = this->Makefile->GetGlobalGenerator();
+
+ // Collect the list of library name prefixes/suffixes to try.
+ std::string const& prefixes_list =
+ this->Makefile->GetRequiredDefinition("CMAKE_FIND_LIBRARY_PREFIXES");
+ std::string const& suffixes_list =
+ this->Makefile->GetRequiredDefinition("CMAKE_FIND_LIBRARY_SUFFIXES");
+ cmExpandList(prefixes_list, this->Prefixes, true);
+ cmExpandList(suffixes_list, this->Suffixes, true);
+ this->RegexFromList(this->PrefixRegexStr, this->Prefixes);
+ this->RegexFromList(this->SuffixRegexStr, this->Suffixes);
+
+ // Check whether to use OpenBSD-style library version comparisons.
+ this->OpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "FIND_LIBRARY_USE_OPENBSD_VERSIONING");
+}
+
+void cmFindLibraryHelper::RegexFromLiteral(std::string& out,
+ std::string const& in)
+{
+ for (char ch : in) {
+ if (ch == '[' || ch == ']' || ch == '(' || ch == ')' || ch == '\\' ||
+ ch == '.' || ch == '*' || ch == '+' || ch == '?' || ch == '-' ||
+ ch == '^' || ch == '$') {
+ out += "\\";
+ }
+#if defined(_WIN32) || defined(__APPLE__)
+ out += static_cast<char>(tolower(ch));
+#else
+ out += ch;
+#endif
+ }
+}
+
+void cmFindLibraryHelper::RegexFromList(std::string& out,
+ std::vector<std::string> const& in)
+{
+ // Surround the list in parens so the '|' does not apply to anything
+ // else and the result can be checked after matching.
+ out += "(";
+ const char* sep = "";
+ for (std::string const& s : in) {
+ // Separate from previous item.
+ out += sep;
+ sep = "|";
+
+ // Append this item.
+ this->RegexFromLiteral(out, s);
+ }
+ out += ")";
+}
+
+bool cmFindLibraryHelper::HasValidSuffix(std::string const& name)
+{
+ for (std::string suffix : this->Suffixes) {
+ if (name.length() <= suffix.length()) {
+ continue;
+ }
+ // Check if the given name ends in a valid library suffix.
+ if (name.substr(name.size() - suffix.length()) == suffix) {
+ return true;
+ }
+ // Check if a valid library suffix is somewhere in the name,
+ // this may happen e.g. for versioned shared libraries: libfoo.so.2
+ suffix += ".";
+ if (name.find(suffix) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void cmFindLibraryHelper::AddName(std::string const& name)
+{
+ Name entry;
+
+ // Consider checking the raw name too.
+ entry.TryRaw = this->HasValidSuffix(name);
+ entry.Raw = name;
+
+ // Build a regular expression to match library names.
+ std::string regex = cmStrCat('^', this->PrefixRegexStr);
+ this->RegexFromLiteral(regex, name);
+ regex += this->SuffixRegexStr;
+ if (this->OpenBSD) {
+ regex += "(\\.[0-9]+\\.[0-9]+)?";
+ }
+ regex += "$";
+ entry.Regex.compile(regex);
+ this->Names.push_back(std::move(entry));
+}
+
+void cmFindLibraryHelper::SetName(std::string const& name)
+{
+ this->Names.clear();
+ this->AddName(name);
+}
+
+bool cmFindLibraryHelper::CheckDirectory(std::string const& path)
+{
+ for (Name& i : this->Names) {
+ if (this->CheckDirectoryForName(path, i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmFindLibraryHelper::CheckDirectoryForName(std::string const& path,
+ Name& name)
+{
+ // If the original library name provided by the user matches one of
+ // the suffixes, try it first. This allows users to search
+ // specifically for a static library on some platforms (on MS tools
+ // one cannot tell just from the library name whether it is a static
+ // library or an import library).
+ if (name.TryRaw) {
+ this->TestPath = cmStrCat(path, name.Raw);
+
+ const bool exists = cmSystemTools::FileExists(this->TestPath, true);
+ if (!exists) {
+ this->DebugLibraryFailed(name.Raw, path);
+ } else {
+ this->DebugLibraryFound(name.Raw, path);
+ this->BestPath = cmSystemTools::CollapseFullPath(this->TestPath);
+ cmSystemTools::ConvertToUnixSlashes(this->BestPath);
+ return true;
+ }
+ }
+
+ // No library file has yet been found.
+ size_type bestPrefix = this->Prefixes.size();
+ size_type bestSuffix = this->Suffixes.size();
+ unsigned int bestMajor = 0;
+ unsigned int bestMinor = 0;
+
+ // Search for a file matching the library name regex.
+ std::string dir = path;
+ cmSystemTools::ConvertToUnixSlashes(dir);
+ std::set<std::string> const& files = this->GG->GetDirectoryContent(dir);
+ for (std::string const& origName : files) {
+#if defined(_WIN32) || defined(__APPLE__)
+ std::string testName = cmSystemTools::LowerCase(origName);
+#else
+ std::string const& testName = origName;
+#endif
+ if (name.Regex.find(testName)) {
+ this->TestPath = cmStrCat(path, origName);
+ // Make sure the path is readable and is not a directory.
+ if (cmSystemTools::FileExists(this->TestPath, true)) {
+ this->DebugLibraryFound(name.Raw, dir);
+
+ // This is a matching file. Check if it is better than the
+ // best name found so far. Earlier prefixes are preferred,
+ // followed by earlier suffixes. For OpenBSD, shared library
+ // version extensions are compared.
+ size_type prefix = this->GetPrefixIndex(name.Regex.match(1));
+ size_type suffix = this->GetSuffixIndex(name.Regex.match(2));
+ unsigned int major = 0;
+ unsigned int minor = 0;
+ if (this->OpenBSD) {
+ sscanf(name.Regex.match(3).c_str(), ".%u.%u", &major, &minor);
+ }
+ if (this->BestPath.empty() || prefix < bestPrefix ||
+ (prefix == bestPrefix && suffix < bestSuffix) ||
+ (prefix == bestPrefix && suffix == bestSuffix &&
+ (major > bestMajor ||
+ (major == bestMajor && minor > bestMinor)))) {
+ this->BestPath = this->TestPath;
+ bestPrefix = prefix;
+ bestSuffix = suffix;
+ bestMajor = major;
+ bestMinor = minor;
+ }
+ }
+ }
+ }
+
+ if (this->BestPath.empty()) {
+ this->DebugLibraryFailed(name.Raw, dir);
+ } else {
+ this->DebugLibraryFound(name.Raw, this->BestPath);
+ }
+
+ // Use the best candidate found in this directory, if any.
+ return !this->BestPath.empty();
+}
+
+std::string cmFindLibraryCommand::FindNormalLibrary()
+{
+ if (this->NamesPerDir) {
+ return this->FindNormalLibraryNamesPerDir();
+ }
+ return this->FindNormalLibraryDirsPerName();
+}
+
+std::string cmFindLibraryCommand::FindNormalLibraryNamesPerDir()
+{
+ // Search for all names in each directory.
+ cmFindLibraryHelper helper(this->Makefile, this);
+ for (std::string const& n : this->Names) {
+ helper.AddName(n);
+ }
+ // Search every directory.
+ for (std::string const& sp : this->SearchPaths) {
+ if (helper.CheckDirectory(sp)) {
+ return helper.BestPath;
+ }
+ }
+ // Couldn't find the library.
+ return "";
+}
+
+std::string cmFindLibraryCommand::FindNormalLibraryDirsPerName()
+{
+ // Search the entire path for each name.
+ cmFindLibraryHelper helper(this->Makefile, this);
+ for (std::string const& n : this->Names) {
+ // Switch to searching for this name.
+ helper.SetName(n);
+
+ // Search every directory.
+ for (std::string const& sp : this->SearchPaths) {
+ if (helper.CheckDirectory(sp)) {
+ return helper.BestPath;
+ }
+ }
+ }
+ // Couldn't find the library.
+ return "";
+}
+
+std::string cmFindLibraryCommand::FindFrameworkLibrary()
+{
+ if (this->NamesPerDir) {
+ return this->FindFrameworkLibraryNamesPerDir();
+ }
+ return this->FindFrameworkLibraryDirsPerName();
+}
+
+std::string cmFindLibraryCommand::FindFrameworkLibraryNamesPerDir()
+{
+ std::string fwPath;
+ // Search for all names in each search path.
+ for (std::string const& d : this->SearchPaths) {
+ for (std::string const& n : this->Names) {
+ fwPath = cmStrCat(d, n, ".framework");
+ if (cmSystemTools::FileIsDirectory(fwPath)) {
+ return cmSystemTools::CollapseFullPath(fwPath);
+ }
+ }
+ }
+
+ // No framework found.
+ return "";
+}
+
+std::string cmFindLibraryCommand::FindFrameworkLibraryDirsPerName()
+{
+ std::string fwPath;
+ // Search for each name in all search paths.
+ for (std::string const& n : this->Names) {
+ for (std::string const& d : this->SearchPaths) {
+ fwPath = cmStrCat(d, n, ".framework");
+ if (cmSystemTools::FileIsDirectory(fwPath)) {
+ return cmSystemTools::CollapseFullPath(fwPath);
+ }
+ }
+ }
+
+ // No framework found.
+ return "";
+}
+
+bool cmFindLibrary(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return cmFindLibraryCommand(status).InitialPass(args);
+}
diff --git a/Source/cmFindLibraryCommand.h b/Source/cmFindLibraryCommand.h
new file mode 100644
index 0000000..f3874ff
--- /dev/null
+++ b/Source/cmFindLibraryCommand.h
@@ -0,0 +1,45 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmFindBase.h"
+
+class cmExecutionStatus;
+
+/** \class cmFindLibraryCommand
+ * \brief Define a command to search for a library.
+ *
+ * cmFindLibraryCommand is used to define a CMake variable
+ * that specifies a library. The command searches for a given
+ * file in a list of directories.
+ */
+class cmFindLibraryCommand : public cmFindBase
+{
+public:
+ cmFindLibraryCommand(cmExecutionStatus& status);
+
+ bool InitialPass(std::vector<std::string> const& args);
+
+protected:
+ void AddArchitecturePaths(const char* suffix);
+ void AddArchitecturePath(std::string const& dir,
+ std::string::size_type start_pos,
+ const char* suffix, bool fresh = true);
+ std::string FindLibrary();
+
+private:
+ std::string FindNormalLibrary();
+ std::string FindNormalLibraryNamesPerDir();
+ std::string FindNormalLibraryDirsPerName();
+ std::string FindFrameworkLibrary();
+ std::string FindFrameworkLibraryNamesPerDir();
+ std::string FindFrameworkLibraryDirsPerName();
+};
+
+bool cmFindLibrary(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
new file mode 100644
index 0000000..3719fe1
--- /dev/null
+++ b/Source/cmFindPackageCommand.cxx
@@ -0,0 +1,2500 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFindPackageCommand.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+#include <deque>
+#include <functional>
+#include <iterator>
+#include <sstream>
+#include <utility>
+
+#include <cm/memory>
+#include <cmext/string_view>
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+#include "cmsys/RegularExpression.hxx"
+#include "cmsys/String.h"
+
+#include "cmAlgorithms.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmSearchPath.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+
+#if defined(__HAIKU__)
+# include <FindDirectory.h>
+# include <StorageDefs.h>
+#endif
+
+class cmExecutionStatus;
+class cmFileList;
+
+cmFindPackageCommand::PathLabel cmFindPackageCommand::PathLabel::UserRegistry(
+ "PACKAGE_REGISTRY");
+cmFindPackageCommand::PathLabel cmFindPackageCommand::PathLabel::Builds(
+ "BUILDS");
+cmFindPackageCommand::PathLabel
+ cmFindPackageCommand::PathLabel::SystemRegistry("SYSTEM_PACKAGE_REGISTRY");
+
+const cm::string_view cmFindPackageCommand::VERSION_ENDPOINT_INCLUDED(
+ "INCLUDE");
+const cm::string_view cmFindPackageCommand::VERSION_ENDPOINT_EXCLUDED(
+ "EXCLUDE");
+
+struct StrverscmpGreater
+{
+ bool operator()(const std::string& lhs, const std::string& rhs) const
+ {
+ return cmSystemTools::strverscmp(lhs, rhs) > 0;
+ }
+};
+
+struct StrverscmpLesser
+{
+ bool operator()(const std::string& lhs, const std::string& rhs) const
+ {
+ return cmSystemTools::strverscmp(lhs, rhs) < 0;
+ }
+};
+
+void cmFindPackageCommand::Sort(std::vector<std::string>::iterator begin,
+ std::vector<std::string>::iterator end,
+ SortOrderType order, SortDirectionType dir)
+{
+ if (order == Name_order) {
+ if (dir == Dec) {
+ std::sort(begin, end, std::greater<std::string>());
+ } else {
+ std::sort(begin, end);
+ }
+ } else if (order == Natural)
+ // natural order uses letters and numbers (contiguous numbers digit are
+ // compared such that e.g. 000 00 < 01 < 010 < 09 < 0 < 1 < 9 < 10
+ {
+ if (dir == Dec) {
+ std::sort(begin, end, StrverscmpGreater());
+ } else {
+ std::sort(begin, end, StrverscmpLesser());
+ }
+ }
+ // else do not sort
+}
+
+cmFindPackageCommand::cmFindPackageCommand(cmExecutionStatus& status)
+ : cmFindCommon(status)
+ , VersionRangeMin(VERSION_ENDPOINT_INCLUDED)
+ , VersionRangeMax(VERSION_ENDPOINT_INCLUDED)
+{
+ this->CMakePathName = "PACKAGE";
+ this->DebugMode = false;
+ this->AppendSearchPathGroups();
+
+ this->DeprecatedFindModules["Qt"] = cmPolicies::CMP0084;
+}
+
+void cmFindPackageCommand::AppendSearchPathGroups()
+{
+ std::vector<cmFindCommon::PathLabel>* labels;
+
+ // Update the All group with new paths
+ labels = &this->PathGroupLabelMap[PathGroup::All];
+ labels->insert(
+ std::find(labels->begin(), labels->end(), PathLabel::CMakeSystem),
+ PathLabel::UserRegistry);
+ labels->insert(
+ std::find(labels->begin(), labels->end(), PathLabel::CMakeSystem),
+ PathLabel::Builds);
+ labels->insert(std::find(labels->begin(), labels->end(), PathLabel::Guess),
+ PathLabel::SystemRegistry);
+
+ // Create the new path objects
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::UserRegistry, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::Builds, cmSearchPath(this)));
+ this->LabeledPaths.insert(
+ std::make_pair(PathLabel::SystemRegistry, cmSearchPath(this)));
+}
+
+bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
+{
+ if (args.empty()) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Lookup required version of CMake.
+ if (cmProp rv =
+ this->Makefile->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
+ unsigned int v[3] = { 0, 0, 0 };
+ sscanf(rv->c_str(), "%u.%u.%u", &v[0], &v[1], &v[2]);
+ this->RequiredCMakeVersion = CMake_VERSION_ENCODE(v[0], v[1], v[2]);
+ }
+
+ this->DebugMode = this->ComputeIfDebugModeWanted();
+ this->DebugBuffer.clear();
+
+ // Lookup target architecture, if any.
+ if (cmProp arch =
+ this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE")) {
+ this->LibraryArchitecture = *arch;
+ }
+
+ // Lookup whether lib32 paths should be used.
+ if (this->Makefile->PlatformIs32Bit() &&
+ this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "FIND_LIBRARY_USE_LIB32_PATHS")) {
+ this->UseLib32Paths = true;
+ }
+
+ // Lookup whether lib64 paths should be used.
+ if (this->Makefile->PlatformIs64Bit() &&
+ this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "FIND_LIBRARY_USE_LIB64_PATHS")) {
+ this->UseLib64Paths = true;
+ }
+
+ // Lookup whether libx32 paths should be used.
+ if (this->Makefile->PlatformIsx32() &&
+ this->Makefile->GetState()->GetGlobalPropertyAsBool(
+ "FIND_LIBRARY_USE_LIBX32_PATHS")) {
+ this->UseLibx32Paths = true;
+ }
+
+ // Check if User Package Registry should be disabled
+ // The `CMAKE_FIND_USE_PACKAGE_REGISTRY` has
+ // priority over the deprecated CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY
+ if (cmProp def =
+ this->Makefile->GetDefinition("CMAKE_FIND_USE_PACKAGE_REGISTRY")) {
+ this->NoUserRegistry = !cmIsOn(*def);
+ } else if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY")) {
+ this->NoUserRegistry = true;
+ }
+
+ // Check if System Package Registry should be disabled
+ // The `CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY` has
+ // priority over the deprecated CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY
+ if (cmProp def = this->Makefile->GetDefinition(
+ "CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY")) {
+ this->NoSystemRegistry = !cmIsOn(*def);
+ } else if (this->Makefile->IsOn(
+ "CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY")) {
+ this->NoSystemRegistry = true;
+ }
+
+ // Check whether we should resolve symlinks when finding packages
+ if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS")) {
+ this->UseRealPath = true;
+ }
+
+ // Check if Sorting should be enabled
+ if (cmProp so =
+ this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_SORT_ORDER")) {
+
+ if (*so == "NAME") {
+ this->SortOrder = Name_order;
+ } else if (*so == "NATURAL") {
+ this->SortOrder = Natural;
+ } else {
+ this->SortOrder = None;
+ }
+ }
+ if (cmProp sd =
+ this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_SORT_DIRECTION")) {
+ this->SortDirection = (*sd == "ASC") ? Asc : Dec;
+ }
+
+ // Find what search path locations have been enabled/disable
+ this->SelectDefaultSearchModes();
+
+ // Find the current root path mode.
+ this->SelectDefaultRootPathMode();
+
+ // Find the current bundle/framework search policy.
+ this->SelectDefaultMacMode();
+
+ // Record options.
+ this->Name = args[0];
+ std::string components;
+ const char* components_sep = "";
+ std::set<std::string> requiredComponents;
+ std::set<std::string> optionalComponents;
+
+ // Always search directly in a generated path.
+ this->SearchPathSuffixes.emplace_back();
+
+ // Parse the arguments.
+ enum Doing
+ {
+ DoingNone,
+ DoingComponents,
+ DoingOptionalComponents,
+ DoingNames,
+ DoingPaths,
+ DoingPathSuffixes,
+ DoingConfigs,
+ DoingHints
+ };
+ Doing doing = DoingNone;
+ cmsys::RegularExpression versionRegex(
+ R"V(^([0-9]+(\.[0-9]+)*)(\.\.\.(<?)([0-9]+(\.[0-9]+)*))?$)V");
+ bool haveVersion = false;
+ std::set<unsigned int> configArgs;
+ std::set<unsigned int> moduleArgs;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "QUIET") {
+ this->Quiet = true;
+ doing = DoingNone;
+ } else if (args[i] == "EXACT") {
+ this->VersionExact = true;
+ doing = DoingNone;
+ } else if (args[i] == "MODULE") {
+ moduleArgs.insert(i);
+ doing = DoingNone;
+ // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
+ // NOLINTNEXTLINE(bugprone-branch-clone)
+ } else if (args[i] == "CONFIG") {
+ configArgs.insert(i);
+ doing = DoingNone;
+ // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
+ // NOLINTNEXTLINE(bugprone-branch-clone)
+ } else if (args[i] == "NO_MODULE") {
+ configArgs.insert(i);
+ doing = DoingNone;
+ } else if (args[i] == "REQUIRED") {
+ this->Required = true;
+ doing = DoingComponents;
+ } else if (args[i] == "COMPONENTS") {
+ doing = DoingComponents;
+ } else if (args[i] == "OPTIONAL_COMPONENTS") {
+ doing = DoingOptionalComponents;
+ } else if (args[i] == "NAMES") {
+ configArgs.insert(i);
+ doing = DoingNames;
+ } else if (args[i] == "PATHS") {
+ configArgs.insert(i);
+ doing = DoingPaths;
+ } else if (args[i] == "HINTS") {
+ configArgs.insert(i);
+ doing = DoingHints;
+ } else if (args[i] == "PATH_SUFFIXES") {
+ configArgs.insert(i);
+ doing = DoingPathSuffixes;
+ } else if (args[i] == "CONFIGS") {
+ configArgs.insert(i);
+ doing = DoingConfigs;
+ } else if (args[i] == "NO_POLICY_SCOPE") {
+ this->PolicyScope = false;
+ doing = DoingNone;
+ } else if (args[i] == "NO_CMAKE_PACKAGE_REGISTRY") {
+ this->NoUserRegistry = true;
+ configArgs.insert(i);
+ doing = DoingNone;
+ } else if (args[i] == "NO_CMAKE_SYSTEM_PACKAGE_REGISTRY") {
+ this->NoSystemRegistry = true;
+ configArgs.insert(i);
+ doing = DoingNone;
+ // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
+ // NOLINTNEXTLINE(bugprone-branch-clone)
+ } else if (args[i] == "NO_CMAKE_BUILDS_PATH") {
+ // Ignore legacy option.
+ configArgs.insert(i);
+ doing = DoingNone;
+ } else if (this->CheckCommonArgument(args[i])) {
+ configArgs.insert(i);
+ doing = DoingNone;
+ } else if ((doing == DoingComponents) ||
+ (doing == DoingOptionalComponents)) {
+ // Set a variable telling the find script whether this component
+ // is required.
+ const char* isRequired = "1";
+ if (doing == DoingOptionalComponents) {
+ isRequired = "0";
+ optionalComponents.insert(args[i]);
+ } else {
+ requiredComponents.insert(args[i]);
+ }
+
+ std::string req_var = this->Name + "_FIND_REQUIRED_" + args[i];
+ this->AddFindDefinition(req_var, isRequired);
+
+ // Append to the list of required components.
+ components += components_sep;
+ components += args[i];
+ components_sep = ";";
+ } else if (doing == DoingNames) {
+ this->Names.push_back(args[i]);
+ } else if (doing == DoingPaths) {
+ this->UserGuessArgs.push_back(args[i]);
+ } else if (doing == DoingHints) {
+ this->UserHintsArgs.push_back(args[i]);
+ } else if (doing == DoingPathSuffixes) {
+ this->AddPathSuffix(args[i]);
+ } else if (doing == DoingConfigs) {
+ if (args[i].find_first_of(":/\\") != std::string::npos ||
+ cmSystemTools::GetFilenameLastExtension(args[i]) != ".cmake") {
+ this->SetError(cmStrCat(
+ "given CONFIGS option followed by invalid file name \"", args[i],
+ "\". The names given must be file names without "
+ "a path and with a \".cmake\" extension."));
+ return false;
+ }
+ this->Configs.push_back(args[i]);
+ } else if (!haveVersion && versionRegex.find(args[i])) {
+ haveVersion = true;
+ this->VersionComplete = args[i];
+ } else {
+ this->SetError(
+ cmStrCat("called with invalid argument \"", args[i], "\""));
+ return false;
+ }
+ }
+
+ std::vector<std::string> doubledComponents;
+ std::set_intersection(requiredComponents.begin(), requiredComponents.end(),
+ optionalComponents.begin(), optionalComponents.end(),
+ std::back_inserter(doubledComponents));
+ if (!doubledComponents.empty()) {
+ this->SetError(
+ cmStrCat("called with components that are both required and "
+ "optional:\n",
+ cmWrap(" ", doubledComponents, "", "\n"), "\n"));
+ return false;
+ }
+
+ // Maybe choose one mode exclusively.
+ this->UseFindModules = configArgs.empty();
+ this->UseConfigFiles = moduleArgs.empty();
+ if (!this->UseFindModules && !this->UseConfigFiles) {
+ std::ostringstream e;
+ e << "given options exclusive to Module mode:\n";
+ for (unsigned int si : moduleArgs) {
+ e << " " << args[si] << "\n";
+ }
+ e << "and options exclusive to Config mode:\n";
+ for (unsigned int si : configArgs) {
+ e << " " << args[si] << "\n";
+ }
+ e << "The options are incompatible.";
+ this->SetError(e.str());
+ return false;
+ }
+
+ // Ignore EXACT with no version.
+ if (this->VersionComplete.empty() && this->VersionExact) {
+ this->VersionExact = false;
+ this->Makefile->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ "Ignoring EXACT since no version is requested.");
+ }
+
+ if (this->VersionComplete.empty() || components.empty()) {
+ // Check whether we are recursing inside "Find<name>.cmake" within
+ // another find_package(<name>) call.
+ std::string mod = cmStrCat(this->Name, "_FIND_MODULE");
+ if (this->Makefile->IsOn(mod)) {
+ if (this->VersionComplete.empty()) {
+ // Get version information from the outer call if necessary.
+ // Requested version string.
+ std::string ver = cmStrCat(this->Name, "_FIND_VERSION_COMPLETE");
+ this->VersionComplete = this->Makefile->GetSafeDefinition(ver);
+
+ // Whether an exact version is required.
+ std::string exact = cmStrCat(this->Name, "_FIND_VERSION_EXACT");
+ this->VersionExact = this->Makefile->IsOn(exact);
+ }
+ if (components.empty()) {
+ std::string components_var = this->Name + "_FIND_COMPONENTS";
+ components = this->Makefile->GetSafeDefinition(components_var);
+ }
+ }
+ }
+
+ // fill various parts of version specification
+ if (!this->VersionComplete.empty()) {
+ if (!versionRegex.find(this->VersionComplete)) {
+ this->SetError("called with invalid version specification.");
+ return false;
+ }
+
+ this->Version = versionRegex.match(1);
+ this->VersionMax = versionRegex.match(5);
+ if (versionRegex.match(4) == "<"_s) {
+ this->VersionRangeMax = VERSION_ENDPOINT_EXCLUDED;
+ }
+ if (!this->VersionMax.empty()) {
+ this->VersionRange = this->VersionComplete;
+ }
+ }
+
+ 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;
+ }
+
+ // Parse the version number and store the results that were
+ // successfully parsed.
+ auto parseVersion = [](const std::string& version, unsigned int& major,
+ unsigned int& minor, unsigned int& patch,
+ unsigned int& tweak) -> unsigned int {
+ return sscanf(version.c_str(), "%u.%u.%u.%u", &major, &minor, &patch,
+ &tweak);
+ };
+
+ if (!this->Version.empty()) {
+ this->VersionCount =
+ parseVersion(this->Version, this->VersionMajor, this->VersionMinor,
+ this->VersionPatch, this->VersionTweak);
+ }
+ if (!this->VersionMax.empty()) {
+ this->VersionMaxCount = parseVersion(
+ this->VersionMax, this->VersionMaxMajor, this->VersionMaxMinor,
+ this->VersionMaxPatch, this->VersionMaxTweak);
+ }
+
+ std::string disableFindPackageVar =
+ cmStrCat("CMAKE_DISABLE_FIND_PACKAGE_", this->Name);
+ if (this->Makefile->IsOn(disableFindPackageVar)) {
+ if (this->Required) {
+ this->SetError(
+ cmStrCat("for module ", this->Name, " called with REQUIRED, but ",
+ disableFindPackageVar,
+ " is enabled. A REQUIRED package cannot be disabled."));
+ return false;
+ }
+
+ return true;
+ }
+
+ {
+ // Allocate a PACKAGE_ROOT_PATH for the current find_package call.
+ this->Makefile->FindPackageRootPathStack.emplace_back();
+ std::vector<std::string>& rootPaths =
+ this->Makefile->FindPackageRootPathStack.back();
+
+ // Add root paths from <PackageName>_ROOT CMake and environment variables,
+ // subject to CMP0074.
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0074)) {
+ case cmPolicies::WARN:
+ this->Makefile->MaybeWarnCMP0074(this->Name);
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior is to ignore the <pkg>_ROOT variables.
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0074));
+ break;
+ case cmPolicies::NEW: {
+ // NEW behavior is to honor the <pkg>_ROOT variables.
+ std::string const rootVar = this->Name + "_ROOT";
+ this->Makefile->GetDefExpandList(rootVar, rootPaths, false);
+ cmSystemTools::GetPath(rootPaths, rootVar.c_str());
+ } break;
+ }
+ }
+
+ this->SetModuleVariables(components);
+
+ // See if there is a Find<PackageName>.cmake module.
+ bool loadedPackage = false;
+ if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_PREFER_CONFIG")) {
+ if (this->UseConfigFiles && this->FindPackageUsingConfigMode()) {
+ loadedPackage = true;
+ } else {
+ if (this->FindPackageUsingModuleMode()) {
+ loadedPackage = true;
+ } else {
+ // The package was not loaded. Report errors.
+ if (this->HandlePackageMode(HandlePackageModeType::Module)) {
+ loadedPackage = true;
+ }
+ }
+ }
+ } else {
+ if (this->UseFindModules && this->FindPackageUsingModuleMode()) {
+ loadedPackage = true;
+ } else {
+ // Handle CMAKE_FIND_PACKAGE_WARN_NO_MODULE (warn when CONFIG mode is
+ // implicitly assumed)
+ if (this->UseFindModules && this->UseConfigFiles &&
+ this->Makefile->IsOn("CMAKE_FIND_PACKAGE_WARN_NO_MODULE")) {
+ std::ostringstream aw;
+ if (this->RequiredCMakeVersion >= CMake_VERSION_ENCODE(2, 8, 8)) {
+ aw << "find_package called without either MODULE or CONFIG option "
+ "and "
+ "no Find"
+ << this->Name
+ << ".cmake module is in CMAKE_MODULE_PATH. "
+ "Add MODULE to exclusively request Module mode and fail if "
+ "Find"
+ << this->Name
+ << ".cmake is missing. "
+ "Add CONFIG to exclusively request Config mode and search for "
+ "a "
+ "package configuration file provided by "
+ << this->Name << " (" << this->Name << "Config.cmake or "
+ << cmSystemTools::LowerCase(this->Name) << "-config.cmake). ";
+ } else {
+ aw << "find_package called without NO_MODULE option and no "
+ "Find"
+ << this->Name
+ << ".cmake module is in CMAKE_MODULE_PATH. "
+ "Add NO_MODULE to exclusively request Config mode and search "
+ "for a "
+ "package configuration file provided by "
+ << this->Name << " (" << this->Name << "Config.cmake or "
+ << cmSystemTools::LowerCase(this->Name)
+ << "-config.cmake). "
+ "Otherwise make Find"
+ << this->Name
+ << ".cmake available in "
+ "CMAKE_MODULE_PATH.";
+ }
+ aw << "\n"
+ "(Variable CMAKE_FIND_PACKAGE_WARN_NO_MODULE enabled this "
+ "warning.)";
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, aw.str());
+ }
+
+ if (this->FindPackageUsingConfigMode()) {
+ loadedPackage = true;
+ }
+ }
+
+ if (this->DebugMode) {
+ this->DebugMessage(this->DebugBuffer);
+ this->DebugBuffer.clear();
+ }
+ }
+
+ this->AppendSuccessInformation();
+
+ return loadedPackage;
+}
+
+bool cmFindPackageCommand::FindPackageUsingModuleMode()
+{
+ bool foundModule = false;
+ if (!this->FindModule(foundModule)) {
+ return false;
+ }
+ return foundModule;
+}
+
+bool cmFindPackageCommand::FindPackageUsingConfigMode()
+{
+ this->Variable = cmStrCat(this->Name, "_DIR");
+
+ // Add the default name.
+ if (this->Names.empty()) {
+ this->Names.push_back(this->Name);
+ }
+
+ // Add the default configs.
+ if (this->Configs.empty()) {
+ for (std::string const& n : this->Names) {
+ std::string config = cmStrCat(n, "Config.cmake");
+ this->Configs.push_back(config);
+
+ config = cmStrCat(cmSystemTools::LowerCase(n), "-config.cmake");
+ this->Configs.push_back(std::move(config));
+ }
+ }
+
+ // get igonored paths from vars and reroot them.
+ std::vector<std::string> ignored;
+ this->GetIgnoredPaths(ignored);
+ this->RerootPaths(ignored);
+
+ // Construct a set of ignored paths
+ this->IgnoredPaths.clear();
+ this->IgnoredPaths.insert(ignored.begin(), ignored.end());
+
+ // Find and load the package.
+ return this->HandlePackageMode(HandlePackageModeType::Config);
+}
+
+void cmFindPackageCommand::SetVersionVariables(
+ const std::function<void(const std::string&, cm::string_view)>&
+ addDefinition,
+ const std::string& prefix, const std::string& version, unsigned int count,
+ unsigned int major, unsigned int minor, unsigned int patch,
+ unsigned int tweak)
+{
+ addDefinition(prefix, version);
+
+ char buf[64];
+ sprintf(buf, "%u", major);
+ addDefinition(prefix + "_MAJOR", buf);
+ sprintf(buf, "%u", minor);
+ addDefinition(prefix + "_MINOR", buf);
+ sprintf(buf, "%u", patch);
+ addDefinition(prefix + "_PATCH", buf);
+ sprintf(buf, "%u", tweak);
+ addDefinition(prefix + "_TWEAK", buf);
+ sprintf(buf, "%u", count);
+ addDefinition(prefix + "_COUNT", buf);
+}
+
+void cmFindPackageCommand::SetModuleVariables(const std::string& components)
+{
+ this->AddFindDefinition("CMAKE_FIND_PACKAGE_NAME", this->Name);
+
+ // Store the list of components.
+ std::string components_var = this->Name + "_FIND_COMPONENTS";
+ this->AddFindDefinition(components_var, components);
+
+ if (this->Quiet) {
+ // Tell the module that is about to be read that it should find
+ // quietly.
+ std::string quietly = cmStrCat(this->Name, "_FIND_QUIETLY");
+ this->AddFindDefinition(quietly, "1"_s);
+ }
+
+ if (this->Required) {
+ // Tell the module that is about to be read that it should report
+ // a fatal error if the package is not found.
+ std::string req = cmStrCat(this->Name, "_FIND_REQUIRED");
+ this->AddFindDefinition(req, "1"_s);
+ }
+
+ if (!this->VersionComplete.empty()) {
+ std::string req = cmStrCat(this->Name, "_FIND_VERSION_COMPLETE");
+ this->AddFindDefinition(req, this->VersionComplete);
+ }
+
+ // Tell the module that is about to be read what version of the
+ // package has been requested.
+ auto addDefinition = [this](const std::string& variable,
+ cm::string_view value) {
+ this->AddFindDefinition(variable, value);
+ };
+
+ if (!this->Version.empty()) {
+ auto prefix = cmStrCat(this->Name, "_FIND_VERSION"_s);
+ this->SetVersionVariables(addDefinition, prefix, this->Version,
+ this->VersionCount, this->VersionMajor,
+ this->VersionMinor, this->VersionPatch,
+ this->VersionTweak);
+
+ // Tell the module whether an exact version has been requested.
+ auto exact = cmStrCat(this->Name, "_FIND_VERSION_EXACT");
+ this->AddFindDefinition(exact, this->VersionExact ? "1"_s : "0"_s);
+ }
+ if (!this->VersionRange.empty()) {
+ auto prefix = cmStrCat(this->Name, "_FIND_VERSION_MIN"_s);
+ this->SetVersionVariables(addDefinition, prefix, this->Version,
+ this->VersionCount, this->VersionMajor,
+ this->VersionMinor, this->VersionPatch,
+ this->VersionTweak);
+
+ prefix = cmStrCat(this->Name, "_FIND_VERSION_MAX"_s);
+ this->SetVersionVariables(addDefinition, prefix, this->VersionMax,
+ this->VersionMaxCount, this->VersionMaxMajor,
+ this->VersionMaxMinor, this->VersionMaxPatch,
+ this->VersionMaxTweak);
+
+ auto id = cmStrCat(this->Name, "_FIND_VERSION_RANGE");
+ this->AddFindDefinition(id, this->VersionRange);
+ id = cmStrCat(this->Name, "_FIND_VERSION_RANGE_MIN");
+ this->AddFindDefinition(id, this->VersionRangeMin);
+ id = cmStrCat(this->Name, "_FIND_VERSION_RANGE_MAX");
+ this->AddFindDefinition(id, this->VersionRangeMax);
+ }
+}
+
+void cmFindPackageCommand::AddFindDefinition(const std::string& var,
+ cm::string_view value)
+{
+ if (cmProp old = this->Makefile->GetDefinition(var)) {
+ this->OriginalDefs[var].exists = true;
+ this->OriginalDefs[var].value = *old;
+ } else {
+ this->OriginalDefs[var].exists = false;
+ }
+ this->Makefile->AddDefinition(var, value);
+}
+
+void cmFindPackageCommand::RestoreFindDefinitions()
+{
+ for (auto const& i : this->OriginalDefs) {
+ OriginalDef const& od = i.second;
+ if (od.exists) {
+ this->Makefile->AddDefinition(i.first, od.value);
+ } else {
+ this->Makefile->RemoveDefinition(i.first);
+ }
+ }
+}
+
+bool cmFindPackageCommand::FindModule(bool& found)
+{
+ std::string module = cmStrCat("Find", this->Name, ".cmake");
+
+ bool system = false;
+ std::string debugBuffer =
+ cmStrCat("find_package considered the following paths for ", this->Name,
+ ".cmake\n");
+ std::string mfile = this->Makefile->GetModulesFile(
+ module, system, this->DebugMode, debugBuffer);
+ if (this->DebugMode) {
+ if (mfile.empty()) {
+ debugBuffer = cmStrCat(debugBuffer, "The file was not found.");
+ } else {
+ debugBuffer =
+ cmStrCat(debugBuffer, "The file was found at\n ", mfile, "\n");
+ }
+ this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+ }
+
+ if (!mfile.empty()) {
+ if (system) {
+ auto it = this->DeprecatedFindModules.find(this->Name);
+ if (it != this->DeprecatedFindModules.end()) {
+ cmPolicies::PolicyStatus status =
+ this->Makefile->GetPolicyStatus(it->second);
+ switch (status) {
+ case cmPolicies::WARN: {
+ this->Makefile->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(cmPolicies::GetPolicyWarning(it->second), "\n"));
+ CM_FALLTHROUGH;
+ }
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ return true;
+ }
+ }
+ }
+
+ // Load the module we found, and set "<name>_FIND_MODULE" to true
+ // while inside it.
+ found = true;
+ std::string var = cmStrCat(this->Name, "_FIND_MODULE");
+ this->Makefile->AddDefinition(var, "1");
+ bool result = this->ReadListFile(mfile, DoPolicyScope);
+ this->Makefile->RemoveDefinition(var);
+
+ if (this->DebugMode) {
+ std::string foundVar = cmStrCat(this->Name, "_FOUND");
+ if (this->Makefile->IsDefinitionSet(foundVar) &&
+ !this->Makefile->IsOn(foundVar)) {
+
+ this->DebugBuffer = cmStrCat(
+ this->DebugBuffer, "The module is considered not found due to ",
+ foundVar, " being FALSE.");
+ }
+ }
+ return result;
+ }
+ return true;
+}
+
+bool cmFindPackageCommand::HandlePackageMode(
+ HandlePackageModeType handlePackageModeType)
+{
+ this->ConsideredConfigs.clear();
+
+ // Try to find the config file.
+ cmProp def = this->Makefile->GetDefinition(this->Variable);
+
+ // Try to load the config file if the directory is known
+ bool fileFound = false;
+ if (this->UseConfigFiles) {
+ if (!cmIsOff(def)) {
+ // Get the directory from the variable value.
+ std::string dir = *def;
+ cmSystemTools::ConvertToUnixSlashes(dir);
+
+ // Treat relative paths with respect to the current source dir.
+ if (!cmSystemTools::FileIsFullPath(dir)) {
+ dir = "/" + dir;
+ dir = this->Makefile->GetCurrentSourceDirectory() + dir;
+ }
+ // The file location was cached. Look for the correct file.
+ std::string file;
+ if (this->FindConfigFile(dir, file)) {
+ this->FileFound = file;
+ fileFound = true;
+ }
+ def = this->Makefile->GetDefinition(this->Variable);
+ }
+
+ // Search for the config file if it is not already found.
+ if (cmIsOff(def) || !fileFound) {
+ fileFound = this->FindConfig();
+ }
+
+ // Sanity check.
+ if (fileFound && this->FileFound.empty()) {
+ this->Makefile->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ "fileFound is true but FileFound is empty!");
+ fileFound = false;
+ }
+ }
+
+ std::string foundVar = cmStrCat(this->Name, "_FOUND");
+ std::string notFoundMessageVar = cmStrCat(this->Name, "_NOT_FOUND_MESSAGE");
+ std::string notFoundMessage;
+
+ // If the directory for the config file was found, try to read the file.
+ bool result = true;
+ bool found = false;
+ bool configFileSetFOUNDFalse = false;
+
+ if (fileFound) {
+ if (this->Makefile->IsDefinitionSet(foundVar) &&
+ !this->Makefile->IsOn(foundVar)) {
+ // by removing Foo_FOUND here if it is FALSE, we don't really change
+ // the situation for the Config file which is about to be included,
+ // but we make it possible to detect later on whether the Config file
+ // has set Foo_FOUND to FALSE itself:
+ this->Makefile->RemoveDefinition(foundVar);
+ }
+ this->Makefile->RemoveDefinition(notFoundMessageVar);
+
+ // Set the version variables before loading the config file.
+ // It may override them.
+ this->StoreVersionFound();
+
+ // Parse the configuration file.
+ if (this->ReadListFile(this->FileFound, DoPolicyScope)) {
+ // The package has been found.
+ found = true;
+
+ // Check whether the Config file has set Foo_FOUND to FALSE:
+ if (this->Makefile->IsDefinitionSet(foundVar) &&
+ !this->Makefile->IsOn(foundVar)) {
+ // we get here if the Config file has set Foo_FOUND actively to FALSE
+ found = false;
+ configFileSetFOUNDFalse = true;
+ notFoundMessage =
+ this->Makefile->GetSafeDefinition(notFoundMessageVar);
+ }
+ } else {
+ // The configuration file is invalid.
+ result = false;
+ }
+ }
+
+ if (this->UseFindModules && !found &&
+ handlePackageModeType == HandlePackageModeType::Config &&
+ this->Makefile->IsOn("CMAKE_FIND_PACKAGE_PREFER_CONFIG")) {
+ // Config mode failed. Allow Module case.
+ result = false;
+ }
+
+ if (this->DebugMode) {
+ this->DebugMessage(this->DebugBuffer);
+ this->DebugBuffer.clear();
+ }
+
+ // package not found
+ if (result && !found) {
+ // warn if package required or neither quiet nor in config mode
+ if (this->Required ||
+ !(this->Quiet ||
+ (this->UseConfigFiles && !this->UseFindModules &&
+ this->ConsideredConfigs.empty()))) {
+ // The variable is not set.
+ std::ostringstream e;
+ std::ostringstream aw;
+ if (configFileSetFOUNDFalse) {
+ /* clang-format off */
+ e << "Found package configuration file:\n"
+ " " << this->FileFound << "\n"
+ "but it set " << foundVar << " to FALSE so package \"" <<
+ this->Name << "\" is considered to be NOT FOUND.";
+ /* clang-format on */
+ if (!notFoundMessage.empty()) {
+ e << " Reason given by package: \n" << notFoundMessage << "\n";
+ }
+ }
+ // If there are files in ConsideredConfigs, it means that FooConfig.cmake
+ // have been found, but they didn't have appropriate versions.
+ else if (!this->ConsideredConfigs.empty()) {
+ auto duplicate_end = cmRemoveDuplicates(this->ConsideredConfigs);
+ e << "Could not find a configuration file for package \"" << this->Name
+ << "\" that "
+ << (this->VersionExact ? "exactly matches" : "is compatible with")
+ << " requested version "
+ << (this->VersionRange.empty() ? "" : "range ") << "\""
+ << this->VersionComplete << "\".\n"
+ << "The following configuration files were considered but not "
+ "accepted:\n";
+
+ for (ConfigFileInfo const& info :
+ cmMakeRange(this->ConsideredConfigs.cbegin(), duplicate_end)) {
+ e << " " << info.filename << ", version: " << info.version << "\n";
+ }
+ } else {
+ std::string requestedVersionString;
+ if (!this->VersionComplete.empty()) {
+ requestedVersionString =
+ cmStrCat(" (requested version ", this->VersionComplete, ')');
+ }
+
+ if (this->UseConfigFiles) {
+ if (this->UseFindModules) {
+ e << "By not providing \"Find" << this->Name
+ << ".cmake\" in "
+ "CMAKE_MODULE_PATH this project has asked CMake to find a "
+ "package configuration file provided by \""
+ << this->Name
+ << "\", "
+ "but CMake did not find one.\n";
+ }
+
+ if (this->Configs.size() == 1) {
+ e << "Could not find a package configuration file named \""
+ << this->Configs[0] << "\" provided by package \"" << this->Name
+ << "\"" << requestedVersionString << ".\n";
+ } else {
+ e << "Could not find a package configuration file provided by \""
+ << this->Name << "\"" << requestedVersionString
+ << " with any of the following names:\n"
+ << cmWrap(" ", this->Configs, "", "\n") << "\n";
+ }
+
+ e << "Add the installation prefix of \"" << this->Name
+ << "\" to "
+ "CMAKE_PREFIX_PATH or set \""
+ << this->Variable
+ << "\" to a "
+ "directory containing one of the above files. "
+ "If \""
+ << this->Name
+ << "\" provides a separate development "
+ "package or SDK, be sure it has been installed.";
+ } else // if(!this->UseFindModules && !this->UseConfigFiles)
+ {
+ e << "No \"Find" << this->Name << ".cmake\" found in "
+ << "CMAKE_MODULE_PATH.";
+
+ aw
+ << "Find" << this->Name
+ << ".cmake must either be part of this "
+ "project itself, in this case adjust CMAKE_MODULE_PATH so that "
+ "it points to the correct location inside its source tree.\n"
+ "Or it must be installed by a package which has already been "
+ "found via find_package(). In this case make sure that "
+ "package has indeed been found and adjust CMAKE_MODULE_PATH to "
+ "contain the location where that package has installed "
+ "Find"
+ << this->Name
+ << ".cmake. This must be a location "
+ "provided by that package. This error in general means that "
+ "the buildsystem of this project is relying on a Find-module "
+ "without ensuring that it is actually available.\n";
+ }
+ }
+
+ this->Makefile->IssueMessage(this->Required ? MessageType::FATAL_ERROR
+ : MessageType::WARNING,
+ e.str());
+ if (this->Required) {
+ cmSystemTools::SetFatalErrorOccured();
+ }
+
+ if (!aw.str().empty()) {
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, aw.str());
+ }
+ }
+ // output result if in config mode but not in quiet mode
+ else if (!this->Quiet) {
+ this->Makefile->DisplayStatus(cmStrCat("Could NOT find ", this->Name,
+ " (missing: ", this->Name,
+ "_DIR)"),
+ -1);
+ }
+ }
+
+ // Set a variable marking whether the package was found.
+ this->Makefile->AddDefinition(foundVar, found ? "1" : "0");
+
+ // Set a variable naming the configuration file that was found.
+ std::string fileVar = cmStrCat(this->Name, "_CONFIG");
+ if (found) {
+ this->Makefile->AddDefinition(fileVar, this->FileFound);
+ } else {
+ this->Makefile->RemoveDefinition(fileVar);
+ }
+
+ std::string consideredConfigsVar =
+ cmStrCat(this->Name, "_CONSIDERED_CONFIGS");
+ std::string consideredVersionsVar =
+ cmStrCat(this->Name, "_CONSIDERED_VERSIONS");
+
+ std::string consideredConfigFiles;
+ std::string consideredVersions;
+
+ const char* sep = "";
+ for (ConfigFileInfo const& i : this->ConsideredConfigs) {
+ consideredConfigFiles += sep;
+ consideredVersions += sep;
+ consideredConfigFiles += i.filename;
+ consideredVersions += i.version;
+ sep = ";";
+ }
+
+ this->Makefile->AddDefinition(consideredConfigsVar, consideredConfigFiles);
+
+ this->Makefile->AddDefinition(consideredVersionsVar, consideredVersions);
+
+ return result;
+}
+
+bool cmFindPackageCommand::FindConfig()
+{
+ // Compute the set of search prefixes.
+ this->ComputePrefixes();
+
+ // Look for the project's configuration file.
+ bool found = false;
+ if (this->DebugMode) {
+ this->DebugBuffer = cmStrCat(this->DebugBuffer,
+ "find_package considered the following "
+ "locations for the Config module:\n");
+ }
+
+ // Search for frameworks.
+ if (!found && (this->SearchFrameworkFirst || this->SearchFrameworkOnly)) {
+ found = this->FindFrameworkConfig();
+ }
+
+ // Search for apps.
+ if (!found && (this->SearchAppBundleFirst || this->SearchAppBundleOnly)) {
+ found = this->FindAppBundleConfig();
+ }
+
+ // Search prefixes.
+ if (!found && !(this->SearchFrameworkOnly || this->SearchAppBundleOnly)) {
+ found = this->FindPrefixedConfig();
+ }
+
+ // Search for frameworks.
+ if (!found && this->SearchFrameworkLast) {
+ found = this->FindFrameworkConfig();
+ }
+
+ // Search for apps.
+ if (!found && this->SearchAppBundleLast) {
+ found = this->FindAppBundleConfig();
+ }
+
+ if (this->DebugMode) {
+ if (found) {
+ this->DebugBuffer = cmStrCat(
+ this->DebugBuffer, "The file was found at\n ", this->FileFound, "\n");
+ } else {
+ this->DebugBuffer =
+ cmStrCat(this->DebugBuffer, "The file was not found.\n");
+ }
+ }
+
+ // Store the entry in the cache so it can be set by the user.
+ std::string init;
+ if (found) {
+ init = cmSystemTools::GetFilenamePath(this->FileFound);
+ } else {
+ init = this->Variable + "-NOTFOUND";
+ }
+ std::string help =
+ cmStrCat("The directory containing a CMake configuration file for ",
+ this->Name, '.');
+ // We force the value since we do not get here if it was already set.
+ this->Makefile->AddCacheDefinition(this->Variable, init, help.c_str(),
+ cmStateEnums::PATH, true);
+
+ return found;
+}
+
+bool cmFindPackageCommand::FindPrefixedConfig()
+{
+ std::vector<std::string> const& prefixes = this->SearchPaths;
+ return std::any_of(
+ prefixes.begin(), prefixes.end(),
+ [this](std::string const& p) -> bool { return this->SearchPrefix(p); });
+}
+
+bool cmFindPackageCommand::FindFrameworkConfig()
+{
+ std::vector<std::string> const& prefixes = this->SearchPaths;
+ return std::any_of(prefixes.begin(), prefixes.end(),
+ [this](std::string const& p) -> bool {
+ return this->SearchFrameworkPrefix(p);
+ });
+}
+
+bool cmFindPackageCommand::FindAppBundleConfig()
+{
+ std::vector<std::string> const& prefixes = this->SearchPaths;
+ return std::any_of(prefixes.begin(), prefixes.end(),
+ [this](std::string const& p) -> bool {
+ return this->SearchAppBundlePrefix(p);
+ });
+}
+
+bool cmFindPackageCommand::ReadListFile(const std::string& f,
+ PolicyScopeRule psr)
+{
+ const bool noPolicyScope = !this->PolicyScope || psr == NoPolicyScope;
+ if (this->Makefile->ReadDependentFile(f, noPolicyScope)) {
+ return true;
+ }
+ std::string e = cmStrCat("Error reading CMake code from \"", f, "\".");
+ this->SetError(e);
+ return false;
+}
+
+void cmFindPackageCommand::AppendToFoundProperty(bool found)
+{
+ std::vector<std::string> foundContents;
+ cmProp foundProp =
+ this->Makefile->GetState()->GetGlobalProperty("PACKAGES_FOUND");
+ if (cmNonempty(foundProp)) {
+ cmExpandList(*foundProp, foundContents, false);
+ auto nameIt =
+ std::find(foundContents.begin(), foundContents.end(), this->Name);
+ if (nameIt != foundContents.end()) {
+ foundContents.erase(nameIt);
+ }
+ }
+
+ std::vector<std::string> notFoundContents;
+ cmProp notFoundProp =
+ this->Makefile->GetState()->GetGlobalProperty("PACKAGES_NOT_FOUND");
+ if (cmNonempty(notFoundProp)) {
+ cmExpandList(*notFoundProp, notFoundContents, false);
+ auto nameIt =
+ std::find(notFoundContents.begin(), notFoundContents.end(), this->Name);
+ if (nameIt != notFoundContents.end()) {
+ notFoundContents.erase(nameIt);
+ }
+ }
+
+ if (found) {
+ foundContents.push_back(this->Name);
+ } else {
+ notFoundContents.push_back(this->Name);
+ }
+
+ std::string tmp = cmJoin(foundContents, ";");
+ this->Makefile->GetState()->SetGlobalProperty("PACKAGES_FOUND", tmp.c_str());
+
+ tmp = cmJoin(notFoundContents, ";");
+ this->Makefile->GetState()->SetGlobalProperty("PACKAGES_NOT_FOUND",
+ tmp.c_str());
+}
+
+void cmFindPackageCommand::AppendSuccessInformation()
+{
+ {
+ std::string transitivePropName =
+ cmStrCat("_CMAKE_", this->Name, "_TRANSITIVE_DEPENDENCY");
+ this->Makefile->GetState()->SetGlobalProperty(transitivePropName, "False");
+ }
+ std::string found = cmStrCat(this->Name, "_FOUND");
+ std::string upperFound = cmSystemTools::UpperCase(found);
+
+ bool upperResult = this->Makefile->IsOn(upperFound);
+ bool result = this->Makefile->IsOn(found);
+ bool packageFound = (result || upperResult);
+
+ this->AppendToFoundProperty(packageFound);
+
+ // Record whether the find was quiet or not, so this can be used
+ // e.g. in FeatureSummary.cmake
+ std::string quietInfoPropName = cmStrCat("_CMAKE_", this->Name, "_QUIET");
+ this->Makefile->GetState()->SetGlobalProperty(
+ quietInfoPropName, this->Quiet ? "TRUE" : "FALSE");
+
+ // set a global property to record the required version of this package
+ std::string versionInfoPropName =
+ cmStrCat("_CMAKE_", this->Name, "_REQUIRED_VERSION");
+ std::string versionInfo;
+ if (!this->VersionRange.empty()) {
+ versionInfo = this->VersionRange;
+ } else if (!this->Version.empty()) {
+ versionInfo =
+ cmStrCat(this->VersionExact ? "==" : ">=", ' ', this->Version);
+ }
+ this->Makefile->GetState()->SetGlobalProperty(versionInfoPropName,
+ versionInfo.c_str());
+ if (this->Required) {
+ std::string requiredInfoPropName =
+ cmStrCat("_CMAKE_", this->Name, "_TYPE");
+ this->Makefile->GetState()->SetGlobalProperty(requiredInfoPropName,
+ "REQUIRED");
+ }
+
+ // Restore original state of "_FIND_" variables we set.
+ this->RestoreFindDefinitions();
+
+ // Pop the package stack
+ this->Makefile->FindPackageRootPathStack.pop_back();
+}
+
+inline std::size_t collectPathsForDebug(std::string& buffer,
+ cmSearchPath const& searchPath,
+ std::size_t startIndex = 0)
+{
+ const auto& paths = searchPath.GetPaths();
+ if (paths.empty()) {
+ buffer += " none";
+ return 0;
+ }
+ for (std::size_t i = startIndex; i < paths.size(); i++) {
+ buffer += " " + paths[i] + "\n";
+ }
+ return paths.size();
+}
+
+void cmFindPackageCommand::ComputePrefixes()
+{
+ if (!this->NoDefaultPath) {
+ if (!this->NoPackageRootPath) {
+ this->FillPrefixesPackageRoot();
+ }
+ if (!this->NoCMakePath) {
+ this->FillPrefixesCMakeVariable();
+ }
+ if (!this->NoCMakeEnvironmentPath) {
+ this->FillPrefixesCMakeEnvironment();
+ }
+ }
+
+ this->FillPrefixesUserHints();
+
+ if (!this->NoDefaultPath) {
+ if (!this->NoSystemEnvironmentPath) {
+ this->FillPrefixesSystemEnvironment();
+ }
+ if (!this->NoUserRegistry) {
+ this->FillPrefixesUserRegistry();
+ }
+ if (!this->NoCMakeSystemPath) {
+ this->FillPrefixesCMakeSystemVariable();
+ }
+ if (!this->NoSystemRegistry) {
+ this->FillPrefixesSystemRegistry();
+ }
+ }
+ this->FillPrefixesUserGuess();
+
+ this->ComputeFinalPaths();
+}
+
+void cmFindPackageCommand::FillPrefixesPackageRoot()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::PackageRoot];
+
+ // Add the PACKAGE_ROOT_PATH from each enclosing find_package call.
+ for (auto pkgPaths = this->Makefile->FindPackageRootPathStack.rbegin();
+ pkgPaths != this->Makefile->FindPackageRootPathStack.rend();
+ ++pkgPaths) {
+ for (std::string const& path : *pkgPaths) {
+ paths.AddPath(path);
+ }
+ }
+ if (this->DebugMode) {
+ std::string debugBuffer = "<PackageName>_ROOT CMake variable "
+ "[CMAKE_FIND_USE_PACKAGE_ROOT_PATH].\n";
+ collectPathsForDebug(debugBuffer, paths);
+ this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+ }
+}
+
+void cmFindPackageCommand::FillPrefixesCMakeEnvironment()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::CMakeEnvironment];
+ std::string debugBuffer;
+ std::size_t debugOffset = 0;
+
+ // Check the environment variable with the same name as the cache
+ // entry.
+ paths.AddEnvPath(this->Variable);
+ if (this->DebugMode) {
+ debugBuffer = cmStrCat("Env variable ", this->Variable,
+ " [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].\n");
+ debugOffset = collectPathsForDebug(debugBuffer, paths);
+ }
+
+ // And now the general CMake environment variables
+ paths.AddEnvPath("CMAKE_PREFIX_PATH");
+ if (this->DebugMode) {
+ debugBuffer = cmStrCat(debugBuffer,
+ "\nCMAKE_PREFIX_PATH env variable "
+ "[CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].\n");
+ debugOffset = collectPathsForDebug(debugBuffer, paths, debugOffset);
+ }
+
+ paths.AddEnvPath("CMAKE_FRAMEWORK_PATH");
+ paths.AddEnvPath("CMAKE_APPBUNDLE_PATH");
+ if (this->DebugMode) {
+ debugBuffer =
+ cmStrCat(debugBuffer,
+ "\nCMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH env "
+ "variables [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].\n");
+ collectPathsForDebug(debugBuffer, paths, debugOffset);
+ this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+ }
+}
+
+void cmFindPackageCommand::FillPrefixesCMakeVariable()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::CMake];
+ std::string debugBuffer;
+ std::size_t debugOffset = 0;
+
+ paths.AddCMakePath("CMAKE_PREFIX_PATH");
+ if (this->DebugMode) {
+ debugBuffer = "CMAKE_PREFIX_PATH variable [CMAKE_FIND_USE_CMAKE_PATH].\n";
+ debugOffset = collectPathsForDebug(debugBuffer, paths);
+ }
+
+ paths.AddCMakePath("CMAKE_FRAMEWORK_PATH");
+ paths.AddCMakePath("CMAKE_APPBUNDLE_PATH");
+ if (this->DebugMode) {
+ debugBuffer =
+ cmStrCat(debugBuffer,
+ "\nCMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH variables "
+ "[CMAKE_FIND_USE_CMAKE_PATH].\n");
+ collectPathsForDebug(debugBuffer, paths, debugOffset);
+ this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+ }
+}
+
+void cmFindPackageCommand::FillPrefixesSystemEnvironment()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::SystemEnvironment];
+
+ // Use the system search path to generate prefixes.
+ // Relative paths are interpreted with respect to the current
+ // working directory.
+ std::vector<std::string> tmp;
+ cmSystemTools::GetPath(tmp);
+ for (std::string const& i : tmp) {
+ // If the path is a PREFIX/bin case then add its parent instead.
+ if ((cmHasLiteralSuffix(i, "/bin")) || (cmHasLiteralSuffix(i, "/sbin"))) {
+ paths.AddPath(cmSystemTools::GetFilenamePath(i));
+ } else {
+ paths.AddPath(i);
+ }
+ }
+ if (this->DebugMode) {
+ std::string debugBuffer = "Standard system environment variables "
+ "[CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH].\n";
+ collectPathsForDebug(debugBuffer, paths);
+ this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+ }
+}
+
+void cmFindPackageCommand::FillPrefixesUserRegistry()
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ this->LoadPackageRegistryWinUser();
+#elif defined(__HAIKU__)
+ char dir[B_PATH_NAME_LENGTH];
+ if (find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, dir, sizeof(dir)) ==
+ B_OK) {
+ std::string fname = cmStrCat(dir, "/cmake/packages/", Name);
+ this->LoadPackageRegistryDir(fname,
+ this->LabeledPaths[PathLabel::UserRegistry]);
+ }
+#else
+ std::string dir;
+ if (cmSystemTools::GetEnv("HOME", dir)) {
+ dir += "/.cmake/packages/";
+ dir += this->Name;
+ this->LoadPackageRegistryDir(dir,
+ this->LabeledPaths[PathLabel::UserRegistry]);
+ }
+#endif
+ if (this->DebugMode) {
+ std::string debugBuffer =
+ "CMake User Package Registry [CMAKE_FIND_USE_PACKAGE_REGISTRY].\n";
+ collectPathsForDebug(debugBuffer,
+ this->LabeledPaths[PathLabel::UserRegistry]);
+ this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+ }
+}
+
+void cmFindPackageCommand::FillPrefixesSystemRegistry()
+{
+ if (this->NoSystemRegistry || this->NoDefaultPath) {
+ return;
+ }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ this->LoadPackageRegistryWinSystem();
+#endif
+
+ if (this->DebugMode) {
+ std::string debugBuffer =
+ "CMake System Package Registry "
+ "[CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY].\n";
+ collectPathsForDebug(debugBuffer,
+ this->LabeledPaths[PathLabel::SystemRegistry]);
+ this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+ }
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <windows.h>
+// http://msdn.microsoft.com/en-us/library/aa384253%28v=vs.85%29.aspx
+# if !defined(KEY_WOW64_32KEY)
+# define KEY_WOW64_32KEY 0x0200
+# endif
+# if !defined(KEY_WOW64_64KEY)
+# define KEY_WOW64_64KEY 0x0100
+# endif
+void cmFindPackageCommand::LoadPackageRegistryWinUser()
+{
+ // HKEY_CURRENT_USER\\Software shares 32-bit and 64-bit views.
+ this->LoadPackageRegistryWin(true, 0,
+ this->LabeledPaths[PathLabel::UserRegistry]);
+}
+
+void cmFindPackageCommand::LoadPackageRegistryWinSystem()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::SystemRegistry];
+
+ // HKEY_LOCAL_MACHINE\\SOFTWARE has separate 32-bit and 64-bit views.
+ // Prefer the target platform view first.
+ if (this->Makefile->PlatformIs64Bit()) {
+ this->LoadPackageRegistryWin(false, KEY_WOW64_64KEY, paths);
+ this->LoadPackageRegistryWin(false, KEY_WOW64_32KEY, paths);
+ } else {
+ this->LoadPackageRegistryWin(false, KEY_WOW64_32KEY, paths);
+ this->LoadPackageRegistryWin(false, KEY_WOW64_64KEY, paths);
+ }
+}
+
+void cmFindPackageCommand::LoadPackageRegistryWin(bool user, unsigned int view,
+ cmSearchPath& outPaths)
+{
+ std::wstring key = L"Software\\Kitware\\CMake\\Packages\\";
+ key += cmsys::Encoding::ToWide(this->Name);
+ std::set<std::wstring> bad;
+ HKEY hKey;
+ if (RegOpenKeyExW(user ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, key.c_str(),
+ 0, KEY_QUERY_VALUE | view, &hKey) == ERROR_SUCCESS) {
+ DWORD valueType = REG_NONE;
+ wchar_t name[16383]; // RegEnumValue docs limit name to 32767 _bytes_
+ std::vector<wchar_t> data(512);
+ bool done = false;
+ DWORD index = 0;
+ while (!done) {
+ DWORD nameSize = static_cast<DWORD>(sizeof(name));
+ DWORD dataSize = static_cast<DWORD>(data.size() * sizeof(data[0]));
+ switch (RegEnumValueW(hKey, index, name, &nameSize, 0, &valueType,
+ (BYTE*)&data[0], &dataSize)) {
+ case ERROR_SUCCESS:
+ ++index;
+ if (valueType == REG_SZ) {
+ data[dataSize] = 0;
+ if (!this->CheckPackageRegistryEntry(
+ cmsys::Encoding::ToNarrow(&data[0]), outPaths)) {
+ // The entry is invalid.
+ bad.insert(name);
+ }
+ }
+ break;
+ case ERROR_MORE_DATA:
+ data.resize((dataSize + sizeof(data[0]) - 1) / sizeof(data[0]));
+ break;
+ case ERROR_NO_MORE_ITEMS:
+ default:
+ done = true;
+ break;
+ }
+ }
+ RegCloseKey(hKey);
+ }
+
+ // Remove bad values if possible.
+ if (user && !bad.empty() &&
+ RegOpenKeyExW(HKEY_CURRENT_USER, key.c_str(), 0, KEY_SET_VALUE | view,
+ &hKey) == ERROR_SUCCESS) {
+ for (std::wstring const& v : bad) {
+ RegDeleteValueW(hKey, v.c_str());
+ }
+ RegCloseKey(hKey);
+ }
+}
+#else
+class cmFindPackageCommandHoldFile
+{
+ const char* File;
+
+public:
+ cmFindPackageCommandHoldFile(const char* f)
+ : File(f)
+ {
+ }
+ ~cmFindPackageCommandHoldFile()
+ {
+ if (this->File) {
+ cmSystemTools::RemoveFile(this->File);
+ }
+ }
+ cmFindPackageCommandHoldFile(const cmFindPackageCommandHoldFile&) = delete;
+ cmFindPackageCommandHoldFile& operator=(
+ const cmFindPackageCommandHoldFile&) = delete;
+ void Release() { this->File = nullptr; }
+};
+
+void cmFindPackageCommand::LoadPackageRegistryDir(std::string const& dir,
+ cmSearchPath& outPaths)
+{
+ cmsys::Directory files;
+ if (!files.Load(dir)) {
+ return;
+ }
+
+ std::string fname;
+ for (unsigned long i = 0; i < files.GetNumberOfFiles(); ++i) {
+ fname = cmStrCat(dir, '/', files.GetFile(i));
+
+ if (!cmSystemTools::FileIsDirectory(fname)) {
+ // Hold this file hostage until it behaves.
+ cmFindPackageCommandHoldFile holdFile(fname.c_str());
+
+ // Load the file.
+ cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
+ std::string fentry;
+ if (fin && cmSystemTools::GetLineFromStream(fin, fentry) &&
+ this->CheckPackageRegistryEntry(fentry, outPaths)) {
+ // The file references an existing package, so release it.
+ holdFile.Release();
+ }
+ }
+ }
+
+ // TODO: Wipe out the directory if it is empty.
+}
+#endif
+
+bool cmFindPackageCommand::CheckPackageRegistryEntry(const std::string& fname,
+ cmSearchPath& outPaths)
+{
+ // Parse the content of one package registry entry.
+ if (cmSystemTools::FileIsFullPath(fname)) {
+ // The first line in the stream is the full path to a file or
+ // directory containing the package.
+ if (cmSystemTools::FileExists(fname)) {
+ // The path exists. Look for the package here.
+ if (!cmSystemTools::FileIsDirectory(fname)) {
+ outPaths.AddPath(cmSystemTools::GetFilenamePath(fname));
+ } else {
+ outPaths.AddPath(fname);
+ }
+ return true;
+ }
+ // The path does not exist. Assume the stream content is
+ // associated with an old package that no longer exists, and
+ // delete it to keep the package registry clean.
+ return false;
+ }
+ // The first line in the stream is not the full path to a file or
+ // directory. Assume the stream content was created by a future
+ // version of CMake that uses a different format, and leave it.
+ return true;
+}
+
+void cmFindPackageCommand::FillPrefixesCMakeSystemVariable()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::CMakeSystem];
+
+ paths.AddCMakePath("CMAKE_SYSTEM_PREFIX_PATH");
+ paths.AddCMakePath("CMAKE_SYSTEM_FRAMEWORK_PATH");
+ paths.AddCMakePath("CMAKE_SYSTEM_APPBUNDLE_PATH");
+
+ if (this->DebugMode) {
+ std::string debugBuffer = "CMake variables defined in the Platform file "
+ "[CMAKE_FIND_USE_CMAKE_SYSTEM_PATH].\n";
+ collectPathsForDebug(debugBuffer, paths);
+ this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+ }
+}
+
+void cmFindPackageCommand::FillPrefixesUserGuess()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::Guess];
+
+ for (std::string const& p : this->UserGuessArgs) {
+ paths.AddUserPath(p);
+ }
+ if (this->DebugMode) {
+ std::string debugBuffer =
+ "Paths specified by the find_package PATHS option.\n";
+ collectPathsForDebug(debugBuffer, paths);
+ this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+ }
+}
+
+void cmFindPackageCommand::FillPrefixesUserHints()
+{
+ cmSearchPath& paths = this->LabeledPaths[PathLabel::Hints];
+
+ for (std::string const& p : this->UserHintsArgs) {
+ paths.AddUserPath(p);
+ }
+ if (this->DebugMode) {
+ std::string debugBuffer =
+ "Paths specified by the find_package HINTS option.\n";
+ collectPathsForDebug(debugBuffer, paths);
+ this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+ }
+}
+
+bool cmFindPackageCommand::SearchDirectory(std::string const& dir)
+{
+ assert(!dir.empty() && dir.back() == '/');
+
+ // Check each path suffix on this directory.
+ for (std::string const& s : this->SearchPathSuffixes) {
+ std::string d = dir;
+ if (!s.empty()) {
+ d += s;
+ d += "/";
+ }
+ if (this->CheckDirectory(d)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmFindPackageCommand::CheckDirectory(std::string const& dir)
+{
+ assert(!dir.empty() && dir.back() == '/');
+
+ // Look for the file in this directory.
+ std::string d = dir.substr(0, dir.size() - 1);
+ if (this->FindConfigFile(d, this->FileFound)) {
+ // Remove duplicate slashes.
+ cmSystemTools::ConvertToUnixSlashes(this->FileFound);
+ return true;
+ }
+ return false;
+}
+
+bool cmFindPackageCommand::FindConfigFile(std::string const& dir,
+ std::string& file)
+{
+ if (this->IgnoredPaths.count(dir)) {
+ return false;
+ }
+
+ for (std::string const& c : this->Configs) {
+ file = cmStrCat(dir, '/', c);
+ if (this->DebugMode) {
+ this->DebugBuffer = cmStrCat(this->DebugBuffer, " ", file, "\n");
+ }
+ if (cmSystemTools::FileExists(file, true) && this->CheckVersion(file)) {
+ // Allow resolving symlinks when the config file is found through a link
+ if (this->UseRealPath) {
+ file = cmSystemTools::GetRealPath(file);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmFindPackageCommand::CheckVersion(std::string const& config_file)
+{
+ bool result = false; // by default, assume the version is not ok.
+ bool haveResult = false;
+ std::string version = "unknown";
+
+ // Get the filename without the .cmake extension.
+ std::string::size_type pos = config_file.rfind('.');
+ std::string version_file_base = config_file.substr(0, pos);
+
+ // Look for foo-config-version.cmake
+ std::string version_file = cmStrCat(version_file_base, "-version.cmake");
+ if (!haveResult && cmSystemTools::FileExists(version_file, true)) {
+ result = this->CheckVersionFile(version_file, version);
+ haveResult = true;
+ }
+
+ // Look for fooConfigVersion.cmake
+ version_file = cmStrCat(version_file_base, "Version.cmake");
+ if (!haveResult && cmSystemTools::FileExists(version_file, true)) {
+ result = this->CheckVersionFile(version_file, version);
+ haveResult = true;
+ }
+
+ // If no version was requested a versionless package is acceptable.
+ if (!haveResult && this->Version.empty()) {
+ result = true;
+ }
+
+ ConfigFileInfo configFileInfo;
+ configFileInfo.filename = config_file;
+ configFileInfo.version = version;
+ this->ConsideredConfigs.push_back(std::move(configFileInfo));
+
+ return result;
+}
+
+bool cmFindPackageCommand::CheckVersionFile(std::string const& version_file,
+ std::string& result_version)
+{
+ // The version file will be loaded in an isolated scope.
+ cmMakefile::ScopePushPop varScope(this->Makefile);
+ cmMakefile::PolicyPushPop polScope(this->Makefile);
+ static_cast<void>(varScope);
+ static_cast<void>(polScope);
+
+ // Clear the output variables.
+ this->Makefile->RemoveDefinition("PACKAGE_VERSION");
+ this->Makefile->RemoveDefinition("PACKAGE_VERSION_UNSUITABLE");
+ this->Makefile->RemoveDefinition("PACKAGE_VERSION_COMPATIBLE");
+ this->Makefile->RemoveDefinition("PACKAGE_VERSION_EXACT");
+
+ // Set the input variables.
+ this->Makefile->AddDefinition("PACKAGE_FIND_NAME", this->Name);
+ this->Makefile->AddDefinition("PACKAGE_FIND_VERSION_COMPLETE",
+ this->VersionComplete);
+
+ auto addDefinition = [this](const std::string& variable,
+ cm::string_view value) {
+ this->Makefile->AddDefinition(variable, value);
+ };
+ this->SetVersionVariables(addDefinition, "PACKAGE_FIND_VERSION",
+ this->Version, this->VersionCount,
+ this->VersionMajor, this->VersionMinor,
+ this->VersionPatch, this->VersionTweak);
+ if (!this->VersionRange.empty()) {
+ this->SetVersionVariables(addDefinition, "PACKAGE_FIND_VERSION_MIN",
+ this->Version, this->VersionCount,
+ this->VersionMajor, this->VersionMinor,
+ this->VersionPatch, this->VersionTweak);
+ this->SetVersionVariables(addDefinition, "PACKAGE_FIND_VERSION_MAX",
+ this->VersionMax, this->VersionMaxCount,
+ this->VersionMaxMajor, this->VersionMaxMinor,
+ this->VersionMaxPatch, this->VersionMaxTweak);
+
+ this->Makefile->AddDefinition("PACKAGE_FIND_VERSION_RANGE",
+ this->VersionComplete);
+ this->Makefile->AddDefinition("PACKAGE_FIND_VERSION_RANGE_MIN",
+ this->VersionRangeMin);
+ this->Makefile->AddDefinition("PACKAGE_FIND_VERSION_RANGE_MAX",
+ this->VersionRangeMax);
+ }
+
+ // Load the version check file. Pass NoPolicyScope because we do
+ // our own policy push/pop independent of CMP0011.
+ bool suitable = false;
+ if (this->ReadListFile(version_file, NoPolicyScope)) {
+ // Check the output variables.
+ bool okay = this->Makefile->IsOn("PACKAGE_VERSION_EXACT");
+ bool unsuitable = this->Makefile->IsOn("PACKAGE_VERSION_UNSUITABLE");
+ if (!okay && !this->VersionExact) {
+ okay = this->Makefile->IsOn("PACKAGE_VERSION_COMPATIBLE");
+ }
+
+ // The package is suitable if the version is okay and not
+ // explicitly unsuitable.
+ suitable = !unsuitable && (okay || this->Version.empty());
+ if (suitable) {
+ // Get the version found.
+ this->VersionFound =
+ this->Makefile->GetSafeDefinition("PACKAGE_VERSION");
+
+ // Try to parse the version number and store the results that were
+ // successfully parsed.
+ unsigned int parsed_major;
+ unsigned int parsed_minor;
+ unsigned int parsed_patch;
+ unsigned int parsed_tweak;
+ this->VersionFoundCount =
+ sscanf(this->VersionFound.c_str(), "%u.%u.%u.%u", &parsed_major,
+ &parsed_minor, &parsed_patch, &parsed_tweak);
+ switch (this->VersionFoundCount) {
+ case 4:
+ this->VersionFoundTweak = parsed_tweak;
+ CM_FALLTHROUGH;
+ case 3:
+ this->VersionFoundPatch = parsed_patch;
+ CM_FALLTHROUGH;
+ case 2:
+ this->VersionFoundMinor = parsed_minor;
+ CM_FALLTHROUGH;
+ case 1:
+ this->VersionFoundMajor = parsed_major;
+ CM_FALLTHROUGH;
+ default:
+ break;
+ }
+ }
+ }
+
+ result_version = this->Makefile->GetSafeDefinition("PACKAGE_VERSION");
+ if (result_version.empty()) {
+ result_version = "unknown";
+ }
+
+ // Succeed if the version is suitable.
+ return suitable;
+}
+
+void cmFindPackageCommand::StoreVersionFound()
+{
+ // Store the whole version string.
+ std::string ver = cmStrCat(this->Name, "_VERSION");
+ auto addDefinition = [this](const std::string& variable,
+ cm::string_view value) {
+ this->Makefile->AddDefinition(variable, value);
+ };
+
+ this->SetVersionVariables(addDefinition, ver, this->VersionFound,
+ this->VersionFoundCount, this->VersionFoundMajor,
+ this->VersionFoundMinor, this->VersionFoundPatch,
+ this->VersionFoundTweak);
+
+ if (this->VersionFound.empty()) {
+ this->Makefile->RemoveDefinition(ver);
+ }
+}
+
+class cmFileListGeneratorBase
+{
+public:
+ virtual ~cmFileListGeneratorBase() = default;
+
+protected:
+ bool Consider(std::string const& fullPath, cmFileList& listing);
+
+private:
+ bool Search(cmFileList&);
+ virtual bool Search(std::string const& parent, cmFileList&) = 0;
+ virtual std::unique_ptr<cmFileListGeneratorBase> Clone() const = 0;
+ friend class cmFileList;
+ cmFileListGeneratorBase* SetNext(cmFileListGeneratorBase const& next);
+ std::unique_ptr<cmFileListGeneratorBase> Next;
+};
+
+class cmFileList
+{
+public:
+ virtual ~cmFileList() = default;
+ cmFileList& operator/(cmFileListGeneratorBase const& rhs)
+ {
+ if (this->Last) {
+ this->Last = this->Last->SetNext(rhs);
+ } else {
+ this->First = rhs.Clone();
+ this->Last = this->First.get();
+ }
+ return *this;
+ }
+ bool Search()
+ {
+ if (this->First) {
+ return this->First->Search(*this);
+ }
+ return false;
+ }
+
+private:
+ virtual bool Visit(std::string const& fullPath) = 0;
+ friend class cmFileListGeneratorBase;
+ std::unique_ptr<cmFileListGeneratorBase> First;
+ cmFileListGeneratorBase* Last = nullptr;
+};
+
+class cmFindPackageFileList : public cmFileList
+{
+public:
+ cmFindPackageFileList(cmFindPackageCommand* fpc, bool use_suffixes = true)
+ : FPC(fpc)
+ , UseSuffixes(use_suffixes)
+ {
+ }
+
+private:
+ bool Visit(std::string const& fullPath) override
+ {
+ if (this->UseSuffixes) {
+ return this->FPC->SearchDirectory(fullPath);
+ }
+ return this->FPC->CheckDirectory(fullPath);
+ }
+ cmFindPackageCommand* FPC;
+ bool UseSuffixes;
+};
+
+bool cmFileListGeneratorBase::Search(cmFileList& listing)
+{
+ return this->Search("", listing);
+}
+
+cmFileListGeneratorBase* cmFileListGeneratorBase::SetNext(
+ cmFileListGeneratorBase const& next)
+{
+ this->Next = next.Clone();
+ return this->Next.get();
+}
+
+bool cmFileListGeneratorBase::Consider(std::string const& fullPath,
+ cmFileList& listing)
+{
+ if (!fullPath.empty() && !cmSystemTools::FileIsDirectory(fullPath)) {
+ return false;
+ }
+ if (this->Next) {
+ return this->Next->Search(fullPath + "/", listing);
+ }
+ return listing.Visit(fullPath + "/");
+}
+
+class cmFileListGeneratorFixed : public cmFileListGeneratorBase
+{
+public:
+ cmFileListGeneratorFixed(std::string str)
+ : String(std::move(str))
+ {
+ }
+ cmFileListGeneratorFixed(cmFileListGeneratorFixed const& r)
+ : String(r.String)
+ {
+ }
+
+private:
+ std::string String;
+ bool Search(std::string const& parent, cmFileList& lister) override
+ {
+ std::string fullPath = parent + this->String;
+ return this->Consider(fullPath, lister);
+ }
+ std::unique_ptr<cmFileListGeneratorBase> Clone() const override
+ {
+ std::unique_ptr<cmFileListGeneratorBase> g(
+ new cmFileListGeneratorFixed(*this));
+ return g;
+ }
+};
+
+class cmFileListGeneratorEnumerate : public cmFileListGeneratorBase
+{
+public:
+ cmFileListGeneratorEnumerate(std::vector<std::string> const& v)
+ : Vector(v)
+ {
+ }
+ cmFileListGeneratorEnumerate(cmFileListGeneratorEnumerate const& r)
+ : Vector(r.Vector)
+ {
+ }
+
+private:
+ std::vector<std::string> const& Vector;
+ bool Search(std::string const& parent, cmFileList& lister) override
+ {
+ for (std::string const& i : this->Vector) {
+ if (this->Consider(parent + i, lister)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ std::unique_ptr<cmFileListGeneratorBase> Clone() const override
+ {
+ std::unique_ptr<cmFileListGeneratorBase> g(
+ new cmFileListGeneratorEnumerate(*this));
+ return g;
+ }
+};
+
+class cmFileListGeneratorProject : public cmFileListGeneratorBase
+{
+public:
+ cmFileListGeneratorProject(std::vector<std::string> const& names,
+ cmFindPackageCommand::SortOrderType so,
+ cmFindPackageCommand::SortDirectionType sd)
+ : Names(names)
+ {
+ this->SetSort(so, sd);
+ }
+ cmFileListGeneratorProject(cmFileListGeneratorProject const& r)
+ : Names(r.Names)
+ {
+ this->SetSort(r.SortOrder, r.SortDirection);
+ }
+
+ void SetSort(cmFindPackageCommand::SortOrderType o,
+ cmFindPackageCommand::SortDirectionType d)
+ {
+ this->SortOrder = o;
+ this->SortDirection = d;
+ }
+
+protected:
+ // sort parameters
+ cmFindPackageCommand::SortOrderType SortOrder;
+ cmFindPackageCommand::SortDirectionType SortDirection;
+
+private:
+ std::vector<std::string> const& Names;
+ bool Search(std::string const& parent, cmFileList& lister) override
+ {
+ // Construct a list of matches.
+ std::vector<std::string> matches;
+ cmsys::Directory d;
+ d.Load(parent);
+ for (unsigned long i = 0; i < d.GetNumberOfFiles(); ++i) {
+ const char* fname = d.GetFile(i);
+ if (strcmp(fname, ".") == 0 || strcmp(fname, "..") == 0) {
+ continue;
+ }
+ for (std::string const& n : this->Names) {
+ if (cmsysString_strncasecmp(fname, n.c_str(), n.length()) == 0) {
+ matches.emplace_back(fname);
+ }
+ }
+ }
+
+ // before testing the matches check if there is a specific sorting order to
+ // perform
+ if (this->SortOrder != cmFindPackageCommand::None) {
+ cmFindPackageCommand::Sort(matches.begin(), matches.end(),
+ this->SortOrder, this->SortDirection);
+ }
+
+ for (std::string const& i : matches) {
+ if (this->Consider(parent + i, lister)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ std::unique_ptr<cmFileListGeneratorBase> Clone() const override
+ {
+ std::unique_ptr<cmFileListGeneratorBase> g(
+ new cmFileListGeneratorProject(*this));
+ return g;
+ }
+};
+
+class cmFileListGeneratorMacProject : public cmFileListGeneratorBase
+{
+public:
+ cmFileListGeneratorMacProject(std::vector<std::string> const& names,
+ const char* ext)
+ : Names(names)
+ , Extension(ext)
+ {
+ }
+ cmFileListGeneratorMacProject(cmFileListGeneratorMacProject const& r)
+ : Names(r.Names)
+ , Extension(r.Extension)
+ {
+ }
+
+private:
+ std::vector<std::string> const& Names;
+ std::string Extension;
+ bool Search(std::string const& parent, cmFileList& lister) override
+ {
+ // Construct a list of matches.
+ std::vector<std::string> matches;
+ cmsys::Directory d;
+ d.Load(parent);
+ for (unsigned long i = 0; i < d.GetNumberOfFiles(); ++i) {
+ const char* fname = d.GetFile(i);
+ if (strcmp(fname, ".") == 0 || strcmp(fname, "..") == 0) {
+ continue;
+ }
+ for (std::string name : this->Names) {
+ name += this->Extension;
+ if (cmsysString_strcasecmp(fname, name.c_str()) == 0) {
+ matches.emplace_back(fname);
+ }
+ }
+ }
+
+ for (std::string const& i : matches) {
+ if (this->Consider(parent + i, lister)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ std::unique_ptr<cmFileListGeneratorBase> Clone() const override
+ {
+ std::unique_ptr<cmFileListGeneratorBase> g(
+ new cmFileListGeneratorMacProject(*this));
+ return g;
+ }
+};
+
+class cmFileListGeneratorCaseInsensitive : public cmFileListGeneratorBase
+{
+public:
+ cmFileListGeneratorCaseInsensitive(std::string str)
+ : String(std::move(str))
+ {
+ }
+ cmFileListGeneratorCaseInsensitive(
+ cmFileListGeneratorCaseInsensitive const& r)
+ : String(r.String)
+ {
+ }
+
+private:
+ std::string String;
+ bool Search(std::string const& parent, cmFileList& lister) override
+ {
+ // Look for matching files.
+ std::vector<std::string> matches;
+ cmsys::Directory d;
+ d.Load(parent);
+ for (unsigned long i = 0; i < d.GetNumberOfFiles(); ++i) {
+ const char* fname = d.GetFile(i);
+ if (strcmp(fname, ".") == 0 || strcmp(fname, "..") == 0) {
+ continue;
+ }
+ if (cmsysString_strcasecmp(fname, this->String.c_str()) == 0) {
+ if (this->Consider(parent + fname, lister)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ std::unique_ptr<cmFileListGeneratorBase> Clone() const override
+ {
+ std::unique_ptr<cmFileListGeneratorBase> g(
+ new cmFileListGeneratorCaseInsensitive(*this));
+ return g;
+ }
+};
+
+class cmFileListGeneratorGlob : public cmFileListGeneratorBase
+{
+public:
+ cmFileListGeneratorGlob(std::string str)
+ : Pattern(std::move(str))
+ {
+ }
+ cmFileListGeneratorGlob(cmFileListGeneratorGlob const& r)
+ : Pattern(r.Pattern)
+ {
+ }
+
+private:
+ std::string Pattern;
+ bool Search(std::string const& parent, cmFileList& lister) override
+ {
+ // Glob the set of matching files.
+ std::string expr = cmStrCat(parent, this->Pattern);
+ cmsys::Glob g;
+ if (!g.FindFiles(expr)) {
+ return false;
+ }
+ std::vector<std::string> const& files = g.GetFiles();
+
+ // Look for directories among the matches.
+ for (std::string const& f : files) {
+ if (this->Consider(f, lister)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ std::unique_ptr<cmFileListGeneratorBase> Clone() const override
+ {
+ return cm::make_unique<cmFileListGeneratorGlob>(*this);
+ }
+};
+
+bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
+{
+ assert(!prefix_in.empty() && prefix_in.back() == '/');
+
+ // Skip this if the prefix does not exist.
+ if (!cmSystemTools::FileIsDirectory(prefix_in)) {
+ return false;
+ }
+
+ // PREFIX/ (useful on windows or in build trees)
+ if (this->SearchDirectory(prefix_in)) {
+ return true;
+ }
+
+ // Strip the trailing slash because the path generator is about to
+ // add one.
+ std::string prefix = prefix_in.substr(0, prefix_in.size() - 1);
+
+ // PREFIX/(cmake|CMake)/ (useful on windows or in build trees)
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorCaseInsensitive("cmake");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // PREFIX/(Foo|foo|FOO).*/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorProject(this->Names, this->SortOrder,
+ this->SortDirection);
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // PREFIX/(Foo|foo|FOO).*/(cmake|CMake)/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorProject(this->Names, this->SortOrder,
+ this->SortDirection) /
+ cmFileListGeneratorCaseInsensitive("cmake");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // Construct list of common install locations (lib and share).
+ std::vector<std::string> common;
+ if (!this->LibraryArchitecture.empty()) {
+ common.push_back("lib/" + this->LibraryArchitecture);
+ }
+ if (this->UseLib32Paths) {
+ common.emplace_back("lib32");
+ }
+ if (this->UseLib64Paths) {
+ common.emplace_back("lib64");
+ }
+ if (this->UseLibx32Paths) {
+ common.emplace_back("libx32");
+ }
+ common.emplace_back("lib");
+ common.emplace_back("share");
+
+ // PREFIX/(lib/ARCH|lib*|share)/cmake/(Foo|foo|FOO).*/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorEnumerate(common) /
+ cmFileListGeneratorFixed("cmake") /
+ cmFileListGeneratorProject(this->Names, this->SortOrder,
+ this->SortDirection);
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // PREFIX/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorEnumerate(common) /
+ cmFileListGeneratorProject(this->Names, this->SortOrder,
+ this->SortDirection);
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // PREFIX/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/(cmake|CMake)/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorEnumerate(common) /
+ cmFileListGeneratorProject(this->Names, this->SortOrder,
+ this->SortDirection) /
+ cmFileListGeneratorCaseInsensitive("cmake");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib*|share)/cmake/(Foo|foo|FOO).*/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorProject(this->Names, this->SortOrder,
+ this->SortDirection) /
+ cmFileListGeneratorEnumerate(common) /
+ cmFileListGeneratorFixed("cmake") /
+ cmFileListGeneratorProject(this->Names, this->SortOrder,
+ this->SortDirection);
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorProject(this->Names, this->SortOrder,
+ this->SortDirection) /
+ cmFileListGeneratorEnumerate(common) /
+ cmFileListGeneratorProject(this->Names, this->SortOrder,
+ this->SortDirection);
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/(cmake|CMake)/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorProject(this->Names, this->SortOrder,
+ this->SortDirection) /
+ cmFileListGeneratorEnumerate(common) /
+ cmFileListGeneratorProject(this->Names, this->SortOrder,
+ this->SortDirection) /
+ cmFileListGeneratorCaseInsensitive("cmake");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool cmFindPackageCommand::SearchFrameworkPrefix(std::string const& prefix_in)
+{
+ assert(!prefix_in.empty() && prefix_in.back() == '/');
+
+ // Strip the trailing slash because the path generator is about to
+ // add one.
+ std::string prefix = prefix_in.substr(0, prefix_in.size() - 1);
+
+ // <prefix>/Foo.framework/Resources/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorMacProject(this->Names, ".framework") /
+ cmFileListGeneratorFixed("Resources");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+ // <prefix>/Foo.framework/Resources/CMake/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorMacProject(this->Names, ".framework") /
+ cmFileListGeneratorFixed("Resources") /
+ cmFileListGeneratorCaseInsensitive("cmake");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // <prefix>/Foo.framework/Versions/*/Resources/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorMacProject(this->Names, ".framework") /
+ cmFileListGeneratorFixed("Versions") /
+ cmFileListGeneratorGlob("*/Resources");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // <prefix>/Foo.framework/Versions/*/Resources/CMake/
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorMacProject(this->Names, ".framework") /
+ cmFileListGeneratorFixed("Versions") /
+ cmFileListGeneratorGlob("*/Resources") /
+ cmFileListGeneratorCaseInsensitive("cmake");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool cmFindPackageCommand::SearchAppBundlePrefix(std::string const& prefix_in)
+{
+ assert(!prefix_in.empty() && prefix_in.back() == '/');
+
+ // Strip the trailing slash because the path generator is about to
+ // add one.
+ std::string prefix = prefix_in.substr(0, prefix_in.size() - 1);
+
+ // <prefix>/Foo.app/Contents/Resources
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorMacProject(this->Names, ".app") /
+ cmFileListGeneratorFixed("Contents/Resources");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ // <prefix>/Foo.app/Contents/Resources/CMake
+ {
+ cmFindPackageFileList lister(this);
+ lister / cmFileListGeneratorFixed(prefix) /
+ cmFileListGeneratorMacProject(this->Names, ".app") /
+ cmFileListGeneratorFixed("Contents/Resources") /
+ cmFileListGeneratorCaseInsensitive("cmake");
+ if (lister.Search()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// TODO: Debug cmsys::Glob double slash problem.
+
+bool cmFindPackage(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return cmFindPackageCommand(status).InitialPass(args);
+}
diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h
new file mode 100644
index 0000000..edf32d4
--- /dev/null
+++ b/Source/cmFindPackageCommand.h
@@ -0,0 +1,255 @@
+/* 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 <cstddef>
+#include <functional>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <cm/string_view>
+
+#include <cm3p/kwiml/int.h>
+
+#include "cmFindCommon.h"
+#include "cmPolicies.h"
+
+// IWYU insists we should forward-declare instead of including <functional>,
+// but we cannot forward-declare reliably because some C++ standard libraries
+// put the template in an inline namespace.
+#ifdef CMAKE_IWYU_FORWARD_STD_HASH
+/* clang-format off */
+namespace std {
+ template <class T> struct hash;
+}
+/* clang-format on */
+#endif
+
+class cmExecutionStatus;
+class cmSearchPath;
+
+/** \class cmFindPackageCommand
+ * \brief Load settings from an external project.
+ *
+ * cmFindPackageCommand
+ */
+class cmFindPackageCommand : public cmFindCommon
+{
+public:
+ /*! A sorting order strategy to be applied to recovered package folders (see
+ * FIND_PACKAGE_SORT_ORDER)*/
+ enum /*class*/ SortOrderType
+ {
+ None,
+ Name_order,
+ Natural
+ };
+ /*! A sorting direction to be applied to recovered package folders (see
+ * FIND_PACKAGE_SORT_DIRECTION)*/
+ enum /*class*/ SortDirectionType
+ {
+ Asc,
+ Dec
+ };
+
+ /*! sorts a given list of string based on the input sort parameters */
+ static void Sort(std::vector<std::string>::iterator begin,
+ std::vector<std::string>::iterator end, SortOrderType order,
+ SortDirectionType dir);
+
+ cmFindPackageCommand(cmExecutionStatus& status);
+
+ bool InitialPass(std::vector<std::string> const& args);
+
+private:
+ class PathLabel : public cmFindCommon::PathLabel
+ {
+ protected:
+ PathLabel();
+
+ public:
+ PathLabel(const std::string& label)
+ : cmFindCommon::PathLabel(label)
+ {
+ }
+ static PathLabel UserRegistry;
+ static PathLabel Builds;
+ static PathLabel SystemRegistry;
+ };
+
+ bool FindPackageUsingModuleMode();
+ bool FindPackageUsingConfigMode();
+
+ // Add additional search path labels and groups not present in the
+ // parent class
+ void AppendSearchPathGroups();
+
+ void AppendSuccessInformation();
+ void AppendToFoundProperty(bool found);
+ void SetVersionVariables(
+ const std::function<void(const std::string&, cm::string_view)>&
+ addDefinition,
+ const std::string& prefix, const std::string& version, unsigned int count,
+ unsigned int major, unsigned int minor, unsigned int patch,
+ unsigned int tweak);
+ void SetModuleVariables(const std::string& components);
+ bool FindModule(bool& found);
+ void AddFindDefinition(const std::string& var, cm::string_view value);
+ void RestoreFindDefinitions();
+
+ enum /*class*/ HandlePackageModeType
+ {
+ Module,
+ Config
+ };
+ bool HandlePackageMode(HandlePackageModeType type);
+
+ bool FindConfig();
+ bool FindPrefixedConfig();
+ bool FindFrameworkConfig();
+ bool FindAppBundleConfig();
+ enum PolicyScopeRule
+ {
+ NoPolicyScope,
+ DoPolicyScope
+ };
+ bool ReadListFile(const std::string& f, PolicyScopeRule psr);
+ void StoreVersionFound();
+
+ void ComputePrefixes();
+ void FillPrefixesPackageRoot();
+ void FillPrefixesCMakeEnvironment();
+ void FillPrefixesCMakeVariable();
+ void FillPrefixesSystemEnvironment();
+ void FillPrefixesUserRegistry();
+ void FillPrefixesSystemRegistry();
+ void FillPrefixesCMakeSystemVariable();
+ void FillPrefixesUserGuess();
+ void FillPrefixesUserHints();
+ void LoadPackageRegistryDir(std::string const& dir, cmSearchPath& outPaths);
+ void LoadPackageRegistryWinUser();
+ void LoadPackageRegistryWinSystem();
+ void LoadPackageRegistryWin(bool user, unsigned int view,
+ cmSearchPath& outPaths);
+ bool CheckPackageRegistryEntry(const std::string& fname,
+ cmSearchPath& outPaths);
+ bool SearchDirectory(std::string const& dir);
+ bool CheckDirectory(std::string const& dir);
+ bool FindConfigFile(std::string const& dir, std::string& file);
+ bool CheckVersion(std::string const& config_file);
+ bool CheckVersionFile(std::string const& version_file,
+ std::string& result_version);
+ bool SearchPrefix(std::string const& prefix);
+ bool SearchFrameworkPrefix(std::string const& prefix_in);
+ bool SearchAppBundlePrefix(std::string const& prefix_in);
+
+ friend class cmFindPackageFileList;
+
+ struct OriginalDef
+ {
+ bool exists;
+ std::string value;
+ };
+ std::map<std::string, OriginalDef> OriginalDefs;
+
+ std::map<std::string, cmPolicies::PolicyID> DeprecatedFindModules;
+
+ static const cm::string_view VERSION_ENDPOINT_INCLUDED;
+ static const cm::string_view VERSION_ENDPOINT_EXCLUDED;
+
+ std::string Name;
+ std::string Variable;
+ std::string VersionComplete;
+ std::string VersionRange;
+ cm::string_view VersionRangeMin;
+ cm::string_view VersionRangeMax;
+ std::string Version;
+ unsigned int VersionMajor = 0;
+ unsigned int VersionMinor = 0;
+ unsigned int VersionPatch = 0;
+ unsigned int VersionTweak = 0;
+ unsigned int VersionCount = 0;
+ std::string VersionMax;
+ unsigned int VersionMaxMajor = 0;
+ unsigned int VersionMaxMinor = 0;
+ unsigned int VersionMaxPatch = 0;
+ unsigned int VersionMaxTweak = 0;
+ unsigned int VersionMaxCount = 0;
+ bool VersionExact = false;
+ std::string FileFound;
+ std::string VersionFound;
+ unsigned int VersionFoundMajor = 0;
+ unsigned int VersionFoundMinor = 0;
+ unsigned int VersionFoundPatch = 0;
+ unsigned int VersionFoundTweak = 0;
+ unsigned int VersionFoundCount = 0;
+ KWIML_INT_uint64_t RequiredCMakeVersion = 0;
+ bool Quiet = false;
+ bool Required = false;
+ bool UseConfigFiles = true;
+ bool UseFindModules = true;
+ bool NoUserRegistry = false;
+ bool NoSystemRegistry = false;
+ bool UseLib32Paths = false;
+ bool UseLib64Paths = false;
+ bool UseLibx32Paths = false;
+ bool UseRealPath = false;
+ bool PolicyScope = true;
+ std::string LibraryArchitecture;
+ std::vector<std::string> Names;
+ std::vector<std::string> Configs;
+ std::set<std::string> IgnoredPaths;
+ std::string DebugBuffer;
+
+ /*! the selected sortOrder (None by default)*/
+ SortOrderType SortOrder = None;
+ /*! the selected sortDirection (Asc by default)*/
+ SortDirectionType SortDirection = Asc;
+
+ struct ConfigFileInfo
+ {
+ std::string filename;
+ std::string version;
+
+ bool operator<(ConfigFileInfo const& rhs) const
+ {
+ return this->filename < rhs.filename;
+ }
+
+ bool operator==(ConfigFileInfo const& rhs) const
+ {
+ return this->filename == rhs.filename;
+ }
+
+ bool operator!=(ConfigFileInfo const& rhs) const
+ {
+ return !(*this == rhs);
+ }
+ };
+ std::vector<ConfigFileInfo> ConsideredConfigs;
+
+ friend struct std::hash<ConfigFileInfo>;
+};
+
+namespace std {
+
+template <>
+struct hash<cmFindPackageCommand::ConfigFileInfo>
+{
+ using argument_type = cmFindPackageCommand::ConfigFileInfo;
+ using result_type = size_t;
+
+ result_type operator()(argument_type const& s) const noexcept
+ {
+ result_type const h(std::hash<std::string>{}(s.filename));
+ return h;
+ }
+};
+}
+
+bool cmFindPackage(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmFindPathCommand.cxx b/Source/cmFindPathCommand.cxx
new file mode 100644
index 0000000..3fb0826
--- /dev/null
+++ b/Source/cmFindPathCommand.cxx
@@ -0,0 +1,168 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFindPathCommand.h"
+
+#include "cmsys/Glob.hxx"
+
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+class cmExecutionStatus;
+
+cmFindPathCommand::cmFindPathCommand(cmExecutionStatus& status)
+ : cmFindBase(status)
+{
+ this->EnvironmentPath = "INCLUDE";
+ this->IncludeFileInPath = false;
+}
+
+// cmFindPathCommand
+bool cmFindPathCommand::InitialPass(std::vector<std::string> const& argsIn)
+{
+ this->DebugMode = this->ComputeIfDebugModeWanted();
+ this->VariableDocumentation = "Path to a file.";
+ this->CMakePathName = "INCLUDE";
+ if (!this->ParseArguments(argsIn)) {
+ return false;
+ }
+ if (this->AlreadyInCache) {
+ // If the user specifies the entry on the command line without a
+ // type we should add the type and docstring but keep the original
+ // value.
+ if (this->AlreadyInCacheWithoutMetaInfo) {
+ this->Makefile->AddCacheDefinition(
+ this->VariableName, "", this->VariableDocumentation.c_str(),
+ (this->IncludeFileInPath ? cmStateEnums::FILEPATH
+ : cmStateEnums::PATH));
+ }
+ return true;
+ }
+
+ std::string result = this->FindHeader();
+ if (!result.empty()) {
+ this->Makefile->AddCacheDefinition(
+ this->VariableName, result, this->VariableDocumentation.c_str(),
+ (this->IncludeFileInPath) ? cmStateEnums::FILEPATH : cmStateEnums::PATH);
+ return true;
+ }
+ this->Makefile->AddCacheDefinition(
+ this->VariableName, this->VariableName + "-NOTFOUND",
+ this->VariableDocumentation.c_str(),
+ (this->IncludeFileInPath) ? cmStateEnums::FILEPATH : cmStateEnums::PATH);
+ if (this->Required) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Could not find " + this->VariableName +
+ " using the following files: " + cmJoin(this->Names, ", "));
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ return true;
+}
+
+std::string cmFindPathCommand::FindHeader()
+{
+ std::string debug_name = this->IncludeFileInPath ? "find_file" : "find_path";
+ cmFindBaseDebugState debug(debug_name, this);
+ std::string header;
+ if (this->SearchFrameworkFirst || this->SearchFrameworkOnly) {
+ header = this->FindFrameworkHeader(debug);
+ }
+ if (header.empty() && !this->SearchFrameworkOnly) {
+ header = this->FindNormalHeader(debug);
+ }
+ if (header.empty() && this->SearchFrameworkLast) {
+ header = this->FindFrameworkHeader(debug);
+ }
+
+ return header;
+}
+
+std::string cmFindPathCommand::FindHeaderInFramework(
+ std::string const& file, std::string const& dir) const
+{
+ std::string fileName = file;
+ std::string frameWorkName;
+ std::string::size_type pos = fileName.find('/');
+ // if there is a / in the name try to find the header as a framework
+ // For example bar/foo.h would look for:
+ // bar.framework/Headers/foo.h
+ if (pos != std::string::npos) {
+ // remove the name from the slash;
+ fileName = fileName.substr(pos + 1);
+ frameWorkName = file;
+ frameWorkName =
+ frameWorkName.substr(0, frameWorkName.size() - fileName.size() - 1);
+ // if the framework has a path in it then just use the filename
+ if (frameWorkName.find('/') != std::string::npos) {
+ fileName = file;
+ frameWorkName.clear();
+ }
+ if (!frameWorkName.empty()) {
+ std::string fpath = cmStrCat(dir, frameWorkName, ".framework");
+ std::string intPath = cmStrCat(fpath, "/Headers/", fileName);
+ if (cmSystemTools::FileExists(intPath)) {
+ if (this->IncludeFileInPath) {
+ return intPath;
+ }
+ return fpath;
+ }
+ }
+ }
+ // if it is not found yet or not a framework header, then do a glob search
+ // for all frameworks in the directory: dir/*.framework/Headers/<file>
+ std::string glob = cmStrCat(dir, "*.framework/Headers/", file);
+ cmsys::Glob globIt;
+ globIt.FindFiles(glob);
+ std::vector<std::string> files = globIt.GetFiles();
+ if (!files.empty()) {
+ std::string fheader = cmSystemTools::CollapseFullPath(files[0]);
+ if (this->IncludeFileInPath) {
+ return fheader;
+ }
+ fheader.resize(fheader.size() - file.size());
+ return fheader;
+ }
+ return "";
+}
+
+std::string cmFindPathCommand::FindNormalHeader(cmFindBaseDebugState& debug)
+{
+ std::string tryPath;
+ for (std::string const& n : this->Names) {
+ for (std::string const& sp : this->SearchPaths) {
+ tryPath = cmStrCat(sp, n);
+ if (cmSystemTools::FileExists(tryPath)) {
+ debug.FoundAt(tryPath);
+ if (this->IncludeFileInPath) {
+ return tryPath;
+ }
+ return sp;
+ }
+ debug.FailedAt(tryPath);
+ }
+ }
+ return "";
+}
+
+std::string cmFindPathCommand::FindFrameworkHeader(cmFindBaseDebugState& debug)
+{
+ for (std::string const& n : this->Names) {
+ for (std::string const& sp : this->SearchPaths) {
+ std::string fwPath = this->FindHeaderInFramework(n, sp);
+ fwPath.empty() ? debug.FailedAt(fwPath) : debug.FoundAt(fwPath);
+ if (!fwPath.empty()) {
+ return fwPath;
+ }
+ }
+ }
+ return "";
+}
+
+bool cmFindPath(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return cmFindPathCommand(status).InitialPass(args);
+}
diff --git a/Source/cmFindPathCommand.h b/Source/cmFindPathCommand.h
new file mode 100644
index 0000000..6101ea1
--- /dev/null
+++ b/Source/cmFindPathCommand.h
@@ -0,0 +1,39 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmFindBase.h"
+
+class cmExecutionStatus;
+
+/** \class cmFindPathCommand
+ * \brief Define a command to search for a library.
+ *
+ * cmFindPathCommand is used to define a CMake variable
+ * that specifies a library. The command searches for a given
+ * file in a list of directories.
+ */
+class cmFindPathCommand : public cmFindBase
+{
+public:
+ cmFindPathCommand(cmExecutionStatus& status);
+
+ bool InitialPass(std::vector<std::string> const& args);
+
+ bool IncludeFileInPath;
+
+private:
+ std::string FindHeaderInFramework(std::string const& file,
+ std::string const& dir) const;
+ std::string FindHeader();
+ std::string FindNormalHeader(cmFindBaseDebugState& debug);
+ std::string FindFrameworkHeader(cmFindBaseDebugState& debug);
+};
+
+bool cmFindPath(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx
new file mode 100644
index 0000000..c22462e
--- /dev/null
+++ b/Source/cmFindProgramCommand.cxx
@@ -0,0 +1,341 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFindProgramCommand.h"
+
+#include <algorithm>
+#include <string>
+
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+class cmExecutionStatus;
+
+#if defined(__APPLE__)
+# include <CoreFoundation/CoreFoundation.h>
+#endif
+
+struct cmFindProgramHelper
+{
+ cmFindProgramHelper(cmMakefile* makefile, cmFindBase const* base)
+ : DebugSearches("find_program", base)
+ , Makefile(makefile)
+ , PolicyCMP0109(makefile->GetPolicyStatus(cmPolicies::CMP0109))
+ {
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
+ // Consider platform-specific extensions.
+ this->Extensions.push_back(".com");
+ this->Extensions.push_back(".exe");
+#endif
+ // Consider original name with no extensions.
+ this->Extensions.emplace_back();
+ }
+
+ // List of valid extensions.
+ std::vector<std::string> Extensions;
+
+ // Keep track of the best program file found so far.
+ std::string BestPath;
+
+ // Current names under consideration.
+ std::vector<std::string> Names;
+
+ // Current name with extension under consideration.
+ std::string TestNameExt;
+
+ // Current full path under consideration.
+ std::string TestPath;
+
+ // Debug state
+ cmFindBaseDebugState DebugSearches;
+ cmMakefile* Makefile;
+
+ cmPolicies::PolicyStatus PolicyCMP0109;
+
+ void AddName(std::string const& name) { this->Names.push_back(name); }
+ void SetName(std::string const& name)
+ {
+ this->Names.clear();
+ this->AddName(name);
+ }
+ bool CheckCompoundNames()
+ {
+ return std::any_of(this->Names.begin(), this->Names.end(),
+ [this](std::string const& n) -> bool {
+ // Only perform search relative to current directory
+ // if the file name contains a directory separator.
+ return n.find('/') != std::string::npos &&
+ this->CheckDirectoryForName("", n);
+ });
+ }
+ bool CheckDirectory(std::string const& path)
+ {
+ return std::any_of(this->Names.begin(), this->Names.end(),
+ [this, &path](std::string const& n) -> bool {
+ // Only perform search relative to current directory
+ // if the file name contains a directory separator.
+ return this->CheckDirectoryForName(path, n);
+ });
+ }
+ bool CheckDirectoryForName(std::string const& path, std::string const& name)
+ {
+ return std::any_of(this->Extensions.begin(), this->Extensions.end(),
+ [this, &path, &name](std::string const& ext) -> bool {
+ if (!ext.empty() && cmHasSuffix(name, ext)) {
+ return false;
+ }
+ this->TestNameExt = cmStrCat(name, ext);
+ this->TestPath = cmSystemTools::CollapseFullPath(
+ this->TestNameExt, path);
+ bool exists = this->FileIsExecutable(this->TestPath);
+ exists ? this->DebugSearches.FoundAt(this->TestPath)
+ : this->DebugSearches.FailedAt(this->TestPath);
+ if (exists) {
+ this->BestPath = this->TestPath;
+ return true;
+ }
+ return false;
+ });
+ }
+ bool FileIsExecutable(std::string const& file) const
+ {
+ switch (this->PolicyCMP0109) {
+ case cmPolicies::OLD:
+ return cmSystemTools::FileExists(file, true);
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ return cmSystemTools::FileIsExecutable(file);
+ default:
+ break;
+ }
+ bool const isExeOld = cmSystemTools::FileExists(file, true);
+ bool const isExeNew = cmSystemTools::FileIsExecutable(file);
+ if (isExeNew == isExeOld) {
+ return isExeNew;
+ }
+ if (isExeNew) {
+ this->Makefile->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0109),
+ "\n"
+ "The file\n"
+ " ",
+ file,
+ "\n"
+ "is executable but not readable. "
+ "CMake is ignoring it for compatibility."));
+ } else {
+ this->Makefile->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0109),
+ "\n"
+ "The file\n"
+ " ",
+ file,
+ "\n"
+ "is readable but not executable. "
+ "CMake is using it for compatibility."));
+ }
+ return isExeOld;
+ }
+};
+
+cmFindProgramCommand::cmFindProgramCommand(cmExecutionStatus& status)
+ : cmFindBase(status)
+{
+ this->NamesPerDirAllowed = true;
+}
+
+// cmFindProgramCommand
+bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn)
+{
+ this->DebugMode = this->ComputeIfDebugModeWanted();
+ this->VariableDocumentation = "Path to a program.";
+ this->CMakePathName = "PROGRAM";
+ // call cmFindBase::ParseArguments
+ if (!this->ParseArguments(argsIn)) {
+ return false;
+ }
+ if (this->AlreadyInCache) {
+ // If the user specifies the entry on the command line without a
+ // type we should add the type and docstring but keep the original
+ // value.
+ if (this->AlreadyInCacheWithoutMetaInfo) {
+ this->Makefile->AddCacheDefinition(this->VariableName, "",
+ this->VariableDocumentation.c_str(),
+ cmStateEnums::FILEPATH);
+ }
+ return true;
+ }
+
+ std::string const result = this->FindProgram();
+ if (!result.empty()) {
+ // Save the value in the cache
+ this->Makefile->AddCacheDefinition(this->VariableName, result,
+ this->VariableDocumentation.c_str(),
+ cmStateEnums::FILEPATH);
+
+ return true;
+ }
+ this->Makefile->AddCacheDefinition(
+ this->VariableName, this->VariableName + "-NOTFOUND",
+ this->VariableDocumentation.c_str(), cmStateEnums::FILEPATH);
+ if (this->Required) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Could not find " + this->VariableName +
+ " using the following names: " + cmJoin(this->Names, ", "));
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ return true;
+}
+
+std::string cmFindProgramCommand::FindProgram()
+{
+ std::string program;
+
+ if (this->SearchAppBundleFirst || this->SearchAppBundleOnly) {
+ program = this->FindAppBundle();
+ }
+ if (program.empty() && !this->SearchAppBundleOnly) {
+ program = this->FindNormalProgram();
+ }
+
+ if (program.empty() && this->SearchAppBundleLast) {
+ program = this->FindAppBundle();
+ }
+ return program;
+}
+
+std::string cmFindProgramCommand::FindNormalProgram()
+{
+ if (this->NamesPerDir) {
+ return this->FindNormalProgramNamesPerDir();
+ }
+ return this->FindNormalProgramDirsPerName();
+}
+
+std::string cmFindProgramCommand::FindNormalProgramNamesPerDir()
+{
+ // Search for all names in each directory.
+ cmFindProgramHelper helper(this->Makefile, this);
+ for (std::string const& n : this->Names) {
+ helper.AddName(n);
+ }
+
+ // Check for the names themselves if they contain a directory separator.
+ if (helper.CheckCompoundNames()) {
+ return helper.BestPath;
+ }
+
+ // Search every directory.
+ for (std::string const& sp : this->SearchPaths) {
+ if (helper.CheckDirectory(sp)) {
+ return helper.BestPath;
+ }
+ }
+ // Couldn't find the program.
+ return "";
+}
+
+std::string cmFindProgramCommand::FindNormalProgramDirsPerName()
+{
+ // Search the entire path for each name.
+ cmFindProgramHelper helper(this->Makefile, this);
+ for (std::string const& n : this->Names) {
+ // Switch to searching for this name.
+ helper.SetName(n);
+
+ // Check for the names themselves if they contain a directory separator.
+ if (helper.CheckCompoundNames()) {
+ return helper.BestPath;
+ }
+
+ // Search every directory.
+ for (std::string const& sp : this->SearchPaths) {
+ if (helper.CheckDirectory(sp)) {
+ return helper.BestPath;
+ }
+ }
+ }
+ // Couldn't find the program.
+ return "";
+}
+
+std::string cmFindProgramCommand::FindAppBundle()
+{
+ for (std::string const& name : this->Names) {
+
+ std::string appName = name + std::string(".app");
+ std::string appPath =
+ cmSystemTools::FindDirectory(appName, this->SearchPaths, true);
+
+ if (!appPath.empty()) {
+ std::string executable = this->GetBundleExecutable(appPath);
+ if (!executable.empty()) {
+ return cmSystemTools::CollapseFullPath(executable);
+ }
+ }
+ }
+
+ // Couldn't find app bundle
+ return "";
+}
+
+std::string cmFindProgramCommand::GetBundleExecutable(
+ std::string const& bundlePath)
+{
+ std::string executable;
+ (void)bundlePath;
+#if defined(__APPLE__)
+ // Started with an example on developer.apple.com about finding bundles
+ // and modified from that.
+
+ // Get a CFString of the app bundle path
+ // XXX - Is it safe to assume everything is in UTF8?
+ CFStringRef bundlePathCFS = CFStringCreateWithCString(
+ kCFAllocatorDefault, bundlePath.c_str(), kCFStringEncodingUTF8);
+
+ // Make a CFURLRef from the CFString representation of the
+ // bundle’s path.
+ CFURLRef bundleURL = CFURLCreateWithFileSystemPath(
+ kCFAllocatorDefault, bundlePathCFS, kCFURLPOSIXPathStyle, true);
+
+ // Make a bundle instance using the URLRef.
+ CFBundleRef appBundle = CFBundleCreate(kCFAllocatorDefault, bundleURL);
+
+ // returned executableURL is relative to <appbundle>/Contents/MacOS/
+ CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
+
+ if (executableURL != nullptr) {
+ const int MAX_OSX_PATH_SIZE = 1024;
+ UInt8 buffer[MAX_OSX_PATH_SIZE];
+
+ if (CFURLGetFileSystemRepresentation(executableURL, false, buffer,
+ MAX_OSX_PATH_SIZE)) {
+ executable = bundlePath + "/Contents/MacOS/" +
+ std::string(reinterpret_cast<char*>(buffer));
+ }
+ // Only release CFURLRef if it's not null
+ CFRelease(executableURL);
+ }
+
+ // Any CF objects returned from functions with "create" or
+ // "copy" in their names must be released by us!
+ CFRelease(bundlePathCFS);
+ CFRelease(bundleURL);
+ CFRelease(appBundle);
+#endif
+
+ return executable;
+}
+
+bool cmFindProgram(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return cmFindProgramCommand(status).InitialPass(args);
+}
diff --git a/Source/cmFindProgramCommand.h b/Source/cmFindProgramCommand.h
new file mode 100644
index 0000000..161a680
--- /dev/null
+++ b/Source/cmFindProgramCommand.h
@@ -0,0 +1,39 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmFindBase.h"
+
+class cmExecutionStatus;
+
+/** \class cmFindProgramCommand
+ * \brief Define a command to search for an executable program.
+ *
+ * cmFindProgramCommand is used to define a CMake variable
+ * that specifies an executable program. The command searches
+ * in the current path (e.g., PATH environment variable) for
+ * an executable that matches one of the supplied names.
+ */
+class cmFindProgramCommand : public cmFindBase
+{
+public:
+ cmFindProgramCommand(cmExecutionStatus& status);
+
+ bool InitialPass(std::vector<std::string> const& args);
+
+private:
+ std::string FindProgram();
+ std::string FindNormalProgram();
+ std::string FindNormalProgramDirsPerName();
+ std::string FindNormalProgramNamesPerDir();
+ std::string FindAppBundle();
+ std::string GetBundleExecutable(std::string const& bundlePath);
+};
+
+bool cmFindProgram(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx
new file mode 100644
index 0000000..bcacb15
--- /dev/null
+++ b/Source/cmForEachCommand.cxx
@@ -0,0 +1,469 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmForEachCommand.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef> // IWYU pragma: keep
+// NOTE The declaration of `std::abs` has moved to `cmath` since C++17
+// See https://en.cppreference.com/w/cpp/numeric/math/abs
+// ALERT But IWYU used to lint `#include`s do not "understand"
+// conditional compilation (i.e. `#if __cplusplus >= 201703L`)
+#include <cstdlib>
+#include <iterator>
+#include <map>
+#include <sstream>
+#include <stdexcept>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmExecutionStatus.h"
+#include "cmFunctionBlocker.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+class cmForEachFunctionBlocker : public cmFunctionBlocker
+{
+public:
+ explicit cmForEachFunctionBlocker(cmMakefile* mf);
+ ~cmForEachFunctionBlocker() override;
+
+ cm::string_view StartCommandName() const override { return "foreach"_s; }
+ cm::string_view EndCommandName() const override { return "endforeach"_s; }
+
+ bool ArgumentsMatch(cmListFileFunction const& lff,
+ cmMakefile& mf) const override;
+
+ bool Replay(std::vector<cmListFileFunction> functions,
+ cmExecutionStatus& inStatus) override;
+
+ void SetIterationVarsCount(const std::size_t varsCount)
+ {
+ this->IterationVarsCount = varsCount;
+ }
+ void SetZipLists() { this->ZipLists = true; }
+
+ std::vector<std::string> Args;
+
+private:
+ struct InvokeResult
+ {
+ bool Restore;
+ bool Break;
+ };
+
+ bool ReplayItems(std::vector<cmListFileFunction> const& functions,
+ cmExecutionStatus& inStatus);
+
+ bool ReplayZipLists(std::vector<cmListFileFunction> const& functions,
+ cmExecutionStatus& inStatus);
+
+ InvokeResult invoke(std::vector<cmListFileFunction> const& functions,
+ cmExecutionStatus& inStatus, cmMakefile& mf);
+
+ cmMakefile* Makefile;
+ std::size_t IterationVarsCount = 0u;
+ bool ZipLists = false;
+};
+
+cmForEachFunctionBlocker::cmForEachFunctionBlocker(cmMakefile* mf)
+ : Makefile(mf)
+{
+ this->Makefile->PushLoopBlock();
+}
+
+cmForEachFunctionBlocker::~cmForEachFunctionBlocker()
+{
+ this->Makefile->PopLoopBlock();
+}
+
+bool cmForEachFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
+ cmMakefile& mf) const
+{
+ std::vector<std::string> expandedArguments;
+ mf.ExpandArguments(lff.Arguments(), expandedArguments);
+ return expandedArguments.empty() ||
+ expandedArguments.front() == this->Args.front();
+}
+
+bool cmForEachFunctionBlocker::Replay(
+ std::vector<cmListFileFunction> functions, cmExecutionStatus& inStatus)
+{
+ return this->ZipLists ? this->ReplayZipLists(functions, inStatus)
+ : this->ReplayItems(functions, inStatus);
+}
+
+bool cmForEachFunctionBlocker::ReplayItems(
+ std::vector<cmListFileFunction> const& functions,
+ cmExecutionStatus& inStatus)
+{
+ assert("Unexpected number of iteration variables" &&
+ this->IterationVarsCount == 1);
+
+ auto& mf = inStatus.GetMakefile();
+
+ // At end of for each execute recorded commands
+ // store the old value
+ std::string oldDef;
+ if (cmProp d = mf.GetDefinition(this->Args.front())) {
+ oldDef = *d;
+ }
+
+ auto restore = false;
+ for (std::string const& arg : cmMakeRange(this->Args).advance(1)) {
+ // Set the variable to the loop value
+ mf.AddDefinition(this->Args.front(), arg);
+ // Invoke all the functions that were collected in the block.
+ auto r = this->invoke(functions, inStatus, mf);
+ restore = r.Restore;
+ if (r.Break) {
+ break;
+ }
+ }
+
+ if (restore) {
+ // restore the variable to its prior value
+ mf.AddDefinition(this->Args.front(), oldDef);
+ }
+ return true;
+}
+
+bool cmForEachFunctionBlocker::ReplayZipLists(
+ std::vector<cmListFileFunction> const& functions,
+ cmExecutionStatus& inStatus)
+{
+ assert("Unexpected number of iteration variables" &&
+ this->IterationVarsCount >= 1);
+
+ auto& mf = inStatus.GetMakefile();
+
+ // Expand the list of list-variables into a list of lists of strings
+ std::vector<std::vector<std::string>> values;
+ values.reserve(this->Args.size() - this->IterationVarsCount);
+ // Also track the longest list size
+ std::size_t maxItems = 0u;
+ for (auto const& var :
+ cmMakeRange(this->Args).advance(this->IterationVarsCount)) {
+ std::vector<std::string> items;
+ auto const& value = mf.GetSafeDefinition(var);
+ if (!value.empty()) {
+ cmExpandList(value, items, true);
+ }
+ maxItems = std::max(maxItems, items.size());
+ values.emplace_back(std::move(items));
+ }
+
+ // Form the list of iteration variables
+ std::vector<std::string> iterationVars;
+ if (this->IterationVarsCount > 1) {
+ // If multiple iteration variables has given,
+ // just copy them to the `iterationVars` list.
+ iterationVars.reserve(values.size());
+ std::copy(this->Args.begin(),
+ this->Args.begin() + this->IterationVarsCount,
+ std::back_inserter(iterationVars));
+ } else {
+ // In case of the only iteration variable,
+ // generate names as `var_name_N`,
+ // where `N` is the count of lists to zip
+ iterationVars.resize(values.size());
+ const auto iter_var_prefix = this->Args.front() + "_";
+ auto i = 0u;
+ std::generate(
+ iterationVars.begin(), iterationVars.end(),
+ [&]() -> std::string { return iter_var_prefix + std::to_string(i++); });
+ }
+ assert("Sanity check" && iterationVars.size() == values.size());
+
+ // Store old values for iteration variables
+ std::map<std::string, std::string> oldDefs;
+ for (auto i = 0u; i < values.size(); ++i) {
+ if (cmProp d = mf.GetDefinition(iterationVars[i])) {
+ oldDefs.emplace(iterationVars[i], *d);
+ }
+ }
+
+ // Form a vector of current positions in all lists (Ok, vectors) of values
+ std::vector<decltype(values)::value_type::iterator> positions;
+ positions.reserve(values.size());
+ std::transform(
+ values.begin(), values.end(), std::back_inserter(positions),
+ // Set the initial position to the beginning of every list
+ [](decltype(values)::value_type& list) { return list.begin(); });
+ assert("Sanity check" && positions.size() == values.size());
+
+ auto restore = false;
+ // Iterate over all the lists simulateneously
+ for (auto i = 0u; i < maxItems; ++i) {
+ // Declare iteration variables
+ for (auto j = 0u; j < values.size(); ++j) {
+ // Define (or not) the iteration variable if the current position
+ // still not at the end...
+ if (positions[j] != values[j].end()) {
+ mf.AddDefinition(iterationVars[j], *positions[j]);
+ ++positions[j];
+ } else {
+ mf.RemoveDefinition(iterationVars[j]);
+ }
+ }
+ // Invoke all the functions that were collected in the block.
+ auto r = this->invoke(functions, inStatus, mf);
+ restore = r.Restore;
+ if (r.Break) {
+ break;
+ }
+ }
+
+ // Restore the variables to its prior value
+ if (restore) {
+ for (auto const& p : oldDefs) {
+ mf.AddDefinition(p.first, p.second);
+ }
+ }
+ return true;
+}
+
+auto cmForEachFunctionBlocker::invoke(
+ std::vector<cmListFileFunction> const& functions,
+ cmExecutionStatus& inStatus, cmMakefile& mf) -> InvokeResult
+{
+ InvokeResult result = { true, false };
+ // Invoke all the functions that were collected in the block.
+ for (cmListFileFunction const& func : functions) {
+ cmExecutionStatus status(mf);
+ mf.ExecuteCommand(func, status);
+ if (status.GetReturnInvoked()) {
+ inStatus.SetReturnInvoked();
+ result.Break = true;
+ break;
+ }
+ if (status.GetBreakInvoked()) {
+ result.Break = true;
+ break;
+ }
+ if (status.GetContinueInvoked()) {
+ break;
+ }
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ result.Restore = false;
+ result.Break = true;
+ break;
+ }
+ }
+ return result;
+}
+
+bool HandleInMode(std::vector<std::string> const& args,
+ std::vector<std::string>::const_iterator kwInIter,
+ cmMakefile& makefile)
+{
+ assert("A valid iterator expected" && kwInIter != args.end());
+
+ auto fb = cm::make_unique<cmForEachFunctionBlocker>(&makefile);
+
+ // Copy iteration variable names first
+ std::copy(args.begin(), kwInIter, std::back_inserter(fb->Args));
+ // Remember the count of given iteration variable names
+ const auto varsCount = fb->Args.size();
+ fb->SetIterationVarsCount(varsCount);
+
+ enum Doing
+ {
+ DoingNone,
+ DoingLists,
+ DoingItems,
+ DoingZipLists
+ };
+ Doing doing = DoingNone;
+ // Iterate over arguments past the "IN" keyword
+ for (std::string const& arg : cmMakeRange(++kwInIter, args.end())) {
+ if (arg == "LISTS") {
+ if (doing == DoingZipLists) {
+ makefile.IssueMessage(MessageType::FATAL_ERROR,
+ "ZIP_LISTS can not be used with LISTS or ITEMS");
+ return true;
+ }
+ if (varsCount != 1u) {
+ makefile.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "ITEMS or LISTS require exactly one iteration variable");
+ return true;
+ }
+ doing = DoingLists;
+
+ } else if (arg == "ITEMS") {
+ if (doing == DoingZipLists) {
+ makefile.IssueMessage(MessageType::FATAL_ERROR,
+ "ZIP_LISTS can not be used with LISTS or ITEMS");
+ return true;
+ }
+ if (varsCount != 1u) {
+ makefile.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "ITEMS or LISTS require exactly one iteration variable");
+ return true;
+ }
+ doing = DoingItems;
+
+ } else if (arg == "ZIP_LISTS") {
+ if (doing != DoingNone) {
+ makefile.IssueMessage(MessageType::FATAL_ERROR,
+ "ZIP_LISTS can not be used with LISTS or ITEMS");
+ return true;
+ }
+ doing = DoingZipLists;
+ fb->SetZipLists();
+
+ } else if (doing == DoingLists) {
+ auto const& value = makefile.GetSafeDefinition(arg);
+ if (!value.empty()) {
+ cmExpandList(value, fb->Args, true);
+ }
+
+ } else if (doing == DoingItems || doing == DoingZipLists) {
+ fb->Args.push_back(arg);
+
+ } else {
+ makefile.IssueMessage(MessageType::FATAL_ERROR,
+ cmStrCat("Unknown argument:\n", " ", arg, "\n"));
+ return true;
+ }
+ }
+
+ // If `ZIP_LISTS` given and variables count more than 1,
+ // make sure the given lists count matches variables...
+ if (doing == DoingZipLists && varsCount > 1u &&
+ (2u * varsCount) != fb->Args.size()) {
+ makefile.IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Expected ", std::to_string(varsCount),
+ " list variables, but given ",
+ std::to_string(fb->Args.size() - varsCount)));
+ return true;
+ }
+
+ makefile.AddFunctionBlocker(std::move(fb));
+
+ return true;
+}
+
+bool TryParseInteger(cmExecutionStatus& status, const std::string& str, int& i)
+{
+ try {
+ i = std::stoi(str);
+ } catch (std::invalid_argument&) {
+ std::ostringstream e;
+ e << "Invalid integer: '" << str << "'";
+ status.SetError(e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ } catch (std::out_of_range&) {
+ std::ostringstream e;
+ e << "Integer out of range: '" << str << "'";
+ status.SetError(e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ return true;
+}
+
+} // anonymous namespace
+
+bool cmForEachCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ auto kwInIter = std::find(args.begin(), args.end(), "IN");
+ if (kwInIter != args.end()) {
+ return HandleInMode(args, kwInIter, status.GetMakefile());
+ }
+
+ // create a function blocker
+ auto fb = cm::make_unique<cmForEachFunctionBlocker>(&status.GetMakefile());
+ if (args.size() > 1) {
+ if (args[1] == "RANGE") {
+ int start = 0;
+ int stop = 0;
+ int step = 0;
+ if (args.size() == 3) {
+ if (!TryParseInteger(status, args[2], stop)) {
+ return false;
+ }
+ }
+ if (args.size() == 4) {
+ if (!TryParseInteger(status, args[2], start)) {
+ return false;
+ }
+ if (!TryParseInteger(status, args[3], stop)) {
+ return false;
+ }
+ }
+ if (args.size() == 5) {
+ if (!TryParseInteger(status, args[2], start)) {
+ return false;
+ }
+ if (!TryParseInteger(status, args[3], stop)) {
+ return false;
+ }
+ if (!TryParseInteger(status, args[4], step)) {
+ return false;
+ }
+ }
+ if (step == 0) {
+ if (start > stop) {
+ step = -1;
+ } else {
+ step = 1;
+ }
+ }
+ if ((start > stop && step > 0) || (start < stop && step < 0) ||
+ step == 0) {
+ status.SetError(
+ cmStrCat("called with incorrect range specification: start ", start,
+ ", stop ", stop, ", step ", step));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ // Calculate expected iterations count and reserve enough space
+ // in the `fb->Args` vector. The first item is the iteration variable
+ // name...
+ const std::size_t iter_cnt = 2u +
+ int(start < stop) * (stop - start) / std::abs(step) +
+ int(start > stop) * (start - stop) / std::abs(step);
+ fb->Args.resize(iter_cnt);
+ fb->Args.front() = args.front();
+ auto cc = start;
+ auto generator = [&cc, step]() -> std::string {
+ auto result = std::to_string(cc);
+ cc += step;
+ return result;
+ };
+ // Fill the `range` vector w/ generated string values
+ // (starting from 2nd position)
+ std::generate(++fb->Args.begin(), fb->Args.end(), generator);
+ } else {
+ fb->Args = args;
+ }
+ } else {
+ fb->Args = args;
+ }
+
+ fb->SetIterationVarsCount(1u);
+ status.GetMakefile().AddFunctionBlocker(std::move(fb));
+
+ return true;
+}
diff --git a/Source/cmForEachCommand.h b/Source/cmForEachCommand.h
new file mode 100644
index 0000000..6476fea
--- /dev/null
+++ b/Source/cmForEachCommand.h
@@ -0,0 +1,14 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/// Starts foreach() ... endforeach() block
+bool cmForEachCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmFortranParser.h b/Source/cmFortranParser.h
new file mode 100644
index 0000000..1b14d17
--- /dev/null
+++ b/Source/cmFortranParser.h
@@ -0,0 +1,182 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#if !defined(cmFortranLexer_cxx) && !defined(cmFortranParser_cxx)
+# include "cmConfigure.h" // IWYU pragma: keep
+
+# include <set>
+# include <string>
+# include <utility>
+# include <vector>
+#endif
+
+#include <cstddef> /* size_t */
+
+/* Forward declare parser object type. */
+using cmFortranParser = struct cmFortranParser_s;
+
+/* Functions to enter/exit #include'd files in order. */
+bool cmFortranParser_FilePush(cmFortranParser* parser, const char* fname);
+bool cmFortranParser_FilePop(cmFortranParser* parser);
+
+/* Callbacks for lexer. */
+int cmFortranParser_Input(cmFortranParser* parser, char* buffer,
+ size_t bufferSize);
+
+void cmFortranParser_StringStart(cmFortranParser* parser);
+const char* cmFortranParser_StringEnd(cmFortranParser* parser);
+void cmFortranParser_StringAppend(cmFortranParser* parser, char c);
+
+void cmFortranParser_SetInInterface(cmFortranParser* parser, bool is_in);
+bool cmFortranParser_GetInInterface(cmFortranParser* parser);
+
+void cmFortranParser_SetInPPFalseBranch(cmFortranParser* parser, bool is_in);
+bool cmFortranParser_GetInPPFalseBranch(cmFortranParser* parser);
+
+void cmFortranParser_SetOldStartcond(cmFortranParser* parser, int arg);
+int cmFortranParser_GetOldStartcond(cmFortranParser* parser);
+
+/* Callbacks for parser. */
+void cmFortranParser_Error(cmFortranParser* parser, const char* message);
+void cmFortranParser_RuleUse(cmFortranParser* parser, const char* module_name);
+void cmFortranParser_RuleLineDirective(cmFortranParser* parser,
+ const char* filename);
+void cmFortranParser_RuleInclude(cmFortranParser* parser, const char* name);
+void cmFortranParser_RuleModule(cmFortranParser* parser,
+ const char* module_name);
+void cmFortranParser_RuleSubmodule(cmFortranParser* parser,
+ const char* module_name,
+ const char* submodule_name);
+void cmFortranParser_RuleSubmoduleNested(cmFortranParser* parser,
+ const char* module_name,
+ const char* submodule_name,
+ const char* nested_submodule_name);
+void cmFortranParser_RuleDefine(cmFortranParser* parser, const char* name);
+void cmFortranParser_RuleUndef(cmFortranParser* parser, const char* name);
+void cmFortranParser_RuleIfdef(cmFortranParser* parser, const char* name);
+void cmFortranParser_RuleIfndef(cmFortranParser* parser, const char* name);
+void cmFortranParser_RuleIf(cmFortranParser* parser);
+void cmFortranParser_RuleElif(cmFortranParser* parser);
+void cmFortranParser_RuleElse(cmFortranParser* parser);
+void cmFortranParser_RuleEndif(cmFortranParser* parser);
+
+/* Define the parser stack element type. */
+struct cmFortran_yystype
+{
+ char* string;
+};
+
+/* Setup the proper yylex interface. */
+#define YY_EXTRA_TYPE cmFortranParser*
+#define YY_DECL int cmFortran_yylex(YYSTYPE* yylvalp, yyscan_t yyscanner)
+#define YYSTYPE cmFortran_yystype
+#define YYSTYPE_IS_DECLARED 1
+#if !defined(cmFortranLexer_cxx)
+# define YY_NO_UNISTD_H
+# include "cmFortranLexer.h"
+#endif
+#if !defined(cmFortranLexer_cxx)
+# if !defined(cmFortranParser_cxx)
+# undef YY_EXTRA_TYPE
+# undef YY_DECL
+# undef YYSTYPE
+# undef YYSTYPE_IS_DECLARED
+# endif
+#endif
+
+#if !defined(cmFortranLexer_cxx) && !defined(cmFortranParser_cxx)
+# include <stack>
+
+// Information about a single source file.
+class cmFortranSourceInfo
+{
+public:
+ // The name of the source file.
+ std::string Source;
+
+ // Set of provided and required modules.
+ std::set<std::string> Provides;
+ std::set<std::string> Requires;
+
+ // Set of files included in the translation unit.
+ std::set<std::string> Includes;
+};
+
+// Parser methods not included in generated interface.
+
+// Get the current buffer processed by the lexer.
+YY_BUFFER_STATE cmFortranLexer_GetCurrentBuffer(yyscan_t yyscanner);
+
+// The parser entry point.
+int cmFortran_yyparse(yyscan_t);
+
+// Define parser object internal structure.
+struct cmFortranFile
+{
+ cmFortranFile(FILE* file, YY_BUFFER_STATE buffer, std::string dir)
+ : File(file)
+ , Buffer(buffer)
+ , Directory(std::move(dir))
+ , LastCharWasNewline(false)
+ {
+ }
+ FILE* File;
+ YY_BUFFER_STATE Buffer;
+ std::string Directory;
+ bool LastCharWasNewline;
+};
+
+struct cmFortranCompiler
+{
+ std::string Id;
+ std::string SModSep;
+ std::string SModExt;
+};
+
+struct cmFortranParser_s
+{
+ cmFortranParser_s(cmFortranCompiler fc, std::vector<std::string> includes,
+ std::set<std::string> defines, cmFortranSourceInfo& info);
+ ~cmFortranParser_s();
+
+ cmFortranParser_s(const cmFortranParser_s&) = delete;
+ cmFortranParser_s& operator=(const cmFortranParser_s&) = delete;
+
+ bool FindIncludeFile(const char* dir, const char* includeName,
+ std::string& fileName);
+
+ std::string ModName(std::string const& mod_name) const;
+ std::string SModName(std::string const& mod_name,
+ std::string const& sub_name) const;
+
+ // What compiler.
+ cmFortranCompiler Compiler;
+
+ // The include file search path.
+ std::vector<std::string> IncludePath;
+
+ // Lexical scanner instance.
+ yyscan_t Scanner;
+
+ // Stack of open files in the translation unit.
+ std::stack<cmFortranFile> FileStack;
+
+ // Buffer for string literals.
+ std::string TokenString;
+
+ // Error message text if a parser error occurs.
+ std::string Error;
+
+ // Flag for whether lexer is reading from inside an interface.
+ bool InInterface;
+
+ int OldStartcond;
+ std::set<std::string> PPDefinitions;
+ size_t InPPFalseBranch;
+ std::stack<bool> SkipToEnd;
+
+ // Information about the parsed source.
+ cmFortranSourceInfo& Info;
+};
+#endif
diff --git a/Source/cmFortranParserImpl.cxx b/Source/cmFortranParserImpl.cxx
new file mode 100644
index 0000000..054a2a9
--- /dev/null
+++ b/Source/cmFortranParserImpl.cxx
@@ -0,0 +1,433 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include <cassert>
+#include <cstdio>
+#include <set>
+#include <stack>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmFortranParser.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+bool cmFortranParser_s::FindIncludeFile(const char* dir,
+ const char* includeName,
+ std::string& fileName)
+{
+ // If the file is a full path, include it directly.
+ if (cmSystemTools::FileIsFullPath(includeName)) {
+ fileName = includeName;
+ return cmSystemTools::FileExists(fileName, true);
+ }
+ // Check for the file in the directory containing the including
+ // file.
+ std::string fullName = cmStrCat(dir, '/', includeName);
+ if (cmSystemTools::FileExists(fullName, true)) {
+ fileName = fullName;
+ return true;
+ }
+
+ // Search the include path for the file.
+ for (std::string const& i : this->IncludePath) {
+ fullName = cmStrCat(i, '/', includeName);
+ if (cmSystemTools::FileExists(fullName, true)) {
+ fileName = fullName;
+ return true;
+ }
+ }
+ return false;
+}
+
+cmFortranParser_s::cmFortranParser_s(cmFortranCompiler fc,
+ std::vector<std::string> includes,
+ std::set<std::string> defines,
+ cmFortranSourceInfo& info)
+ : Compiler(std::move(fc))
+ , IncludePath(std::move(includes))
+ , PPDefinitions(std::move(defines))
+ , Info(info)
+{
+ this->InInterface = false;
+ this->InPPFalseBranch = 0;
+
+ // Initialize the lexical scanner.
+ cmFortran_yylex_init(&this->Scanner);
+ cmFortran_yyset_extra(this, this->Scanner);
+
+ // Create a dummy buffer that is never read but is the fallback
+ // buffer when the last file is popped off the stack.
+ YY_BUFFER_STATE buffer =
+ cmFortran_yy_create_buffer(nullptr, 4, this->Scanner);
+ cmFortran_yy_switch_to_buffer(buffer, this->Scanner);
+}
+
+cmFortranParser_s::~cmFortranParser_s()
+{
+ cmFortran_yylex_destroy(this->Scanner);
+}
+
+std::string cmFortranParser_s::ModName(std::string const& mod_name) const
+{
+ return mod_name + ".mod";
+}
+
+std::string cmFortranParser_s::SModName(std::string const& mod_name,
+ std::string const& sub_name) const
+{
+ std::string const& SModExt =
+ this->Compiler.SModExt.empty() ? ".mod" : this->Compiler.SModExt;
+ // An empty separator means that the compiler does not use a prefix.
+ if (this->Compiler.SModSep.empty()) {
+ return sub_name + SModExt;
+ }
+ return mod_name + this->Compiler.SModSep + sub_name + SModExt;
+}
+
+bool cmFortranParser_FilePush(cmFortranParser* parser, const char* fname)
+{
+ // Open the new file and push it onto the stack. Save the old
+ // buffer with it on the stack.
+ if (FILE* file = cmsys::SystemTools::Fopen(fname, "rb")) {
+ YY_BUFFER_STATE current = cmFortranLexer_GetCurrentBuffer(parser->Scanner);
+ std::string dir = cmSystemTools::GetParentDirectory(fname);
+ cmFortranFile f(file, current, dir);
+ YY_BUFFER_STATE buffer =
+ cmFortran_yy_create_buffer(nullptr, 16384, parser->Scanner);
+ cmFortran_yy_switch_to_buffer(buffer, parser->Scanner);
+ parser->FileStack.push(f);
+ return true;
+ }
+ return false;
+}
+
+bool cmFortranParser_FilePop(cmFortranParser* parser)
+{
+ // Pop one file off the stack and close it. Switch the lexer back
+ // to the next one on the stack.
+ if (parser->FileStack.empty()) {
+ return false;
+ }
+ cmFortranFile f = parser->FileStack.top();
+ parser->FileStack.pop();
+ fclose(f.File);
+ YY_BUFFER_STATE current = cmFortranLexer_GetCurrentBuffer(parser->Scanner);
+ cmFortran_yy_delete_buffer(current, parser->Scanner);
+ cmFortran_yy_switch_to_buffer(f.Buffer, parser->Scanner);
+ return true;
+}
+
+int cmFortranParser_Input(cmFortranParser* parser, char* buffer,
+ size_t bufferSize)
+{
+ // Read from the file on top of the stack. If the stack is empty,
+ // the end of the translation unit has been reached.
+ if (!parser->FileStack.empty()) {
+ cmFortranFile& ff = parser->FileStack.top();
+ FILE* file = ff.File;
+ size_t n = fread(buffer, 1, bufferSize, file);
+ if (n > 0) {
+ ff.LastCharWasNewline = buffer[n - 1] == '\n';
+ } else if (!ff.LastCharWasNewline) {
+ // The file ended without a newline. Inject one so
+ // that the file always ends in an end-of-statement.
+ buffer[0] = '\n';
+ n = 1;
+ ff.LastCharWasNewline = true;
+ }
+ return static_cast<int>(n);
+ }
+ return 0;
+}
+
+void cmFortranParser_StringStart(cmFortranParser* parser)
+{
+ parser->TokenString.clear();
+}
+
+const char* cmFortranParser_StringEnd(cmFortranParser* parser)
+{
+ return parser->TokenString.c_str();
+}
+
+void cmFortranParser_StringAppend(cmFortranParser* parser, char c)
+{
+ parser->TokenString += c;
+}
+
+void cmFortranParser_SetInInterface(cmFortranParser* parser, bool in)
+{
+ if (parser->InPPFalseBranch) {
+ return;
+ }
+
+ parser->InInterface = in;
+}
+
+bool cmFortranParser_GetInInterface(cmFortranParser* parser)
+{
+ return parser->InInterface;
+}
+
+void cmFortranParser_SetOldStartcond(cmFortranParser* parser, int arg)
+{
+ parser->OldStartcond = arg;
+}
+
+int cmFortranParser_GetOldStartcond(cmFortranParser* parser)
+{
+ return parser->OldStartcond;
+}
+
+void cmFortranParser_Error(cmFortranParser* parser, const char* msg)
+{
+ parser->Error = msg ? msg : "unknown error";
+}
+
+void cmFortranParser_RuleUse(cmFortranParser* parser, const char* module_name)
+{
+ if (parser->InPPFalseBranch) {
+ return;
+ }
+
+ // syntax: "use module_name"
+ // requires: "module_name.mod"
+ std::string const& mod_name = cmSystemTools::LowerCase(module_name);
+ parser->Info.Requires.insert(parser->ModName(mod_name));
+}
+
+void cmFortranParser_RuleLineDirective(cmFortranParser* parser,
+ const char* filename)
+{
+ // This is a #line directive naming a file encountered during preprocessing.
+ std::string included = filename;
+
+ // Skip #line directives referencing non-files like
+ // "<built-in>" or "<command-line>".
+ if (included.empty() || included[0] == '<') {
+ return;
+ }
+
+ // Fix windows file path separators since our lexer does not
+ // process escape sequences in string literals.
+ cmSystemTools::ReplaceString(included, "\\\\", "\\");
+ cmSystemTools::ConvertToUnixSlashes(included);
+
+ // Save the named file as included in the source.
+ if (cmSystemTools::FileExists(included, true)) {
+ parser->Info.Includes.insert(included);
+ }
+}
+
+void cmFortranParser_RuleInclude(cmFortranParser* parser, const char* name)
+{
+ if (parser->InPPFalseBranch) {
+ return;
+ }
+
+ // If processing an include statement there must be an open file.
+ assert(!parser->FileStack.empty());
+
+ // Get the directory containing the source in which the include
+ // statement appears. This is always the first search location for
+ // Fortran include files.
+ std::string dir = parser->FileStack.top().Directory;
+
+ // Find the included file. If it cannot be found just ignore the
+ // problem because either the source will not compile or the user
+ // does not care about depending on this included source.
+ std::string fullName;
+ if (parser->FindIncludeFile(dir.c_str(), name, fullName)) {
+ // Found the included file. Save it in the set of included files.
+ parser->Info.Includes.insert(fullName);
+
+ // Parse it immediately to translate the source inline.
+ cmFortranParser_FilePush(parser, fullName.c_str());
+ }
+}
+
+void cmFortranParser_RuleModule(cmFortranParser* parser,
+ const char* module_name)
+{
+ if (parser->InPPFalseBranch) {
+ return;
+ }
+
+ if (!parser->InInterface) {
+ // syntax: "module module_name"
+ // provides: "module_name.mod"
+ std::string const& mod_name = cmSystemTools::LowerCase(module_name);
+ parser->Info.Provides.insert(parser->ModName(mod_name));
+ }
+}
+
+void cmFortranParser_RuleSubmodule(cmFortranParser* parser,
+ const char* module_name,
+ const char* submodule_name)
+{
+ if (parser->InPPFalseBranch) {
+ return;
+ }
+
+ // syntax: "submodule (module_name) submodule_name"
+ // requires: "module_name.mod"
+ // provides: "module_name@submodule_name.smod"
+ //
+ // FIXME: Some compilers split the submodule part of a module into a
+ // separate "module_name.smod" file. Whether it is generated or
+ // not depends on conditions more subtle than we currently detect.
+ // For now we depend directly on "module_name.mod".
+
+ std::string const& mod_name = cmSystemTools::LowerCase(module_name);
+ std::string const& sub_name = cmSystemTools::LowerCase(submodule_name);
+ parser->Info.Requires.insert(parser->ModName(mod_name));
+ parser->Info.Provides.insert(parser->SModName(mod_name, sub_name));
+}
+
+void cmFortranParser_RuleSubmoduleNested(cmFortranParser* parser,
+ const char* module_name,
+ const char* submodule_name,
+ const char* nested_submodule_name)
+{
+ if (parser->InPPFalseBranch) {
+ return;
+ }
+
+ // syntax: "submodule (module_name:submodule_name) nested_submodule_name"
+ // requires: "module_name@submodule_name.smod"
+ // provides: "module_name@nested_submodule_name.smod"
+
+ std::string const& mod_name = cmSystemTools::LowerCase(module_name);
+ std::string const& sub_name = cmSystemTools::LowerCase(submodule_name);
+ std::string const& nest_name =
+ cmSystemTools::LowerCase(nested_submodule_name);
+ parser->Info.Requires.insert(parser->SModName(mod_name, sub_name));
+ parser->Info.Provides.insert(parser->SModName(mod_name, nest_name));
+}
+
+void cmFortranParser_RuleDefine(cmFortranParser* parser, const char* macro)
+{
+ if (!parser->InPPFalseBranch) {
+ parser->PPDefinitions.insert(macro);
+ }
+}
+
+void cmFortranParser_RuleUndef(cmFortranParser* parser, const char* macro)
+{
+ if (!parser->InPPFalseBranch) {
+ std::set<std::string>::iterator match;
+ match = parser->PPDefinitions.find(macro);
+ if (match != parser->PPDefinitions.end()) {
+ parser->PPDefinitions.erase(match);
+ }
+ }
+}
+
+void cmFortranParser_RuleIfdef(cmFortranParser* parser, const char* macro)
+{
+ // A new PP branch has been opened
+ parser->SkipToEnd.push(false);
+
+ if (parser->InPPFalseBranch) {
+ parser->InPPFalseBranch++;
+ } else if (parser->PPDefinitions.find(macro) ==
+ parser->PPDefinitions.end()) {
+ parser->InPPFalseBranch = 1;
+ } else {
+ parser->SkipToEnd.top() = true;
+ }
+}
+
+void cmFortranParser_RuleIfndef(cmFortranParser* parser, const char* macro)
+{
+ // A new PP branch has been opened
+ parser->SkipToEnd.push(false);
+
+ if (parser->InPPFalseBranch) {
+ parser->InPPFalseBranch++;
+ } else if (parser->PPDefinitions.find(macro) !=
+ parser->PPDefinitions.end()) {
+ parser->InPPFalseBranch = 1;
+ } else {
+ // ignore other branches
+ parser->SkipToEnd.top() = true;
+ }
+}
+
+void cmFortranParser_RuleIf(cmFortranParser* parser)
+{
+ /* Note: The current parser is _not_ able to get statements like
+ * #if 0
+ * #if 1
+ * #if MYSMBOL
+ * #if defined(MYSYMBOL)
+ * #if defined(MYSYMBOL) && ...
+ * right. The same for #elif. Thus in
+ * #if SYMBOL_1
+ * ..
+ * #elif SYMBOL_2
+ * ...
+ * ...
+ * #elif SYMBOL_N
+ * ..
+ * #else
+ * ..
+ * #endif
+ * _all_ N+1 branches are considered. If you got something like this
+ * #if defined(MYSYMBOL)
+ * #if !defined(MYSYMBOL)
+ * use
+ * #ifdef MYSYMBOL
+ * #ifndef MYSYMBOL
+ * instead.
+ */
+
+ // A new PP branch has been opened
+ // Never skip! See note above.
+ parser->SkipToEnd.push(false);
+}
+
+void cmFortranParser_RuleElif(cmFortranParser* parser)
+{
+ /* Note: There are parser limitations. See the note at
+ * cmFortranParser_RuleIf(..)
+ */
+
+ // Always taken unless an #ifdef or #ifndef-branch has been taken
+ // already. If the second condition isn't meet already
+ // (parser->InPPFalseBranch == 0) correct it.
+ if (!parser->SkipToEnd.empty() && parser->SkipToEnd.top() &&
+ !parser->InPPFalseBranch) {
+ parser->InPPFalseBranch = 1;
+ }
+}
+
+void cmFortranParser_RuleElse(cmFortranParser* parser)
+{
+ // if the parent branch is false do nothing!
+ if (parser->InPPFalseBranch > 1) {
+ return;
+ }
+
+ // parser->InPPFalseBranch is either 0 or 1. We change it depending on
+ // parser->SkipToEnd.top()
+ if (!parser->SkipToEnd.empty() && parser->SkipToEnd.top()) {
+ parser->InPPFalseBranch = 1;
+ } else {
+ parser->InPPFalseBranch = 0;
+ }
+}
+
+void cmFortranParser_RuleEndif(cmFortranParser* parser)
+{
+ if (!parser->SkipToEnd.empty()) {
+ parser->SkipToEnd.pop();
+ }
+
+ // #endif doesn't know if there was a "#else" in before, so it
+ // always decreases InPPFalseBranch
+ if (parser->InPPFalseBranch) {
+ parser->InPPFalseBranch--;
+ }
+}
diff --git a/Source/cmFunctionBlocker.cxx b/Source/cmFunctionBlocker.cxx
new file mode 100644
index 0000000..d4666d7
--- /dev/null
+++ b/Source/cmFunctionBlocker.cxx
@@ -0,0 +1,48 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFunctionBlocker.h"
+
+#include <cassert>
+#include <memory> // IWYU pragma: keep
+#include <sstream>
+#include <string> // IWYU pragma: keep
+#include <utility>
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+
+bool cmFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
+ cmExecutionStatus& status)
+{
+ if (lff.LowerCaseName() == this->StartCommandName()) {
+ this->ScopeDepth++;
+ } else if (lff.LowerCaseName() == this->EndCommandName()) {
+ this->ScopeDepth--;
+ if (this->ScopeDepth == 0U) {
+ cmMakefile& mf = status.GetMakefile();
+ auto self = mf.RemoveFunctionBlocker();
+ assert(self.get() == this);
+
+ if (!this->ArgumentsMatch(lff, mf)) {
+ cmListFileContext const& lfc = this->GetStartingContext();
+ cmListFileContext closingContext =
+ cmListFileContext::FromCommandContext(lff, lfc.FilePath);
+ std::ostringstream e;
+ /* clang-format off */
+ e << "A logical block opening on the line\n"
+ << " " << lfc << "\n"
+ << "closes on the line\n"
+ << " " << closingContext << "\n"
+ << "with mis-matching arguments.";
+ /* clang-format on */
+ mf.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+ }
+
+ return this->Replay(std::move(this->Functions), status);
+ }
+ }
+
+ this->Functions.push_back(lff);
+ return true;
+}
diff --git a/Source/cmFunctionBlocker.h b/Source/cmFunctionBlocker.h
new file mode 100644
index 0000000..38abeba
--- /dev/null
+++ b/Source/cmFunctionBlocker.h
@@ -0,0 +1,50 @@
+/* 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 <vector>
+
+#include <cm/string_view>
+
+#include "cmListFileCache.h"
+
+class cmExecutionStatus;
+class cmMakefile;
+
+class cmFunctionBlocker
+{
+public:
+ /**
+ * should a function be blocked
+ */
+ bool IsFunctionBlocked(cmListFileFunction const& lff,
+ cmExecutionStatus& status);
+
+ virtual ~cmFunctionBlocker() = default;
+
+ /** Set/Get the context in which this blocker is created. */
+ void SetStartingContext(cmListFileContext const& lfc)
+ {
+ this->StartingContext = lfc;
+ }
+ cmListFileContext const& GetStartingContext() const
+ {
+ return this->StartingContext;
+ }
+
+private:
+ virtual cm::string_view StartCommandName() const = 0;
+ virtual cm::string_view EndCommandName() const = 0;
+
+ virtual bool ArgumentsMatch(cmListFileFunction const& lff,
+ cmMakefile& mf) const = 0;
+
+ virtual bool Replay(std::vector<cmListFileFunction> functions,
+ cmExecutionStatus& status) = 0;
+
+ cmListFileContext StartingContext;
+ std::vector<cmListFileFunction> Functions;
+ unsigned int ScopeDepth = 1;
+};
diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx
new file mode 100644
index 0000000..1359009
--- /dev/null
+++ b/Source/cmFunctionCommand.cxx
@@ -0,0 +1,189 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFunctionCommand.h"
+
+#include <utility>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmExecutionStatus.h"
+#include "cmFunctionBlocker.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmPolicies.h"
+#include "cmRange.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+std::string const ARGC = "ARGC";
+std::string const ARGN = "ARGN";
+std::string const ARGV = "ARGV";
+std::string const CMAKE_CURRENT_FUNCTION = "CMAKE_CURRENT_FUNCTION";
+std::string const CMAKE_CURRENT_FUNCTION_LIST_FILE =
+ "CMAKE_CURRENT_FUNCTION_LIST_FILE";
+std::string const CMAKE_CURRENT_FUNCTION_LIST_DIR =
+ "CMAKE_CURRENT_FUNCTION_LIST_DIR";
+std::string const CMAKE_CURRENT_FUNCTION_LIST_LINE =
+ "CMAKE_CURRENT_FUNCTION_LIST_LINE";
+
+// define the class for function commands
+class cmFunctionHelperCommand
+{
+public:
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool operator()(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& inStatus) const;
+
+ std::vector<std::string> Args;
+ std::vector<cmListFileFunction> Functions;
+ cmPolicies::PolicyMap Policies;
+ std::string FilePath;
+ long Line;
+};
+
+bool cmFunctionHelperCommand::operator()(
+ std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& inStatus) const
+{
+ cmMakefile& makefile = inStatus.GetMakefile();
+
+ // Expand the argument list to the function.
+ std::vector<std::string> expandedArgs;
+ makefile.ExpandArguments(args, expandedArgs);
+
+ // make sure the number of arguments passed is at least the number
+ // required by the signature
+ if (expandedArgs.size() < this->Args.size() - 1) {
+ auto const errorMsg = cmStrCat(
+ "Function invoked with incorrect arguments for function named: ",
+ this->Args.front());
+ inStatus.SetError(errorMsg);
+ return false;
+ }
+
+ cmMakefile::FunctionPushPop functionScope(&makefile, this->FilePath,
+ this->Policies);
+
+ // set the value of argc
+ makefile.AddDefinition(ARGC, std::to_string(expandedArgs.size()));
+ makefile.MarkVariableAsUsed(ARGC);
+
+ // set the values for ARGV0 ARGV1 ...
+ for (auto t = 0u; t < expandedArgs.size(); ++t) {
+ auto const value = cmStrCat(ARGV, std::to_string(t));
+ makefile.AddDefinition(value, expandedArgs[t]);
+ makefile.MarkVariableAsUsed(value);
+ }
+
+ // define the formal arguments
+ for (auto j = 1u; j < this->Args.size(); ++j) {
+ makefile.AddDefinition(this->Args[j], expandedArgs[j - 1]);
+ }
+
+ // define ARGV and ARGN
+ auto const argvDef = cmJoin(expandedArgs, ";");
+ auto const eit = expandedArgs.begin() + (this->Args.size() - 1);
+ auto const argnDef = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";");
+ makefile.AddDefinition(ARGV, argvDef);
+ makefile.MarkVariableAsUsed(ARGV);
+ makefile.AddDefinition(ARGN, argnDef);
+ makefile.MarkVariableAsUsed(ARGN);
+
+ makefile.AddDefinition(CMAKE_CURRENT_FUNCTION, this->Args.front());
+ makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION);
+ makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_FILE, this->FilePath);
+ makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_FILE);
+ makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_DIR,
+ cmSystemTools::GetFilenamePath(this->FilePath));
+ makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_DIR);
+ makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_LINE,
+ std::to_string(this->Line));
+ makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_LINE);
+
+ // Invoke all the functions that were collected in the block.
+ // for each function
+ for (cmListFileFunction const& func : this->Functions) {
+ cmExecutionStatus status(makefile);
+ if (!makefile.ExecuteCommand(func, status) || status.GetNestedError()) {
+ // The error message should have already included the call stack
+ // so we do not need to report an error here.
+ functionScope.Quiet();
+ inStatus.SetNestedError();
+ return false;
+ }
+ if (status.GetReturnInvoked()) {
+ break;
+ }
+ }
+
+ // pop scope on the makefile
+ return true;
+}
+
+class cmFunctionFunctionBlocker : public cmFunctionBlocker
+{
+public:
+ cm::string_view StartCommandName() const override { return "function"_s; }
+ cm::string_view EndCommandName() const override { return "endfunction"_s; }
+
+ bool ArgumentsMatch(cmListFileFunction const&,
+ cmMakefile& mf) const override;
+
+ bool Replay(std::vector<cmListFileFunction> functions,
+ cmExecutionStatus& status) override;
+
+ std::vector<std::string> Args;
+};
+
+bool cmFunctionFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
+ cmMakefile& mf) const
+{
+ std::vector<std::string> expandedArguments;
+ mf.ExpandArguments(lff.Arguments(), expandedArguments);
+ return expandedArguments.empty() ||
+ expandedArguments.front() == this->Args.front();
+}
+
+bool cmFunctionFunctionBlocker::Replay(
+ std::vector<cmListFileFunction> functions, cmExecutionStatus& status)
+{
+ cmMakefile& mf = status.GetMakefile();
+ // create a new command and add it to cmake
+ cmFunctionHelperCommand f;
+ f.Args = this->Args;
+ f.Functions = std::move(functions);
+ f.FilePath = this->GetStartingContext().FilePath;
+ f.Line = this->GetStartingContext().Line;
+ mf.RecordPolicies(f.Policies);
+ return mf.GetState()->AddScriptedCommand(
+ this->Args.front(),
+ BT<cmState::Command>(std::move(f),
+ mf.GetBacktrace().Push(this->GetStartingContext())),
+ mf);
+}
+
+} // anonymous namespace
+
+bool cmFunctionCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // create a function blocker
+ auto fb = cm::make_unique<cmFunctionFunctionBlocker>();
+ cm::append(fb->Args, args);
+ status.GetMakefile().AddFunctionBlocker(std::move(fb));
+
+ return true;
+}
diff --git a/Source/cmFunctionCommand.h b/Source/cmFunctionCommand.h
new file mode 100644
index 0000000..07ff4f7
--- /dev/null
+++ b/Source/cmFunctionCommand.h
@@ -0,0 +1,14 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/// Starts function() ... endfunction() block
+bool cmFunctionCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmGccDepfileLexerHelper.cxx b/Source/cmGccDepfileLexerHelper.cxx
new file mode 100644
index 0000000..afa8e9b
--- /dev/null
+++ b/Source/cmGccDepfileLexerHelper.cxx
@@ -0,0 +1,149 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGccDepfileLexerHelper.h"
+
+#include <cstdio>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "cmGccDepfileReaderTypes.h"
+
+#include "LexerParser/cmGccDepfileLexer.h"
+
+#ifdef _WIN32
+# include <cctype>
+
+# include "cmsys/Encoding.h"
+#endif
+
+bool cmGccDepfileLexerHelper::readFile(const char* filePath)
+{
+#ifdef _WIN32
+ wchar_t* wpath = cmsysEncoding_DupToWide(filePath);
+ FILE* file = _wfopen(wpath, L"rb");
+ free(wpath);
+#else
+ FILE* file = fopen(filePath, "r");
+#endif
+ if (!file) {
+ return false;
+ }
+ this->newEntry();
+ yyscan_t scanner;
+ cmGccDepfile_yylex_init(&scanner);
+ cmGccDepfile_yyset_extra(this, scanner);
+ cmGccDepfile_yyrestart(file, scanner);
+ cmGccDepfile_yylex(scanner);
+ cmGccDepfile_yylex_destroy(scanner);
+ this->sanitizeContent();
+ fclose(file);
+ return this->HelperState != State::Failed;
+}
+
+void cmGccDepfileLexerHelper::newEntry()
+{
+ if (this->HelperState == State::Rule && !this->Content.empty()) {
+ if (!this->Content.back().rules.empty() &&
+ !this->Content.back().rules.back().empty()) {
+ this->HelperState = State::Failed;
+ }
+ return;
+ }
+ this->HelperState = State::Rule;
+ this->Content.emplace_back();
+ this->newRule();
+}
+
+void cmGccDepfileLexerHelper::newRule()
+{
+ auto& entry = this->Content.back();
+ if (entry.rules.empty() || !entry.rules.back().empty()) {
+ entry.rules.emplace_back();
+ }
+}
+
+void cmGccDepfileLexerHelper::newDependency()
+{
+ if (this->HelperState == State::Failed) {
+ return;
+ }
+ this->HelperState = State::Dependency;
+ auto& entry = this->Content.back();
+ if (entry.paths.empty() || !entry.paths.back().empty()) {
+ entry.paths.emplace_back();
+ }
+}
+
+void cmGccDepfileLexerHelper::newRuleOrDependency()
+{
+ if (this->HelperState == State::Rule) {
+ this->newRule();
+ } else if (this->HelperState == State::Dependency) {
+ this->newDependency();
+ }
+}
+
+void cmGccDepfileLexerHelper::addToCurrentPath(const char* s)
+{
+ if (this->Content.empty()) {
+ return;
+ }
+ cmGccStyleDependency* dep = &this->Content.back();
+ std::string* dst = nullptr;
+ switch (this->HelperState) {
+ case State::Rule: {
+ if (dep->rules.empty()) {
+ return;
+ }
+ dst = &dep->rules.back();
+ } break;
+ case State::Dependency: {
+ if (dep->paths.empty()) {
+ return;
+ }
+ dst = &dep->paths.back();
+ } break;
+ case State::Failed:
+ return;
+ }
+ dst->append(s);
+}
+
+void cmGccDepfileLexerHelper::sanitizeContent()
+{
+ for (auto it = this->Content.begin(); it != this->Content.end();) {
+ // Remove empty rules
+ for (auto rit = it->rules.begin(); rit != it->rules.end();) {
+ if (rit->empty()) {
+ rit = it->rules.erase(rit);
+ } else {
+ ++rit;
+ }
+ }
+ // Remove the entry if rules are empty
+ if (it->rules.empty()) {
+ it = this->Content.erase(it);
+ } else {
+ // Remove empty paths and normalize windows paths
+ for (auto pit = it->paths.begin(); pit != it->paths.end();) {
+ if (pit->empty()) {
+ pit = it->paths.erase(pit);
+ } else {
+#if defined(_WIN32)
+ // Unescape the colon following the drive letter.
+ // Some versions of GNU compilers can escape this character.
+ // c\:\path must be transformed to c:\path
+ if (pit->size() >= 3 && std::toupper((*pit)[0]) >= 'A' &&
+ std::toupper((*pit)[0]) <= 'Z' && (*pit)[1] == '\\' &&
+ (*pit)[2] == ':') {
+ pit->erase(1, 1);
+ }
+#endif
+ ++pit;
+ }
+ }
+ ++it;
+ }
+ }
+}
diff --git a/Source/cmGccDepfileLexerHelper.h b/Source/cmGccDepfileLexerHelper.h
new file mode 100644
index 0000000..91132f5
--- /dev/null
+++ b/Source/cmGccDepfileLexerHelper.h
@@ -0,0 +1,38 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <utility>
+
+#include <cmGccDepfileReaderTypes.h>
+
+class cmGccDepfileLexerHelper
+{
+public:
+ cmGccDepfileLexerHelper() = default;
+
+ bool readFile(const char* filePath);
+ cmGccDepfileContent extractContent() && { return std::move(this->Content); }
+
+ // Functions called by the lexer
+ void newEntry();
+ void newRule();
+ void newDependency();
+ void newRuleOrDependency();
+ void addToCurrentPath(const char* s);
+
+private:
+ void sanitizeContent();
+
+ cmGccDepfileContent Content;
+
+ enum class State
+ {
+ Rule,
+ Dependency,
+ Failed,
+ };
+ State HelperState = State::Rule;
+};
+
+#define YY_EXTRA_TYPE cmGccDepfileLexerHelper*
diff --git a/Source/cmGccDepfileReader.cxx b/Source/cmGccDepfileReader.cxx
new file mode 100644
index 0000000..6436baa
--- /dev/null
+++ b/Source/cmGccDepfileReader.cxx
@@ -0,0 +1,46 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGccDepfileReader.h"
+
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+
+#include "cmGccDepfileLexerHelper.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cm::optional<cmGccDepfileContent> cmReadGccDepfile(const char* filePath,
+ const std::string& prefix)
+{
+ cmGccDepfileLexerHelper helper;
+ if (!helper.readFile(filePath)) {
+ return cm::nullopt;
+ }
+ auto deps = cm::make_optional(std::move(helper).extractContent());
+
+ for (auto& dep : *deps) {
+ for (auto& rule : dep.rules) {
+ if (!prefix.empty() && !cmSystemTools::FileIsFullPath(rule)) {
+ rule = cmStrCat(prefix, '/', rule);
+ }
+ if (cmSystemTools::FileIsFullPath(rule)) {
+ rule = cmSystemTools::CollapseFullPath(rule);
+ }
+ cmSystemTools::ConvertToLongPath(rule);
+ }
+ for (auto& path : dep.paths) {
+ if (!prefix.empty() && !cmSystemTools::FileIsFullPath(path)) {
+ path = cmStrCat(prefix, '/', path);
+ }
+ if (cmSystemTools::FileIsFullPath(path)) {
+ path = cmSystemTools::CollapseFullPath(path);
+ }
+ cmSystemTools::ConvertToLongPath(path);
+ }
+ }
+
+ return deps;
+}
diff --git a/Source/cmGccDepfileReader.h b/Source/cmGccDepfileReader.h
new file mode 100644
index 0000000..c8a3748
--- /dev/null
+++ b/Source/cmGccDepfileReader.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 <string>
+
+#include <cm/optional>
+
+#include "cmGccDepfileReaderTypes.h"
+
+/*
+ * Read dependencies file and append prefix to all relative paths
+ */
+cm::optional<cmGccDepfileContent> cmReadGccDepfile(
+ const char* filePath, const std::string& prefix = {});
diff --git a/Source/cmGccDepfileReaderTypes.h b/Source/cmGccDepfileReaderTypes.h
new file mode 100644
index 0000000..246e355
--- /dev/null
+++ b/Source/cmGccDepfileReaderTypes.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+#include <vector>
+
+struct cmGccStyleDependency
+{
+ std::vector<std::string> rules;
+ std::vector<std::string> paths;
+};
+
+using cmGccDepfileContent = std::vector<cmGccStyleDependency>;
diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx
new file mode 100644
index 0000000..43f384a
--- /dev/null
+++ b/Source/cmGeneratedFileStream.cxx
@@ -0,0 +1,242 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGeneratedFileStream.h"
+
+#include <cstdio>
+
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+#if !defined(CMAKE_BOOTSTRAP)
+# include <cm3p/zlib.h>
+
+# include "cm_codecvt.hxx"
+#endif
+
+cmGeneratedFileStream::cmGeneratedFileStream(Encoding encoding)
+ : OriginalLocale(this->getloc())
+{
+#ifndef CMAKE_BOOTSTRAP
+ if (encoding != codecvt::None) {
+ this->imbue(std::locale(this->OriginalLocale, new codecvt(encoding)));
+ }
+#else
+ static_cast<void>(encoding);
+#endif
+}
+
+cmGeneratedFileStream::cmGeneratedFileStream(std::string const& name,
+ bool quiet, Encoding encoding)
+ : cmGeneratedFileStreamBase(name)
+ , Stream(this->TempName.c_str())
+{
+ // Check if the file opened.
+ if (!*this && !quiet) {
+ cmSystemTools::Error("Cannot open file for write: " + this->TempName);
+ cmSystemTools::ReportLastSystemError("");
+ }
+#ifndef CMAKE_BOOTSTRAP
+ if (encoding != codecvt::None) {
+ this->imbue(std::locale(this->getloc(), new codecvt(encoding)));
+ }
+#else
+ static_cast<void>(encoding);
+#endif
+}
+
+cmGeneratedFileStream::~cmGeneratedFileStream()
+{
+ // This is the first destructor called. Check the status of the
+ // stream and give the information to the private base. Next the
+ // stream will be destroyed which will close the temporary file.
+ // Finally the base destructor will be called to replace the
+ // destination file.
+ this->Okay = !this->fail();
+}
+
+cmGeneratedFileStream& cmGeneratedFileStream::Open(std::string const& name,
+ bool quiet, bool binaryFlag)
+{
+ // Store the file name and construct the temporary file name.
+ this->cmGeneratedFileStreamBase::Open(name);
+
+ // Open the temporary output file.
+ if (binaryFlag) {
+ this->Stream::open(this->TempName.c_str(),
+ std::ios::out | std::ios::binary);
+ } else {
+ this->Stream::open(this->TempName.c_str());
+ }
+
+ // Check if the file opened.
+ if (!*this && !quiet) {
+ cmSystemTools::Error("Cannot open file for write: " + this->TempName);
+ cmSystemTools::ReportLastSystemError("");
+ }
+ return *this;
+}
+
+bool cmGeneratedFileStream::Close()
+{
+ // Save whether the temporary output file is valid before closing.
+ this->Okay = !this->fail();
+
+ // Close the temporary output file.
+ this->Stream::close();
+
+ // Remove the temporary file (possibly by renaming to the real file).
+ return this->cmGeneratedFileStreamBase::Close();
+}
+
+void cmGeneratedFileStream::SetCopyIfDifferent(bool copy_if_different)
+{
+ this->CopyIfDifferent = copy_if_different;
+}
+
+void cmGeneratedFileStream::SetCompression(bool compression)
+{
+ this->Compress = compression;
+}
+
+void cmGeneratedFileStream::SetCompressionExtraExtension(bool ext)
+{
+ this->CompressExtraExtension = ext;
+}
+
+cmGeneratedFileStreamBase::cmGeneratedFileStreamBase() = default;
+
+cmGeneratedFileStreamBase::cmGeneratedFileStreamBase(std::string const& name)
+{
+ this->Open(name);
+}
+
+cmGeneratedFileStreamBase::~cmGeneratedFileStreamBase()
+{
+ this->Close();
+}
+
+void cmGeneratedFileStreamBase::Open(std::string const& name)
+{
+ // Save the original name of the file.
+ this->Name = name;
+
+ // Create the name of the temporary file.
+ this->TempName = name;
+#if defined(__VMS)
+ this->TempName += "_";
+#else
+ this->TempName += ".";
+#endif
+ if (!this->TempExt.empty()) {
+ this->TempName += this->TempExt;
+ } else {
+ char buf[64];
+ sprintf(buf, "tmp%05x", cmSystemTools::RandomSeed() & 0xFFFFF);
+ this->TempName += buf;
+ }
+
+ // Make sure the temporary file that will be used is not present.
+ cmSystemTools::RemoveFile(this->TempName);
+
+ std::string dir = cmSystemTools::GetFilenamePath(this->TempName);
+ cmSystemTools::MakeDirectory(dir);
+}
+
+bool cmGeneratedFileStreamBase::Close()
+{
+ bool replaced = false;
+
+ std::string resname = this->Name;
+ if (this->Compress && this->CompressExtraExtension) {
+ resname += ".gz";
+ }
+
+ // Only consider replacing the destination file if no error
+ // occurred.
+ if (!this->Name.empty() && this->Okay &&
+ (!this->CopyIfDifferent ||
+ cmSystemTools::FilesDiffer(this->TempName, resname))) {
+ // The destination is to be replaced. Rename the temporary to the
+ // destination atomically.
+ if (this->Compress) {
+ std::string gzname = cmStrCat(this->TempName, ".temp.gz");
+ if (this->CompressFile(this->TempName, gzname)) {
+ this->RenameFile(gzname, resname);
+ }
+ cmSystemTools::RemoveFile(gzname);
+ } else {
+ this->RenameFile(this->TempName, resname);
+ }
+
+ replaced = true;
+ }
+
+ // Else, the destination was not replaced.
+ //
+ // Always delete the temporary file. We never want it to stay around.
+ cmSystemTools::RemoveFile(this->TempName);
+
+ return replaced;
+}
+
+#ifndef CMAKE_BOOTSTRAP
+int cmGeneratedFileStreamBase::CompressFile(std::string const& oldname,
+ std::string const& newname)
+{
+ gzFile gf = gzopen(newname.c_str(), "w");
+ if (!gf) {
+ return 0;
+ }
+ FILE* ifs = cmsys::SystemTools::Fopen(oldname, "r");
+ if (!ifs) {
+ gzclose(gf);
+ return 0;
+ }
+ size_t res;
+ const size_t BUFFER_SIZE = 1024;
+ char buffer[BUFFER_SIZE];
+ while ((res = fread(buffer, 1, BUFFER_SIZE, ifs)) > 0) {
+ if (!gzwrite(gf, buffer, static_cast<int>(res))) {
+ fclose(ifs);
+ gzclose(gf);
+ return 0;
+ }
+ }
+ fclose(ifs);
+ gzclose(gf);
+ return 1;
+}
+#else
+int cmGeneratedFileStreamBase::CompressFile(std::string const&,
+ std::string const&)
+{
+ return 0;
+}
+#endif
+
+int cmGeneratedFileStreamBase::RenameFile(std::string const& oldname,
+ std::string const& newname)
+{
+ return cmSystemTools::RenameFile(oldname, newname);
+}
+
+void cmGeneratedFileStream::SetName(const std::string& fname)
+{
+ this->Name = fname;
+}
+
+void cmGeneratedFileStream::SetTempExt(std::string const& ext)
+{
+ this->TempExt = ext;
+}
+
+void cmGeneratedFileStream::WriteRaw(std::string const& data)
+{
+#ifndef CMAKE_BOOTSTRAP
+ std::locale activeLocale = this->imbue(this->OriginalLocale);
+ this->write(data.data(), data.size());
+ this->imbue(activeLocale);
+#else
+ this->write(data.data(), data.size());
+#endif
+}
diff --git a/Source/cmGeneratedFileStream.h b/Source/cmGeneratedFileStream.h
new file mode 100644
index 0000000..bb7e3bf
--- /dev/null
+++ b/Source/cmGeneratedFileStream.h
@@ -0,0 +1,159 @@
+/* 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 <string>
+
+#include "cmsys/FStream.hxx"
+
+#include "cm_codecvt.hxx"
+
+// This is the first base class of cmGeneratedFileStream. It will be
+// created before and destroyed after the ofstream portion and can
+// therefore be used to manage the temporary file.
+class cmGeneratedFileStreamBase
+{
+protected:
+ // This constructor does not prepare the temporary file. The open
+ // method must be used.
+ cmGeneratedFileStreamBase();
+
+ // This constructor prepares the temporary output file.
+ cmGeneratedFileStreamBase(std::string const& name);
+
+ // The destructor renames the temporary output file to the real name.
+ ~cmGeneratedFileStreamBase();
+
+ // Internal methods to handle the temporary file. Open is always
+ // called before the real stream is opened. Close is always called
+ // after the real stream is closed and Okay is set to whether the
+ // real stream was still valid for writing when it was closed.
+ void Open(std::string const& name);
+ bool Close();
+
+ // Internal file replacement implementation.
+ int RenameFile(std::string const& oldname, std::string const& newname);
+
+ // Internal file compression implementation.
+ int CompressFile(std::string const& oldname, std::string const& newname);
+
+ // The name of the final destination file for the output.
+ std::string Name;
+
+ // The extension of the temporary file.
+ std::string TempExt;
+
+ // The name of the temporary file.
+ std::string TempName;
+
+ // Whether to do a copy-if-different.
+ bool CopyIfDifferent = false;
+
+ // Whether the real file stream was valid when it was closed.
+ bool Okay = false;
+
+ // Whether the destination file is compressed
+ bool Compress = false;
+
+ // Whether the destination file is compressed
+ bool CompressExtraExtension = true;
+};
+
+/** \class cmGeneratedFileStream
+ * \brief Output stream for generated files.
+ *
+ * File generation should be atomic so that if CMake is killed then a
+ * generated file is either the original version or the complete new
+ * version. This stream is used to make sure file generation is
+ * atomic. Optionally the output file is only replaced if its
+ * contents have changed to prevent the file modification time from
+ * being updated.
+ */
+class cmGeneratedFileStream
+ : private cmGeneratedFileStreamBase
+ , public cmsys::ofstream
+{
+public:
+ using Stream = cmsys::ofstream;
+ using Encoding = codecvt::Encoding;
+
+ /**
+ * This constructor prepares a default stream. The open method must
+ * be used before writing to the stream.
+ */
+ cmGeneratedFileStream(Encoding encoding = codecvt::None);
+
+ /**
+ * This constructor takes the name of the file to be generated. It
+ * automatically generates a name for the temporary file. If the
+ * file cannot be opened an error message is produced unless the
+ * second argument is set to true.
+ */
+ cmGeneratedFileStream(std::string const& name, bool quiet = false,
+ Encoding encoding = codecvt::None);
+
+ /**
+ * The destructor checks the stream status to be sure the temporary
+ * file was successfully written before allowing the original to be
+ * replaced.
+ */
+ ~cmGeneratedFileStream() override;
+
+ cmGeneratedFileStream(cmGeneratedFileStream const&) = delete;
+
+ /**
+ * Open an output file by name. This should be used only with a
+ * non-open stream. It automatically generates a name for the
+ * temporary file. If the file cannot be opened an error message is
+ * produced unless the second argument is set to true.
+ */
+ cmGeneratedFileStream& Open(std::string const& name, bool quiet = false,
+ bool binaryFlag = false);
+
+ /**
+ * Close the output file. This should be used only with an open
+ * stream. The temporary file is atomically renamed to the
+ * destination file if the stream is still valid when this method
+ * is called.
+ */
+ bool Close();
+
+ /**
+ * Set whether copy-if-different is done.
+ */
+ void SetCopyIfDifferent(bool copy_if_different);
+
+ /**
+ * Set whether compression is done.
+ */
+ void SetCompression(bool compression);
+
+ /**
+ * Set whether compression has extra extension
+ */
+ void SetCompressionExtraExtension(bool ext);
+
+ /**
+ * Set name of the file that will hold the actual output. This method allows
+ * the output file to be changed during the use of cmGeneratedFileStream.
+ */
+ void SetName(const std::string& fname);
+
+ /**
+ * Set set a custom temporary file extension used with 'Open'.
+ * This does not work if the file was opened by the constructor.
+ */
+ void SetTempExt(std::string const& ext);
+
+ /**
+ * Writes the given string directly to the file without changing the
+ * encoding.
+ */
+ void WriteRaw(std::string const& data);
+
+private:
+ // The original locale of the stream (performs no encoding conversion).
+ std::locale OriginalLocale;
+};
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
new file mode 100644
index 0000000..840f511
--- /dev/null
+++ b/Source/cmGeneratorExpression.cxx
@@ -0,0 +1,408 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGeneratorExpression.h"
+
+#include <cassert>
+#include <memory>
+#include <utility>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmGeneratorExpressionContext.h"
+#include "cmGeneratorExpressionDAGChecker.h"
+#include "cmGeneratorExpressionEvaluator.h"
+#include "cmGeneratorExpressionLexer.h"
+#include "cmGeneratorExpressionParser.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmGeneratorExpression::cmGeneratorExpression(cmListFileBacktrace backtrace)
+ : Backtrace(std::move(backtrace))
+{
+}
+
+cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression() = default;
+
+cmGeneratorExpression::~cmGeneratorExpression() = default;
+
+std::unique_ptr<cmCompiledGeneratorExpression> cmGeneratorExpression::Parse(
+ std::string input) const
+{
+ return std::unique_ptr<cmCompiledGeneratorExpression>(
+ new cmCompiledGeneratorExpression(this->Backtrace, std::move(input)));
+}
+
+std::string cmGeneratorExpression::Evaluate(
+ std::string input, cmLocalGenerator* lg, const std::string& config,
+ cmGeneratorTarget const* headTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ cmGeneratorTarget const* currentTarget, std::string const& language)
+{
+ if (Find(input) != std::string::npos) {
+ cmCompiledGeneratorExpression cge(cmListFileBacktrace(), std::move(input));
+ return cge.Evaluate(lg, config, headTarget, dagChecker, currentTarget,
+ language);
+ }
+ return input;
+}
+
+const std::string& cmCompiledGeneratorExpression::Evaluate(
+ cmLocalGenerator* lg, const std::string& config,
+ const cmGeneratorTarget* headTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ const cmGeneratorTarget* currentTarget, std::string const& language) const
+{
+ cmGeneratorExpressionContext context(
+ lg, config, this->Quiet, headTarget,
+ currentTarget ? currentTarget : headTarget, this->EvaluateForBuildsystem,
+ this->Backtrace, language);
+
+ return this->EvaluateWithContext(context, dagChecker);
+}
+
+const std::string& cmCompiledGeneratorExpression::EvaluateWithContext(
+ cmGeneratorExpressionContext& context,
+ cmGeneratorExpressionDAGChecker* dagChecker) const
+{
+ if (!this->NeedsEvaluation) {
+ return this->Input;
+ }
+
+ this->Output.clear();
+
+ for (const auto& it : this->Evaluators) {
+ this->Output += it->Evaluate(&context, dagChecker);
+
+ this->SeenTargetProperties.insert(context.SeenTargetProperties.cbegin(),
+ context.SeenTargetProperties.cend());
+ if (context.HadError) {
+ this->Output.clear();
+ break;
+ }
+ }
+
+ this->MaxLanguageStandard = context.MaxLanguageStandard;
+
+ if (!context.HadError) {
+ this->HadContextSensitiveCondition = context.HadContextSensitiveCondition;
+ this->HadHeadSensitiveCondition = context.HadHeadSensitiveCondition;
+ this->HadLinkLanguageSensitiveCondition =
+ context.HadLinkLanguageSensitiveCondition;
+ this->SourceSensitiveTargets = context.SourceSensitiveTargets;
+ }
+
+ this->DependTargets = context.DependTargets;
+ this->AllTargetsSeen = context.AllTargets;
+ return this->Output;
+}
+
+cmCompiledGeneratorExpression::cmCompiledGeneratorExpression(
+ cmListFileBacktrace backtrace, std::string input)
+ : Backtrace(std::move(backtrace))
+ , Input(std::move(input))
+ , EvaluateForBuildsystem(false)
+ , Quiet(false)
+ , HadContextSensitiveCondition(false)
+ , HadHeadSensitiveCondition(false)
+ , HadLinkLanguageSensitiveCondition(false)
+{
+ cmGeneratorExpressionLexer l;
+ std::vector<cmGeneratorExpressionToken> tokens = l.Tokenize(this->Input);
+ this->NeedsEvaluation = l.GetSawGeneratorExpression();
+
+ if (this->NeedsEvaluation) {
+ cmGeneratorExpressionParser p(tokens);
+ p.Parse(this->Evaluators);
+ }
+}
+
+std::string cmGeneratorExpression::StripEmptyListElements(
+ const std::string& input)
+{
+ if (input.find(';') == std::string::npos) {
+ return input;
+ }
+ std::string result;
+ result.reserve(input.size());
+
+ const char* c = input.c_str();
+ const char* last = c;
+ bool skipSemiColons = true;
+ for (; *c; ++c) {
+ if (*c == ';') {
+ if (skipSemiColons) {
+ result.append(last, c - last);
+ last = c + 1;
+ }
+ skipSemiColons = true;
+ } else {
+ skipSemiColons = false;
+ }
+ }
+ result.append(last);
+
+ if (!result.empty() && *(result.end() - 1) == ';') {
+ result.resize(result.size() - 1);
+ }
+
+ return result;
+}
+
+static std::string stripAllGeneratorExpressions(const std::string& input)
+{
+ std::string result;
+ std::string::size_type pos = 0;
+ std::string::size_type lastPos = pos;
+ int nestingLevel = 0;
+ while ((pos = input.find("$<", lastPos)) != std::string::npos) {
+ result += input.substr(lastPos, pos - lastPos);
+ pos += 2;
+ nestingLevel = 1;
+ const char* c = input.c_str() + pos;
+ const char* const cStart = c;
+ for (; *c; ++c) {
+ if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
+ ++nestingLevel;
+ ++c;
+ continue;
+ }
+ if (c[0] == '>') {
+ --nestingLevel;
+ if (nestingLevel == 0) {
+ break;
+ }
+ }
+ }
+ const std::string::size_type traversed = (c - cStart) + 1;
+ if (!*c) {
+ result += "$<" + input.substr(pos, traversed);
+ }
+ pos += traversed;
+ lastPos = pos;
+ }
+ if (nestingLevel == 0) {
+ result += input.substr(lastPos);
+ }
+ return cmGeneratorExpression::StripEmptyListElements(result);
+}
+
+static void prefixItems(const std::string& content, std::string& result,
+ const std::string& prefix)
+{
+ std::vector<std::string> entries;
+ cmGeneratorExpression::Split(content, entries);
+ const char* sep = "";
+ for (std::string const& e : entries) {
+ result += sep;
+ sep = ";";
+ if (!cmSystemTools::FileIsFullPath(e) &&
+ cmGeneratorExpression::Find(e) != 0) {
+ result += prefix;
+ }
+ result += e;
+ }
+}
+
+static std::string stripExportInterface(
+ const std::string& input, cmGeneratorExpression::PreprocessContext context,
+ bool resolveRelative)
+{
+ std::string result;
+
+ int nestingLevel = 0;
+ std::string::size_type pos = 0;
+ std::string::size_type lastPos = pos;
+ while (true) {
+ std::string::size_type bPos = input.find("$<BUILD_INTERFACE:", lastPos);
+ std::string::size_type iPos = input.find("$<INSTALL_INTERFACE:", lastPos);
+
+ if (bPos == std::string::npos && iPos == std::string::npos) {
+ break;
+ }
+
+ if (bPos == std::string::npos) {
+ pos = iPos;
+ } else if (iPos == std::string::npos) {
+ pos = bPos;
+ } else {
+ pos = (bPos < iPos) ? bPos : iPos;
+ }
+
+ result += input.substr(lastPos, pos - lastPos);
+ const bool gotInstallInterface = input[pos + 2] == 'I';
+ pos += gotInstallInterface ? sizeof("$<INSTALL_INTERFACE:") - 1
+ : sizeof("$<BUILD_INTERFACE:") - 1;
+ nestingLevel = 1;
+ const char* c = input.c_str() + pos;
+ const char* const cStart = c;
+ for (; *c; ++c) {
+ if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
+ ++nestingLevel;
+ ++c;
+ continue;
+ }
+ if (c[0] == '>') {
+ --nestingLevel;
+ if (nestingLevel != 0) {
+ continue;
+ }
+ if (context == cmGeneratorExpression::BuildInterface &&
+ !gotInstallInterface) {
+ result += input.substr(pos, c - cStart);
+ } else if (context == cmGeneratorExpression::InstallInterface &&
+ gotInstallInterface) {
+ const std::string content = input.substr(pos, c - cStart);
+ if (resolveRelative) {
+ prefixItems(content, result, "${_IMPORT_PREFIX}/");
+ } else {
+ result += content;
+ }
+ }
+ break;
+ }
+ }
+ const std::string::size_type traversed = (c - cStart) + 1;
+ if (!*c) {
+ result += std::string(gotInstallInterface ? "$<INSTALL_INTERFACE:"
+ : "$<BUILD_INTERFACE:") +
+ input.substr(pos, traversed);
+ }
+ pos += traversed;
+ lastPos = pos;
+ }
+ if (nestingLevel == 0) {
+ result += input.substr(lastPos);
+ }
+
+ return cmGeneratorExpression::StripEmptyListElements(result);
+}
+
+void cmGeneratorExpression::Split(const std::string& input,
+ std::vector<std::string>& output)
+{
+ std::string::size_type pos = 0;
+ std::string::size_type lastPos = pos;
+ while ((pos = input.find("$<", lastPos)) != std::string::npos) {
+ std::string part = input.substr(lastPos, pos - lastPos);
+ std::string preGenex;
+ if (!part.empty()) {
+ std::string::size_type startPos = input.rfind(';', pos);
+ if (startPos == std::string::npos) {
+ preGenex = part;
+ part.clear();
+ } else if (startPos != pos - 1 && startPos >= lastPos) {
+ part = input.substr(lastPos, startPos - lastPos);
+ preGenex = input.substr(startPos + 1, pos - startPos - 1);
+ }
+ if (!part.empty()) {
+ cmExpandList(part, output);
+ }
+ }
+ pos += 2;
+ int nestingLevel = 1;
+ const char* c = input.c_str() + pos;
+ const char* const cStart = c;
+ for (; *c; ++c) {
+ if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
+ ++nestingLevel;
+ ++c;
+ continue;
+ }
+ if (c[0] == '>') {
+ --nestingLevel;
+ if (nestingLevel == 0) {
+ break;
+ }
+ }
+ }
+ for (; *c; ++c) {
+ // Capture the part after the genex and before the next ';'
+ if (c[0] == ';') {
+ --c;
+ break;
+ }
+ }
+ const std::string::size_type traversed = (c - cStart) + 1;
+ output.push_back(preGenex + "$<" + input.substr(pos, traversed));
+ pos += traversed;
+ lastPos = pos;
+ }
+ if (lastPos < input.size()) {
+ cmExpandList(input.substr(lastPos), output);
+ }
+}
+
+std::string cmGeneratorExpression::Preprocess(const std::string& input,
+ PreprocessContext context,
+ bool resolveRelative)
+{
+ if (context == StripAllGeneratorExpressions) {
+ return stripAllGeneratorExpressions(input);
+ }
+ if (context == BuildInterface || context == InstallInterface) {
+ return stripExportInterface(input, context, resolveRelative);
+ }
+
+ assert(false &&
+ "cmGeneratorExpression::Preprocess called with invalid args");
+ return std::string();
+}
+
+std::string::size_type cmGeneratorExpression::Find(const std::string& input)
+{
+ const std::string::size_type openpos = input.find("$<");
+ if (openpos != std::string::npos &&
+ input.find('>', openpos) != std::string::npos) {
+ return openpos;
+ }
+ return std::string::npos;
+}
+
+bool cmGeneratorExpression::IsValidTargetName(const std::string& input)
+{
+ // The ':' is supported to allow use with IMPORTED targets. At least
+ // Qt 4 and 5 IMPORTED targets use ':' as the namespace delimiter.
+ static cmsys::RegularExpression targetNameValidator("^[A-Za-z0-9_.:+-]+$");
+
+ return targetNameValidator.find(input);
+}
+
+void cmGeneratorExpression::ReplaceInstallPrefix(
+ std::string& input, const std::string& replacement)
+{
+ std::string::size_type pos = 0;
+ std::string::size_type lastPos = pos;
+
+ while ((pos = input.find("$<INSTALL_PREFIX>", lastPos)) !=
+ std::string::npos) {
+ std::string::size_type endPos = pos + sizeof("$<INSTALL_PREFIX>") - 1;
+ input.replace(pos, endPos - pos, replacement);
+ lastPos = endPos;
+ }
+}
+
+void cmCompiledGeneratorExpression::GetMaxLanguageStandard(
+ const cmGeneratorTarget* tgt, std::map<std::string, std::string>& mapping)
+{
+ auto it = this->MaxLanguageStandard.find(tgt);
+ if (it != this->MaxLanguageStandard.end()) {
+ mapping = it->second;
+ }
+}
+
+const std::string& cmGeneratorExpressionInterpreter::Evaluate(
+ std::string expression, const std::string& property)
+{
+ this->CompiledGeneratorExpression =
+ this->GeneratorExpression.Parse(std::move(expression));
+
+ // Specify COMPILE_OPTIONS to DAGchecker, same semantic as COMPILE_FLAGS
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this->HeadTarget,
+ property == "COMPILE_FLAGS" ? "COMPILE_OPTIONS" : property, nullptr,
+ nullptr);
+
+ return this->CompiledGeneratorExpression->Evaluate(
+ this->LocalGenerator, this->Config, this->HeadTarget, &dagChecker, nullptr,
+ this->Language);
+}
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
new file mode 100644
index 0000000..03be782
--- /dev/null
+++ b/Source/cmGeneratorExpression.h
@@ -0,0 +1,209 @@
+/* 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 <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmListFileCache.h"
+
+class cmCompiledGeneratorExpression;
+class cmGeneratorTarget;
+class cmLocalGenerator;
+struct cmGeneratorExpressionContext;
+struct cmGeneratorExpressionDAGChecker;
+struct cmGeneratorExpressionEvaluator;
+
+/** \class cmGeneratorExpression
+ * \brief Evaluate generate-time query expression syntax.
+ *
+ * cmGeneratorExpression instances are used by build system generator
+ * implementations to evaluate the $<> generator expression syntax.
+ * Generator expressions are evaluated just before the generate step
+ * writes strings into the build system. They have knowledge of the
+ * build configuration which is not available at configure time.
+ */
+class cmGeneratorExpression
+{
+public:
+ /** Construct. */
+ cmGeneratorExpression(cmListFileBacktrace backtrace = cmListFileBacktrace());
+ ~cmGeneratorExpression();
+
+ cmGeneratorExpression(cmGeneratorExpression const&) = delete;
+ cmGeneratorExpression& operator=(cmGeneratorExpression const&) = delete;
+
+ std::unique_ptr<cmCompiledGeneratorExpression> Parse(
+ std::string input) const;
+
+ static std::string Evaluate(
+ std::string input, cmLocalGenerator* lg, const std::string& config,
+ cmGeneratorTarget const* headTarget = nullptr,
+ cmGeneratorExpressionDAGChecker* dagChecker = nullptr,
+ cmGeneratorTarget const* currentTarget = nullptr,
+ std::string const& language = std::string());
+
+ enum PreprocessContext
+ {
+ StripAllGeneratorExpressions,
+ BuildInterface,
+ InstallInterface
+ };
+
+ static std::string Preprocess(const std::string& input,
+ PreprocessContext context,
+ bool resolveRelative = false);
+
+ static void Split(const std::string& input,
+ std::vector<std::string>& output);
+
+ static std::string::size_type Find(const std::string& input);
+
+ static bool IsValidTargetName(const std::string& input);
+
+ static std::string StripEmptyListElements(const std::string& input);
+
+ static inline bool StartsWithGeneratorExpression(const std::string& input)
+ {
+ return input.length() >= 2 && input[0] == '$' && input[1] == '<';
+ }
+ static inline bool StartsWithGeneratorExpression(const char* input)
+ {
+ return input != nullptr && input[0] == '$' && input[1] == '<';
+ }
+
+ static void ReplaceInstallPrefix(std::string& input,
+ const std::string& replacement);
+
+private:
+ cmListFileBacktrace Backtrace;
+};
+
+class cmCompiledGeneratorExpression
+{
+public:
+ ~cmCompiledGeneratorExpression();
+
+ cmCompiledGeneratorExpression(cmCompiledGeneratorExpression const&) = delete;
+ cmCompiledGeneratorExpression& operator=(
+ cmCompiledGeneratorExpression const&) = delete;
+
+ const std::string& Evaluate(
+ cmLocalGenerator* lg, const std::string& config,
+ cmGeneratorTarget const* headTarget = nullptr,
+ cmGeneratorExpressionDAGChecker* dagChecker = nullptr,
+ cmGeneratorTarget const* currentTarget = nullptr,
+ std::string const& language = std::string()) const;
+
+ /** Get set of targets found during evaluations. */
+ std::set<cmGeneratorTarget*> const& GetTargets() const
+ {
+ return this->DependTargets;
+ }
+
+ std::set<std::string> const& GetSeenTargetProperties() const
+ {
+ return this->SeenTargetProperties;
+ }
+
+ std::set<cmGeneratorTarget const*> const& GetAllTargetsSeen() const
+ {
+ return this->AllTargetsSeen;
+ }
+
+ std::string const& GetInput() const { return this->Input; }
+
+ cmListFileBacktrace GetBacktrace() const { return this->Backtrace; }
+ bool GetHadContextSensitiveCondition() const
+ {
+ return this->HadContextSensitiveCondition;
+ }
+ bool GetHadHeadSensitiveCondition() const
+ {
+ return this->HadHeadSensitiveCondition;
+ }
+ bool GetHadLinkLanguageSensitiveCondition() const
+ {
+ return this->HadLinkLanguageSensitiveCondition;
+ }
+ std::set<cmGeneratorTarget const*> GetSourceSensitiveTargets() const
+ {
+ return this->SourceSensitiveTargets;
+ }
+
+ void SetEvaluateForBuildsystem(bool eval)
+ {
+ this->EvaluateForBuildsystem = eval;
+ }
+
+ void SetQuiet(bool quiet) { this->Quiet = quiet; }
+
+ void GetMaxLanguageStandard(cmGeneratorTarget const* tgt,
+ std::map<std::string, std::string>& mapping);
+
+private:
+ const std::string& EvaluateWithContext(
+ cmGeneratorExpressionContext& context,
+ cmGeneratorExpressionDAGChecker* dagChecker) const;
+
+ cmCompiledGeneratorExpression(cmListFileBacktrace backtrace,
+ std::string input);
+
+ friend class cmGeneratorExpression;
+
+ cmListFileBacktrace Backtrace;
+ std::vector<std::unique_ptr<cmGeneratorExpressionEvaluator>> Evaluators;
+ const std::string Input;
+ bool NeedsEvaluation;
+ bool EvaluateForBuildsystem;
+ bool Quiet;
+
+ mutable std::set<cmGeneratorTarget*> DependTargets;
+ mutable std::set<cmGeneratorTarget const*> AllTargetsSeen;
+ mutable std::set<std::string> SeenTargetProperties;
+ mutable std::map<cmGeneratorTarget const*,
+ std::map<std::string, std::string>>
+ MaxLanguageStandard;
+ mutable std::string Output;
+ mutable bool HadContextSensitiveCondition;
+ mutable bool HadHeadSensitiveCondition;
+ mutable bool HadLinkLanguageSensitiveCondition;
+ mutable std::set<cmGeneratorTarget const*> SourceSensitiveTargets;
+};
+
+class cmGeneratorExpressionInterpreter
+{
+public:
+ cmGeneratorExpressionInterpreter(cmLocalGenerator* localGenerator,
+ std::string config,
+ cmGeneratorTarget const* headTarget,
+ std::string language = std::string())
+ : LocalGenerator(localGenerator)
+ , Config(std::move(config))
+ , HeadTarget(headTarget)
+ , Language(std::move(language))
+ {
+ }
+
+ cmGeneratorExpressionInterpreter(cmGeneratorExpressionInterpreter const&) =
+ delete;
+ cmGeneratorExpressionInterpreter& operator=(
+ cmGeneratorExpressionInterpreter const&) = delete;
+
+ const std::string& Evaluate(std::string expression,
+ const std::string& property);
+
+protected:
+ cmGeneratorExpression GeneratorExpression;
+ std::unique_ptr<cmCompiledGeneratorExpression> CompiledGeneratorExpression;
+ cmLocalGenerator* LocalGenerator = nullptr;
+ std::string Config;
+ cmGeneratorTarget const* HeadTarget = nullptr;
+ std::string Language;
+};
diff --git a/Source/cmGeneratorExpressionContext.cxx b/Source/cmGeneratorExpressionContext.cxx
new file mode 100644
index 0000000..42cbe2a
--- /dev/null
+++ b/Source/cmGeneratorExpressionContext.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 "cmGeneratorExpressionContext.h"
+
+#include <utility>
+
+cmGeneratorExpressionContext::cmGeneratorExpressionContext(
+ cmLocalGenerator* lg, std::string config, bool quiet,
+ cmGeneratorTarget const* headTarget, const cmGeneratorTarget* currentTarget,
+ bool evaluateForBuildsystem, cmListFileBacktrace backtrace,
+ std::string language)
+ : Backtrace(std::move(backtrace))
+ , LG(lg)
+ , Config(std::move(config))
+ , Language(std::move(language))
+ , HeadTarget(headTarget)
+ , CurrentTarget(currentTarget)
+ , Quiet(quiet)
+ , HadError(false)
+ , HadContextSensitiveCondition(false)
+ , HadHeadSensitiveCondition(false)
+ , HadLinkLanguageSensitiveCondition(false)
+ , EvaluateForBuildsystem(evaluateForBuildsystem)
+{
+}
diff --git a/Source/cmGeneratorExpressionContext.h b/Source/cmGeneratorExpressionContext.h
new file mode 100644
index 0000000..22e7463
--- /dev/null
+++ b/Source/cmGeneratorExpressionContext.h
@@ -0,0 +1,44 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "cmListFileCache.h"
+
+class cmGeneratorTarget;
+class cmLocalGenerator;
+
+struct cmGeneratorExpressionContext
+{
+ cmGeneratorExpressionContext(cmLocalGenerator* lg, std::string config,
+ bool quiet, const cmGeneratorTarget* headTarget,
+ cmGeneratorTarget const* currentTarget,
+ bool evaluateForBuildsystem,
+ cmListFileBacktrace backtrace,
+ std::string language);
+
+ cmListFileBacktrace Backtrace;
+ std::set<cmGeneratorTarget*> DependTargets;
+ std::set<cmGeneratorTarget const*> AllTargets;
+ std::set<std::string> SeenTargetProperties;
+ std::set<cmGeneratorTarget const*> SourceSensitiveTargets;
+ std::map<cmGeneratorTarget const*, std::map<std::string, std::string>>
+ MaxLanguageStandard;
+ cmLocalGenerator* LG;
+ std::string Config;
+ std::string Language;
+ // The target whose property is being evaluated.
+ cmGeneratorTarget const* HeadTarget;
+ // The dependent of HeadTarget which appears
+ // directly or indirectly in the property.
+ cmGeneratorTarget const* CurrentTarget;
+ bool Quiet;
+ bool HadError;
+ bool HadContextSensitiveCondition;
+ bool HadHeadSensitiveCondition;
+ bool HadLinkLanguageSensitiveCondition;
+ bool EvaluateForBuildsystem;
+};
diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx
new file mode 100644
index 0000000..a1fce55
--- /dev/null
+++ b/Source/cmGeneratorExpressionDAGChecker.cxx
@@ -0,0 +1,248 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGeneratorExpressionDAGChecker.h"
+
+#include <cstring>
+#include <sstream>
+#include <utility>
+
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmGeneratorExpressionContext.h"
+#include "cmGeneratorExpressionEvaluator.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalGenerator.h"
+#include "cmMessageType.h"
+#include "cmStringAlgorithms.h"
+#include "cmake.h"
+
+cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
+ cmListFileBacktrace backtrace, cmGeneratorTarget const* target,
+ std::string property, const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* parent)
+ : Parent(parent)
+ , Target(target)
+ , Property(std::move(property))
+ , Content(content)
+ , Backtrace(std::move(backtrace))
+ , TransitivePropertiesOnly(false)
+{
+ this->Initialize();
+}
+
+cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
+ cmGeneratorTarget const* target, std::string property,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* parent)
+ : Parent(parent)
+ , Target(target)
+ , Property(std::move(property))
+ , Content(content)
+ , Backtrace()
+ , TransitivePropertiesOnly(false)
+{
+ this->Initialize();
+}
+
+void cmGeneratorExpressionDAGChecker::Initialize()
+{
+ const auto* top = this->Top();
+ this->CheckResult = this->CheckGraph();
+
+#define TEST_TRANSITIVE_PROPERTY_METHOD(METHOD) top->METHOD() ||
+
+ if (this->CheckResult == DAG &&
+ (CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
+ TEST_TRANSITIVE_PROPERTY_METHOD) false)) // NOLINT(*)
+#undef TEST_TRANSITIVE_PROPERTY_METHOD
+ {
+ auto it = top->Seen.find(this->Target);
+ if (it != top->Seen.end()) {
+ const std::set<std::string>& propSet = it->second;
+ if (propSet.find(this->Property) != propSet.end()) {
+ this->CheckResult = ALREADY_SEEN;
+ return;
+ }
+ }
+ top->Seen[this->Target].insert(this->Property);
+ }
+}
+
+cmGeneratorExpressionDAGChecker::Result
+cmGeneratorExpressionDAGChecker::Check() const
+{
+ return this->CheckResult;
+}
+
+void cmGeneratorExpressionDAGChecker::ReportError(
+ cmGeneratorExpressionContext* context, const std::string& expr)
+{
+ if (this->CheckResult == DAG) {
+ return;
+ }
+
+ context->HadError = true;
+ if (context->Quiet) {
+ return;
+ }
+
+ const cmGeneratorExpressionDAGChecker* parent = this->Parent;
+
+ if (parent && !parent->Parent) {
+ std::ostringstream e;
+ e << "Error evaluating generator expression:\n"
+ << " " << expr << "\n"
+ << "Self reference on target \"" << context->HeadTarget->GetName()
+ << "\".\n";
+ context->LG->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+ e.str(), parent->Backtrace);
+ return;
+ }
+
+ {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "Error evaluating generator expression:\n"
+ << " " << expr << "\n"
+ << "Dependency loop found.";
+ /* clang-format on */
+ context->LG->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+ e.str(), context->Backtrace);
+ }
+
+ int loopStep = 1;
+ while (parent) {
+ std::ostringstream e;
+ e << "Loop step " << loopStep << "\n"
+ << " "
+ << (parent->Content ? parent->Content->GetOriginalExpression() : expr)
+ << "\n";
+ context->LG->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+ e.str(), parent->Backtrace);
+ parent = parent->Parent;
+ ++loopStep;
+ }
+}
+
+cmGeneratorExpressionDAGChecker::Result
+cmGeneratorExpressionDAGChecker::CheckGraph() const
+{
+ const cmGeneratorExpressionDAGChecker* parent = this->Parent;
+ while (parent) {
+ if (this->Target == parent->Target && this->Property == parent->Property) {
+ return (parent == this->Parent) ? SELF_REFERENCE : CYCLIC_REFERENCE;
+ }
+ parent = parent->Parent;
+ }
+ return DAG;
+}
+
+bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly() const
+{
+ return this->Top()->TransitivePropertiesOnly;
+}
+
+bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression() const
+{
+ return cmHasLiteralPrefix(this->Property, "TARGET_GENEX_EVAL:") ||
+ cmHasLiteralPrefix(this->Property, "GENEX_EVAL:");
+}
+
+bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression() const
+{
+ return this->Top()->Property == "INTERFACE_POSITION_INDEPENDENT_CODE";
+}
+
+bool cmGeneratorExpressionDAGChecker::EvaluatingCompileExpression() const
+{
+ cm::string_view property(this->Top()->Property);
+
+ return property == "INCLUDE_DIRECTORIES"_s ||
+ property == "COMPILE_DEFINITIONS"_s || property == "COMPILE_OPTIONS"_s;
+}
+
+bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const
+{
+ cm::string_view property(this->Top()->Property);
+
+ return property == "LINK_DIRECTORIES"_s || property == "LINK_OPTIONS"_s ||
+ property == "LINK_DEPENDS"_s;
+}
+
+bool cmGeneratorExpressionDAGChecker::EvaluatingLinkOptionsExpression() const
+{
+ cm::string_view property(this->Top()->Property);
+
+ return property == "LINK_OPTIONS"_s;
+}
+
+bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(
+ cmGeneratorTarget const* tgt) const
+{
+ const auto* top = this->Top();
+
+ cm::string_view prop(top->Property);
+
+ if (tgt) {
+ return top->Target == tgt && prop == "LINK_LIBRARIES"_s;
+ }
+
+ return prop == "LINK_LIBRARIES"_s || prop == "LINK_INTERFACE_LIBRARIES"_s ||
+ prop == "IMPORTED_LINK_INTERFACE_LIBRARIES"_s ||
+ cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES_") ||
+ cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_") ||
+ prop == "INTERFACE_LINK_LIBRARIES"_s;
+}
+
+cmGeneratorExpressionDAGChecker const* cmGeneratorExpressionDAGChecker::Top()
+ const
+{
+ const cmGeneratorExpressionDAGChecker* top = this;
+ const cmGeneratorExpressionDAGChecker* parent = this->Parent;
+ while (parent) {
+ top = parent;
+ parent = parent->Parent;
+ }
+ return top;
+}
+
+cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const
+{
+ return this->Top()->Target;
+}
+
+enum TransitiveProperty
+{
+#define DEFINE_ENUM_ENTRY(NAME) NAME,
+ CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(DEFINE_ENUM_ENTRY)
+#undef DEFINE_ENUM_ENTRY
+ TransitivePropertyTerminal
+};
+
+template <TransitiveProperty>
+bool additionalTest(const char* const /*unused*/)
+{
+ return false;
+}
+
+template <>
+bool additionalTest<COMPILE_DEFINITIONS>(const char* const prop)
+{
+ return cmHasLiteralPrefix(prop, "COMPILE_DEFINITIONS_");
+}
+
+#define DEFINE_TRANSITIVE_PROPERTY_METHOD(METHOD, PROPERTY) \
+ bool cmGeneratorExpressionDAGChecker::METHOD() const \
+ { \
+ const char* const prop = this->Property.c_str(); \
+ if (strcmp(prop, #PROPERTY) == 0 || \
+ strcmp(prop, "INTERFACE_" #PROPERTY) == 0) { \
+ return true; \
+ } \
+ return additionalTest<PROPERTY>(prop); \
+ }
+
+CM_FOR_EACH_TRANSITIVE_PROPERTY(DEFINE_TRANSITIVE_PROPERTY_METHOD)
+
+#undef DEFINE_TRANSITIVE_PROPERTY_METHOD
diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h
new file mode 100644
index 0000000..93b44db
--- /dev/null
+++ b/Source/cmGeneratorExpressionDAGChecker.h
@@ -0,0 +1,100 @@
+/* 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 <map>
+#include <set>
+#include <string>
+
+#include "cmListFileCache.h"
+
+struct GeneratorExpressionContent;
+struct cmGeneratorExpressionContext;
+class cmGeneratorTarget;
+
+#define CM_SELECT_BOTH(F, A1, A2) F(A1, A2)
+#define CM_SELECT_FIRST(F, A1, A2) F(A1)
+#define CM_SELECT_SECOND(F, A1, A2) F(A2)
+
+#define CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, SELECT) \
+ SELECT(F, EvaluatingIncludeDirectories, INCLUDE_DIRECTORIES) \
+ SELECT(F, EvaluatingSystemIncludeDirectories, SYSTEM_INCLUDE_DIRECTORIES) \
+ SELECT(F, EvaluatingCompileDefinitions, COMPILE_DEFINITIONS) \
+ SELECT(F, EvaluatingCompileOptions, COMPILE_OPTIONS) \
+ SELECT(F, EvaluatingAutoUicOptions, AUTOUIC_OPTIONS) \
+ SELECT(F, EvaluatingSources, SOURCES) \
+ SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES) \
+ SELECT(F, EvaluatingLinkOptions, LINK_OPTIONS) \
+ SELECT(F, EvaluatingLinkDirectories, LINK_DIRECTORIES) \
+ SELECT(F, EvaluatingLinkDepends, LINK_DEPENDS) \
+ SELECT(F, EvaluatingPrecompileHeaders, PRECOMPILE_HEADERS)
+
+#define CM_FOR_EACH_TRANSITIVE_PROPERTY(F) \
+ CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH)
+
+#define CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(F) \
+ CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_FIRST)
+
+#define CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(F) \
+ CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_SECOND)
+
+struct cmGeneratorExpressionDAGChecker
+{
+ cmGeneratorExpressionDAGChecker(cmListFileBacktrace backtrace,
+ cmGeneratorTarget const* target,
+ std::string property,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* parent);
+ cmGeneratorExpressionDAGChecker(cmGeneratorTarget const* target,
+ std::string property,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* parent);
+
+ enum Result
+ {
+ DAG,
+ SELF_REFERENCE,
+ CYCLIC_REFERENCE,
+ ALREADY_SEEN
+ };
+
+ Result Check() const;
+
+ void ReportError(cmGeneratorExpressionContext* context,
+ const std::string& expr);
+
+ bool EvaluatingGenexExpression() const;
+ bool EvaluatingPICExpression() const;
+ bool EvaluatingCompileExpression() const;
+ bool EvaluatingLinkExpression() const;
+ bool EvaluatingLinkOptionsExpression() const;
+
+ bool EvaluatingLinkLibraries(cmGeneratorTarget const* tgt = nullptr) const;
+
+#define DECLARE_TRANSITIVE_PROPERTY_METHOD(METHOD) bool METHOD() const;
+
+ CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(DECLARE_TRANSITIVE_PROPERTY_METHOD)
+
+#undef DECLARE_TRANSITIVE_PROPERTY_METHOD
+
+ bool GetTransitivePropertiesOnly() const;
+ void SetTransitivePropertiesOnly() { this->TransitivePropertiesOnly = true; }
+
+ cmGeneratorExpressionDAGChecker const* Top() const;
+ cmGeneratorTarget const* TopTarget() const;
+
+private:
+ Result CheckGraph() const;
+ void Initialize();
+
+ const cmGeneratorExpressionDAGChecker* const Parent;
+ cmGeneratorTarget const* Target;
+ const std::string Property;
+ mutable std::map<cmGeneratorTarget const*, std::set<std::string>> Seen;
+ const GeneratorExpressionContent* const Content;
+ const cmListFileBacktrace Backtrace;
+ Result CheckResult;
+ bool TransitivePropertiesOnly;
+};
diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx
new file mode 100644
index 0000000..9fae15a
--- /dev/null
+++ b/Source/cmGeneratorExpressionEvaluationFile.cxx
@@ -0,0 +1,274 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGeneratorExpressionEvaluationFile.h"
+
+#include <memory>
+#include <sstream>
+#include <utility>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmSourceFile.h"
+#include "cmSystemTools.h"
+
+cmGeneratorExpressionEvaluationFile::cmGeneratorExpressionEvaluationFile(
+ std::string input, std::string target,
+ std::unique_ptr<cmCompiledGeneratorExpression> outputFileExpr,
+ std::unique_ptr<cmCompiledGeneratorExpression> condition,
+ bool inputIsContent, std::string newLineCharacter, mode_t permissions,
+ cmPolicies::PolicyStatus policyStatusCMP0070)
+ : Input(std::move(input))
+ , Target(std::move(target))
+ , OutputFileExpr(std::move(outputFileExpr))
+ , Condition(std::move(condition))
+ , InputIsContent(inputIsContent)
+ , NewLineCharacter(std::move(newLineCharacter))
+ , PolicyStatusCMP0070(policyStatusCMP0070)
+ , Permissions(permissions)
+{
+}
+
+void cmGeneratorExpressionEvaluationFile::Generate(
+ cmLocalGenerator* lg, const std::string& config, const std::string& lang,
+ cmCompiledGeneratorExpression* inputExpression,
+ std::map<std::string, std::string>& outputFiles, mode_t perm)
+{
+ std::string rawCondition = this->Condition->GetInput();
+ cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(this->Target);
+ if (!rawCondition.empty()) {
+ std::string condResult =
+ this->Condition->Evaluate(lg, config, target, nullptr, nullptr, lang);
+ if (condResult == "0") {
+ return;
+ }
+ if (condResult != "1") {
+ std::ostringstream e;
+ e << "Evaluation file condition \"" << rawCondition
+ << "\" did "
+ "not evaluate to valid content. Got \""
+ << condResult << "\".";
+ lg->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+ }
+
+ const std::string outputFileName =
+ this->GetOutputFileName(lg, target, config, lang);
+ const std::string& outputContent =
+ inputExpression->Evaluate(lg, config, target, nullptr, nullptr, lang);
+
+ auto it = outputFiles.find(outputFileName);
+
+ if (it != outputFiles.end()) {
+ if (it->second == outputContent) {
+ return;
+ }
+ std::ostringstream e;
+ e << "Evaluation file to be written multiple times with different "
+ "content. "
+ "This is generally caused by the content evaluating the "
+ "configuration type, language, or location of object files:\n "
+ << outputFileName;
+ lg->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+
+ lg->GetMakefile()->AddCMakeOutputFile(outputFileName);
+ this->Files.push_back(outputFileName);
+ outputFiles[outputFileName] = outputContent;
+
+ bool openWithBinaryFlag = false;
+ if (!this->NewLineCharacter.empty()) {
+ openWithBinaryFlag = true;
+ }
+ cmGeneratedFileStream fout;
+ fout.Open(outputFileName, false, openWithBinaryFlag);
+ if (!fout) {
+ lg->IssueMessage(MessageType::FATAL_ERROR,
+ "Could not open file for write in copy operation " +
+ outputFileName);
+ return;
+ }
+ fout.SetCopyIfDifferent(true);
+ std::istringstream iss(outputContent);
+ std::string line;
+ bool hasNewLine = false;
+ while (cmSystemTools::GetLineFromStream(iss, line, &hasNewLine)) {
+ fout << line;
+ if (!this->NewLineCharacter.empty()) {
+ fout << this->NewLineCharacter;
+ } else if (hasNewLine) {
+ // if new line character is not specified, the file will be opened in
+ // text mode. So, "\n" will be translated to the correct newline
+ // ending based on the platform.
+ fout << "\n";
+ }
+ }
+ if (fout.Close() && perm) {
+ cmSystemTools::SetPermissions(outputFileName.c_str(), perm);
+ }
+}
+
+void cmGeneratorExpressionEvaluationFile::CreateOutputFile(
+ cmLocalGenerator* lg, std::string const& config)
+{
+ std::vector<std::string> enabledLanguages;
+ cmGlobalGenerator* gg = lg->GetGlobalGenerator();
+ cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(this->Target);
+ gg->GetEnabledLanguages(enabledLanguages);
+
+ for (std::string const& le : enabledLanguages) {
+ std::string const name = this->GetOutputFileName(lg, target, config, le);
+ cmSourceFile* sf = lg->GetMakefile()->GetOrCreateGeneratedSource(name);
+
+ // Tell the build system generators that there is no build rule
+ // to generate the file.
+ sf->SetProperty("__CMAKE_GENERATED_BY_CMAKE", "1");
+
+ gg->SetFilenameTargetDepends(
+ sf, this->OutputFileExpr->GetSourceSensitiveTargets());
+ }
+}
+
+void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator* lg)
+{
+ std::string inputContent;
+ if (this->InputIsContent) {
+ inputContent = this->Input;
+ } else {
+ const std::string inputFileName = this->GetInputFileName(lg);
+ lg->GetMakefile()->AddCMakeDependFile(inputFileName);
+ if (!this->Permissions) {
+ cmSystemTools::GetPermissions(inputFileName.c_str(), this->Permissions);
+ }
+ cmsys::ifstream fin(inputFileName.c_str());
+ if (!fin) {
+ std::ostringstream e;
+ e << "Evaluation file \"" << inputFileName << "\" cannot be read.";
+ lg->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+
+ std::string line;
+ std::string sep;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ inputContent += sep + line;
+ sep = "\n";
+ }
+ inputContent += sep;
+ }
+
+ cmListFileBacktrace lfbt = this->OutputFileExpr->GetBacktrace();
+ cmGeneratorExpression contentGE(lfbt);
+ std::unique_ptr<cmCompiledGeneratorExpression> inputExpression =
+ contentGE.Parse(inputContent);
+
+ std::map<std::string, std::string> outputFiles;
+
+ std::vector<std::string> allConfigs =
+ lg->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+ std::vector<std::string> enabledLanguages;
+ cmGlobalGenerator* gg = lg->GetGlobalGenerator();
+ gg->GetEnabledLanguages(enabledLanguages);
+
+ for (std::string const& le : enabledLanguages) {
+ for (std::string const& li : allConfigs) {
+ this->Generate(lg, li, le, inputExpression.get(), outputFiles,
+ this->Permissions);
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ return;
+ }
+ }
+ }
+}
+
+std::string cmGeneratorExpressionEvaluationFile::GetInputFileName(
+ cmLocalGenerator* lg)
+{
+ std::string inputFileName = this->Input;
+
+ if (cmSystemTools::FileIsFullPath(inputFileName)) {
+ inputFileName = cmSystemTools::CollapseFullPath(inputFileName);
+ } else {
+ inputFileName = this->FixRelativePath(inputFileName, PathForInput, lg);
+ }
+
+ return inputFileName;
+}
+
+std::string cmGeneratorExpressionEvaluationFile::GetOutputFileName(
+ cmLocalGenerator* lg, cmGeneratorTarget* target, const std::string& config,
+ const std::string& lang)
+{
+ std::string outputFileName =
+ this->OutputFileExpr->Evaluate(lg, config, target, nullptr, nullptr, lang);
+
+ if (cmSystemTools::FileIsFullPath(outputFileName)) {
+ outputFileName = cmSystemTools::CollapseFullPath(outputFileName);
+ } else {
+ outputFileName = this->FixRelativePath(outputFileName, PathForOutput, lg);
+ }
+
+ return outputFileName;
+}
+
+std::string cmGeneratorExpressionEvaluationFile::FixRelativePath(
+ std::string const& relativePath, PathRole role, cmLocalGenerator* lg)
+{
+ std::string resultPath;
+ switch (this->PolicyStatusCMP0070) {
+ case cmPolicies::WARN: {
+ std::string arg;
+ switch (role) {
+ case PathForInput:
+ arg = "INPUT";
+ break;
+ case PathForOutput:
+ arg = "OUTPUT";
+ break;
+ }
+ std::ostringstream w;
+ /* clang-format off */
+ w <<
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0070) << "\n"
+ "file(GENERATE) given relative " << arg << " path:\n"
+ " " << relativePath << "\n"
+ "This is not defined behavior unless CMP0070 is set to NEW. "
+ "For compatibility with older versions of CMake, the previous "
+ "undefined behavior will be used."
+ ;
+ /* clang-format on */
+ lg->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior is to use the relative path unchanged,
+ // which ends up being used relative to the working dir.
+ resultPath = relativePath;
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // NEW behavior is to interpret the relative path with respect
+ // to the current source or binary directory.
+ switch (role) {
+ case PathForInput:
+ resultPath = cmSystemTools::CollapseFullPath(
+ relativePath, lg->GetCurrentSourceDirectory());
+ break;
+ case PathForOutput:
+ resultPath = cmSystemTools::CollapseFullPath(
+ relativePath, lg->GetCurrentBinaryDirectory());
+ break;
+ }
+ break;
+ }
+ return resultPath;
+}
diff --git a/Source/cmGeneratorExpressionEvaluationFile.h b/Source/cmGeneratorExpressionEvaluationFile.h
new file mode 100644
index 0000000..0eb78ac
--- /dev/null
+++ b/Source/cmGeneratorExpressionEvaluationFile.h
@@ -0,0 +1,64 @@
+/* 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 <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "cm_sys_stat.h"
+
+#include "cmGeneratorExpression.h"
+#include "cmPolicies.h"
+
+class cmGeneratorTarget;
+class cmLocalGenerator;
+
+class cmGeneratorExpressionEvaluationFile
+{
+public:
+ cmGeneratorExpressionEvaluationFile(
+ std::string input, std::string target,
+ std::unique_ptr<cmCompiledGeneratorExpression> outputFileExpr,
+ std::unique_ptr<cmCompiledGeneratorExpression> condition,
+ bool inputIsContent, std::string newLineCharacter, mode_t permissions,
+ cmPolicies::PolicyStatus policyStatusCMP0070);
+
+ void Generate(cmLocalGenerator* lg);
+
+ std::vector<std::string> GetFiles() const { return this->Files; }
+
+ void CreateOutputFile(cmLocalGenerator* lg, std::string const& config);
+
+private:
+ void Generate(cmLocalGenerator* lg, const std::string& config,
+ const std::string& lang,
+ cmCompiledGeneratorExpression* inputExpression,
+ std::map<std::string, std::string>& outputFiles, mode_t perm);
+
+ std::string GetInputFileName(cmLocalGenerator* lg);
+ std::string GetOutputFileName(cmLocalGenerator* lg,
+ cmGeneratorTarget* target,
+ const std::string& config,
+ const std::string& lang);
+ enum PathRole
+ {
+ PathForInput,
+ PathForOutput
+ };
+ std::string FixRelativePath(std::string const& filePath, PathRole role,
+ cmLocalGenerator* lg);
+
+ const std::string Input;
+ const std::string Target;
+ const std::unique_ptr<cmCompiledGeneratorExpression> OutputFileExpr;
+ const std::unique_ptr<cmCompiledGeneratorExpression> Condition;
+ std::vector<std::string> Files;
+ const bool InputIsContent;
+ const std::string NewLineCharacter;
+ cmPolicies::PolicyStatus PolicyStatusCMP0070;
+ mode_t Permissions;
+};
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
new file mode 100644
index 0000000..fec309c
--- /dev/null
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -0,0 +1,174 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGeneratorExpressionEvaluator.h"
+
+#include <sstream>
+
+#include "cmGeneratorExpressionContext.h"
+#include "cmGeneratorExpressionNode.h"
+
+GeneratorExpressionContent::GeneratorExpressionContent(
+ const char* startContent, size_t length)
+ : StartContent(startContent)
+ , ContentLength(length)
+{
+}
+
+GeneratorExpressionContent::~GeneratorExpressionContent() = default;
+
+std::string GeneratorExpressionContent::GetOriginalExpression() const
+{
+ return std::string(this->StartContent, this->ContentLength);
+}
+
+std::string GeneratorExpressionContent::ProcessArbitraryContent(
+ const cmGeneratorExpressionNode* node, const std::string& identifier,
+ cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::vector<cmGeneratorExpressionEvaluatorVector>::const_iterator pit) const
+{
+ std::string result;
+
+ const auto pend = this->ParamChildren.end();
+ for (; pit != pend; ++pit) {
+ for (const auto& pExprEval : *pit) {
+ if (node->RequiresLiteralInput()) {
+ if (pExprEval->GetType() != cmGeneratorExpressionEvaluator::Text) {
+ reportError(context, this->GetOriginalExpression(),
+ "$<" + identifier +
+ "> expression requires literal input.");
+ return std::string();
+ }
+ }
+ result += pExprEval->Evaluate(context, dagChecker);
+ if (context->HadError) {
+ return std::string();
+ }
+ }
+ if ((pit + 1) != pend) {
+ result += ",";
+ }
+ }
+ if (node->RequiresLiteralInput()) {
+ std::vector<std::string> parameters;
+ parameters.push_back(result);
+ return node->Evaluate(parameters, context, this, dagChecker);
+ }
+ return result;
+}
+
+std::string GeneratorExpressionContent::Evaluate(
+ cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker* dagChecker) const
+{
+ std::string identifier;
+ {
+ for (const auto& pExprEval : this->IdentifierChildren) {
+ identifier += pExprEval->Evaluate(context, dagChecker);
+ if (context->HadError) {
+ return std::string();
+ }
+ }
+ }
+
+ const cmGeneratorExpressionNode* node =
+ cmGeneratorExpressionNode::GetNode(identifier);
+
+ if (!node) {
+ reportError(context, this->GetOriginalExpression(),
+ "Expression did not evaluate to a known generator expression");
+ return std::string();
+ }
+
+ if (!node->GeneratesContent()) {
+ if (node->NumExpectedParameters() == 1 &&
+ node->AcceptsArbitraryContentParameter()) {
+ if (this->ParamChildren.empty()) {
+ reportError(context, this->GetOriginalExpression(),
+ "$<" + identifier + "> expression requires a parameter.");
+ }
+ } else {
+ std::vector<std::string> parameters;
+ this->EvaluateParameters(node, identifier, context, dagChecker,
+ parameters);
+ }
+ return std::string();
+ }
+
+ std::vector<std::string> parameters;
+ this->EvaluateParameters(node, identifier, context, dagChecker, parameters);
+ if (context->HadError) {
+ return std::string();
+ }
+
+ return node->Evaluate(parameters, context, this, dagChecker);
+}
+
+std::string GeneratorExpressionContent::EvaluateParameters(
+ const cmGeneratorExpressionNode* node, const std::string& identifier,
+ cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::vector<std::string>& parameters) const
+{
+ const int numExpected = node->NumExpectedParameters();
+ {
+ auto pit = this->ParamChildren.begin();
+ const auto pend = this->ParamChildren.end();
+ const bool acceptsArbitraryContent =
+ node->AcceptsArbitraryContentParameter();
+ int counter = 1;
+ for (; pit != pend; ++pit, ++counter) {
+ if (acceptsArbitraryContent && counter == numExpected) {
+ parameters.push_back(this->ProcessArbitraryContent(
+ node, identifier, context, dagChecker, pit));
+ return std::string();
+ }
+ std::string parameter;
+ for (const auto& pExprEval : *pit) {
+ parameter += pExprEval->Evaluate(context, dagChecker);
+ if (context->HadError) {
+ return std::string();
+ }
+ }
+ parameters.push_back(std::move(parameter));
+ }
+ }
+
+ if ((numExpected > cmGeneratorExpressionNode::DynamicParameters &&
+ static_cast<unsigned int>(numExpected) != parameters.size())) {
+ if (numExpected == 0) {
+ reportError(context, this->GetOriginalExpression(),
+ "$<" + identifier + "> expression requires no parameters.");
+ } else if (numExpected == 1) {
+ reportError(context, this->GetOriginalExpression(),
+ "$<" + identifier +
+ "> expression requires "
+ "exactly one parameter.");
+ } else {
+ std::ostringstream e;
+ e << "$<" + identifier + "> expression requires " << numExpected
+ << " comma separated parameters, but got " << parameters.size()
+ << " instead.";
+ reportError(context, this->GetOriginalExpression(), e.str());
+ }
+ return std::string();
+ }
+
+ if (numExpected == cmGeneratorExpressionNode::OneOrMoreParameters &&
+ parameters.empty()) {
+ reportError(context, this->GetOriginalExpression(),
+ "$<" + identifier +
+ "> expression requires at least one parameter.");
+ } else if (numExpected == cmGeneratorExpressionNode::TwoOrMoreParameters &&
+ parameters.size() < 2) {
+ reportError(context, this->GetOriginalExpression(),
+ "$<" + identifier +
+ "> expression requires at least two parameters.");
+ } else if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters &&
+ parameters.size() > 1) {
+ reportError(context, this->GetOriginalExpression(),
+ "$<" + identifier +
+ "> expression requires one or zero parameters.");
+ }
+ return std::string();
+}
diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h
new file mode 100644
index 0000000..8f47c0b
--- /dev/null
+++ b/Source/cmGeneratorExpressionEvaluator.h
@@ -0,0 +1,115 @@
+/* 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 <cstddef>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+struct cmGeneratorExpressionContext;
+struct cmGeneratorExpressionDAGChecker;
+struct cmGeneratorExpressionNode;
+
+struct cmGeneratorExpressionEvaluator
+{
+ cmGeneratorExpressionEvaluator() = default;
+ virtual ~cmGeneratorExpressionEvaluator() = default;
+
+ cmGeneratorExpressionEvaluator(cmGeneratorExpressionEvaluator const&) =
+ delete;
+ cmGeneratorExpressionEvaluator& operator=(
+ cmGeneratorExpressionEvaluator const&) = delete;
+
+ enum Type
+ {
+ Text,
+ Generator
+ };
+
+ virtual Type GetType() const = 0;
+
+ virtual std::string Evaluate(cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker*) const = 0;
+};
+
+using cmGeneratorExpressionEvaluatorVector =
+ std::vector<std::unique_ptr<cmGeneratorExpressionEvaluator>>;
+
+struct TextContent : public cmGeneratorExpressionEvaluator
+{
+ TextContent(const char* start, size_t length)
+ : Content(start)
+ , Length(length)
+ {
+ }
+
+ std::string Evaluate(cmGeneratorExpressionContext*,
+ cmGeneratorExpressionDAGChecker*) const override
+ {
+ return std::string(this->Content, this->Length);
+ }
+
+ Type GetType() const override
+ {
+ return cmGeneratorExpressionEvaluator::Text;
+ }
+
+ void Extend(size_t length) { this->Length += length; }
+
+ size_t GetLength() const { return this->Length; }
+
+private:
+ const char* Content;
+ size_t Length;
+};
+
+struct GeneratorExpressionContent : public cmGeneratorExpressionEvaluator
+{
+ GeneratorExpressionContent(const char* startContent, size_t length);
+
+ void SetIdentifier(cmGeneratorExpressionEvaluatorVector&& identifier)
+ {
+ this->IdentifierChildren = std::move(identifier);
+ }
+
+ void SetParameters(
+ std::vector<cmGeneratorExpressionEvaluatorVector>&& parameters)
+ {
+ this->ParamChildren = std::move(parameters);
+ }
+
+ Type GetType() const override
+ {
+ return cmGeneratorExpressionEvaluator::Generator;
+ }
+
+ std::string Evaluate(cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker*) const override;
+
+ std::string GetOriginalExpression() const;
+
+ ~GeneratorExpressionContent() override;
+
+private:
+ std::string EvaluateParameters(const cmGeneratorExpressionNode* node,
+ const std::string& identifier,
+ cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::vector<std::string>& parameters) const;
+
+ std::string ProcessArbitraryContent(
+ const cmGeneratorExpressionNode* node, const std::string& identifier,
+ cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::vector<cmGeneratorExpressionEvaluatorVector>::const_iterator pit)
+ const;
+
+ cmGeneratorExpressionEvaluatorVector IdentifierChildren;
+ std::vector<cmGeneratorExpressionEvaluatorVector> ParamChildren;
+ const char* StartContent;
+ size_t ContentLength;
+};
diff --git a/Source/cmGeneratorExpressionLexer.cxx b/Source/cmGeneratorExpressionLexer.cxx
new file mode 100644
index 0000000..b8c38c0
--- /dev/null
+++ b/Source/cmGeneratorExpressionLexer.cxx
@@ -0,0 +1,64 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGeneratorExpressionLexer.h"
+
+cmGeneratorExpressionLexer::cmGeneratorExpressionLexer() = default;
+
+static void InsertText(const char* upto, const char* c,
+ std::vector<cmGeneratorExpressionToken>& result)
+{
+ if (upto != c) {
+ result.emplace_back(cmGeneratorExpressionToken::Text, upto, c - upto);
+ }
+}
+
+std::vector<cmGeneratorExpressionToken> cmGeneratorExpressionLexer::Tokenize(
+ const std::string& input)
+{
+ std::vector<cmGeneratorExpressionToken> result;
+
+ if (input.find('$') == std::string::npos) {
+ result.emplace_back(cmGeneratorExpressionToken::Text, input.c_str(),
+ input.size());
+ return result;
+ }
+
+ const char* c = input.c_str();
+ const char* upto = c;
+
+ for (; *c; ++c) {
+ switch (*c) {
+ case '$':
+ if (c[1] == '<') {
+ InsertText(upto, c, result);
+ result.emplace_back(cmGeneratorExpressionToken::BeginExpression, c,
+ 2);
+ upto = c + 2;
+ ++c;
+ this->SawBeginExpression = true;
+ }
+ break;
+ case '>':
+ InsertText(upto, c, result);
+ result.emplace_back(cmGeneratorExpressionToken::EndExpression, c, 1);
+ upto = c + 1;
+ this->SawGeneratorExpression = this->SawBeginExpression;
+ break;
+ case ':':
+ InsertText(upto, c, result);
+ result.emplace_back(cmGeneratorExpressionToken::ColonSeparator, c, 1);
+ upto = c + 1;
+ break;
+ case ',':
+ InsertText(upto, c, result);
+ result.emplace_back(cmGeneratorExpressionToken::CommaSeparator, c, 1);
+ upto = c + 1;
+ break;
+ default:
+ break;
+ }
+ }
+ InsertText(upto, c, result);
+
+ return result;
+}
diff --git a/Source/cmGeneratorExpressionLexer.h b/Source/cmGeneratorExpressionLexer.h
new file mode 100644
index 0000000..a4321d1
--- /dev/null
+++ b/Source/cmGeneratorExpressionLexer.h
@@ -0,0 +1,50 @@
+/* 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 <cstddef>
+#include <string>
+#include <vector>
+
+struct cmGeneratorExpressionToken
+{
+ cmGeneratorExpressionToken(unsigned type, const char* c, size_t l)
+ : TokenType(type)
+ , Content(c)
+ , Length(l)
+ {
+ }
+ enum
+ {
+ Text,
+ BeginExpression,
+ EndExpression,
+ ColonSeparator,
+ CommaSeparator
+ };
+ unsigned TokenType;
+ const char* Content;
+ size_t Length;
+};
+
+/** \class cmGeneratorExpressionLexer
+ *
+ */
+class cmGeneratorExpressionLexer
+{
+public:
+ cmGeneratorExpressionLexer();
+
+ std::vector<cmGeneratorExpressionToken> Tokenize(const std::string& input);
+
+ bool GetSawGeneratorExpression() const
+ {
+ return this->SawGeneratorExpression;
+ }
+
+private:
+ bool SawBeginExpression = false;
+ bool SawGeneratorExpression = false;
+};
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
new file mode 100644
index 0000000..7125170
--- /dev/null
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -0,0 +1,2697 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGeneratorExpressionNode.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cerrno>
+#include <cstdlib>
+#include <cstring>
+#include <map>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <utility>
+
+#include <cm/iterator>
+#include <cm/optional>
+#include <cm/string_view>
+#include <cm/vector>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmsys/RegularExpression.hxx"
+#include "cmsys/String.h"
+
+#include "cmAlgorithms.h"
+#include "cmComputeLinkInformation.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionContext.h"
+#include "cmGeneratorExpressionDAGChecker.h"
+#include "cmGeneratorExpressionEvaluator.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLinkItem.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmStandardLevelResolver.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmake.h"
+
+std::string cmGeneratorExpressionNode::EvaluateDependentExpression(
+ std::string const& prop, cmLocalGenerator* lg,
+ cmGeneratorExpressionContext* context, cmGeneratorTarget const* headTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ cmGeneratorTarget const* currentTarget)
+{
+ cmGeneratorExpression ge(context->Backtrace);
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
+ cge->SetEvaluateForBuildsystem(context->EvaluateForBuildsystem);
+ cge->SetQuiet(context->Quiet);
+ std::string result =
+ cge->Evaluate(lg, context->Config, headTarget, dagChecker, currentTarget,
+ context->Language);
+ if (cge->GetHadContextSensitiveCondition()) {
+ context->HadContextSensitiveCondition = true;
+ }
+ if (cge->GetHadHeadSensitiveCondition()) {
+ context->HadHeadSensitiveCondition = true;
+ }
+ if (cge->GetHadLinkLanguageSensitiveCondition()) {
+ context->HadLinkLanguageSensitiveCondition = true;
+ }
+ return result;
+}
+
+static const struct ZeroNode : public cmGeneratorExpressionNode
+{
+ ZeroNode() {} // NOLINT(modernize-use-equals-default)
+
+ bool GeneratesContent() const override { return false; }
+
+ bool AcceptsArbitraryContentParameter() const override { return true; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& /*parameters*/,
+ cmGeneratorExpressionContext* /*context*/,
+ const GeneratorExpressionContent* /*content*/,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ return std::string();
+ }
+} zeroNode;
+
+static const struct OneNode : public cmGeneratorExpressionNode
+{
+ OneNode() {} // NOLINT(modernize-use-equals-default)
+
+ bool AcceptsArbitraryContentParameter() const override { return true; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* /*context*/,
+ const GeneratorExpressionContent* /*content*/,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ return parameters.front();
+ }
+} oneNode;
+
+static const struct OneNode buildInterfaceNode;
+
+static const struct ZeroNode installInterfaceNode;
+
+struct BooleanOpNode : public cmGeneratorExpressionNode
+{
+ BooleanOpNode(const char* op_, const char* successVal_,
+ const char* failureVal_)
+ : op(op_)
+ , successVal(successVal_)
+ , failureVal(failureVal_)
+ {
+ }
+
+ int NumExpectedParameters() const override { return OneOrMoreParameters; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker*) const override
+ {
+ for (std::string const& param : parameters) {
+ if (param == this->failureVal) {
+ return this->failureVal;
+ }
+ if (param != this->successVal) {
+ std::ostringstream e;
+ e << "Parameters to $<" << this->op;
+ e << "> must resolve to either '0' or '1'.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return std::string();
+ }
+ }
+ return this->successVal;
+ }
+
+ const char *const op, *const successVal, *const failureVal;
+};
+
+static const BooleanOpNode andNode("AND", "1", "0"), orNode("OR", "0", "1");
+
+static const struct NotNode : public cmGeneratorExpressionNode
+{
+ NotNode() {} // NOLINT(modernize-use-equals-default)
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ if (parameters.front() != "0" && parameters.front() != "1") {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<NOT> parameter must resolve to exactly one '0' or '1' value.");
+ return std::string();
+ }
+ return parameters.front() == "0" ? "1" : "0";
+ }
+} notNode;
+
+static const struct BoolNode : public cmGeneratorExpressionNode
+{
+ BoolNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* /*context*/,
+ const GeneratorExpressionContent* /*content*/,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ return !cmIsOff(parameters.front()) ? "1" : "0";
+ }
+} boolNode;
+
+static const struct IfNode : public cmGeneratorExpressionNode
+{
+ IfNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 3; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker*) const override
+ {
+ if (parameters[0] != "1" && parameters[0] != "0") {
+ reportError(context, content->GetOriginalExpression(),
+ "First parameter to $<IF> must resolve to exactly one '0' "
+ "or '1' value.");
+ return std::string();
+ }
+ return parameters[0] == "1" ? parameters[1] : parameters[2];
+ }
+} ifNode;
+
+static const struct StrEqualNode : public cmGeneratorExpressionNode
+{
+ StrEqualNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 2; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* /*context*/,
+ const GeneratorExpressionContent* /*content*/,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ return parameters.front() == parameters[1] ? "1" : "0";
+ }
+} strEqualNode;
+
+static const struct EqualNode : public cmGeneratorExpressionNode
+{
+ EqualNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 2; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ long numbers[2];
+ for (int i = 0; i < 2; ++i) {
+ if (!ParameterToLong(parameters[i].c_str(), &numbers[i])) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<EQUAL> parameter " + parameters[i] +
+ " is not a valid integer.");
+ return {};
+ }
+ }
+ return numbers[0] == numbers[1] ? "1" : "0";
+ }
+
+ static bool ParameterToLong(const char* param, long* outResult)
+ {
+ const char isNegative = param[0] == '-';
+
+ int base = 0;
+ if (cmHasLiteralPrefix(param, "0b") || cmHasLiteralPrefix(param, "0B")) {
+ base = 2;
+ param += 2;
+ } else if (cmHasLiteralPrefix(param, "-0b") ||
+ cmHasLiteralPrefix(param, "-0B") ||
+ cmHasLiteralPrefix(param, "+0b") ||
+ cmHasLiteralPrefix(param, "+0B")) {
+ base = 2;
+ param += 3;
+ }
+
+ char* pEnd;
+ long result = strtol(param, &pEnd, base);
+ if (pEnd == param || *pEnd != '\0' || errno == ERANGE) {
+ return false;
+ }
+ if (isNegative && result > 0) {
+ result *= -1;
+ }
+ *outResult = result;
+ return true;
+ }
+} equalNode;
+
+static const struct InListNode : public cmGeneratorExpressionNode
+{
+ InListNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 2; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* /*content*/,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ std::vector<std::string> values;
+ std::vector<std::string> checkValues;
+ bool check = false;
+ switch (context->LG->GetPolicyStatus(cmPolicies::CMP0085)) {
+ case cmPolicies::WARN:
+ if (parameters.front().empty()) {
+ check = true;
+ cmExpandList(parameters[1], checkValues, true);
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ cmExpandList(parameters[1], values);
+ if (check && values != checkValues) {
+ std::ostringstream e;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0085)
+ << "\nSearch Item:\n \"" << parameters.front()
+ << "\"\nList:\n \"" << parameters[1] << "\"\n";
+ context->LG->GetCMakeInstance()->IssueMessage(
+ MessageType ::AUTHOR_WARNING, e.str(), context->Backtrace);
+ return "0";
+ }
+ if (values.empty()) {
+ return "0";
+ }
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ cmExpandList(parameters[1], values, true);
+ break;
+ }
+
+ return cm::contains(values, parameters.front()) ? "1" : "0";
+ }
+} inListNode;
+
+static const struct FilterNode : public cmGeneratorExpressionNode
+{
+ FilterNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 3; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ if (parameters.size() != 3) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<FILTER:...> expression requires three parameters");
+ return {};
+ }
+
+ if (parameters[1] != "INCLUDE" && parameters[1] != "EXCLUDE") {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<FILTER:...> second parameter must be either INCLUDE or EXCLUDE");
+ return {};
+ }
+
+ const bool exclude = parameters[1] == "EXCLUDE";
+
+ cmsys::RegularExpression re;
+ if (!re.compile(parameters[2])) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<FILTER:...> failed to compile regex");
+ return {};
+ }
+
+ std::vector<std::string> values;
+ std::vector<std::string> result;
+ cmExpandList(parameters.front(), values, true);
+
+ std::copy_if(values.cbegin(), values.cend(), std::back_inserter(result),
+ [&re, exclude](std::string const& input) {
+ return exclude ^ re.find(input);
+ });
+ return cmJoin(cmMakeRange(result.cbegin(), result.cend()), ";");
+ }
+} filterNode;
+
+static const struct RemoveDuplicatesNode : public cmGeneratorExpressionNode
+{
+ RemoveDuplicatesNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ if (parameters.size() != 1) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<REMOVE_DUPLICATES:...> expression requires one parameter");
+ }
+
+ std::vector<std::string> values = cmExpandedList(parameters.front(), true);
+
+ auto valuesEnd = cmRemoveDuplicates(values);
+ auto valuesBegin = values.cbegin();
+ return cmJoin(cmMakeRange(valuesBegin, valuesEnd), ";");
+ }
+
+} removeDuplicatesNode;
+
+static const struct TargetExistsNode : public cmGeneratorExpressionNode
+{
+ TargetExistsNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ if (parameters.size() != 1) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<TARGET_EXISTS:...> expression requires one parameter");
+ return std::string();
+ }
+
+ std::string targetName = parameters.front();
+ if (targetName.empty() ||
+ !cmGeneratorExpression::IsValidTargetName(targetName)) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<TARGET_EXISTS:tgt> expression requires a non-empty "
+ "valid target name.");
+ return std::string();
+ }
+
+ return context->LG->GetMakefile()->FindTargetToUse(targetName) ? "1" : "0";
+ }
+} targetExistsNode;
+
+static const struct TargetNameIfExistsNode : public cmGeneratorExpressionNode
+{
+ TargetNameIfExistsNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ if (parameters.size() != 1) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<TARGET_NAME_IF_EXISTS:...> expression requires one "
+ "parameter");
+ return std::string();
+ }
+
+ std::string targetName = parameters.front();
+ if (targetName.empty() ||
+ !cmGeneratorExpression::IsValidTargetName(targetName)) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<TARGET_NAME_IF_EXISTS:tgt> expression requires a "
+ "non-empty valid target name.");
+ return std::string();
+ }
+
+ return context->LG->GetMakefile()->FindTargetToUse(targetName)
+ ? targetName
+ : std::string();
+ }
+} targetNameIfExistsNode;
+
+struct GenexEvaluator : public cmGeneratorExpressionNode
+{
+ GenexEvaluator() {} // NOLINT(modernize-use-equals-default)
+
+protected:
+ std::string EvaluateExpression(
+ const std::string& genexOperator, const std::string& expression,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagCheckerParent) const
+ {
+ if (context->HeadTarget) {
+ cmGeneratorExpressionDAGChecker dagChecker(
+ context->Backtrace, context->HeadTarget,
+ genexOperator + ":" + expression, content, dagCheckerParent);
+ switch (dagChecker.Check()) {
+ case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
+ case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: {
+ dagChecker.ReportError(context, content->GetOriginalExpression());
+ return std::string();
+ }
+ case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
+ case cmGeneratorExpressionDAGChecker::DAG:
+ break;
+ }
+
+ return this->EvaluateDependentExpression(
+ expression, context->LG, context, context->HeadTarget, &dagChecker,
+ context->CurrentTarget);
+ }
+
+ return this->EvaluateDependentExpression(
+ expression, context->LG, context, context->HeadTarget, dagCheckerParent,
+ context->CurrentTarget);
+ }
+};
+
+static const struct TargetGenexEvalNode : public GenexEvaluator
+{
+ TargetGenexEvalNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 2; }
+
+ bool AcceptsArbitraryContentParameter() const override { return true; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
+ {
+ const std::string& targetName = parameters.front();
+ if (targetName.empty() ||
+ !cmGeneratorExpression::IsValidTargetName(targetName)) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<TARGET_GENEX_EVAL:tgt, ...> expression requires a "
+ "non-empty valid target name.");
+ return std::string();
+ }
+
+ const auto* target = context->LG->FindGeneratorTargetToUse(targetName);
+ if (!target) {
+ std::ostringstream e;
+ e << "$<TARGET_GENEX_EVAL:tgt, ...> target \"" << targetName
+ << "\" not found.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return std::string();
+ }
+
+ const std::string& expression = parameters[1];
+ if (expression.empty()) {
+ return expression;
+ }
+
+ cmGeneratorExpressionContext targetContext(
+ context->LG, context->Config, context->Quiet, target, target,
+ context->EvaluateForBuildsystem, context->Backtrace, context->Language);
+
+ return this->EvaluateExpression("TARGET_GENEX_EVAL", expression,
+ &targetContext, content, dagCheckerParent);
+ }
+} targetGenexEvalNode;
+
+static const struct GenexEvalNode : public GenexEvaluator
+{
+ GenexEvalNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ bool AcceptsArbitraryContentParameter() const override { return true; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
+ {
+ const std::string& expression = parameters[0];
+ if (expression.empty()) {
+ return expression;
+ }
+
+ return this->EvaluateExpression("GENEX_EVAL", expression, context, content,
+ dagCheckerParent);
+ }
+} genexEvalNode;
+
+static const struct LowerCaseNode : public cmGeneratorExpressionNode
+{
+ LowerCaseNode() {} // NOLINT(modernize-use-equals-default)
+
+ bool AcceptsArbitraryContentParameter() const override { return true; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* /*context*/,
+ const GeneratorExpressionContent* /*content*/,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ return cmSystemTools::LowerCase(parameters.front());
+ }
+} lowerCaseNode;
+
+static const struct UpperCaseNode : public cmGeneratorExpressionNode
+{
+ UpperCaseNode() {} // NOLINT(modernize-use-equals-default)
+
+ bool AcceptsArbitraryContentParameter() const override { return true; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* /*context*/,
+ const GeneratorExpressionContent* /*content*/,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ return cmSystemTools::UpperCase(parameters.front());
+ }
+} upperCaseNode;
+
+static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode
+{
+ MakeCIdentifierNode() {} // NOLINT(modernize-use-equals-default)
+
+ bool AcceptsArbitraryContentParameter() const override { return true; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* /*context*/,
+ const GeneratorExpressionContent* /*content*/,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ return cmSystemTools::MakeCidentifier(parameters.front());
+ }
+} makeCIdentifierNode;
+
+template <char C>
+struct CharacterNode : public cmGeneratorExpressionNode
+{
+ CharacterNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 0; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& /*parameters*/,
+ cmGeneratorExpressionContext* /*context*/,
+ const GeneratorExpressionContent* /*content*/,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ return { C };
+ }
+};
+static const CharacterNode<'>'> angle_rNode;
+static const CharacterNode<','> commaNode;
+static const CharacterNode<';'> semicolonNode;
+
+struct CompilerIdNode : public cmGeneratorExpressionNode
+{
+ CompilerIdNode(const char* compilerLang)
+ : CompilerLanguage(compilerLang)
+ {
+ }
+
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ if (!context->HeadTarget) {
+ std::ostringstream e;
+ e << "$<" << this->CompilerLanguage
+ << "_COMPILER_ID> may only be used with binary targets. It may "
+ "not be used with add_custom_command or add_custom_target.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return {};
+ }
+ return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
+ this->CompilerLanguage);
+ }
+
+ std::string EvaluateWithLanguage(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*unused*/,
+ const std::string& lang) const
+ {
+ std::string const& compilerId =
+ context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
+ "_COMPILER_ID");
+ if (parameters.empty()) {
+ return compilerId;
+ }
+ if (compilerId.empty()) {
+ return parameters.front().empty() ? "1" : "0";
+ }
+ static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$");
+
+ for (auto const& param : parameters) {
+
+ if (!compilerIdValidator.find(param)) {
+ reportError(context, content->GetOriginalExpression(),
+ "Expression syntax not recognized.");
+ return std::string();
+ }
+
+ if (strcmp(param.c_str(), compilerId.c_str()) == 0) {
+ return "1";
+ }
+
+ if (cmsysString_strcasecmp(param.c_str(), compilerId.c_str()) == 0) {
+ switch (context->LG->GetPolicyStatus(cmPolicies::CMP0044)) {
+ case cmPolicies::WARN: {
+ context->LG->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0044),
+ context->Backtrace);
+ CM_FALLTHROUGH;
+ }
+ case cmPolicies::OLD:
+ return "1";
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ break;
+ }
+ }
+ }
+ return "0";
+ }
+
+ const char* const CompilerLanguage;
+};
+
+static const CompilerIdNode cCompilerIdNode("C"), cxxCompilerIdNode("CXX"),
+ cudaCompilerIdNode("CUDA"), objcCompilerIdNode("OBJC"),
+ objcxxCompilerIdNode("OBJCXX"), fortranCompilerIdNode("Fortran"),
+ ispcCompilerIdNode("ISPC");
+
+struct CompilerVersionNode : public cmGeneratorExpressionNode
+{
+ CompilerVersionNode(const char* compilerLang)
+ : CompilerLanguage(compilerLang)
+ {
+ }
+
+ int NumExpectedParameters() const override { return OneOrZeroParameters; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ if (!context->HeadTarget) {
+ std::ostringstream e;
+ e << "$<" << this->CompilerLanguage
+ << "_COMPILER_VERSION> may only be used with binary targets. It "
+ "may not be used with add_custom_command or add_custom_target.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return {};
+ }
+ return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
+ this->CompilerLanguage);
+ }
+
+ std::string EvaluateWithLanguage(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*unused*/,
+ const std::string& lang) const
+ {
+ std::string const& compilerVersion =
+ context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
+ "_COMPILER_VERSION");
+ if (parameters.empty()) {
+ return compilerVersion;
+ }
+
+ static cmsys::RegularExpression compilerIdValidator("^[0-9\\.]*$");
+ if (!compilerIdValidator.find(parameters.front())) {
+ reportError(context, content->GetOriginalExpression(),
+ "Expression syntax not recognized.");
+ return {};
+ }
+ if (compilerVersion.empty()) {
+ return parameters.front().empty() ? "1" : "0";
+ }
+
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
+ parameters.front().c_str(),
+ compilerVersion.c_str())
+ ? "1"
+ : "0";
+ }
+
+ const char* const CompilerLanguage;
+};
+
+static const CompilerVersionNode cCompilerVersionNode("C"),
+ cxxCompilerVersionNode("CXX"), cudaCompilerVersionNode("CUDA"),
+ objcCompilerVersionNode("OBJC"), objcxxCompilerVersionNode("OBJCXX"),
+ fortranCompilerVersionNode("Fortran"), ispcCompilerVersionNode("ISPC");
+
+struct PlatformIdNode : public cmGeneratorExpressionNode
+{
+ PlatformIdNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* /*content*/,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ std::string const& platformId =
+ context->LG->GetMakefile()->GetSafeDefinition("CMAKE_SYSTEM_NAME");
+ if (parameters.empty()) {
+ return platformId;
+ }
+
+ if (platformId.empty()) {
+ return parameters.front().empty() ? "1" : "0";
+ }
+
+ for (auto const& param : parameters) {
+ if (param == platformId) {
+ return "1";
+ }
+ }
+ return "0";
+ }
+} platformIdNode;
+
+template <cmSystemTools::CompareOp Op>
+struct VersionNode : public cmGeneratorExpressionNode
+{
+ VersionNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 2; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* /*context*/,
+ const GeneratorExpressionContent* /*content*/,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ return cmSystemTools::VersionCompare(Op, parameters.front().c_str(),
+ parameters[1].c_str())
+ ? "1"
+ : "0";
+ }
+};
+
+static const VersionNode<cmSystemTools::OP_GREATER> versionGreaterNode;
+static const VersionNode<cmSystemTools::OP_GREATER_EQUAL> versionGreaterEqNode;
+static const VersionNode<cmSystemTools::OP_LESS> versionLessNode;
+static const VersionNode<cmSystemTools::OP_LESS_EQUAL> versionLessEqNode;
+static const VersionNode<cmSystemTools::OP_EQUAL> versionEqualNode;
+
+static const struct LinkOnlyNode : public cmGeneratorExpressionNode
+{
+ LinkOnlyNode() {} // NOLINT(modernize-use-equals-default)
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ if (!dagChecker) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<LINK_ONLY:...> may only be used for linking");
+ return std::string();
+ }
+ if (!dagChecker->GetTransitivePropertiesOnly()) {
+ return parameters.front();
+ }
+ return std::string();
+ }
+} linkOnlyNode;
+
+static const struct ConfigurationNode : public cmGeneratorExpressionNode
+{
+ ConfigurationNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 0; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& /*parameters*/,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* /*content*/,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ context->HadContextSensitiveCondition = true;
+ return context->Config;
+ }
+} configurationNode;
+
+static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
+{
+ ConfigurationTestNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ if (parameters.empty()) {
+ return configurationNode.Evaluate(parameters, context, content, nullptr);
+ }
+ static cmsys::RegularExpression configValidator("^[A-Za-z0-9_]*$");
+ if (!configValidator.find(parameters.front())) {
+ reportError(context, content->GetOriginalExpression(),
+ "Expression syntax not recognized.");
+ return std::string();
+ }
+ context->HadContextSensitiveCondition = true;
+ for (auto const& param : parameters) {
+ if (context->Config.empty()) {
+ if (param.empty()) {
+ return "1";
+ }
+ } else if (cmsysString_strcasecmp(param.c_str(),
+ context->Config.c_str()) == 0) {
+ return "1";
+ }
+ }
+
+ if (context->CurrentTarget && context->CurrentTarget->IsImported()) {
+ cmProp loc = nullptr;
+ cmProp imp = nullptr;
+ std::string suffix;
+ if (context->CurrentTarget->Target->GetMappedConfig(context->Config, loc,
+ imp, suffix)) {
+ // This imported target has an appropriate location
+ // for this (possibly mapped) config.
+ // Check if there is a proper config mapping for the tested config.
+ std::vector<std::string> mappedConfigs;
+ std::string mapProp = cmStrCat(
+ "MAP_IMPORTED_CONFIG_", cmSystemTools::UpperCase(context->Config));
+ if (cmProp mapValue = context->CurrentTarget->GetProperty(mapProp)) {
+ cmExpandList(cmSystemTools::UpperCase(*mapValue), mappedConfigs);
+
+ for (auto const& param : parameters) {
+ if (cm::contains(mappedConfigs, cmSystemTools::UpperCase(param))) {
+ return "1";
+ }
+ }
+ }
+ }
+ }
+ return "0";
+ }
+} configurationTestNode;
+
+static const struct JoinNode : public cmGeneratorExpressionNode
+{
+ JoinNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 2; }
+
+ bool AcceptsArbitraryContentParameter() const override { return true; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* /*context*/,
+ const GeneratorExpressionContent* /*content*/,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ std::vector<std::string> list = cmExpandedList(parameters.front());
+ return cmJoin(list, parameters[1]);
+ }
+} joinNode;
+
+static const struct CompileLanguageNode : public cmGeneratorExpressionNode
+{
+ CompileLanguageNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ if (context->Language.empty() &&
+ (!dagChecker || !dagChecker->EvaluatingCompileExpression())) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<COMPILE_LANGUAGE:...> may only be used to specify include "
+ "directories, compile definitions, compile options, and to evaluate "
+ "components of the file(GENERATE) command.");
+ return std::string();
+ }
+
+ cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
+ std::string genName = gg->GetName();
+ if (genName.find("Makefiles") == std::string::npos &&
+ genName.find("Ninja") == std::string::npos &&
+ genName.find("Visual Studio") == std::string::npos &&
+ genName.find("Xcode") == std::string::npos &&
+ genName.find("Watcom WMake") == std::string::npos) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<COMPILE_LANGUAGE:...> not supported for this generator.");
+ return std::string();
+ }
+ if (parameters.empty()) {
+ return context->Language;
+ }
+
+ for (auto const& param : parameters) {
+ if (context->Language == param) {
+ return "1";
+ }
+ }
+ return "0";
+ }
+} languageNode;
+
+static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode
+{
+ CompileLanguageAndIdNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return TwoOrMoreParameters; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ if (!context->HeadTarget ||
+ (context->Language.empty() &&
+ (!dagChecker || !dagChecker->EvaluatingCompileExpression()))) {
+ // reportError(context, content->GetOriginalExpression(), "");
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary targets "
+ "to specify include directories, compile definitions, and compile "
+ "options. It may not be used with the add_custom_command, "
+ "add_custom_target, or file(GENERATE) commands.");
+ return std::string();
+ }
+ cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
+ std::string genName = gg->GetName();
+ if (genName.find("Makefiles") == std::string::npos &&
+ genName.find("Ninja") == std::string::npos &&
+ genName.find("Visual Studio") == std::string::npos &&
+ genName.find("Xcode") == std::string::npos &&
+ genName.find("Watcom WMake") == std::string::npos) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<COMPILE_LANG_AND_ID:lang,id> not supported for this generator.");
+ return std::string();
+ }
+
+ const std::string& lang = context->Language;
+ if (lang == parameters.front()) {
+ std::vector<std::string> idParameter((parameters.cbegin() + 1),
+ parameters.cend());
+ return CompilerIdNode{ lang.c_str() }.EvaluateWithLanguage(
+ idParameter, context, content, dagChecker, lang);
+ }
+ return "0";
+ }
+} languageAndIdNode;
+
+static const struct LinkLanguageNode : public cmGeneratorExpressionNode
+{
+ LinkLanguageNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ if (!context->HeadTarget || !dagChecker ||
+ !(dagChecker->EvaluatingLinkExpression() ||
+ dagChecker->EvaluatingLinkLibraries())) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<LINK_LANGUAGE:...> may only be used with binary targets "
+ "to specify link libraries, link directories, link options "
+ "and link depends.");
+ return std::string();
+ }
+ if (dagChecker->EvaluatingLinkLibraries() && parameters.empty()) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<LINK_LANGUAGE> is not supported in link libraries expression.");
+ return std::string();
+ }
+
+ cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
+ std::string genName = gg->GetName();
+ if (genName.find("Makefiles") == std::string::npos &&
+ genName.find("Ninja") == std::string::npos &&
+ genName.find("Visual Studio") == std::string::npos &&
+ genName.find("Xcode") == std::string::npos &&
+ genName.find("Watcom WMake") == std::string::npos) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<LINK_LANGUAGE:...> not supported for this generator.");
+ return std::string();
+ }
+
+ if (dagChecker->EvaluatingLinkLibraries()) {
+ context->HadHeadSensitiveCondition = true;
+ context->HadLinkLanguageSensitiveCondition = true;
+ }
+
+ if (parameters.empty()) {
+ return context->Language;
+ }
+
+ for (auto const& param : parameters) {
+ if (context->Language == param) {
+ return "1";
+ }
+ }
+ return "0";
+ }
+} linkLanguageNode;
+
+namespace {
+struct LinkerId
+{
+ static std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ const std::string& lang)
+ {
+ std::string const& linkerId =
+ context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
+ "_COMPILER_ID");
+ if (parameters.empty()) {
+ return linkerId;
+ }
+ if (linkerId.empty()) {
+ return parameters.front().empty() ? "1" : "0";
+ }
+ static cmsys::RegularExpression linkerIdValidator("^[A-Za-z0-9_]*$");
+
+ for (auto const& param : parameters) {
+ if (!linkerIdValidator.find(param)) {
+ reportError(context, content->GetOriginalExpression(),
+ "Expression syntax not recognized.");
+ return std::string();
+ }
+
+ if (param == linkerId) {
+ return "1";
+ }
+ }
+ return "0";
+ }
+};
+}
+
+static const struct LinkLanguageAndIdNode : public cmGeneratorExpressionNode
+{
+ LinkLanguageAndIdNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return TwoOrMoreParameters; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ if (!context->HeadTarget || !dagChecker ||
+ !(dagChecker->EvaluatingLinkExpression() ||
+ dagChecker->EvaluatingLinkLibraries())) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<LINK_LANG_AND_ID:lang,id> may only be used with binary targets "
+ "to specify link libraries, link directories, link options, and link "
+ "depends.");
+ return std::string();
+ }
+
+ cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
+ std::string genName = gg->GetName();
+ if (genName.find("Makefiles") == std::string::npos &&
+ genName.find("Ninja") == std::string::npos &&
+ genName.find("Visual Studio") == std::string::npos &&
+ genName.find("Xcode") == std::string::npos &&
+ genName.find("Watcom WMake") == std::string::npos) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<LINK_LANG_AND_ID:lang,id> not supported for this generator.");
+ return std::string();
+ }
+
+ if (dagChecker->EvaluatingLinkLibraries()) {
+ context->HadHeadSensitiveCondition = true;
+ context->HadLinkLanguageSensitiveCondition = true;
+ }
+
+ const std::string& lang = context->Language;
+ if (lang == parameters.front()) {
+ std::vector<std::string> idParameter((parameters.cbegin() + 1),
+ parameters.cend());
+ return LinkerId::Evaluate(idParameter, context, content, lang);
+ }
+ return "0";
+ }
+} linkLanguageAndIdNode;
+
+static const struct HostLinkNode : public cmGeneratorExpressionNode
+{
+ HostLinkNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ if (!context->HeadTarget || !dagChecker ||
+ !dagChecker->EvaluatingLinkOptionsExpression()) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<HOST_LINK:...> may only be used with binary targets "
+ "to specify link options.");
+ return std::string();
+ }
+
+ return context->HeadTarget->IsDeviceLink() ? std::string()
+ : cmJoin(parameters, ";");
+ }
+} hostLinkNode;
+
+static const struct DeviceLinkNode : public cmGeneratorExpressionNode
+{
+ DeviceLinkNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ if (!context->HeadTarget || !dagChecker ||
+ !dagChecker->EvaluatingLinkOptionsExpression()) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<DEVICE_LINK:...> may only be used with binary targets "
+ "to specify link options.");
+ return std::string();
+ }
+
+ if (context->HeadTarget->IsDeviceLink()) {
+ std::vector<std::string> list;
+ cmExpandLists(parameters.begin(), parameters.end(), list);
+ const auto DL_BEGIN = "<DEVICE_LINK>"_s;
+ const auto DL_END = "</DEVICE_LINK>"_s;
+ cm::erase_if(list, [&](const std::string& item) {
+ return item == DL_BEGIN || item == DL_END;
+ });
+
+ list.insert(list.begin(), static_cast<std::string>(DL_BEGIN));
+ list.push_back(static_cast<std::string>(DL_END));
+
+ return cmJoin(list, ";");
+ }
+
+ return std::string();
+ }
+} deviceLinkNode;
+
+std::string getLinkedTargetsContent(
+ cmGeneratorTarget const* target, std::string const& prop,
+ cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker* dagChecker)
+{
+ std::string result;
+ if (cmLinkImplementationLibraries const* impl =
+ target->GetLinkImplementationLibraries(context->Config)) {
+ for (cmLinkImplItem const& lib : impl->Libraries) {
+ if (lib.Target) {
+ // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
+ // caller's property and hand-evaluate it as if it were compiled.
+ // Create a context as cmCompiledGeneratorExpression::Evaluate does.
+ cmGeneratorExpressionContext libContext(
+ target->GetLocalGenerator(), context->Config, context->Quiet, target,
+ target, context->EvaluateForBuildsystem, lib.Backtrace,
+ context->Language);
+ std::string libResult =
+ lib.Target->EvaluateInterfaceProperty(prop, &libContext, dagChecker);
+ if (!libResult.empty()) {
+ if (result.empty()) {
+ result = std::move(libResult);
+ } else {
+ result.reserve(result.size() + 1 + libResult.size());
+ result += ";";
+ result += libResult;
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+static const struct TargetPropertyNode : public cmGeneratorExpressionNode
+{
+ TargetPropertyNode() {} // NOLINT(modernize-use-equals-default)
+
+ // This node handles errors on parameter count itself.
+ int NumExpectedParameters() const override { return OneOrMoreParameters; }
+
+ static const char* GetErrorText(std::string const& targetName,
+ std::string const& propertyName)
+ {
+ static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
+ if (targetName.empty() && propertyName.empty()) {
+ return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
+ "target name and property name.";
+ }
+ if (targetName.empty()) {
+ return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
+ "target name.";
+ }
+ if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
+ if (!propertyNameValidator.find(propertyName)) {
+ return "Target name and property name not supported.";
+ }
+ return "Target name not supported.";
+ }
+ return nullptr;
+ }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
+ {
+ static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
+
+ cmGeneratorTarget const* target = nullptr;
+ std::string targetName;
+ std::string propertyName;
+
+ if (parameters.size() == 2) {
+ targetName = parameters[0];
+ propertyName = parameters[1];
+
+ if (const char* e = GetErrorText(targetName, propertyName)) {
+ reportError(context, content->GetOriginalExpression(), e);
+ return std::string();
+ }
+ if (propertyName == "ALIASED_TARGET"_s) {
+ if (context->LG->GetMakefile()->IsAlias(targetName)) {
+ if (cmGeneratorTarget* tgt =
+ context->LG->FindGeneratorTargetToUse(targetName)) {
+ return tgt->GetName();
+ }
+ }
+ return std::string();
+ }
+ if (propertyName == "ALIAS_GLOBAL"_s) {
+ if (context->LG->GetMakefile()->IsAlias(targetName)) {
+ return context->LG->GetGlobalGenerator()->IsAlias(targetName)
+ ? "TRUE"
+ : "FALSE";
+ }
+ return std::string();
+ }
+ target = context->LG->FindGeneratorTargetToUse(targetName);
+
+ if (!target) {
+ std::ostringstream e;
+ e << "Target \"" << targetName << "\" not found.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return std::string();
+ }
+ context->AllTargets.insert(target);
+
+ } else if (parameters.size() == 1) {
+ target = context->HeadTarget;
+ propertyName = parameters[0];
+
+ // Keep track of the properties seen while processing.
+ // The evaluation of the LINK_LIBRARIES generator expressions
+ // will check this to ensure that properties have one consistent
+ // value for all evaluations.
+ context->SeenTargetProperties.insert(propertyName);
+
+ context->HadHeadSensitiveCondition = true;
+ if (!target) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<TARGET_PROPERTY:prop> may only be used with binary targets. "
+ "It may not be used with add_custom_command or add_custom_target. "
+ " "
+ "Specify the target to read a property from using the "
+ "$<TARGET_PROPERTY:tgt,prop> signature instead.");
+ return std::string();
+ }
+ } else {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<TARGET_PROPERTY:...> expression requires one or two parameters");
+ return std::string();
+ }
+
+ if (propertyName == "SOURCES") {
+ context->SourceSensitiveTargets.insert(target);
+ }
+
+ if (propertyName.empty()) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<TARGET_PROPERTY:...> expression requires a non-empty property "
+ "name.");
+ return std::string();
+ }
+
+ if (!propertyNameValidator.find(propertyName)) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "Property name not supported.");
+ return std::string();
+ }
+
+ assert(target);
+
+ if (propertyName == "LINKER_LANGUAGE") {
+ if (target->LinkLanguagePropagatesToDependents() && dagCheckerParent &&
+ (dagCheckerParent->EvaluatingLinkLibraries() ||
+ dagCheckerParent->EvaluatingSources())) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "LINKER_LANGUAGE target property can not be used while evaluating "
+ "link libraries for a static library");
+ return std::string();
+ }
+ return target->GetLinkerLanguage(context->Config);
+ }
+
+ std::string interfacePropertyName;
+ bool isInterfaceProperty = false;
+
+#define POPULATE_INTERFACE_PROPERTY_NAME(prop) \
+ if (propertyName == #prop) { \
+ interfacePropertyName = "INTERFACE_" #prop; \
+ } else if (propertyName == "INTERFACE_" #prop) { \
+ interfacePropertyName = "INTERFACE_" #prop; \
+ isInterfaceProperty = true; \
+ } else
+
+ CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(POPULATE_INTERFACE_PROPERTY_NAME)
+ // Note that the above macro terminates with an else
+ /* else */ if (cmHasLiteralPrefix(propertyName, "COMPILE_DEFINITIONS_")) {
+ cmPolicies::PolicyStatus polSt =
+ context->LG->GetPolicyStatus(cmPolicies::CMP0043);
+ if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
+ interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS";
+ }
+ }
+#undef POPULATE_INTERFACE_PROPERTY_NAME
+
+ bool evaluatingLinkLibraries = false;
+
+ if (dagCheckerParent) {
+ if (dagCheckerParent->EvaluatingGenexExpression() ||
+ dagCheckerParent->EvaluatingPICExpression()) {
+ // No check required.
+ } else if (dagCheckerParent->EvaluatingLinkLibraries()) {
+ evaluatingLinkLibraries = true;
+ if (!interfacePropertyName.empty()) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<TARGET_PROPERTY:...> expression in link libraries "
+ "evaluation depends on target property which is transitive "
+ "over the link libraries, creating a recursion.");
+ return std::string();
+ }
+ } else {
+#define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) dagCheckerParent->METHOD() ||
+ assert(CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
+ ASSERT_TRANSITIVE_PROPERTY_METHOD) false); // NOLINT(clang-tidy)
+#undef ASSERT_TRANSITIVE_PROPERTY_METHOD
+ }
+ }
+
+ if (isInterfaceProperty) {
+ return cmGeneratorExpression::StripEmptyListElements(
+ target->EvaluateInterfaceProperty(propertyName, context,
+ dagCheckerParent));
+ }
+
+ cmGeneratorExpressionDAGChecker dagChecker(
+ context->Backtrace, target, propertyName, content, dagCheckerParent);
+
+ switch (dagChecker.Check()) {
+ case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
+ dagChecker.ReportError(context, content->GetOriginalExpression());
+ return std::string();
+ case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
+ // No error. We just skip cyclic references.
+ return std::string();
+ case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
+ // We handle transitive properties above. For non-transitive
+ // properties we accept repeats anyway.
+ case cmGeneratorExpressionDAGChecker::DAG:
+ break;
+ }
+
+ std::string result;
+ bool haveProp = false;
+ if (cmProp p = target->GetProperty(propertyName)) {
+ result = *p;
+ haveProp = true;
+ } else if (evaluatingLinkLibraries) {
+ return std::string();
+ }
+
+ if (!haveProp && !target->IsImported() &&
+ target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+ if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
+ context->Config)) {
+ context->HadContextSensitiveCondition = true;
+ return target->GetLinkInterfaceDependentBoolProperty(propertyName,
+ context->Config)
+ ? "1"
+ : "0";
+ }
+ if (target->IsLinkInterfaceDependentStringProperty(propertyName,
+ context->Config)) {
+ context->HadContextSensitiveCondition = true;
+ const char* propContent =
+ target->GetLinkInterfaceDependentStringProperty(propertyName,
+ context->Config);
+ return propContent ? propContent : "";
+ }
+ if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName,
+ context->Config)) {
+ context->HadContextSensitiveCondition = true;
+ const char* propContent =
+ target->GetLinkInterfaceDependentNumberMinProperty(propertyName,
+ context->Config);
+ return propContent ? propContent : "";
+ }
+ if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName,
+ context->Config)) {
+ context->HadContextSensitiveCondition = true;
+ const char* propContent =
+ target->GetLinkInterfaceDependentNumberMaxProperty(propertyName,
+ context->Config);
+ return propContent ? propContent : "";
+ }
+ }
+
+ if (!target->IsImported() && dagCheckerParent &&
+ !dagCheckerParent->EvaluatingLinkLibraries()) {
+ if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName,
+ context->Config)) {
+ context->HadContextSensitiveCondition = true;
+ const char* propContent =
+ target->GetLinkInterfaceDependentNumberMinProperty(propertyName,
+ context->Config);
+ return propContent ? propContent : "";
+ }
+ if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName,
+ context->Config)) {
+ context->HadContextSensitiveCondition = true;
+ const char* propContent =
+ target->GetLinkInterfaceDependentNumberMaxProperty(propertyName,
+ context->Config);
+ return propContent ? propContent : "";
+ }
+ }
+
+ if (!interfacePropertyName.empty()) {
+ result = cmGeneratorExpression::StripEmptyListElements(
+ this->EvaluateDependentExpression(result, context->LG, context, target,
+ &dagChecker, target));
+ std::string linkedTargetsContent = getLinkedTargetsContent(
+ target, interfacePropertyName, context, &dagChecker);
+ if (!linkedTargetsContent.empty()) {
+ result += (result.empty() ? "" : ";") + linkedTargetsContent;
+ }
+ }
+ return result;
+ }
+} targetPropertyNode;
+
+static const struct TargetNameNode : public cmGeneratorExpressionNode
+{
+ TargetNameNode() {} // NOLINT(modernize-use-equals-default)
+
+ bool GeneratesContent() const override { return true; }
+
+ bool AcceptsArbitraryContentParameter() const override { return true; }
+ bool RequiresLiteralInput() const override { return true; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* /*context*/,
+ const GeneratorExpressionContent* /*content*/,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ return parameters.front();
+ }
+
+ int NumExpectedParameters() const override { return 1; }
+
+} targetNameNode;
+
+static const struct TargetObjectsNode : public cmGeneratorExpressionNode
+{
+ TargetObjectsNode() {} // NOLINT(modernize-use-equals-default)
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ std::string tgtName = parameters.front();
+ cmGeneratorTarget* gt = context->LG->FindGeneratorTargetToUse(tgtName);
+ if (!gt) {
+ std::ostringstream e;
+ e << "Objects of target \"" << tgtName
+ << "\" referenced but no such target exists.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return std::string();
+ }
+ cmStateEnums::TargetType type = gt->GetType();
+ if (type != cmStateEnums::EXECUTABLE &&
+ type != cmStateEnums::STATIC_LIBRARY &&
+ type != cmStateEnums::SHARED_LIBRARY &&
+ type != cmStateEnums::MODULE_LIBRARY &&
+ type != cmStateEnums::OBJECT_LIBRARY) {
+ std::ostringstream e;
+ e << "Objects of target \"" << tgtName
+ << "\" referenced but is not one of the allowed target types "
+ << "(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT).";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return std::string();
+ }
+ if (!context->EvaluateForBuildsystem) {
+ cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
+ std::string reason;
+ if (!gg->HasKnownObjectFileLocation(&reason)) {
+ std::ostringstream e;
+ e << "The evaluation of the TARGET_OBJECTS generator expression "
+ "is only suitable for consumption by CMake (limited"
+ << reason
+ << "). "
+ "It is not suitable for writing out elsewhere.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return std::string();
+ }
+ }
+
+ std::vector<std::string> objects;
+
+ if (gt->IsImported()) {
+ cmProp loc = nullptr;
+ cmProp imp = nullptr;
+ std::string suffix;
+ if (gt->Target->GetMappedConfig(context->Config, loc, imp, suffix)) {
+ cmExpandList(*loc, objects);
+ }
+ context->HadContextSensitiveCondition = true;
+ } else {
+ gt->GetTargetObjectNames(context->Config, objects);
+
+ std::string obj_dir;
+ if (context->EvaluateForBuildsystem) {
+ // Use object file directory with buildsystem placeholder.
+ obj_dir = gt->ObjectDirectory;
+ context->HadContextSensitiveCondition =
+ gt->HasContextDependentSources();
+ } else {
+ // Use object file directory with per-config location.
+ obj_dir = gt->GetObjectDirectory(context->Config);
+ context->HadContextSensitiveCondition = true;
+ }
+
+ for (std::string& o : objects) {
+ o = cmStrCat(obj_dir, o);
+ }
+ }
+
+ // Create the cmSourceFile instances in the referencing directory.
+ cmMakefile* mf = context->LG->GetMakefile();
+ for (std::string& o : objects) {
+ mf->AddTargetObject(tgtName, o);
+ }
+
+ return cmJoin(objects, ";");
+ }
+} targetObjectsNode;
+
+static const struct TargetRuntimeDllsNode : public cmGeneratorExpressionNode
+{
+ TargetRuntimeDllsNode() {} // NOLINT(modernize-use-equals-default)
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ std::string tgtName = parameters.front();
+ cmGeneratorTarget* gt = context->LG->FindGeneratorTargetToUse(tgtName);
+ if (!gt) {
+ std::ostringstream e;
+ e << "Objects of target \"" << tgtName
+ << "\" referenced but no such target exists.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return std::string();
+ }
+ cmStateEnums::TargetType type = gt->GetType();
+ if (type != cmStateEnums::EXECUTABLE &&
+ type != cmStateEnums::SHARED_LIBRARY &&
+ type != cmStateEnums::MODULE_LIBRARY) {
+ std::ostringstream e;
+ e << "Objects of target \"" << tgtName
+ << "\" referenced but is not one of the allowed target types "
+ << "(EXECUTABLE, SHARED, MODULE).";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return std::string();
+ }
+
+ if (auto* cli = gt->GetLinkInformation(context->Config)) {
+ std::vector<std::string> dllPaths;
+ auto const& dlls = cli->GetRuntimeDLLs();
+
+ for (auto const& dll : dlls) {
+ if (auto loc = dll->MaybeGetLocation(context->Config)) {
+ dllPaths.emplace_back(*loc);
+ }
+ }
+
+ return cmJoin(dllPaths, ";");
+ }
+
+ return "";
+ }
+} targetRuntimeDllsNode;
+
+static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
+{
+ CompileFeaturesNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return OneOrMoreParameters; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ cmGeneratorTarget const* target = context->HeadTarget;
+ if (!target) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<COMPILE_FEATURE> may only be used with binary targets. It may "
+ "not be used with add_custom_command or add_custom_target.");
+ return std::string();
+ }
+ context->HadHeadSensitiveCondition = true;
+
+ using LangMap = std::map<std::string, std::vector<std::string>>;
+ static LangMap availableFeatures;
+
+ LangMap testedFeatures;
+ cmStandardLevelResolver standardResolver(context->LG->GetMakefile());
+ for (std::string const& p : parameters) {
+ std::string error;
+ std::string lang;
+ if (!standardResolver.CompileFeatureKnown(
+ context->HeadTarget->Target->GetName(), p, lang, &error)) {
+ reportError(context, content->GetOriginalExpression(), error);
+ return std::string();
+ }
+ testedFeatures[lang].push_back(p);
+
+ if (availableFeatures.find(lang) == availableFeatures.end()) {
+ const char* featuresKnown =
+ standardResolver.CompileFeaturesAvailable(lang, &error);
+ if (!featuresKnown) {
+ reportError(context, content->GetOriginalExpression(), error);
+ return std::string();
+ }
+ cmExpandList(featuresKnown, availableFeatures[lang]);
+ }
+ }
+
+ bool evalLL = dagChecker && dagChecker->EvaluatingLinkLibraries();
+
+ for (auto const& lit : testedFeatures) {
+ std::vector<std::string> const& langAvailable =
+ availableFeatures[lit.first];
+ cmProp standardDefault = context->LG->GetMakefile()->GetDefinition(
+ "CMAKE_" + lit.first + "_STANDARD_DEFAULT");
+ for (std::string const& it : lit.second) {
+ if (!cm::contains(langAvailable, it)) {
+ return "0";
+ }
+ if (standardDefault && standardDefault->empty()) {
+ // This compiler has no notion of language standard levels.
+ // All features known for the language are always available.
+ continue;
+ }
+ if (!standardResolver.HaveStandardAvailable(target, lit.first,
+ context->Config, it)) {
+ if (evalLL) {
+ cmProp l = target->GetLanguageStandard(lit.first, context->Config);
+ if (!l) {
+ l = standardDefault;
+ }
+ assert(l);
+ context->MaxLanguageStandard[target][lit.first] = *l;
+ } else {
+ return "0";
+ }
+ }
+ }
+ }
+ return "1";
+ }
+} compileFeaturesNode;
+
+static const char* targetPolicyWhitelist[] = {
+ nullptr
+#define TARGET_POLICY_STRING(POLICY) , #POLICY
+
+ CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_STRING)
+
+#undef TARGET_POLICY_STRING
+};
+
+cmPolicies::PolicyStatus statusForTarget(cmGeneratorTarget const* tgt,
+ const char* policy)
+{
+#define RETURN_POLICY(POLICY) \
+ if (strcmp(policy, #POLICY) == 0) { \
+ return tgt->GetPolicyStatus##POLICY(); \
+ }
+
+ CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY)
+
+#undef RETURN_POLICY
+
+ assert(false && "Unreachable code. Not a valid policy");
+ return cmPolicies::WARN;
+}
+
+cmPolicies::PolicyID policyForString(const char* policy_id)
+{
+#define RETURN_POLICY_ID(POLICY_ID) \
+ if (strcmp(policy_id, #POLICY_ID) == 0) { \
+ return cmPolicies::POLICY_ID; \
+ }
+
+ CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY_ID)
+
+#undef RETURN_POLICY_ID
+
+ assert(false && "Unreachable code. Not a valid policy");
+ return cmPolicies::CMP0002;
+}
+
+static const struct TargetPolicyNode : public cmGeneratorExpressionNode
+{
+ TargetPolicyNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ if (!context->HeadTarget) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<TARGET_POLICY:prop> may only be used with binary targets. It "
+ "may not be used with add_custom_command or add_custom_target.");
+ return std::string();
+ }
+
+ context->HadContextSensitiveCondition = true;
+ context->HadHeadSensitiveCondition = true;
+
+ for (size_t i = 1; i < cm::size(targetPolicyWhitelist); ++i) {
+ const char* policy = targetPolicyWhitelist[i];
+ if (parameters.front() == policy) {
+ cmLocalGenerator* lg = context->HeadTarget->GetLocalGenerator();
+ switch (statusForTarget(context->HeadTarget, policy)) {
+ case cmPolicies::WARN:
+ lg->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(policyForString(policy)));
+ CM_FALLTHROUGH;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::OLD:
+ return "0";
+ case cmPolicies::NEW:
+ return "1";
+ }
+ }
+ }
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<TARGET_POLICY:prop> may only be used with a limited number of "
+ "policies. Currently it may be used with the following policies:\n"
+
+#define STRINGIFY_HELPER(X) #X
+#define STRINGIFY(X) STRINGIFY_HELPER(X)
+
+#define TARGET_POLICY_LIST_ITEM(POLICY) " * " STRINGIFY(POLICY) "\n"
+
+ CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_LIST_ITEM)
+
+#undef TARGET_POLICY_LIST_ITEM
+ );
+ return std::string();
+ }
+
+} targetPolicyNode;
+
+static const struct InstallPrefixNode : public cmGeneratorExpressionNode
+{
+ InstallPrefixNode() {} // NOLINT(modernize-use-equals-default)
+
+ bool GeneratesContent() const override { return true; }
+ int NumExpectedParameters() const override { return 0; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& /*parameters*/,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ reportError(context, content->GetOriginalExpression(),
+ "INSTALL_PREFIX is a marker for install(EXPORT) only. It "
+ "should never be evaluated.");
+ return std::string();
+ }
+
+} installPrefixNode;
+
+class ArtifactDirTag;
+class ArtifactLinkerTag;
+class ArtifactNameTag;
+class ArtifactPathTag;
+class ArtifactPdbTag;
+class ArtifactSonameTag;
+class ArtifactBundleDirTag;
+class ArtifactBundleContentDirTag;
+
+template <typename ArtifactT, typename ComponentT>
+struct TargetFilesystemArtifactDependency
+{
+ static void AddDependency(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context)
+ {
+ context->DependTargets.insert(target);
+ context->AllTargets.insert(target);
+ }
+};
+
+struct TargetFilesystemArtifactDependencyCMP0112
+{
+ static void AddDependency(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context)
+ {
+ context->AllTargets.insert(target);
+ cmLocalGenerator* lg = context->LG;
+ switch (target->GetPolicyStatusCMP0112()) {
+ case cmPolicies::WARN:
+ if (lg->GetMakefile()->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0112")) {
+ std::string err =
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0112),
+ "\nDependency being added to target:\n \"",
+ target->GetName(), "\"\n");
+ lg->GetCMakeInstance()->IssueMessage(MessageType ::AUTHOR_WARNING,
+ err, context->Backtrace);
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ context->DependTargets.insert(target);
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ break;
+ }
+ }
+};
+
+template <typename ArtifactT>
+struct TargetFilesystemArtifactDependency<ArtifactT, ArtifactNameTag>
+ : TargetFilesystemArtifactDependencyCMP0112
+{
+};
+template <typename ArtifactT>
+struct TargetFilesystemArtifactDependency<ArtifactT, ArtifactDirTag>
+ : TargetFilesystemArtifactDependencyCMP0112
+{
+};
+template <>
+struct TargetFilesystemArtifactDependency<ArtifactBundleDirTag,
+ ArtifactPathTag>
+ : TargetFilesystemArtifactDependencyCMP0112
+{
+};
+template <>
+struct TargetFilesystemArtifactDependency<ArtifactBundleContentDirTag,
+ ArtifactPathTag>
+ : TargetFilesystemArtifactDependencyCMP0112
+{
+};
+
+template <typename ArtifactT>
+struct TargetFilesystemArtifactResultCreator
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content);
+};
+
+template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactSonameTag>
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ // The target soname file (.so.1).
+ if (target->IsDLLPlatform()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_SONAME_FILE is not allowed "
+ "for DLL target platforms.");
+ return std::string();
+ }
+ if (target->GetType() != cmStateEnums::SHARED_LIBRARY) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_SONAME_FILE is allowed only for "
+ "SHARED libraries.");
+ return std::string();
+ }
+ std::string result = cmStrCat(target->GetDirectory(context->Config), '/',
+ target->GetSOName(context->Config));
+ return result;
+ }
+};
+
+template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag>
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (target->IsImported()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE not allowed for IMPORTED targets.");
+ return std::string();
+ }
+
+ std::string language = target->GetLinkerLanguage(context->Config);
+
+ std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB";
+
+ if (!context->LG->GetMakefile()->IsOn(pdbSupportVar)) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE is not supported by the target linker.");
+ return std::string();
+ }
+
+ cmStateEnums::TargetType targetType = target->GetType();
+
+ if (targetType != cmStateEnums::SHARED_LIBRARY &&
+ targetType != cmStateEnums::MODULE_LIBRARY &&
+ targetType != cmStateEnums::EXECUTABLE) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE is allowed only for "
+ "targets with linker created artifacts.");
+ return std::string();
+ }
+
+ std::string result = cmStrCat(target->GetPDBDirectory(context->Config),
+ '/', target->GetPDBName(context->Config));
+ return result;
+ }
+};
+
+template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag>
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ // The file used to link to the target (.so, .lib, .a).
+ if (!target->IsLinkable()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_LINKER_FILE is allowed only for libraries and "
+ "executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+ cmStateEnums::ArtifactType artifact =
+ target->HasImportLibrary(context->Config)
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+ return target->GetFullPath(context->Config, artifact);
+ }
+};
+
+template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirTag>
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (target->IsImported()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_BUNDLE_DIR not allowed for IMPORTED targets.");
+ return std::string();
+ }
+ if (!target->IsBundleOnApple()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_BUNDLE_DIR is allowed only for Bundle targets.");
+ return std::string();
+ }
+
+ std::string outpath = target->GetDirectory(context->Config) + '/';
+ return target->BuildBundleDirectory(outpath, context->Config,
+ cmGeneratorTarget::BundleDirLevel);
+ }
+};
+
+template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactBundleContentDirTag>
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (target->IsImported()) {
+ ::reportError(
+ context, content->GetOriginalExpression(),
+ "TARGET_BUNDLE_CONTENT_DIR not allowed for IMPORTED targets.");
+ return std::string();
+ }
+ if (!target->IsBundleOnApple()) {
+ ::reportError(
+ context, content->GetOriginalExpression(),
+ "TARGET_BUNDLE_CONTENT_DIR is allowed only for Bundle targets.");
+ return std::string();
+ }
+
+ std::string outpath = target->GetDirectory(context->Config) + '/';
+ return target->BuildBundleDirectory(outpath, context->Config,
+ cmGeneratorTarget::ContentLevel);
+ }
+};
+
+template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactNameTag>
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* /*unused*/)
+ {
+ return target->GetFullPath(context->Config,
+ cmStateEnums::RuntimeBinaryArtifact, true);
+ }
+};
+
+template <typename ArtifactT>
+struct TargetFilesystemArtifactResultGetter
+{
+ static std::string Get(const std::string& result);
+};
+
+template <>
+struct TargetFilesystemArtifactResultGetter<ArtifactNameTag>
+{
+ static std::string Get(const std::string& result)
+ {
+ return cmSystemTools::GetFilenameName(result);
+ }
+};
+
+template <>
+struct TargetFilesystemArtifactResultGetter<ArtifactDirTag>
+{
+ static std::string Get(const std::string& result)
+ {
+ return cmSystemTools::GetFilenamePath(result);
+ }
+};
+
+template <>
+struct TargetFilesystemArtifactResultGetter<ArtifactPathTag>
+{
+ static std::string Get(const std::string& result) { return result; }
+};
+
+struct TargetArtifactBase : public cmGeneratorExpressionNode
+{
+ TargetArtifactBase() {} // NOLINT(modernize-use-equals-default)
+
+protected:
+ cmGeneratorTarget* GetTarget(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const
+ {
+ // Lookup the referenced target.
+ std::string name = parameters.front();
+
+ if (!cmGeneratorExpression::IsValidTargetName(name)) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "Expression syntax not recognized.");
+ return nullptr;
+ }
+ cmGeneratorTarget* target = context->LG->FindGeneratorTargetToUse(name);
+ if (!target) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "No target \"" + name + "\"");
+ return nullptr;
+ }
+ if (target->GetType() >= cmStateEnums::OBJECT_LIBRARY &&
+ target->GetType() != cmStateEnums::UNKNOWN_LIBRARY) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "Target \"" + name +
+ "\" is not an executable or library.");
+ return nullptr;
+ }
+ if (dagChecker &&
+ (dagChecker->EvaluatingLinkLibraries(target) ||
+ (dagChecker->EvaluatingSources() &&
+ target == dagChecker->TopTarget()))) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "Expressions which require the linker language may not "
+ "be used while evaluating link libraries");
+ return nullptr;
+ }
+
+ return target;
+ }
+};
+
+template <typename ArtifactT, typename ComponentT>
+struct TargetFilesystemArtifact : public TargetArtifactBase
+{
+ TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ cmGeneratorTarget* target =
+ this->GetTarget(parameters, context, content, dagChecker);
+ if (!target) {
+ return std::string();
+ }
+ // Not a dependent target if we are querying for ArtifactDirTag,
+ // ArtifactNameTag, ArtifactBundleDirTag, and ArtifactBundleContentDirTag
+ TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
+ target, context);
+
+ std::string result =
+ TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, context,
+ content);
+ if (context->HadError) {
+ return std::string();
+ }
+ return TargetFilesystemArtifactResultGetter<ComponentT>::Get(result);
+ }
+};
+
+template <typename ArtifactT>
+struct TargetFilesystemArtifactNodeGroup
+{
+ TargetFilesystemArtifactNodeGroup() // NOLINT(modernize-use-equals-default)
+ {
+ }
+
+ TargetFilesystemArtifact<ArtifactT, ArtifactPathTag> File;
+ TargetFilesystemArtifact<ArtifactT, ArtifactNameTag> FileName;
+ TargetFilesystemArtifact<ArtifactT, ArtifactDirTag> FileDir;
+};
+
+static const TargetFilesystemArtifactNodeGroup<ArtifactNameTag>
+ targetNodeGroup;
+
+static const TargetFilesystemArtifactNodeGroup<ArtifactLinkerTag>
+ targetLinkerNodeGroup;
+
+static const TargetFilesystemArtifactNodeGroup<ArtifactSonameTag>
+ targetSoNameNodeGroup;
+
+static const TargetFilesystemArtifactNodeGroup<ArtifactPdbTag>
+ targetPdbNodeGroup;
+
+static const TargetFilesystemArtifact<ArtifactBundleDirTag, ArtifactPathTag>
+ targetBundleDirNode;
+
+static const TargetFilesystemArtifact<ArtifactBundleContentDirTag,
+ ArtifactPathTag>
+ targetBundleContentDirNode;
+
+//
+// To retrieve base name for various artifacts
+//
+template <typename ArtifactT>
+struct TargetOutputNameArtifactResultGetter
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content);
+};
+
+template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactNameTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* /*unused*/)
+ {
+ return target->GetOutputName(context->Config,
+ cmStateEnums::RuntimeBinaryArtifact) +
+ target->GetFilePostfix(context->Config);
+ }
+};
+
+template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ // The file used to link to the target (.so, .lib, .a).
+ if (!target->IsLinkable()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_LINKER_FILE_BASE_NAME is allowed only for "
+ "libraries and executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+ cmStateEnums::ArtifactType artifact =
+ target->HasImportLibrary(context->Config)
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+ return target->GetOutputName(context->Config, artifact) +
+ target->GetFilePostfix(context->Config);
+ }
+};
+
+template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactPdbTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (target->IsImported()) {
+ ::reportError(
+ context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE_BASE_NAME not allowed for IMPORTED targets.");
+ return std::string();
+ }
+
+ std::string language = target->GetLinkerLanguage(context->Config);
+
+ std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB";
+
+ if (!context->LG->GetMakefile()->IsOn(pdbSupportVar)) {
+ ::reportError(
+ context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE_BASE_NAME is not supported by the target linker.");
+ return std::string();
+ }
+
+ cmStateEnums::TargetType targetType = target->GetType();
+
+ if (targetType != cmStateEnums::SHARED_LIBRARY &&
+ targetType != cmStateEnums::MODULE_LIBRARY &&
+ targetType != cmStateEnums::EXECUTABLE) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE_BASE_NAME is allowed only for "
+ "targets with linker created artifacts.");
+ return std::string();
+ }
+
+ return target->GetPDBOutputName(context->Config) +
+ target->GetFilePostfix(context->Config);
+ }
+};
+
+template <typename ArtifactT>
+struct TargetFileBaseNameArtifact : public TargetArtifactBase
+{
+ TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ cmGeneratorTarget* target =
+ this->GetTarget(parameters, context, content, dagChecker);
+ if (!target) {
+ return std::string();
+ }
+
+ std::string result = TargetOutputNameArtifactResultGetter<ArtifactT>::Get(
+ target, context, content);
+ if (context->HadError) {
+ return std::string();
+ }
+ return result;
+ }
+};
+
+static const TargetFileBaseNameArtifact<ArtifactNameTag>
+ targetFileBaseNameNode;
+static const TargetFileBaseNameArtifact<ArtifactLinkerTag>
+ targetLinkerFileBaseNameNode;
+static const TargetFileBaseNameArtifact<ArtifactPdbTag>
+ targetPdbFileBaseNameNode;
+
+class ArtifactFilePrefixTag;
+class ArtifactLinkerFilePrefixTag;
+class ArtifactFileSuffixTag;
+class ArtifactLinkerFileSuffixTag;
+
+template <typename ArtifactT>
+struct TargetFileArtifactResultGetter
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content);
+};
+
+template <>
+struct TargetFileArtifactResultGetter<ArtifactFilePrefixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent*)
+ {
+ return target->GetFilePrefix(context->Config);
+ }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (!target->IsLinkable()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_LINKER_PREFIX is allowed only for libraries and "
+ "executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+
+ cmStateEnums::ArtifactType artifact =
+ target->HasImportLibrary(context->Config)
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+
+ return target->GetFilePrefix(context->Config, artifact);
+ }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent*)
+ {
+ return target->GetFileSuffix(context->Config);
+ }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (!target->IsLinkable()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_LINKER_SUFFIX is allowed only for libraries and "
+ "executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+
+ cmStateEnums::ArtifactType artifact =
+ target->HasImportLibrary(context->Config)
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+
+ return target->GetFileSuffix(context->Config, artifact);
+ }
+};
+
+template <typename ArtifactT>
+struct TargetFileArtifact : public TargetArtifactBase
+{
+ TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ cmGeneratorTarget* target =
+ this->GetTarget(parameters, context, content, dagChecker);
+ if (!target) {
+ return std::string();
+ }
+
+ std::string result =
+ TargetFileArtifactResultGetter<ArtifactT>::Get(target, context, content);
+ if (context->HadError) {
+ return std::string();
+ }
+ return result;
+ }
+};
+
+static const TargetFileArtifact<ArtifactFilePrefixTag> targetFilePrefixNode;
+static const TargetFileArtifact<ArtifactLinkerFilePrefixTag>
+ targetLinkerFilePrefixNode;
+static const TargetFileArtifact<ArtifactFileSuffixTag> targetFileSuffixNode;
+static const TargetFileArtifact<ArtifactLinkerFileSuffixTag>
+ targetLinkerFileSuffixNode;
+
+static const struct ShellPathNode : public cmGeneratorExpressionNode
+{
+ ShellPathNode() {} // NOLINT(modernize-use-equals-default)
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ std::vector<std::string> listIn = cmExpandedList(parameters.front());
+ if (listIn.empty()) {
+ reportError(context, content->GetOriginalExpression(),
+ "\"\" is not an absolute path.");
+ return std::string();
+ }
+ cmStateSnapshot snapshot = context->LG->GetStateSnapshot();
+ cmOutputConverter converter(snapshot);
+ const char* separator = snapshot.GetState()->UseWindowsShell() ? ";" : ":";
+ std::vector<std::string> listOut;
+ listOut.reserve(listIn.size());
+ for (auto const& in : listIn) {
+ if (!cmSystemTools::FileIsFullPath(in)) {
+ reportError(context, content->GetOriginalExpression(),
+ "\"" + in + "\" is not an absolute path.");
+ return std::string();
+ }
+ listOut.emplace_back(converter.ConvertDirectorySeparatorsForShell(in));
+ }
+ return cmJoin(listOut, separator);
+ }
+} shellPathNode;
+
+const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode(
+ const std::string& identifier)
+{
+ static std::map<std::string, cmGeneratorExpressionNode const*> const nodeMap{
+ { "0", &zeroNode },
+ { "1", &oneNode },
+ { "AND", &andNode },
+ { "OR", &orNode },
+ { "NOT", &notNode },
+ { "C_COMPILER_ID", &cCompilerIdNode },
+ { "CXX_COMPILER_ID", &cxxCompilerIdNode },
+ { "OBJC_COMPILER_ID", &objcCompilerIdNode },
+ { "OBJCXX_COMPILER_ID", &objcxxCompilerIdNode },
+ { "CUDA_COMPILER_ID", &cudaCompilerIdNode },
+ { "Fortran_COMPILER_ID", &fortranCompilerIdNode },
+ { "VERSION_GREATER", &versionGreaterNode },
+ { "VERSION_GREATER_EQUAL", &versionGreaterEqNode },
+ { "VERSION_LESS", &versionLessNode },
+ { "VERSION_LESS_EQUAL", &versionLessEqNode },
+ { "VERSION_EQUAL", &versionEqualNode },
+ { "C_COMPILER_VERSION", &cCompilerVersionNode },
+ { "CXX_COMPILER_VERSION", &cxxCompilerVersionNode },
+ { "CUDA_COMPILER_VERSION", &cudaCompilerVersionNode },
+ { "OBJC_COMPILER_VERSION", &objcCompilerVersionNode },
+ { "OBJCXX_COMPILER_VERSION", &objcxxCompilerVersionNode },
+ { "Fortran_COMPILER_VERSION", &fortranCompilerVersionNode },
+ { "PLATFORM_ID", &platformIdNode },
+ { "COMPILE_FEATURES", &compileFeaturesNode },
+ { "CONFIGURATION", &configurationNode },
+ { "CONFIG", &configurationTestNode },
+ { "TARGET_FILE", &targetNodeGroup.File },
+ { "TARGET_LINKER_FILE", &targetLinkerNodeGroup.File },
+ { "TARGET_SONAME_FILE", &targetSoNameNodeGroup.File },
+ { "TARGET_PDB_FILE", &targetPdbNodeGroup.File },
+ { "TARGET_FILE_BASE_NAME", &targetFileBaseNameNode },
+ { "TARGET_LINKER_FILE_BASE_NAME", &targetLinkerFileBaseNameNode },
+ { "TARGET_PDB_FILE_BASE_NAME", &targetPdbFileBaseNameNode },
+ { "TARGET_FILE_PREFIX", &targetFilePrefixNode },
+ { "TARGET_LINKER_FILE_PREFIX", &targetLinkerFilePrefixNode },
+ { "TARGET_FILE_SUFFIX", &targetFileSuffixNode },
+ { "TARGET_LINKER_FILE_SUFFIX", &targetLinkerFileSuffixNode },
+ { "TARGET_FILE_NAME", &targetNodeGroup.FileName },
+ { "TARGET_LINKER_FILE_NAME", &targetLinkerNodeGroup.FileName },
+ { "TARGET_SONAME_FILE_NAME", &targetSoNameNodeGroup.FileName },
+ { "TARGET_PDB_FILE_NAME", &targetPdbNodeGroup.FileName },
+ { "TARGET_FILE_DIR", &targetNodeGroup.FileDir },
+ { "TARGET_LINKER_FILE_DIR", &targetLinkerNodeGroup.FileDir },
+ { "TARGET_SONAME_FILE_DIR", &targetSoNameNodeGroup.FileDir },
+ { "TARGET_PDB_FILE_DIR", &targetPdbNodeGroup.FileDir },
+ { "TARGET_BUNDLE_DIR", &targetBundleDirNode },
+ { "TARGET_BUNDLE_CONTENT_DIR", &targetBundleContentDirNode },
+ { "STREQUAL", &strEqualNode },
+ { "EQUAL", &equalNode },
+ { "IN_LIST", &inListNode },
+ { "FILTER", &filterNode },
+ { "REMOVE_DUPLICATES", &removeDuplicatesNode },
+ { "LOWER_CASE", &lowerCaseNode },
+ { "UPPER_CASE", &upperCaseNode },
+ { "MAKE_C_IDENTIFIER", &makeCIdentifierNode },
+ { "BOOL", &boolNode },
+ { "IF", &ifNode },
+ { "ANGLE-R", &angle_rNode },
+ { "COMMA", &commaNode },
+ { "SEMICOLON", &semicolonNode },
+ { "TARGET_PROPERTY", &targetPropertyNode },
+ { "TARGET_NAME", &targetNameNode },
+ { "TARGET_OBJECTS", &targetObjectsNode },
+ { "TARGET_POLICY", &targetPolicyNode },
+ { "TARGET_EXISTS", &targetExistsNode },
+ { "TARGET_NAME_IF_EXISTS", &targetNameIfExistsNode },
+ { "TARGET_GENEX_EVAL", &targetGenexEvalNode },
+ { "TARGET_RUNTIME_DLLS", &targetRuntimeDllsNode },
+ { "GENEX_EVAL", &genexEvalNode },
+ { "BUILD_INTERFACE", &buildInterfaceNode },
+ { "INSTALL_INTERFACE", &installInterfaceNode },
+ { "INSTALL_PREFIX", &installPrefixNode },
+ { "JOIN", &joinNode },
+ { "LINK_ONLY", &linkOnlyNode },
+ { "COMPILE_LANG_AND_ID", &languageAndIdNode },
+ { "COMPILE_LANGUAGE", &languageNode },
+ { "LINK_LANG_AND_ID", &linkLanguageAndIdNode },
+ { "LINK_LANGUAGE", &linkLanguageNode },
+ { "HOST_LINK", &hostLinkNode },
+ { "DEVICE_LINK", &deviceLinkNode },
+ { "SHELL_PATH", &shellPathNode }
+ };
+
+ {
+ auto itr = nodeMap.find(identifier);
+ if (itr != nodeMap.end()) {
+ return itr->second;
+ }
+ }
+ return nullptr;
+}
+
+void reportError(cmGeneratorExpressionContext* context,
+ const std::string& expr, const std::string& result)
+{
+ context->HadError = true;
+ if (context->Quiet) {
+ return;
+ }
+
+ std::ostringstream e;
+ /* clang-format off */
+ e << "Error evaluating generator expression:\n"
+ << " " << expr << "\n"
+ << result;
+ /* clang-format on */
+ context->LG->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+ e.str(), context->Backtrace);
+}
diff --git a/Source/cmGeneratorExpressionNode.h b/Source/cmGeneratorExpressionNode.h
new file mode 100644
index 0000000..f068b02
--- /dev/null
+++ b/Source/cmGeneratorExpressionNode.h
@@ -0,0 +1,53 @@
+/* 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 <string>
+#include <vector>
+
+class cmGeneratorTarget;
+class cmLocalGenerator;
+struct GeneratorExpressionContent;
+struct cmGeneratorExpressionContext;
+struct cmGeneratorExpressionDAGChecker;
+
+struct cmGeneratorExpressionNode
+{
+ enum
+ {
+ DynamicParameters = 0,
+ OneOrMoreParameters = -1,
+ TwoOrMoreParameters = -2,
+ ZeroOrMoreParameters = -3,
+ OneOrZeroParameters = -4
+ };
+ virtual ~cmGeneratorExpressionNode() = default;
+
+ virtual bool GeneratesContent() const { return true; }
+
+ virtual bool RequiresLiteralInput() const { return false; }
+
+ virtual bool AcceptsArbitraryContentParameter() const { return false; }
+
+ virtual int NumExpectedParameters() const { return 1; }
+
+ virtual std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const = 0;
+
+ static std::string EvaluateDependentExpression(
+ std::string const& prop, cmLocalGenerator* lg,
+ cmGeneratorExpressionContext* context, const cmGeneratorTarget* headTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ const cmGeneratorTarget* currentTarget);
+
+ static const cmGeneratorExpressionNode* GetNode(
+ const std::string& identifier);
+};
+
+void reportError(cmGeneratorExpressionContext* context,
+ const std::string& expr, const std::string& result);
diff --git a/Source/cmGeneratorExpressionParser.cxx b/Source/cmGeneratorExpressionParser.cxx
new file mode 100644
index 0000000..794c1a1
--- /dev/null
+++ b/Source/cmGeneratorExpressionParser.cxx
@@ -0,0 +1,249 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGeneratorExpressionParser.h"
+
+#include <cassert>
+#include <cstddef>
+#include <utility>
+
+#include <cm/memory>
+#include <cmext/algorithm>
+#include <cmext/memory>
+
+#include "cmGeneratorExpressionEvaluator.h"
+
+cmGeneratorExpressionParser::cmGeneratorExpressionParser(
+ std::vector<cmGeneratorExpressionToken> tokens)
+ : Tokens(std::move(tokens))
+ , NestingLevel(0)
+{
+}
+
+void cmGeneratorExpressionParser::Parse(
+ cmGeneratorExpressionEvaluatorVector& result)
+{
+ this->it = this->Tokens.begin();
+
+ while (this->it != this->Tokens.end()) {
+ this->ParseContent(result);
+ }
+}
+
+static void extendText(
+ cmGeneratorExpressionEvaluatorVector& result,
+ std::vector<cmGeneratorExpressionToken>::const_iterator it)
+{
+ if (!result.empty() &&
+ (*(result.end() - 1))->GetType() ==
+ cmGeneratorExpressionEvaluator::Text) {
+ cm::static_reference_cast<TextContent>(*(result.end() - 1))
+ .Extend(it->Length);
+ } else {
+ auto textContent = cm::make_unique<TextContent>(it->Content, it->Length);
+ result.push_back(std::move(textContent));
+ }
+}
+
+static void extendResult(
+ cmGeneratorExpressionParser::cmGeneratorExpressionEvaluatorVector& result,
+ cmGeneratorExpressionParser::cmGeneratorExpressionEvaluatorVector&& contents)
+{
+ if (!result.empty() &&
+ (*(result.end() - 1))->GetType() ==
+ cmGeneratorExpressionEvaluator::Text &&
+ contents.front()->GetType() == cmGeneratorExpressionEvaluator::Text) {
+ cm::static_reference_cast<TextContent>(*(result.end() - 1))
+ .Extend(
+ cm::static_reference_cast<TextContent>(contents.front()).GetLength());
+ contents.erase(contents.begin());
+ }
+ cm::append(result, std::move(contents));
+}
+
+void cmGeneratorExpressionParser::ParseGeneratorExpression(
+ cmGeneratorExpressionEvaluatorVector& result)
+{
+ assert(this->it != this->Tokens.end());
+ unsigned int nestedLevel = this->NestingLevel;
+ ++this->NestingLevel;
+
+ auto startToken = this->it - 1;
+
+ cmGeneratorExpressionEvaluatorVector identifier;
+ while (this->it->TokenType != cmGeneratorExpressionToken::EndExpression &&
+ this->it->TokenType != cmGeneratorExpressionToken::ColonSeparator) {
+ if (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
+ extendText(identifier, this->it);
+ ++this->it;
+ } else {
+ this->ParseContent(identifier);
+ }
+ if (this->it == this->Tokens.end()) {
+ break;
+ }
+ }
+ if (identifier.empty()) {
+ // ERROR
+ }
+
+ if (this->it != this->Tokens.end() &&
+ this->it->TokenType == cmGeneratorExpressionToken::EndExpression) {
+ auto content = cm::make_unique<GeneratorExpressionContent>(
+ startToken->Content,
+ this->it->Content - startToken->Content + this->it->Length);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ --this->NestingLevel;
+ content->SetIdentifier(std::move(identifier));
+ result.push_back(std::move(content));
+ return;
+ }
+
+ std::vector<cmGeneratorExpressionEvaluatorVector> parameters;
+ std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator>
+ commaTokens;
+ std::vector<cmGeneratorExpressionToken>::const_iterator colonToken;
+
+ bool emptyParamTermination = false;
+
+ if (this->it != this->Tokens.end() &&
+ this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) {
+ colonToken = this->it;
+ parameters.resize(parameters.size() + 1);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ if (this->it == this->Tokens.end()) {
+ emptyParamTermination = true;
+ }
+
+ while (this->it != this->Tokens.end() &&
+ this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
+ commaTokens.push_back(this->it);
+ parameters.resize(parameters.size() + 1);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ if (this->it == this->Tokens.end()) {
+ emptyParamTermination = true;
+ }
+ }
+ while (this->it != this->Tokens.end() &&
+ this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) {
+ extendText(*(parameters.end() - 1), this->it);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ }
+ while (this->it != this->Tokens.end() &&
+ this->it->TokenType != cmGeneratorExpressionToken::EndExpression) {
+ this->ParseContent(*(parameters.end() - 1));
+ if (this->it == this->Tokens.end()) {
+ break;
+ }
+ while (this->it != this->Tokens.end() &&
+ this->it->TokenType ==
+ cmGeneratorExpressionToken::CommaSeparator) {
+ commaTokens.push_back(this->it);
+ parameters.resize(parameters.size() + 1);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ if (this->it == this->Tokens.end()) {
+ emptyParamTermination = true;
+ }
+ }
+ while (this->it != this->Tokens.end() &&
+ this->it->TokenType ==
+ cmGeneratorExpressionToken::ColonSeparator) {
+ extendText(*(parameters.end() - 1), this->it);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ }
+ }
+ if (this->it != this->Tokens.end() &&
+ this->it->TokenType == cmGeneratorExpressionToken::EndExpression) {
+ --this->NestingLevel;
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ }
+ }
+
+ if (nestedLevel != this->NestingLevel) {
+ // There was a '$<' in the text, but no corresponding '>'. Rebuild to
+ // treat the '$<' as having been plain text, along with the
+ // corresponding : and , tokens that might have been found.
+ extendText(result, startToken);
+ extendResult(result, std::move(identifier));
+ if (!parameters.empty()) {
+ extendText(result, colonToken);
+
+ auto pit = parameters.begin();
+ const auto pend = parameters.end();
+ auto commaIt = commaTokens.begin();
+ assert(parameters.size() > commaTokens.size());
+ for (; pit != pend; ++pit, ++commaIt) {
+ if (!pit->empty() && !emptyParamTermination) {
+ extendResult(result, std::move(*pit));
+ }
+ if (commaIt != commaTokens.end()) {
+ extendText(result, *commaIt);
+ } else {
+ break;
+ }
+ }
+ }
+ return;
+ }
+
+ size_t contentLength =
+ ((this->it - 1)->Content - startToken->Content) + (this->it - 1)->Length;
+ auto content = cm::make_unique<GeneratorExpressionContent>(
+ startToken->Content, contentLength);
+ content->SetIdentifier(std::move(identifier));
+ content->SetParameters(std::move(parameters));
+ result.push_back(std::move(content));
+}
+
+void cmGeneratorExpressionParser::ParseContent(
+ cmGeneratorExpressionEvaluatorVector& result)
+{
+ assert(this->it != this->Tokens.end());
+ switch (this->it->TokenType) {
+ case cmGeneratorExpressionToken::Text: {
+ if (this->NestingLevel == 0) {
+ if (!result.empty() &&
+ (*(result.end() - 1))->GetType() ==
+ cmGeneratorExpressionEvaluator::Text) {
+ // A comma in 'plain text' could have split text that should
+ // otherwise be continuous. Extend the last text content instead of
+ // creating a new one.
+ cm::static_reference_cast<TextContent>(*(result.end() - 1))
+ .Extend(this->it->Length);
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ return;
+ }
+ }
+ auto n =
+ cm::make_unique<TextContent>(this->it->Content, this->it->Length);
+ result.push_back(std::move(n));
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ return;
+ }
+ case cmGeneratorExpressionToken::BeginExpression:
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ this->ParseGeneratorExpression(result);
+ return;
+ case cmGeneratorExpressionToken::EndExpression:
+ case cmGeneratorExpressionToken::ColonSeparator:
+ case cmGeneratorExpressionToken::CommaSeparator:
+ if (this->NestingLevel == 0) {
+ extendText(result, this->it);
+ } else {
+ assert(false && "Got unexpected syntax token.");
+ }
+ assert(this->it != this->Tokens.end());
+ ++this->it;
+ return;
+ }
+ assert(false && "Unhandled token in generator expression.");
+}
diff --git a/Source/cmGeneratorExpressionParser.h b/Source/cmGeneratorExpressionParser.h
new file mode 100644
index 0000000..efaef3e
--- /dev/null
+++ b/Source/cmGeneratorExpressionParser.h
@@ -0,0 +1,30 @@
+/* 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 <memory>
+#include <vector>
+
+#include "cmGeneratorExpressionLexer.h"
+
+struct cmGeneratorExpressionEvaluator;
+
+struct cmGeneratorExpressionParser
+{
+ cmGeneratorExpressionParser(std::vector<cmGeneratorExpressionToken> tokens);
+
+ using cmGeneratorExpressionEvaluatorVector =
+ std::vector<std::unique_ptr<cmGeneratorExpressionEvaluator>>;
+
+ void Parse(cmGeneratorExpressionEvaluatorVector& result);
+
+private:
+ void ParseContent(cmGeneratorExpressionEvaluatorVector&);
+ void ParseGeneratorExpression(cmGeneratorExpressionEvaluatorVector&);
+
+ std::vector<cmGeneratorExpressionToken>::const_iterator it;
+ const std::vector<cmGeneratorExpressionToken> Tokens;
+ unsigned int NestingLevel;
+};
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
new file mode 100644
index 0000000..365f8b8
--- /dev/null
+++ b/Source/cmGeneratorTarget.cxx
@@ -0,0 +1,7719 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGeneratorTarget.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cerrno>
+#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iterator>
+#include <queue>
+#include <sstream>
+#include <unordered_set>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmAlgorithms.h"
+#include "cmComputeLinkInformation.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmFileTimes.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionContext.h"
+#include "cmGeneratorExpressionDAGChecker.h"
+#include "cmGeneratorExpressionNode.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmPropertyMap.h"
+#include "cmRange.h"
+#include "cmSourceFile.h"
+#include "cmSourceFileLocation.h"
+#include "cmSourceFileLocationKind.h"
+#include "cmStandardLevelResolver.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetLinkLibraryType.h"
+#include "cmTargetPropertyComputer.h"
+#include "cmake.h"
+
+class cmMessenger;
+
+template <>
+cmProp cmTargetPropertyComputer::GetSources<cmGeneratorTarget>(
+ cmGeneratorTarget const* tgt, cmMessenger* /* messenger */,
+ cmListFileBacktrace const& /* context */)
+{
+ return &tgt->GetSourcesProperty();
+}
+
+template <>
+const std::string&
+cmTargetPropertyComputer::ComputeLocationForBuild<cmGeneratorTarget>(
+ cmGeneratorTarget const* tgt)
+{
+ return tgt->GetLocation("");
+}
+
+template <>
+const std::string&
+cmTargetPropertyComputer::ComputeLocation<cmGeneratorTarget>(
+ cmGeneratorTarget const* tgt, const std::string& config)
+{
+ return tgt->GetLocation(config);
+}
+
+class cmGeneratorTarget::TargetPropertyEntry
+{
+protected:
+ static cmLinkImplItem NoLinkImplItem;
+
+public:
+ TargetPropertyEntry(cmLinkImplItem const& item)
+ : LinkImplItem(item)
+ {
+ }
+ virtual ~TargetPropertyEntry() = default;
+
+ virtual const std::string& Evaluate(
+ cmLocalGenerator* lg, const std::string& config,
+ cmGeneratorTarget const* headTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::string const& language) const = 0;
+
+ virtual cmListFileBacktrace GetBacktrace() const = 0;
+ virtual std::string const& GetInput() const = 0;
+ virtual bool GetHadContextSensitiveCondition() const { return false; }
+
+ cmLinkImplItem const& LinkImplItem;
+};
+cmLinkImplItem cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem;
+
+class TargetPropertyEntryGenex : public cmGeneratorTarget::TargetPropertyEntry
+{
+public:
+ TargetPropertyEntryGenex(std::unique_ptr<cmCompiledGeneratorExpression> cge,
+ cmLinkImplItem const& item = NoLinkImplItem)
+ : cmGeneratorTarget::TargetPropertyEntry(item)
+ , ge(std::move(cge))
+ {
+ }
+
+ const std::string& Evaluate(cmLocalGenerator* lg, const std::string& config,
+ cmGeneratorTarget const* headTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::string const& language) const override
+ {
+ return this->ge->Evaluate(lg, config, headTarget, dagChecker, nullptr,
+ language);
+ }
+
+ cmListFileBacktrace GetBacktrace() const override
+ {
+ return this->ge->GetBacktrace();
+ }
+
+ std::string const& GetInput() const override { return this->ge->GetInput(); }
+
+ bool GetHadContextSensitiveCondition() const override
+ {
+ return this->ge->GetHadContextSensitiveCondition();
+ }
+
+private:
+ const std::unique_ptr<cmCompiledGeneratorExpression> ge;
+};
+
+class TargetPropertyEntryString : public cmGeneratorTarget::TargetPropertyEntry
+{
+public:
+ TargetPropertyEntryString(std::string propertyValue,
+ cmListFileBacktrace backtrace,
+ cmLinkImplItem const& item = NoLinkImplItem)
+ : cmGeneratorTarget::TargetPropertyEntry(item)
+ , PropertyValue(std::move(propertyValue))
+ , Backtrace(std::move(backtrace))
+ {
+ }
+
+ const std::string& Evaluate(cmLocalGenerator*, const std::string&,
+ cmGeneratorTarget const*,
+ cmGeneratorExpressionDAGChecker*,
+ std::string const&) const override
+ {
+ return this->PropertyValue;
+ }
+
+ cmListFileBacktrace GetBacktrace() const override { return this->Backtrace; }
+ std::string const& GetInput() const override { return this->PropertyValue; }
+
+private:
+ std::string PropertyValue;
+ cmListFileBacktrace Backtrace;
+};
+
+std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>
+CreateTargetPropertyEntry(
+ const std::string& propertyValue,
+ cmListFileBacktrace backtrace = cmListFileBacktrace(),
+ bool evaluateForBuildsystem = false)
+{
+ if (cmGeneratorExpression::Find(propertyValue) != std::string::npos) {
+ cmGeneratorExpression ge(std::move(backtrace));
+ std::unique_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(propertyValue);
+ cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
+ return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>(
+ cm::make_unique<TargetPropertyEntryGenex>(std::move(cge)));
+ }
+
+ return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>(
+ cm::make_unique<TargetPropertyEntryString>(propertyValue,
+ std::move(backtrace)));
+}
+
+void CreatePropertyGeneratorExpressions(
+ cmStringRange entries, cmBacktraceRange backtraces,
+ std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>>& items,
+ bool evaluateForBuildsystem = false)
+{
+ auto btIt = backtraces.begin();
+ for (auto it = entries.begin(); it != entries.end(); ++it, ++btIt) {
+ items.push_back(
+ CreateTargetPropertyEntry(*it, *btIt, evaluateForBuildsystem));
+ }
+}
+
+namespace {
+// Represent a target property entry after evaluating generator expressions
+// and splitting up lists.
+struct EvaluatedTargetPropertyEntry
+{
+ EvaluatedTargetPropertyEntry(cmLinkImplItem const& item,
+ cmListFileBacktrace bt)
+ : LinkImplItem(item)
+ , Backtrace(std::move(bt))
+ {
+ }
+
+ // Move-only.
+ EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry&&) = default;
+ EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry const&) = delete;
+ EvaluatedTargetPropertyEntry& operator=(EvaluatedTargetPropertyEntry&&) =
+ delete;
+ EvaluatedTargetPropertyEntry& operator=(
+ EvaluatedTargetPropertyEntry const&) = delete;
+
+ cmLinkImplItem const& LinkImplItem;
+ cmListFileBacktrace Backtrace;
+ std::vector<std::string> Values;
+ bool ContextDependent = false;
+};
+
+EvaluatedTargetPropertyEntry EvaluateTargetPropertyEntry(
+ cmGeneratorTarget const* thisTarget, std::string const& config,
+ std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
+ cmGeneratorTarget::TargetPropertyEntry& entry)
+{
+ EvaluatedTargetPropertyEntry ee(entry.LinkImplItem, entry.GetBacktrace());
+ cmExpandList(entry.Evaluate(thisTarget->GetLocalGenerator(), config,
+ thisTarget, dagChecker, lang),
+ ee.Values);
+ if (entry.GetHadContextSensitiveCondition()) {
+ ee.ContextDependent = true;
+ }
+ return ee;
+}
+
+struct EvaluatedTargetPropertyEntries
+{
+ std::vector<EvaluatedTargetPropertyEntry> Entries;
+ bool HadContextSensitiveCondition = false;
+};
+
+EvaluatedTargetPropertyEntries EvaluateTargetPropertyEntries(
+ cmGeneratorTarget const* thisTarget, std::string const& config,
+ std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
+ std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>> const&
+ in)
+{
+ EvaluatedTargetPropertyEntries out;
+ out.Entries.reserve(in.size());
+ for (auto const& entry : in) {
+ out.Entries.emplace_back(EvaluateTargetPropertyEntry(
+ thisTarget, config, lang, dagChecker, *entry));
+ }
+ return out;
+}
+}
+
+cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
+ : Target(t)
+ , FortranModuleDirectoryCreated(false)
+ , SourceFileFlagsConstructed(false)
+ , PolicyWarnedCMP0022(false)
+ , PolicyReportedCMP0069(false)
+ , DebugIncludesDone(false)
+ , DebugCompileOptionsDone(false)
+ , DebugCompileFeaturesDone(false)
+ , DebugCompileDefinitionsDone(false)
+ , DebugLinkOptionsDone(false)
+ , DebugLinkDirectoriesDone(false)
+ , DebugPrecompileHeadersDone(false)
+ , DebugSourcesDone(false)
+ , UtilityItemsDone(false)
+ , SourcesAreContextDependent(Tribool::Indeterminate)
+{
+ this->Makefile = this->Target->GetMakefile();
+ this->LocalGenerator = lg;
+ this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
+
+ this->GlobalGenerator->ComputeTargetObjectDirectory(this);
+
+ CreatePropertyGeneratorExpressions(t->GetIncludeDirectoriesEntries(),
+ t->GetIncludeDirectoriesBacktraces(),
+ this->IncludeDirectoriesEntries);
+
+ CreatePropertyGeneratorExpressions(t->GetCompileOptionsEntries(),
+ t->GetCompileOptionsBacktraces(),
+ this->CompileOptionsEntries);
+
+ CreatePropertyGeneratorExpressions(t->GetCompileFeaturesEntries(),
+ t->GetCompileFeaturesBacktraces(),
+ this->CompileFeaturesEntries);
+
+ CreatePropertyGeneratorExpressions(t->GetCompileDefinitionsEntries(),
+ t->GetCompileDefinitionsBacktraces(),
+ this->CompileDefinitionsEntries);
+
+ CreatePropertyGeneratorExpressions(t->GetLinkOptionsEntries(),
+ t->GetLinkOptionsBacktraces(),
+ this->LinkOptionsEntries);
+
+ CreatePropertyGeneratorExpressions(t->GetLinkDirectoriesEntries(),
+ t->GetLinkDirectoriesBacktraces(),
+ this->LinkDirectoriesEntries);
+
+ CreatePropertyGeneratorExpressions(t->GetPrecompileHeadersEntries(),
+ t->GetPrecompileHeadersBacktraces(),
+ this->PrecompileHeadersEntries);
+
+ CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
+ t->GetSourceBacktraces(),
+ this->SourceEntries, true);
+
+ this->PolicyMap = t->GetPolicyMap();
+
+ // Get hard-coded linker language
+ if (this->Target->GetProperty("HAS_CXX")) {
+ this->LinkerLanguage = "CXX";
+ } else {
+ this->LinkerLanguage = this->Target->GetSafeProperty("LINKER_LANGUAGE");
+ }
+}
+
+cmGeneratorTarget::~cmGeneratorTarget() = default;
+
+const std::string& cmGeneratorTarget::GetSourcesProperty() const
+{
+ std::vector<std::string> values;
+ for (auto const& se : this->SourceEntries) {
+ values.push_back(se->GetInput());
+ }
+ static std::string value;
+ value.clear();
+ value = cmJoin(values, ";");
+ return value;
+}
+
+cmGlobalGenerator* cmGeneratorTarget::GetGlobalGenerator() const
+{
+ return this->GetLocalGenerator()->GetGlobalGenerator();
+}
+
+cmLocalGenerator* cmGeneratorTarget::GetLocalGenerator() const
+{
+ return this->LocalGenerator;
+}
+
+cmStateEnums::TargetType cmGeneratorTarget::GetType() const
+{
+ return this->Target->GetType();
+}
+
+const std::string& cmGeneratorTarget::GetName() const
+{
+ return this->Target->GetName();
+}
+
+std::string cmGeneratorTarget::GetExportName() const
+{
+ cmProp exportName = this->GetProperty("EXPORT_NAME");
+
+ if (cmNonempty(exportName)) {
+ if (!cmGeneratorExpression::IsValidTargetName(*exportName)) {
+ std::ostringstream e;
+ e << "EXPORT_NAME property \"" << *exportName << "\" for \""
+ << this->GetName() << "\": is not valid.";
+ cmSystemTools::Error(e.str());
+ return "";
+ }
+ return *exportName;
+ }
+ return this->GetName();
+}
+
+cmProp cmGeneratorTarget::GetProperty(const std::string& prop) const
+{
+ if (cmProp result = cmTargetPropertyComputer::GetProperty(
+ this, prop, this->Makefile->GetMessenger(), this->GetBacktrace())) {
+ return result;
+ }
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ return nullptr;
+ }
+ return this->Target->GetProperty(prop);
+}
+
+std::string const& cmGeneratorTarget::GetSafeProperty(
+ std::string const& prop) const
+{
+ cmProp ret = this->GetProperty(prop);
+ if (ret) {
+ return *ret;
+ }
+
+ static std::string const s_empty;
+ return s_empty;
+}
+
+const char* cmGeneratorTarget::GetOutputTargetType(
+ cmStateEnums::ArtifactType artifact) const
+{
+ switch (this->GetType()) {
+ case cmStateEnums::SHARED_LIBRARY:
+ if (this->IsDLLPlatform()) {
+ switch (artifact) {
+ case cmStateEnums::RuntimeBinaryArtifact:
+ // A DLL shared library is treated as a runtime target.
+ return "RUNTIME";
+ case cmStateEnums::ImportLibraryArtifact:
+ // A DLL import library is treated as an archive target.
+ return "ARCHIVE";
+ }
+ } else {
+ // For non-DLL platforms shared libraries are treated as
+ // library targets.
+ return "LIBRARY";
+ }
+ break;
+ case cmStateEnums::STATIC_LIBRARY:
+ // Static libraries are always treated as archive targets.
+ return "ARCHIVE";
+ case cmStateEnums::MODULE_LIBRARY:
+ switch (artifact) {
+ case cmStateEnums::RuntimeBinaryArtifact:
+ // Module libraries are always treated as library targets.
+ return "LIBRARY";
+ case cmStateEnums::ImportLibraryArtifact:
+ // Module import libraries are treated as archive targets.
+ return "ARCHIVE";
+ }
+ break;
+ case cmStateEnums::OBJECT_LIBRARY:
+ // Object libraries are always treated as object targets.
+ return "OBJECT";
+ case cmStateEnums::EXECUTABLE:
+ switch (artifact) {
+ case cmStateEnums::RuntimeBinaryArtifact:
+ // Executables are always treated as runtime targets.
+ return "RUNTIME";
+ case cmStateEnums::ImportLibraryArtifact:
+ // Executable import libraries are treated as archive targets.
+ return "ARCHIVE";
+ }
+ break;
+ default:
+ break;
+ }
+ return "";
+}
+
+std::string cmGeneratorTarget::GetOutputName(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ // Lookup/compute/cache the output name for this configuration.
+ OutputNameKey key(config, artifact);
+ auto i = this->OutputNameMap.find(key);
+ if (i == this->OutputNameMap.end()) {
+ // Add empty name in map to detect potential recursion.
+ OutputNameMapType::value_type entry(key, "");
+ i = this->OutputNameMap.insert(entry).first;
+
+ // Compute output name.
+ std::vector<std::string> props;
+ std::string type = this->GetOutputTargetType(artifact);
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ if (!type.empty() && !configUpper.empty()) {
+ // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
+ props.push_back(type + "_OUTPUT_NAME_" + configUpper);
+ }
+ if (!type.empty()) {
+ // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
+ props.push_back(type + "_OUTPUT_NAME");
+ }
+ if (!configUpper.empty()) {
+ // OUTPUT_NAME_<CONFIG>
+ props.push_back("OUTPUT_NAME_" + configUpper);
+ // <CONFIG>_OUTPUT_NAME
+ props.push_back(configUpper + "_OUTPUT_NAME");
+ }
+ // OUTPUT_NAME
+ props.emplace_back("OUTPUT_NAME");
+
+ std::string outName;
+ for (std::string const& p : props) {
+ if (cmProp outNameProp = this->GetProperty(p)) {
+ outName = *outNameProp;
+ break;
+ }
+ }
+
+ if (outName.empty()) {
+ outName = this->GetName();
+ }
+
+ // Now evaluate genex and update the previously-prepared map entry.
+ i->second =
+ cmGeneratorExpression::Evaluate(outName, this->LocalGenerator, config);
+ } else if (i->second.empty()) {
+ // An empty map entry indicates we have been called recursively
+ // from the above block.
+ this->LocalGenerator->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Target '" + this->GetName() + "' OUTPUT_NAME depends on itself.",
+ this->GetBacktrace());
+ }
+ return i->second;
+}
+
+std::string cmGeneratorTarget::GetFilePrefix(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ if (this->IsImported()) {
+ cmProp prefix = this->GetFilePrefixInternal(config, artifact);
+ return prefix ? *prefix : std::string();
+ }
+
+ std::string prefix;
+ std::string suffix;
+ std::string base;
+ this->GetFullNameInternal(config, artifact, prefix, base, suffix);
+ return prefix;
+}
+std::string cmGeneratorTarget::GetFileSuffix(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ if (this->IsImported()) {
+ cmProp suffix = this->GetFileSuffixInternal(config, artifact);
+ return suffix ? *suffix : std::string();
+ }
+
+ std::string prefix;
+ std::string suffix;
+ std::string base;
+ this->GetFullNameInternal(config, artifact, prefix, base, suffix);
+ return suffix;
+}
+
+std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const
+{
+ cmProp postfix = nullptr;
+ std::string frameworkPostfix;
+ if (!config.empty()) {
+ std::string configProp =
+ cmStrCat(cmSystemTools::UpperCase(config), "_POSTFIX");
+ postfix = this->GetProperty(configProp);
+
+ // Mac application bundles and frameworks have no regular postfix like
+ // libraries do.
+ if (!this->IsImported() && postfix &&
+ (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) {
+ postfix = nullptr;
+ }
+
+ // Frameworks created by multi config generators can have a special
+ // framework postfix.
+ frameworkPostfix = this->GetFrameworkMultiConfigPostfix(config);
+ if (!frameworkPostfix.empty()) {
+ postfix = &frameworkPostfix;
+ }
+ }
+ return postfix ? *postfix : std::string();
+}
+
+std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix(
+ const std::string& config) const
+{
+ cmProp postfix = nullptr;
+ if (!config.empty()) {
+ std::string configProp = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_",
+ cmSystemTools::UpperCase(config));
+ postfix = this->GetProperty(configProp);
+
+ if (!this->IsImported() && postfix &&
+ (this->IsFrameworkOnApple() &&
+ !this->GetGlobalGenerator()->IsMultiConfig())) {
+ postfix = nullptr;
+ }
+ }
+ return postfix ? *postfix : std::string();
+}
+
+cmProp cmGeneratorTarget::GetFilePrefixInternal(
+ std::string const& config, cmStateEnums::ArtifactType artifact,
+ const std::string& language) const
+{
+ // no prefix for non-main target types.
+ if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ return nullptr;
+ }
+
+ const bool isImportedLibraryArtifact =
+ (artifact == cmStateEnums::ImportLibraryArtifact);
+
+ // Return an empty prefix for the import library if this platform
+ // does not support import libraries.
+ if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
+ return nullptr;
+ }
+
+ // The implib option is only allowed for shared libraries, module
+ // libraries, and executables.
+ if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ artifact = cmStateEnums::RuntimeBinaryArtifact;
+ }
+
+ // Compute prefix value.
+ cmProp targetPrefix =
+ (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
+ : this->GetProperty("PREFIX"));
+
+ if (!targetPrefix) {
+ const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
+ if (!language.empty() && cmNonempty(prefixVar)) {
+ std::string langPrefix = cmStrCat(prefixVar, "_", language);
+ targetPrefix = this->Makefile->GetDefinition(langPrefix);
+ }
+
+ // if there is no prefix on the target nor specific language
+ // use the cmake definition.
+ if (!targetPrefix && prefixVar) {
+ targetPrefix = this->Makefile->GetDefinition(prefixVar);
+ }
+ }
+
+ return targetPrefix;
+}
+
+cmProp cmGeneratorTarget::GetFileSuffixInternal(
+ std::string const& config, cmStateEnums::ArtifactType artifact,
+ const std::string& language) const
+{
+ // no suffix for non-main target types.
+ if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ return nullptr;
+ }
+
+ const bool isImportedLibraryArtifact =
+ (artifact == cmStateEnums::ImportLibraryArtifact);
+
+ // Return an empty suffix for the import library if this platform
+ // does not support import libraries.
+ if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
+ return nullptr;
+ }
+
+ // The implib option is only allowed for shared libraries, module
+ // libraries, and executables.
+ if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ artifact = cmStateEnums::RuntimeBinaryArtifact;
+ }
+
+ // Compute suffix value.
+ cmProp targetSuffix =
+ (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
+ : this->GetProperty("SUFFIX"));
+
+ if (!targetSuffix) {
+ const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
+ if (!language.empty() && cmNonempty(suffixVar)) {
+ std::string langSuffix = cmStrCat(suffixVar, "_", language);
+ targetSuffix = this->Makefile->GetDefinition(langSuffix);
+ }
+
+ // if there is no suffix on the target nor specific language
+ // use the cmake definition.
+ if (!targetSuffix && suffixVar) {
+ targetSuffix = this->Makefile->GetDefinition(suffixVar);
+ }
+ }
+
+ return targetSuffix;
+}
+
+void cmGeneratorTarget::ClearSourcesCache()
+{
+ this->AllConfigSources.clear();
+ this->KindedSourcesMap.clear();
+ this->SourcesAreContextDependent = Tribool::Indeterminate;
+ this->Objects.clear();
+ this->VisitedConfigsForObjects.clear();
+}
+
+void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before)
+{
+ this->SourceEntries.insert(
+ before ? this->SourceEntries.begin() : this->SourceEntries.end(),
+ CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true));
+ this->ClearSourcesCache();
+}
+
+void cmGeneratorTarget::AddSource(const std::string& src, bool before)
+{
+ this->Target->AddSource(src, before);
+ this->AddSourceCommon(src, before);
+}
+
+void cmGeneratorTarget::AddTracedSources(std::vector<std::string> const& srcs)
+{
+ this->Target->AddTracedSources(srcs);
+ if (!srcs.empty()) {
+ this->AddSourceCommon(cmJoin(srcs, ";"));
+ }
+}
+
+void cmGeneratorTarget::AddIncludeDirectory(const std::string& src,
+ bool before)
+{
+ this->Target->InsertInclude(src, this->Makefile->GetBacktrace(), before);
+ this->IncludeDirectoriesEntries.insert(
+ before ? this->IncludeDirectoriesEntries.begin()
+ : this->IncludeDirectoriesEntries.end(),
+ CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true));
+}
+
+std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(
+ cmSourceFile const* sf) const
+{
+ auto i = this->SourceDepends.find(sf);
+ if (i != this->SourceDepends.end()) {
+ return &i->second.Depends;
+ }
+ return nullptr;
+}
+
+namespace {
+void handleSystemIncludesDep(cmLocalGenerator* lg,
+ cmGeneratorTarget const* depTgt,
+ const std::string& config,
+ cmGeneratorTarget const* headTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::vector<std::string>& result,
+ bool excludeImported, std::string const& language)
+{
+ if (cmProp dirs =
+ depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) {
+ cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget,
+ dagChecker, depTgt, language),
+ result);
+ }
+ if (!depTgt->IsImported() || excludeImported) {
+ return;
+ }
+
+ if (cmProp dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) {
+ cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget,
+ dagChecker, depTgt, language),
+ result);
+ }
+}
+}
+
+/* clang-format off */
+#define IMPLEMENT_VISIT(KIND) \
+ do { \
+ KindedSources const& kinded = this->GetKindedSources(config); \
+ for (SourceAndKind const& s : kinded.Sources) { \
+ if (s.Kind == KIND) { \
+ data.push_back(s.Source.Value); \
+ } \
+ } \
+ } while (false)
+/* clang-format on */
+
+void cmGeneratorTarget::GetObjectSources(
+ std::vector<cmSourceFile const*>& data, const std::string& config) const
+{
+ IMPLEMENT_VISIT(SourceKindObjectSource);
+
+ if (this->VisitedConfigsForObjects.count(config)) {
+ return;
+ }
+
+ for (cmSourceFile const* it : data) {
+ this->Objects[it];
+ }
+
+ this->LocalGenerator->ComputeObjectFilenames(this->Objects, this);
+ this->VisitedConfigsForObjects.insert(config);
+}
+
+void cmGeneratorTarget::ComputeObjectMapping()
+{
+ auto const& configs =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ std::set<std::string> configSet(configs.begin(), configs.end());
+ if (configSet == this->VisitedConfigsForObjects) {
+ return;
+ }
+
+ for (std::string const& c : configs) {
+ std::vector<cmSourceFile const*> sourceFiles;
+ this->GetObjectSources(sourceFiles, c);
+ }
+}
+
+cmProp cmGeneratorTarget::GetFeature(const std::string& feature,
+ const std::string& config) const
+{
+ if (!config.empty()) {
+ std::string featureConfig =
+ cmStrCat(feature, '_', cmSystemTools::UpperCase(config));
+ if (cmProp value = this->GetProperty(featureConfig)) {
+ return value;
+ }
+ }
+ if (cmProp value = this->GetProperty(feature)) {
+ return value;
+ }
+ return this->LocalGenerator->GetFeature(feature, config);
+}
+
+const char* cmGeneratorTarget::GetLinkPIEProperty(
+ const std::string& config) const
+{
+ static std::string PICValue;
+
+ PICValue = this->GetLinkInterfaceDependentStringAsBoolProperty(
+ "POSITION_INDEPENDENT_CODE", config);
+
+ if (PICValue == "(unset)") {
+ // POSITION_INDEPENDENT_CODE is not set
+ return nullptr;
+ }
+
+ auto status = this->GetPolicyStatusCMP0083();
+ return (status != cmPolicies::WARN && status != cmPolicies::OLD)
+ ? PICValue.c_str()
+ : nullptr;
+}
+
+bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang,
+ std::string const& config) const
+{
+ cmProp feature = this->GetFeature("INTERPROCEDURAL_OPTIMIZATION", config);
+
+ if (!cmIsOn(feature)) {
+ // 'INTERPROCEDURAL_OPTIMIZATION' is off, no need to check policies
+ return false;
+ }
+
+ if (lang != "C" && lang != "CXX" && lang != "Fortran") {
+ // We do not define IPO behavior for other languages.
+ return false;
+ }
+
+ cmPolicies::PolicyStatus cmp0069 = this->GetPolicyStatusCMP0069();
+
+ if (cmp0069 == cmPolicies::OLD || cmp0069 == cmPolicies::WARN) {
+ if (this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_LEGACY_BEHAVIOR")) {
+ return true;
+ }
+ if (this->PolicyReportedCMP0069) {
+ // problem is already reported, no need to issue a message
+ return false;
+ }
+ const bool in_try_compile =
+ this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile();
+ if (cmp0069 == cmPolicies::WARN && !in_try_compile) {
+ std::ostringstream w;
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0069) << "\n";
+ w << "INTERPROCEDURAL_OPTIMIZATION property will be ignored for target "
+ << "'" << this->GetName() << "'.";
+ this->LocalGenerator->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING, w.str(), this->GetBacktrace());
+
+ this->PolicyReportedCMP0069 = true;
+ }
+ return false;
+ }
+
+ // Note: check consistency with messages from CheckIPOSupported
+ const char* message = nullptr;
+ if (!this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_SUPPORTED_BY_CMAKE")) {
+ message = "CMake doesn't support IPO for current compiler";
+ } else if (!this->Makefile->IsOn("_CMAKE_" + lang +
+ "_IPO_MAY_BE_SUPPORTED_BY_COMPILER")) {
+ message = "Compiler doesn't support IPO";
+ } else if (!this->GlobalGenerator->IsIPOSupported()) {
+ message = "CMake doesn't support IPO for current generator";
+ }
+
+ if (!message) {
+ // No error/warning messages
+ return true;
+ }
+
+ if (this->PolicyReportedCMP0069) {
+ // problem is already reported, no need to issue a message
+ return false;
+ }
+
+ this->PolicyReportedCMP0069 = true;
+
+ this->LocalGenerator->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR, message, this->GetBacktrace());
+ return false;
+}
+
+const std::string& cmGeneratorTarget::GetObjectName(cmSourceFile const* file)
+{
+ this->ComputeObjectMapping();
+ return this->Objects[file];
+}
+
+const char* cmGeneratorTarget::GetCustomObjectExtension() const
+{
+ static std::string extension;
+ const bool has_ptx_extension =
+ this->GetPropertyAsBool("CUDA_PTX_COMPILATION");
+ if (has_ptx_extension) {
+ extension = ".ptx";
+ return extension.c_str();
+ }
+ return nullptr;
+}
+
+void cmGeneratorTarget::AddExplicitObjectName(cmSourceFile const* sf)
+{
+ this->ExplicitObjectName.insert(sf);
+}
+
+bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const
+{
+ const_cast<cmGeneratorTarget*>(this)->ComputeObjectMapping();
+ auto it = this->ExplicitObjectName.find(file);
+ return it != this->ExplicitObjectName.end();
+}
+
+BTs<std::string> const* cmGeneratorTarget::GetLanguageStandardProperty(
+ std::string const& lang, std::string const& config) const
+{
+ std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang);
+ auto langStandardIter = this->LanguageStandardMap.find(key);
+ if (langStandardIter != this->LanguageStandardMap.end()) {
+ return &langStandardIter->second;
+ }
+
+ return this->Target->GetLanguageStandardProperty(
+ cmStrCat(lang, "_STANDARD"));
+}
+
+cmProp cmGeneratorTarget::GetLanguageStandard(std::string const& lang,
+ std::string const& config) const
+{
+ BTs<std::string> const* languageStandard =
+ this->GetLanguageStandardProperty(lang, config);
+
+ if (languageStandard) {
+ return &(languageStandard->Value);
+ }
+
+ return nullptr;
+}
+
+cmProp cmGeneratorTarget::GetPropertyWithPairedLanguageSupport(
+ std::string const& lang, const char* suffix) const
+{
+ cmProp propertyValue = this->Target->GetProperty(cmStrCat(lang, suffix));
+ if (propertyValue == nullptr) {
+ // Check if we should use the value set by another language.
+ if (lang == "OBJC") {
+ propertyValue = this->GetPropertyWithPairedLanguageSupport("C", suffix);
+ } else if (lang == "OBJCXX" || lang == "CUDA") {
+ propertyValue =
+ this->GetPropertyWithPairedLanguageSupport("CXX", suffix);
+ }
+ }
+ return propertyValue;
+}
+
+cmProp cmGeneratorTarget::GetLanguageExtensions(std::string const& lang) const
+{
+ return this->GetPropertyWithPairedLanguageSupport(lang, "_EXTENSIONS");
+}
+
+bool cmGeneratorTarget::GetLanguageStandardRequired(
+ std::string const& lang) const
+{
+ return cmIsOn(
+ this->GetPropertyWithPairedLanguageSupport(lang, "_STANDARD_REQUIRED"));
+}
+
+void cmGeneratorTarget::GetModuleDefinitionSources(
+ std::vector<cmSourceFile const*>& data, const std::string& config) const
+{
+ IMPLEMENT_VISIT(SourceKindModuleDefinition);
+}
+
+void cmGeneratorTarget::GetHeaderSources(
+ std::vector<cmSourceFile const*>& data, const std::string& config) const
+{
+ IMPLEMENT_VISIT(SourceKindHeader);
+}
+
+void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile const*>& data,
+ const std::string& config) const
+{
+ IMPLEMENT_VISIT(SourceKindExtra);
+}
+
+void cmGeneratorTarget::GetCustomCommands(
+ std::vector<cmSourceFile const*>& data, const std::string& config) const
+{
+ IMPLEMENT_VISIT(SourceKindCustomCommand);
+}
+
+void cmGeneratorTarget::GetExternalObjects(
+ std::vector<cmSourceFile const*>& data, const std::string& config) const
+{
+ IMPLEMENT_VISIT(SourceKindExternalObject);
+}
+
+void cmGeneratorTarget::GetManifests(std::vector<cmSourceFile const*>& data,
+ const std::string& config) const
+{
+ IMPLEMENT_VISIT(SourceKindManifest);
+}
+
+std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const
+{
+ if (!this->UtilityItemsDone) {
+ this->UtilityItemsDone = true;
+ std::set<BT<std::pair<std::string, bool>>> const& utilities =
+ this->GetUtilities();
+ for (BT<std::pair<std::string, bool>> const& i : utilities) {
+ if (cmGeneratorTarget* gt =
+ this->LocalGenerator->FindGeneratorTargetToUse(i.Value.first)) {
+ this->UtilityItems.insert(cmLinkItem(gt, i.Value.second, i.Backtrace));
+ } else {
+ this->UtilityItems.insert(
+ cmLinkItem(i.Value.first, i.Value.second, i.Backtrace));
+ }
+ }
+ }
+ return this->UtilityItems;
+}
+
+const std::string& cmGeneratorTarget::GetLocation(
+ const std::string& config) const
+{
+ static std::string location;
+ if (this->IsImported()) {
+ location = this->Target->ImportedGetFullPath(
+ config, cmStateEnums::RuntimeBinaryArtifact);
+ } else {
+ location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
+ }
+ return location;
+}
+
+cm::optional<std::string> cmGeneratorTarget::MaybeGetLocation(
+ std::string const& config) const
+{
+ cm::optional<std::string> location;
+ if (cmGeneratorTarget::ImportInfo const* imp = this->GetImportInfo(config)) {
+ if (!imp->Location.empty()) {
+ location = imp->Location;
+ }
+ } else {
+ location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
+ }
+ return location;
+}
+
+std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreBuildCommands()
+ const
+{
+ return this->Target->GetPreBuildCommands();
+}
+
+std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreLinkCommands()
+ const
+{
+ return this->Target->GetPreLinkCommands();
+}
+
+std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPostBuildCommands()
+ const
+{
+ return this->Target->GetPostBuildCommands();
+}
+
+void cmGeneratorTarget::AppendCustomCommandSideEffects(
+ std::set<cmGeneratorTarget const*>& sideEffects) const
+{
+ if (!this->GetPreBuildCommands().empty() ||
+ !this->GetPreLinkCommands().empty() ||
+ !this->GetPostBuildCommands().empty()) {
+ sideEffects.insert(this);
+ } else {
+ for (auto const& source : this->GetAllConfigSources()) {
+ if (source.Source->GetCustomCommand() != nullptr) {
+ sideEffects.insert(this);
+ break;
+ }
+ }
+ }
+}
+
+void cmGeneratorTarget::AppendLanguageSideEffects(
+ std::map<std::string, std::set<cmGeneratorTarget const*>>& sideEffects) const
+{
+ static const std::set<cm::string_view> LANGS_WITH_NO_SIDE_EFFECTS = {
+ "C"_s, "CXX"_s, "OBJC"_s, "OBJCXX"_s, "ASM"_s, "CUDA"_s,
+ };
+
+ for (auto const& lang : this->GetAllConfigCompileLanguages()) {
+ if (!LANGS_WITH_NO_SIDE_EFFECTS.count(lang)) {
+ sideEffects[lang].insert(this);
+ }
+ }
+}
+
+bool cmGeneratorTarget::IsInBuildSystem() const
+{
+ if (this->IsImported()) {
+ return false;
+ }
+ switch (this->Target->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::OBJECT_LIBRARY:
+ case cmStateEnums::UTILITY:
+ case cmStateEnums::GLOBAL_TARGET:
+ return true;
+ case cmStateEnums::INTERFACE_LIBRARY:
+ // An INTERFACE library is in the build system if it has SOURCES.
+ if (!this->SourceEntries.empty()) {
+ return true;
+ }
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ break;
+ }
+ return false;
+}
+
+bool cmGeneratorTarget::IsImported() const
+{
+ return this->Target->IsImported();
+}
+
+bool cmGeneratorTarget::IsImportedGloballyVisible() const
+{
+ return this->Target->IsImportedGloballyVisible();
+}
+
+bool cmGeneratorTarget::CanCompileSources() const
+{
+ return this->Target->CanCompileSources();
+}
+
+const std::string& cmGeneratorTarget::GetLocationForBuild() const
+{
+ static std::string location;
+ if (this->IsImported()) {
+ location = this->Target->ImportedGetFullPath(
+ "", cmStateEnums::RuntimeBinaryArtifact);
+ return location;
+ }
+
+ // Now handle the deprecated build-time configuration location.
+ std::string const noConfig;
+ location = this->GetDirectory(noConfig);
+ cmProp cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR");
+ if (cfgid && (*cfgid != ".")) {
+ location += "/";
+ location += *cfgid;
+ }
+
+ if (this->IsAppBundleOnApple()) {
+ std::string macdir = this->BuildBundleDirectory("", "", FullLevel);
+ if (!macdir.empty()) {
+ location += "/";
+ location += macdir;
+ }
+ }
+ location += "/";
+ location += this->GetFullName("", cmStateEnums::RuntimeBinaryArtifact);
+ return location;
+}
+
+bool cmGeneratorTarget::IsSystemIncludeDirectory(
+ const std::string& dir, const std::string& config,
+ const std::string& language) const
+{
+ assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
+ std::string config_upper;
+ if (!config.empty()) {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+
+ std::string key = cmStrCat(config_upper, "/", language);
+ auto iter = this->SystemIncludesCache.find(key);
+
+ if (iter == this->SystemIncludesCache.end()) {
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr);
+
+ bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED");
+
+ std::vector<std::string> result;
+ for (std::string const& it : this->Target->GetSystemIncludeDirectories()) {
+ cmExpandList(cmGeneratorExpression::Evaluate(it, this->LocalGenerator,
+ config, this, &dagChecker,
+ nullptr, language),
+ result);
+ }
+
+ std::vector<cmGeneratorTarget const*> const& deps =
+ this->GetLinkImplementationClosure(config);
+ for (cmGeneratorTarget const* dep : deps) {
+ handleSystemIncludesDep(this->LocalGenerator, dep, config, this,
+ &dagChecker, result, excludeImported, language);
+ }
+
+ std::for_each(result.begin(), result.end(),
+ cmSystemTools::ConvertToUnixSlashes);
+ std::sort(result.begin(), result.end());
+ result.erase(std::unique(result.begin(), result.end()), result.end());
+
+ iter = this->SystemIncludesCache.emplace(key, result).first;
+ }
+
+ return std::binary_search(iter->second.begin(), iter->second.end(), dir);
+}
+
+bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const
+{
+ return this->Target->GetPropertyAsBool(prop);
+}
+
+bool cmGeneratorTarget::MaybeHaveInterfaceProperty(
+ std::string const& prop, cmGeneratorExpressionContext* context,
+ bool usage_requirements_only) const
+{
+ std::string const key = prop + '@' + context->Config;
+ auto i = this->MaybeInterfacePropertyExists.find(key);
+ if (i == this->MaybeInterfacePropertyExists.end()) {
+ // Insert an entry now in case there is a cycle.
+ i = this->MaybeInterfacePropertyExists.emplace(key, false).first;
+ bool& maybeInterfaceProp = i->second;
+
+ // If this target itself has a non-empty property value, we are done.
+ maybeInterfaceProp = cmNonempty(this->GetProperty(prop));
+
+ // Otherwise, recurse to interface dependencies.
+ if (!maybeInterfaceProp) {
+ cmGeneratorTarget const* headTarget =
+ context->HeadTarget ? context->HeadTarget : this;
+ if (cmLinkInterfaceLibraries const* iface =
+ this->GetLinkInterfaceLibraries(context->Config, headTarget,
+ usage_requirements_only)) {
+ if (iface->HadHeadSensitiveCondition) {
+ // With a different head target we may get to a library with
+ // this interface property.
+ maybeInterfaceProp = true;
+ } else {
+ // The transitive interface libraries do not depend on the
+ // head target, so we can follow them.
+ for (cmLinkItem const& lib : iface->Libraries) {
+ if (lib.Target &&
+ lib.Target->MaybeHaveInterfaceProperty(
+ prop, context, usage_requirements_only)) {
+ maybeInterfaceProp = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return i->second;
+}
+
+std::string cmGeneratorTarget::EvaluateInterfaceProperty(
+ std::string const& prop, cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker* dagCheckerParent,
+ bool usage_requirements_only) const
+{
+ std::string result;
+
+ // If the property does not appear transitively at all, we are done.
+ if (!this->MaybeHaveInterfaceProperty(prop, context,
+ usage_requirements_only)) {
+ return result;
+ }
+
+ // Evaluate $<TARGET_PROPERTY:this,prop> as if it were compiled. This is
+ // a subset of TargetPropertyNode::Evaluate without stringify/parse steps
+ // but sufficient for transitive interface properties.
+ cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, this, prop,
+ nullptr, dagCheckerParent);
+ switch (dagChecker.Check()) {
+ case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
+ dagChecker.ReportError(
+ context, "$<TARGET_PROPERTY:" + this->GetName() + "," + prop + ">");
+ return result;
+ case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
+ // No error. We just skip cyclic references.
+ case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
+ // No error. We have already seen this transitive property.
+ return result;
+ case cmGeneratorExpressionDAGChecker::DAG:
+ break;
+ }
+
+ cmGeneratorTarget const* headTarget =
+ context->HeadTarget ? context->HeadTarget : this;
+
+ if (cmProp p = this->GetProperty(prop)) {
+ result = cmGeneratorExpressionNode::EvaluateDependentExpression(
+ *p, context->LG, context, headTarget, &dagChecker, this);
+ }
+
+ if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries(
+ context->Config, headTarget, usage_requirements_only)) {
+ context->HadContextSensitiveCondition =
+ context->HadContextSensitiveCondition ||
+ iface->HadContextSensitiveCondition;
+ for (cmLinkItem const& lib : iface->Libraries) {
+ // Broken code can have a target in its own link interface.
+ // Don't follow such link interface entries so as not to create a
+ // self-referencing loop.
+ if (lib.Target && lib.Target != this) {
+ // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in the
+ // above property and hand-evaluate it as if it were compiled.
+ // Create a context as cmCompiledGeneratorExpression::Evaluate does.
+ cmGeneratorExpressionContext libContext(
+ context->LG, context->Config, context->Quiet, headTarget, this,
+ context->EvaluateForBuildsystem, context->Backtrace,
+ context->Language);
+ std::string libResult = cmGeneratorExpression::StripEmptyListElements(
+ lib.Target->EvaluateInterfaceProperty(prop, &libContext, &dagChecker,
+ usage_requirements_only));
+ if (!libResult.empty()) {
+ if (result.empty()) {
+ result = std::move(libResult);
+ } else {
+ result.reserve(result.size() + 1 + libResult.size());
+ result += ";";
+ result += libResult;
+ }
+ }
+ context->HadContextSensitiveCondition =
+ context->HadContextSensitiveCondition ||
+ libContext.HadContextSensitiveCondition;
+ context->HadHeadSensitiveCondition =
+ context->HadHeadSensitiveCondition ||
+ libContext.HadHeadSensitiveCondition;
+ }
+ }
+ }
+
+ return result;
+}
+
+namespace {
+
+enum class IncludeDirectoryFallBack
+{
+ BINARY,
+ OBJECT
+};
+
+std::string AddLangSpecificInterfaceIncludeDirectories(
+ const cmGeneratorTarget* root, const cmGeneratorTarget* target,
+ const std::string& lang, const std::string& config,
+ const std::string& propertyName, IncludeDirectoryFallBack mode,
+ cmGeneratorExpressionDAGChecker* context)
+{
+ cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
+ propertyName, nullptr, context };
+ switch (dag.Check()) {
+ case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
+ dag.ReportError(
+ nullptr, "$<TARGET_PROPERTY:" + target->GetName() + ",propertyName");
+ CM_FALLTHROUGH;
+ case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
+ // No error. We just skip cyclic references.
+ case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
+ // No error. We have already seen this transitive property.
+ return "";
+ case cmGeneratorExpressionDAGChecker::DAG:
+ break;
+ }
+
+ std::string directories;
+ if (const auto* interface =
+ target->GetLinkInterfaceLibraries(config, root, true)) {
+ for (const cmLinkItem& library : interface->Libraries) {
+ if (const cmGeneratorTarget* dependency = library.Target) {
+ if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) {
+ auto* lg = dependency->GetLocalGenerator();
+ std::string value = dependency->GetSafeProperty(propertyName);
+ if (value.empty()) {
+ if (mode == IncludeDirectoryFallBack::BINARY) {
+ value = lg->GetCurrentBinaryDirectory();
+ } else if (mode == IncludeDirectoryFallBack::OBJECT) {
+ value = cmStrCat(lg->GetCurrentBinaryDirectory(), '/',
+ lg->GetTargetDirectory(dependency));
+ }
+ }
+
+ if (!directories.empty()) {
+ directories += ";";
+ }
+ directories += value;
+ }
+ }
+ }
+ }
+ return directories;
+}
+
+void AddLangSpecificImplicitIncludeDirectories(
+ const cmGeneratorTarget* target, const std::string& lang,
+ const std::string& config, const std::string& propertyName,
+ IncludeDirectoryFallBack mode, EvaluatedTargetPropertyEntries& entries)
+{
+ if (const auto* libraries = target->GetLinkImplementationLibraries(config)) {
+ cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
+ propertyName, nullptr, nullptr };
+
+ for (const cmLinkImplItem& library : libraries->Libraries) {
+ if (const cmGeneratorTarget* dependency = library.Target) {
+ if (!dependency->IsInBuildSystem()) {
+ continue;
+ }
+ if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) {
+ auto* lg = dependency->GetLocalGenerator();
+ EvaluatedTargetPropertyEntry entry{ library, library.Backtrace };
+
+ if (cmProp val = dependency->GetProperty(propertyName)) {
+ entry.Values.emplace_back(*val);
+ } else {
+ if (mode == IncludeDirectoryFallBack::BINARY) {
+ entry.Values.emplace_back(lg->GetCurrentBinaryDirectory());
+ } else if (mode == IncludeDirectoryFallBack::OBJECT) {
+ entry.Values.emplace_back(
+ dependency->GetObjectDirectory(config));
+ }
+ }
+
+ cmExpandList(
+ AddLangSpecificInterfaceIncludeDirectories(
+ target, dependency, lang, config, propertyName, mode, &dag),
+ entry.Values);
+ entries.Entries.emplace_back(std::move(entry));
+ }
+ }
+ }
+ }
+}
+
+void AddInterfaceEntries(cmGeneratorTarget const* headTarget,
+ std::string const& config, std::string const& prop,
+ std::string const& lang,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ EvaluatedTargetPropertyEntries& entries,
+ bool usage_requirements_only = true)
+{
+ if (cmLinkImplementationLibraries const* impl =
+ headTarget->GetLinkImplementationLibraries(config)) {
+ entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition;
+ for (cmLinkImplItem const& lib : impl->Libraries) {
+ if (lib.Target) {
+ EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace);
+ // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
+ // caller's property and hand-evaluate it as if it were compiled.
+ // Create a context as cmCompiledGeneratorExpression::Evaluate does.
+ cmGeneratorExpressionContext context(
+ headTarget->GetLocalGenerator(), config, false, headTarget,
+ headTarget, true, lib.Backtrace, lang);
+ cmExpandList(lib.Target->EvaluateInterfaceProperty(
+ prop, &context, dagChecker, usage_requirements_only),
+ ee.Values);
+ ee.ContextDependent = context.HadContextSensitiveCondition;
+ entries.Entries.emplace_back(std::move(ee));
+ }
+ }
+ }
+}
+
+void AddObjectEntries(cmGeneratorTarget const* headTarget,
+ std::string const& config,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ EvaluatedTargetPropertyEntries& entries)
+{
+ if (cmLinkImplementationLibraries const* impl =
+ headTarget->GetLinkImplementationLibraries(config)) {
+ entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition;
+ for (cmLinkImplItem const& lib : impl->Libraries) {
+ if (lib.Target &&
+ lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ std::string uniqueName =
+ headTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely(
+ lib.Target);
+ std::string genex = "$<TARGET_OBJECTS:" + std::move(uniqueName) + ">";
+ cmGeneratorExpression ge(lib.Backtrace);
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
+ cge->SetEvaluateForBuildsystem(true);
+
+ EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace);
+ cmExpandList(cge->Evaluate(headTarget->GetLocalGenerator(), config,
+ headTarget, dagChecker),
+ ee.Values);
+ if (cge->GetHadContextSensitiveCondition()) {
+ ee.ContextDependent = true;
+ }
+ entries.Entries.emplace_back(std::move(ee));
+ }
+ }
+ }
+}
+
+bool processSources(cmGeneratorTarget const* tgt,
+ EvaluatedTargetPropertyEntries& entries,
+ std::vector<BT<std::string>>& srcs,
+ std::unordered_set<std::string>& uniqueSrcs,
+ bool debugSources)
+{
+ cmMakefile* mf = tgt->Target->GetMakefile();
+
+ bool contextDependent = entries.HadContextSensitiveCondition;
+
+ for (EvaluatedTargetPropertyEntry& entry : entries.Entries) {
+ if (entry.ContextDependent) {
+ contextDependent = true;
+ }
+
+ cmLinkImplItem const& item = entry.LinkImplItem;
+ std::string const& targetName = item.AsStr();
+
+ for (std::string& src : entry.Values) {
+ cmSourceFile* sf = mf->GetOrCreateSource(src);
+ std::string e;
+ std::string w;
+ std::string fullPath = sf->ResolveFullPath(&e, &w);
+ cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance();
+ if (!w.empty()) {
+ cm->IssueMessage(MessageType::AUTHOR_WARNING, w, tgt->GetBacktrace());
+ }
+ if (fullPath.empty()) {
+ if (!e.empty()) {
+ cm->IssueMessage(MessageType::FATAL_ERROR, e, tgt->GetBacktrace());
+ }
+ return contextDependent;
+ }
+
+ if (!targetName.empty() && !cmSystemTools::FileIsFullPath(src)) {
+ std::ostringstream err;
+ if (!targetName.empty()) {
+ err << "Target \"" << targetName
+ << "\" contains relative path in its INTERFACE_SOURCES:\n \""
+ << src << "\"";
+ } else {
+ err << "Found relative path while evaluating sources of \""
+ << tgt->GetName() << "\":\n \"" << src << "\"\n";
+ }
+ tgt->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
+ err.str());
+ return contextDependent;
+ }
+ src = fullPath;
+ }
+ std::string usedSources;
+ for (std::string const& src : entry.Values) {
+ if (uniqueSrcs.insert(src).second) {
+ srcs.emplace_back(src, entry.Backtrace);
+ if (debugSources) {
+ usedSources += " * " + src + "\n";
+ }
+ }
+ }
+ if (!usedSources.empty()) {
+ tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
+ MessageType::LOG,
+ std::string("Used sources for target ") + tgt->GetName() + ":\n" +
+ usedSources,
+ entry.Backtrace);
+ }
+ }
+ return contextDependent;
+}
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths(
+ std::string const& config) const
+{
+ std::vector<BT<std::string>> files;
+
+ if (!this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
+ // At configure-time, this method can be called as part of getting the
+ // LOCATION property or to export() a file to be include()d. However
+ // there is no cmGeneratorTarget at configure-time, so search the SOURCES
+ // for TARGET_OBJECTS instead for backwards compatibility with OLD
+ // behavior of CMP0024 and CMP0026 only.
+
+ cmStringRange sourceEntries = this->Target->GetSourceEntries();
+ for (std::string const& entry : sourceEntries) {
+ std::vector<std::string> items = cmExpandedList(entry);
+ for (std::string const& item : items) {
+ if (cmHasLiteralPrefix(item, "$<TARGET_OBJECTS:") &&
+ item.back() == '>') {
+ continue;
+ }
+ files.emplace_back(item);
+ }
+ }
+ return files;
+ }
+
+ std::vector<std::string> debugProperties;
+ this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
+ debugProperties);
+
+ bool debugSources =
+ !this->DebugSourcesDone && cm::contains(debugProperties, "SOURCES");
+
+ if (this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
+ this->DebugSourcesDone = true;
+ }
+
+ cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr,
+ nullptr);
+
+ EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
+ this, config, std::string(), &dagChecker, this->SourceEntries);
+
+ std::unordered_set<std::string> uniqueSrcs;
+ bool contextDependentDirectSources =
+ processSources(this, entries, files, uniqueSrcs, debugSources);
+
+ // Collect INTERFACE_SOURCES of all direct link-dependencies.
+ EvaluatedTargetPropertyEntries linkInterfaceSourcesEntries;
+ AddInterfaceEntries(this, config, "INTERFACE_SOURCES", std::string(),
+ &dagChecker, linkInterfaceSourcesEntries);
+ std::vector<std::string>::size_type numFilesBefore = files.size();
+ bool contextDependentInterfaceSources = processSources(
+ this, linkInterfaceSourcesEntries, files, uniqueSrcs, debugSources);
+
+ // Collect TARGET_OBJECTS of direct object link-dependencies.
+ bool contextDependentObjects = false;
+ std::vector<std::string>::size_type numFilesBefore2 = files.size();
+ if (this->GetType() != cmStateEnums::OBJECT_LIBRARY) {
+ EvaluatedTargetPropertyEntries linkObjectsEntries;
+ AddObjectEntries(this, config, &dagChecker, linkObjectsEntries);
+ contextDependentObjects = processSources(this, linkObjectsEntries, files,
+ uniqueSrcs, debugSources);
+ }
+
+ // Determine if sources are context-dependent or not.
+ if (!contextDependentDirectSources &&
+ !(contextDependentInterfaceSources && numFilesBefore < files.size()) &&
+ !(contextDependentObjects && numFilesBefore2 < files.size())) {
+ this->SourcesAreContextDependent = Tribool::False;
+ } else {
+ this->SourcesAreContextDependent = Tribool::True;
+ }
+
+ return files;
+}
+
+void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files,
+ const std::string& config) const
+{
+ std::vector<BT<cmSourceFile*>> tmp = this->GetSourceFiles(config);
+ files.reserve(tmp.size());
+ for (BT<cmSourceFile*>& v : tmp) {
+ files.push_back(v.Value);
+ }
+}
+
+std::vector<BT<cmSourceFile*>> cmGeneratorTarget::GetSourceFiles(
+ std::string const& config) const
+{
+ std::vector<BT<cmSourceFile*>> files;
+ if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ // Since we are still configuring not all sources may exist yet,
+ // so we need to avoid full source classification because that
+ // requires the absolute paths to all sources to be determined.
+ // Since this is only for compatibility with old policies that
+ // projects should not depend on anymore, just compute the files
+ // without memoizing them.
+ std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config);
+ std::set<cmSourceFile*> emitted;
+ for (BT<std::string> const& s : srcs) {
+ cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value);
+ if (emitted.insert(sf).second) {
+ files.emplace_back(sf, s.Backtrace);
+ }
+ }
+ return files;
+ }
+
+ KindedSources const& kinded = this->GetKindedSources(config);
+ files.reserve(kinded.Sources.size());
+ for (SourceAndKind const& si : kinded.Sources) {
+ files.push_back(si.Source);
+ }
+ return files;
+}
+
+void cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
+ std::vector<cmSourceFile*>& files, const std::string& config) const
+{
+ std::vector<BT<cmSourceFile*>> tmp =
+ this->GetSourceFilesWithoutObjectLibraries(config);
+ files.reserve(tmp.size());
+ for (BT<cmSourceFile*>& v : tmp) {
+ files.push_back(v.Value);
+ }
+}
+
+std::vector<BT<cmSourceFile*>>
+cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
+ std::string const& config) const
+{
+ std::vector<BT<cmSourceFile*>> files;
+ KindedSources const& kinded = this->GetKindedSources(config);
+ files.reserve(kinded.Sources.size());
+ for (SourceAndKind const& si : kinded.Sources) {
+ if (si.Source.Value->GetObjectLibrary().empty()) {
+ files.push_back(si.Source);
+ }
+ }
+ return files;
+}
+
+cmGeneratorTarget::KindedSources const& cmGeneratorTarget::GetKindedSources(
+ std::string const& config) const
+{
+ // If we already processed one configuration and found no dependency
+ // on configuration then always use the one result.
+ if (this->SourcesAreContextDependent == Tribool::False) {
+ return this->KindedSourcesMap.begin()->second;
+ }
+
+ // Lookup any existing link implementation for this configuration.
+ std::string const key = cmSystemTools::UpperCase(config);
+ auto it = this->KindedSourcesMap.find(key);
+ if (it != this->KindedSourcesMap.end()) {
+ if (!it->second.Initialized) {
+ std::ostringstream e;
+ e << "The SOURCES of \"" << this->GetName()
+ << "\" use a generator expression that depends on the "
+ "SOURCES themselves.";
+ this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR, e.str(), this->GetBacktrace());
+ static KindedSources empty;
+ return empty;
+ }
+ return it->second;
+ }
+
+ // Add an entry to the map for this configuration.
+ KindedSources& files = this->KindedSourcesMap[key];
+ this->ComputeKindedSources(files, config);
+ files.Initialized = true;
+ return files;
+}
+
+void cmGeneratorTarget::ComputeKindedSources(KindedSources& files,
+ std::string const& config) const
+{
+ // Get the source file paths by string.
+ std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config);
+
+ cmsys::RegularExpression header_regex(CM_HEADER_REGEX);
+ std::vector<cmSourceFile*> badObjLib;
+
+ std::set<cmSourceFile*> emitted;
+ for (BT<std::string> const& s : srcs) {
+ // Create each source at most once.
+ cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value);
+ if (!emitted.insert(sf).second) {
+ continue;
+ }
+
+ // Compute the kind (classification) of this source file.
+ SourceKind kind;
+ std::string ext = cmSystemTools::LowerCase(sf->GetExtension());
+ if (sf->GetCustomCommand()) {
+ kind = SourceKindCustomCommand;
+ } else if (this->Target->GetType() == cmStateEnums::UTILITY ||
+ this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY
+ // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
+ // NOLINTNEXTLINE(bugprone-branch-clone)
+ ) {
+ kind = SourceKindExtra;
+ } else if (this->IsSourceFilePartOfUnityBatch(sf->ResolveFullPath())) {
+ kind = SourceKindUnityBatched;
+ // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
+ // NOLINTNEXTLINE(bugprone-branch-clone)
+ } else if (sf->GetPropertyAsBool("HEADER_FILE_ONLY")) {
+ kind = SourceKindHeader;
+ } else if (sf->GetPropertyAsBool("EXTERNAL_OBJECT")) {
+ kind = SourceKindExternalObject;
+ } else if (!sf->GetOrDetermineLanguage().empty()) {
+ kind = SourceKindObjectSource;
+ } else if (ext == "def") {
+ kind = SourceKindModuleDefinition;
+ if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ badObjLib.push_back(sf);
+ }
+ } else if (ext == "idl") {
+ kind = SourceKindIDL;
+ if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ badObjLib.push_back(sf);
+ }
+ } else if (ext == "resx") {
+ kind = SourceKindResx;
+ } else if (ext == "appxmanifest") {
+ kind = SourceKindAppManifest;
+ } else if (ext == "manifest") {
+ kind = SourceKindManifest;
+ } else if (ext == "pfx") {
+ kind = SourceKindCertificate;
+ } else if (ext == "xaml") {
+ kind = SourceKindXaml;
+ } else if (header_regex.find(sf->ResolveFullPath())) {
+ kind = SourceKindHeader;
+ } else {
+ kind = SourceKindExtra;
+ }
+
+ // Save this classified source file in the result vector.
+ files.Sources.push_back({ BT<cmSourceFile*>(sf, s.Backtrace), kind });
+ }
+
+ if (!badObjLib.empty()) {
+ std::ostringstream e;
+ e << "OBJECT library \"" << this->GetName() << "\" contains:\n";
+ for (cmSourceFile* i : badObjLib) {
+ e << " " << i->GetLocation().GetName() << "\n";
+ }
+ e << "but may contain only sources that compile, header files, and "
+ "other files that would not affect linking of a normal library.";
+ this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR, e.str(), this->GetBacktrace());
+ }
+}
+
+std::vector<cmGeneratorTarget::AllConfigSource> const&
+cmGeneratorTarget::GetAllConfigSources() const
+{
+ if (this->AllConfigSources.empty()) {
+ this->ComputeAllConfigSources();
+ }
+ return this->AllConfigSources;
+}
+
+void cmGeneratorTarget::ComputeAllConfigSources() const
+{
+ std::vector<std::string> configs =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+ std::map<cmSourceFile const*, size_t> index;
+
+ for (size_t ci = 0; ci < configs.size(); ++ci) {
+ KindedSources const& sources = this->GetKindedSources(configs[ci]);
+ for (SourceAndKind const& src : sources.Sources) {
+ auto mi = index.find(src.Source.Value);
+ if (mi == index.end()) {
+ AllConfigSource acs;
+ acs.Source = src.Source.Value;
+ acs.Kind = src.Kind;
+ this->AllConfigSources.push_back(std::move(acs));
+ std::map<cmSourceFile const*, size_t>::value_type entry(
+ src.Source.Value, this->AllConfigSources.size() - 1);
+ mi = index.insert(entry).first;
+ }
+ this->AllConfigSources[mi->second].Configs.push_back(ci);
+ }
+ }
+}
+
+std::vector<cmGeneratorTarget::AllConfigSource>
+cmGeneratorTarget::GetAllConfigSources(SourceKind kind) const
+{
+ std::vector<AllConfigSource> result;
+ for (AllConfigSource const& source : this->GetAllConfigSources()) {
+ if (source.Kind == kind) {
+ result.push_back(source);
+ }
+ }
+ return result;
+}
+
+std::set<std::string> cmGeneratorTarget::GetAllConfigCompileLanguages() const
+{
+ std::set<std::string> languages;
+ std::vector<AllConfigSource> const& sources = this->GetAllConfigSources();
+ for (AllConfigSource const& si : sources) {
+ std::string const& lang = si.Source->GetOrDetermineLanguage();
+ if (!lang.empty()) {
+ languages.emplace(lang);
+ }
+ }
+ return languages;
+}
+
+std::string cmGeneratorTarget::GetCompilePDBName(
+ const std::string& config) const
+{
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
+ prefix, base, suffix);
+
+ // Check for a per-configuration output directory target property.
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ std::string configProp = cmStrCat("COMPILE_PDB_NAME_", configUpper);
+ cmProp config_name = this->GetProperty(configProp);
+ if (cmNonempty(config_name)) {
+ return prefix + *config_name + ".pdb";
+ }
+
+ cmProp name = this->GetProperty("COMPILE_PDB_NAME");
+ if (cmNonempty(name)) {
+ return prefix + *name + ".pdb";
+ }
+
+ return "";
+}
+
+std::string cmGeneratorTarget::GetCompilePDBPath(
+ const std::string& config) const
+{
+ std::string dir = this->GetCompilePDBDirectory(config);
+ std::string name = this->GetCompilePDBName(config);
+ if (dir.empty() && !name.empty() && this->HaveWellDefinedOutputFiles()) {
+ dir = this->GetPDBDirectory(config);
+ }
+ if (!dir.empty()) {
+ dir += "/";
+ }
+ return dir + name;
+}
+
+bool cmGeneratorTarget::HasSOName(const std::string& config) const
+{
+ // soname is supported only for shared libraries and modules,
+ // and then only when the platform supports an soname flag.
+ return ((this->GetType() == cmStateEnums::SHARED_LIBRARY) &&
+ !this->GetPropertyAsBool("NO_SONAME") &&
+ this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config)));
+}
+
+bool cmGeneratorTarget::NeedRelinkBeforeInstall(
+ const std::string& config) const
+{
+ // Only executables and shared libraries can have an rpath and may
+ // need relinking.
+ if (this->GetType() != cmStateEnums::EXECUTABLE &&
+ this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY) {
+ return false;
+ }
+
+ // If there is no install location this target will not be installed
+ // and therefore does not need relinking.
+ if (!this->Target->GetHaveInstallRule()) {
+ return false;
+ }
+
+ // If skipping all rpaths completely then no relinking is needed.
+ if (this->Makefile->IsOn("CMAKE_SKIP_RPATH")) {
+ return false;
+ }
+
+ // If building with the install-tree rpath no relinking is needed.
+ if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
+ return false;
+ }
+
+ // If chrpath is going to be used no relinking is needed.
+ if (this->IsChrpathUsed(config)) {
+ return false;
+ }
+
+ // Check for rpath support on this platform.
+ std::string ll = this->GetLinkerLanguage(config);
+ if (!ll.empty()) {
+ std::string flagVar =
+ cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG");
+ if (!this->Makefile->IsSet(flagVar)) {
+ // There is no rpath support on this platform so nothing needs
+ // relinking.
+ return false;
+ }
+ } else {
+ // No linker language is known. This error will be reported by
+ // other code.
+ return false;
+ }
+
+ // If either a build or install tree rpath is set then the rpath
+ // will likely change between the build tree and install tree and
+ // this target must be relinked.
+ bool have_rpath =
+ this->HaveBuildTreeRPATH(config) || this->HaveInstallTreeRPATH(config);
+ bool is_ninja = this->LocalGenerator->GetGlobalGenerator()->IsNinja();
+
+ if (have_rpath && is_ninja) {
+ std::ostringstream w;
+ /* clang-format off */
+ w <<
+ "The install of the " << this->GetName() << " target requires changing "
+ "an RPATH from the build tree, but this is not supported with the Ninja "
+ "generator unless on an ELF-based or XCOFF-based platform. "
+ "The CMAKE_BUILD_WITH_INSTALL_RPATH variable may be set to avoid this "
+ "relinking step."
+ ;
+ /* clang-format on */
+
+ cmake* cm = this->LocalGenerator->GetCMakeInstance();
+ cm->IssueMessage(MessageType::FATAL_ERROR, w.str(), this->GetBacktrace());
+ }
+
+ return have_rpath;
+}
+
+bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const
+{
+ // Only certain target types have an rpath.
+ if (!(this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ this->GetType() == cmStateEnums::EXECUTABLE)) {
+ return false;
+ }
+
+ // If the target will not be installed we do not need to change its
+ // rpath.
+ if (!this->Target->GetHaveInstallRule()) {
+ return false;
+ }
+
+ // Skip chrpath if skipping rpath altogether.
+ if (this->Makefile->IsOn("CMAKE_SKIP_RPATH")) {
+ return false;
+ }
+
+ // Skip chrpath if it does not need to be changed at install time.
+ if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
+ return false;
+ }
+
+ // Allow the user to disable builtin chrpath explicitly.
+ if (this->Makefile->IsOn("CMAKE_NO_BUILTIN_CHRPATH")) {
+ return false;
+ }
+
+ if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ return true;
+ }
+
+#if defined(CMake_USE_ELF_PARSER) || defined(CMake_USE_XCOFF_PARSER)
+ // Enable if the rpath flag uses a separator and the target uses
+ // binaries we know how to edit.
+ std::string ll = this->GetLinkerLanguage(config);
+ if (!ll.empty()) {
+ std::string sepVar =
+ cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG_SEP");
+ cmProp sep = this->Makefile->GetDefinition(sepVar);
+ if (cmNonempty(sep)) {
+ // TODO: Add binary format check to ABI detection and get rid of
+ // CMAKE_EXECUTABLE_FORMAT.
+ if (cmProp fmt =
+ this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT")) {
+# if defined(CMake_USE_ELF_PARSER)
+ if (*fmt == "ELF") {
+ return true;
+ }
+# endif
+# if defined(CMake_USE_XCOFF_PARSER)
+ if (*fmt == "XCOFF") {
+ return true;
+ }
+# endif
+ }
+ }
+ }
+#endif
+ static_cast<void>(config);
+ return false;
+}
+
+bool cmGeneratorTarget::IsImportedSharedLibWithoutSOName(
+ const std::string& config) const
+{
+ if (this->IsImported() && this->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ if (cmGeneratorTarget::ImportInfo const* info =
+ this->GetImportInfo(config)) {
+ return info->NoSOName;
+ }
+ }
+ return false;
+}
+
+bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir(
+ const std::string& config) const
+{
+ bool install_name_is_rpath = false;
+ bool macosx_rpath = false;
+
+ if (!this->IsImported()) {
+ if (this->GetType() != cmStateEnums::SHARED_LIBRARY) {
+ return false;
+ }
+ cmProp install_name = this->GetProperty("INSTALL_NAME_DIR");
+ bool use_install_name = this->MacOSXUseInstallNameDir();
+ if (install_name && use_install_name && *install_name == "@rpath") {
+ install_name_is_rpath = true;
+ } else if (install_name && use_install_name) {
+ return false;
+ }
+ if (!install_name_is_rpath) {
+ macosx_rpath = this->MacOSXRpathInstallNameDirDefault();
+ }
+ } else {
+ // Lookup the imported soname.
+ if (cmGeneratorTarget::ImportInfo const* info =
+ this->GetImportInfo(config)) {
+ if (!info->NoSOName && !info->SOName.empty()) {
+ if (cmHasLiteralPrefix(info->SOName, "@rpath/")) {
+ install_name_is_rpath = true;
+ }
+ } else {
+ std::string install_name;
+ cmSystemTools::GuessLibraryInstallName(info->Location, install_name);
+ if (install_name.find("@rpath") != std::string::npos) {
+ install_name_is_rpath = true;
+ }
+ }
+ }
+ }
+
+ if (!install_name_is_rpath && !macosx_rpath) {
+ return false;
+ }
+
+ if (!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) {
+ std::ostringstream w;
+ w << "Attempting to use ";
+ if (macosx_rpath) {
+ w << "MACOSX_RPATH";
+ } else {
+ w << "@rpath";
+ }
+ w << " without CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG being set.";
+ w << " This could be because you are using a Mac OS X version";
+ w << " less than 10.5 or because CMake's platform configuration is";
+ w << " corrupt.";
+ cmake* cm = this->LocalGenerator->GetCMakeInstance();
+ cm->IssueMessage(MessageType::FATAL_ERROR, w.str(), this->GetBacktrace());
+ }
+
+ return true;
+}
+
+bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const
+{
+ // we can't do rpaths when unsupported
+ if (!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) {
+ return false;
+ }
+
+ cmProp macosx_rpath_str = this->GetProperty("MACOSX_RPATH");
+ if (macosx_rpath_str) {
+ return this->GetPropertyAsBool("MACOSX_RPATH");
+ }
+
+ cmPolicies::PolicyStatus cmp0042 = this->GetPolicyStatusCMP0042();
+
+ if (cmp0042 == cmPolicies::WARN) {
+ this->LocalGenerator->GetGlobalGenerator()->AddCMP0042WarnTarget(
+ this->GetName());
+ }
+
+ return cmp0042 == cmPolicies::NEW;
+}
+
+bool cmGeneratorTarget::MacOSXUseInstallNameDir() const
+{
+ cmProp build_with_install_name =
+ this->GetProperty("BUILD_WITH_INSTALL_NAME_DIR");
+ if (build_with_install_name) {
+ return cmIsOn(*build_with_install_name);
+ }
+
+ cmPolicies::PolicyStatus cmp0068 = this->GetPolicyStatusCMP0068();
+ if (cmp0068 == cmPolicies::NEW) {
+ return false;
+ }
+
+ bool use_install_name = this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH");
+
+ if (use_install_name && cmp0068 == cmPolicies::WARN) {
+ this->LocalGenerator->GetGlobalGenerator()->AddCMP0068WarnTarget(
+ this->GetName());
+ }
+
+ return use_install_name;
+}
+
+bool cmGeneratorTarget::CanGenerateInstallNameDir(
+ InstallNameType name_type) const
+{
+ cmPolicies::PolicyStatus cmp0068 = this->GetPolicyStatusCMP0068();
+
+ if (cmp0068 == cmPolicies::NEW) {
+ return true;
+ }
+
+ bool skip = this->Makefile->IsOn("CMAKE_SKIP_RPATH");
+ if (name_type == INSTALL_NAME_FOR_INSTALL) {
+ skip |= this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH");
+ } else {
+ skip |= this->GetPropertyAsBool("SKIP_BUILD_RPATH");
+ }
+
+ if (skip && cmp0068 == cmPolicies::WARN) {
+ this->LocalGenerator->GetGlobalGenerator()->AddCMP0068WarnTarget(
+ this->GetName());
+ }
+
+ return !skip;
+}
+
+std::string cmGeneratorTarget::GetSOName(const std::string& config) const
+{
+ if (this->IsImported()) {
+ // Lookup the imported soname.
+ if (cmGeneratorTarget::ImportInfo const* info =
+ this->GetImportInfo(config)) {
+ if (info->NoSOName) {
+ // The imported library has no builtin soname so the name
+ // searched at runtime will be just the filename.
+ return cmSystemTools::GetFilenameName(info->Location);
+ }
+ // Use the soname given if any.
+ if (cmHasLiteralPrefix(info->SOName, "@rpath/")) {
+ return info->SOName.substr(6);
+ }
+ return info->SOName;
+ }
+ return "";
+ }
+ // Compute the soname that will be built.
+ return this->GetLibraryNames(config).SharedObject;
+}
+
+namespace {
+bool shouldAddFullLevel(cmGeneratorTarget::BundleDirectoryLevel level)
+{
+ return level == cmGeneratorTarget::FullLevel;
+}
+
+bool shouldAddContentLevel(cmGeneratorTarget::BundleDirectoryLevel level)
+{
+ return level == cmGeneratorTarget::ContentLevel || shouldAddFullLevel(level);
+}
+}
+
+std::string cmGeneratorTarget::GetAppBundleDirectory(
+ const std::string& config, BundleDirectoryLevel level) const
+{
+ std::string fpath = cmStrCat(
+ this->GetFullName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
+ cmProp ext = this->GetProperty("BUNDLE_EXTENSION");
+ fpath += (ext ? *ext : "app");
+ if (shouldAddContentLevel(level) &&
+ !this->Makefile->PlatformIsAppleEmbedded()) {
+ fpath += "/Contents";
+ if (shouldAddFullLevel(level)) {
+ fpath += "/MacOS";
+ }
+ }
+ return fpath;
+}
+
+bool cmGeneratorTarget::IsBundleOnApple() const
+{
+ return this->IsFrameworkOnApple() || this->IsAppBundleOnApple() ||
+ this->IsCFBundleOnApple();
+}
+
+bool cmGeneratorTarget::IsWin32Executable(const std::string& config) const
+{
+ return cmIsOn(cmGeneratorExpression::Evaluate(
+ this->GetSafeProperty("WIN32_EXECUTABLE"), this->LocalGenerator, config));
+}
+
+std::string cmGeneratorTarget::GetCFBundleDirectory(
+ const std::string& config, BundleDirectoryLevel level) const
+{
+ std::string fpath = cmStrCat(
+ this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
+ std::string ext;
+ if (cmProp p = this->GetProperty("BUNDLE_EXTENSION")) {
+ ext = *p;
+ } else {
+ if (this->IsXCTestOnApple()) {
+ ext = "xctest";
+ } else {
+ ext = "bundle";
+ }
+ }
+ fpath += ext;
+ if (shouldAddContentLevel(level) &&
+ !this->Makefile->PlatformIsAppleEmbedded()) {
+ fpath += "/Contents";
+ if (shouldAddFullLevel(level)) {
+ fpath += "/MacOS";
+ }
+ }
+ return fpath;
+}
+
+std::string cmGeneratorTarget::GetFrameworkDirectory(
+ const std::string& config, BundleDirectoryLevel level) const
+{
+ std::string fpath = cmStrCat(
+ this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
+ cmProp ext = this->GetProperty("BUNDLE_EXTENSION");
+ fpath += (ext ? *ext : "framework");
+ if (shouldAddFullLevel(level) &&
+ !this->Makefile->PlatformIsAppleEmbedded()) {
+ fpath += "/Versions/";
+ fpath += this->GetFrameworkVersion();
+ }
+ return fpath;
+}
+
+std::string cmGeneratorTarget::GetFullName(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ if (this->IsImported()) {
+ return this->GetFullNameImported(config, artifact);
+ }
+ return this->GetFullNameInternal(config, artifact);
+}
+
+std::string cmGeneratorTarget::GetInstallNameDirForBuildTree(
+ const std::string& config) const
+{
+ if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+
+ // If building directly for installation then the build tree install_name
+ // is the same as the install tree.
+ if (this->MacOSXUseInstallNameDir()) {
+ std::string installPrefix =
+ this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
+ return this->GetInstallNameDirForInstallTree(config, installPrefix);
+ }
+
+ // Use the build tree directory for the target.
+ if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_BUILD)) {
+ std::string dir;
+ if (this->MacOSXRpathInstallNameDirDefault()) {
+ dir = "@rpath";
+ } else {
+ dir = this->GetDirectory(config);
+ }
+ dir += "/";
+ return dir;
+ }
+ }
+ return "";
+}
+
+std::string cmGeneratorTarget::GetInstallNameDirForInstallTree(
+ const std::string& config, const std::string& installPrefix) const
+{
+ if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ std::string dir;
+ cmProp install_name_dir = this->GetProperty("INSTALL_NAME_DIR");
+
+ if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_INSTALL)) {
+ if (cmNonempty(install_name_dir)) {
+ dir = *install_name_dir;
+ cmGeneratorExpression::ReplaceInstallPrefix(dir, installPrefix);
+ dir =
+ cmGeneratorExpression::Evaluate(dir, this->LocalGenerator, config);
+ if (!dir.empty()) {
+ dir = cmStrCat(dir, '/');
+ }
+ }
+ }
+ if (!install_name_dir) {
+ if (this->MacOSXRpathInstallNameDirDefault()) {
+ dir = "@rpath/";
+ }
+ }
+ return dir;
+ }
+ return "";
+}
+
+cmListFileBacktrace cmGeneratorTarget::GetBacktrace() const
+{
+ return this->Target->GetBacktrace();
+}
+
+const std::set<BT<std::pair<std::string, bool>>>&
+cmGeneratorTarget::GetUtilities() const
+{
+ return this->Target->GetUtilities();
+}
+
+bool cmGeneratorTarget::HaveWellDefinedOutputFiles() const
+{
+ return this->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
+ this->GetType() == cmStateEnums::EXECUTABLE;
+}
+
+const std::string* cmGeneratorTarget::GetExportMacro() const
+{
+ // Define the symbol for targets that export symbols.
+ if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ this->IsExecutableWithExports()) {
+ if (cmProp custom_export_name = this->GetProperty("DEFINE_SYMBOL")) {
+ this->ExportMacro = *custom_export_name;
+ } else {
+ std::string in = cmStrCat(this->GetName(), "_EXPORTS");
+ this->ExportMacro = cmSystemTools::MakeCidentifier(in);
+ }
+ return &this->ExportMacro;
+ }
+ return nullptr;
+}
+
+class cmTargetCollectLinkLanguages
+{
+public:
+ cmTargetCollectLinkLanguages(cmGeneratorTarget const* target,
+ std::string config,
+ std::unordered_set<std::string>& languages,
+ cmGeneratorTarget const* head, bool secondPass)
+ : Config(std::move(config))
+ , Languages(languages)
+ , HeadTarget(head)
+ , Target(target)
+ , SecondPass(secondPass)
+ {
+ this->Visited.insert(target);
+ }
+
+ void Visit(cmLinkItem const& item)
+ {
+ if (!item.Target) {
+ if (item.AsStr().find("::") != std::string::npos) {
+ bool noMessage = false;
+ MessageType messageType = MessageType::FATAL_ERROR;
+ std::ostringstream e;
+ switch (this->Target->GetLocalGenerator()->GetPolicyStatus(
+ cmPolicies::CMP0028)) {
+ case cmPolicies::WARN: {
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0028) << "\n";
+ messageType = MessageType::AUTHOR_WARNING;
+ } break;
+ case cmPolicies::OLD:
+ noMessage = true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Issue the fatal message.
+ break;
+ }
+
+ if (!noMessage) {
+ e << "Target \"" << this->Target->GetName()
+ << "\" links to target \"" << item.AsStr()
+ << "\" but the target was not found. Perhaps a find_package() "
+ "call is missing for an IMPORTED target, or an ALIAS target is "
+ "missing?";
+ this->Target->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
+ messageType, e.str(), this->Target->GetBacktrace());
+ }
+ }
+ return;
+ }
+ if (!this->Visited.insert(item.Target).second) {
+ return;
+ }
+ cmLinkInterface const* iface = item.Target->GetLinkInterface(
+ this->Config, this->HeadTarget, this->SecondPass);
+ if (!iface) {
+ return;
+ }
+ if (iface->HadLinkLanguageSensitiveCondition) {
+ this->HadLinkLanguageSensitiveCondition = true;
+ }
+
+ for (std::string const& language : iface->Languages) {
+ this->Languages.insert(language);
+ }
+
+ for (cmLinkItem const& lib : iface->Libraries) {
+ this->Visit(lib);
+ }
+ }
+
+ bool GetHadLinkLanguageSensitiveCondition() const
+ {
+ return this->HadLinkLanguageSensitiveCondition;
+ }
+
+private:
+ std::string Config;
+ std::unordered_set<std::string>& Languages;
+ cmGeneratorTarget const* HeadTarget;
+ const cmGeneratorTarget* Target;
+ std::set<cmGeneratorTarget const*> Visited;
+ bool SecondPass;
+ bool HadLinkLanguageSensitiveCondition = false;
+};
+
+cmGeneratorTarget::LinkClosure const* cmGeneratorTarget::GetLinkClosure(
+ const std::string& config) const
+{
+ // There is no link implementation for targets that cannot compile sources.
+ if (!this->CanCompileSources()) {
+ static LinkClosure const empty = { {}, {} };
+ return &empty;
+ }
+
+ std::string key(cmSystemTools::UpperCase(config));
+ auto i = this->LinkClosureMap.find(key);
+ if (i == this->LinkClosureMap.end()) {
+ LinkClosure lc;
+ this->ComputeLinkClosure(config, lc);
+ LinkClosureMapType::value_type entry(key, lc);
+ i = this->LinkClosureMap.insert(entry).first;
+ }
+ return &i->second;
+}
+
+class cmTargetSelectLinker
+{
+ int Preference;
+ cmGeneratorTarget const* Target;
+ cmGlobalGenerator* GG;
+ std::set<std::string> Preferred;
+
+public:
+ cmTargetSelectLinker(cmGeneratorTarget const* target)
+ : Preference(0)
+ , Target(target)
+ {
+ this->GG = this->Target->GetLocalGenerator()->GetGlobalGenerator();
+ }
+ void Consider(const std::string& lang)
+ {
+ int preference = this->GG->GetLinkerPreference(lang);
+ if (preference > this->Preference) {
+ this->Preference = preference;
+ this->Preferred.clear();
+ }
+ if (preference == this->Preference) {
+ this->Preferred.insert(lang);
+ }
+ }
+ std::string Choose()
+ {
+ if (this->Preferred.empty()) {
+ return "";
+ }
+ if (this->Preferred.size() > 1) {
+ std::ostringstream e;
+ e << "Target " << this->Target->GetName()
+ << " contains multiple languages with the highest linker preference"
+ << " (" << this->Preference << "):\n";
+ for (std::string const& li : this->Preferred) {
+ e << " " << li << "\n";
+ }
+ e << "Set the LINKER_LANGUAGE property for this target.";
+ cmake* cm = this->Target->GetLocalGenerator()->GetCMakeInstance();
+ cm->IssueMessage(MessageType::FATAL_ERROR, e.str(),
+ this->Target->GetBacktrace());
+ }
+ return *this->Preferred.begin();
+ }
+};
+
+bool cmGeneratorTarget::ComputeLinkClosure(const std::string& config,
+ LinkClosure& lc,
+ bool secondPass) const
+{
+ // Get languages built in this target.
+ std::unordered_set<std::string> languages;
+ cmLinkImplementation const* impl =
+ this->GetLinkImplementation(config, secondPass);
+ assert(impl);
+ languages.insert(impl->Languages.cbegin(), impl->Languages.cend());
+
+ // Add interface languages from linked targets.
+ // cmTargetCollectLinkLanguages cll(this, config, languages, this,
+ // secondPass);
+ cmTargetCollectLinkLanguages cll(this, config, languages, this, secondPass);
+ for (cmLinkImplItem const& lib : impl->Libraries) {
+ cll.Visit(lib);
+ }
+
+ // Store the transitive closure of languages.
+ cm::append(lc.Languages, languages);
+
+ // Choose the language whose linker should be used.
+ if (secondPass || lc.LinkerLanguage.empty()) {
+ // Find the language with the highest preference value.
+ cmTargetSelectLinker tsl(this);
+
+ // First select from the languages compiled directly in this target.
+ for (std::string const& l : impl->Languages) {
+ tsl.Consider(l);
+ }
+
+ // Now consider languages that propagate from linked targets.
+ for (std::string const& lang : languages) {
+ std::string propagates =
+ "CMAKE_" + lang + "_LINKER_PREFERENCE_PROPAGATES";
+ if (this->Makefile->IsOn(propagates)) {
+ tsl.Consider(lang);
+ }
+ }
+
+ lc.LinkerLanguage = tsl.Choose();
+ }
+
+ return impl->HadLinkLanguageSensitiveCondition ||
+ cll.GetHadLinkLanguageSensitiveCondition();
+}
+
+void cmGeneratorTarget::ComputeLinkClosure(const std::string& config,
+ LinkClosure& lc) const
+{
+ bool secondPass = false;
+
+ {
+ LinkClosure linkClosure;
+ linkClosure.LinkerLanguage = this->LinkerLanguage;
+
+ bool hasHardCodedLinkerLanguage = this->Target->GetProperty("HAS_CXX") ||
+ !this->Target->GetSafeProperty("LINKER_LANGUAGE").empty();
+
+ // Get languages built in this target.
+ secondPass = this->ComputeLinkClosure(config, linkClosure, false) &&
+ !hasHardCodedLinkerLanguage;
+ this->LinkerLanguage = linkClosure.LinkerLanguage;
+ if (!secondPass) {
+ lc = std::move(linkClosure);
+ }
+ }
+
+ if (secondPass) {
+ LinkClosure linkClosure;
+
+ this->ComputeLinkClosure(config, linkClosure, secondPass);
+ lc = std::move(linkClosure);
+
+ // linker language must not be changed between the two passes
+ if (this->LinkerLanguage != lc.LinkerLanguage) {
+ std::ostringstream e;
+ e << "Evaluation of $<LINK_LANGUAGE:...> or $<LINK_LAND_AND_ID:...> "
+ "changes\nthe linker language for target \""
+ << this->GetName() << "\" (from '" << this->LinkerLanguage << "' to '"
+ << lc.LinkerLanguage << "') which is invalid.";
+ cmSystemTools::Error(e.str());
+ }
+ }
+}
+
+void cmGeneratorTarget::GetFullNameComponents(
+ std::string& prefix, std::string& base, std::string& suffix,
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ this->GetFullNameInternal(config, artifact, prefix, base, suffix);
+}
+
+std::string cmGeneratorTarget::BuildBundleDirectory(
+ const std::string& base, const std::string& config,
+ BundleDirectoryLevel level) const
+{
+ std::string fpath = base;
+ if (this->IsAppBundleOnApple()) {
+ fpath += this->GetAppBundleDirectory(config, level);
+ }
+ if (this->IsFrameworkOnApple()) {
+ fpath += this->GetFrameworkDirectory(config, level);
+ }
+ if (this->IsCFBundleOnApple()) {
+ fpath += this->GetCFBundleDirectory(config, level);
+ }
+ return fpath;
+}
+
+std::string cmGeneratorTarget::GetMacContentDirectory(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ // Start with the output directory for the target.
+ std::string fpath = cmStrCat(this->GetDirectory(config, artifact), '/');
+ BundleDirectoryLevel level = ContentLevel;
+ if (this->IsFrameworkOnApple()) {
+ // additional files with a framework go into the version specific
+ // directory
+ level = FullLevel;
+ }
+ fpath = this->BuildBundleDirectory(fpath, config, level);
+ return fpath;
+}
+
+std::string cmGeneratorTarget::GetEffectiveFolderName() const
+{
+ std::string effectiveFolder;
+
+ if (!this->GlobalGenerator->UseFolderProperty()) {
+ return effectiveFolder;
+ }
+
+ cmProp targetFolder = this->GetProperty("FOLDER");
+ if (targetFolder) {
+ effectiveFolder += *targetFolder;
+ }
+
+ return effectiveFolder;
+}
+
+cmGeneratorTarget::CompileInfo const* cmGeneratorTarget::GetCompileInfo(
+ const std::string& config) const
+{
+ // There is no compile information for imported targets.
+ if (this->IsImported()) {
+ return nullptr;
+ }
+
+ if (this->GetType() > cmStateEnums::OBJECT_LIBRARY) {
+ std::string msg = cmStrCat("cmTarget::GetCompileInfo called for ",
+ this->GetName(), " which has type ",
+ cmState::GetTargetTypeName(this->GetType()));
+ this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
+ return nullptr;
+ }
+
+ // Lookup/compute/cache the compile information for this configuration.
+ std::string config_upper;
+ if (!config.empty()) {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+ auto i = this->CompileInfoMap.find(config_upper);
+ if (i == this->CompileInfoMap.end()) {
+ CompileInfo info;
+ this->ComputePDBOutputDir("COMPILE_PDB", config, info.CompilePdbDir);
+ CompileInfoMapType::value_type entry(config_upper, info);
+ i = this->CompileInfoMap.insert(entry).first;
+ }
+ return &i->second;
+}
+
+cmGeneratorTarget::ModuleDefinitionInfo const*
+cmGeneratorTarget::GetModuleDefinitionInfo(std::string const& config) const
+{
+ // A module definition file only makes sense on certain target types.
+ if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ !this->IsExecutableWithExports()) {
+ return nullptr;
+ }
+
+ // Lookup/compute/cache the compile information for this configuration.
+ std::string config_upper;
+ if (!config.empty()) {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+ auto i = this->ModuleDefinitionInfoMap.find(config_upper);
+ if (i == this->ModuleDefinitionInfoMap.end()) {
+ ModuleDefinitionInfo info;
+ this->ComputeModuleDefinitionInfo(config, info);
+ ModuleDefinitionInfoMapType::value_type entry(config_upper, info);
+ i = this->ModuleDefinitionInfoMap.insert(entry).first;
+ }
+ return &i->second;
+}
+
+void cmGeneratorTarget::ComputeModuleDefinitionInfo(
+ std::string const& config, ModuleDefinitionInfo& info) const
+{
+ this->GetModuleDefinitionSources(info.Sources, config);
+ info.WindowsExportAllSymbols =
+ this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") &&
+ this->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS");
+#if !defined(CMAKE_BOOTSTRAP)
+ info.DefFileGenerated =
+ info.WindowsExportAllSymbols || info.Sources.size() > 1;
+#else
+ // Our __create_def helper is not available during CMake bootstrap.
+ info.DefFileGenerated = false;
+#endif
+ if (info.DefFileGenerated) {
+ info.DefFile =
+ this->GetObjectDirectory(config) /* has slash */ + "exports.def";
+ } else if (!info.Sources.empty()) {
+ info.DefFile = info.Sources.front()->GetFullPath();
+ }
+}
+
+bool cmGeneratorTarget::IsDLLPlatform() const
+{
+ return this->Target->IsDLLPlatform();
+}
+
+void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string>& result,
+ const std::string& config) const
+{
+ const char* prop =
+ this->GetLinkInterfaceDependentStringProperty("AUTOUIC_OPTIONS", config);
+ if (!prop) {
+ return;
+ }
+
+ cmGeneratorExpressionDAGChecker dagChecker(this, "AUTOUIC_OPTIONS", nullptr,
+ nullptr);
+ cmExpandList(cmGeneratorExpression::Evaluate(prop, this->LocalGenerator,
+ config, this, &dagChecker),
+ result);
+}
+
+void processILibs(const std::string& config,
+ cmGeneratorTarget const* headTarget, cmLinkItem const& item,
+ cmGlobalGenerator* gg,
+ std::vector<cmGeneratorTarget const*>& tgts,
+ std::set<cmGeneratorTarget const*>& emitted)
+{
+ if (item.Target && emitted.insert(item.Target).second) {
+ tgts.push_back(item.Target);
+ if (cmLinkInterfaceLibraries const* iface =
+ item.Target->GetLinkInterfaceLibraries(config, headTarget, true)) {
+ for (cmLinkItem const& lib : iface->Libraries) {
+ processILibs(config, headTarget, lib, gg, tgts, emitted);
+ }
+ }
+ }
+}
+
+const std::vector<const cmGeneratorTarget*>&
+cmGeneratorTarget::GetLinkImplementationClosure(
+ const std::string& config) const
+{
+ // There is no link implementation for targets that cannot compile sources.
+ if (!this->CanCompileSources()) {
+ static std::vector<const cmGeneratorTarget*> const empty;
+ return empty;
+ }
+
+ LinkImplClosure& tgts = this->LinkImplClosureMap[config];
+ if (!tgts.Done) {
+ tgts.Done = true;
+ std::set<cmGeneratorTarget const*> emitted;
+
+ cmLinkImplementationLibraries const* impl =
+ this->GetLinkImplementationLibraries(config);
+ assert(impl);
+
+ for (cmLinkImplItem const& lib : impl->Libraries) {
+ processILibs(config, this, lib,
+ this->LocalGenerator->GetGlobalGenerator(), tgts, emitted);
+ }
+ }
+ return tgts;
+}
+
+class cmTargetTraceDependencies
+{
+public:
+ cmTargetTraceDependencies(cmGeneratorTarget* target);
+ void Trace();
+
+private:
+ cmGeneratorTarget* GeneratorTarget;
+ cmMakefile* Makefile;
+ cmLocalGenerator* LocalGenerator;
+ cmGlobalGenerator const* GlobalGenerator;
+ using SourceEntry = cmGeneratorTarget::SourceEntry;
+ SourceEntry* CurrentEntry;
+ std::queue<cmSourceFile*> SourceQueue;
+ std::set<cmSourceFile*> SourcesQueued;
+ using NameMapType = std::map<std::string, cmSourcesWithOutput>;
+ NameMapType NameMap;
+ std::vector<std::string> NewSources;
+
+ void QueueSource(cmSourceFile* sf);
+ void FollowName(std::string const& name);
+ void FollowNames(std::vector<std::string> const& names);
+ bool IsUtility(std::string const& dep);
+ void CheckCustomCommand(cmCustomCommand const& cc);
+ void CheckCustomCommands(const std::vector<cmCustomCommand>& commands);
+};
+
+cmTargetTraceDependencies::cmTargetTraceDependencies(cmGeneratorTarget* target)
+ : GeneratorTarget(target)
+{
+ // Convenience.
+ this->Makefile = target->Target->GetMakefile();
+ this->LocalGenerator = target->GetLocalGenerator();
+ this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
+ this->CurrentEntry = nullptr;
+
+ // Queue all the source files already specified for the target.
+ std::set<cmSourceFile*> emitted;
+ std::vector<std::string> const& configs =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ for (std::string const& c : configs) {
+ std::vector<cmSourceFile*> sources;
+ this->GeneratorTarget->GetSourceFiles(sources, c);
+ for (cmSourceFile* sf : sources) {
+ const std::set<cmGeneratorTarget const*> tgts =
+ this->GlobalGenerator->GetFilenameTargetDepends(sf);
+ if (cm::contains(tgts, this->GeneratorTarget)) {
+ std::ostringstream e;
+ e << "Evaluation output file\n \"" << sf->ResolveFullPath()
+ << "\"\ndepends on the sources of a target it is used in. This "
+ "is a dependency loop and is not allowed.";
+ this->GeneratorTarget->LocalGenerator->IssueMessage(
+ MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+ if (emitted.insert(sf).second && this->SourcesQueued.insert(sf).second) {
+ this->SourceQueue.push(sf);
+ }
+ }
+ }
+
+ // Queue pre-build, pre-link, and post-build rule dependencies.
+ this->CheckCustomCommands(this->GeneratorTarget->GetPreBuildCommands());
+ this->CheckCustomCommands(this->GeneratorTarget->GetPreLinkCommands());
+ this->CheckCustomCommands(this->GeneratorTarget->GetPostBuildCommands());
+}
+
+void cmTargetTraceDependencies::Trace()
+{
+ // Process one dependency at a time until the queue is empty.
+ while (!this->SourceQueue.empty()) {
+ // Get the next source from the queue.
+ cmSourceFile* sf = this->SourceQueue.front();
+ this->SourceQueue.pop();
+ this->CurrentEntry = &this->GeneratorTarget->SourceDepends[sf];
+
+ // Queue dependencies added explicitly by the user.
+ if (cmProp additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) {
+ std::vector<std::string> objDeps = cmExpandedList(*additionalDeps);
+ for (std::string& objDep : objDeps) {
+ if (cmSystemTools::FileIsFullPath(objDep)) {
+ objDep = cmSystemTools::CollapseFullPath(objDep);
+ }
+ }
+ this->FollowNames(objDeps);
+ }
+
+ // Queue the source needed to generate this file, if any.
+ this->FollowName(sf->ResolveFullPath());
+
+ // Queue dependencies added programmatically by commands.
+ this->FollowNames(sf->GetDepends());
+
+ // Queue custom command dependencies.
+ if (cmCustomCommand const* cc = sf->GetCustomCommand()) {
+ this->CheckCustomCommand(*cc);
+ }
+ }
+ this->CurrentEntry = nullptr;
+
+ this->GeneratorTarget->AddTracedSources(this->NewSources);
+}
+
+void cmTargetTraceDependencies::QueueSource(cmSourceFile* sf)
+{
+ if (this->SourcesQueued.insert(sf).second) {
+ this->SourceQueue.push(sf);
+
+ // Make sure this file is in the target at the end.
+ this->NewSources.push_back(sf->ResolveFullPath());
+ }
+}
+
+void cmTargetTraceDependencies::FollowName(std::string const& name)
+{
+ // Use lower bound with key comparison to not repeat the search for the
+ // insert position if the name could not be found (which is the common case).
+ auto i = this->NameMap.lower_bound(name);
+ if (i == this->NameMap.end() || i->first != name) {
+ // Check if we know how to generate this file.
+ cmSourcesWithOutput sources =
+ this->LocalGenerator->GetSourcesWithOutput(name);
+ // If we failed to find a target or source and we have a relative path, it
+ // might be a valid source if made relative to the current binary
+ // directory.
+ if (!sources.Target && !sources.Source &&
+ !cmSystemTools::FileIsFullPath(name)) {
+ auto fullname =
+ cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', name);
+ fullname = cmSystemTools::CollapseFullPath(
+ fullname, this->Makefile->GetHomeOutputDirectory());
+ sources = this->LocalGenerator->GetSourcesWithOutput(fullname);
+ }
+ i = this->NameMap.emplace_hint(i, name, sources);
+ }
+ if (cmTarget* t = i->second.Target) {
+ // The name is a byproduct of a utility target or a PRE_BUILD, PRE_LINK, or
+ // POST_BUILD command.
+ this->GeneratorTarget->Target->AddUtility(t->GetName(), false);
+ }
+ if (cmSourceFile* sf = i->second.Source) {
+ // For now only follow the dependency if the source file is not a
+ // byproduct. Semantics of byproducts in a non-Ninja context will have to
+ // be defined first.
+ if (!i->second.SourceIsByproduct) {
+ // Record the dependency we just followed.
+ if (this->CurrentEntry) {
+ this->CurrentEntry->Depends.push_back(sf);
+ }
+ this->QueueSource(sf);
+ }
+ }
+}
+
+void cmTargetTraceDependencies::FollowNames(
+ std::vector<std::string> const& names)
+{
+ for (std::string const& name : names) {
+ this->FollowName(name);
+ }
+}
+
+bool cmTargetTraceDependencies::IsUtility(std::string const& dep)
+{
+ // Dependencies on targets (utilities) are supposed to be named by
+ // just the target name. However for compatibility we support
+ // naming the output file generated by the target (assuming there is
+ // no output-name property which old code would not have set). In
+ // that case the target name will be the file basename of the
+ // dependency.
+ std::string util = cmSystemTools::GetFilenameName(dep);
+ if (cmSystemTools::GetFilenameLastExtension(util) == ".exe") {
+ util = cmSystemTools::GetFilenameWithoutLastExtension(util);
+ }
+
+ // Check for a target with this name.
+ if (cmGeneratorTarget* t =
+ this->GeneratorTarget->GetLocalGenerator()->FindGeneratorTargetToUse(
+ util)) {
+ // If we find the target and the dep was given as a full path,
+ // then make sure it was not a full path to something else, and
+ // the fact that the name matched a target was just a coincidence.
+ if (cmSystemTools::FileIsFullPath(dep)) {
+ if (t->GetType() >= cmStateEnums::EXECUTABLE &&
+ t->GetType() <= cmStateEnums::MODULE_LIBRARY) {
+ // This is really only for compatibility so we do not need to
+ // worry about configuration names and output names.
+ std::string tLocation = t->GetLocationForBuild();
+ tLocation = cmSystemTools::GetFilenamePath(tLocation);
+ std::string depLocation = cmSystemTools::GetFilenamePath(dep);
+ depLocation = cmSystemTools::CollapseFullPath(depLocation);
+ tLocation = cmSystemTools::CollapseFullPath(tLocation);
+ if (depLocation == tLocation) {
+ this->GeneratorTarget->Target->AddUtility(util, false);
+ return true;
+ }
+ }
+ } else {
+ // The original name of the dependency was not a full path. It
+ // must name a target, so add the target-level dependency.
+ this->GeneratorTarget->Target->AddUtility(util, true);
+ return true;
+ }
+ }
+
+ // The dependency does not name a target built in this project.
+ return false;
+}
+
+void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc)
+{
+ // Collect dependencies referenced by all configurations.
+ std::set<std::string> depends;
+ for (std::string const& config :
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)) {
+ for (cmCustomCommandGenerator const& ccg :
+ this->LocalGenerator->MakeCustomCommandGenerators(cc, config)) {
+ // Collect target-level dependencies referenced in command lines.
+ for (auto const& util : ccg.GetUtilities()) {
+ this->GeneratorTarget->Target->AddUtility(util);
+ }
+
+ // Collect file-level dependencies referenced in DEPENDS.
+ depends.insert(ccg.GetDepends().begin(), ccg.GetDepends().end());
+ }
+ }
+
+ // Queue file-level dependencies.
+ for (std::string const& dep : depends) {
+ if (!this->IsUtility(dep)) {
+ // The dependency does not name a target and may be a file we
+ // know how to generate. Queue it.
+ this->FollowName(dep);
+ }
+ }
+}
+
+void cmTargetTraceDependencies::CheckCustomCommands(
+ const std::vector<cmCustomCommand>& commands)
+{
+ for (cmCustomCommand const& command : commands) {
+ this->CheckCustomCommand(command);
+ }
+}
+
+void cmGeneratorTarget::TraceDependencies()
+{
+ // CMake-generated targets have no dependencies to trace. Normally tracing
+ // would find nothing anyway, but when building CMake itself the "install"
+ // target command ends up referencing the "cmake" target but we do not
+ // really want the dependency because "install" depend on "all" anyway.
+ if (this->GetType() == cmStateEnums::GLOBAL_TARGET) {
+ return;
+ }
+
+ // Use a helper object to trace the dependencies.
+ cmTargetTraceDependencies tracer(this);
+ tracer.Trace();
+}
+
+std::string cmGeneratorTarget::GetCompilePDBDirectory(
+ const std::string& config) const
+{
+ if (CompileInfo const* info = this->GetCompileInfo(config)) {
+ return info->CompilePdbDir;
+ }
+ return "";
+}
+
+void cmGeneratorTarget::GetAppleArchs(const std::string& config,
+ std::vector<std::string>& archVec) const
+{
+ if (!this->Makefile->IsOn("APPLE")) {
+ return;
+ }
+ cmProp archs = nullptr;
+ if (!config.empty()) {
+ std::string defVarName =
+ cmStrCat("OSX_ARCHITECTURES_", cmSystemTools::UpperCase(config));
+ archs = this->GetProperty(defVarName);
+ }
+ if (!archs) {
+ archs = this->GetProperty("OSX_ARCHITECTURES");
+ }
+ if (archs) {
+ cmExpandList(*archs, archVec);
+ }
+ if (archVec.empty()) {
+ this->Makefile->GetDefExpandList("_CMAKE_APPLE_ARCHS_DEFAULT", archVec);
+ }
+}
+
+void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags,
+ cmSourceFile const& sf) const
+{
+ cmProp lang = sf.GetProperty("LANGUAGE");
+ if (!lang) {
+ return;
+ }
+
+ switch (this->GetPolicyStatusCMP0119()) {
+ case cmPolicies::WARN:
+ case cmPolicies::OLD:
+ // The OLD behavior is to not add explicit language flags.
+ return;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ // The NEW behavior is to add explicit language flags.
+ break;
+ }
+
+ this->LocalGenerator->AppendFeatureOptions(flags, *lang,
+ "EXPLICIT_LANGUAGE");
+}
+
+void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
+{
+ const std::string& property = this->GetSafeProperty("CUDA_ARCHITECTURES");
+
+ if (property.empty()) {
+ switch (this->GetPolicyStatusCMP0104()) {
+ case cmPolicies::WARN:
+ if (!this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile()) {
+ this->Makefile->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0104) +
+ "\nCUDA_ARCHITECTURES is empty for target \"" + this->GetName() +
+ "\".");
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ break;
+ default:
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "CUDA_ARCHITECTURES is empty for target \"" + this->GetName() +
+ "\".");
+ }
+ }
+
+ // If CUDA_ARCHITECTURES is false we don't add any architectures.
+ if (cmIsOff(property)) {
+ return;
+ }
+
+ struct CudaArchitecture
+ {
+ std::string name;
+ bool real{ true };
+ bool virtual_{ true };
+ };
+ std::vector<CudaArchitecture> architectures;
+
+ {
+ std::vector<std::string> options;
+ cmExpandList(property, options);
+
+ for (std::string& option : options) {
+ CudaArchitecture architecture;
+
+ // Architecture name is up to the first specifier.
+ std::size_t pos = option.find_first_of('-');
+ architecture.name = option.substr(0, pos);
+
+ if (pos != std::string::npos) {
+ cm::string_view specifier{ option.c_str() + pos + 1,
+ option.length() - pos - 1 };
+
+ if (specifier == "real") {
+ architecture.real = true;
+ architecture.virtual_ = false;
+ } else if (specifier == "virtual") {
+ architecture.real = false;
+ architecture.virtual_ = true;
+ } else {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Unknown CUDA architecture specifier \"" + std::string(specifier) +
+ "\".");
+ }
+ }
+
+ architectures.emplace_back(architecture);
+ }
+ }
+
+ std::string const& compiler =
+ this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
+
+ if (compiler == "NVIDIA") {
+ for (CudaArchitecture& architecture : architectures) {
+ flags +=
+ " --generate-code=arch=compute_" + architecture.name + ",code=[";
+
+ if (architecture.virtual_) {
+ flags += "compute_" + architecture.name;
+
+ if (architecture.real) {
+ flags += ",";
+ }
+ }
+
+ if (architecture.real) {
+ flags += "sm_" + architecture.name;
+ }
+
+ flags += "]";
+ }
+ } else if (compiler == "Clang") {
+ for (CudaArchitecture& architecture : architectures) {
+ flags += " --cuda-gpu-arch=sm_" + architecture.name;
+
+ if (!architecture.real) {
+ this->Makefile->IssueMessage(
+ MessageType::WARNING,
+ "Clang doesn't support disabling CUDA real code generation.");
+ }
+
+ if (!architecture.virtual_) {
+ flags += " --no-cuda-include-ptx=sm_" + architecture.name;
+ }
+ }
+ }
+}
+
+void cmGeneratorTarget::AddISPCTargetFlags(std::string& flags) const
+{
+ const std::string& property = this->GetSafeProperty("ISPC_INSTRUCTION_SETS");
+
+ // If ISPC_TARGET is false we don't add any architectures.
+ if (cmIsOff(property)) {
+ return;
+ }
+
+ std::string const& compiler =
+ this->Makefile->GetSafeDefinition("CMAKE_ISPC_COMPILER_ID");
+
+ if (compiler == "Intel") {
+ std::vector<std::string> targets;
+ cmExpandList(property, targets);
+ if (!targets.empty()) {
+ flags += cmStrCat(" --target=", cmWrap("", targets, "", ","));
+ }
+ }
+}
+
+void cmGeneratorTarget::AddCUDAToolkitFlags(std::string& flags) const
+{
+ std::string const& compiler =
+ this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
+
+ if (compiler == "Clang") {
+ // Pass CUDA toolkit explicitly to Clang.
+ // Clang's searching for the system CUDA toolkit isn't very good and it's
+ // expected the user will explicitly pass the toolkit path.
+ // This also avoids Clang having to search for the toolkit on every
+ // invocation.
+ std::string toolkitRoot =
+ this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_LIBRARY_ROOT");
+
+ if (!toolkitRoot.empty()) {
+ flags += " --cuda-path=" +
+ this->LocalGenerator->ConvertToOutputFormat(toolkitRoot,
+ cmOutputConverter::SHELL);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+std::string cmGeneratorTarget::GetFeatureSpecificLinkRuleVariable(
+ std::string const& var, std::string const& lang,
+ std::string const& config) const
+{
+ if (this->IsIPOEnabled(lang, config)) {
+ std::string varIPO = var + "_IPO";
+ if (this->Makefile->IsDefinitionSet(varIPO)) {
+ return varIPO;
+ }
+ }
+
+ return var;
+}
+
+//----------------------------------------------------------------------------
+std::string cmGeneratorTarget::GetCreateRuleVariable(
+ std::string const& lang, std::string const& config) const
+{
+ switch (this->GetType()) {
+ case cmStateEnums::STATIC_LIBRARY: {
+ std::string var = "CMAKE_" + lang + "_CREATE_STATIC_LIBRARY";
+ return this->GetFeatureSpecificLinkRuleVariable(var, lang, config);
+ }
+ case cmStateEnums::SHARED_LIBRARY:
+ return "CMAKE_" + lang + "_CREATE_SHARED_LIBRARY";
+ case cmStateEnums::MODULE_LIBRARY:
+ return "CMAKE_" + lang + "_CREATE_SHARED_MODULE";
+ case cmStateEnums::EXECUTABLE:
+ if (this->IsExecutableWithExports()) {
+ std::string linkExeWithExports =
+ "CMAKE_" + lang + "_LINK_EXECUTABLE_WITH_EXPORTS";
+ if (this->Makefile->IsDefinitionSet(linkExeWithExports)) {
+ return linkExeWithExports;
+ }
+ }
+ return "CMAKE_" + lang + "_LINK_EXECUTABLE";
+ default:
+ break;
+ }
+ return "";
+}
+
+namespace {
+void processIncludeDirectories(cmGeneratorTarget const* tgt,
+ EvaluatedTargetPropertyEntries& entries,
+ std::vector<BT<std::string>>& includes,
+ std::unordered_set<std::string>& uniqueIncludes,
+ bool debugIncludes)
+{
+ for (EvaluatedTargetPropertyEntry& entry : entries.Entries) {
+ cmLinkImplItem const& item = entry.LinkImplItem;
+ std::string const& targetName = item.AsStr();
+ bool const fromImported = item.Target && item.Target->IsImported();
+ bool const checkCMP0027 = item.FromGenex;
+
+ std::string usedIncludes;
+ for (std::string& entryInclude : entry.Values) {
+ if (fromImported && !cmSystemTools::FileExists(entryInclude)) {
+ std::ostringstream e;
+ MessageType messageType = MessageType::FATAL_ERROR;
+ if (checkCMP0027) {
+ switch (tgt->GetPolicyStatusCMP0027()) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0027) << "\n";
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ messageType = MessageType::AUTHOR_WARNING;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ break;
+ }
+ }
+ /* clang-format off */
+ e << "Imported target \"" << targetName << "\" includes "
+ "non-existent path\n \"" << entryInclude << "\"\nin its "
+ "INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:\n"
+ "* The path was deleted, renamed, or moved to another "
+ "location.\n"
+ "* An install or uninstall procedure did not complete "
+ "successfully.\n"
+ "* The installation package was faulty and references files it "
+ "does not provide.\n";
+ /* clang-format on */
+ tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
+ return;
+ }
+
+ if (!cmSystemTools::FileIsFullPath(entryInclude)) {
+ std::ostringstream e;
+ bool noMessage = false;
+ MessageType messageType = MessageType::FATAL_ERROR;
+ if (!targetName.empty()) {
+ /* clang-format off */
+ e << "Target \"" << targetName << "\" contains relative "
+ "path in its INTERFACE_INCLUDE_DIRECTORIES:\n"
+ " \"" << entryInclude << "\"";
+ /* clang-format on */
+ } else {
+ switch (tgt->GetPolicyStatusCMP0021()) {
+ case cmPolicies::WARN: {
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0021) << "\n";
+ messageType = MessageType::AUTHOR_WARNING;
+ } break;
+ case cmPolicies::OLD:
+ noMessage = true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Issue the fatal message.
+ break;
+ }
+ e << "Found relative path while evaluating include directories of "
+ "\""
+ << tgt->GetName() << "\":\n \"" << entryInclude << "\"\n";
+ }
+ if (!noMessage) {
+ tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
+ if (messageType == MessageType::FATAL_ERROR) {
+ return;
+ }
+ }
+ }
+
+ if (!cmIsOff(entryInclude)) {
+ cmSystemTools::ConvertToUnixSlashes(entryInclude);
+ }
+
+ if (uniqueIncludes.insert(entryInclude).second) {
+ includes.emplace_back(entryInclude, entry.Backtrace);
+ if (debugIncludes) {
+ usedIncludes += " * " + entryInclude + "\n";
+ }
+ }
+ }
+ if (!usedIncludes.empty()) {
+ tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
+ MessageType::LOG,
+ std::string("Used includes for target ") + tgt->GetName() + ":\n" +
+ usedIncludes,
+ entry.Backtrace);
+ }
+ }
+}
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
+ const std::string& config, const std::string& lang) const
+{
+ std::vector<BT<std::string>> includes;
+ std::unordered_set<std::string> uniqueIncludes;
+
+ cmGeneratorExpressionDAGChecker dagChecker(this, "INCLUDE_DIRECTORIES",
+ nullptr, nullptr);
+
+ std::vector<std::string> debugProperties;
+ this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
+ debugProperties);
+
+ bool debugIncludes = !this->DebugIncludesDone &&
+ cm::contains(debugProperties, "INCLUDE_DIRECTORIES");
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugIncludesDone = true;
+ }
+
+ EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
+ this, config, lang, &dagChecker, this->IncludeDirectoriesEntries);
+
+ if (lang == "Swift") {
+ AddLangSpecificImplicitIncludeDirectories(
+ this, lang, config, "Swift_MODULE_DIRECTORY",
+ IncludeDirectoryFallBack::BINARY, entries);
+ }
+
+ if (this->CanCompileSources() && (lang != "Swift" && lang != "Fortran")) {
+
+ const std::string propertyName = "ISPC_HEADER_DIRECTORY";
+
+ // If this target has ISPC sources make sure to add the header
+ // directory to other compilation units
+ if (cm::contains(this->GetAllConfigCompileLanguages(), "ISPC")) {
+ if (cmProp val = this->GetProperty(propertyName)) {
+ includes.emplace_back(*val);
+ } else {
+ includes.emplace_back(this->GetObjectDirectory(config));
+ }
+ }
+
+ AddLangSpecificImplicitIncludeDirectories(
+ this, "ISPC", config, propertyName, IncludeDirectoryFallBack::OBJECT,
+ entries);
+ }
+
+ AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES", lang,
+ &dagChecker, entries);
+
+ if (this->Makefile->IsOn("APPLE")) {
+ if (cmLinkImplementationLibraries const* impl =
+ this->GetLinkImplementationLibraries(config)) {
+ for (cmLinkImplItem const& lib : impl->Libraries) {
+ std::string libDir = cmSystemTools::CollapseFullPath(
+ lib.AsStr(), this->Makefile->GetHomeOutputDirectory());
+
+ static cmsys::RegularExpression frameworkCheck(
+ "(.*\\.framework)(/Versions/[^/]+)?/[^/]+$");
+ if (!frameworkCheck.find(libDir)) {
+ continue;
+ }
+
+ libDir = frameworkCheck.match(1);
+
+ EvaluatedTargetPropertyEntry ee(lib, cmListFileBacktrace());
+ ee.Values.emplace_back(std::move(libDir));
+ entries.Entries.emplace_back(std::move(ee));
+ }
+ }
+ }
+
+ processIncludeDirectories(this, entries, includes, uniqueIncludes,
+ debugIncludes);
+
+ return includes;
+}
+
+enum class OptionsParse
+{
+ None,
+ Shell
+};
+
+namespace {
+const auto DL_BEGIN = "<DEVICE_LINK>"_s;
+const auto DL_END = "</DEVICE_LINK>"_s;
+
+void processOptions(cmGeneratorTarget const* tgt,
+ EvaluatedTargetPropertyEntries const& entries,
+ std::vector<BT<std::string>>& options,
+ std::unordered_set<std::string>& uniqueOptions,
+ bool debugOptions, const char* logName, OptionsParse parse,
+ bool processDeviceOptions = false)
+{
+ bool splitOption = !processDeviceOptions;
+ for (EvaluatedTargetPropertyEntry const& entry : entries.Entries) {
+ std::string usedOptions;
+ for (std::string const& opt : entry.Values) {
+ if (processDeviceOptions && (opt == DL_BEGIN || opt == DL_END)) {
+ options.emplace_back(opt, entry.Backtrace);
+ splitOption = opt == DL_BEGIN;
+ continue;
+ }
+
+ if (uniqueOptions.insert(opt).second) {
+ if (parse == OptionsParse::Shell &&
+ cmHasLiteralPrefix(opt, "SHELL:")) {
+ if (splitOption) {
+ std::vector<std::string> tmp;
+ cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp);
+ for (std::string& o : tmp) {
+ options.emplace_back(std::move(o), entry.Backtrace);
+ }
+ } else {
+ options.emplace_back(std::string(opt.c_str() + 6),
+ entry.Backtrace);
+ }
+ } else {
+ options.emplace_back(opt, entry.Backtrace);
+ }
+ if (debugOptions) {
+ usedOptions += " * " + opt + "\n";
+ }
+ }
+ }
+ if (!usedOptions.empty()) {
+ tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
+ MessageType::LOG,
+ std::string("Used ") + logName + std::string(" for target ") +
+ tgt->GetName() + ":\n" + usedOptions,
+ entry.Backtrace);
+ }
+ }
+}
+
+std::vector<BT<std::string>> wrapOptions(
+ std::vector<std::string>& options, const cmListFileBacktrace& bt,
+ const std::vector<std::string>& wrapperFlag, const std::string& wrapperSep,
+ bool concatFlagAndArgs)
+{
+ std::vector<BT<std::string>> result;
+
+ if (options.empty()) {
+ return result;
+ }
+
+ if (wrapperFlag.empty()) {
+ // nothing specified, insert elements as is
+ result.reserve(options.size());
+ for (std::string& o : options) {
+ result.emplace_back(std::move(o), bt);
+ }
+ return result;
+ }
+
+ for (std::vector<std::string>::size_type index = 0; index < options.size();
+ index++) {
+ if (cmHasLiteralPrefix(options[index], "LINKER:")) {
+ // LINKER wrapper specified, insert elements as is
+ result.emplace_back(std::move(options[index]), bt);
+ continue;
+ }
+ if (cmHasLiteralPrefix(options[index], "-Wl,")) {
+ // replace option by LINKER wrapper
+ result.emplace_back(options[index].replace(0, 4, "LINKER:"), bt);
+ continue;
+ }
+ if (cmHasLiteralPrefix(options[index], "-Xlinker=")) {
+ // replace option by LINKER wrapper
+ result.emplace_back(options[index].replace(0, 9, "LINKER:"), bt);
+ continue;
+ }
+ if (options[index] == "-Xlinker") {
+ // replace option by LINKER wrapper
+ if (index + 1 < options.size()) {
+ result.emplace_back("LINKER:" + options[++index], bt);
+ } else {
+ result.emplace_back(std::move(options[index]), bt);
+ }
+ continue;
+ }
+
+ // collect all options which must be transformed
+ std::vector<std::string> opts;
+ while (index < options.size()) {
+ if (!cmHasLiteralPrefix(options[index], "LINKER:") &&
+ !cmHasLiteralPrefix(options[index], "-Wl,") &&
+ !cmHasLiteralPrefix(options[index], "-Xlinker")) {
+ opts.emplace_back(std::move(options[index++]));
+ } else {
+ --index;
+ break;
+ }
+ }
+ if (opts.empty()) {
+ continue;
+ }
+
+ if (!wrapperSep.empty()) {
+ if (concatFlagAndArgs) {
+ // insert flag elements except last one
+ for (auto i = wrapperFlag.begin(); i != wrapperFlag.end() - 1; ++i) {
+ result.emplace_back(*i, bt);
+ }
+ // concatenate last flag element and all list values
+ // in one option
+ result.emplace_back(wrapperFlag.back() + cmJoin(opts, wrapperSep), bt);
+ } else {
+ for (std::string const& i : wrapperFlag) {
+ result.emplace_back(i, bt);
+ }
+ // concatenate all list values in one option
+ result.emplace_back(cmJoin(opts, wrapperSep), bt);
+ }
+ } else {
+ // prefix each element of list with wrapper
+ if (concatFlagAndArgs) {
+ std::transform(opts.begin(), opts.end(), opts.begin(),
+ [&wrapperFlag](std::string const& o) -> std::string {
+ return wrapperFlag.back() + o;
+ });
+ }
+ for (std::string& o : opts) {
+ for (auto i = wrapperFlag.begin(),
+ e = concatFlagAndArgs ? wrapperFlag.end() - 1
+ : wrapperFlag.end();
+ i != e; ++i) {
+ result.emplace_back(*i, bt);
+ }
+ result.emplace_back(std::move(o), bt);
+ }
+ }
+ }
+ return result;
+}
+}
+
+void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const
+{
+ std::vector<BT<std::string>> tmp = this->GetCompileOptions(config, language);
+ result.reserve(tmp.size());
+ for (BT<std::string>& v : tmp) {
+ result.emplace_back(std::move(v.Value));
+ }
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions(
+ std::string const& config, std::string const& language) const
+{
+ std::vector<BT<std::string>> result;
+ std::unordered_set<std::string> uniqueOptions;
+
+ cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_OPTIONS", nullptr,
+ nullptr);
+
+ std::vector<std::string> debugProperties;
+ this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
+ debugProperties);
+
+ bool debugOptions = !this->DebugCompileOptionsDone &&
+ cm::contains(debugProperties, "COMPILE_OPTIONS");
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugCompileOptionsDone = true;
+ }
+
+ EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
+ this, config, language, &dagChecker, this->CompileOptionsEntries);
+
+ AddInterfaceEntries(this, config, "INTERFACE_COMPILE_OPTIONS", language,
+ &dagChecker, entries);
+
+ processOptions(this, entries, result, uniqueOptions, debugOptions,
+ "compile options", OptionsParse::Shell);
+
+ return result;
+}
+
+void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result,
+ const std::string& config) const
+{
+ std::vector<BT<std::string>> tmp = this->GetCompileFeatures(config);
+ result.reserve(tmp.size());
+ for (BT<std::string>& v : tmp) {
+ result.emplace_back(std::move(v.Value));
+ }
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures(
+ std::string const& config) const
+{
+ std::vector<BT<std::string>> result;
+ std::unordered_set<std::string> uniqueFeatures;
+
+ cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_FEATURES", nullptr,
+ nullptr);
+
+ std::vector<std::string> debugProperties;
+ this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
+ debugProperties);
+
+ bool debugFeatures = !this->DebugCompileFeaturesDone &&
+ cm::contains(debugProperties, "COMPILE_FEATURES");
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugCompileFeaturesDone = true;
+ }
+
+ EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
+ this, config, std::string(), &dagChecker, this->CompileFeaturesEntries);
+
+ AddInterfaceEntries(this, config, "INTERFACE_COMPILE_FEATURES",
+ std::string(), &dagChecker, entries);
+
+ processOptions(this, entries, result, uniqueFeatures, debugFeatures,
+ "compile features", OptionsParse::None);
+
+ return result;
+}
+
+void cmGeneratorTarget::GetCompileDefinitions(
+ std::vector<std::string>& result, const std::string& config,
+ const std::string& language) const
+{
+ std::vector<BT<std::string>> tmp =
+ this->GetCompileDefinitions(config, language);
+ result.reserve(tmp.size());
+ for (BT<std::string>& v : tmp) {
+ result.emplace_back(std::move(v.Value));
+ }
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions(
+ std::string const& config, std::string const& language) const
+{
+ std::vector<BT<std::string>> list;
+ std::unordered_set<std::string> uniqueOptions;
+
+ cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_DEFINITIONS",
+ nullptr, nullptr);
+
+ std::vector<std::string> debugProperties;
+ this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
+ debugProperties);
+
+ bool debugDefines = !this->DebugCompileDefinitionsDone &&
+ cm::contains(debugProperties, "COMPILE_DEFINITIONS");
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugCompileDefinitionsDone = true;
+ }
+
+ EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
+ this, config, language, &dagChecker, this->CompileDefinitionsEntries);
+
+ AddInterfaceEntries(this, config, "INTERFACE_COMPILE_DEFINITIONS", language,
+ &dagChecker, entries);
+
+ if (!config.empty()) {
+ std::string configPropName =
+ "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config);
+ cmProp configProp = this->GetProperty(configPropName);
+ if (configProp) {
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0043)) {
+ case cmPolicies::WARN: {
+ this->LocalGenerator->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0043));
+ CM_FALLTHROUGH;
+ }
+ case cmPolicies::OLD: {
+ std::unique_ptr<TargetPropertyEntry> entry =
+ CreateTargetPropertyEntry(*configProp);
+ entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
+ this, config, language, &dagChecker, *entry));
+ } break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ break;
+ }
+ }
+ }
+
+ processOptions(this, entries, list, uniqueOptions, debugDefines,
+ "compile definitions", OptionsParse::None);
+
+ return list;
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders(
+ const std::string& config, const std::string& language) const
+{
+ std::unordered_set<std::string> uniqueOptions;
+
+ cmGeneratorExpressionDAGChecker dagChecker(this, "PRECOMPILE_HEADERS",
+ nullptr, nullptr);
+
+ std::vector<std::string> debugProperties;
+ this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
+ debugProperties);
+
+ bool debugDefines = !this->DebugPrecompileHeadersDone &&
+ std::find(debugProperties.begin(), debugProperties.end(),
+ "PRECOMPILE_HEADERS") != debugProperties.end();
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugPrecompileHeadersDone = true;
+ }
+
+ EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
+ this, config, language, &dagChecker, this->PrecompileHeadersEntries);
+
+ AddInterfaceEntries(this, config, "INTERFACE_PRECOMPILE_HEADERS", language,
+ &dagChecker, entries);
+
+ std::vector<BT<std::string>> list;
+ processOptions(this, entries, list, uniqueOptions, debugDefines,
+ "precompile headers", OptionsParse::None);
+
+ return list;
+}
+
+std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
+ const std::string& language,
+ const std::string& arch) const
+{
+ if (language != "C" && language != "CXX" && language != "OBJC" &&
+ language != "OBJCXX") {
+ return std::string();
+ }
+
+ if (this->GetPropertyAsBool("DISABLE_PRECOMPILE_HEADERS")) {
+ return std::string();
+ }
+ const cmGeneratorTarget* generatorTarget = this;
+ cmProp pchReuseFrom =
+ generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
+
+ const auto inserted =
+ this->PchHeaders.insert(std::make_pair(language + config + arch, ""));
+ if (inserted.second) {
+ const std::vector<BT<std::string>> headers =
+ this->GetPrecompileHeaders(config, language);
+ if (headers.empty() && !pchReuseFrom) {
+ return std::string();
+ }
+ std::string& filename = inserted.first->second;
+
+ if (pchReuseFrom) {
+ generatorTarget =
+ this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
+ }
+
+ filename = cmStrCat(
+ generatorTarget->LocalGenerator->GetCurrentBinaryDirectory(), "/");
+
+ const std::map<std::string, std::string> languageToExtension = {
+ { "C", ".h" },
+ { "CXX", ".hxx" },
+ { "OBJC", ".objc.h" },
+ { "OBJCXX", ".objcxx.hxx" }
+ };
+
+ filename =
+ cmStrCat(filename, "CMakeFiles/", generatorTarget->GetName(), ".dir");
+
+ if (this->GetGlobalGenerator()->IsMultiConfig()) {
+ filename = cmStrCat(filename, "/", config);
+ }
+
+ filename =
+ cmStrCat(filename, "/cmake_pch", arch.empty() ? "" : cmStrCat("_", arch),
+ languageToExtension.at(language));
+
+ const std::string filename_tmp = cmStrCat(filename, ".tmp");
+ if (!pchReuseFrom) {
+ cmProp pchPrologue = this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE");
+ cmProp pchEpilogue = this->Makefile->GetDefinition("CMAKE_PCH_EPILOGUE");
+
+ std::string firstHeaderOnDisk;
+ {
+ cmGeneratedFileStream file(
+ filename_tmp, false,
+ this->GetGlobalGenerator()->GetMakefileEncoding());
+ file << "/* generated by CMake */\n\n";
+ if (pchPrologue) {
+ file << *pchPrologue << "\n";
+ }
+ if (this->GetGlobalGenerator()->IsXcode()) {
+ file << "#ifndef CMAKE_SKIP_PRECOMPILE_HEADERS\n";
+ }
+ if (language == "CXX") {
+ file << "#ifdef __cplusplus\n";
+ }
+ for (auto const& header_bt : headers) {
+ if (header_bt.Value.empty()) {
+ continue;
+ }
+ if (header_bt.Value[0] == '<' || header_bt.Value[0] == '\"') {
+ file << "#include " << header_bt.Value << "\n";
+ } else {
+ file << "#include \"" << header_bt.Value << "\"\n";
+ }
+
+ if (cmSystemTools::FileExists(header_bt.Value) &&
+ firstHeaderOnDisk.empty()) {
+ firstHeaderOnDisk = header_bt.Value;
+ }
+ }
+ if (language == "CXX") {
+ file << "#endif // __cplusplus\n";
+ }
+ if (this->GetGlobalGenerator()->IsXcode()) {
+ file << "#endif // CMAKE_SKIP_PRECOMPILE_HEADERS\n";
+ }
+ if (pchEpilogue) {
+ file << *pchEpilogue << "\n";
+ }
+ }
+
+ if (!firstHeaderOnDisk.empty()) {
+ cmFileTimes::Copy(firstHeaderOnDisk, filename_tmp);
+ }
+
+ cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
+ }
+ }
+ return inserted.first->second;
+}
+
+std::string cmGeneratorTarget::GetPchSource(const std::string& config,
+ const std::string& language,
+ const std::string& arch) const
+{
+ if (language != "C" && language != "CXX" && language != "OBJC" &&
+ language != "OBJCXX") {
+ return std::string();
+ }
+ const auto inserted =
+ this->PchSources.insert(std::make_pair(language + config + arch, ""));
+ if (inserted.second) {
+ const std::string pchHeader = this->GetPchHeader(config, language, arch);
+ if (pchHeader.empty()) {
+ return std::string();
+ }
+ std::string& filename = inserted.first->second;
+
+ const cmGeneratorTarget* generatorTarget = this;
+ cmProp pchReuseFrom =
+ generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
+ if (pchReuseFrom) {
+ generatorTarget =
+ this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
+ }
+
+ filename =
+ cmStrCat(generatorTarget->LocalGenerator->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/", generatorTarget->GetName(), ".dir/cmake_pch");
+
+ // For GCC the source extension will be transformed into .h[xx].gch
+ if (!this->Makefile->IsOn("CMAKE_LINK_PCH")) {
+ const std::map<std::string, std::string> languageToExtension = {
+ { "C", ".h.c" },
+ { "CXX", ".hxx.cxx" },
+ { "OBJC", ".objc.h.m" },
+ { "OBJCXX", ".objcxx.hxx.mm" }
+ };
+
+ filename = cmStrCat(filename, arch.empty() ? "" : cmStrCat("_", arch),
+ languageToExtension.at(language));
+ } else {
+ const std::map<std::string, std::string> languageToExtension = {
+ { "C", ".c" }, { "CXX", ".cxx" }, { "OBJC", ".m" }, { "OBJCXX", ".mm" }
+ };
+
+ filename = cmStrCat(filename, arch.empty() ? "" : cmStrCat("_", arch),
+ languageToExtension.at(language));
+ }
+
+ const std::string filename_tmp = cmStrCat(filename, ".tmp");
+ if (!pchReuseFrom) {
+ {
+ cmGeneratedFileStream file(filename_tmp);
+ file << "/* generated by CMake */\n";
+ }
+ cmFileTimes::Copy(pchHeader, filename_tmp);
+ cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
+ }
+ }
+ return inserted.first->second;
+}
+
+std::string cmGeneratorTarget::GetPchFileObject(const std::string& config,
+ const std::string& language,
+ const std::string& arch)
+{
+ if (language != "C" && language != "CXX" && language != "OBJC" &&
+ language != "OBJCXX") {
+ return std::string();
+ }
+ const auto inserted =
+ this->PchObjectFiles.insert(std::make_pair(language + config + arch, ""));
+ if (inserted.second) {
+ const std::string pchSource = this->GetPchSource(config, language, arch);
+ if (pchSource.empty()) {
+ return std::string();
+ }
+ std::string& filename = inserted.first->second;
+
+ auto* pchSf = this->Makefile->GetOrCreateSource(
+ pchSource, false, cmSourceFileLocationKind::Known);
+
+ filename = cmStrCat(this->ObjectDirectory, this->GetObjectName(pchSf));
+ if (this->GetGlobalGenerator()->IsMultiConfig()) {
+ cmSystemTools::ReplaceString(
+ filename, this->GetGlobalGenerator()->GetCMakeCFGIntDir(), config);
+ }
+ }
+ return inserted.first->second;
+}
+
+std::string cmGeneratorTarget::GetPchFile(const std::string& config,
+ const std::string& language,
+ const std::string& arch)
+{
+ const auto inserted =
+ this->PchFiles.insert(std::make_pair(language + config + arch, ""));
+ if (inserted.second) {
+ std::string& pchFile = inserted.first->second;
+
+ const std::string pchExtension =
+ this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
+
+ if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
+ auto replaceExtension = [](const std::string& str,
+ const std::string& ext) -> std::string {
+ auto dot_pos = str.rfind('.');
+ std::string result;
+ if (dot_pos != std::string::npos) {
+ result = str.substr(0, dot_pos);
+ }
+ result += ext;
+ return result;
+ };
+
+ cmGeneratorTarget* generatorTarget = this;
+ cmProp pchReuseFrom =
+ generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
+ if (pchReuseFrom) {
+ generatorTarget =
+ this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
+ }
+
+ const std::string pchFileObject =
+ generatorTarget->GetPchFileObject(config, language, arch);
+ if (!pchExtension.empty()) {
+ pchFile = replaceExtension(pchFileObject, pchExtension);
+ }
+ } else {
+ pchFile = this->GetPchHeader(config, language, arch);
+ pchFile += pchExtension;
+ }
+ }
+ return inserted.first->second;
+}
+
+std::string cmGeneratorTarget::GetPchCreateCompileOptions(
+ const std::string& config, const std::string& language,
+ const std::string& arch)
+{
+ const auto inserted = this->PchCreateCompileOptions.insert(
+ std::make_pair(language + config + arch, ""));
+ if (inserted.second) {
+ std::string& createOptionList = inserted.first->second;
+
+ if (this->GetPropertyAsBool("PCH_WARN_INVALID")) {
+ createOptionList = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH"));
+ }
+
+ if (this->GetPropertyAsBool("PCH_INSTANTIATE_TEMPLATES")) {
+ std::string varName = cmStrCat(
+ "CMAKE_", language, "_COMPILE_OPTIONS_INSTANTIATE_TEMPLATES_PCH");
+ std::string instantiateOption =
+ this->Makefile->GetSafeDefinition(varName);
+ if (!instantiateOption.empty()) {
+ createOptionList = cmStrCat(createOptionList, ";", instantiateOption);
+ }
+ }
+
+ const std::string createOptVar =
+ cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_CREATE_PCH");
+
+ createOptionList = cmStrCat(
+ createOptionList, ";", this->Makefile->GetSafeDefinition(createOptVar));
+
+ const std::string pchHeader = this->GetPchHeader(config, language, arch);
+ const std::string pchFile = this->GetPchFile(config, language, arch);
+
+ cmSystemTools::ReplaceString(createOptionList, "<PCH_HEADER>", pchHeader);
+ cmSystemTools::ReplaceString(createOptionList, "<PCH_FILE>", pchFile);
+ }
+ return inserted.first->second;
+}
+
+std::string cmGeneratorTarget::GetPchUseCompileOptions(
+ const std::string& config, const std::string& language,
+ const std::string& arch)
+{
+ const auto inserted = this->PchUseCompileOptions.insert(
+ std::make_pair(language + config + arch, ""));
+ if (inserted.second) {
+ std::string& useOptionList = inserted.first->second;
+
+ if (this->GetPropertyAsBool("PCH_WARN_INVALID")) {
+ useOptionList = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH"));
+ }
+
+ const std::string useOptVar =
+ cmStrCat(language, "_COMPILE_OPTIONS_USE_PCH");
+
+ std::string const& useOptionListProperty =
+ this->GetSafeProperty(useOptVar);
+
+ useOptionList = cmStrCat(
+ useOptionList, ";",
+ useOptionListProperty.empty()
+ ? this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_", useOptVar))
+ : useOptionListProperty);
+
+ const std::string pchHeader = this->GetPchHeader(config, language, arch);
+ const std::string pchFile = this->GetPchFile(config, language, arch);
+
+ cmSystemTools::ReplaceString(useOptionList, "<PCH_HEADER>", pchHeader);
+ cmSystemTools::ReplaceString(useOptionList, "<PCH_FILE>", pchFile);
+ }
+ return inserted.first->second;
+}
+
+void cmGeneratorTarget::AddSourceFileToUnityBatch(
+ const std::string& sourceFilename)
+{
+ this->UnityBatchedSourceFiles.insert(sourceFilename);
+}
+
+bool cmGeneratorTarget::IsSourceFilePartOfUnityBatch(
+ const std::string& sourceFilename) const
+{
+ if (!this->GetPropertyAsBool("UNITY_BUILD")) {
+ return false;
+ }
+
+ return this->UnityBatchedSourceFiles.find(sourceFilename) !=
+ this->UnityBatchedSourceFiles.end();
+}
+
+void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const
+{
+ if (this->IsDeviceLink() &&
+ this->GetPolicyStatusCMP0105() != cmPolicies::NEW) {
+ // link options are not propagated to the device link step
+ return;
+ }
+
+ std::vector<BT<std::string>> tmp = this->GetLinkOptions(config, language);
+ result.reserve(tmp.size());
+ for (BT<std::string>& v : tmp) {
+ result.emplace_back(std::move(v.Value));
+ }
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
+ std::string const& config, std::string const& language) const
+{
+ std::vector<BT<std::string>> result;
+ std::unordered_set<std::string> uniqueOptions;
+
+ cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_OPTIONS", nullptr,
+ nullptr);
+
+ std::vector<std::string> debugProperties;
+ this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
+ debugProperties);
+
+ bool debugOptions = !this->DebugLinkOptionsDone &&
+ cm::contains(debugProperties, "LINK_OPTIONS");
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugLinkOptionsDone = true;
+ }
+
+ EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
+ this, config, language, &dagChecker, this->LinkOptionsEntries);
+
+ AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS", language,
+ &dagChecker, entries,
+ this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
+
+ processOptions(this, entries, result, uniqueOptions, debugOptions,
+ "link options", OptionsParse::Shell, this->IsDeviceLink());
+
+ if (this->IsDeviceLink()) {
+ // wrap host link options
+ const std::string wrapper(this->Makefile->GetSafeDefinition(
+ "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG"));
+ std::vector<std::string> wrapperFlag = cmExpandedList(wrapper);
+ const std::string wrapperSep(this->Makefile->GetSafeDefinition(
+ "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG_SEP"));
+ bool concatFlagAndArgs = true;
+ if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
+ concatFlagAndArgs = false;
+ wrapperFlag.pop_back();
+ }
+
+ auto it = result.begin();
+ while (it != result.end()) {
+ if (it->Value == DL_BEGIN) {
+ // device link options, no treatment
+ it = result.erase(it);
+ it = std::find_if(it, result.end(), [](const BT<std::string>& item) {
+ return item.Value == DL_END;
+ });
+ if (it != result.end()) {
+ it = result.erase(it);
+ }
+ } else {
+ // host link options must be wrapped
+ std::vector<std::string> options;
+ cmSystemTools::ParseUnixCommandLine(it->Value.c_str(), options);
+ auto hostOptions = wrapOptions(options, it->Backtrace, wrapperFlag,
+ wrapperSep, concatFlagAndArgs);
+ it = result.erase(it);
+ // some compilers (like gcc 4.8 or Intel 19.0 or XLC 16) do not respect
+ // C++11 standard: 'std::vector::insert()' do not returns an iterator,
+ // so need to recompute the iterator after insertion.
+ if (it == result.end()) {
+ cm::append(result, hostOptions);
+ it = result.end();
+ } else {
+ auto index = it - result.begin();
+ result.insert(it, hostOptions.begin(), hostOptions.end());
+ it = result.begin() + index + hostOptions.size();
+ }
+ }
+ }
+ }
+
+ // Last step: replace "LINKER:" prefixed elements by
+ // actual linker wrapper
+ const std::string wrapper(this->Makefile->GetSafeDefinition(
+ "CMAKE_" + language +
+ (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG"
+ : "_LINKER_WRAPPER_FLAG")));
+ std::vector<std::string> wrapperFlag = cmExpandedList(wrapper);
+ const std::string wrapperSep(this->Makefile->GetSafeDefinition(
+ "CMAKE_" + language +
+ (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG_SEP"
+ : "_LINKER_WRAPPER_FLAG_SEP")));
+ bool concatFlagAndArgs = true;
+ if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
+ concatFlagAndArgs = false;
+ wrapperFlag.pop_back();
+ }
+
+ const std::string LINKER{ "LINKER:" };
+ const std::string SHELL{ "SHELL:" };
+ const std::string LINKER_SHELL = LINKER + SHELL;
+
+ std::vector<BT<std::string>>::iterator entry;
+ while ((entry = std::find_if(result.begin(), result.end(),
+ [&LINKER](BT<std::string> const& item) -> bool {
+ return item.Value.compare(0, LINKER.length(),
+ LINKER) == 0;
+ })) != result.end()) {
+ std::string value = std::move(entry->Value);
+ cmListFileBacktrace bt = std::move(entry->Backtrace);
+ entry = result.erase(entry);
+
+ std::vector<std::string> linkerOptions;
+ if (value.compare(0, LINKER_SHELL.length(), LINKER_SHELL) == 0) {
+ cmSystemTools::ParseUnixCommandLine(
+ value.c_str() + LINKER_SHELL.length(), linkerOptions);
+ } else {
+ linkerOptions = cmTokenize(value.substr(LINKER.length()), ",");
+ }
+
+ if (linkerOptions.empty() ||
+ (linkerOptions.size() == 1 && linkerOptions.front().empty())) {
+ continue;
+ }
+
+ // for now, raise an error if prefix SHELL: is part of arguments
+ if (std::find_if(linkerOptions.begin(), linkerOptions.end(),
+ [&SHELL](const std::string& item) -> bool {
+ return item.find(SHELL) != std::string::npos;
+ }) != linkerOptions.end()) {
+ this->LocalGenerator->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "'SHELL:' prefix is not supported as part of 'LINKER:' arguments.",
+ this->GetBacktrace());
+ return result;
+ }
+
+ std::vector<BT<std::string>> options = wrapOptions(
+ linkerOptions, bt, wrapperFlag, wrapperSep, concatFlagAndArgs);
+ result.insert(entry, options.begin(), options.end());
+ }
+ return result;
+}
+
+void cmGeneratorTarget::GetStaticLibraryLinkOptions(
+ std::vector<std::string>& result, const std::string& config,
+ const std::string& language) const
+{
+ std::vector<BT<std::string>> tmp =
+ this->GetStaticLibraryLinkOptions(config, language);
+ result.reserve(tmp.size());
+ for (BT<std::string>& v : tmp) {
+ result.emplace_back(std::move(v.Value));
+ }
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions(
+ std::string const& config, std::string const& language) const
+{
+ std::vector<BT<std::string>> result;
+ std::unordered_set<std::string> uniqueOptions;
+
+ cmGeneratorExpressionDAGChecker dagChecker(this, "STATIC_LIBRARY_OPTIONS",
+ nullptr, nullptr);
+
+ EvaluatedTargetPropertyEntries entries;
+ if (cmProp linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
+ std::vector<std::string> options = cmExpandedList(*linkOptions);
+ for (const auto& option : options) {
+ std::unique_ptr<TargetPropertyEntry> entry =
+ CreateTargetPropertyEntry(option);
+ entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
+ this, config, language, &dagChecker, *entry));
+ }
+ }
+ processOptions(this, entries, result, uniqueOptions, false,
+ "static library link options", OptionsParse::Shell);
+
+ return result;
+}
+
+namespace {
+void processLinkDirectories(cmGeneratorTarget const* tgt,
+ EvaluatedTargetPropertyEntries& entries,
+ std::vector<BT<std::string>>& directories,
+ std::unordered_set<std::string>& uniqueDirectories,
+ bool debugDirectories)
+{
+ for (EvaluatedTargetPropertyEntry& entry : entries.Entries) {
+ cmLinkImplItem const& item = entry.LinkImplItem;
+ std::string const& targetName = item.AsStr();
+
+ std::string usedDirectories;
+ for (std::string& entryDirectory : entry.Values) {
+ if (!cmSystemTools::FileIsFullPath(entryDirectory)) {
+ std::ostringstream e;
+ bool noMessage = false;
+ MessageType messageType = MessageType::FATAL_ERROR;
+ if (!targetName.empty()) {
+ /* clang-format off */
+ e << "Target \"" << targetName << "\" contains relative "
+ "path in its INTERFACE_LINK_DIRECTORIES:\n"
+ " \"" << entryDirectory << "\"";
+ /* clang-format on */
+ } else {
+ switch (tgt->GetPolicyStatusCMP0081()) {
+ case cmPolicies::WARN: {
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0081) << "\n";
+ messageType = MessageType::AUTHOR_WARNING;
+ } break;
+ case cmPolicies::OLD:
+ noMessage = true;
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Issue the fatal message.
+ break;
+ }
+ e << "Found relative path while evaluating link directories of "
+ "\""
+ << tgt->GetName() << "\":\n \"" << entryDirectory << "\"\n";
+ }
+ if (!noMessage) {
+ tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
+ if (messageType == MessageType::FATAL_ERROR) {
+ return;
+ }
+ }
+ }
+
+ // Sanitize the path the same way the link_directories command does
+ // in case projects set the LINK_DIRECTORIES property directly.
+ cmSystemTools::ConvertToUnixSlashes(entryDirectory);
+ if (uniqueDirectories.insert(entryDirectory).second) {
+ directories.emplace_back(entryDirectory, entry.Backtrace);
+ if (debugDirectories) {
+ usedDirectories += " * " + entryDirectory + "\n";
+ }
+ }
+ }
+ if (!usedDirectories.empty()) {
+ tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
+ MessageType::LOG,
+ std::string("Used link directories for target ") + tgt->GetName() +
+ ":\n" + usedDirectories,
+ entry.Backtrace);
+ }
+ }
+}
+}
+
+void cmGeneratorTarget::GetLinkDirectories(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const
+{
+ std::vector<BT<std::string>> tmp =
+ this->GetLinkDirectories(config, language);
+ result.reserve(tmp.size());
+ for (BT<std::string>& v : tmp) {
+ result.emplace_back(std::move(v.Value));
+ }
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories(
+ std::string const& config, std::string const& language) const
+{
+ std::vector<BT<std::string>> result;
+ std::unordered_set<std::string> uniqueDirectories;
+
+ cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DIRECTORIES", nullptr,
+ nullptr);
+
+ std::vector<std::string> debugProperties;
+ this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES",
+ debugProperties);
+
+ bool debugDirectories = !this->DebugLinkDirectoriesDone &&
+ cm::contains(debugProperties, "LINK_DIRECTORIES");
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugLinkDirectoriesDone = true;
+ }
+
+ EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
+ this, config, language, &dagChecker, this->LinkDirectoriesEntries);
+
+ AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", language,
+ &dagChecker, entries,
+ this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
+
+ processLinkDirectories(this, entries, result, uniqueDirectories,
+ debugDirectories);
+
+ return result;
+}
+
+void cmGeneratorTarget::GetLinkDepends(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const
+{
+ std::vector<BT<std::string>> tmp = this->GetLinkDepends(config, language);
+ result.reserve(tmp.size());
+ for (BT<std::string>& v : tmp) {
+ result.emplace_back(std::move(v.Value));
+ }
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends(
+ std::string const& config, std::string const& language) const
+{
+ std::vector<BT<std::string>> result;
+ std::unordered_set<std::string> uniqueOptions;
+ cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DEPENDS", nullptr,
+ nullptr);
+
+ EvaluatedTargetPropertyEntries entries;
+ if (cmProp linkDepends = this->GetProperty("LINK_DEPENDS")) {
+ std::vector<std::string> depends = cmExpandedList(*linkDepends);
+ for (const auto& depend : depends) {
+ std::unique_ptr<TargetPropertyEntry> entry =
+ CreateTargetPropertyEntry(depend);
+ entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
+ this, config, language, &dagChecker, *entry));
+ }
+ }
+ AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", language,
+ &dagChecker, entries,
+ this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
+
+ processOptions(this, entries, result, uniqueOptions, false, "link depends",
+ OptionsParse::None);
+
+ return result;
+}
+
+void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
+{
+ if (this->IsImported()) {
+ return;
+ }
+ cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator();
+
+ // Get the names.
+ cmGeneratorTarget::Names targetNames;
+ if (this->GetType() == cmStateEnums::EXECUTABLE) {
+ targetNames = this->GetExecutableNames(config);
+ } else if (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ targetNames = this->GetLibraryNames(config);
+ } else {
+ return;
+ }
+
+ // Get the directory.
+ std::string dir =
+ this->GetDirectory(config, cmStateEnums::RuntimeBinaryArtifact);
+
+ // Add each name.
+ std::string f;
+ if (!targetNames.Output.empty()) {
+ f = cmStrCat(dir, '/', targetNames.Output);
+ gg->AddToManifest(f);
+ }
+ if (!targetNames.SharedObject.empty()) {
+ f = cmStrCat(dir, '/', targetNames.SharedObject);
+ gg->AddToManifest(f);
+ }
+ if (!targetNames.Real.empty()) {
+ f = cmStrCat(dir, '/', targetNames.Real);
+ gg->AddToManifest(f);
+ }
+ if (!targetNames.PDB.empty()) {
+ f = cmStrCat(dir, '/', targetNames.PDB);
+ gg->AddToManifest(f);
+ }
+ if (!targetNames.ImportLibrary.empty()) {
+ f =
+ cmStrCat(this->GetDirectory(config, cmStateEnums::ImportLibraryArtifact),
+ '/', targetNames.ImportLibrary);
+ gg->AddToManifest(f);
+ }
+}
+
+bool cmGeneratorTarget::ComputeCompileFeatures(std::string const& config) const
+{
+ // Compute the language standard based on the compile features.
+ cmStandardLevelResolver standardResolver(this->Makefile);
+ std::vector<BT<std::string>> features = this->GetCompileFeatures(config);
+ for (BT<std::string> const& f : features) {
+ std::string lang;
+ if (!standardResolver.CompileFeatureKnown(this->Target->GetName(), f.Value,
+ lang, nullptr)) {
+ return false;
+ }
+
+ std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang);
+ cmProp currentLanguageStandard = this->GetLanguageStandard(lang, config);
+
+ std::string newRequiredStandard;
+ if (!standardResolver.GetNewRequiredStandard(
+ this->Target->GetName(), f.Value, currentLanguageStandard,
+ newRequiredStandard)) {
+ return false;
+ }
+
+ if (!newRequiredStandard.empty()) {
+ BTs<std::string>& languageStandardProperty =
+ this->LanguageStandardMap[key];
+ if (languageStandardProperty.Value != newRequiredStandard) {
+ languageStandardProperty.Value = newRequiredStandard;
+ languageStandardProperty.Backtraces.clear();
+ }
+ languageStandardProperty.Backtraces.emplace_back(f.Backtrace);
+ }
+ }
+
+ return true;
+}
+
+bool cmGeneratorTarget::ComputeCompileFeatures(
+ std::string const& config, std::set<LanguagePair> const& languagePairs) const
+{
+ for (const auto& language : languagePairs) {
+ BTs<std::string> const* generatorTargetLanguageStandard =
+ this->GetLanguageStandardProperty(language.first, config);
+ if (!generatorTargetLanguageStandard) {
+ // If the standard isn't explicitly set we copy it over from the
+ // specified paired language.
+ std::string key =
+ cmStrCat(cmSystemTools::UpperCase(config), '-', language.first);
+ BTs<std::string> const* standardToCopy =
+ this->GetLanguageStandardProperty(language.second, config);
+ if (standardToCopy != nullptr) {
+ this->LanguageStandardMap[key] = *standardToCopy;
+ generatorTargetLanguageStandard = &this->LanguageStandardMap[key];
+ } else {
+ cmProp defaultStandard = this->Makefile->GetDefinition(
+ cmStrCat("CMAKE_", language.second, "_STANDARD_DEFAULT"));
+ if (defaultStandard != nullptr) {
+ this->LanguageStandardMap[key] = BTs<std::string>(*defaultStandard);
+ generatorTargetLanguageStandard = &this->LanguageStandardMap[key];
+ }
+ }
+
+ // Custom updates for the CUDA standard.
+ if (generatorTargetLanguageStandard != nullptr &&
+ language.first == "CUDA") {
+ if (generatorTargetLanguageStandard->Value == "98") {
+ this->LanguageStandardMap[key].Value = "03";
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+std::string cmGeneratorTarget::GetImportedLibName(
+ std::string const& config) const
+{
+ if (cmGeneratorTarget::ImportInfo const* info =
+ this->GetImportInfo(config)) {
+ return info->LibName;
+ }
+ return std::string();
+}
+
+std::string cmGeneratorTarget::GetFullPath(const std::string& config,
+ cmStateEnums::ArtifactType artifact,
+ bool realname) const
+{
+ if (this->IsImported()) {
+ return this->Target->ImportedGetFullPath(config, artifact);
+ }
+ return this->NormalGetFullPath(config, artifact, realname);
+}
+
+std::string cmGeneratorTarget::NormalGetFullPath(
+ const std::string& config, cmStateEnums::ArtifactType artifact,
+ bool realname) const
+{
+ std::string fpath = cmStrCat(this->GetDirectory(config, artifact), '/');
+ if (this->IsAppBundleOnApple()) {
+ fpath =
+ cmStrCat(this->BuildBundleDirectory(fpath, config, FullLevel), '/');
+ }
+
+ // Add the full name of the target.
+ switch (artifact) {
+ case cmStateEnums::RuntimeBinaryArtifact:
+ if (realname) {
+ fpath += this->NormalGetRealName(config);
+ } else {
+ fpath +=
+ this->GetFullName(config, cmStateEnums::RuntimeBinaryArtifact);
+ }
+ break;
+ case cmStateEnums::ImportLibraryArtifact:
+ fpath += this->GetFullName(config, cmStateEnums::ImportLibraryArtifact);
+ break;
+ }
+ return fpath;
+}
+
+std::string cmGeneratorTarget::NormalGetRealName(
+ const std::string& config) const
+{
+ // This should not be called for imported targets.
+ // TODO: Split cmTarget into a class hierarchy to get compile-time
+ // enforcement of the limited imported target API.
+ if (this->IsImported()) {
+ std::string msg = cmStrCat("NormalGetRealName called on imported target: ",
+ this->GetName());
+ this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
+ }
+
+ if (this->GetType() == cmStateEnums::EXECUTABLE) {
+ // Compute the real name that will be built.
+ return this->GetExecutableNames(config).Real;
+ }
+ // Compute the real name that will be built.
+ return this->GetLibraryNames(config).Real;
+}
+
+cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
+ const std::string& config) const
+{
+ cmGeneratorTarget::Names targetNames;
+
+ // This should not be called for imported targets.
+ // TODO: Split cmTarget into a class hierarchy to get compile-time
+ // enforcement of the limited imported target API.
+ if (this->IsImported()) {
+ std::string msg =
+ cmStrCat("GetLibraryNames called on imported target: ", this->GetName());
+ this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
+ }
+
+ // Check for library version properties.
+ cmProp version = this->GetProperty("VERSION");
+ cmProp soversion = this->GetProperty("SOVERSION");
+ if (!this->HasSOName(config) ||
+ this->Makefile->IsOn("CMAKE_PLATFORM_NO_VERSIONED_SONAME") ||
+ this->IsFrameworkOnApple()) {
+ // Versioning is supported only for shared libraries and modules,
+ // and then only when the platform supports an soname flag.
+ version = nullptr;
+ soversion = nullptr;
+ }
+ if (version && !soversion) {
+ // The soversion must be set if the library version is set. Use
+ // the library version as the soversion.
+ soversion = version;
+ }
+ if (!version && soversion) {
+ // Use the soversion as the library version.
+ version = soversion;
+ }
+
+ // Get the components of the library name.
+ std::string prefix;
+ std::string suffix;
+ this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
+ prefix, targetNames.Base, suffix);
+
+ // The library name.
+ targetNames.Output = prefix + targetNames.Base + suffix;
+
+ if (this->IsFrameworkOnApple()) {
+ targetNames.Real = prefix;
+ if (!this->Makefile->PlatformIsAppleEmbedded()) {
+ targetNames.Real += "Versions/";
+ targetNames.Real += this->GetFrameworkVersion();
+ targetNames.Real += "/";
+ }
+ targetNames.Real += targetNames.Base + suffix;
+ targetNames.SharedObject = targetNames.Real + suffix;
+ } else {
+ // The library's soname.
+ this->ComputeVersionedName(targetNames.SharedObject, prefix,
+ targetNames.Base, suffix, targetNames.Output,
+ cmToCStr(soversion));
+
+ // The library's real name on disk.
+ this->ComputeVersionedName(targetNames.Real, prefix, targetNames.Base,
+ suffix, targetNames.Output, cmToCStr(version));
+ }
+
+ // The import library name.
+ if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ targetNames.ImportLibrary =
+ this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
+ }
+
+ // The program database file name.
+ targetNames.PDB = this->GetPDBName(config);
+
+ return targetNames;
+}
+
+cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
+ const std::string& config) const
+{
+ cmGeneratorTarget::Names targetNames;
+
+ // This should not be called for imported targets.
+ // TODO: Split cmTarget into a class hierarchy to get compile-time
+ // enforcement of the limited imported target API.
+ if (this->IsImported()) {
+ std::string msg = cmStrCat(
+ "GetExecutableNames called on imported target: ", this->GetName());
+ this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
+ }
+
+// This versioning is supported only for executables and then only
+// when the platform supports symbolic links.
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ const char* version = nullptr;
+#else
+ // Check for executable version properties.
+ const char* version = cmToCStr(this->GetProperty("VERSION"));
+ if (this->GetType() != cmStateEnums::EXECUTABLE ||
+ this->Makefile->IsOn("XCODE")) {
+ version = nullptr;
+ }
+#endif
+
+ // Get the components of the executable name.
+ std::string prefix;
+ std::string suffix;
+ this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
+ prefix, targetNames.Base, suffix);
+
+ // The executable name.
+ targetNames.Output = prefix + targetNames.Base + suffix;
+
+// The executable's real name on disk.
+#if defined(__CYGWIN__)
+ targetNames.Real = prefix + targetNames.Base;
+#else
+ targetNames.Real = targetNames.Output;
+#endif
+ if (version) {
+ targetNames.Real += "-";
+ targetNames.Real += version;
+ }
+#if defined(__CYGWIN__)
+ targetNames.Real += suffix;
+#endif
+
+ // The import library name.
+ targetNames.ImportLibrary =
+ this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
+
+ // The program database file name.
+ targetNames.PDB = this->GetPDBName(config);
+
+ return targetNames;
+}
+
+std::string cmGeneratorTarget::GetFullNameInternal(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetFullNameInternal(config, artifact, prefix, base, suffix);
+ return prefix + base + suffix;
+}
+
+std::string cmGeneratorTarget::ImportedGetLocation(
+ const std::string& config) const
+{
+ assert(this->IsImported());
+ return this->Target->ImportedGetFullPath(
+ config, cmStateEnums::RuntimeBinaryArtifact);
+}
+
+std::string cmGeneratorTarget::GetFullNameImported(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ return cmSystemTools::GetFilenameName(
+ this->Target->ImportedGetFullPath(config, artifact));
+}
+
+void cmGeneratorTarget::GetFullNameInternal(
+ const std::string& config, cmStateEnums::ArtifactType artifact,
+ std::string& outPrefix, std::string& outBase, std::string& outSuffix) const
+{
+ // Use just the target name for non-main target types.
+ if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ outPrefix.clear();
+ outBase = this->GetName();
+ outSuffix.clear();
+ return;
+ }
+
+ const bool isImportedLibraryArtifact =
+ (artifact == cmStateEnums::ImportLibraryArtifact);
+
+ // Return an empty name for the import library if this platform
+ // does not support import libraries.
+ if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
+ outPrefix.clear();
+ outBase.clear();
+ outSuffix.clear();
+ return;
+ }
+
+ // retrieve prefix and suffix
+ std::string ll = this->GetLinkerLanguage(config);
+ 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.
+ if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ artifact = cmStateEnums::RuntimeBinaryArtifact;
+ }
+
+ // Compute the full name for main target types.
+ const std::string configPostfix = this->GetFilePostfix(config);
+
+ // frameworks have directory prefix but no suffix
+ std::string fw_prefix;
+ if (this->IsFrameworkOnApple()) {
+ fw_prefix =
+ cmStrCat(this->GetFrameworkDirectory(config, ContentLevel), '/');
+ targetPrefix = &fw_prefix;
+ targetSuffix = nullptr;
+ }
+
+ if (this->IsCFBundleOnApple()) {
+ fw_prefix = cmStrCat(this->GetCFBundleDirectory(config, FullLevel), '/');
+ targetPrefix = &fw_prefix;
+ targetSuffix = nullptr;
+ }
+
+ // Begin the final name with the prefix.
+ outPrefix = targetPrefix ? *targetPrefix : "";
+
+ // Append the target name or property-specified name.
+ outBase += this->GetOutputName(config, artifact);
+
+ // Append the per-configuration postfix.
+ // When using Xcode, the postfix should be part of the suffix rather than
+ // the base, because the suffix ends up being used in Xcode's
+ // EXECUTABLE_SUFFIX attribute.
+ if (this->IsFrameworkOnApple() &&
+ this->GetGlobalGenerator()->GetName() == "Xcode") {
+ targetSuffix = &configPostfix;
+ } else {
+ outBase += configPostfix;
+ }
+
+ // Name shared libraries with their version number on some platforms.
+ if (cmProp soversion = this->GetProperty("SOVERSION")) {
+ if (this->GetType() == cmStateEnums::SHARED_LIBRARY &&
+ !isImportedLibraryArtifact &&
+ this->Makefile->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION")) {
+ outBase += "-";
+ outBase += *soversion;
+ }
+ }
+
+ // Append the suffix.
+ outSuffix = targetSuffix ? *targetSuffix : "";
+}
+
+std::string cmGeneratorTarget::GetLinkerLanguage(
+ const std::string& config) const
+{
+ return this->GetLinkClosure(config)->LinkerLanguage;
+}
+
+std::string cmGeneratorTarget::GetPDBOutputName(
+ const std::string& config) const
+{
+ std::string base =
+ this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact);
+
+ std::vector<std::string> props;
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ if (!configUpper.empty()) {
+ // PDB_NAME_<CONFIG>
+ props.push_back("PDB_NAME_" + configUpper);
+ }
+
+ // PDB_NAME
+ props.emplace_back("PDB_NAME");
+
+ for (std::string const& p : props) {
+ if (cmProp outName = this->GetProperty(p)) {
+ base = *outName;
+ break;
+ }
+ }
+ return base;
+}
+
+std::string cmGeneratorTarget::GetPDBName(const std::string& config) const
+{
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
+ prefix, base, suffix);
+
+ std::vector<std::string> props;
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ if (!configUpper.empty()) {
+ // PDB_NAME_<CONFIG>
+ props.push_back("PDB_NAME_" + configUpper);
+ }
+
+ // PDB_NAME
+ props.emplace_back("PDB_NAME");
+
+ for (std::string const& p : props) {
+ if (cmProp outName = this->GetProperty(p)) {
+ base = *outName;
+ break;
+ }
+ }
+ return prefix + base + ".pdb";
+}
+
+std::string cmGeneratorTarget::GetObjectDirectory(
+ std::string const& config) const
+{
+ std::string obj_dir =
+ this->GlobalGenerator->ExpandCFGIntDir(this->ObjectDirectory, config);
+#if defined(__APPLE__)
+ // find and replace $(PROJECT_NAME) xcode placeholder
+ const std::string projectName = this->LocalGenerator->GetProjectName();
+ cmSystemTools::ReplaceString(obj_dir, "$(PROJECT_NAME)", projectName);
+ // Replace Xcode's placeholder for the object file directory since
+ // installation and export scripts need to know the real directory.
+ // Xcode has build-time settings (e.g. for sanitizers) that affect this,
+ // but we use the default here. Users that want to enable sanitizers
+ // will do so at the cost of object library installation and export.
+ cmSystemTools::ReplaceString(obj_dir, "$(OBJECT_FILE_DIR_normal:base)",
+ "Objects-normal");
+#endif
+ return obj_dir;
+}
+
+void cmGeneratorTarget::GetTargetObjectNames(
+ std::string const& config, std::vector<std::string>& objects) const
+{
+ std::vector<cmSourceFile const*> objectSources;
+ this->GetObjectSources(objectSources, config);
+ std::map<cmSourceFile const*, std::string> mapping;
+
+ for (cmSourceFile const* sf : objectSources) {
+ mapping[sf];
+ }
+
+ this->LocalGenerator->ComputeObjectFilenames(mapping, this);
+
+ for (cmSourceFile const* src : objectSources) {
+ // Find the object file name corresponding to this source file.
+ auto map_it = mapping.find(src);
+ // It must exist because we populated the mapping just above.
+ assert(!map_it->second.empty());
+ objects.push_back(map_it->second);
+ }
+
+ // We need to compute the relative path from the root of
+ // of the object directory to handle subdirectory paths
+ std::string rootObjectDir = this->GetObjectDirectory(config);
+ rootObjectDir = cmSystemTools::CollapseFullPath(rootObjectDir);
+ auto ispcObjects = this->GetGeneratedISPCObjects(config);
+ for (std::string const& output : ispcObjects) {
+ auto relativePathFromObjectDir = output.substr(rootObjectDir.size());
+ objects.push_back(relativePathFromObjectDir);
+ }
+}
+
+bool cmGeneratorTarget::StrictTargetComparison::operator()(
+ cmGeneratorTarget const* t1, cmGeneratorTarget const* t2) const
+{
+ int nameResult = strcmp(t1->GetName().c_str(), t2->GetName().c_str());
+ if (nameResult == 0) {
+ return strcmp(
+ t1->GetLocalGenerator()->GetCurrentBinaryDirectory().c_str(),
+ t2->GetLocalGenerator()->GetCurrentBinaryDirectory().c_str()) < 0;
+ }
+ return nameResult < 0;
+}
+
+struct cmGeneratorTarget::SourceFileFlags
+cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const
+{
+ struct SourceFileFlags flags;
+ this->ConstructSourceFileFlags();
+ auto si = this->SourceFlagsMap.find(sf);
+ if (si != this->SourceFlagsMap.end()) {
+ flags = si->second;
+ } else {
+ // Handle the MACOSX_PACKAGE_LOCATION property on source files that
+ // were not listed in one of the other lists.
+ if (cmProp location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) {
+ flags.MacFolder = location->c_str();
+ const bool stripResources =
+ this->GlobalGenerator->ShouldStripResourcePath(this->Makefile);
+ if (*location == "Resources") {
+ flags.Type = cmGeneratorTarget::SourceFileTypeResource;
+ if (stripResources) {
+ flags.MacFolder = "";
+ }
+ } else if (cmHasLiteralPrefix(*location, "Resources/")) {
+ flags.Type = cmGeneratorTarget::SourceFileTypeDeepResource;
+ if (stripResources) {
+ flags.MacFolder += strlen("Resources/");
+ }
+ } else {
+ flags.Type = cmGeneratorTarget::SourceFileTypeMacContent;
+ }
+ }
+ }
+ return flags;
+}
+
+void cmGeneratorTarget::ConstructSourceFileFlags() const
+{
+ if (this->SourceFileFlagsConstructed) {
+ return;
+ }
+ this->SourceFileFlagsConstructed = true;
+
+ // Process public headers to mark the source files.
+ if (cmProp files = this->GetProperty("PUBLIC_HEADER")) {
+ std::vector<std::string> relFiles = cmExpandedList(*files);
+ for (std::string const& relFile : relFiles) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
+ SourceFileFlags& flags = this->SourceFlagsMap[sf];
+ flags.MacFolder = "Headers";
+ flags.Type = cmGeneratorTarget::SourceFileTypePublicHeader;
+ }
+ }
+ }
+
+ // Process private headers after public headers so that they take
+ // precedence if a file is listed in both.
+ if (cmProp files = this->GetProperty("PRIVATE_HEADER")) {
+ std::vector<std::string> relFiles = cmExpandedList(*files);
+ for (std::string const& relFile : relFiles) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
+ SourceFileFlags& flags = this->SourceFlagsMap[sf];
+ flags.MacFolder = "PrivateHeaders";
+ flags.Type = cmGeneratorTarget::SourceFileTypePrivateHeader;
+ }
+ }
+ }
+
+ // Mark sources listed as resources.
+ if (cmProp files = this->GetProperty("RESOURCE")) {
+ std::vector<std::string> relFiles = cmExpandedList(*files);
+ for (std::string const& relFile : relFiles) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
+ SourceFileFlags& flags = this->SourceFlagsMap[sf];
+ flags.MacFolder = "";
+ if (!this->GlobalGenerator->ShouldStripResourcePath(this->Makefile)) {
+ flags.MacFolder = "Resources";
+ }
+ flags.Type = cmGeneratorTarget::SourceFileTypeResource;
+ }
+ }
+ }
+}
+
+const cmGeneratorTarget::CompatibleInterfacesBase&
+cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const
+{
+ cmGeneratorTarget::CompatibleInterfaces& compat =
+ this->CompatibleInterfacesMap[config];
+ if (!compat.Done) {
+ compat.Done = true;
+ compat.PropsBool.insert("POSITION_INDEPENDENT_CODE");
+ compat.PropsString.insert("AUTOUIC_OPTIONS");
+ std::vector<cmGeneratorTarget const*> const& deps =
+ this->GetLinkImplementationClosure(config);
+ for (cmGeneratorTarget const* li : deps) {
+#define CM_READ_COMPATIBLE_INTERFACE(X, x) \
+ if (cmProp prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \
+ std::vector<std::string> props; \
+ cmExpandList(*prop, props); \
+ compat.Props##x.insert(props.begin(), props.end()); \
+ }
+ CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool)
+ CM_READ_COMPATIBLE_INTERFACE(STRING, String)
+ CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN, NumberMin)
+ CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX, NumberMax)
+#undef CM_READ_COMPATIBLE_INTERFACE
+ }
+ }
+ return compat;
+}
+
+bool cmGeneratorTarget::IsLinkInterfaceDependentBoolProperty(
+ const std::string& p, const std::string& config) const
+{
+ if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
+ this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ return false;
+ }
+ return this->GetCompatibleInterfaces(config).PropsBool.count(p) > 0;
+}
+
+bool cmGeneratorTarget::IsLinkInterfaceDependentStringProperty(
+ const std::string& p, const std::string& config) const
+{
+ if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
+ this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ return false;
+ }
+ return this->GetCompatibleInterfaces(config).PropsString.count(p) > 0;
+}
+
+bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMinProperty(
+ const std::string& p, const std::string& config) const
+{
+ if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
+ this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ return false;
+ }
+ return this->GetCompatibleInterfaces(config).PropsNumberMin.count(p) > 0;
+}
+
+bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMaxProperty(
+ const std::string& p, const std::string& config) const
+{
+ if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
+ this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ return false;
+ }
+ return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0;
+}
+
+enum CompatibleType
+{
+ BoolType,
+ StringType,
+ NumberMinType,
+ NumberMaxType
+};
+
+template <typename PropertyType>
+PropertyType getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
+ const std::string& prop,
+ const std::string& config,
+ CompatibleType, PropertyType*);
+
+template <>
+bool getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
+ const std::string& prop,
+ const std::string& config,
+ CompatibleType /*unused*/,
+ bool* /*unused*/)
+{
+ return tgt->GetLinkInterfaceDependentBoolProperty(prop, config);
+}
+
+template <>
+const char* getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
+ const std::string& prop,
+ const std::string& config,
+ CompatibleType t,
+ const char** /*unused*/)
+{
+ switch (t) {
+ case BoolType:
+ assert(false &&
+ "String compatibility check function called for boolean");
+ return nullptr;
+ case StringType:
+ return tgt->GetLinkInterfaceDependentStringProperty(prop, config);
+ case NumberMinType:
+ return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config);
+ case NumberMaxType:
+ return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config);
+ }
+ assert(false && "Unreachable!");
+ return nullptr;
+}
+
+template <typename PropertyType>
+void checkPropertyConsistency(cmGeneratorTarget const* depender,
+ cmGeneratorTarget const* dependee,
+ const std::string& propName,
+ std::set<std::string>& emitted,
+ const std::string& config, CompatibleType t,
+ PropertyType* /*unused*/)
+{
+ cmProp prop = dependee->GetProperty(propName);
+ if (!prop) {
+ return;
+ }
+
+ std::vector<std::string> props = cmExpandedList(*prop);
+ std::string pdir =
+ cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/prop_tgt/");
+
+ for (std::string const& p : props) {
+ std::string pname = cmSystemTools::HelpFileName(p);
+ std::string pfile = pdir + pname + ".rst";
+ if (cmSystemTools::FileExists(pfile, true)) {
+ std::ostringstream e;
+ e << "Target \"" << dependee->GetName() << "\" has property \"" << p
+ << "\" listed in its " << propName
+ << " property. "
+ "This is not allowed. Only user-defined properties may appear "
+ "listed in the "
+ << propName << " property.";
+ depender->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
+ e.str());
+ return;
+ }
+ if (emitted.insert(p).second) {
+ getLinkInterfaceDependentProperty<PropertyType>(depender, p, config, t,
+ nullptr);
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return;
+ }
+ }
+ }
+}
+
+namespace {
+std::string intersect(const std::set<std::string>& s1,
+ const std::set<std::string>& s2)
+{
+ std::set<std::string> intersect;
+ std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
+ std::inserter(intersect, intersect.begin()));
+ if (!intersect.empty()) {
+ return *intersect.begin();
+ }
+ return "";
+}
+
+std::string intersect(const std::set<std::string>& s1,
+ const std::set<std::string>& s2,
+ const std::set<std::string>& s3)
+{
+ std::string result;
+ result = intersect(s1, s2);
+ if (!result.empty()) {
+ return result;
+ }
+ result = intersect(s1, s3);
+ if (!result.empty()) {
+ return result;
+ }
+ return intersect(s2, s3);
+}
+
+std::string intersect(const std::set<std::string>& s1,
+ const std::set<std::string>& s2,
+ const std::set<std::string>& s3,
+ const std::set<std::string>& s4)
+{
+ std::string result;
+ result = intersect(s1, s2);
+ if (!result.empty()) {
+ return result;
+ }
+ result = intersect(s1, s3);
+ if (!result.empty()) {
+ return result;
+ }
+ result = intersect(s1, s4);
+ if (!result.empty()) {
+ return result;
+ }
+ return intersect(s2, s3, s4);
+}
+}
+
+void cmGeneratorTarget::CheckPropertyCompatibility(
+ cmComputeLinkInformation& info, const std::string& config) const
+{
+ const cmComputeLinkInformation::ItemVector& deps = info.GetItems();
+
+ std::set<std::string> emittedBools;
+ static const std::string strBool = "COMPATIBLE_INTERFACE_BOOL";
+ std::set<std::string> emittedStrings;
+ static const std::string strString = "COMPATIBLE_INTERFACE_STRING";
+ std::set<std::string> emittedMinNumbers;
+ static const std::string strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN";
+ std::set<std::string> emittedMaxNumbers;
+ static const std::string strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX";
+
+ for (auto const& dep : deps) {
+ if (!dep.Target) {
+ continue;
+ }
+
+ checkPropertyConsistency<bool>(this, dep.Target, strBool, emittedBools,
+ config, BoolType, nullptr);
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return;
+ }
+ checkPropertyConsistency<const char*>(this, dep.Target, strString,
+ emittedStrings, config, StringType,
+ nullptr);
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return;
+ }
+ checkPropertyConsistency<const char*>(this, dep.Target, strNumMin,
+ emittedMinNumbers, config,
+ NumberMinType, nullptr);
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return;
+ }
+ checkPropertyConsistency<const char*>(this, dep.Target, strNumMax,
+ emittedMaxNumbers, config,
+ NumberMaxType, nullptr);
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return;
+ }
+ }
+
+ std::string prop = intersect(emittedBools, emittedStrings, emittedMinNumbers,
+ emittedMaxNumbers);
+
+ if (!prop.empty()) {
+ // Use a sorted std::vector to keep the error message sorted.
+ std::vector<std::string> props;
+ auto i = emittedBools.find(prop);
+ if (i != emittedBools.end()) {
+ props.push_back(strBool);
+ }
+ i = emittedStrings.find(prop);
+ if (i != emittedStrings.end()) {
+ props.push_back(strString);
+ }
+ i = emittedMinNumbers.find(prop);
+ if (i != emittedMinNumbers.end()) {
+ props.push_back(strNumMin);
+ }
+ i = emittedMaxNumbers.find(prop);
+ if (i != emittedMaxNumbers.end()) {
+ props.push_back(strNumMax);
+ }
+ std::sort(props.begin(), props.end());
+
+ std::string propsString = cmStrCat(
+ cmJoin(cmMakeRange(props).retreat(1), ", "), " and the ", props.back());
+
+ std::ostringstream e;
+ e << "Property \"" << prop << "\" appears in both the " << propsString
+ << " property in the dependencies of target \"" << this->GetName()
+ << "\". This is not allowed. A property may only require "
+ "compatibility "
+ "in a boolean interpretation, a numeric minimum, a numeric maximum "
+ "or a "
+ "string interpretation, but not a mixture.";
+ this->LocalGenerator->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ }
+}
+
+template <typename PropertyType>
+std::string valueAsString(PropertyType);
+template <>
+std::string valueAsString<bool>(bool value)
+{
+ return value ? "TRUE" : "FALSE";
+}
+template <>
+std::string valueAsString<const char*>(const char* value)
+{
+ return value ? value : "(unset)";
+}
+template <>
+std::string valueAsString<std::string>(std::string value)
+{
+ return value;
+}
+template <>
+std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/)
+{
+ return "(unset)";
+}
+
+std::string compatibilityType(CompatibleType t)
+{
+ switch (t) {
+ case BoolType:
+ return "Boolean compatibility";
+ case StringType:
+ return "String compatibility";
+ case NumberMaxType:
+ return "Numeric maximum compatibility";
+ case NumberMinType:
+ return "Numeric minimum compatibility";
+ }
+ assert(false && "Unreachable!");
+ return "";
+}
+
+std::string compatibilityAgree(CompatibleType t, bool dominant)
+{
+ switch (t) {
+ case BoolType:
+ case StringType:
+ return dominant ? "(Disagree)\n" : "(Agree)\n";
+ case NumberMaxType:
+ case NumberMinType:
+ return dominant ? "(Dominant)\n" : "(Ignored)\n";
+ }
+ assert(false && "Unreachable!");
+ return "";
+}
+
+template <typename PropertyType>
+PropertyType getTypedProperty(
+ cmGeneratorTarget const* tgt, const std::string& prop,
+ cmGeneratorExpressionInterpreter* genexInterpreter = nullptr);
+
+template <>
+bool getTypedProperty<bool>(cmGeneratorTarget const* tgt,
+ const std::string& prop,
+ cmGeneratorExpressionInterpreter* genexInterpreter)
+{
+ if (genexInterpreter == nullptr) {
+ return tgt->GetPropertyAsBool(prop);
+ }
+
+ cmProp value = tgt->GetProperty(prop);
+ return cmIsOn(genexInterpreter->Evaluate(value ? *value : "", prop));
+}
+
+template <>
+const char* getTypedProperty<const char*>(
+ cmGeneratorTarget const* tgt, const std::string& prop,
+ cmGeneratorExpressionInterpreter* genexInterpreter)
+{
+ cmProp value = tgt->GetProperty(prop);
+
+ if (genexInterpreter == nullptr) {
+ return cmToCStr(value);
+ }
+
+ return genexInterpreter->Evaluate(value ? *value : "", prop).c_str();
+}
+
+template <>
+std::string getTypedProperty<std::string>(
+ cmGeneratorTarget const* tgt, const std::string& prop,
+ cmGeneratorExpressionInterpreter* genexInterpreter)
+{
+ cmProp value = tgt->GetProperty(prop);
+
+ if (genexInterpreter == nullptr) {
+ return valueAsString(cmToCStr(value));
+ }
+
+ return genexInterpreter->Evaluate(value ? *value : "", prop);
+}
+
+template <typename PropertyType>
+PropertyType impliedValue(PropertyType);
+template <>
+bool impliedValue<bool>(bool /*unused*/)
+{
+ return false;
+}
+template <>
+const char* impliedValue<const char*>(const char* /*unused*/)
+{
+ return "";
+}
+template <>
+std::string impliedValue<std::string>(std::string /*unused*/) // NOLINT(*)
+{
+ return std::string();
+}
+
+template <typename PropertyType>
+std::pair<bool, PropertyType> consistentProperty(PropertyType lhs,
+ PropertyType rhs,
+ CompatibleType t);
+
+template <>
+std::pair<bool, bool> consistentProperty(bool lhs, bool rhs,
+ CompatibleType /*unused*/)
+{
+ return { lhs == rhs, lhs };
+}
+
+std::pair<bool, const char*> consistentStringProperty(const char* lhs,
+ const char* rhs)
+{
+ const bool b = strcmp(lhs, rhs) == 0;
+ return { b, b ? lhs : nullptr };
+}
+
+std::pair<bool, std::string> consistentStringProperty(const std::string& lhs,
+ const std::string& rhs)
+{
+ const bool b = lhs == rhs;
+ return { b, b ? lhs : valueAsString(nullptr) };
+}
+
+std::pair<bool, const char*> consistentNumberProperty(const char* lhs,
+ const char* rhs,
+ CompatibleType t)
+{
+ char* pEnd;
+
+ long lnum = strtol(lhs, &pEnd, 0);
+ if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) {
+ return { false, nullptr };
+ }
+
+ long rnum = strtol(rhs, &pEnd, 0);
+ if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) {
+ return { false, nullptr };
+ }
+
+ if (t == NumberMaxType) {
+ return { true, std::max(lnum, rnum) == lnum ? lhs : rhs };
+ }
+
+ return { true, std::min(lnum, rnum) == lnum ? lhs : rhs };
+}
+
+template <>
+std::pair<bool, const char*> consistentProperty(const char* lhs,
+ const char* rhs,
+ CompatibleType t)
+{
+ if (!lhs && !rhs) {
+ return { true, lhs };
+ }
+ if (!lhs) {
+ return { true, rhs };
+ }
+ if (!rhs) {
+ return { true, lhs };
+ }
+
+ switch (t) {
+ case BoolType: {
+ bool same = cmIsOn(lhs) == cmIsOn(rhs);
+ return { same, same ? lhs : nullptr };
+ }
+ case StringType:
+ return consistentStringProperty(lhs, rhs);
+ case NumberMinType:
+ case NumberMaxType:
+ return consistentNumberProperty(lhs, rhs, t);
+ }
+ assert(false && "Unreachable!");
+ return { false, nullptr };
+}
+
+std::pair<bool, std::string> consistentProperty(const std::string& lhs,
+ const std::string& rhs,
+ CompatibleType t)
+{
+ const std::string null_ptr = valueAsString(nullptr);
+
+ if (lhs == null_ptr && rhs == null_ptr) {
+ return { true, lhs };
+ }
+ if (lhs == null_ptr) {
+ return { true, rhs };
+ }
+ if (rhs == null_ptr) {
+ return { true, lhs };
+ }
+
+ switch (t) {
+ case BoolType: {
+ bool same = cmIsOn(lhs) == cmIsOn(rhs);
+ return { same, same ? lhs : null_ptr };
+ }
+ case StringType:
+ return consistentStringProperty(lhs, rhs);
+ case NumberMinType:
+ case NumberMaxType: {
+ auto value = consistentNumberProperty(lhs.c_str(), rhs.c_str(), t);
+ return { value.first,
+ value.first ? std::string(value.second) : null_ptr };
+ }
+ }
+ assert(false && "Unreachable!");
+ return { false, null_ptr };
+}
+
+template <typename PropertyType>
+PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt,
+ const std::string& p,
+ const std::string& config,
+ const char* defaultValue,
+ CompatibleType t,
+ PropertyType* /*unused*/)
+{
+ PropertyType propContent = getTypedProperty<PropertyType>(tgt, p);
+
+ std::vector<std::string> headPropKeys = tgt->GetPropertyKeys();
+ const bool explicitlySet = cm::contains(headPropKeys, p);
+
+ const bool impliedByUse = tgt->IsNullImpliedByLinkLibraries(p);
+ assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet));
+
+ std::vector<cmGeneratorTarget const*> const& deps =
+ tgt->GetLinkImplementationClosure(config);
+
+ if (deps.empty()) {
+ return propContent;
+ }
+ bool propInitialized = explicitlySet;
+
+ std::string report = cmStrCat(" * Target \"", tgt->GetName());
+ if (explicitlySet) {
+ report += "\" has property content \"";
+ report += valueAsString<PropertyType>(propContent);
+ report += "\"\n";
+ } else if (impliedByUse) {
+ report += "\" property is implied by use.\n";
+ } else {
+ report += "\" property not set.\n";
+ }
+
+ std::string interfaceProperty = "INTERFACE_" + p;
+ std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter;
+ if (p == "POSITION_INDEPENDENT_CODE") {
+ genexInterpreter = cm::make_unique<cmGeneratorExpressionInterpreter>(
+ tgt->GetLocalGenerator(), config, tgt);
+ }
+
+ for (cmGeneratorTarget const* theTarget : deps) {
+ // An error should be reported if one dependency
+ // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other
+ // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the
+ // target itself has a POSITION_INDEPENDENT_CODE which disagrees
+ // with a dependency.
+
+ std::vector<std::string> propKeys = theTarget->GetPropertyKeys();
+
+ const bool ifaceIsSet = cm::contains(propKeys, interfaceProperty);
+ PropertyType ifacePropContent = getTypedProperty<PropertyType>(
+ theTarget, interfaceProperty, genexInterpreter.get());
+
+ std::string reportEntry;
+ if (ifaceIsSet) {
+ reportEntry += " * Target \"";
+ reportEntry += theTarget->GetName();
+ reportEntry += "\" property value \"";
+ reportEntry += valueAsString<PropertyType>(ifacePropContent);
+ reportEntry += "\" ";
+ }
+
+ if (explicitlySet) {
+ if (ifaceIsSet) {
+ std::pair<bool, PropertyType> consistent =
+ consistentProperty(propContent, ifacePropContent, t);
+ report += reportEntry;
+ report += compatibilityAgree(t, propContent != consistent.second);
+ if (!consistent.first) {
+ std::ostringstream e;
+ e << "Property " << p << " on target \"" << tgt->GetName()
+ << "\" does\nnot match the "
+ "INTERFACE_"
+ << p
+ << " property requirement\nof "
+ "dependency \""
+ << theTarget->GetName() << "\".\n";
+ cmSystemTools::Error(e.str());
+ break;
+ }
+ propContent = consistent.second;
+ continue;
+ }
+ // Explicitly set on target and not set in iface. Can't disagree.
+ continue;
+ }
+ if (impliedByUse) {
+ propContent = impliedValue<PropertyType>(propContent);
+
+ if (ifaceIsSet) {
+ std::pair<bool, PropertyType> consistent =
+ consistentProperty(propContent, ifacePropContent, t);
+ report += reportEntry;
+ report += compatibilityAgree(t, propContent != consistent.second);
+ if (!consistent.first) {
+ std::ostringstream e;
+ e << "Property " << p << " on target \"" << tgt->GetName()
+ << "\" is\nimplied to be " << defaultValue
+ << " because it was used to determine the link libraries\n"
+ "already. The INTERFACE_"
+ << p << " property on\ndependency \"" << theTarget->GetName()
+ << "\" is in conflict.\n";
+ cmSystemTools::Error(e.str());
+ break;
+ }
+ propContent = consistent.second;
+ continue;
+ }
+ // Implicitly set on target and not set in iface. Can't disagree.
+ continue;
+ }
+ if (ifaceIsSet) {
+ if (propInitialized) {
+ std::pair<bool, PropertyType> consistent =
+ consistentProperty(propContent, ifacePropContent, t);
+ report += reportEntry;
+ report += compatibilityAgree(t, propContent != consistent.second);
+ if (!consistent.first) {
+ std::ostringstream e;
+ e << "The INTERFACE_" << p << " property of \""
+ << theTarget->GetName() << "\" does\nnot agree with the value of "
+ << p << " already determined\nfor \"" << tgt->GetName() << "\".\n";
+ cmSystemTools::Error(e.str());
+ break;
+ }
+ propContent = consistent.second;
+ continue;
+ }
+ report += reportEntry + "(Interface set)\n";
+ propContent = ifacePropContent;
+ propInitialized = true;
+ } else {
+ // Not set. Nothing to agree on.
+ continue;
+ }
+ }
+
+ tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent),
+ report, compatibilityType(t));
+ return propContent;
+}
+
+bool cmGeneratorTarget::SetDeviceLink(bool deviceLink)
+{
+ bool previous = this->DeviceLink;
+ this->DeviceLink = deviceLink;
+ return previous;
+}
+
+bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty(
+ const std::string& p, const std::string& config) const
+{
+ return checkInterfacePropertyCompatibility<bool>(this, p, config, "FALSE",
+ BoolType, nullptr);
+}
+
+std::string cmGeneratorTarget::GetLinkInterfaceDependentStringAsBoolProperty(
+ const std::string& p, const std::string& config) const
+{
+ return checkInterfacePropertyCompatibility<std::string>(
+ this, p, config, "FALSE", BoolType, nullptr);
+}
+
+const char* cmGeneratorTarget::GetLinkInterfaceDependentStringProperty(
+ const std::string& p, const std::string& config) const
+{
+ return checkInterfacePropertyCompatibility<const char*>(
+ this, p, config, "empty", StringType, nullptr);
+}
+
+const char* cmGeneratorTarget::GetLinkInterfaceDependentNumberMinProperty(
+ const std::string& p, const std::string& config) const
+{
+ return checkInterfacePropertyCompatibility<const char*>(
+ this, p, config, "empty", NumberMinType, nullptr);
+}
+
+const char* cmGeneratorTarget::GetLinkInterfaceDependentNumberMaxProperty(
+ const std::string& p, const std::string& config) const
+{
+ return checkInterfacePropertyCompatibility<const char*>(
+ this, p, config, "empty", NumberMaxType, nullptr);
+}
+
+cmComputeLinkInformation* cmGeneratorTarget::GetLinkInformation(
+ const std::string& config) const
+{
+ // Lookup any existing information for this configuration.
+ std::string key(cmSystemTools::UpperCase(config));
+ auto i = this->LinkInformation.find(key);
+ if (i == this->LinkInformation.end()) {
+ // Compute information for this configuration.
+ auto info = cm::make_unique<cmComputeLinkInformation>(this, config);
+ if (info && !info->Compute()) {
+ info.reset();
+ }
+
+ // Store the information for this configuration.
+ i = this->LinkInformation.emplace(key, std::move(info)).first;
+
+ if (i->second) {
+ this->CheckPropertyCompatibility(*i->second, config);
+ }
+ }
+ return i->second.get();
+}
+
+void cmGeneratorTarget::GetTargetVersion(int& major, int& minor) const
+{
+ int patch;
+ this->GetTargetVersion("VERSION", major, minor, patch);
+}
+
+void cmGeneratorTarget::GetTargetVersionFallback(
+ const std::string& property, const std::string& fallback_property,
+ int& major, int& minor, int& patch) const
+{
+ if (this->GetProperty(property)) {
+ this->GetTargetVersion(property, major, minor, patch);
+ } else {
+ this->GetTargetVersion(fallback_property, major, minor, patch);
+ }
+}
+
+void cmGeneratorTarget::GetTargetVersion(const std::string& property,
+ int& major, int& minor,
+ int& patch) const
+{
+ // Set the default values.
+ major = 0;
+ minor = 0;
+ patch = 0;
+
+ assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
+
+ if (cmProp version = this->GetProperty(property)) {
+ // Try to parse the version number and store the results that were
+ // successfully parsed.
+ int parsed_major;
+ int parsed_minor;
+ int parsed_patch;
+ switch (sscanf(version->c_str(), "%d.%d.%d", &parsed_major, &parsed_minor,
+ &parsed_patch)) {
+ case 3:
+ patch = parsed_patch;
+ CM_FALLTHROUGH;
+ case 2:
+ minor = parsed_minor;
+ CM_FALLTHROUGH;
+ case 1:
+ major = parsed_major;
+ CM_FALLTHROUGH;
+ default:
+ break;
+ }
+ }
+}
+
+std::string cmGeneratorTarget::GetRuntimeLinkLibrary(
+ std::string const& lang, std::string const& config) const
+{
+ // This is activated by the presence of a default selection whether or
+ // not it is overridden by a property.
+ cmProp runtimeLibraryDefault = this->Makefile->GetDefinition(
+ cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT"));
+ if (!cmNonempty(runtimeLibraryDefault)) {
+ return std::string();
+ }
+ cmProp runtimeLibraryValue =
+ this->Target->GetProperty(cmStrCat(lang, "_RUNTIME_LIBRARY"));
+ if (!runtimeLibraryValue) {
+ runtimeLibraryValue = runtimeLibraryDefault;
+ }
+ return cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate(
+ *runtimeLibraryValue, this->LocalGenerator, config, this));
+}
+
+std::string cmGeneratorTarget::GetFortranModuleDirectory(
+ std::string const& working_dir) const
+{
+ if (!this->FortranModuleDirectoryCreated) {
+ this->FortranModuleDirectory =
+ this->CreateFortranModuleDirectory(working_dir);
+ this->FortranModuleDirectoryCreated = true;
+ }
+
+ return this->FortranModuleDirectory;
+}
+
+std::string cmGeneratorTarget::CreateFortranModuleDirectory(
+ std::string const& working_dir) const
+{
+ std::string mod_dir;
+ std::string target_mod_dir;
+ if (cmProp prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) {
+ target_mod_dir = *prop;
+ } else {
+ std::string const& default_mod_dir =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+ if (default_mod_dir != working_dir) {
+ target_mod_dir = default_mod_dir;
+ }
+ }
+ cmProp moddir_flag =
+ this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG");
+ if (!target_mod_dir.empty() && moddir_flag) {
+ // Compute the full path to the module directory.
+ if (cmSystemTools::FileIsFullPath(target_mod_dir)) {
+ // Already a full path.
+ mod_dir = target_mod_dir;
+ } else {
+ // Interpret relative to the current output directory.
+ mod_dir = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(),
+ '/', target_mod_dir);
+ }
+
+ // Make sure the module output directory exists.
+ cmSystemTools::MakeDirectory(mod_dir);
+ }
+ return mod_dir;
+}
+
+void cmGeneratorTarget::AddISPCGeneratedHeader(std::string const& header,
+ std::string const& config)
+{
+ std::string config_upper;
+ if (!config.empty()) {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+ auto iter = this->ISPCGeneratedHeaders.find(config_upper);
+ if (iter == this->ISPCGeneratedHeaders.end()) {
+ std::vector<std::string> headers;
+ headers.emplace_back(header);
+ this->ISPCGeneratedHeaders.insert({ config_upper, headers });
+ } else {
+ iter->second.emplace_back(header);
+ }
+}
+
+std::vector<std::string> cmGeneratorTarget::GetGeneratedISPCHeaders(
+ std::string const& config) const
+{
+ std::string config_upper;
+ if (!config.empty()) {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+ auto iter = this->ISPCGeneratedHeaders.find(config_upper);
+ if (iter == this->ISPCGeneratedHeaders.end()) {
+ return std::vector<std::string>{};
+ }
+ return iter->second;
+}
+
+void cmGeneratorTarget::AddISPCGeneratedObject(std::vector<std::string>&& objs,
+ std::string const& config)
+{
+ std::string config_upper;
+ if (!config.empty()) {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+ auto iter = this->ISPCGeneratedObjects.find(config_upper);
+ if (iter == this->ISPCGeneratedObjects.end()) {
+ this->ISPCGeneratedObjects.insert({ config_upper, objs });
+ } else {
+ iter->second.insert(iter->second.end(), objs.begin(), objs.end());
+ }
+}
+
+std::vector<std::string> cmGeneratorTarget::GetGeneratedISPCObjects(
+ std::string const& config) const
+{
+ std::string config_upper;
+ if (!config.empty()) {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+ auto iter = this->ISPCGeneratedObjects.find(config_upper);
+ if (iter == this->ISPCGeneratedObjects.end()) {
+ return std::vector<std::string>{};
+ }
+ return iter->second;
+}
+
+std::string cmGeneratorTarget::GetFrameworkVersion() const
+{
+ assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
+
+ if (cmProp fversion = this->GetProperty("FRAMEWORK_VERSION")) {
+ return *fversion;
+ }
+ if (cmProp tversion = this->GetProperty("VERSION")) {
+ return *tversion;
+ }
+ return "A";
+}
+
+void cmGeneratorTarget::ComputeVersionedName(std::string& vName,
+ std::string const& prefix,
+ std::string const& base,
+ std::string const& suffix,
+ std::string const& name,
+ const char* version) const
+{
+ vName = this->Makefile->IsOn("APPLE") ? (prefix + base) : name;
+ if (version) {
+ vName += ".";
+ vName += version;
+ }
+ vName += this->Makefile->IsOn("APPLE") ? suffix : std::string();
+}
+
+std::vector<std::string> cmGeneratorTarget::GetPropertyKeys() const
+{
+ return this->Target->GetProperties().GetKeys();
+}
+
+void cmGeneratorTarget::ReportPropertyOrigin(
+ const std::string& p, const std::string& result, const std::string& report,
+ const std::string& compatibilityType) const
+{
+ std::vector<std::string> debugProperties;
+ this->Target->GetMakefile()->GetDefExpandList(
+ "CMAKE_DEBUG_TARGET_PROPERTIES", debugProperties);
+
+ bool debugOrigin = !this->DebugCompatiblePropertiesDone[p] &&
+ cm::contains(debugProperties, p);
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugCompatiblePropertiesDone[p] = true;
+ }
+ if (!debugOrigin) {
+ return;
+ }
+
+ std::string areport =
+ cmStrCat(compatibilityType, " of property \"", p, "\" for target \"",
+ this->GetName(), "\" (result: \"", result, "\"):\n", report);
+
+ this->LocalGenerator->GetCMakeInstance()->IssueMessage(MessageType::LOG,
+ areport);
+}
+
+bool cmGeneratorTarget::IsLinkLookupScope(std::string const& n,
+ cmLocalGenerator const*& lg) const
+{
+ if (cmHasLiteralPrefix(n, CMAKE_DIRECTORY_ID_SEP)) {
+ cmDirectoryId const dirId = n.substr(sizeof(CMAKE_DIRECTORY_ID_SEP) - 1);
+ if (dirId.String.empty()) {
+ lg = this->LocalGenerator;
+ return true;
+ }
+ if (cmLocalGenerator const* otherLG =
+ this->GlobalGenerator->FindLocalGenerator(dirId)) {
+ lg = otherLG;
+ return true;
+ }
+ }
+ return false;
+}
+
+void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names,
+ cmListFileBacktrace const& bt,
+ std::vector<cmLinkItem>& items) const
+{
+ cmLocalGenerator const* lg = this->LocalGenerator;
+ for (std::string const& n : names) {
+ if (this->IsLinkLookupScope(n, lg)) {
+ continue;
+ }
+
+ std::string name = this->CheckCMP0004(n);
+ if (name == this->GetName() || name.empty()) {
+ continue;
+ }
+ items.push_back(this->ResolveLinkItem(name, bt, lg));
+ }
+}
+
+void cmGeneratorTarget::ExpandLinkItems(
+ std::string const& prop, std::string const& value, std::string const& config,
+ cmGeneratorTarget const* headTarget, bool usage_requirements_only,
+ std::vector<cmLinkItem>& items, bool& hadHeadSensitiveCondition,
+ bool& hadContextSensitiveCondition,
+ bool& hadLinkLanguageSensitiveCondition) const
+{
+ // Keep this logic in sync with ComputeLinkImplementationLibraries.
+ cmGeneratorExpression ge;
+ cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr);
+ // The $<LINK_ONLY> expression may be in a link interface to specify
+ // private link dependencies that are otherwise excluded from usage
+ // requirements.
+ if (usage_requirements_only) {
+ dagChecker.SetTransitivePropertiesOnly();
+ }
+ std::vector<std::string> libs;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value);
+ cmExpandList(cge->Evaluate(this->LocalGenerator, config, headTarget,
+ &dagChecker, this, headTarget->LinkerLanguage),
+ libs);
+ this->LookupLinkItems(libs, cge->GetBacktrace(), items);
+ hadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition();
+ hadContextSensitiveCondition = cge->GetHadContextSensitiveCondition();
+ hadLinkLanguageSensitiveCondition =
+ cge->GetHadLinkLanguageSensitiveCondition();
+}
+
+cmLinkInterface const* cmGeneratorTarget::GetLinkInterface(
+ const std::string& config, cmGeneratorTarget const* head) const
+{
+ return this->GetLinkInterface(config, head, false);
+}
+
+cmLinkInterface const* cmGeneratorTarget::GetLinkInterface(
+ const std::string& config, cmGeneratorTarget const* head,
+ bool secondPass) const
+{
+ // Imported targets have their own link interface.
+ if (this->IsImported()) {
+ return this->GetImportLinkInterface(config, head, false, secondPass);
+ }
+
+ // Link interfaces are not supported for executables that do not
+ // export symbols.
+ if (this->GetType() == cmStateEnums::EXECUTABLE &&
+ !this->IsExecutableWithExports()) {
+ return nullptr;
+ }
+
+ // Lookup any existing link interface for this configuration.
+ cmHeadToLinkInterfaceMap& hm = this->GetHeadToLinkInterfaceMap(config);
+
+ if (secondPass) {
+ hm.erase(head);
+ }
+
+ // If the link interface does not depend on the head target
+ // then return the one we computed first.
+ if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
+ return &hm.begin()->second;
+ }
+
+ cmOptionalLinkInterface& iface = hm[head];
+ if (!iface.LibrariesDone) {
+ iface.LibrariesDone = true;
+ this->ComputeLinkInterfaceLibraries(config, iface, head, false);
+ }
+ if (!iface.AllDone) {
+ iface.AllDone = true;
+ if (iface.Exists) {
+ this->ComputeLinkInterface(config, iface, head, secondPass);
+ }
+ }
+
+ return iface.Exists ? &iface : nullptr;
+}
+
+void cmGeneratorTarget::ComputeLinkInterface(
+ const std::string& config, cmOptionalLinkInterface& iface,
+ cmGeneratorTarget const* headTarget) const
+{
+ this->ComputeLinkInterface(config, iface, headTarget, false);
+}
+
+void cmGeneratorTarget::ComputeLinkInterface(
+ const std::string& config, cmOptionalLinkInterface& iface,
+ cmGeneratorTarget const* headTarget, bool secondPass) const
+{
+ if (iface.Explicit) {
+ if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ // Shared libraries may have runtime implementation dependencies
+ // on other shared libraries that are not in the interface.
+ std::set<cmLinkItem> emitted;
+ for (cmLinkItem const& lib : iface.Libraries) {
+ emitted.insert(lib);
+ }
+ if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+ cmLinkImplementation const* impl =
+ this->GetLinkImplementation(config, secondPass);
+ for (cmLinkImplItem const& lib : impl->Libraries) {
+ if (emitted.insert(lib).second) {
+ if (lib.Target) {
+ // This is a runtime dependency on another shared library.
+ if (lib.Target->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ iface.SharedDeps.push_back(lib);
+ }
+ } else {
+ // TODO: Recognize shared library file names. Perhaps this
+ // should be moved to cmComputeLinkInformation, but that
+ // creates a chicken-and-egg problem since this list is needed
+ // for its construction.
+ }
+ }
+ }
+ }
+ }
+ } else if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN ||
+ this->GetPolicyStatusCMP0022() == cmPolicies::OLD) {
+ // The link implementation is the default link interface.
+ cmLinkImplementationLibraries const* impl =
+ this->GetLinkImplementationLibrariesInternal(config, headTarget);
+ iface.ImplementationIsInterface = true;
+ iface.WrongConfigLibraries = impl->WrongConfigLibraries;
+ }
+
+ if (this->LinkLanguagePropagatesToDependents()) {
+ // Targets using this archive need its language runtime libraries.
+ if (cmLinkImplementation const* impl =
+ this->GetLinkImplementation(config, secondPass)) {
+ iface.Languages = impl->Languages;
+ }
+ }
+
+ if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ // Construct the property name suffix for this configuration.
+ std::string suffix = "_";
+ if (!config.empty()) {
+ suffix += cmSystemTools::UpperCase(config);
+ } else {
+ suffix += "NOCONFIG";
+ }
+
+ // How many repetitions are needed if this library has cyclic
+ // dependencies?
+ std::string propName = cmStrCat("LINK_INTERFACE_MULTIPLICITY", suffix);
+ if (cmProp config_reps = this->GetProperty(propName)) {
+ sscanf(config_reps->c_str(), "%u", &iface.Multiplicity);
+ } else if (cmProp reps =
+ this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) {
+ sscanf(reps->c_str(), "%u", &iface.Multiplicity);
+ }
+ }
+}
+
+const cmLinkInterfaceLibraries* cmGeneratorTarget::GetLinkInterfaceLibraries(
+ const std::string& config, cmGeneratorTarget const* head,
+ bool usage_requirements_only) const
+{
+ // Imported targets have their own link interface.
+ if (this->IsImported()) {
+ return this->GetImportLinkInterface(config, head, usage_requirements_only);
+ }
+
+ // Link interfaces are not supported for executables that do not
+ // export symbols.
+ if (this->GetType() == cmStateEnums::EXECUTABLE &&
+ !this->IsExecutableWithExports()) {
+ return nullptr;
+ }
+
+ // Lookup any existing link interface for this configuration.
+ cmHeadToLinkInterfaceMap& hm =
+ (usage_requirements_only
+ ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config)
+ : this->GetHeadToLinkInterfaceMap(config));
+
+ // If the link interface does not depend on the head target
+ // then return the one we computed first.
+ if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
+ return &hm.begin()->second;
+ }
+
+ cmOptionalLinkInterface& iface = hm[head];
+ if (!iface.LibrariesDone) {
+ iface.LibrariesDone = true;
+ this->ComputeLinkInterfaceLibraries(config, iface, head,
+ usage_requirements_only);
+ }
+
+ return iface.Exists ? &iface : nullptr;
+}
+
+std::string cmGeneratorTarget::GetDirectory(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ if (this->IsImported()) {
+ // Return the directory from which the target is imported.
+ return cmSystemTools::GetFilenamePath(
+ this->Target->ImportedGetFullPath(config, artifact));
+ }
+ if (OutputInfo const* info = this->GetOutputInfo(config)) {
+ // Return the directory in which the target will be built.
+ switch (artifact) {
+ case cmStateEnums::RuntimeBinaryArtifact:
+ return info->OutDir;
+ case cmStateEnums::ImportLibraryArtifact:
+ return info->ImpDir;
+ }
+ }
+ return "";
+}
+
+bool cmGeneratorTarget::UsesDefaultOutputDir(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ std::string dir;
+ return this->ComputeOutputDir(config, artifact, dir);
+}
+
+cmGeneratorTarget::OutputInfo const* cmGeneratorTarget::GetOutputInfo(
+ const std::string& config) const
+{
+ // There is no output information for imported targets.
+ if (this->IsImported()) {
+ return nullptr;
+ }
+
+ // Only libraries and executables have well-defined output files.
+ if (!this->HaveWellDefinedOutputFiles()) {
+ std::string msg = cmStrCat("cmGeneratorTarget::GetOutputInfo called for ",
+ this->GetName(), " which has type ",
+ cmState::GetTargetTypeName(this->GetType()));
+ this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
+ return nullptr;
+ }
+
+ // Lookup/compute/cache the output information for this configuration.
+ std::string config_upper;
+ if (!config.empty()) {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+ auto i = this->OutputInfoMap.find(config_upper);
+ if (i == this->OutputInfoMap.end()) {
+ // Add empty info in map to detect potential recursion.
+ OutputInfo info;
+ OutputInfoMapType::value_type entry(config_upper, info);
+ i = this->OutputInfoMap.insert(entry).first;
+
+ // Compute output directories.
+ this->ComputeOutputDir(config, cmStateEnums::RuntimeBinaryArtifact,
+ info.OutDir);
+ this->ComputeOutputDir(config, cmStateEnums::ImportLibraryArtifact,
+ info.ImpDir);
+ if (!this->ComputePDBOutputDir("PDB", config, info.PdbDir)) {
+ info.PdbDir = info.OutDir;
+ }
+
+ // Now update the previously-prepared map entry.
+ i->second = info;
+ } else if (i->second.empty()) {
+ // An empty map entry indicates we have been called recursively
+ // from the above block.
+ this->LocalGenerator->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Target '" + this->GetName() + "' OUTPUT_DIRECTORY depends on itself.",
+ this->GetBacktrace());
+ return nullptr;
+ }
+ return &i->second;
+}
+
+bool cmGeneratorTarget::ComputeOutputDir(const std::string& config,
+ cmStateEnums::ArtifactType artifact,
+ std::string& out) const
+{
+ bool usesDefaultOutputDir = false;
+ std::string conf = config;
+
+ // Look for a target property defining the target output directory
+ // based on the target type.
+ std::string targetTypeName = this->GetOutputTargetType(artifact);
+ std::string propertyName;
+ if (!targetTypeName.empty()) {
+ propertyName = cmStrCat(targetTypeName, "_OUTPUT_DIRECTORY");
+ }
+
+ // Check for a per-configuration output directory target property.
+ std::string configUpper = cmSystemTools::UpperCase(conf);
+ std::string configProp;
+ if (!targetTypeName.empty()) {
+ configProp = cmStrCat(targetTypeName, "_OUTPUT_DIRECTORY_", configUpper);
+ }
+
+ // Select an output directory.
+ if (cmProp config_outdir = this->GetProperty(configProp)) {
+ // Use the user-specified per-configuration output directory.
+ out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator,
+ config, this);
+
+ // Skip per-configuration subdirectory.
+ conf.clear();
+ } else if (cmProp outdir = this->GetProperty(propertyName)) {
+ // Use the user-specified output directory.
+ out = cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator,
+ config, this);
+ // Skip per-configuration subdirectory if the value contained a
+ // generator expression.
+ if (out != *outdir) {
+ conf.clear();
+ }
+ } else if (this->GetType() == cmStateEnums::EXECUTABLE) {
+ // Lookup the output path for executables.
+ out = this->Makefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
+ } else if (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ // Lookup the output path for libraries.
+ out = this->Makefile->GetSafeDefinition("LIBRARY_OUTPUT_PATH");
+ }
+ if (out.empty()) {
+ // Default to the current output directory.
+ usesDefaultOutputDir = true;
+ out = ".";
+ }
+
+ // Convert the output path to a full path in case it is
+ // specified as a relative path. Treat a relative path as
+ // relative to the current output directory for this makefile.
+ out = (cmSystemTools::CollapseFullPath(
+ out, this->LocalGenerator->GetCurrentBinaryDirectory()));
+
+ // The generator may add the configuration's subdirectory.
+ if (!conf.empty()) {
+ bool useEPN =
+ this->GlobalGenerator->UseEffectivePlatformName(this->Makefile);
+ std::string suffix =
+ usesDefaultOutputDir && useEPN ? "${EFFECTIVE_PLATFORM_NAME}" : "";
+ this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
+ "/", conf, suffix, out);
+ }
+
+ return usesDefaultOutputDir;
+}
+
+bool cmGeneratorTarget::ComputePDBOutputDir(const std::string& kind,
+ const std::string& config,
+ std::string& out) const
+{
+ // Look for a target property defining the target output directory
+ // based on the target type.
+ std::string propertyName;
+ if (!kind.empty()) {
+ propertyName = cmStrCat(kind, "_OUTPUT_DIRECTORY");
+ }
+ std::string conf = config;
+
+ // Check for a per-configuration output directory target property.
+ std::string configUpper = cmSystemTools::UpperCase(conf);
+ std::string configProp;
+ if (!kind.empty()) {
+ configProp = cmStrCat(kind, "_OUTPUT_DIRECTORY_", configUpper);
+ }
+
+ // Select an output directory.
+ if (cmProp config_outdir = this->GetProperty(configProp)) {
+ // Use the user-specified per-configuration output directory.
+ out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator,
+ config);
+
+ // Skip per-configuration subdirectory.
+ conf.clear();
+ } else if (cmProp outdir = this->GetProperty(propertyName)) {
+ // Use the user-specified output directory.
+ out =
+ cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator, config);
+
+ // Skip per-configuration subdirectory if the value contained a
+ // generator expression.
+ if (out != *outdir) {
+ conf.clear();
+ }
+ }
+ if (out.empty()) {
+ return false;
+ }
+
+ // Convert the output path to a full path in case it is
+ // specified as a relative path. Treat a relative path as
+ // relative to the current output directory for this makefile.
+ out = (cmSystemTools::CollapseFullPath(
+ out, this->LocalGenerator->GetCurrentBinaryDirectory()));
+
+ // The generator may add the configuration's subdirectory.
+ if (!conf.empty()) {
+ this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
+ "/", conf, "", out);
+ }
+ return true;
+}
+
+bool cmGeneratorTarget::HaveInstallTreeRPATH(const std::string& config) const
+{
+ std::string install_rpath;
+ this->GetInstallRPATH(config, install_rpath);
+ return !install_rpath.empty() &&
+ !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH");
+}
+
+bool cmGeneratorTarget::GetBuildRPATH(const std::string& config,
+ std::string& rpath) const
+{
+ return this->GetRPATH(config, "BUILD_RPATH", rpath);
+}
+
+bool cmGeneratorTarget::GetInstallRPATH(const std::string& config,
+ std::string& rpath) const
+{
+ return this->GetRPATH(config, "INSTALL_RPATH", rpath);
+}
+
+bool cmGeneratorTarget::GetRPATH(const std::string& config,
+ const std::string& prop,
+ std::string& rpath) const
+{
+ cmProp value = this->GetProperty(prop);
+ if (!value) {
+ return false;
+ }
+
+ rpath =
+ cmGeneratorExpression::Evaluate(*value, this->LocalGenerator, config);
+
+ return true;
+}
+
+void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
+ const std::string& config, cmOptionalLinkInterface& iface,
+ cmGeneratorTarget const* headTarget, bool usage_requirements_only) const
+{
+ // Construct the property name suffix for this configuration.
+ std::string suffix = "_";
+ if (!config.empty()) {
+ suffix += cmSystemTools::UpperCase(config);
+ } else {
+ suffix += "NOCONFIG";
+ }
+
+ // An explicit list of interface libraries may be set for shared
+ // libraries and executables that export symbols.
+ cmProp explicitLibraries = nullptr;
+ std::string linkIfaceProp;
+ bool const cmp0022NEW = (this->GetPolicyStatusCMP0022() != cmPolicies::OLD &&
+ this->GetPolicyStatusCMP0022() != cmPolicies::WARN);
+ if (cmp0022NEW) {
+ // CMP0022 NEW behavior is to use INTERFACE_LINK_LIBRARIES.
+ linkIfaceProp = "INTERFACE_LINK_LIBRARIES";
+ explicitLibraries = this->GetProperty(linkIfaceProp);
+ } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->IsExecutableWithExports()) {
+ // CMP0022 OLD behavior is to use LINK_INTERFACE_LIBRARIES if set on a
+ // shared lib or executable.
+
+ // Lookup the per-configuration property.
+ linkIfaceProp = cmStrCat("LINK_INTERFACE_LIBRARIES", suffix);
+ explicitLibraries = this->GetProperty(linkIfaceProp);
+
+ // If not set, try the generic property.
+ if (!explicitLibraries) {
+ linkIfaceProp = "LINK_INTERFACE_LIBRARIES";
+ explicitLibraries = this->GetProperty(linkIfaceProp);
+ }
+ }
+
+ if (explicitLibraries &&
+ this->GetPolicyStatusCMP0022() == cmPolicies::WARN &&
+ !this->PolicyWarnedCMP0022) {
+ // Compare the explicitly set old link interface properties to the
+ // preferred new link interface property one and warn if different.
+ cmProp newExplicitLibraries =
+ this->GetProperty("INTERFACE_LINK_LIBRARIES");
+ if (newExplicitLibraries &&
+ (*newExplicitLibraries != *explicitLibraries)) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n"
+ "Target \"" << this->GetName() << "\" has an "
+ "INTERFACE_LINK_LIBRARIES property which differs from its " <<
+ linkIfaceProp << " properties."
+ "\n"
+ "INTERFACE_LINK_LIBRARIES:\n"
+ " " << *newExplicitLibraries << "\n" <<
+ linkIfaceProp << ":\n"
+ " " << *explicitLibraries << "\n";
+ /* clang-format on */
+ this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ this->PolicyWarnedCMP0022 = true;
+ }
+ }
+
+ // There is no implicit link interface for executables or modules
+ // so if none was explicitly set then there is no link interface.
+ if (!explicitLibraries &&
+ (this->GetType() == cmStateEnums::EXECUTABLE ||
+ (this->GetType() == cmStateEnums::MODULE_LIBRARY))) {
+ return;
+ }
+ iface.Exists = true;
+ iface.Explicit = cmp0022NEW || explicitLibraries != nullptr;
+
+ if (explicitLibraries) {
+ // The interface libraries have been explicitly set.
+ this->ExpandLinkItems(linkIfaceProp, *explicitLibraries, config,
+ headTarget, usage_requirements_only, iface.Libraries,
+ iface.HadHeadSensitiveCondition,
+ iface.HadContextSensitiveCondition,
+ iface.HadLinkLanguageSensitiveCondition);
+ return;
+ }
+
+ // If CMP0022 is NEW then the plain tll signature sets the
+ // INTERFACE_LINK_LIBRARIES, so if we get here then the project
+ // cleared the property explicitly and we should not fall back
+ // to the link implementation.
+ if (cmp0022NEW) {
+ return;
+ }
+
+ // The link implementation is the default link interface.
+ if (cmLinkImplementationLibraries const* impl =
+ this->GetLinkImplementationLibrariesInternal(config, headTarget)) {
+ iface.Libraries.insert(iface.Libraries.end(), impl->Libraries.begin(),
+ impl->Libraries.end());
+ if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN &&
+ !this->PolicyWarnedCMP0022 && !usage_requirements_only) {
+ // Compare the link implementation fallback link interface to the
+ // preferred new link interface property and warn if different.
+ std::vector<cmLinkItem> ifaceLibs;
+ static const std::string newProp = "INTERFACE_LINK_LIBRARIES";
+ if (cmProp newExplicitLibraries = this->GetProperty(newProp)) {
+ bool hadHeadSensitiveConditionDummy = false;
+ bool hadContextSensitiveConditionDummy = false;
+ bool hadLinkLanguageSensitiveConditionDummy = false;
+ this->ExpandLinkItems(newProp, *newExplicitLibraries, config,
+ headTarget, usage_requirements_only, ifaceLibs,
+ hadHeadSensitiveConditionDummy,
+ hadContextSensitiveConditionDummy,
+ hadLinkLanguageSensitiveConditionDummy);
+ }
+ if (ifaceLibs != iface.Libraries) {
+ std::string oldLibraries = cmJoin(impl->Libraries, ";");
+ std::string newLibraries = cmJoin(ifaceLibs, ";");
+ if (oldLibraries.empty()) {
+ oldLibraries = "(empty)";
+ }
+ if (newLibraries.empty()) {
+ newLibraries = "(empty)";
+ }
+
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n"
+ "Target \"" << this->GetName() << "\" has an "
+ "INTERFACE_LINK_LIBRARIES property. "
+ "This should be preferred as the source of the link interface "
+ "for this library but because CMP0022 is not set CMake is "
+ "ignoring the property and using the link implementation "
+ "as the link interface instead."
+ "\n"
+ "INTERFACE_LINK_LIBRARIES:\n"
+ " " << newLibraries << "\n"
+ "Link implementation:\n"
+ " " << oldLibraries << "\n";
+ /* clang-format on */
+ this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING,
+ w.str());
+ this->PolicyWarnedCMP0022 = true;
+ }
+ }
+ }
+}
+
+const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface(
+ const std::string& config, cmGeneratorTarget const* headTarget,
+ bool usage_requirements_only, bool secondPass) const
+{
+ cmGeneratorTarget::ImportInfo const* info = this->GetImportInfo(config);
+ if (!info) {
+ return nullptr;
+ }
+
+ cmHeadToLinkInterfaceMap& hm =
+ (usage_requirements_only
+ ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config)
+ : this->GetHeadToLinkInterfaceMap(config));
+
+ if (secondPass) {
+ hm.erase(headTarget);
+ }
+
+ // If the link interface does not depend on the head target
+ // then return the one we computed first.
+ if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
+ return &hm.begin()->second;
+ }
+
+ cmOptionalLinkInterface& iface = hm[headTarget];
+ if (!iface.AllDone) {
+ iface.AllDone = true;
+ iface.Multiplicity = info->Multiplicity;
+ cmExpandList(info->Languages, iface.Languages);
+ this->ExpandLinkItems(info->LibrariesProp, info->Libraries, config,
+ headTarget, usage_requirements_only, iface.Libraries,
+ iface.HadHeadSensitiveCondition,
+ iface.HadContextSensitiveCondition,
+ iface.HadLinkLanguageSensitiveCondition);
+ std::vector<std::string> deps = cmExpandedList(info->SharedDeps);
+ this->LookupLinkItems(deps, cmListFileBacktrace(), iface.SharedDeps);
+ }
+
+ return &iface;
+}
+
+cmGeneratorTarget::ImportInfo const* cmGeneratorTarget::GetImportInfo(
+ const std::string& config) const
+{
+ // There is no imported information for non-imported targets.
+ if (!this->IsImported()) {
+ return nullptr;
+ }
+
+ // Lookup/compute/cache the import information for this
+ // configuration.
+ std::string config_upper;
+ if (!config.empty()) {
+ config_upper = cmSystemTools::UpperCase(config);
+ } else {
+ config_upper = "NOCONFIG";
+ }
+
+ auto i = this->ImportInfoMap.find(config_upper);
+ if (i == this->ImportInfoMap.end()) {
+ ImportInfo info;
+ this->ComputeImportInfo(config_upper, info);
+ ImportInfoMapType::value_type entry(config_upper, info);
+ i = this->ImportInfoMap.insert(entry).first;
+ }
+
+ if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ return &i->second;
+ }
+ // If the location is empty then the target is not available for
+ // this configuration.
+ if (i->second.Location.empty() && i->second.ImportLibrary.empty()) {
+ return nullptr;
+ }
+
+ // Return the import information.
+ return &i->second;
+}
+
+void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
+ ImportInfo& info) const
+{
+ // This method finds information about an imported target from its
+ // properties. The "IMPORTED_" namespace is reserved for properties
+ // defined by the project exporting the target.
+
+ // Initialize members.
+ info.NoSOName = false;
+
+ cmProp loc = nullptr;
+ cmProp imp = nullptr;
+ std::string suffix;
+ if (!this->Target->GetMappedConfig(desired_config, loc, imp, suffix)) {
+ return;
+ }
+
+ // Get the link interface.
+ {
+ std::string linkProp = "INTERFACE_LINK_LIBRARIES";
+ cmProp propertyLibs = this->GetProperty(linkProp);
+
+ if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+ if (!propertyLibs) {
+ linkProp = cmStrCat("IMPORTED_LINK_INTERFACE_LIBRARIES", suffix);
+ propertyLibs = this->GetProperty(linkProp);
+ }
+
+ if (!propertyLibs) {
+ linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
+ propertyLibs = this->GetProperty(linkProp);
+ }
+ }
+ if (propertyLibs) {
+ info.LibrariesProp = linkProp;
+ info.Libraries = *propertyLibs;
+ }
+ }
+ if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ if (loc) {
+ info.LibName = *loc;
+ }
+ return;
+ }
+
+ // A provided configuration has been chosen. Load the
+ // configuration's properties.
+
+ // Get the location.
+ if (loc) {
+ info.Location = *loc;
+ } else {
+ std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix);
+ if (cmProp config_location = this->GetProperty(impProp)) {
+ info.Location = *config_location;
+ } else if (cmProp location = this->GetProperty("IMPORTED_LOCATION")) {
+ info.Location = *location;
+ }
+ }
+
+ // Get the soname.
+ if (this->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ std::string soProp = cmStrCat("IMPORTED_SONAME", suffix);
+ if (cmProp config_soname = this->GetProperty(soProp)) {
+ info.SOName = *config_soname;
+ } else if (cmProp soname = this->GetProperty("IMPORTED_SONAME")) {
+ info.SOName = *soname;
+ }
+ }
+
+ // Get the "no-soname" mark.
+ if (this->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ std::string soProp = cmStrCat("IMPORTED_NO_SONAME", suffix);
+ if (cmProp config_no_soname = this->GetProperty(soProp)) {
+ info.NoSOName = cmIsOn(*config_no_soname);
+ } else if (cmProp no_soname = this->GetProperty("IMPORTED_NO_SONAME")) {
+ info.NoSOName = cmIsOn(*no_soname);
+ }
+ }
+
+ // Get the import library.
+ if (imp) {
+ info.ImportLibrary = *imp;
+ } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->IsExecutableWithExports()) {
+ std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
+ if (cmProp config_implib = this->GetProperty(impProp)) {
+ info.ImportLibrary = *config_implib;
+ } else if (cmProp implib = this->GetProperty("IMPORTED_IMPLIB")) {
+ info.ImportLibrary = *implib;
+ }
+ }
+
+ // Get the link dependencies.
+ {
+ std::string linkProp =
+ cmStrCat("IMPORTED_LINK_DEPENDENT_LIBRARIES", suffix);
+ if (cmProp config_libs = this->GetProperty(linkProp)) {
+ info.SharedDeps = *config_libs;
+ } else if (cmProp libs =
+ this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES")) {
+ info.SharedDeps = *libs;
+ }
+ }
+
+ // Get the link languages.
+ if (this->LinkLanguagePropagatesToDependents()) {
+ std::string linkProp =
+ cmStrCat("IMPORTED_LINK_INTERFACE_LANGUAGES", suffix);
+ if (cmProp config_libs = this->GetProperty(linkProp)) {
+ info.Languages = *config_libs;
+ } else if (cmProp libs =
+ this->GetProperty("IMPORTED_LINK_INTERFACE_LANGUAGES")) {
+ info.Languages = *libs;
+ }
+ }
+
+ // Get information if target is managed assembly.
+ {
+ std::string linkProp = "IMPORTED_COMMON_LANGUAGE_RUNTIME";
+ if (cmProp pc = this->GetProperty(linkProp + suffix)) {
+ info.Managed = this->CheckManagedType(*pc);
+ } else if (cmProp p = this->GetProperty(linkProp)) {
+ info.Managed = this->CheckManagedType(*p);
+ }
+ }
+
+ // Get the cyclic repetition count.
+ if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ std::string linkProp =
+ cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix);
+ if (cmProp config_reps = this->GetProperty(linkProp)) {
+ sscanf(config_reps->c_str(), "%u", &info.Multiplicity);
+ } else if (cmProp reps =
+ this->GetProperty("IMPORTED_LINK_INTERFACE_MULTIPLICITY")) {
+ sscanf(reps->c_str(), "%u", &info.Multiplicity);
+ }
+ }
+}
+
+cmHeadToLinkInterfaceMap& cmGeneratorTarget::GetHeadToLinkInterfaceMap(
+ const std::string& config) const
+{
+ return this->LinkInterfaceMap[cmSystemTools::UpperCase(config)];
+}
+
+cmHeadToLinkInterfaceMap&
+cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap(
+ const std::string& config) const
+{
+ return this
+ ->LinkInterfaceUsageRequirementsOnlyMap[cmSystemTools::UpperCase(config)];
+}
+
+const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
+ const std::string& config) const
+{
+ return this->GetLinkImplementation(config, false);
+}
+
+const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
+ const std::string& config, bool secondPass) const
+{
+ // There is no link implementation for targets that cannot compile sources.
+ if (!this->CanCompileSources()) {
+ return nullptr;
+ }
+
+ cmOptionalLinkImplementation& impl =
+ this->LinkImplMap[cmSystemTools::UpperCase(config)][this];
+ if (secondPass) {
+ impl = cmOptionalLinkImplementation();
+ }
+ if (!impl.LibrariesDone) {
+ impl.LibrariesDone = true;
+ this->ComputeLinkImplementationLibraries(config, impl, this);
+ }
+ if (!impl.LanguagesDone) {
+ impl.LanguagesDone = true;
+ this->ComputeLinkImplementationLanguages(config, impl);
+ }
+ return &impl;
+}
+
+bool cmGeneratorTarget::GetConfigCommonSourceFilesForXcode(
+ std::vector<cmSourceFile*>& files) const
+{
+ std::vector<std::string> const& configs =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+ auto it = configs.begin();
+ const std::string& firstConfig = *it;
+ this->GetSourceFilesWithoutObjectLibraries(files, firstConfig);
+
+ for (; it != configs.end(); ++it) {
+ std::vector<cmSourceFile*> configFiles;
+ this->GetSourceFilesWithoutObjectLibraries(configFiles, *it);
+ if (configFiles != files) {
+ std::string firstConfigFiles;
+ const char* sep = "";
+ for (cmSourceFile* f : files) {
+ firstConfigFiles += sep;
+ firstConfigFiles += f->ResolveFullPath();
+ sep = "\n ";
+ }
+
+ std::string thisConfigFiles;
+ sep = "";
+ for (cmSourceFile* f : configFiles) {
+ thisConfigFiles += sep;
+ thisConfigFiles += f->ResolveFullPath();
+ sep = "\n ";
+ }
+ std::ostringstream e;
+ /* clang-format off */
+ e << "Target \"" << this->GetName()
+ << "\" has source files which vary by "
+ "configuration. This is not supported by the \""
+ << this->GlobalGenerator->GetName()
+ << "\" generator.\n"
+ "Config \"" << firstConfig << "\":\n"
+ " " << firstConfigFiles << "\n"
+ "Config \"" << *it << "\":\n"
+ " " << thisConfigFiles << "\n";
+ /* clang-format on */
+ this->LocalGenerator->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ }
+ return true;
+}
+
+void cmGeneratorTarget::GetObjectLibrariesCMP0026(
+ std::vector<cmGeneratorTarget*>& objlibs) const
+{
+ // At configure-time, this method can be called as part of getting the
+ // LOCATION property or to export() a file to be include()d. However
+ // there is no cmGeneratorTarget at configure-time, so search the SOURCES
+ // for TARGET_OBJECTS instead for backwards compatibility with OLD
+ // behavior of CMP0024 and CMP0026 only.
+ cmStringRange rng = this->Target->GetSourceEntries();
+ for (std::string const& entry : rng) {
+ std::vector<std::string> files = cmExpandedList(entry);
+ for (std::string const& li : files) {
+ if (cmHasLiteralPrefix(li, "$<TARGET_OBJECTS:") && li.back() == '>') {
+ std::string objLibName = li.substr(17, li.size() - 18);
+
+ if (cmGeneratorExpression::Find(objLibName) != std::string::npos) {
+ continue;
+ }
+ cmGeneratorTarget* objLib =
+ this->LocalGenerator->FindGeneratorTargetToUse(objLibName);
+ if (objLib) {
+ objlibs.push_back(objLib);
+ }
+ }
+ }
+ }
+}
+
+std::string cmGeneratorTarget::CheckCMP0004(std::string const& item) const
+{
+ // Strip whitespace off the library names because we used to do this
+ // in case variables were expanded at generate time. We no longer
+ // do the expansion but users link to libraries like " ${VAR} ".
+ std::string lib = item;
+ std::string::size_type pos = lib.find_first_not_of(" \t\r\n");
+ if (pos != std::string::npos) {
+ lib = lib.substr(pos);
+ }
+ pos = lib.find_last_not_of(" \t\r\n");
+ if (pos != std::string::npos) {
+ lib = lib.substr(0, pos + 1);
+ }
+ if (lib != item) {
+ cmake* cm = this->LocalGenerator->GetCMakeInstance();
+ switch (this->GetPolicyStatusCMP0004()) {
+ case cmPolicies::WARN: {
+ std::ostringstream w;
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0004) << "\n"
+ << "Target \"" << this->GetName() << "\" links to item \"" << item
+ << "\" which has leading or trailing whitespace.";
+ cm->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
+ this->GetBacktrace());
+ }
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::NEW: {
+ std::ostringstream e;
+ e << "Target \"" << this->GetName() << "\" links to item \"" << item
+ << "\" which has leading or trailing whitespace. "
+ << "This is now an error according to policy CMP0004.";
+ cm->IssueMessage(MessageType::FATAL_ERROR, e.str(),
+ this->GetBacktrace());
+ } break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS: {
+ std::ostringstream e;
+ e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0004) << "\n"
+ << "Target \"" << this->GetName() << "\" links to item \"" << item
+ << "\" which has leading or trailing whitespace.";
+ cm->IssueMessage(MessageType::FATAL_ERROR, e.str(),
+ this->GetBacktrace());
+ } break;
+ }
+ }
+ return lib;
+}
+
+bool cmGeneratorTarget::IsDeprecated() const
+{
+ cmProp deprecation = this->GetProperty("DEPRECATION");
+ return cmNonempty(deprecation);
+}
+
+std::string cmGeneratorTarget::GetDeprecation() const
+{
+ // find DEPRECATION property
+ if (cmProp deprecation = this->GetProperty("DEPRECATION")) {
+ return *deprecation;
+ }
+ return std::string();
+}
+
+void cmGeneratorTarget::GetLanguages(std::set<std::string>& languages,
+ const std::string& config) const
+{
+ // Targets that do not compile anything have no languages.
+ if (!this->CanCompileSources()) {
+ return;
+ }
+
+ std::vector<cmSourceFile*> sourceFiles;
+ this->GetSourceFiles(sourceFiles, config);
+ for (cmSourceFile* src : sourceFiles) {
+ const std::string& lang = src->GetOrDetermineLanguage();
+ if (!lang.empty()) {
+ languages.insert(lang);
+ }
+ }
+
+ std::vector<cmGeneratorTarget*> objectLibraries;
+ std::vector<cmSourceFile const*> externalObjects;
+ if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ std::vector<cmGeneratorTarget*> objectTargets;
+ this->GetObjectLibrariesCMP0026(objectTargets);
+ objectLibraries.reserve(objectTargets.size());
+ for (cmGeneratorTarget* gt : objectTargets) {
+ objectLibraries.push_back(gt);
+ }
+ } else {
+ this->GetExternalObjects(externalObjects, config);
+ for (cmSourceFile const* extObj : externalObjects) {
+ std::string objLib = extObj->GetObjectLibrary();
+ if (cmGeneratorTarget* tgt =
+ this->LocalGenerator->FindGeneratorTargetToUse(objLib)) {
+ auto const objLibIt =
+ std::find_if(objectLibraries.cbegin(), objectLibraries.cend(),
+ [tgt](cmGeneratorTarget* t) { return t == tgt; });
+ if (objectLibraries.cend() == objLibIt) {
+ objectLibraries.push_back(tgt);
+ }
+ }
+ }
+ }
+ for (cmGeneratorTarget* objLib : objectLibraries) {
+ objLib->GetLanguages(languages, config);
+ }
+}
+
+bool cmGeneratorTarget::IsLanguageUsed(std::string const& language,
+ std::string const& config) const
+{
+ std::set<std::string> languages;
+ this->GetLanguages(languages, config);
+ return languages.count(language);
+}
+
+bool cmGeneratorTarget::IsCSharpOnly() const
+{
+ // Only certain target types may compile CSharp.
+ if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ return false;
+ }
+ std::set<std::string> languages = this->GetAllConfigCompileLanguages();
+ // Consider an explicit linker language property, but *not* the
+ // computed linker language that may depend on linked targets.
+ cmProp linkLang = this->GetProperty("LINKER_LANGUAGE");
+ if (cmNonempty(linkLang)) {
+ languages.insert(*linkLang);
+ }
+ return languages.size() == 1 && languages.count("CSharp") > 0;
+}
+
+void cmGeneratorTarget::ComputeLinkImplementationLanguages(
+ const std::string& config, cmOptionalLinkImplementation& impl) const
+{
+ // This target needs runtime libraries for its source languages.
+ std::set<std::string> languages;
+ // Get languages used in our source files.
+ this->GetLanguages(languages, config);
+ // Copy the set of languages to the link implementation.
+ impl.Languages.insert(impl.Languages.begin(), languages.begin(),
+ languages.end());
+}
+
+bool cmGeneratorTarget::HaveBuildTreeRPATH(const std::string& config) const
+{
+ if (this->GetPropertyAsBool("SKIP_BUILD_RPATH")) {
+ return false;
+ }
+ std::string build_rpath;
+ if (this->GetBuildRPATH(config, build_rpath)) {
+ return true;
+ }
+ if (cmLinkImplementationLibraries const* impl =
+ this->GetLinkImplementationLibraries(config)) {
+ return !impl->Libraries.empty();
+ }
+ return false;
+}
+
+cmLinkImplementationLibraries const*
+cmGeneratorTarget::GetLinkImplementationLibraries(
+ const std::string& config) const
+{
+ return this->GetLinkImplementationLibrariesInternal(config, this);
+}
+
+cmLinkImplementationLibraries const*
+cmGeneratorTarget::GetLinkImplementationLibrariesInternal(
+ const std::string& config, cmGeneratorTarget const* head) const
+{
+ // There is no link implementation for targets that cannot compile sources.
+ if (!this->CanCompileSources()) {
+ return nullptr;
+ }
+
+ // Populate the link implementation libraries for this configuration.
+ HeadToLinkImplementationMap& hm =
+ this->LinkImplMap[cmSystemTools::UpperCase(config)];
+
+ // If the link implementation does not depend on the head target
+ // then return the one we computed first.
+ if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
+ return &hm.begin()->second;
+ }
+
+ cmOptionalLinkImplementation& impl = hm[head];
+ if (!impl.LibrariesDone) {
+ impl.LibrariesDone = true;
+ this->ComputeLinkImplementationLibraries(config, impl, head);
+ }
+ return &impl;
+}
+
+bool cmGeneratorTarget::IsNullImpliedByLinkLibraries(
+ const std::string& p) const
+{
+ return cm::contains(this->LinkImplicitNullProperties, p);
+}
+
+void cmGeneratorTarget::ComputeLinkImplementationLibraries(
+ const std::string& config, cmOptionalLinkImplementation& impl,
+ cmGeneratorTarget const* head) const
+{
+ cmLocalGenerator const* lg = this->LocalGenerator;
+ cmStringRange entryRange = this->Target->GetLinkImplementationEntries();
+ cmBacktraceRange btRange = this->Target->GetLinkImplementationBacktraces();
+ cmBacktraceRange::const_iterator btIt = btRange.begin();
+ // Collect libraries directly linked in this configuration.
+ for (cmStringRange::const_iterator le = entryRange.begin(),
+ end = entryRange.end();
+ le != end; ++le, ++btIt) {
+ std::vector<std::string> llibs;
+ // Keep this logic in sync with ExpandLinkItems.
+ cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr,
+ nullptr);
+ cmGeneratorExpression ge(*btIt);
+ std::unique_ptr<cmCompiledGeneratorExpression> const cge = ge.Parse(*le);
+ std::string const& evaluated =
+ cge->Evaluate(this->LocalGenerator, config, head, &dagChecker, nullptr,
+ this->LinkerLanguage);
+ cmExpandList(evaluated, llibs);
+ if (cge->GetHadHeadSensitiveCondition()) {
+ impl.HadHeadSensitiveCondition = true;
+ }
+ if (cge->GetHadContextSensitiveCondition()) {
+ impl.HadContextSensitiveCondition = true;
+ }
+ if (cge->GetHadLinkLanguageSensitiveCondition()) {
+ impl.HadLinkLanguageSensitiveCondition = true;
+ }
+
+ for (std::string const& lib : llibs) {
+ if (this->IsLinkLookupScope(lib, lg)) {
+ continue;
+ }
+
+ // Skip entries that resolve to the target itself or are empty.
+ std::string name = this->CheckCMP0004(lib);
+ if (this->GetPolicyStatusCMP0108() == cmPolicies::NEW) {
+ // resolve alias name
+ auto* target = this->Makefile->FindTargetToUse(name);
+ if (target) {
+ name = target->GetName();
+ }
+ }
+ if (name == this->GetName() || name.empty()) {
+ if (name == this->GetName()) {
+ bool noMessage = false;
+ MessageType messageType = MessageType::FATAL_ERROR;
+ std::ostringstream e;
+ switch (this->GetPolicyStatusCMP0038()) {
+ case cmPolicies::WARN: {
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0038) << "\n";
+ messageType = MessageType::AUTHOR_WARNING;
+ } break;
+ case cmPolicies::OLD:
+ noMessage = true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Issue the fatal message.
+ break;
+ }
+
+ if (!noMessage) {
+ e << "Target \"" << this->GetName() << "\" links to itself.";
+ this->LocalGenerator->GetCMakeInstance()->IssueMessage(
+ messageType, e.str(), this->GetBacktrace());
+ if (messageType == MessageType::FATAL_ERROR) {
+ return;
+ }
+ }
+ }
+ continue;
+ }
+
+ // The entry is meant for this configuration.
+ impl.Libraries.emplace_back(this->ResolveLinkItem(name, *btIt, lg),
+ evaluated != *le);
+ }
+
+ std::set<std::string> const& seenProps = cge->GetSeenTargetProperties();
+ for (std::string const& sp : seenProps) {
+ if (!this->GetProperty(sp)) {
+ this->LinkImplicitNullProperties.insert(sp);
+ }
+ }
+ cge->GetMaxLanguageStandard(this, this->MaxLanguageStandards);
+ }
+
+ // Get the list of configurations considered to be DEBUG.
+ std::vector<std::string> debugConfigs =
+ this->Makefile->GetCMakeInstance()->GetDebugConfigs();
+
+ cmTargetLinkLibraryType linkType =
+ CMP0003_ComputeLinkType(config, debugConfigs);
+ cmTarget::LinkLibraryVectorType const& oldllibs =
+ this->Target->GetOriginalLinkLibraries();
+ for (cmTarget::LibraryID const& oldllib : oldllibs) {
+ if (oldllib.second != GENERAL_LibraryType && oldllib.second != linkType) {
+ std::string name = this->CheckCMP0004(oldllib.first);
+ if (name == this->GetName() || name.empty()) {
+ continue;
+ }
+ // Support OLD behavior for CMP0003.
+ impl.WrongConfigLibraries.push_back(
+ this->ResolveLinkItem(name, cmListFileBacktrace()));
+ }
+ }
+}
+
+cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference(
+ std::string const& name) const
+{
+ return this->ResolveTargetReference(name, this->LocalGenerator);
+}
+
+cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference(
+ std::string const& name, cmLocalGenerator const* lg) const
+{
+ TargetOrString resolved;
+
+ if (cmGeneratorTarget* tgt = lg->FindGeneratorTargetToUse(name)) {
+ resolved.Target = tgt;
+ } else {
+ resolved.String = name;
+ }
+
+ return resolved;
+}
+
+cmLinkItem cmGeneratorTarget::ResolveLinkItem(
+ std::string const& name, cmListFileBacktrace const& bt) const
+{
+ return this->ResolveLinkItem(name, bt, this->LocalGenerator);
+}
+
+cmLinkItem cmGeneratorTarget::ResolveLinkItem(std::string const& name,
+ cmListFileBacktrace const& bt,
+ cmLocalGenerator const* lg) const
+{
+ TargetOrString resolved = this->ResolveTargetReference(name, lg);
+
+ if (!resolved.Target) {
+ return cmLinkItem(resolved.String, false, bt);
+ }
+
+ // Check deprecation, issue message with `bt` backtrace.
+ if (resolved.Target->IsDeprecated()) {
+ std::ostringstream w;
+ /* clang-format off */
+ w <<
+ "The library that is being linked to, " << resolved.Target->GetName() <<
+ ", is marked as being deprecated by the owner. The message provided by "
+ "the developer is: \n" << resolved.Target->GetDeprecation() << "\n";
+ /* clang-format on */
+ this->LocalGenerator->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING, w.str(), bt);
+ }
+
+ // Skip targets that will not really be linked. This is probably a
+ // name conflict between an external library and an executable
+ // within the project.
+ if (resolved.Target->GetType() == cmStateEnums::EXECUTABLE &&
+ !resolved.Target->IsExecutableWithExports()) {
+ return cmLinkItem(resolved.Target->GetName(), false, bt);
+ }
+
+ return cmLinkItem(resolved.Target, false, bt);
+}
+
+std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const
+{
+ if (OutputInfo const* info = this->GetOutputInfo(config)) {
+ // Return the directory in which the target will be built.
+ return info->PdbDir;
+ }
+ return "";
+}
+
+bool cmGeneratorTarget::HasImplibGNUtoMS(std::string const& config) const
+{
+ return this->HasImportLibrary(config) && this->GetPropertyAsBool("GNUtoMS");
+}
+
+bool cmGeneratorTarget::GetImplibGNUtoMS(std::string const& config,
+ std::string const& gnuName,
+ std::string& out,
+ const char* newExt) const
+{
+ if (this->HasImplibGNUtoMS(config) && gnuName.size() > 6 &&
+ gnuName.substr(gnuName.size() - 6) == ".dll.a") {
+ out = cmStrCat(cm::string_view(gnuName).substr(0, gnuName.size() - 6),
+ newExt ? newExt : ".lib");
+ return true;
+ }
+ return false;
+}
+
+bool cmGeneratorTarget::HasContextDependentSources() const
+{
+ return this->SourcesAreContextDependent == Tribool::True;
+}
+
+bool cmGeneratorTarget::IsExecutableWithExports() const
+{
+ return (this->GetType() == cmStateEnums::EXECUTABLE &&
+ this->GetPropertyAsBool("ENABLE_EXPORTS"));
+}
+
+bool cmGeneratorTarget::HasImportLibrary(std::string const& config) const
+{
+ return (this->IsDLLPlatform() &&
+ (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->IsExecutableWithExports()) &&
+ // Assemblies which have only managed code do not have
+ // import libraries.
+ this->GetManagedType(config) != ManagedType::Managed) ||
+ (this->Target->IsAIX() && this->IsExecutableWithExports());
+}
+
+bool cmGeneratorTarget::NeedImportLibraryName(std::string const& config) const
+{
+ return this->HasImportLibrary(config) ||
+ // On DLL platforms we always generate the import library name
+ // just in case the sources have export markup.
+ (this->IsDLLPlatform() &&
+ (this->GetType() == cmStateEnums::EXECUTABLE ||
+ this->GetType() == cmStateEnums::MODULE_LIBRARY));
+}
+
+std::string cmGeneratorTarget::GetSupportDirectory() const
+{
+ std::string dir = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/", this->GetName());
+#if defined(__VMS)
+ dir += "_dir";
+#else
+ dir += ".dir";
+#endif
+ return dir;
+}
+
+bool cmGeneratorTarget::IsLinkable() const
+{
+ return (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ this->GetType() == cmStateEnums::UNKNOWN_LIBRARY ||
+ this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
+ this->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ this->IsExecutableWithExports());
+}
+
+bool cmGeneratorTarget::IsFrameworkOnApple() const
+{
+ return ((this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GetType() == cmStateEnums::STATIC_LIBRARY) &&
+ this->Makefile->IsOn("APPLE") &&
+ this->GetPropertyAsBool("FRAMEWORK"));
+}
+
+bool cmGeneratorTarget::IsAppBundleOnApple() const
+{
+ return (this->GetType() == cmStateEnums::EXECUTABLE &&
+ this->Makefile->IsOn("APPLE") &&
+ this->GetPropertyAsBool("MACOSX_BUNDLE"));
+}
+
+bool cmGeneratorTarget::IsXCTestOnApple() const
+{
+ return (this->IsCFBundleOnApple() && this->GetPropertyAsBool("XCTEST"));
+}
+
+bool cmGeneratorTarget::IsCFBundleOnApple() const
+{
+ return (this->GetType() == cmStateEnums::MODULE_LIBRARY &&
+ this->Makefile->IsOn("APPLE") && this->GetPropertyAsBool("BUNDLE"));
+}
+
+cmGeneratorTarget::ManagedType cmGeneratorTarget::CheckManagedType(
+ std::string const& propval) const
+{
+ // The type of the managed assembly (mixed unmanaged C++ and C++/CLI,
+ // or only C++/CLI) does only depend on whether the property is an empty
+ // string or contains any value at all. In Visual Studio generators
+ // this propval is prepended with /clr[:] which results in:
+ //
+ // 1. propval does not exist: no /clr flag, unmanaged target, has import
+ // lib
+ // 2. empty propval: add /clr as flag, mixed unmanaged/managed
+ // target, has import lib
+ // 3. any value (safe,pure): add /clr:[propval] as flag, target with
+ // managed code only, no import lib
+ return propval.empty() ? ManagedType::Mixed : ManagedType::Managed;
+}
+
+cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType(
+ const std::string& config) const
+{
+ // Only libraries and executables can be managed targets.
+ if (this->GetType() > cmStateEnums::SHARED_LIBRARY) {
+ return ManagedType::Undefined;
+ }
+
+ if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ return ManagedType::Native;
+ }
+
+ // Check imported target.
+ if (this->IsImported()) {
+ if (cmGeneratorTarget::ImportInfo const* info =
+ this->GetImportInfo(config)) {
+ return info->Managed;
+ }
+ return ManagedType::Undefined;
+ }
+
+ // Check for explicitly set clr target property.
+ if (cmProp clr = this->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
+ return this->CheckManagedType(*clr);
+ }
+
+ // C# targets are always managed. This language specific check
+ // is added to avoid that the COMMON_LANGUAGE_RUNTIME target property
+ // has to be set manually for C# targets.
+ return this->IsCSharpOnly() ? ManagedType::Managed : ManagedType::Native;
+}
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
new file mode 100644
index 0000000..2935e0b
--- /dev/null
+++ b/Source/cmGeneratorTarget.h
@@ -0,0 +1,1127 @@
+/* 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 <cstddef>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+
+#include "cmLinkItem.h"
+#include "cmListFileCache.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmStateTypes.h"
+
+class cmComputeLinkInformation;
+class cmCustomCommand;
+class cmGlobalGenerator;
+class cmLocalGenerator;
+class cmMakefile;
+class cmSourceFile;
+class cmTarget;
+
+struct cmGeneratorExpressionContext;
+struct cmGeneratorExpressionDAGChecker;
+
+class cmGeneratorTarget
+{
+public:
+ cmGeneratorTarget(cmTarget*, cmLocalGenerator* lg);
+ ~cmGeneratorTarget();
+
+ cmGeneratorTarget(cmGeneratorTarget const&) = delete;
+ cmGeneratorTarget& operator=(cmGeneratorTarget const&) = delete;
+
+ cmLocalGenerator* GetLocalGenerator() const;
+
+ cmGlobalGenerator* GetGlobalGenerator() const;
+
+ bool IsInBuildSystem() const;
+ bool IsImported() const;
+ bool IsImportedGloballyVisible() const;
+ bool CanCompileSources() const;
+ const std::string& GetLocation(const std::string& config) const;
+
+ /** Get the full path to the target's main artifact, if known. */
+ cm::optional<std::string> MaybeGetLocation(std::string const& config) const;
+
+ std::vector<cmCustomCommand> const& GetPreBuildCommands() const;
+ std::vector<cmCustomCommand> const& GetPreLinkCommands() const;
+ std::vector<cmCustomCommand> const& GetPostBuildCommands() const;
+
+ void AppendCustomCommandSideEffects(
+ std::set<cmGeneratorTarget const*>& sideEffects) const;
+ void AppendLanguageSideEffects(
+ std::map<std::string, std::set<cmGeneratorTarget const*>>& sideEffects)
+ const;
+
+#define DECLARE_TARGET_POLICY(POLICY) \
+ cmPolicies::PolicyStatus GetPolicyStatus##POLICY() const \
+ { \
+ return this->PolicyMap.Get(cmPolicies::POLICY); \
+ }
+
+ CM_FOR_EACH_TARGET_POLICY(DECLARE_TARGET_POLICY)
+
+#undef DECLARE_TARGET_POLICY
+
+ /** Get the location of the target in the build tree with a placeholder
+ referencing the configuration in the native build system. This
+ location is suitable for use as the LOCATION target property. */
+ const std::string& GetLocationForBuild() const;
+
+ cmComputeLinkInformation* GetLinkInformation(
+ const std::string& config) const;
+
+ cmStateEnums::TargetType GetType() const;
+ const std::string& GetName() const;
+ std::string GetExportName() const;
+
+ std::vector<std::string> GetPropertyKeys() const;
+ //! Might return a nullptr if the property is not set or invalid
+ cmProp GetProperty(const std::string& prop) const;
+ //! Always returns a valid pointer
+ std::string const& GetSafeProperty(std::string const& prop) const;
+ bool GetPropertyAsBool(const std::string& prop) const;
+ void GetSourceFiles(std::vector<cmSourceFile*>& files,
+ const std::string& config) const;
+ std::vector<BT<cmSourceFile*>> GetSourceFiles(
+ std::string const& config) const;
+
+ /** Source file kinds (classifications).
+ Generators use this to decide how to treat a source file. */
+ enum SourceKind
+ {
+ SourceKindAppManifest,
+ SourceKindCertificate,
+ SourceKindCustomCommand,
+ SourceKindExternalObject,
+ SourceKindExtra,
+ SourceKindHeader,
+ SourceKindIDL,
+ SourceKindManifest,
+ SourceKindModuleDefinition,
+ SourceKindObjectSource,
+ SourceKindResx,
+ SourceKindXaml,
+ SourceKindUnityBatched
+ };
+
+ /** A source file paired with a kind (classification). */
+ struct SourceAndKind
+ {
+ BT<cmSourceFile*> Source;
+ SourceKind Kind;
+ };
+
+ /** All sources needed for a configuration with kinds assigned. */
+ struct KindedSources
+ {
+ std::vector<SourceAndKind> Sources;
+ bool Initialized = false;
+ };
+
+ /** Get all sources needed for a configuration with kinds assigned. */
+ KindedSources const& GetKindedSources(std::string const& config) const;
+
+ struct AllConfigSource
+ {
+ cmSourceFile* Source;
+ cmGeneratorTarget::SourceKind Kind;
+ std::vector<size_t> Configs;
+ };
+
+ /** Get all sources needed for all configurations with kinds and
+ per-source configurations assigned. */
+ std::vector<AllConfigSource> const& GetAllConfigSources() const;
+
+ /** Get all sources needed for all configurations with given kind. */
+ std::vector<AllConfigSource> GetAllConfigSources(SourceKind kind) const;
+
+ /** Get all languages used to compile sources in any configuration.
+ This excludes the languages of objects from object libraries. */
+ std::set<std::string> GetAllConfigCompileLanguages() const;
+
+ void GetObjectSources(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ const std::string& GetObjectName(cmSourceFile const* file);
+ const char* GetCustomObjectExtension() const;
+
+ bool HasExplicitObjectName(cmSourceFile const* file) const;
+ void AddExplicitObjectName(cmSourceFile const* sf);
+
+ BTs<std::string> const* GetLanguageStandardProperty(
+ std::string const& lang, std::string const& config) const;
+
+ cmProp GetLanguageStandard(std::string const& lang,
+ std::string const& config) const;
+
+ cmProp GetLanguageExtensions(std::string const& lang) const;
+
+ bool GetLanguageStandardRequired(std::string const& lang) const;
+
+ void GetModuleDefinitionSources(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetExternalObjects(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetHeaderSources(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetExtraSources(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetCustomCommands(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+ void GetManifests(std::vector<cmSourceFile const*>&,
+ const std::string& config) const;
+
+ std::set<cmLinkItem> const& GetUtilityItems() const;
+
+ void ComputeObjectMapping();
+
+ cmProp GetFeature(const std::string& feature,
+ const std::string& config) const;
+
+ const char* GetLinkPIEProperty(const std::string& config) const;
+
+ bool IsIPOEnabled(std::string const& lang, std::string const& config) const;
+
+ bool IsLinkInterfaceDependentBoolProperty(const std::string& p,
+ const std::string& config) const;
+ bool IsLinkInterfaceDependentStringProperty(const std::string& p,
+ const std::string& config) const;
+ bool IsLinkInterfaceDependentNumberMinProperty(
+ const std::string& p, const std::string& config) const;
+ bool IsLinkInterfaceDependentNumberMaxProperty(
+ const std::string& p, const std::string& config) const;
+
+ bool GetLinkInterfaceDependentBoolProperty(const std::string& p,
+ const std::string& config) const;
+
+ const char* GetLinkInterfaceDependentStringProperty(
+ const std::string& p, const std::string& config) const;
+ const char* GetLinkInterfaceDependentNumberMinProperty(
+ const std::string& p, const std::string& config) const;
+ const char* GetLinkInterfaceDependentNumberMaxProperty(
+ const std::string& p, const std::string& config) const;
+
+ class DeviceLinkSetter
+ {
+ public:
+ DeviceLinkSetter(cmGeneratorTarget& target)
+ : Target(target)
+ {
+ this->PreviousState = target.SetDeviceLink(true);
+ }
+ ~DeviceLinkSetter() { this->Target.SetDeviceLink(this->PreviousState); };
+
+ private:
+ cmGeneratorTarget& Target;
+ bool PreviousState;
+ };
+
+ bool SetDeviceLink(bool deviceLink);
+ bool IsDeviceLink() const { return this->DeviceLink; }
+
+ cmLinkInterface const* GetLinkInterface(
+ const std::string& config, const cmGeneratorTarget* headTarget) const;
+ void ComputeLinkInterface(const std::string& config,
+ cmOptionalLinkInterface& iface,
+ const cmGeneratorTarget* head) const;
+
+ cmLinkInterfaceLibraries const* GetLinkInterfaceLibraries(
+ const std::string& config, const cmGeneratorTarget* headTarget,
+ bool usage_requirements_only) const;
+
+ void ComputeLinkInterfaceLibraries(const std::string& config,
+ cmOptionalLinkInterface& iface,
+ const cmGeneratorTarget* head,
+ bool usage_requirements_only) const;
+
+ /** Get the library name for an imported interface library. */
+ std::string GetImportedLibName(std::string const& config) const;
+
+ /** Get the full path to the target according to the settings in its
+ makefile and the configuration type. */
+ std::string GetFullPath(
+ const std::string& config,
+ cmStateEnums::ArtifactType artifact = cmStateEnums::RuntimeBinaryArtifact,
+ bool realname = false) const;
+ std::string NormalGetFullPath(const std::string& config,
+ cmStateEnums::ArtifactType artifact,
+ bool realname) const;
+ std::string NormalGetRealName(const std::string& config) const;
+
+ /** Get the names of an object library's object files underneath
+ its object file directory. */
+ void GetTargetObjectNames(std::string const& config,
+ std::vector<std::string>& objects) const;
+
+ /** What hierarchy level should the reported directory contain */
+ enum BundleDirectoryLevel
+ {
+ BundleDirLevel,
+ ContentLevel,
+ FullLevel
+ };
+
+ /** @return the Mac App directory without the base */
+ std::string GetAppBundleDirectory(const std::string& config,
+ BundleDirectoryLevel level) const;
+
+ /** Return whether this target is marked as deprecated by the
+ maintainer */
+ bool IsDeprecated() const;
+
+ /** Returns the deprecation message provided by the maintainer */
+ std::string GetDeprecation() const;
+
+ /** Return whether this target is an executable Bundle, a framework
+ or CFBundle on Apple. */
+ bool IsBundleOnApple() const;
+
+ /** Return whether this target is a Win32 executable */
+ bool IsWin32Executable(const std::string& config) const;
+
+ /** Get the full name of the target according to the settings in its
+ makefile. */
+ std::string GetFullName(const std::string& config,
+ cmStateEnums::ArtifactType artifact =
+ cmStateEnums::RuntimeBinaryArtifact) const;
+
+ /** @return the Mac framework directory without the base. */
+ std::string GetFrameworkDirectory(const std::string& config,
+ BundleDirectoryLevel level) const;
+
+ /** Return the framework version string. Undefined if
+ IsFrameworkOnApple returns false. */
+ std::string GetFrameworkVersion() const;
+
+ /** @return the Mac CFBundle directory without the base */
+ std::string GetCFBundleDirectory(const std::string& config,
+ BundleDirectoryLevel level) const;
+
+ /** Return the install name directory for the target in the
+ * build tree. For example: "\@rpath/", "\@loader_path/",
+ * or "/full/path/to/library". */
+ std::string GetInstallNameDirForBuildTree(const std::string& config) const;
+
+ /** Return the install name directory for the target in the
+ * install tree. For example: "\@rpath/" or "\@loader_path/". */
+ std::string GetInstallNameDirForInstallTree(
+ const std::string& config, const std::string& installPrefix) const;
+
+ cmListFileBacktrace GetBacktrace() const;
+
+ std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const;
+
+ bool LinkLanguagePropagatesToDependents() const
+ {
+ return this->GetType() == cmStateEnums::STATIC_LIBRARY;
+ }
+
+ /** Get the macro to define when building sources in this target.
+ If no macro should be defined null is returned. */
+ const std::string* GetExportMacro() const;
+
+ /** Get the soname of the target. Allowed only for a shared library. */
+ std::string GetSOName(const std::string& config) const;
+
+ void GetFullNameComponents(std::string& prefix, std::string& base,
+ std::string& suffix, const std::string& config,
+ cmStateEnums::ArtifactType artifact =
+ cmStateEnums::RuntimeBinaryArtifact) const;
+
+ /** Append to @a base the bundle directory hierarchy up to a certain @a level
+ * and return it. */
+ std::string BuildBundleDirectory(const std::string& base,
+ const std::string& config,
+ BundleDirectoryLevel level) const;
+
+ /** @return the mac content directory for this target. */
+ std::string GetMacContentDirectory(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const;
+
+ /** @return folder prefix for IDEs. */
+ std::string GetEffectiveFolderName() const;
+
+ cmTarget* Target;
+ cmMakefile* Makefile;
+ cmLocalGenerator* LocalGenerator;
+ cmGlobalGenerator const* GlobalGenerator;
+
+ struct ModuleDefinitionInfo
+ {
+ std::string DefFile;
+ bool DefFileGenerated;
+ bool WindowsExportAllSymbols;
+ std::vector<cmSourceFile const*> Sources;
+ };
+ ModuleDefinitionInfo const* GetModuleDefinitionInfo(
+ std::string const& config) const;
+
+ /** Return whether or not the target is for a DLL platform. */
+ bool IsDLLPlatform() const;
+
+ /** @return whether this target have a well defined output file name. */
+ bool HaveWellDefinedOutputFiles() const;
+
+ /** Link information from the transitive closure of the link
+ implementation and the interfaces of its dependencies. */
+ struct LinkClosure
+ {
+ // The preferred linker language.
+ std::string LinkerLanguage;
+
+ // Languages whose runtime libraries must be linked.
+ std::vector<std::string> Languages;
+ };
+
+ LinkClosure const* GetLinkClosure(const std::string& config) const;
+
+ cmLinkImplementation const* GetLinkImplementation(
+ const std::string& config) const;
+
+ void ComputeLinkImplementationLanguages(
+ const std::string& config, cmOptionalLinkImplementation& impl) const;
+
+ cmLinkImplementationLibraries const* GetLinkImplementationLibraries(
+ const std::string& config) const;
+
+ void ComputeLinkImplementationLibraries(const std::string& config,
+ cmOptionalLinkImplementation& impl,
+ const cmGeneratorTarget* head) const;
+
+ struct TargetOrString
+ {
+ std::string String;
+ cmGeneratorTarget* Target = nullptr;
+ };
+ TargetOrString ResolveTargetReference(std::string const& name) const;
+ TargetOrString ResolveTargetReference(std::string const& name,
+ cmLocalGenerator const* lg) const;
+
+ cmLinkItem ResolveLinkItem(std::string const& name,
+ cmListFileBacktrace const& bt) const;
+ cmLinkItem ResolveLinkItem(std::string const& name,
+ cmListFileBacktrace const& bt,
+ cmLocalGenerator const* lg) const;
+
+ // Compute the set of languages compiled by the target. This is
+ // computed every time it is called because the languages can change
+ // when source file properties are changed and we do not have enough
+ // information to forward these property changes to the targets
+ // until we have per-target object file properties.
+ void GetLanguages(std::set<std::string>& languages,
+ std::string const& config) const;
+ bool IsLanguageUsed(std::string const& language,
+ std::string const& config) const;
+
+ bool IsCSharpOnly() const;
+
+ void GetObjectLibrariesCMP0026(
+ std::vector<cmGeneratorTarget*>& objlibs) const;
+
+ std::string GetFullNameImported(const std::string& config,
+ cmStateEnums::ArtifactType artifact) const;
+
+ /** Get source files common to all configurations and diagnose cases
+ with per-config sources. Excludes sources added by a TARGET_OBJECTS
+ generator expression. Do not use outside the Xcode generator. */
+ bool GetConfigCommonSourceFilesForXcode(
+ std::vector<cmSourceFile*>& files) const;
+
+ bool HaveBuildTreeRPATH(const std::string& config) const;
+
+ /** Full path with trailing slash to the top-level directory
+ holding object files for this target. Includes the build
+ time config name placeholder if needed for the generator. */
+ std::string ObjectDirectory;
+
+ /** Full path with trailing slash to the top-level directory
+ holding object files for the given configuration. */
+ std::string GetObjectDirectory(std::string const& config) const;
+
+ void GetAppleArchs(const std::string& config,
+ std::vector<std::string>& archVec) const;
+
+ void AddExplicitLanguageFlags(std::string& flags,
+ cmSourceFile const& sf) const;
+
+ void AddCUDAArchitectureFlags(std::string& flags) const;
+ void AddCUDAToolkitFlags(std::string& flags) const;
+
+ void AddISPCTargetFlags(std::string& flags) const;
+
+ std::string GetFeatureSpecificLinkRuleVariable(
+ std::string const& var, std::string const& lang,
+ std::string const& config) const;
+
+ /** Return the rule variable used to create this type of target. */
+ std::string GetCreateRuleVariable(std::string const& lang,
+ std::string const& config) const;
+
+ /** Get the include directories for this target. */
+ std::vector<BT<std::string>> GetIncludeDirectories(
+ const std::string& config, const std::string& lang) const;
+
+ void GetCompileOptions(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const;
+ std::vector<BT<std::string>> GetCompileOptions(
+ std::string const& config, std::string const& language) const;
+
+ void GetCompileFeatures(std::vector<std::string>& features,
+ const std::string& config) const;
+ std::vector<BT<std::string>> GetCompileFeatures(
+ std::string const& config) const;
+
+ void GetCompileDefinitions(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const;
+ std::vector<BT<std::string>> GetCompileDefinitions(
+ std::string const& config, std::string const& language) const;
+
+ void GetLinkOptions(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const;
+ std::vector<BT<std::string>> GetLinkOptions(
+ std::string const& config, std::string const& language) const;
+
+ void GetStaticLibraryLinkOptions(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const;
+ std::vector<BT<std::string>> GetStaticLibraryLinkOptions(
+ std::string const& config, std::string const& language) const;
+
+ void GetLinkDirectories(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const;
+ std::vector<BT<std::string>> GetLinkDirectories(
+ std::string const& config, std::string const& language) const;
+
+ void GetLinkDepends(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const;
+ std::vector<BT<std::string>> GetLinkDepends(
+ std::string const& config, std::string const& language) const;
+
+ std::vector<BT<std::string>> GetPrecompileHeaders(
+ const std::string& config, const std::string& language) const;
+
+ std::string GetPchHeader(const std::string& config,
+ const std::string& language,
+ const std::string& arch = std::string()) const;
+ std::string GetPchSource(const std::string& config,
+ const std::string& language,
+ const std::string& arch = std::string()) const;
+ std::string GetPchFileObject(const std::string& config,
+ const std::string& language,
+ const std::string& arch = std::string());
+ std::string GetPchFile(const std::string& config,
+ const std::string& language,
+ const std::string& arch = std::string());
+ std::string GetPchCreateCompileOptions(
+ const std::string& config, const std::string& language,
+ const std::string& arch = std::string());
+ std::string GetPchUseCompileOptions(const std::string& config,
+ const std::string& language,
+ const std::string& arch = std::string());
+
+ void AddSourceFileToUnityBatch(const std::string& sourceFilename);
+ bool IsSourceFilePartOfUnityBatch(const std::string& sourceFilename) const;
+
+ bool IsSystemIncludeDirectory(const std::string& dir,
+ const std::string& config,
+ const std::string& language) const;
+
+ /** Add the target output files to the global generator manifest. */
+ void ComputeTargetManifest(const std::string& config) const;
+
+ bool ComputeCompileFeatures(std::string const& config) const;
+
+ using LanguagePair = std::pair<std::string, std::string>;
+ bool ComputeCompileFeatures(
+ std::string const& config,
+ std::set<LanguagePair> const& languagePairs) const;
+
+ /**
+ * Trace through the source files in this target and add al source files
+ * that they depend on, used by all generators
+ */
+ void TraceDependencies();
+
+ /** Get the directory in which this target will be built. If the
+ configuration name is given then the generator will add its
+ subdirectory for that configuration. Otherwise just the canonical
+ output directory is given. */
+ std::string GetDirectory(const std::string& config,
+ cmStateEnums::ArtifactType artifact =
+ cmStateEnums::RuntimeBinaryArtifact) const;
+
+ /** Get the directory in which to place the target compiler .pdb file.
+ If the configuration name is given then the generator will add its
+ subdirectory for that configuration. Otherwise just the canonical
+ compiler pdb output directory is given. */
+ std::string GetCompilePDBDirectory(const std::string& config) const;
+
+ /** Get sources that must be built before the given source. */
+ std::vector<cmSourceFile*> const* GetSourceDepends(
+ cmSourceFile const* sf) const;
+
+ /** Return whether this target uses the default value for its output
+ directory. */
+ bool UsesDefaultOutputDir(const std::string& config,
+ cmStateEnums::ArtifactType artifact) const;
+
+ // Cache target output paths for each configuration.
+ struct OutputInfo
+ {
+ std::string OutDir;
+ std::string ImpDir;
+ std::string PdbDir;
+ bool empty() const
+ {
+ return this->OutDir.empty() && this->ImpDir.empty() &&
+ this->PdbDir.empty();
+ }
+ };
+
+ OutputInfo const* GetOutputInfo(const std::string& config) const;
+
+ // Get the target PDB base name.
+ std::string GetPDBOutputName(const std::string& config) const;
+
+ /** Get the name of the pdb file for the target. */
+ std::string GetPDBName(const std::string& config) const;
+
+ /** Whether this library has soname enabled and platform supports it. */
+ bool HasSOName(const std::string& config) const;
+
+ struct CompileInfo
+ {
+ std::string CompilePdbDir;
+ };
+
+ CompileInfo const* GetCompileInfo(const std::string& config) const;
+
+ using CompileInfoMapType = std::map<std::string, CompileInfo>;
+ mutable CompileInfoMapType CompileInfoMap;
+
+ bool IsNullImpliedByLinkLibraries(const std::string& p) const;
+
+ /** Get the name of the compiler pdb file for the target. */
+ std::string GetCompilePDBName(const std::string& config) const;
+
+ /** Get the path for the MSVC /Fd option for this target. */
+ std::string GetCompilePDBPath(const std::string& config) const;
+
+ // Get the target base name.
+ std::string GetOutputName(const std::string& config,
+ cmStateEnums::ArtifactType artifact) const;
+
+ /** Get target file prefix */
+ std::string GetFilePrefix(const std::string& config,
+ cmStateEnums::ArtifactType artifact =
+ cmStateEnums::RuntimeBinaryArtifact) const;
+ /** Get target file prefix */
+ std::string GetFileSuffix(const std::string& config,
+ cmStateEnums::ArtifactType artifact =
+ cmStateEnums::RuntimeBinaryArtifact) const;
+
+ /** Get target file postfix */
+ std::string GetFilePostfix(const std::string& config) const;
+
+ /** Get framework multi-config-specific postfix */
+ std::string GetFrameworkMultiConfigPostfix(const std::string& config) const;
+
+ /** Clears cached meta data for local and external source files.
+ * The meta data will be recomputed on demand.
+ */
+ void ClearSourcesCache();
+
+ void AddSource(const std::string& src, bool before = false);
+ void AddTracedSources(std::vector<std::string> const& srcs);
+
+ /**
+ * Adds an entry to the INCLUDE_DIRECTORIES list.
+ * If before is true the entry is pushed at the front.
+ */
+ void AddIncludeDirectory(const std::string& src, bool before = false);
+
+ /**
+ * Flags for a given source file as used in this target. Typically assigned
+ * via SET_TARGET_PROPERTIES when the property is a list of source files.
+ */
+ enum SourceFileType
+ {
+ SourceFileTypeNormal,
+ SourceFileTypePrivateHeader, // is in "PRIVATE_HEADER" target property
+ SourceFileTypePublicHeader, // is in "PUBLIC_HEADER" target property
+ SourceFileTypeResource, // is in "RESOURCE" target property *or*
+ // has MACOSX_PACKAGE_LOCATION=="Resources"
+ SourceFileTypeDeepResource, // MACOSX_PACKAGE_LOCATION starts with
+ // "Resources/"
+ SourceFileTypeMacContent // has MACOSX_PACKAGE_LOCATION!="Resources[/]"
+ };
+ struct SourceFileFlags
+ {
+ SourceFileType Type = SourceFileTypeNormal;
+ const char* MacFolder = nullptr; // location inside Mac content folders
+ };
+ void GetAutoUicOptions(std::vector<std::string>& result,
+ const std::string& config) const;
+
+ struct Names
+ {
+ std::string Base;
+ std::string Output;
+ std::string Real;
+ std::string ImportLibrary;
+ std::string PDB;
+ std::string SharedObject;
+ };
+
+ /** Get the names of the executable needed to generate a build rule
+ that takes into account executable version numbers. This should
+ be called only on an executable target. */
+ Names GetExecutableNames(const std::string& config) const;
+
+ /** Get the names of the library needed to generate a build rule
+ that takes into account shared library version numbers. This
+ should be called only on a library target. */
+ Names GetLibraryNames(const std::string& config) const;
+
+ /**
+ * Compute whether this target must be relinked before installing.
+ */
+ bool NeedRelinkBeforeInstall(const std::string& config) const;
+
+ /** Return true if builtin chrpath will work for this target */
+ bool IsChrpathUsed(const std::string& config) const;
+
+ /** Get the directory in which this targets .pdb files will be placed.
+ If the configuration name is given then the generator will add its
+ subdirectory for that configuration. Otherwise just the canonical
+ pdb output directory is given. */
+ std::string GetPDBDirectory(const std::string& config) const;
+
+ //! Return the preferred linker language for this target
+ std::string GetLinkerLanguage(const std::string& config) const;
+
+ /** Does this target have a GNU implib to convert to MS format? */
+ bool HasImplibGNUtoMS(std::string const& config) const;
+
+ /** Convert the given GNU import library name (.dll.a) to a name with a new
+ extension (.lib or ${CMAKE_IMPORT_LIBRARY_SUFFIX}). */
+ bool GetImplibGNUtoMS(std::string const& config, std::string const& gnuName,
+ std::string& out, const char* newExt = nullptr) const;
+
+ /** Can only ever return true if GetSourceFilePaths() was called before.
+ Otherwise, this is indeterminate and false will be assumed/returned! */
+ bool HasContextDependentSources() const;
+
+ bool IsExecutableWithExports() const;
+
+ /** Return whether or not the target has a DLL import library. */
+ bool HasImportLibrary(std::string const& config) const;
+
+ /** Get a build-tree directory in which to place target support files. */
+ std::string GetSupportDirectory() const;
+
+ /** Return whether this target may be used to link another target. */
+ bool IsLinkable() const;
+
+ /** Return whether this target is a shared library Framework on
+ Apple. */
+ bool IsFrameworkOnApple() const;
+
+ /** Return whether this target is an executable Bundle on Apple. */
+ bool IsAppBundleOnApple() const;
+
+ /** Return whether this target is a XCTest on Apple. */
+ bool IsXCTestOnApple() const;
+
+ /** Return whether this target is a CFBundle (plugin) on Apple. */
+ bool IsCFBundleOnApple() const;
+
+ /** Assembly types. The order of the values of this enum is relevant
+ because of smaller/larger comparison operations! */
+ enum ManagedType
+ {
+ Undefined = 0, // target is no lib or executable
+ Native, // target compiles to unmanaged binary.
+ Mixed, // target compiles to mixed (managed and unmanaged) binary.
+ Managed // target compiles to managed binary.
+ };
+
+ /** Return the type of assembly this target compiles to. */
+ ManagedType GetManagedType(const std::string& config) const;
+
+ struct SourceFileFlags GetTargetSourceFileFlags(
+ const cmSourceFile* sf) const;
+
+ void ReportPropertyOrigin(const std::string& p, const std::string& result,
+ const std::string& report,
+ const std::string& compatibilityType) const;
+
+ class TargetPropertyEntry;
+
+ std::string EvaluateInterfaceProperty(
+ std::string const& prop, cmGeneratorExpressionContext* context,
+ cmGeneratorExpressionDAGChecker* dagCheckerParent,
+ bool usage_requirements_only = true) const;
+
+ bool HaveInstallTreeRPATH(const std::string& config) const;
+
+ bool GetBuildRPATH(const std::string& config, std::string& rpath) const;
+ bool GetInstallRPATH(const std::string& config, std::string& rpath) const;
+
+ /** Whether this library has \@rpath and platform supports it. */
+ bool HasMacOSXRpathInstallNameDir(const std::string& config) const;
+
+ /** Whether this library defaults to \@rpath. */
+ bool MacOSXRpathInstallNameDirDefault() const;
+
+ enum InstallNameType
+ {
+ INSTALL_NAME_FOR_BUILD,
+ INSTALL_NAME_FOR_INSTALL
+ };
+ /** Whether to use INSTALL_NAME_DIR. */
+ bool MacOSXUseInstallNameDir() const;
+ /** Whether to generate an install_name. */
+ bool CanGenerateInstallNameDir(InstallNameType t) const;
+
+ /** Test for special case of a third-party shared library that has
+ no soname at all. */
+ bool IsImportedSharedLibWithoutSOName(const std::string& config) const;
+
+ std::string ImportedGetLocation(const std::string& config) const;
+
+ /** Get the target major and minor version numbers interpreted from
+ the VERSION property. Version 0 is returned if the property is
+ not set or cannot be parsed. */
+ void GetTargetVersion(int& major, int& minor) const;
+
+ /** Get the target major, minor, and patch version numbers
+ interpreted from the given property. Version 0
+ is returned if the property is not set or cannot be parsed. */
+ void GetTargetVersion(std::string const& property, int& major, int& minor,
+ int& patch) const;
+
+ /** Get the target major, minor, and patch version numbers
+ interpreted from the given property and if empty use the
+ fallback property. Version 0 is returned if the property is
+ not set or cannot be parsed. */
+ void GetTargetVersionFallback(const std::string& property,
+ const std::string& fallback_property,
+ int& major, int& minor, int& patch) const;
+
+ std::string GetRuntimeLinkLibrary(std::string const& lang,
+ std::string const& config) const;
+
+ std::string GetFortranModuleDirectory(std::string const& working_dir) const;
+
+ const std::string& GetSourcesProperty() const;
+
+ void AddISPCGeneratedHeader(std::string const& header,
+ std::string const& config);
+ std::vector<std::string> GetGeneratedISPCHeaders(
+ std::string const& config) const;
+
+ void AddISPCGeneratedObject(std::vector<std::string>&& objs,
+ std::string const& config);
+ std::vector<std::string> GetGeneratedISPCObjects(
+ std::string const& config) const;
+
+private:
+ void AddSourceCommon(const std::string& src, bool before = false);
+
+ std::string CreateFortranModuleDirectory(
+ std::string const& working_dir) const;
+ mutable bool FortranModuleDirectoryCreated;
+ mutable std::string FortranModuleDirectory;
+
+ friend class cmTargetTraceDependencies;
+ struct SourceEntry
+ {
+ std::vector<cmSourceFile*> Depends;
+ };
+ using SourceEntriesType = std::map<cmSourceFile const*, SourceEntry>;
+ SourceEntriesType SourceDepends;
+ 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;
+
+ void ConstructSourceFileFlags() const;
+ mutable bool SourceFileFlagsConstructed;
+ mutable std::map<cmSourceFile const*, SourceFileFlags> SourceFlagsMap;
+
+ mutable std::map<std::string, bool> DebugCompatiblePropertiesDone;
+
+ bool NeedImportLibraryName(std::string const& config) 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;
+ void GetFullNameInternal(const std::string& config,
+ cmStateEnums::ArtifactType artifact,
+ std::string& outPrefix, std::string& outBase,
+ std::string& outSuffix) const;
+
+ mutable std::string LinkerLanguage;
+ using LinkClosureMapType = std::map<std::string, LinkClosure>;
+ mutable LinkClosureMapType LinkClosureMap;
+ bool DeviceLink = false;
+
+ // Returns ARCHIVE, LIBRARY, or RUNTIME based on platform and type.
+ const char* GetOutputTargetType(cmStateEnums::ArtifactType artifact) const;
+
+ void ComputeVersionedName(std::string& vName, std::string const& prefix,
+ std::string const& base, std::string const& suffix,
+ std::string const& name,
+ const char* version) const;
+
+ struct CompatibleInterfacesBase
+ {
+ std::set<std::string> PropsBool;
+ std::set<std::string> PropsString;
+ std::set<std::string> PropsNumberMax;
+ std::set<std::string> PropsNumberMin;
+ };
+ CompatibleInterfacesBase const& GetCompatibleInterfaces(
+ std::string const& config) const;
+
+ struct CompatibleInterfaces : public CompatibleInterfacesBase
+ {
+ bool Done = false;
+ };
+ mutable std::map<std::string, CompatibleInterfaces> CompatibleInterfacesMap;
+
+ using cmTargetLinkInformationMap =
+ std::map<std::string, std::unique_ptr<cmComputeLinkInformation>>;
+ mutable cmTargetLinkInformationMap LinkInformation;
+
+ void CheckPropertyCompatibility(cmComputeLinkInformation& info,
+ const std::string& config) const;
+
+ void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const;
+ bool ComputeLinkClosure(const std::string& config, LinkClosure& lc,
+ bool secondPass) const;
+
+ struct LinkImplClosure : public std::vector<cmGeneratorTarget const*>
+ {
+ bool Done = false;
+ };
+ mutable std::map<std::string, LinkImplClosure> LinkImplClosureMap;
+
+ using LinkInterfaceMapType = std::map<std::string, cmHeadToLinkInterfaceMap>;
+ mutable LinkInterfaceMapType LinkInterfaceMap;
+ mutable LinkInterfaceMapType LinkInterfaceUsageRequirementsOnlyMap;
+
+ cmHeadToLinkInterfaceMap& GetHeadToLinkInterfaceMap(
+ std::string const& config) const;
+ cmHeadToLinkInterfaceMap& GetHeadToLinkInterfaceUsageRequirementsMap(
+ std::string const& config) const;
+
+ std::string GetLinkInterfaceDependentStringAsBoolProperty(
+ const std::string& p, const std::string& config) const;
+
+ friend class cmTargetCollectLinkLanguages;
+ cmLinkInterface const* GetLinkInterface(const std::string& config,
+ const cmGeneratorTarget* headTarget,
+ bool secondPass) const;
+ void ComputeLinkInterface(const std::string& config,
+ cmOptionalLinkInterface& iface,
+ const cmGeneratorTarget* head,
+ bool secondPass) const;
+ cmLinkImplementation const* GetLinkImplementation(const std::string& config,
+ bool secondPass) const;
+
+ // Cache import information from properties for each configuration.
+ struct ImportInfo
+ {
+ bool NoSOName = false;
+ ManagedType Managed = Native;
+ unsigned int Multiplicity = 0;
+ std::string Location;
+ std::string SOName;
+ std::string ImportLibrary;
+ std::string LibName;
+ std::string Languages;
+ std::string Libraries;
+ std::string LibrariesProp;
+ std::string SharedDeps;
+ };
+
+ using ImportInfoMapType = std::map<std::string, ImportInfo>;
+ mutable ImportInfoMapType ImportInfoMap;
+ void ComputeImportInfo(std::string const& desired_config,
+ ImportInfo& info) const;
+ ImportInfo const* GetImportInfo(const std::string& config) const;
+
+ /** Strip off leading and trailing whitespace from an item named in
+ the link dependencies of this target. */
+ std::string CheckCMP0004(std::string const& item) const;
+
+ cmLinkInterface const* GetImportLinkInterface(const std::string& config,
+ const cmGeneratorTarget* head,
+ bool usage_requirements_only,
+ bool secondPass = false) const;
+
+ using KindedSourcesMapType = std::map<std::string, KindedSources>;
+ mutable KindedSourcesMapType KindedSourcesMap;
+ void ComputeKindedSources(KindedSources& files,
+ std::string const& config) const;
+
+ mutable std::vector<AllConfigSource> AllConfigSources;
+ void ComputeAllConfigSources() const;
+
+ mutable std::unordered_map<std::string, bool> MaybeInterfacePropertyExists;
+ bool MaybeHaveInterfaceProperty(std::string const& prop,
+ cmGeneratorExpressionContext* context,
+ bool usage_requirements_only) const;
+
+ using TargetPropertyEntryVector =
+ std::vector<std::unique_ptr<TargetPropertyEntry>>;
+
+ TargetPropertyEntryVector IncludeDirectoriesEntries;
+ TargetPropertyEntryVector CompileOptionsEntries;
+ TargetPropertyEntryVector CompileFeaturesEntries;
+ TargetPropertyEntryVector CompileDefinitionsEntries;
+ TargetPropertyEntryVector LinkOptionsEntries;
+ TargetPropertyEntryVector LinkDirectoriesEntries;
+ TargetPropertyEntryVector PrecompileHeadersEntries;
+ TargetPropertyEntryVector SourceEntries;
+ mutable std::set<std::string> LinkImplicitNullProperties;
+ mutable std::map<std::string, std::string> PchHeaders;
+ mutable std::map<std::string, std::string> PchSources;
+ mutable std::map<std::string, std::string> PchObjectFiles;
+ mutable std::map<std::string, std::string> PchFiles;
+ mutable std::map<std::string, std::string> PchCreateCompileOptions;
+ mutable std::map<std::string, std::string> PchUseCompileOptions;
+
+ std::unordered_set<std::string> UnityBatchedSourceFiles;
+
+ std::unordered_map<std::string, std::vector<std::string>>
+ ISPCGeneratedHeaders;
+ std::unordered_map<std::string, std::vector<std::string>>
+ ISPCGeneratedObjects;
+
+ bool IsLinkLookupScope(std::string const& n,
+ cmLocalGenerator const*& lg) const;
+
+ void ExpandLinkItems(std::string const& prop, std::string const& value,
+ std::string const& config,
+ const cmGeneratorTarget* headTarget,
+ bool usage_requirements_only,
+ std::vector<cmLinkItem>& items,
+ bool& hadHeadSensitiveCondition,
+ bool& hadContextSensitiveCondition,
+ bool& hadLinkLanguageSensitiveCondition) const;
+ void LookupLinkItems(std::vector<std::string> const& names,
+ cmListFileBacktrace const& bt,
+ std::vector<cmLinkItem>& items) const;
+
+ std::vector<BT<std::string>> GetSourceFilePaths(
+ std::string const& config) const;
+ std::vector<BT<cmSourceFile*>> GetSourceFilesWithoutObjectLibraries(
+ std::string const& config) const;
+ void GetSourceFilesWithoutObjectLibraries(std::vector<cmSourceFile*>& files,
+ const std::string& config) const;
+
+ struct HeadToLinkImplementationMap
+ : public std::map<cmGeneratorTarget const*, cmOptionalLinkImplementation>
+ {
+ };
+ using LinkImplMapType = std::map<std::string, HeadToLinkImplementationMap>;
+ mutable LinkImplMapType LinkImplMap;
+
+ cmLinkImplementationLibraries const* GetLinkImplementationLibrariesInternal(
+ const std::string& config, const cmGeneratorTarget* head) const;
+ bool ComputeOutputDir(const std::string& config,
+ cmStateEnums::ArtifactType artifact,
+ std::string& out) const;
+
+ using OutputInfoMapType = std::map<std::string, OutputInfo>;
+ mutable OutputInfoMapType OutputInfoMap;
+
+ using ModuleDefinitionInfoMapType =
+ std::map<std::string, ModuleDefinitionInfo>;
+ mutable ModuleDefinitionInfoMapType ModuleDefinitionInfoMap;
+ void ComputeModuleDefinitionInfo(std::string const& config,
+ ModuleDefinitionInfo& info) const;
+
+ using OutputNameKey = std::pair<std::string, cmStateEnums::ArtifactType>;
+ using OutputNameMapType = std::map<OutputNameKey, std::string>;
+ mutable OutputNameMapType OutputNameMap;
+ mutable std::set<cmLinkItem> UtilityItems;
+ cmPolicies::PolicyMap PolicyMap;
+ mutable bool PolicyWarnedCMP0022;
+ mutable bool PolicyReportedCMP0069;
+ mutable bool DebugIncludesDone;
+ mutable bool DebugCompileOptionsDone;
+ mutable bool DebugCompileFeaturesDone;
+ mutable bool DebugCompileDefinitionsDone;
+ mutable bool DebugLinkOptionsDone;
+ mutable bool DebugLinkDirectoriesDone;
+ mutable bool DebugPrecompileHeadersDone;
+ mutable bool DebugSourcesDone;
+ mutable bool UtilityItemsDone;
+ enum class Tribool
+ {
+ False = 0x0,
+ True = 0x1,
+ Indeterminate = 0x2
+ };
+ mutable Tribool SourcesAreContextDependent;
+
+ bool ComputePDBOutputDir(const std::string& kind, const std::string& config,
+ std::string& out) const;
+
+ ManagedType CheckManagedType(std::string const& propval) const;
+
+ bool GetRPATH(const std::string& config, const std::string& prop,
+ std::string& rpath) const;
+
+ mutable std::map<std::string, BTs<std::string>> LanguageStandardMap;
+
+ cmProp GetPropertyWithPairedLanguageSupport(std::string const& lang,
+ const char* suffix) const;
+
+public:
+ const std::vector<const cmGeneratorTarget*>& GetLinkImplementationClosure(
+ const std::string& config) const;
+
+ mutable std::map<std::string, std::string> MaxLanguageStandards;
+ std::map<std::string, std::string> const& GetMaxLanguageStandards() const
+ {
+ return this->MaxLanguageStandards;
+ }
+
+ struct StrictTargetComparison
+ {
+ bool operator()(cmGeneratorTarget const* t1,
+ cmGeneratorTarget const* t2) const;
+ };
+};
diff --git a/Source/cmGetCMakePropertyCommand.cxx b/Source/cmGetCMakePropertyCommand.cxx
new file mode 100644
index 0000000..79cbe44
--- /dev/null
+++ b/Source/cmGetCMakePropertyCommand.cxx
@@ -0,0 +1,52 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGetCMakePropertyCommand.h"
+
+#include <set>
+
+#include "cmExecutionStatus.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+
+// cmGetCMakePropertyCommand
+bool cmGetCMakePropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::string const& variable = args[0];
+ std::string output = "NOTFOUND";
+
+ if (args[1] == "VARIABLES") {
+ if (cmProp varsProp = status.GetMakefile().GetProperty("VARIABLES")) {
+ output = *varsProp;
+ }
+ } else if (args[1] == "MACROS") {
+ output.clear();
+ if (cmProp macrosProp = status.GetMakefile().GetProperty("MACROS")) {
+ output = *macrosProp;
+ }
+ } else if (args[1] == "COMPONENTS") {
+ const std::set<std::string>* components =
+ status.GetMakefile().GetGlobalGenerator()->GetInstallComponents();
+ output = cmJoin(*components, ";");
+ } else {
+ cmProp prop = nullptr;
+ if (!args[1].empty()) {
+ prop = status.GetMakefile().GetState()->GetGlobalProperty(args[1]);
+ }
+ if (prop) {
+ output = *prop;
+ }
+ }
+
+ status.GetMakefile().AddDefinition(variable, output);
+
+ return true;
+}
diff --git a/Source/cmGetCMakePropertyCommand.h b/Source/cmGetCMakePropertyCommand.h
new file mode 100644
index 0000000..3a2e702
--- /dev/null
+++ b/Source/cmGetCMakePropertyCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmGetCMakePropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmGetDirectoryPropertyCommand.cxx b/Source/cmGetDirectoryPropertyCommand.cxx
new file mode 100644
index 0000000..7fbd479
--- /dev/null
+++ b/Source/cmGetDirectoryPropertyCommand.cxx
@@ -0,0 +1,108 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGetDirectoryPropertyCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmSystemTools.h"
+
+namespace {
+void StoreResult(cmMakefile& makefile, std::string const& variable,
+ const char* prop);
+}
+
+// cmGetDirectoryPropertyCommand
+bool cmGetDirectoryPropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ auto i = args.begin();
+ std::string const& variable = *i;
+ ++i;
+
+ // get the directory argument if there is one
+ cmMakefile* dir = &status.GetMakefile();
+ if (*i == "DIRECTORY") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError(
+ "DIRECTORY argument provided without subsequent arguments");
+ return false;
+ }
+ std::string sd = cmSystemTools::CollapseFullPath(
+ *i, status.GetMakefile().GetCurrentSourceDirectory());
+
+ // lookup the makefile from the directory name
+ dir = status.GetMakefile().GetGlobalGenerator()->FindMakefile(sd);
+ if (!dir) {
+ status.SetError(
+ "DIRECTORY argument provided but requested directory not found. "
+ "This could be because the directory argument was invalid or, "
+ "it is valid but has not been processed yet.");
+ return false;
+ }
+ ++i;
+ if (i == args.end()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ }
+
+ // OK, now we have the directory to process, we just get the requested
+ // information out of it
+
+ if (*i == "DEFINITION") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("A request for a variable definition was made without "
+ "providing the name of the variable to get.");
+ return false;
+ }
+ std::string const& output = dir->GetSafeDefinition(*i);
+ status.GetMakefile().AddDefinition(variable, output);
+ return true;
+ }
+
+ if (i->empty()) {
+ status.SetError("given empty string for the property name to get");
+ return false;
+ }
+
+ const char* prop = nullptr;
+ if (*i == "DEFINITIONS") {
+ switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0059)) {
+ case cmPolicies::WARN:
+ status.GetMakefile().IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0059));
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ StoreResult(status.GetMakefile(), variable,
+ status.GetMakefile().GetDefineFlagsCMP0059());
+ return true;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ break;
+ }
+ }
+ prop = cmToCStr(dir->GetProperty(*i));
+ StoreResult(status.GetMakefile(), variable, prop);
+ return true;
+}
+
+namespace {
+void StoreResult(cmMakefile& makefile, std::string const& variable,
+ const char* prop)
+{
+ makefile.AddDefinition(variable, prop ? prop : "");
+}
+}
diff --git a/Source/cmGetDirectoryPropertyCommand.h b/Source/cmGetDirectoryPropertyCommand.h
new file mode 100644
index 0000000..4b0883c
--- /dev/null
+++ b/Source/cmGetDirectoryPropertyCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmGetDirectoryPropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx
new file mode 100644
index 0000000..40e8a05
--- /dev/null
+++ b/Source/cmGetFilenameComponentCommand.cxx
@@ -0,0 +1,140 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGetFilenameComponentCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+// cmGetFilenameComponentCommand
+bool cmGetFilenameComponentCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("called with incorrect number of arguments");
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ // Check and see if the value has been stored in the cache
+ // already, if so use that value
+ if (args.size() >= 4 && args.back() == "CACHE") {
+ cmProp cacheValue = status.GetMakefile().GetDefinition(args.front());
+ if (cacheValue && !cmIsNOTFOUND(*cacheValue)) {
+ return true;
+ }
+ }
+
+ std::string result;
+ std::string filename = args[1];
+ if (filename.find("[HKEY") != std::string::npos) {
+ // Check the registry as the target application would view it.
+ cmSystemTools::KeyWOW64 view = cmSystemTools::KeyWOW64_32;
+ cmSystemTools::KeyWOW64 other_view = cmSystemTools::KeyWOW64_64;
+ if (status.GetMakefile().PlatformIs64Bit()) {
+ view = cmSystemTools::KeyWOW64_64;
+ other_view = cmSystemTools::KeyWOW64_32;
+ }
+ cmSystemTools::ExpandRegistryValues(filename, view);
+ if (filename.find("/registry") != std::string::npos) {
+ std::string other = args[1];
+ cmSystemTools::ExpandRegistryValues(other, other_view);
+ if (other.find("/registry") == std::string::npos) {
+ filename = other;
+ }
+ }
+ }
+ std::string storeArgs;
+ std::string programArgs;
+ if (args[2] == "DIRECTORY" || args[2] == "PATH") {
+ result = cmSystemTools::GetFilenamePath(filename);
+ } else if (args[2] == "NAME") {
+ result = cmSystemTools::GetFilenameName(filename);
+ } else if (args[2] == "PROGRAM") {
+ for (unsigned int i = 2; i < args.size(); ++i) {
+ if (args[i] == "PROGRAM_ARGS") {
+ i++;
+ if (i < args.size()) {
+ storeArgs = args[i];
+ }
+ }
+ }
+
+ // First assume the path to the program was specified with no
+ // arguments and with no quoting or escaping for spaces.
+ // Only bother doing this if there is non-whitespace.
+ if (!cmTrimWhitespace(filename).empty()) {
+ result = cmSystemTools::FindProgram(filename);
+ }
+
+ // If that failed then assume a command-line string was given
+ // and split the program part from the rest of the arguments.
+ if (result.empty()) {
+ std::string program;
+ if (cmSystemTools::SplitProgramFromArgs(filename, program,
+ programArgs)) {
+ if (cmSystemTools::FileExists(program)) {
+ result = program;
+ } else {
+ result = cmSystemTools::FindProgram(program);
+ }
+ }
+ if (result.empty()) {
+ programArgs.clear();
+ }
+ }
+ } else if (args[2] == "EXT") {
+ result = cmSystemTools::GetFilenameExtension(filename);
+ } else if (args[2] == "NAME_WE") {
+ result = cmSystemTools::GetFilenameWithoutExtension(filename);
+ } else if (args[2] == "LAST_EXT") {
+ result = cmSystemTools::GetFilenameLastExtension(filename);
+ } else if (args[2] == "NAME_WLE") {
+ result = cmSystemTools::GetFilenameWithoutLastExtension(filename);
+ } else if (args[2] == "ABSOLUTE" || args[2] == "REALPATH") {
+ // If the path given is relative, evaluate it relative to the
+ // current source directory unless the user passes a different
+ // base directory.
+ std::string baseDir = status.GetMakefile().GetCurrentSourceDirectory();
+ for (unsigned int i = 3; i < args.size(); ++i) {
+ if (args[i] == "BASE_DIR") {
+ ++i;
+ if (i < args.size()) {
+ baseDir = args[i];
+ }
+ }
+ }
+ // Collapse the path to its simplest form.
+ result = cmSystemTools::CollapseFullPath(filename, baseDir);
+ if (args[2] == "REALPATH") {
+ // Resolve symlinks if possible
+ result = cmSystemTools::GetRealPath(result);
+ }
+ } else {
+ std::string err = "unknown component " + args[2];
+ status.SetError(err);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (args.size() >= 4 && args.back() == "CACHE") {
+ if (!programArgs.empty() && !storeArgs.empty()) {
+ status.GetMakefile().AddCacheDefinition(
+ storeArgs, programArgs, "",
+ args[2] == "PATH" ? cmStateEnums::FILEPATH : cmStateEnums::STRING);
+ }
+ status.GetMakefile().AddCacheDefinition(
+ args.front(), result, "",
+ args[2] == "PATH" ? cmStateEnums::FILEPATH : cmStateEnums::STRING);
+ } else {
+ if (!programArgs.empty() && !storeArgs.empty()) {
+ status.GetMakefile().AddDefinition(storeArgs, programArgs);
+ }
+ status.GetMakefile().AddDefinition(args.front(), result);
+ }
+
+ return true;
+}
diff --git a/Source/cmGetFilenameComponentCommand.h b/Source/cmGetFilenameComponentCommand.h
new file mode 100644
index 0000000..4e1addf
--- /dev/null
+++ b/Source/cmGetFilenameComponentCommand.h
@@ -0,0 +1,19 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Get a specific component of a filename.
+ *
+ * cmGetFilenameComponentCommand is a utility command used to get the path,
+ * name, extension or name without extension of a full filename.
+ */
+bool cmGetFilenameComponentCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmGetPipes.cxx b/Source/cmGetPipes.cxx
new file mode 100644
index 0000000..a5b6469
--- /dev/null
+++ b/Source/cmGetPipes.cxx
@@ -0,0 +1,48 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGetPipes.h"
+
+#include <cm3p/uv.h>
+#include <fcntl.h>
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <io.h>
+
+int cmGetPipes(int* fds)
+{
+ SECURITY_ATTRIBUTES attr;
+ HANDLE readh, writeh;
+ attr.nLength = sizeof(attr);
+ attr.lpSecurityDescriptor = nullptr;
+ attr.bInheritHandle = FALSE;
+ if (!CreatePipe(&readh, &writeh, &attr, 0))
+ return uv_translate_sys_error(GetLastError());
+ fds[0] = _open_osfhandle((intptr_t)readh, 0);
+ fds[1] = _open_osfhandle((intptr_t)writeh, 0);
+ if (fds[0] == -1 || fds[1] == -1) {
+ CloseHandle(readh);
+ CloseHandle(writeh);
+ return uv_translate_sys_error(GetLastError());
+ }
+ return 0;
+}
+#else
+# include <cerrno>
+
+# include <unistd.h>
+
+int cmGetPipes(int* fds)
+{
+ if (pipe(fds) == -1) {
+ return uv_translate_sys_error(errno);
+ }
+
+ if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
+ fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
+ close(fds[0]);
+ close(fds[1]);
+ return uv_translate_sys_error(errno);
+ }
+ return 0;
+}
+#endif
diff --git a/Source/cmGetPipes.h b/Source/cmGetPipes.h
new file mode 100644
index 0000000..6b1b495
--- /dev/null
+++ b/Source/cmGetPipes.h
@@ -0,0 +1,5 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+int cmGetPipes(int* fds);
diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx
new file mode 100644
index 0000000..cb657f9
--- /dev/null
+++ b/Source/cmGetPropertyCommand.cxx
@@ -0,0 +1,478 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGetPropertyCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstalledFile.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmPropertyDefinition.h"
+#include "cmSetPropertyCommand.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTest.h"
+#include "cmake.h"
+
+class cmMessenger;
+
+namespace {
+enum OutType
+{
+ OutValue,
+ OutDefined,
+ OutBriefDoc,
+ OutFullDoc,
+ OutSet
+};
+
+// Implementation of result storage.
+bool StoreResult(OutType infoType, cmMakefile& makefile,
+ const std::string& variable, const char* value);
+
+// Implementation of each property type.
+bool HandleGlobalMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName);
+bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName);
+bool HandleTargetMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName);
+bool HandleSourceMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName,
+ cmMakefile& directory_makefile,
+ bool source_file_paths_should_be_absolute);
+bool HandleTestMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName);
+bool HandleVariableMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName);
+bool HandleCacheMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName);
+bool HandleInstallMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName);
+}
+
+bool cmGetPropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ OutType infoType = OutValue;
+ if (args.size() < 3) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // The cmake variable in which to store the result.
+ const std::string variable = args[0];
+
+ std::string name;
+ std::string propertyName;
+
+ std::vector<std::string> source_file_directories;
+ std::vector<std::string> source_file_target_directories;
+ bool source_file_directory_option_enabled = false;
+ bool source_file_target_option_enabled = false;
+
+ // Get the scope from which to get the property.
+ cmProperty::ScopeType scope;
+ if (args[1] == "GLOBAL") {
+ scope = cmProperty::GLOBAL;
+ } else if (args[1] == "DIRECTORY") {
+ scope = cmProperty::DIRECTORY;
+ } else if (args[1] == "TARGET") {
+ scope = cmProperty::TARGET;
+ } else if (args[1] == "SOURCE") {
+ scope = cmProperty::SOURCE_FILE;
+ } else if (args[1] == "TEST") {
+ scope = cmProperty::TEST;
+ } else if (args[1] == "VARIABLE") {
+ scope = cmProperty::VARIABLE;
+ } else if (args[1] == "CACHE") {
+ scope = cmProperty::CACHE;
+ } else if (args[1] == "INSTALL") {
+ scope = cmProperty::INSTALL;
+ } else {
+ status.SetError(cmStrCat(
+ "given invalid scope ", args[1],
+ ". "
+ "Valid scopes are "
+ "GLOBAL, DIRECTORY, TARGET, SOURCE, TEST, VARIABLE, CACHE, INSTALL."));
+ return false;
+ }
+
+ // Parse remaining arguments.
+ enum Doing
+ {
+ DoingNone,
+ DoingName,
+ DoingProperty,
+ DoingType,
+ DoingSourceDirectory,
+ DoingSourceTargetDirectory
+ };
+ Doing doing = DoingName;
+ for (unsigned int i = 2; i < args.size(); ++i) {
+ if (args[i] == "PROPERTY") {
+ doing = DoingProperty;
+ } else if (args[i] == "BRIEF_DOCS") {
+ doing = DoingNone;
+ infoType = OutBriefDoc;
+ } else if (args[i] == "FULL_DOCS") {
+ doing = DoingNone;
+ infoType = OutFullDoc;
+ } else if (args[i] == "SET") {
+ doing = DoingNone;
+ infoType = OutSet;
+ } else if (args[i] == "DEFINED") {
+ doing = DoingNone;
+ infoType = OutDefined;
+ } else if (doing == DoingName) {
+ doing = DoingNone;
+ name = args[i];
+ } else if (doing == DoingNone && scope == cmProperty::SOURCE_FILE &&
+ args[i] == "DIRECTORY") {
+ doing = DoingSourceDirectory;
+ source_file_directory_option_enabled = true;
+ } else if (doing == DoingNone && scope == cmProperty::SOURCE_FILE &&
+ args[i] == "TARGET_DIRECTORY") {
+ doing = DoingSourceTargetDirectory;
+ source_file_target_option_enabled = true;
+ } else if (doing == DoingSourceDirectory) {
+ source_file_directories.push_back(args[i]);
+ doing = DoingNone;
+ } else if (doing == DoingSourceTargetDirectory) {
+ source_file_target_directories.push_back(args[i]);
+ doing = DoingNone;
+ } else if (doing == DoingProperty) {
+ doing = DoingNone;
+ propertyName = args[i];
+ } else {
+ status.SetError(cmStrCat("given invalid argument \"", args[i], "\"."));
+ return false;
+ }
+ }
+
+ // Make sure a property name was found.
+ if (propertyName.empty()) {
+ status.SetError("not given a PROPERTY <name> argument.");
+ return false;
+ }
+
+ std::vector<cmMakefile*> source_file_directory_makefiles;
+ bool file_scopes_handled =
+ SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
+ status, source_file_directory_option_enabled,
+ source_file_target_option_enabled, source_file_directories,
+ source_file_target_directories, source_file_directory_makefiles);
+ if (!file_scopes_handled) {
+ return false;
+ }
+
+ // Compute requested output.
+ if (infoType == OutBriefDoc) {
+ // Lookup brief documentation.
+ std::string output;
+ if (cmPropertyDefinition const* def =
+ status.GetMakefile().GetState()->GetPropertyDefinition(propertyName,
+ scope)) {
+ output = def->GetShortDescription();
+ } else {
+ output = "NOTFOUND";
+ }
+ status.GetMakefile().AddDefinition(variable, output);
+ } else if (infoType == OutFullDoc) {
+ // Lookup full documentation.
+ std::string output;
+ if (cmPropertyDefinition const* def =
+ status.GetMakefile().GetState()->GetPropertyDefinition(propertyName,
+ scope)) {
+ output = def->GetFullDescription();
+ } else {
+ output = "NOTFOUND";
+ }
+ status.GetMakefile().AddDefinition(variable, output);
+ } else if (infoType == OutDefined) {
+ // Lookup if the property is defined
+ if (status.GetMakefile().GetState()->GetPropertyDefinition(propertyName,
+ scope)) {
+ status.GetMakefile().AddDefinition(variable, "1");
+ } else {
+ status.GetMakefile().AddDefinition(variable, "0");
+ }
+ } else {
+ // Dispatch property getting.
+ cmMakefile& directory_scope_mf = *(source_file_directory_makefiles[0]);
+ bool source_file_paths_should_be_absolute =
+ source_file_directory_option_enabled ||
+ source_file_target_option_enabled;
+
+ switch (scope) {
+ case cmProperty::GLOBAL:
+ return HandleGlobalMode(status, name, infoType, variable,
+ propertyName);
+ case cmProperty::DIRECTORY:
+ return HandleDirectoryMode(status, name, infoType, variable,
+ propertyName);
+ case cmProperty::TARGET:
+ return HandleTargetMode(status, name, infoType, variable,
+ propertyName);
+ case cmProperty::SOURCE_FILE:
+ return HandleSourceMode(status, name, infoType, variable, propertyName,
+ directory_scope_mf,
+ source_file_paths_should_be_absolute);
+ case cmProperty::TEST:
+ return HandleTestMode(status, name, infoType, variable, propertyName);
+ case cmProperty::VARIABLE:
+ return HandleVariableMode(status, name, infoType, variable,
+ propertyName);
+ case cmProperty::CACHE:
+ return HandleCacheMode(status, name, infoType, variable, propertyName);
+ case cmProperty::INSTALL:
+ return HandleInstallMode(status, name, infoType, variable,
+ propertyName);
+
+ case cmProperty::CACHED_VARIABLE:
+ break; // should never happen
+ }
+ }
+
+ return true;
+}
+
+namespace {
+
+bool StoreResult(OutType infoType, cmMakefile& makefile,
+ const std::string& variable, const char* value)
+{
+ if (infoType == OutSet) {
+ makefile.AddDefinition(variable, value ? "1" : "0");
+ } else // if(infoType == OutValue)
+ {
+ if (value) {
+ makefile.AddDefinition(variable, value);
+ } else {
+ makefile.RemoveDefinition(variable);
+ }
+ }
+ return true;
+}
+
+bool HandleGlobalMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName)
+{
+ if (!name.empty()) {
+ status.SetError("given name for GLOBAL scope.");
+ return false;
+ }
+
+ // Get the property.
+ cmake* cm = status.GetMakefile().GetCMakeInstance();
+ return StoreResult(
+ infoType, status.GetMakefile(), variable,
+ cmToCStr(cm->GetState()->GetGlobalProperty(propertyName)));
+}
+
+bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName)
+{
+ // Default to the current directory.
+ cmMakefile* mf = &status.GetMakefile();
+
+ // Lookup the directory if given.
+ if (!name.empty()) {
+ // Construct the directory name. Interpret relative paths with
+ // respect to the current directory.
+ std::string dir = cmSystemTools::CollapseFullPath(
+ name, status.GetMakefile().GetCurrentSourceDirectory());
+
+ // Lookup the generator.
+ mf = status.GetMakefile().GetGlobalGenerator()->FindMakefile(dir);
+ if (!mf) {
+ // Could not find the directory.
+ status.SetError(
+ "DIRECTORY scope provided but requested directory was not found. "
+ "This could be because the directory argument was invalid or, "
+ "it is valid but has not been processed yet.");
+ return false;
+ }
+ }
+
+ if (propertyName == "DEFINITIONS") {
+ switch (mf->GetPolicyStatus(cmPolicies::CMP0059)) {
+ case cmPolicies::WARN:
+ mf->IssueMessage(MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0059));
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ return StoreResult(infoType, status.GetMakefile(), variable,
+ mf->GetDefineFlagsCMP0059());
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ break;
+ }
+ }
+
+ // Get the property.
+ return StoreResult(infoType, status.GetMakefile(), variable,
+ cmToCStr(mf->GetProperty(propertyName)));
+}
+
+bool HandleTargetMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName)
+{
+ if (name.empty()) {
+ status.SetError("not given name for TARGET scope.");
+ return false;
+ }
+
+ if (cmTarget* target = status.GetMakefile().FindTargetToUse(name)) {
+ if (propertyName == "ALIASED_TARGET" || propertyName == "ALIAS_GLOBAL") {
+ if (status.GetMakefile().IsAlias(name)) {
+ if (propertyName == "ALIASED_TARGET") {
+
+ return StoreResult(infoType, status.GetMakefile(), variable,
+ target->GetName().c_str());
+ }
+ if (propertyName == "ALIAS_GLOBAL") {
+ return StoreResult(
+ infoType, status.GetMakefile(), variable,
+ status.GetMakefile().GetGlobalGenerator()->IsAlias(name)
+ ? "TRUE"
+ : "FALSE");
+ }
+ }
+ return StoreResult(infoType, status.GetMakefile(), variable, nullptr);
+ }
+ cmListFileBacktrace bt = status.GetMakefile().GetBacktrace();
+ cmMessenger* messenger = status.GetMakefile().GetMessenger();
+ cmProp prop = target->GetComputedProperty(propertyName, messenger, bt);
+ if (!prop) {
+ prop = target->GetProperty(propertyName);
+ }
+ return StoreResult(infoType, status.GetMakefile(), variable,
+ cmToCStr(prop));
+ }
+ status.SetError(cmStrCat("could not find TARGET ", name,
+ ". Perhaps it has not yet been created."));
+ return false;
+}
+
+bool HandleSourceMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName,
+ cmMakefile& directory_makefile,
+ const bool source_file_paths_should_be_absolute)
+{
+ if (name.empty()) {
+ status.SetError("not given name for SOURCE scope.");
+ return false;
+ }
+
+ // Get the source file.
+ const std::string source_file_absolute_path =
+ SetPropertyCommand::MakeSourceFilePathAbsoluteIfNeeded(
+ status, name, source_file_paths_should_be_absolute);
+ if (cmSourceFile* sf =
+ directory_makefile.GetOrCreateSource(source_file_absolute_path)) {
+ return StoreResult(infoType, status.GetMakefile(), variable,
+ cmToCStr(sf->GetPropertyForUser(propertyName)));
+ }
+ status.SetError(
+ cmStrCat("given SOURCE name that could not be found or created: ",
+ source_file_absolute_path));
+ return false;
+}
+
+bool HandleTestMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName)
+{
+ if (name.empty()) {
+ status.SetError("not given name for TEST scope.");
+ return false;
+ }
+
+ // Loop over all tests looking for matching names.
+ if (cmTest* test = status.GetMakefile().GetTest(name)) {
+ return StoreResult(infoType, status.GetMakefile(), variable,
+ test->GetProperty(propertyName));
+ }
+
+ // If not found it is an error.
+ status.SetError(cmStrCat("given TEST name that does not exist: ", name));
+ return false;
+}
+
+bool HandleVariableMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName)
+{
+ if (!name.empty()) {
+ status.SetError("given name for VARIABLE scope.");
+ return false;
+ }
+
+ return StoreResult(
+ infoType, status.GetMakefile(), variable,
+ cmToCStr(status.GetMakefile().GetDefinition(propertyName)));
+}
+
+bool HandleCacheMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName)
+{
+ if (name.empty()) {
+ status.SetError("not given name for CACHE scope.");
+ return false;
+ }
+
+ cmProp value = nullptr;
+ if (status.GetMakefile().GetState()->GetCacheEntryValue(name)) {
+ value = status.GetMakefile().GetState()->GetCacheEntryProperty(
+ name, propertyName);
+ }
+ StoreResult(infoType, status.GetMakefile(), variable, cmToCStr(value));
+ return true;
+}
+
+bool HandleInstallMode(cmExecutionStatus& status, const std::string& name,
+ OutType infoType, const std::string& variable,
+ const std::string& propertyName)
+{
+ if (name.empty()) {
+ status.SetError("not given name for INSTALL scope.");
+ return false;
+ }
+
+ // Get the installed file.
+ cmake* cm = status.GetMakefile().GetCMakeInstance();
+
+ if (cmInstalledFile* file =
+ cm->GetOrCreateInstalledFile(&status.GetMakefile(), name)) {
+ std::string value;
+ bool isSet = file->GetProperty(propertyName, value);
+
+ return StoreResult(infoType, status.GetMakefile(), variable,
+ isSet ? value.c_str() : nullptr);
+ }
+ status.SetError(
+ cmStrCat("given INSTALL name that could not be found or created: ", name));
+ return false;
+}
+}
diff --git a/Source/cmGetPropertyCommand.h b/Source/cmGetPropertyCommand.h
new file mode 100644
index 0000000..fac3202
--- /dev/null
+++ b/Source/cmGetPropertyCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmGetPropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmGetSourceFilePropertyCommand.cxx b/Source/cmGetSourceFilePropertyCommand.cxx
new file mode 100644
index 0000000..5301b66
--- /dev/null
+++ b/Source/cmGetSourceFilePropertyCommand.cxx
@@ -0,0 +1,75 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGetSourceFilePropertyCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmSetPropertyCommand.h"
+#include "cmSourceFile.h"
+
+bool cmGetSourceFilePropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ std::vector<std::string>::size_type args_size = args.size();
+ if (args_size != 3 && args_size != 5) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::vector<std::string> source_file_directories;
+ std::vector<std::string> source_file_target_directories;
+ bool source_file_directory_option_enabled = false;
+ bool source_file_target_option_enabled = false;
+
+ int property_arg_index = 2;
+ if (args[2] == "DIRECTORY" && args_size == 5) {
+ property_arg_index = 4;
+ source_file_directory_option_enabled = true;
+ source_file_directories.push_back(args[3]);
+ } else if (args[2] == "TARGET_DIRECTORY" && args_size == 5) {
+ property_arg_index = 4;
+ source_file_target_option_enabled = true;
+ source_file_target_directories.push_back(args[3]);
+ }
+
+ std::vector<cmMakefile*> source_file_directory_makefiles;
+ bool file_scopes_handled =
+ SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
+ status, source_file_directory_option_enabled,
+ source_file_target_option_enabled, source_file_directories,
+ source_file_target_directories, source_file_directory_makefiles);
+ if (!file_scopes_handled) {
+ return false;
+ }
+
+ std::string const& var = args[0];
+ bool source_file_paths_should_be_absolute =
+ source_file_directory_option_enabled || source_file_target_option_enabled;
+ std::string const file =
+ SetPropertyCommand::MakeSourceFilePathAbsoluteIfNeeded(
+ status, args[1], source_file_paths_should_be_absolute);
+ cmMakefile& mf = *source_file_directory_makefiles[0];
+ cmSourceFile* sf = mf.GetSource(file);
+
+ // for the location we must create a source file first
+ if (!sf && args[property_arg_index] == "LOCATION") {
+ sf = mf.CreateSource(file);
+ }
+
+ if (sf) {
+ cmProp prop = nullptr;
+ if (!args[property_arg_index].empty()) {
+ prop = sf->GetPropertyForUser(args[property_arg_index]);
+ }
+ if (prop) {
+ // Set the value on the original Makefile scope, not the scope of the
+ // requested directory.
+ status.GetMakefile().AddDefinition(var, *prop);
+ return true;
+ }
+ }
+
+ status.GetMakefile().AddDefinition(var, "NOTFOUND");
+ return true;
+}
diff --git a/Source/cmGetSourceFilePropertyCommand.h b/Source/cmGetSourceFilePropertyCommand.h
new file mode 100644
index 0000000..4f8eab2
--- /dev/null
+++ b/Source/cmGetSourceFilePropertyCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmGetSourceFilePropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmGetTargetPropertyCommand.cxx b/Source/cmGetTargetPropertyCommand.cxx
new file mode 100644
index 0000000..78a17d2
--- /dev/null
+++ b/Source/cmGetTargetPropertyCommand.cxx
@@ -0,0 +1,88 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGetTargetPropertyCommand.h"
+
+#include <sstream>
+
+#include "cmExecutionStatus.h"
+#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmTarget.h"
+
+class cmMessenger;
+
+bool cmGetTargetPropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ std::string const& var = args[0];
+ std::string const& targetName = args[1];
+ std::string prop;
+ bool prop_exists = false;
+ cmMakefile& mf = status.GetMakefile();
+
+ if (cmTarget* tgt = mf.FindTargetToUse(targetName)) {
+ if (args[2] == "ALIASED_TARGET" || args[2] == "ALIAS_GLOBAL") {
+ if (mf.IsAlias(targetName)) {
+ prop_exists = true;
+ if (args[2] == "ALIASED_TARGET") {
+
+ prop = tgt->GetName();
+ }
+ if (args[2] == "ALIAS_GLOBAL") {
+ prop =
+ mf.GetGlobalGenerator()->IsAlias(targetName) ? "TRUE" : "FALSE";
+ }
+ }
+ } else if (!args[2].empty()) {
+ cmProp prop_cstr = nullptr;
+ cmListFileBacktrace bt = mf.GetBacktrace();
+ cmMessenger* messenger = mf.GetMessenger();
+ prop_cstr = tgt->GetComputedProperty(args[2], messenger, bt);
+ if (!prop_cstr) {
+ prop_cstr = tgt->GetProperty(args[2]);
+ }
+ if (prop_cstr) {
+ prop = *prop_cstr;
+ prop_exists = true;
+ }
+ }
+ } else {
+ bool issueMessage = false;
+ std::ostringstream e;
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+ switch (mf.GetPolicyStatus(cmPolicies::CMP0045)) {
+ case cmPolicies::WARN:
+ issueMessage = true;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0045) << "\n";
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ issueMessage = true;
+ messageType = MessageType::FATAL_ERROR;
+ }
+ if (issueMessage) {
+ e << "get_target_property() called with non-existent target \""
+ << targetName << "\".";
+ mf.IssueMessage(messageType, e.str());
+ if (messageType == MessageType::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+ if (prop_exists) {
+ mf.AddDefinition(var, prop);
+ return true;
+ }
+ mf.AddDefinition(var, var + "-NOTFOUND");
+ return true;
+}
diff --git a/Source/cmGetTargetPropertyCommand.h b/Source/cmGetTargetPropertyCommand.h
new file mode 100644
index 0000000..0fbd23d
--- /dev/null
+++ b/Source/cmGetTargetPropertyCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmGetTargetPropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmGetTestPropertyCommand.cxx b/Source/cmGetTestPropertyCommand.cxx
new file mode 100644
index 0000000..cf8c1d5
--- /dev/null
+++ b/Source/cmGetTestPropertyCommand.cxx
@@ -0,0 +1,33 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGetTestPropertyCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmTest.h"
+
+bool cmGetTestPropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::string const& testName = args[0];
+ std::string const& var = args[2];
+ cmMakefile& mf = status.GetMakefile();
+ cmTest* test = mf.GetTest(testName);
+ if (test) {
+ const char* prop = nullptr;
+ if (!args[1].empty()) {
+ prop = test->GetProperty(args[1]);
+ }
+ if (prop) {
+ mf.AddDefinition(var, prop);
+ return true;
+ }
+ }
+ mf.AddDefinition(var, "NOTFOUND");
+ return true;
+}
diff --git a/Source/cmGetTestPropertyCommand.h b/Source/cmGetTestPropertyCommand.h
new file mode 100644
index 0000000..f1d6010
--- /dev/null
+++ b/Source/cmGetTestPropertyCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmGetTestPropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmGhsMultiGpj.cxx b/Source/cmGhsMultiGpj.cxx
new file mode 100644
index 0000000..da27971
--- /dev/null
+++ b/Source/cmGhsMultiGpj.cxx
@@ -0,0 +1,39 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGhsMultiGpj.h"
+
+#include <ostream>
+
+static const char* GHS_TAG[] = { "[INTEGRITY Application]",
+ "[Library]",
+ "[Project]",
+ "[Program]",
+ "[Reference]",
+ "[Subproject]",
+ "[Custom Target]" };
+
+const char* GhsMultiGpj::GetGpjTag(Types gpjType)
+{
+ char const* tag;
+ switch (gpjType) {
+ case INTERGRITY_APPLICATION:
+ case LIBRARY:
+ case PROJECT:
+ case PROGRAM:
+ case REFERENCE:
+ case SUBPROJECT:
+ case CUSTOM_TARGET:
+ tag = GHS_TAG[gpjType];
+ break;
+ default:
+ tag = "";
+ }
+ return tag;
+}
+
+void GhsMultiGpj::WriteGpjTag(Types gpjType, std::ostream& fout)
+{
+ char const* tag;
+ tag = GhsMultiGpj::GetGpjTag(gpjType);
+ fout << tag << std::endl;
+}
diff --git a/Source/cmGhsMultiGpj.h b/Source/cmGhsMultiGpj.h
new file mode 100644
index 0000000..1cae660
--- /dev/null
+++ b/Source/cmGhsMultiGpj.h
@@ -0,0 +1,26 @@
+/* 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 <iosfwd>
+
+class GhsMultiGpj
+{
+public:
+ enum Types
+ {
+ INTERGRITY_APPLICATION,
+ LIBRARY,
+ PROJECT,
+ PROGRAM,
+ REFERENCE,
+ SUBPROJECT,
+ CUSTOM_TARGET
+ };
+
+ static void WriteGpjTag(Types gpjType, std::ostream& fout);
+
+ static const char* GetGpjTag(Types gpjType);
+};
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
new file mode 100644
index 0000000..ed5bff5
--- /dev/null
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -0,0 +1,781 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGhsMultiTargetGenerator.h"
+
+#include <algorithm>
+#include <memory>
+#include <ostream>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "cmCustomCommand.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGhsMultiGenerator.h"
+#include "cmLinkLineComputer.h" // IWYU pragma: keep
+#include "cmLocalGenerator.h"
+#include "cmLocalGhsMultiGenerator.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmProperty.h"
+#include "cmSourceFile.h"
+#include "cmSourceFileLocation.h"
+#include "cmSourceGroup.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+
+cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target)
+ : GeneratorTarget(target)
+ , LocalGenerator(
+ static_cast<cmLocalGhsMultiGenerator*>(target->GetLocalGenerator()))
+ , Makefile(target->Target->GetMakefile())
+ , Name(target->GetName())
+#ifdef _WIN32
+ , CmdWindowsShell(true)
+#else
+ , CmdWindowsShell(false)
+#endif
+{
+ // Store the configuration name that is being used
+ if (cmProp config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) {
+ // Use the build type given by the user.
+ this->ConfigName = *config;
+ } else {
+ // No configuration type given.
+ this->ConfigName.clear();
+ }
+}
+
+cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator() = default;
+
+void cmGhsMultiTargetGenerator::Generate()
+{
+ // Determine type of target for this project
+ switch (this->GeneratorTarget->GetType()) {
+ case cmStateEnums::EXECUTABLE: {
+ // Get the name of the executable to generate.
+ this->TargetNameReal =
+ this->GeneratorTarget->GetExecutableNames(this->ConfigName).Real;
+ if (this->cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) {
+ this->TagType = GhsMultiGpj::INTERGRITY_APPLICATION;
+ } else {
+ this->TagType = GhsMultiGpj::PROGRAM;
+ }
+ break;
+ }
+ case cmStateEnums::STATIC_LIBRARY: {
+ this->TargetNameReal =
+ this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real;
+ this->TagType = GhsMultiGpj::LIBRARY;
+ break;
+ }
+ case cmStateEnums::SHARED_LIBRARY: {
+ std::string msg =
+ cmStrCat("add_library(<name> SHARED ...) not supported: ", this->Name);
+ cmSystemTools::Message(msg);
+ return;
+ }
+ case cmStateEnums::OBJECT_LIBRARY: {
+ this->TargetNameReal =
+ this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real;
+ this->TagType = GhsMultiGpj::SUBPROJECT;
+ break;
+ }
+ case cmStateEnums::MODULE_LIBRARY: {
+ std::string msg =
+ cmStrCat("add_library(<name> MODULE ...) not supported: ", this->Name);
+ cmSystemTools::Message(msg);
+ return;
+ }
+ case cmStateEnums::UTILITY: {
+ this->TargetNameReal = this->GeneratorTarget->GetName();
+ this->TagType = GhsMultiGpj::CUSTOM_TARGET;
+ break;
+ }
+ case cmStateEnums::GLOBAL_TARGET: {
+ this->TargetNameReal = this->GeneratorTarget->GetName();
+ if (this->TargetNameReal ==
+ this->GetGlobalGenerator()->GetInstallTargetName()) {
+ this->TagType = GhsMultiGpj::CUSTOM_TARGET;
+ } else {
+ return;
+ }
+ break;
+ }
+ default:
+ return;
+ }
+
+ // Tell the global generator the name of the project file
+ this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME",
+ this->Name);
+ this->GeneratorTarget->Target->SetProperty(
+ "GENERATOR_FILE_NAME_EXT", GhsMultiGpj::GetGpjTag(this->TagType));
+
+ this->GenerateTarget();
+}
+
+void cmGhsMultiTargetGenerator::GenerateTarget()
+{
+ // Open the target file in copy-if-different mode.
+ std::string fproj =
+ cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
+ this->Name, cmGlobalGhsMultiGenerator::FILE_EXTENSION);
+ cmGeneratedFileStream fout(fproj);
+ fout.SetCopyIfDifferent(true);
+
+ this->GetGlobalGenerator()->WriteFileHeader(fout);
+ GhsMultiGpj::WriteGpjTag(this->TagType, fout);
+
+ if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+ const std::string language(
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName));
+ this->WriteTargetSpecifics(fout, this->ConfigName);
+ this->SetCompilerFlags(this->ConfigName, language);
+ this->WriteCompilerFlags(fout, this->ConfigName, language);
+ this->WriteCompilerDefinitions(fout, this->ConfigName, language);
+ this->WriteIncludes(fout, this->ConfigName, language);
+ this->WriteTargetLinkLine(fout, this->ConfigName);
+ this->WriteBuildEvents(fout);
+ }
+ this->WriteSources(fout);
+ fout.Close();
+}
+
+cmGlobalGhsMultiGenerator* cmGhsMultiTargetGenerator::GetGlobalGenerator()
+ const
+{
+ return static_cast<cmGlobalGhsMultiGenerator*>(
+ this->LocalGenerator->GetGlobalGenerator());
+}
+
+void cmGhsMultiTargetGenerator::WriteTargetSpecifics(std::ostream& fout,
+ const std::string& config)
+{
+ std::string outpath;
+ std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory();
+
+ if (this->TagType != GhsMultiGpj::SUBPROJECT) {
+ // set target binary file destination
+ outpath = this->GeneratorTarget->GetDirectory(config);
+ outpath =
+ this->LocalGenerator->MaybeConvertToRelativePath(rootpath, outpath);
+ /* clang-format off */
+ fout << " :binDirRelative=\"" << outpath << "\"\n"
+ " -o \"" << this->TargetNameReal << "\"\n";
+ /* clang-format on */
+ }
+
+ // set target object file destination
+ outpath = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ fout << " :outputDirRelative=\"" << outpath << "\"\n";
+}
+
+void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config,
+ const std::string& language)
+{
+ auto i = this->FlagsByLanguage.find(language);
+ if (i == this->FlagsByLanguage.end()) {
+ std::string flags;
+ this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+ language, config);
+ this->LocalGenerator->AddCMP0018Flags(flags, this->GeneratorTarget,
+ language, config);
+ this->LocalGenerator->AddVisibilityPresetFlags(
+ flags, this->GeneratorTarget, language);
+
+ // Append old-style preprocessor definition flags.
+ if (this->Makefile->GetDefineFlags() != " ") {
+ this->LocalGenerator->AppendFlags(flags,
+ this->Makefile->GetDefineFlags());
+ }
+
+ // Add target-specific flags.
+ this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
+ language, config);
+
+ std::map<std::string, std::string>::value_type entry(language, flags);
+ i = this->FlagsByLanguage.insert(entry).first;
+ }
+}
+
+std::string cmGhsMultiTargetGenerator::GetDefines(const std::string& language,
+ std::string const& config)
+{
+ auto i = this->DefinesByLanguage.find(language);
+ if (i == this->DefinesByLanguage.end()) {
+ std::set<std::string> defines;
+ // Add preprocessor definitions for this target and configuration.
+ this->LocalGenerator->GetTargetDefines(this->GeneratorTarget, config,
+ language, defines);
+
+ std::string definesString;
+ this->LocalGenerator->JoinDefines(defines, definesString, language);
+
+ std::map<std::string, std::string>::value_type entry(language,
+ definesString);
+ i = this->DefinesByLanguage.insert(entry).first;
+ }
+ return i->second;
+}
+
+void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::ostream& fout,
+ std::string const&,
+ const std::string& language)
+{
+ auto flagsByLangI = this->FlagsByLanguage.find(language);
+ if (flagsByLangI != this->FlagsByLanguage.end()) {
+ if (!flagsByLangI->second.empty()) {
+ std::vector<std::string> ghsCompFlags =
+ cmSystemTools::ParseArguments(flagsByLangI->second);
+ for (const std::string& f : ghsCompFlags) {
+ fout << " " << f << '\n';
+ }
+ }
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteCompilerDefinitions(
+ std::ostream& fout, const std::string& config, const std::string& language)
+{
+ std::vector<std::string> compileDefinitions;
+ this->GeneratorTarget->GetCompileDefinitions(compileDefinitions, config,
+ language);
+ for (std::string const& compileDefinition : compileDefinitions) {
+ fout << " -D" << compileDefinition << '\n';
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteIncludes(std::ostream& fout,
+ const std::string& config,
+ const std::string& language)
+{
+ std::vector<std::string> includes;
+ this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
+ language, config);
+
+ for (std::string const& include : includes) {
+ fout << " -I\"" << include << "\"\n";
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout,
+ std::string const& config)
+{
+ if (this->TagType == GhsMultiGpj::INTERGRITY_APPLICATION) {
+ return;
+ }
+
+ std::string linkLibraries;
+ std::string flags;
+ std::string linkFlags;
+ std::string frameworkPath;
+ std::string linkPath;
+
+ std::unique_ptr<cmLinkLineComputer> linkLineComputer =
+ this->GetGlobalGenerator()->CreateLinkLineComputer(
+ this->LocalGenerator,
+ this->LocalGenerator->GetStateSnapshot().GetDirectory());
+
+ this->LocalGenerator->GetTargetFlags(
+ linkLineComputer.get(), config, linkLibraries, flags, linkFlags,
+ frameworkPath, linkPath, this->GeneratorTarget);
+
+ // write out link options
+ std::vector<std::string> lopts = cmSystemTools::ParseArguments(linkFlags);
+ for (const std::string& l : lopts) {
+ fout << " " << l << '\n';
+ }
+
+ // write out link search paths
+ // must be quoted for paths that contain spaces
+ std::vector<std::string> lpath = cmSystemTools::ParseArguments(linkPath);
+ for (const std::string& l : lpath) {
+ fout << " -L\"" << l << "\"\n";
+ }
+
+ // write out link libs
+ // must be quoted for filepaths that contains spaces
+ std::string cbd = this->LocalGenerator->GetCurrentBinaryDirectory();
+
+ std::vector<std::string> llibs =
+ cmSystemTools::ParseArguments(linkLibraries);
+ for (const std::string& l : llibs) {
+ if (l.compare(0, 2, "-l") == 0) {
+ fout << " \"" << l << "\"\n";
+ } else {
+ std::string rl = cmSystemTools::CollapseFullPath(l, cbd);
+ fout << " -l\"" << rl << "\"\n";
+ }
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteBuildEvents(std::ostream& fout)
+{
+ this->WriteBuildEventsHelper(
+ fout, this->GeneratorTarget->GetPreBuildCommands(),
+ std::string("prebuild"), std::string("preexecShell"));
+
+ if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+ this->WriteBuildEventsHelper(
+ fout, this->GeneratorTarget->GetPreLinkCommands(),
+ std::string("prelink"), std::string("preexecShell"));
+ }
+
+ this->WriteBuildEventsHelper(
+ fout, this->GeneratorTarget->GetPostBuildCommands(),
+ std::string("postbuild"), std::string("postexecShell"));
+}
+
+void cmGhsMultiTargetGenerator::WriteBuildEventsHelper(
+ std::ostream& fout, const std::vector<cmCustomCommand>& ccv,
+ std::string const& name, std::string const& cmd)
+{
+ int cmdcount = 0;
+
+ for (cmCustomCommand const& cc : ccv) {
+ cmCustomCommandGenerator ccg(cc, this->ConfigName, this->LocalGenerator);
+ // Open the filestream for this custom command
+ std::string fname =
+ cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget),
+ '/', this->Name, '_', name, cmdcount++,
+ this->CmdWindowsShell ? ".bat" : ".sh");
+ cmGeneratedFileStream f(fname);
+ f.SetCopyIfDifferent(true);
+ this->WriteCustomCommandsHelper(f, ccg);
+ f.Close();
+ if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+ fout << " :" << cmd << "=\"" << fname << "\"\n";
+ } else {
+ fout << fname << "\n :outputName=\"" << fname << ".rule\"\n";
+ }
+ for (const auto& byp : ccg.GetByproducts()) {
+ fout << " :extraOutputFile=\"" << byp << "\"\n";
+ }
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
+ std::ostream& fout, cmCustomCommandGenerator const& ccg)
+{
+ std::vector<std::string> cmdLines;
+
+ // if the command specified a working directory use it.
+ std::string dir = this->LocalGenerator->GetCurrentBinaryDirectory();
+ std::string currentBinDir = dir;
+ std::string workingDir = ccg.GetWorkingDirectory();
+ if (!workingDir.empty()) {
+ dir = workingDir;
+ }
+
+ // Line to check for error between commands.
+#ifdef _WIN32
+ std::string check_error = "if %errorlevel% neq 0 exit /b %errorlevel%";
+#else
+ std::string check_error = "if [[ $? -ne 0 ]]; then exit 1; fi";
+#endif
+
+#ifdef _WIN32
+ cmdLines.push_back("@echo off");
+#endif
+ // Echo the custom command's comment text.
+ const char* comment = ccg.GetComment();
+ if (comment && *comment) {
+ std::string echocmd = cmStrCat("echo ", comment);
+ cmdLines.push_back(std::move(echocmd));
+ }
+
+ // Switch to working directory
+ std::string cdCmd;
+#ifdef _WIN32
+ std::string cdStr = "cd /D ";
+#else
+ std::string cdStr = "cd ";
+#endif
+ cdCmd = cdStr +
+ this->LocalGenerator->ConvertToOutputFormat(dir, cmOutputConverter::SHELL);
+ cmdLines.push_back(std::move(cdCmd));
+
+ for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
+ // Build the command line in a single string.
+ std::string cmd = ccg.GetCommand(c);
+ if (!cmd.empty()) {
+ // Use "call " before any invocations of .bat or .cmd files
+ // invoked as custom commands in the WindowsShell.
+ //
+ bool useCall = false;
+
+ if (this->CmdWindowsShell) {
+ std::string suffix;
+ if (cmd.size() > 4) {
+ suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size() - 4));
+ if (suffix == ".bat" || suffix == ".cmd") {
+ useCall = true;
+ }
+ }
+ }
+
+ cmSystemTools::ReplaceString(cmd, "/./", "/");
+ // Convert the command to a relative path only if the current
+ // working directory will be the start-output directory.
+ bool had_slash = cmd.find('/') != std::string::npos;
+ if (workingDir.empty()) {
+ cmd =
+ this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir, cmd);
+ }
+ bool has_slash = cmd.find('/') != std::string::npos;
+ if (had_slash && !has_slash) {
+ // This command was specified as a path to a file in the
+ // current directory. Add a leading "./" so it can run
+ // without the current directory being in the search path.
+ cmd = cmStrCat("./", cmd);
+ }
+ cmd = this->LocalGenerator->ConvertToOutputFormat(
+ cmd, cmOutputConverter::SHELL);
+ if (useCall) {
+ cmd = cmStrCat("call ", cmd);
+ }
+ ccg.AppendArguments(c, cmd);
+ cmdLines.push_back(std::move(cmd));
+ }
+ }
+
+ // push back the custom commands
+ for (auto const& c : cmdLines) {
+ fout << c << '\n' << check_error << '\n';
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteSourceProperty(
+ std::ostream& fout, const cmSourceFile* sf, std::string const& propName,
+ std::string const& propFlag)
+{
+ cmProp prop = sf->GetProperty(propName);
+ if (prop) {
+ std::vector<std::string> list = cmExpandedList(*prop);
+ for (const std::string& p : list) {
+ fout << " " << propFlag << p << '\n';
+ }
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
+{
+ /* vector of all sources for this target */
+ std::vector<cmSourceFile*> sources;
+ this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
+
+ /* vector of all groups defined for this target
+ * -- but the vector is not expanded with sub groups or in any useful order
+ */
+ std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
+
+ /* for each source file assign it to its group */
+ std::map<std::string, std::vector<cmSourceFile*>> groupFiles;
+ std::set<std::string> groupNames;
+ for (cmSourceFile* sf : sources) {
+ cmSourceGroup* sourceGroup =
+ this->Makefile->FindSourceGroup(sf->ResolveFullPath(), sourceGroups);
+ std::string gn = sourceGroup->GetFullName();
+ groupFiles[gn].push_back(sf);
+ groupNames.insert(std::move(gn));
+ }
+
+ /* list of known groups and the order they are displayed in a project file */
+ const std::vector<std::string> standardGroups = {
+ "CMake Rules", "Header Files", "Source Files",
+ "Object Files", "Object Libraries", "Resources"
+ };
+
+ /* list of groups in the order they are displayed in a project file*/
+ std::vector<std::string> groupFilesList(groupFiles.size());
+
+ /* put the groups in the order they should be listed
+ * - standard groups first, and then everything else
+ * in the order used by std::map.
+ */
+ int i = 0;
+ for (const std::string& gn : standardGroups) {
+ auto n = groupNames.find(gn);
+ if (n != groupNames.end()) {
+ groupFilesList[i] = *n;
+ i += 1;
+ groupNames.erase(gn);
+ } else if (this->TagType == GhsMultiGpj::CUSTOM_TARGET &&
+ gn == "CMake Rules") {
+ /* make sure that rules folder always exists in case of custom targets
+ * that have no custom commands except for pre or post build events.
+ */
+ groupFilesList.resize(groupFilesList.size() + 1);
+ groupFilesList[i] = gn;
+ i += 1;
+ }
+ }
+
+ { /* catch-all group - is last item */
+ std::string gn;
+ auto n = groupNames.find(gn);
+ if (n != groupNames.end()) {
+ groupFilesList.back() = *n;
+ groupNames.erase(gn);
+ }
+ }
+
+ for (const auto& n : groupNames) {
+ groupFilesList[i] = n;
+ i += 1;
+ }
+
+ /* sort the files within each group */
+ for (auto& n : groupFilesList) {
+ std::sort(groupFiles[n].begin(), groupFiles[n].end(),
+ [](cmSourceFile* l, cmSourceFile* r) {
+ return l->ResolveFullPath() < r->ResolveFullPath();
+ });
+ }
+
+ /* list of open project files */
+ std::vector<cmGeneratedFileStream*> gfiles;
+
+ /* write files into the proper project file
+ * -- groups go into main project file
+ * unless NO_SOURCE_GROUP_FILE property or variable is set.
+ */
+ for (auto& sg : groupFilesList) {
+ std::ostream* fout;
+ bool useProjectFile =
+ cmIsOn(this->GeneratorTarget->GetProperty("GHS_NO_SOURCE_GROUP_FILE")) ||
+ this->Makefile->IsOn("CMAKE_GHS_NO_SOURCE_GROUP_FILE");
+ if (useProjectFile || sg.empty()) {
+ fout = &fout_proj;
+ } else {
+ // Open the filestream in copy-if-different mode.
+ std::string gname = sg;
+ cmsys::SystemTools::ReplaceString(gname, "\\", "_");
+ std::string lpath = cmStrCat(
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), '/',
+ gname, cmGlobalGhsMultiGenerator::FILE_EXTENSION);
+ std::string fpath = cmStrCat(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), '/', lpath);
+ cmGeneratedFileStream* f = new cmGeneratedFileStream(fpath);
+ f->SetCopyIfDifferent(true);
+ gfiles.push_back(f);
+ fout = f;
+ this->GetGlobalGenerator()->WriteFileHeader(*f);
+ GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT, *f);
+ fout_proj << lpath << " ";
+ GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT, fout_proj);
+ }
+
+ if (useProjectFile) {
+ if (sg.empty()) {
+ *fout << "{comment} Others" << '\n';
+ } else {
+ *fout << "{comment} " << sg << '\n';
+ }
+ } else if (sg.empty()) {
+ *fout << "{comment} Others\n";
+ }
+
+ if (sg != "CMake Rules") {
+ /* output rule for each source file */
+ for (const cmSourceFile* si : groupFiles[sg]) {
+ bool compile = true;
+ // Convert filename to native system
+ // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on
+ // windows when opening some files from the search window.
+ std::string fname(si->GetFullPath());
+ cmSystemTools::ConvertToOutputSlashes(fname);
+
+ /* For custom targets list any associated sources,
+ * comment out source code to prevent it from being
+ * compiled when processing this target.
+ * Otherwise, comment out any custom command (main) dependencies that
+ * are listed as source files to prevent them from being considered
+ * part of the build.
+ */
+ std::string comment;
+ if ((this->TagType == GhsMultiGpj::CUSTOM_TARGET &&
+ !si->GetLanguage().empty()) ||
+ si->GetCustomCommand()) {
+ comment = "{comment} ";
+ compile = false;
+ }
+
+ *fout << comment << fname << '\n';
+ if (compile) {
+ if ("ld" != si->GetExtension() && "int" != si->GetExtension() &&
+ "bsp" != si->GetExtension()) {
+ WriteObjectLangOverride(*fout, si);
+ }
+
+ this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I");
+ this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D");
+ this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", "");
+
+ /* to avoid clutter in the GUI only print out the objectName if it
+ * has been renamed */
+ std::string objectName = this->GeneratorTarget->GetObjectName(si);
+ if (!objectName.empty() &&
+ this->GeneratorTarget->HasExplicitObjectName(si)) {
+ *fout << " -o " << objectName << '\n';
+ }
+ }
+ }
+ } else {
+ std::vector<cmSourceFile const*> customCommands;
+ if (this->ComputeCustomCommandOrder(customCommands)) {
+ std::string message = "The custom commands for target [" +
+ this->GeneratorTarget->GetName() + "] had a cycle.\n";
+ cmSystemTools::Error(message);
+ } else {
+ /* Custom targets do not have a dependency on SOURCES files.
+ * Therefore the dependency list may include SOURCES files after the
+ * custom target. Because nothing can depend on the custom target just
+ * move it to the last item.
+ */
+ for (auto sf = customCommands.begin(); sf != customCommands.end();
+ ++sf) {
+ if (((*sf)->GetLocation()).GetName() == this->Name + ".rule") {
+ std::rotate(sf, sf + 1, customCommands.end());
+ break;
+ }
+ }
+ int cmdcount = 0;
+ for (auto& sf : customCommands) {
+ const cmCustomCommand* cc = sf->GetCustomCommand();
+ cmCustomCommandGenerator ccg(*cc, this->ConfigName,
+ this->LocalGenerator);
+
+ // Open the filestream for this custom command
+ std::string fname = cmStrCat(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget),
+ '/', this->Name, "_cc", cmdcount++, '_',
+ (sf->GetLocation()).GetName(),
+ this->CmdWindowsShell ? ".bat" : ".sh");
+ cmGeneratedFileStream f(fname);
+ f.SetCopyIfDifferent(true);
+ this->WriteCustomCommandsHelper(f, ccg);
+ f.Close();
+ this->WriteCustomCommandLine(*fout, fname, ccg);
+ }
+ }
+ if (this->TagType == GhsMultiGpj::CUSTOM_TARGET) {
+ this->WriteBuildEvents(*fout);
+ }
+ }
+ }
+
+ for (cmGeneratedFileStream* f : gfiles) {
+ f->Close();
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteCustomCommandLine(
+ std::ostream& fout, std::string& fname, cmCustomCommandGenerator const& ccg)
+{
+ /* NOTE: Customization Files are not well documented. Testing showed
+ * that ":outputName=file" can only be used once per script. The
+ * script will only run if ":outputName=file" is missing or just run
+ * once if ":outputName=file" is not specified. If there are
+ * multiple outputs then the script needs to be listed multiple times
+ * for each output. Otherwise it won't rerun the script if one of
+ * the outputs is manually deleted.
+ */
+ bool specifyExtra = true;
+ for (const auto& out : ccg.GetOutputs()) {
+ fout << fname << '\n';
+ fout << " :outputName=\"" << out << "\"\n";
+ if (specifyExtra) {
+ for (const auto& byp : ccg.GetByproducts()) {
+ fout << " :extraOutputFile=\"" << byp << "\"\n";
+ }
+ for (const auto& dep : ccg.GetDepends()) {
+ fout << " :depends=\"" << dep << "\"\n";
+ }
+ specifyExtra = false;
+ }
+ }
+}
+
+void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
+ std::ostream& fout, const cmSourceFile* sourceFile)
+{
+ cmProp rawLangProp = sourceFile->GetProperty("LANGUAGE");
+ if (nullptr != rawLangProp) {
+ std::string sourceLangProp(*rawLangProp);
+ std::string const& extension = sourceFile->GetExtension();
+ if ("CXX" == sourceLangProp && ("c" == extension || "C" == extension)) {
+ fout << " -dotciscxx\n";
+ }
+ }
+}
+
+bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()
+{
+ if (cmProp p = this->GeneratorTarget->GetProperty("ghs_integrity_app")) {
+ return cmIsOn(*p);
+ }
+ std::vector<cmSourceFile*> sources;
+ this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
+ return std::any_of(sources.begin(), sources.end(),
+ [](cmSourceFile const* sf) -> bool {
+ return "int" == sf->GetExtension();
+ });
+}
+
+bool cmGhsMultiTargetGenerator::ComputeCustomCommandOrder(
+ std::vector<cmSourceFile const*>& order)
+{
+ std::set<cmSourceFile const*> temp;
+ std::set<cmSourceFile const*> perm;
+
+ // Collect all custom commands for this target
+ std::vector<cmSourceFile const*> customCommands;
+ this->GeneratorTarget->GetCustomCommands(customCommands, this->ConfigName);
+
+ for (cmSourceFile const* si : customCommands) {
+ bool r = this->VisitCustomCommand(temp, perm, order, si);
+ if (r) {
+ return r;
+ }
+ }
+ return false;
+}
+
+bool cmGhsMultiTargetGenerator::VisitCustomCommand(
+ std::set<cmSourceFile const*>& temp, std::set<cmSourceFile const*>& perm,
+ std::vector<cmSourceFile const*>& order, cmSourceFile const* si)
+{
+ /* check if permanent mark is set*/
+ if (perm.find(si) == perm.end()) {
+ /* set temporary mark; check if revisit*/
+ if (temp.insert(si).second) {
+ for (const auto& di : si->GetCustomCommand()->GetDepends()) {
+ cmSourceFile const* sf =
+ this->GeneratorTarget->GetLocalGenerator()->GetSourceFileWithOutput(
+ di);
+ /* if sf exists then visit */
+ if (sf && this->VisitCustomCommand(temp, perm, order, sf)) {
+ return true;
+ }
+ }
+ /* mark as complete; insert into beginning of list*/
+ perm.insert(si);
+ order.push_back(si);
+ return false;
+ }
+ /* revisiting item - not a DAG */
+ return true;
+ }
+ /* already complete */
+ return false;
+}
diff --git a/Source/cmGhsMultiTargetGenerator.h b/Source/cmGhsMultiTargetGenerator.h
new file mode 100644
index 0000000..e9d7537
--- /dev/null
+++ b/Source/cmGhsMultiTargetGenerator.h
@@ -0,0 +1,83 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmGhsMultiGpj.h"
+
+class cmCustomCommand;
+class cmCustomCommandGenerator;
+class cmGeneratorTarget;
+class cmGlobalGhsMultiGenerator;
+class cmLocalGhsMultiGenerator;
+class cmMakefile;
+class cmSourceFile;
+
+class cmGhsMultiTargetGenerator
+{
+public:
+ cmGhsMultiTargetGenerator(cmGeneratorTarget* target);
+
+ virtual ~cmGhsMultiTargetGenerator();
+
+ virtual void Generate();
+
+private:
+ cmGlobalGhsMultiGenerator* GetGlobalGenerator() const;
+
+ void GenerateTarget();
+
+ void WriteTargetSpecifics(std::ostream& fout, const std::string& config);
+
+ void WriteCompilerFlags(std::ostream& fout, const std::string& config,
+ const std::string& language);
+ void WriteCompilerDefinitions(std::ostream& fout, const std::string& config,
+ const std::string& language);
+
+ void SetCompilerFlags(std::string const& config,
+ const std::string& language);
+
+ std::string GetDefines(const std::string& language,
+ std::string const& config);
+
+ void WriteIncludes(std::ostream& fout, const std::string& config,
+ const std::string& language);
+ void WriteTargetLinkLine(std::ostream& fout, std::string const& config);
+ void WriteBuildEvents(std::ostream& fout);
+ void WriteBuildEventsHelper(std::ostream& fout,
+ const std::vector<cmCustomCommand>& ccv,
+ std::string const& name, std::string const& cmd);
+ void WriteCustomCommandsHelper(std::ostream& fout,
+ cmCustomCommandGenerator const& ccg);
+ void WriteCustomCommandLine(std::ostream& fout, std::string& fname,
+ cmCustomCommandGenerator const& ccg);
+ bool ComputeCustomCommandOrder(std::vector<cmSourceFile const*>& order);
+ bool VisitCustomCommand(std::set<cmSourceFile const*>& temp,
+ std::set<cmSourceFile const*>& perm,
+ std::vector<cmSourceFile const*>& order,
+ cmSourceFile const* sf);
+ void WriteSources(std::ostream& fout_proj);
+ void WriteSourceProperty(std::ostream& fout, const cmSourceFile* sf,
+ std::string const& propName,
+ std::string const& propFlag);
+ static void WriteObjectLangOverride(std::ostream& fout,
+ const cmSourceFile* sourceFile);
+
+ bool DetermineIfIntegrityApp();
+ cmGeneratorTarget* GeneratorTarget;
+ cmLocalGhsMultiGenerator* LocalGenerator;
+ cmMakefile* Makefile;
+ std::map<std::string, std::string> FlagsByLanguage;
+ std::map<std::string, std::string> DefinesByLanguage;
+
+ std::string TargetNameReal;
+ GhsMultiGpj::Types TagType;
+ std::string const Name;
+ std::string ConfigName; /* CMAKE_BUILD_TYPE */
+ bool const CmdWindowsShell; /* custom commands run in cmd.exe or /bin/sh */
+};
diff --git a/Source/cmGlobVerificationManager.cxx b/Source/cmGlobVerificationManager.cxx
new file mode 100644
index 0000000..9ac5cd5
--- /dev/null
+++ b/Source/cmGlobVerificationManager.cxx
@@ -0,0 +1,181 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobVerificationManager.h"
+
+#include <sstream>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmGeneratedFileStream.h"
+#include "cmListFileCache.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+
+bool cmGlobVerificationManager::SaveVerificationScript(const std::string& path)
+{
+ if (this->Cache.empty()) {
+ return true;
+ }
+
+ std::string scriptFile = cmStrCat(path, "/CMakeFiles");
+ std::string stampFile = scriptFile;
+ cmSystemTools::MakeDirectory(scriptFile);
+ scriptFile += "/VerifyGlobs.cmake";
+ stampFile += "/cmake.verify_globs";
+ cmGeneratedFileStream verifyScriptFile(scriptFile);
+ verifyScriptFile.SetCopyIfDifferent(true);
+ if (!verifyScriptFile) {
+ cmSystemTools::Error("Unable to open verification script file for save. " +
+ scriptFile);
+ cmSystemTools::ReportLastSystemError("");
+ return false;
+ }
+
+ verifyScriptFile << std::boolalpha;
+ verifyScriptFile << "# CMAKE generated file: DO NOT EDIT!\n"
+ << "# Generated by CMake Version "
+ << cmVersion::GetMajorVersion() << "."
+ << cmVersion::GetMinorVersion() << "\n";
+
+ verifyScriptFile << "cmake_policy(SET CMP0009 NEW)\n";
+
+ for (auto const& i : this->Cache) {
+ CacheEntryKey k = std::get<0>(i);
+ CacheEntryValue v = std::get<1>(i);
+
+ if (!v.Initialized) {
+ continue;
+ }
+
+ verifyScriptFile << "\n";
+
+ for (auto const& bt : v.Backtraces) {
+ verifyScriptFile << "# " << std::get<0>(bt);
+ std::get<1>(bt).PrintTitle(verifyScriptFile);
+ verifyScriptFile << "\n";
+ }
+
+ k.PrintGlobCommand(verifyScriptFile, "NEW_GLOB");
+ verifyScriptFile << "\n";
+
+ verifyScriptFile << "set(OLD_GLOB\n";
+ for (const std::string& file : v.Files) {
+ verifyScriptFile << " \"" << file << "\"\n";
+ }
+ verifyScriptFile << " )\n";
+
+ verifyScriptFile << "if(NOT \"${NEW_GLOB}\" STREQUAL \"${OLD_GLOB}\")\n"
+ << " message(\"-- GLOB mismatch!\")\n"
+ << " file(TOUCH_NOCREATE \"" << stampFile << "\")\n"
+ << "endif()\n";
+ }
+ verifyScriptFile.Close();
+
+ cmsys::ofstream verifyStampFile(stampFile.c_str());
+ if (!verifyStampFile) {
+ cmSystemTools::Error("Unable to open verification stamp file for write. " +
+ stampFile);
+ return false;
+ }
+ verifyStampFile << "# This file is generated by CMake for checking of the "
+ "VerifyGlobs.cmake file\n";
+ this->VerifyScript = scriptFile;
+ this->VerifyStamp = stampFile;
+ return true;
+}
+
+bool cmGlobVerificationManager::DoWriteVerifyTarget() const
+{
+ return !this->VerifyScript.empty() && !this->VerifyStamp.empty();
+}
+
+bool cmGlobVerificationManager::CacheEntryKey::operator<(
+ const CacheEntryKey& r) const
+{
+ if (this->Recurse < r.Recurse) {
+ return true;
+ }
+ if (this->Recurse > r.Recurse) {
+ return false;
+ }
+ if (this->ListDirectories < r.ListDirectories) {
+ return true;
+ }
+ if (this->ListDirectories > r.ListDirectories) {
+ return false;
+ }
+ if (this->FollowSymlinks < r.FollowSymlinks) {
+ return true;
+ }
+ if (this->FollowSymlinks > r.FollowSymlinks) {
+ return false;
+ }
+ if (this->Relative < r.Relative) {
+ return true;
+ }
+ if (this->Relative > r.Relative) {
+ return false;
+ }
+ if (this->Expression < r.Expression) {
+ return true;
+ }
+ if (this->Expression > r.Expression) {
+ return false;
+ }
+ return false;
+}
+
+void cmGlobVerificationManager::CacheEntryKey::PrintGlobCommand(
+ std::ostream& out, const std::string& cmdVar)
+{
+ out << "file(GLOB" << (this->Recurse ? "_RECURSE " : " ");
+ out << cmdVar << " ";
+ if (this->Recurse && this->FollowSymlinks) {
+ out << "FOLLOW_SYMLINKS ";
+ }
+ out << "LIST_DIRECTORIES " << this->ListDirectories << " ";
+ if (!this->Relative.empty()) {
+ out << "RELATIVE \"" << this->Relative << "\" ";
+ }
+ out << "\"" << this->Expression << "\")";
+}
+
+void cmGlobVerificationManager::AddCacheEntry(
+ const bool recurse, const bool listDirectories, const bool followSymlinks,
+ const std::string& relative, const std::string& expression,
+ const std::vector<std::string>& files, const std::string& variable,
+ const cmListFileBacktrace& backtrace)
+{
+ CacheEntryKey key = CacheEntryKey(recurse, listDirectories, followSymlinks,
+ relative, expression);
+ CacheEntryValue& value = this->Cache[key];
+ if (!value.Initialized) {
+ value.Files = files;
+ value.Initialized = true;
+ value.Backtraces.emplace_back(variable, backtrace);
+ } else if (value.Initialized && value.Files != files) {
+ std::ostringstream message;
+ message << std::boolalpha;
+ message << "The glob expression\n";
+ key.PrintGlobCommand(message, variable);
+ backtrace.PrintTitle(message);
+ message << "\nwas already present in the glob cache but the directory\n"
+ "contents have changed during the configuration run.\n";
+ message << "Matching glob expressions:";
+ for (auto const& bt : value.Backtraces) {
+ message << "\n " << std::get<0>(bt);
+ std::get<1>(bt).PrintTitle(message);
+ }
+ cmSystemTools::Error(message.str());
+ } else {
+ value.Backtraces.emplace_back(variable, backtrace);
+ }
+}
+
+void cmGlobVerificationManager::Reset()
+{
+ this->Cache.clear();
+ this->VerifyScript.clear();
+ this->VerifyStamp.clear();
+}
diff --git a/Source/cmGlobVerificationManager.h b/Source/cmGlobVerificationManager.h
new file mode 100644
index 0000000..b618fb0
--- /dev/null
+++ b/Source/cmGlobVerificationManager.h
@@ -0,0 +1,82 @@
+/* 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 <iosfwd>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmListFileCache.h"
+
+/** \class cmGlobVerificationManager
+ * \brief Class for expressing build-time dependencies on glob expressions.
+ *
+ * Generates a CMake script which verifies glob outputs during prebuild.
+ *
+ */
+class cmGlobVerificationManager
+{
+protected:
+ //! Save verification script for given makefile.
+ //! Saves to output <path>/<CMakeFilesDirectory>/VerifyGlobs.cmake
+ bool SaveVerificationScript(const std::string& path);
+
+ //! Add an entry into the glob cache
+ void AddCacheEntry(bool recurse, bool listDirectories, bool followSymlinks,
+ const std::string& relative,
+ const std::string& expression,
+ const std::vector<std::string>& files,
+ const std::string& variable,
+ const cmListFileBacktrace& bt);
+
+ //! Clear the glob cache for state reset.
+ void Reset();
+
+ //! Check targets should be written in generated build system.
+ bool DoWriteVerifyTarget() const;
+
+ //! Get the paths to the generated script and stamp files
+ std::string const& GetVerifyScript() const { return this->VerifyScript; }
+ std::string const& GetVerifyStamp() const { return this->VerifyStamp; }
+
+private:
+ struct CacheEntryKey
+ {
+ const bool Recurse;
+ const bool ListDirectories;
+ const bool FollowSymlinks;
+ const std::string Relative;
+ const std::string Expression;
+ CacheEntryKey(const bool rec, const bool l, const bool s, std::string rel,
+ std::string e)
+ : Recurse(rec)
+ , ListDirectories(l)
+ , FollowSymlinks(s)
+ , Relative(std::move(rel))
+ , Expression(std::move(e))
+ {
+ }
+ bool operator<(const CacheEntryKey& r) const;
+ void PrintGlobCommand(std::ostream& out, const std::string& cmdVar);
+ };
+
+ struct CacheEntryValue
+ {
+ bool Initialized = false;
+ std::vector<std::string> Files;
+ std::vector<std::pair<std::string, cmListFileBacktrace>> Backtraces;
+ };
+
+ using CacheEntryMap = std::map<CacheEntryKey, CacheEntryValue>;
+ CacheEntryMap Cache;
+ std::string VerifyScript;
+ std::string VerifyStamp;
+
+ // Only cmState should be able to add cache values.
+ // cmGlobVerificationManager should never be used directly.
+ friend class cmState; // allow access to add cache values
+};
diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx
new file mode 100644
index 0000000..996fcff
--- /dev/null
+++ b/Source/cmGlobalBorlandMakefileGenerator.cxx
@@ -0,0 +1,96 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalBorlandMakefileGenerator.h"
+
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmDocumentationEntry.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmState.h"
+#include "cmake.h"
+
+cmGlobalBorlandMakefileGenerator::cmGlobalBorlandMakefileGenerator(cmake* cm)
+ : cmGlobalUnixMakefileGenerator3(cm)
+{
+ this->EmptyRuleHackDepends = "NUL";
+ this->FindMakeProgramFile = "CMakeBorlandFindMake.cmake";
+ this->ForceUnixPaths = false;
+ this->ToolSupportsColor = true;
+ this->UseLinkScript = false;
+ cm->GetState()->SetWindowsShell(true);
+ this->IncludeDirective = "!include";
+ this->DefineWindowsNULL = true;
+ this->PassMakeflags = true;
+ this->UnixCD = false;
+
+ /*
+ * Borland Make does not support long line depend rule, as we have tested
+ * generate one source file includes 40000 header files, and generate
+ * depend.make in one line(use line continued tag), and error occured:
+ * ** Fatal CMakeFiles\main.dir\depend.make 1224: Rule line too long **
+ * we disable long line dependencies rule generation for Borland make
+ */
+ this->ToolSupportsLongLineDependencies = false;
+}
+
+void cmGlobalBorlandMakefileGenerator::EnableLanguage(
+ std::vector<std::string> const& l, cmMakefile* mf, bool optional)
+{
+ std::string outdir = this->CMakeInstance->GetHomeOutputDirectory();
+ mf->AddDefinition("BORLAND", "1");
+ mf->AddDefinition("CMAKE_GENERATOR_CC", "bcc32");
+ mf->AddDefinition("CMAKE_GENERATOR_CXX", "bcc32");
+ this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
+}
+
+//! Create a local generator appropriate to this Global Generator
+std::unique_ptr<cmLocalGenerator>
+cmGlobalBorlandMakefileGenerator::CreateLocalGenerator(cmMakefile* mf)
+{
+ auto lg = cm::make_unique<cmLocalUnixMakefileGenerator3>(this, mf);
+ lg->SetMakefileVariableSize(32);
+ lg->SetMakeCommandEscapeTargetTwice(true);
+ lg->SetBorlandMakeCurlyHack(true);
+ return std::unique_ptr<cmLocalGenerator>(std::move(lg));
+}
+
+void cmGlobalBorlandMakefileGenerator::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalBorlandMakefileGenerator::GetActualName();
+ entry.Brief = "Generates Borland makefiles.";
+}
+
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalBorlandMakefileGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int /*jobs*/, bool verbose,
+ std::vector<std::string> const& makeOptions)
+{
+ return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast,
+ cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
+}
+
+void cmGlobalBorlandMakefileGenerator::PrintBuildCommandAdvice(
+ std::ostream& os, int jobs) const
+{
+ if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
+ // Borland's make does not support parallel builds
+ // see http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Make
+
+ /* clang-format off */
+ os <<
+ "Warning: Borland's make does not support parallel builds. "
+ "Ignoring parallel build command line option.\n";
+ /* clang-format on */
+ }
+
+ this->cmGlobalUnixMakefileGenerator3::PrintBuildCommandAdvice(
+ os, cmake::NO_BUILD_PARALLEL_LEVEL);
+}
diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h
new file mode 100644
index 0000000..5a4e8c2
--- /dev/null
+++ b/Source/cmGlobalBorlandMakefileGenerator.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 <iosfwd>
+#include <memory>
+
+#include "cmGlobalNMakeMakefileGenerator.h"
+
+/** \class cmGlobalBorlandMakefileGenerator
+ * \brief Write a Borland makefiles.
+ *
+ * cmGlobalBorlandMakefileGenerator manages nmake build process for a tree
+ */
+class cmGlobalBorlandMakefileGenerator : public cmGlobalUnixMakefileGenerator3
+{
+public:
+ cmGlobalBorlandMakefileGenerator(cmake* cm);
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
+ {
+ return std::unique_ptr<cmGlobalGeneratorFactory>(
+ new cmGlobalGeneratorSimpleFactory<cmGlobalBorlandMakefileGenerator>());
+ }
+
+ //! Get the name for the generator.
+ std::string GetName() const override
+ {
+ return cmGlobalBorlandMakefileGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "Borland Makefiles"; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ //! Create a local generator appropriate to this Global Generator
+ std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+ cmMakefile* mf) override;
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) override;
+
+ bool AllowNotParallel() const override { return false; }
+ bool AllowDeleteOnError() const override { return false; }
+ bool CanEscapeOctothorpe() const override { return true; }
+
+protected:
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
+
+ void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
+};
diff --git a/Source/cmGlobalCommonGenerator.cxx b/Source/cmGlobalCommonGenerator.cxx
new file mode 100644
index 0000000..9e5bbca
--- /dev/null
+++ b/Source/cmGlobalCommonGenerator.cxx
@@ -0,0 +1,97 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalCommonGenerator.h"
+
+#include <memory>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+
+class cmake;
+
+cmGlobalCommonGenerator::cmGlobalCommonGenerator(cmake* cm)
+ : cmGlobalGenerator(cm)
+{
+}
+
+cmGlobalCommonGenerator::~cmGlobalCommonGenerator() = default;
+
+std::map<std::string, cmGlobalCommonGenerator::DirectoryTarget>
+cmGlobalCommonGenerator::ComputeDirectoryTargets() const
+{
+ std::map<std::string, DirectoryTarget> dirTargets;
+ for (const auto& lg : this->LocalGenerators) {
+ std::string const& currentBinaryDir(
+ lg->GetStateSnapshot().GetDirectory().GetCurrentBinary());
+ DirectoryTarget& dirTarget = dirTargets[currentBinaryDir];
+ dirTarget.LG = lg.get();
+ const std::vector<std::string>& configs =
+ lg->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+ // The directory-level rule should depend on the target-level rules
+ // for all targets in the directory.
+ for (const auto& gt : lg->GetGeneratorTargets()) {
+ cmStateEnums::TargetType const type = gt->GetType();
+ if (type == cmStateEnums::GLOBAL_TARGET || !gt->IsInBuildSystem()) {
+ continue;
+ }
+ DirectoryTarget::Target t;
+ t.GT = gt.get();
+ const std::string EXCLUDE_FROM_ALL("EXCLUDE_FROM_ALL");
+ if (cmProp exclude = gt->GetProperty(EXCLUDE_FROM_ALL)) {
+ for (const std::string& config : configs) {
+ cmGeneratorExpressionInterpreter genexInterpreter(lg.get(), config,
+ gt.get());
+ if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) {
+ // This target has been explicitly excluded.
+ t.ExcludedFromAllInConfigs.push_back(config);
+ }
+ }
+
+ if (t.ExcludedFromAllInConfigs.empty()) {
+ // This target has been explicitly un-excluded. The directory-level
+ // rule for every directory between this and the root should depend
+ // on the target-level rule for this target.
+ for (cmStateSnapshot dir =
+ lg->GetStateSnapshot().GetBuildsystemDirectoryParent();
+ dir.IsValid(); dir = dir.GetBuildsystemDirectoryParent()) {
+ std::string const& d = dir.GetDirectory().GetCurrentBinary();
+ dirTargets[d].Targets.emplace_back(t);
+ }
+ }
+ }
+ dirTarget.Targets.emplace_back(t);
+ }
+
+ // The directory-level rule should depend on the directory-level
+ // rules of the subdirectories.
+ for (cmStateSnapshot const& state : lg->GetStateSnapshot().GetChildren()) {
+ DirectoryTarget::Dir d;
+ d.Path = state.GetDirectory().GetCurrentBinary();
+ d.ExcludeFromAll =
+ state.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL");
+ dirTarget.Children.emplace_back(std::move(d));
+ }
+ }
+
+ return dirTargets;
+}
+
+bool cmGlobalCommonGenerator::IsExcludedFromAllInConfig(
+ const DirectoryTarget::Target& t, const std::string& config)
+{
+ if (this->IsMultiConfig()) {
+ return cm::contains(t.ExcludedFromAllInConfigs, config);
+ }
+ return !t.ExcludedFromAllInConfigs.empty();
+}
diff --git a/Source/cmGlobalCommonGenerator.h b/Source/cmGlobalCommonGenerator.h
new file mode 100644
index 0000000..2aa9d27
--- /dev/null
+++ b/Source/cmGlobalCommonGenerator.h
@@ -0,0 +1,45 @@
+/* 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 <map>
+#include <string>
+#include <vector>
+
+#include "cmGlobalGenerator.h"
+
+class cmake;
+class cmGeneratorTarget;
+class cmLocalGenerator;
+
+/** \class cmGlobalCommonGenerator
+ * \brief Common infrastructure for Makefile and Ninja global generators.
+ */
+class cmGlobalCommonGenerator : public cmGlobalGenerator
+{
+public:
+ cmGlobalCommonGenerator(cmake* cm);
+ ~cmGlobalCommonGenerator() override;
+
+ struct DirectoryTarget
+ {
+ cmLocalGenerator* LG = nullptr;
+ struct Target
+ {
+ cmGeneratorTarget const* GT = nullptr;
+ std::vector<std::string> ExcludedFromAllInConfigs;
+ };
+ std::vector<Target> Targets;
+ struct Dir
+ {
+ std::string Path;
+ bool ExcludeFromAll = false;
+ };
+ std::vector<Dir> Children;
+ };
+ std::map<std::string, DirectoryTarget> ComputeDirectoryTargets() const;
+ bool IsExcludedFromAllInConfig(const DirectoryTarget::Target& t,
+ const std::string& config);
+};
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
new file mode 100644
index 0000000..ab76260
--- /dev/null
+++ b/Source/cmGlobalGenerator.cxx
@@ -0,0 +1,3331 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalGenerator.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <initializer_list>
+#include <iterator>
+#include <sstream>
+#include <utility>
+
+#include <cm/memory>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <windows.h>
+#endif
+
+#include "cmAlgorithms.h"
+#include "cmCPackPropertiesGenerator.h"
+#include "cmComputeTargetDepends.h"
+#include "cmCustomCommand.h"
+#include "cmCustomCommandLines.h"
+#include "cmDuration.h"
+#include "cmExportBuildFileGenerator.h"
+#include "cmExternalMakefileProjectGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmInstallGenerator.h"
+#include "cmLinkLineComputer.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMSVC60LinkLineComputer.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateTypes.h"
+#include "cmVersion.h"
+#include "cmWorkingDirectory.h"
+#include "cmake.h"
+
+#if !defined(CMAKE_BOOTSTRAP)
+# include <cm3p/json/value.h>
+# include <cm3p/json/writer.h>
+
+# include "cmCryptoHash.h"
+# include "cmQtAutoGenGlobalInitializer.h"
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#endif
+
+const std::string kCMAKE_PLATFORM_INFO_INITIALIZED =
+ "CMAKE_PLATFORM_INFO_INITIALIZED";
+
+class cmInstalledFile;
+
+bool cmTarget::StrictTargetComparison::operator()(cmTarget const* t1,
+ cmTarget const* t2) const
+{
+ int nameResult = strcmp(t1->GetName().c_str(), t2->GetName().c_str());
+ if (nameResult == 0) {
+ return strcmp(t1->GetMakefile()->GetCurrentBinaryDirectory().c_str(),
+ t2->GetMakefile()->GetCurrentBinaryDirectory().c_str()) < 0;
+ }
+ return nameResult < 0;
+}
+
+cmGlobalGenerator::cmGlobalGenerator(cmake* cm)
+ : CMakeInstance(cm)
+{
+ // By default the .SYMBOLIC dependency is not needed on symbolic rules.
+ this->NeedSymbolicMark = false;
+
+ // by default use the native paths
+ this->ForceUnixPaths = false;
+
+ // By default do not try to support color.
+ this->ToolSupportsColor = false;
+
+ // By default do not use link scripts.
+ this->UseLinkScript = false;
+
+ // Whether an install target is needed.
+ this->InstallTargetEnabled = false;
+
+ // how long to let try compiles run
+ this->TryCompileTimeout = cmDuration::zero();
+
+ this->CurrentConfigureMakefile = nullptr;
+ this->TryCompileOuterMakefile = nullptr;
+
+ this->ConfigureDoneCMP0026AndCMP0024 = false;
+ this->FirstTimeProgress = 0.0f;
+
+ this->RecursionDepth = 0;
+
+ cm->GetState()->SetIsGeneratorMultiConfig(false);
+ cm->GetState()->SetMinGWMake(false);
+ cm->GetState()->SetMSYSShell(false);
+ cm->GetState()->SetNMake(false);
+ cm->GetState()->SetWatcomWMake(false);
+ cm->GetState()->SetWindowsShell(false);
+ cm->GetState()->SetWindowsVSIDE(false);
+}
+
+cmGlobalGenerator::~cmGlobalGenerator()
+{
+ this->ClearGeneratorMembers();
+}
+
+#if !defined(CMAKE_BOOTSTRAP)
+Json::Value cmGlobalGenerator::GetJson() const
+{
+ Json::Value generator = Json::objectValue;
+ generator["name"] = this->GetName();
+ generator["multiConfig"] = this->IsMultiConfig();
+ return generator;
+}
+#endif
+
+bool cmGlobalGenerator::SetGeneratorInstance(std::string const& i,
+ cmMakefile* mf)
+{
+ if (i.empty()) {
+ return true;
+ }
+
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "does not support instance specification, but instance\n"
+ " " << i << "\n"
+ "was specified.";
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+}
+
+bool cmGlobalGenerator::SetGeneratorPlatform(std::string const& p,
+ cmMakefile* mf)
+{
+ if (p.empty()) {
+ return true;
+ }
+
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "does not support platform specification, but platform\n"
+ " " << p << "\n"
+ "was specified.";
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+}
+
+bool cmGlobalGenerator::SetGeneratorToolset(std::string const& ts, bool,
+ cmMakefile* mf)
+{
+ if (ts.empty()) {
+ return true;
+ }
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "does not support toolset specification, but toolset\n"
+ " " << ts << "\n"
+ "was specified.";
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+}
+
+std::string cmGlobalGenerator::SelectMakeProgram(
+ const std::string& inMakeProgram, const std::string& makeDefault) const
+{
+ std::string makeProgram = inMakeProgram;
+ if (cmIsOff(makeProgram)) {
+ cmProp makeProgramCSTR =
+ this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
+ if (cmIsOff(makeProgramCSTR)) {
+ makeProgram = makeDefault;
+ } else {
+ makeProgram = *makeProgramCSTR;
+ }
+ if (cmIsOff(makeProgram) && !makeProgram.empty()) {
+ makeProgram = "CMAKE_MAKE_PROGRAM-NOTFOUND";
+ }
+ }
+ return makeProgram;
+}
+
+void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang,
+ cmMakefile* mf,
+ bool optional) const
+{
+ std::string langComp = cmStrCat("CMAKE_", lang, "_COMPILER");
+
+ if (!mf->GetDefinition(langComp)) {
+ if (!optional) {
+ cmSystemTools::Error(langComp + " not set, after EnableLanguage");
+ }
+ return;
+ }
+ std::string const& name = mf->GetRequiredDefinition(langComp);
+ std::string path;
+ if (!cmSystemTools::FileIsFullPath(name)) {
+ path = cmSystemTools::FindProgram(name);
+ } else {
+ path = name;
+ }
+ if (!optional && (path.empty() || !cmSystemTools::FileExists(path))) {
+ return;
+ }
+ cmProp cname =
+ this->GetCMakeInstance()->GetState()->GetInitializedCacheValue(langComp);
+
+ // Split compiler from arguments
+ std::vector<std::string> cnameArgVec;
+ if (cname && !cname->empty()) {
+ cmExpandList(*cname, cnameArgVec);
+ cname = &cnameArgVec.front();
+ }
+
+ std::string changeVars;
+ if (cname && !optional) {
+ std::string cnameString;
+ if (!cmSystemTools::FileIsFullPath(*cname)) {
+ cnameString = cmSystemTools::FindProgram(*cname);
+ } else {
+ cnameString = *cname;
+ }
+ std::string pathString = path;
+ // get rid of potentially multiple slashes:
+ cmSystemTools::ConvertToUnixSlashes(cnameString);
+ cmSystemTools::ConvertToUnixSlashes(pathString);
+ if (cnameString != pathString) {
+ cmProp cvars = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
+ "__CMAKE_DELETE_CACHE_CHANGE_VARS_");
+ if (cvars) {
+ changeVars += *cvars;
+ changeVars += ";";
+ }
+ changeVars += langComp;
+ changeVars += ";";
+ changeVars += *cname;
+ this->GetCMakeInstance()->GetState()->SetGlobalProperty(
+ "__CMAKE_DELETE_CACHE_CHANGE_VARS_", changeVars.c_str());
+ }
+ }
+}
+
+void cmGlobalGenerator::AddBuildExportSet(cmExportBuildFileGenerator* gen)
+{
+ this->BuildExportSets[gen->GetMainExportFileName()] = gen;
+}
+
+void cmGlobalGenerator::AddBuildExportExportSet(
+ cmExportBuildFileGenerator* gen)
+{
+ this->BuildExportExportSets[gen->GetMainExportFileName()] = gen;
+ this->AddBuildExportSet(gen);
+}
+
+bool cmGlobalGenerator::GenerateImportFile(const std::string& file)
+{
+ auto const it = this->BuildExportSets.find(file);
+ if (it != this->BuildExportSets.end()) {
+ bool result = it->second->GenerateImportFile();
+
+ if (!this->ConfigureDoneCMP0026AndCMP0024) {
+ for (const auto& m : this->Makefiles) {
+ m->RemoveExportBuildFileGeneratorCMP0024(it->second);
+ }
+ }
+
+ this->BuildExportSets.erase(it);
+ return result;
+ }
+ return false;
+}
+
+void cmGlobalGenerator::ForceLinkerLanguages()
+{
+}
+
+bool cmGlobalGenerator::CheckTargetsForMissingSources() const
+{
+ bool failed = false;
+ for (const auto& localGen : this->LocalGenerators) {
+ for (const auto& target : localGen->GetGeneratorTargets()) {
+ if (!target->CanCompileSources() ||
+ cmIsOn(target->GetProperty("ghs_integrity_app"))) {
+ continue;
+ }
+
+ if (target->GetAllConfigSources().empty()) {
+ std::ostringstream e;
+ e << "No SOURCES given to target: " << target->GetName();
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR, e.str(), target->GetBacktrace());
+ failed = true;
+ }
+ }
+ }
+ return failed;
+}
+
+bool cmGlobalGenerator::CheckTargetsForType() const
+{
+ if (!this->GetLanguageEnabled("Swift")) {
+ return false;
+ }
+ bool failed = false;
+ for (const auto& generator : this->LocalGenerators) {
+ for (const auto& target : generator->GetGeneratorTargets()) {
+ if (target->GetType() == cmStateEnums::EXECUTABLE) {
+ std::vector<std::string> const& configs =
+ target->Makefile->GetGeneratorConfigs(
+ cmMakefile::IncludeEmptyConfig);
+ for (std::string const& config : configs) {
+ if (target->IsWin32Executable(config) &&
+ target->GetLinkerLanguage(config) == "Swift") {
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "WIN32_EXECUTABLE property is not supported on Swift "
+ "executables",
+ target->GetBacktrace());
+ failed = true;
+ }
+ }
+ }
+ }
+ }
+ return failed;
+}
+
+bool cmGlobalGenerator::CheckTargetsForPchCompilePdb() const
+{
+ if (!this->GetLanguageEnabled("C") && !this->GetLanguageEnabled("CXX")) {
+ return false;
+ }
+ bool failed = false;
+ for (const auto& generator : this->LocalGenerators) {
+ for (const auto& target : generator->GetGeneratorTargets()) {
+ if (!target->CanCompileSources() ||
+ cmIsOn(target->GetProperty("ghs_integrity_app"))) {
+ continue;
+ }
+
+ std::string const& reuseFrom =
+ target->GetSafeProperty("PRECOMPILE_HEADERS_REUSE_FROM");
+ std::string const& compilePdb =
+ target->GetSafeProperty("COMPILE_PDB_NAME");
+
+ if (!reuseFrom.empty() && reuseFrom != compilePdb) {
+ const std::string e = cmStrCat(
+ "PRECOMPILE_HEADERS_REUSE_FROM property is set on target (\"",
+ target->GetName(),
+ "\"). Reusable precompile headers requires the COMPILE_PDB_NAME"
+ " property to have the value \"",
+ reuseFrom, "\"\n");
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e,
+ target->GetBacktrace());
+ failed = true;
+ }
+ }
+ }
+ return failed;
+}
+
+bool cmGlobalGenerator::IsExportedTargetsFile(
+ const std::string& filename) const
+{
+ auto const it = this->BuildExportSets.find(filename);
+ if (it == this->BuildExportSets.end()) {
+ return false;
+ }
+ return !cm::contains(this->BuildExportExportSets, filename);
+}
+
+// Find the make program for the generator, required for try compiles
+bool cmGlobalGenerator::FindMakeProgram(cmMakefile* mf)
+{
+ if (this->FindMakeProgramFile.empty()) {
+ cmSystemTools::Error(
+ "Generator implementation error, "
+ "all generators must specify this->FindMakeProgramFile");
+ return false;
+ }
+ if (cmIsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
+ std::string setMakeProgram = mf->GetModulesFile(this->FindMakeProgramFile);
+ if (!setMakeProgram.empty()) {
+ mf->ReadListFile(setMakeProgram);
+ }
+ }
+ if (cmIsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
+ std::ostringstream err;
+ err << "CMake was unable to find a build program corresponding to \""
+ << this->GetName() << "\". CMAKE_MAKE_PROGRAM is not set. You "
+ << "probably need to select a different build tool.";
+ cmSystemTools::Error(err.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ // if there are spaces in the make program use short path
+ // but do not short path the actual program name, as
+ // this can cause trouble with VSExpress
+ if (makeProgram.find(' ') != std::string::npos) {
+ std::string dir;
+ std::string file;
+ cmSystemTools::SplitProgramPath(makeProgram, dir, file);
+ std::string saveFile = file;
+ cmSystemTools::GetShortPath(makeProgram, makeProgram);
+ cmSystemTools::SplitProgramPath(makeProgram, dir, file);
+ makeProgram = cmStrCat(dir, '/', saveFile);
+ mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", makeProgram, "make program",
+ cmStateEnums::FILEPATH);
+ }
+ return true;
+}
+
+bool cmGlobalGenerator::CheckLanguages(
+ std::vector<std::string> const& /* languages */, cmMakefile* /* mf */) const
+{
+ return true;
+}
+
+// enable the given language
+//
+// The following files are loaded in this order:
+//
+// First figure out what OS we are running on:
+//
+// CMakeSystem.cmake - configured file created by CMakeDetermineSystem.cmake
+// CMakeDetermineSystem.cmake - figure out os info and create
+// CMakeSystem.cmake IF CMAKE_SYSTEM
+// not set
+// CMakeSystem.cmake - configured file created by
+// CMakeDetermineSystem.cmake IF CMAKE_SYSTEM_LOADED
+
+// CMakeSystemSpecificInitialize.cmake
+// - includes Platform/${CMAKE_SYSTEM_NAME}-Initialize.cmake
+
+// Next try and enable all languages found in the languages vector
+//
+// FOREACH LANG in languages
+// CMake(LANG)Compiler.cmake - configured file create by
+// CMakeDetermine(LANG)Compiler.cmake
+// CMakeDetermine(LANG)Compiler.cmake - Finds compiler for LANG and
+// creates CMake(LANG)Compiler.cmake
+// CMake(LANG)Compiler.cmake - configured file created by
+// CMakeDetermine(LANG)Compiler.cmake
+//
+// CMakeSystemSpecificInformation.cmake
+// - includes Platform/${CMAKE_SYSTEM_NAME}.cmake
+// may use compiler stuff
+
+// FOREACH LANG in languages
+// CMake(LANG)Information.cmake
+// - loads Platform/${CMAKE_SYSTEM_NAME}-${COMPILER}.cmake
+// CMakeTest(LANG)Compiler.cmake
+// - Make sure the compiler works with a try compile if
+// CMakeDetermine(LANG) was loaded
+//
+// Now load a few files that can override values set in any of the above
+// (PROJECTNAME)Compatibility.cmake
+// - load any backwards compatibility stuff for current project
+// ${CMAKE_USER_MAKE_RULES_OVERRIDE}
+// - allow users a chance to override system variables
+//
+//
+
+void cmGlobalGenerator::EnableLanguage(
+ std::vector<std::string> const& languages, cmMakefile* mf, bool optional)
+{
+ if (languages.empty()) {
+ cmSystemTools::Error("EnableLanguage must have a lang specified!");
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+
+ std::set<std::string> cur_languages(languages.begin(), languages.end());
+ for (std::string const& li : cur_languages) {
+ if (!this->LanguagesInProgress.insert(li).second) {
+ std::ostringstream e;
+ e << "Language '" << li
+ << "' is currently being enabled. "
+ "Recursive call not allowed.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+ }
+
+ if (this->TryCompileOuterMakefile) {
+ // In a try-compile we can only enable languages provided by caller.
+ for (std::string const& lang : languages) {
+ if (lang == "NONE") {
+ this->SetLanguageEnabled("NONE", mf);
+ } else {
+ if (!cm::contains(this->LanguagesReady, lang)) {
+ std::ostringstream e;
+ e << "The test project needs language " << lang
+ << " which is not enabled.";
+ this->TryCompileOuterMakefile->IssueMessage(MessageType::FATAL_ERROR,
+ e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+ }
+ }
+ }
+
+ bool fatalError = false;
+
+ mf->AddDefinitionBool("RUN_CONFIGURE", true);
+ std::string rootBin =
+ cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(), "/CMakeFiles");
+
+ // If the configuration files path has been set,
+ // then we are in a try compile and need to copy the enable language
+ // files from the parent cmake bin dir, into the try compile bin dir
+ if (!this->ConfiguredFilesPath.empty()) {
+ rootBin = this->ConfiguredFilesPath;
+ }
+ rootBin += '/';
+ rootBin += cmVersion::GetCMakeVersion();
+
+ // set the dir for parent files so they can be used by modules
+ mf->AddDefinition("CMAKE_PLATFORM_INFO_DIR", rootBin);
+
+ if (!this->CMakeInstance->GetIsInTryCompile()) {
+ // Keep a mark in the cache to indicate that we've initialized the
+ // platform information directory. If the platform information
+ // directory exists but the mark is missing then CMakeCache.txt
+ // has been removed or replaced without also removing the CMakeFiles/
+ // directory. In this case remove the platform information directory
+ // so that it will be re-initialized and the relevant information
+ // restored in the cache.
+ if (cmSystemTools::FileIsDirectory(rootBin) &&
+ !mf->IsOn(kCMAKE_PLATFORM_INFO_INITIALIZED)) {
+ cmSystemTools::RemoveADirectory(rootBin);
+ }
+ this->GetCMakeInstance()->AddCacheEntry(
+ kCMAKE_PLATFORM_INFO_INITIALIZED, "1",
+ "Platform information initialized", cmStateEnums::INTERNAL);
+ }
+
+ // try and load the CMakeSystem.cmake if it is there
+ std::string fpath = rootBin;
+ bool const readCMakeSystem = !mf->GetDefinition("CMAKE_SYSTEM_LOADED");
+ if (readCMakeSystem) {
+ fpath += "/CMakeSystem.cmake";
+ if (cmSystemTools::FileExists(fpath)) {
+ mf->ReadListFile(fpath);
+ }
+ }
+
+ if (readCMakeSystem) {
+ // Find the native build tool for this generator.
+ // This has to be done early so that MSBuild can be used to examine the
+ // cross-compilation environment.
+ if (this->GetFindMakeProgramStage() == FindMakeProgramStage::Early &&
+ !this->FindMakeProgram(mf)) {
+ return;
+ }
+ }
+
+ // Load the CMakeDetermineSystem.cmake file and find out
+ // what platform we are running on
+ if (!mf->GetDefinition("CMAKE_SYSTEM")) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ /* Windows version number data. */
+ OSVERSIONINFOEXW osviex;
+ ZeroMemory(&osviex, sizeof(osviex));
+ osviex.dwOSVersionInfoSize = sizeof(osviex);
+
+# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+# pragma warning(push)
+# ifdef __INTEL_COMPILER
+# pragma warning(disable : 1478)
+# elif defined __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
+# else
+# pragma warning(disable : 4996)
+# endif
+# endif
+ GetVersionExW((OSVERSIONINFOW*)&osviex);
+# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+# ifdef __clang__
+# pragma clang diagnostic pop
+# else
+# pragma warning(pop)
+# endif
+# endif
+ std::ostringstream windowsVersionString;
+ windowsVersionString << osviex.dwMajorVersion << "."
+ << osviex.dwMinorVersion << "."
+ << osviex.dwBuildNumber;
+ mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION", windowsVersionString.str());
+#endif
+ // Read the DetermineSystem file
+ std::string systemFile = mf->GetModulesFile("CMakeDetermineSystem.cmake");
+ mf->ReadListFile(systemFile);
+ // load the CMakeSystem.cmake from the binary directory
+ // this file is configured by the CMakeDetermineSystem.cmake file
+ fpath = cmStrCat(rootBin, "/CMakeSystem.cmake");
+ mf->ReadListFile(fpath);
+ }
+
+ if (readCMakeSystem) {
+ // Tell the generator about the instance, if any.
+ std::string instance = mf->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE");
+ if (!this->SetGeneratorInstance(instance, mf)) {
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+
+ // Tell the generator about the target system.
+ std::string system = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME");
+ if (!this->SetSystemName(system, mf)) {
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+
+ // Tell the generator about the platform, if any.
+ std::string platform = mf->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM");
+ if (!this->SetGeneratorPlatform(platform, mf)) {
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+
+ // Tell the generator about the toolset, if any.
+ std::string toolset = mf->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET");
+ if (!this->SetGeneratorToolset(toolset, false, mf)) {
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+
+ // Find the native build tool for this generator.
+ if (this->GetFindMakeProgramStage() == FindMakeProgramStage::Late &&
+ !this->FindMakeProgram(mf)) {
+ return;
+ }
+ }
+
+ // Check that the languages are supported by the generator and its
+ // native build tool found above.
+ if (!this->CheckLanguages(languages, mf)) {
+ return;
+ }
+
+ // **** Load the system specific initialization if not yet loaded
+ if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INITIALIZE_LOADED")) {
+ fpath = mf->GetModulesFile("CMakeSystemSpecificInitialize.cmake");
+ if (!mf->ReadListFile(fpath)) {
+ cmSystemTools::Error("Could not find cmake module file: "
+ "CMakeSystemSpecificInitialize.cmake");
+ }
+ }
+
+ std::map<std::string, bool> needTestLanguage;
+ std::map<std::string, bool> needSetLanguageEnabledMaps;
+ // foreach language
+ // load the CMakeDetermine(LANG)Compiler.cmake file to find
+ // the compiler
+
+ for (std::string const& lang : languages) {
+ needSetLanguageEnabledMaps[lang] = false;
+ if (lang == "NONE") {
+ this->SetLanguageEnabled("NONE", mf);
+ continue;
+ }
+ std::string loadedLang = cmStrCat("CMAKE_", lang, "_COMPILER_LOADED");
+ if (!mf->GetDefinition(loadedLang)) {
+ fpath = cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
+
+ // If the existing build tree was already configured with this
+ // version of CMake then try to load the configured file first
+ // to avoid duplicate compiler tests.
+ if (cmSystemTools::FileExists(fpath)) {
+ if (!mf->ReadListFile(fpath)) {
+ cmSystemTools::Error("Could not find cmake module file: " + fpath);
+ }
+ // if this file was found then the language was already determined
+ // to be working
+ needTestLanguage[lang] = false;
+ this->SetLanguageEnabledFlag(lang, mf);
+ needSetLanguageEnabledMaps[lang] = true;
+ // this can only be called after loading CMake(LANG)Compiler.cmake
+ }
+ }
+
+ if (!this->GetLanguageEnabled(lang)) {
+ if (this->CMakeInstance->GetIsInTryCompile()) {
+ cmSystemTools::Error("This should not have happened. "
+ "If you see this message, you are probably "
+ "using a broken CMakeLists.txt file or a "
+ "problematic release of CMake");
+ }
+ // if the CMake(LANG)Compiler.cmake file was not found then
+ // load CMakeDetermine(LANG)Compiler.cmake
+ std::string determineCompiler =
+ cmStrCat("CMakeDetermine", lang, "Compiler.cmake");
+ std::string determineFile = mf->GetModulesFile(determineCompiler);
+ if (!mf->ReadListFile(determineFile)) {
+ cmSystemTools::Error("Could not find cmake module file: " +
+ determineCompiler);
+ }
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ return;
+ }
+ needTestLanguage[lang] = true;
+ // Some generators like visual studio should not use the env variables
+ // So the global generator can specify that in this variable
+ if (!mf->GetDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV")) {
+ // put ${CMake_(LANG)_COMPILER_ENV_VAR}=${CMAKE_(LANG)_COMPILER
+ // into the environment, in case user scripts want to run
+ // configure, or sub cmakes
+ std::string compilerName = cmStrCat("CMAKE_", lang, "_COMPILER");
+ std::string compilerEnv =
+ cmStrCat("CMAKE_", lang, "_COMPILER_ENV_VAR");
+ const std::string& envVar = mf->GetRequiredDefinition(compilerEnv);
+ const std::string& envVarValue =
+ mf->GetRequiredDefinition(compilerName);
+ std::string env = cmStrCat(envVar, '=', envVarValue);
+ cmSystemTools::PutEnv(env);
+ }
+
+ // if determineLanguage was called then load the file it
+ // configures CMake(LANG)Compiler.cmake
+ fpath = cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
+ if (!mf->ReadListFile(fpath)) {
+ cmSystemTools::Error("Could not find cmake module file: " + fpath);
+ }
+ this->SetLanguageEnabledFlag(lang, mf);
+ needSetLanguageEnabledMaps[lang] = true;
+ // this can only be called after loading CMake(LANG)Compiler.cmake
+ // the language must be enabled for try compile to work, but we do
+ // not know if it is a working compiler yet so set the test language
+ // flag
+ needTestLanguage[lang] = true;
+ } // end if(!this->GetLanguageEnabled(lang) )
+ } // end loop over languages
+
+ // **** Load the system specific information if not yet loaded
+ if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INFORMATION_LOADED")) {
+ fpath = mf->GetModulesFile("CMakeSystemSpecificInformation.cmake");
+ if (!mf->ReadListFile(fpath)) {
+ cmSystemTools::Error("Could not find cmake module file: "
+ "CMakeSystemSpecificInformation.cmake");
+ }
+ }
+ // loop over languages again loading CMake(LANG)Information.cmake
+ //
+ for (std::string const& lang : languages) {
+ if (lang == "NONE") {
+ this->SetLanguageEnabled("NONE", mf);
+ continue;
+ }
+
+ // Check that the compiler was found.
+ std::string compilerName = cmStrCat("CMAKE_", lang, "_COMPILER");
+ std::string compilerEnv = cmStrCat("CMAKE_", lang, "_COMPILER_ENV_VAR");
+ std::ostringstream noCompiler;
+ cmProp compilerFile = mf->GetDefinition(compilerName);
+ if (!cmNonempty(compilerFile) || cmIsNOTFOUND(*compilerFile)) {
+ /* clang-format off */
+ noCompiler <<
+ "No " << compilerName << " could be found.\n"
+ ;
+ /* clang-format on */
+ } else if ((lang != "RC") && (lang != "ASM_MASM")) {
+ if (!cmSystemTools::FileIsFullPath(*compilerFile)) {
+ /* clang-format off */
+ noCompiler <<
+ "The " << compilerName << ":\n"
+ " " << *compilerFile << "\n"
+ "is not a full path and was not found in the PATH.\n"
+ ;
+ /* clang-format on */
+ } else if (!cmSystemTools::FileExists(*compilerFile)) {
+ /* clang-format off */
+ noCompiler <<
+ "The " << compilerName << ":\n"
+ " " << *compilerFile << "\n"
+ "is not a full path to an existing compiler tool.\n"
+ ;
+ /* clang-format on */
+ }
+ }
+ if (!noCompiler.str().empty()) {
+ // Skip testing this language since the compiler is not found.
+ needTestLanguage[lang] = false;
+ if (!optional) {
+ // The compiler was not found and it is not optional. Remove
+ // CMake(LANG)Compiler.cmake so we try again next time CMake runs.
+ std::string compilerLangFile =
+ cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
+ cmSystemTools::RemoveFile(compilerLangFile);
+ if (!this->CMakeInstance->GetIsInTryCompile()) {
+ this->PrintCompilerAdvice(noCompiler, lang,
+ cmToCStr(mf->GetDefinition(compilerEnv)));
+ mf->IssueMessage(MessageType::FATAL_ERROR, noCompiler.str());
+ fatalError = true;
+ }
+ }
+ }
+
+ std::string langLoadedVar =
+ cmStrCat("CMAKE_", lang, "_INFORMATION_LOADED");
+ if (!mf->GetDefinition(langLoadedVar)) {
+ fpath = cmStrCat("CMake", lang, "Information.cmake");
+ std::string informationFile = mf->GetModulesFile(fpath);
+ if (informationFile.empty()) {
+ cmSystemTools::Error("Could not find cmake module file: " + fpath);
+ } else if (!mf->ReadListFile(informationFile)) {
+ cmSystemTools::Error("Could not process cmake module file: " +
+ informationFile);
+ }
+ }
+ if (needSetLanguageEnabledMaps[lang]) {
+ this->SetLanguageEnabledMaps(lang, mf);
+ }
+ this->LanguagesReady.insert(lang);
+
+ // Test the compiler for the language just setup
+ // (but only if a compiler has been actually found)
+ // At this point we should have enough info for a try compile
+ // which is used in the backward stuff
+ // If the language is untested then test it now with a try compile.
+ if (needTestLanguage[lang]) {
+ if (!this->CMakeInstance->GetIsInTryCompile()) {
+ std::string testLang = cmStrCat("CMakeTest", lang, "Compiler.cmake");
+ std::string ifpath = mf->GetModulesFile(testLang);
+ if (!mf->ReadListFile(ifpath)) {
+ cmSystemTools::Error("Could not find cmake module file: " +
+ testLang);
+ }
+ std::string compilerWorks =
+ cmStrCat("CMAKE_", lang, "_COMPILER_WORKS");
+ // if the compiler did not work, then remove the
+ // CMake(LANG)Compiler.cmake file so that it will get tested the
+ // next time cmake is run
+ if (!mf->IsOn(compilerWorks)) {
+ std::string compilerLangFile =
+ cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
+ cmSystemTools::RemoveFile(compilerLangFile);
+ }
+ } // end if in try compile
+ } // end need test language
+ // Store the shared library flags so that we can satisfy CMP0018
+ std::string sharedLibFlagsVar =
+ cmStrCat("CMAKE_SHARED_LIBRARY_", lang, "_FLAGS");
+ this->LanguageToOriginalSharedLibFlags[lang] =
+ mf->GetSafeDefinition(sharedLibFlagsVar);
+
+ // Translate compiler ids for compatibility.
+ this->CheckCompilerIdCompatibility(mf, lang);
+ } // end for each language
+
+ // Now load files that can override any settings on the platform or for
+ // the project First load the project compatibility file if it is in
+ // cmake
+ std::string projectCompatibility =
+ cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/",
+ mf->GetSafeDefinition("PROJECT_NAME"), "Compatibility.cmake");
+ if (cmSystemTools::FileExists(projectCompatibility)) {
+ mf->ReadListFile(projectCompatibility);
+ }
+ // Inform any extra generator of the new language.
+ if (this->ExtraGenerator) {
+ this->ExtraGenerator->EnableLanguage(languages, mf, false);
+ }
+
+ if (fatalError) {
+ cmSystemTools::SetFatalErrorOccured();
+ }
+
+ for (std::string const& lang : cur_languages) {
+ this->LanguagesInProgress.erase(lang);
+ }
+}
+
+void cmGlobalGenerator::PrintCompilerAdvice(std::ostream& os,
+ std::string const& lang,
+ const char* envVar) const
+{
+ // Subclasses override this method if they do not support this advice.
+ os << "Tell CMake where to find the compiler by setting ";
+ if (envVar) {
+ os << "either the environment variable \"" << envVar << "\" or ";
+ }
+ os << "the CMake cache entry CMAKE_" << lang
+ << "_COMPILER "
+ "to the full path to the compiler, or to the compiler name "
+ "if it is in the PATH.";
+}
+
+void cmGlobalGenerator::CheckCompilerIdCompatibility(
+ cmMakefile* mf, std::string const& lang) const
+{
+ std::string compilerIdVar = "CMAKE_" + lang + "_COMPILER_ID";
+ std::string const compilerId = mf->GetSafeDefinition(compilerIdVar);
+
+ if (compilerId == "AppleClang") {
+ switch (mf->GetPolicyStatus(cmPolicies::CMP0025)) {
+ case cmPolicies::WARN:
+ if (!this->CMakeInstance->GetIsInTryCompile() &&
+ mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0025")) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0025) << "\n"
+ "Converting " << lang <<
+ R"( compiler id "AppleClang" to "Clang" for compatibility.)"
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior is to convert AppleClang to Clang.
+ mf->AddDefinition(compilerIdVar, "Clang");
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ mf->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0025));
+ case cmPolicies::NEW:
+ // NEW behavior is to keep AppleClang.
+ break;
+ }
+ }
+
+ if (compilerId == "QCC") {
+ switch (mf->GetPolicyStatus(cmPolicies::CMP0047)) {
+ case cmPolicies::WARN:
+ if (!this->CMakeInstance->GetIsInTryCompile() &&
+ mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0047")) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0047) << "\n"
+ "Converting " << lang <<
+ R"( compiler id "QCC" to "GNU" for compatibility.)"
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior is to convert QCC to GNU.
+ mf->AddDefinition(compilerIdVar, "GNU");
+ if (lang == "C") {
+ mf->AddDefinition("CMAKE_COMPILER_IS_GNUCC", "1");
+ } else if (lang == "CXX") {
+ mf->AddDefinition("CMAKE_COMPILER_IS_GNUCXX", "1");
+ }
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ mf->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0047));
+ CM_FALLTHROUGH;
+ case cmPolicies::NEW:
+ // NEW behavior is to keep QCC.
+ break;
+ }
+ }
+
+ if (compilerId == "XLClang") {
+ switch (mf->GetPolicyStatus(cmPolicies::CMP0089)) {
+ case cmPolicies::WARN:
+ if (!this->CMakeInstance->GetIsInTryCompile() &&
+ mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0089")) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0089) << "\n"
+ "Converting " << lang <<
+ R"( compiler id "XLClang" to "XL" for compatibility.)"
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior is to convert XLClang to XL.
+ mf->AddDefinition(compilerIdVar, "XL");
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ mf->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0089));
+ case cmPolicies::NEW:
+ // NEW behavior is to keep AppleClang.
+ break;
+ }
+ }
+}
+
+std::string cmGlobalGenerator::GetLanguageOutputExtension(
+ cmSourceFile const& source) const
+{
+ const std::string& lang = source.GetLanguage();
+ if (!lang.empty()) {
+ auto const it = this->LanguageToOutputExtension.find(lang);
+ if (it != this->LanguageToOutputExtension.end()) {
+ return it->second;
+ }
+ } else {
+ // if no language is found then check to see if it is already an
+ // output extension for some language. In that case it should be ignored
+ // and in this map, so it will not be compiled but will just be used.
+ std::string const& ext = source.GetExtension();
+ if (!ext.empty()) {
+ if (this->OutputExtensions.count(ext)) {
+ return ext;
+ }
+ }
+ }
+ return "";
+}
+
+std::string cmGlobalGenerator::GetLanguageFromExtension(const char* ext) const
+{
+ // if there is an extension and it starts with . then move past the
+ // . because the extensions are not stored with a . in the map
+ if (ext && *ext == '.') {
+ ++ext;
+ }
+ auto const it = this->ExtensionToLanguage.find(ext);
+ if (it != this->ExtensionToLanguage.end()) {
+ return it->second;
+ }
+ return "";
+}
+
+/* SetLanguageEnabled() is now split in two parts:
+at first the enabled-flag is set. This can then be used in EnabledLanguage()
+for checking whether the language is already enabled. After setting this
+flag still the values from the cmake variables have to be copied into the
+internal maps, this is done in SetLanguageEnabledMaps() which is called
+after the system- and compiler specific files have been loaded.
+
+This split was done originally so that compiler-specific configuration
+files could change the object file extension
+(CMAKE_<LANG>_OUTPUT_EXTENSION) before the CMake variables were copied
+to the C++ maps.
+*/
+void cmGlobalGenerator::SetLanguageEnabled(const std::string& l,
+ cmMakefile* mf)
+{
+ this->SetLanguageEnabledFlag(l, mf);
+ this->SetLanguageEnabledMaps(l, mf);
+}
+
+void cmGlobalGenerator::SetLanguageEnabledFlag(const std::string& l,
+ cmMakefile* mf)
+{
+ this->CMakeInstance->GetState()->SetLanguageEnabled(l);
+
+ // Fill the language-to-extension map with the current variable
+ // settings to make sure it is available for the try_compile()
+ // command source file signature. In SetLanguageEnabledMaps this
+ // will be done again to account for any compiler- or
+ // platform-specific entries.
+ this->FillExtensionToLanguageMap(l, mf);
+}
+
+void cmGlobalGenerator::SetLanguageEnabledMaps(const std::string& l,
+ cmMakefile* mf)
+{
+ // use LanguageToLinkerPreference to detect whether this functions has
+ // run before
+ if (cm::contains(this->LanguageToLinkerPreference, l)) {
+ return;
+ }
+
+ std::string linkerPrefVar = "CMAKE_" + l + "_LINKER_PREFERENCE";
+ cmProp linkerPref = mf->GetDefinition(linkerPrefVar);
+ int preference = 0;
+ if (cmNonempty(linkerPref)) {
+ if (sscanf(linkerPref->c_str(), "%d", &preference) != 1) {
+ // backward compatibility: before 2.6 LINKER_PREFERENCE
+ // was either "None" or "Preferred", and only the first character was
+ // tested. So if there is a custom language out there and it is
+ // "Preferred", set its preference high
+ if ((*linkerPref)[0] == 'P') {
+ preference = 100;
+ } else {
+ preference = 0;
+ }
+ }
+ }
+
+ if (preference < 0) {
+ std::string msg =
+ cmStrCat(linkerPrefVar, " is negative, adjusting it to 0");
+ cmSystemTools::Message(msg, "Warning");
+ preference = 0;
+ }
+
+ this->LanguageToLinkerPreference[l] = preference;
+
+ std::string outputExtensionVar = "CMAKE_" + l + "_OUTPUT_EXTENSION";
+ if (cmProp p = mf->GetDefinition(outputExtensionVar)) {
+ std::string outputExtension = *p;
+ this->LanguageToOutputExtension[l] = outputExtension;
+ this->OutputExtensions[outputExtension] = outputExtension;
+ if (cmHasPrefix(outputExtension, ".")) {
+ outputExtension = outputExtension.substr(1);
+ this->OutputExtensions[outputExtension] = outputExtension;
+ }
+ }
+
+ // The map was originally filled by SetLanguageEnabledFlag, but
+ // since then the compiler- and platform-specific files have been
+ // loaded which might have added more entries.
+ this->FillExtensionToLanguageMap(l, mf);
+
+ std::string ignoreExtensionsVar =
+ std::string("CMAKE_") + std::string(l) + std::string("_IGNORE_EXTENSIONS");
+ std::string ignoreExts = mf->GetSafeDefinition(ignoreExtensionsVar);
+ std::vector<std::string> extensionList = cmExpandedList(ignoreExts);
+ for (std::string const& i : extensionList) {
+ this->IgnoreExtensions[i] = true;
+ }
+}
+
+void cmGlobalGenerator::FillExtensionToLanguageMap(const std::string& l,
+ cmMakefile* mf)
+{
+ std::string extensionsVar = std::string("CMAKE_") + std::string(l) +
+ std::string("_SOURCE_FILE_EXTENSIONS");
+ const std::string& exts = mf->GetSafeDefinition(extensionsVar);
+ std::vector<std::string> extensionList = cmExpandedList(exts);
+ for (std::string const& i : extensionList) {
+ this->ExtensionToLanguage[i] = l;
+ }
+}
+
+const char* cmGlobalGenerator::GetGlobalSetting(std::string const& name) const
+{
+ assert(!this->Makefiles.empty());
+ return cmToCStr(this->Makefiles[0]->GetDefinition(name));
+}
+
+bool cmGlobalGenerator::GlobalSettingIsOn(std::string const& name) const
+{
+ assert(!this->Makefiles.empty());
+ return this->Makefiles[0]->IsOn(name);
+}
+
+std::string cmGlobalGenerator::GetSafeGlobalSetting(
+ std::string const& name) const
+{
+ assert(!this->Makefiles.empty());
+ return this->Makefiles[0]->GetSafeDefinition(name);
+}
+
+bool cmGlobalGenerator::IgnoreFile(const char* ext) const
+{
+ if (!this->GetLanguageFromExtension(ext).empty()) {
+ return false;
+ }
+ return (this->IgnoreExtensions.count(ext) > 0);
+}
+
+bool cmGlobalGenerator::GetLanguageEnabled(const std::string& l) const
+{
+ return this->CMakeInstance->GetState()->GetLanguageEnabled(l);
+}
+
+void cmGlobalGenerator::ClearEnabledLanguages()
+{
+ this->CMakeInstance->GetState()->ClearEnabledLanguages();
+}
+
+void cmGlobalGenerator::CreateLocalGenerators()
+{
+ this->LocalGeneratorSearchIndex.clear();
+ this->LocalGenerators.clear();
+ this->LocalGenerators.reserve(this->Makefiles.size());
+ for (const auto& m : this->Makefiles) {
+ auto lg = this->CreateLocalGenerator(m.get());
+ this->IndexLocalGenerator(lg.get());
+ this->LocalGenerators.push_back(std::move(lg));
+ }
+}
+
+void cmGlobalGenerator::Configure()
+{
+ this->FirstTimeProgress = 0.0f;
+ this->ClearGeneratorMembers();
+ this->NextDeferId = 0;
+
+ cmStateSnapshot snapshot = this->CMakeInstance->GetCurrentSnapshot();
+
+ snapshot.GetDirectory().SetCurrentSource(
+ this->CMakeInstance->GetHomeDirectory());
+ snapshot.GetDirectory().SetCurrentBinary(
+ this->CMakeInstance->GetHomeOutputDirectory());
+
+ auto dirMfu = cm::make_unique<cmMakefile>(this, snapshot);
+ auto* dirMf = dirMfu.get();
+ this->Makefiles.push_back(std::move(dirMfu));
+ dirMf->SetRecursionDepth(this->RecursionDepth);
+ this->IndexMakefile(dirMf);
+
+ this->BinaryDirectories.insert(
+ this->CMakeInstance->GetHomeOutputDirectory());
+
+ // now do it
+ this->ConfigureDoneCMP0026AndCMP0024 = false;
+ dirMf->Configure();
+ dirMf->EnforceDirectoryLevelRules();
+
+ this->ConfigureDoneCMP0026AndCMP0024 = true;
+
+ // Put a copy of each global target in every directory.
+ {
+ std::vector<GlobalTargetInfo> globalTargets;
+ this->CreateDefaultGlobalTargets(globalTargets);
+
+ for (const auto& mf : this->Makefiles) {
+ auto& targets = mf->GetTargets();
+ for (GlobalTargetInfo const& globalTarget : globalTargets) {
+ targets.emplace(globalTarget.Name,
+ this->CreateGlobalTarget(globalTarget, mf.get()));
+ }
+ }
+ }
+
+ // update the cache entry for the number of local generators, this is used
+ // for progress
+ char num[100];
+ sprintf(num, "%d", static_cast<int>(this->Makefiles.size()));
+ this->GetCMakeInstance()->AddCacheEntry("CMAKE_NUMBER_OF_MAKEFILES", num,
+ "number of local generators",
+ cmStateEnums::INTERNAL);
+
+ if (this->CMakeInstance->GetWorkingMode() == cmake::NORMAL_MODE) {
+ std::ostringstream msg;
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ msg << "Configuring incomplete, errors occurred!";
+ const char* logs[] = { "CMakeOutput.log", "CMakeError.log", nullptr };
+ for (const char** log = logs; *log; ++log) {
+ std::string f = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
+ "/CMakeFiles/", *log);
+ if (cmSystemTools::FileExists(f)) {
+ msg << "\nSee also \"" << f << "\".";
+ }
+ }
+ } else {
+ msg << "Configuring done";
+ }
+ this->CMakeInstance->UpdateProgress(msg.str(), -1);
+ }
+}
+
+void cmGlobalGenerator::CreateGenerationObjects(TargetTypes targetTypes)
+{
+ this->CreateLocalGenerators();
+ // Commit side effects only if we are actually generating
+ if (this->GetConfigureDoneCMP0026()) {
+ this->CheckTargetProperties();
+ }
+ this->CreateGeneratorTargets(targetTypes);
+ this->ComputeBuildFileGenerators();
+}
+
+void cmGlobalGenerator::CreateImportedGenerationObjects(
+ cmMakefile* mf, const std::vector<std::string>& targets,
+ std::vector<const cmGeneratorTarget*>& exports)
+{
+ this->CreateGenerationObjects(ImportedOnly);
+ auto const mfit =
+ std::find_if(this->Makefiles.begin(), this->Makefiles.end(),
+ [mf](const std::unique_ptr<cmMakefile>& item) {
+ return item.get() == mf;
+ });
+ auto& lg =
+ this->LocalGenerators[std::distance(this->Makefiles.begin(), mfit)];
+ for (std::string const& t : targets) {
+ cmGeneratorTarget* gt = lg->FindGeneratorTargetToUse(t);
+ if (gt) {
+ exports.push_back(gt);
+ }
+ }
+}
+
+cmExportBuildFileGenerator* cmGlobalGenerator::GetExportedTargetsFile(
+ const std::string& filename) const
+{
+ auto const it = this->BuildExportSets.find(filename);
+ return it == this->BuildExportSets.end() ? nullptr : it->second;
+}
+
+void cmGlobalGenerator::AddCMP0042WarnTarget(const std::string& target)
+{
+ this->CMP0042WarnTargets.insert(target);
+}
+
+void cmGlobalGenerator::AddCMP0068WarnTarget(const std::string& target)
+{
+ this->CMP0068WarnTargets.insert(target);
+}
+
+bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const
+{
+ // If the property is not enabled then okay.
+ if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
+ "ALLOW_DUPLICATE_CUSTOM_TARGETS")) {
+ return true;
+ }
+
+ // This generator does not support duplicate custom targets.
+ std::ostringstream e;
+ e << "This project has enabled the ALLOW_DUPLICATE_CUSTOM_TARGETS "
+ << "global property. "
+ << "The \"" << this->GetName() << "\" generator does not support "
+ << "duplicate custom targets. "
+ << "Consider using a Makefiles generator or fix the project to not "
+ << "use duplicate target names.";
+ cmSystemTools::Error(e.str());
+ return false;
+}
+
+void cmGlobalGenerator::ComputeBuildFileGenerators()
+{
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const& gens =
+ this->Makefiles[i]->GetExportBuildFileGenerators();
+ for (std::unique_ptr<cmExportBuildFileGenerator> const& g : gens) {
+ g->Compute(this->LocalGenerators[i].get());
+ }
+ }
+}
+
+bool cmGlobalGenerator::UnsupportedVariableIsDefined(const std::string& name,
+ bool supported) const
+{
+ if (!supported && this->Makefiles.front()->GetDefinition(name)) {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "does not support variable\n"
+ " " << name << "\n"
+ "but it has been specified."
+ ;
+ /* clang-format on */
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return true;
+ }
+
+ return false;
+}
+
+bool cmGlobalGenerator::Compute()
+{
+ // Make sure unsupported variables are not used.
+ if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_BUILD_TYPE",
+ this->SupportsDefaultBuildType())) {
+ return false;
+ }
+ if (this->UnsupportedVariableIsDefined("CMAKE_CROSS_CONFIGS",
+ this->SupportsCrossConfigs())) {
+ return false;
+ }
+ if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_CONFIGS",
+ this->SupportsDefaultConfigs())) {
+ return false;
+ }
+
+ // Some generators track files replaced during the Generate.
+ // Start with an empty vector:
+ this->FilesReplacedDuringGenerate.clear();
+
+ // clear targets to issue warning CMP0042 for
+ this->CMP0042WarnTargets.clear();
+ // clear targets to issue warning CMP0068 for
+ this->CMP0068WarnTargets.clear();
+
+ // Check whether this generator is allowed to run.
+ if (!this->CheckALLOW_DUPLICATE_CUSTOM_TARGETS()) {
+ return false;
+ }
+ this->FinalizeTargetCompileInfo();
+
+ this->CreateGenerationObjects();
+
+ // at this point this->LocalGenerators has been filled,
+ // so create the map from project name to vector of local generators
+ this->FillProjectMap();
+
+ // Add automatically generated sources (e.g. unity build).
+ if (!this->AddAutomaticSources()) {
+ return false;
+ }
+
+ // Iterate through all targets and set up AUTOMOC, AUTOUIC and AUTORCC
+ if (!this->QtAutoGen()) {
+ return false;
+ }
+
+ // Add generator specific helper commands
+ for (const auto& localGen : this->LocalGenerators) {
+ localGen->AddHelperCommands();
+ }
+
+ // Perform up-front computation in order to handle errors (such as unknown
+ // features) at this point. While processing the compile features we also
+ // calculate and cache the language standard required by the compile
+ // features.
+ for (const auto& localGen : this->LocalGenerators) {
+ if (!localGen->ComputeTargetCompileFeatures()) {
+ return false;
+ }
+ }
+
+ for (const auto& localGen : this->LocalGenerators) {
+ cmMakefile* mf = localGen->GetMakefile();
+ for (const auto& g : mf->GetInstallGenerators()) {
+ if (!g->Compute(localGen.get())) {
+ return false;
+ }
+ }
+ }
+
+ this->AddExtraIDETargets();
+
+ // Trace the dependencies, after that no custom commands should be added
+ // because their dependencies might not be handled correctly
+ for (const auto& localGen : this->LocalGenerators) {
+ localGen->TraceDependencies();
+ }
+
+ // Make sure that all (non-imported) targets have source files added!
+ if (this->CheckTargetsForMissingSources()) {
+ return false;
+ }
+
+ this->ForceLinkerLanguages();
+
+ // Compute the manifest of main targets generated.
+ for (const auto& localGen : this->LocalGenerators) {
+ localGen->ComputeTargetManifest();
+ }
+
+ // Compute the inter-target dependencies.
+ if (!this->ComputeTargetDepends()) {
+ return false;
+ }
+ this->ComputeTargetOrder();
+
+ if (this->CheckTargetsForType()) {
+ return false;
+ }
+
+ if (this->CheckTargetsForPchCompilePdb()) {
+ return false;
+ }
+
+ for (const auto& localGen : this->LocalGenerators) {
+ localGen->ComputeHomeRelativeOutputPath();
+ }
+
+ return true;
+}
+
+void cmGlobalGenerator::Generate()
+{
+ // Create a map from local generator to the complete set of targets
+ // it builds by default.
+ this->InitializeProgressMarks();
+
+ this->ProcessEvaluationFiles();
+
+ this->CMakeInstance->UpdateProgress("Generating", 0.1f);
+
+ // Generate project files
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ this->SetCurrentMakefile(this->LocalGenerators[i]->GetMakefile());
+ this->LocalGenerators[i]->Generate();
+ if (!this->LocalGenerators[i]->GetMakefile()->IsOn(
+ "CMAKE_SKIP_INSTALL_RULES")) {
+ this->LocalGenerators[i]->GenerateInstallRules();
+ }
+ this->LocalGenerators[i]->GenerateTestFiles();
+ this->CMakeInstance->UpdateProgress(
+ "Generating",
+ 0.1f +
+ 0.9f * (static_cast<float>(i) + 1.0f) /
+ static_cast<float>(this->LocalGenerators.size()));
+ }
+ this->SetCurrentMakefile(nullptr);
+
+ if (!this->GenerateCPackPropertiesFile()) {
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR, "Could not write CPack properties file.");
+ }
+
+ for (auto& buildExpSet : this->BuildExportSets) {
+ if (!buildExpSet.second->GenerateImportFile()) {
+ if (!cmSystemTools::GetErrorOccuredFlag()) {
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+ "Could not write export file.");
+ }
+ return;
+ }
+ }
+ // Update rule hashes.
+ this->CheckRuleHashes();
+
+ this->WriteSummary();
+
+ if (this->ExtraGenerator) {
+ this->ExtraGenerator->Generate();
+ }
+
+ if (!this->CMP0042WarnTargets.empty()) {
+ std::ostringstream w;
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0042) << "\n";
+ w << "MACOSX_RPATH is not specified for"
+ " the following targets:\n";
+ for (std::string const& t : this->CMP0042WarnTargets) {
+ w << " " << t << "\n";
+ }
+ this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
+ w.str());
+ }
+
+ if (!this->CMP0068WarnTargets.empty()) {
+ std::ostringstream w;
+ /* clang-format off */
+ w <<
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0068) << "\n"
+ "For compatibility with older versions of CMake, the install_name "
+ "fields for the following targets are still affected by RPATH "
+ "settings:\n"
+ ;
+ /* clang-format on */
+ for (std::string const& t : this->CMP0068WarnTargets) {
+ w << " " << t << "\n";
+ }
+ this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
+ w.str());
+ }
+
+ this->CMakeInstance->UpdateProgress("Generating done", -1);
+}
+
+bool cmGlobalGenerator::ComputeTargetDepends()
+{
+ cmComputeTargetDepends ctd(this);
+ if (!ctd.Compute()) {
+ return false;
+ }
+ for (cmGeneratorTarget const* target : ctd.GetTargets()) {
+ ctd.GetTargetDirectDepends(target, this->TargetDependencies[target]);
+ }
+ return true;
+}
+
+std::vector<cmGeneratorTarget*>
+cmGlobalGenerator::GetLocalGeneratorTargetsInOrder(cmLocalGenerator* lg) const
+{
+ std::vector<cmGeneratorTarget*> gts;
+ cm::append(gts, lg->GetGeneratorTargets());
+ std::sort(gts.begin(), gts.end(),
+ [this](cmGeneratorTarget const* l, cmGeneratorTarget const* r) {
+ return this->TargetOrderIndex.at(l) <
+ this->TargetOrderIndex.at(r);
+ });
+ return gts;
+}
+
+void cmGlobalGenerator::ComputeTargetOrder()
+{
+ size_t index = 0;
+ auto const& lgens = this->GetLocalGenerators();
+ for (auto const& lgen : lgens) {
+ const auto& targets = lgen->GetGeneratorTargets();
+ for (const auto& gt : targets) {
+ this->ComputeTargetOrder(gt.get(), index);
+ }
+ }
+ assert(index == this->TargetOrderIndex.size());
+}
+
+void cmGlobalGenerator::ComputeTargetOrder(cmGeneratorTarget const* gt,
+ size_t& index)
+{
+ std::map<cmGeneratorTarget const*, size_t>::value_type value(gt, 0);
+ auto insertion = this->TargetOrderIndex.insert(value);
+ if (!insertion.second) {
+ return;
+ }
+ auto entry = insertion.first;
+
+ const auto& deps = this->GetTargetDirectDepends(gt);
+ for (const auto& d : deps) {
+ this->ComputeTargetOrder(d, index);
+ }
+
+ entry->second = index++;
+}
+
+bool cmGlobalGenerator::QtAutoGen()
+{
+#ifndef CMAKE_BOOTSTRAP
+ cmQtAutoGenGlobalInitializer initializer(this->LocalGenerators);
+ return initializer.generate();
+#else
+ return true;
+#endif
+}
+
+bool cmGlobalGenerator::AddAutomaticSources()
+{
+ for (const auto& lg : this->LocalGenerators) {
+ lg->CreateEvaluationFileOutputs();
+ }
+ for (const auto& lg : this->LocalGenerators) {
+ for (const auto& gt : lg->GetGeneratorTargets()) {
+ if (!gt->CanCompileSources()) {
+ continue;
+ }
+ lg->AddUnityBuild(gt.get());
+ lg->AddISPCDependencies(gt.get());
+ // Targets that re-use a PCH are handled below.
+ if (!gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
+ lg->AddPchDependencies(gt.get());
+ }
+ }
+ }
+ for (const auto& lg : this->LocalGenerators) {
+ for (const auto& gt : lg->GetGeneratorTargets()) {
+ if (!gt->CanCompileSources()) {
+ continue;
+ }
+ // Handle targets that re-use a PCH from an above-handled target.
+ if (gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
+ lg->AddPchDependencies(gt.get());
+ }
+ }
+ }
+ // The above transformations may have changed the classification of sources.
+ // Clear the source list and classification cache (KindedSources) of all
+ // targets so that it will be recomputed correctly by the generators later
+ // now that the above transformations are done for all targets.
+ for (const auto& lg : this->LocalGenerators) {
+ for (const auto& gt : lg->GetGeneratorTargets()) {
+ gt->ClearSourcesCache();
+ }
+ }
+ return true;
+}
+
+std::unique_ptr<cmLinkLineComputer> cmGlobalGenerator::CreateLinkLineComputer(
+ cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const
+{
+ return cm::make_unique<cmLinkLineComputer>(outputConverter, stateDir);
+}
+
+std::unique_ptr<cmLinkLineComputer>
+cmGlobalGenerator::CreateMSVC60LinkLineComputer(
+ cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const
+{
+ return std::unique_ptr<cmLinkLineComputer>(
+ cm::make_unique<cmMSVC60LinkLineComputer>(outputConverter, stateDir));
+}
+
+void cmGlobalGenerator::FinalizeTargetCompileInfo()
+{
+ std::vector<std::string> const langs =
+ this->CMakeInstance->GetState()->GetEnabledLanguages();
+
+ // Construct per-target generator information.
+ for (const auto& mf : this->Makefiles) {
+ const cmStringRange noconfig_compile_definitions =
+ mf->GetCompileDefinitionsEntries();
+ const cmBacktraceRange noconfig_compile_definitions_bts =
+ mf->GetCompileDefinitionsBacktraces();
+
+ for (auto& target : mf->GetTargets()) {
+ cmTarget* t = &target.second;
+ if (t->GetType() == cmStateEnums::GLOBAL_TARGET) {
+ continue;
+ }
+
+ t->AppendBuildInterfaceIncludes();
+
+ if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ continue;
+ }
+
+ {
+ auto btIt = noconfig_compile_definitions_bts.begin();
+ auto it = noconfig_compile_definitions.begin();
+ for (; it != noconfig_compile_definitions.end(); ++it, ++btIt) {
+ t->InsertCompileDefinition(*it, *btIt);
+ }
+ }
+
+ cmPolicies::PolicyStatus polSt =
+ mf->GetPolicyStatus(cmPolicies::CMP0043);
+ if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
+ std::vector<std::string> configs =
+ mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
+
+ for (std::string const& c : configs) {
+ std::string defPropName =
+ cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(c));
+ if (cmProp val = mf->GetProperty(defPropName)) {
+ t->AppendProperty(defPropName, *val);
+ }
+ }
+ }
+ }
+
+ // The standard include directories for each language
+ // should be treated as system include directories.
+ std::set<std::string> standardIncludesSet;
+ for (std::string const& li : langs) {
+ std::string const standardIncludesVar =
+ "CMAKE_" + li + "_STANDARD_INCLUDE_DIRECTORIES";
+ std::string const& standardIncludesStr =
+ mf->GetSafeDefinition(standardIncludesVar);
+ std::vector<std::string> standardIncludesVec =
+ cmExpandedList(standardIncludesStr);
+ standardIncludesSet.insert(standardIncludesVec.begin(),
+ standardIncludesVec.end());
+ }
+ mf->AddSystemIncludeDirectories(standardIncludesSet);
+ }
+}
+
+void cmGlobalGenerator::CreateGeneratorTargets(
+ TargetTypes targetTypes, cmMakefile* mf, cmLocalGenerator* lg,
+ std::map<cmTarget*, cmGeneratorTarget*> const& importedMap)
+{
+ if (targetTypes == AllTargets) {
+ for (auto& target : mf->GetTargets()) {
+ cmTarget* t = &target.second;
+ lg->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(t, lg));
+ }
+ }
+
+ for (cmTarget* t : mf->GetImportedTargets()) {
+ lg->AddImportedGeneratorTarget(importedMap.find(t)->second);
+ }
+}
+
+void cmGlobalGenerator::CreateGeneratorTargets(TargetTypes targetTypes)
+{
+ std::map<cmTarget*, cmGeneratorTarget*> importedMap;
+ for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
+ auto& mf = this->Makefiles[i];
+ for (const auto& ownedImpTgt : mf->GetOwnedImportedTargets()) {
+ cmLocalGenerator* lg = this->LocalGenerators[i].get();
+ auto gt = cm::make_unique<cmGeneratorTarget>(ownedImpTgt.get(), lg);
+ importedMap[ownedImpTgt.get()] = gt.get();
+ lg->AddOwnedImportedGeneratorTarget(std::move(gt));
+ }
+ }
+
+ // Construct per-target generator information.
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ this->CreateGeneratorTargets(targetTypes, this->Makefiles[i].get(),
+ this->LocalGenerators[i].get(), importedMap);
+ }
+}
+
+void cmGlobalGenerator::ClearGeneratorMembers()
+{
+ this->BuildExportSets.clear();
+
+ this->Makefiles.clear();
+
+ this->LocalGenerators.clear();
+
+ this->AliasTargets.clear();
+ this->ExportSets.clear();
+ this->InstallComponents.clear();
+ this->TargetDependencies.clear();
+ this->TargetSearchIndex.clear();
+ this->GeneratorTargetSearchIndex.clear();
+ this->MakefileSearchIndex.clear();
+ this->LocalGeneratorSearchIndex.clear();
+ this->TargetOrderIndex.clear();
+ this->ProjectMap.clear();
+ this->RuleHashes.clear();
+ this->DirectoryContentMap.clear();
+ this->BinaryDirectories.clear();
+ this->GeneratedFiles.clear();
+}
+
+void cmGlobalGenerator::ComputeTargetObjectDirectory(
+ cmGeneratorTarget* /*unused*/) const
+{
+}
+
+void cmGlobalGenerator::CheckTargetProperties()
+{
+ // check for link libraries and include directories containing "NOTFOUND"
+ // and for infinite loops
+ std::map<std::string, std::string> notFoundMap;
+ cmState* state = this->GetCMakeInstance()->GetState();
+ for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
+ this->Makefiles[i]->Generate(*this->LocalGenerators[i]);
+ for (auto const& target : this->Makefiles[i]->GetTargets()) {
+ if (target.second.GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ continue;
+ }
+ for (auto const& lib : target.second.GetOriginalLinkLibraries()) {
+ if (lib.first.size() > 9 && cmIsNOTFOUND(lib.first)) {
+ std::string varName = lib.first.substr(0, lib.first.size() - 9);
+ if (state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) {
+ varName += " (ADVANCED)";
+ }
+ std::string text =
+ cmStrCat(notFoundMap[varName], "\n linked by target \"",
+ target.second.GetName(), "\" in directory ",
+ this->Makefiles[i]->GetCurrentSourceDirectory());
+ notFoundMap[varName] = text;
+ }
+ }
+ std::vector<std::string> incs;
+ cmProp incDirProp = target.second.GetProperty("INCLUDE_DIRECTORIES");
+ if (!incDirProp) {
+ continue;
+ }
+
+ std::string incDirs = cmGeneratorExpression::Preprocess(
+ *incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions);
+
+ cmExpandList(incDirs, incs);
+
+ for (std::string const& incDir : incs) {
+ if (incDir.size() > 9 && cmIsNOTFOUND(incDir)) {
+ std::string varName = incDir.substr(0, incDir.size() - 9);
+ if (state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) {
+ varName += " (ADVANCED)";
+ }
+ std::string text =
+ cmStrCat(notFoundMap[varName],
+ "\n used as include directory in directory ",
+ this->Makefiles[i]->GetCurrentSourceDirectory());
+ notFoundMap[varName] = text;
+ }
+ }
+ }
+ }
+
+ if (!notFoundMap.empty()) {
+ std::string notFoundVars;
+ for (auto const& notFound : notFoundMap) {
+ notFoundVars += notFound.first;
+ notFoundVars += notFound.second;
+ notFoundVars += "\n";
+ }
+ cmSystemTools::Error("The following variables are used in this project, "
+ "but they are set to NOTFOUND.\n"
+ "Please set them or make sure they are set and "
+ "tested correctly in the CMake files:\n" +
+ notFoundVars);
+ }
+}
+
+int cmGlobalGenerator::TryCompile(int jobs, const std::string& srcdir,
+ const std::string& bindir,
+ const std::string& projectName,
+ const std::string& target, bool fast,
+ std::string& output, cmMakefile* mf)
+{
+ // if this is not set, then this is a first time configure
+ // and there is a good chance that the try compile stuff will
+ // take the bulk of the time, so try and guess some progress
+ // by getting closer and closer to 100 without actually getting there.
+ if (!this->CMakeInstance->GetState()->GetInitializedCacheValue(
+ "CMAKE_NUMBER_OF_MAKEFILES")) {
+ // If CMAKE_NUMBER_OF_MAKEFILES is not set
+ // we are in the first time progress and we have no
+ // idea how long it will be. So, just move 1/10th of the way
+ // there each time, and don't go over 95%
+ this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) / 30.0f);
+ if (this->FirstTimeProgress > 0.95f) {
+ this->FirstTimeProgress = 0.95f;
+ }
+ this->CMakeInstance->UpdateProgress("Configuring",
+ this->FirstTimeProgress);
+ }
+
+ std::vector<std::string> newTarget = {};
+ if (!target.empty()) {
+ newTarget = { target };
+ }
+ std::string config =
+ mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
+ return this->Build(jobs, srcdir, bindir, projectName, newTarget, output, "",
+ config, false, fast, false, this->TryCompileTimeout);
+}
+
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalGenerator::GenerateBuildCommand(
+ const std::string& /*unused*/, const std::string& /*unused*/,
+ const std::string& /*unused*/, std::vector<std::string> const& /*unused*/,
+ const std::string& /*unused*/, bool /*unused*/, int /*unused*/,
+ bool /*unused*/, std::vector<std::string> const& /*unused*/)
+{
+ GeneratedMakeCommand makeCommand;
+ makeCommand.Add("cmGlobalGenerator::GenerateBuildCommand not implemented");
+ return { std::move(makeCommand) };
+}
+
+void cmGlobalGenerator::PrintBuildCommandAdvice(std::ostream& /*os*/,
+ int /*jobs*/) const
+{
+ // Subclasses override this method if they e.g want to give a warning that
+ // they do not support certain build command line options
+}
+
+int cmGlobalGenerator::Build(
+ int jobs, const std::string& /*unused*/, const std::string& bindir,
+ const std::string& projectName, const std::vector<std::string>& targets,
+ std::string& output, const std::string& makeCommandCSTR,
+ const std::string& config, bool clean, bool fast, bool verbose,
+ cmDuration timeout, cmSystemTools::OutputOption outputflag,
+ std::vector<std::string> const& nativeOptions)
+{
+ bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
+
+ /**
+ * Run an executable command and put the stdout in output.
+ */
+ cmWorkingDirectory workdir(bindir);
+ output += "Change Dir: ";
+ output += bindir;
+ output += "\n";
+ if (workdir.Failed()) {
+ cmSystemTools::SetRunCommandHideConsole(hideconsole);
+ std::string err = cmStrCat("Failed to change directory: ",
+ std::strerror(workdir.GetLastResult()));
+ cmSystemTools::Error(err);
+ output += err;
+ output += "\n";
+ return 1;
+ }
+ std::string realConfig = config;
+ if (realConfig.empty()) {
+ realConfig = this->GetDefaultBuildConfig();
+ }
+
+ int retVal = 0;
+ cmSystemTools::SetRunCommandHideConsole(true);
+ std::string outputBuffer;
+ std::string* outputPtr = &outputBuffer;
+
+ std::vector<GeneratedMakeCommand> makeCommand =
+ this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, targets,
+ realConfig, fast, jobs, verbose, nativeOptions);
+
+ // Workaround to convince some commands to produce output.
+ if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH &&
+ makeCommand.back().RequiresOutputForward) {
+ outputflag = cmSystemTools::OUTPUT_FORWARD;
+ }
+
+ // should we do a clean first?
+ if (clean) {
+ std::vector<GeneratedMakeCommand> cleanCommand =
+ this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir,
+ { "clean" }, realConfig, fast, jobs, verbose);
+ output += "\nRun Clean Command:";
+ output += cleanCommand.front().Printable();
+ output += "\n";
+ if (cleanCommand.size() != 1) {
+ this->GetCMakeInstance()->IssueMessage(MessageType::INTERNAL_ERROR,
+ "The generator did not produce "
+ "exactly one command for the "
+ "'clean' target");
+ return 1;
+ }
+ if (!cmSystemTools::RunSingleCommand(cleanCommand.front().PrimaryCommand,
+ outputPtr, outputPtr, &retVal,
+ nullptr, outputflag, timeout)) {
+ cmSystemTools::SetRunCommandHideConsole(hideconsole);
+ cmSystemTools::Error("Generator: execution of make clean failed.");
+ output += *outputPtr;
+ output += "\nGenerator: execution of make clean failed.\n";
+
+ return 1;
+ }
+ output += *outputPtr;
+ }
+
+ // now build
+ std::string makeCommandStr;
+ output += "\nRun Build Command(s):";
+
+ retVal = 0;
+ for (auto command = makeCommand.begin();
+ command != makeCommand.end() && retVal == 0; ++command) {
+ makeCommandStr = command->Printable();
+ if (command != makeCommand.end()) {
+ makeCommandStr += " && ";
+ }
+
+ output += makeCommandStr;
+ if (!cmSystemTools::RunSingleCommand(command->PrimaryCommand, outputPtr,
+ outputPtr, &retVal, nullptr,
+ outputflag, timeout)) {
+ cmSystemTools::SetRunCommandHideConsole(hideconsole);
+ cmSystemTools::Error(
+ "Generator: execution of make failed. Make command was: " +
+ makeCommandStr);
+ output += *outputPtr;
+ output += "\nGenerator: execution of make failed. Make command was: " +
+ makeCommandStr + "\n";
+
+ return 1;
+ }
+ output += *outputPtr;
+ }
+ output += "\n";
+ cmSystemTools::SetRunCommandHideConsole(hideconsole);
+
+ // The OpenWatcom tools do not return an error code when a link
+ // library is not found!
+ if (this->CMakeInstance->GetState()->UseWatcomWMake() && retVal == 0 &&
+ output.find("W1008: cannot open") != std::string::npos) {
+ retVal = 1;
+ }
+
+ return retVal;
+}
+
+bool cmGlobalGenerator::Open(const std::string& bindir,
+ const std::string& projectName, bool dryRun)
+{
+ if (this->ExtraGenerator) {
+ return this->ExtraGenerator->Open(bindir, projectName, dryRun);
+ }
+
+ return false;
+}
+
+std::string cmGlobalGenerator::GenerateCMakeBuildCommand(
+ const std::string& target, const std::string& config,
+ const std::string& native, bool ignoreErrors)
+{
+ std::string makeCommand = cmSystemTools::GetCMakeCommand();
+ makeCommand =
+ cmStrCat(cmSystemTools::ConvertToOutputPath(makeCommand), " --build .");
+ if (!config.empty()) {
+ makeCommand += " --config \"";
+ makeCommand += config;
+ makeCommand += "\"";
+ }
+ if (!target.empty()) {
+ makeCommand += " --target \"";
+ makeCommand += target;
+ makeCommand += "\"";
+ }
+ const char* sep = " -- ";
+ if (ignoreErrors) {
+ const char* iflag = this->GetBuildIgnoreErrorsFlag();
+ if (iflag && *iflag) {
+ makeCommand += sep;
+ makeCommand += iflag;
+ sep = " ";
+ }
+ }
+ if (!native.empty()) {
+ makeCommand += sep;
+ makeCommand += native;
+ }
+ return makeCommand;
+}
+
+void cmGlobalGenerator::AddMakefile(std::unique_ptr<cmMakefile> mf)
+{
+ this->IndexMakefile(mf.get());
+ this->Makefiles.push_back(std::move(mf));
+
+ // update progress
+ // estimate how many lg there will be
+ cmProp numGenC = this->CMakeInstance->GetState()->GetInitializedCacheValue(
+ "CMAKE_NUMBER_OF_MAKEFILES");
+
+ if (!numGenC) {
+ // If CMAKE_NUMBER_OF_MAKEFILES is not set
+ // we are in the first time progress and we have no
+ // idea how long it will be. So, just move half way
+ // there each time, and don't go over 95%
+ this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) / 30.0f);
+ if (this->FirstTimeProgress > 0.95f) {
+ this->FirstTimeProgress = 0.95f;
+ }
+ this->CMakeInstance->UpdateProgress("Configuring",
+ this->FirstTimeProgress);
+ return;
+ }
+
+ int numGen = atoi(numGenC->c_str());
+ float prog =
+ static_cast<float>(this->Makefiles.size()) / static_cast<float>(numGen);
+ if (prog > 1.0f) {
+ prog = 1.0f;
+ }
+ this->CMakeInstance->UpdateProgress("Configuring", prog);
+}
+
+void cmGlobalGenerator::AddInstallComponent(const std::string& component)
+{
+ if (!component.empty()) {
+ this->InstallComponents.insert(component);
+ }
+}
+
+void cmGlobalGenerator::MarkAsGeneratedFile(const std::string& filepath)
+{
+ this->GeneratedFiles.insert(filepath);
+}
+
+bool cmGlobalGenerator::IsGeneratedFile(const std::string& filepath)
+{
+ return this->GeneratedFiles.find(filepath) != this->GeneratedFiles.end();
+}
+
+void cmGlobalGenerator::EnableInstallTarget()
+{
+ this->InstallTargetEnabled = true;
+}
+
+std::unique_ptr<cmLocalGenerator> cmGlobalGenerator::CreateLocalGenerator(
+ cmMakefile* mf)
+{
+ return cm::make_unique<cmLocalGenerator>(this, mf);
+}
+
+void cmGlobalGenerator::EnableLanguagesFromGenerator(cmGlobalGenerator* gen,
+ cmMakefile* mf)
+{
+ this->SetConfiguredFilesPath(gen);
+ this->TryCompileOuterMakefile = mf;
+ cmProp make =
+ gen->GetCMakeInstance()->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
+ this->GetCMakeInstance()->AddCacheEntry("CMAKE_MAKE_PROGRAM", cmToCStr(make),
+ "make program",
+ cmStateEnums::FILEPATH);
+ // copy the enabled languages
+ this->GetCMakeInstance()->GetState()->SetEnabledLanguages(
+ gen->GetCMakeInstance()->GetState()->GetEnabledLanguages());
+ this->LanguagesReady = gen->LanguagesReady;
+ this->ExtensionToLanguage = gen->ExtensionToLanguage;
+ this->IgnoreExtensions = gen->IgnoreExtensions;
+ this->LanguageToOutputExtension = gen->LanguageToOutputExtension;
+ this->LanguageToLinkerPreference = gen->LanguageToLinkerPreference;
+ this->OutputExtensions = gen->OutputExtensions;
+}
+
+void cmGlobalGenerator::SetConfiguredFilesPath(cmGlobalGenerator* gen)
+{
+ if (!gen->ConfiguredFilesPath.empty()) {
+ this->ConfiguredFilesPath = gen->ConfiguredFilesPath;
+ } else {
+ this->ConfiguredFilesPath =
+ cmStrCat(gen->CMakeInstance->GetHomeOutputDirectory(), "/CMakeFiles");
+ }
+}
+
+bool cmGlobalGenerator::IsExcluded(cmStateSnapshot const& rootSnp,
+ cmStateSnapshot const& snp_) const
+{
+ cmStateSnapshot snp = snp_;
+ while (snp.IsValid()) {
+ if (snp == rootSnp) {
+ // No directory excludes itself.
+ return false;
+ }
+
+ if (snp.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+ // This directory is excluded from its parent.
+ return true;
+ }
+ snp = snp.GetBuildsystemDirectoryParent();
+ }
+ return false;
+}
+
+bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
+ cmLocalGenerator* gen) const
+{
+ assert(gen);
+
+ cmStateSnapshot rootSnp = root->GetStateSnapshot();
+ cmStateSnapshot snp = gen->GetStateSnapshot();
+
+ return this->IsExcluded(rootSnp, snp);
+}
+
+bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
+ const cmGeneratorTarget* target) const
+{
+ if (!target->IsInBuildSystem()) {
+ return true;
+ }
+ cmMakefile* mf = root->GetMakefile();
+ const std::string EXCLUDE_FROM_ALL = "EXCLUDE_FROM_ALL";
+ if (cmProp exclude = target->GetProperty(EXCLUDE_FROM_ALL)) {
+ // Expand the property value per configuration.
+ unsigned int trueCount = 0;
+ unsigned int falseCount = 0;
+ const std::vector<std::string>& configs =
+ mf->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ for (const std::string& config : configs) {
+ cmGeneratorExpressionInterpreter genexInterpreter(root, config, target);
+ if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) {
+ ++trueCount;
+ } else {
+ ++falseCount;
+ }
+ }
+
+ // Check whether the genex expansion of the property agrees in all
+ // configurations.
+ if (trueCount && falseCount) {
+ std::ostringstream e;
+ e << "The EXCLUDE_FROM_ALL property of target \"" << target->GetName()
+ << "\" varies by configuration. This is not supported by the \""
+ << root->GetGlobalGenerator()->GetName() << "\" generator.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ }
+ return trueCount;
+ }
+ // This target is included in its directory. Check whether the
+ // directory is excluded.
+ return this->IsExcluded(root, target->GetLocalGenerator());
+}
+
+void cmGlobalGenerator::GetEnabledLanguages(
+ std::vector<std::string>& lang) const
+{
+ lang = this->CMakeInstance->GetState()->GetEnabledLanguages();
+}
+
+int cmGlobalGenerator::GetLinkerPreference(const std::string& lang) const
+{
+ auto const it = this->LanguageToLinkerPreference.find(lang);
+ if (it != this->LanguageToLinkerPreference.end()) {
+ return it->second;
+ }
+ return 0;
+}
+
+void cmGlobalGenerator::FillProjectMap()
+{
+ this->ProjectMap.clear(); // make sure we start with a clean map
+ for (const auto& localGen : this->LocalGenerators) {
+ // for each local generator add all projects
+ cmStateSnapshot snp = localGen->GetStateSnapshot();
+ std::string name;
+ do {
+ std::string snpProjName = snp.GetProjectName();
+ if (name != snpProjName) {
+ name = snpProjName;
+ this->ProjectMap[name].push_back(localGen.get());
+ }
+ snp = snp.GetBuildsystemDirectoryParent();
+ } while (snp.IsValid());
+ }
+}
+
+cmMakefile* cmGlobalGenerator::FindMakefile(const std::string& start_dir) const
+{
+ auto const it = this->MakefileSearchIndex.find(start_dir);
+ if (it != this->MakefileSearchIndex.end()) {
+ return it->second;
+ }
+ return nullptr;
+}
+
+cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(
+ cmDirectoryId const& id) const
+{
+ auto const it = this->LocalGeneratorSearchIndex.find(id.String);
+ if (it != this->LocalGeneratorSearchIndex.end()) {
+ return it->second;
+ }
+ return nullptr;
+}
+
+void cmGlobalGenerator::AddAlias(const std::string& name,
+ std::string const& tgtName)
+{
+ this->AliasTargets[name] = tgtName;
+}
+
+bool cmGlobalGenerator::IsAlias(const std::string& name) const
+{
+ return cm::contains(this->AliasTargets, name);
+}
+
+void cmGlobalGenerator::IndexTarget(cmTarget* t)
+{
+ if (!t->IsImported() || t->IsImportedGloballyVisible()) {
+ this->TargetSearchIndex[t->GetName()] = t;
+ }
+}
+
+void cmGlobalGenerator::IndexGeneratorTarget(cmGeneratorTarget* gt)
+{
+ if (!gt->IsImported() || gt->IsImportedGloballyVisible()) {
+ this->GeneratorTargetSearchIndex[gt->GetName()] = gt;
+ }
+}
+
+static char const hexDigits[] = "0123456789abcdef";
+
+std::string cmGlobalGenerator::IndexGeneratorTargetUniquely(
+ cmGeneratorTarget const* gt)
+{
+ // Use the pointer value to uniquely identify the target instance.
+ // Use a ":" prefix to avoid conflict with project-defined targets.
+ // We must satisfy cmGeneratorExpression::IsValidTargetName so use no
+ // other special characters.
+ constexpr size_t sizeof_ptr =
+ sizeof(gt); // NOLINT(bugprone-sizeof-expression)
+ char buf[1 + sizeof_ptr * 2];
+ char* b = buf;
+ *b++ = ':';
+ for (size_t i = 0; i < sizeof_ptr; ++i) {
+ unsigned char const c = reinterpret_cast<unsigned char const*>(&gt)[i];
+ *b++ = hexDigits[(c & 0xf0) >> 4];
+ *b++ = hexDigits[(c & 0x0f)];
+ }
+ std::string id(buf, sizeof(buf));
+ // We internally index pointers to non-const generator targets
+ // but our callers only have pointers to const generator targets.
+ // They will give up non-const privileges when looking up anyway.
+ this->GeneratorTargetSearchIndex[id] = const_cast<cmGeneratorTarget*>(gt);
+ return id;
+}
+
+void cmGlobalGenerator::IndexMakefile(cmMakefile* mf)
+{
+ // We index by both source and binary directory. add_subdirectory
+ // supports multiple build directories sharing the same source directory.
+ // The source directory index will reference only the first time it is used.
+ this->MakefileSearchIndex.insert(
+ MakefileMap::value_type(mf->GetCurrentSourceDirectory(), mf));
+ this->MakefileSearchIndex.insert(
+ MakefileMap::value_type(mf->GetCurrentBinaryDirectory(), mf));
+}
+
+void cmGlobalGenerator::IndexLocalGenerator(cmLocalGenerator* lg)
+{
+ cmDirectoryId id = lg->GetMakefile()->GetDirectoryId();
+ this->LocalGeneratorSearchIndex[id.String] = lg;
+}
+
+cmTarget* cmGlobalGenerator::FindTargetImpl(std::string const& name) const
+{
+ auto const it = this->TargetSearchIndex.find(name);
+ if (it != this->TargetSearchIndex.end()) {
+ return it->second;
+ }
+ return nullptr;
+}
+
+cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTargetImpl(
+ std::string const& name) const
+{
+ auto const it = this->GeneratorTargetSearchIndex.find(name);
+ if (it != this->GeneratorTargetSearchIndex.end()) {
+ return it->second;
+ }
+ return nullptr;
+}
+
+cmTarget* cmGlobalGenerator::FindTarget(const std::string& name,
+ bool excludeAliases) const
+{
+ if (!excludeAliases) {
+ auto const ai = this->AliasTargets.find(name);
+ if (ai != this->AliasTargets.end()) {
+ return this->FindTargetImpl(ai->second);
+ }
+ }
+ return this->FindTargetImpl(name);
+}
+
+cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTarget(
+ const std::string& name) const
+{
+ auto const ai = this->AliasTargets.find(name);
+ if (ai != this->AliasTargets.end()) {
+ return this->FindGeneratorTargetImpl(ai->second);
+ }
+ return this->FindGeneratorTargetImpl(name);
+}
+
+bool cmGlobalGenerator::NameResolvesToFramework(
+ const std::string& libname) const
+{
+ if (cmSystemTools::IsPathToFramework(libname)) {
+ return true;
+ }
+
+ if (cmTarget* tgt = this->FindTarget(libname)) {
+ if (tgt->IsFrameworkOnApple()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool cmGlobalGenerator::CheckCMP0037(std::string const& targetName,
+ std::string const& reason) const
+{
+ cmTarget* tgt = this->FindTarget(targetName);
+ if (!tgt) {
+ return true;
+ }
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+ std::ostringstream e;
+ bool issueMessage = false;
+ switch (tgt->GetPolicyStatusCMP0037()) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n";
+ issueMessage = true;
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ issueMessage = true;
+ messageType = MessageType::FATAL_ERROR;
+ break;
+ }
+ if (issueMessage) {
+ e << "The target name \"" << targetName << "\" is reserved " << reason
+ << ".";
+ if (messageType == MessageType::AUTHOR_WARNING) {
+ e << " It may result in undefined behavior.";
+ }
+ this->GetCMakeInstance()->IssueMessage(messageType, e.str(),
+ tgt->GetBacktrace());
+ if (messageType == MessageType::FATAL_ERROR) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void cmGlobalGenerator::CreateDefaultGlobalTargets(
+ std::vector<GlobalTargetInfo>& targets)
+{
+ this->AddGlobalTarget_Package(targets);
+ this->AddGlobalTarget_PackageSource(targets);
+ this->AddGlobalTarget_Test(targets);
+ this->AddGlobalTarget_EditCache(targets);
+ this->AddGlobalTarget_RebuildCache(targets);
+ this->AddGlobalTarget_Install(targets);
+}
+
+void cmGlobalGenerator::AddGlobalTarget_Package(
+ std::vector<GlobalTargetInfo>& targets)
+{
+ auto& mf = this->Makefiles[0];
+ std::string configFile =
+ cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackConfig.cmake");
+ if (!cmSystemTools::FileExists(configFile)) {
+ return;
+ }
+
+ static const auto reservedTargets = { "package", "PACKAGE" };
+ for (auto const& target : reservedTargets) {
+ if (!this->CheckCMP0037(target, "when CPack packaging is enabled")) {
+ return;
+ }
+ }
+
+ const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
+ GlobalTargetInfo gti;
+ gti.Name = this->GetPackageTargetName();
+ gti.Message = "Run CPack packaging tool...";
+ gti.UsesTerminal = true;
+ gti.WorkingDir = mf->GetCurrentBinaryDirectory();
+ cmCustomCommandLine singleLine;
+ singleLine.push_back(cmSystemTools::GetCPackCommand());
+ if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
+ singleLine.push_back("-C");
+ singleLine.push_back(cmakeCfgIntDir);
+ }
+ singleLine.push_back("--config");
+ singleLine.push_back("./CPackConfig.cmake");
+ gti.CommandLines.push_back(std::move(singleLine));
+ if (this->GetPreinstallTargetName()) {
+ gti.Depends.emplace_back(this->GetPreinstallTargetName());
+ } else {
+ cmProp noPackageAll =
+ mf->GetDefinition("CMAKE_SKIP_PACKAGE_ALL_DEPENDENCY");
+ if (cmIsOff(noPackageAll)) {
+ gti.Depends.emplace_back(this->GetAllTargetName());
+ }
+ }
+ targets.push_back(std::move(gti));
+}
+
+void cmGlobalGenerator::AddGlobalTarget_PackageSource(
+ std::vector<GlobalTargetInfo>& targets)
+{
+ const char* packageSourceTargetName = this->GetPackageSourceTargetName();
+ if (!packageSourceTargetName) {
+ return;
+ }
+
+ auto& mf = this->Makefiles[0];
+ std::string configFile =
+ cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackSourceConfig.cmake");
+ if (!cmSystemTools::FileExists(configFile)) {
+ return;
+ }
+
+ static const auto reservedTargets = { "package_source" };
+ for (auto const& target : reservedTargets) {
+ if (!this->CheckCMP0037(target,
+ "when CPack source packaging is enabled")) {
+ return;
+ }
+ }
+
+ GlobalTargetInfo gti;
+ gti.Name = packageSourceTargetName;
+ gti.Message = "Run CPack packaging tool for source...";
+ gti.WorkingDir = mf->GetCurrentBinaryDirectory();
+ gti.UsesTerminal = true;
+ cmCustomCommandLine singleLine;
+ singleLine.push_back(cmSystemTools::GetCPackCommand());
+ singleLine.push_back("--config");
+ singleLine.push_back("./CPackSourceConfig.cmake");
+ singleLine.push_back(std::move(configFile));
+ gti.CommandLines.push_back(std::move(singleLine));
+ targets.push_back(std::move(gti));
+}
+
+void cmGlobalGenerator::AddGlobalTarget_Test(
+ std::vector<GlobalTargetInfo>& targets)
+{
+ auto& mf = this->Makefiles[0];
+ if (!mf->IsOn("CMAKE_TESTING_ENABLED")) {
+ return;
+ }
+
+ static const auto reservedTargets = { "test", "RUN_TESTS" };
+ for (auto const& target : reservedTargets) {
+ if (!this->CheckCMP0037(target, "when CTest testing is enabled")) {
+ return;
+ }
+ }
+
+ const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
+ GlobalTargetInfo gti;
+ gti.Name = this->GetTestTargetName();
+ gti.Message = "Running tests...";
+ gti.UsesTerminal = true;
+ cmCustomCommandLine singleLine;
+ singleLine.push_back(cmSystemTools::GetCTestCommand());
+ singleLine.push_back("--force-new-ctest-process");
+ std::vector<std::string> args;
+ if (mf->GetDefExpandList("CMAKE_CTEST_ARGUMENTS", args)) {
+ for (auto const& arg : args) {
+ singleLine.push_back(arg);
+ }
+ }
+ if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
+ singleLine.push_back("-C");
+ singleLine.push_back(cmakeCfgIntDir);
+ } else // TODO: This is a hack. Should be something to do with the
+ // generator
+ {
+ singleLine.push_back("$(ARGS)");
+ }
+ gti.CommandLines.push_back(std::move(singleLine));
+ targets.push_back(std::move(gti));
+}
+
+void cmGlobalGenerator::AddGlobalTarget_EditCache(
+ std::vector<GlobalTargetInfo>& targets) const
+{
+ const char* editCacheTargetName = this->GetEditCacheTargetName();
+ if (!editCacheTargetName) {
+ return;
+ }
+ GlobalTargetInfo gti;
+ gti.Name = editCacheTargetName;
+ gti.PerConfig = cmTarget::PerConfig::No;
+ cmCustomCommandLine singleLine;
+
+ // Use generator preference for the edit_cache rule if it is defined.
+ std::string edit_cmd = this->GetEditCacheCommand();
+ if (!edit_cmd.empty()) {
+ singleLine.push_back(std::move(edit_cmd));
+ singleLine.push_back("-S$(CMAKE_SOURCE_DIR)");
+ singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
+ gti.Message = "Running CMake cache editor...";
+ gti.UsesTerminal = true;
+ } else {
+ singleLine.push_back(cmSystemTools::GetCMakeCommand());
+ singleLine.push_back("-E");
+ singleLine.push_back("echo");
+ singleLine.push_back("No interactive CMake dialog available.");
+ gti.Message = "No interactive CMake dialog available...";
+ gti.UsesTerminal = false;
+ gti.StdPipesUTF8 = true;
+ }
+ gti.CommandLines.push_back(std::move(singleLine));
+
+ targets.push_back(std::move(gti));
+}
+
+void cmGlobalGenerator::AddGlobalTarget_RebuildCache(
+ std::vector<GlobalTargetInfo>& targets) const
+{
+ const char* rebuildCacheTargetName = this->GetRebuildCacheTargetName();
+ if (!rebuildCacheTargetName) {
+ return;
+ }
+ GlobalTargetInfo gti;
+ gti.Name = rebuildCacheTargetName;
+ gti.Message = "Running CMake to regenerate build system...";
+ gti.UsesTerminal = true;
+ gti.PerConfig = cmTarget::PerConfig::No;
+ cmCustomCommandLine singleLine;
+ singleLine.push_back(cmSystemTools::GetCMakeCommand());
+ singleLine.push_back("--regenerate-during-build");
+ singleLine.push_back("-S$(CMAKE_SOURCE_DIR)");
+ singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
+ gti.CommandLines.push_back(std::move(singleLine));
+ gti.StdPipesUTF8 = true;
+ targets.push_back(std::move(gti));
+}
+
+void cmGlobalGenerator::AddGlobalTarget_Install(
+ std::vector<GlobalTargetInfo>& targets)
+{
+ auto& mf = this->Makefiles[0];
+ const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
+ bool skipInstallRules = mf->IsOn("CMAKE_SKIP_INSTALL_RULES");
+ if (this->InstallTargetEnabled && skipInstallRules) {
+ this->CMakeInstance->IssueMessage(
+ MessageType::WARNING,
+ "CMAKE_SKIP_INSTALL_RULES was enabled even though "
+ "installation rules have been specified",
+ mf->GetBacktrace());
+ } else if (this->InstallTargetEnabled && !skipInstallRules) {
+ if (!(cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.')) {
+ std::set<std::string>* componentsSet = &this->InstallComponents;
+ std::ostringstream ostr;
+ if (!componentsSet->empty()) {
+ ostr << "Available install components are: ";
+ ostr << cmWrap('"', *componentsSet, '"', " ");
+ } else {
+ ostr << "Only default component available";
+ }
+ GlobalTargetInfo gti;
+ gti.Name = "list_install_components";
+ gti.Message = ostr.str();
+ gti.UsesTerminal = false;
+ targets.push_back(std::move(gti));
+ }
+ std::string cmd = cmSystemTools::GetCMakeCommand();
+ GlobalTargetInfo gti;
+ gti.Name = this->GetInstallTargetName();
+ gti.Message = "Install the project...";
+ gti.UsesTerminal = true;
+ gti.StdPipesUTF8 = true;
+ cmCustomCommandLine singleLine;
+ if (this->GetPreinstallTargetName()) {
+ gti.Depends.emplace_back(this->GetPreinstallTargetName());
+ } else {
+ cmProp noall = mf->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
+ if (cmIsOff(noall)) {
+ gti.Depends.emplace_back(this->GetAllTargetName());
+ }
+ }
+ if (mf->GetDefinition("CMake_BINARY_DIR") &&
+ !mf->IsOn("CMAKE_CROSSCOMPILING")) {
+ // We are building CMake itself. We cannot use the original
+ // executable to install over itself. The generator will
+ // automatically convert this name to the build-time location.
+ cmd = "cmake";
+ }
+ singleLine.push_back(cmd);
+ if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
+ std::string cfgArg = "-DBUILD_TYPE=";
+ bool useEPN = this->UseEffectivePlatformName(mf.get());
+ if (useEPN) {
+ cfgArg += "$(CONFIGURATION)";
+ singleLine.push_back(cfgArg);
+ cfgArg = "-DEFFECTIVE_PLATFORM_NAME=$(EFFECTIVE_PLATFORM_NAME)";
+ } else {
+ cfgArg += cmToCStr(mf->GetDefinition("CMAKE_CFG_INTDIR"));
+ }
+ singleLine.push_back(cfgArg);
+ }
+ singleLine.push_back("-P");
+ singleLine.push_back("cmake_install.cmake");
+ gti.CommandLines.push_back(singleLine);
+ targets.push_back(gti);
+
+ // install_local
+ if (const char* install_local = this->GetInstallLocalTargetName()) {
+ gti.Name = install_local;
+ gti.Message = "Installing only the local directory...";
+ gti.UsesTerminal = true;
+ gti.CommandLines.clear();
+
+ cmCustomCommandLine localCmdLine = singleLine;
+
+ localCmdLine.insert(localCmdLine.begin() + 1,
+ "-DCMAKE_INSTALL_LOCAL_ONLY=1");
+
+ gti.CommandLines.push_back(std::move(localCmdLine));
+ targets.push_back(gti);
+ }
+
+ // install_strip
+ const char* install_strip = this->GetInstallStripTargetName();
+ if ((install_strip != nullptr) && (mf->IsSet("CMAKE_STRIP"))) {
+ gti.Name = install_strip;
+ gti.Message = "Installing the project stripped...";
+ gti.UsesTerminal = true;
+ gti.CommandLines.clear();
+
+ cmCustomCommandLine stripCmdLine = singleLine;
+
+ stripCmdLine.insert(stripCmdLine.begin() + 1,
+ "-DCMAKE_INSTALL_DO_STRIP=1");
+ gti.CommandLines.push_back(std::move(stripCmdLine));
+ targets.push_back(gti);
+ }
+ }
+}
+
+std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const
+{
+ cmProp prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
+ "PREDEFINED_TARGETS_FOLDER");
+
+ if (prop) {
+ return *prop;
+ }
+
+ return "CMakePredefinedTargets";
+}
+
+bool cmGlobalGenerator::UseFolderProperty() const
+{
+ cmProp prop =
+ this->GetCMakeInstance()->GetState()->GetGlobalProperty("USE_FOLDERS");
+
+ // If this property is defined, let the setter turn this on or off...
+ //
+ if (prop) {
+ return cmIsOn(*prop);
+ }
+
+ // By default, this feature is OFF, since it is not supported in the
+ // Visual Studio Express editions until VS11:
+ //
+ return false;
+}
+
+cmTarget cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti,
+ cmMakefile* mf)
+{
+ // Package
+ cmTarget target(gti.Name, cmStateEnums::GLOBAL_TARGET,
+ cmTarget::VisibilityNormal, mf, gti.PerConfig);
+ target.SetProperty("EXCLUDE_FROM_ALL", "TRUE");
+
+ std::vector<std::string> no_outputs;
+ std::vector<std::string> no_byproducts;
+ std::vector<std::string> no_depends;
+ // Store the custom command in the target.
+ cmCustomCommand cc(no_outputs, no_byproducts, no_depends, gti.CommandLines,
+ cmListFileBacktrace(), nullptr, gti.WorkingDir.c_str(),
+ gti.StdPipesUTF8);
+ cc.SetUsesTerminal(gti.UsesTerminal);
+ target.AddPostBuildCommand(std::move(cc));
+ if (!gti.Message.empty()) {
+ target.SetProperty("EchoString", gti.Message);
+ }
+ for (std::string const& d : gti.Depends) {
+ target.AddUtility(d, false);
+ }
+
+ // Organize in the "predefined targets" folder:
+ //
+ if (this->UseFolderProperty()) {
+ target.SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
+ }
+
+ return target;
+}
+
+std::string cmGlobalGenerator::GenerateRuleFile(
+ std::string const& output) const
+{
+ std::string ruleFile = cmStrCat(output, ".rule");
+ const char* dir = this->GetCMakeCFGIntDir();
+ if (dir && dir[0] == '$') {
+ cmSystemTools::ReplaceString(ruleFile, dir, "/CMakeFiles");
+ }
+ return ruleFile;
+}
+
+bool cmGlobalGenerator::ShouldStripResourcePath(cmMakefile* mf) const
+{
+ return mf->PlatformIsAppleEmbedded();
+}
+
+std::string cmGlobalGenerator::GetSharedLibFlagsForLanguage(
+ std::string const& l) const
+{
+ auto const it = this->LanguageToOriginalSharedLibFlags.find(l);
+ if (it != this->LanguageToOriginalSharedLibFlags.end()) {
+ return it->second;
+ }
+ return "";
+}
+
+void cmGlobalGenerator::AppendDirectoryForConfig(const std::string& /*unused*/,
+ const std::string& /*unused*/,
+ const std::string& /*unused*/,
+ std::string& /*unused*/)
+{
+ // Subclasses that support multiple configurations should implement
+ // this method to append the subdirectory for the given build
+ // configuration.
+}
+
+cmGlobalGenerator::TargetDependSet const&
+cmGlobalGenerator::GetTargetDirectDepends(cmGeneratorTarget const* target)
+{
+ return this->TargetDependencies[target];
+}
+
+bool cmGlobalGenerator::IsReservedTarget(std::string const& name)
+{
+ // The following is a list of targets reserved
+ // by one or more of the cmake generators.
+
+ // Adding additional targets to this list will require a policy!
+ const char* reservedTargets[] = { "all", "ALL_BUILD", "help",
+ "install", "INSTALL", "preinstall",
+ "clean", "edit_cache", "rebuild_cache",
+ "ZERO_CHECK" };
+
+ return cm::contains(reservedTargets, name);
+}
+
+void cmGlobalGenerator::SetExternalMakefileProjectGenerator(
+ std::unique_ptr<cmExternalMakefileProjectGenerator> extraGenerator)
+{
+ this->ExtraGenerator = std::move(extraGenerator);
+ if (this->ExtraGenerator) {
+ this->ExtraGenerator->SetGlobalGenerator(this);
+ }
+}
+
+std::string cmGlobalGenerator::GetExtraGeneratorName() const
+{
+ return this->ExtraGenerator ? this->ExtraGenerator->GetName()
+ : std::string();
+}
+
+void cmGlobalGenerator::FileReplacedDuringGenerate(const std::string& filename)
+{
+ this->FilesReplacedDuringGenerate.push_back(filename);
+}
+
+void cmGlobalGenerator::GetFilesReplacedDuringGenerate(
+ std::vector<std::string>& filenames)
+{
+ filenames.clear();
+ std::copy(this->FilesReplacedDuringGenerate.begin(),
+ this->FilesReplacedDuringGenerate.end(),
+ std::back_inserter(filenames));
+}
+
+void cmGlobalGenerator::GetTargetSets(
+ TargetDependSet& projectTargets, TargetDependSet& originalTargets,
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
+{
+ // loop over all local generators
+ for (auto* generator : generators) {
+ // check to make sure generator is not excluded
+ if (this->IsExcluded(root, generator)) {
+ continue;
+ }
+ // loop over all the generator targets in the makefile
+ for (const auto& target : generator->GetGeneratorTargets()) {
+ if (this->IsRootOnlyTarget(target.get()) &&
+ target->GetLocalGenerator() != root) {
+ continue;
+ }
+ // put the target in the set of original targets
+ originalTargets.insert(target.get());
+ // Get the set of targets that depend on target
+ this->AddTargetDepends(target.get(), projectTargets);
+ }
+ }
+}
+
+bool cmGlobalGenerator::IsRootOnlyTarget(cmGeneratorTarget* target) const
+{
+ return (target->GetType() == cmStateEnums::GLOBAL_TARGET ||
+ target->GetName() == this->GetAllTargetName());
+}
+
+void cmGlobalGenerator::AddTargetDepends(cmGeneratorTarget const* target,
+ TargetDependSet& projectTargets)
+{
+ // add the target itself
+ if (projectTargets.insert(target).second) {
+ // This is the first time we have encountered the target.
+ // Recursively follow its dependencies.
+ for (auto const& t : this->GetTargetDirectDepends(target)) {
+ this->AddTargetDepends(t, projectTargets);
+ }
+ }
+}
+
+void cmGlobalGenerator::AddToManifest(std::string const& f)
+{
+ // Add to the content listing for the file's directory.
+ std::string dir = cmSystemTools::GetFilenamePath(f);
+ std::string file = cmSystemTools::GetFilenameName(f);
+ DirectoryContent& dc = this->DirectoryContentMap[dir];
+ dc.Generated.insert(file);
+ dc.All.insert(file);
+}
+
+std::set<std::string> const& cmGlobalGenerator::GetDirectoryContent(
+ std::string const& dir, bool needDisk)
+{
+ DirectoryContent& dc = this->DirectoryContentMap[dir];
+ if (needDisk) {
+ long mt = cmSystemTools::ModifiedTime(dir);
+ if (mt != dc.LastDiskTime) {
+ // Reset to non-loaded directory content.
+ dc.All = dc.Generated;
+
+ // Load the directory content from disk.
+ cmsys::Directory d;
+ if (d.Load(dir)) {
+ unsigned long n = d.GetNumberOfFiles();
+ for (unsigned long i = 0; i < n; ++i) {
+ const char* f = d.GetFile(i);
+ if (strcmp(f, ".") != 0 && strcmp(f, "..") != 0) {
+ dc.All.insert(f);
+ }
+ }
+ }
+ dc.LastDiskTime = mt;
+ }
+ }
+ return dc.All;
+}
+
+void cmGlobalGenerator::AddRuleHash(const std::vector<std::string>& outputs,
+ std::string const& content)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ // Ignore if there are no outputs.
+ if (outputs.empty()) {
+ return;
+ }
+
+ // Compute a hash of the rule.
+ RuleHash hash;
+ {
+ cmCryptoHash md5(cmCryptoHash::AlgoMD5);
+ std::string const md5_hex = md5.HashString(content);
+ memcpy(hash.Data, md5_hex.c_str(), 32);
+ }
+
+ // Shorten the output name (in expected use case).
+ cmStateDirectory cmDir =
+ this->GetMakefiles()[0]->GetStateSnapshot().GetDirectory();
+ std::string fname = cmDir.ConvertToRelPathIfNotContained(
+ this->GetMakefiles()[0]->GetState()->GetBinaryDirectory(), outputs[0]);
+
+ // Associate the hash with this output.
+ this->RuleHashes[fname] = hash;
+#else
+ (void)outputs;
+ (void)content;
+#endif
+}
+
+void cmGlobalGenerator::CheckRuleHashes()
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ std::string home = this->GetCMakeInstance()->GetHomeOutputDirectory();
+ std::string pfile = cmStrCat(home, "/CMakeFiles/CMakeRuleHashes.txt");
+ this->CheckRuleHashes(pfile, home);
+ this->WriteRuleHashes(pfile);
+#endif
+}
+
+void cmGlobalGenerator::CheckRuleHashes(std::string const& pfile,
+ std::string const& home)
+{
+#if defined(_WIN32) || defined(__CYGWIN__)
+ cmsys::ifstream fin(pfile.c_str(), std::ios::in | std::ios::binary);
+#else
+ cmsys::ifstream fin(pfile.c_str());
+#endif
+ if (!fin) {
+ return;
+ }
+ std::string line;
+ std::string fname;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ // Line format is a 32-byte hex string followed by a space
+ // followed by a file name (with no escaping).
+
+ // Skip blank and comment lines.
+ if (line.size() < 34 || line[0] == '#') {
+ continue;
+ }
+
+ // Get the filename.
+ fname = line.substr(33);
+
+ // Look for a hash for this file's rule.
+ auto const rhi = this->RuleHashes.find(fname);
+ if (rhi != this->RuleHashes.end()) {
+ // Compare the rule hash in the file to that we were given.
+ if (strncmp(line.c_str(), rhi->second.Data, 32) != 0) {
+ // The rule has changed. Delete the output so it will be
+ // built again.
+ fname = cmSystemTools::CollapseFullPath(fname, home);
+ cmSystemTools::RemoveFile(fname);
+ }
+ } else {
+ // We have no hash for a rule previously listed. This may be a
+ // case where a user has turned off a build option and might
+ // want to turn it back on later, so do not delete the file.
+ // Instead, we keep the rule hash as long as the file exists so
+ // that if the feature is turned back on and the rule has
+ // changed the file is still rebuilt.
+ std::string fpath = cmSystemTools::CollapseFullPath(fname, home);
+ if (cmSystemTools::FileExists(fpath)) {
+ RuleHash hash;
+ memcpy(hash.Data, line.c_str(), 32);
+ this->RuleHashes[fname] = hash;
+ }
+ }
+ }
+}
+
+void cmGlobalGenerator::WriteRuleHashes(std::string const& pfile)
+{
+ // Now generate a new persistence file with the current hashes.
+ if (this->RuleHashes.empty()) {
+ cmSystemTools::RemoveFile(pfile);
+ } else {
+ cmGeneratedFileStream fout(pfile);
+ fout << "# Hashes of file build rules.\n";
+ for (auto const& rh : this->RuleHashes) {
+ fout.write(rh.second.Data, 32);
+ fout << " " << rh.first << "\n";
+ }
+ }
+}
+
+void cmGlobalGenerator::WriteSummary()
+{
+ // Record all target directories in a central location.
+ std::string fname = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
+ "/CMakeFiles/TargetDirectories.txt");
+ cmGeneratedFileStream fout(fname);
+
+ for (const auto& lg : this->LocalGenerators) {
+ for (const auto& tgt : lg->GetGeneratorTargets()) {
+ if (!tgt->IsInBuildSystem()) {
+ continue;
+ }
+ this->WriteSummary(tgt.get());
+ fout << tgt->GetSupportDirectory() << "\n";
+ }
+ }
+}
+
+void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target)
+{
+ // Place the labels file in a per-target support directory.
+ std::string dir = target->GetSupportDirectory();
+ std::string file = cmStrCat(dir, "/Labels.txt");
+ std::string json_file = dir + "/Labels.json";
+
+#ifndef CMAKE_BOOTSTRAP
+ // Check whether labels are enabled for this target.
+ cmProp targetLabels = target->GetProperty("LABELS");
+ cmProp directoryLabels =
+ target->Target->GetMakefile()->GetProperty("LABELS");
+ cmProp cmakeDirectoryLabels =
+ target->Target->GetMakefile()->GetDefinition("CMAKE_DIRECTORY_LABELS");
+ if (targetLabels || directoryLabels || cmakeDirectoryLabels) {
+ Json::Value lj_root(Json::objectValue);
+ Json::Value& lj_target = lj_root["target"] = Json::objectValue;
+ lj_target["name"] = target->GetName();
+ Json::Value& lj_target_labels = lj_target["labels"] = Json::arrayValue;
+ Json::Value& lj_sources = lj_root["sources"] = Json::arrayValue;
+
+ cmSystemTools::MakeDirectory(dir);
+ cmGeneratedFileStream fout(file);
+
+ std::vector<std::string> labels;
+
+ // List the target-wide labels. All sources in the target get
+ // these labels.
+ if (targetLabels) {
+ cmExpandList(*targetLabels, labels);
+ if (!labels.empty()) {
+ fout << "# Target labels\n";
+ for (std::string const& l : labels) {
+ fout << " " << l << "\n";
+ lj_target_labels.append(l);
+ }
+ }
+ }
+
+ // List directory labels
+ std::vector<std::string> directoryLabelsList;
+ std::vector<std::string> cmakeDirectoryLabelsList;
+
+ if (directoryLabels) {
+ cmExpandList(*directoryLabels, directoryLabelsList);
+ }
+
+ if (cmakeDirectoryLabels) {
+ cmExpandList(*cmakeDirectoryLabels, cmakeDirectoryLabelsList);
+ }
+
+ if (!directoryLabelsList.empty() || !cmakeDirectoryLabelsList.empty()) {
+ fout << "# Directory labels\n";
+ }
+
+ for (std::string const& li : directoryLabelsList) {
+ fout << " " << li << "\n";
+ lj_target_labels.append(li);
+ }
+
+ for (std::string const& li : cmakeDirectoryLabelsList) {
+ fout << " " << li << "\n";
+ lj_target_labels.append(li);
+ }
+
+ // List the source files with any per-source labels.
+ fout << "# Source files and their labels\n";
+ std::vector<cmSourceFile*> sources;
+ std::vector<std::string> const& configs =
+ target->Target->GetMakefile()->GetGeneratorConfigs(
+ cmMakefile::IncludeEmptyConfig);
+ for (std::string const& c : configs) {
+ target->GetSourceFiles(sources, c);
+ }
+ auto const sourcesEnd = cmRemoveDuplicates(sources);
+ for (cmSourceFile* sf : cmMakeRange(sources.cbegin(), sourcesEnd)) {
+ Json::Value& lj_source = lj_sources.append(Json::objectValue);
+ std::string const& sfp = sf->ResolveFullPath();
+ fout << sfp << "\n";
+ lj_source["file"] = sfp;
+ if (cmProp svalue = sf->GetProperty("LABELS")) {
+ labels.clear();
+ Json::Value& lj_source_labels = lj_source["labels"] = Json::arrayValue;
+ cmExpandList(*svalue, labels);
+ for (std::string const& label : labels) {
+ fout << " " << label << "\n";
+ lj_source_labels.append(label);
+ }
+ }
+ }
+ cmGeneratedFileStream json_fout(json_file);
+ json_fout << lj_root;
+ } else
+#endif
+ {
+ cmSystemTools::RemoveFile(file);
+ cmSystemTools::RemoveFile(json_file);
+ }
+}
+
+// static
+std::string cmGlobalGenerator::EscapeJSON(const std::string& s)
+{
+ std::string result;
+ result.reserve(s.size());
+ for (char i : s) {
+ switch (i) {
+ case '"':
+ case '\\':
+ result += '\\';
+ result += i;
+ break;
+ case '\n':
+ result += "\\n";
+ break;
+ case '\t':
+ result += "\\t";
+ break;
+ default:
+ result += i;
+ }
+ }
+ return result;
+}
+
+void cmGlobalGenerator::SetFilenameTargetDepends(
+ cmSourceFile* sf, std::set<cmGeneratorTarget const*> const& tgts)
+{
+ this->FilenameTargetDepends[sf] = tgts;
+}
+
+std::set<cmGeneratorTarget const*> const&
+cmGlobalGenerator::GetFilenameTargetDepends(cmSourceFile* sf) const
+{
+ return this->FilenameTargetDepends[sf];
+}
+
+const std::string& cmGlobalGenerator::GetRealPath(const std::string& dir)
+{
+ auto i = this->RealPaths.lower_bound(dir);
+ if (i == this->RealPaths.end() ||
+ this->RealPaths.key_comp()(dir, i->first)) {
+ i = this->RealPaths.emplace_hint(i, dir, cmSystemTools::GetRealPath(dir));
+ }
+ return i->second;
+}
+
+std::string cmGlobalGenerator::NewDeferId()
+{
+ return cmStrCat("__"_s, std::to_string(this->NextDeferId++));
+}
+
+void cmGlobalGenerator::ProcessEvaluationFiles()
+{
+ std::vector<std::string> generatedFiles;
+ for (auto& localGen : this->LocalGenerators) {
+ localGen->ProcessEvaluationFiles(generatedFiles);
+ }
+}
+
+std::string cmGlobalGenerator::ExpandCFGIntDir(
+ const std::string& str, const std::string& /*config*/) const
+{
+ return str;
+}
+
+bool cmGlobalGenerator::GenerateCPackPropertiesFile()
+{
+ cmake::InstalledFilesMap const& installedFiles =
+ this->CMakeInstance->GetInstalledFiles();
+
+ const auto& lg = this->LocalGenerators[0];
+ cmMakefile* mf = lg->GetMakefile();
+
+ std::vector<std::string> configs =
+ mf->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig);
+ std::string config = mf->GetDefaultConfiguration();
+
+ std::string path = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
+ "/CPackProperties.cmake");
+
+ if (!cmSystemTools::FileExists(path) && installedFiles.empty()) {
+ return true;
+ }
+
+ cmGeneratedFileStream file(path);
+ file << "# CPack properties\n";
+
+ for (auto const& i : installedFiles) {
+ cmInstalledFile const& installedFile = i.second;
+
+ cmCPackPropertiesGenerator cpackPropertiesGenerator(
+ lg.get(), installedFile, configs);
+
+ cpackPropertiesGenerator.Generate(file, config, configs);
+ }
+
+ return true;
+}
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
new file mode 100644
index 0000000..590de26
--- /dev/null
+++ b/Source/cmGlobalGenerator.h
@@ -0,0 +1,759 @@
+/* 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 <cstddef>
+#include <iosfwd>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+#include <cmext/algorithm>
+
+#include "cm_codecvt.hxx"
+
+#include "cmCustomCommandLines.h"
+#include "cmDuration.h"
+#include "cmExportSet.h"
+#include "cmStateSnapshot.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetDepend.h"
+#include "cmTransformDepfile.h"
+
+#if !defined(CMAKE_BOOTSTRAP)
+# include <cm3p/json/value.h>
+
+# include "cmFileLockPool.h"
+#endif
+
+#define CMAKE_DIRECTORY_ID_SEP "::@"
+
+class cmDirectoryId;
+class cmExportBuildFileGenerator;
+class cmExternalMakefileProjectGenerator;
+class cmGeneratorTarget;
+class cmLinkLineComputer;
+class cmLocalGenerator;
+class cmMakefile;
+class cmOutputConverter;
+class cmSourceFile;
+class cmState;
+class cmStateDirectory;
+class cmake;
+
+namespace detail {
+inline void AppendStrs(std::vector<std::string>&)
+{
+}
+template <typename T, typename... Ts>
+inline void AppendStrs(std::vector<std::string>& command, T&& s, Ts&&... ts)
+{
+ command.emplace_back(std::forward<T>(s));
+ AppendStrs(command, std::forward<Ts>(ts)...);
+}
+
+struct GeneratedMakeCommand
+{
+ // Add each argument as a separate element to the vector
+ template <typename... T>
+ void Add(T&&... args)
+ {
+ // iterate the args and append each one
+ AppendStrs(this->PrimaryCommand, std::forward<T>(args)...);
+ }
+
+ // Add each value in the iterators as a separate element to the vector
+ void Add(std::vector<std::string>::const_iterator start,
+ std::vector<std::string>::const_iterator end)
+ {
+ cm::append(this->PrimaryCommand, start, end);
+ }
+
+ std::string Printable() const { return cmJoin(this->PrimaryCommand, " "); }
+
+ std::vector<std::string> PrimaryCommand;
+ bool RequiresOutputForward = false;
+};
+}
+
+/** \class cmGlobalGenerator
+ * \brief Responsible for overseeing the generation process for the entire tree
+ *
+ * Subclasses of this class generate makefiles for various
+ * platforms.
+ */
+class cmGlobalGenerator
+{
+public:
+ using LocalGeneratorVector = std::vector<std::unique_ptr<cmLocalGenerator>>;
+
+ //! Free any memory allocated with the GlobalGenerator
+ cmGlobalGenerator(cmake* cm);
+ virtual ~cmGlobalGenerator();
+
+ virtual std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+ cmMakefile* mf);
+
+ //! Get the name for this generator
+ virtual std::string GetName() const { return "Generic"; }
+
+ /** Check whether the given name matches the current generator. */
+ virtual bool MatchesGeneratorName(const std::string& name) const
+ {
+ return this->GetName() == name;
+ }
+
+ /** Get encoding used by generator for makefile files */
+ virtual codecvt::Encoding GetMakefileEncoding() const
+ {
+ return codecvt::None;
+ }
+
+#if !defined(CMAKE_BOOTSTRAP)
+ /** Get a JSON object describing the generator. */
+ virtual Json::Value GetJson() const;
+#endif
+
+ /** Tell the generator about the target system. */
+ virtual bool SetSystemName(std::string const&, cmMakefile*) { return true; }
+
+ /** Set the generator-specific instance. Returns true if supported. */
+ virtual bool SetGeneratorInstance(std::string const& i, cmMakefile* mf);
+
+ /** Set the generator-specific platform name. Returns true if platform
+ is supported and false otherwise. */
+ virtual bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf);
+
+ /** Set the generator-specific toolset name. Returns true if toolset
+ is supported and false otherwise. */
+ virtual bool SetGeneratorToolset(std::string const& ts, bool build,
+ cmMakefile* mf);
+
+ /** Read any other cache entries needed for cmake --build. */
+ virtual bool ReadCacheEntriesForBuild(const cmState& /*state*/)
+ {
+ return true;
+ }
+
+ /**
+ * Create LocalGenerators and process the CMakeLists files. This does not
+ * actually produce any makefiles, DSPs, etc.
+ */
+ virtual void Configure();
+
+ bool Compute();
+ virtual void AddExtraIDETargets() {}
+
+ enum TargetTypes
+ {
+ AllTargets,
+ ImportedOnly
+ };
+
+ void CreateImportedGenerationObjects(
+ cmMakefile* mf, std::vector<std::string> const& targets,
+ std::vector<cmGeneratorTarget const*>& exports);
+ void CreateGenerationObjects(TargetTypes targetTypes = AllTargets);
+
+ /**
+ * Generate the all required files for building this project/tree. This
+ * basically creates a series of LocalGenerators for each directory and
+ * requests that they Generate.
+ */
+ virtual void Generate();
+
+ virtual std::unique_ptr<cmLinkLineComputer> CreateLinkLineComputer(
+ cmOutputConverter* outputConverter,
+ cmStateDirectory const& stateDir) const;
+
+ std::unique_ptr<cmLinkLineComputer> CreateMSVC60LinkLineComputer(
+ cmOutputConverter* outputConverter,
+ cmStateDirectory const& stateDir) const;
+
+ /**
+ * Set/Get and Clear the enabled languages.
+ */
+ void SetLanguageEnabled(const std::string&, cmMakefile* mf);
+ bool GetLanguageEnabled(const std::string&) const;
+ void ClearEnabledLanguages();
+ void GetEnabledLanguages(std::vector<std::string>& lang) const;
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+
+ /**
+ * Resolve the CMAKE_<lang>_COMPILER setting for the given language.
+ * Intended to be called from EnableLanguage.
+ */
+ void ResolveLanguageCompiler(const std::string& lang, cmMakefile* mf,
+ bool optional) const;
+
+ /**
+ * Try to determine system information, get it from another generator
+ */
+ void EnableLanguagesFromGenerator(cmGlobalGenerator* gen, cmMakefile* mf);
+
+ /**
+ * Try running cmake and building a file. This is used for dynamically
+ * loaded commands, not as part of the usual build process.
+ */
+ int TryCompile(int jobs, const std::string& srcdir,
+ const std::string& bindir, const std::string& projectName,
+ const std::string& targetName, bool fast, std::string& output,
+ cmMakefile* mf);
+
+ /**
+ * Build a file given the following information. This is a more direct call
+ * that is used by both CTest and TryCompile. If target name is NULL or
+ * empty then all is assumed. clean indicates if a "make clean" should be
+ * done first.
+ */
+ int Build(
+ int jobs, const std::string& srcdir, const std::string& bindir,
+ const std::string& projectName,
+ std::vector<std::string> const& targetNames, std::string& output,
+ const std::string& makeProgram, const std::string& config, bool clean,
+ bool fast, bool verbose, cmDuration timeout,
+ cmSystemTools::OutputOption outputflag = cmSystemTools::OUTPUT_NONE,
+ std::vector<std::string> const& nativeOptions =
+ std::vector<std::string>());
+
+ /**
+ * Open a generated IDE project given the following information.
+ */
+ virtual bool Open(const std::string& bindir, const std::string& projectName,
+ bool dryRun);
+
+ struct GeneratedMakeCommand final : public detail::GeneratedMakeCommand
+ {
+ };
+
+ virtual std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions = std::vector<std::string>());
+
+ virtual void PrintBuildCommandAdvice(std::ostream& os, int jobs) const;
+
+ /** Generate a "cmake --build" call for a given target and config. */
+ std::string GenerateCMakeBuildCommand(const std::string& target,
+ const std::string& config,
+ const std::string& native,
+ bool ignoreErrors);
+
+ //! Get the CMake instance
+ cmake* GetCMakeInstance() const { return this->CMakeInstance; }
+
+ void SetConfiguredFilesPath(cmGlobalGenerator* gen);
+ const std::vector<std::unique_ptr<cmMakefile>>& GetMakefiles() const
+ {
+ return this->Makefiles;
+ }
+ const LocalGeneratorVector& GetLocalGenerators() const
+ {
+ return this->LocalGenerators;
+ }
+
+ std::vector<cmGeneratorTarget*> GetLocalGeneratorTargetsInOrder(
+ cmLocalGenerator* lg) const;
+
+ cmMakefile* GetCurrentMakefile() const
+ {
+ return this->CurrentConfigureMakefile;
+ }
+
+ void SetCurrentMakefile(cmMakefile* mf)
+ {
+ this->CurrentConfigureMakefile = mf;
+ }
+
+ void AddMakefile(std::unique_ptr<cmMakefile> mf);
+
+ //! Set an generator for an "external makefile based project"
+ void SetExternalMakefileProjectGenerator(
+ std::unique_ptr<cmExternalMakefileProjectGenerator> extraGenerator);
+
+ std::string GetExtraGeneratorName() const;
+
+ void AddInstallComponent(const std::string& component);
+
+ /** Mark the (absolute path to a) file as generated. */
+ void MarkAsGeneratedFile(const std::string& filepath);
+ /** Determine if the absolute filepath belongs to a generated file. */
+ bool IsGeneratedFile(const std::string& filepath);
+
+ const std::set<std::string>* GetInstallComponents() const
+ {
+ return &this->InstallComponents;
+ }
+
+ cmExportSetMap& GetExportSets() { return this->ExportSets; }
+
+ const char* GetGlobalSetting(std::string const& name) const;
+ bool GlobalSettingIsOn(std::string const& name) const;
+ std::string GetSafeGlobalSetting(std::string const& name) const;
+
+ /** Add a file to the manifest of generated targets for a configuration. */
+ void AddToManifest(std::string const& f);
+
+ void EnableInstallTarget();
+
+ cmDuration TryCompileTimeout;
+
+ bool GetForceUnixPaths() const { return this->ForceUnixPaths; }
+ bool GetToolSupportsColor() const { return this->ToolSupportsColor; }
+
+ //! return the language for the given extension
+ std::string GetLanguageFromExtension(const char* ext) const;
+ //! is an extension to be ignored
+ bool IgnoreFile(const char* ext) const;
+ //! What is the preference for linkers and this language (None or Preferred)
+ int GetLinkerPreference(const std::string& lang) const;
+ //! What is the object file extension for a given source file?
+ std::string GetLanguageOutputExtension(cmSourceFile const&) const;
+
+ //! What is the configurations directory variable called?
+ virtual const char* GetCMakeCFGIntDir() const { return "."; }
+
+ //! expand CFGIntDir for a configuration
+ virtual std::string ExpandCFGIntDir(const std::string& str,
+ const std::string& config) const;
+
+ /** Get whether the generator should use a script for link commands. */
+ bool GetUseLinkScript() const { return this->UseLinkScript; }
+
+ /** Get whether the generator should produce special marks on rules
+ producing symbolic (non-file) outputs. */
+ bool GetNeedSymbolicMark() const { return this->NeedSymbolicMark; }
+
+ /*
+ * Determine what program to use for building the project.
+ */
+ virtual bool FindMakeProgram(cmMakefile*);
+
+ //! Find a target by name by searching the local generators.
+ cmTarget* FindTarget(const std::string& name,
+ bool excludeAliases = false) const;
+
+ cmGeneratorTarget* FindGeneratorTarget(const std::string& name) const;
+
+ void AddAlias(const std::string& name, const std::string& tgtName);
+ bool IsAlias(const std::string& name) const;
+
+ /** Determine if a name resolves to a framework on disk or a built target
+ that is a framework. */
+ bool NameResolvesToFramework(const std::string& libname) const;
+
+ cmMakefile* FindMakefile(const std::string& start_dir) const;
+ cmLocalGenerator* FindLocalGenerator(cmDirectoryId const& id) const;
+
+ /** Append the subdirectory for the given configuration. If anything is
+ appended the given prefix and suffix will be appended around it, which
+ is useful for leading or trailing slashes. */
+ virtual void AppendDirectoryForConfig(const std::string& prefix,
+ const std::string& config,
+ const std::string& suffix,
+ std::string& dir);
+
+ /** Get the content of a directory. Directory listings are cached
+ and re-loaded from disk only when modified. During the generation
+ step the content will include the target files to be built even if
+ they do not yet exist. */
+ std::set<std::string> const& GetDirectoryContent(std::string const& dir,
+ bool needDisk = true);
+
+ void IndexTarget(cmTarget* t);
+ void IndexGeneratorTarget(cmGeneratorTarget* gt);
+
+ // Index the target using a name that is unique to that target
+ // even if other targets have the same name.
+ std::string IndexGeneratorTargetUniquely(cmGeneratorTarget const* gt);
+
+ static bool IsReservedTarget(std::string const& name);
+
+ virtual const char* GetAllTargetName() const { return "ALL_BUILD"; }
+ virtual const char* GetInstallTargetName() const { return "INSTALL"; }
+ virtual const char* GetInstallLocalTargetName() const { return nullptr; }
+ virtual const char* GetInstallStripTargetName() const { return nullptr; }
+ virtual const char* GetPreinstallTargetName() const { return nullptr; }
+ virtual const char* GetTestTargetName() const { return "RUN_TESTS"; }
+ virtual const char* GetPackageTargetName() const { return "PACKAGE"; }
+ virtual const char* GetPackageSourceTargetName() const { return nullptr; }
+ virtual const char* GetEditCacheTargetName() const { return nullptr; }
+ virtual const char* GetRebuildCacheTargetName() const { return nullptr; }
+ virtual const char* GetCleanTargetName() const { return nullptr; }
+
+ // Lookup edit_cache target command preferred by this generator.
+ virtual std::string GetEditCacheCommand() const { return ""; }
+
+ // Default config to use for cmake --build
+ virtual std::string GetDefaultBuildConfig() const { return "Debug"; }
+
+ // Class to track a set of dependencies.
+ using TargetDependSet = cmTargetDependSet;
+
+ // what targets does the specified target depend on directly
+ // via a target_link_libraries or add_dependencies
+ TargetDependSet const& GetTargetDirectDepends(
+ const cmGeneratorTarget* target);
+
+ const std::map<std::string, std::vector<cmLocalGenerator*>>& GetProjectMap()
+ const
+ {
+ return this->ProjectMap;
+ }
+
+ // track files replaced during a Generate
+ void FileReplacedDuringGenerate(const std::string& filename);
+ void GetFilesReplacedDuringGenerate(std::vector<std::string>& filenames);
+
+ void AddRuleHash(const std::vector<std::string>& outputs,
+ std::string const& content);
+
+ /** Return whether the given binary directory is unused. */
+ bool BinaryDirectoryIsNew(const std::string& dir)
+ {
+ return this->BinaryDirectories.insert(dir).second;
+ }
+
+ /** Return true if the generated build tree may contain multiple builds.
+ i.e. "Can I build Debug and Release in the same tree?" */
+ virtual bool IsMultiConfig() const { return false; }
+
+ virtual bool IsXcode() const { return false; }
+
+ virtual bool IsVisualStudio() const { return false; }
+
+ virtual bool IsNinja() const { return false; }
+
+ /** Return true if we know the exact location of object files.
+ If false, store the reason in the given string.
+ This is meaningful only after EnableLanguage has been called. */
+ virtual bool HasKnownObjectFileLocation(std::string*) const { return true; }
+
+ virtual bool UseFolderProperty() const;
+
+ virtual bool IsIPOSupported() const { return false; }
+
+ /** Return whether the generator can import external visual studio project
+ using INCLUDE_EXTERNAL_MSPROJECT */
+ virtual bool IsIncludeExternalMSProjectSupported() const { return false; }
+
+ /** Return whether the generator should use EFFECTIVE_PLATFORM_NAME. This is
+ relevant for mixed macOS and iOS builds. */
+ virtual bool UseEffectivePlatformName(cmMakefile*) const { return false; }
+
+ /** Return whether the "Resources" folder prefix should be stripped from
+ MacFolder. */
+ virtual bool ShouldStripResourcePath(cmMakefile*) const;
+
+ virtual bool SupportsCustomCommandDepfile() const { return false; }
+ virtual cm::optional<cmDepfileFormat> DepfileFormat() const
+ {
+ return cm::nullopt;
+ }
+
+ std::string GetSharedLibFlagsForLanguage(std::string const& lang) const;
+
+ /** Generate an <output>.rule file path for a given command output. */
+ virtual std::string GenerateRuleFile(std::string const& output) const;
+
+ virtual bool SupportsDefaultBuildType() const { return false; }
+ virtual bool SupportsCrossConfigs() const { return false; }
+ virtual bool SupportsDefaultConfigs() const { return false; }
+
+ static std::string EscapeJSON(const std::string& s);
+
+ void ProcessEvaluationFiles();
+
+ std::map<std::string, cmExportBuildFileGenerator*>& GetBuildExportSets()
+ {
+ return this->BuildExportSets;
+ }
+ void AddBuildExportSet(cmExportBuildFileGenerator* gen);
+ void AddBuildExportExportSet(cmExportBuildFileGenerator* gen);
+ bool IsExportedTargetsFile(const std::string& filename) const;
+ bool GenerateImportFile(const std::string& file);
+ cmExportBuildFileGenerator* GetExportedTargetsFile(
+ const std::string& filename) const;
+ void AddCMP0042WarnTarget(const std::string& target);
+ void AddCMP0068WarnTarget(const std::string& target);
+
+ virtual void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const;
+
+ bool GenerateCPackPropertiesFile();
+
+ void SetFilenameTargetDepends(
+ cmSourceFile* sf, std::set<cmGeneratorTarget const*> const& tgts);
+ const std::set<const cmGeneratorTarget*>& GetFilenameTargetDepends(
+ cmSourceFile* sf) const;
+
+#if !defined(CMAKE_BOOTSTRAP)
+ cmFileLockPool& GetFileLockPool() { return this->FileLockPool; }
+#endif
+
+ bool GetConfigureDoneCMP0026() const
+ {
+ return this->ConfigureDoneCMP0026AndCMP0024;
+ }
+
+ std::string MakeSilentFlag;
+
+ int RecursionDepth;
+
+ virtual void GetQtAutoGenConfigs(std::vector<std::string>& configs) const
+ {
+ configs.emplace_back("$<CONFIG>");
+ }
+
+ 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
+ void GetTargetSets(TargetDependSet& projectTargets,
+ TargetDependSet& originalTargets, cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators);
+ bool IsRootOnlyTarget(cmGeneratorTarget* target) const;
+ void AddTargetDepends(const cmGeneratorTarget* target,
+ TargetDependSet& projectTargets);
+ void SetLanguageEnabledFlag(const std::string& l, cmMakefile* mf);
+ void SetLanguageEnabledMaps(const std::string& l, cmMakefile* mf);
+ void FillExtensionToLanguageMap(const std::string& l, cmMakefile* mf);
+ virtual bool CheckLanguages(std::vector<std::string> const& languages,
+ cmMakefile* mf) const;
+ virtual void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
+ const char* envVar) const;
+
+ virtual bool ComputeTargetDepends();
+
+ virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const;
+
+ /// @brief Qt AUTOMOC/UIC/RCC target generation
+ /// @return true on success
+ bool QtAutoGen();
+
+ bool AddAutomaticSources();
+
+ std::string SelectMakeProgram(const std::string& makeProgram,
+ const std::string& makeDefault = "") const;
+
+ // Fill the ProjectMap, this must be called after LocalGenerators
+ // has been populated.
+ void FillProjectMap();
+ void CheckTargetProperties();
+ bool IsExcluded(cmStateSnapshot const& root,
+ cmStateSnapshot const& snp) const;
+ bool IsExcluded(cmLocalGenerator* root, cmLocalGenerator* gen) const;
+ bool IsExcluded(cmLocalGenerator* root,
+ const cmGeneratorTarget* target) const;
+ virtual void InitializeProgressMarks() {}
+
+ struct GlobalTargetInfo
+ {
+ std::string Name;
+ std::string Message;
+ cmCustomCommandLines CommandLines;
+ std::vector<std::string> Depends;
+ std::string WorkingDir;
+ bool UsesTerminal = false;
+ cmTarget::PerConfig PerConfig = cmTarget::PerConfig::Yes;
+ bool StdPipesUTF8 = false;
+ };
+
+ void CreateDefaultGlobalTargets(std::vector<GlobalTargetInfo>& targets);
+
+ void AddGlobalTarget_Package(std::vector<GlobalTargetInfo>& targets);
+ void AddGlobalTarget_PackageSource(std::vector<GlobalTargetInfo>& targets);
+ void AddGlobalTarget_Test(std::vector<GlobalTargetInfo>& targets);
+ void AddGlobalTarget_EditCache(std::vector<GlobalTargetInfo>& targets) const;
+ void AddGlobalTarget_RebuildCache(
+ std::vector<GlobalTargetInfo>& targets) const;
+ void AddGlobalTarget_Install(std::vector<GlobalTargetInfo>& targets);
+ cmTarget CreateGlobalTarget(GlobalTargetInfo const& gti, cmMakefile* mf);
+
+ std::string FindMakeProgramFile;
+ std::string ConfiguredFilesPath;
+ cmake* CMakeInstance;
+ std::vector<std::unique_ptr<cmMakefile>> Makefiles;
+ LocalGeneratorVector LocalGenerators;
+ cmMakefile* CurrentConfigureMakefile;
+ // map from project name to vector of local generators in that project
+ std::map<std::string, std::vector<cmLocalGenerator*>> ProjectMap;
+
+ // Set of named installation components requested by the project.
+ std::set<std::string> InstallComponents;
+ // Sets of named target exports
+ cmExportSetMap ExportSets;
+ std::map<std::string, cmExportBuildFileGenerator*> BuildExportSets;
+ std::map<std::string, cmExportBuildFileGenerator*> BuildExportExportSets;
+
+ std::map<std::string, std::string> AliasTargets;
+
+ cmTarget* FindTargetImpl(std::string const& name) const;
+
+ cmGeneratorTarget* FindGeneratorTargetImpl(std::string const& name) const;
+
+ std::string GetPredefinedTargetsFolder() const;
+
+ enum class FindMakeProgramStage
+ {
+ Early,
+ Late,
+ };
+
+ virtual FindMakeProgramStage GetFindMakeProgramStage() const
+ {
+ return FindMakeProgramStage::Late;
+ }
+
+private:
+ using TargetMap = std::unordered_map<std::string, cmTarget*>;
+ using GeneratorTargetMap =
+ std::unordered_map<std::string, cmGeneratorTarget*>;
+ using MakefileMap = std::unordered_map<std::string, cmMakefile*>;
+ using LocalGeneratorMap = std::unordered_map<std::string, cmLocalGenerator*>;
+ // Map efficiently from target name to cmTarget instance.
+ // Do not use this structure for looping over all targets.
+ // It contains both normal and globally visible imported targets.
+ TargetMap TargetSearchIndex;
+ GeneratorTargetMap GeneratorTargetSearchIndex;
+
+ // Map efficiently from source directory path to cmMakefile instance.
+ // Do not use this structure for looping over all directories.
+ // It may not contain all of them (see note in IndexMakefile method).
+ MakefileMap MakefileSearchIndex;
+
+ // Map efficiently from source directory path to cmLocalGenerator instance.
+ // Do not use this structure for looping over all directories.
+ // Its order is not deterministic.
+ LocalGeneratorMap LocalGeneratorSearchIndex;
+
+ void ComputeTargetOrder();
+ void ComputeTargetOrder(cmGeneratorTarget const* gt, size_t& index);
+ std::map<cmGeneratorTarget const*, size_t> TargetOrderIndex;
+
+ cmMakefile* TryCompileOuterMakefile;
+ // If you add a new map here, make sure it is copied
+ // in EnableLanguagesFromGenerator
+ std::map<std::string, bool> IgnoreExtensions;
+ std::set<std::string> LanguagesReady; // Ready for try_compile
+ std::set<std::string> LanguagesInProgress;
+ std::map<std::string, std::string> OutputExtensions;
+ std::map<std::string, std::string> LanguageToOutputExtension;
+ std::map<std::string, std::string> ExtensionToLanguage;
+ 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
+ {
+ char Data[32];
+ };
+ std::map<std::string, RuleHash> RuleHashes;
+ void CheckRuleHashes();
+ void CheckRuleHashes(std::string const& pfile, std::string const& home);
+ void WriteRuleHashes(std::string const& pfile);
+
+ void WriteSummary();
+ void WriteSummary(cmGeneratorTarget* target);
+ void FinalizeTargetCompileInfo();
+
+ virtual void ForceLinkerLanguages();
+
+ bool CheckTargetsForMissingSources() const;
+ bool CheckTargetsForType() const;
+ bool CheckTargetsForPchCompilePdb() const;
+
+ void CreateLocalGenerators();
+
+ void CheckCompilerIdCompatibility(cmMakefile* mf,
+ std::string const& lang) const;
+
+ void ComputeBuildFileGenerators();
+
+ std::unique_ptr<cmExternalMakefileProjectGenerator> ExtraGenerator;
+
+ // track files replaced during a Generate
+ std::vector<std::string> FilesReplacedDuringGenerate;
+
+ // Store computed inter-target dependencies.
+ using TargetDependMap = std::map<cmGeneratorTarget const*, TargetDependSet>;
+ TargetDependMap TargetDependencies;
+
+ friend class cmake;
+ void CreateGeneratorTargets(
+ TargetTypes targetTypes, cmMakefile* mf, cmLocalGenerator* lg,
+ std::map<cmTarget*, cmGeneratorTarget*> const& importedMap);
+ void CreateGeneratorTargets(TargetTypes targetTypes);
+
+ void ClearGeneratorMembers();
+
+ bool CheckCMP0037(std::string const& targetName,
+ std::string const& reason) const;
+
+ void IndexMakefile(cmMakefile* mf);
+ void IndexLocalGenerator(cmLocalGenerator* lg);
+
+ virtual const char* GetBuildIgnoreErrorsFlag() const { return nullptr; }
+
+ bool UnsupportedVariableIsDefined(const std::string& name,
+ bool supported) const;
+
+ // Cache directory content and target files to be built.
+ struct DirectoryContent
+ {
+ long LastDiskTime = -1;
+ std::set<std::string> All;
+ std::set<std::string> Generated;
+ };
+ std::map<std::string, DirectoryContent> DirectoryContentMap;
+
+ // Set of binary directories on disk.
+ std::set<std::string> BinaryDirectories;
+
+ // track targets to issue CMP0042 warning for.
+ std::set<std::string> CMP0042WarnTargets;
+ // track targets to issue CMP0068 warning for.
+ std::set<std::string> CMP0068WarnTargets;
+
+ mutable std::map<cmSourceFile*, std::set<cmGeneratorTarget const*>>
+ FilenameTargetDepends;
+
+ std::map<std::string, std::string> RealPaths;
+
+ std::unordered_set<std::string> GeneratedFiles;
+
+#if !defined(CMAKE_BOOTSTRAP)
+ // Pool of file locks
+ cmFileLockPool FileLockPool;
+#endif
+
+protected:
+ float FirstTimeProgress;
+ bool NeedSymbolicMark;
+ bool UseLinkScript;
+ bool ForceUnixPaths;
+ bool ToolSupportsColor;
+ bool InstallTargetEnabled;
+ bool ConfigureDoneCMP0026AndCMP0024;
+};
diff --git a/Source/cmGlobalGeneratorFactory.h b/Source/cmGlobalGeneratorFactory.h
new file mode 100644
index 0000000..d6ababb
--- /dev/null
+++ b/Source/cmGlobalGeneratorFactory.h
@@ -0,0 +1,96 @@
+/* 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 <string>
+#include <vector>
+
+#include <cm/memory>
+
+class cmGlobalGenerator;
+class cmake;
+struct cmDocumentationEntry;
+
+/** \class cmGlobalGeneratorFactory
+ * \brief Responable for creating cmGlobalGenerator instances
+ *
+ * Subclasses of this class generate instances of cmGlobalGenerator.
+ */
+class cmGlobalGeneratorFactory
+{
+public:
+ virtual ~cmGlobalGeneratorFactory() = default;
+
+ /** Create a GlobalGenerator */
+ virtual std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+ const std::string& n, bool allowArch, cmake* cm) const = 0;
+
+ /** Get the documentation entry for this factory */
+ virtual void GetDocumentation(cmDocumentationEntry& entry) const = 0;
+
+ /** Get the names of the current registered generators */
+ virtual std::vector<std::string> GetGeneratorNames() const = 0;
+ virtual std::vector<std::string> GetGeneratorNamesWithPlatform() const = 0;
+
+ /** Determine whether or not this generator supports toolsets */
+ virtual bool SupportsToolset() const = 0;
+
+ /** Determine whether or not this generator supports platforms */
+ virtual bool SupportsPlatform() const = 0;
+
+ /** Get the list of supported platforms name for this generator */
+ virtual std::vector<std::string> GetKnownPlatforms() const = 0;
+
+ /** If the generator supports platforms, get its default. */
+ virtual std::string GetDefaultPlatformName() const = 0;
+};
+
+template <class T>
+class cmGlobalGeneratorSimpleFactory : public cmGlobalGeneratorFactory
+{
+public:
+ /** Create a GlobalGenerator */
+ std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+ const std::string& name, bool /*allowArch*/, cmake* cm) const override
+ {
+ if (name != T::GetActualName()) {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+ return std::unique_ptr<cmGlobalGenerator>(cm::make_unique<T>(cm));
+ }
+
+ /** Get the documentation entry for this factory */
+ void GetDocumentation(cmDocumentationEntry& entry) const override
+ {
+ T::GetDocumentation(entry);
+ }
+
+ /** Get the names of the current registered generators */
+ std::vector<std::string> GetGeneratorNames() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(T::GetActualName());
+ return names;
+ }
+ std::vector<std::string> GetGeneratorNamesWithPlatform() const override
+ {
+ return std::vector<std::string>();
+ }
+
+ /** Determine whether or not this generator supports toolsets */
+ bool SupportsToolset() const override { return T::SupportsToolset(); }
+
+ /** Determine whether or not this generator supports platforms */
+ bool SupportsPlatform() const override { return T::SupportsPlatform(); }
+
+ /** Get the list of supported platforms name for this generator */
+ std::vector<std::string> GetKnownPlatforms() const override
+ {
+ // default is no platform supported
+ return std::vector<std::string>();
+ }
+
+ std::string GetDefaultPlatformName() const override { return std::string(); }
+};
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
new file mode 100644
index 0000000..172cf3f
--- /dev/null
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -0,0 +1,744 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalGhsMultiGenerator.h"
+
+#include <algorithm>
+#include <map>
+#include <ostream>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/string>
+#include <cmext/algorithm>
+
+#include "cmDocumentationEntry.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGhsMultiGpj.h"
+#include "cmLocalGenerator.h"
+#include "cmLocalGhsMultiGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+#include "cmake.h"
+
+const char* cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj";
+#ifdef __linux__
+const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild";
+const char* cmGlobalGhsMultiGenerator::DEFAULT_TOOLSET_ROOT = "/usr/ghs";
+#elif defined(_WIN32)
+const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild.exe";
+const char* cmGlobalGhsMultiGenerator::DEFAULT_TOOLSET_ROOT = "C:/ghs";
+#endif
+
+cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm)
+ : cmGlobalGenerator(cm)
+{
+ cm->GetState()->SetGhsMultiIDE(true);
+}
+
+cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator() = default;
+
+std::unique_ptr<cmLocalGenerator>
+cmGlobalGhsMultiGenerator::CreateLocalGenerator(cmMakefile* mf)
+{
+ return std::unique_ptr<cmLocalGenerator>(
+ cm::make_unique<cmLocalGhsMultiGenerator>(this, mf));
+}
+
+void cmGlobalGhsMultiGenerator::GetDocumentation(cmDocumentationEntry& entry)
+{
+ entry.Name = GetActualName();
+ entry.Brief =
+ "Generates Green Hills MULTI files (experimental, work-in-progress).";
+}
+
+void cmGlobalGhsMultiGenerator::ComputeTargetObjectDirectory(
+ cmGeneratorTarget* gt) const
+{
+ // Compute full path to object file directory for this target.
+ std::string dir =
+ cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(), '/',
+ gt->LocalGenerator->GetTargetDirectory(gt), '/');
+ gt->ObjectDirectory = dir;
+}
+
+bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
+ bool build, cmMakefile* mf)
+{
+ if (build) {
+ return true;
+ }
+ std::string tsp; /* toolset path */
+
+ this->GetToolset(mf, tsp, ts);
+
+ /* no toolset was found */
+ if (tsp.empty()) {
+ return false;
+ }
+ if (ts.empty()) {
+ std::string message;
+ message = cmStrCat(
+ "Green Hills MULTI: -T <toolset> not specified; defaulting to \"", tsp,
+ '"');
+ cmSystemTools::Message(message);
+
+ /* store the full toolset for later use
+ * -- already done if -T<toolset> was specified
+ */
+ mf->AddCacheDefinition("CMAKE_GENERATOR_TOOLSET", tsp,
+ "Location of generator toolset.",
+ cmStateEnums::INTERNAL);
+ }
+
+ /* set the build tool to use */
+ std::string gbuild(tsp + ((tsp.back() == '/') ? "" : "/") +
+ DEFAULT_BUILD_PROGRAM);
+ cmProp prevTool = mf->GetDefinition("CMAKE_MAKE_PROGRAM");
+
+ /* check if the toolset changed from last generate */
+ if (prevTool && (gbuild != *prevTool)) {
+ std::string message =
+ cmStrCat("toolset build tool: ", gbuild,
+ "\nDoes not match the previously used build tool: ", *prevTool,
+ "\nEither remove the CMakeCache.txt file and CMakeFiles "
+ "directory or choose a different binary directory.");
+ cmSystemTools::Error(message);
+ return false;
+ }
+
+ /* store the toolset that is being used for this build */
+ mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild, "build program to use",
+ cmStateEnums::INTERNAL, true);
+
+ mf->AddDefinition("CMAKE_SYSTEM_VERSION", tsp);
+
+ return true;
+}
+
+bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p,
+ cmMakefile* mf)
+{
+ std::string arch;
+ if (p.empty()) {
+ cmSystemTools::Message(
+ "Green Hills MULTI: -A <arch> not specified; defaulting to \"arm\"");
+ arch = "arm";
+
+ /* store the platform name for later use
+ * -- already done if -A<arch> was specified
+ */
+ mf->AddCacheDefinition("CMAKE_GENERATOR_PLATFORM", arch,
+ "Name of generator platform.",
+ cmStateEnums::INTERNAL);
+ } else {
+ arch = p;
+ }
+
+ /* check if OS location has been updated by platform scripts */
+ std::string platform = mf->GetSafeDefinition("GHS_TARGET_PLATFORM");
+ std::string osdir = mf->GetSafeDefinition("GHS_OS_DIR");
+ if (cmIsOff(osdir) && platform.find("integrity") != std::string::npos) {
+ if (!this->CMakeInstance->GetIsInTryCompile()) {
+ /* required OS location is not found */
+ std::string m = cmStrCat(
+ "Green Hills MULTI: GHS_OS_DIR not specified; No OS found in \"",
+ mf->GetSafeDefinition("GHS_OS_ROOT"), '"');
+ cmSystemTools::Message(m);
+ }
+ osdir = "GHS_OS_DIR-NOT-SPECIFIED";
+ } else if (!this->CMakeInstance->GetIsInTryCompile() &&
+ cmIsOff(this->OsDir) && !cmIsOff(osdir)) {
+ /* OS location was updated by auto-selection */
+ std::string m = cmStrCat(
+ "Green Hills MULTI: GHS_OS_DIR not specified; found \"", osdir, '"');
+ cmSystemTools::Message(m);
+ }
+ this->OsDir = osdir;
+
+ // Determine GHS_BSP_NAME
+ std::string bspName = mf->GetSafeDefinition("GHS_BSP_NAME");
+
+ if (cmIsOff(bspName) && platform.find("integrity") != std::string::npos) {
+ bspName = "sim" + arch;
+ /* write back the calculate name for next time */
+ mf->AddCacheDefinition("GHS_BSP_NAME", bspName,
+ "Name of GHS target platform.",
+ cmStateEnums::STRING, true);
+ std::string m = cmStrCat(
+ "Green Hills MULTI: GHS_BSP_NAME not specified; defaulting to \"",
+ bspName, '"');
+ cmSystemTools::Message(m);
+ }
+
+ return true;
+}
+
+void cmGlobalGhsMultiGenerator::EnableLanguage(
+ std::vector<std::string> const& l, cmMakefile* mf, bool optional)
+{
+ mf->AddDefinition("CMAKE_SYSTEM_NAME", "GHS-MULTI");
+
+ mf->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files
+
+ const char* tgtPlatform =
+ cmToCStrSafe(mf->GetDefinition("GHS_TARGET_PLATFORM"));
+ if (!tgtPlatform) {
+ cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not "
+ "specified; defaulting to \"integrity\"");
+ tgtPlatform = "integrity";
+ }
+
+ /* store the platform name for later use */
+ mf->AddCacheDefinition("GHS_TARGET_PLATFORM", tgtPlatform,
+ "Name of GHS target platform.", cmStateEnums::STRING);
+
+ /* store original OS location */
+ this->OsDir = mf->GetSafeDefinition("GHS_OS_DIR");
+
+ this->cmGlobalGenerator::EnableLanguage(l, mf, optional);
+}
+
+bool cmGlobalGhsMultiGenerator::FindMakeProgram(cmMakefile* /*mf*/)
+{
+ // The GHS generator only knows how to lookup its build tool
+ // during generation of the project files, but this
+ // can only be done after the toolset is specified.
+
+ return true;
+}
+
+void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile* mf, std::string& tsd,
+ const std::string& ts)
+{
+ cmProp ghsRoot = mf->GetDefinition("GHS_TOOLSET_ROOT");
+
+ if (cmNonempty(ghsRoot)) {
+ tsd = *ghsRoot;
+ } else {
+ tsd = DEFAULT_TOOLSET_ROOT;
+ }
+
+ if (ts.empty()) {
+ std::vector<std::string> output;
+
+ // Use latest? version
+ if (tsd.back() != '/') {
+ tsd += "/";
+ }
+ cmSystemTools::Glob(tsd, "comp_[^;]+", output);
+
+ if (output.empty()) {
+ std::string msg =
+ "No GHS toolsets found in GHS_TOOLSET_ROOT \"" + tsd + "\".";
+ cmSystemTools::Error(msg);
+ tsd = "";
+ } else {
+ tsd += output.back();
+ }
+ } else {
+ std::string tryPath;
+ tryPath = cmSystemTools::CollapseFullPath(ts, tsd);
+ if (!cmSystemTools::FileExists(tryPath)) {
+ std::string msg = "GHS toolset \"" + tryPath + "\" not found.";
+ cmSystemTools::Error(msg);
+ tsd = "";
+ } else {
+ tsd = tryPath;
+ }
+ }
+}
+
+void cmGlobalGhsMultiGenerator::WriteFileHeader(std::ostream& fout)
+{
+ /* clang-format off */
+ fout << "#!gbuild\n"
+ "#\n"
+ "# CMAKE generated file: DO NOT EDIT!\n"
+ "# Generated by \"" << GetActualName() << "\""
+ " Generator, CMake Version " << cmVersion::GetMajorVersion() << '.'
+ << cmVersion::GetMinorVersion() << "\n"
+ "#\n\n";
+ /* clang-format on */
+}
+
+void cmGlobalGhsMultiGenerator::WriteCustomRuleBOD(std::ostream& fout)
+{
+ fout << "Commands {\n"
+ " Custom_Rule_Command {\n"
+ " name = \"Custom Rule Command\"\n"
+ " exec = \""
+#ifdef _WIN32
+ "cmd.exe"
+#else
+ "/bin/sh"
+#endif
+ "\"\n"
+ " options = {\"SpecialOptions\"}\n"
+ " }\n"
+ "}\n"
+
+ "\n\n"
+ "FileTypes {\n"
+ " CmakeRule {\n"
+ " name = \"Custom Rule\"\n"
+ " action = \"&Run\"\n"
+ " extensions = {\""
+#ifdef _WIN32
+ "bat"
+#else
+ "sh"
+#endif
+ "\"}\n"
+ " grepable = false\n"
+ " command = \"Custom Rule Command\"\n"
+ " commandLine = \"$COMMAND "
+#ifdef _WIN32
+ "/c"
+#endif
+ " $INPUTFILE\"\n"
+ " progress = \"Processing Custom Rule\"\n"
+ " promoteToFirstPass = true\n"
+ " outputType = \"None\"\n"
+ " color = \"#800080\"\n"
+ " }\n"
+ "}\n";
+}
+
+void cmGlobalGhsMultiGenerator::WriteCustomTargetBOD(std::ostream& fout)
+{
+ fout << "FileTypes {\n"
+ " CmakeTarget {\n"
+ " name = \"Custom Target\"\n"
+ " action = \"&Execute\"\n"
+ " grepable = false\n"
+ " outputType = \"None\"\n"
+ " color = \"#800080\"\n"
+ " }\n"
+ "}\n";
+}
+
+void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout,
+ cmLocalGenerator* root)
+{
+ this->WriteFileHeader(fout);
+ this->WriteMacros(fout, root);
+ this->WriteHighLevelDirectives(root, fout);
+ GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fout);
+
+ fout << "# Top Level Project File\n";
+
+ // Specify BSP option if supplied by user
+ cmProp bspName =
+ this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME");
+ if (!cmIsOff(bspName)) {
+ 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)) {
+ 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 << "\"" << this->OsDir << "\"\n";
+ }
+}
+
+void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream& fout,
+ std::string& all_target)
+{
+ fout << "CMakeFiles/" << all_target << " [Project]\n";
+ // All known targets
+ for (cmGeneratorTarget const* target : this->ProjectTargets) {
+ if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
+ target->GetName() != this->GetInstallTargetName())) {
+ continue;
+ }
+ fout << "CMakeFiles/" << target->GetName() + ".tgt" + FILE_EXTENSION
+ << " [Project]\n";
+ }
+}
+
+void cmGlobalGhsMultiGenerator::WriteProjectLine(
+ std::ostream& fout, cmGeneratorTarget const* target, cmLocalGenerator* root,
+ std::string& rootBinaryDir)
+{
+ cmProp projName = target->GetProperty("GENERATOR_FILE_NAME");
+ cmProp projType = target->GetProperty("GENERATOR_FILE_NAME_EXT");
+ if (projName && projType) {
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ std::string dir = lg->GetCurrentBinaryDirectory();
+ dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir);
+ if (dir == ".") {
+ dir.clear();
+ } else {
+ if (dir.back() != '/') {
+ dir += "/";
+ }
+ }
+
+ std::string projFile = dir + *projName + FILE_EXTENSION;
+ fout << projFile;
+ fout << ' ' << *projType << '\n';
+ } else {
+ /* Should never happen */
+ std::string message =
+ "The project file for target [" + target->GetName() + "] is missing.\n";
+ cmSystemTools::Error(message);
+ fout << "{comment} " << target->GetName() << " [missing project file]\n";
+ }
+}
+
+void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator* root)
+{
+ std::string rootBinaryDir =
+ cmStrCat(root->GetCurrentBinaryDirectory(), "/CMakeFiles");
+
+ // All known targets
+ for (cmGeneratorTarget const* target : this->ProjectTargets) {
+ if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
+ target->GetName() != this->GetInstallTargetName())) {
+ continue;
+ }
+
+ // create target build file
+ std::string name = cmStrCat(target->GetName(), ".tgt", FILE_EXTENSION);
+ std::string fname = cmStrCat(rootBinaryDir, "/", name);
+ cmGeneratedFileStream fbld(fname);
+ fbld.SetCopyIfDifferent(true);
+ this->WriteFileHeader(fbld);
+ GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld);
+ std::vector<cmGeneratorTarget const*> build;
+ if (this->ComputeTargetBuildOrder(target, build)) {
+ cmSystemTools::Error(
+ cmStrCat("The inter-target dependency graph for target [",
+ target->GetName(), "] had a cycle.\n"));
+ } else {
+ for (auto& tgt : build) {
+ this->WriteProjectLine(fbld, tgt, root, rootBinaryDir);
+ }
+ }
+ fbld.Close();
+ }
+}
+
+void cmGlobalGhsMultiGenerator::WriteAllTarget(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators,
+ std::string& all_target)
+{
+ this->ProjectTargets.clear();
+
+ // create target build file
+ all_target = root->GetProjectName() + "." + this->GetAllTargetName() +
+ ".tgt" + FILE_EXTENSION;
+ std::string fname =
+ root->GetCurrentBinaryDirectory() + "/CMakeFiles/" + all_target;
+ cmGeneratedFileStream fbld(fname);
+ fbld.SetCopyIfDifferent(true);
+ this->WriteFileHeader(fbld);
+ GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld);
+
+ // Collect all targets under this root generator and the transitive
+ // closure of their dependencies.
+ TargetDependSet projectTargets;
+ TargetDependSet originalTargets;
+ this->GetTargetSets(projectTargets, originalTargets, root, generators);
+ OrderedTargetDependSet sortedProjectTargets(projectTargets, "");
+ std::vector<cmGeneratorTarget const*> defaultTargets;
+ for (cmGeneratorTarget const* t : sortedProjectTargets) {
+ /* save list of all targets in sorted order */
+ this->ProjectTargets.push_back(t);
+ }
+ for (cmGeneratorTarget const* t : sortedProjectTargets) {
+ if (!t->IsInBuildSystem()) {
+ continue;
+ }
+ if (!this->IsExcluded(t->GetLocalGenerator(), t)) {
+ defaultTargets.push_back(t);
+ }
+ }
+ std::vector<cmGeneratorTarget const*> build;
+ if (this->ComputeTargetBuildOrder(defaultTargets, build)) {
+ std::string message = "The inter-target dependency graph for project [" +
+ root->GetProjectName() + "] had a cycle.\n";
+ cmSystemTools::Error(message);
+ } else {
+ // determine the targets for ALL target
+ std::string rootBinaryDir =
+ cmStrCat(root->GetCurrentBinaryDirectory(), "/CMakeFiles");
+ for (cmGeneratorTarget const* target : build) {
+ if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ target->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ continue;
+ }
+ this->WriteProjectLine(fbld, target, root, rootBinaryDir);
+ }
+ }
+ fbld.Close();
+}
+
+void cmGlobalGhsMultiGenerator::Generate()
+{
+ std::string fname;
+
+ // first do the superclass method
+ this->cmGlobalGenerator::Generate();
+
+ // output top-level projects
+ for (auto& it : this->ProjectMap) {
+ this->OutputTopLevelProject(it.second[0], it.second);
+ }
+
+ // create custom rule BOD file
+ fname = this->GetCMakeInstance()->GetHomeOutputDirectory() +
+ "/CMakeFiles/custom_rule.bod";
+ cmGeneratedFileStream frule(fname);
+ frule.SetCopyIfDifferent(true);
+ this->WriteFileHeader(frule);
+ this->WriteCustomRuleBOD(frule);
+ frule.Close();
+
+ // create custom target BOD file
+ fname = this->GetCMakeInstance()->GetHomeOutputDirectory() +
+ "/CMakeFiles/custom_target.bod";
+ cmGeneratedFileStream ftarget(fname);
+ ftarget.SetCopyIfDifferent(true);
+ this->WriteFileHeader(ftarget);
+ this->WriteCustomTargetBOD(ftarget);
+ ftarget.Close();
+}
+
+void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
+{
+ std::string fname;
+ std::string all_target;
+
+ if (generators.empty()) {
+ return;
+ }
+
+ /* Name top-level projects as filename.top.gpj to avoid name clashes
+ * with target projects. This avoid the issue where the project has
+ * the same name as the executable target.
+ */
+ fname = cmStrCat(root->GetCurrentBinaryDirectory(), '/',
+ root->GetProjectName(), ".top", FILE_EXTENSION);
+
+ cmGeneratedFileStream top(fname);
+ top.SetCopyIfDifferent(true);
+ this->WriteTopLevelProject(top, root);
+
+ this->WriteAllTarget(root, generators, all_target);
+ this->WriteTargets(root);
+
+ this->WriteSubProjects(top, all_target);
+ top.Close();
+}
+
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalGhsMultiGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& /*config*/, bool /*fast*/, int jobs, bool /*verbose*/,
+ std::vector<std::string> const& makeOptions)
+{
+ GeneratedMakeCommand makeCommand = {};
+ std::string gbuild;
+ if (cmProp gbuildCached =
+ this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM")) {
+ gbuild = *gbuildCached;
+ }
+ makeCommand.Add(this->SelectMakeProgram(makeProgram, gbuild));
+
+ if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
+ makeCommand.Add("-parallel");
+ if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
+ makeCommand.Add(std::to_string(jobs));
+ }
+ }
+
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+
+ /* determine which top-project file to use */
+ std::string proj = projectName + ".top" + FILE_EXTENSION;
+ std::vector<std::string> files;
+ cmSystemTools::Glob(projectDir, ".*\\.top\\.gpj", files);
+ if (!files.empty()) {
+ /* if multiple top-projects are found in build directory
+ * then prefer projectName top-project.
+ */
+ if (!cm::contains(files, proj)) {
+ proj = files.at(0);
+ }
+ }
+
+ makeCommand.Add("-top", proj);
+ if (!targetNames.empty()) {
+ if (cm::contains(targetNames, "clean")) {
+ makeCommand.Add("-clean");
+ } else {
+ for (const auto& tname : targetNames) {
+ if (!tname.empty()) {
+ makeCommand.Add(tname + ".tgt.gpj");
+ }
+ }
+ }
+ } else {
+ /* transform name to default build */;
+ std::string all = proj;
+ all.replace(all.end() - 7, all.end(),
+ std::string(this->GetAllTargetName()) + ".tgt.gpj");
+ makeCommand.Add(all);
+ }
+ return { makeCommand };
+}
+
+void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout,
+ cmLocalGenerator* root)
+{
+ fout << "macro PROJ_NAME=" << root->GetProjectName() << '\n';
+ cmProp ghsGpjMacros =
+ this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS");
+ if (ghsGpjMacros) {
+ std::vector<std::string> expandedList = cmExpandedList(*ghsGpjMacros);
+ for (std::string const& arg : expandedList) {
+ fout << "macro " << arg << '\n';
+ }
+ }
+}
+
+void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(
+ cmLocalGenerator* root, std::ostream& fout)
+{
+ /* set primary target */
+ std::string tgt;
+ cmProp t =
+ this->GetCMakeInstance()->GetCacheDefinition("GHS_PRIMARY_TARGET");
+ if (cmNonempty(t)) {
+ tgt = *t;
+ this->GetCMakeInstance()->MarkCliAsUsed("GHS_PRIMARY_TARGET");
+ } else {
+ cmProp a =
+ this->GetCMakeInstance()->GetCacheDefinition("CMAKE_GENERATOR_PLATFORM");
+ cmProp p =
+ this->GetCMakeInstance()->GetCacheDefinition("GHS_TARGET_PLATFORM");
+ tgt = cmStrCat((a ? *a : ""), '_', (p ? *p : ""), ".tgt");
+ }
+
+ /* clang-format off */
+ fout << "primaryTarget=" << tgt << "\n"
+ "customization=" << root->GetBinaryDirectory()
+ << "/CMakeFiles/custom_rule.bod\n"
+ "customization=" << root->GetBinaryDirectory()
+ << "/CMakeFiles/custom_target.bod" << '\n';
+ /* clang-format on */
+
+ cmProp const customization =
+ this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION");
+ if (cmNonempty(customization)) {
+ fout << "customization="
+ << cmGlobalGhsMultiGenerator::TrimQuotes(*customization) << '\n';
+ this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
+ }
+}
+
+std::string cmGlobalGhsMultiGenerator::TrimQuotes(std::string str)
+{
+ cm::erase(str, '"');
+ return str;
+}
+
+bool cmGlobalGhsMultiGenerator::TargetCompare::operator()(
+ cmGeneratorTarget const* l, cmGeneratorTarget const* r) const
+{
+ // Make sure a given named target is ordered first,
+ // e.g. to set ALL_BUILD as the default active project.
+ // When the empty string is named this is a no-op.
+ if (r->GetName() == this->First) {
+ return false;
+ }
+ if (l->GetName() == this->First) {
+ return true;
+ }
+ return l->GetName() < r->GetName();
+}
+
+cmGlobalGhsMultiGenerator::OrderedTargetDependSet::OrderedTargetDependSet(
+ TargetDependSet const& targets, std::string const& first)
+ : derived(TargetCompare(first))
+{
+ this->insert(targets.begin(), targets.end());
+}
+
+bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
+ cmGeneratorTarget const* tgt, std::vector<cmGeneratorTarget const*>& build)
+{
+ std::vector<cmGeneratorTarget const*> t{ tgt };
+ return this->ComputeTargetBuildOrder(t, build);
+}
+
+bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
+ std::vector<cmGeneratorTarget const*>& tgt,
+ std::vector<cmGeneratorTarget const*>& build)
+{
+ std::set<cmGeneratorTarget const*> temp;
+ std::set<cmGeneratorTarget const*> perm;
+
+ for (const auto* const ti : tgt) {
+ bool r = this->VisitTarget(temp, perm, build, ti);
+ if (r) {
+ return r;
+ }
+ }
+ return false;
+}
+
+bool cmGlobalGhsMultiGenerator::VisitTarget(
+ std::set<cmGeneratorTarget const*>& temp,
+ std::set<cmGeneratorTarget const*>& perm,
+ std::vector<cmGeneratorTarget const*>& order, cmGeneratorTarget const* ti)
+{
+ /* check if permanent mark is set*/
+ if (perm.find(ti) == perm.end()) {
+ /* set temporary mark; check if revisit*/
+ if (temp.insert(ti).second) {
+ /* sort targets lexicographically to ensure that nodes are always visited
+ * in the same order */
+ OrderedTargetDependSet sortedTargets(this->GetTargetDirectDepends(ti),
+ "");
+ for (auto const& di : sortedTargets) {
+ if (this->VisitTarget(temp, perm, order, di)) {
+ return true;
+ }
+ }
+ /* mark as complete; insert into beginning of list*/
+ perm.insert(ti);
+ order.push_back(ti);
+ return false;
+ }
+ /* revisiting item - not a DAG */
+ return true;
+ }
+ /* already complete */
+ return false;
+}
diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h
new file mode 100644
index 0000000..7753b31
--- /dev/null
+++ b/Source/cmGlobalGhsMultiGenerator.h
@@ -0,0 +1,159 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <iosfwd>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmGlobalGenerator.h"
+#include "cmGlobalGeneratorFactory.h"
+#include "cmTargetDepend.h"
+
+class cmGeneratorTarget;
+class cmLocalGenerator;
+class cmMakefile;
+class cmake;
+struct cmDocumentationEntry;
+
+class cmGlobalGhsMultiGenerator : public cmGlobalGenerator
+{
+public:
+ // The default filename extension of GHS MULTI's build files.
+ static const char* FILE_EXTENSION;
+
+ cmGlobalGhsMultiGenerator(cmake* cm);
+ ~cmGlobalGhsMultiGenerator() override;
+
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
+ {
+ return std::unique_ptr<cmGlobalGeneratorFactory>(
+ new cmGlobalGeneratorSimpleFactory<cmGlobalGhsMultiGenerator>());
+ }
+
+ //! create the correct local generator
+ std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+ cmMakefile* mf) override;
+
+ /// @return the name of this generator.
+ static std::string GetActualName() { return "Green Hills MULTI"; }
+
+ //! Get the name for this generator
+ std::string GetName() const override { return GetActualName(); }
+
+ /// Overloaded methods. @see cmGlobalGenerator::GetDocumentation()
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ /**
+ * Utilized by the generator factory to determine if this generator
+ * supports toolsets.
+ */
+ static bool SupportsToolset() { return true; }
+
+ /**
+ * Utilized by the generator factory to determine if this generator
+ * supports platforms.
+ */
+ static bool SupportsPlatform() { return true; }
+
+ // Toolset / Platform Support
+ bool SetGeneratorToolset(std::string const& ts, bool build,
+ cmMakefile* mf) override;
+ bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override;
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) override;
+ /*
+ * Determine what program to use for building the project.
+ */
+ bool FindMakeProgram(cmMakefile* mf) override;
+
+ void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;
+
+ // Write the common disclaimer text at the top of each build file.
+ void WriteFileHeader(std::ostream& fout);
+
+ const char* GetInstallTargetName() const override { return "install"; }
+
+protected:
+ void Generate() override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
+
+private:
+ void GetToolset(cmMakefile* mf, std::string& tsd, const std::string& ts);
+
+ /* top-level project */
+ void OutputTopLevelProject(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators);
+ void WriteTopLevelProject(std::ostream& fout, cmLocalGenerator* root);
+ void WriteMacros(std::ostream& fout, cmLocalGenerator* root);
+ void WriteHighLevelDirectives(cmLocalGenerator* root, std::ostream& fout);
+ void WriteSubProjects(std::ostream& fout, std::string& all_target);
+ void WriteTargets(cmLocalGenerator* root);
+ void WriteProjectLine(std::ostream& fout, cmGeneratorTarget const* target,
+ cmLocalGenerator* root, std::string& rootBinaryDir);
+ void WriteCustomRuleBOD(std::ostream& fout);
+ void WriteCustomTargetBOD(std::ostream& fout);
+ void WriteAllTarget(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators,
+ std::string& all_target);
+
+ static std::string TrimQuotes(std::string str);
+
+ std::string OsDir;
+ static const char* DEFAULT_BUILD_PROGRAM;
+ static const char* DEFAULT_TOOLSET_ROOT;
+
+ bool ComputeTargetBuildOrder(cmGeneratorTarget const* tgt,
+ std::vector<cmGeneratorTarget const*>& build);
+ bool ComputeTargetBuildOrder(std::vector<cmGeneratorTarget const*>& tgt,
+ std::vector<cmGeneratorTarget const*>& build);
+ bool VisitTarget(std::set<cmGeneratorTarget const*>& temp,
+ std::set<cmGeneratorTarget const*>& perm,
+ std::vector<cmGeneratorTarget const*>& order,
+ cmGeneratorTarget const* ti);
+
+ std::vector<cmGeneratorTarget const*> ProjectTargets;
+
+ // Target sorting
+ class TargetSet : public std::set<cmGeneratorTarget const*>
+ {
+ };
+ class TargetCompare
+ {
+ std::string First;
+
+ public:
+ TargetCompare(std::string first)
+ : First(std::move(first))
+ {
+ }
+ bool operator()(cmGeneratorTarget const* l,
+ cmGeneratorTarget const* r) const;
+ };
+ class OrderedTargetDependSet;
+};
+
+class cmGlobalGhsMultiGenerator::OrderedTargetDependSet
+ : public std::multiset<cmTargetDepend,
+ cmGlobalGhsMultiGenerator::TargetCompare>
+{
+ using derived =
+ std::multiset<cmTargetDepend, cmGlobalGhsMultiGenerator::TargetCompare>;
+
+public:
+ using TargetDependSet = cmGlobalGenerator::TargetDependSet;
+ OrderedTargetDependSet(TargetDependSet const&, std::string const& first);
+};
diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx
new file mode 100644
index 0000000..fc3123a
--- /dev/null
+++ b/Source/cmGlobalJOMMakefileGenerator.cxx
@@ -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. */
+#include "cmGlobalJOMMakefileGenerator.h"
+
+#include "cmDocumentationEntry.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmState.h"
+#include "cmake.h"
+
+cmGlobalJOMMakefileGenerator::cmGlobalJOMMakefileGenerator(cmake* cm)
+ : cmGlobalUnixMakefileGenerator3(cm)
+{
+ this->FindMakeProgramFile = "CMakeJOMFindMake.cmake";
+ this->ForceUnixPaths = false;
+ this->ToolSupportsColor = true;
+ this->UseLinkScript = false;
+ cm->GetState()->SetWindowsShell(true);
+ cm->GetState()->SetNMake(true);
+ this->DefineWindowsNULL = true;
+ this->PassMakeflags = true;
+ this->UnixCD = false;
+ this->MakeSilentFlag = "/nologo";
+}
+
+void cmGlobalJOMMakefileGenerator::EnableLanguage(
+ std::vector<std::string> const& l, cmMakefile* mf, bool optional)
+{
+ // pick a default
+ mf->AddDefinition("CMAKE_GENERATOR_CC", "cl");
+ mf->AddDefinition("CMAKE_GENERATOR_CXX", "cl");
+ this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
+}
+
+void cmGlobalJOMMakefileGenerator::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalJOMMakefileGenerator::GetActualName();
+ entry.Brief = "Generates JOM makefiles.";
+}
+
+void cmGlobalJOMMakefileGenerator::PrintCompilerAdvice(
+ std::ostream& os, std::string const& lang, const char* envVar) const
+{
+ if (lang == "CXX" || lang == "C") {
+ /* clang-format off */
+ os <<
+ "To use the JOM generator with Visual C++, cmake must be run from a "
+ "shell that can use the compiler cl from the command line. This "
+ "environment is unable to invoke the cl compiler. To fix this problem, "
+ "run cmake from the Visual Studio Command Prompt (vcvarsall.bat).\n";
+ /* clang-format on */
+ }
+ this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
+}
+
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions)
+{
+ std::vector<std::string> jomMakeOptions;
+
+ // Since we have full control over the invocation of JOM, let us
+ // make it quiet.
+ jomMakeOptions.push_back(this->MakeSilentFlag);
+ cm::append(jomMakeOptions, makeOptions);
+
+ // JOM does parallel builds by default, the -j is only needed if a specific
+ // number is given
+ // see https://github.com/qt-labs/jom/blob/v1.1.2/src/jomlib/options.cpp
+ if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
+ jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
+ }
+
+ return cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast, jobs,
+ verbose, jomMakeOptions);
+}
diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h
new file mode 100644
index 0000000..2d58f91
--- /dev/null
+++ b/Source/cmGlobalJOMMakefileGenerator.h
@@ -0,0 +1,54 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <iosfwd>
+#include <memory>
+
+#include "cmGlobalUnixMakefileGenerator3.h"
+
+/** \class cmGlobalJOMMakefileGenerator
+ * \brief Write a JOM makefiles.
+ *
+ * cmGlobalJOMMakefileGenerator manages nmake build process for a tree
+ */
+class cmGlobalJOMMakefileGenerator : public cmGlobalUnixMakefileGenerator3
+{
+public:
+ cmGlobalJOMMakefileGenerator(cmake* cm);
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
+ {
+ return std::unique_ptr<cmGlobalGeneratorFactory>(
+ new cmGlobalGeneratorSimpleFactory<cmGlobalJOMMakefileGenerator>());
+ }
+ //! Get the name for the generator.
+ std::string GetName() const override
+ {
+ return cmGlobalJOMMakefileGenerator::GetActualName();
+ }
+ // use NMake Makefiles in the name so that scripts/tests that depend on the
+ // name NMake Makefiles will work
+ static std::string GetActualName() { return "NMake Makefiles JOM"; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) override;
+
+protected:
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
+
+private:
+ void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
+ const char* envVar) const override;
+};
diff --git a/Source/cmGlobalMSYSMakefileGenerator.cxx b/Source/cmGlobalMSYSMakefileGenerator.cxx
new file mode 100644
index 0000000..ae9d5a7
--- /dev/null
+++ b/Source/cmGlobalMSYSMakefileGenerator.cxx
@@ -0,0 +1,88 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalMSYSMakefileGenerator.h"
+
+#include "cmsys/FStream.hxx"
+
+#include "cmDocumentationEntry.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmState.h"
+#include "cmake.h"
+
+cmGlobalMSYSMakefileGenerator::cmGlobalMSYSMakefileGenerator(cmake* cm)
+ : cmGlobalUnixMakefileGenerator3(cm)
+{
+ this->FindMakeProgramFile = "CMakeMSYSFindMake.cmake";
+ this->ForceUnixPaths = true;
+ this->ToolSupportsColor = true;
+ this->UseLinkScript = false;
+ cm->GetState()->SetMSYSShell(true);
+}
+
+std::string cmGlobalMSYSMakefileGenerator::FindMinGW(
+ std::string const& makeloc)
+{
+ std::string fstab = cmStrCat(makeloc, "/../etc/fstab");
+ cmsys::ifstream fin(fstab.c_str());
+ std::string path;
+ std::string mount;
+ std::string mingwBin;
+ while (fin) {
+ fin >> path;
+ fin >> mount;
+ if (mount == "/mingw") {
+ mingwBin = cmStrCat(path, "/bin");
+ }
+ }
+ return mingwBin;
+}
+
+void cmGlobalMSYSMakefileGenerator::EnableLanguage(
+ std::vector<std::string> const& l, cmMakefile* mf, bool optional)
+{
+ this->FindMakeProgram(mf);
+ const std::string& makeProgram =
+ mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ std::vector<std::string> locations;
+ std::string makeloc = cmSystemTools::GetProgramPath(makeProgram);
+ locations.push_back(this->FindMinGW(makeloc));
+ locations.push_back(makeloc);
+ locations.push_back("/mingw/bin");
+ locations.push_back("c:/mingw/bin");
+ std::string tgcc = cmSystemTools::FindProgram("gcc", locations);
+ std::string gcc = "gcc.exe";
+ if (!tgcc.empty()) {
+ gcc = tgcc;
+ }
+ std::string tgxx = cmSystemTools::FindProgram("g++", locations);
+ std::string gxx = "g++.exe";
+ if (!tgxx.empty()) {
+ gxx = tgxx;
+ }
+ std::string trc = cmSystemTools::FindProgram("windres", locations);
+ std::string rc = "windres.exe";
+ if (!trc.empty()) {
+ rc = trc;
+ }
+ mf->AddDefinition("MSYS", "1");
+ mf->AddDefinition("CMAKE_GENERATOR_CC", gcc);
+ mf->AddDefinition("CMAKE_GENERATOR_CXX", gxx);
+ mf->AddDefinition("CMAKE_GENERATOR_RC", rc);
+ this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
+
+ if (!mf->IsSet("CMAKE_AR") && !this->CMakeInstance->GetIsInTryCompile() &&
+ !(1 == l.size() && l[0] == "NONE")) {
+ cmSystemTools::Error(
+ "CMAKE_AR was not found, please set to archive program. " +
+ mf->GetSafeDefinition("CMAKE_AR"));
+ }
+}
+
+void cmGlobalMSYSMakefileGenerator::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalMSYSMakefileGenerator::GetActualName();
+ entry.Brief = "Generates MSYS makefiles.";
+}
diff --git a/Source/cmGlobalMSYSMakefileGenerator.h b/Source/cmGlobalMSYSMakefileGenerator.h
new file mode 100644
index 0000000..1a47b4f
--- /dev/null
+++ b/Source/cmGlobalMSYSMakefileGenerator.h
@@ -0,0 +1,43 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <memory>
+
+#include "cmGlobalUnixMakefileGenerator3.h"
+
+/** \class cmGlobalMSYSMakefileGenerator
+ * \brief Write a NMake makefiles.
+ *
+ * cmGlobalMSYSMakefileGenerator manages nmake build process for a tree
+ */
+class cmGlobalMSYSMakefileGenerator : public cmGlobalUnixMakefileGenerator3
+{
+public:
+ cmGlobalMSYSMakefileGenerator(cmake* cm);
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
+ {
+ return std::unique_ptr<cmGlobalGeneratorFactory>(
+ new cmGlobalGeneratorSimpleFactory<cmGlobalMSYSMakefileGenerator>());
+ }
+
+ //! Get the name for the generator.
+ virtual std::string GetName() const
+ {
+ return cmGlobalMSYSMakefileGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "MSYS Makefiles"; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+
+private:
+ std::string FindMinGW(std::string const& makeloc);
+};
diff --git a/Source/cmGlobalMinGWMakefileGenerator.cxx b/Source/cmGlobalMinGWMakefileGenerator.cxx
new file mode 100644
index 0000000..d9fc505
--- /dev/null
+++ b/Source/cmGlobalMinGWMakefileGenerator.cxx
@@ -0,0 +1,58 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalMinGWMakefileGenerator.h"
+
+#include "cmDocumentationEntry.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmState.h"
+#include "cmake.h"
+
+cmGlobalMinGWMakefileGenerator::cmGlobalMinGWMakefileGenerator(cmake* cm)
+ : cmGlobalUnixMakefileGenerator3(cm)
+{
+ this->FindMakeProgramFile = "CMakeMinGWFindMake.cmake";
+ this->ForceUnixPaths = true;
+ this->ToolSupportsColor = true;
+ this->UseLinkScript = true;
+ cm->GetState()->SetWindowsShell(true);
+ cm->GetState()->SetMinGWMake(true);
+}
+
+void cmGlobalMinGWMakefileGenerator::EnableLanguage(
+ std::vector<std::string> const& l, cmMakefile* mf, bool optional)
+{
+ this->FindMakeProgram(mf);
+ const std::string& makeProgram =
+ mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ std::vector<std::string> locations;
+ locations.push_back(cmSystemTools::GetProgramPath(makeProgram));
+ locations.push_back("/mingw/bin");
+ locations.push_back("c:/mingw/bin");
+ std::string tgcc = cmSystemTools::FindProgram("gcc", locations);
+ std::string gcc = "gcc.exe";
+ if (!tgcc.empty()) {
+ gcc = tgcc;
+ }
+ std::string tgxx = cmSystemTools::FindProgram("g++", locations);
+ std::string gxx = "g++.exe";
+ if (!tgxx.empty()) {
+ gxx = tgxx;
+ }
+ std::string trc = cmSystemTools::FindProgram("windres", locations);
+ std::string rc = "windres.exe";
+ if (!trc.empty()) {
+ rc = trc;
+ }
+ mf->AddDefinition("CMAKE_GENERATOR_CC", gcc);
+ mf->AddDefinition("CMAKE_GENERATOR_CXX", gxx);
+ mf->AddDefinition("CMAKE_GENERATOR_RC", rc);
+ this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
+}
+
+void cmGlobalMinGWMakefileGenerator::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalMinGWMakefileGenerator::GetActualName();
+ entry.Brief = "Generates a make file for use with mingw32-make.";
+}
diff --git a/Source/cmGlobalMinGWMakefileGenerator.h b/Source/cmGlobalMinGWMakefileGenerator.h
new file mode 100644
index 0000000..ffc9ebe
--- /dev/null
+++ b/Source/cmGlobalMinGWMakefileGenerator.h
@@ -0,0 +1,39 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <memory>
+
+#include "cmGlobalUnixMakefileGenerator3.h"
+
+/** \class cmGlobalMinGWMakefileGenerator
+ * \brief Write a NMake makefiles.
+ *
+ * cmGlobalMinGWMakefileGenerator manages nmake build process for a tree
+ */
+class cmGlobalMinGWMakefileGenerator : public cmGlobalUnixMakefileGenerator3
+{
+public:
+ cmGlobalMinGWMakefileGenerator(cmake* cm);
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
+ {
+ return std::unique_ptr<cmGlobalGeneratorFactory>(
+ new cmGlobalGeneratorSimpleFactory<cmGlobalMinGWMakefileGenerator>());
+ }
+ //! Get the name for the generator.
+ virtual std::string GetName() const
+ {
+ return cmGlobalMinGWMakefileGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "MinGW Makefiles"; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ virtual void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile*, bool optional);
+};
diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx
new file mode 100644
index 0000000..36f583f
--- /dev/null
+++ b/Source/cmGlobalNMakeMakefileGenerator.cxx
@@ -0,0 +1,94 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalNMakeMakefileGenerator.h"
+
+#include "cmDocumentationEntry.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmState.h"
+#include "cmake.h"
+
+cmGlobalNMakeMakefileGenerator::cmGlobalNMakeMakefileGenerator(cmake* cm)
+ : cmGlobalUnixMakefileGenerator3(cm)
+{
+ this->FindMakeProgramFile = "CMakeNMakeFindMake.cmake";
+ this->ForceUnixPaths = false;
+ this->ToolSupportsColor = true;
+ this->UseLinkScript = false;
+ cm->GetState()->SetWindowsShell(true);
+ cm->GetState()->SetNMake(true);
+ this->DefineWindowsNULL = true;
+ this->PassMakeflags = true;
+ this->UnixCD = false;
+ this->MakeSilentFlag = "/nologo";
+ // nmake breaks on '!' in long-line dependencies
+ this->ToolSupportsLongLineDependencies = false;
+}
+
+void cmGlobalNMakeMakefileGenerator::EnableLanguage(
+ std::vector<std::string> const& l, cmMakefile* mf, bool optional)
+{
+ // pick a default
+ mf->AddDefinition("CMAKE_GENERATOR_CC", "cl");
+ mf->AddDefinition("CMAKE_GENERATOR_CXX", "cl");
+ this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
+}
+
+void cmGlobalNMakeMakefileGenerator::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalNMakeMakefileGenerator::GetActualName();
+ entry.Brief = "Generates NMake makefiles.";
+}
+
+void cmGlobalNMakeMakefileGenerator::PrintCompilerAdvice(
+ std::ostream& os, std::string const& lang, const char* envVar) const
+{
+ if (lang == "CXX" || lang == "C") {
+ /* clang-format off */
+ os <<
+ "To use the NMake generator with Visual C++, cmake must be run from a "
+ "shell that can use the compiler cl from the command line. This "
+ "environment is unable to invoke the cl compiler. To fix this problem, "
+ "run cmake from the Visual Studio Command Prompt (vcvarsall.bat).\n";
+ /* clang-format on */
+ }
+ this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
+}
+
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int /*jobs*/, bool verbose,
+ std::vector<std::string> const& makeOptions)
+{
+ std::vector<std::string> nmakeMakeOptions;
+
+ // Since we have full control over the invocation of nmake, let us
+ // make it quiet.
+ nmakeMakeOptions.push_back(this->MakeSilentFlag);
+ cm::append(nmakeMakeOptions, makeOptions);
+
+ return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast,
+ cmake::NO_BUILD_PARALLEL_LEVEL, verbose, nmakeMakeOptions);
+}
+
+void cmGlobalNMakeMakefileGenerator::PrintBuildCommandAdvice(std::ostream& os,
+ int jobs) const
+{
+ if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
+ // nmake does not support parallel build level
+ // see https://msdn.microsoft.com/en-us/library/afyyse50.aspx
+
+ /* clang-format off */
+ os <<
+ "Warning: NMake does not support parallel builds. "
+ "Ignoring parallel build command line option.\n";
+ /* clang-format on */
+ }
+
+ this->cmGlobalUnixMakefileGenerator3::PrintBuildCommandAdvice(
+ os, cmake::NO_BUILD_PARALLEL_LEVEL);
+}
diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h
new file mode 100644
index 0000000..abe64ff
--- /dev/null
+++ b/Source/cmGlobalNMakeMakefileGenerator.h
@@ -0,0 +1,60 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <iosfwd>
+#include <memory>
+
+#include "cmGlobalUnixMakefileGenerator3.h"
+
+/** \class cmGlobalNMakeMakefileGenerator
+ * \brief Write a NMake makefiles.
+ *
+ * cmGlobalNMakeMakefileGenerator manages nmake build process for a tree
+ */
+class cmGlobalNMakeMakefileGenerator : public cmGlobalUnixMakefileGenerator3
+{
+public:
+ cmGlobalNMakeMakefileGenerator(cmake* cm);
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
+ {
+ return std::unique_ptr<cmGlobalGeneratorFactory>(
+ new cmGlobalGeneratorSimpleFactory<cmGlobalNMakeMakefileGenerator>());
+ }
+ //! Get the name for the generator.
+ std::string GetName() const override
+ {
+ return cmGlobalNMakeMakefileGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "NMake Makefiles"; }
+
+ /** Get encoding used by generator for makefile files */
+ codecvt::Encoding GetMakefileEncoding() const override
+ {
+ return codecvt::ANSI;
+ }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) override;
+
+protected:
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
+
+ void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
+
+private:
+ void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
+ const char* envVar) const override;
+};
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
new file mode 100644
index 0000000..6937639
--- /dev/null
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -0,0 +1,2918 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalNinjaGenerator.h"
+
+#include <algorithm>
+#include <cctype>
+#include <cstdio>
+#include <sstream>
+
+#include <cm/iterator>
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/algorithm>
+#include <cmext/memory>
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+#include <cm3p/json/writer.h>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmDocumentationEntry.h"
+#include "cmFortranParser.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpressionEvaluationFile.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLinkLineComputer.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmLocalNinjaGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmNinjaLinkLineComputer.h"
+#include "cmOutputConverter.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmScanDepFormat.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetDepend.h"
+#include "cmVersion.h"
+#include "cmake.h"
+
+const char* cmGlobalNinjaGenerator::NINJA_BUILD_FILE = "build.ninja";
+const char* cmGlobalNinjaGenerator::NINJA_RULES_FILE =
+ "CMakeFiles/rules.ninja";
+const char* cmGlobalNinjaGenerator::INDENT = " ";
+#ifdef _WIN32
+std::string const cmGlobalNinjaGenerator::SHELL_NOOP = "cd .";
+#else
+std::string const cmGlobalNinjaGenerator::SHELL_NOOP = ":";
+#endif
+
+bool operator==(
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+ return lhs.Target == rhs.Target && lhs.Config == rhs.Config &&
+ lhs.GenexOutput == rhs.GenexOutput;
+}
+
+bool operator!=(
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+ return !(lhs == rhs);
+}
+
+bool operator<(
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+ return lhs.Target < rhs.Target ||
+ (lhs.Target == rhs.Target &&
+ (lhs.Config < rhs.Config ||
+ (lhs.Config == rhs.Config && lhs.GenexOutput < rhs.GenexOutput)));
+}
+
+bool operator>(
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+ return rhs < lhs;
+}
+
+bool operator<=(
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+ return !(lhs > rhs);
+}
+
+bool operator>=(
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+ return rhs <= lhs;
+}
+
+void cmGlobalNinjaGenerator::Indent(std::ostream& os, int count)
+{
+ for (int i = 0; i < count; ++i) {
+ os << cmGlobalNinjaGenerator::INDENT;
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteDivider(std::ostream& os)
+{
+ os << "# ======================================"
+ "=======================================\n";
+}
+
+void cmGlobalNinjaGenerator::WriteComment(std::ostream& os,
+ const std::string& comment)
+{
+ if (comment.empty()) {
+ return;
+ }
+
+ std::string::size_type lpos = 0;
+ std::string::size_type rpos;
+ os << "\n#############################################\n";
+ while ((rpos = comment.find('\n', lpos)) != std::string::npos) {
+ os << "# " << comment.substr(lpos, rpos - lpos) << "\n";
+ lpos = rpos + 1;
+ }
+ os << "# " << comment.substr(lpos) << "\n\n";
+}
+
+std::unique_ptr<cmLinkLineComputer>
+cmGlobalNinjaGenerator::CreateLinkLineComputer(
+ cmOutputConverter* outputConverter,
+ cmStateDirectory const& /* stateDir */) const
+{
+ return std::unique_ptr<cmLinkLineComputer>(
+ cm::make_unique<cmNinjaLinkLineComputer>(
+ outputConverter,
+ this->LocalGenerators[0]->GetStateSnapshot().GetDirectory(), this));
+}
+
+std::string cmGlobalNinjaGenerator::EncodeRuleName(std::string const& name)
+{
+ // Ninja rule names must match "[a-zA-Z0-9_.-]+". Use ".xx" to encode
+ // "." and all invalid characters as hexadecimal.
+ std::string encoded;
+ for (char i : name) {
+ if (isalnum(i) || i == '_' || i == '-') {
+ encoded += i;
+ } else {
+ char buf[16];
+ sprintf(buf, ".%02x", static_cast<unsigned int>(i));
+ encoded += buf;
+ }
+ }
+ return encoded;
+}
+
+std::string cmGlobalNinjaGenerator::EncodeLiteral(const std::string& lit)
+{
+ std::string result = lit;
+ cmSystemTools::ReplaceString(result, "$", "$$");
+ cmSystemTools::ReplaceString(result, "\n", "$\n");
+ if (this->IsMultiConfig()) {
+ cmSystemTools::ReplaceString(result,
+ cmStrCat('$', this->GetCMakeCFGIntDir()),
+ this->GetCMakeCFGIntDir());
+ }
+ return result;
+}
+
+std::string cmGlobalNinjaGenerator::EncodePath(const std::string& path)
+{
+ std::string result = path;
+#ifdef _WIN32
+ if (this->IsGCCOnWindows())
+ std::replace(result.begin(), result.end(), '\\', '/');
+ else
+ std::replace(result.begin(), result.end(), '/', '\\');
+#endif
+ result = this->EncodeLiteral(result);
+ cmSystemTools::ReplaceString(result, " ", "$ ");
+ cmSystemTools::ReplaceString(result, ":", "$:");
+ return result;
+}
+
+void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
+ cmNinjaBuild const& build,
+ int cmdLineLimit,
+ bool* usedResponseFile)
+{
+ // Make sure there is a rule.
+ if (build.Rule.empty()) {
+ cmSystemTools::Error(cmStrCat(
+ "No rule for WriteBuild! called with comment: ", build.Comment));
+ return;
+ }
+
+ // Make sure there is at least one output file.
+ if (build.Outputs.empty()) {
+ cmSystemTools::Error(cmStrCat(
+ "No output files for WriteBuild! called with comment: ", build.Comment));
+ return;
+ }
+
+ cmGlobalNinjaGenerator::WriteComment(os, build.Comment);
+
+ // Write output files.
+ std::string buildStr("build");
+ {
+ // Write explicit outputs
+ for (std::string const& output : build.Outputs) {
+ buildStr += cmStrCat(' ', this->EncodePath(output));
+ if (this->ComputingUnknownDependencies) {
+ this->CombinedBuildOutputs.insert(output);
+ }
+ }
+ // Write implicit outputs
+ if (!build.ImplicitOuts.empty()) {
+ buildStr += " |";
+ for (std::string const& implicitOut : build.ImplicitOuts) {
+ buildStr += cmStrCat(' ', this->EncodePath(implicitOut));
+ }
+ }
+ buildStr += ':';
+
+ // Write the rule.
+ buildStr += cmStrCat(' ', build.Rule);
+ }
+
+ std::string arguments;
+ {
+ // TODO: Better formatting for when there are multiple input/output files.
+
+ // Write explicit dependencies.
+ for (std::string const& explicitDep : build.ExplicitDeps) {
+ arguments += cmStrCat(' ', this->EncodePath(explicitDep));
+ }
+
+ // Write implicit dependencies.
+ if (!build.ImplicitDeps.empty()) {
+ arguments += " |";
+ for (std::string const& implicitDep : build.ImplicitDeps) {
+ arguments += cmStrCat(' ', this->EncodePath(implicitDep));
+ }
+ }
+
+ // Write order-only dependencies.
+ if (!build.OrderOnlyDeps.empty()) {
+ arguments += " ||";
+ for (std::string const& orderOnlyDep : build.OrderOnlyDeps) {
+ arguments += cmStrCat(' ', this->EncodePath(orderOnlyDep));
+ }
+ }
+
+ arguments += '\n';
+ }
+
+ // Write the variables bound to this build statement.
+ std::string assignments;
+ {
+ std::ostringstream variable_assignments;
+ for (auto const& variable : build.Variables) {
+ cmGlobalNinjaGenerator::WriteVariable(
+ variable_assignments, variable.first, variable.second, "", 1);
+ }
+
+ // check if a response file rule should be used
+ assignments = variable_assignments.str();
+ bool useResponseFile = false;
+ if (cmdLineLimit < 0 ||
+ (cmdLineLimit > 0 &&
+ (arguments.size() + buildStr.size() + assignments.size() + 1000) >
+ static_cast<size_t>(cmdLineLimit))) {
+ variable_assignments.str(std::string());
+ cmGlobalNinjaGenerator::WriteVariable(variable_assignments, "RSP_FILE",
+ build.RspFile, "", 1);
+ assignments += variable_assignments.str();
+ useResponseFile = true;
+ }
+ if (usedResponseFile) {
+ *usedResponseFile = useResponseFile;
+ }
+ }
+
+ if (build.Variables.count("dyndep") > 0) {
+ // The ninja 'cleandead' operation does not account for outputs
+ // discovered by 'dyndep' bindings. Avoid removing them.
+ this->DisableCleandead = true;
+ }
+
+ os << buildStr << arguments << assignments << "\n";
+}
+
+void cmGlobalNinjaGenerator::AddCustomCommandRule()
+{
+ cmNinjaRule rule("CUSTOM_COMMAND");
+ rule.Command = "$COMMAND";
+ rule.Description = "$DESC";
+ rule.Comment = "Rule for running custom commands.";
+ this->AddRule(rule);
+}
+
+void cmGlobalNinjaGenerator::WriteCustomCommandBuild(
+ const std::string& command, const std::string& description,
+ const std::string& comment, const std::string& depfile,
+ const std::string& job_pool, bool uses_terminal, bool restat,
+ const cmNinjaDeps& outputs, const std::string& config,
+ const cmNinjaDeps& explicitDeps, const cmNinjaDeps& orderOnlyDeps)
+{
+ this->AddCustomCommandRule();
+
+ {
+ cmNinjaBuild build("CUSTOM_COMMAND");
+ build.Comment = comment;
+ build.Outputs = outputs;
+ build.ExplicitDeps = explicitDeps;
+ build.OrderOnlyDeps = orderOnlyDeps;
+
+ cmNinjaVars& vars = build.Variables;
+ {
+ std::string cmd = command; // NOLINT(*)
+#ifdef _WIN32
+ if (cmd.empty())
+ // TODO Shouldn't an empty command be handled by ninja?
+ cmd = "cmd.exe /c";
+#endif
+ vars["COMMAND"] = std::move(cmd);
+ }
+ vars["DESC"] = this->EncodeLiteral(description);
+ if (restat) {
+ vars["restat"] = "1";
+ }
+ if (uses_terminal && this->SupportsConsolePool()) {
+ vars["pool"] = "console";
+ } else if (!job_pool.empty()) {
+ vars["pool"] = job_pool;
+ }
+ if (!depfile.empty()) {
+ vars["depfile"] = depfile;
+ }
+ if (config.empty()) {
+ this->WriteBuild(*this->GetCommonFileStream(), build);
+ } else {
+ this->WriteBuild(*this->GetImplFileStream(config), build);
+ }
+ }
+
+ if (this->ComputingUnknownDependencies) {
+ // we need to track every dependency that comes in, since we are trying
+ // to find dependencies that are side effects of build commands
+ for (std::string const& dep : explicitDeps) {
+ this->CombinedCustomCommandExplicitDependencies.insert(dep);
+ }
+ }
+}
+
+void cmGlobalNinjaGenerator::AddMacOSXContentRule()
+{
+ cmNinjaRule rule("COPY_OSX_CONTENT");
+ rule.Command = cmStrCat(this->CMakeCmd(), " -E copy $in $out");
+ rule.Description = "Copying OS X Content $out";
+ rule.Comment = "Rule for copying OS X bundle content file.";
+ this->AddRule(rule);
+}
+
+void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(std::string input,
+ std::string output,
+ const std::string& config)
+{
+ this->AddMacOSXContentRule();
+ {
+ cmNinjaBuild build("COPY_OSX_CONTENT");
+ build.Outputs.push_back(std::move(output));
+ build.ExplicitDeps.push_back(std::move(input));
+ this->WriteBuild(*this->GetImplFileStream(config), build);
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteRule(std::ostream& os,
+ cmNinjaRule const& rule)
+{
+ // -- Parameter checks
+ // Make sure the rule has a name.
+ if (rule.Name.empty()) {
+ cmSystemTools::Error(cmStrCat(
+ "No name given for WriteRule! called with comment: ", rule.Comment));
+ return;
+ }
+
+ // Make sure a command is given.
+ if (rule.Command.empty()) {
+ cmSystemTools::Error(cmStrCat(
+ "No command given for WriteRule! called with comment: ", rule.Comment));
+ return;
+ }
+
+ // Make sure response file content is given
+ if (!rule.RspFile.empty() && rule.RspContent.empty()) {
+ cmSystemTools::Error(
+ cmStrCat("rspfile but no rspfile_content given for WriteRule! "
+ "called with comment: ",
+ rule.Comment));
+ return;
+ }
+
+ // -- Write rule
+ // Write rule intro
+ cmGlobalNinjaGenerator::WriteComment(os, rule.Comment);
+ os << "rule " << rule.Name << '\n';
+
+ // Write rule key/value pairs
+ auto writeKV = [&os](const char* key, std::string const& value) {
+ if (!value.empty()) {
+ cmGlobalNinjaGenerator::Indent(os, 1);
+ os << key << " = " << value << '\n';
+ }
+ };
+
+ writeKV("depfile", rule.DepFile);
+ writeKV("deps", rule.DepType);
+ writeKV("command", rule.Command);
+ writeKV("description", rule.Description);
+ if (!rule.RspFile.empty()) {
+ writeKV("rspfile", rule.RspFile);
+ writeKV("rspfile_content", rule.RspContent);
+ }
+ writeKV("restat", rule.Restat);
+ if (rule.Generator) {
+ writeKV("generator", "1");
+ }
+
+ // Finish rule
+ os << '\n';
+}
+
+void cmGlobalNinjaGenerator::WriteVariable(std::ostream& os,
+ const std::string& name,
+ const std::string& value,
+ const std::string& comment,
+ int indent)
+{
+ // Make sure we have a name.
+ if (name.empty()) {
+ cmSystemTools::Error(cmStrCat("No name given for WriteVariable! called "
+ "with comment: ",
+ comment));
+ return;
+ }
+
+ // Do not add a variable if the value is empty.
+ std::string val = cmTrimWhitespace(value);
+ if (val.empty()) {
+ return;
+ }
+
+ cmGlobalNinjaGenerator::WriteComment(os, comment);
+ cmGlobalNinjaGenerator::Indent(os, indent);
+ os << name << " = " << val << "\n";
+}
+
+void cmGlobalNinjaGenerator::WriteInclude(std::ostream& os,
+ const std::string& filename,
+ const std::string& comment)
+{
+ cmGlobalNinjaGenerator::WriteComment(os, comment);
+ os << "include " << filename << "\n";
+}
+
+void cmGlobalNinjaGenerator::WriteDefault(std::ostream& os,
+ const cmNinjaDeps& targets,
+ const std::string& comment)
+{
+ cmGlobalNinjaGenerator::WriteComment(os, comment);
+ os << "default";
+ for (std::string const& target : targets) {
+ os << " " << target;
+ }
+ os << "\n";
+}
+
+cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm)
+ : cmGlobalCommonGenerator(cm)
+{
+#ifdef _WIN32
+ cm->GetState()->SetWindowsShell(true);
+#endif
+ this->FindMakeProgramFile = "CMakeNinjaFindMake.cmake";
+}
+
+// Virtual public methods.
+
+std::unique_ptr<cmLocalGenerator> cmGlobalNinjaGenerator::CreateLocalGenerator(
+ cmMakefile* mf)
+{
+ return std::unique_ptr<cmLocalGenerator>(
+ cm::make_unique<cmLocalNinjaGenerator>(this, mf));
+}
+
+codecvt::Encoding cmGlobalNinjaGenerator::GetMakefileEncoding() const
+{
+ return this->NinjaExpectedEncoding;
+}
+
+void cmGlobalNinjaGenerator::GetDocumentation(cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalNinjaGenerator::GetActualName();
+ entry.Brief = "Generates build.ninja files.";
+}
+
+// Implemented in all cmGlobaleGenerator sub-classes.
+// Used in:
+// Source/cmLocalGenerator.cxx
+// Source/cmake.cxx
+void cmGlobalNinjaGenerator::Generate()
+{
+ // Check minimum Ninja version.
+ if (cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
+ this->NinjaVersion.c_str(),
+ RequiredNinjaVersion().c_str())) {
+ std::ostringstream msg;
+ msg << "The detected version of Ninja (" << this->NinjaVersion;
+ msg << ") is less than the version of Ninja required by CMake (";
+ msg << cmGlobalNinjaGenerator::RequiredNinjaVersion() << ").";
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+ msg.str());
+ return;
+ }
+ if (!this->InspectConfigTypeVariables()) {
+ return;
+ }
+ if (!this->OpenBuildFileStreams()) {
+ return;
+ }
+ if (!this->OpenRulesFileStream()) {
+ return;
+ }
+
+ for (auto& it : this->Configs) {
+ it.second.TargetDependsClosures.clear();
+ }
+
+ this->InitOutputPathPrefix();
+ this->TargetAll = this->NinjaOutputPath("all");
+ this->CMakeCacheFile = this->NinjaOutputPath("CMakeCache.txt");
+ this->DisableCleandead = false;
+ this->DiagnosedCxxModuleSupport = false;
+
+ this->PolicyCMP0058 =
+ this->LocalGenerators[0]->GetMakefile()->GetPolicyStatus(
+ cmPolicies::CMP0058);
+ this->ComputingUnknownDependencies =
+ (this->PolicyCMP0058 == cmPolicies::OLD ||
+ this->PolicyCMP0058 == cmPolicies::WARN);
+
+ this->cmGlobalGenerator::Generate();
+
+ this->WriteAssumedSourceDependencies();
+ this->WriteTargetAliases(*this->GetCommonFileStream());
+ this->WriteFolderTargets(*this->GetCommonFileStream());
+ this->WriteUnknownExplicitDependencies(*this->GetCommonFileStream());
+ this->WriteBuiltinTargets(*this->GetCommonFileStream());
+
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ this->RulesFileStream->setstate(std::ios::failbit);
+ for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs(
+ cmMakefile::IncludeEmptyConfig)) {
+ this->GetImplFileStream(config)->setstate(std::ios::failbit);
+ this->GetConfigFileStream(config)->setstate(std::ios::failbit);
+ }
+ this->GetCommonFileStream()->setstate(std::ios::failbit);
+ }
+
+ this->CloseCompileCommandsStream();
+ this->CloseRulesFileStream();
+ this->CloseBuildFileStreams();
+
+#ifdef _WIN32
+ // Older ninja tools will not be able to update metadata on Windows
+ // when we are re-generating inside an existing 'ninja' invocation
+ // because the outer tool has the files open for write.
+ if (this->NinjaSupportsMetadataOnRegeneration ||
+ !this->GetCMakeInstance()->GetRegenerateDuringBuild())
+#endif
+ {
+ this->CleanMetaData();
+ }
+}
+
+void cmGlobalNinjaGenerator::CleanMetaData()
+{
+ auto run_ninja_tool = [this](std::vector<char const*> const& args) {
+ std::vector<std::string> command;
+ command.push_back(this->NinjaCommand);
+ command.emplace_back("-C");
+ command.emplace_back(this->GetCMakeInstance()->GetHomeOutputDirectory());
+ command.emplace_back("-t");
+ for (auto const& arg : args) {
+ command.emplace_back(arg);
+ }
+ std::string error;
+ if (!cmSystemTools::RunSingleCommand(command, nullptr, &error, nullptr,
+ nullptr,
+ cmSystemTools::OUTPUT_NONE)) {
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+ cmStrCat("Running\n '",
+ cmJoin(command, "' '"),
+ "'\n"
+ "failed with:\n ",
+ error));
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ };
+
+ // Can the tools below expect 'build.ninja' to be loadable?
+ bool const expectBuildManifest =
+ !this->IsMultiConfig() && this->OutputPathPrefix.empty();
+
+ // Skip some ninja tools if they need 'build.ninja' but it is missing.
+ bool const missingBuildManifest = expectBuildManifest &&
+ this->NinjaSupportsUnconditionalRecompactTool &&
+ !cmSystemTools::FileExists("build.ninja");
+
+ // The `recompact` tool loads the manifest. As above, we don't have a single
+ // `build.ninja` to load for this in Ninja-Multi. This may be relaxed in the
+ // future pending further investigation into how Ninja works upstream
+ // (ninja#1721).
+ if (this->NinjaSupportsUnconditionalRecompactTool &&
+ !this->GetCMakeInstance()->GetRegenerateDuringBuild() &&
+ expectBuildManifest && !missingBuildManifest) {
+ run_ninja_tool({ "recompact" });
+ }
+ if (this->NinjaSupportsRestatTool && this->OutputPathPrefix.empty()) {
+ // XXX(ninja): We only list `build.ninja` entry files here because CMake
+ // *always* rewrites these files on a reconfigure. If CMake ever gets
+ // smarter about this, all CMake-time created/edited files listed as
+ // outputs for the reconfigure build statement will need to be listed here.
+ cmNinjaDeps outputs;
+ this->AddRebuildManifestOutputs(outputs);
+ std::vector<const char*> args;
+ args.reserve(outputs.size() + 1);
+ args.push_back("restat");
+ for (auto const& output : outputs) {
+ args.push_back(output.c_str());
+ }
+ run_ninja_tool(args);
+ }
+}
+
+bool cmGlobalNinjaGenerator::FindMakeProgram(cmMakefile* mf)
+{
+ if (!this->cmGlobalGenerator::FindMakeProgram(mf)) {
+ return false;
+ }
+ if (cmProp ninjaCommand = mf->GetDefinition("CMAKE_MAKE_PROGRAM")) {
+ this->NinjaCommand = *ninjaCommand;
+ std::vector<std::string> command;
+ command.push_back(this->NinjaCommand);
+ command.emplace_back("--version");
+ std::string version;
+ std::string error;
+ if (!cmSystemTools::RunSingleCommand(command, &version, &error, nullptr,
+ nullptr,
+ cmSystemTools::OUTPUT_NONE)) {
+ mf->IssueMessage(MessageType::FATAL_ERROR,
+ cmStrCat("Running\n '", cmJoin(command, "' '"),
+ "'\n"
+ "failed with:\n ",
+ error));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ this->NinjaVersion = cmTrimWhitespace(version);
+ this->CheckNinjaFeatures();
+ }
+ return true;
+}
+
+void cmGlobalNinjaGenerator::CheckNinjaFeatures()
+{
+ this->NinjaSupportsConsolePool = !cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+ RequiredNinjaVersionForConsolePool().c_str());
+ this->NinjaSupportsImplicitOuts = !cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+ cmGlobalNinjaGenerator::RequiredNinjaVersionForImplicitOuts().c_str());
+ this->NinjaSupportsManifestRestat = !cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+ RequiredNinjaVersionForManifestRestat().c_str());
+ this->NinjaSupportsMultilineDepfile = !cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+ RequiredNinjaVersionForMultilineDepfile().c_str());
+ this->NinjaSupportsDyndeps = !cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+ RequiredNinjaVersionForDyndeps().c_str());
+ if (!this->NinjaSupportsDyndeps) {
+ // The ninja version number is not new enough to have upstream support.
+ // Our ninja branch adds ".dyndep-#" to its version number,
+ // where '#' is a feature-specific version number. Extract it.
+ static std::string const k_DYNDEP_ = ".dyndep-";
+ std::string::size_type pos = this->NinjaVersion.find(k_DYNDEP_);
+ if (pos != std::string::npos) {
+ const char* fv = &this->NinjaVersion[pos + k_DYNDEP_.size()];
+ unsigned long dyndep = 0;
+ cmStrToULong(fv, &dyndep);
+ if (dyndep == 1) {
+ this->NinjaSupportsDyndeps = true;
+ }
+ }
+ }
+ this->NinjaSupportsUnconditionalRecompactTool =
+ !cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+ RequiredNinjaVersionForUnconditionalRecompactTool().c_str());
+ this->NinjaSupportsRestatTool = !cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+ RequiredNinjaVersionForRestatTool().c_str());
+ this->NinjaSupportsMultipleOutputs = !cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+ RequiredNinjaVersionForMultipleOutputs().c_str());
+ this->NinjaSupportsMetadataOnRegeneration = !cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+ RequiredNinjaVersionForMetadataOnRegeneration().c_str());
+#ifdef _WIN32
+ this->NinjaSupportsCodePage = !cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+ RequiredNinjaVersionForCodePage().c_str());
+ if (this->NinjaSupportsCodePage) {
+ this->CheckNinjaCodePage();
+ } else {
+ this->NinjaExpectedEncoding = codecvt::ANSI;
+ }
+#endif
+}
+
+void cmGlobalNinjaGenerator::CheckNinjaCodePage()
+{
+ std::vector<std::string> command{ this->NinjaCommand, "-t", "wincodepage" };
+ std::string output;
+ std::string error;
+ int result;
+ if (!cmSystemTools::RunSingleCommand(command, &output, &error, &result,
+ nullptr, cmSystemTools::OUTPUT_NONE)) {
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+ cmStrCat("Running\n '",
+ cmJoin(command, "' '"),
+ "'\n"
+ "failed with:\n ",
+ error));
+ cmSystemTools::SetFatalErrorOccured();
+ } else if (result == 0) {
+ std::istringstream outputStream(output);
+ std::string line;
+ bool found = false;
+ while (cmSystemTools::GetLineFromStream(outputStream, line)) {
+ if (cmHasLiteralPrefix(line, "Build file encoding: ")) {
+ cm::string_view lineView(line);
+ cm::string_view encoding =
+ lineView.substr(cmStrLen("Build file encoding: "));
+ if (encoding == "UTF-8") {
+ // Ninja expects UTF-8. We use that internally. No conversion needed.
+ this->NinjaExpectedEncoding = codecvt::None;
+ } else {
+ this->NinjaExpectedEncoding = codecvt::ANSI;
+ }
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::WARNING,
+ "Could not determine Ninja's code page, defaulting to UTF-8");
+ this->NinjaExpectedEncoding = codecvt::None;
+ }
+ } else {
+ this->NinjaExpectedEncoding = codecvt::ANSI;
+ }
+}
+
+bool cmGlobalNinjaGenerator::CheckLanguages(
+ std::vector<std::string> const& languages, cmMakefile* mf) const
+{
+ if (cm::contains(languages, "Fortran")) {
+ return this->CheckFortran(mf);
+ }
+ if (cm::contains(languages, "ISPC")) {
+ return this->CheckISPC(mf);
+ }
+ if (cm::contains(languages, "Swift")) {
+ const std::string architectures =
+ mf->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES");
+ if (architectures.find_first_of(';') != std::string::npos) {
+ mf->IssueMessage(MessageType::FATAL_ERROR,
+ "multiple values for CMAKE_OSX_ARCHITECTURES not "
+ "supported with Swift");
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmGlobalNinjaGenerator::CheckCxxModuleSupport()
+{
+ bool const diagnose = !this->DiagnosedCxxModuleSupport &&
+ !this->CMakeInstance->GetIsInTryCompile();
+ if (diagnose) {
+ this->DiagnosedCxxModuleSupport = true;
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ "C++20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP "
+ "is experimental. It is meant only for compiler developers to try.");
+ }
+ if (this->NinjaSupportsDyndeps) {
+ return true;
+ }
+ if (diagnose) {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "The Ninja generator does not support C++20 modules "
+ "using Ninja version \n"
+ " " << this->NinjaVersion << "\n"
+ "due to lack of required features. "
+ "Ninja " << RequiredNinjaVersionForDyndeps() << " or higher is required."
+ ;
+ /* clang-format on */
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ return false;
+}
+
+bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const
+{
+ if (this->NinjaSupportsDyndeps) {
+ return true;
+ }
+
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "The Ninja generator does not support Fortran using Ninja version\n"
+ " " << this->NinjaVersion << "\n"
+ "due to lack of required features. "
+ "Ninja " << RequiredNinjaVersionForDyndeps() << " or higher is required."
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+}
+
+bool cmGlobalNinjaGenerator::CheckISPC(cmMakefile* mf) const
+{
+ if (this->NinjaSupportsMultipleOutputs) {
+ return true;
+ }
+
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "The Ninja generator does not support ISPC using Ninja version\n"
+ " " << this->NinjaVersion << "\n"
+ "due to lack of required features. "
+ "Ninja " << RequiredNinjaVersionForMultipleOutputs() <<
+ " or higher is required."
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+}
+
+void cmGlobalNinjaGenerator::EnableLanguage(
+ std::vector<std::string> const& langs, cmMakefile* mf, bool optional)
+{
+ if (this->IsMultiConfig()) {
+ if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
+ mf->AddCacheDefinition(
+ "CMAKE_CONFIGURATION_TYPES", "Debug;Release;RelWithDebInfo",
+ "Semicolon separated list of supported configuration types, only "
+ "supports Debug, Release, MinSizeRel, and RelWithDebInfo, anything "
+ "else will be ignored",
+ cmStateEnums::STRING);
+ }
+ }
+
+ this->cmGlobalGenerator::EnableLanguage(langs, mf, optional);
+ for (std::string const& l : langs) {
+ if (l == "NONE") {
+ continue;
+ }
+ this->ResolveLanguageCompiler(l, mf, optional);
+ }
+#ifdef _WIN32
+ const bool clangGnuMode =
+ ((mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "Clang") &&
+ (mf->GetSafeDefinition("CMAKE_C_COMPILER_FRONTEND_VARIANT") == "GNU")) ||
+ ((mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "Clang") &&
+ (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_FRONTEND_VARIANT") == "GNU"));
+
+ if (clangGnuMode ||
+ ((mf->GetSafeDefinition("CMAKE_C_SIMULATE_ID") != "MSVC") &&
+ (mf->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID") != "MSVC") &&
+ (mf->IsOn("CMAKE_COMPILER_IS_MINGW") ||
+ (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "GNU") ||
+ (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "GNU") ||
+ (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "Clang") ||
+ (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "Clang") ||
+ (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "QCC") ||
+ (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "QCC")))) {
+ this->UsingGCCOnWindows = true;
+ }
+#endif
+}
+
+// Implemented by:
+// cmGlobalUnixMakefileGenerator3
+// cmGlobalGhsMultiGenerator
+// cmGlobalVisualStudio10Generator
+// cmGlobalVisualStudio7Generator
+// cmGlobalXCodeGenerator
+// Called by:
+// cmGlobalGenerator::Build()
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalNinjaGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& /*projectName*/,
+ const std::string& /*projectDir*/,
+ std::vector<std::string> const& targetNames, const std::string& config,
+ bool /*fast*/, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions)
+{
+ GeneratedMakeCommand makeCommand;
+ makeCommand.Add(this->SelectMakeProgram(makeProgram));
+
+ if (verbose) {
+ makeCommand.Add("-v");
+ }
+
+ if ((jobs != cmake::NO_BUILD_PARALLEL_LEVEL) &&
+ (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL)) {
+ makeCommand.Add("-j", std::to_string(jobs));
+ }
+
+ this->AppendNinjaFileArgument(makeCommand, config);
+
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ for (const auto& tname : targetNames) {
+ if (!tname.empty()) {
+ makeCommand.Add(tname);
+ }
+ }
+ return { std::move(makeCommand) };
+}
+
+// Non-virtual public methods.
+
+void cmGlobalNinjaGenerator::AddRule(cmNinjaRule const& rule)
+{
+ // Do not add the same rule twice.
+ if (!this->Rules.insert(rule.Name).second) {
+ return;
+ }
+ // Store command length
+ this->RuleCmdLength[rule.Name] = static_cast<int>(rule.Command.size());
+ // Write rule
+ cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream, rule);
+}
+
+bool cmGlobalNinjaGenerator::HasRule(const std::string& name)
+{
+ return (this->Rules.find(name) != this->Rules.end());
+}
+
+// Private virtual overrides
+
+std::string cmGlobalNinjaGenerator::GetEditCacheCommand() const
+{
+ // Ninja by design does not run interactive tools in the terminal,
+ // so our only choice is cmake-gui.
+ return cmSystemTools::GetCMakeGUICommand();
+}
+
+void cmGlobalNinjaGenerator::ComputeTargetObjectDirectory(
+ cmGeneratorTarget* gt) const
+{
+ // Compute full path to object file directory for this target.
+ std::string dir = cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(),
+ '/', gt->LocalGenerator->GetTargetDirectory(gt),
+ '/', this->GetCMakeCFGIntDir(), '/');
+ gt->ObjectDirectory = dir;
+}
+
+// Private methods
+
+bool cmGlobalNinjaGenerator::OpenBuildFileStreams()
+{
+ if (!this->OpenFileStream(this->BuildFileStream,
+ cmGlobalNinjaGenerator::NINJA_BUILD_FILE)) {
+ return false;
+ }
+
+ // Write a comment about this file.
+ *this->BuildFileStream
+ << "# This file contains all the build statements describing the\n"
+ << "# compilation DAG.\n\n";
+
+ return true;
+}
+
+bool cmGlobalNinjaGenerator::OpenFileStream(
+ std::unique_ptr<cmGeneratedFileStream>& stream, const std::string& name)
+{
+ // Get a stream where to generate things.
+ if (!stream) {
+ // Compute Ninja's build file path.
+ std::string path =
+ cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), '/', name);
+ stream = cm::make_unique<cmGeneratedFileStream>(
+ path, false, this->GetMakefileEncoding());
+ if (!(*stream)) {
+ // An error message is generated by the constructor if it cannot
+ // open the file.
+ return false;
+ }
+
+ // Write the do not edit header.
+ this->WriteDisclaimer(*stream);
+ }
+
+ return true;
+}
+
+cm::optional<std::set<std::string>> cmGlobalNinjaGenerator::ListSubsetWithAll(
+ const std::set<std::string>& all, const std::set<std::string>& defaults,
+ const std::vector<std::string>& items)
+{
+ std::set<std::string> result;
+
+ for (auto const& item : items) {
+ if (item == "all") {
+ if (items.size() == 1) {
+ result = defaults;
+ } else {
+ return cm::nullopt;
+ }
+ } else if (all.count(item)) {
+ result.insert(item);
+ } else {
+ return cm::nullopt;
+ }
+ }
+
+ return cm::make_optional(result);
+}
+
+void cmGlobalNinjaGenerator::CloseBuildFileStreams()
+{
+ if (this->BuildFileStream) {
+ this->BuildFileStream.reset();
+ } else {
+ cmSystemTools::Error("Build file stream was not open.");
+ }
+}
+
+bool cmGlobalNinjaGenerator::OpenRulesFileStream()
+{
+ if (!this->OpenFileStream(this->RulesFileStream,
+ cmGlobalNinjaGenerator::NINJA_RULES_FILE)) {
+ return false;
+ }
+
+ // Write comment about this file.
+ /* clang-format off */
+ *this->RulesFileStream
+ << "# This file contains all the rules used to get the outputs files\n"
+ << "# built from the input files.\n"
+ << "# It is included in the main '" << NINJA_BUILD_FILE << "'.\n\n"
+ ;
+ /* clang-format on */
+ return true;
+}
+
+void cmGlobalNinjaGenerator::CloseRulesFileStream()
+{
+ if (this->RulesFileStream) {
+ this->RulesFileStream.reset();
+ } else {
+ cmSystemTools::Error("Rules file stream was not open.");
+ }
+}
+
+static void EnsureTrailingSlash(std::string& path)
+{
+ if (path.empty()) {
+ return;
+ }
+ std::string::value_type last = path.back();
+#ifdef _WIN32
+ if (last != '\\') {
+ path += '\\';
+ }
+#else
+ if (last != '/') {
+ path += '/';
+ }
+#endif
+}
+
+std::string const& cmGlobalNinjaGenerator::ConvertToNinjaPath(
+ const std::string& path) const
+{
+ auto const f = this->ConvertToNinjaPathCache.find(path);
+ if (f != this->ConvertToNinjaPathCache.end()) {
+ return f->second;
+ }
+
+ const auto& ng =
+ cm::static_reference_cast<cmLocalNinjaGenerator>(this->LocalGenerators[0]);
+ std::string const& bin_dir = ng.GetState()->GetBinaryDirectory();
+ std::string convPath = ng.MaybeConvertToRelativePath(bin_dir, path);
+ convPath = this->NinjaOutputPath(convPath);
+#ifdef _WIN32
+ std::replace(convPath.begin(), convPath.end(), '/', '\\');
+#endif
+ return this->ConvertToNinjaPathCache.emplace(path, std::move(convPath))
+ .first->second;
+}
+
+void cmGlobalNinjaGenerator::AddAdditionalCleanFile(std::string fileName,
+ const std::string& config)
+{
+ this->Configs[config].AdditionalCleanFiles.emplace(std::move(fileName));
+}
+
+void cmGlobalNinjaGenerator::AddCXXCompileCommand(
+ const std::string& commandLine, const std::string& sourceFile)
+{
+ // Compute Ninja's build file path.
+ std::string buildFileDir =
+ this->GetCMakeInstance()->GetHomeOutputDirectory();
+ if (!this->CompileCommandsStream) {
+ std::string buildFilePath =
+ cmStrCat(buildFileDir, "/compile_commands.json");
+ if (this->ComputingUnknownDependencies) {
+ this->CombinedBuildOutputs.insert(
+ this->NinjaOutputPath("compile_commands.json"));
+ }
+
+ // Get a stream where to generate things.
+ this->CompileCommandsStream =
+ cm::make_unique<cmGeneratedFileStream>(buildFilePath);
+ *this->CompileCommandsStream << "[\n";
+ } else {
+ *this->CompileCommandsStream << ",\n";
+ }
+
+ std::string sourceFileName = sourceFile;
+ if (!cmSystemTools::FileIsFullPath(sourceFileName)) {
+ sourceFileName = cmSystemTools::CollapseFullPath(
+ sourceFileName, this->GetCMakeInstance()->GetHomeOutputDirectory());
+ }
+
+ /* clang-format off */
+ *this->CompileCommandsStream << "{\n"
+ << R"( "directory": ")"
+ << cmGlobalGenerator::EscapeJSON(buildFileDir) << "\",\n"
+ << R"( "command": ")"
+ << cmGlobalGenerator::EscapeJSON(commandLine) << "\",\n"
+ << R"( "file": ")"
+ << cmGlobalGenerator::EscapeJSON(sourceFileName) << "\"\n"
+ << "}";
+ /* clang-format on */
+}
+
+void cmGlobalNinjaGenerator::CloseCompileCommandsStream()
+{
+ if (this->CompileCommandsStream) {
+ *this->CompileCommandsStream << "\n]";
+ this->CompileCommandsStream.reset();
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os) const
+{
+ os << "# CMAKE generated file: DO NOT EDIT!\n"
+ << "# Generated by \"" << this->GetName() << "\""
+ << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
+ << cmVersion::GetMinorVersion() << "\n\n";
+}
+
+void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies()
+{
+ for (auto const& asd : this->AssumedSourceDependencies) {
+ cmNinjaDeps orderOnlyDeps;
+ std::copy(asd.second.begin(), asd.second.end(),
+ std::back_inserter(orderOnlyDeps));
+ this->WriteCustomCommandBuild(
+ /*command=*/"", /*description=*/"",
+ "Assume dependencies for generated source file.",
+ /*depfile*/ "", /*job_pool*/ "",
+ /*uses_terminal*/ false,
+ /*restat*/ true, cmNinjaDeps(1, asd.first), "", cmNinjaDeps(),
+ orderOnlyDeps);
+ }
+}
+
+std::string cmGlobalNinjaGenerator::OrderDependsTargetForTarget(
+ cmGeneratorTarget const* target, const std::string& /*config*/) const
+{
+ return cmStrCat("cmake_object_order_depends_target_", target->GetName());
+}
+
+void cmGlobalNinjaGenerator::AppendTargetOutputs(
+ cmGeneratorTarget const* target, cmNinjaDeps& outputs,
+ const std::string& config, cmNinjaTargetDepends depends) const
+{
+ // for frameworks, we want the real name, not smple name
+ // frameworks always appear versioned, and the build.ninja
+ // will always attempt to manage symbolic links instead
+ // of letting cmOSXBundleGenerator do it.
+ bool realname = target->IsFrameworkOnApple();
+
+ switch (target->GetType()) {
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY: {
+ if (depends == DependOnTargetOrdering) {
+ outputs.push_back(this->OrderDependsTargetForTarget(target, config));
+ break;
+ }
+ }
+ // FALLTHROUGH
+ case cmStateEnums::EXECUTABLE: {
+ outputs.push_back(this->ConvertToNinjaPath(target->GetFullPath(
+ config, cmStateEnums::RuntimeBinaryArtifact, realname)));
+ break;
+ }
+ case cmStateEnums::OBJECT_LIBRARY: {
+ if (depends == DependOnTargetOrdering) {
+ outputs.push_back(this->OrderDependsTargetForTarget(target, config));
+ break;
+ }
+ }
+ // FALLTHROUGH
+ case cmStateEnums::GLOBAL_TARGET:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ case cmStateEnums::UTILITY: {
+ std::string path =
+ cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/',
+ target->GetName());
+ std::string output = this->ConvertToNinjaPath(path);
+ if (target->Target->IsPerConfig()) {
+ output = this->BuildAlias(output, config);
+ }
+ outputs.push_back(output);
+ break;
+ }
+
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ break;
+ }
+}
+
+void cmGlobalNinjaGenerator::AppendTargetDepends(
+ cmGeneratorTarget const* target, cmNinjaDeps& outputs,
+ const std::string& config, const std::string& fileConfig,
+ cmNinjaTargetDepends depends)
+{
+ if (target->GetType() == cmStateEnums::GLOBAL_TARGET) {
+ // These depend only on other CMake-provided targets, e.g. "all".
+ for (BT<std::pair<std::string, bool>> const& util :
+ target->GetUtilities()) {
+ std::string d =
+ cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/',
+ util.Value.first);
+ outputs.push_back(this->BuildAlias(this->ConvertToNinjaPath(d), config));
+ }
+ } else {
+ cmNinjaDeps outs;
+
+ auto computeISPCOuputs = [](cmGlobalNinjaGenerator* gg,
+ cmGeneratorTarget const* depTarget,
+ cmNinjaDeps& outputDeps,
+ const std::string& targetConfig) {
+ if (depTarget->CanCompileSources()) {
+ auto headers = depTarget->GetGeneratedISPCHeaders(targetConfig);
+ if (!headers.empty()) {
+ std::transform(headers.begin(), headers.end(), headers.begin(),
+ gg->MapToNinjaPath());
+ outputDeps.insert(outputDeps.end(), headers.begin(), headers.end());
+ }
+ auto objs = depTarget->GetGeneratedISPCObjects(targetConfig);
+ if (!objs.empty()) {
+ std::transform(objs.begin(), objs.end(), objs.begin(),
+ gg->MapToNinjaPath());
+ outputDeps.insert(outputDeps.end(), objs.begin(), objs.end());
+ }
+ }
+ };
+
+ for (cmTargetDepend const& targetDep :
+ this->GetTargetDirectDepends(target)) {
+ if (!targetDep->IsInBuildSystem()) {
+ continue;
+ }
+ if (targetDep.IsCross()) {
+ this->AppendTargetOutputs(targetDep, outs, fileConfig, depends);
+ computeISPCOuputs(this, targetDep, outs, fileConfig);
+ } else {
+ this->AppendTargetOutputs(targetDep, outs, config, depends);
+ computeISPCOuputs(this, targetDep, outs, config);
+ }
+ }
+ std::sort(outs.begin(), outs.end());
+ cm::append(outputs, outs);
+ }
+}
+
+void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
+ cmGeneratorTarget const* target, cmNinjaDeps& outputs,
+ const std::string& config, const std::string& fileConfig, bool genexOutput)
+{
+ cmNinjaOuts outs;
+ this->AppendTargetDependsClosure(target, outs, config, fileConfig,
+ genexOutput, true);
+ cm::append(outputs, outs);
+}
+
+void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
+ cmGeneratorTarget const* target, cmNinjaOuts& outputs,
+ const std::string& config, const std::string& fileConfig, bool genexOutput,
+ bool omit_self)
+{
+
+ // try to locate the target in the cache
+ ByConfig::TargetDependsClosureKey key{
+ target,
+ config,
+ genexOutput,
+ };
+ auto find = this->Configs[fileConfig].TargetDependsClosures.lower_bound(key);
+
+ if (find == this->Configs[fileConfig].TargetDependsClosures.end() ||
+ find->first != key) {
+ // We now calculate the closure outputs by inspecting the dependent
+ // targets recursively.
+ // For that we have to distinguish between a local result set that is only
+ // relevant for filling the cache entries properly isolated and a global
+ // result set that is relevant for the result of the top level call to
+ // AppendTargetDependsClosure.
+ cmNinjaOuts this_outs; // this will be the new cache entry
+
+ for (auto const& dep_target : this->GetTargetDirectDepends(target)) {
+ if (!dep_target->IsInBuildSystem()) {
+ continue;
+ }
+
+ if (!this->IsSingleConfigUtility(target) &&
+ !this->IsSingleConfigUtility(dep_target) &&
+ this->EnableCrossConfigBuild() && !dep_target.IsCross() &&
+ !genexOutput) {
+ continue;
+ }
+
+ if (dep_target.IsCross()) {
+ this->AppendTargetDependsClosure(dep_target, this_outs, fileConfig,
+ fileConfig, genexOutput, false);
+ } else {
+ this->AppendTargetDependsClosure(dep_target, this_outs, config,
+ fileConfig, genexOutput, false);
+ }
+ }
+ find = this->Configs[fileConfig].TargetDependsClosures.emplace_hint(
+ find, key, std::move(this_outs));
+ }
+
+ // now fill the outputs of the final result from the newly generated cache
+ // entry
+ outputs.insert(find->second.begin(), find->second.end());
+
+ // finally generate the outputs of the target itself, if applicable
+ cmNinjaDeps outs;
+ if (!omit_self) {
+ this->AppendTargetOutputs(target, outs, config, DependOnTargetArtifact);
+ }
+ outputs.insert(outs.begin(), outs.end());
+}
+
+void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias,
+ cmGeneratorTarget* target,
+ const std::string& config)
+{
+ std::string outputPath = this->NinjaOutputPath(alias);
+ std::string buildAlias = this->BuildAlias(outputPath, config);
+ cmNinjaDeps outputs;
+ if (config != "all") {
+ this->AppendTargetOutputs(target, outputs, config, DependOnTargetArtifact);
+ }
+ // Mark the target's outputs as ambiguous to ensure that no other target
+ // uses the output as an alias.
+ for (std::string const& output : outputs) {
+ this->TargetAliases[output].GeneratorTarget = nullptr;
+ this->DefaultTargetAliases[output].GeneratorTarget = nullptr;
+ for (const std::string& config2 :
+ this->Makefiles.front()->GetGeneratorConfigs(
+ cmMakefile::IncludeEmptyConfig)) {
+ this->Configs[config2].TargetAliases[output].GeneratorTarget = nullptr;
+ }
+ }
+
+ // Insert the alias into the map. If the alias was already present in the
+ // map and referred to another target, mark it as ambiguous.
+ TargetAlias ta;
+ ta.GeneratorTarget = target;
+ ta.Config = config;
+
+ auto newAliasGlobal =
+ this->TargetAliases.insert(std::make_pair(buildAlias, ta));
+ if (newAliasGlobal.second &&
+ newAliasGlobal.first->second.GeneratorTarget != target) {
+ newAliasGlobal.first->second.GeneratorTarget = nullptr;
+ }
+
+ auto newAliasConfig =
+ this->Configs[config].TargetAliases.insert(std::make_pair(outputPath, ta));
+ if (newAliasConfig.second &&
+ newAliasConfig.first->second.GeneratorTarget != target) {
+ newAliasConfig.first->second.GeneratorTarget = nullptr;
+ }
+ if (this->DefaultConfigs.count(config)) {
+ auto newAliasDefaultGlobal =
+ this->DefaultTargetAliases.insert(std::make_pair(outputPath, ta));
+ if (newAliasDefaultGlobal.second &&
+ newAliasDefaultGlobal.first->second.GeneratorTarget != target) {
+ newAliasDefaultGlobal.first->second.GeneratorTarget = nullptr;
+ }
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os)
+{
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << "# Target aliases.\n\n";
+
+ cmNinjaBuild build("phony");
+ build.Outputs.emplace_back();
+ for (auto const& ta : this->TargetAliases) {
+ // Don't write ambiguous aliases.
+ if (!ta.second.GeneratorTarget) {
+ continue;
+ }
+
+ // Don't write alias if there is a already a custom command with
+ // matching output
+ if (this->HasCustomCommandOutput(ta.first)) {
+ continue;
+ }
+
+ build.Outputs.front() = ta.first;
+ build.ExplicitDeps.clear();
+ if (ta.second.Config == "all") {
+ for (auto const& config : this->CrossConfigs) {
+ this->AppendTargetOutputs(ta.second.GeneratorTarget,
+ build.ExplicitDeps, config,
+ DependOnTargetArtifact);
+ }
+ } else {
+ this->AppendTargetOutputs(ta.second.GeneratorTarget, build.ExplicitDeps,
+ ta.second.Config, DependOnTargetArtifact);
+ }
+ this->WriteBuild(this->EnableCrossConfigBuild() &&
+ (ta.second.Config == "all" ||
+ this->CrossConfigs.count(ta.second.Config))
+ ? os
+ : *this->GetImplFileStream(ta.second.Config),
+ build);
+ }
+
+ if (this->IsMultiConfig()) {
+ for (auto const& config : this->Makefiles.front()->GetGeneratorConfigs(
+ cmMakefile::IncludeEmptyConfig)) {
+ for (auto const& ta : this->Configs[config].TargetAliases) {
+ // Don't write ambiguous aliases.
+ if (!ta.second.GeneratorTarget) {
+ continue;
+ }
+
+ // Don't write alias if there is a already a custom command with
+ // matching output
+ if (this->HasCustomCommandOutput(ta.first)) {
+ continue;
+ }
+
+ build.Outputs.front() = ta.first;
+ build.ExplicitDeps.clear();
+ this->AppendTargetOutputs(ta.second.GeneratorTarget,
+ build.ExplicitDeps, config,
+ DependOnTargetArtifact);
+ this->WriteBuild(*this->GetConfigFileStream(config), build);
+ }
+ }
+
+ if (!this->DefaultConfigs.empty()) {
+ for (auto const& ta : this->DefaultTargetAliases) {
+ // Don't write ambiguous aliases.
+ if (!ta.second.GeneratorTarget) {
+ continue;
+ }
+
+ // Don't write alias if there is a already a custom command with
+ // matching output
+ if (this->HasCustomCommandOutput(ta.first)) {
+ continue;
+ }
+
+ build.Outputs.front() = ta.first;
+ build.ExplicitDeps.clear();
+ for (auto const& config : this->DefaultConfigs) {
+ this->AppendTargetOutputs(ta.second.GeneratorTarget,
+ build.ExplicitDeps, config,
+ DependOnTargetArtifact);
+ }
+ this->WriteBuild(*this->GetDefaultFileStream(), build);
+ }
+ }
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
+{
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << "# Folder targets.\n\n";
+
+ std::map<std::string, DirectoryTarget> dirTargets =
+ this->ComputeDirectoryTargets();
+
+ for (auto const& it : dirTargets) {
+ cmNinjaBuild build("phony");
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ std::string const& currentBinaryDir = it.first;
+ DirectoryTarget const& dt = it.second;
+ std::vector<std::string> configs =
+ dt.LG->GetMakefile()->GetGeneratorConfigs(
+ cmMakefile::IncludeEmptyConfig);
+
+ // Setup target
+ cmNinjaDeps configDeps;
+ build.Comment = cmStrCat("Folder: ", currentBinaryDir);
+ build.Outputs.emplace_back();
+ std::string const buildDirAllTarget =
+ this->ConvertToNinjaPath(cmStrCat(currentBinaryDir, "/all"));
+ for (auto const& config : configs) {
+ build.ExplicitDeps.clear();
+ build.Outputs.front() = this->BuildAlias(buildDirAllTarget, config);
+ configDeps.emplace_back(build.Outputs.front());
+ for (DirectoryTarget::Target const& t : dt.Targets) {
+ if (!this->IsExcludedFromAllInConfig(t, config)) {
+ this->AppendTargetOutputs(t.GT, build.ExplicitDeps, config,
+ DependOnTargetArtifact);
+ }
+ }
+ for (DirectoryTarget::Dir const& d : dt.Children) {
+ if (!d.ExcludeFromAll) {
+ build.ExplicitDeps.emplace_back(this->BuildAlias(
+ this->ConvertToNinjaPath(cmStrCat(d.Path, "/all")), config));
+ }
+ }
+ // Write target
+ this->WriteBuild(this->EnableCrossConfigBuild() &&
+ this->CrossConfigs.count(config)
+ ? os
+ : *this->GetImplFileStream(config),
+ build);
+ }
+
+ // Add shortcut target
+ if (this->IsMultiConfig()) {
+ for (auto const& config : configs) {
+ build.ExplicitDeps = { this->BuildAlias(buildDirAllTarget, config) };
+ build.Outputs.front() = buildDirAllTarget;
+ this->WriteBuild(*this->GetConfigFileStream(config), build);
+ }
+
+ if (!this->DefaultFileConfig.empty()) {
+ build.ExplicitDeps.clear();
+ for (auto const& config : this->DefaultConfigs) {
+ build.ExplicitDeps.push_back(
+ this->BuildAlias(buildDirAllTarget, config));
+ }
+ build.Outputs.front() = buildDirAllTarget;
+ this->WriteBuild(*this->GetDefaultFileStream(), build);
+ }
+ }
+
+ // Add target for all configs
+ if (this->EnableCrossConfigBuild()) {
+ build.ExplicitDeps.clear();
+ for (auto const& config : this->CrossConfigs) {
+ build.ExplicitDeps.push_back(
+ this->BuildAlias(buildDirAllTarget, config));
+ }
+ build.Outputs.front() = this->BuildAlias(buildDirAllTarget, "all");
+ this->WriteBuild(os, build);
+ }
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os)
+{
+ if (!this->ComputingUnknownDependencies) {
+ return;
+ }
+
+ // We need to collect the set of known build outputs.
+ // Start with those generated by WriteBuild calls.
+ // No other method needs this so we can take ownership
+ // of the set locally and throw it out when we are done.
+ std::set<std::string> knownDependencies;
+ knownDependencies.swap(this->CombinedBuildOutputs);
+
+ // now write out the unknown explicit dependencies.
+
+ // union the configured files, evaluations files and the
+ // CombinedBuildOutputs,
+ // and then difference with CombinedExplicitDependencies to find the explicit
+ // dependencies that we have no rule for
+
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ /* clang-format off */
+ os << "# Unknown Build Time Dependencies.\n"
+ << "# Tell Ninja that they may appear as side effects of build rules\n"
+ << "# otherwise ordered by order-only dependencies.\n\n";
+ /* clang-format on */
+
+ // get the list of files that cmake itself has generated as a
+ // product of configuration.
+
+ for (const auto& lg : this->LocalGenerators) {
+ // get the vector of files created by this makefile and convert them
+ // to ninja paths, which are all relative in respect to the build directory
+ for (std::string const& file : lg->GetMakefile()->GetOutputFiles()) {
+ knownDependencies.insert(this->ConvertToNinjaPath(file));
+ }
+ if (!this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
+ // get list files which are implicit dependencies as well and will be
+ // phony for rebuild manifest
+ for (std::string const& j : lg->GetMakefile()->GetListFiles()) {
+ knownDependencies.insert(this->ConvertToNinjaPath(j));
+ }
+ }
+ for (const auto& li : lg->GetMakefile()->GetEvaluationFiles()) {
+ // get all the files created by generator expressions and convert them
+ // to ninja paths
+ for (std::string const& evaluationFile : li->GetFiles()) {
+ knownDependencies.insert(this->ConvertToNinjaPath(evaluationFile));
+ }
+ }
+ }
+ knownDependencies.insert(this->CMakeCacheFile);
+
+ for (auto const& ta : this->TargetAliases) {
+ knownDependencies.insert(this->ConvertToNinjaPath(ta.first));
+ }
+
+ // remove all source files we know will exist.
+ for (auto const& i : this->AssumedSourceDependencies) {
+ knownDependencies.insert(this->ConvertToNinjaPath(i.first));
+ }
+
+ // now we difference with CombinedCustomCommandExplicitDependencies to find
+ // the list of items we know nothing about.
+ // We have encoded all the paths in CombinedCustomCommandExplicitDependencies
+ // and knownDependencies so no matter if unix or windows paths they
+ // should all match now.
+
+ std::vector<std::string> unknownExplicitDepends;
+ this->CombinedCustomCommandExplicitDependencies.erase(this->TargetAll);
+
+ std::set_difference(this->CombinedCustomCommandExplicitDependencies.begin(),
+ this->CombinedCustomCommandExplicitDependencies.end(),
+ knownDependencies.begin(), knownDependencies.end(),
+ std::back_inserter(unknownExplicitDepends));
+
+ std::vector<std::string> warnExplicitDepends;
+ if (!unknownExplicitDepends.empty()) {
+ cmake* cmk = this->GetCMakeInstance();
+ std::string const& buildRoot = cmk->GetHomeOutputDirectory();
+ bool const inSource = (buildRoot == cmk->GetHomeDirectory());
+ bool const warn = (!inSource && (this->PolicyCMP0058 == cmPolicies::WARN));
+ cmNinjaBuild build("phony");
+ build.Outputs.emplace_back("");
+ for (std::string const& ued : unknownExplicitDepends) {
+ // verify the file is in the build directory
+ std::string const absDepPath =
+ cmSystemTools::CollapseFullPath(ued, buildRoot);
+ if (cmSystemTools::IsSubDirectory(absDepPath, buildRoot)) {
+ // Generate phony build statement
+ build.Outputs[0] = ued;
+ this->WriteBuild(os, build);
+ // Add to warning on demand
+ if (warn && warnExplicitDepends.size() < 10) {
+ warnExplicitDepends.push_back(ued);
+ }
+ }
+ }
+ }
+
+ if (!warnExplicitDepends.empty()) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0058) << "\n"
+ "This project specifies custom command DEPENDS on files "
+ "in the build tree that are not specified as the OUTPUT or "
+ "BYPRODUCTS of any add_custom_command or add_custom_target:\n"
+ " " << cmJoin(warnExplicitDepends, "\n ") <<
+ "\n"
+ "For compatibility with versions of CMake that did not have "
+ "the BYPRODUCTS option, CMake is generating phony rules for "
+ "such files to convince 'ninja' to build."
+ "\n"
+ "Project authors should add the missing BYPRODUCTS or OUTPUT "
+ "options to the custom commands that produce these files."
+ ;
+ /* clang-format on */
+ this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
+ w.str());
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os)
+{
+ // Write headers.
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << "# Built-in targets\n\n";
+
+ this->WriteTargetRebuildManifest(os);
+ this->WriteTargetClean(os);
+ this->WriteTargetHelp(os);
+
+ for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs(
+ cmMakefile::IncludeEmptyConfig)) {
+ this->WriteTargetDefault(*this->GetConfigFileStream(config));
+ }
+
+ if (!this->DefaultFileConfig.empty()) {
+ this->WriteTargetDefault(*this->GetDefaultFileStream());
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteTargetDefault(std::ostream& os)
+{
+ if (!this->HasOutputPathPrefix()) {
+ cmNinjaDeps all;
+ all.push_back(this->TargetAll);
+ cmGlobalNinjaGenerator::WriteDefault(os, all,
+ "Make the all target the default.");
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
+{
+ if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
+ return;
+ }
+ const auto& lg = this->LocalGenerators[0];
+
+ {
+ cmNinjaRule rule("RERUN_CMAKE");
+ rule.Command =
+ cmStrCat(this->CMakeCmd(), " --regenerate-during-build -S",
+ lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
+ cmOutputConverter::SHELL),
+ " -B",
+ lg->ConvertToOutputFormat(lg->GetBinaryDirectory(),
+ cmOutputConverter::SHELL));
+ rule.Description = "Re-running CMake...";
+ rule.Comment = "Rule for re-running cmake.";
+ rule.Generator = true;
+ WriteRule(*this->RulesFileStream, rule);
+ }
+
+ cmNinjaBuild reBuild("RERUN_CMAKE");
+ reBuild.Comment = "Re-run CMake if any of its inputs changed.";
+ this->AddRebuildManifestOutputs(reBuild.Outputs);
+
+ for (const auto& localGen : this->LocalGenerators) {
+ for (std::string const& fi : localGen->GetMakefile()->GetListFiles()) {
+ reBuild.ImplicitDeps.push_back(this->ConvertToNinjaPath(fi));
+ }
+ }
+ reBuild.ImplicitDeps.push_back(this->CMakeCacheFile);
+
+ // Use 'console' pool to get non buffered output of the CMake re-run call
+ // Available since Ninja 1.5
+ if (this->SupportsConsolePool()) {
+ reBuild.Variables["pool"] = "console";
+ }
+
+ cmake* cm = this->GetCMakeInstance();
+ if (this->SupportsManifestRestat() && cm->DoWriteGlobVerifyTarget()) {
+ {
+ cmNinjaRule rule("VERIFY_GLOBS");
+ rule.Command =
+ cmStrCat(this->CMakeCmd(), " -P ",
+ lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
+ cmOutputConverter::SHELL));
+ rule.Description = "Re-checking globbed directories...";
+ rule.Comment = "Rule for re-checking globbed directories.";
+ rule.Generator = true;
+ this->WriteRule(*this->RulesFileStream, rule);
+ }
+
+ cmNinjaBuild phonyBuild("phony");
+ phonyBuild.Comment = "Phony target to force glob verification run.";
+ phonyBuild.Outputs.push_back(
+ cmStrCat(cm->GetGlobVerifyScript(), "_force"));
+ this->WriteBuild(os, phonyBuild);
+
+ reBuild.Variables["restat"] = "1";
+ std::string const verifyScriptFile =
+ this->NinjaOutputPath(cm->GetGlobVerifyScript());
+ std::string const verifyStampFile =
+ this->NinjaOutputPath(cm->GetGlobVerifyStamp());
+ {
+ cmNinjaBuild vgBuild("VERIFY_GLOBS");
+ vgBuild.Comment =
+ "Re-run CMake to check if globbed directories changed.";
+ vgBuild.Outputs.push_back(verifyStampFile);
+ vgBuild.ImplicitDeps = phonyBuild.Outputs;
+ vgBuild.Variables = reBuild.Variables;
+ this->WriteBuild(os, vgBuild);
+ }
+ reBuild.Variables.erase("restat");
+ reBuild.ImplicitDeps.push_back(verifyScriptFile);
+ reBuild.ExplicitDeps.push_back(verifyStampFile);
+ } else if (!this->SupportsManifestRestat() &&
+ cm->DoWriteGlobVerifyTarget()) {
+ std::ostringstream msg;
+ msg << "The detected version of Ninja:\n"
+ << " " << this->NinjaVersion << "\n"
+ << "is less than the version of Ninja required by CMake for adding "
+ "restat dependencies to the build.ninja manifest regeneration "
+ "target:\n"
+ << " "
+ << cmGlobalNinjaGenerator::RequiredNinjaVersionForManifestRestat()
+ << "\n";
+ msg << "Any pre-check scripts, such as those generated for file(GLOB "
+ "CONFIGURE_DEPENDS), will not be run by Ninja.";
+ this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
+ msg.str());
+ }
+
+ std::sort(reBuild.ImplicitDeps.begin(), reBuild.ImplicitDeps.end());
+ reBuild.ImplicitDeps.erase(
+ std::unique(reBuild.ImplicitDeps.begin(), reBuild.ImplicitDeps.end()),
+ reBuild.ImplicitDeps.end());
+
+ this->WriteBuild(os, reBuild);
+
+ {
+ cmNinjaBuild build("phony");
+ build.Comment = "A missing CMake input file is not an error.";
+ std::set_difference(std::make_move_iterator(reBuild.ImplicitDeps.begin()),
+ std::make_move_iterator(reBuild.ImplicitDeps.end()),
+ this->CustomCommandOutputs.begin(),
+ this->CustomCommandOutputs.end(),
+ std::back_inserter(build.Outputs));
+ this->WriteBuild(os, build);
+ }
+}
+
+std::string cmGlobalNinjaGenerator::CMakeCmd() const
+{
+ const auto& lgen = this->LocalGenerators.at(0);
+ return lgen->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
+ cmOutputConverter::SHELL);
+}
+
+std::string cmGlobalNinjaGenerator::NinjaCmd() const
+{
+ const auto& lgen = this->LocalGenerators[0];
+ if (lgen != nullptr) {
+ return lgen->ConvertToOutputFormat(this->NinjaCommand,
+ cmOutputConverter::SHELL);
+ }
+ return "ninja";
+}
+
+bool cmGlobalNinjaGenerator::SupportsConsolePool() const
+{
+ return this->NinjaSupportsConsolePool;
+}
+
+bool cmGlobalNinjaGenerator::SupportsImplicitOuts() const
+{
+ return this->NinjaSupportsImplicitOuts;
+}
+
+bool cmGlobalNinjaGenerator::SupportsManifestRestat() const
+{
+ return this->NinjaSupportsManifestRestat;
+}
+
+bool cmGlobalNinjaGenerator::SupportsMultilineDepfile() const
+{
+ return this->NinjaSupportsMultilineDepfile;
+}
+
+bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os)
+{
+ const auto& lgr = this->LocalGenerators.at(0);
+ std::string cleanScriptRel = "CMakeFiles/clean_additional.cmake";
+ std::string cleanScriptAbs =
+ cmStrCat(lgr->GetBinaryDirectory(), '/', cleanScriptRel);
+ std::vector<std::string> configs =
+ this->Makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+ // Check if there are additional files to clean
+ bool empty = true;
+ for (auto const& config : configs) {
+ auto const it = this->Configs.find(config);
+ if (it != this->Configs.end() &&
+ !it->second.AdditionalCleanFiles.empty()) {
+ empty = false;
+ break;
+ }
+ }
+ if (empty) {
+ // Remove cmake clean script file if it exists
+ cmSystemTools::RemoveFile(cleanScriptAbs);
+ return false;
+ }
+
+ // Write cmake clean script file
+ {
+ cmGeneratedFileStream fout(cleanScriptAbs);
+ if (!fout) {
+ return false;
+ }
+ fout << "# Additional clean files\ncmake_minimum_required(VERSION 3.16)\n";
+ for (auto const& config : configs) {
+ auto const it = this->Configs.find(config);
+ if (it != this->Configs.end() &&
+ !it->second.AdditionalCleanFiles.empty()) {
+ fout << "\nif(\"${CONFIG}\" STREQUAL \"\" OR \"${CONFIG}\" STREQUAL \""
+ << config << "\")\n";
+ fout << " file(REMOVE_RECURSE\n";
+ for (std::string const& acf : it->second.AdditionalCleanFiles) {
+ fout << " "
+ << cmOutputConverter::EscapeForCMake(
+ this->ConvertToNinjaPath(acf))
+ << '\n';
+ }
+ fout << " )\n";
+ fout << "endif()\n";
+ }
+ }
+ }
+ // Register clean script file
+ lgr->GetMakefile()->AddCMakeOutputFile(cleanScriptAbs);
+
+ // Write rule
+ {
+ cmNinjaRule rule("CLEAN_ADDITIONAL");
+ rule.Command = cmStrCat(
+ this->CMakeCmd(), " -DCONFIG=$CONFIG -P ",
+ lgr->ConvertToOutputFormat(this->NinjaOutputPath(cleanScriptRel),
+ cmOutputConverter::SHELL));
+ rule.Description = "Cleaning additional files...";
+ rule.Comment = "Rule for cleaning additional files.";
+ WriteRule(*this->RulesFileStream, rule);
+ }
+
+ // Write build
+ {
+ cmNinjaBuild build("CLEAN_ADDITIONAL");
+ build.Comment = "Clean additional files.";
+ build.Outputs.emplace_back();
+ for (auto const& config : configs) {
+ build.Outputs.front() = this->BuildAlias(
+ this->NinjaOutputPath(this->GetAdditionalCleanTargetName()), config);
+ build.Variables["CONFIG"] = config;
+ this->WriteBuild(os, build);
+ }
+ if (this->IsMultiConfig()) {
+ build.Outputs.front() =
+ this->NinjaOutputPath(this->GetAdditionalCleanTargetName());
+ build.Variables["CONFIG"] = "";
+ this->WriteBuild(os, build);
+ }
+ }
+ // Return success
+ return true;
+}
+
+void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
+{
+ // -- Additional clean target
+ bool additionalFiles = this->WriteTargetCleanAdditional(os);
+
+ // -- Default clean target
+ // Write rule
+ {
+ cmNinjaRule rule("CLEAN");
+ rule.Command = cmStrCat(this->NinjaCmd(), " $FILE_ARG -t clean $TARGETS");
+ rule.Description = "Cleaning all built files...";
+ rule.Comment = "Rule for cleaning all built files.";
+ WriteRule(*this->RulesFileStream, rule);
+ }
+
+ auto const configs = this->Makefiles.front()->GetGeneratorConfigs(
+ cmMakefile::IncludeEmptyConfig);
+
+ // Write build
+ {
+ cmNinjaBuild build("CLEAN");
+ build.Comment = "Clean all the built files.";
+ build.Outputs.emplace_back();
+
+ for (auto const& config : configs) {
+ build.Outputs.front() = this->BuildAlias(
+ this->NinjaOutputPath(this->GetCleanTargetName()), config);
+ if (this->IsMultiConfig()) {
+ build.Variables["TARGETS"] =
+ cmStrCat(this->BuildAlias(GetByproductsForCleanTargetName(), config),
+ " ", GetByproductsForCleanTargetName());
+ }
+ build.ExplicitDeps.clear();
+ if (additionalFiles) {
+ build.ExplicitDeps.push_back(this->BuildAlias(
+ this->NinjaOutputPath(this->GetAdditionalCleanTargetName()),
+ config));
+ }
+ for (auto const& fileConfig : configs) {
+ if (fileConfig != config && !this->EnableCrossConfigBuild()) {
+ continue;
+ }
+ if (this->IsMultiConfig()) {
+ build.Variables["FILE_ARG"] = cmStrCat(
+ "-f ",
+ cmGlobalNinjaMultiGenerator::GetNinjaImplFilename(fileConfig));
+ }
+ this->WriteBuild(*this->GetImplFileStream(fileConfig), build);
+ }
+ }
+
+ if (this->EnableCrossConfigBuild()) {
+ build.Outputs.front() = this->BuildAlias(
+ this->NinjaOutputPath(this->GetCleanTargetName()), "all");
+ build.ExplicitDeps.clear();
+
+ if (additionalFiles) {
+ for (auto const& config : this->CrossConfigs) {
+ build.ExplicitDeps.push_back(this->BuildAlias(
+ this->NinjaOutputPath(this->GetAdditionalCleanTargetName()),
+ config));
+ }
+ }
+
+ std::vector<std::string> byproducts;
+ for (auto const& config : this->CrossConfigs) {
+ byproducts.push_back(
+ this->BuildAlias(GetByproductsForCleanTargetName(), config));
+ }
+ byproducts.emplace_back(GetByproductsForCleanTargetName());
+ build.Variables["TARGETS"] = cmJoin(byproducts, " ");
+
+ for (auto const& fileConfig : configs) {
+ build.Variables["FILE_ARG"] = cmStrCat(
+ "-f ",
+ cmGlobalNinjaMultiGenerator::GetNinjaImplFilename(fileConfig));
+ this->WriteBuild(*this->GetImplFileStream(fileConfig), build);
+ }
+ }
+ }
+
+ if (this->IsMultiConfig()) {
+ cmNinjaBuild build("phony");
+ build.Outputs.emplace_back(
+ this->NinjaOutputPath(this->GetCleanTargetName()));
+ build.ExplicitDeps.emplace_back();
+
+ for (auto const& config : configs) {
+ build.ExplicitDeps.front() = this->BuildAlias(
+ this->NinjaOutputPath(this->GetCleanTargetName()), config);
+ this->WriteBuild(*this->GetConfigFileStream(config), build);
+ }
+
+ if (!this->DefaultConfigs.empty()) {
+ build.ExplicitDeps.clear();
+ for (auto const& config : this->DefaultConfigs) {
+ build.ExplicitDeps.push_back(this->BuildAlias(
+ this->NinjaOutputPath(this->GetCleanTargetName()), config));
+ }
+ this->WriteBuild(*this->GetDefaultFileStream(), build);
+ }
+ }
+
+ // Write byproducts
+ if (this->IsMultiConfig()) {
+ cmNinjaBuild build("phony");
+ build.Comment = "Clean byproducts.";
+ build.Outputs.emplace_back(
+ this->ConvertToNinjaPath(GetByproductsForCleanTargetName()));
+ build.ExplicitDeps = this->ByproductsForCleanTarget;
+ this->WriteBuild(os, build);
+
+ for (auto const& config : configs) {
+ build.Outputs.front() = this->BuildAlias(
+ this->ConvertToNinjaPath(GetByproductsForCleanTargetName()), config);
+ build.ExplicitDeps = this->Configs[config].ByproductsForCleanTarget;
+ this->WriteBuild(os, build);
+ }
+ }
+}
+
+void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os)
+{
+ {
+ cmNinjaRule rule("HELP");
+ rule.Command = cmStrCat(this->NinjaCmd(), " -t targets");
+ rule.Description = "All primary targets available:";
+ rule.Comment = "Rule for printing all primary targets available.";
+ WriteRule(*this->RulesFileStream, rule);
+ }
+ {
+ cmNinjaBuild build("HELP");
+ build.Comment = "Print all primary targets available.";
+ build.Outputs.push_back(this->NinjaOutputPath("help"));
+ this->WriteBuild(os, build);
+ }
+}
+
+void cmGlobalNinjaGenerator::InitOutputPathPrefix()
+{
+ this->OutputPathPrefix =
+ this->LocalGenerators[0]->GetMakefile()->GetSafeDefinition(
+ "CMAKE_NINJA_OUTPUT_PATH_PREFIX");
+ EnsureTrailingSlash(this->OutputPathPrefix);
+}
+
+std::string cmGlobalNinjaGenerator::NinjaOutputPath(
+ std::string const& path) const
+{
+ if (!this->HasOutputPathPrefix() || cmSystemTools::FileIsFullPath(path)) {
+ return path;
+ }
+ return cmStrCat(this->OutputPathPrefix, path);
+}
+
+void cmGlobalNinjaGenerator::StripNinjaOutputPathPrefixAsSuffix(
+ std::string& path)
+{
+ if (path.empty()) {
+ return;
+ }
+ EnsureTrailingSlash(path);
+ cmStripSuffixIfExists(path, this->OutputPathPrefix);
+}
+
+#if !defined(CMAKE_BOOTSTRAP)
+
+/*
+
+We use the following approach to support Fortran. Each target already
+has a <target>.dir/ directory used to hold intermediate files for CMake.
+For each target, a FortranDependInfo.json file is generated by CMake with
+information about include directories, module directories, and the locations
+the per-target directories for target dependencies.
+
+Compilation of source files within a target is split into the following steps:
+
+1. Preprocess all sources, scan preprocessed output for module dependencies.
+ This step is done with independent build statements for each source,
+ and can therefore be done in parallel.
+
+ rule Fortran_PREPROCESS
+ depfile = $DEP_FILE
+ command = gfortran -cpp $DEFINES $INCLUDES $FLAGS -E $in -o $out &&
+ cmake -E cmake_ninja_depends \
+ --tdi=FortranDependInfo.json --pp=$out --dep=$DEP_FILE \
+ --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE \
+ --lang=Fortran
+
+ build src.f90-pp.f90 | src.f90.o.ddi: Fortran_PREPROCESS src.f90
+ OBJ_FILE = src.f90.o
+ DEP_FILE = src.f90.o.d
+ DYNDEP_INTERMEDIATE_FILE = src.f90.o.ddi
+
+ The ``cmake -E cmake_ninja_depends`` tool reads the preprocessed output
+ and generates the ninja depfile for preprocessor dependencies. It also
+ generates a "ddi" file (in a format private to CMake) that lists the
+ object file that compilation will produce along with the module names
+ it provides and/or requires. The "ddi" file is an implicit output
+ because it should not appear in "$out" but is generated by the rule.
+
+2. Consolidate the per-source module dependencies saved in the "ddi"
+ files from all sources to produce a ninja "dyndep" file, ``Fortran.dd``.
+
+ rule Fortran_DYNDEP
+ command = cmake -E cmake_ninja_dyndep \
+ --tdi=FortranDependInfo.json --lang=Fortran --dd=$out $in
+
+ build Fortran.dd: Fortran_DYNDEP src1.f90.o.ddi src2.f90.o.ddi
+
+ The ``cmake -E cmake_ninja_dyndep`` tool reads the "ddi" files from all
+ sources in the target and the ``FortranModules.json`` files from targets
+ on which the target depends. It computes dependency edges on compilations
+ that require modules to those that provide the modules. This information
+ is placed in the ``Fortran.dd`` file for ninja to load later. It also
+ writes the expected location of modules provided by this target into
+ ``FortranModules.json`` for use by dependent targets.
+
+3. Compile all sources after loading dynamically discovered dependencies
+ of the compilation build statements from their ``dyndep`` bindings.
+
+ rule Fortran_COMPILE
+ command = gfortran $INCLUDES $FLAGS -c $in -o $out
+
+ build src1.f90.o: Fortran_COMPILE src1.f90-pp.f90 || Fortran.dd
+ dyndep = Fortran.dd
+
+ The "dyndep" binding tells ninja to load dynamically discovered
+ dependency information from ``Fortran.dd``. This adds information
+ such as:
+
+ build src1.f90.o | mod1.mod: dyndep
+ restat = 1
+
+ This tells ninja that ``mod1.mod`` is an implicit output of compiling
+ the object file ``src1.f90.o``. The ``restat`` binding tells it that
+ the timestamp of the output may not always change. Additionally:
+
+ build src2.f90.o: dyndep | mod1.mod
+
+ This tells ninja that ``mod1.mod`` is a dependency of compiling the
+ object file ``src2.f90.o``. This ensures that ``src1.f90.o`` and
+ ``mod1.mod`` will always be up to date before ``src2.f90.o`` is built
+ (because the latter consumes the module).
+*/
+
+static std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
+ std::string const& arg_tdi, std::string const& arg_pp);
+
+int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
+ std::vector<std::string>::const_iterator argEnd)
+{
+ std::string arg_tdi;
+ std::string arg_src;
+ std::string arg_pp;
+ std::string arg_dep;
+ std::string arg_obj;
+ std::string arg_ddi;
+ std::string arg_lang;
+ for (std::string const& arg : cmMakeRange(argBeg, argEnd)) {
+ if (cmHasLiteralPrefix(arg, "--tdi=")) {
+ arg_tdi = arg.substr(6);
+ } else if (cmHasLiteralPrefix(arg, "--src=")) {
+ arg_src = arg.substr(6);
+ } else if (cmHasLiteralPrefix(arg, "--pp=")) {
+ arg_pp = arg.substr(5);
+ } else if (cmHasLiteralPrefix(arg, "--dep=")) {
+ arg_dep = arg.substr(6);
+ } else if (cmHasLiteralPrefix(arg, "--obj=")) {
+ arg_obj = arg.substr(6);
+ } else if (cmHasLiteralPrefix(arg, "--ddi=")) {
+ arg_ddi = arg.substr(6);
+ } else if (cmHasLiteralPrefix(arg, "--lang=")) {
+ arg_lang = arg.substr(7);
+ } else {
+ cmSystemTools::Error(
+ cmStrCat("-E cmake_ninja_depends unknown argument: ", arg));
+ return 1;
+ }
+ }
+ if (arg_tdi.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_depends requires value for --tdi=");
+ return 1;
+ }
+ if (arg_pp.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_depends requires value for --pp=");
+ return 1;
+ }
+ if (arg_dep.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_depends requires value for --dep=");
+ return 1;
+ }
+ if (arg_obj.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_depends requires value for --obj=");
+ return 1;
+ }
+ if (arg_ddi.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_depends requires value for --ddi=");
+ return 1;
+ }
+ if (arg_lang.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_depends requires value for --lang=");
+ return 1;
+ }
+ if (arg_src.empty()) {
+ arg_src = cmStrCat("<", arg_obj, " input file>");
+ }
+
+ std::unique_ptr<cmSourceInfo> info;
+ if (arg_lang == "Fortran") {
+ info = cmcmd_cmake_ninja_depends_fortran(arg_tdi, arg_pp);
+ } else {
+ cmSystemTools::Error(
+ cmStrCat("-E cmake_ninja_depends does not understand the ", arg_lang,
+ " language"));
+ return 1;
+ }
+
+ if (!info) {
+ // The error message is already expected to have been output.
+ return 1;
+ }
+
+ info->PrimaryOutput = arg_obj;
+
+ {
+ cmGeneratedFileStream depfile(arg_dep);
+ depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":";
+ for (std::string const& include : info->Includes) {
+ depfile << " \\\n " << cmSystemTools::ConvertToUnixOutputPath(include);
+ }
+ depfile << "\n";
+ }
+
+ if (!cmScanDepFormat_P1689_Write(arg_ddi, arg_src, *info)) {
+ cmSystemTools::Error(
+ cmStrCat("-E cmake_ninja_depends failed to write ", arg_ddi));
+ return 1;
+ }
+ return 0;
+}
+
+std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
+ std::string const& arg_tdi, std::string const& arg_pp)
+{
+ cmFortranCompiler fc;
+ std::vector<std::string> includes;
+ {
+ Json::Value tdio;
+ Json::Value const& tdi = tdio;
+ {
+ cmsys::ifstream tdif(arg_tdi.c_str(), std::ios::in | std::ios::binary);
+ Json::Reader reader;
+ if (!reader.parse(tdif, tdio, false)) {
+ cmSystemTools::Error(
+ cmStrCat("-E cmake_ninja_depends failed to parse ", arg_tdi,
+ reader.getFormattedErrorMessages()));
+ return nullptr;
+ }
+ }
+
+ Json::Value const& tdi_include_dirs = tdi["include-dirs"];
+ if (tdi_include_dirs.isArray()) {
+ for (auto const& tdi_include_dir : tdi_include_dirs) {
+ includes.push_back(tdi_include_dir.asString());
+ }
+ }
+
+ Json::Value const& tdi_compiler_id = tdi["compiler-id"];
+ fc.Id = tdi_compiler_id.asString();
+
+ Json::Value const& tdi_submodule_sep = tdi["submodule-sep"];
+ fc.SModSep = tdi_submodule_sep.asString();
+
+ Json::Value const& tdi_submodule_ext = tdi["submodule-ext"];
+ fc.SModExt = tdi_submodule_ext.asString();
+ }
+
+ cmFortranSourceInfo finfo;
+ std::set<std::string> defines;
+ cmFortranParser parser(fc, includes, defines, finfo);
+ if (!cmFortranParser_FilePush(&parser, arg_pp.c_str())) {
+ cmSystemTools::Error(
+ cmStrCat("-E cmake_ninja_depends failed to open ", arg_pp));
+ return nullptr;
+ }
+ if (cmFortran_yyparse(parser.Scanner) != 0) {
+ // Failed to parse the file.
+ return nullptr;
+ }
+
+ auto info = cm::make_unique<cmSourceInfo>();
+ for (std::string const& provide : finfo.Provides) {
+ cmSourceReqInfo src_info;
+ src_info.LogicalName = provide;
+ src_info.CompiledModulePath = provide;
+ info->Provides.emplace_back(src_info);
+ }
+ for (std::string const& require : finfo.Requires) {
+ // Require modules not provided in the same source.
+ if (finfo.Provides.count(require)) {
+ continue;
+ }
+ cmSourceReqInfo src_info;
+ src_info.LogicalName = require;
+ src_info.CompiledModulePath = require;
+ info->Requires.emplace_back(src_info);
+ }
+ for (std::string const& include : finfo.Includes) {
+ info->Includes.push_back(include);
+ }
+ return info;
+}
+
+bool cmGlobalNinjaGenerator::WriteDyndepFile(
+ std::string const& dir_top_src, std::string const& dir_top_bld,
+ std::string const& dir_cur_src, std::string const& dir_cur_bld,
+ std::string const& arg_dd, std::vector<std::string> const& arg_ddis,
+ std::string const& module_dir,
+ std::vector<std::string> const& linked_target_dirs,
+ std::string const& arg_lang, std::string const& arg_modmapfmt)
+{
+ // Setup path conversions.
+ {
+ cmStateSnapshot snapshot = this->GetCMakeInstance()->GetCurrentSnapshot();
+ snapshot.GetDirectory().SetCurrentSource(dir_cur_src);
+ snapshot.GetDirectory().SetCurrentBinary(dir_cur_bld);
+ snapshot.GetDirectory().SetRelativePathTopSource(dir_top_src.c_str());
+ snapshot.GetDirectory().SetRelativePathTopBinary(dir_top_bld.c_str());
+ auto mfd = cm::make_unique<cmMakefile>(this, snapshot);
+ auto lgd = this->CreateLocalGenerator(mfd.get());
+ this->Makefiles.push_back(std::move(mfd));
+ this->LocalGenerators.push_back(std::move(lgd));
+ }
+
+ std::vector<cmSourceInfo> objects;
+ for (std::string const& arg_ddi : arg_ddis) {
+ cmSourceInfo info;
+ if (!cmScanDepFormat_P1689_Parse(arg_ddi, &info)) {
+ cmSystemTools::Error(
+ cmStrCat("-E cmake_ninja_dyndep failed to parse ddi file ", arg_ddi));
+ return false;
+ }
+ objects.push_back(std::move(info));
+ }
+
+ // Map from module name to module file path, if known.
+ std::map<std::string, std::string> mod_files;
+
+ // Populate the module map with those provided by linked targets first.
+ for (std::string const& linked_target_dir : linked_target_dirs) {
+ std::string const ltmn =
+ cmStrCat(linked_target_dir, "/", arg_lang, "Modules.json");
+ Json::Value ltm;
+ cmsys::ifstream ltmf(ltmn.c_str(), std::ios::in | std::ios::binary);
+ Json::Reader reader;
+ if (ltmf && !reader.parse(ltmf, ltm, false)) {
+ cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
+ linked_target_dir,
+ reader.getFormattedErrorMessages()));
+ return false;
+ }
+ if (ltm.isObject()) {
+ for (Json::Value::iterator i = ltm.begin(); i != ltm.end(); ++i) {
+ mod_files[i.key().asString()] = i->asString();
+ }
+ }
+ }
+
+ // Extend the module map with those provided by this target.
+ // We do this after loading the modules provided by linked targets
+ // in case we have one of the same name that must be preferred.
+ Json::Value tm = Json::objectValue;
+ for (cmSourceInfo const& object : objects) {
+ for (auto const& p : object.Provides) {
+ std::string const mod = cmStrCat(
+ module_dir, cmSystemTools::GetFilenameName(p.CompiledModulePath));
+ mod_files[p.LogicalName] = mod;
+ tm[p.LogicalName] = mod;
+ }
+ }
+
+ cmGeneratedFileStream ddf(arg_dd);
+ ddf << "ninja_dyndep_version = 1.0\n";
+
+ {
+ cmNinjaBuild build("dyndep");
+ build.Outputs.emplace_back("");
+ for (cmSourceInfo const& object : objects) {
+ build.Outputs[0] = this->ConvertToNinjaPath(object.PrimaryOutput);
+ build.ImplicitOuts.clear();
+ for (auto const& p : object.Provides) {
+ build.ImplicitOuts.push_back(
+ this->ConvertToNinjaPath(mod_files[p.LogicalName]));
+ }
+ build.ImplicitDeps.clear();
+ for (auto const& r : object.Requires) {
+ auto mit = mod_files.find(r.LogicalName);
+ if (mit != mod_files.end()) {
+ build.ImplicitDeps.push_back(this->ConvertToNinjaPath(mit->second));
+ }
+ }
+ build.Variables.clear();
+ if (!object.Provides.empty()) {
+ build.Variables.emplace("restat", "1");
+ }
+
+ if (arg_modmapfmt.empty()) {
+ // nothing to do.
+ } else {
+ std::stringstream mm;
+ if (arg_modmapfmt == "gcc") {
+ // Documented in GCC's documentation. The format is a series of lines
+ // with a module name and the associated filename separated by
+ // spaces. The first line may use `$root` as the module name to
+ // specify a "repository root". That is used to anchor any relative
+ // paths present in the file (CMake should never generate any).
+
+ // Write the root directory to use for module paths.
+ mm << "$root .\n";
+
+ for (auto const& l : object.Provides) {
+ auto m = mod_files.find(l.LogicalName);
+ if (m != mod_files.end()) {
+ mm << l.LogicalName << " " << this->ConvertToNinjaPath(m->second)
+ << "\n";
+ }
+ }
+ for (auto const& r : object.Requires) {
+ auto m = mod_files.find(r.LogicalName);
+ if (m != mod_files.end()) {
+ mm << r.LogicalName << " " << this->ConvertToNinjaPath(m->second)
+ << "\n";
+ }
+ }
+ } else {
+ cmSystemTools::Error(
+ cmStrCat("-E cmake_ninja_dyndep does not understand the ",
+ arg_modmapfmt, " module map format"));
+ return false;
+ }
+
+ // XXX(modmap): If changing this path construction, change
+ // `cmNinjaTargetGenerator::WriteObjectBuildStatements` to generate the
+ // corresponding file path.
+ cmGeneratedFileStream mmf(cmStrCat(object.PrimaryOutput, ".modmap"));
+ mmf << mm.str();
+ }
+
+ this->WriteBuild(ddf, build);
+ }
+ }
+
+ // Store the map of modules provided by this target in a file for
+ // use by dependents that reference this target in linked-target-dirs.
+ std::string const target_mods_file = cmStrCat(
+ cmSystemTools::GetFilenamePath(arg_dd), '/', arg_lang, "Modules.json");
+ cmGeneratedFileStream tmf(target_mods_file);
+ tmf << tm;
+
+ return true;
+}
+
+int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
+ std::vector<std::string>::const_iterator argEnd)
+{
+ std::vector<std::string> arg_full =
+ cmSystemTools::HandleResponseFile(argBeg, argEnd);
+
+ std::string arg_dd;
+ std::string arg_lang;
+ std::string arg_tdi;
+ std::string arg_modmapfmt;
+ std::vector<std::string> arg_ddis;
+ for (std::string const& arg : arg_full) {
+ if (cmHasLiteralPrefix(arg, "--tdi=")) {
+ arg_tdi = arg.substr(6);
+ } else if (cmHasLiteralPrefix(arg, "--lang=")) {
+ arg_lang = arg.substr(7);
+ } else if (cmHasLiteralPrefix(arg, "--dd=")) {
+ arg_dd = arg.substr(5);
+ } else if (cmHasLiteralPrefix(arg, "--modmapfmt=")) {
+ arg_modmapfmt = arg.substr(12);
+ } else if (!cmHasLiteralPrefix(arg, "--") &&
+ cmHasLiteralSuffix(arg, ".ddi")) {
+ arg_ddis.push_back(arg);
+ } else {
+ cmSystemTools::Error(
+ cmStrCat("-E cmake_ninja_dyndep unknown argument: ", arg));
+ return 1;
+ }
+ }
+ if (arg_tdi.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --tdi=");
+ return 1;
+ }
+ if (arg_lang.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --lang=");
+ return 1;
+ }
+ if (arg_dd.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --dd=");
+ return 1;
+ }
+
+ Json::Value tdio;
+ Json::Value const& tdi = tdio;
+ {
+ cmsys::ifstream tdif(arg_tdi.c_str(), std::ios::in | std::ios::binary);
+ Json::Reader reader;
+ if (!reader.parse(tdif, tdio, false)) {
+ cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
+ arg_tdi,
+ reader.getFormattedErrorMessages()));
+ return 1;
+ }
+ }
+
+ std::string const dir_cur_bld = tdi["dir-cur-bld"].asString();
+ std::string const dir_cur_src = tdi["dir-cur-src"].asString();
+ std::string const dir_top_bld = tdi["dir-top-bld"].asString();
+ std::string const dir_top_src = tdi["dir-top-src"].asString();
+ std::string module_dir = tdi["module-dir"].asString();
+ if (!module_dir.empty() && !cmHasLiteralSuffix(module_dir, "/")) {
+ module_dir += '/';
+ }
+ std::vector<std::string> linked_target_dirs;
+ Json::Value const& tdi_linked_target_dirs = tdi["linked-target-dirs"];
+ if (tdi_linked_target_dirs.isArray()) {
+ for (auto const& tdi_linked_target_dir : tdi_linked_target_dirs) {
+ linked_target_dirs.push_back(tdi_linked_target_dir.asString());
+ }
+ }
+
+ cmake cm(cmake::RoleInternal, cmState::Unknown);
+ cm.SetHomeDirectory(dir_top_src);
+ cm.SetHomeOutputDirectory(dir_top_bld);
+ auto ggd = cm.CreateGlobalGenerator("Ninja");
+ if (!ggd ||
+ !cm::static_reference_cast<cmGlobalNinjaGenerator>(ggd).WriteDyndepFile(
+ dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld, arg_dd, arg_ddis,
+ module_dir, linked_target_dirs, arg_lang, arg_modmapfmt)) {
+ return 1;
+ }
+ return 0;
+}
+
+#endif
+
+bool cmGlobalNinjaGenerator::EnableCrossConfigBuild() const
+{
+ return !this->CrossConfigs.empty();
+}
+
+void cmGlobalNinjaGenerator::AppendDirectoryForConfig(
+ const std::string& prefix, const std::string& config,
+ const std::string& suffix, std::string& dir)
+{
+ if (!config.empty() && this->IsMultiConfig()) {
+ dir += cmStrCat(prefix, config, suffix);
+ }
+}
+
+std::set<std::string> cmGlobalNinjaGenerator::GetCrossConfigs(
+ const std::string& fileConfig) const
+{
+ auto result = this->CrossConfigs;
+ result.insert(fileConfig);
+ return result;
+}
+
+bool cmGlobalNinjaGenerator::IsSingleConfigUtility(
+ cmGeneratorTarget const* target) const
+{
+ return target->GetType() == cmStateEnums::UTILITY &&
+ !this->PerConfigUtilityTargets.count(target->GetName());
+}
+
+const char* cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE =
+ "CMakeFiles/common.ninja";
+const char* cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION = ".ninja";
+
+cmGlobalNinjaMultiGenerator::cmGlobalNinjaMultiGenerator(cmake* cm)
+ : cmGlobalNinjaGenerator(cm)
+{
+ cm->GetState()->SetIsGeneratorMultiConfig(true);
+ cm->GetState()->SetNinjaMulti(true);
+}
+
+void cmGlobalNinjaMultiGenerator::GetDocumentation(cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalNinjaMultiGenerator::GetActualName();
+ entry.Brief = "Generates build-<Config>.ninja files.";
+}
+
+std::string cmGlobalNinjaMultiGenerator::ExpandCFGIntDir(
+ const std::string& str, const std::string& config) const
+{
+ std::string result = str;
+ cmSystemTools::ReplaceString(result, this->GetCMakeCFGIntDir(), config);
+ return result;
+}
+
+bool cmGlobalNinjaMultiGenerator::OpenBuildFileStreams()
+{
+ if (!this->OpenFileStream(this->CommonFileStream,
+ cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE)) {
+ return false;
+ }
+
+ if (!this->OpenFileStream(this->DefaultFileStream, NINJA_BUILD_FILE)) {
+ return false;
+ }
+ *this->DefaultFileStream << "# Build using rules for '"
+ << this->DefaultFileConfig << "'.\n\n"
+ << "include "
+ << GetNinjaImplFilename(this->DefaultFileConfig)
+ << "\n\n";
+
+ // Write a comment about this file.
+ *this->CommonFileStream
+ << "# This file contains build statements common to all "
+ "configurations.\n\n";
+
+ auto const& configs =
+ this->Makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ return std::all_of(
+ configs.begin(), configs.end(), [this](std::string const& config) -> bool {
+ // Open impl file.
+ if (!this->OpenFileStream(this->ImplFileStreams[config],
+ GetNinjaImplFilename(config))) {
+ return false;
+ }
+
+ // Write a comment about this file.
+ *this->ImplFileStreams[config]
+ << "# This file contains build statements specific to the \"" << config
+ << "\"\n# configuration.\n\n";
+
+ // Open config file.
+ if (!this->OpenFileStream(this->ConfigFileStreams[config],
+ GetNinjaConfigFilename(config))) {
+ return false;
+ }
+
+ // Write a comment about this file.
+ *this->ConfigFileStreams[config]
+ << "# This file contains aliases specific to the \"" << config
+ << "\"\n# configuration.\n\n"
+ << "include " << GetNinjaImplFilename(config) << "\n\n";
+
+ return true;
+ });
+}
+
+void cmGlobalNinjaMultiGenerator::CloseBuildFileStreams()
+{
+ if (this->CommonFileStream) {
+ this->CommonFileStream.reset();
+ } else {
+ cmSystemTools::Error("Common file stream was not open.");
+ }
+
+ if (this->DefaultFileStream) {
+ this->DefaultFileStream.reset();
+ } // No error if it wasn't open
+
+ for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs(
+ cmMakefile::IncludeEmptyConfig)) {
+ if (this->ImplFileStreams[config]) {
+ this->ImplFileStreams[config].reset();
+ } else {
+ cmSystemTools::Error(
+ cmStrCat("Impl file stream for \"", config, "\" was not open."));
+ }
+ if (this->ConfigFileStreams[config]) {
+ this->ConfigFileStreams[config].reset();
+ } else {
+ cmSystemTools::Error(
+ cmStrCat("Config file stream for \"", config, "\" was not open."));
+ }
+ }
+}
+
+void cmGlobalNinjaMultiGenerator::AppendNinjaFileArgument(
+ GeneratedMakeCommand& command, const std::string& config) const
+{
+ if (!config.empty()) {
+ command.Add("-f");
+ command.Add(GetNinjaConfigFilename(config));
+ }
+}
+
+std::string cmGlobalNinjaMultiGenerator::GetNinjaImplFilename(
+ const std::string& config)
+{
+ return cmStrCat("CMakeFiles/impl-", config,
+ cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION);
+}
+
+std::string cmGlobalNinjaMultiGenerator::GetNinjaConfigFilename(
+ const std::string& config)
+{
+ return cmStrCat("build-", config,
+ cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION);
+}
+
+void cmGlobalNinjaMultiGenerator::AddRebuildManifestOutputs(
+ cmNinjaDeps& outputs) const
+{
+ for (auto const& config : this->Makefiles.front()->GetGeneratorConfigs(
+ cmMakefile::IncludeEmptyConfig)) {
+ outputs.push_back(this->NinjaOutputPath(GetNinjaImplFilename(config)));
+ outputs.push_back(this->NinjaOutputPath(GetNinjaConfigFilename(config)));
+ }
+ if (!this->DefaultFileConfig.empty()) {
+ outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE));
+ }
+}
+
+void cmGlobalNinjaMultiGenerator::GetQtAutoGenConfigs(
+ std::vector<std::string>& configs) const
+{
+ auto allConfigs =
+ this->Makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ configs.insert(configs.end(), cm::cbegin(allConfigs), cm::cend(allConfigs));
+}
+
+bool cmGlobalNinjaMultiGenerator::InspectConfigTypeVariables()
+{
+ std::vector<std::string> configsVec;
+ cmExpandList(
+ this->Makefiles.front()->GetSafeDefinition("CMAKE_CONFIGURATION_TYPES"),
+ configsVec);
+ if (configsVec.empty()) {
+ configsVec.emplace_back();
+ }
+ std::set<std::string> configs(configsVec.cbegin(), configsVec.cend());
+
+ this->DefaultFileConfig =
+ this->Makefiles.front()->GetSafeDefinition("CMAKE_DEFAULT_BUILD_TYPE");
+ if (this->DefaultFileConfig.empty()) {
+ this->DefaultFileConfig = configsVec.front();
+ }
+ if (!configs.count(this->DefaultFileConfig)) {
+ std::ostringstream msg;
+ msg << "The configuration specified by "
+ << "CMAKE_DEFAULT_BUILD_TYPE (" << this->DefaultFileConfig
+ << ") is not present in CMAKE_CONFIGURATION_TYPES";
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+ msg.str());
+ return false;
+ }
+
+ std::vector<std::string> crossConfigsVec;
+ cmExpandList(
+ this->Makefiles.front()->GetSafeDefinition("CMAKE_CROSS_CONFIGS"),
+ crossConfigsVec);
+ auto crossConfigs = ListSubsetWithAll(configs, configs, crossConfigsVec);
+ if (!crossConfigs) {
+ std::ostringstream msg;
+ msg << "CMAKE_CROSS_CONFIGS is not a subset of "
+ << "CMAKE_CONFIGURATION_TYPES";
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+ msg.str());
+ return false;
+ }
+ this->CrossConfigs = *crossConfigs;
+
+ auto defaultConfigsString =
+ this->Makefiles.front()->GetSafeDefinition("CMAKE_DEFAULT_CONFIGS");
+ if (defaultConfigsString.empty()) {
+ defaultConfigsString = this->DefaultFileConfig;
+ }
+ if (!defaultConfigsString.empty() &&
+ defaultConfigsString != this->DefaultFileConfig &&
+ (this->DefaultFileConfig.empty() || this->CrossConfigs.empty())) {
+ std::ostringstream msg;
+ msg << "CMAKE_DEFAULT_CONFIGS cannot be used without "
+ << "CMAKE_DEFAULT_BUILD_TYPE or CMAKE_CROSS_CONFIGS";
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+ msg.str());
+ return false;
+ }
+
+ std::vector<std::string> defaultConfigsVec;
+ cmExpandList(defaultConfigsString, defaultConfigsVec);
+ if (!this->DefaultFileConfig.empty()) {
+ auto defaultConfigs =
+ ListSubsetWithAll(this->GetCrossConfigs(this->DefaultFileConfig),
+ this->CrossConfigs, defaultConfigsVec);
+ if (!defaultConfigs) {
+ std::ostringstream msg;
+ msg << "CMAKE_DEFAULT_CONFIGS is not a subset of CMAKE_CROSS_CONFIGS";
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+ msg.str());
+ return false;
+ }
+ this->DefaultConfigs = *defaultConfigs;
+ }
+
+ return true;
+}
+
+std::string cmGlobalNinjaMultiGenerator::GetDefaultBuildConfig() const
+{
+ return "";
+}
+
+std::string cmGlobalNinjaMultiGenerator::OrderDependsTargetForTarget(
+ cmGeneratorTarget const* target, const std::string& config) const
+{
+ return cmStrCat("cmake_object_order_depends_target_", target->GetName(), '_',
+ cmSystemTools::UpperCase(config));
+}
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
new file mode 100644
index 0000000..9f31708
--- /dev/null
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -0,0 +1,725 @@
+/* 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 <iosfwd>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+
+#include "cm_codecvt.hxx"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalCommonGenerator.h"
+#include "cmGlobalGeneratorFactory.h"
+#include "cmNinjaTypes.h"
+#include "cmPolicies.h"
+#include "cmStringAlgorithms.h"
+#include "cmTransformDepfile.h"
+
+class cmCustomCommand;
+class cmGeneratorTarget;
+class cmLinkLineComputer;
+class cmLocalGenerator;
+class cmMakefile;
+class cmOutputConverter;
+class cmStateDirectory;
+class cmake;
+struct cmDocumentationEntry;
+
+/**
+ * \class cmGlobalNinjaGenerator
+ * \brief Write a build.ninja file.
+ *
+ * The main differences between this generator and the UnixMakefile
+ * generator family are:
+ * - We don't care about VERBOSE variable or RULE_MESSAGES property since
+ * it is handle by Ninja's -v option.
+ * - We don't care about computing any progress status since Ninja manages
+ * it itself.
+ * - We generate one build.ninja and one rules.ninja per project.
+ * - We try to minimize the number of generated rules: one per target and
+ * language.
+ * - We use Ninja special variable $in and $out to produce nice output.
+ * - We extensively use Ninja variable overloading system to minimize the
+ * number of generated rules.
+ */
+class cmGlobalNinjaGenerator : public cmGlobalCommonGenerator
+{
+public:
+ /// The default name of Ninja's build file. Typically: build.ninja.
+ static const char* NINJA_BUILD_FILE;
+
+ /// The default name of Ninja's rules file. Typically: rules.ninja.
+ /// It is included in the main build.ninja file.
+ static const char* NINJA_RULES_FILE;
+
+ /// The indentation string used when generating Ninja's build file.
+ static const char* INDENT;
+
+ /// The shell command used for a no-op.
+ static std::string const SHELL_NOOP;
+
+ /// Write @a count times INDENT level to output stream @a os.
+ static void Indent(std::ostream& os, int count);
+
+ /// Write a divider in the given output stream @a os.
+ static void WriteDivider(std::ostream& os);
+
+ static std::string EncodeRuleName(std::string const& name);
+ std::string EncodeLiteral(const std::string& lit);
+ std::string EncodePath(const std::string& path);
+
+ std::unique_ptr<cmLinkLineComputer> CreateLinkLineComputer(
+ cmOutputConverter* outputConverter,
+ cmStateDirectory const& stateDir) const override;
+
+ /**
+ * Write the given @a comment to the output stream @a os. It
+ * handles new line character properly.
+ */
+ static void WriteComment(std::ostream& os, const std::string& comment);
+
+ /**
+ * Utilized by the generator factory to determine if this generator
+ * supports toolsets.
+ */
+ static bool SupportsToolset() { return false; }
+
+ /**
+ * Utilized by the generator factory to determine if this generator
+ * supports platforms.
+ */
+ static bool SupportsPlatform() { return false; }
+
+ bool IsIPOSupported() const override { return true; }
+
+ /**
+ * Write a build statement @a build to @a os.
+ * @warning no escaping of any kind is done here.
+ */
+ void WriteBuild(std::ostream& os, cmNinjaBuild const& build,
+ int cmdLineLimit = 0, bool* usedResponseFile = nullptr);
+
+ void WriteCustomCommandBuild(
+ const std::string& command, const std::string& description,
+ const std::string& comment, const std::string& depfile,
+ const std::string& pool, bool uses_terminal, bool restat,
+ const cmNinjaDeps& outputs, const std::string& config,
+ const cmNinjaDeps& explicitDeps = cmNinjaDeps(),
+ const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps());
+
+ void WriteMacOSXContentBuild(std::string input, std::string output,
+ const std::string& config);
+
+ /**
+ * Write a rule statement to @a os.
+ * @warning no escaping of any kind is done here.
+ */
+ static void WriteRule(std::ostream& os, cmNinjaRule const& rule);
+
+ /**
+ * Write a variable named @a name to @a os with value @a value and an
+ * optional @a comment. An @a indent level can be specified.
+ * @warning no escaping of any kind is done here.
+ */
+ static void WriteVariable(std::ostream& os, const std::string& name,
+ const std::string& value,
+ const std::string& comment = "", int indent = 0);
+
+ /**
+ * Write an include statement including @a filename with an optional
+ * @a comment to the @a os stream.
+ */
+ static void WriteInclude(std::ostream& os, const std::string& filename,
+ const std::string& comment = "");
+
+ /**
+ * Write a default target statement specifying @a targets as
+ * the default targets.
+ */
+ static void WriteDefault(std::ostream& os, const cmNinjaDeps& targets,
+ const std::string& comment = "");
+
+ bool IsGCCOnWindows() const { return this->UsingGCCOnWindows; }
+
+ cmGlobalNinjaGenerator(cmake* cm);
+
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
+ {
+ return std::unique_ptr<cmGlobalGeneratorFactory>(
+ new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaGenerator>());
+ }
+
+ std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+ cmMakefile* mf) override;
+
+ std::string GetName() const override
+ {
+ return cmGlobalNinjaGenerator::GetActualName();
+ }
+
+ static std::string GetActualName() { return "Ninja"; }
+
+ bool IsNinja() const override { return true; }
+
+ /** Get encoding used by generator for ninja files */
+ codecvt::Encoding GetMakefileEncoding() const override;
+
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ void EnableLanguage(std::vector<std::string> const& languages,
+ cmMakefile* mf, bool optional) override;
+
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
+
+ // Setup target names
+ const char* GetAllTargetName() const override { return "all"; }
+ const char* GetInstallTargetName() const override { return "install"; }
+ const char* GetInstallLocalTargetName() const override
+ {
+ return "install/local";
+ }
+ const char* GetInstallStripTargetName() const override
+ {
+ return "install/strip";
+ }
+ const char* GetTestTargetName() const override { return "test"; }
+ const char* GetPackageTargetName() const override { return "package"; }
+ const char* GetPackageSourceTargetName() const override
+ {
+ return "package_source";
+ }
+ const char* GetEditCacheTargetName() const override { return "edit_cache"; }
+ const char* GetRebuildCacheTargetName() const override
+ {
+ return "rebuild_cache";
+ }
+ const char* GetCleanTargetName() const override { return "clean"; }
+
+ bool SupportsCustomCommandDepfile() const override { return true; }
+ cm::optional<cmDepfileFormat> DepfileFormat() const override
+ {
+ return cmDepfileFormat::GccDepfile;
+ }
+
+ virtual cmGeneratedFileStream* GetImplFileStream(
+ const std::string& /*config*/) const
+ {
+ return this->BuildFileStream.get();
+ }
+
+ virtual cmGeneratedFileStream* GetConfigFileStream(
+ const std::string& /*config*/) const
+ {
+ return this->BuildFileStream.get();
+ }
+
+ virtual cmGeneratedFileStream* GetDefaultFileStream() const
+ {
+ return this->BuildFileStream.get();
+ }
+
+ virtual cmGeneratedFileStream* GetCommonFileStream() const
+ {
+ return this->BuildFileStream.get();
+ }
+
+ cmGeneratedFileStream* GetRulesFileStream() const
+ {
+ return this->RulesFileStream.get();
+ }
+
+ std::string const& ConvertToNinjaPath(const std::string& path) const;
+
+ struct MapToNinjaPathImpl
+ {
+ cmGlobalNinjaGenerator* GG;
+ MapToNinjaPathImpl(cmGlobalNinjaGenerator* gg)
+ : GG(gg)
+ {
+ }
+ std::string operator()(std::string const& path) const
+ {
+ return this->GG->ConvertToNinjaPath(path);
+ }
+ };
+ MapToNinjaPathImpl MapToNinjaPath() { return { this }; }
+
+ // -- Additional clean files
+ void AddAdditionalCleanFile(std::string fileName, const std::string& config);
+ const char* GetAdditionalCleanTargetName() const
+ {
+ return "CMakeFiles/clean.additional";
+ }
+
+ static const char* GetByproductsForCleanTargetName()
+ {
+ return "CMakeFiles/cmake_byproducts_for_clean_target";
+ }
+
+ void AddCXXCompileCommand(const std::string& commandLine,
+ const std::string& sourceFile);
+
+ /**
+ * Add a rule to the generated build system.
+ * Call WriteRule() behind the scene but perform some check before like:
+ * - Do not add twice the same rule.
+ */
+ void AddRule(cmNinjaRule const& rule);
+
+ bool HasRule(const std::string& name);
+
+ void AddCustomCommandRule();
+ void AddMacOSXContentRule();
+
+ bool HasCustomCommandOutput(const std::string& output)
+ {
+ return this->CustomCommandOutputs.find(output) !=
+ this->CustomCommandOutputs.end();
+ }
+
+ /// Called when we have seen the given custom command. Returns true
+ /// if we has seen it before.
+ bool SeenCustomCommand(cmCustomCommand const* cc, const std::string& config)
+ {
+ return !this->Configs[config].CustomCommands.insert(cc).second;
+ }
+
+ /// Called when we have seen the given custom command output.
+ void SeenCustomCommandOutput(const std::string& output)
+ {
+ this->CustomCommandOutputs.insert(output);
+ // We don't need the assumed dependencies anymore, because we have
+ // an output.
+ this->AssumedSourceDependencies.erase(output);
+ }
+
+ void AddAssumedSourceDependencies(const std::string& source,
+ const cmNinjaDeps& deps)
+ {
+ std::set<std::string>& ASD = this->AssumedSourceDependencies[source];
+ // Because we may see the same source file multiple times (same source
+ // specified in multiple targets), compute the union of any assumed
+ // dependencies.
+ ASD.insert(deps.begin(), deps.end());
+ }
+
+ virtual std::string OrderDependsTargetForTarget(
+ cmGeneratorTarget const* target, const std::string& config) const;
+
+ void AppendTargetOutputs(cmGeneratorTarget const* target,
+ cmNinjaDeps& outputs, const std::string& config,
+ cmNinjaTargetDepends depends) const;
+ void AppendTargetDepends(cmGeneratorTarget const* target,
+ cmNinjaDeps& outputs, const std::string& config,
+ const std::string& fileConfig,
+ cmNinjaTargetDepends depends);
+ void AppendTargetDependsClosure(cmGeneratorTarget const* target,
+ cmNinjaDeps& outputs,
+ const std::string& config,
+ const std::string& fileConfig,
+ bool genexOutput);
+ void AppendTargetDependsClosure(cmGeneratorTarget const* target,
+ cmNinjaOuts& outputs,
+ const std::string& config,
+ const std::string& fileConfig,
+ bool genexOutput, bool omit_self);
+
+ void AppendDirectoryForConfig(const std::string& prefix,
+ const std::string& config,
+ const std::string& suffix,
+ std::string& dir) override;
+
+ virtual void AppendNinjaFileArgument(GeneratedMakeCommand& /*command*/,
+ const std::string& /*config*/) const
+ {
+ }
+
+ virtual void AddRebuildManifestOutputs(cmNinjaDeps& outputs) const
+ {
+ outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE));
+ }
+
+ int GetRuleCmdLength(const std::string& name)
+ {
+ return this->RuleCmdLength[name];
+ }
+
+ void AddTargetAlias(const std::string& alias, cmGeneratorTarget* target,
+ const std::string& config);
+
+ void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;
+
+ // Ninja generator uses 'deps' and 'msvc_deps_prefix' introduced in 1.3
+ static std::string RequiredNinjaVersion() { return "1.3"; }
+ static std::string RequiredNinjaVersionForConsolePool() { return "1.5"; }
+ static std::string RequiredNinjaVersionForImplicitOuts() { return "1.7"; }
+ static std::string RequiredNinjaVersionForManifestRestat() { return "1.8"; }
+ static std::string RequiredNinjaVersionForMultilineDepfile()
+ {
+ return "1.9";
+ }
+ static std::string RequiredNinjaVersionForDyndeps() { return "1.10"; }
+ static std::string RequiredNinjaVersionForRestatTool() { return "1.10"; }
+ static std::string RequiredNinjaVersionForUnconditionalRecompactTool()
+ {
+ return "1.10";
+ }
+ static std::string RequiredNinjaVersionForMultipleOutputs()
+ {
+ return "1.10";
+ }
+ static std::string RequiredNinjaVersionForMetadataOnRegeneration()
+ {
+ return "1.10.2";
+ }
+ static std::string RequiredNinjaVersionForCodePage() { return "1.11"; }
+ bool SupportsConsolePool() const;
+ bool SupportsImplicitOuts() const;
+ bool SupportsManifestRestat() const;
+ bool SupportsMultilineDepfile() const;
+
+ std::string NinjaOutputPath(std::string const& path) const;
+ bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
+ void StripNinjaOutputPathPrefixAsSuffix(std::string& path);
+
+ bool WriteDyndepFile(
+ std::string const& dir_top_src, std::string const& dir_top_bld,
+ std::string const& dir_cur_src, std::string const& dir_cur_bld,
+ std::string const& arg_dd, std::vector<std::string> const& arg_ddis,
+ std::string const& module_dir,
+ std::vector<std::string> const& linked_target_dirs,
+ std::string const& arg_lang, std::string const& arg_modmapfmt);
+
+ virtual std::string BuildAlias(const std::string& alias,
+ const std::string& /*config*/) const
+ {
+ return alias;
+ }
+
+ virtual std::string ConfigDirectory(const std::string& /*config*/) const
+ {
+ return "";
+ }
+
+ cmNinjaDeps& GetByproductsForCleanTarget()
+ {
+ return this->ByproductsForCleanTarget;
+ }
+
+ cmNinjaDeps& GetByproductsForCleanTarget(const std::string& config)
+ {
+ return this->Configs[config].ByproductsForCleanTarget;
+ }
+
+ bool EnableCrossConfigBuild() const;
+
+ std::set<std::string> GetCrossConfigs(const std::string& config) const;
+
+ const std::set<std::string>& GetDefaultConfigs() const
+ {
+ return this->DefaultConfigs;
+ }
+
+ const std::set<std::string>& GetPerConfigUtilityTargets() const
+ {
+ return this->PerConfigUtilityTargets;
+ }
+
+ void AddPerConfigUtilityTarget(const std::string& name)
+ {
+ this->PerConfigUtilityTargets.insert(name);
+ }
+
+ bool IsSingleConfigUtility(cmGeneratorTarget const* target) const;
+
+ bool CheckCxxModuleSupport();
+
+protected:
+ void Generate() override;
+
+ bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const override { return true; }
+
+ virtual bool OpenBuildFileStreams();
+ virtual void CloseBuildFileStreams();
+
+ bool OpenFileStream(std::unique_ptr<cmGeneratedFileStream>& stream,
+ const std::string& name);
+
+ static cm::optional<std::set<std::string>> ListSubsetWithAll(
+ const std::set<std::string>& all, const std::set<std::string>& defaults,
+ const std::vector<std::string>& items);
+
+ virtual bool InspectConfigTypeVariables() { return true; }
+
+ std::set<std::string> CrossConfigs;
+ std::set<std::string> DefaultConfigs;
+ std::string DefaultFileConfig;
+
+private:
+ std::string GetEditCacheCommand() const override;
+ bool FindMakeProgram(cmMakefile* mf) override;
+ void CheckNinjaFeatures();
+ void CheckNinjaCodePage();
+ bool CheckLanguages(std::vector<std::string> const& languages,
+ cmMakefile* mf) const override;
+ bool CheckFortran(cmMakefile* mf) const;
+ bool CheckISPC(cmMakefile* mf) const;
+
+ void CloseCompileCommandsStream();
+
+ bool OpenRulesFileStream();
+ void CloseRulesFileStream();
+ void CleanMetaData();
+
+ /// Write the common disclaimer text at the top of each build file.
+ void WriteDisclaimer(std::ostream& os) const;
+
+ void WriteAssumedSourceDependencies();
+
+ void WriteTargetAliases(std::ostream& os);
+ void WriteFolderTargets(std::ostream& os);
+ void WriteUnknownExplicitDependencies(std::ostream& os);
+
+ void WriteBuiltinTargets(std::ostream& os);
+ void WriteTargetDefault(std::ostream& os);
+ void WriteTargetRebuildManifest(std::ostream& os);
+ bool WriteTargetCleanAdditional(std::ostream& os);
+ void WriteTargetClean(std::ostream& os);
+ void WriteTargetHelp(std::ostream& os);
+
+ void ComputeTargetDependsClosure(
+ cmGeneratorTarget const* target,
+ std::set<cmGeneratorTarget const*>& depends);
+
+ std::string CMakeCmd() const;
+ std::string NinjaCmd() const;
+
+ /// The file containing the build statement. (the relationship of the
+ /// compilation DAG).
+ std::unique_ptr<cmGeneratedFileStream> BuildFileStream;
+ /// The file containing the rule statements. (The action attached to each
+ /// edge of the compilation DAG).
+ std::unique_ptr<cmGeneratedFileStream> RulesFileStream;
+ std::unique_ptr<cmGeneratedFileStream> CompileCommandsStream;
+
+ /// The set of rules added to the generated build system.
+ std::unordered_set<std::string> Rules;
+
+ /// Length of rule command, used by rsp file evaluation
+ std::unordered_map<std::string, int> RuleCmdLength;
+
+ bool UsingGCCOnWindows = false;
+
+ /// The set of custom command outputs we have seen.
+ std::set<std::string> CustomCommandOutputs;
+
+ /// Whether we are collecting known build outputs and needed
+ /// dependencies to determine unknown dependencies.
+ bool ComputingUnknownDependencies = false;
+ cmPolicies::PolicyStatus PolicyCMP0058 = cmPolicies::WARN;
+
+ /// The combined explicit dependencies of custom build commands
+ std::set<std::string> CombinedCustomCommandExplicitDependencies;
+
+ /// When combined with CombinedCustomCommandExplicitDependencies it allows
+ /// us to detect the set of explicit dependencies that have
+ std::set<std::string> CombinedBuildOutputs;
+
+ /// The mapping from source file to assumed dependencies.
+ std::map<std::string, std::set<std::string>> AssumedSourceDependencies;
+
+ /// Utility targets which have per-config outputs
+ std::set<std::string> PerConfigUtilityTargets;
+
+ struct TargetAlias
+ {
+ cmGeneratorTarget* GeneratorTarget;
+ std::string Config;
+ };
+ using TargetAliasMap = std::map<std::string, TargetAlias>;
+ TargetAliasMap TargetAliases;
+ TargetAliasMap DefaultTargetAliases;
+
+ /// the local cache for calls to ConvertToNinjaPath
+ mutable std::unordered_map<std::string, std::string> ConvertToNinjaPathCache;
+
+ std::string NinjaCommand;
+ std::string NinjaVersion;
+ bool NinjaSupportsConsolePool = false;
+ bool NinjaSupportsImplicitOuts = false;
+ bool NinjaSupportsManifestRestat = false;
+ bool NinjaSupportsMultilineDepfile = false;
+ bool NinjaSupportsDyndeps = false;
+ bool NinjaSupportsRestatTool = false;
+ bool NinjaSupportsUnconditionalRecompactTool = false;
+ bool NinjaSupportsMultipleOutputs = false;
+ bool NinjaSupportsMetadataOnRegeneration = false;
+ bool NinjaSupportsCodePage = false;
+
+ codecvt::Encoding NinjaExpectedEncoding = codecvt::None;
+
+ bool DiagnosedCxxModuleSupport = false;
+
+ void InitOutputPathPrefix();
+
+ std::string OutputPathPrefix;
+ std::string TargetAll;
+ std::string CMakeCacheFile;
+ bool DisableCleandead = false;
+
+ struct ByConfig
+ {
+ std::set<std::string> AdditionalCleanFiles;
+
+ /// The set of custom commands we have seen.
+ std::set<cmCustomCommand const*> CustomCommands;
+
+ struct TargetDependsClosureKey
+ {
+ cmGeneratorTarget const* Target;
+ std::string Config;
+ bool GenexOutput;
+ };
+
+ std::map<TargetDependsClosureKey, cmNinjaOuts> TargetDependsClosures;
+
+ TargetAliasMap TargetAliases;
+
+ cmNinjaDeps ByproductsForCleanTarget;
+ };
+ std::map<std::string, ByConfig> Configs;
+
+ cmNinjaDeps ByproductsForCleanTarget;
+
+ friend bool operator==(const ByConfig::TargetDependsClosureKey& lhs,
+ const ByConfig::TargetDependsClosureKey& rhs);
+ friend bool operator!=(const ByConfig::TargetDependsClosureKey& lhs,
+ const ByConfig::TargetDependsClosureKey& rhs);
+ friend bool operator<(const ByConfig::TargetDependsClosureKey& lhs,
+ const ByConfig::TargetDependsClosureKey& rhs);
+ friend bool operator>(const ByConfig::TargetDependsClosureKey& lhs,
+ const ByConfig::TargetDependsClosureKey& rhs);
+ friend bool operator<=(const ByConfig::TargetDependsClosureKey& lhs,
+ const ByConfig::TargetDependsClosureKey& rhs);
+ friend bool operator>=(const ByConfig::TargetDependsClosureKey& lhs,
+ const ByConfig::TargetDependsClosureKey& rhs);
+};
+
+class cmGlobalNinjaMultiGenerator : public cmGlobalNinjaGenerator
+{
+public:
+ /// The default name of Ninja's common file. Typically: common.ninja.
+ static const char* NINJA_COMMON_FILE;
+ /// The default file extension to use for per-config Ninja files.
+ static const char* NINJA_FILE_EXTENSION;
+
+ cmGlobalNinjaMultiGenerator(cmake* cm);
+ bool IsMultiConfig() const override { return true; }
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
+ {
+ return std::unique_ptr<cmGlobalGeneratorFactory>(
+ new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaMultiGenerator>());
+ }
+
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ std::string GetName() const override
+ {
+ return cmGlobalNinjaMultiGenerator::GetActualName();
+ }
+
+ static std::string GetActualName() { return "Ninja Multi-Config"; }
+
+ std::string BuildAlias(const std::string& alias,
+ const std::string& config) const override
+ {
+ if (config.empty()) {
+ return alias;
+ }
+ return cmStrCat(alias, ":", config);
+ }
+
+ std::string ConfigDirectory(const std::string& config) const override
+ {
+ if (!config.empty()) {
+ return cmStrCat('/', config);
+ }
+ return "";
+ }
+
+ const char* GetCMakeCFGIntDir() const override { return "${CONFIGURATION}"; }
+
+ std::string ExpandCFGIntDir(const std::string& str,
+ const std::string& config) const override;
+
+ cmGeneratedFileStream* GetImplFileStream(
+ const std::string& config) const override
+ {
+ return this->ImplFileStreams.at(config).get();
+ }
+
+ cmGeneratedFileStream* GetConfigFileStream(
+ const std::string& config) const override
+ {
+ return this->ConfigFileStreams.at(config).get();
+ }
+
+ cmGeneratedFileStream* GetDefaultFileStream() const override
+ {
+ return this->DefaultFileStream.get();
+ }
+
+ cmGeneratedFileStream* GetCommonFileStream() const override
+ {
+ return this->CommonFileStream.get();
+ }
+
+ void AppendNinjaFileArgument(GeneratedMakeCommand& command,
+ const std::string& config) const override;
+
+ static std::string GetNinjaImplFilename(const std::string& config);
+ static std::string GetNinjaConfigFilename(const std::string& config);
+
+ void AddRebuildManifestOutputs(cmNinjaDeps& outputs) const override;
+
+ void GetQtAutoGenConfigs(std::vector<std::string>& configs) const override;
+
+ bool InspectConfigTypeVariables() override;
+
+ std::string GetDefaultBuildConfig() const override;
+
+ bool SupportsDefaultBuildType() const override { return true; }
+ bool SupportsCrossConfigs() const override { return true; }
+ bool SupportsDefaultConfigs() const override { return true; }
+
+ std::string OrderDependsTargetForTarget(
+ cmGeneratorTarget const* target, const std::string& config) const override;
+
+protected:
+ bool OpenBuildFileStreams() override;
+ void CloseBuildFileStreams() override;
+
+private:
+ std::map<std::string, std::unique_ptr<cmGeneratedFileStream>>
+ ImplFileStreams;
+ std::map<std::string, std::unique_ptr<cmGeneratedFileStream>>
+ ConfigFileStreams;
+ std::unique_ptr<cmGeneratedFileStream> CommonFileStream;
+ std::unique_ptr<cmGeneratedFileStream> DefaultFileStream;
+};
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
new file mode 100644
index 0000000..97384cd
--- /dev/null
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -0,0 +1,1014 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalUnixMakefileGenerator3.h"
+
+#include <algorithm>
+#include <functional>
+#include <sstream>
+#include <utility>
+
+#include <cm/memory>
+#include <cmext/algorithm>
+#include <cmext/memory>
+
+#include "cmDocumentationEntry.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmMakefileTargetGenerator.h"
+#include "cmOutputConverter.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTargetDepend.h"
+#include "cmake.h"
+
+cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3(cmake* cm)
+ : cmGlobalCommonGenerator(cm)
+{
+ // This type of makefile always requires unix style paths
+ this->ForceUnixPaths = true;
+ this->FindMakeProgramFile = "CMakeUnixFindMake.cmake";
+ this->ToolSupportsColor = true;
+
+#if defined(_WIN32) || defined(__VMS)
+ this->UseLinkScript = false;
+#else
+ this->UseLinkScript = true;
+#endif
+
+ this->IncludeDirective = "include";
+ this->LineContinueDirective = "\\\n";
+ this->DefineWindowsNULL = false;
+ this->PassMakeflags = false;
+ this->UnixCD = true;
+}
+
+cmGlobalUnixMakefileGenerator3::~cmGlobalUnixMakefileGenerator3() = default;
+
+void cmGlobalUnixMakefileGenerator3::EnableLanguage(
+ std::vector<std::string> const& languages, cmMakefile* mf, bool optional)
+{
+ this->cmGlobalGenerator::EnableLanguage(languages, mf, optional);
+ for (std::string const& language : languages) {
+ if (language == "NONE") {
+ continue;
+ }
+ this->ResolveLanguageCompiler(language, mf, optional);
+ }
+}
+
+//! Create a local generator appropriate to this Global Generator
+std::unique_ptr<cmLocalGenerator>
+cmGlobalUnixMakefileGenerator3::CreateLocalGenerator(cmMakefile* mf)
+{
+ return std::unique_ptr<cmLocalGenerator>(
+ cm::make_unique<cmLocalUnixMakefileGenerator3>(this, mf));
+}
+
+void cmGlobalUnixMakefileGenerator3::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalUnixMakefileGenerator3::GetActualName();
+ entry.Brief = "Generates standard UNIX makefiles.";
+}
+
+std::string cmGlobalUnixMakefileGenerator3::GetEditCacheCommand() const
+{
+ // If generating for an extra IDE, the edit_cache target cannot
+ // launch a terminal-interactive tool, so always use cmake-gui.
+ if (!this->GetExtraGeneratorName().empty()) {
+ return cmSystemTools::GetCMakeGUICommand();
+ }
+
+ // Use an internal cache entry to track the latest dialog used
+ // to edit the cache, and use that for the edit_cache target.
+ cmake* cm = this->GetCMakeInstance();
+ std::string editCacheCommand = cm->GetCMakeEditCommand();
+ if (!cm->GetCacheDefinition("CMAKE_EDIT_COMMAND") ||
+ !editCacheCommand.empty()) {
+ if (editCacheCommand.empty()) {
+ editCacheCommand = cmSystemTools::GetCMakeCursesCommand();
+ }
+ if (editCacheCommand.empty()) {
+ editCacheCommand = cmSystemTools::GetCMakeGUICommand();
+ }
+ if (!editCacheCommand.empty()) {
+ cm->AddCacheEntry("CMAKE_EDIT_COMMAND", editCacheCommand.c_str(),
+ "Path to cache edit program executable.",
+ cmStateEnums::INTERNAL);
+ }
+ }
+ cmProp edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND");
+ return edit_cmd ? *edit_cmd : std::string();
+}
+
+void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory(
+ cmGeneratorTarget* gt) const
+{
+ // Compute full path to object file directory for this target.
+ std::string dir =
+ cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(), '/',
+ gt->LocalGenerator->GetTargetDirectory(gt), '/');
+ gt->ObjectDirectory = dir;
+}
+
+bool cmGlobalUnixMakefileGenerator3::CanEscapeOctothorpe() const
+{
+ // Make tools that use UNIX-style '/' paths also support '\' escaping.
+ return this->ForceUnixPaths;
+}
+
+void cmGlobalUnixMakefileGenerator3::Configure()
+{
+ // Initialize CMAKE_EDIT_COMMAND cache entry.
+ this->GetEditCacheCommand();
+
+ this->cmGlobalGenerator::Configure();
+}
+
+void cmGlobalUnixMakefileGenerator3::Generate()
+{
+ // first do superclass method
+ this->cmGlobalGenerator::Generate();
+
+ // initialize progress
+ unsigned long total = 0;
+ for (auto const& pmi : this->ProgressMap) {
+ total += pmi.second.NumberOfActions;
+ }
+
+ // write each target's progress.make this loop is done twice. Basically the
+ // Generate pass counts all the actions, the first loop below determines
+ // how many actions have progress updates for each target and writes to
+ // corrrect variable values for everything except the all targets. The
+ // second loop actually writes out correct values for the all targets as
+ // well. This is because the all targets require more information that is
+ // computed in the first loop.
+ unsigned long current = 0;
+ for (auto& pmi : this->ProgressMap) {
+ pmi.second.WriteProgressVariables(total, current);
+ }
+ for (const auto& lg : this->LocalGenerators) {
+ std::string markFileName =
+ cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles/progress.marks");
+ cmGeneratedFileStream markFile(markFileName);
+ markFile << this->CountProgressMarksInAll(*lg) << "\n";
+ }
+
+ // write the main makefile
+ this->WriteMainMakefile2();
+ this->WriteMainCMakefile();
+
+ if (this->CommandDatabase) {
+ *this->CommandDatabase << "\n]";
+ this->CommandDatabase.reset();
+ }
+}
+
+void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand(
+ const std::string& sourceFile, const std::string& workingDirectory,
+ const std::string& compileCommand)
+{
+ if (!this->CommandDatabase) {
+ std::string commandDatabaseName =
+ this->GetCMakeInstance()->GetHomeOutputDirectory() +
+ "/compile_commands.json";
+ this->CommandDatabase =
+ cm::make_unique<cmGeneratedFileStream>(commandDatabaseName);
+ *this->CommandDatabase << "[\n";
+ } else {
+ *this->CommandDatabase << ",\n";
+ }
+ *this->CommandDatabase << "{\n"
+ << R"( "directory": ")"
+ << cmGlobalGenerator::EscapeJSON(workingDirectory)
+ << "\",\n"
+ << R"( "command": ")"
+ << cmGlobalGenerator::EscapeJSON(compileCommand)
+ << "\",\n"
+ << R"( "file": ")"
+ << cmGlobalGenerator::EscapeJSON(sourceFile)
+ << "\"\n}";
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
+{
+ // Open the output file. This should not be copy-if-different
+ // because the check-build-system step compares the makefile time to
+ // see if the build system must be regenerated.
+ std::string makefileName =
+ cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(),
+ "/CMakeFiles/Makefile2");
+ cmGeneratedFileStream makefileStream(makefileName, false,
+ this->GetMakefileEncoding());
+ if (!makefileStream) {
+ return;
+ }
+
+ // get a local generator for some useful methods
+ auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
+ this->LocalGenerators[0]);
+
+ // Write the do not edit header.
+ lg.WriteDisclaimer(makefileStream);
+
+ // Write the main entry point target. This must be the VERY first
+ // target so that make with no arguments will run it.
+ // Just depend on the all target to drive the build.
+ std::vector<std::string> depends;
+ std::vector<std::string> no_commands;
+ depends.emplace_back("all");
+
+ // Write the rule.
+ lg.WriteMakeRule(makefileStream,
+ "Default target executed when no arguments are "
+ "given to make.",
+ "default_target", depends, no_commands, true);
+
+ depends.clear();
+
+ // The all and preinstall rules might never have any dependencies
+ // added to them.
+ if (!this->EmptyRuleHackDepends.empty()) {
+ depends.push_back(this->EmptyRuleHackDepends);
+ }
+
+ // Write out the "special" stuff
+ lg.WriteSpecialTargetsTop(makefileStream);
+
+ // Write the directory level rules.
+ for (auto const& it : this->ComputeDirectoryTargets()) {
+ this->WriteDirectoryRules2(makefileStream, it.second);
+ }
+
+ // Write the target convenience rules
+ for (const auto& localGen : this->LocalGenerators) {
+ this->WriteConvenienceRules2(
+ makefileStream,
+ cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen));
+ }
+
+ // Write special bottom targets
+ lg.WriteSpecialTargetsBottom(makefileStream);
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
+{
+ if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
+ return;
+ }
+
+ // Open the output file. This should not be copy-if-different
+ // because the check-build-system step compares the makefile time to
+ // see if the build system must be regenerated.
+ std::string cmakefileName =
+ cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(),
+ "/CMakeFiles/Makefile.cmake");
+ cmGeneratedFileStream cmakefileStream(cmakefileName);
+ if (!cmakefileStream) {
+ return;
+ }
+
+ std::string makefileName =
+ cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), "/Makefile");
+
+ {
+ // get a local generator for some useful methods
+ auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
+ this->LocalGenerators[0]);
+
+ // Write the do not edit header.
+ lg.WriteDisclaimer(cmakefileStream);
+ }
+
+ // Save the generator name
+ cmakefileStream << "# The generator used is:\n"
+ << "set(CMAKE_DEPENDS_GENERATOR \"" << this->GetName()
+ << "\")\n\n";
+
+ // for each cmMakefile get its list of dependencies
+ std::vector<std::string> lfiles;
+ for (const auto& localGen : this->LocalGenerators) {
+ // Get the list of files contributing to this generation step.
+ cm::append(lfiles, localGen->GetMakefile()->GetListFiles());
+ }
+
+ cmake* cm = this->GetCMakeInstance();
+ if (cm->DoWriteGlobVerifyTarget()) {
+ lfiles.push_back(cm->GetGlobVerifyScript());
+ lfiles.push_back(cm->GetGlobVerifyStamp());
+ }
+
+ // Sort the list and remove duplicates.
+ std::sort(lfiles.begin(), lfiles.end(), std::less<std::string>());
+#if !defined(__VMS) // The Compaq STL on VMS crashes, so accept duplicates.
+ auto new_end = std::unique(lfiles.begin(), lfiles.end());
+ lfiles.erase(new_end, lfiles.end());
+#endif
+
+ {
+ // reset lg to the first makefile
+ const auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
+ this->LocalGenerators[0]);
+
+ const std::string& currentBinDir = lg.GetCurrentBinaryDirectory();
+ // Save the list to the cmake file.
+ cmakefileStream
+ << "# The top level Makefile was generated from the following files:\n"
+ << "set(CMAKE_MAKEFILE_DEPENDS\n"
+ << " \"CMakeCache.txt\"\n";
+ for (std::string const& f : lfiles) {
+ cmakefileStream << " \""
+ << lg.MaybeConvertToRelativePath(currentBinDir, f)
+ << "\"\n";
+ }
+ cmakefileStream << " )\n\n";
+
+ // Build the path to the cache check file.
+ std::string check =
+ cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(),
+ "/CMakeFiles/cmake.check_cache");
+
+ // Set the corresponding makefile in the cmake file.
+ cmakefileStream << "# The corresponding makefile is:\n"
+ << "set(CMAKE_MAKEFILE_OUTPUTS\n"
+ << " \""
+ << lg.MaybeConvertToRelativePath(currentBinDir,
+ makefileName)
+ << "\"\n"
+ << " \""
+ << lg.MaybeConvertToRelativePath(currentBinDir, check)
+ << "\"\n";
+ cmakefileStream << " )\n\n";
+
+ const std::string& binDir = lg.GetBinaryDirectory();
+
+ // CMake must rerun if a byproduct is missing.
+ cmakefileStream << "# Byproducts of CMake generate step:\n"
+ << "set(CMAKE_MAKEFILE_PRODUCTS\n";
+
+ // add in any byproducts and all the directory information files
+ std::string tmpStr;
+ for (const auto& localGen : this->LocalGenerators) {
+ for (std::string const& outfile :
+ localGen->GetMakefile()->GetOutputFiles()) {
+ cmakefileStream << " \""
+ << lg.MaybeConvertToRelativePath(binDir, outfile)
+ << "\"\n";
+ }
+ tmpStr = cmStrCat(localGen->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/CMakeDirectoryInformation.cmake");
+ cmakefileStream << " \""
+ << localGen->MaybeConvertToRelativePath(binDir, tmpStr)
+ << "\"\n";
+ }
+ cmakefileStream << " )\n\n";
+ }
+
+ this->WriteMainCMakefileLanguageRules(cmakefileStream,
+ this->LocalGenerators);
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteMainCMakefileLanguageRules(
+ cmGeneratedFileStream& cmakefileStream,
+ std::vector<std::unique_ptr<cmLocalGenerator>>& lGenerators)
+{
+ // now list all the target info files
+ cmakefileStream << "# Dependency information for all targets:\n";
+ cmakefileStream << "set(CMAKE_DEPEND_INFO_FILES\n";
+ for (const auto& lGenerator : lGenerators) {
+ const auto& lg =
+ cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(lGenerator);
+ // for all of out targets
+ for (const auto& tgt : lg.GetGeneratorTargets()) {
+ if (tgt->IsInBuildSystem() &&
+ tgt->GetType() != cmStateEnums::GLOBAL_TARGET) {
+ std::string tname = cmStrCat(lg.GetRelativeTargetDirectory(tgt.get()),
+ "/DependInfo.cmake");
+ cmSystemTools::ConvertToUnixSlashes(tname);
+ cmakefileStream << " \"" << tname << "\"\n";
+ }
+ }
+ }
+ cmakefileStream << " )\n";
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
+ std::ostream& ruleFileStream, DirectoryTarget const& dt, const char* pass,
+ bool check_all, bool check_relink, std::vector<std::string> const& commands)
+{
+ auto* lg = static_cast<cmLocalUnixMakefileGenerator3*>(dt.LG);
+ std::string makeTarget =
+ cmStrCat(lg->GetCurrentBinaryDirectory(), '/', pass);
+
+ // The directory-level rule should depend on the target-level rules
+ // for all targets in the directory.
+ std::vector<std::string> depends;
+ for (DirectoryTarget::Target const& t : dt.Targets) {
+ // Add this to the list of depends rules in this directory.
+ if ((!check_all || t.ExcludedFromAllInConfigs.empty()) &&
+ (!check_relink ||
+ t.GT->NeedRelinkBeforeInstall(lg->GetConfigName()))) {
+ // The target may be from a different directory; use its local gen.
+ auto const* tlg = static_cast<cmLocalUnixMakefileGenerator3 const*>(
+ t.GT->GetLocalGenerator());
+ std::string tname =
+ cmStrCat(tlg->GetRelativeTargetDirectory(t.GT), '/', pass);
+ depends.push_back(std::move(tname));
+ }
+ }
+
+ // The directory-level rule should depend on the directory-level
+ // rules of the subdirectories.
+ for (DirectoryTarget::Dir const& d : dt.Children) {
+ if (check_all && d.ExcludeFromAll) {
+ continue;
+ }
+ std::string subdir = cmStrCat(d.Path, '/', pass);
+ depends.push_back(std::move(subdir));
+ }
+
+ // Work-around for makes that drop rules that have no dependencies
+ // or commands.
+ if (depends.empty() && !this->EmptyRuleHackDepends.empty()) {
+ depends.push_back(this->EmptyRuleHackDepends);
+ }
+
+ // Write the rule.
+ std::string doc;
+ if (lg->IsRootMakefile()) {
+ doc = cmStrCat("The main recursive \"", pass, "\" target.");
+ } else {
+ doc = cmStrCat("Recursive \"", pass, "\" directory target.");
+ }
+ lg->WriteMakeRule(ruleFileStream, doc.c_str(), makeTarget, depends, commands,
+ true);
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2(
+ std::ostream& ruleFileStream, DirectoryTarget const& dt)
+{
+ auto* lg = static_cast<cmLocalUnixMakefileGenerator3*>(dt.LG);
+ // Begin the directory-level rules section.
+ {
+ std::string dir =
+ cmSystemTools::ConvertToOutputPath(lg->MaybeConvertToRelativePath(
+ lg->GetBinaryDirectory(), lg->GetCurrentBinaryDirectory()));
+ lg->WriteDivider(ruleFileStream);
+ if (lg->IsRootMakefile()) {
+ ruleFileStream << "# Directory level rules for the build root directory";
+ } else {
+ ruleFileStream << "# Directory level rules for directory " << dir;
+ }
+ ruleFileStream << "\n\n";
+ }
+
+ // Write directory-level rules for "all".
+ this->WriteDirectoryRule2(ruleFileStream, dt, "all", true, false);
+
+ // Write directory-level rules for "preinstall".
+ this->WriteDirectoryRule2(ruleFileStream, dt, "preinstall", true, true);
+
+ // Write directory-level rules for "clean".
+ {
+ std::vector<std::string> cmds;
+ lg->AppendDirectoryCleanCommand(cmds);
+ this->WriteDirectoryRule2(ruleFileStream, dt, "clean", false, false, cmds);
+ }
+}
+
+namespace {
+std::string ConvertToMakefilePathForUnix(std::string const& path)
+{
+ std::string result;
+ result.reserve(path.size());
+ for (char c : path) {
+ switch (c) {
+ case '=':
+ // We provide 'EQUALS = =' to encode '=' in a non-assignment case.
+ result.append("$(EQUALS)");
+ break;
+ case '$':
+ result.append("$$");
+ break;
+ case '\\':
+ case ' ':
+ case '#':
+ result.push_back('\\');
+ CM_FALLTHROUGH;
+ default:
+ result.push_back(c);
+ break;
+ }
+ }
+ return result;
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+std::string ConvertToMakefilePathForWindows(std::string const& path)
+{
+ bool const quote = path.find_first_of(" #") != std::string::npos;
+ std::string result;
+ result.reserve(path.size() + (quote ? 2 : 0));
+ if (quote) {
+ result.push_back('"');
+ }
+ for (char c : path) {
+ switch (c) {
+ case '=':
+ // We provide 'EQUALS = =' to encode '=' in a non-assignment case.
+ result.append("$(EQUALS)");
+ break;
+ case '$':
+ result.append("$$");
+ break;
+ case '/':
+ result.push_back('\\');
+ break;
+ default:
+ result.push_back(c);
+ break;
+ }
+ }
+ if (quote) {
+ result.push_back('"');
+ }
+ return result;
+}
+#endif
+}
+
+std::string cmGlobalUnixMakefileGenerator3::ConvertToMakefilePath(
+ std::string const& path) const
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (!this->ForceUnixPaths) {
+ return ConvertToMakefilePathForWindows(path);
+ }
+#endif
+ return ConvertToMakefilePathForUnix(path);
+}
+
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& /*projectName*/,
+ const std::string& /*projectDir*/,
+ std::vector<std::string> const& targetNames, const std::string& /*config*/,
+ bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions)
+{
+ std::unique_ptr<cmMakefile> mfu;
+ cmMakefile* mf;
+ if (!this->Makefiles.empty()) {
+ mf = this->Makefiles[0].get();
+ } else {
+ cmStateSnapshot snapshot = this->CMakeInstance->GetCurrentSnapshot();
+ snapshot.GetDirectory().SetCurrentSource(
+ this->CMakeInstance->GetHomeDirectory());
+ snapshot.GetDirectory().SetCurrentBinary(
+ this->CMakeInstance->GetHomeOutputDirectory());
+ snapshot.SetDefaultDefinitions();
+ mfu = cm::make_unique<cmMakefile>(this, snapshot);
+ mf = mfu.get();
+ }
+
+ GeneratedMakeCommand makeCommand;
+
+ // Make it possible to set verbosity also from command line
+ if (verbose) {
+ makeCommand.Add(cmSystemTools::GetCMakeCommand());
+ makeCommand.Add("-E");
+ makeCommand.Add("env");
+ makeCommand.Add("VERBOSE=1");
+ }
+ makeCommand.Add(this->SelectMakeProgram(makeProgram));
+
+ // Explicitly tell the make tool to use the Makefile written by
+ // cmLocalUnixMakefileGenerator3::WriteLocalMakefile
+ makeCommand.Add("-f");
+ makeCommand.Add("Makefile");
+
+ if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
+ if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
+ makeCommand.Add("-j");
+ } else {
+ makeCommand.Add("-j" + std::to_string(jobs));
+ }
+ }
+
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ for (auto tname : targetNames) {
+ if (!tname.empty()) {
+ if (fast) {
+ tname += "/fast";
+ }
+ tname =
+ mf->GetStateSnapshot().GetDirectory().ConvertToRelPathIfNotContained(
+ mf->GetState()->GetBinaryDirectory(), tname);
+ cmSystemTools::ConvertToOutputSlashes(tname);
+ makeCommand.Add(std::move(tname));
+ }
+ }
+ return { std::move(makeCommand) };
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules(
+ std::ostream& ruleFileStream, std::set<std::string>& emitted)
+{
+ std::vector<std::string> depends;
+ std::vector<std::string> commands;
+
+ bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
+ if (regenerate) {
+ depends.emplace_back("cmake_check_build_system");
+ }
+
+ // write the target convenience rules
+ for (const auto& localGen : this->LocalGenerators) {
+ auto& lg =
+ cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen);
+ // for each target Generate the rule files for each target.
+ for (const auto& gtarget : lg.GetGeneratorTargets()) {
+ // Don't emit the same rule twice (e.g. two targets with the same
+ // simple name)
+ std::string name = gtarget->GetName();
+ if (!name.empty() && emitted.insert(name).second &&
+ // Handle user targets here. Global targets are handled in
+ // the local generator on a per-directory basis.
+ (gtarget->IsInBuildSystem() &&
+ gtarget->GetType() != cmStateEnums::GLOBAL_TARGET)) {
+ // Add a rule to build the target by name.
+ lg.WriteDivider(ruleFileStream);
+ ruleFileStream << "# Target rules for targets named " << name
+ << "\n\n";
+
+ // Write the rule.
+ commands.clear();
+ std::string tmp = "CMakeFiles/Makefile2";
+ commands.push_back(lg.GetRecursiveMakeCall(tmp, name));
+ depends.clear();
+ if (regenerate) {
+ depends.emplace_back("cmake_check_build_system");
+ }
+ lg.WriteMakeRule(ruleFileStream, "Build rule for target.", name,
+ depends, commands, true);
+
+ // Add a fast rule to build the target
+ std::string localName = lg.GetRelativeTargetDirectory(gtarget.get());
+ std::string makefileName;
+ makefileName = cmStrCat(localName, "/build.make");
+ depends.clear();
+ commands.clear();
+ std::string makeTargetName = cmStrCat(localName, "/build");
+ localName = cmStrCat(name, "/fast");
+ commands.push_back(
+ lg.GetRecursiveMakeCall(makefileName, makeTargetName));
+ lg.WriteMakeRule(ruleFileStream, "fast build rule for target.",
+ localName, depends, commands, true);
+
+ // Add a local name for the rule to relink the target before
+ // installation.
+ if (gtarget->NeedRelinkBeforeInstall(lg.GetConfigName())) {
+ makeTargetName = cmStrCat(
+ lg.GetRelativeTargetDirectory(gtarget.get()), "/preinstall");
+ localName = cmStrCat(name, "/preinstall");
+ depends.clear();
+ commands.clear();
+ commands.push_back(
+ lg.GetRecursiveMakeCall(makefileName, makeTargetName));
+ lg.WriteMakeRule(ruleFileStream,
+ "Manual pre-install relink rule for target.",
+ localName, depends, commands, true);
+ }
+ }
+ }
+ }
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
+ std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3& lg)
+{
+ std::vector<std::string> depends;
+ std::vector<std::string> commands;
+ std::string localName;
+ std::string makeTargetName;
+
+ bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
+ if (regenerate) {
+ depends.emplace_back("cmake_check_build_system");
+ }
+
+ // for each target Generate the rule files for each target.
+ for (const auto& gtarget : lg.GetGeneratorTargets()) {
+ std::string name = gtarget->GetName();
+ if (!name.empty() &&
+ (gtarget->IsInBuildSystem() &&
+ gtarget->GetType() != cmStateEnums::GLOBAL_TARGET)) {
+ std::string makefileName;
+ // Add a rule to build the target by name.
+ localName = lg.GetRelativeTargetDirectory(gtarget.get());
+ makefileName = cmStrCat(localName, "/build.make");
+
+ lg.WriteDivider(ruleFileStream);
+ ruleFileStream << "# Target rules for target " << localName << "\n\n";
+
+ commands.clear();
+ makeTargetName = cmStrCat(localName, "/depend");
+ commands.push_back(
+ lg.GetRecursiveMakeCall(makefileName, makeTargetName));
+
+ makeTargetName = cmStrCat(localName, "/build");
+ commands.push_back(
+ lg.GetRecursiveMakeCall(makefileName, makeTargetName));
+
+ // Write the rule.
+ localName += "/all";
+ depends.clear();
+
+ cmLocalUnixMakefileGenerator3::EchoProgress progress;
+ progress.Dir = cmStrCat(lg.GetBinaryDirectory(), "/CMakeFiles");
+ {
+ std::ostringstream progressArg;
+ const char* sep = "";
+ for (unsigned long progFile : this->ProgressMap[gtarget.get()].Marks) {
+ progressArg << sep << progFile;
+ sep = ",";
+ }
+ progress.Arg = progressArg.str();
+ }
+
+ bool targetMessages = true;
+ if (cmProp tgtMsg =
+ this->GetCMakeInstance()->GetState()->GetGlobalProperty(
+ "TARGET_MESSAGES")) {
+ targetMessages = cmIsOn(*tgtMsg);
+ }
+
+ if (targetMessages) {
+ lg.AppendEcho(commands, "Built target " + name,
+ cmLocalUnixMakefileGenerator3::EchoNormal, &progress);
+ }
+
+ this->AppendGlobalTargetDepends(depends, gtarget.get());
+ lg.WriteMakeRule(ruleFileStream, "All Build rule for target.", localName,
+ depends, commands, true);
+
+ // Write the rule.
+ commands.clear();
+
+ {
+ // TODO: Convert the total progress count to a make variable.
+ std::ostringstream progCmd;
+ progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
+ // # in target
+ progCmd << lg.ConvertToOutputFormat(progress.Dir,
+ cmOutputConverter::SHELL);
+ //
+ std::set<cmGeneratorTarget const*> emitted;
+ progCmd << " "
+ << this->CountProgressMarksInTarget(gtarget.get(), emitted);
+ commands.push_back(progCmd.str());
+ }
+ std::string tmp = "CMakeFiles/Makefile2";
+ commands.push_back(lg.GetRecursiveMakeCall(tmp, localName));
+ {
+ std::ostringstream progCmd;
+ progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
+ progCmd << lg.ConvertToOutputFormat(progress.Dir,
+ cmOutputConverter::SHELL);
+ progCmd << " 0";
+ commands.push_back(progCmd.str());
+ }
+ depends.clear();
+ if (regenerate) {
+ depends.emplace_back("cmake_check_build_system");
+ }
+ localName =
+ cmStrCat(lg.GetRelativeTargetDirectory(gtarget.get()), "/rule");
+ lg.WriteMakeRule(ruleFileStream,
+ "Build rule for subdir invocation for target.",
+ localName, depends, commands, true);
+
+ // Add a target with the canonical name (no prefix, suffix or path).
+ commands.clear();
+ depends.clear();
+ depends.push_back(localName);
+ lg.WriteMakeRule(ruleFileStream, "Convenience name for target.", name,
+ depends, commands, true);
+
+ // Add rules to prepare the target for installation.
+ if (gtarget->NeedRelinkBeforeInstall(lg.GetConfigName())) {
+ localName = cmStrCat(lg.GetRelativeTargetDirectory(gtarget.get()),
+ "/preinstall");
+ depends.clear();
+ commands.clear();
+ commands.push_back(lg.GetRecursiveMakeCall(makefileName, localName));
+ lg.WriteMakeRule(ruleFileStream, "Pre-install relink rule for target.",
+ localName, depends, commands, true);
+ }
+
+ // add the clean rule
+ localName = lg.GetRelativeTargetDirectory(gtarget.get());
+ makeTargetName = cmStrCat(localName, "/clean");
+ depends.clear();
+ commands.clear();
+ commands.push_back(
+ lg.GetRecursiveMakeCall(makefileName, makeTargetName));
+ lg.WriteMakeRule(ruleFileStream, "clean rule for target.",
+ makeTargetName, depends, commands, true);
+ commands.clear();
+ }
+ }
+}
+
+// Build a map that contains the set of targets used by each local
+// generator directory level.
+void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks()
+{
+ this->DirectoryTargetsMap.clear();
+ // Loop over all targets in all local generators.
+ for (const auto& lg : this->LocalGenerators) {
+ for (const auto& gt : lg->GetGeneratorTargets()) {
+ cmLocalGenerator* tlg = gt->GetLocalGenerator();
+
+ if (!gt->IsInBuildSystem() || this->IsExcluded(lg.get(), gt.get())) {
+ continue;
+ }
+
+ cmStateSnapshot csnp = lg->GetStateSnapshot();
+ cmStateSnapshot tsnp = tlg->GetStateSnapshot();
+
+ // Consider the directory containing the target and all its
+ // parents until something excludes the target.
+ for (; csnp.IsValid() && !this->IsExcluded(csnp, tsnp);
+ csnp = csnp.GetBuildsystemDirectoryParent()) {
+ // This local generator includes the target.
+ std::set<cmGeneratorTarget const*>& targetSet =
+ this->DirectoryTargetsMap[csnp];
+ targetSet.insert(gt.get());
+
+ // Add dependencies of the included target. An excluded
+ // target may still be included if it is a dependency of a
+ // non-excluded target.
+ for (cmTargetDepend const& tgtdep :
+ this->GetTargetDirectDepends(gt.get())) {
+ targetSet.insert(tgtdep);
+ }
+ }
+ }
+ }
+}
+
+size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInTarget(
+ cmGeneratorTarget const* target, std::set<cmGeneratorTarget const*>& emitted)
+{
+ size_t count = 0;
+ if (emitted.insert(target).second) {
+ count = this->ProgressMap[target].Marks.size();
+ for (cmTargetDepend const& depend : this->GetTargetDirectDepends(target)) {
+ if (!depend->IsInBuildSystem()) {
+ continue;
+ }
+ count += this->CountProgressMarksInTarget(depend, emitted);
+ }
+ }
+ return count;
+}
+
+size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInAll(
+ const cmLocalGenerator& lg)
+{
+ size_t count = 0;
+ std::set<cmGeneratorTarget const*> emitted;
+ for (cmGeneratorTarget const* target :
+ this->DirectoryTargetsMap[lg.GetStateSnapshot()]) {
+ count += this->CountProgressMarksInTarget(target, emitted);
+ }
+ return count;
+}
+
+void cmGlobalUnixMakefileGenerator3::RecordTargetProgress(
+ cmMakefileTargetGenerator* tg)
+{
+ TargetProgress& tp = this->ProgressMap[tg->GetGeneratorTarget()];
+ tp.NumberOfActions = tg->GetNumberOfProgressActions();
+ tp.VariableFile = tg->GetProgressFileNameFull();
+}
+
+void cmGlobalUnixMakefileGenerator3::TargetProgress::WriteProgressVariables(
+ unsigned long total, unsigned long& current)
+{
+ cmGeneratedFileStream fout(this->VariableFile);
+ for (unsigned long i = 1; i <= this->NumberOfActions; ++i) {
+ fout << "CMAKE_PROGRESS_" << i << " = ";
+ if (total <= 100) {
+ unsigned long num = i + current;
+ fout << num;
+ this->Marks.push_back(num);
+ } else if (((i + current) * 100) / total >
+ ((i - 1 + current) * 100) / total) {
+ unsigned long num = ((i + current) * 100) / total;
+ fout << num;
+ this->Marks.push_back(num);
+ }
+ fout << "\n";
+ }
+ fout << "\n";
+ current += this->NumberOfActions;
+}
+
+void cmGlobalUnixMakefileGenerator3::AppendGlobalTargetDepends(
+ std::vector<std::string>& depends, cmGeneratorTarget* target)
+{
+ for (cmTargetDepend const& i : this->GetTargetDirectDepends(target)) {
+ // Create the target-level dependency.
+ cmGeneratorTarget const* dep = i;
+ if (!dep->IsInBuildSystem()) {
+ continue;
+ }
+ cmLocalUnixMakefileGenerator3* lg3 =
+ static_cast<cmLocalUnixMakefileGenerator3*>(dep->GetLocalGenerator());
+ std::string tgtName = cmStrCat(
+ lg3->GetRelativeTargetDirectory(const_cast<cmGeneratorTarget*>(dep)),
+ "/all");
+ depends.push_back(tgtName);
+ }
+}
+
+void cmGlobalUnixMakefileGenerator3::WriteHelpRule(
+ std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg)
+{
+ // add the help target
+ std::string path;
+ std::vector<std::string> no_depends;
+ std::vector<std::string> commands;
+ lg->AppendEcho(commands,
+ "The following are some of the valid targets "
+ "for this Makefile:");
+ lg->AppendEcho(commands, "... all (the default if no target is provided)");
+ lg->AppendEcho(commands, "... clean");
+ if (!this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
+ lg->AppendEcho(commands, "... depend");
+ }
+
+ // Keep track of targets already listed.
+ std::set<std::string> emittedTargets;
+ std::set<std::string> utility_targets;
+ std::set<std::string> globals_targets;
+ std::set<std::string> project_targets;
+
+ // for each local generator
+ for (const auto& localGen : this->LocalGenerators) {
+ const auto& lg2 =
+ cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen);
+ // for the passed in makefile or if this is the top Makefile wripte out
+ // the targets
+ if (&lg2 == lg || lg->IsRootMakefile()) {
+ // for each target Generate the rule files for each target.
+ for (const auto& target : lg2.GetGeneratorTargets()) {
+ cmStateEnums::TargetType type = target->GetType();
+ if ((type == cmStateEnums::EXECUTABLE) ||
+ (type == cmStateEnums::STATIC_LIBRARY) ||
+ (type == cmStateEnums::SHARED_LIBRARY) ||
+ (type == cmStateEnums::MODULE_LIBRARY) ||
+ (type == cmStateEnums::OBJECT_LIBRARY) ||
+ (type == cmStateEnums::INTERFACE_LIBRARY &&
+ target->IsInBuildSystem())) {
+ project_targets.insert(target->GetName());
+ } else if (type == cmStateEnums::GLOBAL_TARGET) {
+ globals_targets.insert(target->GetName());
+ } else if (type == cmStateEnums::UTILITY) {
+ utility_targets.insert(target->GetName());
+ }
+ }
+ }
+ }
+
+ for (std::string const& name : globals_targets) {
+ path = cmStrCat("... ", name);
+ lg->AppendEcho(commands, path);
+ }
+ for (std::string const& name : utility_targets) {
+ path = cmStrCat("... ", name);
+ lg->AppendEcho(commands, path);
+ }
+ for (std::string const& name : project_targets) {
+ path = cmStrCat("... ", name);
+ lg->AppendEcho(commands, path);
+ }
+
+ for (std::string const& o : lg->GetLocalHelp()) {
+ path = cmStrCat("... ", o);
+ lg->AppendEcho(commands, path);
+ }
+ lg->WriteMakeRule(ruleFileStream, "Help Target", "help", no_depends,
+ commands, true);
+ ruleFileStream << "\n\n";
+}
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
new file mode 100644
index 0000000..7c950cc
--- /dev/null
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -0,0 +1,287 @@
+/* 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 <cstddef>
+#include <iosfwd>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmGeneratorTarget.h"
+#include "cmGlobalCommonGenerator.h"
+#include "cmGlobalGeneratorFactory.h"
+#include "cmStateSnapshot.h"
+
+class cmGeneratedFileStream;
+class cmLocalGenerator;
+class cmLocalUnixMakefileGenerator3;
+class cmMakefile;
+class cmMakefileTargetGenerator;
+class cmake;
+struct cmDocumentationEntry;
+
+/** \class cmGlobalUnixMakefileGenerator3
+ * \brief Write a Unix makefiles.
+ *
+ * cmGlobalUnixMakefileGenerator3 manages UNIX build process for a tree
+
+
+ The basic approach of this generator is to produce Makefiles that will all
+ be run with the current working directory set to the Home Output
+ directory. The one exception to this is the subdirectory Makefiles which are
+ created as a convenience and just cd up to the Home Output directory and
+ invoke the main Makefiles.
+
+ The make process starts with Makefile. Makefile should only contain the
+ targets the user is likely to invoke directly from a make command line. No
+ internal targets should be in this file. Makefile2 contains the internal
+ targets that are required to make the process work.
+
+ Makefile2 in turn will recursively make targets in the correct order. Each
+ target has its own directory \<target\>.dir and its own makefile build.make in
+ that directory. Also in that directory is a couple makefiles per source file
+ used by the target. Typically these are named source.obj.build.make and
+ source.obj.build.depend.make. The source.obj.build.make contains the rules
+ for building, cleaning, and computing dependencies for the given source
+ file. The build.depend.make contains additional dependencies that were
+ computed during dependency scanning. An additional file called
+ source.obj.depend is used as a marker to indicate when dependencies must be
+ rescanned.
+
+ Rules for custom commands follow the same model as rules for source files.
+
+ */
+
+class cmGlobalUnixMakefileGenerator3 : public cmGlobalCommonGenerator
+{
+public:
+ cmGlobalUnixMakefileGenerator3(cmake* cm);
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
+ {
+ return std::unique_ptr<cmGlobalGeneratorFactory>(
+ new cmGlobalGeneratorSimpleFactory<cmGlobalUnixMakefileGenerator3>());
+ }
+
+ ~cmGlobalUnixMakefileGenerator3() override;
+
+ cmGlobalUnixMakefileGenerator3(const cmGlobalUnixMakefileGenerator3&) =
+ delete;
+ cmGlobalUnixMakefileGenerator3& operator=(
+ const cmGlobalUnixMakefileGenerator3&) = delete;
+
+ //! Get the name for the generator.
+ std::string GetName() const override
+ {
+ return cmGlobalUnixMakefileGenerator3::GetActualName();
+ }
+ static std::string GetActualName() { return "Unix Makefiles"; }
+
+ /**
+ * Utilized by the generator factory to determine if this generator
+ * supports toolsets.
+ */
+ static bool SupportsToolset() { return false; }
+
+ /**
+ * Utilized by the generator factory to determine if this generator
+ * supports platforms.
+ */
+ static bool SupportsPlatform() { return false; }
+
+ /**
+ * Utilized to determine if this generator
+ * supports DEPFILE option.
+ */
+ bool SupportsCustomCommandDepfile() const override { return true; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+ cmMakefile* mf) override;
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) override;
+
+ void Configure() override;
+
+ /**
+ * Generate the all required files for building this project/tree. This
+ * basically creates a series of LocalGenerators for each directory and
+ * requests that they Generate.
+ */
+ void Generate() override;
+
+ void WriteMainCMakefileLanguageRules(
+ cmGeneratedFileStream& cmakefileStream,
+ std::vector<std::unique_ptr<cmLocalGenerator>>&);
+
+ // write out the help rule listing the valid targets
+ void WriteHelpRule(std::ostream& ruleFileStream,
+ cmLocalUnixMakefileGenerator3*);
+
+ // write the top level target rules
+ void WriteConvenienceRules(std::ostream& ruleFileStream,
+ std::set<std::string>& emitted);
+
+ // Make tool supports dependency files generated by compiler
+ bool SupportsCompilerDependencies() const
+ {
+ return this->ToolSupportsCompilerDependencies;
+ }
+
+ // Make tool supports long line dependencies
+ bool SupportsLongLineDependencies() const
+ {
+ return this->ToolSupportsLongLineDependencies;
+ }
+
+ /** Get the command to use for a target that has no rule. This is
+ used for multiple output dependencies and for cmake_force. */
+ std::string GetEmptyRuleHackCommand() { return this->EmptyRuleHackCommand; }
+
+ /** Get the fake dependency to use when a rule has no real commands
+ or dependencies. */
+ std::string GetEmptyRuleHackDepends() { return this->EmptyRuleHackDepends; }
+
+ /**
+ * Convert a file path to a Makefile target or dependency with
+ * escaping and quoting suitable for the generator's make tool.
+ */
+ std::string ConvertToMakefilePath(std::string const& path) const;
+
+ // change the build command for speed
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
+
+ /** Record per-target progress information. */
+ void RecordTargetProgress(cmMakefileTargetGenerator* tg);
+
+ void AddCXXCompileCommand(const std::string& sourceFile,
+ const std::string& workingDirectory,
+ const std::string& compileCommand);
+
+ /** Does the make tool tolerate .NOTPARALLEL? */
+ virtual bool AllowNotParallel() const { return true; }
+
+ /** Does the make tool tolerate .DELETE_ON_ERROR? */
+ virtual bool AllowDeleteOnError() const { return true; }
+
+ /** Does the make tool interpret '\#' as '#'? */
+ virtual bool CanEscapeOctothorpe() const;
+
+ bool IsIPOSupported() const override { return true; }
+
+ void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;
+
+ std::string IncludeDirective;
+ std::string LineContinueDirective;
+ bool DefineWindowsNULL;
+ bool PassMakeflags;
+ bool UnixCD;
+
+protected:
+ void WriteMainMakefile2();
+ void WriteMainCMakefile();
+
+ void WriteConvenienceRules2(std::ostream& ruleFileStream,
+ cmLocalUnixMakefileGenerator3&);
+
+ void WriteDirectoryRule2(std::ostream& ruleFileStream,
+ DirectoryTarget const& dt, const char* pass,
+ bool check_all, bool check_relink,
+ std::vector<std::string> const& commands = {});
+ void WriteDirectoryRules2(std::ostream& ruleFileStream,
+ DirectoryTarget const& dt);
+
+ void AppendGlobalTargetDepends(std::vector<std::string>& depends,
+ cmGeneratorTarget* target);
+
+ // Target name hooks for superclass.
+ const char* GetAllTargetName() const override { return "all"; }
+ const char* GetInstallTargetName() const override { return "install"; }
+ const char* GetInstallLocalTargetName() const override
+ {
+ return "install/local";
+ }
+ const char* GetInstallStripTargetName() const override
+ {
+ return "install/strip";
+ }
+ const char* GetPreinstallTargetName() const override { return "preinstall"; }
+ const char* GetTestTargetName() const override { return "test"; }
+ const char* GetPackageTargetName() const override { return "package"; }
+ const char* GetPackageSourceTargetName() const override
+ {
+ return "package_source";
+ }
+ const char* GetEditCacheTargetName() const override { return "edit_cache"; }
+ const char* GetRebuildCacheTargetName() const override
+ {
+ return "rebuild_cache";
+ }
+ const char* GetCleanTargetName() const override { return "clean"; }
+
+ bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const override { return true; }
+
+ // Specify if the make tool is able to consume dependency files
+ // generated by the compiler
+ bool ToolSupportsCompilerDependencies = true;
+
+ // some Make generator, such as Borland not support long line dependencies,
+ // we add SupportsLongLineDependencies to predicate.
+ bool ToolSupportsLongLineDependencies = true;
+
+ // Some make programs (Borland) do not keep a rule if there are no
+ // dependencies or commands. This is a problem for creating rules
+ // that might not do anything but might have other dependencies
+ // added later. If non-empty this variable holds a fake dependency
+ // that can be added.
+ std::string EmptyRuleHackDepends;
+
+ // Some make programs (Watcom) do not like rules with no commands.
+ // If non-empty this variable holds a bogus command that may be put
+ // in the rule to satisfy the make program.
+ std::string EmptyRuleHackCommand;
+
+ // Store per-target progress counters.
+ struct TargetProgress
+ {
+ unsigned long NumberOfActions = 0;
+ std::string VariableFile;
+ std::vector<unsigned long> Marks;
+ void WriteProgressVariables(unsigned long total, unsigned long& current);
+ };
+ using ProgressMapType = std::map<cmGeneratorTarget const*, TargetProgress,
+ cmGeneratorTarget::StrictTargetComparison>;
+ ProgressMapType ProgressMap;
+
+ size_t CountProgressMarksInTarget(
+ cmGeneratorTarget const* target,
+ std::set<cmGeneratorTarget const*>& emitted);
+ size_t CountProgressMarksInAll(const cmLocalGenerator& lg);
+
+ std::unique_ptr<cmGeneratedFileStream> CommandDatabase;
+
+private:
+ const char* GetBuildIgnoreErrorsFlag() const override { return "-i"; }
+ std::string GetEditCacheCommand() const override;
+
+ std::map<cmStateSnapshot, std::set<cmGeneratorTarget const*>,
+ cmStateSnapshot::StrictWeakOrder>
+ DirectoryTargetsMap;
+ void InitializeProgressMarks() override;
+};
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
new file mode 100644
index 0000000..93fbe37
--- /dev/null
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -0,0 +1,1655 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalVisualStudio10Generator.h"
+
+#include <algorithm>
+#include <utility>
+
+#include <cm/memory>
+
+#include <cm3p/json/reader.h>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmAlgorithms.h"
+#include "cmDocumentationEntry.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalVisualStudio10Generator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
+#include "cmVersion.h"
+#include "cmVisualStudioSlnData.h"
+#include "cmVisualStudioSlnParser.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+static const char vs10generatorName[] = "Visual Studio 10 2010";
+static std::map<std::string, std::vector<cmIDEFlagTable>> loadedFlagJsonFiles;
+
+static void ConvertToWindowsSlashes(std::string& s)
+{
+ // first convert all of the slashes
+ for (auto& ch : s) {
+ if (ch == '/') {
+ ch = '\\';
+ }
+ }
+}
+
+// Map generator name without year to name with year.
+static const char* cmVS10GenName(const std::string& name, std::string& genName)
+{
+ if (strncmp(name.c_str(), vs10generatorName,
+ sizeof(vs10generatorName) - 6) != 0) {
+ return 0;
+ }
+ const char* p = name.c_str() + sizeof(vs10generatorName) - 6;
+ if (cmHasLiteralPrefix(p, " 2010")) {
+ p += 5;
+ }
+ genName = std::string(vs10generatorName) + p;
+ return p;
+}
+
+class cmGlobalVisualStudio10Generator::Factory
+ : public cmGlobalGeneratorFactory
+{
+public:
+ std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+ const std::string& name, bool allowArch, cmake* cm) const override
+ {
+ std::string genName;
+ const char* p = cmVS10GenName(name, genName);
+ if (!p) {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+ if (!*p) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio10Generator(cm, genName, ""));
+ }
+ if (!allowArch || *p++ != ' ') {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+ if (strcmp(p, "Win64") == 0) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio10Generator(cm, genName, "x64"));
+ }
+ if (strcmp(p, "IA64") == 0) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio10Generator(cm, genName, "Itanium"));
+ }
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+
+ void GetDocumentation(cmDocumentationEntry& entry) const override
+ {
+ entry.Name = std::string(vs10generatorName) + " [arch]";
+ entry.Brief = "Generates Visual Studio 2010 project files. "
+ "Optional [arch] can be \"Win64\" or \"IA64\".";
+ }
+
+ std::vector<std::string> GetGeneratorNames() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(vs10generatorName);
+ return names;
+ }
+
+ std::vector<std::string> GetGeneratorNamesWithPlatform() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(vs10generatorName + std::string(" IA64"));
+ names.push_back(vs10generatorName + std::string(" Win64"));
+ return names;
+ }
+
+ bool SupportsToolset() const override { return true; }
+ bool SupportsPlatform() const override { return true; }
+
+ std::vector<std::string> GetKnownPlatforms() const override
+ {
+ std::vector<std::string> platforms;
+ platforms.emplace_back("x64");
+ platforms.emplace_back("Win32");
+ platforms.emplace_back("Itanium");
+ return platforms;
+ }
+
+ std::string GetDefaultPlatformName() const override { return "Win32"; }
+};
+
+std::unique_ptr<cmGlobalGeneratorFactory>
+cmGlobalVisualStudio10Generator::NewFactory()
+{
+ return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
+}
+
+cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator(
+ cmake* cm, const std::string& name,
+ std::string const& platformInGeneratorName)
+ : cmGlobalVisualStudio8Generator(cm, name, platformInGeneratorName)
+{
+ std::string vc10Express;
+ this->ExpressEdition = cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\10.0\\Setup\\VC;"
+ "ProductDir",
+ vc10Express, cmSystemTools::KeyWOW64_32);
+ this->CudaEnabled = false;
+ this->MSBuildCommandInitialized = false;
+ {
+ std::string envPlatformToolset;
+ if (cmSystemTools::GetEnv("PlatformToolset", envPlatformToolset) &&
+ envPlatformToolset == "Windows7.1SDK") {
+ // We are running from a Windows7.1SDK command prompt.
+ this->DefaultPlatformToolset = "Windows7.1SDK";
+ } else {
+ this->DefaultPlatformToolset = "v100";
+ }
+ }
+ this->DefaultCLFlagTableName = "v10";
+ this->DefaultCSharpFlagTableName = "v10";
+ this->DefaultLibFlagTableName = "v10";
+ this->DefaultLinkFlagTableName = "v10";
+ this->DefaultCudaFlagTableName = "v10";
+ this->DefaultCudaHostFlagTableName = "v10";
+ this->DefaultMasmFlagTableName = "v10";
+ this->DefaultNasmFlagTableName = "v10";
+ this->DefaultRCFlagTableName = "v10";
+
+ this->Version = VS10;
+ this->PlatformToolsetNeedsDebugEnum = false;
+}
+
+bool cmGlobalVisualStudio10Generator::MatchesGeneratorName(
+ const std::string& name) const
+{
+ std::string genName;
+ if (cmVS10GenName(name, genName)) {
+ return genName == this->GetName();
+ }
+ return false;
+}
+
+bool cmGlobalVisualStudio10Generator::SetSystemName(std::string const& s,
+ cmMakefile* mf)
+{
+ this->SystemName = s;
+ this->SystemVersion = mf->GetSafeDefinition("CMAKE_SYSTEM_VERSION");
+ if (!this->InitializeSystem(mf)) {
+ return false;
+ }
+ return this->cmGlobalVisualStudio8Generator::SetSystemName(s, mf);
+}
+
+bool cmGlobalVisualStudio10Generator::SetGeneratorPlatform(
+ std::string const& p, cmMakefile* mf)
+{
+ if (!this->cmGlobalVisualStudio8Generator::SetGeneratorPlatform(p, mf)) {
+ return false;
+ }
+ if (this->GetPlatformName() == "Itanium" ||
+ this->GetPlatformName() == "x64") {
+ if (this->IsExpressEdition() && !this->Find64BitTools(mf)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void cmCudaToolVersion(std::string& s)
+{
+ // "CUDA x.y.props" => "x.y"
+ s = s.substr(5);
+ s = s.substr(0, s.size() - 6);
+}
+
+bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
+ std::string const& ts, bool build, cmMakefile* mf)
+{
+ if (this->SystemIsWindowsCE && ts.empty() &&
+ this->DefaultPlatformToolset.empty()) {
+ std::ostringstream e;
+ e << this->GetName() << " Windows CE version '" << this->SystemVersion
+ << "' requires CMAKE_GENERATOR_TOOLSET to be set.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ if (!this->ParseGeneratorToolset(ts, mf)) {
+ return false;
+ }
+
+ if (build) {
+ return true;
+ }
+
+ if (this->CustomVCTargetsPath.empty() && !this->FindVCTargetsPath(mf)) {
+ return false;
+ }
+
+ if (!this->CustomFlagTableDir.empty() &&
+ !(cmSystemTools::FileIsFullPath(this->CustomFlagTableDir) &&
+ cmSystemTools::FileIsDirectory(this->CustomFlagTableDir))) {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "given toolset\n"
+ " customFlagTableDir=" << this->CustomFlagTableDir << "\n"
+ "that is not an absolute path to an existing directory.";
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (cmHasLiteralPrefix(this->GetPlatformToolsetString(), "v140")) {
+ // The GenerateDebugInformation link setting for the v140 toolset
+ // in VS 2015 was originally an enum with "No" and "Debug" values,
+ // differing from the "false" and "true" values used in older toolsets.
+ // A VS 2015 update changed it back. Parse the "link.xml" file to
+ // discover which one we need.
+ std::string const link_xml = this->VCTargetsPath + "/1033/link.xml";
+ cmsys::ifstream fin(link_xml.c_str());
+ std::string line;
+ while (fin && cmSystemTools::GetLineFromStream(fin, line)) {
+ if (line.find(" Switch=\"DEBUG\" ") != std::string::npos) {
+ this->PlatformToolsetNeedsDebugEnum =
+ line.find(" Name=\"Debug\" ") != std::string::npos;
+ break;
+ }
+ }
+ }
+
+ this->SupportsUnityBuilds =
+ this->Version >= cmGlobalVisualStudioGenerator::VS16 ||
+ (this->Version == cmGlobalVisualStudioGenerator::VS15 &&
+ cmSystemTools::PathExists(this->VCTargetsPath +
+ "/Microsoft.Cpp.Unity.targets"));
+
+ if (this->GeneratorToolsetCuda.empty()) {
+ // Find the highest available version of the CUDA tools.
+ std::vector<std::string> cudaTools;
+ std::string bcDir;
+ if (this->GeneratorToolsetCudaCustomDir.empty()) {
+ bcDir = this->VCTargetsPath + "/BuildCustomizations";
+ } else {
+ bcDir = this->GetPlatformToolsetCudaCustomDirString() +
+ this->GetPlatformToolsetCudaVSIntegrationSubdirString() +
+ "extras\\visual_studio_integration\\MSBuildExtensions";
+ cmSystemTools::ConvertToUnixSlashes(bcDir);
+ }
+ cmsys::Glob gl;
+ gl.SetRelative(bcDir.c_str());
+ if (gl.FindFiles(bcDir + "/CUDA *.props")) {
+ cudaTools = gl.GetFiles();
+ }
+ if (!cudaTools.empty()) {
+ std::for_each(cudaTools.begin(), cudaTools.end(), cmCudaToolVersion);
+ std::sort(cudaTools.begin(), cudaTools.end(),
+ cmSystemTools::VersionCompareGreater);
+ this->GeneratorToolsetCuda = cudaTools.at(0);
+ } else if (!this->GeneratorToolsetCudaCustomDir.empty()) {
+ // Generate an error if Visual Studio integration files are not found
+ // inside of custom cuda toolset.
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "given toolset\n"
+ " cuda=" << this->GeneratorToolsetCudaCustomDir << "\n"
+ "cannot detect Visual Studio integration files in path\n"
+ " " << bcDir;
+
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+
+ // Clear the configured tool-set
+ this->GeneratorToolsetCuda.clear();
+ }
+ }
+
+ if (!this->GeneratorToolsetVersion.empty() &&
+ this->GeneratorToolsetVersion != "Test Toolset Version") {
+ // If a specific minor version of the toolset was requested, verify that it
+ // is compatible to the major version and that is exists on disk.
+ // If not clear the value.
+ std::string versionToolset = this->GeneratorToolsetVersion;
+ cmsys::RegularExpression regex("[0-9][0-9]\\.[0-9][0-9]");
+ if (regex.find(versionToolset)) {
+ versionToolset = "v" + versionToolset.erase(2, 1);
+ } else {
+ // Version not recognized. Clear it.
+ versionToolset.clear();
+ }
+
+ if (!cmHasPrefix(versionToolset, this->GetPlatformToolsetString())) {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "given toolset and version specification\n"
+ " " << this->GetPlatformToolsetString() << ",version=" <<
+ this->GeneratorToolsetVersion << "\n"
+ "contains an invalid version specification."
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+
+ // Clear the configured tool-set
+ this->GeneratorToolsetVersion.clear();
+ }
+
+ std::string auxProps;
+ switch (this->FindAuxToolset(this->GeneratorToolsetVersion, auxProps)) {
+ case AuxToolset::None:
+ this->GeneratorToolsetVersionProps = {};
+ break;
+ case AuxToolset::Default:
+ // The given version is the default toolset. Remove the setting.
+ this->GeneratorToolsetVersion.clear();
+ this->GeneratorToolsetVersionProps = {};
+ break;
+ case AuxToolset::PropsExist:
+ this->GeneratorToolsetVersionProps = std::move(auxProps);
+ break;
+ case AuxToolset::PropsMissing: {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "given toolset and version specification\n"
+ " " << this->GetPlatformToolsetString() << ",version=" <<
+ this->GeneratorToolsetVersion << "\n"
+ "does not seem to be installed at\n" <<
+ " " << auxProps;
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+
+ // Clear the configured tool-set
+ this->GeneratorToolsetVersion.clear();
+ this->GeneratorToolsetVersionProps = {};
+ } break;
+ }
+ }
+
+ if (const char* toolset = this->GetPlatformToolset()) {
+ mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET", toolset);
+ }
+ if (!this->GeneratorToolsetVersion.empty()) {
+ mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_VERSION",
+ this->GeneratorToolsetVersion);
+ }
+ if (const char* hostArch = this->GetPlatformToolsetHostArchitecture()) {
+ mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE", hostArch);
+ }
+ if (const char* cuda = this->GetPlatformToolsetCuda()) {
+ mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_CUDA", cuda);
+ }
+ if (const char* cudaDir = this->GetPlatformToolsetCudaCustomDir()) {
+ mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR", cudaDir);
+ }
+ if (const char* vcTargetsDir = this->GetCustomVCTargetsPath()) {
+ mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR",
+ vcTargetsDir);
+ }
+
+ return true;
+}
+
+bool cmGlobalVisualStudio10Generator::ParseGeneratorToolset(
+ std::string const& ts, cmMakefile* mf)
+{
+ std::vector<std::string> const fields = cmTokenize(ts, ",");
+ std::vector<std::string>::const_iterator fi = fields.begin();
+ if (fi == fields.end()) {
+ return true;
+ }
+
+ // The first field may be the VS platform toolset.
+ if (fi->find('=') == fi->npos) {
+ this->GeneratorToolset = *fi;
+ ++fi;
+ }
+
+ std::set<std::string> handled;
+
+ // The rest of the fields must be key=value pairs.
+ for (; fi != fields.end(); ++fi) {
+ std::string::size_type pos = fi->find('=');
+ if (pos == fi->npos) {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "given toolset specification\n"
+ " " << ts << "\n"
+ "that contains a field after the first ',' with no '='."
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ std::string const key = fi->substr(0, pos);
+ std::string const value = fi->substr(pos + 1);
+ if (!handled.insert(key).second) {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "given toolset specification\n"
+ " " << ts << "\n"
+ "that contains duplicate field key '" << key << "'."
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ if (!this->ProcessGeneratorToolsetField(key, value)) {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "given toolset specification\n"
+ " " << ts << "\n"
+ "that contains invalid field '" << *fi << "'."
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool cmGlobalVisualStudio10Generator::ProcessGeneratorToolsetField(
+ std::string const& key, std::string const& value)
+{
+ if (key == "cuda") {
+ /* test if cuda toolset is path to custom dir or cuda version */
+ auto pos = value.find_first_not_of("0123456789.");
+ if (pos != std::string::npos) {
+ this->GeneratorToolsetCudaCustomDir = value;
+ /* ensure trailing backslash for easy path joining */
+ if (this->GeneratorToolsetCudaCustomDir.back() != '\\') {
+ this->GeneratorToolsetCudaCustomDir.push_back('\\');
+ }
+ /* check for legacy toolkit folder structure */
+ if (cmsys::SystemTools::FileIsDirectory(
+ cmStrCat(this->GeneratorToolsetCudaCustomDir, "nvcc"))) {
+ this->GeneratorToolsetCudaNvccSubdir = "nvcc\\";
+ }
+ if (cmsys::SystemTools::FileIsDirectory(
+ cmStrCat(this->GeneratorToolsetCudaCustomDir,
+ "CUDAVisualStudioIntegration"))) {
+ this->GeneratorToolsetCudaVSIntegrationSubdir =
+ "CUDAVisualStudioIntegration\\";
+ }
+ } else {
+ this->GeneratorToolsetCuda = value;
+ }
+ return true;
+ }
+ if (key == "customFlagTableDir") {
+ this->CustomFlagTableDir = value;
+ cmSystemTools::ConvertToUnixSlashes(this->CustomFlagTableDir);
+ return true;
+ }
+ if (key == "version") {
+ this->GeneratorToolsetVersion = value;
+ return true;
+ }
+ if (key == "VCTargetsPath") {
+ this->CustomVCTargetsPath = value;
+ ConvertToWindowsSlashes(this->CustomVCTargetsPath);
+ return true;
+ }
+ return false;
+}
+
+bool cmGlobalVisualStudio10Generator::InitializeSystem(cmMakefile* mf)
+{
+ if (this->SystemName == "Windows") {
+ if (!this->InitializeWindows(mf)) {
+ return false;
+ }
+ } else if (this->SystemName == "WindowsCE") {
+ this->SystemIsWindowsCE = true;
+ if (!this->InitializeWindowsCE(mf)) {
+ return false;
+ }
+ } else if (this->SystemName == "WindowsPhone") {
+ this->SystemIsWindowsPhone = true;
+ if (!this->InitializeWindowsPhone(mf)) {
+ return false;
+ }
+ } else if (this->SystemName == "WindowsStore") {
+ this->SystemIsWindowsStore = true;
+ if (!this->InitializeWindowsStore(mf)) {
+ return false;
+ }
+ } else if (this->SystemName == "Android") {
+ if (this->PlatformInGeneratorName) {
+ std::ostringstream e;
+ e << "CMAKE_SYSTEM_NAME is 'Android' but CMAKE_GENERATOR "
+ << "specifies a platform too: '" << this->GetName() << "'";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ if (mf->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM") == "Tegra-Android") {
+ if (!this->InitializeTegraAndroid(mf)) {
+ return false;
+ }
+ } else {
+ this->SystemIsAndroid = true;
+ if (!this->InitializeAndroid(mf)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool cmGlobalVisualStudio10Generator::InitializeWindows(cmMakefile*)
+{
+ return true;
+}
+
+bool cmGlobalVisualStudio10Generator::InitializeWindowsCE(cmMakefile* mf)
+{
+ if (this->PlatformInGeneratorName) {
+ std::ostringstream e;
+ e << "CMAKE_SYSTEM_NAME is 'WindowsCE' but CMAKE_GENERATOR "
+ << "specifies a platform too: '" << this->GetName() << "'";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ this->DefaultPlatformToolset = this->SelectWindowsCEToolset();
+
+ return true;
+}
+
+bool cmGlobalVisualStudio10Generator::InitializeWindowsPhone(cmMakefile* mf)
+{
+ std::ostringstream e;
+ e << this->GetName() << " does not support Windows Phone.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+}
+
+bool cmGlobalVisualStudio10Generator::InitializeWindowsStore(cmMakefile* mf)
+{
+ std::ostringstream e;
+ e << this->GetName() << " does not support Windows Store.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+}
+
+bool cmGlobalVisualStudio10Generator::InitializeTegraAndroid(cmMakefile* mf)
+{
+ std::string v = this->GetInstalledNsightTegraVersion();
+ if (v.empty()) {
+ mf->IssueMessage(MessageType::FATAL_ERROR,
+ "CMAKE_SYSTEM_NAME is 'Android' but "
+ "'NVIDIA Nsight Tegra Visual Studio Edition' "
+ "is not installed.");
+ return false;
+ }
+ this->DefaultPlatformName = "Tegra-Android";
+ this->DefaultPlatformToolset = "Default";
+ this->NsightTegraVersion = v;
+ mf->AddDefinition("CMAKE_VS_NsightTegra_VERSION", v);
+ return true;
+}
+
+bool cmGlobalVisualStudio10Generator::InitializeAndroid(cmMakefile* mf)
+{
+ std::ostringstream e;
+ e << this->GetName() << " does not support Android.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+}
+
+bool cmGlobalVisualStudio10Generator::SelectWindowsPhoneToolset(
+ std::string& toolset) const
+{
+ toolset.clear();
+ return false;
+}
+
+bool cmGlobalVisualStudio10Generator::SelectWindowsStoreToolset(
+ std::string& toolset) const
+{
+ toolset.clear();
+ return false;
+}
+
+std::string cmGlobalVisualStudio10Generator::SelectWindowsCEToolset() const
+{
+ if (this->SystemVersion == "8.0") {
+ return "CE800";
+ }
+ return "";
+}
+
+//! Create a local generator appropriate to this Global Generator
+std::unique_ptr<cmLocalGenerator>
+cmGlobalVisualStudio10Generator::CreateLocalGenerator(cmMakefile* mf)
+{
+ return std::unique_ptr<cmLocalGenerator>(
+ cm::make_unique<cmLocalVisualStudio10Generator>(this, mf));
+}
+
+void cmGlobalVisualStudio10Generator::Generate()
+{
+ this->LongestSource = LongestSourcePath();
+ this->cmGlobalVisualStudio8Generator::Generate();
+ if (!this->AndroidExecutableWarnings.empty() &&
+ !this->CMakeInstance->GetIsInTryCompile()) {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "You are using Visual Studio tools for Android, which does not support "
+ "standalone executables. However, the following executable targets do "
+ "not have the ANDROID_GUI property set, and thus will not be built as "
+ "expected. They will be built as shared libraries with executable "
+ "filenames:\n"
+ " ";
+ /* clang-format on */
+ bool first = true;
+ for (auto const& name : this->AndroidExecutableWarnings) {
+ if (!first) {
+ e << ", ";
+ }
+ first = false;
+ e << name;
+ }
+ this->CMakeInstance->IssueMessage(MessageType::WARNING, e.str());
+ }
+ if (this->LongestSource.Length > 0) {
+ cmLocalGenerator* lg = this->LongestSource.Target->GetLocalGenerator();
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "The binary and/or source directory paths may be too long to generate "
+ "Visual Studio 10 files for this project. "
+ "Consider choosing shorter directory names to build this project with "
+ "Visual Studio 10. "
+ "A more detailed explanation follows."
+ "\n"
+ "There is a bug in the VS 10 IDE that renders property dialog fields "
+ "blank for files referenced by full path in the project file. "
+ "However, CMake must reference at least one file by full path:\n"
+ " " << this->LongestSource.SourceFile->GetFullPath() << "\n"
+ "This is because some Visual Studio tools would append the relative "
+ "path to the end of the referencing directory path, as in:\n"
+ " " << lg->GetCurrentBinaryDirectory() << "/"
+ << this->LongestSource.SourceRel << "\n"
+ "and then incorrectly complain that the file does not exist because "
+ "the path length is too long for some internal buffer or API. "
+ "To avoid this problem CMake must use a full path for this file "
+ "which then triggers the VS 10 property dialog bug.";
+ /* clang-format on */
+ lg->IssueMessage(MessageType::WARNING, e.str());
+ }
+}
+
+void cmGlobalVisualStudio10Generator::EnableLanguage(
+ std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
+{
+ for (std::string const& it : lang) {
+ if (it == "ASM_NASM") {
+ this->NasmEnabled = true;
+ }
+ if (it == "CUDA") {
+ this->CudaEnabled = true;
+ }
+ }
+ this->AddPlatformDefinitions(mf);
+ cmGlobalVisualStudio8Generator::EnableLanguage(lang, mf, optional);
+}
+
+const char* cmGlobalVisualStudio10Generator::GetCustomVCTargetsPath() const
+{
+ if (this->CustomVCTargetsPath.empty()) {
+ return nullptr;
+ }
+ return this->CustomVCTargetsPath.c_str();
+}
+
+const char* cmGlobalVisualStudio10Generator::GetPlatformToolset() const
+{
+ std::string const& toolset = this->GetPlatformToolsetString();
+ if (toolset.empty()) {
+ return nullptr;
+ }
+ return toolset.c_str();
+}
+
+std::string const& cmGlobalVisualStudio10Generator::GetPlatformToolsetString()
+ const
+{
+ if (!this->GeneratorToolset.empty()) {
+ return this->GeneratorToolset;
+ }
+ if (this->SystemIsAndroid) {
+ if (!this->DefaultAndroidToolset.empty()) {
+ return this->DefaultAndroidToolset;
+ }
+ } else {
+ if (!this->DefaultPlatformToolset.empty()) {
+ return this->DefaultPlatformToolset;
+ }
+ }
+ static std::string const empty;
+ return empty;
+}
+
+std::string const&
+cmGlobalVisualStudio10Generator::GetPlatformToolsetVersionProps() const
+{
+ return this->GeneratorToolsetVersionProps;
+}
+
+const char*
+cmGlobalVisualStudio10Generator::GetPlatformToolsetHostArchitecture() const
+{
+ std::string const& hostArch =
+ this->GetPlatformToolsetHostArchitectureString();
+ if (hostArch.empty()) {
+ return nullptr;
+ }
+ return hostArch.c_str();
+}
+
+std::string const&
+cmGlobalVisualStudio10Generator::GetPlatformToolsetHostArchitectureString()
+ const
+{
+ if (!this->GeneratorToolsetHostArchitecture.empty()) {
+ return this->GeneratorToolsetHostArchitecture;
+ }
+ if (!this->DefaultPlatformToolsetHostArchitecture.empty()) {
+ return this->DefaultPlatformToolsetHostArchitecture;
+ }
+ static std::string const empty;
+ return empty;
+}
+
+const char* cmGlobalVisualStudio10Generator::GetPlatformToolsetCuda() const
+{
+ if (!this->GeneratorToolsetCuda.empty()) {
+ return this->GeneratorToolsetCuda.c_str();
+ }
+ return nullptr;
+}
+
+std::string const&
+cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaString() const
+{
+ return this->GeneratorToolsetCuda;
+}
+
+const char* cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaCustomDir()
+ const
+{
+ if (!this->GeneratorToolsetCudaCustomDir.empty()) {
+ return this->GeneratorToolsetCudaCustomDir.c_str();
+ }
+ return nullptr;
+}
+
+std::string const&
+cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaCustomDirString() const
+{
+ return this->GeneratorToolsetCudaCustomDir;
+}
+
+std::string const&
+cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaNvccSubdirString() const
+{
+ return this->GeneratorToolsetCudaNvccSubdir;
+}
+
+std::string const& cmGlobalVisualStudio10Generator::
+ GetPlatformToolsetCudaVSIntegrationSubdirString() const
+{
+ return this->GeneratorToolsetCudaVSIntegrationSubdir;
+}
+
+cmGlobalVisualStudio10Generator::AuxToolset
+cmGlobalVisualStudio10Generator::FindAuxToolset(std::string&,
+ std::string&) const
+{
+ return AuxToolset::None;
+}
+
+bool cmGlobalVisualStudio10Generator::FindMakeProgram(cmMakefile* mf)
+{
+ if (!this->cmGlobalVisualStudio8Generator::FindMakeProgram(mf)) {
+ return false;
+ }
+ mf->AddDefinition("CMAKE_VS_MSBUILD_COMMAND", this->GetMSBuildCommand());
+ return true;
+}
+
+std::string const& cmGlobalVisualStudio10Generator::GetMSBuildCommand()
+{
+ if (!this->MSBuildCommandInitialized) {
+ this->MSBuildCommandInitialized = true;
+ this->MSBuildCommand = this->FindMSBuildCommand();
+ }
+ return this->MSBuildCommand;
+}
+
+std::string cmGlobalVisualStudio10Generator::FindMSBuildCommand()
+{
+ std::string msbuild;
+ std::string mskey;
+
+ // Search in standard location.
+ mskey = cmStrCat(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\",
+ this->GetToolsVersion(), ";MSBuildToolsPath");
+ if (cmSystemTools::ReadRegistryValue(mskey.c_str(), msbuild,
+ cmSystemTools::KeyWOW64_32)) {
+ cmSystemTools::ConvertToUnixSlashes(msbuild);
+ msbuild += "/MSBuild.exe";
+ if (cmSystemTools::FileExists(msbuild, true)) {
+ return msbuild;
+ }
+ }
+
+ msbuild = "MSBuild.exe";
+ return msbuild;
+}
+
+std::string cmGlobalVisualStudio10Generator::FindDevEnvCommand()
+{
+ if (this->ExpressEdition) {
+ // Visual Studio Express >= 10 do not have "devenv.com" or
+ // "VCExpress.exe" that we can use to build reliably.
+ // Tell the caller it needs to use MSBuild instead.
+ return "";
+ }
+ // Skip over the cmGlobalVisualStudio8Generator implementation because
+ // we expect a real devenv and do not want to look for VCExpress.
+ return this->cmGlobalVisualStudio71Generator::FindDevEnvCommand();
+}
+
+bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf)
+{
+ // Skip this in special cases within our own test suite.
+ if (this->GetPlatformName() == "Test Platform" ||
+ this->GetPlatformToolsetString() == "Test Toolset") {
+ return true;
+ }
+
+ std::string wd;
+ if (!this->ConfiguredFilesPath.empty()) {
+ // In a try-compile we are given the outer CMakeFiles directory.
+ wd = this->ConfiguredFilesPath;
+ } else {
+ wd = cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(),
+ "/CMakeFiles");
+ }
+ wd += "/";
+ wd += cmVersion::GetCMakeVersion();
+
+ // We record the result persistently in a file.
+ std::string const txt = wd + "/VCTargetsPath.txt";
+
+ // If we have a recorded result, use it.
+ {
+ cmsys::ifstream fin(txt.c_str());
+ if (fin && cmSystemTools::GetLineFromStream(fin, this->VCTargetsPath) &&
+ cmSystemTools::FileIsDirectory(this->VCTargetsPath)) {
+ cmSystemTools::ConvertToUnixSlashes(this->VCTargetsPath);
+ return true;
+ }
+ }
+
+ // Prepare the work directory.
+ if (!cmSystemTools::MakeDirectory(wd)) {
+ std::string e = "Failed to make directory:\n " + wd;
+ mf->IssueMessage(MessageType::FATAL_ERROR, e);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ // Generate a project file for MSBuild to tell us the VCTargetsPath value.
+ std::string const vcxproj = "VCTargetsPath.vcxproj";
+ {
+ std::string const vcxprojAbs = wd + "/" + vcxproj;
+ cmsys::ofstream fout(vcxprojAbs.c_str());
+ cmXMLWriter xw(fout);
+
+ cmXMLDocument doc(xw);
+ cmXMLElement eprj(doc, "Project");
+ eprj.Attribute("DefaultTargets", "Build");
+ eprj.Attribute("ToolsVersion", "4.0");
+ eprj.Attribute("xmlns",
+ "http://schemas.microsoft.com/developer/msbuild/2003");
+ if (this->IsNsightTegra()) {
+ cmXMLElement epg(eprj, "PropertyGroup");
+ epg.Attribute("Label", "NsightTegraProject");
+ cmXMLElement(epg, "NsightTegraProjectRevisionNumber").Content("6");
+ }
+ {
+ cmXMLElement eig(eprj, "ItemGroup");
+ eig.Attribute("Label", "ProjectConfigurations");
+ cmXMLElement epc(eig, "ProjectConfiguration");
+ epc.Attribute("Include", "Debug|" + this->GetPlatformName());
+ cmXMLElement(epc, "Configuration").Content("Debug");
+ cmXMLElement(epc, "Platform").Content(this->GetPlatformName());
+ }
+ {
+ cmXMLElement epg(eprj, "PropertyGroup");
+ epg.Attribute("Label", "Globals");
+ cmXMLElement(epg, "ProjectGuid")
+ .Content("{F3FC6D86-508D-3FB1-96D2-995F08B142EC}");
+ cmXMLElement(epg, "Keyword")
+ .Content(mf->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android"
+ ? "Android"
+ : "Win32Proj");
+ cmXMLElement(epg, "Platform").Content(this->GetPlatformName());
+ if (this->GetSystemName() == "WindowsPhone") {
+ cmXMLElement(epg, "ApplicationType").Content("Windows Phone");
+ cmXMLElement(epg, "ApplicationTypeRevision")
+ .Content(this->GetApplicationTypeRevision());
+ } else if (this->GetSystemName() == "WindowsStore") {
+ cmXMLElement(epg, "ApplicationType").Content("Windows Store");
+ cmXMLElement(epg, "ApplicationTypeRevision")
+ .Content(this->GetApplicationTypeRevision());
+ } else if (this->GetSystemName() == "Android") {
+ cmXMLElement(epg, "ApplicationType").Content("Android");
+ cmXMLElement(epg, "ApplicationTypeRevision")
+ .Content(this->GetApplicationTypeRevision());
+ }
+ if (!this->WindowsTargetPlatformVersion.empty()) {
+ cmXMLElement(epg, "WindowsTargetPlatformVersion")
+ .Content(this->WindowsTargetPlatformVersion);
+ }
+ if (this->GetSystemName() != "Android") {
+ if (this->GetPlatformName() == "ARM64") {
+ cmXMLElement(epg, "WindowsSDKDesktopARM64Support").Content("true");
+ } else if (this->GetPlatformName() == "ARM") {
+ cmXMLElement(epg, "WindowsSDKDesktopARMSupport").Content("true");
+ }
+ }
+ }
+ cmXMLElement(eprj, "Import")
+ .Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.Default.props");
+ if (const char* hostArch = this->GetPlatformToolsetHostArchitecture()) {
+ cmXMLElement epg(eprj, "PropertyGroup");
+ cmXMLElement(epg, "PreferredToolArchitecture").Content(hostArch);
+ }
+ {
+ cmXMLElement epg(eprj, "PropertyGroup");
+ epg.Attribute("Label", "Configuration");
+ {
+ cmXMLElement ect(epg, "ConfigurationType");
+ if (this->IsNsightTegra()) {
+ // Tegra-Android platform does not understand "Utility".
+ ect.Content("StaticLibrary");
+ } else {
+ ect.Content("Utility");
+ }
+ }
+ cmXMLElement(epg, "CharacterSet").Content("MultiByte");
+ if (this->IsNsightTegra()) {
+ cmXMLElement(epg, "NdkToolchainVersion")
+ .Content(this->GetPlatformToolsetString());
+ } else {
+ cmXMLElement(epg, "PlatformToolset")
+ .Content(this->GetPlatformToolsetString());
+ }
+ }
+ cmXMLElement(eprj, "Import")
+ .Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props");
+ {
+ cmXMLElement eidg(eprj, "ItemDefinitionGroup");
+ cmXMLElement epbe(eidg, "PostBuildEvent");
+ cmXMLElement(epbe, "Command")
+ .Content("echo VCTargetsPath=$(VCTargetsPath)");
+ }
+ cmXMLElement(eprj, "Import")
+ .Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets");
+ }
+
+ std::vector<std::string> cmd;
+ cmd.push_back(this->GetMSBuildCommand());
+ cmd.push_back(vcxproj);
+ cmd.push_back("/p:Configuration=Debug");
+ cmd.push_back(std::string("/p:VisualStudioVersion=") +
+ this->GetIDEVersion());
+ std::string out;
+ int ret = 0;
+ cmsys::RegularExpression regex("\n *VCTargetsPath=([^%\r\n]+)[\r\n]");
+ if (!cmSystemTools::RunSingleCommand(cmd, &out, &out, &ret, wd.c_str(),
+ cmSystemTools::OUTPUT_NONE) ||
+ ret != 0 || !regex.find(out)) {
+ cmSystemTools::ReplaceString(out, "\n", "\n ");
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Failed to run MSBuild command:\n"
+ " " << cmd[0] << "\n"
+ "to get the value of VCTargetsPath:\n"
+ " " << out << "\n"
+ ;
+ /* clang-format on */
+ if (ret != 0) {
+ e << "Exit code: " << ret << "\n";
+ }
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ this->VCTargetsPath = regex.match(1);
+ cmSystemTools::ConvertToUnixSlashes(this->VCTargetsPath);
+
+ {
+ cmsys::ofstream fout(txt.c_str());
+ fout << this->VCTargetsPath << "\n";
+ }
+ return true;
+}
+
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalVisualStudio10Generator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions)
+{
+ std::vector<GeneratedMakeCommand> makeCommands;
+ // Select the caller- or user-preferred make program, else MSBuild.
+ std::string makeProgramSelected =
+ this->SelectMakeProgram(makeProgram, this->GetMSBuildCommand());
+
+ // Check if the caller explicitly requested a devenv tool.
+ std::string makeProgramLower = makeProgramSelected;
+ cmSystemTools::LowerCase(makeProgramLower);
+ bool useDevEnv = (makeProgramLower.find("devenv") != std::string::npos ||
+ makeProgramLower.find("vcexpress") != std::string::npos);
+
+ // Workaround to convince VCExpress.exe to produce output.
+ const bool requiresOutputForward =
+ (makeProgramLower.find("vcexpress") != std::string::npos);
+
+ // MSBuild is preferred (and required for VS Express), but if the .sln has
+ // an Intel Fortran .vfproj then we have to use devenv. Parse it to find out.
+ cmSlnData slnData;
+ {
+ std::string slnFile;
+ if (!projectDir.empty()) {
+ slnFile = cmStrCat(projectDir, '/');
+ }
+ slnFile += projectName;
+ slnFile += ".sln";
+ cmVisualStudioSlnParser parser;
+ if (parser.ParseFile(slnFile, slnData,
+ cmVisualStudioSlnParser::DataGroupProjects)) {
+ std::vector<cmSlnProjectEntry> slnProjects = slnData.GetProjects();
+ for (cmSlnProjectEntry const& project : slnProjects) {
+ if (useDevEnv) {
+ break;
+ }
+ std::string proj = project.GetRelativePath();
+ if (proj.size() > 7 && proj.substr(proj.size() - 7) == ".vfproj") {
+ useDevEnv = true;
+ }
+ }
+ }
+ }
+ if (useDevEnv) {
+ // Use devenv to build solutions containing Intel Fortran projects.
+ return cmGlobalVisualStudio7Generator::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast, jobs,
+ verbose, makeOptions);
+ }
+
+ std::vector<std::string> realTargetNames = targetNames;
+ if (targetNames.empty() ||
+ ((targetNames.size() == 1) && targetNames.front().empty())) {
+ realTargetNames = { "ALL_BUILD" };
+ }
+ for (const auto& tname : realTargetNames) {
+ // msbuild.exe CxxOnly.sln /t:Build /p:Configuration=Debug
+ // /target:ALL_BUILD
+ // /m
+ if (tname.empty()) {
+ continue;
+ }
+
+ GeneratedMakeCommand makeCommand;
+ makeCommand.RequiresOutputForward = requiresOutputForward;
+ makeCommand.Add(makeProgramSelected);
+
+ if (tname == "clean") {
+ makeCommand.Add(std::string(projectName) + ".sln");
+ makeCommand.Add("/t:Clean");
+ } else {
+ std::string targetProject = cmStrCat(tname, ".vcxproj");
+ if (targetProject.find('/') == std::string::npos) {
+ // it might be in a subdir
+ if (cmSlnProjectEntry const* proj = slnData.GetProjectByName(tname)) {
+ targetProject = proj->GetRelativePath();
+ cmSystemTools::ConvertToUnixSlashes(targetProject);
+ }
+ }
+ makeCommand.Add(std::move(targetProject));
+ }
+ std::string configArg = "/p:Configuration=";
+ if (!config.empty()) {
+ configArg += config;
+ } else {
+ configArg += "Debug";
+ }
+ makeCommand.Add(configArg);
+ makeCommand.Add(std::string("/p:Platform=") + this->GetPlatformName());
+ makeCommand.Add(std::string("/p:VisualStudioVersion=") +
+ this->GetIDEVersion());
+
+ if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
+ if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
+ makeCommand.Add("/m");
+ } else {
+ makeCommand.Add(std::string("/m:") + std::to_string(jobs));
+ }
+ // Having msbuild.exe and cl.exe using multiple jobs is discouraged
+ makeCommand.Add("/p:CL_MPCount=1");
+ }
+
+ // Respect the verbosity: 'n' normal will show build commands
+ // 'm' minimal only the build step's title
+ makeCommand.Add(std::string("/v:") + ((verbose) ? "n" : "m"));
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ makeCommands.emplace_back(std::move(makeCommand));
+ }
+ return makeCommands;
+}
+
+bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
+{
+ if (this->DefaultPlatformToolset == "v100") {
+ // The v100 64-bit toolset does not exist in the express edition.
+ this->DefaultPlatformToolset.clear();
+ }
+ if (this->GetPlatformToolset()) {
+ return true;
+ }
+ // This edition does not come with 64-bit tools. Look for them.
+ //
+ // TODO: Detect available tools? x64\v100 exists but does not work?
+ // HKLM\\SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\4.0;VCTargetsPath
+ // c:/Program Files (x86)/MSBuild/Microsoft.Cpp/v4.0/Platforms/
+ // {Itanium,Win32,x64}/PlatformToolsets/{v100,v90,Windows7.1SDK}
+ std::string winSDK_7_1;
+ if (cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\"
+ "Windows\\v7.1;InstallationFolder",
+ winSDK_7_1)) {
+ std::ostringstream m;
+ m << "Found Windows SDK v7.1: " << winSDK_7_1;
+ mf->DisplayStatus(m.str(), -1);
+ this->DefaultPlatformToolset = "Windows7.1SDK";
+ return true;
+ } else {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "Cannot enable 64-bit tools with Visual Studio 2010 Express.\n"
+ << "Install the Microsoft Windows SDK v7.1 to get 64-bit tools:\n"
+ << " http://msdn.microsoft.com/en-us/windows/bb980924.aspx";
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str().c_str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+}
+
+std::string cmGlobalVisualStudio10Generator::GenerateRuleFile(
+ std::string const& output) const
+{
+ // The VS 10 generator needs to create the .rule files on disk.
+ // Hide them away under the CMakeFiles directory.
+ std::string ruleDir = cmStrCat(
+ this->GetCMakeInstance()->GetHomeOutputDirectory(), "/CMakeFiles/",
+ cmSystemTools::ComputeStringMD5(cmSystemTools::GetFilenamePath(output)));
+ std::string ruleFile =
+ cmStrCat(ruleDir, '/', cmSystemTools::GetFilenameName(output), ".rule");
+ return ruleFile;
+}
+
+void cmGlobalVisualStudio10Generator::PathTooLong(cmGeneratorTarget* target,
+ cmSourceFile const* sf,
+ std::string const& sfRel)
+{
+ size_t len =
+ (target->GetLocalGenerator()->GetCurrentBinaryDirectory().length() + 1 +
+ sfRel.length());
+ if (len > this->LongestSource.Length) {
+ this->LongestSource.Length = len;
+ this->LongestSource.Target = target;
+ this->LongestSource.SourceFile = sf;
+ this->LongestSource.SourceRel = sfRel;
+ }
+}
+
+std::string cmGlobalVisualStudio10Generator::Encoding()
+{
+ return "utf-8";
+}
+
+const char* cmGlobalVisualStudio10Generator::GetToolsVersion() const
+{
+ switch (this->Version) {
+ case cmGlobalVisualStudioGenerator::VS9:
+ case cmGlobalVisualStudioGenerator::VS10:
+ case cmGlobalVisualStudioGenerator::VS11:
+ return "4.0";
+
+ // in Visual Studio 2013 they detached the MSBuild tools version
+ // from the .Net Framework version and instead made it have it's own
+ // version number
+ case cmGlobalVisualStudioGenerator::VS12:
+ return "12.0";
+ case cmGlobalVisualStudioGenerator::VS14:
+ return "14.0";
+ case cmGlobalVisualStudioGenerator::VS15:
+ return "15.0";
+ case cmGlobalVisualStudioGenerator::VS16:
+ return "16.0";
+ }
+ return "";
+}
+
+bool cmGlobalVisualStudio10Generator::IsNsightTegra() const
+{
+ return !this->NsightTegraVersion.empty();
+}
+
+std::string cmGlobalVisualStudio10Generator::GetNsightTegraVersion() const
+{
+ return this->NsightTegraVersion;
+}
+
+std::string cmGlobalVisualStudio10Generator::GetInstalledNsightTegraVersion()
+{
+ std::string version;
+ cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NVIDIA Corporation\\Nsight Tegra;"
+ "Version",
+ version, cmSystemTools::KeyWOW64_32);
+ return version;
+}
+
+std::string cmGlobalVisualStudio10Generator::GetApplicationTypeRevision() const
+{
+ if (this->GetSystemName() == "Android") {
+ return this->GetAndroidApplicationTypeRevision();
+ }
+
+ // Return the first two '.'-separated components of the Windows version.
+ std::string::size_type end1 = this->SystemVersion.find('.');
+ std::string::size_type end2 =
+ end1 == std::string::npos ? end1 : this->SystemVersion.find('.', end1 + 1);
+ return this->SystemVersion.substr(0, end2);
+}
+
+static std::string cmLoadFlagTableString(Json::Value entry, const char* field)
+{
+ if (entry.isMember(field)) {
+ auto string = entry[field];
+ if (string.isConvertibleTo(Json::ValueType::stringValue)) {
+ return string.asString();
+ }
+ }
+ return "";
+}
+
+static unsigned int cmLoadFlagTableSpecial(Json::Value entry,
+ const char* field)
+{
+ unsigned int value = 0;
+ if (entry.isMember(field)) {
+ auto specials = entry[field];
+ if (specials.isArray()) {
+ for (auto const& special : specials) {
+ std::string s = special.asString();
+ if (s == "UserValue") {
+ value |= cmIDEFlagTable::UserValue;
+ } else if (s == "UserIgnored") {
+ value |= cmIDEFlagTable::UserIgnored;
+ } else if (s == "UserRequired") {
+ value |= cmIDEFlagTable::UserRequired;
+ } else if (s == "Continue") {
+ value |= cmIDEFlagTable::Continue;
+ } else if (s == "SemicolonAppendable") {
+ value |= cmIDEFlagTable::SemicolonAppendable;
+ } else if (s == "UserFollowing") {
+ value |= cmIDEFlagTable::UserFollowing;
+ } else if (s == "CaseInsensitive") {
+ value |= cmIDEFlagTable::CaseInsensitive;
+ } else if (s == "SpaceAppendable") {
+ value |= cmIDEFlagTable::SpaceAppendable;
+ } else if (s == "CommaAppendable") {
+ value |= cmIDEFlagTable::CommaAppendable;
+ }
+ }
+ }
+ }
+ return value;
+}
+
+static cmIDEFlagTable const* cmLoadFlagTableJson(
+ std::string const& flagJsonPath)
+{
+ cmIDEFlagTable* ret = nullptr;
+ auto savedFlagIterator = loadedFlagJsonFiles.find(flagJsonPath);
+ if (savedFlagIterator != loadedFlagJsonFiles.end()) {
+ ret = savedFlagIterator->second.data();
+ } else {
+ Json::Reader reader;
+ cmsys::ifstream stream;
+
+ stream.open(flagJsonPath.c_str(), std::ios_base::in);
+ if (stream) {
+ Json::Value flags;
+ if (reader.parse(stream, flags, false) && flags.isArray()) {
+ std::vector<cmIDEFlagTable> flagTable;
+ for (auto const& flag : flags) {
+ cmIDEFlagTable flagEntry;
+ flagEntry.IDEName = cmLoadFlagTableString(flag, "name");
+ flagEntry.commandFlag = cmLoadFlagTableString(flag, "switch");
+ flagEntry.comment = cmLoadFlagTableString(flag, "comment");
+ flagEntry.value = cmLoadFlagTableString(flag, "value");
+ flagEntry.special = cmLoadFlagTableSpecial(flag, "flags");
+ flagTable.push_back(flagEntry);
+ }
+ cmIDEFlagTable endFlag{ "", "", "", "", 0 };
+ flagTable.push_back(endFlag);
+
+ loadedFlagJsonFiles[flagJsonPath] = flagTable;
+ ret = loadedFlagJsonFiles[flagJsonPath].data();
+ }
+ }
+ }
+ return ret;
+}
+
+cm::optional<std::string> cmGlobalVisualStudio10Generator::FindFlagTable(
+ cm::string_view toolsetName, cm::string_view table) const
+{
+ if (!this->CustomFlagTableDir.empty()) {
+ std::string customFlagTableFile =
+ cmStrCat(this->CustomFlagTableDir, '/', this->GetPlatformName(), '_',
+ toolsetName, '_', table, ".json");
+ if (cmSystemTools::FileExists(customFlagTableFile)) {
+ return customFlagTableFile;
+ }
+ customFlagTableFile =
+ cmStrCat(this->CustomFlagTableDir, '/', this->GetPlatformName(), '_',
+ table, ".json");
+ if (cmSystemTools::FileExists(customFlagTableFile)) {
+ return customFlagTableFile;
+ }
+ }
+ std::string fullPath =
+ cmStrCat(cmSystemTools::GetCMakeRoot(), "/Templates/MSBuild/FlagTables/",
+ toolsetName, '_', table, ".json");
+ if (cmSystemTools::FileExists(fullPath)) {
+ return fullPath;
+ }
+ return {};
+}
+
+cmIDEFlagTable const* cmGlobalVisualStudio10Generator::LoadFlagTable(
+ std::string const& toolSpecificName, std::string const& defaultName,
+ std::string const& table) const
+{
+ cmMakefile* mf = this->GetCurrentMakefile();
+
+ std::string filename;
+ if (!toolSpecificName.empty()) {
+ if (cm::optional<std::string> found =
+ this->FindFlagTable(toolSpecificName, table)) {
+ filename = std::move(*found);
+ } else {
+ mf->IssueMessage(MessageType::FATAL_ERROR,
+ cmStrCat("JSON flag table for ", table,
+ " not found for toolset ", toolSpecificName));
+ return nullptr;
+ }
+ } else {
+ std::string const& genericName =
+ this->CanonicalToolsetName(this->GetPlatformToolsetString());
+ cm::optional<std::string> found = this->FindFlagTable(genericName, table);
+ if (!found) {
+ found = this->FindFlagTable(defaultName, table);
+ }
+ if (found) {
+ filename = std::move(*found);
+ } else {
+ mf->IssueMessage(MessageType::FATAL_ERROR,
+ cmStrCat("JSON flag table for ", table,
+ " not found for toolset ", genericName, " ",
+ defaultName));
+ return nullptr;
+ }
+ }
+
+ if (cmIDEFlagTable const* ret = cmLoadFlagTableJson(filename)) {
+ return ret;
+ }
+
+ mf->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("JSON flag table could not be loaded:\n ", filename));
+ return nullptr;
+}
+
+cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetClFlagTable() const
+{
+ return LoadFlagTable(this->GetClFlagTableName(),
+ this->DefaultCLFlagTableName, "CL");
+}
+
+cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCSharpFlagTable()
+ const
+{
+ return LoadFlagTable(this->GetCSharpFlagTableName(),
+ this->DefaultCSharpFlagTableName, "CSharp");
+}
+
+cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetRcFlagTable() const
+{
+ return LoadFlagTable(this->GetRcFlagTableName(),
+ this->DefaultRCFlagTableName, "RC");
+}
+
+cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetLibFlagTable() const
+{
+ return LoadFlagTable(this->GetLibFlagTableName(),
+ this->DefaultLibFlagTableName, "LIB");
+}
+
+cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetLinkFlagTable() const
+{
+ return LoadFlagTable(this->GetLinkFlagTableName(),
+ this->DefaultLinkFlagTableName, "Link");
+}
+
+cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaFlagTable() const
+{
+ return LoadFlagTable(std::string(), this->DefaultCudaFlagTableName, "Cuda");
+}
+
+cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaHostFlagTable()
+ const
+{
+ return LoadFlagTable(std::string(), this->DefaultCudaHostFlagTableName,
+ "CudaHost");
+}
+
+cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetMasmFlagTable() const
+{
+ return LoadFlagTable(this->GetMasmFlagTableName(),
+ this->DefaultMasmFlagTableName, "MASM");
+}
+
+cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetNasmFlagTable() const
+{
+ return LoadFlagTable(std::string(), this->DefaultNasmFlagTableName, "NASM");
+}
+
+std::string cmGlobalVisualStudio10Generator::GetClFlagTableName() const
+{
+ std::string const& toolset = this->GetPlatformToolsetString();
+ std::string const useToolset = this->CanonicalToolsetName(toolset);
+
+ if (toolset == "v142") {
+ return "v142";
+ } else if (toolset == "v141") {
+ return "v141";
+ } else if (useToolset == "v140") {
+ return "v140";
+ } else if (useToolset == "v120") {
+ return "v12";
+ } else if (useToolset == "v110") {
+ return "v11";
+ } else if (useToolset == "v100") {
+ return "v10";
+ } else {
+ return "";
+ }
+}
+
+std::string cmGlobalVisualStudio10Generator::GetCSharpFlagTableName() const
+{
+ std::string const& toolset = this->GetPlatformToolsetString();
+ std::string const useToolset = this->CanonicalToolsetName(toolset);
+
+ if (useToolset == "v142") {
+ return "v142";
+ } else if (useToolset == "v141") {
+ return "v141";
+ } else if (useToolset == "v140") {
+ return "v140";
+ } else if (useToolset == "v120") {
+ return "v12";
+ } else if (useToolset == "v110") {
+ return "v11";
+ } else if (useToolset == "v100") {
+ return "v10";
+ } else {
+ return "";
+ }
+}
+
+std::string cmGlobalVisualStudio10Generator::GetRcFlagTableName() const
+{
+ std::string const& toolset = this->GetPlatformToolsetString();
+ std::string const useToolset = this->CanonicalToolsetName(toolset);
+
+ if ((useToolset == "v140") || (useToolset == "v141") ||
+ (useToolset == "v142")) {
+ return "v14";
+ } else if (useToolset == "v120") {
+ return "v12";
+ } else if (useToolset == "v110") {
+ return "v11";
+ } else if (useToolset == "v100") {
+ return "v10";
+ } else {
+ return "";
+ }
+}
+
+std::string cmGlobalVisualStudio10Generator::GetLibFlagTableName() const
+{
+ std::string const& toolset = this->GetPlatformToolsetString();
+ std::string const useToolset = this->CanonicalToolsetName(toolset);
+
+ if ((useToolset == "v140") || (useToolset == "v141") ||
+ (useToolset == "v142")) {
+ return "v14";
+ } else if (useToolset == "v120") {
+ return "v12";
+ } else if (useToolset == "v110") {
+ return "v11";
+ } else if (useToolset == "v100") {
+ return "v10";
+ } else {
+ return "";
+ }
+}
+
+std::string cmGlobalVisualStudio10Generator::GetLinkFlagTableName() const
+{
+ std::string const& toolset = this->GetPlatformToolsetString();
+ std::string const useToolset = this->CanonicalToolsetName(toolset);
+
+ if (useToolset == "v142") {
+ return "v142";
+ } else if (useToolset == "v141") {
+ return "v141";
+ } else if (useToolset == "v140") {
+ return "v140";
+ } else if (useToolset == "v120") {
+ return "v12";
+ } else if (useToolset == "v110") {
+ return "v11";
+ } else if (useToolset == "v100") {
+ return "v10";
+ } else {
+ return "";
+ }
+}
+
+std::string cmGlobalVisualStudio10Generator::GetMasmFlagTableName() const
+{
+ std::string const& toolset = this->GetPlatformToolsetString();
+ std::string const useToolset = this->CanonicalToolsetName(toolset);
+
+ if ((useToolset == "v140") || (useToolset == "v141") ||
+ (useToolset == "v142")) {
+ return "v14";
+ } else if (useToolset == "v120") {
+ return "v12";
+ } else if (useToolset == "v110") {
+ return "v11";
+ } else if (useToolset == "v100") {
+ return "v10";
+ } else {
+ return "";
+ }
+}
+
+std::string cmGlobalVisualStudio10Generator::CanonicalToolsetName(
+ std::string const& toolset) const
+{
+ std::size_t length = toolset.length();
+
+ if (cmHasLiteralSuffix(toolset, "_xp")) {
+ length -= 3;
+ }
+
+ return toolset.substr(0, length);
+}
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
new file mode 100644
index 0000000..2596720
--- /dev/null
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -0,0 +1,275 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <memory>
+#include <set>
+
+#include <cm/optional>
+#include <cm/string_view>
+
+#include "cmGlobalVisualStudio8Generator.h"
+
+/** \class cmGlobalVisualStudio10Generator
+ * \brief Write a Unix makefiles.
+ *
+ * cmGlobalVisualStudio10Generator manages UNIX build process for a tree
+ */
+class cmGlobalVisualStudio10Generator : public cmGlobalVisualStudio8Generator
+{
+public:
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory();
+
+ bool MatchesGeneratorName(const std::string& name) const override;
+
+ bool SetSystemName(std::string const& s, cmMakefile* mf) override;
+ bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override;
+ bool SetGeneratorToolset(std::string const& ts, bool build,
+ cmMakefile* mf) override;
+
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
+
+ //! create the correct local generator
+ std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+ cmMakefile* mf) override;
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) override;
+
+ void AddAndroidExecutableWarning(const std::string& name)
+ {
+ this->AndroidExecutableWarnings.insert(name);
+ }
+
+ bool IsCudaEnabled() const { return this->CudaEnabled; }
+
+ /** Generating for Nsight Tegra VS plugin? */
+ bool IsNsightTegra() const;
+ std::string GetNsightTegraVersion() const;
+
+ /** The vctargets path for the target platform. */
+ const char* GetCustomVCTargetsPath() const;
+
+ /** The toolset name for the target platform. */
+ const char* GetPlatformToolset() const;
+ std::string const& GetPlatformToolsetString() const;
+
+ /** The toolset version props file, if any. */
+ std::string const& GetPlatformToolsetVersionProps() const;
+
+ /** The toolset host architecture name (e.g. x64 for 64-bit host tools). */
+ const char* GetPlatformToolsetHostArchitecture() const;
+ std::string const& GetPlatformToolsetHostArchitectureString() const;
+
+ /** The cuda toolset version. */
+ const char* GetPlatformToolsetCuda() const;
+ std::string const& GetPlatformToolsetCudaString() const;
+
+ /** The custom cuda install directory */
+ const char* GetPlatformToolsetCudaCustomDir() const;
+ std::string const& GetPlatformToolsetCudaCustomDirString() const;
+
+ /** The nvcc subdirectory of a custom cuda install directory */
+ std::string const& GetPlatformToolsetCudaNvccSubdirString() const;
+
+ /** The visual studio integration subdirectory of a custom cuda install
+ * directory */
+ std::string const& GetPlatformToolsetCudaVSIntegrationSubdirString() const;
+
+ /** Return whether we need to use No/Debug instead of false/true
+ for GenerateDebugInformation. */
+ bool GetPlatformToolsetNeedsDebugEnum() const
+ {
+ return this->PlatformToolsetNeedsDebugEnum;
+ }
+
+ /** Return the CMAKE_SYSTEM_NAME. */
+ std::string const& GetSystemName() const { return this->SystemName; }
+
+ /** Return the CMAKE_SYSTEM_VERSION. */
+ std::string const& GetSystemVersion() const { return this->SystemVersion; }
+
+ /** Return the Windows version targeted on VS 2015 and above. */
+ std::string const& GetWindowsTargetPlatformVersion() const
+ {
+ return this->WindowsTargetPlatformVersion;
+ }
+
+ /** Return true if building for WindowsCE */
+ bool TargetsWindowsCE() const override { return this->SystemIsWindowsCE; }
+
+ /** Return true if building for WindowsPhone */
+ bool TargetsWindowsPhone() const { return this->SystemIsWindowsPhone; }
+
+ /** Return true if building for WindowsStore */
+ bool TargetsWindowsStore() const { return this->SystemIsWindowsStore; }
+
+ /** Return true if building for Android */
+ bool TargetsAndroid() const { return this->SystemIsAndroid; }
+
+ const char* GetCMakeCFGIntDir() const override { return "$(Configuration)"; }
+ bool Find64BitTools(cmMakefile* mf);
+
+ /** Generate an <output>.rule file path for a given command output. */
+ std::string GenerateRuleFile(std::string const& output) const override;
+
+ void PathTooLong(cmGeneratorTarget* target, cmSourceFile const* sf,
+ std::string const& sfRel);
+
+ std::string Encoding() override;
+ const char* GetToolsVersion() const;
+
+ bool GetSupportsUnityBuilds() const { return this->SupportsUnityBuilds; }
+
+ bool FindMakeProgram(cmMakefile* mf) override;
+
+ bool IsIPOSupported() const override { return true; }
+
+ virtual bool IsStdOutEncodingSupported() const { return false; }
+
+ static std::string GetInstalledNsightTegraVersion();
+
+ /** Return the first two components of CMAKE_SYSTEM_VERSION. */
+ std::string GetApplicationTypeRevision() const;
+
+ virtual const char* GetAndroidApplicationTypeRevision() const { return ""; }
+
+ cmIDEFlagTable const* GetClFlagTable() const;
+ cmIDEFlagTable const* GetCSharpFlagTable() const;
+ cmIDEFlagTable const* GetRcFlagTable() const;
+ cmIDEFlagTable const* GetLibFlagTable() const;
+ cmIDEFlagTable const* GetLinkFlagTable() const;
+ cmIDEFlagTable const* GetCudaFlagTable() const;
+ cmIDEFlagTable const* GetCudaHostFlagTable() const;
+ cmIDEFlagTable const* GetMasmFlagTable() const;
+ cmIDEFlagTable const* GetNasmFlagTable() const;
+
+protected:
+ cmGlobalVisualStudio10Generator(cmake* cm, const std::string& name,
+ std::string const& platformInGeneratorName);
+
+ void Generate() override;
+ virtual bool InitializeSystem(cmMakefile* mf);
+ virtual bool InitializeWindows(cmMakefile* mf);
+ virtual bool InitializeWindowsCE(cmMakefile* mf);
+ virtual bool InitializeWindowsPhone(cmMakefile* mf);
+ virtual bool InitializeWindowsStore(cmMakefile* mf);
+ virtual bool InitializeTegraAndroid(cmMakefile* mf);
+ virtual bool InitializeAndroid(cmMakefile* mf);
+
+ virtual bool ProcessGeneratorToolsetField(std::string const& key,
+ std::string const& value);
+
+ virtual std::string SelectWindowsCEToolset() const;
+ virtual bool SelectWindowsPhoneToolset(std::string& toolset) const;
+ virtual bool SelectWindowsStoreToolset(std::string& toolset) const;
+
+ enum class AuxToolset
+ {
+ None,
+ Default,
+ PropsExist,
+ PropsMissing
+ };
+ virtual AuxToolset FindAuxToolset(std::string& version,
+ std::string& props) const;
+
+ std::string const& GetMSBuildCommand();
+
+ cmIDEFlagTable const* LoadFlagTable(std::string const& toolSpecificName,
+ std::string const& defaultName,
+ std::string const& table) const;
+
+ std::string GeneratorToolset;
+ std::string GeneratorToolsetVersionProps;
+ std::string GeneratorToolsetHostArchitecture;
+ std::string GeneratorToolsetCustomVCTargetsDir;
+ std::string GeneratorToolsetCuda;
+ std::string GeneratorToolsetCudaCustomDir;
+ std::string GeneratorToolsetCudaNvccSubdir;
+ std::string GeneratorToolsetCudaVSIntegrationSubdir;
+ std::string DefaultPlatformToolset;
+ std::string DefaultPlatformToolsetHostArchitecture;
+ std::string DefaultAndroidToolset;
+ std::string WindowsTargetPlatformVersion;
+ std::string SystemName;
+ std::string SystemVersion;
+ std::string NsightTegraVersion;
+ std::string DefaultCLFlagTableName;
+ std::string DefaultCSharpFlagTableName;
+ std::string DefaultLibFlagTableName;
+ std::string DefaultLinkFlagTableName;
+ std::string DefaultCudaFlagTableName;
+ std::string DefaultCudaHostFlagTableName;
+ std::string DefaultMasmFlagTableName;
+ std::string DefaultNasmFlagTableName;
+ std::string DefaultRCFlagTableName;
+ bool SupportsUnityBuilds = false;
+ bool SystemIsWindowsCE = false;
+ bool SystemIsWindowsPhone = false;
+ bool SystemIsWindowsStore = false;
+ bool SystemIsAndroid = false;
+
+private:
+ class Factory;
+ friend class Factory;
+
+ struct LongestSourcePath
+ {
+ LongestSourcePath()
+ : Length(0)
+ , Target(0)
+ , SourceFile(0)
+ {
+ }
+ size_t Length;
+ cmGeneratorTarget* Target;
+ cmSourceFile const* SourceFile;
+ std::string SourceRel;
+ };
+ LongestSourcePath LongestSource;
+
+ std::string MSBuildCommand;
+ bool MSBuildCommandInitialized;
+ std::set<std::string> AndroidExecutableWarnings;
+ virtual std::string FindMSBuildCommand();
+ std::string FindDevEnvCommand() override;
+ std::string GetVSMakeProgram() override { return this->GetMSBuildCommand(); }
+
+ std::string GeneratorToolsetVersion;
+
+ bool PlatformToolsetNeedsDebugEnum;
+
+ bool ParseGeneratorToolset(std::string const& ts, cmMakefile* mf);
+
+ std::string GetClFlagTableName() const;
+ std::string GetCSharpFlagTableName() const;
+ std::string GetRcFlagTableName() const;
+ std::string GetLibFlagTableName() const;
+ std::string GetLinkFlagTableName() const;
+ std::string GetMasmFlagTableName() const;
+ std::string CanonicalToolsetName(std::string const& toolset) const;
+
+ cm::optional<std::string> FindFlagTable(cm::string_view toolsetName,
+ cm::string_view table) const;
+
+ std::string CustomFlagTableDir;
+
+ std::string CustomVCTargetsPath;
+ std::string VCTargetsPath;
+ bool FindVCTargetsPath(cmMakefile* mf);
+
+ bool CudaEnabled;
+
+ // We do not use the reload macros for VS >= 10.
+ std::string GetUserMacrosDirectory() override { return ""; }
+};
diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx
new file mode 100644
index 0000000..a5ffcf0
--- /dev/null
+++ b/Source/cmGlobalVisualStudio11Generator.cxx
@@ -0,0 +1,302 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalVisualStudio11Generator.h"
+
+#include <utility>
+
+#include "cmAlgorithms.h"
+#include "cmDocumentationEntry.h"
+#include "cmLocalVisualStudio10Generator.h"
+#include "cmMakefile.h"
+
+static const char vs11generatorName[] = "Visual Studio 11 2012";
+
+// Map generator name without year to name with year.
+static const char* cmVS11GenName(const std::string& name, std::string& genName)
+{
+ if (strncmp(name.c_str(), vs11generatorName,
+ sizeof(vs11generatorName) - 6) != 0) {
+ return 0;
+ }
+ const char* p = name.c_str() + sizeof(vs11generatorName) - 6;
+ if (cmHasLiteralPrefix(p, " 2012")) {
+ p += 5;
+ }
+ genName = std::string(vs11generatorName) + p;
+ return p;
+}
+
+class cmGlobalVisualStudio11Generator::Factory
+ : public cmGlobalGeneratorFactory
+{
+public:
+ std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+ const std::string& name, bool allowArch, cmake* cm) const override
+ {
+ std::string genName;
+ const char* p = cmVS11GenName(name, genName);
+ if (!p) {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+ if (!*p) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio11Generator(cm, genName, ""));
+ }
+ if (!allowArch || *p++ != ' ') {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+ if (strcmp(p, "Win64") == 0) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio11Generator(cm, genName, "x64"));
+ }
+ if (strcmp(p, "ARM") == 0) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio11Generator(cm, genName, "ARM"));
+ }
+
+ std::set<std::string> installedSDKs =
+ cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs();
+
+ if (installedSDKs.find(p) == installedSDKs.end()) {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+
+ auto ret = std::unique_ptr<cmGlobalVisualStudio11Generator>(
+ new cmGlobalVisualStudio11Generator(cm, name, p));
+ ret->WindowsCEVersion = "8.00";
+ return std::unique_ptr<cmGlobalGenerator>(std::move(ret));
+ }
+
+ void GetDocumentation(cmDocumentationEntry& entry) const override
+ {
+ entry.Name = std::string(vs11generatorName) + " [arch]";
+ entry.Brief = "Generates Visual Studio 2012 project files. "
+ "Optional [arch] can be \"Win64\" or \"ARM\".";
+ }
+
+ std::vector<std::string> GetGeneratorNames() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(vs11generatorName);
+ return names;
+ }
+
+ std::vector<std::string> GetGeneratorNamesWithPlatform() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(vs11generatorName + std::string(" ARM"));
+ names.push_back(vs11generatorName + std::string(" Win64"));
+
+ std::set<std::string> installedSDKs =
+ cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs();
+ for (std::string const& i : installedSDKs) {
+ names.push_back(std::string(vs11generatorName) + " " + i);
+ }
+
+ return names;
+ }
+
+ bool SupportsToolset() const override { return true; }
+ bool SupportsPlatform() const override { return true; }
+
+ std::vector<std::string> GetKnownPlatforms() const override
+ {
+ std::vector<std::string> platforms;
+ platforms.emplace_back("x64");
+ platforms.emplace_back("Win32");
+ platforms.emplace_back("ARM");
+
+ std::set<std::string> installedSDKs =
+ cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs();
+ for (std::string const& i : installedSDKs) {
+ platforms.emplace_back(i);
+ }
+
+ return platforms;
+ }
+
+ std::string GetDefaultPlatformName() const override { return "Win32"; }
+};
+
+std::unique_ptr<cmGlobalGeneratorFactory>
+cmGlobalVisualStudio11Generator::NewFactory()
+{
+ return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
+}
+
+cmGlobalVisualStudio11Generator::cmGlobalVisualStudio11Generator(
+ cmake* cm, const std::string& name,
+ std::string const& platformInGeneratorName)
+ : cmGlobalVisualStudio10Generator(cm, name, platformInGeneratorName)
+{
+ std::string vc11Express;
+ this->ExpressEdition = cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\11.0\\Setup\\VC;"
+ "ProductDir",
+ vc11Express, cmSystemTools::KeyWOW64_32);
+ this->DefaultPlatformToolset = "v110";
+ this->DefaultCLFlagTableName = "v11";
+ this->DefaultCSharpFlagTableName = "v11";
+ this->DefaultLibFlagTableName = "v11";
+ this->DefaultLinkFlagTableName = "v11";
+ this->DefaultMasmFlagTableName = "v11";
+ this->DefaultRCFlagTableName = "v11";
+ this->Version = VS11;
+}
+
+bool cmGlobalVisualStudio11Generator::MatchesGeneratorName(
+ const std::string& name) const
+{
+ std::string genName;
+ if (cmVS11GenName(name, genName)) {
+ return genName == this->GetName();
+ }
+ return false;
+}
+
+bool cmGlobalVisualStudio11Generator::InitializeWindowsPhone(cmMakefile* mf)
+{
+ if (!this->SelectWindowsPhoneToolset(this->DefaultPlatformToolset)) {
+ std::ostringstream e;
+ if (this->DefaultPlatformToolset.empty()) {
+ e << this->GetName() << " supports Windows Phone '8.0', but not '"
+ << this->SystemVersion << "'. Check CMAKE_SYSTEM_VERSION.";
+ } else {
+ e << "A Windows Phone component with CMake requires both the Windows "
+ << "Desktop SDK as well as the Windows Phone '" << this->SystemVersion
+ << "' SDK. Please make sure that you have both installed";
+ }
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ return true;
+}
+
+bool cmGlobalVisualStudio11Generator::InitializeWindowsStore(cmMakefile* mf)
+{
+ if (!this->SelectWindowsStoreToolset(this->DefaultPlatformToolset)) {
+ std::ostringstream e;
+ if (this->DefaultPlatformToolset.empty()) {
+ e << this->GetName() << " supports Windows Store '8.0', but not '"
+ << this->SystemVersion << "'. Check CMAKE_SYSTEM_VERSION.";
+ } else {
+ e << "A Windows Store component with CMake requires both the Windows "
+ << "Desktop SDK as well as the Windows Store '" << this->SystemVersion
+ << "' SDK. Please make sure that you have both installed";
+ }
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ return true;
+}
+
+bool cmGlobalVisualStudio11Generator::SelectWindowsPhoneToolset(
+ std::string& toolset) const
+{
+ if (this->SystemVersion == "8.0") {
+ if (this->IsWindowsPhoneToolsetInstalled() &&
+ this->IsWindowsDesktopToolsetInstalled()) {
+ toolset = "v110_wp80";
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return this->cmGlobalVisualStudio10Generator::SelectWindowsPhoneToolset(
+ toolset);
+}
+
+bool cmGlobalVisualStudio11Generator::SelectWindowsStoreToolset(
+ std::string& toolset) const
+{
+ if (this->SystemVersion == "8.0") {
+ if (this->IsWindowsStoreToolsetInstalled() &&
+ this->IsWindowsDesktopToolsetInstalled()) {
+ toolset = "v110";
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return this->cmGlobalVisualStudio10Generator::SelectWindowsStoreToolset(
+ toolset);
+}
+
+bool cmGlobalVisualStudio11Generator::UseFolderProperty() const
+{
+ // Intentionally skip up to the top-level class implementation.
+ // Folders are not supported by the Express editions in VS10 and earlier,
+ // but they are in VS11 Express and above.
+ return cmGlobalGenerator::UseFolderProperty();
+}
+
+std::set<std::string>
+cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs()
+{
+ const char sdksKey[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "Windows CE Tools\\SDKs";
+
+ std::vector<std::string> subkeys;
+ cmSystemTools::GetRegistrySubKeys(sdksKey, subkeys,
+ cmSystemTools::KeyWOW64_32);
+
+ std::set<std::string> ret;
+ for (std::string const& i : subkeys) {
+ std::string key = sdksKey;
+ key += '\\';
+ key += i;
+ key += ';';
+
+ std::string path;
+ if (cmSystemTools::ReadRegistryValue(key, path,
+ cmSystemTools::KeyWOW64_32) &&
+ !path.empty()) {
+ ret.insert(i);
+ }
+ }
+
+ return ret;
+}
+
+bool cmGlobalVisualStudio11Generator::TargetSystemSupportsDeployment() const
+{
+ return this->SystemIsWindowsPhone || this->SystemIsWindowsStore ||
+ cmGlobalVisualStudio10Generator::TargetSystemSupportsDeployment();
+}
+
+bool cmGlobalVisualStudio11Generator::IsWindowsDesktopToolsetInstalled() const
+{
+ const char desktop80Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "VisualStudio\\11.0\\VC\\Libraries\\Extended";
+ const char VS2012DesktopExpressKey[] =
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "WDExpress\\11.0;InstallDir";
+
+ std::vector<std::string> subkeys;
+ std::string path;
+ return cmSystemTools::ReadRegistryValue(VS2012DesktopExpressKey, path,
+ cmSystemTools::KeyWOW64_32) ||
+ cmSystemTools::GetRegistrySubKeys(desktop80Key, subkeys,
+ cmSystemTools::KeyWOW64_32);
+}
+
+bool cmGlobalVisualStudio11Generator::IsWindowsPhoneToolsetInstalled() const
+{
+ const char wp80Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "Microsoft SDKs\\WindowsPhone\\v8.0\\"
+ "Install Path;Install Path";
+
+ std::string path;
+ cmSystemTools::ReadRegistryValue(wp80Key, path, cmSystemTools::KeyWOW64_32);
+ return !path.empty();
+}
+
+bool cmGlobalVisualStudio11Generator::IsWindowsStoreToolsetInstalled() const
+{
+ const char win80Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "VisualStudio\\11.0\\VC\\Libraries\\Core\\Arm";
+
+ std::vector<std::string> subkeys;
+ return cmSystemTools::GetRegistrySubKeys(win80Key, subkeys,
+ cmSystemTools::KeyWOW64_32);
+}
diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h
new file mode 100644
index 0000000..6e409cf
--- /dev/null
+++ b/Source/cmGlobalVisualStudio11Generator.h
@@ -0,0 +1,54 @@
+/* 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 <iosfwd>
+#include <memory>
+#include <set>
+#include <string>
+
+#include "cmGlobalVisualStudio10Generator.h"
+#include "cmStateTypes.h"
+
+class cmGlobalGeneratorFactory;
+class cmMakefile;
+class cmake;
+
+/** \class cmGlobalVisualStudio11Generator */
+class cmGlobalVisualStudio11Generator : public cmGlobalVisualStudio10Generator
+{
+public:
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory();
+
+ bool MatchesGeneratorName(const std::string& name) const override;
+
+protected:
+ cmGlobalVisualStudio11Generator(cmake* cm, const std::string& name,
+ std::string const& platformInGeneratorName);
+
+ bool InitializeWindowsPhone(cmMakefile* mf) override;
+ bool InitializeWindowsStore(cmMakefile* mf) override;
+ bool SelectWindowsPhoneToolset(std::string& toolset) const override;
+ bool SelectWindowsStoreToolset(std::string& toolset) const override;
+
+ // Used to verify that the Desktop toolset for the current generator is
+ // installed on the machine.
+ virtual bool IsWindowsDesktopToolsetInstalled() const;
+
+ // These aren't virtual because we need to check if the selected version
+ // of the toolset is installed
+ bool IsWindowsPhoneToolsetInstalled() const;
+ bool IsWindowsStoreToolsetInstalled() const;
+
+ bool UseFolderProperty() const override;
+ static std::set<std::string> GetInstalledWindowsCESDKs();
+
+ /** Return true if target system supports debugging deployment. */
+ bool TargetSystemSupportsDeployment() const override;
+
+private:
+ class Factory;
+ friend class Factory;
+};
diff --git a/Source/cmGlobalVisualStudio12Generator.cxx b/Source/cmGlobalVisualStudio12Generator.cxx
new file mode 100644
index 0000000..8bdf356
--- /dev/null
+++ b/Source/cmGlobalVisualStudio12Generator.cxx
@@ -0,0 +1,242 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalVisualStudio12Generator.h"
+
+#include "cmAlgorithms.h"
+#include "cmDocumentationEntry.h"
+#include "cmLocalVisualStudio10Generator.h"
+#include "cmMakefile.h"
+
+static const char vs12generatorName[] = "Visual Studio 12 2013";
+
+// Map generator name without year to name with year.
+static const char* cmVS12GenName(const std::string& name, std::string& genName)
+{
+ if (strncmp(name.c_str(), vs12generatorName,
+ sizeof(vs12generatorName) - 6) != 0) {
+ return 0;
+ }
+ const char* p = name.c_str() + sizeof(vs12generatorName) - 6;
+ if (cmHasLiteralPrefix(p, " 2013")) {
+ p += 5;
+ }
+ genName = std::string(vs12generatorName) + p;
+ return p;
+}
+
+class cmGlobalVisualStudio12Generator::Factory
+ : public cmGlobalGeneratorFactory
+{
+public:
+ std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+ const std::string& name, bool allowArch, cmake* cm) const override
+ {
+ std::string genName;
+ const char* p = cmVS12GenName(name, genName);
+ if (!p) {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+ if (!*p) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio12Generator(cm, genName, ""));
+ }
+ if (!allowArch || *p++ != ' ') {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+ if (strcmp(p, "Win64") == 0) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio12Generator(cm, genName, "x64"));
+ }
+ if (strcmp(p, "ARM") == 0) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio12Generator(cm, genName, "ARM"));
+ }
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+
+ void GetDocumentation(cmDocumentationEntry& entry) const override
+ {
+ entry.Name = std::string(vs12generatorName) + " [arch]";
+ entry.Brief = "Generates Visual Studio 2013 project files. "
+ "Optional [arch] can be \"Win64\" or \"ARM\".";
+ }
+
+ std::vector<std::string> GetGeneratorNames() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(vs12generatorName);
+ return names;
+ }
+
+ std::vector<std::string> GetGeneratorNamesWithPlatform() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(vs12generatorName + std::string(" ARM"));
+ names.push_back(vs12generatorName + std::string(" Win64"));
+ return names;
+ }
+
+ bool SupportsToolset() const override { return true; }
+ bool SupportsPlatform() const override { return true; }
+
+ std::vector<std::string> GetKnownPlatforms() const override
+ {
+ std::vector<std::string> platforms;
+ platforms.emplace_back("x64");
+ platforms.emplace_back("Win32");
+ platforms.emplace_back("ARM");
+ return platforms;
+ }
+
+ std::string GetDefaultPlatformName() const override { return "Win32"; }
+};
+
+std::unique_ptr<cmGlobalGeneratorFactory>
+cmGlobalVisualStudio12Generator::NewFactory()
+{
+ return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
+}
+
+cmGlobalVisualStudio12Generator::cmGlobalVisualStudio12Generator(
+ cmake* cm, const std::string& name,
+ std::string const& platformInGeneratorName)
+ : cmGlobalVisualStudio11Generator(cm, name, platformInGeneratorName)
+{
+ std::string vc12Express;
+ this->ExpressEdition = cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\12.0\\Setup\\VC;"
+ "ProductDir",
+ vc12Express, cmSystemTools::KeyWOW64_32);
+ this->DefaultPlatformToolset = "v120";
+ this->DefaultCLFlagTableName = "v12";
+ this->DefaultCSharpFlagTableName = "v12";
+ this->DefaultLibFlagTableName = "v12";
+ this->DefaultLinkFlagTableName = "v12";
+ this->DefaultMasmFlagTableName = "v12";
+ this->DefaultRCFlagTableName = "v12";
+ this->Version = VS12;
+}
+
+bool cmGlobalVisualStudio12Generator::MatchesGeneratorName(
+ const std::string& name) const
+{
+ std::string genName;
+ if (cmVS12GenName(name, genName)) {
+ return genName == this->GetName();
+ }
+ return false;
+}
+
+bool cmGlobalVisualStudio12Generator::ProcessGeneratorToolsetField(
+ std::string const& key, std::string const& value)
+{
+ if (key == "host" && (value == "x64" || value == "x86")) {
+ this->GeneratorToolsetHostArchitecture = value;
+ return true;
+ }
+ return this->cmGlobalVisualStudio11Generator::ProcessGeneratorToolsetField(
+ key, value);
+}
+
+bool cmGlobalVisualStudio12Generator::InitializeWindowsPhone(cmMakefile* mf)
+{
+ if (!this->SelectWindowsPhoneToolset(this->DefaultPlatformToolset)) {
+ std::ostringstream e;
+ if (this->DefaultPlatformToolset.empty()) {
+ e << this->GetName()
+ << " supports Windows Phone '8.0' and '8.1', but "
+ "not '"
+ << this->SystemVersion << "'. Check CMAKE_SYSTEM_VERSION.";
+ } else {
+ e << "A Windows Phone component with CMake requires both the Windows "
+ << "Desktop SDK as well as the Windows Phone '" << this->SystemVersion
+ << "' SDK. Please make sure that you have both installed";
+ }
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ return true;
+}
+
+bool cmGlobalVisualStudio12Generator::InitializeWindowsStore(cmMakefile* mf)
+{
+ if (!this->SelectWindowsStoreToolset(this->DefaultPlatformToolset)) {
+ std::ostringstream e;
+ if (this->DefaultPlatformToolset.empty()) {
+ e << this->GetName()
+ << " supports Windows Store '8.0' and '8.1', but "
+ "not '"
+ << this->SystemVersion << "'. Check CMAKE_SYSTEM_VERSION.";
+ } else {
+ e << "A Windows Store component with CMake requires both the Windows "
+ << "Desktop SDK as well as the Windows Store '" << this->SystemVersion
+ << "' SDK. Please make sure that you have both installed";
+ }
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ return true;
+}
+
+bool cmGlobalVisualStudio12Generator::SelectWindowsPhoneToolset(
+ std::string& toolset) const
+{
+ if (this->SystemVersion == "8.1") {
+ if (this->IsWindowsPhoneToolsetInstalled() &&
+ this->IsWindowsDesktopToolsetInstalled()) {
+ toolset = "v120_wp81";
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return this->cmGlobalVisualStudio11Generator::SelectWindowsPhoneToolset(
+ toolset);
+}
+
+bool cmGlobalVisualStudio12Generator::SelectWindowsStoreToolset(
+ std::string& toolset) const
+{
+ if (this->SystemVersion == "8.1") {
+ if (this->IsWindowsStoreToolsetInstalled() &&
+ this->IsWindowsDesktopToolsetInstalled()) {
+ toolset = "v120";
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return this->cmGlobalVisualStudio11Generator::SelectWindowsStoreToolset(
+ toolset);
+}
+
+bool cmGlobalVisualStudio12Generator::IsWindowsDesktopToolsetInstalled() const
+{
+ const char desktop81Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "VisualStudio\\12.0\\VC\\LibraryDesktop";
+
+ std::vector<std::string> subkeys;
+ return cmSystemTools::GetRegistrySubKeys(desktop81Key, subkeys,
+ cmSystemTools::KeyWOW64_32);
+}
+
+bool cmGlobalVisualStudio12Generator::IsWindowsPhoneToolsetInstalled() const
+{
+ const char wp81Key[] =
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "Microsoft SDKs\\WindowsPhone\\v8.1\\Install Path;Install Path";
+
+ std::string path;
+ cmSystemTools::ReadRegistryValue(wp81Key, path, cmSystemTools::KeyWOW64_32);
+ return !path.empty();
+}
+
+bool cmGlobalVisualStudio12Generator::IsWindowsStoreToolsetInstalled() const
+{
+ const char win81Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "VisualStudio\\12.0\\VC\\Libraries\\Core\\Arm";
+
+ std::vector<std::string> subkeys;
+ return cmSystemTools::GetRegistrySubKeys(win81Key, subkeys,
+ cmSystemTools::KeyWOW64_32);
+}
diff --git a/Source/cmGlobalVisualStudio12Generator.h b/Source/cmGlobalVisualStudio12Generator.h
new file mode 100644
index 0000000..c220d40
--- /dev/null
+++ b/Source/cmGlobalVisualStudio12Generator.h
@@ -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. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <memory>
+#include <string>
+
+#include "cmGlobalVisualStudio11Generator.h"
+
+class cmGlobalGeneratorFactory;
+class cmMakefile;
+class cmake;
+
+/** \class cmGlobalVisualStudio12Generator */
+class cmGlobalVisualStudio12Generator : public cmGlobalVisualStudio11Generator
+{
+public:
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory();
+
+ bool MatchesGeneratorName(const std::string& name) const override;
+
+protected:
+ cmGlobalVisualStudio12Generator(cmake* cm, const std::string& name,
+ std::string const& platformInGeneratorName);
+
+ bool ProcessGeneratorToolsetField(std::string const& key,
+ std::string const& value) override;
+
+ bool InitializeWindowsPhone(cmMakefile* mf) override;
+ bool InitializeWindowsStore(cmMakefile* mf) override;
+ bool SelectWindowsPhoneToolset(std::string& toolset) const override;
+ bool SelectWindowsStoreToolset(std::string& toolset) const override;
+
+ // Used to verify that the Desktop toolset for the current generator is
+ // installed on the machine.
+ bool IsWindowsDesktopToolsetInstalled() const override;
+
+ // These aren't virtual because we need to check if the selected version
+ // of the toolset is installed
+ bool IsWindowsPhoneToolsetInstalled() const;
+ bool IsWindowsStoreToolsetInstalled() const;
+
+private:
+ class Factory;
+ friend class Factory;
+};
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
new file mode 100644
index 0000000..b46f1b9
--- /dev/null
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -0,0 +1,370 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalVisualStudio14Generator.h"
+
+#include <cm/vector>
+
+#include "cmDocumentationEntry.h"
+#include "cmLocalVisualStudio10Generator.h"
+#include "cmMakefile.h"
+
+static const char vs14generatorName[] = "Visual Studio 14 2015";
+
+// Map generator name without year to name with year.
+static const char* cmVS14GenName(const std::string& name, std::string& genName)
+{
+ if (strncmp(name.c_str(), vs14generatorName,
+ sizeof(vs14generatorName) - 6) != 0) {
+ return 0;
+ }
+ const char* p = name.c_str() + sizeof(vs14generatorName) - 6;
+ if (cmHasLiteralPrefix(p, " 2015")) {
+ p += 5;
+ }
+ genName = std::string(vs14generatorName) + p;
+ return p;
+}
+
+class cmGlobalVisualStudio14Generator::Factory
+ : public cmGlobalGeneratorFactory
+{
+public:
+ std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+ const std::string& name, bool allowArch, cmake* cm) const override
+ {
+ std::string genName;
+ const char* p = cmVS14GenName(name, genName);
+ if (!p) {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+ if (!*p) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio14Generator(cm, genName, ""));
+ }
+ if (!allowArch || *p++ != ' ') {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+ if (strcmp(p, "Win64") == 0) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio14Generator(cm, genName, "x64"));
+ }
+ if (strcmp(p, "ARM") == 0) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio14Generator(cm, genName, "ARM"));
+ }
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+
+ void GetDocumentation(cmDocumentationEntry& entry) const override
+ {
+ entry.Name = std::string(vs14generatorName) + " [arch]";
+ entry.Brief = "Generates Visual Studio 2015 project files. "
+ "Optional [arch] can be \"Win64\" or \"ARM\".";
+ }
+
+ std::vector<std::string> GetGeneratorNames() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(vs14generatorName);
+ return names;
+ }
+
+ std::vector<std::string> GetGeneratorNamesWithPlatform() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(vs14generatorName + std::string(" ARM"));
+ names.push_back(vs14generatorName + std::string(" Win64"));
+ return names;
+ }
+
+ bool SupportsToolset() const override { return true; }
+ bool SupportsPlatform() const override { return true; }
+
+ std::vector<std::string> GetKnownPlatforms() const override
+ {
+ std::vector<std::string> platforms;
+ platforms.emplace_back("x64");
+ platforms.emplace_back("Win32");
+ platforms.emplace_back("ARM");
+ return platforms;
+ }
+
+ std::string GetDefaultPlatformName() const override { return "Win32"; }
+};
+
+std::unique_ptr<cmGlobalGeneratorFactory>
+cmGlobalVisualStudio14Generator::NewFactory()
+{
+ return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
+}
+
+cmGlobalVisualStudio14Generator::cmGlobalVisualStudio14Generator(
+ cmake* cm, const std::string& name,
+ std::string const& platformInGeneratorName)
+ : cmGlobalVisualStudio12Generator(cm, name, platformInGeneratorName)
+{
+ std::string vc14Express;
+ this->ExpressEdition = cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\14.0\\Setup\\VC;"
+ "ProductDir",
+ vc14Express, cmSystemTools::KeyWOW64_32);
+ this->DefaultPlatformToolset = "v140";
+ this->DefaultAndroidToolset = "Clang_3_8";
+ this->DefaultCLFlagTableName = "v140";
+ this->DefaultCSharpFlagTableName = "v140";
+ this->DefaultLibFlagTableName = "v14";
+ this->DefaultLinkFlagTableName = "v140";
+ this->DefaultMasmFlagTableName = "v14";
+ this->DefaultRCFlagTableName = "v14";
+ this->Version = VS14;
+}
+
+bool cmGlobalVisualStudio14Generator::MatchesGeneratorName(
+ const std::string& name) const
+{
+ std::string genName;
+ if (cmVS14GenName(name, genName)) {
+ return genName == this->GetName();
+ }
+ return false;
+}
+
+bool cmGlobalVisualStudio14Generator::InitializeWindows(cmMakefile* mf)
+{
+ if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) {
+ return this->SelectWindows10SDK(mf, false);
+ }
+ return true;
+}
+
+bool cmGlobalVisualStudio14Generator::InitializeWindowsStore(cmMakefile* mf)
+{
+ std::ostringstream e;
+ if (!this->SelectWindowsStoreToolset(this->DefaultPlatformToolset)) {
+ if (this->DefaultPlatformToolset.empty()) {
+ e << this->GetName()
+ << " supports Windows Store '8.0', '8.1' and "
+ "'10.0', but not '"
+ << this->SystemVersion << "'. Check CMAKE_SYSTEM_VERSION.";
+ } else {
+ e << "A Windows Store component with CMake requires both the Windows "
+ << "Desktop SDK as well as the Windows Store '" << this->SystemVersion
+ << "' SDK. Please make sure that you have both installed";
+ }
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) {
+ return this->SelectWindows10SDK(mf, true);
+ }
+ return true;
+}
+
+bool cmGlobalVisualStudio14Generator::InitializeAndroid(cmMakefile*)
+{
+ return true;
+}
+
+bool cmGlobalVisualStudio14Generator::SelectWindows10SDK(cmMakefile* mf,
+ bool required)
+{
+ // Find the default version of the Windows 10 SDK.
+ std::string const version = this->GetWindows10SDKVersion(mf);
+
+ if (required && version.empty()) {
+ std::ostringstream e;
+ e << "Could not find an appropriate version of the Windows 10 SDK"
+ << " installed on this machine";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ this->SetWindowsTargetPlatformVersion(version, mf);
+ return true;
+}
+
+void cmGlobalVisualStudio14Generator::SetWindowsTargetPlatformVersion(
+ std::string const& version, cmMakefile* mf)
+{
+ this->WindowsTargetPlatformVersion = version;
+ if (!cmSystemTools::VersionCompareEqual(this->WindowsTargetPlatformVersion,
+ this->SystemVersion)) {
+ std::ostringstream e;
+ e << "Selecting Windows SDK version " << this->WindowsTargetPlatformVersion
+ << " to target Windows " << this->SystemVersion << ".";
+ mf->DisplayStatus(e.str(), -1);
+ }
+ mf->AddDefinition("CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION",
+ this->WindowsTargetPlatformVersion);
+}
+
+bool cmGlobalVisualStudio14Generator::SelectWindowsStoreToolset(
+ std::string& toolset) const
+{
+ if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) {
+ if (this->IsWindowsStoreToolsetInstalled() &&
+ this->IsWindowsDesktopToolsetInstalled()) {
+ toolset = "v140";
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return this->cmGlobalVisualStudio12Generator::SelectWindowsStoreToolset(
+ toolset);
+}
+
+bool cmGlobalVisualStudio14Generator::IsWindowsDesktopToolsetInstalled() const
+{
+ const char desktop10Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "VisualStudio\\14.0\\VC\\Runtimes";
+
+ std::vector<std::string> vc14;
+ return cmSystemTools::GetRegistrySubKeys(desktop10Key, vc14,
+ cmSystemTools::KeyWOW64_32);
+}
+
+bool cmGlobalVisualStudio14Generator::IsWindowsStoreToolsetInstalled() const
+{
+ const char universal10Key[] =
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "VisualStudio\\14.0\\Setup\\Build Tools for Windows 10;SrcPath";
+
+ std::string win10SDK;
+ return cmSystemTools::ReadRegistryValue(universal10Key, win10SDK,
+ cmSystemTools::KeyWOW64_32);
+}
+
+std::string cmGlobalVisualStudio14Generator::GetWindows10SDKMaxVersion(
+ cmMakefile* mf) const
+{
+ // if the given value is set, it can either be OFF/FALSE or a valid SDK
+ // string
+ if (cmProp value = mf->GetDefinition(
+ "CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM")) {
+
+ // If the value is some off/false value, then there is NO maximum set.
+ if (cmIsOff(value)) {
+ return std::string();
+ }
+ // If the value is something else, trust that it is a valid SDK value.
+ else if (value) {
+ return *value;
+ }
+ // If value is an invalid pointer, leave result unchanged.
+ }
+
+ return this->GetWindows10SDKMaxVersionDefault(mf);
+}
+
+std::string cmGlobalVisualStudio14Generator::GetWindows10SDKMaxVersionDefault(
+ cmMakefile*) const
+{
+ // The last Windows 10 SDK version that VS 2015 can target is 10.0.14393.0.
+ //
+ // "VS 2015 Users: The Windows 10 SDK (15063, 16299, 17134, 17763) is
+ // officially only supported for VS 2017." From:
+ // https://blogs.msdn.microsoft.com/chuckw/2018/10/02/windows-10-october-2018-update/
+ return "10.0.14393.0";
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+struct NoWindowsH
+{
+ bool operator()(std::string const& p)
+ {
+ return !cmSystemTools::FileExists(p + "/um/windows.h", true);
+ }
+};
+class WindowsSDKTooRecent
+{
+ std::string const& MaxVersion;
+
+public:
+ WindowsSDKTooRecent(std::string const& maxVersion)
+ : MaxVersion(maxVersion)
+ {
+ }
+ bool operator()(std::string const& v)
+ {
+ return cmSystemTools::VersionCompareGreater(v, MaxVersion);
+ }
+};
+#endif
+
+std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion(
+ cmMakefile* mf)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ std::vector<std::string> win10Roots;
+
+ {
+ std::string win10Root;
+ if (cmSystemTools::GetEnv("CMAKE_WINDOWS_KITS_10_DIR", win10Root)) {
+ cmSystemTools::ConvertToUnixSlashes(win10Root);
+ win10Roots.push_back(win10Root);
+ }
+ }
+
+ {
+ // This logic is taken from the vcvarsqueryregistry.bat file from VS2015
+ // Try HKLM and then HKCU.
+ std::string win10Root;
+ if (cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "Windows Kits\\Installed Roots;KitsRoot10",
+ win10Root, cmSystemTools::KeyWOW64_32) ||
+ cmSystemTools::ReadRegistryValue(
+ "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\"
+ "Windows Kits\\Installed Roots;KitsRoot10",
+ win10Root, cmSystemTools::KeyWOW64_32)) {
+ cmSystemTools::ConvertToUnixSlashes(win10Root);
+ win10Roots.push_back(win10Root);
+ }
+ }
+
+ if (win10Roots.empty()) {
+ return std::string();
+ }
+
+ std::vector<std::string> sdks;
+ // Grab the paths of the different SDKs that are installed
+ for (std::string const& i : win10Roots) {
+ std::string path = i + "/Include/*";
+ cmSystemTools::GlobDirs(path, sdks);
+ }
+
+ // Skip SDKs that do not contain <um/windows.h> because that indicates that
+ // only the UCRT MSIs were installed for them.
+ cm::erase_if(sdks, NoWindowsH());
+
+ // Only use the filename, which will be the SDK version.
+ for (std::string& i : sdks) {
+ i = cmSystemTools::GetFilenameName(i);
+ }
+
+ // Skip SDKs that cannot be used with our toolset, unless the user does not
+ // want to limit the highest supported SDK according to the Microsoft
+ // documentation.
+ std::string maxVersion = this->GetWindows10SDKMaxVersion(mf);
+ if (!maxVersion.empty()) {
+ cm::erase_if(sdks, WindowsSDKTooRecent(maxVersion));
+ }
+
+ // Sort the results to make sure we select the most recent one.
+ std::sort(sdks.begin(), sdks.end(), cmSystemTools::VersionCompareGreater);
+
+ // Look for a SDK exactly matching the requested target version.
+ for (std::string const& i : sdks) {
+ if (cmSystemTools::VersionCompareEqual(i, this->SystemVersion)) {
+ return i;
+ }
+ }
+
+ if (!sdks.empty()) {
+ // Use the latest Windows 10 SDK since the exact version is not available.
+ return sdks.at(0);
+ }
+#endif
+ // Return an empty string
+ return std::string();
+}
diff --git a/Source/cmGlobalVisualStudio14Generator.h b/Source/cmGlobalVisualStudio14Generator.h
new file mode 100644
index 0000000..7804b83
--- /dev/null
+++ b/Source/cmGlobalVisualStudio14Generator.h
@@ -0,0 +1,65 @@
+/* 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 <iosfwd>
+#include <memory>
+#include <string>
+
+#include "cmGlobalVisualStudio12Generator.h"
+
+class cmGlobalGeneratorFactory;
+class cmMakefile;
+class cmake;
+
+/** \class cmGlobalVisualStudio14Generator */
+class cmGlobalVisualStudio14Generator : public cmGlobalVisualStudio12Generator
+{
+public:
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory();
+
+ bool MatchesGeneratorName(const std::string& name) const override;
+
+ const char* GetAndroidApplicationTypeRevision() const override
+ {
+ return "2.0";
+ }
+
+protected:
+ cmGlobalVisualStudio14Generator(cmake* cm, const std::string& name,
+ std::string const& platformInGeneratorName);
+
+ bool InitializeWindows(cmMakefile* mf) override;
+ bool InitializeWindowsStore(cmMakefile* mf) override;
+ bool InitializeAndroid(cmMakefile* mf) override;
+ bool SelectWindowsStoreToolset(std::string& toolset) const override;
+
+ // These aren't virtual because we need to check if the selected version
+ // of the toolset is installed
+ bool IsWindowsStoreToolsetInstalled() const;
+
+ // Used to adjust the max-SDK-version calculation to accommodate user
+ // configuration.
+ std::string GetWindows10SDKMaxVersion(cmMakefile* mf) const;
+
+ // Used to make sure that the Windows 10 SDK selected can work with the
+ // version of the toolset.
+ virtual std::string GetWindows10SDKMaxVersionDefault(cmMakefile* mf) const;
+
+ virtual bool SelectWindows10SDK(cmMakefile* mf, bool required);
+
+ void SetWindowsTargetPlatformVersion(std::string const& version,
+ cmMakefile* mf);
+
+ // Used to verify that the Desktop toolset for the current generator is
+ // installed on the machine.
+ bool IsWindowsDesktopToolsetInstalled() const override;
+
+ std::string GetWindows10SDKVersion(cmMakefile* mf);
+
+private:
+ class Factory;
+ friend class Factory;
+};
diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx
new file mode 100644
index 0000000..0083c40
--- /dev/null
+++ b/Source/cmGlobalVisualStudio71Generator.cxx
@@ -0,0 +1,218 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalVisualStudio71Generator.h"
+
+#include "cmDocumentationEntry.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalVisualStudio7Generator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+
+cmGlobalVisualStudio71Generator::cmGlobalVisualStudio71Generator(
+ cmake* cm, const std::string& platformName)
+ : cmGlobalVisualStudio7Generator(cm, platformName)
+{
+ this->ProjectConfigurationSectionName = "ProjectConfiguration";
+}
+
+void cmGlobalVisualStudio71Generator::WriteSLNFile(
+ std::ostream& fout, cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators)
+{
+ std::vector<std::string> configs =
+ root->GetMakefile()->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
+
+ // Write out the header for a SLN file
+ this->WriteSLNHeader(fout);
+
+ // Collect all targets under this root generator and the transitive
+ // closure of their dependencies.
+ TargetDependSet projectTargets;
+ TargetDependSet originalTargets;
+ this->GetTargetSets(projectTargets, originalTargets, root, generators);
+ OrderedTargetDependSet orderedProjectTargets(
+ projectTargets, this->GetStartupProjectName(root));
+
+ // Generate the targets specification to a string. We will put this in
+ // the actual .sln file later. As a side effect, this method also
+ // populates the set of folders.
+ std::ostringstream targetsSlnString;
+ this->WriteTargetsToSolution(targetsSlnString, root, orderedProjectTargets);
+
+ // Generate folder specification.
+ bool useFolderProperty = this->UseFolderProperty();
+ if (useFolderProperty) {
+ this->WriteFolders(fout);
+ }
+
+ // Now write the actual target specification content.
+ fout << targetsSlnString.str();
+
+ // Write out the configurations information for the solution
+ fout << "Global\n";
+ // Write out the configurations for the solution
+ this->WriteSolutionConfigurations(fout, configs);
+ fout << "\tGlobalSection(" << this->ProjectConfigurationSectionName
+ << ") = postSolution\n";
+ // Write out the configurations for all the targets in the project
+ this->WriteTargetConfigurations(fout, configs, orderedProjectTargets);
+ fout << "\tEndGlobalSection\n";
+
+ if (useFolderProperty) {
+ // Write out project folders
+ fout << "\tGlobalSection(NestedProjects) = preSolution\n";
+ this->WriteFoldersContent(fout);
+ fout << "\tEndGlobalSection\n";
+ }
+
+ // Write out global sections
+ this->WriteSLNGlobalSections(fout, root);
+
+ // Write the footer for the SLN file
+ this->WriteSLNFooter(fout);
+}
+
+void cmGlobalVisualStudio71Generator::WriteSolutionConfigurations(
+ std::ostream& fout, std::vector<std::string> const& configs)
+{
+ fout << "\tGlobalSection(SolutionConfiguration) = preSolution\n";
+ for (std::string const& i : configs) {
+ fout << "\t\t" << i << " = " << i << "\n";
+ }
+ fout << "\tEndGlobalSection\n";
+}
+
+// Write a dsp file into the SLN file,
+// Note, that dependencies from executables to
+// the libraries it uses are also done here
+void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout,
+ const std::string& dspname,
+ const std::string& dir,
+ cmGeneratorTarget const* t)
+{
+ // check to see if this is a fortran build
+ std::string ext = ".vcproj";
+ const char* project =
+ "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"";
+ if (this->TargetIsFortranOnly(t)) {
+ ext = ".vfproj";
+ project = "Project(\"{6989167D-11E4-40FE-8C1A-2192A86A7E90}\") = \"";
+ }
+ if (t->IsCSharpOnly()) {
+ ext = ".csproj";
+ project = "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"";
+ }
+ cmProp targetExt = t->GetProperty("GENERATOR_FILE_NAME_EXT");
+ if (targetExt) {
+ ext = *targetExt;
+ }
+
+ std::string guid = this->GetGUID(dspname);
+ fout << project << dspname << "\", \"" << this->ConvertToSolutionPath(dir)
+ << (!dir.empty() ? "\\" : "") << dspname << ext << "\", \"{" << guid
+ << "}\"\n";
+ fout << "\tProjectSection(ProjectDependencies) = postProject\n";
+ this->WriteProjectDepends(fout, dspname, dir, t);
+ fout << "\tEndProjectSection\n";
+
+ fout << "EndProject\n";
+
+ UtilityDependsMap::iterator ui = this->UtilityDepends.find(t);
+ if (ui != this->UtilityDepends.end()) {
+ const char* uname = ui->second.c_str();
+ /* clang-format off */
+ fout << "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \""
+ << uname << "\", \""
+ << this->ConvertToSolutionPath(dir) << (dir[0]? "\\":"")
+ << uname << ".vcproj" << "\", \"{"
+ << this->GetGUID(uname) << "}\"\n"
+ << "\tProjectSection(ProjectDependencies) = postProject\n"
+ << "\t\t{" << guid << "} = {" << guid << "}\n"
+ << "\tEndProjectSection\n"
+ << "EndProject\n";
+ /* clang-format on */
+ }
+}
+
+// Write a dsp file into the SLN file,
+// Note, that dependencies from executables to
+// the libraries it uses are also done here
+void cmGlobalVisualStudio71Generator::WriteProjectDepends(
+ std::ostream& fout, const std::string&, const std::string&,
+ cmGeneratorTarget const* target)
+{
+ VSDependSet const& depends = this->VSTargetDepends[target];
+ for (std::string const& name : depends) {
+ std::string guid = this->GetGUID(name);
+ if (guid.empty()) {
+ std::string m = cmStrCat("Target: ", target->GetName(),
+ " depends on unknown target: ", name);
+ cmSystemTools::Error(m);
+ }
+ fout << "\t\t{" << guid << "} = {" << guid << "}\n";
+ }
+}
+
+// Write a dsp file into the SLN file, Note, that dependencies from
+// executables to the libraries it uses are also done here
+void cmGlobalVisualStudio71Generator::WriteExternalProject(
+ std::ostream& fout, const std::string& name, const std::string& location,
+ const char* typeGuid,
+ const std::set<BT<std::pair<std::string, bool>>>& depends)
+{
+ fout << "Project(\"{"
+ << (typeGuid ? typeGuid : this->ExternalProjectType(location))
+ << "}\") = \"" << name << "\", \""
+ << this->ConvertToSolutionPath(location) << "\", \"{"
+ << this->GetGUID(name) << "}\"\n";
+
+ // write out the dependencies here VS 7.1 includes dependencies with the
+ // project instead of in the global section
+ if (!depends.empty()) {
+ fout << "\tProjectSection(ProjectDependencies) = postProject\n";
+ for (BT<std::pair<std::string, bool>> const& it : depends) {
+ std::string const& dep = it.Value.first;
+ if (!dep.empty()) {
+ fout << "\t\t{" << this->GetGUID(dep) << "} = {" << this->GetGUID(dep)
+ << "}\n";
+ }
+ }
+ fout << "\tEndProjectSection\n";
+ }
+
+ fout << "EndProject\n";
+}
+
+// Write a dsp file into the SLN file, Note, that dependencies from
+// executables to the libraries it uses are also done here
+void cmGlobalVisualStudio71Generator::WriteProjectConfigurations(
+ std::ostream& fout, const std::string& name, cmGeneratorTarget const& target,
+ std::vector<std::string> const& configs,
+ const std::set<std::string>& configsPartOfDefaultBuild,
+ std::string const& platformMapping)
+{
+ const std::string& platformName =
+ !platformMapping.empty() ? platformMapping : this->GetPlatformName();
+ std::string guid = this->GetGUID(name);
+ for (std::string const& i : configs) {
+ std::vector<std::string> mapConfig;
+ const char* dstConfig = i.c_str();
+ if (target.GetProperty("EXTERNAL_MSPROJECT")) {
+ if (cmProp m = target.GetProperty("MAP_IMPORTED_CONFIG_" +
+ cmSystemTools::UpperCase(i))) {
+ cmExpandList(*m, mapConfig);
+ if (!mapConfig.empty()) {
+ dstConfig = mapConfig[0].c_str();
+ }
+ }
+ }
+ fout << "\t\t{" << guid << "}." << i << ".ActiveCfg = " << dstConfig << "|"
+ << platformName << std::endl;
+ std::set<std::string>::const_iterator ci =
+ configsPartOfDefaultBuild.find(i);
+ if (!(ci == configsPartOfDefaultBuild.end())) {
+ fout << "\t\t{" << guid << "}." << i << ".Build.0 = " << dstConfig << "|"
+ << platformName << std::endl;
+ }
+ }
+}
diff --git a/Source/cmGlobalVisualStudio71Generator.h b/Source/cmGlobalVisualStudio71Generator.h
new file mode 100644
index 0000000..7d38199
--- /dev/null
+++ b/Source/cmGlobalVisualStudio71Generator.h
@@ -0,0 +1,43 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmGlobalVisualStudio7Generator.h"
+
+/** \class cmGlobalVisualStudio71Generator
+ * \brief Write a Unix makefiles.
+ *
+ * cmGlobalVisualStudio71Generator manages UNIX build process for a tree
+ */
+class cmGlobalVisualStudio71Generator : public cmGlobalVisualStudio7Generator
+{
+public:
+ cmGlobalVisualStudio71Generator(cmake* cm,
+ const std::string& platformName = "");
+
+protected:
+ void WriteSLNFile(std::ostream& fout, cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators) override;
+ virtual void WriteSolutionConfigurations(
+ std::ostream& fout, std::vector<std::string> const& configs);
+ void WriteProject(std::ostream& fout, const std::string& name,
+ const std::string& path,
+ const cmGeneratorTarget* t) override;
+ void WriteProjectDepends(std::ostream& fout, const std::string& name,
+ const std::string& path,
+ cmGeneratorTarget const* t) override;
+ void WriteProjectConfigurations(
+ std::ostream& fout, const std::string& name,
+ cmGeneratorTarget const& target, std::vector<std::string> const& configs,
+ const std::set<std::string>& configsPartOfDefaultBuild,
+ const std::string& platformMapping = "") override;
+ void WriteExternalProject(
+ std::ostream& fout, const std::string& name, const std::string& path,
+ const char* typeGuid,
+ const std::set<BT<std::pair<std::string, bool>>>& depends) override;
+
+ // Folders are not supported by VS 7.1.
+ bool UseFolderProperty() const override { return false; }
+
+ std::string ProjectConfigurationSectionName;
+};
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
new file mode 100644
index 0000000..75cd714
--- /dev/null
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -0,0 +1,719 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalVisualStudio7Generator.h"
+
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cm/string_view>
+
+#include <windows.h>
+
+#include <assert.h>
+
+#include "cmsys/Encoding.hxx"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalVisualStudio7Generator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmUuid.h"
+#include "cmake.h"
+
+static cmVS7FlagTable cmVS7ExtraFlagTable[] = {
+ // Precompiled header and related options. Note that the
+ // UsePrecompiledHeader entries are marked as "Continue" so that the
+ // corresponding PrecompiledHeaderThrough entry can be found.
+ { "UsePrecompiledHeader", "YX", "Automatically Generate", "2",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeaderThrough", "YX", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "UsePrecompiledHeader", "Yu", "Use Precompiled Header", "3",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeaderThrough", "Yu", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "WholeProgramOptimization", "LTCG", "WholeProgramOptimization", "true",
+ 0 },
+
+ // Exception handling mode. If no entries match, it will be FALSE.
+ { "ExceptionHandling", "GX", "enable c++ exceptions", "true", 0 },
+ { "ExceptionHandling", "EHsc", "enable c++ exceptions", "true", 0 },
+ // The EHa option does not have an IDE setting. Let it go to false,
+ // and have EHa passed on the command line by leaving out the table
+ // entry.
+
+ { "", "", "", "", 0 }
+};
+
+namespace {
+std::string GetSLNFile(cmLocalGenerator* root)
+{
+ return cmStrCat(root->GetCurrentBinaryDirectory(), '/',
+ root->GetProjectName(), ".sln");
+}
+}
+
+cmGlobalVisualStudio7Generator::cmGlobalVisualStudio7Generator(
+ cmake* cm, std::string const& platformInGeneratorName)
+ : cmGlobalVisualStudioGenerator(cm, platformInGeneratorName)
+{
+ this->DevEnvCommandInitialized = false;
+ this->MasmEnabled = false;
+ this->NasmEnabled = false;
+ this->ExtraFlagTable = cmVS7ExtraFlagTable;
+}
+
+cmGlobalVisualStudio7Generator::~cmGlobalVisualStudio7Generator()
+{
+}
+
+// Package GUID of Intel Visual Fortran plugin to VS IDE
+#define CM_INTEL_PLUGIN_GUID "{B68A201D-CB9B-47AF-A52F-7EEC72E217E4}"
+
+const std::string& cmGlobalVisualStudio7Generator::GetIntelProjectVersion()
+{
+ if (this->IntelProjectVersion.empty()) {
+ // Compute the version of the Intel plugin to the VS IDE.
+ // If the key does not exist then use a default guess.
+ std::string intelVersion;
+ std::string vskey =
+ cmStrCat(this->GetRegistryBase(),
+ "\\Packages\\" CM_INTEL_PLUGIN_GUID ";ProductVersion");
+ cmSystemTools::ReadRegistryValue(vskey, intelVersion,
+ cmSystemTools::KeyWOW64_32);
+ unsigned int intelVersionNumber = ~0u;
+ sscanf(intelVersion.c_str(), "%u", &intelVersionNumber);
+ if (intelVersionNumber >= 11) {
+ // Default to latest known project file version.
+ intelVersion = "11.0";
+ } else if (intelVersionNumber == 10) {
+ // Version 10.x actually uses 9.10 in project files!
+ intelVersion = "9.10";
+ } else {
+ // Version <= 9: use ProductVersion from registry.
+ }
+ this->IntelProjectVersion = intelVersion;
+ }
+ return this->IntelProjectVersion;
+}
+
+void cmGlobalVisualStudio7Generator::EnableLanguage(
+ std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
+{
+ mf->AddDefinition("CMAKE_GENERATOR_RC", "rc");
+ mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
+ if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
+ mf->AddCacheDefinition(
+ "CMAKE_CONFIGURATION_TYPES", "Debug;Release;MinSizeRel;RelWithDebInfo",
+ "Semicolon separated list of supported configuration types, "
+ "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
+ "anything else will be ignored.",
+ cmStateEnums::STRING);
+ }
+
+ // Create list of configurations requested by user's cache, if any.
+ this->cmGlobalVisualStudioGenerator::EnableLanguage(lang, mf, optional);
+
+ // if this environment variable is set, then copy it to
+ // a static cache entry. It will be used by
+ // cmLocalGenerator::ConstructScript, to add an extra PATH
+ // to all custom commands. This is because the VS IDE
+ // does not use the environment it is run in, and this allows
+ // for running commands and using dll's that the IDE environment
+ // does not know about.
+ std::string extraPath;
+ if (cmSystemTools::GetEnv("CMAKE_MSVCIDE_RUN_PATH", extraPath)) {
+ mf->AddCacheDefinition("CMAKE_MSVCIDE_RUN_PATH", extraPath,
+ "Saved environment variable CMAKE_MSVCIDE_RUN_PATH",
+ cmStateEnums::STATIC);
+ }
+}
+
+bool cmGlobalVisualStudio7Generator::FindMakeProgram(cmMakefile* mf)
+{
+ if (!this->cmGlobalVisualStudioGenerator::FindMakeProgram(mf)) {
+ return false;
+ }
+ mf->AddDefinition("CMAKE_VS_DEVENV_COMMAND", this->GetDevEnvCommand());
+ return true;
+}
+
+std::string const& cmGlobalVisualStudio7Generator::GetDevEnvCommand()
+{
+ if (!this->DevEnvCommandInitialized) {
+ this->DevEnvCommandInitialized = true;
+ this->DevEnvCommand = this->FindDevEnvCommand();
+ }
+ return this->DevEnvCommand;
+}
+
+std::string cmGlobalVisualStudio7Generator::FindDevEnvCommand()
+{
+ std::string vscmd;
+ std::string vskey;
+
+ // Search in standard location.
+ vskey = this->GetRegistryBase() + ";InstallDir";
+ if (cmSystemTools::ReadRegistryValue(vskey.c_str(), vscmd,
+ cmSystemTools::KeyWOW64_32)) {
+ cmSystemTools::ConvertToUnixSlashes(vscmd);
+ vscmd += "/devenv.com";
+ if (cmSystemTools::FileExists(vscmd, true)) {
+ return vscmd;
+ }
+ }
+
+ // Search where VS15Preview places it.
+ vskey = cmStrCat(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7;",
+ this->GetIDEVersion());
+ if (cmSystemTools::ReadRegistryValue(vskey.c_str(), vscmd,
+ cmSystemTools::KeyWOW64_32)) {
+ cmSystemTools::ConvertToUnixSlashes(vscmd);
+ vscmd += "/Common7/IDE/devenv.com";
+ if (cmSystemTools::FileExists(vscmd, true)) {
+ return vscmd;
+ }
+ }
+
+ vscmd = "devenv.com";
+ return vscmd;
+}
+
+const char* cmGlobalVisualStudio7Generator::ExternalProjectType(
+ const std::string& location)
+{
+ std::string extension = cmSystemTools::GetFilenameLastExtension(location);
+ if (extension == ".vbproj") {
+ return "F184B08F-C81C-45F6-A57F-5ABD9991F28F";
+ } else if (extension == ".csproj") {
+ return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC";
+ } else if (extension == ".fsproj") {
+ return "F2A71F9B-5D33-465A-A702-920D77279786";
+ } else if (extension == ".vdproj") {
+ return "54435603-DBB4-11D2-8724-00A0C9A8B90C";
+ } else if (extension == ".dbproj") {
+ return "C8D11400-126E-41CD-887F-60BD40844F9E";
+ } else if (extension == ".wixproj") {
+ return "930C7802-8A8C-48F9-8165-68863BCCD9DD";
+ } else if (extension == ".pyproj") {
+ return "888888A0-9F3D-457C-B088-3A5042F75D52";
+ }
+ return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942";
+}
+
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalVisualStudio7Generator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& /*projectDir*/,
+ std::vector<std::string> const& targetNames, const std::string& config,
+ bool /*fast*/, int /*jobs*/, bool /*verbose*/,
+ std::vector<std::string> const& makeOptions)
+{
+ // Select the caller- or user-preferred make program, else devenv.
+ std::string makeProgramSelected =
+ this->SelectMakeProgram(makeProgram, this->GetDevEnvCommand());
+
+ // Ignore the above preference if it is msbuild.
+ // Assume any other value is either a devenv or
+ // command-line compatible with devenv.
+ std::string makeProgramLower = makeProgramSelected;
+ cmSystemTools::LowerCase(makeProgramLower);
+ if (makeProgramLower.find("msbuild") != std::string::npos) {
+ makeProgramSelected = this->GetDevEnvCommand();
+ }
+
+ // Workaround to convince VCExpress.exe to produce output.
+ const bool requiresOutputForward =
+ (makeProgramLower.find("vcexpress") != std::string::npos);
+ std::vector<GeneratedMakeCommand> makeCommands;
+
+ std::vector<std::string> realTargetNames = targetNames;
+ if (targetNames.empty() ||
+ ((targetNames.size() == 1) && targetNames.front().empty())) {
+ realTargetNames = { "ALL_BUILD" };
+ }
+ for (const auto& tname : realTargetNames) {
+ std::string realTarget;
+ if (!tname.empty()) {
+ realTarget = tname;
+ } else {
+ continue;
+ }
+ bool clean = false;
+ if (realTarget == "clean") {
+ clean = true;
+ realTarget = "ALL_BUILD";
+ }
+ GeneratedMakeCommand makeCommand;
+ makeCommand.RequiresOutputForward = requiresOutputForward;
+ makeCommand.Add(makeProgramSelected);
+ makeCommand.Add(projectName + ".sln");
+ makeCommand.Add((clean ? "/clean" : "/build"));
+ makeCommand.Add((config.empty() ? "Debug" : config));
+ makeCommand.Add("/project");
+ makeCommand.Add(realTarget);
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ makeCommands.emplace_back(std::move(makeCommand));
+ }
+ return makeCommands;
+}
+
+//! Create a local generator appropriate to this Global Generator
+std::unique_ptr<cmLocalGenerator>
+cmGlobalVisualStudio7Generator::CreateLocalGenerator(cmMakefile* mf)
+{
+ auto lg = cm::make_unique<cmLocalVisualStudio7Generator>(this, mf);
+ return std::unique_ptr<cmLocalGenerator>(std::move(lg));
+}
+
+#if !defined(CMAKE_BOOTSTRAP)
+Json::Value cmGlobalVisualStudio7Generator::GetJson() const
+{
+ Json::Value generator = this->cmGlobalVisualStudioGenerator::GetJson();
+ generator["platform"] = this->GetPlatformName();
+ return generator;
+}
+#endif
+
+bool cmGlobalVisualStudio7Generator::SetSystemName(std::string const& s,
+ cmMakefile* mf)
+{
+ mf->AddDefinition("CMAKE_VS_INTEL_Fortran_PROJECT_VERSION",
+ this->GetIntelProjectVersion());
+ return this->cmGlobalVisualStudioGenerator::SetSystemName(s, mf);
+}
+
+void cmGlobalVisualStudio7Generator::Generate()
+{
+ // first do the superclass method
+ this->cmGlobalVisualStudioGenerator::Generate();
+
+ // Now write out the DSW
+ this->OutputSLNFile();
+ // If any solution or project files changed during the generation,
+ // tell Visual Studio to reload them...
+ if (!cmSystemTools::GetErrorOccuredFlag() &&
+ !this->LocalGenerators.empty()) {
+ this->CallVisualStudioMacro(MacroReload,
+ GetSLNFile(this->LocalGenerators[0].get()));
+ }
+}
+
+void cmGlobalVisualStudio7Generator::OutputSLNFile(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
+{
+ if (generators.empty()) {
+ return;
+ }
+ this->CurrentProject = root->GetProjectName();
+ std::string fname = GetSLNFile(root);
+ cmGeneratedFileStream fout(fname.c_str());
+ fout.SetCopyIfDifferent(true);
+ if (!fout) {
+ return;
+ }
+ this->WriteSLNFile(fout, root, generators);
+ if (fout.Close()) {
+ this->FileReplacedDuringGenerate(fname);
+ }
+}
+
+// output the SLN file
+void cmGlobalVisualStudio7Generator::OutputSLNFile()
+{
+ for (auto& it : this->ProjectMap) {
+ this->OutputSLNFile(it.second[0], it.second);
+ }
+}
+
+void cmGlobalVisualStudio7Generator::WriteTargetConfigurations(
+ std::ostream& fout, std::vector<std::string> const& configs,
+ OrderedTargetDependSet const& projectTargets)
+{
+ // loop over again and write out configurations for each target
+ // in the solution
+ for (cmGeneratorTarget const* target : projectTargets) {
+ if (!target->IsInBuildSystem()) {
+ continue;
+ }
+ cmProp expath = target->GetProperty("EXTERNAL_MSPROJECT");
+ if (expath) {
+ std::set<std::string> allConfigurations(configs.begin(), configs.end());
+ cmProp mapping = target->GetProperty("VS_PLATFORM_MAPPING");
+ this->WriteProjectConfigurations(fout, target->GetName(), *target,
+ configs, allConfigurations,
+ mapping ? *mapping : "");
+ } else {
+ const std::set<std::string>& configsPartOfDefaultBuild =
+ this->IsPartOfDefaultBuild(configs, projectTargets, target);
+ cmProp vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
+ if (vcprojName) {
+ this->WriteProjectConfigurations(fout, *vcprojName, *target, configs,
+ configsPartOfDefaultBuild);
+ }
+ }
+ }
+}
+
+void cmGlobalVisualStudio7Generator::WriteTargetsToSolution(
+ std::ostream& fout, cmLocalGenerator* root,
+ OrderedTargetDependSet const& projectTargets)
+{
+ VisualStudioFolders.clear();
+
+ std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
+ for (cmGeneratorTarget const* target : projectTargets) {
+ if (!target->IsInBuildSystem()) {
+ continue;
+ }
+ bool written = false;
+
+ // handle external vc project files
+ cmProp expath = target->GetProperty("EXTERNAL_MSPROJECT");
+ if (expath) {
+ std::string project = target->GetName();
+ std::string location = *expath;
+
+ this->WriteExternalProject(
+ fout, project, location,
+ cmToCStr(target->GetProperty("VS_PROJECT_TYPE")),
+ target->GetUtilities());
+ written = true;
+ } else {
+ cmProp vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
+ if (vcprojName) {
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ std::string dir = lg->GetCurrentBinaryDirectory();
+ dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir);
+ if (dir == ".") {
+ dir.clear(); // msbuild cannot handle ".\" prefix
+ }
+ this->WriteProject(fout, *vcprojName, dir, target);
+ written = true;
+ }
+ }
+
+ // Create "solution folder" information from FOLDER target property
+ //
+ if (written && this->UseFolderProperty()) {
+ const std::string targetFolder = target->GetEffectiveFolderName();
+ if (!targetFolder.empty()) {
+ std::vector<std::string> tokens =
+ cmSystemTools::SplitString(targetFolder, '/', false);
+
+ std::string cumulativePath;
+
+ for (std::string const& iter : tokens) {
+ if (!iter.size()) {
+ continue;
+ }
+
+ if (cumulativePath.empty()) {
+ cumulativePath = "CMAKE_FOLDER_GUID_" + iter;
+ } else {
+ VisualStudioFolders[cumulativePath].insert(cumulativePath + "/" +
+ iter);
+
+ cumulativePath = cumulativePath + "/" + iter;
+ }
+ }
+
+ if (!cumulativePath.empty()) {
+ VisualStudioFolders[cumulativePath].insert(target->GetName());
+ }
+ }
+ }
+ }
+}
+
+void cmGlobalVisualStudio7Generator::WriteTargetDepends(
+ std::ostream& fout, OrderedTargetDependSet const& projectTargets)
+{
+ for (cmGeneratorTarget const* target : projectTargets) {
+ if (!target->IsInBuildSystem()) {
+ continue;
+ }
+ cmProp vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
+ if (vcprojName) {
+ std::string dir =
+ target->GetLocalGenerator()->GetCurrentSourceDirectory();
+ this->WriteProjectDepends(fout, *vcprojName, dir, target);
+ }
+ }
+}
+
+void cmGlobalVisualStudio7Generator::WriteFolders(std::ostream& fout)
+{
+ cm::string_view const prefix = "CMAKE_FOLDER_GUID_";
+ std::string guidProjectTypeFolder = "2150E333-8FDC-42A3-9474-1A3956D46DE8";
+ for (auto const& iter : VisualStudioFolders) {
+ std::string fullName = iter.first;
+ std::string guid = this->GetGUID(fullName);
+
+ std::replace(fullName.begin(), fullName.end(), '/', '\\');
+ if (cmHasPrefix(fullName, prefix)) {
+ fullName = fullName.substr(prefix.size());
+ }
+
+ std::string nameOnly = cmSystemTools::GetFilenameName(fullName);
+
+ fout << "Project(\"{" << guidProjectTypeFolder << "}\") = \"" << nameOnly
+ << "\", \"" << fullName << "\", \"{" << guid << "}\"\nEndProject\n";
+ }
+}
+
+void cmGlobalVisualStudio7Generator::WriteFoldersContent(std::ostream& fout)
+{
+ for (auto const& iter : VisualStudioFolders) {
+ std::string key(iter.first);
+ std::string guidParent(this->GetGUID(key));
+
+ for (std::string const& it : iter.second) {
+ std::string value(it);
+ std::string guid(this->GetGUID(value));
+
+ fout << "\t\t{" << guid << "} = {" << guidParent << "}\n";
+ }
+ }
+}
+
+std::string cmGlobalVisualStudio7Generator::ConvertToSolutionPath(
+ const std::string& path)
+{
+ // Convert to backslashes. Do not use ConvertToOutputPath because
+ // we will add quoting ourselves, and we know these projects always
+ // use windows slashes.
+ std::string d = path;
+ std::string::size_type pos = 0;
+ while ((pos = d.find('/', pos)) != d.npos) {
+ d[pos++] = '\\';
+ }
+ return d;
+}
+
+void cmGlobalVisualStudio7Generator::WriteSLNGlobalSections(
+ std::ostream& fout, cmLocalGenerator* root)
+{
+ std::string const guid = this->GetGUID(root->GetProjectName() + ".sln");
+ bool extensibilityGlobalsOverridden = false;
+ bool extensibilityAddInsOverridden = false;
+ const std::vector<std::string> propKeys =
+ root->GetMakefile()->GetPropertyKeys();
+ for (std::string const& it : propKeys) {
+ if (cmHasLiteralPrefix(it, "VS_GLOBAL_SECTION_")) {
+ std::string sectionType;
+ std::string name = it.substr(18);
+ if (cmHasLiteralPrefix(name, "PRE_")) {
+ name = name.substr(4);
+ sectionType = "preSolution";
+ } else if (cmHasLiteralPrefix(name, "POST_")) {
+ name = name.substr(5);
+ sectionType = "postSolution";
+ } else
+ continue;
+ if (!name.empty()) {
+ bool addGuid = false;
+ if (name == "ExtensibilityGlobals" && sectionType == "postSolution") {
+ addGuid = true;
+ extensibilityGlobalsOverridden = true;
+ } else if (name == "ExtensibilityAddIns" &&
+ sectionType == "postSolution") {
+ extensibilityAddInsOverridden = true;
+ }
+ fout << "\tGlobalSection(" << name << ") = " << sectionType << "\n";
+ cmProp p = root->GetMakefile()->GetProperty(it);
+ std::vector<std::string> keyValuePairs = cmExpandedList(p ? *p : "");
+ for (std::string const& itPair : keyValuePairs) {
+ const std::string::size_type posEqual = itPair.find('=');
+ if (posEqual != std::string::npos) {
+ const std::string key =
+ cmTrimWhitespace(itPair.substr(0, posEqual));
+ const std::string value =
+ cmTrimWhitespace(itPair.substr(posEqual + 1));
+ fout << "\t\t" << key << " = " << value << "\n";
+ if (key == "SolutionGuid") {
+ addGuid = false;
+ }
+ }
+ }
+ if (addGuid) {
+ fout << "\t\tSolutionGuid = {" << guid << "}\n";
+ }
+ fout << "\tEndGlobalSection\n";
+ }
+ }
+ }
+ if (!extensibilityGlobalsOverridden) {
+ fout << "\tGlobalSection(ExtensibilityGlobals) = postSolution\n"
+ << "\t\tSolutionGuid = {" << guid << "}\n"
+ << "\tEndGlobalSection\n";
+ }
+ if (!extensibilityAddInsOverridden)
+ fout << "\tGlobalSection(ExtensibilityAddIns) = postSolution\n"
+ << "\tEndGlobalSection\n";
+}
+
+// Standard end of dsw file
+void cmGlobalVisualStudio7Generator::WriteSLNFooter(std::ostream& fout)
+{
+ fout << "EndGlobal\n";
+}
+
+std::string cmGlobalVisualStudio7Generator::WriteUtilityDepend(
+ cmGeneratorTarget const* target)
+{
+ std::vector<std::string> configs =
+ target->Target->GetMakefile()->GetGeneratorConfigs(
+ cmMakefile::ExcludeEmptyConfig);
+ std::string pname = cmStrCat(target->GetName(), "_UTILITY");
+ std::string fname =
+ cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/',
+ pname, ".vcproj");
+ cmGeneratedFileStream fout(fname.c_str());
+ fout.SetCopyIfDifferent(true);
+ std::string guid = this->GetGUID(pname.c_str());
+
+ /* clang-format off */
+ fout <<
+ "<?xml version=\"1.0\" encoding = \""
+ << this->Encoding() << "\"?>\n"
+ "<VisualStudioProject\n"
+ "\tProjectType=\"Visual C++\"\n"
+ "\tVersion=\"" << this->GetIDEVersion() << "0\"\n"
+ "\tName=\"" << pname << "\"\n"
+ "\tProjectGUID=\"{" << guid << "}\"\n"
+ "\tKeyword=\"Win32Proj\">\n"
+ "\t<Platforms><Platform Name=\"Win32\"/></Platforms>\n"
+ "\t<Configurations>\n"
+ ;
+ /* clang-format on */
+ for (std::string const& i : configs) {
+ /* clang-format off */
+ fout <<
+ "\t\t<Configuration\n"
+ "\t\t\tName=\"" << i << "|Win32\"\n"
+ "\t\t\tOutputDirectory=\"" << i << "\"\n"
+ "\t\t\tIntermediateDirectory=\"" << pname << ".dir\\" << i << "\"\n"
+ "\t\t\tConfigurationType=\"10\"\n"
+ "\t\t\tUseOfMFC=\"0\"\n"
+ "\t\t\tATLMinimizesCRunTimeLibraryUsage=\"FALSE\"\n"
+ "\t\t\tCharacterSet=\"2\">\n"
+ "\t\t</Configuration>\n"
+ ;
+ /* clang-format on */
+ }
+ /* clang-format off */
+ fout <<
+ "\t</Configurations>\n"
+ "\t<Files></Files>\n"
+ "\t<Globals></Globals>\n"
+ "</VisualStudioProject>\n"
+ ;
+ /* clang-format on */
+
+ if (fout.Close()) {
+ this->FileReplacedDuringGenerate(fname);
+ }
+ return pname;
+}
+
+std::string cmGlobalVisualStudio7Generator::GetGUID(std::string const& name)
+{
+ std::string const& guidStoreName = name + "_GUID_CMAKE";
+ if (cmProp storedGUID =
+ this->CMakeInstance->GetCacheDefinition(guidStoreName)) {
+ return *storedGUID;
+ }
+ // Compute a GUID that is deterministic but unique to the build tree.
+ std::string input =
+ cmStrCat(this->CMakeInstance->GetState()->GetBinaryDirectory(), '|', name);
+
+ cmUuid uuidGenerator;
+
+ std::vector<unsigned char> uuidNamespace;
+ uuidGenerator.StringToBinary("ee30c4be-5192-4fb0-b335-722a2dffe760",
+ uuidNamespace);
+
+ std::string guid = uuidGenerator.FromMd5(uuidNamespace, input);
+
+ return cmSystemTools::UpperCase(guid);
+}
+
+void cmGlobalVisualStudio7Generator::AppendDirectoryForConfig(
+ const std::string& prefix, const std::string& config,
+ const std::string& suffix, std::string& dir)
+{
+ if (!config.empty()) {
+ dir += prefix;
+ dir += config;
+ dir += suffix;
+ }
+}
+
+std::set<std::string> cmGlobalVisualStudio7Generator::IsPartOfDefaultBuild(
+ std::vector<std::string> const& configs,
+ OrderedTargetDependSet const& projectTargets,
+ cmGeneratorTarget const* target)
+{
+ std::set<std::string> activeConfigs;
+ // if it is a utilitiy target then only make it part of the
+ // default build if another target depends on it
+ int type = target->GetType();
+ if (type == cmStateEnums::GLOBAL_TARGET) {
+ std::vector<std::string> targetNames;
+ targetNames.push_back("INSTALL");
+ targetNames.push_back("PACKAGE");
+ for (std::string const& t : targetNames) {
+ // check if target <t> is part of default build
+ if (target->GetName() == t) {
+ const std::string propertyName =
+ "CMAKE_VS_INCLUDE_" + t + "_TO_DEFAULT_BUILD";
+ // inspect CMAKE_VS_INCLUDE_<t>_TO_DEFAULT_BUILD properties
+ for (std::string const& i : configs) {
+ cmProp propertyValue =
+ target->Target->GetMakefile()->GetDefinition(propertyName);
+ if (propertyValue &&
+ cmIsOn(cmGeneratorExpression::Evaluate(
+ *propertyValue, target->GetLocalGenerator(), i))) {
+ activeConfigs.insert(i);
+ }
+ }
+ }
+ }
+ return activeConfigs;
+ }
+ if (type == cmStateEnums::UTILITY &&
+ !this->IsDependedOn(projectTargets, target)) {
+ return activeConfigs;
+ }
+ // inspect EXCLUDE_FROM_DEFAULT_BUILD[_<CONFIG>] properties
+ for (std::string const& i : configs) {
+ if (cmIsOff(target->GetFeature("EXCLUDE_FROM_DEFAULT_BUILD", i))) {
+ activeConfigs.insert(i);
+ }
+ }
+ return activeConfigs;
+}
+
+bool cmGlobalVisualStudio7Generator::IsDependedOn(
+ OrderedTargetDependSet const& projectTargets, cmGeneratorTarget const* gtIn)
+{
+ for (cmTargetDepend const& l : projectTargets) {
+ TargetDependSet const& tgtdeps = this->GetTargetDirectDepends(l);
+ if (tgtdeps.count(gtIn)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::string cmGlobalVisualStudio7Generator::Encoding()
+{
+ return "UTF-8";
+}
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
new file mode 100644
index 0000000..148762e
--- /dev/null
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -0,0 +1,175 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <memory>
+
+#include "cmGlobalGeneratorFactory.h"
+#include "cmGlobalVisualStudioGenerator.h"
+
+class cmTarget;
+struct cmIDEFlagTable;
+
+/** \class cmGlobalVisualStudio7Generator
+ * \brief Write a Unix makefiles.
+ *
+ * cmGlobalVisualStudio7Generator manages UNIX build process for a tree
+ */
+class cmGlobalVisualStudio7Generator : public cmGlobalVisualStudioGenerator
+{
+public:
+ ~cmGlobalVisualStudio7Generator();
+
+ //! Create a local generator appropriate to this Global Generator
+ std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+ cmMakefile* mf) override;
+
+#if !defined(CMAKE_BOOTSTRAP)
+ Json::Value GetJson() const override;
+#endif
+
+ bool SetSystemName(std::string const& s, cmMakefile* mf) override;
+
+ /**
+ * Utilized by the generator factory to determine if this generator
+ * supports toolsets.
+ */
+ static bool SupportsToolset() { return false; }
+
+ /**
+ * Utilized by the generator factory to determine if this generator
+ * supports platforms.
+ */
+ static bool SupportsPlatform() { return false; }
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) override;
+
+ /**
+ * Try running cmake and building a file. This is used for dynamically
+ * loaded commands, not as part of the usual build process.
+ */
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
+
+ /**
+ * Generate the DSW workspace file.
+ */
+ virtual void OutputSLNFile();
+
+ //! Lookup a stored GUID or compute one deterministically.
+ std::string GetGUID(std::string const& name);
+
+ /** Append the subdirectory for the given configuration. */
+ void AppendDirectoryForConfig(const std::string& prefix,
+ const std::string& config,
+ const std::string& suffix,
+ std::string& dir) override;
+
+ //! What is the configurations directory variable called?
+ const char* GetCMakeCFGIntDir() const override
+ {
+ return "$(ConfigurationName)";
+ }
+
+ /** Return true if the target project file should have the option
+ LinkLibraryDependencies and link to .sln dependencies. */
+ virtual bool NeedLinkLibraryDependencies(cmGeneratorTarget*)
+ {
+ return false;
+ }
+
+ const std::string& GetIntelProjectVersion();
+
+ bool FindMakeProgram(cmMakefile* mf) override;
+
+ /** Is the Microsoft Assembler enabled? */
+ bool IsMasmEnabled() const { return this->MasmEnabled; }
+ bool IsNasmEnabled() const { return this->NasmEnabled; }
+
+ // Encoding for Visual Studio files
+ virtual std::string Encoding();
+
+ cmIDEFlagTable const* ExtraFlagTable;
+
+protected:
+ cmGlobalVisualStudio7Generator(cmake* cm,
+ std::string const& platformInGeneratorName);
+
+ void Generate() override;
+
+ std::string const& GetDevEnvCommand();
+ virtual std::string FindDevEnvCommand();
+
+ static const char* ExternalProjectType(const std::string& location);
+
+ virtual void OutputSLNFile(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators);
+ virtual void WriteSLNFile(std::ostream& fout, cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators) = 0;
+ virtual void WriteProject(std::ostream& fout, const std::string& name,
+ const std::string& path,
+ const cmGeneratorTarget* t) = 0;
+ virtual void WriteProjectDepends(std::ostream& fout, const std::string& name,
+ const std::string& path,
+ cmGeneratorTarget const* t) = 0;
+ virtual void WriteProjectConfigurations(
+ std::ostream& fout, const std::string& name,
+ cmGeneratorTarget const& target, std::vector<std::string> const& configs,
+ const std::set<std::string>& configsPartOfDefaultBuild,
+ const std::string& platformMapping = "") = 0;
+ virtual void WriteSLNGlobalSections(std::ostream& fout,
+ cmLocalGenerator* root);
+ virtual void WriteSLNFooter(std::ostream& fout);
+ std::string WriteUtilityDepend(const cmGeneratorTarget* target) override;
+
+ virtual void WriteTargetsToSolution(
+ std::ostream& fout, cmLocalGenerator* root,
+ OrderedTargetDependSet const& projectTargets);
+ virtual void WriteTargetDepends(
+ std::ostream& fout, OrderedTargetDependSet const& projectTargets);
+ virtual void WriteTargetConfigurations(
+ std::ostream& fout, std::vector<std::string> const& configs,
+ OrderedTargetDependSet const& projectTargets);
+
+ virtual void WriteExternalProject(
+ std::ostream& fout, const std::string& name, const std::string& path,
+ const char* typeGuid,
+ const std::set<BT<std::pair<std::string, bool>>>& dependencies) = 0;
+
+ std::string ConvertToSolutionPath(const std::string& path);
+
+ std::set<std::string> IsPartOfDefaultBuild(
+ std::vector<std::string> const& configs,
+ OrderedTargetDependSet const& projectTargets,
+ cmGeneratorTarget const* target);
+ bool IsDependedOn(OrderedTargetDependSet const& projectTargets,
+ cmGeneratorTarget const* target);
+ std::map<std::string, std::string> GUIDMap;
+
+ virtual void WriteFolders(std::ostream& fout);
+ virtual void WriteFoldersContent(std::ostream& fout);
+ std::map<std::string, std::set<std::string>> VisualStudioFolders;
+
+ // Set during OutputSLNFile with the name of the current project.
+ // There is one SLN file per project.
+ std::string CurrentProject;
+ bool MasmEnabled;
+ bool NasmEnabled;
+
+private:
+ std::string IntelProjectVersion;
+ std::string DevEnvCommand;
+ bool DevEnvCommandInitialized;
+ std::string GetVSMakeProgram() override { return this->GetDevEnvCommand(); }
+};
+
+#define CMAKE_CHECK_BUILD_SYSTEM_TARGET "ZERO_CHECK"
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
new file mode 100644
index 0000000..b19212e
--- /dev/null
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -0,0 +1,394 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalVisualStudio8Generator.h"
+
+#include <cm/memory>
+#include <cmext/memory>
+
+#include "cmCustomCommand.h"
+#include "cmCustomCommandLines.h"
+#include "cmDocumentationEntry.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalVisualStudio7Generator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmSourceFile.h"
+#include "cmVisualStudioWCEPlatformParser.h"
+#include "cmake.h"
+
+cmGlobalVisualStudio8Generator::cmGlobalVisualStudio8Generator(
+ cmake* cm, const std::string& name,
+ std::string const& platformInGeneratorName)
+ : cmGlobalVisualStudio71Generator(cm, platformInGeneratorName)
+{
+ this->ProjectConfigurationSectionName = "ProjectConfigurationPlatforms";
+ this->Name = name;
+ this->ExtraFlagTable = this->GetExtraFlagTableVS8();
+}
+
+std::string cmGlobalVisualStudio8Generator::FindDevEnvCommand()
+{
+ // First look for VCExpress.
+ std::string vsxcmd;
+ std::string vsxkey =
+ cmStrCat("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\",
+ this->GetIDEVersion(), ";InstallDir");
+ if (cmSystemTools::ReadRegistryValue(vsxkey.c_str(), vsxcmd,
+ cmSystemTools::KeyWOW64_32)) {
+ cmSystemTools::ConvertToUnixSlashes(vsxcmd);
+ vsxcmd += "/VCExpress.exe";
+ return vsxcmd;
+ }
+ // Now look for devenv.
+ return this->cmGlobalVisualStudio71Generator::FindDevEnvCommand();
+}
+
+void cmGlobalVisualStudio8Generator::EnableLanguage(
+ std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
+{
+ for (std::string const& it : lang) {
+ if (it == "ASM_MASM") {
+ this->MasmEnabled = true;
+ }
+ }
+ this->AddPlatformDefinitions(mf);
+ cmGlobalVisualStudio7Generator::EnableLanguage(lang, mf, optional);
+}
+
+void cmGlobalVisualStudio8Generator::AddPlatformDefinitions(cmMakefile* mf)
+{
+ if (this->TargetsWindowsCE()) {
+ mf->AddDefinition("CMAKE_VS_WINCE_VERSION", this->WindowsCEVersion);
+ }
+}
+
+bool cmGlobalVisualStudio8Generator::SetGeneratorPlatform(std::string const& p,
+ cmMakefile* mf)
+{
+ if (!this->PlatformInGeneratorName) {
+ this->GeneratorPlatform = p;
+ return this->cmGlobalVisualStudio7Generator::SetGeneratorPlatform("", mf);
+ } else {
+ return this->cmGlobalVisualStudio7Generator::SetGeneratorPlatform(p, mf);
+ }
+}
+
+std::string cmGlobalVisualStudio8Generator::GetGenerateStampList()
+{
+ return "generate.stamp.list";
+}
+
+void cmGlobalVisualStudio8Generator::Configure()
+{
+ this->cmGlobalVisualStudio7Generator::Configure();
+}
+
+bool cmGlobalVisualStudio8Generator::UseFolderProperty() const
+{
+ return IsExpressEdition() ? false : cmGlobalGenerator::UseFolderProperty();
+}
+
+bool cmGlobalVisualStudio8Generator::AddCheckTarget()
+{
+ // Add a special target on which all other targets depend that
+ // checks the build system and optionally re-runs CMake.
+ // Skip the target if no regeneration is to be done.
+ if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
+ return false;
+ }
+
+ std::vector<std::unique_ptr<cmLocalGenerator>> const& generators =
+ this->LocalGenerators;
+ auto& lg =
+ cm::static_reference_cast<cmLocalVisualStudio7Generator>(generators[0]);
+
+ const char* no_working_directory = nullptr;
+ std::vector<std::string> no_byproducts;
+ std::vector<std::string> no_depends;
+ cmCustomCommandLines no_commands;
+ cmTarget* tgt = lg.AddUtilityCommand(
+ CMAKE_CHECK_BUILD_SYSTEM_TARGET, false, no_working_directory,
+ no_byproducts, no_depends, no_commands, cmPolicies::NEW);
+
+ auto ptr = cm::make_unique<cmGeneratorTarget>(tgt, &lg);
+ auto gt = ptr.get();
+ lg.AddGeneratorTarget(std::move(ptr));
+
+ // Organize in the "predefined targets" folder:
+ //
+ if (this->UseFolderProperty()) {
+ tgt->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
+ }
+
+ // Create a list of all stamp files for this project.
+ std::vector<std::string> stamps;
+ std::string stampList = cmStrCat(
+ "CMakeFiles/", cmGlobalVisualStudio8Generator::GetGenerateStampList());
+ {
+ std::string stampListFile =
+ cmStrCat(generators[0]->GetMakefile()->GetCurrentBinaryDirectory(), '/',
+ stampList);
+ std::string stampFile;
+ cmGeneratedFileStream fout(stampListFile.c_str());
+ for (const auto& gi : generators) {
+ stampFile = cmStrCat(gi->GetMakefile()->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/generate.stamp");
+ fout << stampFile << "\n";
+ stamps.push_back(stampFile);
+ }
+ }
+
+ // Add a custom rule to re-run CMake if any input files changed.
+ {
+ // The custom rule runs cmake so set UTF-8 pipes.
+ bool stdPipesUTF8 = true;
+
+ // Collect the input files used to generate all targets in this
+ // project.
+ std::vector<std::string> listFiles;
+ for (const auto& gen : generators) {
+ cm::append(listFiles, gen->GetMakefile()->GetListFiles());
+ }
+
+ // Add a custom prebuild target to run the VerifyGlobs script.
+ cmake* cm = this->GetCMakeInstance();
+ if (cm->DoWriteGlobVerifyTarget()) {
+ cmCustomCommandLines verifyCommandLines = cmMakeSingleCommandLine(
+ { cmSystemTools::GetCMakeCommand(), "-P", cm->GetGlobVerifyScript() });
+ std::vector<std::string> byproducts;
+ byproducts.push_back(cm->GetGlobVerifyStamp());
+
+ lg.AddCustomCommandToTarget(CMAKE_CHECK_BUILD_SYSTEM_TARGET, byproducts,
+ no_depends, verifyCommandLines,
+ cmCustomCommandType::PRE_BUILD,
+ "Checking File Globs", no_working_directory,
+ cmPolicies::NEW, stdPipesUTF8);
+
+ // Ensure ZERO_CHECK always runs in Visual Studio using MSBuild,
+ // otherwise the prebuild command will not be run.
+ tgt->SetProperty("VS_GLOBAL_DisableFastUpToDateCheck", "true");
+ listFiles.push_back(cm->GetGlobVerifyStamp());
+ }
+
+ // Sort the list of input files and remove duplicates.
+ std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>());
+ std::vector<std::string>::iterator new_end =
+ std::unique(listFiles.begin(), listFiles.end());
+ listFiles.erase(new_end, listFiles.end());
+
+ // Create a rule to re-run CMake.
+ std::string argS = cmStrCat("-S", lg.GetSourceDirectory());
+ std::string argB = cmStrCat("-B", lg.GetBinaryDirectory());
+ std::string const sln =
+ lg.GetBinaryDirectory() + "/" + lg.GetProjectName() + ".sln";
+ cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
+ { cmSystemTools::GetCMakeCommand(), argS, argB, "--check-stamp-list",
+ stampList, "--vs-solution-file", sln });
+
+ // Add the rule. Note that we cannot use the CMakeLists.txt
+ // file as the main dependency because it would get
+ // overwritten by the CreateVCProjBuildRule.
+ // (this could be avoided with per-target source files)
+ std::string no_main_dependency;
+ cmImplicitDependsList no_implicit_depends;
+ if (cmSourceFile* file = lg.AddCustomCommandToOutput(
+ stamps, no_byproducts, listFiles, no_main_dependency,
+ no_implicit_depends, commandLines, "Checking Build System",
+ no_working_directory, cmPolicies::NEW, true, false, false, false, "",
+ "", stdPipesUTF8)) {
+ gt->AddSource(file->ResolveFullPath());
+ } else {
+ cmSystemTools::Error("Error adding rule for " + stamps[0]);
+ }
+ }
+
+ return true;
+}
+
+void cmGlobalVisualStudio8Generator::AddExtraIDETargets()
+{
+ cmGlobalVisualStudio7Generator::AddExtraIDETargets();
+ if (this->AddCheckTarget()) {
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
+ const auto& tgts = this->LocalGenerators[i]->GetGeneratorTargets();
+ // All targets depend on the build-system check target.
+ for (const auto& ti : tgts) {
+ if (ti->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
+ ti->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false);
+ }
+ }
+ }
+ }
+}
+
+void cmGlobalVisualStudio8Generator::WriteSolutionConfigurations(
+ std::ostream& fout, std::vector<std::string> const& configs)
+{
+ fout << "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n";
+ for (std::string const& i : configs) {
+ fout << "\t\t" << i << "|" << this->GetPlatformName() << " = " << i << "|"
+ << this->GetPlatformName() << "\n";
+ }
+ fout << "\tEndGlobalSection\n";
+}
+
+void cmGlobalVisualStudio8Generator::WriteProjectConfigurations(
+ std::ostream& fout, const std::string& name, cmGeneratorTarget const& target,
+ std::vector<std::string> const& configs,
+ const std::set<std::string>& configsPartOfDefaultBuild,
+ std::string const& platformMapping)
+{
+ std::string guid = this->GetGUID(name);
+ for (std::string const& i : configs) {
+ std::vector<std::string> mapConfig;
+ const char* dstConfig = i.c_str();
+ if (target.GetProperty("EXTERNAL_MSPROJECT")) {
+ if (cmProp m = target.GetProperty("MAP_IMPORTED_CONFIG_" +
+ cmSystemTools::UpperCase(i))) {
+ cmExpandList(*m, mapConfig);
+ if (!mapConfig.empty()) {
+ dstConfig = mapConfig[0].c_str();
+ }
+ }
+ }
+ fout << "\t\t{" << guid << "}." << i << "|" << this->GetPlatformName()
+ << ".ActiveCfg = " << dstConfig << "|"
+ << (!platformMapping.empty() ? platformMapping
+ : this->GetPlatformName())
+ << "\n";
+ std::set<std::string>::const_iterator ci =
+ configsPartOfDefaultBuild.find(i);
+ if (!(ci == configsPartOfDefaultBuild.end())) {
+ fout << "\t\t{" << guid << "}." << i << "|" << this->GetPlatformName()
+ << ".Build.0 = " << dstConfig << "|"
+ << (!platformMapping.empty() ? platformMapping
+ : this->GetPlatformName())
+ << "\n";
+ }
+ if (this->NeedsDeploy(target, dstConfig)) {
+ fout << "\t\t{" << guid << "}." << i << "|" << this->GetPlatformName()
+ << ".Deploy.0 = " << dstConfig << "|"
+ << (!platformMapping.empty() ? platformMapping
+ : this->GetPlatformName())
+ << "\n";
+ }
+ }
+}
+
+bool cmGlobalVisualStudio8Generator::NeedsDeploy(
+ cmGeneratorTarget const& target, const char* config) const
+{
+ cmStateEnums::TargetType const type = target.GetType();
+ if (type != cmStateEnums::EXECUTABLE &&
+ type != cmStateEnums::SHARED_LIBRARY) {
+ // deployment only valid on executables and shared libraries.
+ return false;
+ }
+
+ if (cmProp prop = target.GetProperty("VS_SOLUTION_DEPLOY")) {
+ // If set, it dictates behavior
+ return cmIsOn(
+ cmGeneratorExpression::Evaluate(*prop, target.LocalGenerator, config));
+ }
+
+ // To be deprecated, disable deployment even if target supports it.
+ if (cmProp prop = target.GetProperty("VS_NO_SOLUTION_DEPLOY")) {
+ if (cmIsOn(cmGeneratorExpression::Evaluate(*prop, target.LocalGenerator,
+ config))) {
+ // If true, always disable deployment
+ return false;
+ }
+ }
+
+ // Legacy behavior, enabled deployment based on 'hard-coded' target
+ // platforms.
+ return this->TargetSystemSupportsDeployment();
+}
+
+bool cmGlobalVisualStudio8Generator::TargetSystemSupportsDeployment() const
+{
+ return this->TargetsWindowsCE();
+}
+
+bool cmGlobalVisualStudio8Generator::ComputeTargetDepends()
+{
+ // Skip over the cmGlobalVisualStudioGenerator implementation!
+ // We do not need the support that VS <= 7.1 needs.
+ return this->cmGlobalGenerator::ComputeTargetDepends();
+}
+
+void cmGlobalVisualStudio8Generator::WriteProjectDepends(
+ std::ostream& fout, const std::string&, const std::string&,
+ cmGeneratorTarget const* gt)
+{
+ TargetDependSet const& unordered = this->GetTargetDirectDepends(gt);
+ OrderedTargetDependSet depends(unordered, std::string());
+ for (cmTargetDepend const& i : depends) {
+ if (!i->IsInBuildSystem()) {
+ continue;
+ }
+ std::string guid = this->GetGUID(i->GetName());
+ fout << "\t\t{" << guid << "} = {" << guid << "}\n";
+ }
+}
+
+bool cmGlobalVisualStudio8Generator::NeedLinkLibraryDependencies(
+ cmGeneratorTarget* target)
+{
+ // Look for utility dependencies that magically link.
+ for (BT<std::pair<std::string, bool>> const& ui : target->GetUtilities()) {
+ if (cmGeneratorTarget* depTarget =
+ target->GetLocalGenerator()->FindGeneratorTargetToUse(
+ ui.Value.first)) {
+ if (depTarget->IsInBuildSystem() &&
+ depTarget->GetProperty("EXTERNAL_MSPROJECT")) {
+ // This utility dependency names an external .vcproj target.
+ // We use LinkLibraryDependencies="true" to link to it without
+ // predicting the .lib file location or name.
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static cmVS7FlagTable cmVS8ExtraFlagTable[] = {
+ { "CallingConvention", "Gd", "cdecl", "0", 0 },
+ { "CallingConvention", "Gr", "fastcall", "1", 0 },
+ { "CallingConvention", "Gz", "stdcall", "2", 0 },
+
+ { "Detect64BitPortabilityProblems", "Wp64",
+ "Detect 64Bit Portability Problems", "true", 0 },
+ { "ErrorReporting", "errorReport:prompt", "Report immediately", "1", 0 },
+ { "ErrorReporting", "errorReport:queue", "Queue for next login", "2", 0 },
+ // Precompiled header and related options. Note that the
+ // UsePrecompiledHeader entries are marked as "Continue" so that the
+ // corresponding PrecompiledHeaderThrough entry can be found.
+ { "UsePrecompiledHeader", "Yu", "Use Precompiled Header", "2",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeaderThrough", "Yu", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ // There is no YX option in the VS8 IDE.
+
+ // Exception handling mode. If no entries match, it will be FALSE.
+ { "ExceptionHandling", "GX", "enable c++ exceptions", "1", 0 },
+ { "ExceptionHandling", "EHsc", "enable c++ exceptions", "1", 0 },
+ { "ExceptionHandling", "EHa", "enable SEH exceptions", "2", 0 },
+
+ { "EnablePREfast", "analyze", "", "true", 0 },
+ { "EnablePREfast", "analyze-", "", "false", 0 },
+
+ // Language options
+ { "TreatWChar_tAsBuiltInType", "Zc:wchar_t", "wchar_t is a built-in type",
+ "true", 0 },
+ { "TreatWChar_tAsBuiltInType", "Zc:wchar_t-",
+ "wchar_t is not a built-in type", "false", 0 },
+
+ { "", "", "", "", 0 }
+};
+cmIDEFlagTable const* cmGlobalVisualStudio8Generator::GetExtraFlagTableVS8()
+{
+ return cmVS8ExtraFlagTable;
+}
diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h
new file mode 100644
index 0000000..96e3553
--- /dev/null
+++ b/Source/cmGlobalVisualStudio8Generator.h
@@ -0,0 +1,79 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmGlobalVisualStudio71Generator.h"
+
+/** \class cmGlobalVisualStudio8Generator
+ * \brief Write a Unix makefiles.
+ *
+ * cmGlobalVisualStudio8Generator manages UNIX build process for a tree
+ */
+class cmGlobalVisualStudio8Generator : public cmGlobalVisualStudio71Generator
+{
+public:
+ //! Get the name for the generator.
+ std::string GetName() const override { return this->Name; }
+
+ /** Get the name of the main stamp list file. */
+ static std::string GetGenerateStampList();
+
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) override;
+ virtual void AddPlatformDefinitions(cmMakefile* mf);
+
+ bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override;
+
+ /**
+ * Override Configure and Generate to add the build-system check
+ * target.
+ */
+ void Configure() override;
+
+ /** Return true if the target project file should have the option
+ LinkLibraryDependencies and link to .sln dependencies. */
+ bool NeedLinkLibraryDependencies(cmGeneratorTarget* target) override;
+
+ /** Return true if building for Windows CE */
+ bool TargetsWindowsCE() const override
+ {
+ return !this->WindowsCEVersion.empty();
+ }
+
+protected:
+ cmGlobalVisualStudio8Generator(cmake* cm, const std::string& name,
+ std::string const& platformInGeneratorName);
+
+ void AddExtraIDETargets() override;
+
+ std::string FindDevEnvCommand() override;
+
+ bool VSLinksDependencies() const override { return false; }
+
+ bool AddCheckTarget();
+
+ /** Return true if the configuration needs to be deployed */
+ virtual bool NeedsDeploy(cmGeneratorTarget const& target,
+ const char* config) const;
+
+ /** Returns true if the target system support debugging deployment. */
+ virtual bool TargetSystemSupportsDeployment() const;
+
+ static cmIDEFlagTable const* GetExtraFlagTableVS8();
+ void WriteSolutionConfigurations(
+ std::ostream& fout, std::vector<std::string> const& configs) override;
+ void WriteProjectConfigurations(
+ std::ostream& fout, const std::string& name,
+ cmGeneratorTarget const& target, std::vector<std::string> const& configs,
+ const std::set<std::string>& configsPartOfDefaultBuild,
+ const std::string& platformMapping = "") override;
+ bool ComputeTargetDepends() override;
+ void WriteProjectDepends(std::ostream& fout, const std::string& name,
+ const std::string& path,
+ const cmGeneratorTarget* t) override;
+
+ bool UseFolderProperty() const override;
+
+ std::string Name;
+ std::string WindowsCEVersion;
+};
diff --git a/Source/cmGlobalVisualStudio9Generator.cxx b/Source/cmGlobalVisualStudio9Generator.cxx
new file mode 100644
index 0000000..2339a80
--- /dev/null
+++ b/Source/cmGlobalVisualStudio9Generator.cxx
@@ -0,0 +1,158 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalVisualStudio9Generator.h"
+
+#include <utility>
+
+#include "cmDocumentationEntry.h"
+#include "cmLocalVisualStudio7Generator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmVisualStudioWCEPlatformParser.h"
+
+static const char vs9generatorName[] = "Visual Studio 9 2008";
+
+class cmGlobalVisualStudio9Generator::Factory : public cmGlobalGeneratorFactory
+{
+public:
+ std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+ const std::string& name, bool allowArch, cmake* cm) const override
+ {
+ if (strncmp(name.c_str(), vs9generatorName,
+ sizeof(vs9generatorName) - 1) != 0) {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+
+ const char* p = name.c_str() + sizeof(vs9generatorName) - 1;
+ if (p[0] == '\0') {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio9Generator(cm, name, ""));
+ }
+
+ if (!allowArch || p[0] != ' ') {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+
+ ++p;
+
+ if (!strcmp(p, "IA64")) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio9Generator(cm, name, "Itanium"));
+ }
+
+ if (!strcmp(p, "Win64")) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudio9Generator(cm, name, "x64"));
+ }
+
+ cmVisualStudioWCEPlatformParser parser(p);
+ parser.ParseVersion("9.0");
+ if (!parser.Found()) {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+
+ auto ret = std::unique_ptr<cmGlobalVisualStudio9Generator>(
+ new cmGlobalVisualStudio9Generator(cm, name, p));
+ ret->WindowsCEVersion = parser.GetOSVersion();
+ return std::unique_ptr<cmGlobalGenerator>(std::move(ret));
+ }
+
+ void GetDocumentation(cmDocumentationEntry& entry) const override
+ {
+ entry.Name = std::string(vs9generatorName) + " [arch]";
+ entry.Brief = "Generates Visual Studio 2008 project files. "
+ "Optional [arch] can be \"Win64\" or \"IA64\".";
+ }
+
+ std::vector<std::string> GetGeneratorNames() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(vs9generatorName);
+ return names;
+ }
+
+ std::vector<std::string> GetGeneratorNamesWithPlatform() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(vs9generatorName + std::string(" Win64"));
+ names.push_back(vs9generatorName + std::string(" IA64"));
+ cmVisualStudioWCEPlatformParser parser;
+ parser.ParseVersion("9.0");
+ const std::vector<std::string>& availablePlatforms =
+ parser.GetAvailablePlatforms();
+ for (std::string const& i : availablePlatforms) {
+ names.push_back("Visual Studio 9 2008 " + i);
+ }
+ return names;
+ }
+
+ bool SupportsToolset() const override { return false; }
+ bool SupportsPlatform() const override { return true; }
+
+ std::vector<std::string> GetKnownPlatforms() const override
+ {
+ std::vector<std::string> platforms;
+ platforms.emplace_back("x64");
+ platforms.emplace_back("Win32");
+ platforms.emplace_back("Itanium");
+ cmVisualStudioWCEPlatformParser parser;
+ parser.ParseVersion("9.0");
+ const std::vector<std::string>& availablePlatforms =
+ parser.GetAvailablePlatforms();
+ for (std::string const& i : availablePlatforms) {
+ platforms.emplace_back(i);
+ }
+ return platforms;
+ }
+
+ std::string GetDefaultPlatformName() const override { return "Win32"; }
+};
+
+std::unique_ptr<cmGlobalGeneratorFactory>
+cmGlobalVisualStudio9Generator::NewFactory()
+{
+ return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
+}
+
+cmGlobalVisualStudio9Generator::cmGlobalVisualStudio9Generator(
+ cmake* cm, const std::string& name,
+ std::string const& platformInGeneratorName)
+ : cmGlobalVisualStudio8Generator(cm, name, platformInGeneratorName)
+{
+ this->Version = VS9;
+ std::string vc9Express;
+ this->ExpressEdition = cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\9.0\\Setup\\VC;"
+ "ProductDir",
+ vc9Express, cmSystemTools::KeyWOW64_32);
+}
+
+std::string cmGlobalVisualStudio9Generator::GetUserMacrosDirectory()
+{
+ std::string base;
+ std::string path;
+
+ // base begins with the VisualStudioProjectsLocation reg value...
+ if (cmSystemTools::ReadRegistryValue(
+ "HKEY_CURRENT_USER\\Software\\Microsoft\\VisualStudio\\9.0;"
+ "VisualStudioProjectsLocation",
+ base)) {
+ cmSystemTools::ConvertToUnixSlashes(base);
+
+ // 9.0 macros folder:
+ path = base + "/VSMacros80";
+ // *NOT* a typo; right now in Visual Studio 2008 beta the macros
+ // folder is VSMacros80... They may change it to 90 before final
+ // release of 2008 or they may not... we'll have to keep our eyes
+ // on it
+ }
+
+ // path is (correctly) still empty if we did not read the base value from
+ // the Registry value
+ return path;
+}
+
+std::string cmGlobalVisualStudio9Generator::GetUserMacrosRegKeyBase()
+{
+ return "Software\\Microsoft\\VisualStudio\\9.0\\vsmacros";
+}
diff --git a/Source/cmGlobalVisualStudio9Generator.h b/Source/cmGlobalVisualStudio9Generator.h
new file mode 100644
index 0000000..6f4d159
--- /dev/null
+++ b/Source/cmGlobalVisualStudio9Generator.h
@@ -0,0 +1,39 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <memory>
+
+#include "cmGlobalVisualStudio8Generator.h"
+
+/** \class cmGlobalVisualStudio9Generator
+ * \brief Write a Unix makefiles.
+ *
+ * cmGlobalVisualStudio9Generator manages UNIX build process for a tree
+ */
+class cmGlobalVisualStudio9Generator : public cmGlobalVisualStudio8Generator
+{
+public:
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory();
+
+ /**
+ * Where does this version of Visual Studio look for macros for the
+ * current user? Returns the empty string if this version of Visual
+ * Studio does not implement support for VB macros.
+ */
+ std::string GetUserMacrosDirectory() override;
+
+ /**
+ * What is the reg key path to "vsmacros" for this version of Visual
+ * Studio?
+ */
+ std::string GetUserMacrosRegKeyBase() override;
+
+protected:
+ cmGlobalVisualStudio9Generator(cmake* cm, const std::string& name,
+ std::string const& platformInGeneratorName);
+
+private:
+ class Factory;
+ friend class Factory;
+};
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
new file mode 100644
index 0000000..c23ee94
--- /dev/null
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -0,0 +1,969 @@
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalVisualStudioGenerator.h"
+
+#include <future>
+#include <iostream>
+
+#include <cm/iterator>
+#include <cm/memory>
+
+#include <windows.h>
+
+#include <objbase.h>
+#include <shellapi.h>
+
+#include "cmsys/Encoding.hxx"
+
+#include "cmCallVisualStudioMacro.h"
+#include "cmCustomCommand.h"
+#include "cmCustomCommandLines.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalVisualStudioGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmTarget.h"
+#include "cmake.h"
+
+cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator(
+ cmake* cm, std::string const& platformInGeneratorName)
+ : cmGlobalGenerator(cm)
+{
+ cm->GetState()->SetIsGeneratorMultiConfig(true);
+ cm->GetState()->SetWindowsShell(true);
+ cm->GetState()->SetWindowsVSIDE(true);
+
+ if (platformInGeneratorName.empty()) {
+ this->DefaultPlatformName = "Win32";
+ } else {
+ this->DefaultPlatformName = platformInGeneratorName;
+ this->PlatformInGeneratorName = true;
+ }
+}
+
+cmGlobalVisualStudioGenerator::~cmGlobalVisualStudioGenerator()
+{
+}
+
+cmGlobalVisualStudioGenerator::VSVersion
+cmGlobalVisualStudioGenerator::GetVersion() const
+{
+ return this->Version;
+}
+
+void cmGlobalVisualStudioGenerator::SetVersion(VSVersion v)
+{
+ this->Version = v;
+}
+
+void cmGlobalVisualStudioGenerator::EnableLanguage(
+ std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
+{
+ mf->AddDefinition("CMAKE_VS_PLATFORM_NAME_DEFAULT",
+ this->DefaultPlatformName);
+ this->cmGlobalGenerator::EnableLanguage(lang, mf, optional);
+}
+
+bool cmGlobalVisualStudioGenerator::SetGeneratorPlatform(std::string const& p,
+ cmMakefile* mf)
+{
+ if (this->GetPlatformName() == "x64") {
+ mf->AddDefinition("CMAKE_FORCE_WIN64", "TRUE");
+ } else if (this->GetPlatformName() == "Itanium") {
+ mf->AddDefinition("CMAKE_FORCE_IA64", "TRUE");
+ }
+ mf->AddDefinition("CMAKE_VS_PLATFORM_NAME", this->GetPlatformName());
+ return this->cmGlobalGenerator::SetGeneratorPlatform(p, mf);
+}
+
+std::string const& cmGlobalVisualStudioGenerator::GetPlatformName() const
+{
+ if (!this->GeneratorPlatform.empty()) {
+ return this->GeneratorPlatform;
+ }
+ return this->DefaultPlatformName;
+}
+
+const char* cmGlobalVisualStudioGenerator::GetIDEVersion() const
+{
+ switch (this->Version) {
+ case cmGlobalVisualStudioGenerator::VS9:
+ return "9.0";
+ case cmGlobalVisualStudioGenerator::VS10:
+ return "10.0";
+ case cmGlobalVisualStudioGenerator::VS11:
+ return "11.0";
+ case cmGlobalVisualStudioGenerator::VS12:
+ return "12.0";
+ case cmGlobalVisualStudioGenerator::VS14:
+ return "14.0";
+ case cmGlobalVisualStudioGenerator::VS15:
+ return "15.0";
+ case cmGlobalVisualStudioGenerator::VS16:
+ return "16.0";
+ }
+ return "";
+}
+
+void cmGlobalVisualStudioGenerator::WriteSLNHeader(std::ostream& fout)
+{
+ char utf8bom[] = { char(0xEF), char(0xBB), char(0xBF) };
+ fout.write(utf8bom, 3);
+ fout << '\n';
+
+ switch (this->Version) {
+ case cmGlobalVisualStudioGenerator::VS9:
+ fout << "Microsoft Visual Studio Solution File, Format Version 10.00\n";
+ fout << "# Visual Studio 2008\n";
+ break;
+ case cmGlobalVisualStudioGenerator::VS10:
+ fout << "Microsoft Visual Studio Solution File, Format Version 11.00\n";
+ if (this->ExpressEdition) {
+ fout << "# Visual C++ Express 2010\n";
+ } else {
+ fout << "# Visual Studio 2010\n";
+ }
+ break;
+ case cmGlobalVisualStudioGenerator::VS11:
+ fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
+ if (this->ExpressEdition) {
+ fout << "# Visual Studio Express 2012 for Windows Desktop\n";
+ } else {
+ fout << "# Visual Studio 2012\n";
+ }
+ break;
+ case cmGlobalVisualStudioGenerator::VS12:
+ fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
+ if (this->ExpressEdition) {
+ fout << "# Visual Studio Express 2013 for Windows Desktop\n";
+ } else {
+ fout << "# Visual Studio 2013\n";
+ }
+ break;
+ case cmGlobalVisualStudioGenerator::VS14:
+ // Visual Studio 14 writes .sln format 12.00
+ fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
+ if (this->ExpressEdition) {
+ fout << "# Visual Studio Express 14 for Windows Desktop\n";
+ } else {
+ fout << "# Visual Studio 14\n";
+ }
+ break;
+ case cmGlobalVisualStudioGenerator::VS15:
+ // Visual Studio 15 writes .sln format 12.00
+ fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
+ if (this->ExpressEdition) {
+ fout << "# Visual Studio Express 15 for Windows Desktop\n";
+ } else {
+ fout << "# Visual Studio 15\n";
+ }
+ break;
+ case cmGlobalVisualStudioGenerator::VS16:
+ // Visual Studio 16 writes .sln format 12.00
+ fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
+ if (this->ExpressEdition) {
+ fout << "# Visual Studio Express 16 for Windows Desktop\n";
+ } else {
+ fout << "# Visual Studio Version 16\n";
+ }
+ break;
+ }
+}
+
+std::string cmGlobalVisualStudioGenerator::GetRegistryBase()
+{
+ return cmGlobalVisualStudioGenerator::GetRegistryBase(this->GetIDEVersion());
+}
+
+std::string cmGlobalVisualStudioGenerator::GetRegistryBase(const char* version)
+{
+ std::string key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\";
+ return key + version;
+}
+
+void cmGlobalVisualStudioGenerator::AddExtraIDETargets()
+{
+ // Add a special target that depends on ALL projects for easy build
+ // of one configuration only.
+ const char* no_working_dir = nullptr;
+ std::vector<std::string> no_byproducts;
+ std::vector<std::string> no_depends;
+ cmCustomCommandLines no_commands;
+ for (auto const& it : this->ProjectMap) {
+ std::vector<cmLocalGenerator*> const& gen = it.second;
+ // add the ALL_BUILD to the first local generator of each project
+ if (!gen.empty()) {
+ // Use no actual command lines so that the target itself is not
+ // considered always out of date.
+ cmTarget* allBuild = gen[0]->AddUtilityCommand(
+ "ALL_BUILD", true, no_working_dir, no_byproducts, no_depends,
+ no_commands, cmPolicies::NEW, false, "Build all projects");
+
+ gen[0]->AddGeneratorTarget(
+ cm::make_unique<cmGeneratorTarget>(allBuild, gen[0]));
+
+ //
+ // Organize in the "predefined targets" folder:
+ //
+ if (this->UseFolderProperty()) {
+ allBuild->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
+ }
+
+ // Now make all targets depend on the ALL_BUILD target
+ for (cmLocalGenerator const* i : gen) {
+ for (const auto& tgt : i->GetGeneratorTargets()) {
+ if (tgt->GetType() == cmStateEnums::GLOBAL_TARGET ||
+ tgt->IsImported()) {
+ continue;
+ }
+ if (!this->IsExcluded(gen[0], tgt.get())) {
+ allBuild->AddUtility(tgt->GetName(), false);
+ }
+ }
+ }
+ }
+ }
+
+ // Configure CMake Visual Studio macros, for this user on this version
+ // of Visual Studio.
+ this->ConfigureCMakeVisualStudioMacros();
+}
+
+void cmGlobalVisualStudioGenerator::ComputeTargetObjectDirectory(
+ cmGeneratorTarget* gt) const
+{
+ std::string dir =
+ cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(), '/');
+ std::string tgtDir = gt->LocalGenerator->GetTargetDirectory(gt);
+ if (!tgtDir.empty()) {
+ dir += tgtDir;
+ dir += "/";
+ }
+ const char* cd = this->GetCMakeCFGIntDir();
+ if (cd && *cd) {
+ dir += cd;
+ dir += "/";
+ }
+ gt->ObjectDirectory = dir;
+}
+
+bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile,
+ const std::string& regKeyBase,
+ std::string& nextAvailableSubKeyName);
+
+void RegisterVisualStudioMacros(const std::string& macrosFile,
+ const std::string& regKeyBase);
+
+#define CMAKE_VSMACROS_FILENAME "CMakeVSMacros2.vsmacros"
+
+#define CMAKE_VSMACROS_RELOAD_MACRONAME \
+ "Macros.CMakeVSMacros2.Macros.ReloadProjects"
+
+#define CMAKE_VSMACROS_STOP_MACRONAME "Macros.CMakeVSMacros2.Macros.StopBuild"
+
+void cmGlobalVisualStudioGenerator::ConfigureCMakeVisualStudioMacros()
+{
+ std::string dir = this->GetUserMacrosDirectory();
+
+ if (!dir.empty()) {
+ std::string src = cmStrCat(cmSystemTools::GetCMakeRoot(),
+ "/Templates/" CMAKE_VSMACROS_FILENAME);
+
+ std::string dst = dir + "/CMakeMacros/" CMAKE_VSMACROS_FILENAME;
+
+ // Copy the macros file to the user directory only if the
+ // destination does not exist or the source location is newer.
+ // This will allow the user to edit the macros for development
+ // purposes but newer versions distributed with CMake will replace
+ // older versions in user directories.
+ int res;
+ if (!cmSystemTools::FileTimeCompare(src, dst, &res) || res > 0) {
+ if (!cmSystemTools::CopyFileAlways(src, dst)) {
+ std::ostringstream oss;
+ oss << "Could not copy from: " << src << std::endl;
+ oss << " to: " << dst << std::endl;
+ cmSystemTools::Message(oss.str(), "Warning");
+ }
+ }
+
+ RegisterVisualStudioMacros(dst, this->GetUserMacrosRegKeyBase());
+ }
+}
+
+void cmGlobalVisualStudioGenerator::CallVisualStudioMacro(
+ MacroName m, const std::string& vsSolutionFile)
+{
+ // If any solution or project files changed during the generation,
+ // tell Visual Studio to reload them...
+ std::string dir = this->GetUserMacrosDirectory();
+
+ // Only really try to call the macro if:
+ // - there is a UserMacrosDirectory
+ // - the CMake vsmacros file exists
+ // - the CMake vsmacros file is registered
+ // - there were .sln/.vcproj files changed during generation
+ //
+ if (!dir.empty()) {
+ std::string macrosFile = dir + "/CMakeMacros/" CMAKE_VSMACROS_FILENAME;
+ std::string nextSubkeyName;
+ if (cmSystemTools::FileExists(macrosFile) &&
+ IsVisualStudioMacrosFileRegistered(
+ macrosFile, this->GetUserMacrosRegKeyBase(), nextSubkeyName)) {
+ if (m == MacroReload) {
+ std::vector<std::string> filenames;
+ this->GetFilesReplacedDuringGenerate(filenames);
+ if (!filenames.empty()) {
+ std::string projects = cmJoin(filenames, ";");
+ cmCallVisualStudioMacro::CallMacro(
+ vsSolutionFile, CMAKE_VSMACROS_RELOAD_MACRONAME, projects,
+ this->GetCMakeInstance()->GetDebugOutput());
+ }
+ } else if (m == MacroStop) {
+ cmCallVisualStudioMacro::CallMacro(
+ vsSolutionFile, CMAKE_VSMACROS_STOP_MACRONAME, "",
+ this->GetCMakeInstance()->GetDebugOutput());
+ }
+ }
+ }
+}
+
+std::string cmGlobalVisualStudioGenerator::GetUserMacrosDirectory()
+{
+ return "";
+}
+
+std::string cmGlobalVisualStudioGenerator::GetUserMacrosRegKeyBase()
+{
+ return "";
+}
+
+void cmGlobalVisualStudioGenerator::FillLinkClosure(
+ const cmGeneratorTarget* target, TargetSet& linked)
+{
+ if (linked.insert(target).second) {
+ TargetDependSet const& depends = this->GetTargetDirectDepends(target);
+ for (cmTargetDepend const& di : depends) {
+ if (di.IsLink()) {
+ this->FillLinkClosure(di, linked);
+ }
+ }
+ }
+}
+
+cmGlobalVisualStudioGenerator::TargetSet const&
+cmGlobalVisualStudioGenerator::GetTargetLinkClosure(cmGeneratorTarget* target)
+{
+ auto i = this->TargetLinkClosure.find(target);
+ if (i == this->TargetLinkClosure.end()) {
+ TargetSetMap::value_type entry(target, TargetSet());
+ i = this->TargetLinkClosure.insert(entry).first;
+ this->FillLinkClosure(target, i->second);
+ }
+ return i->second;
+}
+
+void cmGlobalVisualStudioGenerator::FollowLinkDepends(
+ const cmGeneratorTarget* target, std::set<const cmGeneratorTarget*>& linked)
+{
+ if (!target->IsInBuildSystem()) {
+ return;
+ }
+ if (linked.insert(target).second &&
+ target->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ // Static library targets do not list their link dependencies so
+ // we must follow them transitively now.
+ TargetDependSet const& depends = this->GetTargetDirectDepends(target);
+ for (cmTargetDepend const& di : depends) {
+ if (di.IsLink()) {
+ this->FollowLinkDepends(di, linked);
+ }
+ }
+ }
+}
+
+bool cmGlobalVisualStudioGenerator::ComputeTargetDepends()
+{
+ if (!this->cmGlobalGenerator::ComputeTargetDepends()) {
+ return false;
+ }
+ for (auto const& it : this->ProjectMap) {
+ for (const cmLocalGenerator* i : it.second) {
+ for (const auto& ti : i->GetGeneratorTargets()) {
+ this->ComputeVSTargetDepends(ti.get());
+ }
+ }
+ }
+ return true;
+}
+
+static bool VSLinkable(cmGeneratorTarget const* t)
+{
+ return t->IsLinkable() || t->GetType() == cmStateEnums::OBJECT_LIBRARY;
+}
+
+void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(
+ cmGeneratorTarget* target)
+{
+ if (this->VSTargetDepends.find(target) != this->VSTargetDepends.end()) {
+ return;
+ }
+ VSDependSet& vsTargetDepend = this->VSTargetDepends[target];
+ // VS <= 7.1 has two behaviors that affect solution dependencies.
+ //
+ // (1) Solution-level dependencies between a linkable target and a
+ // library cause that library to be linked. We use an intermedite
+ // empty utility target to express the dependency. (VS 8 and above
+ // provide a project file "LinkLibraryDependencies" setting to
+ // choose whether to activate this behavior. We disable it except
+ // when linking external project files.)
+ //
+ // (2) We cannot let static libraries depend directly on targets to
+ // which they "link" because the librarian tool will copy the
+ // targets into the static library. While the work-around for
+ // behavior (1) would also avoid this, it would create a large
+ // number of extra utility targets for little gain. Instead, use
+ // the above work-around only for dependencies explicitly added by
+ // the add_dependencies() command. Approximate link dependencies by
+ // leaving them out for the static library itself but following them
+ // transitively for other targets.
+
+ bool allowLinkable = (target->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ target->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ target->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ target->GetType() != cmStateEnums::EXECUTABLE);
+
+ TargetDependSet const& depends = this->GetTargetDirectDepends(target);
+
+ // Collect implicit link dependencies (target_link_libraries).
+ // Static libraries cannot depend on their link implementation
+ // due to behavior (2), but they do not really need to.
+ std::set<cmGeneratorTarget const*> linkDepends;
+ if (target->GetType() != cmStateEnums::STATIC_LIBRARY) {
+ for (cmTargetDepend const& di : depends) {
+ if (di.IsLink()) {
+ this->FollowLinkDepends(di, linkDepends);
+ }
+ }
+ }
+
+ // Collect explicit util dependencies (add_dependencies).
+ std::set<cmGeneratorTarget const*> utilDepends;
+ for (cmTargetDepend const& di : depends) {
+ if (di.IsUtil()) {
+ this->FollowLinkDepends(di, utilDepends);
+ }
+ }
+
+ // Collect all targets linked by this target so we can avoid
+ // intermediate targets below.
+ TargetSet linked;
+ if (target->GetType() != cmStateEnums::STATIC_LIBRARY) {
+ linked = this->GetTargetLinkClosure(target);
+ }
+
+ // Emit link dependencies.
+ for (cmGeneratorTarget const* dep : linkDepends) {
+ vsTargetDepend.insert(dep->GetName());
+ }
+
+ // Emit util dependencies. Possibly use intermediate targets.
+ for (cmGeneratorTarget const* dgt : utilDepends) {
+ if (allowLinkable || !VSLinkable(dgt) || linked.count(dgt)) {
+ // Direct dependency allowed.
+ vsTargetDepend.insert(dgt->GetName());
+ } else {
+ // Direct dependency on linkable target not allowed.
+ // Use an intermediate utility target.
+ vsTargetDepend.insert(this->GetUtilityDepend(dgt));
+ }
+ }
+}
+
+bool cmGlobalVisualStudioGenerator::FindMakeProgram(cmMakefile* mf)
+{
+ // Visual Studio generators know how to lookup their build tool
+ // directly instead of needing a helper module to do it, so we
+ // do not actually need to put CMAKE_MAKE_PROGRAM into the cache.
+ if (cmIsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
+ mf->AddDefinition("CMAKE_MAKE_PROGRAM", this->GetVSMakeProgram());
+ }
+ return true;
+}
+
+std::string cmGlobalVisualStudioGenerator::GetUtilityDepend(
+ cmGeneratorTarget const* target)
+{
+ auto i = this->UtilityDepends.find(target);
+ if (i == this->UtilityDepends.end()) {
+ std::string name = this->WriteUtilityDepend(target);
+ UtilityDependsMap::value_type entry(target, name);
+ i = this->UtilityDepends.insert(entry).first;
+ }
+ return i->second;
+}
+
+std::string cmGlobalVisualStudioGenerator::GetStartupProjectName(
+ cmLocalGenerator const* root) const
+{
+ cmProp n = root->GetMakefile()->GetProperty("VS_STARTUP_PROJECT");
+ if (cmNonempty(n)) {
+ std::string startup = *n;
+ if (this->FindTarget(startup)) {
+ return startup;
+ } else {
+ root->GetMakefile()->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ "Directory property VS_STARTUP_PROJECT specifies target "
+ "'" +
+ startup + "' that does not exist. Ignoring.");
+ }
+ }
+
+ // default, if not specified
+ return this->GetAllTargetName();
+}
+
+bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile,
+ const std::string& regKeyBase,
+ std::string& nextAvailableSubKeyName)
+{
+ bool macrosRegistered = false;
+
+ std::string s1;
+ std::string s2;
+
+ // Make lowercase local copies, convert to Unix slashes, and
+ // see if the resulting strings are the same:
+ s1 = cmSystemTools::LowerCase(macrosFile);
+ cmSystemTools::ConvertToUnixSlashes(s1);
+
+ std::string keyname;
+ HKEY hkey = NULL;
+ LONG result = ERROR_SUCCESS;
+ DWORD index = 0;
+
+ keyname = regKeyBase + "\\OtherProjects7";
+ hkey = NULL;
+ result =
+ RegOpenKeyExW(HKEY_CURRENT_USER, cmsys::Encoding::ToWide(keyname).c_str(),
+ 0, KEY_READ, &hkey);
+ if (ERROR_SUCCESS == result) {
+ // Iterate the subkeys and look for the values of interest in each subkey:
+ wchar_t subkeyname[256];
+ DWORD cch_subkeyname = cm::size(subkeyname);
+ wchar_t keyclass[256];
+ DWORD cch_keyclass = cm::size(keyclass);
+ FILETIME lastWriteTime;
+ lastWriteTime.dwHighDateTime = 0;
+ lastWriteTime.dwLowDateTime = 0;
+
+ while (ERROR_SUCCESS ==
+ RegEnumKeyExW(hkey, index, subkeyname, &cch_subkeyname, 0, keyclass,
+ &cch_keyclass, &lastWriteTime)) {
+ // Open the subkey and query the values of interest:
+ HKEY hsubkey = NULL;
+ result = RegOpenKeyExW(hkey, subkeyname, 0, KEY_READ, &hsubkey);
+ if (ERROR_SUCCESS == result) {
+ DWORD valueType = REG_SZ;
+ wchar_t data1[256];
+ DWORD cch_data1 = sizeof(data1);
+ RegQueryValueExW(hsubkey, L"Path", 0, &valueType, (LPBYTE)data1,
+ &cch_data1);
+
+ DWORD data2 = 0;
+ DWORD cch_data2 = sizeof(data2);
+ RegQueryValueExW(hsubkey, L"Security", 0, &valueType, (LPBYTE)&data2,
+ &cch_data2);
+
+ DWORD data3 = 0;
+ DWORD cch_data3 = sizeof(data3);
+ RegQueryValueExW(hsubkey, L"StorageFormat", 0, &valueType,
+ (LPBYTE)&data3, &cch_data3);
+
+ s2 = cmSystemTools::LowerCase(cmsys::Encoding::ToNarrow(data1));
+ cmSystemTools::ConvertToUnixSlashes(s2);
+ if (s2 == s1) {
+ macrosRegistered = true;
+ }
+
+ std::string fullname = cmsys::Encoding::ToNarrow(data1);
+ std::string filename;
+ std::string filepath;
+ std::string filepathname;
+ std::string filepathpath;
+ if (cmSystemTools::FileExists(fullname)) {
+ filename = cmSystemTools::GetFilenameName(fullname);
+ filepath = cmSystemTools::GetFilenamePath(fullname);
+ filepathname = cmSystemTools::GetFilenameName(filepath);
+ filepathpath = cmSystemTools::GetFilenamePath(filepath);
+ }
+
+ // std::cout << keyname << "\\" << subkeyname << ":" << std::endl;
+ // std::cout << " Path: " << data1 << std::endl;
+ // std::cout << " Security: " << data2 << std::endl;
+ // std::cout << " StorageFormat: " << data3 << std::endl;
+ // std::cout << " filename: " << filename << std::endl;
+ // std::cout << " filepath: " << filepath << std::endl;
+ // std::cout << " filepathname: " << filepathname << std::endl;
+ // std::cout << " filepathpath: " << filepathpath << std::endl;
+ // std::cout << std::endl;
+
+ RegCloseKey(hsubkey);
+ } else {
+ std::cout << "error opening subkey: " << subkeyname << std::endl;
+ std::cout << std::endl;
+ }
+
+ ++index;
+ cch_subkeyname = cm::size(subkeyname);
+ cch_keyclass = cm::size(keyclass);
+ lastWriteTime.dwHighDateTime = 0;
+ lastWriteTime.dwLowDateTime = 0;
+ }
+
+ RegCloseKey(hkey);
+ } else {
+ std::cout << "error opening key: " << keyname << std::endl;
+ std::cout << std::endl;
+ }
+
+ // Pass back next available sub key name, assuming sub keys always
+ // follow the expected naming scheme. Expected naming scheme is that
+ // the subkeys of OtherProjects7 is 0 to n-1, so it's ok to use "n"
+ // as the name of the next subkey.
+ nextAvailableSubKeyName = std::to_string(index);
+
+ keyname = regKeyBase + "\\RecordingProject7";
+ hkey = NULL;
+ result =
+ RegOpenKeyExW(HKEY_CURRENT_USER, cmsys::Encoding::ToWide(keyname).c_str(),
+ 0, KEY_READ, &hkey);
+ if (ERROR_SUCCESS == result) {
+ DWORD valueType = REG_SZ;
+ wchar_t data1[256];
+ DWORD cch_data1 = sizeof(data1);
+ RegQueryValueExW(hkey, L"Path", 0, &valueType, (LPBYTE)data1, &cch_data1);
+
+ DWORD data2 = 0;
+ DWORD cch_data2 = sizeof(data2);
+ RegQueryValueExW(hkey, L"Security", 0, &valueType, (LPBYTE)&data2,
+ &cch_data2);
+
+ DWORD data3 = 0;
+ DWORD cch_data3 = sizeof(data3);
+ RegQueryValueExW(hkey, L"StorageFormat", 0, &valueType, (LPBYTE)&data3,
+ &cch_data3);
+
+ s2 = cmSystemTools::LowerCase(cmsys::Encoding::ToNarrow(data1));
+ cmSystemTools::ConvertToUnixSlashes(s2);
+ if (s2 == s1) {
+ macrosRegistered = true;
+ }
+
+ // std::cout << keyname << ":" << std::endl;
+ // std::cout << " Path: " << data1 << std::endl;
+ // std::cout << " Security: " << data2 << std::endl;
+ // std::cout << " StorageFormat: " << data3 << std::endl;
+ // std::cout << std::endl;
+
+ RegCloseKey(hkey);
+ } else {
+ std::cout << "error opening key: " << keyname << std::endl;
+ std::cout << std::endl;
+ }
+
+ return macrosRegistered;
+}
+
+void WriteVSMacrosFileRegistryEntry(const std::string& nextAvailableSubKeyName,
+ const std::string& macrosFile,
+ const std::string& regKeyBase)
+{
+ std::string keyname = regKeyBase + "\\OtherProjects7";
+ HKEY hkey = NULL;
+ LONG result =
+ RegOpenKeyExW(HKEY_CURRENT_USER, cmsys::Encoding::ToWide(keyname).c_str(),
+ 0, KEY_READ | KEY_WRITE, &hkey);
+ if (ERROR_SUCCESS == result) {
+ // Create the subkey and set the values of interest:
+ HKEY hsubkey = NULL;
+ wchar_t lpClass[] = L"";
+ result = RegCreateKeyExW(
+ hkey, cmsys::Encoding::ToWide(nextAvailableSubKeyName).c_str(), 0,
+ lpClass, 0, KEY_READ | KEY_WRITE, 0, &hsubkey, 0);
+ if (ERROR_SUCCESS == result) {
+ DWORD dw = 0;
+
+ std::string s(macrosFile);
+ std::replace(s.begin(), s.end(), '/', '\\');
+ std::wstring ws = cmsys::Encoding::ToWide(s);
+
+ result =
+ RegSetValueExW(hsubkey, L"Path", 0, REG_SZ, (LPBYTE)ws.c_str(),
+ static_cast<DWORD>(ws.size() + 1) * sizeof(wchar_t));
+ if (ERROR_SUCCESS != result) {
+ std::cout << "error result 1: " << result << std::endl;
+ std::cout << std::endl;
+ }
+
+ // Security value is always "1" for sample macros files (seems to be "2"
+ // if you put the file somewhere outside the standard VSMacros folder)
+ dw = 1;
+ result = RegSetValueExW(hsubkey, L"Security", 0, REG_DWORD, (LPBYTE)&dw,
+ sizeof(DWORD));
+ if (ERROR_SUCCESS != result) {
+ std::cout << "error result 2: " << result << std::endl;
+ std::cout << std::endl;
+ }
+
+ // StorageFormat value is always "0" for sample macros files
+ dw = 0;
+ result = RegSetValueExW(hsubkey, L"StorageFormat", 0, REG_DWORD,
+ (LPBYTE)&dw, sizeof(DWORD));
+ if (ERROR_SUCCESS != result) {
+ std::cout << "error result 3: " << result << std::endl;
+ std::cout << std::endl;
+ }
+
+ RegCloseKey(hsubkey);
+ } else {
+ std::cout << "error creating subkey: " << nextAvailableSubKeyName
+ << std::endl;
+ std::cout << std::endl;
+ }
+ RegCloseKey(hkey);
+ } else {
+ std::cout << "error opening key: " << keyname << std::endl;
+ std::cout << std::endl;
+ }
+}
+
+void RegisterVisualStudioMacros(const std::string& macrosFile,
+ const std::string& regKeyBase)
+{
+ bool macrosRegistered;
+ std::string nextAvailableSubKeyName;
+
+ macrosRegistered = IsVisualStudioMacrosFileRegistered(
+ macrosFile, regKeyBase, nextAvailableSubKeyName);
+
+ if (!macrosRegistered) {
+ int count =
+ cmCallVisualStudioMacro::GetNumberOfRunningVisualStudioInstances("ALL");
+
+ // Only register the macros file if there are *no* instances of Visual
+ // Studio running. If we register it while one is running, first, it has
+ // no effect on the running instance; second, and worse, Visual Studio
+ // removes our newly added registration entry when it quits. Instead,
+ // emit a warning asking the user to exit all running Visual Studio
+ // instances...
+ //
+ if (0 != count) {
+ std::ostringstream oss;
+ oss << "Could not register CMake's Visual Studio macros file '"
+ << CMAKE_VSMACROS_FILENAME "' while Visual Studio is running."
+ << " Please exit all running instances of Visual Studio before"
+ << " continuing." << std::endl
+ << std::endl
+ << "CMake needs to register Visual Studio macros when its macros"
+ << " file is updated or when it detects that its current macros file"
+ << " is no longer registered with Visual Studio." << std::endl;
+ cmSystemTools::Message(oss.str(), "Warning");
+
+ // Count them again now that the warning is over. In the case of a GUI
+ // warning, the user may have gone to close Visual Studio and then come
+ // back to the CMake GUI and clicked ok on the above warning. If so,
+ // then register the macros *now* if the count is *now* 0...
+ //
+ count = cmCallVisualStudioMacro::GetNumberOfRunningVisualStudioInstances(
+ "ALL");
+
+ // Also re-get the nextAvailableSubKeyName in case Visual Studio
+ // wrote out new registered macros information as it was exiting:
+ //
+ if (0 == count) {
+ IsVisualStudioMacrosFileRegistered(macrosFile, regKeyBase,
+ nextAvailableSubKeyName);
+ }
+ }
+
+ // Do another if check - 'count' may have changed inside the above if:
+ //
+ if (0 == count) {
+ WriteVSMacrosFileRegistryEntry(nextAvailableSubKeyName, macrosFile,
+ regKeyBase);
+ }
+ }
+}
+bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly(
+ cmGeneratorTarget const* gt)
+{
+ // If there's only one source language, Fortran has to be used
+ // in order for the sources to compile.
+ std::set<std::string> languages = gt->GetAllConfigCompileLanguages();
+ // Consider an explicit linker language property, but *not* the
+ // computed linker language that may depend on linked targets.
+ // This allows the project to control the language choice in
+ // a target with none of its own sources, e.g. when also using
+ // object libraries.
+ cmProp linkLang = gt->GetProperty("LINKER_LANGUAGE");
+ if (cmNonempty(linkLang)) {
+ languages.insert(*linkLang);
+ }
+
+ // Intel Fortran .vfproj files do support the resource compiler.
+ languages.erase("RC");
+
+ return languages.size() == 1 && *languages.begin() == "Fortran";
+}
+
+bool cmGlobalVisualStudioGenerator::TargetCompare::operator()(
+ cmGeneratorTarget const* l, cmGeneratorTarget const* r) const
+{
+ // Make sure a given named target is ordered first,
+ // e.g. to set ALL_BUILD as the default active project.
+ // When the empty string is named this is a no-op.
+ if (r->GetName() == this->First) {
+ return false;
+ }
+ if (l->GetName() == this->First) {
+ return true;
+ }
+ return l->GetName() < r->GetName();
+}
+
+cmGlobalVisualStudioGenerator::OrderedTargetDependSet::OrderedTargetDependSet(
+ TargetDependSet const& targets, std::string const& first)
+ : derived(TargetCompare(first))
+{
+ this->insert(targets.begin(), targets.end());
+}
+
+cmGlobalVisualStudioGenerator::OrderedTargetDependSet::OrderedTargetDependSet(
+ TargetSet const& targets, std::string const& first)
+ : derived(TargetCompare(first))
+{
+ for (cmGeneratorTarget const* it : targets) {
+ this->insert(it);
+ }
+}
+
+std::string cmGlobalVisualStudioGenerator::ExpandCFGIntDir(
+ const std::string& str, const std::string& config) const
+{
+ std::string replace = GetCMakeCFGIntDir();
+
+ std::string tmp = str;
+ for (std::string::size_type i = tmp.find(replace); i != std::string::npos;
+ i = tmp.find(replace, i)) {
+ tmp.replace(i, replace.size(), config);
+ i += config.size();
+ }
+ return tmp;
+}
+
+void cmGlobalVisualStudioGenerator::AddSymbolExportCommand(
+ cmGeneratorTarget* gt, std::vector<cmCustomCommand>& commands,
+ std::string const& configName)
+{
+ cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
+ gt->GetModuleDefinitionInfo(configName);
+ if (!mdi || !mdi->DefFileGenerated) {
+ return;
+ }
+
+ std::vector<std::string> outputs;
+ outputs.push_back(mdi->DefFile);
+ std::vector<std::string> empty;
+ std::vector<cmSourceFile const*> objectSources;
+ gt->GetObjectSources(objectSources, configName);
+ std::map<cmSourceFile const*, std::string> mapping;
+ for (cmSourceFile const* it : objectSources) {
+ mapping[it];
+ }
+ gt->LocalGenerator->ComputeObjectFilenames(mapping, gt);
+ std::string obj_dir = gt->ObjectDirectory;
+ std::string cmakeCommand = cmSystemTools::GetCMakeCommand();
+ std::string obj_dir_expanded = obj_dir;
+ cmSystemTools::ReplaceString(obj_dir_expanded, this->GetCMakeCFGIntDir(),
+ configName.c_str());
+ cmSystemTools::MakeDirectory(obj_dir_expanded);
+ std::string const objs_file = obj_dir_expanded + "/objects.txt";
+ cmGeneratedFileStream fout(objs_file.c_str());
+ if (!fout) {
+ cmSystemTools::Error("could not open " + objs_file);
+ return;
+ }
+
+ if (mdi->WindowsExportAllSymbols) {
+ std::vector<std::string> objs;
+ for (cmSourceFile const* it : objectSources) {
+ // Find the object file name corresponding to this source file.
+ // It must exist because we populated the mapping just above.
+ const auto& v = mapping[it];
+ assert(!v.empty());
+ std::string objFile = obj_dir + v;
+ objs.push_back(objFile);
+ }
+ std::vector<cmSourceFile const*> externalObjectSources;
+ gt->GetExternalObjects(externalObjectSources, configName);
+ for (cmSourceFile const* it : externalObjectSources) {
+ objs.push_back(it->GetFullPath());
+ }
+
+ for (std::string const& it : objs) {
+ std::string objFile = it;
+ // replace $(ConfigurationName) in the object names
+ cmSystemTools::ReplaceString(objFile, this->GetCMakeCFGIntDir(),
+ configName);
+ if (cmHasLiteralSuffix(objFile, ".obj")) {
+ fout << objFile << "\n";
+ }
+ }
+ }
+
+ for (cmSourceFile const* i : mdi->Sources) {
+ fout << i->GetFullPath() << "\n";
+ }
+
+ cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
+ { cmakeCommand, "-E", "__create_def", mdi->DefFile, objs_file });
+ cmCustomCommand command(outputs, empty, empty, commandLines,
+ gt->Target->GetMakefile()->GetBacktrace(),
+ "Auto build dll exports", ".", true);
+ commands.push_back(std::move(command));
+}
+
+static bool OpenSolution(std::string sln)
+{
+ HRESULT comInitialized =
+ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
+ if (FAILED(comInitialized)) {
+ return false;
+ }
+
+ HINSTANCE hi =
+ ShellExecuteA(NULL, "open", sln.c_str(), NULL, NULL, SW_SHOWNORMAL);
+
+ CoUninitialize();
+
+ return reinterpret_cast<intptr_t>(hi) > 32;
+}
+
+bool cmGlobalVisualStudioGenerator::Open(const std::string& bindir,
+ const std::string& projectName,
+ bool dryRun)
+{
+ std::string sln = bindir + "/" + projectName + ".sln";
+
+ if (dryRun) {
+ return cmSystemTools::FileExists(sln, true);
+ }
+
+ sln = cmSystemTools::ConvertToOutputPath(sln);
+
+ return std::async(std::launch::async, OpenSolution, sln).get();
+}
diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h
new file mode 100644
index 0000000..3bfcbd0
--- /dev/null
+++ b/Source/cmGlobalVisualStudioGenerator.h
@@ -0,0 +1,230 @@
+/* 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 <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmGlobalGenerator.h"
+#include "cmTargetDepend.h"
+
+class cmCustomCommand;
+class cmGeneratorTarget;
+class cmLocalGenerator;
+class cmMakefile;
+class cmake;
+
+/** \class cmGlobalVisualStudioGenerator
+ * \brief Base class for global Visual Studio generators.
+ *
+ * cmGlobalVisualStudioGenerator provides functionality common to all
+ * global Visual Studio generators.
+ */
+class cmGlobalVisualStudioGenerator : public cmGlobalGenerator
+{
+public:
+ /** Known versions of Visual Studio. */
+ enum VSVersion
+ {
+ VS9 = 90,
+ VS10 = 100,
+ VS11 = 110,
+ VS12 = 120,
+ /* VS13 = 130 was skipped */
+ VS14 = 140,
+ VS15 = 150,
+ VS16 = 160
+ };
+
+ virtual ~cmGlobalVisualStudioGenerator();
+
+ VSVersion GetVersion() const;
+ void SetVersion(VSVersion v);
+
+ /** Is the installed VS an Express edition? */
+ bool IsExpressEdition() const { return this->ExpressEdition; }
+
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) override;
+
+ bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override;
+
+ /**
+ * Get the name of the target platform (architecture) for which we generate.
+ * The names are as defined by VS, e.g. "Win32", "x64", "Itanium", "ARM".
+ */
+ std::string const& GetPlatformName() const;
+
+ /**
+ * Configure CMake's Visual Studio macros file into the user's Visual
+ * Studio macros directory.
+ */
+ virtual void ConfigureCMakeVisualStudioMacros();
+
+ /**
+ * Where does this version of Visual Studio look for macros for the
+ * current user? Returns the empty string if this version of Visual
+ * Studio does not implement support for VB macros.
+ */
+ virtual std::string GetUserMacrosDirectory();
+
+ /**
+ * What is the reg key path to "vsmacros" for this version of Visual
+ * Studio?
+ */
+ virtual std::string GetUserMacrosRegKeyBase();
+
+ enum MacroName
+ {
+ MacroReload,
+ MacroStop
+ };
+
+ /**
+ * Call the ReloadProjects macro if necessary based on
+ * GetFilesReplacedDuringGenerate results.
+ */
+ void CallVisualStudioMacro(MacroName m, const std::string& vsSolutionFile);
+
+ // return true if target is fortran only
+ bool TargetIsFortranOnly(const cmGeneratorTarget* gt);
+
+ /** Get the top-level registry key for this VS version. */
+ std::string GetRegistryBase();
+
+ /** Get the top-level registry key for the given VS version. */
+ static std::string GetRegistryBase(const char* version);
+
+ /** Return true if the generated build tree may contain multiple builds.
+ i.e. "Can I build Debug and Release in the same tree?" */
+ bool IsMultiConfig() const override { return true; }
+
+ /** Return true if building for Windows CE */
+ virtual bool TargetsWindowsCE() const { return false; }
+
+ bool IsIncludeExternalMSProjectSupported() const override { return true; }
+
+ /** Get encoding used by generator for generated source files
+ */
+ codecvt::Encoding GetMakefileEncoding() const override
+ {
+ return codecvt::ANSI;
+ }
+
+ class TargetSet : public std::set<cmGeneratorTarget const*>
+ {
+ };
+ class TargetCompare
+ {
+ std::string First;
+
+ public:
+ TargetCompare(std::string const& first)
+ : First(first)
+ {
+ }
+ bool operator()(cmGeneratorTarget const* l,
+ cmGeneratorTarget const* r) const;
+ };
+ class OrderedTargetDependSet;
+
+ bool FindMakeProgram(cmMakefile*) override;
+
+ std::string ExpandCFGIntDir(const std::string& str,
+ const std::string& config) const override;
+
+ void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;
+
+ std::string GetStartupProjectName(cmLocalGenerator const* root) const;
+
+ void AddSymbolExportCommand(cmGeneratorTarget*,
+ std::vector<cmCustomCommand>& commands,
+ std::string const& configName);
+
+ bool Open(const std::string& bindir, const std::string& projectName,
+ bool dryRun) override;
+
+ bool IsVisualStudio() const override { return true; }
+
+protected:
+ cmGlobalVisualStudioGenerator(cmake* cm,
+ std::string const& platformInGeneratorName);
+
+ void AddExtraIDETargets() override;
+
+ // Does this VS version link targets to each other if there are
+ // dependencies in the SLN file? This was done for VS versions
+ // below 8.
+ virtual bool VSLinksDependencies() const { return true; }
+
+ const char* GetIDEVersion() const;
+
+ void WriteSLNHeader(std::ostream& fout);
+
+ FindMakeProgramStage GetFindMakeProgramStage() const override
+ {
+ return FindMakeProgramStage::Early;
+ }
+
+ bool ComputeTargetDepends() override;
+ class VSDependSet : public std::set<std::string>
+ {
+ };
+ class VSDependMap : public std::map<cmGeneratorTarget const*, VSDependSet>
+ {
+ };
+ VSDependMap VSTargetDepends;
+ void ComputeVSTargetDepends(cmGeneratorTarget*);
+
+ bool CheckTargetLinks(cmGeneratorTarget& target, const std::string& name);
+ std::string GetUtilityForTarget(cmGeneratorTarget& target,
+ const std::string&);
+ virtual std::string WriteUtilityDepend(cmGeneratorTarget const*) = 0;
+ std::string GetUtilityDepend(const cmGeneratorTarget* target);
+ using UtilityDependsMap = std::map<cmGeneratorTarget const*, std::string>;
+ UtilityDependsMap UtilityDepends;
+
+protected:
+ VSVersion Version;
+ bool ExpressEdition;
+
+ std::string GeneratorPlatform;
+ std::string DefaultPlatformName;
+ bool PlatformInGeneratorName = false;
+
+private:
+ virtual std::string GetVSMakeProgram() = 0;
+ void PrintCompilerAdvice(std::ostream&, std::string const&,
+ const char*) const override
+ {
+ }
+
+ void FollowLinkDepends(cmGeneratorTarget const* target,
+ std::set<cmGeneratorTarget const*>& linked);
+
+ class TargetSetMap : public std::map<cmGeneratorTarget*, TargetSet>
+ {
+ };
+ TargetSetMap TargetLinkClosure;
+ void FillLinkClosure(const cmGeneratorTarget* target, TargetSet& linked);
+ TargetSet const& GetTargetLinkClosure(cmGeneratorTarget* target);
+};
+
+class cmGlobalVisualStudioGenerator::OrderedTargetDependSet
+ : public std::multiset<cmTargetDepend,
+ cmGlobalVisualStudioGenerator::TargetCompare>
+{
+ using derived = std::multiset<cmTargetDepend,
+ cmGlobalVisualStudioGenerator::TargetCompare>;
+
+public:
+ using TargetDependSet = cmGlobalGenerator::TargetDependSet;
+ using TargetSet = cmGlobalVisualStudioGenerator::TargetSet;
+ OrderedTargetDependSet(TargetDependSet const&, std::string const& first);
+ OrderedTargetDependSet(TargetSet const&, std::string const& first);
+};
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
new file mode 100644
index 0000000..9a9a465
--- /dev/null
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
@@ -0,0 +1,634 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalVisualStudioVersionedGenerator.h"
+
+#include <cmext/string_view>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+
+#include "cmAlgorithms.h"
+#include "cmDocumentationEntry.h"
+#include "cmLocalVisualStudio10Generator.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmVSSetupHelper.h"
+#include "cmake.h"
+
+#if defined(_M_ARM64)
+# define HOST_PLATFORM_NAME "ARM64"
+# define HOST_TOOLS_ARCH ""
+#elif defined(_M_ARM)
+# define HOST_PLATFORM_NAME "ARM"
+# define HOST_TOOLS_ARCH ""
+#elif defined(_M_IA64)
+# define HOST_PLATFORM_NAME "Itanium"
+# define HOST_TOOLS_ARCH ""
+#elif defined(_WIN64)
+# define HOST_PLATFORM_NAME "x64"
+# define HOST_TOOLS_ARCH "x64"
+#else
+static bool VSIsWow64()
+{
+ BOOL isWow64 = false;
+ return IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64;
+}
+#endif
+
+static std::string VSHostPlatformName()
+{
+#ifdef HOST_PLATFORM_NAME
+ return HOST_PLATFORM_NAME;
+#else
+ if (VSIsWow64()) {
+ return "x64";
+ } else {
+ return "Win32";
+ }
+#endif
+}
+
+static std::string VSHostArchitecture()
+{
+#ifdef HOST_TOOLS_ARCH
+ return HOST_TOOLS_ARCH;
+#else
+ if (VSIsWow64()) {
+ return "x64";
+ } else {
+ return "x86";
+ }
+#endif
+}
+
+static unsigned int VSVersionToMajor(
+ cmGlobalVisualStudioGenerator::VSVersion v)
+{
+ switch (v) {
+ case cmGlobalVisualStudioGenerator::VS9:
+ return 9;
+ case cmGlobalVisualStudioGenerator::VS10:
+ return 10;
+ case cmGlobalVisualStudioGenerator::VS11:
+ return 11;
+ case cmGlobalVisualStudioGenerator::VS12:
+ return 12;
+ case cmGlobalVisualStudioGenerator::VS14:
+ return 14;
+ case cmGlobalVisualStudioGenerator::VS15:
+ return 15;
+ case cmGlobalVisualStudioGenerator::VS16:
+ return 16;
+ }
+ return 0;
+}
+
+static const char* VSVersionToToolset(
+ cmGlobalVisualStudioGenerator::VSVersion v)
+{
+ switch (v) {
+ case cmGlobalVisualStudioGenerator::VS9:
+ return "v90";
+ case cmGlobalVisualStudioGenerator::VS10:
+ return "v100";
+ case cmGlobalVisualStudioGenerator::VS11:
+ return "v110";
+ case cmGlobalVisualStudioGenerator::VS12:
+ return "v120";
+ case cmGlobalVisualStudioGenerator::VS14:
+ return "v140";
+ case cmGlobalVisualStudioGenerator::VS15:
+ return "v141";
+ case cmGlobalVisualStudioGenerator::VS16:
+ return "v142";
+ }
+ return "";
+}
+
+static const char* VSVersionToAndroidToolset(
+ cmGlobalVisualStudioGenerator::VSVersion v)
+{
+ switch (v) {
+ case cmGlobalVisualStudioGenerator::VS9:
+ case cmGlobalVisualStudioGenerator::VS10:
+ case cmGlobalVisualStudioGenerator::VS11:
+ case cmGlobalVisualStudioGenerator::VS12:
+ return "";
+ case cmGlobalVisualStudioGenerator::VS14:
+ return "Clang_3_8";
+ case cmGlobalVisualStudioGenerator::VS15:
+ case cmGlobalVisualStudioGenerator::VS16:
+ return "Clang_5_0";
+ }
+ return "";
+}
+
+static const char vs15generatorName[] = "Visual Studio 15 2017";
+
+// Map generator name without year to name with year.
+static const char* cmVS15GenName(const std::string& name, std::string& genName)
+{
+ if (strncmp(name.c_str(), vs15generatorName,
+ sizeof(vs15generatorName) - 6) != 0) {
+ return 0;
+ }
+ const char* p = name.c_str() + sizeof(vs15generatorName) - 6;
+ if (cmHasLiteralPrefix(p, " 2017")) {
+ p += 5;
+ }
+ genName = std::string(vs15generatorName) + p;
+ return p;
+}
+
+class cmGlobalVisualStudioVersionedGenerator::Factory15
+ : public cmGlobalGeneratorFactory
+{
+public:
+ std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+ const std::string& name, bool allowArch, cmake* cm) const override
+ {
+ std::string genName;
+ const char* p = cmVS15GenName(name, genName);
+ if (!p) {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+ if (!*p) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudioVersionedGenerator(
+ cmGlobalVisualStudioGenerator::VS15, cm, genName, ""));
+ }
+ if (!allowArch || *p++ != ' ') {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+ if (strcmp(p, "Win64") == 0) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudioVersionedGenerator(
+ cmGlobalVisualStudioGenerator::VS15, cm, genName, "x64"));
+ }
+ if (strcmp(p, "ARM") == 0) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudioVersionedGenerator(
+ cmGlobalVisualStudioGenerator::VS15, cm, genName, "ARM"));
+ }
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+
+ void GetDocumentation(cmDocumentationEntry& entry) const override
+ {
+ entry.Name = std::string(vs15generatorName) + " [arch]";
+ entry.Brief = "Generates Visual Studio 2017 project files. "
+ "Optional [arch] can be \"Win64\" or \"ARM\".";
+ }
+
+ std::vector<std::string> GetGeneratorNames() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(vs15generatorName);
+ return names;
+ }
+
+ std::vector<std::string> GetGeneratorNamesWithPlatform() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(vs15generatorName + std::string(" ARM"));
+ names.push_back(vs15generatorName + std::string(" Win64"));
+ return names;
+ }
+
+ bool SupportsToolset() const override { return true; }
+ bool SupportsPlatform() const override { return true; }
+
+ std::vector<std::string> GetKnownPlatforms() const override
+ {
+ std::vector<std::string> platforms;
+ platforms.emplace_back("x64");
+ platforms.emplace_back("Win32");
+ platforms.emplace_back("ARM");
+ platforms.emplace_back("ARM64");
+ platforms.emplace_back("ARM64EC");
+ return platforms;
+ }
+
+ std::string GetDefaultPlatformName() const override { return "Win32"; }
+};
+
+std::unique_ptr<cmGlobalGeneratorFactory>
+cmGlobalVisualStudioVersionedGenerator::NewFactory15()
+{
+ return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory15);
+}
+
+static const char vs16generatorName[] = "Visual Studio 16 2019";
+
+// Map generator name without year to name with year.
+static const char* cmVS16GenName(const std::string& name, std::string& genName)
+{
+ if (strncmp(name.c_str(), vs16generatorName,
+ sizeof(vs16generatorName) - 6) != 0) {
+ return 0;
+ }
+ const char* p = name.c_str() + sizeof(vs16generatorName) - 6;
+ if (cmHasLiteralPrefix(p, " 2019")) {
+ p += 5;
+ }
+ genName = std::string(vs16generatorName) + p;
+ return p;
+}
+
+class cmGlobalVisualStudioVersionedGenerator::Factory16
+ : public cmGlobalGeneratorFactory
+{
+public:
+ std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+ const std::string& name, bool /*allowArch*/, cmake* cm) const override
+ {
+ std::string genName;
+ const char* p = cmVS16GenName(name, genName);
+ if (!p) {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+ if (!*p) {
+ return std::unique_ptr<cmGlobalGenerator>(
+ new cmGlobalVisualStudioVersionedGenerator(
+ cmGlobalVisualStudioGenerator::VS16, cm, genName, ""));
+ }
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+
+ void GetDocumentation(cmDocumentationEntry& entry) const override
+ {
+ entry.Name = std::string(vs16generatorName);
+ entry.Brief = "Generates Visual Studio 2019 project files. "
+ "Use -A option to specify architecture.";
+ }
+
+ std::vector<std::string> GetGeneratorNames() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(vs16generatorName);
+ return names;
+ }
+
+ std::vector<std::string> GetGeneratorNamesWithPlatform() const override
+ {
+ return std::vector<std::string>();
+ }
+
+ bool SupportsToolset() const override { return true; }
+ bool SupportsPlatform() const override { return true; }
+
+ std::vector<std::string> GetKnownPlatforms() const override
+ {
+ std::vector<std::string> platforms;
+ platforms.emplace_back("x64");
+ platforms.emplace_back("Win32");
+ platforms.emplace_back("ARM");
+ platforms.emplace_back("ARM64");
+ return platforms;
+ }
+
+ std::string GetDefaultPlatformName() const override
+ {
+ return VSHostPlatformName();
+ }
+};
+
+std::unique_ptr<cmGlobalGeneratorFactory>
+cmGlobalVisualStudioVersionedGenerator::NewFactory16()
+{
+ return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory16);
+}
+
+cmGlobalVisualStudioVersionedGenerator::cmGlobalVisualStudioVersionedGenerator(
+ VSVersion version, cmake* cm, const std::string& name,
+ std::string const& platformInGeneratorName)
+ : cmGlobalVisualStudio14Generator(cm, name, platformInGeneratorName)
+ , vsSetupAPIHelper(VSVersionToMajor(version))
+{
+ this->Version = version;
+ this->ExpressEdition = false;
+ this->DefaultPlatformToolset = VSVersionToToolset(this->Version);
+ this->DefaultAndroidToolset = VSVersionToAndroidToolset(this->Version);
+ this->DefaultCLFlagTableName = VSVersionToToolset(this->Version);
+ this->DefaultCSharpFlagTableName = VSVersionToToolset(this->Version);
+ this->DefaultLinkFlagTableName = VSVersionToToolset(this->Version);
+ if (this->Version >= cmGlobalVisualStudioGenerator::VS16) {
+ this->DefaultPlatformName = VSHostPlatformName();
+ this->DefaultPlatformToolsetHostArchitecture = VSHostArchitecture();
+ }
+}
+
+bool cmGlobalVisualStudioVersionedGenerator::MatchesGeneratorName(
+ const std::string& name) const
+{
+ std::string genName;
+ switch (this->Version) {
+ case cmGlobalVisualStudioGenerator::VS9:
+ case cmGlobalVisualStudioGenerator::VS10:
+ case cmGlobalVisualStudioGenerator::VS11:
+ case cmGlobalVisualStudioGenerator::VS12:
+ case cmGlobalVisualStudioGenerator::VS14:
+ break;
+ case cmGlobalVisualStudioGenerator::VS15:
+ if (cmVS15GenName(name, genName)) {
+ return genName == this->GetName();
+ }
+ break;
+ case cmGlobalVisualStudioGenerator::VS16:
+ if (cmVS16GenName(name, genName)) {
+ return genName == this->GetName();
+ }
+ break;
+ }
+ return false;
+}
+
+bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance(
+ std::string const& i, cmMakefile* mf)
+{
+ if (!i.empty()) {
+ if (!this->vsSetupAPIHelper.SetVSInstance(i)) {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "could not find specified instance of Visual Studio:\n"
+ " " << i;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ }
+
+ std::string vsInstance;
+ if (!this->vsSetupAPIHelper.GetVSInstanceInfo(vsInstance)) {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "could not find any instance of Visual Studio.\n";
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ // Save the selected instance persistently.
+ std::string genInstance = mf->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE");
+ if (vsInstance != genInstance) {
+ this->CMakeInstance->AddCacheEntry(
+ "CMAKE_GENERATOR_INSTANCE", vsInstance.c_str(),
+ "Generator instance identifier.", cmStateEnums::INTERNAL);
+ }
+
+ return true;
+}
+
+bool cmGlobalVisualStudioVersionedGenerator::GetVSInstance(
+ std::string& dir) const
+{
+ return vsSetupAPIHelper.GetVSInstanceInfo(dir);
+}
+
+bool cmGlobalVisualStudioVersionedGenerator::GetVSInstanceVersion(
+ unsigned long long& vsInstanceVersion) const
+{
+ return vsSetupAPIHelper.GetVSInstanceVersion(vsInstanceVersion);
+}
+
+bool cmGlobalVisualStudioVersionedGenerator::IsStdOutEncodingSupported() const
+{
+ // Supported from Visual Studio 16.7 Preview 3.
+ if (this->Version > cmGlobalVisualStudioGenerator::VSVersion::VS16) {
+ return true;
+ }
+ if (this->Version < cmGlobalVisualStudioGenerator::VSVersion::VS16) {
+ return false;
+ }
+ unsigned long long const vsInstanceVersion16_7_P2 = 4503631666610212;
+ unsigned long long vsInstanceVersion;
+ return (this->GetVSInstanceVersion(vsInstanceVersion) &&
+ vsInstanceVersion > vsInstanceVersion16_7_P2);
+}
+
+const char*
+cmGlobalVisualStudioVersionedGenerator::GetAndroidApplicationTypeRevision()
+ const
+{
+ switch (this->Version) {
+ case cmGlobalVisualStudioGenerator::VS9:
+ case cmGlobalVisualStudioGenerator::VS10:
+ case cmGlobalVisualStudioGenerator::VS11:
+ case cmGlobalVisualStudioGenerator::VS12:
+ return "";
+ case cmGlobalVisualStudioGenerator::VS14:
+ return "2.0";
+ case cmGlobalVisualStudioGenerator::VS15:
+ case cmGlobalVisualStudioGenerator::VS16:
+ return "3.0";
+ }
+ return "";
+}
+
+cmGlobalVisualStudioVersionedGenerator::AuxToolset
+cmGlobalVisualStudioVersionedGenerator::FindAuxToolset(
+ std::string& version, std::string& props) const
+{
+ if (version.empty()) {
+ return AuxToolset::None;
+ }
+
+ std::string instancePath;
+ this->GetVSInstance(instancePath);
+ cmSystemTools::ConvertToUnixSlashes(instancePath);
+
+ // Translate three-component format accepted by "vcvarsall -vcvars_ver=".
+ cmsys::RegularExpression threeComponent(
+ "^([0-9]+\\.[0-9]+)\\.[0-9][0-9][0-9][0-9][0-9]$");
+ if (threeComponent.find(version)) {
+ // Load "VC/Auxiliary/Build/*/Microsoft.VCToolsVersion.*.txt" files
+ // with two matching components to check their three-component version.
+ std::string const& twoComponent = threeComponent.match(1);
+ std::string pattern =
+ cmStrCat(instancePath, "/VC/Auxiliary/Build/"_s, twoComponent,
+ "*/Microsoft.VCToolsVersion."_s, twoComponent, "*.txt"_s);
+ cmsys::Glob glob;
+ glob.SetRecurseThroughSymlinks(false);
+ if (glob.FindFiles(pattern)) {
+ for (std::string const& txt : glob.GetFiles()) {
+ std::string ver;
+ cmsys::ifstream fin(txt.c_str());
+ if (fin && std::getline(fin, ver)) {
+ // Strip trailing whitespace.
+ ver = ver.substr(0, ver.find_first_not_of("0123456789."));
+ // If the three-component version matches, translate it to
+ // that used by the "Microsoft.VCToolsVersion.*.txt" file name.
+ if (ver == version) {
+ cmsys::RegularExpression extractVersion(
+ "VCToolsVersion\\.([0-9.]+)\\.txt$");
+ if (extractVersion.find(txt)) {
+ version = extractVersion.match(1);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (cmSystemTools::VersionCompareGreaterEq(version, "14.20")) {
+ props = cmStrCat(instancePath, "/VC/Auxiliary/Build."_s, version,
+ "/Microsoft.VCToolsVersion."_s, version, ".props"_s);
+ if (cmSystemTools::PathExists(props)) {
+ return AuxToolset::PropsExist;
+ }
+ }
+ props = cmStrCat(instancePath, "/VC/Auxiliary/Build/"_s, version,
+ "/Microsoft.VCToolsVersion."_s, version, ".props"_s);
+ if (cmSystemTools::PathExists(props)) {
+ return AuxToolset::PropsExist;
+ }
+
+ // Accept the toolset version that is default in the current VS version
+ // by matching the name later VS versions will use for the SxS props files.
+ std::string vcToolsetVersion;
+ if (this->vsSetupAPIHelper.GetVCToolsetVersion(vcToolsetVersion)) {
+ // Accept an exact-match (three-component version).
+ if (version == vcToolsetVersion) {
+ return AuxToolset::Default;
+ }
+
+ // Accept known SxS props file names using four version components
+ // in VS versions later than the current.
+ if (version == "14.28.16.9" && vcToolsetVersion == "14.28.29910") {
+ return AuxToolset::Default;
+ }
+
+ // The first two components of the default toolset version typically
+ // match the name used by later VS versions for the SxS props files.
+ cmsys::RegularExpression twoComponent("^([0-9]+\\.[0-9]+)");
+ if (twoComponent.find(version)) {
+ std::string const versionPrefix = cmStrCat(twoComponent.match(1), '.');
+ if (cmHasPrefix(vcToolsetVersion, versionPrefix)) {
+ return AuxToolset::Default;
+ }
+ }
+ }
+
+ return AuxToolset::PropsMissing;
+}
+
+bool cmGlobalVisualStudioVersionedGenerator::InitializeWindows(cmMakefile* mf)
+{
+ // If the Win 8.1 SDK is installed then we can select a SDK matching
+ // the target Windows version.
+ if (this->IsWin81SDKInstalled()) {
+ // VS 2019 does not default to 8.1 so specify it explicitly when needed.
+ if (this->Version >= cmGlobalVisualStudioGenerator::VS16 &&
+ !cmSystemTools::VersionCompareGreater(this->SystemVersion, "8.1")) {
+ this->SetWindowsTargetPlatformVersion("8.1", mf);
+ return true;
+ }
+ return cmGlobalVisualStudio14Generator::InitializeWindows(mf);
+ }
+ // Otherwise we must choose a Win 10 SDK even if we are not targeting
+ // Windows 10.
+ return this->SelectWindows10SDK(mf, false);
+}
+
+bool cmGlobalVisualStudioVersionedGenerator::SelectWindowsStoreToolset(
+ std::string& toolset) const
+{
+ if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) {
+ if (this->IsWindowsStoreToolsetInstalled() &&
+ this->IsWindowsDesktopToolsetInstalled()) {
+ toolset = VSVersionToToolset(this->Version);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return this->cmGlobalVisualStudio14Generator::SelectWindowsStoreToolset(
+ toolset);
+}
+
+bool cmGlobalVisualStudioVersionedGenerator::IsWindowsDesktopToolsetInstalled()
+ const
+{
+ return vsSetupAPIHelper.IsVSInstalled();
+}
+
+bool cmGlobalVisualStudioVersionedGenerator::IsWindowsStoreToolsetInstalled()
+ const
+{
+ return vsSetupAPIHelper.IsWin10SDKInstalled();
+}
+
+bool cmGlobalVisualStudioVersionedGenerator::IsWin81SDKInstalled() const
+{
+ // Does the VS installer tool know about one?
+ if (vsSetupAPIHelper.IsWin81SDKInstalled()) {
+ return true;
+ }
+
+ // Does the registry know about one (e.g. from VS 2015)?
+ std::string win81Root;
+ if (cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "Windows Kits\\Installed Roots;KitsRoot81",
+ win81Root, cmSystemTools::KeyWOW64_32) ||
+ cmSystemTools::ReadRegistryValue(
+ "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\"
+ "Windows Kits\\Installed Roots;KitsRoot81",
+ win81Root, cmSystemTools::KeyWOW64_32)) {
+ return cmSystemTools::FileExists(win81Root + "/include/um/windows.h",
+ true);
+ }
+ return false;
+}
+
+std::string
+cmGlobalVisualStudioVersionedGenerator::GetWindows10SDKMaxVersionDefault(
+ cmMakefile*) const
+{
+ return std::string();
+}
+
+std::string cmGlobalVisualStudioVersionedGenerator::FindMSBuildCommand()
+{
+ std::string msbuild;
+
+ // Ask Visual Studio Installer tool.
+ std::string vs;
+ if (vsSetupAPIHelper.GetVSInstanceInfo(vs)) {
+ msbuild = vs + "/MSBuild/Current/Bin/MSBuild.exe";
+ if (cmSystemTools::FileExists(msbuild)) {
+ return msbuild;
+ }
+ msbuild = vs + "/MSBuild/15.0/Bin/MSBuild.exe";
+ if (cmSystemTools::FileExists(msbuild)) {
+ return msbuild;
+ }
+ }
+
+ msbuild = "MSBuild.exe";
+ return msbuild;
+}
+
+std::string cmGlobalVisualStudioVersionedGenerator::FindDevEnvCommand()
+{
+ std::string devenv;
+
+ // Ask Visual Studio Installer tool.
+ std::string vs;
+ if (vsSetupAPIHelper.GetVSInstanceInfo(vs)) {
+ devenv = vs + "/Common7/IDE/devenv.com";
+ if (cmSystemTools::FileExists(devenv)) {
+ return devenv;
+ }
+ }
+
+ devenv = "devenv.com";
+ return devenv;
+}
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h
new file mode 100644
index 0000000..cee129e
--- /dev/null
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.h
@@ -0,0 +1,70 @@
+/* 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 <iosfwd>
+#include <memory>
+#include <string>
+
+#include "cmGlobalVisualStudio14Generator.h"
+#include "cmVSSetupHelper.h"
+
+class cmGlobalGeneratorFactory;
+class cmake;
+
+/** \class cmGlobalVisualStudioVersionedGenerator */
+class cmGlobalVisualStudioVersionedGenerator
+ : public cmGlobalVisualStudio14Generator
+{
+public:
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory15();
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory16();
+
+ bool MatchesGeneratorName(const std::string& name) const override;
+
+ bool SetGeneratorInstance(std::string const& i, cmMakefile* mf) override;
+
+ bool GetVSInstance(std::string& dir) const;
+
+ bool GetVSInstanceVersion(unsigned long long& vsInstanceVersion) const;
+
+ AuxToolset FindAuxToolset(std::string& version,
+ std::string& props) const override;
+
+ bool IsStdOutEncodingSupported() const override;
+
+ const char* GetAndroidApplicationTypeRevision() const override;
+
+protected:
+ cmGlobalVisualStudioVersionedGenerator(
+ VSVersion version, cmake* cm, const std::string& name,
+ std::string const& platformInGeneratorName);
+
+ bool InitializeWindows(cmMakefile* mf) override;
+ bool SelectWindowsStoreToolset(std::string& toolset) const override;
+
+ // Used to verify that the Desktop toolset for the current generator is
+ // installed on the machine.
+ bool IsWindowsDesktopToolsetInstalled() const override;
+
+ // These aren't virtual because we need to check if the selected version
+ // of the toolset is installed
+ bool IsWindowsStoreToolsetInstalled() const;
+
+ // Check for a Win 8 SDK known to the registry or VS installer tool.
+ bool IsWin81SDKInstalled() const;
+
+ std::string GetWindows10SDKMaxVersionDefault(cmMakefile*) const override;
+
+ std::string FindMSBuildCommand() override;
+ std::string FindDevEnvCommand() override;
+
+private:
+ class Factory15;
+ friend class Factory15;
+ class Factory16;
+ friend class Factory16;
+ mutable cmVSSetupAPIHelper vsSetupAPIHelper;
+};
diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx
new file mode 100644
index 0000000..3e2d92d
--- /dev/null
+++ b/Source/cmGlobalWatcomWMakeGenerator.cxx
@@ -0,0 +1,91 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalWatcomWMakeGenerator.h"
+
+#include <ostream>
+
+#include "cmDocumentationEntry.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmState.h"
+#include "cmake.h"
+
+cmGlobalWatcomWMakeGenerator::cmGlobalWatcomWMakeGenerator(cmake* cm)
+ : cmGlobalUnixMakefileGenerator3(cm)
+{
+ this->FindMakeProgramFile = "CMakeFindWMake.cmake";
+#ifdef _WIN32
+ this->ForceUnixPaths = false;
+#endif
+ this->ToolSupportsColor = true;
+ this->NeedSymbolicMark = true;
+ this->EmptyRuleHackCommand = "@%null";
+#ifdef _WIN32
+ cm->GetState()->SetWindowsShell(true);
+#endif
+ cm->GetState()->SetWatcomWMake(true);
+ this->IncludeDirective = "!include";
+ this->LineContinueDirective = "&\n";
+ this->DefineWindowsNULL = true;
+ this->UnixCD = false;
+ this->MakeSilentFlag = "-h";
+}
+
+void cmGlobalWatcomWMakeGenerator::EnableLanguage(
+ std::vector<std::string> const& l, cmMakefile* mf, bool optional)
+{
+ // pick a default
+ mf->AddDefinition("WATCOM", "1");
+ mf->AddDefinition("CMAKE_QUOTE_INCLUDE_PATHS", "1");
+ mf->AddDefinition("CMAKE_MANGLE_OBJECT_FILE_NAMES", "1");
+ mf->AddDefinition("CMAKE_MAKE_SYMBOLIC_RULE", ".SYMBOLIC");
+ mf->AddDefinition("CMAKE_GENERATOR_CC", "wcl386");
+ mf->AddDefinition("CMAKE_GENERATOR_CXX", "wcl386");
+ this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
+}
+
+bool cmGlobalWatcomWMakeGenerator::SetSystemName(std::string const& s,
+ cmMakefile* mf)
+{
+ if (mf->GetSafeDefinition("CMAKE_SYSTEM_PROCESSOR") == "I86") {
+ mf->AddDefinition("CMAKE_GENERATOR_CC", "wcl");
+ mf->AddDefinition("CMAKE_GENERATOR_CXX", "wcl");
+ }
+ return this->cmGlobalUnixMakefileGenerator3::SetSystemName(s, mf);
+}
+
+void cmGlobalWatcomWMakeGenerator::GetDocumentation(
+ cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalWatcomWMakeGenerator::GetActualName();
+ entry.Brief = "Generates Watcom WMake makefiles.";
+}
+
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalWatcomWMakeGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int /*jobs*/, bool verbose,
+ std::vector<std::string> const& makeOptions)
+{
+ return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast,
+ cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
+}
+
+void cmGlobalWatcomWMakeGenerator::PrintBuildCommandAdvice(std::ostream& os,
+ int jobs) const
+{
+ if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
+ // wmake does not support parallel build level
+
+ /* clang-format off */
+ os <<
+ "Warning: Watcom's WMake does not support parallel builds. "
+ "Ignoring parallel build command line option.\n";
+ /* clang-format on */
+ }
+
+ this->cmGlobalUnixMakefileGenerator3::PrintBuildCommandAdvice(
+ os, cmake::NO_BUILD_PARALLEL_LEVEL);
+}
diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h
new file mode 100644
index 0000000..da39d3f
--- /dev/null
+++ b/Source/cmGlobalWatcomWMakeGenerator.h
@@ -0,0 +1,65 @@
+/* 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 <iosfwd>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "cmGlobalGeneratorFactory.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+
+class cmMakefile;
+class cmake;
+struct cmDocumentationEntry;
+
+/** \class cmGlobalWatcomWMakeGenerator
+ * \brief Write a NMake makefiles.
+ *
+ * cmGlobalWatcomWMakeGenerator manages nmake build process for a tree
+ */
+class cmGlobalWatcomWMakeGenerator : public cmGlobalUnixMakefileGenerator3
+{
+public:
+ cmGlobalWatcomWMakeGenerator(cmake* cm);
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
+ {
+ return std::unique_ptr<cmGlobalGeneratorFactory>(
+ new cmGlobalGeneratorSimpleFactory<cmGlobalWatcomWMakeGenerator>());
+ }
+ //! Get the name for the generator.
+ std::string GetName() const override
+ {
+ return cmGlobalWatcomWMakeGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "Watcom WMake"; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ /** Tell the generator about the target system. */
+ bool SetSystemName(std::string const& s, cmMakefile* mf) override;
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) override;
+
+ bool AllowNotParallel() const override { return false; }
+ bool AllowDeleteOnError() const override { return false; }
+
+protected:
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
+
+ void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
+};
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
new file mode 100644
index 0000000..7dd1704
--- /dev/null
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -0,0 +1,4827 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGlobalXCodeGenerator.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+#include <iomanip>
+#include <sstream>
+#include <unordered_set>
+#include <utility>
+
+#include <cm/memory>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmComputeLinkInformation.h"
+#include "cmCryptoHash.h"
+#include "cmCustomCommand.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmCustomCommandLines.h"
+#include "cmDocumentationEntry.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGeneratorFactory.h"
+#include "cmLocalGenerator.h"
+#include "cmLocalXCodeGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmSourceFile.h"
+#include "cmSourceGroup.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmXCode21Object.h"
+#include "cmXCodeObject.h"
+#include "cmXCodeScheme.h"
+#include "cmake.h"
+
+struct cmLinkImplementation;
+
+#if !defined(CMAKE_BOOTSTRAP) && defined(__APPLE__)
+# include <CoreFoundation/CoreFoundation.h>
+# if !TARGET_OS_IPHONE
+# define HAVE_APPLICATION_SERVICES
+# include <ApplicationServices/ApplicationServices.h>
+# endif
+#endif
+
+#if !defined(CMAKE_BOOTSTRAP)
+# include "cmXMLParser.h"
+
+// parse the xml file storing the installed version of Xcode on
+// the machine
+class cmXcodeVersionParser : public cmXMLParser
+{
+public:
+ cmXcodeVersionParser()
+ : Version("1.5")
+ {
+ }
+ void StartElement(const std::string&, const char**) override
+ {
+ this->Data = "";
+ }
+ void EndElement(const std::string& name) override
+ {
+ if (name == "key") {
+ this->Key = this->Data;
+ } else if (name == "string") {
+ if (this->Key == "CFBundleShortVersionString") {
+ this->Version = this->Data;
+ }
+ }
+ }
+ void CharacterDataHandler(const char* data, int length) override
+ {
+ this->Data.append(data, length);
+ }
+ std::string Version;
+ std::string Key;
+ std::string Data;
+};
+#endif
+
+// Builds either an object list or a space-separated string from the
+// given inputs.
+class cmGlobalXCodeGenerator::BuildObjectListOrString
+{
+ cmGlobalXCodeGenerator* Generator;
+ cmXCodeObject* Group;
+ bool Empty;
+ std::string String;
+
+public:
+ BuildObjectListOrString(cmGlobalXCodeGenerator* gen, bool buildObjectList)
+ : Generator(gen)
+ , Group(nullptr)
+ , Empty(true)
+ {
+ if (buildObjectList) {
+ this->Group = this->Generator->CreateObject(cmXCodeObject::OBJECT_LIST);
+ }
+ }
+
+ bool IsEmpty() const { return this->Empty; }
+
+ void Add(const std::string& newString)
+ {
+ this->Empty = false;
+
+ if (this->Group) {
+ this->Group->AddObject(this->Generator->CreateString(newString));
+ } else {
+ this->String += newString;
+ this->String += ' ';
+ }
+ }
+
+ const std::string& GetString() const { return this->String; }
+
+ cmXCodeObject* CreateList()
+ {
+ if (this->Group) {
+ return this->Group;
+ }
+ return this->Generator->CreateString(this->String);
+ }
+};
+
+class cmGlobalXCodeGenerator::Factory : public cmGlobalGeneratorFactory
+{
+public:
+ std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+ const std::string& name, bool allowArch, cmake* cm) const override;
+
+ void GetDocumentation(cmDocumentationEntry& entry) const override
+ {
+ cmGlobalXCodeGenerator::GetDocumentation(entry);
+ }
+
+ std::vector<std::string> GetGeneratorNames() const override
+ {
+ std::vector<std::string> names;
+ names.push_back(cmGlobalXCodeGenerator::GetActualName());
+ return names;
+ }
+
+ std::vector<std::string> GetGeneratorNamesWithPlatform() const override
+ {
+ return std::vector<std::string>();
+ }
+
+ bool SupportsToolset() const override { return true; }
+ bool SupportsPlatform() const override { return false; }
+
+ std::vector<std::string> GetKnownPlatforms() const override
+ {
+ return std::vector<std::string>();
+ }
+
+ std::string GetDefaultPlatformName() const override { return std::string(); }
+};
+
+cmGlobalXCodeGenerator::cmGlobalXCodeGenerator(
+ cmake* cm, std::string const& version_string, unsigned int version_number)
+ : cmGlobalGenerator(cm)
+{
+ this->VersionString = version_string;
+ this->XcodeVersion = version_number;
+ if (this->XcodeVersion >= 120) {
+ this->XcodeBuildSystem = BuildSystem::Twelve;
+ } else {
+ this->XcodeBuildSystem = BuildSystem::One;
+ }
+
+ this->RootObject = nullptr;
+ this->MainGroupChildren = nullptr;
+ this->FrameworkGroup = nullptr;
+ this->CurrentMakefile = nullptr;
+ this->CurrentLocalGenerator = nullptr;
+ this->XcodeBuildCommandInitialized = false;
+
+ this->ObjectDirArchDefault = "$(CURRENT_ARCH)";
+ this->ObjectDirArch = this->ObjectDirArchDefault;
+
+ cm->GetState()->SetIsGeneratorMultiConfig(true);
+}
+
+std::unique_ptr<cmGlobalGeneratorFactory> cmGlobalXCodeGenerator::NewFactory()
+{
+ return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
+}
+
+std::unique_ptr<cmGlobalGenerator>
+cmGlobalXCodeGenerator::Factory::CreateGlobalGenerator(const std::string& name,
+ bool /*allowArch*/,
+ cmake* cm) const
+{
+ if (name != GetActualName()) {
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+#if !defined(CMAKE_BOOTSTRAP)
+ cmXcodeVersionParser parser;
+ std::string versionFile;
+ {
+ std::string out;
+ bool commandResult = cmSystemTools::RunSingleCommand(
+ "xcode-select --print-path", &out, nullptr, nullptr, nullptr,
+ cmSystemTools::OUTPUT_NONE);
+ if (commandResult) {
+ std::string::size_type pos = out.find(".app/");
+ if (pos != std::string::npos) {
+ versionFile = out.substr(0, pos + 5) + "Contents/version.plist";
+ }
+ }
+ }
+ if (!versionFile.empty() && cmSystemTools::FileExists(versionFile)) {
+ parser.ParseFile(versionFile.c_str());
+ } else if (cmSystemTools::FileExists(
+ "/Applications/Xcode.app/Contents/version.plist")) {
+ parser.ParseFile("/Applications/Xcode.app/Contents/version.plist");
+ } else {
+ parser.ParseFile(
+ "/Developer/Applications/Xcode.app/Contents/version.plist");
+ }
+ std::string const& version_string = parser.Version;
+
+ // Compute an integer form of the version number.
+ unsigned int v[2] = { 0, 0 };
+ sscanf(version_string.c_str(), "%u.%u", &v[0], &v[1]);
+ unsigned int version_number = 10 * v[0] + v[1];
+
+ if (version_number < 50) {
+ cm->IssueMessage(MessageType::FATAL_ERROR,
+ "Xcode " + version_string + " not supported.");
+ return std::unique_ptr<cmGlobalGenerator>();
+ }
+
+ return std::unique_ptr<cmGlobalGenerator>(
+ cm::make_unique<cmGlobalXCodeGenerator>(cm, version_string,
+ version_number));
+#else
+ std::cerr << "CMake should be built with cmake to use Xcode, "
+ "default to Xcode 1.5\n";
+ return std::unique_ptr<cmGlobalGenerator>(
+ cm::make_unique<cmGlobalXCodeGenerator>(cm));
+#endif
+}
+
+bool cmGlobalXCodeGenerator::FindMakeProgram(cmMakefile* mf)
+{
+ // The Xcode generator knows how to lookup its build tool
+ // directly instead of needing a helper module to do it, so we
+ // do not actually need to put CMAKE_MAKE_PROGRAM into the cache.
+ if (cmIsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
+ mf->AddDefinition("CMAKE_MAKE_PROGRAM", this->GetXcodeBuildCommand());
+ }
+ return true;
+}
+
+std::string const& cmGlobalXCodeGenerator::GetXcodeBuildCommand()
+{
+ if (!this->XcodeBuildCommandInitialized) {
+ this->XcodeBuildCommandInitialized = true;
+ this->XcodeBuildCommand = this->FindXcodeBuildCommand();
+ }
+ return this->XcodeBuildCommand;
+}
+
+std::string cmGlobalXCodeGenerator::FindXcodeBuildCommand()
+{
+ std::string makeProgram = cmSystemTools::FindProgram("xcodebuild");
+ if (makeProgram.empty()) {
+ makeProgram = "xcodebuild";
+ }
+ return makeProgram;
+}
+
+bool cmGlobalXCodeGenerator::SetSystemName(std::string const& s,
+ cmMakefile* mf)
+{
+ this->SystemName = s;
+ return this->cmGlobalGenerator::SetSystemName(s, mf);
+}
+
+namespace {
+cm::string_view cmXcodeBuildSystemString(cmGlobalXCodeGenerator::BuildSystem b)
+{
+ switch (b) {
+ case cmGlobalXCodeGenerator::BuildSystem::One:
+ return "1"_s;
+ case cmGlobalXCodeGenerator::BuildSystem::Twelve:
+ return "12"_s;
+ }
+ return {};
+}
+}
+
+bool cmGlobalXCodeGenerator::SetGeneratorToolset(std::string const& ts,
+ bool build, cmMakefile* mf)
+{
+ if (!this->ParseGeneratorToolset(ts, mf)) {
+ return false;
+ }
+ if (build) {
+ return true;
+ }
+ if (!this->GeneratorToolset.empty()) {
+ mf->AddDefinition("CMAKE_XCODE_PLATFORM_TOOLSET", this->GeneratorToolset);
+ }
+ mf->AddDefinition("CMAKE_XCODE_BUILD_SYSTEM",
+ cmXcodeBuildSystemString(this->XcodeBuildSystem));
+ return true;
+}
+
+bool cmGlobalXCodeGenerator::ParseGeneratorToolset(std::string const& ts,
+ cmMakefile* mf)
+{
+ std::vector<std::string> const fields = cmTokenize(ts, ",");
+ auto fi = fields.cbegin();
+ if (fi == fields.cend()) {
+ return true;
+ }
+
+ // The first field may be the Xcode GCC_VERSION.
+ if (fi->find('=') == fi->npos) {
+ this->GeneratorToolset = *fi;
+ ++fi;
+ }
+
+ std::unordered_set<std::string> handled;
+
+ // The rest of the fields must be key=value pairs.
+ for (; fi != fields.cend(); ++fi) {
+ std::string::size_type pos = fi->find('=');
+ if (pos == fi->npos) {
+ /* clang-format off */
+ std::string const& e = cmStrCat(
+ "Generator\n"
+ " ", this->GetName(), "\n"
+ "given toolset specification\n"
+ " ", ts, "\n"
+ "that contains a field after the first ',' with no '='."
+ );
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e);
+ return false;
+ }
+ std::string const key = fi->substr(0, pos);
+ std::string const value = fi->substr(pos + 1);
+ if (!handled.insert(key).second) {
+ /* clang-format off */
+ std::string const& e = cmStrCat(
+ "Generator\n"
+ " ", this->GetName(), "\n"
+ "given toolset specification\n"
+ " ", ts, "\n"
+ "that contains duplicate field key '", key, "'."
+ );
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e);
+ return false;
+ }
+ if (!this->ProcessGeneratorToolsetField(key, value, mf)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool cmGlobalXCodeGenerator::ProcessGeneratorToolsetField(
+ std::string const& key, std::string const& value, cmMakefile* mf)
+{
+ if (key == "buildsystem") {
+ if (value == "1"_s) {
+ this->XcodeBuildSystem = BuildSystem::One;
+ } else if (value == "12"_s) {
+ this->XcodeBuildSystem = BuildSystem::Twelve;
+ } else {
+ /* clang-format off */
+ std::string const& e = cmStrCat(
+ "Generator\n"
+ " ", this->GetName(), "\n"
+ "toolset specification field\n"
+ " buildsystem=", value, "\n"
+ "value is unkonwn. It must be '1' or '12'."
+ );
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e);
+ return false;
+ }
+ if (this->XcodeBuildSystem == BuildSystem::Twelve &&
+ this->XcodeVersion < 120) {
+ /* clang-format off */
+ std::string const& e = cmStrCat(
+ "Generator\n"
+ " ", this->GetName(), "\n"
+ "toolset specification field\n"
+ " buildsystem=", value, "\n"
+ "is not allowed with Xcode ", this->VersionString, '.'
+ );
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e);
+ return false;
+ }
+ return true;
+ }
+ /* clang-format off */
+ std::string const& e = cmStrCat(
+ "Generator\n"
+ " ", this->GetName(), "\n"
+ "given toolset specification that contains invalid field '", key, "'."
+ );
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e);
+ return false;
+}
+
+void cmGlobalXCodeGenerator::EnableLanguage(
+ std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
+{
+ mf->AddDefinition("XCODE", "1");
+ mf->AddDefinition("XCODE_VERSION", this->VersionString);
+ if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
+ mf->AddCacheDefinition(
+ "CMAKE_CONFIGURATION_TYPES", "Debug;Release;MinSizeRel;RelWithDebInfo",
+ "Semicolon separated list of supported configuration types, "
+ "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
+ "anything else will be ignored.",
+ cmStateEnums::STRING);
+ }
+ mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
+ this->cmGlobalGenerator::EnableLanguage(lang, mf, optional);
+ this->ComputeArchitectures(mf);
+}
+
+bool cmGlobalXCodeGenerator::Open(const std::string& bindir,
+ const std::string& projectName, bool dryRun)
+{
+ bool ret = false;
+
+#ifdef HAVE_APPLICATION_SERVICES
+ std::string url = bindir + "/" + projectName + ".xcodeproj";
+
+ if (dryRun) {
+ return cmSystemTools::FileExists(url, false);
+ }
+
+ CFStringRef cfStr = CFStringCreateWithCString(
+ kCFAllocatorDefault, url.c_str(), kCFStringEncodingUTF8);
+ if (cfStr) {
+ CFURLRef cfUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfStr,
+ kCFURLPOSIXPathStyle, true);
+ if (cfUrl) {
+ OSStatus err = LSOpenCFURLRef(cfUrl, nullptr);
+ ret = err == noErr;
+ CFRelease(cfUrl);
+ }
+ CFRelease(cfStr);
+ }
+#endif
+
+ return ret;
+}
+
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalXCodeGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& /*projectDir*/,
+ std::vector<std::string> const& targetNames, const std::string& config,
+ bool /*fast*/, int jobs, bool /*verbose*/,
+ std::vector<std::string> const& makeOptions)
+{
+ GeneratedMakeCommand makeCommand;
+ // now build the test
+ makeCommand.Add(
+ this->SelectMakeProgram(makeProgram, this->GetXcodeBuildCommand()));
+
+ if (!projectName.empty()) {
+ makeCommand.Add("-project");
+ std::string projectArg = cmStrCat(projectName, ".xcodeproj");
+ makeCommand.Add(projectArg);
+ }
+ if (cm::contains(targetNames, "clean")) {
+ makeCommand.Add("clean");
+ makeCommand.Add("-target", "ALL_BUILD");
+ } else {
+ makeCommand.Add("build");
+ if (targetNames.empty() ||
+ ((targetNames.size() == 1) && targetNames.front().empty())) {
+ makeCommand.Add("-target", "ALL_BUILD");
+ } else {
+ for (const auto& tname : targetNames) {
+ if (!tname.empty()) {
+ makeCommand.Add("-target", tname);
+ }
+ }
+ }
+ }
+
+ if ((this->XcodeBuildSystem >= BuildSystem::Twelve) ||
+ (jobs != cmake::NO_BUILD_PARALLEL_LEVEL)) {
+ makeCommand.Add("-parallelizeTargets");
+ }
+ makeCommand.Add("-configuration", (config.empty() ? "Debug" : config));
+
+ if ((jobs != cmake::NO_BUILD_PARALLEL_LEVEL) &&
+ (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL)) {
+ makeCommand.Add("-jobs", std::to_string(jobs));
+ }
+
+ if (this->XcodeVersion >= 70) {
+ makeCommand.Add("-hideShellScriptEnvironment");
+ }
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ return { std::move(makeCommand) };
+}
+
+//! Create a local generator appropriate to this Global Generator
+std::unique_ptr<cmLocalGenerator> cmGlobalXCodeGenerator::CreateLocalGenerator(
+ cmMakefile* mf)
+{
+ std::unique_ptr<cmLocalGenerator> lg(
+ cm::make_unique<cmLocalXCodeGenerator>(this, mf));
+ if (this->XcodeBuildSystem >= BuildSystem::Twelve) {
+ // For this build system variant we generate custom commands as
+ // shell scripts directly rather than inside Makefiles.
+ // FIXME: Rename or refactor this option for clarity.
+ lg->SetLinkScriptShell(true);
+ }
+ return lg;
+}
+
+void cmGlobalXCodeGenerator::AddExtraIDETargets()
+{
+ // make sure extra targets are added before calling
+ // the parent generate which will call trace depends
+ for (auto keyVal : this->ProjectMap) {
+ cmLocalGenerator* root = keyVal.second[0];
+ this->SetGenerationRoot(root);
+ // add ALL_BUILD, INSTALL, etc
+ this->AddExtraTargets(root, keyVal.second);
+ }
+}
+
+void cmGlobalXCodeGenerator::Generate()
+{
+ this->cmGlobalGenerator::Generate();
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return;
+ }
+
+ for (auto keyVal : this->ProjectMap) {
+ cmLocalGenerator* root = keyVal.second[0];
+
+ bool generateTopLevelProjectOnly =
+ root->GetMakefile()->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY");
+
+ if (generateTopLevelProjectOnly) {
+ cmStateSnapshot snp = root->GetStateSnapshot();
+ if (snp.GetBuildsystemDirectoryParent().IsValid()) {
+ continue;
+ }
+ }
+
+ // cache the enabled languages for source file type queries
+ this->GetEnabledLanguages(this->EnabledLangs);
+
+ this->SetGenerationRoot(root);
+ // now create the project
+ this->OutputXCodeProject(root, keyVal.second);
+ }
+}
+
+void cmGlobalXCodeGenerator::SetGenerationRoot(cmLocalGenerator* root)
+{
+ this->CurrentProject = root->GetProjectName();
+ this->SetCurrentLocalGenerator(root);
+ cmSystemTools::SplitPath(
+ this->CurrentLocalGenerator->GetCurrentSourceDirectory(),
+ this->ProjectSourceDirectoryComponents);
+ cmSystemTools::SplitPath(
+ this->CurrentLocalGenerator->GetCurrentBinaryDirectory(),
+ this->ProjectOutputDirectoryComponents);
+
+ this->CurrentXCodeHackMakefile =
+ cmStrCat(root->GetCurrentBinaryDirectory(), "/CMakeScripts");
+ cmSystemTools::MakeDirectory(this->CurrentXCodeHackMakefile);
+ this->CurrentXCodeHackMakefile += "/XCODE_DEPEND_HELPER.make";
+}
+
+std::string cmGlobalXCodeGenerator::PostBuildMakeTarget(
+ std::string const& tName, std::string const& configName)
+{
+ std::string target = tName;
+ std::replace(target.begin(), target.end(), ' ', '_');
+ std::string out = cmStrCat("PostBuild.", target, '.', configName);
+ return out;
+}
+
+#define CMAKE_CHECK_BUILD_SYSTEM_TARGET "ZERO_CHECK"
+#define OBJECT_LIBRARY_ARTIFACT_DIR std::string()
+
+void cmGlobalXCodeGenerator::AddExtraTargets(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& gens)
+{
+ const char* no_working_directory = nullptr;
+ std::vector<std::string> no_byproducts;
+ std::vector<std::string> no_depends;
+
+ // Add ALL_BUILD
+ cmTarget* allbuild = root->AddUtilityCommand(
+ "ALL_BUILD", true, no_working_directory, no_byproducts, no_depends,
+ cmMakeSingleCommandLine({ "echo", "Build all projects" }),
+ cmPolicies::NEW);
+
+ root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(allbuild, root));
+
+ // Add XCODE depend helper
+ std::string legacyDependHelperDir = root->GetCurrentBinaryDirectory();
+ cmCustomCommandLines legacyDependHelperCommandLines;
+ if (this->XcodeBuildSystem == BuildSystem::One) {
+ legacyDependHelperCommandLines = cmMakeSingleCommandLine(
+ { "make", "-C", legacyDependHelperDir, "-f",
+ this->CurrentXCodeHackMakefile, "OBJDIR=$(OBJDIR)",
+ /* placeholder, see below */ "" });
+ }
+
+ // Add ZERO_CHECK
+ bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
+ bool generateTopLevelProjectOnly =
+ root->GetMakefile()->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY");
+ bool isTopLevel =
+ !root->GetStateSnapshot().GetBuildsystemDirectoryParent().IsValid();
+ bool isGenerateProject = isTopLevel || !generateTopLevelProjectOnly;
+ if (regenerate && isGenerateProject) {
+ this->CreateReRunCMakeFile(root, gens);
+ std::string file =
+ this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile);
+ cmSystemTools::ReplaceString(file, "\\ ", " ");
+ cmTarget* check = root->AddUtilityCommand(
+ CMAKE_CHECK_BUILD_SYSTEM_TARGET, true, no_working_directory,
+ no_byproducts, no_depends,
+ cmMakeSingleCommandLine({ "make", "-f", file }), cmPolicies::NEW);
+
+ root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(check, root));
+ }
+
+ // now make the allbuild depend on all the non-utility targets
+ // in the project
+ for (auto& gen : gens) {
+ for (const auto& target : gen->GetGeneratorTargets()) {
+ if (target->GetType() == cmStateEnums::GLOBAL_TARGET) {
+ continue;
+ }
+
+ if (regenerate &&
+ (target->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET)) {
+ target->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false);
+ }
+
+ // make all exe, shared libs and modules
+ // run the depend check makefile as a post build rule
+ // this will make sure that when the next target is built
+ // things are up-to-date
+ if (this->XcodeBuildSystem == BuildSystem::One && isGenerateProject &&
+ target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ legacyDependHelperCommandLines.front().back() = // fill placeholder
+ this->PostBuildMakeTarget(target->GetName(), "$(CONFIGURATION)");
+ gen->AddCustomCommandToTarget(
+ target->GetName(), no_byproducts, no_depends,
+ legacyDependHelperCommandLines, cmCustomCommandType::POST_BUILD,
+ "Depend check for xcode", legacyDependHelperDir.c_str(),
+ cmPolicies::NEW, true, false, "", "", false,
+ cmObjectLibraryCommands::Accept);
+ }
+
+ if (!this->IsExcluded(gens[0], target.get())) {
+ allbuild->AddUtility(target->GetName(), false);
+ }
+ }
+ }
+}
+
+void cmGlobalXCodeGenerator::CreateReRunCMakeFile(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*> const& gens)
+{
+ std::vector<std::string> lfiles;
+ for (auto gen : gens) {
+ cm::append(lfiles, gen->GetMakefile()->GetListFiles());
+ }
+
+ // sort the array
+ std::sort(lfiles.begin(), lfiles.end());
+ lfiles.erase(std::unique(lfiles.begin(), lfiles.end()), lfiles.end());
+
+ cmake* cm = this->GetCMakeInstance();
+ if (cm->DoWriteGlobVerifyTarget()) {
+ lfiles.emplace_back(cm->GetGlobVerifyStamp());
+ }
+
+ this->CurrentReRunCMakeMakefile =
+ cmStrCat(root->GetCurrentBinaryDirectory(), "/CMakeScripts");
+ cmSystemTools::MakeDirectory(this->CurrentReRunCMakeMakefile);
+ this->CurrentReRunCMakeMakefile += "/ReRunCMake.make";
+ cmGeneratedFileStream makefileStream(this->CurrentReRunCMakeMakefile);
+ makefileStream.SetCopyIfDifferent(true);
+ makefileStream << "# Generated by CMake, DO NOT EDIT\n\n";
+
+ makefileStream << "TARGETS:= \n";
+ makefileStream << "empty:= \n";
+ makefileStream << "space:= $(empty) $(empty)\n";
+ makefileStream << "spaceplus:= $(empty)\\ $(empty)\n\n";
+
+ for (const auto& lfile : lfiles) {
+ makefileStream << "TARGETS += $(subst $(space),$(spaceplus),$(wildcard "
+ << this->ConvertToRelativeForMake(lfile) << "))\n";
+ }
+ makefileStream << "\n";
+
+ std::string checkCache =
+ cmStrCat(root->GetBinaryDirectory(), "/CMakeFiles/cmake.check_cache");
+
+ if (cm->DoWriteGlobVerifyTarget()) {
+ makefileStream << ".NOTPARALLEL:\n\n";
+ makefileStream << ".PHONY: all VERIFY_GLOBS\n\n";
+ makefileStream << "all: VERIFY_GLOBS "
+ << this->ConvertToRelativeForMake(checkCache) << "\n\n";
+ makefileStream << "VERIFY_GLOBS:\n";
+ makefileStream << "\t"
+ << this->ConvertToRelativeForMake(
+ cmSystemTools::GetCMakeCommand())
+ << " -P "
+ << this->ConvertToRelativeForMake(cm->GetGlobVerifyScript())
+ << "\n\n";
+ }
+
+ makefileStream << this->ConvertToRelativeForMake(checkCache)
+ << ": $(TARGETS)\n";
+ makefileStream << "\t"
+ << this->ConvertToRelativeForMake(
+ cmSystemTools::GetCMakeCommand())
+ << " -H"
+ << this->ConvertToRelativeForMake(root->GetSourceDirectory())
+ << " -B"
+ << this->ConvertToRelativeForMake(root->GetBinaryDirectory())
+ << "\n";
+}
+
+static bool objectIdLessThan(const std::unique_ptr<cmXCodeObject>& l,
+ const std::unique_ptr<cmXCodeObject>& r)
+{
+ return l->GetId() < r->GetId();
+}
+
+void cmGlobalXCodeGenerator::SortXCodeObjects()
+{
+ std::sort(this->XCodeObjects.begin(), this->XCodeObjects.end(),
+ objectIdLessThan);
+}
+
+void cmGlobalXCodeGenerator::ClearXCodeObjects()
+{
+ this->TargetDoneSet.clear();
+ this->XCodeObjects.clear();
+ this->XCodeObjectIDs.clear();
+ this->XCodeObjectMap.clear();
+ this->GroupMap.clear();
+ this->GroupNameMap.clear();
+ this->TargetGroup.clear();
+ this->FileRefs.clear();
+ this->ExternalLibRefs.clear();
+ this->EmbeddedLibRefs.clear();
+ this->FileRefToBuildFileMap.clear();
+ this->FileRefToEmbedBuildFileMap.clear();
+ this->CommandsVisited.clear();
+}
+
+void cmGlobalXCodeGenerator::addObject(std::unique_ptr<cmXCodeObject> obj)
+{
+ if (obj->GetType() == cmXCodeObject::OBJECT) {
+ const std::string& id = obj->GetId();
+
+ // If this is a duplicate id, it's an error:
+ //
+ if (this->XCodeObjectIDs.count(id)) {
+ cmSystemTools::Error(
+ "Xcode generator: duplicate object ids not allowed");
+ }
+
+ this->XCodeObjectIDs.insert(id);
+ }
+
+ this->XCodeObjects.push_back(std::move(obj));
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateObject(
+ cmXCodeObject::PBXType ptype, cm::string_view key)
+{
+ auto obj = cm::make_unique<cmXCode21Object>(ptype, cmXCodeObject::OBJECT,
+ this->GetObjectId(ptype, key));
+ auto ptr = obj.get();
+ this->addObject(std::move(obj));
+ return ptr;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::Type type)
+{
+ auto obj = cm::make_unique<cmXCodeObject>(
+ cmXCodeObject::None, type,
+ "Temporary cmake object, should not be referred to in Xcode file");
+ auto ptr = obj.get();
+ this->addObject(std::move(obj));
+ return ptr;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateString(const std::string& s)
+{
+ cmXCodeObject* obj = this->CreateObject(cmXCodeObject::STRING);
+ obj->SetString(s);
+ return obj;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateObjectReference(
+ cmXCodeObject* ref)
+{
+ cmXCodeObject* obj = this->CreateObject(cmXCodeObject::OBJECT_REF);
+ obj->SetObject(ref);
+ return obj;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateFlatClone(cmXCodeObject* orig)
+{
+ cmXCodeObject* obj = this->CreateObject(orig->GetType());
+ obj->CopyAttributes(orig);
+ return obj;
+}
+
+std::string GetGroupMapKeyFromPath(cmGeneratorTarget* target,
+ const std::string& fullpath)
+{
+ std::string key(target->GetName());
+ key += "-";
+ key += fullpath;
+ return key;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeBuildFileFromPath(
+ const std::string& fullpath, cmGeneratorTarget* target,
+ const std::string& lang, cmSourceFile* sf)
+{
+ // Using a map and the full path guarantees that we will always get the same
+ // fileRef object for any given full path. Same goes for the buildFile
+ // object.
+ cmXCodeObject* fileRef =
+ this->CreateXCodeFileReferenceFromPath(fullpath, target, lang, sf);
+ if (fileRef) {
+ auto it = this->FileRefToBuildFileMap.find(fileRef);
+ if (it == this->FileRefToBuildFileMap.end()) {
+ cmXCodeObject* buildFile =
+ this->CreateObject(cmXCodeObject::PBXBuildFile);
+ buildFile->SetComment(fileRef->GetComment());
+ buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
+ this->FileRefToBuildFileMap[fileRef] = buildFile;
+ return buildFile;
+ }
+ return it->second;
+ }
+ return nullptr;
+}
+
+class XCodeGeneratorExpressionInterpreter
+ : public cmGeneratorExpressionInterpreter
+{
+public:
+ XCodeGeneratorExpressionInterpreter(cmSourceFile* sourceFile,
+ cmLocalGenerator* localGenerator,
+ cmGeneratorTarget* headTarget,
+ const std::string& lang)
+ : cmGeneratorExpressionInterpreter(
+ localGenerator, "NO-PER-CONFIG-SUPPORT-IN-XCODE", headTarget, lang)
+ , SourceFile(sourceFile)
+ {
+ }
+
+ XCodeGeneratorExpressionInterpreter(
+ XCodeGeneratorExpressionInterpreter const&) = delete;
+ XCodeGeneratorExpressionInterpreter& operator=(
+ XCodeGeneratorExpressionInterpreter const&) = delete;
+
+ const std::string& Evaluate(const char* expression,
+ const std::string& property)
+ {
+ return this->Evaluate(std::string(expression ? expression : ""), property);
+ }
+
+ const std::string& Evaluate(const std::string& expression,
+ const std::string& property)
+ {
+ const std::string& processed =
+ this->cmGeneratorExpressionInterpreter::Evaluate(expression, property);
+ if (this->CompiledGeneratorExpression->GetHadContextSensitiveCondition()) {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Xcode does not support per-config per-source " << property << ":\n"
+ " " << expression << "\n"
+ "specified for source:\n"
+ " " << this->SourceFile->ResolveFullPath() << "\n";
+ /* clang-format on */
+ this->LocalGenerator->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ }
+
+ return processed;
+ }
+
+private:
+ cmSourceFile* SourceFile = nullptr;
+};
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
+ cmLocalGenerator* lg, cmSourceFile* sf, cmGeneratorTarget* gtgt)
+{
+ std::string lang = this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
+
+ XCodeGeneratorExpressionInterpreter genexInterpreter(sf, lg, gtgt, lang);
+
+ // Add flags from target and source file properties.
+ std::string flags;
+ std::string const& srcfmt = sf->GetSafeProperty("Fortran_FORMAT");
+ switch (cmOutputConverter::GetFortranFormat(srcfmt)) {
+ case cmOutputConverter::FortranFormatFixed:
+ flags = "-fixed " + flags;
+ break;
+ case cmOutputConverter::FortranFormatFree:
+ flags = "-free " + flags;
+ break;
+ default:
+ break;
+ }
+
+ // Explicitly add the explicit language flag before any other flag
+ // so user flags can override it.
+ gtgt->AddExplicitLanguageFlags(flags, *sf);
+
+ const std::string COMPILE_FLAGS("COMPILE_FLAGS");
+ if (cmProp cflags = sf->GetProperty(COMPILE_FLAGS)) {
+ lg->AppendFlags(flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));
+ }
+ const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
+ if (cmProp coptions = sf->GetProperty(COMPILE_OPTIONS)) {
+ lg->AppendCompileOptions(
+ flags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
+ }
+
+ // Add per-source definitions.
+ BuildObjectListOrString flagsBuild(this, false);
+ const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
+ if (cmProp compile_defs = sf->GetProperty(COMPILE_DEFINITIONS)) {
+ this->AppendDefines(
+ flagsBuild,
+ genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS).c_str(),
+ true);
+ }
+
+ if (sf->GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS")) {
+ this->AppendDefines(flagsBuild, "CMAKE_SKIP_PRECOMPILE_HEADERS", true);
+ }
+
+ if (!flagsBuild.IsEmpty()) {
+ if (!flags.empty()) {
+ flags += ' ';
+ }
+ flags += flagsBuild.GetString();
+ }
+
+ // Add per-source include directories.
+ std::vector<std::string> includes;
+ const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
+ if (cmProp cincludes = sf->GetProperty(INCLUDE_DIRECTORIES)) {
+ lg->AppendIncludeDirectories(
+ includes, genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES),
+ *sf);
+ }
+ lg->AppendFlags(flags,
+ lg->GetIncludeFlags(includes, gtgt, lang, std::string()));
+
+ cmXCodeObject* buildFile =
+ this->CreateXCodeBuildFileFromPath(sf->ResolveFullPath(), gtgt, lang, sf);
+
+ cmXCodeObject* settings = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ settings->AddAttributeIfNotEmpty("COMPILER_FLAGS",
+ this->CreateString(flags));
+
+ cmGeneratorTarget::SourceFileFlags tsFlags =
+ gtgt->GetTargetSourceFileFlags(sf);
+
+ cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+
+ // Is this a "private" or "public" framework header file?
+ // Set the ATTRIBUTES attribute appropriately...
+ //
+ if (gtgt->IsFrameworkOnApple()) {
+ if (tsFlags.Type == cmGeneratorTarget::SourceFileTypePrivateHeader) {
+ attrs->AddObject(this->CreateString("Private"));
+ } else if (tsFlags.Type == cmGeneratorTarget::SourceFileTypePublicHeader) {
+ attrs->AddObject(this->CreateString("Public"));
+ }
+ }
+
+ // Add user-specified file attributes.
+ cmProp extraFileAttributes = sf->GetProperty("XCODE_FILE_ATTRIBUTES");
+ if (extraFileAttributes) {
+ // Expand the list of attributes.
+ std::vector<std::string> attributes = cmExpandedList(*extraFileAttributes);
+
+ // Store the attributes.
+ for (const auto& attribute : attributes) {
+ attrs->AddObject(this->CreateString(attribute));
+ }
+ }
+
+ settings->AddAttributeIfNotEmpty("ATTRIBUTES", attrs);
+
+ if (buildFile) {
+ buildFile->AddAttributeIfNotEmpty("settings", settings);
+ }
+ return buildFile;
+}
+
+void cmGlobalXCodeGenerator::AddXCodeProjBuildRule(
+ cmGeneratorTarget* target, std::vector<cmSourceFile*>& sources) const
+{
+ std::string listfile =
+ cmStrCat(target->GetLocalGenerator()->GetCurrentSourceDirectory(),
+ "/CMakeLists.txt");
+ cmSourceFile* srcCMakeLists = target->Makefile->GetOrCreateSource(
+ listfile, false, cmSourceFileLocationKind::Known);
+ if (!cm::contains(sources, srcCMakeLists)) {
+ sources.push_back(srcCMakeLists);
+ }
+}
+
+namespace {
+
+bool IsLinkPhaseLibraryExtension(const std::string& fileExt)
+{
+ // Empty file extension is a special case for paths to framework's
+ // internal binary which could be MyFw.framework/Versions/*/MyFw
+ return (fileExt == ".framework" || fileExt == ".a" || fileExt == ".o" ||
+ fileExt == ".dylib" || fileExt == ".tbd" || fileExt.empty());
+}
+bool IsLibraryType(const std::string& fileType)
+{
+ return (fileType == "wrapper.framework" || fileType == "archive.ar" ||
+ fileType == "compiled.mach-o.objfile" ||
+ fileType == "compiled.mach-o.dylib" ||
+ fileType == "compiled.mach-o.executable" ||
+ fileType == "sourcecode.text-based-dylib-definition");
+}
+
+std::string GetDirectoryValueFromFileExtension(const std::string& dirExt)
+{
+ std::string ext = cmSystemTools::LowerCase(dirExt);
+ if (ext == "framework") {
+ return "wrapper.framework";
+ }
+ if (ext == "xcassets") {
+ return "folder.assetcatalog";
+ }
+ return "folder";
+}
+
+std::string GetSourcecodeValueFromFileExtension(
+ const std::string& _ext, const std::string& lang,
+ bool& keepLastKnownFileType, const std::vector<std::string>& enabled_langs)
+{
+ std::string ext = cmSystemTools::LowerCase(_ext);
+ std::string sourcecode = "sourcecode";
+
+ if (ext == "o") {
+ keepLastKnownFileType = true;
+ sourcecode = "compiled.mach-o.objfile";
+ } else if (ext == "xctest") {
+ sourcecode = "wrapper.cfbundle";
+ } else if (ext == "xib") {
+ keepLastKnownFileType = true;
+ sourcecode = "file.xib";
+ } else if (ext == "storyboard") {
+ keepLastKnownFileType = true;
+ sourcecode = "file.storyboard";
+ } else if (ext == "mm" && !cm::contains(enabled_langs, "OBJCXX")) {
+ sourcecode += ".cpp.objcpp";
+ } else if (ext == "m" && !cm::contains(enabled_langs, "OBJC")) {
+ sourcecode += ".c.objc";
+ } else if (ext == "swift") {
+ sourcecode += ".swift";
+ } else if (ext == "plist") {
+ sourcecode += ".text.plist";
+ } else if (ext == "h") {
+ sourcecode += ".c.h";
+ } else if (ext == "hxx" || ext == "hpp" || ext == "txx" || ext == "pch" ||
+ ext == "hh") {
+ sourcecode += ".cpp.h";
+ } else if (ext == "png" || ext == "gif" || ext == "jpg") {
+ keepLastKnownFileType = true;
+ sourcecode = "image";
+ } else if (ext == "txt") {
+ sourcecode += ".text";
+ } else if (lang == "CXX") {
+ sourcecode += ".cpp.cpp";
+ } else if (lang == "C") {
+ sourcecode += ".c.c";
+ } else if (lang == "OBJCXX") {
+ sourcecode += ".cpp.objcpp";
+ } else if (lang == "OBJC") {
+ sourcecode += ".c.objc";
+ } else if (lang == "Fortran") {
+ sourcecode += ".fortran.f90";
+ } else if (lang == "ASM") {
+ sourcecode += ".asm";
+ } else if (ext == "metal") {
+ sourcecode += ".metal";
+ } else if (ext == "mig") {
+ sourcecode += ".mig";
+ } else if (ext == "tbd") {
+ sourcecode += ".text-based-dylib-definition";
+ } else if (ext == "a") {
+ keepLastKnownFileType = true;
+ sourcecode = "archive.ar";
+ } else if (ext == "dylib") {
+ keepLastKnownFileType = true;
+ sourcecode = "compiled.mach-o.dylib";
+ } else if (ext == "framework") {
+ keepLastKnownFileType = true;
+ sourcecode = "wrapper.framework";
+ } else if (ext == "xcassets") {
+ keepLastKnownFileType = true;
+ sourcecode = "folder.assetcatalog";
+ }
+ // else
+ // {
+ // // Already specialized above or we leave sourcecode == "sourcecode"
+ // // which is probably the most correct choice. Extensionless headers,
+ // // for example... Or file types unknown to Xcode that do not map to a
+ // // valid explicitFileType value.
+ // }
+
+ return sourcecode;
+}
+
+// If the file has no extension it's either a raw executable or might
+// be a direct reference to a binary within a framework (bad practice!).
+// This is where we change the path to point to the framework directory.
+// .tbd files also can be located in SDK frameworks (they are
+// placeholders for actual libraries shipped with the OS)
+std::string GetLibraryOrFrameworkPath(const std::string& path)
+{
+ auto ext = cmSystemTools::GetFilenameLastExtension(path);
+ if (ext.empty() || ext == ".tbd") {
+ auto name = cmSystemTools::GetFilenameWithoutExtension(path);
+ // Check for iOS framework structure:
+ // FwName.framework/FwName (and also on macOS where FwName lib is a
+ // symlink)
+ auto parentDir = cmSystemTools::GetParentDirectory(path);
+ auto parentName = cmSystemTools::GetFilenameWithoutExtension(parentDir);
+ ext = cmSystemTools::GetFilenameLastExtension(parentDir);
+ if (ext == ".framework" && name == parentName) {
+ return parentDir;
+ }
+ // Check for macOS framework structure:
+ // FwName.framework/Versions/*/FwName
+ std::vector<std::string> components;
+ cmSystemTools::SplitPath(path, components);
+ if (components.size() > 3 &&
+ components[components.size() - 3] == "Versions") {
+ ext = cmSystemTools::GetFilenameLastExtension(
+ components[components.size() - 4]);
+ parentName = cmSystemTools::GetFilenameWithoutExtension(
+ components[components.size() - 4]);
+ if (ext == ".framework" && name == parentName) {
+ components.erase(components.begin() + components.size() - 3,
+ components.end());
+ return cmSystemTools::JoinPath(components);
+ }
+ }
+ }
+ return path;
+}
+
+} // anonymous
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
+ const std::string& fullpath, cmGeneratorTarget* target,
+ const std::string& lang, cmSourceFile* sf)
+{
+ bool useLastKnownFileType = false;
+ std::string fileType;
+ if (sf) {
+ if (cmProp e = sf->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) {
+ fileType = *e;
+ } else if (cmProp l = sf->GetProperty("XCODE_LAST_KNOWN_FILE_TYPE")) {
+ useLastKnownFileType = true;
+ fileType = *l;
+ }
+ }
+ // Make a copy so that we can override it later
+ std::string path = cmSystemTools::CollapseFullPath(fullpath);
+ // Compute the extension without leading '.'.
+ std::string ext = cmSystemTools::GetFilenameLastExtension(path);
+ if (!ext.empty()) {
+ ext = ext.substr(1);
+ }
+ if (fileType.empty()) {
+ path = GetLibraryOrFrameworkPath(path);
+ ext = cmSystemTools::GetFilenameLastExtension(path);
+ if (!ext.empty()) {
+ ext = ext.substr(1);
+ }
+ // If fullpath references a directory, then we need to specify
+ // lastKnownFileType as folder in order for Xcode to be able to
+ // open the contents of the folder.
+ // (Xcode 4.6 does not like explicitFileType=folder).
+ if (cmSystemTools::FileIsDirectory(path)) {
+ fileType = GetDirectoryValueFromFileExtension(ext);
+ useLastKnownFileType = true;
+ } else {
+ if (ext.empty() && !sf) {
+ // Special case for executable or library without extension
+ // that is not a source file. We can't tell which without reading
+ // its Mach-O header, but the file might not exist yet, so we
+ // have to pick one here.
+ useLastKnownFileType = true;
+ fileType = "compiled.mach-o.executable";
+ } else {
+ fileType = GetSourcecodeValueFromFileExtension(
+ ext, lang, useLastKnownFileType, this->EnabledLangs);
+ }
+ }
+ }
+
+ std::string key = GetGroupMapKeyFromPath(target, path);
+ cmXCodeObject* fileRef = this->FileRefs[key];
+ if (!fileRef) {
+ fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
+ fileRef->SetComment(path);
+ this->FileRefs[key] = fileRef;
+ }
+ fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
+ fileRef->AddAttribute(useLastKnownFileType ? "lastKnownFileType"
+ : "explicitFileType",
+ this->CreateString(fileType));
+ // Store the file path relative to the top of the source tree.
+ if (!IsLibraryType(fileType)) {
+ path = this->RelativeToSource(path);
+ }
+ std::string name = cmSystemTools::GetFilenameName(path);
+ const char* sourceTree =
+ cmSystemTools::FileIsFullPath(path) ? "<absolute>" : "SOURCE_ROOT";
+ fileRef->AddAttribute("name", this->CreateString(name));
+ fileRef->AddAttribute("path", this->CreateString(path));
+ fileRef->AddAttribute("sourceTree", this->CreateString(sourceTree));
+
+ cmXCodeObject* group = this->GroupMap[key];
+ if (!group && IsLibraryType(fileType)) {
+ group = this->FrameworkGroup;
+ this->GroupMap[key] = group;
+ }
+ if (!group) {
+ cmSystemTools::Error("Could not find a PBX group for " + key);
+ return nullptr;
+ }
+ cmXCodeObject* children = group->GetAttribute("children");
+ if (!children->HasObject(fileRef)) {
+ children->AddObject(fileRef);
+ }
+ return fileRef;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReference(
+ cmSourceFile* sf, cmGeneratorTarget* target)
+{
+ std::string lang = this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
+
+ return this->CreateXCodeFileReferenceFromPath(sf->ResolveFullPath(), target,
+ lang, sf);
+}
+
+bool cmGlobalXCodeGenerator::SpecialTargetEmitted(std::string const& tname)
+{
+ if (tname == "ALL_BUILD" || tname == "install" || tname == "package" ||
+ tname == "RUN_TESTS" || tname == CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
+ if (this->TargetDoneSet.find(tname) != this->TargetDoneSet.end()) {
+ return true;
+ }
+ this->TargetDoneSet.insert(tname);
+ return false;
+ }
+ return false;
+}
+
+void cmGlobalXCodeGenerator::SetCurrentLocalGenerator(cmLocalGenerator* gen)
+{
+ this->CurrentLocalGenerator = gen;
+ this->CurrentMakefile = gen->GetMakefile();
+
+ // Select the current set of configuration types.
+ this->CurrentConfigurationTypes =
+ this->CurrentMakefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+}
+
+struct cmSourceFilePathCompare
+{
+ bool operator()(cmSourceFile* l, cmSourceFile* r)
+ {
+ return l->ResolveFullPath() < r->ResolveFullPath();
+ }
+};
+
+struct cmCompareTargets
+{
+ bool operator()(cmXCodeObject* l, cmXCodeObject* r) const
+ {
+ std::string const& a = l->GetTarget()->GetName();
+ std::string const& b = r->GetTarget()->GetName();
+ if (a == "ALL_BUILD") {
+ return true;
+ }
+ if (b == "ALL_BUILD") {
+ return false;
+ }
+ return a < b;
+ }
+};
+
+bool cmGlobalXCodeGenerator::CreateXCodeTargets(
+ cmLocalGenerator* gen, std::vector<cmXCodeObject*>& targets)
+{
+ this->SetCurrentLocalGenerator(gen);
+ std::vector<cmGeneratorTarget*> gts =
+ this->GetLocalGeneratorTargetsInOrder(gen);
+ for (auto gtgt : gts) {
+ if (!this->CreateXCodeTarget(gtgt, targets)) {
+ return false;
+ }
+ }
+ std::sort(targets.begin(), targets.end(), cmCompareTargets());
+ return true;
+}
+
+bool cmGlobalXCodeGenerator::CreateXCodeTarget(
+ cmGeneratorTarget* gtgt, std::vector<cmXCodeObject*>& targets)
+{
+ std::string targetName = gtgt->GetName();
+
+ // make sure ALL_BUILD, INSTALL, etc are only done once
+ if (this->SpecialTargetEmitted(targetName)) {
+ return true;
+ }
+
+ if (!gtgt->IsInBuildSystem()) {
+ return true;
+ }
+
+ auto& gtgt_visited = this->CommandsVisited[gtgt];
+ auto& deps = this->GetTargetDirectDepends(gtgt);
+ for (auto& d : deps) {
+ // Take the union of visited source files of custom commands so far.
+ // ComputeTargetOrder ensures our dependencies already visited their
+ // custom commands and updated CommandsVisited.
+ auto& dep_visited = this->CommandsVisited[d];
+ gtgt_visited.insert(dep_visited.begin(), dep_visited.end());
+ }
+
+ if (gtgt->GetType() == cmStateEnums::UTILITY ||
+ gtgt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ gtgt->GetType() == cmStateEnums::GLOBAL_TARGET) {
+ cmXCodeObject* t = this->CreateUtilityTarget(gtgt);
+ if (!t) {
+ return false;
+ }
+ targets.push_back(t);
+ return true;
+ }
+
+ // organize the sources
+ std::vector<cmSourceFile*> commonSourceFiles;
+ if (!gtgt->GetConfigCommonSourceFilesForXcode(commonSourceFiles)) {
+ return false;
+ }
+
+ // Add CMakeLists.txt file for user convenience.
+ this->AddXCodeProjBuildRule(gtgt, commonSourceFiles);
+
+ // Add the Info.plist we are about to generate for an App Bundle.
+ if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) {
+ std::string plist = this->ComputeInfoPListLocation(gtgt);
+ cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(
+ plist, true, cmSourceFileLocationKind::Known);
+ commonSourceFiles.push_back(sf);
+ }
+
+ std::sort(commonSourceFiles.begin(), commonSourceFiles.end(),
+ cmSourceFilePathCompare());
+
+ gtgt->ComputeObjectMapping();
+
+ std::vector<cmXCodeObject*> externalObjFiles;
+ std::vector<cmXCodeObject*> headerFiles;
+ std::vector<cmXCodeObject*> resourceFiles;
+ std::vector<cmXCodeObject*> sourceFiles;
+ for (auto sourceFile : commonSourceFiles) {
+ cmXCodeObject* xsf = this->CreateXCodeSourceFile(
+ this->CurrentLocalGenerator, sourceFile, gtgt);
+ cmXCodeObject* fr = xsf->GetAttribute("fileRef");
+ cmXCodeObject* filetype =
+ fr->GetObject()->GetAttribute("explicitFileType");
+ if (!filetype) {
+ filetype = fr->GetObject()->GetAttribute("lastKnownFileType");
+ }
+
+ cmGeneratorTarget::SourceFileFlags tsFlags =
+ gtgt->GetTargetSourceFileFlags(sourceFile);
+
+ if (filetype && filetype->GetString() == "compiled.mach-o.objfile") {
+ if (sourceFile->GetObjectLibrary().empty()) {
+ externalObjFiles.push_back(xsf);
+ }
+ } else if (this->IsHeaderFile(sourceFile) ||
+ (tsFlags.Type ==
+ cmGeneratorTarget::SourceFileTypePrivateHeader) ||
+ (tsFlags.Type ==
+ cmGeneratorTarget::SourceFileTypePublicHeader)) {
+ headerFiles.push_back(xsf);
+ } else if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeResource) {
+ resourceFiles.push_back(xsf);
+ } else if (!sourceFile->GetPropertyAsBool("HEADER_FILE_ONLY") &&
+ !gtgt->IsSourceFilePartOfUnityBatch(
+ sourceFile->ResolveFullPath())) {
+ // Include this file in the build if it has a known language
+ // and has not been listed as an ignored extension for this
+ // generator.
+ if (!this->CurrentLocalGenerator->GetSourceFileLanguage(*sourceFile)
+ .empty() &&
+ !this->IgnoreFile(sourceFile->GetExtension().c_str())) {
+ sourceFiles.push_back(xsf);
+ }
+ }
+ }
+
+ // some build phases only apply to bundles and/or frameworks
+ bool isFrameworkTarget = gtgt->IsFrameworkOnApple();
+ bool isBundleTarget = gtgt->GetPropertyAsBool("MACOSX_BUNDLE");
+ bool isCFBundleTarget = gtgt->IsCFBundleOnApple();
+
+ cmXCodeObject* buildFiles = nullptr;
+
+ // create source build phase
+ cmXCodeObject* sourceBuildPhase = nullptr;
+ if (!sourceFiles.empty()) {
+ sourceBuildPhase = this->CreateObject(cmXCodeObject::PBXSourcesBuildPhase);
+ sourceBuildPhase->SetComment("Sources");
+ sourceBuildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (auto& sourceFile : sourceFiles) {
+ buildFiles->AddObject(sourceFile);
+ }
+ sourceBuildPhase->AddAttribute("files", buildFiles);
+ sourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ }
+
+ // create header build phase - only for framework targets
+ cmXCodeObject* headerBuildPhase = nullptr;
+ if (!headerFiles.empty() && isFrameworkTarget) {
+ headerBuildPhase = this->CreateObject(cmXCodeObject::PBXHeadersBuildPhase);
+ headerBuildPhase->SetComment("Headers");
+ headerBuildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (auto& headerFile : headerFiles) {
+ buildFiles->AddObject(headerFile);
+ }
+ headerBuildPhase->AddAttribute("files", buildFiles);
+ headerBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ }
+
+ // create resource build phase - only for framework or bundle targets
+ cmXCodeObject* resourceBuildPhase = nullptr;
+ if (!resourceFiles.empty() &&
+ (isFrameworkTarget || isBundleTarget || isCFBundleTarget)) {
+ resourceBuildPhase =
+ this->CreateObject(cmXCodeObject::PBXResourcesBuildPhase);
+ resourceBuildPhase->SetComment("Resources");
+ resourceBuildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (auto& resourceFile : resourceFiles) {
+ buildFiles->AddObject(resourceFile);
+ }
+ resourceBuildPhase->AddAttribute("files", buildFiles);
+ resourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ }
+
+ // create vector of "non-resource content file" build phases - only for
+ // framework or bundle targets
+ std::vector<cmXCodeObject*> contentBuildPhases;
+ if (isFrameworkTarget || isBundleTarget || isCFBundleTarget) {
+ using mapOfVectorOfSourceFiles =
+ std::map<std::string, std::vector<cmSourceFile*>>;
+ mapOfVectorOfSourceFiles bundleFiles;
+ for (auto sourceFile : commonSourceFiles) {
+ cmGeneratorTarget::SourceFileFlags tsFlags =
+ gtgt->GetTargetSourceFileFlags(sourceFile);
+ if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeMacContent) {
+ bundleFiles[tsFlags.MacFolder].push_back(sourceFile);
+ }
+ }
+ for (auto const& keySources : bundleFiles) {
+ cmXCodeObject* copyFilesBuildPhase =
+ this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase);
+ copyFilesBuildPhase->SetComment("Copy files");
+ copyFilesBuildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ copyFilesBuildPhase->AddAttribute("dstSubfolderSpec",
+ this->CreateString("6"));
+ std::ostringstream ostr;
+ if (gtgt->IsFrameworkOnApple()) {
+ // dstPath in frameworks is relative to Versions/<version>
+ ostr << keySources.first;
+ } else if (keySources.first != "MacOS") {
+ if (gtgt->Target->GetMakefile()->PlatformIsAppleEmbedded()) {
+ ostr << keySources.first;
+ } else {
+ // dstPath in bundles is relative to Contents/MacOS
+ ostr << "../" << keySources.first;
+ }
+ }
+ copyFilesBuildPhase->AddAttribute("dstPath",
+ this->CreateString(ostr.str()));
+ copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ copyFilesBuildPhase->AddAttribute("files", buildFiles);
+ for (auto sourceFile : keySources.second) {
+ cmXCodeObject* xsf = this->CreateXCodeSourceFile(
+ this->CurrentLocalGenerator, sourceFile, gtgt);
+ buildFiles->AddObject(xsf);
+ }
+ contentBuildPhases.push_back(copyFilesBuildPhase);
+ }
+ }
+
+ // create vector of "resource content file" build phases - only for
+ // framework or bundle targets
+ if (isFrameworkTarget || isBundleTarget || isCFBundleTarget) {
+ using mapOfVectorOfSourceFiles =
+ std::map<std::string, std::vector<cmSourceFile*>>;
+ mapOfVectorOfSourceFiles bundleFiles;
+ for (auto sourceFile : commonSourceFiles) {
+ cmGeneratorTarget::SourceFileFlags tsFlags =
+ gtgt->GetTargetSourceFileFlags(sourceFile);
+ if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeDeepResource) {
+ bundleFiles[tsFlags.MacFolder].push_back(sourceFile);
+ }
+ }
+ for (auto const& keySources : bundleFiles) {
+ cmXCodeObject* copyFilesBuildPhase =
+ this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase);
+ copyFilesBuildPhase->SetComment("Copy files");
+ copyFilesBuildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ copyFilesBuildPhase->AddAttribute("dstSubfolderSpec",
+ this->CreateString("7"));
+ copyFilesBuildPhase->AddAttribute("dstPath",
+ this->CreateString(keySources.first));
+ copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ copyFilesBuildPhase->AddAttribute("files", buildFiles);
+ for (auto sourceFile : keySources.second) {
+ cmXCodeObject* xsf = this->CreateXCodeSourceFile(
+ this->CurrentLocalGenerator, sourceFile, gtgt);
+ buildFiles->AddObject(xsf);
+ }
+ contentBuildPhases.push_back(copyFilesBuildPhase);
+ }
+ }
+
+ // Always create Link Binary With Libraries build phase
+ cmXCodeObject* frameworkBuildPhase = nullptr;
+ frameworkBuildPhase =
+ this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase);
+ frameworkBuildPhase->SetComment("Frameworks");
+ frameworkBuildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ frameworkBuildPhase->AddAttribute("files", buildFiles);
+ // Add all collected .o files to this build phase
+ for (auto& externalObjFile : externalObjFiles) {
+ buildFiles->AddObject(externalObjFile);
+ }
+ frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+
+ // create list of build phases and create the Xcode target
+ cmXCodeObject* buildPhases = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+
+ this->CreateCustomCommands(buildPhases, sourceBuildPhase, headerBuildPhase,
+ resourceBuildPhase, contentBuildPhases,
+ frameworkBuildPhase, gtgt);
+
+ targets.push_back(this->CreateXCodeTarget(gtgt, buildPhases));
+ return true;
+}
+
+void cmGlobalXCodeGenerator::ForceLinkerLanguages()
+{
+ for (const auto& localGenerator : this->LocalGenerators) {
+ // All targets depend on the build-system check target.
+ for (const auto& tgt : localGenerator->GetGeneratorTargets()) {
+ // This makes sure all targets link using the proper language.
+ this->ForceLinkerLanguage(tgt.get());
+ }
+ }
+}
+
+void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmGeneratorTarget* gtgt)
+{
+ // This matters only for targets that link.
+ if (gtgt->GetType() != cmStateEnums::EXECUTABLE &&
+ gtgt->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ gtgt->GetType() != cmStateEnums::MODULE_LIBRARY) {
+ return;
+ }
+
+ std::string llang = gtgt->GetLinkerLanguage("NOCONFIG");
+ if (llang.empty()) {
+ return;
+ }
+
+ // If the language is compiled as a source trust Xcode to link with it.
+ for (auto const& Language :
+ gtgt->GetLinkImplementation("NOCONFIG")->Languages) {
+ if (Language == llang) {
+ return;
+ }
+ }
+
+ // Allow empty source file list for iOS Sticker packs
+ if (const char* productType = GetTargetProductType(gtgt)) {
+ if (strcmp(productType,
+ "com.apple.product-type.app-extension.messages-sticker-pack") ==
+ 0)
+ return;
+ }
+
+ // Add an empty source file to the target that compiles with the
+ // linker language. This should convince Xcode to choose the proper
+ // language.
+ cmMakefile* mf = gtgt->Target->GetMakefile();
+ std::string fname = cmStrCat(
+ gtgt->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/CMakeFiles/",
+ gtgt->GetName(), "-CMakeForceLinker.", cmSystemTools::LowerCase(llang));
+ {
+ cmGeneratedFileStream fout(fname);
+ fout << "\n";
+ }
+ if (cmSourceFile* sf = mf->GetOrCreateSource(fname)) {
+ sf->SetProperty("LANGUAGE", llang.c_str());
+ gtgt->AddSource(fname);
+ }
+}
+
+bool cmGlobalXCodeGenerator::IsHeaderFile(cmSourceFile* sf)
+{
+ return cm::contains(this->CMakeInstance->GetHeaderExtensions(),
+ sf->GetExtension());
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateLegacyRunScriptBuildPhase(
+ const char* name, const char* name2, cmGeneratorTarget* target,
+ const std::vector<cmCustomCommand>& commands)
+{
+ if (commands.empty() && strcmp(name, "CMake ReRun") != 0) {
+ return nullptr;
+ }
+ cmXCodeObject* buildPhase =
+ this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
+ buildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ buildPhase->AddAttribute("files", buildFiles);
+ buildPhase->AddAttribute("name", this->CreateString(name));
+ buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ buildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh"));
+ this->AddCommandsToBuildPhase(buildPhase, target, commands, name2);
+ return buildPhase;
+}
+
+void cmGlobalXCodeGenerator::CreateCustomCommands(
+ cmXCodeObject* buildPhases, cmXCodeObject* sourceBuildPhase,
+ cmXCodeObject* headerBuildPhase, cmXCodeObject* resourceBuildPhase,
+ std::vector<cmXCodeObject*> const& contentBuildPhases,
+ cmXCodeObject* frameworkBuildPhase, cmGeneratorTarget* gtgt)
+{
+ std::vector<cmCustomCommand> const& prebuild = gtgt->GetPreBuildCommands();
+ std::vector<cmCustomCommand> const& prelink = gtgt->GetPreLinkCommands();
+ std::vector<cmCustomCommand> postbuild = gtgt->GetPostBuildCommands();
+
+ if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY &&
+ !gtgt->IsFrameworkOnApple()) {
+ std::string str_file = cmStrCat("$<TARGET_FILE:", gtgt->GetName(), '>');
+ std::string str_so_file =
+ cmStrCat("$<TARGET_SONAME_FILE:", gtgt->GetName(), '>');
+ std::string str_link_file =
+ cmStrCat("$<TARGET_LINKER_FILE:", gtgt->GetName(), '>');
+ bool stdPipesUTF8 = true;
+ cmCustomCommandLines cmd = cmMakeSingleCommandLine(
+ { cmSystemTools::GetCMakeCommand(), "-E", "cmake_symlink_library",
+ str_file, str_so_file, str_link_file });
+
+ cmCustomCommand command(
+ std::vector<std::string>(), std::vector<std::string>(),
+ std::vector<std::string>(), cmd, this->CurrentMakefile->GetBacktrace(),
+ "Creating symlinks", "", stdPipesUTF8);
+
+ postbuild.push_back(std::move(command));
+ }
+
+ cmXCodeObject* legacyCustomCommandsBuildPhase = nullptr;
+ cmXCodeObject* preBuildPhase = nullptr;
+ cmXCodeObject* preLinkPhase = nullptr;
+ cmXCodeObject* postBuildPhase = nullptr;
+
+ if (this->XcodeBuildSystem >= BuildSystem::Twelve) {
+ // create prebuild phase
+ preBuildPhase =
+ this->CreateRunScriptBuildPhase("CMake PreBuild Rules", gtgt, prebuild);
+ // create prelink phase
+ preLinkPhase =
+ this->CreateRunScriptBuildPhase("CMake PreLink Rules", gtgt, prelink);
+ // create postbuild phase
+ postBuildPhase = this->CreateRunScriptBuildPhase("CMake PostBuild Rules",
+ gtgt, postbuild);
+ } else {
+ std::vector<cmSourceFile*> classes;
+ if (!gtgt->GetConfigCommonSourceFilesForXcode(classes)) {
+ return;
+ }
+ // add all the sources
+ std::vector<cmCustomCommand> commands;
+ auto& visited = this->CommandsVisited[gtgt];
+ for (auto sourceFile : classes) {
+ if (sourceFile->GetCustomCommand() &&
+ visited.insert(sourceFile).second) {
+ commands.push_back(*sourceFile->GetCustomCommand());
+ if (this->XcodeBuildSystem >= BuildSystem::Twelve) {
+ this->CustomCommandRoots[sourceFile].insert(gtgt);
+ }
+ }
+ }
+ // create custom commands phase
+ legacyCustomCommandsBuildPhase = this->CreateLegacyRunScriptBuildPhase(
+ "CMake Rules", "cmakeRulesBuildPhase", gtgt, commands);
+ // create prebuild phase
+ preBuildPhase = this->CreateLegacyRunScriptBuildPhase(
+ "CMake PreBuild Rules", "preBuildCommands", gtgt, prebuild);
+ // create prelink phase
+ preLinkPhase = this->CreateLegacyRunScriptBuildPhase(
+ "CMake PreLink Rules", "preLinkCommands", gtgt, prelink);
+ // create postbuild phase
+ postBuildPhase = this->CreateLegacyRunScriptBuildPhase(
+ "CMake PostBuild Rules", "postBuildPhase", gtgt, postbuild);
+ }
+
+ // The order here is the order they will be built in.
+ // The order "headers, resources, sources" mimics a native project generated
+ // from an xcode template...
+ //
+ if (preBuildPhase) {
+ buildPhases->AddObject(preBuildPhase);
+ }
+ if (legacyCustomCommandsBuildPhase) {
+ buildPhases->AddObject(legacyCustomCommandsBuildPhase);
+ }
+ if (this->XcodeBuildSystem >= BuildSystem::Twelve) {
+ this->CreateRunScriptBuildPhases(buildPhases, gtgt);
+ }
+ if (headerBuildPhase) {
+ buildPhases->AddObject(headerBuildPhase);
+ }
+ if (resourceBuildPhase) {
+ buildPhases->AddObject(resourceBuildPhase);
+ }
+ for (auto obj : contentBuildPhases) {
+ buildPhases->AddObject(obj);
+ }
+ if (sourceBuildPhase) {
+ buildPhases->AddObject(sourceBuildPhase);
+ }
+ if (preLinkPhase) {
+ buildPhases->AddObject(preLinkPhase);
+ }
+ if (frameworkBuildPhase) {
+ buildPhases->AddObject(frameworkBuildPhase);
+ }
+
+ // When this build phase is present, it must be last. More build phases may
+ // be added later for embedding things and they will insert themselves just
+ // before this last build phase.
+ if (postBuildPhase) {
+ buildPhases->AddObject(postBuildPhase);
+ }
+}
+
+void cmGlobalXCodeGenerator::CreateRunScriptBuildPhases(
+ cmXCodeObject* buildPhases, cmGeneratorTarget const* gt)
+{
+ std::vector<cmSourceFile*> sources;
+ if (!gt->GetConfigCommonSourceFilesForXcode(sources)) {
+ return;
+ }
+ auto& visited = this->CommandsVisited[gt];
+ for (auto sf : sources) {
+ this->CreateRunScriptBuildPhases(buildPhases, sf, gt, visited);
+ }
+}
+
+void cmGlobalXCodeGenerator::CreateRunScriptBuildPhases(
+ cmXCodeObject* buildPhases, cmSourceFile const* sf,
+ cmGeneratorTarget const* gt, std::set<cmSourceFile const*>& visited)
+{
+ cmCustomCommand const* cc = sf->GetCustomCommand();
+ if (cc && visited.insert(sf).second) {
+ this->CustomCommandRoots[sf].insert(gt);
+ if (std::vector<cmSourceFile*> const* depends = gt->GetSourceDepends(sf)) {
+ for (cmSourceFile const* di : *depends) {
+ this->CreateRunScriptBuildPhases(buildPhases, di, gt, visited);
+ }
+ }
+ cmXCodeObject* buildPhase = this->CreateRunScriptBuildPhase(sf, gt, *cc);
+ buildPhases->AddObject(buildPhase);
+ }
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase(
+ cmSourceFile const* sf, cmGeneratorTarget const* gt,
+ cmCustomCommand const& cc)
+{
+ std::set<std::string> allConfigInputs;
+ std::set<std::string> allConfigOutputs;
+
+ std::string shellScript = "set -e\n";
+ for (std::string const& configName : this->CurrentConfigurationTypes) {
+ cmCustomCommandGenerator ccg(cc, configName, this->CurrentLocalGenerator);
+ std::vector<std::string> realDepends;
+ realDepends.reserve(ccg.GetDepends().size());
+ for (auto const& d : ccg.GetDepends()) {
+ std::string dep;
+ if (this->CurrentLocalGenerator->GetRealDependency(d, configName, dep)) {
+ realDepends.emplace_back(std::move(dep));
+ }
+ }
+
+ allConfigInputs.insert(realDepends.begin(), realDepends.end());
+ allConfigOutputs.insert(ccg.GetByproducts().begin(),
+ ccg.GetByproducts().end());
+ allConfigOutputs.insert(ccg.GetOutputs().begin(), ccg.GetOutputs().end());
+
+ shellScript =
+ cmStrCat(shellScript, R"(if test "$CONFIGURATION" = ")", configName,
+ "\"; then :\n", this->ConstructScript(ccg), "fi\n");
+ }
+
+ cmXCodeObject* buildPhase =
+ this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase,
+ cmStrCat(gt->GetName(), ':', sf->GetFullPath()));
+ buildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ buildPhase->AddAttribute("files", buildFiles);
+ {
+ std::string name;
+ if (!allConfigOutputs.empty()) {
+ name = cmStrCat("Generate ",
+ this->RelativeToBinary(*allConfigOutputs.begin()));
+ } else {
+ name = sf->GetLocation().GetName();
+ }
+ buildPhase->AddAttribute("name", this->CreateString(name));
+ }
+ buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ buildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh"));
+ buildPhase->AddAttribute("shellScript", this->CreateString(shellScript));
+ buildPhase->AddAttribute("showEnvVarsInLog", this->CreateString("0"));
+
+ bool symbolic = false;
+ {
+ cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (std::string const& i : allConfigInputs) {
+ inputPaths->AddUniqueObject(this->CreateString(i));
+ if (!symbolic) {
+ if (cmSourceFile* isf =
+ gt->GetLocalGenerator()->GetMakefile()->GetSource(
+ i, cmSourceFileLocationKind::Known)) {
+ symbolic = isf->GetPropertyAsBool("SYMBOLIC");
+ }
+ }
+ }
+ buildPhase->AddAttribute("inputPaths", inputPaths);
+ }
+ {
+ cmXCodeObject* outputPaths =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (std::string const& o : allConfigOutputs) {
+ outputPaths->AddUniqueObject(this->CreateString(o));
+ if (!symbolic) {
+ if (cmSourceFile* osf =
+ gt->GetLocalGenerator()->GetMakefile()->GetSource(
+ o, cmSourceFileLocationKind::Known)) {
+ symbolic = osf->GetPropertyAsBool("SYMBOLIC");
+ }
+ }
+ }
+ buildPhase->AddAttribute("outputPaths", outputPaths);
+ }
+ if (symbolic) {
+ buildPhase->AddAttribute("alwaysOutOfDate", this->CreateString("1"));
+ }
+
+ return buildPhase;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase(
+ std::string const& name, cmGeneratorTarget const* gt,
+ std::vector<cmCustomCommand> const& commands)
+{
+ if (commands.empty()) {
+ return nullptr;
+ }
+
+ std::set<std::string> allConfigOutputs;
+
+ std::string shellScript = "set -e\n";
+ for (std::string const& configName : this->CurrentConfigurationTypes) {
+ shellScript = cmStrCat(shellScript, R"(if test "$CONFIGURATION" = ")",
+ configName, "\"; then :\n");
+ for (cmCustomCommand const& cc : commands) {
+ cmCustomCommandGenerator ccg(cc, configName,
+ this->CurrentLocalGenerator);
+ shellScript = cmStrCat(shellScript, this->ConstructScript(ccg));
+ allConfigOutputs.insert(ccg.GetByproducts().begin(),
+ ccg.GetByproducts().end());
+ }
+ shellScript = cmStrCat(shellScript, "fi\n");
+ }
+
+ cmXCodeObject* buildPhase =
+ this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase,
+ cmStrCat(gt->GetName(), ':', name));
+ buildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ buildPhase->AddAttribute("files", buildFiles);
+ buildPhase->AddAttribute("name", this->CreateString(name));
+ buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ buildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh"));
+ buildPhase->AddAttribute("shellScript", this->CreateString(shellScript));
+ buildPhase->AddAttribute("showEnvVarsInLog", this->CreateString("0"));
+ {
+ cmXCodeObject* outputPaths =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (std::string const& o : allConfigOutputs) {
+ outputPaths->AddUniqueObject(this->CreateString(o));
+ }
+ buildPhase->AddAttribute("outputPaths", outputPaths);
+ }
+ buildPhase->AddAttribute("alwaysOutOfDate", this->CreateString("1"));
+
+ return buildPhase;
+}
+
+namespace {
+void ReplaceScriptVars(std::string& cmd)
+{
+ cmSystemTools::ReplaceString(cmd, "$(CONFIGURATION)", "$CONFIGURATION");
+ cmSystemTools::ReplaceString(cmd, "$(EFFECTIVE_PLATFORM_NAME)",
+ "$EFFECTIVE_PLATFORM_NAME");
+}
+}
+
+std::string cmGlobalXCodeGenerator::ConstructScript(
+ cmCustomCommandGenerator const& ccg)
+{
+ std::string script;
+ cmLocalGenerator* lg = this->CurrentLocalGenerator;
+ std::string wd = ccg.GetWorkingDirectory();
+ if (wd.empty()) {
+ wd = lg->GetCurrentBinaryDirectory();
+ }
+ wd = lg->ConvertToOutputFormat(wd, cmOutputConverter::SHELL);
+ ReplaceScriptVars(wd);
+ script = cmStrCat(script, " cd ", wd, "\n");
+ for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
+ std::string cmd = ccg.GetCommand(c);
+ if (cmd.empty()) {
+ continue;
+ }
+ cmSystemTools::ReplaceString(cmd, "/./", "/");
+ cmd = lg->ConvertToOutputFormat(cmd, cmOutputConverter::SHELL);
+ ccg.AppendArguments(c, cmd);
+ ReplaceScriptVars(cmd);
+ script = cmStrCat(script, " ", cmd, '\n');
+ }
+ return script;
+}
+
+// This function removes each occurrence of the flag and returns the last one
+// (i.e., the dominant flag in GCC)
+std::string cmGlobalXCodeGenerator::ExtractFlag(const char* flag,
+ std::string& flags)
+{
+ std::string retFlag;
+ std::string::size_type lastOccurancePos = flags.rfind(flag);
+ bool saved = false;
+ while (lastOccurancePos != std::string::npos) {
+ // increment pos, we use lastOccurancePos to reduce search space on next
+ // inc
+ std::string::size_type pos = lastOccurancePos;
+ if (pos == 0 || flags[pos - 1] == ' ') {
+ while (pos < flags.size() && flags[pos] != ' ') {
+ if (!saved) {
+ retFlag += flags[pos];
+ }
+ flags[pos] = ' ';
+ pos++;
+ }
+ saved = true;
+ }
+ // decrement lastOccurancePos while making sure we don't loop around
+ // and become a very large positive number since size_type is unsigned
+ lastOccurancePos = lastOccurancePos == 0 ? 0 : lastOccurancePos - 1;
+ lastOccurancePos = flags.rfind(flag, lastOccurancePos);
+ }
+ return retFlag;
+}
+
+// This function removes each matching occurrence of the expression and
+// returns the last one (i.e., the dominant flag in GCC)
+std::string cmGlobalXCodeGenerator::ExtractFlagRegex(const char* exp,
+ int matchIndex,
+ std::string& flags)
+{
+ std::string retFlag;
+
+ cmsys::RegularExpression regex(exp);
+ assert(regex.is_valid());
+ if (!regex.is_valid()) {
+ return retFlag;
+ }
+
+ std::string::size_type offset = 0;
+
+ while (regex.find(&flags[offset])) {
+ const std::string::size_type startPos = offset + regex.start(matchIndex);
+ const std::string::size_type endPos = offset + regex.end(matchIndex);
+ const std::string::size_type size = endPos - startPos;
+
+ offset = startPos + 1;
+
+ retFlag.assign(flags, startPos, size);
+ flags.replace(startPos, size, size, ' ');
+ }
+
+ return retFlag;
+}
+
+//----------------------------------------------------------------------------
+// This function strips off Xcode attributes that do not target the current
+// configuration
+void cmGlobalXCodeGenerator::FilterConfigurationAttribute(
+ std::string const& configName, std::string& attribute)
+{
+ // Handle [variant=<config>] condition explicitly here.
+ std::string::size_type beginVariant = attribute.find("[variant=");
+ if (beginVariant == std::string::npos) {
+ // There is no variant in this attribute.
+ return;
+ }
+
+ std::string::size_type endVariant = attribute.find(']', beginVariant + 9);
+ if (endVariant == std::string::npos) {
+ // There is no terminating bracket.
+ return;
+ }
+
+ // Compare the variant to the configuration.
+ std::string variant =
+ attribute.substr(beginVariant + 9, endVariant - beginVariant - 9);
+ if (variant == configName) {
+ // The variant matches the configuration so use this
+ // attribute but drop the [variant=<config>] condition.
+ attribute.erase(beginVariant, endVariant - beginVariant + 1);
+ } else {
+ // The variant does not match the configuration so
+ // do not use this attribute.
+ attribute.clear();
+ }
+}
+
+void cmGlobalXCodeGenerator::AddCommandsToBuildPhase(
+ cmXCodeObject* buildphase, cmGeneratorTarget* target,
+ std::vector<cmCustomCommand> const& commands, const char* name)
+{
+ std::string dir = cmStrCat(
+ this->CurrentLocalGenerator->GetCurrentBinaryDirectory(), "/CMakeScripts");
+ cmSystemTools::MakeDirectory(dir);
+ std::string makefile =
+ cmStrCat(dir, '/', target->GetName(), '_', name, ".make");
+
+ for (const auto& currentConfig : this->CurrentConfigurationTypes) {
+ this->CreateCustomRulesMakefile(makefile.c_str(), target, commands,
+ currentConfig);
+ }
+
+ std::string cdir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory();
+ cdir = this->ConvertToRelativeForMake(cdir);
+ std::string makecmd =
+ cmStrCat("make -C ", cdir, " -f ",
+ this->ConvertToRelativeForMake((makefile + "$CONFIGURATION")),
+ " OBJDIR=$(basename \"$OBJECT_FILE_DIR_normal\") all");
+ buildphase->AddAttribute("shellScript", this->CreateString(makecmd));
+ buildphase->AddAttribute("showEnvVarsInLog", this->CreateString("0"));
+}
+
+void cmGlobalXCodeGenerator::CreateCustomRulesMakefile(
+ const char* makefileBasename, cmGeneratorTarget* target,
+ std::vector<cmCustomCommand> const& commands, const std::string& configName)
+{
+ std::string makefileName = cmStrCat(makefileBasename, configName);
+ cmGeneratedFileStream makefileStream(makefileName);
+ if (!makefileStream) {
+ return;
+ }
+ makefileStream.SetCopyIfDifferent(true);
+ makefileStream << "# Generated by CMake, DO NOT EDIT\n";
+ makefileStream << "# Custom rules for " << target->GetName() << "\n";
+
+ // disable the implicit rules
+ makefileStream << ".SUFFIXES: "
+ << "\n";
+
+ // have all depend on all outputs
+ makefileStream << "all: ";
+ std::map<const cmCustomCommand*, std::string> tname;
+ int count = 0;
+ for (auto const& command : commands) {
+ cmCustomCommandGenerator ccg(command, configName,
+ this->CurrentLocalGenerator);
+ if (ccg.GetNumberOfCommands() > 0) {
+ const std::vector<std::string>& outputs = ccg.GetOutputs();
+ if (!outputs.empty()) {
+ for (auto const& output : outputs) {
+ makefileStream << "\\\n\t" << this->ConvertToRelativeForMake(output);
+ }
+ } else {
+ std::ostringstream str;
+ str << "_buildpart_" << count++;
+ tname[&ccg.GetCC()] = target->GetName() + str.str();
+ makefileStream << "\\\n\t" << tname[&ccg.GetCC()];
+ }
+ }
+ }
+ makefileStream << "\n\n";
+ for (auto const& command : commands) {
+ cmCustomCommandGenerator ccg(command, configName,
+ this->CurrentLocalGenerator);
+ std::vector<std::string> realDepends;
+ realDepends.reserve(ccg.GetDepends().size());
+ for (auto const& d : ccg.GetDepends()) {
+ std::string dep;
+ if (this->CurrentLocalGenerator->GetRealDependency(d, configName, dep)) {
+ realDepends.emplace_back(std::move(dep));
+ }
+ }
+
+ if (ccg.GetNumberOfCommands() > 0) {
+ makefileStream << "\n";
+ const std::vector<std::string>& outputs = ccg.GetOutputs();
+ if (!outputs.empty()) {
+ // There is at least one output, start the rule for it
+ const char* sep = "";
+ for (auto const& output : outputs) {
+ makefileStream << sep << this->ConvertToRelativeForMake(output);
+ sep = " ";
+ }
+ makefileStream << ": ";
+ } else {
+ // There are no outputs. Use the generated force rule name.
+ makefileStream << tname[&ccg.GetCC()] << ": ";
+ }
+ for (auto const& dep : realDepends) {
+ makefileStream << "\\\n" << this->ConvertToRelativeForMake(dep);
+ }
+ makefileStream << "\n";
+
+ if (const char* comment = ccg.GetComment()) {
+ std::string echo_cmd =
+ cmStrCat("echo ",
+ (this->CurrentLocalGenerator->EscapeForShell(
+ comment, ccg.GetCC().GetEscapeAllowMakeVars())));
+ makefileStream << "\t" << echo_cmd << "\n";
+ }
+
+ // Add each command line to the set of commands.
+ for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
+ // Build the command line in a single string.
+ std::string cmd2 = ccg.GetCommand(c);
+ cmSystemTools::ReplaceString(cmd2, "/./", "/");
+ cmd2 = this->ConvertToRelativeForMake(cmd2);
+ std::string cmd;
+ std::string wd = ccg.GetWorkingDirectory();
+ if (!wd.empty()) {
+ cmd += "cd ";
+ cmd += this->ConvertToRelativeForMake(wd);
+ cmd += " && ";
+ }
+ cmd += cmd2;
+ ccg.AppendArguments(c, cmd);
+ makefileStream << "\t" << cmd << "\n";
+ }
+
+ // Symbolic inputs are not expected to exist, so add dummy rules.
+ for (auto const& dep : realDepends) {
+ if (cmSourceFile* dsf =
+ target->GetLocalGenerator()->GetMakefile()->GetSource(
+ dep, cmSourceFileLocationKind::Known)) {
+ if (dsf->GetPropertyAsBool("SYMBOLIC")) {
+ makefileStream << this->ConvertToRelativeForMake(dep) << ":\n";
+ }
+ }
+ }
+ }
+ }
+}
+
+void cmGlobalXCodeGenerator::AddPositionIndependentLinkAttribute(
+ cmGeneratorTarget* target, cmXCodeObject* buildSettings,
+ const std::string& configName)
+{
+ // For now, only EXECUTABLE is concerned
+ if (target->GetType() != cmStateEnums::EXECUTABLE) {
+ return;
+ }
+
+ const char* PICValue = target->GetLinkPIEProperty(configName);
+ if (PICValue == nullptr) {
+ // POSITION_INDEPENDENT_CODE is not set
+ return;
+ }
+
+ buildSettings->AddAttribute(
+ "LD_NO_PIE", this->CreateString(cmIsOn(PICValue) ? "NO" : "YES"));
+}
+
+void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
+ cmXCodeObject* buildSettings,
+ const std::string& configName)
+{
+ if (!gtgt->IsInBuildSystem()) {
+ return;
+ }
+
+ std::string defFlags;
+ bool shared = ((gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) ||
+ (gtgt->GetType() == cmStateEnums::MODULE_LIBRARY));
+ bool binary = ((gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY) ||
+ (gtgt->GetType() == cmStateEnums::STATIC_LIBRARY) ||
+ (gtgt->GetType() == cmStateEnums::EXECUTABLE) || shared);
+
+ // Compute the compilation flags for each language.
+ std::set<std::string> languages;
+ gtgt->GetLanguages(languages, configName);
+ std::map<std::string, std::string> cflags;
+ for (auto const& lang : languages) {
+ std::string& flags = cflags[lang];
+
+ // Add language-specific flags.
+ this->CurrentLocalGenerator->AddLanguageFlags(flags, gtgt, lang,
+ configName);
+
+ if (gtgt->IsIPOEnabled(lang, configName)) {
+ this->CurrentLocalGenerator->AppendFeatureOptions(flags, lang, "IPO");
+ }
+
+ // Add shared-library flags if needed.
+ this->CurrentLocalGenerator->AddCMP0018Flags(flags, gtgt, lang,
+ configName);
+
+ this->CurrentLocalGenerator->AddVisibilityPresetFlags(flags, gtgt, lang);
+
+ this->CurrentLocalGenerator->AddCompileOptions(flags, gtgt, lang,
+ configName);
+ }
+
+ std::string llang = gtgt->GetLinkerLanguage(configName);
+ if (binary && llang.empty()) {
+ cmSystemTools::Error(
+ "CMake can not determine linker language for target: " +
+ gtgt->GetName());
+ return;
+ }
+ std::string const& langForPreprocessor = llang;
+
+ if (gtgt->IsIPOEnabled(llang, configName)) {
+ const char* ltoValue =
+ this->CurrentMakefile->IsOn("_CMAKE_LTO_THIN") ? "YES_THIN" : "YES";
+ buildSettings->AddAttribute("LLVM_LTO", this->CreateString(ltoValue));
+ }
+
+ // Handle PIE linker configuration
+ this->AddPositionIndependentLinkAttribute(gtgt, buildSettings, configName);
+
+ // Add define flags
+ this->CurrentLocalGenerator->AppendFlags(
+ defFlags, this->CurrentMakefile->GetDefineFlags());
+
+ // Add preprocessor definitions for this target and configuration.
+ BuildObjectListOrString ppDefs(this, true);
+ this->AppendDefines(
+ ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"");
+ if (const std::string* exportMacro = gtgt->GetExportMacro()) {
+ // Add the export symbol definition for shared library objects.
+ this->AppendDefines(ppDefs, exportMacro->c_str());
+ }
+ std::vector<std::string> targetDefines;
+ if (!langForPreprocessor.empty()) {
+ gtgt->GetCompileDefinitions(targetDefines, configName,
+ langForPreprocessor);
+ }
+ this->AppendDefines(ppDefs, targetDefines);
+ buildSettings->AddAttribute("GCC_PREPROCESSOR_DEFINITIONS",
+ ppDefs.CreateList());
+
+ std::string extraLinkOptionsVar;
+ std::string extraLinkOptions;
+ if (gtgt->GetType() == cmStateEnums::EXECUTABLE) {
+ extraLinkOptionsVar = "CMAKE_EXE_LINKER_FLAGS";
+ } else if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ extraLinkOptionsVar = "CMAKE_SHARED_LINKER_FLAGS";
+ } else if (gtgt->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ extraLinkOptionsVar = "CMAKE_MODULE_LINKER_FLAGS";
+ }
+ if (!extraLinkOptionsVar.empty()) {
+ this->CurrentLocalGenerator->AddConfigVariableFlags(
+ extraLinkOptions, extraLinkOptionsVar, configName);
+ }
+
+ if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY ||
+ gtgt->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ this->CurrentLocalGenerator->GetStaticLibraryFlags(
+ extraLinkOptions, configName, llang, gtgt);
+ } else {
+ cmProp targetLinkFlags = gtgt->GetProperty("LINK_FLAGS");
+ if (targetLinkFlags) {
+ this->CurrentLocalGenerator->AppendFlags(extraLinkOptions,
+ *targetLinkFlags);
+ }
+ if (!configName.empty()) {
+ std::string linkFlagsVar =
+ cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(configName));
+ if (cmProp linkFlags = gtgt->GetProperty(linkFlagsVar)) {
+ this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, *linkFlags);
+ }
+ }
+ std::vector<std::string> opts;
+ gtgt->GetLinkOptions(opts, configName, llang);
+ // LINK_OPTIONS are escaped.
+ this->CurrentLocalGenerator->AppendCompileOptions(extraLinkOptions, opts);
+ }
+
+ // Set target-specific architectures.
+ std::vector<std::string> archs;
+ gtgt->GetAppleArchs(configName, archs);
+
+ if (!archs.empty()) {
+ // Enable ARCHS attribute.
+ buildSettings->AddAttribute("ONLY_ACTIVE_ARCH", this->CreateString("NO"));
+
+ // Store ARCHS value.
+ if (archs.size() == 1) {
+ buildSettings->AddAttribute("ARCHS", this->CreateString(archs[0]));
+ } else {
+ cmXCodeObject* archObjects =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (auto& arch : archs) {
+ archObjects->AddObject(this->CreateString(arch));
+ }
+ buildSettings->AddAttribute("ARCHS", archObjects);
+ }
+ }
+
+ // Get the product name components.
+ std::string pnprefix;
+ std::string pnbase;
+ std::string pnsuffix;
+ gtgt->GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
+
+ cmProp version = gtgt->GetProperty("VERSION");
+ cmProp soversion = gtgt->GetProperty("SOVERSION");
+ if (!gtgt->HasSOName(configName) || gtgt->IsFrameworkOnApple()) {
+ version = nullptr;
+ soversion = nullptr;
+ }
+ if (version && !soversion) {
+ soversion = version;
+ }
+ if (!version && soversion) {
+ version = soversion;
+ }
+
+ std::string realName = pnbase;
+ std::string soName = pnbase;
+ if (version && soversion) {
+ realName += ".";
+ realName += *version;
+ soName += ".";
+ soName += *soversion;
+ }
+
+ // Set attributes to specify the proper name for the target.
+ std::string pndir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory();
+ if (gtgt->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ gtgt->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ gtgt->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ gtgt->GetType() == cmStateEnums::EXECUTABLE) {
+ if (!gtgt->UsesDefaultOutputDir(configName,
+ cmStateEnums::RuntimeBinaryArtifact)) {
+ std::string pncdir = gtgt->GetDirectory(configName);
+ buildSettings->AddAttribute("CONFIGURATION_BUILD_DIR",
+ this->CreateString(pncdir));
+ }
+
+ if (gtgt->IsFrameworkOnApple() || gtgt->IsCFBundleOnApple()) {
+ pnprefix = "";
+ }
+
+ buildSettings->AddAttribute("EXECUTABLE_PREFIX",
+ this->CreateString(pnprefix));
+ buildSettings->AddAttribute("EXECUTABLE_SUFFIX",
+ this->CreateString(pnsuffix));
+ } else if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ pnprefix = "lib";
+ pnbase = gtgt->GetName();
+ pnsuffix = ".a";
+
+ std::string pncdir = this->GetObjectsDirectory(
+ this->CurrentProject, configName, gtgt, OBJECT_LIBRARY_ARTIFACT_DIR);
+ buildSettings->AddAttribute("CONFIGURATION_BUILD_DIR",
+ this->CreateString(pncdir));
+ }
+
+ // Store the product name for all target types.
+ buildSettings->AddAttribute("PRODUCT_NAME", this->CreateString(realName));
+ buildSettings->AddAttribute("SYMROOT", this->CreateString(pndir));
+
+ // Handle settings for each target type.
+ switch (gtgt->GetType()) {
+ case cmStateEnums::STATIC_LIBRARY:
+ if (gtgt->GetPropertyAsBool("FRAMEWORK")) {
+ std::string fw_version = gtgt->GetFrameworkVersion();
+ buildSettings->AddAttribute("FRAMEWORK_VERSION",
+ this->CreateString(fw_version));
+ cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION");
+ if (ext) {
+ buildSettings->AddAttribute("WRAPPER_EXTENSION",
+ this->CreateString(*ext));
+ }
+
+ std::string plist = this->ComputeInfoPListLocation(gtgt);
+ // Xcode will create the final version of Info.plist at build time,
+ // so let it replace the framework name. This avoids creating
+ // a per-configuration Info.plist file.
+ this->CurrentLocalGenerator->GenerateFrameworkInfoPList(
+ gtgt, "$(EXECUTABLE_NAME)", plist);
+ buildSettings->AddAttribute("INFOPLIST_FILE",
+ this->CreateString(plist));
+ buildSettings->AddAttribute("MACH_O_TYPE",
+ this->CreateString("staticlib"));
+ } else {
+ buildSettings->AddAttribute("LIBRARY_STYLE",
+ this->CreateString("STATIC"));
+ }
+ break;
+
+ case cmStateEnums::OBJECT_LIBRARY: {
+ buildSettings->AddAttribute("LIBRARY_STYLE",
+ this->CreateString("STATIC"));
+ break;
+ }
+
+ case cmStateEnums::MODULE_LIBRARY: {
+ buildSettings->AddAttribute("LIBRARY_STYLE",
+ this->CreateString("BUNDLE"));
+ if (gtgt->IsCFBundleOnApple()) {
+ // It turns out that a BUNDLE is basically the same
+ // in many ways as an application bundle, as far as
+ // link flags go
+ std::string createFlags = this->LookupFlags(
+ "CMAKE_SHARED_MODULE_CREATE_", llang, "_FLAGS", "-bundle");
+ if (!createFlags.empty()) {
+ extraLinkOptions += " ";
+ extraLinkOptions += createFlags;
+ }
+ cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION");
+ if (ext) {
+ buildSettings->AddAttribute("WRAPPER_EXTENSION",
+ this->CreateString(*ext));
+ }
+ std::string plist = this->ComputeInfoPListLocation(gtgt);
+ // Xcode will create the final version of Info.plist at build time,
+ // so let it replace the cfbundle name. This avoids creating
+ // a per-configuration Info.plist file. The cfbundle plist
+ // is very similar to the application bundle plist
+ this->CurrentLocalGenerator->GenerateAppleInfoPList(
+ gtgt, "$(EXECUTABLE_NAME)", plist);
+ buildSettings->AddAttribute("INFOPLIST_FILE",
+ this->CreateString(plist));
+ } else {
+ buildSettings->AddAttribute("MACH_O_TYPE",
+ this->CreateString("mh_bundle"));
+ buildSettings->AddAttribute("GCC_DYNAMIC_NO_PIC",
+ this->CreateString("NO"));
+ // Add the flags to create an executable.
+ std::string createFlags =
+ this->LookupFlags("CMAKE_", llang, "_LINK_FLAGS", "");
+ if (!createFlags.empty()) {
+ extraLinkOptions += " ";
+ extraLinkOptions += createFlags;
+ }
+ }
+ break;
+ }
+ case cmStateEnums::SHARED_LIBRARY: {
+ if (gtgt->GetPropertyAsBool("FRAMEWORK")) {
+ std::string fw_version = gtgt->GetFrameworkVersion();
+ buildSettings->AddAttribute("FRAMEWORK_VERSION",
+ this->CreateString(fw_version));
+ cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION");
+ if (ext) {
+ buildSettings->AddAttribute("WRAPPER_EXTENSION",
+ this->CreateString(*ext));
+ }
+
+ std::string plist = this->ComputeInfoPListLocation(gtgt);
+ // Xcode will create the final version of Info.plist at build time,
+ // so let it replace the framework name. This avoids creating
+ // a per-configuration Info.plist file.
+ this->CurrentLocalGenerator->GenerateFrameworkInfoPList(
+ gtgt, "$(EXECUTABLE_NAME)", plist);
+ buildSettings->AddAttribute("INFOPLIST_FILE",
+ this->CreateString(plist));
+ } else {
+ // Add the flags to create a shared library.
+ std::string createFlags = this->LookupFlags(
+ "CMAKE_SHARED_LIBRARY_CREATE_", llang, "_FLAGS", "-dynamiclib");
+ if (!createFlags.empty()) {
+ extraLinkOptions += " ";
+ extraLinkOptions += createFlags;
+ }
+ }
+
+ buildSettings->AddAttribute("LIBRARY_STYLE",
+ this->CreateString("DYNAMIC"));
+ break;
+ }
+ case cmStateEnums::EXECUTABLE: {
+ // Add the flags to create an executable.
+ std::string createFlags =
+ this->LookupFlags("CMAKE_", llang, "_LINK_FLAGS", "");
+ if (!createFlags.empty()) {
+ extraLinkOptions += " ";
+ extraLinkOptions += createFlags;
+ }
+
+ // Handle bundles and normal executables separately.
+ if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) {
+ cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION");
+ if (ext) {
+ buildSettings->AddAttribute("WRAPPER_EXTENSION",
+ this->CreateString(*ext));
+ }
+ std::string plist = this->ComputeInfoPListLocation(gtgt);
+ // Xcode will create the final version of Info.plist at build time,
+ // so let it replace the executable name. This avoids creating
+ // a per-configuration Info.plist file.
+ this->CurrentLocalGenerator->GenerateAppleInfoPList(
+ gtgt, "$(EXECUTABLE_NAME)", plist);
+ buildSettings->AddAttribute("INFOPLIST_FILE",
+ this->CreateString(plist));
+ }
+ } break;
+ default:
+ break;
+ }
+
+ BuildObjectListOrString dirs(this, true);
+ BuildObjectListOrString fdirs(this, true);
+ BuildObjectListOrString sysdirs(this, true);
+ BuildObjectListOrString sysfdirs(this, true);
+ const bool emitSystemIncludes = this->XcodeVersion >= 83;
+
+ std::vector<std::string> includes;
+ if (!langForPreprocessor.empty()) {
+ this->CurrentLocalGenerator->GetIncludeDirectories(
+ includes, gtgt, langForPreprocessor, configName);
+ }
+ std::set<std::string> emitted;
+ emitted.insert("/System/Library/Frameworks");
+
+ for (auto& include : includes) {
+ if (this->NameResolvesToFramework(include)) {
+ std::string frameworkDir = cmStrCat(include, "/../");
+ frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
+ if (emitted.insert(frameworkDir).second) {
+ std::string incpath = this->XCodeEscapePath(frameworkDir);
+ if (emitSystemIncludes &&
+ gtgt->IsSystemIncludeDirectory(frameworkDir, configName,
+ langForPreprocessor)) {
+ sysfdirs.Add(incpath);
+ } else {
+ fdirs.Add(incpath);
+ }
+ }
+ } else {
+ std::string incpath = this->XCodeEscapePath(include);
+ if (emitSystemIncludes &&
+ gtgt->IsSystemIncludeDirectory(include, configName,
+ langForPreprocessor)) {
+ sysdirs.Add(incpath);
+ } else {
+ dirs.Add(incpath);
+ }
+ }
+ }
+ // Add framework search paths needed for linking.
+ if (cmComputeLinkInformation* cli = gtgt->GetLinkInformation(configName)) {
+ for (auto const& fwDir : cli->GetFrameworkPaths()) {
+ if (emitted.insert(fwDir).second) {
+ std::string incpath = this->XCodeEscapePath(fwDir);
+ if (emitSystemIncludes &&
+ gtgt->IsSystemIncludeDirectory(fwDir, configName,
+ langForPreprocessor)) {
+ sysfdirs.Add(incpath);
+ } else {
+ fdirs.Add(incpath);
+ }
+ }
+ }
+ }
+ if (!fdirs.IsEmpty()) {
+ buildSettings->AddAttribute("FRAMEWORK_SEARCH_PATHS", fdirs.CreateList());
+ }
+ if (!dirs.IsEmpty()) {
+ buildSettings->AddAttribute("HEADER_SEARCH_PATHS", dirs.CreateList());
+ }
+ if (!sysfdirs.IsEmpty()) {
+ buildSettings->AddAttribute("SYSTEM_FRAMEWORK_SEARCH_PATHS",
+ sysfdirs.CreateList());
+ }
+ if (!sysdirs.IsEmpty()) {
+ buildSettings->AddAttribute("SYSTEM_HEADER_SEARCH_PATHS",
+ sysdirs.CreateList());
+ }
+
+ if (this->XcodeVersion >= 60 && !emitSystemIncludes) {
+ // Add those per-language flags in addition to HEADER_SEARCH_PATHS to gain
+ // system include directory awareness. We need to also keep on setting
+ // HEADER_SEARCH_PATHS to work around a missing compile options flag for
+ // GNU assembly files (#16449)
+ for (auto const& language : languages) {
+ std::string includeFlags = this->CurrentLocalGenerator->GetIncludeFlags(
+ includes, gtgt, language, configName);
+
+ if (!includeFlags.empty()) {
+ cflags[language] += " " + includeFlags;
+ }
+ }
+ }
+
+ bool same_gflags = true;
+ std::map<std::string, std::string> gflags;
+ std::string const* last_gflag = nullptr;
+ std::string optLevel = "0";
+
+ // Minimal map of flags to build settings.
+ for (auto const& language : languages) {
+ std::string& flags = cflags[language];
+ std::string& gflag = gflags[language];
+ std::string oflag =
+ this->ExtractFlagRegex("(^| )(-Ofast|-Os|-O[0-9]*)( |$)", 2, flags);
+ if (oflag.size() == 2) {
+ optLevel = "1";
+ } else if (oflag.size() > 2) {
+ optLevel = oflag.substr(2);
+ }
+ gflag = this->ExtractFlag("-g", flags);
+ // put back gdwarf-2 if used since there is no way
+ // to represent it in the gui, but we still want debug yes
+ if (gflag == "-gdwarf-2") {
+ flags += " ";
+ flags += gflag;
+ }
+ if (last_gflag && *last_gflag != gflag) {
+ same_gflags = false;
+ }
+ last_gflag = &gflag;
+ }
+
+ const char* debugStr = "YES";
+ if (!same_gflags) {
+ // We can't set the Xcode flag differently depending on the language,
+ // so put them back in this case.
+ for (auto const& language : languages) {
+ cflags[language] += " ";
+ cflags[language] += gflags[language];
+ }
+ debugStr = "NO";
+ } else if (last_gflag && (last_gflag->empty() || *last_gflag == "-g0")) {
+ debugStr = "NO";
+ }
+
+ // extract C++ stdlib
+ for (auto const& language : languages) {
+ if (language != "CXX" && language != "OBJCXX") {
+ continue;
+ }
+ std::string& flags = cflags[language];
+
+ auto stdlib =
+ this->ExtractFlagRegex("(^| )(-stdlib=[^ ]+)( |$)", 2, flags);
+ if (stdlib.size() > 8) {
+ const auto cxxLibrary = stdlib.substr(8);
+ if (language == "CXX" ||
+ !buildSettings->GetAttribute("CLANG_CXX_LIBRARY")) {
+ buildSettings->AddAttribute("CLANG_CXX_LIBRARY",
+ this->CreateString(cxxLibrary));
+ }
+ }
+ }
+
+ buildSettings->AddAttribute("COMBINE_HIDPI_IMAGES",
+ this->CreateString("YES"));
+ buildSettings->AddAttribute("GCC_GENERATE_DEBUGGING_SYMBOLS",
+ this->CreateString(debugStr));
+ buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL",
+ this->CreateString(optLevel));
+ buildSettings->AddAttribute("GCC_SYMBOLS_PRIVATE_EXTERN",
+ this->CreateString("NO"));
+ buildSettings->AddAttribute("GCC_INLINES_ARE_PRIVATE_EXTERN",
+ this->CreateString("NO"));
+
+ for (auto const& language : languages) {
+ std::string flags = cflags[language] + " " + defFlags;
+ if (language == "CXX" || language == "OBJCXX") {
+ if (language == "CXX" ||
+ !buildSettings->GetAttribute("OTHER_CPLUSPLUSFLAGS")) {
+ buildSettings->AddAttribute("OTHER_CPLUSPLUSFLAGS",
+ this->CreateString(flags));
+ }
+ } else if (language == "Fortran") {
+ buildSettings->AddAttribute("IFORT_OTHER_FLAGS",
+ this->CreateString(flags));
+ } else if (language == "C" || language == "OBJC") {
+ if (language == "C" || !buildSettings->GetAttribute("OTHER_CFLAGS")) {
+ buildSettings->AddAttribute("OTHER_CFLAGS", this->CreateString(flags));
+ }
+ } else if (language == "Swift") {
+ buildSettings->AddAttribute("OTHER_SWIFT_FLAGS",
+ this->CreateString(flags));
+ }
+ }
+
+ // Add Fortran source format attribute if property is set.
+ const char* format = nullptr;
+ std::string const& tgtfmt = gtgt->GetSafeProperty("Fortran_FORMAT");
+ switch (cmOutputConverter::GetFortranFormat(tgtfmt)) {
+ case cmOutputConverter::FortranFormatFixed:
+ format = "fixed";
+ break;
+ case cmOutputConverter::FortranFormatFree:
+ format = "free";
+ break;
+ default:
+ break;
+ }
+ if (format) {
+ buildSettings->AddAttribute("IFORT_LANG_SRCFMT",
+ this->CreateString(format));
+ }
+
+ // Create the INSTALL_PATH attribute.
+ std::string install_name_dir;
+ if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ // Get the install_name directory for the build tree.
+ install_name_dir = gtgt->GetInstallNameDirForBuildTree(configName);
+ // Xcode doesn't create the correct install_name in some cases.
+ // That is, if the INSTALL_PATH is empty, or if we have versioning
+ // of dylib libraries, we want to specify the install_name.
+ // This is done by adding a link flag to create an install_name
+ // with just the library soname.
+ std::string install_name;
+ if (!install_name_dir.empty()) {
+ // Convert to a path for the native build tool.
+ cmSystemTools::ConvertToUnixSlashes(install_name_dir);
+ install_name += install_name_dir;
+ install_name += "/";
+ }
+ install_name += gtgt->GetSOName(configName);
+
+ if ((realName != soName) || install_name_dir.empty()) {
+ install_name_dir = "";
+ extraLinkOptions += " -install_name ";
+ extraLinkOptions += XCodeEscapePath(install_name);
+ }
+ }
+ buildSettings->AddAttribute("INSTALL_PATH",
+ this->CreateString(install_name_dir));
+
+ // Create the LD_RUNPATH_SEARCH_PATHS
+ cmComputeLinkInformation* pcli = gtgt->GetLinkInformation(configName);
+ if (pcli) {
+ std::string search_paths;
+ std::vector<std::string> runtimeDirs;
+ pcli->GetRPath(runtimeDirs, false);
+ // runpath dirs needs to be unique to prevent corruption
+ std::set<std::string> unique_dirs;
+
+ for (auto runpath : runtimeDirs) {
+ runpath = this->ExpandCFGIntDir(runpath, configName);
+
+ if (unique_dirs.find(runpath) == unique_dirs.end()) {
+ unique_dirs.insert(runpath);
+ if (!search_paths.empty()) {
+ search_paths += " ";
+ }
+ search_paths += this->XCodeEscapePath(runpath);
+ }
+ }
+ if (!search_paths.empty()) {
+ buildSettings->AddAttribute("LD_RUNPATH_SEARCH_PATHS",
+ this->CreateString(search_paths));
+ }
+ }
+
+ buildSettings->AddAttribute(this->GetTargetLinkFlagsVar(gtgt),
+ this->CreateString(extraLinkOptions));
+ buildSettings->AddAttribute("OTHER_REZFLAGS", this->CreateString(""));
+ buildSettings->AddAttribute("SECTORDER_FLAGS", this->CreateString(""));
+ buildSettings->AddAttribute("USE_HEADERMAP", this->CreateString("NO"));
+ cmXCodeObject* group = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ group->AddObject(this->CreateString("$(inherited)"));
+ buildSettings->AddAttribute("WARNING_CFLAGS", group);
+
+ // Runtime version information.
+ if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ int major;
+ int minor;
+ int patch;
+
+ // MACHO_CURRENT_VERSION or VERSION -> current_version
+ gtgt->GetTargetVersionFallback("MACHO_CURRENT_VERSION", "VERSION", major,
+ minor, patch);
+ std::ostringstream v;
+
+ // Xcode always wants at least 1.0.0 or nothing
+ if (!(major == 0 && minor == 0 && patch == 0)) {
+ v << major << "." << minor << "." << patch;
+ }
+ buildSettings->AddAttribute("DYLIB_CURRENT_VERSION",
+ this->CreateString(v.str()));
+
+ // MACHO_COMPATIBILITY_VERSION or SOVERSION -> compatibility_version
+ gtgt->GetTargetVersionFallback("MACHO_COMPATIBILITY_VERSION", "SOVERSION",
+ major, minor, patch);
+ std::ostringstream vso;
+
+ // Xcode always wants at least 1.0.0 or nothing
+ if (!(major == 0 && minor == 0 && patch == 0)) {
+ vso << major << "." << minor << "." << patch;
+ }
+ buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION",
+ this->CreateString(vso.str()));
+ }
+
+ // Precompile Headers
+ std::string pchHeader = gtgt->GetPchHeader(configName, llang);
+ if (!pchHeader.empty()) {
+ buildSettings->AddAttribute("GCC_PREFIX_HEADER",
+ this->CreateString(pchHeader));
+ buildSettings->AddAttribute("GCC_PRECOMPILE_PREFIX_HEADER",
+ this->CreateString("YES"));
+ }
+
+ // put this last so it can override existing settings
+ // Convert "XCODE_ATTRIBUTE_*" properties directly.
+ {
+ for (auto const& prop : gtgt->GetPropertyKeys()) {
+ if (cmHasLiteralPrefix(prop, "XCODE_ATTRIBUTE_")) {
+ std::string attribute = prop.substr(16);
+ this->FilterConfigurationAttribute(configName, attribute);
+ if (!attribute.empty()) {
+ std::string const& pr = gtgt->GetSafeProperty(prop);
+ std::string processed = cmGeneratorExpression::Evaluate(
+ pr, this->CurrentLocalGenerator, configName);
+ buildSettings->AddAttribute(attribute,
+ this->CreateString(processed));
+ }
+ }
+ }
+ }
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateUtilityTarget(
+ cmGeneratorTarget* gtgt)
+{
+ cmXCodeObject* shellBuildPhase = this->CreateObject(
+ cmXCodeObject::PBXShellScriptBuildPhase, gtgt->GetName());
+ shellBuildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ shellBuildPhase->AddAttribute("files", buildFiles);
+ cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ shellBuildPhase->AddAttribute("inputPaths", inputPaths);
+ cmXCodeObject* outputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ shellBuildPhase->AddAttribute("outputPaths", outputPaths);
+ shellBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ shellBuildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh"));
+ shellBuildPhase->AddAttribute(
+ "shellScript", this->CreateString("# shell script goes here\nexit 0"));
+ shellBuildPhase->AddAttribute("showEnvVarsInLog", this->CreateString("0"));
+
+ cmXCodeObject* target =
+ this->CreateObject(cmXCodeObject::PBXAggregateTarget);
+ target->SetComment(gtgt->GetName());
+ cmXCodeObject* buildPhases = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ std::vector<cmXCodeObject*> emptyContentVector;
+ this->CreateCustomCommands(buildPhases, nullptr, nullptr, nullptr,
+ emptyContentVector, nullptr, gtgt);
+ target->AddAttribute("buildPhases", buildPhases);
+ this->AddConfigurations(target, gtgt);
+ cmXCodeObject* dependencies = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ target->AddAttribute("dependencies", dependencies);
+ target->AddAttribute("name", this->CreateString(gtgt->GetName()));
+ target->AddAttribute("productName", this->CreateString(gtgt->GetName()));
+ target->SetTarget(gtgt);
+ this->XCodeObjectMap[gtgt] = target;
+
+ // Add source files without build rules for editing convenience.
+ if (gtgt->GetType() != cmStateEnums::GLOBAL_TARGET &&
+ gtgt->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
+ std::vector<cmSourceFile*> sources;
+ if (!gtgt->GetConfigCommonSourceFilesForXcode(sources)) {
+ return nullptr;
+ }
+
+ // Add CMakeLists.txt file for user convenience.
+ this->AddXCodeProjBuildRule(gtgt, sources);
+
+ for (auto sourceFile : sources) {
+ if (!sourceFile->GetIsGenerated()) {
+ this->CreateXCodeFileReference(sourceFile, gtgt);
+ }
+ }
+ }
+
+ target->SetId(this->GetOrCreateId(gtgt->GetName(), target->GetId()));
+
+ return target;
+}
+
+std::string cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target,
+ cmGeneratorTarget* gtgt)
+{
+ std::vector<std::string> const configVector = cmExpandedList(
+ this->CurrentMakefile->GetRequiredDefinition("CMAKE_CONFIGURATION_TYPES"));
+ cmXCodeObject* configlist =
+ this->CreateObject(cmXCodeObject::XCConfigurationList);
+ cmXCodeObject* buildConfigurations =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ configlist->AddAttribute("buildConfigurations", buildConfigurations);
+ std::string comment = cmStrCat("Build configuration list for ",
+ cmXCodeObject::PBXTypeNames[target->GetIsA()],
+ " \"", gtgt->GetName(), '"');
+ configlist->SetComment(comment);
+ target->AddAttribute("buildConfigurationList",
+ this->CreateObjectReference(configlist));
+ for (auto const& i : configVector) {
+ cmXCodeObject* config =
+ this->CreateObject(cmXCodeObject::XCBuildConfiguration);
+ buildConfigurations->AddObject(config);
+ cmXCodeObject* buildSettings =
+ this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ this->CreateBuildSettings(gtgt, buildSettings, i);
+ config->AddAttribute("name", this->CreateString(i));
+ config->SetComment(i);
+ config->AddAttribute("buildSettings", buildSettings);
+ }
+ if (!configVector.empty()) {
+ configlist->AddAttribute("defaultConfigurationName",
+ this->CreateString(configVector[0]));
+ configlist->AddAttribute("defaultConfigurationIsVisible",
+ this->CreateString("0"));
+ return configVector[0];
+ }
+ return "";
+}
+
+const char* cmGlobalXCodeGenerator::GetTargetLinkFlagsVar(
+ cmGeneratorTarget const* target) const
+{
+ if (this->XcodeVersion >= 60 &&
+ (target->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ target->GetType() == cmStateEnums::OBJECT_LIBRARY)) {
+ return "OTHER_LIBTOOLFLAGS";
+ }
+ return "OTHER_LDFLAGS";
+}
+
+const char* cmGlobalXCodeGenerator::GetTargetFileType(
+ cmGeneratorTarget* target)
+{
+ if (cmProp e = target->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) {
+ return e->c_str();
+ }
+
+ switch (target->GetType()) {
+ case cmStateEnums::OBJECT_LIBRARY:
+ return "archive.ar";
+ case cmStateEnums::STATIC_LIBRARY:
+ return (target->GetPropertyAsBool("FRAMEWORK") ? "wrapper.framework"
+ : "archive.ar");
+ case cmStateEnums::MODULE_LIBRARY:
+ if (target->IsXCTestOnApple()) {
+ return "wrapper.cfbundle";
+ }
+ if (target->IsCFBundleOnApple()) {
+ return "wrapper.plug-in";
+ }
+ return "compiled.mach-o.executable";
+ case cmStateEnums::SHARED_LIBRARY:
+ return (target->GetPropertyAsBool("FRAMEWORK")
+ ? "wrapper.framework"
+ : "compiled.mach-o.dylib");
+ case cmStateEnums::EXECUTABLE:
+ return "compiled.mach-o.executable";
+ default:
+ break;
+ }
+ return nullptr;
+}
+
+const char* cmGlobalXCodeGenerator::GetTargetProductType(
+ cmGeneratorTarget* target)
+{
+ if (cmProp e = target->GetProperty("XCODE_PRODUCT_TYPE")) {
+ return e->c_str();
+ }
+
+ switch (target->GetType()) {
+ case cmStateEnums::OBJECT_LIBRARY:
+ return "com.apple.product-type.library.static";
+ case cmStateEnums::STATIC_LIBRARY:
+ return (target->GetPropertyAsBool("FRAMEWORK")
+ ? "com.apple.product-type.framework"
+ : "com.apple.product-type.library.static");
+ case cmStateEnums::MODULE_LIBRARY:
+ if (target->IsXCTestOnApple()) {
+ return "com.apple.product-type.bundle.unit-test";
+ } else if (target->IsCFBundleOnApple()) {
+ return "com.apple.product-type.bundle";
+ } else {
+ return "com.apple.product-type.tool";
+ }
+ case cmStateEnums::SHARED_LIBRARY:
+ return (target->GetPropertyAsBool("FRAMEWORK")
+ ? "com.apple.product-type.framework"
+ : "com.apple.product-type.library.dynamic");
+ case cmStateEnums::EXECUTABLE:
+ return (target->GetPropertyAsBool("MACOSX_BUNDLE")
+ ? "com.apple.product-type.application"
+ : "com.apple.product-type.tool");
+ default:
+ break;
+ }
+ return nullptr;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeTarget(
+ cmGeneratorTarget* gtgt, cmXCodeObject* buildPhases)
+{
+ if (!gtgt->IsInBuildSystem()) {
+ return nullptr;
+ }
+ cmXCodeObject* target = this->CreateObject(cmXCodeObject::PBXNativeTarget);
+ target->AddAttribute("buildPhases", buildPhases);
+ cmXCodeObject* buildRules = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ target->AddAttribute("buildRules", buildRules);
+ std::string defConfig;
+ defConfig = this->AddConfigurations(target, gtgt);
+ cmXCodeObject* dependencies = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ target->AddAttribute("dependencies", dependencies);
+ target->AddAttribute("name", this->CreateString(gtgt->GetName()));
+ target->AddAttribute("productName", this->CreateString(gtgt->GetName()));
+
+ cmXCodeObject* fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
+ if (const char* fileType = this->GetTargetFileType(gtgt)) {
+ fileRef->AddAttribute("explicitFileType", this->CreateString(fileType));
+ }
+ std::string fullName;
+ if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ fullName = cmStrCat("lib", gtgt->GetName(), ".a");
+ } else {
+ fullName = gtgt->GetFullName(defConfig);
+ }
+ fileRef->AddAttribute("path", this->CreateString(fullName));
+ fileRef->AddAttribute("sourceTree",
+ this->CreateString("BUILT_PRODUCTS_DIR"));
+ fileRef->SetComment(gtgt->GetName());
+ target->AddAttribute("productReference",
+ this->CreateObjectReference(fileRef));
+ if (const char* productType = this->GetTargetProductType(gtgt)) {
+ target->AddAttribute("productType", this->CreateString(productType));
+ }
+ target->SetTarget(gtgt);
+ this->XCodeObjectMap[gtgt] = target;
+ target->SetId(this->GetOrCreateId(gtgt->GetName(), target->GetId()));
+ return target;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::FindXCodeTarget(
+ cmGeneratorTarget const* t)
+{
+ if (!t) {
+ return nullptr;
+ }
+
+ auto const i = this->XCodeObjectMap.find(t);
+ if (i == this->XCodeObjectMap.end()) {
+ return nullptr;
+ }
+ return i->second;
+}
+
+std::string cmGlobalXCodeGenerator::GetObjectId(cmXCodeObject::PBXType ptype,
+ cm::string_view key)
+{
+ std::string objectId;
+ if (!key.empty()) {
+ cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
+ hash.Initialize();
+ hash.Append(&ptype, sizeof(ptype));
+ hash.Append(key);
+ objectId = cmSystemTools::UpperCase(hash.FinalizeHex().substr(0, 24));
+ } else {
+ char cUuid[40] = { 0 };
+ CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
+ CFStringRef s = CFUUIDCreateString(kCFAllocatorDefault, uuid);
+ CFStringGetCString(s, cUuid, sizeof(cUuid), kCFStringEncodingUTF8);
+ objectId = cUuid;
+ CFRelease(s);
+ CFRelease(uuid);
+ cmSystemTools::ReplaceString(objectId, "-", "");
+ if (objectId.size() > 24) {
+ objectId = objectId.substr(0, 24);
+ }
+ }
+ return objectId;
+}
+
+std::string cmGlobalXCodeGenerator::GetOrCreateId(const std::string& name,
+ const std::string& id)
+{
+ std::string guidStoreName = cmStrCat(name, "_GUID_CMAKE");
+ cmProp storedGUID = this->CMakeInstance->GetCacheDefinition(guidStoreName);
+
+ if (storedGUID) {
+ return *storedGUID;
+ }
+
+ this->CMakeInstance->AddCacheEntry(guidStoreName, id.c_str(),
+ "Stored Xcode object GUID",
+ cmStateEnums::INTERNAL);
+
+ return id;
+}
+
+void cmGlobalXCodeGenerator::AddDependTarget(cmXCodeObject* target,
+ cmXCodeObject* dependTarget)
+{
+ // This is called once for every edge in the target dependency graph.
+ cmXCodeObject* container =
+ this->CreateObject(cmXCodeObject::PBXContainerItemProxy);
+ container->SetComment("PBXContainerItemProxy");
+ container->AddAttribute("containerPortal",
+ this->CreateObjectReference(this->RootObject));
+ container->AddAttribute("proxyType", this->CreateString("1"));
+ container->AddAttribute("remoteGlobalIDString",
+ this->CreateObjectReference(dependTarget));
+ container->AddAttribute(
+ "remoteInfo", this->CreateString(dependTarget->GetTarget()->GetName()));
+ cmXCodeObject* targetdep =
+ this->CreateObject(cmXCodeObject::PBXTargetDependency);
+ targetdep->SetComment("PBXTargetDependency");
+ targetdep->AddAttribute("target", this->CreateObjectReference(dependTarget));
+ targetdep->AddAttribute("targetProxy",
+ this->CreateObjectReference(container));
+
+ cmXCodeObject* depends = target->GetAttribute("dependencies");
+ if (!depends) {
+ cmSystemTools::Error(
+ "target does not have dependencies attribute error..");
+
+ } else {
+ depends->AddUniqueObject(targetdep);
+ }
+}
+
+void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings,
+ const char* attribute,
+ cmXCodeObject* value)
+{
+ if (settings) {
+ cmXCodeObject* attr = settings->GetAttribute(attribute);
+ if (!attr) {
+ settings->AddAttribute(attribute, value);
+ } else {
+ this->AppendBuildSettingAttribute(settings, attribute, attr, value);
+ }
+ }
+}
+
+void cmGlobalXCodeGenerator::AppendBuildSettingAttribute(
+ cmXCodeObject* settings, const char* attribute, cmXCodeObject* attr,
+ cmXCodeObject* value)
+{
+ if (value->GetType() != cmXCodeObject::OBJECT_LIST &&
+ value->GetType() != cmXCodeObject::STRING) {
+ cmSystemTools::Error("Unsupported value type for appending: " +
+ std::string(attribute));
+ return;
+ }
+ if (attr->GetType() == cmXCodeObject::OBJECT_LIST) {
+ if (value->GetType() == cmXCodeObject::OBJECT_LIST) {
+ for (auto* obj : value->GetObjectList()) {
+ attr->AddObject(obj);
+ }
+ } else {
+ attr->AddObject(value);
+ }
+ } else if (attr->GetType() == cmXCodeObject::STRING) {
+ if (value->GetType() == cmXCodeObject::OBJECT_LIST) {
+ // Add old value as a list item to new object list
+ // and replace the attribute with the new list
+ value->PrependObject(attr);
+ settings->AddAttribute(attribute, value);
+ } else {
+ std::string newValue =
+ cmStrCat(attr->GetString(), ' ', value->GetString());
+ attr->SetString(newValue);
+ }
+ } else {
+ cmSystemTools::Error("Unsupported attribute type for appending: " +
+ std::string(attribute));
+ }
+}
+
+void cmGlobalXCodeGenerator::AppendBuildSettingAttribute(
+ cmXCodeObject* target, const char* attribute, cmXCodeObject* value,
+ const std::string& configName)
+{
+ // There are multiple configurations. Add the setting to the
+ // buildSettings of the configuration name given.
+ cmXCodeObject* configurationList =
+ target->GetAttribute("buildConfigurationList")->GetObject();
+ cmXCodeObject* buildConfigs =
+ configurationList->GetAttribute("buildConfigurations");
+ for (auto obj : buildConfigs->GetObjectList()) {
+ if (configName.empty() ||
+ obj->GetAttribute("name")->GetString() == configName) {
+ cmXCodeObject* settings = obj->GetAttribute("buildSettings");
+ this->AppendOrAddBuildSetting(settings, attribute, value);
+ }
+ }
+}
+
+void cmGlobalXCodeGenerator::InheritBuildSettingAttribute(
+ cmXCodeObject* target, const char* attribute)
+{
+ cmXCodeObject* configurationList =
+ target->GetAttribute("buildConfigurationList")->GetObject();
+ cmXCodeObject* buildConfigs =
+ configurationList->GetAttribute("buildConfigurations");
+ for (auto obj : buildConfigs->GetObjectList()) {
+ cmXCodeObject* settings = obj->GetAttribute("buildSettings");
+ if (cmXCodeObject* attr = settings->GetAttribute(attribute)) {
+ BuildObjectListOrString inherited(this, true);
+ inherited.Add("$(inherited)");
+ this->AppendBuildSettingAttribute(settings, attribute, attr,
+ inherited.CreateList());
+ }
+ }
+}
+
+void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
+{
+ cmGeneratorTarget* gt = target->GetTarget();
+ if (!gt) {
+ cmSystemTools::Error("Error no target on xobject\n");
+ return;
+ }
+ if (!gt->IsInBuildSystem()) {
+ return;
+ }
+
+ // Add dependencies on other CMake targets.
+ for (const auto& dep : this->GetTargetDirectDepends(gt)) {
+ if (cmXCodeObject* dptarget = this->FindXCodeTarget(dep)) {
+ this->AddDependTarget(target, dptarget);
+ }
+ }
+
+ // Separate libraries into ones that can be linked using "Link Binary With
+ // Libraries" build phase and the ones that can't. Only targets that build
+ // Apple bundles (.app, .framework, .bundle), executables and dylibs can use
+ // this feature and only targets that represent actual libraries (object,
+ // static, dynamic or bundle, excluding executables) will be used. These are
+ // limitations imposed by CMake use-cases - otherwise a lot of things break.
+ // The rest will be linked using linker flags (OTHER_LDFLAGS setting in Xcode
+ // project).
+ std::map<std::string, std::vector<cmComputeLinkInformation::Item const*>>
+ configItemMap;
+ auto addToLinkerArguments =
+ [&configItemMap](const std::string& configName,
+ cmComputeLinkInformation::Item const* libItemPtr) {
+ auto& linkVector = configItemMap[configName];
+ if (std::find_if(linkVector.begin(), linkVector.end(),
+ [libItemPtr](cmComputeLinkInformation::Item const* p) {
+ return p == libItemPtr;
+ }) == linkVector.end()) {
+ linkVector.push_back(libItemPtr);
+ }
+ };
+ std::vector<cmComputeLinkInformation::Item const*> linkPhaseTargetVector;
+ std::map<std::string, std::vector<std::string>> targetConfigMap;
+ using ConfigItemPair =
+ std::pair<std::string, cmComputeLinkInformation::Item const*>;
+ std::map<std::string, std::vector<ConfigItemPair>> targetItemMap;
+ std::map<std::string, std::vector<std::string>> targetProductNameMap;
+ bool useLinkPhase = false;
+ bool forceLinkPhase = false;
+ cmProp prop =
+ target->GetTarget()->GetProperty("XCODE_LINK_BUILD_PHASE_MODE");
+ if (prop) {
+ if (*prop == "BUILT_ONLY") {
+ useLinkPhase = true;
+ } else if (*prop == "KNOWN_LOCATION") {
+ useLinkPhase = true;
+ forceLinkPhase = true;
+ } else if (*prop != "NONE") {
+ cmSystemTools::Error("Invalid value for XCODE_LINK_BUILD_PHASE_MODE: " +
+ *prop);
+ return;
+ }
+ }
+ for (auto const& configName : this->CurrentConfigurationTypes) {
+ cmComputeLinkInformation* cli = gt->GetLinkInformation(configName);
+ if (!cli) {
+ continue;
+ }
+ for (auto const& libItem : cli->GetItems()) {
+ // We want to put only static libraries, dynamic libraries, frameworks
+ // and bundles that are built from targets that are not imported in "Link
+ // Binary With Libraries" build phase. Except if the target property
+ // XCODE_LINK_BUILD_PHASE_MODE is KNOWN_LOCATION then all imported and
+ // non-target libraries will be added as well.
+ if (useLinkPhase &&
+ (gt->GetType() == cmStateEnums::EXECUTABLE ||
+ gt->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ gt->GetType() == cmStateEnums::MODULE_LIBRARY) &&
+ ((libItem.Target &&
+ (!libItem.Target->IsImported() || forceLinkPhase) &&
+ (libItem.Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ libItem.Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ libItem.Target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ libItem.Target->GetType() == cmStateEnums::UNKNOWN_LIBRARY)) ||
+ (!libItem.Target && libItem.IsPath && forceLinkPhase))) {
+ std::string libName;
+ bool canUseLinkPhase = true;
+ if (libItem.Target) {
+ if (libItem.Target->GetType() == cmStateEnums::UNKNOWN_LIBRARY) {
+ canUseLinkPhase = canUseLinkPhase && forceLinkPhase;
+ } else {
+ // If a library target uses custom build output directory Xcode
+ // won't pick it up so we have to resort back to linker flags, but
+ // that's OK as long as the custom output dir is absolute path.
+ for (auto const& libConfigName : this->CurrentConfigurationTypes) {
+ canUseLinkPhase = canUseLinkPhase &&
+ libItem.Target->UsesDefaultOutputDir(
+ libConfigName, cmStateEnums::RuntimeBinaryArtifact);
+ }
+ }
+ libName = libItem.Target->GetName();
+ } else {
+ libName = cmSystemTools::GetFilenameName(libItem.Value.Value);
+ // We don't want all the possible files here, just standard libraries
+ const auto libExt = cmSystemTools::GetFilenameExtension(libName);
+ if (!IsLinkPhaseLibraryExtension(libExt)) {
+ canUseLinkPhase = false;
+ }
+ }
+ if (canUseLinkPhase) {
+ // Add unique configuration name to target-config map for later
+ // checks
+ auto& configVector = targetConfigMap[libName];
+ if (std::find(configVector.begin(), configVector.end(),
+ configName) == configVector.end()) {
+ configVector.push_back(configName);
+ }
+ // Add a pair of config and item to target-item map
+ auto& itemVector = targetItemMap[libName];
+ itemVector.emplace_back(ConfigItemPair(configName, &libItem));
+ // Add product file-name to a lib-product map
+ auto productName =
+ cmSystemTools::GetFilenameName(libItem.Value.Value);
+ auto& productVector = targetProductNameMap[libName];
+ if (std::find(productVector.begin(), productVector.end(),
+ productName) == productVector.end()) {
+ productVector.push_back(productName);
+ }
+ continue;
+ }
+ }
+ // Add this library item to a regular linker flag list
+ addToLinkerArguments(configName, &libItem);
+ }
+ }
+
+ // Go through target library map and separate libraries that are linked
+ // in all configurations and produce only single product, from the rest.
+ // Only these will be linked through "Link Binary With Libraries" build
+ // phase.
+ for (auto const& targetLibConfigs : targetConfigMap) {
+ // Add this library to "Link Binary With Libraries" build phase if it's
+ // linked in all configurations and it has only one product name
+ auto& itemVector = targetItemMap[targetLibConfigs.first];
+ auto& productVector = targetProductNameMap[targetLibConfigs.first];
+ if (targetLibConfigs.second == this->CurrentConfigurationTypes &&
+ productVector.size() == 1) {
+ // Add this library to "Link Binary With Libraries" list
+ linkPhaseTargetVector.push_back(itemVector[0].second);
+ } else {
+ for (auto const& libItem : targetItemMap[targetLibConfigs.first]) {
+ // Add this library item to a regular linker flag list
+ addToLinkerArguments(libItem.first, libItem.second);
+ }
+ }
+ }
+
+ // Add libraries to "Link Binary With Libraries" build phase and collect
+ // their search paths. Xcode does not support per-configuration linking
+ // in this build phase so we don't have to do this for each configuration
+ // separately.
+ std::vector<std::string> linkSearchPaths;
+ std::vector<std::string> frameworkSearchPaths;
+ for (auto const& libItem : linkPhaseTargetVector) {
+ // Add target output directory as a library search path
+ std::string linkDir;
+ if (libItem->Target) {
+ linkDir = libItem->Target->GetLocationForBuild();
+ } else {
+ linkDir = libItem->Value.Value;
+ }
+ linkDir = GetLibraryOrFrameworkPath(linkDir);
+ bool isFramework = cmSystemTools::IsPathToFramework(linkDir);
+ linkDir = cmSystemTools::GetParentDirectory(linkDir);
+ if (isFramework) {
+ if (std::find(frameworkSearchPaths.begin(), frameworkSearchPaths.end(),
+ linkDir) == frameworkSearchPaths.end()) {
+ frameworkSearchPaths.push_back(linkDir);
+ }
+ } else {
+ if (std::find(linkSearchPaths.begin(), linkSearchPaths.end(), linkDir) ==
+ linkSearchPaths.end()) {
+ linkSearchPaths.push_back(linkDir);
+ }
+ }
+ // Add target dependency
+ if (libItem->Target && !libItem->Target->IsImported()) {
+ for (auto const& configName : this->CurrentConfigurationTypes) {
+ target->AddDependTarget(configName, libItem->Target->GetName());
+ }
+ }
+ // Get the library target
+ auto* libTarget = FindXCodeTarget(libItem->Target);
+ cmXCodeObject* buildFile;
+ if (!libTarget) {
+ if (libItem->IsPath) {
+ // Get or create a direct file ref in the root project
+ auto cleanPath = libItem->Value.Value;
+ if (cmSystemTools::FileIsFullPath(cleanPath)) {
+ // Some arguments are reported as paths, but they are actually not,
+ // so we can't collapse them, and neither can we collapse relative
+ // paths
+ cleanPath = cmSystemTools::CollapseFullPath(cleanPath);
+ }
+ auto it = this->ExternalLibRefs.find(cleanPath);
+ if (it == this->ExternalLibRefs.end()) {
+ buildFile = CreateXCodeBuildFileFromPath(cleanPath, gt, "", nullptr);
+ if (!buildFile) {
+ // Add this library item back to a regular linker flag list
+ for (const auto& conf : configItemMap) {
+ addToLinkerArguments(conf.first, libItem);
+ }
+ continue;
+ }
+ this->ExternalLibRefs.emplace(cleanPath, buildFile);
+ } else {
+ buildFile = it->second;
+ }
+ } else {
+ // Add this library item back to a regular linker flag list
+ for (const auto& conf : configItemMap) {
+ addToLinkerArguments(conf.first, libItem);
+ }
+ continue;
+ }
+ } else {
+ // Add the target output file as a build reference for other targets
+ // to link against
+ auto* fileRefObject = libTarget->GetAttribute("productReference");
+ if (!fileRefObject) {
+ // Add this library item back to a regular linker flag list
+ for (const auto& conf : configItemMap) {
+ addToLinkerArguments(conf.first, libItem);
+ }
+ continue;
+ }
+ auto it = FileRefToBuildFileMap.find(fileRefObject);
+ if (it == FileRefToBuildFileMap.end()) {
+ buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
+ buildFile->AddAttribute("fileRef", fileRefObject);
+ FileRefToBuildFileMap[fileRefObject] = buildFile;
+ } else {
+ buildFile = it->second;
+ }
+ }
+ // Add this reference to current target
+ auto* buildPhases = target->GetAttribute("buildPhases");
+ if (!buildPhases) {
+ cmSystemTools::Error("Missing buildPhase of target");
+ continue;
+ }
+ auto* frameworkBuildPhase =
+ buildPhases->GetObject(cmXCodeObject::PBXFrameworksBuildPhase);
+ if (!frameworkBuildPhase) {
+ cmSystemTools::Error("Missing PBXFrameworksBuildPhase of buildPhase");
+ continue;
+ }
+ auto* buildFiles = frameworkBuildPhase->GetAttribute("files");
+ if (!buildFiles) {
+ cmSystemTools::Error("Missing files of PBXFrameworksBuildPhase");
+ continue;
+ }
+ if (buildFile && !buildFiles->HasObject(buildFile)) {
+ buildFiles->AddObject(buildFile);
+ }
+ }
+
+ // Loop over configuration types and set per-configuration info.
+ for (auto const& configName : this->CurrentConfigurationTypes) {
+ {
+ // Add object library contents as link flags.
+ BuildObjectListOrString libSearchPaths(this, true);
+ std::vector<cmSourceFile const*> objs;
+ gt->GetExternalObjects(objs, configName);
+ for (auto sourceFile : objs) {
+ if (sourceFile->GetObjectLibrary().empty()) {
+ continue;
+ }
+ libSearchPaths.Add(this->XCodeEscapePath(sourceFile->GetFullPath()));
+ }
+ this->AppendBuildSettingAttribute(
+ target, this->GetTargetLinkFlagsVar(gt), libSearchPaths.CreateList(),
+ configName);
+ }
+
+ // Skip link information for object libraries.
+ if (gt->GetType() == cmStateEnums::OBJECT_LIBRARY ||
+ gt->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ continue;
+ }
+
+ // Compute the link library and directory information.
+ cmComputeLinkInformation* cli = gt->GetLinkInformation(configName);
+ if (!cli) {
+ continue;
+ }
+
+ // Add dependencies directly on library files.
+ for (auto const& libDep : cli->GetDepends()) {
+ target->AddDependLibrary(configName, libDep);
+ }
+
+ // add the library search paths
+ {
+ BuildObjectListOrString libSearchPaths(this, true);
+ std::string linkDirs;
+ for (auto const& libDir : cli->GetDirectories()) {
+ if (!libDir.empty() && libDir != "/usr/lib") {
+ libSearchPaths.Add(this->XCodeEscapePath(
+ libDir + "/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"));
+ libSearchPaths.Add(this->XCodeEscapePath(libDir));
+ }
+ }
+ // Add previously collected paths where to look for libraries
+ // that were added to "Link Binary With Libraries"
+ for (auto& libDir : linkSearchPaths) {
+ libSearchPaths.Add(this->XCodeEscapePath(libDir));
+ }
+ if (!libSearchPaths.IsEmpty()) {
+ this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
+ libSearchPaths.CreateList(),
+ configName);
+ }
+ }
+
+ // add framework search paths
+ {
+ BuildObjectListOrString fwSearchPaths(this, true);
+ // Add previously collected paths where to look for frameworks
+ // that were added to "Link Binary With Libraries"
+ for (auto& fwDir : frameworkSearchPaths) {
+ fwSearchPaths.Add(this->XCodeEscapePath(fwDir));
+ }
+ if (!fwSearchPaths.IsEmpty()) {
+ this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS",
+ fwSearchPaths.CreateList(),
+ configName);
+ }
+ }
+
+ // now add the left-over link libraries
+ {
+ // Keep track of framework search paths we've already added or that are
+ // part of the set of implicit search paths. We don't want to repeat
+ // them and we also need to avoid hard-coding any SDK-specific paths.
+ // This is essential for getting device-and-simulator builds to work,
+ // otherwise we end up hard-coding a path to the wrong SDK for
+ // SDK-provided frameworks that are added by their full path.
+ std::set<std::string> emitted(cli->GetFrameworkPathsEmitted());
+ const auto& fwPaths = cli->GetFrameworkPaths();
+ emitted.insert(fwPaths.begin(), fwPaths.end());
+ BuildObjectListOrString libPaths(this, true);
+ for (auto const& libItem : configItemMap[configName]) {
+ auto const& libName = *libItem;
+ if (libName.IsPath) {
+ auto cleanPath = libName.Value.Value;
+ if (cmSystemTools::FileIsFullPath(cleanPath)) {
+ cleanPath = cmSystemTools::CollapseFullPath(cleanPath);
+ }
+ const auto libPath = GetLibraryOrFrameworkPath(cleanPath);
+ if (cmSystemTools::StringEndsWith(libPath.c_str(), ".framework")) {
+ const auto fwName =
+ cmSystemTools::GetFilenameWithoutExtension(libPath);
+ const auto fwDir = cmSystemTools::GetParentDirectory(libPath);
+ if (emitted.insert(fwDir).second) {
+ // This is a search path we had not added before and it isn't an
+ // implicit search path, so we need it
+ libPaths.Add("-F " + this->XCodeEscapePath(fwDir));
+ }
+ libPaths.Add("-framework " + this->XCodeEscapePath(fwName));
+ } else {
+ libPaths.Add(this->XCodeEscapePath(cleanPath));
+ }
+ if ((!libName.Target || libName.Target->IsImported()) &&
+ IsLinkPhaseLibraryExtension(libPath)) {
+ // Create file reference for embedding
+ auto it = this->ExternalLibRefs.find(cleanPath);
+ if (it == this->ExternalLibRefs.end()) {
+ auto* buildFile =
+ this->CreateXCodeBuildFileFromPath(cleanPath, gt, "", nullptr);
+ if (buildFile) {
+ this->ExternalLibRefs.emplace(cleanPath, buildFile);
+ }
+ }
+ }
+ } else if (!libName.Target ||
+ libName.Target->GetType() !=
+ cmStateEnums::INTERFACE_LIBRARY) {
+ libPaths.Add(libName.Value.Value);
+ }
+ if (libName.Target && !libName.Target->IsImported()) {
+ target->AddDependTarget(configName, libName.Target->GetName());
+ }
+ }
+ this->AppendBuildSettingAttribute(target,
+ this->GetTargetLinkFlagsVar(gt),
+ libPaths.CreateList(), configName);
+ }
+ }
+}
+
+void cmGlobalXCodeGenerator::AddEmbeddedFrameworks(cmXCodeObject* target)
+{
+ cmGeneratorTarget* gt = target->GetTarget();
+ if (!gt) {
+ cmSystemTools::Error("Error no target on xobject\n");
+ return;
+ }
+ if (!gt->IsInBuildSystem()) {
+ return;
+ }
+ bool isFrameworkTarget = gt->IsFrameworkOnApple();
+ bool isBundleTarget = gt->GetPropertyAsBool("MACOSX_BUNDLE");
+ bool isCFBundleTarget = gt->IsCFBundleOnApple();
+ if (!(isFrameworkTarget || isBundleTarget || isCFBundleTarget)) {
+ return;
+ }
+ cmProp files = gt->GetProperty("XCODE_EMBED_FRAMEWORKS");
+ if (!files) {
+ return;
+ }
+
+ // Create an "Embedded Frameworks" build phase
+ auto* copyFilesBuildPhase =
+ this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase);
+ std::string copyFilesBuildPhaseName = "Embed Frameworks";
+ std::string destinationFrameworks = "10";
+ copyFilesBuildPhase->SetComment(copyFilesBuildPhaseName);
+ copyFilesBuildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ copyFilesBuildPhase->AddAttribute("dstSubfolderSpec",
+ this->CreateString(destinationFrameworks));
+ copyFilesBuildPhase->AddAttribute(
+ "name", this->CreateString(copyFilesBuildPhaseName));
+ if (cmProp fwEmbedPath = gt->GetProperty("XCODE_EMBED_FRAMEWORKS_PATH")) {
+ copyFilesBuildPhase->AddAttribute("dstPath",
+ this->CreateString(*fwEmbedPath));
+ } else {
+ copyFilesBuildPhase->AddAttribute("dstPath", this->CreateString(""));
+ }
+ copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ // Collect all embedded frameworks and add them to build phase
+ std::vector<std::string> relFiles = cmExpandedList(*files);
+ for (std::string const& relFile : relFiles) {
+ cmXCodeObject* buildFile{ nullptr };
+ std::string filePath = relFile;
+ auto* genTarget = FindGeneratorTarget(relFile);
+ if (genTarget) {
+ // This is a target - get it's product path reference
+ auto* xcTarget = FindXCodeTarget(genTarget);
+ if (!xcTarget) {
+ cmSystemTools::Error("Can not find a target for " +
+ genTarget->GetName());
+ continue;
+ }
+ // Add the target output file as a build reference for other targets
+ // to link against
+ auto* fileRefObject = xcTarget->GetAttribute("productReference");
+ if (!fileRefObject) {
+ cmSystemTools::Error("Target " + genTarget->GetName() +
+ " is missing product reference");
+ continue;
+ }
+ auto it = FileRefToEmbedBuildFileMap.find(fileRefObject);
+ if (it == FileRefToEmbedBuildFileMap.end()) {
+ buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
+ buildFile->AddAttribute("fileRef", fileRefObject);
+ FileRefToEmbedBuildFileMap[fileRefObject] = buildFile;
+ } else {
+ buildFile = it->second;
+ }
+ } else if (cmSystemTools::IsPathToFramework(relFile)) {
+ // This is a regular string path - create file reference
+ auto it = EmbeddedLibRefs.find(relFile);
+ if (it == EmbeddedLibRefs.end()) {
+ cmXCodeObject* fileRef =
+ this->CreateXCodeFileReferenceFromPath(relFile, gt, "", nullptr);
+ if (fileRef) {
+ buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
+ buildFile->SetComment(fileRef->GetComment());
+ buildFile->AddAttribute("fileRef",
+ this->CreateObjectReference(fileRef));
+ }
+ if (!buildFile) {
+ cmSystemTools::Error("Can't create build file for " + relFile);
+ continue;
+ }
+ this->EmbeddedLibRefs.emplace(filePath, buildFile);
+ } else {
+ buildFile = it->second;
+ }
+ }
+ if (!buildFile) {
+ cmSystemTools::Error("Can't find a build file for " + relFile);
+ continue;
+ }
+ // Set build file configuration
+ cmXCodeObject* settings =
+ this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ const auto& rmHeadersProp =
+ gt->GetSafeProperty("XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY");
+ if (cmIsOn(rmHeadersProp)) {
+ attrs->AddObject(this->CreateString("RemoveHeadersOnCopy"));
+ }
+ const auto& codeSignProp =
+ gt->GetSafeProperty("XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY");
+ if (cmIsOn(codeSignProp)) {
+ attrs->AddObject(this->CreateString("CodeSignOnCopy"));
+ }
+ settings->AddAttributeIfNotEmpty("ATTRIBUTES", attrs);
+ buildFile->AddAttributeIfNotEmpty("settings", settings);
+ if (!buildFiles->HasObject(buildFile)) {
+ buildFiles->AddObject(buildFile);
+ }
+ }
+ copyFilesBuildPhase->AddAttribute("files", buildFiles);
+ auto* buildPhases = target->GetAttribute("buildPhases");
+ // Insert embed build phase right before the post-build command
+ buildPhases->InsertObject(buildPhases->GetObjectCount() - 1,
+ copyFilesBuildPhase);
+}
+
+bool cmGlobalXCodeGenerator::CreateGroups(
+ std::vector<cmLocalGenerator*>& generators)
+{
+ for (auto& generator : generators) {
+ cmMakefile* mf = generator->GetMakefile();
+ std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups();
+ for (const auto& gtgt : generator->GetGeneratorTargets()) {
+ // Same skipping logic here as in CreateXCodeTargets so that we do not
+ // end up with (empty anyhow) ZERO_CHECK, install, or test source
+ // groups:
+ //
+ if (!gtgt->IsInBuildSystem() ||
+ gtgt->GetType() == cmStateEnums::GLOBAL_TARGET ||
+ gtgt->GetName() == CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
+ continue;
+ }
+
+ auto addSourceToGroup = [this, mf, &gtgt,
+ &sourceGroups](std::string const& source) {
+ cmSourceGroup* sourceGroup = mf->FindSourceGroup(source, sourceGroups);
+ cmXCodeObject* pbxgroup =
+ this->CreateOrGetPBXGroup(gtgt.get(), sourceGroup);
+ std::string key = GetGroupMapKeyFromPath(gtgt.get(), source);
+ this->GroupMap[key] = pbxgroup;
+ };
+
+ // Put cmSourceFile instances in proper groups:
+ for (auto const& si : gtgt->GetAllConfigSources()) {
+ cmSourceFile const* sf = si.Source;
+ if (!sf->GetObjectLibrary().empty()) {
+ // Object library files go on the link line instead.
+ continue;
+ }
+ addSourceToGroup(sf->GetFullPath());
+ }
+
+ // Add CMakeLists.txt file for user convenience.
+ {
+ std::string listfile =
+ cmStrCat(gtgt->GetLocalGenerator()->GetCurrentSourceDirectory(),
+ "/CMakeLists.txt");
+ cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(
+ listfile, false, cmSourceFileLocationKind::Known);
+ addSourceToGroup(sf->ResolveFullPath());
+ }
+
+ // Add the Info.plist we are about to generate for an App Bundle.
+ if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) {
+ std::string plist = this->ComputeInfoPListLocation(gtgt.get());
+ cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(
+ plist, true, cmSourceFileLocationKind::Known);
+ addSourceToGroup(sf->ResolveFullPath());
+ }
+ }
+ }
+ return true;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreatePBXGroup(cmXCodeObject* parent,
+ const std::string& name)
+{
+ cmXCodeObject* parentChildren = nullptr;
+ if (parent) {
+ parentChildren = parent->GetAttribute("children");
+ }
+ cmXCodeObject* group = this->CreateObject(cmXCodeObject::PBXGroup);
+ cmXCodeObject* groupChildren =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ group->AddAttribute("name", this->CreateString(name));
+ group->AddAttribute("children", groupChildren);
+ group->AddAttribute("sourceTree", this->CreateString("<group>"));
+ if (parentChildren) {
+ parentChildren->AddObject(group);
+ }
+ return group;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateOrGetPBXGroup(
+ cmGeneratorTarget* gtgt, cmSourceGroup* sg)
+{
+ std::string s;
+ std::string target;
+ const std::string targetFolder = gtgt->GetEffectiveFolderName();
+ if (!targetFolder.empty()) {
+ target = cmStrCat(targetFolder, '/');
+ }
+ target += gtgt->GetName();
+ s = cmStrCat(target, '/', sg->GetFullName());
+ auto it = this->GroupNameMap.find(s);
+ if (it != this->GroupNameMap.end()) {
+ return it->second;
+ }
+
+ it = this->TargetGroup.find(target);
+ cmXCodeObject* tgroup = nullptr;
+ if (it != this->TargetGroup.end()) {
+ tgroup = it->second;
+ } else {
+ std::vector<std::string> tgt_folders = cmTokenize(target, "/");
+ std::string curr_tgt_folder;
+ for (std::vector<std::string>::size_type i = 0; i < tgt_folders.size();
+ i++) {
+ if (i != 0) {
+ curr_tgt_folder += "/";
+ }
+ curr_tgt_folder += tgt_folders[i];
+ it = this->TargetGroup.find(curr_tgt_folder);
+ if (it != this->TargetGroup.end()) {
+ tgroup = it->second;
+ continue;
+ }
+ tgroup = this->CreatePBXGroup(tgroup, tgt_folders[i]);
+ this->TargetGroup[curr_tgt_folder] = tgroup;
+ if (i == 0) {
+ this->MainGroupChildren->AddObject(tgroup);
+ }
+ }
+ }
+ this->TargetGroup[target] = tgroup;
+
+ // If it's the default source group (empty name) then put the source file
+ // directly in the tgroup...
+ //
+ if (sg->GetFullName().empty()) {
+ this->GroupNameMap[s] = tgroup;
+ return tgroup;
+ }
+
+ // It's a recursive folder structure, let's find the real parent group
+ if (sg->GetFullName() != sg->GetName()) {
+ std::string curr_folder = cmStrCat(target, '/');
+ for (auto const& folder : cmTokenize(sg->GetFullName(), "\\")) {
+ curr_folder += folder;
+ auto const i_folder = this->GroupNameMap.find(curr_folder);
+ // Create new folder
+ if (i_folder == this->GroupNameMap.end()) {
+ cmXCodeObject* group = this->CreatePBXGroup(tgroup, folder);
+ this->GroupNameMap[curr_folder] = group;
+ tgroup = group;
+ } else {
+ tgroup = i_folder->second;
+ }
+ curr_folder += "\\";
+ }
+ return tgroup;
+ }
+ cmXCodeObject* group = this->CreatePBXGroup(tgroup, sg->GetName());
+ this->GroupNameMap[s] = group;
+ return group;
+}
+
+bool cmGlobalXCodeGenerator::CreateXCodeObjects(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
+{
+ this->ClearXCodeObjects();
+ this->RootObject = nullptr;
+ this->MainGroupChildren = nullptr;
+ this->FrameworkGroup = nullptr;
+ cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
+ cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (const std::string& CurrentConfigurationType :
+ this->CurrentConfigurationTypes) {
+ cmXCodeObject* buildStyle =
+ this->CreateObject(cmXCodeObject::PBXBuildStyle);
+ const std::string& name = CurrentConfigurationType;
+ buildStyle->AddAttribute("name", this->CreateString(name));
+ buildStyle->SetComment(name);
+ cmXCodeObject* sgroup = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ sgroup->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
+ buildStyle->AddAttribute("buildSettings", sgroup);
+ listObjs->AddObject(buildStyle);
+ }
+
+ cmXCodeObject* mainGroup = this->CreateObject(cmXCodeObject::PBXGroup);
+ this->MainGroupChildren = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ mainGroup->AddAttribute("children", this->MainGroupChildren);
+ mainGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
+
+ // now create the cmake groups
+ if (!this->CreateGroups(generators)) {
+ return false;
+ }
+
+ cmXCodeObject* productGroup = this->CreateObject(cmXCodeObject::PBXGroup);
+ productGroup->AddAttribute("name", this->CreateString("Products"));
+ productGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
+ cmXCodeObject* productGroupChildren =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ productGroup->AddAttribute("children", productGroupChildren);
+ this->MainGroupChildren->AddObject(productGroup);
+
+ this->FrameworkGroup = this->CreateObject(cmXCodeObject::PBXGroup);
+ this->FrameworkGroup->AddAttribute("name", this->CreateString("Frameworks"));
+ this->FrameworkGroup->AddAttribute("sourceTree",
+ this->CreateString("<group>"));
+ cmXCodeObject* frameworkGroupChildren =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ this->FrameworkGroup->AddAttribute("children", frameworkGroupChildren);
+ this->MainGroupChildren->AddObject(this->FrameworkGroup);
+
+ this->RootObject = this->CreateObject(cmXCodeObject::PBXProject);
+ this->RootObject->SetComment("Project object");
+
+ std::string project_id = cmStrCat("PROJECT_", root->GetProjectName());
+ this->RootObject->SetId(
+ this->GetOrCreateId(project_id, this->RootObject->GetId()));
+
+ group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ this->RootObject->AddAttribute("mainGroup",
+ this->CreateObjectReference(mainGroup));
+ this->RootObject->AddAttribute("buildSettings", group);
+ this->RootObject->AddAttribute("buildStyles", listObjs);
+ this->RootObject->AddAttribute("hasScannedForEncodings",
+ this->CreateString("0"));
+ group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ group->AddAttribute("BuildIndependentTargetsInParallel",
+ this->CreateString("YES"));
+ std::ostringstream v;
+ v << std::setfill('0') << std::setw(4) << XcodeVersion * 10;
+ group->AddAttribute("LastUpgradeCheck", this->CreateString(v.str()));
+ this->RootObject->AddAttribute("attributes", group);
+ this->RootObject->AddAttribute("compatibilityVersion",
+ this->CreateString("Xcode 3.2"));
+ // Point Xcode at the top of the source tree.
+ {
+ std::string pdir =
+ this->RelativeToBinary(root->GetCurrentSourceDirectory());
+ this->RootObject->AddAttribute("projectDirPath", this->CreateString(pdir));
+ this->RootObject->AddAttribute("projectRoot", this->CreateString(""));
+ }
+ cmXCodeObject* configlist =
+ this->CreateObject(cmXCodeObject::XCConfigurationList);
+ cmXCodeObject* buildConfigurations =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ using Configs = std::vector<std::pair<std::string, cmXCodeObject*>>;
+ Configs configs;
+ std::string defaultConfigName;
+ for (const auto& name : this->CurrentConfigurationTypes) {
+ if (defaultConfigName.empty()) {
+ defaultConfigName = name;
+ }
+ cmXCodeObject* config =
+ this->CreateObject(cmXCodeObject::XCBuildConfiguration);
+ config->AddAttribute("name", this->CreateString(name));
+ configs.push_back(std::make_pair(name, config));
+ }
+ if (defaultConfigName.empty()) {
+ defaultConfigName = "Debug";
+ }
+ for (auto& config : configs) {
+ buildConfigurations->AddObject(config.second);
+ }
+ configlist->AddAttribute("buildConfigurations", buildConfigurations);
+
+ std::string comment = cmStrCat("Build configuration list for PBXProject \"",
+ this->CurrentProject, '"');
+ configlist->SetComment(comment);
+ configlist->AddAttribute("defaultConfigurationIsVisible",
+ this->CreateString("0"));
+ configlist->AddAttribute("defaultConfigurationName",
+ this->CreateString(defaultConfigName));
+ cmXCodeObject* buildSettings =
+ this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+ cmProp sysroot = this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT");
+ cmProp deploymentTarget =
+ this->CurrentMakefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
+ if (sysroot) {
+ buildSettings->AddAttribute("SDKROOT", this->CreateString(*sysroot));
+ }
+ // recompute this as it may have been changed since enable language
+ this->ComputeArchitectures(this->CurrentMakefile);
+ std::string const archs = cmJoin(this->Architectures, " ");
+ if (archs.empty()) {
+ // Tell Xcode to use NATIVE_ARCH instead of ARCHS.
+ buildSettings->AddAttribute("ONLY_ACTIVE_ARCH", this->CreateString("YES"));
+ // When targeting macOS, use only the host architecture.
+ if (this->SystemName == "Darwin"_s &&
+ (!cmNonempty(sysroot) ||
+ cmSystemTools::LowerCase(*sysroot).find("macos") !=
+ std::string::npos)) {
+ buildSettings->AddAttribute("ARCHS",
+ this->CreateString("$(NATIVE_ARCH_ACTUAL)"));
+ }
+ } else {
+ // Tell Xcode to use ARCHS (ONLY_ACTIVE_ARCH defaults to NO).
+ buildSettings->AddAttribute("ARCHS", this->CreateString(archs));
+ }
+ if (cmNonempty(deploymentTarget)) {
+ buildSettings->AddAttribute(GetDeploymentPlatform(root->GetMakefile()),
+ this->CreateString(*deploymentTarget));
+ }
+ if (!this->GeneratorToolset.empty()) {
+ buildSettings->AddAttribute("GCC_VERSION",
+ this->CreateString(this->GeneratorToolset));
+ }
+ if (this->GetLanguageEnabled("Swift")) {
+ std::string swiftVersion;
+ if (cmProp vers = this->CurrentMakefile->GetDefinition(
+ "CMAKE_Swift_LANGUAGE_VERSION")) {
+ swiftVersion = *vers;
+ } else if (this->XcodeVersion >= 102) {
+ swiftVersion = "4.0";
+ } else if (this->XcodeVersion >= 83) {
+ swiftVersion = "3.0";
+ } else {
+ swiftVersion = "2.3";
+ }
+ buildSettings->AddAttribute("SWIFT_VERSION",
+ this->CreateString(swiftVersion));
+ }
+
+ std::string symroot = cmStrCat(root->GetCurrentBinaryDirectory(), "/build");
+ buildSettings->AddAttribute("SYMROOT", this->CreateString(symroot));
+
+ // Inside a try_compile project, do not require signing on any platform.
+ if (this->CMakeInstance->GetIsInTryCompile()) {
+ buildSettings->AddAttribute("CODE_SIGNING_ALLOWED",
+ this->CreateString("NO"));
+ }
+
+ for (auto& config : configs) {
+ cmXCodeObject* buildSettingsForCfg = this->CreateFlatClone(buildSettings);
+
+ // Put this last so it can override existing settings
+ // Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly.
+ for (const auto& var : this->CurrentMakefile->GetDefinitions()) {
+ if (cmHasLiteralPrefix(var, "CMAKE_XCODE_ATTRIBUTE_")) {
+ std::string attribute = var.substr(22);
+ this->FilterConfigurationAttribute(config.first, attribute);
+ if (!attribute.empty()) {
+ std::string processed = cmGeneratorExpression::Evaluate(
+ this->CurrentMakefile->GetSafeDefinition(var),
+ this->CurrentLocalGenerator, config.first);
+ buildSettingsForCfg->AddAttribute(attribute,
+ this->CreateString(processed));
+ }
+ }
+ }
+ // store per-config buildSettings into configuration object
+ config.second->AddAttribute("buildSettings", buildSettingsForCfg);
+ }
+
+ this->RootObject->AddAttribute("buildConfigurationList",
+ this->CreateObjectReference(configlist));
+
+ std::vector<cmXCodeObject*> targets;
+ for (auto& generator : generators) {
+ if (!this->CreateXCodeTargets(generator, targets)) {
+ return false;
+ }
+ for (auto const& ccRoot : this->CustomCommandRoots) {
+ if (ccRoot.second.size() > 1) {
+ std::string e = "The custom command ";
+ std::vector<std::string> const& outputs =
+ ccRoot.first->GetCustomCommand()->GetOutputs();
+ if (!outputs.empty()) {
+ e = cmStrCat(e, "generating\n ", outputs[0]);
+ } else {
+ e = cmStrCat(e, "driven by\n ", ccRoot.first->GetFullPath());
+ }
+ e = cmStrCat(e, "\nis attached to multiple targets:");
+ for (cmGeneratorTarget const* gt : ccRoot.second) {
+ e = cmStrCat(e, "\n ", gt->GetName());
+ }
+ e = cmStrCat(
+ e,
+ "\nbut none of these is a common dependency of the other(s). "
+ "This is not allowed by the Xcode \"new build system\".");
+ generator->IssueMessage(MessageType::FATAL_ERROR, e);
+ return false;
+ }
+ }
+ this->CustomCommandRoots.clear();
+ }
+ // loop over all targets and add link and depend info
+ for (auto t : targets) {
+ this->AddDependAndLinkInformation(t);
+ this->AddEmbeddedFrameworks(t);
+ // Inherit project-wide values for any target-specific search paths.
+ this->InheritBuildSettingAttribute(t, "HEADER_SEARCH_PATHS");
+ this->InheritBuildSettingAttribute(t, "SYSTEM_HEADER_SEARCH_PATHS");
+ this->InheritBuildSettingAttribute(t, "FRAMEWORK_SEARCH_PATHS");
+ this->InheritBuildSettingAttribute(t, "SYSTEM_FRAMEWORK_SEARCH_PATHS");
+ this->InheritBuildSettingAttribute(t, "LIBRARY_SEARCH_PATHS");
+ this->InheritBuildSettingAttribute(t, "LD_RUNPATH_SEARCH_PATHS");
+ }
+
+ if (this->XcodeBuildSystem == BuildSystem::One) {
+ this->CreateXCodeDependHackMakefile(targets);
+ }
+ // now add all targets to the root object
+ cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (auto t : targets) {
+ allTargets->AddObject(t);
+ cmXCodeObject* productRef = t->GetAttribute("productReference");
+ if (productRef) {
+ productGroupChildren->AddObject(productRef->GetObject());
+ }
+ }
+ this->RootObject->AddAttribute("targets", allTargets);
+ return true;
+}
+
+std::string cmGlobalXCodeGenerator::GetObjectsDirectory(
+ const std::string& projName, const std::string& configName,
+ const cmGeneratorTarget* t, const std::string& variant) const
+{
+ std::string dir = cmStrCat(
+ t->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/', projName,
+ ".build/", configName, '/', t->GetName(), ".build/", variant);
+ return dir;
+}
+
+void cmGlobalXCodeGenerator::ComputeArchitectures(cmMakefile* mf)
+{
+ this->Architectures.clear();
+ cmProp sysroot = mf->GetDefinition("CMAKE_OSX_SYSROOT");
+ if (sysroot) {
+ mf->GetDefExpandList("CMAKE_OSX_ARCHITECTURES", this->Architectures);
+ }
+
+ if (this->Architectures.empty()) {
+ mf->GetDefExpandList("_CMAKE_APPLE_ARCHS_DEFAULT", this->Architectures);
+ }
+
+ if (this->Architectures.empty()) {
+ // With no ARCHS we use ONLY_ACTIVE_ARCH and possibly a
+ // platform-specific default ARCHS placeholder value.
+ // Look up the arch that Xcode chooses in this case.
+ if (cmProp arch = mf->GetDefinition("CMAKE_XCODE_ARCHS")) {
+ this->ObjectDirArchDefault = *arch;
+ // We expect only one arch but choose the first just in case.
+ std::string::size_type pos = this->ObjectDirArchDefault.find(';');
+ if (pos != std::string::npos) {
+ this->ObjectDirArchDefault = this->ObjectDirArchDefault.substr(0, pos);
+ }
+ }
+ }
+
+ this->ComputeObjectDirArch(mf);
+}
+
+void cmGlobalXCodeGenerator::ComputeObjectDirArch(cmMakefile* mf)
+{
+ if (this->Architectures.size() > 1 || this->UseEffectivePlatformName(mf)) {
+ this->ObjectDirArch = "$(CURRENT_ARCH)";
+ } else if (!this->Architectures.empty()) {
+ this->ObjectDirArch = this->Architectures[0];
+ } else {
+ this->ObjectDirArch = this->ObjectDirArchDefault;
+ }
+}
+
+void cmGlobalXCodeGenerator::CreateXCodeDependHackMakefile(
+ std::vector<cmXCodeObject*>& targets)
+{
+ cmGeneratedFileStream makefileStream(this->CurrentXCodeHackMakefile);
+ if (!makefileStream) {
+ cmSystemTools::Error("Could not create " + this->CurrentXCodeHackMakefile);
+ return;
+ }
+ makefileStream.SetCopyIfDifferent(true);
+ // one more pass for external depend information not handled
+ // correctly by xcode
+ /* clang-format off */
+ makefileStream << "# DO NOT EDIT\n";
+ makefileStream << "# This makefile makes sure all linkable targets are\n";
+ makefileStream << "# up-to-date with anything they link to\n"
+ "default:\n"
+ "\techo \"Do not invoke directly\"\n"
+ "\n";
+ /* clang-format on */
+
+ std::set<std::string> dummyRules;
+
+ // Write rules to help Xcode relink things at the right time.
+ /* clang-format off */
+ makefileStream <<
+ "# Rules to remove targets that are older than anything to which they\n"
+ "# link. This forces Xcode to relink the targets from scratch. It\n"
+ "# does not seem to check these dependencies itself.\n";
+ /* clang-format on */
+ for (const auto& configName : this->CurrentConfigurationTypes) {
+ for (auto target : targets) {
+ cmGeneratorTarget* gt = target->GetTarget();
+
+ if (gt->GetType() == cmStateEnums::EXECUTABLE ||
+ gt->GetType() == cmStateEnums::OBJECT_LIBRARY ||
+ gt->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ gt->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ gt->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ // Declare an entry point for the target post-build phase.
+ makefileStream << this->PostBuildMakeTarget(gt->GetName(), configName)
+ << ":\n";
+ }
+
+ if (gt->GetType() == cmStateEnums::EXECUTABLE ||
+ gt->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ gt->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ gt->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ std::string tfull = gt->GetFullPath(configName);
+ std::string trel = this->ConvertToRelativeForMake(tfull);
+
+ // Add this target to the post-build phases of its dependencies.
+ auto const y = target->GetDependTargets().find(configName);
+ if (y != target->GetDependTargets().end()) {
+ for (auto const& deptgt : y->second) {
+ makefileStream << this->PostBuildMakeTarget(deptgt, configName)
+ << ": " << trel << "\n";
+ }
+ }
+
+ std::vector<cmGeneratorTarget*> objlibs;
+ gt->GetObjectLibrariesCMP0026(objlibs);
+ for (auto objLib : objlibs) {
+ makefileStream << this->PostBuildMakeTarget(objLib->GetName(),
+ configName)
+ << ": " << trel << "\n";
+ }
+
+ // Create a rule for this target.
+ makefileStream << trel << ":";
+
+ // List dependencies if any exist.
+ auto const x = target->GetDependLibraries().find(configName);
+ if (x != target->GetDependLibraries().end()) {
+ for (auto const& deplib : x->second) {
+ std::string file = this->ConvertToRelativeForMake(deplib);
+ makefileStream << "\\\n\t" << file;
+ dummyRules.insert(file);
+ }
+ }
+
+ for (auto objLib : objlibs) {
+
+ const std::string objLibName = objLib->GetName();
+ std::string d = cmStrCat(
+ this->GetObjectsDirectory(this->CurrentProject, configName, objLib,
+ OBJECT_LIBRARY_ARTIFACT_DIR),
+ "lib", objLibName, ".a");
+
+ std::string dependency = this->ConvertToRelativeForMake(d);
+ makefileStream << "\\\n\t" << dependency;
+ dummyRules.insert(dependency);
+ }
+
+ // Write the action to remove the target if it is out of date.
+ makefileStream << "\n";
+ makefileStream << "\t/bin/rm -f "
+ << this->ConvertToRelativeForMake(tfull) << "\n";
+ // if building for more than one architecture
+ // then remove those executables as well
+ if (this->Architectures.size() > 1) {
+ std::string universal = this->GetObjectsDirectory(
+ this->CurrentProject, configName, gt, "$(OBJDIR)/");
+ for (const auto& architecture : this->Architectures) {
+ std::string universalFile = cmStrCat(universal, architecture, '/',
+ gt->GetFullName(configName));
+ makefileStream << "\t/bin/rm -f "
+ << this->ConvertToRelativeForMake(universalFile)
+ << "\n";
+ }
+ }
+ makefileStream << "\n\n";
+ }
+ }
+ }
+
+ makefileStream << "\n\n"
+ << "# For each target create a dummy rule"
+ << "so the target does not have to exist\n";
+ for (auto const& dummyRule : dummyRules) {
+ makefileStream << dummyRule << ":\n";
+ }
+}
+
+void cmGlobalXCodeGenerator::OutputXCodeProject(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
+{
+ if (generators.empty()) {
+ return;
+ }
+ if (!this->CreateXCodeObjects(root, generators)) {
+ return;
+ }
+ std::string xcodeDir = cmStrCat(root->GetCurrentBinaryDirectory(), '/',
+ root->GetProjectName(), ".xcodeproj");
+ cmSystemTools::MakeDirectory(xcodeDir);
+ std::string xcodeProjFile = xcodeDir + "/project.pbxproj";
+ cmGeneratedFileStream fout(xcodeProjFile);
+ fout.SetCopyIfDifferent(true);
+ if (!fout) {
+ return;
+ }
+ this->WriteXCodePBXProj(fout, root, generators);
+
+ bool hasGeneratedSchemes = this->OutputXCodeSharedSchemes(xcodeDir, root);
+ this->OutputXCodeWorkspaceSettings(xcodeDir, hasGeneratedSchemes);
+
+ this->ClearXCodeObjects();
+
+ // Since this call may have created new cache entries, save the cache:
+ //
+ root->GetMakefile()->GetCMakeInstance()->SaveCache(
+ root->GetBinaryDirectory());
+}
+
+bool cmGlobalXCodeGenerator::OutputXCodeSharedSchemes(
+ const std::string& xcProjDir, cmLocalGenerator* root)
+{
+ // collect all tests for the targets
+ std::map<std::string, cmXCodeScheme::TestObjects> testables;
+
+ for (const auto& obj : this->XCodeObjects) {
+ if (obj->GetType() != cmXCodeObject::OBJECT ||
+ obj->GetIsA() != cmXCodeObject::PBXNativeTarget) {
+ continue;
+ }
+
+ if (!obj->GetTarget()->IsXCTestOnApple()) {
+ continue;
+ }
+
+ cmProp testee = obj->GetTarget()->GetProperty("XCTEST_TESTEE");
+ if (!testee) {
+ continue;
+ }
+
+ testables[*testee].push_back(obj.get());
+ }
+
+ // generate scheme
+ bool ret = false;
+
+ // Since the lowest available Xcode version for testing was 6.4,
+ // I'm setting this as a limit then
+ if (this->XcodeVersion >= 64) {
+ for (const auto& obj : this->XCodeObjects) {
+ if (obj->GetType() == cmXCodeObject::OBJECT &&
+ (obj->GetIsA() == cmXCodeObject::PBXNativeTarget ||
+ obj->GetIsA() == cmXCodeObject::PBXAggregateTarget) &&
+ (root->GetMakefile()->GetCMakeInstance()->GetIsInTryCompile() ||
+ obj->GetTarget()->GetPropertyAsBool("XCODE_GENERATE_SCHEME"))) {
+ const std::string& targetName = obj->GetTarget()->GetName();
+ cmXCodeScheme schm(root, obj.get(), testables[targetName],
+ this->CurrentConfigurationTypes,
+ this->XcodeVersion);
+ schm.WriteXCodeSharedScheme(xcProjDir,
+ this->RelativeToSource(xcProjDir));
+ ret = true;
+ }
+ }
+ }
+
+ return ret;
+}
+
+void cmGlobalXCodeGenerator::OutputXCodeWorkspaceSettings(
+ const std::string& xcProjDir, bool hasGeneratedSchemes)
+{
+ std::string xcodeSharedDataDir =
+ cmStrCat(xcProjDir, "/project.xcworkspace/xcshareddata");
+ cmSystemTools::MakeDirectory(xcodeSharedDataDir);
+
+ std::string workspaceSettingsFile =
+ cmStrCat(xcodeSharedDataDir, "/WorkspaceSettings.xcsettings");
+
+ cmGeneratedFileStream fout(workspaceSettingsFile);
+ fout.SetCopyIfDifferent(true);
+ if (!fout) {
+ return;
+ }
+
+ cmXMLWriter xout(fout);
+ xout.StartDocument();
+ xout.Doctype("plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\""
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"");
+ xout.StartElement("plist");
+ xout.Attribute("version", "1.0");
+ xout.StartElement("dict");
+ if (this->XcodeVersion >= 100) {
+ xout.Element("key", "BuildSystemType");
+ switch (this->XcodeBuildSystem) {
+ case BuildSystem::One:
+ xout.Element("string", "Original");
+ xout.Element("key", "DisableBuildSystemDeprecationWarning");
+ xout.Element("true");
+ break;
+ case BuildSystem::Twelve:
+ xout.Element("string", "Latest");
+ break;
+ }
+ }
+ if (hasGeneratedSchemes) {
+ xout.Element("key",
+ "IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded");
+ xout.Element("false");
+ }
+ xout.EndElement(); // dict
+ xout.EndElement(); // plist
+ xout.EndDocument();
+}
+
+void cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
+ cmLocalGenerator*,
+ std::vector<cmLocalGenerator*>&)
+{
+ SortXCodeObjects();
+
+ fout << "// !$*UTF8*$!\n";
+ fout << "{\n";
+ cmXCodeObject::Indent(1, fout);
+ fout << "archiveVersion = 1;\n";
+ cmXCodeObject::Indent(1, fout);
+ fout << "classes = {\n";
+ cmXCodeObject::Indent(1, fout);
+ fout << "};\n";
+ cmXCodeObject::Indent(1, fout);
+ fout << "objectVersion = 46;\n";
+ cmXCode21Object::PrintList(this->XCodeObjects, fout);
+ cmXCodeObject::Indent(1, fout);
+ fout << "rootObject = " << this->RootObject->GetId()
+ << " /* Project object */;\n";
+ fout << "}\n";
+}
+
+const char* cmGlobalXCodeGenerator::GetCMakeCFGIntDir() const
+{
+ return "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)";
+}
+
+std::string cmGlobalXCodeGenerator::ExpandCFGIntDir(
+ const std::string& str, const std::string& config) const
+{
+ std::string replace1 = "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)";
+ std::string replace2 = "$(CONFIGURATION)";
+
+ std::string tmp = str;
+ for (std::string::size_type i = tmp.find(replace1); i != std::string::npos;
+ i = tmp.find(replace1, i)) {
+ tmp.replace(i, replace1.size(), config);
+ i += config.size();
+ }
+ for (std::string::size_type i = tmp.find(replace2); i != std::string::npos;
+ i = tmp.find(replace2, i)) {
+ tmp.replace(i, replace2.size(), config);
+ i += config.size();
+ }
+ return tmp;
+}
+
+void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry)
+{
+ entry.Name = cmGlobalXCodeGenerator::GetActualName();
+ entry.Brief = "Generate Xcode project files.";
+}
+
+std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake(
+ std::string const& p)
+{
+ return cmSystemTools::ConvertToOutputPath(p);
+}
+
+std::string cmGlobalXCodeGenerator::RelativeToSource(const std::string& p)
+{
+ // We force conversion because Xcode breakpoints do not work unless
+ // they are in a file named relative to the source tree.
+ return cmSystemTools::ForceToRelativePath(
+ cmSystemTools::JoinPath(this->ProjectSourceDirectoryComponents), p);
+}
+
+std::string cmGlobalXCodeGenerator::RelativeToBinary(const std::string& p)
+{
+ return this->CurrentLocalGenerator->MaybeConvertToRelativePath(
+ cmSystemTools::JoinPath(this->ProjectOutputDirectoryComponents), p);
+}
+
+std::string cmGlobalXCodeGenerator::XCodeEscapePath(const std::string& p)
+{
+ if (p.find_first_of(" []") != std::string::npos) {
+ std::string t = cmStrCat('"', p, '"');
+ return t;
+ }
+ return p;
+}
+
+void cmGlobalXCodeGenerator::AppendDirectoryForConfig(
+ const std::string& prefix, const std::string& config,
+ const std::string& suffix, std::string& dir)
+{
+ if (!config.empty()) {
+ dir += prefix;
+ dir += config;
+ dir += suffix;
+ }
+}
+
+std::string cmGlobalXCodeGenerator::LookupFlags(
+ const std::string& varNamePrefix, const std::string& varNameLang,
+ const std::string& varNameSuffix, const std::string& default_flags)
+{
+ if (!varNameLang.empty()) {
+ std::string varName = cmStrCat(varNamePrefix, varNameLang, varNameSuffix);
+ if (cmProp varValue = this->CurrentMakefile->GetDefinition(varName)) {
+ if (!varValue->empty()) {
+ return *varValue;
+ }
+ }
+ }
+ return default_flags;
+}
+
+void cmGlobalXCodeGenerator::AppendDefines(BuildObjectListOrString& defs,
+ const char* defines_list,
+ bool dflag)
+{
+ // Skip this if there are no definitions.
+ if (!defines_list) {
+ return;
+ }
+
+ // Expand the list of definitions.
+ std::vector<std::string> defines = cmExpandedList(defines_list);
+
+ // Store the definitions in the string.
+ this->AppendDefines(defs, defines, dflag);
+}
+
+void cmGlobalXCodeGenerator::AppendDefines(
+ BuildObjectListOrString& defs, std::vector<std::string> const& defines,
+ bool dflag)
+{
+ // GCC_PREPROCESSOR_DEFINITIONS is a space-separated list of definitions.
+ std::string def;
+ for (auto const& define : defines) {
+ // Start with -D if requested.
+ def = cmStrCat(dflag ? "-D" : "", define);
+
+ // Append the flag with needed escapes.
+ std::string tmp;
+ this->AppendFlag(tmp, def);
+ defs.Add(tmp);
+ }
+}
+
+void cmGlobalXCodeGenerator::AppendFlag(std::string& flags,
+ std::string const& flag) const
+{
+ // Short-circuit for an empty flag.
+ if (flag.empty()) {
+ return;
+ }
+
+ // Separate from previous flags.
+ if (!flags.empty()) {
+ flags += " ";
+ }
+
+ // Check if the flag needs quoting.
+ bool quoteFlag =
+ flag.find_first_of("`~!@#$%^&*()+={}[]|:;\"'<>,.? ") != std::string::npos;
+
+ // We escape a flag as follows:
+ // - Place each flag in single quotes ''
+ // - Escape a single quote as \'
+ // - Escape a backslash as \\ since it itself is an escape
+ // Note that in the code below we need one more level of escapes for
+ // C string syntax in this source file.
+ //
+ // The final level of escaping is done when the string is stored
+ // into the project file by cmXCodeObject::PrintString.
+
+ if (quoteFlag) {
+ // Open single quote.
+ flags += "'";
+ }
+
+ // Flag value with escaped quotes and backslashes.
+ for (auto c : flag) {
+ if (c == '\'') {
+ flags += "'\\''";
+ } else if (c == '\\') {
+ flags += "\\\\";
+ } else {
+ flags += c;
+ }
+ }
+
+ if (quoteFlag) {
+ // Close single quote.
+ flags += "'";
+ }
+}
+
+std::string cmGlobalXCodeGenerator::ComputeInfoPListLocation(
+ cmGeneratorTarget* target)
+{
+ std::string plist =
+ cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/", target->GetName(), ".dir/Info.plist");
+ return plist;
+}
+
+// Return true if the generated build tree may contain multiple builds.
+// i.e. "Can I build Debug and Release in the same tree?"
+bool cmGlobalXCodeGenerator::IsMultiConfig() const
+{
+ // Newer Xcode versions are multi config:
+ return true;
+}
+
+bool cmGlobalXCodeGenerator::HasKnownObjectFileLocation(
+ std::string* reason) const
+{
+ if (this->ObjectDirArch.find('$') != std::string::npos) {
+ if (reason != nullptr) {
+ *reason = " under Xcode with multiple architectures";
+ }
+ return false;
+ }
+ return true;
+}
+
+bool cmGlobalXCodeGenerator::UseEffectivePlatformName(cmMakefile* mf) const
+{
+ cmProp epnValue = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
+ "XCODE_EMIT_EFFECTIVE_PLATFORM_NAME");
+
+ if (!epnValue) {
+ return mf->PlatformIsAppleEmbedded();
+ }
+
+ return cmIsOn(*epnValue);
+}
+
+bool cmGlobalXCodeGenerator::ShouldStripResourcePath(cmMakefile*) const
+{
+ // Xcode determines Resource location itself
+ return true;
+}
+
+void cmGlobalXCodeGenerator::ComputeTargetObjectDirectory(
+ cmGeneratorTarget* gt) const
+{
+ std::string configName = this->GetCMakeCFGIntDir();
+ std::string dir =
+ cmStrCat(this->GetObjectsDirectory("$(PROJECT_NAME)", configName, gt,
+ "$(OBJECT_FILE_DIR_normal:base)/"),
+ this->ObjectDirArch, '/');
+ gt->ObjectDirectory = dir;
+}
+
+std::string cmGlobalXCodeGenerator::GetDeploymentPlatform(const cmMakefile* mf)
+{
+ switch (mf->GetAppleSDKType()) {
+ case cmMakefile::AppleSDK::AppleTVOS:
+ case cmMakefile::AppleSDK::AppleTVSimulator:
+ return "TVOS_DEPLOYMENT_TARGET";
+
+ case cmMakefile::AppleSDK::IPhoneOS:
+ case cmMakefile::AppleSDK::IPhoneSimulator:
+ return "IPHONEOS_DEPLOYMENT_TARGET";
+
+ case cmMakefile::AppleSDK::WatchOS:
+ case cmMakefile::AppleSDK::WatchSimulator:
+ return "WATCHOS_DEPLOYMENT_TARGET";
+
+ case cmMakefile::AppleSDK::MacOS:
+ default:
+ return "MACOSX_DEPLOYMENT_TARGET";
+ }
+}
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
new file mode 100644
index 0000000..1ab56e2
--- /dev/null
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -0,0 +1,352 @@
+/* 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 <iosfwd>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmGlobalGenerator.h"
+#include "cmXCodeObject.h"
+
+class cmCustomCommand;
+class cmCustomCommandGenerator;
+class cmGeneratorTarget;
+class cmGlobalGeneratorFactory;
+class cmLocalGenerator;
+class cmMakefile;
+class cmSourceFile;
+class cmSourceGroup;
+class cmake;
+struct cmDocumentationEntry;
+
+/** \class cmGlobalXCodeGenerator
+ * \brief Write a Unix makefiles.
+ *
+ * cmGlobalXCodeGenerator manages Xcode build process for a tree
+ */
+class cmGlobalXCodeGenerator : public cmGlobalGenerator
+{
+public:
+ cmGlobalXCodeGenerator(cmake* cm, std::string const& version_string,
+ unsigned int version_number);
+ static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory();
+
+ cmGlobalXCodeGenerator(const cmGlobalXCodeGenerator&) = delete;
+ const cmGlobalXCodeGenerator& operator=(const cmGlobalXCodeGenerator&) =
+ delete;
+
+ //! Get the name for the generator.
+ std::string GetName() const override
+ {
+ return cmGlobalXCodeGenerator::GetActualName();
+ }
+ static std::string GetActualName() { return "Xcode"; }
+
+ /** Get the documentation entry for this generator. */
+ static void GetDocumentation(cmDocumentationEntry& entry);
+
+ //! Create a local generator appropriate to this Global Generator
+ std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+ cmMakefile* mf) override;
+
+ /**
+ * Try to determine system information such as shared library
+ * extension, pthreads, byte order etc.
+ */
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) override;
+
+ /**
+ * Open a generated IDE project given the following information.
+ */
+ bool Open(const std::string& bindir, const std::string& projectName,
+ bool dryRun) override;
+
+ /**
+ * Try running cmake and building a file. This is used for dynalically
+ * loaded commands, not as part of the usual build process.
+ */
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
+
+ /** Append the subdirectory for the given configuration. */
+ void AppendDirectoryForConfig(const std::string& prefix,
+ const std::string& config,
+ const std::string& suffix,
+ std::string& dir) override;
+
+ bool FindMakeProgram(cmMakefile*) override;
+
+ //! What is the configurations directory variable called?
+ const char* GetCMakeCFGIntDir() const override;
+ //! expand CFGIntDir
+ std::string ExpandCFGIntDir(const std::string& str,
+ const std::string& config) const override;
+
+ void SetCurrentLocalGenerator(cmLocalGenerator*);
+
+ /** Return true if the generated build tree may contain multiple builds.
+ i.e. "Can I build Debug and Release in the same tree?" */
+ bool IsMultiConfig() const override;
+
+ bool IsXcode() const override { return true; }
+
+ bool HasKnownObjectFileLocation(std::string* reason) const override;
+
+ bool IsIPOSupported() const override { return true; }
+
+ bool UseEffectivePlatformName(cmMakefile* mf) const override;
+
+ bool ShouldStripResourcePath(cmMakefile*) const override;
+
+ bool SetSystemName(std::string const& s, cmMakefile* mf) override;
+ bool SetGeneratorToolset(std::string const& ts, bool build,
+ cmMakefile* mf) override;
+ void AppendFlag(std::string& flags, std::string const& flag) const;
+
+ enum class BuildSystem
+ {
+ One = 1,
+ Twelve = 12,
+ };
+
+protected:
+ void AddExtraIDETargets() override;
+ void Generate() override;
+
+ FindMakeProgramStage GetFindMakeProgramStage() const override
+ {
+ return FindMakeProgramStage::Early;
+ }
+
+private:
+ bool ParseGeneratorToolset(std::string const& ts, cmMakefile* mf);
+ bool ProcessGeneratorToolsetField(std::string const& key,
+ std::string const& value, cmMakefile* mf);
+
+ cmXCodeObject* CreateOrGetPBXGroup(cmGeneratorTarget* gtgt,
+ cmSourceGroup* sg);
+ cmXCodeObject* CreatePBXGroup(cmXCodeObject* parent,
+ const std::string& name);
+ bool CreateGroups(std::vector<cmLocalGenerator*>& generators);
+ std::string XCodeEscapePath(const std::string& p);
+ std::string RelativeToSource(const std::string& p);
+ std::string RelativeToBinary(const std::string& p);
+ std::string ConvertToRelativeForMake(std::string const& p);
+ void CreateCustomCommands(
+ cmXCodeObject* buildPhases, cmXCodeObject* sourceBuildPhase,
+ cmXCodeObject* headerBuildPhase, cmXCodeObject* resourceBuildPhase,
+ std::vector<cmXCodeObject*> const& contentBuildPhases,
+ cmXCodeObject* frameworkBuildPhase, cmGeneratorTarget* gtgt);
+
+ std::string ComputeInfoPListLocation(cmGeneratorTarget* target);
+
+ void AddCommandsToBuildPhase(cmXCodeObject* buildphase,
+ cmGeneratorTarget* target,
+ std::vector<cmCustomCommand> const& commands,
+ const char* commandFileName);
+
+ void CreateCustomRulesMakefile(const char* makefileBasename,
+ cmGeneratorTarget* target,
+ std::vector<cmCustomCommand> const& commands,
+ const std::string& configName);
+
+ cmXCodeObject* FindXCodeTarget(const cmGeneratorTarget*);
+ std::string GetObjectId(cmXCodeObject::PBXType ptype, cm::string_view key);
+ std::string GetOrCreateId(const std::string& name, const std::string& id);
+
+ // create cmXCodeObject from these functions so that memory can be managed
+ // correctly. All objects created are stored in this->XCodeObjects.
+ cmXCodeObject* CreateObject(cmXCodeObject::PBXType ptype,
+ cm::string_view key = {});
+ cmXCodeObject* CreateObject(cmXCodeObject::Type type);
+ cmXCodeObject* CreateString(const std::string& s);
+ cmXCodeObject* CreateObjectReference(cmXCodeObject*);
+ cmXCodeObject* CreateFlatClone(cmXCodeObject*);
+ cmXCodeObject* CreateXCodeTarget(cmGeneratorTarget* gtgt,
+ cmXCodeObject* buildPhases);
+ void ForceLinkerLanguages() override;
+ void ForceLinkerLanguage(cmGeneratorTarget* gtgt);
+ const char* GetTargetLinkFlagsVar(const cmGeneratorTarget* target) const;
+ const char* GetTargetFileType(cmGeneratorTarget* target);
+ const char* GetTargetProductType(cmGeneratorTarget* target);
+ std::string AddConfigurations(cmXCodeObject* target,
+ cmGeneratorTarget* gtgt);
+ void AppendOrAddBuildSetting(cmXCodeObject* settings, const char* attr,
+ cmXCodeObject* value);
+ void AppendBuildSettingAttribute(cmXCodeObject* settings,
+ const char* attribute, cmXCodeObject* attr,
+ cmXCodeObject* value);
+ void AppendBuildSettingAttribute(cmXCodeObject* target, const char* attr,
+ cmXCodeObject* value,
+ const std::string& configName);
+ void InheritBuildSettingAttribute(cmXCodeObject* target,
+ const char* attribute);
+ cmXCodeObject* CreateUtilityTarget(cmGeneratorTarget* gtgt);
+ void AddDependAndLinkInformation(cmXCodeObject* target);
+ void AddEmbeddedFrameworks(cmXCodeObject* target);
+ void AddPositionIndependentLinkAttribute(cmGeneratorTarget* target,
+ cmXCodeObject* buildSettings,
+ const std::string& configName);
+ void CreateBuildSettings(cmGeneratorTarget* gtgt,
+ cmXCodeObject* buildSettings,
+ const std::string& buildType);
+ std::string ExtractFlag(const char* flag, std::string& flags);
+ std::string ExtractFlagRegex(const char* exp, int matchIndex,
+ std::string& flags);
+ void FilterConfigurationAttribute(std::string const& configName,
+ std::string& attribute);
+ void SortXCodeObjects();
+ // delete all objects in the this->XCodeObjects vector.
+ void ClearXCodeObjects();
+ bool CreateXCodeObjects(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators);
+ void OutputXCodeProject(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators);
+ // Write shared scheme files for all the native targets
+ // return true if any were written
+ bool OutputXCodeSharedSchemes(const std::string& xcProjDir,
+ cmLocalGenerator* root);
+ void OutputXCodeWorkspaceSettings(const std::string& xcProjDir,
+ bool hasGeneratedSchemes);
+ void WriteXCodePBXProj(std::ostream& fout, cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators);
+ cmXCodeObject* CreateXCodeFileReferenceFromPath(const std::string& fullpath,
+ cmGeneratorTarget* target,
+ const std::string& lang,
+ cmSourceFile* sf);
+ cmXCodeObject* CreateXCodeBuildFileFromPath(const std::string& fullpath,
+ cmGeneratorTarget* target,
+ const std::string& lang,
+ cmSourceFile* sf);
+ cmXCodeObject* CreateXCodeFileReference(cmSourceFile* sf,
+ cmGeneratorTarget* target);
+ cmXCodeObject* CreateXCodeSourceFile(cmLocalGenerator* gen, cmSourceFile* sf,
+ cmGeneratorTarget* gtgt);
+ void AddXCodeProjBuildRule(cmGeneratorTarget* target,
+ std::vector<cmSourceFile*>& sources) const;
+ bool CreateXCodeTargets(cmLocalGenerator* gen, std::vector<cmXCodeObject*>&);
+ bool CreateXCodeTarget(cmGeneratorTarget* gtgt,
+ std::vector<cmXCodeObject*>&);
+ bool IsHeaderFile(cmSourceFile*);
+ void AddDependTarget(cmXCodeObject* target, cmXCodeObject* dependTarget);
+ void CreateXCodeDependHackMakefile(std::vector<cmXCodeObject*>& targets);
+ bool SpecialTargetEmitted(std::string const& tname);
+ void SetGenerationRoot(cmLocalGenerator* root);
+ void AddExtraTargets(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& gens);
+ cmXCodeObject* CreateLegacyRunScriptBuildPhase(
+ const char* name, const char* name2, cmGeneratorTarget* target,
+ const std::vector<cmCustomCommand>&);
+ void CreateRunScriptBuildPhases(cmXCodeObject* buildPhases,
+ cmGeneratorTarget const* gt);
+ void CreateRunScriptBuildPhases(cmXCodeObject* buildPhases,
+ cmSourceFile const* sf,
+ cmGeneratorTarget const* gt,
+ std::set<cmSourceFile const*>& visited);
+ cmXCodeObject* CreateRunScriptBuildPhase(cmSourceFile const* sf,
+ cmGeneratorTarget const* gt,
+ cmCustomCommand const& cc);
+ cmXCodeObject* CreateRunScriptBuildPhase(
+ std::string const& name, cmGeneratorTarget const* gt,
+ std::vector<cmCustomCommand> const& commands);
+ std::string ConstructScript(cmCustomCommandGenerator const& ccg);
+ void CreateReRunCMakeFile(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*> const& gens);
+
+ std::string LookupFlags(const std::string& varNamePrefix,
+ const std::string& varNameLang,
+ const std::string& varNameSuffix,
+ const std::string& default_flags);
+
+ class Factory;
+ class BuildObjectListOrString;
+ friend class BuildObjectListOrString;
+
+ void AppendDefines(BuildObjectListOrString& defs, const char* defines_list,
+ bool dflag = false);
+ void AppendDefines(BuildObjectListOrString& defs,
+ std::vector<std::string> const& defines,
+ bool dflag = false);
+
+ void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;
+
+protected:
+ const char* GetInstallTargetName() const override { return "install"; }
+ const char* GetPackageTargetName() const override { return "package"; }
+
+ unsigned int XcodeVersion;
+ std::string VersionString;
+ std::set<std::string> XCodeObjectIDs;
+ std::vector<std::unique_ptr<cmXCodeObject>> XCodeObjects;
+ cmXCodeObject* RootObject;
+
+ BuildSystem XcodeBuildSystem = BuildSystem::One;
+
+private:
+ std::string const& GetXcodeBuildCommand();
+ std::string FindXcodeBuildCommand();
+ std::string XcodeBuildCommand;
+ bool XcodeBuildCommandInitialized;
+
+ void PrintCompilerAdvice(std::ostream&, std::string const&,
+ const char*) const override
+ {
+ }
+
+ std::string GetObjectsDirectory(const std::string& projName,
+ const std::string& configName,
+ const cmGeneratorTarget* t,
+ const std::string& variant) const;
+
+ static std::string GetDeploymentPlatform(const cmMakefile* mf);
+
+ void ComputeArchitectures(cmMakefile* mf);
+ void ComputeObjectDirArch(cmMakefile* mf);
+
+ void addObject(std::unique_ptr<cmXCodeObject> obj);
+ std::string PostBuildMakeTarget(std::string const& tName,
+ std::string const& configName);
+ cmXCodeObject* MainGroupChildren;
+ cmXCodeObject* FrameworkGroup;
+ cmMakefile* CurrentMakefile;
+ cmLocalGenerator* CurrentLocalGenerator;
+ std::vector<std::string> CurrentConfigurationTypes;
+ std::string CurrentReRunCMakeMakefile;
+ std::string CurrentXCodeHackMakefile;
+ std::string CurrentProject;
+ std::set<std::string> TargetDoneSet;
+ std::vector<std::string> ProjectSourceDirectoryComponents;
+ std::vector<std::string> ProjectOutputDirectoryComponents;
+ std::map<std::string, cmXCodeObject*> GroupMap;
+ std::map<std::string, cmXCodeObject*> GroupNameMap;
+ std::map<std::string, cmXCodeObject*> TargetGroup;
+ std::map<std::string, cmXCodeObject*> FileRefs;
+ std::map<std::string, cmXCodeObject*> ExternalLibRefs;
+ std::map<std::string, cmXCodeObject*> EmbeddedLibRefs;
+ std::map<cmGeneratorTarget const*, cmXCodeObject*> XCodeObjectMap;
+ std::map<cmXCodeObject*, cmXCodeObject*> FileRefToBuildFileMap;
+ std::map<cmXCodeObject*, cmXCodeObject*> FileRefToEmbedBuildFileMap;
+ std::vector<std::string> Architectures;
+ std::string ObjectDirArchDefault;
+ std::string ObjectDirArch;
+ std::string SystemName;
+ std::string GeneratorToolset;
+ std::vector<std::string> EnabledLangs;
+ std::map<cmGeneratorTarget const*, std::set<cmSourceFile const*>>
+ CommandsVisited;
+ std::map<cmSourceFile const*, std::set<cmGeneratorTarget const*>>
+ CustomCommandRoots;
+};
diff --git a/Source/cmGraphAdjacencyList.h b/Source/cmGraphAdjacencyList.h
new file mode 100644
index 0000000..fe9fbe2
--- /dev/null
+++ b/Source/cmGraphAdjacencyList.h
@@ -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. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <utility>
+#include <vector>
+
+#include "cmListFileCache.h"
+
+/**
+ * Graph edge representation. Most use cases just need the
+ * destination vertex, so we support conversion to/from an int. We
+ * also store boolean to indicate whether an edge is "strong".
+ */
+class cmGraphEdge
+{
+public:
+ cmGraphEdge(int n, bool s, bool c, cmListFileBacktrace bt)
+ : Dest(n)
+ , Strong(s)
+ , Cross(c)
+ , Backtrace(std::move(bt))
+ {
+ }
+ operator int() const { return this->Dest; }
+
+ bool IsStrong() const { return this->Strong; }
+
+ bool IsCross() const { return this->Cross; }
+
+ cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; }
+
+private:
+ int Dest;
+ bool Strong;
+ bool Cross;
+ cmListFileBacktrace Backtrace;
+};
+struct cmGraphEdgeList : public std::vector<cmGraphEdge>
+{
+};
+struct cmGraphNodeList : public std::vector<int>
+{
+};
+struct cmGraphAdjacencyList : public std::vector<cmGraphEdgeList>
+{
+};
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
new file mode 100644
index 0000000..122bda5
--- /dev/null
+++ b/Source/cmGraphVizWriter.cxx
@@ -0,0 +1,617 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGraphVizWriter.h"
+
+#include <algorithm>
+#include <cctype>
+#include <iostream>
+#include <memory>
+#include <set>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLinkItem.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+namespace {
+
+char const* const GRAPHVIZ_EDGE_STYLE_PUBLIC = "solid";
+char const* const GRAPHVIZ_EDGE_STYLE_INTERFACE = "dashed";
+char const* const GRAPHVIZ_EDGE_STYLE_PRIVATE = "dotted";
+
+char const* const GRAPHVIZ_NODE_SHAPE_EXECUTABLE = "egg"; // egg-xecutable
+
+// Normal libraries.
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC = "octagon";
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED = "doubleoctagon";
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE = "tripleoctagon";
+
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE = "pentagon";
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT = "hexagon";
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN = "septagon";
+
+char const* const GRAPHVIZ_NODE_SHAPE_UTILITY = "box";
+
+const char* getShapeForTarget(const cmLinkItem& item)
+{
+ if (item.Target == nullptr) {
+ return GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN;
+ }
+
+ switch (item.Target->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ return GRAPHVIZ_NODE_SHAPE_EXECUTABLE;
+ case cmStateEnums::STATIC_LIBRARY:
+ return GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC;
+ case cmStateEnums::SHARED_LIBRARY:
+ return GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED;
+ case cmStateEnums::MODULE_LIBRARY:
+ return GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE;
+ case cmStateEnums::OBJECT_LIBRARY:
+ return GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT;
+ case cmStateEnums::UTILITY:
+ return GRAPHVIZ_NODE_SHAPE_UTILITY;
+ case cmStateEnums::INTERFACE_LIBRARY:
+ return GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE;
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ default:
+ return GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN;
+ }
+}
+
+struct DependeesDir
+{
+ template <typename T>
+ static const cmLinkItem& src(const T& con)
+ {
+ return con.src;
+ }
+
+ template <typename T>
+ static const cmLinkItem& dst(const T& con)
+ {
+ return con.dst;
+ }
+};
+
+struct DependersDir
+{
+ template <typename T>
+ static const cmLinkItem& src(const T& con)
+ {
+ return con.dst;
+ }
+
+ template <typename T>
+ static const cmLinkItem& dst(const T& con)
+ {
+ return con.src;
+ }
+};
+}
+
+cmGraphVizWriter::cmGraphVizWriter(std::string const& fileName,
+ const cmGlobalGenerator* globalGenerator)
+ : FileName(fileName)
+ , GlobalFileStream(fileName)
+ , GraphName(globalGenerator->GetSafeGlobalSetting("CMAKE_PROJECT_NAME"))
+ , GraphHeader("node [\n fontsize = \"12\"\n];")
+ , GraphNodePrefix("node")
+ , GlobalGenerator(globalGenerator)
+ , NextNodeId(0)
+ , GenerateForExecutables(true)
+ , GenerateForStaticLibs(true)
+ , GenerateForSharedLibs(true)
+ , GenerateForModuleLibs(true)
+ , GenerateForInterfaceLibs(true)
+ , GenerateForObjectLibs(true)
+ , GenerateForUnknownLibs(true)
+ , GenerateForCustomTargets(false)
+ , GenerateForExternals(true)
+ , GeneratePerTarget(true)
+ , GenerateDependers(true)
+{
+}
+
+cmGraphVizWriter::~cmGraphVizWriter()
+{
+ this->WriteFooter(this->GlobalFileStream);
+}
+
+void cmGraphVizWriter::VisitGraph(std::string const&)
+{
+ this->WriteHeader(this->GlobalFileStream, this->GraphName);
+ this->WriteLegend(this->GlobalFileStream);
+}
+
+void cmGraphVizWriter::OnItem(cmLinkItem const& item)
+{
+ if (this->ItemExcluded(item)) {
+ return;
+ }
+
+ this->NodeNames[item.AsStr()] =
+ cmStrCat(this->GraphNodePrefix, this->NextNodeId);
+ ++this->NextNodeId;
+
+ this->WriteNode(this->GlobalFileStream, item);
+}
+
+std::unique_ptr<cmGeneratedFileStream> cmGraphVizWriter::CreateTargetFile(
+ cmLinkItem const& item, std::string const& fileNameSuffix)
+{
+ auto const pathSafeItemName = PathSafeString(item.AsStr());
+ auto const perTargetFileName =
+ cmStrCat(this->FileName, '.', pathSafeItemName, fileNameSuffix);
+ auto perTargetFileStream =
+ cm::make_unique<cmGeneratedFileStream>(perTargetFileName);
+
+ this->WriteHeader(*perTargetFileStream, item.AsStr());
+ this->WriteNode(*perTargetFileStream, item);
+
+ return perTargetFileStream;
+}
+
+void cmGraphVizWriter::OnDirectLink(cmLinkItem const& depender,
+ cmLinkItem const& dependee,
+ DependencyType dt)
+{
+ this->VisitLink(depender, dependee, true, GetEdgeStyle(dt));
+}
+
+void cmGraphVizWriter::OnIndirectLink(cmLinkItem const& depender,
+ cmLinkItem const& dependee)
+{
+ this->VisitLink(depender, dependee, false);
+}
+
+void cmGraphVizWriter::VisitLink(cmLinkItem const& depender,
+ cmLinkItem const& dependee, bool isDirectLink,
+ std::string const& scopeType)
+{
+ if (this->ItemExcluded(depender) || this->ItemExcluded(dependee)) {
+ return;
+ }
+
+ if (!isDirectLink) {
+ return;
+ }
+
+ // write global data directly
+ this->WriteConnection(this->GlobalFileStream, depender, dependee, scopeType);
+
+ if (this->GeneratePerTarget) {
+ this->PerTargetConnections[depender].emplace_back(depender, dependee,
+ scopeType);
+ }
+
+ if (this->GenerateDependers) {
+ this->TargetDependersConnections[dependee].emplace_back(dependee, depender,
+ scopeType);
+ }
+}
+
+void cmGraphVizWriter::ReadSettings(
+ const std::string& settingsFileName,
+ const std::string& fallbackSettingsFileName)
+{
+ cmake cm(cmake::RoleScript, cmState::Unknown);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator ggi(&cm);
+ cmMakefile mf(&ggi, cm.GetCurrentSnapshot());
+ std::unique_ptr<cmLocalGenerator> lg(ggi.CreateLocalGenerator(&mf));
+
+ std::string inFileName = settingsFileName;
+ if (!cmSystemTools::FileExists(inFileName)) {
+ inFileName = fallbackSettingsFileName;
+ if (!cmSystemTools::FileExists(inFileName)) {
+ return;
+ }
+ }
+
+ if (!mf.ReadListFile(inFileName)) {
+ cmSystemTools::Error("Problem opening GraphViz options file: " +
+ inFileName);
+ return;
+ }
+
+ std::cout << "Reading GraphViz options file: " << inFileName << std::endl;
+
+#define set_if_set(var, cmakeDefinition) \
+ do { \
+ cmProp value = mf.GetDefinition(cmakeDefinition); \
+ if (value) { \
+ (var) = *value; \
+ } \
+ } while (false)
+
+ set_if_set(this->GraphName, "GRAPHVIZ_GRAPH_NAME");
+ set_if_set(this->GraphHeader, "GRAPHVIZ_GRAPH_HEADER");
+ set_if_set(this->GraphNodePrefix, "GRAPHVIZ_NODE_PREFIX");
+
+#define set_bool_if_set(var, cmakeDefinition) \
+ do { \
+ cmProp value = mf.GetDefinition(cmakeDefinition); \
+ if (value) { \
+ (var) = cmIsOn(*value); \
+ } \
+ } while (false)
+
+ set_bool_if_set(this->GenerateForExecutables, "GRAPHVIZ_EXECUTABLES");
+ set_bool_if_set(this->GenerateForStaticLibs, "GRAPHVIZ_STATIC_LIBS");
+ set_bool_if_set(this->GenerateForSharedLibs, "GRAPHVIZ_SHARED_LIBS");
+ set_bool_if_set(this->GenerateForModuleLibs, "GRAPHVIZ_MODULE_LIBS");
+ set_bool_if_set(this->GenerateForInterfaceLibs, "GRAPHVIZ_INTERFACE_LIBS");
+ set_bool_if_set(this->GenerateForObjectLibs, "GRAPHVIZ_OBJECT_LIBS");
+ set_bool_if_set(this->GenerateForUnknownLibs, "GRAPHVIZ_UNKNOWN_LIBS");
+ set_bool_if_set(this->GenerateForCustomTargets, "GRAPHVIZ_CUSTOM_TARGETS");
+ set_bool_if_set(this->GenerateForExternals, "GRAPHVIZ_EXTERNAL_LIBS");
+ set_bool_if_set(this->GeneratePerTarget, "GRAPHVIZ_GENERATE_PER_TARGET");
+ set_bool_if_set(this->GenerateDependers, "GRAPHVIZ_GENERATE_DEPENDERS");
+
+ std::string ignoreTargetsRegexes;
+ set_if_set(ignoreTargetsRegexes, "GRAPHVIZ_IGNORE_TARGETS");
+
+ this->TargetsToIgnoreRegex.clear();
+ if (!ignoreTargetsRegexes.empty()) {
+ std::vector<std::string> ignoreTargetsRegExVector =
+ cmExpandedList(ignoreTargetsRegexes);
+ for (std::string const& currentRegexString : ignoreTargetsRegExVector) {
+ cmsys::RegularExpression currentRegex;
+ if (!currentRegex.compile(currentRegexString)) {
+ std::cerr << "Could not compile bad regex \"" << currentRegexString
+ << "\"" << std::endl;
+ }
+ this->TargetsToIgnoreRegex.push_back(std::move(currentRegex));
+ }
+ }
+}
+
+void cmGraphVizWriter::Write()
+{
+ const auto* gg = this->GlobalGenerator;
+
+ this->VisitGraph(gg->GetName());
+
+ // We want to traverse in a determined order, such that the output is always
+ // the same for a given project (this makes tests reproducible, etc.)
+ std::set<cmGeneratorTarget const*, cmGeneratorTarget::StrictTargetComparison>
+ sortedGeneratorTargets;
+
+ for (const auto& lg : gg->GetLocalGenerators()) {
+ for (const auto& gt : lg->GetGeneratorTargets()) {
+ // Reserved targets have inconsistent names across platforms (e.g. 'all'
+ // vs. 'ALL_BUILD'), which can disrupt the traversal ordering.
+ // We don't need or want them anyway.
+ if (!cmGlobalGenerator::IsReservedTarget(gt->GetName())) {
+ sortedGeneratorTargets.insert(gt.get());
+ }
+ }
+ }
+
+ // write global data and collect all connection data for per target graphs
+ for (const auto* const gt : sortedGeneratorTargets) {
+ auto item = cmLinkItem(gt, false, gt->GetBacktrace());
+ this->VisitItem(item);
+ }
+
+ if (this->GeneratePerTarget) {
+ this->WritePerTargetConnections<DependeesDir>(this->PerTargetConnections);
+ }
+
+ if (this->GenerateDependers) {
+ this->WritePerTargetConnections<DependersDir>(
+ this->TargetDependersConnections, ".dependers");
+ }
+}
+
+void cmGraphVizWriter::FindAllConnections(const ConnectionsMap& connectionMap,
+ const cmLinkItem& rootItem,
+ Connections& extendedCons,
+ std::set<cmLinkItem>& visitedItems)
+{
+ // some "targets" are not in map, e.g. linker flags as -lm or
+ // targets without dependency.
+ // in both cases we are finished with traversing the graph
+ if (connectionMap.find(rootItem) == connectionMap.cend()) {
+ return;
+ }
+
+ const Connections& origCons = connectionMap.at(rootItem);
+
+ for (const Connection& con : origCons) {
+ extendedCons.emplace_back(con);
+ const cmLinkItem& dstItem = con.dst;
+ bool const visited = visitedItems.find(dstItem) != visitedItems.cend();
+ if (!visited) {
+ visitedItems.insert(dstItem);
+ this->FindAllConnections(connectionMap, dstItem, extendedCons,
+ visitedItems);
+ }
+ }
+}
+
+void cmGraphVizWriter::FindAllConnections(const ConnectionsMap& connectionMap,
+ const cmLinkItem& rootItem,
+ Connections& extendedCons)
+{
+ std::set<cmLinkItem> visitedItems = { rootItem };
+ this->FindAllConnections(connectionMap, rootItem, extendedCons,
+ visitedItems);
+}
+
+template <typename DirFunc>
+void cmGraphVizWriter::WritePerTargetConnections(
+ const ConnectionsMap& connections, const std::string& fileNameSuffix)
+{
+ // the per target connections must be extended by indirect dependencies
+ ConnectionsMap extendedConnections;
+ for (auto const& conPerTarget : connections) {
+ const cmLinkItem& rootItem = conPerTarget.first;
+ Connections& extendedCons = extendedConnections[conPerTarget.first];
+ this->FindAllConnections(connections, rootItem, extendedCons);
+ }
+
+ for (auto const& conPerTarget : extendedConnections) {
+ const cmLinkItem& rootItem = conPerTarget.first;
+
+ // some of the nodes are excluded completely and are not written
+ if (this->ItemExcluded(rootItem)) {
+ continue;
+ }
+
+ const Connections& cons = conPerTarget.second;
+
+ std::unique_ptr<cmGeneratedFileStream> fileStream =
+ this->CreateTargetFile(rootItem, fileNameSuffix);
+
+ for (const Connection& con : cons) {
+ const cmLinkItem& src = DirFunc::src(con);
+ const cmLinkItem& dst = DirFunc::dst(con);
+ this->WriteNode(*fileStream, con.dst);
+ this->WriteConnection(*fileStream, src, dst, con.scopeType);
+ }
+
+ this->WriteFooter(*fileStream);
+ }
+}
+
+void cmGraphVizWriter::WriteHeader(cmGeneratedFileStream& fs,
+ const std::string& name)
+{
+ auto const escapedGraphName = EscapeForDotFile(name);
+ fs << "digraph \"" << escapedGraphName << "\" {\n"
+ << this->GraphHeader << '\n';
+}
+
+void cmGraphVizWriter::WriteFooter(cmGeneratedFileStream& fs)
+{
+ fs << "}\n";
+}
+
+void cmGraphVizWriter::WriteLegend(cmGeneratedFileStream& fs)
+{
+ // Note that the subgraph name must start with "cluster", as done here, to
+ // make Graphviz layout engines do the right thing and keep the nodes
+ // together.
+ /* clang-format off */
+ fs << "subgraph clusterLegend {\n"
+ " label = \"Legend\";\n"
+ // Set the color of the box surrounding the legend.
+ " color = black;\n"
+ // We use invisible edges just to enforce the layout.
+ " edge [ style = invis ];\n"
+ // Nodes.
+ " legendNode0 [ label = \"Executable\", shape = "
+ << GRAPHVIZ_NODE_SHAPE_EXECUTABLE << " ];\n"
+ " legendNode1 [ label = \"Static Library\", shape = "
+ << GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC << " ];\n"
+ " legendNode2 [ label = \"Shared Library\", shape = "
+ << GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED << " ];\n"
+ " legendNode3 [ label = \"Module Library\", shape = "
+ << GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE << " ];\n"
+ " legendNode4 [ label = \"Interface Library\", shape = "
+ << GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE << " ];\n"
+ " legendNode5 [ label = \"Object Library\", shape = "
+ << GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT << " ];\n"
+ " legendNode6 [ label = \"Unknown Library\", shape = "
+ << GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN << " ];\n"
+ " legendNode7 [ label = \"Custom Target\", shape = "
+ << GRAPHVIZ_NODE_SHAPE_UTILITY << " ];\n"
+ // Edges.
+ // Some of those are dummy (invisible) edges to enforce a layout.
+ " legendNode0 -> legendNode1 [ style = "
+ << GRAPHVIZ_EDGE_STYLE_PUBLIC << " ];\n"
+ " legendNode0 -> legendNode2 [ style = "
+ << GRAPHVIZ_EDGE_STYLE_PUBLIC << " ];\n"
+ " legendNode0 -> legendNode3;\n"
+ " legendNode1 -> legendNode4 [ label = \"Interface\", style = "
+ << GRAPHVIZ_EDGE_STYLE_INTERFACE << " ];\n"
+ " legendNode2 -> legendNode5 [ label = \"Private\", style = "
+ << GRAPHVIZ_EDGE_STYLE_PRIVATE << " ];\n"
+ " legendNode3 -> legendNode6 [ style = "
+ << GRAPHVIZ_EDGE_STYLE_PUBLIC << " ];\n"
+ " legendNode0 -> legendNode7;\n"
+ "}\n";
+ /* clang-format off */
+}
+
+void cmGraphVizWriter::WriteNode(cmGeneratedFileStream& fs,
+ cmLinkItem const& item)
+{
+ auto const& itemName = item.AsStr();
+ auto const& nodeName = this->NodeNames[itemName];
+
+ auto const itemNameWithAliases = this->ItemNameWithAliases(itemName);
+ auto const escapedLabel = EscapeForDotFile(itemNameWithAliases);
+
+ fs << " \"" << nodeName << "\" [ label = \"" << escapedLabel
+ << "\", shape = " << getShapeForTarget(item) << " ];\n";
+}
+
+void cmGraphVizWriter::WriteConnection(cmGeneratedFileStream& fs,
+ cmLinkItem const& depender,
+ cmLinkItem const& dependee,
+ std::string const& edgeStyle)
+{
+ auto const& dependerName = depender.AsStr();
+ auto const& dependeeName = dependee.AsStr();
+
+ fs << " \"" << this->NodeNames[dependerName] << "\" -> \""
+ << this->NodeNames[dependeeName] << "\" "
+ << edgeStyle
+ << " // " << dependerName << " -> " << dependeeName << '\n';
+}
+
+bool cmGraphVizWriter::ItemExcluded(cmLinkItem const& item)
+{
+ auto const itemName = item.AsStr();
+
+ if (this->ItemNameFilteredOut(itemName)) {
+ return true;
+ }
+
+ if (item.Target == nullptr) {
+ return !this->GenerateForExternals;
+ }
+
+ if (item.Target->GetType() == cmStateEnums::UTILITY) {
+ if (cmHasLiteralPrefix(itemName, "Nightly") ||
+ cmHasLiteralPrefix(itemName, "Continuous") ||
+ cmHasLiteralPrefix(itemName, "Experimental")) {
+ return true;
+ }
+ }
+
+ if (item.Target->IsImported() && !this->GenerateForExternals) {
+ return true;
+ }
+
+ return !this->TargetTypeEnabled(item.Target->GetType());
+}
+
+bool cmGraphVizWriter::ItemNameFilteredOut(std::string const& itemName)
+{
+ if (itemName == ">") {
+ // FIXME: why do we even receive such a target here?
+ return true;
+ }
+
+ if (cmGlobalGenerator::IsReservedTarget(itemName)) {
+ return true;
+ }
+
+ for (cmsys::RegularExpression& regEx : this->TargetsToIgnoreRegex) {
+ if (regEx.is_valid()) {
+ if (regEx.find(itemName)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool cmGraphVizWriter::TargetTypeEnabled(
+ cmStateEnums::TargetType targetType) const
+{
+ switch (targetType) {
+ case cmStateEnums::EXECUTABLE:
+ return this->GenerateForExecutables;
+ case cmStateEnums::STATIC_LIBRARY:
+ return this->GenerateForStaticLibs;
+ case cmStateEnums::SHARED_LIBRARY:
+ return this->GenerateForSharedLibs;
+ case cmStateEnums::MODULE_LIBRARY:
+ return this->GenerateForModuleLibs;
+ case cmStateEnums::INTERFACE_LIBRARY:
+ return this->GenerateForInterfaceLibs;
+ case cmStateEnums::OBJECT_LIBRARY:
+ return this->GenerateForObjectLibs;
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ return this->GenerateForUnknownLibs;
+ case cmStateEnums::UTILITY:
+ return this->GenerateForCustomTargets;
+ case cmStateEnums::GLOBAL_TARGET:
+ // Built-in targets like edit_cache, etc.
+ // We don't need/want those in the dot file.
+ return false;
+ default:
+ break;
+ }
+ return false;
+}
+
+std::string cmGraphVizWriter::ItemNameWithAliases(
+ std::string const& itemName) const
+{
+ std::vector<std::string> items;
+ for (auto const& lg : this->GlobalGenerator->GetLocalGenerators()) {
+ for (auto const& aliasTargets : lg->GetMakefile()->GetAliasTargets()) {
+ if (aliasTargets.second == itemName) {
+ items.push_back(aliasTargets.first);
+ }
+ }
+ }
+
+ std::sort(items.begin(), items.end());
+ items.erase(std::unique(items.begin(), items.end()), items.end());
+
+ auto nameWithAliases = itemName;
+ for(auto const& item : items) {
+ nameWithAliases += "\\n(" + item + ")";
+ }
+
+ return nameWithAliases;
+}
+
+std::string cmGraphVizWriter::GetEdgeStyle(DependencyType dt)
+{
+ std::string style;
+ switch (dt) {
+ case DependencyType::LinkPrivate:
+ style = "[ style = " + std::string(GRAPHVIZ_EDGE_STYLE_PRIVATE) + " ]";
+ break;
+ case DependencyType::LinkInterface:
+ style = "[ style = " + std::string(GRAPHVIZ_EDGE_STYLE_INTERFACE) + " ]";
+ break;
+ default:
+ break;
+ }
+ return style;
+}
+
+std::string cmGraphVizWriter::EscapeForDotFile(std::string const& str)
+{
+ return cmSystemTools::EscapeChars(str.data(), "\"");
+}
+
+std::string cmGraphVizWriter::PathSafeString(std::string const& str)
+{
+ std::string pathSafeStr;
+
+ // We'll only keep alphanumerical characters, plus the following ones that
+ // are common, and safe on all platforms:
+ auto const extra_chars = std::set<char>{ '.', '-', '_' };
+
+ for (char c : str) {
+ if (std::isalnum(c) || extra_chars.find(c) != extra_chars.cend()) {
+ pathSafeStr += c;
+ }
+ }
+
+ return pathSafeStr;
+}
diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h
new file mode 100644
index 0000000..0912fc8
--- /dev/null
+++ b/Source/cmGraphVizWriter.h
@@ -0,0 +1,137 @@
+/* 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 <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmGeneratedFileStream.h"
+#include "cmLinkItem.h"
+#include "cmLinkItemGraphVisitor.h"
+#include "cmStateTypes.h"
+
+class cmGlobalGenerator;
+
+/** This class implements writing files for graphviz (dot) for graphs
+ * representing the dependencies between the targets in the project. */
+class cmGraphVizWriter : public cmLinkItemGraphVisitor
+{
+public:
+ cmGraphVizWriter(std::string const& fileName,
+ const cmGlobalGenerator* globalGenerator);
+ ~cmGraphVizWriter() override;
+
+ void VisitGraph(std::string const& name) override;
+
+ void OnItem(cmLinkItem const& item) override;
+
+ void OnDirectLink(cmLinkItem const& depender, cmLinkItem const& dependee,
+ DependencyType dt) override;
+
+ void OnIndirectLink(cmLinkItem const& depender,
+ cmLinkItem const& dependee) override;
+
+ void ReadSettings(const std::string& settingsFileName,
+ const std::string& fallbackSettingsFileName);
+
+ void Write();
+
+private:
+ struct Connection
+ {
+ Connection(cmLinkItem s, cmLinkItem d, std::string scope)
+ : src(std::move(s))
+ , dst(std::move(d))
+ , scopeType(std::move(scope))
+ {
+ }
+
+ cmLinkItem src;
+ cmLinkItem dst;
+ std::string scopeType;
+ };
+ using Connections = std::vector<Connection>;
+ using ConnectionsMap = std::map<cmLinkItem, Connections>;
+
+ void VisitLink(cmLinkItem const& depender, cmLinkItem const& dependee,
+ bool isDirectLink, std::string const& scopeType = "");
+
+ void WriteHeader(cmGeneratedFileStream& fs, std::string const& name);
+
+ void WriteFooter(cmGeneratedFileStream& fs);
+
+ void WriteLegend(cmGeneratedFileStream& fs);
+
+ void WriteNode(cmGeneratedFileStream& fs, cmLinkItem const& item);
+
+ std::unique_ptr<cmGeneratedFileStream> CreateTargetFile(
+ cmLinkItem const& target, std::string const& fileNameSuffix = "");
+
+ void WriteConnection(cmGeneratedFileStream& fs,
+ cmLinkItem const& dependerTargetName,
+ cmLinkItem const& dependeeTargetName,
+ std::string const& edgeStyle);
+
+ void FindAllConnections(const ConnectionsMap& connectionMap,
+ const cmLinkItem& rootItem,
+ Connections& extendedCons,
+ std::set<cmLinkItem>& visitedItems);
+
+ void FindAllConnections(const ConnectionsMap& connectionMap,
+ const cmLinkItem& rootItem,
+ Connections& extendedCons);
+
+ template <typename DirFunc>
+ void WritePerTargetConnections(const ConnectionsMap& connections,
+ const std::string& fileNameSuffix = "");
+
+ bool ItemExcluded(cmLinkItem const& item);
+ bool ItemNameFilteredOut(std::string const& itemName);
+ bool TargetTypeEnabled(cmStateEnums::TargetType targetType) const;
+
+ std::string ItemNameWithAliases(std::string const& itemName) const;
+
+ static std::string GetEdgeStyle(DependencyType dt);
+
+ static std::string EscapeForDotFile(std::string const& str);
+
+ static std::string PathSafeString(std::string const& str);
+
+ std::string FileName;
+ cmGeneratedFileStream GlobalFileStream;
+
+ ConnectionsMap PerTargetConnections;
+ ConnectionsMap TargetDependersConnections;
+
+ std::string GraphName;
+ std::string GraphHeader;
+ std::string GraphNodePrefix;
+
+ std::vector<cmsys::RegularExpression> TargetsToIgnoreRegex;
+
+ cmGlobalGenerator const* GlobalGenerator;
+
+ int NextNodeId;
+ // maps from the actual item names to node names in dot:
+ std::map<std::string, std::string> NodeNames;
+
+ bool GenerateForExecutables;
+ bool GenerateForStaticLibs;
+ bool GenerateForSharedLibs;
+ bool GenerateForModuleLibs;
+ bool GenerateForInterfaceLibs;
+ bool GenerateForObjectLibs;
+ bool GenerateForUnknownLibs;
+ bool GenerateForCustomTargets;
+ bool GenerateForExternals;
+ bool GeneratePerTarget;
+ bool GenerateDependers;
+};
diff --git a/Source/cmHexFileConverter.cxx b/Source/cmHexFileConverter.cxx
new file mode 100644
index 0000000..2fa4b55
--- /dev/null
+++ b/Source/cmHexFileConverter.cxx
@@ -0,0 +1,212 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmHexFileConverter.h"
+
+#include <cctype>
+#include <cstdio>
+#include <cstring>
+
+#include "cmSystemTools.h"
+
+#define INTEL_HEX_MIN_LINE_LENGTH (1 + 8 + 2)
+#define INTEL_HEX_MAX_LINE_LENGTH (1 + 8 + (256 * 2) + 2)
+#define MOTOROLA_SREC_MIN_LINE_LENGTH (2 + 2 + 4 + 2)
+#define MOTOROLA_SREC_MAX_LINE_LENGTH (2 + 2 + 8 + (256 * 2) + 2)
+
+static unsigned int ChompStrlen(const char* line)
+{
+ if (line == nullptr) {
+ return 0;
+ }
+ unsigned int length = static_cast<unsigned int>(strlen(line));
+ if ((line[length - 1] == '\n') || (line[length - 1] == '\r')) {
+ length--;
+ }
+ if ((line[length - 1] == '\n') || (line[length - 1] == '\r')) {
+ length--;
+ }
+ return length;
+}
+
+static bool OutputBin(FILE* file, const char* buf, unsigned int startIndex,
+ unsigned int stopIndex)
+{
+ bool success = true;
+ char hexNumber[3];
+ hexNumber[2] = '\0';
+ char outBuf[256];
+ unsigned int outBufCount = 0;
+ for (unsigned int i = startIndex; i < stopIndex; i += 2) {
+ hexNumber[0] = buf[i];
+ hexNumber[1] = buf[i + 1];
+ unsigned int convertedByte = 0;
+ if (sscanf(hexNumber, "%x", &convertedByte) != 1) {
+ success = false;
+ break;
+ }
+ outBuf[outBufCount] = static_cast<char>(convertedByte & 0xff);
+ outBufCount++;
+ }
+ if (success) {
+ success = (fwrite(outBuf, 1, outBufCount, file) == outBufCount);
+ }
+ return success;
+}
+
+// see http://www.die.net/doc/linux/man/man5/srec.5.html
+static bool ConvertMotorolaSrecLine(const char* buf, FILE* outFile)
+{
+ unsigned int slen = ChompStrlen(buf);
+ if ((slen < MOTOROLA_SREC_MIN_LINE_LENGTH) ||
+ (slen > MOTOROLA_SREC_MAX_LINE_LENGTH)) {
+ return false;
+ }
+
+ // line length must be even
+ if (slen % 2 == 1) {
+ return false;
+ }
+
+ if (buf[0] != 'S') {
+ return false;
+ }
+
+ unsigned int dataStart = 0;
+ // ignore extra address records
+ if ((buf[1] == '5') || (buf[1] == '7') || (buf[1] == '8') ||
+ (buf[1] == '9')) {
+ return true;
+ }
+ if (buf[1] == '1') {
+ dataStart = 8;
+ } else if (buf[1] == '2') {
+ dataStart = 10;
+ } else if (buf[1] == '3') {
+ dataStart = 12;
+ } else // unknown record type
+ {
+ return false;
+ }
+
+ // ignore the last two bytes (checksum)
+ return OutputBin(outFile, buf, dataStart, slen - 2);
+}
+
+// see http://en.wikipedia.org/wiki/Intel_hex
+static bool ConvertIntelHexLine(const char* buf, FILE* outFile)
+{
+ unsigned int slen = ChompStrlen(buf);
+ if ((slen < INTEL_HEX_MIN_LINE_LENGTH) ||
+ (slen > INTEL_HEX_MAX_LINE_LENGTH)) {
+ return false;
+ }
+
+ // line length must be odd
+ if (slen % 2 == 0) {
+ return false;
+ }
+
+ if ((buf[0] != ':') || (buf[7] != '0')) {
+ return false;
+ }
+
+ unsigned int dataStart = 0;
+ if ((buf[8] == '0') || (buf[8] == '1')) {
+ dataStart = 9;
+ }
+ // ignore extra address records
+ else if ((buf[8] == '2') || (buf[8] == '3') || (buf[8] == '4') ||
+ (buf[8] == '5')) {
+ return true;
+ } else // unknown record type
+ {
+ return false;
+ }
+
+ // ignore the last two bytes (checksum)
+ return OutputBin(outFile, buf, dataStart, slen - 2);
+}
+
+cmHexFileConverter::FileType cmHexFileConverter::DetermineFileType(
+ const std::string& inFileName)
+{
+ char buf[1024];
+ FILE* inFile = cmsys::SystemTools::Fopen(inFileName, "rb");
+ if (inFile == nullptr) {
+ return Binary;
+ }
+
+ if (!fgets(buf, 1024, inFile)) {
+ buf[0] = 0;
+ }
+ fclose(inFile);
+ FileType type = Binary;
+ unsigned int minLineLength = 0;
+ unsigned int maxLineLength = 0;
+ if (buf[0] == ':') // might be an intel hex file
+ {
+ type = IntelHex;
+ minLineLength = INTEL_HEX_MIN_LINE_LENGTH;
+ maxLineLength = INTEL_HEX_MAX_LINE_LENGTH;
+ } else if (buf[0] == 'S') // might be a motorola srec file
+ {
+ type = MotorolaSrec;
+ minLineLength = MOTOROLA_SREC_MIN_LINE_LENGTH;
+ maxLineLength = MOTOROLA_SREC_MAX_LINE_LENGTH;
+ } else {
+ return Binary;
+ }
+
+ unsigned int slen = ChompStrlen(buf);
+ if ((slen < minLineLength) || (slen > maxLineLength)) {
+ return Binary;
+ }
+
+ for (unsigned int i = 1; i < slen; i++) {
+ if (!isxdigit(buf[i])) {
+ return Binary;
+ }
+ }
+ return type;
+}
+
+bool cmHexFileConverter::TryConvert(const std::string& inFileName,
+ const std::string& outFileName)
+{
+ FileType type = DetermineFileType(inFileName);
+ if (type == Binary) {
+ return false;
+ }
+
+ // try to open the file
+ FILE* inFile = cmsys::SystemTools::Fopen(inFileName, "rb");
+ FILE* outFile = cmsys::SystemTools::Fopen(outFileName, "wb");
+ if ((inFile == nullptr) || (outFile == nullptr)) {
+ if (inFile != nullptr) {
+ fclose(inFile);
+ }
+ if (outFile != nullptr) {
+ fclose(outFile);
+ }
+ return false;
+ }
+
+ // convert them line by line
+ bool success = false;
+ char buf[1024];
+ while (fgets(buf, 1024, inFile) != nullptr) {
+ if (type == MotorolaSrec) {
+ success = ConvertMotorolaSrecLine(buf, outFile);
+ } else if (type == IntelHex) {
+ success = ConvertIntelHexLine(buf, outFile);
+ }
+ if (!success) {
+ break;
+ }
+ }
+
+ // close them again
+ fclose(inFile);
+ fclose(outFile);
+ return success;
+}
diff --git a/Source/cmHexFileConverter.h b/Source/cmHexFileConverter.h
new file mode 100644
index 0000000..35a91ed
--- /dev/null
+++ b/Source/cmHexFileConverter.h
@@ -0,0 +1,26 @@
+/* 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 <string>
+
+/** \class cmHexFileConverter
+ * \brief Can detects Intel Hex and Motorola S-record files and convert them
+ * to binary files.
+ *
+ */
+class cmHexFileConverter
+{
+public:
+ enum FileType
+ {
+ Binary,
+ IntelHex,
+ MotorolaSrec
+ };
+ static FileType DetermineFileType(const std::string& inFileName);
+ static bool TryConvert(const std::string& inFileName,
+ const std::string& outFileName);
+};
diff --git a/Source/cmIDEFlagTable.h b/Source/cmIDEFlagTable.h
new file mode 100644
index 0000000..5901771
--- /dev/null
+++ b/Source/cmIDEFlagTable.h
@@ -0,0 +1,38 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+
+// This is a table mapping XML tag IDE names to command line options
+struct cmIDEFlagTable
+{
+ std::string IDEName; // name used in the IDE xml file
+ std::string commandFlag; // command line flag
+ std::string comment; // comment
+ std::string value; // string value
+ unsigned int special; // flags for special handling requests
+ enum
+ {
+ UserValue = (1 << 0), // flag contains a user-specified value
+ UserIgnored = (1 << 1), // ignore any user value
+ UserRequired = (1 << 2), // match only when user value is non-empty
+ Continue = (1 << 3), // continue looking for matching entries
+ SemicolonAppendable = (1 << 4), // a flag that if specified multiple times
+ // should have its value appended to the
+ // old value with semicolons (e.g.
+ // /NODEFAULTLIB: =>
+ // IgnoreDefaultLibraryNames)
+ UserFollowing = (1 << 5), // expect value in following argument
+ CaseInsensitive = (1 << 6), // flag may be any case
+ SpaceAppendable = (1 << 7), // a flag that if specified multiple times
+ // should have its value appended to the
+ // old value with spaces
+ CommaAppendable = (1 << 8), // a flag that if specified multiple times
+ // should have its value appended to the
+ // old value with commas (e.g. C# /nowarn
+
+ UserValueIgnored = UserValue | UserIgnored,
+ UserValueRequired = UserValue | UserRequired
+ };
+};
diff --git a/Source/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx
new file mode 100644
index 0000000..b53319f
--- /dev/null
+++ b/Source/cmIDEOptions.cxx
@@ -0,0 +1,257 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmIDEOptions.h"
+
+#include <iterator>
+
+#include <cmext/algorithm>
+
+#include <string.h>
+
+#include "cmsys/String.h"
+
+#include "cmAlgorithms.h"
+#include "cmIDEFlagTable.h"
+#include "cmStringAlgorithms.h"
+
+cmIDEOptions::cmIDEOptions()
+{
+ this->DoingDefine = false;
+ this->AllowDefine = true;
+ this->DoingInclude = false;
+ this->AllowSlash = false;
+ this->DoingFollowing = 0;
+ for (int i = 0; i < FlagTableCount; ++i) {
+ this->FlagTable[i] = 0;
+ }
+}
+
+cmIDEOptions::~cmIDEOptions()
+{
+}
+
+void cmIDEOptions::HandleFlag(std::string const& flag)
+{
+ // If the last option was -D then this option is the definition.
+ if (this->DoingDefine) {
+ this->DoingDefine = false;
+ this->Defines.push_back(flag);
+ return;
+ }
+
+ // If the last option was -I then this option is the include directory.
+ if (this->DoingInclude) {
+ this->DoingInclude = false;
+ this->Includes.push_back(flag);
+ return;
+ }
+
+ // If the last option expected a following value, this is it.
+ if (this->DoingFollowing) {
+ this->FlagMapUpdate(this->DoingFollowing, flag);
+ this->DoingFollowing = 0;
+ return;
+ }
+
+ // Look for known arguments.
+ size_t len = flag.length();
+ if (len > 0 && (flag[0] == '-' || (this->AllowSlash && flag[0] == '/'))) {
+ // Look for preprocessor definitions.
+ if (this->AllowDefine && len > 1 && flag[1] == 'D') {
+ if (len <= 2) {
+ // The next argument will have the definition.
+ this->DoingDefine = true;
+ } else {
+ // Store this definition.
+ this->Defines.push_back(flag.substr(2));
+ }
+ return;
+ }
+ // Look for include directory.
+ if (this->AllowInclude && len > 1 && flag[1] == 'I') {
+ if (len <= 2) {
+ // The next argument will have the include directory.
+ this->DoingInclude = true;
+ } else {
+ // Store this include directory.
+ this->Includes.push_back(flag.substr(2));
+ }
+ return;
+ }
+
+ // Look through the available flag tables.
+ bool flag_handled = false;
+ for (int i = 0; i < FlagTableCount && this->FlagTable[i]; ++i) {
+ if (this->CheckFlagTable(this->FlagTable[i], flag, flag_handled)) {
+ return;
+ }
+ }
+
+ // If any map entry handled the flag we are done.
+ if (flag_handled) {
+ return;
+ }
+ }
+
+ // This option is not known. Store it in the output flags.
+ this->StoreUnknownFlag(flag);
+}
+
+bool cmIDEOptions::CheckFlagTable(cmIDEFlagTable const* table,
+ std::string const& flag, bool& flag_handled)
+{
+ const char* pf = flag.c_str() + 1;
+ // Look for an entry in the flag table matching this flag.
+ for (cmIDEFlagTable const* entry = table; !entry->IDEName.empty(); ++entry) {
+ bool entry_found = false;
+ if (entry->special & cmIDEFlagTable::UserValue) {
+ // This flag table entry accepts a user-specified value. If
+ // the entry specifies UserRequired we must match only if a
+ // non-empty value is given.
+ int n = static_cast<int>(entry->commandFlag.length());
+ if ((strncmp(pf, entry->commandFlag.c_str(), n) == 0 ||
+ (entry->special & cmIDEFlagTable::CaseInsensitive &&
+ cmsysString_strncasecmp(pf, entry->commandFlag.c_str(), n))) &&
+ (!(entry->special & cmIDEFlagTable::UserRequired) ||
+ static_cast<int>(strlen(pf)) > n)) {
+ this->FlagMapUpdate(entry, std::string(pf + n));
+ entry_found = true;
+ }
+ } else if (strcmp(pf, entry->commandFlag.c_str()) == 0 ||
+ (entry->special & cmIDEFlagTable::CaseInsensitive &&
+ cmsysString_strcasecmp(pf, entry->commandFlag.c_str()) == 0)) {
+ if (entry->special & cmIDEFlagTable::UserFollowing) {
+ // This flag expects a value in the following argument.
+ this->DoingFollowing = entry;
+ } else {
+ // This flag table entry provides a fixed value.
+ this->FlagMap[entry->IDEName] = entry->value;
+ }
+ entry_found = true;
+ }
+
+ // If the flag has been handled by an entry not requesting a
+ // search continuation we are done.
+ if (entry_found && !(entry->special & cmIDEFlagTable::Continue)) {
+ return true;
+ }
+
+ // If the entry was found the flag has been handled.
+ flag_handled = flag_handled || entry_found;
+ }
+
+ return false;
+}
+
+void cmIDEOptions::FlagMapUpdate(cmIDEFlagTable const* entry,
+ std::string const& new_value)
+{
+ if (entry->special & cmIDEFlagTable::UserIgnored) {
+ // Ignore the user-specified value.
+ this->FlagMap[entry->IDEName] = entry->value;
+ } else if (entry->special & cmIDEFlagTable::SemicolonAppendable) {
+ this->FlagMap[entry->IDEName].push_back(new_value);
+ } else if (entry->special & cmIDEFlagTable::SpaceAppendable) {
+ this->FlagMap[entry->IDEName].append_with_space(new_value);
+ } else if (entry->special & cmIDEFlagTable::CommaAppendable) {
+ this->FlagMap[entry->IDEName].append_with_comma(new_value);
+ } else {
+ // Use the user-specified value.
+ this->FlagMap[entry->IDEName] = new_value;
+ }
+}
+
+void cmIDEOptions::AddDefine(const std::string& def)
+{
+ this->Defines.push_back(def);
+}
+
+void cmIDEOptions::AddDefines(std::string const& defines)
+{
+ if (!defines.empty()) {
+ // Expand the list of definitions.
+ cmExpandList(defines, this->Defines);
+ }
+}
+void cmIDEOptions::AddDefines(const std::vector<std::string>& defines)
+{
+ cm::append(this->Defines, defines);
+}
+
+std::vector<std::string> const& cmIDEOptions::GetDefines() const
+{
+ return this->Defines;
+}
+
+void cmIDEOptions::AddInclude(const std::string& include)
+{
+ this->Includes.push_back(include);
+}
+
+void cmIDEOptions::AddIncludes(std::string const& includes)
+{
+ if (!includes.empty()) {
+ // Expand the list of includes.
+ cmExpandList(includes, this->Includes);
+ }
+}
+void cmIDEOptions::AddIncludes(const std::vector<std::string>& includes)
+{
+ cm::append(this->Includes, includes);
+}
+
+std::vector<std::string> const& cmIDEOptions::GetIncludes() const
+{
+ return this->Includes;
+}
+
+void cmIDEOptions::AddFlag(std::string const& flag, std::string const& value)
+{
+ this->FlagMap[flag] = value;
+}
+
+void cmIDEOptions::AddFlag(std::string const& flag,
+ std::vector<std::string> const& value)
+{
+ this->FlagMap[flag] = value;
+}
+
+void cmIDEOptions::AppendFlag(std::string const& flag,
+ std::string const& value)
+{
+ this->FlagMap[flag].push_back(value);
+}
+
+void cmIDEOptions::AppendFlag(std::string const& flag,
+ std::vector<std::string> const& value)
+{
+ FlagValue& fv = this->FlagMap[flag];
+ std::copy(value.begin(), value.end(), std::back_inserter(fv));
+}
+
+void cmIDEOptions::AppendFlagString(std::string const& flag,
+ std::string const& value)
+{
+ this->FlagMap[flag].append_with_space(value);
+}
+
+void cmIDEOptions::RemoveFlag(std::string const& flag)
+{
+ this->FlagMap.erase(flag);
+}
+
+bool cmIDEOptions::HasFlag(std::string const& flag) const
+{
+ return this->FlagMap.find(flag) != this->FlagMap.end();
+}
+
+const char* cmIDEOptions::GetFlag(std::string const& flag) const
+{
+ // This method works only for single-valued flags!
+ std::map<std::string, FlagValue>::const_iterator i =
+ this->FlagMap.find(flag);
+ if (i != this->FlagMap.cend() && i->second.size() == 1) {
+ return i->second[0].c_str();
+ }
+ return nullptr;
+}
diff --git a/Source/cmIDEOptions.h b/Source/cmIDEOptions.h
new file mode 100644
index 0000000..fbe9c37
--- /dev/null
+++ b/Source/cmIDEOptions.h
@@ -0,0 +1,113 @@
+/* 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 <map>
+#include <string>
+#include <vector>
+
+struct cmIDEFlagTable;
+
+/** \class cmIDEOptions
+ * \brief Superclass for IDE option processing
+ */
+class cmIDEOptions
+{
+public:
+ cmIDEOptions();
+ virtual ~cmIDEOptions();
+
+ // Store definitions, includes and flags.
+ void AddDefine(const std::string& define);
+ void AddDefines(std::string const& defines);
+ void AddDefines(const std::vector<std::string>& defines);
+ std::vector<std::string> const& GetDefines() const;
+
+ void AddInclude(const std::string& includes);
+ void AddIncludes(std::string const& includes);
+ void AddIncludes(const std::vector<std::string>& includes);
+ std::vector<std::string> const& GetIncludes() const;
+
+ void AddFlag(std::string const& flag, std::string const& value);
+ void AddFlag(std::string const& flag, std::vector<std::string> const& value);
+ void AppendFlag(std::string const& flag, std::string const& value);
+ void AppendFlag(std::string const& flag,
+ std::vector<std::string> const& value);
+ void AppendFlagString(std::string const& flag, std::string const& value);
+ void RemoveFlag(std::string const& flag);
+ bool HasFlag(std::string const& flag) const;
+ const char* GetFlag(std::string const& flag) const;
+
+protected:
+ // create a map of xml tags to the values they should have in the output
+ // for example, "BufferSecurityCheck" = "TRUE"
+ // first fill this table with the values for the configuration
+ // Debug, Release, etc,
+ // Then parse the command line flags specified in CMAKE_CXX_FLAGS
+ // and CMAKE_C_FLAGS
+ // and overwrite or add new values to this map
+ class FlagValue : public std::vector<std::string>
+ {
+ using derived = std::vector<std::string>;
+
+ public:
+ FlagValue& operator=(std::string const& r)
+ {
+ this->resize(1);
+ this->operator[](0) = r;
+ return *this;
+ }
+ FlagValue& operator=(std::vector<std::string> const& r)
+ {
+ this->derived::operator=(r);
+ return *this;
+ }
+ FlagValue& append_with_comma(std::string const& r)
+ {
+ return append_with_separator(r, ',');
+ }
+ FlagValue& append_with_space(std::string const& r)
+ {
+ return append_with_separator(r, ' ');
+ }
+
+ private:
+ FlagValue& append_with_separator(std::string const& r, char separator)
+ {
+ this->resize(1);
+ std::string& l = this->operator[](0);
+ if (!l.empty()) {
+ l += separator;
+ }
+ l += r;
+ return *this;
+ }
+ };
+ std::map<std::string, FlagValue> FlagMap;
+
+ // Preprocessor definitions.
+ std::vector<std::string> Defines;
+
+ // Include directories.
+ std::vector<std::string> Includes;
+
+ bool DoingDefine;
+ bool AllowDefine;
+ bool DoingInclude;
+ bool AllowInclude;
+ bool AllowSlash;
+ cmIDEFlagTable const* DoingFollowing;
+ enum
+ {
+ FlagTableCount = 16
+ };
+ cmIDEFlagTable const* FlagTable[FlagTableCount];
+ void HandleFlag(std::string const& flag);
+ bool CheckFlagTable(cmIDEFlagTable const* table, std::string const& flag,
+ bool& flag_handled);
+ void FlagMapUpdate(cmIDEFlagTable const* entry,
+ std::string const& new_value);
+ virtual void StoreUnknownFlag(std::string const& flag) = 0;
+};
diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx
new file mode 100644
index 0000000..55f6453
--- /dev/null
+++ b/Source/cmIfCommand.cxx
@@ -0,0 +1,207 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmIfCommand.h"
+
+#include <string>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmConditionEvaluator.h"
+#include "cmExecutionStatus.h"
+#include "cmExpandedCommandArgument.h"
+#include "cmFunctionBlocker.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+static std::string cmIfCommandError(
+ std::vector<cmExpandedCommandArgument> const& args)
+{
+ std::string err = "given arguments:\n ";
+ for (cmExpandedCommandArgument const& i : args) {
+ err += " ";
+ err += cmOutputConverter::EscapeForCMake(i.GetValue());
+ }
+ err += "\n";
+ return err;
+}
+
+class cmIfFunctionBlocker : public cmFunctionBlocker
+{
+public:
+ cm::string_view StartCommandName() const override { return "if"_s; }
+ cm::string_view EndCommandName() const override { return "endif"_s; }
+
+ bool ArgumentsMatch(cmListFileFunction const& lff,
+ cmMakefile&) const override;
+
+ bool Replay(std::vector<cmListFileFunction> functions,
+ cmExecutionStatus& inStatus) override;
+
+ std::vector<cmListFileArgument> Args;
+ bool IsBlocking;
+ bool HasRun = false;
+ bool ElseSeen = false;
+};
+
+bool cmIfFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
+ cmMakefile&) const
+{
+ return lff.Arguments().empty() || lff.Arguments() == this->Args;
+}
+
+bool cmIfFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
+ cmExecutionStatus& inStatus)
+{
+ cmMakefile& mf = inStatus.GetMakefile();
+ // execute the functions for the true parts of the if statement
+ int scopeDepth = 0;
+ for (cmListFileFunction const& func : functions) {
+ // keep track of scope depth
+ if (func.LowerCaseName() == "if") {
+ scopeDepth++;
+ }
+ if (func.LowerCaseName() == "endif") {
+ scopeDepth--;
+ }
+ // watch for our state change
+ if (scopeDepth == 0 && func.LowerCaseName() == "else") {
+
+ if (this->ElseSeen) {
+ cmListFileBacktrace elseBT = mf.GetBacktrace().Push(cmListFileContext{
+ func.OriginalName(), this->GetStartingContext().FilePath,
+ func.Line() });
+ mf.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "A duplicate ELSE command was found inside an IF block.", elseBT);
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+
+ this->IsBlocking = this->HasRun;
+ this->HasRun = true;
+ this->ElseSeen = true;
+
+ // if trace is enabled, print a (trivially) evaluated "else"
+ // statement
+ if (!this->IsBlocking && mf.GetCMakeInstance()->GetTrace()) {
+ mf.PrintCommandTrace(func);
+ }
+ } else if (scopeDepth == 0 && func.LowerCaseName() == "elseif") {
+ cmListFileBacktrace elseifBT = mf.GetBacktrace().Push(
+ cmListFileContext{ func.OriginalName(),
+ this->GetStartingContext().FilePath, func.Line() });
+ if (this->ElseSeen) {
+ mf.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "An ELSEIF command was found after an ELSE command.", elseifBT);
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+
+ if (this->HasRun) {
+ this->IsBlocking = true;
+ } else {
+ // if trace is enabled, print the evaluated "elseif" statement
+ if (mf.GetCMakeInstance()->GetTrace()) {
+ mf.PrintCommandTrace(func);
+ }
+
+ std::string errorString;
+
+ std::vector<cmExpandedCommandArgument> expandedArguments;
+ mf.ExpandArguments(func.Arguments(), expandedArguments);
+
+ MessageType messType;
+
+ cmConditionEvaluator conditionEvaluator(mf, elseifBT);
+
+ bool isTrue =
+ conditionEvaluator.IsTrue(expandedArguments, errorString, messType);
+
+ if (!errorString.empty()) {
+ std::string err =
+ cmStrCat(cmIfCommandError(expandedArguments), errorString);
+ mf.GetCMakeInstance()->IssueMessage(messType, err, elseifBT);
+ if (messType == MessageType::FATAL_ERROR) {
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ }
+
+ if (isTrue) {
+ this->IsBlocking = false;
+ this->HasRun = true;
+ }
+ }
+ }
+
+ // should we execute?
+ else if (!this->IsBlocking) {
+ cmExecutionStatus status(mf);
+ mf.ExecuteCommand(func, status);
+ if (status.GetReturnInvoked()) {
+ inStatus.SetReturnInvoked();
+ return true;
+ }
+ if (status.GetBreakInvoked()) {
+ inStatus.SetBreakInvoked();
+ return true;
+ }
+ if (status.GetContinueInvoked()) {
+ inStatus.SetContinueInvoked();
+ return true;
+ }
+ }
+ }
+ return true;
+}
+
+//=========================================================================
+bool cmIfCommand(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& inStatus)
+{
+ cmMakefile& makefile = inStatus.GetMakefile();
+ std::string errorString;
+
+ std::vector<cmExpandedCommandArgument> expandedArguments;
+ makefile.ExpandArguments(args, expandedArguments);
+
+ MessageType status;
+
+ cmConditionEvaluator conditionEvaluator(makefile, makefile.GetBacktrace());
+
+ bool isTrue =
+ conditionEvaluator.IsTrue(expandedArguments, errorString, status);
+
+ if (!errorString.empty()) {
+ std::string err =
+ cmStrCat("if ", cmIfCommandError(expandedArguments), errorString);
+ if (status == MessageType::FATAL_ERROR) {
+ makefile.IssueMessage(MessageType::FATAL_ERROR, err);
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ makefile.IssueMessage(status, err);
+ }
+
+ {
+ auto fb = cm::make_unique<cmIfFunctionBlocker>();
+ // if is isn't true block the commands
+ fb->IsBlocking = !isTrue;
+ if (isTrue) {
+ fb->HasRun = true;
+ }
+ fb->Args = args;
+ makefile.AddFunctionBlocker(std::move(fb));
+ }
+
+ return true;
+}
diff --git a/Source/cmIfCommand.h b/Source/cmIfCommand.h
new file mode 100644
index 0000000..f056587
--- /dev/null
+++ b/Source/cmIfCommand.h
@@ -0,0 +1,14 @@
+/* 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 <vector>
+
+class cmExecutionStatus;
+struct cmListFileArgument;
+
+/// Starts an if block
+bool cmIfCommand(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx
new file mode 100644
index 0000000..ce1f030
--- /dev/null
+++ b/Source/cmIncludeCommand.cxx
@@ -0,0 +1,185 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmIncludeCommand.h"
+
+#include <map>
+#include <sstream>
+#include <utility>
+
+#include "cmExecutionStatus.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+// cmIncludeCommand
+bool cmIncludeCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ static std::map<std::string, cmPolicies::PolicyID> DeprecatedModules;
+ if (DeprecatedModules.empty()) {
+ DeprecatedModules["Documentation"] = cmPolicies::CMP0106;
+ DeprecatedModules["WriteCompilerDetectionHeader"] = cmPolicies::CMP0120;
+ }
+
+ if (args.empty() || args.size() > 4) {
+ status.SetError("called with wrong number of arguments. "
+ "include() only takes one file.");
+ return false;
+ }
+ bool optional = false;
+ bool noPolicyScope = false;
+ std::string fname = args[0];
+ std::string resultVarName;
+
+ for (unsigned int i = 1; i < args.size(); i++) {
+ if (args[i] == "OPTIONAL") {
+ if (optional) {
+ status.SetError("called with invalid arguments: OPTIONAL used twice");
+ return false;
+ }
+ optional = true;
+ } else if (args[i] == "RESULT_VARIABLE") {
+ if (!resultVarName.empty()) {
+ status.SetError("called with invalid arguments: "
+ "only one result variable allowed");
+ return false;
+ }
+ if (++i < args.size()) {
+ resultVarName = args[i];
+ } else {
+ status.SetError("called with no value for RESULT_VARIABLE.");
+ return false;
+ }
+ } else if (args[i] == "NO_POLICY_SCOPE") {
+ noPolicyScope = true;
+ } else if (i > 1) // compat.: in previous cmake versions the second
+ // parameter was ignored if it wasn't "OPTIONAL"
+ {
+ std::string errorText =
+ cmStrCat("called with invalid argument: ", args[i]);
+ status.SetError(errorText);
+ return false;
+ }
+ }
+
+ if (fname.empty()) {
+ status.GetMakefile().IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ "include() given empty file name (ignored).");
+ return true;
+ }
+
+ if (!cmSystemTools::FileIsFullPath(fname)) {
+ bool system = false;
+ // Not a path. Maybe module.
+ std::string module = cmStrCat(fname, ".cmake");
+ std::string mfile = status.GetMakefile().GetModulesFile(module, system);
+
+ if (system) {
+ auto ModulePolicy = DeprecatedModules.find(fname);
+ if (ModulePolicy != DeprecatedModules.end()) {
+ cmPolicies::PolicyStatus PolicyStatus =
+ status.GetMakefile().GetPolicyStatus(ModulePolicy->second);
+ switch (PolicyStatus) {
+ case cmPolicies::WARN: {
+ status.GetMakefile().IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(cmPolicies::GetPolicyWarning(ModulePolicy->second),
+ "\n"));
+ CM_FALLTHROUGH;
+ }
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ mfile = "";
+ break;
+ }
+ }
+ }
+
+ if (!mfile.empty()) {
+ fname = mfile;
+ }
+ }
+
+ std::string fname_abs = cmSystemTools::CollapseFullPath(
+ fname, status.GetMakefile().GetCurrentSourceDirectory());
+
+ cmGlobalGenerator* gg = status.GetMakefile().GetGlobalGenerator();
+ if (gg->IsExportedTargetsFile(fname_abs)) {
+ const char* modal = nullptr;
+ std::ostringstream e;
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+
+ switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0024)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0024) << "\n";
+ modal = "should";
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ modal = "may";
+ messageType = MessageType::FATAL_ERROR;
+ }
+ if (modal) {
+ e << "The file\n " << fname_abs
+ << "\nwas generated by the export() "
+ "command. It "
+ << modal
+ << " not be used as the argument to the "
+ "include() command. Use ALIAS targets instead to refer to targets "
+ "by alternative names.\n";
+ status.GetMakefile().IssueMessage(messageType, e.str());
+ if (messageType == MessageType::FATAL_ERROR) {
+ return false;
+ }
+ }
+ gg->CreateGenerationObjects();
+ gg->GenerateImportFile(fname_abs);
+ }
+
+ std::string listFile = cmSystemTools::CollapseFullPath(
+ fname, status.GetMakefile().GetCurrentSourceDirectory());
+
+ const bool fileDoesnotExist = !cmSystemTools::FileExists(listFile);
+ const bool fileIsDirectory = cmSystemTools::FileIsDirectory(listFile);
+ if (fileDoesnotExist || fileIsDirectory) {
+ if (!resultVarName.empty()) {
+ status.GetMakefile().AddDefinition(resultVarName, "NOTFOUND");
+ }
+ if (optional) {
+ return true;
+ }
+ if (fileDoesnotExist) {
+ status.SetError(cmStrCat("could not find requested file:\n ", fname));
+ return false;
+ }
+ if (fileIsDirectory) {
+ status.SetError(cmStrCat("requested file is a directory:\n ", fname));
+ return false;
+ }
+ }
+
+ bool readit =
+ status.GetMakefile().ReadDependentFile(listFile, noPolicyScope);
+
+ // add the location of the included file if a result variable was given
+ if (!resultVarName.empty()) {
+ status.GetMakefile().AddDefinition(
+ resultVarName, readit ? fname_abs.c_str() : "NOTFOUND");
+ }
+
+ if (!optional && !readit && !cmSystemTools::GetFatalErrorOccured()) {
+ std::string m = cmStrCat("could not load requested file:\n ", fname);
+ status.SetError(m);
+ return false;
+ }
+ return true;
+}
diff --git a/Source/cmIncludeCommand.h b/Source/cmIncludeCommand.h
new file mode 100644
index 0000000..af26163
--- /dev/null
+++ b/Source/cmIncludeCommand.h
@@ -0,0 +1,19 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief cmIncludeCommand defines a list of distant
+ * files that can be "included" in the current list file.
+ * In almost every sense, this is identical to a C/C++
+ * #include command. Arguments are first expended as usual.
+ */
+bool cmIncludeCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx
new file mode 100644
index 0000000..b408f72
--- /dev/null
+++ b/Source/cmIncludeDirectoryCommand.cxx
@@ -0,0 +1,132 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmIncludeDirectoryCommand.h"
+
+#include <algorithm>
+#include <set>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+static void GetIncludes(cmMakefile& mf, const std::string& arg,
+ std::vector<std::string>& incs);
+static void NormalizeInclude(cmMakefile& mf, std::string& inc);
+
+bool cmIncludeDirectoryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ return true;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ auto i = args.begin();
+
+ bool before = mf.IsOn("CMAKE_INCLUDE_DIRECTORIES_BEFORE");
+ bool system = false;
+
+ if ((*i) == "BEFORE") {
+ before = true;
+ ++i;
+ } else if ((*i) == "AFTER") {
+ before = false;
+ ++i;
+ }
+
+ std::vector<std::string> beforeIncludes;
+ std::vector<std::string> afterIncludes;
+ std::set<std::string> systemIncludes;
+
+ for (; i != args.end(); ++i) {
+ if (*i == "SYSTEM") {
+ system = true;
+ continue;
+ }
+ if (i->empty()) {
+ status.SetError("given empty-string as include directory.");
+ return false;
+ }
+
+ std::vector<std::string> includes;
+
+ GetIncludes(mf, *i, includes);
+
+ if (before) {
+ cm::append(beforeIncludes, includes);
+ } else {
+ cm::append(afterIncludes, includes);
+ }
+ if (system) {
+ systemIncludes.insert(includes.begin(), includes.end());
+ }
+ }
+ std::reverse(beforeIncludes.begin(), beforeIncludes.end());
+
+ mf.AddIncludeDirectories(afterIncludes);
+ mf.AddIncludeDirectories(beforeIncludes, before);
+ mf.AddSystemIncludeDirectories(systemIncludes);
+
+ return true;
+}
+
+// do a lot of cleanup on the arguments because this is one place where folks
+// sometimes take the output of a program and pass it directly into this
+// command not thinking that a single argument could be filled with spaces
+// and newlines etc like below:
+//
+// " /foo/bar
+// /boo/hoo /dingle/berry "
+//
+// ideally that should be three separate arguments but when sucking the
+// output from a program and passing it into a command the cleanup doesn't
+// always happen
+//
+static void GetIncludes(cmMakefile& mf, const std::string& arg,
+ std::vector<std::string>& incs)
+{
+ // break apart any line feed arguments
+ std::string::size_type pos = 0;
+ std::string::size_type lastPos = 0;
+ while ((pos = arg.find('\n', lastPos)) != std::string::npos) {
+ if (pos) {
+ std::string inc = arg.substr(lastPos, pos);
+ NormalizeInclude(mf, inc);
+ if (!inc.empty()) {
+ incs.push_back(std::move(inc));
+ }
+ }
+ lastPos = pos + 1;
+ }
+ std::string inc = arg.substr(lastPos);
+ NormalizeInclude(mf, inc);
+ if (!inc.empty()) {
+ incs.push_back(std::move(inc));
+ }
+}
+
+static void NormalizeInclude(cmMakefile& mf, std::string& inc)
+{
+ std::string::size_type b = inc.find_first_not_of(" \r");
+ std::string::size_type e = inc.find_last_not_of(" \r");
+ if ((b != std::string::npos) && (e != std::string::npos)) {
+ inc.assign(inc, b, 1 + e - b); // copy the remaining substring
+ } else {
+ inc.clear();
+ return;
+ }
+
+ if (!cmIsOff(inc)) {
+ cmSystemTools::ConvertToUnixSlashes(inc);
+ if (!cmSystemTools::FileIsFullPath(inc) &&
+ !cmGeneratorExpression::StartsWithGeneratorExpression(inc)) {
+ inc = cmStrCat(mf.GetCurrentSourceDirectory(), '/', inc);
+ }
+ }
+}
diff --git a/Source/cmIncludeDirectoryCommand.h b/Source/cmIncludeDirectoryCommand.h
new file mode 100644
index 0000000..d830dbf
--- /dev/null
+++ b/Source/cmIncludeDirectoryCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmIncludeDirectoryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmIncludeExternalMSProjectCommand.cxx b/Source/cmIncludeExternalMSProjectCommand.cxx
new file mode 100644
index 0000000..5b532ce
--- /dev/null
+++ b/Source/cmIncludeExternalMSProjectCommand.cxx
@@ -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. */
+#include "cmIncludeExternalMSProjectCommand.h"
+
+#include "cmExecutionStatus.h"
+
+#ifdef _WIN32
+# include "cmGlobalGenerator.h"
+# include "cmMakefile.h"
+# include "cmStateTypes.h"
+# include "cmSystemTools.h"
+# include "cmTarget.h"
+# include "cmake.h"
+#endif
+
+bool cmIncludeExternalMSProjectCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("INCLUDE_EXTERNAL_MSPROJECT called with incorrect "
+ "number of arguments");
+ return false;
+ }
+
+// only compile this for win32 to avoid coverage errors
+#ifdef _WIN32
+ cmMakefile& mf = status.GetMakefile();
+ if (mf.GetDefinition("WIN32") ||
+ mf.GetGlobalGenerator()->IsIncludeExternalMSProjectSupported()) {
+ enum Doing
+ {
+ DoingNone,
+ DoingType,
+ DoingGuid,
+ DoingPlatform
+ };
+
+ Doing doing = DoingNone;
+
+ std::string customType;
+ std::string customGuid;
+ std::string platformMapping;
+
+ std::vector<std::string> depends;
+ for (unsigned int i = 2; i < args.size(); ++i) {
+ if (args[i] == "TYPE") {
+ doing = DoingType;
+ } else if (args[i] == "GUID") {
+ doing = DoingGuid;
+ } else if (args[i] == "PLATFORM") {
+ doing = DoingPlatform;
+ } else {
+ switch (doing) {
+ case DoingNone:
+ depends.push_back(args[i]);
+ break;
+ case DoingType:
+ customType = args[i];
+ break;
+ case DoingGuid:
+ customGuid = args[i];
+ break;
+ case DoingPlatform:
+ platformMapping = args[i];
+ break;
+ }
+ doing = DoingNone;
+ }
+ }
+
+ // Hack together a utility target storing enough information
+ // to reproduce the target inclusion.
+ std::string utility_name = args[0];
+
+ std::string path = args[1];
+ cmSystemTools::ConvertToUnixSlashes(path);
+
+ if (!customGuid.empty()) {
+ std::string guidVariable = utility_name + "_GUID_CMAKE";
+ mf.GetCMakeInstance()->AddCacheEntry(guidVariable, customGuid.c_str(),
+ "Stored GUID",
+ cmStateEnums::INTERNAL);
+ }
+
+ // Create a target instance for this utility.
+ cmTarget* target = mf.AddNewTarget(cmStateEnums::UTILITY, utility_name);
+ if (mf.GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+ target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
+ }
+
+ target->SetProperty("GENERATOR_FILE_NAME", utility_name);
+ target->SetProperty("EXTERNAL_MSPROJECT", path);
+
+ if (!customType.empty())
+ target->SetProperty("VS_PROJECT_TYPE", customType);
+ if (!platformMapping.empty())
+ target->SetProperty("VS_PLATFORM_MAPPING", platformMapping);
+
+ for (std::string const& d : depends) {
+ target->AddUtility(d, false);
+ }
+ }
+#endif
+ return true;
+}
diff --git a/Source/cmIncludeExternalMSProjectCommand.h b/Source/cmIncludeExternalMSProjectCommand.h
new file mode 100644
index 0000000..fd77407
--- /dev/null
+++ b/Source/cmIncludeExternalMSProjectCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmIncludeExternalMSProjectCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmIncludeGuardCommand.cxx b/Source/cmIncludeGuardCommand.cxx
new file mode 100644
index 0000000..aefd098
--- /dev/null
+++ b/Source/cmIncludeGuardCommand.cxx
@@ -0,0 +1,108 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmIncludeGuardCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+namespace {
+
+enum IncludeGuardScope
+{
+ VARIABLE,
+ DIRECTORY,
+ GLOBAL
+};
+
+std::string GetIncludeGuardVariableName(std::string const& filePath)
+{
+ std::string result = "__INCGUARD_";
+#ifndef CMAKE_BOOTSTRAP
+ result += cmSystemTools::ComputeStringMD5(filePath);
+#else
+ result += cmSystemTools::MakeCidentifier(filePath);
+#endif
+ result += "__";
+ return result;
+}
+
+bool CheckIncludeGuardIsSet(cmMakefile* mf, std::string const& includeGuardVar)
+{
+ if (mf->GetProperty(includeGuardVar)) {
+ return true;
+ }
+ cmStateSnapshot dirSnapshot =
+ mf->GetStateSnapshot().GetBuildsystemDirectoryParent();
+ while (dirSnapshot.GetState()) {
+ cmStateDirectory stateDir = dirSnapshot.GetDirectory();
+ if (stateDir.GetProperty(includeGuardVar)) {
+ return true;
+ }
+ dirSnapshot = dirSnapshot.GetBuildsystemDirectoryParent();
+ }
+ return false;
+}
+
+} // anonymous namespace
+
+// cmIncludeGuardCommand
+bool cmIncludeGuardCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() > 1) {
+ status.SetError(
+ "given an invalid number of arguments. The command takes at "
+ "most 1 argument.");
+ return false;
+ }
+
+ IncludeGuardScope scope = VARIABLE;
+
+ if (!args.empty()) {
+ std::string const& arg = args[0];
+ if (arg == "DIRECTORY") {
+ scope = DIRECTORY;
+ } else if (arg == "GLOBAL") {
+ scope = GLOBAL;
+ } else {
+ status.SetError("given an invalid scope: " + arg);
+ return false;
+ }
+ }
+
+ std::string includeGuardVar = GetIncludeGuardVariableName(
+ *status.GetMakefile().GetDefinition("CMAKE_CURRENT_LIST_FILE"));
+
+ cmMakefile* const mf = &status.GetMakefile();
+
+ switch (scope) {
+ case VARIABLE:
+ if (mf->IsDefinitionSet(includeGuardVar)) {
+ status.SetReturnInvoked();
+ return true;
+ }
+ mf->AddDefinitionBool(includeGuardVar, true);
+ break;
+ case DIRECTORY:
+ if (CheckIncludeGuardIsSet(mf, includeGuardVar)) {
+ status.SetReturnInvoked();
+ return true;
+ }
+ mf->SetProperty(includeGuardVar, "TRUE");
+ break;
+ case GLOBAL:
+ cmake* const cm = mf->GetCMakeInstance();
+ if (cm->GetProperty(includeGuardVar)) {
+ status.SetReturnInvoked();
+ return true;
+ }
+ cm->SetProperty(includeGuardVar, "TRUE");
+ break;
+ }
+
+ return true;
+}
diff --git a/Source/cmIncludeGuardCommand.h b/Source/cmIncludeGuardCommand.h
new file mode 100644
index 0000000..c4de3d4
--- /dev/null
+++ b/Source/cmIncludeGuardCommand.h
@@ -0,0 +1,19 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief cmIncludeGuardCommand identical to C++ #pragma_once command
+ * Can work in 3 modes: GLOBAL (works on global properties),
+ * DIRECTORY(use directory property), VARIABLE(unnamed overload without
+ * arguments) define an ordinary variable to be used as include guard checker
+ */
+bool cmIncludeGuardCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmIncludeRegularExpressionCommand.cxx b/Source/cmIncludeRegularExpressionCommand.cxx
new file mode 100644
index 0000000..655ebd6
--- /dev/null
+++ b/Source/cmIncludeRegularExpressionCommand.cxx
@@ -0,0 +1,24 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmIncludeRegularExpressionCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+
+bool cmIncludeRegularExpressionCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty() || args.size() > 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ mf.SetIncludeRegularExpression(args[0].c_str());
+
+ if (args.size() > 1) {
+ mf.SetComplainRegularExpression(args[1]);
+ }
+
+ return true;
+}
diff --git a/Source/cmIncludeRegularExpressionCommand.h b/Source/cmIncludeRegularExpressionCommand.h
new file mode 100644
index 0000000..a402f97
--- /dev/null
+++ b/Source/cmIncludeRegularExpressionCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmIncludeRegularExpressionCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
new file mode 100644
index 0000000..7788db3
--- /dev/null
+++ b/Source/cmInstallCommand.cxx
@@ -0,0 +1,1707 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallCommand.h"
+
+#include <cstddef>
+#include <set>
+#include <sstream>
+#include <utility>
+
+#include <cm/memory>
+#include <cmext/string_view>
+
+#include "cmsys/Glob.hxx"
+
+#include "cmArgumentParser.h"
+#include "cmExecutionStatus.h"
+#include "cmExportSet.h"
+#include "cmGeneratorExpression.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallCommandArguments.h"
+#include "cmInstallDirectoryGenerator.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallFilesGenerator.h"
+#include "cmInstallGenerator.h"
+#include "cmInstallScriptGenerator.h"
+#include "cmInstallTargetGenerator.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSubcommandTable.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetExport.h"
+
+namespace {
+
+class Helper
+{
+public:
+ Helper(cmExecutionStatus& status)
+ : Status(status)
+ , Makefile(&status.GetMakefile())
+ {
+ this->DefaultComponentName = this->Makefile->GetSafeDefinition(
+ "CMAKE_INSTALL_DEFAULT_COMPONENT_NAME");
+ if (this->DefaultComponentName.empty()) {
+ this->DefaultComponentName = "Unspecified";
+ }
+ }
+
+ void SetError(std::string const& err) { this->Status.SetError(err); }
+
+ bool MakeFilesFullPath(const char* modeName,
+ const std::vector<std::string>& relFiles,
+ std::vector<std::string>& absFiles);
+ bool CheckCMP0006(bool& failure) const;
+
+ std::string GetDestination(const cmInstallCommandArguments* args,
+ const std::string& varName,
+ const std::string& guess) const;
+ std::string GetRuntimeDestination(
+ const cmInstallCommandArguments* args) const;
+ std::string GetSbinDestination(const cmInstallCommandArguments* args) const;
+ std::string GetArchiveDestination(
+ const cmInstallCommandArguments* args) const;
+ std::string GetLibraryDestination(
+ const cmInstallCommandArguments* args) const;
+ std::string GetIncludeDestination(
+ const cmInstallCommandArguments* args) const;
+ std::string GetSysconfDestination(
+ const cmInstallCommandArguments* args) const;
+ std::string GetSharedStateDestination(
+ const cmInstallCommandArguments* args) const;
+ std::string GetLocalStateDestination(
+ const cmInstallCommandArguments* args) const;
+ std::string GetRunStateDestination(
+ const cmInstallCommandArguments* args) const;
+ std::string GetDataRootDestination(
+ const cmInstallCommandArguments* args) const;
+ std::string GetDataDestination(const cmInstallCommandArguments* args) const;
+ std::string GetInfoDestination(const cmInstallCommandArguments* args) const;
+ std::string GetLocaleDestination(
+ const cmInstallCommandArguments* args) const;
+ std::string GetManDestination(const cmInstallCommandArguments* args) const;
+ std::string GetDocDestination(const cmInstallCommandArguments* args) const;
+ std::string GetDestinationForType(const cmInstallCommandArguments* args,
+ const std::string& type) const;
+
+ cmExecutionStatus& Status;
+ cmMakefile* Makefile;
+ std::string DefaultComponentName;
+};
+
+std::unique_ptr<cmInstallTargetGenerator> CreateInstallTargetGenerator(
+ cmTarget& target, const cmInstallCommandArguments& args, bool impLib,
+ cmListFileBacktrace const& backtrace, const std::string& destination,
+ bool forceOpt = false, bool namelink = false)
+{
+ cmInstallGenerator::MessageLevel message =
+ cmInstallGenerator::SelectMessageLevel(target.GetMakefile());
+ target.SetHaveInstallRule(true);
+ const std::string& component =
+ namelink ? args.GetNamelinkComponent() : args.GetComponent();
+ auto g = cm::make_unique<cmInstallTargetGenerator>(
+ target.GetName(), destination, impLib, args.GetPermissions(),
+ args.GetConfigurations(), component, message, args.GetExcludeFromAll(),
+ args.GetOptional() || forceOpt, backtrace);
+ target.AddInstallGenerator(g.get());
+ return g;
+}
+
+std::unique_ptr<cmInstallTargetGenerator> CreateInstallTargetGenerator(
+ cmTarget& target, const cmInstallCommandArguments& args, bool impLib,
+ cmListFileBacktrace const& backtrace, bool forceOpt = false,
+ bool namelink = false)
+{
+ return CreateInstallTargetGenerator(target, args, impLib, backtrace,
+ args.GetDestination(), forceOpt,
+ namelink);
+}
+
+std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator(
+ cmMakefile* mf, const std::vector<std::string>& absFiles,
+ const cmInstallCommandArguments& args, bool programs,
+ const std::string& destination)
+{
+ cmInstallGenerator::MessageLevel message =
+ cmInstallGenerator::SelectMessageLevel(mf);
+ return cm::make_unique<cmInstallFilesGenerator>(
+ absFiles, destination, programs, args.GetPermissions(),
+ args.GetConfigurations(), args.GetComponent(), message,
+ args.GetExcludeFromAll(), args.GetRename(), args.GetOptional(),
+ mf->GetBacktrace());
+}
+
+std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator(
+ cmMakefile* mf, const std::vector<std::string>& absFiles,
+ const cmInstallCommandArguments& args, bool programs)
+{
+ return CreateInstallFilesGenerator(mf, absFiles, args, programs,
+ args.GetDestination());
+}
+
+std::set<std::string> const allowedTypes{
+ "BIN", "SBIN", "LIB", "INCLUDE", "SYSCONF",
+ "SHAREDSTATE", "LOCALSTATE", "RUNSTATE", "DATA", "INFO",
+ "LOCALE", "MAN", "DOC",
+};
+
+bool HandleScriptMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ Helper helper(status);
+
+ std::string component = helper.DefaultComponentName;
+ int componentCount = 0;
+ bool doing_script = false;
+ bool doing_code = false;
+ bool exclude_from_all = false;
+
+ // Scan the args once for COMPONENT. Only allow one.
+ //
+ for (size_t i = 0; i < args.size(); ++i) {
+ if (args[i] == "COMPONENT" && i + 1 < args.size()) {
+ ++componentCount;
+ ++i;
+ component = args[i];
+ }
+ if (args[i] == "EXCLUDE_FROM_ALL") {
+ exclude_from_all = true;
+ }
+ }
+
+ if (componentCount > 1) {
+ status.SetError("given more than one COMPONENT for the SCRIPT or CODE "
+ "signature of the INSTALL command. "
+ "Use multiple INSTALL commands with one COMPONENT each.");
+ return false;
+ }
+
+ // Scan the args again, this time adding install generators each time we
+ // encounter a SCRIPT or CODE arg:
+ //
+ for (std::string const& arg : args) {
+ if (arg == "SCRIPT") {
+ doing_script = true;
+ doing_code = false;
+ } else if (arg == "CODE") {
+ doing_script = false;
+ doing_code = true;
+ } else if (arg == "COMPONENT") {
+ doing_script = false;
+ doing_code = false;
+ } else if (doing_script) {
+ doing_script = false;
+ std::string script = arg;
+ if (!cmSystemTools::FileIsFullPath(script)) {
+ script =
+ cmStrCat(helper.Makefile->GetCurrentSourceDirectory(), '/', arg);
+ }
+ if (cmSystemTools::FileIsDirectory(script)) {
+ status.SetError("given a directory as value of SCRIPT argument.");
+ return false;
+ }
+ helper.Makefile->AddInstallGenerator(
+ cm::make_unique<cmInstallScriptGenerator>(
+ script, false, component, exclude_from_all,
+ helper.Makefile->GetBacktrace()));
+ } else if (doing_code) {
+ doing_code = false;
+ std::string const& code = arg;
+ helper.Makefile->AddInstallGenerator(
+ cm::make_unique<cmInstallScriptGenerator>(
+ code, true, component, exclude_from_all,
+ helper.Makefile->GetBacktrace()));
+ }
+ }
+
+ if (doing_script) {
+ status.SetError("given no value for SCRIPT argument.");
+ return false;
+ }
+ if (doing_code) {
+ status.SetError("given no value for CODE argument.");
+ return false;
+ }
+
+ // Tell the global generator about any installation component names
+ // specified.
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(component);
+
+ return true;
+}
+
+bool HandleTargetsMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ Helper helper(status);
+
+ // This is the TARGETS mode.
+ std::vector<cmTarget*> targets;
+
+ struct ArgVectors
+ {
+ std::vector<std::string> Archive;
+ std::vector<std::string> Library;
+ std::vector<std::string> Runtime;
+ std::vector<std::string> Object;
+ std::vector<std::string> Framework;
+ std::vector<std::string> Bundle;
+ std::vector<std::string> Includes;
+ std::vector<std::string> PrivateHeader;
+ std::vector<std::string> PublicHeader;
+ std::vector<std::string> Resource;
+ };
+
+ static auto const argHelper =
+ cmArgumentParser<ArgVectors>{}
+ .Bind("ARCHIVE"_s, &ArgVectors::Archive)
+ .Bind("LIBRARY"_s, &ArgVectors::Library)
+ .Bind("RUNTIME"_s, &ArgVectors::Runtime)
+ .Bind("OBJECTS"_s, &ArgVectors::Object)
+ .Bind("FRAMEWORK"_s, &ArgVectors::Framework)
+ .Bind("BUNDLE"_s, &ArgVectors::Bundle)
+ .Bind("INCLUDES"_s, &ArgVectors::Includes)
+ .Bind("PRIVATE_HEADER"_s, &ArgVectors::PrivateHeader)
+ .Bind("PUBLIC_HEADER"_s, &ArgVectors::PublicHeader)
+ .Bind("RESOURCE"_s, &ArgVectors::Resource);
+
+ std::vector<std::string> genericArgVector;
+ ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector);
+
+ // now parse the generic args (i.e. the ones not specialized on LIBRARY/
+ // ARCHIVE, RUNTIME etc. (see above)
+ // These generic args also contain the targets and the export stuff
+ std::vector<std::string> targetList;
+ std::string exports;
+ std::vector<std::string> unknownArgs;
+ cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
+ genericArgs.Bind("TARGETS"_s, targetList);
+ genericArgs.Bind("EXPORT"_s, exports);
+ genericArgs.Parse(genericArgVector, &unknownArgs);
+ bool success = genericArgs.Finalize();
+
+ cmInstallCommandArguments archiveArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments objectArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments bundleArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments privateHeaderArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments publicHeaderArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments resourceArgs(helper.DefaultComponentName);
+ cmInstallCommandIncludesArgument includesArgs;
+
+ // now parse the args for specific parts of the target (e.g. LIBRARY,
+ // RUNTIME, ARCHIVE etc.
+ archiveArgs.Parse(argVectors.Archive, &unknownArgs);
+ libraryArgs.Parse(argVectors.Library, &unknownArgs);
+ runtimeArgs.Parse(argVectors.Runtime, &unknownArgs);
+ objectArgs.Parse(argVectors.Object, &unknownArgs);
+ frameworkArgs.Parse(argVectors.Framework, &unknownArgs);
+ bundleArgs.Parse(argVectors.Bundle, &unknownArgs);
+ privateHeaderArgs.Parse(argVectors.PrivateHeader, &unknownArgs);
+ publicHeaderArgs.Parse(argVectors.PublicHeader, &unknownArgs);
+ resourceArgs.Parse(argVectors.Resource, &unknownArgs);
+ includesArgs.Parse(&argVectors.Includes, &unknownArgs);
+
+ if (!unknownArgs.empty()) {
+ // Unknown argument.
+ status.SetError(
+ cmStrCat("TARGETS given unknown argument \"", unknownArgs[0], "\"."));
+ return false;
+ }
+
+ // apply generic args
+ archiveArgs.SetGenericArguments(&genericArgs);
+ libraryArgs.SetGenericArguments(&genericArgs);
+ runtimeArgs.SetGenericArguments(&genericArgs);
+ objectArgs.SetGenericArguments(&genericArgs);
+ frameworkArgs.SetGenericArguments(&genericArgs);
+ bundleArgs.SetGenericArguments(&genericArgs);
+ privateHeaderArgs.SetGenericArguments(&genericArgs);
+ publicHeaderArgs.SetGenericArguments(&genericArgs);
+ resourceArgs.SetGenericArguments(&genericArgs);
+
+ success = success && archiveArgs.Finalize();
+ success = success && libraryArgs.Finalize();
+ success = success && runtimeArgs.Finalize();
+ success = success && objectArgs.Finalize();
+ success = success && frameworkArgs.Finalize();
+ success = success && bundleArgs.Finalize();
+ success = success && privateHeaderArgs.Finalize();
+ success = success && publicHeaderArgs.Finalize();
+ success = success && resourceArgs.Finalize();
+
+ if (!success) {
+ return false;
+ }
+
+ // Enforce argument rules too complex to specify for the
+ // general-purpose parser.
+ if (archiveArgs.GetNamelinkOnly() || runtimeArgs.GetNamelinkOnly() ||
+ objectArgs.GetNamelinkOnly() || frameworkArgs.GetNamelinkOnly() ||
+ bundleArgs.GetNamelinkOnly() || privateHeaderArgs.GetNamelinkOnly() ||
+ publicHeaderArgs.GetNamelinkOnly() || resourceArgs.GetNamelinkOnly()) {
+ status.SetError(
+ "TARGETS given NAMELINK_ONLY option not in LIBRARY group. "
+ "The NAMELINK_ONLY option may be specified only following LIBRARY.");
+ return false;
+ }
+ if (archiveArgs.GetNamelinkSkip() || runtimeArgs.GetNamelinkSkip() ||
+ objectArgs.GetNamelinkSkip() || frameworkArgs.GetNamelinkSkip() ||
+ bundleArgs.GetNamelinkSkip() || privateHeaderArgs.GetNamelinkSkip() ||
+ publicHeaderArgs.GetNamelinkSkip() || resourceArgs.GetNamelinkSkip()) {
+ status.SetError(
+ "TARGETS given NAMELINK_SKIP option not in LIBRARY group. "
+ "The NAMELINK_SKIP option may be specified only following LIBRARY.");
+ return false;
+ }
+ if (archiveArgs.HasNamelinkComponent() ||
+ runtimeArgs.HasNamelinkComponent() ||
+ objectArgs.HasNamelinkComponent() ||
+ frameworkArgs.HasNamelinkComponent() ||
+ bundleArgs.HasNamelinkComponent() ||
+ privateHeaderArgs.HasNamelinkComponent() ||
+ publicHeaderArgs.HasNamelinkComponent() ||
+ resourceArgs.HasNamelinkComponent()) {
+ status.SetError(
+ "TARGETS given NAMELINK_COMPONENT option not in LIBRARY group. "
+ "The NAMELINK_COMPONENT option may be specified only following "
+ "LIBRARY.");
+ return false;
+ }
+ if (libraryArgs.GetNamelinkOnly() && libraryArgs.GetNamelinkSkip()) {
+ status.SetError("TARGETS given NAMELINK_ONLY and NAMELINK_SKIP. "
+ "At most one of these two options may be specified.");
+ return false;
+ }
+ if (!genericArgs.GetType().empty() || !archiveArgs.GetType().empty() ||
+ !libraryArgs.GetType().empty() || !runtimeArgs.GetType().empty() ||
+ !objectArgs.GetType().empty() || !frameworkArgs.GetType().empty() ||
+ !bundleArgs.GetType().empty() || !privateHeaderArgs.GetType().empty() ||
+ !publicHeaderArgs.GetType().empty() || !resourceArgs.GetType().empty()) {
+ status.SetError(
+ "TARGETS given TYPE option. The TYPE option may only be specified in "
+ " install(FILES) and install(DIRECTORIES).");
+ return false;
+ }
+
+ // Select the mode for installing symlinks to versioned shared libraries.
+ cmInstallTargetGenerator::NamelinkModeType namelinkMode =
+ cmInstallTargetGenerator::NamelinkModeNone;
+ if (libraryArgs.GetNamelinkOnly()) {
+ namelinkMode = cmInstallTargetGenerator::NamelinkModeOnly;
+ } else if (libraryArgs.GetNamelinkSkip()) {
+ namelinkMode = cmInstallTargetGenerator::NamelinkModeSkip;
+ }
+
+ // Check if there is something to do.
+ if (targetList.empty()) {
+ return true;
+ }
+
+ for (std::string const& tgt : targetList) {
+
+ if (helper.Makefile->IsAlias(tgt)) {
+ status.SetError(
+ cmStrCat("TARGETS given target \"", tgt, "\" which is an alias."));
+ return false;
+ }
+ // Lookup this target in the current directory.
+ cmTarget* target = helper.Makefile->FindLocalNonAliasTarget(tgt);
+ if (!target) {
+ // If no local target has been found, find it in the global scope.
+ cmTarget* const global_target =
+ helper.Makefile->GetGlobalGenerator()->FindTarget(tgt, true);
+ if (global_target && !global_target->IsImported()) {
+ target = global_target;
+ }
+ }
+ if (target) {
+ // Found the target. Check its type.
+ if (target->GetType() != cmStateEnums::EXECUTABLE &&
+ target->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ target->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ target->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ target->GetType() != cmStateEnums::OBJECT_LIBRARY &&
+ target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+ status.SetError(
+ cmStrCat("TARGETS given target \"", tgt,
+ "\" which is not an executable, library, or module."));
+ return false;
+ }
+ // Store the target in the list to be installed.
+ targets.push_back(target);
+ } else {
+ // Did not find the target.
+ status.SetError(
+ cmStrCat("TARGETS given target \"", tgt, "\" which does not exist."));
+ return false;
+ }
+ }
+
+ // Keep track of whether we will be performing an installation of
+ // any files of the given type.
+ bool installsArchive = false;
+ bool installsLibrary = false;
+ bool installsNamelink = false;
+ bool installsRuntime = false;
+ bool installsObject = false;
+ bool installsFramework = false;
+ bool installsBundle = false;
+ bool installsPrivateHeader = false;
+ bool installsPublicHeader = false;
+ bool installsResource = false;
+
+ // Generate install script code to install the given targets.
+ for (cmTarget* ti : targets) {
+ // Handle each target type.
+ cmTarget& target = *ti;
+ std::unique_ptr<cmInstallTargetGenerator> archiveGenerator;
+ std::unique_ptr<cmInstallTargetGenerator> libraryGenerator;
+ std::unique_ptr<cmInstallTargetGenerator> namelinkGenerator;
+ std::unique_ptr<cmInstallTargetGenerator> runtimeGenerator;
+ std::unique_ptr<cmInstallTargetGenerator> objectGenerator;
+ std::unique_ptr<cmInstallTargetGenerator> frameworkGenerator;
+ std::unique_ptr<cmInstallTargetGenerator> bundleGenerator;
+ std::unique_ptr<cmInstallFilesGenerator> privateHeaderGenerator;
+ std::unique_ptr<cmInstallFilesGenerator> publicHeaderGenerator;
+ std::unique_ptr<cmInstallFilesGenerator> resourceGenerator;
+
+ // Avoid selecting default destinations for PUBLIC_HEADER and
+ // PRIVATE_HEADER if any artifacts are specified.
+ bool artifactsSpecified = false;
+
+ // Track whether this is a namelink-only rule.
+ bool namelinkOnly = false;
+
+ auto addTargetExport = [&]() {
+ // Add this install rule to an export if one was specified.
+ if (!exports.empty()) {
+ auto te = cm::make_unique<cmTargetExport>();
+ te->TargetName = target.GetName();
+ te->ArchiveGenerator = archiveGenerator.get();
+ te->BundleGenerator = bundleGenerator.get();
+ te->FrameworkGenerator = frameworkGenerator.get();
+ te->HeaderGenerator = publicHeaderGenerator.get();
+ te->LibraryGenerator = libraryGenerator.get();
+ te->RuntimeGenerator = runtimeGenerator.get();
+ te->ObjectsGenerator = objectGenerator.get();
+ te->InterfaceIncludeDirectories =
+ cmJoin(includesArgs.GetIncludeDirs(), ";");
+ te->NamelinkOnly = namelinkOnly;
+ helper.Makefile->GetGlobalGenerator()
+ ->GetExportSets()[exports]
+ .AddTargetExport(std::move(te));
+ }
+ };
+
+ switch (target.GetType()) {
+ case cmStateEnums::SHARED_LIBRARY: {
+ // Shared libraries are handled differently on DLL and non-DLL
+ // platforms. All windows platforms are DLL platforms including
+ // cygwin. Currently no other platform is a DLL platform.
+ if (target.IsDLLPlatform()) {
+ // When in namelink only mode skip all libraries on Windows.
+ if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
+ namelinkOnly = true;
+ addTargetExport();
+ continue;
+ }
+
+ // This is a DLL platform.
+ if (!archiveArgs.GetDestination().empty()) {
+ // The import library uses the ARCHIVE properties.
+ archiveGenerator = CreateInstallTargetGenerator(
+ target, archiveArgs, true, helper.Makefile->GetBacktrace());
+ artifactsSpecified = true;
+ }
+ if (!runtimeArgs.GetDestination().empty()) {
+ // The DLL uses the RUNTIME properties.
+ runtimeGenerator = CreateInstallTargetGenerator(
+ target, runtimeArgs, false, helper.Makefile->GetBacktrace());
+ artifactsSpecified = true;
+ }
+ if (!archiveGenerator && !runtimeGenerator) {
+ archiveGenerator = CreateInstallTargetGenerator(
+ target, archiveArgs, true, helper.Makefile->GetBacktrace(),
+ helper.GetArchiveDestination(nullptr));
+ runtimeGenerator = CreateInstallTargetGenerator(
+ target, runtimeArgs, false, helper.Makefile->GetBacktrace(),
+ helper.GetRuntimeDestination(nullptr));
+ }
+ } else {
+ // This is a non-DLL platform.
+ // If it is marked with FRAMEWORK property use the FRAMEWORK set of
+ // INSTALL properties. Otherwise, use the LIBRARY properties.
+ if (target.IsFrameworkOnApple()) {
+ // When in namelink only mode skip frameworks.
+ if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
+ namelinkOnly = true;
+ addTargetExport();
+ continue;
+ }
+
+ // Use the FRAMEWORK properties.
+ if (!frameworkArgs.GetDestination().empty()) {
+ frameworkGenerator = CreateInstallTargetGenerator(
+ target, frameworkArgs, false, helper.Makefile->GetBacktrace());
+ } else {
+ status.SetError(
+ cmStrCat("TARGETS given no FRAMEWORK DESTINATION for shared "
+ "library FRAMEWORK target \"",
+ target.GetName(), "\"."));
+ return false;
+ }
+ } else {
+ // The shared library uses the LIBRARY properties.
+ if (!libraryArgs.GetDestination().empty()) {
+ artifactsSpecified = true;
+ }
+ if (namelinkMode != cmInstallTargetGenerator::NamelinkModeOnly) {
+ libraryGenerator = CreateInstallTargetGenerator(
+ target, libraryArgs, false, helper.Makefile->GetBacktrace(),
+ helper.GetLibraryDestination(&libraryArgs));
+ libraryGenerator->SetNamelinkMode(
+ cmInstallTargetGenerator::NamelinkModeSkip);
+ }
+ if (namelinkMode != cmInstallTargetGenerator::NamelinkModeSkip) {
+ namelinkGenerator = CreateInstallTargetGenerator(
+ target, libraryArgs, false, helper.Makefile->GetBacktrace(),
+ helper.GetLibraryDestination(&libraryArgs), false, true);
+ namelinkGenerator->SetNamelinkMode(
+ cmInstallTargetGenerator::NamelinkModeOnly);
+ }
+ namelinkOnly =
+ (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
+ }
+ }
+ } break;
+ case cmStateEnums::STATIC_LIBRARY: {
+ // If it is marked with FRAMEWORK property use the FRAMEWORK set of
+ // INSTALL properties. Otherwise, use the LIBRARY properties.
+ if (target.IsFrameworkOnApple()) {
+ // When in namelink only mode skip frameworks.
+ if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
+ namelinkOnly = true;
+ addTargetExport();
+ continue;
+ }
+
+ // Use the FRAMEWORK properties.
+ if (!frameworkArgs.GetDestination().empty()) {
+ frameworkGenerator = CreateInstallTargetGenerator(
+ target, frameworkArgs, false, helper.Makefile->GetBacktrace());
+ } else {
+ status.SetError(
+ cmStrCat("TARGETS given no FRAMEWORK DESTINATION for static "
+ "library FRAMEWORK target \"",
+ target.GetName(), "\"."));
+ return false;
+ }
+ } else {
+ // Static libraries use ARCHIVE properties.
+ if (!archiveArgs.GetDestination().empty()) {
+ artifactsSpecified = true;
+ }
+ archiveGenerator = CreateInstallTargetGenerator(
+ target, archiveArgs, false, helper.Makefile->GetBacktrace(),
+ helper.GetArchiveDestination(&archiveArgs));
+ }
+ } break;
+ case cmStateEnums::MODULE_LIBRARY: {
+ // Modules use LIBRARY properties.
+ if (!libraryArgs.GetDestination().empty()) {
+ libraryGenerator = CreateInstallTargetGenerator(
+ target, libraryArgs, false, helper.Makefile->GetBacktrace());
+ libraryGenerator->SetNamelinkMode(namelinkMode);
+ namelinkOnly =
+ (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
+ } else {
+ status.SetError(
+ cmStrCat("TARGETS given no LIBRARY DESTINATION for module "
+ "target \"",
+ target.GetName(), "\"."));
+ return false;
+ }
+ } break;
+ case cmStateEnums::OBJECT_LIBRARY: {
+ // Objects use OBJECT properties.
+ if (!objectArgs.GetDestination().empty()) {
+ // Verify that we know where the objects are to install them.
+ std::string reason;
+ if (!helper.Makefile->GetGlobalGenerator()
+ ->HasKnownObjectFileLocation(&reason)) {
+ status.SetError(
+ cmStrCat("TARGETS given OBJECT library \"", target.GetName(),
+ "\" whose objects may not be installed", reason, "."));
+ return false;
+ }
+
+ objectGenerator = CreateInstallTargetGenerator(
+ target, objectArgs, false, helper.Makefile->GetBacktrace());
+ } else {
+ // Installing an OBJECT library without a destination transforms
+ // it to an INTERFACE library. It installs no files but can be
+ // exported.
+ }
+ } break;
+ case cmStateEnums::EXECUTABLE: {
+ if (target.IsAppBundleOnApple()) {
+ // Application bundles use the BUNDLE properties.
+ if (!bundleArgs.GetDestination().empty()) {
+ bundleGenerator = CreateInstallTargetGenerator(
+ target, bundleArgs, false, helper.Makefile->GetBacktrace());
+ } else if (!runtimeArgs.GetDestination().empty()) {
+ bool failure = false;
+ if (helper.CheckCMP0006(failure)) {
+ // For CMake 2.4 compatibility fallback to the RUNTIME
+ // properties.
+ bundleGenerator = CreateInstallTargetGenerator(
+ target, runtimeArgs, false, helper.Makefile->GetBacktrace());
+ } else if (failure) {
+ return false;
+ }
+ }
+ if (!bundleGenerator) {
+ status.SetError(cmStrCat("TARGETS given no BUNDLE DESTINATION for "
+ "MACOSX_BUNDLE executable target \"",
+ target.GetName(), "\"."));
+ return false;
+ }
+ } else {
+ // Executables use the RUNTIME properties.
+ if (!runtimeArgs.GetDestination().empty()) {
+ artifactsSpecified = true;
+ }
+ runtimeGenerator = CreateInstallTargetGenerator(
+ target, runtimeArgs, false, helper.Makefile->GetBacktrace(),
+ helper.GetRuntimeDestination(&runtimeArgs));
+ }
+
+ // On DLL platforms an executable may also have an import
+ // library. Install it to the archive destination if it
+ // exists.
+ if ((target.IsDLLPlatform() || target.IsAIX()) &&
+ !archiveArgs.GetDestination().empty() &&
+ target.IsExecutableWithExports()) {
+ // The import library uses the ARCHIVE properties.
+ artifactsSpecified = true;
+ archiveGenerator = CreateInstallTargetGenerator(
+ target, archiveArgs, true, helper.Makefile->GetBacktrace(), true);
+ }
+ } break;
+ case cmStateEnums::INTERFACE_LIBRARY:
+ // Nothing to do. An INTERFACE_LIBRARY can be installed, but the
+ // only effect of that is to make it exportable. It installs no
+ // other files itself.
+ default:
+ // This should never happen due to the above type check.
+ // Ignore the case.
+ break;
+ }
+
+ // These well-known sets of files are installed *automatically* for
+ // FRAMEWORK SHARED library targets on the Mac as part of installing the
+ // FRAMEWORK. For other target types or on other platforms, they are not
+ // installed automatically and so we need to create install files
+ // generators for them.
+ bool createInstallGeneratorsForTargetFileSets = true;
+
+ if (target.IsFrameworkOnApple()) {
+ createInstallGeneratorsForTargetFileSets = false;
+ }
+
+ if (createInstallGeneratorsForTargetFileSets && !namelinkOnly) {
+ cmProp files = target.GetProperty("PRIVATE_HEADER");
+ if (cmNonempty(files)) {
+ std::vector<std::string> relFiles = cmExpandedList(*files);
+ std::vector<std::string> absFiles;
+ if (!helper.MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles)) {
+ return false;
+ }
+
+ // Create the files install generator.
+ if (!artifactsSpecified ||
+ !privateHeaderArgs.GetDestination().empty()) {
+ privateHeaderGenerator = CreateInstallFilesGenerator(
+ helper.Makefile, absFiles, privateHeaderArgs, false,
+ helper.GetIncludeDestination(&privateHeaderArgs));
+ } else {
+ std::ostringstream e;
+ e << "INSTALL TARGETS - target " << target.GetName() << " has "
+ << "PRIVATE_HEADER files but no PRIVATE_HEADER DESTINATION.";
+ cmSystemTools::Message(e.str(), "Warning");
+ }
+ }
+
+ files = target.GetProperty("PUBLIC_HEADER");
+ if (cmNonempty(files)) {
+ std::vector<std::string> relFiles = cmExpandedList(*files);
+ std::vector<std::string> absFiles;
+ if (!helper.MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles)) {
+ return false;
+ }
+
+ // Create the files install generator.
+ if (!artifactsSpecified ||
+ !publicHeaderArgs.GetDestination().empty()) {
+ publicHeaderGenerator = CreateInstallFilesGenerator(
+ helper.Makefile, absFiles, publicHeaderArgs, false,
+ helper.GetIncludeDestination(&publicHeaderArgs));
+ } else {
+ std::ostringstream e;
+ e << "INSTALL TARGETS - target " << target.GetName() << " has "
+ << "PUBLIC_HEADER files but no PUBLIC_HEADER DESTINATION.";
+ cmSystemTools::Message(e.str(), "Warning");
+ }
+ }
+
+ files = target.GetProperty("RESOURCE");
+ if (cmNonempty(files)) {
+ std::vector<std::string> relFiles = cmExpandedList(*files);
+ std::vector<std::string> absFiles;
+ if (!helper.MakeFilesFullPath("RESOURCE", relFiles, absFiles)) {
+ return false;
+ }
+
+ // Create the files install generator.
+ if (!resourceArgs.GetDestination().empty()) {
+ resourceGenerator = CreateInstallFilesGenerator(
+ helper.Makefile, absFiles, resourceArgs, false);
+ } else {
+ cmSystemTools::Message(
+ cmStrCat("INSTALL TARGETS - target ", target.GetName(),
+ " has RESOURCE files but no RESOURCE DESTINATION."),
+ "Warning");
+ }
+ }
+ }
+
+ // Add this install rule to an export if one was specified.
+ addTargetExport();
+
+ // Keep track of whether we're installing anything in each category
+ installsArchive = installsArchive || archiveGenerator;
+ installsLibrary = installsLibrary || libraryGenerator;
+ installsNamelink = installsNamelink || namelinkGenerator;
+ installsRuntime = installsRuntime || runtimeGenerator;
+ installsObject = installsObject || objectGenerator;
+ installsFramework = installsFramework || frameworkGenerator;
+ installsBundle = installsBundle || bundleGenerator;
+ installsPrivateHeader = installsPrivateHeader || privateHeaderGenerator;
+ installsPublicHeader = installsPublicHeader || publicHeaderGenerator;
+ installsResource = installsResource || resourceGenerator;
+
+ helper.Makefile->AddInstallGenerator(std::move(archiveGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(libraryGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(namelinkGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(runtimeGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(objectGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(frameworkGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(bundleGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(privateHeaderGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(publicHeaderGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(resourceGenerator));
+ }
+
+ // Tell the global generator about any installation component names
+ // specified
+ if (installsArchive) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ archiveArgs.GetComponent());
+ }
+ if (installsLibrary) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ libraryArgs.GetComponent());
+ }
+ if (installsNamelink) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ libraryArgs.GetNamelinkComponent());
+ }
+ if (installsRuntime) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ runtimeArgs.GetComponent());
+ }
+ if (installsObject) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ objectArgs.GetComponent());
+ }
+ if (installsFramework) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ frameworkArgs.GetComponent());
+ }
+ if (installsBundle) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ bundleArgs.GetComponent());
+ }
+ if (installsPrivateHeader) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ privateHeaderArgs.GetComponent());
+ }
+ if (installsPublicHeader) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ publicHeaderArgs.GetComponent());
+ }
+ if (installsResource) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ resourceArgs.GetComponent());
+ }
+
+ return true;
+}
+
+bool HandleFilesMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ Helper helper(status);
+
+ // This is the FILES mode.
+ bool programs = (args[0] == "PROGRAMS");
+ cmInstallCommandArguments ica(helper.DefaultComponentName);
+ std::vector<std::string> files;
+ ica.Bind(programs ? "PROGRAMS"_s : "FILES"_s, files);
+ std::vector<std::string> unknownArgs;
+ ica.Parse(args, &unknownArgs);
+
+ if (!unknownArgs.empty()) {
+ // Unknown argument.
+ status.SetError(
+ cmStrCat(args[0], " given unknown argument \"", unknownArgs[0], "\"."));
+ return false;
+ }
+
+ std::string type = ica.GetType();
+ if (!type.empty() && allowedTypes.count(type) == 0) {
+ status.SetError(
+ cmStrCat(args[0], " given non-type \"", type, "\" with TYPE argument."));
+ return false;
+ }
+
+ const std::vector<std::string>& filesVector = files;
+
+ // Check if there is something to do.
+ if (filesVector.empty()) {
+ return true;
+ }
+
+ if (!ica.GetRename().empty() && filesVector.size() > 1) {
+ // The rename option works only with one file.
+ status.SetError(
+ cmStrCat(args[0], " given RENAME option with more than one file."));
+ return false;
+ }
+
+ std::vector<std::string> absFiles;
+ if (!helper.MakeFilesFullPath(args[0].c_str(), filesVector, absFiles)) {
+ return false;
+ }
+
+ cmPolicies::PolicyStatus policyStatus =
+ helper.Makefile->GetPolicyStatus(cmPolicies::CMP0062);
+
+ cmGlobalGenerator* gg = helper.Makefile->GetGlobalGenerator();
+ for (std::string const& file : filesVector) {
+ if (gg->IsExportedTargetsFile(file)) {
+ const char* modal = nullptr;
+ std::ostringstream e;
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+
+ switch (policyStatus) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0062) << "\n";
+ modal = "should";
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ modal = "may";
+ messageType = MessageType::FATAL_ERROR;
+ }
+ if (modal) {
+ e << "The file\n " << file
+ << "\nwas generated by the export() "
+ "command. It "
+ << modal
+ << " not be installed with the "
+ "install() command. Use the install(EXPORT) mechanism "
+ "instead. See the cmake-packages(7) manual for more.\n";
+ helper.Makefile->IssueMessage(messageType, e.str());
+ if (messageType == MessageType::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+ }
+
+ if (!ica.Finalize()) {
+ return false;
+ }
+
+ if (!type.empty() && !ica.GetDestination().empty()) {
+ status.SetError(cmStrCat(args[0],
+ " given both TYPE and DESTINATION arguments. "
+ "You may only specify one."));
+ return false;
+ }
+
+ std::string destination = helper.GetDestinationForType(&ica, type);
+ if (destination.empty()) {
+ // A destination is required.
+ status.SetError(cmStrCat(args[0], " given no DESTINATION!"));
+ return false;
+ }
+
+ // Create the files install generator.
+ helper.Makefile->AddInstallGenerator(CreateInstallFilesGenerator(
+ helper.Makefile, absFiles, ica, programs, destination));
+
+ // Tell the global generator about any installation component names
+ // specified.
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ ica.GetComponent());
+
+ return true;
+}
+
+bool HandleDirectoryMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ Helper helper(status);
+
+ enum Doing
+ {
+ DoingNone,
+ DoingDirs,
+ DoingDestination,
+ DoingPattern,
+ DoingRegex,
+ DoingPermsFile,
+ DoingPermsDir,
+ DoingPermsMatch,
+ DoingConfigurations,
+ DoingComponent,
+ DoingType
+ };
+ Doing doing = DoingDirs;
+ bool in_match_mode = false;
+ bool optional = false;
+ bool exclude_from_all = false;
+ bool message_never = false;
+ std::vector<std::string> dirs;
+ const std::string* destination = nullptr;
+ std::string permissions_file;
+ std::string permissions_dir;
+ std::vector<std::string> configurations;
+ std::string component = helper.DefaultComponentName;
+ std::string literal_args;
+ std::string type;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "DESTINATION") {
+ if (in_match_mode) {
+ status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
+ "\" after PATTERN or REGEX."));
+ return false;
+ }
+
+ // Switch to setting the destination property.
+ doing = DoingDestination;
+ } else if (args[i] == "TYPE") {
+ if (in_match_mode) {
+ status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
+ "\" after PATTERN or REGEX."));
+ return false;
+ }
+
+ // Switch to setting the type.
+ doing = DoingType;
+ } else if (args[i] == "OPTIONAL") {
+ if (in_match_mode) {
+ status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
+ "\" after PATTERN or REGEX."));
+ return false;
+ }
+
+ // Mark the rule as optional.
+ optional = true;
+ doing = DoingNone;
+ } else if (args[i] == "MESSAGE_NEVER") {
+ if (in_match_mode) {
+ status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
+ "\" after PATTERN or REGEX."));
+ return false;
+ }
+
+ // Mark the rule as quiet.
+ message_never = true;
+ doing = DoingNone;
+ } else if (args[i] == "PATTERN") {
+ // Switch to a new pattern match rule.
+ doing = DoingPattern;
+ in_match_mode = true;
+ } else if (args[i] == "REGEX") {
+ // Switch to a new regex match rule.
+ doing = DoingRegex;
+ in_match_mode = true;
+ } else if (args[i] == "EXCLUDE") {
+ // Add this property to the current match rule.
+ if (!in_match_mode || doing == DoingPattern || doing == DoingRegex) {
+ status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
+ "\" before a PATTERN or REGEX is given."));
+ return false;
+ }
+ literal_args += " EXCLUDE";
+ doing = DoingNone;
+ } else if (args[i] == "PERMISSIONS") {
+ if (!in_match_mode) {
+ status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
+ "\" before a PATTERN or REGEX is given."));
+ return false;
+ }
+
+ // Switch to setting the current match permissions property.
+ literal_args += " PERMISSIONS";
+ doing = DoingPermsMatch;
+ } else if (args[i] == "FILE_PERMISSIONS") {
+ if (in_match_mode) {
+ status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
+ "\" after PATTERN or REGEX."));
+ return false;
+ }
+
+ // Switch to setting the file permissions property.
+ doing = DoingPermsFile;
+ } else if (args[i] == "DIRECTORY_PERMISSIONS") {
+ if (in_match_mode) {
+ status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
+ "\" after PATTERN or REGEX."));
+ return false;
+ }
+
+ // Switch to setting the directory permissions property.
+ doing = DoingPermsDir;
+ } else if (args[i] == "USE_SOURCE_PERMISSIONS") {
+ if (in_match_mode) {
+ status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
+ "\" after PATTERN or REGEX."));
+ return false;
+ }
+
+ // Add this option literally.
+ literal_args += " USE_SOURCE_PERMISSIONS";
+ doing = DoingNone;
+ } else if (args[i] == "FILES_MATCHING") {
+ if (in_match_mode) {
+ status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
+ "\" after PATTERN or REGEX."));
+ return false;
+ }
+
+ // Add this option literally.
+ literal_args += " FILES_MATCHING";
+ doing = DoingNone;
+ } else if (args[i] == "CONFIGURATIONS") {
+ if (in_match_mode) {
+ status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
+ "\" after PATTERN or REGEX."));
+ return false;
+ }
+
+ // Switch to setting the configurations property.
+ doing = DoingConfigurations;
+ } else if (args[i] == "COMPONENT") {
+ if (in_match_mode) {
+ status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
+ "\" after PATTERN or REGEX."));
+ return false;
+ }
+
+ // Switch to setting the component property.
+ doing = DoingComponent;
+ } else if (args[i] == "EXCLUDE_FROM_ALL") {
+ if (in_match_mode) {
+ status.SetError(cmStrCat(args[0], " does not allow \"", args[i],
+ "\" after PATTERN or REGEX."));
+ return false;
+ }
+ exclude_from_all = true;
+ doing = DoingNone;
+ } else if (doing == DoingDirs) {
+ // Convert this directory to a full path.
+ std::string dir = args[i];
+ std::string::size_type gpos = cmGeneratorExpression::Find(dir);
+ if (gpos != 0 && !cmSystemTools::FileIsFullPath(dir)) {
+ dir =
+ cmStrCat(helper.Makefile->GetCurrentSourceDirectory(), '/', args[i]);
+ }
+
+ // Make sure the name is a directory.
+ if (cmSystemTools::FileExists(dir) &&
+ !cmSystemTools::FileIsDirectory(dir)) {
+ status.SetError(cmStrCat(args[0], " given non-directory \"", args[i],
+ "\" to install."));
+ return false;
+ }
+
+ // Store the directory for installation.
+ dirs.push_back(std::move(dir));
+ } else if (doing == DoingConfigurations) {
+ configurations.push_back(args[i]);
+ } else if (doing == DoingDestination) {
+ destination = &args[i];
+ doing = DoingNone;
+ } else if (doing == DoingType) {
+ if (allowedTypes.count(args[i]) == 0) {
+ status.SetError(cmStrCat(args[0], " given non-type \"", args[i],
+ "\" with TYPE argument."));
+ return false;
+ }
+
+ type = args[i];
+ doing = DoingNone;
+ } else if (doing == DoingPattern) {
+ // Convert the pattern to a regular expression. Require a
+ // leading slash and trailing end-of-string in the matched
+ // string to make sure the pattern matches only whole file
+ // names.
+ literal_args += " REGEX \"/";
+ std::string regex = cmsys::Glob::PatternToRegex(args[i], false);
+ cmSystemTools::ReplaceString(regex, "\\", "\\\\");
+ literal_args += regex;
+ literal_args += "$\"";
+ doing = DoingNone;
+ } else if (doing == DoingRegex) {
+ literal_args += " REGEX \"";
+// Match rules are case-insensitive on some platforms.
+#if defined(_WIN32) || defined(__APPLE__)
+ std::string regex = cmSystemTools::LowerCase(args[i]);
+#else
+ std::string regex = args[i];
+#endif
+ cmSystemTools::ReplaceString(regex, "\\", "\\\\");
+ literal_args += regex;
+ literal_args += "\"";
+ doing = DoingNone;
+ } else if (doing == DoingComponent) {
+ component = args[i];
+ doing = DoingNone;
+ } else if (doing == DoingPermsFile) {
+ // Check the requested permission.
+ if (!cmInstallCommandArguments::CheckPermissions(args[i],
+ permissions_file)) {
+ status.SetError(cmStrCat(args[0], " given invalid file permission \"",
+ args[i], "\"."));
+ return false;
+ }
+ } else if (doing == DoingPermsDir) {
+ // Check the requested permission.
+ if (!cmInstallCommandArguments::CheckPermissions(args[i],
+ permissions_dir)) {
+ status.SetError(cmStrCat(
+ args[0], " given invalid directory permission \"", args[i], "\"."));
+ return false;
+ }
+ } else if (doing == DoingPermsMatch) {
+ // Check the requested permission.
+ if (!cmInstallCommandArguments::CheckPermissions(args[i],
+ literal_args)) {
+ status.SetError(
+ cmStrCat(args[0], " given invalid permission \"", args[i], "\"."));
+ return false;
+ }
+ } else {
+ // Unknown argument.
+ status.SetError(
+ cmStrCat(args[0], " given unknown argument \"", args[i], "\"."));
+ return false;
+ }
+ }
+
+ // Support installing an empty directory.
+ if (dirs.empty() && destination) {
+ dirs.emplace_back();
+ }
+
+ // Check if there is something to do.
+ if (dirs.empty()) {
+ return true;
+ }
+ std::string destinationStr;
+ if (!destination) {
+ if (type.empty()) {
+ // A destination is required.
+ status.SetError(cmStrCat(args[0], " given no DESTINATION!"));
+ return false;
+ }
+ destinationStr = helper.GetDestinationForType(nullptr, type);
+ destination = &destinationStr;
+ } else if (!type.empty()) {
+ status.SetError(cmStrCat(args[0],
+ " given both TYPE and DESTINATION "
+ "arguments. You may only specify one."));
+ return false;
+ }
+
+ cmInstallGenerator::MessageLevel message =
+ cmInstallGenerator::SelectMessageLevel(helper.Makefile, message_never);
+
+ // Create the directory install generator.
+ helper.Makefile->AddInstallGenerator(
+ cm::make_unique<cmInstallDirectoryGenerator>(
+ dirs, *destination, permissions_file, permissions_dir, configurations,
+ component, message, exclude_from_all, literal_args, optional,
+ helper.Makefile->GetBacktrace()));
+
+ // Tell the global generator about any installation component names
+ // specified.
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(component);
+
+ return true;
+}
+
+bool HandleExportAndroidMKMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+#ifndef CMAKE_BOOTSTRAP
+ Helper helper(status);
+
+ // This is the EXPORT mode.
+ cmInstallCommandArguments ica(helper.DefaultComponentName);
+
+ std::string exp;
+ std::string name_space;
+ bool exportOld = false;
+ std::string filename;
+
+ ica.Bind("EXPORT_ANDROID_MK"_s, exp);
+ ica.Bind("NAMESPACE"_s, name_space);
+ ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld);
+ ica.Bind("FILE"_s, filename);
+
+ std::vector<std::string> unknownArgs;
+ ica.Parse(args, &unknownArgs);
+
+ if (!unknownArgs.empty()) {
+ // Unknown argument.
+ status.SetError(
+ cmStrCat(args[0], " given unknown argument \"", unknownArgs[0], "\"."));
+ return false;
+ }
+
+ if (!ica.Finalize()) {
+ return false;
+ }
+
+ // Make sure there is a destination.
+ if (ica.GetDestination().empty()) {
+ // A destination is required.
+ status.SetError(cmStrCat(args[0], " given no DESTINATION!"));
+ return false;
+ }
+
+ // Check the file name.
+ std::string fname = filename;
+ if (fname.find_first_of(":/\\") != std::string::npos) {
+ status.SetError(cmStrCat(args[0], " given invalid export file name \"",
+ fname,
+ "\". The FILE argument may not contain a path. "
+ "Specify the path in the DESTINATION argument."));
+ return false;
+ }
+
+ // Check the file extension.
+ if (!fname.empty() &&
+ cmSystemTools::GetFilenameLastExtension(fname) != ".mk") {
+ status.SetError(cmStrCat(
+ args[0], " given invalid export file name \"", fname,
+ R"(". The FILE argument must specify a name ending in ".mk".)"));
+ return false;
+ }
+ if (fname.find_first_of(":/\\") != std::string::npos) {
+ status.SetError(
+ cmStrCat(args[0], " given export name \"", exp,
+ "\". "
+ "This name cannot be safely converted to a file name. "
+ "Specify a different export name or use the FILE option to set "
+ "a file name explicitly."));
+ return false;
+ }
+ // Use the default name
+ if (fname.empty()) {
+ fname = "Android.mk";
+ }
+
+ cmExportSet& exportSet =
+ helper.Makefile->GetGlobalGenerator()->GetExportSets()[exp];
+
+ cmInstallGenerator::MessageLevel message =
+ cmInstallGenerator::SelectMessageLevel(helper.Makefile);
+
+ // Create the export install generator.
+ helper.Makefile->AddInstallGenerator(
+ cm::make_unique<cmInstallExportGenerator>(
+ &exportSet, ica.GetDestination(), ica.GetPermissions(),
+ ica.GetConfigurations(), ica.GetComponent(), message,
+ ica.GetExcludeFromAll(), fname, name_space, exportOld, true,
+ helper.Makefile->GetBacktrace()));
+
+ return true;
+#else
+ static_cast<void>(args);
+ status.SetError("EXPORT_ANDROID_MK not supported in bootstrap cmake");
+ return false;
+#endif
+}
+
+bool HandleExportMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ Helper helper(status);
+
+ // This is the EXPORT mode.
+ cmInstallCommandArguments ica(helper.DefaultComponentName);
+
+ std::string exp;
+ std::string name_space;
+ bool exportOld = false;
+ std::string filename;
+
+ ica.Bind("EXPORT"_s, exp);
+ ica.Bind("NAMESPACE"_s, name_space);
+ ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld);
+ ica.Bind("FILE"_s, filename);
+
+ std::vector<std::string> unknownArgs;
+ ica.Parse(args, &unknownArgs);
+
+ if (!unknownArgs.empty()) {
+ // Unknown argument.
+ status.SetError(
+ cmStrCat(args[0], " given unknown argument \"", unknownArgs[0], "\"."));
+ return false;
+ }
+
+ if (!ica.Finalize()) {
+ return false;
+ }
+
+ // Make sure there is a destination.
+ if (ica.GetDestination().empty()) {
+ // A destination is required.
+ status.SetError(cmStrCat(args[0], " given no DESTINATION!"));
+ return false;
+ }
+
+ // Check the file name.
+ std::string fname = filename;
+ if (fname.find_first_of(":/\\") != std::string::npos) {
+ status.SetError(cmStrCat(args[0], " given invalid export file name \"",
+ fname,
+ "\". "
+ "The FILE argument may not contain a path. "
+ "Specify the path in the DESTINATION argument."));
+ return false;
+ }
+
+ // Check the file extension.
+ if (!fname.empty() &&
+ cmSystemTools::GetFilenameLastExtension(fname) != ".cmake") {
+ status.SetError(
+ cmStrCat(args[0], " given invalid export file name \"", fname,
+ "\". "
+ "The FILE argument must specify a name ending in \".cmake\"."));
+ return false;
+ }
+
+ // Construct the file name.
+ if (fname.empty()) {
+ fname = cmStrCat(exp, ".cmake");
+
+ if (fname.find_first_of(":/\\") != std::string::npos) {
+ status.SetError(cmStrCat(
+ args[0], " given export name \"", exp,
+ "\". "
+ "This name cannot be safely converted to a file name. "
+ "Specify a different export name or use the FILE option to set "
+ "a file name explicitly."));
+ return false;
+ }
+ }
+
+ cmExportSet& exportSet =
+ helper.Makefile->GetGlobalGenerator()->GetExportSets()[exp];
+ if (exportOld) {
+ for (auto const& te : exportSet.GetTargetExports()) {
+ cmTarget* tgt =
+ helper.Makefile->GetGlobalGenerator()->FindTarget(te->TargetName);
+ const bool newCMP0022Behavior =
+ (tgt && tgt->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
+ tgt->GetPolicyStatusCMP0022() != cmPolicies::OLD);
+
+ if (!newCMP0022Behavior) {
+ status.SetError(cmStrCat(
+ "INSTALL(EXPORT) given keyword \""
+ "EXPORT_LINK_INTERFACE_LIBRARIES\", but target \"",
+ te->TargetName, "\" does not have policy CMP0022 set to NEW."));
+ return false;
+ }
+ }
+ }
+
+ cmInstallGenerator::MessageLevel message =
+ cmInstallGenerator::SelectMessageLevel(helper.Makefile);
+
+ // Create the export install generator.
+ helper.Makefile->AddInstallGenerator(
+ cm::make_unique<cmInstallExportGenerator>(
+ &exportSet, ica.GetDestination(), ica.GetPermissions(),
+ ica.GetConfigurations(), ica.GetComponent(), message,
+ ica.GetExcludeFromAll(), fname, name_space, exportOld, false,
+ helper.Makefile->GetBacktrace()));
+
+ return true;
+}
+
+bool Helper::MakeFilesFullPath(const char* modeName,
+ const std::vector<std::string>& relFiles,
+ std::vector<std::string>& absFiles)
+{
+ for (std::string const& relFile : relFiles) {
+ std::string file = relFile;
+ std::string::size_type gpos = cmGeneratorExpression::Find(file);
+ if (gpos != 0 && !cmSystemTools::FileIsFullPath(file)) {
+ file =
+ cmStrCat(this->Makefile->GetCurrentSourceDirectory(), '/', relFile);
+ }
+
+ // Make sure the file is not a directory.
+ if (gpos == std::string::npos && cmSystemTools::FileIsDirectory(file)) {
+ this->SetError(
+ cmStrCat(modeName, " given directory \"", relFile, "\" to install."));
+ return false;
+ }
+ // Store the file for installation.
+ absFiles.push_back(std::move(file));
+ }
+ return true;
+}
+
+bool Helper::CheckCMP0006(bool& failure) const
+{
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0006)) {
+ case cmPolicies::WARN:
+ this->Makefile->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0006));
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior is to allow compatibility
+ return true;
+ case cmPolicies::NEW:
+ // NEW behavior is to disallow compatibility
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ failure = true;
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0006));
+ break;
+ }
+ return false;
+}
+
+std::string Helper::GetDestination(const cmInstallCommandArguments* args,
+ const std::string& varName,
+ const std::string& guess) const
+{
+ if (args && !args->GetDestination().empty()) {
+ return args->GetDestination();
+ }
+ std::string val = this->Makefile->GetSafeDefinition(varName);
+ if (!val.empty()) {
+ return val;
+ }
+ return guess;
+}
+
+std::string Helper::GetRuntimeDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_BINDIR", "bin");
+}
+
+std::string Helper::GetSbinDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_SBINDIR", "sbin");
+}
+
+std::string Helper::GetArchiveDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_LIBDIR", "lib");
+}
+
+std::string Helper::GetLibraryDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_LIBDIR", "lib");
+}
+
+std::string Helper::GetIncludeDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_INCLUDEDIR", "include");
+}
+
+std::string Helper::GetSysconfDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_SYSCONFDIR", "etc");
+}
+
+std::string Helper::GetSharedStateDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_SHAREDSTATEDIR", "com");
+}
+
+std::string Helper::GetLocalStateDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_LOCALSTATEDIR", "var");
+}
+
+std::string Helper::GetRunStateDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_RUNSTATEDIR",
+ this->GetLocalStateDestination(nullptr) +
+ "/run");
+}
+
+std::string Helper::GetDataRootDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_DATAROOTDIR", "share");
+}
+
+std::string Helper::GetDataDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_DATADIR",
+ this->GetDataRootDestination(nullptr));
+}
+
+std::string Helper::GetInfoDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_INFODIR",
+ this->GetDataRootDestination(nullptr) + "/info");
+}
+
+std::string Helper::GetLocaleDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_LOCALEDIR",
+ this->GetDataRootDestination(nullptr) +
+ "/locale");
+}
+
+std::string Helper::GetManDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_MANDIR",
+ this->GetDataRootDestination(nullptr) + "/man");
+}
+
+std::string Helper::GetDocDestination(
+ const cmInstallCommandArguments* args) const
+{
+ return this->GetDestination(args, "CMAKE_INSTALL_DOCDIR",
+ this->GetDataRootDestination(nullptr) + "/doc");
+}
+
+std::string Helper::GetDestinationForType(
+ const cmInstallCommandArguments* args, const std::string& type) const
+{
+ if (args && !args->GetDestination().empty()) {
+ return args->GetDestination();
+ }
+ if (type == "BIN") {
+ return this->GetRuntimeDestination(nullptr);
+ }
+ if (type == "SBIN") {
+ return this->GetSbinDestination(nullptr);
+ }
+ if (type == "SYSCONF") {
+ return this->GetSysconfDestination(nullptr);
+ }
+ if (type == "SHAREDSTATE") {
+ return this->GetSharedStateDestination(nullptr);
+ }
+ if (type == "LOCALSTATE") {
+ return this->GetLocalStateDestination(nullptr);
+ }
+ if (type == "RUNSTATE") {
+ return this->GetRunStateDestination(nullptr);
+ }
+ if (type == "LIB") {
+ return this->GetLibraryDestination(nullptr);
+ }
+ if (type == "INCLUDE") {
+ return this->GetIncludeDestination(nullptr);
+ }
+ if (type == "DATA") {
+ return this->GetDataDestination(nullptr);
+ }
+ if (type == "INFO") {
+ return this->GetInfoDestination(nullptr);
+ }
+ if (type == "LOCALE") {
+ return this->GetLocaleDestination(nullptr);
+ }
+ if (type == "MAN") {
+ return this->GetManDestination(nullptr);
+ }
+ if (type == "DOC") {
+ return this->GetDocDestination(nullptr);
+ }
+ return "";
+}
+
+} // namespace
+
+bool cmInstallCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // Allow calling with no arguments so that arguments may be built up
+ // using a variable that may be left empty.
+ if (args.empty()) {
+ return true;
+ }
+
+ // Enable the install target.
+ status.GetMakefile().GetGlobalGenerator()->EnableInstallTarget();
+
+ static cmSubcommandTable const subcommand{
+ { "SCRIPT"_s, HandleScriptMode },
+ { "CODE"_s, HandleScriptMode },
+ { "TARGETS"_s, HandleTargetsMode },
+ { "FILES"_s, HandleFilesMode },
+ { "PROGRAMS"_s, HandleFilesMode },
+ { "DIRECTORY"_s, HandleDirectoryMode },
+ { "EXPORT"_s, HandleExportMode },
+ { "EXPORT_ANDROID_MK"_s, HandleExportAndroidMKMode },
+ };
+
+ return subcommand(args[0], args, status);
+}
diff --git a/Source/cmInstallCommand.h b/Source/cmInstallCommand.h
new file mode 100644
index 0000000..f0ba44e
--- /dev/null
+++ b/Source/cmInstallCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmInstallCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx
new file mode 100644
index 0000000..cc3df2a
--- /dev/null
+++ b/Source/cmInstallCommandArguments.cxx
@@ -0,0 +1,222 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallCommandArguments.h"
+
+#include <algorithm>
+#include <utility>
+
+#include <cmext/string_view>
+
+#include "cmRange.h"
+#include "cmSystemTools.h"
+
+// Table of valid permissions.
+const char* cmInstallCommandArguments::PermissionsTable[] = {
+ "OWNER_READ", "OWNER_WRITE", "OWNER_EXECUTE", "GROUP_READ",
+ "GROUP_WRITE", "GROUP_EXECUTE", "WORLD_READ", "WORLD_WRITE",
+ "WORLD_EXECUTE", "SETUID", "SETGID", nullptr
+};
+
+const std::string cmInstallCommandArguments::EmptyString;
+
+cmInstallCommandArguments::cmInstallCommandArguments(
+ std::string defaultComponent)
+ : DefaultComponentName(std::move(defaultComponent))
+{
+ this->Bind("DESTINATION"_s, this->Destination);
+ this->Bind("COMPONENT"_s, this->Component);
+ this->Bind("NAMELINK_COMPONENT"_s, this->NamelinkComponent);
+ this->Bind("EXCLUDE_FROM_ALL"_s, this->ExcludeFromAll);
+ this->Bind("RENAME"_s, this->Rename);
+ this->Bind("PERMISSIONS"_s, this->Permissions);
+ this->Bind("CONFIGURATIONS"_s, this->Configurations);
+ this->Bind("OPTIONAL"_s, this->Optional);
+ this->Bind("NAMELINK_ONLY"_s, this->NamelinkOnly);
+ this->Bind("NAMELINK_SKIP"_s, this->NamelinkSkip);
+ this->Bind("TYPE"_s, this->Type);
+}
+
+const std::string& cmInstallCommandArguments::GetDestination() const
+{
+ if (!this->DestinationString.empty()) {
+ return this->DestinationString;
+ }
+ if (this->GenericArguments != nullptr) {
+ return this->GenericArguments->GetDestination();
+ }
+ return EmptyString;
+}
+
+const std::string& cmInstallCommandArguments::GetComponent() const
+{
+ if (!this->Component.empty()) {
+ return this->Component;
+ }
+ if (this->GenericArguments != nullptr) {
+ return this->GenericArguments->GetComponent();
+ }
+ if (!this->DefaultComponentName.empty()) {
+ return this->DefaultComponentName;
+ }
+ static std::string unspecifiedComponent = "Unspecified";
+ return unspecifiedComponent;
+}
+
+const std::string& cmInstallCommandArguments::GetNamelinkComponent() const
+{
+ if (!this->NamelinkComponent.empty()) {
+ return this->NamelinkComponent;
+ }
+ return this->GetComponent();
+}
+
+const std::string& cmInstallCommandArguments::GetRename() const
+{
+ if (!this->Rename.empty()) {
+ return this->Rename;
+ }
+ if (this->GenericArguments != nullptr) {
+ return this->GenericArguments->GetRename();
+ }
+ return EmptyString;
+}
+
+const std::string& cmInstallCommandArguments::GetPermissions() const
+{
+ if (!this->PermissionsString.empty()) {
+ return this->PermissionsString;
+ }
+ if (this->GenericArguments != nullptr) {
+ return this->GenericArguments->GetPermissions();
+ }
+ return EmptyString;
+}
+
+bool cmInstallCommandArguments::GetOptional() const
+{
+ if (this->Optional) {
+ return true;
+ }
+ if (this->GenericArguments != nullptr) {
+ return this->GenericArguments->GetOptional();
+ }
+ return false;
+}
+
+bool cmInstallCommandArguments::GetExcludeFromAll() const
+{
+ if (this->ExcludeFromAll) {
+ return true;
+ }
+ if (this->GenericArguments != nullptr) {
+ return this->GenericArguments->GetExcludeFromAll();
+ }
+ return false;
+}
+
+bool cmInstallCommandArguments::GetNamelinkOnly() const
+{
+ if (this->NamelinkOnly) {
+ return true;
+ }
+ if (this->GenericArguments != nullptr) {
+ return this->GenericArguments->GetNamelinkOnly();
+ }
+ return false;
+}
+
+bool cmInstallCommandArguments::GetNamelinkSkip() const
+{
+ if (this->NamelinkSkip) {
+ return true;
+ }
+ if (this->GenericArguments != nullptr) {
+ return this->GenericArguments->GetNamelinkSkip();
+ }
+ return false;
+}
+
+bool cmInstallCommandArguments::HasNamelinkComponent() const
+{
+ if (!this->NamelinkComponent.empty()) {
+ return true;
+ }
+ if (this->GenericArguments != nullptr) {
+ return this->GenericArguments->HasNamelinkComponent();
+ }
+ return false;
+}
+
+const std::string& cmInstallCommandArguments::GetType() const
+{
+ return this->Type;
+}
+
+const std::vector<std::string>& cmInstallCommandArguments::GetConfigurations()
+ const
+{
+ if (!this->Configurations.empty()) {
+ return this->Configurations;
+ }
+ if (this->GenericArguments != nullptr) {
+ return this->GenericArguments->GetConfigurations();
+ }
+ return this->Configurations;
+}
+
+bool cmInstallCommandArguments::Finalize()
+{
+ if (!this->CheckPermissions()) {
+ return false;
+ }
+ this->DestinationString = this->Destination;
+ cmSystemTools::ConvertToUnixSlashes(this->DestinationString);
+ return true;
+}
+
+bool cmInstallCommandArguments::CheckPermissions()
+{
+ this->PermissionsString.clear();
+ return std::all_of(this->Permissions.begin(), this->Permissions.end(),
+ [this](std::string const& perm) -> bool {
+ return cmInstallCommandArguments::CheckPermissions(
+ perm, this->PermissionsString);
+ });
+}
+
+bool cmInstallCommandArguments::CheckPermissions(
+ const std::string& onePermission, std::string& permissions)
+{
+ // Check the permission against the table.
+ for (const char** valid = cmInstallCommandArguments::PermissionsTable;
+ *valid; ++valid) {
+ if (onePermission == *valid) {
+ // This is a valid permission.
+ permissions += " ";
+ permissions += onePermission;
+ return true;
+ }
+ }
+ // This is not a valid permission.
+ return false;
+}
+
+cmInstallCommandIncludesArgument::cmInstallCommandIncludesArgument() = default;
+
+const std::vector<std::string>&
+cmInstallCommandIncludesArgument::GetIncludeDirs() const
+{
+ return this->IncludeDirs;
+}
+
+void cmInstallCommandIncludesArgument::Parse(
+ const std::vector<std::string>* args, std::vector<std::string>*)
+{
+ if (args->empty()) {
+ return;
+ }
+ for (std::string dir : cmMakeRange(*args).advance(1)) {
+ cmSystemTools::ConvertToUnixSlashes(dir);
+ this->IncludeDirs.push_back(std::move(dir));
+ }
+}
diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h
new file mode 100644
index 0000000..f318a1a
--- /dev/null
+++ b/Source/cmInstallCommandArguments.h
@@ -0,0 +1,73 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmArgumentParser.h"
+
+class cmInstallCommandArguments : public cmArgumentParser<void>
+{
+public:
+ cmInstallCommandArguments(std::string defaultComponent);
+ void SetGenericArguments(cmInstallCommandArguments* args)
+ {
+ this->GenericArguments = args;
+ }
+
+ // Compute destination path.and check permissions
+ bool Finalize();
+
+ const std::string& GetDestination() const;
+ const std::string& GetComponent() const;
+ const std::string& GetNamelinkComponent() const;
+ bool GetExcludeFromAll() const;
+ const std::string& GetRename() const;
+ const std::string& GetPermissions() const;
+ const std::vector<std::string>& GetConfigurations() const;
+ bool GetOptional() const;
+ bool GetNamelinkOnly() const;
+ bool GetNamelinkSkip() const;
+ bool HasNamelinkComponent() const;
+ const std::string& GetType() const;
+
+ static bool CheckPermissions(const std::string& onePerm, std::string& perm);
+
+private:
+ std::string Destination;
+ std::string Component;
+ std::string NamelinkComponent;
+ bool ExcludeFromAll = false;
+ std::string Rename;
+ std::vector<std::string> Permissions;
+ std::vector<std::string> Configurations;
+ bool Optional = false;
+ bool NamelinkOnly = false;
+ bool NamelinkSkip = false;
+ std::string Type;
+
+ std::string DestinationString;
+ std::string PermissionsString;
+
+ cmInstallCommandArguments* GenericArguments = nullptr;
+ static const char* PermissionsTable[];
+ static const std::string EmptyString;
+ std::string DefaultComponentName;
+ bool CheckPermissions();
+};
+
+class cmInstallCommandIncludesArgument
+{
+public:
+ cmInstallCommandIncludesArgument();
+ void Parse(const std::vector<std::string>* args,
+ std::vector<std::string>* unconsumedArgs);
+
+ const std::vector<std::string>& GetIncludeDirs() const;
+
+private:
+ std::vector<std::string> IncludeDirs;
+};
diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx
new file mode 100644
index 0000000..4eb5f69
--- /dev/null
+++ b/Source/cmInstallDirectoryGenerator.cxx
@@ -0,0 +1,113 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallDirectoryGenerator.h"
+
+#include <utility>
+
+#include "cmGeneratorExpression.h"
+#include "cmInstallType.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmInstallDirectoryGenerator::cmInstallDirectoryGenerator(
+ std::vector<std::string> const& dirs, std::string const& dest,
+ std::string file_permissions, std::string dir_permissions,
+ std::vector<std::string> const& configurations, std::string const& component,
+ MessageLevel message, bool exclude_from_all, std::string literal_args,
+ bool optional, cmListFileBacktrace backtrace)
+ : cmInstallGenerator(dest, configurations, component, message,
+ exclude_from_all, std::move(backtrace))
+ , LocalGenerator(nullptr)
+ , Directories(dirs)
+ , FilePermissions(std::move(file_permissions))
+ , DirPermissions(std::move(dir_permissions))
+ , LiteralArguments(std::move(literal_args))
+ , Optional(optional)
+{
+ // We need per-config actions if destination have generator expressions.
+ if (cmGeneratorExpression::Find(this->Destination) != std::string::npos) {
+ this->ActionsPerConfig = true;
+ }
+
+ // We need per-config actions if any directories have generator expressions.
+ if (!this->ActionsPerConfig) {
+ for (std::string const& dir : dirs) {
+ if (cmGeneratorExpression::Find(dir) != std::string::npos) {
+ this->ActionsPerConfig = true;
+ break;
+ }
+ }
+ }
+}
+
+cmInstallDirectoryGenerator::~cmInstallDirectoryGenerator() = default;
+
+bool cmInstallDirectoryGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LocalGenerator = lg;
+ return true;
+}
+
+std::vector<std::string> cmInstallDirectoryGenerator::GetDirectories(
+ std::string const& config) const
+{
+ std::vector<std::string> directories;
+ if (this->ActionsPerConfig) {
+ for (std::string const& f : this->Directories) {
+ cmExpandList(
+ cmGeneratorExpression::Evaluate(f, this->LocalGenerator, config),
+ directories);
+ }
+ } else {
+ directories = this->Directories;
+ }
+ return directories;
+}
+
+void cmInstallDirectoryGenerator::GenerateScriptActions(std::ostream& os,
+ Indent indent)
+{
+ if (this->ActionsPerConfig) {
+ this->cmInstallGenerator::GenerateScriptActions(os, indent);
+ } else {
+ this->AddDirectoryInstallRule(os, "", indent, this->Directories);
+ }
+}
+
+void cmInstallDirectoryGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent indent)
+{
+ std::vector<std::string> dirs = this->GetDirectories(config);
+
+ // Make sure all dirs have absolute paths.
+ cmMakefile const& mf = *this->LocalGenerator->GetMakefile();
+ for (std::string& d : dirs) {
+ if (!cmSystemTools::FileIsFullPath(d)) {
+ d = cmStrCat(mf.GetCurrentSourceDirectory(), "/", d);
+ }
+ }
+
+ this->AddDirectoryInstallRule(os, config, indent, dirs);
+}
+
+void cmInstallDirectoryGenerator::AddDirectoryInstallRule(
+ std::ostream& os, const std::string& config, Indent indent,
+ std::vector<std::string> const& dirs)
+{
+ // Write code to install the directories.
+ const char* no_rename = nullptr;
+ this->AddInstallRule(os, this->GetDestination(config),
+ cmInstallType_DIRECTORY, dirs, this->Optional,
+ this->FilePermissions.c_str(),
+ this->DirPermissions.c_str(), no_rename,
+ this->LiteralArguments.c_str(), indent);
+}
+
+std::string cmInstallDirectoryGenerator::GetDestination(
+ std::string const& config) const
+{
+ return cmGeneratorExpression::Evaluate(this->Destination,
+ this->LocalGenerator, config);
+}
diff --git a/Source/cmInstallDirectoryGenerator.h b/Source/cmInstallDirectoryGenerator.h
new file mode 100644
index 0000000..0f91a59
--- /dev/null
+++ b/Source/cmInstallDirectoryGenerator.h
@@ -0,0 +1,51 @@
+/* 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 <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
+#include "cmScriptGenerator.h"
+
+class cmLocalGenerator;
+
+/** \class cmInstallDirectoryGenerator
+ * \brief Generate directory installation rules.
+ */
+class cmInstallDirectoryGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallDirectoryGenerator(
+ std::vector<std::string> const& dirs, std::string const& dest,
+ std::string file_permissions, std::string dir_permissions,
+ std::vector<std::string> const& configurations,
+ std::string const& component, MessageLevel message, bool exclude_from_all,
+ std::string literal_args, bool optional, cmListFileBacktrace backtrace);
+ ~cmInstallDirectoryGenerator() override;
+
+ bool Compute(cmLocalGenerator* lg) override;
+
+ std::string GetDestination(std::string const& config) const;
+ std::vector<std::string> GetDirectories(std::string const& config) const;
+
+ bool GetOptional() const { return this->Optional; }
+
+protected:
+ void GenerateScriptActions(std::ostream& os, Indent indent) override;
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent indent) override;
+ void AddDirectoryInstallRule(std::ostream& os, const std::string& config,
+ Indent indent,
+ std::vector<std::string> const& dirs);
+ cmLocalGenerator* LocalGenerator;
+ std::vector<std::string> const Directories;
+ std::string const FilePermissions;
+ std::string const DirPermissions;
+ std::string const LiteralArguments;
+ bool const Optional;
+};
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx
new file mode 100644
index 0000000..fdc3f8c
--- /dev/null
+++ b/Source/cmInstallExportGenerator.cxx
@@ -0,0 +1,222 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallExportGenerator.h"
+
+#include <algorithm>
+#include <map>
+#include <sstream>
+#include <utility>
+
+#include <cm/memory>
+
+#ifndef CMAKE_BOOTSTRAP
+# include "cmExportInstallAndroidMKGenerator.h"
+#endif
+#include "cmExportInstallFileGenerator.h"
+#include "cmExportSet.h"
+#include "cmInstallType.h"
+#include "cmLocalGenerator.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmInstallExportGenerator::cmInstallExportGenerator(
+ cmExportSet* exportSet, std::string const& destination,
+ std::string file_permissions, std::vector<std::string> const& configurations,
+ std::string const& component, MessageLevel message, bool exclude_from_all,
+ std::string filename, std::string name_space, bool exportOld, bool android,
+ cmListFileBacktrace backtrace)
+ : cmInstallGenerator(destination, configurations, component, message,
+ exclude_from_all, std::move(backtrace))
+ , ExportSet(exportSet)
+ , FilePermissions(std::move(file_permissions))
+ , FileName(std::move(filename))
+ , Namespace(std::move(name_space))
+ , ExportOld(exportOld)
+ , LocalGenerator(nullptr)
+{
+ if (android) {
+#ifndef CMAKE_BOOTSTRAP
+ this->EFGen = cm::make_unique<cmExportInstallAndroidMKGenerator>(this);
+#endif
+ } else {
+ this->EFGen = cm::make_unique<cmExportInstallFileGenerator>(this);
+ }
+ exportSet->AddInstallation(this);
+}
+
+cmInstallExportGenerator::~cmInstallExportGenerator() = default;
+
+bool cmInstallExportGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LocalGenerator = lg;
+ this->ExportSet->Compute(lg);
+ return true;
+}
+
+void cmInstallExportGenerator::ComputeTempDir()
+{
+ // Choose a temporary directory in which to generate the import
+ // files to be installed.
+ this->TempDir = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/Export");
+ if (this->Destination.empty()) {
+ return;
+ }
+ this->TempDir += "/";
+
+ // Enforce a maximum length.
+ bool useMD5 = false;
+#if defined(_WIN32) || defined(__CYGWIN__)
+ std::string::size_type const max_total_len = 250;
+#else
+ std::string::size_type const max_total_len = 1000;
+#endif
+ // Will generate files of the form "<temp-dir>/<base>-<config>.<ext>".
+ std::string::size_type const len = this->TempDir.size() + 1 +
+ this->FileName.size() + 1 + this->GetMaxConfigLength();
+ if (len < max_total_len) {
+ // Keep the total path length below the limit.
+ std::string::size_type const max_len = max_total_len - len;
+ if (this->Destination.size() > max_len) {
+ useMD5 = true;
+ }
+ } else {
+ useMD5 = true;
+ }
+ if (useMD5) {
+ // Replace the destination path with a hash to keep it short.
+ this->TempDir += cmSystemTools::ComputeStringMD5(this->Destination);
+ } else {
+ std::string dest = this->Destination;
+ // Avoid unix full paths.
+ if (dest[0] == '/') {
+ dest[0] = '_';
+ }
+ // Avoid windows full paths by removing colons.
+ std::replace(dest.begin(), dest.end(), ':', '_');
+ // Avoid relative paths that go up the tree.
+ cmSystemTools::ReplaceString(dest, "../", "__/");
+ // Avoid spaces.
+ std::replace(dest.begin(), dest.end(), ' ', '_');
+ this->TempDir += dest;
+ }
+}
+
+size_t cmInstallExportGenerator::GetMaxConfigLength() const
+{
+ // Always use at least 8 for "noconfig".
+ size_t len = 8;
+ if (this->ConfigurationTypes->empty()) {
+ if (this->ConfigurationName.size() > 8) {
+ len = this->ConfigurationName.size();
+ }
+ } else {
+ for (std::string const& c : *this->ConfigurationTypes) {
+ if (c.size() > len) {
+ len = c.size();
+ }
+ }
+ }
+ return len;
+}
+
+void cmInstallExportGenerator::GenerateScript(std::ostream& os)
+{
+ // Skip empty sets.
+ if (this->ExportSet->GetTargetExports().empty()) {
+ std::ostringstream e;
+ e << "INSTALL(EXPORT) given unknown export \""
+ << this->ExportSet->GetName() << "\"";
+ cmSystemTools::Error(e.str());
+ return;
+ }
+
+ // Create the temporary directory in which to store the files.
+ this->ComputeTempDir();
+ cmSystemTools::MakeDirectory(this->TempDir);
+
+ // Construct a temporary location for the file.
+ this->MainImportFile = cmStrCat(this->TempDir, '/', this->FileName);
+
+ // Generate the import file for this export set.
+ this->EFGen->SetExportFile(this->MainImportFile.c_str());
+ this->EFGen->SetNamespace(this->Namespace);
+ this->EFGen->SetExportOld(this->ExportOld);
+ if (this->ConfigurationTypes->empty()) {
+ if (!this->ConfigurationName.empty()) {
+ this->EFGen->AddConfiguration(this->ConfigurationName);
+ } else {
+ this->EFGen->AddConfiguration("");
+ }
+ } else {
+ for (std::string const& c : *this->ConfigurationTypes) {
+ this->EFGen->AddConfiguration(c);
+ }
+ }
+ this->EFGen->GenerateImportFile();
+
+ // Perform the main install script generation.
+ this->cmInstallGenerator::GenerateScript(os);
+}
+
+void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
+ Indent indent)
+{
+ // Create the main install rules first.
+ this->cmInstallGenerator::GenerateScriptConfigs(os, indent);
+
+ // Now create a configuration-specific install rule for the import
+ // file of each configuration.
+ std::vector<std::string> files;
+ for (auto const& i : this->EFGen->GetConfigImportFiles()) {
+ files.push_back(i.second);
+ std::string config_test = this->CreateConfigTest(i.first);
+ os << indent << "if(" << config_test << ")\n";
+ this->AddInstallRule(os, this->Destination, cmInstallType_FILES, files,
+ false, this->FilePermissions.c_str(), nullptr,
+ nullptr, nullptr, indent.Next());
+ os << indent << "endif()\n";
+ files.clear();
+ }
+}
+
+void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os,
+ Indent indent)
+{
+ // Remove old per-configuration export files if the main changes.
+ std::string installedDir =
+ cmStrCat("$ENV{DESTDIR}",
+ this->ConvertToAbsoluteDestination(this->Destination), '/');
+ std::string installedFile = cmStrCat(installedDir, this->FileName);
+ os << indent << "if(EXISTS \"" << installedFile << "\")\n";
+ Indent indentN = indent.Next();
+ Indent indentNN = indentN.Next();
+ Indent indentNNN = indentNN.Next();
+ /* clang-format off */
+ os << indentN << "file(DIFFERENT EXPORT_FILE_CHANGED FILES\n"
+ << indentN << " \"" << installedFile << "\"\n"
+ << indentN << " \"" << this->MainImportFile << "\")\n";
+ os << indentN << "if(EXPORT_FILE_CHANGED)\n";
+ os << indentNN << "file(GLOB OLD_CONFIG_FILES \"" << installedDir
+ << this->EFGen->GetConfigImportFileGlob() << "\")\n";
+ os << indentNN << "if(OLD_CONFIG_FILES)\n";
+ os << indentNNN << R"(message(STATUS "Old export file \")" << installedFile
+ << "\\\" will be replaced. Removing files [${OLD_CONFIG_FILES}].\")\n";
+ os << indentNNN << "file(REMOVE ${OLD_CONFIG_FILES})\n";
+ os << indentNN << "endif()\n";
+ os << indentN << "endif()\n";
+ os << indent << "endif()\n";
+ /* clang-format on */
+
+ // Install the main export file.
+ std::vector<std::string> files;
+ files.push_back(this->MainImportFile);
+ this->AddInstallRule(os, this->Destination, cmInstallType_FILES, files,
+ false, this->FilePermissions.c_str(), nullptr, nullptr,
+ nullptr, indent);
+}
+
+std::string cmInstallExportGenerator::GetDestinationFile() const
+{
+ return this->Destination + '/' + this->FileName;
+}
diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h
new file mode 100644
index 0000000..efeae86
--- /dev/null
+++ b/Source/cmInstallExportGenerator.h
@@ -0,0 +1,73 @@
+/* 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 <cstddef>
+#include <iosfwd>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
+#include "cmScriptGenerator.h"
+
+class cmExportInstallFileGenerator;
+class cmExportSet;
+class cmLocalGenerator;
+
+/** \class cmInstallExportGenerator
+ * \brief Generate rules for creating an export files.
+ */
+class cmInstallExportGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallExportGenerator(cmExportSet* exportSet, std::string const& dest,
+ std::string file_permissions,
+ const std::vector<std::string>& configurations,
+ std::string const& component, MessageLevel message,
+ bool exclude_from_all, std::string filename,
+ std::string name_space, bool exportOld,
+ bool android, cmListFileBacktrace backtrace);
+ cmInstallExportGenerator(const cmInstallExportGenerator&) = delete;
+ ~cmInstallExportGenerator() override;
+
+ cmInstallExportGenerator& operator=(const cmInstallExportGenerator&) =
+ delete;
+
+ cmExportSet* GetExportSet() { return this->ExportSet; }
+
+ bool Compute(cmLocalGenerator* lg) override;
+
+ cmLocalGenerator* GetLocalGenerator() const { return this->LocalGenerator; }
+
+ const std::string& GetNamespace() const { return this->Namespace; }
+
+ std::string const& GetMainImportFile() const { return this->MainImportFile; }
+
+ std::string const& GetDestination() const { return this->Destination; }
+ std::string GetDestinationFile() const;
+ std::string GetFileName() const { return this->FileName; }
+
+protected:
+ void GenerateScript(std::ostream& os) override;
+ void GenerateScriptConfigs(std::ostream& os, Indent indent) override;
+ void GenerateScriptActions(std::ostream& os, Indent indent) override;
+ void GenerateImportFile(cmExportSet const* exportSet);
+ void GenerateImportFile(const char* config, cmExportSet const* exportSet);
+ void ComputeTempDir();
+ size_t GetMaxConfigLength() const;
+
+ cmExportSet* const ExportSet;
+ std::string const FilePermissions;
+ std::string const FileName;
+ std::string const Namespace;
+ bool const ExportOld;
+ cmLocalGenerator* LocalGenerator;
+
+ std::string TempDir;
+ std::string MainImportFile;
+ std::unique_ptr<cmExportInstallFileGenerator> EFGen;
+};
diff --git a/Source/cmInstallFilesCommand.cxx b/Source/cmInstallFilesCommand.cxx
new file mode 100644
index 0000000..e65cb24
--- /dev/null
+++ b/Source/cmInstallFilesCommand.cxx
@@ -0,0 +1,160 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallFilesCommand.h"
+
+#include <cm/memory>
+
+#include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallFilesGenerator.h"
+#include "cmInstallGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+class cmListFileBacktrace;
+
+static std::string FindInstallSource(cmMakefile& makefile, const char* name);
+static void CreateInstallGenerator(cmMakefile& makefile,
+ std::string const& dest,
+ std::vector<std::string> const& files);
+static void FinalAction(cmMakefile& makefile, std::string const& dest,
+ std::vector<std::string> const& args);
+
+bool cmInstallFilesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ // Enable the install target.
+ mf.GetGlobalGenerator()->EnableInstallTarget();
+
+ std::string const& dest = args[0];
+
+ if ((args.size() > 1) && (args[1] == "FILES")) {
+ std::vector<std::string> files;
+ for (std::string const& arg : cmMakeRange(args).advance(2)) {
+ // Find the source location for each file listed.
+ files.push_back(FindInstallSource(mf, arg.c_str()));
+ }
+ CreateInstallGenerator(mf, dest, files);
+ } else {
+ std::vector<std::string> finalArgs(args.begin() + 1, args.end());
+ mf.AddGeneratorAction(
+ [dest, finalArgs](cmLocalGenerator& lg, const cmListFileBacktrace&) {
+ FinalAction(*lg.GetMakefile(), dest, finalArgs);
+ });
+ }
+
+ mf.GetGlobalGenerator()->AddInstallComponent(
+ mf.GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"));
+
+ return true;
+}
+
+static void FinalAction(cmMakefile& makefile, std::string const& dest,
+ std::vector<std::string> const& args)
+{
+ std::string testf;
+ std::string const& ext = args[0];
+ std::vector<std::string> installFiles;
+
+ // two different options
+ if (args.size() > 1) {
+ // now put the files into the list
+ auto s = args.begin();
+ ++s;
+ // for each argument, get the files
+ for (; s != args.end(); ++s) {
+ // replace any variables
+ std::string const& temps = *s;
+ if (!cmSystemTools::GetFilenamePath(temps).empty()) {
+ testf = cmSystemTools::GetFilenamePath(temps) + "/" +
+ cmSystemTools::GetFilenameWithoutLastExtension(temps) + ext;
+ } else {
+ testf = cmSystemTools::GetFilenameWithoutLastExtension(temps) + ext;
+ }
+
+ // add to the result
+ installFiles.push_back(FindInstallSource(makefile, testf.c_str()));
+ }
+ } else // reg exp list
+ {
+ std::vector<std::string> files;
+ std::string const& regex = args[0];
+ cmSystemTools::Glob(makefile.GetCurrentSourceDirectory(), regex, files);
+
+ auto s = files.begin();
+ // for each argument, get the files
+ for (; s != files.end(); ++s) {
+ installFiles.push_back(FindInstallSource(makefile, s->c_str()));
+ }
+ }
+
+ CreateInstallGenerator(makefile, dest, installFiles);
+}
+
+static void CreateInstallGenerator(cmMakefile& makefile,
+ std::string const& dest,
+ std::vector<std::string> const& files)
+{
+ // Construct the destination. This command always installs under
+ // the prefix. We skip the leading slash given by the user.
+ std::string destination = dest.substr(1);
+ cmSystemTools::ConvertToUnixSlashes(destination);
+ if (destination.empty()) {
+ destination = ".";
+ }
+
+ // Use a file install generator.
+ const std::string no_permissions;
+ const std::string no_rename;
+ bool no_exclude_from_all = false;
+ std::string no_component =
+ makefile.GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME");
+ std::vector<std::string> no_configurations;
+ cmInstallGenerator::MessageLevel message =
+ cmInstallGenerator::SelectMessageLevel(&makefile);
+ makefile.AddInstallGenerator(cm::make_unique<cmInstallFilesGenerator>(
+ files, destination, false, no_permissions, no_configurations, no_component,
+ message, no_exclude_from_all, no_rename, false, makefile.GetBacktrace()));
+}
+
+/**
+ * Find a file in the build or source tree for installation given a
+ * relative path from the CMakeLists.txt file. This will favor files
+ * present in the build tree. If a full path is given, it is just
+ * returned.
+ */
+static std::string FindInstallSource(cmMakefile& makefile, const char* name)
+{
+ if (cmSystemTools::FileIsFullPath(name) ||
+ cmGeneratorExpression::Find(name) == 0) {
+ // This is a full path.
+ return name;
+ }
+
+ // This is a relative path.
+ std::string tb = cmStrCat(makefile.GetCurrentBinaryDirectory(), '/', name);
+ std::string ts = cmStrCat(makefile.GetCurrentSourceDirectory(), '/', name);
+
+ if (cmSystemTools::FileExists(tb)) {
+ // The file exists in the binary tree. Use it.
+ return tb;
+ }
+ if (cmSystemTools::FileExists(ts)) {
+ // The file exists in the source tree. Use it.
+ return ts;
+ }
+ // The file doesn't exist. Assume it will be present in the
+ // binary tree when the install occurs.
+ return tb;
+}
diff --git a/Source/cmInstallFilesCommand.h b/Source/cmInstallFilesCommand.h
new file mode 100644
index 0000000..219bb97
--- /dev/null
+++ b/Source/cmInstallFilesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmInstallFilesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx
new file mode 100644
index 0000000..556c938
--- /dev/null
+++ b/Source/cmInstallFilesGenerator.cxx
@@ -0,0 +1,113 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallFilesGenerator.h"
+
+#include <utility>
+
+#include "cmGeneratorExpression.h"
+#include "cmInstallType.h"
+#include "cmStringAlgorithms.h"
+
+class cmLocalGenerator;
+
+cmInstallFilesGenerator::cmInstallFilesGenerator(
+ std::vector<std::string> const& files, std::string const& dest,
+ bool programs, std::string file_permissions,
+ std::vector<std::string> const& configurations, std::string const& component,
+ MessageLevel message, bool exclude_from_all, std::string rename,
+ bool optional, cmListFileBacktrace backtrace)
+ : cmInstallGenerator(dest, configurations, component, message,
+ exclude_from_all, std::move(backtrace))
+ , LocalGenerator(nullptr)
+ , Files(files)
+ , FilePermissions(std::move(file_permissions))
+ , Rename(std::move(rename))
+ , Programs(programs)
+ , Optional(optional)
+{
+ // We need per-config actions if the destination and rename have generator
+ // expressions.
+ if (cmGeneratorExpression::Find(this->Destination) != std::string::npos) {
+ this->ActionsPerConfig = true;
+ }
+ if (cmGeneratorExpression::Find(this->Rename) != std::string::npos) {
+ this->ActionsPerConfig = true;
+ }
+
+ // We need per-config actions if any directories have generator expressions.
+ if (!this->ActionsPerConfig) {
+ for (std::string const& file : files) {
+ if (cmGeneratorExpression::Find(file) != std::string::npos) {
+ this->ActionsPerConfig = true;
+ break;
+ }
+ }
+ }
+}
+
+cmInstallFilesGenerator::~cmInstallFilesGenerator() = default;
+
+bool cmInstallFilesGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LocalGenerator = lg;
+ return true;
+}
+
+std::string cmInstallFilesGenerator::GetDestination(
+ std::string const& config) const
+{
+ return cmGeneratorExpression::Evaluate(this->Destination,
+ this->LocalGenerator, config);
+}
+
+std::string cmInstallFilesGenerator::GetRename(std::string const& config) const
+{
+ return cmGeneratorExpression::Evaluate(this->Rename, this->LocalGenerator,
+ config);
+}
+
+std::vector<std::string> cmInstallFilesGenerator::GetFiles(
+ std::string const& config) const
+{
+ std::vector<std::string> files;
+ if (this->ActionsPerConfig) {
+ for (std::string const& f : this->Files) {
+ cmExpandList(
+ cmGeneratorExpression::Evaluate(f, this->LocalGenerator, config),
+ files);
+ }
+ } else {
+ files = this->Files;
+ }
+ return files;
+}
+
+void cmInstallFilesGenerator::AddFilesInstallRule(
+ std::ostream& os, std::string const& config, Indent indent,
+ std::vector<std::string> const& files)
+{
+ // Write code to install the files.
+ const char* no_dir_permissions = nullptr;
+ this->AddInstallRule(
+ os, this->GetDestination(config),
+ (this->Programs ? cmInstallType_PROGRAMS : cmInstallType_FILES), files,
+ this->Optional, this->FilePermissions.c_str(), no_dir_permissions,
+ this->GetRename(config).c_str(), nullptr, indent);
+}
+
+void cmInstallFilesGenerator::GenerateScriptActions(std::ostream& os,
+ Indent indent)
+{
+ if (this->ActionsPerConfig) {
+ this->cmInstallGenerator::GenerateScriptActions(os, indent);
+ } else {
+ this->AddFilesInstallRule(os, "", indent, this->Files);
+ }
+}
+
+void cmInstallFilesGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent indent)
+{
+ std::vector<std::string> files = this->GetFiles(config);
+ this->AddFilesInstallRule(os, config, indent, files);
+}
diff --git a/Source/cmInstallFilesGenerator.h b/Source/cmInstallFilesGenerator.h
new file mode 100644
index 0000000..af7f113
--- /dev/null
+++ b/Source/cmInstallFilesGenerator.h
@@ -0,0 +1,53 @@
+/* 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 <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
+#include "cmScriptGenerator.h"
+
+class cmLocalGenerator;
+
+/** \class cmInstallFilesGenerator
+ * \brief Generate file installation rules.
+ */
+class cmInstallFilesGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallFilesGenerator(std::vector<std::string> const& files,
+ std::string const& dest, bool programs,
+ std::string file_permissions,
+ std::vector<std::string> const& configurations,
+ std::string const& component, MessageLevel message,
+ bool exclude_from_all, std::string rename,
+ bool optional, cmListFileBacktrace backtrace);
+ ~cmInstallFilesGenerator() override;
+
+ bool Compute(cmLocalGenerator* lg) override;
+
+ std::string GetDestination(std::string const& config) const;
+ std::string GetRename(std::string const& config) const;
+ std::vector<std::string> GetFiles(std::string const& config) const;
+ bool GetOptional() const { return this->Optional; }
+
+protected:
+ void GenerateScriptActions(std::ostream& os, Indent indent) override;
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent indent) override;
+ void AddFilesInstallRule(std::ostream& os, std::string const& config,
+ Indent indent,
+ std::vector<std::string> const& files);
+
+ cmLocalGenerator* LocalGenerator;
+ std::vector<std::string> const Files;
+ std::string const FilePermissions;
+ std::string const Rename;
+ bool const Programs;
+ bool const Optional;
+};
diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
new file mode 100644
index 0000000..98e3766
--- /dev/null
+++ b/Source/cmInstallGenerator.cxx
@@ -0,0 +1,207 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallGenerator.h"
+
+#include <ostream>
+#include <utility>
+
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+cmInstallGenerator::cmInstallGenerator(
+ std::string destination, std::vector<std::string> const& configurations,
+ std::string component, MessageLevel message, bool exclude_from_all,
+ cmListFileBacktrace backtrace)
+ : cmScriptGenerator("CMAKE_INSTALL_CONFIG_NAME", configurations)
+ , Destination(std::move(destination))
+ , Component(std::move(component))
+ , Message(message)
+ , ExcludeFromAll(exclude_from_all)
+ , Backtrace(std::move(backtrace))
+{
+}
+
+cmInstallGenerator::~cmInstallGenerator() = default;
+
+bool cmInstallGenerator::HaveInstall()
+{
+ return true;
+}
+
+void cmInstallGenerator::CheckCMP0082(bool& haveSubdirectoryInstall,
+ bool& haveInstallAfterSubdirectory)
+{
+ if (haveSubdirectoryInstall) {
+ haveInstallAfterSubdirectory = true;
+ }
+}
+
+void cmInstallGenerator::AddInstallRule(
+ std::ostream& os, std::string const& dest, cmInstallType type,
+ std::vector<std::string> const& files, bool optional /* = false */,
+ const char* permissions_file /* = 0 */,
+ const char* permissions_dir /* = 0 */, const char* rename /* = 0 */,
+ const char* literal_args /* = 0 */, Indent indent)
+{
+ // Use the FILE command to install the file.
+ std::string stype;
+ switch (type) {
+ case cmInstallType_DIRECTORY:
+ stype = "DIRECTORY";
+ break;
+ case cmInstallType_PROGRAMS:
+ stype = "PROGRAM";
+ break;
+ case cmInstallType_EXECUTABLE:
+ stype = "EXECUTABLE";
+ break;
+ case cmInstallType_STATIC_LIBRARY:
+ stype = "STATIC_LIBRARY";
+ break;
+ case cmInstallType_SHARED_LIBRARY:
+ stype = "SHARED_LIBRARY";
+ break;
+ case cmInstallType_MODULE_LIBRARY:
+ stype = "MODULE";
+ break;
+ case cmInstallType_FILES:
+ stype = "FILE";
+ break;
+ }
+ os << indent;
+ if (cmSystemTools::FileIsFullPath(dest)) {
+ os << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n";
+ os << indent << " \"";
+ bool firstIteration = true;
+ for (std::string const& file : files) {
+ if (!firstIteration) {
+ os << ";";
+ }
+ os << dest << "/";
+ if (rename && *rename) {
+ os << rename;
+ } else {
+ os << cmSystemTools::GetFilenameName(file);
+ }
+ firstIteration = false;
+ }
+ os << "\")\n";
+ os << indent << "if(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n";
+ os << indent << indent << "message(WARNING \"ABSOLUTE path INSTALL "
+ << "DESTINATION : ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n";
+ os << indent << "endif()\n";
+
+ os << indent << "if(CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n";
+ os << indent << indent << "message(FATAL_ERROR \"ABSOLUTE path INSTALL "
+ << "DESTINATION forbidden (by caller): "
+ << "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n";
+ os << indent << "endif()\n";
+ }
+ std::string absDest = this->ConvertToAbsoluteDestination(dest);
+ os << "file(INSTALL DESTINATION \"" << absDest << "\" TYPE " << stype;
+ if (optional) {
+ os << " OPTIONAL";
+ }
+ switch (this->Message) {
+ case MessageDefault:
+ break;
+ case MessageAlways:
+ os << " MESSAGE_ALWAYS";
+ break;
+ case MessageLazy:
+ os << " MESSAGE_LAZY";
+ break;
+ case MessageNever:
+ os << " MESSAGE_NEVER";
+ break;
+ }
+ if (permissions_file && *permissions_file) {
+ os << " PERMISSIONS" << permissions_file;
+ }
+ if (permissions_dir && *permissions_dir) {
+ os << " DIR_PERMISSIONS" << permissions_dir;
+ }
+ if (rename && *rename) {
+ os << " RENAME \"" << rename << "\"";
+ }
+ os << " FILES";
+ if (files.size() == 1) {
+ os << " \"" << files[0] << "\"";
+ } else {
+ for (std::string const& f : files) {
+ os << "\n" << indent << " \"" << f << "\"";
+ }
+ os << "\n" << indent << " ";
+ if (!(literal_args && *literal_args)) {
+ os << " ";
+ }
+ }
+ if (literal_args && *literal_args) {
+ os << literal_args;
+ }
+ os << ")\n";
+}
+
+std::string cmInstallGenerator::CreateComponentTest(
+ const std::string& component, bool exclude_from_all)
+{
+ std::string result = R"("x${CMAKE_INSTALL_COMPONENT}x" STREQUAL "x)";
+ result += component;
+ result += "x\"";
+ if (!exclude_from_all) {
+ result += " OR NOT CMAKE_INSTALL_COMPONENT";
+ }
+ return result;
+}
+
+void cmInstallGenerator::GenerateScript(std::ostream& os)
+{
+ // Track indentation.
+ Indent indent;
+
+ // Begin this block of installation.
+ std::string component_test =
+ this->CreateComponentTest(this->Component, this->ExcludeFromAll);
+ os << indent << "if(" << component_test << ")\n";
+
+ // Generate the script possibly with per-configuration code.
+ this->GenerateScriptConfigs(os, indent.Next());
+
+ // End this block of installation.
+ os << indent << "endif()\n\n";
+}
+
+bool cmInstallGenerator::InstallsForConfig(const std::string& config)
+{
+ return this->GeneratesForConfig(config);
+}
+
+std::string cmInstallGenerator::ConvertToAbsoluteDestination(
+ std::string const& dest) const
+{
+ std::string result;
+ if (!dest.empty() && !cmSystemTools::FileIsFullPath(dest)) {
+ result = "${CMAKE_INSTALL_PREFIX}/";
+ }
+ result += dest;
+ return result;
+}
+
+cmInstallGenerator::MessageLevel cmInstallGenerator::SelectMessageLevel(
+ cmMakefile* mf, bool never)
+{
+ if (never) {
+ return MessageNever;
+ }
+ std::string m = mf->GetSafeDefinition("CMAKE_INSTALL_MESSAGE");
+ if (m == "ALWAYS") {
+ return MessageAlways;
+ }
+ if (m == "LAZY") {
+ return MessageLazy;
+ }
+ if (m == "NEVER") {
+ return MessageNever;
+ }
+ return MessageDefault;
+}
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
new file mode 100644
index 0000000..6cd9ff9
--- /dev/null
+++ b/Source/cmInstallGenerator.h
@@ -0,0 +1,83 @@
+/* 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 <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmInstallType.h"
+#include "cmListFileCache.h"
+#include "cmScriptGenerator.h"
+
+class cmLocalGenerator;
+class cmMakefile;
+
+/** \class cmInstallGenerator
+ * \brief Support class for generating install scripts.
+ *
+ */
+class cmInstallGenerator : public cmScriptGenerator
+{
+public:
+ enum MessageLevel
+ {
+ MessageDefault,
+ MessageAlways,
+ MessageLazy,
+ MessageNever
+ };
+
+ cmInstallGenerator(std::string destination,
+ std::vector<std::string> const& configurations,
+ std::string component, MessageLevel message,
+ bool exclude_from_all, cmListFileBacktrace backtrace);
+ ~cmInstallGenerator() override;
+
+ cmInstallGenerator(cmInstallGenerator const&) = delete;
+ cmInstallGenerator& operator=(cmInstallGenerator const&) = delete;
+
+ virtual bool HaveInstall();
+ virtual void CheckCMP0082(bool& haveSubdirectoryInstall,
+ bool& haveInstallAfterSubdirectory);
+
+ void AddInstallRule(
+ std::ostream& os, std::string const& dest, cmInstallType type,
+ std::vector<std::string> const& files, bool optional = false,
+ const char* permissions_file = nullptr,
+ const char* permissions_dir = nullptr, const char* rename = nullptr,
+ const char* literal_args = nullptr, Indent indent = Indent());
+
+ /** Get the install destination as it should appear in the
+ installation script. */
+ std::string ConvertToAbsoluteDestination(std::string const& dest) const;
+
+ /** Test if this generator installs something for a given configuration. */
+ bool InstallsForConfig(const std::string& config);
+
+ /** Select message level from CMAKE_INSTALL_MESSAGE or 'never'. */
+ static MessageLevel SelectMessageLevel(cmMakefile* mf, bool never = false);
+
+ virtual bool Compute(cmLocalGenerator*) { return true; }
+
+ std::string const& GetComponent() const { return this->Component; }
+
+ bool GetExcludeFromAll() const { return this->ExcludeFromAll; }
+
+ cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; }
+
+protected:
+ void GenerateScript(std::ostream& os) override;
+
+ std::string CreateComponentTest(const std::string& component,
+ bool exclude_from_all);
+
+ // Information shared by most generator types.
+ std::string const Destination;
+ std::string const Component;
+ MessageLevel const Message;
+ bool const ExcludeFromAll;
+ cmListFileBacktrace const Backtrace;
+};
diff --git a/Source/cmInstallProgramsCommand.cxx b/Source/cmInstallProgramsCommand.cxx
new file mode 100644
index 0000000..65b8d89
--- /dev/null
+++ b/Source/cmInstallProgramsCommand.cxx
@@ -0,0 +1,134 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallProgramsCommand.h"
+
+#include <cm/memory>
+
+#include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallFilesGenerator.h"
+#include "cmInstallGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+class cmListFileBacktrace;
+
+static void FinalAction(cmMakefile& makefile, std::string const& dest,
+ std::vector<std::string> const& args);
+static std::string FindInstallSource(cmMakefile& makefile, const char* name);
+
+bool cmInstallProgramsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ // Enable the install target.
+ mf.GetGlobalGenerator()->EnableInstallTarget();
+
+ mf.GetGlobalGenerator()->AddInstallComponent(
+ mf.GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"));
+
+ std::string const& dest = args[0];
+ std::vector<std::string> const finalArgs(args.begin() + 1, args.end());
+ mf.AddGeneratorAction(
+ [dest, finalArgs](cmLocalGenerator& lg, const cmListFileBacktrace&) {
+ FinalAction(*lg.GetMakefile(), dest, finalArgs);
+ });
+ return true;
+}
+
+static void FinalAction(cmMakefile& makefile, std::string const& dest,
+ std::vector<std::string> const& args)
+{
+ bool files_mode = false;
+ if (!args.empty() && args[0] == "FILES") {
+ files_mode = true;
+ }
+
+ std::vector<std::string> files;
+
+ // two different options
+ if (args.size() > 1 || files_mode) {
+ // for each argument, get the programs
+ auto s = args.begin();
+ if (files_mode) {
+ // Skip the FILES argument in files mode.
+ ++s;
+ }
+ for (; s != args.end(); ++s) {
+ // add to the result
+ files.push_back(FindInstallSource(makefile, s->c_str()));
+ }
+ } else // reg exp list
+ {
+ std::vector<std::string> programs;
+ cmSystemTools::Glob(makefile.GetCurrentSourceDirectory(), args[0],
+ programs);
+
+ auto s = programs.begin();
+ // for each argument, get the programs
+ for (; s != programs.end(); ++s) {
+ files.push_back(FindInstallSource(makefile, s->c_str()));
+ }
+ }
+
+ // Construct the destination. This command always installs under
+ // the prefix. We skip the leading slash given by the user.
+ std::string destination = dest.substr(1);
+ cmSystemTools::ConvertToUnixSlashes(destination);
+ if (destination.empty()) {
+ destination = ".";
+ }
+
+ // Use a file install generator.
+ const std::string no_permissions;
+ const std::string no_rename;
+ bool no_exclude_from_all = false;
+ std::string no_component =
+ makefile.GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME");
+ std::vector<std::string> no_configurations;
+ cmInstallGenerator::MessageLevel message =
+ cmInstallGenerator::SelectMessageLevel(&makefile);
+ makefile.AddInstallGenerator(cm::make_unique<cmInstallFilesGenerator>(
+ files, destination, true, no_permissions, no_configurations, no_component,
+ message, no_exclude_from_all, no_rename, false, makefile.GetBacktrace()));
+}
+
+/**
+ * Find a file in the build or source tree for installation given a
+ * relative path from the CMakeLists.txt file. This will favor files
+ * present in the build tree. If a full path is given, it is just
+ * returned.
+ */
+static std::string FindInstallSource(cmMakefile& makefile, const char* name)
+{
+ if (cmSystemTools::FileIsFullPath(name) ||
+ cmGeneratorExpression::Find(name) == 0) {
+ // This is a full path.
+ return name;
+ }
+
+ // This is a relative path.
+ std::string tb = cmStrCat(makefile.GetCurrentBinaryDirectory(), '/', name);
+ std::string ts = cmStrCat(makefile.GetCurrentSourceDirectory(), '/', name);
+
+ if (cmSystemTools::FileExists(tb)) {
+ // The file exists in the binary tree. Use it.
+ return tb;
+ }
+ if (cmSystemTools::FileExists(ts)) {
+ // The file exists in the source tree. Use it.
+ return ts;
+ }
+ // The file doesn't exist. Assume it will be present in the
+ // binary tree when the install occurs.
+ return tb;
+}
diff --git a/Source/cmInstallProgramsCommand.h b/Source/cmInstallProgramsCommand.h
new file mode 100644
index 0000000..e3c3e81
--- /dev/null
+++ b/Source/cmInstallProgramsCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmInstallProgramsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmInstallScriptGenerator.cxx b/Source/cmInstallScriptGenerator.cxx
new file mode 100644
index 0000000..bb38990
--- /dev/null
+++ b/Source/cmInstallScriptGenerator.cxx
@@ -0,0 +1,93 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallScriptGenerator.h"
+
+#include <ostream>
+#include <utility>
+#include <vector>
+
+#include "cmGeneratorExpression.h"
+#include "cmLocalGenerator.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmScriptGenerator.h"
+
+cmInstallScriptGenerator::cmInstallScriptGenerator(
+ std::string script, bool code, std::string const& component,
+ bool exclude_from_all, cmListFileBacktrace backtrace)
+ : cmInstallGenerator("", std::vector<std::string>(), component,
+ MessageDefault, exclude_from_all, std::move(backtrace))
+ , Script(std::move(script))
+ , Code(code)
+ , AllowGenex(false)
+{
+ // We need per-config actions if the script has generator expressions.
+ if (cmGeneratorExpression::Find(this->Script) != std::string::npos) {
+ this->ActionsPerConfig = true;
+ }
+}
+
+cmInstallScriptGenerator::~cmInstallScriptGenerator() = default;
+
+bool cmInstallScriptGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LocalGenerator = lg;
+
+ if (this->ActionsPerConfig) {
+ switch (this->LocalGenerator->GetPolicyStatus(cmPolicies::CMP0087)) {
+ case cmPolicies::WARN:
+ this->LocalGenerator->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0087));
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ this->AllowGenex = true;
+ break;
+ }
+ }
+
+ return true;
+}
+
+std::string cmInstallScriptGenerator::GetScript(
+ std::string const& config) const
+{
+ std::string script;
+ if (this->AllowGenex && this->ActionsPerConfig) {
+ script = cmGeneratorExpression::Evaluate(this->Script,
+ this->LocalGenerator, config);
+ } else {
+ script = this->Script;
+ }
+ return script;
+}
+
+void cmInstallScriptGenerator::AddScriptInstallRule(
+ std::ostream& os, Indent indent, std::string const& script) const
+{
+ if (this->Code) {
+ os << indent << script << "\n";
+ } else {
+ os << indent << "include(\"" << script << "\")\n";
+ }
+}
+
+void cmInstallScriptGenerator::GenerateScriptActions(std::ostream& os,
+ Indent indent)
+{
+ if (this->AllowGenex && this->ActionsPerConfig) {
+ this->cmInstallGenerator::GenerateScriptActions(os, indent);
+ } else {
+ this->AddScriptInstallRule(os, indent, this->Script);
+ }
+}
+
+void cmInstallScriptGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent indent)
+{
+ this->AddScriptInstallRule(os, indent, this->GetScript(config));
+}
diff --git a/Source/cmInstallScriptGenerator.h b/Source/cmInstallScriptGenerator.h
new file mode 100644
index 0000000..6274f1c
--- /dev/null
+++ b/Source/cmInstallScriptGenerator.h
@@ -0,0 +1,45 @@
+/* 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 <iosfwd>
+#include <string>
+
+#include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
+#include "cmScriptGenerator.h"
+
+class cmLocalGenerator;
+
+/** \class cmInstallScriptGenerator
+ * \brief Generate target installation rules.
+ */
+class cmInstallScriptGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallScriptGenerator(
+ std::string script, bool code, std::string const& component,
+ bool exclude_from_all,
+ cmListFileBacktrace backtrace = cmListFileBacktrace());
+ ~cmInstallScriptGenerator() override;
+
+ bool Compute(cmLocalGenerator* lg) override;
+
+ bool IsCode() const { return this->Code; }
+
+ std::string GetScript(std::string const& config) const;
+
+protected:
+ void GenerateScriptActions(std::ostream& os, Indent indent) override;
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent indent) override;
+ void AddScriptInstallRule(std::ostream& os, Indent indent,
+ std::string const& script) const;
+
+ std::string const Script;
+ bool const Code;
+ cmLocalGenerator* LocalGenerator;
+ bool AllowGenex;
+};
diff --git a/Source/cmInstallSubdirectoryGenerator.cxx b/Source/cmInstallSubdirectoryGenerator.cxx
new file mode 100644
index 0000000..76806e5
--- /dev/null
+++ b/Source/cmInstallSubdirectoryGenerator.cxx
@@ -0,0 +1,79 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallSubdirectoryGenerator.h"
+
+#include <memory>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmPolicies.h"
+#include "cmScriptGenerator.h"
+#include "cmSystemTools.h"
+
+cmInstallSubdirectoryGenerator::cmInstallSubdirectoryGenerator(
+ cmMakefile* makefile, std::string binaryDirectory, bool excludeFromAll,
+ cmListFileBacktrace backtrace)
+ : cmInstallGenerator("", std::vector<std::string>(), "", MessageDefault,
+ excludeFromAll, std::move(backtrace))
+ , Makefile(makefile)
+ , BinaryDirectory(std::move(binaryDirectory))
+{
+}
+
+cmInstallSubdirectoryGenerator::~cmInstallSubdirectoryGenerator() = default;
+
+bool cmInstallSubdirectoryGenerator::HaveInstall()
+{
+ for (const auto& generator : this->Makefile->GetInstallGenerators()) {
+ if (generator->HaveInstall()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void cmInstallSubdirectoryGenerator::CheckCMP0082(
+ bool& haveSubdirectoryInstall, bool& /*unused*/)
+{
+ if (this->HaveInstall()) {
+ haveSubdirectoryInstall = true;
+ }
+}
+
+bool cmInstallSubdirectoryGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LocalGenerator = lg;
+ return true;
+}
+
+void cmInstallSubdirectoryGenerator::GenerateScript(std::ostream& os)
+{
+ if (!this->ExcludeFromAll) {
+ cmPolicies::PolicyStatus status =
+ this->LocalGenerator->GetPolicyStatus(cmPolicies::CMP0082);
+ switch (status) {
+ case cmPolicies::WARN:
+ case cmPolicies::OLD:
+ // OLD behavior is handled in cmLocalGenerator::GenerateInstallRules()
+ break;
+
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS: {
+ Indent indent;
+ std::string odir = this->BinaryDirectory;
+ cmSystemTools::ConvertToUnixSlashes(odir);
+ os << indent << "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n"
+ << indent.Next()
+ << "# Include the install script for the subdirectory.\n"
+ << indent.Next() << "include(\"" << odir
+ << "/cmake_install.cmake\")\n"
+ << indent << "endif()\n\n";
+ } break;
+ }
+ }
+}
diff --git a/Source/cmInstallSubdirectoryGenerator.h b/Source/cmInstallSubdirectoryGenerator.h
new file mode 100644
index 0000000..614cef9
--- /dev/null
+++ b/Source/cmInstallSubdirectoryGenerator.h
@@ -0,0 +1,40 @@
+/* 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 <iosfwd>
+#include <string>
+
+#include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
+
+class cmLocalGenerator;
+class cmMakefile;
+
+/** \class cmInstallSubdirectoryGenerator
+ * \brief Generate target installation rules.
+ */
+class cmInstallSubdirectoryGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallSubdirectoryGenerator(cmMakefile* makefile,
+ std::string binaryDirectory,
+ bool excludeFromAll,
+ cmListFileBacktrace backtrace);
+ ~cmInstallSubdirectoryGenerator() override;
+
+ bool HaveInstall() override;
+ void CheckCMP0082(bool& haveSubdirectoryInstall,
+ bool& haveInstallAfterSubdirectory) override;
+
+ bool Compute(cmLocalGenerator* lg) override;
+
+protected:
+ void GenerateScript(std::ostream& os) override;
+
+ cmMakefile* const Makefile;
+ std::string const BinaryDirectory;
+ cmLocalGenerator* LocalGenerator;
+};
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
new file mode 100644
index 0000000..eb214fa
--- /dev/null
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -0,0 +1,927 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallTargetGenerator.h"
+
+#include <cassert>
+#include <map>
+#include <set>
+#include <sstream>
+#include <utility>
+
+#include "cmComputeLinkInformation.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallType.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmake.h"
+
+namespace {
+std::string computeInstallObjectDir(cmGeneratorTarget* gt,
+ std::string const& config)
+{
+ std::string objectDir = "objects";
+ if (!config.empty()) {
+ objectDir += "-";
+ objectDir += config;
+ }
+ objectDir += "/";
+ objectDir += gt->GetName();
+ return objectDir;
+}
+}
+
+cmInstallTargetGenerator::cmInstallTargetGenerator(
+ std::string targetName, std::string const& dest, bool implib,
+ std::string file_permissions, std::vector<std::string> const& configurations,
+ std::string const& component, MessageLevel message, bool exclude_from_all,
+ bool optional, cmListFileBacktrace backtrace)
+ : cmInstallGenerator(dest, configurations, component, message,
+ exclude_from_all, std::move(backtrace))
+ , TargetName(std::move(targetName))
+ , Target(nullptr)
+ , FilePermissions(std::move(file_permissions))
+ , ImportLibrary(implib)
+ , Optional(optional)
+{
+ this->ActionsPerConfig = true;
+ this->NamelinkMode = NamelinkModeNone;
+}
+
+cmInstallTargetGenerator::~cmInstallTargetGenerator() = default;
+
+void cmInstallTargetGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent indent)
+{
+ // Compute the list of files to install for this target.
+ Files files = this->GetFiles(config);
+
+ // Skip this rule if no files are to be installed for the target.
+ if (files.From.empty()) {
+ return;
+ }
+
+ // Compute the effective install destination.
+ std::string dest = this->GetDestination(config);
+ if (!files.ToDir.empty()) {
+ dest = cmStrCat(dest, '/', files.ToDir);
+ }
+
+ // Tweak files located in the destination directory.
+ std::string toDir = cmStrCat(this->ConvertToAbsoluteDestination(dest), '/');
+
+ // Add pre-installation tweaks.
+ if (!files.NoTweak) {
+ this->AddTweak(os, indent, config, toDir, files.To,
+ &cmInstallTargetGenerator::PreReplacementTweaks);
+ }
+
+ // Write code to install the target file.
+ const char* no_dir_permissions = nullptr;
+ const char* no_rename = nullptr;
+ bool optional = this->Optional || this->ImportLibrary;
+ std::string literal_args;
+ if (!files.FromDir.empty()) {
+ literal_args += " FILES_FROM_DIR \"" + files.FromDir + "\"";
+ }
+ if (files.UseSourcePermissions) {
+ literal_args += " USE_SOURCE_PERMISSIONS";
+ }
+ this->AddInstallRule(os, dest, files.Type, files.From, optional,
+ this->FilePermissions.c_str(), no_dir_permissions,
+ no_rename, literal_args.c_str(), indent);
+
+ // Add post-installation tweaks.
+ if (!files.NoTweak) {
+ this->AddTweak(os, indent, config, toDir, files.To,
+ &cmInstallTargetGenerator::PostReplacementTweaks);
+ }
+}
+
+cmInstallTargetGenerator::Files cmInstallTargetGenerator::GetFiles(
+ std::string const& config) const
+{
+ Files files;
+
+ cmStateEnums::TargetType targetType = this->Target->GetType();
+ switch (targetType) {
+ case cmStateEnums::EXECUTABLE:
+ files.Type = cmInstallType_EXECUTABLE;
+ break;
+ case cmStateEnums::STATIC_LIBRARY:
+ files.Type = cmInstallType_STATIC_LIBRARY;
+ break;
+ case cmStateEnums::SHARED_LIBRARY:
+ files.Type = cmInstallType_SHARED_LIBRARY;
+ break;
+ case cmStateEnums::MODULE_LIBRARY:
+ files.Type = cmInstallType_MODULE_LIBRARY;
+ break;
+ case cmStateEnums::INTERFACE_LIBRARY:
+ // Not reachable. We never create a cmInstallTargetGenerator for
+ // an INTERFACE_LIBRARY.
+ assert(false &&
+ "INTERFACE_LIBRARY targets have no installable outputs.");
+ break;
+
+ case cmStateEnums::OBJECT_LIBRARY: {
+ // Compute all the object files inside this target
+ std::vector<std::string> objects;
+ this->Target->GetTargetObjectNames(config, objects);
+
+ files.Type = cmInstallType_FILES;
+ files.NoTweak = true;
+ files.FromDir = this->Target->GetObjectDirectory(config);
+ files.ToDir = computeInstallObjectDir(this->Target, config);
+ for (std::string& obj : objects) {
+ files.From.emplace_back(obj);
+ files.To.emplace_back(std::move(obj));
+ }
+ return files;
+ }
+
+ case cmStateEnums::UTILITY:
+ case cmStateEnums::GLOBAL_TARGET:
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ this->Target->GetLocalGenerator()->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ "cmInstallTargetGenerator created with non-installable target.");
+ return files;
+ }
+
+ // Compute the build tree directory from which to copy the target.
+ std::string fromDirConfig;
+ if (this->Target->NeedRelinkBeforeInstall(config)) {
+ fromDirConfig =
+ cmStrCat(this->Target->GetLocalGenerator()->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/CMakeRelink.dir/");
+ } else {
+ cmStateEnums::ArtifactType artifact = this->ImportLibrary
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+ fromDirConfig =
+ cmStrCat(this->Target->GetDirectory(config, artifact), '/');
+ }
+
+ if (targetType == cmStateEnums::EXECUTABLE) {
+ // There is a bug in cmInstallCommand if this fails.
+ assert(this->NamelinkMode == NamelinkModeNone);
+
+ cmGeneratorTarget::Names targetNames =
+ this->Target->GetExecutableNames(config);
+ if (this->ImportLibrary) {
+ std::string from1 = fromDirConfig + targetNames.ImportLibrary;
+ std::string to1 = targetNames.ImportLibrary;
+ files.From.emplace_back(std::move(from1));
+ files.To.emplace_back(std::move(to1));
+ std::string targetNameImportLib;
+ if (this->Target->GetImplibGNUtoMS(config, targetNames.ImportLibrary,
+ targetNameImportLib)) {
+ files.From.emplace_back(fromDirConfig + targetNameImportLib);
+ files.To.emplace_back(targetNameImportLib);
+ }
+
+ // An import library looks like a static library.
+ files.Type = cmInstallType_STATIC_LIBRARY;
+ } else {
+ std::string from1 = fromDirConfig + targetNames.Output;
+ std::string to1 = targetNames.Output;
+
+ // Handle OSX Bundles.
+ if (this->Target->IsAppBundleOnApple()) {
+ cmMakefile const* mf = this->Target->Target->GetMakefile();
+
+ // Get App Bundle Extension
+ std::string ext;
+ if (cmProp p = this->Target->GetProperty("BUNDLE_EXTENSION")) {
+ ext = *p;
+ } else {
+ ext = "app";
+ }
+
+ // Install the whole app bundle directory.
+ files.Type = cmInstallType_DIRECTORY;
+ files.UseSourcePermissions = true;
+ from1 += ".";
+ from1 += ext;
+
+ // Tweaks apply to the binary inside the bundle.
+ to1 += ".";
+ to1 += ext;
+ to1 += "/";
+ if (!mf->PlatformIsAppleEmbedded()) {
+ to1 += "Contents/MacOS/";
+ }
+ to1 += targetNames.Output;
+ } else {
+ // Tweaks apply to the real file, so list it first.
+ if (targetNames.Real != targetNames.Output) {
+ std::string from2 = fromDirConfig + targetNames.Real;
+ std::string to2 = targetNames.Real;
+ files.From.emplace_back(std::move(from2));
+ files.To.emplace_back(std::move(to2));
+ }
+ }
+
+ files.From.emplace_back(std::move(from1));
+ files.To.emplace_back(std::move(to1));
+ }
+ } else {
+ cmGeneratorTarget::Names targetNames =
+ this->Target->GetLibraryNames(config);
+ if (this->ImportLibrary) {
+ // There is a bug in cmInstallCommand if this fails.
+ assert(this->NamelinkMode == NamelinkModeNone);
+
+ std::string from1 = fromDirConfig + targetNames.ImportLibrary;
+ std::string to1 = targetNames.ImportLibrary;
+ files.From.emplace_back(std::move(from1));
+ files.To.emplace_back(std::move(to1));
+ std::string targetNameImportLib;
+ if (this->Target->GetImplibGNUtoMS(config, targetNames.ImportLibrary,
+ targetNameImportLib)) {
+ files.From.emplace_back(fromDirConfig + targetNameImportLib);
+ files.To.emplace_back(targetNameImportLib);
+ }
+
+ // An import library looks like a static library.
+ files.Type = cmInstallType_STATIC_LIBRARY;
+ } else if (this->Target->IsFrameworkOnApple()) {
+ // FIXME: In principle we should be able to
+ // assert(this->NamelinkMode == NamelinkModeNone);
+ // but since the current install() command implementation checks
+ // the FRAMEWORK property immediately instead of delaying until
+ // generate time, it is possible for project code to set the
+ // property after calling install(). In such a case, the install()
+ // command will use the LIBRARY code path and create two install
+ // generators, one for the namelink component (NamelinkModeOnly)
+ // and one for the primary artifact component (NamelinkModeSkip).
+ // Historically this was not diagnosed and resulted in silent
+ // installation of a framework to the LIBRARY destination.
+ // Retain that behavior and warn about the case.
+ switch (this->NamelinkMode) {
+ case NamelinkModeNone:
+ // Normal case.
+ break;
+ case NamelinkModeOnly:
+ // Assume the NamelinkModeSkip instance will warn and install.
+ return files;
+ case NamelinkModeSkip: {
+ std::string e = "Target '" + this->Target->GetName() +
+ "' was changed to a FRAMEWORK sometime after install(). "
+ "This may result in the wrong install DESTINATION. "
+ "Set the FRAMEWORK property earlier.";
+ this->Target->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING, e, this->GetBacktrace());
+ } break;
+ }
+
+ // Install the whole framework directory.
+ files.Type = cmInstallType_DIRECTORY;
+ files.UseSourcePermissions = true;
+
+ std::string from1 = fromDirConfig + targetNames.Output;
+ from1 = cmSystemTools::GetFilenamePath(from1);
+
+ // Tweaks apply to the binary inside the bundle.
+ std::string to1 = targetNames.Real;
+
+ files.From.emplace_back(std::move(from1));
+ files.To.emplace_back(std::move(to1));
+ } else if (this->Target->IsCFBundleOnApple()) {
+ // Install the whole app bundle directory.
+ files.Type = cmInstallType_DIRECTORY;
+ files.UseSourcePermissions = true;
+
+ std::string targetNameBase =
+ targetNames.Output.substr(0, targetNames.Output.find('/'));
+
+ std::string from1 = fromDirConfig + targetNameBase;
+ std::string to1 = targetNames.Output;
+
+ files.From.emplace_back(std::move(from1));
+ files.To.emplace_back(std::move(to1));
+ } else {
+ bool haveNamelink = false;
+
+ // Library link name.
+ std::string fromName = fromDirConfig + targetNames.Output;
+ std::string toName = targetNames.Output;
+
+ // Library interface name.
+ std::string fromSOName;
+ std::string toSOName;
+ if (targetNames.SharedObject != targetNames.Output) {
+ haveNamelink = true;
+ fromSOName = fromDirConfig + targetNames.SharedObject;
+ toSOName = targetNames.SharedObject;
+ }
+
+ // Library implementation name.
+ std::string fromRealName;
+ std::string toRealName;
+ if (targetNames.Real != targetNames.Output &&
+ targetNames.Real != targetNames.SharedObject) {
+ haveNamelink = true;
+ fromRealName = fromDirConfig + targetNames.Real;
+ toRealName = targetNames.Real;
+ }
+
+ // Add the names based on the current namelink mode.
+ if (haveNamelink) {
+ files.NamelinkMode = this->NamelinkMode;
+ // With a namelink we need to check the mode.
+ if (this->NamelinkMode == NamelinkModeOnly) {
+ // Install the namelink only.
+ files.From.emplace_back(fromName);
+ files.To.emplace_back(toName);
+ } else {
+ // Install the real file if it has its own name.
+ if (!fromRealName.empty()) {
+ files.From.emplace_back(fromRealName);
+ files.To.emplace_back(toRealName);
+ }
+
+ // Install the soname link if it has its own name.
+ if (!fromSOName.empty()) {
+ files.From.emplace_back(fromSOName);
+ files.To.emplace_back(toSOName);
+ }
+
+ // Install the namelink if it is not to be skipped.
+ if (this->NamelinkMode != NamelinkModeSkip) {
+ files.From.emplace_back(fromName);
+ files.To.emplace_back(toName);
+ }
+ }
+ } else {
+ // Without a namelink there will be only one file. Install it
+ // if this is not a namelink-only rule.
+ if (this->NamelinkMode != NamelinkModeOnly) {
+ files.From.emplace_back(fromName);
+ files.To.emplace_back(toName);
+ }
+ }
+ }
+ }
+
+ // If this fails the above code is buggy.
+ assert(files.From.size() == files.To.size());
+
+ return files;
+}
+
+void cmInstallTargetGenerator::GetInstallObjectNames(
+ std::string const& config, std::vector<std::string>& objects) const
+{
+ this->Target->GetTargetObjectNames(config, objects);
+ for (std::string& o : objects) {
+ o = cmStrCat(computeInstallObjectDir(this->Target, config), "/", o);
+ }
+}
+
+std::string cmInstallTargetGenerator::GetDestination(
+ std::string const& config) const
+{
+ return cmGeneratorExpression::Evaluate(
+ this->Destination, this->Target->GetLocalGenerator(), config);
+}
+
+std::string cmInstallTargetGenerator::GetInstallFilename(
+ const std::string& config) const
+{
+ NameType nameType = this->ImportLibrary ? NameImplib : NameNormal;
+ return cmInstallTargetGenerator::GetInstallFilename(this->Target, config,
+ nameType);
+}
+
+std::string cmInstallTargetGenerator::GetInstallFilename(
+ cmGeneratorTarget const* target, const std::string& config,
+ NameType nameType)
+{
+ std::string fname;
+ // Compute the name of the library.
+ if (target->GetType() == cmStateEnums::EXECUTABLE) {
+ cmGeneratorTarget::Names targetNames = target->GetExecutableNames(config);
+ if (nameType == NameImplib) {
+ // Use the import library name.
+ if (!target->GetImplibGNUtoMS(config, targetNames.ImportLibrary, fname,
+ "${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
+ fname = targetNames.ImportLibrary;
+ }
+ } else if (nameType == NameReal) {
+ // Use the canonical name.
+ fname = targetNames.Real;
+ } else {
+ // Use the canonical name.
+ fname = targetNames.Output;
+ }
+ } else {
+ cmGeneratorTarget::Names targetNames = target->GetLibraryNames(config);
+ if (nameType == NameImplib) {
+ // Use the import library name.
+ if (!target->GetImplibGNUtoMS(config, targetNames.ImportLibrary, fname,
+ "${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
+ fname = targetNames.ImportLibrary;
+ }
+ } else if (nameType == NameSO) {
+ // Use the soname.
+ fname = targetNames.SharedObject;
+ } else if (nameType == NameReal) {
+ // Use the real name.
+ fname = targetNames.Real;
+ } else {
+ // Use the canonical name.
+ fname = targetNames.Output;
+ }
+ }
+
+ return fname;
+}
+
+bool cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
+{
+ // Lookup this target in the current directory.
+ this->Target = lg->FindLocalNonAliasGeneratorTarget(this->TargetName);
+ if (!this->Target) {
+ // If no local target has been found, find it in the global scope.
+ this->Target =
+ lg->GetGlobalGenerator()->FindGeneratorTarget(this->TargetName);
+ }
+
+ return true;
+}
+
+void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent,
+ const std::string& config,
+ std::string const& file,
+ TweakMethod tweak)
+{
+ std::ostringstream tw;
+ (this->*tweak)(tw, indent.Next(), config, file);
+ std::string tws = tw.str();
+ if (!tws.empty()) {
+ os << indent << "if(EXISTS \"" << file << "\" AND\n"
+ << indent << " NOT IS_SYMLINK \"" << file << "\")\n";
+ os << tws;
+ os << indent << "endif()\n";
+ }
+}
+
+void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent,
+ const std::string& config,
+ std::string const& dir,
+ std::vector<std::string> const& files,
+ TweakMethod tweak)
+{
+ if (files.size() == 1) {
+ // Tweak a single file.
+ this->AddTweak(os, indent, config,
+ this->GetDestDirPath(cmStrCat(dir, files[0])), tweak);
+ } else {
+ // Generate a foreach loop to tweak multiple files.
+ std::ostringstream tw;
+ this->AddTweak(tw, indent.Next(), config, "${file}", tweak);
+ std::string tws = tw.str();
+ if (!tws.empty()) {
+ Indent indent2 = indent.Next().Next();
+ os << indent << "foreach(file\n";
+ for (std::string const& f : files) {
+ os << indent2 << "\"" << this->GetDestDirPath(cmStrCat(dir, f))
+ << "\"\n";
+ }
+ os << indent2 << ")\n";
+ os << tws;
+ os << indent << "endforeach()\n";
+ }
+ }
+}
+
+std::string cmInstallTargetGenerator::GetDestDirPath(std::string const& file)
+{
+ // Construct the path of the file on disk after installation on
+ // which tweaks may be performed.
+ std::string toDestDirPath = "$ENV{DESTDIR}";
+ if (file[0] != '/' && file[0] != '$') {
+ toDestDirPath += "/";
+ }
+ toDestDirPath += file;
+ return toDestDirPath;
+}
+
+void cmInstallTargetGenerator::PreReplacementTweaks(std::ostream& os,
+ Indent indent,
+ const std::string& config,
+ std::string const& file)
+{
+ this->AddRPathCheckRule(os, indent, config, file);
+}
+
+void cmInstallTargetGenerator::PostReplacementTweaks(std::ostream& os,
+ Indent indent,
+ const std::string& config,
+ std::string const& file)
+{
+ this->AddInstallNamePatchRule(os, indent, config, file);
+ this->AddChrpathPatchRule(os, indent, config, file);
+ this->AddUniversalInstallRule(os, indent, file);
+ this->AddRanlibRule(os, indent, file);
+ this->AddStripRule(os, indent, file);
+}
+
+void cmInstallTargetGenerator::AddInstallNamePatchRule(
+ std::ostream& os, Indent indent, const std::string& config,
+ std::string const& toDestDirPath)
+{
+ if (this->ImportLibrary ||
+ !(this->Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->Target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ this->Target->GetType() == cmStateEnums::EXECUTABLE)) {
+ return;
+ }
+
+ // Fix the install_name settings in installed binaries.
+ std::string installNameTool =
+ this->Target->Target->GetMakefile()->GetSafeDefinition(
+ "CMAKE_INSTALL_NAME_TOOL");
+
+ if (installNameTool.empty()) {
+ return;
+ }
+
+ // Build a map of build-tree install_name to install-tree install_name for
+ // shared libraries linked to this target.
+ std::map<std::string, std::string> install_name_remap;
+ if (cmComputeLinkInformation* cli =
+ this->Target->GetLinkInformation(config)) {
+ std::set<cmGeneratorTarget const*> const& sharedLibs =
+ cli->GetSharedLibrariesLinked();
+ for (cmGeneratorTarget const* tgt : sharedLibs) {
+ // The install_name of an imported target does not change.
+ if (tgt->IsImported()) {
+ continue;
+ }
+
+ // If the build tree and install tree use different path
+ // components of the install_name field then we need to create a
+ // mapping to be applied after installation.
+ std::string for_build = tgt->GetInstallNameDirForBuildTree(config);
+ std::string for_install = tgt->GetInstallNameDirForInstallTree(
+ config, "${CMAKE_INSTALL_PREFIX}");
+ if (for_build != for_install) {
+ // The directory portions differ. Append the filename to
+ // create the mapping.
+ std::string fname = this->GetInstallFilename(tgt, config, NameSO);
+
+ // Map from the build-tree install_name.
+ for_build += fname;
+
+ // Map to the install-tree install_name.
+ for_install += fname;
+
+ // Store the mapping entry.
+ install_name_remap[for_build] = for_install;
+ }
+ }
+ }
+
+ // Edit the install_name of the target itself if necessary.
+ std::string new_id;
+ if (this->Target->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ std::string for_build =
+ this->Target->GetInstallNameDirForBuildTree(config);
+ std::string for_install = this->Target->GetInstallNameDirForInstallTree(
+ config, "${CMAKE_INSTALL_PREFIX}");
+
+ if (this->Target->IsFrameworkOnApple() && for_install.empty()) {
+ // Frameworks seem to have an id corresponding to their own full
+ // path.
+ // ...
+ // for_install = fullDestPath_without_DESTDIR_or_name;
+ }
+
+ // If the install name will change on installation set the new id
+ // on the installed file.
+ if (for_build != for_install) {
+ // Prepare to refer to the install-tree install_name.
+ new_id = cmStrCat(
+ for_install, this->GetInstallFilename(this->Target, config, NameSO));
+ }
+ }
+
+ // Write a rule to run install_name_tool to set the install-tree
+ // install_name value and references.
+ if (!new_id.empty() || !install_name_remap.empty()) {
+ os << indent << "execute_process(COMMAND \"" << installNameTool;
+ os << "\"";
+ if (!new_id.empty()) {
+ os << "\n" << indent << " -id \"" << new_id << "\"";
+ }
+ for (auto const& i : install_name_remap) {
+ os << "\n"
+ << indent << " -change \"" << i.first << "\" \"" << i.second << "\"";
+ }
+ os << "\n" << indent << " \"" << toDestDirPath << "\")\n";
+ }
+}
+
+void cmInstallTargetGenerator::AddRPathCheckRule(
+ std::ostream& os, Indent indent, const std::string& config,
+ std::string const& toDestDirPath)
+{
+ // Skip the chrpath if the target does not need it.
+ if (this->ImportLibrary || !this->Target->IsChrpathUsed(config)) {
+ return;
+ }
+ // Skip if on Apple
+ if (this->Target->Target->GetMakefile()->IsOn(
+ "CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ return;
+ }
+
+ // Get the link information for this target.
+ // It can provide the RPATH.
+ cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
+ if (!cli) {
+ return;
+ }
+
+ // Write a rule to remove the installed file if its rpath is not the
+ // new rpath. This is needed for existing build/install trees when
+ // the installed rpath changes but the file is not rebuilt.
+ os << indent << "file(RPATH_CHECK\n"
+ << indent << " FILE \"" << toDestDirPath << "\"\n";
+
+ // CMP0095: ``RPATH`` entries are properly escaped in the intermediary
+ // CMake install script.
+ switch (this->Target->GetPolicyStatusCMP0095()) {
+ case cmPolicies::WARN:
+ // No author warning needed here, we warn later in
+ // cmInstallTargetGenerator::AddChrpathPatchRule().
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD: {
+ // Get the install RPATH from the link information.
+ std::string newRpath = cli->GetChrpathString();
+ os << indent << " RPATH \"" << newRpath << "\")\n";
+ break;
+ }
+ default: {
+ // Get the install RPATH from the link information and
+ // escape any CMake syntax in the install RPATH.
+ std::string escapedNewRpath =
+ cmOutputConverter::EscapeForCMake(cli->GetChrpathString());
+ os << indent << " RPATH " << escapedNewRpath << ")\n";
+ break;
+ }
+ }
+}
+
+void cmInstallTargetGenerator::AddChrpathPatchRule(
+ std::ostream& os, Indent indent, const std::string& config,
+ std::string const& toDestDirPath)
+{
+ // Skip the chrpath if the target does not need it.
+ if (this->ImportLibrary || !this->Target->IsChrpathUsed(config)) {
+ return;
+ }
+
+ // Get the link information for this target.
+ // It can provide the RPATH.
+ cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
+ if (!cli) {
+ return;
+ }
+
+ cmMakefile* mf = this->Target->Target->GetMakefile();
+
+ if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+ // If using install_name_tool, set up the rules to modify the rpaths.
+ std::string installNameTool =
+ mf->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
+
+ std::vector<std::string> oldRuntimeDirs;
+ std::vector<std::string> newRuntimeDirs;
+ cli->GetRPath(oldRuntimeDirs, false);
+ cli->GetRPath(newRuntimeDirs, true);
+
+ std::string darwin_major_version_s =
+ mf->GetSafeDefinition("DARWIN_MAJOR_VERSION");
+
+ std::istringstream ss(darwin_major_version_s);
+ int darwin_major_version;
+ ss >> darwin_major_version;
+ if (!ss.fail() && darwin_major_version <= 9 &&
+ (!oldRuntimeDirs.empty() || !newRuntimeDirs.empty())) {
+ std::ostringstream msg;
+ msg
+ << "WARNING: Target \"" << this->Target->GetName()
+ << "\" has runtime paths which cannot be changed during install. "
+ << "To change runtime paths, OS X version 10.6 or newer is required. "
+ << "Therefore, runtime paths will not be changed when installing. "
+ << "CMAKE_BUILD_WITH_INSTALL_RPATH may be used to work around"
+ " this limitation.";
+ mf->IssueMessage(MessageType::WARNING, msg.str());
+ } else {
+ // Note: These paths are kept unique to avoid
+ // install_name_tool corruption.
+ std::set<std::string> runpaths;
+ for (std::string const& i : oldRuntimeDirs) {
+ std::string runpath =
+ mf->GetGlobalGenerator()->ExpandCFGIntDir(i, config);
+
+ if (runpaths.find(runpath) == runpaths.end()) {
+ runpaths.insert(runpath);
+ os << indent << "execute_process(COMMAND " << installNameTool
+ << "\n";
+ os << indent << " -delete_rpath \"" << runpath << "\"\n";
+ os << indent << " \"" << toDestDirPath << "\")\n";
+ }
+ }
+
+ runpaths.clear();
+ for (std::string const& i : newRuntimeDirs) {
+ std::string runpath =
+ mf->GetGlobalGenerator()->ExpandCFGIntDir(i, config);
+
+ if (runpaths.find(runpath) == runpaths.end()) {
+ os << indent << "execute_process(COMMAND " << installNameTool
+ << "\n";
+ os << indent << " -add_rpath \"" << runpath << "\"\n";
+ os << indent << " \"" << toDestDirPath << "\")\n";
+ }
+ }
+ }
+ } else {
+ // Construct the original rpath string to be replaced.
+ std::string oldRpath = cli->GetRPathString(false);
+
+ // Get the install RPATH from the link information.
+ std::string newRpath = cli->GetChrpathString();
+
+ // Skip the rule if the paths are identical
+ if (oldRpath == newRpath) {
+ return;
+ }
+
+ // Escape any CMake syntax in the RPATHs.
+ std::string escapedOldRpath = cmOutputConverter::EscapeForCMake(oldRpath);
+ std::string escapedNewRpath = cmOutputConverter::EscapeForCMake(newRpath);
+
+ // Write a rule to run chrpath to set the install-tree RPATH
+ os << indent << "file(RPATH_CHANGE\n"
+ << indent << " FILE \"" << toDestDirPath << "\"\n"
+ << indent << " OLD_RPATH " << escapedOldRpath << "\n";
+
+ // CMP0095: ``RPATH`` entries are properly escaped in the intermediary
+ // CMake install script.
+ switch (this->Target->GetPolicyStatusCMP0095()) {
+ case cmPolicies::WARN:
+ this->IssueCMP0095Warning(newRpath);
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ os << indent << " NEW_RPATH \"" << newRpath << "\"";
+ break;
+ default:
+ os << indent << " NEW_RPATH " << escapedNewRpath;
+ break;
+ }
+
+ if (this->Target->GetPropertyAsBool("INSTALL_REMOVE_ENVIRONMENT_RPATH")) {
+ os << "\n" << indent << " INSTALL_REMOVE_ENVIRONMENT_RPATH)\n";
+ } else {
+ os << ")\n";
+ }
+ }
+}
+
+void cmInstallTargetGenerator::AddStripRule(std::ostream& os, Indent indent,
+ const std::string& toDestDirPath)
+{
+
+ // don't strip static and import libraries, because it removes the only
+ // symbol table they have so you can't link to them anymore
+ if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ this->ImportLibrary) {
+ return;
+ }
+
+ // Don't handle OSX Bundles.
+ if (this->Target->Target->GetMakefile()->IsOn("APPLE") &&
+ this->Target->GetPropertyAsBool("MACOSX_BUNDLE")) {
+ return;
+ }
+
+ if (!this->Target->Target->GetMakefile()->IsSet("CMAKE_STRIP")) {
+ return;
+ }
+
+ std::string stripArgs;
+
+ // macOS 'strip' is picky, executables need '-u -r' and dylibs need '-x'.
+ if (this->Target->Target->GetMakefile()->IsOn("APPLE")) {
+ if (this->Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->Target->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ stripArgs = "-x ";
+ } else if (this->Target->GetType() == cmStateEnums::EXECUTABLE) {
+ stripArgs = "-u -r ";
+ }
+ }
+
+ os << indent << "if(CMAKE_INSTALL_DO_STRIP)\n";
+ os << indent << " execute_process(COMMAND \""
+ << this->Target->Target->GetMakefile()->GetSafeDefinition("CMAKE_STRIP")
+ << "\" " << stripArgs << "\"" << toDestDirPath << "\")\n";
+ os << indent << "endif()\n";
+}
+
+void cmInstallTargetGenerator::AddRanlibRule(std::ostream& os, Indent indent,
+ const std::string& toDestDirPath)
+{
+ // Static libraries need ranlib on this platform.
+ if (this->Target->GetType() != cmStateEnums::STATIC_LIBRARY) {
+ return;
+ }
+
+ // Perform post-installation processing on the file depending
+ // on its type.
+ if (!this->Target->Target->GetMakefile()->IsOn("APPLE")) {
+ return;
+ }
+
+ const std::string& ranlib =
+ this->Target->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
+ if (ranlib.empty()) {
+ return;
+ }
+
+ os << indent << "execute_process(COMMAND \"" << ranlib << "\" \""
+ << toDestDirPath << "\")\n";
+}
+
+void cmInstallTargetGenerator::AddUniversalInstallRule(
+ std::ostream& os, Indent indent, const std::string& toDestDirPath)
+{
+ cmMakefile const* mf = this->Target->Target->GetMakefile();
+
+ if (!mf->PlatformIsAppleEmbedded() || !mf->IsOn("XCODE")) {
+ return;
+ }
+
+ cmProp xcodeVersion = mf->GetDefinition("XCODE_VERSION");
+ if (!xcodeVersion ||
+ cmSystemTools::VersionCompareGreater("6", *xcodeVersion)) {
+ return;
+ }
+
+ switch (this->Target->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ break;
+
+ default:
+ return;
+ }
+
+ if (!this->Target->Target->GetPropertyAsBool("IOS_INSTALL_COMBINED")) {
+ return;
+ }
+
+ os << indent << "include(CMakeIOSInstallCombined)\n";
+ os << indent << "ios_install_combined("
+ << "\"" << this->Target->Target->GetName() << "\" "
+ << "\"" << toDestDirPath << "\")\n";
+}
+
+void cmInstallTargetGenerator::IssueCMP0095Warning(
+ const std::string& unescapedRpath)
+{
+ // Reduce warning noise to cases where used RPATHs may actually be affected
+ // by CMP0095. This filter is meant to skip warnings in cases when
+ // non-curly-braces syntax (e.g. $ORIGIN) or no keyword is used which has
+ // worked already before CMP0095. We intend to issue a warning in all cases
+ // with curly-braces syntax, even if the workaround of double-escaping is in
+ // place, since we deprecate the need for it with CMP0095.
+ const bool potentially_affected(unescapedRpath.find("${") !=
+ std::string::npos);
+
+ if (potentially_affected) {
+ std::ostringstream w;
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0095) << "\n";
+ w << "RPATH entries for target '" << this->Target->GetName() << "' "
+ << "will not be escaped in the intermediary "
+ << "cmake_install.cmake script.";
+ this->Target->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING, w.str(), this->GetBacktrace());
+ }
+}
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
new file mode 100644
index 0000000..84fce42
--- /dev/null
+++ b/Source/cmInstallTargetGenerator.h
@@ -0,0 +1,135 @@
+/* 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 <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmInstallGenerator.h"
+#include "cmInstallType.h"
+#include "cmListFileCache.h"
+#include "cmScriptGenerator.h"
+
+class cmGeneratorTarget;
+class cmLocalGenerator;
+
+/** \class cmInstallTargetGenerator
+ * \brief Generate target installation rules.
+ */
+class cmInstallTargetGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallTargetGenerator(
+ std::string targetName, std::string const& dest, bool implib,
+ std::string file_permissions,
+ std::vector<std::string> const& configurations,
+ std::string const& component, MessageLevel message, bool exclude_from_all,
+ bool optional, cmListFileBacktrace backtrace = cmListFileBacktrace());
+ ~cmInstallTargetGenerator() override;
+
+ /** Select the policy for installing shared library linkable name
+ symlinks. */
+ enum NamelinkModeType
+ {
+ NamelinkModeNone,
+ NamelinkModeOnly,
+ NamelinkModeSkip
+ };
+ void SetNamelinkMode(NamelinkModeType mode) { this->NamelinkMode = mode; }
+
+ std::string GetInstallFilename(const std::string& config) const;
+
+ void GetInstallObjectNames(std::string const& config,
+ std::vector<std::string>& objects) const;
+
+ enum NameType
+ {
+ NameNormal,
+ NameImplib,
+ NameSO,
+ NameReal
+ };
+
+ static std::string GetInstallFilename(const cmGeneratorTarget* target,
+ const std::string& config,
+ NameType nameType = NameNormal);
+
+ bool Compute(cmLocalGenerator* lg) override;
+
+ cmGeneratorTarget* GetTarget() const { return this->Target; }
+
+ bool IsImportLibrary() const { return this->ImportLibrary; }
+
+ std::string GetDestination(std::string const& config) const;
+
+ struct Files
+ {
+ // Names or paths of files to be read from the source or build tree.
+ // The paths may be computed as [FromDir/] + From[i].
+ std::vector<std::string> From;
+
+ // Corresponding names of files to be written in the install directory.
+ // The paths may be computed as Destination/ + [ToDir/] + To[i].
+ std::vector<std::string> To;
+
+ // Prefix for all files in From.
+ std::string FromDir;
+
+ // Prefix for all files in To.
+ std::string ToDir;
+
+ NamelinkModeType NamelinkMode = NamelinkModeNone;
+ bool NoTweak = false;
+ bool UseSourcePermissions = false;
+ cmInstallType Type = cmInstallType();
+ };
+ Files GetFiles(std::string const& config) const;
+
+ bool GetOptional() const { return this->Optional; }
+
+protected:
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent indent) override;
+ using TweakMethod = void (cmInstallTargetGenerator::*)(std::ostream&, Indent,
+ const std::string&,
+ const std::string&);
+ void AddTweak(std::ostream& os, Indent indent, const std::string& config,
+ std::string const& file, TweakMethod tweak);
+ void AddTweak(std::ostream& os, Indent indent, const std::string& config,
+ std::string const& dir, std::vector<std::string> const& files,
+ TweakMethod tweak);
+ std::string GetDestDirPath(std::string const& file);
+ void PreReplacementTweaks(std::ostream& os, Indent indent,
+ const std::string& config,
+ std::string const& file);
+ void PostReplacementTweaks(std::ostream& os, Indent indent,
+ const std::string& config,
+ std::string const& file);
+ void AddInstallNamePatchRule(std::ostream& os, Indent indent,
+ const std::string& config,
+ const std::string& toDestDirPath);
+ void AddChrpathPatchRule(std::ostream& os, Indent indent,
+ const std::string& config,
+ std::string const& toDestDirPath);
+ void AddRPathCheckRule(std::ostream& os, Indent indent,
+ const std::string& config,
+ std::string const& toDestDirPath);
+
+ void AddStripRule(std::ostream& os, Indent indent,
+ const std::string& toDestDirPath);
+ void AddRanlibRule(std::ostream& os, Indent indent,
+ const std::string& toDestDirPath);
+ void AddUniversalInstallRule(std::ostream& os, Indent indent,
+ const std::string& toDestDirPath);
+ void IssueCMP0095Warning(const std::string& unescapedRpath);
+
+ std::string const TargetName;
+ cmGeneratorTarget* Target;
+ std::string const FilePermissions;
+ NamelinkModeType NamelinkMode;
+ bool const ImportLibrary;
+ bool const Optional;
+};
diff --git a/Source/cmInstallTargetsCommand.cxx b/Source/cmInstallTargetsCommand.cxx
new file mode 100644
index 0000000..44f23a5
--- /dev/null
+++ b/Source/cmInstallTargetsCommand.cxx
@@ -0,0 +1,58 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallTargetsCommand.h"
+
+#include <unordered_map>
+#include <utility>
+
+#include "cmExecutionStatus.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmTarget.h"
+
+bool cmInstallTargetsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ // Enable the install target.
+ mf.GetGlobalGenerator()->EnableInstallTarget();
+
+ cmMakefile::cmTargetMap& tgts = mf.GetTargets();
+ auto s = args.begin();
+ ++s;
+ std::string runtime_dir = "/bin";
+ for (; s != args.end(); ++s) {
+ if (*s == "RUNTIME_DIRECTORY") {
+ ++s;
+ if (s == args.end()) {
+ status.SetError("called with RUNTIME_DIRECTORY but no actual "
+ "directory");
+ return false;
+ }
+
+ runtime_dir = *s;
+ } else {
+ auto ti = tgts.find(*s);
+ if (ti != tgts.end()) {
+ ti->second.SetInstallPath(args[0]);
+ ti->second.SetRuntimeInstallPath(runtime_dir);
+ ti->second.SetHaveInstallRule(true);
+ } else {
+ std::string str = "Cannot find target: \"" + *s + "\" to install.";
+ status.SetError(str);
+ return false;
+ }
+ }
+ }
+
+ mf.GetGlobalGenerator()->AddInstallComponent(
+ mf.GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"));
+
+ return true;
+}
diff --git a/Source/cmInstallTargetsCommand.h b/Source/cmInstallTargetsCommand.h
new file mode 100644
index 0000000..716e7ce
--- /dev/null
+++ b/Source/cmInstallTargetsCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmInstallTargetsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmInstallType.h b/Source/cmInstallType.h
new file mode 100644
index 0000000..33fa7a9
--- /dev/null
+++ b/Source/cmInstallType.h
@@ -0,0 +1,17 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+/**
+ * Enumerate types known to file(INSTALL).
+ */
+enum cmInstallType
+{
+ cmInstallType_EXECUTABLE,
+ cmInstallType_STATIC_LIBRARY,
+ cmInstallType_SHARED_LIBRARY,
+ cmInstallType_MODULE_LIBRARY,
+ cmInstallType_FILES,
+ cmInstallType_PROGRAMS,
+ cmInstallType_DIRECTORY
+};
diff --git a/Source/cmInstalledFile.cxx b/Source/cmInstalledFile.cxx
new file mode 100644
index 0000000..32395d1
--- /dev/null
+++ b/Source/cmInstalledFile.cxx
@@ -0,0 +1,107 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstalledFile.h"
+
+#include <utility>
+
+#include "cmGeneratorExpression.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+
+cmInstalledFile::cmInstalledFile() = default;
+
+cmInstalledFile::~cmInstalledFile() = default;
+
+cmInstalledFile::Property::Property() = default;
+
+cmInstalledFile::Property::~Property() = default;
+
+void cmInstalledFile::SetName(cmMakefile* mf, const std::string& name)
+{
+ cmListFileBacktrace backtrace = mf->GetBacktrace();
+ cmGeneratorExpression ge(backtrace);
+
+ this->Name = name;
+ this->NameExpression = ge.Parse(name);
+}
+
+std::string const& cmInstalledFile::GetName() const
+{
+ return this->Name;
+}
+
+cmCompiledGeneratorExpression const& cmInstalledFile::GetNameExpression() const
+{
+ return *(this->NameExpression);
+}
+
+void cmInstalledFile::RemoveProperty(const std::string& prop)
+{
+ this->Properties.erase(prop);
+}
+
+void cmInstalledFile::SetProperty(cmMakefile const* mf,
+ const std::string& prop,
+ const std::string& value)
+{
+ this->RemoveProperty(prop);
+ this->AppendProperty(mf, prop, value);
+}
+
+void cmInstalledFile::AppendProperty(cmMakefile const* mf,
+ const std::string& prop,
+ const std::string& value,
+ bool /*asString*/)
+{
+ cmListFileBacktrace backtrace = mf->GetBacktrace();
+ cmGeneratorExpression ge(backtrace);
+
+ Property& property = this->Properties[prop];
+ property.ValueExpressions.push_back(ge.Parse(value));
+}
+
+bool cmInstalledFile::HasProperty(const std::string& prop) const
+{
+ return this->Properties.find(prop) != this->Properties.end();
+}
+
+bool cmInstalledFile::GetProperty(const std::string& prop,
+ std::string& value) const
+{
+ auto i = this->Properties.find(prop);
+ if (i == this->Properties.end()) {
+ return false;
+ }
+
+ Property const& property = i->second;
+
+ std::string output;
+ std::string separator;
+
+ for (const auto& ve : property.ValueExpressions) {
+ output += separator;
+ output += ve->GetInput();
+ separator = ";";
+ }
+
+ value = output;
+ return true;
+}
+
+bool cmInstalledFile::GetPropertyAsBool(const std::string& prop) const
+{
+ std::string value;
+ bool isSet = this->GetProperty(prop, value);
+ return isSet && cmIsOn(value);
+}
+
+void cmInstalledFile::GetPropertyAsList(const std::string& prop,
+ std::vector<std::string>& list) const
+{
+ std::string value;
+ this->GetProperty(prop, value);
+
+ list.clear();
+ cmExpandList(value, list);
+}
diff --git a/Source/cmInstalledFile.h b/Source/cmInstalledFile.h
new file mode 100644
index 0000000..82474f5
--- /dev/null
+++ b/Source/cmInstalledFile.h
@@ -0,0 +1,77 @@
+/* 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 <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+class cmCompiledGeneratorExpression;
+class cmMakefile;
+
+/** \class cmInstalledFile
+ * \brief Represents a file intended for installation.
+ *
+ * cmInstalledFile represents a file intended for installation.
+ */
+class cmInstalledFile
+{
+public:
+ using CompiledGeneratorExpressionPtrType =
+ std::unique_ptr<cmCompiledGeneratorExpression>;
+
+ using ExpressionVectorType = std::vector<CompiledGeneratorExpressionPtrType>;
+
+ struct Property
+ {
+ Property();
+ ~Property();
+
+ Property(const Property&) = delete;
+ Property& operator=(const Property&) = delete;
+
+ ExpressionVectorType ValueExpressions;
+ };
+
+ using PropertyMapType = std::map<std::string, Property>;
+
+ cmInstalledFile();
+
+ ~cmInstalledFile();
+
+ cmInstalledFile(const cmInstalledFile&) = delete;
+ cmInstalledFile& operator=(const cmInstalledFile&) = delete;
+
+ void RemoveProperty(const std::string& prop);
+
+ void SetProperty(cmMakefile const* mf, const std::string& prop,
+ const std::string& value);
+
+ void AppendProperty(cmMakefile const* mf, const std::string& prop,
+ const std::string& value, bool asString = false);
+
+ bool HasProperty(const std::string& prop) const;
+
+ bool GetProperty(const std::string& prop, std::string& value) const;
+
+ bool GetPropertyAsBool(const std::string& prop) const;
+
+ void GetPropertyAsList(const std::string& prop,
+ std::vector<std::string>& list) const;
+
+ void SetName(cmMakefile* mf, const std::string& name);
+
+ std::string const& GetName() const;
+
+ cmCompiledGeneratorExpression const& GetNameExpression() const;
+
+ PropertyMapType const& GetProperties() const { return this->Properties; }
+
+private:
+ std::string Name;
+ CompiledGeneratorExpressionPtrType NameExpression;
+ PropertyMapType Properties;
+};
diff --git a/Source/cmJSONHelpers.h b/Source/cmJSONHelpers.h
new file mode 100644
index 0000000..6690aef
--- /dev/null
+++ b/Source/cmJSONHelpers.h
@@ -0,0 +1,315 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <algorithm>
+#include <cstddef>
+#include <functional>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+#include <cm/string_view>
+
+#include <cm3p/json/value.h>
+
+template <typename T, typename E>
+using cmJSONHelper = std::function<E(T& out, const Json::Value* value)>;
+
+template <typename T, typename E>
+class cmJSONObjectHelper
+{
+public:
+ cmJSONObjectHelper(E&& success, E&& fail, bool allowExtra = true);
+
+ template <typename U, typename M, typename F>
+ cmJSONObjectHelper& Bind(const cm::string_view& name, M U::*member, F func,
+ bool required = true);
+ template <typename M, typename F>
+ cmJSONObjectHelper& Bind(const cm::string_view& name, std::nullptr_t, F func,
+ bool required = true);
+ template <typename F>
+ cmJSONObjectHelper& Bind(const cm::string_view& name, F func,
+ bool required = true);
+
+ E operator()(T& out, const Json::Value* value) const;
+
+private:
+ // Not a true cmJSONHelper, it just happens to match the signature
+ using MemberFunction = std::function<E(T& out, const Json::Value* value)>;
+ struct Member
+ {
+ cm::string_view Name;
+ MemberFunction Function;
+ bool Required;
+ };
+ std::vector<Member> Members;
+ bool AnyRequired = false;
+ E Success;
+ E Fail;
+ bool AllowExtra;
+
+ cmJSONObjectHelper& BindPrivate(const cm::string_view& name,
+ MemberFunction&& func, bool required);
+};
+
+template <typename T, typename E>
+cmJSONObjectHelper<T, E>::cmJSONObjectHelper(E&& success, E&& fail,
+ bool allowExtra)
+ : Success(std::move(success))
+ , Fail(std::move(fail))
+ , AllowExtra(allowExtra)
+{
+}
+
+template <typename T, typename E>
+template <typename U, typename M, typename F>
+cmJSONObjectHelper<T, E>& cmJSONObjectHelper<T, E>::Bind(
+ const cm::string_view& name, M U::*member, F func, bool required)
+{
+ return this->BindPrivate(
+ name,
+ [func, member](T& out, const Json::Value* value) -> E {
+ return func(out.*member, value);
+ },
+ required);
+}
+
+template <typename T, typename E>
+template <typename M, typename F>
+cmJSONObjectHelper<T, E>& cmJSONObjectHelper<T, E>::Bind(
+ const cm::string_view& name, std::nullptr_t, F func, bool required)
+{
+ return this->BindPrivate(name,
+ [func](T& /*out*/, const Json::Value* value) -> E {
+ M dummy;
+ return func(dummy, value);
+ },
+ required);
+}
+
+template <typename T, typename E>
+template <typename F>
+cmJSONObjectHelper<T, E>& cmJSONObjectHelper<T, E>::Bind(
+ const cm::string_view& name, F func, bool required)
+{
+ return this->BindPrivate(name, MemberFunction(func), required);
+}
+
+template <typename T, typename E>
+cmJSONObjectHelper<T, E>& cmJSONObjectHelper<T, E>::BindPrivate(
+ const cm::string_view& name, MemberFunction&& func, bool required)
+{
+ Member m;
+ m.Name = name;
+ m.Function = std::move(func);
+ m.Required = required;
+ this->Members.push_back(std::move(m));
+ if (required) {
+ this->AnyRequired = true;
+ }
+ return *this;
+}
+
+template <typename T, typename E>
+E cmJSONObjectHelper<T, E>::operator()(T& out, const Json::Value* value) const
+{
+ if (!value && this->AnyRequired) {
+ return this->Fail;
+ }
+ if (value && !value->isObject()) {
+ return this->Fail;
+ }
+ Json::Value::Members extraFields;
+ if (value) {
+ extraFields = value->getMemberNames();
+ }
+
+ for (auto const& m : this->Members) {
+ std::string name(m.Name.data(), m.Name.size());
+ if (value && value->isMember(name)) {
+ E result = m.Function(out, &(*value)[name]);
+ if (result != this->Success) {
+ return result;
+ }
+ extraFields.erase(
+ std::find(extraFields.begin(), extraFields.end(), name));
+ } else if (!m.Required) {
+ E result = m.Function(out, nullptr);
+ if (result != this->Success) {
+ return result;
+ }
+ } else {
+ return this->Fail;
+ }
+ }
+
+ return this->AllowExtra || extraFields.empty() ? this->Success : this->Fail;
+}
+
+template <typename E>
+cmJSONHelper<std::string, E> cmJSONStringHelper(E success, E fail,
+ const std::string& defval = "")
+{
+ return
+ [success, fail, defval](std::string& out, const Json::Value* value) -> E {
+ if (!value) {
+ out = defval;
+ return success;
+ }
+ if (!value->isString()) {
+ return fail;
+ }
+ out = value->asString();
+ return success;
+ };
+}
+
+template <typename E>
+cmJSONHelper<int, E> cmJSONIntHelper(E success, E fail, int defval = 0)
+{
+ return [success, fail, defval](int& out, const Json::Value* value) -> E {
+ if (!value) {
+ out = defval;
+ return success;
+ }
+ if (!value->isInt()) {
+ return fail;
+ }
+ out = value->asInt();
+ return success;
+ };
+}
+
+template <typename E>
+cmJSONHelper<unsigned int, E> cmJSONUIntHelper(E success, E fail,
+ unsigned int defval = 0)
+{
+ return
+ [success, fail, defval](unsigned int& out, const Json::Value* value) -> E {
+ if (!value) {
+ out = defval;
+ return success;
+ }
+ if (!value->isUInt()) {
+ return fail;
+ }
+ out = value->asUInt();
+ return success;
+ };
+}
+
+template <typename E>
+cmJSONHelper<bool, E> cmJSONBoolHelper(E success, E fail, bool defval = false)
+{
+ return [success, fail, defval](bool& out, const Json::Value* value) -> E {
+ if (!value) {
+ out = defval;
+ return success;
+ }
+ if (!value->isBool()) {
+ return fail;
+ }
+ out = value->asBool();
+ return success;
+ };
+}
+
+template <typename T, typename E, typename F, typename Filter>
+cmJSONHelper<std::vector<T>, E> cmJSONVectorFilterHelper(E success, E fail,
+ F func, Filter filter)
+{
+ return [success, fail, func, filter](std::vector<T>& out,
+ const Json::Value* value) -> E {
+ if (!value) {
+ out.clear();
+ return success;
+ }
+ if (!value->isArray()) {
+ return fail;
+ }
+ out.clear();
+ for (auto const& item : *value) {
+ T t;
+ E result = func(t, &item);
+ if (result != success) {
+ return result;
+ }
+ if (!filter(t)) {
+ continue;
+ }
+ out.push_back(std::move(t));
+ }
+ return success;
+ };
+}
+
+template <typename T, typename E, typename F>
+cmJSONHelper<std::vector<T>, E> cmJSONVectorHelper(E success, E fail, F func)
+{
+ return cmJSONVectorFilterHelper<T, E, F>(success, fail, func,
+ [](const T&) { return true; });
+}
+
+template <typename T, typename E, typename F, typename Filter>
+cmJSONHelper<std::map<std::string, T>, E> cmJSONMapFilterHelper(E success,
+ E fail, F func,
+ Filter filter)
+{
+ return [success, fail, func, filter](std::map<std::string, T>& out,
+ const Json::Value* value) -> E {
+ if (!value) {
+ out.clear();
+ return success;
+ }
+ if (!value->isObject()) {
+ return fail;
+ }
+ out.clear();
+ for (auto const& key : value->getMemberNames()) {
+ if (!filter(key)) {
+ continue;
+ }
+ T t;
+ E result = func(t, &(*value)[key]);
+ if (result != success) {
+ return result;
+ }
+ out[key] = std::move(t);
+ }
+ return success;
+ };
+}
+
+template <typename T, typename E, typename F>
+cmJSONHelper<std::map<std::string, T>, E> cmJSONMapHelper(E success, E fail,
+ F func)
+{
+ return cmJSONMapFilterHelper<T, E, F>(
+ success, fail, func, [](const std::string&) { return true; });
+}
+
+template <typename T, typename E, typename F>
+cmJSONHelper<cm::optional<T>, E> cmJSONOptionalHelper(E success, F func)
+{
+ return [success, func](cm::optional<T>& out, const Json::Value* value) -> E {
+ if (!value) {
+ out.reset();
+ return success;
+ }
+ out.emplace();
+ return func(*out, value);
+ };
+}
+
+template <typename T, typename E, typename F>
+cmJSONHelper<T, E> cmJSONRequiredHelper(E fail, F func)
+{
+ return [fail, func](T& out, const Json::Value* value) -> E {
+ if (!value) {
+ return fail;
+ }
+ return func(out, value);
+ };
+}
diff --git a/Source/cmLDConfigLDConfigTool.cxx b/Source/cmLDConfigLDConfigTool.cxx
new file mode 100644
index 0000000..cce6178
--- /dev/null
+++ b/Source/cmLDConfigLDConfigTool.cxx
@@ -0,0 +1,71 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmLDConfigLDConfigTool.h"
+
+#include <istream>
+#include <string>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmMakefile.h"
+#include "cmRuntimeDependencyArchive.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmUVProcessChain.h"
+
+cmLDConfigLDConfigTool::cmLDConfigLDConfigTool(
+ cmRuntimeDependencyArchive* archive)
+ : cmLDConfigTool(archive)
+{
+}
+
+bool cmLDConfigLDConfigTool::GetLDConfigPaths(std::vector<std::string>& paths)
+{
+ std::string ldConfigPath =
+ this->Archive->GetMakefile()->GetSafeDefinition("CMAKE_LDCONFIG_COMMAND");
+ if (ldConfigPath.empty()) {
+ ldConfigPath = cmSystemTools::FindProgram(
+ "ldconfig", { "/sbin", "/usr/sbin", "/usr/local/sbin" });
+ if (ldConfigPath.empty()) {
+ this->Archive->SetError("Could not find ldconfig");
+ return false;
+ }
+ }
+
+ std::vector<std::string> ldConfigCommand = cmExpandedList(ldConfigPath);
+ ldConfigCommand.emplace_back("-v");
+ ldConfigCommand.emplace_back("-N"); // Don't rebuild the cache.
+ ldConfigCommand.emplace_back("-X"); // Don't update links.
+
+ cmUVProcessChainBuilder builder;
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
+ .AddCommand(ldConfigCommand);
+ auto process = builder.Start();
+ if (!process.Valid()) {
+ this->Archive->SetError("Failed to start ldconfig process");
+ return false;
+ }
+
+ std::string line;
+ static const cmsys::RegularExpression regex("^([^\t:]*):");
+ while (std::getline(*process.OutputStream(), line)) {
+ cmsys::RegularExpressionMatch match;
+ if (regex.find(line.c_str(), match)) {
+ paths.push_back(match.match(1));
+ }
+ }
+
+ if (!process.Wait()) {
+ this->Archive->SetError("Failed to wait on ldconfig process");
+ return false;
+ }
+ auto status = process.GetStatus();
+ if (!status[0] || status[0]->ExitStatus != 0) {
+ this->Archive->SetError("Failed to run ldconfig");
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmLDConfigLDConfigTool.h b/Source/cmLDConfigLDConfigTool.h
new file mode 100644
index 0000000..eeb86dd
--- /dev/null
+++ b/Source/cmLDConfigLDConfigTool.h
@@ -0,0 +1,19 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "cmLDConfigTool.h"
+
+class cmRuntimeDependencyArchive;
+
+class cmLDConfigLDConfigTool : public cmLDConfigTool
+{
+public:
+ cmLDConfigLDConfigTool(cmRuntimeDependencyArchive* archive);
+
+ bool GetLDConfigPaths(std::vector<std::string>& paths) override;
+};
diff --git a/Source/cmLDConfigTool.cxx b/Source/cmLDConfigTool.cxx
new file mode 100644
index 0000000..8d5d563
--- /dev/null
+++ b/Source/cmLDConfigTool.cxx
@@ -0,0 +1,9 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmLDConfigTool.h"
+
+cmLDConfigTool::cmLDConfigTool(cmRuntimeDependencyArchive* archive)
+ : Archive(archive)
+{
+}
diff --git a/Source/cmLDConfigTool.h b/Source/cmLDConfigTool.h
new file mode 100644
index 0000000..3116f80
--- /dev/null
+++ b/Source/cmLDConfigTool.h
@@ -0,0 +1,21 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmLDConfigTool
+{
+public:
+ cmLDConfigTool(cmRuntimeDependencyArchive* archive);
+ virtual ~cmLDConfigTool() = default;
+
+ virtual bool GetLDConfigPaths(std::vector<std::string>& paths) = 0;
+
+protected:
+ cmRuntimeDependencyArchive* Archive;
+};
diff --git a/Source/cmLinkDirectoriesCommand.cxx b/Source/cmLinkDirectoriesCommand.cxx
new file mode 100644
index 0000000..2914046
--- /dev/null
+++ b/Source/cmLinkDirectoriesCommand.cxx
@@ -0,0 +1,84 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmLinkDirectoriesCommand.h"
+
+#include <sstream>
+
+#include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+static void AddLinkDir(cmMakefile& mf, std::string const& dir,
+ std::vector<std::string>& directories);
+
+bool cmLinkDirectoriesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ return true;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ bool before = mf.IsOn("CMAKE_LINK_DIRECTORIES_BEFORE");
+
+ auto i = args.cbegin();
+ if ((*i) == "BEFORE") {
+ before = true;
+ ++i;
+ } else if ((*i) == "AFTER") {
+ before = false;
+ ++i;
+ }
+
+ std::vector<std::string> directories;
+ for (; i != args.cend(); ++i) {
+ AddLinkDir(mf, *i, directories);
+ }
+
+ mf.AddLinkDirectory(cmJoin(directories, ";"), before);
+
+ return true;
+}
+
+static void AddLinkDir(cmMakefile& mf, std::string const& dir,
+ std::vector<std::string>& directories)
+{
+ std::string unixPath = dir;
+ cmSystemTools::ConvertToUnixSlashes(unixPath);
+ if (!cmSystemTools::FileIsFullPath(unixPath) &&
+ !cmGeneratorExpression::StartsWithGeneratorExpression(unixPath)) {
+ bool convertToAbsolute = false;
+ std::ostringstream e;
+ /* clang-format off */
+ e << "This command specifies the relative path\n"
+ << " " << unixPath << "\n"
+ << "as a link directory.\n";
+ /* clang-format on */
+ switch (mf.GetPolicyStatus(cmPolicies::CMP0015)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0015);
+ mf.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+ break;
+ case cmPolicies::OLD:
+ // OLD behavior does not convert
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0015);
+ mf.IssueMessage(MessageType::FATAL_ERROR, e.str());
+ CM_FALLTHROUGH;
+ case cmPolicies::NEW:
+ // NEW behavior converts
+ convertToAbsolute = true;
+ break;
+ }
+ if (convertToAbsolute) {
+ unixPath = cmStrCat(mf.GetCurrentSourceDirectory(), '/', unixPath);
+ }
+ }
+ directories.push_back(unixPath);
+}
diff --git a/Source/cmLinkDirectoriesCommand.h b/Source/cmLinkDirectoriesCommand.h
new file mode 100644
index 0000000..2a3499d
--- /dev/null
+++ b/Source/cmLinkDirectoriesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmLinkDirectoriesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmLinkItem.cxx b/Source/cmLinkItem.cxx
new file mode 100644
index 0000000..4e50d70
--- /dev/null
+++ b/Source/cmLinkItem.cxx
@@ -0,0 +1,71 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmLinkItem.h"
+
+#include <utility> // IWYU pragma: keep
+
+#include "cmGeneratorTarget.h"
+
+cmLinkItem::cmLinkItem() = default;
+
+cmLinkItem::cmLinkItem(std::string n, bool c, cmListFileBacktrace bt)
+ : String(std::move(n))
+ , Cross(c)
+ , Backtrace(std::move(bt))
+{
+}
+
+cmLinkItem::cmLinkItem(cmGeneratorTarget const* t, bool c,
+ cmListFileBacktrace bt)
+ : Target(t)
+ , Cross(c)
+ , Backtrace(std::move(bt))
+{
+}
+
+std::string const& cmLinkItem::AsStr() const
+{
+ return this->Target ? this->Target->GetName() : this->String;
+}
+
+bool operator<(cmLinkItem const& l, cmLinkItem const& r)
+{
+ // Order among targets.
+ if (l.Target && r.Target) {
+ return l.Target < r.Target;
+ }
+ // Order targets before strings.
+ if (l.Target) {
+ return true;
+ }
+ if (r.Target) {
+ return false;
+ }
+ // Order among strings.
+ if (l.String < r.String) {
+ return true;
+ }
+ // Order among cross-config.
+ return l.Cross < r.Cross;
+}
+
+bool operator==(cmLinkItem const& l, cmLinkItem const& r)
+{
+ return l.Target == r.Target && l.String == r.String && l.Cross == r.Cross;
+}
+
+std::ostream& operator<<(std::ostream& os, cmLinkItem const& item)
+{
+ return os << item.AsStr();
+}
+
+cmLinkImplItem::cmLinkImplItem()
+ : cmLinkItem()
+{
+}
+
+cmLinkImplItem::cmLinkImplItem(cmLinkItem item, bool fromGenex)
+ : cmLinkItem(std::move(item))
+ , FromGenex(fromGenex)
+{
+}
diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h
new file mode 100644
index 0000000..5a90e7e
--- /dev/null
+++ b/Source/cmLinkItem.h
@@ -0,0 +1,141 @@
+/* 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 <map>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include <cmext/algorithm>
+
+#include "cmListFileCache.h"
+#include "cmSystemTools.h"
+#include "cmTargetLinkLibraryType.h"
+
+class cmGeneratorTarget;
+
+// Basic information about each link item.
+class cmLinkItem
+{
+ std::string String;
+
+public:
+ cmLinkItem();
+ cmLinkItem(std::string s, bool c, cmListFileBacktrace bt);
+ cmLinkItem(cmGeneratorTarget const* t, bool c, cmListFileBacktrace bt);
+ std::string const& AsStr() const;
+ cmGeneratorTarget const* Target = nullptr;
+ bool Cross = false;
+ cmListFileBacktrace Backtrace;
+ friend bool operator<(cmLinkItem const& l, cmLinkItem const& r);
+ friend bool operator==(cmLinkItem const& l, cmLinkItem const& r);
+ friend std::ostream& operator<<(std::ostream& os, cmLinkItem const& item);
+};
+
+class cmLinkImplItem : public cmLinkItem
+{
+public:
+ cmLinkImplItem();
+ cmLinkImplItem(cmLinkItem item, bool fromGenex);
+ bool FromGenex = false;
+};
+
+/** The link implementation specifies the direct library
+ dependencies needed by the object files of the target. */
+struct cmLinkImplementationLibraries
+{
+ // Libraries linked directly in this configuration.
+ std::vector<cmLinkImplItem> Libraries;
+
+ // Libraries linked directly in other configurations.
+ // Needed only for OLD behavior of CMP0003.
+ std::vector<cmLinkItem> WrongConfigLibraries;
+
+ // Whether the list depends on a genex referencing the configuration.
+ bool HadContextSensitiveCondition = false;
+};
+
+struct cmLinkInterfaceLibraries
+{
+ // Libraries listed in the interface.
+ std::vector<cmLinkItem> Libraries;
+
+ // Whether the list depends on a genex referencing the head target.
+ bool HadHeadSensitiveCondition = false;
+
+ // Whether the list depends on a genex referencing the configuration.
+ bool HadContextSensitiveCondition = false;
+};
+
+struct cmLinkInterface : public cmLinkInterfaceLibraries
+{
+ // Languages whose runtime libraries must be linked.
+ std::vector<std::string> Languages;
+
+ // Shared library dependencies needed for linking on some platforms.
+ std::vector<cmLinkItem> SharedDeps;
+
+ // Number of repetitions of a strongly connected component of two
+ // or more static libraries.
+ unsigned int Multiplicity = 0;
+
+ // Libraries listed for other configurations.
+ // Needed only for OLD behavior of CMP0003.
+ std::vector<cmLinkItem> WrongConfigLibraries;
+
+ bool ImplementationIsInterface = false;
+
+ // Whether the list depends on a link language genex.
+ bool HadLinkLanguageSensitiveCondition = false;
+};
+
+struct cmOptionalLinkInterface : public cmLinkInterface
+{
+ bool LibrariesDone = false;
+ bool AllDone = false;
+ bool Exists = false;
+ bool Explicit = false;
+};
+
+struct cmHeadToLinkInterfaceMap
+ : public std::map<cmGeneratorTarget const*, cmOptionalLinkInterface>
+{
+};
+
+struct cmLinkImplementation : public cmLinkImplementationLibraries
+{
+ // Languages whose runtime libraries must be linked.
+ std::vector<std::string> Languages;
+
+ // Whether the list depends on a link language genex.
+ bool HadLinkLanguageSensitiveCondition = false;
+};
+
+// Cache link implementation computation from each configuration.
+struct cmOptionalLinkImplementation : public cmLinkImplementation
+{
+ bool LibrariesDone = false;
+ bool LanguagesDone = false;
+ bool HadHeadSensitiveCondition = false;
+};
+
+/** Compute the link type to use for the given configuration. */
+inline cmTargetLinkLibraryType CMP0003_ComputeLinkType(
+ const std::string& config, std::vector<std::string> const& debugConfigs)
+{
+ // No configuration is always optimized.
+ if (config.empty()) {
+ return OPTIMIZED_LibraryType;
+ }
+
+ // Check if any entry in the list matches this configuration.
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ if (cm::contains(debugConfigs, configUpper)) {
+ return DEBUG_LibraryType;
+ }
+ // The current configuration is not a debug configuration.
+ return OPTIMIZED_LibraryType;
+}
diff --git a/Source/cmLinkItemGraphVisitor.cxx b/Source/cmLinkItemGraphVisitor.cxx
new file mode 100644
index 0000000..7ad8690
--- /dev/null
+++ b/Source/cmLinkItemGraphVisitor.cxx
@@ -0,0 +1,140 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmLinkItemGraphVisitor.h"
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "cmGeneratorTarget.h"
+#include "cmLinkItem.h"
+#include "cmMakefile.h"
+
+void cmLinkItemGraphVisitor::VisitItem(cmLinkItem const& item)
+{
+ if (this->ItemVisited(item)) {
+ return;
+ }
+
+ this->OnItem(item);
+
+ this->VisitLinks(item, item);
+}
+
+void cmLinkItemGraphVisitor::VisitLinks(cmLinkItem const& item,
+ cmLinkItem const& rootItem)
+{
+ if (item.Target == nullptr) {
+ return;
+ }
+
+ for (auto const& config : item.Target->Makefile->GetGeneratorConfigs(
+ cmMakefile::IncludeEmptyConfig)) {
+ this->VisitLinks(item, rootItem, config);
+ }
+}
+
+void cmLinkItemGraphVisitor::VisitLinks(cmLinkItem const& item,
+ cmLinkItem const& rootItem,
+ std::string const& config)
+{
+ auto const& target = *item.Target;
+
+ DependencyMap dependencies;
+ cmLinkItemGraphVisitor::GetDependencies(target, config, dependencies);
+
+ for (auto const& d : dependencies) {
+ auto const& dependency = d.second;
+ auto const& dependencyType = dependency.first;
+ auto const& dependee = dependency.second;
+ this->VisitItem(dependee);
+
+ if (this->LinkVisited(item, dependee)) {
+ continue;
+ }
+
+ this->OnDirectLink(item, dependee, dependencyType);
+
+ if (rootItem.AsStr() != item.AsStr()) {
+ this->OnIndirectLink(rootItem, dependee);
+ }
+
+ // Visit all the direct and indirect links.
+ this->VisitLinks(dependee, dependee);
+ this->VisitLinks(dependee, item);
+ this->VisitLinks(dependee, rootItem);
+ }
+}
+
+bool cmLinkItemGraphVisitor::ItemVisited(cmLinkItem const& item)
+{
+ auto& collection = this->VisitedItems;
+
+ bool const visited = collection.find(item.AsStr()) != collection.cend();
+
+ if (!visited) {
+ collection.insert(item.AsStr());
+ }
+
+ return visited;
+}
+
+bool cmLinkItemGraphVisitor::LinkVisited(cmLinkItem const& depender,
+ cmLinkItem const& dependee)
+{
+ auto const link = std::make_pair<>(depender.AsStr(), dependee.AsStr());
+
+ bool const linkVisited =
+ this->VisitedLinks.find(link) != this->VisitedLinks.cend();
+
+ if (!linkVisited) {
+ this->VisitedLinks.insert(link);
+ }
+
+ return linkVisited;
+}
+
+void cmLinkItemGraphVisitor::GetDependencies(cmGeneratorTarget const& target,
+ std::string const& config,
+ DependencyMap& dependencies)
+{
+ const auto* implementationLibraries =
+ target.GetLinkImplementationLibraries(config);
+ if (implementationLibraries != nullptr) {
+ for (auto const& lib : implementationLibraries->Libraries) {
+ auto const& name = lib.AsStr();
+ dependencies[name] = Dependency(DependencyType::LinkPrivate, lib);
+ }
+ }
+
+ const auto* interfaceLibraries =
+ target.GetLinkInterfaceLibraries(config, &target, true);
+ if (interfaceLibraries != nullptr) {
+ for (auto const& lib : interfaceLibraries->Libraries) {
+ auto const& name = lib.AsStr();
+ if (dependencies.find(name) != dependencies.cend()) {
+ dependencies[name] = Dependency(DependencyType::LinkPublic, lib);
+ } else {
+ dependencies[name] = Dependency(DependencyType::LinkInterface, lib);
+ }
+ }
+ }
+
+ std::vector<cmGeneratorTarget*> objectLibraries;
+ target.GetObjectLibrariesCMP0026(objectLibraries);
+ for (auto const& lib : objectLibraries) {
+ auto const& name = lib->GetName();
+ if (dependencies.find(name) == dependencies.cend()) {
+ auto objectItem = cmLinkItem(lib, false, lib->GetBacktrace());
+ dependencies[name] = Dependency(DependencyType::Object, objectItem);
+ }
+ }
+
+ auto const& utilityItems = target.GetUtilityItems();
+ for (auto const& item : utilityItems) {
+ auto const& name = item.AsStr();
+ if (dependencies.find(name) == dependencies.cend()) {
+ dependencies[name] = Dependency(DependencyType::Utility, item);
+ }
+ }
+}
diff --git a/Source/cmLinkItemGraphVisitor.h b/Source/cmLinkItemGraphVisitor.h
new file mode 100644
index 0000000..0d6676a
--- /dev/null
+++ b/Source/cmLinkItemGraphVisitor.h
@@ -0,0 +1,72 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+
+#include "cmLinkItem.h"
+
+class cmGeneratorTarget;
+
+/** \class cmLinkItemGraphVisitor
+ * \brief Visits a graph of linked items.
+ *
+ * Allows to visit items and dependency links (direct and indirect) between
+ * those items.
+ * This abstract class takes care of the graph traversal, making sure that:
+ * - it terminates even in the presence of cycles;
+ * - it visits every object once (and only once);
+ * - it visits the objects in the same order every time.
+ *
+ * Children classes only have to implement OnItem() etc. to handle whatever
+ * logic they care about.
+ */
+class cmLinkItemGraphVisitor
+{
+public:
+ virtual ~cmLinkItemGraphVisitor() = default;
+
+ virtual void VisitGraph(std::string const& name) = 0;
+
+ void VisitItem(cmLinkItem const& item);
+
+protected:
+ enum class DependencyType
+ {
+ LinkInterface,
+ LinkPublic,
+ LinkPrivate,
+ Object,
+ Utility
+ };
+
+ virtual void OnItem(cmLinkItem const& item) = 0;
+
+ virtual void OnDirectLink(cmLinkItem const& depender,
+ cmLinkItem const& dependee, DependencyType dt) = 0;
+
+ virtual void OnIndirectLink(cmLinkItem const& depender,
+ cmLinkItem const& dependee) = 0;
+
+private:
+ std::set<std::string> VisitedItems;
+
+ std::set<std::pair<std::string, std::string>> VisitedLinks;
+
+ void VisitLinks(cmLinkItem const& item, cmLinkItem const& rootItem);
+ void VisitLinks(cmLinkItem const& item, cmLinkItem const& rootItem,
+ std::string const& config);
+
+ using Dependency = std::pair<DependencyType, cmLinkItem>;
+ using DependencyMap = std::map<std::string, Dependency>;
+
+ bool ItemVisited(cmLinkItem const& item);
+ bool LinkVisited(cmLinkItem const& depender, cmLinkItem const& dependee);
+
+ static void GetDependencies(cmGeneratorTarget const& target,
+ std::string const& config,
+ DependencyMap& dependencies);
+};
diff --git a/Source/cmLinkLibrariesCommand.cxx b/Source/cmLinkLibrariesCommand.cxx
new file mode 100644
index 0000000..2b8f836
--- /dev/null
+++ b/Source/cmLinkLibrariesCommand.cxx
@@ -0,0 +1,39 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmLinkLibrariesCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+
+bool cmLinkLibrariesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ return true;
+ }
+ cmMakefile& mf = status.GetMakefile();
+ // add libraries, note that there is an optional prefix
+ // of debug and optimized than can be used
+ for (auto i = args.begin(); i != args.end(); ++i) {
+ if (*i == "debug") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("The \"debug\" argument must be followed by "
+ "a library");
+ return false;
+ }
+ mf.AppendProperty("LINK_LIBRARIES", "debug");
+ } else if (*i == "optimized") {
+ ++i;
+ if (i == args.end()) {
+ status.SetError("The \"optimized\" argument must be followed by "
+ "a library");
+ return false;
+ }
+ mf.AppendProperty("LINK_LIBRARIES", "optimized");
+ }
+ mf.AppendProperty("LINK_LIBRARIES", *i);
+ }
+
+ return true;
+}
diff --git a/Source/cmLinkLibrariesCommand.h b/Source/cmLinkLibrariesCommand.h
new file mode 100644
index 0000000..27c410f
--- /dev/null
+++ b/Source/cmLinkLibrariesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmLinkLibrariesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmLinkLineComputer.cxx b/Source/cmLinkLineComputer.cxx
new file mode 100644
index 0000000..480c005
--- /dev/null
+++ b/Source/cmLinkLineComputer.cxx
@@ -0,0 +1,273 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmLinkLineComputer.h"
+
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include "cmComputeLinkInformation.h"
+#include "cmGeneratorTarget.h"
+#include "cmListFileCache.h"
+#include "cmOutputConverter.h"
+#include "cmStateDirectory.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmLinkLineComputer::cmLinkLineComputer(cmOutputConverter* outputConverter,
+ cmStateDirectory const& stateDir)
+ : StateDir(stateDir)
+ , OutputConverter(outputConverter)
+ , ForResponse(false)
+ , UseWatcomQuote(false)
+ , UseNinjaMulti(false)
+ , Relink(false)
+{
+}
+
+cmLinkLineComputer::~cmLinkLineComputer() = default;
+
+void cmLinkLineComputer::SetUseWatcomQuote(bool useWatcomQuote)
+{
+ this->UseWatcomQuote = useWatcomQuote;
+}
+
+void cmLinkLineComputer::SetUseNinjaMulti(bool useNinjaMulti)
+{
+ this->UseNinjaMulti = useNinjaMulti;
+}
+
+void cmLinkLineComputer::SetForResponse(bool forResponse)
+{
+ this->ForResponse = forResponse;
+}
+
+void cmLinkLineComputer::SetRelink(bool relink)
+{
+ this->Relink = relink;
+}
+
+std::string cmLinkLineComputer::ConvertToLinkReference(
+ std::string const& lib) const
+{
+ std::string relLib = lib;
+
+ if (this->StateDir.ContainsBoth(this->StateDir.GetCurrentBinary(), lib)) {
+ relLib = cmSystemTools::ForceToRelativePath(
+ this->StateDir.GetCurrentBinary(), lib);
+ }
+ return relLib;
+}
+
+std::string cmLinkLineComputer::ComputeLinkLibs(cmComputeLinkInformation& cli)
+{
+ std::string linkLibs;
+ std::vector<BT<std::string>> linkLibsList;
+ this->ComputeLinkLibs(cli, linkLibsList);
+ cli.AppendValues(linkLibs, linkLibsList);
+ return linkLibs;
+}
+
+void cmLinkLineComputer::ComputeLinkLibs(
+ cmComputeLinkInformation& cli, std::vector<BT<std::string>>& linkLibraries)
+{
+ using ItemVector = cmComputeLinkInformation::ItemVector;
+ ItemVector const& items = cli.GetItems();
+ for (auto const& item : items) {
+ if (item.Target &&
+ item.Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ continue;
+ }
+
+ BT<std::string> linkLib;
+ if (item.IsPath) {
+ linkLib.Value += cli.GetLibLinkFileFlag();
+ linkLib.Value += this->ConvertToOutputFormat(
+ this->ConvertToLinkReference(item.Value.Value));
+ linkLib.Backtrace = item.Value.Backtrace;
+ } else {
+ linkLib = item.Value;
+ }
+ linkLib.Value += " ";
+
+ linkLibraries.emplace_back(linkLib);
+ }
+}
+
+std::string cmLinkLineComputer::ConvertToOutputFormat(std::string const& input)
+{
+ cmOutputConverter::OutputFormat shellFormat = cmOutputConverter::SHELL;
+ if (this->ForResponse) {
+ shellFormat = cmOutputConverter::RESPONSE;
+ } else if (this->UseWatcomQuote) {
+ shellFormat = cmOutputConverter::WATCOMQUOTE;
+ } else if (this->UseNinjaMulti) {
+ shellFormat = cmOutputConverter::NINJAMULTI;
+ }
+
+ return this->OutputConverter->ConvertToOutputFormat(input, shellFormat);
+}
+
+std::string cmLinkLineComputer::ConvertToOutputForExisting(
+ std::string const& input)
+{
+ cmOutputConverter::OutputFormat shellFormat = cmOutputConverter::SHELL;
+ if (this->ForResponse) {
+ shellFormat = cmOutputConverter::RESPONSE;
+ } else if (this->UseWatcomQuote) {
+ shellFormat = cmOutputConverter::WATCOMQUOTE;
+ } else if (this->UseNinjaMulti) {
+ shellFormat = cmOutputConverter::NINJAMULTI;
+ }
+
+ return this->OutputConverter->ConvertToOutputForExisting(input, shellFormat);
+}
+
+std::string cmLinkLineComputer::ComputeLinkPath(
+ cmComputeLinkInformation& cli, std::string const& libPathFlag,
+ std::string const& libPathTerminator)
+{
+ std::string linkPath;
+ std::vector<BT<std::string>> linkPathList;
+ this->ComputeLinkPath(cli, libPathFlag, libPathTerminator, linkPathList);
+ cli.AppendValues(linkPath, linkPathList);
+ return linkPath;
+}
+
+void cmLinkLineComputer::ComputeLinkPath(
+ cmComputeLinkInformation& cli, std::string const& libPathFlag,
+ std::string const& libPathTerminator, std::vector<BT<std::string>>& linkPath)
+{
+ if (cli.GetLinkLanguage() == "Swift") {
+ std::string linkPathNoBT;
+
+ for (const cmComputeLinkInformation::Item& item : cli.GetItems()) {
+ const cmGeneratorTarget* target = item.Target;
+ if (!target) {
+ continue;
+ }
+
+ if (target->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ target->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ cmStateEnums::ArtifactType type = cmStateEnums::RuntimeBinaryArtifact;
+ if (target->HasImportLibrary(cli.GetConfig())) {
+ type = cmStateEnums::ImportLibraryArtifact;
+ }
+
+ linkPathNoBT +=
+ cmStrCat(" ", libPathFlag,
+ this->ConvertToOutputForExisting(
+ item.Target->GetDirectory(cli.GetConfig(), type)),
+ libPathTerminator, " ");
+ }
+ }
+
+ if (!linkPathNoBT.empty()) {
+ linkPath.emplace_back(std::move(linkPathNoBT));
+ }
+ }
+
+ for (BT<std::string> libDir : cli.GetDirectoriesWithBacktraces()) {
+ libDir.Value = cmStrCat(" ", libPathFlag,
+ this->ConvertToOutputForExisting(libDir.Value),
+ libPathTerminator, " ");
+ linkPath.emplace_back(libDir);
+ }
+}
+
+std::string cmLinkLineComputer::ComputeRPath(cmComputeLinkInformation& cli)
+{
+ std::string rpath;
+ // Check what kind of rpath flags to use.
+ if (cli.GetRuntimeSep().empty()) {
+ // Each rpath entry gets its own option ("-R a -R b -R c")
+ std::vector<std::string> runtimeDirs;
+ cli.GetRPath(runtimeDirs, this->Relink);
+
+ for (std::string const& rd : runtimeDirs) {
+ rpath += cli.GetRuntimeFlag();
+ rpath += this->ConvertToOutputFormat(rd);
+ rpath += " ";
+ }
+ } else {
+ // All rpath entries are combined ("-Wl,-rpath,a:b:c").
+ std::string rpathString = cli.GetRPathString(this->Relink);
+
+ // Store the rpath option in the stream.
+ if (!rpathString.empty()) {
+ rpath += cli.GetRuntimeFlag();
+ rpath +=
+ this->OutputConverter->EscapeForShell(rpathString, !this->ForResponse);
+ rpath += " ";
+ }
+ }
+ return rpath;
+}
+
+std::string cmLinkLineComputer::ComputeFrameworkPath(
+ cmComputeLinkInformation& cli, std::string const& fwSearchFlag)
+{
+ std::string frameworkPath;
+ if (!fwSearchFlag.empty()) {
+ std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths();
+ for (std::string const& fd : fwDirs) {
+ frameworkPath += fwSearchFlag;
+ frameworkPath += this->ConvertToOutputFormat(fd);
+ frameworkPath += " ";
+ }
+ }
+ return frameworkPath;
+}
+
+std::string cmLinkLineComputer::ComputeLinkLibraries(
+ cmComputeLinkInformation& cli, std::string const& stdLibString)
+{
+ std::string linkLibraries;
+ std::vector<BT<std::string>> linkLibrariesList;
+ this->ComputeLinkLibraries(cli, stdLibString, linkLibrariesList);
+ cli.AppendValues(linkLibraries, linkLibrariesList);
+ return linkLibraries;
+}
+
+void cmLinkLineComputer::ComputeLinkLibraries(
+ cmComputeLinkInformation& cli, std::string const& stdLibString,
+ std::vector<BT<std::string>>& linkLibraries)
+{
+ std::ostringstream rpathOut;
+ rpathOut << this->ComputeRPath(cli);
+
+ std::string rpath = rpathOut.str();
+ if (!rpath.empty()) {
+ linkLibraries.emplace_back(std::move(rpath));
+ }
+
+ // Write the library flags to the build rule.
+ this->ComputeLinkLibs(cli, linkLibraries);
+
+ // Add the linker runtime search path if any.
+ std::ostringstream fout;
+ std::string rpath_link = cli.GetRPathLinkString();
+ if (!cli.GetRPathLinkFlag().empty() && !rpath_link.empty()) {
+ fout << cli.GetRPathLinkFlag();
+ fout << this->OutputConverter->EscapeForShell(rpath_link,
+ !this->ForResponse);
+ fout << " ";
+ }
+
+ if (!stdLibString.empty()) {
+ fout << stdLibString << " ";
+ }
+
+ std::string remainingLibs = fout.str();
+ if (!remainingLibs.empty()) {
+ linkLibraries.emplace_back(remainingLibs);
+ }
+}
+
+std::string cmLinkLineComputer::GetLinkerLanguage(cmGeneratorTarget* target,
+ std::string const& config)
+{
+ return target->GetLinkerLanguage(config);
+}
diff --git a/Source/cmLinkLineComputer.h b/Source/cmLinkLineComputer.h
new file mode 100644
index 0000000..a1dafc4
--- /dev/null
+++ b/Source/cmLinkLineComputer.h
@@ -0,0 +1,74 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmStateDirectory.h"
+
+class cmComputeLinkInformation;
+class cmGeneratorTarget;
+class cmOutputConverter;
+template <typename T>
+class BT;
+
+class cmLinkLineComputer
+{
+public:
+ cmLinkLineComputer(cmOutputConverter* outputConverter,
+ cmStateDirectory const& stateDir);
+ virtual ~cmLinkLineComputer();
+
+ cmLinkLineComputer(cmLinkLineComputer const&) = delete;
+ cmLinkLineComputer& operator=(cmLinkLineComputer const&) = delete;
+
+ void SetUseWatcomQuote(bool useWatcomQuote);
+ void SetUseNinjaMulti(bool useNinjaMulti);
+ void SetForResponse(bool forResponse);
+ void SetRelink(bool relink);
+
+ virtual std::string ConvertToLinkReference(std::string const& input) const;
+
+ std::string ComputeLinkPath(cmComputeLinkInformation& cli,
+ std::string const& libPathFlag,
+ std::string const& libPathTerminator);
+
+ void ComputeLinkPath(cmComputeLinkInformation& cli,
+ std::string const& libPathFlag,
+ std::string const& libPathTerminator,
+ std::vector<BT<std::string>>& linkPath);
+
+ std::string ComputeFrameworkPath(cmComputeLinkInformation& cli,
+ std::string const& fwSearchFlag);
+
+ std::string ComputeLinkLibraries(cmComputeLinkInformation& cli,
+ std::string const& stdLibString);
+
+ virtual void ComputeLinkLibraries(
+ cmComputeLinkInformation& cli, std::string const& stdLibString,
+ std::vector<BT<std::string>>& linkLibraries);
+
+ virtual std::string GetLinkerLanguage(cmGeneratorTarget* target,
+ std::string const& config);
+
+protected:
+ std::string ComputeLinkLibs(cmComputeLinkInformation& cli);
+ void ComputeLinkLibs(cmComputeLinkInformation& cli,
+ std::vector<BT<std::string>>& linkLibraries);
+ std::string ComputeRPath(cmComputeLinkInformation& cli);
+
+ std::string ConvertToOutputFormat(std::string const& input);
+ std::string ConvertToOutputForExisting(std::string const& input);
+
+ cmStateDirectory StateDir;
+ cmOutputConverter* OutputConverter;
+
+ bool ForResponse;
+ bool UseWatcomQuote;
+ bool UseNinjaMulti;
+ bool Relink;
+};
diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx
new file mode 100644
index 0000000..9cae926
--- /dev/null
+++ b/Source/cmLinkLineDeviceComputer.cxx
@@ -0,0 +1,216 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmLinkLineDeviceComputer.h"
+
+#include <algorithm>
+#include <set>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmComputeLinkInformation.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLinkItem.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+
+class cmOutputConverter;
+
+cmLinkLineDeviceComputer::cmLinkLineDeviceComputer(
+ cmOutputConverter* outputConverter, cmStateDirectory const& stateDir)
+ : cmLinkLineComputer(outputConverter, stateDir)
+{
+}
+
+cmLinkLineDeviceComputer::~cmLinkLineDeviceComputer() = default;
+
+static bool cmLinkItemValidForDevice(std::string const& item)
+{
+ // Valid items are:
+ // * Non-flags (does not start in '-')
+ // * Specific flags --library, --library-path, -l, -L
+ // For example:
+ // * 'cublas_device' => pass-along
+ // * '--library pthread' => pass-along
+ // * '-lpthread' => pass-along
+ // * '-pthread' => drop
+ // * '-a' => drop
+ // * '-framework Name' (as one string) => drop
+ return (!cmHasLiteralPrefix(item, "-") || //
+ cmHasLiteralPrefix(item, "-l") || //
+ cmHasLiteralPrefix(item, "-L") || //
+ cmHasLiteralPrefix(item, "--library"));
+}
+
+bool cmLinkLineDeviceComputer::ComputeRequiresDeviceLinking(
+ cmComputeLinkInformation& cli)
+{
+ // Determine if this item might requires device linking.
+ // For this we only consider targets
+ using ItemVector = cmComputeLinkInformation::ItemVector;
+ ItemVector const& items = cli.GetItems();
+ std::string config = cli.GetConfig();
+ return std::any_of(
+ items.begin(), items.end(),
+ [](cmComputeLinkInformation::Item const& item) -> bool {
+ return item.Target &&
+ item.Target->GetType() == cmStateEnums::STATIC_LIBRARY &&
+ // this dependency requires us to device link it
+ !item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS") &&
+ item.Target->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION");
+ });
+}
+
+void cmLinkLineDeviceComputer::ComputeLinkLibraries(
+ cmComputeLinkInformation& cli, std::string const& stdLibString,
+ std::vector<BT<std::string>>& linkLibraries)
+{
+ // Generate the unique set of link items when device linking.
+ // The nvcc device linker is designed so that each static library
+ // with device symbols only needs to be listed once as it doesn't
+ // care about link order.
+ std::set<std::string> emitted;
+ using ItemVector = cmComputeLinkInformation::ItemVector;
+ ItemVector const& items = cli.GetItems();
+ std::string config = cli.GetConfig();
+ bool skipItemAfterFramework = false;
+ // Note:
+ // Any modification of this algorithm should be reflected also in
+ // cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions
+ for (auto const& item : items) {
+ if (skipItemAfterFramework) {
+ skipItemAfterFramework = false;
+ continue;
+ }
+
+ if (item.Target) {
+ bool skip = false;
+ switch (item.Target->GetType()) {
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ skip = true;
+ break;
+ case cmStateEnums::STATIC_LIBRARY:
+ skip = item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS");
+ break;
+ default:
+ break;
+ }
+ if (skip) {
+ continue;
+ }
+ }
+
+ BT<std::string> linkLib;
+ if (item.IsPath) {
+ // nvcc understands absolute paths to libraries ending in '.a' or '.lib'.
+ // These should be passed to nvlink. Other extensions need to be left
+ // out because nvlink may not understand or need them. Even though it
+ // can tolerate '.so' or '.dylib' it cannot tolerate '.so.1'.
+ if (cmHasLiteralSuffix(item.Value.Value, ".a") ||
+ cmHasLiteralSuffix(item.Value.Value, ".lib")) {
+ linkLib.Value += this->ConvertToOutputFormat(
+ this->ConvertToLinkReference(item.Value.Value));
+ }
+ } else if (item.Value == "-framework") {
+ // This is the first part of '-framework Name' where the framework
+ // name is specified as a following item. Ignore both.
+ skipItemAfterFramework = true;
+ continue;
+ } else if (cmLinkItemValidForDevice(item.Value.Value)) {
+ linkLib.Value += item.Value.Value;
+ }
+
+ if (emitted.insert(linkLib.Value).second) {
+ linkLib.Value += " ";
+
+ const cmLinkImplementation* linkImpl =
+ cli.GetTarget()->GetLinkImplementation(cli.GetConfig());
+
+ for (const cmLinkImplItem& iter : linkImpl->Libraries) {
+ if (iter.Target != nullptr &&
+ iter.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+ std::string libPath = iter.Target->GetLocation(cli.GetConfig());
+ if (item.Value == libPath) {
+ linkLib.Backtrace = iter.Backtrace;
+ break;
+ }
+ }
+ }
+
+ linkLibraries.emplace_back(linkLib);
+ }
+ }
+
+ if (!stdLibString.empty()) {
+ linkLibraries.emplace_back(cmStrCat(stdLibString, ' '));
+ }
+}
+
+std::string cmLinkLineDeviceComputer::GetLinkerLanguage(cmGeneratorTarget*,
+ std::string const&)
+{
+ return "CUDA";
+}
+
+bool requireDeviceLinking(cmGeneratorTarget& target, cmLocalGenerator& lg,
+ const std::string& config)
+{
+ if (!target.GetGlobalGenerator()->GetLanguageEnabled("CUDA")) {
+ return false;
+ }
+
+ if (target.GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ return false;
+ }
+
+ if (!lg.GetMakefile()->IsOn("CMAKE_CUDA_COMPILER_HAS_DEVICE_LINK_PHASE")) {
+ return false;
+ }
+
+ if (cmProp resolveDeviceSymbols =
+ target.GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
+ // If CUDA_RESOLVE_DEVICE_SYMBOLS has been explicitly set we need
+ // to honor the value no matter what it is.
+ return cmIsOn(*resolveDeviceSymbols);
+ }
+
+ // Determine if we have any dependencies that require
+ // us to do a device link step
+ cmGeneratorTarget::LinkClosure const* closure =
+ target.GetLinkClosure(config);
+
+ if (cm::contains(closure->Languages, "CUDA")) {
+ if (cmIsOn(target.GetProperty("CUDA_SEPARABLE_COMPILATION"))) {
+ bool doDeviceLinking = false;
+ switch (target.GetType()) {
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::EXECUTABLE:
+ doDeviceLinking = true;
+ break;
+ default:
+ break;
+ }
+ return doDeviceLinking;
+ }
+
+ cmComputeLinkInformation* pcli = target.GetLinkInformation(config);
+ if (pcli) {
+ cmLinkLineDeviceComputer deviceLinkComputer(
+ &lg, lg.GetStateSnapshot().GetDirectory());
+ return deviceLinkComputer.ComputeRequiresDeviceLinking(*pcli);
+ }
+ return true;
+ }
+ return false;
+}
diff --git a/Source/cmLinkLineDeviceComputer.h b/Source/cmLinkLineDeviceComputer.h
new file mode 100644
index 0000000..dee625b
--- /dev/null
+++ b/Source/cmLinkLineDeviceComputer.h
@@ -0,0 +1,43 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmLinkLineComputer.h"
+
+class cmComputeLinkInformation;
+class cmGeneratorTarget;
+class cmLocalGenerator;
+class cmOutputConverter;
+class cmStateDirectory;
+template <typename T>
+class BT;
+
+class cmLinkLineDeviceComputer : public cmLinkLineComputer
+{
+public:
+ cmLinkLineDeviceComputer(cmOutputConverter* outputConverter,
+ cmStateDirectory const& stateDir);
+ ~cmLinkLineDeviceComputer() override;
+
+ cmLinkLineDeviceComputer(cmLinkLineDeviceComputer const&) = delete;
+ cmLinkLineDeviceComputer& operator=(cmLinkLineDeviceComputer const&) =
+ delete;
+
+ bool ComputeRequiresDeviceLinking(cmComputeLinkInformation& cli);
+
+ void ComputeLinkLibraries(
+ cmComputeLinkInformation& cli, std::string const& stdLibString,
+ std::vector<BT<std::string>>& linkLibraries) override;
+
+ std::string GetLinkerLanguage(cmGeneratorTarget* target,
+ std::string const& config) override;
+};
+
+bool requireDeviceLinking(cmGeneratorTarget& target, cmLocalGenerator& lg,
+ const std::string& config);
diff --git a/Source/cmLinkedTree.h b/Source/cmLinkedTree.h
new file mode 100644
index 0000000..616bf7e
--- /dev/null
+++ b/Source/cmLinkedTree.h
@@ -0,0 +1,189 @@
+/* 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 <cassert>
+#include <vector>
+
+/**
+ @brief A adaptor for traversing a tree structure in a vector
+
+ This class is not intended to be wholly generic like a standard library
+ container adaptor. Mostly it exists to facilitate code sharing for the
+ needs of the cmState. For example, the Truncate() method is a specific
+ requirement of the cmState.
+
+ An empty cmLinkedTree provides a Root() method, and an Push() method,
+ each of which return iterators. A Tree can be built up by extending
+ from the root, and then extending from any other iterator.
+
+ An iterator resulting from this tree construction can be
+ forward-only-iterated toward the root. Extending the tree never
+ invalidates existing iterators.
+ */
+template <typename T>
+class cmLinkedTree
+{
+ using PositionType = typename std::vector<T>::size_type;
+ using PointerType = T*;
+ using ReferenceType = T&;
+
+public:
+ class iterator
+ {
+ friend class cmLinkedTree;
+ cmLinkedTree* Tree;
+
+ // The Position is always 'one past the end'.
+ PositionType Position;
+
+ iterator(cmLinkedTree* tree, PositionType pos)
+ : Tree(tree)
+ , Position(pos)
+ {
+ }
+
+ public:
+ iterator()
+ : Tree(nullptr)
+ , Position(0)
+ {
+ }
+
+ void operator++()
+ {
+ assert(this->Tree);
+ assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
+ assert(this->Position <= this->Tree->Data.size());
+ assert(this->Position > 0);
+ this->Position = this->Tree->UpPositions[this->Position - 1];
+ }
+
+ PointerType operator->() const
+ {
+ assert(this->Tree);
+ assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
+ assert(this->Position <= this->Tree->Data.size());
+ assert(this->Position > 0);
+ return this->Tree->GetPointer(this->Position - 1);
+ }
+
+ PointerType operator->()
+ {
+ assert(this->Tree);
+ assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
+ assert(this->Position <= this->Tree->Data.size());
+ assert(this->Position > 0);
+ return this->Tree->GetPointer(this->Position - 1);
+ }
+
+ ReferenceType operator*() const
+ {
+ assert(this->Tree);
+ assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
+ assert(this->Position <= this->Tree->Data.size());
+ assert(this->Position > 0);
+ return this->Tree->GetReference(this->Position - 1);
+ }
+
+ ReferenceType operator*()
+ {
+ assert(this->Tree);
+ assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
+ assert(this->Position <= this->Tree->Data.size());
+ assert(this->Position > 0);
+ return this->Tree->GetReference(this->Position - 1);
+ }
+
+ bool operator==(iterator other) const
+ {
+ assert(this->Tree);
+ assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
+ assert(this->Tree == other.Tree);
+ return this->Position == other.Position;
+ }
+
+ bool operator!=(iterator other) const
+ {
+ assert(this->Tree);
+ assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
+ return !(*this == other);
+ }
+
+ bool IsValid() const
+ {
+ if (!this->Tree) {
+ return false;
+ }
+ return this->Position <= this->Tree->Data.size();
+ }
+
+ bool StrictWeakOrdered(iterator other) const
+ {
+ assert(this->Tree);
+ assert(this->Tree == other.Tree);
+ return this->Position < other.Position;
+ }
+ };
+
+ iterator Root() const
+ {
+ return iterator(const_cast<cmLinkedTree*>(this), 0);
+ }
+
+ iterator Push(iterator it) { return this->Push_impl(it, T()); }
+
+ iterator Push(iterator it, T t) { return this->Push_impl(it, std::move(t)); }
+
+ bool IsLast(iterator it) { return it.Position == this->Data.size(); }
+
+ iterator Pop(iterator it)
+ {
+ assert(!this->Data.empty());
+ assert(this->UpPositions.size() == this->Data.size());
+ bool const isLast = this->IsLast(it);
+ ++it;
+ // If this is the last entry then no other entry can refer
+ // to it so we can drop its storage.
+ if (isLast) {
+ this->Data.pop_back();
+ this->UpPositions.pop_back();
+ }
+ return it;
+ }
+
+ iterator Truncate()
+ {
+ assert(!this->UpPositions.empty());
+ this->UpPositions.erase(this->UpPositions.begin() + 1,
+ this->UpPositions.end());
+ assert(!this->Data.empty());
+ this->Data.erase(this->Data.begin() + 1, this->Data.end());
+ return iterator(this, 1);
+ }
+
+ void Clear()
+ {
+ this->UpPositions.clear();
+ this->Data.clear();
+ }
+
+private:
+ T& GetReference(PositionType pos) { return this->Data[pos]; }
+
+ T* GetPointer(PositionType pos) { return &this->Data[pos]; }
+
+ iterator Push_impl(iterator it, T&& t)
+ {
+ assert(this->UpPositions.size() == this->Data.size());
+ assert(it.Position <= this->UpPositions.size());
+ this->UpPositions.push_back(it.Position);
+ this->Data.push_back(std::move(t));
+ return iterator(this, this->UpPositions.size());
+ }
+
+ std::vector<T> Data;
+ std::vector<PositionType> UpPositions;
+};
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx
new file mode 100644
index 0000000..09cd88e
--- /dev/null
+++ b/Source/cmListCommand.cxx
@@ -0,0 +1,1547 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmListCommand.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <functional>
+#include <iterator>
+#include <set>
+#include <sstream>
+#include <stdexcept>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmAlgorithms.h"
+#include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmStringReplaceHelper.h"
+#include "cmSubcommandTable.h"
+#include "cmSystemTools.h"
+
+namespace {
+
+bool GetIndexArg(const std::string& arg, int* idx, cmMakefile& mf)
+{
+ long value;
+ if (!cmStrToLong(arg, &value)) {
+ switch (mf.GetPolicyStatus(cmPolicies::CMP0121)) {
+ case cmPolicies::WARN: {
+ // Default is to warn and use old behavior OLD behavior is to allow
+ // compatibility, so issue a warning and use the previous behavior.
+ std::string warn =
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0121),
+ " Invalid list index \"", arg, "\".");
+ mf.IssueMessage(MessageType::AUTHOR_WARNING, warn);
+ break;
+ }
+ case cmPolicies::OLD:
+ // OLD behavior is to allow compatibility, so just ignore the
+ // situation.
+ break;
+ case cmPolicies::NEW:
+ return false;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ std::string msg =
+ cmStrCat(cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0121),
+ " Invalid list index \"", arg, "\".");
+ mf.IssueMessage(MessageType::FATAL_ERROR, msg);
+ break;
+ }
+ }
+
+ // Truncation is happening here, but it had always been happening here.
+ *idx = static_cast<int>(value);
+
+ return true;
+}
+
+bool FilterRegex(std::vector<std::string> const& args, bool includeMatches,
+ std::string const& listName,
+ std::vector<std::string>& varArgsExpanded,
+ cmExecutionStatus& status);
+
+bool GetListString(std::string& listString, const std::string& var,
+ const cmMakefile& makefile)
+{
+ // get the old value
+ cmProp cacheValue = makefile.GetDefinition(var);
+ if (!cacheValue) {
+ return false;
+ }
+ listString = *cacheValue;
+ return true;
+}
+
+bool GetList(std::vector<std::string>& list, const std::string& var,
+ const cmMakefile& makefile)
+{
+ std::string listString;
+ if (!GetListString(listString, var, makefile)) {
+ return false;
+ }
+ // if the size of the list
+ if (listString.empty()) {
+ return true;
+ }
+ // expand the variable into a list
+ cmExpandList(listString, list, true);
+ // if no empty elements then just return
+ if (!cm::contains(list, std::string())) {
+ return true;
+ }
+ // if we have empty elements we need to check policy CMP0007
+ switch (makefile.GetPolicyStatus(cmPolicies::CMP0007)) {
+ case cmPolicies::WARN: {
+ // Default is to warn and use old behavior
+ // OLD behavior is to allow compatibility, so recall
+ // ExpandListArgument without the true which will remove
+ // empty values
+ list.clear();
+ cmExpandList(listString, list);
+ std::string warn =
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0007),
+ " List has value = [", listString, "].");
+ makefile.IssueMessage(MessageType::AUTHOR_WARNING, warn);
+ return true;
+ }
+ case cmPolicies::OLD:
+ // OLD behavior is to allow compatibility, so recall
+ // ExpandListArgument without the true which will remove
+ // empty values
+ list.clear();
+ cmExpandList(listString, list);
+ return true;
+ case cmPolicies::NEW:
+ return true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ makefile.IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0007));
+ return false;
+ }
+ return true;
+}
+
+bool HandleLengthCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError("sub-command LENGTH requires two arguments.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ const std::string& variableName = args.back();
+ std::vector<std::string> varArgsExpanded;
+ // do not check the return value here
+ // if the list var is not found varArgsExpanded will have size 0
+ // and we will return 0
+ GetList(varArgsExpanded, listName, status.GetMakefile());
+ size_t length = varArgsExpanded.size();
+ char buffer[1024];
+ sprintf(buffer, "%d", static_cast<int>(length));
+
+ status.GetMakefile().AddDefinition(variableName, buffer);
+ return true;
+}
+
+bool HandleGetCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 4) {
+ status.SetError("sub-command GET requires at least three arguments.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ const std::string& variableName = args.back();
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
+ status.GetMakefile().AddDefinition(variableName, "NOTFOUND");
+ return true;
+ }
+ // FIXME: Add policy to make non-existing lists an error like empty lists.
+ if (varArgsExpanded.empty()) {
+ status.SetError("GET given empty list");
+ return false;
+ }
+
+ std::string value;
+ size_t cc;
+ const char* sep = "";
+ size_t nitem = varArgsExpanded.size();
+ for (cc = 2; cc < args.size() - 1; cc++) {
+ int item;
+ if (!GetIndexArg(args[cc], &item, status.GetMakefile())) {
+ status.SetError(cmStrCat("index: ", args[cc], " is not a valid index"));
+ return false;
+ }
+ value += sep;
+ sep = ";";
+ if (item < 0) {
+ item = static_cast<int>(nitem) + item;
+ }
+ if (item < 0 || nitem <= static_cast<size_t>(item)) {
+ status.SetError(cmStrCat("index: ", item, " out of range (-", nitem,
+ ", ", nitem - 1, ")"));
+ return false;
+ }
+ value += varArgsExpanded[item];
+ }
+
+ status.GetMakefile().AddDefinition(variableName, value);
+ return true;
+}
+
+bool HandleAppendCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ assert(args.size() >= 2);
+
+ // Skip if nothing to append.
+ if (args.size() < 3) {
+ return true;
+ }
+
+ cmMakefile& makefile = status.GetMakefile();
+ std::string const& listName = args[1];
+ // expand the variable
+ std::string listString;
+ GetListString(listString, listName, makefile);
+
+ // If `listString` or `args` is empty, no need to append `;`,
+ // then index is going to be `1` and points to the end-of-string ";"
+ auto const offset =
+ std::string::size_type(listString.empty() || args.empty());
+ listString += &";"[offset] + cmJoin(cmMakeRange(args).advance(2), ";");
+
+ makefile.AddDefinition(listName, listString);
+ return true;
+}
+
+bool HandlePrependCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ assert(args.size() >= 2);
+
+ // Skip if nothing to prepend.
+ if (args.size() < 3) {
+ return true;
+ }
+
+ cmMakefile& makefile = status.GetMakefile();
+ std::string const& listName = args[1];
+ // expand the variable
+ std::string listString;
+ GetListString(listString, listName, makefile);
+
+ // If `listString` or `args` is empty, no need to append `;`,
+ // then `offset` is going to be `1` and points to the end-of-string ";"
+ auto const offset =
+ std::string::size_type(listString.empty() || args.empty());
+ listString.insert(0,
+ cmJoin(cmMakeRange(args).advance(2), ";") + &";"[offset]);
+
+ makefile.AddDefinition(listName, listString);
+ return true;
+}
+
+bool HandlePopBackCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ assert(args.size() >= 2);
+
+ cmMakefile& makefile = status.GetMakefile();
+ auto ai = args.cbegin();
+ ++ai; // Skip subcommand name
+ std::string const& listName = *ai++;
+ std::vector<std::string> varArgsExpanded;
+ if (!GetList(varArgsExpanded, listName, makefile)) {
+ // Can't get the list definition... undefine any vars given after.
+ for (; ai != args.cend(); ++ai) {
+ makefile.RemoveDefinition(*ai);
+ }
+ return true;
+ }
+
+ if (!varArgsExpanded.empty()) {
+ if (ai == args.cend()) {
+ // No variables are given... Just remove one element.
+ varArgsExpanded.pop_back();
+ } else {
+ // Ok, assign elements to be removed to the given variables
+ for (; !varArgsExpanded.empty() && ai != args.cend(); ++ai) {
+ assert(!ai->empty());
+ makefile.AddDefinition(*ai, varArgsExpanded.back());
+ varArgsExpanded.pop_back();
+ }
+ // Undefine the rest variables if the list gets empty earlier...
+ for (; ai != args.cend(); ++ai) {
+ makefile.RemoveDefinition(*ai);
+ }
+ }
+
+ makefile.AddDefinition(listName, cmJoin(varArgsExpanded, ";"));
+
+ } else if (ai !=
+ args.cend()) { // The list is empty, but some args were given
+ // Need to *undefine* 'em all, cuz there are no items to assign...
+ for (; ai != args.cend(); ++ai) {
+ makefile.RemoveDefinition(*ai);
+ }
+ }
+
+ return true;
+}
+
+bool HandlePopFrontCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ assert(args.size() >= 2);
+
+ cmMakefile& makefile = status.GetMakefile();
+ auto ai = args.cbegin();
+ ++ai; // Skip subcommand name
+ std::string const& listName = *ai++;
+ std::vector<std::string> varArgsExpanded;
+ if (!GetList(varArgsExpanded, listName, makefile)) {
+ // Can't get the list definition... undefine any vars given after.
+ for (; ai != args.cend(); ++ai) {
+ makefile.RemoveDefinition(*ai);
+ }
+ return true;
+ }
+
+ if (!varArgsExpanded.empty()) {
+ if (ai == args.cend()) {
+ // No variables are given... Just remove one element.
+ varArgsExpanded.erase(varArgsExpanded.begin());
+ } else {
+ // Ok, assign elements to be removed to the given variables
+ auto vi = varArgsExpanded.begin();
+ for (; vi != varArgsExpanded.end() && ai != args.cend(); ++ai, ++vi) {
+ assert(!ai->empty());
+ makefile.AddDefinition(*ai, *vi);
+ }
+ varArgsExpanded.erase(varArgsExpanded.begin(), vi);
+ // Undefine the rest variables if the list gets empty earlier...
+ for (; ai != args.cend(); ++ai) {
+ makefile.RemoveDefinition(*ai);
+ }
+ }
+
+ makefile.AddDefinition(listName, cmJoin(varArgsExpanded, ";"));
+
+ } else if (ai !=
+ args.cend()) { // The list is empty, but some args were given
+ // Need to *undefine* 'em all, cuz there are no items to assign...
+ for (; ai != args.cend(); ++ai) {
+ makefile.RemoveDefinition(*ai);
+ }
+ }
+
+ return true;
+}
+
+bool HandleFindCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 4) {
+ status.SetError("sub-command FIND requires three arguments.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ const std::string& variableName = args.back();
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
+ status.GetMakefile().AddDefinition(variableName, "-1");
+ return true;
+ }
+
+ auto it = std::find(varArgsExpanded.begin(), varArgsExpanded.end(), args[2]);
+ if (it != varArgsExpanded.end()) {
+ status.GetMakefile().AddDefinition(
+ variableName,
+ std::to_string(std::distance(varArgsExpanded.begin(), it)));
+ return true;
+ }
+
+ status.GetMakefile().AddDefinition(variableName, "-1");
+ return true;
+}
+
+bool HandleInsertCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 4) {
+ status.SetError("sub-command INSERT requires at least three arguments.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+
+ // expand the variable
+ int item;
+ if (!GetIndexArg(args[2], &item, status.GetMakefile())) {
+ status.SetError(cmStrCat("index: ", args[2], " is not a valid index"));
+ return false;
+ }
+ std::vector<std::string> varArgsExpanded;
+ if ((!GetList(varArgsExpanded, listName, status.GetMakefile()) ||
+ varArgsExpanded.empty()) &&
+ item != 0) {
+ status.SetError(cmStrCat("index: ", item, " out of range (0, 0)"));
+ return false;
+ }
+
+ if (!varArgsExpanded.empty()) {
+ size_t nitem = varArgsExpanded.size();
+ if (item < 0) {
+ item = static_cast<int>(nitem) + item;
+ }
+ if (item < 0 || nitem < static_cast<size_t>(item)) {
+ status.SetError(cmStrCat("index: ", item, " out of range (-",
+ varArgsExpanded.size(), ", ",
+ varArgsExpanded.size(), ")"));
+ return false;
+ }
+ }
+
+ varArgsExpanded.insert(varArgsExpanded.begin() + item, args.begin() + 3,
+ args.end());
+
+ std::string value = cmJoin(varArgsExpanded, ";");
+ status.GetMakefile().AddDefinition(listName, value);
+ return true;
+}
+
+bool HandleJoinCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 4) {
+ status.SetError(cmStrCat("sub-command JOIN requires three arguments (",
+ args.size() - 1, " found)."));
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ const std::string& glue = args[2];
+ const std::string& variableName = args[3];
+
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
+ status.GetMakefile().AddDefinition(variableName, "");
+ return true;
+ }
+
+ std::string value =
+ cmJoin(cmMakeRange(varArgsExpanded.begin(), varArgsExpanded.end()), glue);
+
+ status.GetMakefile().AddDefinition(variableName, value);
+ return true;
+}
+
+bool HandleRemoveItemCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ assert(args.size() >= 2);
+
+ if (args.size() == 2) {
+ return true;
+ }
+
+ const std::string& listName = args[1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
+ return true;
+ }
+
+ std::vector<std::string> remove(args.begin() + 2, args.end());
+ std::sort(remove.begin(), remove.end());
+ auto remEnd = std::unique(remove.begin(), remove.end());
+ auto remBegin = remove.begin();
+
+ auto argsEnd =
+ cmRemoveMatching(varArgsExpanded, cmMakeRange(remBegin, remEnd));
+ auto argsBegin = varArgsExpanded.cbegin();
+ std::string value = cmJoin(cmMakeRange(argsBegin, argsEnd), ";");
+ status.GetMakefile().AddDefinition(listName, value);
+ return true;
+}
+
+bool HandleReverseCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ assert(args.size() >= 2);
+ if (args.size() > 2) {
+ status.SetError("sub-command REVERSE only takes one argument.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
+ return true;
+ }
+
+ std::string value = cmJoin(cmReverseRange(varArgsExpanded), ";");
+
+ status.GetMakefile().AddDefinition(listName, value);
+ return true;
+}
+
+bool HandleRemoveDuplicatesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ assert(args.size() >= 2);
+ if (args.size() > 2) {
+ status.SetError("sub-command REMOVE_DUPLICATES only takes one argument.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
+ return true;
+ }
+
+ auto argsEnd = cmRemoveDuplicates(varArgsExpanded);
+ auto argsBegin = varArgsExpanded.cbegin();
+ std::string value = cmJoin(cmMakeRange(argsBegin, argsEnd), ";");
+
+ status.GetMakefile().AddDefinition(listName, value);
+ return true;
+}
+
+// Helpers for list(TRANSFORM <list> ...)
+using transform_type = std::function<std::string(const std::string&)>;
+
+class transform_error : public std::runtime_error
+{
+public:
+ transform_error(const std::string& error)
+ : std::runtime_error(error)
+ {
+ }
+};
+
+class TransformSelector
+{
+public:
+ virtual ~TransformSelector() = default;
+
+ std::string Tag;
+
+ virtual bool Validate(std::size_t count = 0) = 0;
+
+ virtual bool InSelection(const std::string&) = 0;
+
+ virtual void Transform(std::vector<std::string>& list,
+ const transform_type& transform)
+ {
+ std::transform(list.begin(), list.end(), list.begin(), transform);
+ }
+
+protected:
+ TransformSelector(std::string&& tag)
+ : Tag(std::move(tag))
+ {
+ }
+};
+class TransformNoSelector : public TransformSelector
+{
+public:
+ TransformNoSelector()
+ : TransformSelector("NO SELECTOR")
+ {
+ }
+
+ bool Validate(std::size_t) override { return true; }
+
+ bool InSelection(const std::string&) override { return true; }
+};
+class TransformSelectorRegex : public TransformSelector
+{
+public:
+ TransformSelectorRegex(const std::string& regex)
+ : TransformSelector("REGEX")
+ , Regex(regex)
+ {
+ }
+
+ bool Validate(std::size_t) override { return this->Regex.is_valid(); }
+
+ bool InSelection(const std::string& value) override
+ {
+ return this->Regex.find(value);
+ }
+
+ cmsys::RegularExpression Regex;
+};
+class TransformSelectorIndexes : public TransformSelector
+{
+public:
+ std::vector<int> Indexes;
+
+ bool InSelection(const std::string&) override { return true; }
+
+ void Transform(std::vector<std::string>& list,
+ const transform_type& transform) override
+ {
+ this->Validate(list.size());
+
+ for (auto index : this->Indexes) {
+ list[index] = transform(list[index]);
+ }
+ }
+
+protected:
+ TransformSelectorIndexes(std::string&& tag)
+ : TransformSelector(std::move(tag))
+ {
+ }
+ TransformSelectorIndexes(std::string&& tag, std::vector<int>&& indexes)
+ : TransformSelector(std::move(tag))
+ , Indexes(indexes)
+ {
+ }
+
+ int NormalizeIndex(int index, std::size_t count)
+ {
+ if (index < 0) {
+ index = static_cast<int>(count) + index;
+ }
+ if (index < 0 || count <= static_cast<std::size_t>(index)) {
+ throw transform_error(cmStrCat(
+ "sub-command TRANSFORM, selector ", this->Tag, ", index: ", index,
+ " out of range (-", count, ", ", count - 1, ")."));
+ }
+ return index;
+ }
+};
+class TransformSelectorAt : public TransformSelectorIndexes
+{
+public:
+ TransformSelectorAt(std::vector<int>&& indexes)
+ : TransformSelectorIndexes("AT", std::move(indexes))
+ {
+ }
+
+ bool Validate(std::size_t count) override
+ {
+ decltype(this->Indexes) indexes;
+
+ for (auto index : this->Indexes) {
+ indexes.push_back(this->NormalizeIndex(index, count));
+ }
+ this->Indexes = std::move(indexes);
+
+ return true;
+ }
+};
+class TransformSelectorFor : public TransformSelectorIndexes
+{
+public:
+ TransformSelectorFor(int start, int stop, int step)
+ : TransformSelectorIndexes("FOR")
+ , Start(start)
+ , Stop(stop)
+ , Step(step)
+ {
+ }
+
+ bool Validate(std::size_t count) override
+ {
+ this->Start = this->NormalizeIndex(this->Start, count);
+ this->Stop = this->NormalizeIndex(this->Stop, count);
+
+ // compute indexes
+ auto size = (this->Stop - this->Start + 1) / this->Step;
+ if ((this->Stop - this->Start + 1) % this->Step != 0) {
+ size += 1;
+ }
+
+ this->Indexes.resize(size);
+ auto start = this->Start;
+ auto step = this->Step;
+ std::generate(this->Indexes.begin(), this->Indexes.end(),
+ [&start, step]() -> int {
+ auto r = start;
+ start += step;
+ return r;
+ });
+
+ return true;
+ }
+
+private:
+ int Start, Stop, Step;
+};
+
+class TransformAction
+{
+public:
+ virtual ~TransformAction() = default;
+
+ virtual std::string Transform(const std::string& input) = 0;
+};
+class TransformReplace : public TransformAction
+{
+public:
+ TransformReplace(const std::vector<std::string>& arguments,
+ cmMakefile* makefile)
+ : ReplaceHelper(arguments[0], arguments[1], makefile)
+ {
+ makefile->ClearMatches();
+
+ if (!this->ReplaceHelper.IsRegularExpressionValid()) {
+ throw transform_error(
+ cmStrCat("sub-command TRANSFORM, action REPLACE: Failed to compile "
+ "regex \"",
+ arguments[0], "\"."));
+ }
+ if (!this->ReplaceHelper.IsReplaceExpressionValid()) {
+ throw transform_error(cmStrCat("sub-command TRANSFORM, action REPLACE: ",
+ this->ReplaceHelper.GetError(), "."));
+ }
+ }
+
+ std::string Transform(const std::string& input) override
+ {
+ // Scan through the input for all matches.
+ std::string output;
+
+ if (!this->ReplaceHelper.Replace(input, output)) {
+ throw transform_error(cmStrCat("sub-command TRANSFORM, action REPLACE: ",
+ this->ReplaceHelper.GetError(), "."));
+ }
+
+ return output;
+ }
+
+private:
+ cmStringReplaceHelper ReplaceHelper;
+};
+
+bool HandleTransformCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError(
+ "sub-command TRANSFORM requires an action to be specified.");
+ return false;
+ }
+
+ // Structure collecting all elements of the command
+ struct Command
+ {
+ Command(const std::string& listName)
+ : ListName(listName)
+ , OutputName(listName)
+ {
+ }
+
+ std::string Name;
+ std::string ListName;
+ std::vector<std::string> Arguments;
+ std::unique_ptr<TransformAction> Action;
+ std::unique_ptr<TransformSelector> Selector;
+ std::string OutputName;
+ } command(args[1]);
+
+ // Descriptor of action
+ // Arity: number of arguments required for the action
+ // Transform: lambda function implementing the action
+ struct ActionDescriptor
+ {
+ ActionDescriptor(std::string name)
+ : Name(std::move(name))
+ {
+ }
+ ActionDescriptor(std::string name, int arity, transform_type transform)
+ : Name(std::move(name))
+ , Arity(arity)
+#if defined(__GNUC__) && __GNUC__ == 6 && defined(__aarch64__)
+ // std::function move constructor miscompiles on this architecture
+ , Transform(transform)
+#else
+ , Transform(std::move(transform))
+#endif
+ {
+ }
+
+ operator const std::string&() const { return this->Name; }
+
+ std::string Name;
+ int Arity = 0;
+ transform_type Transform;
+ };
+
+ // Build a set of supported actions.
+ std::set<ActionDescriptor,
+ std::function<bool(const std::string&, const std::string&)>>
+ descriptors(
+ [](const std::string& x, const std::string& y) { return x < y; });
+ descriptors = { { "APPEND", 1,
+ [&command](const std::string& s) -> std::string {
+ if (command.Selector->InSelection(s)) {
+ return s + command.Arguments[0];
+ }
+
+ return s;
+ } },
+ { "PREPEND", 1,
+ [&command](const std::string& s) -> std::string {
+ if (command.Selector->InSelection(s)) {
+ return command.Arguments[0] + s;
+ }
+
+ return s;
+ } },
+ { "TOUPPER", 0,
+ [&command](const std::string& s) -> std::string {
+ if (command.Selector->InSelection(s)) {
+ return cmSystemTools::UpperCase(s);
+ }
+
+ return s;
+ } },
+ { "TOLOWER", 0,
+ [&command](const std::string& s) -> std::string {
+ if (command.Selector->InSelection(s)) {
+ return cmSystemTools::LowerCase(s);
+ }
+
+ return s;
+ } },
+ { "STRIP", 0,
+ [&command](const std::string& s) -> std::string {
+ if (command.Selector->InSelection(s)) {
+ return cmTrimWhitespace(s);
+ }
+
+ return s;
+ } },
+ { "GENEX_STRIP", 0,
+ [&command](const std::string& s) -> std::string {
+ if (command.Selector->InSelection(s)) {
+ return cmGeneratorExpression::Preprocess(
+ s,
+ cmGeneratorExpression::StripAllGeneratorExpressions);
+ }
+
+ return s;
+ } },
+ { "REPLACE", 2,
+ [&command](const std::string& s) -> std::string {
+ if (command.Selector->InSelection(s)) {
+ return command.Action->Transform(s);
+ }
+
+ return s;
+ } } };
+
+ using size_type = std::vector<std::string>::size_type;
+ size_type index = 2;
+
+ // Parse all possible function parameters
+ auto descriptor = descriptors.find(args[index]);
+
+ if (descriptor == descriptors.end()) {
+ status.SetError(
+ cmStrCat(" sub-command TRANSFORM, ", args[index], " invalid action."));
+ return false;
+ }
+
+ // Action arguments
+ index += 1;
+ if (args.size() < index + descriptor->Arity) {
+ status.SetError(cmStrCat("sub-command TRANSFORM, action ",
+ descriptor->Name, " expects ", descriptor->Arity,
+ " argument(s)."));
+ return false;
+ }
+
+ command.Name = descriptor->Name;
+ index += descriptor->Arity;
+ if (descriptor->Arity > 0) {
+ command.Arguments =
+ std::vector<std::string>(args.begin() + 3, args.begin() + index);
+ }
+
+ if (command.Name == "REPLACE") {
+ try {
+ command.Action = cm::make_unique<TransformReplace>(
+ command.Arguments, &status.GetMakefile());
+ } catch (const transform_error& e) {
+ status.SetError(e.what());
+ return false;
+ }
+ }
+
+ const std::string REGEX{ "REGEX" };
+ const std::string AT{ "AT" };
+ const std::string FOR{ "FOR" };
+ const std::string OUTPUT_VARIABLE{ "OUTPUT_VARIABLE" };
+
+ // handle optional arguments
+ while (args.size() > index) {
+ if ((args[index] == REGEX || args[index] == AT || args[index] == FOR) &&
+ command.Selector) {
+ status.SetError(
+ cmStrCat("sub-command TRANSFORM, selector already specified (",
+ command.Selector->Tag, ")."));
+
+ return false;
+ }
+
+ // REGEX selector
+ if (args[index] == REGEX) {
+ if (args.size() == ++index) {
+ status.SetError("sub-command TRANSFORM, selector REGEX expects "
+ "'regular expression' argument.");
+ return false;
+ }
+
+ command.Selector = cm::make_unique<TransformSelectorRegex>(args[index]);
+ if (!command.Selector->Validate()) {
+ status.SetError(
+ cmStrCat("sub-command TRANSFORM, selector REGEX failed to compile "
+ "regex \"",
+ args[index], "\"."));
+ return false;
+ }
+
+ index += 1;
+ continue;
+ }
+
+ // AT selector
+ if (args[index] == AT) {
+ // get all specified indexes
+ std::vector<int> indexes;
+ while (args.size() > ++index) {
+ std::size_t pos;
+ int value;
+
+ try {
+ value = std::stoi(args[index], &pos);
+ if (pos != args[index].length()) {
+ // this is not a number, stop processing
+ break;
+ }
+ indexes.push_back(value);
+ } catch (const std::invalid_argument&) {
+ // this is not a number, stop processing
+ break;
+ }
+ }
+
+ if (indexes.empty()) {
+ status.SetError(
+ "sub-command TRANSFORM, selector AT expects at least one "
+ "numeric value.");
+ return false;
+ }
+
+ command.Selector =
+ cm::make_unique<TransformSelectorAt>(std::move(indexes));
+
+ continue;
+ }
+
+ // FOR selector
+ if (args[index] == FOR) {
+ if (args.size() <= ++index + 1) {
+ status.SetError(
+ "sub-command TRANSFORM, selector FOR expects, at least,"
+ " two arguments.");
+ return false;
+ }
+
+ int start = 0;
+ int stop = 0;
+ int step = 1;
+ bool valid = true;
+ try {
+ std::size_t pos;
+
+ start = std::stoi(args[index], &pos);
+ if (pos != args[index].length()) {
+ // this is not a number
+ valid = false;
+ } else {
+ stop = std::stoi(args[++index], &pos);
+ if (pos != args[index].length()) {
+ // this is not a number
+ valid = false;
+ }
+ }
+ } catch (const std::invalid_argument&) {
+ // this is not numbers
+ valid = false;
+ }
+ if (!valid) {
+ status.SetError("sub-command TRANSFORM, selector FOR expects, "
+ "at least, two numeric values.");
+ return false;
+ }
+ // try to read a third numeric value for step
+ if (args.size() > ++index) {
+ try {
+ std::size_t pos;
+
+ step = std::stoi(args[index], &pos);
+ if (pos != args[index].length()) {
+ // this is not a number
+ step = 1;
+ } else {
+ index += 1;
+ }
+ } catch (const std::invalid_argument&) {
+ // this is not number, ignore exception
+ }
+ }
+
+ if (step < 0) {
+ status.SetError("sub-command TRANSFORM, selector FOR expects "
+ "non negative numeric value for <step>.");
+ }
+
+ command.Selector =
+ cm::make_unique<TransformSelectorFor>(start, stop, step);
+
+ continue;
+ }
+
+ // output variable
+ if (args[index] == OUTPUT_VARIABLE) {
+ if (args.size() == ++index) {
+ status.SetError("sub-command TRANSFORM, OUTPUT_VARIABLE "
+ "expects variable name argument.");
+ return false;
+ }
+
+ command.OutputName = args[index++];
+ continue;
+ }
+
+ status.SetError(cmStrCat("sub-command TRANSFORM, '",
+ cmJoin(cmMakeRange(args).advance(index), " "),
+ "': unexpected argument(s)."));
+ return false;
+ }
+
+ // expand the list variable
+ std::vector<std::string> varArgsExpanded;
+ if (!GetList(varArgsExpanded, command.ListName, status.GetMakefile())) {
+ status.GetMakefile().AddDefinition(command.OutputName, "");
+ return true;
+ }
+
+ if (!command.Selector) {
+ // no selector specified, apply transformation to all elements
+ command.Selector = cm::make_unique<TransformNoSelector>();
+ }
+
+ try {
+ command.Selector->Transform(varArgsExpanded, descriptor->Transform);
+ } catch (const transform_error& e) {
+ status.SetError(e.what());
+ return false;
+ }
+
+ status.GetMakefile().AddDefinition(command.OutputName,
+ cmJoin(varArgsExpanded, ";"));
+
+ return true;
+}
+
+class cmStringSorter
+{
+public:
+ enum class Order
+ {
+ UNINITIALIZED,
+ ASCENDING,
+ DESCENDING,
+ };
+
+ enum class Compare
+ {
+ UNINITIALIZED,
+ STRING,
+ FILE_BASENAME,
+ NATURAL,
+ };
+ enum class CaseSensitivity
+ {
+ UNINITIALIZED,
+ SENSITIVE,
+ INSENSITIVE,
+ };
+
+protected:
+ using StringFilter = std::string (*)(const std::string&);
+ StringFilter GetCompareFilter(Compare compare)
+ {
+ return (compare == Compare::FILE_BASENAME) ? cmSystemTools::GetFilenameName
+ : nullptr;
+ }
+
+ StringFilter GetCaseFilter(CaseSensitivity sensitivity)
+ {
+ return (sensitivity == CaseSensitivity::INSENSITIVE)
+ ? cmSystemTools::LowerCase
+ : nullptr;
+ }
+
+ using ComparisonFunction =
+ std::function<bool(const std::string&, const std::string&)>;
+ ComparisonFunction GetComparisonFunction(Compare compare)
+ {
+ if (compare == Compare::NATURAL) {
+ return std::function<bool(const std::string&, const std::string&)>(
+ [](const std::string& x, const std::string& y) {
+ return cmSystemTools::strverscmp(x, y) < 0;
+ });
+ }
+ return std::function<bool(const std::string&, const std::string&)>(
+ [](const std::string& x, const std::string& y) { return x < y; });
+ }
+
+public:
+ cmStringSorter(Compare compare, CaseSensitivity caseSensitivity,
+ Order desc = Order::ASCENDING)
+ : filters{ this->GetCompareFilter(compare),
+ this->GetCaseFilter(caseSensitivity) }
+ , sortMethod(this->GetComparisonFunction(compare))
+ , descending(desc == Order::DESCENDING)
+ {
+ }
+
+ std::string ApplyFilter(const std::string& argument)
+ {
+ std::string result = argument;
+ for (auto filter : this->filters) {
+ if (filter != nullptr) {
+ result = filter(result);
+ }
+ }
+ return result;
+ }
+
+ bool operator()(const std::string& a, const std::string& b)
+ {
+ std::string af = this->ApplyFilter(a);
+ std::string bf = this->ApplyFilter(b);
+ bool result;
+ if (this->descending) {
+ result = this->sortMethod(bf, af);
+ } else {
+ result = this->sortMethod(af, bf);
+ }
+ return result;
+ }
+
+protected:
+ StringFilter filters[2] = { nullptr, nullptr };
+ ComparisonFunction sortMethod;
+ bool descending;
+};
+
+bool HandleSortCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ assert(args.size() >= 2);
+ if (args.size() > 8) {
+ status.SetError("sub-command SORT only takes up to six arguments.");
+ return false;
+ }
+
+ auto sortCompare = cmStringSorter::Compare::UNINITIALIZED;
+ auto sortCaseSensitivity = cmStringSorter::CaseSensitivity::UNINITIALIZED;
+ auto sortOrder = cmStringSorter::Order::UNINITIALIZED;
+
+ size_t argumentIndex = 2;
+ const std::string messageHint = "sub-command SORT ";
+
+ while (argumentIndex < args.size()) {
+ const std::string option = args[argumentIndex++];
+ if (option == "COMPARE") {
+ if (sortCompare != cmStringSorter::Compare::UNINITIALIZED) {
+ std::string error = cmStrCat(messageHint, "option \"", option,
+ "\" has been specified multiple times.");
+ status.SetError(error);
+ return false;
+ }
+ if (argumentIndex < args.size()) {
+ const std::string argument = args[argumentIndex++];
+ if (argument == "STRING") {
+ sortCompare = cmStringSorter::Compare::STRING;
+ } else if (argument == "FILE_BASENAME") {
+ sortCompare = cmStringSorter::Compare::FILE_BASENAME;
+ } else if (argument == "NATURAL") {
+ sortCompare = cmStringSorter::Compare::NATURAL;
+ } else {
+ std::string error =
+ cmStrCat(messageHint, "value \"", argument, "\" for option \"",
+ option, "\" is invalid.");
+ status.SetError(error);
+ return false;
+ }
+ } else {
+ status.SetError(cmStrCat(messageHint, "missing argument for option \"",
+ option, "\"."));
+ return false;
+ }
+ } else if (option == "CASE") {
+ if (sortCaseSensitivity !=
+ cmStringSorter::CaseSensitivity::UNINITIALIZED) {
+ status.SetError(cmStrCat(messageHint, "option \"", option,
+ "\" has been specified multiple times."));
+ return false;
+ }
+ if (argumentIndex < args.size()) {
+ const std::string argument = args[argumentIndex++];
+ if (argument == "SENSITIVE") {
+ sortCaseSensitivity = cmStringSorter::CaseSensitivity::SENSITIVE;
+ } else if (argument == "INSENSITIVE") {
+ sortCaseSensitivity = cmStringSorter::CaseSensitivity::INSENSITIVE;
+ } else {
+ status.SetError(cmStrCat(messageHint, "value \"", argument,
+ "\" for option \"", option,
+ "\" is invalid."));
+ return false;
+ }
+ } else {
+ status.SetError(cmStrCat(messageHint, "missing argument for option \"",
+ option, "\"."));
+ return false;
+ }
+ } else if (option == "ORDER") {
+
+ if (sortOrder != cmStringSorter::Order::UNINITIALIZED) {
+ status.SetError(cmStrCat(messageHint, "option \"", option,
+ "\" has been specified multiple times."));
+ return false;
+ }
+ if (argumentIndex < args.size()) {
+ const std::string argument = args[argumentIndex++];
+ if (argument == "ASCENDING") {
+ sortOrder = cmStringSorter::Order::ASCENDING;
+ } else if (argument == "DESCENDING") {
+ sortOrder = cmStringSorter::Order::DESCENDING;
+ } else {
+ status.SetError(cmStrCat(messageHint, "value \"", argument,
+ "\" for option \"", option,
+ "\" is invalid."));
+ return false;
+ }
+ } else {
+ status.SetError(cmStrCat(messageHint, "missing argument for option \"",
+ option, "\"."));
+ return false;
+ }
+ } else {
+ status.SetError(
+ cmStrCat(messageHint, "option \"", option, "\" is unknown."));
+ return false;
+ }
+ }
+ // set Default Values if Option is not given
+ if (sortCompare == cmStringSorter::Compare::UNINITIALIZED) {
+ sortCompare = cmStringSorter::Compare::STRING;
+ }
+ if (sortCaseSensitivity == cmStringSorter::CaseSensitivity::UNINITIALIZED) {
+ sortCaseSensitivity = cmStringSorter::CaseSensitivity::SENSITIVE;
+ }
+ if (sortOrder == cmStringSorter::Order::UNINITIALIZED) {
+ sortOrder = cmStringSorter::Order::ASCENDING;
+ }
+
+ const std::string& listName = args[1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
+ return true;
+ }
+
+ if ((sortCompare == cmStringSorter::Compare::STRING) &&
+ (sortCaseSensitivity == cmStringSorter::CaseSensitivity::SENSITIVE) &&
+ (sortOrder == cmStringSorter::Order::ASCENDING)) {
+ std::sort(varArgsExpanded.begin(), varArgsExpanded.end());
+ } else {
+ cmStringSorter sorter(sortCompare, sortCaseSensitivity, sortOrder);
+ std::sort(varArgsExpanded.begin(), varArgsExpanded.end(), sorter);
+ }
+
+ std::string value = cmJoin(varArgsExpanded, ";");
+ status.GetMakefile().AddDefinition(listName, value);
+ return true;
+}
+
+bool HandleSublistCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 5) {
+ status.SetError(cmStrCat("sub-command SUBLIST requires four arguments (",
+ args.size() - 1, " found)."));
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ const std::string& variableName = args.back();
+
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!GetList(varArgsExpanded, listName, status.GetMakefile()) ||
+ varArgsExpanded.empty()) {
+ status.GetMakefile().AddDefinition(variableName, "");
+ return true;
+ }
+
+ int start;
+ int length;
+ if (!GetIndexArg(args[2], &start, status.GetMakefile())) {
+ status.SetError(cmStrCat("index: ", args[2], " is not a valid index"));
+ return false;
+ }
+ if (!GetIndexArg(args[3], &length, status.GetMakefile())) {
+ status.SetError(cmStrCat("index: ", args[3], " is not a valid index"));
+ return false;
+ }
+
+ using size_type = decltype(varArgsExpanded)::size_type;
+
+ if (start < 0 || size_type(start) >= varArgsExpanded.size()) {
+ status.SetError(cmStrCat("begin index: ", start, " is out of range 0 - ",
+ varArgsExpanded.size() - 1));
+ return false;
+ }
+ if (length < -1) {
+ status.SetError(cmStrCat("length: ", length, " should be -1 or greater"));
+ return false;
+ }
+
+ const size_type end =
+ (length == -1 || size_type(start + length) > varArgsExpanded.size())
+ ? varArgsExpanded.size()
+ : size_type(start + length);
+ std::vector<std::string> sublist(varArgsExpanded.begin() + start,
+ varArgsExpanded.begin() + end);
+ status.GetMakefile().AddDefinition(variableName, cmJoin(sublist, ";"));
+ return true;
+}
+
+bool HandleRemoveAtCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("sub-command REMOVE_AT requires at least "
+ "two arguments.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!GetList(varArgsExpanded, listName, status.GetMakefile()) ||
+ varArgsExpanded.empty()) {
+ std::ostringstream str;
+ str << "index: ";
+ for (size_t i = 1; i < args.size(); ++i) {
+ str << args[i];
+ if (i != args.size() - 1) {
+ str << ", ";
+ }
+ }
+ str << " out of range (0, 0)";
+ status.SetError(str.str());
+ return false;
+ }
+
+ size_t cc;
+ std::vector<size_t> removed;
+ size_t nitem = varArgsExpanded.size();
+ for (cc = 2; cc < args.size(); ++cc) {
+ int item;
+ if (!GetIndexArg(args[cc], &item, status.GetMakefile())) {
+ status.SetError(cmStrCat("index: ", args[cc], " is not a valid index"));
+ return false;
+ }
+ if (item < 0) {
+ item = static_cast<int>(nitem) + item;
+ }
+ if (item < 0 || nitem <= static_cast<size_t>(item)) {
+ status.SetError(cmStrCat("index: ", item, " out of range (-", nitem,
+ ", ", nitem - 1, ")"));
+ return false;
+ }
+ removed.push_back(static_cast<size_t>(item));
+ }
+
+ std::sort(removed.begin(), removed.end());
+ auto remEnd = std::unique(removed.begin(), removed.end());
+ auto remBegin = removed.begin();
+
+ auto argsEnd =
+ cmRemoveIndices(varArgsExpanded, cmMakeRange(remBegin, remEnd));
+ auto argsBegin = varArgsExpanded.cbegin();
+ std::string value = cmJoin(cmMakeRange(argsBegin, argsEnd), ";");
+
+ status.GetMakefile().AddDefinition(listName, value);
+ return true;
+}
+
+bool HandleFilterCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("sub-command FILTER requires a list to be specified.");
+ return false;
+ }
+
+ if (args.size() < 3) {
+ status.SetError(
+ "sub-command FILTER requires an operator to be specified.");
+ return false;
+ }
+
+ if (args.size() < 4) {
+ status.SetError("sub-command FILTER requires a mode to be specified.");
+ return false;
+ }
+
+ const std::string& op = args[2];
+ bool includeMatches;
+ if (op == "INCLUDE") {
+ includeMatches = true;
+ } else if (op == "EXCLUDE") {
+ includeMatches = false;
+ } else {
+ status.SetError("sub-command FILTER does not recognize operator " + op);
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
+ return true;
+ }
+
+ const std::string& mode = args[3];
+ if (mode == "REGEX") {
+ if (args.size() != 5) {
+ status.SetError("sub-command FILTER, mode REGEX "
+ "requires five arguments.");
+ return false;
+ }
+ return FilterRegex(args, includeMatches, listName, varArgsExpanded,
+ status);
+ }
+
+ status.SetError("sub-command FILTER does not recognize mode " + mode);
+ return false;
+}
+
+class MatchesRegex
+{
+public:
+ MatchesRegex(cmsys::RegularExpression& in_regex, bool in_includeMatches)
+ : regex(in_regex)
+ , includeMatches(in_includeMatches)
+ {
+ }
+
+ bool operator()(const std::string& target)
+ {
+ return this->regex.find(target) ^ this->includeMatches;
+ }
+
+private:
+ cmsys::RegularExpression& regex;
+ const bool includeMatches;
+};
+
+bool FilterRegex(std::vector<std::string> const& args, bool includeMatches,
+ std::string const& listName,
+ std::vector<std::string>& varArgsExpanded,
+ cmExecutionStatus& status)
+{
+ const std::string& pattern = args[4];
+ cmsys::RegularExpression regex(pattern);
+ if (!regex.is_valid()) {
+ std::string error =
+ cmStrCat("sub-command FILTER, mode REGEX failed to compile regex \"",
+ pattern, "\".");
+ status.SetError(error);
+ return false;
+ }
+
+ auto argsBegin = varArgsExpanded.begin();
+ auto argsEnd = varArgsExpanded.end();
+ auto newArgsEnd =
+ std::remove_if(argsBegin, argsEnd, MatchesRegex(regex, includeMatches));
+
+ std::string value = cmJoin(cmMakeRange(argsBegin, newArgsEnd), ";");
+ status.GetMakefile().AddDefinition(listName, value);
+ return true;
+}
+
+} // namespace
+
+bool cmListCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("must be called with at least two arguments.");
+ return false;
+ }
+
+ static cmSubcommandTable const subcommand{
+ { "LENGTH"_s, HandleLengthCommand },
+ { "GET"_s, HandleGetCommand },
+ { "APPEND"_s, HandleAppendCommand },
+ { "PREPEND"_s, HandlePrependCommand },
+ { "POP_BACK"_s, HandlePopBackCommand },
+ { "POP_FRONT"_s, HandlePopFrontCommand },
+ { "FIND"_s, HandleFindCommand },
+ { "INSERT"_s, HandleInsertCommand },
+ { "JOIN"_s, HandleJoinCommand },
+ { "REMOVE_AT"_s, HandleRemoveAtCommand },
+ { "REMOVE_ITEM"_s, HandleRemoveItemCommand },
+ { "REMOVE_DUPLICATES"_s, HandleRemoveDuplicatesCommand },
+ { "TRANSFORM"_s, HandleTransformCommand },
+ { "SORT"_s, HandleSortCommand },
+ { "SUBLIST"_s, HandleSublistCommand },
+ { "REVERSE"_s, HandleReverseCommand },
+ { "FILTER"_s, HandleFilterCommand },
+ };
+
+ return subcommand(args[0], args, status);
+}
diff --git a/Source/cmListCommand.h b/Source/cmListCommand.h
new file mode 100644
index 0000000..6efab16
--- /dev/null
+++ b/Source/cmListCommand.h
@@ -0,0 +1,17 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Common list operations
+ *
+ */
+bool cmListCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
new file mode 100644
index 0000000..5c3a034
--- /dev/null
+++ b/Source/cmListFileCache.cxx
@@ -0,0 +1,654 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmListFileCache.h"
+
+#include <cassert>
+#include <memory>
+#include <sstream>
+#include <utility>
+
+#ifdef _WIN32
+# include <cmsys/Encoding.hxx>
+#endif
+
+#include "cmListFileLexer.h"
+#include "cmMessageType.h"
+#include "cmMessenger.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+struct cmListFileParser
+{
+ cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt,
+ cmMessenger* messenger);
+ ~cmListFileParser();
+ cmListFileParser(const cmListFileParser&) = delete;
+ cmListFileParser& operator=(const cmListFileParser&) = delete;
+ void IssueFileOpenError(std::string const& text) const;
+ void IssueError(std::string const& text) const;
+ bool ParseFile(const char* filename);
+ bool ParseString(const char* str, const char* virtual_filename);
+ bool Parse();
+ bool ParseFunction(const char* name, long line);
+ bool AddArgument(cmListFileLexer_Token* token,
+ cmListFileArgument::Delimiter delim);
+ cm::optional<cmListFileContext> CheckNesting() const;
+ cmListFile* ListFile;
+ cmListFileBacktrace Backtrace;
+ cmMessenger* Messenger;
+ const char* FileName;
+ cmListFileLexer* Lexer;
+ std::string FunctionName;
+ long FunctionLine;
+ std::vector<cmListFileArgument> FunctionArguments;
+ enum
+ {
+ SeparationOkay,
+ SeparationWarning,
+ SeparationError
+ } Separation;
+};
+
+cmListFileParser::cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt,
+ cmMessenger* messenger)
+ : ListFile(lf)
+ , Backtrace(std::move(lfbt))
+ , Messenger(messenger)
+ , FileName(nullptr)
+ , Lexer(cmListFileLexer_New())
+{
+}
+
+cmListFileParser::~cmListFileParser()
+{
+ cmListFileLexer_Delete(this->Lexer);
+}
+
+void cmListFileParser::IssueFileOpenError(const std::string& text) const
+{
+ this->Messenger->IssueMessage(MessageType::FATAL_ERROR, text,
+ this->Backtrace);
+}
+
+void cmListFileParser::IssueError(const std::string& text) const
+{
+ cmListFileContext lfc;
+ lfc.FilePath = this->FileName;
+ lfc.Line = cmListFileLexer_GetCurrentLine(this->Lexer);
+ cmListFileBacktrace lfbt = this->Backtrace;
+ lfbt = lfbt.Push(lfc);
+ this->Messenger->IssueMessage(MessageType::FATAL_ERROR, text, lfbt);
+ cmSystemTools::SetFatalErrorOccured();
+}
+
+bool cmListFileParser::ParseFile(const char* filename)
+{
+ this->FileName = filename;
+
+#ifdef _WIN32
+ std::string expandedFileName = cmsys::Encoding::ToNarrow(
+ cmSystemTools::ConvertToWindowsExtendedPath(filename));
+ filename = expandedFileName.c_str();
+#endif
+
+ // Open the file.
+ cmListFileLexer_BOM bom;
+ if (!cmListFileLexer_SetFileName(this->Lexer, filename, &bom)) {
+ this->IssueFileOpenError("cmListFileCache: error can not open file.");
+ return false;
+ }
+
+ if (bom == cmListFileLexer_BOM_Broken) {
+ cmListFileLexer_SetFileName(this->Lexer, nullptr, nullptr);
+ this->IssueFileOpenError("Error while reading Byte-Order-Mark. "
+ "File not seekable?");
+ return false;
+ }
+
+ // Verify the Byte-Order-Mark, if any.
+ if (bom != cmListFileLexer_BOM_None && bom != cmListFileLexer_BOM_UTF8) {
+ cmListFileLexer_SetFileName(this->Lexer, nullptr, nullptr);
+ this->IssueFileOpenError(
+ "File starts with a Byte-Order-Mark that is not UTF-8.");
+ return false;
+ }
+
+ return this->Parse();
+}
+
+bool cmListFileParser::ParseString(const char* str,
+ const char* virtual_filename)
+{
+ this->FileName = virtual_filename;
+
+ if (!cmListFileLexer_SetString(this->Lexer, str)) {
+ this->IssueFileOpenError("cmListFileCache: cannot allocate buffer.");
+ return false;
+ }
+
+ return this->Parse();
+}
+
+bool cmListFileParser::Parse()
+{
+ // Use a simple recursive-descent parser to process the token
+ // stream.
+ bool haveNewline = true;
+ while (cmListFileLexer_Token* token = cmListFileLexer_Scan(this->Lexer)) {
+ if (token->type == cmListFileLexer_Token_Space) {
+ } else if (token->type == cmListFileLexer_Token_Newline) {
+ haveNewline = true;
+ } else if (token->type == cmListFileLexer_Token_CommentBracket) {
+ haveNewline = false;
+ } else if (token->type == cmListFileLexer_Token_Identifier) {
+ if (haveNewline) {
+ haveNewline = false;
+ if (this->ParseFunction(token->text, token->line)) {
+ this->ListFile->Functions.emplace_back(
+ std::move(this->FunctionName), this->FunctionLine,
+ std::move(this->FunctionArguments));
+ } else {
+ return false;
+ }
+ } else {
+ std::ostringstream error;
+ error << "Parse error. Expected a newline, got "
+ << cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
+ << " with text \"" << token->text << "\".";
+ this->IssueError(error.str());
+ return false;
+ }
+ } else {
+ std::ostringstream error;
+ error << "Parse error. Expected a command name, got "
+ << cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
+ << " with text \"" << token->text << "\".";
+ this->IssueError(error.str());
+ return false;
+ }
+ }
+
+ // Check if all functions are nested properly.
+ if (auto badNesting = this->CheckNesting()) {
+ this->Messenger->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Flow control statements are not properly nested.",
+ this->Backtrace.Push(*badNesting));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ return true;
+}
+
+bool cmListFile::ParseFile(const char* filename, cmMessenger* messenger,
+ cmListFileBacktrace const& lfbt)
+{
+ if (!cmSystemTools::FileExists(filename) ||
+ cmSystemTools::FileIsDirectory(filename)) {
+ return false;
+ }
+
+ bool parseError = false;
+
+ {
+ cmListFileParser parser(this, lfbt, messenger);
+ parseError = !parser.ParseFile(filename);
+ }
+
+ return !parseError;
+}
+
+bool cmListFile::ParseString(const char* str, const char* virtual_filename,
+ cmMessenger* messenger,
+ const cmListFileBacktrace& lfbt)
+{
+ bool parseError = false;
+
+ {
+ cmListFileParser parser(this, lfbt, messenger);
+ parseError = !parser.ParseString(str, virtual_filename);
+ }
+
+ return !parseError;
+}
+
+bool cmListFileParser::ParseFunction(const char* name, long line)
+{
+ // Ininitialize a new function call.
+ this->FunctionName = name;
+ this->FunctionLine = line;
+
+ // Command name has already been parsed. Read the left paren.
+ cmListFileLexer_Token* token;
+ while ((token = cmListFileLexer_Scan(this->Lexer)) &&
+ token->type == cmListFileLexer_Token_Space) {
+ }
+ if (!token) {
+ std::ostringstream error;
+ /* clang-format off */
+ error << "Unexpected end of file.\n"
+ << "Parse error. Function missing opening \"(\".";
+ /* clang-format on */
+ this->IssueError(error.str());
+ return false;
+ }
+ if (token->type != cmListFileLexer_Token_ParenLeft) {
+ std::ostringstream error;
+ error << "Parse error. Expected \"(\", got "
+ << cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
+ << " with text \"" << token->text << "\".";
+ this->IssueError(error.str());
+ return false;
+ }
+
+ // Arguments.
+ unsigned long parenDepth = 0;
+ this->Separation = SeparationOkay;
+ while ((token = cmListFileLexer_Scan(this->Lexer))) {
+ if (token->type == cmListFileLexer_Token_Space ||
+ token->type == cmListFileLexer_Token_Newline) {
+ this->Separation = SeparationOkay;
+ continue;
+ }
+ if (token->type == cmListFileLexer_Token_ParenLeft) {
+ parenDepth++;
+ this->Separation = SeparationOkay;
+ if (!this->AddArgument(token, cmListFileArgument::Unquoted)) {
+ return false;
+ }
+ } else if (token->type == cmListFileLexer_Token_ParenRight) {
+ if (parenDepth == 0) {
+ return true;
+ }
+ parenDepth--;
+ this->Separation = SeparationOkay;
+ if (!this->AddArgument(token, cmListFileArgument::Unquoted)) {
+ return false;
+ }
+ this->Separation = SeparationWarning;
+ } else if (token->type == cmListFileLexer_Token_Identifier ||
+ token->type == cmListFileLexer_Token_ArgumentUnquoted) {
+ if (!this->AddArgument(token, cmListFileArgument::Unquoted)) {
+ return false;
+ }
+ this->Separation = SeparationWarning;
+ } else if (token->type == cmListFileLexer_Token_ArgumentQuoted) {
+ if (!this->AddArgument(token, cmListFileArgument::Quoted)) {
+ return false;
+ }
+ this->Separation = SeparationWarning;
+ } else if (token->type == cmListFileLexer_Token_ArgumentBracket) {
+ if (!this->AddArgument(token, cmListFileArgument::Bracket)) {
+ return false;
+ }
+ this->Separation = SeparationError;
+ } else if (token->type == cmListFileLexer_Token_CommentBracket) {
+ this->Separation = SeparationError;
+ } else {
+ // Error.
+ std::ostringstream error;
+ error << "Parse error. Function missing ending \")\". "
+ << "Instead found "
+ << cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
+ << " with text \"" << token->text << "\".";
+ this->IssueError(error.str());
+ return false;
+ }
+ }
+
+ std::ostringstream error;
+ cmListFileContext lfc;
+ lfc.FilePath = this->FileName;
+ lfc.Line = line;
+ cmListFileBacktrace lfbt = this->Backtrace;
+ lfbt = lfbt.Push(lfc);
+ error << "Parse error. Function missing ending \")\". "
+ << "End of file reached.";
+ this->Messenger->IssueMessage(MessageType::FATAL_ERROR, error.str(), lfbt);
+ return false;
+}
+
+bool cmListFileParser::AddArgument(cmListFileLexer_Token* token,
+ cmListFileArgument::Delimiter delim)
+{
+ this->FunctionArguments.emplace_back(token->text, delim, token->line);
+ if (this->Separation == SeparationOkay) {
+ return true;
+ }
+ bool isError = (this->Separation == SeparationError ||
+ delim == cmListFileArgument::Bracket);
+ std::ostringstream m;
+ cmListFileContext lfc;
+ lfc.FilePath = this->FileName;
+ lfc.Line = token->line;
+ cmListFileBacktrace lfbt = this->Backtrace;
+ lfbt = lfbt.Push(lfc);
+
+ m << "Syntax " << (isError ? "Error" : "Warning") << " in cmake code at "
+ << "column " << token->column << "\n"
+ << "Argument not separated from preceding token by whitespace.";
+ /* clang-format on */
+ if (isError) {
+ this->Messenger->IssueMessage(MessageType::FATAL_ERROR, m.str(), lfbt);
+ return false;
+ }
+ this->Messenger->IssueMessage(MessageType::AUTHOR_WARNING, m.str(), lfbt);
+ return true;
+}
+
+namespace {
+enum class NestingStateEnum
+{
+ If,
+ Else,
+ While,
+ Foreach,
+ Function,
+ Macro,
+};
+
+struct NestingState
+{
+ NestingStateEnum State;
+ cmListFileContext Context;
+};
+
+bool TopIs(std::vector<NestingState>& stack, NestingStateEnum state)
+{
+ return !stack.empty() && stack.back().State == state;
+}
+}
+
+cm::optional<cmListFileContext> cmListFileParser::CheckNesting() const
+{
+ std::vector<NestingState> stack;
+
+ for (auto const& func : this->ListFile->Functions) {
+ auto const& name = func.LowerCaseName();
+ if (name == "if") {
+ stack.push_back({
+ NestingStateEnum::If,
+ cmListFileContext::FromCommandContext(func, this->FileName),
+ });
+ } else if (name == "elseif") {
+ if (!TopIs(stack, NestingStateEnum::If)) {
+ return cmListFileContext::FromCommandContext(func, this->FileName);
+ }
+ stack.back() = {
+ NestingStateEnum::If,
+ cmListFileContext::FromCommandContext(func, this->FileName),
+ };
+ } else if (name == "else") {
+ if (!TopIs(stack, NestingStateEnum::If)) {
+ return cmListFileContext::FromCommandContext(func, this->FileName);
+ }
+ stack.back() = {
+ NestingStateEnum::Else,
+ cmListFileContext::FromCommandContext(func, this->FileName),
+ };
+ } else if (name == "endif") {
+ if (!TopIs(stack, NestingStateEnum::If) &&
+ !TopIs(stack, NestingStateEnum::Else)) {
+ return cmListFileContext::FromCommandContext(func, this->FileName);
+ }
+ stack.pop_back();
+ } else if (name == "while") {
+ stack.push_back({
+ NestingStateEnum::While,
+ cmListFileContext::FromCommandContext(func, this->FileName),
+ });
+ } else if (name == "endwhile") {
+ if (!TopIs(stack, NestingStateEnum::While)) {
+ return cmListFileContext::FromCommandContext(func, this->FileName);
+ }
+ stack.pop_back();
+ } else if (name == "foreach") {
+ stack.push_back({
+ NestingStateEnum::Foreach,
+ cmListFileContext::FromCommandContext(func, this->FileName),
+ });
+ } else if (name == "endforeach") {
+ if (!TopIs(stack, NestingStateEnum::Foreach)) {
+ return cmListFileContext::FromCommandContext(func, this->FileName);
+ }
+ stack.pop_back();
+ } else if (name == "function") {
+ stack.push_back({
+ NestingStateEnum::Function,
+ cmListFileContext::FromCommandContext(func, this->FileName),
+ });
+ } else if (name == "endfunction") {
+ if (!TopIs(stack, NestingStateEnum::Function)) {
+ return cmListFileContext::FromCommandContext(func, this->FileName);
+ }
+ stack.pop_back();
+ } else if (name == "macro") {
+ stack.push_back({
+ NestingStateEnum::Macro,
+ cmListFileContext::FromCommandContext(func, this->FileName),
+ });
+ } else if (name == "endmacro") {
+ if (!TopIs(stack, NestingStateEnum::Macro)) {
+ return cmListFileContext::FromCommandContext(func, this->FileName);
+ }
+ stack.pop_back();
+ }
+ }
+
+ if (!stack.empty()) {
+ return stack.back().Context;
+ }
+
+ return cm::nullopt;
+}
+
+// We hold either the bottom scope of a directory or a call/file context.
+// Discriminate these cases via the parent pointer.
+struct cmListFileBacktrace::Entry
+{
+ Entry(cmStateSnapshot bottom)
+ : Bottom(bottom)
+ {
+ }
+
+ Entry(std::shared_ptr<Entry const> parent, cmListFileContext lfc)
+ : Context(std::move(lfc))
+ , Parent(std::move(parent))
+ {
+ }
+
+ ~Entry()
+ {
+ if (this->Parent) {
+ this->Context.~cmListFileContext();
+ } else {
+ this->Bottom.~cmStateSnapshot();
+ }
+ }
+
+ bool IsBottom() const { return !this->Parent; }
+
+ union
+ {
+ cmStateSnapshot Bottom;
+ cmListFileContext Context;
+ };
+ std::shared_ptr<Entry const> Parent;
+};
+
+cmListFileBacktrace::cmListFileBacktrace(cmStateSnapshot const& snapshot)
+ : TopEntry(std::make_shared<Entry const>(snapshot.GetCallStackBottom()))
+{
+}
+
+/* NOLINTNEXTLINE(performance-unnecessary-value-param) */
+cmListFileBacktrace::cmListFileBacktrace(std::shared_ptr<Entry const> parent,
+ cmListFileContext const& lfc)
+ : TopEntry(std::make_shared<Entry const>(std::move(parent), lfc))
+{
+}
+
+cmListFileBacktrace::cmListFileBacktrace(std::shared_ptr<Entry const> top)
+ : TopEntry(std::move(top))
+{
+}
+
+cmStateSnapshot cmListFileBacktrace::GetBottom() const
+{
+ cmStateSnapshot bottom;
+ if (Entry const* cur = this->TopEntry.get()) {
+ while (Entry const* parent = cur->Parent.get()) {
+ cur = parent;
+ }
+ bottom = cur->Bottom;
+ }
+ return bottom;
+}
+
+cmListFileBacktrace cmListFileBacktrace::Push(std::string const& file) const
+{
+ // We are entering a file-level scope but have not yet reached
+ // any specific line or command invocation within it. This context
+ // is useful to print when it is at the top but otherwise can be
+ // skipped during call stack printing.
+ cmListFileContext lfc;
+ lfc.FilePath = file;
+ return this->Push(lfc);
+}
+
+cmListFileBacktrace cmListFileBacktrace::Push(
+ cmListFileContext const& lfc) const
+{
+ assert(this->TopEntry);
+ assert(!this->TopEntry->IsBottom() || this->TopEntry->Bottom.IsValid());
+ return cmListFileBacktrace(this->TopEntry, lfc);
+}
+
+cmListFileBacktrace cmListFileBacktrace::Pop() const
+{
+ assert(this->TopEntry);
+ assert(!this->TopEntry->IsBottom());
+ return cmListFileBacktrace(this->TopEntry->Parent);
+}
+
+cmListFileContext const& cmListFileBacktrace::Top() const
+{
+ assert(this->TopEntry);
+ assert(!this->TopEntry->IsBottom());
+ return this->TopEntry->Context;
+}
+
+void cmListFileBacktrace::PrintTitle(std::ostream& out) const
+{
+ // The title exists only if we have a call on top of the bottom.
+ if (!this->TopEntry || this->TopEntry->IsBottom()) {
+ return;
+ }
+ cmListFileContext lfc = this->TopEntry->Context;
+ cmStateSnapshot bottom = this->GetBottom();
+ if (!bottom.GetState()->GetIsInTryCompile()) {
+ lfc.FilePath = bottom.GetDirectory().ConvertToRelPathIfNotContained(
+ bottom.GetState()->GetSourceDirectory(), lfc.FilePath);
+ }
+ out << (lfc.Line ? " at " : " in ") << lfc;
+}
+
+void cmListFileBacktrace::PrintCallStack(std::ostream& out) const
+{
+ // The call stack exists only if we have at least two calls on top
+ // of the bottom.
+ if (!this->TopEntry || this->TopEntry->IsBottom() ||
+ this->TopEntry->Parent->IsBottom()) {
+ return;
+ }
+
+ bool first = true;
+ cmStateSnapshot bottom = this->GetBottom();
+ for (Entry const* cur = this->TopEntry->Parent.get(); !cur->IsBottom();
+ cur = cur->Parent.get()) {
+ 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;
+ }
+ if (first) {
+ first = false;
+ out << "Call Stack (most recent call first):\n";
+ }
+ cmListFileContext lfc = cur->Context;
+ if (!bottom.GetState()->GetIsInTryCompile()) {
+ lfc.FilePath = bottom.GetDirectory().ConvertToRelPathIfNotContained(
+ bottom.GetState()->GetSourceDirectory(), lfc.FilePath);
+ }
+ out << " " << lfc << "\n";
+ }
+}
+
+size_t cmListFileBacktrace::Depth() const
+{
+ size_t depth = 0;
+ if (Entry const* cur = this->TopEntry.get()) {
+ for (; !cur->IsBottom(); cur = cur->Parent.get()) {
+ ++depth;
+ }
+ }
+ return depth;
+}
+
+bool cmListFileBacktrace::Empty() const
+{
+ return !this->TopEntry || this->TopEntry->IsBottom();
+}
+
+std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc)
+{
+ os << lfc.FilePath;
+ if (lfc.Line > 0) {
+ os << ":" << lfc.Line;
+ if (!lfc.Name.empty()) {
+ os << " (" << lfc.Name << ")";
+ }
+ } else if (lfc.Line == cmListFileContext::DeferPlaceholderLine) {
+ os << ":DEFERRED";
+ }
+ return os;
+}
+
+bool operator<(const cmListFileContext& lhs, const cmListFileContext& rhs)
+{
+ if (lhs.Line != rhs.Line) {
+ return lhs.Line < rhs.Line;
+ }
+ return lhs.FilePath < rhs.FilePath;
+}
+
+bool operator==(const cmListFileContext& lhs, const cmListFileContext& rhs)
+{
+ return lhs.Line == rhs.Line && lhs.FilePath == rhs.FilePath;
+}
+
+bool operator!=(const cmListFileContext& lhs, const cmListFileContext& rhs)
+{
+ return !(lhs == rhs);
+}
+
+std::ostream& operator<<(std::ostream& os, BT<std::string> const& s)
+{
+ return os << s.Value;
+}
+
+std::vector<BT<std::string>> ExpandListWithBacktrace(
+ std::string const& list, cmListFileBacktrace const& bt)
+{
+ std::vector<BT<std::string>> result;
+ std::vector<std::string> tmp = cmExpandedList(list);
+ result.reserve(tmp.size());
+ for (std::string& i : tmp) {
+ result.emplace_back(std::move(i), bt);
+ }
+ return result;
+}
diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h
new file mode 100644
index 0000000..98cb4a7
--- /dev/null
+++ b/Source/cmListFileCache.h
@@ -0,0 +1,281 @@
+/* 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 <cstddef>
+#include <iosfwd>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+
+#include "cmStateSnapshot.h"
+#include "cmSystemTools.h"
+
+/** \class cmListFileCache
+ * \brief A class to cache list file contents.
+ *
+ * cmListFileCache is a class used to cache the contents of parsed
+ * cmake list files.
+ */
+
+class cmMessenger;
+
+struct cmCommandContext
+{
+ struct cmCommandName
+ {
+ std::string Original;
+ std::string Lower;
+ cmCommandName() = default;
+ cmCommandName(std::string name)
+ : Original(std::move(name))
+ , Lower(cmSystemTools::LowerCase(this->Original))
+ {
+ }
+ } Name;
+ long Line = 0;
+ cmCommandContext() = default;
+ cmCommandContext(std::string name, long line)
+ : Name(std::move(name))
+ , Line(line)
+ {
+ }
+};
+
+struct cmListFileArgument
+{
+ enum Delimiter
+ {
+ Unquoted,
+ Quoted,
+ Bracket
+ };
+ cmListFileArgument() = default;
+ cmListFileArgument(std::string v, Delimiter d, long line)
+ : Value(std::move(v))
+ , Delim(d)
+ , Line(line)
+ {
+ }
+ bool operator==(const cmListFileArgument& r) const
+ {
+ return (this->Value == r.Value) && (this->Delim == r.Delim);
+ }
+ bool operator!=(const cmListFileArgument& r) const { return !(*this == r); }
+ std::string Value;
+ Delimiter Delim = Unquoted;
+ long Line = 0;
+};
+
+class cmListFileContext
+{
+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)
+ {
+ }
+
+#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
+ cmListFileContext(const cmListFileContext& /*other*/) = default;
+ cmListFileContext(cmListFileContext&& /*other*/) = default;
+
+ cmListFileContext& operator=(const cmListFileContext& /*other*/) = default;
+ cmListFileContext& operator=(cmListFileContext&& /*other*/) = delete;
+#endif
+
+ 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;
+ }
+};
+
+std::ostream& operator<<(std::ostream&, cmListFileContext const&);
+bool operator<(const cmListFileContext& lhs, const cmListFileContext& rhs);
+bool operator==(cmListFileContext const& lhs, cmListFileContext const& rhs);
+bool operator!=(cmListFileContext const& lhs, cmListFileContext const& rhs);
+
+class cmListFileFunction
+{
+public:
+ cmListFileFunction(std::string name, long line,
+ std::vector<cmListFileArgument> args)
+ : Impl{ std::make_shared<Implementation>(std::move(name), line,
+ std::move(args)) }
+ {
+ }
+
+ std::string const& OriginalName() const noexcept
+ {
+ return this->Impl->Name.Original;
+ }
+
+ std::string const& LowerCaseName() const noexcept
+ {
+ return this->Impl->Name.Lower;
+ }
+
+ long Line() const noexcept { return this->Impl->Line; }
+
+ std::vector<cmListFileArgument> const& Arguments() const noexcept
+ {
+ return this->Impl->Arguments;
+ }
+
+ operator cmCommandContext const&() const noexcept { return *this->Impl; }
+
+private:
+ struct Implementation : public cmCommandContext
+ {
+ Implementation(std::string name, long line,
+ std::vector<cmListFileArgument> args)
+ : cmCommandContext{ std::move(name), line }
+ , Arguments{ std::move(args) }
+ {
+ }
+ std::vector<cmListFileArgument> Arguments;
+ };
+
+ std::shared_ptr<Implementation const> Impl;
+};
+
+// Represent a backtrace (call stack). Provide value semantics
+// but use efficient reference-counting underneath to avoid copies.
+class cmListFileBacktrace
+{
+public:
+ // Default-constructed backtrace may not be used until after
+ // set via assignment from a backtrace constructed with a
+ // valid snapshot.
+ cmListFileBacktrace() = default;
+
+ // Construct an empty backtrace whose bottom sits in the directory
+ // indicated by the given valid snapshot.
+ cmListFileBacktrace(cmStateSnapshot const& snapshot);
+
+ cmStateSnapshot GetBottom() const;
+
+ // Get a backtrace with the given file scope added to the top.
+ // May not be called until after construction with a valid snapshot.
+ cmListFileBacktrace Push(std::string const& file) const;
+
+ // Get a backtrace with the given call context added to the top.
+ // May not be called until after construction with a valid snapshot.
+ cmListFileBacktrace Push(cmListFileContext const& lfc) const;
+
+ // Get a backtrace with the top level removed.
+ // May not be called until after a matching Push.
+ cmListFileBacktrace Pop() const;
+
+ // Get the context at the top of the backtrace.
+ // This may be called only if Empty() would return false.
+ cmListFileContext const& Top() const;
+
+ // Print the top of the backtrace.
+ void PrintTitle(std::ostream& out) const;
+
+ // Print the call stack below the top of the backtrace.
+ void PrintCallStack(std::ostream& out) const;
+
+ // Get the number of 'frames' in this backtrace
+ size_t Depth() const;
+
+ // Return true if this backtrace is empty.
+ bool Empty() const;
+
+private:
+ struct Entry;
+ std::shared_ptr<Entry const> TopEntry;
+ cmListFileBacktrace(std::shared_ptr<Entry const> parent,
+ cmListFileContext const& lfc);
+ cmListFileBacktrace(std::shared_ptr<Entry const> top);
+};
+
+// Wrap type T as a value with a backtrace. For purposes of
+// ordering and equality comparison, only the original value is
+// used. The backtrace is considered incidental.
+template <typename T>
+class BT
+{
+public:
+ BT(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace())
+ : Value(std::move(v))
+ , Backtrace(std::move(bt))
+ {
+ }
+ T Value;
+ cmListFileBacktrace Backtrace;
+ friend bool operator==(BT<T> const& l, BT<T> const& r)
+ {
+ return l.Value == r.Value;
+ }
+ friend bool operator<(BT<T> const& l, BT<T> const& r)
+ {
+ return l.Value < r.Value;
+ }
+ friend bool operator==(BT<T> const& l, T const& r) { return l.Value == r; }
+ friend bool operator==(T const& l, BT<T> const& r) { return l == r.Value; }
+};
+
+std::ostream& operator<<(std::ostream& os, BT<std::string> const& s);
+
+// Wrap type T as a value with potentially multiple backtraces. For purposes
+// of ordering and equality comparison, only the original value is used. The
+// backtrace is considered incidental.
+template <typename T>
+class BTs
+{
+public:
+ BTs(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace())
+ : Value(std::move(v))
+ {
+ this->Backtraces.emplace_back(std::move(bt));
+ }
+ T Value;
+ std::vector<cmListFileBacktrace> Backtraces;
+ friend bool operator==(BTs<T> const& l, BTs<T> const& r)
+ {
+ return l.Value == r.Value;
+ }
+ friend bool operator<(BTs<T> const& l, BTs<T> const& r)
+ {
+ return l.Value < r.Value;
+ }
+ friend bool operator==(BTs<T> const& l, T const& r) { return l.Value == r; }
+ friend bool operator==(T const& l, BTs<T> const& r) { return l == r.Value; }
+};
+
+std::vector<BT<std::string>> ExpandListWithBacktrace(
+ std::string const& list,
+ cmListFileBacktrace const& bt = cmListFileBacktrace());
+
+struct cmListFile
+{
+ bool ParseFile(const char* path, cmMessenger* messenger,
+ cmListFileBacktrace const& lfbt);
+
+ bool ParseString(const char* str, const char* virtual_filename,
+ cmMessenger* messenger, cmListFileBacktrace const& lfbt);
+
+ std::vector<cmListFileFunction> Functions;
+};
diff --git a/Source/cmListFileLexer.h b/Source/cmListFileLexer.h
new file mode 100644
index 0000000..3c89f63
--- /dev/null
+++ b/Source/cmListFileLexer.h
@@ -0,0 +1,68 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* NOLINTNEXTLINE(modernize-use-using) */
+typedef enum cmListFileLexer_Type_e
+{
+ cmListFileLexer_Token_None,
+ cmListFileLexer_Token_Space,
+ cmListFileLexer_Token_Newline,
+ cmListFileLexer_Token_Identifier,
+ cmListFileLexer_Token_ParenLeft,
+ cmListFileLexer_Token_ParenRight,
+ cmListFileLexer_Token_ArgumentUnquoted,
+ cmListFileLexer_Token_ArgumentQuoted,
+ cmListFileLexer_Token_ArgumentBracket,
+ cmListFileLexer_Token_CommentBracket,
+ cmListFileLexer_Token_BadCharacter,
+ cmListFileLexer_Token_BadBracket,
+ cmListFileLexer_Token_BadString
+} cmListFileLexer_Type;
+
+/* NOLINTNEXTLINE(modernize-use-using) */
+typedef struct cmListFileLexer_Token_s cmListFileLexer_Token;
+struct cmListFileLexer_Token_s
+{
+ cmListFileLexer_Type type;
+ char* text;
+ int length;
+ int line;
+ int column;
+};
+
+enum cmListFileLexer_BOM_e
+{
+ cmListFileLexer_BOM_None,
+ cmListFileLexer_BOM_Broken,
+ cmListFileLexer_BOM_UTF8,
+ cmListFileLexer_BOM_UTF16BE,
+ cmListFileLexer_BOM_UTF16LE,
+ cmListFileLexer_BOM_UTF32BE,
+ cmListFileLexer_BOM_UTF32LE
+};
+
+/* NOLINTNEXTLINE(modernize-use-using) */
+typedef enum cmListFileLexer_BOM_e cmListFileLexer_BOM;
+
+/* NOLINTNEXTLINE(modernize-use-using) */
+typedef struct cmListFileLexer_s cmListFileLexer;
+
+cmListFileLexer* cmListFileLexer_New(void);
+int cmListFileLexer_SetFileName(cmListFileLexer*, const char*,
+ cmListFileLexer_BOM* bom);
+int cmListFileLexer_SetString(cmListFileLexer*, const char*);
+cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer*);
+long cmListFileLexer_GetCurrentLine(cmListFileLexer*);
+long cmListFileLexer_GetCurrentColumn(cmListFileLexer*);
+const char* cmListFileLexer_GetTypeAsString(cmListFileLexer*,
+ cmListFileLexer_Type);
+void cmListFileLexer_Delete(cmListFileLexer*);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
diff --git a/Source/cmLoadCacheCommand.cxx b/Source/cmLoadCacheCommand.cxx
new file mode 100644
index 0000000..d49e711
--- /dev/null
+++ b/Source/cmLoadCacheCommand.cxx
@@ -0,0 +1,183 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmLoadCacheCommand.h"
+
+#include <set>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+static bool ReadWithPrefix(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
+
+static void CheckLine(cmMakefile& mf, std::string const& prefix,
+ std::set<std::string> const& variablesToRead,
+ const char* line);
+
+bool cmLoadCacheCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with wrong number of arguments.");
+ return false;
+ }
+
+ if (args.size() >= 2 && args[1] == "READ_WITH_PREFIX") {
+ return ReadWithPrefix(args, status);
+ }
+
+ if (status.GetMakefile().GetCMakeInstance()->GetWorkingMode() ==
+ cmake::SCRIPT_MODE) {
+ status.SetError(
+ "Only load_cache(READ_WITH_PREFIX) may be used in script mode");
+ return false;
+ }
+
+ // Cache entries to be excluded from the import list.
+ // If this set is empty, all cache entries are brought in
+ // and they can not be overridden.
+ bool excludeFiles = false;
+ std::set<std::string> excludes;
+
+ for (std::string const& arg : args) {
+ if (excludeFiles) {
+ excludes.insert(arg);
+ }
+ if (arg == "EXCLUDE") {
+ excludeFiles = true;
+ }
+ if (excludeFiles && (arg == "INCLUDE_INTERNALS")) {
+ break;
+ }
+ }
+
+ // Internal cache entries to be imported.
+ // If this set is empty, no internal cache entries are
+ // brought in.
+ bool includeFiles = false;
+ std::set<std::string> includes;
+
+ for (std::string const& arg : args) {
+ if (includeFiles) {
+ includes.insert(arg);
+ }
+ if (arg == "INCLUDE_INTERNALS") {
+ includeFiles = true;
+ }
+ if (includeFiles && (arg == "EXCLUDE")) {
+ break;
+ }
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ // Loop over each build directory listed in the arguments. Each
+ // directory has a cache file.
+ for (std::string const& arg : args) {
+ if ((arg == "EXCLUDE") || (arg == "INCLUDE_INTERNALS")) {
+ break;
+ }
+ mf.GetCMakeInstance()->LoadCache(arg, false, excludes, includes);
+ }
+
+ return true;
+}
+
+static bool ReadWithPrefix(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // Make sure we have a prefix.
+ if (args.size() < 3) {
+ status.SetError("READ_WITH_PREFIX form must specify a prefix.");
+ return false;
+ }
+
+ // Make sure the cache file exists.
+ std::string cacheFile = args[0] + "/CMakeCache.txt";
+ if (!cmSystemTools::FileExists(cacheFile)) {
+ std::string e = "Cannot load cache file from " + cacheFile;
+ status.SetError(e);
+ return false;
+ }
+
+ // Prepare the table of variables to read.
+ std::string const prefix = args[2];
+ std::set<std::string> const variablesToRead(args.begin() + 3, args.end());
+
+ // Read the cache file.
+ cmsys::ifstream fin(cacheFile.c_str());
+
+ cmMakefile& mf = status.GetMakefile();
+
+ // This is a big hack read loop to overcome a buggy ifstream
+ // implementation on HP-UX. This should work on all platforms even
+ // for small buffer sizes.
+ const int bufferSize = 4096;
+ char buffer[bufferSize];
+ std::string line;
+ while (fin) {
+ // Read a block of the file.
+ fin.read(buffer, bufferSize);
+ if (fin.gcount()) {
+ // Parse for newlines directly.
+ const char* i = buffer;
+ const char* end = buffer + fin.gcount();
+ while (i != end) {
+ const char* begin = i;
+ while (i != end && *i != '\n') {
+ ++i;
+ }
+ if (i == begin || *(i - 1) != '\r') {
+ // Include this portion of the line.
+ line += std::string(begin, i - begin);
+ } else {
+ // Include this portion of the line.
+ // Don't include the \r in a \r\n pair.
+ line += std::string(begin, i - 1 - begin);
+ }
+ if (i != end) {
+ // Completed a line.
+ CheckLine(mf, prefix, variablesToRead, line.c_str());
+ line.clear();
+
+ // Skip the newline character.
+ ++i;
+ }
+ }
+ }
+ }
+ if (!line.empty()) {
+ // Partial last line.
+ CheckLine(mf, prefix, variablesToRead, line.c_str());
+ }
+
+ return true;
+}
+
+static void CheckLine(cmMakefile& mf, std::string const& prefix,
+ std::set<std::string> const& variablesToRead,
+ const char* line)
+{
+ // Check one line of the cache file.
+ std::string var;
+ std::string value;
+ cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
+ if (cmake::ParseCacheEntry(line, var, value, type)) {
+ // Found a real entry. See if this one was requested.
+ if (variablesToRead.find(var) != variablesToRead.end()) {
+ // This was requested. Set this variable locally with the given
+ // prefix.
+ var = prefix + var;
+ if (!value.empty()) {
+ mf.AddDefinition(var, value);
+ } else {
+ mf.RemoveDefinition(var);
+ }
+ }
+ }
+}
diff --git a/Source/cmLoadCacheCommand.h b/Source/cmLoadCacheCommand.h
new file mode 100644
index 0000000..5f5b705
--- /dev/null
+++ b/Source/cmLoadCacheCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmLoadCacheCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx
new file mode 100644
index 0000000..2981ef8
--- /dev/null
+++ b/Source/cmLoadCommandCommand.cxx
@@ -0,0 +1,271 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#if !defined(_WIN32) && !defined(__sun) && !defined(__OpenBSD__)
+// POSIX APIs are needed
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
+# define _POSIX_C_SOURCE 200809L
+#endif
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+// For isascii
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
+# define _XOPEN_SOURCE 700
+#endif
+
+#include "cmLoadCommandCommand.h"
+
+#include <csignal>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmCPluginAPI.h"
+#include "cmCommand.h"
+#include "cmDynamicLoader.h"
+#include "cmExecutionStatus.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+// NOLINTNEXTLINE(bugprone-suspicious-include)
+#include "cmCPluginAPI.cxx"
+
+#ifdef __QNX__
+# include <malloc.h> /* for malloc/free on QNX */
+#endif
+
+namespace {
+
+const char* LastName = nullptr;
+
+extern "C" void TrapsForSignals(int sig)
+{
+ fprintf(stderr, "CMake loaded command %s crashed with signal: %d.\n",
+ LastName, sig);
+}
+
+struct SignalHandlerGuard
+{
+ explicit SignalHandlerGuard(const char* name)
+ {
+ LastName = name != nullptr ? name : "????";
+
+ signal(SIGSEGV, TrapsForSignals);
+#ifdef SIGBUS
+ signal(SIGBUS, TrapsForSignals);
+#endif
+ signal(SIGILL, TrapsForSignals);
+ }
+
+ ~SignalHandlerGuard()
+ {
+ signal(SIGSEGV, nullptr);
+#ifdef SIGBUS
+ signal(SIGBUS, nullptr);
+#endif
+ signal(SIGILL, nullptr);
+ }
+
+ SignalHandlerGuard(SignalHandlerGuard const&) = delete;
+ SignalHandlerGuard& operator=(SignalHandlerGuard const&) = delete;
+};
+
+struct LoadedCommandImpl : cmLoadedCommandInfo
+{
+ explicit LoadedCommandImpl(CM_INIT_FUNCTION init)
+ : cmLoadedCommandInfo{ 0, 0, &cmStaticCAPI, 0,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr }
+ {
+ init(this);
+ }
+
+ ~LoadedCommandImpl()
+ {
+ if (this->Destructor) {
+ SignalHandlerGuard guard(this->Name);
+ this->Destructor(this);
+ }
+ if (this->Error != nullptr) {
+ free(this->Error);
+ }
+ }
+
+ LoadedCommandImpl(LoadedCommandImpl const&) = delete;
+ LoadedCommandImpl& operator=(LoadedCommandImpl const&) = delete;
+
+ int DoInitialPass(cmMakefile* mf, int argc, char* argv[])
+ {
+ SignalHandlerGuard guard(this->Name);
+ return this->InitialPass(this, mf, argc, argv);
+ }
+
+ void DoFinalPass(cmMakefile* mf)
+ {
+ SignalHandlerGuard guard(this->Name);
+ this->FinalPass(this, mf);
+ }
+};
+
+// a class for loadabple commands
+class cmLoadedCommand : public cmCommand
+{
+public:
+ cmLoadedCommand() = default;
+ explicit cmLoadedCommand(CM_INIT_FUNCTION init)
+ : Impl(std::make_shared<LoadedCommandImpl>(init))
+ {
+ }
+
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ auto newC = cm::make_unique<cmLoadedCommand>();
+ // we must copy when we clone
+ newC->Impl = this->Impl;
+ return std::unique_ptr<cmCommand>(std::move(newC));
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&) override;
+
+private:
+ std::shared_ptr<LoadedCommandImpl> Impl;
+};
+
+bool cmLoadedCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&)
+{
+ if (!this->Impl->InitialPass) {
+ return true;
+ }
+
+ // clear the error string
+ if (this->Impl->Error) {
+ free(this->Impl->Error);
+ }
+
+ // create argc and argv and then invoke the command
+ int argc = static_cast<int>(args.size());
+ char** argv = nullptr;
+ if (argc) {
+ argv = static_cast<char**>(malloc(argc * sizeof(char*)));
+ }
+ int i;
+ for (i = 0; i < argc; ++i) {
+ argv[i] = strdup(args[i].c_str());
+ }
+ int result = this->Impl->DoInitialPass(this->Makefile, argc, argv);
+ cmFreeArguments(argc, argv);
+
+ if (result) {
+ if (this->Impl->FinalPass) {
+ auto impl = this->Impl;
+ this->Makefile->AddGeneratorAction(
+ [impl](cmLocalGenerator& lg, const cmListFileBacktrace&) {
+ impl->DoFinalPass(lg.GetMakefile());
+ });
+ }
+ return true;
+ }
+
+ /* Initial Pass must have failed so set the error string */
+ if (this->Impl->Error) {
+ this->SetError(this->Impl->Error);
+ }
+ return false;
+}
+
+} // namespace
+
+// cmLoadCommandCommand
+bool cmLoadCommandCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ return true;
+ }
+
+ // Construct a variable to report what file was loaded, if any.
+ // Start by removing the definition in case of failure.
+ std::string reportVar = cmStrCat("CMAKE_LOADED_COMMAND_", args[0]);
+ status.GetMakefile().RemoveDefinition(reportVar);
+
+ // the file must exist
+ std::string moduleName = cmStrCat(
+ status.GetMakefile().GetRequiredDefinition("CMAKE_SHARED_MODULE_PREFIX"),
+ "cm", args[0],
+ status.GetMakefile().GetRequiredDefinition("CMAKE_SHARED_MODULE_SUFFIX"));
+
+ // search for the file
+ std::vector<std::string> path;
+ for (unsigned int j = 1; j < args.size(); j++) {
+ // expand variables
+ std::string exp = args[j];
+ cmSystemTools::ExpandRegistryValues(exp);
+
+ // Glob the entry in case of wildcards.
+ cmSystemTools::GlobDirs(exp, path);
+ }
+
+ // Try to find the program.
+ std::string fullPath = cmSystemTools::FindFile(moduleName, path);
+ if (fullPath.empty()) {
+ status.SetError(cmStrCat("Attempt to load command failed from file \"",
+ moduleName, "\""));
+ return false;
+ }
+
+ // try loading the shared library / dll
+ cmsys::DynamicLoader::LibraryHandle lib =
+ cmDynamicLoader::OpenLibrary(fullPath.c_str());
+ if (!lib) {
+ std::string err =
+ cmStrCat("Attempt to load the library ", fullPath, " failed.");
+ const char* error = cmsys::DynamicLoader::LastError();
+ if (error) {
+ err += " Additional error info is:\n";
+ err += error;
+ }
+ status.SetError(err);
+ return false;
+ }
+
+ // Report what file was loaded for this command.
+ status.GetMakefile().AddDefinition(reportVar, fullPath);
+
+ // find the init function
+ std::string initFuncName = args[0] + "Init";
+ CM_INIT_FUNCTION initFunction = reinterpret_cast<CM_INIT_FUNCTION>(
+ cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName));
+ if (!initFunction) {
+ initFuncName = cmStrCat('_', args[0], "Init");
+ initFunction = reinterpret_cast<CM_INIT_FUNCTION>(
+ cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName));
+ }
+ // if the symbol is found call it to set the name on the
+ // function blocker
+ if (initFunction) {
+ return status.GetMakefile().GetState()->AddScriptedCommand(
+ args[0],
+ BT<cmState::Command>(
+ cmLegacyCommandWrapper(cm::make_unique<cmLoadedCommand>(initFunction)),
+ status.GetMakefile().GetBacktrace()),
+ status.GetMakefile());
+ }
+ status.SetError("Attempt to load command failed. "
+ "No init function found.");
+ return false;
+}
diff --git a/Source/cmLoadCommandCommand.h b/Source/cmLoadCommandCommand.h
new file mode 100644
index 0000000..d30ba16
--- /dev/null
+++ b/Source/cmLoadCommandCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmLoadCommandCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx
new file mode 100644
index 0000000..5daaeff
--- /dev/null
+++ b/Source/cmLocalCommonGenerator.cxx
@@ -0,0 +1,93 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmLocalCommonGenerator.h"
+
+#include <utility>
+#include <vector>
+
+#include "cmGeneratorTarget.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmProperty.h"
+#include "cmStringAlgorithms.h"
+
+class cmGlobalGenerator;
+
+cmLocalCommonGenerator::cmLocalCommonGenerator(cmGlobalGenerator* gg,
+ cmMakefile* mf, std::string wd)
+ : cmLocalGenerator(gg, mf)
+ , WorkingDirectory(std::move(wd))
+{
+ this->ConfigNames =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+}
+
+cmLocalCommonGenerator::~cmLocalCommonGenerator() = default;
+
+std::string cmLocalCommonGenerator::GetTargetFortranFlags(
+ cmGeneratorTarget const* target, std::string const& config)
+{
+ std::string flags;
+
+ // Enable module output if necessary.
+ this->AppendFlags(
+ flags, this->Makefile->GetSafeDefinition("CMAKE_Fortran_MODOUT_FLAG"));
+
+ // Add a module output directory flag if necessary.
+ std::string mod_dir =
+ target->GetFortranModuleDirectory(this->WorkingDirectory);
+ if (!mod_dir.empty()) {
+ mod_dir = this->ConvertToOutputFormat(
+ this->MaybeConvertToRelativePath(this->WorkingDirectory, mod_dir),
+ cmOutputConverter::SHELL);
+ } else {
+ mod_dir =
+ this->Makefile->GetSafeDefinition("CMAKE_Fortran_MODDIR_DEFAULT");
+ }
+ if (!mod_dir.empty()) {
+ std::string modflag = cmStrCat(
+ this->Makefile->GetRequiredDefinition("CMAKE_Fortran_MODDIR_FLAG"),
+ mod_dir);
+ this->AppendFlags(flags, modflag);
+ // Some compilers do not search their own module output directory
+ // for using other modules. Add an include directory explicitly
+ // for consistency with compilers that do search it.
+ std::string incflag =
+ this->Makefile->GetSafeDefinition("CMAKE_Fortran_MODDIR_INCLUDE_FLAG");
+ if (!incflag.empty()) {
+ incflag = cmStrCat(incflag, mod_dir);
+ this->AppendFlags(flags, incflag);
+ }
+ }
+
+ // If there is a separate module path flag then duplicate the
+ // include path with it. This compiler does not search the include
+ // path for modules.
+ if (cmProp modpath_flag =
+ this->Makefile->GetDefinition("CMAKE_Fortran_MODPATH_FLAG")) {
+ std::vector<std::string> includes;
+ this->GetIncludeDirectories(includes, target, "C", config);
+ for (std::string const& id : includes) {
+ std::string flg =
+ cmStrCat(*modpath_flag,
+ this->ConvertToOutputFormat(id, cmOutputConverter::SHELL));
+ this->AppendFlags(flags, flg);
+ }
+ }
+
+ return flags;
+}
+
+void cmLocalCommonGenerator::ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* gt)
+{
+ // Determine if these object files should use a custom extension
+ char const* custom_ext = gt->GetCustomObjectExtension();
+ for (auto& si : mapping) {
+ cmSourceFile const* sf = si.first;
+ bool keptSourceExtension;
+ si.second = this->GetObjectFileNameWithoutTarget(
+ *sf, gt->ObjectDirectory, &keptSourceExtension, custom_ext);
+ }
+}
diff --git a/Source/cmLocalCommonGenerator.h b/Source/cmLocalCommonGenerator.h
new file mode 100644
index 0000000..f1eaf61
--- /dev/null
+++ b/Source/cmLocalCommonGenerator.h
@@ -0,0 +1,48 @@
+/* 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 <map>
+#include <string>
+#include <vector>
+
+#include "cmLocalGenerator.h"
+
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmMakefile;
+class cmSourceFile;
+
+/** \class cmLocalCommonGenerator
+ * \brief Common infrastructure for Makefile and Ninja local generators.
+ */
+class cmLocalCommonGenerator : public cmLocalGenerator
+{
+public:
+ cmLocalCommonGenerator(cmGlobalGenerator* gg, cmMakefile* mf,
+ std::string wd);
+ ~cmLocalCommonGenerator() override;
+
+ std::vector<std::string> const& GetConfigNames() const
+ {
+ return this->ConfigNames;
+ }
+
+ std::string GetWorkingDirectory() const { return this->WorkingDirectory; }
+
+ std::string GetTargetFortranFlags(cmGeneratorTarget const* target,
+ std::string const& config) override;
+
+ void ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* gt = nullptr) override;
+
+protected:
+ std::string WorkingDirectory;
+
+ std::vector<std::string> ConfigNames;
+
+ friend class cmCommonTargetGenerator;
+};
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
new file mode 100644
index 0000000..b301c6e
--- /dev/null
+++ b/Source/cmLocalGenerator.cxx
@@ -0,0 +1,4500 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmLocalGenerator.h"
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <initializer_list>
+#include <iterator>
+#include <sstream>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmAlgorithms.h"
+#include "cmComputeLinkInformation.h"
+#include "cmCustomCommand.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmCustomCommandLines.h"
+#include "cmCustomCommandTypes.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionEvaluationFile.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallGenerator.h"
+#include "cmInstallScriptGenerator.h"
+#include "cmInstallTargetGenerator.h"
+#include "cmLinkLineComputer.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmRulePlaceholderExpander.h"
+#include "cmSourceFile.h"
+#include "cmSourceFileLocation.h"
+#include "cmSourceFileLocationKind.h"
+#include "cmStandardLevelResolver.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTestGenerator.h"
+#include "cmVersion.h"
+#include "cmake.h"
+
+#if !defined(CMAKE_BOOTSTRAP)
+# define CM_LG_ENCODE_OBJECT_NAMES
+# include "cmCryptoHash.h"
+#endif
+
+#if defined(__HAIKU__)
+# include <FindDirectory.h>
+# include <StorageDefs.h>
+#endif
+
+// List of variables that are replaced when
+// rules are expanced. These variables are
+// replaced in the form <var> with GetSafeDefinition(var).
+// ${LANG} is replaced in the variable first with all enabled
+// languages.
+static auto ruleReplaceVars = { "CMAKE_${LANG}_COMPILER",
+ "CMAKE_SHARED_LIBRARY_CREATE_${LANG}_FLAGS",
+ "CMAKE_SHARED_MODULE_CREATE_${LANG}_FLAGS",
+ "CMAKE_SHARED_MODULE_${LANG}_FLAGS",
+ "CMAKE_SHARED_LIBRARY_${LANG}_FLAGS",
+ "CMAKE_${LANG}_LINK_FLAGS",
+ "CMAKE_SHARED_LIBRARY_SONAME_${LANG}_FLAG",
+ "CMAKE_${LANG}_ARCHIVE",
+ "CMAKE_AR",
+ "CMAKE_CURRENT_SOURCE_DIR",
+ "CMAKE_CURRENT_BINARY_DIR",
+ "CMAKE_RANLIB",
+ "CMAKE_LINKER",
+ "CMAKE_MT",
+ "CMAKE_CUDA_HOST_COMPILER",
+ "CMAKE_CUDA_HOST_LINK_LAUNCHER",
+ "CMAKE_CL_SHOWINCLUDES_PREFIX" };
+
+cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
+ : cmOutputConverter(makefile->GetStateSnapshot())
+ , StateSnapshot(makefile->GetStateSnapshot())
+ , DirectoryBacktrace(makefile->GetBacktrace())
+{
+ this->GlobalGenerator = gg;
+
+ this->Makefile = makefile;
+
+ this->AliasTargets = makefile->GetAliasTargets();
+
+ this->EmitUniversalBinaryFlags = true;
+ this->BackwardsCompatibility = 0;
+ this->BackwardsCompatibilityFinal = false;
+
+ this->ComputeObjectMaxPath();
+
+ // Canonicalize entries of the CPATH environment variable the same
+ // way detection of CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES does.
+ {
+ std::vector<std::string> cpath;
+ cmSystemTools::GetPath(cpath, "CPATH");
+ for (std::string& cp : cpath) {
+ if (cmSystemTools::FileIsFullPath(cp)) {
+ cp = cmSystemTools::CollapseFullPath(cp);
+ this->EnvCPATH.emplace(std::move(cp));
+ }
+ }
+ }
+
+ std::vector<std::string> enabledLanguages =
+ this->GetState()->GetEnabledLanguages();
+
+ if (cmProp sysrootCompile =
+ this->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE")) {
+ this->CompilerSysroot = *sysrootCompile;
+ } else {
+ this->CompilerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
+ }
+
+ if (cmProp sysrootLink =
+ this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
+ this->LinkerSysroot = *sysrootLink;
+ } else {
+ this->LinkerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
+ }
+
+ if (cmProp appleArchSysroots =
+ this->Makefile->GetDefinition("CMAKE_APPLE_ARCH_SYSROOTS")) {
+ std::string const& appleArchs =
+ this->Makefile->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES");
+ std::vector<std::string> archs;
+ std::vector<std::string> sysroots;
+ cmExpandList(appleArchs, archs);
+ cmExpandList(*appleArchSysroots, sysroots, true);
+ if (archs.size() == sysroots.size()) {
+ for (size_t i = 0; i < archs.size(); ++i) {
+ this->AppleArchSysroots[archs[i]] = sysroots[i];
+ }
+ } else {
+ std::string const e =
+ cmStrCat("CMAKE_APPLE_ARCH_SYSROOTS:\n ", *appleArchSysroots,
+ "\n"
+ "is not the same length as CMAKE_OSX_ARCHITECTURES:\n ",
+ appleArchs);
+ this->IssueMessage(MessageType::FATAL_ERROR, e);
+ }
+ }
+
+ for (std::string const& lang : enabledLanguages) {
+ if (lang == "NONE") {
+ continue;
+ }
+ this->Compilers["CMAKE_" + lang + "_COMPILER"] = lang;
+
+ this->VariableMappings["CMAKE_" + lang + "_COMPILER"] =
+ this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER");
+
+ std::string const& compilerArg1 = "CMAKE_" + lang + "_COMPILER_ARG1";
+ std::string const& compilerTarget = "CMAKE_" + lang + "_COMPILER_TARGET";
+ std::string const& compilerOptionTarget =
+ "CMAKE_" + lang + "_COMPILE_OPTIONS_TARGET";
+ std::string const& compilerExternalToolchain =
+ "CMAKE_" + lang + "_COMPILER_EXTERNAL_TOOLCHAIN";
+ std::string const& compilerOptionExternalToolchain =
+ "CMAKE_" + lang + "_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN";
+ std::string const& compilerOptionSysroot =
+ "CMAKE_" + lang + "_COMPILE_OPTIONS_SYSROOT";
+
+ this->VariableMappings[compilerArg1] =
+ this->Makefile->GetSafeDefinition(compilerArg1);
+ this->VariableMappings[compilerTarget] =
+ this->Makefile->GetSafeDefinition(compilerTarget);
+ this->VariableMappings[compilerOptionTarget] =
+ this->Makefile->GetSafeDefinition(compilerOptionTarget);
+ this->VariableMappings[compilerExternalToolchain] =
+ this->Makefile->GetSafeDefinition(compilerExternalToolchain);
+ this->VariableMappings[compilerOptionExternalToolchain] =
+ this->Makefile->GetSafeDefinition(compilerOptionExternalToolchain);
+ this->VariableMappings[compilerOptionSysroot] =
+ this->Makefile->GetSafeDefinition(compilerOptionSysroot);
+
+ for (std::string replaceVar : ruleReplaceVars) {
+ if (replaceVar.find("${LANG}") != std::string::npos) {
+ cmSystemTools::ReplaceString(replaceVar, "${LANG}", lang);
+ }
+
+ this->VariableMappings[replaceVar] =
+ this->Makefile->GetSafeDefinition(replaceVar);
+ }
+ }
+}
+
+cmRulePlaceholderExpander* cmLocalGenerator::CreateRulePlaceholderExpander()
+ const
+{
+ return new cmRulePlaceholderExpander(this->Compilers, this->VariableMappings,
+ this->CompilerSysroot,
+ this->LinkerSysroot);
+}
+
+cmLocalGenerator::~cmLocalGenerator() = default;
+
+void cmLocalGenerator::IssueMessage(MessageType t,
+ std::string const& text) const
+{
+ this->GetCMakeInstance()->IssueMessage(t, text, this->DirectoryBacktrace);
+}
+
+void cmLocalGenerator::ComputeObjectMaxPath()
+{
+// Choose a maximum object file name length.
+#if defined(_WIN32) || defined(__CYGWIN__)
+ this->ObjectPathMax = 250;
+#else
+ this->ObjectPathMax = 1000;
+#endif
+ cmProp plen = this->Makefile->GetDefinition("CMAKE_OBJECT_PATH_MAX");
+ if (cmNonempty(plen)) {
+ unsigned int pmax;
+ if (sscanf(plen->c_str(), "%u", &pmax) == 1) {
+ if (pmax >= 128) {
+ this->ObjectPathMax = pmax;
+ } else {
+ std::ostringstream w;
+ w << "CMAKE_OBJECT_PATH_MAX is set to " << pmax
+ << ", which is less than the minimum of 128. "
+ << "The value will be ignored.";
+ this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+ } else {
+ std::ostringstream w;
+ w << "CMAKE_OBJECT_PATH_MAX is set to \"" << *plen
+ << "\", which fails to parse as a positive integer. "
+ << "The value will be ignored.";
+ this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+ }
+ this->ObjectMaxPathViolations.clear();
+}
+
+static void MoveSystemIncludesToEnd(std::vector<std::string>& includeDirs,
+ const std::string& config,
+ const std::string& lang,
+ const cmGeneratorTarget* target)
+{
+ if (!target) {
+ return;
+ }
+
+ std::stable_sort(
+ includeDirs.begin(), includeDirs.end(),
+ [&target, &config, &lang](std::string const& a, std::string const& b) {
+ return !target->IsSystemIncludeDirectory(a, config, lang) &&
+ target->IsSystemIncludeDirectory(b, config, lang);
+ });
+}
+
+static void MoveSystemIncludesToEnd(std::vector<BT<std::string>>& includeDirs,
+ const std::string& config,
+ const std::string& lang,
+ const cmGeneratorTarget* target)
+{
+ if (!target) {
+ return;
+ }
+
+ std::stable_sort(includeDirs.begin(), includeDirs.end(),
+ [target, &config, &lang](BT<std::string> const& a,
+ BT<std::string> const& b) {
+ return !target->IsSystemIncludeDirectory(a.Value, config,
+ lang) &&
+ target->IsSystemIncludeDirectory(b.Value, config, lang);
+ });
+}
+
+void cmLocalGenerator::TraceDependencies() const
+{
+ // Generate the rule files for each target.
+ const auto& targets = this->GetGeneratorTargets();
+ for (const auto& target : targets) {
+ if (!target->IsInBuildSystem()) {
+ continue;
+ }
+ target->TraceDependencies();
+ }
+}
+
+void cmLocalGenerator::GenerateTestFiles()
+{
+ if (!this->Makefile->IsOn("CMAKE_TESTING_ENABLED")) {
+ return;
+ }
+
+ // Compute the set of configurations.
+ std::vector<std::string> configurationTypes =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig);
+ std::string config = this->Makefile->GetDefaultConfiguration();
+
+ std::string file =
+ cmStrCat(this->StateSnapshot.GetDirectory().GetCurrentBinary(),
+ "/CTestTestfile.cmake");
+
+ cmGeneratedFileStream fout(file);
+ fout.SetCopyIfDifferent(true);
+
+ fout << "# CMake generated Testfile for \n"
+ "# Source directory: "
+ << this->StateSnapshot.GetDirectory().GetCurrentSource()
+ << "\n"
+ "# Build directory: "
+ << this->StateSnapshot.GetDirectory().GetCurrentBinary()
+ << "\n"
+ "# \n"
+ "# This file includes the relevant testing commands "
+ "required for \n"
+ "# testing this directory and lists subdirectories to "
+ "be tested as well.\n";
+
+ std::string resourceSpecFile =
+ this->Makefile->GetSafeDefinition("CTEST_RESOURCE_SPEC_FILE");
+ if (!resourceSpecFile.empty()) {
+ fout << "set(CTEST_RESOURCE_SPEC_FILE \"" << resourceSpecFile << "\")\n";
+ }
+
+ cmProp testIncludeFile = this->Makefile->GetProperty("TEST_INCLUDE_FILE");
+ if (testIncludeFile) {
+ fout << "include(\"" << *testIncludeFile << "\")\n";
+ }
+
+ cmProp testIncludeFiles = this->Makefile->GetProperty("TEST_INCLUDE_FILES");
+ if (testIncludeFiles) {
+ std::vector<std::string> includesList = cmExpandedList(*testIncludeFiles);
+ for (std::string const& i : includesList) {
+ fout << "include(\"" << i << "\")\n";
+ }
+ }
+
+ // Ask each test generator to write its code.
+ for (const auto& tester : this->Makefile->GetTestGenerators()) {
+ tester->Compute(this);
+ tester->Generate(fout, config, configurationTypes);
+ }
+ using vec_t = std::vector<cmStateSnapshot>;
+ vec_t const& children = this->Makefile->GetStateSnapshot().GetChildren();
+ std::string parentBinDir = this->GetCurrentBinaryDirectory();
+ for (cmStateSnapshot const& i : children) {
+ // TODO: Use add_subdirectory instead?
+ std::string outP = i.GetDirectory().GetCurrentBinary();
+ outP = this->MaybeConvertToRelativePath(parentBinDir, outP);
+ outP = cmOutputConverter::EscapeForCMake(outP);
+ fout << "subdirs(" << outP << ")\n";
+ }
+
+ // Add directory labels property
+ cmProp directoryLabels =
+ this->Makefile->GetDefinition("CMAKE_DIRECTORY_LABELS");
+ cmProp labels = this->Makefile->GetProperty("LABELS");
+
+ if (labels || directoryLabels) {
+ fout << "set_directory_properties(PROPERTIES LABELS ";
+ if (labels) {
+ fout << cmOutputConverter::EscapeForCMake(*labels);
+ }
+ if (labels && directoryLabels) {
+ fout << ";";
+ }
+ if (directoryLabels) {
+ fout << cmOutputConverter::EscapeForCMake(*directoryLabels);
+ }
+ fout << ")\n";
+ }
+}
+
+void cmLocalGenerator::CreateEvaluationFileOutputs()
+{
+ std::vector<std::string> const& configs =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ for (std::string const& c : configs) {
+ this->CreateEvaluationFileOutputs(c);
+ }
+}
+
+void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config)
+{
+ for (const auto& geef : this->Makefile->GetEvaluationFiles()) {
+ geef->CreateOutputFile(this, config);
+ }
+}
+
+void cmLocalGenerator::ProcessEvaluationFiles(
+ std::vector<std::string>& generatedFiles)
+{
+ for (const auto& geef : this->Makefile->GetEvaluationFiles()) {
+ geef->Generate(this);
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ return;
+ }
+ std::vector<std::string> files = geef->GetFiles();
+ std::sort(files.begin(), files.end());
+
+ std::vector<std::string> intersection;
+ std::set_intersection(files.begin(), files.end(), generatedFiles.begin(),
+ generatedFiles.end(),
+ std::back_inserter(intersection));
+ if (!intersection.empty()) {
+ cmSystemTools::Error("Files to be generated by multiple different "
+ "commands: " +
+ cmWrap('"', intersection, '"', " "));
+ return;
+ }
+
+ cm::append(generatedFiles, files);
+ std::inplace_merge(generatedFiles.begin(),
+ generatedFiles.end() - files.size(),
+ generatedFiles.end());
+ }
+}
+
+void cmLocalGenerator::GenerateInstallRules()
+{
+ // Compute the install prefix.
+ const char* prefix =
+ cmToCStr(this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX"));
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ std::string prefix_win32;
+ if (!prefix) {
+ if (!cmSystemTools::GetEnv("SystemDrive", prefix_win32)) {
+ prefix_win32 = "C:";
+ }
+ cmProp project_name = this->Makefile->GetDefinition("PROJECT_NAME");
+ if (cmNonempty(project_name)) {
+ prefix_win32 += "/Program Files/";
+ prefix_win32 += *project_name;
+ } else {
+ prefix_win32 += "/InstalledCMakeProject";
+ }
+ prefix = prefix_win32.c_str();
+ }
+#elif defined(__HAIKU__)
+ char dir[B_PATH_NAME_LENGTH];
+ if (!prefix) {
+ if (find_directory(B_SYSTEM_DIRECTORY, -1, false, dir, sizeof(dir)) ==
+ B_OK) {
+ prefix = dir;
+ } else {
+ prefix = "/boot/system";
+ }
+ }
+#else
+ if (!prefix) {
+ prefix = "/usr/local";
+ }
+#endif
+ if (cmProp stagingPrefix =
+ this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX")) {
+ prefix = stagingPrefix->c_str();
+ }
+
+ // Compute the set of configurations.
+ std::vector<std::string> configurationTypes =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig);
+ std::string config = this->Makefile->GetDefaultConfiguration();
+
+ // Choose a default install configuration.
+ std::string default_config = config;
+ const char* default_order[] = { "RELEASE", "MINSIZEREL", "RELWITHDEBINFO",
+ "DEBUG", nullptr };
+ for (const char** c = default_order; *c && default_config.empty(); ++c) {
+ for (std::string const& configurationType : configurationTypes) {
+ if (cmSystemTools::UpperCase(configurationType) == *c) {
+ default_config = configurationType;
+ }
+ }
+ }
+ if (default_config.empty() && !configurationTypes.empty()) {
+ default_config = configurationTypes[0];
+ }
+
+ // Create the install script file.
+ std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary();
+ std::string homedir = this->GetState()->GetBinaryDirectory();
+ int toplevel_install = 0;
+ if (file == homedir) {
+ toplevel_install = 1;
+ }
+ file += "/cmake_install.cmake";
+ cmGeneratedFileStream fout(file);
+ fout.SetCopyIfDifferent(true);
+
+ // Write the header.
+ /* clang-format off */
+ fout << "# Install script for directory: "
+ << this->StateSnapshot.GetDirectory().GetCurrentSource()
+ << "\n\n"
+ "# Set the install prefix\n"
+ "if(NOT DEFINED CMAKE_INSTALL_PREFIX)\n"
+ " set(CMAKE_INSTALL_PREFIX \"" << prefix << "\")\n"
+ "endif()\n"
+ << R"(string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX )"
+ << "\"${CMAKE_INSTALL_PREFIX}\")\n\n";
+ /* clang-format on */
+
+ // Write support code for generating per-configuration install rules.
+ /* clang-format off */
+ fout <<
+ "# Set the install configuration name.\n"
+ "if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)\n"
+ " if(BUILD_TYPE)\n"
+ " string(REGEX REPLACE \"^[^A-Za-z0-9_]+\" \"\"\n"
+ " CMAKE_INSTALL_CONFIG_NAME \"${BUILD_TYPE}\")\n"
+ " else()\n"
+ " set(CMAKE_INSTALL_CONFIG_NAME \"" << default_config << "\")\n"
+ " endif()\n"
+ " message(STATUS \"Install configuration: "
+ "\\\"${CMAKE_INSTALL_CONFIG_NAME}\\\"\")\n"
+ "endif()\n"
+ "\n";
+ /* clang-format on */
+
+ // Write support code for dealing with component-specific installs.
+ /* clang-format off */
+ fout <<
+ "# Set the component getting installed.\n"
+ "if(NOT CMAKE_INSTALL_COMPONENT)\n"
+ " if(COMPONENT)\n"
+ " message(STATUS \"Install component: \\\"${COMPONENT}\\\"\")\n"
+ " set(CMAKE_INSTALL_COMPONENT \"${COMPONENT}\")\n"
+ " else()\n"
+ " set(CMAKE_INSTALL_COMPONENT)\n"
+ " endif()\n"
+ "endif()\n"
+ "\n";
+ /* clang-format on */
+
+ // Copy user-specified install options to the install code.
+ if (cmProp so_no_exe =
+ this->Makefile->GetDefinition("CMAKE_INSTALL_SO_NO_EXE")) {
+ /* clang-format off */
+ fout <<
+ "# Install shared libraries without execute permission?\n"
+ "if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)\n"
+ " set(CMAKE_INSTALL_SO_NO_EXE \"" << *so_no_exe << "\")\n"
+ "endif()\n"
+ "\n";
+ /* clang-format on */
+ }
+
+ // Copy cmake cross compile state to install code.
+ if (cmProp crosscompiling =
+ this->Makefile->GetDefinition("CMAKE_CROSSCOMPILING")) {
+ /* clang-format off */
+ fout <<
+ "# Is this installation the result of a crosscompile?\n"
+ "if(NOT DEFINED CMAKE_CROSSCOMPILING)\n"
+ " set(CMAKE_CROSSCOMPILING \"" << *crosscompiling << "\")\n"
+ "endif()\n"
+ "\n";
+ /* clang-format on */
+ }
+
+ // Write default directory permissions.
+ if (cmProp defaultDirPermissions = this->Makefile->GetDefinition(
+ "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS")) {
+ /* clang-format off */
+ fout <<
+ "# Set default install directory permissions.\n"
+ "if(NOT DEFINED CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS)\n"
+ " set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS \""
+ << *defaultDirPermissions << "\")\n"
+ "endif()\n"
+ "\n";
+ /* clang-format on */
+ }
+
+ // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM so that
+ // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)`
+ // has same platform variable as when running cmake
+ if (cmProp platform = this->Makefile->GetDefinition(
+ "CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM")) {
+ /* clang-format off */
+ fout <<
+ "# Set default install directory permissions.\n"
+ "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM)\n"
+ " set(CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM \""
+ << *platform << "\")\n"
+ "endif()\n"
+ "\n";
+ /* clang-format on */
+ }
+
+ // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL so that
+ // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)`
+ // has same tool selected as when running cmake
+ if (cmProp command =
+ this->Makefile->GetDefinition("CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL")) {
+ /* clang-format off */
+ fout <<
+ "# Set default install directory permissions.\n"
+ "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL)\n"
+ " set(CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL \""
+ << *command << "\")\n"
+ "endif()\n"
+ "\n";
+ /* clang-format on */
+ }
+
+ // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND so that
+ // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)`
+ // has same path to the tool as when running cmake
+ if (cmProp command = this->Makefile->GetDefinition(
+ "CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND")) {
+ /* clang-format off */
+ fout <<
+ "# Set default install directory permissions.\n"
+ "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND)\n"
+ " set(CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND \""
+ << *command << "\")\n"
+ "endif()\n"
+ "\n";
+ /* clang-format on */
+ }
+
+ // Write out CMAKE_OBJDUMP so that installed code that uses
+ // `file(GET_RUNTIME_DEPENDENCIES)` and hasn't specified
+ // CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND has consistent
+ // logic to fallback to CMAKE_OBJDUMP when `objdump` is
+ // not on the path
+ if (cmProp command = this->Makefile->GetDefinition("CMAKE_OBJDUMP")) {
+ /* clang-format off */
+ fout <<
+ "# Set default install directory permissions.\n"
+ "if(NOT DEFINED CMAKE_OBJDUMP)\n"
+ " set(CMAKE_OBJDUMP \""
+ << *command << "\")\n"
+ "endif()\n"
+ "\n";
+ /* clang-format on */
+ }
+
+ this->AddGeneratorSpecificInstallSetup(fout);
+
+ // Ask each install generator to write its code.
+ cmPolicies::PolicyStatus status = this->GetPolicyStatus(cmPolicies::CMP0082);
+ auto const& installers = this->Makefile->GetInstallGenerators();
+ bool haveSubdirectoryInstall = false;
+ bool haveInstallAfterSubdirectory = false;
+ if (status == cmPolicies::WARN) {
+ for (const auto& installer : installers) {
+ installer->CheckCMP0082(haveSubdirectoryInstall,
+ haveInstallAfterSubdirectory);
+ installer->Generate(fout, config, configurationTypes);
+ }
+ } else {
+ for (const auto& installer : installers) {
+ installer->Generate(fout, config, configurationTypes);
+ }
+ }
+
+ // Write rules from old-style specification stored in targets.
+ this->GenerateTargetInstallRules(fout, config, configurationTypes);
+
+ // Include install scripts from subdirectories.
+ switch (status) {
+ case cmPolicies::WARN:
+ if (haveInstallAfterSubdirectory &&
+ this->Makefile->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0082")) {
+ std::ostringstream e;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0082) << "\n";
+ this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD: {
+ std::vector<cmStateSnapshot> children =
+ this->Makefile->GetStateSnapshot().GetChildren();
+ if (!children.empty()) {
+ fout << "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n";
+ fout << " # Include the install script for each subdirectory.\n";
+ for (cmStateSnapshot const& c : children) {
+ if (!c.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+ std::string odir = c.GetDirectory().GetCurrentBinary();
+ cmSystemTools::ConvertToUnixSlashes(odir);
+ fout << " include(\"" << odir << "/cmake_install.cmake\")\n";
+ }
+ }
+ fout << "\n";
+ fout << "endif()\n\n";
+ }
+ } break;
+
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // NEW behavior is handled in
+ // cmInstallSubdirectoryGenerator::GenerateScript()
+ break;
+ }
+
+ // Record the install manifest.
+ if (toplevel_install) {
+ /* clang-format off */
+ fout <<
+ "if(CMAKE_INSTALL_COMPONENT)\n"
+ " set(CMAKE_INSTALL_MANIFEST \"install_manifest_"
+ "${CMAKE_INSTALL_COMPONENT}.txt\")\n"
+ "else()\n"
+ " set(CMAKE_INSTALL_MANIFEST \"install_manifest.txt\")\n"
+ "endif()\n"
+ "\n"
+ "string(REPLACE \";\" \"\\n\" CMAKE_INSTALL_MANIFEST_CONTENT\n"
+ " \"${CMAKE_INSTALL_MANIFEST_FILES}\")\n"
+ "file(WRITE \"" << homedir << "/${CMAKE_INSTALL_MANIFEST}\"\n"
+ " \"${CMAKE_INSTALL_MANIFEST_CONTENT}\")\n";
+ /* clang-format on */
+ }
+}
+
+void cmLocalGenerator::AddGeneratorTarget(
+ std::unique_ptr<cmGeneratorTarget> gt)
+{
+ cmGeneratorTarget* gt_ptr = gt.get();
+
+ this->GeneratorTargets.push_back(std::move(gt));
+ this->GeneratorTargetSearchIndex.emplace(gt_ptr->GetName(), gt_ptr);
+ this->GlobalGenerator->IndexGeneratorTarget(gt_ptr);
+}
+
+void cmLocalGenerator::AddImportedGeneratorTarget(cmGeneratorTarget* gt)
+{
+ this->ImportedGeneratorTargets.emplace(gt->GetName(), gt);
+ this->GlobalGenerator->IndexGeneratorTarget(gt);
+}
+
+void cmLocalGenerator::AddOwnedImportedGeneratorTarget(
+ std::unique_ptr<cmGeneratorTarget> gt)
+{
+ this->OwnedImportedGeneratorTargets.push_back(std::move(gt));
+}
+
+cmGeneratorTarget* cmLocalGenerator::FindLocalNonAliasGeneratorTarget(
+ const std::string& name) const
+{
+ auto ti = this->GeneratorTargetSearchIndex.find(name);
+ if (ti != this->GeneratorTargetSearchIndex.end()) {
+ return ti->second;
+ }
+ return nullptr;
+}
+
+void cmLocalGenerator::ComputeTargetManifest()
+{
+ // Collect the set of configuration types.
+ std::vector<std::string> configNames =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+ // Add our targets to the manifest for each configuration.
+ const auto& targets = this->GetGeneratorTargets();
+ for (const auto& target : targets) {
+ if (!target->IsInBuildSystem()) {
+ continue;
+ }
+ for (std::string const& c : configNames) {
+ target->ComputeTargetManifest(c);
+ }
+ }
+}
+
+bool cmLocalGenerator::ComputeTargetCompileFeatures()
+{
+ // Collect the set of configuration types.
+ std::vector<std::string> configNames =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+ using LanguagePair = std::pair<std::string, std::string>;
+ std::vector<LanguagePair> pairedLanguages{ { "OBJC", "C" },
+ { "OBJCXX", "CXX" },
+ { "CUDA", "CXX" } };
+ std::set<LanguagePair> inferredEnabledLanguages;
+ for (auto const& lang : pairedLanguages) {
+ if (this->Makefile->GetState()->GetLanguageEnabled(lang.first)) {
+ inferredEnabledLanguages.insert(lang);
+ }
+ }
+
+ // Process compile features of all targets.
+ const auto& targets = this->GetGeneratorTargets();
+ for (const auto& target : targets) {
+ for (std::string const& c : configNames) {
+ if (!target->ComputeCompileFeatures(c)) {
+ return false;
+ }
+ }
+
+ // Now that C/C++ _STANDARD values have been computed
+ // set the values to ObjC/ObjCXX _STANDARD variables
+ if (target->CanCompileSources()) {
+ for (std::string const& c : configNames) {
+ target->ComputeCompileFeatures(c, inferredEnabledLanguages);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool cmLocalGenerator::IsRootMakefile() const
+{
+ return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid();
+}
+
+cmState* cmLocalGenerator::GetState() const
+{
+ return this->GlobalGenerator->GetCMakeInstance()->GetState();
+}
+
+cmStateSnapshot cmLocalGenerator::GetStateSnapshot() const
+{
+ return this->Makefile->GetStateSnapshot();
+}
+
+cmProp cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target,
+ const std::string& prop)
+{
+ if (target) {
+ return target->GetProperty(prop);
+ }
+ return this->Makefile->GetProperty(prop);
+}
+
+std::string cmLocalGenerator::ConvertToIncludeReference(
+ std::string const& path, IncludePathStyle pathStyle, OutputFormat format)
+{
+ static_cast<void>(pathStyle);
+ return this->ConvertToOutputForExisting(path, format);
+}
+
+std::string cmLocalGenerator::GetIncludeFlags(
+ std::vector<std::string> const& includeDirs, cmGeneratorTarget* target,
+ std::string const& lang, std::string const& config, bool forResponseFile,
+ IncludePathStyle pathStyle)
+{
+ if (lang.empty()) {
+ return "";
+ }
+
+ std::vector<std::string> includes = includeDirs;
+ MoveSystemIncludesToEnd(includes, config, lang, target);
+
+ OutputFormat shellFormat = forResponseFile ? RESPONSE : SHELL;
+ std::ostringstream includeFlags;
+
+ std::string const& includeFlag =
+ this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_INCLUDE_FLAG_", lang));
+ const char* sep = cmToCStr(
+ this->Makefile->GetDefinition(cmStrCat("CMAKE_INCLUDE_FLAG_SEP_", lang)));
+ bool quotePaths = false;
+ if (this->Makefile->GetDefinition("CMAKE_QUOTE_INCLUDE_PATHS")) {
+ quotePaths = true;
+ }
+ bool repeatFlag = true;
+ // should the include flag be repeated like ie. -IA -IB
+ if (!sep) {
+ sep = " ";
+ } else {
+ // if there is a separator then the flag is not repeated but is only
+ // given once i.e. -classpath a:b:c
+ repeatFlag = false;
+ }
+
+ // Support special system include flag if it is available and the
+ // normal flag is repeated for each directory.
+ cmProp sysIncludeFlag = nullptr;
+ if (repeatFlag) {
+ sysIncludeFlag = this->Makefile->GetDefinition(
+ cmStrCat("CMAKE_INCLUDE_SYSTEM_FLAG_", lang));
+ }
+
+ cmProp fwSearchFlag = this->Makefile->GetDefinition(
+ cmStrCat("CMAKE_", lang, "_FRAMEWORK_SEARCH_FLAG"));
+ cmProp sysFwSearchFlag = this->Makefile->GetDefinition(
+ cmStrCat("CMAKE_", lang, "_SYSTEM_FRAMEWORK_SEARCH_FLAG"));
+
+ bool flagUsed = false;
+ std::set<std::string> emitted;
+#ifdef __APPLE__
+ emitted.insert("/System/Library/Frameworks");
+#endif
+ for (std::string const& i : includes) {
+ if (cmNonempty(fwSearchFlag) && this->Makefile->IsOn("APPLE") &&
+ cmSystemTools::IsPathToFramework(i)) {
+ std::string const frameworkDir =
+ cmSystemTools::CollapseFullPath(cmStrCat(i, "/../"));
+ if (emitted.insert(frameworkDir).second) {
+ if (sysFwSearchFlag && target &&
+ target->IsSystemIncludeDirectory(i, config, lang)) {
+ includeFlags << *sysFwSearchFlag;
+ } else {
+ includeFlags << *fwSearchFlag;
+ }
+ includeFlags << this->ConvertToOutputFormat(frameworkDir, shellFormat)
+ << " ";
+ }
+ continue;
+ }
+
+ if (!flagUsed || repeatFlag) {
+ if (sysIncludeFlag && target &&
+ target->IsSystemIncludeDirectory(i, config, lang)) {
+ includeFlags << *sysIncludeFlag;
+ } else {
+ includeFlags << includeFlag;
+ }
+ flagUsed = true;
+ }
+ std::string includePath =
+ this->ConvertToIncludeReference(i, pathStyle, shellFormat);
+ if (quotePaths && !includePath.empty() && includePath.front() != '\"') {
+ includeFlags << "\"";
+ }
+ includeFlags << includePath;
+ if (quotePaths && !includePath.empty() && includePath.front() != '\"') {
+ includeFlags << "\"";
+ }
+ includeFlags << sep;
+ }
+ std::string flags = includeFlags.str();
+ // remove trailing separators
+ if ((sep[0] != ' ') && !flags.empty() && flags.back() == sep[0]) {
+ flags.back() = ' ';
+ }
+ return cmTrimWhitespace(flags);
+}
+
+void cmLocalGenerator::AddCompileOptions(std::string& flags,
+ cmGeneratorTarget* target,
+ const std::string& lang,
+ const std::string& config)
+{
+ std::vector<BT<std::string>> tmpFlags;
+ this->AddCompileOptions(tmpFlags, target, lang, config);
+ this->AppendFlags(flags, tmpFlags);
+}
+
+void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags,
+ cmGeneratorTarget* target,
+ const std::string& lang,
+ const std::string& config)
+{
+ std::string langFlagRegexVar = cmStrCat("CMAKE_", lang, "_FLAG_REGEX");
+
+ if (cmProp langFlagRegexStr =
+ this->Makefile->GetDefinition(langFlagRegexVar)) {
+ // Filter flags acceptable to this language.
+ if (cmProp targetFlags = target->GetProperty("COMPILE_FLAGS")) {
+ std::vector<std::string> opts;
+ cmSystemTools::ParseWindowsCommandLine(targetFlags->c_str(), opts);
+ // Re-escape these flags since COMPILE_FLAGS were already parsed
+ // as a command line above.
+ std::string compileOpts;
+ this->AppendCompileOptions(compileOpts, opts, langFlagRegexStr->c_str());
+ if (!compileOpts.empty()) {
+ flags.emplace_back(std::move(compileOpts));
+ }
+ }
+ std::vector<BT<std::string>> targetCompileOpts =
+ target->GetCompileOptions(config, lang);
+ // COMPILE_OPTIONS are escaped.
+ this->AppendCompileOptions(flags, targetCompileOpts,
+ langFlagRegexStr->c_str());
+ } else {
+ // Use all flags.
+ if (cmProp targetFlags = target->GetProperty("COMPILE_FLAGS")) {
+ // COMPILE_FLAGS are not escaped for historical reasons.
+ std::string compileFlags;
+ this->AppendFlags(compileFlags, *targetFlags);
+ if (!compileFlags.empty()) {
+ flags.emplace_back(std::move(compileFlags));
+ }
+ }
+ std::vector<BT<std::string>> targetCompileOpts =
+ target->GetCompileOptions(config, lang);
+ // COMPILE_OPTIONS are escaped.
+ this->AppendCompileOptions(flags, targetCompileOpts);
+ }
+
+ cmStandardLevelResolver standardResolver(this->Makefile);
+ for (auto const& it : target->GetMaxLanguageStandards()) {
+ cmProp standard = target->GetLanguageStandard(it.first, config);
+ if (!standard) {
+ continue;
+ }
+ if (standardResolver.IsLaterStandard(it.first, *standard, it.second)) {
+ std::ostringstream e;
+ e << "The COMPILE_FEATURES property of target \"" << target->GetName()
+ << "\" was evaluated when computing the link "
+ "implementation, and the \""
+ << it.first << "_STANDARD\" was \"" << it.second
+ << "\" for that computation. Computing the "
+ "COMPILE_FEATURES based on the link implementation resulted in a "
+ "higher \""
+ << it.first << "_STANDARD\" \"" << *standard
+ << "\". "
+ "This is not permitted. The COMPILE_FEATURES may not both depend "
+ "on "
+ "and be depended on by the link implementation.\n";
+ this->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+ }
+
+ std::string compReqFlag;
+ this->AddCompilerRequirementFlag(compReqFlag, target, lang, config);
+ if (!compReqFlag.empty()) {
+ flags.emplace_back(std::move(compReqFlag));
+ }
+
+ // Add compile flag for the MSVC compiler only.
+ cmMakefile* mf = this->GetMakefile();
+ if (cmProp jmc =
+ mf->GetDefinition("CMAKE_" + lang + "_COMPILE_OPTIONS_JMC")) {
+
+ // Handle Just My Code debugging flags, /JMC.
+ // If the target is a Managed C++ one, /JMC is not compatible.
+ if (target->GetManagedType(config) !=
+ cmGeneratorTarget::ManagedType::Managed) {
+ // add /JMC flags if target property VS_JUST_MY_CODE_DEBUGGING is set
+ // to ON
+ if (cmProp jmcExprGen =
+ target->GetProperty("VS_JUST_MY_CODE_DEBUGGING")) {
+ std::string isJMCEnabled =
+ cmGeneratorExpression::Evaluate(*jmcExprGen, this, config);
+ if (cmIsOn(isJMCEnabled)) {
+ std::vector<std::string> optVec = cmExpandedList(*jmc);
+ std::string jmcFlags;
+ this->AppendCompileOptions(jmcFlags, optVec);
+ if (!jmcFlags.empty()) {
+ flags.emplace_back(std::move(jmcFlags));
+ }
+ }
+ }
+ }
+ }
+}
+
+cmTarget* cmLocalGenerator::AddCustomCommandToTarget(
+ const std::string& target, const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, cmCustomCommandType type,
+ const char* comment, const char* workingDir,
+ cmPolicies::PolicyStatus cmp0116, bool escapeOldStyle, bool uses_terminal,
+ const std::string& depfile, const std::string& job_pool,
+ bool command_expand_lists, cmObjectLibraryCommands objLibCommands,
+ bool stdPipesUTF8)
+{
+ cmTarget* t = this->Makefile->GetCustomCommandTarget(
+ target, objLibCommands, this->DirectoryBacktrace);
+ if (!t) {
+ return nullptr;
+ }
+
+ detail::AddCustomCommandToTarget(
+ *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, t, byproducts,
+ depends, commandLines, type, comment, workingDir, escapeOldStyle,
+ uses_terminal, depfile, job_pool, command_expand_lists, stdPipesUTF8,
+ cmp0116);
+
+ return t;
+}
+
+cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput(
+ const std::string& output, const std::vector<std::string>& depends,
+ const std::string& main_dependency, const cmCustomCommandLines& commandLines,
+ const char* comment, const char* workingDir,
+ cmPolicies::PolicyStatus cmp0116, bool replace, bool escapeOldStyle,
+ bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+ const std::string& job_pool, bool stdPipesUTF8)
+{
+ std::vector<std::string> no_byproducts;
+ cmImplicitDependsList no_implicit_depends;
+ return this->AddCustomCommandToOutput(
+ { output }, no_byproducts, depends, main_dependency, no_implicit_depends,
+ commandLines, comment, workingDir, cmp0116, replace, escapeOldStyle,
+ uses_terminal, command_expand_lists, depfile, job_pool, stdPipesUTF8);
+}
+
+cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput(
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends, const std::string& main_dependency,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, cmPolicies::PolicyStatus cmp0116, bool replace,
+ bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
+ const std::string& depfile, const std::string& job_pool, bool stdPipesUTF8)
+{
+ // Make sure there is at least one output.
+ if (outputs.empty()) {
+ cmSystemTools::Error("Attempt to add a custom rule with no output!");
+ return nullptr;
+ }
+
+ return detail::AddCustomCommandToOutput(
+ *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, outputs,
+ byproducts, depends, main_dependency, implicit_depends, commandLines,
+ comment, workingDir, replace, escapeOldStyle, uses_terminal,
+ command_expand_lists, depfile, job_pool, stdPipesUTF8, cmp0116);
+}
+
+cmTarget* cmLocalGenerator::AddUtilityCommand(
+ const std::string& utilityName, bool excludeFromAll, const char* workingDir,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, cmPolicies::PolicyStatus cmp0116,
+ bool escapeOldStyle, const char* comment, bool uses_terminal,
+ bool command_expand_lists, const std::string& job_pool, bool stdPipesUTF8)
+{
+ cmTarget* target =
+ this->Makefile->AddNewUtilityTarget(utilityName, excludeFromAll);
+ target->SetIsGeneratorProvided(true);
+
+ if (commandLines.empty() && depends.empty()) {
+ return target;
+ }
+
+ detail::AddUtilityCommand(
+ *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, target,
+ workingDir, byproducts, depends, commandLines, escapeOldStyle, comment,
+ uses_terminal, command_expand_lists, job_pool, stdPipesUTF8, cmp0116);
+
+ return target;
+}
+
+std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit(
+ cmGeneratorTarget const* target, std::string const& lang,
+ std::string const& config, bool stripImplicitDirs,
+ bool appendAllImplicitDirs) const
+{
+ std::vector<BT<std::string>> result;
+ // Do not repeat an include path.
+ std::set<std::string> emitted;
+
+ auto emitDir = [&result, &emitted](std::string const& dir) {
+ if (emitted.insert(dir).second) {
+ result.emplace_back(dir);
+ }
+ };
+
+ auto emitBT = [&result, &emitted](BT<std::string> const& dir) {
+ if (emitted.insert(dir.Value).second) {
+ result.emplace_back(dir);
+ }
+ };
+
+ // When automatic include directories are requested for a build then
+ // include the source and binary directories at the beginning of the
+ // include path to approximate include file behavior for an
+ // in-source build. This does not account for the case of a source
+ // file in a subdirectory of the current source directory but we
+ // cannot fix this because not all native build tools support
+ // per-source-file include paths.
+ if (this->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR")) {
+ // Current binary directory
+ emitDir(this->StateSnapshot.GetDirectory().GetCurrentBinary());
+ // Current source directory
+ emitDir(this->StateSnapshot.GetDirectory().GetCurrentSource());
+ }
+
+ if (!target) {
+ return result;
+ }
+
+ // Standard include directories to be added unconditionally at the end.
+ // These are intended to simulate additional implicit include directories.
+ std::vector<std::string> userStandardDirs;
+ {
+ std::string const value = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_STANDARD_INCLUDE_DIRECTORIES"));
+ cmExpandList(value, userStandardDirs);
+ for (std::string& usd : userStandardDirs) {
+ cmSystemTools::ConvertToUnixSlashes(usd);
+ }
+ }
+
+ // Implicit include directories
+ std::vector<std::string> implicitDirs;
+ std::set<std::string> implicitSet;
+ // Include directories to be excluded as if they were implicit.
+ std::set<std::string> implicitExclude;
+ {
+ // Raw list of implicit include directories
+ // Start with "standard" directories that we unconditionally add below.
+ std::vector<std::string> impDirVec = userStandardDirs;
+
+ // Load implicit include directories for this language.
+ // We ignore this for Fortran because:
+ // * There are no standard library headers to avoid overriding.
+ // * Compilers like gfortran do not search their own implicit include
+ // directories for modules ('.mod' files).
+ if (lang != "Fortran") {
+ size_t const impDirVecOldSize = impDirVec.size();
+ if (this->Makefile->GetDefExpandList(
+ cmStrCat("CMAKE_", lang, "_IMPLICIT_INCLUDE_DIRECTORIES"),
+ impDirVec)) {
+ // FIXME: Use cmRange with 'advance()' when it supports non-const.
+ for (size_t i = impDirVecOldSize; i < impDirVec.size(); ++i) {
+ cmSystemTools::ConvertToUnixSlashes(impDirVec[i]);
+ }
+ }
+ }
+
+ // The Platform/UnixPaths module used to hard-code /usr/include for C, CXX,
+ // and CUDA in CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES, but those
+ // variables are now computed. On macOS the /usr/include directory is
+ // inside the platform SDK so the computed value does not contain it
+ // directly. In this case adding -I/usr/include can hide SDK headers so we
+ // must still exclude it.
+ if ((lang == "C" || lang == "CXX" || lang == "CUDA") &&
+ !cm::contains(impDirVec, "/usr/include") &&
+ std::find_if(impDirVec.begin(), impDirVec.end(),
+ [](std::string const& d) {
+ return cmHasLiteralSuffix(d, "/usr/include");
+ }) != impDirVec.end()) {
+ // Only exclude this hard coded path for backwards compatibility.
+ implicitExclude.emplace("/usr/include");
+ }
+
+ for (std::string const& i : impDirVec) {
+ if (implicitSet.insert(this->GlobalGenerator->GetRealPath(i)).second) {
+ implicitDirs.emplace_back(i);
+ }
+ }
+ }
+
+ // Checks if this is not an excluded (implicit) include directory.
+ auto notExcluded = [this, &implicitSet, &implicitExclude,
+ &lang](std::string const& dir) {
+ return (
+ // Do not exclude directories that are not in an excluded set.
+ ((!cm::contains(implicitSet, this->GlobalGenerator->GetRealPath(dir))) &&
+ (!cm::contains(implicitExclude, dir)))
+ // Do not exclude entries of the CPATH environment variable even though
+ // they are implicitly searched by the compiler. They are meant to be
+ // user-specified directories that can be re-ordered or converted to
+ // -isystem without breaking real compiler builtin headers.
+ ||
+ ((lang == "C" || lang == "CXX") && cm::contains(this->EnvCPATH, dir)));
+ };
+
+ // Get the target-specific include directories.
+ std::vector<BT<std::string>> userDirs =
+ target->GetIncludeDirectories(config, lang);
+
+ // Support putting all the in-project include directories first if
+ // it is requested by the project.
+ if (this->Makefile->IsOn("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")) {
+ std::string const& topSourceDir = this->GetState()->GetSourceDirectory();
+ std::string const& topBinaryDir = this->GetState()->GetBinaryDirectory();
+ for (BT<std::string> const& udr : userDirs) {
+ // Emit this directory only if it is a subdirectory of the
+ // top-level source or binary tree.
+ if (cmSystemTools::ComparePath(udr.Value, topSourceDir) ||
+ cmSystemTools::ComparePath(udr.Value, topBinaryDir) ||
+ cmSystemTools::IsSubDirectory(udr.Value, topSourceDir) ||
+ cmSystemTools::IsSubDirectory(udr.Value, topBinaryDir)) {
+ if (notExcluded(udr.Value)) {
+ emitBT(udr);
+ }
+ }
+ }
+ }
+
+ // Emit remaining non implicit user directories.
+ for (BT<std::string> const& udr : userDirs) {
+ if (notExcluded(udr.Value)) {
+ emitBT(udr);
+ }
+ }
+
+ // Sort result
+ MoveSystemIncludesToEnd(result, config, lang, target);
+
+ // Append standard include directories for this language.
+ userDirs.reserve(userDirs.size() + userStandardDirs.size());
+ for (std::string& usd : userStandardDirs) {
+ emitDir(usd);
+ userDirs.emplace_back(std::move(usd));
+ }
+
+ // Append compiler implicit include directories
+ if (!stripImplicitDirs) {
+ // Append implicit directories that were requested by the user only
+ for (BT<std::string> const& udr : userDirs) {
+ if (cm::contains(implicitSet, cmSystemTools::GetRealPath(udr.Value))) {
+ emitBT(udr);
+ }
+ }
+ // Append remaining implicit directories (on demand)
+ if (appendAllImplicitDirs) {
+ for (std::string& imd : implicitDirs) {
+ emitDir(imd);
+ }
+ }
+ }
+
+ return result;
+}
+
+void cmLocalGenerator::GetIncludeDirectoriesImplicit(
+ std::vector<std::string>& dirs, cmGeneratorTarget const* target,
+ const std::string& lang, const std::string& config, bool stripImplicitDirs,
+ bool appendAllImplicitDirs) const
+{
+ std::vector<BT<std::string>> tmp = this->GetIncludeDirectoriesImplicit(
+ target, lang, config, stripImplicitDirs, appendAllImplicitDirs);
+ dirs.reserve(dirs.size() + tmp.size());
+ for (BT<std::string>& v : tmp) {
+ dirs.emplace_back(std::move(v.Value));
+ }
+}
+
+std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectories(
+ cmGeneratorTarget const* target, std::string const& lang,
+ std::string const& config) const
+{
+ return this->GetIncludeDirectoriesImplicit(target, lang, config);
+}
+
+void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
+ cmGeneratorTarget const* target,
+ const std::string& lang,
+ const std::string& config) const
+{
+ this->GetIncludeDirectoriesImplicit(dirs, target, lang, config);
+}
+
+void cmLocalGenerator::GetStaticLibraryFlags(std::string& flags,
+ std::string const& config,
+ std::string const& linkLanguage,
+ cmGeneratorTarget* target)
+{
+ std::vector<BT<std::string>> tmpFlags =
+ this->GetStaticLibraryFlags(config, linkLanguage, target);
+ this->AppendFlags(flags, tmpFlags);
+}
+
+std::vector<BT<std::string>> cmLocalGenerator::GetStaticLibraryFlags(
+ std::string const& config, std::string const& linkLanguage,
+ cmGeneratorTarget* target)
+{
+ const std::string configUpper = cmSystemTools::UpperCase(config);
+ std::vector<BT<std::string>> flags;
+ if (linkLanguage != "Swift") {
+ std::string staticLibFlags;
+ this->AppendFlags(
+ staticLibFlags,
+ this->Makefile->GetSafeDefinition("CMAKE_STATIC_LINKER_FLAGS"));
+ if (!configUpper.empty()) {
+ std::string name = "CMAKE_STATIC_LINKER_FLAGS_" + configUpper;
+ this->AppendFlags(staticLibFlags,
+ this->Makefile->GetSafeDefinition(name));
+ }
+ if (!staticLibFlags.empty()) {
+ flags.emplace_back(std::move(staticLibFlags));
+ }
+ }
+
+ std::string staticLibFlags;
+ this->AppendFlags(staticLibFlags,
+ target->GetSafeProperty("STATIC_LIBRARY_FLAGS"));
+ if (!configUpper.empty()) {
+ std::string name = "STATIC_LIBRARY_FLAGS_" + configUpper;
+ this->AppendFlags(staticLibFlags, target->GetSafeProperty(name));
+ }
+
+ if (!staticLibFlags.empty()) {
+ flags.emplace_back(std::move(staticLibFlags));
+ }
+
+ std::vector<BT<std::string>> staticLibOpts =
+ target->GetStaticLibraryLinkOptions(config, linkLanguage);
+ // STATIC_LIBRARY_OPTIONS are escaped.
+ this->AppendCompileOptions(flags, staticLibOpts);
+
+ return flags;
+}
+
+void cmLocalGenerator::GetDeviceLinkFlags(
+ cmLinkLineComputer* linkLineComputer, const std::string& config,
+ std::string& linkLibs, std::string& linkFlags, std::string& frameworkPath,
+ std::string& linkPath, cmGeneratorTarget* target)
+{
+ cmGeneratorTarget::DeviceLinkSetter setter(*target);
+
+ cmComputeLinkInformation* pcli = target->GetLinkInformation(config);
+ const std::string linkLanguage =
+ linkLineComputer->GetLinkerLanguage(target, config);
+
+ if (pcli) {
+ // Compute the required cuda device link libraries when
+ // resolving cuda device symbols
+ this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, frameworkPath,
+ linkPath);
+ }
+
+ std::vector<std::string> linkOpts;
+ target->GetLinkOptions(linkOpts, config, linkLanguage);
+ // LINK_OPTIONS are escaped.
+ this->AppendCompileOptions(linkFlags, linkOpts);
+}
+
+void cmLocalGenerator::GetTargetFlags(
+ cmLinkLineComputer* linkLineComputer, const std::string& config,
+ std::string& linkLibs, std::string& flags, std::string& linkFlags,
+ std::string& frameworkPath, std::string& linkPath, cmGeneratorTarget* target)
+{
+ std::vector<BT<std::string>> linkFlagsList;
+ std::vector<BT<std::string>> linkPathList;
+ std::vector<BT<std::string>> linkLibsList;
+ this->GetTargetFlags(linkLineComputer, config, linkLibsList, flags,
+ linkFlagsList, frameworkPath, linkPathList, target);
+ this->AppendFlags(linkFlags, linkFlagsList);
+ this->AppendFlags(linkPath, linkPathList);
+ this->AppendFlags(linkLibs, linkLibsList);
+}
+
+void cmLocalGenerator::GetTargetFlags(
+ cmLinkLineComputer* linkLineComputer, const std::string& config,
+ std::vector<BT<std::string>>& linkLibs, std::string& flags,
+ std::vector<BT<std::string>>& linkFlags, std::string& frameworkPath,
+ std::vector<BT<std::string>>& linkPath, cmGeneratorTarget* target)
+{
+ const std::string configUpper = cmSystemTools::UpperCase(config);
+ cmComputeLinkInformation* pcli = target->GetLinkInformation(config);
+ const char* libraryLinkVariable =
+ "CMAKE_SHARED_LINKER_FLAGS"; // default to shared library
+
+ const std::string linkLanguage =
+ linkLineComputer->GetLinkerLanguage(target, config);
+
+ switch (target->GetType()) {
+ case cmStateEnums::STATIC_LIBRARY:
+ linkFlags = this->GetStaticLibraryFlags(config, linkLanguage, target);
+ break;
+ case cmStateEnums::MODULE_LIBRARY:
+ libraryLinkVariable = "CMAKE_MODULE_LINKER_FLAGS";
+ CM_FALLTHROUGH;
+ case cmStateEnums::SHARED_LIBRARY: {
+ std::string sharedLibFlags;
+ if (linkLanguage != "Swift") {
+ sharedLibFlags = cmStrCat(
+ this->Makefile->GetSafeDefinition(libraryLinkVariable), ' ');
+ if (!configUpper.empty()) {
+ std::string build = cmStrCat(libraryLinkVariable, '_', configUpper);
+ sharedLibFlags += this->Makefile->GetSafeDefinition(build);
+ sharedLibFlags += " ";
+ }
+ if (this->Makefile->IsOn("WIN32") &&
+ !(this->Makefile->IsOn("CYGWIN") ||
+ this->Makefile->IsOn("MINGW"))) {
+ std::vector<cmSourceFile*> sources;
+ target->GetSourceFiles(sources, config);
+ std::string defFlag =
+ this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG");
+ for (cmSourceFile* sf : sources) {
+ if (sf->GetExtension() == "def") {
+ sharedLibFlags += defFlag;
+ sharedLibFlags +=
+ this->ConvertToOutputFormat(sf->ResolveFullPath(), SHELL);
+ sharedLibFlags += " ";
+ }
+ }
+ }
+ }
+
+ cmProp targetLinkFlags = target->GetProperty("LINK_FLAGS");
+ if (targetLinkFlags) {
+ sharedLibFlags += *targetLinkFlags;
+ sharedLibFlags += " ";
+ }
+ if (!configUpper.empty()) {
+ targetLinkFlags =
+ target->GetProperty(cmStrCat("LINK_FLAGS_", configUpper));
+ if (targetLinkFlags) {
+ sharedLibFlags += *targetLinkFlags;
+ sharedLibFlags += " ";
+ }
+ }
+
+ if (!sharedLibFlags.empty()) {
+ linkFlags.emplace_back(std::move(sharedLibFlags));
+ }
+
+ std::vector<BT<std::string>> linkOpts =
+ target->GetLinkOptions(config, linkLanguage);
+ // LINK_OPTIONS are escaped.
+ this->AppendCompileOptions(linkFlags, linkOpts);
+ if (pcli) {
+ this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
+ frameworkPath, linkPath);
+ }
+ } break;
+ case cmStateEnums::EXECUTABLE: {
+ std::string exeFlags;
+ if (linkLanguage != "Swift") {
+ exeFlags = this->Makefile->GetSafeDefinition("CMAKE_EXE_LINKER_FLAGS");
+ exeFlags += " ";
+ if (!configUpper.empty()) {
+ exeFlags += this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_EXE_LINKER_FLAGS_", configUpper));
+ exeFlags += " ";
+ }
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error(
+ "CMake can not determine linker language for target: " +
+ target->GetName());
+ return;
+ }
+
+ if (target->IsWin32Executable(config)) {
+ exeFlags += this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", linkLanguage, "_CREATE_WIN32_EXE"));
+ exeFlags += " ";
+ } else {
+ exeFlags += this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", linkLanguage, "_CREATE_CONSOLE_EXE"));
+ exeFlags += " ";
+ }
+
+ if (target->IsExecutableWithExports()) {
+ exeFlags += this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_EXE_EXPORTS_", linkLanguage, "_FLAG"));
+ exeFlags += " ";
+ }
+ }
+
+ this->AddLanguageFlagsForLinking(flags, target, linkLanguage, config);
+ if (pcli) {
+ this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
+ frameworkPath, linkPath);
+ }
+
+ if (this->Makefile->IsOn("BUILD_SHARED_LIBS")) {
+ std::string sFlagVar = "CMAKE_SHARED_BUILD_" + linkLanguage + "_FLAGS";
+ exeFlags += this->Makefile->GetSafeDefinition(sFlagVar);
+ exeFlags += " ";
+ }
+
+ std::string cmp0065Flags =
+ this->GetLinkLibsCMP0065(linkLanguage, *target);
+ if (!cmp0065Flags.empty()) {
+ exeFlags += cmp0065Flags;
+ exeFlags += " ";
+ }
+
+ cmProp targetLinkFlags = target->GetProperty("LINK_FLAGS");
+ if (targetLinkFlags) {
+ exeFlags += *targetLinkFlags;
+ exeFlags += " ";
+ }
+ if (!configUpper.empty()) {
+ targetLinkFlags =
+ target->GetProperty(cmStrCat("LINK_FLAGS_", configUpper));
+ if (targetLinkFlags) {
+ exeFlags += *targetLinkFlags;
+ exeFlags += " ";
+ }
+ }
+
+ if (!exeFlags.empty()) {
+ linkFlags.emplace_back(std::move(exeFlags));
+ }
+
+ std::vector<BT<std::string>> linkOpts =
+ target->GetLinkOptions(config, linkLanguage);
+ // LINK_OPTIONS are escaped.
+ this->AppendCompileOptions(linkFlags, linkOpts);
+ } break;
+ default:
+ break;
+ }
+
+ std::string extraLinkFlags;
+ this->AppendPositionIndependentLinkerFlags(extraLinkFlags, target, config,
+ linkLanguage);
+ this->AppendIPOLinkerFlags(extraLinkFlags, target, config, linkLanguage);
+
+ if (!extraLinkFlags.empty()) {
+ linkFlags.emplace_back(std::move(extraLinkFlags));
+ }
+}
+
+void cmLocalGenerator::GetTargetCompileFlags(cmGeneratorTarget* target,
+ std::string const& config,
+ std::string const& lang,
+ std::string& flags,
+ std::string const& arch)
+{
+ std::vector<BT<std::string>> tmpFlags =
+ this->GetTargetCompileFlags(target, config, lang, arch);
+ this->AppendFlags(flags, tmpFlags);
+}
+
+std::vector<BT<std::string>> cmLocalGenerator::GetTargetCompileFlags(
+ cmGeneratorTarget* target, std::string const& config,
+ std::string const& lang, std::string const& arch)
+{
+ std::vector<BT<std::string>> flags;
+ std::string compileFlags;
+
+ cmMakefile* mf = this->GetMakefile();
+
+ // Add language-specific flags.
+ this->AddLanguageFlags(compileFlags, target, lang, config);
+
+ if (target->IsIPOEnabled(lang, config)) {
+ this->AppendFeatureOptions(compileFlags, lang, "IPO");
+ }
+
+ this->AddArchitectureFlags(compileFlags, target, lang, config, arch);
+
+ if (lang == "Fortran") {
+ this->AppendFlags(compileFlags,
+ this->GetTargetFortranFlags(target, config));
+ }
+
+ this->AddCMP0018Flags(compileFlags, target, lang, config);
+ this->AddVisibilityPresetFlags(compileFlags, target, lang);
+ this->AppendFlags(compileFlags, mf->GetDefineFlags());
+ this->AppendFlags(compileFlags,
+ this->GetFrameworkFlags(lang, config, target));
+
+ if (!compileFlags.empty()) {
+ flags.emplace_back(std::move(compileFlags));
+ }
+ this->AddCompileOptions(flags, target, lang, config);
+ return flags;
+}
+
+static std::string GetFrameworkFlags(const std::string& lang,
+ const std::string& config,
+ cmGeneratorTarget* target)
+{
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ cmMakefile* mf = lg->GetMakefile();
+
+ if (!mf->IsOn("APPLE")) {
+ return std::string();
+ }
+
+ std::string fwSearchFlagVar = "CMAKE_" + lang + "_FRAMEWORK_SEARCH_FLAG";
+ cmProp fwSearchFlag = mf->GetDefinition(fwSearchFlagVar);
+ if (!cmNonempty(fwSearchFlag)) {
+ return std::string();
+ }
+
+ std::set<std::string> emitted;
+#ifdef __APPLE__ /* don't insert this when crosscompiling e.g. to iphone */
+ emitted.insert("/System/Library/Frameworks");
+#endif
+ std::vector<std::string> includes;
+
+ lg->GetIncludeDirectories(includes, target, "C", config);
+ // check all include directories for frameworks as this
+ // will already have added a -F for the framework
+ for (std::string const& include : includes) {
+ if (lg->GetGlobalGenerator()->NameResolvesToFramework(include)) {
+ std::string frameworkDir = cmStrCat(include, "/../");
+ frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
+ emitted.insert(frameworkDir);
+ }
+ }
+
+ std::string flags;
+ if (cmComputeLinkInformation* cli = target->GetLinkInformation(config)) {
+ std::vector<std::string> const& frameworks = cli->GetFrameworkPaths();
+ for (std::string const& framework : frameworks) {
+ if (emitted.insert(framework).second) {
+ flags += *fwSearchFlag;
+ flags +=
+ lg->ConvertToOutputFormat(framework, cmOutputConverter::SHELL);
+ flags += " ";
+ }
+ }
+ }
+ return flags;
+}
+
+std::string cmLocalGenerator::GetFrameworkFlags(std::string const& l,
+ std::string const& config,
+ cmGeneratorTarget* target)
+{
+ return ::GetFrameworkFlags(l, config, target);
+}
+
+void cmLocalGenerator::GetTargetDefines(cmGeneratorTarget const* target,
+ std::string const& config,
+ std::string const& lang,
+ std::set<std::string>& defines) const
+{
+ std::set<BT<std::string>> tmp = this->GetTargetDefines(target, config, lang);
+ for (BT<std::string> const& v : tmp) {
+ defines.emplace(v.Value);
+ }
+}
+
+std::set<BT<std::string>> cmLocalGenerator::GetTargetDefines(
+ cmGeneratorTarget const* target, std::string const& config,
+ std::string const& lang) const
+{
+ std::set<BT<std::string>> defines;
+
+ // Add the export symbol definition for shared library objects.
+ if (const std::string* exportMacro = target->GetExportMacro()) {
+ this->AppendDefines(defines, *exportMacro);
+ }
+
+ // Add preprocessor definitions for this target and configuration.
+ std::vector<BT<std::string>> targetDefines =
+ target->GetCompileDefinitions(config, lang);
+ this->AppendDefines(defines, targetDefines);
+
+ return defines;
+}
+
+std::string cmLocalGenerator::GetTargetFortranFlags(
+ cmGeneratorTarget const* /*unused*/, std::string const& /*unused*/)
+{
+ // Implemented by specific generators that override this.
+ return std::string();
+}
+
+/**
+ * Output the linking rules on a command line. For executables,
+ * targetLibrary should be a NULL pointer. For libraries, it should point
+ * to the name of the library. This will not link a library against itself.
+ */
+void cmLocalGenerator::OutputLinkLibraries(
+ cmComputeLinkInformation* pcli, cmLinkLineComputer* linkLineComputer,
+ std::string& linkLibraries, std::string& frameworkPath,
+ std::string& linkPath)
+{
+ std::vector<BT<std::string>> linkLibrariesList;
+ std::vector<BT<std::string>> linkPathList;
+ this->OutputLinkLibraries(pcli, linkLineComputer, linkLibrariesList,
+ frameworkPath, linkPathList);
+ pcli->AppendValues(linkLibraries, linkLibrariesList);
+ pcli->AppendValues(linkPath, linkPathList);
+}
+
+void cmLocalGenerator::OutputLinkLibraries(
+ cmComputeLinkInformation* pcli, cmLinkLineComputer* linkLineComputer,
+ std::vector<BT<std::string>>& linkLibraries, std::string& frameworkPath,
+ std::vector<BT<std::string>>& linkPath)
+{
+ cmComputeLinkInformation& cli = *pcli;
+
+ std::string linkLanguage = cli.GetLinkLanguage();
+
+ std::string libPathFlag;
+ if (cmProp value = this->Makefile->GetDefinition(
+ "CMAKE_" + cli.GetLinkLanguage() + "_LIBRARY_PATH_FLAG")) {
+ libPathFlag = *value;
+ } else {
+ libPathFlag =
+ this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG");
+ }
+
+ std::string libPathTerminator;
+ if (cmProp value = this->Makefile->GetDefinition(
+ "CMAKE_" + cli.GetLinkLanguage() + "_LIBRARY_PATH_TERMINATOR")) {
+ libPathTerminator = *value;
+ } else {
+ libPathTerminator =
+ this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_TERMINATOR");
+ }
+
+ // Add standard libraries for this language.
+ std::string stdLibString = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", cli.GetLinkLanguage(), "_STANDARD_LIBRARIES"));
+
+ // Append the framework search path flags.
+ std::string fwSearchFlag = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", linkLanguage, "_FRAMEWORK_SEARCH_FLAG"));
+
+ frameworkPath = linkLineComputer->ComputeFrameworkPath(cli, fwSearchFlag);
+ linkLineComputer->ComputeLinkPath(cli, libPathFlag, libPathTerminator,
+ linkPath);
+ linkLineComputer->ComputeLinkLibraries(cli, stdLibString, linkLibraries);
+}
+
+std::string cmLocalGenerator::GetLinkLibsCMP0065(
+ std::string const& linkLanguage, cmGeneratorTarget& tgt) const
+{
+ std::string linkFlags;
+
+ // Flags to link an executable to shared libraries.
+ if (tgt.GetType() == cmStateEnums::EXECUTABLE &&
+ this->StateSnapshot.GetState()->GetGlobalPropertyAsBool(
+ "TARGET_SUPPORTS_SHARED_LIBS")) {
+ bool add_shlib_flags = false;
+ switch (tgt.GetPolicyStatusCMP0065()) {
+ case cmPolicies::WARN:
+ if (!tgt.GetPropertyAsBool("ENABLE_EXPORTS") &&
+ this->Makefile->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0065")) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0065) << "\n"
+ "For compatibility with older versions of CMake, "
+ "additional flags may be added to export symbols on all "
+ "executables regardless of their ENABLE_EXPORTS property.";
+ /* clang-format on */
+ this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior is to always add the flags, except on AIX where
+ // we compute symbol exports if ENABLE_EXPORTS is on.
+ add_shlib_flags =
+ !(tgt.Target->IsAIX() && tgt.GetPropertyAsBool("ENABLE_EXPORTS"));
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0065));
+ CM_FALLTHROUGH;
+ case cmPolicies::NEW:
+ // NEW behavior is to only add the flags if ENABLE_EXPORTS is on,
+ // except on AIX where we compute symbol exports.
+ add_shlib_flags =
+ !tgt.Target->IsAIX() && tgt.GetPropertyAsBool("ENABLE_EXPORTS");
+ break;
+ }
+
+ if (add_shlib_flags) {
+ linkFlags = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_SHARED_LIBRARY_LINK_", linkLanguage, "_FLAGS"));
+ }
+ }
+ return linkFlags;
+}
+
+bool cmLocalGenerator::AllAppleArchSysrootsAreTheSame(
+ const std::vector<std::string>& archs, const char* sysroot)
+{
+ if (!sysroot) {
+ return false;
+ }
+
+ return std::all_of(archs.begin(), archs.end(),
+ [this, &sysroot](std::string const& arch) -> bool {
+ std::string const& archSysroot =
+ this->AppleArchSysroots[arch];
+ return cmIsOff(archSysroot) || archSysroot == sysroot;
+ });
+}
+
+void cmLocalGenerator::AddArchitectureFlags(std::string& flags,
+ cmGeneratorTarget const* target,
+ const std::string& lang,
+ const std::string& config,
+ const std::string& filterArch)
+{
+ // Only add Apple specific flags on Apple platforms
+ if (this->Makefile->IsOn("APPLE") && this->EmitUniversalBinaryFlags) {
+ std::vector<std::string> archs;
+ target->GetAppleArchs(config, archs);
+ if (!archs.empty() &&
+ (lang == "C" || lang == "CXX" || lang == "OBJ" || lang == "OBJCXX" ||
+ lang == "ASM")) {
+ for (std::string const& arch : archs) {
+ if (filterArch.empty() || filterArch == arch) {
+ flags += " -arch ";
+ flags += arch;
+ }
+ }
+ }
+
+ cmProp sysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT");
+ if (sysroot && *sysroot == "/") {
+ sysroot = nullptr;
+ }
+ std::string sysrootFlagVar = "CMAKE_" + lang + "_SYSROOT_FLAG";
+ cmProp sysrootFlag = this->Makefile->GetDefinition(sysrootFlagVar);
+ if (cmNonempty(sysrootFlag)) {
+ if (!this->AppleArchSysroots.empty() &&
+ !this->AllAppleArchSysrootsAreTheSame(archs, cmToCStr(sysroot))) {
+ for (std::string const& arch : archs) {
+ std::string const& archSysroot = this->AppleArchSysroots[arch];
+ if (cmIsOff(archSysroot)) {
+ continue;
+ }
+ if (filterArch.empty() || filterArch == arch) {
+ flags += " -Xarch_" + arch + " ";
+ // Combine sysroot flag and path to work with -Xarch
+ std::string arch_sysroot = *sysrootFlag + archSysroot;
+ flags += this->ConvertToOutputFormat(arch_sysroot, SHELL);
+ }
+ }
+ } else if (cmNonempty(sysroot)) {
+ flags += " ";
+ flags += *sysrootFlag;
+ flags += " ";
+ flags += this->ConvertToOutputFormat(*sysroot, SHELL);
+ }
+ }
+
+ cmProp deploymentTarget =
+ this->Makefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
+ std::string deploymentTargetFlagVar =
+ "CMAKE_" + lang + "_OSX_DEPLOYMENT_TARGET_FLAG";
+ cmProp deploymentTargetFlag =
+ this->Makefile->GetDefinition(deploymentTargetFlagVar);
+ if (cmNonempty(deploymentTargetFlag) && cmNonempty(deploymentTarget)) {
+ flags += " ";
+ flags += *deploymentTargetFlag;
+ flags += *deploymentTarget;
+ }
+ }
+}
+
+void cmLocalGenerator::AddLanguageFlags(std::string& flags,
+ cmGeneratorTarget const* target,
+ const std::string& lang,
+ const std::string& config)
+{
+ // Add language-specific flags.
+ this->AddConfigVariableFlags(flags, cmStrCat("CMAKE_", lang, "_FLAGS"),
+ config);
+
+ std::string compiler = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
+
+ std::string compilerSimulateId = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_SIMULATE_ID"));
+ if (lang == "Swift") {
+ if (cmProp v = target->GetProperty("Swift_LANGUAGE_VERSION")) {
+ if (cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
+ cmToCStr(this->Makefile->GetDefinition(
+ "CMAKE_Swift_COMPILER_VERSION")),
+ "4.2")) {
+ this->AppendFlags(flags, "-swift-version " + *v);
+ }
+ }
+ } else if (lang == "CUDA") {
+ target->AddCUDAArchitectureFlags(flags);
+ target->AddCUDAToolkitFlags(flags);
+ } else if (lang == "ISPC") {
+ target->AddISPCTargetFlags(flags);
+ } else if (lang == "RC" &&
+ this->Makefile->GetSafeDefinition("CMAKE_RC_COMPILER")
+ .find("llvm-rc") != std::string::npos) {
+ compiler = this->Makefile->GetSafeDefinition("CMAKE_C_COMPILER_ID");
+ if (!compiler.empty()) {
+ compilerSimulateId =
+ this->Makefile->GetSafeDefinition("CMAKE_C_SIMULATE_ID");
+ } else {
+ compiler = this->Makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_ID");
+ compilerSimulateId =
+ this->Makefile->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID");
+ }
+ }
+
+ // Add VFS Overlay for Clang compiliers
+ if (compiler == "Clang") {
+ if (cmProp vfsOverlay =
+ this->Makefile->GetDefinition("CMAKE_CLANG_VFS_OVERLAY")) {
+ if (compilerSimulateId == "MSVC") {
+ this->AppendCompileOptions(
+ flags,
+ std::vector<std::string>{ "-Xclang", "-ivfsoverlay", "-Xclang",
+ *vfsOverlay });
+ } else {
+ this->AppendCompileOptions(
+ flags, std::vector<std::string>{ "-ivfsoverlay", *vfsOverlay });
+ }
+ }
+ }
+ // Add MSVC runtime library flags. This is activated by the presence
+ // of a default selection whether or not it is overridden by a property.
+ cmProp msvcRuntimeLibraryDefault =
+ this->Makefile->GetDefinition("CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT");
+ if (cmNonempty(msvcRuntimeLibraryDefault)) {
+ cmProp msvcRuntimeLibraryValue =
+ target->GetProperty("MSVC_RUNTIME_LIBRARY");
+ if (!msvcRuntimeLibraryValue) {
+ msvcRuntimeLibraryValue = msvcRuntimeLibraryDefault;
+ }
+ std::string const msvcRuntimeLibrary = cmGeneratorExpression::Evaluate(
+ *msvcRuntimeLibraryValue, this, config, target);
+ if (!msvcRuntimeLibrary.empty()) {
+ if (cmProp msvcRuntimeLibraryOptions = this->Makefile->GetDefinition(
+ "CMAKE_" + lang + "_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_" +
+ msvcRuntimeLibrary)) {
+ this->AppendCompileOptions(flags, *msvcRuntimeLibraryOptions);
+ } else if ((this->Makefile->GetSafeDefinition(
+ "CMAKE_" + lang + "_COMPILER_ID") == "MSVC" ||
+ this->Makefile->GetSafeDefinition(
+ "CMAKE_" + lang + "_SIMULATE_ID") == "MSVC") &&
+ !cmSystemTools::GetErrorOccuredFlag()) {
+ // The compiler uses the MSVC ABI so it needs a known runtime library.
+ this->IssueMessage(MessageType::FATAL_ERROR,
+ "MSVC_RUNTIME_LIBRARY value '" +
+ msvcRuntimeLibrary + "' not known for this " +
+ lang + " compiler.");
+ }
+ }
+ }
+}
+
+void cmLocalGenerator::AddLanguageFlagsForLinking(
+ std::string& flags, cmGeneratorTarget const* target, const std::string& lang,
+ const std::string& config)
+{
+ if (this->Makefile->IsOn("CMAKE_" + lang +
+ "_LINK_WITH_STANDARD_COMPILE_OPTION")) {
+ // This toolchain requires use of the language standard flag
+ // when linking in order to use the matching standard library.
+ // FIXME: If CMake gains an abstraction for standard library
+ // selection, this will have to be reconciled with it.
+ this->AddCompilerRequirementFlag(flags, target, lang, config);
+ }
+
+ this->AddLanguageFlags(flags, target, lang, config);
+
+ if (target->IsIPOEnabled(lang, config)) {
+ this->AppendFeatureOptions(flags, lang, "IPO");
+ }
+}
+
+cmGeneratorTarget* cmLocalGenerator::FindGeneratorTargetToUse(
+ const std::string& name) const
+{
+ auto imported = this->ImportedGeneratorTargets.find(name);
+ if (imported != this->ImportedGeneratorTargets.end()) {
+ return imported->second;
+ }
+
+ // find local alias to imported target
+ auto aliased = this->AliasTargets.find(name);
+ if (aliased != this->AliasTargets.end()) {
+ imported = this->ImportedGeneratorTargets.find(aliased->second);
+ if (imported != this->ImportedGeneratorTargets.end()) {
+ return imported->second;
+ }
+ }
+
+ if (cmGeneratorTarget* t = this->FindLocalNonAliasGeneratorTarget(name)) {
+ return t;
+ }
+
+ return this->GetGlobalGenerator()->FindGeneratorTarget(name);
+}
+
+bool cmLocalGenerator::GetRealDependency(const std::string& inName,
+ const std::string& config,
+ std::string& dep)
+{
+ // Older CMake code may specify the dependency using the target
+ // output file rather than the target name. Such code would have
+ // been written before there was support for target properties that
+ // modify the name so stripping down to just the file name should
+ // produce the target name in this case.
+ std::string name = cmSystemTools::GetFilenameName(inName);
+
+ // If the input name is the empty string, there is no real
+ // dependency. Short-circuit the other checks:
+ if (name.empty()) {
+ return false;
+ }
+ if (cmSystemTools::GetFilenameLastExtension(name) == ".exe") {
+ name = cmSystemTools::GetFilenameWithoutLastExtension(name);
+ }
+
+ // Look for a CMake target with the given name.
+ if (cmGeneratorTarget* target = this->FindGeneratorTargetToUse(name)) {
+ // make sure it is not just a coincidence that the target name
+ // found is part of the inName
+ if (cmSystemTools::FileIsFullPath(inName)) {
+ std::string tLocation;
+ if (target->GetType() >= cmStateEnums::EXECUTABLE &&
+ target->GetType() <= cmStateEnums::MODULE_LIBRARY) {
+ tLocation = target->GetLocation(config);
+ tLocation = cmSystemTools::GetFilenamePath(tLocation);
+ tLocation = cmSystemTools::CollapseFullPath(tLocation);
+ }
+ std::string depLocation =
+ cmSystemTools::GetFilenamePath(std::string(inName));
+ depLocation = cmSystemTools::CollapseFullPath(depLocation);
+ if (depLocation != tLocation) {
+ // it is a full path to a depend that has the same name
+ // as a target but is in a different location so do not use
+ // the target as the depend
+ dep = inName;
+ return true;
+ }
+ }
+ switch (target->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ dep = target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact,
+ /*realname=*/true);
+ return true;
+ case cmStateEnums::OBJECT_LIBRARY:
+ // An object library has no single file on which to depend.
+ // This was listed to get the target-level dependency.
+ case cmStateEnums::INTERFACE_LIBRARY:
+ // An interface library has no file on which to depend.
+ // This was listed to get the target-level dependency.
+ case cmStateEnums::UTILITY:
+ case cmStateEnums::GLOBAL_TARGET:
+ // A utility target has no file on which to depend. This was listed
+ // only to get the target-level dependency.
+ return false;
+ }
+ }
+
+ // The name was not that of a CMake target. It must name a file.
+ if (cmSystemTools::FileIsFullPath(inName)) {
+ // This is a full path. Return it as given.
+ dep = inName;
+ return true;
+ }
+
+ // Check for a source file in this directory that matches the
+ // dependency.
+ if (cmSourceFile* sf = this->Makefile->GetSource(inName)) {
+ dep = sf->ResolveFullPath();
+ return true;
+ }
+
+ // Treat the name as relative to the source directory in which it
+ // was given.
+ dep = cmStrCat(this->GetCurrentSourceDirectory(), '/', inName);
+
+ // If the in-source path does not exist, assume it instead lives in the
+ // binary directory.
+ if (!cmSystemTools::FileExists(dep)) {
+ dep = cmStrCat(this->GetCurrentBinaryDirectory(), '/', inName);
+ }
+
+ dep = cmSystemTools::CollapseFullPath(dep, this->GetBinaryDirectory());
+
+ return true;
+}
+
+void cmLocalGenerator::AddSharedFlags(std::string& flags,
+ const std::string& lang, bool shared)
+{
+ std::string flagsVar;
+
+ // Add flags for dealing with shared libraries for this language.
+ if (shared) {
+ this->AppendFlags(flags,
+ this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_SHARED_LIBRARY_", lang, "_FLAGS")));
+ }
+}
+
+void cmLocalGenerator::AddCompilerRequirementFlag(
+ std::string& flags, cmGeneratorTarget const* target, const std::string& lang,
+ const std::string& config)
+{
+ cmStandardLevelResolver standardResolver(this->Makefile);
+
+ std::string const& optionFlagDef =
+ standardResolver.GetCompileOptionDef(target, lang, config);
+ if (!optionFlagDef.empty()) {
+ cmProp opt = target->Target->GetMakefile()->GetDefinition(optionFlagDef);
+ if (opt) {
+ std::vector<std::string> optVec = cmExpandedList(*opt);
+ for (std::string const& i : optVec) {
+ this->AppendFlagEscape(flags, i);
+ }
+ }
+ }
+}
+
+static void AddVisibilityCompileOption(std::string& flags,
+ cmGeneratorTarget const* target,
+ cmLocalGenerator* lg,
+ const std::string& lang,
+ std::string* warnCMP0063)
+{
+ std::string compileOption = "CMAKE_" + lang + "_COMPILE_OPTIONS_VISIBILITY";
+ cmProp opt = lg->GetMakefile()->GetDefinition(compileOption);
+ if (!opt) {
+ return;
+ }
+ std::string flagDefine = lang + "_VISIBILITY_PRESET";
+
+ cmProp prop = target->GetProperty(flagDefine);
+ if (!prop) {
+ return;
+ }
+ if (warnCMP0063) {
+ *warnCMP0063 += " " + flagDefine + "\n";
+ return;
+ }
+ if ((*prop != "hidden") && (*prop != "default") && (*prop != "protected") &&
+ (*prop != "internal")) {
+ std::ostringstream e;
+ e << "Target " << target->GetName() << " uses unsupported value \""
+ << *prop << "\" for " << flagDefine << "."
+ << " The supported values are: default, hidden, protected, and "
+ "internal.";
+ cmSystemTools::Error(e.str());
+ return;
+ }
+ std::string option = *opt + *prop;
+ lg->AppendFlags(flags, option);
+}
+
+static void AddInlineVisibilityCompileOption(std::string& flags,
+ cmGeneratorTarget const* target,
+ cmLocalGenerator* lg,
+ std::string* warnCMP0063,
+ const std::string& lang)
+{
+ std::string compileOption =
+ cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN");
+ cmProp opt = lg->GetMakefile()->GetDefinition(compileOption);
+ if (!opt) {
+ return;
+ }
+
+ bool prop = target->GetPropertyAsBool("VISIBILITY_INLINES_HIDDEN");
+ if (!prop) {
+ return;
+ }
+ if (warnCMP0063) {
+ *warnCMP0063 += " VISIBILITY_INLINES_HIDDEN\n";
+ return;
+ }
+ lg->AppendFlags(flags, *opt);
+}
+
+void cmLocalGenerator::AddVisibilityPresetFlags(
+ std::string& flags, cmGeneratorTarget const* target, const std::string& lang)
+{
+ if (lang.empty()) {
+ return;
+ }
+
+ std::string warnCMP0063;
+ std::string* pWarnCMP0063 = nullptr;
+ if (target->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ target->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ !target->IsExecutableWithExports()) {
+ switch (target->GetPolicyStatusCMP0063()) {
+ case cmPolicies::OLD:
+ return;
+ case cmPolicies::WARN:
+ pWarnCMP0063 = &warnCMP0063;
+ break;
+ default:
+ break;
+ }
+ }
+
+ AddVisibilityCompileOption(flags, target, this, lang, pWarnCMP0063);
+
+ if (lang == "CXX" || lang == "OBJCXX") {
+ AddInlineVisibilityCompileOption(flags, target, this, pWarnCMP0063, lang);
+ }
+
+ if (!warnCMP0063.empty() && this->WarnCMP0063.insert(target).second) {
+ std::ostringstream w;
+ /* clang-format off */
+ w <<
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0063) << "\n"
+ "Target \"" << target->GetName() << "\" of "
+ "type \"" << cmState::GetTargetTypeName(target->GetType()) << "\" "
+ "has the following visibility properties set for " << lang << ":\n" <<
+ warnCMP0063 <<
+ "For compatibility CMake is not honoring them for this target.";
+ /* clang-format on */
+ target->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING, w.str(), target->GetBacktrace());
+ }
+}
+
+void cmLocalGenerator::AddCMP0018Flags(std::string& flags,
+ cmGeneratorTarget const* target,
+ std::string const& lang,
+ const std::string& config)
+{
+ int targetType = target->GetType();
+
+ bool shared = ((targetType == cmStateEnums::SHARED_LIBRARY) ||
+ (targetType == cmStateEnums::MODULE_LIBRARY));
+
+ if (this->GetShouldUseOldFlags(shared, lang)) {
+ this->AddSharedFlags(flags, lang, shared);
+ } else {
+ if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ if (target->GetPropertyAsBool("POSITION_INDEPENDENT_CODE")) {
+ this->AddPositionIndependentFlags(flags, lang, targetType);
+ }
+ return;
+ }
+
+ if (target->GetLinkInterfaceDependentBoolProperty(
+ "POSITION_INDEPENDENT_CODE", config)) {
+ this->AddPositionIndependentFlags(flags, lang, targetType);
+ }
+ if (shared) {
+ this->AppendFeatureOptions(flags, lang, "DLL");
+ }
+ }
+}
+
+bool cmLocalGenerator::GetShouldUseOldFlags(bool shared,
+ const std::string& lang) const
+{
+ std::string originalFlags =
+ this->GlobalGenerator->GetSharedLibFlagsForLanguage(lang);
+ if (shared) {
+ std::string flagsVar = cmStrCat("CMAKE_SHARED_LIBRARY_", lang, "_FLAGS");
+ std::string const& flags = this->Makefile->GetSafeDefinition(flagsVar);
+
+ if (flags != originalFlags) {
+ switch (this->GetPolicyStatus(cmPolicies::CMP0018)) {
+ case cmPolicies::WARN: {
+ std::ostringstream e;
+ e << "Variable " << flagsVar
+ << " has been modified. CMake "
+ "will ignore the POSITION_INDEPENDENT_CODE target property "
+ "for "
+ "shared libraries and will use the "
+ << flagsVar
+ << " variable "
+ "instead. This may cause errors if the original content of "
+ << flagsVar << " was removed.\n"
+ << cmPolicies::GetPolicyWarning(cmPolicies::CMP0018);
+
+ this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+ CM_FALLTHROUGH;
+ }
+ case cmPolicies::OLD:
+ return true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+void cmLocalGenerator::AddPositionIndependentFlags(std::string& flags,
+ std::string const& lang,
+ int targetType)
+{
+ std::string picFlags;
+
+ if (targetType == cmStateEnums::EXECUTABLE) {
+ picFlags = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_PIE"));
+ }
+ if (picFlags.empty()) {
+ picFlags = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_PIC"));
+ }
+ if (!picFlags.empty()) {
+ std::vector<std::string> options = cmExpandedList(picFlags);
+ for (std::string const& o : options) {
+ this->AppendFlagEscape(flags, o);
+ }
+ }
+}
+
+void cmLocalGenerator::AddConfigVariableFlags(std::string& flags,
+ const std::string& var,
+ const std::string& config)
+{
+ // Add the flags from the variable itself.
+ this->AppendFlags(flags, this->Makefile->GetSafeDefinition(var));
+ // Add the flags from the build-type specific variable.
+ if (!config.empty()) {
+ const std::string flagsVar =
+ cmStrCat(var, '_', cmSystemTools::UpperCase(config));
+ this->AppendFlags(flags, this->Makefile->GetSafeDefinition(flagsVar));
+ }
+}
+
+void cmLocalGenerator::AppendFlags(std::string& flags,
+ const std::string& newFlags) const
+{
+ bool allSpaces = std::all_of(newFlags.begin(), newFlags.end(), cmIsSpace);
+
+ if (!newFlags.empty() && !allSpaces) {
+ if (!flags.empty()) {
+ flags += " ";
+ }
+ flags += newFlags;
+ }
+}
+
+void cmLocalGenerator::AppendFlags(
+ std::string& flags, const std::vector<BT<std::string>>& newFlags) const
+{
+ for (BT<std::string> const& flag : newFlags) {
+ this->AppendFlags(flags, flag.Value);
+ }
+}
+
+void cmLocalGenerator::AppendFlagEscape(std::string& flags,
+ const std::string& rawFlag) const
+{
+ this->AppendFlags(
+ flags,
+ this->EscapeForShell(rawFlag, false, false, false, this->IsNinjaMulti()));
+}
+
+void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target)
+{
+ std::vector<std::string> enabledLanguages =
+ this->GetState()->GetEnabledLanguages();
+ if (std::find(enabledLanguages.begin(), enabledLanguages.end(), "ISPC") ==
+ enabledLanguages.end()) {
+ return;
+ }
+
+ cmProp ispcHeaderSuffixProp = target->GetProperty("ISPC_HEADER_SUFFIX");
+ assert(ispcHeaderSuffixProp != nullptr);
+
+ std::vector<std::string> ispcArchSuffixes =
+ detail::ComputeISPCObjectSuffixes(target);
+ const bool extra_objects = (ispcArchSuffixes.size() > 1);
+
+ std::vector<std::string> configsList =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ for (std::string const& config : configsList) {
+
+ std::string rootObjectDir = target->GetObjectDirectory(config);
+ std::string headerDir = rootObjectDir;
+ if (cmProp prop = target->GetProperty("ISPC_HEADER_DIRECTORY")) {
+ headerDir = cmSystemTools::CollapseFullPath(
+ cmStrCat(this->GetBinaryDirectory(), '/', *prop));
+ }
+
+ std::vector<cmSourceFile*> sources;
+ target->GetSourceFiles(sources, config);
+
+ // build up the list of ispc headers and extra objects that this target is
+ // generating
+ for (cmSourceFile const* sf : sources) {
+ // Generate this object file's rule file.
+ const std::string& lang = sf->GetLanguage();
+ if (lang == "ISPC") {
+ std::string const& objectName = target->GetObjectName(sf);
+
+ // Drop both ".obj" and the source file extension
+ std::string ispcSource =
+ cmSystemTools::GetFilenameWithoutLastExtension(objectName);
+ ispcSource =
+ cmSystemTools::GetFilenameWithoutLastExtension(ispcSource);
+
+ auto headerPath =
+ cmStrCat(headerDir, '/', ispcSource, *ispcHeaderSuffixProp);
+ target->AddISPCGeneratedHeader(headerPath, config);
+ if (extra_objects) {
+ std::vector<std::string> objs = detail::ComputeISPCExtraObjects(
+ objectName, rootObjectDir, ispcArchSuffixes);
+ target->AddISPCGeneratedObject(std::move(objs), config);
+ }
+ }
+ }
+ }
+}
+
+void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
+{
+ std::vector<std::string> configsList =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+ for (std::string const& config : configsList) {
+ // FIXME: Refactor collection of sources to not evaluate object
+ // libraries.
+ std::vector<cmSourceFile*> sources;
+ target->GetSourceFiles(sources, config);
+
+ const std::string configUpper = cmSystemTools::UpperCase(config);
+ static const std::array<std::string, 4> langs = { { "C", "CXX", "OBJC",
+ "OBJCXX" } };
+
+ for (const std::string& lang : langs) {
+ auto langSources = std::count_if(
+ sources.begin(), sources.end(), [lang](cmSourceFile* sf) {
+ return lang == sf->GetLanguage() &&
+ !sf->GetProperty("SKIP_PRECOMPILE_HEADERS");
+ });
+ if (langSources == 0) {
+ continue;
+ }
+
+ std::vector<std::string> architectures;
+ if (!this->GetGlobalGenerator()->IsXcode()) {
+ target->GetAppleArchs(config, architectures);
+ }
+ if (architectures.empty()) {
+ architectures.emplace_back();
+ } else {
+ std::string useMultiArchPch;
+ for (const std::string& arch : architectures) {
+ const std::string pchHeader =
+ target->GetPchHeader(config, lang, arch);
+ if (!pchHeader.empty()) {
+ useMultiArchPch = cmStrCat(useMultiArchPch, ";-Xarch_", arch,
+ ";-include", pchHeader);
+ }
+ }
+
+ if (!useMultiArchPch.empty()) {
+
+ target->Target->AppendProperty(
+ cmStrCat(lang, "_COMPILE_OPTIONS_USE_PCH"),
+ cmStrCat("$<$<CONFIG:", config, ">:", useMultiArchPch, ">"));
+ }
+ }
+
+ for (const std::string& arch : architectures) {
+ const std::string pchSource = target->GetPchSource(config, lang, arch);
+ const std::string pchHeader = target->GetPchHeader(config, lang, arch);
+
+ if (pchSource.empty() || pchHeader.empty()) {
+ continue;
+ }
+
+ const std::string pchExtension =
+ this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
+
+ if (pchExtension.empty()) {
+ continue;
+ }
+
+ cmProp ReuseFrom =
+ target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
+
+ auto* pch_sf = this->Makefile->GetOrCreateSource(
+ pchSource, false, cmSourceFileLocationKind::Known);
+
+ if (!this->GetGlobalGenerator()->IsXcode()) {
+ if (!ReuseFrom) {
+ target->AddSource(pchSource, true);
+ }
+
+ const std::string pchFile = target->GetPchFile(config, lang, arch);
+
+ // Exclude the pch files from linking
+ if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
+ if (!ReuseFrom) {
+ pch_sf->AppendProperty(
+ "OBJECT_OUTPUTS",
+ cmStrCat("$<$<CONFIG:", config, ">:", pchFile, ">"));
+ } else {
+ auto* reuseTarget =
+ this->GlobalGenerator->FindGeneratorTarget(*ReuseFrom);
+
+ if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
+
+ const std::string compilerId =
+ this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
+
+ const std::string compilerVersion =
+ this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_COMPILER_VERSION"));
+
+ const std::string langFlags =
+ this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_FLAGS_", configUpper));
+
+ bool editAndContinueDebugInfo =
+ langFlags.find("/ZI") != std::string::npos ||
+ langFlags.find("-ZI") != std::string::npos;
+
+ bool enableDebuggingInformation =
+ langFlags.find("/Zi") != std::string::npos ||
+ langFlags.find("-Zi") != std::string::npos;
+
+ // MSVC 2008 is producing both .pdb and .idb files with /Zi.
+ bool msvc2008OrLess =
+ cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, compilerVersion.c_str(), "16.0") &&
+ compilerId == "MSVC";
+ // but not when used via toolset -Tv90
+ if (this->Makefile->GetSafeDefinition(
+ "CMAKE_VS_PLATFORM_TOOLSET") == "v90") {
+ msvc2008OrLess = false;
+ }
+
+ if (editAndContinueDebugInfo || msvc2008OrLess) {
+ this->CopyPchCompilePdb(config, target, *ReuseFrom,
+ reuseTarget, { ".pdb", ".idb" });
+ } else if (enableDebuggingInformation) {
+ this->CopyPchCompilePdb(config, target, *ReuseFrom,
+ reuseTarget, { ".pdb" });
+ }
+ }
+
+ // Link to the pch object file
+ std::string pchSourceObj =
+ reuseTarget->GetPchFileObject(config, lang, arch);
+
+ if (target->GetType() != cmStateEnums::OBJECT_LIBRARY) {
+ std::string linkerProperty = "LINK_FLAGS_";
+ if (target->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ linkerProperty = "STATIC_LIBRARY_FLAGS_";
+ }
+ target->Target->AppendProperty(
+ cmStrCat(linkerProperty, configUpper),
+ cmStrCat(" ",
+ this->ConvertToOutputFormat(pchSourceObj, SHELL)),
+ true);
+ } else {
+ target->Target->AppendProperty(
+ "INTERFACE_LINK_LIBRARIES",
+ cmStrCat("$<$<CONFIG:", config,
+ ">:$<LINK_ONLY:", pchSourceObj, ">>"));
+ }
+ }
+ } else {
+ pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str());
+ }
+
+ // Add pchHeader to source files, which will
+ // be grouped as "Precompile Header File"
+ auto* pchHeader_sf = this->Makefile->GetOrCreateSource(
+ pchHeader, false, cmSourceFileLocationKind::Known);
+ std::string err;
+ pchHeader_sf->ResolveFullPath(&err);
+ if (!err.empty()) {
+ std::ostringstream msg;
+ msg << "Unable to resolve full path of PCH-header '" << pchHeader
+ << "' assigned to target " << target->GetName()
+ << ", although its path is supposed to be known!";
+ this->IssueMessage(MessageType::FATAL_ERROR, msg.str());
+ }
+ target->AddSource(pchHeader);
+ }
+ }
+ }
+ }
+}
+
+void cmLocalGenerator::CopyPchCompilePdb(
+ const std::string& config, cmGeneratorTarget* target,
+ const std::string& ReuseFrom, cmGeneratorTarget* reuseTarget,
+ const std::vector<std::string>& extensions)
+{
+ const std::string pdb_prefix =
+ this->GetGlobalGenerator()->IsMultiConfig() ? cmStrCat(config, "/") : "";
+
+ const std::string target_compile_pdb_dir =
+ cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
+ target->GetName(), ".dir/");
+
+ const std::string copy_script =
+ cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake");
+ cmGeneratedFileStream file(copy_script);
+
+ file << "# CMake generated file\n";
+
+ file << "# The compiler generated pdb file needs to be written to disk\n"
+ << "# by mspdbsrv. The foreach retry loop is needed to make sure\n"
+ << "# the pdb file is ready to be copied.\n\n";
+
+ for (auto const& extension : extensions) {
+ const std::string from_file =
+ cmStrCat(reuseTarget->GetLocalGenerator()->GetCurrentBinaryDirectory(),
+ "/", ReuseFrom, ".dir/${PDB_PREFIX}", ReuseFrom, extension);
+
+ const std::string to_dir =
+ cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
+ target->GetName(), ".dir/${PDB_PREFIX}");
+
+ const std::string to_file = cmStrCat(to_dir, ReuseFrom, extension);
+
+ std::string dest_file = to_file;
+
+ std::string const& prefix = target->GetSafeProperty("PREFIX");
+ if (!prefix.empty()) {
+ dest_file = cmStrCat(to_dir, prefix, ReuseFrom, extension);
+ }
+
+ file << "foreach(retry RANGE 1 30)\n";
+ file << " if (EXISTS \"" << from_file << "\" AND (NOT EXISTS \""
+ << dest_file << "\" OR NOT \"" << dest_file << " \" IS_NEWER_THAN \""
+ << from_file << "\"))\n";
+ file << " execute_process(COMMAND ${CMAKE_COMMAND} -E copy";
+ file << " \"" << from_file << "\""
+ << " \"" << to_dir << "\" RESULT_VARIABLE result "
+ << " ERROR_QUIET)\n";
+ file << " if (NOT result EQUAL 0)\n"
+ << " execute_process(COMMAND ${CMAKE_COMMAND}"
+ << " -E sleep 1)\n"
+ << " else()\n";
+ if (!prefix.empty()) {
+ file << " file(REMOVE \"" << dest_file << "\")\n";
+ file << " file(RENAME \"" << to_file << "\" \"" << dest_file << "\")\n";
+ }
+ file << " break()\n"
+ << " endif()\n";
+ file << " elseif(NOT EXISTS \"" << from_file << "\")\n"
+ << " execute_process(COMMAND ${CMAKE_COMMAND}"
+ << " -E sleep 1)\n"
+ << " endif()\n";
+ file << "endforeach()\n";
+ }
+
+ bool stdPipesUTF8 = true;
+
+ auto configGenex = [&](cm::string_view expr) -> std::string {
+ if (this->GetGlobalGenerator()->IsVisualStudio()) {
+ return cmStrCat("$<$<CONFIG:", config, ">:", expr, ">");
+ }
+ return std::string(expr);
+ };
+
+ cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
+ { configGenex(cmSystemTools::GetCMakeCommand()),
+ configGenex(cmStrCat("-DPDB_PREFIX=", pdb_prefix)), configGenex("-P"),
+ configGenex(copy_script) });
+
+ const std::string no_main_dependency;
+ const std::vector<std::string> no_deps;
+ const char* no_message = "";
+ const char* no_current_dir = nullptr;
+ const cmPolicies::PolicyStatus cmp0116_new = cmPolicies::NEW;
+ std::vector<std::string> no_byproducts;
+
+ std::vector<std::string> outputs;
+ outputs.push_back(
+ cmStrCat(target_compile_pdb_dir, pdb_prefix, ReuseFrom, ".pdb"));
+
+ if (this->GetGlobalGenerator()->IsVisualStudio()) {
+ this->AddCustomCommandToTarget(
+ target->GetName(), outputs, no_deps, commandLines,
+ cmCustomCommandType::PRE_BUILD, no_message, no_current_dir, cmp0116_new,
+ true, false, "", "", false, cmObjectLibraryCommands::Accept,
+ stdPipesUTF8);
+ } else {
+ cmImplicitDependsList no_implicit_depends;
+ cmSourceFile* copy_rule = this->AddCustomCommandToOutput(
+ outputs, no_byproducts, no_deps, no_main_dependency, no_implicit_depends,
+ commandLines, no_message, no_current_dir, cmp0116_new, false, true,
+ false, false, "", "", stdPipesUTF8);
+
+ if (copy_rule) {
+ target->AddSource(copy_rule->ResolveFullPath());
+ }
+ }
+
+ target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
+ target_compile_pdb_dir);
+}
+
+namespace {
+
+inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf,
+ std::string const& filename)
+{
+ target->AddSourceFileToUnityBatch(sf->ResolveFullPath());
+ sf->SetProperty("UNITY_SOURCE_FILE", filename.c_str());
+}
+}
+
+void cmLocalGenerator::IncludeFileInUnitySources(
+ cmGeneratedFileStream& unity_file, std::string const& sf_full_path,
+ cmProp beforeInclude, cmProp afterInclude, cmProp uniqueIdName) const
+{
+ if (uniqueIdName && !uniqueIdName->empty()) {
+ std::string pathToHash;
+ auto PathEqOrSubDir = [](std::string const& a, std::string const& b) {
+ return (cmSystemTools::ComparePath(a, b) ||
+ cmSystemTools::IsSubDirectory(a, b));
+ };
+ const auto path = cmSystemTools::GetFilenamePath(sf_full_path);
+ if (PathEqOrSubDir(path, this->GetBinaryDirectory())) {
+ pathToHash = "BLD_" +
+ cmSystemTools::RelativePath(this->GetBinaryDirectory(), sf_full_path);
+ } else if (PathEqOrSubDir(path, this->GetSourceDirectory())) {
+ pathToHash = "SRC_" +
+ cmSystemTools::RelativePath(this->GetSourceDirectory(), sf_full_path);
+ } else {
+ pathToHash = "ABS_" + sf_full_path;
+ }
+ unity_file << "/* " << pathToHash << " */\n"
+ << "#undef " << *uniqueIdName << "\n"
+ << "#define " << *uniqueIdName << " unity_"
+ << cmSystemTools::ComputeStringMD5(pathToHash) << "\n";
+ }
+
+ if (beforeInclude) {
+ unity_file << *beforeInclude << "\n";
+ }
+
+ unity_file << "#include \"" << sf_full_path << "\"\n";
+
+ if (afterInclude) {
+ unity_file << *afterInclude << "\n";
+ }
+ unity_file << "\n";
+}
+
+std::vector<std::string> cmLocalGenerator::AddUnityFilesModeAuto(
+ cmGeneratorTarget* target, std::string const& lang,
+ std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude,
+ cmProp afterInclude, std::string const& filename_base, size_t batchSize)
+{
+ if (batchSize == 0) {
+ batchSize = filtered_sources.size();
+ }
+
+ cmProp uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID");
+
+ std::vector<std::string> unity_files;
+ for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0;
+ itemsLeft > 0; itemsLeft -= chunk, ++batch) {
+
+ chunk = std::min(itemsLeft, batchSize);
+
+ std::string filename = cmStrCat(filename_base, "unity_", batch,
+ (lang == "C") ? "_c.c" : "_cxx.cxx");
+
+ const std::string filename_tmp = cmStrCat(filename, ".tmp");
+ {
+ size_t begin = batch * batchSize;
+ size_t end = begin + chunk;
+
+ cmGeneratedFileStream file(
+ filename_tmp, false,
+ target->GetGlobalGenerator()->GetMakefileEncoding());
+ file << "/* generated by CMake */\n\n";
+
+ for (; begin != end; ++begin) {
+ cmSourceFile* sf = filtered_sources[begin];
+ RegisterUnitySources(target, sf, filename);
+ IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude,
+ afterInclude, uniqueIdName);
+ }
+ }
+ cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
+ unity_files.emplace_back(std::move(filename));
+ }
+ return unity_files;
+}
+
+std::vector<std::string> cmLocalGenerator::AddUnityFilesModeGroup(
+ cmGeneratorTarget* target, std::string const& lang,
+ std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude,
+ cmProp afterInclude, std::string const& filename_base)
+{
+ std::vector<std::string> unity_files;
+
+ // sources organized by group name. Drop any source
+ // without a group
+ std::unordered_map<std::string, std::vector<cmSourceFile*>> explicit_mapping;
+ for (cmSourceFile* sf : filtered_sources) {
+ if (cmProp value = sf->GetProperty("UNITY_GROUP")) {
+ auto i = explicit_mapping.find(*value);
+ if (i == explicit_mapping.end()) {
+ std::vector<cmSourceFile*> sources{ sf };
+ explicit_mapping.emplace(*value, sources);
+ } else {
+ i->second.emplace_back(sf);
+ }
+ }
+ }
+
+ cmProp uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID");
+
+ for (auto const& item : explicit_mapping) {
+ auto const& name = item.first;
+ std::string filename = cmStrCat(filename_base, "unity_", name,
+ (lang == "C") ? "_c.c" : "_cxx.cxx");
+
+ const std::string filename_tmp = cmStrCat(filename, ".tmp");
+ {
+ cmGeneratedFileStream file(
+ filename_tmp, false,
+ target->GetGlobalGenerator()->GetMakefileEncoding());
+ file << "/* generated by CMake */\n\n";
+
+ for (cmSourceFile* sf : item.second) {
+ RegisterUnitySources(target, sf, filename);
+ IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude,
+ afterInclude, uniqueIdName);
+ }
+ }
+ cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
+ unity_files.emplace_back(std::move(filename));
+ }
+
+ return unity_files;
+}
+
+void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target)
+{
+ if (!target->GetPropertyAsBool("UNITY_BUILD")) {
+ return;
+ }
+
+ // FIXME: Handle all configurations in multi-config generators.
+ std::string config;
+ if (!this->GetGlobalGenerator()->IsMultiConfig()) {
+ config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ }
+
+ std::string filename_base =
+ cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/",
+ target->GetName(), ".dir/Unity/");
+
+ // FIXME: Refactor collection of sources to not evaluate object libraries.
+ std::vector<cmSourceFile*> sources;
+ target->GetSourceFiles(sources, config);
+
+ cmProp batchSizeString = target->GetProperty("UNITY_BUILD_BATCH_SIZE");
+ const size_t unityBatchSize = batchSizeString
+ ? static_cast<size_t>(std::atoi(batchSizeString->c_str()))
+ : 0;
+
+ cmProp beforeInclude =
+ target->GetProperty("UNITY_BUILD_CODE_BEFORE_INCLUDE");
+ cmProp afterInclude = target->GetProperty("UNITY_BUILD_CODE_AFTER_INCLUDE");
+ cmProp unityMode = target->GetProperty("UNITY_BUILD_MODE");
+
+ for (std::string lang : { "C", "CXX" }) {
+ std::vector<cmSourceFile*> filtered_sources;
+ std::copy_if(sources.begin(), sources.end(),
+ std::back_inserter(filtered_sources), [&](cmSourceFile* sf) {
+ return sf->GetLanguage() == lang &&
+ !sf->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION") &&
+ !sf->GetPropertyAsBool("HEADER_FILE_ONLY") &&
+ !sf->GetProperty("COMPILE_OPTIONS") &&
+ !sf->GetProperty("COMPILE_DEFINITIONS") &&
+ !sf->GetProperty("COMPILE_FLAGS") &&
+ !sf->GetProperty("INCLUDE_DIRECTORIES");
+ });
+
+ std::vector<std::string> unity_files;
+ if (!unityMode || *unityMode == "BATCH") {
+ unity_files =
+ AddUnityFilesModeAuto(target, lang, filtered_sources, beforeInclude,
+ afterInclude, filename_base, unityBatchSize);
+ } else if (unityMode && *unityMode == "GROUP") {
+ unity_files =
+ AddUnityFilesModeGroup(target, lang, filtered_sources, beforeInclude,
+ afterInclude, filename_base);
+ } else {
+ // unity mode is set to an unsupported value
+ std::string e("Invalid UNITY_BUILD_MODE value of " + *unityMode +
+ " assigned to target " + target->GetName() +
+ ". Acceptable values are BATCH and GROUP.");
+ this->IssueMessage(MessageType::FATAL_ERROR, e);
+ }
+
+ for (auto const& file : unity_files) {
+ auto* unity = this->GetMakefile()->GetOrCreateSource(file);
+ target->AddSource(file, true);
+ unity->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "ON");
+ unity->SetProperty("UNITY_SOURCE_FILE", file.c_str());
+ }
+ }
+}
+
+void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags,
+ cmGeneratorTarget* target,
+ const std::string& config,
+ const std::string& lang)
+{
+ if (!target->IsIPOEnabled(lang, config)) {
+ return;
+ }
+
+ switch (target->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ break;
+ default:
+ return;
+ }
+
+ const std::string name = "CMAKE_" + lang + "_LINK_OPTIONS_IPO";
+ cmProp rawFlagsList = this->Makefile->GetDefinition(name);
+ if (rawFlagsList == nullptr) {
+ return;
+ }
+
+ std::vector<std::string> flagsList = cmExpandedList(*rawFlagsList);
+ for (std::string const& o : flagsList) {
+ this->AppendFlagEscape(flags, o);
+ }
+}
+
+void cmLocalGenerator::AppendPositionIndependentLinkerFlags(
+ std::string& flags, cmGeneratorTarget* target, const std::string& config,
+ const std::string& lang)
+{
+ // For now, only EXECUTABLE is concerned
+ if (target->GetType() != cmStateEnums::EXECUTABLE) {
+ return;
+ }
+
+ const char* PICValue = target->GetLinkPIEProperty(config);
+ if (PICValue == nullptr) {
+ // POSITION_INDEPENDENT_CODE is not set
+ return;
+ }
+
+ const std::string mode = cmIsOn(PICValue) ? "PIE" : "NO_PIE";
+
+ std::string supported = "CMAKE_" + lang + "_LINK_" + mode + "_SUPPORTED";
+ if (cmIsOff(this->Makefile->GetDefinition(supported))) {
+ return;
+ }
+
+ std::string name = "CMAKE_" + lang + "_LINK_OPTIONS_" + mode;
+
+ auto pieFlags = this->Makefile->GetSafeDefinition(name);
+ if (pieFlags.empty()) {
+ return;
+ }
+
+ std::vector<std::string> flagsList = cmExpandedList(pieFlags);
+ for (const auto& flag : flagsList) {
+ this->AppendFlagEscape(flags, flag);
+ }
+}
+
+void cmLocalGenerator::AppendCompileOptions(std::string& options,
+ std::string const& options_list,
+ const char* regex) const
+{
+ // Short-circuit if there are no options.
+ if (options_list.empty()) {
+ return;
+ }
+
+ // Expand the list of options.
+ std::vector<std::string> options_vec = cmExpandedList(options_list);
+ this->AppendCompileOptions(options, options_vec, regex);
+}
+
+void cmLocalGenerator::AppendCompileOptions(
+ std::string& options, const std::vector<std::string>& options_vec,
+ const char* regex) const
+{
+ if (regex != nullptr) {
+ // Filter flags upon specified reges.
+ cmsys::RegularExpression r(regex);
+
+ for (std::string const& opt : options_vec) {
+ if (r.find(opt)) {
+ this->AppendFlagEscape(options, opt);
+ }
+ }
+ } else {
+ for (std::string const& opt : options_vec) {
+ this->AppendFlagEscape(options, opt);
+ }
+ }
+}
+
+void cmLocalGenerator::AppendCompileOptions(
+ std::vector<BT<std::string>>& options,
+ const std::vector<BT<std::string>>& options_vec, const char* regex) const
+{
+ if (regex != nullptr) {
+ // Filter flags upon specified regular expressions.
+ cmsys::RegularExpression r(regex);
+
+ for (BT<std::string> const& opt : options_vec) {
+ if (r.find(opt.Value)) {
+ std::string flag;
+ this->AppendFlagEscape(flag, opt.Value);
+ options.emplace_back(std::move(flag), opt.Backtrace);
+ }
+ }
+ } else {
+ for (BT<std::string> const& opt : options_vec) {
+ std::string flag;
+ this->AppendFlagEscape(flag, opt.Value);
+ options.emplace_back(std::move(flag), opt.Backtrace);
+ }
+ }
+}
+
+void cmLocalGenerator::AppendIncludeDirectories(
+ std::vector<std::string>& includes, const std::string& includes_list,
+ const cmSourceFile& sourceFile) const
+{
+ // Short-circuit if there are no includes.
+ if (includes_list.empty()) {
+ return;
+ }
+
+ // Expand the list of includes.
+ std::vector<std::string> includes_vec = cmExpandedList(includes_list);
+ this->AppendIncludeDirectories(includes, includes_vec, sourceFile);
+}
+
+void cmLocalGenerator::AppendIncludeDirectories(
+ std::vector<std::string>& includes,
+ const std::vector<std::string>& includes_vec,
+ const cmSourceFile& sourceFile) const
+{
+ std::unordered_set<std::string> uniqueIncludes;
+
+ for (const std::string& include : includes_vec) {
+ if (!cmSystemTools::FileIsFullPath(include)) {
+ std::ostringstream e;
+ e << "Found relative path while evaluating include directories of "
+ "\""
+ << sourceFile.GetLocation().GetName() << "\":\n \"" << include
+ << "\"\n";
+
+ this->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+
+ std::string inc = include;
+
+ if (!cmIsOff(inc)) {
+ cmSystemTools::ConvertToUnixSlashes(inc);
+ }
+
+ if (uniqueIncludes.insert(inc).second) {
+ includes.push_back(std::move(inc));
+ }
+ }
+}
+
+void cmLocalGenerator::AppendDefines(std::set<std::string>& defines,
+ std::string const& defines_list) const
+{
+ std::set<BT<std::string>> tmp;
+ this->AppendDefines(tmp, ExpandListWithBacktrace(defines_list));
+ for (BT<std::string> const& i : tmp) {
+ defines.emplace(i.Value);
+ }
+}
+
+void cmLocalGenerator::AppendDefines(std::set<BT<std::string>>& defines,
+ std::string const& defines_list) const
+{
+ // Short-circuit if there are no definitions.
+ if (defines_list.empty()) {
+ return;
+ }
+
+ // Expand the list of definitions.
+ this->AppendDefines(defines, ExpandListWithBacktrace(defines_list));
+}
+
+void cmLocalGenerator::AppendDefines(
+ std::set<BT<std::string>>& defines,
+ const std::vector<BT<std::string>>& defines_vec) const
+{
+ for (BT<std::string> const& d : defines_vec) {
+ // Skip unsupported definitions.
+ if (!this->CheckDefinition(d.Value)) {
+ continue;
+ }
+ defines.insert(d);
+ }
+}
+
+void cmLocalGenerator::JoinDefines(const std::set<std::string>& defines,
+ std::string& definesString,
+ const std::string& lang)
+{
+ // Lookup the define flag for the current language.
+ std::string dflag = "-D";
+ if (!lang.empty()) {
+ cmProp df =
+ this->Makefile->GetDefinition(cmStrCat("CMAKE_", lang, "_DEFINE_FLAG"));
+ if (cmNonempty(df)) {
+ dflag = *df;
+ }
+ }
+ const char* itemSeparator = definesString.empty() ? "" : " ";
+ for (std::string const& define : defines) {
+ // Append the definition with proper escaping.
+ std::string def = dflag;
+ if (this->GetState()->UseWatcomWMake()) {
+ // The Watcom compiler does its own command line parsing instead
+ // of using the windows shell rules. Definitions are one of
+ // -DNAME
+ // -DNAME=<cpp-token>
+ // -DNAME="c-string with spaces and other characters(?@#$)"
+ //
+ // Watcom will properly parse each of these cases from the
+ // command line without any escapes. However we still have to
+ // get the '$' and '#' characters through WMake as '$$' and
+ // '$#'.
+ for (char c : define) {
+ if (c == '$' || c == '#') {
+ def += '$';
+ }
+ def += c;
+ }
+ } else {
+ // Make the definition appear properly on the command line. Use
+ // -DNAME="value" instead of -D"NAME=value" for historical reasons.
+ std::string::size_type eq = define.find('=');
+ def += define.substr(0, eq);
+ if (eq != std::string::npos) {
+ def += "=";
+ def += this->EscapeForShell(define.substr(eq + 1), true);
+ }
+ }
+ definesString += itemSeparator;
+ itemSeparator = " ";
+ definesString += def;
+ }
+}
+
+void cmLocalGenerator::AppendFeatureOptions(std::string& flags,
+ const std::string& lang,
+ const char* feature)
+{
+ cmProp optionList = this->Makefile->GetDefinition(
+ cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_", feature));
+ if (optionList != nullptr) {
+ std::vector<std::string> options = cmExpandedList(*optionList);
+ for (std::string const& o : options) {
+ this->AppendFlagEscape(flags, o);
+ }
+ }
+}
+
+cmProp cmLocalGenerator::GetFeature(const std::string& feature,
+ const std::string& config)
+{
+ std::string featureName = feature;
+ // TODO: Define accumulation policy for features (prepend, append,
+ // replace). Currently we always replace.
+ if (!config.empty()) {
+ featureName += "_";
+ featureName += cmSystemTools::UpperCase(config);
+ }
+ cmStateSnapshot snp = this->StateSnapshot;
+ while (snp.IsValid()) {
+ if (cmProp value = snp.GetDirectory().GetProperty(featureName)) {
+ return value;
+ }
+ snp = snp.GetBuildsystemDirectoryParent();
+ }
+ return nullptr;
+}
+
+std::string cmLocalGenerator::GetProjectName() const
+{
+ return this->StateSnapshot.GetProjectName();
+}
+
+std::string cmLocalGenerator::ConstructComment(
+ cmCustomCommandGenerator const& ccg, const char* default_comment) const
+{
+ // Check for a comment provided with the command.
+ if (ccg.GetComment()) {
+ return ccg.GetComment();
+ }
+
+ // Construct a reasonable default comment if possible.
+ if (!ccg.GetOutputs().empty()) {
+ std::string comment;
+ comment = "Generating ";
+ const char* sep = "";
+ std::string currentBinaryDir = this->GetCurrentBinaryDirectory();
+ for (std::string const& o : ccg.GetOutputs()) {
+ comment += sep;
+ comment += this->MaybeConvertToRelativePath(currentBinaryDir, o);
+ sep = ", ";
+ }
+ return comment;
+ }
+
+ // Otherwise use the provided default.
+ return default_comment;
+}
+
+class cmInstallTargetGeneratorLocal : public cmInstallTargetGenerator
+{
+public:
+ cmInstallTargetGeneratorLocal(cmLocalGenerator* lg, std::string const& t,
+ std::string const& dest, bool implib)
+ : cmInstallTargetGenerator(
+ t, dest, implib, "", std::vector<std::string>(), "Unspecified",
+ cmInstallGenerator::SelectMessageLevel(lg->GetMakefile()), false,
+ false)
+ {
+ this->Compute(lg);
+ }
+};
+
+void cmLocalGenerator::GenerateTargetInstallRules(
+ std::ostream& os, const std::string& config,
+ std::vector<std::string> const& configurationTypes)
+{
+ // Convert the old-style install specification from each target to
+ // an install generator and run it.
+ const auto& tgts = this->GetGeneratorTargets();
+ for (const auto& l : tgts) {
+ if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ continue;
+ }
+
+ // Include the user-specified pre-install script for this target.
+ if (cmProp preinstall = l->GetProperty("PRE_INSTALL_SCRIPT")) {
+ cmInstallScriptGenerator g(*preinstall, false, "", false);
+ g.Generate(os, config, configurationTypes);
+ }
+
+ // Install this target if a destination is given.
+ if (!l->Target->GetInstallPath().empty()) {
+ // Compute the full install destination. Note that converting
+ // to unix slashes also removes any trailing slash.
+ // We also skip over the leading slash given by the user.
+ std::string destination = l->Target->GetInstallPath().substr(1);
+ cmSystemTools::ConvertToUnixSlashes(destination);
+ if (destination.empty()) {
+ destination = ".";
+ }
+
+ // Generate the proper install generator for this target type.
+ switch (l->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY: {
+ // Use a target install generator.
+ cmInstallTargetGeneratorLocal g(this, l->GetName(), destination,
+ false);
+ g.Generate(os, config, configurationTypes);
+ } break;
+ case cmStateEnums::SHARED_LIBRARY: {
+#if defined(_WIN32) || defined(__CYGWIN__)
+ // Special code to handle DLL. Install the import library
+ // to the normal destination and the DLL to the runtime
+ // destination.
+ cmInstallTargetGeneratorLocal g1(this, l->GetName(), destination,
+ true);
+ g1.Generate(os, config, configurationTypes);
+ // We also skip over the leading slash given by the user.
+ destination = l->Target->GetRuntimeInstallPath().substr(1);
+ cmSystemTools::ConvertToUnixSlashes(destination);
+ cmInstallTargetGeneratorLocal g2(this, l->GetName(), destination,
+ false);
+ g2.Generate(os, config, configurationTypes);
+#else
+ // Use a target install generator.
+ cmInstallTargetGeneratorLocal g(this, l->GetName(), destination,
+ false);
+ g.Generate(os, config, configurationTypes);
+#endif
+ } break;
+ default:
+ break;
+ }
+ }
+
+ // Include the user-specified post-install script for this target.
+ if (cmProp postinstall = l->GetProperty("POST_INSTALL_SCRIPT")) {
+ cmInstallScriptGenerator g(*postinstall, false, "", false);
+ g.Generate(os, config, configurationTypes);
+ }
+ }
+}
+
+#if defined(CM_LG_ENCODE_OBJECT_NAMES)
+static bool cmLocalGeneratorShortenObjectName(std::string& objName,
+ std::string::size_type max_len)
+{
+ // Replace the beginning of the path portion of the object name with
+ // its own md5 sum.
+ std::string::size_type pos =
+ objName.find('/', objName.size() - max_len + 32);
+ if (pos != std::string::npos) {
+ cmCryptoHash md5(cmCryptoHash::AlgoMD5);
+ std::string md5name = cmStrCat(md5.HashString(objName.substr(0, pos)),
+ cm::string_view(objName).substr(pos));
+ objName = md5name;
+
+ // The object name is now short enough.
+ return true;
+ }
+ // The object name could not be shortened enough.
+ return false;
+}
+
+bool cmLocalGeneratorCheckObjectName(std::string& objName,
+ std::string::size_type dir_len,
+ std::string::size_type max_total_len)
+{
+ // Enforce the maximum file name length if possible.
+ std::string::size_type max_obj_len = max_total_len;
+ if (dir_len < max_total_len) {
+ max_obj_len = max_total_len - dir_len;
+ if (objName.size() > max_obj_len) {
+ // The current object file name is too long. Try to shorten it.
+ return cmLocalGeneratorShortenObjectName(objName, max_obj_len);
+ }
+ // The object file name is short enough.
+ return true;
+ }
+ // The build directory in which the object will be stored is
+ // already too deep.
+ return false;
+}
+#endif
+
+std::string& cmLocalGenerator::CreateSafeUniqueObjectFileName(
+ const std::string& sin, std::string const& dir_max)
+{
+ // Look for an existing mapped name for this object file.
+ auto it = this->UniqueObjectNamesMap.find(sin);
+
+ // If no entry exists create one.
+ if (it == this->UniqueObjectNamesMap.end()) {
+ // Start with the original name.
+ std::string ssin = sin;
+
+ // Avoid full paths by removing leading slashes.
+ ssin.erase(0, ssin.find_first_not_of('/'));
+
+ // Avoid full paths by removing colons.
+ std::replace(ssin.begin(), ssin.end(), ':', '_');
+
+ // Avoid relative paths that go up the tree.
+ cmSystemTools::ReplaceString(ssin, "../", "__/");
+
+ // Avoid spaces.
+ std::replace(ssin.begin(), ssin.end(), ' ', '_');
+
+ // Mangle the name if necessary.
+ if (this->Makefile->IsOn("CMAKE_MANGLE_OBJECT_FILE_NAMES")) {
+ bool done;
+ int cc = 0;
+ char rpstr[100];
+ sprintf(rpstr, "_p_");
+ cmSystemTools::ReplaceString(ssin, "+", rpstr);
+ std::string sssin = sin;
+ do {
+ done = true;
+ for (it = this->UniqueObjectNamesMap.begin();
+ it != this->UniqueObjectNamesMap.end(); ++it) {
+ if (it->second == ssin) {
+ done = false;
+ }
+ }
+ if (done) {
+ break;
+ }
+ sssin = ssin;
+ cmSystemTools::ReplaceString(ssin, "_p_", rpstr);
+ sprintf(rpstr, "_p%d_", cc++);
+ } while (!done);
+ }
+
+#if defined(CM_LG_ENCODE_OBJECT_NAMES)
+ if (!cmLocalGeneratorCheckObjectName(ssin, dir_max.size(),
+ this->ObjectPathMax)) {
+ // Warn if this is the first time the path has been seen.
+ if (this->ObjectMaxPathViolations.insert(dir_max).second) {
+ std::ostringstream m;
+ /* clang-format off */
+ m << "The object file directory\n"
+ << " " << dir_max << "\n"
+ << "has " << dir_max.size() << " characters. "
+ << "The maximum full path to an object file is "
+ << this->ObjectPathMax << " characters "
+ << "(see CMAKE_OBJECT_PATH_MAX). "
+ << "Object file\n"
+ << " " << ssin << "\n"
+ << "cannot be safely placed under this directory. "
+ << "The build may not work correctly.";
+ /* clang-format on */
+ this->IssueMessage(MessageType::WARNING, m.str());
+ }
+ }
+#else
+ (void)dir_max;
+#endif
+
+ // Insert the newly mapped object file name.
+ std::map<std::string, std::string>::value_type e(sin, ssin);
+ it = this->UniqueObjectNamesMap.insert(e).first;
+ }
+
+ // Return the map entry.
+ return it->second;
+}
+
+void cmLocalGenerator::ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& /*unused*/,
+ cmGeneratorTarget const* /*unused*/)
+{
+}
+
+bool cmLocalGenerator::IsWindowsShell() const
+{
+ return this->GetState()->UseWindowsShell();
+}
+
+bool cmLocalGenerator::IsWatcomWMake() const
+{
+ return this->GetState()->UseWatcomWMake();
+}
+
+bool cmLocalGenerator::IsMinGWMake() const
+{
+ return this->GetState()->UseMinGWMake();
+}
+
+bool cmLocalGenerator::IsNMake() const
+{
+ return this->GetState()->UseNMake();
+}
+
+bool cmLocalGenerator::IsNinjaMulti() const
+{
+ return this->GetState()->UseNinjaMulti();
+}
+
+std::string cmLocalGenerator::GetObjectFileNameWithoutTarget(
+ const cmSourceFile& source, std::string const& dir_max,
+ bool* hasSourceExtension, char const* customOutputExtension)
+{
+ // Construct the object file name using the full path to the source
+ // file which is its only unique identification.
+ std::string const& fullPath = source.GetFullPath();
+
+ // Try referencing the source relative to the source tree.
+ std::string relFromSource = this->MaybeConvertToRelativePath(
+ this->GetCurrentSourceDirectory(), fullPath);
+ assert(!relFromSource.empty());
+ bool relSource = !cmSystemTools::FileIsFullPath(relFromSource);
+ bool subSource = relSource && relFromSource[0] != '.';
+
+ // Try referencing the source relative to the binary tree.
+ std::string relFromBinary = this->MaybeConvertToRelativePath(
+ this->GetCurrentBinaryDirectory(), fullPath);
+ assert(!relFromBinary.empty());
+ bool relBinary = !cmSystemTools::FileIsFullPath(relFromBinary);
+ bool subBinary = relBinary && relFromBinary[0] != '.';
+
+ // Select a nice-looking reference to the source file to construct
+ // the object file name.
+ std::string objectName;
+ // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
+ // NOLINTNEXTLINE(bugprone-branch-clone)
+ if ((relSource && !relBinary) || (subSource && !subBinary)) {
+ objectName = relFromSource;
+ } else if ((relBinary && !relSource) || (subBinary && !subSource) ||
+ relFromBinary.length() < relFromSource.length()) {
+ objectName = relFromBinary;
+ } else {
+ objectName = relFromSource;
+ }
+
+ // if it is still a full path check for the try compile case
+ // try compile never have in source sources, and should not
+ // have conflicting source file names in the same target
+ if (cmSystemTools::FileIsFullPath(objectName)) {
+ if (this->GetGlobalGenerator()->GetCMakeInstance()->GetIsInTryCompile()) {
+ objectName = cmSystemTools::GetFilenameName(source.GetFullPath());
+ }
+ }
+
+ // Ensure that for the CMakeFiles/<target>.dir/generated_source_file
+ // we don't end up having:
+ // CMakeFiles/<target>.dir/CMakeFiles/<target>.dir/generated_source_file.obj
+ cmProp unitySourceFile = source.GetProperty("UNITY_SOURCE_FILE");
+ cmProp pchExtension = source.GetProperty("PCH_EXTENSION");
+ const bool isPchObject = objectName.find("cmake_pch") != std::string::npos;
+ if (unitySourceFile || pchExtension || isPchObject) {
+ if (pchExtension) {
+ customOutputExtension = pchExtension->c_str();
+ }
+
+ cmsys::RegularExpression var("(CMakeFiles/[^/]+.dir/)");
+ if (var.find(objectName)) {
+ objectName.erase(var.start(), var.end() - var.start());
+ }
+ }
+
+ // Replace the original source file extension with the object file
+ // extension.
+ bool keptSourceExtension = true;
+ if (!source.GetPropertyAsBool("KEEP_EXTENSION")) {
+ // Decide whether this language wants to replace the source
+ // extension with the object extension. For CMake 2.4
+ // compatibility do this by default.
+ bool replaceExt = this->NeedBackwardsCompatibility_2_4();
+ if (!replaceExt) {
+ std::string lang = source.GetLanguage();
+ if (!lang.empty()) {
+ replaceExt = this->Makefile->IsOn(
+ cmStrCat("CMAKE_", lang, "_OUTPUT_EXTENSION_REPLACE"));
+ }
+ }
+
+ // Remove the source extension if it is to be replaced.
+ if (replaceExt || customOutputExtension) {
+ keptSourceExtension = false;
+ std::string::size_type dot_pos = objectName.rfind('.');
+ if (dot_pos != std::string::npos) {
+ objectName = objectName.substr(0, dot_pos);
+ }
+ }
+
+ // Store the new extension.
+ if (customOutputExtension) {
+ objectName += customOutputExtension;
+ } else {
+ objectName += this->GlobalGenerator->GetLanguageOutputExtension(source);
+ }
+ }
+ if (hasSourceExtension) {
+ *hasSourceExtension = keptSourceExtension;
+ }
+
+ // Convert to a safe name.
+ return this->CreateSafeUniqueObjectFileName(objectName, dir_max);
+}
+
+std::string cmLocalGenerator::GetSourceFileLanguage(const cmSourceFile& source)
+{
+ return source.GetLanguage();
+}
+
+cmake* cmLocalGenerator::GetCMakeInstance() const
+{
+ return this->GlobalGenerator->GetCMakeInstance();
+}
+
+std::string const& cmLocalGenerator::GetSourceDirectory() const
+{
+ return this->GetCMakeInstance()->GetHomeDirectory();
+}
+
+std::string const& cmLocalGenerator::GetBinaryDirectory() const
+{
+ return this->GetCMakeInstance()->GetHomeOutputDirectory();
+}
+
+std::string const& cmLocalGenerator::GetCurrentBinaryDirectory() const
+{
+ return this->StateSnapshot.GetDirectory().GetCurrentBinary();
+}
+
+std::string const& cmLocalGenerator::GetCurrentSourceDirectory() const
+{
+ return this->StateSnapshot.GetDirectory().GetCurrentSource();
+}
+
+std::string cmLocalGenerator::MaybeConvertToRelativePath(
+ std::string const& local_path, std::string const& remote_path) const
+{
+ return this->StateSnapshot.GetDirectory().ConvertToRelPathIfNotContained(
+ local_path, remote_path);
+}
+
+std::string cmLocalGenerator::GetTargetDirectory(
+ const cmGeneratorTarget* /*unused*/) const
+{
+ cmSystemTools::Error("GetTargetDirectory"
+ " called on cmLocalGenerator");
+ return "";
+}
+
+KWIML_INT_uint64_t cmLocalGenerator::GetBackwardsCompatibility()
+{
+ // The computed version may change until the project is fully
+ // configured.
+ if (!this->BackwardsCompatibilityFinal) {
+ unsigned int major = 0;
+ unsigned int minor = 0;
+ unsigned int patch = 0;
+ if (cmProp value =
+ this->Makefile->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY")) {
+ switch (sscanf(value->c_str(), "%u.%u.%u", &major, &minor, &patch)) {
+ case 2:
+ patch = 0;
+ break;
+ case 1:
+ minor = 0;
+ patch = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ this->BackwardsCompatibility = CMake_VERSION_ENCODE(major, minor, patch);
+ this->BackwardsCompatibilityFinal = true;
+ }
+
+ return this->BackwardsCompatibility;
+}
+
+bool cmLocalGenerator::NeedBackwardsCompatibility_2_4()
+{
+ // Check the policy to decide whether to pay attention to this
+ // variable.
+ switch (this->GetPolicyStatus(cmPolicies::CMP0001)) {
+ case cmPolicies::WARN:
+ // WARN is just OLD without warning because user code does not
+ // always affect whether this check is done.
+ case cmPolicies::OLD:
+ // Old behavior is to check the variable.
+ break;
+ case cmPolicies::NEW:
+ // New behavior is to ignore the variable.
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ // This will never be the case because the only way to require
+ // the setting is to require the user to specify version policy
+ // 2.6 or higher. Once we add that requirement then this whole
+ // method can be removed anyway.
+ return false;
+ }
+
+ // Compatibility is needed if CMAKE_BACKWARDS_COMPATIBILITY is set
+ // equal to or lower than the given version.
+ KWIML_INT_uint64_t actual_compat = this->GetBackwardsCompatibility();
+ return (actual_compat && actual_compat <= CMake_VERSION_ENCODE(2, 4, 255));
+}
+
+cmPolicies::PolicyStatus cmLocalGenerator::GetPolicyStatus(
+ cmPolicies::PolicyID id) const
+{
+ return this->Makefile->GetPolicyStatus(id);
+}
+
+bool cmLocalGenerator::CheckDefinition(std::string const& define) const
+{
+ // Many compilers do not support -DNAME(arg)=sdf so we disable it.
+ std::string::size_type pos = define.find_first_of("(=");
+ if (pos != std::string::npos) {
+ if (define[pos] == '(') {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "WARNING: Function-style preprocessor definitions may not be "
+ << "passed on the compiler command line because many compilers "
+ << "do not support it.\n"
+ << "CMake is dropping a preprocessor definition: " << define << "\n"
+ << "Consider defining the macro in a (configured) header file.\n";
+ /* clang-format on */
+ cmSystemTools::Message(e.str());
+ return false;
+ }
+ }
+
+ // Many compilers do not support # in the value so we disable it.
+ if (define.find_first_of('#') != std::string::npos) {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "WARNING: Preprocessor definitions containing '#' may not be "
+ << "passed on the compiler command line because many compilers "
+ << "do not support it.\n"
+ << "CMake is dropping a preprocessor definition: " << define << "\n"
+ << "Consider defining the macro in a (configured) header file.\n";
+ /* clang-format on */
+ cmSystemTools::Message(e.str());
+ return false;
+ }
+
+ // Assume it is supported.
+ return true;
+}
+
+static void cmLGInfoProp(cmMakefile* mf, cmGeneratorTarget* target,
+ const std::string& prop)
+{
+ if (cmProp val = target->GetProperty(prop)) {
+ mf->AddDefinition(prop, *val);
+ }
+}
+
+void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target,
+ const std::string& targetName,
+ const std::string& fname)
+{
+ // Find the Info.plist template.
+ cmProp in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST");
+ std::string inFile = cmNonempty(in) ? *in : "MacOSXBundleInfo.plist.in";
+ if (!cmSystemTools::FileIsFullPath(inFile)) {
+ std::string inMod = this->Makefile->GetModulesFile(inFile);
+ if (!inMod.empty()) {
+ inFile = inMod;
+ }
+ }
+ if (!cmSystemTools::FileExists(inFile, true)) {
+ std::ostringstream e;
+ e << "Target " << target->GetName() << " Info.plist template \"" << inFile
+ << "\" could not be found.";
+ cmSystemTools::Error(e.str());
+ return;
+ }
+
+ // Convert target properties to variables in an isolated makefile
+ // scope to configure the file. If properties are set they will
+ // override user make variables. If not the configuration will fall
+ // back to the directory-level values set by the user.
+ cmMakefile* mf = this->Makefile;
+ cmMakefile::ScopePushPop varScope(mf);
+ mf->AddDefinition("MACOSX_BUNDLE_EXECUTABLE_NAME", targetName);
+ cmLGInfoProp(mf, target, "MACOSX_BUNDLE_INFO_STRING");
+ cmLGInfoProp(mf, target, "MACOSX_BUNDLE_ICON_FILE");
+ cmLGInfoProp(mf, target, "MACOSX_BUNDLE_GUI_IDENTIFIER");
+ cmLGInfoProp(mf, target, "MACOSX_BUNDLE_LONG_VERSION_STRING");
+ cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_NAME");
+ cmLGInfoProp(mf, target, "MACOSX_BUNDLE_SHORT_VERSION_STRING");
+ cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_VERSION");
+ cmLGInfoProp(mf, target, "MACOSX_BUNDLE_COPYRIGHT");
+ mf->ConfigureFile(inFile, fname, false, false, false);
+}
+
+void cmLocalGenerator::GenerateFrameworkInfoPList(
+ cmGeneratorTarget* target, const std::string& targetName,
+ const std::string& fname)
+{
+ // Find the Info.plist template.
+ cmProp in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST");
+ std::string inFile = cmNonempty(in) ? *in : "MacOSXFrameworkInfo.plist.in";
+ if (!cmSystemTools::FileIsFullPath(inFile)) {
+ std::string inMod = this->Makefile->GetModulesFile(inFile);
+ if (!inMod.empty()) {
+ inFile = inMod;
+ }
+ }
+ if (!cmSystemTools::FileExists(inFile, true)) {
+ std::ostringstream e;
+ e << "Target " << target->GetName() << " Info.plist template \"" << inFile
+ << "\" could not be found.";
+ cmSystemTools::Error(e.str());
+ return;
+ }
+
+ // Convert target properties to variables in an isolated makefile
+ // scope to configure the file. If properties are set they will
+ // override user make variables. If not the configuration will fall
+ // back to the directory-level values set by the user.
+ cmMakefile* mf = this->Makefile;
+ cmMakefile::ScopePushPop varScope(mf);
+ mf->AddDefinition("MACOSX_FRAMEWORK_NAME", targetName);
+ cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_ICON_FILE");
+ cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_IDENTIFIER");
+ cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_SHORT_VERSION_STRING");
+ cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_VERSION");
+ mf->ConfigureFile(inFile, fname, false, false, false);
+}
+
+namespace {
+cm::string_view CustomOutputRoleKeyword(cmLocalGenerator::OutputRole role)
+{
+ return (role == cmLocalGenerator::OutputRole::Primary ? "OUTPUT"_s
+ : "BYPRODUCTS"_s);
+}
+
+void CreateGeneratedSource(cmLocalGenerator& lg, const std::string& output,
+ cmLocalGenerator::OutputRole role,
+ cmCommandOrigin origin,
+ const cmListFileBacktrace& lfbt)
+{
+ if (cmGeneratorExpression::Find(output) != std::string::npos) {
+ lg.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Generator expressions in custom command outputs are not implemented!",
+ lfbt);
+ return;
+ }
+
+ // Make sure the file will not be generated into the source
+ // directory during an out of source build.
+ if (!lg.GetMakefile()->CanIWriteThisFile(output)) {
+ lg.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(CustomOutputRoleKeyword(role), " path\n ", output,
+ "\nin a source directory as an output of custom command."),
+ lfbt);
+ return;
+ }
+
+ // Make sure the output file name has no invalid characters.
+ std::string::size_type pos = output.find_first_of("#<>");
+ if (pos != std::string::npos) {
+ lg.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(CustomOutputRoleKeyword(role), " containing a \"", output[pos],
+ "\" is not allowed."),
+ lfbt);
+ return;
+ }
+
+ // Outputs without generator expressions from the project are already
+ // created and marked as generated. Do not mark them again, because
+ // other commands might have overwritten the property.
+ if (origin == cmCommandOrigin::Generator) {
+ lg.GetMakefile()->GetOrCreateGeneratedSource(output);
+ }
+}
+
+std::string ComputeCustomCommandRuleFileName(cmLocalGenerator& lg,
+ cmListFileBacktrace const& bt,
+ std::string const& output)
+{
+ // If the output path has no generator expressions, use it directly.
+ if (cmGeneratorExpression::Find(output) == std::string::npos) {
+ return output;
+ }
+
+ // The output path contains a generator expression, but we must choose
+ // a single source file path to which to attach the custom command.
+ // Use some heuristics to provie a nice-looking name when possible.
+
+ // If the only genex is $<CONFIG>, replace that gracefully.
+ {
+ std::string simple = output;
+ cmSystemTools::ReplaceString(simple, "$<CONFIG>", "(CONFIG)");
+ if (cmGeneratorExpression::Find(simple) == std::string::npos) {
+ return simple;
+ }
+ }
+
+ // If the genex evaluates to the same value in all configurations, use that.
+ {
+ std::vector<std::string> allConfigOutputs =
+ lg.ExpandCustomCommandOutputGenex(output, bt);
+ if (allConfigOutputs.size() == 1) {
+ return allConfigOutputs.front();
+ }
+ }
+
+ // Fall back to a deterministic unique name.
+ cmCryptoHash h(cmCryptoHash::AlgoSHA256);
+ return cmStrCat(lg.GetCurrentBinaryDirectory(), "/CMakeFiles/",
+ h.HashString(output).substr(0, 16));
+}
+
+cmSourceFile* AddCustomCommand(
+ cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+ cmCommandOrigin origin, const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends, const std::string& main_dependency,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, bool replace, bool escapeOldStyle,
+ bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+ const std::string& job_pool, bool stdPipesUTF8,
+ cmPolicies::PolicyStatus cmp0116)
+{
+ cmMakefile* mf = lg.GetMakefile();
+
+ // Choose a source file on which to store the custom command.
+ cmSourceFile* file = nullptr;
+ if (!commandLines.empty() && !main_dependency.empty()) {
+ // The main dependency was specified. Use it unless a different
+ // custom command already used it.
+ file = mf->GetSource(main_dependency);
+ if (file && file->GetCustomCommand() && !replace) {
+ // The main dependency already has a custom command.
+ if (commandLines == file->GetCustomCommand()->GetCommandLines()) {
+ // The existing custom command is identical. Silently ignore
+ // the duplicate.
+ return file;
+ }
+ // The existing custom command is different. We need to
+ // generate a rule file for this new command.
+ file = nullptr;
+ } else if (!file) {
+ file = mf->CreateSource(main_dependency);
+ }
+ }
+
+ // Generate a rule file if the main dependency is not available.
+ if (!file) {
+ cmGlobalGenerator* gg = lg.GetGlobalGenerator();
+
+ // Construct a rule file associated with the first output produced.
+ std::string outName = gg->GenerateRuleFile(
+ ComputeCustomCommandRuleFileName(lg, lfbt, outputs[0]));
+
+ // Check if the rule file already exists.
+ file = mf->GetSource(outName, cmSourceFileLocationKind::Known);
+ if (file && file->GetCustomCommand() && !replace) {
+ // The rule file already exists.
+ if (commandLines != file->GetCustomCommand()->GetCommandLines()) {
+ lg.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Attempt to add a custom rule to output\n ", outName,
+ "\nwhich already has a custom rule."),
+ lfbt);
+ }
+ return file;
+ }
+
+ // Create a cmSourceFile for the rule file.
+ if (!file) {
+ file = mf->CreateSource(outName, true, cmSourceFileLocationKind::Known);
+ }
+ file->SetProperty("__CMAKE_RULE", "1");
+ }
+
+ // Attach the custom command to the file.
+ if (file) {
+ // Construct a complete list of dependencies.
+ std::vector<std::string> depends2(depends);
+ if (!main_dependency.empty()) {
+ depends2.push_back(main_dependency);
+ }
+
+ std::unique_ptr<cmCustomCommand> cc = cm::make_unique<cmCustomCommand>(
+ outputs, byproducts, depends2, commandLines, lfbt, comment, workingDir,
+ stdPipesUTF8);
+ cc->SetEscapeOldStyle(escapeOldStyle);
+ cc->SetEscapeAllowMakeVars(true);
+ cc->SetImplicitDepends(implicit_depends);
+ cc->SetUsesTerminal(uses_terminal);
+ cc->SetCommandExpandLists(command_expand_lists);
+ cc->SetDepfile(depfile);
+ cc->SetJobPool(job_pool);
+ cc->SetCMP0116Status(cmp0116);
+ file->SetCustomCommand(std::move(cc));
+
+ lg.AddSourceOutputs(file, outputs, cmLocalGenerator::OutputRole::Primary,
+ lfbt, origin);
+ lg.AddSourceOutputs(file, byproducts,
+ cmLocalGenerator::OutputRole::Byproduct, lfbt, origin);
+ }
+ return file;
+}
+
+bool AnyOutputMatches(const std::string& name,
+ const std::vector<std::string>& outputs)
+{
+ return std::any_of(outputs.begin(), outputs.end(),
+ [&name](std::string const& output) -> bool {
+ std::string::size_type pos = output.rfind(name);
+ // If the output matches exactly
+ return (pos != std::string::npos &&
+ pos == output.size() - name.size() &&
+ (pos == 0 || output[pos - 1] == '/'));
+ });
+}
+
+bool AnyTargetCommandOutputMatches(
+ const std::string& name, const std::vector<cmCustomCommand>& commands)
+{
+ return std::any_of(commands.begin(), commands.end(),
+ [&name](cmCustomCommand const& command) -> bool {
+ return AnyOutputMatches(name, command.GetByproducts());
+ });
+}
+}
+
+namespace detail {
+void AddCustomCommandToTarget(cmLocalGenerator& lg,
+ const cmListFileBacktrace& lfbt,
+ cmCommandOrigin origin, cmTarget* target,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines,
+ cmCustomCommandType type, const char* comment,
+ const char* workingDir, bool escapeOldStyle,
+ bool uses_terminal, const std::string& depfile,
+ const std::string& job_pool,
+ bool command_expand_lists, bool stdPipesUTF8,
+ cmPolicies::PolicyStatus cmp0116)
+{
+ // Add the command to the appropriate build step for the target.
+ std::vector<std::string> no_output;
+ cmCustomCommand cc(no_output, byproducts, depends, commandLines, lfbt,
+ comment, workingDir, stdPipesUTF8);
+ cc.SetEscapeOldStyle(escapeOldStyle);
+ cc.SetEscapeAllowMakeVars(true);
+ cc.SetUsesTerminal(uses_terminal);
+ cc.SetCommandExpandLists(command_expand_lists);
+ cc.SetDepfile(depfile);
+ cc.SetJobPool(job_pool);
+ cc.SetCMP0116Status(cmp0116);
+ switch (type) {
+ case cmCustomCommandType::PRE_BUILD:
+ target->AddPreBuildCommand(std::move(cc));
+ break;
+ case cmCustomCommandType::PRE_LINK:
+ target->AddPreLinkCommand(std::move(cc));
+ break;
+ case cmCustomCommandType::POST_BUILD:
+ target->AddPostBuildCommand(std::move(cc));
+ break;
+ }
+
+ lg.AddTargetByproducts(target, byproducts, lfbt, origin);
+}
+
+cmSourceFile* AddCustomCommandToOutput(
+ cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+ cmCommandOrigin origin, const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends, const std::string& main_dependency,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, bool replace, bool escapeOldStyle,
+ bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+ const std::string& job_pool, bool stdPipesUTF8,
+ cmPolicies::PolicyStatus cmp0116)
+{
+ return AddCustomCommand(lg, lfbt, origin, outputs, byproducts, depends,
+ main_dependency, implicit_depends, commandLines,
+ comment, workingDir, replace, escapeOldStyle,
+ uses_terminal, command_expand_lists, depfile,
+ job_pool, stdPipesUTF8, cmp0116);
+}
+
+void AppendCustomCommandToOutput(cmLocalGenerator& lg,
+ const cmListFileBacktrace& lfbt,
+ const std::string& output,
+ const std::vector<std::string>& depends,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines)
+{
+ // Lookup an existing command.
+ cmSourceFile* sf = nullptr;
+ if (cmGeneratorExpression::Find(output) == std::string::npos) {
+ sf = lg.GetSourceFileWithOutput(output);
+ } else {
+ // This output path has a generator expression. Evaluate it to
+ // find the output for any configurations.
+ for (std::string const& out :
+ lg.ExpandCustomCommandOutputGenex(output, lfbt)) {
+ sf = lg.GetSourceFileWithOutput(out);
+ if (sf) {
+ break;
+ }
+ }
+ }
+
+ if (sf) {
+ if (cmCustomCommand* cc = sf->GetCustomCommand()) {
+ cc->AppendCommands(commandLines);
+ cc->AppendDepends(depends);
+ cc->AppendImplicitDepends(implicit_depends);
+ return;
+ }
+ }
+
+ // No existing command found.
+ lg.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Attempt to APPEND to custom command with output\n ", output,
+ "\nwhich is not already a custom command output."),
+ lfbt);
+}
+
+void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+ cmCommandOrigin origin, cmTarget* target,
+ const char* workingDir,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines,
+ bool escapeOldStyle, const char* comment,
+ bool uses_terminal, bool command_expand_lists,
+ const std::string& job_pool, bool stdPipesUTF8,
+ cmPolicies::PolicyStatus cmp0116)
+{
+ // Use an empty comment to avoid generation of default comment.
+ if (!comment) {
+ comment = "";
+ }
+
+ // Create the generated symbolic output name of the utility target.
+ std::string output =
+ lg.CreateUtilityOutput(target->GetName(), byproducts, lfbt);
+
+ std::string no_main_dependency;
+ cmImplicitDependsList no_implicit_depends;
+ cmSourceFile* rule = AddCustomCommand(
+ lg, lfbt, origin, { output }, byproducts, depends, no_main_dependency,
+ no_implicit_depends, commandLines, comment, workingDir,
+ /*replace=*/false, escapeOldStyle, uses_terminal, command_expand_lists,
+ /*depfile=*/"", job_pool, stdPipesUTF8, cmp0116);
+ if (rule) {
+ lg.AddTargetByproducts(target, byproducts, lfbt, origin);
+ }
+
+ target->AddSource(output);
+}
+
+std::vector<std::string> ComputeISPCObjectSuffixes(cmGeneratorTarget* target)
+{
+ const std::string& targetProperty =
+ target->GetSafeProperty("ISPC_INSTRUCTION_SETS");
+ std::vector<std::string> ispcTargets;
+
+ if (!cmIsOff(targetProperty)) {
+ cmExpandList(targetProperty, ispcTargets);
+ for (auto& ispcTarget : ispcTargets) {
+ // transform targets into the suffixes
+ auto pos = ispcTarget.find('-');
+ auto target_suffix = ispcTarget.substr(0, pos);
+ if (target_suffix ==
+ "avx1") { // when targetting avx1 ISPC uses the 'avx' output string
+ target_suffix = "avx";
+ }
+ ispcTarget = target_suffix;
+ }
+ }
+ return ispcTargets;
+}
+
+std::vector<std::string> ComputeISPCExtraObjects(
+ std::string const& objectName, std::string const& buildDirectory,
+ std::vector<std::string> const& ispcSuffixes)
+{
+ auto normalizedDir = cmSystemTools::CollapseFullPath(buildDirectory);
+ std::vector<std::string> computedObjects;
+ computedObjects.reserve(ispcSuffixes.size());
+
+ auto extension = cmSystemTools::GetFilenameLastExtension(objectName);
+
+ // We can't use cmSystemTools::GetFilenameWithoutLastExtension as it
+ // drops any directories in objectName
+ auto objNameNoExt = objectName;
+ std::string::size_type dot_pos = objectName.rfind('.');
+ if (dot_pos != std::string::npos) {
+ objNameNoExt.resize(dot_pos);
+ }
+
+ for (const auto& ispcTarget : ispcSuffixes) {
+ computedObjects.emplace_back(
+ cmStrCat(normalizedDir, "/", objNameNoExt, "_", ispcTarget, extension));
+ }
+
+ return computedObjects;
+}
+}
+
+cmSourcesWithOutput cmLocalGenerator::GetSourcesWithOutput(
+ const std::string& name) const
+{
+ // Linear search? Also see GetSourceFileWithOutput for detail.
+ if (!cmSystemTools::FileIsFullPath(name)) {
+ cmSourcesWithOutput sources;
+ sources.Target = this->LinearGetTargetWithOutput(name);
+ sources.Source = this->LinearGetSourceFileWithOutput(
+ name, cmSourceOutputKind::OutputOrByproduct, sources.SourceIsByproduct);
+ return sources;
+ }
+ // Otherwise we use an efficient lookup map.
+ auto o = this->OutputToSource.find(name);
+ if (o != this->OutputToSource.end()) {
+ return o->second.Sources;
+ }
+ return {};
+}
+
+cmSourceFile* cmLocalGenerator::GetSourceFileWithOutput(
+ const std::string& name, cmSourceOutputKind kind) const
+{
+ // If the queried path is not absolute we use the backward compatible
+ // linear-time search for an output with a matching suffix.
+ if (!cmSystemTools::FileIsFullPath(name)) {
+ bool byproduct = false;
+ return this->LinearGetSourceFileWithOutput(name, kind, byproduct);
+ }
+ // Otherwise we use an efficient lookup map.
+ auto o = this->OutputToSource.find(name);
+ if (o != this->OutputToSource.end() &&
+ (!o->second.Sources.SourceIsByproduct ||
+ kind == cmSourceOutputKind::OutputOrByproduct)) {
+ // Source file could also be null pointer for example if we found the
+ // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD
+ // command of a target, or a not yet created custom command.
+ return o->second.Sources.Source;
+ }
+ return nullptr;
+}
+
+std::string cmLocalGenerator::CreateUtilityOutput(
+ std::string const& targetName, std::vector<std::string> const&,
+ cmListFileBacktrace const&)
+{
+ std::string force =
+ cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/", targetName);
+ // The output is not actually created so mark it symbolic.
+ if (cmSourceFile* sf = this->Makefile->GetOrCreateGeneratedSource(force)) {
+ sf->SetProperty("SYMBOLIC", "1");
+ } else {
+ cmSystemTools::Error("Could not get source file entry for " + force);
+ }
+ return force;
+}
+
+std::vector<cmCustomCommandGenerator>
+cmLocalGenerator::MakeCustomCommandGenerators(cmCustomCommand const& cc,
+ std::string const& config)
+{
+ std::vector<cmCustomCommandGenerator> ccgs;
+ ccgs.emplace_back(cc, config, this);
+ return ccgs;
+}
+
+std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputPaths(
+ cmCompiledGeneratorExpression const& cge, std::string const& config)
+{
+ std::vector<std::string> paths = cmExpandedList(cge.Evaluate(this, config));
+ for (std::string& p : paths) {
+ p = cmSystemTools::CollapseFullPath(p, this->GetCurrentBinaryDirectory());
+ }
+ return paths;
+}
+
+std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputGenex(
+ std::string const& o, cmListFileBacktrace const& bt)
+{
+ std::vector<std::string> allConfigOutputs;
+ cmGeneratorExpression ge(bt);
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(o);
+ std::vector<std::string> configs =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ for (std::string const& config : configs) {
+ std::vector<std::string> configOutputs =
+ this->ExpandCustomCommandOutputPaths(*cge, config);
+ allConfigOutputs.reserve(allConfigOutputs.size() + configOutputs.size());
+ std::move(configOutputs.begin(), configOutputs.end(),
+ std::back_inserter(allConfigOutputs));
+ }
+ auto endUnique =
+ cmRemoveDuplicates(allConfigOutputs.begin(), allConfigOutputs.end());
+ allConfigOutputs.erase(endUnique, allConfigOutputs.end());
+ return allConfigOutputs;
+}
+
+void cmLocalGenerator::AddTargetByproducts(
+ cmTarget* target, const std::vector<std::string>& byproducts,
+ cmListFileBacktrace const& bt, cmCommandOrigin origin)
+{
+ for (std::string const& o : byproducts) {
+ if (cmGeneratorExpression::Find(o) == std::string::npos) {
+ this->UpdateOutputToSourceMap(o, target, bt, origin);
+ continue;
+ }
+
+ // This byproduct path has a generator expression. Evaluate it to
+ // register the byproducts for all configurations.
+ for (std::string const& b : this->ExpandCustomCommandOutputGenex(o, bt)) {
+ this->UpdateOutputToSourceMap(b, target, bt, cmCommandOrigin::Generator);
+ }
+ }
+}
+
+void cmLocalGenerator::AddSourceOutputs(
+ cmSourceFile* source, const std::vector<std::string>& outputs,
+ OutputRole role, cmListFileBacktrace const& bt, cmCommandOrigin origin)
+{
+ for (std::string const& o : outputs) {
+ if (cmGeneratorExpression::Find(o) == std::string::npos) {
+ this->UpdateOutputToSourceMap(o, source, role, bt, origin);
+ continue;
+ }
+
+ // This output path has a generator expression. Evaluate it to
+ // register the outputs for all configurations.
+ for (std::string const& out :
+ this->ExpandCustomCommandOutputGenex(o, bt)) {
+ this->UpdateOutputToSourceMap(out, source, role, bt,
+ cmCommandOrigin::Generator);
+ }
+ }
+}
+
+void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& byproduct,
+ cmTarget* target,
+ cmListFileBacktrace const& bt,
+ cmCommandOrigin origin)
+{
+ SourceEntry entry;
+ entry.Sources.Target = target;
+
+ auto pr = this->OutputToSource.emplace(byproduct, entry);
+ if (pr.second) {
+ CreateGeneratedSource(*this, byproduct, OutputRole::Byproduct, origin, bt);
+ } else {
+ SourceEntry& current = pr.first->second;
+ // Has the target already been set?
+ if (!current.Sources.Target) {
+ current.Sources.Target = target;
+ } else {
+ // Multiple custom commands/targets produce the same output (source file
+ // or target). See also comment in other UpdateOutputToSourceMap
+ // overload.
+ //
+ // TODO: Warn the user about this case.
+ }
+ }
+}
+
+void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& output,
+ cmSourceFile* source,
+ OutputRole role,
+ cmListFileBacktrace const& bt,
+ cmCommandOrigin origin)
+{
+ SourceEntry entry;
+ entry.Sources.Source = source;
+ entry.Sources.SourceIsByproduct = role == OutputRole::Byproduct;
+
+ auto pr = this->OutputToSource.emplace(output, entry);
+ if (pr.second) {
+ CreateGeneratedSource(*this, output, role, origin, bt);
+ } else {
+ SourceEntry& current = pr.first->second;
+ // Outputs take precedence over byproducts
+ if (!current.Sources.Source ||
+ (current.Sources.SourceIsByproduct && role == OutputRole::Primary)) {
+ current.Sources.Source = source;
+ current.Sources.SourceIsByproduct = false;
+ } else {
+ // Multiple custom commands produce the same output but may
+ // be attached to a different source file (MAIN_DEPENDENCY).
+ // LinearGetSourceFileWithOutput would return the first one,
+ // so keep the mapping for the first one.
+ //
+ // TODO: Warn the user about this case. However, the VS 8 generator
+ // triggers it for separate generate.stamp rules in ZERO_CHECK and
+ // individual targets.
+ }
+ }
+}
+
+cmTarget* cmLocalGenerator::LinearGetTargetWithOutput(
+ const std::string& name) const
+{
+ // We go through the ordered vector of targets to get reproducible results
+ // should multiple names match.
+ for (cmTarget* t : this->Makefile->GetOrderedTargets()) {
+ // Does the output of any command match the source file name?
+ if (AnyTargetCommandOutputMatches(name, t->GetPreBuildCommands())) {
+ return t;
+ }
+ if (AnyTargetCommandOutputMatches(name, t->GetPreLinkCommands())) {
+ return t;
+ }
+ if (AnyTargetCommandOutputMatches(name, t->GetPostBuildCommands())) {
+ return t;
+ }
+ }
+ return nullptr;
+}
+
+cmSourceFile* cmLocalGenerator::LinearGetSourceFileWithOutput(
+ const std::string& name, cmSourceOutputKind kind, bool& byproduct) const
+{
+ // Outputs take precedence over byproducts.
+ byproduct = false;
+ cmSourceFile* fallback = nullptr;
+
+ // Look through all the source files that have custom commands and see if the
+ // custom command has the passed source file as an output.
+ for (const auto& src : this->Makefile->GetSourceFiles()) {
+ // Does this source file have a custom command?
+ if (src->GetCustomCommand()) {
+ // Does the output of the custom command match the source file name?
+ if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) {
+ // Return the first matching output.
+ return src.get();
+ }
+ if (kind == cmSourceOutputKind::OutputOrByproduct) {
+ if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) {
+ // Do not return the source yet as there might be a matching output.
+ fallback = src.get();
+ }
+ }
+ }
+ }
+
+ // Did we find a byproduct?
+ byproduct = fallback != nullptr;
+ return fallback;
+}
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
new file mode 100644
index 0000000..f597120
--- /dev/null
+++ b/Source/cmLocalGenerator.h
@@ -0,0 +1,737 @@
+/* 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 <cstddef>
+#include <iosfwd>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <cm3p/kwiml/int.h>
+
+#include "cmCustomCommandTypes.h"
+#include "cmListFileCache.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmStateSnapshot.h"
+
+class cmCompiledGeneratorExpression;
+class cmComputeLinkInformation;
+class cmCustomCommand;
+class cmCustomCommandGenerator;
+class cmCustomCommandLines;
+class cmGeneratedFileStream;
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmImplicitDependsList;
+class cmLinkLineComputer;
+class cmMakefile;
+class cmRulePlaceholderExpander;
+class cmSourceFile;
+class cmState;
+class cmTarget;
+class cmake;
+
+/** Flag if byproducts shall also be considered. */
+enum class cmSourceOutputKind
+{
+ OutputOnly,
+ OutputOrByproduct
+};
+
+/** What scanner to use for dependencies lookup. */
+enum class cmDependencyScannerKind
+{
+ CMake,
+ Compiler
+};
+
+/** Target and source file which have a specific output. */
+struct cmSourcesWithOutput
+{
+ /** Target with byproduct. */
+ cmTarget* Target = nullptr;
+
+ /** Source file with output or byproduct. */
+ cmSourceFile* Source = nullptr;
+ bool SourceIsByproduct = false;
+};
+
+/** \class cmLocalGenerator
+ * \brief Create required build files for a directory.
+ *
+ * Subclasses of this abstract class generate makefiles, DSP, etc for various
+ * platforms. This class should never be constructed directly. A
+ * GlobalGenerator will create it and invoke the appropriate commands on it.
+ */
+class cmLocalGenerator : public cmOutputConverter
+{
+public:
+ cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile);
+ virtual ~cmLocalGenerator();
+
+ /**
+ * Generate the makefile for this directory.
+ */
+ virtual void Generate() {}
+
+ virtual void ComputeHomeRelativeOutputPath() {}
+
+ /**
+ * Calls TraceVSDependencies() on all targets of this generator.
+ */
+ void TraceDependencies() const;
+
+ virtual void AddHelperCommands() {}
+
+ /**
+ * Generate the install rules files in this directory.
+ */
+ void GenerateInstallRules();
+
+ /**
+ * Generate the test files for tests.
+ */
+ void GenerateTestFiles();
+
+ /**
+ * Generate a manifest of target files that will be built.
+ */
+ void ComputeTargetManifest();
+
+ bool ComputeTargetCompileFeatures();
+
+ bool IsRootMakefile() const;
+
+ //! Get the makefile for this generator
+ cmMakefile* GetMakefile() { return this->Makefile; }
+
+ //! Get the makefile for this generator, const version
+ const cmMakefile* GetMakefile() const { return this->Makefile; }
+
+ //! Get the GlobalGenerator this is associated with
+ cmGlobalGenerator* GetGlobalGenerator() { return this->GlobalGenerator; }
+ const cmGlobalGenerator* GetGlobalGenerator() const
+ {
+ return this->GlobalGenerator;
+ }
+
+ virtual cmRulePlaceholderExpander* CreateRulePlaceholderExpander() const;
+
+ std::string GetLinkLibsCMP0065(std::string const& linkLanguage,
+ cmGeneratorTarget& tgt) const;
+
+ cmState* GetState() const;
+ cmStateSnapshot GetStateSnapshot() const;
+
+ void AddArchitectureFlags(std::string& flags,
+ cmGeneratorTarget const* target,
+ const std::string& lang, const std::string& config,
+ const std::string& filterArch = std::string());
+
+ void AddLanguageFlags(std::string& flags, cmGeneratorTarget const* target,
+ const std::string& lang, const std::string& config);
+ void AddLanguageFlagsForLinking(std::string& flags,
+ cmGeneratorTarget const* target,
+ const std::string& lang,
+ const std::string& config);
+ void AddCMP0018Flags(std::string& flags, cmGeneratorTarget const* target,
+ std::string const& lang, const std::string& config);
+ void AddVisibilityPresetFlags(std::string& flags,
+ cmGeneratorTarget const* target,
+ const std::string& lang);
+ void AddConfigVariableFlags(std::string& flags, const std::string& var,
+ const std::string& config);
+ void AddCompilerRequirementFlag(std::string& flags,
+ cmGeneratorTarget const* target,
+ const std::string& lang,
+ const std::string& config);
+ //! Append flags to a string.
+ virtual void AppendFlags(std::string& flags,
+ const std::string& newFlags) const;
+ virtual void AppendFlags(std::string& flags,
+ const std::vector<BT<std::string>>& newFlags) const;
+ virtual void AppendFlagEscape(std::string& flags,
+ const std::string& rawFlag) const;
+ void AddISPCDependencies(cmGeneratorTarget* target);
+ void AddPchDependencies(cmGeneratorTarget* target);
+ void AddUnityBuild(cmGeneratorTarget* target);
+ void AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target,
+ const std::string& config,
+ const std::string& lang);
+ void AppendPositionIndependentLinkerFlags(std::string& flags,
+ cmGeneratorTarget* target,
+ const std::string& config,
+ const std::string& lang);
+
+ enum class IncludePathStyle
+ {
+ Default,
+ Absolute,
+ };
+
+ //! Get the include flags for the current makefile and language
+ std::string GetIncludeFlags(
+ std::vector<std::string> const& includes, cmGeneratorTarget* target,
+ std::string const& lang, std::string const& config,
+ bool forResponseFile = false,
+ IncludePathStyle pathStyle = IncludePathStyle::Default);
+
+ using GeneratorTargetVector =
+ std::vector<std::unique_ptr<cmGeneratorTarget>>;
+ const GeneratorTargetVector& GetGeneratorTargets() const
+ {
+ return this->GeneratorTargets;
+ }
+
+ void AddGeneratorTarget(std::unique_ptr<cmGeneratorTarget> gt);
+ void AddImportedGeneratorTarget(cmGeneratorTarget* gt);
+ void AddOwnedImportedGeneratorTarget(std::unique_ptr<cmGeneratorTarget> gt);
+
+ cmGeneratorTarget* FindLocalNonAliasGeneratorTarget(
+ const std::string& name) const;
+ cmGeneratorTarget* FindGeneratorTargetToUse(const std::string& name) const;
+
+ /**
+ * Process a list of include directories
+ */
+ void AppendIncludeDirectories(std::vector<std::string>& includes,
+ std::string const& includes_list,
+ const cmSourceFile& sourceFile) const;
+ void AppendIncludeDirectories(std::vector<std::string>& includes,
+ const std::vector<std::string>& includes_vec,
+ const cmSourceFile& sourceFile) const;
+
+ /**
+ * Encode a list of preprocessor definitions for the compiler
+ * command line.
+ */
+ void AppendDefines(std::set<std::string>& defines,
+ std::string const& defines_list) const;
+ void AppendDefines(std::set<BT<std::string>>& defines,
+ std::string const& defines_list) const;
+ void AppendDefines(std::set<BT<std::string>>& defines,
+ const std::vector<BT<std::string>>& defines_vec) const;
+
+ /**
+ * Encode a list of compile options for the compiler
+ * command line.
+ */
+ void AppendCompileOptions(std::string& options,
+ std::string const& options_list,
+ const char* regex = nullptr) const;
+ void AppendCompileOptions(std::string& options,
+ const std::vector<std::string>& options_vec,
+ const char* regex = nullptr) const;
+ void AppendCompileOptions(std::vector<BT<std::string>>& options,
+ const std::vector<BT<std::string>>& options_vec,
+ const char* regex = nullptr) const;
+
+ /**
+ * Join a set of defines into a definesString with a space separator.
+ */
+ void JoinDefines(const std::set<std::string>& defines,
+ std::string& definesString, const std::string& lang);
+
+ /** Lookup and append options associated with a particular feature. */
+ void AppendFeatureOptions(std::string& flags, const std::string& lang,
+ const char* feature);
+
+ cmProp GetFeature(const std::string& feature, const std::string& config);
+
+ /** \brief Get absolute path to dependency \a name
+ *
+ * Translate a dependency as given in CMake code to the name to
+ * appear in a generated build file.
+ * - If \a name is a utility target, returns false.
+ * - If \a name is a CMake target, it will be transformed to the real output
+ * location of that target for the given configuration.
+ * - If \a name is the full path to a file, it will be returned.
+ * - Otherwise \a name is treated as a relative path with respect to
+ * the source directory of this generator. This should only be
+ * used for dependencies of custom commands.
+ */
+ bool GetRealDependency(const std::string& name, const std::string& config,
+ std::string& dep);
+
+ /** Called from command-line hook to clear dependencies. */
+ virtual void ClearDependencies(cmMakefile* /* mf */, bool /* verbose */) {}
+
+ /** Called from command-line hook to update dependencies. */
+ virtual bool UpdateDependencies(const std::string& /* tgtInfo */,
+ bool /*verbose*/, bool /*color*/)
+ {
+ return true;
+ }
+
+ /** @brief Get the include directories for the current makefile and language
+ * and optional the compiler implicit include directories.
+ *
+ * @arg stripImplicitDirs Strip all directories found in
+ * CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES from the result.
+ * @arg appendAllImplicitDirs Append all directories found in
+ * CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES to the result.
+ */
+ std::vector<BT<std::string>> GetIncludeDirectoriesImplicit(
+ cmGeneratorTarget const* target, std::string const& lang = "C",
+ std::string const& config = "", bool stripImplicitDirs = true,
+ bool appendAllImplicitDirs = false) const;
+
+ /** @brief Get the include directories for the current makefile and language
+ * and optional the compiler implicit include directories.
+ *
+ * @arg dirs Directories are appended to this list
+ */
+ void GetIncludeDirectoriesImplicit(std::vector<std::string>& dirs,
+ cmGeneratorTarget const* target,
+ const std::string& lang = "C",
+ const std::string& config = "",
+ bool stripImplicitDirs = true,
+ bool appendAllImplicitDirs = false) const;
+
+ /** @brief Get the include directories for the current makefile and language.
+ * @arg dirs Include directories are appended to this list
+ */
+ void GetIncludeDirectories(std::vector<std::string>& dirs,
+ cmGeneratorTarget const* target,
+ const std::string& lang = "C",
+ const std::string& config = "") const;
+
+ /** @brief Get the include directories for the current makefile and language.
+ * @return The include directory list
+ */
+ std::vector<BT<std::string>> GetIncludeDirectories(
+ cmGeneratorTarget const* target, std::string const& lang = "C",
+ std::string const& config = "") const;
+
+ void AddCompileOptions(std::string& flags, cmGeneratorTarget* target,
+ const std::string& lang, const std::string& config);
+ void AddCompileOptions(std::vector<BT<std::string>>& flags,
+ cmGeneratorTarget* target, const std::string& lang,
+ const std::string& config);
+
+ /**
+ * Add a custom PRE_BUILD, PRE_LINK, or POST_BUILD command to a target.
+ */
+ cmTarget* AddCustomCommandToTarget(
+ const std::string& target, const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, cmCustomCommandType type,
+ const char* comment, const char* workingDir,
+ cmPolicies::PolicyStatus cmp0116, bool escapeOldStyle = true,
+ bool uses_terminal = false, const std::string& depfile = "",
+ const std::string& job_pool = "", bool command_expand_lists = false,
+ cmObjectLibraryCommands objLibCommands = cmObjectLibraryCommands::Reject,
+ bool stdPipesUTF8 = false);
+
+ /**
+ * Add a custom command to a source file.
+ */
+ cmSourceFile* AddCustomCommandToOutput(
+ const std::string& output, const std::vector<std::string>& depends,
+ const std::string& main_dependency,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, cmPolicies::PolicyStatus cmp0116,
+ bool replace = false, bool escapeOldStyle = true,
+ bool uses_terminal = false, bool command_expand_lists = false,
+ const std::string& depfile = "", const std::string& job_pool = "",
+ bool stdPipesUTF8 = false);
+ cmSourceFile* AddCustomCommandToOutput(
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const std::string& main_dependency,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, cmPolicies::PolicyStatus cmp0116,
+ bool replace = false, bool escapeOldStyle = true,
+ bool uses_terminal = false, bool command_expand_lists = false,
+ const std::string& depfile = "", const std::string& job_pool = "",
+ bool stdPipesUTF8 = false);
+
+ /**
+ * Add a utility to the build. A utility target is a command that is run
+ * every time the target is built.
+ */
+ cmTarget* AddUtilityCommand(
+ const std::string& utilityName, bool excludeFromAll,
+ const char* workingDir, const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, cmPolicies::PolicyStatus cmp0116,
+ bool escapeOldStyle = true, const char* comment = nullptr,
+ bool uses_terminal = false, bool command_expand_lists = false,
+ const std::string& job_pool = "", bool stdPipesUTF8 = false);
+
+ virtual std::string CreateUtilityOutput(
+ std::string const& targetName, std::vector<std::string> const& byproducts,
+ cmListFileBacktrace const& bt);
+
+ virtual std::vector<cmCustomCommandGenerator> MakeCustomCommandGenerators(
+ cmCustomCommand const& cc, std::string const& config);
+
+ std::vector<std::string> ExpandCustomCommandOutputPaths(
+ cmCompiledGeneratorExpression const& cge, std::string const& config);
+ std::vector<std::string> ExpandCustomCommandOutputGenex(
+ std::string const& o, cmListFileBacktrace const& bt);
+
+ /**
+ * Add target byproducts.
+ */
+ void AddTargetByproducts(cmTarget* target,
+ const std::vector<std::string>& byproducts,
+ cmListFileBacktrace const& bt,
+ cmCommandOrigin origin);
+
+ enum class OutputRole
+ {
+ Primary,
+ Byproduct,
+ };
+
+ /**
+ * Add source file outputs.
+ */
+ void AddSourceOutputs(cmSourceFile* source,
+ std::vector<std::string> const& outputs,
+ OutputRole role, cmListFileBacktrace const& bt,
+ cmCommandOrigin origin);
+
+ /**
+ * Return the target if the provided source name is a byproduct of a utility
+ * target or a PRE_BUILD, PRE_LINK, or POST_BUILD command.
+ * Return the source file which has the provided source name as output.
+ */
+ cmSourcesWithOutput GetSourcesWithOutput(const std::string& name) const;
+
+ /**
+ * Is there a source file that has the provided source name as an output?
+ * If so then return it.
+ */
+ cmSourceFile* GetSourceFileWithOutput(
+ const std::string& name,
+ cmSourceOutputKind kind = cmSourceOutputKind::OutputOnly) const;
+
+ std::string GetProjectName() const;
+
+ /** Compute the language used to compile the given source file. */
+ std::string GetSourceFileLanguage(const cmSourceFile& source);
+
+ // Fill the vector with the target names for the object files,
+ // preprocessed files and assembly files.
+ void GetIndividualFileTargets(std::vector<std::string>&) {}
+
+ /**
+ * Get the relative path from the generator output directory to a
+ * per-target support directory.
+ */
+ virtual std::string GetTargetDirectory(
+ cmGeneratorTarget const* target) const;
+
+ /**
+ * Get the level of backwards compatibility requested by the project
+ * in this directory. This is the value of the CMake variable
+ * CMAKE_BACKWARDS_COMPATIBILITY whose format is
+ * "major.minor[.patch]". The returned integer is encoded as
+ *
+ * CMake_VERSION_ENCODE(major, minor, patch)
+ *
+ * and is monotonically increasing with the CMake version.
+ */
+ KWIML_INT_uint64_t GetBackwardsCompatibility();
+
+ /**
+ * Test whether compatibility is set to a given version or lower.
+ */
+ bool NeedBackwardsCompatibility_2_4();
+
+ cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id) const;
+
+ cmake* GetCMakeInstance() const;
+
+ std::string const& GetSourceDirectory() const;
+ std::string const& GetBinaryDirectory() const;
+
+ std::string const& GetCurrentBinaryDirectory() const;
+ std::string const& GetCurrentSourceDirectory() const;
+
+ /**
+ * Convert the given remote path to a relative path with respect to
+ * the given local path. Both paths must use forward slashes and not
+ * already be escaped or quoted.
+ * The conversion is skipped if the paths are not both in the source
+ * or both in the binary tree.
+ */
+ std::string MaybeConvertToRelativePath(std::string const& local_path,
+ std::string const& remote_path) const;
+
+ /**
+ * Generate a macOS application bundle Info.plist file.
+ */
+ void GenerateAppleInfoPList(cmGeneratorTarget* target,
+ const std::string& targetName,
+ const std::string& fname);
+
+ /**
+ * Generate a macOS framework Info.plist file.
+ */
+ void GenerateFrameworkInfoPList(cmGeneratorTarget* target,
+ const std::string& targetName,
+ const std::string& fname);
+ /** Construct a comment for a custom command. */
+ std::string ConstructComment(cmCustomCommandGenerator const& ccg,
+ const char* default_comment = "") const;
+ // Compute object file names.
+ std::string GetObjectFileNameWithoutTarget(
+ const cmSourceFile& source, std::string const& dir_max,
+ bool* hasSourceExtension = nullptr,
+ char const* customOutputExtension = nullptr);
+
+ /** Fill out the static linker flags for the given target. */
+ void GetStaticLibraryFlags(std::string& flags, std::string const& config,
+ std::string const& linkLanguage,
+ cmGeneratorTarget* target);
+ std::vector<BT<std::string>> GetStaticLibraryFlags(
+ std::string const& config, std::string const& linkLanguage,
+ cmGeneratorTarget* target);
+
+ /** Fill out these strings for the given target. Libraries to link,
+ * flags, and linkflags. */
+ void GetDeviceLinkFlags(cmLinkLineComputer* linkLineComputer,
+ const std::string& config, std::string& linkLibs,
+ std::string& linkFlags, std::string& frameworkPath,
+ std::string& linkPath, cmGeneratorTarget* target);
+
+ void GetTargetFlags(cmLinkLineComputer* linkLineComputer,
+ const std::string& config, std::string& linkLibs,
+ std::string& flags, std::string& linkFlags,
+ std::string& frameworkPath, std::string& linkPath,
+ cmGeneratorTarget* target);
+ void GetTargetFlags(
+ cmLinkLineComputer* linkLineComputer, const std::string& config,
+ std::vector<BT<std::string>>& linkLibs, std::string& flags,
+ std::vector<BT<std::string>>& linkFlags, std::string& frameworkPath,
+ std::vector<BT<std::string>>& linkPath, cmGeneratorTarget* target);
+ void GetTargetDefines(cmGeneratorTarget const* target,
+ std::string const& config, std::string const& lang,
+ std::set<std::string>& defines) const;
+ std::set<BT<std::string>> GetTargetDefines(cmGeneratorTarget const* target,
+ std::string const& config,
+ std::string const& lang) const;
+ void GetTargetCompileFlags(cmGeneratorTarget* target,
+ std::string const& config,
+ std::string const& lang, std::string& flags,
+ std::string const& arch);
+ std::vector<BT<std::string>> GetTargetCompileFlags(
+ cmGeneratorTarget* target, std::string const& config,
+ std::string const& lang, std::string const& arch = std::string());
+
+ std::string GetFrameworkFlags(std::string const& l,
+ std::string const& config,
+ cmGeneratorTarget* target);
+ virtual std::string GetTargetFortranFlags(cmGeneratorTarget const* target,
+ std::string const& config);
+
+ virtual void ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* gt = nullptr);
+
+ bool IsWindowsShell() const;
+ bool IsWatcomWMake() const;
+ bool IsMinGWMake() const;
+ bool IsNMake() const;
+ bool IsNinjaMulti() const;
+
+ void IssueMessage(MessageType t, std::string const& text) const;
+
+ void CreateEvaluationFileOutputs();
+ void CreateEvaluationFileOutputs(const std::string& config);
+ void ProcessEvaluationFiles(std::vector<std::string>& generatedFiles);
+
+ cmProp GetRuleLauncher(cmGeneratorTarget* target, const std::string& prop);
+
+protected:
+ // The default implementation ignores the IncludePathStyle and always
+ // uses absolute paths. A generator may override this to use relative
+ // paths in some cases.
+ virtual std::string ConvertToIncludeReference(
+ std::string const& path, IncludePathStyle pathStyle,
+ cmOutputConverter::OutputFormat format);
+
+ //! put all the libraries for a target on into the given stream
+ void OutputLinkLibraries(cmComputeLinkInformation* pcli,
+ cmLinkLineComputer* linkLineComputer,
+ std::string& linkLibraries,
+ std::string& frameworkPath, std::string& linkPath);
+ void OutputLinkLibraries(cmComputeLinkInformation* pcli,
+ cmLinkLineComputer* linkLineComputer,
+ std::vector<BT<std::string>>& linkLibraries,
+ std::string& frameworkPath,
+ std::vector<BT<std::string>>& linkPath);
+
+ // Handle old-style install rules stored in the targets.
+ void GenerateTargetInstallRules(
+ std::ostream& os, const std::string& config,
+ std::vector<std::string> const& configurationTypes);
+
+ virtual void AddGeneratorSpecificInstallSetup(std::ostream&) {}
+
+ std::string& CreateSafeUniqueObjectFileName(const std::string& sin,
+ std::string const& dir_max);
+
+ /** Check whether the native build system supports the given
+ definition. Issues a warning. */
+ virtual bool CheckDefinition(std::string const& define) const;
+
+ cmMakefile* Makefile;
+ cmStateSnapshot StateSnapshot;
+ cmListFileBacktrace DirectoryBacktrace;
+ cmGlobalGenerator* GlobalGenerator;
+ std::map<std::string, std::string> UniqueObjectNamesMap;
+ std::string::size_type ObjectPathMax;
+ std::set<std::string> ObjectMaxPathViolations;
+
+ std::set<std::string> EnvCPATH;
+
+ using GeneratorTargetMap =
+ std::unordered_map<std::string, cmGeneratorTarget*>;
+ GeneratorTargetMap GeneratorTargetSearchIndex;
+ GeneratorTargetVector GeneratorTargets;
+
+ std::set<cmGeneratorTarget const*> WarnCMP0063;
+ GeneratorTargetMap ImportedGeneratorTargets;
+ GeneratorTargetVector OwnedImportedGeneratorTargets;
+ std::map<std::string, std::string> AliasTargets;
+
+ std::map<std::string, std::string> Compilers;
+ std::map<std::string, std::string> VariableMappings;
+ std::string CompilerSysroot;
+ std::string LinkerSysroot;
+ std::unordered_map<std::string, std::string> AppleArchSysroots;
+
+ bool EmitUniversalBinaryFlags;
+
+ KWIML_INT_uint64_t BackwardsCompatibility;
+ bool BackwardsCompatibilityFinal;
+
+private:
+ /**
+ * See LinearGetSourceFileWithOutput for background information
+ */
+ cmTarget* LinearGetTargetWithOutput(const std::string& name) const;
+
+ /**
+ * Generalized old version of GetSourceFileWithOutput kept for
+ * backward-compatibility. It implements a linear search and supports
+ * relative file paths. It is used as a fall back by GetSourceFileWithOutput
+ * and GetSourcesWithOutput.
+ */
+ cmSourceFile* LinearGetSourceFileWithOutput(const std::string& name,
+ cmSourceOutputKind kind,
+ bool& byproduct) const;
+ struct SourceEntry
+ {
+ cmSourcesWithOutput Sources;
+ };
+
+ // A map for fast output to input look up.
+ using OutputToSourceMap = std::unordered_map<std::string, SourceEntry>;
+ OutputToSourceMap OutputToSource;
+
+ void UpdateOutputToSourceMap(std::string const& byproduct, cmTarget* target,
+ cmListFileBacktrace const& bt,
+ cmCommandOrigin origin);
+ void UpdateOutputToSourceMap(std::string const& output, cmSourceFile* source,
+ OutputRole role, cmListFileBacktrace const& bt,
+ cmCommandOrigin origin);
+
+ void AddSharedFlags(std::string& flags, const std::string& lang,
+ bool shared);
+ bool GetShouldUseOldFlags(bool shared, const std::string& lang) const;
+ void AddPositionIndependentFlags(std::string& flags, std::string const& l,
+ int targetType);
+
+ void ComputeObjectMaxPath();
+ bool AllAppleArchSysrootsAreTheSame(const std::vector<std::string>& archs,
+ const char* sysroot);
+
+ void CopyPchCompilePdb(const std::string& config, cmGeneratorTarget* target,
+ const std::string& ReuseFrom,
+ cmGeneratorTarget* reuseTarget,
+ std::vector<std::string> const& extensions);
+ void IncludeFileInUnitySources(cmGeneratedFileStream& unity_file,
+ std::string const& sf_full_path,
+ cmProp beforeInclude, cmProp afterInclude,
+ cmProp uniqueIdName) const;
+ std::vector<std::string> AddUnityFilesModeAuto(
+ cmGeneratorTarget* target, std::string const& lang,
+ std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude,
+ cmProp afterInclude, std::string const& filename_base, size_t batchSize);
+ std::vector<std::string> AddUnityFilesModeGroup(
+ cmGeneratorTarget* target, std::string const& lang,
+ std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude,
+ cmProp afterInclude, std::string const& filename_base);
+};
+
+#if !defined(CMAKE_BOOTSTRAP)
+bool cmLocalGeneratorCheckObjectName(std::string& objName,
+ std::string::size_type dir_len,
+ std::string::size_type max_total_len);
+#endif
+
+namespace detail {
+void AddCustomCommandToTarget(cmLocalGenerator& lg,
+ const cmListFileBacktrace& lfbt,
+ cmCommandOrigin origin, cmTarget* target,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines,
+ cmCustomCommandType type, const char* comment,
+ const char* workingDir, bool escapeOldStyle,
+ bool uses_terminal, const std::string& depfile,
+ const std::string& job_pool,
+ bool command_expand_lists, bool stdPipesUTF8,
+ cmPolicies::PolicyStatus cmp0116);
+
+cmSourceFile* AddCustomCommandToOutput(
+ cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+ cmCommandOrigin origin, const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends, const std::string& main_dependency,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, bool replace, bool escapeOldStyle,
+ bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+ const std::string& job_pool, bool stdPipesUTF8,
+ cmPolicies::PolicyStatus cmp0116);
+
+void AppendCustomCommandToOutput(cmLocalGenerator& lg,
+ const cmListFileBacktrace& lfbt,
+ const std::string& output,
+ const std::vector<std::string>& depends,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines);
+
+void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+ cmCommandOrigin origin, cmTarget* target,
+ const char* workingDir,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines,
+ bool escapeOldStyle, const char* comment,
+ bool uses_terminal, bool command_expand_lists,
+ const std::string& job_pool, bool stdPipesUTF8,
+ cmPolicies::PolicyStatus cmp0116);
+
+std::vector<std::string> ComputeISPCObjectSuffixes(cmGeneratorTarget* target);
+std::vector<std::string> ComputeISPCExtraObjects(
+ std::string const& objectName, std::string const& buildDirectory,
+ std::vector<std::string> const& ispcSuffixes);
+}
diff --git a/Source/cmLocalGhsMultiGenerator.cxx b/Source/cmLocalGhsMultiGenerator.cxx
new file mode 100644
index 0000000..b223813
--- /dev/null
+++ b/Source/cmLocalGhsMultiGenerator.cxx
@@ -0,0 +1,80 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmLocalGhsMultiGenerator.h"
+
+#include <utility>
+#include <vector>
+
+#include "cmGeneratorTarget.h"
+#include "cmGhsMultiTargetGenerator.h"
+#include "cmGlobalGenerator.h"
+#include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmLocalGhsMultiGenerator::cmLocalGhsMultiGenerator(cmGlobalGenerator* gg,
+ cmMakefile* mf)
+ : cmLocalGenerator(gg, mf)
+{
+}
+
+cmLocalGhsMultiGenerator::~cmLocalGhsMultiGenerator() = default;
+
+std::string cmLocalGhsMultiGenerator::GetTargetDirectory(
+ cmGeneratorTarget const* target) const
+{
+ std::string dir = cmStrCat(target->GetName(), ".dir");
+ return dir;
+}
+
+void cmLocalGhsMultiGenerator::Generate()
+{
+ for (cmGeneratorTarget* gt :
+ this->GlobalGenerator->GetLocalGeneratorTargetsInOrder(this)) {
+ if (!gt->IsInBuildSystem()) {
+ continue;
+ }
+
+ cmGhsMultiTargetGenerator tg(gt);
+ tg.Generate();
+ }
+}
+
+void cmLocalGhsMultiGenerator::ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* gt)
+{
+ std::string dir_max = cmStrCat(this->GetCurrentBinaryDirectory(), '/',
+ this->GetTargetDirectory(gt), '/');
+
+ // Count the number of object files with each name. Note that
+ // filesystem may not be case sensitive.
+ std::map<std::string, int> counts;
+
+ for (auto const& si : mapping) {
+ cmSourceFile const* sf = si.first;
+ std::string objectNameLower = cmStrCat(
+ cmSystemTools::LowerCase(
+ cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath())),
+ this->GlobalGenerator->GetLanguageOutputExtension(*sf));
+ counts[objectNameLower] += 1;
+ }
+
+ // For all source files producing duplicate names we need unique
+ // object name computation.
+ for (auto& si : mapping) {
+ cmSourceFile const* sf = si.first;
+ std::string objectName = cmStrCat(
+ cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()),
+ this->GlobalGenerator->GetLanguageOutputExtension(*sf));
+
+ if (counts[cmSystemTools::LowerCase(objectName)] > 1) {
+ const_cast<cmGeneratorTarget*>(gt)->AddExplicitObjectName(sf);
+ bool keptSourceExtension;
+ objectName = this->GetObjectFileNameWithoutTarget(*sf, dir_max,
+ &keptSourceExtension);
+ cmsys::SystemTools::ReplaceString(objectName, "/", "_");
+ }
+ si.second = objectName;
+ }
+}
diff --git a/Source/cmLocalGhsMultiGenerator.h b/Source/cmLocalGhsMultiGenerator.h
new file mode 100644
index 0000000..be32a94
--- /dev/null
+++ b/Source/cmLocalGhsMultiGenerator.h
@@ -0,0 +1,39 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <map>
+#include <string>
+
+#include "cmLocalGenerator.h"
+
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmMakefile;
+class cmSourceFile;
+
+/** \class cmLocalGhsMultiGenerator
+ * \brief Write Green Hills MULTI project files.
+ *
+ * cmLocalGhsMultiGenerator produces a set of .gpj
+ * file for each target in its mirrored directory.
+ */
+class cmLocalGhsMultiGenerator : public cmLocalGenerator
+{
+public:
+ cmLocalGhsMultiGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
+
+ ~cmLocalGhsMultiGenerator() override;
+
+ /**
+ * Generate the makefile for this directory.
+ */
+ void Generate() override;
+
+ std::string GetTargetDirectory(
+ cmGeneratorTarget const* target) const override;
+
+ void ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* gt = nullptr) override;
+};
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
new file mode 100644
index 0000000..c2a6410
--- /dev/null
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -0,0 +1,913 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmLocalNinjaGenerator.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <iterator>
+#include <memory>
+#include <sstream>
+#include <utility>
+
+#include <cmext/string_view>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmCryptoHash.h"
+#include "cmCustomCommand.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmNinjaTargetGenerator.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmRulePlaceholderExpander.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmake.h"
+
+cmLocalNinjaGenerator::cmLocalNinjaGenerator(cmGlobalGenerator* gg,
+ cmMakefile* mf)
+ : cmLocalCommonGenerator(gg, mf, mf->GetState()->GetBinaryDirectory())
+{
+}
+
+// Virtual public methods.
+
+cmRulePlaceholderExpander*
+cmLocalNinjaGenerator::CreateRulePlaceholderExpander() const
+{
+ cmRulePlaceholderExpander* ret =
+ this->cmLocalGenerator::CreateRulePlaceholderExpander();
+ ret->SetTargetImpLib("$TARGET_IMPLIB");
+ return ret;
+}
+
+cmLocalNinjaGenerator::~cmLocalNinjaGenerator() = default;
+
+void cmLocalNinjaGenerator::Generate()
+{
+ // Compute the path to use when referencing the current output
+ // directory from the top output directory.
+ this->HomeRelativeOutputPath = this->MaybeConvertToRelativePath(
+ this->GetBinaryDirectory(), this->GetCurrentBinaryDirectory());
+ if (this->HomeRelativeOutputPath == ".") {
+ this->HomeRelativeOutputPath.clear();
+ }
+
+ if (this->GetGlobalGenerator()->IsMultiConfig()) {
+ for (auto const& config : this->GetConfigNames()) {
+ this->WriteProcessedMakefile(this->GetImplFileStream(config));
+ }
+ }
+ this->WriteProcessedMakefile(this->GetCommonFileStream());
+#ifdef NINJA_GEN_VERBOSE_FILES
+ this->WriteProcessedMakefile(this->GetRulesFileStream());
+#endif
+
+ // We do that only once for the top CMakeLists.txt file.
+ if (this->IsRootMakefile()) {
+ this->WriteBuildFileTop();
+
+ this->WritePools(this->GetRulesFileStream());
+
+ const std::string& showIncludesPrefix =
+ this->GetMakefile()->GetSafeDefinition("CMAKE_CL_SHOWINCLUDES_PREFIX");
+ if (!showIncludesPrefix.empty()) {
+ cmGlobalNinjaGenerator::WriteComment(this->GetRulesFileStream(),
+ "localized /showIncludes string");
+ this->GetRulesFileStream() << "msvc_deps_prefix = ";
+#ifdef WIN32
+ // Ninja uses the ANSI Windows APIs, so strings in the rules file
+ // typically need to be ANSI encoded. However, in this case the compiler
+ // is being invoked using the UTF-8 codepage so the /showIncludes prefix
+ // will be UTF-8 encoded on stdout. Ninja can't successfully compare this
+ // UTF-8 encoded prefix to the ANSI encoded msvc_deps_prefix if it
+ // contains any non-ASCII characters and dependency checking will fail.
+ // As a workaround, leave the msvc_deps_prefix UTF-8 encoded even though
+ // the rest of the file is ANSI encoded.
+ if (GetConsoleOutputCP() == CP_UTF8 && GetACP() != CP_UTF8 &&
+ this->GetGlobalGenerator()->GetMakefileEncoding() != codecvt::None) {
+ this->GetRulesFileStream().WriteRaw(showIncludesPrefix);
+ } else {
+ // Ninja 1.11 and above uses the UTF-8 code page if it's supported, so
+ // in that case we can write it normally without using raw bytes.
+ this->GetRulesFileStream() << showIncludesPrefix;
+ }
+#else
+ // It's safe to use the standard encoding on other platforms.
+ this->GetRulesFileStream() << showIncludesPrefix;
+#endif
+ this->GetRulesFileStream() << "\n\n";
+ }
+ }
+
+ for (const auto& target : this->GetGeneratorTargets()) {
+ if (!target->IsInBuildSystem()) {
+ continue;
+ }
+ auto tg = cmNinjaTargetGenerator::New(target.get());
+ if (tg) {
+ if (target->Target->IsPerConfig()) {
+ for (auto const& config : this->GetConfigNames()) {
+ tg->Generate(config);
+ if (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
+ this->GetGlobalGenerator()->IsMultiConfig()) {
+ cmNinjaBuild phonyAlias("phony");
+ this->GetGlobalNinjaGenerator()->AppendTargetOutputs(
+ target.get(), phonyAlias.Outputs, "", DependOnTargetArtifact);
+ this->GetGlobalNinjaGenerator()->AppendTargetOutputs(
+ target.get(), phonyAlias.ExplicitDeps, config,
+ DependOnTargetArtifact);
+ this->GetGlobalNinjaGenerator()->WriteBuild(
+ *this->GetGlobalNinjaGenerator()->GetConfigFileStream(config),
+ phonyAlias);
+ }
+ }
+ if (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
+ this->GetGlobalGenerator()->IsMultiConfig()) {
+ if (!this->GetGlobalNinjaGenerator()->GetDefaultConfigs().empty()) {
+ cmNinjaBuild phonyAlias("phony");
+ this->GetGlobalNinjaGenerator()->AppendTargetOutputs(
+ target.get(), phonyAlias.Outputs, "", DependOnTargetArtifact);
+ for (auto const& config :
+ this->GetGlobalNinjaGenerator()->GetDefaultConfigs()) {
+ this->GetGlobalNinjaGenerator()->AppendTargetOutputs(
+ target.get(), phonyAlias.ExplicitDeps, config,
+ DependOnTargetArtifact);
+ }
+ this->GetGlobalNinjaGenerator()->WriteBuild(
+ *this->GetGlobalNinjaGenerator()->GetDefaultFileStream(),
+ phonyAlias);
+ }
+ cmNinjaBuild phonyAlias("phony");
+ this->GetGlobalNinjaGenerator()->AppendTargetOutputs(
+ target.get(), phonyAlias.Outputs, "all", DependOnTargetArtifact);
+ for (auto const& config : this->GetConfigNames()) {
+ this->GetGlobalNinjaGenerator()->AppendTargetOutputs(
+ target.get(), phonyAlias.ExplicitDeps, config,
+ DependOnTargetArtifact);
+ }
+ this->GetGlobalNinjaGenerator()->WriteBuild(
+ *this->GetGlobalNinjaGenerator()->GetDefaultFileStream(),
+ phonyAlias);
+ }
+ } else {
+ tg->Generate("");
+ }
+ }
+ }
+
+ for (auto const& config : this->GetConfigNames()) {
+ this->WriteCustomCommandBuildStatements(config);
+ this->AdditionalCleanFiles(config);
+ }
+}
+
+// TODO: Picked up from cmLocalUnixMakefileGenerator3. Refactor it.
+std::string cmLocalNinjaGenerator::GetTargetDirectory(
+ cmGeneratorTarget const* target) const
+{
+ std::string dir = cmStrCat("CMakeFiles/", target->GetName());
+#if defined(__VMS)
+ dir += "_dir";
+#else
+ dir += ".dir";
+#endif
+ return dir;
+}
+
+// Non-virtual public methods.
+
+const cmGlobalNinjaGenerator* cmLocalNinjaGenerator::GetGlobalNinjaGenerator()
+ const
+{
+ return static_cast<const cmGlobalNinjaGenerator*>(
+ this->GetGlobalGenerator());
+}
+
+cmGlobalNinjaGenerator* cmLocalNinjaGenerator::GetGlobalNinjaGenerator()
+{
+ return static_cast<cmGlobalNinjaGenerator*>(this->GetGlobalGenerator());
+}
+
+// Virtual protected methods.
+
+std::string cmLocalNinjaGenerator::ConvertToIncludeReference(
+ std::string const& path, IncludePathStyle pathStyle,
+ cmOutputConverter::OutputFormat format)
+{
+ if (pathStyle == IncludePathStyle::Absolute) {
+ return this->ConvertToOutputFormat(
+ cmSystemTools::CollapseFullPath(path, this->GetCurrentBinaryDirectory()),
+ format);
+ }
+ return this->ConvertToOutputFormat(
+ this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), path),
+ format);
+}
+
+// Private methods.
+
+cmGeneratedFileStream& cmLocalNinjaGenerator::GetImplFileStream(
+ const std::string& config) const
+{
+ return *this->GetGlobalNinjaGenerator()->GetImplFileStream(config);
+}
+
+cmGeneratedFileStream& cmLocalNinjaGenerator::GetCommonFileStream() const
+{
+ return *this->GetGlobalNinjaGenerator()->GetCommonFileStream();
+}
+
+cmGeneratedFileStream& cmLocalNinjaGenerator::GetRulesFileStream() const
+{
+ return *this->GetGlobalNinjaGenerator()->GetRulesFileStream();
+}
+
+const cmake* cmLocalNinjaGenerator::GetCMakeInstance() const
+{
+ return this->GetGlobalGenerator()->GetCMakeInstance();
+}
+
+cmake* cmLocalNinjaGenerator::GetCMakeInstance()
+{
+ return this->GetGlobalGenerator()->GetCMakeInstance();
+}
+
+void cmLocalNinjaGenerator::WriteBuildFileTop()
+{
+ this->WriteProjectHeader(this->GetCommonFileStream());
+
+ if (this->GetGlobalGenerator()->IsMultiConfig()) {
+ for (auto const& config : this->GetConfigNames()) {
+ auto& stream = this->GetImplFileStream(config);
+ this->WriteProjectHeader(stream);
+ this->WriteNinjaRequiredVersion(stream);
+ this->WriteNinjaConfigurationVariable(stream, config);
+ this->WriteNinjaFilesInclusionConfig(stream);
+ }
+ } else {
+ this->WriteNinjaRequiredVersion(this->GetCommonFileStream());
+ this->WriteNinjaConfigurationVariable(this->GetCommonFileStream(),
+ this->GetConfigNames().front());
+ }
+ this->WriteNinjaFilesInclusionCommon(this->GetCommonFileStream());
+
+ // For the rule file.
+ this->WriteProjectHeader(this->GetRulesFileStream());
+}
+
+void cmLocalNinjaGenerator::WriteProjectHeader(std::ostream& os)
+{
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << "# Project: " << this->GetProjectName() << '\n'
+ << "# Configurations: " << cmJoin(this->GetConfigNames(), ", ") << '\n';
+ cmGlobalNinjaGenerator::WriteDivider(os);
+}
+
+void cmLocalNinjaGenerator::WriteNinjaRequiredVersion(std::ostream& os)
+{
+ // Default required version
+ std::string requiredVersion = cmGlobalNinjaGenerator::RequiredNinjaVersion();
+
+ // Ninja generator uses the 'console' pool if available (>= 1.5)
+ if (this->GetGlobalNinjaGenerator()->SupportsConsolePool()) {
+ requiredVersion =
+ cmGlobalNinjaGenerator::RequiredNinjaVersionForConsolePool();
+ }
+
+ // The Ninja generator writes rules which require support for restat
+ // when rebuilding build.ninja manifest (>= 1.8)
+ if (this->GetGlobalNinjaGenerator()->SupportsManifestRestat() &&
+ this->GetCMakeInstance()->DoWriteGlobVerifyTarget() &&
+ !this->GetGlobalNinjaGenerator()->GlobalSettingIsOn(
+ "CMAKE_SUPPRESS_REGENERATION")) {
+ requiredVersion =
+ cmGlobalNinjaGenerator::RequiredNinjaVersionForManifestRestat();
+ }
+
+ cmGlobalNinjaGenerator::WriteComment(
+ os, "Minimal version of Ninja required by this file");
+ os << "ninja_required_version = " << requiredVersion << "\n\n";
+}
+
+void cmLocalNinjaGenerator::WriteNinjaConfigurationVariable(
+ std::ostream& os, const std::string& config)
+{
+ cmGlobalNinjaGenerator::WriteVariable(
+ os, "CONFIGURATION", config,
+ "Set configuration variable for custom commands.");
+}
+
+void cmLocalNinjaGenerator::WritePools(std::ostream& os)
+{
+ cmGlobalNinjaGenerator::WriteDivider(os);
+
+ cmProp jobpools =
+ this->GetCMakeInstance()->GetState()->GetGlobalProperty("JOB_POOLS");
+ if (!jobpools) {
+ jobpools = this->GetMakefile()->GetDefinition("CMAKE_JOB_POOLS");
+ }
+ if (jobpools) {
+ cmGlobalNinjaGenerator::WriteComment(
+ os, "Pools defined by global property JOB_POOLS");
+ std::vector<std::string> pools = cmExpandedList(*jobpools);
+ for (std::string const& pool : pools) {
+ const std::string::size_type eq = pool.find('=');
+ unsigned int jobs;
+ if (eq != std::string::npos &&
+ sscanf(pool.c_str() + eq, "=%u", &jobs) == 1) {
+ os << "pool " << pool.substr(0, eq) << "\n depth = " << jobs
+ << "\n\n";
+ } else {
+ cmSystemTools::Error("Invalid pool defined by property 'JOB_POOLS': " +
+ pool);
+ }
+ }
+ }
+}
+
+void cmLocalNinjaGenerator::WriteNinjaFilesInclusionConfig(std::ostream& os)
+{
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << "# Include auxiliary files.\n\n";
+ cmGlobalNinjaGenerator* ng = this->GetGlobalNinjaGenerator();
+ std::string const ninjaCommonFile =
+ ng->NinjaOutputPath(cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE);
+ std::string const commonFilePath = ng->EncodePath(ninjaCommonFile);
+ cmGlobalNinjaGenerator::WriteInclude(os, commonFilePath,
+ "Include common file.");
+ os << "\n";
+}
+
+void cmLocalNinjaGenerator::WriteNinjaFilesInclusionCommon(std::ostream& os)
+{
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << "# Include auxiliary files.\n\n";
+ cmGlobalNinjaGenerator* ng = this->GetGlobalNinjaGenerator();
+ std::string const ninjaRulesFile =
+ ng->NinjaOutputPath(cmGlobalNinjaGenerator::NINJA_RULES_FILE);
+ std::string const rulesFilePath = ng->EncodePath(ninjaRulesFile);
+ cmGlobalNinjaGenerator::WriteInclude(os, rulesFilePath,
+ "Include rules file.");
+ os << "\n";
+}
+
+void cmLocalNinjaGenerator::WriteProcessedMakefile(std::ostream& os)
+{
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << "# Write statements declared in CMakeLists.txt:\n"
+ << "# " << this->Makefile->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE")
+ << '\n';
+ if (this->IsRootMakefile()) {
+ os << "# Which is the root file.\n";
+ }
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ os << '\n';
+}
+
+void cmLocalNinjaGenerator::AppendTargetOutputs(cmGeneratorTarget* target,
+ cmNinjaDeps& outputs,
+ const std::string& config)
+{
+ this->GetGlobalNinjaGenerator()->AppendTargetOutputs(target, outputs, config,
+ DependOnTargetArtifact);
+}
+
+void cmLocalNinjaGenerator::AppendTargetDepends(cmGeneratorTarget* target,
+ cmNinjaDeps& outputs,
+ const std::string& config,
+ const std::string& fileConfig,
+ cmNinjaTargetDepends depends)
+{
+ this->GetGlobalNinjaGenerator()->AppendTargetDepends(target, outputs, config,
+ fileConfig, depends);
+}
+
+void cmLocalNinjaGenerator::AppendCustomCommandDeps(
+ cmCustomCommandGenerator const& ccg, cmNinjaDeps& ninjaDeps,
+ const std::string& config)
+{
+ for (std::string const& i : ccg.GetDepends()) {
+ std::string dep;
+ if (this->GetRealDependency(i, config, dep)) {
+ ninjaDeps.push_back(
+ this->GetGlobalNinjaGenerator()->ConvertToNinjaPath(dep));
+ }
+ }
+}
+
+std::string cmLocalNinjaGenerator::WriteCommandScript(
+ std::vector<std::string> const& cmdLines, std::string const& customStep,
+ cmGeneratorTarget const* target) const
+{
+ std::string scriptPath;
+ if (target) {
+ scriptPath = target->GetSupportDirectory();
+ } else {
+ scriptPath = cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles");
+ }
+ cmSystemTools::MakeDirectory(scriptPath);
+ scriptPath += '/';
+ scriptPath += customStep;
+#ifdef _WIN32
+ scriptPath += ".bat";
+#else
+ scriptPath += ".sh";
+#endif
+
+ cmsys::ofstream script(scriptPath.c_str());
+
+#ifdef _WIN32
+ script << "@echo off\n";
+ int line = 1;
+#else
+ script << "set -e\n\n";
+#endif
+
+ for (auto const& i : cmdLines) {
+ std::string cmd = i;
+ // The command line was built assuming it would be written to
+ // the build.ninja file, so it uses '$$' for '$'. Remove this
+ // for the raw shell script.
+ cmSystemTools::ReplaceString(cmd, "$$", "$");
+#ifdef _WIN32
+ script << cmd << " || (set FAIL_LINE=" << ++line << "& goto :ABORT)"
+ << '\n';
+#else
+ script << cmd << '\n';
+#endif
+ }
+
+#ifdef _WIN32
+ script << "goto :EOF\n\n"
+ ":ABORT\n"
+ "set ERROR_CODE=%ERRORLEVEL%\n"
+ "echo Batch file failed at line %FAIL_LINE% "
+ "with errorcode %ERRORLEVEL%\n"
+ "exit /b %ERROR_CODE%";
+#endif
+
+ return scriptPath;
+}
+
+std::string cmLocalNinjaGenerator::BuildCommandLine(
+ std::vector<std::string> const& cmdLines, std::string const& customStep,
+ cmGeneratorTarget const* target) const
+{
+ // If we have no commands but we need to build a command anyway, use noop.
+ // This happens when building a POST_BUILD value for link targets that
+ // don't use POST_BUILD.
+ if (cmdLines.empty()) {
+ return cmGlobalNinjaGenerator::SHELL_NOOP;
+ }
+
+ // If this is a custom step then we will have no '$VAR' ninja placeholders.
+ // This means we can deal with long command sequences by writing to a script.
+ // Do this if the command lines are on the scale of the OS limit.
+ if (!customStep.empty()) {
+ size_t cmdLinesTotal = 0;
+ for (std::string const& cmd : cmdLines) {
+ cmdLinesTotal += cmd.length() + 6;
+ }
+ if (cmdLinesTotal > cmSystemTools::CalculateCommandLineLengthLimit() / 2) {
+ std::string const scriptPath =
+ this->WriteCommandScript(cmdLines, customStep, target);
+ std::string cmd
+#ifndef _WIN32
+ = "/bin/sh "
+#endif
+ ;
+ cmd += this->ConvertToOutputFormat(
+ this->GetGlobalNinjaGenerator()->ConvertToNinjaPath(scriptPath),
+ cmOutputConverter::SHELL);
+
+ // Add an unused argument based on script content so that Ninja
+ // knows when the command lines change.
+ cmd += " ";
+ cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
+ cmd += hash.HashFile(scriptPath).substr(0, 16);
+ return cmd;
+ }
+ }
+
+ std::ostringstream cmd;
+ for (auto li = cmdLines.begin(); li != cmdLines.end(); ++li)
+#ifdef _WIN32
+ {
+ if (li != cmdLines.begin()) {
+ cmd << " && ";
+ } else if (cmdLines.size() > 1) {
+ cmd << "cmd.exe /C \"";
+ }
+ // Put current cmdLine in brackets if it contains "||" because it has
+ // higher precedence than "&&" in cmd.exe
+ if (li->find("||") != std::string::npos) {
+ cmd << "( " << *li << " )";
+ } else {
+ cmd << *li;
+ }
+ }
+ if (cmdLines.size() > 1) {
+ cmd << "\"";
+ }
+#else
+ {
+ if (li != cmdLines.begin()) {
+ cmd << " && ";
+ }
+ cmd << *li;
+ }
+#endif
+ return cmd.str();
+}
+
+void cmLocalNinjaGenerator::AppendCustomCommandLines(
+ cmCustomCommandGenerator const& ccg, std::vector<std::string>& cmdLines)
+{
+ auto* gg = this->GetGlobalNinjaGenerator();
+
+ if (ccg.GetNumberOfCommands() > 0) {
+ std::string wd = ccg.GetWorkingDirectory();
+ if (wd.empty()) {
+ wd = this->GetCurrentBinaryDirectory();
+ }
+
+ std::ostringstream cdCmd;
+#ifdef _WIN32
+ std::string cdStr = "cd /D ";
+#else
+ std::string cdStr = "cd ";
+#endif
+ cdCmd << cdStr
+ << this->ConvertToOutputFormat(wd, cmOutputConverter::SHELL);
+ cmdLines.push_back(cdCmd.str());
+ }
+
+ std::string launcher = this->MakeCustomLauncher(ccg);
+
+ for (unsigned i = 0; i != ccg.GetNumberOfCommands(); ++i) {
+ std::string c = ccg.GetCommand(i);
+ if (c.empty()) {
+ continue;
+ }
+ cmdLines.push_back(launcher +
+ this->ConvertToOutputFormat(
+ c,
+ gg->IsMultiConfig() ? cmOutputConverter::NINJAMULTI
+ : cmOutputConverter::SHELL));
+
+ std::string& cmd = cmdLines.back();
+ ccg.AppendArguments(i, cmd);
+ }
+}
+
+void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
+ cmCustomCommand const* cc, const std::set<cmGeneratorTarget*>& targets,
+ const std::string& fileConfig)
+{
+ cmGlobalNinjaGenerator* gg = this->GetGlobalNinjaGenerator();
+ if (gg->SeenCustomCommand(cc, fileConfig)) {
+ return;
+ }
+
+ auto ccgs = this->MakeCustomCommandGenerators(*cc, fileConfig);
+ for (cmCustomCommandGenerator const& ccg : ccgs) {
+ if (ccg.GetOutputs().empty() && ccg.GetByproducts().empty()) {
+ // Generator expressions evaluate to no output for this config.
+ continue;
+ }
+
+ cmNinjaDeps orderOnlyDeps;
+
+ // A custom command may appear on multiple targets. However, some build
+ // systems exist where the target dependencies on some of the targets are
+ // overspecified, leading to a dependency cycle. If we assume all target
+ // dependencies are a superset of the true target dependencies for this
+ // custom command, we can take the set intersection of all target
+ // dependencies to obtain a correct dependency list.
+ //
+ // FIXME: This won't work in certain obscure scenarios involving indirect
+ // dependencies.
+ auto j = targets.begin();
+ assert(j != targets.end());
+ this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(
+ *j, orderOnlyDeps, ccg.GetOutputConfig(), fileConfig, ccgs.size() > 1);
+ std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end());
+ ++j;
+
+ for (; j != targets.end(); ++j) {
+ std::vector<std::string> jDeps;
+ std::vector<std::string> depsIntersection;
+ this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(
+ *j, jDeps, ccg.GetOutputConfig(), fileConfig, ccgs.size() > 1);
+ std::sort(jDeps.begin(), jDeps.end());
+ std::set_intersection(orderOnlyDeps.begin(), orderOnlyDeps.end(),
+ jDeps.begin(), jDeps.end(),
+ std::back_inserter(depsIntersection));
+ orderOnlyDeps = depsIntersection;
+ }
+
+ const std::vector<std::string>& outputs = ccg.GetOutputs();
+ const std::vector<std::string>& byproducts = ccg.GetByproducts();
+
+ bool symbolic = false;
+ for (std::string const& output : outputs) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(output)) {
+ if (sf->GetPropertyAsBool("SYMBOLIC")) {
+ symbolic = true;
+ break;
+ }
+ }
+ }
+
+ cmNinjaDeps ninjaOutputs(outputs.size() + byproducts.size());
+ std::transform(outputs.begin(), outputs.end(), ninjaOutputs.begin(),
+ gg->MapToNinjaPath());
+ std::transform(byproducts.begin(), byproducts.end(),
+ ninjaOutputs.begin() + outputs.size(),
+ gg->MapToNinjaPath());
+
+ for (std::string const& ninjaOutput : ninjaOutputs) {
+ gg->SeenCustomCommandOutput(ninjaOutput);
+ }
+
+ cmNinjaDeps ninjaDeps;
+ this->AppendCustomCommandDeps(ccg, ninjaDeps, fileConfig);
+
+ std::vector<std::string> cmdLines;
+ this->AppendCustomCommandLines(ccg, cmdLines);
+
+ if (cmdLines.empty()) {
+ cmNinjaBuild build("phony");
+ build.Comment = "Phony custom command for " + ninjaOutputs[0];
+ build.Outputs = std::move(ninjaOutputs);
+ build.ExplicitDeps = std::move(ninjaDeps);
+ build.OrderOnlyDeps = orderOnlyDeps;
+ gg->WriteBuild(this->GetImplFileStream(fileConfig), build);
+ } else {
+ std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]);
+ if (this->GlobalGenerator->IsMultiConfig()) {
+ customStep += '-';
+ customStep += fileConfig;
+ customStep += '-';
+ customStep += ccg.GetOutputConfig();
+ }
+ // Hash full path to make unique.
+ customStep += '-';
+ cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
+ customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7);
+
+ std::string depfile = ccg.GetDepfile();
+ if (!depfile.empty()) {
+ switch (cc->GetCMP0116Status()) {
+ case cmPolicies::WARN:
+ if (this->GetCurrentBinaryDirectory() !=
+ this->GetBinaryDirectory() ||
+ this->Makefile->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0116")) {
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0116),
+ cc->GetBacktrace());
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ cmSystemTools::MakeDirectory(
+ cmStrCat(this->GetBinaryDirectory(), "/CMakeFiles/d"));
+ depfile = ccg.GetInternalDepfile();
+ break;
+ }
+ }
+
+ gg->WriteCustomCommandBuild(
+ this->BuildCommandLine(cmdLines, customStep),
+ this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0],
+ depfile, cc->GetJobPool(), cc->GetUsesTerminal(),
+ /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, fileConfig,
+ ninjaDeps, orderOnlyDeps);
+ }
+ }
+}
+
+bool cmLocalNinjaGenerator::HasUniqueByproducts(
+ std::vector<std::string> const& byproducts, cmListFileBacktrace const& bt)
+{
+ std::vector<std::string> configs =
+ this->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ cmGeneratorExpression ge(bt);
+ for (std::string const& p : byproducts) {
+ if (cmGeneratorExpression::Find(p) == std::string::npos) {
+ return false;
+ }
+ std::set<std::string> seen;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(p);
+ for (std::string const& config : configs) {
+ for (std::string const& b :
+ this->ExpandCustomCommandOutputPaths(*cge, config)) {
+ if (!seen.insert(b).second) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+namespace {
+bool HasUniqueOutputs(std::vector<cmCustomCommandGenerator> const& ccgs)
+{
+ std::set<std::string> allOutputs;
+ std::set<std::string> allByproducts;
+ for (cmCustomCommandGenerator const& ccg : ccgs) {
+ for (std::string const& output : ccg.GetOutputs()) {
+ if (!allOutputs.insert(output).second) {
+ return false;
+ }
+ }
+ for (std::string const& byproduct : ccg.GetByproducts()) {
+ if (!allByproducts.insert(byproduct).second) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+}
+
+std::string cmLocalNinjaGenerator::CreateUtilityOutput(
+ std::string const& targetName, std::vector<std::string> const& byproducts,
+ cmListFileBacktrace const& bt)
+{
+ // In Ninja Multi-Config, we can only produce cross-config utility
+ // commands if all byproducts are per-config.
+ if (!this->GetGlobalGenerator()->IsMultiConfig() ||
+ !this->HasUniqueByproducts(byproducts, bt)) {
+ return this->cmLocalGenerator::CreateUtilityOutput(targetName, byproducts,
+ bt);
+ }
+
+ std::string const base = cmStrCat(this->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/", targetName, '-');
+ // The output is not actually created so mark it symbolic.
+ for (std::string const& config :
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)) {
+ std::string const force = cmStrCat(base, config);
+ if (cmSourceFile* sf = this->Makefile->GetOrCreateGeneratedSource(force)) {
+ sf->SetProperty("SYMBOLIC", "1");
+ } else {
+ cmSystemTools::Error("Could not get source file entry for " + force);
+ }
+ }
+ this->GetGlobalNinjaGenerator()->AddPerConfigUtilityTarget(targetName);
+ return cmStrCat(base, "$<CONFIG>"_s);
+}
+
+std::vector<cmCustomCommandGenerator>
+cmLocalNinjaGenerator::MakeCustomCommandGenerators(
+ cmCustomCommand const& cc, std::string const& fileConfig)
+{
+ cmGlobalNinjaGenerator const* gg = this->GetGlobalNinjaGenerator();
+
+ bool transformDepfile = false;
+ switch (cc.GetCMP0116Status()) {
+ case cmPolicies::OLD:
+ case cmPolicies::WARN:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ transformDepfile = true;
+ break;
+ }
+
+ // Start with the build graph's configuration.
+ std::vector<cmCustomCommandGenerator> ccgs;
+ ccgs.emplace_back(cc, fileConfig, this, transformDepfile);
+
+ // Consider adding cross configurations.
+ if (!gg->EnableCrossConfigBuild()) {
+ return ccgs;
+ }
+
+ // Outputs and byproducts must be expressed using generator expressions.
+ for (std::string const& output : cc.GetOutputs()) {
+ if (cmGeneratorExpression::Find(output) == std::string::npos) {
+ return ccgs;
+ }
+ }
+ for (std::string const& byproduct : cc.GetByproducts()) {
+ if (cmGeneratorExpression::Find(byproduct) == std::string::npos) {
+ return ccgs;
+ }
+ }
+
+ // Tentatively add the other cross configurations.
+ for (std::string const& config : gg->GetCrossConfigs(fileConfig)) {
+ if (fileConfig != config) {
+ ccgs.emplace_back(cc, fileConfig, this, transformDepfile, config);
+ }
+ }
+
+ // If outputs and byproducts are not unique to each configuration,
+ // drop the cross configurations.
+ if (!HasUniqueOutputs(ccgs)) {
+ ccgs.erase(ccgs.begin() + 1, ccgs.end());
+ }
+
+ return ccgs;
+}
+
+void cmLocalNinjaGenerator::AddCustomCommandTarget(cmCustomCommand const* cc,
+ cmGeneratorTarget* target)
+{
+ CustomCommandTargetMap::value_type v(cc, std::set<cmGeneratorTarget*>());
+ std::pair<CustomCommandTargetMap::iterator, bool> ins =
+ this->CustomCommandTargets.insert(v);
+ if (ins.second) {
+ this->CustomCommands.push_back(cc);
+ }
+ ins.first->second.insert(target);
+}
+
+void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements(
+ const std::string& fileConfig)
+{
+ for (cmCustomCommand const* customCommand : this->CustomCommands) {
+ auto i = this->CustomCommandTargets.find(customCommand);
+ assert(i != this->CustomCommandTargets.end());
+
+ this->WriteCustomCommandBuildStatement(i->first, i->second, fileConfig);
+ }
+}
+
+std::string cmLocalNinjaGenerator::MakeCustomLauncher(
+ cmCustomCommandGenerator const& ccg)
+{
+ cmProp property_value = this->Makefile->GetProperty("RULE_LAUNCH_CUSTOM");
+
+ if (!cmNonempty(property_value)) {
+ return std::string();
+ }
+
+ // Expand rule variables referenced in the given launcher command.
+ cmRulePlaceholderExpander::RuleVariables vars;
+
+ std::string output;
+ const std::vector<std::string>& outputs = ccg.GetOutputs();
+ if (!outputs.empty()) {
+ output = outputs[0];
+ if (ccg.GetWorkingDirectory().empty()) {
+ output = this->MaybeConvertToRelativePath(
+ this->GetCurrentBinaryDirectory(), output);
+ }
+ output = this->ConvertToOutputFormat(output, cmOutputConverter::SHELL);
+ }
+ vars.Output = output.c_str();
+
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->CreateRulePlaceholderExpander());
+
+ std::string launcher = *property_value;
+ rulePlaceholderExpander->ExpandRuleVariables(this, launcher, vars);
+ if (!launcher.empty()) {
+ launcher += " ";
+ }
+
+ return launcher;
+}
+
+void cmLocalNinjaGenerator::AdditionalCleanFiles(const std::string& config)
+{
+ if (cmProp prop_value =
+ this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) {
+ std::vector<std::string> cleanFiles;
+ {
+ cmExpandList(cmGeneratorExpression::Evaluate(*prop_value, this, config),
+ cleanFiles);
+ }
+ std::string const& binaryDir = this->GetCurrentBinaryDirectory();
+ cmGlobalNinjaGenerator* gg = this->GetGlobalNinjaGenerator();
+ for (std::string const& cleanFile : cleanFiles) {
+ // Support relative paths
+ gg->AddAdditionalCleanFile(
+ cmSystemTools::CollapseFullPath(cleanFile, binaryDir), config);
+ }
+ }
+}
diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h
new file mode 100644
index 0000000..8b6824f
--- /dev/null
+++ b/Source/cmLocalNinjaGenerator.h
@@ -0,0 +1,133 @@
+/* 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 <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmListFileCache.h"
+#include "cmLocalCommonGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmNinjaTypes.h"
+#include "cmOutputConverter.h"
+
+class cmCustomCommand;
+class cmCustomCommandGenerator;
+class cmGeneratedFileStream;
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmGlobalNinjaGenerator;
+class cmMakefile;
+class cmRulePlaceholderExpander;
+class cmake;
+
+/**
+ * \class cmLocalNinjaGenerator
+ * \brief Write a local build.ninja file.
+ *
+ * cmLocalNinjaGenerator produces a local build.ninja file from its
+ * member Makefile.
+ */
+class cmLocalNinjaGenerator : public cmLocalCommonGenerator
+{
+public:
+ cmLocalNinjaGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
+
+ ~cmLocalNinjaGenerator() override;
+
+ void Generate() override;
+
+ cmRulePlaceholderExpander* CreateRulePlaceholderExpander() const override;
+
+ std::string GetTargetDirectory(
+ cmGeneratorTarget const* target) const override;
+
+ const cmGlobalNinjaGenerator* GetGlobalNinjaGenerator() const;
+ cmGlobalNinjaGenerator* GetGlobalNinjaGenerator();
+
+ const cmake* GetCMakeInstance() const;
+ cmake* GetCMakeInstance();
+
+ /// @returns the relative path between the HomeOutputDirectory and this
+ /// local generators StartOutputDirectory.
+ std::string GetHomeRelativeOutputPath() const
+ {
+ return this->HomeRelativeOutputPath;
+ }
+
+ std::string BuildCommandLine(
+ std::vector<std::string> const& cmdLines,
+ std::string const& customStep = std::string(),
+ cmGeneratorTarget const* target = nullptr) const;
+
+ void AppendTargetOutputs(cmGeneratorTarget* target, cmNinjaDeps& outputs,
+ const std::string& config);
+ void AppendTargetDepends(cmGeneratorTarget* target, cmNinjaDeps& outputs,
+ const std::string& config,
+ const std::string& fileConfig,
+ cmNinjaTargetDepends depends);
+
+ std::string CreateUtilityOutput(std::string const& targetName,
+ std::vector<std::string> const& byproducts,
+ cmListFileBacktrace const& bt) override;
+
+ std::vector<cmCustomCommandGenerator> MakeCustomCommandGenerators(
+ cmCustomCommand const& cc, std::string const& config) override;
+
+ void AddCustomCommandTarget(cmCustomCommand const* cc,
+ cmGeneratorTarget* target);
+ void AppendCustomCommandLines(cmCustomCommandGenerator const& ccg,
+ std::vector<std::string>& cmdLines);
+ void AppendCustomCommandDeps(cmCustomCommandGenerator const& ccg,
+ cmNinjaDeps& ninjaDeps,
+ const std::string& config);
+
+ bool HasUniqueByproducts(std::vector<std::string> const& byproducts,
+ cmListFileBacktrace const& bt);
+
+protected:
+ std::string ConvertToIncludeReference(
+ std::string const& path, IncludePathStyle pathStyle,
+ cmOutputConverter::OutputFormat format) override;
+
+private:
+ cmGeneratedFileStream& GetImplFileStream(const std::string& config) const;
+ cmGeneratedFileStream& GetCommonFileStream() const;
+ cmGeneratedFileStream& GetRulesFileStream() const;
+
+ void WriteBuildFileTop();
+ void WriteProjectHeader(std::ostream& os);
+ void WriteNinjaRequiredVersion(std::ostream& os);
+ void WriteNinjaConfigurationVariable(std::ostream& os,
+ const std::string& config);
+ void WriteNinjaFilesInclusionConfig(std::ostream& os);
+ void WriteNinjaFilesInclusionCommon(std::ostream& os);
+ void WriteProcessedMakefile(std::ostream& os);
+ void WritePools(std::ostream& os);
+
+ void WriteCustomCommandBuildStatement(
+ cmCustomCommand const* cc, const std::set<cmGeneratorTarget*>& targets,
+ const std::string& config);
+
+ void WriteCustomCommandBuildStatements(const std::string& config);
+
+ std::string MakeCustomLauncher(cmCustomCommandGenerator const& ccg);
+
+ std::string WriteCommandScript(std::vector<std::string> const& cmdLines,
+ std::string const& customStep,
+ cmGeneratorTarget const* target) const;
+
+ void AdditionalCleanFiles(const std::string& config);
+
+ std::string HomeRelativeOutputPath;
+
+ using CustomCommandTargetMap =
+ std::map<cmCustomCommand const*, std::set<cmGeneratorTarget*>>;
+ CustomCommandTargetMap CustomCommandTargets;
+ std::vector<cmCustomCommand const*> CustomCommands;
+};
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
new file mode 100644
index 0000000..464df68
--- /dev/null
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -0,0 +1,2239 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmLocalUnixMakefileGenerator3.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <functional>
+#include <sstream>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cm/vector>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Terminal.h"
+
+#include "cmCMakePath.h"
+#include "cmCustomCommand.h" // IWYU pragma: keep
+#include "cmCustomCommandGenerator.h"
+#include "cmDependsCompiler.h"
+#include "cmFileTimeCache.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMakefileTargetGenerator.h"
+#include "cmOutputConverter.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmRulePlaceholderExpander.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTargetDepend.h"
+#include "cmVersion.h"
+#include "cmake.h"
+
+// Include dependency scanners for supported languages. Only the
+// C/C++ scanner is needed for bootstrapping CMake.
+#include "cmDependsC.h"
+#ifndef CMAKE_BOOTSTRAP
+# include "cmDependsFortran.h"
+# include "cmDependsJava.h"
+#endif
+
+namespace {
+// Helper function used below.
+std::string cmSplitExtension(std::string const& in, std::string& base)
+{
+ std::string ext;
+ std::string::size_type dot_pos = in.rfind('.');
+ if (dot_pos != std::string::npos) {
+ // Remove the extension first in case &base == &in.
+ ext = in.substr(dot_pos);
+ base = in.substr(0, dot_pos);
+ } else {
+ base = in;
+ }
+ return ext;
+}
+
+// Helper predicate for removing absolute paths that don't point to the
+// source or binary directory. It is used when CMAKE_DEPENDS_IN_PROJECT_ONLY
+// is set ON, to only consider in-project dependencies during the build.
+class NotInProjectDir
+{
+public:
+ // Constructor with the source and binary directory's path
+ NotInProjectDir(cm::string_view sourceDir, cm::string_view binaryDir)
+ : SourceDir(sourceDir)
+ , BinaryDir(binaryDir)
+ {
+ }
+
+ // Operator evaluating the predicate
+ bool operator()(const std::string& p) const
+ {
+ auto path = cmCMakePath(p).Normal();
+
+ // Keep all relative paths:
+ if (path.IsRelative()) {
+ return false;
+ }
+
+ // If it's an absolute path, check if it starts with the source
+ // directory:
+ return !(cmCMakePath(this->SourceDir).IsPrefix(path) ||
+ cmCMakePath(this->BinaryDir).IsPrefix(path));
+ }
+
+private:
+ // The path to the source directory
+ cm::string_view SourceDir;
+ // The path to the binary directory
+ cm::string_view BinaryDir;
+};
+}
+
+cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3(
+ cmGlobalGenerator* gg, cmMakefile* mf)
+ : cmLocalCommonGenerator(gg, mf, mf->GetCurrentBinaryDirectory())
+{
+ this->MakefileVariableSize = 0;
+ this->ColorMakefile = false;
+ this->SkipPreprocessedSourceRules = false;
+ this->SkipAssemblySourceRules = false;
+ this->MakeCommandEscapeTargetTwice = false;
+ this->BorlandMakeCurlyHack = false;
+}
+
+cmLocalUnixMakefileGenerator3::~cmLocalUnixMakefileGenerator3() = default;
+
+std::string cmLocalUnixMakefileGenerator3::GetConfigName() const
+{
+ auto const& configNames = this->GetConfigNames();
+ assert(configNames.size() == 1);
+ return configNames.front();
+}
+
+void cmLocalUnixMakefileGenerator3::Generate()
+{
+ // Record whether some options are enabled to avoid checking many
+ // times later.
+ if (!this->GetGlobalGenerator()->GetCMakeInstance()->GetIsInTryCompile()) {
+ this->ColorMakefile = this->Makefile->IsOn("CMAKE_COLOR_MAKEFILE");
+ }
+ this->SkipPreprocessedSourceRules =
+ this->Makefile->IsOn("CMAKE_SKIP_PREPROCESSED_SOURCE_RULES");
+ this->SkipAssemblySourceRules =
+ this->Makefile->IsOn("CMAKE_SKIP_ASSEMBLY_SOURCE_RULES");
+
+ // Generate the rule files for each target.
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ for (cmGeneratorTarget* gt :
+ this->GlobalGenerator->GetLocalGeneratorTargetsInOrder(this)) {
+ if (!gt->IsInBuildSystem()) {
+ continue;
+ }
+
+ auto& gtVisited = this->GetCommandsVisited(gt);
+ const auto& deps = this->GlobalGenerator->GetTargetDirectDepends(gt);
+ for (const auto& d : deps) {
+ // Take the union of visited source files of custom commands
+ auto depVisited = this->GetCommandsVisited(d);
+ gtVisited.insert(depVisited.begin(), depVisited.end());
+ }
+
+ std::unique_ptr<cmMakefileTargetGenerator> tg(
+ cmMakefileTargetGenerator::New(gt));
+ if (tg) {
+ tg->WriteRuleFiles();
+ gg->RecordTargetProgress(tg.get());
+ }
+ }
+
+ // write the local Makefile
+ this->WriteLocalMakefile();
+
+ // Write the cmake file with information for this directory.
+ this->WriteDirectoryInformationFile();
+}
+
+void cmLocalUnixMakefileGenerator3::ComputeHomeRelativeOutputPath()
+{
+ // Compute the path to use when referencing the current output
+ // directory from the top output directory.
+ this->HomeRelativeOutputPath = this->MaybeConvertToRelativePath(
+ this->GetBinaryDirectory(), this->GetCurrentBinaryDirectory());
+ if (this->HomeRelativeOutputPath == ".") {
+ this->HomeRelativeOutputPath.clear();
+ }
+ if (!this->HomeRelativeOutputPath.empty()) {
+ this->HomeRelativeOutputPath += "/";
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::GetLocalObjectFiles(
+ std::map<std::string, LocalObjectInfo>& localObjectFiles)
+{
+ for (const auto& gt : this->GetGeneratorTargets()) {
+ if (!gt->CanCompileSources()) {
+ continue;
+ }
+ std::vector<cmSourceFile const*> objectSources;
+ gt->GetObjectSources(objectSources, this->GetConfigName());
+ // Compute full path to object file directory for this target.
+ std::string dir = cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(),
+ '/', this->GetTargetDirectory(gt.get()), '/');
+ // Compute the name of each object file.
+ for (cmSourceFile const* sf : objectSources) {
+ bool hasSourceExtension = true;
+ std::string objectName =
+ this->GetObjectFileNameWithoutTarget(*sf, dir, &hasSourceExtension);
+ if (cmSystemTools::FileIsFullPath(objectName)) {
+ objectName = cmSystemTools::GetFilenameName(objectName);
+ }
+ LocalObjectInfo& info = localObjectFiles[objectName];
+ info.HasSourceExtension = hasSourceExtension;
+ info.emplace_back(gt.get(), sf->GetLanguage());
+ }
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::GetIndividualFileTargets(
+ std::vector<std::string>& targets)
+{
+ std::map<std::string, LocalObjectInfo> localObjectFiles;
+ this->GetLocalObjectFiles(localObjectFiles);
+ for (auto const& localObjectFile : localObjectFiles) {
+ targets.push_back(localObjectFile.first);
+
+ std::string::size_type dot_pos = localObjectFile.first.rfind(".");
+ std::string base = localObjectFile.first.substr(0, dot_pos);
+ if (localObjectFile.second.HasPreprocessRule) {
+ targets.push_back(base + ".i");
+ }
+
+ if (localObjectFile.second.HasAssembleRule) {
+ targets.push_back(base + ".s");
+ }
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::WriteLocalMakefile()
+{
+ // generate the includes
+ std::string ruleFileName = "Makefile";
+
+ // Open the rule file. This should be copy-if-different because the
+ // rules may depend on this file itself.
+ std::string ruleFileNameFull = this->ConvertToFullPath(ruleFileName);
+ cmGeneratedFileStream ruleFileStream(
+ ruleFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding());
+ if (!ruleFileStream) {
+ return;
+ }
+ // always write the top makefile
+ if (!this->IsRootMakefile()) {
+ ruleFileStream.SetCopyIfDifferent(true);
+ }
+
+ // write the all rules
+ this->WriteLocalAllRules(ruleFileStream);
+
+ // only write local targets unless at the top Keep track of targets already
+ // listed.
+ std::set<std::string> emittedTargets;
+ if (!this->IsRootMakefile()) {
+ // write our targets, and while doing it collect up the object
+ // file rules
+ this->WriteLocalMakefileTargets(ruleFileStream, emittedTargets);
+ } else {
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ gg->WriteConvenienceRules(ruleFileStream, emittedTargets);
+ }
+
+ bool do_preprocess_rules = this->GetCreatePreprocessedSourceRules();
+ bool do_assembly_rules = this->GetCreateAssemblySourceRules();
+
+ std::map<std::string, LocalObjectInfo> localObjectFiles;
+ this->GetLocalObjectFiles(localObjectFiles);
+
+ // now write out the object rules
+ // for each object file name
+ for (auto& localObjectFile : localObjectFiles) {
+ // Add a convenience rule for building the object file.
+ this->WriteObjectConvenienceRule(
+ ruleFileStream, "target to build an object file", localObjectFile.first,
+ localObjectFile.second);
+
+ // Check whether preprocessing and assembly rules make sense.
+ // They make sense only for C and C++ sources.
+ bool lang_has_preprocessor = false;
+ bool lang_has_assembly = false;
+
+ for (LocalObjectEntry const& entry : localObjectFile.second) {
+ if (entry.Language == "C" || entry.Language == "CXX" ||
+ entry.Language == "CUDA" || entry.Language == "Fortran" ||
+ entry.Language == "ISPC") {
+ // Right now, C, C++, Fortran and CUDA have both a preprocessor and the
+ // ability to generate assembly code
+ lang_has_preprocessor = true;
+ lang_has_assembly = true;
+ break;
+ }
+ }
+
+ // Add convenience rules for preprocessed and assembly files.
+ if (lang_has_preprocessor && do_preprocess_rules) {
+ std::string::size_type dot_pos = localObjectFile.first.rfind(".");
+ std::string base = localObjectFile.first.substr(0, dot_pos);
+ this->WriteObjectConvenienceRule(ruleFileStream,
+ "target to preprocess a source file",
+ (base + ".i"), localObjectFile.second);
+ localObjectFile.second.HasPreprocessRule = true;
+ }
+
+ if (lang_has_assembly && do_assembly_rules) {
+ std::string::size_type dot_pos = localObjectFile.first.rfind(".");
+ std::string base = localObjectFile.first.substr(0, dot_pos);
+ this->WriteObjectConvenienceRule(
+ ruleFileStream, "target to generate assembly for a file",
+ (base + ".s"), localObjectFile.second);
+ localObjectFile.second.HasAssembleRule = true;
+ }
+ }
+
+ // add a help target as long as there isn;t a real target named help
+ if (emittedTargets.insert("help").second) {
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ gg->WriteHelpRule(ruleFileStream, this);
+ }
+
+ this->WriteSpecialTargetsBottom(ruleFileStream);
+}
+
+void cmLocalUnixMakefileGenerator3::WriteObjectConvenienceRule(
+ std::ostream& ruleFileStream, const char* comment, const std::string& output,
+ LocalObjectInfo const& info)
+{
+ // If the rule includes the source file extension then create a
+ // version that has the extension removed. The help should include
+ // only the version without source extension.
+ bool inHelp = true;
+ if (info.HasSourceExtension) {
+ // Remove the last extension. This should be kept.
+ std::string outBase1 = output;
+ std::string outExt1 = cmSplitExtension(outBase1, outBase1);
+
+ // Now remove the source extension and put back the last
+ // extension.
+ std::string outNoExt;
+ cmSplitExtension(outBase1, outNoExt);
+ outNoExt += outExt1;
+
+ // Add a rule to drive the rule below.
+ std::vector<std::string> depends;
+ depends.emplace_back(output);
+ std::vector<std::string> no_commands;
+ this->WriteMakeRule(ruleFileStream, nullptr, outNoExt, depends,
+ no_commands, true, true);
+ inHelp = false;
+ }
+
+ // Recursively make the rule for each target using the object file.
+ std::vector<std::string> commands;
+ for (LocalObjectEntry const& t : info) {
+ std::string tgtMakefileName = this->GetRelativeTargetDirectory(t.Target);
+ std::string targetName = tgtMakefileName;
+ tgtMakefileName += "/build.make";
+ targetName += "/";
+ targetName += output;
+ commands.push_back(
+ this->GetRecursiveMakeCall(tgtMakefileName, targetName));
+ }
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ this->GetCurrentBinaryDirectory());
+
+ // Write the rule to the makefile.
+ std::vector<std::string> no_depends;
+ this->WriteMakeRule(ruleFileStream, comment, output, no_depends, commands,
+ true, inHelp);
+}
+
+void cmLocalUnixMakefileGenerator3::WriteLocalMakefileTargets(
+ std::ostream& ruleFileStream, std::set<std::string>& emitted)
+{
+ std::vector<std::string> depends;
+ std::vector<std::string> commands;
+
+ // for each target we just provide a rule to cd up to the top and do a make
+ // on the target
+ std::string localName;
+ for (const auto& target : this->GetGeneratorTargets()) {
+ if ((target->GetType() == cmStateEnums::EXECUTABLE) ||
+ (target->GetType() == cmStateEnums::STATIC_LIBRARY) ||
+ (target->GetType() == cmStateEnums::SHARED_LIBRARY) ||
+ (target->GetType() == cmStateEnums::MODULE_LIBRARY) ||
+ (target->GetType() == cmStateEnums::OBJECT_LIBRARY) ||
+ (target->GetType() == cmStateEnums::UTILITY)) {
+ emitted.insert(target->GetName());
+
+ // for subdirs add a rule to build this specific target by name.
+ localName =
+ cmStrCat(this->GetRelativeTargetDirectory(target.get()), "/rule");
+ commands.clear();
+ depends.clear();
+
+ // Build the target for this pass.
+ std::string makefile2 = "CMakeFiles/Makefile2";
+ commands.push_back(this->GetRecursiveMakeCall(makefile2, localName));
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ this->GetCurrentBinaryDirectory());
+ this->WriteMakeRule(ruleFileStream, "Convenience name for target.",
+ localName, depends, commands, true);
+
+ // Add a target with the canonical name (no prefix, suffix or path).
+ if (localName != target->GetName()) {
+ commands.clear();
+ depends.push_back(localName);
+ this->WriteMakeRule(ruleFileStream, "Convenience name for target.",
+ target->GetName(), depends, commands, true);
+ }
+
+ // Add a fast rule to build the target
+ std::string makefileName = cmStrCat(
+ this->GetRelativeTargetDirectory(target.get()), "/build.make");
+ // make sure the makefile name is suitable for a makefile
+ std::string makeTargetName =
+ cmStrCat(this->GetRelativeTargetDirectory(target.get()), "/build");
+ localName = cmStrCat(target->GetName(), "/fast");
+ depends.clear();
+ commands.clear();
+ commands.push_back(
+ this->GetRecursiveMakeCall(makefileName, makeTargetName));
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ this->GetCurrentBinaryDirectory());
+ this->WriteMakeRule(ruleFileStream, "fast build rule for target.",
+ localName, depends, commands, true);
+
+ // Add a local name for the rule to relink the target before
+ // installation.
+ if (target->NeedRelinkBeforeInstall(this->GetConfigName())) {
+ makeTargetName = cmStrCat(
+ this->GetRelativeTargetDirectory(target.get()), "/preinstall");
+ localName = cmStrCat(target->GetName(), "/preinstall");
+ depends.clear();
+ commands.clear();
+ commands.push_back(
+ this->GetRecursiveMakeCall(makefile2, makeTargetName));
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ this->GetCurrentBinaryDirectory());
+ this->WriteMakeRule(ruleFileStream,
+ "Manual pre-install relink rule for target.",
+ localName, depends, commands, true);
+ }
+ }
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::WriteDirectoryInformationFile()
+{
+ std::string infoFileName =
+ cmStrCat(this->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/CMakeDirectoryInformation.cmake");
+
+ // Open the output file.
+ cmGeneratedFileStream infoFileStream(infoFileName);
+ if (!infoFileStream) {
+ return;
+ }
+
+ infoFileStream.SetCopyIfDifferent(true);
+ // Write the do not edit header.
+ this->WriteDisclaimer(infoFileStream);
+
+ // Setup relative path conversion tops.
+ /* clang-format off */
+ infoFileStream
+ << "# Relative path conversion top directories.\n"
+ << "set(CMAKE_RELATIVE_PATH_TOP_SOURCE \""
+ << this->StateSnapshot.GetDirectory().GetRelativePathTopSource()
+ << "\")\n"
+ << "set(CMAKE_RELATIVE_PATH_TOP_BINARY \""
+ << this->StateSnapshot.GetDirectory().GetRelativePathTopBinary()
+ << "\")\n"
+ << "\n";
+ /* clang-format on */
+
+ // Tell the dependency scanner to use unix paths if necessary.
+ if (cmSystemTools::GetForceUnixPaths()) {
+ /* clang-format off */
+ infoFileStream
+ << "# Force unix paths in dependencies.\n"
+ << "set(CMAKE_FORCE_UNIX_PATHS 1)\n"
+ << "\n";
+ /* clang-format on */
+ }
+
+ // Store the include regular expressions for this directory.
+ infoFileStream << "\n"
+ << "# The C and CXX include file regular expressions for "
+ << "this directory.\n";
+ infoFileStream << "set(CMAKE_C_INCLUDE_REGEX_SCAN ";
+ cmLocalUnixMakefileGenerator3::WriteCMakeArgument(
+ infoFileStream, this->Makefile->GetIncludeRegularExpression());
+ infoFileStream << ")\n";
+ infoFileStream << "set(CMAKE_C_INCLUDE_REGEX_COMPLAIN ";
+ cmLocalUnixMakefileGenerator3::WriteCMakeArgument(
+ infoFileStream, this->Makefile->GetComplainRegularExpression());
+ infoFileStream << ")\n";
+ infoFileStream
+ << "set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN})\n";
+ infoFileStream << "set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN "
+ "${CMAKE_C_INCLUDE_REGEX_COMPLAIN})\n";
+}
+
+std::string cmLocalUnixMakefileGenerator3::ConvertToFullPath(
+ const std::string& localPath)
+{
+ std::string dir =
+ cmStrCat(this->GetCurrentBinaryDirectory(), '/', localPath);
+ return dir;
+}
+
+const std::string& cmLocalUnixMakefileGenerator3::GetHomeRelativeOutputPath()
+{
+ return this->HomeRelativeOutputPath;
+}
+
+std::string cmLocalUnixMakefileGenerator3::ConvertToMakefilePath(
+ std::string const& path) const
+{
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ return gg->ConvertToMakefilePath(path);
+}
+
+void cmLocalUnixMakefileGenerator3::WriteMakeRule(
+ std::ostream& os, const char* comment, const std::string& target,
+ const std::vector<std::string>& depends,
+ const std::vector<std::string>& commands, bool symbolic, bool in_help)
+{
+ // Make sure there is a target.
+ if (target.empty()) {
+ std::string err("No target for WriteMakeRule! called with comment: ");
+ if (comment) {
+ err += comment;
+ }
+ cmSystemTools::Error(err);
+ return;
+ }
+
+ std::string replace;
+
+ // Write the comment describing the rule in the makefile.
+ if (comment) {
+ replace = comment;
+ std::string::size_type lpos = 0;
+ std::string::size_type rpos;
+ while ((rpos = replace.find('\n', lpos)) != std::string::npos) {
+ os << "# " << replace.substr(lpos, rpos - lpos) << "\n";
+ lpos = rpos + 1;
+ }
+ os << "# " << replace.substr(lpos) << "\n";
+ }
+
+ // Construct the left hand side of the rule.
+ std::string tgt = this->ConvertToMakefilePath(
+ this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), target));
+
+ const char* space = "";
+ if (tgt.size() == 1) {
+ // Add a space before the ":" to avoid drive letter confusion on
+ // Windows.
+ space = " ";
+ }
+
+ // Mark the rule as symbolic if requested.
+ if (symbolic) {
+ if (cmProp sym =
+ this->Makefile->GetDefinition("CMAKE_MAKE_SYMBOLIC_RULE")) {
+ os << tgt << space << ": " << *sym << "\n";
+ }
+ }
+
+ // Write the rule.
+ if (depends.empty()) {
+ // No dependencies. The commands will always run.
+ os << tgt << space << ":\n";
+ } else {
+ // Split dependencies into multiple rule lines. This allows for
+ // very long dependency lists even on older make implementations.
+ std::string binDir = this->GetBinaryDirectory();
+ for (std::string const& depend : depends) {
+ os << tgt << space << ": "
+ << this->ConvertToMakefilePath(
+ this->MaybeConvertToRelativePath(binDir, depend))
+ << '\n';
+ }
+ }
+
+ if (!commands.empty()) {
+ // Write the list of commands.
+ os << cmWrap("\t", commands, "", "\n") << "\n";
+ }
+ if (symbolic && !this->IsWatcomWMake()) {
+ os << ".PHONY : " << tgt << "\n";
+ }
+ os << "\n";
+ // Add the output to the local help if requested.
+ if (in_help) {
+ this->LocalHelp.push_back(target);
+ }
+}
+
+std::string cmLocalUnixMakefileGenerator3::MaybeConvertWatcomShellCommand(
+ std::string const& cmd)
+{
+ if (this->IsWatcomWMake() && cmSystemTools::FileIsFullPath(cmd) &&
+ cmd.find_first_of("( )") != std::string::npos) {
+ // On Watcom WMake use the windows short path for the command
+ // name. This is needed to avoid funny quoting problems on
+ // lines with shell redirection operators.
+ std::string scmd;
+ if (cmSystemTools::GetShortPath(cmd, scmd)) {
+ return this->ConvertToOutputFormat(scmd, cmOutputConverter::SHELL);
+ }
+ }
+ return std::string();
+}
+
+void cmLocalUnixMakefileGenerator3::WriteMakeVariables(
+ std::ostream& makefileStream)
+{
+ this->WriteDivider(makefileStream);
+ makefileStream << "# Set environment variables for the build.\n"
+ << "\n";
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ if (gg->DefineWindowsNULL) {
+ makefileStream << "!IF \"$(OS)\" == \"Windows_NT\"\n"
+ << "NULL=\n"
+ << "!ELSE\n"
+ << "NULL=nul\n"
+ << "!ENDIF\n";
+ }
+ if (this->IsWindowsShell()) {
+ makefileStream << "SHELL = cmd.exe\n"
+ << "\n";
+ } else {
+#if !defined(__VMS)
+ /* clang-format off */
+ makefileStream
+ << "# The shell in which to execute make rules.\n"
+ << "SHELL = /bin/sh\n"
+ << "\n";
+/* clang-format on */
+#endif
+ }
+
+ std::string cmakeShellCommand =
+ this->MaybeConvertWatcomShellCommand(cmSystemTools::GetCMakeCommand());
+ if (cmakeShellCommand.empty()) {
+ cmakeShellCommand = this->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
+ }
+
+ /* clang-format off */
+ makefileStream
+ << "# The CMake executable.\n"
+ << "CMAKE_COMMAND = "
+ << cmakeShellCommand
+ << "\n"
+ << "\n";
+ makefileStream
+ << "# The command to remove a file.\n"
+ << "RM = "
+ << cmakeShellCommand
+ << " -E rm -f\n"
+ << "\n";
+ makefileStream
+ << "# Escaping for special characters.\n"
+ << "EQUALS = =\n"
+ << "\n";
+ makefileStream
+ << "# The top-level source directory on which CMake was run.\n"
+ << "CMAKE_SOURCE_DIR = "
+ << this->ConvertToOutputFormat(
+ this->GetSourceDirectory(), cmOutputConverter::SHELL)
+ << "\n"
+ << "\n";
+ makefileStream
+ << "# The top-level build directory on which CMake was run.\n"
+ << "CMAKE_BINARY_DIR = "
+ << this->ConvertToOutputFormat(
+ this->GetBinaryDirectory(), cmOutputConverter::SHELL)
+ << "\n"
+ << "\n";
+ /* clang-format on */
+}
+
+void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsTop(
+ std::ostream& makefileStream)
+{
+ this->WriteDivider(makefileStream);
+ makefileStream << "# Special targets provided by cmake.\n"
+ << "\n";
+
+ std::vector<std::string> no_commands;
+ std::vector<std::string> no_depends;
+
+ // Special target to cleanup operation of make tool.
+ // This should be the first target except for the default_target in
+ // the interface Makefile.
+ this->WriteMakeRule(makefileStream,
+ "Disable implicit rules so canonical targets will work.",
+ ".SUFFIXES", no_depends, no_commands, false);
+
+ if (!this->IsNMake() && !this->IsWatcomWMake() &&
+ !this->BorlandMakeCurlyHack) {
+ // turn off RCS and SCCS automatic stuff from gmake
+ constexpr const char* vcs_rules[] = {
+ "%,v", "RCS/%", "RCS/%,v", "SCCS/s.%", "s.%",
+ };
+ for (const auto* vcs_rule : vcs_rules) {
+ std::vector<std::string> vcs_depend;
+ vcs_depend.emplace_back(vcs_rule);
+ this->WriteMakeRule(makefileStream, "Disable VCS-based implicit rules.",
+ "%", vcs_depend, no_commands, false);
+ }
+ }
+ // Add a fake suffix to keep HP happy. Must be max 32 chars for SGI make.
+ std::vector<std::string> depends;
+ depends.emplace_back(".hpux_make_needs_suffix_list");
+ this->WriteMakeRule(makefileStream, nullptr, ".SUFFIXES", depends,
+ no_commands, false);
+ if (this->IsWatcomWMake()) {
+ // Switch on WMake feature, if an error or interrupt occurs during
+ // makefile processing, the current target being made may be deleted
+ // without prompting (the same as command line -e option).
+ /* clang-format off */
+ makefileStream <<
+ "\n"
+ ".ERASE\n"
+ "\n"
+ ;
+ /* clang-format on */
+ }
+ if (this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")) {
+ /* clang-format off */
+ makefileStream
+ << "# Produce verbose output by default.\n"
+ << "VERBOSE = 1\n"
+ << "\n";
+ /* clang-format on */
+ }
+ if (this->IsWatcomWMake()) {
+ /* clang-format off */
+ makefileStream <<
+ "!ifndef VERBOSE\n"
+ ".SILENT\n"
+ "!endif\n"
+ "\n"
+ ;
+ /* clang-format on */
+ } else {
+ makefileStream << "# Command-line flag to silence nested $(MAKE).\n"
+ "$(VERBOSE)MAKESILENT = -s\n"
+ "\n";
+
+ // Write special target to silence make output. This must be after
+ // the default target in case VERBOSE is set (which changes the
+ // name). The setting of CMAKE_VERBOSE_MAKEFILE to ON will cause a
+ // "VERBOSE=1" to be added as a make variable which will change the
+ // name of this special target. This gives a make-time choice to
+ // the user.
+ // Write directly to the stream since WriteMakeRule escapes '$'.
+ makefileStream << "#Suppress display of executed commands.\n"
+ "$(VERBOSE).SILENT:\n"
+ "\n";
+ }
+
+ // Work-around for makes that drop rules that have no dependencies
+ // or commands.
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ std::string hack = gg->GetEmptyRuleHackDepends();
+ if (!hack.empty()) {
+ no_depends.push_back(std::move(hack));
+ }
+ std::string hack_cmd = gg->GetEmptyRuleHackCommand();
+ if (!hack_cmd.empty()) {
+ no_commands.push_back(std::move(hack_cmd));
+ }
+
+ // Special symbolic target that never exists to force dependers to
+ // run their rules.
+ this->WriteMakeRule(makefileStream, "A target that is always out of date.",
+ "cmake_force", no_depends, no_commands, true);
+
+ // Variables for reference by other rules.
+ this->WriteMakeVariables(makefileStream);
+}
+
+void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom(
+ std::ostream& makefileStream)
+{
+ this->WriteDivider(makefileStream);
+ makefileStream << "# Special targets to cleanup operation of make.\n"
+ << "\n";
+
+ // Write special "cmake_check_build_system" target to run cmake with
+ // the --check-build-system flag.
+ if (!this->GlobalGenerator->GlobalSettingIsOn(
+ "CMAKE_SUPPRESS_REGENERATION")) {
+ // Build command to run CMake to check if anything needs regenerating.
+ std::vector<std::string> commands;
+ cmake* cm = this->GlobalGenerator->GetCMakeInstance();
+ if (cm->DoWriteGlobVerifyTarget()) {
+ std::string rescanRule =
+ cmStrCat("$(CMAKE_COMMAND) -P ",
+ this->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
+ cmOutputConverter::SHELL));
+ commands.push_back(rescanRule);
+ }
+ std::string cmakefileName = "CMakeFiles/Makefile.cmake";
+ std::string runRule = cmStrCat(
+ "$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) "
+ "--check-build-system ",
+ this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL),
+ " 0");
+
+ std::vector<std::string> no_depends;
+ commands.push_back(std::move(runRule));
+ if (!this->IsRootMakefile()) {
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ this->GetCurrentBinaryDirectory());
+ }
+ this->WriteMakeRule(makefileStream,
+ "Special rule to run CMake to check the build system "
+ "integrity.\n"
+ "No rule that depends on this can have "
+ "commands that come from listfiles\n"
+ "because they might be regenerated.",
+ "cmake_check_build_system", no_depends, commands,
+ true);
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::WriteConvenienceRule(
+ std::ostream& ruleFileStream, const std::string& realTarget,
+ const std::string& helpTarget)
+{
+ // A rule is only needed if the names are different.
+ if (realTarget != helpTarget) {
+ // The helper target depends on the real target.
+ std::vector<std::string> depends;
+ depends.push_back(realTarget);
+
+ // There are no commands.
+ std::vector<std::string> no_commands;
+
+ // Write the rule.
+ this->WriteMakeRule(ruleFileStream, "Convenience name for target.",
+ helpTarget, depends, no_commands, true);
+ }
+}
+
+std::string cmLocalUnixMakefileGenerator3::GetRelativeTargetDirectory(
+ cmGeneratorTarget const* target) const
+{
+ std::string dir =
+ cmStrCat(this->HomeRelativeOutputPath, this->GetTargetDirectory(target));
+ return dir;
+}
+
+void cmLocalUnixMakefileGenerator3::AppendFlags(
+ std::string& flags, const std::string& newFlags) const
+{
+ if (this->IsWatcomWMake() && !newFlags.empty()) {
+ std::string newf = newFlags;
+ if (newf.find("\\\"") != std::string::npos) {
+ cmSystemTools::ReplaceString(newf, "\\\"", "\"");
+ this->cmLocalGenerator::AppendFlags(flags, newf);
+ return;
+ }
+ }
+ this->cmLocalGenerator::AppendFlags(flags, newFlags);
+}
+
+void cmLocalUnixMakefileGenerator3::AppendRuleDepend(
+ std::vector<std::string>& depends, const char* ruleFileName)
+{
+ // Add a dependency on the rule file itself unless an option to skip
+ // it is specifically enabled by the user or project.
+ cmProp nodep = this->Makefile->GetDefinition("CMAKE_SKIP_RULE_DEPENDENCY");
+ if (cmIsOff(nodep)) {
+ depends.emplace_back(ruleFileName);
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::AppendRuleDepends(
+ std::vector<std::string>& depends, std::vector<std::string> const& ruleFiles)
+{
+ // Add a dependency on the rule file itself unless an option to skip
+ // it is specifically enabled by the user or project.
+ if (!this->Makefile->IsOn("CMAKE_SKIP_RULE_DEPENDENCY")) {
+ cm::append(depends, ruleFiles);
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::AppendCustomDepends(
+ std::vector<std::string>& depends, const std::vector<cmCustomCommand>& ccs)
+{
+ for (cmCustomCommand const& cc : ccs) {
+ cmCustomCommandGenerator ccg(cc, this->GetConfigName(), this);
+ this->AppendCustomDepend(depends, ccg);
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::AppendCustomDepend(
+ std::vector<std::string>& depends, cmCustomCommandGenerator const& ccg)
+{
+ for (std::string const& d : ccg.GetDepends()) {
+ // Lookup the real name of the dependency in case it is a CMake target.
+ std::string dep;
+ if (this->GetRealDependency(d, this->GetConfigName(), dep)) {
+ depends.push_back(std::move(dep));
+ }
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::AppendCustomCommands(
+ std::vector<std::string>& commands, const std::vector<cmCustomCommand>& ccs,
+ cmGeneratorTarget* target, std::string const& relative)
+{
+ for (cmCustomCommand const& cc : ccs) {
+ cmCustomCommandGenerator ccg(cc, this->GetConfigName(), this);
+ this->AppendCustomCommand(commands, ccg, target, relative, true);
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::AppendCustomCommand(
+ std::vector<std::string>& commands, cmCustomCommandGenerator const& ccg,
+ cmGeneratorTarget* target, std::string const& relative, bool echo_comment,
+ std::ostream* content)
+{
+ // Optionally create a command to display the custom command's
+ // comment text. This is used for pre-build, pre-link, and
+ // post-build command comments. Custom build step commands have
+ // their comments generated elsewhere.
+ if (echo_comment) {
+ const char* comment = ccg.GetComment();
+ if (comment && *comment) {
+ this->AppendEcho(commands, comment,
+ cmLocalUnixMakefileGenerator3::EchoGenerate);
+ }
+ }
+
+ // if the command specified a working directory use it.
+ std::string dir = this->GetCurrentBinaryDirectory();
+ std::string workingDir = ccg.GetWorkingDirectory();
+ if (!workingDir.empty()) {
+ dir = workingDir;
+ }
+ if (content) {
+ *content << dir;
+ }
+
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->CreateRulePlaceholderExpander());
+
+ // Add each command line to the set of commands.
+ std::vector<std::string> commands1;
+ std::string currentBinDir = this->GetCurrentBinaryDirectory();
+ for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
+ // Build the command line in a single string.
+ std::string cmd = ccg.GetCommand(c);
+ if (!cmd.empty()) {
+ // Use "call " before any invocations of .bat or .cmd files
+ // invoked as custom commands in the WindowsShell.
+ //
+ bool useCall = false;
+
+ if (this->IsWindowsShell()) {
+ std::string suffix;
+ if (cmd.size() > 4) {
+ suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size() - 4));
+ if (suffix == ".bat" || suffix == ".cmd") {
+ useCall = true;
+ }
+ }
+ }
+
+ cmSystemTools::ReplaceString(cmd, "/./", "/");
+ // Convert the command to a relative path only if the current
+ // working directory will be the start-output directory.
+ bool had_slash = cmd.find('/') != std::string::npos;
+ if (workingDir.empty()) {
+ cmd = this->MaybeConvertToRelativePath(currentBinDir, cmd);
+ }
+ bool has_slash = cmd.find('/') != std::string::npos;
+ if (had_slash && !has_slash) {
+ // This command was specified as a path to a file in the
+ // current directory. Add a leading "./" so it can run
+ // without the current directory being in the search path.
+ cmd = cmStrCat("./", cmd);
+ }
+
+ std::string launcher;
+ // Short-circuit if there is no launcher.
+ cmProp val = this->GetRuleLauncher(target, "RULE_LAUNCH_CUSTOM");
+ if (cmNonempty(val)) {
+ // Expand rule variables referenced in the given launcher command.
+ cmRulePlaceholderExpander::RuleVariables vars;
+ vars.CMTargetName = target->GetName().c_str();
+ vars.CMTargetType =
+ cmState::GetTargetTypeName(target->GetType()).c_str();
+ std::string output;
+ const std::vector<std::string>& outputs = ccg.GetOutputs();
+ if (!outputs.empty()) {
+ output = outputs[0];
+ if (workingDir.empty()) {
+ output = this->MaybeConvertToRelativePath(
+ this->GetCurrentBinaryDirectory(), output);
+ }
+ output =
+ this->ConvertToOutputFormat(output, cmOutputConverter::SHELL);
+ }
+ vars.Output = output.c_str();
+
+ launcher = *val;
+ rulePlaceholderExpander->ExpandRuleVariables(this, launcher, vars);
+ if (!launcher.empty()) {
+ launcher += " ";
+ }
+ }
+
+ std::string shellCommand = this->MaybeConvertWatcomShellCommand(cmd);
+ if (shellCommand.empty()) {
+ shellCommand =
+ this->ConvertToOutputFormat(cmd, cmOutputConverter::SHELL);
+ }
+ cmd = launcher + shellCommand;
+
+ ccg.AppendArguments(c, cmd);
+ if (content) {
+ // Rule content does not include the launcher.
+ *content << (cmd.c_str() + launcher.size());
+ }
+ if (this->BorlandMakeCurlyHack) {
+ // Borland Make has a very strange bug. If the first curly
+ // brace anywhere in the command string is a left curly, it
+ // must be written {{} instead of just {. Otherwise some
+ // curly braces are removed. The hack can be skipped if the
+ // first curly brace is the last character.
+ std::string::size_type lcurly = cmd.find('{');
+ if (lcurly != std::string::npos && lcurly < (cmd.size() - 1)) {
+ std::string::size_type rcurly = cmd.find('}');
+ if (rcurly == std::string::npos || rcurly > lcurly) {
+ // The first curly is a left curly. Use the hack.
+ cmd =
+ cmStrCat(cmd.substr(0, lcurly), "{{}", cmd.substr(lcurly + 1));
+ }
+ }
+ }
+ if (launcher.empty()) {
+ if (useCall) {
+ cmd = cmStrCat("call ", cmd);
+ } else if (this->IsNMake() && cmd[0] == '"') {
+ cmd = cmStrCat("echo >nul && ", cmd);
+ }
+ }
+ commands1.push_back(std::move(cmd));
+ }
+ }
+
+ // Setup the proper working directory for the commands.
+ this->CreateCDCommand(commands1, dir, relative);
+
+ // push back the custom commands
+ cm::append(commands, commands1);
+}
+
+void cmLocalUnixMakefileGenerator3::AppendCleanCommand(
+ std::vector<std::string>& commands, const std::set<std::string>& files,
+ cmGeneratorTarget* target, const char* filename)
+{
+ std::string currentBinDir = this->GetCurrentBinaryDirectory();
+ std::string cleanfile = cmStrCat(
+ currentBinDir, '/', this->GetTargetDirectory(target), "/cmake_clean");
+ if (filename) {
+ cleanfile += "_";
+ cleanfile += filename;
+ }
+ cleanfile += ".cmake";
+ cmsys::ofstream fout(cleanfile.c_str());
+ if (!fout) {
+ cmSystemTools::Error("Could not create " + cleanfile);
+ }
+ if (!files.empty()) {
+ fout << "file(REMOVE_RECURSE\n";
+ for (std::string const& file : files) {
+ std::string fc = this->MaybeConvertToRelativePath(currentBinDir, file);
+ fout << " " << cmOutputConverter::EscapeForCMake(fc) << "\n";
+ }
+ fout << ")\n";
+ }
+ {
+ std::string remove =
+ cmStrCat("$(CMAKE_COMMAND) -P ",
+ this->ConvertToOutputFormat(
+ this->MaybeConvertToRelativePath(
+ this->GetCurrentBinaryDirectory(), cleanfile),
+ cmOutputConverter::SHELL));
+ commands.push_back(std::move(remove));
+ }
+
+ // For the main clean rule add per-language cleaning.
+ if (!filename) {
+ // Get the set of source languages in the target.
+ std::set<std::string> languages;
+ target->GetLanguages(
+ languages, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ /* clang-format off */
+ fout << "\n"
+ << "# Per-language clean rules from dependency scanning.\n"
+ << "foreach(lang " << cmJoin(languages, " ") << ")\n"
+ << " include(" << this->GetTargetDirectory(target)
+ << "/cmake_clean_${lang}.cmake OPTIONAL)\n"
+ << "endforeach()\n";
+ /* clang-format on */
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::AppendDirectoryCleanCommand(
+ std::vector<std::string>& commands)
+{
+ std::vector<std::string> cleanFiles;
+ // Look for additional files registered for cleaning in this directory.
+ if (cmProp prop_value =
+ this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) {
+ cmExpandList(cmGeneratorExpression::Evaluate(
+ *prop_value, this,
+ this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")),
+ cleanFiles);
+ }
+ if (cleanFiles.empty()) {
+ return;
+ }
+
+ const auto& rootLG = this->GetGlobalGenerator()->GetLocalGenerators().at(0);
+ std::string const& binaryDir = rootLG->GetCurrentBinaryDirectory();
+ std::string const& currentBinaryDir = this->GetCurrentBinaryDirectory();
+ std::string cleanfile =
+ cmStrCat(currentBinaryDir, "/CMakeFiles/cmake_directory_clean.cmake");
+ // Write clean script
+ {
+ cmsys::ofstream fout(cleanfile.c_str());
+ if (!fout) {
+ cmSystemTools::Error("Could not create " + cleanfile);
+ return;
+ }
+ fout << "file(REMOVE_RECURSE\n";
+ for (std::string const& cfl : cleanFiles) {
+ std::string fc = rootLG->MaybeConvertToRelativePath(
+ binaryDir, cmSystemTools::CollapseFullPath(cfl, currentBinaryDir));
+ fout << " " << cmOutputConverter::EscapeForCMake(fc) << "\n";
+ }
+ fout << ")\n";
+ }
+ // Create command
+ {
+ std::string remove =
+ cmStrCat("$(CMAKE_COMMAND) -P ",
+ this->ConvertToOutputFormat(
+ rootLG->MaybeConvertToRelativePath(binaryDir, cleanfile),
+ cmOutputConverter::SHELL));
+ commands.push_back(std::move(remove));
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::AppendEcho(
+ std::vector<std::string>& commands, std::string const& text, EchoColor color,
+ EchoProgress const* progress)
+{
+ // Choose the color for the text.
+ std::string color_name;
+ if (this->GlobalGenerator->GetToolSupportsColor() && this->ColorMakefile) {
+ // See cmake::ExecuteEchoColor in cmake.cxx for these options.
+ // This color set is readable on both black and white backgrounds.
+ switch (color) {
+ case EchoNormal:
+ break;
+ case EchoDepend:
+ color_name = "--magenta --bold ";
+ break;
+ case EchoBuild:
+ color_name = "--green ";
+ break;
+ case EchoLink:
+ color_name = "--green --bold ";
+ break;
+ case EchoGenerate:
+ color_name = "--blue --bold ";
+ break;
+ case EchoGlobal:
+ color_name = "--cyan ";
+ break;
+ }
+ }
+
+ // Echo one line at a time.
+ std::string line;
+ line.reserve(200);
+ for (const char* c = text.c_str();; ++c) {
+ if (*c == '\n' || *c == '\0') {
+ // Avoid writing a blank last line on end-of-string.
+ if (*c != '\0' || !line.empty()) {
+ // Add a command to echo this line.
+ std::string cmd;
+ if (color_name.empty() && !progress) {
+ // Use the native echo command.
+ cmd = cmStrCat("@echo ", this->EscapeForShell(line, false, true));
+ } else {
+ // Use cmake to echo the text in color.
+ cmd = cmStrCat(
+ "@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) ",
+ color_name);
+ if (progress) {
+ cmd += "--progress-dir=";
+ cmd += this->ConvertToOutputFormat(progress->Dir,
+ cmOutputConverter::SHELL);
+ cmd += " ";
+ cmd += "--progress-num=";
+ cmd += progress->Arg;
+ cmd += " ";
+ }
+ cmd += this->EscapeForShell(line);
+ }
+ commands.push_back(std::move(cmd));
+ }
+
+ // Reset the line to empty.
+ line.clear();
+
+ // Progress appears only on first line.
+ progress = nullptr;
+
+ // Terminate on end-of-string.
+ if (*c == '\0') {
+ return;
+ }
+ } else if (*c != '\r') {
+ // Append this character to the current line.
+ line += *c;
+ }
+ }
+}
+
+std::string cmLocalUnixMakefileGenerator3::CreateMakeVariable(
+ std::string const& s, std::string const& s2)
+{
+ std::string unmodified = cmStrCat(s, s2);
+ // if there is no restriction on the length of make variables
+ // and there are no "." characters in the string, then return the
+ // unmodified combination.
+ if ((!this->MakefileVariableSize &&
+ unmodified.find('.') == std::string::npos) &&
+ (!this->MakefileVariableSize &&
+ unmodified.find('+') == std::string::npos) &&
+ (!this->MakefileVariableSize &&
+ unmodified.find('-') == std::string::npos)) {
+ return unmodified;
+ }
+
+ // see if the variable has been defined before and return
+ // the modified version of the variable
+ auto i = this->MakeVariableMap.find(unmodified);
+ if (i != this->MakeVariableMap.end()) {
+ return i->second;
+ }
+ // start with the unmodified variable
+ std::string ret = unmodified;
+ // if this there is no value for this->MakefileVariableSize then
+ // the string must have bad characters in it
+ if (!this->MakefileVariableSize) {
+ std::replace(ret.begin(), ret.end(), '.', '_');
+ cmSystemTools::ReplaceString(ret, "-", "__");
+ cmSystemTools::ReplaceString(ret, "+", "___");
+ int ni = 0;
+ char buffer[5];
+ // make sure the _ version is not already used, if
+ // it is used then add number to the end of the variable
+ while (this->ShortMakeVariableMap.count(ret) && ni < 1000) {
+ ++ni;
+ sprintf(buffer, "%04d", ni);
+ ret = unmodified + buffer;
+ }
+ this->ShortMakeVariableMap[ret] = "1";
+ this->MakeVariableMap[unmodified] = ret;
+ return ret;
+ }
+
+ // if the string is greater than 32 chars it is an invalid variable name
+ // for borland make
+ if (static_cast<int>(ret.size()) > this->MakefileVariableSize) {
+ int keep = this->MakefileVariableSize - 8;
+ int size = keep + 3;
+ std::string str1 = s;
+ std::string str2 = s2;
+ // we must shorten the combined string by 4 characters
+ // keep no more than 24 characters from the second string
+ if (static_cast<int>(str2.size()) > keep) {
+ str2 = str2.substr(0, keep);
+ }
+ if (static_cast<int>(str1.size()) + static_cast<int>(str2.size()) > size) {
+ str1 = str1.substr(0, size - str2.size());
+ }
+ char buffer[5];
+ int ni = 0;
+ sprintf(buffer, "%04d", ni);
+ ret = str1 + str2 + buffer;
+ while (this->ShortMakeVariableMap.count(ret) && ni < 1000) {
+ ++ni;
+ sprintf(buffer, "%04d", ni);
+ ret = str1 + str2 + buffer;
+ }
+ if (ni == 1000) {
+ cmSystemTools::Error("Borland makefile variable length too long");
+ return unmodified;
+ }
+ // once an unused variable is found
+ this->ShortMakeVariableMap[ret] = "1";
+ }
+ // always make an entry into the unmodified to variable map
+ this->MakeVariableMap[unmodified] = ret;
+ return ret;
+}
+
+bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
+ const std::string& tgtInfo, bool verbose, bool color)
+{
+ // read in the target info file
+ if (!this->Makefile->ReadListFile(tgtInfo) ||
+ cmSystemTools::GetErrorOccuredFlag()) {
+ cmSystemTools::Error("Target DependInfo.cmake file not found");
+ }
+
+ bool status = true;
+
+ // Check if any multiple output pairs have a missing file.
+ this->CheckMultipleOutputs(verbose);
+
+ std::string const targetDir = cmSystemTools::GetFilenamePath(tgtInfo);
+ if (!this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES").empty()) {
+ // dependencies are managed by CMake itself
+
+ std::string const internalDependFile = targetDir + "/depend.internal";
+ std::string const dependFile = targetDir + "/depend.make";
+
+ // If the target DependInfo.cmake file has changed since the last
+ // time dependencies were scanned then force rescanning. This may
+ // happen when a new source file is added and CMake regenerates the
+ // project but no other sources were touched.
+ bool needRescanDependInfo = false;
+ cmFileTimeCache* ftc =
+ this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache();
+ {
+ int result;
+ if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) {
+ if (verbose) {
+ cmSystemTools::Stdout(cmStrCat("Dependee \"", tgtInfo,
+ "\" is newer than depender \"",
+ internalDependFile, "\".\n"));
+ }
+ needRescanDependInfo = true;
+ }
+ }
+
+ // If the directory information is newer than depend.internal, include
+ // dirs may have changed. In this case discard all old dependencies.
+ bool needRescanDirInfo = false;
+ {
+ std::string dirInfoFile =
+ cmStrCat(this->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/CMakeDirectoryInformation.cmake");
+ int result;
+ if (!ftc->Compare(internalDependFile, dirInfoFile, &result) ||
+ result < 0) {
+ if (verbose) {
+ cmSystemTools::Stdout(cmStrCat("Dependee \"", dirInfoFile,
+ "\" is newer than depender \"",
+ internalDependFile, "\".\n"));
+ }
+ needRescanDirInfo = true;
+ }
+ }
+
+ // Check the implicit dependencies to see if they are up to date.
+ // The build.make file may have explicit dependencies for the object
+ // files but these will not affect the scanning process so they need
+ // not be considered.
+ cmDepends::DependencyMap validDependencies;
+ bool needRescanDependencies = false;
+ if (!needRescanDirInfo) {
+ cmDependsC checker;
+ checker.SetVerbose(verbose);
+ checker.SetFileTimeCache(ftc);
+ // cmDependsC::Check() fills the vector validDependencies() with the
+ // dependencies for those files where they are still valid, i.e.
+ // neither the files themselves nor any files they depend on have
+ // changed. We don't do that if the CMakeDirectoryInformation.cmake
+ // file has changed, because then potentially all dependencies have
+ // changed. This information is given later on to cmDependsC, which
+ // then only rescans the files where it did not get valid dependencies
+ // via this dependency vector. This means that in the normal case, when
+ // only few or one file have been edited, then also only this one file
+ // is actually scanned again, instead of all files for this target.
+ needRescanDependencies =
+ !checker.Check(dependFile, internalDependFile, validDependencies);
+ }
+
+ if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) {
+ // The dependencies must be regenerated.
+ std::string targetName = cmSystemTools::GetFilenameName(targetDir);
+ targetName = targetName.substr(0, targetName.length() - 4);
+ std::string message =
+ cmStrCat("Scanning dependencies of target ", targetName);
+ cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
+ cmsysTerminal_Color_ForegroundBold,
+ message.c_str(), true, color);
+
+ status = this->ScanDependencies(targetDir, dependFile,
+ internalDependFile, validDependencies);
+ }
+ }
+
+ auto depends =
+ this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_DEPENDENCY_FILES");
+ if (!depends.empty()) {
+ // dependencies are managed by compiler
+ auto depFiles = cmExpandedList(depends, true);
+ std::string const internalDepFile =
+ targetDir + "/compiler_depend.internal";
+ std::string const depFile = targetDir + "/compiler_depend.make";
+ cmDepends::DependencyMap dependencies;
+ cmDependsCompiler depsManager;
+ bool projectOnly = cmIsOn(
+ this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_IN_PROJECT_ONLY"));
+
+ depsManager.SetVerbose(verbose);
+ depsManager.SetLocalGenerator(this);
+
+ if (!depsManager.CheckDependencies(
+ internalDepFile, depFiles, dependencies,
+ projectOnly ? NotInProjectDir(this->GetSourceDirectory(),
+ this->GetBinaryDirectory())
+ : std::function<bool(const std::string&)>())) {
+ // regenerate dependencies files
+ std::string targetName =
+ cmCMakePath(targetDir).GetFileName().RemoveExtension().GenericString();
+ auto message = cmStrCat(
+ "Consolidate compiler generated dependencies of target ", targetName);
+ cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
+ cmsysTerminal_Color_ForegroundBold,
+ message.c_str(), true, color);
+
+ // Open the make depends file. This should be copy-if-different
+ // because the make tool may try to reload it needlessly otherwise.
+ cmGeneratedFileStream ruleFileStream(
+ depFile, false, this->GlobalGenerator->GetMakefileEncoding());
+ ruleFileStream.SetCopyIfDifferent(true);
+ if (!ruleFileStream) {
+ return false;
+ }
+
+ // Open the cmake dependency tracking file. This should not be
+ // copy-if-different because dependencies are re-scanned when it is
+ // older than the DependInfo.cmake.
+ cmGeneratedFileStream internalRuleFileStream(
+ internalDepFile, false, this->GlobalGenerator->GetMakefileEncoding());
+ if (!internalRuleFileStream) {
+ return false;
+ }
+
+ this->WriteDisclaimer(ruleFileStream);
+ this->WriteDisclaimer(internalRuleFileStream);
+
+ depsManager.WriteDependencies(dependencies, ruleFileStream,
+ internalRuleFileStream);
+ }
+ }
+
+ // The dependencies are already up-to-date.
+ return status;
+}
+
+bool cmLocalUnixMakefileGenerator3::ScanDependencies(
+ std::string const& targetDir, std::string const& dependFile,
+ std::string const& internalDependFile, cmDepends::DependencyMap& validDeps)
+{
+ // Read the directory information file.
+ cmMakefile* mf = this->Makefile;
+ bool haveDirectoryInfo = false;
+ {
+ std::string dirInfoFile =
+ cmStrCat(this->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/CMakeDirectoryInformation.cmake");
+ if (mf->ReadListFile(dirInfoFile) &&
+ !cmSystemTools::GetErrorOccuredFlag()) {
+ haveDirectoryInfo = true;
+ }
+ }
+
+ // Lookup useful directory information.
+ if (haveDirectoryInfo) {
+ // Test whether we need to force Unix paths.
+ if (cmProp force = mf->GetDefinition("CMAKE_FORCE_UNIX_PATHS")) {
+ if (!cmIsOff(force)) {
+ cmSystemTools::SetForceUnixPaths(true);
+ }
+ }
+
+ // Setup relative path top directories.
+ if (cmProp relativePathTopSource =
+ mf->GetDefinition("CMAKE_RELATIVE_PATH_TOP_SOURCE")) {
+ this->StateSnapshot.GetDirectory().SetRelativePathTopSource(
+ relativePathTopSource->c_str());
+ }
+ if (cmProp relativePathTopBinary =
+ mf->GetDefinition("CMAKE_RELATIVE_PATH_TOP_BINARY")) {
+ this->StateSnapshot.GetDirectory().SetRelativePathTopBinary(
+ relativePathTopBinary->c_str());
+ }
+ } else {
+ cmSystemTools::Error("Directory Information file not found");
+ }
+
+ // Open the make depends file. This should be copy-if-different
+ // because the make tool may try to reload it needlessly otherwise.
+ cmGeneratedFileStream ruleFileStream(
+ dependFile, false, this->GlobalGenerator->GetMakefileEncoding());
+ ruleFileStream.SetCopyIfDifferent(true);
+ if (!ruleFileStream) {
+ return false;
+ }
+
+ // Open the cmake dependency tracking file. This should not be
+ // copy-if-different because dependencies are re-scanned when it is
+ // older than the DependInfo.cmake.
+ cmGeneratedFileStream internalRuleFileStream(
+ internalDependFile, false, this->GlobalGenerator->GetMakefileEncoding());
+ if (!internalRuleFileStream) {
+ return false;
+ }
+
+ this->WriteDisclaimer(ruleFileStream);
+ this->WriteDisclaimer(internalRuleFileStream);
+
+ // for each language we need to scan, scan it
+ std::vector<std::string> langs =
+ cmExpandedList(mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES"));
+ for (std::string const& lang : langs) {
+ // construct the checker
+ // Create the scanner for this language
+ std::unique_ptr<cmDepends> scanner;
+ if (lang == "C" || lang == "CXX" || lang == "RC" || lang == "ASM" ||
+ lang == "OBJC" || lang == "OBJCXX" || lang == "CUDA" ||
+ lang == "ISPC") {
+ // TODO: Handle RC (resource files) dependencies correctly.
+ scanner = cm::make_unique<cmDependsC>(this, targetDir, lang, &validDeps);
+ }
+#ifndef CMAKE_BOOTSTRAP
+ else if (lang == "Fortran") {
+ ruleFileStream << "# Note that incremental build could trigger "
+ << "a call to cmake_copy_f90_mod on each re-build\n";
+ scanner = cm::make_unique<cmDependsFortran>(this);
+ } else if (lang == "Java") {
+ scanner = cm::make_unique<cmDependsJava>();
+ }
+#endif
+
+ if (scanner) {
+ scanner->SetLocalGenerator(this);
+ scanner->SetFileTimeCache(
+ this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache());
+ scanner->SetLanguage(lang);
+ scanner->SetTargetDirectory(targetDir);
+ scanner->Write(ruleFileStream, internalRuleFileStream);
+ }
+ }
+
+ return true;
+}
+
+void cmLocalUnixMakefileGenerator3::CheckMultipleOutputs(bool verbose)
+{
+ cmMakefile* mf = this->Makefile;
+
+ // Get the string listing the multiple output pairs.
+ cmProp pairs_string = mf->GetDefinition("CMAKE_MULTIPLE_OUTPUT_PAIRS");
+ if (!pairs_string) {
+ return;
+ }
+
+ // Convert the string to a list and preserve empty entries.
+ std::vector<std::string> pairs = cmExpandedList(*pairs_string, true);
+ for (auto i = pairs.begin(); i != pairs.end() && (i + 1) != pairs.end();) {
+ const std::string& depender = *i++;
+ const std::string& dependee = *i++;
+
+ // If the depender is missing then delete the dependee to make
+ // sure both will be regenerated.
+ if (cmSystemTools::FileExists(dependee) &&
+ !cmSystemTools::FileExists(depender)) {
+ if (verbose) {
+ cmSystemTools::Stdout(cmStrCat(
+ "Deleting primary custom command output \"", dependee,
+ "\" because another output \"", depender, "\" does not exist.\n"));
+ }
+ cmSystemTools::RemoveFile(dependee);
+ }
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::WriteLocalAllRules(
+ std::ostream& ruleFileStream)
+{
+ this->WriteDisclaimer(ruleFileStream);
+
+ // Write the main entry point target. This must be the VERY first
+ // target so that make with no arguments will run it.
+ {
+ // Just depend on the all target to drive the build.
+ std::vector<std::string> depends;
+ std::vector<std::string> no_commands;
+ depends.emplace_back("all");
+
+ // Write the rule.
+ this->WriteMakeRule(ruleFileStream,
+ "Default target executed when no arguments are "
+ "given to make.",
+ "default_target", depends, no_commands, true);
+
+ // Help out users that try "gmake target1 target2 -j".
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ if (gg->AllowNotParallel()) {
+ std::vector<std::string> no_depends;
+ this->WriteMakeRule(ruleFileStream,
+ "Allow only one \"make -f "
+ "Makefile2\" at a time, but pass "
+ "parallelism.",
+ ".NOTPARALLEL", no_depends, no_commands, false);
+ }
+ }
+
+ this->WriteSpecialTargetsTop(ruleFileStream);
+
+ // Include the progress variables for the target.
+ // Write all global targets
+ this->WriteDivider(ruleFileStream);
+ ruleFileStream << "# Targets provided globally by CMake.\n"
+ << "\n";
+ const auto& targets = this->GetGeneratorTargets();
+ for (const auto& gt : targets) {
+ if (gt->GetType() == cmStateEnums::GLOBAL_TARGET) {
+ std::string targetString =
+ "Special rule for the target " + gt->GetName();
+ std::vector<std::string> commands;
+ std::vector<std::string> depends;
+
+ cmProp p = gt->GetProperty("EchoString");
+ const char* text = p ? p->c_str() : "Running external command ...";
+ depends.reserve(gt->GetUtilities().size());
+ for (BT<std::pair<std::string, bool>> const& u : gt->GetUtilities()) {
+ depends.push_back(u.Value.first);
+ }
+ this->AppendEcho(commands, text,
+ cmLocalUnixMakefileGenerator3::EchoGlobal);
+
+ // Global targets store their rules in pre- and post-build commands.
+ this->AppendCustomDepends(depends, gt->GetPreBuildCommands());
+ this->AppendCustomDepends(depends, gt->GetPostBuildCommands());
+ this->AppendCustomCommands(commands, gt->GetPreBuildCommands(), gt.get(),
+ this->GetCurrentBinaryDirectory());
+ this->AppendCustomCommands(commands, gt->GetPostBuildCommands(),
+ gt.get(), this->GetCurrentBinaryDirectory());
+ std::string targetName = gt->GetName();
+ this->WriteMakeRule(ruleFileStream, targetString.c_str(), targetName,
+ depends, commands, true);
+
+ // Provide a "/fast" version of the target.
+ depends.clear();
+ if ((targetName == "install") || (targetName == "install/local") ||
+ (targetName == "install/strip")) {
+ // Provide a fast install target that does not depend on all
+ // but has the same command.
+ depends.emplace_back("preinstall/fast");
+ } else {
+ // Just forward to the real target so at least it will work.
+ depends.push_back(targetName);
+ commands.clear();
+ }
+ targetName += "/fast";
+ this->WriteMakeRule(ruleFileStream, targetString.c_str(), targetName,
+ depends, commands, true);
+ }
+ }
+
+ std::vector<std::string> depends;
+ std::vector<std::string> commands;
+
+ // Write the all rule.
+ std::string recursiveTarget =
+ cmStrCat(this->GetCurrentBinaryDirectory(), "/all");
+
+ bool regenerate =
+ !this->GlobalGenerator->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
+ if (regenerate) {
+ depends.emplace_back("cmake_check_build_system");
+ }
+
+ std::string progressDir =
+ cmStrCat(this->GetBinaryDirectory(), "/CMakeFiles");
+ {
+ std::ostringstream progCmd;
+ progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
+ progCmd << this->ConvertToOutputFormat(progressDir,
+ cmOutputConverter::SHELL);
+
+ std::string progressFile = "/CMakeFiles/progress.marks";
+ std::string progressFileNameFull = this->ConvertToFullPath(progressFile);
+ progCmd << " "
+ << this->ConvertToOutputFormat(progressFileNameFull,
+ cmOutputConverter::SHELL);
+ commands.push_back(progCmd.str());
+ }
+ std::string mf2Dir = "CMakeFiles/Makefile2";
+ commands.push_back(this->GetRecursiveMakeCall(mf2Dir, recursiveTarget));
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ this->GetCurrentBinaryDirectory());
+ {
+ std::ostringstream progCmd;
+ progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
+ progCmd << this->ConvertToOutputFormat(progressDir,
+ cmOutputConverter::SHELL);
+ progCmd << " 0";
+ commands.push_back(progCmd.str());
+ }
+ this->WriteMakeRule(ruleFileStream, "The main all target", "all", depends,
+ commands, true);
+
+ // Write the clean rule.
+ recursiveTarget = cmStrCat(this->GetCurrentBinaryDirectory(), "/clean");
+ commands.clear();
+ depends.clear();
+ commands.push_back(this->GetRecursiveMakeCall(mf2Dir, recursiveTarget));
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ this->GetCurrentBinaryDirectory());
+ this->WriteMakeRule(ruleFileStream, "The main clean target", "clean",
+ depends, commands, true);
+ commands.clear();
+ depends.clear();
+ depends.emplace_back("clean");
+ this->WriteMakeRule(ruleFileStream, "The main clean target", "clean/fast",
+ depends, commands, true);
+
+ // Write the preinstall rule.
+ recursiveTarget = cmStrCat(this->GetCurrentBinaryDirectory(), "/preinstall");
+ commands.clear();
+ depends.clear();
+ cmProp noall =
+ this->Makefile->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
+ if (cmIsOff(noall)) {
+ // Drive the build before installing.
+ depends.emplace_back("all");
+ } else if (regenerate) {
+ // At least make sure the build system is up to date.
+ depends.emplace_back("cmake_check_build_system");
+ }
+ commands.push_back(this->GetRecursiveMakeCall(mf2Dir, recursiveTarget));
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ this->GetCurrentBinaryDirectory());
+ this->WriteMakeRule(ruleFileStream, "Prepare targets for installation.",
+ "preinstall", depends, commands, true);
+ depends.clear();
+ this->WriteMakeRule(ruleFileStream, "Prepare targets for installation.",
+ "preinstall/fast", depends, commands, true);
+
+ if (regenerate) {
+ // write the depend rule, really a recompute depends rule
+ depends.clear();
+ commands.clear();
+ cmake* cm = this->GlobalGenerator->GetCMakeInstance();
+ if (cm->DoWriteGlobVerifyTarget()) {
+ std::string rescanRule =
+ cmStrCat("$(CMAKE_COMMAND) -P ",
+ this->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
+ cmOutputConverter::SHELL));
+ commands.push_back(rescanRule);
+ }
+ std::string cmakefileName = "CMakeFiles/Makefile.cmake";
+ {
+ std::string runRule = cmStrCat(
+ "$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) "
+ "--check-build-system ",
+ this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL),
+ " 1");
+ commands.push_back(std::move(runRule));
+ }
+ this->CreateCDCommand(commands, this->GetBinaryDirectory(),
+ this->GetCurrentBinaryDirectory());
+ this->WriteMakeRule(ruleFileStream, "clear depends", "depend", depends,
+ commands, true);
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf,
+ bool verbose)
+{
+ // Get the list of target files to check
+ cmProp infoDef = mf->GetDefinition("CMAKE_DEPEND_INFO_FILES");
+ if (!infoDef) {
+ return;
+ }
+ std::vector<std::string> files = cmExpandedList(*infoDef);
+
+ // Each depend information file corresponds to a target. Clear the
+ // dependencies for that target.
+ cmDepends clearer;
+ clearer.SetVerbose(verbose);
+ for (std::string const& file : files) {
+ auto snapshot = mf->GetState()->CreateBaseSnapshot();
+ cmMakefile lmf(mf->GetGlobalGenerator(), snapshot);
+ lmf.ReadListFile(file);
+
+ if (!lmf.GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES").empty()) {
+ std::string dir = cmSystemTools::GetFilenamePath(file);
+
+ // Clear the implicit dependency makefile.
+ std::string dependFile = dir + "/depend.make";
+ clearer.Clear(dependFile);
+
+ // Remove the internal dependency check file to force
+ // regeneration.
+ std::string internalDependFile = dir + "/depend.internal";
+ cmSystemTools::RemoveFile(internalDependFile);
+ }
+
+ auto depsFiles = lmf.GetSafeDefinition("CMAKE_DEPENDS_DEPENDENCY_FILES");
+ if (!depsFiles.empty()) {
+ auto dir = cmCMakePath(file).GetParentPath();
+ // Clear the implicit dependency makefile.
+ auto depFile = cmCMakePath(dir).Append("compiler_depend.make");
+ clearer.Clear(depFile.GenericString());
+
+ // Remove the internal dependency check file
+ auto internalDepFile =
+ cmCMakePath(dir).Append("compiler_depend.internal");
+ cmSystemTools::RemoveFile(internalDepFile.GenericString());
+
+ // Touch timestamp file to force dependencies regeneration
+ auto DepTimestamp = cmCMakePath(dir).Append("compiler_depend.ts");
+ cmSystemTools::Touch(DepTimestamp.GenericString(), true);
+
+ // clear the dependencies files generated by the compiler
+ std::vector<std::string> dependencies = cmExpandedList(depsFiles);
+ cmDependsCompiler depsManager;
+ depsManager.SetVerbose(verbose);
+ depsManager.ClearDependencies(dependencies);
+ }
+ }
+}
+
+void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo(
+ std::ostream& cmakefileStream, cmGeneratorTarget* target)
+{
+ // To enable dependencies filtering
+ cmakefileStream << "\n"
+ << "# Consider dependencies only in project.\n"
+ << "set(CMAKE_DEPENDS_IN_PROJECT_ONLY "
+ << (cmIsOn(this->Makefile->GetSafeDefinition(
+ "CMAKE_DEPENDS_IN_PROJECT_ONLY"))
+ ? "ON"
+ : "OFF")
+ << ")\n\n";
+
+ auto const& implicitLangs =
+ this->GetImplicitDepends(target, cmDependencyScannerKind::CMake);
+
+ // list the languages
+ cmakefileStream << "# The set of languages for which implicit "
+ "dependencies are needed:\n";
+ cmakefileStream << "set(CMAKE_DEPENDS_LANGUAGES\n";
+ for (auto const& implicitLang : implicitLangs) {
+ cmakefileStream << " \"" << implicitLang.first << "\"\n";
+ }
+ cmakefileStream << " )\n";
+
+ if (!implicitLangs.empty()) {
+ // now list the files for each language
+ cmakefileStream
+ << "# The set of files for implicit dependencies of each language:\n";
+ for (auto const& implicitLang : implicitLangs) {
+ const auto& lang = implicitLang.first;
+
+ cmakefileStream << "set(CMAKE_DEPENDS_CHECK_" << lang << "\n";
+ auto const& implicitPairs = implicitLang.second;
+
+ // for each file pair
+ for (auto const& implicitPair : implicitPairs) {
+ for (auto const& di : implicitPair.second) {
+ cmakefileStream << " \"" << di << "\" ";
+ cmakefileStream << "\"" << implicitPair.first << "\"\n";
+ }
+ }
+ cmakefileStream << " )\n";
+
+ // Tell the dependency scanner what compiler is used.
+ std::string cidVar = cmStrCat("CMAKE_", lang, "_COMPILER_ID");
+ cmProp cid = this->Makefile->GetDefinition(cidVar);
+ if (cmNonempty(cid)) {
+ cmakefileStream << "set(CMAKE_" << lang << "_COMPILER_ID \"" << *cid
+ << "\")\n";
+ }
+
+ if (lang == "Fortran") {
+ std::string smodSep =
+ this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP");
+ std::string smodExt =
+ this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT");
+ cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_SEP \"" << smodSep
+ << "\")\n";
+ cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_EXT \"" << smodExt
+ << "\")\n";
+ }
+
+ // Build a list of preprocessor definitions for the target.
+ std::set<std::string> defines;
+ this->GetTargetDefines(target, this->GetConfigName(), lang, defines);
+ if (!defines.empty()) {
+ /* clang-format off */
+ cmakefileStream
+ << "\n"
+ << "# Preprocessor definitions for this target.\n"
+ << "set(CMAKE_TARGET_DEFINITIONS_" << lang << "\n";
+ /* clang-format on */
+ for (std::string const& define : defines) {
+ cmakefileStream << " " << cmOutputConverter::EscapeForCMake(define)
+ << "\n";
+ }
+ cmakefileStream << " )\n";
+ }
+
+ // Target-specific include directories:
+ cmakefileStream << "\n"
+ << "# The include file search paths:\n";
+ cmakefileStream << "set(CMAKE_" << lang << "_TARGET_INCLUDE_PATH\n";
+ std::vector<std::string> includes;
+
+ this->GetIncludeDirectories(includes, target, lang,
+ this->GetConfigName());
+ std::string const& binaryDir = this->GetState()->GetBinaryDirectory();
+ if (this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY")) {
+ std::string const& sourceDir = this->GetState()->GetSourceDirectory();
+ cm::erase_if(includes, ::NotInProjectDir(sourceDir, binaryDir));
+ }
+ for (std::string const& include : includes) {
+ cmakefileStream << " \""
+ << this->MaybeConvertToRelativePath(binaryDir, include)
+ << "\"\n";
+ }
+ cmakefileStream << " )\n";
+ }
+
+ // Store include transform rule properties. Write the directory
+ // rules first because they may be overridden by later target rules.
+ std::vector<std::string> transformRules;
+ if (cmProp xform =
+ this->Makefile->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
+ cmExpandList(*xform, transformRules);
+ }
+ if (cmProp xform =
+ target->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
+ cmExpandList(*xform, transformRules);
+ }
+ if (!transformRules.empty()) {
+ cmakefileStream << "\nset(CMAKE_INCLUDE_TRANSFORMS\n";
+ for (std::string const& tr : transformRules) {
+ cmakefileStream << " " << cmOutputConverter::EscapeForCMake(tr)
+ << "\n";
+ }
+ cmakefileStream << " )\n";
+ }
+ }
+
+ auto const& compilerLangs =
+ this->GetImplicitDepends(target, cmDependencyScannerKind::Compiler);
+
+ // list the dependency files managed by the compiler
+ cmakefileStream << "\n# The set of dependency files which are needed:\n";
+ cmakefileStream << "set(CMAKE_DEPENDS_DEPENDENCY_FILES\n";
+ for (auto const& compilerLang : compilerLangs) {
+ auto const& compilerPairs = compilerLang.second;
+ if (compilerLang.first == "CUSTOM"_s) {
+ for (auto const& compilerPair : compilerPairs) {
+ for (auto const& src : compilerPair.second) {
+ cmakefileStream << R"( "" ")"
+ << this->MaybeConvertToRelativePath(
+ this->GetBinaryDirectory(), compilerPair.first)
+ << R"(" "custom" ")"
+ << this->MaybeConvertToRelativePath(
+ this->GetBinaryDirectory(), src)
+ << "\"\n";
+ }
+ }
+ } else {
+ auto depFormat = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", compilerLang.first, "_DEPFILE_FORMAT"));
+ for (auto const& compilerPair : compilerPairs) {
+ for (auto const& src : compilerPair.second) {
+ cmakefileStream << " \"" << src << "\" \""
+ << this->MaybeConvertToRelativePath(
+ this->GetBinaryDirectory(), compilerPair.first)
+ << "\" \"" << depFormat << "\" \""
+ << this->MaybeConvertToRelativePath(
+ this->GetBinaryDirectory(), compilerPair.first)
+ << ".d\"\n";
+ }
+ }
+ }
+ }
+ cmakefileStream << " )\n";
+}
+
+void cmLocalUnixMakefileGenerator3::WriteDisclaimer(std::ostream& os)
+{
+ os << "# CMAKE generated file: DO NOT EDIT!\n"
+ << "# Generated by \"" << this->GlobalGenerator->GetName() << "\""
+ << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
+ << cmVersion::GetMinorVersion() << "\n\n";
+}
+
+std::string cmLocalUnixMakefileGenerator3::GetRecursiveMakeCall(
+ const std::string& makefile, const std::string& tgt)
+{
+ // Call make on the given file.
+ std::string cmd = cmStrCat(
+ "$(MAKE) $(MAKESILENT) -f ",
+ this->ConvertToOutputFormat(makefile, cmOutputConverter::SHELL), ' ');
+
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ // Pass down verbosity level.
+ if (!gg->MakeSilentFlag.empty()) {
+ cmd += gg->MakeSilentFlag;
+ cmd += " ";
+ }
+
+ // Most unix makes will pass the command line flags to make down to
+ // sub-invoked makes via an environment variable. However, some
+ // makes do not support that, so you have to pass the flags
+ // explicitly.
+ if (gg->PassMakeflags) {
+ cmd += "-$(MAKEFLAGS) ";
+ }
+
+ // Add the target.
+ if (!tgt.empty()) {
+ // The make target is always relative to the top of the build tree.
+ std::string tgt2 =
+ this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), tgt);
+
+ // The target may have been written with windows paths.
+ cmSystemTools::ConvertToOutputSlashes(tgt2);
+
+ // Escape one extra time if the make tool requires it.
+ if (this->MakeCommandEscapeTargetTwice) {
+ tgt2 = this->EscapeForShell(tgt2, true, false);
+ }
+
+ // The target name is now a string that should be passed verbatim
+ // on the command line.
+ cmd += this->EscapeForShell(tgt2, true, false);
+ }
+ return cmd;
+}
+
+void cmLocalUnixMakefileGenerator3::WriteDivider(std::ostream& os)
+{
+ os << "#======================================"
+ "=======================================\n";
+}
+
+void cmLocalUnixMakefileGenerator3::WriteCMakeArgument(std::ostream& os,
+ const std::string& s)
+{
+ // Write the given string to the stream with escaping to get it back
+ // into CMake through the lexical scanner.
+ os << '"';
+ for (char c : s) {
+ if (c == '\\') {
+ os << "\\\\";
+ } else if (c == '"') {
+ os << "\\\"";
+ } else {
+ os << c;
+ }
+ }
+ os << '"';
+}
+
+std::string cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath(
+ const std::string& p, bool useWatcomQuote)
+{
+ // Split the path into its components.
+ std::vector<std::string> components;
+ cmSystemTools::SplitPath(p, components);
+
+ // Open the quoted result.
+ std::string result;
+ if (useWatcomQuote) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ result = "'";
+#else
+ result = "\"'";
+#endif
+ } else {
+ result = "\"";
+ }
+
+ // Return an empty path if there are no components.
+ if (!components.empty()) {
+ // Choose a slash direction and fix root component.
+ const char* slash = "/";
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (!cmSystemTools::GetForceUnixPaths()) {
+ slash = "\\";
+ for (char& i : components[0]) {
+ if (i == '/') {
+ i = '\\';
+ }
+ }
+ }
+#endif
+
+ // Begin the quoted result with the root component.
+ result += components[0];
+
+ if (components.size() > 1) {
+ // Now add the rest of the components separated by the proper slash
+ // direction for this platform.
+ auto compEnd = std::remove(components.begin() + 1, components.end() - 1,
+ std::string());
+ auto compStart = components.begin() + 1;
+ result += cmJoin(cmMakeRange(compStart, compEnd), slash);
+ // Only the last component can be empty to avoid double slashes.
+ result += slash;
+ result += components.back();
+ }
+ }
+
+ // Close the quoted result.
+ if (useWatcomQuote) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ result += "'";
+#else
+ result += "'\"";
+#endif
+ } else {
+ result += "\"";
+ }
+
+ return result;
+}
+
+std::string cmLocalUnixMakefileGenerator3::GetTargetDirectory(
+ cmGeneratorTarget const* target) const
+{
+ std::string dir = cmStrCat("CMakeFiles/", target->GetName());
+#if defined(__VMS)
+ dir += "_dir";
+#else
+ dir += ".dir";
+#endif
+ return dir;
+}
+
+cmLocalUnixMakefileGenerator3::ImplicitDependLanguageMap const&
+cmLocalUnixMakefileGenerator3::GetImplicitDepends(
+ const cmGeneratorTarget* tgt, cmDependencyScannerKind scanner)
+{
+ return this->ImplicitDepends[tgt->GetName()][scanner];
+}
+
+void cmLocalUnixMakefileGenerator3::AddImplicitDepends(
+ const cmGeneratorTarget* tgt, const std::string& lang,
+ const std::string& obj, const std::string& src,
+ cmDependencyScannerKind scanner)
+{
+ this->ImplicitDepends[tgt->GetName()][scanner][lang][obj].push_back(src);
+}
+
+void cmLocalUnixMakefileGenerator3::CreateCDCommand(
+ std::vector<std::string>& commands, std::string const& tgtDir,
+ std::string const& relDir)
+{
+ // do we need to cd?
+ if (tgtDir == relDir) {
+ return;
+ }
+
+ // In a Windows shell we must change drive letter too. The shell
+ // used by NMake and Borland make does not support "cd /d" so this
+ // feature simply cannot work with them (Borland make does not even
+ // support changing the drive letter with just "d:").
+ const char* cd_cmd = this->IsMinGWMake() ? "cd /d " : "cd ";
+
+ cmGlobalUnixMakefileGenerator3* gg =
+ static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+ if (!gg->UnixCD) {
+ // On Windows we must perform each step separately and then change
+ // back because the shell keeps the working directory between
+ // commands.
+ std::string cmd =
+ cmStrCat(cd_cmd, this->ConvertToOutputForExisting(tgtDir));
+ commands.insert(commands.begin(), cmd);
+
+ // Change back to the starting directory.
+ cmd = cmStrCat(cd_cmd, this->ConvertToOutputForExisting(relDir));
+ commands.push_back(std::move(cmd));
+ } else {
+ // On UNIX we must construct a single shell command to change
+ // directory and build because make resets the directory between
+ // each command.
+ std::string outputForExisting = this->ConvertToOutputForExisting(tgtDir);
+ std::string prefix = cd_cmd + outputForExisting + " && ";
+ std::transform(commands.begin(), commands.end(), commands.begin(),
+ [&prefix](std::string const& s) { return prefix + s; });
+ }
+}
diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h
new file mode 100644
index 0000000..14dd0ba
--- /dev/null
+++ b/Source/cmLocalUnixMakefileGenerator3.h
@@ -0,0 +1,306 @@
+/* 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 <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmDepends.h"
+#include "cmLocalCommonGenerator.h"
+#include "cmLocalGenerator.h"
+
+class cmCustomCommand;
+class cmCustomCommandGenerator;
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmMakefile;
+class cmSourceFile;
+
+/** \class cmLocalUnixMakefileGenerator3
+ * \brief Write a LocalUnix makefiles.
+ *
+ * cmLocalUnixMakefileGenerator3 produces a LocalUnix makefile from its
+ * member Makefile.
+ */
+class cmLocalUnixMakefileGenerator3 : public cmLocalCommonGenerator
+{
+public:
+ cmLocalUnixMakefileGenerator3(cmGlobalGenerator* gg, cmMakefile* mf);
+ ~cmLocalUnixMakefileGenerator3() override;
+
+ std::string GetConfigName() const;
+
+ void ComputeHomeRelativeOutputPath() override;
+
+ /**
+ * Generate the makefile for this directory.
+ */
+ void Generate() override;
+
+ // this returns the relative path between the HomeOutputDirectory and this
+ // local generators StartOutputDirectory
+ const std::string& GetHomeRelativeOutputPath();
+
+ /**
+ * Convert a file path to a Makefile target or dependency with
+ * escaping and quoting suitable for the generator's make tool.
+ */
+ std::string ConvertToMakefilePath(std::string const& path) const;
+
+ // Write out a make rule
+ void WriteMakeRule(std::ostream& os, const char* comment,
+ const std::string& target,
+ const std::vector<std::string>& depends,
+ const std::vector<std::string>& commands, bool symbolic,
+ bool in_help = false);
+
+ // write the main variables used by the makefiles
+ void WriteMakeVariables(std::ostream& makefileStream);
+
+ /**
+ * Set max makefile variable size, default is 0 which means unlimited.
+ */
+ void SetMakefileVariableSize(int s) { this->MakefileVariableSize = s; }
+
+ /**
+ * Set whether passing a make target on a command line requires an
+ * extra level of escapes.
+ */
+ void SetMakeCommandEscapeTargetTwice(bool b)
+ {
+ this->MakeCommandEscapeTargetTwice = b;
+ }
+
+ /**
+ * Set whether the Borland curly brace command line hack should be
+ * applied.
+ */
+ void SetBorlandMakeCurlyHack(bool b) { this->BorlandMakeCurlyHack = b; }
+
+ // used in writing out Cmake files such as WriteDirectoryInformation
+ static void WriteCMakeArgument(std::ostream& os, const std::string& s);
+
+ /** creates the common disclaimer text at the top of each makefile */
+ void WriteDisclaimer(std::ostream& os);
+
+ // write a comment line #====... in the stream
+ void WriteDivider(std::ostream& os);
+
+ /** used to create a recursive make call */
+ std::string GetRecursiveMakeCall(const std::string& makefile,
+ const std::string& tgt);
+
+ // append flags to a string
+ void AppendFlags(std::string& flags,
+ const std::string& newFlags) const override;
+ using cmLocalCommonGenerator::AppendFlags;
+
+ // append an echo command
+ enum EchoColor
+ {
+ EchoNormal,
+ EchoDepend,
+ EchoBuild,
+ EchoLink,
+ EchoGenerate,
+ EchoGlobal
+ };
+ struct EchoProgress
+ {
+ std::string Dir;
+ std::string Arg;
+ };
+ void AppendEcho(std::vector<std::string>& commands, std::string const& text,
+ EchoColor color = EchoNormal, EchoProgress const* = nullptr);
+
+ /** Get whether the makefile is to have color. */
+ bool GetColorMakefile() const { return this->ColorMakefile; }
+
+ std::string GetTargetDirectory(
+ cmGeneratorTarget const* target) const override;
+
+ // create a command that cds to the start dir then runs the commands
+ void CreateCDCommand(std::vector<std::string>& commands,
+ std::string const& targetDir,
+ std::string const& relDir);
+
+ static std::string ConvertToQuotedOutputPath(const std::string& p,
+ bool useWatcomQuote);
+
+ std::string CreateMakeVariable(const std::string& sin,
+ const std::string& s2in);
+
+ /** Called from command-line hook to bring dependencies up to date
+ for a target. */
+ bool UpdateDependencies(const std::string& tgtInfo, bool verbose,
+ bool color) override;
+
+ /** Called from command-line hook to clear dependencies. */
+ void ClearDependencies(cmMakefile* mf, bool verbose) override;
+
+ /** write some extra rules such as make test etc */
+ void WriteSpecialTargetsTop(std::ostream& makefileStream);
+ void WriteSpecialTargetsBottom(std::ostream& makefileStream);
+
+ std::string GetRelativeTargetDirectory(
+ cmGeneratorTarget const* target) const;
+
+ // File pairs for implicit dependency scanning. The key of the map
+ // is the depender and the value is the explicit dependee.
+ using ImplicitDependFileMap = cmDepends::DependencyMap;
+ using ImplicitDependLanguageMap =
+ std::map<std::string, ImplicitDependFileMap>;
+ using ImplicitDependScannerMap =
+ std::map<cmDependencyScannerKind, ImplicitDependLanguageMap>;
+ using ImplicitDependTargetMap =
+ std::map<std::string, ImplicitDependScannerMap>;
+ ImplicitDependLanguageMap const& GetImplicitDepends(
+ cmGeneratorTarget const* tgt,
+ cmDependencyScannerKind scanner = cmDependencyScannerKind::CMake);
+
+ void AddImplicitDepends(
+ cmGeneratorTarget const* tgt, const std::string& lang,
+ const std::string& obj, const std::string& src,
+ cmDependencyScannerKind scanner = cmDependencyScannerKind::CMake);
+
+ // write the target rules for the local Makefile into the stream
+ void WriteLocalAllRules(std::ostream& ruleFileStream);
+
+ std::vector<std::string> const& GetLocalHelp() { return this->LocalHelp; }
+
+ /** Get whether to create rules to generate preprocessed and
+ assembly sources. This could be converted to a variable lookup
+ later. */
+ bool GetCreatePreprocessedSourceRules() const
+ {
+ return !this->SkipPreprocessedSourceRules;
+ }
+ bool GetCreateAssemblySourceRules() const
+ {
+ return !this->SkipAssemblySourceRules;
+ }
+
+ // Fill the vector with the target names for the object files,
+ // preprocessed files and assembly files. Currently only used by the
+ // Eclipse generator.
+ void GetIndividualFileTargets(std::vector<std::string>& targets);
+
+protected:
+ void WriteLocalMakefile();
+
+ // write the target rules for the local Makefile into the stream
+ void WriteLocalMakefileTargets(std::ostream& ruleFileStream,
+ std::set<std::string>& emitted);
+
+ // this method Writes the Directory information files
+ void WriteDirectoryInformationFile();
+
+ // write the depend info
+ void WriteDependLanguageInfo(std::ostream& cmakefileStream,
+ cmGeneratorTarget* tgt);
+
+ // this converts a file name that is relative to the StartOuputDirectory
+ // into a full path
+ std::string ConvertToFullPath(const std::string& localPath);
+
+ void WriteConvenienceRule(std::ostream& ruleFileStream,
+ const std::string& realTarget,
+ const std::string& helpTarget);
+
+ void AppendRuleDepend(std::vector<std::string>& depends,
+ const char* ruleFileName);
+ void AppendRuleDepends(std::vector<std::string>& depends,
+ std::vector<std::string> const& ruleFiles);
+ void AppendCustomDepends(std::vector<std::string>& depends,
+ const std::vector<cmCustomCommand>& ccs);
+ void AppendCustomDepend(std::vector<std::string>& depends,
+ cmCustomCommandGenerator const& cc);
+ void AppendCustomCommands(std::vector<std::string>& commands,
+ const std::vector<cmCustomCommand>& ccs,
+ cmGeneratorTarget* target,
+ std::string const& relative);
+ void AppendCustomCommand(std::vector<std::string>& commands,
+ cmCustomCommandGenerator const& ccg,
+ cmGeneratorTarget* target,
+ std::string const& relative,
+ bool echo_comment = false,
+ std::ostream* content = nullptr);
+ void AppendCleanCommand(std::vector<std::string>& commands,
+ const std::set<std::string>& files,
+ cmGeneratorTarget* target,
+ const char* filename = nullptr);
+ void AppendDirectoryCleanCommand(std::vector<std::string>& commands);
+
+ // Helper methods for dependency updates.
+ bool ScanDependencies(std::string const& targetDir,
+ std::string const& dependFile,
+ std::string const& internalDependFile,
+ cmDepends::DependencyMap& validDeps);
+ void CheckMultipleOutputs(bool verbose);
+
+private:
+ std::string MaybeConvertWatcomShellCommand(std::string const& cmd);
+
+ friend class cmMakefileTargetGenerator;
+ friend class cmMakefileExecutableTargetGenerator;
+ friend class cmMakefileLibraryTargetGenerator;
+ friend class cmMakefileUtilityTargetGenerator;
+ friend class cmGlobalUnixMakefileGenerator3;
+
+ ImplicitDependTargetMap ImplicitDepends;
+
+ std::string HomeRelativeOutputPath;
+
+ struct LocalObjectEntry
+ {
+ cmGeneratorTarget* Target = nullptr;
+ std::string Language;
+ LocalObjectEntry() = default;
+ LocalObjectEntry(cmGeneratorTarget* t, std::string lang)
+ : Target(t)
+ , Language(std::move(lang))
+ {
+ }
+ };
+ struct LocalObjectInfo : public std::vector<LocalObjectEntry>
+ {
+ bool HasSourceExtension = false;
+ bool HasPreprocessRule = false;
+ bool HasAssembleRule = false;
+ };
+ void GetLocalObjectFiles(
+ std::map<std::string, LocalObjectInfo>& localObjectFiles);
+
+ void WriteObjectConvenienceRule(std::ostream& ruleFileStream,
+ const char* comment,
+ const std::string& output,
+ LocalObjectInfo const& info);
+
+ std::vector<std::string> LocalHelp;
+
+ /* does the work for each target */
+ std::map<std::string, std::string> MakeVariableMap;
+ std::map<std::string, std::string> ShortMakeVariableMap;
+
+ int MakefileVariableSize;
+ bool MakeCommandEscapeTargetTwice;
+ bool BorlandMakeCurlyHack;
+ bool ColorMakefile;
+ bool SkipPreprocessedSourceRules;
+ bool SkipAssemblySourceRules;
+
+ std::set<cmSourceFile const*>& GetCommandsVisited(
+ cmGeneratorTarget const* target)
+ {
+ return this->CommandsVisited[target];
+ };
+
+ std::map<cmGeneratorTarget const*, std::set<cmSourceFile const*>>
+ CommandsVisited;
+};
diff --git a/Source/cmLocalVisualStudio10Generator.cxx b/Source/cmLocalVisualStudio10Generator.cxx
new file mode 100644
index 0000000..3ed49a0
--- /dev/null
+++ b/Source/cmLocalVisualStudio10Generator.cxx
@@ -0,0 +1,103 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmLocalVisualStudio10Generator.h"
+
+#include <cmext/algorithm>
+
+#include <cm3p/expat.h>
+
+#include "cmAlgorithms.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalVisualStudio10Generator.h"
+#include "cmMakefile.h"
+#include "cmVisualStudio10TargetGenerator.h"
+#include "cmXMLParser.h"
+#include "cmake.h"
+
+class cmVS10XMLParser : public cmXMLParser
+{
+public:
+ virtual void EndElement(const std::string& /* name */) {}
+ virtual void CharacterDataHandler(const char* data, int length)
+ {
+ if (this->DoGUID) {
+ if (data[0] == '{') {
+ // remove surrounding curly brackets
+ this->GUID.assign(data + 1, length - 2);
+ } else {
+ this->GUID.assign(data, length);
+ }
+ this->DoGUID = false;
+ }
+ }
+ virtual void StartElement(const std::string& name, const char**)
+ {
+ // once the GUID is found do nothing
+ if (!this->GUID.empty()) {
+ return;
+ }
+ if ("ProjectGUID" == name || "ProjectGuid" == name) {
+ this->DoGUID = true;
+ }
+ }
+ int InitializeParser()
+ {
+ this->DoGUID = false;
+ int ret = cmXMLParser::InitializeParser();
+ if (ret == 0) {
+ return ret;
+ }
+ // visual studio projects have a strange encoding, but it is
+ // really utf-8
+ XML_SetEncoding(static_cast<XML_Parser>(this->Parser), "utf-8");
+ return 1;
+ }
+ std::string GUID;
+ bool DoGUID;
+};
+
+cmLocalVisualStudio10Generator::cmLocalVisualStudio10Generator(
+ cmGlobalGenerator* gg, cmMakefile* mf)
+ : cmLocalVisualStudio7Generator(gg, mf)
+{
+}
+
+cmLocalVisualStudio10Generator::~cmLocalVisualStudio10Generator()
+{
+}
+
+void cmLocalVisualStudio10Generator::GenerateTarget(cmGeneratorTarget* target)
+{
+ if (static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator)
+ ->TargetIsFortranOnly(target)) {
+ this->cmLocalVisualStudio7Generator::GenerateTarget(target);
+ } else {
+ cmVisualStudio10TargetGenerator tg(
+ target,
+ static_cast<cmGlobalVisualStudio10Generator*>(
+ this->GetGlobalGenerator()));
+ tg.Generate();
+ }
+}
+
+void cmLocalVisualStudio10Generator::ReadAndStoreExternalGUID(
+ const std::string& name, const char* path)
+{
+ cmVS10XMLParser parser;
+ parser.ParseFile(path);
+
+ // if we can not find a GUID then we will generate one later
+ if (parser.GUID.empty()) {
+ return;
+ }
+
+ std::string guidStoreName = cmStrCat(name, "_GUID_CMAKE");
+ // save the GUID in the cache
+ this->GlobalGenerator->GetCMakeInstance()->AddCacheEntry(
+ guidStoreName, parser.GUID.c_str(), "Stored GUID", cmStateEnums::INTERNAL);
+}
+
+const char* cmLocalVisualStudio10Generator::ReportErrorLabel() const
+{
+ return ":VCEnd";
+}
diff --git a/Source/cmLocalVisualStudio10Generator.h b/Source/cmLocalVisualStudio10Generator.h
new file mode 100644
index 0000000..45ee082
--- /dev/null
+++ b/Source/cmLocalVisualStudio10Generator.h
@@ -0,0 +1,37 @@
+/* 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 <string>
+
+#include "cmLocalVisualStudio7Generator.h"
+
+class cmGlobalGenerator;
+class cmMakefile;
+
+/** \class cmLocalVisualStudio10Generator
+ * \brief Write Visual Studio 10 project files.
+ *
+ * cmLocalVisualStudio10Generator produces a Visual Studio 10 project
+ * file for each target in its directory.
+ */
+class cmLocalVisualStudio10Generator : public cmLocalVisualStudio7Generator
+{
+public:
+ //! Set cache only and recurse to false by default.
+ cmLocalVisualStudio10Generator(cmGlobalGenerator* gg, cmMakefile* mf);
+
+ virtual ~cmLocalVisualStudio10Generator();
+
+ void ReadAndStoreExternalGUID(const std::string& name,
+ const char* path) override;
+
+protected:
+ const char* ReportErrorLabel() const override;
+ bool CustomCommandUseLocal() const override { return true; }
+
+private:
+ void GenerateTarget(cmGeneratorTarget* target) override;
+};
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
new file mode 100644
index 0000000..a3940ea
--- /dev/null
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -0,0 +1,2172 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmLocalVisualStudio7Generator.h"
+
+#include <cm/memory>
+#include <cmext/algorithm>
+
+#include <windows.h>
+
+#include <cm3p/expat.h>
+#include <ctype.h> // for isspace
+
+#include "cmComputeLinkInformation.h"
+#include "cmCustomCommand.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalVisualStudio7Generator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include "cmake.h"
+
+static bool cmLVS7G_IsFAT(const char* dir);
+
+class cmLocalVisualStudio7GeneratorInternals
+{
+public:
+ cmLocalVisualStudio7GeneratorInternals(cmLocalVisualStudio7Generator* e)
+ : LocalGenerator(e)
+ {
+ }
+ using ItemVector = cmComputeLinkInformation::ItemVector;
+ void OutputLibraries(std::ostream& fout, ItemVector const& libs);
+ void OutputObjects(std::ostream& fout, cmGeneratorTarget* t,
+ std::string const& config, const char* isep = 0);
+
+private:
+ cmLocalVisualStudio7Generator* LocalGenerator;
+};
+
+class cmLocalVisualStudio7Generator::AllConfigSources
+{
+public:
+ std::vector<cmGeneratorTarget::AllConfigSource> Sources;
+ std::map<cmSourceFile const*, size_t> Index;
+};
+
+extern cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[];
+
+cmLocalVisualStudio7Generator::cmLocalVisualStudio7Generator(
+ cmGlobalGenerator* gg, cmMakefile* mf)
+ : cmLocalVisualStudioGenerator(gg, mf)
+ , Internal(cm::make_unique<cmLocalVisualStudio7GeneratorInternals>(this))
+{
+}
+
+cmLocalVisualStudio7Generator::~cmLocalVisualStudio7Generator() = default;
+
+void cmLocalVisualStudio7Generator::AddHelperCommands()
+{
+ // Now create GUIDs for targets
+ const auto& tgts = this->GetGeneratorTargets();
+ for (const auto& l : tgts) {
+ if (!l->IsInBuildSystem()) {
+ continue;
+ }
+ cmProp path = l->GetProperty("EXTERNAL_MSPROJECT");
+ if (path) {
+ this->ReadAndStoreExternalGUID(l->GetName(), path->c_str());
+ }
+ }
+
+ this->FixGlobalTargets();
+}
+
+void cmLocalVisualStudio7Generator::Generate()
+{
+ // Create the project file for each target.
+ for (cmGeneratorTarget* gt :
+ this->GlobalGenerator->GetLocalGeneratorTargetsInOrder(this)) {
+ if (!gt->IsInBuildSystem() || gt->GetProperty("EXTERNAL_MSPROJECT")) {
+ continue;
+ }
+
+ auto& gtVisited = this->GetSourcesVisited(gt);
+ auto& deps = this->GlobalGenerator->GetTargetDirectDepends(gt);
+ for (auto& d : deps) {
+ // Take the union of visited source files of custom commands
+ auto depVisited = this->GetSourcesVisited(d);
+ gtVisited.insert(depVisited.begin(), depVisited.end());
+ }
+
+ this->GenerateTarget(gt);
+ }
+
+ this->WriteStampFiles();
+}
+
+void cmLocalVisualStudio7Generator::FixGlobalTargets()
+{
+ // Visual Studio .NET 2003 Service Pack 1 will not run post-build
+ // commands for targets in which no sources are built. Add dummy
+ // rules to force these targets to build.
+ const auto& tgts = this->GetGeneratorTargets();
+ for (auto& l : tgts) {
+ if (l->GetType() == cmStateEnums::GLOBAL_TARGET) {
+ std::vector<std::string> no_depends;
+ cmCustomCommandLines force_commands =
+ cmMakeSingleCommandLine({ "cd", "." });
+ std::string no_main_dependency;
+ std::string force = cmStrCat(this->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/", l->GetName(), "_force");
+ if (cmSourceFile* sf =
+ this->Makefile->GetOrCreateGeneratedSource(force)) {
+ sf->SetProperty("SYMBOLIC", "1");
+ }
+ if (cmSourceFile* file = this->AddCustomCommandToOutput(
+ force, no_depends, no_main_dependency, force_commands, " ",
+ nullptr, cmPolicies::NEW, true)) {
+ l->AddSource(file->ResolveFullPath());
+ }
+ }
+ }
+}
+
+void cmLocalVisualStudio7Generator::WriteStampFiles()
+{
+ // Touch a timestamp file used to determine when the project file is
+ // out of date.
+ std::string stampName =
+ cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles");
+ cmSystemTools::MakeDirectory(stampName);
+ stampName += "/generate.stamp";
+ cmsys::ofstream stamp(stampName.c_str());
+ stamp << "# CMake generation timestamp file for this directory.\n";
+
+ // Create a helper file so CMake can determine when it is run
+ // through the rule created by CreateVCProjBuildRule whether it
+ // really needs to regenerate the project. This file lists its own
+ // dependencies. If any file listed in it is newer than itself then
+ // CMake must rerun. Otherwise the project files are up to date and
+ // the stamp file can just be touched.
+ std::string depName = cmStrCat(stampName, ".depend");
+ cmsys::ofstream depFile(depName.c_str());
+ depFile << "# CMake generation dependency list for this directory.\n";
+
+ std::vector<std::string> listFiles(this->Makefile->GetListFiles());
+ cmake* cm = this->GlobalGenerator->GetCMakeInstance();
+ if (cm->DoWriteGlobVerifyTarget()) {
+ listFiles.push_back(cm->GetGlobVerifyStamp());
+ }
+
+ // Sort the list of input files and remove duplicates.
+ std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>());
+ std::vector<std::string>::iterator new_end =
+ std::unique(listFiles.begin(), listFiles.end());
+ listFiles.erase(new_end, listFiles.end());
+
+ for (const std::string& lf : listFiles) {
+ depFile << lf << "\n";
+ }
+}
+
+void cmLocalVisualStudio7Generator::GenerateTarget(cmGeneratorTarget* target)
+{
+ std::string const& lname = target->GetName();
+ cmGlobalVisualStudioGenerator* gg =
+ static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator);
+ this->FortranProject = gg->TargetIsFortranOnly(target);
+ this->WindowsCEProject = gg->TargetsWindowsCE();
+
+ // Intel Fortran for VS10 uses VS9 format ".vfproj" files.
+ cmGlobalVisualStudioGenerator::VSVersion realVersion = gg->GetVersion();
+ if (this->FortranProject &&
+ gg->GetVersion() >= cmGlobalVisualStudioGenerator::VS10) {
+ gg->SetVersion(cmGlobalVisualStudioGenerator::VS9);
+ }
+
+ // add to the list of projects
+ target->Target->SetProperty("GENERATOR_FILE_NAME", lname);
+ // create the dsp.cmake file
+ std::string fname;
+ fname = cmStrCat(this->GetCurrentBinaryDirectory(), '/', lname);
+ if (this->FortranProject) {
+ fname += ".vfproj";
+ } else {
+ fname += ".vcproj";
+ }
+
+ // Generate the project file and replace it atomically with
+ // copy-if-different. We use a separate timestamp so that the IDE
+ // does not reload project files unnecessarily.
+ cmGeneratedFileStream fout(fname.c_str());
+ fout.SetCopyIfDifferent(true);
+ this->WriteVCProjFile(fout, lname, target);
+ if (fout.Close()) {
+ this->GlobalGenerator->FileReplacedDuringGenerate(fname);
+ }
+
+ gg->SetVersion(realVersion);
+}
+
+cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule()
+{
+ if (this->GlobalGenerator->GlobalSettingIsOn(
+ "CMAKE_SUPPRESS_REGENERATION")) {
+ return nullptr;
+ }
+
+ std::string makefileIn =
+ cmStrCat(this->GetCurrentSourceDirectory(), "/CMakeLists.txt");
+ if (cmSourceFile* file = this->Makefile->GetSource(makefileIn)) {
+ if (file->GetCustomCommand()) {
+ return file;
+ }
+ }
+ if (!cmSystemTools::FileExists(makefileIn)) {
+ return nullptr;
+ }
+
+ std::vector<std::string> listFiles = this->Makefile->GetListFiles();
+ cmake* cm = this->GlobalGenerator->GetCMakeInstance();
+ if (cm->DoWriteGlobVerifyTarget()) {
+ listFiles.push_back(cm->GetGlobVerifyStamp());
+ }
+
+ // Sort the list of input files and remove duplicates.
+ std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>());
+ std::vector<std::string>::iterator new_end =
+ std::unique(listFiles.begin(), listFiles.end());
+ listFiles.erase(new_end, listFiles.end());
+
+ std::string argS = cmStrCat("-S", this->GetSourceDirectory());
+ std::string argB = cmStrCat("-B", this->GetBinaryDirectory());
+ std::string stampName =
+ cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/generate.stamp");
+ bool stdPipesUTF8 = true;
+ cmCustomCommandLines commandLines =
+ cmMakeSingleCommandLine({ cmSystemTools::GetCMakeCommand(), argS, argB,
+ "--check-stamp-file", stampName });
+ std::string comment = cmStrCat("Building Custom Rule ", makefileIn);
+ const char* no_working_directory = nullptr;
+ this->AddCustomCommandToOutput(stampName, listFiles, makefileIn,
+ commandLines, comment.c_str(),
+ no_working_directory, cmPolicies::NEW, true,
+ false, false, false, "", "", stdPipesUTF8);
+ if (cmSourceFile* file = this->Makefile->GetSource(makefileIn)) {
+ // Finalize the source file path now since we're adding this after
+ // the generator validated all project-named sources.
+ file->ResolveFullPath();
+ return file;
+ } else {
+ cmSystemTools::Error("Error adding rule for " + makefileIn);
+ return nullptr;
+ }
+}
+
+void cmLocalVisualStudio7Generator::WriteConfigurations(
+ std::ostream& fout, std::vector<std::string> const& configs,
+ const std::string& libName, cmGeneratorTarget* target)
+{
+ fout << "\t<Configurations>\n";
+ for (std::string const& config : configs) {
+ this->WriteConfiguration(fout, config, libName, target);
+ }
+ fout << "\t</Configurations>\n";
+}
+cmVS7FlagTable cmLocalVisualStudio7GeneratorFortranFlagTable[] = {
+ { "Preprocess", "fpp", "Run Preprocessor on files", "preprocessYes", 0 },
+ { "Preprocess", "nofpp", "Run Preprocessor on files", "preprocessNo", 0 },
+ { "SuppressStartupBanner", "nologo", "SuppressStartupBanner", "true", 0 },
+ { "SourceFileFormat", "fixed", "Use Fixed Format", "fileFormatFixed", 0 },
+ { "SourceFileFormat", "free", "Use Free Format", "fileFormatFree", 0 },
+ { "DebugInformationFormat", "debug:full", "full debug", "debugEnabled", 0 },
+ { "DebugInformationFormat", "debug:minimal", "line numbers",
+ "debugLineInfoOnly", 0 },
+ { "Optimization", "Od", "disable optimization", "optimizeDisabled", 0 },
+ { "Optimization", "O1", "min space", "optimizeMinSpace", 0 },
+ { "Optimization", "O3", "full optimize", "optimizeFull", 0 },
+ { "GlobalOptimizations", "Og", "global optimize", "true", 0 },
+ { "InlineFunctionExpansion", "Ob0", "", "expandDisable", 0 },
+ { "InlineFunctionExpansion", "Ob1", "", "expandOnlyInline", 0 },
+ { "FavorSizeOrSpeed", "Os", "", "favorSize", 0 },
+ { "OmitFramePointers", "Oy-", "", "false", 0 },
+ { "OptimizeForProcessor", "GB", "", "procOptimizeBlended", 0 },
+ { "OptimizeForProcessor", "G5", "", "procOptimizePentium", 0 },
+ { "OptimizeForProcessor", "G6", "", "procOptimizePentiumProThruIII", 0 },
+ { "UseProcessorExtensions", "QzxK", "", "codeForStreamingSIMD", 0 },
+ { "OptimizeForProcessor", "QaxN", "", "codeForPentium4", 0 },
+ { "OptimizeForProcessor", "QaxB", "", "codeForPentiumM", 0 },
+ { "OptimizeForProcessor", "QaxP", "", "codeForCodeNamedPrescott", 0 },
+ { "OptimizeForProcessor", "QaxT", "", "codeForCore2Duo", 0 },
+ { "OptimizeForProcessor", "QxK", "", "codeExclusivelyStreamingSIMD", 0 },
+ { "OptimizeForProcessor", "QxN", "", "codeExclusivelyPentium4", 0 },
+ { "OptimizeForProcessor", "QxB", "", "codeExclusivelyPentiumM", 0 },
+ { "OptimizeForProcessor", "QxP", "", "codeExclusivelyCodeNamedPrescott", 0 },
+ { "OptimizeForProcessor", "QxT", "", "codeExclusivelyCore2Duo", 0 },
+ { "OptimizeForProcessor", "QxO", "", "codeExclusivelyCore2StreamingSIMD",
+ 0 },
+ { "OptimizeForProcessor", "QxS", "", "codeExclusivelyCore2StreamingSIMD4",
+ 0 },
+ { "OpenMP", "Qopenmp", "", "OpenMPParallelCode", 0 },
+ { "OpenMP", "Qopenmp-stubs", "", "OpenMPSequentialCode", 0 },
+ { "Traceback", "traceback", "", "true", 0 },
+ { "Traceback", "notraceback", "", "false", 0 },
+ { "FloatingPointExceptionHandling", "fpe:0", "", "fpe0", 0 },
+ { "FloatingPointExceptionHandling", "fpe:1", "", "fpe1", 0 },
+ { "FloatingPointExceptionHandling", "fpe:3", "", "fpe3", 0 },
+
+ { "MultiProcessorCompilation", "MP", "", "true",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "ProcessorNumber", "MP", "Multi-processor Compilation", "",
+ cmVS7FlagTable::UserValueRequired },
+
+ { "ModulePath", "module:", "", "", cmVS7FlagTable::UserValueRequired },
+ { "LoopUnrolling", "Qunroll:", "", "", cmVS7FlagTable::UserValueRequired },
+ { "AutoParallelThreshold", "Qpar-threshold:", "", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "HeapArrays", "heap-arrays:", "", "", cmVS7FlagTable::UserValueRequired },
+ { "ObjectText", "bintext:", "", "", cmVS7FlagTable::UserValueRequired },
+ { "Parallelization", "Qparallel", "", "true", 0 },
+ { "PrefetchInsertion", "Qprefetch-", "", "false", 0 },
+ { "BufferedIO", "assume:buffered_io", "", "true", 0 },
+ { "CallingConvention", "iface:stdcall", "", "callConventionStdCall", 0 },
+ { "CallingConvention", "iface:cref", "", "callConventionCRef", 0 },
+ { "CallingConvention", "iface:stdref", "", "callConventionStdRef", 0 },
+ { "CallingConvention", "iface:stdcall", "", "callConventionStdCall", 0 },
+ { "CallingConvention", "iface:cvf", "", "callConventionCVF", 0 },
+ { "EnableRecursion", "recursive", "", "true", 0 },
+ { "ReentrantCode", "reentrancy", "", "true", 0 },
+ // done up to Language
+ { "", "", "", "", 0 }
+};
+// fill the table here currently the comment field is not used for
+// anything other than documentation NOTE: Make sure the longer
+// commandFlag comes FIRST!
+cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[] = {
+ // option flags (some flags map to the same option)
+ { "BasicRuntimeChecks", "GZ", "Stack frame checks", "1", 0 },
+ { "BasicRuntimeChecks", "RTCsu", "Both stack and uninitialized checks", "3",
+ 0 },
+ { "BasicRuntimeChecks", "RTCs", "Stack frame checks", "1", 0 },
+ { "BasicRuntimeChecks", "RTCu", "Uninitialized Variables ", "2", 0 },
+ { "BasicRuntimeChecks", "RTC1", "Both stack and uninitialized checks", "3",
+ 0 },
+ { "DebugInformationFormat", "Z7", "debug format", "1", 0 },
+ { "DebugInformationFormat", "Zd", "debug format", "2", 0 },
+ { "DebugInformationFormat", "Zi", "debug format", "3", 0 },
+ { "DebugInformationFormat", "ZI", "debug format", "4", 0 },
+ { "EnableEnhancedInstructionSet", "arch:SSE2", "Use sse2 instructions", "2",
+ 0 },
+ { "EnableEnhancedInstructionSet", "arch:SSE", "Use sse instructions", "1",
+ 0 },
+ { "FloatingPointModel", "fp:precise", "Use precise floating point model",
+ "0", 0 },
+ { "FloatingPointModel", "fp:strict", "Use strict floating point model", "1",
+ 0 },
+ { "FloatingPointModel", "fp:fast", "Use fast floating point model", "2", 0 },
+ { "FavorSizeOrSpeed", "Ot", "Favor fast code", "1", 0 },
+ { "FavorSizeOrSpeed", "Os", "Favor small code", "2", 0 },
+ { "CompileAs", "TC", "Compile as c code", "1", 0 },
+ { "CompileAs", "TP", "Compile as c++ code", "2", 0 },
+ { "Optimization", "Od", "Non Debug", "0", 0 },
+ { "Optimization", "O1", "Min Size", "1", 0 },
+ { "Optimization", "O2", "Max Speed", "2", 0 },
+ { "Optimization", "Ox", "Max Optimization", "3", 0 },
+ { "OptimizeForProcessor", "GB", "Blended processor mode", "0", 0 },
+ { "OptimizeForProcessor", "G5", "Pentium", "1", 0 },
+ { "OptimizeForProcessor", "G6", "PPro PII PIII", "2", 0 },
+ { "OptimizeForProcessor", "G7", "Pentium 4 or Athlon", "3", 0 },
+ { "InlineFunctionExpansion", "Ob0", "no inlines", "0", 0 },
+ { "InlineFunctionExpansion", "Ob1", "when inline keyword", "1", 0 },
+ { "InlineFunctionExpansion", "Ob2", "any time you can inline", "2", 0 },
+ { "RuntimeLibrary", "MTd", "Multithreaded debug", "1", 0 },
+ { "RuntimeLibrary", "MT", "Multithreaded", "0", 0 },
+ { "RuntimeLibrary", "MDd", "Multithreaded dll debug", "3", 0 },
+ { "RuntimeLibrary", "MD", "Multithreaded dll", "2", 0 },
+ { "RuntimeLibrary", "MLd", "Single Thread debug", "5", 0 },
+ { "RuntimeLibrary", "ML", "Single Thread", "4", 0 },
+ { "StructMemberAlignment", "Zp16", "struct align 16 byte ", "5", 0 },
+ { "StructMemberAlignment", "Zp1", "struct align 1 byte ", "1", 0 },
+ { "StructMemberAlignment", "Zp2", "struct align 2 byte ", "2", 0 },
+ { "StructMemberAlignment", "Zp4", "struct align 4 byte ", "3", 0 },
+ { "StructMemberAlignment", "Zp8", "struct align 8 byte ", "4", 0 },
+ { "WarningLevel", "W0", "Warning level", "0", 0 },
+ { "WarningLevel", "W1", "Warning level", "1", 0 },
+ { "WarningLevel", "W2", "Warning level", "2", 0 },
+ { "WarningLevel", "W3", "Warning level", "3", 0 },
+ { "WarningLevel", "W4", "Warning level", "4", 0 },
+ { "DisableSpecificWarnings", "wd", "Disable specific warnings", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+
+ // Precompiled header and related options. Note that the
+ // UsePrecompiledHeader entries are marked as "Continue" so that the
+ // corresponding PrecompiledHeaderThrough entry can be found.
+ { "UsePrecompiledHeader", "Yc", "Create Precompiled Header", "1",
+ cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
+ { "PrecompiledHeaderThrough", "Yc", "Precompiled Header Name", "",
+ cmVS7FlagTable::UserValueRequired },
+ { "PrecompiledHeaderFile", "Fp", "Generated Precompiled Header", "",
+ cmVS7FlagTable::UserValue },
+ // The YX and Yu options are in a per-global-generator table because
+ // their values differ based on the VS IDE version.
+ { "ForcedIncludeFiles", "FI", "Forced include files", "",
+ cmVS7FlagTable::UserValueRequired | cmVS7FlagTable::SemicolonAppendable },
+
+ { "AssemblerListingLocation", "Fa", "ASM List Location", "",
+ cmVS7FlagTable::UserValue },
+ { "ProgramDataBaseFileName", "Fd", "Program Database File Name", "",
+ cmVS7FlagTable::UserValue },
+
+ // boolean flags
+ { "BufferSecurityCheck", "GS", "Buffer security check", "true", 0 },
+ { "BufferSecurityCheck", "GS-", "Turn off Buffer security check", "false",
+ 0 },
+ { "Detect64BitPortabilityProblems", "Wp64",
+ "Detect 64-bit Portability Problems", "true", 0 },
+ { "EnableFiberSafeOptimizations", "GT", "Enable Fiber-safe Optimizations",
+ "true", 0 },
+ { "EnableFunctionLevelLinking", "Gy", "EnableFunctionLevelLinking", "true",
+ 0 },
+ { "EnableIntrinsicFunctions", "Oi", "EnableIntrinsicFunctions", "true", 0 },
+ { "GlobalOptimizations", "Og", "Global Optimize", "true", 0 },
+ { "ImproveFloatingPointConsistency", "Op", "ImproveFloatingPointConsistency",
+ "true", 0 },
+ { "MinimalRebuild", "Gm", "minimal rebuild", "true", 0 },
+ { "OmitFramePointers", "Oy", "OmitFramePointers", "true", 0 },
+ { "OptimizeForWindowsApplication", "GA", "Optimize for windows", "true", 0 },
+ { "RuntimeTypeInfo", "GR", "Turn on Run time type information for c++",
+ "true", 0 },
+ { "RuntimeTypeInfo", "GR-", "Turn off Run time type information for c++",
+ "false", 0 },
+ { "SmallerTypeCheck", "RTCc", "smaller type check", "true", 0 },
+ { "SuppressStartupBanner", "nologo", "SuppressStartupBanner", "true", 0 },
+ { "WholeProgramOptimization", "GL", "Enables whole program optimization",
+ "true", 0 },
+ { "WholeProgramOptimization", "GL-", "Disables whole program optimization",
+ "false", 0 },
+ { "WarnAsError", "WX", "Treat warnings as errors", "true", 0 },
+ { "BrowseInformation", "FR", "Generate browse information", "1", 0 },
+ { "StringPooling", "GF", "Enable StringPooling", "true", 0 },
+ { "", "", "", "", 0 }
+};
+
+cmVS7FlagTable cmLocalVisualStudio7GeneratorLinkFlagTable[] = {
+ // option flags (some flags map to the same option)
+ { "GenerateManifest", "MANIFEST:NO", "disable manifest generation", "false",
+ 0 },
+ { "GenerateManifest", "MANIFEST", "enable manifest generation", "true", 0 },
+ { "LinkIncremental", "INCREMENTAL:NO", "link incremental", "1", 0 },
+ { "LinkIncremental", "INCREMENTAL:YES", "link incremental", "2", 0 },
+ { "CLRUnmanagedCodeCheck", "CLRUNMANAGEDCODECHECK:NO", "", "false", 0 },
+ { "CLRUnmanagedCodeCheck", "CLRUNMANAGEDCODECHECK", "", "true", 0 },
+ { "DataExecutionPrevention", "NXCOMPAT:NO",
+ "Not known to work with Windows Data Execution Prevention", "1", 0 },
+ { "DataExecutionPrevention", "NXCOMPAT",
+ "Known to work with Windows Data Execution Prevention", "2", 0 },
+ { "DelaySign", "DELAYSIGN:NO", "", "false", 0 },
+ { "DelaySign", "DELAYSIGN", "", "true", 0 },
+ { "EntryPointSymbol", "ENTRY:", "sets the starting address", "",
+ cmVS7FlagTable::UserValue },
+ { "IgnoreDefaultLibraryNames", "NODEFAULTLIB:", "default libs to ignore", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "IgnoreAllDefaultLibraries", "NODEFAULTLIB", "ignore all default libs",
+ "true", 0 },
+ { "FixedBaseAddress", "FIXED:NO", "Generate a relocation section", "1", 0 },
+ { "FixedBaseAddress", "FIXED", "Image must be loaded at a fixed address",
+ "2", 0 },
+ { "EnableCOMDATFolding", "OPT:NOICF", "Do not remove redundant COMDATs", "1",
+ 0 },
+ { "EnableCOMDATFolding", "OPT:ICF", "Remove redundant COMDATs", "2", 0 },
+ { "ResourceOnlyDLL", "NOENTRY", "Create DLL with no entry point", "true",
+ 0 },
+ { "OptimizeReferences", "OPT:NOREF", "Keep unreferenced data", "1", 0 },
+ { "OptimizeReferences", "OPT:REF", "Eliminate unreferenced data", "2", 0 },
+ { "Profile", "PROFILE", "", "true", 0 },
+ { "RandomizedBaseAddress", "DYNAMICBASE:NO",
+ "Image may not be rebased at load-time", "1", 0 },
+ { "RandomizedBaseAddress", "DYNAMICBASE",
+ "Image may be rebased at load-time", "2", 0 },
+ { "SetChecksum", "RELEASE", "Enable setting checksum in header", "true", 0 },
+ { "SupportUnloadOfDelayLoadedDLL", "DELAY:UNLOAD", "", "true", 0 },
+ { "TargetMachine", "MACHINE:I386", "Machine x86", "1", 0 },
+ { "TargetMachine", "MACHINE:X86", "Machine x86", "1", 0 },
+ { "TargetMachine", "MACHINE:AM33", "Machine AM33", "2", 0 },
+ { "TargetMachine", "MACHINE:ARM", "Machine ARM", "3", 0 },
+ { "TargetMachine", "MACHINE:EBC", "Machine EBC", "4", 0 },
+ { "TargetMachine", "MACHINE:IA64", "Machine IA64", "5", 0 },
+ { "TargetMachine", "MACHINE:M32R", "Machine M32R", "6", 0 },
+ { "TargetMachine", "MACHINE:MIPS", "Machine MIPS", "7", 0 },
+ { "TargetMachine", "MACHINE:MIPS16", "Machine MIPS16", "8", 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU)", "Machine MIPSFPU", "9", 0 },
+ { "TargetMachine", "MACHINE:MIPSFPU16", "Machine MIPSFPU16", "10", 0 },
+ { "TargetMachine", "MACHINE:MIPSR41XX", "Machine MIPSR41XX", "11", 0 },
+ { "TargetMachine", "MACHINE:SH3", "Machine SH3", "12", 0 },
+ { "TargetMachine", "MACHINE:SH3DSP", "Machine SH3DSP", "13", 0 },
+ { "TargetMachine", "MACHINE:SH4", "Machine SH4", "14", 0 },
+ { "TargetMachine", "MACHINE:SH5", "Machine SH5", "15", 0 },
+ { "TargetMachine", "MACHINE:THUMB", "Machine THUMB", "16", 0 },
+ { "TargetMachine", "MACHINE:X64", "Machine x64", "17", 0 },
+ { "TargetMachine", "MACHINE:ARM64", "Machine ARM64", "18", 0 },
+ { "TurnOffAssemblyGeneration", "NOASSEMBLY",
+ "No assembly even if CLR information is present in objects.", "true", 0 },
+ { "ModuleDefinitionFile", "DEF:", "add an export def file", "",
+ cmVS7FlagTable::UserValue },
+ { "GenerateMapFile", "MAP", "enable generation of map file", "true", 0 },
+ { "", "", "", "", 0 }
+};
+
+cmVS7FlagTable cmLocalVisualStudio7GeneratorFortranLinkFlagTable[] = {
+ { "LinkIncremental", "INCREMENTAL:NO", "link incremental",
+ "linkIncrementalNo", 0 },
+ { "LinkIncremental", "INCREMENTAL:YES", "link incremental",
+ "linkIncrementalYes", 0 },
+ { "EnableCOMDATFolding", "OPT:NOICF", "Do not remove redundant COMDATs",
+ "optNoFolding", 0 },
+ { "EnableCOMDATFolding", "OPT:ICF", "Remove redundant COMDATs", "optFolding",
+ 0 },
+ { "OptimizeReferences", "OPT:NOREF", "Keep unreferenced data",
+ "optNoReferences", 0 },
+ { "OptimizeReferences", "OPT:REF", "Eliminate unreferenced data",
+ "optReferences", 0 },
+ { "", "", "", "", 0 }
+};
+
+// Helper class to write build event <Tool .../> elements.
+class cmLocalVisualStudio7Generator::EventWriter
+{
+public:
+ EventWriter(cmLocalVisualStudio7Generator* lg, const std::string& config,
+ std::ostream& os)
+ : LG(lg)
+ , Config(config)
+ , Stream(os)
+ , First(true)
+ {
+ }
+ void Start(const char* tool)
+ {
+ this->First = true;
+ this->Stream << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"";
+ }
+ void Finish() { this->Stream << (this->First ? "" : "\"") << "/>\n"; }
+ void Write(std::vector<cmCustomCommand> const& ccs)
+ {
+ for (cmCustomCommand const& command : ccs) {
+ this->Write(command);
+ }
+ }
+ void Write(cmCustomCommand const& cc)
+ {
+ cmCustomCommandGenerator ccg(cc, this->Config, this->LG);
+ if (this->First) {
+ const char* comment = ccg.GetComment();
+ if (comment && *comment) {
+ this->Stream << "\nDescription=\"" << this->LG->EscapeForXML(comment)
+ << "\"";
+ }
+ this->Stream << "\nCommandLine=\"";
+ this->First = false;
+ } else {
+ this->Stream << this->LG->EscapeForXML("\n");
+ }
+ std::string script = this->LG->ConstructScript(ccg);
+ this->Stream << this->LG->EscapeForXML(script);
+ }
+
+private:
+ cmLocalVisualStudio7Generator* LG;
+ std::string Config;
+ std::ostream& Stream;
+ bool First;
+};
+
+void cmLocalVisualStudio7Generator::WriteConfiguration(
+ std::ostream& fout, const std::string& configName,
+ const std::string& libName, cmGeneratorTarget* target)
+{
+ std::string mfcFlag;
+ if (cmProp p = this->Makefile->GetDefinition("CMAKE_MFC_FLAG")) {
+ mfcFlag = cmGeneratorExpression::Evaluate(*p, this, configName);
+ } else {
+ mfcFlag = "0";
+ }
+ cmGlobalVisualStudio7Generator* gg =
+ static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
+ fout << "\t\t<Configuration\n"
+ << "\t\t\tName=\"" << configName << "|" << gg->GetPlatformName()
+ << "\"\n";
+ // This is an internal type to Visual Studio, it seems that:
+ // 4 == static library
+ // 2 == dll
+ // 1 == executable
+ // 10 == utility
+ const char* configType = "10";
+ const char* projectType = 0;
+ bool targetBuilds = true;
+
+ switch (target->GetType()) {
+ case cmStateEnums::OBJECT_LIBRARY:
+ targetBuilds = false; // no manifest tool for object library
+ CM_FALLTHROUGH;
+ case cmStateEnums::STATIC_LIBRARY:
+ projectType = "typeStaticLibrary";
+ configType = "4";
+ break;
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ projectType = "typeDynamicLibrary";
+ configType = "2";
+ break;
+ case cmStateEnums::EXECUTABLE:
+ configType = "1";
+ break;
+ case cmStateEnums::UTILITY:
+ case cmStateEnums::GLOBAL_TARGET:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ configType = "10";
+ CM_FALLTHROUGH;
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ targetBuilds = false;
+ break;
+ }
+ if (this->FortranProject && projectType) {
+ configType = projectType;
+ }
+ std::string flags;
+ std::string langForClCompile;
+ if (target->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
+ const std::string& linkLanguage =
+ (this->FortranProject ? std::string("Fortran")
+ : target->GetLinkerLanguage(configName));
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error(
+ "CMake can not determine linker language for target: " +
+ target->GetName());
+ return;
+ }
+ langForClCompile = linkLanguage;
+ if (langForClCompile == "C" || langForClCompile == "CXX" ||
+ langForClCompile == "Fortran") {
+ this->AddLanguageFlags(flags, target, langForClCompile, configName);
+ }
+ // set the correct language
+ if (linkLanguage == "C") {
+ flags += " /TC ";
+ }
+ if (linkLanguage == "CXX") {
+ flags += " /TP ";
+ }
+
+ // Add the target-specific flags.
+ this->AddCompileOptions(flags, target, langForClCompile, configName);
+
+ // Check IPO related warning/error.
+ target->IsIPOEnabled(linkLanguage, configName);
+ }
+
+ if (this->FortranProject) {
+ switch (cmOutputConverter::GetFortranFormat(
+ target->GetSafeProperty("Fortran_FORMAT"))) {
+ case cmOutputConverter::FortranFormatFixed:
+ flags += " -fixed";
+ break;
+ case cmOutputConverter::FortranFormatFree:
+ flags += " -free";
+ break;
+ default:
+ break;
+ }
+
+ switch (cmOutputConverter::GetFortranPreprocess(
+ target->GetSafeProperty("Fortran_PREPROCESS"))) {
+ case cmOutputConverter::FortranPreprocess::Needed:
+ flags += " -fpp";
+ break;
+ case cmOutputConverter::FortranPreprocess::NotNeeded:
+ flags += " -nofpp";
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Get preprocessor definitions for this directory.
+ std::string defineFlags = this->Makefile->GetDefineFlags();
+ Options::Tool t = Options::Compiler;
+ cmVS7FlagTable const* table = cmLocalVisualStudio7GeneratorFlagTable;
+ if (this->FortranProject) {
+ t = Options::FortranCompiler;
+ table = cmLocalVisualStudio7GeneratorFortranFlagTable;
+ }
+ Options targetOptions(this, t, table, gg->ExtraFlagTable);
+ targetOptions.FixExceptionHandlingDefault();
+ targetOptions.AddFlag("AssemblerListingLocation", "$(IntDir)\\");
+ targetOptions.Parse(flags);
+ targetOptions.Parse(defineFlags);
+ targetOptions.ParseFinish();
+ if (!langForClCompile.empty()) {
+ std::vector<std::string> targetDefines;
+ target->GetCompileDefinitions(targetDefines, configName, langForClCompile);
+ targetOptions.AddDefines(targetDefines);
+
+ std::vector<std::string> targetIncludes;
+ this->GetIncludeDirectories(targetIncludes, target, langForClCompile,
+ configName);
+ targetOptions.AddIncludes(targetIncludes);
+ }
+ targetOptions.SetVerboseMakefile(
+ this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
+
+ // Add a definition for the configuration name.
+ std::string configDefine = cmStrCat("CMAKE_INTDIR=\"", configName, '"');
+ targetOptions.AddDefine(configDefine);
+
+ // Add the export symbol definition for shared library objects.
+ if (const std::string* exportMacro = target->GetExportMacro()) {
+ targetOptions.AddDefine(*exportMacro);
+ }
+
+ // The intermediate directory name consists of a directory for the
+ // target and a subdirectory for the configuration name.
+ std::string intermediateDir =
+ cmStrCat(this->GetTargetDirectory(target), '/', configName);
+
+ if (target->GetType() < cmStateEnums::UTILITY) {
+ std::string const& outDir =
+ target->GetType() == cmStateEnums::OBJECT_LIBRARY
+ ? intermediateDir
+ : target->GetDirectory(configName);
+ /* clang-format off */
+ fout << "\t\t\tOutputDirectory=\""
+ << this->ConvertToXMLOutputPathSingle(outDir) << "\"\n";
+ /* clang-format on */
+ }
+
+ /* clang-format off */
+ fout << "\t\t\tIntermediateDirectory=\""
+ << this->ConvertToXMLOutputPath(intermediateDir)
+ << "\"\n"
+ << "\t\t\tConfigurationType=\"" << configType << "\"\n"
+ << "\t\t\tUseOfMFC=\"" << mfcFlag << "\"\n"
+ << "\t\t\tATLMinimizesCRunTimeLibraryUsage=\"false\"\n";
+ /* clang-format on */
+
+ if (this->FortranProject) {
+ // Intel Fortran >= 15.0 uses TargetName property.
+ std::string const targetNameFull = target->GetFullName(configName);
+ std::string const targetName =
+ cmSystemTools::GetFilenameWithoutLastExtension(targetNameFull);
+ std::string const targetExt =
+ target->GetType() == cmStateEnums::OBJECT_LIBRARY
+ ? ".lib"
+ : cmSystemTools::GetFilenameLastExtension(targetNameFull);
+ /* clang-format off */
+ fout <<
+ "\t\t\tTargetName=\"" << this->EscapeForXML(targetName) << "\"\n"
+ "\t\t\tTargetExt=\"" << this->EscapeForXML(targetExt) << "\"\n"
+ ;
+ /* clang-format on */
+ }
+
+ // If unicode is enabled change the character set to unicode, if not
+ // then default to MBCS.
+ if (targetOptions.UsingUnicode()) {
+ fout << "\t\t\tCharacterSet=\"1\">\n";
+ } else if (targetOptions.UsingSBCS()) {
+ fout << "\t\t\tCharacterSet=\"0\">\n";
+ } else {
+ fout << "\t\t\tCharacterSet=\"2\">\n";
+ }
+ const char* tool = "VCCLCompilerTool";
+ if (this->FortranProject) {
+ tool = "VFFortranCompilerTool";
+ }
+ fout << "\t\t\t<Tool\n"
+ << "\t\t\t\tName=\"" << tool << "\"\n";
+ if (this->FortranProject) {
+ cmProp target_mod_dir = target->GetProperty("Fortran_MODULE_DIRECTORY");
+ std::string modDir;
+ if (target_mod_dir) {
+ modDir = this->MaybeConvertToRelativePath(
+ this->GetCurrentBinaryDirectory(), *target_mod_dir);
+ } else {
+ modDir = ".";
+ }
+ fout << "\t\t\t\tModulePath=\"" << this->ConvertToXMLOutputPath(modDir)
+ << "\\$(ConfigurationName)\"\n";
+ }
+ targetOptions.OutputAdditionalIncludeDirectories(
+ fout, 4, this->FortranProject ? "Fortran" : langForClCompile);
+ targetOptions.OutputFlagMap(fout, 4);
+ targetOptions.OutputPreprocessorDefinitions(fout, 4, langForClCompile);
+ fout << "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n";
+ if (target->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
+ // Specify the compiler program database file if configured.
+ std::string pdb = target->GetCompilePDBPath(configName);
+ if (!pdb.empty()) {
+ fout << "\t\t\t\tProgramDataBaseFileName=\""
+ << this->ConvertToXMLOutputPathSingle(pdb) << "\"\n";
+ }
+ }
+ fout << "/>\n"; // end of <Tool Name=VCCLCompilerTool
+ if (gg->IsMasmEnabled() && !this->FortranProject) {
+ Options masmOptions(this, Options::MasmCompiler, 0, 0);
+ /* clang-format off */
+ fout <<
+ "\t\t\t<Tool\n"
+ "\t\t\t\tName=\"MASM\"\n"
+ ;
+ /* clang-format on */
+ targetOptions.OutputAdditionalIncludeDirectories(fout, 4, "ASM_MASM");
+ // Use same preprocessor definitions as VCCLCompilerTool.
+ targetOptions.OutputPreprocessorDefinitions(fout, 4, "ASM_MASM");
+ masmOptions.OutputFlagMap(fout, 4);
+ /* clang-format off */
+ fout <<
+ "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n"
+ "\t\t\t/>\n";
+ /* clang-format on */
+ }
+ tool = "VCCustomBuildTool";
+ if (this->FortranProject) {
+ tool = "VFCustomBuildTool";
+ }
+ fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"/>\n";
+ tool = "VCResourceCompilerTool";
+ if (this->FortranProject) {
+ tool = "VFResourceCompilerTool";
+ }
+ fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n";
+ targetOptions.OutputAdditionalIncludeDirectories(fout, 4, "RC");
+ // add the -D flags to the RC tool
+ targetOptions.OutputPreprocessorDefinitions(fout, 4, "RC");
+ fout << "\t\t\t/>\n";
+ tool = "VCMIDLTool";
+ if (this->FortranProject) {
+ tool = "VFMIDLTool";
+ }
+ fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n";
+ targetOptions.OutputAdditionalIncludeDirectories(fout, 4, "MIDL");
+ fout << "\t\t\t\tMkTypLibCompatible=\"false\"\n";
+ if (gg->GetPlatformName() == "x64") {
+ fout << "\t\t\t\tTargetEnvironment=\"3\"\n";
+ } else if (gg->GetPlatformName() == "ia64") {
+ fout << "\t\t\t\tTargetEnvironment=\"2\"\n";
+ } else {
+ fout << "\t\t\t\tTargetEnvironment=\"1\"\n";
+ }
+ fout << "\t\t\t\tGenerateStublessProxies=\"true\"\n";
+ fout << "\t\t\t\tTypeLibraryName=\"$(InputName).tlb\"\n";
+ fout << "\t\t\t\tOutputDirectory=\"$(IntDir)\"\n";
+ fout << "\t\t\t\tHeaderFileName=\"$(InputName).h\"\n";
+ fout << "\t\t\t\tDLLDataFileName=\"\"\n";
+ fout << "\t\t\t\tInterfaceIdentifierFileName=\"$(InputName)_i.c\"\n";
+ fout << "\t\t\t\tProxyFileName=\"$(InputName)_p.c\"/>\n";
+ // end of <Tool Name=VCMIDLTool
+
+ // Add manifest tool settings.
+ if (targetBuilds) {
+ const char* manifestTool = "VCManifestTool";
+ if (this->FortranProject) {
+ manifestTool = "VFManifestTool";
+ }
+ /* clang-format off */
+ fout <<
+ "\t\t\t<Tool\n"
+ "\t\t\t\tName=\"" << manifestTool << "\"";
+ /* clang-format on */
+
+ std::vector<cmSourceFile const*> manifest_srcs;
+ target->GetManifests(manifest_srcs, configName);
+ if (!manifest_srcs.empty()) {
+ fout << "\n\t\t\t\tAdditionalManifestFiles=\"";
+ for (cmSourceFile const* manifest : manifest_srcs) {
+ std::string m = manifest->GetFullPath();
+ fout << this->ConvertToXMLOutputPath(m) << ";";
+ }
+ fout << "\"";
+ }
+
+ // Check if we need the FAT32 workaround.
+ // Check the filesystem type where the target will be written.
+ if (cmLVS7G_IsFAT(target->GetDirectory(configName).c_str())) {
+ // Add a flag telling the manifest tool to use a workaround
+ // for FAT32 file systems, which can cause an empty manifest
+ // to be embedded into the resulting executable. See CMake
+ // bug #2617.
+ fout << "\n\t\t\t\tUseFAT32Workaround=\"true\"";
+ }
+ fout << "/>\n";
+ }
+
+ this->OutputTargetRules(fout, configName, target, libName);
+ this->OutputBuildTool(fout, configName, target, targetOptions);
+ this->OutputDeploymentDebuggerTool(fout, configName, target);
+ fout << "\t\t</Configuration>\n";
+}
+
+std::string cmLocalVisualStudio7Generator::GetBuildTypeLinkerFlags(
+ std::string rootLinkerFlags, const std::string& configName)
+{
+ std::string configTypeUpper = cmSystemTools::UpperCase(configName);
+ std::string extraLinkOptionsBuildTypeDef =
+ rootLinkerFlags + "_" + configTypeUpper;
+
+ const std::string& extraLinkOptionsBuildType =
+ this->Makefile->GetRequiredDefinition(extraLinkOptionsBuildTypeDef);
+
+ return extraLinkOptionsBuildType;
+}
+
+void cmLocalVisualStudio7Generator::OutputBuildTool(
+ std::ostream& fout, const std::string& configName, cmGeneratorTarget* target,
+ const Options& targetOptions)
+{
+ cmGlobalVisualStudio7Generator* gg =
+ static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
+ std::string temp;
+ std::string extraLinkOptions;
+ if (target->GetType() == cmStateEnums::EXECUTABLE) {
+ extraLinkOptions =
+ this->Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS") + " " +
+ GetBuildTypeLinkerFlags("CMAKE_EXE_LINKER_FLAGS", configName);
+ }
+ if (target->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ extraLinkOptions =
+ this->Makefile->GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS") +
+ " " + GetBuildTypeLinkerFlags("CMAKE_SHARED_LINKER_FLAGS", configName);
+ }
+ if (target->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ extraLinkOptions =
+ this->Makefile->GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS") +
+ " " + GetBuildTypeLinkerFlags("CMAKE_MODULE_LINKER_FLAGS", configName);
+ }
+
+ cmProp targetLinkFlags = target->GetProperty("LINK_FLAGS");
+ if (targetLinkFlags) {
+ extraLinkOptions += " ";
+ extraLinkOptions += *targetLinkFlags;
+ }
+ std::string configTypeUpper = cmSystemTools::UpperCase(configName);
+ std::string linkFlagsConfig = cmStrCat("LINK_FLAGS_", configTypeUpper);
+ targetLinkFlags = target->GetProperty(linkFlagsConfig);
+ if (targetLinkFlags) {
+ extraLinkOptions += " ";
+ extraLinkOptions += *targetLinkFlags;
+ }
+
+ std::vector<std::string> opts;
+ target->GetLinkOptions(opts, configName,
+ target->GetLinkerLanguage(configName));
+ // LINK_OPTIONS are escaped.
+ this->AppendCompileOptions(extraLinkOptions, opts);
+
+ Options linkOptions(this, Options::Linker);
+ if (this->FortranProject) {
+ linkOptions.AddTable(cmLocalVisualStudio7GeneratorFortranLinkFlagTable);
+ }
+ linkOptions.AddTable(cmLocalVisualStudio7GeneratorLinkFlagTable);
+
+ linkOptions.Parse(extraLinkOptions);
+ cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
+ target->GetModuleDefinitionInfo(configName);
+ if (mdi && !mdi->DefFile.empty()) {
+ std::string defFile =
+ this->ConvertToOutputFormat(mdi->DefFile, cmOutputConverter::SHELL);
+ linkOptions.AddFlag("ModuleDefinitionFile", defFile);
+ }
+
+ switch (target->GetType()) {
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ break;
+ case cmStateEnums::OBJECT_LIBRARY: {
+ std::string libpath =
+ cmStrCat(this->GetTargetDirectory(target), '/', configName, '/',
+ target->GetName(), ".lib");
+ const char* tool =
+ this->FortranProject ? "VFLibrarianTool" : "VCLibrarianTool";
+ fout << "\t\t\t<Tool\n"
+ << "\t\t\t\tName=\"" << tool << "\"\n";
+ fout << "\t\t\t\tOutputFile=\""
+ << this->ConvertToXMLOutputPathSingle(libpath) << "\"/>\n";
+ break;
+ }
+ case cmStateEnums::STATIC_LIBRARY: {
+ std::string targetNameFull = target->GetFullName(configName);
+ std::string libpath =
+ cmStrCat(target->GetDirectory(configName), '/', targetNameFull);
+ const char* tool = "VCLibrarianTool";
+ if (this->FortranProject) {
+ tool = "VFLibrarianTool";
+ }
+ fout << "\t\t\t<Tool\n"
+ << "\t\t\t\tName=\"" << tool << "\"\n";
+
+ if (this->FortranProject) {
+ std::ostringstream libdeps;
+ this->Internal->OutputObjects(libdeps, target, configName);
+ if (!libdeps.str().empty()) {
+ fout << "\t\t\t\tAdditionalDependencies=\"" << libdeps.str()
+ << "\"\n";
+ }
+ }
+ std::string libflags;
+ this->GetStaticLibraryFlags(
+ libflags, configName, target->GetLinkerLanguage(configName), target);
+ if (!libflags.empty()) {
+ fout << "\t\t\t\tAdditionalOptions=\"" << this->EscapeForXML(libflags)
+ << "\"\n";
+ }
+ fout << "\t\t\t\tOutputFile=\""
+ << this->ConvertToXMLOutputPathSingle(libpath) << "\"/>\n";
+ break;
+ }
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY: {
+ cmGeneratorTarget::Names targetNames =
+ target->GetLibraryNames(configName);
+
+ // Compute the link library and directory information.
+ cmComputeLinkInformation* pcli = target->GetLinkInformation(configName);
+ if (!pcli) {
+ return;
+ }
+ cmComputeLinkInformation& cli = *pcli;
+ std::string linkLanguage = cli.GetLinkLanguage();
+
+ // Compute the variable name to lookup standard libraries for this
+ // language.
+ std::string standardLibsVar =
+ cmStrCat("CMAKE_", linkLanguage, "_STANDARD_LIBRARIES");
+ const char* tool = "VCLinkerTool";
+ if (this->FortranProject) {
+ tool = "VFLinkerTool";
+ }
+ fout << "\t\t\t<Tool\n"
+ << "\t\t\t\tName=\"" << tool << "\"\n";
+ if (!gg->NeedLinkLibraryDependencies(target)) {
+ fout << "\t\t\t\tLinkLibraryDependencies=\"false\"\n";
+ }
+ // Use the NOINHERIT macro to avoid getting VS project default
+ // libraries which may be set by the user to something bad.
+ fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
+ << this->Makefile->GetSafeDefinition(standardLibsVar);
+ if (this->FortranProject) {
+ this->Internal->OutputObjects(fout, target, configName, " ");
+ }
+ fout << " ";
+ this->Internal->OutputLibraries(fout, cli.GetItems());
+ fout << "\"\n";
+ temp =
+ cmStrCat(target->GetDirectory(configName), '/', targetNames.Output);
+ fout << "\t\t\t\tOutputFile=\""
+ << this->ConvertToXMLOutputPathSingle(temp) << "\"\n";
+ this->WriteTargetVersionAttribute(fout, target);
+ linkOptions.OutputFlagMap(fout, 4);
+ fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
+ this->OutputLibraryDirectories(fout, cli.GetDirectories());
+ fout << "\"\n";
+ temp =
+ cmStrCat(target->GetPDBDirectory(configName), '/', targetNames.PDB);
+ fout << "\t\t\t\tProgramDatabaseFile=\""
+ << this->ConvertToXMLOutputPathSingle(temp) << "\"\n";
+ if (targetOptions.IsDebug()) {
+ fout << "\t\t\t\tGenerateDebugInformation=\"true\"\n";
+ }
+ if (this->WindowsCEProject) {
+ if (this->GetVersion() < cmGlobalVisualStudioGenerator::VS9) {
+ fout << "\t\t\t\tSubSystem=\"9\"\n";
+ } else {
+ fout << "\t\t\t\tSubSystem=\"8\"\n";
+ }
+ }
+ std::string stackVar = cmStrCat("CMAKE_", linkLanguage, "_STACK_SIZE");
+ cmProp stackVal = this->Makefile->GetDefinition(stackVar);
+ if (stackVal) {
+ fout << "\t\t\t\tStackReserveSize=\"" << *stackVal << "\"\n";
+ }
+ 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\"";
+ }
+ fout << "/>\n";
+ } break;
+ case cmStateEnums::EXECUTABLE: {
+ cmGeneratorTarget::Names targetNames =
+ target->GetExecutableNames(configName);
+
+ // Compute the link library and directory information.
+ cmComputeLinkInformation* pcli = target->GetLinkInformation(configName);
+ if (!pcli) {
+ return;
+ }
+ cmComputeLinkInformation& cli = *pcli;
+ std::string linkLanguage = cli.GetLinkLanguage();
+
+ bool isWin32Executable = target->IsWin32Executable(configName);
+
+ // Compute the variable name to lookup standard libraries for this
+ // language.
+ std::string standardLibsVar =
+ cmStrCat("CMAKE_", linkLanguage, "_STANDARD_LIBRARIES");
+ const char* tool = "VCLinkerTool";
+ if (this->FortranProject) {
+ tool = "VFLinkerTool";
+ }
+ fout << "\t\t\t<Tool\n"
+ << "\t\t\t\tName=\"" << tool << "\"\n";
+ if (!gg->NeedLinkLibraryDependencies(target)) {
+ fout << "\t\t\t\tLinkLibraryDependencies=\"false\"\n";
+ }
+ // Use the NOINHERIT macro to avoid getting VS project default
+ // libraries which may be set by the user to something bad.
+ fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
+ << this->Makefile->GetSafeDefinition(standardLibsVar);
+ if (this->FortranProject) {
+ this->Internal->OutputObjects(fout, target, configName, " ");
+ }
+ fout << " ";
+ this->Internal->OutputLibraries(fout, cli.GetItems());
+ fout << "\"\n";
+ temp =
+ cmStrCat(target->GetDirectory(configName), '/', targetNames.Output);
+ fout << "\t\t\t\tOutputFile=\""
+ << this->ConvertToXMLOutputPathSingle(temp) << "\"\n";
+ this->WriteTargetVersionAttribute(fout, target);
+ linkOptions.OutputFlagMap(fout, 4);
+ fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
+ this->OutputLibraryDirectories(fout, cli.GetDirectories());
+ fout << "\"\n";
+ std::string path = this->ConvertToXMLOutputPathSingle(
+ target->GetPDBDirectory(configName));
+ fout << "\t\t\t\tProgramDatabaseFile=\"" << path << "/"
+ << targetNames.PDB << "\"\n";
+ if (targetOptions.IsDebug()) {
+ fout << "\t\t\t\tGenerateDebugInformation=\"true\"\n";
+ }
+ if (this->WindowsCEProject) {
+ if (this->GetVersion() < cmGlobalVisualStudioGenerator::VS9) {
+ fout << "\t\t\t\tSubSystem=\"9\"\n";
+ } else {
+ fout << "\t\t\t\tSubSystem=\"8\"\n";
+ }
+
+ if (!linkOptions.GetFlag("EntryPointSymbol")) {
+ const char* entryPointSymbol = targetOptions.UsingUnicode()
+ ? (isWin32Executable ? "wWinMainCRTStartup" : "mainWCRTStartup")
+ : (isWin32Executable ? "WinMainCRTStartup" : "mainACRTStartup");
+ fout << "\t\t\t\tEntryPointSymbol=\"" << entryPointSymbol << "\"\n";
+ }
+ } else if (this->FortranProject) {
+ fout << "\t\t\t\tSubSystem=\""
+ << (isWin32Executable ? "subSystemWindows" : "subSystemConsole")
+ << "\"\n";
+ } else {
+ fout << "\t\t\t\tSubSystem=\"" << (isWin32Executable ? "2" : "1")
+ << "\"\n";
+ }
+ std::string stackVar = cmStrCat("CMAKE_", linkLanguage, "_STACK_SIZE");
+ cmProp stackVal = this->Makefile->GetDefinition(stackVar);
+ if (stackVal) {
+ fout << "\t\t\t\tStackReserveSize=\"" << *stackVal << "\"";
+ }
+ temp = cmStrCat(
+ target->GetDirectory(configName, cmStateEnums::ImportLibraryArtifact),
+ '/', targetNames.ImportLibrary);
+ fout << "\t\t\t\tImportLibrary=\""
+ << this->ConvertToXMLOutputPathSingle(temp) << "\"/>\n";
+ break;
+ }
+ case cmStateEnums::UTILITY:
+ case cmStateEnums::GLOBAL_TARGET:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ break;
+ }
+}
+
+static std::string cmLocalVisualStudio7GeneratorEscapeForXML(
+ const std::string& s)
+{
+ std::string ret = s;
+ cmSystemTools::ReplaceString(ret, "&", "&amp;");
+ cmSystemTools::ReplaceString(ret, "\"", "&quot;");
+ cmSystemTools::ReplaceString(ret, "<", "&lt;");
+ cmSystemTools::ReplaceString(ret, ">", "&gt;");
+ cmSystemTools::ReplaceString(ret, "\n", "&#x0D;&#x0A;");
+ return ret;
+}
+
+static std::string GetEscapedPropertyIfValueNotNULL(const char* propertyValue)
+{
+ return propertyValue == nullptr
+ ? std::string()
+ : cmLocalVisualStudio7GeneratorEscapeForXML(propertyValue);
+}
+
+void cmLocalVisualStudio7Generator::OutputDeploymentDebuggerTool(
+ std::ostream& fout, std::string const& config, cmGeneratorTarget* target)
+{
+ if (this->WindowsCEProject) {
+ cmProp dir = target->GetProperty("DEPLOYMENT_REMOTE_DIRECTORY");
+ cmProp additionalFiles =
+ target->GetProperty("DEPLOYMENT_ADDITIONAL_FILES");
+
+ if (dir == nullptr && additionalFiles == nullptr) {
+ return;
+ }
+
+ fout << "\t\t\t<DeploymentTool\n"
+ "\t\t\t\tForceDirty=\"-1\"\n"
+ "\t\t\t\tRemoteDirectory=\""
+ << GetEscapedPropertyIfValueNotNULL(dir->c_str())
+ << "\"\n"
+ "\t\t\t\tRegisterOutput=\"0\"\n"
+ "\t\t\t\tAdditionalFiles=\""
+ << GetEscapedPropertyIfValueNotNULL(additionalFiles->c_str())
+ << "\"/>\n";
+
+ if (dir != nullptr) {
+ std::string const exe = *dir + "\\" + target->GetFullName(config);
+
+ fout << "\t\t\t<DebuggerTool\n"
+ "\t\t\t\tRemoteExecutable=\""
+ << this->EscapeForXML(exe)
+ << "\"\n"
+ "\t\t\t\tArguments=\"\"\n"
+ "\t\t\t/>\n";
+ }
+ }
+}
+
+void cmLocalVisualStudio7Generator::WriteTargetVersionAttribute(
+ std::ostream& fout, cmGeneratorTarget* gt)
+{
+ int major;
+ int minor;
+ gt->GetTargetVersion(major, minor);
+ fout << "\t\t\t\tVersion=\"" << major << "." << minor << "\"\n";
+}
+
+void cmLocalVisualStudio7GeneratorInternals::OutputLibraries(
+ std::ostream& fout, ItemVector const& libs)
+{
+ cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
+ std::string currentBinDir = lg->GetCurrentBinaryDirectory();
+ for (auto const& lib : libs) {
+ if (lib.IsPath) {
+ std::string rel =
+ lg->MaybeConvertToRelativePath(currentBinDir, lib.Value.Value);
+ fout << lg->ConvertToXMLOutputPath(rel) << " ";
+ } else if (!lib.Target ||
+ lib.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+ fout << lib.Value.Value << " ";
+ }
+ }
+}
+
+void cmLocalVisualStudio7GeneratorInternals::OutputObjects(
+ std::ostream& fout, cmGeneratorTarget* gt, std::string const& configName,
+ const char* isep)
+{
+ // VS < 8 does not support per-config source locations so we
+ // list object library content on the link line instead.
+ cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
+ std::string currentBinDir = lg->GetCurrentBinaryDirectory();
+
+ std::vector<cmSourceFile const*> objs;
+ gt->GetExternalObjects(objs, configName);
+
+ const char* sep = isep ? isep : "";
+ for (cmSourceFile const* obj : objs) {
+ if (!obj->GetObjectLibrary().empty()) {
+ std::string const& objFile = obj->GetFullPath();
+ std::string rel = lg->MaybeConvertToRelativePath(currentBinDir, objFile);
+ fout << sep << lg->ConvertToXMLOutputPath(rel);
+ sep = " ";
+ }
+ }
+}
+
+void cmLocalVisualStudio7Generator::OutputLibraryDirectories(
+ std::ostream& fout, std::vector<std::string> const& dirs)
+{
+ const char* comma = "";
+ std::string currentBinDir = this->GetCurrentBinaryDirectory();
+ for (std::string dir : dirs) {
+ // Remove any trailing slash and skip empty paths.
+ if (dir.back() == '/') {
+ dir = dir.substr(0, dir.size() - 1);
+ }
+ if (dir.empty()) {
+ continue;
+ }
+
+ // Switch to a relative path specification if it is shorter.
+ if (cmSystemTools::FileIsFullPath(dir)) {
+ std::string rel = this->MaybeConvertToRelativePath(currentBinDir, dir);
+ if (rel.size() < dir.size()) {
+ dir = rel;
+ }
+ }
+
+ // First search a configuration-specific subdirectory and then the
+ // original directory.
+ fout << comma
+ << this->ConvertToXMLOutputPath(dir + "/$(ConfigurationName)") << ","
+ << this->ConvertToXMLOutputPath(dir);
+ comma = ",";
+ }
+}
+
+void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
+ const std::string& libName,
+ cmGeneratorTarget* target)
+{
+ std::vector<std::string> configs =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
+
+ // We may be modifying the source groups temporarily, so make a copy.
+ std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
+
+ AllConfigSources sources;
+ sources.Sources = target->GetAllConfigSources();
+
+ // Add CMakeLists.txt file with rule to re-run CMake for user convenience.
+ if (target->GetType() != cmStateEnums::GLOBAL_TARGET &&
+ target->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
+ if (cmSourceFile* sf = this->CreateVCProjBuildRule()) {
+ cmGeneratorTarget::AllConfigSource acs;
+ acs.Source = sf;
+ acs.Kind = cmGeneratorTarget::SourceKindCustomCommand;
+ for (size_t ci = 0; ci < configs.size(); ++ci) {
+ acs.Configs.push_back(ci);
+ }
+ bool haveCMakeLists = false;
+ for (cmGeneratorTarget::AllConfigSource& si : sources.Sources) {
+ if (si.Source == sf) {
+ haveCMakeLists = true;
+ // Replace the explicit source reference with our generated one.
+ si = acs;
+ break;
+ }
+ }
+ if (!haveCMakeLists) {
+ sources.Sources.emplace_back(std::move(acs));
+ }
+ }
+ }
+
+ for (size_t si = 0; si < sources.Sources.size(); ++si) {
+ cmSourceFile const* sf = sources.Sources[si].Source;
+ sources.Index[sf] = si;
+ if (!sf->GetObjectLibrary().empty()) {
+ if (this->FortranProject) {
+ // Intel Fortran does not support per-config source locations
+ // so we list object library content on the link line instead.
+ // See OutputObjects.
+ continue;
+ }
+ }
+ // Add the file to the list of sources.
+ std::string const source = sf->GetFullPath();
+ cmSourceGroup* sourceGroup =
+ this->Makefile->FindSourceGroup(source, sourceGroups);
+ sourceGroup->AssignSource(sf);
+ }
+
+ // open the project
+ this->WriteProjectStart(fout, libName, target, sourceGroups);
+ // write the configuration information
+ this->WriteConfigurations(fout, configs, libName, target);
+
+ fout << "\t<Files>\n";
+
+ // Loop through every source group.
+ for (unsigned int i = 0; i < sourceGroups.size(); ++i) {
+ cmSourceGroup sg = sourceGroups[i];
+ this->WriteGroup(&sg, target, fout, libName, configs, sources);
+ }
+
+ fout << "\t</Files>\n";
+
+ // Write the VCProj file's footer.
+ this->WriteVCProjFooter(fout, target);
+}
+
+struct cmLVS7GFileConfig
+{
+ std::string ObjectName;
+ std::string CompileFlags;
+ std::string CompileDefs;
+ std::string CompileDefsConfig;
+ std::string AdditionalDeps;
+ std::string IncludeDirs;
+ bool ExcludedFromBuild;
+};
+
+class cmLocalVisualStudio7GeneratorFCInfo
+{
+public:
+ cmLocalVisualStudio7GeneratorFCInfo(
+ cmLocalVisualStudio7Generator* lg, cmGeneratorTarget* target,
+ cmGeneratorTarget::AllConfigSource const& acs,
+ std::vector<std::string> const& configs);
+ std::map<std::string, cmLVS7GFileConfig> FileConfigMap;
+};
+
+cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
+ cmLocalVisualStudio7Generator* lg, cmGeneratorTarget* gt,
+ cmGeneratorTarget::AllConfigSource const& acs,
+ std::vector<std::string> const& configs)
+{
+ cmSourceFile const& sf = *acs.Source;
+ std::string objectName;
+ if (gt->HasExplicitObjectName(&sf)) {
+ objectName = gt->GetObjectName(&sf);
+ }
+
+ // Compute per-source, per-config information.
+ size_t ci = 0;
+ for (std::string const& config : configs) {
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ cmLVS7GFileConfig fc;
+
+ std::string lang =
+ lg->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str());
+ const std::string& sourceLang = lg->GetSourceFileLanguage(sf);
+ bool needForceLang = false;
+ // source file does not match its extension language
+ if (lang != sourceLang) {
+ needForceLang = true;
+ lang = sourceLang;
+ }
+
+ cmGeneratorExpressionInterpreter genexInterpreter(lg, config, gt, lang);
+
+ bool needfc = false;
+ if (!objectName.empty()) {
+ fc.ObjectName = objectName;
+ needfc = true;
+ }
+ const std::string COMPILE_FLAGS("COMPILE_FLAGS");
+ if (cmProp cflags = sf.GetProperty(COMPILE_FLAGS)) {
+ fc.CompileFlags = genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS);
+ needfc = true;
+ }
+ const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
+ if (cmProp coptions = sf.GetProperty(COMPILE_OPTIONS)) {
+ lg->AppendCompileOptions(
+ fc.CompileFlags,
+ genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
+ needfc = true;
+ }
+ // Add precompile headers compile options.
+ const std::string pchSource = gt->GetPchSource(config, lang);
+ if (!pchSource.empty() && !sf.GetProperty("SKIP_PRECOMPILE_HEADERS")) {
+ std::string pchOptions;
+ if (sf.GetFullPath() == pchSource) {
+ pchOptions = gt->GetPchCreateCompileOptions(config, lang);
+ } else {
+ pchOptions = gt->GetPchUseCompileOptions(config, lang);
+ }
+
+ lg->AppendCompileOptions(
+ fc.CompileFlags,
+ genexInterpreter.Evaluate(pchOptions, COMPILE_OPTIONS));
+ needfc = true;
+ }
+
+ if (lg->FortranProject) {
+ switch (cmOutputConverter::GetFortranPreprocess(
+ sf.GetSafeProperty("Fortran_PREPROCESS"))) {
+ case cmOutputConverter::FortranPreprocess::Needed:
+ fc.CompileFlags = cmStrCat("-fpp ", fc.CompileFlags);
+ needfc = true;
+ break;
+ case cmOutputConverter::FortranPreprocess::NotNeeded:
+ fc.CompileFlags = cmStrCat("-nofpp ", fc.CompileFlags);
+ needfc = true;
+ break;
+ default:
+ break;
+ }
+
+ switch (cmOutputConverter::GetFortranFormat(
+ sf.GetSafeProperty("Fortran_FORMAT"))) {
+ case cmOutputConverter::FortranFormatFixed:
+ fc.CompileFlags = "-fixed " + fc.CompileFlags;
+ needfc = true;
+ break;
+ case cmOutputConverter::FortranFormatFree:
+ fc.CompileFlags = "-free " + fc.CompileFlags;
+ needfc = true;
+ break;
+ default:
+ break;
+ }
+ }
+ const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
+ if (cmProp cdefs = sf.GetProperty(COMPILE_DEFINITIONS)) {
+ fc.CompileDefs = genexInterpreter.Evaluate(*cdefs, COMPILE_DEFINITIONS);
+ needfc = true;
+ }
+ std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", configUpper);
+ if (cmProp ccdefs = sf.GetProperty(defPropName)) {
+ fc.CompileDefsConfig =
+ genexInterpreter.Evaluate(*ccdefs, COMPILE_DEFINITIONS);
+ needfc = true;
+ }
+
+ const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
+ if (cmProp cincs = sf.GetProperty(INCLUDE_DIRECTORIES)) {
+ fc.IncludeDirs = genexInterpreter.Evaluate(*cincs, INCLUDE_DIRECTORIES);
+ needfc = true;
+ }
+
+ // Check for extra object-file dependencies.
+ if (cmProp deps = sf.GetProperty("OBJECT_DEPENDS")) {
+ std::vector<std::string> depends = cmExpandedList(*deps);
+ const char* sep = "";
+ for (const std::string& d : depends) {
+ fc.AdditionalDeps += sep;
+ fc.AdditionalDeps += lg->ConvertToXMLOutputPath(d);
+ sep = ";";
+ needfc = true;
+ }
+ }
+
+ const std::string& linkLanguage = gt->GetLinkerLanguage(config);
+ // If HEADER_FILE_ONLY is set, we must suppress this generation in
+ // the project file
+ fc.ExcludedFromBuild = sf.GetPropertyAsBool("HEADER_FILE_ONLY") ||
+ !cm::contains(acs.Configs, ci) ||
+ (gt->GetPropertyAsBool("UNITY_BUILD") &&
+ sf.GetProperty("UNITY_SOURCE_FILE") &&
+ !sf.GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION"));
+ if (fc.ExcludedFromBuild) {
+ needfc = true;
+ }
+
+ // if the source file does not match the linker language
+ // then force c or c++
+ if (needForceLang || (linkLanguage != lang)) {
+ if (lang == "CXX") {
+ // force a C++ file type
+ fc.CompileFlags += " /TP ";
+ needfc = true;
+ } else if (lang == "C") {
+ // force to c
+ fc.CompileFlags += " /TC ";
+ needfc = true;
+ }
+ }
+
+ if (needfc) {
+ this->FileConfigMap[config] = fc;
+ }
+ ++ci;
+ }
+}
+
+std::string cmLocalVisualStudio7Generator::ComputeLongestObjectDirectory(
+ cmGeneratorTarget const* target) const
+{
+ std::vector<std::string> configs =
+ target->Target->GetMakefile()->GetGeneratorConfigs(
+ cmMakefile::ExcludeEmptyConfig);
+
+ // Compute the maximum length configuration name.
+ std::string config_max;
+ for (std::vector<std::string>::iterator i = configs.begin();
+ i != configs.end(); ++i) {
+ if (i->size() > config_max.size()) {
+ config_max = *i;
+ }
+ }
+
+ // Compute the maximum length full path to the intermediate
+ // files directory for any configuration. This is used to construct
+ // object file names that do not produce paths that are too long.
+ std::string dir_max =
+ cmStrCat(this->GetCurrentBinaryDirectory(), '/',
+ this->GetTargetDirectory(target), '/', config_max, '/');
+ return dir_max;
+}
+
+bool cmLocalVisualStudio7Generator::WriteGroup(
+ const cmSourceGroup* sg, cmGeneratorTarget* target, std::ostream& fout,
+ const std::string& libName, std::vector<std::string> const& configs,
+ AllConfigSources const& sources)
+{
+ cmGlobalVisualStudio7Generator* gg =
+ static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
+ const std::vector<const cmSourceFile*>& sourceFiles = sg->GetSourceFiles();
+ std::vector<cmSourceGroup> const& children = sg->GetGroupChildren();
+
+ // Write the children to temporary output.
+ bool hasChildrenWithSources = false;
+ std::ostringstream tmpOut;
+ for (unsigned int i = 0; i < children.size(); ++i) {
+ if (this->WriteGroup(&children[i], target, tmpOut, libName, configs,
+ sources)) {
+ hasChildrenWithSources = true;
+ }
+ }
+
+ // If the group is empty, don't write it at all.
+ if (sourceFiles.empty() && !hasChildrenWithSources) {
+ return false;
+ }
+
+ // If the group has a name, write the header.
+ std::string const& name = sg->GetName();
+ if (!name.empty()) {
+ this->WriteVCProjBeginGroup(fout, name.c_str(), "");
+ }
+
+ auto& sourcesVisited = this->GetSourcesVisited(target);
+
+ // Loop through each source in the source group.
+ for (const cmSourceFile* sf : sourceFiles) {
+ std::string source = sf->GetFullPath();
+
+ if (source != libName || target->GetType() == cmStateEnums::UTILITY ||
+ target->GetType() == cmStateEnums::GLOBAL_TARGET ||
+ target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ // Look up the source kind and configs.
+ std::map<cmSourceFile const*, size_t>::const_iterator map_it =
+ sources.Index.find(sf);
+ // The map entry must exist because we populated it earlier.
+ assert(map_it != sources.Index.end());
+ cmGeneratorTarget::AllConfigSource const& acs =
+ sources.Sources[map_it->second];
+
+ FCInfo fcinfo(this, target, acs, configs);
+
+ fout << "\t\t\t<File\n";
+ std::string d = this->ConvertToXMLOutputPathSingle(source);
+ // Tell MS-Dev what the source is. If the compiler knows how to
+ // build it, then it will.
+ fout << "\t\t\t\tRelativePath=\"" << d << "\">\n";
+ if (cmCustomCommand const* command = sf->GetCustomCommand()) {
+ if (sourcesVisited.insert(sf).second) {
+ this->WriteCustomRule(fout, configs, source.c_str(), *command,
+ fcinfo);
+ }
+ } else if (!fcinfo.FileConfigMap.empty()) {
+ const char* aCompilerTool = "VCCLCompilerTool";
+ std::string ppLang = "CXX";
+ if (this->FortranProject) {
+ aCompilerTool = "VFFortranCompilerTool";
+ }
+ std::string const& lang = sf->GetLanguage();
+ std::string ext = sf->GetExtension();
+ ext = cmSystemTools::LowerCase(ext);
+ if (ext == "idl") {
+ aCompilerTool = "VCMIDLTool";
+ if (this->FortranProject) {
+ aCompilerTool = "VFMIDLTool";
+ }
+ }
+ if (ext == "rc") {
+ aCompilerTool = "VCResourceCompilerTool";
+ ppLang = "RC";
+ if (this->FortranProject) {
+ aCompilerTool = "VFResourceCompilerTool";
+ }
+ }
+ if (ext == "def") {
+ aCompilerTool = "VCCustomBuildTool";
+ if (this->FortranProject) {
+ aCompilerTool = "VFCustomBuildTool";
+ }
+ }
+ if (gg->IsMasmEnabled() && !this->FortranProject &&
+ lang == "ASM_MASM") {
+ aCompilerTool = "MASM";
+ }
+ if (acs.Kind == cmGeneratorTarget::SourceKindExternalObject) {
+ aCompilerTool = "VCCustomBuildTool";
+ }
+ for (auto const& fci : fcinfo.FileConfigMap) {
+ cmLVS7GFileConfig const& fc = fci.second;
+ fout << "\t\t\t\t<FileConfiguration\n"
+ << "\t\t\t\t\tName=\"" << fci.first << "|"
+ << gg->GetPlatformName() << "\"";
+ if (fc.ExcludedFromBuild) {
+ fout << " ExcludedFromBuild=\"true\"";
+ }
+ fout << ">\n";
+ fout << "\t\t\t\t\t<Tool\n"
+ << "\t\t\t\t\tName=\"" << aCompilerTool << "\"\n";
+ if (!fc.CompileFlags.empty() || !fc.CompileDefs.empty() ||
+ !fc.CompileDefsConfig.empty() || !fc.IncludeDirs.empty()) {
+ Options::Tool tool = Options::Compiler;
+ cmVS7FlagTable const* table =
+ cmLocalVisualStudio7GeneratorFlagTable;
+ if (this->FortranProject) {
+ tool = Options::FortranCompiler;
+ table = cmLocalVisualStudio7GeneratorFortranFlagTable;
+ }
+ Options fileOptions(this, tool, table, gg->ExtraFlagTable);
+ fileOptions.Parse(fc.CompileFlags);
+ fileOptions.AddDefines(fc.CompileDefs);
+ fileOptions.AddDefines(fc.CompileDefsConfig);
+ // validate source level include directories
+ std::vector<std::string> includes;
+ this->AppendIncludeDirectories(includes, fc.IncludeDirs, *sf);
+ fileOptions.AddIncludes(includes);
+ fileOptions.OutputFlagMap(fout, 5);
+ fileOptions.OutputAdditionalIncludeDirectories(
+ fout, 5,
+ ppLang == "CXX" && this->FortranProject ? "Fortran" : ppLang);
+ fileOptions.OutputPreprocessorDefinitions(fout, 5, ppLang);
+ }
+ if (!fc.AdditionalDeps.empty()) {
+ fout << "\t\t\t\t\tAdditionalDependencies=\"" << fc.AdditionalDeps
+ << "\"\n";
+ }
+ if (!fc.ObjectName.empty()) {
+ fout << "\t\t\t\t\tObjectFile=\"$(IntDir)/" << fc.ObjectName
+ << "\"\n";
+ }
+ fout << "\t\t\t\t\t/>\n"
+ << "\t\t\t\t</FileConfiguration>\n";
+ }
+ }
+ fout << "\t\t\t</File>\n";
+ }
+ }
+
+ // If the group has children with source files, write the children.
+ if (hasChildrenWithSources) {
+ fout << tmpOut.str();
+ }
+
+ // If the group has a name, write the footer.
+ if (!name.empty()) {
+ this->WriteVCProjEndGroup(fout);
+ }
+
+ return true;
+}
+
+void cmLocalVisualStudio7Generator::WriteCustomRule(
+ std::ostream& fout, std::vector<std::string> const& configs,
+ const char* source, const cmCustomCommand& command, FCInfo& fcinfo)
+{
+ cmGlobalVisualStudio7Generator* gg =
+ static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
+
+ // Write the rule for each configuration.
+ const char* compileTool = "VCCLCompilerTool";
+ if (this->FortranProject) {
+ compileTool = "VFCLCompilerTool";
+ }
+ const char* customTool = "VCCustomBuildTool";
+ if (this->FortranProject) {
+ customTool = "VFCustomBuildTool";
+ }
+ for (std::string const& config : configs) {
+ cmCustomCommandGenerator ccg(command, config, this);
+ cmLVS7GFileConfig const& fc = fcinfo.FileConfigMap[config];
+ fout << "\t\t\t\t<FileConfiguration\n";
+ fout << "\t\t\t\t\tName=\"" << config << "|" << gg->GetPlatformName()
+ << "\">\n";
+ if (!fc.CompileFlags.empty()) {
+ fout << "\t\t\t\t\t<Tool\n"
+ << "\t\t\t\t\tName=\"" << compileTool << "\"\n"
+ << "\t\t\t\t\tAdditionalOptions=\""
+ << this->EscapeForXML(fc.CompileFlags) << "\"/>\n";
+ }
+
+ std::string comment = this->ConstructComment(ccg);
+ std::string script = this->ConstructScript(ccg);
+ if (this->FortranProject) {
+ cmSystemTools::ReplaceString(script, "$(Configuration)", config);
+ }
+ /* clang-format off */
+ fout << "\t\t\t\t\t<Tool\n"
+ << "\t\t\t\t\tName=\"" << customTool << "\"\n"
+ << "\t\t\t\t\tDescription=\""
+ << this->EscapeForXML(comment) << "\"\n"
+ << "\t\t\t\t\tCommandLine=\""
+ << this->EscapeForXML(script) << "\"\n"
+ << "\t\t\t\t\tAdditionalDependencies=\"";
+ /* clang-format on */
+ if (ccg.GetDepends().empty()) {
+ // There are no real dependencies. Produce an artificial one to
+ // make sure the rule runs reliably.
+ if (!cmSystemTools::FileExists(source)) {
+ cmsys::ofstream depout(source);
+ depout << "Artificial dependency for a custom command.\n";
+ }
+ fout << this->ConvertToXMLOutputPath(source);
+ } else {
+ // Write out the dependencies for the rule.
+ for (std::string const& d : ccg.GetDepends()) {
+ // Get the real name of the dependency in case it is a CMake target.
+ std::string dep;
+ if (this->GetRealDependency(d, config, dep)) {
+ fout << this->ConvertToXMLOutputPath(dep) << ";";
+ }
+ }
+ }
+ fout << "\"\n";
+ fout << "\t\t\t\t\tOutputs=\"";
+ if (ccg.GetOutputs().empty()) {
+ fout << source << "_force";
+ } else {
+ // Write a rule for the output generated by this command.
+ const char* sep = "";
+ for (std::string const& output : ccg.GetOutputs()) {
+ fout << sep << this->ConvertToXMLOutputPathSingle(output);
+ sep = ";";
+ }
+ }
+ fout << "\"/>\n";
+ fout << "\t\t\t\t</FileConfiguration>\n";
+ }
+}
+
+void cmLocalVisualStudio7Generator::WriteVCProjBeginGroup(std::ostream& fout,
+ const char* group,
+ const char*)
+{
+ /* clang-format off */
+ fout << "\t\t<Filter\n"
+ << "\t\t\tName=\"" << group << "\"\n"
+ << "\t\t\tFilter=\"\">\n";
+ /* clang-format on */
+}
+
+void cmLocalVisualStudio7Generator::WriteVCProjEndGroup(std::ostream& fout)
+{
+ fout << "\t\t</Filter>\n";
+}
+
+// look for custom rules on a target and collect them together
+void cmLocalVisualStudio7Generator::OutputTargetRules(
+ std::ostream& fout, const std::string& configName, cmGeneratorTarget* target,
+ const std::string& /*libName*/)
+{
+ if (target->GetType() > cmStateEnums::GLOBAL_TARGET) {
+ return;
+ }
+ EventWriter event(this, configName, fout);
+
+ // Add pre-build event.
+ const char* tool =
+ this->FortranProject ? "VFPreBuildEventTool" : "VCPreBuildEventTool";
+ event.Start(tool);
+ event.Write(target->GetPreBuildCommands());
+ event.Finish();
+
+ // Add pre-link event.
+ tool = this->FortranProject ? "VFPreLinkEventTool" : "VCPreLinkEventTool";
+ event.Start(tool);
+ bool addedPrelink = false;
+ cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
+ target->GetModuleDefinitionInfo(configName);
+ if (mdi && mdi->DefFileGenerated) {
+ addedPrelink = true;
+ std::vector<cmCustomCommand> commands = target->GetPreLinkCommands();
+ cmGlobalVisualStudioGenerator* gg =
+ static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator);
+ gg->AddSymbolExportCommand(target, commands, configName);
+ event.Write(commands);
+ }
+ if (!addedPrelink) {
+ event.Write(target->GetPreLinkCommands());
+ }
+ std::unique_ptr<cmCustomCommand> pcc(
+ this->MaybeCreateImplibDir(target, configName, this->FortranProject));
+ if (pcc.get()) {
+ event.Write(*pcc);
+ }
+ event.Finish();
+
+ // Add post-build event.
+ tool =
+ this->FortranProject ? "VFPostBuildEventTool" : "VCPostBuildEventTool";
+ event.Start(tool);
+ event.Write(target->GetPostBuildCommands());
+ event.Finish();
+}
+
+void cmLocalVisualStudio7Generator::WriteProjectSCC(std::ostream& fout,
+ cmGeneratorTarget* target)
+{
+ // if we have all the required Source code control tags
+ // then add that to the project
+ cmProp vsProjectname = target->GetProperty("VS_SCC_PROJECTNAME");
+ cmProp vsLocalpath = target->GetProperty("VS_SCC_LOCALPATH");
+ cmProp vsProvider = target->GetProperty("VS_SCC_PROVIDER");
+
+ if (vsProvider && vsLocalpath && vsProjectname) {
+ /* clang-format off */
+ fout << "\tSccProjectName=\"" << *vsProjectname << "\"\n"
+ << "\tSccLocalPath=\"" << *vsLocalpath << "\"\n"
+ << "\tSccProvider=\"" << *vsProvider << "\"\n";
+ /* clang-format on */
+
+ cmProp vsAuxPath = target->GetProperty("VS_SCC_AUXPATH");
+ if (vsAuxPath) {
+ fout << "\tSccAuxPath=\"" << *vsAuxPath << "\"\n";
+ }
+ }
+}
+
+void cmLocalVisualStudio7Generator::WriteProjectStartFortran(
+ std::ostream& fout, const std::string& libName, cmGeneratorTarget* target)
+{
+
+ cmGlobalVisualStudio7Generator* gg =
+ static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
+ /* clang-format off */
+ fout << "<?xml version=\"1.0\" encoding = \""
+ << gg->Encoding() << "\"?>\n"
+ << "<VisualStudioProject\n"
+ << "\tProjectCreator=\"Intel Fortran\"\n"
+ << "\tVersion=\"" << gg->GetIntelProjectVersion() << "\"\n";
+ /* clang-format on */
+ cmProp p = target->GetProperty("VS_KEYWORD");
+ const char* keyword = p ? p->c_str() : "Console Application";
+ const char* projectType = 0;
+ switch (target->GetType()) {
+ case cmStateEnums::OBJECT_LIBRARY:
+ case cmStateEnums::STATIC_LIBRARY:
+ projectType = "typeStaticLibrary";
+ if (keyword) {
+ keyword = "Static Library";
+ }
+ break;
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ projectType = "typeDynamicLibrary";
+ if (!keyword) {
+ keyword = "Dll";
+ }
+ break;
+ case cmStateEnums::EXECUTABLE:
+ if (!keyword) {
+ keyword = "Console Application";
+ }
+ projectType = 0;
+ break;
+ case cmStateEnums::UTILITY:
+ case cmStateEnums::GLOBAL_TARGET:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ break;
+ }
+ if (projectType) {
+ fout << "\tProjectType=\"" << projectType << "\"\n";
+ }
+ this->WriteProjectSCC(fout, target);
+ /* clang-format off */
+ fout<< "\tKeyword=\"" << keyword << "\">\n"
+ << "\tProjectGUID=\"{" << gg->GetGUID(libName) << "}\">\n"
+ << "\t<Platforms>\n"
+ << "\t\t<Platform\n\t\t\tName=\"" << gg->GetPlatformName() << "\"/>\n"
+ << "\t</Platforms>\n";
+ /* clang-format on */
+}
+
+void cmLocalVisualStudio7Generator::WriteProjectStart(
+ std::ostream& fout, const std::string& libName, cmGeneratorTarget* target,
+ std::vector<cmSourceGroup>&)
+{
+ if (this->FortranProject) {
+ this->WriteProjectStartFortran(fout, libName, target);
+ return;
+ }
+
+ cmGlobalVisualStudio7Generator* gg =
+ static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
+
+ /* clang-format off */
+ fout << "<?xml version=\"1.0\" encoding = \""
+ << gg->Encoding() << "\"?>\n"
+ << "<VisualStudioProject\n"
+ << "\tProjectType=\"Visual C++\"\n";
+ /* clang-format on */
+ fout << "\tVersion=\"" << (gg->GetVersion() / 10) << ".00\"\n";
+ cmProp p = target->GetProperty("PROJECT_LABEL");
+ const std::string projLabel = p ? *p : libName;
+ p = target->GetProperty("VS_KEYWORD");
+ const std::string keyword = p ? *p : "Win32Proj";
+ fout << "\tName=\"" << projLabel << "\"\n";
+ fout << "\tProjectGUID=\"{" << gg->GetGUID(libName) << "}\"\n";
+ this->WriteProjectSCC(fout, target);
+ if (cmProp targetFrameworkVersion =
+ target->GetProperty("VS_DOTNET_TARGET_FRAMEWORK_VERSION")) {
+ fout << "\tTargetFrameworkVersion=\"" << *targetFrameworkVersion << "\"\n";
+ }
+ /* clang-format off */
+ fout << "\tKeyword=\"" << keyword << "\">\n"
+ << "\t<Platforms>\n"
+ << "\t\t<Platform\n\t\t\tName=\"" << gg->GetPlatformName() << "\"/>\n"
+ << "\t</Platforms>\n";
+ /* clang-format on */
+ if (gg->IsMasmEnabled()) {
+ /* clang-format off */
+ fout <<
+ "\t<ToolFiles>\n"
+ "\t\t<DefaultToolFile\n"
+ "\t\t\tFileName=\"masm.rules\"\n"
+ "\t\t/>\n"
+ "\t</ToolFiles>\n"
+ ;
+ /* clang-format on */
+ }
+}
+
+void cmLocalVisualStudio7Generator::WriteVCProjFooter(
+ std::ostream& fout, cmGeneratorTarget* target)
+{
+ fout << "\t<Globals>\n";
+
+ for (std::string const& key : target->GetPropertyKeys()) {
+ if (cmHasLiteralPrefix(key, "VS_GLOBAL_")) {
+ std::string name = key.substr(10);
+ if (!name.empty()) {
+ /* clang-format off */
+ fout << "\t\t<Global\n"
+ << "\t\t\tName=\"" << name << "\"\n"
+ << "\t\t\tValue=\"" << target->GetProperty(key) << "\"\n"
+ << "\t\t/>\n";
+ /* clang-format on */
+ }
+ }
+ }
+
+ fout << "\t</Globals>\n"
+ << "</VisualStudioProject>\n";
+}
+
+std::string cmLocalVisualStudio7Generator::EscapeForXML(const std::string& s)
+{
+ return cmLocalVisualStudio7GeneratorEscapeForXML(s);
+}
+
+std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPath(
+ const std::string& path)
+{
+ std::string ret =
+ this->ConvertToOutputFormat(path, cmOutputConverter::SHELL);
+ cmSystemTools::ReplaceString(ret, "&", "&amp;");
+ cmSystemTools::ReplaceString(ret, "\"", "&quot;");
+ cmSystemTools::ReplaceString(ret, "<", "&lt;");
+ cmSystemTools::ReplaceString(ret, ">", "&gt;");
+ return ret;
+}
+
+std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPathSingle(
+ const std::string& path)
+{
+ std::string ret =
+ this->ConvertToOutputFormat(path, cmOutputConverter::SHELL);
+ cmSystemTools::ReplaceString(ret, "\"", "");
+ cmSystemTools::ReplaceString(ret, "&", "&amp;");
+ cmSystemTools::ReplaceString(ret, "<", "&lt;");
+ cmSystemTools::ReplaceString(ret, ">", "&gt;");
+ return ret;
+}
+
+void cmVS7GeneratorOptions::OutputFlag(std::ostream& fout, int indent,
+ const std::string& flag,
+ const std::string& content)
+{
+ fout.fill('\t');
+ fout.width(indent);
+ // write an empty string to get the fill level indent to print
+ fout << "";
+ fout << flag << "=\"";
+ fout << cmLocalVisualStudio7GeneratorEscapeForXML(content);
+ fout << "\"\n";
+}
+
+// This class is used to parse an existing vs 7 project
+// and extract the GUID
+class cmVS7XMLParser : public cmXMLParser
+{
+public:
+ virtual void EndElement(const std::string& /* name */) {}
+ virtual void StartElement(const std::string& name, const char** atts)
+ {
+ // once the GUID is found do nothing
+ if (!this->GUID.empty()) {
+ return;
+ }
+ int i = 0;
+ if ("VisualStudioProject" == name) {
+ while (atts[i]) {
+ if (strcmp(atts[i], "ProjectGUID") == 0) {
+ if (atts[i + 1]) {
+ this->GUID = atts[i + 1];
+ if (this->GUID[0] == '{') {
+ // remove surrounding curly brackets
+ this->GUID = this->GUID.substr(1, this->GUID.size() - 2);
+ }
+ } else {
+ this->GUID.clear();
+ }
+ return;
+ }
+ ++i;
+ }
+ }
+ }
+ int InitializeParser()
+ {
+ int ret = cmXMLParser::InitializeParser();
+ if (ret == 0) {
+ return ret;
+ }
+ // visual studio projects have a strange encoding, but it is
+ // really utf-8
+ XML_SetEncoding(static_cast<XML_Parser>(this->Parser), "utf-8");
+ return 1;
+ }
+ std::string GUID;
+};
+
+void cmLocalVisualStudio7Generator::ReadAndStoreExternalGUID(
+ const std::string& name, const char* path)
+{
+ cmVS7XMLParser parser;
+ parser.ParseFile(path);
+ // if we can not find a GUID then we will generate one later
+ if (parser.GUID.empty()) {
+ return;
+ }
+ std::string guidStoreName = cmStrCat(name, "_GUID_CMAKE");
+ // save the GUID in the cache
+ this->GlobalGenerator->GetCMakeInstance()->AddCacheEntry(
+ guidStoreName, parser.GUID.c_str(), "Stored GUID", cmStateEnums::INTERNAL);
+}
+
+std::string cmLocalVisualStudio7Generator::GetTargetDirectory(
+ cmGeneratorTarget const* target) const
+{
+ std::string dir = cmStrCat(target->GetName(), ".dir");
+ return dir;
+}
+
+static bool cmLVS7G_IsFAT(const char* dir)
+{
+ if (dir[0] && dir[1] == ':') {
+ char volRoot[4] = "_:/";
+ volRoot[0] = dir[0];
+ char fsName[16];
+ if (GetVolumeInformationA(volRoot, 0, 0, 0, 0, 0, fsName, 16) &&
+ strstr(fsName, "FAT") != 0) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h
new file mode 100644
index 0000000..6e06c09
--- /dev/null
+++ b/Source/cmLocalVisualStudio7Generator.h
@@ -0,0 +1,160 @@
+/* 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 <iosfwd>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "cmLocalVisualStudioGenerator.h"
+#include "cmVisualStudioGeneratorOptions.h"
+
+class cmCustomCommand;
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmLocalVisualStudio7GeneratorFCInfo;
+class cmLocalVisualStudio7GeneratorInternals;
+class cmMakefile;
+class cmSourceFile;
+class cmSourceGroup;
+
+class cmVS7GeneratorOptions : public cmVisualStudioGeneratorOptions
+{
+public:
+ cmVS7GeneratorOptions(cmLocalVisualStudioGenerator* lg, Tool tool,
+ cmVS7FlagTable const* table = nullptr,
+ cmVS7FlagTable const* extraTable = nullptr)
+ : cmVisualStudioGeneratorOptions(lg, tool, table, extraTable)
+ {
+ }
+ void OutputFlag(std::ostream& fout, int indent, const std::string& tag,
+ const std::string& content) override;
+};
+
+/** \class cmLocalVisualStudio7Generator
+ * \brief Write Visual Studio .NET project files.
+ *
+ * cmLocalVisualStudio7Generator produces a Visual Studio .NET project
+ * file for each target in its directory.
+ */
+class cmLocalVisualStudio7Generator : public cmLocalVisualStudioGenerator
+{
+public:
+ //! Set cache only and recurse to false by default.
+ cmLocalVisualStudio7Generator(cmGlobalGenerator* gg, cmMakefile* mf);
+
+ virtual ~cmLocalVisualStudio7Generator();
+
+ cmLocalVisualStudio7Generator(const cmLocalVisualStudio7Generator&) = delete;
+ const cmLocalVisualStudio7Generator& operator=(
+ const cmLocalVisualStudio7Generator&) = delete;
+
+ void AddHelperCommands() override;
+
+ /**
+ * Generate the makefile for this directory.
+ */
+ void Generate() override;
+
+ enum BuildType
+ {
+ STATIC_LIBRARY,
+ DLL,
+ EXECUTABLE,
+ WIN32_EXECUTABLE,
+ UTILITY
+ };
+
+ /**
+ * Specify the type of the build: static, dll, or executable.
+ */
+ void SetBuildType(BuildType, const std::string& name);
+
+ std::string GetTargetDirectory(
+ cmGeneratorTarget const* target) const override;
+ cmSourceFile* CreateVCProjBuildRule();
+ void WriteStampFiles();
+ std::string ComputeLongestObjectDirectory(
+ cmGeneratorTarget const*) const override;
+
+ virtual void ReadAndStoreExternalGUID(const std::string& name,
+ const char* path);
+
+ std::set<cmSourceFile const*>& GetSourcesVisited(
+ cmGeneratorTarget const* target)
+ {
+ return this->SourcesVisited[target];
+ };
+
+protected:
+ virtual void GenerateTarget(cmGeneratorTarget* target);
+
+private:
+ using Options = cmVS7GeneratorOptions;
+ using FCInfo = cmLocalVisualStudio7GeneratorFCInfo;
+ std::string GetBuildTypeLinkerFlags(std::string rootLinkerFlags,
+ const std::string& configName);
+ void FixGlobalTargets();
+ void WriteVCProjHeader(std::ostream& fout, const std::string& libName,
+ cmGeneratorTarget* tgt,
+ std::vector<cmSourceGroup>& sgs);
+ void WriteVCProjFooter(std::ostream& fout, cmGeneratorTarget* target);
+ void WriteVCProjFile(std::ostream& fout, const std::string& libName,
+ cmGeneratorTarget* tgt);
+ void WriteConfigurations(std::ostream& fout,
+ std::vector<std::string> const& configs,
+ const std::string& libName, cmGeneratorTarget* tgt);
+ void WriteConfiguration(std::ostream& fout, const std::string& configName,
+ const std::string& libName, cmGeneratorTarget* tgt);
+ std::string EscapeForXML(const std::string& s);
+ std::string ConvertToXMLOutputPath(const std::string& path);
+ std::string ConvertToXMLOutputPathSingle(const std::string& path);
+ void OutputTargetRules(std::ostream& fout, const std::string& configName,
+ cmGeneratorTarget* target,
+ const std::string& libName);
+ void OutputBuildTool(std::ostream& fout, const std::string& configName,
+ cmGeneratorTarget* t, const Options& targetOptions);
+ void OutputDeploymentDebuggerTool(std::ostream& fout,
+ std::string const& config,
+ cmGeneratorTarget* target);
+ void OutputLibraryDirectories(std::ostream& fout,
+ std::vector<std::string> const& dirs);
+ void WriteProjectSCC(std::ostream& fout, cmGeneratorTarget* target);
+ void WriteProjectStart(std::ostream& fout, const std::string& libName,
+ cmGeneratorTarget* tgt,
+ std::vector<cmSourceGroup>& sgs);
+ void WriteProjectStartFortran(std::ostream& fout, const std::string& libName,
+ cmGeneratorTarget* tgt);
+ void WriteVCProjBeginGroup(std::ostream& fout, const char* group,
+ const char* filter);
+ void WriteVCProjEndGroup(std::ostream& fout);
+
+ void WriteCustomRule(std::ostream& fout,
+ std::vector<std::string> const& configs,
+ const char* source, const cmCustomCommand& command,
+ FCInfo& fcinfo);
+ void WriteTargetVersionAttribute(std::ostream& fout, cmGeneratorTarget* gt);
+
+ class AllConfigSources;
+ bool WriteGroup(const cmSourceGroup* sg, cmGeneratorTarget* target,
+ std::ostream& fout, const std::string& libName,
+ std::vector<std::string> const& configs,
+ AllConfigSources const& sources);
+
+ friend class cmLocalVisualStudio7GeneratorFCInfo;
+ friend class cmLocalVisualStudio7GeneratorInternals;
+
+ class EventWriter;
+
+ friend class EventWriter;
+
+ bool FortranProject;
+ bool WindowsCEProject;
+ std::unique_ptr<cmLocalVisualStudio7GeneratorInternals> Internal;
+
+ std::map<cmGeneratorTarget const*, std::set<cmSourceFile const*>>
+ SourcesVisited;
+};
diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx
new file mode 100644
index 0000000..6d6ed9f
--- /dev/null
+++ b/Source/cmLocalVisualStudioGenerator.cxx
@@ -0,0 +1,244 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmLocalVisualStudioGenerator.h"
+
+#include "windows.h"
+
+#include "cmCustomCommand.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmSystemTools.h"
+
+cmLocalVisualStudioGenerator::cmLocalVisualStudioGenerator(
+ cmGlobalGenerator* gg, cmMakefile* mf)
+ : cmLocalGenerator(gg, mf)
+{
+}
+
+cmLocalVisualStudioGenerator::~cmLocalVisualStudioGenerator()
+{
+}
+
+cmGlobalVisualStudioGenerator::VSVersion
+cmLocalVisualStudioGenerator::GetVersion() const
+{
+ cmGlobalVisualStudioGenerator* gg =
+ static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator);
+ return gg->GetVersion();
+}
+
+void cmLocalVisualStudioGenerator::ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* gt)
+{
+ char const* custom_ext = gt->GetCustomObjectExtension();
+ std::string dir_max = this->ComputeLongestObjectDirectory(gt);
+
+ // Count the number of object files with each name. Note that
+ // windows file names are not case sensitive.
+ std::map<std::string, int> counts;
+
+ for (auto const& si : mapping) {
+ cmSourceFile const* sf = si.first;
+ std::string objectNameLower = cmSystemTools::LowerCase(
+ cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
+ if (custom_ext) {
+ objectNameLower += custom_ext;
+ } else {
+ objectNameLower +=
+ this->GlobalGenerator->GetLanguageOutputExtension(*sf);
+ }
+ counts[objectNameLower] += 1;
+ }
+
+ // For all source files producing duplicate names we need unique
+ // object name computation.
+
+ for (auto& si : mapping) {
+ cmSourceFile const* sf = si.first;
+ std::string objectName =
+ cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
+ if (custom_ext) {
+ objectName += custom_ext;
+ } else {
+ objectName += this->GlobalGenerator->GetLanguageOutputExtension(*sf);
+ }
+ if (counts[cmSystemTools::LowerCase(objectName)] > 1) {
+ const_cast<cmGeneratorTarget*>(gt)->AddExplicitObjectName(sf);
+ bool keptSourceExtension;
+ objectName = this->GetObjectFileNameWithoutTarget(
+ *sf, dir_max, &keptSourceExtension, custom_ext);
+ }
+ si.second = objectName;
+ }
+}
+
+std::unique_ptr<cmCustomCommand>
+cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmGeneratorTarget* target,
+ const std::string& config,
+ bool isFortran)
+{
+ std::unique_ptr<cmCustomCommand> pcc;
+
+ // If an executable exports symbols then VS wants to create an
+ // import library but forgets to create the output directory.
+ // The Intel Fortran plugin always forgets to the directory.
+ if (target->GetType() != cmStateEnums::EXECUTABLE &&
+ !(isFortran && target->GetType() == cmStateEnums::SHARED_LIBRARY)) {
+ return pcc;
+ }
+ std::string outDir =
+ target->GetDirectory(config, cmStateEnums::RuntimeBinaryArtifact);
+ std::string impDir =
+ target->GetDirectory(config, cmStateEnums::ImportLibraryArtifact);
+ if (impDir == outDir) {
+ return pcc;
+ }
+
+ // Add a pre-build event to create the directory.
+ std::vector<std::string> no_output;
+ std::vector<std::string> no_byproducts;
+ std::vector<std::string> no_depends;
+ bool stdPipesUTF8 = true;
+ cmCustomCommandLines commands = cmMakeSingleCommandLine(
+ { cmSystemTools::GetCMakeCommand(), "-E", "make_directory", impDir });
+ pcc.reset(new cmCustomCommand(no_output, no_byproducts, no_depends, commands,
+ cmListFileBacktrace(), nullptr, nullptr,
+ stdPipesUTF8));
+ pcc->SetEscapeOldStyle(false);
+ pcc->SetEscapeAllowMakeVars(true);
+ return pcc;
+}
+
+const char* cmLocalVisualStudioGenerator::ReportErrorLabel() const
+{
+ return ":VCReportError";
+}
+
+const char* cmLocalVisualStudioGenerator::GetReportErrorLabel() const
+{
+ return this->ReportErrorLabel();
+}
+
+std::string cmLocalVisualStudioGenerator::ConstructScript(
+ cmCustomCommandGenerator const& ccg, const std::string& newline_text)
+{
+ bool useLocal = this->CustomCommandUseLocal();
+ std::string workingDirectory = ccg.GetWorkingDirectory();
+
+ // Avoid leading or trailing newlines.
+ std::string newline;
+
+ // Line to check for error between commands.
+ std::string check_error = newline_text;
+ if (useLocal) {
+ check_error += "if %errorlevel% neq 0 goto :cmEnd";
+ } else {
+ check_error += "if errorlevel 1 goto ";
+ check_error += this->GetReportErrorLabel();
+ }
+
+ // Store the script in a string.
+ std::string script;
+
+ // Open a local context.
+ if (useLocal) {
+ script += newline;
+ newline = newline_text;
+ script += "setlocal";
+ }
+
+ if (!workingDirectory.empty()) {
+ // Change the working directory.
+ script += newline;
+ newline = newline_text;
+ script += "cd ";
+ script += this->ConvertToOutputFormat(workingDirectory, SHELL);
+ script += check_error;
+
+ // Change the working drive.
+ if (workingDirectory.size() > 1 && workingDirectory[1] == ':') {
+ script += newline;
+ newline = newline_text;
+ script += workingDirectory[0];
+ script += workingDirectory[1];
+ script += check_error;
+ }
+ }
+
+ // for visual studio IDE add extra stuff to the PATH
+ // if CMAKE_MSVCIDE_RUN_PATH is set.
+ if (this->Makefile->GetDefinition("MSVC_IDE")) {
+ cmProp extraPath = this->Makefile->GetDefinition("CMAKE_MSVCIDE_RUN_PATH");
+ if (extraPath) {
+ script += newline;
+ newline = newline_text;
+ script += "set PATH=";
+ script += *extraPath;
+ script += ";%PATH%";
+ }
+ }
+
+ // Write each command on a single line.
+ for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
+ // Add this command line.
+ std::string cmd = ccg.GetCommand(c);
+
+ if (cmd.empty()) {
+ continue;
+ }
+
+ // Start a new line.
+ script += newline;
+ newline = newline_text;
+
+ // Use "call " before any invocations of .bat or .cmd files
+ // invoked as custom commands.
+ //
+ std::string suffix;
+ if (cmd.size() > 4) {
+ suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size() - 4));
+ if (suffix == ".bat" || suffix == ".cmd") {
+ script += "call ";
+ }
+ }
+
+ if (workingDirectory.empty()) {
+ script +=
+ this->ConvertToOutputFormat(this->MaybeConvertToRelativePath(
+ this->GetCurrentBinaryDirectory(), cmd),
+ cmOutputConverter::SHELL);
+ } else {
+ script += this->ConvertToOutputFormat(cmd.c_str(), SHELL);
+ }
+ ccg.AppendArguments(c, script);
+
+ // After each custom command, check for an error result.
+ // If there was an error, jump to the VCReportError label,
+ // skipping the run of any subsequent commands in this
+ // sequence.
+ script += check_error;
+ }
+
+ // Close the local context.
+ if (useLocal) {
+ script += newline;
+ script += ":cmEnd";
+ script += newline;
+ script += "endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone";
+ script += newline;
+ script += ":cmErrorLevel";
+ script += newline;
+ script += "exit /b %1";
+ script += newline;
+ script += ":cmDone";
+ script += newline;
+ script += "if %errorlevel% neq 0 goto ";
+ script += this->GetReportErrorLabel();
+ }
+
+ return script;
+}
diff --git a/Source/cmLocalVisualStudioGenerator.h b/Source/cmLocalVisualStudioGenerator.h
new file mode 100644
index 0000000..91fb6b0
--- /dev/null
+++ b/Source/cmLocalVisualStudioGenerator.h
@@ -0,0 +1,57 @@
+/* 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 <map>
+#include <memory>
+#include <string>
+
+#include "cmGlobalVisualStudioGenerator.h"
+#include "cmLocalGenerator.h"
+
+class cmCustomCommand;
+class cmCustomCommandGenerator;
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmMakefile;
+class cmSourceFile;
+
+/** \class cmLocalVisualStudioGenerator
+ * \brief Base class for Visual Studio generators.
+ *
+ * cmLocalVisualStudioGenerator provides functionality common to all
+ * Visual Studio generators.
+ */
+class cmLocalVisualStudioGenerator : public cmLocalGenerator
+{
+public:
+ cmLocalVisualStudioGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
+ virtual ~cmLocalVisualStudioGenerator();
+
+ /** Construct a script from the given list of command lines. */
+ std::string ConstructScript(cmCustomCommandGenerator const& ccg,
+ const std::string& newline = "\n");
+
+ /** Label to which to jump in a batch file after a failed step in a
+ sequence of custom commands. */
+ const char* GetReportErrorLabel() const;
+
+ cmGlobalVisualStudioGenerator::VSVersion GetVersion() const;
+
+ virtual std::string ComputeLongestObjectDirectory(
+ cmGeneratorTarget const*) const = 0;
+
+ void ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* = 0) override;
+
+protected:
+ virtual const char* ReportErrorLabel() const;
+ virtual bool CustomCommandUseLocal() const { return false; }
+
+ /** Construct a custom command to make exe import lib dir. */
+ std::unique_ptr<cmCustomCommand> MaybeCreateImplibDir(
+ cmGeneratorTarget* target, const std::string& config, bool isFortran);
+};
diff --git a/Source/cmLocalXCodeGenerator.cxx b/Source/cmLocalXCodeGenerator.cxx
new file mode 100644
index 0000000..3b4e3a8
--- /dev/null
+++ b/Source/cmLocalXCodeGenerator.cxx
@@ -0,0 +1,132 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmLocalXCodeGenerator.h"
+
+#include "cmGeneratorTarget.h"
+#include "cmGlobalXCodeGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmMakefile;
+
+cmLocalXCodeGenerator::cmLocalXCodeGenerator(cmGlobalGenerator* gg,
+ cmMakefile* mf)
+ : cmLocalGenerator(gg, mf)
+{
+ // the global generator does this, so do not
+ // put these flags into the language flags
+ this->EmitUniversalBinaryFlags = false;
+}
+
+cmLocalXCodeGenerator::~cmLocalXCodeGenerator() = default;
+
+std::string cmLocalXCodeGenerator::GetTargetDirectory(
+ cmGeneratorTarget const*) const
+{
+ // No per-target directory for this generator (yet).
+ return "";
+}
+
+void cmLocalXCodeGenerator::AppendFlagEscape(std::string& flags,
+ const std::string& rawFlag) const
+{
+ const cmGlobalXCodeGenerator* gg =
+ static_cast<const cmGlobalXCodeGenerator*>(this->GlobalGenerator);
+ gg->AppendFlag(flags, rawFlag);
+}
+
+void cmLocalXCodeGenerator::Generate()
+{
+ cmLocalGenerator::Generate();
+
+ for (const auto& target : this->GetGeneratorTargets()) {
+ target->HasMacOSXRpathInstallNameDir("");
+ }
+}
+
+void cmLocalXCodeGenerator::AddGeneratorSpecificInstallSetup(std::ostream& os)
+{
+ // First check if we need to warn about incompatible settings
+ for (const auto& target : this->GetGeneratorTargets()) {
+ target->HasMacOSXRpathInstallNameDir("");
+ }
+
+ // CMakeIOSInstallCombined.cmake needs to know the location of the top of
+ // the build directory
+ os << "set(CMAKE_BINARY_DIR \"" << this->GetBinaryDirectory() << "\")\n\n";
+
+ if (this->Makefile->PlatformIsAppleEmbedded()) {
+ std::string platformName;
+ switch (this->Makefile->GetAppleSDKType()) {
+ case cmMakefile::AppleSDK::IPhoneOS:
+ platformName = "iphoneos";
+ break;
+ case cmMakefile::AppleSDK::IPhoneSimulator:
+ platformName = "iphonesimulator";
+ break;
+ case cmMakefile::AppleSDK::AppleTVOS:
+ platformName = "appletvos";
+ break;
+ case cmMakefile::AppleSDK::AppleTVSimulator:
+ platformName = "appletvsimulator";
+ break;
+ case cmMakefile::AppleSDK::WatchOS:
+ platformName = "watchos";
+ break;
+ case cmMakefile::AppleSDK::WatchSimulator:
+ platformName = "watchsimulator";
+ break;
+ case cmMakefile::AppleSDK::MacOS:
+ break;
+ }
+ if (!platformName.empty()) {
+ // The effective platform name is just the platform name with a hyphen
+ // prepended. We can get the SUPPORTED_PLATFORMS from the project file
+ // at runtime, so we don't need to compute that here.
+ /* clang-format off */
+ os <<
+ "if(NOT PLATFORM_NAME)\n"
+ " if(NOT \"$ENV{PLATFORM_NAME}\" STREQUAL \"\")\n"
+ " set(PLATFORM_NAME \"$ENV{PLATFORM_NAME}\")\n"
+ " endif()\n"
+ " if(NOT PLATFORM_NAME)\n"
+ " set(PLATFORM_NAME " << platformName << ")\n"
+ " endif()\n"
+ "endif()\n\n"
+ "if(NOT EFFECTIVE_PLATFORM_NAME)\n"
+ " if(NOT \"$ENV{EFFECTIVE_PLATFORM_NAME}\" STREQUAL \"\")\n"
+ " set(EFFECTIVE_PLATFORM_NAME \"$ENV{EFFECTIVE_PLATFORM_NAME}\")\n"
+ " endif()\n"
+ " if(NOT EFFECTIVE_PLATFORM_NAME)\n"
+ " set(EFFECTIVE_PLATFORM_NAME -" << platformName << ")\n"
+ " endif()\n"
+ "endif()\n\n";
+ /* clang-format off */
+ }
+ }
+}
+
+void cmLocalXCodeGenerator::ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const*)
+{
+ // Count the number of object files with each name. Warn about duplicate
+ // names since Xcode names them uniquely automatically with a numeric suffix
+ // to avoid exact duplicate file names. Note that Mac file names are not
+ // typically case sensitive, hence the LowerCase.
+ std::map<std::string, int> counts;
+ for (auto& si : mapping) {
+ cmSourceFile const* sf = si.first;
+ std::string objectName = cmStrCat(
+ cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()), ".o");
+
+ std::string objectNameLower = cmSystemTools::LowerCase(objectName);
+ counts[objectNameLower] += 1;
+ if (2 == counts[objectNameLower]) {
+ // TODO: emit warning about duplicate name?
+ }
+ si.second = objectName;
+ }
+}
diff --git a/Source/cmLocalXCodeGenerator.h b/Source/cmLocalXCodeGenerator.h
new file mode 100644
index 0000000..5f72f6d
--- /dev/null
+++ b/Source/cmLocalXCodeGenerator.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 "cmConfigure.h" // IWYU pragma: keep
+
+#include <map>
+#include <string>
+
+#include "cmLocalGenerator.h"
+
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmMakefile;
+class cmSourceFile;
+
+/** \class cmLocalXCodeGenerator
+ * \brief Write a local Xcode project
+ *
+ * cmLocalXCodeGenerator produces a LocalUnix makefile from its
+ * member Makefile.
+ */
+class cmLocalXCodeGenerator : public cmLocalGenerator
+{
+public:
+ //! Set cache only and recurse to false by default.
+ cmLocalXCodeGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
+
+ ~cmLocalXCodeGenerator() override;
+ std::string GetTargetDirectory(
+ cmGeneratorTarget const* target) const override;
+ void AppendFlagEscape(std::string& flags,
+ const std::string& rawFlag) const override;
+ void Generate() override;
+ void AddGeneratorSpecificInstallSetup(std::ostream& os) override;
+ void ComputeObjectFilenames(
+ std::map<cmSourceFile const*, std::string>& mapping,
+ cmGeneratorTarget const* gt = nullptr) override;
+
+private:
+};
diff --git a/Source/cmLocale.h b/Source/cmLocale.h
new file mode 100644
index 0000000..f7636ac
--- /dev/null
+++ b/Source/cmLocale.h
@@ -0,0 +1,26 @@
+/* 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 <clocale>
+#include <string>
+
+class cmLocaleRAII
+{
+public:
+ cmLocaleRAII()
+ : OldLocale(setlocale(LC_CTYPE, nullptr))
+ {
+ setlocale(LC_CTYPE, "");
+ }
+
+ ~cmLocaleRAII() { setlocale(LC_CTYPE, this->OldLocale.c_str()); }
+
+ cmLocaleRAII(cmLocaleRAII const&) = delete;
+ cmLocaleRAII& operator=(cmLocaleRAII const&) = delete;
+
+private:
+ std::string OldLocale;
+};
diff --git a/Source/cmMSVC60LinkLineComputer.cxx b/Source/cmMSVC60LinkLineComputer.cxx
new file mode 100644
index 0000000..8cf3765
--- /dev/null
+++ b/Source/cmMSVC60LinkLineComputer.cxx
@@ -0,0 +1,40 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmMSVC60LinkLineComputer.h"
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include "cmSystemTools.h"
+#endif
+
+class cmOutputConverter;
+
+cmMSVC60LinkLineComputer::cmMSVC60LinkLineComputer(
+ cmOutputConverter* outputConverter, cmStateDirectory const& stateDir)
+ : cmLinkLineComputer(outputConverter, stateDir)
+{
+}
+
+std::string cmMSVC60LinkLineComputer::ConvertToLinkReference(
+ std::string const& lib) const
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // Work-ardound command line parsing limitations in MSVC 6.0
+ // Search for the last space.
+ std::string::size_type pos = lib.rfind(' ');
+ if (pos != std::string::npos) {
+ // Find the slash after the last space, if any.
+ pos = lib.find('/', pos);
+
+ // Convert the portion of the path with a space to a short path.
+ std::string sp;
+ if (cmSystemTools::GetShortPath(lib.substr(0, pos).c_str(), sp)) {
+ // Append the rest of the path with no space.
+ sp += lib.substr(pos);
+ return sp;
+ }
+ }
+#endif
+
+ return this->cmLinkLineComputer::ConvertToLinkReference(lib);
+}
diff --git a/Source/cmMSVC60LinkLineComputer.h b/Source/cmMSVC60LinkLineComputer.h
new file mode 100644
index 0000000..0a303ab
--- /dev/null
+++ b/Source/cmMSVC60LinkLineComputer.h
@@ -0,0 +1,26 @@
+/* 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 <string>
+
+#include "cmLinkLineComputer.h"
+
+class cmOutputConverter;
+class cmStateDirectory;
+
+class cmMSVC60LinkLineComputer : public cmLinkLineComputer
+{
+public:
+ cmMSVC60LinkLineComputer(cmOutputConverter* outputConverter,
+ cmStateDirectory const& stateDir);
+
+ cmMSVC60LinkLineComputer(cmMSVC60LinkLineComputer const&) = delete;
+ cmMSVC60LinkLineComputer& operator=(cmMSVC60LinkLineComputer const&) =
+ delete;
+
+ std::string ConvertToLinkReference(std::string const& input) const override;
+};
diff --git a/Source/cmMachO.cxx b/Source/cmMachO.cxx
new file mode 100644
index 0000000..53112e0
--- /dev/null
+++ b/Source/cmMachO.cxx
@@ -0,0 +1,355 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmMachO.h"
+
+#include <cstddef>
+#include <string>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmAlgorithms.h"
+
+// Include the Mach-O format information system header.
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+
+/**
+
+ https://developer.apple.com/library/mac/documentation/
+ DeveloperTools/Conceptual/MachORuntime/index.html
+
+ A Mach-O file has 3 major regions: header, load commands and segments.
+ Data Structures are provided from <mach-o/loader.h> which
+ correspond to the file structure.
+
+ The header can be either a struct mach_header or struct mach_header_64.
+ One can peek at the first 4 bytes to identify the type of header.
+
+ Following is the load command region which starts with
+ struct load_command, and is followed by n number of load commands.
+
+ In the case of a universal binary (an archive of multiple Mach-O files),
+ the file begins with a struct fat_header and is followed by multiple
+ struct fat_arch instances. The struct fat_arch indicates the offset
+ for each Mach-O file.
+
+ */
+
+namespace {
+
+// peek in the file
+template <typename T>
+bool peek(cmsys::ifstream& fin, T& v)
+{
+ std::streampos p = fin.tellg();
+ if (!fin.read(reinterpret_cast<char*>(&v), sizeof(T))) {
+ return false;
+ }
+ fin.seekg(p);
+ return fin.good();
+}
+
+// read from the file and fill a data structure
+template <typename T>
+bool read(cmsys::ifstream& fin, T& v)
+{
+ return !!fin.read(reinterpret_cast<char*>(&v), sizeof(T));
+}
+
+// read from the file and fill multiple data structures where
+// the vector has been resized
+template <typename T>
+bool read(cmsys::ifstream& fin, std::vector<T>& v)
+{
+ // nothing to read
+ if (v.empty()) {
+ return true;
+ }
+ return !!fin.read(reinterpret_cast<char*>(&v[0]), sizeof(T) * v.size());
+}
+}
+
+// Contains header and load commands for a single Mach-O file
+class cmMachOHeaderAndLoadCommands
+{
+public:
+ // A load_command and its associated data
+ struct RawLoadCommand
+ {
+ uint32_t type(const cmMachOHeaderAndLoadCommands& m) const
+ {
+ if (this->LoadCommand.size() < sizeof(load_command)) {
+ return 0;
+ }
+ const load_command* cmd =
+ reinterpret_cast<const load_command*>(&this->LoadCommand[0]);
+ return m.swap(cmd->cmd);
+ }
+ std::vector<char> LoadCommand;
+ };
+
+ cmMachOHeaderAndLoadCommands(bool _swap)
+ : Swap(_swap)
+ {
+ }
+ virtual ~cmMachOHeaderAndLoadCommands() = default;
+
+ virtual bool read_mach_o(cmsys::ifstream& fin) = 0;
+
+ const std::vector<RawLoadCommand>& load_commands() const
+ {
+ return this->LoadCommands;
+ }
+
+ uint32_t swap(uint32_t v) const
+ {
+ if (this->Swap) {
+ char* c = reinterpret_cast<char*>(&v);
+ std::swap(c[0], c[3]);
+ std::swap(c[1], c[2]);
+ }
+ return v;
+ }
+
+protected:
+ bool read_load_commands(uint32_t ncmds, uint32_t sizeofcmds,
+ cmsys::ifstream& fin);
+
+ bool Swap;
+ std::vector<RawLoadCommand> LoadCommands;
+};
+
+// Implementation for reading Mach-O header and load commands.
+// This is 32 or 64 bit arch specific.
+template <typename T>
+class cmMachOHeaderAndLoadCommandsImpl : public cmMachOHeaderAndLoadCommands
+{
+public:
+ cmMachOHeaderAndLoadCommandsImpl(bool _swap)
+ : cmMachOHeaderAndLoadCommands(_swap)
+ {
+ }
+ bool read_mach_o(cmsys::ifstream& fin) override
+ {
+ if (!read(fin, this->Header)) {
+ return false;
+ }
+ this->Header.cputype = swap(this->Header.cputype);
+ this->Header.cpusubtype = swap(this->Header.cpusubtype);
+ this->Header.filetype = swap(this->Header.filetype);
+ this->Header.ncmds = swap(this->Header.ncmds);
+ this->Header.sizeofcmds = swap(this->Header.sizeofcmds);
+ this->Header.flags = swap(this->Header.flags);
+
+ return read_load_commands(this->Header.ncmds, this->Header.sizeofcmds,
+ fin);
+ }
+
+protected:
+ T Header;
+};
+
+bool cmMachOHeaderAndLoadCommands::read_load_commands(uint32_t ncmds,
+ uint32_t sizeofcmds,
+ cmsys::ifstream& fin)
+{
+ uint32_t size_read = 0;
+ this->LoadCommands.resize(ncmds);
+ for (uint32_t i = 0; i < ncmds; i++) {
+ load_command lc;
+ if (!peek(fin, lc)) {
+ return false;
+ }
+ lc.cmd = swap(lc.cmd);
+ lc.cmdsize = swap(lc.cmdsize);
+ size_read += lc.cmdsize;
+
+ RawLoadCommand& c = this->LoadCommands[i];
+ c.LoadCommand.resize(lc.cmdsize);
+ if (!read(fin, c.LoadCommand)) {
+ return false;
+ }
+ }
+
+ if (size_read != sizeofcmds) {
+ this->LoadCommands.clear();
+ return false;
+ }
+
+ return true;
+}
+
+class cmMachOInternal
+{
+public:
+ cmMachOInternal(const char* fname);
+ cmMachOInternal(const cmMachOInternal&) = delete;
+ ~cmMachOInternal();
+
+ cmMachOInternal& operator=(const cmMachOInternal&) = delete;
+
+ // read a Mach-O file
+ bool read_mach_o(uint32_t file_offset);
+
+ // the file we are reading
+ cmsys::ifstream Fin;
+
+ // The archs in the universal binary
+ // If the binary is not a universal binary, this will be empty.
+ std::vector<fat_arch> FatArchs;
+
+ // the error message while parsing
+ std::string ErrorMessage;
+
+ // the list of Mach-O's
+ std::vector<std::unique_ptr<cmMachOHeaderAndLoadCommands>> MachOList;
+};
+
+cmMachOInternal::cmMachOInternal(const char* fname)
+ : Fin(fname)
+{
+ // Quit now if the file could not be opened.
+ if (!this->Fin || !this->Fin.get()) {
+ this->ErrorMessage = "Error opening input file.";
+ return;
+ }
+
+ if (!this->Fin.seekg(0)) {
+ this->ErrorMessage = "Error seeking to beginning of file.";
+ return;
+ }
+
+ // Read the binary identification block.
+ uint32_t magic = 0;
+ if (!peek(this->Fin, magic)) {
+ this->ErrorMessage = "Error reading Mach-O identification.";
+ return;
+ }
+
+ // Verify the binary identification.
+ if (!(magic == MH_CIGAM || magic == MH_MAGIC || magic == MH_CIGAM_64 ||
+ magic == MH_MAGIC_64 || magic == FAT_CIGAM || magic == FAT_MAGIC)) {
+ this->ErrorMessage = "File does not have a valid Mach-O identification.";
+ return;
+ }
+
+ if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
+ // this is a universal binary
+ fat_header header;
+ if (!read(this->Fin, header)) {
+ this->ErrorMessage = "Error reading fat header.";
+ return;
+ }
+
+ // read fat_archs
+ this->FatArchs.resize(OSSwapBigToHostInt32(header.nfat_arch));
+ if (!read(this->Fin, this->FatArchs)) {
+ this->ErrorMessage = "Error reading fat header archs.";
+ return;
+ }
+
+ // parse each Mach-O file
+ for (const auto& arch : this->FatArchs) {
+ if (!this->read_mach_o(OSSwapBigToHostInt32(arch.offset))) {
+ return;
+ }
+ }
+ } else {
+ // parse Mach-O file at the beginning of the file
+ this->read_mach_o(0);
+ }
+}
+
+cmMachOInternal::~cmMachOInternal() = default;
+
+bool cmMachOInternal::read_mach_o(uint32_t file_offset)
+{
+ if (!this->Fin.seekg(file_offset)) {
+ this->ErrorMessage = "Failed to locate Mach-O content.";
+ return false;
+ }
+
+ uint32_t magic;
+ if (!peek(this->Fin, magic)) {
+ this->ErrorMessage = "Error reading Mach-O identification.";
+ return false;
+ }
+
+ std::unique_ptr<cmMachOHeaderAndLoadCommands> f;
+ if (magic == MH_CIGAM || magic == MH_MAGIC) {
+ bool swap = false;
+ if (magic == MH_CIGAM) {
+ swap = true;
+ }
+ f = cm::make_unique<cmMachOHeaderAndLoadCommandsImpl<mach_header>>(swap);
+ } else if (magic == MH_CIGAM_64 || magic == MH_MAGIC_64) {
+ bool swap = false;
+ if (magic == MH_CIGAM_64) {
+ swap = true;
+ }
+ f =
+ cm::make_unique<cmMachOHeaderAndLoadCommandsImpl<mach_header_64>>(swap);
+ }
+
+ if (f && f->read_mach_o(this->Fin)) {
+ this->MachOList.push_back(std::move(f));
+ } else {
+ this->ErrorMessage = "Failed to read Mach-O header.";
+ return false;
+ }
+
+ return true;
+}
+
+//============================================================================
+// External class implementation.
+
+cmMachO::cmMachO(const char* fname)
+ : Internal(cm::make_unique<cmMachOInternal>(fname))
+{
+}
+
+cmMachO::~cmMachO() = default;
+
+std::string const& cmMachO::GetErrorMessage() const
+{
+ return this->Internal->ErrorMessage;
+}
+
+bool cmMachO::Valid() const
+{
+ return !this->Internal->MachOList.empty();
+}
+
+bool cmMachO::GetInstallName(std::string& install_name)
+{
+ if (this->Internal->MachOList.empty()) {
+ return false;
+ }
+
+ // grab the first Mach-O and get the install name from that one
+ std::unique_ptr<cmMachOHeaderAndLoadCommands>& macho =
+ this->Internal->MachOList[0];
+ for (size_t i = 0; i < macho->load_commands().size(); i++) {
+ const cmMachOHeaderAndLoadCommands::RawLoadCommand& cmd =
+ macho->load_commands()[i];
+ uint32_t lc_cmd = cmd.type(*macho);
+ if (lc_cmd == LC_ID_DYLIB || lc_cmd == LC_LOAD_WEAK_DYLIB ||
+ lc_cmd == LC_LOAD_DYLIB) {
+ if (sizeof(dylib_command) < cmd.LoadCommand.size()) {
+ uint32_t namelen = cmd.LoadCommand.size() - sizeof(dylib_command);
+ install_name.assign(&cmd.LoadCommand[sizeof(dylib_command)], namelen);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void cmMachO::PrintInfo(std::ostream& /*os*/) const
+{
+}
diff --git a/Source/cmMachO.h b/Source/cmMachO.h
new file mode 100644
index 0000000..faa024b
--- /dev/null
+++ b/Source/cmMachO.h
@@ -0,0 +1,44 @@
+/* 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 <iosfwd>
+#include <string>
+
+#if !defined(CMake_USE_MACH_PARSER)
+# error "This file may be included only if CMake_USE_MACH_PARSER is enabled."
+#endif
+
+class cmMachOInternal;
+
+/** \class cmMachO
+ * \brief Executable and Link Format (Mach-O) parser.
+ */
+class cmMachO
+{
+public:
+ /** Construct with the name of the Mach-O input file to parse. */
+ cmMachO(const char* fname);
+
+ /** Destruct. */
+ ~cmMachO();
+
+ /** Get the error message if any. */
+ std::string const& GetErrorMessage() const;
+
+ /** Boolean conversion. True if the Mach-O file is valid. */
+ explicit operator bool() const { return this->Valid(); }
+
+ /** Get Install name from binary **/
+ bool GetInstallName(std::string& install_name);
+
+ /** Print human-readable information about the Mach-O file. */
+ void PrintInfo(std::ostream& os) const;
+
+private:
+ friend class cmMachOInternal;
+ bool Valid() const;
+ std::unique_ptr<cmMachOInternal> Internal;
+};
diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx
new file mode 100644
index 0000000..8c4b2a7
--- /dev/null
+++ b/Source/cmMacroCommand.cxx
@@ -0,0 +1,197 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmMacroCommand.h"
+
+#include <cstdio>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmExecutionStatus.h"
+#include "cmFunctionBlocker.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmPolicies.h"
+#include "cmRange.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+
+// define the class for macro commands
+class cmMacroHelperCommand
+{
+public:
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool operator()(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& inStatus) const;
+
+ std::vector<std::string> Args;
+ std::vector<cmListFileFunction> Functions;
+ cmPolicies::PolicyMap Policies;
+ std::string FilePath;
+};
+
+bool cmMacroHelperCommand::operator()(
+ std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& inStatus) const
+{
+ cmMakefile& makefile = inStatus.GetMakefile();
+
+ // Expand the argument list to the macro.
+ std::vector<std::string> expandedArgs;
+ makefile.ExpandArguments(args, expandedArgs);
+
+ // make sure the number of arguments passed is at least the number
+ // required by the signature
+ if (expandedArgs.size() < this->Args.size() - 1) {
+ std::string errorMsg =
+ cmStrCat("Macro invoked with incorrect arguments for macro named: ",
+ this->Args[0]);
+ inStatus.SetError(errorMsg);
+ return false;
+ }
+
+ cmMakefile::MacroPushPop macroScope(&makefile, this->FilePath,
+ this->Policies);
+
+ // set the value of argc
+ std::string argcDef = std::to_string(expandedArgs.size());
+
+ auto eit = expandedArgs.begin() + (this->Args.size() - 1);
+ std::string expandedArgn = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";");
+ std::string expandedArgv = cmJoin(expandedArgs, ";");
+ std::vector<std::string> variables;
+ variables.reserve(this->Args.size() - 1);
+ for (unsigned int j = 1; j < this->Args.size(); ++j) {
+ variables.push_back("${" + this->Args[j] + "}");
+ }
+ std::vector<std::string> argVs;
+ argVs.reserve(expandedArgs.size());
+ char argvName[60];
+ for (unsigned int j = 0; j < expandedArgs.size(); ++j) {
+ sprintf(argvName, "${ARGV%u}", j);
+ argVs.emplace_back(argvName);
+ }
+ // Invoke all the functions that were collected in the block.
+ // for each function
+ for (cmListFileFunction const& func : this->Functions) {
+ // Replace the formal arguments and then invoke the command.
+ std::vector<cmListFileArgument> newLFFArgs;
+ newLFFArgs.reserve(func.Arguments().size());
+
+ // for each argument of the current function
+ for (cmListFileArgument const& k : func.Arguments()) {
+ cmListFileArgument arg;
+ arg.Value = k.Value;
+ if (k.Delim != cmListFileArgument::Bracket) {
+ // replace formal arguments
+ for (unsigned int j = 0; j < variables.size(); ++j) {
+ cmSystemTools::ReplaceString(arg.Value, variables[j],
+ expandedArgs[j]);
+ }
+ // replace argc
+ cmSystemTools::ReplaceString(arg.Value, "${ARGC}", argcDef);
+
+ cmSystemTools::ReplaceString(arg.Value, "${ARGN}", expandedArgn);
+ cmSystemTools::ReplaceString(arg.Value, "${ARGV}", expandedArgv);
+
+ // if the current argument of the current function has ${ARGV in it
+ // then try replacing ARGV values
+ if (arg.Value.find("${ARGV") != std::string::npos) {
+ for (unsigned int t = 0; t < expandedArgs.size(); ++t) {
+ cmSystemTools::ReplaceString(arg.Value, argVs[t], expandedArgs[t]);
+ }
+ }
+ }
+ arg.Delim = k.Delim;
+ arg.Line = k.Line;
+ newLFFArgs.push_back(std::move(arg));
+ }
+ cmListFileFunction newLFF{ func.OriginalName(), func.Line(),
+ std::move(newLFFArgs) };
+ cmExecutionStatus status(makefile);
+ if (!makefile.ExecuteCommand(newLFF, status) || status.GetNestedError()) {
+ // The error message should have already included the call stack
+ // so we do not need to report an error here.
+ macroScope.Quiet();
+ inStatus.SetNestedError();
+ return false;
+ }
+ if (status.GetReturnInvoked()) {
+ inStatus.SetReturnInvoked();
+ return true;
+ }
+ if (status.GetBreakInvoked()) {
+ inStatus.SetBreakInvoked();
+ return true;
+ }
+ }
+ return true;
+}
+
+class cmMacroFunctionBlocker : public cmFunctionBlocker
+{
+public:
+ cm::string_view StartCommandName() const override { return "macro"_s; }
+ cm::string_view EndCommandName() const override { return "endmacro"_s; }
+
+ bool ArgumentsMatch(cmListFileFunction const&,
+ cmMakefile& mf) const override;
+
+ bool Replay(std::vector<cmListFileFunction> functions,
+ cmExecutionStatus& status) override;
+
+ std::vector<std::string> Args;
+};
+
+bool cmMacroFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
+ cmMakefile& mf) const
+{
+ std::vector<std::string> expandedArguments;
+ mf.ExpandArguments(lff.Arguments(), expandedArguments);
+ return expandedArguments.empty() || expandedArguments[0] == this->Args[0];
+}
+
+bool cmMacroFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
+ cmExecutionStatus& status)
+{
+ cmMakefile& mf = status.GetMakefile();
+ mf.AppendProperty("MACROS", this->Args[0]);
+ // create a new command and add it to cmake
+ cmMacroHelperCommand f;
+ f.Args = this->Args;
+ f.Functions = std::move(functions);
+ f.FilePath = this->GetStartingContext().FilePath;
+ mf.RecordPolicies(f.Policies);
+ return mf.GetState()->AddScriptedCommand(
+ this->Args[0],
+ BT<cmState::Command>(std::move(f),
+ mf.GetBacktrace().Push(this->GetStartingContext())),
+ mf);
+}
+}
+
+bool cmMacroCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // create a function blocker
+ {
+ auto fb = cm::make_unique<cmMacroFunctionBlocker>();
+ cm::append(fb->Args, args);
+ status.GetMakefile().AddFunctionBlocker(std::move(fb));
+ }
+ return true;
+}
diff --git a/Source/cmMacroCommand.h b/Source/cmMacroCommand.h
new file mode 100644
index 0000000..b65a887
--- /dev/null
+++ b/Source/cmMacroCommand.h
@@ -0,0 +1,14 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/// Starts macro() ... endmacro() block
+bool cmMacroCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmMakeDirectoryCommand.cxx b/Source/cmMakeDirectoryCommand.cxx
new file mode 100644
index 0000000..cdde6f9
--- /dev/null
+++ b/Source/cmMakeDirectoryCommand.cxx
@@ -0,0 +1,26 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmMakeDirectoryCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+// cmMakeDirectoryCommand
+bool cmMakeDirectoryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 1) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ if (!status.GetMakefile().CanIWriteThisFile(args[0])) {
+ std::string e = "attempted to create a directory: " + args[0] +
+ " into a source directory.";
+ status.SetError(e);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ cmSystemTools::MakeDirectory(args[0]);
+ return true;
+}
diff --git a/Source/cmMakeDirectoryCommand.h b/Source/cmMakeDirectoryCommand.h
new file mode 100644
index 0000000..340bca8
--- /dev/null
+++ b/Source/cmMakeDirectoryCommand.h
@@ -0,0 +1,22 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Specify auxiliary source code directories.
+ *
+ * cmMakeDirectoryCommand specifies source code directories
+ * that must be built as part of this build process. This directories
+ * are not recursively processed like the SUBDIR command (cmSubdirCommand).
+ * A side effect of this command is to create a subdirectory in the build
+ * directory structure.
+ */
+bool cmMakeDirectoryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
new file mode 100644
index 0000000..40a67a3
--- /dev/null
+++ b/Source/cmMakefile.cxx
@@ -0,0 +1,4517 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmMakefile.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <sstream>
+#include <utility>
+
+#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>
+
+#ifndef CMAKE_BOOTSTRAP
+# include <cm3p/json/value.h>
+# include <cm3p/json/writer.h>
+#endif
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCommandArgumentParserHelper.h"
+#include "cmCustomCommand.h"
+#include "cmCustomCommandLines.h"
+#include "cmExecutionStatus.h"
+#include "cmExpandedCommandArgument.h" // IWYU pragma: keep
+#include "cmExportBuildFileGenerator.h"
+#include "cmFileLockPool.h"
+#include "cmFunctionBlocker.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionEvaluationFile.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallGenerator.h" // IWYU pragma: keep
+#include "cmInstallSubdirectoryGenerator.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMessageType.h"
+#include "cmRange.h"
+#include "cmSourceFile.h"
+#include "cmSourceFileLocation.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetLinkLibraryType.h"
+#include "cmTest.h"
+#include "cmTestGenerator.h" // IWYU pragma: keep
+#include "cmVersion.h"
+#include "cmWorkingDirectory.h"
+#include "cmake.h"
+
+#ifndef CMAKE_BOOTSTRAP
+# include "cmMakefileProfilingData.h"
+# include "cmVariableWatch.h"
+#endif
+
+class cmMessenger;
+
+cmDirectoryId::cmDirectoryId(std::string s)
+ : String(std::move(s))
+{
+}
+
+// default is not to be building executables
+cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator,
+ cmStateSnapshot const& snapshot)
+ : GlobalGenerator(globalGenerator)
+ , StateSnapshot(snapshot)
+ , Backtrace(snapshot)
+{
+ this->IsSourceFileTryCompile = false;
+
+ this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars();
+
+ this->SuppressSideEffects = false;
+
+ // Setup the default include complaint regular expression (match nothing).
+ this->ComplainFileRegularExpression = "^$";
+
+ this->DefineFlags = " ";
+
+ this->cmDefineRegex.compile("#([ \t]*)cmakedefine[ \t]+([A-Za-z_0-9]*)");
+ this->cmDefine01Regex.compile("#([ \t]*)cmakedefine01[ \t]+([A-Za-z_0-9]*)");
+ this->cmAtVarRegex.compile("(@[A-Za-z_0-9/.+-]+@)");
+ this->cmNamedCurly.compile("^[A-Za-z0-9/_.+-]+{");
+
+ this->StateSnapshot =
+ this->StateSnapshot.GetState()->CreatePolicyScopeSnapshot(
+ this->StateSnapshot);
+ this->RecursionDepth = 0;
+
+ // Enter a policy level for this directory.
+ this->PushPolicy();
+
+ // push empty loop block
+ this->PushLoopBlockBarrier();
+
+ // By default the check is not done. It is enabled by
+ // cmListFileCache in the top level if necessary.
+ this->CheckCMP0000 = false;
+
+#if !defined(CMAKE_BOOTSTRAP)
+ this->AddSourceGroup("", "^.*$");
+ this->AddSourceGroup("Source Files", CM_SOURCE_REGEX);
+ this->AddSourceGroup("Header Files", CM_HEADER_REGEX);
+ this->AddSourceGroup("Precompile Header File", CM_PCH_REGEX);
+ this->AddSourceGroup("CMake Rules", "\\.rule$");
+ this->AddSourceGroup("Resources", CM_RESOURCE_REGEX);
+ this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$");
+
+ this->ObjectLibrariesSourceGroupIndex = this->SourceGroups.size();
+ this->SourceGroups.emplace_back("Object Libraries", "^MATCH_NO_SOURCES$");
+#endif
+}
+
+cmMakefile::~cmMakefile() = default;
+
+cmDirectoryId cmMakefile::GetDirectoryId() const
+{
+ // Use the instance pointer value to uniquely identify this directory.
+ // If we ever need to expose this to CMake language code we should
+ // add a read-only property in cmMakefile::GetProperty.
+ char buf[32];
+ sprintf(buf, "(%p)",
+ static_cast<void const*>(this)); // cast avoids format warning
+ return std::string(buf);
+}
+
+void cmMakefile::IssueMessage(MessageType t, std::string const& text) const
+{
+ if (!this->ExecutionStatusStack.empty()) {
+ if ((t == MessageType::FATAL_ERROR) ||
+ (t == MessageType::INTERNAL_ERROR)) {
+ this->ExecutionStatusStack.back()->SetNestedError();
+ }
+ }
+ this->GetCMakeInstance()->IssueMessage(t, text, this->Backtrace);
+}
+
+bool cmMakefile::CheckCMP0037(std::string const& targetName,
+ cmStateEnums::TargetType targetType) const
+{
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+ std::ostringstream e;
+ bool issueMessage = false;
+ switch (this->GetPolicyStatus(cmPolicies::CMP0037)) {
+ case cmPolicies::WARN:
+ if (targetType != cmStateEnums::INTERFACE_LIBRARY) {
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n";
+ issueMessage = true;
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ issueMessage = true;
+ messageType = MessageType::FATAL_ERROR;
+ break;
+ }
+ if (issueMessage) {
+ e << "The target name \"" << targetName
+ << "\" is reserved or not valid for certain "
+ "CMake features, such as generator expressions, and may result "
+ "in undefined behavior.";
+ this->IssueMessage(messageType, e.str());
+
+ if (messageType == MessageType::FATAL_ERROR) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void cmMakefile::MaybeWarnCMP0074(std::string const& pkg)
+{
+ // Warn if a <pkg>_ROOT variable we may use is set.
+ std::string const varName = pkg + "_ROOT";
+ cmProp var = this->GetDefinition(varName);
+ std::string env;
+ cmSystemTools::GetEnv(varName, env);
+
+ bool const haveVar = cmNonempty(var);
+ bool const haveEnv = !env.empty();
+ if ((haveVar || haveEnv) && this->WarnedCMP0074.insert(varName).second) {
+ std::ostringstream w;
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0074) << "\n";
+ if (haveVar) {
+ w << "CMake variable " << varName << " is set to:\n"
+ << " " << *var << "\n";
+ }
+ if (haveEnv) {
+ w << "Environment variable " << varName << " is set to:\n"
+ << " " << env << "\n";
+ }
+ w << "For compatibility, CMake is ignoring the variable.";
+ this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+}
+
+cmStringRange cmMakefile::GetIncludeDirectoriesEntries() const
+{
+ return this->StateSnapshot.GetDirectory().GetIncludeDirectoriesEntries();
+}
+
+cmBacktraceRange cmMakefile::GetIncludeDirectoriesBacktraces() const
+{
+ return this->StateSnapshot.GetDirectory()
+ .GetIncludeDirectoriesEntryBacktraces();
+}
+
+cmStringRange cmMakefile::GetCompileOptionsEntries() const
+{
+ return this->StateSnapshot.GetDirectory().GetCompileOptionsEntries();
+}
+
+cmBacktraceRange cmMakefile::GetCompileOptionsBacktraces() const
+{
+ return this->StateSnapshot.GetDirectory().GetCompileOptionsEntryBacktraces();
+}
+
+cmStringRange cmMakefile::GetCompileDefinitionsEntries() const
+{
+ return this->StateSnapshot.GetDirectory().GetCompileDefinitionsEntries();
+}
+
+cmBacktraceRange cmMakefile::GetCompileDefinitionsBacktraces() const
+{
+ return this->StateSnapshot.GetDirectory()
+ .GetCompileDefinitionsEntryBacktraces();
+}
+
+cmStringRange cmMakefile::GetLinkOptionsEntries() const
+{
+ return this->StateSnapshot.GetDirectory().GetLinkOptionsEntries();
+}
+
+cmBacktraceRange cmMakefile::GetLinkOptionsBacktraces() const
+{
+ return this->StateSnapshot.GetDirectory().GetLinkOptionsEntryBacktraces();
+}
+
+cmStringRange cmMakefile::GetLinkDirectoriesEntries() const
+{
+ return this->StateSnapshot.GetDirectory().GetLinkDirectoriesEntries();
+}
+
+cmBacktraceRange cmMakefile::GetLinkDirectoriesBacktraces() const
+{
+ return this->StateSnapshot.GetDirectory()
+ .GetLinkDirectoriesEntryBacktraces();
+}
+
+cmListFileBacktrace cmMakefile::GetBacktrace() const
+{
+ return this->Backtrace;
+}
+
+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->GetBacktrace().Top().FilePath;
+ std::string const& only_filename = cmSystemTools::GetFilenameName(full_path);
+ bool trace = trace_only_this_files.empty();
+ if (!trace) {
+ for (std::string const& file : trace_only_this_files) {
+ std::string::size_type const pos = full_path.rfind(file);
+ trace = (pos != std::string::npos) &&
+ ((pos + file.size()) == full_path.size()) &&
+ (only_filename == cmSystemTools::GetFilenameName(file));
+ if (trace) {
+ break;
+ }
+ }
+ // Do nothing if current file wasn't requested for trace...
+ if (!trace) {
+ return;
+ }
+ }
+
+ std::ostringstream msg;
+ std::vector<std::string> args;
+ std::string temp;
+ bool expand = this->GetCMakeInstance()->GetTraceExpand();
+
+ args.reserve(lff.Arguments().size());
+ for (cmListFileArgument const& arg : lff.Arguments()) {
+ if (expand && arg.Delim != cmListFileArgument::Bracket) {
+ temp = arg.Value;
+ this->ExpandVariablesInString(temp);
+ args.push_back(temp);
+ } else {
+ args.push_back(arg.Value);
+ }
+ }
+
+ switch (this->GetCMakeInstance()->GetTraceFormat()) {
+ case cmake::TraceFormat::TRACE_JSON_V1: {
+#ifndef CMAKE_BOOTSTRAP
+ Json::Value val;
+ Json::StreamWriterBuilder builder;
+ builder["indentation"] = "";
+ val["file"] = full_path;
+ val["line"] = static_cast<Json::Value::Int64>(lff.Line());
+ if (deferId) {
+ val["defer"] = *deferId;
+ }
+ val["cmd"] = lff.OriginalName();
+ val["args"] = Json::Value(Json::arrayValue);
+ for (std::string const& arg : args) {
+ val["args"].append(arg);
+ }
+ val["time"] = cmSystemTools::GetTime();
+ val["frame"] =
+ static_cast<Json::Value::UInt64>(this->ExecutionStatusStack.size());
+ msg << Json::writeString(builder, val);
+#endif
+ break;
+ }
+ case cmake::TraceFormat::TRACE_HUMAN:
+ msg << full_path << "(" << lff.Line() << "):";
+ if (deferId) {
+ msg << "DEFERRED:" << *deferId << ":";
+ }
+ msg << " " << lff.OriginalName() << "(";
+
+ for (std::string const& arg : args) {
+ msg << arg << " ";
+ }
+ msg << ")";
+ break;
+ case cmake::TraceFormat::TRACE_UNDEFINED:
+ msg << "INTERNAL ERROR: Trace format is TRACE_UNDEFINED";
+ break;
+ }
+
+ auto& f = this->GetCMakeInstance()->GetTraceFile();
+ if (f) {
+ f << msg.str() << '\n';
+ } else {
+ cmSystemTools::Message(msg.str());
+ }
+}
+
+// Helper class to make sure the call stack is valid.
+class cmMakefileCall
+{
+public:
+ cmMakefileCall(cmMakefile* mf, cmListFileFunction const& lff,
+ cm::optional<std::string> deferId, cmExecutionStatus& status)
+ : Makefile(mf)
+ {
+ cmListFileContext const& lfc = cmListFileContext::FromCommandContext(
+ 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);
+#if !defined(CMAKE_BOOTSTRAP)
+ if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) {
+ this->Makefile->GetCMakeInstance()->GetProfilingOutput().StartEntry(lff,
+ lfc);
+ }
+#endif
+ }
+
+ ~cmMakefileCall()
+ {
+#if !defined(CMAKE_BOOTSTRAP)
+ if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) {
+ this->Makefile->GetCMakeInstance()->GetProfilingOutput().StopEntry();
+ }
+#endif
+ this->Makefile->ExecutionStatusStack.pop_back();
+ --this->Makefile->RecursionDepth;
+ this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
+ }
+
+ cmMakefileCall(const cmMakefileCall&) = delete;
+ cmMakefileCall& operator=(const cmMakefileCall&) = delete;
+
+private:
+ cmMakefile* Makefile;
+};
+
+void cmMakefile::OnExecuteCommand(std::function<void()> callback)
+{
+ this->ExecuteCommandCallback = std::move(callback);
+}
+
+bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
+ cmExecutionStatus& status,
+ cm::optional<std::string> deferId)
+{
+ bool result = true;
+
+ // quick return if blocked
+ if (this->IsFunctionBlocked(lff, status)) {
+ // No error.
+ return result;
+ }
+
+ if (this->ExecuteCommandCallback) {
+ this->ExecuteCommandCallback();
+ }
+
+ // Place this call on the call stack.
+ cmMakefileCall stack_manager(this, lff, std::move(deferId), status);
+ static_cast<void>(stack_manager);
+
+ // Check for maximum recursion depth.
+ int depth = CMake_DEFAULT_RECURSION_LIMIT;
+ cmProp depthStr = this->GetDefinition("CMAKE_MAXIMUM_RECURSION_DEPTH");
+ if (depthStr) {
+ std::istringstream s(*depthStr);
+ int d;
+ if (s >> d) {
+ depth = d;
+ }
+ }
+ if (this->RecursionDepth > depth) {
+ std::ostringstream e;
+ e << "Maximum recursion depth of " << depth << " exceeded";
+ this->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ // Lookup the command prototype.
+ if (cmState::Command command =
+ this->GetState()->GetCommandByExactName(lff.LowerCaseName())) {
+ // Decide whether to invoke the command.
+ if (!cmSystemTools::GetFatalErrorOccured()) {
+ // if trace is enabled, print out invoke information
+ if (this->GetCMakeInstance()->GetTrace()) {
+ this->PrintCommandTrace(lff, this->Backtrace.Top().DeferId);
+ }
+ // Try invoking the command.
+ bool invokeSucceeded = command(lff.Arguments(), status);
+ bool hadNestedError = status.GetNestedError();
+ if (!invokeSucceeded || hadNestedError) {
+ if (!hadNestedError) {
+ // The command invocation requested that we report an error.
+ std::string const error =
+ std::string(lff.OriginalName()) + " " + status.GetError();
+ this->IssueMessage(MessageType::FATAL_ERROR, error);
+ }
+ result = false;
+ if (this->GetCMakeInstance()->GetWorkingMode() != cmake::NORMAL_MODE) {
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ }
+ }
+ } else {
+ if (!cmSystemTools::GetFatalErrorOccured()) {
+ std::string error =
+ cmStrCat("Unknown CMake command \"", lff.OriginalName(), "\".");
+ this->IssueMessage(MessageType::FATAL_ERROR, error);
+ result = false;
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ }
+
+ return result;
+}
+
+class cmMakefile::IncludeScope
+{
+public:
+ IncludeScope(cmMakefile* mf, std::string const& filenametoread,
+ bool noPolicyScope);
+ ~IncludeScope();
+ void Quiet() { this->ReportError = false; }
+
+ IncludeScope(const IncludeScope&) = delete;
+ IncludeScope& operator=(const IncludeScope&) = delete;
+
+private:
+ cmMakefile* Makefile;
+ bool NoPolicyScope;
+ bool CheckCMP0011;
+ bool ReportError;
+ void EnforceCMP0011();
+};
+
+cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf,
+ std::string const& filenametoread,
+ bool noPolicyScope)
+ : Makefile(mf)
+ , NoPolicyScope(noPolicyScope)
+ , CheckCMP0011(false)
+ , ReportError(true)
+{
+ this->Makefile->Backtrace = this->Makefile->Backtrace.Push(filenametoread);
+
+ this->Makefile->PushFunctionBlockerBarrier();
+
+ this->Makefile->StateSnapshot =
+ this->Makefile->GetState()->CreateIncludeFileSnapshot(
+ this->Makefile->StateSnapshot, filenametoread);
+ if (!this->NoPolicyScope) {
+ // Check CMP0011 to determine the policy scope type.
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0011)) {
+ case cmPolicies::WARN:
+ // We need to push a scope to detect whether the script sets
+ // any policies that would affect the includer and therefore
+ // requires a warning. We use a weak scope to simulate OLD
+ // behavior by allowing policy changes to affect the includer.
+ this->Makefile->PushPolicy(true);
+ this->CheckCMP0011 = true;
+ break;
+ case cmPolicies::OLD:
+ // OLD behavior is to not push a scope at all.
+ this->NoPolicyScope = true;
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ // We should never make this policy required, but we handle it
+ // here just in case.
+ this->CheckCMP0011 = true;
+ CM_FALLTHROUGH;
+ case cmPolicies::NEW:
+ // NEW behavior is to push a (strong) scope.
+ this->Makefile->PushPolicy();
+ break;
+ }
+ }
+}
+
+cmMakefile::IncludeScope::~IncludeScope()
+{
+ if (!this->NoPolicyScope) {
+ // If we need to enforce policy CMP0011 then the top entry is the
+ // one we pushed above. If the entry is empty, then the included
+ // script did not set any policies that might affect the includer so
+ // we do not need to enforce the policy.
+ if (this->CheckCMP0011 &&
+ !this->Makefile->StateSnapshot.HasDefinedPolicyCMP0011()) {
+ this->CheckCMP0011 = false;
+ }
+
+ // Pop the scope we pushed for the script.
+ this->Makefile->PopPolicy();
+
+ // We enforce the policy after the script's policy stack entry has
+ // been removed.
+ if (this->CheckCMP0011) {
+ this->EnforceCMP0011();
+ }
+ }
+ this->Makefile->PopSnapshot(this->ReportError);
+
+ this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
+
+ this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
+}
+
+void cmMakefile::IncludeScope::EnforceCMP0011()
+{
+ // We check the setting of this policy again because the included
+ // script might actually set this policy for its includer.
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0011)) {
+ case cmPolicies::WARN:
+ // Warn because the user did not set this policy.
+ {
+ std::ostringstream w;
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0011) << "\n"
+ << "The included script\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.";
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS: {
+ std::ostringstream e;
+ /* clang-format off */
+ e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0011) << "\n"
+ << "The included script\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());
+ } break;
+ case cmPolicies::OLD:
+ case cmPolicies::NEW:
+ // The script set this policy. We assume the purpose of the
+ // script is to initialize policies for its includer, and since
+ // the policy is now set for later scripts, we do not warn.
+ break;
+ }
+}
+
+bool cmMakefile::ReadDependentFile(const std::string& filename,
+ bool noPolicyScope)
+{
+ if (cmProp def = this->GetDefinition("CMAKE_CURRENT_LIST_FILE")) {
+ this->AddDefinition("CMAKE_PARENT_LIST_FILE", *def);
+ }
+ std::string filenametoread = cmSystemTools::CollapseFullPath(
+ filename, this->GetCurrentSourceDirectory());
+
+ IncludeScope incScope(this, filenametoread, noPolicyScope);
+
+ cmListFile listFile;
+ if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(),
+ this->Backtrace)) {
+ return false;
+ }
+
+ this->RunListFile(listFile, filenametoread);
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ incScope.Quiet();
+ }
+ return true;
+}
+
+class cmMakefile::ListFileScope
+{
+public:
+ ListFileScope(cmMakefile* mf, std::string const& filenametoread)
+ : Makefile(mf)
+ , ReportError(true)
+ {
+ this->Makefile->Backtrace = this->Makefile->Backtrace.Push(filenametoread);
+
+ this->Makefile->StateSnapshot =
+ this->Makefile->GetState()->CreateInlineListFileSnapshot(
+ this->Makefile->StateSnapshot, filenametoread);
+ assert(this->Makefile->StateSnapshot.IsValid());
+
+ this->Makefile->PushFunctionBlockerBarrier();
+ }
+
+ ~ListFileScope()
+ {
+ this->Makefile->PopSnapshot(this->ReportError);
+ this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
+ this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
+ }
+
+ void Quiet() { this->ReportError = false; }
+
+ ListFileScope(const ListFileScope&) = delete;
+ ListFileScope& operator=(const ListFileScope&) = delete;
+
+private:
+ cmMakefile* Makefile;
+ 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(
+ filename, this->GetCurrentSourceDirectory());
+
+ ListFileScope scope(this, filenametoread);
+
+ cmListFile listFile;
+ if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(),
+ this->Backtrace)) {
+ return false;
+ }
+
+ this->RunListFile(listFile, filenametoread);
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ scope.Quiet();
+ }
+ return true;
+}
+
+bool cmMakefile::ReadListFileAsString(const std::string& content,
+ const std::string& virtualFileName)
+{
+ std::string filenametoread = cmSystemTools::CollapseFullPath(
+ virtualFileName, this->GetCurrentSourceDirectory());
+
+ ListFileScope scope(this, filenametoread);
+
+ cmListFile listFile;
+ if (!listFile.ParseString(content.c_str(), virtualFileName.c_str(),
+ this->GetMessenger(), this->Backtrace)) {
+ return false;
+ }
+
+ this->RunListFile(listFile, filenametoread);
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ scope.Quiet();
+ }
+ return true;
+}
+
+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);
+
+ std::string currentParentFile =
+ this->GetSafeDefinition("CMAKE_PARENT_LIST_FILE");
+ std::string currentFile = this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE");
+
+ this->AddDefinition("CMAKE_CURRENT_LIST_FILE", filenametoread);
+ this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
+ cmSystemTools::GetFilenamePath(filenametoread));
+
+ this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
+ this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
+ this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");
+
+ // Run the parsed commands.
+ const size_t numberFunctions = listFile.Functions.size();
+ for (size_t i = 0; i < numberFunctions; ++i) {
+ cmExecutionStatus status(*this);
+ this->ExecuteCommand(listFile.Functions[i], status);
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ break;
+ }
+ if (status.GetReturnInvoked()) {
+ // Exit early due to return command.
+ break;
+ }
+ }
+
+ // 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",
+ cmSystemTools::GetFilenamePath(currentFile));
+ this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
+ this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
+ this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");
+}
+
+void cmMakefile::EnforceDirectoryLevelRules() const
+{
+ // Diagnose a violation of CMP0000 if necessary.
+ if (this->CheckCMP0000) {
+ std::ostringstream msg;
+ msg << "No cmake_minimum_required command is present. "
+ << "A line of code such as\n"
+ << " cmake_minimum_required(VERSION " << cmVersion::GetMajorVersion()
+ << "." << cmVersion::GetMinorVersion() << ")\n"
+ << "should be added at the top of the file. "
+ << "The version specified may be lower if you wish to "
+ << "support older CMake versions for this project. "
+ << "For more information run "
+ << "\"cmake --help-policy CMP0000\".";
+ switch (this->GetPolicyStatus(cmPolicies::CMP0000)) {
+ case cmPolicies::WARN:
+ // Warn because the user did not provide a minimum required
+ // version.
+ this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
+ msg.str(), this->Backtrace);
+ case cmPolicies::OLD:
+ // OLD behavior is to use policy version 2.4 set in
+ // cmListFileCache.
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // NEW behavior is to issue an error.
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+ msg.str(), this->Backtrace);
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+ }
+}
+
+void cmMakefile::AddEvaluationFile(
+ const std::string& inputFile, const std::string& targetName,
+ std::unique_ptr<cmCompiledGeneratorExpression> outputName,
+ std::unique_ptr<cmCompiledGeneratorExpression> condition,
+ const std::string& newLineCharacter, mode_t permissions, bool inputIsContent)
+{
+ this->EvaluationFiles.push_back(
+ cm::make_unique<cmGeneratorExpressionEvaluationFile>(
+ inputFile, targetName, std::move(outputName), std::move(condition),
+ inputIsContent, newLineCharacter, permissions,
+ this->GetPolicyStatus(cmPolicies::CMP0070)));
+}
+
+const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>&
+cmMakefile::GetEvaluationFiles() const
+{
+ return this->EvaluationFiles;
+}
+
+std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const&
+cmMakefile::GetExportBuildFileGenerators() const
+{
+ return this->ExportBuildFileGenerators;
+}
+
+void cmMakefile::RemoveExportBuildFileGeneratorCMP0024(
+ cmExportBuildFileGenerator* gen)
+{
+ auto it =
+ std::find_if(this->ExportBuildFileGenerators.begin(),
+ this->ExportBuildFileGenerators.end(),
+ [gen](std::unique_ptr<cmExportBuildFileGenerator> const& p) {
+ return p.get() == gen;
+ });
+ if (it != this->ExportBuildFileGenerators.end()) {
+ this->ExportBuildFileGenerators.erase(it);
+ }
+}
+
+void cmMakefile::AddExportBuildFileGenerator(
+ std::unique_ptr<cmExportBuildFileGenerator> gen)
+{
+ this->ExportBuildFileGenerators.emplace_back(std::move(gen));
+}
+
+namespace {
+struct file_not_persistent
+{
+ bool operator()(const std::string& path) const
+ {
+ return !(path.find("CMakeTmp") == std::string::npos &&
+ cmSystemTools::FileExists(path));
+ }
+};
+}
+
+void cmMakefile::AddGeneratorAction(GeneratorAction action)
+{
+ assert(!this->GeneratorActionsInvoked);
+ this->GeneratorActions.emplace_back(std::move(action), this->Backtrace);
+}
+
+void cmMakefile::DoGenerate(cmLocalGenerator& lg)
+{
+ // do all the variable expansions here
+ this->ExpandVariablesCMP0019();
+
+ // give all the commands a chance to do something
+ // after the file has been parsed before generation
+ for (const BT<GeneratorAction>& action : this->GeneratorActions) {
+ action.Value(lg, action.Backtrace);
+ }
+ this->GeneratorActionsInvoked = true;
+
+ // go through all configured files and see which ones still exist.
+ // we don't want cmake to re-run if a configured file is created and deleted
+ // during processing as that would make it a transient file that can't
+ // influence the build process
+ cm::erase_if(this->OutputFiles, file_not_persistent());
+
+ // if a configured file is used as input for another configured file,
+ // and then deleted it will show up in the input list files so we
+ // need to scan those too
+ cm::erase_if(this->ListFiles, file_not_persistent());
+}
+
+// Generate the output file
+void cmMakefile::Generate(cmLocalGenerator& lg)
+{
+ this->DoGenerate(lg);
+ cmProp oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
+ if (oldValue &&
+ cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, oldValue->c_str(),
+ "2.4")) {
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "You have set CMAKE_BACKWARDS_COMPATIBILITY to a CMake version less "
+ "than 2.4. This version of CMake only supports backwards compatibility "
+ "with CMake 2.4 or later. For compatibility with older versions please "
+ "use any CMake 2.8.x release or lower.",
+ this->Backtrace);
+ }
+}
+
+namespace {
+// There are still too many implicit backtraces through cmMakefile. As a
+// workaround we reset the backtrace temporarily.
+struct BacktraceGuard
+{
+ BacktraceGuard(cmListFileBacktrace& lfbt, cmListFileBacktrace current)
+ : Backtrace(lfbt)
+ , Previous(lfbt)
+ {
+ this->Backtrace = std::move(current);
+ }
+
+ ~BacktraceGuard() { this->Backtrace = std::move(this->Previous); }
+
+private:
+ cmListFileBacktrace& Backtrace;
+ cmListFileBacktrace Previous;
+};
+
+cm::optional<std::string> MakeOptionalString(const char* str)
+{
+ if (str) {
+ return str;
+ }
+ return cm::nullopt;
+}
+
+const char* GetCStrOrNull(const cm::optional<std::string>& str)
+{
+ return str ? str->c_str() : nullptr;
+}
+}
+
+bool cmMakefile::ValidateCustomCommand(
+ const cmCustomCommandLines& commandLines) const
+{
+ // TODO: More strict?
+ for (cmCustomCommandLine const& cl : commandLines) {
+ if (!cl.empty() && !cl[0].empty() && cl[0][0] == '"') {
+ std::ostringstream e;
+ e << "COMMAND may not contain literal quotes:\n " << cl[0] << "\n";
+ this->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+cmTarget* cmMakefile::GetCustomCommandTarget(
+ const std::string& target, cmObjectLibraryCommands objLibCommands,
+ const cmListFileBacktrace& lfbt) const
+{
+ // Find the target to which to add the custom command.
+ auto ti = this->Targets.find(target);
+
+ if (ti == this->Targets.end()) {
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+ bool issueMessage = false;
+ std::ostringstream e;
+ switch (this->GetPolicyStatus(cmPolicies::CMP0040)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0040) << "\n";
+ issueMessage = true;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ issueMessage = true;
+ messageType = MessageType::FATAL_ERROR;
+ }
+
+ if (issueMessage) {
+ if (cmTarget const* t = this->FindTargetToUse(target)) {
+ if (t->IsImported()) {
+ e << "TARGET '" << target
+ << "' is IMPORTED and does not build here.";
+ } else {
+ e << "TARGET '" << target << "' was not created in this directory.";
+ }
+ } else {
+ e << "No TARGET '" << target
+ << "' has been created in this directory.";
+ }
+ this->GetCMakeInstance()->IssueMessage(messageType, e.str(), lfbt);
+ }
+
+ return nullptr;
+ }
+
+ cmTarget* t = &ti->second;
+ if (objLibCommands == cmObjectLibraryCommands::Reject &&
+ t->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ std::ostringstream e;
+ e << "Target \"" << target
+ << "\" is an OBJECT library "
+ "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(),
+ lfbt);
+ return nullptr;
+ }
+ if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ std::ostringstream e;
+ e << "Target \"" << target
+ << "\" is an INTERFACE library "
+ "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(),
+ lfbt);
+ return nullptr;
+ }
+
+ return t;
+}
+
+cmTarget* cmMakefile::AddCustomCommandToTarget(
+ const std::string& target, const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, cmCustomCommandType type,
+ const char* comment, const char* workingDir,
+ cmPolicies::PolicyStatus cmp0116, bool escapeOldStyle, bool uses_terminal,
+ const std::string& depfile, const std::string& job_pool,
+ bool command_expand_lists, bool stdPipesUTF8)
+{
+ cmTarget* t = this->GetCustomCommandTarget(
+ target, cmObjectLibraryCommands::Reject, this->Backtrace);
+
+ // Validate custom commands.
+ if (!t || !this->ValidateCustomCommand(commandLines)) {
+ return t;
+ }
+
+ // Always create the byproduct sources and mark them generated.
+ this->CreateGeneratedOutputs(byproducts);
+
+ // Strings could be moved into the callback function with C++14.
+ cm::optional<std::string> commentStr = MakeOptionalString(comment);
+ cm::optional<std::string> workingStr = MakeOptionalString(workingDir);
+
+ // Dispatch command creation to allow generator expressions in outputs.
+ this->AddGeneratorAction(
+ [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
+ BacktraceGuard guard(this->Backtrace, lfbt);
+ detail::AddCustomCommandToTarget(
+ lg, lfbt, cmCommandOrigin::Project, t, byproducts, depends,
+ commandLines, type, GetCStrOrNull(commentStr),
+ GetCStrOrNull(workingStr), escapeOldStyle, uses_terminal, depfile,
+ job_pool, command_expand_lists, stdPipesUTF8, cmp0116);
+ });
+
+ return t;
+}
+
+void cmMakefile::AddCustomCommandToOutput(
+ const std::string& output, const std::vector<std::string>& depends,
+ const std::string& main_dependency, const cmCustomCommandLines& commandLines,
+ const char* comment, const char* workingDir,
+ cmPolicies::PolicyStatus cmp0116, const CommandSourceCallback& callback,
+ bool replace, bool escapeOldStyle, bool uses_terminal,
+ bool command_expand_lists, const std::string& depfile,
+ const std::string& job_pool, bool stdPipesUTF8)
+{
+ std::vector<std::string> no_byproducts;
+ cmImplicitDependsList no_implicit_depends;
+ this->AddCustomCommandToOutput(
+ { output }, no_byproducts, depends, main_dependency, no_implicit_depends,
+ commandLines, comment, workingDir, cmp0116, callback, replace,
+ escapeOldStyle, uses_terminal, command_expand_lists, depfile, job_pool,
+ stdPipesUTF8);
+}
+
+void cmMakefile::AddCustomCommandToOutput(
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends, const std::string& main_dependency,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, cmPolicies::PolicyStatus cmp0116,
+ const CommandSourceCallback& callback, bool replace, bool escapeOldStyle,
+ bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+ const std::string& job_pool, bool stdPipesUTF8)
+{
+ // Make sure there is at least one output.
+ if (outputs.empty()) {
+ cmSystemTools::Error("Attempt to add a custom rule with no output!");
+ return;
+ }
+
+ // Validate custom commands.
+ if (!this->ValidateCustomCommand(commandLines)) {
+ return;
+ }
+
+ // Always create the output sources and mark them generated.
+ this->CreateGeneratedOutputs(outputs);
+ this->CreateGeneratedOutputs(byproducts);
+
+ // Strings could be moved into the callback function with C++14.
+ cm::optional<std::string> commentStr = MakeOptionalString(comment);
+ cm::optional<std::string> workingStr = MakeOptionalString(workingDir);
+
+ // Dispatch command creation to allow generator expressions in outputs.
+ this->AddGeneratorAction(
+ [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
+ BacktraceGuard guard(this->Backtrace, lfbt);
+ cmSourceFile* sf = detail::AddCustomCommandToOutput(
+ lg, lfbt, cmCommandOrigin::Project, outputs, byproducts, depends,
+ main_dependency, implicit_depends, commandLines,
+ GetCStrOrNull(commentStr), GetCStrOrNull(workingStr), replace,
+ escapeOldStyle, uses_terminal, command_expand_lists, depfile, job_pool,
+ stdPipesUTF8, cmp0116);
+ if (callback && sf) {
+ callback(sf);
+ }
+ });
+}
+
+void cmMakefile::AddCustomCommandOldStyle(
+ const std::string& target, const std::vector<std::string>& outputs,
+ const std::vector<std::string>& depends, const std::string& source,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ cmPolicies::PolicyStatus cmp0116)
+{
+ // Translate the old-style signature to one of the new-style
+ // signatures.
+ if (source == target) {
+ // In the old-style signature if the source and target were the
+ // same then it added a post-build rule to the target. Preserve
+ // this behavior.
+ std::vector<std::string> no_byproducts;
+ this->AddCustomCommandToTarget(
+ target, no_byproducts, depends, commandLines,
+ cmCustomCommandType::POST_BUILD, comment, nullptr, cmp0116);
+ return;
+ }
+
+ auto ti = this->Targets.find(target);
+ cmTarget* t = ti != this->Targets.end() ? &ti->second : nullptr;
+
+ auto addRuleFileToTarget = [=](cmSourceFile* sf) {
+ // If the rule was added to the source (and not a .rule file),
+ // then add the source to the target to make sure the rule is
+ // included.
+ if (!sf->GetPropertyAsBool("__CMAKE_RULE")) {
+ if (t) {
+ t->AddSource(sf->ResolveFullPath());
+ } else {
+ cmSystemTools::Error("Attempt to add a custom rule to a target "
+ "that does not exist yet for target " +
+ target);
+ }
+ }
+ };
+
+ // Each output must get its own copy of this rule.
+ cmsys::RegularExpression sourceFiles(
+ "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|mpp|ixx|cppm|cu|m|mm|"
+ "rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|"
+ "hm|hpp|hxx|in|txx|inl)$");
+
+ // Choose whether to use a main dependency.
+ if (sourceFiles.find(source)) {
+ // The source looks like a real file. Use it as the main dependency.
+ for (std::string const& output : outputs) {
+ this->AddCustomCommandToOutput(output, depends, source, commandLines,
+ comment, nullptr, cmp0116,
+ addRuleFileToTarget);
+ }
+ } else {
+ std::string no_main_dependency;
+ std::vector<std::string> depends2 = depends;
+ depends2.push_back(source);
+
+ // The source may not be a real file. Do not use a main dependency.
+ for (std::string const& output : outputs) {
+ this->AddCustomCommandToOutput(output, depends2, no_main_dependency,
+ commandLines, comment, nullptr, cmp0116,
+ addRuleFileToTarget);
+ }
+ }
+}
+
+void cmMakefile::AppendCustomCommandToOutput(
+ const std::string& output, const std::vector<std::string>& depends,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines)
+{
+ // Validate custom commands.
+ if (this->ValidateCustomCommand(commandLines)) {
+ // Dispatch command creation to allow generator expressions in outputs.
+ this->AddGeneratorAction(
+ [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
+ BacktraceGuard guard(this->Backtrace, lfbt);
+ detail::AppendCustomCommandToOutput(lg, lfbt, output, depends,
+ implicit_depends, commandLines);
+ });
+ }
+}
+
+cmTarget* cmMakefile::AddUtilityCommand(
+ const std::string& utilityName, bool excludeFromAll, const char* workingDir,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, cmPolicies::PolicyStatus cmp0116,
+ bool escapeOldStyle, const char* comment, bool uses_terminal,
+ bool command_expand_lists, const std::string& job_pool, bool stdPipesUTF8)
+{
+ cmTarget* target = this->AddNewUtilityTarget(utilityName, excludeFromAll);
+
+ // Validate custom commands.
+ if ((commandLines.empty() && depends.empty()) ||
+ !this->ValidateCustomCommand(commandLines)) {
+ return target;
+ }
+
+ // Always create the byproduct sources and mark them generated.
+ this->CreateGeneratedOutputs(byproducts);
+
+ // Strings could be moved into the callback function with C++14.
+ cm::optional<std::string> commentStr = MakeOptionalString(comment);
+ cm::optional<std::string> workingStr = MakeOptionalString(workingDir);
+
+ // Dispatch command creation to allow generator expressions in outputs.
+ this->AddGeneratorAction(
+ [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
+ BacktraceGuard guard(this->Backtrace, lfbt);
+ detail::AddUtilityCommand(
+ lg, lfbt, cmCommandOrigin::Project, target, GetCStrOrNull(workingStr),
+ byproducts, depends, commandLines, escapeOldStyle,
+ GetCStrOrNull(commentStr), uses_terminal, command_expand_lists,
+ job_pool, stdPipesUTF8, cmp0116);
+ });
+
+ return target;
+}
+
+static void s_AddDefineFlag(std::string const& flag, std::string& dflags)
+{
+ // remove any \n\r
+ std::string::size_type initSize = dflags.size();
+ dflags += ' ';
+ dflags += flag;
+ std::string::iterator flagStart = dflags.begin() + initSize + 1;
+ std::replace(flagStart, dflags.end(), '\n', ' ');
+ std::replace(flagStart, dflags.end(), '\r', ' ');
+}
+
+void cmMakefile::AddDefineFlag(std::string const& flag)
+{
+ if (flag.empty()) {
+ return;
+ }
+
+ // Update the string used for the old DEFINITIONS property.
+ s_AddDefineFlag(flag, this->DefineFlagsOrig);
+
+ // If this is really a definition, update COMPILE_DEFINITIONS.
+ if (this->ParseDefineFlag(flag, false)) {
+ return;
+ }
+
+ // Add this flag that does not look like a definition.
+ s_AddDefineFlag(flag, this->DefineFlags);
+}
+
+static void s_RemoveDefineFlag(std::string const& flag, std::string& dflags)
+{
+ std::string::size_type const len = flag.length();
+ // Remove all instances of the flag that are surrounded by
+ // whitespace or the beginning/end of the string.
+ for (std::string::size_type lpos = dflags.find(flag, 0);
+ lpos != std::string::npos; lpos = dflags.find(flag, lpos)) {
+ std::string::size_type rpos = lpos + len;
+ if ((lpos <= 0 || isspace(dflags[lpos - 1])) &&
+ (rpos >= dflags.size() || isspace(dflags[rpos]))) {
+ dflags.erase(lpos, len);
+ } else {
+ ++lpos;
+ }
+ }
+}
+
+void cmMakefile::RemoveDefineFlag(std::string const& flag)
+{
+ // Check the length of the flag to remove.
+ if (flag.empty()) {
+ return;
+ }
+
+ // Update the string used for the old DEFINITIONS property.
+ s_RemoveDefineFlag(flag, this->DefineFlagsOrig);
+
+ // If this is really a definition, update COMPILE_DEFINITIONS.
+ if (this->ParseDefineFlag(flag, true)) {
+ return;
+ }
+
+ // Remove this flag that does not look like a definition.
+ s_RemoveDefineFlag(flag, this->DefineFlags);
+}
+
+void cmMakefile::AddCompileDefinition(std::string const& option)
+{
+ this->AppendProperty("COMPILE_DEFINITIONS", option);
+}
+
+void cmMakefile::AddCompileOption(std::string const& option)
+{
+ this->AppendProperty("COMPILE_OPTIONS", option);
+}
+
+void cmMakefile::AddLinkOption(std::string const& option)
+{
+ this->AppendProperty("LINK_OPTIONS", option);
+}
+
+void cmMakefile::AddLinkDirectory(std::string const& directory, bool before)
+{
+ if (before) {
+ this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry(
+ directory, this->Backtrace);
+ } else {
+ this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry(
+ directory, this->Backtrace);
+ }
+}
+
+bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove)
+{
+ // Create a regular expression to match valid definitions.
+ static cmsys::RegularExpression valid("^[-/]D[A-Za-z_][A-Za-z0-9_]*(=.*)?$");
+
+ // Make sure the definition matches.
+ if (!valid.find(def)) {
+ return false;
+ }
+
+ // Definitions with non-trivial values require a policy check.
+ static cmsys::RegularExpression trivial(
+ "^[-/]D[A-Za-z_][A-Za-z0-9_]*(=[A-Za-z0-9_.]+)?$");
+ if (!trivial.find(def)) {
+ // This definition has a non-trivial value.
+ switch (this->GetPolicyStatus(cmPolicies::CMP0005)) {
+ case cmPolicies::WARN:
+ this->IssueMessage(MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0005));
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior is to not escape the value. We should not
+ // convert the definition to use the property.
+ return false;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0005));
+ return false;
+ case cmPolicies::NEW:
+ // NEW behavior is to escape the value. Proceed to convert it
+ // to an entry in the property.
+ break;
+ }
+ }
+
+ // Get the definition part after the flag.
+ const char* define = def.c_str() + 2;
+
+ if (remove) {
+ if (cmProp cdefs = this->GetProperty("COMPILE_DEFINITIONS")) {
+ // Expand the list.
+ std::vector<std::string> defs = cmExpandedList(*cdefs);
+
+ // Recompose the list without the definition.
+ auto defEnd = std::remove(defs.begin(), defs.end(), define);
+ auto defBegin = defs.begin();
+ std::string ndefs = cmJoin(cmMakeRange(defBegin, defEnd), ";");
+
+ // Store the new list.
+ this->SetProperty("COMPILE_DEFINITIONS", ndefs.c_str());
+ }
+ } else {
+ // Append the definition to the directory property.
+ this->AppendProperty("COMPILE_DEFINITIONS", define);
+ }
+
+ return true;
+}
+
+void cmMakefile::InitializeFromParent(cmMakefile* parent)
+{
+ this->SystemIncludeDirectories = parent->SystemIncludeDirectories;
+
+ // define flags
+ this->DefineFlags = parent->DefineFlags;
+ this->DefineFlagsOrig = parent->DefineFlagsOrig;
+
+ // Include transform property. There is no per-config version.
+ {
+ const char* prop = "IMPLICIT_DEPENDS_INCLUDE_TRANSFORM";
+ this->SetProperty(prop, cmToCStr(parent->GetProperty(prop)));
+ }
+
+ // compile definitions property and per-config versions
+ cmPolicies::PolicyStatus polSt = this->GetPolicyStatus(cmPolicies::CMP0043);
+ if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
+ this->SetProperty("COMPILE_DEFINITIONS",
+ cmToCStr(parent->GetProperty("COMPILE_DEFINITIONS")));
+ std::vector<std::string> configs =
+ this->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
+ for (std::string const& config : configs) {
+ std::string defPropName =
+ cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(config));
+ cmProp prop = parent->GetProperty(defPropName);
+ this->SetProperty(defPropName, cmToCStr(prop));
+ }
+ }
+
+ // labels
+ this->SetProperty("LABELS", cmToCStr(parent->GetProperty("LABELS")));
+
+ // link libraries
+ this->SetProperty("LINK_LIBRARIES",
+ cmToCStr(parent->GetProperty("LINK_LIBRARIES")));
+
+ // the initial project name
+ this->StateSnapshot.SetProjectName(parent->StateSnapshot.GetProjectName());
+
+ // Copy include regular expressions.
+ this->ComplainFileRegularExpression = parent->ComplainFileRegularExpression;
+
+ // Imported targets.
+ this->ImportedTargets = parent->ImportedTargets;
+
+ // Non-global Alias targets.
+ this->AliasTargets = parent->AliasTargets;
+
+ // Recursion depth.
+ this->RecursionDepth = parent->RecursionDepth;
+}
+
+void cmMakefile::AddInstallGenerator(std::unique_ptr<cmInstallGenerator> g)
+{
+ if (g) {
+ this->InstallGenerators.push_back(std::move(g));
+ }
+}
+
+void cmMakefile::AddTestGenerator(std::unique_ptr<cmTestGenerator> g)
+{
+ if (g) {
+ this->TestGenerators.push_back(std::move(g));
+ }
+}
+
+void cmMakefile::PushFunctionScope(std::string const& fileName,
+ const cmPolicies::PolicyMap& pm)
+{
+ this->StateSnapshot = this->GetState()->CreateFunctionCallSnapshot(
+ this->StateSnapshot, fileName);
+ assert(this->StateSnapshot.IsValid());
+
+ this->PushLoopBlockBarrier();
+
+#if !defined(CMAKE_BOOTSTRAP)
+ this->GetGlobalGenerator()->GetFileLockPool().PushFunctionScope();
+#endif
+
+ this->PushFunctionBlockerBarrier();
+
+ this->PushPolicy(true, pm);
+}
+
+void cmMakefile::PopFunctionScope(bool reportError)
+{
+ this->PopPolicy();
+
+ this->PopSnapshot(reportError);
+
+ this->PopFunctionBlockerBarrier(reportError);
+
+#if !defined(CMAKE_BOOTSTRAP)
+ this->GetGlobalGenerator()->GetFileLockPool().PopFunctionScope();
+#endif
+
+ this->PopLoopBlockBarrier();
+}
+
+void cmMakefile::PushMacroScope(std::string const& fileName,
+ const cmPolicies::PolicyMap& pm)
+{
+ this->StateSnapshot =
+ this->GetState()->CreateMacroCallSnapshot(this->StateSnapshot, fileName);
+ assert(this->StateSnapshot.IsValid());
+
+ this->PushFunctionBlockerBarrier();
+
+ this->PushPolicy(true, pm);
+}
+
+void cmMakefile::PopMacroScope(bool reportError)
+{
+ this->PopPolicy();
+ this->PopSnapshot(reportError);
+
+ this->PopFunctionBlockerBarrier(reportError);
+}
+
+bool cmMakefile::IsRootMakefile() const
+{
+ return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid();
+}
+
+class cmMakefile::BuildsystemFileScope
+{
+public:
+ BuildsystemFileScope(cmMakefile* mf)
+ : Makefile(mf)
+ , ReportError(true)
+ {
+ std::string currentStart =
+ cmStrCat(this->Makefile->StateSnapshot.GetDirectory().GetCurrentSource(),
+ "/CMakeLists.txt");
+ this->Makefile->StateSnapshot.SetListFile(currentStart);
+ this->Makefile->StateSnapshot =
+ this->Makefile->StateSnapshot.GetState()->CreatePolicyScopeSnapshot(
+ this->Makefile->StateSnapshot);
+ this->Makefile->PushFunctionBlockerBarrier();
+
+ this->GG = mf->GetGlobalGenerator();
+ this->CurrentMakefile = this->GG->GetCurrentMakefile();
+ this->Snapshot = this->GG->GetCMakeInstance()->GetCurrentSnapshot();
+ this->GG->GetCMakeInstance()->SetCurrentSnapshot(this->Snapshot);
+ this->GG->SetCurrentMakefile(mf);
+#if !defined(CMAKE_BOOTSTRAP)
+ this->GG->GetFileLockPool().PushFileScope();
+#endif
+ }
+
+ ~BuildsystemFileScope()
+ {
+ this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
+ this->Makefile->PopSnapshot(this->ReportError);
+#if !defined(CMAKE_BOOTSTRAP)
+ this->GG->GetFileLockPool().PopFileScope();
+#endif
+ this->GG->SetCurrentMakefile(this->CurrentMakefile);
+ this->GG->GetCMakeInstance()->SetCurrentSnapshot(this->Snapshot);
+ }
+
+ void Quiet() { this->ReportError = false; }
+
+ BuildsystemFileScope(const BuildsystemFileScope&) = delete;
+ BuildsystemFileScope& operator=(const BuildsystemFileScope&) = delete;
+
+private:
+ cmMakefile* Makefile;
+ cmGlobalGenerator* GG;
+ cmMakefile* CurrentMakefile;
+ cmStateSnapshot Snapshot;
+ bool ReportError;
+};
+
+void cmMakefile::Configure()
+{
+ std::string currentStart = cmStrCat(
+ this->StateSnapshot.GetDirectory().GetCurrentSource(), "/CMakeLists.txt");
+
+ // Add the bottom of all backtraces within this directory.
+ // We will never pop this scope because it should be available
+ // for messages during the generate step too.
+ this->Backtrace = this->Backtrace.Push(currentStart);
+
+ BuildsystemFileScope scope(this);
+
+ // make sure the CMakeFiles dir is there
+ std::string filesDir = cmStrCat(
+ this->StateSnapshot.GetDirectory().GetCurrentBinary(), "/CMakeFiles");
+ cmSystemTools::MakeDirectory(filesDir);
+
+ assert(cmSystemTools::FileExists(currentStart, true));
+ this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentStart);
+
+ cmListFile listFile;
+ if (!listFile.ParseFile(currentStart.c_str(), this->GetMessenger(),
+ this->Backtrace)) {
+ return;
+ }
+ if (this->IsRootMakefile()) {
+ bool hasVersion = false;
+ // search for the right policy command
+ for (cmListFileFunction const& func : listFile.Functions) {
+ if (func.LowerCaseName() == "cmake_minimum_required") {
+ hasVersion = true;
+ break;
+ }
+ }
+ // if no policy command is found this is an error if they use any
+ // non advanced functions or a lot of functions
+ if (!hasVersion) {
+ bool isProblem = true;
+ if (listFile.Functions.size() < 30) {
+ // the list of simple commands DO NOT ADD TO THIS LIST!!!!!
+ // these commands must have backwards compatibility forever and
+ // and that is a lot longer than your tiny mind can comprehend mortal
+ std::set<std::string> allowedCommands;
+ allowedCommands.insert("project");
+ allowedCommands.insert("set");
+ allowedCommands.insert("if");
+ allowedCommands.insert("endif");
+ allowedCommands.insert("else");
+ allowedCommands.insert("elseif");
+ allowedCommands.insert("add_executable");
+ allowedCommands.insert("add_library");
+ allowedCommands.insert("target_link_libraries");
+ allowedCommands.insert("option");
+ allowedCommands.insert("message");
+ isProblem = false;
+ for (cmListFileFunction const& func : listFile.Functions) {
+ if (!cm::contains(allowedCommands, func.LowerCaseName())) {
+ isProblem = true;
+ break;
+ }
+ }
+ }
+
+ if (isProblem) {
+ // Tell the top level cmMakefile to diagnose
+ // this violation of CMP0000.
+ this->SetCheckCMP0000(true);
+
+ // Implicitly set the version for the user.
+ cmPolicies::ApplyPolicyVersion(this, 2, 4, 0,
+ cmPolicies::WarnCompat::Off);
+ }
+ }
+ bool hasProject = false;
+ // search for a project command
+ for (cmListFileFunction const& func : listFile.Functions) {
+ if (func.LowerCaseName() == "project") {
+ hasProject = true;
+ break;
+ }
+ }
+ // if no project command is found, add one
+ if (!hasProject) {
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ "No project() command is present. The top-level CMakeLists.txt "
+ "file must contain a literal, direct call to the project() command. "
+ "Add a line of code such as\n"
+ " project(ProjectName)\n"
+ "near the top of the file, but after cmake_minimum_required().\n"
+ "CMake is pretending there is a \"project(Project)\" command on "
+ "the first line.",
+ this->Backtrace);
+ cmListFileFunction project{ "project",
+ 0,
+ { { "Project", cmListFileArgument::Unquoted,
+ 0 },
+ { "__CMAKE_INJECTED_PROJECT_COMMAND__",
+ cmListFileArgument::Unquoted, 0 } } };
+ listFile.Functions.insert(listFile.Functions.begin(), project);
+ }
+ }
+
+ this->Defer = cm::make_unique<DeferCommands>();
+ this->RunListFile(listFile, currentStart, this->Defer.get());
+ this->Defer.reset();
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ scope.Quiet();
+ }
+
+ // at the end handle any old style subdirs
+ std::vector<cmMakefile*> subdirs = this->UnConfiguredDirectories;
+
+ // for each subdir recurse
+ auto sdi = subdirs.begin();
+ for (; sdi != subdirs.end(); ++sdi) {
+ (*sdi)->StateSnapshot.InitializeFromParent_ForSubdirsCommand();
+ this->ConfigureSubDirectory(*sdi);
+ }
+
+ this->AddCMakeDependFilesFromUser();
+}
+
+void cmMakefile::ConfigureSubDirectory(cmMakefile* mf)
+{
+ mf->InitializeFromParent(this);
+ std::string currentStart = mf->GetCurrentSourceDirectory();
+ if (this->GetCMakeInstance()->GetDebugOutput()) {
+ std::string msg = cmStrCat(" Entering ", currentStart);
+ cmSystemTools::Message(msg);
+ }
+
+ std::string const currentStartFile = currentStart + "/CMakeLists.txt";
+ if (!cmSystemTools::FileExists(currentStartFile, true)) {
+ // The file is missing. Check policy CMP0014.
+ std::ostringstream e;
+ /* clang-format off */
+ e << "The source directory\n"
+ << " " << currentStart << "\n"
+ << "does not contain a CMakeLists.txt file.";
+ /* clang-format on */
+ switch (this->GetPolicyStatus(cmPolicies::CMP0014)) {
+ case cmPolicies::WARN:
+ // Print the warning.
+ /* clang-format off */
+ e << "\n"
+ << "CMake does not support this case but it used "
+ << "to work accidentally and is being allowed for "
+ << "compatibility."
+ << "\n"
+ << cmPolicies::GetPolicyWarning(cmPolicies::CMP0014);
+ /* clang-format on */
+ this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+ case cmPolicies::OLD:
+ // OLD behavior does not warn.
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ e << "\n" << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0014);
+ CM_FALLTHROUGH;
+ case cmPolicies::NEW:
+ // NEW behavior prints the error.
+ this->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ }
+ return;
+ }
+ // finally configure the subdir
+ mf->Configure();
+
+ if (this->GetCMakeInstance()->GetDebugOutput()) {
+ std::string msg =
+ cmStrCat(" Returning to ", this->GetCurrentSourceDirectory());
+ cmSystemTools::Message(msg);
+ }
+}
+
+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;
+ }
+
+ cmStateSnapshot newSnapshot =
+ this->GetState()->CreateBuildsystemDirectorySnapshot(this->StateSnapshot);
+
+ newSnapshot.GetDirectory().SetCurrentSource(srcPath);
+ newSnapshot.GetDirectory().SetCurrentBinary(binPath);
+
+ cmSystemTools::MakeDirectory(binPath);
+
+ auto subMfu =
+ cm::make_unique<cmMakefile>(this->GlobalGenerator, newSnapshot);
+ auto* subMf = subMfu.get();
+ this->GetGlobalGenerator()->AddMakefile(std::move(subMfu));
+
+ if (excludeFromAll) {
+ subMf->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
+ }
+
+ if (immediate) {
+ this->ConfigureSubDirectory(subMf);
+ } else {
+ this->UnConfiguredDirectories.push_back(subMf);
+ }
+
+ this->AddInstallGenerator(cm::make_unique<cmInstallSubdirectoryGenerator>(
+ subMf, binPath, excludeFromAll, this->GetBacktrace()));
+}
+
+const std::string& cmMakefile::GetCurrentSourceDirectory() const
+{
+ return this->StateSnapshot.GetDirectory().GetCurrentSource();
+}
+
+const std::string& cmMakefile::GetCurrentBinaryDirectory() const
+{
+ return this->StateSnapshot.GetDirectory().GetCurrentBinary();
+}
+
+std::vector<cmTarget*> cmMakefile::GetImportedTargets() const
+{
+ std::vector<cmTarget*> tgts;
+ tgts.reserve(this->ImportedTargets.size());
+ for (auto const& impTarget : this->ImportedTargets) {
+ tgts.push_back(impTarget.second);
+ }
+ return tgts;
+}
+
+void cmMakefile::AddIncludeDirectories(const std::vector<std::string>& incs,
+ bool before)
+{
+ if (incs.empty()) {
+ return;
+ }
+
+ std::string entryString = cmJoin(incs, ";");
+ if (before) {
+ this->StateSnapshot.GetDirectory().PrependIncludeDirectoriesEntry(
+ entryString, this->Backtrace);
+ } else {
+ this->StateSnapshot.GetDirectory().AppendIncludeDirectoriesEntry(
+ entryString, this->Backtrace);
+ }
+
+ // Property on each target:
+ for (auto& target : this->Targets) {
+ cmTarget& t = target.second;
+ t.InsertInclude(entryString, this->Backtrace, before);
+ }
+}
+
+void cmMakefile::AddSystemIncludeDirectories(const std::set<std::string>& incs)
+{
+ if (incs.empty()) {
+ return;
+ }
+
+ this->SystemIncludeDirectories.insert(incs.begin(), incs.end());
+
+ for (auto& target : this->Targets) {
+ cmTarget& t = target.second;
+ t.AddSystemIncludeDirectories(incs);
+ }
+}
+
+void cmMakefile::AddDefinition(const std::string& name, cm::string_view value)
+{
+ this->StateSnapshot.SetDefinition(name, value);
+
+#ifndef CMAKE_BOOTSTRAP
+ cmVariableWatch* vv = this->GetVariableWatch();
+ if (vv) {
+ vv->VariableAccessed(name, cmVariableWatch::VARIABLE_MODIFIED_ACCESS,
+ value.data(), this);
+ }
+#endif
+}
+
+void cmMakefile::AddDefinitionBool(const std::string& name, bool value)
+{
+ this->AddDefinition(name, value ? "ON" : "OFF");
+}
+
+void cmMakefile::AddCacheDefinition(const std::string& name, const char* value,
+ const char* doc,
+ cmStateEnums::CacheEntryType type,
+ bool force)
+{
+ cmProp existingValue = this->GetState()->GetInitializedCacheValue(name);
+ // must be outside the following if() to keep it alive long enough
+ std::string nvalue;
+
+ if (existingValue &&
+ (this->GetState()->GetCacheEntryType(name) ==
+ cmStateEnums::UNINITIALIZED)) {
+ // if this is not a force, then use the value from the cache
+ // if it is a force, then use the value being passed in
+ if (!force) {
+ value = existingValue->c_str();
+ }
+ if (type == cmStateEnums::PATH || type == cmStateEnums::FILEPATH) {
+ std::vector<std::string>::size_type cc;
+ std::vector<std::string> files;
+ nvalue = value ? value : "";
+
+ cmExpandList(nvalue, files);
+ nvalue.clear();
+ for (cc = 0; cc < files.size(); cc++) {
+ if (!cmIsOff(files[cc])) {
+ files[cc] = cmSystemTools::CollapseFullPath(files[cc]);
+ }
+ if (cc > 0) {
+ nvalue += ";";
+ }
+ nvalue += files[cc];
+ }
+
+ this->GetCMakeInstance()->AddCacheEntry(name, nvalue.c_str(), doc, type);
+ nvalue = *this->GetState()->GetInitializedCacheValue(name);
+ value = nvalue.c_str();
+ }
+ }
+ this->GetCMakeInstance()->AddCacheEntry(name, value, doc, type);
+ // if there was a definition then remove it
+ this->StateSnapshot.RemoveDefinition(name);
+}
+
+void cmMakefile::MarkVariableAsUsed(const std::string& var)
+{
+ this->StateSnapshot.GetDefinition(var);
+}
+
+bool cmMakefile::VariableInitialized(const std::string& var) const
+{
+ return this->StateSnapshot.IsInitialized(var);
+}
+
+void cmMakefile::MaybeWarnUninitialized(std::string const& variable,
+ const char* sourceFilename) const
+{
+ // check to see if we need to print a warning
+ // if strict mode is on and the variable has
+ // not been "cleared"/initialized with a set(foo ) call
+ if (this->GetCMakeInstance()->GetWarnUninitialized() &&
+ !this->VariableInitialized(variable)) {
+ if (this->CheckSystemVars ||
+ (sourceFilename && this->IsProjectFile(sourceFilename))) {
+ std::ostringstream msg;
+ msg << "uninitialized variable \'" << variable << "\'";
+ this->IssueMessage(MessageType::AUTHOR_WARNING, msg.str());
+ }
+ }
+}
+
+void cmMakefile::RemoveDefinition(const std::string& name)
+{
+ this->StateSnapshot.RemoveDefinition(name);
+#ifndef CMAKE_BOOTSTRAP
+ cmVariableWatch* vv = this->GetVariableWatch();
+ if (vv) {
+ vv->VariableAccessed(name, cmVariableWatch::VARIABLE_REMOVED_ACCESS,
+ nullptr, this);
+ }
+#endif
+}
+
+void cmMakefile::RemoveCacheDefinition(const std::string& name) const
+{
+ this->GetState()->RemoveCacheEntry(name);
+}
+
+void cmMakefile::SetProjectName(std::string const& p)
+{
+ this->StateSnapshot.SetProjectName(p);
+}
+
+void cmMakefile::AddGlobalLinkInformation(cmTarget& target)
+{
+ // for these targets do not add anything
+ switch (target.GetType()) {
+ case cmStateEnums::UTILITY:
+ case cmStateEnums::GLOBAL_TARGET:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ return;
+ default:;
+ }
+
+ if (cmProp linkLibsProp = this->GetProperty("LINK_LIBRARIES")) {
+ std::vector<std::string> linkLibs = cmExpandedList(*linkLibsProp);
+
+ for (auto j = linkLibs.begin(); j != linkLibs.end(); ++j) {
+ std::string libraryName = *j;
+ cmTargetLinkLibraryType libType = GENERAL_LibraryType;
+ if (libraryName == "optimized") {
+ libType = OPTIMIZED_LibraryType;
+ ++j;
+ libraryName = *j;
+ } else if (libraryName == "debug") {
+ libType = DEBUG_LibraryType;
+ ++j;
+ libraryName = *j;
+ }
+ // This is equivalent to the target_link_libraries plain signature.
+ target.AddLinkLibrary(*this, libraryName, libType);
+ target.AppendProperty(
+ "INTERFACE_LINK_LIBRARIES",
+ target.GetDebugGeneratorExpressions(libraryName, libType));
+ }
+ }
+}
+
+void cmMakefile::AddAlias(const std::string& lname, std::string const& tgtName,
+ bool globallyVisible)
+{
+ this->AliasTargets[lname] = tgtName;
+ if (globallyVisible) {
+ this->GetGlobalGenerator()->AddAlias(lname, tgtName);
+ }
+}
+
+cmTarget* cmMakefile::AddLibrary(const std::string& lname,
+ cmStateEnums::TargetType type,
+ const std::vector<std::string>& srcs,
+ bool excludeFromAll)
+{
+ assert(type == cmStateEnums::STATIC_LIBRARY ||
+ type == cmStateEnums::SHARED_LIBRARY ||
+ type == cmStateEnums::MODULE_LIBRARY ||
+ type == cmStateEnums::OBJECT_LIBRARY ||
+ type == cmStateEnums::INTERFACE_LIBRARY);
+
+ cmTarget* target = this->AddNewTarget(type, lname);
+ // Clear its dependencies. Otherwise, dependencies might persist
+ // over changes in CMakeLists.txt, making the information stale and
+ // hence useless.
+ target->ClearDependencyInformation(*this);
+ if (excludeFromAll) {
+ target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
+ }
+ target->AddSources(srcs);
+ this->AddGlobalLinkInformation(*target);
+ return target;
+}
+
+cmTarget* cmMakefile::AddExecutable(const std::string& exeName,
+ const std::vector<std::string>& srcs,
+ bool excludeFromAll)
+{
+ cmTarget* target = this->AddNewTarget(cmStateEnums::EXECUTABLE, exeName);
+ if (excludeFromAll) {
+ target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
+ }
+ target->AddSources(srcs);
+ this->AddGlobalLinkInformation(*target);
+ return target;
+}
+
+cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type,
+ const std::string& name)
+{
+ auto it = this->Targets
+ .emplace(name,
+ cmTarget(name, type, cmTarget::VisibilityNormal, this,
+ cmTarget::PerConfig::Yes))
+ .first;
+ this->OrderedTargets.push_back(&it->second);
+ this->GetGlobalGenerator()->IndexTarget(&it->second);
+ this->GetStateSnapshot().GetDirectory().AddNormalTargetName(name);
+ return &it->second;
+}
+
+cmTarget* cmMakefile::AddNewUtilityTarget(const std::string& utilityName,
+ bool excludeFromAll)
+{
+ cmTarget* target = this->AddNewTarget(cmStateEnums::UTILITY, utilityName);
+ if (excludeFromAll) {
+ target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
+ }
+ return target;
+}
+
+namespace {
+}
+
+#if !defined(CMAKE_BOOTSTRAP)
+cmSourceGroup* cmMakefile::GetSourceGroup(
+ const std::vector<std::string>& name) const
+{
+ cmSourceGroup* sg = nullptr;
+
+ // first look for source group starting with the same as the one we want
+ for (cmSourceGroup const& srcGroup : this->SourceGroups) {
+ std::string const& sgName = srcGroup.GetName();
+ if (sgName == name[0]) {
+ sg = const_cast<cmSourceGroup*>(&srcGroup);
+ break;
+ }
+ }
+
+ if (sg != nullptr) {
+ // iterate through its children to find match source group
+ for (unsigned int i = 1; i < name.size(); ++i) {
+ sg = sg->LookupChild(name[i]);
+ if (sg == nullptr) {
+ break;
+ }
+ }
+ }
+ return sg;
+}
+
+void cmMakefile::AddSourceGroup(const std::string& name, const char* regex)
+{
+ std::vector<std::string> nameVector;
+ nameVector.push_back(name);
+ this->AddSourceGroup(nameVector, regex);
+}
+
+void cmMakefile::AddSourceGroup(const std::vector<std::string>& name,
+ const char* regex)
+{
+ cmSourceGroup* sg = nullptr;
+ std::vector<std::string> currentName;
+ int i = 0;
+ const int lastElement = static_cast<int>(name.size() - 1);
+ for (i = lastElement; i >= 0; --i) {
+ currentName.assign(name.begin(), name.begin() + i + 1);
+ sg = this->GetSourceGroup(currentName);
+ if (sg != nullptr) {
+ break;
+ }
+ }
+
+ // i now contains the index of the last found component
+ if (i == lastElement) {
+ // group already exists, replace its regular expression
+ if (regex && sg) {
+ // We only want to set the regular expression. If there are already
+ // source files in the group, we don't want to remove them.
+ sg->SetGroupRegex(regex);
+ }
+ return;
+ }
+ if (i == -1) {
+ // group does not exist nor belong to any existing group
+ // add its first component
+ this->SourceGroups.emplace_back(name[0], regex);
+ sg = this->GetSourceGroup(currentName);
+ i = 0; // last component found
+ }
+ if (!sg) {
+ cmSystemTools::Error("Could not create source group ");
+ return;
+ }
+ // build the whole source group path
+ for (++i; i <= lastElement; ++i) {
+ sg->AddChild(cmSourceGroup(name[i], nullptr, sg->GetFullName().c_str()));
+ sg = sg->LookupChild(name[i]);
+ }
+
+ sg->SetGroupRegex(regex);
+}
+
+cmSourceGroup* cmMakefile::GetOrCreateSourceGroup(
+ const std::vector<std::string>& folders)
+{
+ cmSourceGroup* sg = this->GetSourceGroup(folders);
+ if (sg == nullptr) {
+ this->AddSourceGroup(folders);
+ sg = this->GetSourceGroup(folders);
+ }
+ return sg;
+}
+
+cmSourceGroup* cmMakefile::GetOrCreateSourceGroup(const std::string& name)
+{
+ std::string delimiters;
+ if (cmProp p = this->GetDefinition("SOURCE_GROUP_DELIMITER")) {
+ delimiters = *p;
+ } else {
+ delimiters = "/\\";
+ }
+ return this->GetOrCreateSourceGroup(cmTokenize(name, delimiters));
+}
+
+/**
+ * Find a source group whose regular expression matches the filename
+ * part of the given source name. Search backward through the list of
+ * source groups, and take the first matching group found. This way
+ * non-inherited SOURCE_GROUP commands will have precedence over
+ * inherited ones.
+ */
+cmSourceGroup* cmMakefile::FindSourceGroup(
+ const std::string& source, std::vector<cmSourceGroup>& groups) const
+{
+ // First search for a group that lists the file explicitly.
+ for (auto sg = groups.rbegin(); sg != groups.rend(); ++sg) {
+ cmSourceGroup* result = sg->MatchChildrenFiles(source);
+ if (result) {
+ return result;
+ }
+ }
+
+ // Now search for a group whose regex matches the file.
+ for (auto sg = groups.rbegin(); sg != groups.rend(); ++sg) {
+ cmSourceGroup* result = sg->MatchChildrenRegex(source);
+ if (result) {
+ return result;
+ }
+ }
+
+ // Shouldn't get here, but just in case, return the default group.
+ return groups.data();
+}
+#endif
+
+static bool mightExpandVariablesCMP0019(const char* s)
+{
+ return s && *s && strstr(s, "${") && strchr(s, '}');
+}
+
+void cmMakefile::ExpandVariablesCMP0019()
+{
+ // Drop this ancient compatibility behavior with a policy.
+ cmPolicies::PolicyStatus pol = this->GetPolicyStatus(cmPolicies::CMP0019);
+ if (pol != cmPolicies::OLD && pol != cmPolicies::WARN) {
+ return;
+ }
+ std::ostringstream w;
+
+ cmProp includeDirs = this->GetProperty("INCLUDE_DIRECTORIES");
+ if (includeDirs && mightExpandVariablesCMP0019(includeDirs->c_str())) {
+ std::string dirs = *includeDirs;
+ this->ExpandVariablesInString(dirs, true, true);
+ if (pol == cmPolicies::WARN && dirs != *includeDirs) {
+ /* clang-format off */
+ w << "Evaluated directory INCLUDE_DIRECTORIES\n"
+ << " " << *includeDirs << "\n"
+ << "as\n"
+ << " " << dirs << "\n";
+ /* clang-format on */
+ }
+ this->SetProperty("INCLUDE_DIRECTORIES", dirs.c_str());
+ }
+
+ // Also for each target's INCLUDE_DIRECTORIES property:
+ for (auto& target : this->Targets) {
+ cmTarget& t = target.second;
+ if (t.GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ t.GetType() == cmStateEnums::GLOBAL_TARGET) {
+ continue;
+ }
+ includeDirs = t.GetProperty("INCLUDE_DIRECTORIES");
+ if (includeDirs && mightExpandVariablesCMP0019(includeDirs->c_str())) {
+ std::string dirs = *includeDirs;
+ this->ExpandVariablesInString(dirs, true, true);
+ if (pol == cmPolicies::WARN && dirs != *includeDirs) {
+ /* clang-format off */
+ w << "Evaluated target " << t.GetName() << " INCLUDE_DIRECTORIES\n"
+ << " " << *includeDirs << "\n"
+ << "as\n"
+ << " " << dirs << "\n";
+ /* clang-format on */
+ }
+ t.SetProperty("INCLUDE_DIRECTORIES", dirs);
+ }
+ }
+
+ if (cmProp linkDirsProp = this->GetProperty("LINK_DIRECTORIES")) {
+ if (mightExpandVariablesCMP0019(linkDirsProp->c_str())) {
+ std::string d = *linkDirsProp;
+ const std::string orig = d;
+ this->ExpandVariablesInString(d, true, true);
+ if (pol == cmPolicies::WARN && d != orig) {
+ /* clang-format off */
+ w << "Evaluated link directories\n"
+ << " " << orig << "\n"
+ << "as\n"
+ << " " << d << "\n";
+ /* clang-format on */
+ }
+ }
+ }
+
+ if (cmProp linkLibsProp = this->GetProperty("LINK_LIBRARIES")) {
+ std::vector<std::string> linkLibs = cmExpandedList(*linkLibsProp);
+
+ for (auto l = linkLibs.begin(); l != linkLibs.end(); ++l) {
+ std::string libName = *l;
+ if (libName == "optimized"_s || libName == "debug"_s) {
+ ++l;
+ libName = *l;
+ }
+ if (mightExpandVariablesCMP0019(libName.c_str())) {
+ const std::string orig = libName;
+ this->ExpandVariablesInString(libName, true, true);
+ if (pol == cmPolicies::WARN && libName != orig) {
+ /* clang-format off */
+ w << "Evaluated link library\n"
+ << " " << orig << "\n"
+ << "as\n"
+ << " " << libName << "\n";
+ /* clang-format on */
+ }
+ }
+ }
+ }
+
+ if (!w.str().empty()) {
+ std::ostringstream m;
+ /* clang-format off */
+ m << cmPolicies::GetPolicyWarning(cmPolicies::CMP0019)
+ << "\n"
+ << "The following variable evaluations were encountered:\n"
+ << w.str();
+ /* clang-format on */
+ this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
+ m.str(), this->Backtrace);
+ }
+}
+
+bool cmMakefile::IsOn(const std::string& name) const
+{
+ return cmIsOn(this->GetDefinition(name));
+}
+
+bool cmMakefile::IsSet(const std::string& name) const
+{
+ cmProp value = this->GetDefinition(name);
+ if (!value) {
+ return false;
+ }
+
+ if (value->empty()) {
+ return false;
+ }
+
+ if (cmIsNOTFOUND(*value)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool cmMakefile::PlatformIs32Bit() const
+{
+ if (cmProp plat_abi = this->GetDefinition("CMAKE_INTERNAL_PLATFORM_ABI")) {
+ if (*plat_abi == "ELF X32") {
+ return false;
+ }
+ }
+ if (cmProp sizeof_dptr = this->GetDefinition("CMAKE_SIZEOF_VOID_P")) {
+ return atoi(sizeof_dptr->c_str()) == 4;
+ }
+ return false;
+}
+
+bool cmMakefile::PlatformIs64Bit() const
+{
+ if (cmProp sizeof_dptr = this->GetDefinition("CMAKE_SIZEOF_VOID_P")) {
+ return atoi(sizeof_dptr->c_str()) == 8;
+ }
+ return false;
+}
+
+bool cmMakefile::PlatformIsx32() const
+{
+ if (cmProp plat_abi = this->GetDefinition("CMAKE_INTERNAL_PLATFORM_ABI")) {
+ if (*plat_abi == "ELF X32") {
+ return true;
+ }
+ }
+ return false;
+}
+
+cmMakefile::AppleSDK cmMakefile::GetAppleSDKType() const
+{
+ std::string sdkRoot;
+ sdkRoot = this->GetSafeDefinition("CMAKE_OSX_SYSROOT");
+ sdkRoot = cmSystemTools::LowerCase(sdkRoot);
+
+ struct
+ {
+ std::string name;
+ AppleSDK sdk;
+ } const sdkDatabase[]{
+ { "appletvos", AppleSDK::AppleTVOS },
+ { "appletvsimulator", AppleSDK::AppleTVSimulator },
+ { "iphoneos", AppleSDK::IPhoneOS },
+ { "iphonesimulator", AppleSDK::IPhoneSimulator },
+ { "watchos", AppleSDK::WatchOS },
+ { "watchsimulator", AppleSDK::WatchSimulator },
+ };
+
+ for (auto const& entry : sdkDatabase) {
+ if (cmHasPrefix(sdkRoot, entry.name) ||
+ sdkRoot.find(std::string("/") + entry.name) != std::string::npos) {
+ return entry.sdk;
+ }
+ }
+
+ return AppleSDK::MacOS;
+}
+
+bool cmMakefile::PlatformIsAppleEmbedded() const
+{
+ return this->GetAppleSDKType() != AppleSDK::MacOS;
+}
+
+const char* cmMakefile::GetSONameFlag(const std::string& language) const
+{
+ std::string name = "CMAKE_SHARED_LIBRARY_SONAME";
+ if (!language.empty()) {
+ name += "_";
+ name += language;
+ }
+ name += "_FLAG";
+ return cmToCStr(this->GetDefinition(name));
+}
+
+bool cmMakefile::CanIWriteThisFile(std::string const& fileName) const
+{
+ if (!this->IsOn("CMAKE_DISABLE_SOURCE_CHANGES")) {
+ return true;
+ }
+ // If we are doing an in-source build, then the test will always fail
+ if (cmSystemTools::SameFile(this->GetHomeDirectory(),
+ this->GetHomeOutputDirectory())) {
+ return !this->IsOn("CMAKE_DISABLE_IN_SOURCE_BUILD");
+ }
+
+ return !cmSystemTools::IsSubDirectory(fileName, this->GetHomeDirectory()) ||
+ cmSystemTools::IsSubDirectory(fileName, this->GetHomeOutputDirectory()) ||
+ cmSystemTools::SameFile(fileName, this->GetHomeOutputDirectory());
+}
+
+const std::string& cmMakefile::GetRequiredDefinition(
+ const std::string& name) const
+{
+ static std::string const empty;
+ const std::string* def = this->GetDefinition(name);
+ if (!def) {
+ cmSystemTools::Error("Error required internal CMake variable not "
+ "set, cmake may not be built correctly.\n"
+ "Missing variable is:\n" +
+ name);
+ return empty;
+ }
+ return *def;
+}
+
+bool cmMakefile::IsDefinitionSet(const std::string& name) const
+{
+ cmProp def = this->StateSnapshot.GetDefinition(name);
+ if (!def) {
+ def = this->GetState()->GetInitializedCacheValue(name);
+ }
+#ifndef CMAKE_BOOTSTRAP
+ if (cmVariableWatch* vv = this->GetVariableWatch()) {
+ if (!def) {
+ vv->VariableAccessed(
+ name, cmVariableWatch::UNKNOWN_VARIABLE_DEFINED_ACCESS, nullptr, this);
+ }
+ }
+#endif
+ return def != nullptr;
+}
+
+cmProp cmMakefile::GetDefinition(const std::string& name) const
+{
+ cmProp def = this->StateSnapshot.GetDefinition(name);
+ if (!def) {
+ def = this->GetState()->GetInitializedCacheValue(name);
+ }
+#ifndef CMAKE_BOOTSTRAP
+ cmVariableWatch* vv = this->GetVariableWatch();
+ if (vv && !this->SuppressSideEffects) {
+ bool const watch_function_executed =
+ vv->VariableAccessed(name,
+ def ? cmVariableWatch::VARIABLE_READ_ACCESS
+ : cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS,
+ cmToCStr(def), this);
+
+ if (watch_function_executed) {
+ // A callback was executed and may have caused re-allocation of the
+ // variable storage. Look it up again for now.
+ // FIXME: Refactor variable storage to avoid this problem.
+ def = this->StateSnapshot.GetDefinition(name);
+ if (!def) {
+ def = this->GetState()->GetInitializedCacheValue(name);
+ }
+ }
+ }
+#endif
+ return def;
+}
+
+const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const
+{
+ static std::string const empty;
+ const std::string* def = this->GetDefinition(name);
+ if (!def) {
+ return empty;
+ }
+ return *def;
+}
+
+bool cmMakefile::GetDefExpandList(const std::string& name,
+ std::vector<std::string>& out,
+ bool emptyArgs) const
+{
+ cmProp def = this->GetDefinition(name);
+ if (!def) {
+ return false;
+ }
+ cmExpandList(*def, out, emptyArgs);
+ return true;
+}
+
+std::vector<std::string> cmMakefile::GetDefinitions() const
+{
+ std::vector<std::string> res = this->StateSnapshot.ClosureKeys();
+ cm::append(res, this->GetState()->GetCacheEntryKeys());
+ std::sort(res.begin(), res.end());
+ return res;
+}
+
+const std::string& cmMakefile::ExpandVariablesInString(
+ std::string& source) const
+{
+ return this->ExpandVariablesInString(source, false, false);
+}
+
+const std::string& cmMakefile::ExpandVariablesInString(
+ std::string& source, bool escapeQuotes, bool noEscapes, bool atOnly,
+ const char* filename, long line, bool removeEmpty, bool replaceAt) const
+{
+ bool compareResults = false;
+ MessageType mtype = MessageType::LOG;
+ std::string errorstr;
+ std::string original;
+
+ // Sanity check the @ONLY mode.
+ if (atOnly && (!noEscapes || !removeEmpty)) {
+ // This case should never be called. At-only is for
+ // configure-file/string which always does no escapes.
+ this->IssueMessage(MessageType::INTERNAL_ERROR,
+ "ExpandVariablesInString @ONLY called "
+ "on something with escapes.");
+ return source;
+ }
+
+ // Variables used in the WARN case.
+ std::string newResult;
+ std::string newErrorstr;
+ MessageType newError = MessageType::LOG;
+
+ switch (this->GetPolicyStatus(cmPolicies::CMP0053)) {
+ case cmPolicies::WARN: {
+ // Save the original string for the warning.
+ original = source;
+ newResult = source;
+ compareResults = true;
+ // Suppress variable watches to avoid calling hooks twice. Suppress new
+ // dereferences since the OLD behavior is still what is actually used.
+ this->SuppressSideEffects = true;
+ newError = this->ExpandVariablesInStringNew(
+ newErrorstr, newResult, escapeQuotes, noEscapes, atOnly, filename,
+ line, replaceAt);
+ this->SuppressSideEffects = false;
+ CM_FALLTHROUGH;
+ }
+ case cmPolicies::OLD:
+ mtype = this->ExpandVariablesInStringOld(errorstr, source, escapeQuotes,
+ noEscapes, atOnly, filename,
+ line, removeEmpty, true);
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ // Messaging here would be *very* verbose.
+ case cmPolicies::NEW:
+ mtype = this->ExpandVariablesInStringNew(errorstr, source, escapeQuotes,
+ noEscapes, atOnly, filename,
+ line, replaceAt);
+ break;
+ }
+
+ // If it's an error in either case, just report the error...
+ if (mtype != MessageType::LOG) {
+ if (mtype == MessageType::FATAL_ERROR) {
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ this->IssueMessage(mtype, errorstr);
+ }
+ // ...otherwise, see if there's a difference that needs to be warned about.
+ else if (compareResults && (newResult != source || newError != mtype)) {
+ std::string msg =
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0053), '\n');
+
+ std::string msg_input = original;
+ cmSystemTools::ReplaceString(msg_input, "\n", "\n ");
+ msg += "For input:\n '";
+ msg += msg_input;
+ msg += "'\n";
+
+ std::string msg_old = source;
+ cmSystemTools::ReplaceString(msg_old, "\n", "\n ");
+ msg += "the old evaluation rules produce:\n '";
+ msg += msg_old;
+ msg += "'\n";
+
+ if (newError == mtype) {
+ std::string msg_new = newResult;
+ cmSystemTools::ReplaceString(msg_new, "\n", "\n ");
+ msg += "but the new evaluation rules produce:\n '";
+ msg += msg_new;
+ msg += "'\n";
+ } else {
+ std::string msg_err = newErrorstr;
+ cmSystemTools::ReplaceString(msg_err, "\n", "\n ");
+ msg += "but the new evaluation rules produce an error:\n ";
+ msg += msg_err;
+ msg += "\n";
+ }
+
+ msg +=
+ "Using the old result for compatibility since the policy is not set.";
+
+ this->IssueMessage(MessageType::AUTHOR_WARNING, msg);
+ }
+
+ return source;
+}
+
+MessageType cmMakefile::ExpandVariablesInStringOld(
+ std::string& errorstr, std::string& source, bool escapeQuotes,
+ bool noEscapes, bool atOnly, const char* filename, long line,
+ bool removeEmpty, bool replaceAt) const
+{
+ // Fast path strings without any special characters.
+ if (source.find_first_of("$@\\") == std::string::npos) {
+ return MessageType::LOG;
+ }
+
+ // Special-case the @ONLY mode.
+ if (atOnly) {
+ // Store an original copy of the input.
+ std::string input = source;
+
+ // Start with empty output.
+ source.clear();
+
+ // Look for one @VAR@ at a time.
+ const char* in = input.c_str();
+ while (this->cmAtVarRegex.find(in)) {
+ // Get the range of the string to replace.
+ const char* first = in + this->cmAtVarRegex.start();
+ const char* last = in + this->cmAtVarRegex.end();
+
+ // Store the unchanged part of the string now.
+ source.append(in, first - in);
+
+ // Lookup the definition of VAR.
+ std::string var(first + 1, last - first - 2);
+ if (cmProp val = this->GetDefinition(var)) {
+ // Store the value in the output escaping as requested.
+ if (escapeQuotes) {
+ source.append(cmEscapeQuotes(*val));
+ } else {
+ source.append(*val);
+ }
+ }
+
+ // Continue looking for @VAR@ further along the string.
+ in = last;
+ }
+
+ // Append the rest of the unchanged part of the string.
+ source.append(in);
+
+ return MessageType::LOG;
+ }
+
+ // This method replaces ${VAR} and @VAR@ where VAR is looked up
+ // with GetDefinition(), if not found in the map, nothing is expanded.
+ // It also supports the $ENV{VAR} syntax where VAR is looked up in
+ // the current environment variables.
+
+ cmCommandArgumentParserHelper parser;
+ parser.SetMakefile(this);
+ parser.SetLineFile(line, filename);
+ parser.SetEscapeQuotes(escapeQuotes);
+ parser.SetNoEscapeMode(noEscapes);
+ parser.SetReplaceAtSyntax(replaceAt);
+ parser.SetRemoveEmpty(removeEmpty);
+ int res = parser.ParseString(source, 0);
+ const char* emsg = parser.GetError();
+ MessageType mtype = MessageType::LOG;
+ if (res && !emsg[0]) {
+ source = parser.GetResult();
+ } else {
+ // Construct the main error message.
+ std::ostringstream error;
+ error << "Syntax error in cmake code ";
+ if (filename && line > 0) {
+ // This filename and line number may be more specific than the
+ // command context because one command invocation can have
+ // arguments on multiple lines.
+ error << "at\n"
+ << " " << filename << ":" << line << "\n";
+ }
+ error << "when parsing string\n"
+ << " " << source << "\n";
+ error << emsg;
+
+ // If the parser failed ("res" is false) then this is a real
+ // argument parsing error, so the policy applies. Otherwise the
+ // parser reported an error message without failing because the
+ // helper implementation is unhappy, which has always reported an
+ // error.
+ mtype = MessageType::FATAL_ERROR;
+ if (!res) {
+ // This is a real argument parsing error. Use policy CMP0010 to
+ // decide whether it is an error.
+ switch (this->GetPolicyStatus(cmPolicies::CMP0010)) {
+ case cmPolicies::WARN:
+ error << "\n" << cmPolicies::GetPolicyWarning(cmPolicies::CMP0010);
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior is to just warn and continue.
+ mtype = MessageType::AUTHOR_WARNING;
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ error << "\n"
+ << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0010);
+ case cmPolicies::NEW:
+ // NEW behavior is to report the error.
+ break;
+ }
+ }
+ errorstr = error.str();
+ }
+ return mtype;
+}
+
+enum t_domain
+{
+ NORMAL,
+ ENVIRONMENT,
+ CACHE
+};
+
+struct t_lookup
+{
+ t_domain domain = NORMAL;
+ size_t loc = 0;
+};
+
+bool cmMakefile::IsProjectFile(const char* filename) const
+{
+ return cmSystemTools::IsSubDirectory(filename, this->GetHomeDirectory()) ||
+ (cmSystemTools::IsSubDirectory(filename, this->GetHomeOutputDirectory()) &&
+ !cmSystemTools::IsSubDirectory(filename, "/CMakeFiles"));
+}
+
+int cmMakefile::GetRecursionDepth() const
+{
+ return this->RecursionDepth;
+}
+
+void cmMakefile::SetRecursionDepth(int recursionDepth)
+{
+ this->RecursionDepth = recursionDepth;
+}
+
+std::string cmMakefile::NewDeferId() const
+{
+ 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.OriginalName();
+ 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,
+ bool replaceAt) const
+{
+ // This method replaces ${VAR} and @VAR@ where VAR is looked up
+ // with GetDefinition(), if not found in the map, nothing is expanded.
+ // It also supports the $ENV{VAR} syntax where VAR is looked up in
+ // the current environment variables.
+
+ const char* in = source.c_str();
+ const char* last = in;
+ std::string result;
+ result.reserve(source.size());
+ std::vector<t_lookup> openstack;
+ bool error = false;
+ bool done = false;
+ MessageType mtype = MessageType::LOG;
+
+ cmState* state = this->GetCMakeInstance()->GetState();
+
+ static const std::string lineVar = "CMAKE_CURRENT_LIST_LINE";
+ do {
+ char inc = *in;
+ switch (inc) {
+ case '}':
+ if (!openstack.empty()) {
+ t_lookup var = openstack.back();
+ openstack.pop_back();
+ result.append(last, in - last);
+ std::string const& lookup = result.substr(var.loc);
+ cmProp value = nullptr;
+ std::string varresult;
+ std::string svalue;
+ switch (var.domain) {
+ case NORMAL:
+ if (filename && lookup == lineVar) {
+ 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);
+ }
+ break;
+ case ENVIRONMENT:
+ if (cmSystemTools::GetEnv(lookup, svalue)) {
+ value = &svalue;
+ }
+ break;
+ case CACHE:
+ value = state->GetCacheEntryValue(lookup);
+ break;
+ }
+ // Get the string we're meant to append to.
+ if (value) {
+ if (escapeQuotes) {
+ varresult = cmEscapeQuotes(*value);
+ } else {
+ varresult = *value;
+ }
+ } else if (!this->SuppressSideEffects) {
+ this->MaybeWarnUninitialized(lookup, filename);
+ }
+ result.replace(var.loc, result.size() - var.loc, varresult);
+ // Start looking from here on out.
+ last = in + 1;
+ }
+ break;
+ case '$':
+ if (!atOnly) {
+ t_lookup lookup;
+ const char* next = in + 1;
+ const char* start = nullptr;
+ char nextc = *next;
+ if (nextc == '{') {
+ // Looking for a variable.
+ start = in + 2;
+ lookup.domain = NORMAL;
+ } else if (nextc == '<') {
+ } else if (!nextc) {
+ result.append(last, next - last);
+ last = next;
+ } else if (cmHasLiteralPrefix(next, "ENV{")) {
+ // Looking for an environment variable.
+ start = in + 5;
+ lookup.domain = ENVIRONMENT;
+ } else if (cmHasLiteralPrefix(next, "CACHE{")) {
+ // Looking for a cache variable.
+ start = in + 7;
+ lookup.domain = CACHE;
+ } else {
+ if (this->cmNamedCurly.find(next)) {
+ errorstr = "Syntax $" +
+ std::string(next, this->cmNamedCurly.end()) +
+ "{} is not supported. Only ${}, $ENV{}, "
+ "and $CACHE{} are allowed.";
+ mtype = MessageType::FATAL_ERROR;
+ error = true;
+ }
+ }
+ if (start) {
+ result.append(last, in - last);
+ last = start;
+ in = start - 1;
+ lookup.loc = result.size();
+ openstack.push_back(lookup);
+ }
+ break;
+ }
+ CM_FALLTHROUGH;
+ case '\\':
+ if (!noEscapes) {
+ const char* next = in + 1;
+ char nextc = *next;
+ if (nextc == 't') {
+ result.append(last, in - last);
+ result.append("\t");
+ last = next + 1;
+ } else if (nextc == 'n') {
+ result.append(last, in - last);
+ result.append("\n");
+ last = next + 1;
+ } else if (nextc == 'r') {
+ result.append(last, in - last);
+ result.append("\r");
+ last = next + 1;
+ } else if (nextc == ';' && openstack.empty()) {
+ // Handled in ExpandListArgument; pass the backslash literally.
+ } else if (isalnum(nextc) || nextc == '\0') {
+ errorstr += "Invalid character escape '\\";
+ if (nextc) {
+ errorstr += nextc;
+ errorstr += "'.";
+ } else {
+ errorstr += "' (at end of input).";
+ }
+ error = true;
+ } else {
+ // Take what we've found so far, skipping the escape character.
+ result.append(last, in - last);
+ // Start tracking from the next character.
+ last = in + 1;
+ }
+ // Skip the next character since it was escaped, but don't read past
+ // the end of the string.
+ if (*last) {
+ ++in;
+ }
+ }
+ break;
+ case '\n':
+ // Onto the next line.
+ ++line;
+ break;
+ case '\0':
+ done = true;
+ break;
+ case '@':
+ if (replaceAt) {
+ const char* nextAt = strchr(in + 1, '@');
+ if (nextAt && nextAt != in + 1 &&
+ nextAt ==
+ in + 1 +
+ strspn(in + 1,
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789/_.+-")) {
+ std::string variable(in + 1, nextAt - in - 1);
+
+ std::string varresult;
+ if (filename && variable == lineVar) {
+ varresult = std::to_string(line);
+ } else {
+ const std::string* def = this->GetDefinition(variable);
+ if (def) {
+ varresult = *def;
+ } else if (!this->SuppressSideEffects) {
+ this->MaybeWarnUninitialized(variable, filename);
+ }
+ }
+
+ if (escapeQuotes) {
+ varresult = cmEscapeQuotes(varresult);
+ }
+ // Skip over the variable.
+ result.append(last, in - last);
+ result.append(varresult);
+ in = nextAt;
+ last = in + 1;
+ break;
+ }
+ }
+ // Failed to find a valid @ expansion; treat it as literal.
+ /* FALLTHROUGH */
+ default: {
+ if (!openstack.empty() &&
+ !(isalnum(inc) || inc == '_' || inc == '/' || inc == '.' ||
+ inc == '+' || inc == '-')) {
+ errorstr += "Invalid character (\'";
+ errorstr += inc;
+ result.append(last, in - last);
+ errorstr += "\') in a variable name: "
+ "'" +
+ result.substr(openstack.back().loc) + "'";
+ mtype = MessageType::FATAL_ERROR;
+ error = true;
+ }
+ break;
+ }
+ }
+ // Look at the next character.
+ } while (!error && !done && *++in);
+
+ // Check for open variable references yet.
+ if (!error && !openstack.empty()) {
+ // There's an open variable reference waiting. Policy CMP0010 flags
+ // whether this is an error or not. The new parser now enforces
+ // CMP0010 as well.
+ errorstr += "There is an unterminated variable reference.";
+ error = true;
+ }
+
+ if (error) {
+ std::ostringstream emsg;
+ emsg << "Syntax error in cmake code ";
+ if (filename) {
+ // This filename and line number may be more specific than the
+ // command context because one command invocation can have
+ // arguments on multiple lines.
+ emsg << "at\n"
+ << " " << filename << ":" << line << "\n";
+ }
+ emsg << "when parsing string\n"
+ << " " << source << "\n";
+ emsg << errorstr;
+ mtype = MessageType::FATAL_ERROR;
+ errorstr = emsg.str();
+ } else {
+ // Append the rest of the unchanged part of the string.
+ result.append(last);
+
+ source = result;
+ }
+
+ return mtype;
+}
+
+void cmMakefile::RemoveVariablesInString(std::string& source,
+ bool atOnly) const
+{
+ if (!atOnly) {
+ cmsys::RegularExpression var("(\\${[A-Za-z_0-9]*})");
+ while (var.find(source)) {
+ source.erase(var.start(), var.end() - var.start());
+ }
+ }
+
+ if (!atOnly) {
+ cmsys::RegularExpression varb("(\\$ENV{[A-Za-z_0-9]*})");
+ while (varb.find(source)) {
+ source.erase(varb.start(), varb.end() - varb.start());
+ }
+ }
+ cmsys::RegularExpression var2("(@[A-Za-z_0-9]*@)");
+ while (var2.find(source)) {
+ source.erase(var2.start(), var2.end() - var2.start());
+ }
+}
+
+std::string cmMakefile::GetDefaultConfiguration() const
+{
+ if (this->GetGlobalGenerator()->IsMultiConfig()) {
+ return std::string{};
+ }
+ return this->GetSafeDefinition("CMAKE_BUILD_TYPE");
+}
+
+std::vector<std::string> cmMakefile::GetGeneratorConfigs(
+ GeneratorConfigQuery mode) const
+{
+ std::vector<std::string> configs;
+ if (this->GetGlobalGenerator()->IsMultiConfig()) {
+ this->GetDefExpandList("CMAKE_CONFIGURATION_TYPES", configs);
+ } else if (mode != cmMakefile::OnlyMultiConfig) {
+ const std::string& buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ if (!buildType.empty()) {
+ configs.emplace_back(buildType);
+ }
+ }
+ if (mode == cmMakefile::IncludeEmptyConfig && configs.empty()) {
+ configs.emplace_back();
+ }
+ return configs;
+}
+
+bool cmMakefile::IsFunctionBlocked(const cmListFileFunction& lff,
+ cmExecutionStatus& status)
+{
+ // if there are no blockers get out of here
+ if (this->FunctionBlockers.empty()) {
+ return false;
+ }
+
+ return this->FunctionBlockers.top()->IsFunctionBlocked(lff, status);
+}
+
+void cmMakefile::PushFunctionBlockerBarrier()
+{
+ this->FunctionBlockerBarriers.push_back(this->FunctionBlockers.size());
+}
+
+void cmMakefile::PopFunctionBlockerBarrier(bool reportError)
+{
+ // Remove any extra entries pushed on the barrier.
+ FunctionBlockersType::size_type barrier =
+ this->FunctionBlockerBarriers.back();
+ while (this->FunctionBlockers.size() > barrier) {
+ std::unique_ptr<cmFunctionBlocker> fb(
+ std::move(this->FunctionBlockers.top()));
+ this->FunctionBlockers.pop();
+ if (reportError) {
+ // Report the context in which the unclosed block was opened.
+ cmListFileContext const& lfc = fb->GetStartingContext();
+ std::ostringstream e;
+ /* clang-format off */
+ e << "A logical block opening on the line\n"
+ << " " << lfc << "\n"
+ << "is not closed.";
+ /* clang-format on */
+ this->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ reportError = false;
+ }
+ }
+
+ // Remove the barrier.
+ this->FunctionBlockerBarriers.pop_back();
+}
+
+void cmMakefile::PushLoopBlock()
+{
+ assert(!this->LoopBlockCounter.empty());
+ this->LoopBlockCounter.top()++;
+}
+
+void cmMakefile::PopLoopBlock()
+{
+ assert(!this->LoopBlockCounter.empty());
+ assert(this->LoopBlockCounter.top() > 0);
+ this->LoopBlockCounter.top()--;
+}
+
+void cmMakefile::PushLoopBlockBarrier()
+{
+ this->LoopBlockCounter.push(0);
+}
+
+void cmMakefile::PopLoopBlockBarrier()
+{
+ assert(!this->LoopBlockCounter.empty());
+ assert(this->LoopBlockCounter.top() == 0);
+ this->LoopBlockCounter.pop();
+}
+
+bool cmMakefile::IsLoopBlock() const
+{
+ assert(!this->LoopBlockCounter.empty());
+ return !this->LoopBlockCounter.empty() && this->LoopBlockCounter.top() > 0;
+}
+
+bool cmMakefile::ExpandArguments(std::vector<cmListFileArgument> const& inArgs,
+ std::vector<std::string>& outArgs) const
+{
+ std::string const& filename = this->GetBacktrace().Top().FilePath;
+ std::string value;
+ outArgs.reserve(inArgs.size());
+ for (cmListFileArgument const& i : inArgs) {
+ // No expansion in a bracket argument.
+ if (i.Delim == cmListFileArgument::Bracket) {
+ outArgs.push_back(i.Value);
+ continue;
+ }
+ // Expand the variables in the argument.
+ value = i.Value;
+ 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.
+ if (i.Delim == cmListFileArgument::Quoted) {
+ outArgs.push_back(value);
+ } else {
+ cmExpandList(value, outArgs);
+ }
+ }
+ return !cmSystemTools::GetFatalErrorOccured();
+}
+
+bool cmMakefile::ExpandArguments(
+ std::vector<cmListFileArgument> const& inArgs,
+ std::vector<cmExpandedCommandArgument>& outArgs) const
+{
+ std::string const& filename = this->GetBacktrace().Top().FilePath;
+ std::string value;
+ outArgs.reserve(inArgs.size());
+ for (cmListFileArgument const& i : inArgs) {
+ // No expansion in a bracket argument.
+ if (i.Delim == cmListFileArgument::Bracket) {
+ outArgs.emplace_back(i.Value, true);
+ continue;
+ }
+ // Expand the variables in the argument.
+ value = i.Value;
+ 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.
+ if (i.Delim == cmListFileArgument::Quoted) {
+ outArgs.emplace_back(value, true);
+ } else {
+ std::vector<std::string> stringArgs = cmExpandedList(value);
+ for (std::string const& stringArg : stringArgs) {
+ outArgs.emplace_back(stringArg, false);
+ }
+ }
+ }
+ return !cmSystemTools::GetFatalErrorOccured();
+}
+
+void cmMakefile::AddFunctionBlocker(std::unique_ptr<cmFunctionBlocker> fb)
+{
+ if (!this->ExecutionStatusStack.empty()) {
+ // Record the context in which the blocker is created.
+ fb->SetStartingContext(this->Backtrace.Top());
+ }
+
+ this->FunctionBlockers.push(std::move(fb));
+}
+
+std::unique_ptr<cmFunctionBlocker> cmMakefile::RemoveFunctionBlocker()
+{
+ assert(!this->FunctionBlockers.empty());
+ assert(this->FunctionBlockerBarriers.empty() ||
+ this->FunctionBlockers.size() > this->FunctionBlockerBarriers.back());
+
+ auto b = std::move(this->FunctionBlockers.top());
+ this->FunctionBlockers.pop();
+ return b;
+}
+
+std::string const& cmMakefile::GetHomeDirectory() const
+{
+ return this->GetCMakeInstance()->GetHomeDirectory();
+}
+
+std::string const& cmMakefile::GetHomeOutputDirectory() const
+{
+ return this->GetCMakeInstance()->GetHomeOutputDirectory();
+}
+
+void cmMakefile::SetScriptModeFile(std::string const& scriptfile)
+{
+ this->AddDefinition("CMAKE_SCRIPT_MODE_FILE", scriptfile);
+}
+
+void cmMakefile::SetArgcArgv(const std::vector<std::string>& args)
+{
+ this->AddDefinition("CMAKE_ARGC", std::to_string(args.size()));
+ // this->MarkVariableAsUsed("CMAKE_ARGC");
+
+ for (unsigned int t = 0; t < args.size(); ++t) {
+ std::ostringstream tmpStream;
+ tmpStream << "CMAKE_ARGV" << t;
+ this->AddDefinition(tmpStream.str(), args[t]);
+ // this->MarkVariableAsUsed(tmpStream.str().c_str());
+ }
+}
+
+cmSourceFile* cmMakefile::GetSource(const std::string& sourceName,
+ cmSourceFileLocationKind kind) const
+{
+ // First check "Known" paths (avoids the creation of cmSourceFileLocation)
+ if (kind == cmSourceFileLocationKind::Known) {
+ auto sfsi = this->KnownFileSearchIndex.find(sourceName);
+ if (sfsi != this->KnownFileSearchIndex.end()) {
+ return sfsi->second;
+ }
+ }
+
+ cmSourceFileLocation sfl(this, sourceName, kind);
+ auto name = this->GetCMakeInstance()->StripExtension(sfl.GetName());
+#if defined(_WIN32) || defined(__APPLE__)
+ name = cmSystemTools::LowerCase(name);
+#endif
+ auto sfsi = this->SourceFileSearchIndex.find(name);
+ if (sfsi != this->SourceFileSearchIndex.end()) {
+ for (auto* sf : sfsi->second) {
+ if (sf->Matches(sfl)) {
+ return sf;
+ }
+ }
+ }
+ return nullptr;
+}
+
+cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName,
+ bool generated,
+ cmSourceFileLocationKind kind)
+{
+ auto sf = cm::make_unique<cmSourceFile>(this, sourceName, generated, kind);
+ auto name =
+ this->GetCMakeInstance()->StripExtension(sf->GetLocation().GetName());
+#if defined(_WIN32) || defined(__APPLE__)
+ name = cmSystemTools::LowerCase(name);
+#endif
+ this->SourceFileSearchIndex[name].push_back(sf.get());
+ // for "Known" paths add direct lookup (used for faster lookup in GetSource)
+ if (kind == cmSourceFileLocationKind::Known) {
+ this->KnownFileSearchIndex[sourceName] = sf.get();
+ }
+
+ this->SourceFiles.push_back(std::move(sf));
+
+ return this->SourceFiles.back().get();
+}
+
+cmSourceFile* cmMakefile::GetOrCreateSource(const std::string& sourceName,
+ bool generated,
+ cmSourceFileLocationKind kind)
+{
+ if (cmSourceFile* esf = this->GetSource(sourceName, kind)) {
+ return esf;
+ }
+ return this->CreateSource(sourceName, generated, kind);
+}
+
+cmSourceFile* cmMakefile::GetOrCreateGeneratedSource(
+ const std::string& sourceName)
+{
+ cmSourceFile* sf =
+ this->GetOrCreateSource(sourceName, true, cmSourceFileLocationKind::Known);
+ sf->MarkAsGenerated(); // In case we did not create the source file.
+ return sf;
+}
+
+void cmMakefile::CreateGeneratedOutputs(
+ const std::vector<std::string>& outputs)
+{
+ for (std::string const& o : outputs) {
+ if (cmGeneratorExpression::Find(o) == std::string::npos) {
+ this->GetOrCreateGeneratedSource(o);
+ }
+ }
+}
+
+void cmMakefile::AddTargetObject(std::string const& tgtName,
+ std::string const& objFile)
+{
+ cmSourceFile* sf = this->GetOrCreateSource(objFile, true);
+ sf->SetObjectLibrary(tgtName);
+ sf->SetProperty("EXTERNAL_OBJECT", "1");
+#if !defined(CMAKE_BOOTSTRAP)
+ this->SourceGroups[this->ObjectLibrariesSourceGroupIndex].AddGroupFile(
+ sf->ResolveFullPath());
+#endif
+}
+
+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);
+ }
+ // If RC is explicitly listed we need to do it after other languages.
+ // On some platforms we enable RC implicitly while enabling others.
+ // Do not let that look like recursive enable_language(RC).
+ std::vector<std::string> langs;
+ std::vector<std::string> langsRC;
+ langs.reserve(lang.size());
+ for (std::string const& i : lang) {
+ if (i == "RC") {
+ langsRC.push_back(i);
+ } else {
+ langs.push_back(i);
+ }
+ }
+ if (!langs.empty()) {
+ this->GetGlobalGenerator()->EnableLanguage(langs, this, optional);
+ }
+ if (!langsRC.empty()) {
+ this->GetGlobalGenerator()->EnableLanguage(langsRC, this, optional);
+ }
+}
+
+int cmMakefile::TryCompile(const std::string& srcdir,
+ const std::string& bindir,
+ const std::string& projectName,
+ const std::string& targetName, bool fast, int jobs,
+ const std::vector<std::string>* cmakeArgs,
+ std::string& output)
+{
+ this->IsSourceFileTryCompile = fast;
+ // does the binary directory exist ? If not create it...
+ if (!cmSystemTools::FileIsDirectory(bindir)) {
+ cmSystemTools::MakeDirectory(bindir);
+ }
+
+ // change to the tests directory and run cmake
+ // use the cmake object instead of calling cmake
+ cmWorkingDirectory workdir(bindir);
+ if (workdir.Failed()) {
+ this->IssueMessage(MessageType::FATAL_ERROR,
+ "Failed to set working directory to " + bindir + " : " +
+ std::strerror(workdir.GetLastResult()));
+ cmSystemTools::SetFatalErrorOccured();
+ this->IsSourceFileTryCompile = false;
+ return 1;
+ }
+
+ // make sure the same generator is used
+ // use this program as the cmake to be run, it should not
+ // be run that way but the cmake object requires a vailid path
+ cmake cm(cmake::RoleProject, cmState::Project);
+ cm.SetIsInTryCompile(true);
+ auto gg = cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName());
+ if (!gg) {
+ this->IssueMessage(MessageType::INTERNAL_ERROR,
+ "Global generator '" +
+ this->GetGlobalGenerator()->GetName() +
+ "' could not be created.");
+ cmSystemTools::SetFatalErrorOccured();
+ this->IsSourceFileTryCompile = false;
+ return 1;
+ }
+ gg->RecursionDepth = this->RecursionDepth;
+ cm.SetGlobalGenerator(std::move(gg));
+
+ // do a configure
+ cm.SetHomeDirectory(srcdir);
+ cm.SetHomeOutputDirectory(bindir);
+ cm.SetGeneratorInstance(this->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE"));
+ cm.SetGeneratorPlatform(this->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM"));
+ cm.SetGeneratorToolset(this->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET"));
+ cm.LoadCache();
+ if (!cm.GetGlobalGenerator()->IsMultiConfig()) {
+ if (cmProp config =
+ this->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION")) {
+ // Tell the single-configuration generator which one to use.
+ // Add this before the user-provided CMake arguments in case
+ // one of the arguments is -DCMAKE_BUILD_TYPE=...
+ cm.AddCacheEntry("CMAKE_BUILD_TYPE", config->c_str(),
+ "Build configuration", cmStateEnums::STRING);
+ }
+ }
+ cmProp recursionDepth = this->GetDefinition("CMAKE_MAXIMUM_RECURSION_DEPTH");
+ if (recursionDepth) {
+ cm.AddCacheEntry("CMAKE_MAXIMUM_RECURSION_DEPTH", recursionDepth->c_str(),
+ "Maximum recursion depth", cmStateEnums::STRING);
+ }
+ // if cmake args were provided then pass them in
+ if (cmakeArgs) {
+ // FIXME: Workaround to ignore unused CLI variables in try-compile.
+ //
+ // Ideally we should use SetArgs for options like --no-warn-unused-cli.
+ // However, there is a subtle problem when certain arguments are passed to
+ // a macro wrapping around try_compile or try_run that does not escape
+ // semicolons in its parameters but just passes ${ARGV} or ${ARGN}. In
+ // this case a list argument like "-DVAR=a;b" gets split into multiple
+ // cmake arguments "-DVAR=a" and "b". Currently SetCacheArgs ignores
+ // argument "b" and uses just "-DVAR=a", leading to a subtle bug in that
+ // the try_compile or try_run does not get the proper value of VAR. If we
+ // call SetArgs here then it would treat "b" as the source directory and
+ // cause an error such as "The source directory .../CMakeFiles/CMakeTmp/b
+ // does not exist", thus breaking the try_compile or try_run completely.
+ //
+ // Strictly speaking the bug is in the wrapper macro because the CMake
+ // language has always flattened nested lists and the macro should escape
+ // the semicolons in its arguments before forwarding them. However, this
+ // bug is so subtle that projects typically work anyway, usually because
+ // the value VAR=a is sufficient for the try_compile or try_run to get the
+ // correct result. Calling SetArgs here would break such projects that
+ // previously built. Instead we work around the issue by never reporting
+ // unused arguments and ignoring options such as --no-warn-unused-cli.
+ cm.SetWarnUnusedCli(false);
+ // cm.SetArgs(*cmakeArgs, true);
+
+ cm.SetCacheArgs(*cmakeArgs);
+ }
+ // to save time we pass the EnableLanguage info directly
+ cm.GetGlobalGenerator()->EnableLanguagesFromGenerator(
+ this->GetGlobalGenerator(), this);
+ if (this->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
+ cm.AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "TRUE", "",
+ cmStateEnums::INTERNAL);
+ } else {
+ cm.AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "FALSE", "",
+ cmStateEnums::INTERNAL);
+ }
+ if (cm.Configure() != 0) {
+ this->IssueMessage(MessageType::FATAL_ERROR,
+ "Failed to configure test project build system.");
+ cmSystemTools::SetFatalErrorOccured();
+ this->IsSourceFileTryCompile = false;
+ return 1;
+ }
+
+ if (cm.Generate() != 0) {
+ this->IssueMessage(MessageType::FATAL_ERROR,
+ "Failed to generate test project build system.");
+ cmSystemTools::SetFatalErrorOccured();
+ this->IsSourceFileTryCompile = false;
+ return 1;
+ }
+
+ // finally call the generator to actually build the resulting project
+ int ret = this->GetGlobalGenerator()->TryCompile(
+ jobs, srcdir, bindir, projectName, targetName, fast, output, this);
+
+ this->IsSourceFileTryCompile = false;
+ return ret;
+}
+
+bool cmMakefile::GetIsSourceFileTryCompile() const
+{
+ return this->IsSourceFileTryCompile;
+}
+
+cmake* cmMakefile::GetCMakeInstance() const
+{
+ return this->GlobalGenerator->GetCMakeInstance();
+}
+
+cmMessenger* cmMakefile::GetMessenger() const
+{
+ return this->GetCMakeInstance()->GetMessenger();
+}
+
+cmGlobalGenerator* cmMakefile::GetGlobalGenerator() const
+{
+ return this->GlobalGenerator;
+}
+
+#ifndef CMAKE_BOOTSTRAP
+cmVariableWatch* cmMakefile::GetVariableWatch() const
+{
+ if (this->GetCMakeInstance() &&
+ this->GetCMakeInstance()->GetVariableWatch()) {
+ return this->GetCMakeInstance()->GetVariableWatch();
+ }
+ return nullptr;
+}
+#endif
+
+cmState* cmMakefile::GetState() const
+{
+ return this->GetCMakeInstance()->GetState();
+}
+
+void cmMakefile::DisplayStatus(const std::string& message, float s) const
+{
+ cmake* cm = this->GetCMakeInstance();
+ if (cm->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
+ // don't output any STATUS message in FIND_PACKAGE_MODE, since they will
+ // directly be fed to the compiler, which will be confused.
+ return;
+ }
+ cm->UpdateProgress(message, s);
+}
+
+std::string cmMakefile::GetModulesFile(const std::string& filename,
+ bool& system, bool debug,
+ std::string& debugBuffer) const
+{
+ std::string result;
+
+ // We search the module always in CMAKE_ROOT and in CMAKE_MODULE_PATH,
+ // and then decide based on the policy setting which one to return.
+ // See CMP0017 for more details.
+ // The specific problem was that KDE 4.5.0 installs a
+ // FindPackageHandleStandardArgs.cmake which doesn't have the new features
+ // of FPHSA.cmake introduced in CMake 2.8.3 yet, and by setting
+ // CMAKE_MODULE_PATH also e.g. FindZLIB.cmake from cmake included
+ // FPHSA.cmake from kdelibs and not from CMake, and tried to use the
+ // new features, which were not there in the version from kdelibs, and so
+ // failed ("
+ std::string moduleInCMakeRoot;
+ std::string moduleInCMakeModulePath;
+
+ // Always search in CMAKE_MODULE_PATH:
+ cmProp cmakeModulePath = this->GetDefinition("CMAKE_MODULE_PATH");
+ if (cmakeModulePath) {
+ std::vector<std::string> modulePath = cmExpandedList(*cmakeModulePath);
+
+ // Look through the possible module directories.
+ for (std::string itempl : modulePath) {
+ cmSystemTools::ConvertToUnixSlashes(itempl);
+ itempl += "/";
+ itempl += filename;
+ if (cmSystemTools::FileExists(itempl)) {
+ moduleInCMakeModulePath = itempl;
+ break;
+ }
+ if (debug) {
+ debugBuffer = cmStrCat(debugBuffer, " ", itempl, "\n");
+ }
+ }
+ }
+
+ // Always search in the standard modules location.
+ moduleInCMakeRoot =
+ cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/", filename);
+ cmSystemTools::ConvertToUnixSlashes(moduleInCMakeRoot);
+ if (!cmSystemTools::FileExists(moduleInCMakeRoot)) {
+ if (debug) {
+ debugBuffer = cmStrCat(debugBuffer, " ", moduleInCMakeRoot, "\n");
+ }
+ moduleInCMakeRoot.clear();
+ }
+
+ // Normally, prefer the files found in CMAKE_MODULE_PATH. Only when the file
+ // from which we are being called is located itself in CMAKE_ROOT, then
+ // prefer results from CMAKE_ROOT depending on the policy setting.
+ system = false;
+ result = moduleInCMakeModulePath;
+ if (result.empty()) {
+ system = true;
+ result = moduleInCMakeRoot;
+ }
+
+ if (!moduleInCMakeModulePath.empty() && !moduleInCMakeRoot.empty()) {
+ cmProp currentFile = this->GetDefinition("CMAKE_CURRENT_LIST_FILE");
+ std::string mods = cmSystemTools::GetCMakeRoot() + "/Modules/";
+ if (currentFile && cmSystemTools::IsSubDirectory(*currentFile, mods)) {
+ switch (this->GetPolicyStatus(cmPolicies::CMP0017)) {
+ case cmPolicies::WARN: {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "File " << *currentFile << " includes "
+ << moduleInCMakeModulePath
+ << " (found via CMAKE_MODULE_PATH) which shadows "
+ << moduleInCMakeRoot << ". This may cause errors later on .\n"
+ << cmPolicies::GetPolicyWarning(cmPolicies::CMP0017);
+ /* clang-format on */
+
+ this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+ CM_FALLTHROUGH;
+ }
+ case cmPolicies::OLD:
+ system = false;
+ result = moduleInCMakeModulePath;
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ system = true;
+ result = moduleInCMakeRoot;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+void cmMakefile::ConfigureString(const std::string& input, std::string& output,
+ bool atOnly, bool escapeQuotes) const
+{
+ // Split input to handle one line at a time.
+ std::string::const_iterator lineStart = input.begin();
+ while (lineStart != input.end()) {
+ // Find the end of this line.
+ std::string::const_iterator lineEnd = lineStart;
+ while (lineEnd != input.end() && *lineEnd != '\n') {
+ ++lineEnd;
+ }
+
+ // Copy the line.
+ std::string line(lineStart, lineEnd);
+
+ // Skip the newline character.
+ bool haveNewline = (lineEnd != input.end());
+ if (haveNewline) {
+ ++lineEnd;
+ }
+
+ // Replace #cmakedefine instances.
+ if (this->cmDefineRegex.find(line)) {
+ cmProp def = this->GetDefinition(this->cmDefineRegex.match(2));
+ if (!cmIsOff(def)) {
+ const std::string indentation = this->cmDefineRegex.match(1);
+ cmSystemTools::ReplaceString(line, "#" + indentation + "cmakedefine",
+ "#" + indentation + "define");
+ output += line;
+ } else {
+ output += "/* #undef ";
+ output += this->cmDefineRegex.match(2);
+ output += " */";
+ }
+ } else if (this->cmDefine01Regex.find(line)) {
+ const std::string indentation = this->cmDefine01Regex.match(1);
+ cmProp def = this->GetDefinition(this->cmDefine01Regex.match(2));
+ cmSystemTools::ReplaceString(line, "#" + indentation + "cmakedefine01",
+ "#" + indentation + "define");
+ output += line;
+ if (!cmIsOff(def)) {
+ output += " 1";
+ } else {
+ output += " 0";
+ }
+ } else {
+ output += line;
+ }
+
+ if (haveNewline) {
+ output += "\n";
+ }
+
+ // Move to the next line.
+ lineStart = lineEnd;
+ }
+
+ // Perform variable replacements.
+ const char* filename = nullptr;
+ long lineNumber = -1;
+ if (!this->Backtrace.Empty()) {
+ const auto& currentTrace = this->Backtrace.Top();
+ filename = currentTrace.FilePath.c_str();
+ lineNumber = currentTrace.Line;
+ }
+ this->ExpandVariablesInString(output, escapeQuotes, true, atOnly, filename,
+ lineNumber, true, true);
+}
+
+int cmMakefile::ConfigureFile(const std::string& infile,
+ const std::string& outfile, bool copyonly,
+ bool atOnly, bool escapeQuotes,
+ mode_t permissions, cmNewLineStyle newLine)
+{
+ int res = 1;
+ if (!this->CanIWriteThisFile(outfile)) {
+ cmSystemTools::Error("Attempt to write file: " + outfile +
+ " into a source directory.");
+ return 0;
+ }
+ if (!cmSystemTools::FileExists(infile)) {
+ cmSystemTools::Error("File " + infile + " does not exist.");
+ return 0;
+ }
+ std::string soutfile = outfile;
+ const std::string& sinfile = infile;
+ this->AddCMakeDependFile(sinfile);
+ cmSystemTools::ConvertToUnixSlashes(soutfile);
+
+ // Re-generate if non-temporary outputs are missing.
+ // when we finalize the configuration we will remove all
+ // output files that now don't exist.
+ this->AddCMakeOutputFile(soutfile);
+
+ if (permissions == 0) {
+ cmSystemTools::GetPermissions(sinfile, permissions);
+ }
+
+ std::string::size_type pos = soutfile.rfind('/');
+ if (pos != std::string::npos) {
+ std::string path = soutfile.substr(0, pos);
+ cmSystemTools::MakeDirectory(path);
+ }
+
+ if (copyonly) {
+ if (!cmSystemTools::CopyFileIfDifferent(sinfile, soutfile)) {
+ this->IssueMessage(MessageType::FATAL_ERROR,
+ cmSystemTools::GetLastSystemError());
+ return 0;
+ }
+ if (!cmSystemTools::SetPermissions(soutfile, permissions)) {
+ this->IssueMessage(MessageType::FATAL_ERROR,
+ cmSystemTools::GetLastSystemError());
+ return 0;
+ }
+ } else {
+ std::string newLineCharacters;
+ std::ios::openmode omode = std::ios::out | std::ios::trunc;
+ if (newLine.IsValid()) {
+ newLineCharacters = newLine.GetCharacters();
+ omode |= std::ios::binary;
+ } else {
+ newLineCharacters = "\n";
+ }
+ std::string tempOutputFile = cmStrCat(soutfile, ".tmp");
+ cmsys::ofstream fout(tempOutputFile.c_str(), omode);
+ if (!fout) {
+ cmSystemTools::Error("Could not open file for write in copy operation " +
+ tempOutputFile);
+ cmSystemTools::ReportLastSystemError("");
+ return 0;
+ }
+ cmsys::ifstream fin(sinfile.c_str());
+ if (!fin) {
+ cmSystemTools::Error("Could not open file for read in copy operation " +
+ sinfile);
+ return 0;
+ }
+
+ cmsys::FStream::BOM bom = cmsys::FStream::ReadBOM(fin);
+ if (bom != cmsys::FStream::BOM_None && bom != cmsys::FStream::BOM_UTF8) {
+ std::ostringstream e;
+ e << "File starts with a Byte-Order-Mark that is not UTF-8:\n "
+ << sinfile;
+ this->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return 0;
+ }
+ // rewind to copy BOM to output file
+ fin.seekg(0);
+
+ // now copy input to output and expand variables in the
+ // input file at the same time
+ std::string inLine;
+ std::string outLine;
+ while (cmSystemTools::GetLineFromStream(fin, inLine)) {
+ outLine.clear();
+ this->ConfigureString(inLine, outLine, atOnly, escapeQuotes);
+ fout << outLine << newLineCharacters;
+ }
+ // close the files before attempting to copy
+ fin.close();
+ fout.close();
+ if (!cmSystemTools::CopyFileIfDifferent(tempOutputFile, soutfile)) {
+ this->IssueMessage(MessageType::FATAL_ERROR,
+ cmSystemTools::GetLastSystemError());
+ res = 0;
+ } else {
+ if (!cmSystemTools::SetPermissions(soutfile, permissions)) {
+ this->IssueMessage(MessageType::FATAL_ERROR,
+ cmSystemTools::GetLastSystemError());
+ res = 0;
+ }
+ }
+ cmSystemTools::RemoveFile(tempOutputFile);
+ }
+ return res;
+}
+
+void cmMakefile::SetProperty(const std::string& prop, const char* value)
+{
+ this->StateSnapshot.GetDirectory().SetProperty(prop, value, this->Backtrace);
+}
+
+void cmMakefile::AppendProperty(const std::string& prop,
+ const std::string& value, bool asString)
+{
+ this->StateSnapshot.GetDirectory().AppendProperty(prop, value, asString,
+ this->Backtrace);
+}
+
+cmProp cmMakefile::GetProperty(const std::string& prop) const
+{
+ // Check for computed properties.
+ static std::string output;
+ if (prop == "TESTS") {
+ std::vector<std::string> keys;
+ // get list of keys
+ std::transform(this->Tests.begin(), this->Tests.end(),
+ std::back_inserter(keys),
+ [](decltype(this->Tests)::value_type const& pair) {
+ return pair.first;
+ });
+ output = cmJoin(keys, ";");
+ return &output;
+ }
+
+ return this->StateSnapshot.GetDirectory().GetProperty(prop);
+}
+
+cmProp cmMakefile::GetProperty(const std::string& prop, bool chain) const
+{
+ return this->StateSnapshot.GetDirectory().GetProperty(prop, chain);
+}
+
+bool cmMakefile::GetPropertyAsBool(const std::string& prop) const
+{
+ return cmIsOn(this->GetProperty(prop));
+}
+
+std::vector<std::string> cmMakefile::GetPropertyKeys() const
+{
+ return this->StateSnapshot.GetDirectory().GetPropertyKeys();
+}
+
+cmTarget* cmMakefile::FindLocalNonAliasTarget(const std::string& name) const
+{
+ auto i = this->Targets.find(name);
+ if (i != this->Targets.end()) {
+ return &i->second;
+ }
+ return nullptr;
+}
+
+cmTest* cmMakefile::CreateTest(const std::string& testName)
+{
+ cmTest* test = this->GetTest(testName);
+ if (test) {
+ return test;
+ }
+ auto newTest = cm::make_unique<cmTest>(this);
+ test = newTest.get();
+ newTest->SetName(testName);
+ this->Tests[testName] = std::move(newTest);
+ return test;
+}
+
+cmTest* cmMakefile::GetTest(const std::string& testName) const
+{
+ auto mi = this->Tests.find(testName);
+ if (mi != this->Tests.end()) {
+ return mi->second.get();
+ }
+ return nullptr;
+}
+
+void cmMakefile::GetTests(const std::string& config,
+ std::vector<cmTest*>& tests) const
+{
+ for (const auto& generator : this->GetTestGenerators()) {
+ if (generator->TestsForConfig(config)) {
+ tests.push_back(generator->GetTest());
+ }
+ }
+}
+
+void cmMakefile::AddCMakeDependFilesFromUser()
+{
+ std::vector<std::string> deps;
+ if (cmProp deps_str = this->GetProperty("CMAKE_CONFIGURE_DEPENDS")) {
+ cmExpandList(*deps_str, deps);
+ }
+ for (std::string const& dep : deps) {
+ if (cmSystemTools::FileIsFullPath(dep)) {
+ this->AddCMakeDependFile(dep);
+ } else {
+ std::string f = cmStrCat(this->GetCurrentSourceDirectory(), '/', dep);
+ this->AddCMakeDependFile(f);
+ }
+ }
+}
+
+std::string cmMakefile::FormatListFileStack() const
+{
+ std::vector<std::string> listFiles;
+ cmStateSnapshot snp = this->StateSnapshot;
+ while (snp.IsValid()) {
+ listFiles.push_back(snp.GetExecutionListFile());
+ snp = snp.GetCallStackParent();
+ }
+ std::reverse(listFiles.begin(), listFiles.end());
+ std::ostringstream tmp;
+ size_t depth = listFiles.size();
+ if (depth > 0) {
+ auto it = listFiles.end();
+ do {
+ if (depth != listFiles.size()) {
+ tmp << "\n ";
+ }
+ --it;
+ tmp << "[";
+ tmp << depth;
+ tmp << "]\t";
+ tmp << *it;
+ depth--;
+ } while (it != listFiles.begin());
+ }
+ return tmp.str();
+}
+
+void cmMakefile::PushScope()
+{
+ this->StateSnapshot =
+ this->GetState()->CreateVariableScopeSnapshot(this->StateSnapshot);
+ this->PushLoopBlockBarrier();
+
+#if !defined(CMAKE_BOOTSTRAP)
+ this->GetGlobalGenerator()->GetFileLockPool().PushFunctionScope();
+#endif
+}
+
+void cmMakefile::PopScope()
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ this->GetGlobalGenerator()->GetFileLockPool().PopFunctionScope();
+#endif
+
+ this->PopLoopBlockBarrier();
+
+ this->PopSnapshot();
+}
+
+void cmMakefile::RaiseScope(const std::string& var, const char* varDef)
+{
+ if (var.empty()) {
+ return;
+ }
+
+ if (!this->StateSnapshot.RaiseScope(var, varDef)) {
+ std::ostringstream m;
+ m << "Cannot set \"" << var << "\": current scope has no parent.";
+ this->IssueMessage(MessageType::AUTHOR_WARNING, m.str());
+ return;
+ }
+
+#ifndef CMAKE_BOOTSTRAP
+ cmVariableWatch* vv = this->GetVariableWatch();
+ if (vv) {
+ vv->VariableAccessed(var, cmVariableWatch::VARIABLE_MODIFIED_ACCESS,
+ varDef, this);
+ }
+#endif
+}
+
+cmTarget* cmMakefile::AddImportedTarget(const std::string& name,
+ cmStateEnums::TargetType type,
+ bool global)
+{
+ // Create the target.
+ std::unique_ptr<cmTarget> target(
+ new cmTarget(name, type,
+ global ? cmTarget::VisibilityImportedGlobally
+ : cmTarget::VisibilityImported,
+ this, cmTarget::PerConfig::Yes));
+
+ // Add to the set of available imported targets.
+ this->ImportedTargets[name] = target.get();
+ this->GetGlobalGenerator()->IndexTarget(target.get());
+
+ // Transfer ownership to this cmMakefile object.
+ this->ImportedTargetsOwned.push_back(std::move(target));
+ return this->ImportedTargetsOwned.back().get();
+}
+
+cmTarget* cmMakefile::FindTargetToUse(const std::string& name,
+ bool excludeAliases) const
+{
+ // Look for an imported target. These take priority because they
+ // are more local in scope and do not have to be globally unique.
+ auto targetName = name;
+ if (!excludeAliases) {
+ // Look for local alias targets.
+ auto alias = this->AliasTargets.find(name);
+ if (alias != this->AliasTargets.end()) {
+ targetName = alias->second;
+ }
+ }
+ auto imported = this->ImportedTargets.find(targetName);
+ if (imported != this->ImportedTargets.end()) {
+ return imported->second;
+ }
+
+ // Look for a target built in this directory.
+ if (cmTarget* t = this->FindLocalNonAliasTarget(name)) {
+ return t;
+ }
+
+ // Look for a target built in this project.
+ return this->GetGlobalGenerator()->FindTarget(name, excludeAliases);
+}
+
+bool cmMakefile::IsAlias(const std::string& name) const
+{
+ if (cm::contains(this->AliasTargets, name)) {
+ return true;
+ }
+ return this->GetGlobalGenerator()->IsAlias(name);
+}
+
+bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg,
+ bool isCustom) const
+{
+ if (this->IsAlias(name)) {
+ std::ostringstream e;
+ e << "cannot create target \"" << name
+ << "\" because an alias with the same name already exists.";
+ msg = e.str();
+ return false;
+ }
+ if (cmTarget* existing = this->FindTargetToUse(name)) {
+ // The name given conflicts with an existing target. Produce an
+ // error in a compatible way.
+ if (existing->IsImported()) {
+ // Imported targets were not supported in previous versions.
+ // This is new code, so we can make it an error.
+ std::ostringstream e;
+ e << "cannot create target \"" << name
+ << "\" because an imported target with the same name already exists.";
+ msg = e.str();
+ return false;
+ }
+ // target names must be globally unique
+ switch (this->GetPolicyStatus(cmPolicies::CMP0002)) {
+ case cmPolicies::WARN:
+ this->IssueMessage(MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0002));
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ return true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0002));
+ return true;
+ case cmPolicies::NEW:
+ break;
+ }
+
+ // The conflict is with a non-imported target.
+ // Allow this if the user has requested support.
+ cmake* cm = this->GetCMakeInstance();
+ if (isCustom && existing->GetType() == cmStateEnums::UTILITY &&
+ this != existing->GetMakefile() &&
+ cm->GetState()->GetGlobalPropertyAsBool(
+ "ALLOW_DUPLICATE_CUSTOM_TARGETS")) {
+ return true;
+ }
+
+ // Produce an error that tells the user how to work around the
+ // problem.
+ std::ostringstream e;
+ e << "cannot create target \"" << name
+ << "\" because another target with the same name already exists. "
+ << "The existing target is ";
+ switch (existing->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ e << "an executable ";
+ break;
+ case cmStateEnums::STATIC_LIBRARY:
+ e << "a static library ";
+ break;
+ case cmStateEnums::SHARED_LIBRARY:
+ e << "a shared library ";
+ break;
+ case cmStateEnums::MODULE_LIBRARY:
+ e << "a module library ";
+ break;
+ case cmStateEnums::UTILITY:
+ e << "a custom target ";
+ break;
+ case cmStateEnums::INTERFACE_LIBRARY:
+ e << "an interface library ";
+ break;
+ default:
+ break;
+ }
+ e << "created in source directory \""
+ << existing->GetMakefile()->GetCurrentSourceDirectory() << "\". "
+ << "See documentation for policy CMP0002 for more details.";
+ msg = e.str();
+ return false;
+ }
+ return true;
+}
+
+bool cmMakefile::EnforceUniqueDir(const std::string& srcPath,
+ const std::string& binPath) const
+{
+ // Make sure the binary directory is unique.
+ cmGlobalGenerator* gg = this->GetGlobalGenerator();
+ if (gg->BinaryDirectoryIsNew(binPath)) {
+ return true;
+ }
+ std::ostringstream e;
+ switch (this->GetPolicyStatus(cmPolicies::CMP0013)) {
+ case cmPolicies::WARN:
+ // Print the warning.
+ /* clang-format off */
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0013)
+ << "\n"
+ << "The binary directory\n"
+ << " " << binPath << "\n"
+ << "is already used to build a source directory. "
+ << "This command uses it to build source directory\n"
+ << " " << srcPath << "\n"
+ << "which can generate conflicting build files. "
+ << "CMake does not support this use case but it used "
+ << "to work accidentally and is being allowed for "
+ << "compatibility.";
+ /* clang-format on */
+ this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior does not warn.
+ return true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0013) << "\n";
+ CM_FALLTHROUGH;
+ case cmPolicies::NEW:
+ // NEW behavior prints the error.
+ /* clang-format off */
+ e << "The binary directory\n"
+ << " " << binPath << "\n"
+ << "is already used to build a source directory. "
+ << "It cannot be used to build source directory\n"
+ << " " << srcPath << "\n"
+ << "Specify a unique binary directory name.";
+ /* clang-format on */
+ this->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ break;
+ }
+
+ return false;
+}
+
+static std::string const matchVariables[] = {
+ "CMAKE_MATCH_0", "CMAKE_MATCH_1", "CMAKE_MATCH_2", "CMAKE_MATCH_3",
+ "CMAKE_MATCH_4", "CMAKE_MATCH_5", "CMAKE_MATCH_6", "CMAKE_MATCH_7",
+ "CMAKE_MATCH_8", "CMAKE_MATCH_9"
+};
+
+static std::string const nMatchesVariable = "CMAKE_MATCH_COUNT";
+
+void cmMakefile::ClearMatches()
+{
+ cmProp nMatchesStr = this->GetDefinition(nMatchesVariable);
+ if (!nMatchesStr) {
+ return;
+ }
+ int nMatches = atoi(nMatchesStr->c_str());
+ for (int i = 0; i <= nMatches; i++) {
+ std::string const& var = matchVariables[i];
+ std::string const& s = this->GetSafeDefinition(var);
+ if (!s.empty()) {
+ this->AddDefinition(var, "");
+ this->MarkVariableAsUsed(var);
+ }
+ }
+ this->AddDefinition(nMatchesVariable, "0");
+ this->MarkVariableAsUsed(nMatchesVariable);
+}
+
+void cmMakefile::StoreMatches(cmsys::RegularExpression& re)
+{
+ char highest = 0;
+ for (int i = 0; i < 10; i++) {
+ std::string const& m = re.match(i);
+ if (!m.empty()) {
+ std::string const& var = matchVariables[i];
+ this->AddDefinition(var, m);
+ this->MarkVariableAsUsed(var);
+ highest = static_cast<char>('0' + i);
+ }
+ }
+ char nMatches[] = { highest, '\0' };
+ this->AddDefinition(nMatchesVariable, nMatches);
+ this->MarkVariableAsUsed(nMatchesVariable);
+}
+
+cmStateSnapshot cmMakefile::GetStateSnapshot() const
+{
+ return this->StateSnapshot;
+}
+
+const char* cmMakefile::GetDefineFlagsCMP0059() const
+{
+ return this->DefineFlagsOrig.c_str();
+}
+
+cmPolicies::PolicyStatus cmMakefile::GetPolicyStatus(cmPolicies::PolicyID id,
+ bool parent_scope) const
+{
+ return this->StateSnapshot.GetPolicy(id, parent_scope);
+}
+
+bool cmMakefile::PolicyOptionalWarningEnabled(std::string const& var) const
+{
+ // Check for an explicit CMAKE_POLICY_WARNING_CMP<NNNN> setting.
+ if (cmProp val = this->GetDefinition(var)) {
+ return cmIsOn(val);
+ }
+ // Enable optional policy warnings with --debug-output, --trace,
+ // or --trace-expand.
+ cmake* cm = this->GetCMakeInstance();
+ return cm->GetDebugOutput() || cm->GetTrace();
+}
+
+bool cmMakefile::SetPolicy(const char* id, cmPolicies::PolicyStatus status)
+{
+ cmPolicies::PolicyID pid;
+ if (!cmPolicies::GetPolicyID(id, /* out */ pid)) {
+ std::ostringstream e;
+ e << "Policy \"" << id << "\" is not known to this version of CMake.";
+ this->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ return this->SetPolicy(pid, status);
+}
+
+bool cmMakefile::SetPolicy(cmPolicies::PolicyID id,
+ cmPolicies::PolicyStatus status)
+{
+ // A REQUIRED_ALWAYS policy may be set only to NEW.
+ if (status != cmPolicies::NEW &&
+ cmPolicies::GetPolicyStatus(id) == cmPolicies::REQUIRED_ALWAYS) {
+ std::string msg = cmPolicies::GetRequiredAlwaysPolicyError(id);
+ this->IssueMessage(MessageType::FATAL_ERROR, msg);
+ return false;
+ }
+
+ // Deprecate old policies, especially those that require a lot
+ // of code to maintain the old behavior.
+ if (status == cmPolicies::OLD && id <= cmPolicies::CMP0081 &&
+ !(this->GetCMakeInstance()->GetIsInTryCompile() &&
+ (
+ // Policies set by cmCoreTryCompile::TryCompileCode.
+ id == cmPolicies::CMP0065))) {
+ this->IssueMessage(MessageType::DEPRECATION_WARNING,
+ cmPolicies::GetPolicyDeprecatedWarning(id));
+ }
+
+ this->StateSnapshot.SetPolicy(id, status);
+ return true;
+}
+
+cmMakefile::PolicyPushPop::PolicyPushPop(cmMakefile* m)
+ : Makefile(m)
+{
+ this->Makefile->PushPolicy();
+}
+
+cmMakefile::PolicyPushPop::~PolicyPushPop()
+{
+ this->Makefile->PopPolicy();
+}
+
+void cmMakefile::PushPolicy(bool weak, cmPolicies::PolicyMap const& pm)
+{
+ this->StateSnapshot.PushPolicy(pm, weak);
+}
+
+void cmMakefile::PopPolicy()
+{
+ if (!this->StateSnapshot.PopPolicy()) {
+ this->IssueMessage(MessageType::FATAL_ERROR,
+ "cmake_policy POP without matching PUSH");
+ }
+}
+
+void cmMakefile::PopSnapshot(bool reportError)
+{
+ // cmStateSnapshot manages nested policy scopes within it.
+ // Since the scope corresponding to the snapshot is closing,
+ // reject any still-open nested policy scopes with an error.
+ while (this->StateSnapshot.CanPopPolicyScope()) {
+ if (reportError) {
+ this->IssueMessage(MessageType::FATAL_ERROR,
+ "cmake_policy PUSH without matching POP");
+ reportError = false;
+ }
+ this->PopPolicy();
+ }
+
+ this->StateSnapshot = this->GetState()->Pop(this->StateSnapshot);
+ assert(this->StateSnapshot.IsValid());
+}
+
+bool cmMakefile::SetPolicyVersion(std::string const& version_min,
+ std::string const& version_max)
+{
+ return cmPolicies::ApplyPolicyVersion(this, version_min, version_max,
+ cmPolicies::WarnCompat::On);
+}
+
+bool cmMakefile::HasCMP0054AlreadyBeenReported(
+ cmListFileContext const& context) const
+{
+ return !this->CMP0054ReportedIds.insert(context).second;
+}
+
+void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm) const
+{
+ /* Record the setting of every policy. */
+ using PolicyID = cmPolicies::PolicyID;
+ for (PolicyID pid = cmPolicies::CMP0000; pid != cmPolicies::CMPCOUNT;
+ pid = PolicyID(pid + 1)) {
+ pm.Set(pid, this->GetPolicyStatus(pid));
+ }
+}
+
+bool cmMakefile::IgnoreErrorsCMP0061() const
+{
+ bool ignoreErrors = true;
+ switch (this->GetPolicyStatus(cmPolicies::CMP0061)) {
+ case cmPolicies::WARN:
+ // No warning for this policy!
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ ignoreErrors = false;
+ break;
+ }
+ return ignoreErrors;
+}
+
+cmMakefile::FunctionPushPop::FunctionPushPop(cmMakefile* mf,
+ const std::string& fileName,
+ cmPolicies::PolicyMap const& pm)
+ : Makefile(mf)
+ , ReportError(true)
+{
+ this->Makefile->PushFunctionScope(fileName, pm);
+}
+
+cmMakefile::FunctionPushPop::~FunctionPushPop()
+{
+ this->Makefile->PopFunctionScope(this->ReportError);
+}
+
+cmMakefile::MacroPushPop::MacroPushPop(cmMakefile* mf,
+ const std::string& fileName,
+ const cmPolicies::PolicyMap& pm)
+ : Makefile(mf)
+ , ReportError(true)
+{
+ this->Makefile->PushMacroScope(fileName, pm);
+}
+
+cmMakefile::MacroPushPop::~MacroPushPop()
+{
+ this->Makefile->PopMacroScope(this->ReportError);
+}
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
new file mode 100644
index 0000000..71d765c
--- /dev/null
+++ b/Source/cmMakefile.h
@@ -0,0 +1,1097 @@
+/* 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 <cstddef>
+#include <deque>
+#include <functional>
+#include <map>
+#include <memory>
+#include <set>
+#include <stack>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <cm/optional>
+#include <cm/string_view>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cm_sys_stat.h"
+
+#include "cmAlgorithms.h"
+#include "cmCustomCommandTypes.h"
+#include "cmListFileCache.h"
+#include "cmMessageType.h"
+#include "cmNewLineStyle.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmSourceFileLocationKind.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+
+// IWYU does not see that 'std::unordered_map<std::string, cmTarget>'
+// will not compile without the complete type.
+#include "cmTarget.h" // IWYU pragma: keep
+
+#if !defined(CMAKE_BOOTSTRAP)
+# include "cmSourceGroup.h"
+#endif
+
+class cmCompiledGeneratorExpression;
+class cmCustomCommandLines;
+class cmExecutionStatus;
+class cmExpandedCommandArgument;
+class cmExportBuildFileGenerator;
+class cmFunctionBlocker;
+class cmGeneratorExpressionEvaluationFile;
+class cmGlobalGenerator;
+class cmImplicitDependsList;
+class cmInstallGenerator;
+class cmLocalGenerator;
+class cmMessenger;
+class cmSourceFile;
+class cmState;
+class cmTest;
+class cmTestGenerator;
+class cmVariableWatch;
+class cmake;
+
+/** A type-safe wrapper for a string representing a directory id. */
+class cmDirectoryId
+{
+public:
+ cmDirectoryId(std::string s);
+ std::string String;
+};
+
+/** \class cmMakefile
+ * \brief Process the input CMakeLists.txt file.
+ *
+ * Process and store into memory the input CMakeLists.txt file.
+ * Each CMakeLists.txt file is parsed and the commands found there
+ * are added into the build process.
+ */
+class cmMakefile
+{
+public:
+ /* Mark a variable as used */
+ void MarkVariableAsUsed(const std::string& var);
+ /* return true if a variable has been initialized */
+ bool VariableInitialized(const std::string&) const;
+
+ /**
+ * Construct an empty makefile.
+ */
+ cmMakefile(cmGlobalGenerator* globalGenerator,
+ const cmStateSnapshot& snapshot);
+
+ /**
+ * Destructor.
+ */
+ ~cmMakefile();
+
+ cmMakefile(cmMakefile const&) = delete;
+ cmMakefile& operator=(cmMakefile const&) = delete;
+
+ cmDirectoryId GetDirectoryId() const;
+
+ bool ReadListFile(const std::string& filename);
+
+ bool ReadListFileAsString(const std::string& content,
+ const std::string& virtualFileName);
+
+ bool ReadDependentFile(const std::string& filename,
+ bool noPolicyScope = true);
+
+ /**
+ * Add a function blocker to this makefile
+ */
+ void AddFunctionBlocker(std::unique_ptr<cmFunctionBlocker> fb);
+
+ /// @return whether we are processing the top CMakeLists.txt file.
+ bool IsRootMakefile() const;
+
+ /**
+ * Remove the function blocker whose scope ends with the given command.
+ * This returns ownership of the function blocker object.
+ */
+ std::unique_ptr<cmFunctionBlocker> RemoveFunctionBlocker();
+
+ /**
+ * Try running cmake and building a file. This is used for dynamically
+ * loaded commands, not as part of the usual build process.
+ */
+ int TryCompile(const std::string& srcdir, const std::string& bindir,
+ const std::string& projectName, const std::string& targetName,
+ bool fast, int jobs,
+ const std::vector<std::string>* cmakeArgs,
+ std::string& output);
+
+ bool GetIsSourceFileTryCompile() const;
+
+ /**
+ * Help enforce global target name uniqueness.
+ */
+ bool EnforceUniqueName(std::string const& name, std::string& msg,
+ bool isCustom = false) const;
+
+ using GeneratorAction =
+ std::function<void(cmLocalGenerator&, const cmListFileBacktrace&)>;
+
+ /**
+ * Register an action that is executed during Generate
+ */
+ void AddGeneratorAction(GeneratorAction action);
+
+ /**
+ * Perform generate actions, Library dependency analysis etc before output of
+ * the makefile.
+ */
+ void Generate(cmLocalGenerator& lg);
+
+ /**
+ * Get the target for PRE_BUILD, PRE_LINK, or POST_BUILD commands.
+ */
+ cmTarget* GetCustomCommandTarget(const std::string& target,
+ cmObjectLibraryCommands objLibCommands,
+ const cmListFileBacktrace& lfbt) const;
+
+ /**
+ * Dispatch adding a custom PRE_BUILD, PRE_LINK, or POST_BUILD command to a
+ * target.
+ */
+ cmTarget* AddCustomCommandToTarget(
+ const std::string& target, const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, cmCustomCommandType type,
+ const char* comment, const char* workingDir,
+ cmPolicies::PolicyStatus cmp0116, bool escapeOldStyle = true,
+ bool uses_terminal = false, const std::string& depfile = "",
+ const std::string& job_pool = "", bool command_expand_lists = false,
+ bool stdPipesUTF8 = false);
+
+ /**
+ * Called for each file with custom command.
+ */
+ using CommandSourceCallback = std::function<void(cmSourceFile*)>;
+
+ /**
+ * Dispatch adding a custom command to a source file.
+ */
+ void AddCustomCommandToOutput(
+ const std::string& output, const std::vector<std::string>& depends,
+ const std::string& main_dependency,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, cmPolicies::PolicyStatus cmp0116,
+ const CommandSourceCallback& callback = nullptr, bool replace = false,
+ bool escapeOldStyle = true, bool uses_terminal = false,
+ bool command_expand_lists = false, const std::string& depfile = "",
+ const std::string& job_pool = "", bool stdPipesUTF8 = false);
+ void AddCustomCommandToOutput(
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const std::string& main_dependency,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines, const char* comment,
+ const char* workingDir, cmPolicies::PolicyStatus cmp0116,
+ const CommandSourceCallback& callback = nullptr, bool replace = false,
+ bool escapeOldStyle = true, bool uses_terminal = false,
+ bool command_expand_lists = false, const std::string& depfile = "",
+ const std::string& job_pool = "", bool stdPipesUTF8 = false);
+ void AddCustomCommandOldStyle(const std::string& target,
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& depends,
+ const std::string& source,
+ const cmCustomCommandLines& commandLines,
+ const char* comment,
+ cmPolicies::PolicyStatus cmp0116);
+ void AppendCustomCommandToOutput(
+ const std::string& output, const std::vector<std::string>& depends,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines);
+
+ /**
+ * Add a define flag to the build.
+ */
+ void AddDefineFlag(std::string const& definition);
+ void RemoveDefineFlag(std::string const& definition);
+ void AddCompileDefinition(std::string const& definition);
+ void AddCompileOption(std::string const& option);
+ void AddLinkOption(std::string const& option);
+ void AddLinkDirectory(std::string const& directory, bool before = false);
+
+ /** Create a new imported target with the name and type given. */
+ cmTarget* AddImportedTarget(const std::string& name,
+ cmStateEnums::TargetType type, bool global);
+
+ cmTarget* AddNewTarget(cmStateEnums::TargetType type,
+ const std::string& name);
+
+ /** Create a target instance for the utility. */
+ cmTarget* AddNewUtilityTarget(const std::string& utilityName,
+ bool excludeFromAll);
+
+ /**
+ * Add an executable to the build.
+ */
+ cmTarget* AddExecutable(const std::string& exename,
+ const std::vector<std::string>& srcs,
+ bool excludeFromAll = false);
+
+ /**
+ * Dispatch adding a utility to the build. A utility target is a command
+ * that is run every time the target is built.
+ */
+ cmTarget* AddUtilityCommand(
+ const std::string& utilityName, bool excludeFromAll,
+ const char* workingDir, const std::vector<std::string>& byproducts,
+ const std::vector<std::string>& depends,
+ const cmCustomCommandLines& commandLines, cmPolicies::PolicyStatus cmp0116,
+ bool escapeOldStyle = true, const char* comment = nullptr,
+ bool uses_terminal = false, bool command_expand_lists = false,
+ const std::string& job_pool = "", bool stdPipesUTF8 = false);
+
+ /**
+ * Add a subdirectory to the build.
+ */
+ void AddSubDirectory(const std::string& fullSrcDir,
+ const std::string& fullBinDir, bool excludeFromAll,
+ bool immediate);
+
+ void Configure();
+
+ /**
+ * Configure a subdirectory
+ */
+ void ConfigureSubDirectory(cmMakefile* mf);
+
+ /**
+ * Add an include directory to the build.
+ */
+ void AddIncludeDirectories(const std::vector<std::string>& incs,
+ bool before = false);
+
+ /**
+ * Add a variable definition to the build. This variable
+ * can be used in CMake to refer to lists, directories, etc.
+ */
+ void AddDefinition(const std::string& name, cm::string_view value);
+ /**
+ * Add bool variable definition to the build.
+ */
+ void AddDefinitionBool(const std::string& name, bool);
+ //! Add a definition to this makefile and the global cmake cache.
+ void AddCacheDefinition(const std::string& name, const char* value,
+ const char* doc, cmStateEnums::CacheEntryType type,
+ bool force = false);
+ void AddCacheDefinition(const std::string& name, const std::string& value,
+ const char* doc, cmStateEnums::CacheEntryType type,
+ bool force = false)
+ {
+ this->AddCacheDefinition(name, value.c_str(), doc, type, force);
+ }
+
+ /**
+ * Remove a variable definition from the build. This is not valid
+ * for cache entries, and will only affect the current makefile.
+ */
+ void RemoveDefinition(const std::string& name);
+ //! Remove a definition from the cache.
+ void RemoveCacheDefinition(const std::string& name) const;
+
+ /**
+ * Specify the name of the project for this build.
+ */
+ void SetProjectName(std::string const& name);
+
+ /* Get the default configuration */
+ std::string GetDefaultConfiguration() const;
+
+ enum GeneratorConfigQuery
+ {
+ IncludeEmptyConfig, // Include "" aka noconfig
+ ExcludeEmptyConfig, // Exclude "" aka noconfig
+ OnlyMultiConfig,
+ };
+
+ /** Get the configurations for dependency checking. */
+ std::vector<std::string> GetGeneratorConfigs(
+ GeneratorConfigQuery mode) const;
+
+ /**
+ * Set the name of the library.
+ */
+ cmTarget* AddLibrary(const std::string& libname,
+ cmStateEnums::TargetType type,
+ const std::vector<std::string>& srcs,
+ bool excludeFromAll = false);
+ void AddAlias(const std::string& libname, const std::string& tgt,
+ bool globallyVisible = true);
+
+ //@{
+ /**
+ * Set, Push, Pop policy values for CMake.
+ */
+ bool SetPolicy(cmPolicies::PolicyID id, cmPolicies::PolicyStatus status);
+ bool SetPolicy(const char* id, cmPolicies::PolicyStatus status);
+ cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id,
+ bool parent_scope = false) const;
+ bool SetPolicyVersion(std::string const& version_min,
+ std::string const& version_max);
+ void RecordPolicies(cmPolicies::PolicyMap& pm) const;
+ //@}
+
+ /** Helper class to push and pop policies automatically. */
+ class PolicyPushPop
+ {
+ public:
+ PolicyPushPop(cmMakefile* m);
+ ~PolicyPushPop();
+
+ PolicyPushPop(const PolicyPushPop&) = delete;
+ PolicyPushPop& operator=(const PolicyPushPop&) = delete;
+
+ private:
+ cmMakefile* Makefile;
+ };
+ friend class PolicyPushPop;
+
+ /**
+ * Determine if the given context, name pair has already been reported
+ * in context of CMP0054.
+ */
+ bool HasCMP0054AlreadyBeenReported(const cmListFileContext& context) const;
+
+ bool IgnoreErrorsCMP0061() const;
+
+ std::string const& GetHomeDirectory() const;
+ std::string const& GetHomeOutputDirectory() const;
+
+ /**
+ * Set CMAKE_SCRIPT_MODE_FILE variable when running a -P script.
+ */
+ void SetScriptModeFile(std::string const& scriptfile);
+
+ /**
+ * Set CMAKE_ARGC, CMAKE_ARGV0 ... variables.
+ */
+ void SetArgcArgv(const std::vector<std::string>& args);
+
+ std::string const& GetCurrentSourceDirectory() const;
+ std::string const& GetCurrentBinaryDirectory() const;
+
+ //@}
+
+ /**
+ * Set a regular expression that include files must match
+ * in order to be considered as part of the depend information.
+ */
+ void SetIncludeRegularExpression(const char* regex)
+ {
+ this->SetProperty("INCLUDE_REGULAR_EXPRESSION", regex);
+ }
+ const char* GetIncludeRegularExpression() const
+ {
+ return cmToCStr(this->GetProperty("INCLUDE_REGULAR_EXPRESSION"));
+ }
+
+ /**
+ * Set a regular expression that include files that are not found
+ * must match in order to be considered a problem.
+ */
+ void SetComplainRegularExpression(const std::string& regex)
+ {
+ this->ComplainFileRegularExpression = regex;
+ }
+ const std::string& GetComplainRegularExpression() const
+ {
+ return this->ComplainFileRegularExpression;
+ }
+
+ // -- List of targets
+ using cmTargetMap = std::unordered_map<std::string, cmTarget>;
+ /** Get the target map */
+ cmTargetMap& GetTargets() { return this->Targets; }
+ /** Get the target map - const version */
+ cmTargetMap const& GetTargets() const { return this->Targets; }
+
+ const std::vector<std::unique_ptr<cmTarget>>& GetOwnedImportedTargets() const
+ {
+ return this->ImportedTargetsOwned;
+ }
+ std::vector<cmTarget*> GetImportedTargets() const;
+
+ cmTarget* FindLocalNonAliasTarget(const std::string& name) const;
+
+ /** Find a target to use in place of the given name. The target
+ returned may be imported or built within the project. */
+ cmTarget* FindTargetToUse(const std::string& name,
+ bool excludeAliases = false) const;
+ bool IsAlias(const std::string& name) const;
+
+ std::map<std::string, std::string> GetAliasTargets() const
+ {
+ return this->AliasTargets;
+ }
+
+ /**
+ * Mark include directories as system directories.
+ */
+ void AddSystemIncludeDirectories(const std::set<std::string>& incs);
+
+ /** Get a cmSourceFile pointer for a given source name, if the name is
+ * not found, then a null pointer is returned.
+ */
+ cmSourceFile* GetSource(
+ const std::string& sourceName,
+ cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous) const;
+
+ /** Create the source file and return it. generated
+ * indicates if it is a generated file, this is used in determining
+ * how to create the source file instance e.g. name
+ */
+ cmSourceFile* CreateSource(
+ const std::string& sourceName, bool generated = false,
+ cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous);
+
+ /** Get a cmSourceFile pointer for a given source name, if the name is
+ * not found, then create the source file and return it. generated
+ * indicates if it is a generated file, this is used in determining
+ * how to create the source file instance e.g. name
+ */
+ cmSourceFile* GetOrCreateSource(
+ const std::string& sourceName, bool generated = false,
+ cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous);
+
+ /** Get a cmSourceFile pointer for a given source name and always mark the
+ * file as generated, if the name is not found, then create the source file
+ * and return it.
+ */
+ cmSourceFile* GetOrCreateGeneratedSource(const std::string& sourceName);
+
+ void AddTargetObject(std::string const& tgtName, std::string const& objFile);
+
+ /**
+ * Given a variable name, return its value (as a string).
+ * If the variable is not found in this makefile instance, the
+ * cache is then queried.
+ */
+ cmProp GetDefinition(const std::string&) const;
+ const std::string& GetSafeDefinition(const std::string&) const;
+ const std::string& GetRequiredDefinition(const std::string& name) const;
+ bool IsDefinitionSet(const std::string&) const;
+ bool GetDefExpandList(const std::string& name, std::vector<std::string>& out,
+ bool emptyArgs = false) const;
+ /**
+ * Get the list of all variables in the current space. If argument
+ * cacheonly is specified and is greater than 0, then only cache
+ * variables will be listed.
+ */
+ std::vector<std::string> GetDefinitions() const;
+
+ /**
+ * Test a boolean variable to see if it is true or false.
+ * If the variable is not found in this makefile instance, the
+ * cache is then queried.
+ * Returns false if no entry defined.
+ */
+ bool IsOn(const std::string& name) const;
+ bool IsSet(const std::string& name) const;
+
+ /** Return whether the target platform is 32-bit. */
+ bool PlatformIs32Bit() const;
+
+ /** Return whether the target platform is 64-bit. */
+ bool PlatformIs64Bit() const;
+ /** Return whether the target platform is x32. */
+ bool PlatformIsx32() const;
+
+ /** Apple SDK Type */
+ enum class AppleSDK
+ {
+ MacOS,
+ IPhoneOS,
+ IPhoneSimulator,
+ AppleTVOS,
+ AppleTVSimulator,
+ WatchOS,
+ WatchSimulator,
+ };
+
+ /** What SDK type points CMAKE_OSX_SYSROOT to? */
+ AppleSDK GetAppleSDKType() const;
+
+ /** Return whether the target platform is Apple iOS. */
+ bool PlatformIsAppleEmbedded() const;
+
+ /** Retrieve soname flag for the specified language if supported */
+ const char* GetSONameFlag(const std::string& language) const;
+
+ /**
+ * Get a list of preprocessor define flags.
+ */
+ std::string GetDefineFlags() const { return this->DefineFlags; }
+
+ /**
+ * Make sure CMake can write this file
+ */
+ bool CanIWriteThisFile(std::string const& fileName) const;
+
+#if !defined(CMAKE_BOOTSTRAP)
+ /**
+ * Get the vector source groups.
+ */
+ const std::vector<cmSourceGroup>& GetSourceGroups() const
+ {
+ return this->SourceGroups;
+ }
+
+ /**
+ * Get the source group
+ */
+ cmSourceGroup* GetSourceGroup(const std::vector<std::string>& name) const;
+
+ /**
+ * Add a root source group for consideration when adding a new source.
+ */
+ void AddSourceGroup(const std::string& name, const char* regex = nullptr);
+
+ /**
+ * Add a source group for consideration when adding a new source.
+ * name is tokenized.
+ */
+ void AddSourceGroup(const std::vector<std::string>& name,
+ const char* regex = nullptr);
+
+ /**
+ * Get and existing or create a new source group.
+ */
+ cmSourceGroup* GetOrCreateSourceGroup(
+ const std::vector<std::string>& folders);
+
+ /**
+ * Get and existing or create a new source group.
+ * The name will be tokenized.
+ */
+ cmSourceGroup* GetOrCreateSourceGroup(const std::string& name);
+
+ /**
+ * find what source group this source is in
+ */
+ cmSourceGroup* FindSourceGroup(const std::string& source,
+ std::vector<cmSourceGroup>& groups) const;
+#endif
+
+ /**
+ * Get the vector of list files on which this makefile depends
+ */
+ const std::vector<std::string>& GetListFiles() const
+ {
+ return this->ListFiles;
+ }
+ //! When the file changes cmake will be re-run from the build system.
+ void AddCMakeDependFile(const std::string& file)
+ {
+ this->ListFiles.push_back(file);
+ }
+ void AddCMakeDependFilesFromUser();
+
+ std::string FormatListFileStack() const;
+
+ /**
+ * Get the current context backtrace.
+ */
+ cmListFileBacktrace GetBacktrace() const;
+
+ /**
+ * Get the vector of files created by this makefile
+ */
+ const std::vector<std::string>& GetOutputFiles() const
+ {
+ return this->OutputFiles;
+ }
+ void AddCMakeOutputFile(const std::string& file)
+ {
+ this->OutputFiles.push_back(file);
+ }
+
+ /**
+ * Expand all defined variables in the string.
+ * Defined variables come from the this->Definitions map.
+ * They are expanded with ${var} where var is the
+ * entry in the this->Definitions map. Also \@var\@ is
+ * expanded to match autoconf style expansions.
+ */
+ const std::string& ExpandVariablesInString(std::string& source) const;
+ const std::string& ExpandVariablesInString(
+ std::string& source, bool escapeQuotes, bool noEscapes,
+ bool atOnly = false, const char* filename = nullptr, long line = -1,
+ bool removeEmpty = false, bool replaceAt = false) const;
+
+ /**
+ * Remove any remaining variables in the string. Anything with ${var} or
+ * \@var\@ will be removed.
+ */
+ void RemoveVariablesInString(std::string& source, bool atOnly = false) const;
+
+ /**
+ * Expand variables in the makefiles ivars such as link directories etc
+ */
+ void ExpandVariablesCMP0019();
+
+ /**
+ * Replace variables and #cmakedefine lines in the given string.
+ * See cmConfigureFileCommand for details.
+ */
+ void ConfigureString(const std::string& input, std::string& output,
+ bool atOnly, bool escapeQuotes) const;
+
+ /**
+ * Copy file but change lines according to ConfigureString
+ */
+ int ConfigureFile(const std::string& infile, const std::string& outfile,
+ bool copyonly, bool atOnly, bool escapeQuotes,
+ mode_t permissions = 0, cmNewLineStyle = cmNewLineStyle());
+
+ /**
+ * Print a command's invocation
+ */
+ void PrintCommandTrace(cmListFileFunction const& lff,
+ cm::optional<std::string> const& deferId = {}) const;
+
+ /**
+ * Set a callback that is invoked whenever ExecuteCommand is called.
+ */
+ void OnExecuteCommand(std::function<void()> callback);
+
+ /**
+ * Execute a single CMake command. Returns true if the command
+ * succeeded or false if it failed.
+ */
+ bool ExecuteCommand(const cmListFileFunction& lff, cmExecutionStatus& status,
+ cm::optional<std::string> deferId = {});
+
+ //! Enable support for named language, if nil then all languages are
+ /// enabled.
+ void EnableLanguage(std::vector<std::string> const& languages,
+ bool optional);
+
+ cmState* GetState() const;
+
+/**
+ * Get the variable watch. This is used to determine when certain variables
+ * are accessed.
+ */
+#ifndef CMAKE_BOOTSTRAP
+ cmVariableWatch* GetVariableWatch() const;
+#endif
+
+ //! Display progress or status message.
+ void DisplayStatus(const std::string&, float) const;
+
+ /**
+ * Expand the given list file arguments into the full set after
+ * variable replacement and list expansion.
+ */
+ bool ExpandArguments(std::vector<cmListFileArgument> const& inArgs,
+ std::vector<std::string>& outArgs) const;
+ bool ExpandArguments(std::vector<cmListFileArgument> const& inArgs,
+ std::vector<cmExpandedCommandArgument>& outArgs) const;
+
+ /**
+ * Get the instance
+ */
+ cmake* GetCMakeInstance() const;
+ cmMessenger* GetMessenger() const;
+ cmGlobalGenerator* GetGlobalGenerator() const;
+
+ /**
+ * Get all the source files this makefile knows about
+ */
+ const std::vector<std::unique_ptr<cmSourceFile>>& GetSourceFiles() const
+ {
+ return this->SourceFiles;
+ }
+
+ std::vector<cmTarget*> const& GetOrderedTargets() const
+ {
+ return this->OrderedTargets;
+ }
+
+ //! Add a new cmTest to the list of tests for this makefile.
+ cmTest* CreateTest(const std::string& testName);
+
+ /** Get a cmTest pointer for a given test name, if the name is
+ * not found, then a null pointer is returned.
+ */
+ cmTest* GetTest(const std::string& testName) const;
+
+ /**
+ * Get all tests that run under the given configuration.
+ */
+ void GetTests(const std::string& config, std::vector<cmTest*>& tests) const;
+
+ /**
+ * Return a location of a file in cmake or custom modules directory
+ */
+ std::string GetModulesFile(const std::string& name) const
+ {
+ bool system;
+ std::string debugBuffer;
+ return this->GetModulesFile(name, system, false, debugBuffer);
+ }
+
+ /**
+ * Return a location of a file in cmake or custom modules directory
+ */
+ std::string GetModulesFile(const std::string& name, bool& system) const
+ {
+ std::string debugBuffer;
+ return this->GetModulesFile(name, system, false, debugBuffer);
+ }
+
+ std::string GetModulesFile(const std::string& name, bool& system, bool debug,
+ std::string& debugBuffer) const;
+
+ //! Set/Get a property of this directory
+ void SetProperty(const std::string& prop, const char* value);
+ void AppendProperty(const std::string& prop, const std::string& value,
+ bool asString = false);
+ cmProp GetProperty(const std::string& prop) const;
+ cmProp GetProperty(const std::string& prop, bool chain) const;
+ bool GetPropertyAsBool(const std::string& prop) const;
+ std::vector<std::string> GetPropertyKeys() const;
+
+ //! Initialize a makefile from its parent
+ void InitializeFromParent(cmMakefile* parent);
+
+ void AddInstallGenerator(std::unique_ptr<cmInstallGenerator> g);
+
+ std::vector<std::unique_ptr<cmInstallGenerator>>& GetInstallGenerators()
+ {
+ return this->InstallGenerators;
+ }
+ const std::vector<std::unique_ptr<cmInstallGenerator>>&
+ GetInstallGenerators() const
+ {
+ return this->InstallGenerators;
+ }
+
+ void AddTestGenerator(std::unique_ptr<cmTestGenerator> g);
+
+ const std::vector<std::unique_ptr<cmTestGenerator>>& GetTestGenerators()
+ const
+ {
+ return this->TestGenerators;
+ }
+
+ class FunctionPushPop
+ {
+ public:
+ FunctionPushPop(cmMakefile* mf, std::string const& fileName,
+ cmPolicies::PolicyMap const& pm);
+ ~FunctionPushPop();
+
+ FunctionPushPop(const FunctionPushPop&) = delete;
+ FunctionPushPop& operator=(const FunctionPushPop&) = delete;
+
+ void Quiet() { this->ReportError = false; }
+
+ private:
+ cmMakefile* Makefile;
+ bool ReportError;
+ };
+
+ class MacroPushPop
+ {
+ public:
+ MacroPushPop(cmMakefile* mf, std::string const& fileName,
+ cmPolicies::PolicyMap const& pm);
+ ~MacroPushPop();
+
+ MacroPushPop(const MacroPushPop&) = delete;
+ MacroPushPop& operator=(const MacroPushPop&) = delete;
+
+ void Quiet() { this->ReportError = false; }
+
+ private:
+ cmMakefile* Makefile;
+ bool ReportError;
+ };
+
+ void PushFunctionScope(std::string const& fileName,
+ cmPolicies::PolicyMap const& pm);
+ void PopFunctionScope(bool reportError);
+ void PushMacroScope(std::string const& fileName,
+ cmPolicies::PolicyMap const& pm);
+ void PopMacroScope(bool reportError);
+ void PushScope();
+ void PopScope();
+ void RaiseScope(const std::string& var, const char* value);
+
+ // push and pop loop scopes
+ void PushLoopBlockBarrier();
+ void PopLoopBlockBarrier();
+
+ /** Helper class to push and pop scopes automatically. */
+ class ScopePushPop
+ {
+ public:
+ ScopePushPop(cmMakefile* m)
+ : Makefile(m)
+ {
+ this->Makefile->PushScope();
+ }
+
+ ~ScopePushPop() { this->Makefile->PopScope(); }
+
+ ScopePushPop(ScopePushPop const&) = delete;
+ ScopePushPop& operator=(ScopePushPop const&) = delete;
+
+ private:
+ cmMakefile* Makefile;
+ };
+
+ void IssueMessage(MessageType t, std::string const& text) const;
+
+ /** Set whether or not to report a CMP0000 violation. */
+ void SetCheckCMP0000(bool b) { this->CheckCMP0000 = b; }
+
+ bool CheckCMP0037(std::string const& targetName,
+ cmStateEnums::TargetType targetType) const;
+
+ cmStringRange GetIncludeDirectoriesEntries() const;
+ cmBacktraceRange GetIncludeDirectoriesBacktraces() const;
+ cmStringRange GetCompileOptionsEntries() const;
+ cmBacktraceRange GetCompileOptionsBacktraces() const;
+ cmStringRange GetCompileDefinitionsEntries() const;
+ cmBacktraceRange GetCompileDefinitionsBacktraces() const;
+ cmStringRange GetLinkOptionsEntries() const;
+ cmBacktraceRange GetLinkOptionsBacktraces() const;
+ cmStringRange GetLinkDirectoriesEntries() const;
+ cmBacktraceRange GetLinkDirectoriesBacktraces() const;
+
+ std::set<std::string> const& GetSystemIncludeDirectories() const
+ {
+ return this->SystemIncludeDirectories;
+ }
+
+ bool PolicyOptionalWarningEnabled(std::string const& var) const;
+
+ void PushLoopBlock();
+ void PopLoopBlock();
+ bool IsLoopBlock() const;
+
+ void ClearMatches();
+ void StoreMatches(cmsys::RegularExpression& re);
+
+ cmStateSnapshot GetStateSnapshot() const;
+
+ const char* GetDefineFlagsCMP0059() const;
+
+ void EnforceDirectoryLevelRules() const;
+
+ void AddEvaluationFile(
+ const std::string& inputFile, const std::string& targetName,
+ std::unique_ptr<cmCompiledGeneratorExpression> outputName,
+ std::unique_ptr<cmCompiledGeneratorExpression> condition,
+ const std::string& newLineCharacter, mode_t permissions,
+ bool inputIsContent);
+ const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>&
+ GetEvaluationFiles() const;
+
+ std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const&
+ GetExportBuildFileGenerators() const;
+ void RemoveExportBuildFileGeneratorCMP0024(cmExportBuildFileGenerator* gen);
+ void AddExportBuildFileGenerator(
+ std::unique_ptr<cmExportBuildFileGenerator> gen);
+
+ // Maintain a stack of package roots to allow nested PACKAGE_ROOT_PATH
+ // searches
+ std::deque<std::vector<std::string>> FindPackageRootPathStack;
+
+ void MaybeWarnCMP0074(std::string const& pkg);
+ void MaybeWarnUninitialized(std::string const& variable,
+ const char* sourceFilename) const;
+ bool IsProjectFile(const char* filename) const;
+
+ int GetRecursionDepth() const;
+ void SetRecursionDepth(int recursionDepth);
+
+ std::string NewDeferId() const;
+ 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);
+
+ mutable std::set<cmListFileContext> CMP0054ReportedIds;
+
+ // libraries, classes, and executables
+ mutable cmTargetMap Targets;
+ std::map<std::string, std::string> AliasTargets;
+
+ std::vector<cmTarget*> OrderedTargets;
+
+ std::vector<std::unique_ptr<cmSourceFile>> SourceFiles;
+
+ // Because cmSourceFile names are compared in a fuzzy way (see
+ // cmSourceFileLocation::Match()) we can't have a straight mapping from
+ // filename to cmSourceFile. To make lookups more efficient we store the
+ // Name portion of the cmSourceFileLocation and then compare on the list of
+ // cmSourceFiles that might match that name. Note that on platforms which
+ // have a case-insensitive filesystem we store the key in all lowercase.
+ using SourceFileMap =
+ std::unordered_map<std::string, std::vector<cmSourceFile*>>;
+ SourceFileMap SourceFileSearchIndex;
+
+ // For "Known" paths we can store a direct filename to cmSourceFile map
+ std::unordered_map<std::string, cmSourceFile*> KnownFileSearchIndex;
+
+ // Tests
+ std::map<std::string, std::unique_ptr<cmTest>> Tests;
+
+ // The set of include directories that are marked as system include
+ // directories.
+ std::set<std::string> SystemIncludeDirectories;
+
+ std::vector<std::string> ListFiles;
+ std::vector<std::string> OutputFiles;
+
+ std::vector<std::unique_ptr<cmInstallGenerator>> InstallGenerators;
+ std::vector<std::unique_ptr<cmTestGenerator>> TestGenerators;
+
+ std::string ComplainFileRegularExpression;
+ std::string DefineFlags;
+
+ // Track the value of the computed DEFINITIONS property.
+ std::string DefineFlagsOrig;
+
+#if !defined(CMAKE_BOOTSTRAP)
+ std::vector<cmSourceGroup> SourceGroups;
+ size_t ObjectLibrariesSourceGroupIndex;
+#endif
+
+ cmGlobalGenerator* GlobalGenerator;
+ bool IsFunctionBlocked(const cmListFileFunction& lff,
+ cmExecutionStatus& status);
+
+private:
+ cmStateSnapshot StateSnapshot;
+ 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 RunListFile(cmListFile const& listFile,
+ const std::string& filenametoread,
+ DeferCommands* defer = nullptr);
+
+ bool ParseDefineFlag(std::string const& definition, bool remove);
+
+ bool EnforceUniqueDir(const std::string& srcPath,
+ const std::string& binPath) const;
+
+ std::function<void()> ExecuteCommandCallback;
+ using FunctionBlockerPtr = std::unique_ptr<cmFunctionBlocker>;
+ using FunctionBlockersType =
+ std::stack<FunctionBlockerPtr, std::vector<FunctionBlockerPtr>>;
+ FunctionBlockersType FunctionBlockers;
+ std::vector<FunctionBlockersType::size_type> FunctionBlockerBarriers;
+ void PushFunctionBlockerBarrier();
+ void PopFunctionBlockerBarrier(bool reportError = true);
+
+ std::stack<int> LoopBlockCounter;
+
+ mutable cmsys::RegularExpression cmDefineRegex;
+ mutable cmsys::RegularExpression cmDefine01Regex;
+ mutable cmsys::RegularExpression cmAtVarRegex;
+ mutable cmsys::RegularExpression cmNamedCurly;
+
+ std::vector<cmMakefile*> UnConfiguredDirectories;
+ std::vector<std::unique_ptr<cmExportBuildFileGenerator>>
+ ExportBuildFileGenerators;
+
+ std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>
+ EvaluationFiles;
+
+ std::vector<cmExecutionStatus*> ExecutionStatusStack;
+ friend class cmMakefileCall;
+ friend class cmParseFileScope;
+
+ std::vector<std::unique_ptr<cmTarget>> ImportedTargetsOwned;
+ using TargetMap = std::unordered_map<std::string, cmTarget*>;
+ TargetMap ImportedTargets;
+
+ // Internal policy stack management.
+ void PushPolicy(bool weak = false,
+ cmPolicies::PolicyMap const& pm = cmPolicies::PolicyMap());
+ void PopPolicy();
+ void PopSnapshot(bool reportError = true);
+ friend bool cmCMakePolicyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
+ class IncludeScope;
+ friend class IncludeScope;
+
+ class ListFileScope;
+ friend class ListFileScope;
+
+ class DeferScope;
+ friend class DeferScope;
+
+ class DeferCallScope;
+ friend class DeferCallScope;
+
+ class BuildsystemFileScope;
+ friend class BuildsystemFileScope;
+
+ // CMP0053 == old
+ MessageType ExpandVariablesInStringOld(std::string& errorstr,
+ std::string& source,
+ bool escapeQuotes, bool noEscapes,
+ bool atOnly, const char* filename,
+ long line, bool removeEmpty,
+ bool replaceAt) const;
+ // CMP0053 == new
+ MessageType ExpandVariablesInStringNew(std::string& errorstr,
+ std::string& source,
+ bool escapeQuotes, bool noEscapes,
+ bool atOnly, const char* filename,
+ long line, bool replaceAt) const;
+
+ bool ValidateCustomCommand(const cmCustomCommandLines& commandLines) const;
+
+ void CreateGeneratedOutputs(const std::vector<std::string>& outputs);
+
+ std::vector<BT<GeneratorAction>> GeneratorActions;
+ bool GeneratorActionsInvoked = false;
+
+ bool CheckSystemVars;
+ bool CheckCMP0000;
+ std::set<std::string> WarnedCMP0074;
+ bool IsSourceFileTryCompile;
+ mutable bool SuppressSideEffects;
+};
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
new file mode 100644
index 0000000..6783341
--- /dev/null
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -0,0 +1,677 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmMakefileExecutableTargetGenerator.h"
+
+#include <set>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cmext/algorithm>
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLinkLineComputer.h"
+#include "cmLinkLineDeviceComputer.h"
+#include "cmLocalGenerator.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmOSXBundleGenerator.h"
+#include "cmOutputConverter.h"
+#include "cmProperty.h"
+#include "cmRulePlaceholderExpander.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator(
+ cmGeneratorTarget* target)
+ : cmMakefileTargetGenerator(target)
+{
+ this->CustomCommandDriver = OnDepends;
+ this->TargetNames =
+ this->GeneratorTarget->GetExecutableNames(this->GetConfigName());
+
+ this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target);
+ this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
+}
+
+cmMakefileExecutableTargetGenerator::~cmMakefileExecutableTargetGenerator() =
+ default;
+
+void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
+{
+ // create the build.make file and directory, put in the common blocks
+ this->CreateRuleFile();
+
+ // write rules used to help build object files
+ this->WriteCommonCodeRules();
+
+ // write the per-target per-language flags
+ this->WriteTargetLanguageFlags();
+
+ // write in rules for object files and custom commands
+ this->WriteTargetBuildRules();
+
+ // write the device link rules
+ this->WriteDeviceExecutableRule(false);
+
+ // write the link rules
+ this->WriteExecutableRule(false);
+ if (this->GeneratorTarget->NeedRelinkBeforeInstall(this->GetConfigName())) {
+ // Write rules to link an installable version of the target.
+ this->WriteExecutableRule(true);
+ }
+
+ // Write clean target
+ this->WriteTargetCleanRules();
+
+ // Write the dependency generation rule. This must be done last so
+ // that multiple output pair information is available.
+ this->WriteTargetDependRules();
+
+ // close the streams
+ this->CloseFileStreams();
+}
+
+void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
+ bool relink)
+{
+#ifndef CMAKE_BOOTSTRAP
+ const bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName());
+ if (!requiresDeviceLinking) {
+ return;
+ }
+
+ std::vector<std::string> commands;
+
+ // Get the name of the device object to generate.
+ std::string const& objExt =
+ this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION");
+ std::string const targetOutput =
+ this->GeneratorTarget->ObjectDirectory + "cmake_device_link" + objExt;
+ this->DeviceLinkObject = targetOutput;
+
+ this->NumberOfProgressActions++;
+ if (!this->NoRuleMessages) {
+ cmLocalUnixMakefileGenerator3::EchoProgress progress;
+ this->MakeEchoProgress(progress);
+ // Add the link message.
+ std::string buildEcho =
+ cmStrCat("Linking CUDA device code ",
+ this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ this->DeviceLinkObject),
+ cmOutputConverter::SHELL));
+ this->LocalGenerator->AppendEcho(
+ commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress);
+ }
+
+ if (this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID") == "Clang") {
+ this->WriteDeviceLinkRule(commands, targetOutput);
+ } else {
+ this->WriteNvidiaDeviceExecutableRule(relink, commands, targetOutput);
+ }
+
+ // Write the main driver rule to build everything in this target.
+ this->WriteTargetDriverRule(targetOutput, relink);
+#else
+ static_cast<void>(relink);
+#endif
+}
+
+void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule(
+ bool relink, std::vector<std::string>& commands,
+ const std::string& targetOutput)
+{
+ const std::string linkLanguage = "CUDA";
+
+ // Build list of dependencies.
+ std::vector<std::string> depends;
+ this->AppendLinkDepends(depends, linkLanguage);
+
+ // Build a list of compiler flags and linker flags.
+ std::string langFlags;
+ std::string linkFlags;
+
+ // Add language feature flags.
+ this->LocalGenerator->AddLanguageFlagsForLinking(
+ langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
+
+ // Add device-specific linker flags.
+ this->GetDeviceLinkFlags(linkFlags, linkLanguage);
+
+ // Construct a list of files associated with this executable that
+ // may need to be cleaned.
+ std::vector<std::string> exeCleanFiles;
+ exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutput));
+
+ // Determine whether a link script will be used.
+ bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
+
+ // Construct the main link rule.
+ std::vector<std::string> real_link_commands;
+ const std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_EXECUTABLE";
+ const std::string linkRule = this->GetLinkRule(linkRuleVar);
+ std::vector<std::string> commands1;
+ cmExpandList(linkRule, real_link_commands);
+
+ bool useResponseFileForObjects =
+ this->CheckUseResponseFileForObjects(linkLanguage);
+ bool const useResponseFileForLibs =
+ this->CheckUseResponseFileForLibraries(linkLanguage);
+
+ // Expand the rule variables.
+ {
+ bool useWatcomQuote =
+ this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE");
+
+ // Set path conversion for link script shells.
+ this->LocalGenerator->SetLinkScriptShell(useLinkScript);
+
+ std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+ new cmLinkLineDeviceComputer(
+ this->LocalGenerator,
+ this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+ linkLineComputer->SetForResponse(useResponseFileForLibs);
+ linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
+ linkLineComputer->SetRelink(relink);
+
+ // Collect up flags to link in needed libraries.
+ std::string linkLibs;
+ this->CreateLinkLibs(linkLineComputer.get(), linkLibs,
+ useResponseFileForLibs, depends);
+
+ // Construct object file lists that may be needed to expand the
+ // rule.
+ std::string buildObjs;
+ this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects,
+ buildObjs, depends, useWatcomQuote);
+
+ std::string const& aixExports = this->GetAIXExports(this->GetConfigName());
+
+ cmRulePlaceholderExpander::RuleVariables vars;
+ std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
+
+ objectDir = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), objectDir),
+ cmOutputConverter::SHELL);
+
+ cmOutputConverter::OutputFormat output = (useWatcomQuote)
+ ? cmOutputConverter::WATCOMQUOTE
+ : cmOutputConverter::SHELL;
+ std::string target = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutput),
+ output);
+
+ std::string targetFullPathCompilePDB =
+ this->ComputeTargetCompilePDB(this->GetConfigName());
+ std::string targetOutPathCompilePDB =
+ this->LocalGenerator->ConvertToOutputFormat(targetFullPathCompilePDB,
+ cmOutputConverter::SHELL);
+
+ vars.Language = linkLanguage.c_str();
+ vars.AIXExports = aixExports.c_str();
+ vars.Objects = buildObjs.c_str();
+ vars.ObjectDir = objectDir.c_str();
+ vars.Target = target.c_str();
+ vars.LinkLibraries = linkLibs.c_str();
+ vars.LanguageCompileFlags = langFlags.c_str();
+ vars.LinkFlags = linkFlags.c_str();
+ vars.TargetCompilePDB = targetOutPathCompilePDB.c_str();
+
+ std::string launcher;
+
+ cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
+ "RULE_LAUNCH_LINK");
+ if (cmNonempty(val)) {
+ launcher = cmStrCat(*val, ' ');
+ }
+
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->LocalGenerator->CreateRulePlaceholderExpander());
+
+ // Expand placeholders in the commands.
+ rulePlaceholderExpander->SetTargetImpLib(targetOutput);
+ for (std::string& real_link_command : real_link_commands) {
+ real_link_command = cmStrCat(launcher, real_link_command);
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+ real_link_command, vars);
+ }
+
+ // Restore path conversion to normal shells.
+ this->LocalGenerator->SetLinkScriptShell(false);
+ }
+
+ // Optionally convert the build rule to use a script to avoid long
+ // command lines in the make shell.
+ if (useLinkScript) {
+ // Use a link script.
+ const char* name = (relink ? "drelink.txt" : "dlink.txt");
+ this->CreateLinkScript(name, real_link_commands, commands1, depends);
+ } else {
+ // No link script. Just use the link rule directly.
+ commands1 = real_link_commands;
+ }
+ this->LocalGenerator->CreateCDCommand(
+ commands1, this->Makefile->GetCurrentBinaryDirectory(),
+ this->LocalGenerator->GetBinaryDirectory());
+ cm::append(commands, commands1);
+ commands1.clear();
+
+ // Write the build rule.
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
+ targetOutput, depends, commands, false);
+
+ // Clean all the possible executable names and symlinks.
+ this->CleanFiles.insert(exeCleanFiles.begin(), exeCleanFiles.end());
+}
+
+void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
+{
+ std::vector<std::string> commands;
+
+ // Get the name of the executable to generate.
+ cmGeneratorTarget::Names targetNames =
+ this->GeneratorTarget->GetExecutableNames(this->GetConfigName());
+
+ // Construct the full path version of the names.
+ std::string outpath =
+ this->GeneratorTarget->GetDirectory(this->GetConfigName());
+ if (this->GeneratorTarget->IsAppBundleOnApple()) {
+ this->OSXBundleGenerator->CreateAppBundle(targetNames.Output, outpath,
+ this->GetConfigName());
+ }
+ outpath += '/';
+ std::string outpathImp;
+ if (relink) {
+ outpath = cmStrCat(this->Makefile->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/CMakeRelink.dir");
+ cmSystemTools::MakeDirectory(outpath);
+ outpath += '/';
+ if (!targetNames.ImportLibrary.empty()) {
+ outpathImp = outpath;
+ }
+ } else {
+ cmSystemTools::MakeDirectory(outpath);
+ if (!targetNames.ImportLibrary.empty()) {
+ outpathImp = this->GeneratorTarget->GetDirectory(
+ this->GetConfigName(), cmStateEnums::ImportLibraryArtifact);
+ cmSystemTools::MakeDirectory(outpathImp);
+ outpathImp += '/';
+ }
+ }
+
+ std::string compilePdbOutputPath =
+ this->GeneratorTarget->GetCompilePDBDirectory(this->GetConfigName());
+ cmSystemTools::MakeDirectory(compilePdbOutputPath);
+
+ std::string pdbOutputPath =
+ this->GeneratorTarget->GetPDBDirectory(this->GetConfigName());
+ cmSystemTools::MakeDirectory(pdbOutputPath);
+ pdbOutputPath += '/';
+
+ std::string targetFullPath = outpath + targetNames.Output;
+ std::string targetFullPathReal = outpath + targetNames.Real;
+ std::string targetFullPathPDB = pdbOutputPath + targetNames.PDB;
+ std::string targetFullPathImport = outpathImp + targetNames.ImportLibrary;
+ std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat(
+ targetFullPathPDB, cmOutputConverter::SHELL);
+ // Convert to the output path to use in constructing commands.
+ std::string targetOutPath = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPath),
+ cmOutputConverter::SHELL);
+ std::string targetOutPathReal = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal),
+ cmOutputConverter::SHELL);
+ std::string targetOutPathImport =
+ this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ targetFullPathImport),
+ cmOutputConverter::SHELL);
+
+ // Get the language to use for linking this executable.
+ std::string linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
+
+ // Make sure we have a link language.
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error("Cannot determine link language for target \"" +
+ this->GeneratorTarget->GetName() + "\".");
+ return;
+ }
+
+ // Build list of dependencies.
+ std::vector<std::string> depends;
+ this->AppendLinkDepends(depends, linkLanguage);
+ if (!this->DeviceLinkObject.empty()) {
+ depends.push_back(this->DeviceLinkObject);
+ }
+
+ this->NumberOfProgressActions++;
+ if (!this->NoRuleMessages) {
+ cmLocalUnixMakefileGenerator3::EchoProgress progress;
+ this->MakeEchoProgress(progress);
+ // Add the link message.
+ std::string buildEcho =
+ cmStrCat("Linking ", linkLanguage, " executable ", targetOutPath);
+ this->LocalGenerator->AppendEcho(
+ commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress);
+ }
+
+ // Build a list of compiler flags and linker flags.
+ std::string flags;
+ std::string linkFlags;
+
+ // Add flags to create an executable.
+ this->LocalGenerator->AddConfigVariableFlags(
+ linkFlags, "CMAKE_EXE_LINKER_FLAGS", this->GetConfigName());
+
+ if (this->GeneratorTarget->IsWin32Executable(
+ this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"))) {
+ this->LocalGenerator->AppendFlags(
+ linkFlags,
+ this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", linkLanguage, "_CREATE_WIN32_EXE")));
+ } else {
+ this->LocalGenerator->AppendFlags(
+ linkFlags,
+ this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", linkLanguage, "_CREATE_CONSOLE_EXE")));
+ }
+
+ // Add symbol export flags if necessary.
+ if (this->GeneratorTarget->IsExecutableWithExports()) {
+ std::string export_flag_var =
+ cmStrCat("CMAKE_EXE_EXPORTS_", linkLanguage, "_FLAG");
+ this->LocalGenerator->AppendFlags(
+ linkFlags, this->Makefile->GetSafeDefinition(export_flag_var));
+ }
+
+ this->LocalGenerator->AppendFlags(linkFlags,
+ this->LocalGenerator->GetLinkLibsCMP0065(
+ linkLanguage, *this->GeneratorTarget));
+
+ if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
+ this->LocalGenerator->AppendFlags(linkFlags, " -Wl,--no-as-needed");
+ }
+
+ // Add language feature flags.
+ this->LocalGenerator->AddLanguageFlagsForLinking(
+ flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
+
+ this->LocalGenerator->AddArchitectureFlags(
+ flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
+
+ // Add target-specific linker flags.
+ this->GetTargetLinkFlags(linkFlags, linkLanguage);
+
+ {
+ std::unique_ptr<cmLinkLineComputer> linkLineComputer =
+ this->CreateLinkLineComputer(
+ this->LocalGenerator,
+ this->LocalGenerator->GetStateSnapshot().GetDirectory());
+
+ this->AddModuleDefinitionFlag(linkLineComputer.get(), linkFlags,
+ this->GetConfigName());
+ }
+
+ this->LocalGenerator->AppendIPOLinkerFlags(
+ linkFlags, this->GeneratorTarget, this->GetConfigName(), linkLanguage);
+
+ // Construct a list of files associated with this executable that
+ // may need to be cleaned.
+ std::vector<std::string> exeCleanFiles;
+ exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPath));
+#ifdef _WIN32
+ // There may be a manifest file for this target. Add it to the
+ // clean set just in case.
+ exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ targetFullPath + ".manifest"));
+#endif
+ if (this->TargetNames.Real != this->TargetNames.Output) {
+ exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal));
+ }
+ if (!this->TargetNames.ImportLibrary.empty()) {
+ exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ targetFullPathImport));
+ std::string implib;
+ if (this->GeneratorTarget->GetImplibGNUtoMS(
+ this->GetConfigName(), targetFullPathImport, implib)) {
+ exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), implib));
+ }
+ }
+
+ // List the PDB for cleaning only when the whole target is
+ // cleaned. We do not want to delete the .pdb file just before
+ // linking the target.
+ this->CleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathPDB));
+
+ // Add the pre-build and pre-link rules building but not when relinking.
+ if (!relink) {
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPreBuildCommands(),
+ this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPreLinkCommands(),
+ this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
+ }
+
+ // Determine whether a link script will be used.
+ bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
+
+ // Construct the main link rule.
+ std::vector<std::string> real_link_commands;
+ std::string linkRuleVar = this->GeneratorTarget->GetCreateRuleVariable(
+ linkLanguage, this->GetConfigName());
+ std::string linkRule = this->GetLinkRule(linkRuleVar);
+ std::vector<std::string> commands1;
+ cmExpandList(linkRule, real_link_commands);
+ if (this->GeneratorTarget->IsExecutableWithExports()) {
+ // If a separate rule for creating an import library is specified
+ // add it now.
+ std::string implibRuleVar =
+ cmStrCat("CMAKE_", linkLanguage, "_CREATE_IMPORT_LIBRARY");
+ this->Makefile->GetDefExpandList(implibRuleVar, real_link_commands);
+ }
+
+ bool useResponseFileForObjects =
+ this->CheckUseResponseFileForObjects(linkLanguage);
+ bool const useResponseFileForLibs =
+ this->CheckUseResponseFileForLibraries(linkLanguage);
+
+ // Expand the rule variables.
+ {
+ bool useWatcomQuote =
+ this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE");
+
+ // Set path conversion for link script shells.
+ this->LocalGenerator->SetLinkScriptShell(useLinkScript);
+
+ std::unique_ptr<cmLinkLineComputer> linkLineComputer =
+ this->CreateLinkLineComputer(
+ this->LocalGenerator,
+ this->LocalGenerator->GetStateSnapshot().GetDirectory());
+ linkLineComputer->SetForResponse(useResponseFileForLibs);
+ linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
+ linkLineComputer->SetRelink(relink);
+
+ // Collect up flags to link in needed libraries.
+ std::string linkLibs;
+ this->CreateLinkLibs(linkLineComputer.get(), linkLibs,
+ useResponseFileForLibs, depends);
+
+ // Construct object file lists that may be needed to expand the
+ // rule.
+ std::string buildObjs;
+ this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects,
+ buildObjs, depends, useWatcomQuote);
+ if (!this->DeviceLinkObject.empty()) {
+ buildObjs += " " +
+ this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ this->DeviceLinkObject),
+ cmOutputConverter::SHELL);
+ }
+
+ // maybe create .def file from list of objects
+ this->GenDefFile(real_link_commands);
+
+ std::string manifests = this->GetManifests(this->GetConfigName());
+
+ cmRulePlaceholderExpander::RuleVariables vars;
+ vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
+ vars.CMTargetType =
+ cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str();
+ vars.Language = linkLanguage.c_str();
+ vars.Objects = buildObjs.c_str();
+ std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
+
+ objectDir = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), objectDir),
+ cmOutputConverter::SHELL);
+ vars.ObjectDir = objectDir.c_str();
+ cmOutputConverter::OutputFormat output = (useWatcomQuote)
+ ? cmOutputConverter::WATCOMQUOTE
+ : cmOutputConverter::SHELL;
+ std::string target = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal),
+ output);
+ vars.Target = target.c_str();
+ vars.TargetPDB = targetOutPathPDB.c_str();
+
+ // Setup the target version.
+ std::string targetVersionMajor;
+ std::string targetVersionMinor;
+ {
+ std::ostringstream majorStream;
+ std::ostringstream minorStream;
+ int major;
+ int minor;
+ this->GeneratorTarget->GetTargetVersion(major, minor);
+ majorStream << major;
+ minorStream << minor;
+ targetVersionMajor = majorStream.str();
+ targetVersionMinor = minorStream.str();
+ }
+ vars.TargetVersionMajor = targetVersionMajor.c_str();
+ vars.TargetVersionMinor = targetVersionMinor.c_str();
+
+ vars.LinkLibraries = linkLibs.c_str();
+ vars.Flags = flags.c_str();
+ vars.LinkFlags = linkFlags.c_str();
+ vars.Manifests = manifests.c_str();
+
+ if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
+ std::string cmakeCommand =
+ cmStrCat(this->LocalGenerator->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL),
+ " -E __run_co_compile --lwyu=", targetOutPathReal);
+ real_link_commands.push_back(std::move(cmakeCommand));
+ }
+
+ std::string launcher;
+
+ cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
+ "RULE_LAUNCH_LINK");
+ if (cmNonempty(val)) {
+ launcher = cmStrCat(*val, ' ');
+ }
+
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->LocalGenerator->CreateRulePlaceholderExpander());
+
+ // Expand placeholders in the commands.
+ rulePlaceholderExpander->SetTargetImpLib(targetOutPathImport);
+ for (std::string& real_link_command : real_link_commands) {
+ real_link_command = cmStrCat(launcher, real_link_command);
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+ real_link_command, vars);
+ }
+
+ // Restore path conversion to normal shells.
+ this->LocalGenerator->SetLinkScriptShell(false);
+ }
+
+ // Optionally convert the build rule to use a script to avoid long
+ // command lines in the make shell.
+ if (useLinkScript) {
+ // Use a link script.
+ const char* name = (relink ? "relink.txt" : "link.txt");
+ this->CreateLinkScript(name, real_link_commands, commands1, depends);
+ } else {
+ // No link script. Just use the link rule directly.
+ commands1 = real_link_commands;
+ }
+ this->LocalGenerator->CreateCDCommand(
+ commands1, this->Makefile->GetCurrentBinaryDirectory(),
+ this->LocalGenerator->GetBinaryDirectory());
+ cm::append(commands, commands1);
+ commands1.clear();
+
+ // Add a rule to create necessary symlinks for the library.
+ if (targetOutPath != targetOutPathReal) {
+ std::string symlink =
+ cmStrCat("$(CMAKE_COMMAND) -E cmake_symlink_executable ",
+ targetOutPathReal, ' ', targetOutPath);
+ commands1.push_back(std::move(symlink));
+ this->LocalGenerator->CreateCDCommand(
+ commands1, this->Makefile->GetCurrentBinaryDirectory(),
+ this->LocalGenerator->GetBinaryDirectory());
+ cm::append(commands, commands1);
+ commands1.clear();
+ }
+
+ // Add the post-build rules when building but not when relinking.
+ if (!relink) {
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPostBuildCommands(),
+ this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
+ }
+
+ // Write the build rule.
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
+ targetFullPathReal, depends, commands,
+ false);
+
+ // The symlink name for the target should depend on the real target
+ // so if the target version changes it rebuilds and recreates the
+ // symlink.
+ if (targetFullPath != targetFullPathReal) {
+ depends.clear();
+ commands.clear();
+ depends.push_back(targetFullPathReal);
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
+ targetFullPath, depends, commands,
+ false);
+ }
+
+ // Write the main driver rule to build everything in this target.
+ this->WriteTargetDriverRule(targetFullPath, relink);
+
+ // Clean all the possible executable names and symlinks.
+ this->CleanFiles.insert(exeCleanFiles.begin(), exeCleanFiles.end());
+}
diff --git a/Source/cmMakefileExecutableTargetGenerator.h b/Source/cmMakefileExecutableTargetGenerator.h
new file mode 100644
index 0000000..520f577
--- /dev/null
+++ b/Source/cmMakefileExecutableTargetGenerator.h
@@ -0,0 +1,33 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmMakefileTargetGenerator.h"
+
+class cmGeneratorTarget;
+
+class cmMakefileExecutableTargetGenerator : public cmMakefileTargetGenerator
+{
+public:
+ cmMakefileExecutableTargetGenerator(cmGeneratorTarget* target);
+ ~cmMakefileExecutableTargetGenerator() override;
+
+ /* the main entry point for this class. Writes the Makefiles associated
+ with this target */
+ void WriteRuleFiles() override;
+
+protected:
+ virtual void WriteExecutableRule(bool relink);
+ virtual void WriteDeviceExecutableRule(bool relink);
+ virtual void WriteNvidiaDeviceExecutableRule(
+ bool relink, std::vector<std::string>& commands,
+ const std::string& targetOutput);
+
+private:
+ std::string DeviceLinkObject;
+};
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
new file mode 100644
index 0000000..5e4f03d
--- /dev/null
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -0,0 +1,962 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmMakefileLibraryTargetGenerator.h"
+
+#include <cstddef>
+#include <set>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cmext/algorithm>
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLinkLineComputer.h"
+#include "cmLinkLineDeviceComputer.h"
+#include "cmLocalGenerator.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmOSXBundleGenerator.h"
+#include "cmOutputConverter.h"
+#include "cmProperty.h"
+#include "cmRulePlaceholderExpander.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator(
+ cmGeneratorTarget* target)
+ : cmMakefileTargetGenerator(target)
+{
+ this->CustomCommandDriver = OnDepends;
+ if (this->GeneratorTarget->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+ this->TargetNames =
+ this->GeneratorTarget->GetLibraryNames(this->GetConfigName());
+ }
+
+ this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target);
+ this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
+}
+
+cmMakefileLibraryTargetGenerator::~cmMakefileLibraryTargetGenerator() =
+ default;
+
+void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
+{
+ // create the build.make file and directory, put in the common blocks
+ this->CreateRuleFile();
+
+ // write rules used to help build object files
+ this->WriteCommonCodeRules();
+
+ // write the per-target per-language flags
+ this->WriteTargetLanguageFlags();
+
+ // write in rules for object files and custom commands
+ this->WriteTargetBuildRules();
+
+ // write the link rules
+ // Write the rule for this target type.
+ switch (this->GeneratorTarget->GetType()) {
+ case cmStateEnums::STATIC_LIBRARY:
+ this->WriteStaticLibraryRules();
+ break;
+ case cmStateEnums::SHARED_LIBRARY:
+ this->WriteSharedLibraryRules(false);
+ if (this->GeneratorTarget->NeedRelinkBeforeInstall(
+ this->GetConfigName())) {
+ // Write rules to link an installable version of the target.
+ this->WriteSharedLibraryRules(true);
+ }
+ break;
+ case cmStateEnums::MODULE_LIBRARY:
+ this->WriteModuleLibraryRules(false);
+ if (this->GeneratorTarget->NeedRelinkBeforeInstall(
+ this->GetConfigName())) {
+ // Write rules to link an installable version of the target.
+ this->WriteModuleLibraryRules(true);
+ }
+ break;
+ case cmStateEnums::OBJECT_LIBRARY:
+ this->WriteObjectLibraryRules();
+ break;
+ default:
+ // If language is not known, this is an error.
+ cmSystemTools::Error("Unknown Library Type");
+ break;
+ }
+
+ // Write clean target
+ this->WriteTargetCleanRules();
+
+ // Write the dependency generation rule. This must be done last so
+ // that multiple output pair information is available.
+ this->WriteTargetDependRules();
+
+ // close the streams
+ this->CloseFileStreams();
+}
+
+void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules()
+{
+ std::vector<std::string> commands;
+ std::vector<std::string> depends;
+
+ // Add post-build rules.
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPostBuildCommands(),
+ this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
+
+ // Depend on the object files.
+ this->AppendObjectDepends(depends);
+
+ // Write the rule.
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
+ this->GeneratorTarget->GetName(),
+ depends, commands, true);
+
+ // Write the main driver rule to build everything in this target.
+ this->WriteTargetDriverRule(this->GeneratorTarget->GetName(), false);
+}
+
+void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
+{
+ const bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName());
+ if (requiresDeviceLinking) {
+ this->WriteDeviceLibraryRules("CMAKE_CUDA_DEVICE_LINK_LIBRARY", false);
+ }
+
+ std::string linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
+
+ std::string linkRuleVar = this->GeneratorTarget->GetCreateRuleVariable(
+ linkLanguage, this->GetConfigName());
+
+ std::string extraFlags;
+ this->LocalGenerator->GetStaticLibraryFlags(
+ extraFlags, this->GetConfigName(), linkLanguage, this->GeneratorTarget);
+ this->WriteLibraryRules(linkRuleVar, extraFlags, false);
+}
+
+void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
+{
+ if (this->GeneratorTarget->IsFrameworkOnApple()) {
+ this->WriteFrameworkRules(relink);
+ return;
+ }
+
+ if (!relink) {
+ const bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName());
+ if (requiresDeviceLinking) {
+ this->WriteDeviceLibraryRules("CMAKE_CUDA_DEVICE_LINK_LIBRARY", relink);
+ }
+ }
+
+ std::string linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
+ std::string linkRuleVar =
+ cmStrCat("CMAKE_", linkLanguage, "_CREATE_SHARED_LIBRARY");
+
+ std::string extraFlags;
+ this->GetTargetLinkFlags(extraFlags, linkLanguage);
+ this->LocalGenerator->AddConfigVariableFlags(
+ extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->GetConfigName());
+
+ std::unique_ptr<cmLinkLineComputer> linkLineComputer =
+ this->CreateLinkLineComputer(
+ this->LocalGenerator,
+ this->LocalGenerator->GetStateSnapshot().GetDirectory());
+
+ this->AddModuleDefinitionFlag(linkLineComputer.get(), extraFlags,
+ this->GetConfigName());
+
+ if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
+ this->LocalGenerator->AppendFlags(extraFlags, " -Wl,--no-as-needed");
+ }
+ this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
+}
+
+void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
+{
+ if (!relink) {
+ const bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName());
+ if (requiresDeviceLinking) {
+ this->WriteDeviceLibraryRules("CMAKE_CUDA_DEVICE_LINK_LIBRARY", relink);
+ }
+ }
+
+ std::string linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
+ std::string linkRuleVar =
+ cmStrCat("CMAKE_", linkLanguage, "_CREATE_SHARED_MODULE");
+
+ std::string extraFlags;
+ this->GetTargetLinkFlags(extraFlags, linkLanguage);
+ this->LocalGenerator->AddConfigVariableFlags(
+ extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->GetConfigName());
+
+ std::unique_ptr<cmLinkLineComputer> linkLineComputer =
+ this->CreateLinkLineComputer(
+ this->LocalGenerator,
+ this->LocalGenerator->GetStateSnapshot().GetDirectory());
+
+ this->AddModuleDefinitionFlag(linkLineComputer.get(), extraFlags,
+ this->GetConfigName());
+
+ this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
+}
+
+void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink)
+{
+ std::string linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
+ std::string linkRuleVar =
+ cmStrCat("CMAKE_", linkLanguage, "_CREATE_MACOSX_FRAMEWORK");
+
+ std::string extraFlags;
+ this->GetTargetLinkFlags(extraFlags, linkLanguage);
+ this->LocalGenerator->AddConfigVariableFlags(
+ extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->GetConfigName());
+
+ this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
+}
+
+void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
+ const std::string& linkRuleVar, bool relink)
+{
+#ifndef CMAKE_BOOTSTRAP
+ // TODO: Merge the methods that call this method to avoid
+ // code duplication.
+ std::vector<std::string> commands;
+ std::string const objExt =
+ this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION");
+
+ // Get the name of the device object to generate.
+ std::string const targetOutput =
+ this->GeneratorTarget->ObjectDirectory + "cmake_device_link" + objExt;
+ this->DeviceLinkObject = targetOutput;
+
+ this->NumberOfProgressActions++;
+ if (!this->NoRuleMessages) {
+ cmLocalUnixMakefileGenerator3::EchoProgress progress;
+ this->MakeEchoProgress(progress);
+ // Add the link message.
+ std::string buildEcho =
+ cmStrCat("Linking CUDA device code ",
+ this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ this->DeviceLinkObject),
+ cmOutputConverter::SHELL));
+ this->LocalGenerator->AppendEcho(
+ commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress);
+ }
+
+ if (this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID") == "Clang") {
+ this->WriteDeviceLinkRule(commands, targetOutput);
+ } else {
+ this->WriteNvidiaDeviceLibraryRules(linkRuleVar, relink, commands,
+ targetOutput);
+ }
+
+ // Write the main driver rule to build everything in this target.
+ this->WriteTargetDriverRule(targetOutput, relink);
+}
+
+void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules(
+ const std::string& linkRuleVar, bool relink,
+ std::vector<std::string>& commands, const std::string& targetOutput)
+{
+ std::string linkLanguage = "CUDA";
+
+ // Build list of dependencies.
+ std::vector<std::string> depends;
+ this->AppendLinkDepends(depends, linkLanguage);
+
+ // Add language-specific flags.
+ std::string langFlags;
+ this->LocalGenerator->AddLanguageFlagsForLinking(
+ langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
+
+ // Create set of linking flags.
+ std::string linkFlags;
+ this->GetDeviceLinkFlags(linkFlags, linkLanguage);
+
+ // Clean files associated with this library.
+ std::set<std::string> libCleanFiles;
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutput));
+
+ // Determine whether a link script will be used.
+ bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
+
+ bool useResponseFileForObjects =
+ this->CheckUseResponseFileForObjects(linkLanguage);
+ bool const useResponseFileForLibs =
+ this->CheckUseResponseFileForLibraries(linkLanguage);
+
+ cmRulePlaceholderExpander::RuleVariables vars;
+ vars.Language = linkLanguage.c_str();
+
+ // Expand the rule variables.
+ std::vector<std::string> real_link_commands;
+ {
+ bool useWatcomQuote =
+ this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE");
+
+ // Set path conversion for link script shells.
+ this->LocalGenerator->SetLinkScriptShell(useLinkScript);
+
+ // Collect up flags to link in needed libraries.
+ std::string linkLibs;
+ std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+ new cmLinkLineDeviceComputer(
+ this->LocalGenerator,
+ this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+ linkLineComputer->SetForResponse(useResponseFileForLibs);
+ linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
+ linkLineComputer->SetRelink(relink);
+
+ this->CreateLinkLibs(linkLineComputer.get(), linkLibs,
+ useResponseFileForLibs, depends);
+
+ // Construct object file lists that may be needed to expand the
+ // rule.
+ std::string buildObjs;
+ this->CreateObjectLists(useLinkScript, false, // useArchiveRules
+ useResponseFileForObjects, buildObjs, depends,
+ useWatcomQuote);
+
+ cmOutputConverter::OutputFormat output = (useWatcomQuote)
+ ? cmOutputConverter::WATCOMQUOTE
+ : cmOutputConverter::SHELL;
+
+ std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
+ objectDir = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), objectDir),
+ cmOutputConverter::SHELL);
+
+ std::string target = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutput),
+ output);
+
+ std::string targetFullPathCompilePDB =
+ this->ComputeTargetCompilePDB(this->GetConfigName());
+ std::string targetOutPathCompilePDB =
+ this->LocalGenerator->ConvertToOutputFormat(targetFullPathCompilePDB,
+ cmOutputConverter::SHELL);
+
+ vars.Objects = buildObjs.c_str();
+ vars.ObjectDir = objectDir.c_str();
+ vars.Target = target.c_str();
+ vars.LinkLibraries = linkLibs.c_str();
+ vars.ObjectsQuoted = buildObjs.c_str();
+ vars.LanguageCompileFlags = langFlags.c_str();
+ vars.LinkFlags = linkFlags.c_str();
+ vars.TargetCompilePDB = targetOutPathCompilePDB.c_str();
+
+ std::string launcher;
+ cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
+ "RULE_LAUNCH_LINK");
+ if (cmNonempty(val)) {
+ launcher = cmStrCat(*val, ' ');
+ }
+
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->LocalGenerator->CreateRulePlaceholderExpander());
+
+ // Construct the main link rule and expand placeholders.
+ rulePlaceholderExpander->SetTargetImpLib(targetOutput);
+ std::string linkRule = this->GetLinkRule(linkRuleVar);
+ cmExpandList(linkRule, real_link_commands);
+
+ // Expand placeholders.
+ for (std::string& real_link_command : real_link_commands) {
+ real_link_command = cmStrCat(launcher, real_link_command);
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+ real_link_command, vars);
+ }
+ // Restore path conversion to normal shells.
+ this->LocalGenerator->SetLinkScriptShell(false);
+
+ // Clean all the possible library names and symlinks.
+ this->CleanFiles.insert(libCleanFiles.begin(), libCleanFiles.end());
+ }
+
+ std::vector<std::string> commands1;
+ // Optionally convert the build rule to use a script to avoid long
+ // command lines in the make shell.
+ if (useLinkScript) {
+ // Use a link script.
+ const char* name = (relink ? "drelink.txt" : "dlink.txt");
+ this->CreateLinkScript(name, real_link_commands, commands1, depends);
+ } else {
+ // No link script. Just use the link rule directly.
+ commands1 = real_link_commands;
+ }
+ this->LocalGenerator->CreateCDCommand(
+ commands1, this->Makefile->GetCurrentBinaryDirectory(),
+ this->LocalGenerator->GetBinaryDirectory());
+ cm::append(commands, commands1);
+ commands1.clear();
+
+ // Compute the list of outputs.
+ std::vector<std::string> outputs(1, targetOutput);
+
+ // Write the build rule.
+ this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends,
+ commands, false);
+#else
+ static_cast<void>(linkRuleVar);
+ static_cast<void>(relink);
+#endif
+}
+
+void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
+ const std::string& linkRuleVar, const std::string& extraFlags, bool relink)
+{
+ // TODO: Merge the methods that call this method to avoid
+ // code duplication.
+ std::vector<std::string> commands;
+
+ // Get the language to use for linking this library.
+ std::string linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
+
+ // Make sure we have a link language.
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error("Cannot determine link language for target \"" +
+ this->GeneratorTarget->GetName() + "\".");
+ return;
+ }
+
+ // Build list of dependencies.
+ std::vector<std::string> depends;
+ this->AppendLinkDepends(depends, linkLanguage);
+ if (!this->DeviceLinkObject.empty()) {
+ depends.push_back(this->DeviceLinkObject);
+ }
+
+ // Create set of linking flags.
+ std::string linkFlags;
+ this->LocalGenerator->AppendFlags(linkFlags, extraFlags);
+ this->LocalGenerator->AppendIPOLinkerFlags(
+ linkFlags, this->GeneratorTarget, this->GetConfigName(), linkLanguage);
+
+ // Add OSX version flags, if any.
+ if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ this->AppendOSXVerFlag(linkFlags, linkLanguage, "COMPATIBILITY", true);
+ this->AppendOSXVerFlag(linkFlags, linkLanguage, "CURRENT", false);
+ }
+
+ // Construct the name of the library.
+ this->GeneratorTarget->GetLibraryNames(this->GetConfigName());
+
+ // Construct the full path version of the names.
+ std::string outpath;
+ std::string outpathImp;
+ if (this->GeneratorTarget->IsFrameworkOnApple()) {
+ outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName());
+ this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output,
+ outpath, this->GetConfigName());
+ outpath += '/';
+ } else if (this->GeneratorTarget->IsCFBundleOnApple()) {
+ outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName());
+ this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output, outpath,
+ this->GetConfigName());
+ outpath += '/';
+ } else if (relink) {
+ outpath = cmStrCat(this->Makefile->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/CMakeRelink.dir");
+ cmSystemTools::MakeDirectory(outpath);
+ outpath += '/';
+ if (!this->TargetNames.ImportLibrary.empty()) {
+ outpathImp = outpath;
+ }
+ } else {
+ outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName());
+ cmSystemTools::MakeDirectory(outpath);
+ outpath += '/';
+ if (!this->TargetNames.ImportLibrary.empty()) {
+ outpathImp = this->GeneratorTarget->GetDirectory(
+ this->GetConfigName(), cmStateEnums::ImportLibraryArtifact);
+ cmSystemTools::MakeDirectory(outpathImp);
+ outpathImp += '/';
+ }
+ }
+
+ std::string compilePdbOutputPath =
+ this->GeneratorTarget->GetCompilePDBDirectory(this->GetConfigName());
+ cmSystemTools::MakeDirectory(compilePdbOutputPath);
+
+ std::string pdbOutputPath =
+ this->GeneratorTarget->GetPDBDirectory(this->GetConfigName());
+ cmSystemTools::MakeDirectory(pdbOutputPath);
+ pdbOutputPath += "/";
+
+ std::string targetFullPath = outpath + this->TargetNames.Output;
+ std::string targetFullPathPDB = pdbOutputPath + this->TargetNames.PDB;
+ std::string targetFullPathSO = outpath + this->TargetNames.SharedObject;
+ std::string targetFullPathReal = outpath + this->TargetNames.Real;
+ std::string targetFullPathImport =
+ outpathImp + this->TargetNames.ImportLibrary;
+
+ // Construct the output path version of the names for use in command
+ // arguments.
+ std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat(
+ targetFullPathPDB, cmOutputConverter::SHELL);
+
+ std::string targetOutPath = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPath),
+ cmOutputConverter::SHELL);
+ std::string targetOutPathSO = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathSO),
+ cmOutputConverter::SHELL);
+ std::string targetOutPathReal = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal),
+ cmOutputConverter::SHELL);
+ std::string targetOutPathImport =
+ this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ targetFullPathImport),
+ cmOutputConverter::SHELL);
+
+ this->NumberOfProgressActions++;
+ if (!this->NoRuleMessages) {
+ cmLocalUnixMakefileGenerator3::EchoProgress progress;
+ this->MakeEchoProgress(progress);
+ // Add the link message.
+ std::string buildEcho = cmStrCat("Linking ", linkLanguage);
+ switch (this->GeneratorTarget->GetType()) {
+ case cmStateEnums::STATIC_LIBRARY:
+ buildEcho += " static library ";
+ break;
+ case cmStateEnums::SHARED_LIBRARY:
+ buildEcho += " shared library ";
+ break;
+ case cmStateEnums::MODULE_LIBRARY:
+ if (this->GeneratorTarget->IsCFBundleOnApple()) {
+ buildEcho += " CFBundle";
+ }
+ buildEcho += " shared module ";
+ break;
+ default:
+ buildEcho += " library ";
+ break;
+ }
+ buildEcho += targetOutPath;
+ this->LocalGenerator->AppendEcho(
+ commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress);
+ }
+
+ // Clean files associated with this library.
+ std::set<std::string> libCleanFiles;
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal));
+
+ std::vector<std::string> commands1;
+ // Add a command to remove any existing files for this library.
+ // for static libs only
+ if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ this->LocalGenerator->AppendCleanCommand(commands1, libCleanFiles,
+ this->GeneratorTarget, "target");
+ this->LocalGenerator->CreateCDCommand(
+ commands1, this->Makefile->GetCurrentBinaryDirectory(),
+ this->LocalGenerator->GetBinaryDirectory());
+ cm::append(commands, commands1);
+ commands1.clear();
+ }
+
+ if (this->TargetNames.Output != this->TargetNames.Real) {
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPath));
+ }
+ if (this->TargetNames.SharedObject != this->TargetNames.Real &&
+ this->TargetNames.SharedObject != this->TargetNames.Output) {
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathSO));
+ }
+ if (!this->TargetNames.ImportLibrary.empty()) {
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ targetFullPathImport));
+ std::string implib;
+ if (this->GeneratorTarget->GetImplibGNUtoMS(
+ this->GetConfigName(), targetFullPathImport, implib)) {
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), implib));
+ }
+ }
+
+ // List the PDB for cleaning only when the whole target is
+ // cleaned. We do not want to delete the .pdb file just before
+ // linking the target.
+ this->CleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathPDB));
+
+#ifdef _WIN32
+ // There may be a manifest file for this target. Add it to the
+ // clean set just in case.
+ if (this->GeneratorTarget->GetType() != cmStateEnums::STATIC_LIBRARY) {
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ targetFullPath + ".manifest"));
+ }
+#endif
+
+ // Add the pre-build and pre-link rules building but not when relinking.
+ if (!relink) {
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPreBuildCommands(),
+ this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPreLinkCommands(),
+ this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
+ }
+
+ // Determine whether a link script will be used.
+ bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
+
+ bool useResponseFileForObjects =
+ this->CheckUseResponseFileForObjects(linkLanguage);
+ bool const useResponseFileForLibs =
+ this->CheckUseResponseFileForLibraries(linkLanguage);
+
+ // For static libraries there might be archiving rules.
+ bool haveStaticLibraryRule = false;
+ std::vector<std::string> archiveCreateCommands;
+ std::vector<std::string> archiveAppendCommands;
+ std::vector<std::string> archiveFinishCommands;
+ std::string::size_type archiveCommandLimit = std::string::npos;
+ if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ haveStaticLibraryRule = this->Makefile->IsDefinitionSet(linkRuleVar);
+ std::string arCreateVar =
+ cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_CREATE");
+
+ arCreateVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable(
+ arCreateVar, linkLanguage, this->GetConfigName());
+
+ this->Makefile->GetDefExpandList(arCreateVar, archiveCreateCommands);
+ std::string arAppendVar =
+ cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_APPEND");
+
+ arAppendVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable(
+ arAppendVar, linkLanguage, this->GetConfigName());
+
+ this->Makefile->GetDefExpandList(arAppendVar, archiveAppendCommands);
+ std::string arFinishVar =
+ cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_FINISH");
+
+ arFinishVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable(
+ arFinishVar, linkLanguage, this->GetConfigName());
+
+ this->Makefile->GetDefExpandList(arFinishVar, archiveFinishCommands);
+ }
+
+ // Decide whether to use archiving rules.
+ bool useArchiveRules = !haveStaticLibraryRule &&
+ !archiveCreateCommands.empty() && !archiveAppendCommands.empty();
+ if (useArchiveRules) {
+ // Archiving rules are always run with a link script.
+ useLinkScript = true;
+
+ // Archiving rules never use a response file.
+ useResponseFileForObjects = false;
+
+ // Limit the length of individual object lists to less than half of
+ // the command line length limit (leaving half for other flags).
+ // This may result in several calls to the archiver.
+ if (size_t limit = cmSystemTools::CalculateCommandLineLengthLimit()) {
+ archiveCommandLimit = limit / 2;
+ } else {
+ archiveCommandLimit = 8000;
+ }
+ }
+
+ // Expand the rule variables.
+ std::vector<std::string> real_link_commands;
+ {
+ bool useWatcomQuote =
+ this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE");
+
+ // Set path conversion for link script shells.
+ this->LocalGenerator->SetLinkScriptShell(useLinkScript);
+
+ // Collect up flags to link in needed libraries.
+ std::string linkLibs;
+ if (this->GeneratorTarget->GetType() != cmStateEnums::STATIC_LIBRARY) {
+
+ std::unique_ptr<cmLinkLineComputer> linkLineComputer =
+ this->CreateLinkLineComputer(
+ this->LocalGenerator,
+ this->LocalGenerator->GetStateSnapshot().GetDirectory());
+ linkLineComputer->SetForResponse(useResponseFileForLibs);
+ linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
+ linkLineComputer->SetRelink(relink);
+
+ this->CreateLinkLibs(linkLineComputer.get(), linkLibs,
+ useResponseFileForLibs, depends);
+ }
+
+ // Construct object file lists that may be needed to expand the
+ // rule.
+ std::string buildObjs;
+ this->CreateObjectLists(useLinkScript, useArchiveRules,
+ useResponseFileForObjects, buildObjs, depends,
+ useWatcomQuote);
+ if (!this->DeviceLinkObject.empty()) {
+ buildObjs += " " +
+ this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ this->DeviceLinkObject),
+ cmOutputConverter::SHELL);
+ }
+
+ std::string const& aixExports = this->GetAIXExports(this->GetConfigName());
+
+ // maybe create .def file from list of objects
+ this->GenDefFile(real_link_commands);
+
+ std::string manifests = this->GetManifests(this->GetConfigName());
+
+ cmRulePlaceholderExpander::RuleVariables vars;
+ vars.TargetPDB = targetOutPathPDB.c_str();
+
+ // Setup the target version.
+ std::string targetVersionMajor;
+ std::string targetVersionMinor;
+ {
+ std::ostringstream majorStream;
+ std::ostringstream minorStream;
+ int major;
+ int minor;
+ this->GeneratorTarget->GetTargetVersion(major, minor);
+ majorStream << major;
+ minorStream << minor;
+ targetVersionMajor = majorStream.str();
+ targetVersionMinor = minorStream.str();
+ }
+ vars.TargetVersionMajor = targetVersionMajor.c_str();
+ vars.TargetVersionMinor = targetVersionMinor.c_str();
+
+ vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
+ vars.CMTargetType =
+ cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str();
+ vars.Language = linkLanguage.c_str();
+ vars.AIXExports = aixExports.c_str();
+ vars.Objects = buildObjs.c_str();
+ std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
+
+ objectDir = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), objectDir),
+ cmOutputConverter::SHELL);
+
+ vars.ObjectDir = objectDir.c_str();
+ cmOutputConverter::OutputFormat output = (useWatcomQuote)
+ ? cmOutputConverter::WATCOMQUOTE
+ : cmOutputConverter::SHELL;
+ std::string target = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal),
+ output);
+ vars.Target = target.c_str();
+ vars.LinkLibraries = linkLibs.c_str();
+ vars.ObjectsQuoted = buildObjs.c_str();
+ std::string targetOutSOName;
+ if (this->GeneratorTarget->HasSOName(this->GetConfigName())) {
+ vars.SONameFlag = this->Makefile->GetSONameFlag(linkLanguage);
+ targetOutSOName = this->LocalGenerator->ConvertToOutputFormat(
+ this->TargetNames.SharedObject.c_str(), cmOutputConverter::SHELL);
+ vars.TargetSOName = targetOutSOName.c_str();
+ }
+ vars.LinkFlags = linkFlags.c_str();
+
+ vars.Manifests = manifests.c_str();
+
+ // Compute the directory portion of the install_name setting.
+ std::string install_name_dir;
+ if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ // Get the install_name directory for the build tree.
+ install_name_dir = this->GeneratorTarget->GetInstallNameDirForBuildTree(
+ this->GetConfigName());
+
+ // Set the rule variable replacement value.
+ if (install_name_dir.empty()) {
+ vars.TargetInstallNameDir = "";
+ } else {
+ // Convert to a path for the native build tool.
+ install_name_dir = this->LocalGenerator->ConvertToOutputFormat(
+ install_name_dir, cmOutputConverter::SHELL);
+ vars.TargetInstallNameDir = install_name_dir.c_str();
+ }
+ }
+
+ // Add language-specific flags.
+ std::string langFlags;
+ this->LocalGenerator->AddLanguageFlagsForLinking(
+ langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
+
+ this->LocalGenerator->AddArchitectureFlags(
+ langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
+
+ vars.LanguageCompileFlags = langFlags.c_str();
+
+ std::string launcher;
+ cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
+ "RULE_LAUNCH_LINK");
+ if (cmNonempty(val)) {
+ launcher = cmStrCat(*val, ' ');
+ }
+
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->LocalGenerator->CreateRulePlaceholderExpander());
+ // Construct the main link rule and expand placeholders.
+ rulePlaceholderExpander->SetTargetImpLib(targetOutPathImport);
+ if (useArchiveRules) {
+ // Construct the individual object list strings.
+ std::vector<std::string> object_strings;
+ this->WriteObjectsStrings(object_strings, archiveCommandLimit);
+
+ // Add the cuda device object to the list of archive files. This will
+ // only occur on archives which have CUDA_RESOLVE_DEVICE_SYMBOLS enabled
+ if (!this->DeviceLinkObject.empty()) {
+ object_strings.push_back(this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ this->DeviceLinkObject),
+ cmOutputConverter::SHELL));
+ }
+
+ // Create the archive with the first set of objects.
+ auto osi = object_strings.begin();
+ {
+ vars.Objects = osi->c_str();
+ for (std::string const& acc : archiveCreateCommands) {
+ std::string cmd = launcher + acc;
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+ cmd, vars);
+ real_link_commands.push_back(std::move(cmd));
+ }
+ }
+ // Append to the archive with the other object sets.
+ for (++osi; osi != object_strings.end(); ++osi) {
+ vars.Objects = osi->c_str();
+ for (std::string const& aac : archiveAppendCommands) {
+ std::string cmd = launcher + aac;
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+ cmd, vars);
+ real_link_commands.push_back(std::move(cmd));
+ }
+ }
+ // Finish the archive.
+ vars.Objects = "";
+ for (std::string const& afc : archiveFinishCommands) {
+ std::string cmd = launcher + afc;
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, cmd,
+ vars);
+ // If there is no ranlib the command will be ":". Skip it.
+ if (!cmd.empty() && cmd[0] != ':') {
+ real_link_commands.push_back(std::move(cmd));
+ }
+ }
+ } else {
+ // Get the set of commands.
+ std::string linkRule = this->GetLinkRule(linkRuleVar);
+ cmExpandList(linkRule, real_link_commands);
+ if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE") &&
+ (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY)) {
+ std::string cmakeCommand = cmStrCat(
+ this->LocalGenerator->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL),
+ " -E __run_co_compile --lwyu=", targetOutPathReal);
+ real_link_commands.push_back(std::move(cmakeCommand));
+ }
+
+ // Expand placeholders.
+ for (std::string& real_link_command : real_link_commands) {
+ real_link_command = cmStrCat(launcher, real_link_command);
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+ real_link_command, vars);
+ }
+ }
+
+ // Restore path conversion to normal shells.
+ this->LocalGenerator->SetLinkScriptShell(false);
+ }
+
+ // Optionally convert the build rule to use a script to avoid long
+ // command lines in the make shell.
+ if (useLinkScript) {
+ // Use a link script.
+ const char* name = (relink ? "relink.txt" : "link.txt");
+ this->CreateLinkScript(name, real_link_commands, commands1, depends);
+ } else {
+ // No link script. Just use the link rule directly.
+ commands1 = real_link_commands;
+ }
+ this->LocalGenerator->CreateCDCommand(
+ commands1, this->Makefile->GetCurrentBinaryDirectory(),
+ this->LocalGenerator->GetBinaryDirectory());
+ cm::append(commands, commands1);
+ commands1.clear();
+
+ // Add a rule to create necessary symlinks for the library.
+ // Frameworks are handled by cmOSXBundleGenerator.
+ if (targetOutPath != targetOutPathReal &&
+ !this->GeneratorTarget->IsFrameworkOnApple()) {
+ std::string symlink =
+ cmStrCat("$(CMAKE_COMMAND) -E cmake_symlink_library ", targetOutPathReal,
+ ' ', targetOutPathSO, ' ', targetOutPath);
+ commands1.push_back(std::move(symlink));
+ this->LocalGenerator->CreateCDCommand(
+ commands1, this->Makefile->GetCurrentBinaryDirectory(),
+ this->LocalGenerator->GetBinaryDirectory());
+ cm::append(commands, commands1);
+ commands1.clear();
+ }
+
+ // Add the post-build rules when building but not when relinking.
+ if (!relink) {
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPostBuildCommands(),
+ this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
+ }
+
+ // Compute the list of outputs.
+ std::vector<std::string> outputs(1, targetFullPathReal);
+ if (this->TargetNames.SharedObject != this->TargetNames.Real) {
+ outputs.push_back(targetFullPathSO);
+ }
+ if (this->TargetNames.Output != this->TargetNames.SharedObject &&
+ this->TargetNames.Output != this->TargetNames.Real) {
+ outputs.push_back(targetFullPath);
+ }
+
+ // Write the build rule.
+ this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends,
+ commands, false);
+
+ // Write the main driver rule to build everything in this target.
+ this->WriteTargetDriverRule(targetFullPath, relink);
+
+ // Clean all the possible library names and symlinks.
+ this->CleanFiles.insert(libCleanFiles.begin(), libCleanFiles.end());
+}
diff --git a/Source/cmMakefileLibraryTargetGenerator.h b/Source/cmMakefileLibraryTargetGenerator.h
new file mode 100644
index 0000000..cc989e7
--- /dev/null
+++ b/Source/cmMakefileLibraryTargetGenerator.h
@@ -0,0 +1,45 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmMakefileTargetGenerator.h"
+
+class cmGeneratorTarget;
+
+class cmMakefileLibraryTargetGenerator : public cmMakefileTargetGenerator
+{
+public:
+ cmMakefileLibraryTargetGenerator(cmGeneratorTarget* target);
+ ~cmMakefileLibraryTargetGenerator() override;
+
+ /* the main entry point for this class. Writes the Makefiles associated
+ with this target */
+ void WriteRuleFiles() override;
+
+protected:
+ void WriteObjectLibraryRules();
+ void WriteStaticLibraryRules();
+ void WriteSharedLibraryRules(bool relink);
+ void WriteModuleLibraryRules(bool relink);
+
+ void WriteDeviceLibraryRules(const std::string& linkRule, bool relink);
+ void WriteNvidiaDeviceLibraryRules(const std::string& linkRuleVar,
+ bool relink,
+ std::vector<std::string>& commands,
+ const std::string& targetOutput);
+ void WriteLibraryRules(const std::string& linkRule,
+ const std::string& extraFlags, bool relink);
+ // MacOSX Framework support methods
+ void WriteFrameworkRules(bool relink);
+
+ // Store the computd framework version for OS X Frameworks.
+ std::string FrameworkVersion;
+
+private:
+ std::string DeviceLinkObject;
+};
diff --git a/Source/cmMakefileProfilingData.cxx b/Source/cmMakefileProfilingData.cxx
new file mode 100644
index 0000000..86188db
--- /dev/null
+++ b/Source/cmMakefileProfilingData.cxx
@@ -0,0 +1,114 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmMakefileProfilingData.h"
+
+#include <chrono>
+#include <stdexcept>
+#include <vector>
+
+#include <cm3p/json/value.h>
+#include <cm3p/json/writer.h>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/SystemInformation.hxx"
+
+#include "cmListFileCache.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmMakefileProfilingData::cmMakefileProfilingData(
+ const std::string& profileStream)
+{
+ std::ios::openmode omode = std::ios::out | std::ios::trunc;
+ this->ProfileStream.open(profileStream.c_str(), omode);
+ Json::StreamWriterBuilder wbuilder;
+ this->JsonWriter =
+ std::unique_ptr<Json::StreamWriter>(wbuilder.newStreamWriter());
+ if (!this->ProfileStream.good()) {
+ throw std::runtime_error(std::string("Unable to open: ") + profileStream);
+ }
+
+ this->ProfileStream << "[";
+};
+
+cmMakefileProfilingData::~cmMakefileProfilingData() noexcept
+{
+ if (this->ProfileStream.good()) {
+ try {
+ this->ProfileStream << "]";
+ this->ProfileStream.close();
+ } catch (...) {
+ cmSystemTools::Error("Error writing profiling output!");
+ }
+ }
+}
+
+void cmMakefileProfilingData::StartEntry(const cmListFileFunction& lff,
+ cmListFileContext const& lfc)
+{
+ /* Do not try again if we previously failed to write to output. */
+ if (!this->ProfileStream.good()) {
+ return;
+ }
+
+ try {
+ if (this->ProfileStream.tellp() > 1) {
+ this->ProfileStream << ",";
+ }
+ cmsys::SystemInformation info;
+ Json::Value v;
+ v["ph"] = "B";
+ v["name"] = lff.LowerCaseName();
+ v["cat"] = "cmake";
+ v["ts"] = Json::Value::UInt64(
+ std::chrono::duration_cast<std::chrono::microseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count());
+ v["pid"] = static_cast<int>(info.GetProcessId());
+ v["tid"] = 0;
+ Json::Value argsValue;
+ if (!lff.Arguments().empty()) {
+ std::string args;
+ for (auto const& a : lff.Arguments()) {
+ args += (args.empty() ? "" : " ") + a.Value;
+ }
+ argsValue["functionArgs"] = args;
+ }
+ argsValue["location"] = lfc.FilePath + ":" + std::to_string(lfc.Line);
+ v["args"] = argsValue;
+
+ this->JsonWriter->write(v, &this->ProfileStream);
+ } catch (std::ios_base::failure& fail) {
+ cmSystemTools::Error(
+ cmStrCat("Failed to write to profiling output: ", fail.what()));
+ } catch (...) {
+ cmSystemTools::Error("Error writing profiling output!");
+ }
+}
+
+void cmMakefileProfilingData::StopEntry()
+{
+ /* Do not try again if we previously failed to write to output. */
+ if (!this->ProfileStream.good()) {
+ return;
+ }
+
+ try {
+ this->ProfileStream << ",";
+ cmsys::SystemInformation info;
+ Json::Value v;
+ v["ph"] = "E";
+ v["ts"] = Json::Value::UInt64(
+ std::chrono::duration_cast<std::chrono::microseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count());
+ v["pid"] = static_cast<int>(info.GetProcessId());
+ v["tid"] = 0;
+ this->JsonWriter->write(v, &this->ProfileStream);
+ } catch (std::ios_base::failure& fail) {
+ cmSystemTools::Error(
+ cmStrCat("Failed to write to profiling output:", fail.what()));
+ } catch (...) {
+ cmSystemTools::Error("Error writing profiling output!");
+ }
+}
diff --git a/Source/cmMakefileProfilingData.h b/Source/cmMakefileProfilingData.h
new file mode 100644
index 0000000..a86764a
--- /dev/null
+++ b/Source/cmMakefileProfilingData.h
@@ -0,0 +1,27 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+#include <memory>
+#include <string>
+
+#include "cmsys/FStream.hxx"
+
+namespace Json {
+class StreamWriter;
+}
+
+class cmListFileContext;
+class cmListFileFunction;
+
+class cmMakefileProfilingData
+{
+public:
+ cmMakefileProfilingData(const std::string&);
+ ~cmMakefileProfilingData() noexcept;
+ void StartEntry(const cmListFileFunction& lff, cmListFileContext const& lfc);
+ void StopEntry();
+
+private:
+ cmsys::ofstream ProfileStream;
+ std::unique_ptr<Json::StreamWriter> JsonWriter;
+};
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
new file mode 100644
index 0000000..fa469ed
--- /dev/null
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -0,0 +1,2268 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmMakefileTargetGenerator.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <iterator>
+#include <sstream>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmComputeLinkInformation.h"
+#include "cmCustomCommand.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLinkLineComputer.h" // IWYU pragma: keep
+#include "cmLocalCommonGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmMakefileExecutableTargetGenerator.h"
+#include "cmMakefileLibraryTargetGenerator.h"
+#include "cmMakefileUtilityTargetGenerator.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmRulePlaceholderExpander.h"
+#include "cmSourceFile.h"
+#include "cmSourceFileLocationKind.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target)
+ : cmCommonTargetGenerator(target)
+{
+ this->CustomCommandDriver = OnBuild;
+ this->LocalGenerator =
+ static_cast<cmLocalUnixMakefileGenerator3*>(target->GetLocalGenerator());
+ this->GlobalGenerator = static_cast<cmGlobalUnixMakefileGenerator3*>(
+ this->LocalGenerator->GetGlobalGenerator());
+ cmake* cm = this->GlobalGenerator->GetCMakeInstance();
+ this->NoRuleMessages = false;
+ if (cmProp ruleStatus = cm->GetState()->GetGlobalProperty("RULE_MESSAGES")) {
+ this->NoRuleMessages = cmIsOff(*ruleStatus);
+ }
+ switch (this->GeneratorTarget->GetPolicyStatusCMP0113()) {
+ case cmPolicies::WARN:
+ case cmPolicies::OLD:
+ this->CMP0113New = false;
+ break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->CMP0113New = true;
+ break;
+ }
+ this->MacOSXContentGenerator =
+ cm::make_unique<MacOSXContentGeneratorType>(this);
+}
+
+cmMakefileTargetGenerator::~cmMakefileTargetGenerator() = default;
+
+std::unique_ptr<cmMakefileTargetGenerator> cmMakefileTargetGenerator::New(
+ cmGeneratorTarget* tgt)
+{
+ std::unique_ptr<cmMakefileTargetGenerator> result;
+
+ switch (tgt->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ result = cm::make_unique<cmMakefileExecutableTargetGenerator>(tgt);
+ break;
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::OBJECT_LIBRARY:
+ result = cm::make_unique<cmMakefileLibraryTargetGenerator>(tgt);
+ break;
+ case cmStateEnums::INTERFACE_LIBRARY:
+ case cmStateEnums::UTILITY:
+ result = cm::make_unique<cmMakefileUtilityTargetGenerator>(tgt);
+ break;
+ default:
+ return result;
+ // break; /* unreachable */
+ }
+ return result;
+}
+
+std::string cmMakefileTargetGenerator::GetConfigName()
+{
+ auto const& configNames = this->LocalGenerator->GetConfigNames();
+ assert(configNames.size() == 1);
+ return configNames.front();
+}
+
+void cmMakefileTargetGenerator::GetDeviceLinkFlags(
+ std::string& linkFlags, const std::string& linkLanguage)
+{
+ cmGeneratorTarget::DeviceLinkSetter setter(*this->GetGeneratorTarget());
+
+ std::vector<std::string> linkOpts;
+ this->GeneratorTarget->GetLinkOptions(linkOpts, this->GetConfigName(),
+ linkLanguage);
+ // LINK_OPTIONS are escaped.
+ this->LocalGenerator->AppendCompileOptions(linkFlags, linkOpts);
+}
+
+void cmMakefileTargetGenerator::GetTargetLinkFlags(
+ std::string& flags, const std::string& linkLanguage)
+{
+ this->LocalGenerator->AppendFlags(
+ flags, this->GeneratorTarget->GetSafeProperty("LINK_FLAGS"));
+
+ std::string linkFlagsConfig =
+ cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(this->GetConfigName()));
+ this->LocalGenerator->AppendFlags(
+ flags, this->GeneratorTarget->GetSafeProperty(linkFlagsConfig));
+
+ std::vector<std::string> opts;
+ this->GeneratorTarget->GetLinkOptions(opts, this->GetConfigName(),
+ linkLanguage);
+ // LINK_OPTIONS are escaped.
+ this->LocalGenerator->AppendCompileOptions(flags, opts);
+
+ this->LocalGenerator->AppendPositionIndependentLinkerFlags(
+ flags, this->GeneratorTarget, this->GetConfigName(), linkLanguage);
+}
+
+void cmMakefileTargetGenerator::CreateRuleFile()
+{
+ // Create a directory for this target.
+ this->TargetBuildDirectory =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ this->TargetBuildDirectoryFull =
+ this->LocalGenerator->ConvertToFullPath(this->TargetBuildDirectory);
+ cmSystemTools::MakeDirectory(this->TargetBuildDirectoryFull);
+
+ // Construct the rule file name.
+ this->BuildFileName = cmStrCat(this->TargetBuildDirectory, "/build.make");
+ this->BuildFileNameFull =
+ cmStrCat(this->TargetBuildDirectoryFull, "/build.make");
+
+ // Construct the rule file name.
+ this->ProgressFileNameFull =
+ cmStrCat(this->TargetBuildDirectoryFull, "/progress.make");
+
+ // reset the progress count
+ this->NumberOfProgressActions = 0;
+
+ // Open the rule file. This should be copy-if-different because the
+ // rules may depend on this file itself.
+ this->BuildFileStream = cm::make_unique<cmGeneratedFileStream>(
+ this->BuildFileNameFull, false,
+ this->GlobalGenerator->GetMakefileEncoding());
+ if (!this->BuildFileStream) {
+ return;
+ }
+ this->BuildFileStream->SetCopyIfDifferent(true);
+ this->LocalGenerator->WriteDisclaimer(*this->BuildFileStream);
+ if (this->GlobalGenerator->AllowDeleteOnError()) {
+ std::vector<std::string> no_depends;
+ std::vector<std::string> no_commands;
+ this->LocalGenerator->WriteMakeRule(
+ *this->BuildFileStream, "Delete rule output on recipe failure.",
+ ".DELETE_ON_ERROR", no_depends, no_commands, false);
+ }
+ this->LocalGenerator->WriteSpecialTargetsTop(*this->BuildFileStream);
+}
+
+void cmMakefileTargetGenerator::WriteTargetBuildRules()
+{
+ // -- Write the custom commands for this target
+
+ // Evaluates generator expressions and expands prop_value
+ auto evaluatedFiles =
+ [this](const std::string& prop_value) -> std::vector<std::string> {
+ std::vector<std::string> files;
+ cmExpandList(cmGeneratorExpression::Evaluate(
+ prop_value, this->LocalGenerator, this->GetConfigName(),
+ this->GeneratorTarget),
+ files);
+ return files;
+ };
+
+ // Look for additional files registered for cleaning in this directory.
+ if (cmProp prop_value =
+ this->Makefile->GetProperty("ADDITIONAL_MAKE_CLEAN_FILES")) {
+ std::vector<std::string> const files = evaluatedFiles(*prop_value);
+ this->CleanFiles.insert(files.begin(), files.end());
+ }
+
+ // Look for additional files registered for cleaning in this target.
+ if (cmProp prop_value =
+ this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) {
+ std::vector<std::string> const files = evaluatedFiles(*prop_value);
+ // For relative path support
+ std::string const& binaryDir =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+ for (std::string const& cfl : files) {
+ this->CleanFiles.insert(cmSystemTools::CollapseFullPath(cfl, binaryDir));
+ }
+ }
+
+ std::string currentBinDir =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+
+ // Look for ISPC extra object files generated by this target
+ auto ispcAdditionalObjs =
+ this->GeneratorTarget->GetGeneratedISPCObjects(this->GetConfigName());
+ for (std::string const& ispcObj : ispcAdditionalObjs) {
+ this->CleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
+ currentBinDir, ispcObj));
+ }
+
+ // add custom commands to the clean rules?
+ bool clean = cmIsOff(this->Makefile->GetProperty("CLEAN_NO_CUSTOM"));
+
+ // First generate the object rule files. Save a list of all object
+ // files for this target.
+ std::vector<cmSourceFile const*> customCommands;
+ this->GeneratorTarget->GetCustomCommands(customCommands,
+ this->GetConfigName());
+ for (cmSourceFile const* sf : customCommands) {
+ if (this->CMP0113New &&
+ !this->LocalGenerator->GetCommandsVisited(this->GeneratorTarget)
+ .insert(sf)
+ .second) {
+ continue;
+ }
+ cmCustomCommandGenerator ccg(*sf->GetCustomCommand(),
+ this->GetConfigName(), this->LocalGenerator);
+ this->GenerateCustomRuleFile(ccg);
+ if (clean) {
+ const std::vector<std::string>& outputs = ccg.GetOutputs();
+ for (std::string const& output : outputs) {
+ this->CleanFiles.insert(
+ this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir,
+ output));
+ }
+ const std::vector<std::string>& byproducts = ccg.GetByproducts();
+ for (std::string const& byproduct : byproducts) {
+ this->CleanFiles.insert(
+ this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir,
+ byproduct));
+ }
+ }
+ }
+
+ // Add byproducts from build events to the clean rules
+ if (clean) {
+ std::vector<cmCustomCommand> buildEventCommands =
+ this->GeneratorTarget->GetPreBuildCommands();
+
+ cm::append(buildEventCommands,
+ this->GeneratorTarget->GetPreLinkCommands());
+ cm::append(buildEventCommands,
+ this->GeneratorTarget->GetPostBuildCommands());
+
+ for (const auto& be : buildEventCommands) {
+ cmCustomCommandGenerator beg(be, this->GetConfigName(),
+ this->LocalGenerator);
+ const std::vector<std::string>& byproducts = beg.GetByproducts();
+ for (std::string const& byproduct : byproducts) {
+ this->CleanFiles.insert(
+ this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir,
+ byproduct));
+ }
+ }
+ }
+ std::vector<cmSourceFile const*> headerSources;
+ this->GeneratorTarget->GetHeaderSources(headerSources,
+ this->GetConfigName());
+ this->OSXBundleGenerator->GenerateMacOSXContentStatements(
+ headerSources, this->MacOSXContentGenerator.get(), this->GetConfigName());
+ std::vector<cmSourceFile const*> extraSources;
+ this->GeneratorTarget->GetExtraSources(extraSources, this->GetConfigName());
+ this->OSXBundleGenerator->GenerateMacOSXContentStatements(
+ extraSources, this->MacOSXContentGenerator.get(), this->GetConfigName());
+ cmProp pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
+ std::vector<cmSourceFile const*> externalObjects;
+ this->GeneratorTarget->GetExternalObjects(externalObjects,
+ this->GetConfigName());
+ for (cmSourceFile const* sf : externalObjects) {
+ auto const& objectFileName = sf->GetFullPath();
+ if (!cmSystemTools::StringEndsWith(objectFileName,
+ cmToCStr(pchExtension))) {
+ this->ExternalObjects.push_back(objectFileName);
+ }
+ }
+
+ std::vector<cmSourceFile const*> objectSources;
+ this->GeneratorTarget->GetObjectSources(objectSources,
+ this->GetConfigName());
+ for (cmSourceFile const* sf : objectSources) {
+ // Generate this object file's rule file.
+ this->WriteObjectRuleFiles(*sf);
+ }
+}
+
+void cmMakefileTargetGenerator::WriteCommonCodeRules()
+{
+ const char* root = (this->Makefile->IsOn("CMAKE_MAKE_INCLUDE_FROM_ROOT")
+ ? "$(CMAKE_BINARY_DIR)/"
+ : "");
+
+ // Include the dependencies for the target.
+ std::string dependFileNameFull =
+ cmStrCat(this->TargetBuildDirectoryFull, "/depend.make");
+ *this->BuildFileStream
+ << "# Include any dependencies generated for this target.\n"
+ << this->GlobalGenerator->IncludeDirective << " " << root
+ << cmSystemTools::ConvertToOutputPath(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(), dependFileNameFull))
+ << "\n";
+
+ std::string depsUseCompiler = "CMAKE_DEPENDS_USE_COMPILER";
+ if (!this->Makefile->IsDefinitionSet(depsUseCompiler) ||
+ this->Makefile->IsOn(depsUseCompiler)) {
+ std::string compilerDependFile =
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.make");
+ *this->BuildFileStream
+ << "# Include any dependencies generated by the "
+ "compiler for this target.\n"
+ << this->GlobalGenerator->IncludeDirective << " " << root
+ << cmSystemTools::ConvertToOutputPath(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(), compilerDependFile))
+ << "\n\n";
+
+ // Write an empty dependency file.
+ cmGeneratedFileStream depFileStream(
+ compilerDependFile, false, this->GlobalGenerator->GetMakefileEncoding());
+ depFileStream << "# Empty compiler generated dependencies file for "
+ << this->GeneratorTarget->GetName() << ".\n"
+ << "# This may be replaced when dependencies are built.\n";
+ // remove internal dependency file
+ cmSystemTools::RemoveFile(
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.internal"));
+
+ std::string compilerDependTimestamp =
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts");
+ if (!cmSystemTools::FileExists(compilerDependTimestamp)) {
+ // Write a dependency timestamp file.
+ cmGeneratedFileStream timestampFileStream(
+ compilerDependTimestamp, false,
+ this->GlobalGenerator->GetMakefileEncoding());
+ timestampFileStream
+ << "# CMAKE generated file: DO NOT EDIT!\n"
+ << "# Timestamp file for compiler generated dependencies "
+ "management for "
+ << this->GeneratorTarget->GetName() << ".\n";
+ }
+
+ // deactivate no longer needed legacy dependency files
+ // Write an empty dependency file.
+ cmGeneratedFileStream legacyDepFileStream(
+ dependFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding());
+ legacyDepFileStream
+ << "# Empty dependencies file for " << this->GeneratorTarget->GetName()
+ << ".\n"
+ << "# This may be replaced when dependencies are built.\n";
+ // remove internal dependency file
+ cmSystemTools::RemoveFile(
+ cmStrCat(this->TargetBuildDirectoryFull, "/depend.internal"));
+ } else {
+ // make sure the depend file exists
+ if (!cmSystemTools::FileExists(dependFileNameFull)) {
+ // Write an empty dependency file.
+ cmGeneratedFileStream depFileStream(
+ dependFileNameFull, false,
+ this->GlobalGenerator->GetMakefileEncoding());
+ depFileStream << "# Empty dependencies file for "
+ << this->GeneratorTarget->GetName() << ".\n"
+ << "# This may be replaced when dependencies are built.\n";
+ }
+ }
+
+ if (!this->NoRuleMessages) {
+ // Include the progress variables for the target.
+ *this->BuildFileStream
+ << "# Include the progress variables for this target.\n"
+ << this->GlobalGenerator->IncludeDirective << " " << root
+ << cmSystemTools::ConvertToOutputPath(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(),
+ this->ProgressFileNameFull))
+ << "\n\n";
+ }
+
+ // Open the flags file. This should be copy-if-different because the
+ // rules may depend on this file itself.
+ this->FlagFileNameFull =
+ cmStrCat(this->TargetBuildDirectoryFull, "/flags.make");
+ this->FlagFileStream = cm::make_unique<cmGeneratedFileStream>(
+ this->FlagFileNameFull, false,
+ this->GlobalGenerator->GetMakefileEncoding());
+ if (!this->FlagFileStream) {
+ return;
+ }
+ this->FlagFileStream->SetCopyIfDifferent(true);
+ this->LocalGenerator->WriteDisclaimer(*this->FlagFileStream);
+
+ // Include the flags for the target.
+ *this->BuildFileStream
+ << "# Include the compile flags for this target's objects.\n"
+ << this->GlobalGenerator->IncludeDirective << " " << root
+ << cmSystemTools::ConvertToOutputPath(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(), this->FlagFileNameFull))
+ << "\n\n";
+}
+
+void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
+{
+ // write language flags for target
+ std::set<std::string> languages;
+ this->GeneratorTarget->GetLanguages(
+ languages, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+ // put the compiler in the rules.make file so that if it changes
+ // things rebuild
+ for (std::string const& language : languages) {
+ std::string compiler = cmStrCat("CMAKE_", language, "_COMPILER");
+ *this->FlagFileStream << "# compile " << language << " with "
+ << this->Makefile->GetSafeDefinition(compiler)
+ << "\n";
+ }
+
+ bool const escapeOctothorpe = this->GlobalGenerator->CanEscapeOctothorpe();
+
+ for (std::string const& language : languages) {
+ std::string defines = this->GetDefines(language, this->GetConfigName());
+ std::string includes = this->GetIncludes(language, this->GetConfigName());
+ if (escapeOctothorpe) {
+ // Escape comment characters so they do not terminate assignment.
+ cmSystemTools::ReplaceString(defines, "#", "\\#");
+ cmSystemTools::ReplaceString(includes, "#", "\\#");
+ }
+ *this->FlagFileStream << language << "_DEFINES = " << defines << "\n\n";
+ *this->FlagFileStream << language << "_INCLUDES = " << includes << "\n\n";
+
+ std::vector<std::string> architectures;
+ this->GeneratorTarget->GetAppleArchs(this->GetConfigName(), architectures);
+ architectures.emplace_back();
+
+ for (const std::string& arch : architectures) {
+ std::string flags =
+ this->GetFlags(language, this->GetConfigName(), arch);
+ if (escapeOctothorpe) {
+ cmSystemTools::ReplaceString(flags, "#", "\\#");
+ }
+ *this->FlagFileStream << language << "_FLAGS" << arch << " = " << flags
+ << "\n\n";
+ }
+ }
+}
+
+void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()(
+ cmSourceFile const& source, const char* pkgloc, const std::string& config)
+{
+ // Skip OS X content when not building a Framework or Bundle.
+ if (!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) {
+ return;
+ }
+
+ std::string macdir =
+ this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc,
+ config);
+
+ // Get the input file location.
+ std::string const& input = source.GetFullPath();
+
+ // Get the output file location.
+ std::string output =
+ cmStrCat(macdir, '/', cmSystemTools::GetFilenameName(input));
+ this->Generator->CleanFiles.insert(
+ this->Generator->LocalGenerator->MaybeConvertToRelativePath(
+ this->Generator->LocalGenerator->GetCurrentBinaryDirectory(), output));
+ output = this->Generator->LocalGenerator->MaybeConvertToRelativePath(
+ this->Generator->LocalGenerator->GetBinaryDirectory(), output);
+
+ // Create a rule to copy the content into the bundle.
+ std::vector<std::string> depends;
+ std::vector<std::string> commands;
+ depends.push_back(input);
+ std::string copyEcho = cmStrCat("Copying OS X content ", output);
+ this->Generator->LocalGenerator->AppendEcho(
+ commands, copyEcho, cmLocalUnixMakefileGenerator3::EchoBuild);
+ std::string copyCommand =
+ cmStrCat("$(CMAKE_COMMAND) -E copy ",
+ this->Generator->LocalGenerator->ConvertToOutputFormat(
+ input, cmOutputConverter::SHELL),
+ ' ',
+ this->Generator->LocalGenerator->ConvertToOutputFormat(
+ output, cmOutputConverter::SHELL));
+ commands.push_back(std::move(copyCommand));
+ this->Generator->LocalGenerator->WriteMakeRule(
+ *this->Generator->BuildFileStream, nullptr, output, depends, commands,
+ false);
+ this->Generator->ExtraFiles.insert(output);
+}
+
+void cmMakefileTargetGenerator::WriteObjectRuleFiles(
+ cmSourceFile const& source)
+{
+ // Identify the language of the source file.
+ const std::string& lang =
+ this->LocalGenerator->GetSourceFileLanguage(source);
+ if (lang.empty()) {
+ // don't know anything about this file so skip it
+ return;
+ }
+
+ // Use compiler to generate dependencies, if supported.
+ bool compilerGenerateDeps =
+ this->GlobalGenerator->SupportsCompilerDependencies() &&
+ cmIsOn(this->Makefile->GetDefinition(
+ cmStrCat("CMAKE_", lang, "_DEPENDS_USE_COMPILER")));
+ auto scanner = compilerGenerateDeps ? cmDependencyScannerKind::Compiler
+ : cmDependencyScannerKind::CMake;
+
+ // Get the full path name of the object file.
+ std::string const& objectName =
+ this->GeneratorTarget->GetObjectName(&source);
+ std::string obj =
+ cmStrCat(this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget),
+ '/', objectName);
+
+ // Avoid generating duplicate rules.
+ if (this->ObjectFiles.find(obj) == this->ObjectFiles.end()) {
+ this->ObjectFiles.insert(obj);
+ } else {
+ std::ostringstream err;
+ err << "Warning: Source file \"" << source.GetFullPath()
+ << "\" is listed multiple times for target \""
+ << this->GeneratorTarget->GetName() << "\".";
+ cmSystemTools::Message(err.str(), "Warning");
+ return;
+ }
+
+ // Create the directory containing the object file. This may be a
+ // subdirectory under the target's directory.
+ {
+ std::string dir = cmSystemTools::GetFilenamePath(obj);
+ cmSystemTools::MakeDirectory(this->LocalGenerator->ConvertToFullPath(dir));
+ }
+
+ // Save this in the target's list of object files.
+ this->Objects.push_back(obj);
+ this->CleanFiles.insert(obj);
+
+ std::vector<std::string> depends;
+
+ // The object file should be checked for dependency integrity.
+ std::string objFullPath =
+ cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/', obj);
+ objFullPath = cmSystemTools::CollapseFullPath(objFullPath);
+ std::string srcFullPath =
+ cmSystemTools::CollapseFullPath(source.GetFullPath());
+ this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, lang,
+ objFullPath, srcFullPath, scanner);
+
+ this->LocalGenerator->AppendRuleDepend(depends,
+ this->FlagFileNameFull.c_str());
+ this->LocalGenerator->AppendRuleDepends(depends,
+ this->FlagFileDepends[lang]);
+
+ // generate the depend scanning rule
+ this->WriteObjectDependRules(source, depends);
+
+ std::string config = this->GetConfigName();
+ std::string configUpper = cmSystemTools::UpperCase(config);
+
+ // Add precompile headers dependencies
+ std::vector<std::string> architectures;
+ this->GeneratorTarget->GetAppleArchs(config, architectures);
+ if (architectures.empty()) {
+ architectures.emplace_back();
+ }
+
+ std::string filterArch;
+ std::unordered_map<std::string, std::string> pchSources;
+ for (const std::string& arch : architectures) {
+ const std::string pchSource =
+ this->GeneratorTarget->GetPchSource(config, lang, arch);
+ if (pchSource == source.GetFullPath()) {
+ filterArch = arch;
+ }
+ if (!pchSource.empty()) {
+ pchSources.insert(std::make_pair(pchSource, arch));
+ }
+ }
+
+ if (!pchSources.empty() && !source.GetProperty("SKIP_PRECOMPILE_HEADERS")) {
+ for (const std::string& arch : architectures) {
+ std::string const& pchHeader =
+ this->GeneratorTarget->GetPchHeader(config, lang, arch);
+ depends.push_back(pchHeader);
+ if (pchSources.find(source.GetFullPath()) == pchSources.end()) {
+ depends.push_back(
+ this->GeneratorTarget->GetPchFile(config, lang, arch));
+ }
+ this->LocalGenerator->AddImplicitDepends(
+ this->GeneratorTarget, lang, objFullPath, pchHeader, scanner);
+ }
+ }
+
+ if (lang != "ISPC") {
+ auto const& headers =
+ this->GeneratorTarget->GetGeneratedISPCHeaders(config);
+ if (!headers.empty()) {
+ depends.insert(depends.end(), headers.begin(), headers.end());
+ }
+ }
+
+ std::string relativeObj =
+ cmStrCat(this->LocalGenerator->GetHomeRelativeOutputPath(), obj);
+ // Write the build rule.
+
+ // Build the set of compiler flags.
+ std::string flags;
+
+ // Explicitly add the explicit language flag before any other flag
+ // so user flags can override it.
+ this->GeneratorTarget->AddExplicitLanguageFlags(flags, source);
+
+ // Add language-specific flags.
+ std::string langFlags = cmStrCat("$(", lang, "_FLAGS", filterArch, ")");
+ this->LocalGenerator->AppendFlags(flags, langFlags);
+
+ cmGeneratorExpressionInterpreter genexInterpreter(
+ this->LocalGenerator, config, this->GeneratorTarget, lang);
+
+ // Add Fortran format flags.
+ if (lang == "Fortran") {
+ this->AppendFortranFormatFlags(flags, source);
+ this->AppendFortranPreprocessFlags(flags, source);
+ }
+
+ std::string ispcHeaderRelative;
+ std::string ispcHeaderForShell;
+ if (lang == "ISPC") {
+ std::string ispcSource =
+ cmSystemTools::GetFilenameWithoutLastExtension(objectName);
+ ispcSource = cmSystemTools::GetFilenameWithoutLastExtension(ispcSource);
+
+ cmProp ispcSuffixProp =
+ this->GeneratorTarget->GetProperty("ISPC_HEADER_SUFFIX");
+ assert(ispcSuffixProp != nullptr);
+
+ std::string directory = this->GeneratorTarget->GetObjectDirectory(config);
+ if (cmProp prop =
+ this->GeneratorTarget->GetProperty("ISPC_HEADER_DIRECTORY")) {
+ directory =
+ cmStrCat(this->LocalGenerator->GetBinaryDirectory(), '/', *prop);
+ }
+ ispcHeaderRelative = cmStrCat(directory, '/', ispcSource, *ispcSuffixProp);
+ ispcHeaderForShell = this->LocalGenerator->ConvertToOutputFormat(
+ ispcHeaderRelative, cmOutputConverter::SHELL);
+ }
+
+ // Add flags from source file properties.
+ const std::string COMPILE_FLAGS("COMPILE_FLAGS");
+ if (cmProp cflags = source.GetProperty(COMPILE_FLAGS)) {
+ const std::string& evaluatedFlags =
+ genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS);
+ this->LocalGenerator->AppendFlags(flags, evaluatedFlags);
+ *this->FlagFileStream << "# Custom flags: " << relativeObj
+ << "_FLAGS = " << evaluatedFlags << "\n"
+ << "\n";
+ }
+
+ const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
+ if (cmProp coptions = source.GetProperty(COMPILE_OPTIONS)) {
+ const std::string& evaluatedOptions =
+ genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS);
+ this->LocalGenerator->AppendCompileOptions(flags, evaluatedOptions);
+ *this->FlagFileStream << "# Custom options: " << relativeObj
+ << "_OPTIONS = " << evaluatedOptions << "\n"
+ << "\n";
+ }
+
+ // Add precompile headers compile options.
+ if (!pchSources.empty() && !source.GetProperty("SKIP_PRECOMPILE_HEADERS")) {
+ std::string pchOptions;
+ auto pchIt = pchSources.find(source.GetFullPath());
+ if (pchIt != pchSources.end()) {
+ pchOptions = this->GeneratorTarget->GetPchCreateCompileOptions(
+ config, lang, pchIt->second);
+ } else {
+ pchOptions =
+ this->GeneratorTarget->GetPchUseCompileOptions(config, lang);
+ }
+
+ const std::string& evaluatedFlags =
+ genexInterpreter.Evaluate(pchOptions, COMPILE_OPTIONS);
+
+ this->LocalGenerator->AppendCompileOptions(flags, evaluatedFlags);
+ *this->FlagFileStream << "# PCH options: " << relativeObj
+ << "_OPTIONS = " << evaluatedFlags << "\n"
+ << "\n";
+ }
+
+ // Add include directories from source file properties.
+ std::vector<std::string> includes;
+
+ const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
+ if (cmProp cincludes = source.GetProperty(INCLUDE_DIRECTORIES)) {
+ const std::string& evaluatedIncludes =
+ genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES);
+ this->LocalGenerator->AppendIncludeDirectories(includes, evaluatedIncludes,
+ source);
+ *this->FlagFileStream << "# Custom include directories: " << relativeObj
+ << "_INCLUDE_DIRECTORIES = " << evaluatedIncludes
+ << "\n"
+ << "\n";
+ }
+
+ // Add language-specific defines.
+ std::set<std::string> defines;
+
+ // Add source-specific preprocessor definitions.
+ const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
+ if (cmProp compile_defs = source.GetProperty(COMPILE_DEFINITIONS)) {
+ const std::string& evaluatedDefs =
+ genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS);
+ this->LocalGenerator->AppendDefines(defines, evaluatedDefs);
+ *this->FlagFileStream << "# Custom defines: " << relativeObj
+ << "_DEFINES = " << evaluatedDefs << "\n"
+ << "\n";
+ }
+ std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", configUpper);
+ if (cmProp config_compile_defs = source.GetProperty(defPropName)) {
+ const std::string& evaluatedDefs =
+ genexInterpreter.Evaluate(*config_compile_defs, COMPILE_DEFINITIONS);
+ this->LocalGenerator->AppendDefines(defines, evaluatedDefs);
+ *this->FlagFileStream << "# Custom defines: " << relativeObj << "_DEFINES_"
+ << configUpper << " = " << evaluatedDefs << "\n"
+ << "\n";
+ }
+
+ // Get the output paths for source and object files.
+ std::string sourceFile = this->LocalGenerator->ConvertToOutputFormat(
+ source.GetFullPath(), cmOutputConverter::SHELL);
+
+ // Construct the build message.
+ std::vector<std::string> no_depends;
+ std::vector<std::string> commands;
+
+ // add in a progress call if needed
+ this->NumberOfProgressActions++;
+
+ if (!this->NoRuleMessages) {
+ cmLocalUnixMakefileGenerator3::EchoProgress progress;
+ this->MakeEchoProgress(progress);
+ std::string buildEcho =
+ cmStrCat("Building ", lang, " object ", relativeObj);
+ this->LocalGenerator->AppendEcho(commands, buildEcho,
+ cmLocalUnixMakefileGenerator3::EchoBuild,
+ &progress);
+ }
+
+ std::string targetOutPathReal;
+ std::string targetOutPathPDB;
+ std::string targetOutPathCompilePDB;
+ {
+ std::string targetFullPathReal;
+ std::string targetFullPathPDB;
+ std::string targetFullPathCompilePDB =
+ this->ComputeTargetCompilePDB(this->GetConfigName());
+ if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE ||
+ this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ targetFullPathReal = this->GeneratorTarget->GetFullPath(
+ this->GetConfigName(), cmStateEnums::RuntimeBinaryArtifact, true);
+ targetFullPathPDB = cmStrCat(
+ this->GeneratorTarget->GetPDBDirectory(this->GetConfigName()), '/',
+ this->GeneratorTarget->GetPDBName(this->GetConfigName()));
+ }
+
+ targetOutPathReal = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal),
+ cmOutputConverter::SHELL);
+ targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat(
+ targetFullPathPDB, cmOutputConverter::SHELL);
+ targetOutPathCompilePDB = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ targetFullPathCompilePDB),
+ cmOutputConverter::SHELL);
+
+ if (this->LocalGenerator->IsMinGWMake() &&
+ cmHasLiteralSuffix(targetOutPathCompilePDB, "\\")) {
+ // mingw32-make incorrectly interprets 'a\ b c' as 'a b' and 'c'
+ // (but 'a\ b "c"' as 'a\', 'b', and 'c'!). Workaround this by
+ // avoiding a trailing backslash in the argument.
+ targetOutPathCompilePDB.back() = '/';
+ }
+
+ std::string compilePdbOutputPath =
+ this->GeneratorTarget->GetCompilePDBDirectory(this->GetConfigName());
+ cmSystemTools::MakeDirectory(compilePdbOutputPath);
+ }
+ cmRulePlaceholderExpander::RuleVariables vars;
+ vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
+ vars.CMTargetType =
+ cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str();
+ vars.Language = lang.c_str();
+ vars.Target = targetOutPathReal.c_str();
+ vars.TargetPDB = targetOutPathPDB.c_str();
+ vars.TargetCompilePDB = targetOutPathCompilePDB.c_str();
+ vars.Source = sourceFile.c_str();
+ std::string shellObj =
+ this->LocalGenerator->ConvertToOutputFormat(obj, cmOutputConverter::SHELL);
+ vars.Object = shellObj.c_str();
+ std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
+ objectDir = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), objectDir),
+ cmOutputConverter::SHELL);
+ vars.ObjectDir = objectDir.c_str();
+ std::string objectFileDir = cmSystemTools::GetFilenamePath(obj);
+ objectFileDir = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), objectFileDir),
+ cmOutputConverter::SHELL);
+ vars.ObjectFileDir = objectFileDir.c_str();
+ vars.Flags = flags.c_str();
+ vars.ISPCHeader = ispcHeaderForShell.c_str();
+
+ std::string definesString = cmStrCat("$(", lang, "_DEFINES)");
+
+ this->LocalGenerator->JoinDefines(defines, definesString, lang);
+
+ vars.Defines = definesString.c_str();
+
+ std::string includesString = this->LocalGenerator->GetIncludeFlags(
+ includes, this->GeneratorTarget, lang, config);
+ this->LocalGenerator->AppendFlags(includesString,
+ "$(" + lang + "_INCLUDES)");
+ vars.Includes = includesString.c_str();
+
+ std::string dependencyTarget;
+ std::string shellDependencyFile;
+ std::string dependencyTimestamp;
+ if (compilerGenerateDeps) {
+ dependencyTarget = this->LocalGenerator->EscapeForShell(
+ this->LocalGenerator->ConvertToMakefilePath(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(), relativeObj)));
+ vars.DependencyTarget = dependencyTarget.c_str();
+
+ auto depFile = cmStrCat(obj, ".d");
+ shellDependencyFile = this->LocalGenerator->ConvertToOutputFormat(
+ depFile, cmOutputConverter::SHELL);
+ vars.DependencyFile = shellDependencyFile.c_str();
+ this->CleanFiles.insert(depFile);
+
+ dependencyTimestamp = this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(),
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts"));
+ }
+
+ // At the moment, it is assumed that C, C++, Fortran, and CUDA have both
+ // assembly and preprocessor capabilities. The same is true for the
+ // ability to export compile commands
+ bool lang_has_preprocessor =
+ ((lang == "C") || (lang == "CXX") || (lang == "OBJC") ||
+ (lang == "OBJCXX") || (lang == "Fortran") || (lang == "CUDA") ||
+ lang == "ISPC" || lang == "ASM");
+ bool const lang_has_assembly = lang_has_preprocessor;
+ bool const lang_can_export_cmds = lang_has_preprocessor;
+
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->LocalGenerator->CreateRulePlaceholderExpander());
+
+ // Construct the compile rules.
+ {
+ std::vector<std::string> compileCommands;
+ if (lang == "CUDA") {
+ std::string cmdVar;
+ if (this->GeneratorTarget->GetPropertyAsBool(
+ "CUDA_SEPARABLE_COMPILATION")) {
+ cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION";
+ } else if (this->GeneratorTarget->GetPropertyAsBool(
+ "CUDA_PTX_COMPILATION")) {
+ cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION";
+ } else {
+ cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION";
+ }
+ const std::string& compileRule =
+ this->Makefile->GetRequiredDefinition(cmdVar);
+ cmExpandList(compileRule, compileCommands);
+ } else {
+ const std::string cmdVar = "CMAKE_" + lang + "_COMPILE_OBJECT";
+ const std::string& compileRule =
+ this->Makefile->GetRequiredDefinition(cmdVar);
+ cmExpandList(compileRule, compileCommands);
+ }
+
+ if (this->GeneratorTarget->GetPropertyAsBool("EXPORT_COMPILE_COMMANDS") &&
+ lang_can_export_cmds && compileCommands.size() == 1) {
+ std::string compileCommand = compileCommands[0];
+
+ // no launcher for CMAKE_EXPORT_COMPILE_COMMANDS
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+ compileCommand, vars);
+ std::string workingDirectory =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+ compileCommand.replace(compileCommand.find(langFlags), langFlags.size(),
+ this->GetFlags(lang, this->GetConfigName()));
+ std::string langDefines = std::string("$(") + lang + "_DEFINES)";
+ std::string::size_type ldPos = compileCommand.find(langDefines);
+ if (ldPos != std::string::npos) {
+ compileCommand.replace(ldPos, langDefines.size(),
+ this->GetDefines(lang, this->GetConfigName()));
+ }
+ std::string langIncludes = std::string("$(") + lang + "_INCLUDES)";
+ std::string::size_type liPos = compileCommand.find(langIncludes);
+ if (liPos != std::string::npos) {
+ compileCommand.replace(liPos, langIncludes.size(),
+ this->GetIncludes(lang, this->GetConfigName()));
+ }
+
+ cmProp eliminate[] = {
+ this->Makefile->GetDefinition("CMAKE_START_TEMP_FILE"),
+ this->Makefile->GetDefinition("CMAKE_END_TEMP_FILE")
+ };
+ for (cmProp el : eliminate) {
+ if (el) {
+ cmSystemTools::ReplaceString(compileCommand, *el, "");
+ }
+ }
+
+ this->GlobalGenerator->AddCXXCompileCommand(
+ source.GetFullPath(), workingDirectory, compileCommand);
+ }
+
+ // See if we need to use a compiler launcher like ccache or distcc
+ std::string compilerLauncher;
+ if (!compileCommands.empty() &&
+ (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA" ||
+ lang == "ISPC" || lang == "OBJC" || lang == "OBJCXX")) {
+ std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER";
+ cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
+ if (cmNonempty(clauncher)) {
+ compilerLauncher = *clauncher;
+ }
+ }
+
+ // Maybe insert an include-what-you-use runner.
+ if (!compileCommands.empty() &&
+ (lang == "C" || lang == "CXX" || lang == "OBJC" || lang == "OBJCXX")) {
+ std::string const tidy_prop = lang + "_CLANG_TIDY";
+ cmProp tidy = this->GeneratorTarget->GetProperty(tidy_prop);
+ cmProp iwyu = nullptr;
+ cmProp cpplint = nullptr;
+ cmProp cppcheck = nullptr;
+ if (lang == "C" || lang == "CXX") {
+ std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE";
+ iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
+ std::string const cpplint_prop = lang + "_CPPLINT";
+ cpplint = this->GeneratorTarget->GetProperty(cpplint_prop);
+ std::string const cppcheck_prop = lang + "_CPPCHECK";
+ cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
+ }
+ if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) ||
+ cmNonempty(cppcheck)) {
+ std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_co_compile";
+ if (!compilerLauncher.empty()) {
+ // In __run_co_compile case the launcher command is supplied
+ // via --launcher=<maybe-list> and consumed
+ run_iwyu += " --launcher=";
+ run_iwyu += this->LocalGenerator->EscapeForShell(compilerLauncher);
+ compilerLauncher.clear();
+ }
+ if (cmNonempty(iwyu)) {
+ run_iwyu += " --iwyu=";
+ run_iwyu += this->LocalGenerator->EscapeForShell(*iwyu);
+ }
+ if (cmNonempty(tidy)) {
+ run_iwyu += " --tidy=";
+ cmProp p = this->Makefile->GetDefinition("CMAKE_" + lang +
+ "_CLANG_TIDY_DRIVER_MODE");
+ std::string driverMode;
+ if (cmNonempty(p)) {
+ driverMode = *p;
+ } else {
+ driverMode = lang == "C" ? "gcc" : "g++";
+ }
+ run_iwyu += this->LocalGenerator->EscapeForShell(
+ cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode));
+ }
+ if (cmNonempty(cpplint)) {
+ run_iwyu += " --cpplint=";
+ run_iwyu += this->LocalGenerator->EscapeForShell(*cpplint);
+ }
+ if (cmNonempty(cppcheck)) {
+ run_iwyu += " --cppcheck=";
+ run_iwyu += this->LocalGenerator->EscapeForShell(*cppcheck);
+ }
+ if (cmNonempty(tidy) || (cmNonempty(cpplint)) ||
+ (cmNonempty(cppcheck))) {
+ run_iwyu += " --source=";
+ run_iwyu += sourceFile;
+ }
+ run_iwyu += " -- ";
+ compileCommands.front().insert(0, run_iwyu);
+ }
+ }
+
+ // If compiler launcher was specified and not consumed above, it
+ // goes to the beginning of the command line.
+ if (!compileCommands.empty() && !compilerLauncher.empty()) {
+ std::vector<std::string> args = cmExpandedList(compilerLauncher, true);
+ if (!args.empty()) {
+ args[0] = this->LocalGenerator->ConvertToOutputFormat(
+ args[0], cmOutputConverter::SHELL);
+ for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) {
+ i = this->LocalGenerator->EscapeForShell(i);
+ }
+ }
+ compileCommands.front().insert(0, cmJoin(args, " ") + " ");
+ }
+
+ std::string launcher;
+ {
+ cmProp val = this->LocalGenerator->GetRuleLauncher(
+ this->GeneratorTarget, "RULE_LAUNCH_COMPILE");
+ if (cmNonempty(val)) {
+ launcher = cmStrCat(*val, ' ');
+ }
+ }
+
+ std::string flagsWithDeps(flags);
+
+ if (compilerGenerateDeps) {
+ // Injects dependency computation
+ auto depFlags = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_DEPFILE_FLAGS_", lang));
+
+ if (!depFlags.empty()) {
+ // Add dependency flags
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+ depFlags, vars);
+ flagsWithDeps.append(1, ' ');
+ flagsWithDeps.append(depFlags);
+ }
+ vars.Flags = flagsWithDeps.c_str();
+
+ const auto& extraCommands = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_DEPENDS_EXTRA_COMMANDS"));
+ if (!extraCommands.empty()) {
+ auto commandList = cmExpandedList(extraCommands);
+ compileCommands.insert(compileCommands.end(), commandList.cbegin(),
+ commandList.cend());
+ }
+
+ const auto& depFormat = this->Makefile->GetRequiredDefinition(
+ cmStrCat("CMAKE_", lang, "_DEPFILE_FORMAT"));
+
+ if (depFormat == "msvc"_s) {
+ // compiler must be launched through a wrapper to pick-up dependencies
+ std::string depFilter =
+ "$(CMAKE_COMMAND) -E cmake_cl_compile_depends ";
+ depFilter += cmStrCat("--dep-file=", shellDependencyFile);
+ depFilter +=
+ cmStrCat(" --working-dir=",
+ this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ cmOutputConverter::SHELL));
+ const auto& prefix = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_CL_SHOWINCLUDES_PREFIX"));
+ depFilter += cmStrCat(" --filter-prefix=",
+ this->LocalGenerator->ConvertToOutputFormat(
+ prefix, cmOutputConverter::SHELL));
+ depFilter += " -- ";
+ compileCommands.front().insert(0, depFilter);
+ }
+ }
+
+ // Expand placeholders in the commands.
+ for (std::string& compileCommand : compileCommands) {
+ compileCommand = cmStrCat(launcher, compileCommand);
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+ compileCommand, vars);
+ }
+
+ // Change the command working directory to the local build tree.
+ this->LocalGenerator->CreateCDCommand(
+ compileCommands, this->LocalGenerator->GetCurrentBinaryDirectory(),
+ this->LocalGenerator->GetBinaryDirectory());
+ cm::append(commands, compileCommands);
+ }
+
+ // Check for extra outputs created by the compilation.
+ std::vector<std::string> outputs(1, relativeObj);
+ if (cmProp extra_outputs_str = source.GetProperty("OBJECT_OUTPUTS")) {
+ std::string evaluated_outputs = cmGeneratorExpression::Evaluate(
+ *extra_outputs_str, this->LocalGenerator, config);
+
+ if (!evaluated_outputs.empty()) {
+ // Register these as extra files to clean.
+ cmExpandList(evaluated_outputs, outputs);
+ }
+ }
+ if (!ispcHeaderRelative.empty()) {
+ // can't move ispcHeader as vars is using it
+ outputs.emplace_back(ispcHeaderRelative);
+ }
+
+ if (outputs.size() > 1) {
+ this->CleanFiles.insert(outputs.begin() + 1, outputs.end());
+ }
+
+ if (compilerGenerateDeps) {
+ depends.push_back(dependencyTimestamp);
+ }
+
+ // Write the rule.
+ this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends,
+ commands);
+
+ if (compilerGenerateDeps) {
+ // set back flags without dependency generation
+ vars.Flags = flags.c_str();
+ }
+
+ bool do_preprocess_rules = lang_has_preprocessor &&
+ this->LocalGenerator->GetCreatePreprocessedSourceRules();
+ bool do_assembly_rules =
+ lang_has_assembly && this->LocalGenerator->GetCreateAssemblySourceRules();
+ if (do_preprocess_rules || do_assembly_rules) {
+ std::vector<std::string> force_depends;
+ force_depends.emplace_back("cmake_force");
+ std::string::size_type dot_pos = relativeObj.rfind('.');
+ std::string relativeObjBase = relativeObj.substr(0, dot_pos);
+ dot_pos = obj.rfind('.');
+ std::string objBase = obj.substr(0, dot_pos);
+
+ if (do_preprocess_rules) {
+ commands.clear();
+ std::string relativeObjI = relativeObjBase + ".i";
+ std::string objI = objBase + ".i";
+
+ std::string preprocessEcho =
+ cmStrCat("Preprocessing ", lang, " source to ", objI);
+ this->LocalGenerator->AppendEcho(
+ commands, preprocessEcho, cmLocalUnixMakefileGenerator3::EchoBuild);
+
+ std::string preprocessRuleVar =
+ cmStrCat("CMAKE_", lang, "_CREATE_PREPROCESSED_SOURCE");
+ if (cmProp preprocessRule =
+ this->Makefile->GetDefinition(preprocessRuleVar)) {
+ std::vector<std::string> preprocessCommands =
+ cmExpandedList(*preprocessRule);
+
+ std::string shellObjI = this->LocalGenerator->ConvertToOutputFormat(
+ objI, cmOutputConverter::SHELL);
+ vars.PreprocessedSource = shellObjI.c_str();
+
+ // Expand placeholders in the commands.
+ for (std::string& preprocessCommand : preprocessCommands) {
+ // no launcher for preprocessor commands
+ rulePlaceholderExpander->ExpandRuleVariables(
+ this->LocalGenerator, preprocessCommand, vars);
+ }
+
+ this->LocalGenerator->CreateCDCommand(
+ preprocessCommands,
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ this->LocalGenerator->GetBinaryDirectory());
+ cm::append(commands, preprocessCommands);
+ } else {
+ std::string cmd =
+ cmStrCat("$(CMAKE_COMMAND) -E cmake_unimplemented_variable ",
+ preprocessRuleVar);
+ commands.push_back(std::move(cmd));
+ }
+
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
+ relativeObjI, force_depends,
+ commands, false);
+ }
+
+ if (do_assembly_rules) {
+ commands.clear();
+ std::string relativeObjS = relativeObjBase + ".s";
+ std::string objS = objBase + ".s";
+
+ std::string assemblyEcho =
+ cmStrCat("Compiling ", lang, " source to assembly ", objS);
+ this->LocalGenerator->AppendEcho(
+ commands, assemblyEcho, cmLocalUnixMakefileGenerator3::EchoBuild);
+
+ std::string assemblyRuleVar =
+ cmStrCat("CMAKE_", lang, "_CREATE_ASSEMBLY_SOURCE");
+ if (cmProp assemblyRule =
+ this->Makefile->GetDefinition(assemblyRuleVar)) {
+ std::vector<std::string> assemblyCommands =
+ cmExpandedList(*assemblyRule);
+
+ std::string shellObjS = this->LocalGenerator->ConvertToOutputFormat(
+ objS, cmOutputConverter::SHELL);
+ vars.AssemblySource = shellObjS.c_str();
+
+ // Expand placeholders in the commands.
+ for (std::string& assemblyCommand : assemblyCommands) {
+ // no launcher for assembly commands
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+ assemblyCommand, vars);
+ }
+
+ this->LocalGenerator->CreateCDCommand(
+ assemblyCommands, this->LocalGenerator->GetCurrentBinaryDirectory(),
+ this->LocalGenerator->GetBinaryDirectory());
+ cm::append(commands, assemblyCommands);
+ } else {
+ std::string cmd =
+ cmStrCat("$(CMAKE_COMMAND) -E cmake_unimplemented_variable ",
+ assemblyRuleVar);
+ commands.push_back(std::move(cmd));
+ }
+
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
+ relativeObjS, force_depends,
+ commands, false);
+ }
+ }
+}
+
+void cmMakefileTargetGenerator::WriteTargetCleanRules()
+{
+ std::vector<std::string> depends;
+ std::vector<std::string> commands;
+
+ // Construct the clean target name.
+ std::string cleanTarget = cmStrCat(
+ this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget),
+ "/clean");
+
+ // Construct the clean command.
+ this->LocalGenerator->AppendCleanCommand(commands, this->CleanFiles,
+ this->GeneratorTarget);
+ this->LocalGenerator->CreateCDCommand(
+ commands, this->LocalGenerator->GetCurrentBinaryDirectory(),
+ this->LocalGenerator->GetBinaryDirectory());
+
+ // Write the rule.
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
+ cleanTarget, depends, commands, true);
+}
+
+bool cmMakefileTargetGenerator::WriteMakeRule(
+ std::ostream& os, const char* comment,
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& depends,
+ const std::vector<std::string>& commands, bool in_help)
+{
+ bool symbolic = false;
+ if (outputs.empty()) {
+ return symbolic;
+ }
+
+ // Check whether we need to bother checking for a symbolic output.
+ bool need_symbolic = this->GlobalGenerator->GetNeedSymbolicMark();
+
+ // Check whether the first output is marked as symbolic.
+ if (need_symbolic) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(outputs[0])) {
+ symbolic = sf->GetPropertyAsBool("SYMBOLIC");
+ }
+ }
+
+ // We always attach the actual commands to the first output.
+ this->LocalGenerator->WriteMakeRule(os, comment, outputs[0], depends,
+ commands, symbolic, in_help);
+
+ // For single outputs, we are done.
+ if (outputs.size() == 1) {
+ return symbolic;
+ }
+
+ // For multiple outputs, make the extra ones depend on the first one.
+ std::vector<std::string> const output_depends(1, outputs[0]);
+ std::string binDir = this->LocalGenerator->GetBinaryDirectory();
+ for (std::string const& output : cmMakeRange(outputs).advance(1)) {
+ // Touch the extra output so "make" knows that it was updated,
+ // but only if the output was actually created.
+ std::string const out = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(binDir, output),
+ cmOutputConverter::SHELL);
+ std::vector<std::string> output_commands;
+
+ bool o_symbolic = false;
+ if (need_symbolic) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(output)) {
+ o_symbolic = sf->GetPropertyAsBool("SYMBOLIC");
+ }
+ }
+ symbolic = symbolic && o_symbolic;
+
+ if (!o_symbolic) {
+ output_commands.push_back("@$(CMAKE_COMMAND) -E touch_nocreate " + out);
+ }
+ this->LocalGenerator->WriteMakeRule(os, nullptr, output, output_depends,
+ output_commands, o_symbolic, in_help);
+
+ if (!o_symbolic) {
+ // At build time, remove the first output if this one does not exist
+ // so that "make" will rerun the real commands that create this one.
+ MultipleOutputPairsType::value_type p(output, outputs[0]);
+ this->MultipleOutputPairs.insert(p);
+ }
+ }
+ return symbolic;
+}
+
+void cmMakefileTargetGenerator::WriteTargetDependRules()
+{
+ // must write the targets depend info file
+ std::string dir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ this->InfoFileNameFull = cmStrCat(dir, "/DependInfo.cmake");
+ this->InfoFileNameFull =
+ this->LocalGenerator->ConvertToFullPath(this->InfoFileNameFull);
+ this->InfoFileStream =
+ cm::make_unique<cmGeneratedFileStream>(this->InfoFileNameFull);
+ if (!this->InfoFileStream) {
+ return;
+ }
+ this->InfoFileStream->SetCopyIfDifferent(true);
+ this->LocalGenerator->WriteDependLanguageInfo(*this->InfoFileStream,
+ this->GeneratorTarget);
+
+ // Store multiple output pairs in the depend info file.
+ if (!this->MultipleOutputPairs.empty()) {
+ /* clang-format off */
+ *this->InfoFileStream
+ << "\n"
+ << "# Pairs of files generated by the same build rule.\n"
+ << "set(CMAKE_MULTIPLE_OUTPUT_PAIRS\n";
+ /* clang-format on */
+ for (auto const& pi : this->MultipleOutputPairs) {
+ *this->InfoFileStream
+ << " " << cmOutputConverter::EscapeForCMake(pi.first) << " "
+ << cmOutputConverter::EscapeForCMake(pi.second) << "\n";
+ }
+ *this->InfoFileStream << " )\n\n";
+ }
+
+ // Store list of targets linked directly or transitively.
+ {
+ /* clang-format off */
+ *this->InfoFileStream
+ << "\n"
+ << "# Targets to which this target links.\n"
+ << "set(CMAKE_TARGET_LINKED_INFO_FILES\n";
+ /* clang-format on */
+ std::vector<std::string> dirs =
+ this->GetLinkedTargetDirectories(this->GetConfigName());
+ for (std::string const& d : dirs) {
+ *this->InfoFileStream << " \"" << d << "/DependInfo.cmake\"\n";
+ }
+ *this->InfoFileStream << " )\n";
+ }
+
+ std::string const& working_dir =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+
+ /* clang-format off */
+ *this->InfoFileStream
+ << "\n"
+ << "# Fortran module output directory.\n"
+ << "set(CMAKE_Fortran_TARGET_MODULE_DIR \""
+ << this->GeneratorTarget->GetFortranModuleDirectory(working_dir)
+ << "\")\n";
+ /* clang-format on */
+
+ // and now write the rule to use it
+ std::vector<std::string> depends;
+ std::vector<std::string> commands;
+
+ // Construct the name of the dependency generation target.
+ std::string depTarget = cmStrCat(
+ this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget),
+ "/depend");
+
+ // Add a command to call CMake to scan dependencies. CMake will
+ // touch the corresponding depends file after scanning dependencies.
+ std::ostringstream depCmd;
+// TODO: Account for source file properties and directory-level
+// definitions when scanning for dependencies.
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ // This platform supports symlinks, so cmSystemTools will translate
+ // paths. Make sure PWD is set to the original name of the home
+ // output directory to help cmSystemTools to create the same
+ // translation table for the dependency scanning process.
+ depCmd << "cd "
+ << (this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->GetBinaryDirectory(),
+ cmOutputConverter::SHELL))
+ << " && ";
+#endif
+ // Generate a call this signature:
+ //
+ // cmake -E cmake_depends <generator>
+ // <home-src-dir> <start-src-dir>
+ // <home-out-dir> <start-out-dir>
+ // <dep-info> --color=$(COLOR)
+ //
+ // This gives the dependency scanner enough information to recreate
+ // the state of our local generator sufficiently for its needs.
+ depCmd << "$(CMAKE_COMMAND) -E cmake_depends \""
+ << this->GlobalGenerator->GetName() << "\" "
+ << this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->GetSourceDirectory(),
+ cmOutputConverter::SHELL)
+ << " "
+ << this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->GetCurrentSourceDirectory(),
+ cmOutputConverter::SHELL)
+ << " "
+ << this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->GetBinaryDirectory(),
+ cmOutputConverter::SHELL)
+ << " "
+ << this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ cmOutputConverter::SHELL)
+ << " "
+ << this->LocalGenerator->ConvertToOutputFormat(
+ cmSystemTools::CollapseFullPath(this->InfoFileNameFull),
+ cmOutputConverter::SHELL);
+ if (this->LocalGenerator->GetColorMakefile()) {
+ depCmd << " --color=$(COLOR)";
+ }
+ commands.push_back(depCmd.str());
+
+ // Make sure all custom command outputs in this target are built.
+ if (this->CustomCommandDriver == OnDepends) {
+ this->DriveCustomCommands(depends);
+ }
+
+ // Write the rule.
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
+ depTarget, depends, commands, true);
+}
+
+void cmMakefileTargetGenerator::DriveCustomCommands(
+ std::vector<std::string>& depends)
+{
+ // Depend on all custom command outputs.
+ cm::append(depends, this->CustomCommandOutputs);
+}
+
+void cmMakefileTargetGenerator::WriteObjectDependRules(
+ cmSourceFile const& source, std::vector<std::string>& depends)
+{
+ // Create the list of dependencies known at cmake time. These are
+ // shared between the object file and dependency scanning rule.
+ depends.push_back(source.GetFullPath());
+ if (cmProp objectDeps = source.GetProperty("OBJECT_DEPENDS")) {
+ cmExpandList(*objectDeps, depends);
+ }
+}
+
+void cmMakefileTargetGenerator::WriteDeviceLinkRule(
+ std::vector<std::string>& commands, const std::string& output)
+{
+ std::string architecturesStr =
+ this->GeneratorTarget->GetSafeProperty("CUDA_ARCHITECTURES");
+
+ if (cmIsOff(architecturesStr)) {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ "CUDA_SEPARABLE_COMPILATION on Clang "
+ "requires CUDA_ARCHITECTURES to be set.");
+ return;
+ }
+
+ std::vector<std::string> architectures = cmExpandedList(architecturesStr);
+
+ // Ensure there are no duplicates.
+ const std::vector<std::string> linkDeps = [&]() -> std::vector<std::string> {
+ std::vector<std::string> deps;
+ this->AppendTargetDepends(deps, true);
+ this->GeneratorTarget->GetLinkDepends(deps, this->GetConfigName(), "CUDA");
+ std::copy(this->Objects.begin(), this->Objects.end(),
+ std::back_inserter(deps));
+
+ std::unordered_set<std::string> depsSet(deps.begin(), deps.end());
+ deps.clear();
+ std::copy(depsSet.begin(), depsSet.end(), std::back_inserter(deps));
+ return deps;
+ }();
+
+ const std::string objectDir = this->GeneratorTarget->ObjectDirectory;
+ const std::string relObjectDir =
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), objectDir);
+
+ // Construct a list of files associated with this executable that
+ // may need to be cleaned.
+ std::vector<std::string> cleanFiles;
+ cleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), output));
+
+ std::string profiles;
+ std::vector<std::string> fatbinaryDepends;
+ std::string registerFile = cmStrCat(objectDir, "cmake_cuda_register.h");
+
+ // Link device code for each architecture.
+ for (const std::string& architectureKind : architectures) {
+ // Clang always generates real code, so strip the specifier.
+ const std::string architecture =
+ architectureKind.substr(0, architectureKind.find('-'));
+ const std::string cubin =
+ cmStrCat(relObjectDir, "sm_", architecture, ".cubin");
+
+ profiles += cmStrCat(" -im=profile=sm_", architecture, ",file=", cubin);
+ fatbinaryDepends.emplace_back(cubin);
+
+ std::string registerFileCmd;
+
+ // The generated register file contains macros that when expanded
+ // register the device routines. Because the routines are the same for
+ // all architectures the register file will be the same too. Thus
+ // generate it only on the first invocation to reduce overhead.
+ if (fatbinaryDepends.size() == 1) {
+ std::string registerFileRel =
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), registerFile);
+ registerFileCmd =
+ cmStrCat(" --register-link-binaries=", registerFileRel);
+ cleanFiles.push_back(registerFileRel);
+ }
+
+ std::string command = cmStrCat(
+ this->Makefile->GetRequiredDefinition("CMAKE_CUDA_DEVICE_LINKER"),
+ " -arch=sm_", architecture, registerFileCmd, " -o=$@ ",
+ cmJoin(linkDeps, " "));
+
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, cubin,
+ linkDeps, { command }, false);
+ }
+
+ // Combine all architectures into a single fatbinary.
+ const std::string fatbinaryCommand =
+ cmStrCat(this->Makefile->GetRequiredDefinition("CMAKE_CUDA_FATBINARY"),
+ " -64 -cmdline=--compile-only -compress-all -link "
+ "--embedded-fatbin=$@",
+ profiles);
+ const std::string fatbinaryOutput =
+ cmStrCat(objectDir, "cmake_cuda_fatbin.h");
+ const std::string fatbinaryOutputRel =
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), fatbinaryOutput);
+
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
+ fatbinaryOutputRel, fatbinaryDepends,
+ { fatbinaryCommand }, false);
+
+ // Compile the stub that registers the kernels and contains the
+ // fatbinaries.
+ cmRulePlaceholderExpander::RuleVariables vars;
+ vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
+ vars.CMTargetType =
+ cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()).c_str();
+
+ vars.Language = "CUDA";
+ vars.Object = output.c_str();
+ vars.Fatbinary = fatbinaryOutput.c_str();
+ vars.RegisterFile = registerFile.c_str();
+
+ std::string flags = this->GetFlags("CUDA", this->GetConfigName());
+ vars.Flags = flags.c_str();
+
+ std::string compileCmd = this->GetLinkRule("CMAKE_CUDA_DEVICE_LINK_COMPILE");
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->LocalGenerator->CreateRulePlaceholderExpander());
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+ compileCmd, vars);
+
+ commands.emplace_back(compileCmd);
+ this->LocalGenerator->WriteMakeRule(
+ *this->BuildFileStream, nullptr, output,
+ { cmStrCat(relObjectDir, "cmake_cuda_fatbin.h") }, commands, false);
+
+ // Clean all the possible executable names and symlinks.
+ this->CleanFiles.insert(cleanFiles.begin(), cleanFiles.end());
+}
+
+void cmMakefileTargetGenerator::GenerateCustomRuleFile(
+ cmCustomCommandGenerator const& ccg)
+{
+ // Collect the commands.
+ std::vector<std::string> commands;
+ std::string comment = this->LocalGenerator->ConstructComment(ccg);
+ if (!comment.empty()) {
+ // add in a progress call if needed
+ this->NumberOfProgressActions++;
+ if (!this->NoRuleMessages) {
+ cmLocalUnixMakefileGenerator3::EchoProgress progress;
+ this->MakeEchoProgress(progress);
+ this->LocalGenerator->AppendEcho(
+ commands, comment, cmLocalUnixMakefileGenerator3::EchoGenerate,
+ &progress);
+ }
+ }
+
+ // Now append the actual user-specified commands.
+ std::ostringstream content;
+ this->LocalGenerator->AppendCustomCommand(
+ commands, ccg, this->GeneratorTarget,
+ this->LocalGenerator->GetBinaryDirectory(), false, &content);
+
+ // Collect the dependencies.
+ std::vector<std::string> depends;
+ this->LocalGenerator->AppendCustomDepend(depends, ccg);
+
+ if (!ccg.GetCC().GetDepfile().empty()) {
+ // Add dependency over timestamp file for dependencies management
+ auto dependTimestamp = cmSystemTools::ConvertToOutputPath(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(),
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts")));
+
+ depends.push_back(dependTimestamp);
+ }
+
+ // Write the rule.
+ const std::vector<std::string>& outputs = ccg.GetOutputs();
+ bool symbolic = this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs,
+ depends, commands);
+
+ // Symbolic inputs are not expected to exist, so add dummy rules.
+ if (this->CMP0113New && !depends.empty()) {
+ std::vector<std::string> no_depends;
+ std::vector<std::string> no_commands;
+ for (std::string const& dep : depends) {
+ if (cmSourceFile* dsf =
+ this->Makefile->GetSource(dep, cmSourceFileLocationKind::Known)) {
+ if (dsf->GetPropertyAsBool("SYMBOLIC")) {
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
+ dep, no_depends, no_commands,
+ true);
+ }
+ }
+ }
+ }
+
+ // If the rule has changed make sure the output is rebuilt.
+ if (!symbolic) {
+ this->GlobalGenerator->AddRuleHash(ccg.GetOutputs(), content.str());
+ }
+
+ // Setup implicit dependency scanning.
+ for (auto const& idi : ccg.GetCC().GetImplicitDepends()) {
+ std::string objFullPath = cmSystemTools::CollapseFullPath(
+ outputs[0], this->LocalGenerator->GetCurrentBinaryDirectory());
+ std::string srcFullPath = cmSystemTools::CollapseFullPath(
+ idi.second, this->LocalGenerator->GetCurrentBinaryDirectory());
+ this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, idi.first,
+ objFullPath, srcFullPath);
+ }
+
+ // Setup implicit depend for depfile if any
+ if (!ccg.GetCC().GetDepfile().empty()) {
+ std::string objFullPath = cmSystemTools::CollapseFullPath(
+ outputs[0], this->LocalGenerator->GetCurrentBinaryDirectory());
+ this->LocalGenerator->AddImplicitDepends(
+ this->GeneratorTarget, "CUSTOM", objFullPath, ccg.GetFullDepfile(),
+ cmDependencyScannerKind::Compiler);
+ }
+
+ this->CustomCommandOutputs.insert(outputs.begin(), outputs.end());
+}
+
+void cmMakefileTargetGenerator::MakeEchoProgress(
+ cmLocalUnixMakefileGenerator3::EchoProgress& progress) const
+{
+ progress.Dir =
+ cmStrCat(this->LocalGenerator->GetBinaryDirectory(), "/CMakeFiles");
+ std::ostringstream progressArg;
+ progressArg << "$(CMAKE_PROGRESS_" << this->NumberOfProgressActions << ")";
+ progress.Arg = progressArg.str();
+}
+
+void cmMakefileTargetGenerator::WriteObjectsVariable(
+ std::string& variableName, std::string& variableNameExternal,
+ bool useWatcomQuote)
+{
+ // Write a make variable assignment that lists all objects for the
+ // target.
+ variableName = this->LocalGenerator->CreateMakeVariable(
+ this->GeneratorTarget->GetName(), "_OBJECTS");
+ *this->BuildFileStream << "# Object files for target "
+ << this->GeneratorTarget->GetName() << "\n"
+ << variableName << " =";
+ std::string object;
+ const auto& lineContinue = this->GlobalGenerator->LineContinueDirective;
+
+ cmProp pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
+
+ for (std::string const& obj : this->Objects) {
+ if (cmSystemTools::StringEndsWith(obj, cmToCStr(pchExtension))) {
+ continue;
+ }
+ *this->BuildFileStream << " " << lineContinue;
+ *this->BuildFileStream
+ << cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath(
+ obj, useWatcomQuote);
+ }
+ *this->BuildFileStream << "\n";
+
+ // Write a make variable assignment that lists all external objects
+ // for the target.
+ variableNameExternal = this->LocalGenerator->CreateMakeVariable(
+ this->GeneratorTarget->GetName(), "_EXTERNAL_OBJECTS");
+ /* clang-format off */
+ *this->BuildFileStream
+ << "\n"
+ << "# External object files for target "
+ << this->GeneratorTarget->GetName() << "\n"
+ << variableNameExternal << " =";
+ /* clang-format on */
+ std::string currentBinDir =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+ for (std::string const& obj : this->ExternalObjects) {
+ object =
+ this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir, obj);
+ *this->BuildFileStream << " " << lineContinue;
+ *this->BuildFileStream
+ << cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath(
+ obj, useWatcomQuote);
+ }
+ *this->BuildFileStream << "\n"
+ << "\n";
+}
+
+class cmMakefileTargetGeneratorObjectStrings
+{
+public:
+ cmMakefileTargetGeneratorObjectStrings(std::vector<std::string>& strings,
+ cmOutputConverter* outputConverter,
+ cmStateDirectory const& stateDir,
+ std::string::size_type limit)
+ : Strings(strings)
+ , OutputConverter(outputConverter)
+ , StateDir(stateDir)
+ , LengthLimit(limit)
+ {
+ this->Space = "";
+ }
+ void Feed(std::string const& obj)
+ {
+ // Construct the name of the next object.
+ this->NextObject = this->OutputConverter->ConvertToOutputFormat(
+ this->MaybeConvertToRelativePath(obj), cmOutputConverter::RESPONSE);
+
+ // Roll over to next string if the limit will be exceeded.
+ if (this->LengthLimit != std::string::npos &&
+ (this->CurrentString.length() + 1 + this->NextObject.length() >
+ this->LengthLimit)) {
+ this->Strings.push_back(this->CurrentString);
+ this->CurrentString.clear();
+ this->Space = "";
+ }
+
+ // Separate from previous object.
+ this->CurrentString += this->Space;
+ this->Space = " ";
+
+ // Append this object.
+ this->CurrentString += this->NextObject;
+ }
+ void Done() { this->Strings.push_back(this->CurrentString); }
+
+private:
+ std::string MaybeConvertToRelativePath(std::string const& obj)
+ {
+ if (!this->StateDir.ContainsBoth(this->StateDir.GetCurrentBinary(), obj)) {
+ return obj;
+ }
+ return cmSystemTools::ForceToRelativePath(
+ this->StateDir.GetCurrentBinary(), obj);
+ }
+
+ std::vector<std::string>& Strings;
+ cmOutputConverter* OutputConverter;
+ cmStateDirectory StateDir;
+ std::string::size_type LengthLimit;
+ std::string CurrentString;
+ std::string NextObject;
+ const char* Space;
+};
+
+void cmMakefileTargetGenerator::WriteObjectsStrings(
+ std::vector<std::string>& objStrings, std::string::size_type limit)
+{
+ cmProp pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
+
+ cmMakefileTargetGeneratorObjectStrings helper(
+ objStrings, this->LocalGenerator,
+ this->LocalGenerator->GetStateSnapshot().GetDirectory(), limit);
+ for (std::string const& obj : this->Objects) {
+ if (cmSystemTools::StringEndsWith(obj, cmToCStr(pchExtension))) {
+ continue;
+ }
+ helper.Feed(obj);
+ }
+ for (std::string const& obj : this->ExternalObjects) {
+ helper.Feed(obj);
+ }
+ auto ispcAdditionalObjs =
+ this->GeneratorTarget->GetGeneratedISPCObjects(this->GetConfigName());
+ for (std::string const& obj : ispcAdditionalObjs) {
+ helper.Feed(obj);
+ }
+ helper.Done();
+}
+
+void cmMakefileTargetGenerator::WriteTargetDriverRule(
+ const std::string& main_output, bool relink)
+{
+ // Compute the name of the driver target.
+ std::string dir =
+ this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget);
+ std::string buildTargetRuleName =
+ cmStrCat(dir, relink ? "/preinstall" : "/build");
+ buildTargetRuleName = this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(), buildTargetRuleName);
+
+ // Build the list of target outputs to drive.
+ std::vector<std::string> depends;
+ depends.push_back(main_output);
+
+ const char* comment = nullptr;
+ if (relink) {
+ // Setup the comment for the preinstall driver.
+ comment = "Rule to relink during preinstall.";
+ } else {
+ // Setup the comment for the main build driver.
+ comment = "Rule to build all files generated by this target.";
+
+ // Make sure all custom command outputs in this target are built.
+ if (this->CustomCommandDriver == OnBuild) {
+ this->DriveCustomCommands(depends);
+ }
+
+ // Make sure the extra files are built.
+ cm::append(depends, this->ExtraFiles);
+ }
+
+ // Write the driver rule.
+ std::vector<std::string> no_commands;
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, comment,
+ buildTargetRuleName, depends,
+ no_commands, true);
+}
+
+void cmMakefileTargetGenerator::AppendTargetDepends(
+ std::vector<std::string>& depends, bool ignoreType)
+{
+ // Static libraries never depend on anything for linking.
+ if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY &&
+ !ignoreType) {
+ return;
+ }
+
+ // Loop over all library dependencies.
+ const std::string& cfg = this->GetConfigName();
+ if (cmComputeLinkInformation* cli =
+ this->GeneratorTarget->GetLinkInformation(cfg)) {
+ cm::append(depends, cli->GetDepends());
+ }
+}
+
+void cmMakefileTargetGenerator::AppendObjectDepends(
+ std::vector<std::string>& depends)
+{
+ // Add dependencies on the compiled object files.
+ std::string const& relPath =
+ this->LocalGenerator->GetHomeRelativeOutputPath();
+ for (std::string const& obj : this->Objects) {
+ std::string objTarget = cmStrCat(relPath, obj);
+ depends.push_back(std::move(objTarget));
+ }
+
+ // Add dependencies on the external object files.
+ cm::append(depends, this->ExternalObjects);
+
+ // Add a dependency on the rule file itself.
+ this->LocalGenerator->AppendRuleDepend(depends,
+ this->BuildFileNameFull.c_str());
+}
+
+void cmMakefileTargetGenerator::AppendLinkDepends(
+ std::vector<std::string>& depends, const std::string& linkLanguage)
+{
+ this->AppendObjectDepends(depends);
+
+ // Add dependencies on targets that must be built first.
+ this->AppendTargetDepends(depends);
+
+ // Add a dependency on the link definitions file, if any.
+ if (cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
+ this->GeneratorTarget->GetModuleDefinitionInfo(
+ this->GetConfigName())) {
+ for (cmSourceFile const* src : mdi->Sources) {
+ depends.push_back(src->GetFullPath());
+ }
+ }
+
+ // Add a dependency on user-specified manifest files, if any.
+ std::vector<cmSourceFile const*> manifest_srcs;
+ this->GeneratorTarget->GetManifests(manifest_srcs, this->GetConfigName());
+ for (cmSourceFile const* manifest_src : manifest_srcs) {
+ depends.push_back(manifest_src->GetFullPath());
+ }
+
+ // Add user-specified dependencies.
+ this->GeneratorTarget->GetLinkDepends(depends, this->GetConfigName(),
+ linkLanguage);
+}
+
+std::string cmMakefileTargetGenerator::GetLinkRule(
+ const std::string& linkRuleVar)
+{
+ std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar);
+ if (this->GeneratorTarget->HasImplibGNUtoMS(this->GetConfigName())) {
+ std::string ruleVar =
+ cmStrCat("CMAKE_",
+ this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()),
+ "_GNUtoMS_RULE");
+ if (cmProp rule = this->Makefile->GetDefinition(ruleVar)) {
+ linkRule += *rule;
+ }
+ }
+ return linkRule;
+}
+
+void cmMakefileTargetGenerator::CloseFileStreams()
+{
+ this->BuildFileStream.reset();
+ this->InfoFileStream.reset();
+ this->FlagFileStream.reset();
+}
+
+void cmMakefileTargetGenerator::CreateLinkScript(
+ const char* name, std::vector<std::string> const& link_commands,
+ std::vector<std::string>& makefile_commands,
+ std::vector<std::string>& makefile_depends)
+{
+ // Create the link script file.
+ std::string linkScriptName =
+ cmStrCat(this->TargetBuildDirectoryFull, '/', name);
+ cmGeneratedFileStream linkScriptStream(linkScriptName);
+ linkScriptStream.SetCopyIfDifferent(true);
+ for (std::string const& link_command : link_commands) {
+ // Do not write out empty commands or commands beginning in the
+ // shell no-op ":".
+ if (!link_command.empty() && link_command[0] != ':') {
+ linkScriptStream << link_command << "\n";
+ }
+ }
+
+ // Create the makefile command to invoke the link script.
+ std::string link_command = cmStrCat(
+ "$(CMAKE_COMMAND) -E cmake_link_script ",
+ this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), linkScriptName),
+ cmOutputConverter::SHELL),
+ " --verbose=$(VERBOSE)");
+ makefile_commands.push_back(std::move(link_command));
+ makefile_depends.push_back(std::move(linkScriptName));
+}
+
+bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects(
+ std::string const& l) const
+{
+ // Check for an explicit setting one way or the other.
+ std::string const responseVar =
+ "CMAKE_" + l + "_USE_RESPONSE_FILE_FOR_OBJECTS";
+ if (cmProp val = this->Makefile->GetDefinition(responseVar)) {
+ if (!val->empty()) {
+ return cmIsOn(val);
+ }
+ }
+
+ // Check for a system limit.
+ if (size_t const limit = cmSystemTools::CalculateCommandLineLengthLimit()) {
+ // Compute the total length of our list of object files with room
+ // for argument separation and quoting. This does not convert paths
+ // relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so
+ // the actual list will likely be much shorter than this. However, in
+ // the worst case all objects will remain as absolute paths.
+ size_t length = 0;
+ for (std::string const& obj : this->Objects) {
+ length += obj.size() + 3;
+ }
+ for (std::string const& ext_obj : this->ExternalObjects) {
+ length += ext_obj.size() + 3;
+ }
+
+ // We need to guarantee room for both objects and libraries, so
+ // if the objects take up more than half then use a response file
+ // for them.
+ if (length > (limit / 2)) {
+ return true;
+ }
+ }
+
+ // We do not need a response file for objects.
+ return false;
+}
+
+bool cmMakefileTargetGenerator::CheckUseResponseFileForLibraries(
+ std::string const& l) const
+{
+ // Check for an explicit setting one way or the other.
+ std::string const responseVar =
+ "CMAKE_" + l + "_USE_RESPONSE_FILE_FOR_LIBRARIES";
+ if (cmProp val = this->Makefile->GetDefinition(responseVar)) {
+ if (!val->empty()) {
+ return cmIsOn(val);
+ }
+ }
+
+ // We do not need a response file for libraries.
+ return false;
+}
+
+std::string cmMakefileTargetGenerator::CreateResponseFile(
+ const char* name, std::string const& options,
+ std::vector<std::string>& makefile_depends)
+{
+ // Create the response file.
+ std::string responseFileNameFull =
+ cmStrCat(this->TargetBuildDirectoryFull, '/', name);
+ cmGeneratedFileStream responseStream(responseFileNameFull);
+ responseStream.SetCopyIfDifferent(true);
+ responseStream << options << "\n";
+
+ // Add a dependency so the target will rebuild when the set of
+ // objects changes.
+ makefile_depends.push_back(std::move(responseFileNameFull));
+
+ // Construct the name to be used on the command line.
+ std::string responseFileName =
+ cmStrCat(this->TargetBuildDirectory, '/', name);
+ return responseFileName;
+}
+
+std::unique_ptr<cmLinkLineComputer>
+cmMakefileTargetGenerator::CreateLinkLineComputer(
+ cmOutputConverter* outputConverter, cmStateDirectory const& stateDir)
+{
+ if (this->Makefile->IsOn("MSVC60")) {
+ return this->GlobalGenerator->CreateMSVC60LinkLineComputer(outputConverter,
+ stateDir);
+ }
+ return this->GlobalGenerator->CreateLinkLineComputer(outputConverter,
+ stateDir);
+}
+
+void cmMakefileTargetGenerator::CreateLinkLibs(
+ cmLinkLineComputer* linkLineComputer, std::string& linkLibs,
+ bool useResponseFile, std::vector<std::string>& makefile_depends)
+{
+ std::string frameworkPath;
+ std::string linkPath;
+ cmComputeLinkInformation* pcli =
+ this->GeneratorTarget->GetLinkInformation(this->GetConfigName());
+ this->LocalGenerator->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
+ frameworkPath, linkPath);
+ linkLibs = frameworkPath + linkPath + linkLibs;
+
+ if (useResponseFile &&
+ linkLibs.find_first_not_of(' ') != std::string::npos) {
+ // Lookup the response file reference flag.
+ std::string responseFlagVar =
+ cmStrCat("CMAKE_",
+ this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()),
+ "_RESPONSE_FILE_LINK_FLAG");
+ std::string responseFlag;
+ if (cmProp p = this->Makefile->GetDefinition(responseFlagVar)) {
+ responseFlag = *p;
+ } else {
+ responseFlag = "@";
+ }
+
+ // Create this response file.
+ std::string link_rsp =
+ this->CreateResponseFile("linklibs.rsp", linkLibs, makefile_depends);
+
+ // Reference the response file.
+ linkLibs = cmStrCat(responseFlag,
+ this->LocalGenerator->ConvertToOutputFormat(
+ link_rsp, cmOutputConverter::SHELL));
+ }
+}
+
+void cmMakefileTargetGenerator::CreateObjectLists(
+ bool useLinkScript, bool useArchiveRules, bool useResponseFile,
+ std::string& buildObjs, std::vector<std::string>& makefile_depends,
+ bool useWatcomQuote)
+{
+ std::string variableName;
+ std::string variableNameExternal;
+ this->WriteObjectsVariable(variableName, variableNameExternal,
+ useWatcomQuote);
+ if (useResponseFile) {
+ // MSVC response files cannot exceed 128K.
+ std::string::size_type const responseFileLimit = 131000;
+
+ // Construct the individual object list strings.
+ std::vector<std::string> object_strings;
+ this->WriteObjectsStrings(object_strings, responseFileLimit);
+
+ // Lookup the response file reference flag.
+ std::string responseFlagVar =
+ cmStrCat("CMAKE_",
+ this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()),
+ "_RESPONSE_FILE_LINK_FLAG");
+ std::string responseFlag;
+ if (cmProp p = this->Makefile->GetDefinition(responseFlagVar)) {
+ responseFlag = *p;
+ } else {
+ responseFlag = "@";
+ }
+
+ // Write a response file for each string.
+ const char* sep = "";
+ for (unsigned int i = 0; i < object_strings.size(); ++i) {
+ // Number the response files.
+ char rsp[32];
+ sprintf(rsp, "objects%u.rsp", i + 1);
+
+ // Create this response file.
+ std::string objects_rsp =
+ this->CreateResponseFile(rsp, object_strings[i], makefile_depends);
+
+ // Separate from previous response file references.
+ buildObjs += sep;
+ sep = " ";
+
+ // Reference the response file.
+ buildObjs += responseFlag;
+ buildObjs += this->LocalGenerator->ConvertToOutputFormat(
+ objects_rsp, cmOutputConverter::SHELL);
+ }
+ } else if (useLinkScript) {
+ if (!useArchiveRules) {
+ std::vector<std::string> objStrings;
+ this->WriteObjectsStrings(objStrings);
+ buildObjs = objStrings[0];
+ }
+ } else {
+ buildObjs =
+ cmStrCat("$(", variableName, ") $(", variableNameExternal, ')');
+ }
+}
+
+void cmMakefileTargetGenerator::AddIncludeFlags(std::string& flags,
+ const std::string& lang,
+ const std::string& /*config*/)
+{
+ std::string responseVar =
+ cmStrCat("CMAKE_", lang, "_USE_RESPONSE_FILE_FOR_INCLUDES");
+ bool useResponseFile = this->Makefile->IsOn(responseVar);
+
+ std::vector<std::string> includes;
+ this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
+ lang, this->GetConfigName());
+
+ std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
+ includes, this->GeneratorTarget, lang, this->GetConfigName(),
+ useResponseFile);
+ if (includeFlags.empty()) {
+ return;
+ }
+
+ if (useResponseFile) {
+ std::string const responseFlagVar =
+ "CMAKE_" + lang + "_RESPONSE_FILE_FLAG";
+ std::string responseFlag =
+ this->Makefile->GetSafeDefinition(responseFlagVar);
+ if (responseFlag.empty()) {
+ responseFlag = "@";
+ }
+ std::string name = cmStrCat("includes_", lang, ".rsp");
+ std::string arg = std::move(responseFlag) +
+ this->CreateResponseFile(name.c_str(), includeFlags,
+ this->FlagFileDepends[lang]);
+ this->LocalGenerator->AppendFlags(flags, arg);
+ } else {
+ this->LocalGenerator->AppendFlags(flags, includeFlags);
+ }
+}
+
+void cmMakefileTargetGenerator::GenDefFile(
+ std::vector<std::string>& real_link_commands)
+{
+ cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
+ this->GeneratorTarget->GetModuleDefinitionInfo(this->GetConfigName());
+ if (!mdi || !mdi->DefFileGenerated) {
+ return;
+ }
+ std::string cmd = cmSystemTools::GetCMakeCommand();
+ cmd = cmStrCat(
+ this->LocalGenerator->ConvertToOutputFormat(cmd, cmOutputConverter::SHELL),
+ " -E __create_def ",
+ this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), mdi->DefFile),
+ cmOutputConverter::SHELL),
+ ' ');
+ std::string objlist_file = mdi->DefFile + ".objs";
+ cmd += this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), objlist_file),
+ cmOutputConverter::SHELL);
+ cmProp nm_executable = this->Makefile->GetDefinition("CMAKE_NM");
+ if (cmNonempty(nm_executable)) {
+ cmd += " --nm=";
+ cmd += this->LocalCommonGenerator->ConvertToOutputFormat(
+ *nm_executable, cmOutputConverter::SHELL);
+ }
+ real_link_commands.insert(real_link_commands.begin(), cmd);
+ // create a list of obj files for the -E __create_def to read
+ cmGeneratedFileStream fout(objlist_file);
+
+ if (mdi->WindowsExportAllSymbols) {
+ for (std::string const& obj : this->Objects) {
+ if (cmHasLiteralSuffix(obj, ".obj")) {
+ fout << obj << "\n";
+ }
+ }
+ for (std::string const& obj : this->ExternalObjects) {
+ fout << obj << "\n";
+ }
+ }
+
+ for (cmSourceFile const* src : mdi->Sources) {
+ fout << src->GetFullPath() << "\n";
+ }
+}
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
new file mode 100644
index 0000000..cb804e0
--- /dev/null
+++ b/Source/cmMakefileTargetGenerator.h
@@ -0,0 +1,256 @@
+/* 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 <iosfwd>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmCommonTargetGenerator.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmOSXBundleGenerator.h"
+
+class cmCustomCommandGenerator;
+class cmGeneratedFileStream;
+class cmGlobalUnixMakefileGenerator3;
+class cmLinkLineComputer;
+class cmOutputConverter;
+class cmSourceFile;
+class cmStateDirectory;
+
+/** \class cmMakefileTargetGenerator
+ * \brief Support Routines for writing makefiles
+ *
+ */
+class cmMakefileTargetGenerator : public cmCommonTargetGenerator
+{
+public:
+ // constructor to set the ivars
+ cmMakefileTargetGenerator(cmGeneratorTarget* target);
+ cmMakefileTargetGenerator(const cmMakefileTargetGenerator&) = delete;
+ ~cmMakefileTargetGenerator() override;
+
+ cmMakefileTargetGenerator& operator=(const cmMakefileTargetGenerator&) =
+ delete;
+
+ // construct using this factory call
+ static std::unique_ptr<cmMakefileTargetGenerator> New(
+ cmGeneratorTarget* tgt);
+
+ /* the main entry point for this class. Writes the Makefiles associated
+ with this target */
+ virtual void WriteRuleFiles() = 0;
+
+ /* return the number of actions that have progress reporting on them */
+ virtual unsigned long GetNumberOfProgressActions()
+ {
+ return this->NumberOfProgressActions;
+ }
+ std::string GetProgressFileNameFull() { return this->ProgressFileNameFull; }
+
+ cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; }
+
+ std::string GetConfigName();
+
+protected:
+ void GetDeviceLinkFlags(std::string& linkFlags,
+ const std::string& linkLanguage);
+ void GetTargetLinkFlags(std::string& flags, const std::string& linkLanguage);
+
+ // create the file and directory etc
+ void CreateRuleFile();
+
+ // outputs the rules for object files and custom commands used by
+ // this target
+ void WriteTargetBuildRules();
+
+ // write some common code at the top of build.make
+ void WriteCommonCodeRules();
+ void WriteTargetLanguageFlags();
+
+ // write the clean rules for this target
+ void WriteTargetCleanRules();
+
+ // write the depend rules for this target
+ void WriteTargetDependRules();
+
+ // write rules for macOS Application Bundle content.
+ struct MacOSXContentGeneratorType
+ : cmOSXBundleGenerator::MacOSXContentGeneratorType
+ {
+ MacOSXContentGeneratorType(cmMakefileTargetGenerator* gen)
+ : Generator(gen)
+ {
+ }
+
+ void operator()(cmSourceFile const& source, const char* pkgloc,
+ const std::string& config) override;
+
+ private:
+ cmMakefileTargetGenerator* Generator;
+ };
+ friend struct MacOSXContentGeneratorType;
+
+ // write the rules for an object
+ void WriteObjectRuleFiles(cmSourceFile const& source);
+
+ // write the depend.make file for an object
+ void WriteObjectDependRules(cmSourceFile const& source,
+ std::vector<std::string>& depends);
+
+ // CUDA device linking.
+ void WriteDeviceLinkRule(std::vector<std::string>& commands,
+ const std::string& output);
+
+ // write the build rule for a custom command
+ void GenerateCustomRuleFile(cmCustomCommandGenerator const& ccg);
+
+ // write a rule to drive building of more than one output from
+ // another rule
+ void GenerateExtraOutput(const char* out, const char* in,
+ bool symbolic = false);
+
+ void MakeEchoProgress(cmLocalUnixMakefileGenerator3::EchoProgress&) const;
+
+ // write out the variable that lists the objects for this target
+ void WriteObjectsVariable(std::string& variableName,
+ std::string& variableNameExternal,
+ bool useWatcomQuote);
+ void WriteObjectsStrings(std::vector<std::string>& objStrings,
+ std::string::size_type limit = std::string::npos);
+
+ // write the driver rule to build target outputs
+ void WriteTargetDriverRule(const std::string& main_output, bool relink);
+
+ void DriveCustomCommands(std::vector<std::string>& depends);
+
+ // append intertarget dependencies
+ void AppendTargetDepends(std::vector<std::string>& depends,
+ bool ignoreType = false);
+
+ // Append object file dependencies.
+ void AppendObjectDepends(std::vector<std::string>& depends);
+
+ // Append link rule dependencies (objects, etc.).
+ void AppendLinkDepends(std::vector<std::string>& depends,
+ const std::string& linkLanguage);
+
+ // Lookup the link rule for this target.
+ std::string GetLinkRule(const std::string& linkRuleVar);
+
+ /** Create a script to hold link rules and a command to invoke the
+ script at build time. */
+ void CreateLinkScript(const char* name,
+ std::vector<std::string> const& link_commands,
+ std::vector<std::string>& makefile_commands,
+ std::vector<std::string>& makefile_depends);
+
+ std::unique_ptr<cmLinkLineComputer> CreateLinkLineComputer(
+ cmOutputConverter* outputConverter, cmStateDirectory const& stateDir);
+
+ /** Create a response file with the given set of options. Returns
+ the relative path from the target build working directory to the
+ response file name. */
+ std::string CreateResponseFile(const char* name, std::string const& options,
+ std::vector<std::string>& makefile_depends);
+
+ bool CheckUseResponseFileForObjects(std::string const& l) const;
+ bool CheckUseResponseFileForLibraries(std::string const& l) const;
+
+ /** Create list of flags for link libraries. */
+ void CreateLinkLibs(cmLinkLineComputer* linkLineComputer,
+ std::string& linkLibs, bool useResponseFile,
+ std::vector<std::string>& makefile_depends);
+
+ /** Create lists of object files for linking and cleaning. */
+ void CreateObjectLists(bool useLinkScript, bool useArchiveRules,
+ bool useResponseFile, std::string& buildObjs,
+ std::vector<std::string>& makefile_depends,
+ bool useWatcomQuote);
+
+ /** Add commands for generate def files */
+ void GenDefFile(std::vector<std::string>& real_link_commands);
+
+ void AddIncludeFlags(std::string& flags, const std::string& lang,
+ const std::string& config) override;
+
+ virtual void CloseFileStreams();
+ cmLocalUnixMakefileGenerator3* LocalGenerator;
+ cmGlobalUnixMakefileGenerator3* GlobalGenerator;
+
+ enum CustomCommandDriveType
+ {
+ OnBuild,
+ OnDepends,
+ OnUtility
+ };
+ CustomCommandDriveType CustomCommandDriver;
+
+ // the full path to the build file
+ std::string BuildFileName;
+ std::string BuildFileNameFull;
+
+ // the full path to the progress file
+ std::string ProgressFileNameFull;
+ unsigned long NumberOfProgressActions;
+ bool NoRuleMessages;
+
+ bool CMP0113New = false;
+
+ // the path to the directory the build file is in
+ std::string TargetBuildDirectory;
+ std::string TargetBuildDirectoryFull;
+
+ // the stream for the build file
+ std::unique_ptr<cmGeneratedFileStream> BuildFileStream;
+
+ // the stream for the flag file
+ std::string FlagFileNameFull;
+ std::unique_ptr<cmGeneratedFileStream> FlagFileStream;
+ class StringList : public std::vector<std::string>
+ {
+ };
+ std::map<std::string, StringList> FlagFileDepends;
+
+ // the stream for the info file
+ std::string InfoFileNameFull;
+ std::unique_ptr<cmGeneratedFileStream> InfoFileStream;
+
+ // files to clean
+ std::set<std::string> CleanFiles;
+
+ // objects used by this target
+ std::vector<std::string> Objects;
+ std::vector<std::string> ExternalObjects;
+
+ // Set of object file names that will be built in this directory.
+ std::set<std::string> ObjectFiles;
+
+ // Set of extra output files to be driven by the build.
+ std::set<std::string> ExtraFiles;
+
+ // Set of custom command output files to be driven by the build.
+ std::set<std::string> CustomCommandOutputs;
+
+ using MultipleOutputPairsType = std::map<std::string, std::string>;
+ MultipleOutputPairsType MultipleOutputPairs;
+ bool WriteMakeRule(std::ostream& os, const char* comment,
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& depends,
+ const std::vector<std::string>& commands,
+ bool in_help = false);
+
+ // Target name info.
+ cmGeneratorTarget::Names TargetNames;
+
+ // macOS content info.
+ std::set<std::string> MacContentFolders;
+ std::unique_ptr<cmOSXBundleGenerator> OSXBundleGenerator;
+ std::unique_ptr<MacOSXContentGeneratorType> MacOSXContentGenerator;
+};
diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx
new file mode 100644
index 0000000..a885b17
--- /dev/null
+++ b/Source/cmMakefileUtilityTargetGenerator.cxx
@@ -0,0 +1,145 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmMakefileUtilityTargetGenerator.h"
+
+#include <ostream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmMakefile.h"
+#include "cmOSXBundleGenerator.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmMakefileUtilityTargetGenerator::cmMakefileUtilityTargetGenerator(
+ cmGeneratorTarget* target)
+ : cmMakefileTargetGenerator(target)
+{
+ this->CustomCommandDriver = OnUtility;
+ this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target);
+ this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
+}
+
+cmMakefileUtilityTargetGenerator::~cmMakefileUtilityTargetGenerator() =
+ default;
+
+void cmMakefileUtilityTargetGenerator::WriteRuleFiles()
+{
+ this->CreateRuleFile();
+
+ *this->BuildFileStream << "# Utility rule file for "
+ << this->GeneratorTarget->GetName() << ".\n\n";
+
+ const char* root = (this->Makefile->IsOn("CMAKE_MAKE_INCLUDE_FROM_ROOT")
+ ? "$(CMAKE_BINARY_DIR)/"
+ : "");
+
+ // Include the dependencies for the target.
+ std::string dependFile =
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.make");
+ *this->BuildFileStream
+ << "# Include any custom commands dependencies for this target.\n"
+ << this->GlobalGenerator->IncludeDirective << " " << root
+ << cmSystemTools::ConvertToOutputPath(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(), dependFile))
+ << "\n\n";
+ if (!cmSystemTools::FileExists(dependFile)) {
+ // Write an empty dependency file.
+ cmGeneratedFileStream depFileStream(
+ dependFile, false, this->GlobalGenerator->GetMakefileEncoding());
+ depFileStream << "# Empty custom commands generated dependencies file for "
+ << this->GeneratorTarget->GetName() << ".\n"
+ << "# This may be replaced when dependencies are built.\n";
+ }
+
+ std::string dependTimestamp =
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts");
+ if (!cmSystemTools::FileExists(dependTimestamp)) {
+ // Write a dependency timestamp file.
+ cmGeneratedFileStream depFileStream(
+ dependTimestamp, false, this->GlobalGenerator->GetMakefileEncoding());
+ depFileStream << "# CMAKE generated file: DO NOT EDIT!\n"
+ << "# Timestamp file for custom commands dependencies "
+ "management for "
+ << this->GeneratorTarget->GetName() << ".\n";
+ }
+
+ if (!this->NoRuleMessages) {
+ // Include the progress variables for the target.
+ *this->BuildFileStream
+ << "# Include the progress variables for this target.\n"
+ << this->GlobalGenerator->IncludeDirective << " " << root
+ << cmSystemTools::ConvertToOutputPath(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(),
+ this->ProgressFileNameFull))
+ << "\n\n";
+ }
+
+ // write the custom commands for this target
+ this->WriteTargetBuildRules();
+
+ // Collect the commands and dependencies.
+ std::vector<std::string> commands;
+ std::vector<std::string> depends;
+
+ // Utility targets store their rules in pre- and post-build commands.
+ this->LocalGenerator->AppendCustomDepends(
+ depends, this->GeneratorTarget->GetPreBuildCommands());
+
+ this->LocalGenerator->AppendCustomDepends(
+ depends, this->GeneratorTarget->GetPostBuildCommands());
+
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPreBuildCommands(),
+ this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
+
+ // Depend on all custom command outputs for sources
+ this->DriveCustomCommands(depends);
+
+ this->LocalGenerator->AppendCustomCommands(
+ commands, this->GeneratorTarget->GetPostBuildCommands(),
+ this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
+
+ // Add dependencies on targets that must be built first.
+ this->AppendTargetDepends(depends);
+
+ // Add a dependency on the rule file itself.
+ this->LocalGenerator->AppendRuleDepend(depends,
+ this->BuildFileNameFull.c_str());
+
+ // If the rule is empty add the special empty rule dependency needed
+ // by some make tools.
+ if (depends.empty() && commands.empty()) {
+ std::string hack = this->GlobalGenerator->GetEmptyRuleHackDepends();
+ if (!hack.empty()) {
+ depends.push_back(std::move(hack));
+ }
+ }
+
+ // Write the rule.
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
+ this->GeneratorTarget->GetName(),
+ depends, commands, true);
+
+ // Write the main driver rule to build everything in this target.
+ this->WriteTargetDriverRule(this->GeneratorTarget->GetName(), false);
+
+ // Write clean target
+ this->WriteTargetCleanRules();
+
+ // Write the dependency generation rule. This must be done last so
+ // that multiple output pair information is available.
+ this->WriteTargetDependRules();
+
+ // close the streams
+ this->CloseFileStreams();
+}
diff --git a/Source/cmMakefileUtilityTargetGenerator.h b/Source/cmMakefileUtilityTargetGenerator.h
new file mode 100644
index 0000000..d2b4ba5
--- /dev/null
+++ b/Source/cmMakefileUtilityTargetGenerator.h
@@ -0,0 +1,22 @@
+/* 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 "cmMakefileTargetGenerator.h"
+
+class cmGeneratorTarget;
+
+class cmMakefileUtilityTargetGenerator : public cmMakefileTargetGenerator
+{
+public:
+ cmMakefileUtilityTargetGenerator(cmGeneratorTarget* target);
+ ~cmMakefileUtilityTargetGenerator() override;
+
+ /* the main entry point for this class. Writes the Makefiles associated
+ with this target */
+ void WriteRuleFiles() override;
+
+protected:
+};
diff --git a/Source/cmMarkAsAdvancedCommand.cxx b/Source/cmMarkAsAdvancedCommand.cxx
new file mode 100644
index 0000000..45043fa
--- /dev/null
+++ b/Source/cmMarkAsAdvancedCommand.cxx
@@ -0,0 +1,100 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmMarkAsAdvancedCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+// cmMarkAsAdvancedCommand
+bool cmMarkAsAdvancedCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ unsigned int i = 0;
+ const char* value = "1";
+ bool overwrite = false;
+ if (args[0] == "CLEAR" || args[0] == "FORCE") {
+ overwrite = true;
+ if (args[0] == "CLEAR") {
+ value = "0";
+ }
+ i = 1;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ cmState* state = mf.GetState();
+
+ for (; i < args.size(); ++i) {
+ std::string const& variable = args[i];
+
+ bool issueMessage = false;
+ bool oldBehavior = false;
+ bool ignoreVariable = false;
+ switch (mf.GetPolicyStatus(cmPolicies::CMP0102)) {
+ case cmPolicies::WARN:
+ if (mf.PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0102")) {
+ if (!state->GetCacheEntryValue(variable)) {
+ issueMessage = true;
+ }
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ oldBehavior = true;
+ break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ if (!state->GetCacheEntryValue(variable)) {
+ ignoreVariable = true;
+ }
+ break;
+ }
+
+ // First see if we should issue a message about CMP0102
+ if (issueMessage) {
+ std::string err = cmStrCat(
+ "Policy CMP0102 is not set: The variable named \"", variable,
+ "\" is not in the cache. This results in an empty cache entry which "
+ "is no longer created when policy CMP0102 is set to NEW. Run \"cmake "
+ "--help-policy CMP0102\" for policy details. Use the cmake_policy "
+ "command to set the policy and suppress this warning.");
+ mf.IssueMessage(MessageType::AUTHOR_WARNING, err);
+ }
+
+ // If it's not in the cache and we're using the new behavior, nothing to
+ // see here.
+ if (ignoreVariable) {
+ continue;
+ }
+
+ // Check if we want the old behavior of making a dummy cache entry.
+ if (oldBehavior) {
+ if (!state->GetCacheEntryValue(variable)) {
+ status.GetMakefile().GetCMakeInstance()->AddCacheEntry(
+ variable, nullptr, nullptr, cmStateEnums::UNINITIALIZED);
+ overwrite = true;
+ }
+ }
+
+ // We need a cache entry to do this.
+ if (!state->GetCacheEntryValue(variable)) {
+ cmSystemTools::Error("This should never happen...");
+ return false;
+ }
+ if (!state->GetCacheEntryProperty(variable, "ADVANCED") || overwrite) {
+ state->SetCacheEntryProperty(variable, "ADVANCED", value);
+ }
+ }
+ return true;
+}
diff --git a/Source/cmMarkAsAdvancedCommand.h b/Source/cmMarkAsAdvancedCommand.h
new file mode 100644
index 0000000..e420e64
--- /dev/null
+++ b/Source/cmMarkAsAdvancedCommand.h
@@ -0,0 +1,18 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief mark_as_advanced command
+ *
+ * cmMarkAsAdvancedCommand implements the mark_as_advanced CMake command
+ */
+bool cmMarkAsAdvancedCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmMathCommand.cxx b/Source/cmMathCommand.cxx
new file mode 100644
index 0000000..56221bf
--- /dev/null
+++ b/Source/cmMathCommand.cxx
@@ -0,0 +1,120 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmMathCommand.h"
+
+#include <cstdio>
+
+#include <cm3p/kwiml/int.h>
+
+#include "cmExecutionStatus.h"
+#include "cmExprParserHelper.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+
+namespace {
+bool HandleExprCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
+}
+
+bool cmMathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("must be called with at least one argument.");
+ return false;
+ }
+ const std::string& subCommand = args[0];
+ if (subCommand == "EXPR") {
+ return HandleExprCommand(args, status);
+ }
+ std::string e = "does not recognize sub-command " + subCommand;
+ status.SetError(e);
+ return false;
+}
+
+namespace {
+bool HandleExprCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if ((args.size() != 3) && (args.size() != 5)) {
+ status.SetError("EXPR called with incorrect arguments.");
+ return false;
+ }
+
+ enum class NumericFormat
+ {
+ UNINITIALIZED,
+ DECIMAL,
+ HEXADECIMAL,
+ };
+
+ const std::string& outputVariable = args[1];
+ const std::string& expression = args[2];
+ size_t argumentIndex = 3;
+ NumericFormat outputFormat = NumericFormat::UNINITIALIZED;
+
+ status.GetMakefile().AddDefinition(outputVariable, "ERROR");
+
+ if (argumentIndex < args.size()) {
+ const std::string messageHint = "sub-command EXPR ";
+ const std::string option = args[argumentIndex++];
+ if (option == "OUTPUT_FORMAT") {
+ if (argumentIndex < args.size()) {
+ const std::string argument = args[argumentIndex++];
+ if (argument == "DECIMAL") {
+ outputFormat = NumericFormat::DECIMAL;
+ } else if (argument == "HEXADECIMAL") {
+ outputFormat = NumericFormat::HEXADECIMAL;
+ } else {
+ std::string error = messageHint + "value \"" + argument +
+ "\" for option \"" + option + "\" is invalid.";
+ status.SetError(error);
+ return false;
+ }
+ } else {
+ std::string error =
+ messageHint + "missing argument for option \"" + option + "\".";
+ status.SetError(error);
+ return false;
+ }
+ } else {
+ std::string error =
+ messageHint + "option \"" + option + "\" is unknown.";
+ status.SetError(error);
+ return false;
+ }
+ }
+
+ if (outputFormat == NumericFormat::UNINITIALIZED) {
+ outputFormat = NumericFormat::DECIMAL;
+ }
+
+ cmExprParserHelper helper;
+ if (!helper.ParseString(expression.c_str(), 0)) {
+ status.SetError(helper.GetError());
+ return false;
+ }
+
+ char buffer[1024];
+ const char* fmt;
+ switch (outputFormat) {
+ case NumericFormat::HEXADECIMAL:
+ fmt = "0x%" KWIML_INT_PRIx64;
+ break;
+ case NumericFormat::DECIMAL:
+ CM_FALLTHROUGH;
+ default:
+ fmt = "%" KWIML_INT_PRId64;
+ break;
+ }
+ sprintf(buffer, fmt, helper.GetResult());
+
+ std::string const& w = helper.GetWarning();
+ if (!w.empty()) {
+ status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, w);
+ }
+
+ status.GetMakefile().AddDefinition(outputVariable, buffer);
+ return true;
+}
+}
diff --git a/Source/cmMathCommand.h b/Source/cmMathCommand.h
new file mode 100644
index 0000000..e6b347b
--- /dev/null
+++ b/Source/cmMathCommand.h
@@ -0,0 +1,14 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/// Mathematical expressions: math(EXPR ...) command.
+bool cmMathCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
new file mode 100644
index 0000000..c7bb9a7
--- /dev/null
+++ b/Source/cmMessageCommand.cxx
@@ -0,0 +1,228 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmMessageCommand.h"
+
+#include <cassert>
+#include <utility>
+
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmMessenger.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+namespace {
+
+enum class CheckingType
+{
+ UNDEFINED,
+ CHECK_START,
+ CHECK_PASS,
+ CHECK_FAIL
+};
+
+std::string IndentText(std::string text, cmMakefile& mf)
+{
+ auto indent =
+ cmJoin(cmExpandedList(mf.GetSafeDefinition("CMAKE_MESSAGE_INDENT")), "");
+
+ const auto showContext = mf.GetCMakeInstance()->GetShowLogContext() ||
+ mf.IsOn("CMAKE_MESSAGE_CONTEXT_SHOW");
+ if (showContext) {
+ auto context = cmJoin(
+ cmExpandedList(mf.GetSafeDefinition("CMAKE_MESSAGE_CONTEXT")), ".");
+ if (!context.empty()) {
+ indent.insert(0u, cmStrCat("["_s, context, "] "_s));
+ }
+ }
+
+ if (!indent.empty()) {
+ cmSystemTools::ReplaceString(text, "\n", "\n" + indent);
+ text.insert(0u, indent);
+ }
+ return text;
+}
+
+void ReportCheckResult(cm::string_view what, std::string result,
+ cmMakefile& mf)
+{
+ if (mf.GetCMakeInstance()->HasCheckInProgress()) {
+ auto text = mf.GetCMakeInstance()->GetTopCheckInProgressMessage() + " - " +
+ std::move(result);
+ mf.DisplayStatus(IndentText(std::move(text), mf), -1);
+ } else {
+ mf.GetMessenger()->DisplayMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat("Ignored "_s, what, " without CHECK_START"_s),
+ mf.GetBacktrace());
+ }
+}
+
+} // anonymous namespace
+
+// cmLibraryCommand
+bool cmMessageCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ auto& mf = status.GetMakefile();
+
+ auto i = args.cbegin();
+
+ auto type = MessageType::MESSAGE;
+ auto fatal = false;
+ auto level = cmake::LogLevel::LOG_UNDEFINED;
+ auto checkingType = CheckingType::UNDEFINED;
+ if (*i == "SEND_ERROR") {
+ type = MessageType::FATAL_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
+ ++i;
+ } else if (*i == "FATAL_ERROR") {
+ fatal = true;
+ type = MessageType::FATAL_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
+ ++i;
+ } else if (*i == "WARNING") {
+ type = MessageType::WARNING;
+ level = cmake::LogLevel::LOG_WARNING;
+ ++i;
+ } else if (*i == "AUTHOR_WARNING") {
+ if (mf.IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") &&
+ !mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) {
+ fatal = true;
+ type = MessageType::AUTHOR_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
+ } else if (!mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
+ type = MessageType::AUTHOR_WARNING;
+ level = cmake::LogLevel::LOG_WARNING;
+ } else {
+ return true;
+ }
+ ++i;
+ } else if (*i == "CHECK_START") {
+ level = cmake::LogLevel::LOG_STATUS;
+ checkingType = CheckingType::CHECK_START;
+ ++i;
+ } else if (*i == "CHECK_PASS") {
+ level = cmake::LogLevel::LOG_STATUS;
+ checkingType = CheckingType::CHECK_PASS;
+ ++i;
+ } else if (*i == "CHECK_FAIL") {
+ level = cmake::LogLevel::LOG_STATUS;
+ checkingType = CheckingType::CHECK_FAIL;
+ ++i;
+ } else if (*i == "STATUS") {
+ level = cmake::LogLevel::LOG_STATUS;
+ ++i;
+ } else if (*i == "VERBOSE") {
+ level = cmake::LogLevel::LOG_VERBOSE;
+ ++i;
+ } else if (*i == "DEBUG") {
+ level = cmake::LogLevel::LOG_DEBUG;
+ ++i;
+ } else if (*i == "TRACE") {
+ level = cmake::LogLevel::LOG_TRACE;
+ ++i;
+ } else if (*i == "DEPRECATION") {
+ if (mf.IsOn("CMAKE_ERROR_DEPRECATED")) {
+ fatal = true;
+ type = MessageType::DEPRECATION_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
+ } else if (!mf.IsSet("CMAKE_WARN_DEPRECATED") ||
+ mf.IsOn("CMAKE_WARN_DEPRECATED")) {
+ type = MessageType::DEPRECATION_WARNING;
+ level = cmake::LogLevel::LOG_WARNING;
+ } else {
+ return true;
+ }
+ ++i;
+ } else if (*i == "NOTICE") {
+ // `NOTICE` message type is going to be output to stderr
+ level = cmake::LogLevel::LOG_NOTICE;
+ ++i;
+ } else {
+ // Messages w/o any type are `NOTICE`s
+ level = cmake::LogLevel::LOG_NOTICE;
+ }
+ assert("Message log level expected to be set" &&
+ level != cmake::LogLevel::LOG_UNDEFINED);
+
+ auto desiredLevel = mf.GetCMakeInstance()->GetLogLevel();
+ assert("Expected a valid log level here" &&
+ desiredLevel != cmake::LogLevel::LOG_UNDEFINED);
+
+ // Command line option takes precedence over the cache variable
+ if (!mf.GetCMakeInstance()->WasLogLevelSetViaCLI()) {
+ const auto desiredLevelFromCache =
+ cmake::StringToLogLevel(mf.GetSafeDefinition("CMAKE_MESSAGE_LOG_LEVEL"));
+ if (desiredLevelFromCache != cmake::LogLevel::LOG_UNDEFINED) {
+ desiredLevel = desiredLevelFromCache;
+ }
+ }
+
+ if (desiredLevel < level) {
+ // Suppress the message
+ return true;
+ }
+
+ auto message = cmJoin(cmMakeRange(i, args.cend()), "");
+
+ switch (level) {
+ case cmake::LogLevel::LOG_ERROR:
+ case cmake::LogLevel::LOG_WARNING:
+ // we've overridden the message type, above, so display it directly
+ mf.GetMessenger()->DisplayMessage(type, message, mf.GetBacktrace());
+ break;
+
+ case cmake::LogLevel::LOG_NOTICE:
+ cmSystemTools::Message(IndentText(message, mf));
+ break;
+
+ case cmake::LogLevel::LOG_STATUS:
+ switch (checkingType) {
+ case CheckingType::CHECK_START:
+ mf.DisplayStatus(IndentText(message, mf), -1);
+ mf.GetCMakeInstance()->PushCheckInProgressMessage(message);
+ break;
+
+ case CheckingType::CHECK_PASS:
+ ReportCheckResult("CHECK_PASS"_s, message, mf);
+ break;
+
+ case CheckingType::CHECK_FAIL:
+ ReportCheckResult("CHECK_FAIL"_s, message, mf);
+ break;
+
+ default:
+ mf.DisplayStatus(IndentText(message, mf), -1);
+ break;
+ }
+ break;
+
+ case cmake::LogLevel::LOG_VERBOSE:
+ case cmake::LogLevel::LOG_DEBUG:
+ case cmake::LogLevel::LOG_TRACE:
+ mf.DisplayStatus(IndentText(message, mf), -1);
+ break;
+
+ default:
+ assert("Unexpected log level! Review the `cmMessageCommand.cxx`." &&
+ false);
+ break;
+ }
+
+ if (fatal) {
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ return true;
+}
diff --git a/Source/cmMessageCommand.h b/Source/cmMessageCommand.h
new file mode 100644
index 0000000..c37098c
--- /dev/null
+++ b/Source/cmMessageCommand.h
@@ -0,0 +1,17 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Displays a message to the user
+ *
+ */
+bool cmMessageCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmMessageType.h b/Source/cmMessageType.h
new file mode 100644
index 0000000..44de429
--- /dev/null
+++ b/Source/cmMessageType.h
@@ -0,0 +1,18 @@
+/* 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
+
+enum class MessageType
+{
+ AUTHOR_WARNING,
+ AUTHOR_ERROR,
+ FATAL_ERROR,
+ INTERNAL_ERROR,
+ MESSAGE,
+ WARNING,
+ LOG,
+ DEPRECATION_ERROR,
+ DEPRECATION_WARNING
+};
diff --git a/Source/cmMessenger.cxx b/Source/cmMessenger.cxx
new file mode 100644
index 0000000..af83478
--- /dev/null
+++ b/Source/cmMessenger.cxx
@@ -0,0 +1,168 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmMessenger.h"
+
+#include "cmDocumentationFormatter.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+#if !defined(CMAKE_BOOTSTRAP)
+# include "cmsys/SystemInformation.hxx"
+#endif
+
+#include <sstream>
+
+MessageType cmMessenger::ConvertMessageType(MessageType t) const
+{
+ bool warningsAsErrors;
+
+ if (t == MessageType::AUTHOR_WARNING || t == MessageType::AUTHOR_ERROR) {
+ warningsAsErrors = this->GetDevWarningsAsErrors();
+ if (warningsAsErrors && t == MessageType::AUTHOR_WARNING) {
+ t = MessageType::AUTHOR_ERROR;
+ } else if (!warningsAsErrors && t == MessageType::AUTHOR_ERROR) {
+ t = MessageType::AUTHOR_WARNING;
+ }
+ } else if (t == MessageType::DEPRECATION_WARNING ||
+ t == MessageType::DEPRECATION_ERROR) {
+ warningsAsErrors = this->GetDeprecatedWarningsAsErrors();
+ if (warningsAsErrors && t == MessageType::DEPRECATION_WARNING) {
+ t = MessageType::DEPRECATION_ERROR;
+ } else if (!warningsAsErrors && t == MessageType::DEPRECATION_ERROR) {
+ t = MessageType::DEPRECATION_WARNING;
+ }
+ }
+
+ return t;
+}
+
+bool cmMessenger::IsMessageTypeVisible(MessageType t) const
+{
+ bool isVisible = true;
+
+ if (t == MessageType::DEPRECATION_ERROR) {
+ if (!this->GetDeprecatedWarningsAsErrors()) {
+ isVisible = false;
+ }
+ } else if (t == MessageType::DEPRECATION_WARNING) {
+ if (this->GetSuppressDeprecatedWarnings()) {
+ isVisible = false;
+ }
+ } else if (t == MessageType::AUTHOR_ERROR) {
+ if (!this->GetDevWarningsAsErrors()) {
+ isVisible = false;
+ }
+ } else if (t == MessageType::AUTHOR_WARNING) {
+ if (this->GetSuppressDevWarnings()) {
+ isVisible = false;
+ }
+ }
+
+ return isVisible;
+}
+
+static bool printMessagePreamble(MessageType t, std::ostream& msg)
+{
+ // Construct the message header.
+ if (t == MessageType::FATAL_ERROR) {
+ msg << "CMake Error";
+ } else if (t == MessageType::INTERNAL_ERROR) {
+ msg << "CMake Internal Error (please report a bug)";
+ } else if (t == MessageType::LOG) {
+ msg << "CMake Debug Log";
+ } else if (t == MessageType::DEPRECATION_ERROR) {
+ msg << "CMake Deprecation Error";
+ } else if (t == MessageType::DEPRECATION_WARNING) {
+ msg << "CMake Deprecation Warning";
+ } else if (t == MessageType::AUTHOR_WARNING) {
+ msg << "CMake Warning (dev)";
+ } else if (t == MessageType::AUTHOR_ERROR) {
+ msg << "CMake Error (dev)";
+ } else {
+ msg << "CMake Warning";
+ }
+ return true;
+}
+
+void printMessageText(std::ostream& msg, std::string const& text)
+{
+ msg << ":\n";
+ cmDocumentationFormatter formatter;
+ formatter.SetIndent(" ");
+ formatter.PrintFormatted(msg, text.c_str());
+}
+
+void displayMessage(MessageType t, std::ostringstream& msg)
+{
+ // Add a note about warning suppression.
+ if (t == MessageType::AUTHOR_WARNING) {
+ msg << "This warning is for project developers. Use -Wno-dev to suppress "
+ "it.";
+ } else if (t == MessageType::AUTHOR_ERROR) {
+ msg << "This error is for project developers. Use -Wno-error=dev to "
+ "suppress it.";
+ }
+
+ // Add a terminating blank line.
+ msg << "\n";
+
+#if !defined(CMAKE_BOOTSTRAP)
+ // Add a C++ stack trace to internal errors.
+ if (t == MessageType::INTERNAL_ERROR) {
+ std::string stack = cmsys::SystemInformation::GetProgramStack(0, 0);
+ if (!stack.empty()) {
+ if (cmHasLiteralPrefix(stack, "WARNING:")) {
+ stack = "Note:" + stack.substr(8);
+ }
+ msg << stack << "\n";
+ }
+ }
+#endif
+
+ // Output the message.
+ if (t == MessageType::FATAL_ERROR || t == MessageType::INTERNAL_ERROR ||
+ t == MessageType::DEPRECATION_ERROR || t == MessageType::AUTHOR_ERROR) {
+ cmSystemTools::SetErrorOccured();
+ cmSystemTools::Message(msg.str(), "Error");
+ } else {
+ cmSystemTools::Message(msg.str(), "Warning");
+ }
+}
+
+void cmMessenger::IssueMessage(MessageType t, const std::string& text,
+ const cmListFileBacktrace& backtrace) const
+{
+ bool force = false;
+ if (!force) {
+ // override the message type, if needed, for warnings and errors
+ MessageType override = this->ConvertMessageType(t);
+ if (override != t) {
+ t = override;
+ force = true;
+ }
+ }
+
+ if (!force && !this->IsMessageTypeVisible(t)) {
+ return;
+ }
+ this->DisplayMessage(t, text, backtrace);
+}
+
+void cmMessenger::DisplayMessage(MessageType t, const std::string& text,
+ const cmListFileBacktrace& backtrace) const
+{
+ std::ostringstream msg;
+ if (!printMessagePreamble(t, msg)) {
+ return;
+ }
+
+ // Add the immediate context.
+ backtrace.PrintTitle(msg);
+
+ printMessageText(msg, text);
+
+ // Add the rest of the context.
+ backtrace.PrintCallStack(msg);
+
+ displayMessage(t, msg);
+}
diff --git a/Source/cmMessenger.h b/Source/cmMessenger.h
new file mode 100644
index 0000000..b6f5712
--- /dev/null
+++ b/Source/cmMessenger.h
@@ -0,0 +1,58 @@
+/* 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 <string>
+
+#include "cmListFileCache.h"
+#include "cmMessageType.h"
+
+class cmMessenger
+{
+public:
+ void IssueMessage(
+ MessageType t, std::string const& text,
+ cmListFileBacktrace const& backtrace = cmListFileBacktrace()) const;
+
+ void DisplayMessage(MessageType t, std::string const& text,
+ cmListFileBacktrace const& backtrace) const;
+
+ void SetSuppressDevWarnings(bool suppress)
+ {
+ this->SuppressDevWarnings = suppress;
+ }
+ void SetSuppressDeprecatedWarnings(bool suppress)
+ {
+ this->SuppressDeprecatedWarnings = suppress;
+ }
+ void SetDevWarningsAsErrors(bool error)
+ {
+ this->DevWarningsAsErrors = error;
+ }
+ void SetDeprecatedWarningsAsErrors(bool error)
+ {
+ this->DeprecatedWarningsAsErrors = error;
+ }
+
+ bool GetSuppressDevWarnings() const { return this->SuppressDevWarnings; }
+ bool GetSuppressDeprecatedWarnings() const
+ {
+ return this->SuppressDeprecatedWarnings;
+ }
+ bool GetDevWarningsAsErrors() const { return this->DevWarningsAsErrors; }
+ bool GetDeprecatedWarningsAsErrors() const
+ {
+ return this->DeprecatedWarningsAsErrors;
+ }
+
+private:
+ bool IsMessageTypeVisible(MessageType t) const;
+ MessageType ConvertMessageType(MessageType t) const;
+
+ bool SuppressDevWarnings = false;
+ bool SuppressDeprecatedWarnings = false;
+ bool DevWarningsAsErrors = false;
+ bool DeprecatedWarningsAsErrors = false;
+};
diff --git a/Source/cmNewLineStyle.cxx b/Source/cmNewLineStyle.cxx
new file mode 100644
index 0000000..28baeb6
--- /dev/null
+++ b/Source/cmNewLineStyle.cxx
@@ -0,0 +1,65 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmNewLineStyle.h"
+
+#include <cstddef>
+
+cmNewLineStyle::cmNewLineStyle() = default;
+
+bool cmNewLineStyle::IsValid() const
+{
+ return this->NewLineStyle != Invalid;
+}
+
+bool cmNewLineStyle::ReadFromArguments(const std::vector<std::string>& args,
+ std::string& errorString)
+{
+ this->NewLineStyle = Invalid;
+
+ for (size_t i = 0; i < args.size(); i++) {
+ if (args[i] == "NEWLINE_STYLE") {
+ size_t const styleIndex = i + 1;
+ if (args.size() > styleIndex) {
+ std::string const& eol = args[styleIndex];
+ if (eol == "LF" || eol == "UNIX") {
+ this->NewLineStyle = LF;
+ return true;
+ }
+ if (eol == "CRLF" || eol == "WIN32" || eol == "DOS") {
+ this->NewLineStyle = CRLF;
+ return true;
+ }
+ errorString = "NEWLINE_STYLE sets an unknown style, only LF, "
+ "CRLF, UNIX, DOS, and WIN32 are supported";
+ return false;
+ }
+ errorString = "NEWLINE_STYLE must set a style: "
+ "LF, CRLF, UNIX, DOS, or WIN32";
+ return false;
+ }
+ }
+ return true;
+}
+
+std::string cmNewLineStyle::GetCharacters() const
+{
+ switch (this->NewLineStyle) {
+ case Invalid:
+ return "";
+ case LF:
+ return "\n";
+ case CRLF:
+ return "\r\n";
+ }
+ return "";
+}
+
+void cmNewLineStyle::SetStyle(Style style)
+{
+ this->NewLineStyle = style;
+}
+
+cmNewLineStyle::Style cmNewLineStyle::GetStyle() const
+{
+ return this->NewLineStyle;
+}
diff --git a/Source/cmNewLineStyle.h b/Source/cmNewLineStyle.h
new file mode 100644
index 0000000..a2b985b
--- /dev/null
+++ b/Source/cmNewLineStyle.h
@@ -0,0 +1,36 @@
+/* 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 <string>
+#include <vector>
+
+class cmNewLineStyle
+{
+public:
+ cmNewLineStyle();
+
+ enum Style
+ {
+ Invalid,
+ // LF = '\n', 0x0A, 10
+ // CR = '\r', 0x0D, 13
+ LF, // Unix
+ CRLF // Dos
+ };
+
+ void SetStyle(Style);
+ Style GetStyle() const;
+
+ bool IsValid() const;
+
+ bool ReadFromArguments(const std::vector<std::string>& args,
+ std::string& errorString);
+
+ std::string GetCharacters() const;
+
+private:
+ Style NewLineStyle = Invalid;
+};
diff --git a/Source/cmNinjaLinkLineComputer.cxx b/Source/cmNinjaLinkLineComputer.cxx
new file mode 100644
index 0000000..2304ad2
--- /dev/null
+++ b/Source/cmNinjaLinkLineComputer.cxx
@@ -0,0 +1,22 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmNinjaLinkLineComputer.h"
+
+#include "cmGlobalNinjaGenerator.h"
+
+class cmOutputConverter;
+
+cmNinjaLinkLineComputer::cmNinjaLinkLineComputer(
+ cmOutputConverter* outputConverter, cmStateDirectory const& stateDir,
+ cmGlobalNinjaGenerator const* gg)
+ : cmLinkLineComputer(outputConverter, stateDir)
+ , GG(gg)
+{
+}
+
+std::string cmNinjaLinkLineComputer::ConvertToLinkReference(
+ std::string const& lib) const
+{
+ return this->GG->ConvertToNinjaPath(lib);
+}
diff --git a/Source/cmNinjaLinkLineComputer.h b/Source/cmNinjaLinkLineComputer.h
new file mode 100644
index 0000000..5d22f3e
--- /dev/null
+++ b/Source/cmNinjaLinkLineComputer.h
@@ -0,0 +1,30 @@
+/* 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 <string>
+
+#include "cmLinkLineComputer.h"
+
+class cmGlobalNinjaGenerator;
+class cmOutputConverter;
+class cmStateDirectory;
+
+class cmNinjaLinkLineComputer : public cmLinkLineComputer
+{
+public:
+ cmNinjaLinkLineComputer(cmOutputConverter* outputConverter,
+ cmStateDirectory const& stateDir,
+ cmGlobalNinjaGenerator const* gg);
+
+ cmNinjaLinkLineComputer(cmNinjaLinkLineComputer const&) = delete;
+ cmNinjaLinkLineComputer& operator=(cmNinjaLinkLineComputer const&) = delete;
+
+ std::string ConvertToLinkReference(std::string const& input) const override;
+
+private:
+ cmGlobalNinjaGenerator const* GG;
+};
diff --git a/Source/cmNinjaLinkLineDeviceComputer.cxx b/Source/cmNinjaLinkLineDeviceComputer.cxx
new file mode 100644
index 0000000..f66e2f5
--- /dev/null
+++ b/Source/cmNinjaLinkLineDeviceComputer.cxx
@@ -0,0 +1,20 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmNinjaLinkLineDeviceComputer.h"
+
+#include "cmGlobalNinjaGenerator.h"
+
+cmNinjaLinkLineDeviceComputer::cmNinjaLinkLineDeviceComputer(
+ cmOutputConverter* outputConverter, cmStateDirectory const& stateDir,
+ cmGlobalNinjaGenerator const* gg)
+ : cmLinkLineDeviceComputer(outputConverter, stateDir)
+ , GG(gg)
+{
+}
+
+std::string cmNinjaLinkLineDeviceComputer::ConvertToLinkReference(
+ std::string const& lib) const
+{
+ return this->GG->ConvertToNinjaPath(lib);
+}
diff --git a/Source/cmNinjaLinkLineDeviceComputer.h b/Source/cmNinjaLinkLineDeviceComputer.h
new file mode 100644
index 0000000..457f036
--- /dev/null
+++ b/Source/cmNinjaLinkLineDeviceComputer.h
@@ -0,0 +1,31 @@
+/* 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 <string>
+
+#include "cmLinkLineDeviceComputer.h"
+
+class cmGlobalNinjaGenerator;
+class cmOutputConverter;
+class cmStateDirectory;
+
+class cmNinjaLinkLineDeviceComputer : public cmLinkLineDeviceComputer
+{
+public:
+ cmNinjaLinkLineDeviceComputer(cmOutputConverter* outputConverter,
+ cmStateDirectory const& stateDir,
+ cmGlobalNinjaGenerator const* gg);
+
+ cmNinjaLinkLineDeviceComputer(cmNinjaLinkLineDeviceComputer const&) = delete;
+ cmNinjaLinkLineDeviceComputer& operator=(
+ cmNinjaLinkLineDeviceComputer const&) = delete;
+
+ std::string ConvertToLinkReference(std::string const& input) const override;
+
+private:
+ cmGlobalNinjaGenerator const* GG;
+};
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
new file mode 100644
index 0000000..1d511f2
--- /dev/null
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -0,0 +1,1469 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmNinjaNormalTargetGenerator.h"
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <map>
+#include <set>
+#include <sstream>
+#include <unordered_set>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/optional>
+#include <cm/vector>
+
+#include "cmComputeLinkInformation.h"
+#include "cmCustomCommand.h" // IWYU pragma: keep
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmLinkLineComputer.h"
+#include "cmLinkLineDeviceComputer.h"
+#include "cmLocalCommonGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmLocalNinjaGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmNinjaLinkLineDeviceComputer.h"
+#include "cmNinjaTypes.h"
+#include "cmOSXBundleGenerator.h"
+#include "cmOutputConverter.h"
+#include "cmProperty.h"
+#include "cmRulePlaceholderExpander.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
+ cmGeneratorTarget* target)
+ : cmNinjaTargetGenerator(target)
+{
+ if (target->GetType() != cmStateEnums::OBJECT_LIBRARY) {
+ // on Windows the output dir is already needed at compile time
+ // ensure the directory exists (OutDir test)
+ for (auto const& config : this->GetConfigNames()) {
+ this->EnsureDirectoryExists(target->GetDirectory(config));
+ }
+ }
+
+ this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target);
+ this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
+}
+
+cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator() = default;
+
+void cmNinjaNormalTargetGenerator::Generate(const std::string& config)
+{
+ std::string lang = this->GeneratorTarget->GetLinkerLanguage(config);
+ if (this->TargetLinkLanguage(config).empty()) {
+ cmSystemTools::Error("CMake can not determine linker language for "
+ "target: " +
+ this->GetGeneratorTarget()->GetName());
+ return;
+ }
+
+ // Write the rules for each language.
+ this->WriteLanguagesRules(config);
+
+ // Write the build statements
+ bool firstForConfig = true;
+ for (auto const& fileConfig : this->GetConfigNames()) {
+ if (!this->GetGlobalGenerator()
+ ->GetCrossConfigs(fileConfig)
+ .count(config)) {
+ continue;
+ }
+ this->WriteObjectBuildStatements(config, fileConfig, firstForConfig);
+ firstForConfig = false;
+ }
+
+ if (this->GetGeneratorTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ this->WriteObjectLibStatement(config);
+ } else {
+ firstForConfig = true;
+ for (auto const& fileConfig : this->GetConfigNames()) {
+ if (!this->GetGlobalGenerator()
+ ->GetCrossConfigs(fileConfig)
+ .count(config)) {
+ continue;
+ }
+ // If this target has cuda language link inputs, and we need to do
+ // device linking
+ this->WriteDeviceLinkStatement(config, fileConfig, firstForConfig);
+ this->WriteLinkStatement(config, fileConfig, firstForConfig);
+ firstForConfig = false;
+ }
+ }
+ if (this->GetGlobalGenerator()->EnableCrossConfigBuild()) {
+ this->GetGlobalGenerator()->AddTargetAlias(
+ this->GetTargetName(), this->GetGeneratorTarget(), "all");
+ }
+
+ // Find ADDITIONAL_CLEAN_FILES
+ this->AdditionalCleanFiles(config);
+}
+
+void cmNinjaNormalTargetGenerator::WriteLanguagesRules(
+ const std::string& config)
+{
+#ifdef NINJA_GEN_VERBOSE_FILES
+ cmGlobalNinjaGenerator::WriteDivider(this->GetRulesFileStream());
+ this->GetRulesFileStream()
+ << "# Rules for each languages for "
+ << cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
+ << " target " << this->GetTargetName() << "\n\n";
+#endif
+
+ // Write rules for languages compiled in this target.
+ std::set<std::string> languages;
+ std::vector<cmSourceFile const*> sourceFiles;
+ this->GetGeneratorTarget()->GetObjectSources(sourceFiles, config);
+ for (cmSourceFile const* sf : sourceFiles) {
+ std::string const lang = sf->GetLanguage();
+ if (!lang.empty()) {
+ languages.insert(lang);
+ }
+ }
+ for (std::string const& language : languages) {
+ this->WriteLanguageRules(language, config);
+ }
+}
+
+const char* cmNinjaNormalTargetGenerator::GetVisibleTypeName() const
+{
+ switch (this->GetGeneratorTarget()->GetType()) {
+ case cmStateEnums::STATIC_LIBRARY:
+ return "static library";
+ case cmStateEnums::SHARED_LIBRARY:
+ return "shared library";
+ case cmStateEnums::MODULE_LIBRARY:
+ if (this->GetGeneratorTarget()->IsCFBundleOnApple()) {
+ return "CFBundle shared module";
+ } else {
+ return "shared module";
+ }
+ case cmStateEnums::EXECUTABLE:
+ return "executable";
+ default:
+ return nullptr;
+ }
+}
+
+std::string cmNinjaNormalTargetGenerator::LanguageLinkerRule(
+ const std::string& config) const
+{
+ return cmStrCat(
+ this->TargetLinkLanguage(config), "_",
+ cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()),
+ "_LINKER__",
+ cmGlobalNinjaGenerator::EncodeRuleName(
+ this->GetGeneratorTarget()->GetName()),
+ "_", config);
+}
+
+std::string cmNinjaNormalTargetGenerator::LanguageLinkerDeviceRule(
+ const std::string& config) const
+{
+ return cmStrCat(
+ this->TargetLinkLanguage(config), "_",
+ cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()),
+ "_DEVICE_LINKER__",
+ cmGlobalNinjaGenerator::EncodeRuleName(
+ this->GetGeneratorTarget()->GetName()),
+ "_", config);
+}
+
+std::string cmNinjaNormalTargetGenerator::LanguageLinkerCudaDeviceRule(
+ const std::string& config) const
+{
+ return cmStrCat(
+ this->TargetLinkLanguage(config), "_DEVICE_LINK__",
+ cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
+ '_', config);
+}
+
+std::string cmNinjaNormalTargetGenerator::LanguageLinkerCudaDeviceCompileRule(
+ const std::string& config) const
+{
+ return cmStrCat(
+ this->TargetLinkLanguage(config), "_DEVICE_LINK_COMPILE__",
+ cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
+ '_', config);
+}
+
+std::string cmNinjaNormalTargetGenerator::LanguageLinkerCudaFatbinaryRule(
+ const std::string& config) const
+{
+ return cmStrCat(
+ this->TargetLinkLanguage(config), "_FATBINARY__",
+ cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
+ '_', config);
+}
+
+struct cmNinjaRemoveNoOpCommands
+{
+ bool operator()(std::string const& cmd)
+ {
+ return cmd.empty() || cmd[0] == ':';
+ }
+};
+
+void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkRule(
+ bool useResponseFile, const std::string& config)
+{
+ cmNinjaRule rule(this->LanguageLinkerDeviceRule(config));
+ if (!this->GetGlobalGenerator()->HasRule(rule.Name)) {
+ cmRulePlaceholderExpander::RuleVariables vars;
+ vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
+ vars.CMTargetType =
+ cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
+ .c_str();
+
+ vars.Language = "CUDA";
+
+ // build response file name
+ std::string responseFlag = this->GetMakefile()->GetSafeDefinition(
+ "CMAKE_CUDA_RESPONSE_FILE_DEVICE_LINK_FLAG");
+
+ if (!useResponseFile || responseFlag.empty()) {
+ vars.Objects = "$in";
+ vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
+ } else {
+ rule.RspFile = "$RSP_FILE";
+ responseFlag += rule.RspFile;
+
+ // build response file content
+ if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
+ rule.RspContent = "$in";
+ } else {
+ rule.RspContent = "$in_newline";
+ }
+ rule.RspContent += " $LINK_LIBRARIES";
+ vars.Objects = responseFlag.c_str();
+ vars.LinkLibraries = "";
+ }
+
+ vars.ObjectDir = "$OBJECT_DIR";
+
+ vars.Target = "$TARGET_FILE";
+
+ vars.SONameFlag = "$SONAME_FLAG";
+ vars.TargetSOName = "$SONAME";
+ vars.TargetPDB = "$TARGET_PDB";
+ vars.TargetCompilePDB = "$TARGET_COMPILE_PDB";
+
+ vars.Flags = "$FLAGS";
+ vars.LinkFlags = "$LINK_FLAGS";
+ vars.Manifests = "$MANIFESTS";
+
+ vars.LanguageCompileFlags = "$LANGUAGE_COMPILE_FLAGS";
+
+ std::string launcher;
+ cmProp val = this->GetLocalGenerator()->GetRuleLauncher(
+ this->GetGeneratorTarget(), "RULE_LAUNCH_LINK");
+ if (cmNonempty(val)) {
+ launcher = cmStrCat(*val, ' ');
+ }
+
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->GetLocalGenerator()->CreateRulePlaceholderExpander());
+
+ // Rule for linking library/executable.
+ std::vector<std::string> linkCmds = this->ComputeDeviceLinkCmd();
+ for (std::string& linkCmd : linkCmds) {
+ linkCmd = cmStrCat(launcher, linkCmd);
+ rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
+ linkCmd, vars);
+ }
+
+ // If there is no ranlib the command will be ":". Skip it.
+ cm::erase_if(linkCmds, cmNinjaRemoveNoOpCommands());
+
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(linkCmds);
+
+ // Write the linker rule with response file if needed.
+ rule.Comment =
+ cmStrCat("Rule for linking ", this->TargetLinkLanguage(config), ' ',
+ this->GetVisibleTypeName(), '.');
+ rule.Description =
+ cmStrCat("Linking ", this->TargetLinkLanguage(config), ' ',
+ this->GetVisibleTypeName(), " $TARGET_FILE");
+ rule.Restat = "$RESTAT";
+
+ this->GetGlobalGenerator()->AddRule(rule);
+ }
+}
+
+void cmNinjaNormalTargetGenerator::WriteDeviceLinkRules(
+ const std::string& config)
+{
+ const cmMakefile* mf = this->GetMakefile();
+
+ cmNinjaRule rule(this->LanguageLinkerCudaDeviceRule(config));
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(
+ { cmStrCat(mf->GetRequiredDefinition("CMAKE_CUDA_DEVICE_LINKER"),
+ " -arch=$ARCH $REGISTER -o=$out $in") });
+ rule.Comment = "Rule for CUDA device linking.";
+ rule.Description = "Linking CUDA $out";
+ this->GetGlobalGenerator()->AddRule(rule);
+
+ cmRulePlaceholderExpander::RuleVariables vars;
+ vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
+ vars.CMTargetType =
+ cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()).c_str();
+
+ vars.Language = "CUDA";
+ vars.Object = "$out";
+ vars.Fatbinary = "$FATBIN";
+ vars.RegisterFile = "$REGISTER";
+
+ std::string flags = this->GetFlags("CUDA", config);
+ vars.Flags = flags.c_str();
+
+ std::string compileCmd = this->GetMakefile()->GetRequiredDefinition(
+ "CMAKE_CUDA_DEVICE_LINK_COMPILE");
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->GetLocalGenerator()->CreateRulePlaceholderExpander());
+ rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
+ compileCmd, vars);
+
+ rule.Name = this->LanguageLinkerCudaDeviceCompileRule(config);
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine({ compileCmd });
+ rule.Comment = "Rule for compiling CUDA device stubs.";
+ rule.Description = "Compiling CUDA device stub $out";
+ this->GetGlobalGenerator()->AddRule(rule);
+
+ rule.Name = this->LanguageLinkerCudaFatbinaryRule(config);
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(
+ { cmStrCat(mf->GetRequiredDefinition("CMAKE_CUDA_FATBINARY"),
+ " -64 -cmdline=--compile-only -compress-all -link "
+ "--embedded-fatbin=$out $PROFILES") });
+ rule.Comment = "Rule for CUDA fatbinaries.";
+ rule.Description = "Creating fatbinary $out";
+ this->GetGlobalGenerator()->AddRule(rule);
+}
+
+void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
+ const std::string& config)
+{
+ cmStateEnums::TargetType targetType = this->GetGeneratorTarget()->GetType();
+
+ std::string linkRuleName = this->LanguageLinkerRule(config);
+ if (!this->GetGlobalGenerator()->HasRule(linkRuleName)) {
+ cmNinjaRule rule(std::move(linkRuleName));
+ cmRulePlaceholderExpander::RuleVariables vars;
+ vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
+ vars.CMTargetType = cmState::GetTargetTypeName(targetType).c_str();
+
+ std::string lang = this->TargetLinkLanguage(config);
+ vars.Language = config.c_str();
+ vars.AIXExports = "$AIX_EXPORTS";
+
+ if (this->TargetLinkLanguage(config) == "Swift") {
+ vars.SwiftLibraryName = "$SWIFT_LIBRARY_NAME";
+ vars.SwiftModule = "$SWIFT_MODULE";
+ vars.SwiftModuleName = "$SWIFT_MODULE_NAME";
+ vars.SwiftOutputFileMap = "$SWIFT_OUTPUT_FILE_MAP";
+ vars.SwiftSources = "$SWIFT_SOURCES";
+
+ vars.Defines = "$DEFINES";
+ vars.Flags = "$FLAGS";
+ vars.Includes = "$INCLUDES";
+ }
+
+ std::string responseFlag;
+
+ std::string cmakeVarLang =
+ cmStrCat("CMAKE_", this->TargetLinkLanguage(config));
+
+ // build response file name
+ std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
+ cmProp flag = this->GetMakefile()->GetDefinition(cmakeLinkVar);
+
+ if (flag) {
+ responseFlag = *flag;
+ } else {
+ responseFlag = "@";
+ }
+
+ if (!useResponseFile || responseFlag.empty()) {
+ vars.Objects = "$in";
+ vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
+ } else {
+ rule.RspFile = "$RSP_FILE";
+ responseFlag += rule.RspFile;
+
+ // build response file content
+ if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
+ rule.RspContent = "$in";
+ } else {
+ rule.RspContent = "$in_newline";
+ }
+ rule.RspContent += " $LINK_PATH $LINK_LIBRARIES";
+ if (this->TargetLinkLanguage(config) == "Swift") {
+ vars.SwiftSources = responseFlag.c_str();
+ } else {
+ vars.Objects = responseFlag.c_str();
+ }
+ vars.LinkLibraries = "";
+ }
+
+ vars.ObjectDir = "$OBJECT_DIR";
+
+ vars.Target = "$TARGET_FILE";
+
+ vars.SONameFlag = "$SONAME_FLAG";
+ vars.TargetSOName = "$SONAME";
+ vars.TargetInstallNameDir = "$INSTALLNAME_DIR";
+ vars.TargetPDB = "$TARGET_PDB";
+
+ // Setup the target version.
+ std::string targetVersionMajor;
+ std::string targetVersionMinor;
+ {
+ std::ostringstream majorStream;
+ std::ostringstream minorStream;
+ int major;
+ int minor;
+ this->GetGeneratorTarget()->GetTargetVersion(major, minor);
+ majorStream << major;
+ minorStream << minor;
+ targetVersionMajor = majorStream.str();
+ targetVersionMinor = minorStream.str();
+ }
+ vars.TargetVersionMajor = targetVersionMajor.c_str();
+ vars.TargetVersionMinor = targetVersionMinor.c_str();
+
+ vars.Flags = "$FLAGS";
+ vars.LinkFlags = "$LINK_FLAGS";
+ vars.Manifests = "$MANIFESTS";
+
+ std::string langFlags;
+ if (targetType != cmStateEnums::EXECUTABLE) {
+ langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS";
+ vars.LanguageCompileFlags = langFlags.c_str();
+ }
+
+ std::string launcher;
+ cmProp val = this->GetLocalGenerator()->GetRuleLauncher(
+ this->GetGeneratorTarget(), "RULE_LAUNCH_LINK");
+ if (cmNonempty(val)) {
+ launcher = cmStrCat(*val, ' ');
+ }
+
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->GetLocalGenerator()->CreateRulePlaceholderExpander());
+
+ // Rule for linking library/executable.
+ std::vector<std::string> linkCmds = this->ComputeLinkCmd(config);
+ for (std::string& linkCmd : linkCmds) {
+ linkCmd = cmStrCat(launcher, linkCmd);
+ rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
+ linkCmd, vars);
+ }
+
+ // If there is no ranlib the command will be ":". Skip it.
+ cm::erase_if(linkCmds, cmNinjaRemoveNoOpCommands());
+
+ linkCmds.insert(linkCmds.begin(), "$PRE_LINK");
+ linkCmds.emplace_back("$POST_BUILD");
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(linkCmds);
+
+ // Write the linker rule with response file if needed.
+ rule.Comment =
+ cmStrCat("Rule for linking ", this->TargetLinkLanguage(config), ' ',
+ this->GetVisibleTypeName(), '.');
+ rule.Description =
+ cmStrCat("Linking ", this->TargetLinkLanguage(config), ' ',
+ this->GetVisibleTypeName(), " $TARGET_FILE");
+ rule.Restat = "$RESTAT";
+ this->GetGlobalGenerator()->AddRule(rule);
+ }
+
+ auto const tgtNames = this->TargetNames(config);
+ if (tgtNames.Output != tgtNames.Real &&
+ !this->GetGeneratorTarget()->IsFrameworkOnApple()) {
+ std::string cmakeCommand =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
+ if (targetType == cmStateEnums::EXECUTABLE) {
+ cmNinjaRule rule("CMAKE_SYMLINK_EXECUTABLE");
+ {
+ std::vector<std::string> cmd;
+ cmd.push_back(cmakeCommand + " -E cmake_symlink_executable $in $out");
+ cmd.emplace_back("$POST_BUILD");
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(cmd);
+ }
+ rule.Description = "Creating executable symlink $out";
+ rule.Comment = "Rule for creating executable symlink.";
+ this->GetGlobalGenerator()->AddRule(rule);
+ } else {
+ cmNinjaRule rule("CMAKE_SYMLINK_LIBRARY");
+ {
+ std::vector<std::string> cmd;
+ cmd.push_back(cmakeCommand +
+ " -E cmake_symlink_library $in $SONAME $out");
+ cmd.emplace_back("$POST_BUILD");
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(cmd);
+ }
+ rule.Description = "Creating library symlink $out";
+ rule.Comment = "Rule for creating library symlink.";
+ this->GetGlobalGenerator()->AddRule(rule);
+ }
+ }
+}
+
+std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeDeviceLinkCmd()
+{
+ std::vector<std::string> linkCmds;
+
+ // this target requires separable cuda compilation
+ // now build the correct command depending on if the target is
+ // an executable or a dynamic library.
+ std::string linkCmd;
+ switch (this->GetGeneratorTarget()->GetType()) {
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY: {
+ this->GetMakefile()->GetDefExpandList("CMAKE_CUDA_DEVICE_LINK_LIBRARY",
+ linkCmds);
+ } break;
+ case cmStateEnums::EXECUTABLE: {
+ this->GetMakefile()->GetDefExpandList(
+ "CMAKE_CUDA_DEVICE_LINK_EXECUTABLE", linkCmds);
+ } break;
+ default:
+ break;
+ }
+ return linkCmds;
+}
+
+std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd(
+ const std::string& config)
+{
+ std::vector<std::string> linkCmds;
+ cmMakefile* mf = this->GetMakefile();
+ {
+ // If we have a rule variable prefer it. In the case of static libraries
+ // this occurs when things like IPO is enabled, and we need to use the
+ // CMAKE_<lang>_CREATE_STATIC_LIBRARY_IPO define instead.
+ std::string linkCmdVar = this->GetGeneratorTarget()->GetCreateRuleVariable(
+ this->TargetLinkLanguage(config), config);
+ cmProp linkCmd = mf->GetDefinition(linkCmdVar);
+ if (linkCmd) {
+ std::string linkCmdStr = *linkCmd;
+ if (this->GetGeneratorTarget()->HasImplibGNUtoMS(config)) {
+ std::string ruleVar =
+ cmStrCat("CMAKE_", this->GeneratorTarget->GetLinkerLanguage(config),
+ "_GNUtoMS_RULE");
+ if (cmProp rule = this->Makefile->GetDefinition(ruleVar)) {
+ linkCmdStr += *rule;
+ }
+ }
+ cmExpandList(linkCmdStr, linkCmds);
+ if (this->GetGeneratorTarget()->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
+ std::string cmakeCommand = cmStrCat(
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL),
+ " -E __run_co_compile --lwyu=");
+ cmGeneratorTarget& gt = *this->GetGeneratorTarget();
+ std::string targetOutputReal = this->ConvertToNinjaPath(
+ gt.GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact,
+ /*realname=*/true));
+ cmakeCommand += targetOutputReal;
+ linkCmds.push_back(std::move(cmakeCommand));
+ }
+ return linkCmds;
+ }
+ }
+ switch (this->GetGeneratorTarget()->GetType()) {
+ case cmStateEnums::STATIC_LIBRARY: {
+ // We have archive link commands set. First, delete the existing archive.
+ {
+ std::string cmakeCommand =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
+ linkCmds.push_back(cmakeCommand + " -E rm -f $TARGET_FILE");
+ }
+ // TODO: Use ARCHIVE_APPEND for archives over a certain size.
+ {
+ std::string linkCmdVar = cmStrCat(
+ "CMAKE_", this->TargetLinkLanguage(config), "_ARCHIVE_CREATE");
+
+ linkCmdVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable(
+ linkCmdVar, this->TargetLinkLanguage(config), config);
+
+ std::string const& linkCmd = mf->GetRequiredDefinition(linkCmdVar);
+ cmExpandList(linkCmd, linkCmds);
+ }
+ {
+ std::string linkCmdVar = cmStrCat(
+ "CMAKE_", this->TargetLinkLanguage(config), "_ARCHIVE_FINISH");
+
+ linkCmdVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable(
+ linkCmdVar, this->TargetLinkLanguage(config), config);
+
+ std::string const& linkCmd = mf->GetRequiredDefinition(linkCmdVar);
+ cmExpandList(linkCmd, linkCmds);
+ }
+#ifdef __APPLE__
+ // On macOS ranlib truncates the fractional part of the static archive
+ // file modification time. If the archive and at least one contained
+ // object file were created within the same second this will make look
+ // the archive older than the object file. On subsequent ninja runs this
+ // leads to re-achiving and updating dependent targets.
+ // As a work-around we touch the archive after ranlib (see #19222).
+ {
+ std::string cmakeCommand =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
+ linkCmds.push_back(cmakeCommand + " -E touch $TARGET_FILE");
+ }
+#endif
+ } break;
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ break;
+ case cmStateEnums::EXECUTABLE:
+ if (this->TargetLinkLanguage(config) == "Swift") {
+ if (this->GeneratorTarget->IsExecutableWithExports()) {
+ this->Makefile->GetDefExpandList("CMAKE_EXE_EXPORTS_Swift_FLAG",
+ linkCmds);
+ }
+ }
+ break;
+ default:
+ assert(false && "Unexpected target type");
+ }
+ return linkCmds;
+}
+
+void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement(
+ const std::string& config, const std::string& fileConfig,
+ bool firstForConfig)
+{
+ cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
+ if (!globalGen->GetLanguageEnabled("CUDA")) {
+ return;
+ }
+
+ cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
+
+ bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->GetLocalGenerator(), config);
+ if (!requiresDeviceLinking) {
+ return;
+ }
+
+ // First and very important step is to make sure while inside this
+ // step our link language is set to CUDA
+ std::string const& objExt =
+ this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION");
+
+ std::string targetOutputDir =
+ cmStrCat(this->GetLocalGenerator()->GetTargetDirectory(genTarget),
+ globalGen->ConfigDirectory(config), "/");
+ targetOutputDir = globalGen->ExpandCFGIntDir(targetOutputDir, config);
+
+ std::string targetOutputReal =
+ this->ConvertToNinjaPath(targetOutputDir + "cmake_device_link" + objExt);
+
+ if (firstForConfig) {
+ globalGen->GetByproductsForCleanTarget(config).push_back(targetOutputReal);
+ }
+ this->DeviceLinkObject = targetOutputReal;
+
+ // Write comments.
+ cmGlobalNinjaGenerator::WriteDivider(this->GetCommonFileStream());
+ this->GetCommonFileStream()
+ << "# Device Link build statements for "
+ << cmState::GetTargetTypeName(genTarget->GetType()) << " target "
+ << this->GetTargetName() << "\n\n";
+
+ if (this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID") == "Clang") {
+ std::string architecturesStr =
+ this->GeneratorTarget->GetSafeProperty("CUDA_ARCHITECTURES");
+
+ if (cmIsOff(architecturesStr)) {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ "CUDA_SEPARABLE_COMPILATION on Clang "
+ "requires CUDA_ARCHITECTURES to be set.");
+ return;
+ }
+
+ this->WriteDeviceLinkRules(config);
+ this->WriteDeviceLinkStatements(config, cmExpandedList(architecturesStr),
+ targetOutputReal);
+ } else {
+ this->WriteNvidiaDeviceLinkStatement(config, fileConfig, targetOutputDir,
+ targetOutputReal);
+ }
+}
+
+void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatements(
+ const std::string& config, const std::vector<std::string>& architectures,
+ const std::string& output)
+{
+ // Ensure there are no duplicates.
+ const cmNinjaDeps explicitDeps = [&]() -> std::vector<std::string> {
+ std::unordered_set<std::string> depsSet;
+ const cmNinjaDeps linkDeps =
+ this->ComputeLinkDeps(this->TargetLinkLanguage(config), config, true);
+ const cmNinjaDeps objects = this->GetObjects(config);
+ depsSet.insert(linkDeps.begin(), linkDeps.end());
+ depsSet.insert(objects.begin(), objects.end());
+
+ std::vector<std::string> deps;
+ std::copy(depsSet.begin(), depsSet.end(), std::back_inserter(deps));
+ return deps;
+ }();
+
+ const std::string objectDir =
+ cmStrCat(this->GeneratorTarget->GetSupportDirectory(),
+ this->GetGlobalGenerator()->ConfigDirectory(config));
+ const std::string ninjaOutputDir = this->ConvertToNinjaPath(objectDir);
+
+ cmNinjaBuild fatbinary(this->LanguageLinkerCudaFatbinaryRule(config));
+
+ // Link device code for each architecture.
+ for (const std::string& architectureKind : architectures) {
+ // Clang always generates real code, so strip the specifier.
+ const std::string architecture =
+ architectureKind.substr(0, architectureKind.find('-'));
+ const std::string cubin =
+ cmStrCat(ninjaOutputDir, "/sm_", architecture, ".cubin");
+
+ fatbinary.Variables["PROFILES"] +=
+ cmStrCat(" -im=profile=sm_", architecture, ",file=", cubin);
+ fatbinary.ExplicitDeps.emplace_back(cubin);
+
+ cmNinjaBuild dlink(this->LanguageLinkerCudaDeviceRule(config));
+ dlink.ExplicitDeps = explicitDeps;
+ dlink.Outputs = { cubin };
+ dlink.Variables["ARCH"] = cmStrCat("sm_", architecture);
+
+ // The generated register file contains macros that when expanded register
+ // the device routines. Because the routines are the same for all
+ // architectures the register file will be the same too. Thus generate it
+ // only on the first invocation to reduce overhead.
+ if (fatbinary.ExplicitDeps.size() == 1) {
+ dlink.Variables["REGISTER"] = cmStrCat(
+ "--register-link-binaries=", ninjaOutputDir, "/cmake_cuda_register.h");
+ }
+
+ this->GetGlobalGenerator()->WriteBuild(this->GetCommonFileStream(), dlink);
+ }
+
+ // Combine all architectures into a single fatbinary.
+ fatbinary.Outputs = { cmStrCat(ninjaOutputDir, "/cmake_cuda_fatbin.h") };
+ this->GetGlobalGenerator()->WriteBuild(this->GetCommonFileStream(),
+ fatbinary);
+
+ // Compile the stub that registers the kernels and contains the fatbinaries.
+ cmNinjaBuild dcompile(this->LanguageLinkerCudaDeviceCompileRule(config));
+ dcompile.Outputs = { output };
+ dcompile.ExplicitDeps = { cmStrCat(ninjaOutputDir, "/cmake_cuda_fatbin.h") };
+ dcompile.Variables["FATBIN"] =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmStrCat(objectDir, "/cmake_cuda_fatbin.h"), cmOutputConverter::SHELL);
+ dcompile.Variables["REGISTER"] =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmStrCat(objectDir, "/cmake_cuda_register.h"), cmOutputConverter::SHELL);
+ this->GetGlobalGenerator()->WriteBuild(this->GetCommonFileStream(),
+ dcompile);
+}
+
+void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkStatement(
+ const std::string& config, const std::string& fileConfig,
+ const std::string& outputDir, const std::string& output)
+{
+ cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
+ cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
+
+ std::string targetOutputImplib = this->ConvertToNinjaPath(
+ genTarget->GetFullPath(config, cmStateEnums::ImportLibraryArtifact));
+
+ if (config != fileConfig) {
+ std::string targetOutputFileConfigDir =
+ cmStrCat(this->GetLocalGenerator()->GetTargetDirectory(genTarget),
+ globalGen->ConfigDirectory(fileConfig), "/");
+ targetOutputFileConfigDir =
+ globalGen->ExpandCFGIntDir(outputDir, fileConfig);
+ if (outputDir == targetOutputFileConfigDir) {
+ return;
+ }
+
+ if (!genTarget->GetFullName(config, cmStateEnums::ImportLibraryArtifact)
+ .empty() &&
+ !genTarget
+ ->GetFullName(fileConfig, cmStateEnums::ImportLibraryArtifact)
+ .empty() &&
+ targetOutputImplib ==
+ this->ConvertToNinjaPath(genTarget->GetFullPath(
+ fileConfig, cmStateEnums::ImportLibraryArtifact))) {
+ return;
+ }
+ }
+
+ // Compute the comment.
+ cmNinjaBuild build(this->LanguageLinkerDeviceRule(config));
+ build.Comment =
+ cmStrCat("Link the ", this->GetVisibleTypeName(), ' ', output);
+
+ cmNinjaVars& vars = build.Variables;
+
+ // Compute outputs.
+ build.Outputs.push_back(output);
+ // Compute specific libraries to link with.
+ build.ExplicitDeps = this->GetObjects(config);
+ build.ImplicitDeps =
+ this->ComputeLinkDeps(this->TargetLinkLanguage(config), config);
+
+ std::string frameworkPath;
+ std::string linkPath;
+
+ std::string createRule =
+ genTarget->GetCreateRuleVariable(this->TargetLinkLanguage(config), config);
+ const bool useWatcomQuote =
+ this->GetMakefile()->IsOn(createRule + "_USE_WATCOM_QUOTE");
+ cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
+
+ vars["TARGET_FILE"] =
+ localGen.ConvertToOutputFormat(output, cmOutputConverter::SHELL);
+
+ std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+ new cmNinjaLinkLineDeviceComputer(
+ this->GetLocalGenerator(),
+ this->GetLocalGenerator()->GetStateSnapshot().GetDirectory(),
+ globalGen));
+ linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
+ linkLineComputer->SetUseNinjaMulti(globalGen->IsMultiConfig());
+
+ localGen.GetDeviceLinkFlags(linkLineComputer.get(), config,
+ vars["LINK_LIBRARIES"], vars["LINK_FLAGS"],
+ frameworkPath, linkPath, genTarget);
+
+ this->addPoolNinjaVariable("JOB_POOL_LINK", genTarget, vars);
+
+ vars["LINK_FLAGS"] = globalGen->EncodeLiteral(vars["LINK_FLAGS"]);
+
+ vars["MANIFESTS"] = this->GetManifests(config);
+
+ vars["LINK_PATH"] = frameworkPath + linkPath;
+
+ // Compute language specific link flags.
+ std::string langFlags;
+ localGen.AddLanguageFlagsForLinking(langFlags, genTarget, "CUDA", config);
+ vars["LANGUAGE_COMPILE_FLAGS"] = langFlags;
+
+ auto const tgtNames = this->TargetNames(config);
+ if (genTarget->HasSOName(config)) {
+ vars["SONAME_FLAG"] =
+ this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage(config));
+ vars["SONAME"] = localGen.ConvertToOutputFormat(tgtNames.SharedObject,
+ cmOutputConverter::SHELL);
+ if (genTarget->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ std::string install_dir =
+ this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(config);
+ if (!install_dir.empty()) {
+ vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat(
+ install_dir, cmOutputConverter::SHELL);
+ }
+ }
+ }
+
+ if (!tgtNames.ImportLibrary.empty()) {
+ const std::string impLibPath = localGen.ConvertToOutputFormat(
+ targetOutputImplib, cmOutputConverter::SHELL);
+ vars["TARGET_IMPLIB"] = impLibPath;
+ this->EnsureParentDirectoryExists(impLibPath);
+ }
+
+ const std::string objPath =
+ cmStrCat(this->GetGeneratorTarget()->GetSupportDirectory(),
+ globalGen->ConfigDirectory(config));
+
+ vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
+ this->EnsureDirectoryExists(objPath);
+
+ this->SetMsvcTargetPdbVariable(vars, config);
+
+ std::string& linkLibraries = vars["LINK_LIBRARIES"];
+ std::string& link_path = vars["LINK_PATH"];
+ if (globalGen->IsGCCOnWindows()) {
+ // ar.exe can't handle backslashes in rsp files (implicitly used by gcc)
+ std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/');
+ std::replace(link_path.begin(), link_path.end(), '\\', '/');
+ }
+
+ // Device linking currently doesn't support response files so
+ // do not check if the user has explicitly forced a response file.
+ int const commandLineLengthLimit =
+ static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
+ globalGen->GetRuleCmdLength(build.Rule);
+
+ build.RspFile = this->ConvertToNinjaPath(
+ cmStrCat("CMakeFiles/", genTarget->GetName(),
+ globalGen->IsMultiConfig() ? cmStrCat('.', config) : "", ".rsp"));
+
+ // Gather order-only dependencies.
+ this->GetLocalGenerator()->AppendTargetDepends(
+ this->GetGeneratorTarget(), build.OrderOnlyDeps, config, config,
+ DependOnTargetArtifact);
+
+ // Write the build statement for this target.
+ bool usedResponseFile = false;
+ globalGen->WriteBuild(this->GetCommonFileStream(), build,
+ commandLineLengthLimit, &usedResponseFile);
+ this->WriteNvidiaDeviceLinkRule(usedResponseFile, config);
+}
+
+void cmNinjaNormalTargetGenerator::WriteLinkStatement(
+ const std::string& config, const std::string& fileConfig,
+ bool firstForConfig)
+{
+ cmMakefile* mf = this->GetMakefile();
+ cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
+ cmGeneratorTarget* gt = this->GetGeneratorTarget();
+
+ std::string targetOutput = this->ConvertToNinjaPath(gt->GetFullPath(config));
+ std::string targetOutputReal = this->ConvertToNinjaPath(
+ gt->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact,
+ /*realname=*/true));
+ std::string targetOutputImplib = this->ConvertToNinjaPath(
+ gt->GetFullPath(config, cmStateEnums::ImportLibraryArtifact));
+
+ if (config != fileConfig) {
+ if (targetOutput ==
+ this->ConvertToNinjaPath(gt->GetFullPath(fileConfig))) {
+ return;
+ }
+ if (targetOutputReal ==
+ this->ConvertToNinjaPath(
+ gt->GetFullPath(fileConfig, cmStateEnums::RuntimeBinaryArtifact,
+ /*realname=*/true))) {
+ return;
+ }
+ if (!gt->GetFullName(config, cmStateEnums::ImportLibraryArtifact)
+ .empty() &&
+ !gt->GetFullName(fileConfig, cmStateEnums::ImportLibraryArtifact)
+ .empty() &&
+ targetOutputImplib ==
+ this->ConvertToNinjaPath(gt->GetFullPath(
+ fileConfig, cmStateEnums::ImportLibraryArtifact))) {
+ return;
+ }
+ }
+
+ auto const tgtNames = this->TargetNames(config);
+ if (gt->IsAppBundleOnApple()) {
+ // Create the app bundle
+ std::string outpath = gt->GetDirectory(config);
+ this->OSXBundleGenerator->CreateAppBundle(tgtNames.Output, outpath,
+ config);
+
+ // Calculate the output path
+ targetOutput = cmStrCat(outpath, '/', tgtNames.Output);
+ targetOutput = this->ConvertToNinjaPath(targetOutput);
+ targetOutputReal = cmStrCat(outpath, '/', tgtNames.Real);
+ targetOutputReal = this->ConvertToNinjaPath(targetOutputReal);
+ } else if (gt->IsFrameworkOnApple()) {
+ // Create the library framework.
+
+ cmOSXBundleGenerator::SkipParts bundleSkipParts;
+ if (globalGen->GetName() == "Ninja Multi-Config") {
+ const auto postFix = this->GeneratorTarget->GetFilePostfix(config);
+ // Skip creating Info.plist when there are multiple configurations, and
+ // the current configuration has a postfix. The non-postfix configuration
+ // Info.plist can be used by all the other configurations.
+ if (!postFix.empty()) {
+ bundleSkipParts.infoPlist = true;
+ }
+ }
+
+ this->OSXBundleGenerator->CreateFramework(
+ tgtNames.Output, gt->GetDirectory(config), config, bundleSkipParts);
+ } else if (gt->IsCFBundleOnApple()) {
+ // Create the core foundation bundle.
+ this->OSXBundleGenerator->CreateCFBundle(tgtNames.Output,
+ gt->GetDirectory(config), config);
+ }
+
+ // Write comments.
+ cmGlobalNinjaGenerator::WriteDivider(this->GetImplFileStream(fileConfig));
+ const cmStateEnums::TargetType targetType = gt->GetType();
+ this->GetImplFileStream(fileConfig)
+ << "# Link build statements for " << cmState::GetTargetTypeName(targetType)
+ << " target " << this->GetTargetName() << "\n\n";
+
+ cmNinjaBuild linkBuild(this->LanguageLinkerRule(config));
+ cmNinjaVars& vars = linkBuild.Variables;
+
+ // Compute the comment.
+ linkBuild.Comment =
+ cmStrCat("Link the ", this->GetVisibleTypeName(), ' ', targetOutputReal);
+
+ // Compute outputs.
+ linkBuild.Outputs.push_back(targetOutputReal);
+ if (firstForConfig) {
+ globalGen->GetByproductsForCleanTarget(config).push_back(targetOutputReal);
+ }
+
+ if (this->TargetLinkLanguage(config) == "Swift") {
+ vars["SWIFT_LIBRARY_NAME"] = [this, config]() -> std::string {
+ cmGeneratorTarget::Names targetNames =
+ this->GetGeneratorTarget()->GetLibraryNames(config);
+ return targetNames.Base;
+ }();
+
+ vars["SWIFT_MODULE_NAME"] = [gt]() -> std::string {
+ if (cmProp name = gt->GetProperty("Swift_MODULE_NAME")) {
+ return *name;
+ }
+ return gt->GetName();
+ }();
+
+ vars["SWIFT_MODULE"] = [this](const std::string& module) -> std::string {
+ std::string directory =
+ this->GetLocalGenerator()->GetCurrentBinaryDirectory();
+ if (cmProp prop = this->GetGeneratorTarget()->GetProperty(
+ "Swift_MODULE_DIRECTORY")) {
+ directory = *prop;
+ }
+
+ std::string name = module + ".swiftmodule";
+ if (cmProp prop =
+ this->GetGeneratorTarget()->GetProperty("Swift_MODULE")) {
+ name = *prop;
+ }
+
+ return this->GetLocalGenerator()->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(directory + "/" + name),
+ cmOutputConverter::SHELL);
+ }(vars["SWIFT_MODULE_NAME"]);
+
+ const std::string map = cmStrCat(gt->GetSupportDirectory(), '/', config,
+ '/', "output-file-map.json");
+ vars["SWIFT_OUTPUT_FILE_MAP"] =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(map), cmOutputConverter::SHELL);
+
+ vars["SWIFT_SOURCES"] = [this, config]() -> std::string {
+ std::vector<cmSourceFile const*> sources;
+ std::stringstream oss;
+
+ this->GetGeneratorTarget()->GetObjectSources(sources, config);
+ cmLocalGenerator const* LocalGen = this->GetLocalGenerator();
+ for (const auto& source : sources) {
+ oss << " "
+ << LocalGen->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(this->GetSourceFilePath(source)),
+ cmOutputConverter::SHELL);
+ }
+ return oss.str();
+ }();
+
+ // Since we do not perform object builds, compute the
+ // defines/flags/includes here so that they can be passed along
+ // appropriately.
+ vars["DEFINES"] = this->GetDefines("Swift", config);
+ vars["FLAGS"] = this->GetFlags("Swift", config);
+ vars["INCLUDES"] = this->GetIncludes("Swift", config);
+ }
+
+ // Compute specific libraries to link with.
+ if (this->TargetLinkLanguage(config) == "Swift") {
+ std::vector<cmSourceFile const*> sources;
+ gt->GetObjectSources(sources, config);
+ for (const auto& source : sources) {
+ linkBuild.Outputs.push_back(
+ this->ConvertToNinjaPath(this->GetObjectFilePath(source, config)));
+ linkBuild.ExplicitDeps.push_back(
+ this->ConvertToNinjaPath(this->GetSourceFilePath(source)));
+ }
+ linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]);
+ } else {
+ linkBuild.ExplicitDeps = this->GetObjects(config);
+ }
+
+ std::vector<std::string> extraISPCObjects =
+ this->GetGeneratorTarget()->GetGeneratedISPCObjects(config);
+ std::transform(extraISPCObjects.begin(), extraISPCObjects.end(),
+ std::back_inserter(linkBuild.ExplicitDeps),
+ this->MapToNinjaPath());
+
+ linkBuild.ImplicitDeps =
+ this->ComputeLinkDeps(this->TargetLinkLanguage(config), config);
+
+ if (!this->DeviceLinkObject.empty()) {
+ linkBuild.ExplicitDeps.push_back(this->DeviceLinkObject);
+ }
+
+ std::string frameworkPath;
+ std::string linkPath;
+
+ std::string createRule =
+ gt->GetCreateRuleVariable(this->TargetLinkLanguage(config), config);
+ bool useWatcomQuote = mf->IsOn(createRule + "_USE_WATCOM_QUOTE");
+ cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
+
+ vars["TARGET_FILE"] =
+ localGen.ConvertToOutputFormat(targetOutputReal, cmOutputConverter::SHELL);
+
+ std::unique_ptr<cmLinkLineComputer> linkLineComputer =
+ globalGen->CreateLinkLineComputer(
+ this->GetLocalGenerator(),
+ this->GetLocalGenerator()->GetStateSnapshot().GetDirectory());
+ linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
+ linkLineComputer->SetUseNinjaMulti(globalGen->IsMultiConfig());
+
+ localGen.GetTargetFlags(linkLineComputer.get(), config,
+ vars["LINK_LIBRARIES"], vars["FLAGS"],
+ vars["LINK_FLAGS"], frameworkPath, linkPath, gt);
+
+ // Add OS X version flags, if any.
+ if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ this->AppendOSXVerFlag(vars["LINK_FLAGS"],
+ this->TargetLinkLanguage(config), "COMPATIBILITY",
+ true);
+ this->AppendOSXVerFlag(vars["LINK_FLAGS"],
+ this->TargetLinkLanguage(config), "CURRENT", false);
+ }
+
+ this->addPoolNinjaVariable("JOB_POOL_LINK", gt, vars);
+
+ this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"],
+ config);
+ vars["LINK_FLAGS"] = globalGen->EncodeLiteral(vars["LINK_FLAGS"]);
+
+ vars["MANIFESTS"] = this->GetManifests(config);
+ vars["AIX_EXPORTS"] = this->GetAIXExports(config);
+
+ vars["LINK_PATH"] = frameworkPath + linkPath;
+ std::string lwyuFlags;
+ if (gt->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
+ lwyuFlags = " -Wl,--no-as-needed";
+ }
+
+ // Compute architecture specific link flags. Yes, these go into a different
+ // variable for executables, probably due to a mistake made when duplicating
+ // code between the Makefile executable and library generators.
+ if (targetType == cmStateEnums::EXECUTABLE) {
+ std::string t = vars["FLAGS"];
+ localGen.AddArchitectureFlags(t, gt, this->TargetLinkLanguage(config),
+ config);
+ t += lwyuFlags;
+ vars["FLAGS"] = t;
+ } else {
+ std::string t = vars["ARCH_FLAGS"];
+ localGen.AddArchitectureFlags(t, gt, this->TargetLinkLanguage(config),
+ config);
+ vars["ARCH_FLAGS"] = t;
+ t.clear();
+ t += lwyuFlags;
+ localGen.AddLanguageFlagsForLinking(
+ t, gt, this->TargetLinkLanguage(config), config);
+ vars["LANGUAGE_COMPILE_FLAGS"] = t;
+ }
+ if (gt->HasSOName(config)) {
+ vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage(config));
+ vars["SONAME"] = localGen.ConvertToOutputFormat(tgtNames.SharedObject,
+ cmOutputConverter::SHELL);
+ if (targetType == cmStateEnums::SHARED_LIBRARY) {
+ std::string install_dir = gt->GetInstallNameDirForBuildTree(config);
+ if (!install_dir.empty()) {
+ vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat(
+ install_dir, cmOutputConverter::SHELL);
+ }
+ }
+ }
+
+ cmNinjaDeps byproducts;
+
+ if (!tgtNames.ImportLibrary.empty()) {
+ const std::string impLibPath = localGen.ConvertToOutputFormat(
+ targetOutputImplib, cmOutputConverter::SHELL);
+ vars["TARGET_IMPLIB"] = impLibPath;
+ this->EnsureParentDirectoryExists(impLibPath);
+ if (gt->HasImportLibrary(config)) {
+ byproducts.push_back(targetOutputImplib);
+ if (firstForConfig) {
+ globalGen->GetByproductsForCleanTarget(config).push_back(
+ targetOutputImplib);
+ }
+ }
+ }
+
+ if (!this->SetMsvcTargetPdbVariable(vars, config)) {
+ // It is common to place debug symbols at a specific place,
+ // so we need a plain target name in the rule available.
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ gt->GetFullNameComponents(prefix, base, suffix, config);
+ std::string dbg_suffix = ".dbg";
+ // TODO: Where to document?
+ if (cmProp d = mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) {
+ dbg_suffix = *d;
+ }
+ vars["TARGET_PDB"] = base + suffix + dbg_suffix;
+ }
+
+ const std::string objPath =
+ cmStrCat(gt->GetSupportDirectory(), globalGen->ConfigDirectory(config));
+ vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
+ this->EnsureDirectoryExists(objPath);
+
+ std::string& linkLibraries = vars["LINK_LIBRARIES"];
+ std::string& link_path = vars["LINK_PATH"];
+ if (globalGen->IsGCCOnWindows()) {
+ // ar.exe can't handle backslashes in rsp files (implicitly used by gcc)
+ std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/');
+ std::replace(link_path.begin(), link_path.end(), '\\', '/');
+ }
+
+ const std::vector<cmCustomCommand>* cmdLists[3] = {
+ &gt->GetPreBuildCommands(), &gt->GetPreLinkCommands(),
+ &gt->GetPostBuildCommands()
+ };
+
+ std::vector<std::string> preLinkCmdLines;
+ std::vector<std::string> postBuildCmdLines;
+
+ std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines,
+ &preLinkCmdLines,
+ &postBuildCmdLines };
+
+ for (unsigned i = 0; i != 3; ++i) {
+ for (cmCustomCommand const& cc : *cmdLists[i]) {
+ if (config == fileConfig ||
+ this->GetLocalGenerator()->HasUniqueByproducts(cc.GetByproducts(),
+ cc.GetBacktrace())) {
+ cmCustomCommandGenerator ccg(cc, fileConfig, this->GetLocalGenerator(),
+ true, config);
+ localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]);
+ std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
+ std::transform(ccByproducts.begin(), ccByproducts.end(),
+ std::back_inserter(byproducts), this->MapToNinjaPath());
+ std::transform(
+ ccByproducts.begin(), ccByproducts.end(),
+ std::back_inserter(globalGen->GetByproductsForCleanTarget()),
+ this->MapToNinjaPath());
+ }
+ }
+ }
+
+ // maybe create .def file from list of objects
+ cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
+ gt->GetModuleDefinitionInfo(config);
+ if (mdi && mdi->DefFileGenerated) {
+ std::string cmakeCommand =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
+ std::string cmd =
+ cmStrCat(cmakeCommand, " -E __create_def ",
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ mdi->DefFile, cmOutputConverter::SHELL),
+ ' ');
+ std::string obj_list_file = mdi->DefFile + ".objs";
+ cmd += this->GetLocalGenerator()->ConvertToOutputFormat(
+ obj_list_file, cmOutputConverter::SHELL);
+
+ cmProp nm_executable = this->GetMakefile()->GetDefinition("CMAKE_NM");
+ if (cmNonempty(nm_executable)) {
+ cmd += " --nm=";
+ cmd += this->LocalCommonGenerator->ConvertToOutputFormat(
+ *nm_executable, cmOutputConverter::SHELL);
+ }
+ preLinkCmdLines.push_back(std::move(cmd));
+
+ // create a list of obj files for the -E __create_def to read
+ cmGeneratedFileStream fout(obj_list_file);
+
+ if (mdi->WindowsExportAllSymbols) {
+ cmNinjaDeps objs = this->GetObjects(config);
+ for (std::string const& obj : objs) {
+ if (cmHasLiteralSuffix(obj, ".obj")) {
+ fout << obj << "\n";
+ }
+ }
+ }
+
+ for (cmSourceFile const* src : mdi->Sources) {
+ fout << src->GetFullPath() << "\n";
+ }
+ }
+ // If we have any PRE_LINK commands, we need to go back to CMAKE_BINARY_DIR
+ // for the link commands.
+ if (!preLinkCmdLines.empty()) {
+ const std::string homeOutDir = localGen.ConvertToOutputFormat(
+ localGen.GetBinaryDirectory(), cmOutputConverter::SHELL);
+ preLinkCmdLines.push_back("cd " + homeOutDir);
+ }
+
+ vars["PRE_LINK"] = localGen.BuildCommandLine(preLinkCmdLines, "pre-link",
+ this->GeneratorTarget);
+ std::string postBuildCmdLine = localGen.BuildCommandLine(
+ postBuildCmdLines, "post-build", this->GeneratorTarget);
+
+ cmNinjaVars symlinkVars;
+ bool const symlinkNeeded =
+ (targetOutput != targetOutputReal && !gt->IsFrameworkOnApple());
+ if (!symlinkNeeded) {
+ vars["POST_BUILD"] = postBuildCmdLine;
+ } else {
+ vars["POST_BUILD"] = cmGlobalNinjaGenerator::SHELL_NOOP;
+ symlinkVars["POST_BUILD"] = postBuildCmdLine;
+ }
+
+ std::string cmakeVarLang =
+ cmStrCat("CMAKE_", this->TargetLinkLanguage(config));
+
+ // build response file name
+ std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
+
+ cmProp flag = this->GetMakefile()->GetDefinition(cmakeLinkVar);
+
+ bool const lang_supports_response =
+ !(this->TargetLinkLanguage(config) == "RC" ||
+ (this->TargetLinkLanguage(config) == "CUDA" && !flag));
+ int commandLineLengthLimit = -1;
+ if (!lang_supports_response || !this->ForceResponseFile()) {
+ commandLineLengthLimit =
+ static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
+ globalGen->GetRuleCmdLength(linkBuild.Rule);
+ }
+
+ linkBuild.RspFile = this->ConvertToNinjaPath(
+ cmStrCat("CMakeFiles/", gt->GetName(),
+ globalGen->IsMultiConfig() ? cmStrCat('.', config) : "", ".rsp"));
+
+ // Gather order-only dependencies.
+ this->GetLocalGenerator()->AppendTargetDepends(
+ gt, linkBuild.OrderOnlyDeps, config, fileConfig, DependOnTargetArtifact);
+
+ // Add order-only dependencies on versioning symlinks of shared libs we link.
+ if (!this->GeneratorTarget->IsDLLPlatform()) {
+ if (cmComputeLinkInformation* cli =
+ this->GeneratorTarget->GetLinkInformation(config)) {
+ for (auto const& item : cli->GetItems()) {
+ if (item.Target &&
+ item.Target->GetType() == cmStateEnums::SHARED_LIBRARY &&
+ !item.Target->IsFrameworkOnApple()) {
+ std::string const& lib =
+ this->ConvertToNinjaPath(item.Target->GetFullPath(config));
+ if (std::find(linkBuild.ImplicitDeps.begin(),
+ linkBuild.ImplicitDeps.end(),
+ lib) == linkBuild.ImplicitDeps.end()) {
+ linkBuild.OrderOnlyDeps.emplace_back(lib);
+ }
+ }
+ }
+ }
+ }
+
+ // Ninja should restat after linking if and only if there are byproducts.
+ vars["RESTAT"] = byproducts.empty() ? "" : "1";
+
+ for (std::string const& o : byproducts) {
+ globalGen->SeenCustomCommandOutput(o);
+ linkBuild.Outputs.push_back(o);
+ }
+
+ // Write the build statement for this target.
+ bool usedResponseFile = false;
+ globalGen->WriteBuild(this->GetImplFileStream(fileConfig), linkBuild,
+ commandLineLengthLimit, &usedResponseFile);
+ this->WriteLinkRule(usedResponseFile, config);
+
+ if (symlinkNeeded) {
+ if (targetType == cmStateEnums::EXECUTABLE) {
+ cmNinjaBuild build("CMAKE_SYMLINK_EXECUTABLE");
+ build.Comment = "Create executable symlink " + targetOutput;
+ build.Outputs.push_back(targetOutput);
+ if (firstForConfig) {
+ globalGen->GetByproductsForCleanTarget(config).push_back(targetOutput);
+ }
+ build.ExplicitDeps.push_back(targetOutputReal);
+ build.Variables = std::move(symlinkVars);
+ globalGen->WriteBuild(this->GetImplFileStream(fileConfig), build);
+ } else {
+ cmNinjaBuild build("CMAKE_SYMLINK_LIBRARY");
+ build.Comment = "Create library symlink " + targetOutput;
+
+ std::string const soName = this->ConvertToNinjaPath(
+ this->GetTargetFilePath(tgtNames.SharedObject, config));
+ // If one link has to be created.
+ if (targetOutputReal == soName || targetOutput == soName) {
+ symlinkVars["SONAME"] =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ soName, cmOutputConverter::SHELL);
+ } else {
+ symlinkVars["SONAME"].clear();
+ build.Outputs.push_back(soName);
+ if (firstForConfig) {
+ globalGen->GetByproductsForCleanTarget(config).push_back(soName);
+ }
+ }
+ build.Outputs.push_back(targetOutput);
+ if (firstForConfig) {
+ globalGen->GetByproductsForCleanTarget(config).push_back(targetOutput);
+ }
+ build.ExplicitDeps.push_back(targetOutputReal);
+ build.Variables = std::move(symlinkVars);
+
+ globalGen->WriteBuild(this->GetImplFileStream(fileConfig), build);
+ }
+ }
+
+ // Add aliases for the file name and the target name.
+ globalGen->AddTargetAlias(tgtNames.Output, gt, config);
+ globalGen->AddTargetAlias(this->GetTargetName(), gt, config);
+}
+
+void cmNinjaNormalTargetGenerator::WriteObjectLibStatement(
+ const std::string& config)
+{
+ // Write a phony output that depends on all object files.
+ {
+ cmNinjaBuild build("phony");
+ build.Comment = "Object library " + this->GetTargetName();
+ this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
+ build.Outputs, config);
+ this->GetLocalGenerator()->AppendTargetOutputs(
+ this->GetGeneratorTarget(),
+ this->GetGlobalGenerator()->GetByproductsForCleanTarget(config), config);
+ build.ExplicitDeps = this->GetObjects(config);
+ this->GetGlobalGenerator()->WriteBuild(this->GetCommonFileStream(), build);
+ }
+
+ // Add aliases for the target name.
+ this->GetGlobalGenerator()->AddTargetAlias(
+ this->GetTargetName(), this->GetGeneratorTarget(), config);
+}
+
+cmGeneratorTarget::Names cmNinjaNormalTargetGenerator::TargetNames(
+ const std::string& config) const
+{
+ if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
+ return this->GeneratorTarget->GetExecutableNames(config);
+ }
+ return this->GeneratorTarget->GetLibraryNames(config);
+}
+
+std::string cmNinjaNormalTargetGenerator::TargetLinkLanguage(
+ const std::string& config) const
+{
+ return this->GeneratorTarget->GetLinkerLanguage(config);
+}
diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h
new file mode 100644
index 0000000..30127fe
--- /dev/null
+++ b/Source/cmNinjaNormalTargetGenerator.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 "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+#include "cmGeneratorTarget.h"
+#include "cmNinjaTargetGenerator.h"
+
+class cmNinjaNormalTargetGenerator : public cmNinjaTargetGenerator
+{
+public:
+ cmNinjaNormalTargetGenerator(cmGeneratorTarget* target);
+ ~cmNinjaNormalTargetGenerator() override;
+
+ void Generate(const std::string& config) override;
+
+private:
+ std::string LanguageLinkerRule(const std::string& config) const;
+ std::string LanguageLinkerDeviceRule(const std::string& config) const;
+ std::string LanguageLinkerCudaDeviceRule(const std::string& config) const;
+ std::string LanguageLinkerCudaDeviceCompileRule(
+ const std::string& config) const;
+ std::string LanguageLinkerCudaFatbinaryRule(const std::string& config) const;
+
+ const char* GetVisibleTypeName() const;
+ void WriteLanguagesRules(const std::string& config);
+
+ void WriteLinkRule(bool useResponseFile, const std::string& config);
+ void WriteDeviceLinkRules(const std::string& config);
+ void WriteNvidiaDeviceLinkRule(bool useResponseFile,
+ const std::string& config);
+
+ void WriteLinkStatement(const std::string& config,
+ const std::string& fileConfig, bool firstForConfig);
+ void WriteDeviceLinkStatement(const std::string& config,
+ const std::string& fileConfig,
+ bool firstForConfig);
+ void WriteDeviceLinkStatements(const std::string& config,
+ const std::vector<std::string>& architectures,
+ const std::string& output);
+ void WriteNvidiaDeviceLinkStatement(const std::string& config,
+ const std::string& fileConfig,
+ const std::string& outputDir,
+ const std::string& output);
+
+ void WriteObjectLibStatement(const std::string& config);
+
+ std::vector<std::string> ComputeLinkCmd(const std::string& config);
+ std::vector<std::string> ComputeDeviceLinkCmd();
+
+ // Target name info.
+ cmGeneratorTarget::Names TargetNames(const std::string& config) const;
+ std::string TargetLinkLanguage(const std::string& config) const;
+ std::string DeviceLinkObject;
+};
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
new file mode 100644
index 0000000..2e0ffdb
--- /dev/null
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -0,0 +1,1793 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmNinjaTargetGenerator.h"
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <map>
+#include <ostream>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include <cm3p/json/value.h>
+#include <cm3p/json/writer.h>
+
+#include "cmComputeLinkInformation.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmLocalNinjaGenerator.h"
+#include "cmMakefile.h"
+#include "cmNinjaNormalTargetGenerator.h"
+#include "cmNinjaUtilityTargetGenerator.h"
+#include "cmOutputConverter.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmRulePlaceholderExpander.h"
+#include "cmSourceFile.h"
+#include "cmStandardLevelResolver.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+std::unique_ptr<cmNinjaTargetGenerator> cmNinjaTargetGenerator::New(
+ cmGeneratorTarget* target)
+{
+ switch (target->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::OBJECT_LIBRARY:
+ return cm::make_unique<cmNinjaNormalTargetGenerator>(target);
+
+ case cmStateEnums::UTILITY:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ case cmStateEnums::GLOBAL_TARGET:
+ return cm::make_unique<cmNinjaUtilityTargetGenerator>(target);
+
+ default:
+ return std::unique_ptr<cmNinjaTargetGenerator>();
+ }
+}
+
+cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmGeneratorTarget* target)
+ : cmCommonTargetGenerator(target)
+ , OSXBundleGenerator(nullptr)
+ , LocalGenerator(
+ static_cast<cmLocalNinjaGenerator*>(target->GetLocalGenerator()))
+{
+ for (auto const& fileConfig :
+ target->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)) {
+ this->Configs[fileConfig].MacOSXContentGenerator =
+ cm::make_unique<MacOSXContentGeneratorType>(this, fileConfig);
+ }
+}
+
+cmNinjaTargetGenerator::~cmNinjaTargetGenerator() = default;
+
+cmGeneratedFileStream& cmNinjaTargetGenerator::GetImplFileStream(
+ const std::string& config) const
+{
+ return *this->GetGlobalGenerator()->GetImplFileStream(config);
+}
+
+cmGeneratedFileStream& cmNinjaTargetGenerator::GetCommonFileStream() const
+{
+ return *this->GetGlobalGenerator()->GetCommonFileStream();
+}
+
+cmGeneratedFileStream& cmNinjaTargetGenerator::GetRulesFileStream() const
+{
+ return *this->GetGlobalGenerator()->GetRulesFileStream();
+}
+
+cmGlobalNinjaGenerator* cmNinjaTargetGenerator::GetGlobalGenerator() const
+{
+ return this->LocalGenerator->GetGlobalNinjaGenerator();
+}
+
+std::string cmNinjaTargetGenerator::LanguageCompilerRule(
+ const std::string& lang, const std::string& config) const
+{
+ return cmStrCat(
+ lang, "_COMPILER__",
+ cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
+ '_', config);
+}
+
+std::string cmNinjaTargetGenerator::LanguagePreprocessAndScanRule(
+ std::string const& lang, const std::string& config) const
+{
+ return cmStrCat(
+ lang, "_PREPROCESS_SCAN__",
+ cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
+ '_', config);
+}
+
+std::string cmNinjaTargetGenerator::LanguageScanRule(
+ std::string const& lang, const std::string& config) const
+{
+ return cmStrCat(
+ lang, "_SCAN__",
+ cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
+ '_', config);
+}
+
+bool cmNinjaTargetGenerator::NeedExplicitPreprocessing(
+ std::string const& lang) const
+{
+ return lang == "Fortran";
+}
+
+bool cmNinjaTargetGenerator::CompileWithDefines(std::string const& lang) const
+{
+ return this->Makefile->IsOn(
+ cmStrCat("CMAKE_", lang, "_COMPILE_WITH_DEFINES"));
+}
+
+std::string cmNinjaTargetGenerator::LanguageDyndepRule(
+ const std::string& lang, const std::string& config) const
+{
+ return cmStrCat(
+ lang, "_DYNDEP__",
+ cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
+ '_', config);
+}
+
+bool cmNinjaTargetGenerator::NeedCxxModuleSupport(
+ std::string const& lang, std::string const& config) const
+{
+ if (lang != "CXX") {
+ return false;
+ }
+ if (!this->Makefile->IsOn("CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP")) {
+ return false;
+ }
+ cmGeneratorTarget const* tgt = this->GetGeneratorTarget();
+ cmStandardLevelResolver standardResolver(this->Makefile);
+ bool const uses_cxx20 =
+ standardResolver.HaveStandardAvailable(tgt, "CXX", config, "cxx_std_20");
+ return uses_cxx20 && this->GetGlobalGenerator()->CheckCxxModuleSupport();
+}
+
+bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang,
+ std::string const& config) const
+{
+ return lang == "Fortran" || this->NeedCxxModuleSupport(lang, config);
+}
+
+std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget(
+ const std::string& config)
+{
+ return this->GetGlobalGenerator()->OrderDependsTargetForTarget(
+ this->GeneratorTarget, config);
+}
+
+// TODO: Most of the code is picked up from
+// void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink),
+// void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
+// Refactor it.
+std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
+ cmSourceFile const* source, const std::string& language,
+ const std::string& config)
+{
+ std::vector<std::string> architectures;
+ std::unordered_map<std::string, std::string> pchSources;
+ this->GeneratorTarget->GetAppleArchs(config, architectures);
+ if (architectures.empty()) {
+ architectures.emplace_back();
+ }
+
+ std::string filterArch;
+ for (const std::string& arch : architectures) {
+ const std::string pchSource =
+ this->GeneratorTarget->GetPchSource(config, language, arch);
+ if (pchSource == source->GetFullPath()) {
+ filterArch = arch;
+ }
+ if (!pchSource.empty()) {
+ pchSources.insert(std::make_pair(pchSource, arch));
+ }
+ }
+
+ std::string flags;
+ // Explicitly add the explicit language flag before any other flag
+ // so user flags can override it.
+ this->GeneratorTarget->AddExplicitLanguageFlags(flags, *source);
+
+ if (!flags.empty()) {
+ flags += " ";
+ }
+ flags += this->GetFlags(language, config, filterArch);
+
+ // Add Fortran format flags.
+ if (language == "Fortran") {
+ this->AppendFortranFormatFlags(flags, *source);
+ this->AppendFortranPreprocessFlags(flags, *source);
+ }
+
+ // Add source file specific flags.
+ cmGeneratorExpressionInterpreter genexInterpreter(
+ this->LocalGenerator, config, this->GeneratorTarget, language);
+
+ const std::string COMPILE_FLAGS("COMPILE_FLAGS");
+ if (cmProp cflags = source->GetProperty(COMPILE_FLAGS)) {
+ this->LocalGenerator->AppendFlags(
+ flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));
+ }
+
+ const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
+ if (cmProp coptions = source->GetProperty(COMPILE_OPTIONS)) {
+ this->LocalGenerator->AppendCompileOptions(
+ flags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
+ }
+
+ // Add precompile headers compile options.
+ if (!pchSources.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
+ std::string pchOptions;
+ auto pchIt = pchSources.find(source->GetFullPath());
+ if (pchIt != pchSources.end()) {
+ pchOptions = this->GeneratorTarget->GetPchCreateCompileOptions(
+ config, language, pchIt->second);
+ } else {
+ pchOptions =
+ this->GeneratorTarget->GetPchUseCompileOptions(config, language);
+ }
+
+ this->LocalGenerator->AppendCompileOptions(
+ flags, genexInterpreter.Evaluate(pchOptions, COMPILE_OPTIONS));
+ }
+
+ return flags;
+}
+
+void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags,
+ std::string const& language,
+ const std::string& config)
+{
+ std::vector<std::string> includes;
+ this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
+ language, config);
+ // Add include directory flags.
+ std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
+ includes, this->GeneratorTarget, language, config, false,
+ // full include paths for RC needed by cmcldeps
+ language == "RC" ? cmLocalGenerator::IncludePathStyle::Absolute
+ : cmLocalGenerator::IncludePathStyle::Default);
+ if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
+ std::replace(includeFlags.begin(), includeFlags.end(), '\\', '/');
+ }
+
+ this->LocalGenerator->AppendFlags(languageFlags, includeFlags);
+}
+
+// TODO: Refactor with
+// void cmMakefileTargetGenerator::WriteTargetLanguageFlags().
+std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source,
+ const std::string& language,
+ const std::string& config)
+{
+ std::set<std::string> defines;
+ cmGeneratorExpressionInterpreter genexInterpreter(
+ this->LocalGenerator, config, this->GeneratorTarget, language);
+
+ // Seriously??
+ if (this->GetGlobalGenerator()->IsMultiConfig()) {
+ defines.insert(cmStrCat("CMAKE_INTDIR=\"", config, '"'));
+ }
+
+ const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
+ if (cmProp compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) {
+ this->LocalGenerator->AppendDefines(
+ defines, genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS));
+ }
+
+ std::string defPropName =
+ cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(config));
+ if (cmProp config_compile_defs = source->GetProperty(defPropName)) {
+ this->LocalGenerator->AppendDefines(
+ defines,
+ genexInterpreter.Evaluate(*config_compile_defs, COMPILE_DEFINITIONS));
+ }
+
+ std::string definesString = this->GetDefines(language, config);
+ this->LocalGenerator->JoinDefines(defines, definesString, language);
+
+ return definesString;
+}
+
+std::string cmNinjaTargetGenerator::ComputeIncludes(
+ cmSourceFile const* source, const std::string& language,
+ const std::string& config)
+{
+ std::vector<std::string> includes;
+ cmGeneratorExpressionInterpreter genexInterpreter(
+ this->LocalGenerator, config, this->GeneratorTarget, language);
+
+ const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
+ if (cmProp cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) {
+ this->LocalGenerator->AppendIncludeDirectories(
+ includes, genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES),
+ *source);
+ }
+
+ std::string includesString = this->LocalGenerator->GetIncludeFlags(
+ includes, this->GeneratorTarget, language, config, false,
+ cmLocalGenerator::IncludePathStyle::Absolute);
+ this->LocalGenerator->AppendFlags(includesString,
+ this->GetIncludes(language, config));
+
+ return includesString;
+}
+
+cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps(
+ const std::string& linkLanguage, const std::string& config,
+ bool ignoreType) const
+{
+ // Static libraries never depend on other targets for linking.
+ if (!ignoreType &&
+ (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmStateEnums::OBJECT_LIBRARY)) {
+ return cmNinjaDeps();
+ }
+
+ cmComputeLinkInformation* cli =
+ this->GeneratorTarget->GetLinkInformation(config);
+ if (!cli) {
+ return cmNinjaDeps();
+ }
+
+ const std::vector<std::string>& deps = cli->GetDepends();
+ cmNinjaDeps result(deps.size());
+ std::transform(deps.begin(), deps.end(), result.begin(),
+ this->MapToNinjaPath());
+
+ // Add a dependency on the link definitions file, if any.
+ if (cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
+ this->GeneratorTarget->GetModuleDefinitionInfo(config)) {
+ for (cmSourceFile const* src : mdi->Sources) {
+ result.push_back(this->ConvertToNinjaPath(src->GetFullPath()));
+ }
+ }
+
+ // Add a dependency on user-specified manifest files, if any.
+ std::vector<cmSourceFile const*> manifest_srcs;
+ this->GeneratorTarget->GetManifests(manifest_srcs, config);
+ for (cmSourceFile const* manifest_src : manifest_srcs) {
+ result.push_back(this->ConvertToNinjaPath(manifest_src->GetFullPath()));
+ }
+
+ // Add user-specified dependencies.
+ std::vector<std::string> linkDeps;
+ this->GeneratorTarget->GetLinkDepends(linkDeps, config, linkLanguage);
+ std::transform(linkDeps.begin(), linkDeps.end(), std::back_inserter(result),
+ this->MapToNinjaPath());
+
+ return result;
+}
+
+std::string cmNinjaTargetGenerator::GetSourceFilePath(
+ cmSourceFile const* source) const
+{
+ return this->ConvertToNinjaPath(source->GetFullPath());
+}
+
+std::string cmNinjaTargetGenerator::GetObjectFilePath(
+ cmSourceFile const* source, const std::string& config) const
+{
+ std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
+ if (!path.empty()) {
+ path += '/';
+ }
+ std::string const& objectName = this->GeneratorTarget->GetObjectName(source);
+ path += cmStrCat(
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget),
+ this->GetGlobalGenerator()->ConfigDirectory(config), '/', objectName);
+ return path;
+}
+
+std::string cmNinjaTargetGenerator::GetPreprocessedFilePath(
+ cmSourceFile const* source, const std::string& config) const
+{
+ // Choose an extension to compile already-preprocessed source.
+ std::string ppExt = source->GetExtension();
+ if (cmHasLiteralPrefix(ppExt, "F")) {
+ // Some Fortran compilers automatically enable preprocessing for
+ // upper-case extensions. Since the source is already preprocessed,
+ // use a lower-case extension.
+ ppExt = cmSystemTools::LowerCase(ppExt);
+ }
+ if (ppExt == "fpp") {
+ // Some Fortran compilers automatically enable preprocessing for
+ // the ".fpp" extension. Since the source is already preprocessed,
+ // use the ".f" extension.
+ ppExt = "f";
+ }
+
+ // Take the object file name and replace the extension.
+ std::string const& objName = this->GeneratorTarget->GetObjectName(source);
+ std::string const& objExt =
+ this->GetGlobalGenerator()->GetLanguageOutputExtension(*source);
+ assert(objName.size() >= objExt.size());
+ std::string const ppName =
+ cmStrCat(objName.substr(0, objName.size() - objExt.size()), "-pp.", ppExt);
+
+ std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
+ if (!path.empty()) {
+ path += '/';
+ }
+ path +=
+ cmStrCat(this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget),
+ this->GetGlobalGenerator()->ConfigDirectory(config), '/', ppName);
+ return path;
+}
+
+std::string cmNinjaTargetGenerator::GetDyndepFilePath(
+ std::string const& lang, const std::string& config) const
+{
+ std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
+ if (!path.empty()) {
+ path += '/';
+ }
+ path += cmStrCat(
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget),
+ this->GetGlobalGenerator()->ConfigDirectory(config), '/', lang, ".dd");
+ return path;
+}
+
+std::string cmNinjaTargetGenerator::GetTargetDependInfoPath(
+ std::string const& lang, const std::string& config) const
+{
+ std::string path =
+ cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/',
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget),
+ this->GetGlobalGenerator()->ConfigDirectory(config), '/', lang,
+ "DependInfo.json");
+ return path;
+}
+
+std::string cmNinjaTargetGenerator::GetTargetOutputDir(
+ const std::string& config) const
+{
+ std::string dir = this->GeneratorTarget->GetDirectory(config);
+ return this->ConvertToNinjaPath(dir);
+}
+
+std::string cmNinjaTargetGenerator::GetTargetFilePath(
+ const std::string& name, const std::string& config) const
+{
+ std::string path = this->GetTargetOutputDir(config);
+ if (path.empty() || path == ".") {
+ return name;
+ }
+ path += cmStrCat('/', name);
+ return path;
+}
+
+std::string cmNinjaTargetGenerator::GetTargetName() const
+{
+ return this->GeneratorTarget->GetName();
+}
+
+bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(
+ cmNinjaVars& vars, const std::string& config) const
+{
+ cmMakefile* mf = this->GetMakefile();
+ if (mf->GetDefinition("MSVC_C_ARCHITECTURE_ID") ||
+ mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID") ||
+ mf->GetDefinition("MSVC_CUDA_ARCHITECTURE_ID")) {
+ std::string pdbPath;
+ std::string compilePdbPath = this->ComputeTargetCompilePDB(config);
+ if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE ||
+ this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ pdbPath = cmStrCat(this->GeneratorTarget->GetPDBDirectory(config), '/',
+ this->GeneratorTarget->GetPDBName(config));
+ }
+
+ vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(pdbPath), cmOutputConverter::SHELL);
+ vars["TARGET_COMPILE_PDB"] =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(compilePdbPath), cmOutputConverter::SHELL);
+
+ this->EnsureParentDirectoryExists(pdbPath);
+ this->EnsureParentDirectoryExists(compilePdbPath);
+ return true;
+ }
+ return false;
+}
+
+void cmNinjaTargetGenerator::WriteLanguageRules(const std::string& language,
+ const std::string& config)
+{
+#ifdef NINJA_GEN_VERBOSE_FILES
+ this->GetRulesFileStream() << "# Rules for language " << language << "\n\n";
+#endif
+ this->WriteCompileRule(language, config);
+}
+
+namespace {
+// Create the command to run the dependency scanner
+std::string GetScanCommand(const std::string& cmakeCmd, const std::string& tdi,
+ const std::string& lang, const std::string& ppFile,
+ const std::string& ddiFile)
+{
+ return cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi,
+ " --lang=", lang, " --src=$in", " --pp=", ppFile,
+ " --dep=$DEP_FILE --obj=$OBJ_FILE --ddi=", ddiFile);
+}
+
+// Helper function to create dependency scanning rule that may or may
+// not perform explicit preprocessing too.
+cmNinjaRule GetScanRule(
+ const std::string& ruleName,
+ cmRulePlaceholderExpander::RuleVariables const& vars,
+ const std::string& responseFlag, const std::string& flags,
+ cmRulePlaceholderExpander* const rulePlaceholderExpander,
+ cmLocalNinjaGenerator* generator, std::vector<std::string> scanCmds)
+{
+ cmNinjaRule rule(ruleName);
+ // Scanning always uses a depfile for preprocessor dependencies.
+ rule.DepType = ""; // no deps= for multiple outputs
+ rule.DepFile = "$DEP_FILE";
+
+ cmRulePlaceholderExpander::RuleVariables scanVars;
+ scanVars.CMTargetName = vars.CMTargetName;
+ scanVars.CMTargetType = vars.CMTargetType;
+ scanVars.Language = vars.Language;
+ scanVars.Object = "$OBJ_FILE";
+ scanVars.PreprocessedSource = "$out";
+ scanVars.DynDepFile = "$DYNDEP_INTERMEDIATE_FILE";
+ scanVars.DependencyFile = rule.DepFile.c_str();
+ scanVars.DependencyTarget = "$out";
+
+ // Scanning needs the same preprocessor settings as direct compilation would.
+ scanVars.Source = vars.Source;
+ scanVars.Defines = vars.Defines;
+ scanVars.Includes = vars.Includes;
+
+ // Scanning needs the compilation flags too.
+ std::string scanFlags = flags;
+
+ // If using a response file, move defines, includes, and flags into it.
+ if (!responseFlag.empty()) {
+ rule.RspFile = "$RSP_FILE";
+ rule.RspContent =
+ cmStrCat(' ', scanVars.Defines, ' ', scanVars.Includes, ' ', scanFlags);
+ scanFlags = cmStrCat(responseFlag, rule.RspFile);
+ scanVars.Defines = "";
+ scanVars.Includes = "";
+ }
+
+ scanVars.Flags = scanFlags.c_str();
+
+ // Rule for scanning a source file.
+ for (std::string& scanCmd : scanCmds) {
+ rulePlaceholderExpander->ExpandRuleVariables(generator, scanCmd, scanVars);
+ }
+ rule.Command = generator->BuildCommandLine(scanCmds);
+
+ return rule;
+}
+}
+
+void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
+ const std::string& config)
+{
+ cmRulePlaceholderExpander::RuleVariables vars;
+ vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
+ vars.CMTargetType =
+ cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()).c_str();
+ vars.Language = lang.c_str();
+ vars.Source = "$in";
+ vars.Object = "$out";
+ vars.Defines = "$DEFINES";
+ vars.Includes = "$INCLUDES";
+ vars.TargetPDB = "$TARGET_PDB";
+ vars.TargetCompilePDB = "$TARGET_COMPILE_PDB";
+ vars.ObjectDir = "$OBJECT_DIR";
+ vars.ObjectFileDir = "$OBJECT_FILE_DIR";
+ vars.ISPCHeader = "$ISPC_HEADER_FILE";
+
+ cmMakefile* mf = this->GetMakefile();
+
+ // For some cases we scan to dynamically discover dependencies.
+ bool const needDyndep = this->NeedDyndep(lang, config);
+ bool const compilationPreprocesses = !this->NeedExplicitPreprocessing(lang);
+
+ std::string flags = "$FLAGS";
+
+ std::string responseFlag;
+ bool const lang_supports_response = lang != "RC";
+ if (lang_supports_response && this->ForceResponseFile()) {
+ std::string const responseFlagVar =
+ cmStrCat("CMAKE_", lang, "_RESPONSE_FILE_FLAG");
+ responseFlag = this->Makefile->GetSafeDefinition(responseFlagVar);
+ if (responseFlag.empty() && lang != "CUDA") {
+ responseFlag = "@";
+ }
+ }
+ std::string const modmapFormatVar =
+ cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_MODULE_MAP_FORMAT");
+ std::string const modmapFormat =
+ this->Makefile->GetSafeDefinition(modmapFormatVar);
+
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->GetLocalGenerator()->CreateRulePlaceholderExpander());
+
+ std::string const tdi = this->GetLocalGenerator()->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(this->GetTargetDependInfoPath(lang, config)),
+ cmLocalGenerator::SHELL);
+
+ std::string launcher;
+ cmProp val = this->GetLocalGenerator()->GetRuleLauncher(
+ this->GetGeneratorTarget(), "RULE_LAUNCH_COMPILE");
+ if (cmNonempty(val)) {
+ launcher = cmStrCat(*val, ' ');
+ }
+
+ std::string const cmakeCmd =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
+
+ if (needDyndep) {
+ // Rule to scan dependencies of sources that need preprocessing.
+ {
+ std::vector<std::string> scanCommands;
+ std::string scanRuleName;
+ if (compilationPreprocesses) {
+ scanRuleName = this->LanguageScanRule(lang, config);
+ std::string const& scanCommand = mf->GetRequiredDefinition(
+ cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_SCANDEP_SOURCE"));
+ cmExpandList(scanCommand, scanCommands);
+ for (std::string& i : scanCommands) {
+ i = cmStrCat(launcher, i);
+ }
+ } else {
+ scanRuleName = this->LanguagePreprocessAndScanRule(lang, config);
+ std::string const& ppCommmand = mf->GetRequiredDefinition(
+ cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE"));
+ cmExpandList(ppCommmand, scanCommands);
+ for (std::string& i : scanCommands) {
+ i = cmStrCat(launcher, i);
+ }
+ scanCommands.emplace_back(GetScanCommand(cmakeCmd, tdi, lang, "$out",
+ "$DYNDEP_INTERMEDIATE_FILE"));
+ }
+
+ auto scanRule = GetScanRule(
+ scanRuleName, vars, responseFlag, flags, rulePlaceholderExpander.get(),
+ this->GetLocalGenerator(), std::move(scanCommands));
+
+ scanRule.Comment =
+ cmStrCat("Rule for generating ", lang, " dependencies.");
+ if (compilationPreprocesses) {
+ scanRule.Description =
+ cmStrCat("Scanning $in for ", lang, " dependencies");
+ } else {
+ scanRule.Description =
+ cmStrCat("Building ", lang, " preprocessed $out");
+ }
+
+ this->GetGlobalGenerator()->AddRule(scanRule);
+ }
+
+ if (!compilationPreprocesses) {
+ // Compilation will not preprocess, so it does not need the defines
+ // unless the compiler wants them for some other purpose.
+ if (!this->CompileWithDefines(lang)) {
+ vars.Defines = "";
+ }
+
+ // Rule to scan dependencies of sources that do not need preprocessing.
+ std::string const& scanRuleName = this->LanguageScanRule(lang, config);
+ std::vector<std::string> scanCommands;
+ scanCommands.emplace_back(
+ GetScanCommand(cmakeCmd, tdi, lang, "$in", "$out"));
+
+ auto scanRule = GetScanRule(
+ scanRuleName, vars, "", flags, rulePlaceholderExpander.get(),
+ this->GetLocalGenerator(), std::move(scanCommands));
+
+ // Write the rule for generating dependencies for the given language.
+ scanRule.Comment = cmStrCat("Rule for generating ", lang,
+ " dependencies on non-preprocessed files.");
+ scanRule.Description =
+ cmStrCat("Generating ", lang, " dependencies for $in");
+
+ this->GetGlobalGenerator()->AddRule(scanRule);
+ }
+
+ // Write the rule for ninja dyndep file generation.
+ cmNinjaRule rule(this->LanguageDyndepRule(lang, config));
+ // Command line length is almost always limited -> use response file for
+ // dyndep rules
+ rule.RspFile = "$out.rsp";
+ rule.RspContent = "$in";
+
+ // Run CMake dependency scanner on the source file (using the preprocessed
+ // source if that was performed).
+ std::string ddModmapArg;
+ if (!modmapFormat.empty()) {
+ ddModmapArg += cmStrCat(" --modmapfmt=", modmapFormat);
+ }
+ {
+ std::vector<std::string> ddCmds;
+ {
+ std::string ccmd = cmStrCat(
+ cmakeCmd, " -E cmake_ninja_dyndep --tdi=", tdi, " --lang=", lang,
+ ddModmapArg, " --dd=$out @", rule.RspFile);
+ ddCmds.emplace_back(std::move(ccmd));
+ }
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(ddCmds);
+ }
+ rule.Comment =
+ cmStrCat("Rule to generate ninja dyndep files for ", lang, '.');
+ rule.Description = cmStrCat("Generating ", lang, " dyndep file $out");
+ this->GetGlobalGenerator()->AddRule(rule);
+ }
+
+ cmNinjaRule rule(this->LanguageCompilerRule(lang, config));
+ // If using a response file, move defines, includes, and flags into it.
+ if (!responseFlag.empty()) {
+ rule.RspFile = "$RSP_FILE";
+ rule.RspContent =
+ cmStrCat(' ', vars.Defines, ' ', vars.Includes, ' ', flags);
+ flags = cmStrCat(responseFlag, rule.RspFile);
+ vars.Defines = "";
+ vars.Includes = "";
+ }
+
+ // Tell ninja dependency format so all deps can be loaded into a database
+ std::string cldeps;
+ if (!compilationPreprocesses) {
+ // The compiler will not do preprocessing, so it has no such dependencies.
+ } else if (mf->IsOn(cmStrCat("CMAKE_NINJA_CMCLDEPS_", lang))) {
+ // For the MS resource compiler we need cmcldeps, but skip dependencies
+ // for source-file try_compile cases because they are always fresh.
+ if (!mf->GetIsSourceFileTryCompile()) {
+ rule.DepType = "gcc";
+ rule.DepFile = "$DEP_FILE";
+ cmProp d = mf->GetDefinition("CMAKE_C_COMPILER");
+ const std::string cl =
+ d ? *d : mf->GetSafeDefinition("CMAKE_CXX_COMPILER");
+ cldeps = cmStrCat('"', cmSystemTools::GetCMClDepsCommand(), "\" ", lang,
+ ' ', vars.Source, " $DEP_FILE $out \"",
+ mf->GetSafeDefinition("CMAKE_CL_SHOWINCLUDES_PREFIX"),
+ "\" \"", cl, "\" ");
+ }
+ } else {
+ const auto& depType = this->GetMakefile()->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_DEPFILE_FORMAT"));
+ if (depType == "msvc"_s) {
+ rule.DepType = "msvc";
+ rule.DepFile.clear();
+ } else {
+ rule.DepType = "gcc";
+ rule.DepFile = "$DEP_FILE";
+ }
+ vars.DependencyFile = rule.DepFile.c_str();
+ vars.DependencyTarget = "$out";
+
+ const std::string flagsName = cmStrCat("CMAKE_DEPFILE_FLAGS_", lang);
+ std::string depfileFlags = mf->GetSafeDefinition(flagsName);
+ if (!depfileFlags.empty()) {
+ rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
+ depfileFlags, vars);
+ flags += cmStrCat(' ', depfileFlags);
+ }
+ }
+
+ if (needDyndep && !modmapFormat.empty()) {
+ std::string modmapFlags = mf->GetRequiredDefinition(
+ cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_MODULE_MAP_FLAG"));
+ cmSystemTools::ReplaceString(modmapFlags, "<MODULE_MAP_FILE>",
+ "$DYNDEP_MODULE_MAP_FILE");
+ flags += cmStrCat(' ', modmapFlags);
+ }
+
+ vars.Flags = flags.c_str();
+ vars.DependencyFile = rule.DepFile.c_str();
+
+ // Rule for compiling object file.
+ std::vector<std::string> compileCmds;
+ if (lang == "CUDA") {
+ std::string cmdVar;
+ if (this->GeneratorTarget->GetPropertyAsBool(
+ "CUDA_SEPARABLE_COMPILATION")) {
+ cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION";
+ } else if (this->GeneratorTarget->GetPropertyAsBool(
+ "CUDA_PTX_COMPILATION")) {
+ cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION";
+ } else {
+ cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION";
+ }
+ const std::string& compileCmd = mf->GetRequiredDefinition(cmdVar);
+ cmExpandList(compileCmd, compileCmds);
+ } else {
+ const std::string cmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_OBJECT");
+ const std::string& compileCmd = mf->GetRequiredDefinition(cmdVar);
+ cmExpandList(compileCmd, compileCmds);
+ }
+
+ // See if we need to use a compiler launcher like ccache or distcc
+ std::string compilerLauncher;
+ if (!compileCmds.empty() &&
+ (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA" ||
+ lang == "ISPC" || lang == "OBJC" || lang == "OBJCXX")) {
+ std::string const clauncher_prop = cmStrCat(lang, "_COMPILER_LAUNCHER");
+ cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
+ if (cmNonempty(clauncher)) {
+ compilerLauncher = *clauncher;
+ }
+ }
+
+ // Maybe insert an include-what-you-use runner.
+ if (!compileCmds.empty() &&
+ (lang == "C" || lang == "CXX" || lang == "OBJC" || lang == "OBJCXX")) {
+ std::string const tidy_prop = cmStrCat(lang, "_CLANG_TIDY");
+ cmProp tidy = this->GeneratorTarget->GetProperty(tidy_prop);
+ cmProp iwyu = nullptr;
+ cmProp cpplint = nullptr;
+ cmProp cppcheck = nullptr;
+ if (lang == "C" || lang == "CXX") {
+ std::string const iwyu_prop = cmStrCat(lang, "_INCLUDE_WHAT_YOU_USE");
+ iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
+ std::string const cpplint_prop = cmStrCat(lang, "_CPPLINT");
+ cpplint = this->GeneratorTarget->GetProperty(cpplint_prop);
+ std::string const cppcheck_prop = cmStrCat(lang, "_CPPCHECK");
+ cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
+ }
+ if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) ||
+ cmNonempty(cppcheck)) {
+ std::string run_iwyu = cmStrCat(cmakeCmd, " -E __run_co_compile");
+ if (!compilerLauncher.empty()) {
+ // In __run_co_compile case the launcher command is supplied
+ // via --launcher=<maybe-list> and consumed
+ run_iwyu +=
+ cmStrCat(" --launcher=",
+ this->LocalGenerator->EscapeForShell(compilerLauncher));
+ compilerLauncher.clear();
+ }
+ if (cmNonempty(iwyu)) {
+ run_iwyu += cmStrCat(" --iwyu=",
+ this->GetLocalGenerator()->EscapeForShell(*iwyu));
+ }
+ if (cmNonempty(tidy)) {
+ run_iwyu += " --tidy=";
+ cmProp p = this->Makefile->GetDefinition(
+ cmStrCat("CMAKE_", lang, "_CLANG_TIDY_DRIVER_MODE"));
+ std::string driverMode;
+ if (cmNonempty(p)) {
+ driverMode = *p;
+ } else {
+ driverMode = lang == "C" ? "gcc" : "g++";
+ }
+ run_iwyu += this->GetLocalGenerator()->EscapeForShell(
+ cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode));
+ }
+ if (cmNonempty(cpplint)) {
+ run_iwyu += cmStrCat(
+ " --cpplint=", this->GetLocalGenerator()->EscapeForShell(*cpplint));
+ }
+ if (cmNonempty(cppcheck)) {
+ run_iwyu +=
+ cmStrCat(" --cppcheck=",
+ this->GetLocalGenerator()->EscapeForShell(*cppcheck));
+ }
+ if (cmNonempty(tidy) || cmNonempty(cpplint) || cmNonempty(cppcheck)) {
+ run_iwyu += " --source=$in";
+ }
+ run_iwyu += " -- ";
+ compileCmds.front().insert(0, run_iwyu);
+ }
+ }
+
+ // If compiler launcher was specified and not consumed above, it
+ // goes to the beginning of the command line.
+ if (!compileCmds.empty() && !compilerLauncher.empty()) {
+ std::vector<std::string> args = cmExpandedList(compilerLauncher, true);
+ if (!args.empty()) {
+ args[0] = this->LocalGenerator->ConvertToOutputFormat(
+ args[0], cmOutputConverter::SHELL);
+ for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) {
+ i = this->LocalGenerator->EscapeForShell(i);
+ }
+ }
+ compileCmds.front().insert(0, cmStrCat(cmJoin(args, " "), ' '));
+ }
+
+ if (!compileCmds.empty()) {
+ compileCmds.front().insert(0, cldeps);
+ }
+
+ const auto& extraCommands = this->GetMakefile()->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_DEPENDS_EXTRA_COMMANDS"));
+ if (!extraCommands.empty()) {
+ auto commandList = cmExpandedList(extraCommands);
+ compileCmds.insert(compileCmds.end(), commandList.cbegin(),
+ commandList.cend());
+ }
+
+ for (std::string& i : compileCmds) {
+ i = cmStrCat(launcher, i);
+ rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), i,
+ vars);
+ }
+
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(compileCmds);
+
+ // Write the rule for compiling file of the given language.
+ rule.Comment = cmStrCat("Rule for compiling ", lang, " files.");
+ rule.Description = cmStrCat("Building ", lang, " object $out");
+ this->GetGlobalGenerator()->AddRule(rule);
+}
+
+void cmNinjaTargetGenerator::WriteObjectBuildStatements(
+ const std::string& config, const std::string& fileConfig,
+ bool firstForConfig)
+{
+ // Write comments.
+ cmGlobalNinjaGenerator::WriteDivider(this->GetImplFileStream(fileConfig));
+ this->GetImplFileStream(fileConfig)
+ << "# Object build statements for "
+ << cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
+ << " target " << this->GetTargetName() << "\n\n";
+
+ {
+ std::vector<cmSourceFile const*> customCommands;
+ this->GeneratorTarget->GetCustomCommands(customCommands, config);
+ for (cmSourceFile const* sf : customCommands) {
+ cmCustomCommand const* cc = sf->GetCustomCommand();
+ this->GetLocalGenerator()->AddCustomCommandTarget(
+ cc, this->GetGeneratorTarget());
+ // Record the custom commands for this target. The container is used
+ // in WriteObjectBuildStatement when called in a loop below.
+ this->Configs[config].CustomCommands.push_back(cc);
+ }
+ }
+ {
+ std::vector<cmSourceFile const*> headerSources;
+ this->GeneratorTarget->GetHeaderSources(headerSources, config);
+ this->OSXBundleGenerator->GenerateMacOSXContentStatements(
+ headerSources, this->Configs[fileConfig].MacOSXContentGenerator.get(),
+ config);
+ }
+ {
+ std::vector<cmSourceFile const*> extraSources;
+ this->GeneratorTarget->GetExtraSources(extraSources, config);
+ this->OSXBundleGenerator->GenerateMacOSXContentStatements(
+ extraSources, this->Configs[fileConfig].MacOSXContentGenerator.get(),
+ config);
+ }
+ if (firstForConfig) {
+ cmProp pchExtension =
+ this->GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION");
+
+ std::vector<cmSourceFile const*> externalObjects;
+ this->GeneratorTarget->GetExternalObjects(externalObjects, config);
+ for (cmSourceFile const* sf : externalObjects) {
+ auto objectFileName = this->GetGlobalGenerator()->ExpandCFGIntDir(
+ this->GetSourceFilePath(sf), config);
+ if (!cmSystemTools::StringEndsWith(objectFileName,
+ cmToCStr(pchExtension))) {
+ this->Configs[config].Objects.push_back(objectFileName);
+ }
+ }
+ }
+
+ {
+ cmNinjaBuild build("phony");
+ build.Comment =
+ cmStrCat("Order-only phony target for ", this->GetTargetName());
+ build.Outputs.push_back(this->OrderDependsTargetForTarget(config));
+
+ cmNinjaDeps& orderOnlyDeps = build.OrderOnlyDeps;
+ this->GetLocalGenerator()->AppendTargetDepends(
+ this->GeneratorTarget, orderOnlyDeps, config, fileConfig,
+ DependOnTargetOrdering);
+
+ // Add order-only dependencies on other files associated with the target.
+ cm::append(orderOnlyDeps, this->Configs[config].ExtraFiles);
+
+ // Add order-only dependencies on custom command outputs.
+ for (cmCustomCommand const* cc : this->Configs[config].CustomCommands) {
+ cmCustomCommandGenerator ccg(*cc, config, this->GetLocalGenerator());
+ const std::vector<std::string>& ccoutputs = ccg.GetOutputs();
+ const std::vector<std::string>& ccbyproducts = ccg.GetByproducts();
+ std::transform(ccoutputs.begin(), ccoutputs.end(),
+ std::back_inserter(orderOnlyDeps),
+ this->MapToNinjaPath());
+ std::transform(ccbyproducts.begin(), ccbyproducts.end(),
+ std::back_inserter(orderOnlyDeps),
+ this->MapToNinjaPath());
+ }
+
+ std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end());
+ orderOnlyDeps.erase(
+ std::unique(orderOnlyDeps.begin(), orderOnlyDeps.end()),
+ orderOnlyDeps.end());
+
+ // The phony target must depend on at least one input or ninja will explain
+ // that "output ... of phony edge with no inputs doesn't exist" and
+ // consider the phony output "dirty".
+ if (orderOnlyDeps.empty()) {
+ // Any path that always exists will work here. It would be nice to
+ // use just "." but that is not supported by Ninja < 1.7.
+ std::string tgtDir = cmStrCat(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget));
+ orderOnlyDeps.push_back(this->ConvertToNinjaPath(tgtDir));
+ }
+
+ this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
+ build);
+ }
+
+ {
+ std::vector<cmSourceFile const*> objectSources;
+ this->GeneratorTarget->GetObjectSources(objectSources, config);
+
+ for (cmSourceFile const* sf : objectSources) {
+ this->WriteObjectBuildStatement(sf, config, fileConfig, firstForConfig);
+ }
+ }
+
+ for (auto const& langDDIFiles : this->Configs[config].DDIFiles) {
+ std::string const& language = langDDIFiles.first;
+ cmNinjaDeps const& ddiFiles = langDDIFiles.second;
+
+ cmNinjaBuild build(this->LanguageDyndepRule(language, config));
+ build.Outputs.push_back(this->GetDyndepFilePath(language, config));
+ build.ExplicitDeps = ddiFiles;
+
+ this->WriteTargetDependInfo(language, config);
+
+ // Make sure dyndep files for all our dependencies have already
+ // been generated so that the '<LANG>Modules.json' files they
+ // produced as side-effects are available for us to read.
+ // Ideally we should depend on the '<LANG>Modules.json' files
+ // from our dependencies directly, but we don't know which of
+ // our dependencies produces them. Fixing this will require
+ // refactoring the Ninja generator to generate targets in
+ // dependency order so that we can collect the needed information.
+ this->GetLocalGenerator()->AppendTargetDepends(
+ this->GeneratorTarget, build.OrderOnlyDeps, config, fileConfig,
+ DependOnTargetArtifact);
+
+ this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
+ build);
+ }
+
+ this->GetImplFileStream(fileConfig) << "\n";
+
+ if (!this->Configs[config].SwiftOutputMap.empty()) {
+ std::string const mapFilePath =
+ cmStrCat(this->GeneratorTarget->GetSupportDirectory(), '/', config, '/',
+ "output-file-map.json");
+ std::string const targetSwiftDepsPath = [this, config]() -> std::string {
+ cmGeneratorTarget const* target = this->GeneratorTarget;
+ if (cmProp name = target->GetProperty("Swift_DEPENDENCIES_FILE")) {
+ return *name;
+ }
+ return this->ConvertToNinjaPath(
+ cmStrCat(target->GetSupportDirectory(), '/', config, '/',
+ target->GetName(), ".swiftdeps"));
+ }();
+
+ // build the global target dependencies
+ // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps
+ Json::Value deps(Json::objectValue);
+ deps["swift-dependencies"] = targetSwiftDepsPath;
+ this->Configs[config].SwiftOutputMap[""] = deps;
+
+ cmGeneratedFileStream output(mapFilePath);
+ output << this->Configs[config].SwiftOutputMap;
+ }
+}
+
+namespace {
+cmNinjaBuild GetScanBuildStatement(const std::string& ruleName,
+ const std::string& ppFileName,
+ bool compilePP, bool compilePPWithDefines,
+ cmNinjaBuild& objBuild, cmNinjaVars& vars,
+ std::string const& modmapFormat,
+ const std::string& objectFileName,
+ cmLocalGenerator* lg)
+{
+ cmNinjaBuild scanBuild(ruleName);
+
+ if (!ppFileName.empty()) {
+ scanBuild.RspFile = cmStrCat(ppFileName, ".rsp");
+ } else {
+ scanBuild.RspFile = "$out.rsp";
+ }
+
+ if (compilePP) {
+ // Move compilation dependencies to the scan/preprocessing build statement.
+ std::swap(scanBuild.ExplicitDeps, objBuild.ExplicitDeps);
+ std::swap(scanBuild.ImplicitDeps, objBuild.ImplicitDeps);
+ std::swap(scanBuild.OrderOnlyDeps, objBuild.OrderOnlyDeps);
+ std::swap(scanBuild.Variables["IN_ABS"], vars["IN_ABS"]);
+
+ // The actual compilation will now use the preprocessed source.
+ objBuild.ExplicitDeps.push_back(ppFileName);
+ } else {
+ // Copy compilation dependencies to the scan/preprocessing build statement.
+ scanBuild.ExplicitDeps = objBuild.ExplicitDeps;
+ scanBuild.ImplicitDeps = objBuild.ImplicitDeps;
+ scanBuild.OrderOnlyDeps = objBuild.OrderOnlyDeps;
+ scanBuild.Variables["IN_ABS"] = vars["IN_ABS"];
+ }
+
+ // Scanning and compilation generally use the same flags.
+ scanBuild.Variables["FLAGS"] = vars["FLAGS"];
+
+ if (compilePP && !compilePPWithDefines) {
+ // Move preprocessor definitions to the scan/preprocessor build statement.
+ std::swap(scanBuild.Variables["DEFINES"], vars["DEFINES"]);
+ } else {
+ // Copy preprocessor definitions to the scan/preprocessor build statement.
+ scanBuild.Variables["DEFINES"] = vars["DEFINES"];
+ }
+
+ // Copy include directories to the preprocessor build statement. The
+ // Fortran compilation build statement still needs them for the INCLUDE
+ // directive.
+ scanBuild.Variables["INCLUDES"] = vars["INCLUDES"];
+
+ // Tell dependency scanner the object file that will result from
+ // compiling the source.
+ scanBuild.Variables["OBJ_FILE"] = objectFileName;
+
+ // Tell dependency scanner where to store dyndep intermediate results.
+ std::string const& ddiFile = cmStrCat(objectFileName, ".ddi");
+ scanBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
+
+ // Outputs of the scan/preprocessor build statement.
+ if (!ppFileName.empty()) {
+ scanBuild.Outputs.push_back(ppFileName);
+ scanBuild.ImplicitOuts.push_back(ddiFile);
+ } else {
+ scanBuild.Outputs.push_back(ddiFile);
+ }
+
+ // Scanning always uses a depfile for preprocessor dependencies.
+ std::string const& depFileName = cmStrCat(scanBuild.Outputs.front(), ".d");
+ scanBuild.Variables["DEP_FILE"] =
+ lg->ConvertToOutputFormat(depFileName, cmOutputConverter::SHELL);
+ if (compilePP) {
+ // The actual compilation does not need a depfile because it
+ // depends on the already-preprocessed source.
+ vars.erase("DEP_FILE");
+ }
+
+ if (!modmapFormat.empty()) {
+ // XXX(modmap): If changing this path construction, change
+ // `cmGlobalNinjaGenerator::WriteDyndep` to expect the corresponding
+ // file path.
+ std::string const ddModmapFile = cmStrCat(objectFileName, ".modmap");
+ scanBuild.Variables["DYNDEP_MODULE_MAP_FILE"] = ddModmapFile;
+ scanBuild.ImplicitOuts.push_back(ddModmapFile);
+ }
+
+ return scanBuild;
+}
+}
+
+void cmNinjaTargetGenerator::WriteObjectBuildStatement(
+ cmSourceFile const* source, const std::string& config,
+ const std::string& fileConfig, bool firstForConfig)
+{
+ std::string const language = source->GetLanguage();
+ std::string const sourceFileName =
+ language == "RC" ? source->GetFullPath() : this->GetSourceFilePath(source);
+ std::string const objectDir = this->ConvertToNinjaPath(
+ cmStrCat(this->GeneratorTarget->GetSupportDirectory(),
+ this->GetGlobalGenerator()->ConfigDirectory(config)));
+ std::string const objectFileName =
+ this->ConvertToNinjaPath(this->GetObjectFilePath(source, config));
+ std::string const objectFileDir =
+ cmSystemTools::GetFilenamePath(objectFileName);
+
+ std::string cmakeVarLang = cmStrCat("CMAKE_", language);
+
+ // build response file name
+ std::string cmakeLinkVar = cmStrCat(cmakeVarLang, "_RESPONSE_FILE_FLAG");
+
+ cmProp flag = this->GetMakefile()->GetDefinition(cmakeLinkVar);
+
+ bool const lang_supports_response =
+ !(language == "RC" || (language == "CUDA" && !flag));
+ int const commandLineLengthLimit =
+ ((lang_supports_response && this->ForceResponseFile())) ? -1 : 0;
+
+ cmNinjaBuild objBuild(this->LanguageCompilerRule(language, config));
+ cmNinjaVars& vars = objBuild.Variables;
+ vars["FLAGS"] = this->ComputeFlagsForObject(source, language, config);
+ vars["DEFINES"] = this->ComputeDefines(source, language, config);
+ vars["INCLUDES"] = this->ComputeIncludes(source, language, config);
+
+ if (this->GetMakefile()->GetSafeDefinition(
+ cmStrCat("CMAKE_", language, "_DEPFILE_FORMAT")) != "msvc"_s) {
+ bool replaceExt(false);
+ if (!language.empty()) {
+ std::string repVar =
+ cmStrCat("CMAKE_", language, "_DEPFILE_EXTENSION_REPLACE");
+ replaceExt = this->Makefile->IsOn(repVar);
+ }
+ if (!replaceExt) {
+ // use original code
+ vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmStrCat(objectFileName, ".d"), cmOutputConverter::SHELL);
+ } else {
+ // Replace the original source file extension with the
+ // depend file extension.
+ std::string dependFileName = cmStrCat(
+ cmSystemTools::GetFilenameWithoutLastExtension(objectFileName), ".d");
+ vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmStrCat(objectFileDir, '/', dependFileName),
+ cmOutputConverter::SHELL);
+ }
+ }
+
+ this->ExportObjectCompileCommand(
+ language, sourceFileName, objectDir, objectFileName, objectFileDir,
+ vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"]);
+
+ objBuild.Outputs.push_back(objectFileName);
+ if (firstForConfig) {
+ cmProp pchExtension =
+ this->GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION");
+ if (!cmSystemTools::StringEndsWith(objectFileName,
+ cmToCStr(pchExtension))) {
+ // Add this object to the list of object files.
+ this->Configs[config].Objects.push_back(objectFileName);
+ }
+ }
+
+ objBuild.ExplicitDeps.push_back(sourceFileName);
+
+ // Add precompile headers dependencies
+ std::vector<std::string> depList;
+
+ std::vector<std::string> architectures;
+ this->GeneratorTarget->GetAppleArchs(config, architectures);
+ if (architectures.empty()) {
+ architectures.emplace_back();
+ }
+
+ std::unordered_set<std::string> pchSources;
+ for (const std::string& arch : architectures) {
+ const std::string pchSource =
+ this->GeneratorTarget->GetPchSource(config, language, arch);
+
+ if (!pchSource.empty()) {
+ pchSources.insert(pchSource);
+ }
+ }
+
+ if (!pchSources.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
+ for (const std::string& arch : architectures) {
+ depList.push_back(
+ this->GeneratorTarget->GetPchHeader(config, language, arch));
+ if (pchSources.find(source->GetFullPath()) == pchSources.end()) {
+ depList.push_back(
+ this->GeneratorTarget->GetPchFile(config, language, arch));
+ }
+ }
+ }
+
+ if (cmProp objectDeps = source->GetProperty("OBJECT_DEPENDS")) {
+ std::vector<std::string> objDepList = cmExpandedList(*objectDeps);
+ std::copy(objDepList.begin(), objDepList.end(),
+ std::back_inserter(depList));
+ }
+
+ if (!depList.empty()) {
+ for (std::string& odi : depList) {
+ if (cmSystemTools::FileIsFullPath(odi)) {
+ odi = cmSystemTools::CollapseFullPath(odi);
+ }
+ }
+ std::transform(depList.begin(), depList.end(),
+ std::back_inserter(objBuild.ImplicitDeps),
+ this->MapToNinjaPath());
+ }
+
+ objBuild.OrderOnlyDeps.push_back(this->OrderDependsTargetForTarget(config));
+
+ // If the source file is GENERATED and does not have a custom command
+ // (either attached to this source file or another one), assume that one of
+ // the target dependencies, OBJECT_DEPENDS or header file custom commands
+ // will rebuild the file.
+ if (source->GetIsGenerated() &&
+ !source->GetPropertyAsBool("__CMAKE_GENERATED_BY_CMAKE") &&
+ !source->GetCustomCommand() &&
+ !this->GetGlobalGenerator()->HasCustomCommandOutput(sourceFileName)) {
+ this->GetGlobalGenerator()->AddAssumedSourceDependencies(
+ sourceFileName, objBuild.OrderOnlyDeps);
+ }
+
+ // For some cases we scan to dynamically discover dependencies.
+ bool const needDyndep = this->NeedDyndep(language, config);
+ bool const compilationPreprocesses =
+ !this->NeedExplicitPreprocessing(language);
+
+ std::string modmapFormat;
+ if (needDyndep) {
+ std::string const modmapFormatVar =
+ cmStrCat("CMAKE_EXPERIMENTAL_", language, "_MODULE_MAP_FORMAT");
+ modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar);
+ }
+
+ if (needDyndep) {
+ // If source/target has preprocessing turned off, we still need to
+ // generate an explicit dependency step
+ const auto srcpp = source->GetSafeProperty("Fortran_PREPROCESS");
+ cmOutputConverter::FortranPreprocess preprocess =
+ cmOutputConverter::GetFortranPreprocess(srcpp);
+ if (preprocess == cmOutputConverter::FortranPreprocess::Unset) {
+ const auto& tgtpp =
+ this->GeneratorTarget->GetSafeProperty("Fortran_PREPROCESS");
+ preprocess = cmOutputConverter::GetFortranPreprocess(tgtpp);
+ }
+
+ bool const compilePP = !compilationPreprocesses &&
+ (preprocess != cmOutputConverter::FortranPreprocess::NotNeeded);
+ bool const compilePPWithDefines =
+ compilePP && this->CompileWithDefines(language);
+
+ std::string scanRuleName;
+ std::string ppFileName;
+ if (compilePP) {
+ scanRuleName = this->LanguagePreprocessAndScanRule(language, config);
+ ppFileName = this->ConvertToNinjaPath(
+ this->GetPreprocessedFilePath(source, config));
+ } else {
+ scanRuleName = this->LanguageScanRule(language, config);
+ }
+
+ cmNinjaBuild ppBuild = GetScanBuildStatement(
+ scanRuleName, ppFileName, compilePP, compilePPWithDefines, objBuild,
+ vars, modmapFormat, objectFileName, this->LocalGenerator);
+
+ if (compilePP) {
+ // In case compilation requires flags that are incompatible with
+ // preprocessing, include them here.
+ std::string const& postFlag = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", language, "_POSTPROCESS_FLAG"));
+ this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag);
+
+ // Prepend source file's original directory as an include directory
+ // so e.g. Fortran INCLUDE statements can look for files in it.
+ std::vector<std::string> sourceDirectory;
+ sourceDirectory.push_back(
+ cmSystemTools::GetParentDirectory(source->GetFullPath()));
+
+ std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
+ sourceDirectory, this->GeneratorTarget, language, config, false,
+ cmLocalGenerator::IncludePathStyle::Default);
+
+ vars["INCLUDES"] = cmStrCat(sourceDirectoryFlag, ' ', vars["INCLUDES"]);
+ }
+
+ if (firstForConfig) {
+ std::string const ddiFile = cmStrCat(objectFileName, ".ddi");
+ this->Configs[config].DDIFiles[language].push_back(ddiFile);
+ }
+
+ this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
+ ppBuild.Variables);
+
+ this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
+ ppBuild, commandLineLengthLimit);
+
+ std::string const dyndep = this->GetDyndepFilePath(language, config);
+ objBuild.OrderOnlyDeps.push_back(dyndep);
+ vars["dyndep"] = dyndep;
+
+ if (!modmapFormat.empty()) {
+ std::string const ddModmapFile = cmStrCat(objectFileName, ".modmap");
+ vars["DYNDEP_MODULE_MAP_FILE"] = ddModmapFile;
+ objBuild.OrderOnlyDeps.push_back(ddModmapFile);
+ }
+ }
+
+ this->EnsureParentDirectoryExists(objectFileName);
+
+ vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
+ objectDir, cmOutputConverter::SHELL);
+ vars["OBJECT_FILE_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
+ objectFileDir, cmOutputConverter::SHELL);
+
+ this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
+ vars);
+
+ if (!pchSources.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
+ auto pchIt = pchSources.find(source->GetFullPath());
+ if (pchIt != pchSources.end()) {
+ this->addPoolNinjaVariable("JOB_POOL_PRECOMPILE_HEADER",
+ this->GetGeneratorTarget(), vars);
+ }
+ }
+
+ this->SetMsvcTargetPdbVariable(vars, config);
+
+ objBuild.RspFile = cmStrCat(objectFileName, ".rsp");
+
+ if (language == "ISPC") {
+ std::string const& objectName =
+ this->GeneratorTarget->GetObjectName(source);
+ std::string ispcSource =
+ cmSystemTools::GetFilenameWithoutLastExtension(objectName);
+ ispcSource = cmSystemTools::GetFilenameWithoutLastExtension(ispcSource);
+
+ cmProp ispcSuffixProp =
+ this->GeneratorTarget->GetProperty("ISPC_HEADER_SUFFIX");
+ assert(ispcSuffixProp != nullptr);
+
+ std::string ispcHeaderDirectory =
+ this->GeneratorTarget->GetObjectDirectory(config);
+ if (cmProp prop =
+ this->GeneratorTarget->GetProperty("ISPC_HEADER_DIRECTORY")) {
+ ispcHeaderDirectory =
+ cmStrCat(this->LocalGenerator->GetBinaryDirectory(), '/', *prop);
+ }
+
+ std::string ispcHeader =
+ cmStrCat(ispcHeaderDirectory, '/', ispcSource, *ispcSuffixProp);
+ ispcHeader = this->ConvertToNinjaPath(ispcHeader);
+
+ // Make sure ninja knows what command generates the header
+ objBuild.ImplicitOuts.push_back(ispcHeader);
+
+ // Make sure ninja knows how to clean the generated header
+ this->GetGlobalGenerator()->AddAdditionalCleanFile(ispcHeader, config);
+
+ auto ispcSuffixes =
+ detail::ComputeISPCObjectSuffixes(this->GeneratorTarget);
+ if (ispcSuffixes.size() > 1) {
+ std::string rootObjectDir =
+ this->GeneratorTarget->GetObjectDirectory(config);
+ auto ispcSideEfffectObjects = detail::ComputeISPCExtraObjects(
+ objectName, rootObjectDir, ispcSuffixes);
+
+ for (auto sideEffect : ispcSideEfffectObjects) {
+ sideEffect = this->ConvertToNinjaPath(sideEffect);
+ objBuild.ImplicitOuts.emplace_back(sideEffect);
+ this->GetGlobalGenerator()->AddAdditionalCleanFile(sideEffect, config);
+ }
+ }
+
+ vars["ISPC_HEADER_FILE"] =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ ispcHeader, cmOutputConverter::SHELL);
+ } else {
+ auto headers = this->GeneratorTarget->GetGeneratedISPCHeaders(config);
+ if (!headers.empty()) {
+ std::transform(headers.begin(), headers.end(), headers.begin(),
+ this->MapToNinjaPath());
+ objBuild.OrderOnlyDeps.insert(objBuild.OrderOnlyDeps.end(),
+ headers.begin(), headers.end());
+ }
+ }
+
+ if (language == "Swift") {
+ this->EmitSwiftDependencyInfo(source, config);
+ } else {
+ this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
+ objBuild, commandLineLengthLimit);
+ }
+
+ if (cmProp objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) {
+ std::string evaluatedObjectOutputs = cmGeneratorExpression::Evaluate(
+ *objectOutputs, this->LocalGenerator, config);
+
+ if (!evaluatedObjectOutputs.empty()) {
+ cmNinjaBuild build("phony");
+ build.Comment = "Additional output files.";
+ build.Outputs = cmExpandedList(evaluatedObjectOutputs);
+ std::transform(build.Outputs.begin(), build.Outputs.end(),
+ build.Outputs.begin(), this->MapToNinjaPath());
+ build.ExplicitDeps = objBuild.Outputs;
+ this->GetGlobalGenerator()->WriteBuild(
+ this->GetImplFileStream(fileConfig), build);
+ }
+ }
+}
+
+void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang,
+ const std::string& config)
+{
+ Json::Value tdi(Json::objectValue);
+ tdi["language"] = lang;
+ tdi["compiler-id"] = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
+
+ std::string mod_dir;
+ if (lang == "Fortran") {
+ mod_dir = this->GeneratorTarget->GetFortranModuleDirectory(
+ this->Makefile->GetHomeOutputDirectory());
+ } else if (lang == "CXX") {
+ mod_dir =
+ cmSystemTools::CollapseFullPath(this->GeneratorTarget->ObjectDirectory);
+ }
+ if (mod_dir.empty()) {
+ mod_dir = this->Makefile->GetCurrentBinaryDirectory();
+ }
+ tdi["module-dir"] = mod_dir;
+
+ if (lang == "Fortran") {
+ tdi["submodule-sep"] =
+ this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP");
+ tdi["submodule-ext"] =
+ this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT");
+ } else if (lang == "CXX") {
+ // No extra information necessary.
+ }
+
+ tdi["dir-cur-bld"] = this->Makefile->GetCurrentBinaryDirectory();
+ tdi["dir-cur-src"] = this->Makefile->GetCurrentSourceDirectory();
+ tdi["dir-top-bld"] = this->Makefile->GetHomeOutputDirectory();
+ tdi["dir-top-src"] = this->Makefile->GetHomeDirectory();
+
+ Json::Value& tdi_include_dirs = tdi["include-dirs"] = Json::arrayValue;
+ std::vector<std::string> includes;
+ this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
+ lang, config);
+ for (std::string const& i : includes) {
+ // Convert the include directories the same way we do for -I flags.
+ // See upstream ninja issue 1251.
+ tdi_include_dirs.append(this->ConvertToNinjaPath(i));
+ }
+
+ Json::Value& tdi_linked_target_dirs = tdi["linked-target-dirs"] =
+ Json::arrayValue;
+ for (std::string const& l : this->GetLinkedTargetDirectories(config)) {
+ tdi_linked_target_dirs.append(l);
+ }
+
+ std::string const tdin = this->GetTargetDependInfoPath(lang, config);
+ cmGeneratedFileStream tdif(tdin);
+ tdif << tdi;
+}
+
+void cmNinjaTargetGenerator::EmitSwiftDependencyInfo(
+ cmSourceFile const* source, const std::string& config)
+{
+ std::string const sourceFilePath =
+ this->ConvertToNinjaPath(this->GetSourceFilePath(source));
+ std::string const objectFilePath =
+ this->ConvertToNinjaPath(this->GetObjectFilePath(source, config));
+ std::string const swiftDepsPath = [source, objectFilePath]() -> std::string {
+ if (cmProp name = source->GetProperty("Swift_DEPENDENCIES_FILE")) {
+ return *name;
+ }
+ return cmStrCat(objectFilePath, ".swiftdeps");
+ }();
+ std::string const swiftDiaPath = [source, objectFilePath]() -> std::string {
+ if (cmProp name = source->GetProperty("Swift_DIAGNOSTICS_FILE")) {
+ return *name;
+ }
+ return cmStrCat(objectFilePath, ".dia");
+ }();
+ std::string const makeDepsPath = [this, source, config]() -> std::string {
+ cmLocalNinjaGenerator const* local = this->GetLocalGenerator();
+ std::string const objectFileName =
+ this->ConvertToNinjaPath(this->GetObjectFilePath(source, config));
+ std::string const objectFileDir =
+ cmSystemTools::GetFilenamePath(objectFileName);
+
+ if (this->Makefile->IsOn("CMAKE_Swift_DEPFLE_EXTNSION_REPLACE")) {
+ std::string dependFileName = cmStrCat(
+ cmSystemTools::GetFilenameWithoutLastExtension(objectFileName), ".d");
+ return local->ConvertToOutputFormat(
+ cmStrCat(objectFileDir, '/', dependFileName),
+ cmOutputConverter::SHELL);
+ }
+ return local->ConvertToOutputFormat(cmStrCat(objectFileName, ".d"),
+ cmOutputConverter::SHELL);
+ }();
+
+ // build the source file mapping
+ // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps
+ Json::Value entry = Json::Value(Json::objectValue);
+ entry["object"] = objectFilePath;
+ entry["dependencies"] = makeDepsPath;
+ entry["swift-dependencies"] = swiftDepsPath;
+ entry["diagnostics"] = swiftDiaPath;
+ this->Configs[config].SwiftOutputMap[sourceFilePath] = entry;
+}
+
+void cmNinjaTargetGenerator::ExportObjectCompileCommand(
+ std::string const& language, std::string const& sourceFileName,
+ std::string const& objectDir, std::string const& objectFileName,
+ std::string const& objectFileDir, std::string const& flags,
+ std::string const& defines, std::string const& includes)
+{
+ if (!this->GeneratorTarget->GetPropertyAsBool("EXPORT_COMPILE_COMMANDS")) {
+ return;
+ }
+
+ cmRulePlaceholderExpander::RuleVariables compileObjectVars;
+ compileObjectVars.Language = language.c_str();
+
+ std::string escapedSourceFileName = sourceFileName;
+
+ if (!cmSystemTools::FileIsFullPath(sourceFileName)) {
+ escapedSourceFileName =
+ cmSystemTools::CollapseFullPath(escapedSourceFileName,
+ this->GetGlobalGenerator()
+ ->GetCMakeInstance()
+ ->GetHomeOutputDirectory());
+ }
+
+ escapedSourceFileName = this->LocalGenerator->ConvertToOutputFormat(
+ escapedSourceFileName, cmOutputConverter::SHELL);
+
+ compileObjectVars.Source = escapedSourceFileName.c_str();
+ compileObjectVars.Object = objectFileName.c_str();
+ compileObjectVars.ObjectDir = objectDir.c_str();
+ compileObjectVars.ObjectFileDir = objectFileDir.c_str();
+ compileObjectVars.Flags = flags.c_str();
+ compileObjectVars.Defines = defines.c_str();
+ compileObjectVars.Includes = includes.c_str();
+
+ // Rule for compiling object file.
+ std::vector<std::string> compileCmds;
+ if (language == "CUDA") {
+ std::string cmdVar;
+ if (this->GeneratorTarget->GetPropertyAsBool(
+ "CUDA_SEPARABLE_COMPILATION")) {
+ cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION";
+ } else if (this->GeneratorTarget->GetPropertyAsBool(
+ "CUDA_PTX_COMPILATION")) {
+ cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION";
+ } else {
+ cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION";
+ }
+ const std::string& compileCmd =
+ this->GetMakefile()->GetRequiredDefinition(cmdVar);
+ cmExpandList(compileCmd, compileCmds);
+ } else {
+ const std::string cmdVar = cmStrCat("CMAKE_", language, "_COMPILE_OBJECT");
+ const std::string& compileCmd =
+ this->GetMakefile()->GetRequiredDefinition(cmdVar);
+ cmExpandList(compileCmd, compileCmds);
+ }
+
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->GetLocalGenerator()->CreateRulePlaceholderExpander());
+
+ for (std::string& i : compileCmds) {
+ // no launcher for CMAKE_EXPORT_COMPILE_COMMANDS
+ rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), i,
+ compileObjectVars);
+ }
+
+ std::string cmdLine =
+ this->GetLocalGenerator()->BuildCommandLine(compileCmds);
+
+ this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName);
+}
+
+void cmNinjaTargetGenerator::AdditionalCleanFiles(const std::string& config)
+{
+ if (cmProp prop_value =
+ this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) {
+ cmLocalNinjaGenerator* lg = this->LocalGenerator;
+ std::vector<std::string> cleanFiles;
+ cmExpandList(cmGeneratorExpression::Evaluate(*prop_value, lg, config,
+ this->GeneratorTarget),
+ cleanFiles);
+ std::string const& binaryDir = lg->GetCurrentBinaryDirectory();
+ cmGlobalNinjaGenerator* gg = lg->GetGlobalNinjaGenerator();
+ for (std::string const& cleanFile : cleanFiles) {
+ // Support relative paths
+ gg->AddAdditionalCleanFile(
+ cmSystemTools::CollapseFullPath(cleanFile, binaryDir), config);
+ }
+ }
+}
+
+cmNinjaDeps cmNinjaTargetGenerator::GetObjects(const std::string& config) const
+{
+ auto const it = this->Configs.find(config);
+ if (it != this->Configs.end()) {
+ return it->second.Objects;
+ }
+ return {};
+}
+
+void cmNinjaTargetGenerator::EnsureDirectoryExists(
+ const std::string& path) const
+{
+ if (cmSystemTools::FileIsFullPath(path)) {
+ cmSystemTools::MakeDirectory(path);
+ } else {
+ cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator();
+ std::string fullPath = gg->GetCMakeInstance()->GetHomeOutputDirectory();
+ // Also ensures their is a trailing slash.
+ gg->StripNinjaOutputPathPrefixAsSuffix(fullPath);
+ fullPath += path;
+ cmSystemTools::MakeDirectory(fullPath);
+ }
+}
+
+void cmNinjaTargetGenerator::EnsureParentDirectoryExists(
+ const std::string& path) const
+{
+ this->EnsureDirectoryExists(cmSystemTools::GetParentDirectory(path));
+}
+
+void cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()(
+ cmSourceFile const& source, const char* pkgloc, const std::string& config)
+{
+ // Skip OS X content when not building a Framework or Bundle.
+ if (!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) {
+ return;
+ }
+
+ std::string macdir =
+ this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc,
+ config);
+
+ // Reject files that collide with files from the Ninja file's native config.
+ if (config != this->FileConfig) {
+ std::string nativeMacdir =
+ this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(
+ pkgloc, this->FileConfig);
+ if (macdir == nativeMacdir) {
+ return;
+ }
+ }
+
+ // Get the input file location.
+ std::string input = source.GetFullPath();
+ input = this->Generator->GetGlobalGenerator()->ConvertToNinjaPath(input);
+
+ // Get the output file location.
+ std::string output =
+ cmStrCat(macdir, '/', cmSystemTools::GetFilenameName(input));
+ output = this->Generator->GetGlobalGenerator()->ConvertToNinjaPath(output);
+
+ // Write a build statement to copy the content into the bundle.
+ this->Generator->GetGlobalGenerator()->WriteMacOSXContentBuild(
+ input, output, this->FileConfig);
+
+ // Add as a dependency to the target so that it gets called.
+ this->Generator->Configs[config].ExtraFiles.push_back(std::move(output));
+}
+
+void cmNinjaTargetGenerator::addPoolNinjaVariable(
+ const std::string& pool_property, cmGeneratorTarget* target,
+ cmNinjaVars& vars)
+{
+ cmProp pool = target->GetProperty(pool_property);
+ if (pool) {
+ vars["pool"] = *pool;
+ }
+}
+
+bool cmNinjaTargetGenerator::ForceResponseFile()
+{
+ static std::string const forceRspFile = "CMAKE_NINJA_FORCE_RESPONSE_FILE";
+ return (this->GetMakefile()->IsDefinitionSet(forceRspFile) ||
+ cmSystemTools::HasEnv(forceRspFile));
+}
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
new file mode 100644
index 0000000..79dc622
--- /dev/null
+++ b/Source/cmNinjaTargetGenerator.h
@@ -0,0 +1,220 @@
+/* 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 <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm3p/json/value.h>
+
+#include "cmCommonTargetGenerator.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmNinjaTypes.h"
+#include "cmOSXBundleGenerator.h"
+
+class cmCustomCommand;
+class cmGeneratedFileStream;
+class cmGeneratorTarget;
+class cmLocalNinjaGenerator;
+class cmMakefile;
+class cmSourceFile;
+
+class cmNinjaTargetGenerator : public cmCommonTargetGenerator
+{
+public:
+ /// Create a cmNinjaTargetGenerator according to the @a target's type.
+ static std::unique_ptr<cmNinjaTargetGenerator> New(
+ cmGeneratorTarget* target);
+
+ /// Build a NinjaTargetGenerator.
+ cmNinjaTargetGenerator(cmGeneratorTarget* target);
+
+ /// Destructor.
+ ~cmNinjaTargetGenerator() override;
+
+ virtual void Generate(const std::string& config) = 0;
+
+ std::string GetTargetName() const;
+
+protected:
+ bool SetMsvcTargetPdbVariable(cmNinjaVars&, const std::string& config) const;
+
+ cmGeneratedFileStream& GetImplFileStream(const std::string& config) const;
+ cmGeneratedFileStream& GetCommonFileStream() const;
+ cmGeneratedFileStream& GetRulesFileStream() const;
+
+ cmGeneratorTarget* GetGeneratorTarget() const
+ {
+ return this->GeneratorTarget;
+ }
+
+ cmLocalNinjaGenerator* GetLocalGenerator() const
+ {
+ return this->LocalGenerator;
+ }
+
+ cmGlobalNinjaGenerator* GetGlobalGenerator() const;
+
+ cmMakefile* GetMakefile() const { return this->Makefile; }
+
+ std::string LanguageCompilerRule(const std::string& lang,
+ const std::string& config) const;
+ std::string LanguagePreprocessAndScanRule(std::string const& lang,
+ const std::string& config) const;
+ std::string LanguageScanRule(std::string const& lang,
+ const std::string& config) const;
+ std::string LanguageDyndepRule(std::string const& lang,
+ const std::string& config) const;
+ bool NeedDyndep(std::string const& lang, std::string const& config) const;
+ bool NeedExplicitPreprocessing(std::string const& lang) const;
+ bool CompileWithDefines(std::string const& lang) const;
+ bool NeedCxxModuleSupport(std::string const& lang,
+ std::string const& config) const;
+
+ std::string OrderDependsTargetForTarget(const std::string& config);
+
+ std::string ComputeOrderDependsForTarget();
+
+ /**
+ * Compute the flags for compilation of object files for a given @a language.
+ * @note Generally it is the value of the variable whose name is computed
+ * by LanguageFlagsVarName().
+ */
+ std::string ComputeFlagsForObject(cmSourceFile const* source,
+ const std::string& language,
+ const std::string& config);
+
+ void AddIncludeFlags(std::string& flags, std::string const& lang,
+ const std::string& config) override;
+
+ std::string ComputeDefines(cmSourceFile const* source,
+ const std::string& language,
+ const std::string& config);
+
+ std::string ComputeIncludes(cmSourceFile const* source,
+ const std::string& language,
+ const std::string& config);
+
+ std::string ConvertToNinjaPath(const std::string& path) const
+ {
+ return this->GetGlobalGenerator()->ConvertToNinjaPath(path);
+ }
+ cmGlobalNinjaGenerator::MapToNinjaPathImpl MapToNinjaPath() const
+ {
+ return this->GetGlobalGenerator()->MapToNinjaPath();
+ }
+
+ /// @return the list of link dependency for the given target @a target.
+ cmNinjaDeps ComputeLinkDeps(const std::string& linkLanguage,
+ const std::string& config,
+ bool ignoreType = false) const;
+
+ /// @return the source file path for the given @a source.
+ std::string GetSourceFilePath(cmSourceFile const* source) const;
+
+ /// @return the object file path for the given @a source.
+ std::string GetObjectFilePath(cmSourceFile const* source,
+ const std::string& config) const;
+
+ /// @return the preprocessed source file path for the given @a source.
+ std::string GetPreprocessedFilePath(cmSourceFile const* source,
+ const std::string& config) const;
+
+ /// @return the dyndep file path for this target.
+ std::string GetDyndepFilePath(std::string const& lang,
+ const std::string& config) const;
+
+ /// @return the target dependency scanner info file path
+ std::string GetTargetDependInfoPath(std::string const& lang,
+ const std::string& config) const;
+
+ /// @return the file path where the target named @a name is generated.
+ std::string GetTargetFilePath(const std::string& name,
+ const std::string& config) const;
+
+ /// @return the output path for the target.
+ virtual std::string GetTargetOutputDir(const std::string& config) const;
+
+ void WriteLanguageRules(const std::string& language,
+ const std::string& config);
+ void WriteCompileRule(const std::string& language,
+ const std::string& config);
+ void WriteObjectBuildStatements(const std::string& config,
+ const std::string& fileConfig,
+ bool firstForConfig);
+ void WriteObjectBuildStatement(cmSourceFile const* source,
+ const std::string& config,
+ const std::string& fileConfig,
+ bool firstForConfig);
+ void WriteTargetDependInfo(std::string const& lang,
+ const std::string& config);
+
+ void EmitSwiftDependencyInfo(cmSourceFile const* source,
+ const std::string& config);
+
+ void ExportObjectCompileCommand(
+ std::string const& language, std::string const& sourceFileName,
+ std::string const& objectDir, std::string const& objectFileName,
+ std::string const& objectFileDir, std::string const& flags,
+ std::string const& defines, std::string const& includes);
+
+ void AdditionalCleanFiles(const std::string& config);
+
+ cmNinjaDeps GetObjects(const std::string& config) const;
+
+ void EnsureDirectoryExists(const std::string& dir) const;
+ void EnsureParentDirectoryExists(const std::string& path) const;
+
+ // write rules for macOS Application Bundle content.
+ struct MacOSXContentGeneratorType
+ : cmOSXBundleGenerator::MacOSXContentGeneratorType
+ {
+ MacOSXContentGeneratorType(cmNinjaTargetGenerator* g,
+ std::string fileConfig)
+ : Generator(g)
+ , FileConfig(std::move(fileConfig))
+ {
+ }
+
+ void operator()(cmSourceFile const& source, const char* pkgloc,
+ const std::string& config) override;
+
+ private:
+ cmNinjaTargetGenerator* Generator;
+ std::string FileConfig;
+ };
+ friend struct MacOSXContentGeneratorType;
+
+ // Properly initialized by sub-classes.
+ std::unique_ptr<cmOSXBundleGenerator> OSXBundleGenerator;
+ std::set<std::string> MacContentFolders;
+
+ void addPoolNinjaVariable(const std::string& pool_property,
+ cmGeneratorTarget* target, cmNinjaVars& vars);
+
+ bool ForceResponseFile();
+
+private:
+ cmLocalNinjaGenerator* LocalGenerator;
+
+ struct ByConfig
+ {
+ /// List of object files for this target.
+ cmNinjaDeps Objects;
+ // Fortran Support
+ std::map<std::string, cmNinjaDeps> DDIFiles;
+ // Swift Support
+ Json::Value SwiftOutputMap;
+ std::vector<cmCustomCommand const*> CustomCommands;
+ cmNinjaDeps ExtraFiles;
+ std::unique_ptr<MacOSXContentGeneratorType> MacOSXContentGenerator;
+ };
+
+ std::map<std::string, ByConfig> Configs;
+};
diff --git a/Source/cmNinjaTypes.h b/Source/cmNinjaTypes.h
new file mode 100644
index 0000000..320f41b
--- /dev/null
+++ b/Source/cmNinjaTypes.h
@@ -0,0 +1,61 @@
+/* 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 <map>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+enum cmNinjaTargetDepends
+{
+ DependOnTargetArtifact,
+ DependOnTargetOrdering
+};
+
+using cmNinjaDeps = std::vector<std::string>;
+using cmNinjaOuts = std::set<std::string>;
+using cmNinjaVars = std::map<std::string, std::string>;
+
+class cmNinjaRule
+{
+public:
+ cmNinjaRule(std::string name)
+ : Name(std::move(name))
+ {
+ }
+
+ std::string Name;
+ std::string Command;
+ std::string Description;
+ std::string Comment;
+ std::string DepFile;
+ std::string DepType;
+ std::string RspFile;
+ std::string RspContent;
+ std::string Restat;
+ bool Generator = false;
+};
+
+class cmNinjaBuild
+{
+public:
+ cmNinjaBuild() = default;
+ cmNinjaBuild(std::string rule)
+ : Rule(std::move(rule))
+ {
+ }
+
+ std::string Comment;
+ std::string Rule;
+ cmNinjaDeps Outputs;
+ cmNinjaDeps ImplicitOuts;
+ cmNinjaDeps ExplicitDeps;
+ cmNinjaDeps ImplicitDeps;
+ cmNinjaDeps OrderOnlyDeps;
+ cmNinjaVars Variables;
+ std::string RspFile;
+};
diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx
new file mode 100644
index 0000000..a18ca20
--- /dev/null
+++ b/Source/cmNinjaUtilityTargetGenerator.cxx
@@ -0,0 +1,203 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmNinjaUtilityTargetGenerator.h"
+
+#include <algorithm>
+#include <array>
+#include <iterator>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmCustomCommand.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmLocalNinjaGenerator.h"
+#include "cmNinjaTypes.h"
+#include "cmOutputConverter.h"
+#include "cmProperty.h"
+#include "cmSourceFile.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+
+cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator(
+ cmGeneratorTarget* target)
+ : cmNinjaTargetGenerator(target)
+{
+}
+
+cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() = default;
+
+void cmNinjaUtilityTargetGenerator::Generate(const std::string& config)
+{
+ if (!this->GetGeneratorTarget()->Target->IsPerConfig()) {
+ this->WriteUtilBuildStatements(config, config);
+ return;
+ }
+
+ for (auto const& fileConfig : this->GetConfigNames()) {
+ if (!this->GetGlobalGenerator()
+ ->GetCrossConfigs(fileConfig)
+ .count(config)) {
+ continue;
+ }
+ if (fileConfig != config &&
+ this->GetGeneratorTarget()->GetType() == cmStateEnums::GLOBAL_TARGET) {
+ continue;
+ }
+ this->WriteUtilBuildStatements(config, fileConfig);
+ }
+}
+
+void cmNinjaUtilityTargetGenerator::WriteUtilBuildStatements(
+ std::string const& config, std::string const& fileConfig)
+{
+ cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator();
+ cmLocalNinjaGenerator* lg = this->GetLocalGenerator();
+ cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
+
+ std::string configDir;
+ if (genTarget->Target->IsPerConfig()) {
+ configDir = gg->ConfigDirectory(fileConfig);
+ }
+ std::string utilCommandName =
+ cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles", configDir, "/",
+ this->GetTargetName(), ".util");
+ utilCommandName = this->ConvertToNinjaPath(utilCommandName);
+
+ cmNinjaBuild phonyBuild("phony");
+ std::vector<std::string> commands;
+ cmNinjaDeps deps;
+ cmNinjaDeps util_outputs(1, utilCommandName);
+
+ bool uses_terminal = false;
+ {
+ std::array<std::vector<cmCustomCommand> const*, 2> const cmdLists = {
+ { &genTarget->GetPreBuildCommands(), &genTarget->GetPostBuildCommands() }
+ };
+
+ for (std::vector<cmCustomCommand> const* cmdList : cmdLists) {
+ for (cmCustomCommand const& ci : *cmdList) {
+ cmCustomCommandGenerator ccg(ci, fileConfig, lg);
+ lg->AppendCustomCommandDeps(ccg, deps, fileConfig);
+ lg->AppendCustomCommandLines(ccg, commands);
+ std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
+ std::transform(ccByproducts.begin(), ccByproducts.end(),
+ std::back_inserter(util_outputs),
+ this->MapToNinjaPath());
+ if (ci.GetUsesTerminal()) {
+ uses_terminal = true;
+ }
+ }
+ }
+ }
+
+ {
+ std::vector<cmSourceFile*> sources;
+ genTarget->GetSourceFiles(sources, config);
+ for (cmSourceFile const* source : sources) {
+ if (cmCustomCommand const* cc = source->GetCustomCommand()) {
+ cmCustomCommandGenerator ccg(*cc, config, lg);
+ lg->AddCustomCommandTarget(cc, genTarget);
+
+ // Depend on all custom command outputs.
+ const std::vector<std::string>& ccOutputs = ccg.GetOutputs();
+ const std::vector<std::string>& ccByproducts = ccg.GetByproducts();
+ std::transform(ccOutputs.begin(), ccOutputs.end(),
+ std::back_inserter(deps), this->MapToNinjaPath());
+ std::transform(ccByproducts.begin(), ccByproducts.end(),
+ std::back_inserter(deps), this->MapToNinjaPath());
+ }
+ }
+ }
+
+ std::string outputConfig;
+ if (genTarget->Target->IsPerConfig()) {
+ outputConfig = config;
+ }
+ lg->AppendTargetOutputs(genTarget, phonyBuild.Outputs, outputConfig);
+ if (genTarget->Target->GetType() != cmStateEnums::GLOBAL_TARGET) {
+ lg->AppendTargetOutputs(genTarget, gg->GetByproductsForCleanTarget(),
+ config);
+ std::copy(util_outputs.begin(), util_outputs.end(),
+ std::back_inserter(gg->GetByproductsForCleanTarget()));
+ }
+ lg->AppendTargetDepends(genTarget, deps, config, fileConfig,
+ DependOnTargetArtifact);
+
+ if (commands.empty()) {
+ phonyBuild.Comment = "Utility command for " + this->GetTargetName();
+ phonyBuild.ExplicitDeps = std::move(deps);
+ if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
+ gg->WriteBuild(this->GetImplFileStream(fileConfig), phonyBuild);
+ } else {
+ gg->WriteBuild(this->GetCommonFileStream(), phonyBuild);
+ }
+ } else {
+ std::string command =
+ lg->BuildCommandLine(commands, "utility", this->GeneratorTarget);
+ std::string desc;
+ cmProp echoStr = genTarget->GetProperty("EchoString");
+ if (echoStr) {
+ desc = *echoStr;
+ } else {
+ desc = "Running utility command for " + this->GetTargetName();
+ }
+
+ // TODO: fix problematic global targets. For now, search and replace the
+ // makefile vars.
+ cmSystemTools::ReplaceString(
+ command, "$(CMAKE_SOURCE_DIR)",
+ lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
+ cmOutputConverter::SHELL));
+ cmSystemTools::ReplaceString(
+ command, "$(CMAKE_BINARY_DIR)",
+ lg->ConvertToOutputFormat(lg->GetBinaryDirectory(),
+ cmOutputConverter::SHELL));
+ cmSystemTools::ReplaceString(command, "$(ARGS)", "");
+ command = gg->ExpandCFGIntDir(command, config);
+
+ if (command.find('$') != std::string::npos) {
+ return;
+ }
+
+ for (std::string const& util_output : util_outputs) {
+ gg->SeenCustomCommandOutput(util_output);
+ }
+
+ std::string ccConfig;
+ if (genTarget->Target->IsPerConfig() &&
+ genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
+ ccConfig = fileConfig;
+ }
+ if (config == fileConfig ||
+ gg->GetPerConfigUtilityTargets().count(genTarget->GetName())) {
+ gg->WriteCustomCommandBuild(
+ command, desc, "Utility command for " + this->GetTargetName(),
+ /*depfile*/ "", /*job_pool*/ "", uses_terminal,
+ /*restat*/ true, util_outputs, ccConfig, deps);
+ }
+
+ phonyBuild.ExplicitDeps.push_back(utilCommandName);
+ if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
+ gg->WriteBuild(this->GetImplFileStream(fileConfig), phonyBuild);
+ } else {
+ gg->WriteBuild(this->GetCommonFileStream(), phonyBuild);
+ }
+ }
+
+ // Find ADDITIONAL_CLEAN_FILES
+ this->AdditionalCleanFiles(config);
+
+ // Add an alias for the logical target name regardless of what directory
+ // contains it. Skip this for GLOBAL_TARGET because they are meant to
+ // be per-directory and have one at the top-level anyway.
+ if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
+ gg->AddTargetAlias(this->GetTargetName(), genTarget, config);
+ }
+}
diff --git a/Source/cmNinjaUtilityTargetGenerator.h b/Source/cmNinjaUtilityTargetGenerator.h
new file mode 100644
index 0000000..dbd3797
--- /dev/null
+++ b/Source/cmNinjaUtilityTargetGenerator.h
@@ -0,0 +1,24 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+
+#include "cmNinjaTargetGenerator.h"
+
+class cmGeneratorTarget;
+
+class cmNinjaUtilityTargetGenerator : public cmNinjaTargetGenerator
+{
+public:
+ cmNinjaUtilityTargetGenerator(cmGeneratorTarget* target);
+ ~cmNinjaUtilityTargetGenerator() override;
+
+ void Generate(const std::string& config) override;
+
+private:
+ void WriteUtilBuildStatements(std::string const& config,
+ std::string const& fileConfig);
+};
diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx
new file mode 100644
index 0000000..7eea4b2
--- /dev/null
+++ b/Source/cmOSXBundleGenerator.cxx
@@ -0,0 +1,217 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmOSXBundleGenerator.h"
+
+#include <cassert>
+
+#include "cmGeneratorTarget.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+
+class cmSourceFile;
+
+cmOSXBundleGenerator::cmOSXBundleGenerator(cmGeneratorTarget* target)
+ : GT(target)
+ , Makefile(target->Target->GetMakefile())
+ , LocalGenerator(target->GetLocalGenerator())
+ , MacContentFolders(nullptr)
+{
+ if (this->MustSkip()) {
+ return;
+ }
+}
+
+bool cmOSXBundleGenerator::MustSkip()
+{
+ return !this->GT->HaveWellDefinedOutputFiles();
+}
+
+void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName,
+ std::string& outpath,
+ const std::string& config)
+{
+ if (this->MustSkip()) {
+ return;
+ }
+
+ // Compute bundle directory names.
+ std::string out = cmStrCat(
+ outpath, '/',
+ this->GT->GetAppBundleDirectory(config, cmGeneratorTarget::FullLevel));
+ cmSystemTools::MakeDirectory(out);
+ this->Makefile->AddCMakeOutputFile(out);
+
+ // Configure the Info.plist file. Note that it needs the executable name
+ // to be set.
+ std::string plist = cmStrCat(
+ outpath, '/',
+ this->GT->GetAppBundleDirectory(config, cmGeneratorTarget::ContentLevel),
+ "/Info.plist");
+ this->LocalGenerator->GenerateAppleInfoPList(this->GT, targetName, plist);
+ this->Makefile->AddCMakeOutputFile(plist);
+ outpath = out;
+}
+
+void cmOSXBundleGenerator::CreateFramework(
+ const std::string& targetName, const std::string& outpath,
+ const std::string& config, const cmOSXBundleGenerator::SkipParts& skipParts)
+{
+ if (this->MustSkip()) {
+ return;
+ }
+
+ assert(this->MacContentFolders);
+
+ // Compute the location of the top-level foo.framework directory.
+ std::string contentdir = cmStrCat(
+ outpath, '/',
+ this->GT->GetFrameworkDirectory(config, cmGeneratorTarget::ContentLevel),
+ '/');
+
+ std::string newoutpath = outpath + "/" +
+ this->GT->GetFrameworkDirectory(config, cmGeneratorTarget::FullLevel);
+
+ std::string frameworkVersion = this->GT->GetFrameworkVersion();
+
+ std::string name = cmSystemTools::GetFilenameName(targetName);
+ if (!skipParts.infoPlist) {
+ // Configure the Info.plist file
+ std::string plist = newoutpath;
+ if (!this->Makefile->PlatformIsAppleEmbedded()) {
+ // Put the Info.plist file into the Resources directory.
+ this->MacContentFolders->insert("Resources");
+ plist += "/Resources";
+ }
+ plist += "/Info.plist";
+ this->LocalGenerator->GenerateFrameworkInfoPList(this->GT, name, plist);
+ }
+
+ // Generate Versions directory only for MacOSX frameworks
+ if (this->Makefile->PlatformIsAppleEmbedded()) {
+ return;
+ }
+
+ // TODO: Use the cmMakefileTargetGenerator::ExtraFiles vector to
+ // drive rules to create these files at build time.
+ std::string oldName;
+ std::string newName;
+
+ // Make foo.framework/Versions
+ std::string versions = cmStrCat(contentdir, "Versions");
+ cmSystemTools::MakeDirectory(versions);
+
+ // Make foo.framework/Versions/version
+ cmSystemTools::MakeDirectory(newoutpath);
+
+ // Current -> version
+ oldName = frameworkVersion;
+ newName = cmStrCat(versions, "/Current");
+ cmSystemTools::RemoveFile(newName);
+ cmSystemTools::CreateSymlink(oldName, newName);
+ this->Makefile->AddCMakeOutputFile(newName);
+
+ // foo -> Versions/Current/foo
+ oldName = cmStrCat("Versions/Current/", name);
+ newName = cmStrCat(contentdir, name);
+ cmSystemTools::RemoveFile(newName);
+ cmSystemTools::CreateSymlink(oldName, newName);
+ this->Makefile->AddCMakeOutputFile(newName);
+
+ // Resources -> Versions/Current/Resources
+ if (this->MacContentFolders->find("Resources") !=
+ this->MacContentFolders->end()) {
+ oldName = "Versions/Current/Resources";
+ newName = cmStrCat(contentdir, "Resources");
+ cmSystemTools::RemoveFile(newName);
+ cmSystemTools::CreateSymlink(oldName, newName);
+ this->Makefile->AddCMakeOutputFile(newName);
+ }
+
+ // Headers -> Versions/Current/Headers
+ if (this->MacContentFolders->find("Headers") !=
+ this->MacContentFolders->end()) {
+ oldName = "Versions/Current/Headers";
+ newName = cmStrCat(contentdir, "Headers");
+ cmSystemTools::RemoveFile(newName);
+ cmSystemTools::CreateSymlink(oldName, newName);
+ this->Makefile->AddCMakeOutputFile(newName);
+ }
+
+ // PrivateHeaders -> Versions/Current/PrivateHeaders
+ if (this->MacContentFolders->find("PrivateHeaders") !=
+ this->MacContentFolders->end()) {
+ oldName = "Versions/Current/PrivateHeaders";
+ newName = cmStrCat(contentdir, "PrivateHeaders");
+ cmSystemTools::RemoveFile(newName);
+ cmSystemTools::CreateSymlink(oldName, newName);
+ this->Makefile->AddCMakeOutputFile(newName);
+ }
+}
+
+void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName,
+ const std::string& root,
+ const std::string& config)
+{
+ if (this->MustSkip()) {
+ return;
+ }
+
+ // Compute bundle directory names.
+ std::string out = cmStrCat(
+ root, '/',
+ this->GT->GetCFBundleDirectory(config, cmGeneratorTarget::FullLevel));
+ cmSystemTools::MakeDirectory(out);
+ this->Makefile->AddCMakeOutputFile(out);
+
+ // Configure the Info.plist file. Note that it needs the executable name
+ // to be set.
+ std::string plist = cmStrCat(
+ root, '/',
+ this->GT->GetCFBundleDirectory(config, cmGeneratorTarget::ContentLevel),
+ "/Info.plist");
+ std::string name = cmSystemTools::GetFilenameName(targetName);
+ this->LocalGenerator->GenerateAppleInfoPList(this->GT, name, plist);
+ this->Makefile->AddCMakeOutputFile(plist);
+}
+
+void cmOSXBundleGenerator::GenerateMacOSXContentStatements(
+ std::vector<cmSourceFile const*> const& sources,
+ MacOSXContentGeneratorType* generator, const std::string& config)
+{
+ if (this->MustSkip()) {
+ return;
+ }
+
+ for (cmSourceFile const* source : sources) {
+ cmGeneratorTarget::SourceFileFlags tsFlags =
+ this->GT->GetTargetSourceFileFlags(source);
+ if (tsFlags.Type != cmGeneratorTarget::SourceFileTypeNormal) {
+ (*generator)(*source, tsFlags.MacFolder, config);
+ }
+ }
+}
+
+std::string cmOSXBundleGenerator::InitMacOSXContentDirectory(
+ const char* pkgloc, const std::string& config)
+{
+ // Construct the full path to the content subdirectory.
+
+ std::string macdir = cmStrCat(this->GT->GetMacContentDirectory(
+ config, cmStateEnums::RuntimeBinaryArtifact),
+ '/', pkgloc);
+ cmSystemTools::MakeDirectory(macdir);
+
+ // Record use of this content location. Only the first level
+ // directory is needed.
+ {
+ std::string loc = pkgloc;
+ loc = loc.substr(0, loc.find('/'));
+ this->MacContentFolders->insert(loc);
+ }
+
+ return macdir;
+}
diff --git a/Source/cmOSXBundleGenerator.h b/Source/cmOSXBundleGenerator.h
new file mode 100644
index 0000000..a3b6f98
--- /dev/null
+++ b/Source/cmOSXBundleGenerator.h
@@ -0,0 +1,69 @@
+/* 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>
+
+class cmGeneratorTarget;
+class cmLocalGenerator;
+class cmMakefile;
+class cmSourceFile;
+
+class cmOSXBundleGenerator
+{
+public:
+ cmOSXBundleGenerator(cmGeneratorTarget* target);
+
+ struct SkipParts
+ {
+ SkipParts()
+ : infoPlist(false)
+ {
+ }
+ bool infoPlist; // NOLINT(modernize-use-default-member-init)
+ };
+
+ // create an app bundle at a given root, and return
+ // the directory within the bundle that contains the executable
+ void CreateAppBundle(const std::string& targetName, std::string& root,
+ const std::string& config);
+
+ // create a framework at a given root
+ void CreateFramework(const std::string& targetName, const std::string& root,
+ const std::string& config,
+ const SkipParts& skipParts = SkipParts());
+
+ // create a cf bundle at a given root
+ void CreateCFBundle(const std::string& targetName, const std::string& root,
+ const std::string& config);
+
+ struct MacOSXContentGeneratorType
+ {
+ virtual ~MacOSXContentGeneratorType() = default;
+ virtual void operator()(cmSourceFile const& source, const char* pkgloc,
+ const std::string& config) = 0;
+ };
+
+ void GenerateMacOSXContentStatements(
+ std::vector<cmSourceFile const*> const& sources,
+ MacOSXContentGeneratorType* generator, const std::string& config);
+ std::string InitMacOSXContentDirectory(const char* pkgloc,
+ const std::string& config);
+
+ void SetMacContentFolders(std::set<std::string>* macContentFolders)
+ {
+ this->MacContentFolders = macContentFolders;
+ }
+
+private:
+ bool MustSkip();
+
+ cmGeneratorTarget* GT;
+ cmMakefile* Makefile;
+ cmLocalGenerator* LocalGenerator;
+ std::set<std::string>* MacContentFolders;
+};
diff --git a/Source/cmOptionCommand.cxx b/Source/cmOptionCommand.cxx
new file mode 100644
index 0000000..a58e2f8
--- /dev/null
+++ b/Source/cmOptionCommand.cxx
@@ -0,0 +1,86 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmOptionCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+
+// cmOptionCommand
+bool cmOptionCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ const bool argError = (args.size() < 2) || (args.size() > 3);
+ if (argError) {
+ std::string m = cmStrCat("called with incorrect number of arguments: ",
+ cmJoin(args, " "));
+ status.SetError(m);
+ return false;
+ }
+
+ // Determine the state of the option policy
+ bool checkAndWarn = false;
+ {
+ auto policyStatus =
+ status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0077);
+ const auto* existsBeforeSet =
+ status.GetMakefile().GetStateSnapshot().GetDefinition(args[0]);
+ switch (policyStatus) {
+ case cmPolicies::WARN:
+ checkAndWarn = (existsBeforeSet != nullptr);
+ break;
+ case cmPolicies::OLD:
+ // OLD behavior does not warn.
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW: {
+ // See if a local variable with this name already exists.
+ // If so we ignore the option command.
+ if (existsBeforeSet) {
+ return true;
+ }
+ } break;
+ }
+ }
+
+ // See if a cache variable with this name already exists
+ // If so just make sure the doc state is correct
+ cmState* state = status.GetMakefile().GetState();
+ cmProp existingValue = state->GetCacheEntryValue(args[0]);
+ if (existingValue &&
+ (state->GetCacheEntryType(args[0]) != cmStateEnums::UNINITIALIZED)) {
+ state->SetCacheEntryProperty(args[0], "HELPSTRING", args[1]);
+ return true;
+ }
+
+ // Nothing in the cache so add it
+ std::string initialValue = existingValue ? *existingValue : "Off";
+ if (args.size() == 3) {
+ initialValue = args[2];
+ }
+ bool init = cmIsOn(initialValue);
+ status.GetMakefile().AddCacheDefinition(args[0], init ? "ON" : "OFF",
+ args[1].c_str(), cmStateEnums::BOOL);
+
+ if (checkAndWarn) {
+ const auto* existsAfterSet =
+ status.GetMakefile().GetStateSnapshot().GetDefinition(args[0]);
+ if (!existsAfterSet) {
+ status.GetMakefile().IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0077),
+ "\n"
+ "For compatibility with older versions of CMake, option "
+ "is clearing the normal variable '",
+ args[0], "'."));
+ }
+ }
+ return true;
+}
diff --git a/Source/cmOptionCommand.h b/Source/cmOptionCommand.h
new file mode 100644
index 0000000..912e0ee
--- /dev/null
+++ b/Source/cmOptionCommand.h
@@ -0,0 +1,18 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Provide an option to the user
+ *
+ * cmOptionCommand provides an option for the user to select
+ */
+bool cmOptionCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx
new file mode 100644
index 0000000..68f40a9
--- /dev/null
+++ b/Source/cmOrderDirectories.cxx
@@ -0,0 +1,564 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmOrderDirectories.h"
+
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <sstream>
+#include <vector>
+
+#include <cm/memory>
+#include <cmext/algorithm>
+
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmMessageType.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+/*
+Directory ordering computation.
+ - Useful to compute a safe runtime library path order
+ - Need runtime path for supporting INSTALL_RPATH_USE_LINK_PATH
+ - Need runtime path at link time to pickup transitive link dependencies
+ for shared libraries.
+*/
+
+class cmOrderDirectoriesConstraint
+{
+public:
+ cmOrderDirectoriesConstraint(cmOrderDirectories* od, std::string const& file)
+ : OD(od)
+ , GlobalGenerator(od->GlobalGenerator)
+ {
+ this->FullPath = file;
+
+ if (file.rfind(".framework") != std::string::npos) {
+ static cmsys::RegularExpression splitFramework(
+ "^(.*)/(.*).framework/(.*)$");
+ if (splitFramework.find(file) &&
+ (std::string::npos !=
+ splitFramework.match(3).find(splitFramework.match(2)))) {
+ this->Directory = splitFramework.match(1);
+ this->FileName =
+ std::string(file.begin() + this->Directory.size() + 1, file.end());
+ }
+ }
+
+ if (this->FileName.empty()) {
+ this->Directory = cmSystemTools::GetFilenamePath(file);
+ this->FileName = cmSystemTools::GetFilenameName(file);
+ }
+ }
+ virtual ~cmOrderDirectoriesConstraint() = default;
+
+ void AddDirectory()
+ {
+ this->DirectoryIndex = this->OD->AddOriginalDirectory(this->Directory);
+ }
+
+ virtual void Report(std::ostream& e) = 0;
+
+ void FindConflicts(unsigned int index)
+ {
+ for (unsigned int i = 0; i < this->OD->OriginalDirectories.size(); ++i) {
+ // Check if this directory conflicts with the entry.
+ std::string const& dir = this->OD->OriginalDirectories[i];
+ if (!this->OD->IsSameDirectory(dir, this->Directory) &&
+ this->FindConflict(dir)) {
+ // The library will be found in this directory but this is not
+ // the directory named for it. Add an entry to make sure the
+ // desired directory comes before this one.
+ cmOrderDirectories::ConflictPair p(this->DirectoryIndex, index);
+ this->OD->ConflictGraph[i].push_back(p);
+ }
+ }
+ }
+
+ void FindImplicitConflicts(std::ostringstream& w)
+ {
+ bool first = true;
+ for (std::string const& dir : this->OD->OriginalDirectories) {
+ // Check if this directory conflicts with the entry.
+ if (dir != this->Directory &&
+ cmSystemTools::GetRealPath(dir) !=
+ cmSystemTools::GetRealPath(this->Directory) &&
+ this->FindConflict(dir)) {
+ // The library will be found in this directory but it is
+ // supposed to be found in an implicit search directory.
+ if (first) {
+ first = false;
+ w << " ";
+ this->Report(w);
+ w << " in " << this->Directory << " may be hidden by files in:\n";
+ }
+ w << " " << dir << "\n";
+ }
+ }
+ }
+
+protected:
+ virtual bool FindConflict(std::string const& dir) = 0;
+
+ bool FileMayConflict(std::string const& dir, std::string const& name);
+
+ cmOrderDirectories* OD;
+ cmGlobalGenerator* GlobalGenerator;
+
+ // The location in which the item is supposed to be found.
+ std::string FullPath;
+ std::string Directory;
+ std::string FileName;
+
+ // The index assigned to the directory.
+ int DirectoryIndex;
+};
+
+bool cmOrderDirectoriesConstraint::FileMayConflict(std::string const& dir,
+ std::string const& name)
+{
+ // Check if the file exists on disk.
+ std::string file = cmStrCat(dir, '/', name);
+ if (cmSystemTools::FileExists(file, true)) {
+ // The file conflicts only if it is not the same as the original
+ // file due to a symlink or hardlink.
+ return !cmSystemTools::SameFile(this->FullPath, file);
+ }
+
+ // Check if the file will be built by cmake.
+ std::set<std::string> const& files =
+ (this->GlobalGenerator->GetDirectoryContent(dir, false));
+ auto fi = files.find(name);
+ return fi != files.end();
+}
+
+class cmOrderDirectoriesConstraintSOName : public cmOrderDirectoriesConstraint
+{
+public:
+ cmOrderDirectoriesConstraintSOName(cmOrderDirectories* od,
+ std::string const& file,
+ const char* soname)
+ : cmOrderDirectoriesConstraint(od, file)
+ , SOName(soname ? soname : "")
+ {
+ if (this->SOName.empty()) {
+ // Try to guess the soname.
+ std::string soguess;
+ if (cmSystemTools::GuessLibrarySOName(file, soguess)) {
+ this->SOName = soguess;
+ }
+ }
+ }
+
+ void Report(std::ostream& e) override
+ {
+ e << "runtime library [";
+ if (this->SOName.empty()) {
+ e << this->FileName;
+ } else {
+ e << this->SOName;
+ }
+ e << "]";
+ }
+
+ bool FindConflict(std::string const& dir) override;
+
+private:
+ // The soname of the shared library if it is known.
+ std::string SOName;
+};
+
+bool cmOrderDirectoriesConstraintSOName::FindConflict(std::string const& dir)
+{
+ // Determine which type of check to do.
+ if (!this->SOName.empty()) {
+ // We have the library soname. Check if it will be found.
+ if (this->FileMayConflict(dir, this->SOName)) {
+ return true;
+ }
+ } else {
+ // We do not have the soname. Look for files in the directory
+ // that may conflict.
+ std::set<std::string> const& files =
+ (this->GlobalGenerator->GetDirectoryContent(dir, true));
+
+ // Get the set of files that might conflict. Since we do not
+ // know the soname just look at all files that start with the
+ // file name. Usually the soname starts with the library name.
+ std::string base = this->FileName;
+ auto first = files.lower_bound(base);
+ ++base.back();
+ auto last = files.upper_bound(base);
+ if (first != last) {
+ return true;
+ }
+ }
+ return false;
+}
+
+class cmOrderDirectoriesConstraintLibrary : public cmOrderDirectoriesConstraint
+{
+public:
+ cmOrderDirectoriesConstraintLibrary(cmOrderDirectories* od,
+ std::string const& file)
+ : cmOrderDirectoriesConstraint(od, file)
+ {
+ }
+
+ void Report(std::ostream& e) override
+ {
+ e << "link library [" << this->FileName << "]";
+ }
+
+ bool FindConflict(std::string const& dir) override;
+};
+
+bool cmOrderDirectoriesConstraintLibrary::FindConflict(std::string const& dir)
+{
+ // We have the library file name. Check if it will be found.
+ if (this->FileMayConflict(dir, this->FileName)) {
+ return true;
+ }
+
+ // Now check if the file exists with other extensions the linker
+ // might consider.
+ if (!this->OD->LinkExtensions.empty() &&
+ this->OD->RemoveLibraryExtension.find(this->FileName)) {
+ std::string lib = this->OD->RemoveLibraryExtension.match(1);
+ std::string ext = this->OD->RemoveLibraryExtension.match(2);
+ for (std::string const& LinkExtension : this->OD->LinkExtensions) {
+ if (LinkExtension != ext) {
+ std::string fname = cmStrCat(lib, LinkExtension);
+ if (this->FileMayConflict(dir, fname)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+cmOrderDirectories::cmOrderDirectories(cmGlobalGenerator* gg,
+ const cmGeneratorTarget* target,
+ const char* purpose)
+{
+ this->GlobalGenerator = gg;
+ this->Target = target;
+ this->Purpose = purpose;
+ this->Computed = false;
+}
+
+cmOrderDirectories::~cmOrderDirectories() = default;
+
+std::vector<std::string> const& cmOrderDirectories::GetOrderedDirectories()
+{
+ if (!this->Computed) {
+ this->Computed = true;
+ this->CollectOriginalDirectories();
+ this->FindConflicts();
+ this->OrderDirectories();
+ }
+ return this->OrderedDirectories;
+}
+
+void cmOrderDirectories::AddRuntimeLibrary(std::string const& fullPath,
+ const char* soname)
+{
+ // Add the runtime library at most once.
+ if (this->EmmittedConstraintSOName.insert(fullPath).second) {
+ // Implicit link directories need special handling.
+ if (!this->ImplicitDirectories.empty()) {
+ std::string dir = cmSystemTools::GetFilenamePath(fullPath);
+
+ if (fullPath.rfind(".framework") != std::string::npos) {
+ static cmsys::RegularExpression splitFramework(
+ "^(.*)/(.*).framework/(.*)$");
+ if (splitFramework.find(fullPath) &&
+ (std::string::npos !=
+ splitFramework.match(3).find(splitFramework.match(2)))) {
+ dir = splitFramework.match(1);
+ }
+ }
+
+ if (this->IsImplicitDirectory(dir)) {
+ this->ImplicitDirEntries.push_back(
+ cm::make_unique<cmOrderDirectoriesConstraintSOName>(this, fullPath,
+ soname));
+ return;
+ }
+ }
+
+ // Construct the runtime information entry for this library.
+ this->ConstraintEntries.push_back(
+ cm::make_unique<cmOrderDirectoriesConstraintSOName>(this, fullPath,
+ soname));
+ } else {
+ // This can happen if the same library is linked multiple times.
+ // In that case the runtime information check need be done only
+ // once anyway. For shared libs we could add a check in AddItem
+ // to not repeat them.
+ }
+}
+
+void cmOrderDirectories::AddLinkLibrary(std::string const& fullPath)
+{
+ // Link extension info is required for library constraints.
+ assert(!this->LinkExtensions.empty());
+
+ // Add the link library at most once.
+ if (this->EmmittedConstraintLibrary.insert(fullPath).second) {
+ // Implicit link directories need special handling.
+ if (!this->ImplicitDirectories.empty()) {
+ std::string dir = cmSystemTools::GetFilenamePath(fullPath);
+ if (this->IsImplicitDirectory(dir)) {
+ this->ImplicitDirEntries.push_back(
+ cm::make_unique<cmOrderDirectoriesConstraintLibrary>(this,
+ fullPath));
+ return;
+ }
+ }
+
+ // Construct the link library entry.
+ this->ConstraintEntries.push_back(
+ cm::make_unique<cmOrderDirectoriesConstraintLibrary>(this, fullPath));
+ }
+}
+
+void cmOrderDirectories::AddUserDirectories(
+ std::vector<std::string> const& extra)
+{
+ cm::append(this->UserDirectories, extra);
+}
+
+void cmOrderDirectories::AddLanguageDirectories(
+ std::vector<std::string> const& dirs)
+{
+ cm::append(this->LanguageDirectories, dirs);
+}
+
+void cmOrderDirectories::SetImplicitDirectories(
+ std::set<std::string> const& implicitDirs)
+{
+ this->ImplicitDirectories.clear();
+ for (std::string const& implicitDir : implicitDirs) {
+ this->ImplicitDirectories.insert(this->GetRealPath(implicitDir));
+ }
+}
+
+bool cmOrderDirectories::IsImplicitDirectory(std::string const& dir)
+{
+ std::string const& real = this->GetRealPath(dir);
+ return this->ImplicitDirectories.find(real) !=
+ this->ImplicitDirectories.end();
+}
+
+void cmOrderDirectories::SetLinkExtensionInfo(
+ std::vector<std::string> const& linkExtensions,
+ std::string const& removeExtRegex)
+{
+ this->LinkExtensions = linkExtensions;
+ this->RemoveLibraryExtension.compile(removeExtRegex);
+}
+
+void cmOrderDirectories::CollectOriginalDirectories()
+{
+ // Add user directories specified for inclusion. These should be
+ // indexed first so their original order is preserved as much as
+ // possible subject to the constraints.
+ this->AddOriginalDirectories(this->UserDirectories);
+
+ // Add directories containing constraints.
+ for (const auto& entry : this->ConstraintEntries) {
+ entry->AddDirectory();
+ }
+
+ // Add language runtime directories last.
+ this->AddOriginalDirectories(this->LanguageDirectories);
+}
+
+int cmOrderDirectories::AddOriginalDirectory(std::string const& dir)
+{
+ // Add the runtime directory with a unique index.
+ auto i = this->DirectoryIndex.find(dir);
+ if (i == this->DirectoryIndex.end()) {
+ std::map<std::string, int>::value_type entry(
+ dir, static_cast<int>(this->OriginalDirectories.size()));
+ i = this->DirectoryIndex.insert(entry).first;
+ this->OriginalDirectories.push_back(dir);
+ }
+
+ return i->second;
+}
+
+void cmOrderDirectories::AddOriginalDirectories(
+ std::vector<std::string> const& dirs)
+{
+ for (std::string const& dir : dirs) {
+ // We never explicitly specify implicit link directories.
+ if (this->IsImplicitDirectory(dir)) {
+ continue;
+ }
+
+ // Skip the empty string.
+ if (dir.empty()) {
+ continue;
+ }
+
+ // Add this directory.
+ this->AddOriginalDirectory(dir);
+ }
+}
+
+struct cmOrderDirectoriesCompare
+{
+ using ConflictPair = std::pair<int, int>;
+
+ // The conflict pair is unique based on just the directory
+ // (first). The second element is only used for displaying
+ // information about why the entry is present.
+ bool operator()(ConflictPair l, ConflictPair r)
+ {
+ return l.first == r.first;
+ }
+};
+
+void cmOrderDirectories::FindConflicts()
+{
+ // Allocate the conflict graph.
+ this->ConflictGraph.resize(this->OriginalDirectories.size());
+ this->DirectoryVisited.resize(this->OriginalDirectories.size(), 0);
+
+ // Find directories conflicting with each entry.
+ for (unsigned int i = 0; i < this->ConstraintEntries.size(); ++i) {
+ this->ConstraintEntries[i]->FindConflicts(i);
+ }
+
+ // Clean up the conflict graph representation.
+ for (ConflictList& cl : this->ConflictGraph) {
+ // Sort the outgoing edges for each graph node so that the
+ // original order will be preserved as much as possible.
+ std::sort(cl.begin(), cl.end());
+
+ // Make the edge list unique so cycle detection will be reliable.
+ auto last = std::unique(cl.begin(), cl.end(), cmOrderDirectoriesCompare());
+ cl.erase(last, cl.end());
+ }
+
+ // Check items in implicit link directories.
+ this->FindImplicitConflicts();
+}
+
+void cmOrderDirectories::FindImplicitConflicts()
+{
+ // Check for items in implicit link directories that have conflicts
+ // in the explicit directories.
+ std::ostringstream conflicts;
+ for (const auto& entry : this->ImplicitDirEntries) {
+ entry->FindImplicitConflicts(conflicts);
+ }
+
+ // Skip warning if there were no conflicts.
+ std::string const text = conflicts.str();
+ if (text.empty()) {
+ return;
+ }
+
+ // Warn about the conflicts.
+ this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
+ MessageType::WARNING,
+ cmStrCat("Cannot generate a safe ", this->Purpose, " for target ",
+ this->Target->GetName(),
+ " because files in some directories may "
+ "conflict with libraries in implicit directories:\n",
+ text, "Some of these libraries may not be found correctly."),
+ this->Target->GetBacktrace());
+}
+
+void cmOrderDirectories::OrderDirectories()
+{
+ // Allow a cycle to be diagnosed once.
+ this->CycleDiagnosed = false;
+ this->WalkId = 0;
+
+ // Iterate through the directories in the original order.
+ for (unsigned int i = 0; i < this->OriginalDirectories.size(); ++i) {
+ // Start a new DFS from this node.
+ ++this->WalkId;
+ this->VisitDirectory(i);
+ }
+}
+
+void cmOrderDirectories::VisitDirectory(unsigned int i)
+{
+ // Skip nodes already visited.
+ if (this->DirectoryVisited[i]) {
+ if (this->DirectoryVisited[i] == this->WalkId) {
+ // We have reached a node previously visited on this DFS.
+ // There is a cycle.
+ this->DiagnoseCycle();
+ }
+ return;
+ }
+
+ // We are now visiting this node so mark it.
+ this->DirectoryVisited[i] = this->WalkId;
+
+ // Visit the neighbors of the node first.
+ ConflictList const& clist = this->ConflictGraph[i];
+ for (ConflictPair const& j : clist) {
+ this->VisitDirectory(j.first);
+ }
+
+ // Now that all directories required to come before this one have
+ // been emmitted, emit this directory.
+ this->OrderedDirectories.push_back(this->OriginalDirectories[i]);
+}
+
+void cmOrderDirectories::DiagnoseCycle()
+{
+ // Report the cycle at most once.
+ if (this->CycleDiagnosed) {
+ return;
+ }
+ this->CycleDiagnosed = true;
+
+ // Construct the message.
+ std::ostringstream e;
+ e << "Cannot generate a safe " << this->Purpose << " for target "
+ << this->Target->GetName()
+ << " because there is a cycle in the constraint graph:\n";
+
+ // Display the conflict graph.
+ for (unsigned int i = 0; i < this->ConflictGraph.size(); ++i) {
+ ConflictList const& clist = this->ConflictGraph[i];
+ e << " dir " << i << " is [" << this->OriginalDirectories[i] << "]\n";
+ for (ConflictPair const& j : clist) {
+ e << " dir " << j.first << " must precede it due to ";
+ this->ConstraintEntries[j.second]->Report(e);
+ e << "\n";
+ }
+ }
+ e << "Some of these libraries may not be found correctly.";
+ this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
+ MessageType::WARNING, e.str(), this->Target->GetBacktrace());
+}
+
+bool cmOrderDirectories::IsSameDirectory(std::string const& l,
+ std::string const& r)
+{
+ return this->GetRealPath(l) == this->GetRealPath(r);
+}
+
+std::string const& cmOrderDirectories::GetRealPath(std::string const& dir)
+{
+ auto i = this->RealPaths.lower_bound(dir);
+ if (i == this->RealPaths.end() ||
+ this->RealPaths.key_comp()(dir, i->first)) {
+ using value_type = std::map<std::string, std::string>::value_type;
+ i = this->RealPaths.insert(
+ i, value_type(dir, cmSystemTools::GetRealPath(dir)));
+ }
+ return i->second;
+}
diff --git a/Source/cmOrderDirectories.h b/Source/cmOrderDirectories.h
new file mode 100644
index 0000000..7788ea8
--- /dev/null
+++ b/Source/cmOrderDirectories.h
@@ -0,0 +1,96 @@
+/* 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 <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmOrderDirectoriesConstraint;
+
+/** \class cmOrderDirectories
+ * \brief Compute a safe runtime path order for a set of shared libraries.
+ */
+class cmOrderDirectories
+{
+public:
+ cmOrderDirectories(cmGlobalGenerator* gg, cmGeneratorTarget const* target,
+ const char* purpose);
+ ~cmOrderDirectories();
+ cmOrderDirectories(const cmOrderDirectories&) = delete;
+ cmOrderDirectories& operator=(const cmOrderDirectories&) = delete;
+ void AddRuntimeLibrary(std::string const& fullPath,
+ const char* soname = nullptr);
+ void AddLinkLibrary(std::string const& fullPath);
+ void AddUserDirectories(std::vector<std::string> const& extra);
+ void AddLanguageDirectories(std::vector<std::string> const& dirs);
+ void SetImplicitDirectories(std::set<std::string> const& implicitDirs);
+ void SetLinkExtensionInfo(std::vector<std::string> const& linkExtensions,
+ std::string const& removeExtRegex);
+
+ std::vector<std::string> const& GetOrderedDirectories();
+
+private:
+ cmGlobalGenerator* GlobalGenerator;
+ cmGeneratorTarget const* Target;
+ std::string Purpose;
+
+ std::vector<std::string> OrderedDirectories;
+
+ std::vector<std::unique_ptr<cmOrderDirectoriesConstraint>> ConstraintEntries;
+ std::vector<std::unique_ptr<cmOrderDirectoriesConstraint>>
+ ImplicitDirEntries;
+ std::vector<std::string> UserDirectories;
+ std::vector<std::string> LanguageDirectories;
+ cmsys::RegularExpression RemoveLibraryExtension;
+ std::vector<std::string> LinkExtensions;
+ std::set<std::string> ImplicitDirectories;
+ std::set<std::string> EmmittedConstraintSOName;
+ std::set<std::string> EmmittedConstraintLibrary;
+ std::vector<std::string> OriginalDirectories;
+ std::map<std::string, int> DirectoryIndex;
+ std::vector<int> DirectoryVisited;
+ void CollectOriginalDirectories();
+ int AddOriginalDirectory(std::string const& dir);
+ void AddOriginalDirectories(std::vector<std::string> const& dirs);
+ void FindConflicts();
+ void FindImplicitConflicts();
+ void OrderDirectories();
+ void VisitDirectory(unsigned int i);
+ void DiagnoseCycle();
+ int WalkId;
+ bool CycleDiagnosed;
+ bool Computed;
+
+ // Adjacency-list representation of runtime path ordering graph.
+ // This maps from directory to those that must come *before* it.
+ // Each entry that must come before is a pair. The first element is
+ // the index of the directory that must come first. The second
+ // element is the index of the runtime library that added the
+ // constraint.
+ using ConflictPair = std::pair<int, int>;
+ struct ConflictList : public std::vector<ConflictPair>
+ {
+ };
+ std::vector<ConflictList> ConflictGraph;
+
+ // Compare directories after resolving symlinks.
+ bool IsSameDirectory(std::string const& l, std::string const& r);
+
+ bool IsImplicitDirectory(std::string const& dir);
+
+ std::string const& GetRealPath(std::string const& dir);
+ std::map<std::string, std::string> RealPaths;
+
+ friend class cmOrderDirectoriesConstraint;
+ friend class cmOrderDirectoriesConstraintLibrary;
+};
diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx
new file mode 100644
index 0000000..ec54537
--- /dev/null
+++ b/Source/cmOutputConverter.cxx
@@ -0,0 +1,529 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmOutputConverter.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <set>
+#include <vector>
+
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmOutputConverter::cmOutputConverter(cmStateSnapshot const& snapshot)
+ : StateSnapshot(snapshot)
+ , LinkScriptShell(false)
+{
+ assert(this->StateSnapshot.IsValid());
+}
+
+std::string cmOutputConverter::ConvertToOutputForExisting(
+ const std::string& remote, OutputFormat format) const
+{
+ // If this is a windows shell, the result has a space, and the path
+ // already exists, we can use a short-path to reference it without a
+ // space.
+ if (this->GetState()->UseWindowsShell() &&
+ remote.find_first_of(" #") != std::string::npos &&
+ cmSystemTools::FileExists(remote)) {
+ std::string tmp;
+ if (cmSystemTools::GetShortPath(remote, tmp)) {
+ return this->ConvertToOutputFormat(tmp, format);
+ }
+ }
+
+ // Otherwise, perform standard conversion.
+ return this->ConvertToOutputFormat(remote, format);
+}
+
+std::string cmOutputConverter::ConvertToOutputFormat(cm::string_view source,
+ OutputFormat output) const
+{
+ std::string result(source);
+ // Convert it to an output path.
+ if (output == SHELL || output == WATCOMQUOTE || output == NINJAMULTI) {
+ result = this->ConvertDirectorySeparatorsForShell(source);
+ result = this->EscapeForShell(result, true, false, output == WATCOMQUOTE,
+ output == NINJAMULTI);
+ } else if (output == RESPONSE) {
+ result = this->EscapeForShell(result, false, false, false);
+ }
+ return result;
+}
+
+std::string cmOutputConverter::ConvertDirectorySeparatorsForShell(
+ cm::string_view source) const
+{
+ std::string result(source);
+ // For the MSYS shell convert drive letters to posix paths, so
+ // that c:/some/path becomes /c/some/path. This is needed to
+ // avoid problems with the shell path translation.
+ if (this->GetState()->UseMSYSShell() && !this->LinkScriptShell) {
+ if (result.size() > 2 && result[1] == ':') {
+ result[1] = result[0];
+ result[0] = '/';
+ }
+ }
+ if (this->GetState()->UseWindowsShell()) {
+ std::replace(result.begin(), result.end(), '/', '\\');
+ }
+ return result;
+}
+
+static bool cmOutputConverterIsShellOperator(cm::string_view str)
+{
+ static std::set<cm::string_view> const shellOperators{
+ "<", ">", "<<", ">>", "|", "||", "&&", "&>", "1>", "2>", "2>&1", "1>&2"
+ };
+ return (shellOperators.count(str) != 0);
+}
+
+std::string cmOutputConverter::EscapeForShell(
+ cm::string_view str, bool makeVars, bool forEcho, bool useWatcomQuote,
+ bool unescapeNinjaConfiguration) const
+{
+ // Do not escape shell operators.
+ if (cmOutputConverterIsShellOperator(str)) {
+ return std::string(str);
+ }
+
+ // Compute the flags for the target shell environment.
+ int flags = 0;
+ if (this->GetState()->UseWindowsVSIDE()) {
+ flags |= Shell_Flag_VSIDE;
+ } else if (!this->LinkScriptShell) {
+ flags |= Shell_Flag_Make;
+ }
+ if (unescapeNinjaConfiguration) {
+ flags |= Shell_Flag_UnescapeNinjaConfiguration;
+ }
+ if (makeVars) {
+ flags |= Shell_Flag_AllowMakeVariables;
+ }
+ if (forEcho) {
+ flags |= Shell_Flag_EchoWindows;
+ }
+ if (useWatcomQuote) {
+ flags |= Shell_Flag_WatcomQuote;
+ }
+ if (this->GetState()->UseWatcomWMake()) {
+ flags |= Shell_Flag_WatcomWMake;
+ }
+ if (this->GetState()->UseMinGWMake()) {
+ flags |= Shell_Flag_MinGWMake;
+ }
+ if (this->GetState()->UseNMake()) {
+ flags |= Shell_Flag_NMake;
+ }
+ if (!this->GetState()->UseWindowsShell()) {
+ flags |= Shell_Flag_IsUnix;
+ }
+
+ return Shell_GetArgument(str, flags);
+}
+
+std::string cmOutputConverter::EscapeForCMake(cm::string_view str)
+{
+ // Always double-quote the argument to take care of most escapes.
+ std::string result = "\"";
+ for (const char c : str) {
+ if (c == '"') {
+ // Escape the double quote to avoid ending the argument.
+ result += "\\\"";
+ } else if (c == '$') {
+ // Escape the dollar to avoid expanding variables.
+ result += "\\$";
+ } else if (c == '\\') {
+ // Escape the backslash to avoid other escapes.
+ result += "\\\\";
+ } else {
+ // Other characters will be parsed correctly.
+ result += c;
+ }
+ }
+ result += "\"";
+ return result;
+}
+
+std::string cmOutputConverter::EscapeWindowsShellArgument(cm::string_view arg,
+ int shell_flags)
+{
+ return Shell_GetArgument(arg, shell_flags);
+}
+
+cmOutputConverter::FortranFormat cmOutputConverter::GetFortranFormat(
+ cm::string_view value)
+{
+ FortranFormat format = FortranFormatNone;
+ if (!value.empty()) {
+ for (std::string const& fi : cmExpandedList(value)) {
+ if (fi == "FIXED") {
+ format = FortranFormatFixed;
+ }
+ if (fi == "FREE") {
+ format = FortranFormatFree;
+ }
+ }
+ }
+ return format;
+}
+
+cmOutputConverter::FortranPreprocess cmOutputConverter::GetFortranPreprocess(
+ cm::string_view value)
+{
+ if (value.empty()) {
+ return FortranPreprocess::Unset;
+ }
+
+ return cmIsOn(value) ? FortranPreprocess::Needed
+ : FortranPreprocess::NotNeeded;
+}
+
+void cmOutputConverter::SetLinkScriptShell(bool linkScriptShell)
+{
+ this->LinkScriptShell = linkScriptShell;
+}
+
+cmState* cmOutputConverter::GetState() const
+{
+ return this->StateSnapshot.GetState();
+}
+
+/*
+
+Notes:
+
+Make variable replacements open a can of worms. Sometimes they should
+be quoted and sometimes not. Sometimes their replacement values are
+already quoted.
+
+VS variables cause problems. In order to pass the referenced value
+with spaces the reference must be quoted. If the variable value ends
+in a backslash then it will escape the ending quote! In order to make
+the ending backslash appear we need this:
+
+ "$(InputDir)\"
+
+However if there is not a trailing backslash then this will put a
+quote in the value so we need:
+
+ "$(InputDir)"
+
+Make variable references are platform specific so we should probably
+just NOT quote them and let the listfile author deal with it.
+
+*/
+
+/*
+TODO: For windows echo:
+
+To display a pipe (|) or redirection character (< or >) when using the
+echo command, use a caret character immediately before the pipe or
+redirection character (for example, ^>, ^<, or ^| ). If you need to
+use the caret character itself (^), use two in a row (^^).
+*/
+
+/* Some helpers to identify character classes */
+static bool Shell_CharIsWhitespace(char c)
+{
+ return ((c == ' ') || (c == '\t'));
+}
+
+static bool Shell_CharNeedsQuotesOnUnix(char c)
+{
+ return ((c == '\'') || (c == '`') || (c == ';') || (c == '#') ||
+ (c == '&') || (c == '$') || (c == '(') || (c == ')') || (c == '~') ||
+ (c == '<') || (c == '>') || (c == '|') || (c == '*') || (c == '^') ||
+ (c == '\\'));
+}
+
+static bool Shell_CharNeedsQuotesOnWindows(char c)
+{
+ return ((c == '\'') || (c == '#') || (c == '&') || (c == '<') ||
+ (c == '>') || (c == '|') || (c == '^'));
+}
+
+static bool Shell_CharIsMakeVariableName(char c)
+{
+ return c && (c == '_' || isalpha((static_cast<int>(c))));
+}
+
+bool cmOutputConverter::Shell_CharNeedsQuotes(char c, int flags)
+{
+ /* On Windows the built-in command shell echo never needs quotes. */
+ if (!(flags & Shell_Flag_IsUnix) && (flags & Shell_Flag_EchoWindows)) {
+ return false;
+ }
+
+ /* On all platforms quotes are needed to preserve whitespace. */
+ if (Shell_CharIsWhitespace(c)) {
+ return true;
+ }
+
+ if (flags & Shell_Flag_IsUnix) {
+ /* On UNIX several special characters need quotes to preserve them. */
+ if (Shell_CharNeedsQuotesOnUnix(c)) {
+ return true;
+ }
+ } else {
+ /* On Windows several special characters need quotes to preserve them. */
+ if (Shell_CharNeedsQuotesOnWindows(c)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+cm::string_view::iterator cmOutputConverter::Shell_SkipMakeVariables(
+ cm::string_view::iterator c, cm::string_view::iterator end)
+{
+ while ((c != end && (c + 1) != end) && (*c == '$' && *(c + 1) == '(')) {
+ cm::string_view::iterator skip = c + 2;
+ while ((skip != end) && Shell_CharIsMakeVariableName(*skip)) {
+ ++skip;
+ }
+ if ((skip != end) && *skip == ')') {
+ c = skip + 1;
+ } else {
+ break;
+ }
+ }
+ return c;
+}
+
+/*
+Allowing make variable replacements opens a can of worms. Sometimes
+they should be quoted and sometimes not. Sometimes their replacement
+values are already quoted or contain escapes.
+
+Some Visual Studio variables cause problems. In order to pass the
+referenced value with spaces the reference must be quoted. If the
+variable value ends in a backslash then it will escape the ending
+quote! In order to make the ending backslash appear we need this:
+
+ "$(InputDir)\"
+
+However if there is not a trailing backslash then this will put a
+quote in the value so we need:
+
+ "$(InputDir)"
+
+This macro decides whether we quote an argument just because it
+contains a make variable reference. This should be replaced with a
+flag later when we understand applications of this better.
+*/
+#define KWSYS_SYSTEM_SHELL_QUOTE_MAKE_VARIABLES 0
+
+bool cmOutputConverter::Shell_ArgumentNeedsQuotes(cm::string_view in,
+ int flags)
+{
+ /* The empty string needs quotes. */
+ if (in.empty()) {
+ return true;
+ }
+
+ /* Scan the string for characters that require quoting. */
+ for (cm::string_view::iterator cit = in.begin(), cend = in.end();
+ cit != cend; ++cit) {
+ /* Look for $(MAKEVAR) syntax if requested. */
+ if (flags & Shell_Flag_AllowMakeVariables) {
+#if KWSYS_SYSTEM_SHELL_QUOTE_MAKE_VARIABLES
+ cm::string_view::iterator skip = Shell_SkipMakeVariables(cit, cend);
+ if (skip != cit) {
+ /* We need to quote make variable references to preserve the
+ string with contents substituted in its place. */
+ return true;
+ }
+#else
+ /* Skip over the make variable references if any are present. */
+ cit = Shell_SkipMakeVariables(cit, cend);
+
+ /* Stop if we have reached the end of the string. */
+ if (cit == cend) {
+ break;
+ }
+#endif
+ }
+
+ /* Check whether this character needs quotes. */
+ if (Shell_CharNeedsQuotes(*cit, flags)) {
+ return true;
+ }
+ }
+
+ /* On Windows some single character arguments need quotes. */
+ if (flags & Shell_Flag_IsUnix && in.size() == 1) {
+ char c = in[0];
+ if ((c == '?') || (c == '&') || (c == '^') || (c == '|') || (c == '#')) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+std::string cmOutputConverter::Shell_GetArgument(cm::string_view in, int flags)
+{
+ /* Output will be at least as long as input string. */
+ std::string out;
+ out.reserve(in.size());
+
+ /* Keep track of how many backslashes have been encountered in a row. */
+ int windows_backslashes = 0;
+
+ /* Whether the argument must be quoted. */
+ int needQuotes = Shell_ArgumentNeedsQuotes(in, flags);
+ if (needQuotes) {
+ /* Add the opening quote for this argument. */
+ if (flags & Shell_Flag_WatcomQuote) {
+ if (flags & Shell_Flag_IsUnix) {
+ out += '"';
+ }
+ out += '\'';
+ } else {
+ out += '"';
+ }
+ }
+
+ /* Scan the string for characters that require escaping or quoting. */
+ for (cm::string_view::iterator cit = in.begin(), cend = in.end();
+ cit != cend; ++cit) {
+ /* Look for $(MAKEVAR) syntax if requested. */
+ if (flags & Shell_Flag_AllowMakeVariables) {
+ cm::string_view::iterator skip = Shell_SkipMakeVariables(cit, cend);
+ if (skip != cit) {
+ /* Copy to the end of the make variable references. */
+ while (cit != skip) {
+ out += *cit++;
+ }
+
+ /* The make variable reference eliminates any escaping needed
+ for preceding backslashes. */
+ windows_backslashes = 0;
+
+ /* Stop if we have reached the end of the string. */
+ if (cit == cend) {
+ break;
+ }
+ }
+ }
+
+ /* Check whether this character needs escaping for the shell. */
+ if (flags & Shell_Flag_IsUnix) {
+ /* On Unix a few special characters need escaping even inside a
+ quoted argument. */
+ if (*cit == '\\' || *cit == '"' || *cit == '`' || *cit == '$') {
+ /* This character needs a backslash to escape it. */
+ out += '\\';
+ }
+ } else if (flags & Shell_Flag_EchoWindows) {
+ /* On Windows the built-in command shell echo never needs escaping. */
+ } else {
+ /* On Windows only backslashes and double-quotes need escaping. */
+ if (*cit == '\\') {
+ /* Found a backslash. It may need to be escaped later. */
+ ++windows_backslashes;
+ } else if (*cit == '"') {
+ /* Found a double-quote. Escape all immediately preceding
+ backslashes. */
+ while (windows_backslashes > 0) {
+ --windows_backslashes;
+ out += '\\';
+ }
+
+ /* Add the backslash to escape the double-quote. */
+ out += '\\';
+ } else {
+ /* We encountered a normal character. This eliminates any
+ escaping needed for preceding backslashes. */
+ windows_backslashes = 0;
+ }
+ }
+
+ /* Check whether this character needs escaping for a make tool. */
+ if (*cit == '$') {
+ if (flags & Shell_Flag_Make) {
+ /* In Makefiles a dollar is written $$. The make tool will
+ replace it with just $ before passing it to the shell. */
+ out += "$$";
+ } else if (flags & Shell_Flag_VSIDE) {
+ /* In a VS IDE a dollar is written "$". If this is written in
+ an un-quoted argument it starts a quoted segment, inserts
+ the $ and ends the segment. If it is written in a quoted
+ argument it ends quoting, inserts the $ and restarts
+ quoting. Either way the $ is isolated from surrounding
+ text to avoid looking like a variable reference. */
+ out += "\"$\"";
+ } else {
+ /* Otherwise a dollar is written just $. */
+ out += '$';
+ }
+ } else if (*cit == '#') {
+ if ((flags & Shell_Flag_Make) && (flags & Shell_Flag_WatcomWMake)) {
+ /* In Watcom WMake makefiles a pound is written $#. The make
+ tool will replace it with just # before passing it to the
+ shell. */
+ out += "$#";
+ } else {
+ /* Otherwise a pound is written just #. */
+ out += '#';
+ }
+ } else if (*cit == '%') {
+ if ((flags & Shell_Flag_VSIDE) ||
+ ((flags & Shell_Flag_Make) &&
+ ((flags & Shell_Flag_MinGWMake) || (flags & Shell_Flag_NMake)))) {
+ /* In the VS IDE, NMake, or MinGW make a percent is written %%. */
+ out += "%%";
+ } else {
+ /* Otherwise a percent is written just %. */
+ out += '%';
+ }
+ } else if (*cit == ';') {
+ if (flags & Shell_Flag_VSIDE) {
+ /* In a VS IDE a semicolon is written ";". If this is written
+ in an un-quoted argument it starts a quoted segment,
+ inserts the ; and ends the segment. If it is written in a
+ quoted argument it ends quoting, inserts the ; and restarts
+ quoting. Either way the ; is isolated. */
+ out += "\";\"";
+ } else {
+ /* Otherwise a semicolon is written just ;. */
+ out += ';';
+ }
+ } else {
+ /* Store this character. */
+ out += *cit;
+ }
+ }
+
+ if (needQuotes) {
+ /* Add enough backslashes to escape any trailing ones. */
+ while (windows_backslashes > 0) {
+ --windows_backslashes;
+ out += '\\';
+ }
+
+ /* Add the closing quote for this argument. */
+ if (flags & Shell_Flag_WatcomQuote) {
+ out += '\'';
+ if (flags & Shell_Flag_IsUnix) {
+ out += '"';
+ }
+ } else {
+ out += '"';
+ }
+ }
+
+ if (flags & Shell_Flag_UnescapeNinjaConfiguration) {
+ std::string ninjaConfigReplace;
+ if (flags & Shell_Flag_IsUnix) {
+ ninjaConfigReplace += '\\';
+ }
+ ninjaConfigReplace += "$${CONFIGURATION}";
+ cmSystemTools::ReplaceString(out, ninjaConfigReplace, "${CONFIGURATION}");
+ }
+
+ return out;
+}
diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h
new file mode 100644
index 0000000..f1a8041
--- /dev/null
+++ b/Source/cmOutputConverter.h
@@ -0,0 +1,117 @@
+/* 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 <string>
+
+#include <cm/string_view>
+
+#include "cmStateSnapshot.h"
+
+class cmState;
+
+class cmOutputConverter
+{
+public:
+ cmOutputConverter(cmStateSnapshot const& snapshot);
+
+ enum OutputFormat
+ {
+ SHELL,
+ WATCOMQUOTE,
+ NINJAMULTI,
+ RESPONSE
+ };
+ std::string ConvertToOutputFormat(cm::string_view source,
+ OutputFormat output) const;
+ std::string ConvertDirectorySeparatorsForShell(cm::string_view source) const;
+
+ //! for existing files convert to output path and short path if spaces
+ std::string ConvertToOutputForExisting(const std::string& remote,
+ OutputFormat format = SHELL) const;
+
+ void SetLinkScriptShell(bool linkScriptShell);
+
+ /**
+ * Flags to pass to Shell_GetArgument. These modify the generated
+ * quoting and escape sequences to work under alternative
+ * environments.
+ */
+ enum Shell_Flag_e
+ {
+ /** The target shell is in a makefile. */
+ Shell_Flag_Make = (1 << 0),
+
+ /** The target shell is in a VS project file. Do not use with
+ Shell_Flag_Make. */
+ Shell_Flag_VSIDE = (1 << 1),
+
+ /** In a windows shell the argument is being passed to "echo". */
+ Shell_Flag_EchoWindows = (1 << 2),
+
+ /** The target shell is in a Watcom WMake makefile. */
+ Shell_Flag_WatcomWMake = (1 << 3),
+
+ /** The target shell is in a MinGW Make makefile. */
+ Shell_Flag_MinGWMake = (1 << 4),
+
+ /** The target shell is in a NMake makefile. */
+ Shell_Flag_NMake = (1 << 5),
+
+ /** Make variable reference syntax $(MAKEVAR) should not be escaped
+ to allow a build tool to replace it. Replacement values
+ containing spaces, quotes, backslashes, or other
+ non-alphanumeric characters that have significance to some makes
+ or shells produce undefined behavior. */
+ Shell_Flag_AllowMakeVariables = (1 << 6),
+
+ /** The target shell quoting uses extra single Quotes for Watcom tools. */
+ Shell_Flag_WatcomQuote = (1 << 7),
+
+ Shell_Flag_IsUnix = (1 << 8),
+
+ Shell_Flag_UnescapeNinjaConfiguration = (1 << 9),
+ };
+
+ std::string EscapeForShell(cm::string_view str, bool makeVars = false,
+ bool forEcho = false, bool useWatcomQuote = false,
+ bool unescapeNinjaConfiguration = false) const;
+
+ static std::string EscapeForCMake(cm::string_view str);
+
+ /** Compute an escaped version of the given argument for use in a
+ windows shell. */
+ static std::string EscapeWindowsShellArgument(cm::string_view arg,
+ int shell_flags);
+
+ enum FortranFormat
+ {
+ FortranFormatNone,
+ FortranFormatFixed,
+ FortranFormatFree
+ };
+ static FortranFormat GetFortranFormat(cm::string_view value);
+
+ enum class FortranPreprocess
+ {
+ Unset,
+ NotNeeded,
+ Needed
+ };
+ static FortranPreprocess GetFortranPreprocess(cm::string_view value);
+
+private:
+ cmState* GetState() const;
+
+ static bool Shell_CharNeedsQuotes(char c, int flags);
+ static cm::string_view::iterator Shell_SkipMakeVariables(
+ cm::string_view::iterator begin, cm::string_view::iterator end);
+ static bool Shell_ArgumentNeedsQuotes(cm::string_view in, int flags);
+ static std::string Shell_GetArgument(cm::string_view in, int flags);
+
+ cmStateSnapshot StateSnapshot;
+
+ bool LinkScriptShell;
+};
diff --git a/Source/cmOutputRequiredFilesCommand.cxx b/Source/cmOutputRequiredFilesCommand.cxx
new file mode 100644
index 0000000..d589614
--- /dev/null
+++ b/Source/cmOutputRequiredFilesCommand.cxx
@@ -0,0 +1,514 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmOutputRequiredFilesCommand.h"
+
+#include <cstdio>
+#include <map>
+#include <set>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+
+namespace {
+/** \class cmDependInformation
+ * \brief Store dependency information for a single source file.
+ *
+ * This structure stores the depend information for a single source file.
+ */
+class cmDependInformation
+{
+public:
+ /**
+ * Construct with dependency generation marked not done; instance
+ * not placed in cmMakefile's list.
+ */
+ cmDependInformation() = default;
+
+ /**
+ * The set of files on which this one depends.
+ */
+ using DependencySetType = std::set<cmDependInformation*>;
+ DependencySetType DependencySet;
+
+ /**
+ * This flag indicates whether dependency checking has been
+ * performed for this file.
+ */
+ bool DependDone = false;
+
+ /**
+ * If this object corresponds to a cmSourceFile instance, this points
+ * to it.
+ */
+ const cmSourceFile* SourceFile = nullptr;
+
+ /**
+ * Full path to this file.
+ */
+ std::string FullPath;
+
+ /**
+ * Full path not including file name.
+ */
+ std::string PathOnly;
+
+ /**
+ * Name used to #include this file.
+ */
+ std::string IncludeName;
+
+ /**
+ * This method adds the dependencies of another file to this one.
+ */
+ void AddDependencies(cmDependInformation* info)
+ {
+ if (this != info) {
+ this->DependencySet.insert(info);
+ }
+ }
+};
+
+class cmLBDepend
+{
+public:
+ /**
+ * Construct the object with verbose turned off.
+ */
+ cmLBDepend()
+ {
+ this->Verbose = false;
+ this->IncludeFileRegularExpression.compile("^.*$");
+ this->ComplainFileRegularExpression.compile("^$");
+ }
+
+ /**
+ * Destructor.
+ */
+ ~cmLBDepend() = default;
+
+ cmLBDepend(const cmLBDepend&) = delete;
+ cmLBDepend& operator=(const cmLBDepend&) = delete;
+
+ /**
+ * Set the makefile that is used as a source of classes.
+ */
+ void SetMakefile(cmMakefile* makefile)
+ {
+ this->Makefile = makefile;
+
+ // Now extract the include file regular expression from the makefile.
+ this->IncludeFileRegularExpression.compile(
+ this->Makefile->GetIncludeRegularExpression());
+ this->ComplainFileRegularExpression.compile(
+ this->Makefile->GetComplainRegularExpression());
+
+ // Now extract any include paths from the targets
+ std::set<std::string> uniqueIncludes;
+ std::vector<std::string> orderedAndUniqueIncludes;
+ for (auto const& target : this->Makefile->GetTargets()) {
+ cmProp incDirProp = target.second.GetProperty("INCLUDE_DIRECTORIES");
+ if (!incDirProp) {
+ continue;
+ }
+
+ std::string incDirs = cmGeneratorExpression::Preprocess(
+ *incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions);
+
+ std::vector<std::string> includes = cmExpandedList(incDirs);
+
+ for (std::string& path : includes) {
+ this->Makefile->ExpandVariablesInString(path);
+ if (uniqueIncludes.insert(path).second) {
+ orderedAndUniqueIncludes.push_back(path);
+ }
+ }
+ }
+
+ for (std::string const& inc : orderedAndUniqueIncludes) {
+ this->AddSearchPath(inc);
+ }
+ }
+
+ /**
+ * Add a directory to the search path for include files.
+ */
+ void AddSearchPath(const std::string& path)
+ {
+ this->IncludeDirectories.push_back(path);
+ }
+
+ /**
+ * Generate dependencies for the file given. Returns a pointer to
+ * the cmDependInformation object for the file.
+ */
+ const cmDependInformation* FindDependencies(const std::string& file)
+ {
+ cmDependInformation* info = this->GetDependInformation(file, "");
+ this->GenerateDependInformation(info);
+ return info;
+ }
+
+protected:
+ /**
+ * Compute the depend information for this class.
+ */
+
+ void DependWalk(cmDependInformation* info)
+ {
+ cmsys::ifstream fin(info->FullPath.c_str());
+ if (!fin) {
+ cmSystemTools::Error("error can not open " + info->FullPath);
+ return;
+ }
+
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (cmHasLiteralPrefix(line, "#include")) {
+ // if it is an include line then create a string class
+ size_t qstart = line.find('\"', 8);
+ size_t qend;
+ // if a quote is not found look for a <
+ if (qstart == std::string::npos) {
+ qstart = line.find('<', 8);
+ // if a < is not found then move on
+ if (qstart == std::string::npos) {
+ cmSystemTools::Error("unknown include directive " + line);
+ continue;
+ }
+ qend = line.find('>', qstart + 1);
+ } else {
+ qend = line.find('\"', qstart + 1);
+ }
+ // extract the file being included
+ std::string includeFile = line.substr(qstart + 1, qend - qstart - 1);
+ // see if the include matches the regular expression
+ if (!this->IncludeFileRegularExpression.find(includeFile)) {
+ if (this->Verbose) {
+ std::string message =
+ cmStrCat("Skipping ", includeFile, " for file ", info->FullPath);
+ cmSystemTools::Error(message);
+ }
+ continue;
+ }
+
+ // Add this file and all its dependencies.
+ this->AddDependency(info, includeFile);
+ /// add the cxx file if it exists
+ std::string cxxFile = includeFile;
+ std::string::size_type pos = cxxFile.rfind('.');
+ if (pos != std::string::npos) {
+ std::string root = cxxFile.substr(0, pos);
+ cxxFile = root + ".cxx";
+ bool found = false;
+ // try jumping to .cxx .cpp and .c in order
+ if (cmSystemTools::FileExists(cxxFile)) {
+ found = true;
+ }
+ for (std::string const& path : this->IncludeDirectories) {
+ if (cmSystemTools::FileExists(cmStrCat(path, "/", cxxFile))) {
+ found = true;
+ }
+ }
+ if (!found) {
+ cxxFile = root + ".cpp";
+ if (cmSystemTools::FileExists(cxxFile)) {
+ found = true;
+ }
+ for (std::string const& path : this->IncludeDirectories) {
+ if (cmSystemTools::FileExists(cmStrCat(path, "/", cxxFile))) {
+ found = true;
+ }
+ }
+ }
+ if (!found) {
+ cxxFile = root + ".c";
+ if (cmSystemTools::FileExists(cxxFile)) {
+ found = true;
+ }
+ for (std::string const& path : this->IncludeDirectories) {
+ if (cmSystemTools::FileExists(cmStrCat(path, "/", cxxFile))) {
+ found = true;
+ }
+ }
+ }
+ if (!found) {
+ cxxFile = root + ".txx";
+ if (cmSystemTools::FileExists(cxxFile)) {
+ found = true;
+ }
+ for (std::string const& path : this->IncludeDirectories) {
+ if (cmSystemTools::FileExists(cmStrCat(path, "/", cxxFile))) {
+ found = true;
+ }
+ }
+ }
+ if (found) {
+ this->AddDependency(info, cxxFile);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Add a dependency. Possibly walk it for more dependencies.
+ */
+ void AddDependency(cmDependInformation* info, const std::string& file)
+ {
+ cmDependInformation* dependInfo =
+ this->GetDependInformation(file, info->PathOnly);
+ this->GenerateDependInformation(dependInfo);
+ info->AddDependencies(dependInfo);
+ }
+
+ /**
+ * Fill in the given object with dependency information. If the
+ * information is already complete, nothing is done.
+ */
+ void GenerateDependInformation(cmDependInformation* info)
+ {
+ // If dependencies are already done, stop now.
+ if (info->DependDone) {
+ return;
+ }
+ // Make sure we don't visit the same file more than once.
+ info->DependDone = true;
+
+ const std::string& path = info->FullPath;
+ if (path.empty()) {
+ cmSystemTools::Error(
+ "Attempt to find dependencies for file without path!");
+ return;
+ }
+
+ bool found = false;
+
+ // If the file exists, use it to find dependency information.
+ if (cmSystemTools::FileExists(path, true)) {
+ // Use the real file to find its dependencies.
+ this->DependWalk(info);
+ found = true;
+ }
+
+ // See if the cmSourceFile for it has any files specified as
+ // dependency hints.
+ if (info->SourceFile != nullptr) {
+
+ // Get the cmSourceFile corresponding to this.
+ const cmSourceFile& cFile = *(info->SourceFile);
+ // See if there are any hints for finding dependencies for the missing
+ // file.
+ if (!cFile.GetDepends().empty()) {
+ // Dependency hints have been given. Use them to begin the
+ // recursion.
+ for (std::string const& file : cFile.GetDepends()) {
+ this->AddDependency(info, file);
+ }
+
+ // Found dependency information. We are done.
+ found = true;
+ }
+ }
+
+ if (!found) {
+ // Try to find the file amongst the sources
+ cmSourceFile* srcFile = this->Makefile->GetSource(
+ cmSystemTools::GetFilenameWithoutExtension(path));
+ if (srcFile) {
+ if (srcFile->ResolveFullPath() == path) {
+ found = true;
+ } else {
+ // try to guess which include path to use
+ for (std::string incpath : this->IncludeDirectories) {
+ if (!incpath.empty() && incpath.back() != '/') {
+ incpath += "/";
+ }
+ incpath += path;
+ if (srcFile->ResolveFullPath() == incpath) {
+ // set the path to the guessed path
+ info->FullPath = incpath;
+ found = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ // Couldn't find any dependency information.
+ if (this->ComplainFileRegularExpression.find(info->IncludeName)) {
+ cmSystemTools::Error("error cannot find dependencies for " + path);
+ } else {
+ // Destroy the name of the file so that it won't be output as a
+ // dependency.
+ info->FullPath.clear();
+ }
+ }
+ }
+
+ /**
+ * Get an instance of cmDependInformation corresponding to the given file
+ * name.
+ */
+ cmDependInformation* GetDependInformation(const std::string& file,
+ const std::string& extraPath)
+ {
+ // Get the full path for the file so that lookup is unambiguous.
+ std::string fullPath = this->FullPath(file, extraPath);
+
+ // Try to find the file's instance of cmDependInformation.
+ auto result = this->DependInformationMap.find(fullPath);
+ if (result != this->DependInformationMap.end()) {
+ // Found an instance, return it.
+ return result->second.get();
+ }
+ // Didn't find an instance. Create a new one and save it.
+ auto info = cm::make_unique<cmDependInformation>();
+ auto* ptr = info.get();
+ info->FullPath = fullPath;
+ info->PathOnly = cmSystemTools::GetFilenamePath(fullPath);
+ info->IncludeName = file;
+ this->DependInformationMap[fullPath] = std::move(info);
+ return ptr;
+ }
+
+ /**
+ * Find the full path name for the given file name.
+ * This uses the include directories.
+ * TODO: Cache path conversions to reduce FileExists calls.
+ */
+ std::string FullPath(const std::string& fname, const std::string& extraPath)
+ {
+ auto m = this->DirectoryToFileToPathMap.find(extraPath);
+
+ if (m != this->DirectoryToFileToPathMap.end()) {
+ FileToPathMapType& map = m->second;
+ auto p = map.find(fname);
+ if (p != map.end()) {
+ return p->second;
+ }
+ }
+
+ if (cmSystemTools::FileExists(fname, true)) {
+ std::string fp = cmSystemTools::CollapseFullPath(fname);
+ this->DirectoryToFileToPathMap[extraPath][fname] = fp;
+ return fp;
+ }
+
+ for (std::string path : this->IncludeDirectories) {
+ if (!path.empty() && path.back() != '/') {
+ path += "/";
+ }
+ path += fname;
+ if (cmSystemTools::FileExists(path, true) &&
+ !cmSystemTools::FileIsDirectory(path)) {
+ std::string fp = cmSystemTools::CollapseFullPath(path);
+ this->DirectoryToFileToPathMap[extraPath][fname] = fp;
+ return fp;
+ }
+ }
+
+ if (!extraPath.empty()) {
+ std::string path = extraPath;
+ if (!path.empty() && path.back() != '/') {
+ path = path + "/";
+ }
+ path = path + fname;
+ if (cmSystemTools::FileExists(path, true) &&
+ !cmSystemTools::FileIsDirectory(path)) {
+ std::string fp = cmSystemTools::CollapseFullPath(path);
+ this->DirectoryToFileToPathMap[extraPath][fname] = fp;
+ return fp;
+ }
+ }
+
+ // Couldn't find the file.
+ return fname;
+ }
+
+ cmMakefile* Makefile;
+ bool Verbose;
+ cmsys::RegularExpression IncludeFileRegularExpression;
+ cmsys::RegularExpression ComplainFileRegularExpression;
+ std::vector<std::string> IncludeDirectories;
+ using FileToPathMapType = std::map<std::string, std::string>;
+ using DirectoryToFileToPathMapType =
+ std::map<std::string, FileToPathMapType>;
+ using DependInformationMapType =
+ std::map<std::string, std::unique_ptr<cmDependInformation>>;
+ DependInformationMapType DependInformationMap;
+ DirectoryToFileToPathMapType DirectoryToFileToPathMap;
+};
+
+void ListDependencies(cmDependInformation const* info, FILE* fout,
+ std::set<cmDependInformation const*>* visited);
+}
+
+// cmOutputRequiredFilesCommand
+bool cmOutputRequiredFilesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // store the arg for final pass
+ const std::string& file = args[0];
+ const std::string& outputFile = args[1];
+
+ // compute the list of files
+ cmLBDepend md;
+ md.SetMakefile(&status.GetMakefile());
+ md.AddSearchPath(status.GetMakefile().GetCurrentSourceDirectory());
+ // find the depends for a file
+ const cmDependInformation* info = md.FindDependencies(file);
+ if (info) {
+ // write them out
+ FILE* fout = cmsys::SystemTools::Fopen(outputFile, "w");
+ if (!fout) {
+ status.SetError(cmStrCat("Can not open output file: ", outputFile));
+ return false;
+ }
+ std::set<cmDependInformation const*> visited;
+ ListDependencies(info, fout, &visited);
+ fclose(fout);
+ }
+
+ return true;
+}
+
+namespace {
+void ListDependencies(cmDependInformation const* info, FILE* fout,
+ std::set<cmDependInformation const*>* visited)
+{
+ // add info to the visited set
+ visited->insert(info);
+ // now recurse with info's dependencies
+ for (cmDependInformation* d : info->DependencySet) {
+ if (visited->find(d) == visited->end()) {
+ if (!info->FullPath.empty()) {
+ std::string tmp = d->FullPath;
+ std::string::size_type pos = tmp.rfind('.');
+ if (pos != std::string::npos && (tmp.substr(pos) != ".h")) {
+ tmp = tmp.substr(0, pos);
+ fprintf(fout, "%s\n", d->FullPath.c_str());
+ }
+ }
+ ListDependencies(d, fout, visited);
+ }
+ }
+}
+}
diff --git a/Source/cmOutputRequiredFilesCommand.h b/Source/cmOutputRequiredFilesCommand.h
new file mode 100644
index 0000000..9daba8f
--- /dev/null
+++ b/Source/cmOutputRequiredFilesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmOutputRequiredFilesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx
new file mode 100644
index 0000000..2465069
--- /dev/null
+++ b/Source/cmParseArgumentsCommand.cxx
@@ -0,0 +1,222 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmParseArgumentsCommand.h"
+
+#include <map>
+#include <set>
+#include <sstream>
+#include <utility>
+
+#include <cm/string_view>
+
+#include "cmArgumentParser.h"
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+static std::string EscapeArg(const std::string& arg)
+{
+ // replace ";" with "\;" so output argument lists will split correctly
+ std::string escapedArg;
+ for (char i : arg) {
+ if (i == ';') {
+ escapedArg += '\\';
+ }
+ escapedArg += i;
+ }
+ return escapedArg;
+}
+
+static std::string JoinList(std::vector<std::string> const& arg, bool escape)
+{
+ return escape ? cmJoin(cmMakeRange(arg).transform(EscapeArg), ";")
+ : cmJoin(cmMakeRange(arg), ";");
+}
+
+namespace {
+
+using options_map = std::map<std::string, bool>;
+using single_map = std::map<std::string, std::string>;
+using multi_map = std::map<std::string, std::vector<std::string>>;
+using options_set = std::set<std::string>;
+
+struct UserArgumentParser : public cmArgumentParser<void>
+{
+ template <typename T, typename H>
+ void Bind(std::vector<std::string> const& names,
+ std::map<std::string, T>& ref, H duplicateKey)
+ {
+ for (std::string const& key : names) {
+ auto const it = ref.emplace(key, T{}).first;
+ bool const inserted = this->cmArgumentParser<void>::Bind(
+ cm::string_view(it->first), it->second);
+ if (!inserted) {
+ duplicateKey(key);
+ }
+ }
+ }
+};
+
+} // namespace
+
+static void PassParsedArguments(
+ const std::string& prefix, cmMakefile& makefile, const options_map& options,
+ const single_map& singleValArgs, const multi_map& multiValArgs,
+ const std::vector<std::string>& unparsed,
+ const options_set& keywordsMissingValues, bool parseFromArgV)
+{
+ for (auto const& iter : options) {
+ makefile.AddDefinition(prefix + iter.first,
+ iter.second ? "TRUE" : "FALSE");
+ }
+
+ for (auto const& iter : singleValArgs) {
+ if (!iter.second.empty()) {
+ makefile.AddDefinition(prefix + iter.first, iter.second);
+ } else {
+ makefile.RemoveDefinition(prefix + iter.first);
+ }
+ }
+
+ for (auto const& iter : multiValArgs) {
+ if (!iter.second.empty()) {
+ makefile.AddDefinition(prefix + iter.first,
+ JoinList(iter.second, parseFromArgV));
+ } else {
+ makefile.RemoveDefinition(prefix + iter.first);
+ }
+ }
+
+ if (!unparsed.empty()) {
+ makefile.AddDefinition(prefix + "UNPARSED_ARGUMENTS",
+ JoinList(unparsed, parseFromArgV));
+ } else {
+ makefile.RemoveDefinition(prefix + "UNPARSED_ARGUMENTS");
+ }
+
+ if (!keywordsMissingValues.empty()) {
+ makefile.AddDefinition(prefix + "KEYWORDS_MISSING_VALUES",
+ cmJoin(cmMakeRange(keywordsMissingValues), ";"));
+ } else {
+ makefile.RemoveDefinition(prefix + "KEYWORDS_MISSING_VALUES");
+ }
+}
+
+bool cmParseArgumentsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // cmake_parse_arguments(prefix options single multi <ARGN>)
+ // 1 2 3 4
+ // or
+ // cmake_parse_arguments(PARSE_ARGV N prefix options single multi)
+ if (args.size() < 4) {
+ status.SetError("must be called with at least 4 arguments.");
+ return false;
+ }
+
+ auto argIter = args.begin();
+ auto argEnd = args.end();
+ bool parseFromArgV = false;
+ unsigned long argvStart = 0;
+ if (*argIter == "PARSE_ARGV") {
+ if (args.size() != 6) {
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ "PARSE_ARGV must be called with exactly 6 arguments.");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ parseFromArgV = true;
+ argIter++; // move past PARSE_ARGV
+ if (!cmStrToULong(*argIter, &argvStart)) {
+ status.GetMakefile().IssueMessage(MessageType::FATAL_ERROR,
+ "PARSE_ARGV index '" + *argIter +
+ "' is not an unsigned integer");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ argIter++; // move past N
+ }
+ // the first argument is the prefix
+ const std::string prefix = (*argIter++) + "_";
+
+ UserArgumentParser parser;
+
+ // define the result maps holding key/value pairs for
+ // options, single values and multi values
+ options_map options;
+ single_map singleValArgs;
+ multi_map multiValArgs;
+
+ // anything else is put into a vector of unparsed strings
+ std::vector<std::string> unparsed;
+
+ auto const duplicateKey = [&status](std::string const& key) {
+ status.GetMakefile().IssueMessage(
+ MessageType::WARNING, "keyword defined more than once: " + key);
+ };
+
+ // the second argument is a (cmake) list of options without argument
+ std::vector<std::string> list = cmExpandedList(*argIter++);
+ parser.Bind(list, options, duplicateKey);
+
+ // the third argument is a (cmake) list of single argument options
+ list.clear();
+ cmExpandList(*argIter++, list);
+ parser.Bind(list, singleValArgs, duplicateKey);
+
+ // the fourth argument is a (cmake) list of multi argument options
+ list.clear();
+ cmExpandList(*argIter++, list);
+ parser.Bind(list, multiValArgs, duplicateKey);
+
+ list.clear();
+ if (!parseFromArgV) {
+ // Flatten ;-lists in the arguments into a single list as was done
+ // by the original function(CMAKE_PARSE_ARGUMENTS).
+ for (; argIter != argEnd; ++argIter) {
+ cmExpandList(*argIter, list);
+ }
+ } else {
+ // in the PARSE_ARGV move read the arguments from ARGC and ARGV#
+ std::string argc = status.GetMakefile().GetSafeDefinition("ARGC");
+ unsigned long count;
+ if (!cmStrToULong(argc, &count)) {
+ status.GetMakefile().IssueMessage(MessageType::FATAL_ERROR,
+ "PARSE_ARGV called with ARGC='" +
+ argc +
+ "' that is not an unsigned integer");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ for (unsigned long i = argvStart; i < count; ++i) {
+ std::ostringstream argName;
+ argName << "ARGV" << i;
+ cmProp arg = status.GetMakefile().GetDefinition(argName.str());
+ if (!arg) {
+ status.GetMakefile().IssueMessage(MessageType::FATAL_ERROR,
+ "PARSE_ARGV called with " +
+ argName.str() + " not set");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ list.emplace_back(*arg);
+ }
+ }
+
+ std::vector<std::string> keywordsMissingValues;
+
+ parser.Parse(list, &unparsed, &keywordsMissingValues);
+
+ PassParsedArguments(
+ prefix, status.GetMakefile(), options, singleValArgs, multiValArgs,
+ unparsed,
+ options_set(keywordsMissingValues.begin(), keywordsMissingValues.end()),
+ parseFromArgV);
+
+ return true;
+}
diff --git a/Source/cmParseArgumentsCommand.h b/Source/cmParseArgumentsCommand.h
new file mode 100644
index 0000000..008977b
--- /dev/null
+++ b/Source/cmParseArgumentsCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmParseArgumentsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmPathLabel.cxx b/Source/cmPathLabel.cxx
new file mode 100644
index 0000000..fb81351
--- /dev/null
+++ b/Source/cmPathLabel.cxx
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmPathLabel.h"
+
+#include <utility>
+
+cmPathLabel::cmPathLabel(std::string label)
+ : Label(std::move(label))
+ , Hash(0)
+{
+ // Use a Jenkins one-at-a-time hash with under/over-flow protection
+ for (char i : this->Label) {
+ this->Hash += i;
+ this->Hash += ((this->Hash & 0x003FFFFF) << 10);
+ this->Hash ^= ((this->Hash & 0xFFFFFFC0) >> 6);
+ }
+ this->Hash += ((this->Hash & 0x1FFFFFFF) << 3);
+ this->Hash ^= ((this->Hash & 0xFFFFF800) >> 11);
+ this->Hash += ((this->Hash & 0x0001FFFF) << 15);
+}
+
+bool cmPathLabel::operator<(const cmPathLabel& l) const
+{
+ return this->Hash < l.Hash;
+}
+
+bool cmPathLabel::operator==(const cmPathLabel& l) const
+{
+ return this->Hash == l.Hash;
+}
diff --git a/Source/cmPathLabel.h b/Source/cmPathLabel.h
new file mode 100644
index 0000000..d19d2be
--- /dev/null
+++ b/Source/cmPathLabel.h
@@ -0,0 +1,34 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+
+/** \class cmPathLabel
+ * \brief Helper class for text based labels
+ *
+ * cmPathLabel is extended in different classes to act as an inheritable
+ * enum. Comparisons are done on a precomputed Jenkins hash of the string
+ * label for indexing and searchig.
+ */
+class cmPathLabel
+{
+public:
+ cmPathLabel(std::string label);
+
+ // The comparison operators are only for quick sorting and searching and
+ // in no way imply any lexicographical order of the label
+ bool operator<(const cmPathLabel& l) const;
+ bool operator==(const cmPathLabel& l) const;
+
+ const std::string& GetLabel() const { return this->Label; }
+ const unsigned int& GetHash() const { return this->Hash; }
+
+protected:
+ cmPathLabel();
+
+ std::string Label;
+ unsigned int Hash;
+};
diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx
new file mode 100644
index 0000000..01e8c04
--- /dev/null
+++ b/Source/cmPolicies.cxx
@@ -0,0 +1,443 @@
+#include "cmPolicies.h"
+
+#include <cassert>
+#include <cctype>
+#include <cstdio>
+#include <cstring>
+#include <sstream>
+#include <vector>
+
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+
+static bool stringToId(const char* input, cmPolicies::PolicyID& pid)
+{
+ assert(input);
+ if (strlen(input) != 7) {
+ return false;
+ }
+ if (!cmHasLiteralPrefix(input, "CMP")) {
+ return false;
+ }
+ if (cmHasLiteralSuffix(input, "0000")) {
+ pid = cmPolicies::CMP0000;
+ return true;
+ }
+ for (int i = 3; i < 7; ++i) {
+ if (!isdigit(*(input + i))) {
+ return false;
+ }
+ }
+ long id;
+ if (!cmStrToLong(input + 3, &id)) {
+ return false;
+ }
+ if (id >= cmPolicies::CMPCOUNT) {
+ return false;
+ }
+ pid = cmPolicies::PolicyID(id);
+ return true;
+}
+
+#define CM_SELECT_ID_VERSION(F, A1, A2, A3, A4, A5, A6) F(A1, A3, A4, A5)
+#define CM_FOR_EACH_POLICY_ID_VERSION(POLICY) \
+ CM_FOR_EACH_POLICY_TABLE(POLICY, CM_SELECT_ID_VERSION)
+
+#define CM_SELECT_ID_DOC(F, A1, A2, A3, A4, A5, A6) F(A1, A2)
+#define CM_FOR_EACH_POLICY_ID_DOC(POLICY) \
+ CM_FOR_EACH_POLICY_TABLE(POLICY, CM_SELECT_ID_DOC)
+
+static const char* idToString(cmPolicies::PolicyID id)
+{
+ switch (id) {
+#define POLICY_CASE(ID) \
+ case cmPolicies::ID: \
+ return #ID;
+ CM_FOR_EACH_POLICY_ID(POLICY_CASE)
+#undef POLICY_CASE
+ case cmPolicies::CMPCOUNT:
+ return nullptr;
+ }
+ return nullptr;
+}
+
+static const char* idToVersion(cmPolicies::PolicyID id)
+{
+ switch (id) {
+#define POLICY_CASE(ID, V_MAJOR, V_MINOR, V_PATCH) \
+ case cmPolicies::ID: \
+ return #V_MAJOR "." #V_MINOR "." #V_PATCH;
+ // NOLINTNEXTLINE(bugprone-branch-clone)
+ CM_FOR_EACH_POLICY_ID_VERSION(POLICY_CASE)
+#undef POLICY_CASE
+ case cmPolicies::CMPCOUNT:
+ return nullptr;
+ }
+ return nullptr;
+}
+
+static bool isPolicyNewerThan(cmPolicies::PolicyID id, unsigned int majorV,
+ unsigned int minorV, unsigned int patchV)
+{
+ switch (id) {
+#define POLICY_CASE(ID, V_MAJOR, V_MINOR, V_PATCH) \
+ case cmPolicies::ID: \
+ return (majorV < (V_MAJOR) || \
+ (majorV == (V_MAJOR) && minorV + 1 < (V_MINOR) + 1) || \
+ (majorV == (V_MAJOR) && minorV == (V_MINOR) && \
+ patchV + 1 < (V_PATCH) + 1));
+ // NOLINTNEXTLINE(bugprone-branch-clone)
+ CM_FOR_EACH_POLICY_ID_VERSION(POLICY_CASE)
+#undef POLICY_CASE
+ case cmPolicies::CMPCOUNT:
+ return false;
+ }
+ return false;
+}
+
+const char* idToShortDescription(cmPolicies::PolicyID id)
+{
+ switch (id) {
+#define POLICY_CASE(ID, SHORT_DESCRIPTION) \
+ case cmPolicies::ID: \
+ return SHORT_DESCRIPTION;
+ CM_FOR_EACH_POLICY_ID_DOC(POLICY_CASE)
+#undef POLICY_CASE
+ case cmPolicies::CMPCOUNT:
+ return nullptr;
+ }
+ return nullptr;
+}
+
+static void DiagnoseAncientPolicies(
+ std::vector<cmPolicies::PolicyID> const& ancient, unsigned int majorVer,
+ unsigned int minorVer, unsigned int patchVer, cmMakefile* mf)
+{
+ std::ostringstream e;
+ e << "The project requests behavior compatible with CMake version \""
+ << majorVer << "." << minorVer << "." << patchVer
+ << "\", which requires the OLD behavior for some policies:\n";
+ for (cmPolicies::PolicyID i : ancient) {
+ e << " " << idToString(i) << ": " << idToShortDescription(i) << "\n";
+ }
+ e << "However, this version of CMake no longer supports the OLD "
+ << "behavior for these policies. "
+ << "Please either update your CMakeLists.txt files to conform to "
+ << "the new behavior or use an older version of CMake that still "
+ << "supports the old behavior.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+}
+
+static bool GetPolicyDefault(cmMakefile* mf, std::string const& policy,
+ cmPolicies::PolicyStatus* defaultSetting)
+{
+ std::string defaultVar = "CMAKE_POLICY_DEFAULT_" + policy;
+ std::string const& defaultValue = mf->GetSafeDefinition(defaultVar);
+ if (defaultValue == "NEW") {
+ *defaultSetting = cmPolicies::NEW;
+ } else if (defaultValue == "OLD") {
+ *defaultSetting = cmPolicies::OLD;
+ } else if (defaultValue.empty()) {
+ *defaultSetting = cmPolicies::WARN;
+ } else {
+ std::ostringstream e;
+ e << defaultVar << " has value \"" << defaultValue
+ << R"(" but must be "OLD", "NEW", or "" (empty).)";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ return true;
+}
+
+bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf,
+ std::string const& version_min,
+ std::string const& version_max,
+ WarnCompat warnCompat)
+{
+ // Parse components of the minimum version.
+ unsigned int minMajor = 2;
+ unsigned int minMinor = 0;
+ unsigned int minPatch = 0;
+ unsigned int minTweak = 0;
+ if (sscanf(version_min.c_str(), "%u.%u.%u.%u", &minMajor, &minMinor,
+ &minPatch, &minTweak) < 2) {
+ std::ostringstream e;
+ e << "Invalid policy version value \"" << version_min << "\". "
+ << "A numeric major.minor[.patch[.tweak]] must be given.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ // it is an error if the policy version is less than 2.4
+ if (minMajor < 2 || (minMajor == 2 && minMinor < 4)) {
+ mf->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Compatibility with CMake < 2.4 is not supported by CMake >= 3.0. "
+ "For compatibility with older versions please use any CMake 2.8.x "
+ "release or lower.");
+ return false;
+ }
+
+ // It is an error if the policy version is greater than the running
+ // CMake.
+ if (minMajor > cmVersion::GetMajorVersion() ||
+ (minMajor == cmVersion::GetMajorVersion() &&
+ minMinor > cmVersion::GetMinorVersion()) ||
+ (minMajor == cmVersion::GetMajorVersion() &&
+ minMinor == cmVersion::GetMinorVersion() &&
+ minPatch > cmVersion::GetPatchVersion()) ||
+ (minMajor == cmVersion::GetMajorVersion() &&
+ minMinor == cmVersion::GetMinorVersion() &&
+ minPatch == cmVersion::GetPatchVersion() &&
+ minTweak > cmVersion::GetTweakVersion())) {
+ std::ostringstream e;
+ e << "An attempt was made to set the policy version of CMake to \""
+ << version_min << "\" which is greater than this version of CMake. "
+ << "This is not allowed because the greater version may have new "
+ << "policies not known to this CMake. "
+ << "You may need a newer CMake version to build this project.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ unsigned int polMajor = minMajor;
+ unsigned int polMinor = minMinor;
+ unsigned int polPatch = minPatch;
+
+ if (!version_max.empty()) {
+ // Parse components of the maximum version.
+ unsigned int maxMajor = 0;
+ unsigned int maxMinor = 0;
+ unsigned int maxPatch = 0;
+ unsigned int maxTweak = 0;
+ if (sscanf(version_max.c_str(), "%u.%u.%u.%u", &maxMajor, &maxMinor,
+ &maxPatch, &maxTweak) < 2) {
+ std::ostringstream e;
+ e << "Invalid policy max version value \"" << version_max << "\". "
+ << "A numeric major.minor[.patch[.tweak]] must be given.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ // It is an error if the min version is greater than the max version.
+ if (minMajor > maxMajor || (minMajor == maxMajor && minMinor > maxMinor) ||
+ (minMajor == maxMajor && minMinor == maxMinor &&
+ minPatch > maxPatch) ||
+ (minMajor == maxMajor && minMinor == maxMinor &&
+ minPatch == maxPatch && minTweak > maxTweak)) {
+ std::ostringstream e;
+ e << "Policy VERSION range \"" << version_min << "..." << version_max
+ << "\""
+ << " specifies a larger minimum than maximum.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ // Use the max version as the policy version.
+ polMajor = maxMajor;
+ polMinor = maxMinor;
+ polPatch = maxPatch;
+ }
+
+ return cmPolicies::ApplyPolicyVersion(mf, polMajor, polMinor, polPatch,
+ warnCompat);
+}
+
+bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, unsigned int majorVer,
+ unsigned int minorVer,
+ unsigned int patchVer,
+ WarnCompat warnCompat)
+{
+ // Warn about policy versions for which support will be removed.
+ if (warnCompat == WarnCompat::On &&
+ (majorVer < 2 || (majorVer == 2 && minorVer < 8) ||
+ (majorVer == 2 && minorVer == 8 && patchVer < 12)) &&
+ // Avoid warning on calls generated by install(EXPORT)
+ // in CMake versions prior to 3.18.
+ !(majorVer == 2 && minorVer == 6 && patchVer == 0 &&
+ mf->GetStateSnapshot().CanPopPolicyScope() &&
+ cmSystemTools::Strucmp(mf->GetBacktrace().Top().Name.c_str(),
+ "cmake_policy") == 0)) {
+ mf->IssueMessage(
+ MessageType::DEPRECATION_WARNING,
+ "Compatibility with CMake < 2.8.12 will be removed from "
+ "a future version of CMake.\n"
+ "Update the VERSION argument <min> value or use a ...<max> suffix "
+ "to tell CMake that the project does not need compatibility with "
+ "older versions.");
+ }
+
+ // now loop over all the policies and set them as appropriate
+ std::vector<cmPolicies::PolicyID> ancientPolicies;
+ for (PolicyID pid = cmPolicies::CMP0000; pid != cmPolicies::CMPCOUNT;
+ pid = PolicyID(pid + 1)) {
+ if (isPolicyNewerThan(pid, majorVer, minorVer, patchVer)) {
+ if (cmPolicies::GetPolicyStatus(pid) == cmPolicies::REQUIRED_ALWAYS) {
+ ancientPolicies.push_back(pid);
+ } else {
+ cmPolicies::PolicyStatus status = cmPolicies::WARN;
+ if (!GetPolicyDefault(mf, idToString(pid), &status) ||
+ !mf->SetPolicy(pid, status)) {
+ return false;
+ }
+ if (pid == cmPolicies::CMP0001 &&
+ (status == cmPolicies::WARN || status == cmPolicies::OLD)) {
+ if (!(mf->GetState()->GetInitializedCacheValue(
+ "CMAKE_BACKWARDS_COMPATIBILITY"))) {
+ // Set it to 2.4 because that is the last version where the
+ // variable had meaning.
+ mf->AddCacheDefinition(
+ "CMAKE_BACKWARDS_COMPATIBILITY", "2.4",
+ "For backwards compatibility, what version of CMake "
+ "commands and "
+ "syntax should this version of CMake try to support.",
+ cmStateEnums::STRING);
+ }
+ }
+ }
+ } else {
+ if (!mf->SetPolicy(pid, cmPolicies::NEW)) {
+ return false;
+ }
+ }
+ }
+
+ // Make sure the project does not use any ancient policies.
+ if (!ancientPolicies.empty()) {
+ DiagnoseAncientPolicies(ancientPolicies, majorVer, minorVer, patchVer, mf);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ return true;
+}
+
+bool cmPolicies::GetPolicyID(const char* id, cmPolicies::PolicyID& pid)
+{
+ return stringToId(id, pid);
+}
+
+//! return a warning string for a given policy
+std::string cmPolicies::GetPolicyWarning(cmPolicies::PolicyID id)
+{
+ std::ostringstream msg;
+ msg << "Policy " << idToString(id)
+ << " is not set: "
+ ""
+ << idToShortDescription(id)
+ << " "
+ "Run \"cmake --help-policy "
+ << idToString(id)
+ << "\" for "
+ "policy details. "
+ "Use the cmake_policy command to set the policy "
+ "and suppress this warning.";
+ return msg.str();
+}
+
+std::string cmPolicies::GetPolicyDeprecatedWarning(cmPolicies::PolicyID id)
+{
+ std::ostringstream msg;
+ /* clang-format off */
+ msg <<
+ "The OLD behavior for policy " << idToString(id) << " "
+ "will be removed from a future version of CMake.\n"
+ "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."
+ ;
+ /* clang-format on */
+ return msg.str();
+}
+
+//! return an error string for when a required policy is unspecified
+std::string cmPolicies::GetRequiredPolicyError(cmPolicies::PolicyID id)
+{
+ std::ostringstream error;
+ error << "Policy " << idToString(id)
+ << " is not set to NEW: "
+ ""
+ << idToShortDescription(id)
+ << " "
+ "Run \"cmake --help-policy "
+ << idToString(id)
+ << "\" for "
+ "policy details. "
+ "CMake now requires this policy to be set to NEW by the project. "
+ "The policy may be set explicitly using the code\n"
+ " cmake_policy(SET "
+ << idToString(id)
+ << " NEW)\n"
+ "or by upgrading all policies with the code\n"
+ " cmake_policy(VERSION "
+ << idToVersion(id)
+ << ") # or later\n"
+ "Run \"cmake --help-command cmake_policy\" for more information.";
+ return error.str();
+}
+
+//! Get the default status for a policy
+cmPolicies::PolicyStatus cmPolicies::GetPolicyStatus(
+ cmPolicies::PolicyID /*unused*/)
+{
+ return cmPolicies::WARN;
+}
+
+std::string cmPolicies::GetRequiredAlwaysPolicyError(cmPolicies::PolicyID id)
+{
+ std::string pid = idToString(id);
+ std::ostringstream e;
+ e << "Policy " << pid << " may not be set to OLD behavior because this "
+ << "version of CMake no longer supports it. "
+ << "The policy was introduced in "
+ << "CMake version " << idToVersion(id)
+ << ", and use of NEW behavior is now required."
+ << "\n"
+ << "Please either update your CMakeLists.txt files to conform to "
+ << "the new behavior or use an older version of CMake that still "
+ << "supports the old behavior. "
+ << "Run cmake --help-policy " << pid << " for more information.";
+ return e.str();
+}
+
+cmPolicies::PolicyStatus cmPolicies::PolicyMap::Get(
+ cmPolicies::PolicyID id) const
+{
+ PolicyStatus status = cmPolicies::WARN;
+
+ if (this->Status[(POLICY_STATUS_COUNT * id) + OLD]) {
+ status = cmPolicies::OLD;
+ } else if (this->Status[(POLICY_STATUS_COUNT * id) + NEW]) {
+ status = cmPolicies::NEW;
+ }
+ return status;
+}
+
+void cmPolicies::PolicyMap::Set(cmPolicies::PolicyID id,
+ cmPolicies::PolicyStatus status)
+{
+ this->Status[(POLICY_STATUS_COUNT * id) + OLD] = (status == OLD);
+ this->Status[(POLICY_STATUS_COUNT * id) + WARN] = (status == WARN);
+ this->Status[(POLICY_STATUS_COUNT * id) + NEW] = (status == NEW);
+}
+
+bool cmPolicies::PolicyMap::IsDefined(cmPolicies::PolicyID id) const
+{
+ return this->Status[(POLICY_STATUS_COUNT * id) + OLD] ||
+ this->Status[(POLICY_STATUS_COUNT * id) + WARN] ||
+ this->Status[(POLICY_STATUS_COUNT * id) + NEW];
+}
+
+bool cmPolicies::PolicyMap::IsEmpty() const
+{
+ return this->Status.none();
+}
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
new file mode 100644
index 0000000..d546b6e
--- /dev/null
+++ b/Source/cmPolicies.h
@@ -0,0 +1,485 @@
+/* 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 <bitset>
+#include <string>
+
+class cmMakefile;
+
+#define CM_FOR_EACH_POLICY_TABLE(POLICY, SELECT) \
+ SELECT(POLICY, CMP0000, \
+ "A minimum required CMake version must be specified.", 2, 6, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0001, \
+ "CMAKE_BACKWARDS_COMPATIBILITY should no longer be used.", 2, 6, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0002, "Logical target names must be globally unique.", 2, \
+ 6, 0, cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0003, \
+ "Libraries linked via full path no longer produce linker search paths.", \
+ 2, 6, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0004, \
+ "Libraries linked may not have leading or trailing whitespace.", 2, \
+ 6, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0005, \
+ "Preprocessor definition values are now escaped automatically.", 2, \
+ 6, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0006, \
+ "Installing MACOSX_BUNDLE targets requires a BUNDLE DESTINATION.", \
+ 2, 6, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0007, "list command no longer ignores empty elements.", \
+ 2, 6, 0, cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0008, \
+ "Libraries linked by full-path must have a valid library file name.", 2, \
+ 6, 1, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0009, \
+ "FILE GLOB_RECURSE calls should not follow symlinks by default.", 2, \
+ 6, 2, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0010, "Bad variable reference syntax is an error.", 2, 6, \
+ 3, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0011, \
+ "Included scripts do automatic cmake_policy PUSH and POP.", 2, 6, 3, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0012, "if() recognizes numbers and boolean constants.", \
+ 2, 8, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0013, "Duplicate binary directories are not allowed.", 2, \
+ 8, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0014, "Input directories must have CMakeLists.txt.", 2, \
+ 8, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0015, \
+ "link_directories() treats paths relative to the source dir.", 2, 8, \
+ 1, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0016, \
+ "target_link_libraries() reports error if its only argument " \
+ "is not a target.", \
+ 2, 8, 3, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0017, \
+ "Prefer files from the CMake module directory when including from " \
+ "there.", \
+ 2, 8, 4, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0018, \
+ "Ignore CMAKE_SHARED_LIBRARY_<Lang>_FLAGS variable.", 2, 8, 9, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0019, \
+ "Do not re-expand variables in include and link information.", 2, 8, \
+ 11, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0020, \
+ "Automatically link Qt executables to qtmain target on Windows.", 2, \
+ 8, 11, cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0021, \
+ "Fatal error on relative paths in INCLUDE_DIRECTORIES target property.", \
+ 2, 8, 12, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0022, \
+ "INTERFACE_LINK_LIBRARIES defines the link interface.", 2, 8, 12, \
+ cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0023, \
+ "Plain and keyword target_link_libraries signatures cannot be mixed.", 2, \
+ 8, 12, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0024, "Disallow include export result.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0025, "Compiler id for Apple Clang is now AppleClang.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0026, "Disallow use of the LOCATION target property.", 3, \
+ 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0027, \
+ "Conditionally linked imported targets with missing include " \
+ "directories.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0028, \
+ "Double colon in target name means ALIAS or IMPORTED target.", 3, 0, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0029, "The subdir_depends command should not be called.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0030, \
+ "The use_mangled_mesa command should not be called.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0031, "The load_command command should not be called.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0032, \
+ "The output_required_files command should not be called.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0033, \
+ "The export_library_dependencies command should not be called.", 3, \
+ 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0034, "The utility_source command should not be called.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0035, \
+ "The variable_requires command should not be called.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0036, "The build_name command should not be called.", 3, \
+ 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0037, \
+ "Target names should not be reserved and should match a validity " \
+ "pattern.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0038, "Targets may not link directly to themselves.", 3, \
+ 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0039, "Utility targets may not have link dependencies.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0040, \
+ "The target in the TARGET signature of add_custom_command() must " \
+ "exist and must be defined in the current directory.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0041, \
+ "Error on relative include with generator expression.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0042, "MACOSX_RPATH is enabled by default.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0043, "Ignore COMPILE_DEFINITIONS_<Config> properties.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0044, \
+ "Case sensitive <LANG>_COMPILER_ID generator expressions.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0045, \
+ "Error on non-existent target in get_target_property.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0046, \
+ "Error on non-existent dependency in add_dependencies.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0047, "Use QCC compiler id for the qcc drivers on QNX.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0048, "project() command manages VERSION variables.", 3, \
+ 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0049, \
+ "Do not expand variables in target source entries.", 3, 0, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0050, "Disallow add_custom_command SOURCE signatures.", \
+ 3, 0, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0051, "List TARGET_OBJECTS in SOURCES target property.", \
+ 3, 1, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0052, \
+ "Reject source and build dirs in installed " \
+ "INTERFACE_INCLUDE_DIRECTORIES.", \
+ 3, 1, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0053, \
+ "Simplify variable reference and escape sequence evaluation.", 3, 1, \
+ 0, cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0054, \
+ "Only interpret if() arguments as variables or keywords when unquoted.", \
+ 3, 1, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0055, "Strict checking for break() command.", 3, 2, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0056, \
+ "Honor link flags in try_compile() source-file signature.", 3, 2, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0057, "Support new IN_LIST if() operator.", 3, 3, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0058, \
+ "Ninja requires custom command byproducts to be explicit.", 3, 3, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0059, \
+ "Do not treat DEFINITIONS as a built-in directory property.", 3, 3, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0060, \
+ "Link libraries by full path even in implicit directories.", 3, 3, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0061, \
+ "CTest does not by default tell make to ignore errors (-i).", 3, 3, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0062, "Disallow install() of export() result.", 3, 3, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0063, \
+ "Honor visibility properties for all target types.", 3, 3, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0064, "Support new TEST if() operator.", 3, 4, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0065, \
+ "Do not add flags to export symbols from executables without " \
+ "the ENABLE_EXPORTS target property.", \
+ 3, 4, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0066, \
+ "Honor per-config flags in try_compile() source-file signature.", 3, \
+ 7, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0067, \
+ "Honor language standard in try_compile() source-file signature.", \
+ 3, 8, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0068, \
+ "RPATH settings on macOS do not affect install_name.", 3, 9, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0069, \
+ "INTERPROCEDURAL_OPTIMIZATION is enforced when enabled.", 3, 9, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0070, \
+ "Define file(GENERATE) behavior for relative paths.", 3, 10, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0071, "Let AUTOMOC and AUTOUIC process GENERATED files.", \
+ 3, 10, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0072, \
+ "FindOpenGL prefers GLVND by default when available.", 3, 11, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0073, \
+ "Do not produce legacy _LIB_DEPENDS cache entries.", 3, 12, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0074, "find_package uses <PackageName>_ROOT variables.", \
+ 3, 12, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0075, \
+ "Include file check macros honor CMAKE_REQUIRED_LIBRARIES.", 3, 12, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0076, \
+ "target_sources() command converts relative paths to absolute.", 3, \
+ 13, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0077, "option() honors normal variables.", 3, 13, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0078, "UseSWIG generates standard target names.", 3, 13, \
+ 0, cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0079, \
+ "target_link_libraries allows use with targets in other directories.", 3, \
+ 13, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0080, \
+ "BundleUtilities cannot be included at configure time.", 3, 13, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0081, \
+ "Relative paths not allowed in LINK_DIRECTORIES target property.", \
+ 3, 13, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0082, \
+ "Install rules from add_subdirectory() are interleaved with those " \
+ "in caller.", \
+ 3, 14, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0083, "Add PIE options when linking executable.", 3, 14, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0084, \
+ "The FindQt module does not exist for find_package().", 3, 14, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0085, "$<IN_LIST:...> handles empty list items.", 3, 14, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0086, \
+ "UseSWIG honors SWIG_MODULE_NAME via -module flag.", 3, 14, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0087, \
+ "Install CODE|SCRIPT allow the use of generator " \
+ "expressions.", \
+ 3, 14, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0088, \
+ "FindBISON runs bison in CMAKE_CURRENT_BINARY_DIR when executing.", \
+ 3, 14, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0089, \
+ "Compiler id for IBM Clang-based XL compilers is now XLClang.", 3, \
+ 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0090, \
+ "export(PACKAGE) does not populate package registry by default.", 3, \
+ 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0091, \
+ "MSVC runtime library flags are selected by an abstraction.", 3, 15, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0092, \
+ "MSVC warning flags are not in CMAKE_<LANG>_FLAGS by default.", 3, \
+ 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0093, "FindBoost reports Boost_VERSION in x.y.z format.", \
+ 3, 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0094, \
+ "FindPython3, FindPython2 and FindPyton use " \
+ "LOCATION for lookup strategy.", \
+ 3, 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0095, \
+ "RPATH entries are properly escaped in the intermediary CMake " \
+ "install script.", \
+ 3, 16, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0096, \
+ "project() preserves leading zeros in version components.", 3, 16, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0097, \
+ "ExternalProject_Add with GIT_SUBMODULES \"\" initializes no " \
+ "submodules.", \
+ 3, 16, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0098, \
+ "FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing.", 3, \
+ 17, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0099, \
+ "Link properties are transitive over private dependency on static " \
+ "libraries.", \
+ 3, 17, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0100, "Let AUTOMOC and AUTOUIC process .hh files.", 3, \
+ 17, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0101, \
+ "target_compile_options honors BEFORE keyword in all scopes.", 3, \
+ 17, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0102, \
+ "mark_as_advanced() does nothing if a cache entry does not exist.", \
+ 3, 17, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0103, \
+ "Multiple export() with same FILE without APPEND is not allowed.", \
+ 3, 18, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0104, \
+ "CMAKE_CUDA_ARCHITECTURES now detected for NVCC, empty " \
+ "CUDA_ARCHITECTURES not allowed.", \
+ 3, 18, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0105, "Device link step uses the link options.", 3, 18, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0106, "The Documentation module is removed.", 3, 18, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0107, "An ALIAS target cannot overwrite another target.", \
+ 3, 18, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0108, "A target cannot link to itself through an alias.", \
+ 3, 18, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0109, \
+ "find_program() requires permission to execute but not to read.", 3, \
+ 19, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0110, \
+ "add_test() supports arbitrary characters in test names.", 3, 19, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0111, \
+ "An imported target missing its location property fails during " \
+ "generation.", \
+ 3, 19, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0112, \
+ "Target file component generator expressions do not add target " \
+ "dependencies.", \
+ 3, 19, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0113, \
+ "Makefile generators do not repeat custom commands from target " \
+ "dependencies.", \
+ 3, 19, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0114, \
+ "ExternalProject step targets fully adopt their steps.", 3, 19, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0115, "Source file extensions must be explicit.", 3, 20, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0116, \
+ "Ninja generators transform DEPFILEs from add_custom_command().", 3, \
+ 20, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0117, \
+ "MSVC RTTI flag /GR is not added to CMAKE_CXX_FLAGS by default.", 3, \
+ 20, 0, cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0118, \
+ "The GENERATED source file property is now visible in all directories.", \
+ 3, 20, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0119, \
+ "LANGUAGE source file property explicitly compiles as specified " \
+ "language.", \
+ 3, 20, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0120, \
+ "The WriteCompilerDetectionHeader module is removed.", 3, 20, 0, \
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0121, \
+ "The list() command now validates parsing of index arguments.", 3, \
+ 21, 0, cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0122, \
+ "UseSWIG use standard library name conventions for csharp language.", 3, \
+ 21, 0, cmPolicies::WARN)
+
+#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
+#define CM_FOR_EACH_POLICY_ID(POLICY) \
+ CM_FOR_EACH_POLICY_TABLE(POLICY, CM_SELECT_ID)
+
+#define CM_FOR_EACH_TARGET_POLICY(F) \
+ F(CMP0003) \
+ F(CMP0004) \
+ F(CMP0008) \
+ F(CMP0020) \
+ F(CMP0021) \
+ F(CMP0022) \
+ F(CMP0027) \
+ F(CMP0037) \
+ F(CMP0038) \
+ F(CMP0041) \
+ F(CMP0042) \
+ F(CMP0046) \
+ F(CMP0052) \
+ F(CMP0060) \
+ F(CMP0063) \
+ F(CMP0065) \
+ F(CMP0068) \
+ F(CMP0069) \
+ F(CMP0073) \
+ F(CMP0076) \
+ F(CMP0081) \
+ F(CMP0083) \
+ F(CMP0095) \
+ F(CMP0099) \
+ F(CMP0104) \
+ F(CMP0105) \
+ F(CMP0108) \
+ F(CMP0112) \
+ F(CMP0113) \
+ F(CMP0119)
+
+/** \class cmPolicies
+ * \brief Handles changes in CMake behavior and policies
+ *
+ * See the cmake-policies(7) manual for an overview of this class's purpose.
+ */
+class cmPolicies
+{
+public:
+ /// Status of a policy
+ enum PolicyStatus
+ {
+ OLD, ///< Use old behavior
+ WARN, ///< Use old behavior but issue a warning
+ NEW, ///< Use new behavior
+ /// Issue an error if user doesn't set policy status to NEW and hits the
+ /// check
+ REQUIRED_IF_USED,
+ REQUIRED_ALWAYS ///< Issue an error unless user sets policy status to NEW.
+ };
+
+ /// Policy identifiers
+ enum PolicyID
+ {
+#define POLICY_ENUM(POLICY_ID) POLICY_ID,
+ CM_FOR_EACH_POLICY_ID(POLICY_ENUM)
+#undef POLICY_ENUM
+
+ /** \brief Always the last entry.
+ *
+ * Useful mostly to avoid adding a comma the last policy when adding a new
+ * one.
+ */
+ CMPCOUNT
+ };
+
+ //! convert a string policy ID into a number
+ static bool GetPolicyID(const char* id, /* out */ cmPolicies::PolicyID& pid);
+
+ //! Get the default status for a policy
+ static cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id);
+
+ enum class WarnCompat
+ {
+ Off,
+ On
+ };
+
+ //! Set a policy level for this listfile
+ static bool ApplyPolicyVersion(cmMakefile* mf,
+ std::string const& version_min,
+ std::string const& version_max,
+ WarnCompat warnCompat);
+ static bool ApplyPolicyVersion(cmMakefile* mf, unsigned int majorVer,
+ unsigned int minorVer, unsigned int patchVer,
+ WarnCompat warnCompat);
+
+ //! return a warning string for a given policy
+ static std::string GetPolicyWarning(cmPolicies::PolicyID id);
+ static std::string GetPolicyDeprecatedWarning(cmPolicies::PolicyID id);
+
+ //! return an error string for when a required policy is unspecified
+ static std::string GetRequiredPolicyError(cmPolicies::PolicyID id);
+
+ //! return an error string for when a required policy is unspecified
+ static std::string GetRequiredAlwaysPolicyError(cmPolicies::PolicyID id);
+
+ /** Represent a set of policy values. */
+ struct PolicyMap
+ {
+ PolicyStatus Get(PolicyID id) const;
+ void Set(PolicyID id, PolicyStatus status);
+ bool IsDefined(PolicyID id) const;
+ bool IsEmpty() const;
+
+ private:
+#define POLICY_STATUS_COUNT 3
+ std::bitset<cmPolicies::CMPCOUNT * POLICY_STATUS_COUNT> Status;
+ };
+};
diff --git a/Source/cmProcessOutput.cxx b/Source/cmProcessOutput.cxx
new file mode 100644
index 0000000..10c4215
--- /dev/null
+++ b/Source/cmProcessOutput.cxx
@@ -0,0 +1,170 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmProcessOutput.h"
+
+#if defined(_WIN32)
+# include <cm/memory>
+
+# include <windows.h>
+
+unsigned int cmProcessOutput::defaultCodepage =
+ KWSYS_ENCODING_DEFAULT_CODEPAGE;
+#endif
+
+cmProcessOutput::Encoding cmProcessOutput::FindEncoding(
+ std::string const& name)
+{
+ Encoding encoding = Auto;
+ if ((name == "UTF8") || (name == "UTF-8")) {
+ encoding = UTF8;
+ } else if (name == "NONE") {
+ encoding = None;
+ } else if (name == "ANSI") {
+ encoding = ANSI;
+ } else if (name == "OEM") {
+ encoding = OEM;
+ }
+ return encoding;
+}
+
+cmProcessOutput::cmProcessOutput(Encoding encoding, unsigned int maxSize)
+{
+#if defined(_WIN32)
+ codepage = 0;
+ bufferSize = maxSize;
+ if (encoding == None) {
+ codepage = defaultCodepage;
+ } else if (encoding == Auto) {
+ codepage = GetConsoleCP();
+ } else if (encoding == UTF8) {
+ codepage = CP_UTF8;
+ } else if (encoding == OEM) {
+ codepage = GetOEMCP();
+ }
+ if (!codepage || encoding == ANSI) {
+ codepage = GetACP();
+ }
+#else
+ static_cast<void>(encoding);
+ static_cast<void>(maxSize);
+#endif
+}
+
+bool cmProcessOutput::DecodeText(std::string raw, std::string& decoded,
+ size_t id)
+{
+#if !defined(_WIN32)
+ static_cast<void>(id);
+ decoded.swap(raw);
+ return true;
+#else
+ bool success = true;
+ decoded = raw;
+ if (id > 0) {
+ if (rawparts.size() < id) {
+ rawparts.reserve(id);
+ while (rawparts.size() < id)
+ rawparts.push_back(std::string());
+ }
+ raw = rawparts[id - 1] + raw;
+ rawparts[id - 1].clear();
+ decoded = raw;
+ }
+ if (raw.size() > 0 && codepage != defaultCodepage) {
+ success = false;
+ CPINFOEXW cpinfo;
+ if (id > 0 && bufferSize > 0 && raw.size() == bufferSize &&
+ GetCPInfoExW(codepage, 0, &cpinfo) == 1 && cpinfo.MaxCharSize > 1) {
+ if (cpinfo.MaxCharSize == 2 && cpinfo.LeadByte[0] != 0) {
+ LPSTR prevChar =
+ CharPrevExA(codepage, raw.c_str(), raw.c_str() + raw.size(), 0);
+ bool isLeadByte =
+ (*(prevChar + 1) == 0) && IsDBCSLeadByteEx(codepage, *prevChar);
+ if (isLeadByte) {
+ rawparts[id - 1] += *(raw.end() - 1);
+ raw.resize(raw.size() - 1);
+ }
+ success = DoDecodeText(raw, decoded, NULL);
+ } else {
+ bool restoreDecoded = false;
+ std::string firstDecoded = decoded;
+ wchar_t lastChar = 0;
+ for (UINT i = 0; i < cpinfo.MaxCharSize; i++) {
+ success = DoDecodeText(raw, decoded, &lastChar);
+ if (success && lastChar != 0) {
+ if (i == 0) {
+ firstDecoded = decoded;
+ }
+ if (lastChar == cpinfo.UnicodeDefaultChar) {
+ restoreDecoded = true;
+ rawparts[id - 1] = *(raw.end() - 1) + rawparts[id - 1];
+ raw.resize(raw.size() - 1);
+ } else {
+ restoreDecoded = false;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ if (restoreDecoded) {
+ decoded = firstDecoded;
+ rawparts[id - 1].clear();
+ }
+ }
+ } else {
+ success = DoDecodeText(raw, decoded, NULL);
+ }
+ }
+ return success;
+#endif
+}
+
+bool cmProcessOutput::DecodeText(const char* data, size_t length,
+ std::string& decoded, size_t id)
+{
+ return this->DecodeText(std::string(data, length), decoded, id);
+}
+
+bool cmProcessOutput::DecodeText(std::vector<char> raw,
+ std::vector<char>& decoded, size_t id)
+{
+ std::string str;
+ const bool success =
+ this->DecodeText(std::string(raw.begin(), raw.end()), str, id);
+ decoded.assign(str.begin(), str.end());
+ return success;
+}
+
+#if defined(_WIN32)
+bool cmProcessOutput::DoDecodeText(std::string raw, std::string& decoded,
+ wchar_t* lastChar)
+{
+ bool success = false;
+ const int wlength =
+ MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), NULL, 0);
+ auto wdata = cm::make_unique<wchar_t[]>(wlength);
+ int r = MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()),
+ wdata.get(), wlength);
+ if (r > 0) {
+ if (lastChar) {
+ *lastChar = 0;
+ if ((wlength >= 2 && wdata[wlength - 2] != wdata[wlength - 1]) ||
+ wlength >= 1) {
+ *lastChar = wdata[wlength - 1];
+ }
+ }
+ int length = WideCharToMultiByte(defaultCodepage, 0, wdata.get(), wlength,
+ NULL, 0, NULL, NULL);
+ auto data = cm::make_unique<char[]>(length);
+ r = WideCharToMultiByte(defaultCodepage, 0, wdata.get(), wlength,
+ data.get(), length, NULL, NULL);
+ if (r > 0) {
+ decoded = std::string(data.get(), length);
+ success = true;
+ }
+ }
+ return success;
+}
+#endif
diff --git a/Source/cmProcessOutput.h b/Source/cmProcessOutput.h
new file mode 100644
index 0000000..8cee987
--- /dev/null
+++ b/Source/cmProcessOutput.h
@@ -0,0 +1,85 @@
+/* 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 <cstddef>
+#include <string>
+#include <vector>
+
+/** \class cmProcessOutput
+ * \brief Decode text data to internal encoding.
+ *
+ * cmProcessOutput is used to decode text output from external process
+ * using external encoding to our internal encoding.
+ */
+class cmProcessOutput
+{
+public:
+ enum Encoding
+ {
+ None,
+ Auto,
+ UTF8,
+ ANSI,
+ OEM
+ };
+
+ /**
+ * Find encoding enum value for given encoding \a name.
+ * \param name a encoding name.
+ * \return encoding enum value or Auto if \a name was not found.
+ */
+ static Encoding FindEncoding(std::string const& name);
+
+ /// The code page that is used as internal encoding to which we will encode.
+ static unsigned int defaultCodepage;
+
+ /**
+ * A class constructor.
+ * \param encoding external process encoding from which we will decode.
+ * \param maxSize a maximal size for process output buffer. It should match
+ * to KWSYSPE_PIPE_BUFFER_SIZE. If text we decode is same size as \a maxSize
+ * then we will check for incomplete character at end of buffer and
+ * we will not return last incomplete character. This character will be
+ * returned with next DecodeText() call. To disable this behavior specify
+ * 0 as \a maxSize.
+ */
+ cmProcessOutput(Encoding encoding = Auto, unsigned int maxSize = 1024);
+ ~cmProcessOutput() = default;
+ /**
+ * Decode \a raw string using external encoding to internal
+ * encoding in \a decoded.
+ * \a id specifies which internal buffer to use. This is important when we
+ * are decoding both stdout and stderr from process output and we need to
+ * keep incomplete characters in separate buffers for each stream.
+ * \return true if successfully decoded \a raw to \a decoded or false if not.
+ */
+ bool DecodeText(std::string raw, std::string& decoded, size_t id = 0);
+ /**
+ * Decode \a data with \a length from external encoding to internal
+ * encoding in \a decoded.
+ * \param data a pointer to process output text data.
+ * \param length a size of data buffer.
+ * \param decoded a string which will contain decoded text.
+ * \param id an internal buffer id to use.
+ * \return true if successfully decoded \a data to \a decoded or false if
+ * not.
+ */
+ bool DecodeText(const char* data, size_t length, std::string& decoded,
+ size_t id = 0);
+ /**
+ * \overload
+ */
+ bool DecodeText(std::vector<char> raw, std::vector<char>& decoded,
+ size_t id = 0);
+
+private:
+#if defined(_WIN32)
+ unsigned int codepage;
+ unsigned int bufferSize;
+ std::vector<std::string> rawparts;
+ bool DoDecodeText(std::string raw, std::string& decoded, wchar_t* lastChar);
+#endif
+};
diff --git a/Source/cmProcessTools.cxx b/Source/cmProcessTools.cxx
new file mode 100644
index 0000000..9ebf5b7
--- /dev/null
+++ b/Source/cmProcessTools.cxx
@@ -0,0 +1,86 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmProcessTools.h"
+
+#include <ostream>
+
+#include "cmsys/Process.h"
+
+#include "cmProcessOutput.h"
+
+void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
+ OutputParser* err, Encoding encoding)
+{
+ cmsysProcess_Execute(cp);
+ char* data = nullptr;
+ int length = 0;
+ int p;
+ cmProcessOutput processOutput(encoding);
+ std::string strdata;
+ while ((out || err) &&
+ (p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) {
+ if (out && p == cmsysProcess_Pipe_STDOUT) {
+ processOutput.DecodeText(data, length, strdata, 1);
+ if (!out->Process(strdata.c_str(), int(strdata.size()))) {
+ out = nullptr;
+ }
+ } else if (err && p == cmsysProcess_Pipe_STDERR) {
+ processOutput.DecodeText(data, length, strdata, 2);
+ if (!err->Process(strdata.c_str(), int(strdata.size()))) {
+ err = nullptr;
+ }
+ }
+ }
+ if (out) {
+ processOutput.DecodeText(std::string(), strdata, 1);
+ if (!strdata.empty()) {
+ out->Process(strdata.c_str(), int(strdata.size()));
+ }
+ }
+ if (err) {
+ processOutput.DecodeText(std::string(), strdata, 2);
+ if (!strdata.empty()) {
+ err->Process(strdata.c_str(), int(strdata.size()));
+ }
+ }
+ cmsysProcess_WaitForExit(cp, nullptr);
+}
+
+cmProcessTools::LineParser::LineParser(char sep, bool ignoreCR)
+ : Separator(sep)
+ , IgnoreCR(ignoreCR)
+{
+}
+
+void cmProcessTools::LineParser::SetLog(std::ostream* log, const char* prefix)
+{
+ this->Log = log;
+ this->Prefix = prefix ? prefix : "";
+}
+
+bool cmProcessTools::LineParser::ProcessChunk(const char* first, int length)
+{
+ const char* last = first + length;
+ for (const char* c = first; c != last; ++c) {
+ if (*c == this->Separator || *c == '\0') {
+ this->LineEnd = *c;
+
+ // Log this line.
+ if (this->Log && this->Prefix) {
+ *this->Log << this->Prefix << this->Line << "\n";
+ }
+
+ // Hand this line to the subclass implementation.
+ if (!this->ProcessLine()) {
+ this->Line.clear();
+ return false;
+ }
+
+ this->Line.clear();
+ } else if (*c != '\r' || !this->IgnoreCR) {
+ // Append this character to the line under construction.
+ this->Line.append(1, *c);
+ }
+ }
+ return true;
+}
diff --git a/Source/cmProcessTools.h b/Source/cmProcessTools.h
new file mode 100644
index 0000000..74ec5e0
--- /dev/null
+++ b/Source/cmProcessTools.h
@@ -0,0 +1,87 @@
+/* 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 <cstring>
+#include <iosfwd>
+#include <string>
+
+#include "cmProcessOutput.h"
+
+/** \class cmProcessTools
+ * \brief Helper classes for process output parsing
+ *
+ */
+class cmProcessTools
+{
+public:
+ using Encoding = cmProcessOutput::Encoding;
+ /** Abstract interface for process output parsers. */
+ class OutputParser
+ {
+ public:
+ /** Process the given output data from a tool. Processing may be
+ done incrementally. Returns true if the parser is interested
+ in any more data and false if it is done. */
+ bool Process(const char* data, int length)
+ {
+ return this->ProcessChunk(data, length);
+ }
+ bool Process(const char* data)
+ {
+ return this->Process(data, static_cast<int>(strlen(data)));
+ }
+
+ virtual ~OutputParser() = default;
+
+ protected:
+ /** Implement in a subclass to process a chunk of data. It should
+ return true only if it is interested in more data. */
+ virtual bool ProcessChunk(const char* data, int length) = 0;
+ };
+
+ /** Process output parser that extracts one line at a time. */
+ class LineParser : public OutputParser
+ {
+ public:
+ /** Construct with line separation character and choose whether to
+ ignore carriage returns. */
+ LineParser(char sep = '\n', bool ignoreCR = true);
+
+ /** Configure logging of lines as they are extracted. */
+ void SetLog(std::ostream* log, const char* prefix);
+
+ protected:
+ std::ostream* Log = nullptr;
+ const char* Prefix = nullptr;
+ std::string Line;
+ char Separator;
+ char LineEnd = '\0';
+ bool IgnoreCR;
+ bool ProcessChunk(const char* data, int length) override;
+
+ /** Implement in a subclass to process one line of input. It
+ should return true only if it is interested in more data. */
+ virtual bool ProcessLine() = 0;
+ };
+
+ /** Trivial line handler for simple logging. */
+ class OutputLogger : public LineParser
+ {
+ public:
+ OutputLogger(std::ostream& log, const char* prefix = nullptr)
+ {
+ this->SetLog(&log, prefix);
+ }
+
+ private:
+ bool ProcessLine() override { return true; }
+ };
+
+ /** Run a process and send output to given parsers. */
+ static void RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
+ OutputParser* err = nullptr,
+ Encoding encoding = cmProcessOutput::Auto);
+};
diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx
new file mode 100644
index 0000000..acdb09f
--- /dev/null
+++ b/Source/cmProjectCommand.cxx
@@ -0,0 +1,402 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmProjectCommand.h"
+
+#include <array>
+#include <cstddef>
+#include <cstdio>
+#include <functional>
+#include <limits>
+#include <utility>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+static bool IncludeByVariable(cmExecutionStatus& status,
+ const std::string& variable);
+static void TopLevelCMakeVarCondSet(cmMakefile& mf, std::string const& name,
+ std::string const& value);
+
+bool cmProjectCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("PROJECT called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ if (!IncludeByVariable(status, "CMAKE_PROJECT_INCLUDE_BEFORE")) {
+ return false;
+ }
+
+ std::string const& projectName = args[0];
+
+ if (!IncludeByVariable(status,
+ "CMAKE_PROJECT_" + projectName + "_INCLUDE_BEFORE")) {
+ return false;
+ }
+
+ mf.SetProjectName(projectName);
+
+ mf.AddCacheDefinition(projectName + "_BINARY_DIR",
+ mf.GetCurrentBinaryDirectory(),
+ "Value Computed by CMake", cmStateEnums::STATIC);
+ mf.AddCacheDefinition(projectName + "_SOURCE_DIR",
+ mf.GetCurrentSourceDirectory(),
+ "Value Computed by CMake", cmStateEnums::STATIC);
+
+ mf.AddDefinition("PROJECT_BINARY_DIR", mf.GetCurrentBinaryDirectory());
+ mf.AddDefinition("PROJECT_SOURCE_DIR", mf.GetCurrentSourceDirectory());
+
+ mf.AddDefinition("PROJECT_NAME", projectName);
+
+ mf.AddDefinitionBool("PROJECT_IS_TOP_LEVEL", mf.IsRootMakefile());
+ mf.AddCacheDefinition(projectName + "_IS_TOP_LEVEL",
+ mf.IsRootMakefile() ? "ON" : "OFF",
+ "Value Computed by CMake", cmStateEnums::STATIC);
+
+ // Set the CMAKE_PROJECT_NAME variable to be the highest-level
+ // project name in the tree. If there are two project commands
+ // in the same CMakeLists.txt file, and it is the top level
+ // CMakeLists.txt file, then go with the last one, so that
+ // CMAKE_PROJECT_NAME will match PROJECT_NAME, and cmake --build
+ // will work.
+ if (!mf.GetDefinition("CMAKE_PROJECT_NAME") || mf.IsRootMakefile()) {
+ mf.AddDefinition("CMAKE_PROJECT_NAME", projectName);
+ mf.AddCacheDefinition("CMAKE_PROJECT_NAME", projectName,
+ "Value Computed by CMake", cmStateEnums::STATIC);
+ }
+
+ bool haveVersion = false;
+ bool haveLanguages = false;
+ bool haveDescription = false;
+ bool haveHomepage = false;
+ bool injectedProjectCommand = false;
+ std::string version;
+ std::string description;
+ std::string homepage;
+ std::vector<std::string> languages;
+ std::function<void()> missedValueReporter;
+ auto resetReporter = [&missedValueReporter]() {
+ missedValueReporter = std::function<void()>();
+ };
+ enum Doing
+ {
+ DoingDescription,
+ DoingHomepage,
+ DoingLanguages,
+ DoingVersion
+ };
+ Doing doing = DoingLanguages;
+ for (size_t i = 1; i < args.size(); ++i) {
+ if (args[i] == "LANGUAGES") {
+ if (haveLanguages) {
+ mf.IssueMessage(MessageType::FATAL_ERROR,
+ "LANGUAGES may be specified at most once.");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ haveLanguages = true;
+ if (missedValueReporter) {
+ missedValueReporter();
+ }
+ doing = DoingLanguages;
+ if (!languages.empty()) {
+ std::string msg = cmStrCat(
+ "the following parameters must be specified after LANGUAGES "
+ "keyword: ",
+ cmJoin(languages, ", "), '.');
+ mf.IssueMessage(MessageType::WARNING, msg);
+ }
+ } else if (args[i] == "VERSION") {
+ if (haveVersion) {
+ mf.IssueMessage(MessageType::FATAL_ERROR,
+ "VERSION may be specified at most once.");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ haveVersion = true;
+ if (missedValueReporter) {
+ missedValueReporter();
+ }
+ doing = DoingVersion;
+ missedValueReporter = [&mf, &resetReporter]() {
+ mf.IssueMessage(
+ MessageType::WARNING,
+ "VERSION keyword not followed by a value or was followed by a "
+ "value that expanded to nothing.");
+ resetReporter();
+ };
+ } else if (args[i] == "DESCRIPTION") {
+ if (haveDescription) {
+ mf.IssueMessage(MessageType::FATAL_ERROR,
+ "DESCRIPTION may be specified at most once.");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ haveDescription = true;
+ if (missedValueReporter) {
+ missedValueReporter();
+ }
+ doing = DoingDescription;
+ missedValueReporter = [&mf, &resetReporter]() {
+ mf.IssueMessage(
+ MessageType::WARNING,
+ "DESCRIPTION keyword not followed by a value or was followed "
+ "by a value that expanded to nothing.");
+ resetReporter();
+ };
+ } else if (args[i] == "HOMEPAGE_URL") {
+ if (haveHomepage) {
+ mf.IssueMessage(MessageType::FATAL_ERROR,
+ "HOMEPAGE_URL may be specified at most once.");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ haveHomepage = true;
+ doing = DoingHomepage;
+ missedValueReporter = [&mf, &resetReporter]() {
+ mf.IssueMessage(
+ MessageType::WARNING,
+ "HOMEPAGE_URL keyword not followed by a value or was followed "
+ "by a value that expanded to nothing.");
+ resetReporter();
+ };
+ } else if (i == 1 && args[i] == "__CMAKE_INJECTED_PROJECT_COMMAND__") {
+ injectedProjectCommand = true;
+ } else if (doing == DoingVersion) {
+ doing = DoingLanguages;
+ version = args[i];
+ resetReporter();
+ } else if (doing == DoingDescription) {
+ doing = DoingLanguages;
+ description = args[i];
+ resetReporter();
+ } else if (doing == DoingHomepage) {
+ doing = DoingLanguages;
+ homepage = args[i];
+ resetReporter();
+ } else // doing == DoingLanguages
+ {
+ languages.push_back(args[i]);
+ }
+ }
+
+ if (missedValueReporter) {
+ missedValueReporter();
+ }
+
+ if ((haveVersion || haveDescription || haveHomepage) && !haveLanguages &&
+ !languages.empty()) {
+ mf.IssueMessage(MessageType::FATAL_ERROR,
+ "project with VERSION, DESCRIPTION or HOMEPAGE_URL must "
+ "use LANGUAGES before language names.");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ if (haveLanguages && languages.empty()) {
+ languages.emplace_back("NONE");
+ }
+
+ cmPolicies::PolicyStatus const cmp0048 =
+ mf.GetPolicyStatus(cmPolicies::CMP0048);
+ if (haveVersion) {
+ // Set project VERSION variables to given values
+ if (cmp0048 == cmPolicies::OLD || cmp0048 == cmPolicies::WARN) {
+ mf.IssueMessage(MessageType::FATAL_ERROR,
+ "VERSION not allowed unless CMP0048 is set to NEW");
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+
+ cmsys::RegularExpression vx(
+ R"(^([0-9]+(\.[0-9]+(\.[0-9]+(\.[0-9]+)?)?)?)?$)");
+ if (!vx.find(version)) {
+ std::string e = R"(VERSION ")" + version + R"(" format invalid.)";
+ mf.IssueMessage(MessageType::FATAL_ERROR, e);
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+
+ cmPolicies::PolicyStatus const cmp0096 =
+ mf.GetPolicyStatus(cmPolicies::CMP0096);
+
+ constexpr std::size_t MAX_VERSION_COMPONENTS = 4u;
+ std::string version_string;
+ std::array<std::string, MAX_VERSION_COMPONENTS> version_components;
+
+ if (cmp0096 == cmPolicies::OLD || cmp0096 == cmPolicies::WARN) {
+ char vb[MAX_VERSION_COMPONENTS]
+ [std::numeric_limits<unsigned>::digits10 + 2];
+ unsigned v[MAX_VERSION_COMPONENTS] = { 0, 0, 0, 0 };
+ const int vc = std::sscanf(version.c_str(), "%u.%u.%u.%u", &v[0], &v[1],
+ &v[2], &v[3]);
+ for (auto i = 0u; i < MAX_VERSION_COMPONENTS; ++i) {
+ if (int(i) < vc) {
+ std::sprintf(vb[i], "%u", v[i]);
+ version_string += &"."[std::size_t(i == 0)];
+ version_string += vb[i];
+ version_components[i] = vb[i];
+ } else {
+ vb[i][0] = '\x00';
+ }
+ }
+ } else {
+ // The regex above verified that we have a .-separated string of
+ // non-negative integer components. Keep the original string.
+ version_string = std::move(version);
+ // Split the integer components.
+ auto components = cmSystemTools::SplitString(version_string, '.');
+ for (auto i = 0u; i < components.size(); ++i) {
+ version_components[i] = std::move(components[i]);
+ }
+ }
+
+ std::string vv;
+ vv = projectName + "_VERSION";
+ mf.AddDefinition("PROJECT_VERSION", version_string);
+ mf.AddDefinition(vv, version_string);
+ vv = projectName + "_VERSION_MAJOR";
+ mf.AddDefinition("PROJECT_VERSION_MAJOR", version_components[0]);
+ mf.AddDefinition(vv, version_components[0]);
+ vv = projectName + "_VERSION_MINOR";
+ mf.AddDefinition("PROJECT_VERSION_MINOR", version_components[1]);
+ mf.AddDefinition(vv, version_components[1]);
+ vv = projectName + "_VERSION_PATCH";
+ mf.AddDefinition("PROJECT_VERSION_PATCH", version_components[2]);
+ mf.AddDefinition(vv, version_components[2]);
+ vv = projectName + "_VERSION_TWEAK";
+ mf.AddDefinition("PROJECT_VERSION_TWEAK", version_components[3]);
+ mf.AddDefinition(vv, version_components[3]);
+ // Also, try set top level variables
+ TopLevelCMakeVarCondSet(mf, "CMAKE_PROJECT_VERSION", version_string);
+ TopLevelCMakeVarCondSet(mf, "CMAKE_PROJECT_VERSION_MAJOR",
+ version_components[0]);
+ TopLevelCMakeVarCondSet(mf, "CMAKE_PROJECT_VERSION_MINOR",
+ version_components[1]);
+ TopLevelCMakeVarCondSet(mf, "CMAKE_PROJECT_VERSION_PATCH",
+ version_components[2]);
+ TopLevelCMakeVarCondSet(mf, "CMAKE_PROJECT_VERSION_TWEAK",
+ version_components[3]);
+ } else if (cmp0048 != cmPolicies::OLD) {
+ // Set project VERSION variables to empty
+ std::vector<std::string> vv = { "PROJECT_VERSION",
+ "PROJECT_VERSION_MAJOR",
+ "PROJECT_VERSION_MINOR",
+ "PROJECT_VERSION_PATCH",
+ "PROJECT_VERSION_TWEAK",
+ projectName + "_VERSION",
+ projectName + "_VERSION_MAJOR",
+ projectName + "_VERSION_MINOR",
+ projectName + "_VERSION_PATCH",
+ projectName + "_VERSION_TWEAK" };
+ if (mf.IsRootMakefile()) {
+ vv.emplace_back("CMAKE_PROJECT_VERSION");
+ vv.emplace_back("CMAKE_PROJECT_VERSION_MAJOR");
+ vv.emplace_back("CMAKE_PROJECT_VERSION_MINOR");
+ vv.emplace_back("CMAKE_PROJECT_VERSION_PATCH");
+ vv.emplace_back("CMAKE_PROJECT_VERSION_TWEAK");
+ }
+ std::string vw;
+ for (std::string const& i : vv) {
+ cmProp v = mf.GetDefinition(i);
+ if (cmNonempty(v)) {
+ if (cmp0048 == cmPolicies::WARN) {
+ if (!injectedProjectCommand) {
+ vw += "\n ";
+ vw += i;
+ }
+ } else {
+ mf.AddDefinition(i, "");
+ }
+ }
+ }
+ if (!vw.empty()) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0048),
+ "\nThe following variable(s) would be set to empty:", vw));
+ }
+ }
+
+ mf.AddDefinition("PROJECT_DESCRIPTION", description);
+ mf.AddDefinition(projectName + "_DESCRIPTION", description);
+ TopLevelCMakeVarCondSet(mf, "CMAKE_PROJECT_DESCRIPTION", description);
+
+ mf.AddDefinition("PROJECT_HOMEPAGE_URL", homepage);
+ mf.AddDefinition(projectName + "_HOMEPAGE_URL", homepage);
+ TopLevelCMakeVarCondSet(mf, "CMAKE_PROJECT_HOMEPAGE_URL", homepage);
+
+ if (languages.empty()) {
+ // if no language is specified do c and c++
+ languages = { "C", "CXX" };
+ }
+ mf.EnableLanguage(languages, false);
+
+ if (!IncludeByVariable(status, "CMAKE_PROJECT_INCLUDE")) {
+ return false;
+ }
+
+ if (!IncludeByVariable(status,
+ "CMAKE_PROJECT_" + projectName + "_INCLUDE")) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool IncludeByVariable(cmExecutionStatus& status,
+ const std::string& variable)
+{
+ cmMakefile& mf = status.GetMakefile();
+ cmProp include = mf.GetDefinition(variable);
+ if (!include) {
+ return true;
+ }
+
+ std::string includeFile =
+ cmSystemTools::CollapseFullPath(*include, mf.GetCurrentSourceDirectory());
+ if (!cmSystemTools::FileExists(includeFile)) {
+ status.SetError(cmStrCat("could not find requested file:\n ", *include));
+ return false;
+ }
+ if (cmSystemTools::FileIsDirectory(includeFile)) {
+ status.SetError(cmStrCat("requested file is a directory:\n ", *include));
+ return false;
+ }
+
+ const bool readit = mf.ReadDependentFile(*include);
+ if (readit) {
+ return true;
+ }
+
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ return true;
+ }
+
+ status.SetError(cmStrCat("could not load requested file:\n ", *include));
+ return false;
+}
+
+static void TopLevelCMakeVarCondSet(cmMakefile& mf, std::string const& name,
+ std::string const& value)
+{
+ // Set the CMAKE_PROJECT_XXX variable to be the highest-level
+ // project name in the tree. If there are two project commands
+ // in the same CMakeLists.txt file, and it is the top level
+ // CMakeLists.txt file, then go with the last one.
+ if (!mf.GetDefinition(name) || mf.IsRootMakefile()) {
+ mf.AddDefinition(name, value);
+ mf.AddCacheDefinition(name, value, "Value Computed by CMake",
+ cmStateEnums::STATIC);
+ }
+}
diff --git a/Source/cmProjectCommand.h b/Source/cmProjectCommand.h
new file mode 100644
index 0000000..33f0955
--- /dev/null
+++ b/Source/cmProjectCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmProjectCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmProperty.h b/Source/cmProperty.h
new file mode 100644
index 0000000..1e03c3f
--- /dev/null
+++ b/Source/cmProperty.h
@@ -0,0 +1,36 @@
+/* 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 <string>
+
+class cmProperty
+{
+public:
+ enum ScopeType
+ {
+ TARGET,
+ SOURCE_FILE,
+ DIRECTORY,
+ GLOBAL,
+ CACHE,
+ TEST,
+ VARIABLE,
+ CACHED_VARIABLE,
+ INSTALL
+ };
+};
+
+using cmProp = const std::string*;
+
+inline const char* cmToCStr(cmProp p)
+{
+ return p ? p->c_str() : nullptr;
+}
+
+inline const char* cmToCStrSafe(cmProp p)
+{
+ return p ? p->c_str() : "";
+}
diff --git a/Source/cmPropertyDefinition.cxx b/Source/cmPropertyDefinition.cxx
new file mode 100644
index 0000000..1796bb8
--- /dev/null
+++ b/Source/cmPropertyDefinition.cxx
@@ -0,0 +1,39 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmPropertyDefinition.h"
+
+#include <tuple>
+
+cmPropertyDefinition::cmPropertyDefinition(std::string shortDescription,
+ std::string fullDescription,
+ bool chained)
+ : ShortDescription(std::move(shortDescription))
+ , FullDescription(std::move(fullDescription))
+ , Chained(chained)
+{
+}
+
+void cmPropertyDefinitionMap::DefineProperty(
+ const std::string& name, cmProperty::ScopeType scope,
+ const std::string& ShortDescription, const std::string& FullDescription,
+ bool chain)
+{
+ auto it = this->Map_.find(key_type(name, scope));
+ if (it == this->Map_.end()) {
+ // try_emplace() since C++17
+ this->Map_.emplace(
+ std::piecewise_construct, std::forward_as_tuple(name, scope),
+ std::forward_as_tuple(ShortDescription, FullDescription, chain));
+ }
+}
+
+cmPropertyDefinition const* cmPropertyDefinitionMap::GetPropertyDefinition(
+ const std::string& name, cmProperty::ScopeType scope) const
+{
+ auto it = this->Map_.find(key_type(name, scope));
+ if (it != this->Map_.end()) {
+ return &it->second;
+ }
+
+ return nullptr;
+}
diff --git a/Source/cmPropertyDefinition.h b/Source/cmPropertyDefinition.h
new file mode 100644
index 0000000..fca936e
--- /dev/null
+++ b/Source/cmPropertyDefinition.h
@@ -0,0 +1,66 @@
+/* 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 <map>
+#include <string>
+#include <utility>
+
+#include "cmProperty.h"
+
+/** \class cmPropertyDefinition
+ * \brief Property meta-information
+ *
+ * This class contains the following meta-information about property:
+ * - Various documentation strings;
+ * - If the property is chained.
+ */
+class cmPropertyDefinition
+{
+public:
+ /// Constructor
+ cmPropertyDefinition(std::string shortDescription,
+ std::string fullDescription, bool chained);
+
+ /// Is the property chained?
+ bool IsChained() const { return this->Chained; }
+
+ /// Get the documentation (short version)
+ const std::string& GetShortDescription() const
+ {
+ return this->ShortDescription;
+ }
+
+ /// Get the documentation (full version)
+ const std::string& GetFullDescription() const
+ {
+ return this->FullDescription;
+ }
+
+private:
+ std::string ShortDescription;
+ std::string FullDescription;
+ bool Chained;
+};
+
+/** \class cmPropertyDefinitionMap
+ * \brief Map property name and scope to their definition
+ */
+class cmPropertyDefinitionMap
+{
+public:
+ // define the property
+ void DefineProperty(const std::string& name, cmProperty::ScopeType scope,
+ const std::string& ShortDescription,
+ const std::string& FullDescription, bool chain);
+
+ // get the property definition if present, otherwise nullptr
+ cmPropertyDefinition const* GetPropertyDefinition(
+ const std::string& name, cmProperty::ScopeType scope) const;
+
+private:
+ using key_type = std::pair<std::string, cmProperty::ScopeType>;
+ std::map<key_type, cmPropertyDefinition> Map_;
+};
diff --git a/Source/cmPropertyMap.cxx b/Source/cmPropertyMap.cxx
new file mode 100644
index 0000000..06e151a
--- /dev/null
+++ b/Source/cmPropertyMap.cxx
@@ -0,0 +1,78 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmPropertyMap.h"
+
+#include <algorithm>
+#include <utility>
+
+void cmPropertyMap::Clear()
+{
+ this->Map_.clear();
+}
+
+void cmPropertyMap::SetProperty(const std::string& name, const char* value)
+{
+ if (!value) {
+ this->Map_.erase(name);
+ return;
+ }
+
+ this->Map_[name] = value;
+}
+
+void cmPropertyMap::AppendProperty(const std::string& name,
+ const std::string& value, bool asString)
+{
+ // Skip if nothing to append.
+ if (value.empty()) {
+ return;
+ }
+
+ {
+ std::string& pVal = this->Map_[name];
+ if (!pVal.empty() && !asString) {
+ pVal += ';';
+ }
+ pVal += value;
+ }
+}
+
+void cmPropertyMap::RemoveProperty(const std::string& name)
+{
+ this->Map_.erase(name);
+}
+
+cmProp cmPropertyMap::GetPropertyValue(const std::string& name) const
+{
+ auto it = this->Map_.find(name);
+ if (it != this->Map_.end()) {
+ return &it->second;
+ }
+ return nullptr;
+}
+
+std::vector<std::string> cmPropertyMap::GetKeys() const
+{
+ std::vector<std::string> keyList;
+ keyList.reserve(this->Map_.size());
+ for (auto const& item : this->Map_) {
+ keyList.push_back(item.first);
+ }
+ std::sort(keyList.begin(), keyList.end());
+ return keyList;
+}
+
+std::vector<std::pair<std::string, std::string>> cmPropertyMap::GetList() const
+{
+ using StringPair = std::pair<std::string, std::string>;
+ std::vector<StringPair> kvList;
+ kvList.reserve(this->Map_.size());
+ for (auto const& item : this->Map_) {
+ kvList.emplace_back(item.first, item.second);
+ }
+ std::sort(kvList.begin(), kvList.end(),
+ [](StringPair const& a, StringPair const& b) {
+ return a.first < b.first;
+ });
+ return kvList;
+}
diff --git a/Source/cmPropertyMap.h b/Source/cmPropertyMap.h
new file mode 100644
index 0000000..cda585a
--- /dev/null
+++ b/Source/cmPropertyMap.h
@@ -0,0 +1,50 @@
+/* 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 <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include "cmProperty.h"
+
+/** \class cmPropertyMap
+ * \brief String property map.
+ */
+class cmPropertyMap
+{
+public:
+ // -- General
+
+ //! Clear property list
+ void Clear();
+
+ // -- Properties
+
+ //! Set the property value
+ void SetProperty(const std::string& name, const char* value);
+
+ //! Append to the property value
+ void AppendProperty(const std::string& name, const std::string& value,
+ bool asString = false);
+
+ //! Get the property value
+ cmProp GetPropertyValue(const std::string& name) const;
+
+ //! Remove the property @a name from the map
+ void RemoveProperty(const std::string& name);
+
+ // -- Lists
+
+ //! Get a sorted list of property keys
+ std::vector<std::string> GetKeys() const;
+
+ //! Get a sorted by key list of property key,value pairs
+ std::vector<std::pair<std::string, std::string>> GetList() const;
+
+private:
+ std::unordered_map<std::string, std::string> Map_;
+};
diff --git a/Source/cmQTWrapCPPCommand.cxx b/Source/cmQTWrapCPPCommand.cxx
new file mode 100644
index 0000000..e9670f9
--- /dev/null
+++ b/Source/cmQTWrapCPPCommand.cxx
@@ -0,0 +1,86 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmQTWrapCPPCommand.h"
+
+#include "cmCustomCommandLines.h"
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+bool cmQTWrapCPPCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ // Get the moc executable to run in the custom command.
+ std::string const& moc_exe = mf.GetRequiredDefinition("QT_MOC_EXECUTABLE");
+
+ // Get the variable holding the list of sources.
+ std::string const& sourceList = args[1];
+ std::string sourceListValue = mf.GetSafeDefinition(sourceList);
+
+ // Create a rule for all sources listed.
+ for (std::string const& arg : cmMakeRange(args).advance(2)) {
+ cmSourceFile* curr = mf.GetSource(arg);
+ // if we should wrap the class
+ if (!(curr && curr->GetPropertyAsBool("WRAP_EXCLUDE"))) {
+ // Compute the name of the file to generate.
+ std::string srcName =
+ cmSystemTools::GetFilenameWithoutLastExtension(arg);
+ std::string newName =
+ cmStrCat(mf.GetCurrentBinaryDirectory(), "/moc_", srcName, ".cxx");
+ cmSourceFile* sf = mf.GetOrCreateSource(newName, true);
+ if (curr) {
+ sf->SetProperty("ABSTRACT", cmToCStr(curr->GetProperty("ABSTRACT")));
+ }
+
+ // Compute the name of the header from which to generate the file.
+ std::string hname;
+ if (cmSystemTools::FileIsFullPath(arg)) {
+ hname = arg;
+ } else {
+ if (curr && curr->GetIsGenerated()) {
+ hname = mf.GetCurrentBinaryDirectory();
+ } else {
+ hname = mf.GetCurrentSourceDirectory();
+ }
+ hname += "/";
+ hname += arg;
+ }
+
+ // Append the generated source file to the list.
+ if (!sourceListValue.empty()) {
+ sourceListValue += ";";
+ }
+ sourceListValue += newName;
+
+ // Create the custom command to generate the file.
+ cmCustomCommandLines commandLines =
+ cmMakeSingleCommandLine({ moc_exe, "-o", newName, hname });
+
+ std::vector<std::string> depends;
+ depends.push_back(moc_exe);
+ depends.push_back(hname);
+
+ std::string no_main_dependency;
+ const char* no_working_dir = nullptr;
+ mf.AddCustomCommandToOutput(
+ newName, depends, no_main_dependency, commandLines, "Qt Wrapped File",
+ no_working_dir, mf.GetPolicyStatus(cmPolicies::CMP0116));
+ }
+ }
+
+ // Store the final list of source files.
+ mf.AddDefinition(sourceList, sourceListValue);
+ return true;
+}
diff --git a/Source/cmQTWrapCPPCommand.h b/Source/cmQTWrapCPPCommand.h
new file mode 100644
index 0000000..28ceb3a
--- /dev/null
+++ b/Source/cmQTWrapCPPCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmQTWrapCPPCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmQTWrapUICommand.cxx b/Source/cmQTWrapUICommand.cxx
new file mode 100644
index 0000000..f98f0b3
--- /dev/null
+++ b/Source/cmQTWrapUICommand.cxx
@@ -0,0 +1,111 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmQTWrapUICommand.h"
+
+#include "cmCustomCommandLines.h"
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmPolicies.h"
+#include "cmRange.h"
+#include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+bool cmQTWrapUICommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 4) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ // Get the uic and moc executables to run in the custom commands.
+ std::string const& uic_exe = mf.GetRequiredDefinition("QT_UIC_EXECUTABLE");
+ std::string const& moc_exe = mf.GetRequiredDefinition("QT_MOC_EXECUTABLE");
+
+ // Get the variable holding the list of sources.
+ std::string const& headerList = args[1];
+ std::string const& sourceList = args[2];
+ std::string headerListValue = mf.GetSafeDefinition(headerList);
+ std::string sourceListValue = mf.GetSafeDefinition(sourceList);
+
+ // Create rules for all sources listed.
+ for (std::string const& arg : cmMakeRange(args).advance(3)) {
+ cmSourceFile* curr = mf.GetSource(arg);
+ // if we should wrap the class
+ if (!(curr && curr->GetPropertyAsBool("WRAP_EXCLUDE"))) {
+ // Compute the name of the files to generate.
+ std::string srcName =
+ cmSystemTools::GetFilenameWithoutLastExtension(arg);
+ std::string hName =
+ cmStrCat(mf.GetCurrentBinaryDirectory(), '/', srcName, ".h");
+ std::string cxxName =
+ cmStrCat(mf.GetCurrentBinaryDirectory(), '/', srcName, ".cxx");
+ std::string mocName =
+ cmStrCat(mf.GetCurrentBinaryDirectory(), "/moc_", srcName, ".cxx");
+
+ // Compute the name of the ui file from which to generate others.
+ std::string uiName;
+ if (cmSystemTools::FileIsFullPath(arg)) {
+ uiName = arg;
+ } else {
+ if (curr && curr->GetIsGenerated()) {
+ uiName = mf.GetCurrentBinaryDirectory();
+ } else {
+ uiName = mf.GetCurrentSourceDirectory();
+ }
+ uiName += "/";
+ uiName += arg;
+ }
+
+ // create the list of headers
+ if (!headerListValue.empty()) {
+ headerListValue += ";";
+ }
+ headerListValue += hName;
+
+ // create the list of sources
+ if (!sourceListValue.empty()) {
+ sourceListValue += ";";
+ }
+ sourceListValue += cxxName;
+ sourceListValue += ";";
+ sourceListValue += mocName;
+
+ // set up .ui to .h and .cxx command
+ cmCustomCommandLines hCommandLines =
+ cmMakeSingleCommandLine({ uic_exe, "-o", hName, uiName });
+ cmCustomCommandLines cxxCommandLines = cmMakeSingleCommandLine(
+ { uic_exe, "-impl", hName, "-o", cxxName, uiName });
+ cmCustomCommandLines mocCommandLines =
+ cmMakeSingleCommandLine({ moc_exe, "-o", mocName, hName });
+
+ std::vector<std::string> depends;
+ depends.push_back(uiName);
+ std::string no_main_dependency;
+ const char* no_comment = nullptr;
+ const char* no_working_dir = nullptr;
+ mf.AddCustomCommandToOutput(hName, depends, no_main_dependency,
+ hCommandLines, no_comment, no_working_dir,
+ mf.GetPolicyStatus(cmPolicies::CMP0116));
+
+ depends.push_back(hName);
+ mf.AddCustomCommandToOutput(cxxName, depends, no_main_dependency,
+ cxxCommandLines, no_comment, no_working_dir,
+ mf.GetPolicyStatus(cmPolicies::CMP0116));
+
+ depends.clear();
+ depends.push_back(hName);
+ mf.AddCustomCommandToOutput(mocName, depends, no_main_dependency,
+ mocCommandLines, no_comment, no_working_dir,
+ mf.GetPolicyStatus(cmPolicies::CMP0116));
+ }
+ }
+
+ // Store the final list of source files and headers.
+ mf.AddDefinition(sourceList, sourceListValue);
+ mf.AddDefinition(headerList, headerListValue);
+ return true;
+}
diff --git a/Source/cmQTWrapUICommand.h b/Source/cmQTWrapUICommand.h
new file mode 100644
index 0000000..3f92ea9
--- /dev/null
+++ b/Source/cmQTWrapUICommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmQTWrapUICommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx
new file mode 100644
index 0000000..57fcd2d
--- /dev/null
+++ b/Source/cmQtAutoGen.cxx
@@ -0,0 +1,386 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmQtAutoGen.h"
+
+#include <algorithm>
+#include <array>
+#include <initializer_list>
+#include <sstream>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmDuration.h"
+#include "cmProcessOutput.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+// - Static functions
+
+/// @brief Merges newOpts into baseOpts
+/// @arg valueOpts list of options that accept a value
+void MergeOptions(std::vector<std::string>& baseOpts,
+ std::vector<std::string> const& newOpts,
+ std::initializer_list<cm::string_view> valueOpts, bool isQt5)
+{
+ if (newOpts.empty()) {
+ return;
+ }
+ if (baseOpts.empty()) {
+ baseOpts = newOpts;
+ return;
+ }
+
+ std::vector<std::string> extraOpts;
+ for (auto fit = newOpts.begin(), fitEnd = newOpts.end(); fit != fitEnd;
+ ++fit) {
+ std::string const& newOpt = *fit;
+ auto existIt = std::find(baseOpts.begin(), baseOpts.end(), newOpt);
+ if (existIt != baseOpts.end()) {
+ if (newOpt.size() >= 2) {
+ // Acquire the option name
+ std::string optName;
+ {
+ auto oit = newOpt.begin();
+ if (*oit == '-') {
+ ++oit;
+ if (isQt5 && (*oit == '-')) {
+ ++oit;
+ }
+ optName.assign(oit, newOpt.end());
+ }
+ }
+ // Test if this is a value option and change the existing value
+ if (!optName.empty() && cm::contains(valueOpts, optName)) {
+ const auto existItNext(existIt + 1);
+ const auto fitNext(fit + 1);
+ if ((existItNext != baseOpts.end()) && (fitNext != fitEnd)) {
+ *existItNext = *fitNext;
+ ++fit;
+ }
+ }
+ }
+ } else {
+ extraOpts.push_back(newOpt);
+ }
+ }
+ // Append options
+ cm::append(baseOpts, extraOpts);
+}
+
+// - Class definitions
+
+unsigned int const cmQtAutoGen::ParallelMax = 64;
+
+cm::string_view cmQtAutoGen::GeneratorName(GenT genType)
+{
+ switch (genType) {
+ case GenT::GEN:
+ return "AutoGen";
+ case GenT::MOC:
+ return "AutoMoc";
+ case GenT::UIC:
+ return "AutoUic";
+ case GenT::RCC:
+ return "AutoRcc";
+ }
+ return "AutoGen";
+}
+
+cm::string_view cmQtAutoGen::GeneratorNameUpper(GenT genType)
+{
+ switch (genType) {
+ case GenT::GEN:
+ return "AUTOGEN";
+ case GenT::MOC:
+ return "AUTOMOC";
+ case GenT::UIC:
+ return "AUTOUIC";
+ case GenT::RCC:
+ return "AUTORCC";
+ }
+ return "AUTOGEN";
+}
+
+std::string cmQtAutoGen::Tools(bool moc, bool uic, bool rcc)
+{
+ std::array<cm::string_view, 3> lst;
+ decltype(lst)::size_type num = 0;
+ if (moc) {
+ lst.at(num++) = "AUTOMOC";
+ }
+ if (uic) {
+ lst.at(num++) = "AUTOUIC";
+ }
+ if (rcc) {
+ lst.at(num++) = "AUTORCC";
+ }
+ switch (num) {
+ case 1:
+ return std::string(lst[0]);
+ case 2:
+ return cmStrCat(lst[0], " and ", lst[1]);
+ case 3:
+ return cmStrCat(lst[0], ", ", lst[1], " and ", lst[2]);
+ default:
+ break;
+ }
+ return std::string();
+}
+
+std::string cmQtAutoGen::Quoted(cm::string_view text)
+{
+ static std::initializer_list<std::pair<const char*, const char*>> const
+ replacements = { { "\\", "\\\\" }, { "\"", "\\\"" }, { "\a", "\\a" },
+ { "\b", "\\b" }, { "\f", "\\f" }, { "\n", "\\n" },
+ { "\r", "\\r" }, { "\t", "\\t" }, { "\v", "\\v" } };
+
+ std::string res(text);
+ for (auto const& pair : replacements) {
+ cmSystemTools::ReplaceString(res, pair.first, pair.second);
+ }
+ return cmStrCat('"', res, '"');
+}
+
+std::string cmQtAutoGen::QuotedCommand(std::vector<std::string> const& command)
+{
+ std::string res;
+ for (std::string const& item : command) {
+ if (!res.empty()) {
+ res.push_back(' ');
+ }
+ std::string const cesc = cmQtAutoGen::Quoted(item);
+ if (item.empty() || (cesc.size() > (item.size() + 2)) ||
+ (cesc.find(' ') != std::string::npos)) {
+ res += cesc;
+ } else {
+ res += item;
+ }
+ }
+ return res;
+}
+
+std::string cmQtAutoGen::FileNameWithoutLastExtension(cm::string_view filename)
+{
+ auto slashPos = filename.rfind('/');
+ if (slashPos != cm::string_view::npos) {
+ filename.remove_prefix(slashPos + 1);
+ }
+ auto dotPos = filename.rfind('.');
+ return std::string(filename.substr(0, dotPos));
+}
+
+std::string cmQtAutoGen::ParentDir(cm::string_view filename)
+{
+ auto slashPos = filename.rfind('/');
+ if (slashPos == cm::string_view::npos) {
+ return std::string();
+ }
+ return std::string(filename.substr(0, slashPos));
+}
+
+std::string cmQtAutoGen::SubDirPrefix(cm::string_view filename)
+{
+ auto slashPos = filename.rfind('/');
+ if (slashPos == cm::string_view::npos) {
+ return std::string();
+ }
+ return std::string(filename.substr(0, slashPos + 1));
+}
+
+std::string cmQtAutoGen::AppendFilenameSuffix(cm::string_view filename,
+ cm::string_view suffix)
+{
+ auto dotPos = filename.rfind('.');
+ if (dotPos == cm::string_view::npos) {
+ return cmStrCat(filename, suffix);
+ }
+ return cmStrCat(filename.substr(0, dotPos), suffix,
+ filename.substr(dotPos, filename.size() - dotPos));
+}
+
+void cmQtAutoGen::UicMergeOptions(std::vector<std::string>& baseOpts,
+ std::vector<std::string> const& newOpts,
+ bool isQt5)
+{
+ static std::initializer_list<cm::string_view> const valueOpts = {
+ "tr", "translate", "postfix", "generator",
+ "include", // Since Qt 5.3
+ "g"
+ };
+ MergeOptions(baseOpts, newOpts, valueOpts, isQt5);
+}
+
+void cmQtAutoGen::RccMergeOptions(std::vector<std::string>& baseOpts,
+ std::vector<std::string> const& newOpts,
+ bool isQt5)
+{
+ static std::initializer_list<cm::string_view> const valueOpts = {
+ "name", "root", "compress", "threshold"
+ };
+ MergeOptions(baseOpts, newOpts, valueOpts, isQt5);
+}
+
+static void RccListParseContent(std::string const& content,
+ std::vector<std::string>& files)
+{
+ cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
+ cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)");
+
+ const char* contentChars = content.c_str();
+ while (fileMatchRegex.find(contentChars)) {
+ std::string const qrcEntry = fileMatchRegex.match(1);
+ contentChars += qrcEntry.size();
+ {
+ fileReplaceRegex.find(qrcEntry);
+ std::string const tag = fileReplaceRegex.match(1);
+ files.push_back(qrcEntry.substr(tag.size()));
+ }
+ }
+}
+
+static bool RccListParseOutput(std::string const& rccStdOut,
+ std::string const& rccStdErr,
+ std::vector<std::string>& files,
+ std::string& error)
+{
+ // Lambda to strip CR characters
+ auto StripCR = [](std::string& line) {
+ std::string::size_type cr = line.find('\r');
+ if (cr != std::string::npos) {
+ line = line.substr(0, cr);
+ }
+ };
+
+ // Parse rcc std output
+ {
+ std::istringstream ostr(rccStdOut);
+ std::string oline;
+ while (std::getline(ostr, oline)) {
+ StripCR(oline);
+ if (!oline.empty()) {
+ files.push_back(oline);
+ }
+ }
+ }
+ // Parse rcc error output
+ {
+ std::istringstream estr(rccStdErr);
+ std::string eline;
+ while (std::getline(estr, eline)) {
+ StripCR(eline);
+ if (cmHasLiteralPrefix(eline, "RCC: Error in")) {
+ static std::string const searchString = "Cannot find file '";
+
+ std::string::size_type pos = eline.find(searchString);
+ if (pos == std::string::npos) {
+ error = cmStrCat("rcc lists unparsable output:\n",
+ cmQtAutoGen::Quoted(eline), '\n');
+ return false;
+ }
+ pos += searchString.length();
+ std::string::size_type sz = eline.size() - pos - 1;
+ files.push_back(eline.substr(pos, sz));
+ }
+ }
+ }
+
+ return true;
+}
+
+cmQtAutoGen::RccLister::RccLister() = default;
+
+cmQtAutoGen::RccLister::RccLister(std::string rccExecutable,
+ std::vector<std::string> listOptions)
+ : RccExcutable_(std::move(rccExecutable))
+ , ListOptions_(std::move(listOptions))
+{
+}
+
+bool cmQtAutoGen::RccLister::list(std::string const& qrcFile,
+ std::vector<std::string>& files,
+ std::string& error, bool verbose) const
+{
+ error.clear();
+
+ if (!cmSystemTools::FileExists(qrcFile, true)) {
+ error =
+ cmStrCat("The resource file ", Quoted(qrcFile), " does not exist.");
+ return false;
+ }
+
+ // Run rcc list command in the directory of the qrc file with the pathless
+ // qrc file name argument. This way rcc prints relative paths.
+ // This avoids issues on Windows when the qrc file is in a path that
+ // contains non-ASCII characters.
+ std::string const fileDir = cmSystemTools::GetFilenamePath(qrcFile);
+
+ if (!this->RccExcutable_.empty() &&
+ cmSystemTools::FileExists(this->RccExcutable_, true) &&
+ !this->ListOptions_.empty()) {
+
+ bool result = false;
+ int retVal = 0;
+ std::string rccStdOut;
+ std::string rccStdErr;
+ {
+ std::vector<std::string> cmd;
+ cmd.emplace_back(this->RccExcutable_);
+ cm::append(cmd, this->ListOptions_);
+ cmd.emplace_back(cmSystemTools::GetFilenameName(qrcFile));
+
+ // Log command
+ if (verbose) {
+ cmSystemTools::Stdout(
+ cmStrCat("Running command:\n", QuotedCommand(cmd), '\n'));
+ }
+
+ result = cmSystemTools::RunSingleCommand(
+ cmd, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(),
+ cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto);
+ }
+ if (!result || retVal) {
+ error =
+ cmStrCat("The rcc list process failed for ", Quoted(qrcFile), '\n');
+ if (!rccStdOut.empty()) {
+ error += cmStrCat(rccStdOut, '\n');
+ }
+ if (!rccStdErr.empty()) {
+ error += cmStrCat(rccStdErr, '\n');
+ }
+ return false;
+ }
+ if (!RccListParseOutput(rccStdOut, rccStdErr, files, error)) {
+ return false;
+ }
+ } else {
+ // We can't use rcc for the file listing.
+ // Read the qrc file content into string and parse it.
+ {
+ std::string qrcContents;
+ {
+ cmsys::ifstream ifs(qrcFile.c_str());
+ if (ifs) {
+ std::ostringstream osst;
+ osst << ifs.rdbuf();
+ qrcContents = osst.str();
+ } else {
+ error = cmStrCat("The resource file ", Quoted(qrcFile),
+ " is not readable\n");
+ return false;
+ }
+ }
+ // Parse string content
+ RccListParseContent(qrcContents, files);
+ }
+ }
+
+ // Convert relative paths to absolute paths
+ for (std::string& entry : files) {
+ entry = cmSystemTools::CollapseFullPath(entry, fileDir);
+ }
+ return true;
+}
diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h
new file mode 100644
index 0000000..466a954
--- /dev/null
+++ b/Source/cmQtAutoGen.h
@@ -0,0 +1,141 @@
+/* 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 <memory>
+#include <string>
+#include <vector>
+
+#include <cm/string_view>
+
+/** \class cmQtAutoGen
+ * \brief Common base class for QtAutoGen classes
+ */
+class cmQtAutoGen
+{
+public:
+ /** Integer version. */
+ struct IntegerVersion
+ {
+ unsigned int Major = 0;
+ unsigned int Minor = 0;
+
+ IntegerVersion() = default;
+ IntegerVersion(unsigned int major, unsigned int minor)
+ : Major(major)
+ , Minor(minor)
+ {
+ }
+
+ bool operator>(IntegerVersion const version) const
+ {
+ return (this->Major > version.Major) ||
+ ((this->Major == version.Major) && (this->Minor > version.Minor));
+ }
+
+ bool operator>=(IntegerVersion const version) const
+ {
+ return (this->Major > version.Major) ||
+ ((this->Major == version.Major) && (this->Minor >= version.Minor));
+ }
+ };
+
+ /** Compiler features. */
+ class CompilerFeatures
+ {
+ public:
+ bool Evaluated = false;
+ std::string HelpOutput;
+ std::vector<std::string> ListOptions;
+ };
+ using CompilerFeaturesHandle = std::shared_ptr<CompilerFeatures>;
+
+ /** AutoGen generator type. */
+ enum class GenT
+ {
+ GEN, // AUTOGEN
+ MOC, // AUTOMOC
+ UIC, // AUTOUIC
+ RCC // AUTORCC
+ };
+
+ /// @brief Maximum number of parallel threads/processes in a generator
+ static unsigned int const ParallelMax;
+
+ /// @brief Returns the generator name
+ static cm::string_view GeneratorName(GenT genType);
+ /// @brief Returns the generator name in upper case
+ static cm::string_view GeneratorNameUpper(GenT genType);
+
+ /// @brief Returns a string with the requested tool names
+ static std::string Tools(bool moc, bool uic, bool rcc);
+
+ /// @brief Returns the string escaped and enclosed in quotes
+ static std::string Quoted(cm::string_view text);
+
+ static std::string QuotedCommand(std::vector<std::string> const& command);
+
+ /// @brief Returns the file name without path and extension (thread safe)
+ static std::string FileNameWithoutLastExtension(cm::string_view filename);
+
+ /// @brief Returns the parent directory of the file (thread safe)
+ static std::string ParentDir(cm::string_view filename);
+
+ /// @brief Returns the parent directory of the file with a "/" suffix
+ static std::string SubDirPrefix(cm::string_view filename);
+
+ /// @brief Appends the suffix to the filename before the last dot
+ static std::string AppendFilenameSuffix(cm::string_view filename,
+ cm::string_view suffix);
+
+ /// @brief Merges newOpts into baseOpts
+ static void UicMergeOptions(std::vector<std::string>& baseOpts,
+ std::vector<std::string> const& newOpts,
+ bool isQt5);
+
+ /// @brief Merges newOpts into baseOpts
+ static void RccMergeOptions(std::vector<std::string>& baseOpts,
+ std::vector<std::string> const& newOpts,
+ bool isQt5);
+
+ /** @class RccLister
+ * @brief Lists files in qrc resource files
+ */
+ class RccLister
+ {
+ public:
+ RccLister();
+ RccLister(std::string rccExecutable, std::vector<std::string> listOptions);
+
+ //! The rcc executable
+ std::string const& RccExcutable() const { return this->RccExcutable_; }
+ void SetRccExecutable(std::string const& rccExecutable)
+ {
+ this->RccExcutable_ = rccExecutable;
+ }
+
+ //! The rcc executable list options
+ std::vector<std::string> const& ListOptions() const
+ {
+ return this->ListOptions_;
+ }
+ void SetListOptions(std::vector<std::string> const& listOptions)
+ {
+ this->ListOptions_ = listOptions;
+ }
+
+ /**
+ * @brief Lists a files in the qrcFile
+ * @arg files The file names are appended to this list
+ * @arg error contains the error message when the function fails
+ */
+ bool list(std::string const& qrcFile, std::vector<std::string>& files,
+ std::string& error, bool verbose = false) const;
+
+ private:
+ std::string RccExcutable_;
+ std::vector<std::string> ListOptions_;
+ };
+};
diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx
new file mode 100644
index 0000000..f79ffd4
--- /dev/null
+++ b/Source/cmQtAutoGenGlobalInitializer.cxx
@@ -0,0 +1,302 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmQtAutoGenGlobalInitializer.h"
+
+#include <set>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmCustomCommandLines.h"
+#include "cmDuration.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProcessOutput.h"
+#include "cmProperty.h"
+#include "cmQtAutoGen.h"
+#include "cmQtAutoGenInitializer.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+
+cmQtAutoGenGlobalInitializer::Keywords::Keywords()
+ : AUTOMOC("AUTOMOC")
+ , AUTOUIC("AUTOUIC")
+ , AUTORCC("AUTORCC")
+ , AUTOMOC_EXECUTABLE("AUTOMOC_EXECUTABLE")
+ , AUTOUIC_EXECUTABLE("AUTOUIC_EXECUTABLE")
+ , AUTORCC_EXECUTABLE("AUTORCC_EXECUTABLE")
+ , SKIP_AUTOGEN("SKIP_AUTOGEN")
+ , SKIP_AUTOMOC("SKIP_AUTOMOC")
+ , SKIP_AUTOUIC("SKIP_AUTOUIC")
+ , SKIP_AUTORCC("SKIP_AUTORCC")
+ , AUTOUIC_OPTIONS("AUTOUIC_OPTIONS")
+ , AUTORCC_OPTIONS("AUTORCC_OPTIONS")
+ , qrc("qrc")
+ , ui("ui")
+{
+}
+
+cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
+ std::vector<std::unique_ptr<cmLocalGenerator>> const& localGenerators)
+{
+ for (const auto& localGen : localGenerators) {
+ // Detect global autogen and autorcc target names
+ bool globalAutoGenTarget = false;
+ bool globalAutoRccTarget = false;
+ {
+ cmMakefile* makefile = localGen->GetMakefile();
+ // Detect global autogen target name
+ if (makefile->IsOn("CMAKE_GLOBAL_AUTOGEN_TARGET")) {
+ std::string targetName =
+ makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTOGEN_TARGET_NAME");
+ if (targetName.empty()) {
+ targetName = "autogen";
+ }
+ this->GlobalAutoGenTargets_.emplace(localGen.get(),
+ std::move(targetName));
+ globalAutoGenTarget = true;
+ }
+
+ // Detect global autorcc target name
+ if (makefile->IsOn("CMAKE_GLOBAL_AUTORCC_TARGET")) {
+ std::string targetName =
+ makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTORCC_TARGET_NAME");
+ if (targetName.empty()) {
+ targetName = "autorcc";
+ }
+ this->GlobalAutoRccTargets_.emplace(localGen.get(),
+ std::move(targetName));
+ globalAutoRccTarget = true;
+ }
+ }
+
+ // Find targets that require AUTOMOC/UIC/RCC processing
+ for (const auto& target : localGen->GetGeneratorTargets()) {
+ // Process only certain target types
+ switch (target->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::OBJECT_LIBRARY:
+ // Process target
+ break;
+ default:
+ // Don't process target
+ continue;
+ }
+ if (target->IsImported()) {
+ // Don't process target
+ continue;
+ }
+ std::set<std::string> const& languages =
+ target->GetAllConfigCompileLanguages();
+ if (languages.count("CSharp")) {
+ // Don't process target if it's a CSharp target
+ continue;
+ }
+
+ bool const moc = target->GetPropertyAsBool(this->kw().AUTOMOC);
+ bool const uic = target->GetPropertyAsBool(this->kw().AUTOUIC);
+ bool const rcc = target->GetPropertyAsBool(this->kw().AUTORCC);
+ if (moc || uic || rcc) {
+ std::string const& mocExec =
+ target->GetSafeProperty(this->kw().AUTOMOC_EXECUTABLE);
+ std::string const& uicExec =
+ target->GetSafeProperty(this->kw().AUTOUIC_EXECUTABLE);
+ std::string const& rccExec =
+ target->GetSafeProperty(this->kw().AUTORCC_EXECUTABLE);
+
+ // We support Qt4, Qt5 and Qt6
+ auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target.get());
+ bool const validQt = (qtVersion.first.Major == 4) ||
+ (qtVersion.first.Major == 5) || (qtVersion.first.Major == 6);
+
+ bool const mocAvailable = (validQt || !mocExec.empty());
+ bool const uicAvailable = (validQt || !uicExec.empty());
+ bool const rccAvailable = (validQt || !rccExec.empty());
+ bool const mocIsValid = (moc && mocAvailable);
+ bool const uicIsValid = (uic && uicAvailable);
+ bool const rccIsValid = (rcc && rccAvailable);
+ // Disabled AUTOMOC/UIC/RCC warning
+ bool const mocDisabled = (moc && !mocAvailable);
+ bool const uicDisabled = (uic && !uicAvailable);
+ bool const rccDisabled = (rcc && !rccAvailable);
+ if (mocDisabled || uicDisabled || rccDisabled) {
+ cmAlphaNum version = (qtVersion.second == 0)
+ ? cmAlphaNum("<QTVERSION>")
+ : cmAlphaNum(qtVersion.second);
+ cmAlphaNum component = uicDisabled ? "Widgets" : "Core";
+
+ std::string const msg = cmStrCat(
+ "AUTOGEN: No valid Qt version found for target ",
+ target->GetName(), ". ",
+ cmQtAutoGen::Tools(mocDisabled, uicDisabled, rccDisabled),
+ " disabled. Consider adding:\n", " find_package(Qt", version,
+ " COMPONENTS ", component, ")\n", "to your CMakeLists.txt file.");
+ target->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, msg);
+ }
+ if (mocIsValid || uicIsValid || rccIsValid) {
+ // Create autogen target initializer
+ this->Initializers_.emplace_back(
+ cm::make_unique<cmQtAutoGenInitializer>(
+ this, target.get(), qtVersion.first, mocIsValid, uicIsValid,
+ rccIsValid, globalAutoGenTarget, globalAutoRccTarget));
+ }
+ }
+ }
+ }
+}
+
+cmQtAutoGenGlobalInitializer::~cmQtAutoGenGlobalInitializer() = default;
+
+void cmQtAutoGenGlobalInitializer::GetOrCreateGlobalTarget(
+ cmLocalGenerator* localGen, std::string const& name,
+ std::string const& comment)
+{
+ // Test if the target already exists
+ if (localGen->FindGeneratorTargetToUse(name) == nullptr) {
+ cmMakefile* makefile = localGen->GetMakefile();
+
+ // Create utility target
+ std::vector<std::string> no_byproducts;
+ std::vector<std::string> no_depends;
+ cmCustomCommandLines no_commands;
+ const cmPolicies::PolicyStatus cmp0116_new = cmPolicies::NEW;
+ cmTarget* target = localGen->AddUtilityCommand(
+ name, true, makefile->GetHomeOutputDirectory().c_str(), no_byproducts,
+ no_depends, no_commands, cmp0116_new, false, comment.c_str());
+ localGen->AddGeneratorTarget(
+ cm::make_unique<cmGeneratorTarget>(target, localGen));
+
+ // Set FOLDER property in the target
+ {
+ cmProp folder =
+ makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER");
+ if (folder != nullptr) {
+ target->SetProperty("FOLDER", *folder);
+ }
+ }
+ }
+}
+
+void cmQtAutoGenGlobalInitializer::AddToGlobalAutoGen(
+ cmLocalGenerator* localGen, std::string const& targetName)
+{
+ auto it = this->GlobalAutoGenTargets_.find(localGen);
+ if (it != this->GlobalAutoGenTargets_.end()) {
+ cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second);
+ if (target != nullptr) {
+ target->Target->AddUtility(targetName, false, localGen->GetMakefile());
+ }
+ }
+}
+
+void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc(
+ cmLocalGenerator* localGen, std::string const& targetName)
+{
+ auto it = this->GlobalAutoRccTargets_.find(localGen);
+ if (it != this->GlobalAutoRccTargets_.end()) {
+ cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second);
+ if (target != nullptr) {
+ target->Target->AddUtility(targetName, false, localGen->GetMakefile());
+ }
+ }
+}
+
+cmQtAutoGen::CompilerFeaturesHandle
+cmQtAutoGenGlobalInitializer::GetCompilerFeatures(
+ std::string const& generator, std::string const& executable,
+ std::string& error)
+{
+ // Check if we have cached features
+ {
+ auto it = this->CompilerFeatures_.find(executable);
+ if (it != this->CompilerFeatures_.end()) {
+ return it->second;
+ }
+ }
+
+ // Check if the executable exists
+ if (!cmSystemTools::FileExists(executable, true)) {
+ error = cmStrCat("The \"", generator, "\" executable ",
+ cmQtAutoGen::Quoted(executable), " does not exist.");
+ return cmQtAutoGen::CompilerFeaturesHandle();
+ }
+
+ // Test the executable
+ std::string stdOut;
+ {
+ std::string stdErr;
+ std::vector<std::string> command;
+ command.emplace_back(executable);
+ command.emplace_back("-h");
+ int retVal = 0;
+ const bool runResult = cmSystemTools::RunSingleCommand(
+ command, &stdOut, &stdErr, &retVal, nullptr, cmSystemTools::OUTPUT_NONE,
+ cmDuration::zero(), cmProcessOutput::Auto);
+ if (!runResult) {
+ error = cmStrCat("Test run of \"", generator, "\" executable ",
+ cmQtAutoGen::Quoted(executable), " failed.\n",
+ cmQtAutoGen::QuotedCommand(command), '\n', stdOut, '\n',
+ stdErr);
+ return cmQtAutoGen::CompilerFeaturesHandle();
+ }
+ }
+
+ // Create valid handle
+ cmQtAutoGen::CompilerFeaturesHandle res =
+ std::make_shared<cmQtAutoGen::CompilerFeatures>();
+ res->HelpOutput = std::move(stdOut);
+
+ // Register compiler features
+ this->CompilerFeatures_.emplace(executable, res);
+
+ return res;
+}
+
+bool cmQtAutoGenGlobalInitializer::generate()
+{
+ return (this->InitializeCustomTargets() && this->SetupCustomTargets());
+}
+
+bool cmQtAutoGenGlobalInitializer::InitializeCustomTargets()
+{
+ // Initialize global autogen targets
+ {
+ std::string const comment = "Global AUTOGEN target";
+ for (auto const& pair : this->GlobalAutoGenTargets_) {
+ this->GetOrCreateGlobalTarget(pair.first, pair.second, comment);
+ }
+ }
+ // Initialize global autorcc targets
+ {
+ std::string const comment = "Global AUTORCC target";
+ for (auto const& pair : this->GlobalAutoRccTargets_) {
+ this->GetOrCreateGlobalTarget(pair.first, pair.second, comment);
+ }
+ }
+ // Initialize per target autogen targets
+ for (auto& initializer : this->Initializers_) {
+ if (!initializer->InitCustomTargets()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoGenGlobalInitializer::SetupCustomTargets()
+{
+ for (auto& initializer : this->Initializers_) {
+ if (!initializer->SetupCustomTargets()) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/Source/cmQtAutoGenGlobalInitializer.h b/Source/cmQtAutoGenGlobalInitializer.h
new file mode 100644
index 0000000..afcb4a2
--- /dev/null
+++ b/Source/cmQtAutoGenGlobalInitializer.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 <map>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "cmQtAutoGen.h"
+
+class cmLocalGenerator;
+class cmQtAutoGenInitializer;
+
+/// @brief Initializes the QtAutoGen generators
+class cmQtAutoGenGlobalInitializer
+{
+public:
+ /// @brief Collection of QtAutogen related keywords
+ class Keywords
+ {
+ public:
+ Keywords();
+
+ std::string AUTOMOC;
+ std::string AUTOUIC;
+ std::string AUTORCC;
+
+ std::string AUTOMOC_EXECUTABLE;
+ std::string AUTOUIC_EXECUTABLE;
+ std::string AUTORCC_EXECUTABLE;
+
+ std::string SKIP_AUTOGEN;
+ std::string SKIP_AUTOMOC;
+ std::string SKIP_AUTOUIC;
+ std::string SKIP_AUTORCC;
+
+ std::string AUTOUIC_OPTIONS;
+ std::string AUTORCC_OPTIONS;
+
+ std::string qrc;
+ std::string ui;
+ };
+
+ cmQtAutoGenGlobalInitializer(
+ std::vector<std::unique_ptr<cmLocalGenerator>> const& localGenerators);
+ ~cmQtAutoGenGlobalInitializer();
+
+ Keywords const& kw() const { return this->Keywords_; };
+
+ bool generate();
+
+private:
+ friend class cmQtAutoGenInitializer;
+
+ bool InitializeCustomTargets();
+ bool SetupCustomTargets();
+
+ void GetOrCreateGlobalTarget(cmLocalGenerator* localGen,
+ std::string const& name,
+ std::string const& comment);
+
+ void AddToGlobalAutoGen(cmLocalGenerator* localGen,
+ std::string const& targetName);
+ void AddToGlobalAutoRcc(cmLocalGenerator* localGen,
+ std::string const& targetName);
+
+ cmQtAutoGen::CompilerFeaturesHandle GetCompilerFeatures(
+ std::string const& generator, std::string const& executable,
+ std::string& error);
+
+ std::vector<std::unique_ptr<cmQtAutoGenInitializer>> Initializers_;
+ std::map<cmLocalGenerator*, std::string> GlobalAutoGenTargets_;
+ std::map<cmLocalGenerator*, std::string> GlobalAutoRccTargets_;
+ std::unordered_map<std::string, cmQtAutoGen::CompilerFeaturesHandle>
+ CompilerFeatures_;
+ Keywords const Keywords_;
+};
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
new file mode 100644
index 0000000..3adeb1a
--- /dev/null
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -0,0 +1,2039 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmQtAutoGenInitializer.h"
+
+#include <cstddef>
+#include <deque>
+#include <initializer_list>
+#include <map>
+#include <ostream>
+#include <set>
+#include <string>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <cm/algorithm>
+#include <cm/iterator>
+#include <cm/memory>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include <cm3p/json/value.h>
+#include <cm3p/json/writer.h>
+
+#include "cmsys/SystemInformation.hxx"
+
+#include "cmCustomCommand.h"
+#include "cmCustomCommandLines.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmLinkItem.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmQtAutoGen.h"
+#include "cmQtAutoGenGlobalInitializer.h"
+#include "cmSourceFile.h"
+#include "cmSourceFileLocationKind.h"
+#include "cmSourceGroup.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmake.h"
+
+namespace {
+
+unsigned int GetParallelCPUCount()
+{
+ static unsigned int count = 0;
+ // Detect only on the first call
+ if (count == 0) {
+ cmsys::SystemInformation info;
+ info.RunCPUCheck();
+ count =
+ cm::clamp(info.GetNumberOfPhysicalCPU(), 1u, cmQtAutoGen::ParallelMax);
+ }
+ return count;
+}
+
+std::string FileProjectRelativePath(cmMakefile* makefile,
+ std::string const& fileName)
+{
+ std::string res;
+ {
+ std::string pSource = cmSystemTools::RelativePath(
+ makefile->GetCurrentSourceDirectory(), fileName);
+ std::string pBinary = cmSystemTools::RelativePath(
+ makefile->GetCurrentBinaryDirectory(), fileName);
+ if (pSource.size() < pBinary.size()) {
+ res = std::move(pSource);
+ } else if (pBinary.size() < fileName.size()) {
+ res = std::move(pBinary);
+ } else {
+ res = fileName;
+ }
+ }
+ return res;
+}
+
+/**
+ * Tests if targetDepend is a STATIC_LIBRARY and if any of its
+ * recursive STATIC_LIBRARY dependencies depends on targetOrigin
+ * (STATIC_LIBRARY cycle).
+ */
+bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin,
+ cmGeneratorTarget const* targetDepend,
+ std::string const& config)
+{
+ bool cycle = false;
+ if ((targetOrigin->GetType() == cmStateEnums::STATIC_LIBRARY) &&
+ (targetDepend->GetType() == cmStateEnums::STATIC_LIBRARY)) {
+ std::set<cmGeneratorTarget const*> knownLibs;
+ std::deque<cmGeneratorTarget const*> testLibs;
+
+ // Insert initial static_library dependency
+ knownLibs.insert(targetDepend);
+ testLibs.push_back(targetDepend);
+
+ while (!testLibs.empty()) {
+ cmGeneratorTarget const* testTarget = testLibs.front();
+ testLibs.pop_front();
+ // Check if the test target is the origin target (cycle)
+ if (testTarget == targetOrigin) {
+ cycle = true;
+ break;
+ }
+ // Collect all static_library dependencies from the test target
+ cmLinkImplementationLibraries const* libs =
+ testTarget->GetLinkImplementationLibraries(config);
+ if (libs != nullptr) {
+ for (cmLinkItem const& item : libs->Libraries) {
+ cmGeneratorTarget const* depTarget = item.Target;
+ if ((depTarget != nullptr) &&
+ (depTarget->GetType() == cmStateEnums::STATIC_LIBRARY) &&
+ knownLibs.insert(depTarget).second) {
+ testLibs.push_back(depTarget);
+ }
+ }
+ }
+ }
+ }
+ return cycle;
+}
+
+/** Sanitizes file search paths. */
+class SearchPathSanitizer
+{
+public:
+ SearchPathSanitizer(cmMakefile* makefile)
+ : SourcePath_(makefile->GetCurrentSourceDirectory())
+ {
+ }
+ std::vector<std::string> operator()(
+ std::vector<std::string> const& paths) const;
+
+private:
+ std::string SourcePath_;
+};
+
+std::vector<std::string> SearchPathSanitizer::operator()(
+ std::vector<std::string> const& paths) const
+{
+ std::vector<std::string> res;
+ res.reserve(paths.size());
+ for (std::string const& srcPath : paths) {
+ // Collapse relative paths
+ std::string path =
+ cmSystemTools::CollapseFullPath(srcPath, this->SourcePath_);
+ // Remove suffix slashes
+ while (cmHasSuffix(path, '/')) {
+ path.pop_back();
+ }
+ // Accept only non empty paths
+ if (!path.empty()) {
+ res.emplace_back(std::move(path));
+ }
+ }
+ return res;
+}
+
+/** @brief Writes a CMake info file. */
+class InfoWriter
+{
+public:
+ // -- Single value
+ void Set(std::string const& key, std::string const& value)
+ {
+ this->Value_[key] = value;
+ }
+ void SetConfig(std::string const& key,
+ cmQtAutoGenInitializer::ConfigString const& cfgStr);
+ void SetBool(std::string const& key, bool value)
+ {
+ this->Value_[key] = value;
+ }
+ void SetUInt(std::string const& key, unsigned int value)
+ {
+ this->Value_[key] = value;
+ }
+
+ // -- Array utility
+ template <typename CONT>
+ static bool MakeArray(Json::Value& jval, CONT const& container);
+
+ template <typename CONT>
+ static void MakeStringArray(Json::Value& jval, CONT const& container);
+
+ // -- Array value
+ template <typename CONT>
+ void SetArray(std::string const& key, CONT const& container);
+ template <typename CONT>
+ void SetConfigArray(
+ std::string const& key,
+ cmQtAutoGenInitializer::ConfigStrings<CONT> const& cfgStr);
+
+ // -- Array of arrays
+ template <typename CONT, typename FUNC>
+ void SetArrayArray(std::string const& key, CONT const& container, FUNC func);
+
+ // -- Save to json file
+ bool Save(std::string const& filename);
+
+private:
+ Json::Value Value_;
+};
+
+void InfoWriter::SetConfig(std::string const& key,
+ cmQtAutoGenInitializer::ConfigString const& cfgStr)
+{
+ this->Set(key, cfgStr.Default);
+ for (auto const& item : cfgStr.Config) {
+ this->Set(cmStrCat(key, '_', item.first), item.second);
+ }
+}
+
+template <typename CONT>
+bool InfoWriter::MakeArray(Json::Value& jval, CONT const& container)
+{
+ jval = Json::arrayValue;
+ std::size_t const listSize = cm::size(container);
+ if (listSize == 0) {
+ return false;
+ }
+ jval.resize(static_cast<unsigned int>(listSize));
+ return true;
+}
+
+template <typename CONT>
+void InfoWriter::MakeStringArray(Json::Value& jval, CONT const& container)
+{
+ if (MakeArray(jval, container)) {
+ Json::ArrayIndex ii = 0;
+ for (std::string const& item : container) {
+ jval[ii++] = item;
+ }
+ }
+}
+
+template <typename CONT>
+void InfoWriter::SetArray(std::string const& key, CONT const& container)
+{
+ MakeStringArray(this->Value_[key], container);
+}
+
+template <typename CONT, typename FUNC>
+void InfoWriter::SetArrayArray(std::string const& key, CONT const& container,
+ FUNC func)
+{
+ Json::Value& jval = this->Value_[key];
+ if (MakeArray(jval, container)) {
+ Json::ArrayIndex ii = 0;
+ for (auto const& citem : container) {
+ Json::Value& aval = jval[ii++];
+ aval = Json::arrayValue;
+ func(aval, citem);
+ }
+ }
+}
+
+template <typename CONT>
+void InfoWriter::SetConfigArray(
+ std::string const& key,
+ cmQtAutoGenInitializer::ConfigStrings<CONT> const& cfgStr)
+{
+ this->SetArray(key, cfgStr.Default);
+ for (auto const& item : cfgStr.Config) {
+ this->SetArray(cmStrCat(key, '_', item.first), item.second);
+ }
+}
+
+bool InfoWriter::Save(std::string const& filename)
+{
+ cmGeneratedFileStream fileStream;
+ fileStream.SetCopyIfDifferent(true);
+ fileStream.Open(filename, false, true);
+ if (!fileStream) {
+ return false;
+ }
+
+ Json::StyledStreamWriter jsonWriter;
+ try {
+ jsonWriter.write(fileStream, this->Value_);
+ } catch (...) {
+ return false;
+ }
+
+ return fileStream.Close();
+}
+
+void AddAutogenExecutableToDependencies(
+ cmQtAutoGenInitializer::GenVarsT const& genVars,
+ std::vector<std::string>& dependencies)
+{
+ if (genVars.ExecutableTarget != nullptr) {
+ dependencies.push_back(genVars.ExecutableTarget->Target->GetName());
+ } else if (!genVars.Executable.empty()) {
+ dependencies.push_back(genVars.Executable);
+ }
+}
+
+} // End of unnamed namespace
+
+cmQtAutoGenInitializer::cmQtAutoGenInitializer(
+ cmQtAutoGenGlobalInitializer* globalInitializer,
+ cmGeneratorTarget* genTarget, IntegerVersion const& qtVersion,
+ bool mocEnabled, bool uicEnabled, bool rccEnabled, bool globalAutogenTarget,
+ bool globalAutoRccTarget)
+ : GlobalInitializer(globalInitializer)
+ , GenTarget(genTarget)
+ , GlobalGen(genTarget->GetGlobalGenerator())
+ , LocalGen(genTarget->GetLocalGenerator())
+ , Makefile(genTarget->Makefile)
+ , PathCheckSum(genTarget->Makefile)
+ , QtVersion(qtVersion)
+{
+ this->AutogenTarget.GlobalTarget = globalAutogenTarget;
+ this->Moc.Enabled = mocEnabled;
+ this->Uic.Enabled = uicEnabled;
+ this->Rcc.Enabled = rccEnabled;
+ this->Rcc.GlobalTarget = globalAutoRccTarget;
+}
+
+bool cmQtAutoGenInitializer::InitCustomTargets()
+{
+ // Configurations
+ this->MultiConfig = this->GlobalGen->IsMultiConfig();
+ this->ConfigDefault = this->Makefile->GetDefaultConfiguration();
+ this->ConfigsList =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+ // Verbosity
+ {
+ std::string def =
+ this->Makefile->GetSafeDefinition("CMAKE_AUTOGEN_VERBOSE");
+ if (!def.empty()) {
+ unsigned long iVerb = 0;
+ if (cmStrToULong(def, &iVerb)) {
+ // Numeric verbosity
+ this->Verbosity = static_cast<unsigned int>(iVerb);
+ } else {
+ // Non numeric verbosity
+ if (cmIsOn(def)) {
+ this->Verbosity = 1;
+ }
+ }
+ }
+ }
+
+ // Targets FOLDER
+ {
+ cmProp folder =
+ this->Makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER");
+ if (folder == nullptr) {
+ folder = this->Makefile->GetState()->GetGlobalProperty(
+ "AUTOGEN_TARGETS_FOLDER");
+ }
+ // Inherit FOLDER property from target (#13688)
+ if (folder == nullptr) {
+ folder = this->GenTarget->GetProperty("FOLDER");
+ }
+ if (folder != nullptr) {
+ this->TargetsFolder = *folder;
+ }
+ }
+
+ // Check status of policy CMP0071 regarding handling of GENERATED files
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0071)) {
+ case cmPolicies::WARN:
+ // Ignore GENERATED files but warn
+ this->CMP0071Warn = true;
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // Ignore GENERATED files
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Process GENERATED files
+ this->CMP0071Accept = true;
+ break;
+ }
+
+ // Check status of policy CMP0100 regarding handling of .hh headers
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0100)) {
+ case cmPolicies::WARN:
+ // Ignore but .hh files but warn
+ this->CMP0100Warn = true;
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // Ignore .hh files
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Process .hh file
+ this->CMP0100Accept = true;
+ break;
+ }
+
+ // Common directories
+ {
+ // Collapsed current binary directory
+ std::string const cbd = cmSystemTools::CollapseFullPath(
+ std::string(), this->Makefile->GetCurrentBinaryDirectory());
+
+ // Info directory
+ this->Dir.Info = cmStrCat(cbd, "/CMakeFiles/", this->GenTarget->GetName(),
+ "_autogen.dir");
+ cmSystemTools::ConvertToUnixSlashes(this->Dir.Info);
+
+ // Build directory
+ this->Dir.Build = this->GenTarget->GetSafeProperty("AUTOGEN_BUILD_DIR");
+ if (this->Dir.Build.empty()) {
+ this->Dir.Build =
+ cmStrCat(cbd, '/', this->GenTarget->GetName(), "_autogen");
+ }
+ cmSystemTools::ConvertToUnixSlashes(this->Dir.Build);
+ // Cleanup build directory
+ this->AddCleanFile(this->Dir.Build);
+
+ // Working directory
+ this->Dir.Work = cbd;
+ cmSystemTools::ConvertToUnixSlashes(this->Dir.Work);
+
+ // Include directory
+ this->ConfigFileNamesAndGenex(this->Dir.Include, this->Dir.IncludeGenExp,
+ cmStrCat(this->Dir.Build, "/include"), "");
+ }
+
+ // Moc, Uic and _autogen target settings
+ if (this->MocOrUicEnabled()) {
+ // Init moc specific settings
+ if (this->Moc.Enabled && !this->InitMoc()) {
+ return false;
+ }
+
+ // Init uic specific settings
+ if (this->Uic.Enabled && !this->InitUic()) {
+ return false;
+ }
+
+ // Autogen target name
+ this->AutogenTarget.Name =
+ cmStrCat(this->GenTarget->GetName(), "_autogen");
+
+ // Autogen target parallel processing
+ {
+ std::string const& prop =
+ this->GenTarget->GetSafeProperty("AUTOGEN_PARALLEL");
+ if (prop.empty() || (prop == "AUTO")) {
+ // Autodetect number of CPUs
+ this->AutogenTarget.Parallel = GetParallelCPUCount();
+ } else {
+ this->AutogenTarget.Parallel = 1;
+ }
+ }
+
+ // Autogen target info and settings files
+ {
+ // Info file
+ this->AutogenTarget.InfoFile =
+ cmStrCat(this->Dir.Info, "/AutogenInfo.json");
+
+ // Used settings file
+ this->ConfigFileNames(this->AutogenTarget.SettingsFile,
+ cmStrCat(this->Dir.Info, "/AutogenUsed"), ".txt");
+ this->ConfigFileClean(this->AutogenTarget.SettingsFile);
+
+ // Parse cache file
+ this->ConfigFileNames(this->AutogenTarget.ParseCacheFile,
+ cmStrCat(this->Dir.Info, "/ParseCache"), ".txt");
+ this->ConfigFileClean(this->AutogenTarget.ParseCacheFile);
+ }
+
+ // Autogen target: Compute user defined dependencies
+ {
+ this->AutogenTarget.DependOrigin =
+ this->GenTarget->GetPropertyAsBool("AUTOGEN_ORIGIN_DEPENDS");
+
+ std::string const& deps =
+ this->GenTarget->GetSafeProperty("AUTOGEN_TARGET_DEPENDS");
+ if (!deps.empty()) {
+ for (std::string const& depName : cmExpandedList(deps)) {
+ // Allow target and file dependencies
+ auto* depTarget = this->Makefile->FindTargetToUse(depName);
+ if (depTarget != nullptr) {
+ this->AutogenTarget.DependTargets.insert(depTarget);
+ } else {
+ this->AutogenTarget.DependFiles.insert(depName);
+ }
+ }
+ }
+ }
+
+ if (this->Moc.Enabled) {
+ // Path prefix
+ if (cmIsOn(this->GenTarget->GetProperty("AUTOMOC_PATH_PREFIX"))) {
+ this->Moc.PathPrefix = true;
+ }
+
+ // CMAKE_AUTOMOC_RELAXED_MODE
+ if (this->Makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE")) {
+ this->Moc.RelaxedMode = true;
+ this->Makefile->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat("AUTOMOC: CMAKE_AUTOMOC_RELAXED_MODE is "
+ "deprecated an will be removed in the future. Consider "
+ "disabling it and converting the target ",
+ this->GenTarget->GetName(), " to regular mode."));
+ }
+
+ // Options
+ cmExpandList(this->GenTarget->GetSafeProperty("AUTOMOC_MOC_OPTIONS"),
+ this->Moc.Options);
+ // Filters
+ cmExpandList(this->GenTarget->GetSafeProperty("AUTOMOC_MACRO_NAMES"),
+ this->Moc.MacroNames);
+ {
+ auto filterList = cmExpandedList(
+ this->GenTarget->GetSafeProperty("AUTOMOC_DEPEND_FILTERS"));
+ if ((filterList.size() % 2) != 0) {
+ cmSystemTools::Error(
+ cmStrCat("AutoMoc: AUTOMOC_DEPEND_FILTERS predefs size ",
+ filterList.size(), " is not a multiple of 2."));
+ return false;
+ }
+ this->Moc.DependFilters.reserve(1 + (filterList.size() / 2));
+ this->Moc.DependFilters.emplace_back(
+ "Q_PLUGIN_METADATA",
+ "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
+ "[^\\)]*FILE[ \t]*\"([^\"]+)\"");
+ for (std::size_t ii = 0; ii != filterList.size(); ii += 2) {
+ this->Moc.DependFilters.emplace_back(filterList[ii],
+ filterList[ii + 1]);
+ }
+ }
+ }
+ }
+
+ // Init rcc specific settings
+ if (this->Rcc.Enabled && !this->InitRcc()) {
+ return false;
+ }
+
+ // Add autogen include directory to the origin target INCLUDE_DIRECTORIES
+ if (this->MocOrUicEnabled() || (this->Rcc.Enabled && this->MultiConfig)) {
+ this->GenTarget->AddIncludeDirectory(this->Dir.IncludeGenExp, true);
+ }
+
+ // Scan files
+ if (!this->InitScanFiles()) {
+ return false;
+ }
+
+ // Create autogen target
+ if (this->MocOrUicEnabled() && !this->InitAutogenTarget()) {
+ return false;
+ }
+
+ // Create rcc targets
+ if (this->Rcc.Enabled && !this->InitRccTargets()) {
+ return false;
+ }
+
+ return true;
+}
+
+bool cmQtAutoGenInitializer::InitMoc()
+{
+ // Mocs compilation file
+ if (this->GlobalGen->IsXcode()) {
+ // XXX(xcode-per-cfg-src): Drop this Xcode-specific code path
+ // when the Xcode generator supports per-config sources.
+ this->Moc.CompilationFile.Default =
+ cmStrCat(this->Dir.Build, "/mocs_compilation.cpp");
+ this->Moc.CompilationFileGenex = this->Moc.CompilationFile.Default;
+ } else {
+ this->ConfigFileNamesAndGenex(
+ this->Moc.CompilationFile, this->Moc.CompilationFileGenex,
+ cmStrCat(this->Dir.Build, "/mocs_compilation"_s), ".cpp"_s);
+ }
+
+ // Moc predefs
+ if (this->GenTarget->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") &&
+ (this->QtVersion >= IntegerVersion(5, 8))) {
+ // Command
+ this->Makefile->GetDefExpandList("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND",
+ this->Moc.PredefsCmd);
+ // Header
+ if (!this->Moc.PredefsCmd.empty()) {
+ this->ConfigFileNames(this->Moc.PredefsFile,
+ cmStrCat(this->Dir.Build, "/moc_predefs"), ".h");
+ }
+ }
+
+ // Moc includes
+ {
+ SearchPathSanitizer sanitizer(this->Makefile);
+ auto getDirs =
+ [this, &sanitizer](std::string const& cfg) -> std::vector<std::string> {
+ // Get the include dirs for this target, without stripping the implicit
+ // include dirs off, see issue #13667.
+ std::vector<std::string> dirs;
+ bool const appendImplicit = (this->QtVersion.Major >= 5);
+ this->LocalGen->GetIncludeDirectoriesImplicit(
+ dirs, this->GenTarget, "CXX", cfg, false, appendImplicit);
+ return sanitizer(dirs);
+ };
+
+ // Default configuration include directories
+ this->Moc.Includes.Default = getDirs(this->ConfigDefault);
+ // Other configuration settings
+ if (this->MultiConfig) {
+ for (std::string const& cfg : this->ConfigsList) {
+ std::vector<std::string> dirs = getDirs(cfg);
+ if (dirs == this->Moc.Includes.Default) {
+ continue;
+ }
+ this->Moc.Includes.Config[cfg] = std::move(dirs);
+ }
+ }
+ }
+
+ // Moc compile definitions
+ {
+ auto getDefs = [this](std::string const& cfg) -> std::set<std::string> {
+ std::set<std::string> defines;
+ this->LocalGen->GetTargetDefines(this->GenTarget, cfg, "CXX", defines);
+#ifdef _WIN32
+ if (this->Moc.PredefsCmd.empty()) {
+ // Add WIN32 definition if we don't have a moc_predefs.h
+ defines.insert("WIN32");
+ }
+#endif
+ return defines;
+ };
+
+ // Default configuration defines
+ this->Moc.Defines.Default = getDefs(this->ConfigDefault);
+ // Other configuration defines
+ if (this->MultiConfig) {
+ for (std::string const& cfg : this->ConfigsList) {
+ std::set<std::string> defines = getDefs(cfg);
+ if (defines == this->Moc.Defines.Default) {
+ continue;
+ }
+ this->Moc.Defines.Config[cfg] = std::move(defines);
+ }
+ }
+ }
+
+ // Moc executable
+ {
+ if (!this->GetQtExecutable(this->Moc, "moc", false)) {
+ return false;
+ }
+ // Let the _autogen target depend on the moc executable
+ if (this->Moc.ExecutableTarget != nullptr) {
+ this->AutogenTarget.DependTargets.insert(
+ this->Moc.ExecutableTarget->Target);
+ }
+ }
+
+ return true;
+}
+
+bool cmQtAutoGenInitializer::InitUic()
+{
+ // Uic search paths
+ {
+ std::string const& usp =
+ this->GenTarget->GetSafeProperty("AUTOUIC_SEARCH_PATHS");
+ if (!usp.empty()) {
+ this->Uic.SearchPaths =
+ SearchPathSanitizer(this->Makefile)(cmExpandedList(usp));
+ }
+ }
+ // Uic target options
+ {
+ auto getOpts = [this](std::string const& cfg) -> std::vector<std::string> {
+ std::vector<std::string> opts;
+ this->GenTarget->GetAutoUicOptions(opts, cfg);
+ return opts;
+ };
+
+ // Default options
+ this->Uic.Options.Default = getOpts(this->ConfigDefault);
+ // Configuration specific options
+ if (this->MultiConfig) {
+ for (std::string const& cfg : this->ConfigsList) {
+ std::vector<std::string> options = getOpts(cfg);
+ if (options == this->Uic.Options.Default) {
+ continue;
+ }
+ this->Uic.Options.Config[cfg] = std::move(options);
+ }
+ }
+ }
+
+ // Uic executable
+ {
+ if (!this->GetQtExecutable(this->Uic, "uic", true)) {
+ return false;
+ }
+ // Let the _autogen target depend on the uic executable
+ if (this->Uic.ExecutableTarget != nullptr) {
+ this->AutogenTarget.DependTargets.insert(
+ this->Uic.ExecutableTarget->Target);
+ }
+ }
+
+ return true;
+}
+
+bool cmQtAutoGenInitializer::InitRcc()
+{
+ // Rcc executable
+ {
+ if (!this->GetQtExecutable(this->Rcc, "rcc", false)) {
+ return false;
+ }
+ // Evaluate test output on demand
+ CompilerFeatures& features = *this->Rcc.ExecutableFeatures;
+ if (!features.Evaluated) {
+ // Look for list options
+ if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) {
+ if (features.HelpOutput.find("--list") != std::string::npos) {
+ features.ListOptions.emplace_back("--list");
+ } else if (features.HelpOutput.find("-list") != std::string::npos) {
+ features.ListOptions.emplace_back("-list");
+ }
+ }
+ // Evaluation finished
+ features.Evaluated = true;
+ }
+ }
+
+ return true;
+}
+
+bool cmQtAutoGenInitializer::InitScanFiles()
+{
+ cmake const* cm = this->Makefile->GetCMakeInstance();
+ auto const& kw = this->GlobalInitializer->kw();
+
+ auto makeMUFile = [this, &kw](cmSourceFile* sf, std::string const& fullPath,
+ std::vector<size_t> const& configs,
+ bool muIt) -> MUFileHandle {
+ MUFileHandle muf = cm::make_unique<MUFile>();
+ muf->FullPath = fullPath;
+ muf->SF = sf;
+ if (!configs.empty() && configs.size() != this->ConfigsList.size()) {
+ muf->Configs = configs;
+ }
+ muf->Generated = sf->GetIsGenerated();
+ bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN);
+ muf->SkipMoc = this->Moc.Enabled &&
+ (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOMOC));
+ muf->SkipUic = this->Uic.Enabled &&
+ (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC));
+ if (muIt) {
+ muf->MocIt = this->Moc.Enabled && !muf->SkipMoc;
+ muf->UicIt = this->Uic.Enabled && !muf->SkipUic;
+ }
+ return muf;
+ };
+
+ auto addMUHeader = [this](MUFileHandle&& muf, cm::string_view extension) {
+ cmSourceFile* sf = muf->SF;
+ const bool muIt = (muf->MocIt || muf->UicIt);
+ if (this->CMP0100Accept || (extension != "hh")) {
+ // Accept
+ if (muIt && muf->Generated) {
+ this->AutogenTarget.FilesGenerated.emplace_back(muf.get());
+ }
+ this->AutogenTarget.Headers.emplace(sf, std::move(muf));
+ } else if (muIt && this->CMP0100Warn) {
+ // Store file for warning message
+ this->AutogenTarget.CMP0100HeadersWarn.push_back(sf);
+ }
+ };
+
+ auto addMUSource = [this](MUFileHandle&& muf) {
+ if ((muf->MocIt || muf->UicIt) && muf->Generated) {
+ this->AutogenTarget.FilesGenerated.emplace_back(muf.get());
+ }
+ this->AutogenTarget.Sources.emplace(muf->SF, std::move(muf));
+ };
+
+ // Scan through target files
+ {
+ // Scan through target files
+ for (cmGeneratorTarget::AllConfigSource const& acs :
+ this->GenTarget->GetAllConfigSources()) {
+ std::string const& fullPath = acs.Source->GetFullPath();
+ std::string const& extLower =
+ cmSystemTools::LowerCase(acs.Source->GetExtension());
+
+ // Register files that will be scanned by moc or uic
+ if (this->MocOrUicEnabled()) {
+ if (cm->IsAHeaderExtension(extLower)) {
+ addMUHeader(makeMUFile(acs.Source, fullPath, acs.Configs, true),
+ extLower);
+ } else if (cm->IsACLikeSourceExtension(extLower)) {
+ addMUSource(makeMUFile(acs.Source, fullPath, acs.Configs, true));
+ }
+ }
+
+ // Register rcc enabled files
+ if (this->Rcc.Enabled) {
+ if ((extLower == kw.qrc) &&
+ !acs.Source->GetPropertyAsBool(kw.SKIP_AUTOGEN) &&
+ !acs.Source->GetPropertyAsBool(kw.SKIP_AUTORCC)) {
+ // Register qrc file
+ Qrc qrc;
+ qrc.QrcFile = fullPath;
+ qrc.QrcName =
+ cmSystemTools::GetFilenameWithoutLastExtension(qrc.QrcFile);
+ qrc.Generated = acs.Source->GetIsGenerated();
+ // RCC options
+ {
+ std::string const& opts =
+ acs.Source->GetSafeProperty(kw.AUTORCC_OPTIONS);
+ if (!opts.empty()) {
+ cmExpandList(opts, qrc.Options);
+ }
+ }
+ this->Rcc.Qrcs.push_back(std::move(qrc));
+ }
+ }
+ }
+ }
+ // cmGeneratorTarget::GetAllConfigSources computes the target's
+ // sources meta data cache. Clear it so that OBJECT library targets that
+ // are AUTOGEN initialized after this target get their added
+ // mocs_compilation.cpp source acknowledged by this target.
+ this->GenTarget->ClearSourcesCache();
+
+ // For source files find additional headers and private headers
+ if (this->MocOrUicEnabled()) {
+ // Header search suffixes and extensions
+ static std::initializer_list<cm::string_view> const suffixes{ "", "_p" };
+ auto const& exts = cm->GetHeaderExtensions();
+ // Scan through sources
+ for (auto const& pair : this->AutogenTarget.Sources) {
+ MUFile const& muf = *pair.second;
+ if (muf.MocIt || muf.UicIt) {
+ // Search for the default header file and a private header
+ std::string const& srcFullPath = muf.SF->ResolveFullPath();
+ std::string basePath = cmStrCat(
+ cmQtAutoGen::SubDirPrefix(srcFullPath),
+ cmSystemTools::GetFilenameWithoutLastExtension(srcFullPath));
+ for (auto const& suffix : suffixes) {
+ std::string const suffixedPath = cmStrCat(basePath, suffix);
+ for (auto const& ext : exts) {
+ std::string fullPath = cmStrCat(suffixedPath, '.', ext);
+
+ auto constexpr locationKind = cmSourceFileLocationKind::Known;
+ cmSourceFile* sf =
+ this->Makefile->GetSource(fullPath, locationKind);
+ if (sf != nullptr) {
+ // Check if we know about this header already
+ if (cm::contains(this->AutogenTarget.Headers, sf)) {
+ continue;
+ }
+ // We only accept not-GENERATED files that do exist.
+ if (!sf->GetIsGenerated() &&
+ !cmSystemTools::FileExists(fullPath)) {
+ continue;
+ }
+ } else if (cmSystemTools::FileExists(fullPath)) {
+ // Create a new source file for the existing file
+ sf = this->Makefile->CreateSource(fullPath, false, locationKind);
+ }
+
+ if (sf != nullptr) {
+ auto eMuf = makeMUFile(sf, fullPath, muf.Configs, true);
+ // Only process moc/uic when the parent is processed as well
+ if (!muf.MocIt) {
+ eMuf->MocIt = false;
+ }
+ if (!muf.UicIt) {
+ eMuf->UicIt = false;
+ }
+ addMUHeader(std::move(eMuf), ext);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Scan through all source files in the makefile to extract moc and uic
+ // parameters. Historically we support non target source file parameters.
+ // The reason is that their file names might be discovered from source files
+ // at generation time.
+ if (this->MocOrUicEnabled()) {
+ for (const auto& sf : this->Makefile->GetSourceFiles()) {
+ // sf->GetExtension() is only valid after sf->ResolveFullPath() ...
+ // Since we're iterating over source files that might be not in the
+ // target we need to check for path errors (not existing files).
+ std::string pathError;
+ std::string const& fullPath = sf->ResolveFullPath(&pathError);
+ if (!pathError.empty() || fullPath.empty()) {
+ continue;
+ }
+ std::string const& extLower =
+ cmSystemTools::LowerCase(sf->GetExtension());
+
+ if (cm->IsAHeaderExtension(extLower)) {
+ if (!cm::contains(this->AutogenTarget.Headers, sf.get())) {
+ auto muf = makeMUFile(sf.get(), fullPath, {}, false);
+ if (muf->SkipMoc || muf->SkipUic) {
+ addMUHeader(std::move(muf), extLower);
+ }
+ }
+ } else if (cm->IsACLikeSourceExtension(extLower)) {
+ if (!cm::contains(this->AutogenTarget.Sources, sf.get())) {
+ auto muf = makeMUFile(sf.get(), fullPath, {}, false);
+ if (muf->SkipMoc || muf->SkipUic) {
+ addMUSource(std::move(muf));
+ }
+ }
+ } else if (this->Uic.Enabled && (extLower == kw.ui)) {
+ // .ui file
+ bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN);
+ bool const skipUic =
+ (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC));
+ if (!skipUic) {
+ // Check if the .ui file has uic options
+ std::string const uicOpts = sf->GetSafeProperty(kw.AUTOUIC_OPTIONS);
+ if (uicOpts.empty()) {
+ this->Uic.UiFilesNoOptions.emplace_back(fullPath);
+ } else {
+ this->Uic.UiFilesWithOptions.emplace_back(fullPath,
+ cmExpandedList(uicOpts));
+ }
+
+ auto uiHeaderRelativePath = cmSystemTools::RelativePath(
+ this->LocalGen->GetCurrentSourceDirectory(),
+ cmSystemTools::GetFilenamePath(fullPath));
+
+ // Avoid creating a path containing adjacent slashes
+ if (!uiHeaderRelativePath.empty() &&
+ uiHeaderRelativePath.back() != '/') {
+ uiHeaderRelativePath += '/';
+ }
+
+ auto uiHeaderFilePath = cmStrCat(
+ '/', uiHeaderRelativePath, "ui_"_s,
+ cmSystemTools::GetFilenameWithoutLastExtension(fullPath), ".h"_s);
+
+ ConfigString uiHeader;
+ std::string uiHeaderGenex;
+ this->ConfigFileNamesAndGenex(
+ uiHeader, uiHeaderGenex, cmStrCat(this->Dir.Build, "/include"_s),
+ uiHeaderFilePath);
+
+ this->Uic.UiHeaders.emplace_back(
+ std::make_pair(uiHeader, uiHeaderGenex));
+ } else {
+ // Register skipped .ui file
+ this->Uic.SkipUi.insert(fullPath);
+ }
+ }
+ }
+ }
+
+ // Process GENERATED sources and headers
+ if (this->MocOrUicEnabled() && !this->AutogenTarget.FilesGenerated.empty()) {
+ if (this->CMP0071Accept) {
+ // Let the autogen target depend on the GENERATED files
+ for (MUFile* muf : this->AutogenTarget.FilesGenerated) {
+ this->AutogenTarget.DependFiles.insert(muf->FullPath);
+ }
+ } else if (this->CMP0071Warn) {
+ cm::string_view property;
+ if (this->Moc.Enabled && this->Uic.Enabled) {
+ property = "SKIP_AUTOGEN";
+ } else if (this->Moc.Enabled) {
+ property = "SKIP_AUTOMOC";
+ } else if (this->Uic.Enabled) {
+ property = "SKIP_AUTOUIC";
+ }
+ std::string files;
+ for (MUFile* muf : this->AutogenTarget.FilesGenerated) {
+ files += cmStrCat(" ", Quoted(muf->FullPath), '\n');
+ }
+ this->Makefile->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0071), '\n',
+ "For compatibility, CMake is excluding the GENERATED source "
+ "file(s):\n",
+ files, "from processing by ",
+ cmQtAutoGen::Tools(this->Moc.Enabled, this->Uic.Enabled, false),
+ ". If any of the files should be processed, set CMP0071 to NEW. "
+ "If any of the files should not be processed, "
+ "explicitly exclude them by setting the source file property ",
+ property, ":\n set_property(SOURCE file.h PROPERTY ", property,
+ " ON)\n"));
+ }
+ }
+
+ // Generate CMP0100 warning
+ if (this->MocOrUicEnabled() &&
+ !this->AutogenTarget.CMP0100HeadersWarn.empty()) {
+ cm::string_view property;
+ if (this->Moc.Enabled && this->Uic.Enabled) {
+ property = "SKIP_AUTOGEN";
+ } else if (this->Moc.Enabled) {
+ property = "SKIP_AUTOMOC";
+ } else if (this->Uic.Enabled) {
+ property = "SKIP_AUTOUIC";
+ }
+ std::string files;
+ for (cmSourceFile* sf : this->AutogenTarget.CMP0100HeadersWarn) {
+ files += cmStrCat(" ", Quoted(sf->GetFullPath()), '\n');
+ }
+ this->Makefile->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0100), '\n',
+ "For compatibility, CMake is excluding the header file(s):\n", files,
+ "from processing by ",
+ cmQtAutoGen::Tools(this->Moc.Enabled, this->Uic.Enabled, false),
+ ". If any of the files should be processed, set CMP0100 to NEW. "
+ "If any of the files should not be processed, "
+ "explicitly exclude them by setting the source file property ",
+ property, ":\n set_property(SOURCE file.hh PROPERTY ", property,
+ " ON)\n"));
+ }
+
+ // Process qrc files
+ if (!this->Rcc.Qrcs.empty()) {
+ const bool modernQt = (this->QtVersion.Major >= 5);
+ // Target rcc options
+ std::vector<std::string> optionsTarget =
+ cmExpandedList(this->GenTarget->GetSafeProperty(kw.AUTORCC_OPTIONS));
+
+ // Check if file name is unique
+ for (Qrc& qrc : this->Rcc.Qrcs) {
+ qrc.Unique = true;
+ for (Qrc const& qrc2 : this->Rcc.Qrcs) {
+ if ((&qrc != &qrc2) && (qrc.QrcName == qrc2.QrcName)) {
+ qrc.Unique = false;
+ break;
+ }
+ }
+ }
+ // Path checksum and file names
+ for (Qrc& qrc : this->Rcc.Qrcs) {
+ // Path checksum
+ qrc.QrcPathChecksum = this->PathCheckSum.getPart(qrc.QrcFile);
+ // Output file name
+ qrc.OutputFile = cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum,
+ "/qrc_", qrc.QrcName, ".cpp");
+ std::string const base = cmStrCat(this->Dir.Info, "/AutoRcc_",
+ qrc.QrcName, '_', qrc.QrcPathChecksum);
+ qrc.LockFile = cmStrCat(base, "_Lock.lock");
+ qrc.InfoFile = cmStrCat(base, "_Info.json");
+ this->ConfigFileNames(qrc.SettingsFile, cmStrCat(base, "_Used"), ".txt");
+ }
+ // rcc options
+ for (Qrc& qrc : this->Rcc.Qrcs) {
+ // Target options
+ std::vector<std::string> opts = optionsTarget;
+ // Merge computed "-name XYZ" option
+ {
+ std::string name = qrc.QrcName;
+ // Replace '-' with '_'. The former is not valid for symbol names.
+ std::replace(name.begin(), name.end(), '-', '_');
+ if (!qrc.Unique) {
+ name += cmStrCat('_', qrc.QrcPathChecksum);
+ }
+ std::vector<std::string> nameOpts;
+ nameOpts.emplace_back("-name");
+ nameOpts.emplace_back(std::move(name));
+ RccMergeOptions(opts, nameOpts, modernQt);
+ }
+ // Merge file option
+ RccMergeOptions(opts, qrc.Options, modernQt);
+ qrc.Options = std::move(opts);
+ }
+ // rcc resources
+ for (Qrc& qrc : this->Rcc.Qrcs) {
+ if (!qrc.Generated) {
+ std::string error;
+ RccLister const lister(this->Rcc.Executable,
+ this->Rcc.ExecutableFeatures->ListOptions);
+ if (!lister.list(qrc.QrcFile, qrc.Resources, error)) {
+ cmSystemTools::Error(error);
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool cmQtAutoGenInitializer::InitAutogenTarget()
+{
+ // Register info file as generated by CMake
+ this->Makefile->AddCMakeOutputFile(this->AutogenTarget.InfoFile);
+
+ // Files provided by the autogen target
+ std::vector<std::string> autogenByproducts;
+ if (this->Moc.Enabled) {
+ this->AddGeneratedSource(this->Moc.CompilationFile, this->Moc, true);
+ autogenByproducts.push_back(this->Moc.CompilationFileGenex);
+ }
+
+ if (this->Uic.Enabled) {
+ for (const auto& file : this->Uic.UiHeaders) {
+ this->AddGeneratedSource(file.first, this->Uic);
+ autogenByproducts.push_back(file.second);
+ }
+ }
+
+ // Compose target comment
+ std::string autogenComment;
+ {
+ std::string tools;
+ if (this->Moc.Enabled) {
+ tools += "MOC";
+ }
+ if (this->Uic.Enabled) {
+ if (!tools.empty()) {
+ tools += " and ";
+ }
+ tools += "UIC";
+ }
+ autogenComment = cmStrCat("Automatic ", tools, " for target ",
+ this->GenTarget->GetName());
+ }
+
+ // Compose command lines
+ // FIXME: Take advantage of our per-config mocs_compilation_$<CONFIG>.cpp
+ // instead of fiddling with the include directories
+ std::vector<std::string> configs;
+ this->GlobalGen->GetQtAutoGenConfigs(configs);
+ bool stdPipesUTF8 = true;
+ cmCustomCommandLines commandLines;
+ for (auto const& config : configs) {
+ commandLines.push_back(cmMakeCommandLine(
+ { cmSystemTools::GetCMakeCommand(), "-E", "cmake_autogen",
+ this->AutogenTarget.InfoFile, config }));
+ }
+
+ // Use PRE_BUILD on demand
+ bool usePRE_BUILD = false;
+ if (this->GlobalGen->GetName().find("Visual Studio") != std::string::npos) {
+ // Under VS use a PRE_BUILD event instead of a separate target to
+ // reduce the number of targets loaded into the IDE.
+ // This also works around a VS 11 bug that may skip updating the target:
+ // https://connect.microsoft.com/VisualStudio/feedback/details/769495
+ usePRE_BUILD = true;
+ }
+ // Disable PRE_BUILD in some cases
+ if (usePRE_BUILD) {
+ // Cannot use PRE_BUILD with file depends
+ if (!this->AutogenTarget.DependFiles.empty()) {
+ usePRE_BUILD = false;
+ }
+ // Cannot use PRE_BUILD when a global autogen target is in place
+ if (this->AutogenTarget.GlobalTarget) {
+ usePRE_BUILD = false;
+ }
+ }
+ // Create the autogen target/command
+ if (usePRE_BUILD) {
+ // Add additional autogen target dependencies to origin target
+ for (cmTarget* depTarget : this->AutogenTarget.DependTargets) {
+ this->GenTarget->Target->AddUtility(depTarget->GetName(), false,
+ this->Makefile);
+ }
+
+ if (!this->Uic.UiFilesNoOptions.empty() ||
+ !this->Uic.UiFilesWithOptions.empty()) {
+ // Add a generated timestamp file
+ ConfigString timestampFile;
+ std::string timestampFileGenex;
+ ConfigFileNamesAndGenex(timestampFile, timestampFileGenex,
+ cmStrCat(this->Dir.Build, "/autouic"_s),
+ ".stamp"_s);
+ this->AddGeneratedSource(timestampFile, this->Uic);
+
+ // Add a step in the pre-build command to touch the timestamp file
+ commandLines.push_back(
+ cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", "touch",
+ timestampFileGenex }));
+
+ // UIC needs to be re-run if any of the known UI files change or the
+ // executable itself has been updated
+ auto uicDependencies = this->Uic.UiFilesNoOptions;
+ for (auto const& uiFile : this->Uic.UiFilesWithOptions) {
+ uicDependencies.push_back(uiFile.first);
+ }
+ AddAutogenExecutableToDependencies(this->Uic, uicDependencies);
+
+ // Add a rule file to cause the target to build if a dependency has
+ // changed, which will trigger the pre-build command to run autogen
+ std::string no_main_dependency;
+ cmCustomCommandLines no_command_lines;
+ this->LocalGen->AddCustomCommandToOutput(
+ timestampFileGenex, uicDependencies, no_main_dependency,
+ no_command_lines, /*comment=*/"", this->Dir.Work.c_str(),
+ /*cmp0116=*/cmPolicies::NEW, /*replace=*/false,
+ /*escapeOldStyle=*/false, /*uses_terminal=*/false,
+ /*command_expand_lists=*/false, /*depfile=*/"", /*job_pool=*/"",
+ stdPipesUTF8);
+ }
+
+ // Add the pre-build command directly to bypass the OBJECT_LIBRARY
+ // rejection in cmMakefile::AddCustomCommandToTarget because we know
+ // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case.
+ //
+ // PRE_BUILD does not support file dependencies!
+ const std::vector<std::string> no_output;
+ const std::vector<std::string> no_deps;
+ cmCustomCommand cc(no_output, autogenByproducts, no_deps, commandLines,
+ this->Makefile->GetBacktrace(), autogenComment.c_str(),
+ this->Dir.Work.c_str(), stdPipesUTF8);
+ cc.SetEscapeOldStyle(false);
+ cc.SetEscapeAllowMakeVars(true);
+ this->GenTarget->Target->AddPreBuildCommand(std::move(cc));
+ } else {
+
+ // Add link library target dependencies to the autogen target
+ // dependencies
+ if (this->AutogenTarget.DependOrigin) {
+ // add_dependencies/addUtility do not support generator expressions.
+ // We depend only on the libraries found in all configs therefore.
+ std::map<cmGeneratorTarget const*, std::size_t> commonTargets;
+ for (std::string const& config : this->ConfigsList) {
+ cmLinkImplementationLibraries const* libs =
+ this->GenTarget->GetLinkImplementationLibraries(config);
+ if (libs != nullptr) {
+ for (cmLinkItem const& item : libs->Libraries) {
+ cmGeneratorTarget const* libTarget = item.Target;
+ if ((libTarget != nullptr) &&
+ !StaticLibraryCycle(this->GenTarget, libTarget, config)) {
+ // Increment target config count
+ commonTargets[libTarget]++;
+ }
+ }
+ }
+ }
+ for (auto const& item : commonTargets) {
+ if (item.second == this->ConfigsList.size()) {
+ this->AutogenTarget.DependTargets.insert(item.first->Target);
+ }
+ }
+ }
+
+ std::vector<std::string> dependencies(
+ this->AutogenTarget.DependFiles.begin(),
+ this->AutogenTarget.DependFiles.end());
+
+ const bool useNinjaDepfile = this->QtVersion >= IntegerVersion(5, 15) &&
+ this->GlobalGen->GetName().find("Ninja") != std::string::npos;
+ if (useNinjaDepfile) {
+ // Create a custom command that generates a timestamp file and
+ // has a depfile assigned. The depfile is created by JobDepFilesMergeT.
+ //
+ // Also create an additional '_autogen_timestamp_deps' that the custom
+ // command will depend on. It will have no sources or commands to
+ // execute, but it will have dependencies that would originally be
+ // assigned to the pre-Qt 5.15 'autogen' target. These dependencies will
+ // serve as a list of order-only dependencies for the custom command,
+ // without forcing the custom command to re-execute.
+ //
+ // The dependency tree would then look like
+ // '_autogen_timestamp_deps (order-only)' <- '/timestamp' file <-
+ // '_autogen' target.
+ const auto timestampTargetName =
+ cmStrCat(this->GenTarget->GetName(), "_autogen_timestamp_deps");
+ std::vector<std::string> timestampTargetProvides;
+ cmCustomCommandLines timestampTargetCommandLines;
+
+ // Add additional autogen target dependencies to
+ // '_autogen_timestamp_deps'.
+ for (const cmTarget* t : this->AutogenTarget.DependTargets) {
+ dependencies.push_back(t->GetName());
+ }
+
+ cmTarget* timestampTarget = this->LocalGen->AddUtilityCommand(
+ timestampTargetName, true, this->Dir.Work.c_str(),
+ /*byproducts=*/timestampTargetProvides,
+ /*depends=*/dependencies, timestampTargetCommandLines, cmPolicies::NEW,
+ false, nullptr);
+ this->LocalGen->AddGeneratorTarget(
+ cm::make_unique<cmGeneratorTarget>(timestampTarget, this->LocalGen));
+
+ // Set FOLDER property on the timestamp target, so it appears in the
+ // appropriate folder in an IDE or in the file api.
+ if (!this->TargetsFolder.empty()) {
+ timestampTarget->SetProperty("FOLDER", this->TargetsFolder);
+ }
+
+ // Make '/timestamp' file depend on '_autogen_timestamp_deps' and on the
+ // moc and uic executables (whichever are enabled).
+ dependencies.clear();
+ dependencies.push_back(timestampTargetName);
+
+ AddAutogenExecutableToDependencies(this->Moc, dependencies);
+ AddAutogenExecutableToDependencies(this->Uic, dependencies);
+
+ // Create the custom command that outputs the timestamp file.
+ const char timestampFileName[] = "timestamp";
+ const std::string outputFile =
+ cmStrCat(this->Dir.Build, "/", timestampFileName);
+ this->AutogenTarget.DepFile = cmStrCat(this->Dir.Build, "/deps");
+ this->AutogenTarget.DepFileRuleName =
+ cmStrCat(this->GenTarget->GetName(), "_autogen/", timestampFileName);
+ commandLines.push_back(cmMakeCommandLine(
+ { cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile }));
+
+ this->AddGeneratedSource(outputFile, this->Moc);
+ const std::string no_main_dependency;
+ this->LocalGen->AddCustomCommandToOutput(
+ outputFile, dependencies, no_main_dependency, commandLines,
+ autogenComment.c_str(), this->Dir.Work.c_str(),
+ /*cmp0116=*/cmPolicies::NEW, /*replace=*/false,
+ /*escapeOldStyle=*/false,
+ /*uses_terminal=*/false,
+ /*command_expand_lists=*/false, this->AutogenTarget.DepFile, "",
+ stdPipesUTF8);
+
+ // Alter variables for the autogen target which now merely wraps the
+ // custom command
+ dependencies.clear();
+ dependencies.push_back(outputFile);
+ commandLines.clear();
+ autogenComment.clear();
+ }
+
+ // Create autogen target
+ cmTarget* autogenTarget = this->LocalGen->AddUtilityCommand(
+ this->AutogenTarget.Name, true, this->Dir.Work.c_str(),
+ /*byproducts=*/autogenByproducts,
+ /*depends=*/dependencies, commandLines, cmPolicies::NEW, false,
+ autogenComment.c_str());
+ // Create autogen generator target
+ this->LocalGen->AddGeneratorTarget(
+ cm::make_unique<cmGeneratorTarget>(autogenTarget, this->LocalGen));
+
+ // Forward origin utilities to autogen target
+ if (this->AutogenTarget.DependOrigin) {
+ for (BT<std::pair<std::string, bool>> const& depName :
+ this->GenTarget->GetUtilities()) {
+ autogenTarget->AddUtility(depName.Value.first, false, this->Makefile);
+ }
+ }
+ if (!useNinjaDepfile) {
+ // Add additional autogen target dependencies to autogen target
+ for (cmTarget* depTarget : this->AutogenTarget.DependTargets) {
+ autogenTarget->AddUtility(depTarget->GetName(), false, this->Makefile);
+ }
+ }
+
+ // Set FOLDER property in autogen target
+ if (!this->TargetsFolder.empty()) {
+ autogenTarget->SetProperty("FOLDER", this->TargetsFolder);
+ }
+
+ // Add autogen target to the origin target dependencies
+ this->GenTarget->Target->AddUtility(this->AutogenTarget.Name, false,
+ this->Makefile);
+
+ // Add autogen target to the global autogen target dependencies
+ if (this->AutogenTarget.GlobalTarget) {
+ this->GlobalInitializer->AddToGlobalAutoGen(this->LocalGen,
+ this->AutogenTarget.Name);
+ }
+ }
+
+ return true;
+}
+
+bool cmQtAutoGenInitializer::InitRccTargets()
+{
+ for (Qrc const& qrc : this->Rcc.Qrcs) {
+ // Register info file as generated by CMake
+ this->Makefile->AddCMakeOutputFile(qrc.InfoFile);
+ // Register file at target
+ {
+ cmSourceFile* sf = this->AddGeneratedSource(qrc.OutputFile, this->Rcc);
+ sf->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "On");
+ }
+
+ std::vector<std::string> ccOutput;
+ ccOutput.push_back(qrc.OutputFile);
+
+ std::vector<std::string> ccDepends;
+ // Add the .qrc and info file to the custom command dependencies
+ ccDepends.push_back(qrc.QrcFile);
+ ccDepends.push_back(qrc.InfoFile);
+
+ bool stdPipesUTF8 = true;
+ cmCustomCommandLines commandLines;
+ if (this->MultiConfig) {
+ // Build for all configurations
+ for (std::string const& config : this->ConfigsList) {
+ commandLines.push_back(
+ cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E",
+ "cmake_autorcc", qrc.InfoFile, config }));
+ }
+ } else {
+ commandLines.push_back(
+ cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E",
+ "cmake_autorcc", qrc.InfoFile, "$<CONFIG>" }));
+ }
+ std::string ccComment =
+ cmStrCat("Automatic RCC for ",
+ FileProjectRelativePath(this->Makefile, qrc.QrcFile));
+
+ if (qrc.Generated || this->Rcc.GlobalTarget) {
+ // Create custom rcc target
+ std::string ccName;
+ {
+ ccName = cmStrCat(this->GenTarget->GetName(), "_arcc_", qrc.QrcName);
+ if (!qrc.Unique) {
+ ccName += cmStrCat('_', qrc.QrcPathChecksum);
+ }
+
+ cmTarget* autoRccTarget = this->LocalGen->AddUtilityCommand(
+ ccName, true, this->Dir.Work.c_str(), ccOutput, ccDepends,
+ commandLines, cmPolicies::NEW, false, ccComment.c_str(), false,
+ false, "", stdPipesUTF8);
+
+ // Create autogen generator target
+ this->LocalGen->AddGeneratorTarget(
+ cm::make_unique<cmGeneratorTarget>(autoRccTarget, this->LocalGen));
+
+ // Set FOLDER property in autogen target
+ if (!this->TargetsFolder.empty()) {
+ autoRccTarget->SetProperty("FOLDER", this->TargetsFolder);
+ }
+ if (!this->Rcc.ExecutableTargetName.empty()) {
+ autoRccTarget->AddUtility(this->Rcc.ExecutableTargetName, false,
+ this->Makefile);
+ }
+ }
+ // Add autogen target to the origin target dependencies
+ this->GenTarget->Target->AddUtility(ccName, false, this->Makefile);
+
+ // Add autogen target to the global autogen target dependencies
+ if (this->Rcc.GlobalTarget) {
+ this->GlobalInitializer->AddToGlobalAutoRcc(this->LocalGen, ccName);
+ }
+ } else {
+ // Create custom rcc command
+ {
+ std::vector<std::string> ccByproducts;
+
+ // Add the resource files to the dependencies
+ for (std::string const& fileName : qrc.Resources) {
+ // Add resource file to the custom command dependencies
+ ccDepends.push_back(fileName);
+ }
+ if (!this->Rcc.ExecutableTargetName.empty()) {
+ ccDepends.push_back(this->Rcc.ExecutableTargetName);
+ }
+ std::string no_main_dependency;
+ cmImplicitDependsList no_implicit_depends;
+ this->LocalGen->AddCustomCommandToOutput(
+ ccOutput, ccByproducts, ccDepends, no_main_dependency,
+ no_implicit_depends, commandLines, ccComment.c_str(),
+ this->Dir.Work.c_str(), cmPolicies::NEW, false, true, false, false,
+ "", "", stdPipesUTF8);
+ }
+ // Reconfigure when .qrc file changes
+ this->Makefile->AddCMakeDependFile(qrc.QrcFile);
+ }
+ }
+
+ return true;
+}
+
+bool cmQtAutoGenInitializer::SetupCustomTargets()
+{
+ // Create info directory on demand
+ if (!cmSystemTools::MakeDirectory(this->Dir.Info)) {
+ cmSystemTools::Error(cmStrCat("AutoGen: Could not create directory: ",
+ Quoted(this->Dir.Info)));
+ return false;
+ }
+
+ // Generate autogen target info file
+ if (this->MocOrUicEnabled()) {
+ // Write autogen target info files
+ if (!this->SetupWriteAutogenInfo()) {
+ return false;
+ }
+ }
+
+ // Write AUTORCC info files
+ return !this->Rcc.Enabled || this->SetupWriteRccInfo();
+}
+
+bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
+{
+ // Utility lambdas
+ auto MfDef = [this](std::string const& key) {
+ return this->Makefile->GetSafeDefinition(key);
+ };
+
+ // Filtered headers and sources
+ std::set<std::string> moc_skip;
+ std::set<std::string> uic_skip;
+ std::vector<MUFile const*> headers;
+ std::vector<MUFile const*> sources;
+
+ // Filter headers
+ {
+ headers.reserve(this->AutogenTarget.Headers.size());
+ for (auto const& pair : this->AutogenTarget.Headers) {
+ MUFile const* const muf = pair.second.get();
+ if (muf->SkipMoc) {
+ moc_skip.insert(muf->FullPath);
+ }
+ if (muf->SkipUic) {
+ uic_skip.insert(muf->FullPath);
+ }
+ if (muf->Generated && !this->CMP0071Accept) {
+ continue;
+ }
+ if (muf->MocIt || muf->UicIt) {
+ headers.emplace_back(muf);
+ }
+ }
+ std::sort(headers.begin(), headers.end(),
+ [](MUFile const* a, MUFile const* b) {
+ return (a->FullPath < b->FullPath);
+ });
+ }
+
+ // Filter sources
+ {
+ sources.reserve(this->AutogenTarget.Sources.size());
+ for (auto const& pair : this->AutogenTarget.Sources) {
+ MUFile const* const muf = pair.second.get();
+ if (muf->Generated && !this->CMP0071Accept) {
+ continue;
+ }
+ if (muf->SkipMoc) {
+ moc_skip.insert(muf->FullPath);
+ }
+ if (muf->SkipUic) {
+ uic_skip.insert(muf->FullPath);
+ }
+ if (muf->MocIt || muf->UicIt) {
+ sources.emplace_back(muf);
+ }
+ }
+ std::sort(sources.begin(), sources.end(),
+ [](MUFile const* a, MUFile const* b) {
+ return (a->FullPath < b->FullPath);
+ });
+ }
+
+ // Info writer
+ InfoWriter info;
+
+ // General
+ info.SetBool("MULTI_CONFIG", this->MultiConfig);
+ info.SetUInt("PARALLEL", this->AutogenTarget.Parallel);
+ info.SetUInt("VERBOSITY", this->Verbosity);
+
+ // Directories
+ info.Set("CMAKE_SOURCE_DIR", MfDef("CMAKE_SOURCE_DIR"));
+ info.Set("CMAKE_BINARY_DIR", MfDef("CMAKE_BINARY_DIR"));
+ info.Set("CMAKE_CURRENT_SOURCE_DIR", MfDef("CMAKE_CURRENT_SOURCE_DIR"));
+ info.Set("CMAKE_CURRENT_BINARY_DIR", MfDef("CMAKE_CURRENT_BINARY_DIR"));
+ info.Set("BUILD_DIR", this->Dir.Build);
+ info.SetConfig("INCLUDE_DIR", this->Dir.Include);
+
+ info.SetUInt("QT_VERSION_MAJOR", this->QtVersion.Major);
+ info.SetUInt("QT_VERSION_MINOR", this->QtVersion.Minor);
+ info.Set("QT_MOC_EXECUTABLE", this->Moc.Executable);
+ info.Set("QT_UIC_EXECUTABLE", this->Uic.Executable);
+
+ info.Set("CMAKE_EXECUTABLE", cmSystemTools::GetCMakeCommand());
+ info.SetConfig("SETTINGS_FILE", this->AutogenTarget.SettingsFile);
+ info.SetConfig("PARSE_CACHE_FILE", this->AutogenTarget.ParseCacheFile);
+ info.Set("DEP_FILE", this->AutogenTarget.DepFile);
+ info.Set("DEP_FILE_RULE_NAME", this->AutogenTarget.DepFileRuleName);
+ info.SetArray("CMAKE_LIST_FILES", this->Makefile->GetListFiles());
+ info.SetArray("HEADER_EXTENSIONS",
+ this->Makefile->GetCMakeInstance()->GetHeaderExtensions());
+ auto cfgArray = [this](std::vector<size_t> const& configs) -> Json::Value {
+ Json::Value value;
+ if (!configs.empty()) {
+ value = Json::arrayValue;
+ for (size_t ci : configs) {
+ value.append(this->ConfigsList[ci]);
+ }
+ }
+ return value;
+ };
+ info.SetArrayArray("HEADERS", headers,
+ [this, &cfgArray](Json::Value& jval, MUFile const* muf) {
+ jval.resize(4u);
+ jval[0u] = muf->FullPath;
+ jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm',
+ muf->UicIt ? 'U' : 'u');
+ jval[2u] = this->GetMocBuildPath(*muf);
+ jval[3u] = cfgArray(muf->Configs);
+ });
+ info.SetArrayArray(
+ "SOURCES", sources, [&cfgArray](Json::Value& jval, MUFile const* muf) {
+ jval.resize(3u);
+ jval[0u] = muf->FullPath;
+ jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm', muf->UicIt ? 'U' : 'u');
+ jval[2u] = cfgArray(muf->Configs);
+ });
+
+ // Write moc settings
+ if (this->Moc.Enabled) {
+ info.SetArray("MOC_SKIP", moc_skip);
+ info.SetConfigArray("MOC_DEFINITIONS", this->Moc.Defines);
+ info.SetConfigArray("MOC_INCLUDES", this->Moc.Includes);
+ info.SetArray("MOC_OPTIONS", this->Moc.Options);
+ info.SetBool("MOC_RELAXED_MODE", this->Moc.RelaxedMode);
+ info.SetBool("MOC_PATH_PREFIX", this->Moc.PathPrefix);
+ info.SetArray("MOC_MACRO_NAMES", this->Moc.MacroNames);
+ info.SetArrayArray(
+ "MOC_DEPEND_FILTERS", this->Moc.DependFilters,
+ [](Json::Value& jval, std::pair<std::string, std::string> const& pair) {
+ jval.resize(2u);
+ jval[0u] = pair.first;
+ jval[1u] = pair.second;
+ });
+ info.SetConfig("MOC_COMPILATION_FILE", this->Moc.CompilationFile);
+ info.SetArray("MOC_PREDEFS_CMD", this->Moc.PredefsCmd);
+ info.SetConfig("MOC_PREDEFS_FILE", this->Moc.PredefsFile);
+ }
+
+ // Write uic settings
+ if (this->Uic.Enabled) {
+ // Add skipped .ui files
+ uic_skip.insert(this->Uic.SkipUi.begin(), this->Uic.SkipUi.end());
+
+ info.SetArray("UIC_SKIP", uic_skip);
+ info.SetArrayArray("UIC_UI_FILES", this->Uic.UiFilesWithOptions,
+ [](Json::Value& jval, UicT::UiFileT const& uiFile) {
+ jval.resize(2u);
+ jval[0u] = uiFile.first;
+ InfoWriter::MakeStringArray(jval[1u], uiFile.second);
+ });
+ info.SetConfigArray("UIC_OPTIONS", this->Uic.Options);
+ info.SetArray("UIC_SEARCH_PATHS", this->Uic.SearchPaths);
+ }
+
+ info.Save(this->AutogenTarget.InfoFile);
+
+ return true;
+}
+
+bool cmQtAutoGenInitializer::SetupWriteRccInfo()
+{
+ for (Qrc const& qrc : this->Rcc.Qrcs) {
+ // Utility lambdas
+ auto MfDef = [this](std::string const& key) {
+ return this->Makefile->GetSafeDefinition(key);
+ };
+
+ InfoWriter info;
+
+ // General
+ info.SetBool("MULTI_CONFIG", this->MultiConfig);
+ info.SetUInt("VERBOSITY", this->Verbosity);
+
+ // Files
+ info.Set("LOCK_FILE", qrc.LockFile);
+ info.SetConfig("SETTINGS_FILE", qrc.SettingsFile);
+
+ // Directories
+ info.Set("CMAKE_SOURCE_DIR", MfDef("CMAKE_SOURCE_DIR"));
+ info.Set("CMAKE_BINARY_DIR", MfDef("CMAKE_BINARY_DIR"));
+ info.Set("CMAKE_CURRENT_SOURCE_DIR", MfDef("CMAKE_CURRENT_SOURCE_DIR"));
+ info.Set("CMAKE_CURRENT_BINARY_DIR", MfDef("CMAKE_CURRENT_BINARY_DIR"));
+ info.Set("BUILD_DIR", this->Dir.Build);
+ info.SetConfig("INCLUDE_DIR", this->Dir.Include);
+
+ // rcc executable
+ info.Set("RCC_EXECUTABLE", this->Rcc.Executable);
+ info.SetArray("RCC_LIST_OPTIONS",
+ this->Rcc.ExecutableFeatures->ListOptions);
+
+ // qrc file
+ info.Set("SOURCE", qrc.QrcFile);
+ info.Set("OUTPUT_CHECKSUM", qrc.QrcPathChecksum);
+ info.Set("OUTPUT_NAME", cmSystemTools::GetFilenameName(qrc.OutputFile));
+ info.SetArray("OPTIONS", qrc.Options);
+ info.SetArray("INPUTS", qrc.Resources);
+
+ info.Save(qrc.InfoFile);
+ }
+
+ return true;
+}
+
+cmSourceFile* cmQtAutoGenInitializer::RegisterGeneratedSource(
+ std::string const& filename)
+{
+ cmSourceFile* gFile = this->Makefile->GetOrCreateSource(filename, true);
+ gFile->MarkAsGenerated();
+ gFile->SetProperty("SKIP_AUTOGEN", "1");
+ return gFile;
+}
+
+cmSourceFile* cmQtAutoGenInitializer::AddGeneratedSource(
+ std::string const& filename, GenVarsT const& genVars, bool prepend)
+{
+ // Register source at makefile
+ cmSourceFile* gFile = this->RegisterGeneratedSource(filename);
+ // Add source file to target
+ this->GenTarget->AddSource(filename, prepend);
+
+ // Add source file to source group
+ this->AddToSourceGroup(filename, genVars.GenNameUpper);
+
+ return gFile;
+}
+
+void cmQtAutoGenInitializer::AddGeneratedSource(ConfigString const& filename,
+ GenVarsT const& genVars,
+ bool prepend)
+{
+ // XXX(xcode-per-cfg-src): Drop the Xcode-specific part of the condition
+ // when the Xcode generator supports per-config sources.
+ if (!this->MultiConfig || this->GlobalGen->IsXcode()) {
+ this->AddGeneratedSource(filename.Default, genVars, prepend);
+ return;
+ }
+ for (auto const& cfg : this->ConfigsList) {
+ std::string const& filenameCfg = filename.Config.at(cfg);
+ // Register source at makefile
+ this->RegisterGeneratedSource(filenameCfg);
+ // Add source file to target for this configuration.
+ this->GenTarget->AddSource(
+ cmStrCat("$<$<CONFIG:"_s, cfg, ">:"_s, filenameCfg, ">"_s), prepend);
+ // Add source file to source group
+ this->AddToSourceGroup(filenameCfg, genVars.GenNameUpper);
+ }
+}
+
+void cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName,
+ cm::string_view genNameUpper)
+{
+ cmSourceGroup* sourceGroup = nullptr;
+ // Acquire source group
+ {
+ std::string property;
+ std::string groupName;
+ {
+ // Prefer generator specific source group name
+ std::initializer_list<std::string> const props{
+ cmStrCat(genNameUpper, "_SOURCE_GROUP"), "AUTOGEN_SOURCE_GROUP"
+ };
+ for (std::string const& prop : props) {
+ cmProp propName = this->Makefile->GetState()->GetGlobalProperty(prop);
+ if (cmNonempty(propName)) {
+ groupName = *propName;
+ property = prop;
+ break;
+ }
+ }
+ }
+ // Generate a source group on demand
+ if (!groupName.empty()) {
+ sourceGroup = this->Makefile->GetOrCreateSourceGroup(groupName);
+ if (sourceGroup == nullptr) {
+ cmSystemTools::Error(
+ cmStrCat(genNameUpper, " error in ", property,
+ ": Could not find or create the source group ",
+ cmQtAutoGen::Quoted(groupName)));
+ }
+ }
+ }
+ if (sourceGroup != nullptr) {
+ sourceGroup->AddGroupFile(fileName);
+ }
+}
+
+void cmQtAutoGenInitializer::AddCleanFile(std::string const& fileName)
+{
+ this->GenTarget->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", fileName,
+ false);
+}
+
+void cmQtAutoGenInitializer::ConfigFileNames(ConfigString& configString,
+ cm::string_view prefix,
+ cm::string_view suffix)
+{
+ configString.Default = cmStrCat(prefix, suffix);
+ if (this->MultiConfig) {
+ for (auto const& cfg : this->ConfigsList) {
+ configString.Config[cfg] = cmStrCat(prefix, '_', cfg, suffix);
+ }
+ }
+}
+
+void cmQtAutoGenInitializer::ConfigFileNamesAndGenex(
+ ConfigString& configString, std::string& genex, cm::string_view const prefix,
+ cm::string_view const suffix)
+{
+ this->ConfigFileNames(configString, prefix, suffix);
+ if (this->MultiConfig) {
+ genex = cmStrCat(prefix, "_$<CONFIG>"_s, suffix);
+ } else {
+ genex = configString.Default;
+ }
+}
+
+void cmQtAutoGenInitializer::ConfigFileClean(ConfigString& configString)
+{
+ this->AddCleanFile(configString.Default);
+ if (this->MultiConfig) {
+ for (auto const& pair : configString.Config) {
+ this->AddCleanFile(pair.second);
+ }
+ }
+}
+
+std::pair<cmQtAutoGen::IntegerVersion, unsigned int>
+cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target)
+{
+ // Converts a char ptr to an unsigned int value
+ auto toUInt = [](const char* const input) -> unsigned int {
+ unsigned long tmp = 0;
+ if (input != nullptr && cmStrToULong(input, &tmp)) {
+ return static_cast<unsigned int>(tmp);
+ }
+ return 0u;
+ };
+ auto toUInt2 = [](cmProp input) -> unsigned int {
+ unsigned long tmp = 0;
+ if (input != nullptr && cmStrToULong(*input, &tmp)) {
+ return static_cast<unsigned int>(tmp);
+ }
+ return 0u;
+ };
+
+ // Initialize return value to a default
+ std::pair<IntegerVersion, unsigned int> res(
+ IntegerVersion(),
+ toUInt(target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION",
+ "")));
+
+ // Acquire known Qt versions
+ std::vector<cmQtAutoGen::IntegerVersion> knownQtVersions;
+ {
+ // Qt version variable prefixes
+ static std::initializer_list<
+ std::pair<cm::string_view, cm::string_view>> const keys{
+ { "Qt6Core_VERSION_MAJOR", "Qt6Core_VERSION_MINOR" },
+ { "Qt5Core_VERSION_MAJOR", "Qt5Core_VERSION_MINOR" },
+ { "QT_VERSION_MAJOR", "QT_VERSION_MINOR" },
+ };
+
+ knownQtVersions.reserve(keys.size() * 2);
+
+ // Adds a version to the result (nullptr safe)
+ auto addVersion = [&knownQtVersions, &toUInt2](cmProp major,
+ cmProp minor) {
+ cmQtAutoGen::IntegerVersion ver(toUInt2(major), toUInt2(minor));
+ if (ver.Major != 0) {
+ knownQtVersions.emplace_back(ver);
+ }
+ };
+
+ // Read versions from variables
+ for (auto const& keyPair : keys) {
+ addVersion(target->Makefile->GetDefinition(std::string(keyPair.first)),
+ target->Makefile->GetDefinition(std::string(keyPair.second)));
+ }
+
+ // Read versions from directory properties
+ for (auto const& keyPair : keys) {
+ addVersion(target->Makefile->GetProperty(std::string(keyPair.first)),
+ target->Makefile->GetProperty(std::string(keyPair.second)));
+ }
+ }
+
+ // Evaluate known Qt versions
+ if (!knownQtVersions.empty()) {
+ if (res.second == 0) {
+ // No specific version was requested by the target:
+ // Use highest known Qt version.
+ res.first = knownQtVersions.at(0);
+ } else {
+ // Pick a version from the known versions:
+ for (auto it : knownQtVersions) {
+ if (it.Major == res.second) {
+ res.first = it;
+ break;
+ }
+ }
+ }
+ }
+ return res;
+}
+
+std::string cmQtAutoGenInitializer::GetMocBuildPath(MUFile const& muf)
+{
+ std::string res;
+ if (!muf.MocIt) {
+ return res;
+ }
+
+ std::string basePath =
+ cmStrCat(this->PathCheckSum.getPart(muf.FullPath), "/moc_",
+ FileNameWithoutLastExtension(muf.FullPath));
+
+ res = cmStrCat(basePath, ".cpp");
+ if (this->Moc.EmittedBuildPaths.emplace(res).second) {
+ return res;
+ }
+
+ // File name already emitted.
+ // Try appending the header suffix to the base path.
+ basePath = cmStrCat(basePath, '_', muf.SF->GetExtension());
+ res = cmStrCat(basePath, ".cpp");
+ if (this->Moc.EmittedBuildPaths.emplace(res).second) {
+ return res;
+ }
+
+ // File name with header extension already emitted.
+ // Try adding a number to the base path.
+ constexpr std::size_t number_begin = 2;
+ constexpr std::size_t number_end = 256;
+ for (std::size_t ii = number_begin; ii != number_end; ++ii) {
+ res = cmStrCat(basePath, '_', ii, ".cpp");
+ if (this->Moc.EmittedBuildPaths.emplace(res).second) {
+ return res;
+ }
+ }
+
+ // Output file name conflict (unlikely, but still...)
+ cmSystemTools::Error(
+ cmStrCat("moc output file name conflict for ", muf.FullPath));
+
+ return res;
+}
+
+bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
+ const std::string& executable,
+ bool ignoreMissingTarget) const
+{
+ auto print_err = [this, &genVars](std::string const& err) {
+ cmSystemTools::Error(cmStrCat(genVars.GenNameUpper, " for target ",
+ this->GenTarget->GetName(), ": ", err));
+ };
+
+ // Custom executable
+ {
+ std::string const prop = cmStrCat(genVars.GenNameUpper, "_EXECUTABLE");
+ std::string const& val = this->GenTarget->Target->GetSafeProperty(prop);
+ if (!val.empty()) {
+ // Evaluate generator expression
+ {
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ cmGeneratorExpression ge(lfbt);
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(val);
+ genVars.Executable = cge->Evaluate(this->LocalGen, "");
+ }
+ if (genVars.Executable.empty() && !ignoreMissingTarget) {
+ print_err(prop + " evaluates to an empty value");
+ return false;
+ }
+
+ // Create empty compiler features.
+ genVars.ExecutableFeatures =
+ std::make_shared<cmQtAutoGen::CompilerFeatures>();
+ return true;
+ }
+ }
+
+ // Find executable target
+ {
+ // Find executable target name
+ cm::string_view prefix;
+ if (this->QtVersion.Major == 4) {
+ prefix = "Qt4::";
+ } else if (this->QtVersion.Major == 5) {
+ prefix = "Qt5::";
+ } else if (this->QtVersion.Major == 6) {
+ prefix = "Qt6::";
+ }
+ std::string const targetName = cmStrCat(prefix, executable);
+
+ // Find target
+ cmGeneratorTarget* genTarget =
+ this->LocalGen->FindGeneratorTargetToUse(targetName);
+ if (genTarget != nullptr) {
+ genVars.ExecutableTargetName = targetName;
+ genVars.ExecutableTarget = genTarget;
+ if (genTarget->IsImported()) {
+ genVars.Executable = genTarget->ImportedGetLocation("");
+ } else {
+ genVars.Executable = genTarget->GetLocation("");
+ }
+ } else {
+ if (ignoreMissingTarget) {
+ // Create empty compiler features.
+ genVars.ExecutableFeatures =
+ std::make_shared<cmQtAutoGen::CompilerFeatures>();
+ return true;
+ }
+ print_err(cmStrCat("Could not find ", executable, " executable target ",
+ targetName));
+ return false;
+ }
+ }
+
+ // Get executable features
+ {
+ std::string err;
+ genVars.ExecutableFeatures = this->GlobalInitializer->GetCompilerFeatures(
+ executable, genVars.Executable, err);
+ if (!genVars.ExecutableFeatures) {
+ print_err(err);
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h
new file mode 100644
index 0000000..8a6d8f9
--- /dev/null
+++ b/Source/cmQtAutoGenInitializer.h
@@ -0,0 +1,258 @@
+/* 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 <cstddef>
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmFilePathChecksum.h"
+#include "cmQtAutoGen.h"
+
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmLocalGenerator;
+class cmMakefile;
+class cmQtAutoGenGlobalInitializer;
+class cmSourceFile;
+class cmTarget;
+
+/** \class cmQtAutoGenerator
+ * \brief Initializes the QtAutoGen generators
+ */
+class cmQtAutoGenInitializer : public cmQtAutoGen
+{
+public:
+ /** String value with per configuration variants. */
+ class ConfigString
+ {
+ public:
+ std::string Default;
+ std::unordered_map<std::string, std::string> Config;
+ };
+
+ /** String values with per configuration variants. */
+ template <typename C>
+ class ConfigStrings
+ {
+ public:
+ C Default;
+ std::unordered_map<std::string, C> Config;
+ };
+
+ /** rcc job. */
+ class Qrc
+ {
+ public:
+ std::string LockFile;
+ std::string QrcFile;
+ std::string QrcName;
+ std::string QrcPathChecksum;
+ std::string InfoFile;
+ ConfigString SettingsFile;
+ std::string OutputFile;
+ bool Generated = false;
+ bool Unique = false;
+ std::vector<std::string> Options;
+ std::vector<std::string> Resources;
+ };
+
+ /** moc and/or uic file. */
+ struct MUFile
+ {
+ std::string FullPath;
+ cmSourceFile* SF = nullptr;
+ std::vector<size_t> Configs;
+ bool Generated = false;
+ bool SkipMoc = false;
+ bool SkipUic = false;
+ bool MocIt = false;
+ bool UicIt = false;
+ };
+ using MUFileHandle = std::unique_ptr<MUFile>;
+
+ /** Abstract moc/uic/rcc generator variables base class. */
+ struct GenVarsT
+ {
+ bool Enabled = false;
+ // Generator type/name
+ GenT Gen;
+ cm::string_view GenNameUpper;
+ // Executable
+ std::string ExecutableTargetName;
+ cmGeneratorTarget* ExecutableTarget = nullptr;
+ std::string Executable;
+ CompilerFeaturesHandle ExecutableFeatures;
+
+ GenVarsT(GenT gen)
+ : Gen(gen)
+ , GenNameUpper(cmQtAutoGen::GeneratorNameUpper(gen)){};
+ };
+
+ /** @return The detected Qt version and the required Qt major version. */
+ static std::pair<IntegerVersion, unsigned int> GetQtVersion(
+ cmGeneratorTarget const* genTarget);
+
+ cmQtAutoGenInitializer(cmQtAutoGenGlobalInitializer* globalInitializer,
+ cmGeneratorTarget* genTarget,
+ IntegerVersion const& qtVersion, bool mocEnabled,
+ bool uicEnabled, bool rccEnabled,
+ bool globalAutogenTarget, bool globalAutoRccTarget);
+
+ bool InitCustomTargets();
+ bool SetupCustomTargets();
+
+private:
+ /** If moc or uic is enabled, the autogen target will be generated. */
+ bool MocOrUicEnabled() const
+ {
+ return (this->Moc.Enabled || this->Uic.Enabled);
+ }
+
+ bool InitMoc();
+ bool InitUic();
+ bool InitRcc();
+
+ bool InitScanFiles();
+ bool InitAutogenTarget();
+ bool InitRccTargets();
+
+ bool SetupWriteAutogenInfo();
+ bool SetupWriteRccInfo();
+
+ cmSourceFile* RegisterGeneratedSource(std::string const& filename);
+ cmSourceFile* AddGeneratedSource(std::string const& filename,
+ GenVarsT const& genVars,
+ bool prepend = false);
+ void AddGeneratedSource(ConfigString const& filename,
+ GenVarsT const& genVars, bool prepend = false);
+ void AddToSourceGroup(std::string const& fileName,
+ cm::string_view genNameUpper);
+ void AddCleanFile(std::string const& fileName);
+
+ void ConfigFileNames(ConfigString& configString, cm::string_view prefix,
+ cm::string_view suffix);
+ void ConfigFileNamesAndGenex(ConfigString& configString, std::string& genex,
+ cm::string_view prefix, cm::string_view suffix);
+ void ConfigFileClean(ConfigString& configString);
+
+ std::string GetMocBuildPath(MUFile const& muf);
+
+ bool GetQtExecutable(GenVarsT& genVars, const std::string& executable,
+ bool ignoreMissingTarget) const;
+
+ cmQtAutoGenGlobalInitializer* GlobalInitializer = nullptr;
+ cmGeneratorTarget* GenTarget = nullptr;
+ cmGlobalGenerator* GlobalGen = nullptr;
+ cmLocalGenerator* LocalGen = nullptr;
+ cmMakefile* Makefile = nullptr;
+ cmFilePathChecksum const PathCheckSum;
+
+ // -- Configuration
+ IntegerVersion QtVersion;
+ unsigned int Verbosity = 0;
+ bool MultiConfig = false;
+ bool CMP0071Accept = false;
+ bool CMP0071Warn = false;
+ bool CMP0100Accept = false;
+ bool CMP0100Warn = false;
+ std::string ConfigDefault;
+ std::vector<std::string> ConfigsList;
+ std::string TargetsFolder;
+
+ /** Common directories. */
+ struct
+ {
+ std::string Info;
+ std::string Build;
+ std::string Work;
+ ConfigString Include;
+ std::string IncludeGenExp;
+ } Dir;
+
+ /** Autogen target variables. */
+ struct
+ {
+ std::string Name;
+ bool GlobalTarget = false;
+ // Settings
+ unsigned int Parallel = 1;
+ // Configuration files
+ std::string InfoFile;
+ ConfigString SettingsFile;
+ ConfigString ParseCacheFile;
+ // Dependencies
+ bool DependOrigin = false;
+ std::set<std::string> DependFiles;
+ std::set<cmTarget*> DependTargets;
+ std::string DepFile;
+ std::string DepFileRuleName;
+ // Sources to process
+ std::unordered_map<cmSourceFile*, MUFileHandle> Headers;
+ std::unordered_map<cmSourceFile*, MUFileHandle> Sources;
+ std::vector<MUFile*> FilesGenerated;
+ std::vector<cmSourceFile*> CMP0100HeadersWarn;
+ } AutogenTarget;
+
+ /** moc variables. */
+ struct MocT : public GenVarsT
+ {
+ MocT()
+ : GenVarsT(GenT::MOC){};
+
+ bool RelaxedMode = false;
+ bool PathPrefix = false;
+ ConfigString CompilationFile;
+ std::string CompilationFileGenex;
+ // Compiler implicit pre defines
+ std::vector<std::string> PredefsCmd;
+ ConfigString PredefsFile;
+ // Defines
+ ConfigStrings<std::set<std::string>> Defines;
+ // Includes
+ ConfigStrings<std::vector<std::string>> Includes;
+ // Options
+ std::vector<std::string> Options;
+ // Filters
+ std::vector<std::string> MacroNames;
+ std::vector<std::pair<std::string, std::string>> DependFilters;
+ // Utility
+ std::unordered_set<std::string> EmittedBuildPaths;
+ } Moc;
+
+ /** uic variables. */
+ struct UicT : public GenVarsT
+ {
+ using UiFileT = std::pair<std::string, std::vector<std::string>>;
+
+ UicT()
+ : GenVarsT(GenT::UIC){};
+
+ std::set<std::string> SkipUi;
+ std::vector<std::string> UiFilesNoOptions;
+ std::vector<UiFileT> UiFilesWithOptions;
+ ConfigStrings<std::vector<std::string>> Options;
+ std::vector<std::string> SearchPaths;
+ std::vector<std::pair<ConfigString /*ui header*/, std::string /*genex*/>>
+ UiHeaders;
+ } Uic;
+
+ /** rcc variables. */
+ struct RccT : public GenVarsT
+ {
+ RccT()
+ : GenVarsT(GenT::RCC){};
+
+ bool GlobalTarget = false;
+ std::vector<Qrc> Qrcs;
+ } Rcc;
+};
diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx
new file mode 100644
index 0000000..6e88e26
--- /dev/null
+++ b/Source/cmQtAutoGenerator.cxx
@@ -0,0 +1,495 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmQtAutoGenerator.h"
+
+#include <cm3p/json/reader.h>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmQtAutoGen.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmQtAutoGenerator::Logger::Logger()
+{
+ // Initialize logger
+ {
+ std::string verbose;
+ if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) {
+ unsigned long iVerbose = 0;
+ if (cmStrToULong(verbose, &iVerbose)) {
+ this->SetVerbosity(static_cast<unsigned int>(iVerbose));
+ } else {
+ // Non numeric verbosity
+ this->SetVerbose(cmIsOn(verbose));
+ }
+ }
+ }
+ {
+ std::string colorEnv;
+ cmSystemTools::GetEnv("COLOR", colorEnv);
+ if (!colorEnv.empty()) {
+ this->SetColorOutput(cmIsOn(colorEnv));
+ } else {
+ this->SetColorOutput(true);
+ }
+ }
+}
+
+void cmQtAutoGenerator::Logger::RaiseVerbosity(unsigned int value)
+{
+ if (this->Verbosity_ < value) {
+ this->Verbosity_ = value;
+ }
+}
+
+void cmQtAutoGenerator::Logger::SetColorOutput(bool value)
+{
+ this->ColorOutput_ = value;
+}
+
+std::string cmQtAutoGenerator::Logger::HeadLine(cm::string_view title)
+{
+ return cmStrCat(title, '\n', std::string(title.size(), '-'), '\n');
+}
+
+void cmQtAutoGenerator::Logger::Info(GenT genType,
+ cm::string_view message) const
+{
+ std::string msg = cmStrCat(GeneratorName(genType), ": ", message,
+ cmHasSuffix(message, '\n') ? "" : "\n");
+ {
+ std::lock_guard<std::mutex> lock(this->Mutex_);
+ cmSystemTools::Stdout(msg);
+ }
+}
+
+void cmQtAutoGenerator::Logger::Warning(GenT genType,
+ cm::string_view message) const
+{
+ std::string msg;
+ if (message.find('\n') == std::string::npos) {
+ // Single line message
+ msg = cmStrCat(GeneratorName(genType), " warning: ", message,
+ cmHasSuffix(message, '\n') ? "\n" : "\n\n");
+ } else {
+ // Multi line message
+ msg = cmStrCat(HeadLine(cmStrCat(GeneratorName(genType), " warning")),
+ message, cmHasSuffix(message, '\n') ? "\n" : "\n\n");
+ }
+ {
+ std::lock_guard<std::mutex> lock(this->Mutex_);
+ cmSystemTools::Stdout(msg);
+ }
+}
+
+void cmQtAutoGenerator::Logger::Error(GenT genType,
+ cm::string_view message) const
+{
+ std::string msg =
+ cmStrCat('\n', HeadLine(cmStrCat(GeneratorName(genType), " error")),
+ message, cmHasSuffix(message, '\n') ? "\n" : "\n\n");
+ {
+ std::lock_guard<std::mutex> lock(this->Mutex_);
+ cmSystemTools::Stderr(msg);
+ }
+}
+
+void cmQtAutoGenerator::Logger::ErrorCommand(
+ GenT genType, cm::string_view message,
+ std::vector<std::string> const& command, std::string const& output) const
+{
+ std::string msg = cmStrCat(
+ '\n', HeadLine(cmStrCat(GeneratorName(genType), " subprocess error")),
+ message, cmHasSuffix(message, '\n') ? "\n" : "\n\n");
+ msg += cmStrCat(HeadLine("Command"), QuotedCommand(command), "\n\n");
+ msg += cmStrCat(HeadLine("Output"), output,
+ cmHasSuffix(output, '\n') ? "\n" : "\n\n");
+ {
+ std::lock_guard<std::mutex> lock(this->Mutex_);
+ cmSystemTools::Stderr(msg);
+ }
+}
+
+bool cmQtAutoGenerator::MakeParentDirectory(std::string const& filename)
+{
+ bool success = true;
+ std::string const dirName = cmSystemTools::GetFilenamePath(filename);
+ if (!dirName.empty()) {
+ success = cmSystemTools::MakeDirectory(dirName);
+ }
+ return success;
+}
+
+bool cmQtAutoGenerator::FileRead(std::string& content,
+ std::string const& filename,
+ std::string* error)
+{
+ content.clear();
+ if (!cmSystemTools::FileExists(filename, true)) {
+ if (error != nullptr) {
+ *error = "Not a file.";
+ }
+ return false;
+ }
+
+ unsigned long const length = cmSystemTools::FileLength(filename);
+ cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
+
+ // Use lambda to save destructor calls of ifs
+ return [&ifs, length, &content, error]() -> bool {
+ if (!ifs) {
+ if (error != nullptr) {
+ *error = "Opening the file for reading failed.";
+ }
+ return false;
+ }
+ content.reserve(length);
+ using IsIt = std::istreambuf_iterator<char>;
+ content.assign(IsIt{ ifs }, IsIt{});
+ if (!ifs) {
+ content.clear();
+ if (error != nullptr) {
+ *error = "Reading from the file failed.";
+ }
+ return false;
+ }
+ return true;
+ }();
+}
+
+bool cmQtAutoGenerator::FileWrite(std::string const& filename,
+ std::string const& content,
+ std::string* error)
+{
+ // Make sure the parent directory exists
+ if (!cmQtAutoGenerator::MakeParentDirectory(filename)) {
+ if (error != nullptr) {
+ *error = "Could not create parent directory.";
+ }
+ return false;
+ }
+ cmsys::ofstream ofs;
+ ofs.open(filename.c_str(),
+ (std::ios::out | std::ios::binary | std::ios::trunc));
+
+ // Use lambda to save destructor calls of ofs
+ return [&ofs, &content, error]() -> bool {
+ if (!ofs) {
+ if (error != nullptr) {
+ *error = "Opening file for writing failed.";
+ }
+ return false;
+ }
+ ofs << content;
+ if (!ofs.good()) {
+ if (error != nullptr) {
+ *error = "File writing failed.";
+ }
+ return false;
+ }
+ return true;
+ }();
+}
+
+bool cmQtAutoGenerator::FileDiffers(std::string const& filename,
+ std::string const& content)
+{
+ bool differs = true;
+ std::string oldContents;
+ if (FileRead(oldContents, filename) && (oldContents == content)) {
+ differs = false;
+ }
+ return differs;
+}
+
+cmQtAutoGenerator::cmQtAutoGenerator(GenT genType)
+ : GenType_(genType)
+{
+}
+
+cmQtAutoGenerator::~cmQtAutoGenerator() = default;
+
+bool cmQtAutoGenerator::InfoT::Read(std::istream& istr)
+{
+ try {
+ istr >> this->Json_;
+ } catch (...) {
+ return false;
+ }
+ return true;
+}
+
+bool cmQtAutoGenerator::InfoT::GetJsonArray(std::vector<std::string>& list,
+ Json::Value const& jval)
+{
+ Json::ArrayIndex const arraySize = jval.size();
+ if (arraySize == 0) {
+ return false;
+ }
+
+ bool picked = false;
+ list.reserve(list.size() + arraySize);
+ for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) {
+ Json::Value const& ival = jval[ii];
+ if (ival.isString()) {
+ list.emplace_back(ival.asString());
+ picked = true;
+ }
+ }
+ return picked;
+}
+
+bool cmQtAutoGenerator::InfoT::GetJsonArray(
+ std::unordered_set<std::string>& list, Json::Value const& jval)
+{
+ Json::ArrayIndex const arraySize = jval.size();
+ if (arraySize == 0) {
+ return false;
+ }
+
+ bool picked = false;
+ list.reserve(list.size() + arraySize);
+ for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) {
+ Json::Value const& ival = jval[ii];
+ if (ival.isString()) {
+ list.emplace(ival.asString());
+ picked = true;
+ }
+ }
+ return picked;
+}
+
+std::string cmQtAutoGenerator::InfoT::ConfigKey(cm::string_view key) const
+{
+ return cmStrCat(key, '_', this->Gen_.InfoConfig());
+}
+
+bool cmQtAutoGenerator::InfoT::GetString(std::string const& key,
+ std::string& value,
+ bool required) const
+{
+ Json::Value const& jval = this->Json_[key];
+ if (!jval.isString()) {
+ if (!jval.isNull() || required) {
+ return this->LogError(cmStrCat(key, " is not a string."));
+ }
+ } else {
+ value = jval.asString();
+ if (value.empty() && required) {
+ return this->LogError(cmStrCat(key, " is empty."));
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoGenerator::InfoT::GetStringConfig(std::string const& key,
+ std::string& value,
+ bool required) const
+{
+ { // Try config
+ std::string const configKey = this->ConfigKey(key);
+ Json::Value const& jval = this->Json_[configKey];
+ if (!jval.isNull()) {
+ if (!jval.isString()) {
+ return this->LogError(cmStrCat(configKey, " is not a string."));
+ }
+ value = jval.asString();
+ if (required && value.empty()) {
+ return this->LogError(cmStrCat(configKey, " is empty."));
+ }
+ return true;
+ }
+ }
+ // Try plain
+ return this->GetString(key, value, required);
+}
+
+bool cmQtAutoGenerator::InfoT::GetBool(std::string const& key, bool& value,
+ bool required) const
+{
+ Json::Value const& jval = this->Json_[key];
+ if (jval.isBool()) {
+ value = jval.asBool();
+ } else {
+ if (!jval.isNull() || required) {
+ return this->LogError(cmStrCat(key, " is not a boolean."));
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoGenerator::InfoT::GetUInt(std::string const& key,
+ unsigned int& value,
+ bool required) const
+{
+ Json::Value const& jval = this->Json_[key];
+ if (jval.isUInt()) {
+ value = jval.asUInt();
+ } else {
+ if (!jval.isNull() || required) {
+ return this->LogError(cmStrCat(key, " is not an unsigned integer."));
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoGenerator::InfoT::GetArray(std::string const& key,
+ std::vector<std::string>& list,
+ bool required) const
+{
+ Json::Value const& jval = this->Json_[key];
+ if (!jval.isArray()) {
+ if (!jval.isNull() || required) {
+ return this->LogError(cmStrCat(key, " is not an array."));
+ }
+ }
+ return GetJsonArray(list, jval) || !required;
+}
+
+bool cmQtAutoGenerator::InfoT::GetArray(std::string const& key,
+ std::unordered_set<std::string>& list,
+ bool required) const
+{
+ Json::Value const& jval = this->Json_[key];
+ if (!jval.isArray()) {
+ if (!jval.isNull() || required) {
+ return this->LogError(cmStrCat(key, " is not an array."));
+ }
+ }
+ return GetJsonArray(list, jval) || !required;
+}
+
+bool cmQtAutoGenerator::InfoT::GetArrayConfig(std::string const& key,
+ std::vector<std::string>& list,
+ bool required) const
+{
+ { // Try config
+ std::string const configKey = this->ConfigKey(key);
+ Json::Value const& jval = this->Json_[configKey];
+ if (!jval.isNull()) {
+ if (!jval.isArray()) {
+ return this->LogError(cmStrCat(configKey, " is not an array string."));
+ }
+ if (!GetJsonArray(list, jval) && required) {
+ return this->LogError(cmStrCat(configKey, " is empty."));
+ }
+ return true;
+ }
+ }
+ // Try plain
+ return this->GetArray(key, list, required);
+}
+
+bool cmQtAutoGenerator::InfoT::LogError(GenT genType,
+ cm::string_view message) const
+{
+ this->Gen_.Log().Error(genType,
+ cmStrCat("Info error in info file\n",
+ Quoted(this->Gen_.InfoFile()), ":\n",
+ message));
+ return false;
+}
+
+bool cmQtAutoGenerator::InfoT::LogError(cm::string_view message) const
+{
+ return this->LogError(this->Gen_.GenType_, message);
+}
+
+std::string cmQtAutoGenerator::SettingsFind(cm::string_view content,
+ cm::string_view key)
+{
+ cm::string_view res;
+ std::string const prefix = cmStrCat(key, ':');
+ cm::string_view::size_type pos = content.find(prefix);
+ if (pos != cm::string_view::npos) {
+ pos += prefix.size();
+ if (pos < content.size()) {
+ cm::string_view::size_type posE = content.find('\n', pos);
+ if ((posE != cm::string_view::npos) && (posE != pos)) {
+ res = content.substr(pos, posE - pos);
+ }
+ }
+ }
+ return std::string(res);
+}
+
+std::string cmQtAutoGenerator::MessagePath(cm::string_view path) const
+{
+ std::string res;
+ if (cmHasPrefix(path, this->ProjectDirs().Source)) {
+ res = cmStrCat("SRC:", path.substr(this->ProjectDirs().Source.size()));
+ } else if (cmHasPrefix(path, this->ProjectDirs().Binary)) {
+ res = cmStrCat("BIN:", path.substr(this->ProjectDirs().Binary.size()));
+ } else {
+ res = std::string(path);
+ }
+ return cmQtAutoGen::Quoted(res);
+}
+
+bool cmQtAutoGenerator::Run(cm::string_view infoFile, cm::string_view config)
+{
+ // Info config
+ this->InfoConfig_ = std::string(config);
+
+ // Info file
+ this->InfoFile_ = std::string(infoFile);
+ cmSystemTools::CollapseFullPath(this->InfoFile_);
+ this->InfoDir_ = cmSystemTools::GetFilenamePath(this->InfoFile_);
+
+ // Load info file time
+ if (!this->InfoFileTime_.Load(this->InfoFile_)) {
+ cmSystemTools::Stderr(cmStrCat("AutoGen: The info file ",
+ Quoted(this->InfoFile_),
+ " is not readable\n"));
+ return false;
+ }
+
+ {
+ InfoT info(*this);
+
+ // Read info file
+ {
+ cmsys::ifstream ifs(this->InfoFile_.c_str(),
+ (std::ios::in | std::ios::binary));
+ if (!ifs) {
+ this->Log().Error(
+ this->GenType_,
+ cmStrCat("Could not to open info file ", Quoted(this->InfoFile_)));
+ return false;
+ }
+ if (!info.Read(ifs)) {
+ this->Log().Error(
+ this->GenType_,
+ cmStrCat("Could not read info file ", Quoted(this->InfoFile_)));
+ return false;
+ }
+ }
+
+ // -- Read common info settings
+ {
+ unsigned int verbosity = 0;
+ // Info: setup project directories
+ if (!info.GetUInt("VERBOSITY", verbosity, false) ||
+ !info.GetString("CMAKE_SOURCE_DIR", this->ProjectDirs_.Source,
+ true) ||
+ !info.GetString("CMAKE_BINARY_DIR", this->ProjectDirs_.Binary,
+ true) ||
+ !info.GetString("CMAKE_CURRENT_SOURCE_DIR",
+ this->ProjectDirs_.CurrentSource, true) ||
+ !info.GetString("CMAKE_CURRENT_BINARY_DIR",
+ this->ProjectDirs_.CurrentBinary, true)) {
+ return false;
+ }
+ this->Logger_.RaiseVerbosity(verbosity);
+ }
+
+ // -- Call virtual init from info method.
+ if (!this->InitFromInfo(info)) {
+ return false;
+ }
+ }
+
+ // Call virtual process method.
+ return this->Process();
+}
diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h
new file mode 100644
index 0000000..5c3a8ad
--- /dev/null
+++ b/Source/cmQtAutoGenerator.h
@@ -0,0 +1,175 @@
+/* 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 <istream>
+#include <mutex>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include <cm/string_view>
+
+#include <cm3p/json/value.h>
+
+#include "cmFileTime.h"
+#include "cmQtAutoGen.h"
+
+/** \class cmQtAutoGenerator
+ * \brief Base class for QtAutoGen generators
+ */
+class cmQtAutoGenerator : public cmQtAutoGen
+{
+public:
+ // -- Types
+
+ /** Thread safe logger. */
+ class Logger
+ {
+ public:
+ // -- Construction
+ Logger();
+ ~Logger() = default;
+ // -- Verbosity
+ unsigned int Verbosity() const { return this->Verbosity_; }
+ void SetVerbosity(unsigned int value) { this->Verbosity_ = value; }
+ void RaiseVerbosity(unsigned int value);
+ bool Verbose() const { return (this->Verbosity_ != 0); }
+ void SetVerbose(bool value) { this->Verbosity_ = value ? 1 : 0; }
+ // -- Color output
+ bool ColorOutput() const { return this->ColorOutput_; }
+ void SetColorOutput(bool value);
+ // -- Log info
+ void Info(GenT genType, cm::string_view message) const;
+ // -- Log warning
+ void Warning(GenT genType, cm::string_view message) const;
+ // -- Log error
+ void Error(GenT genType, cm::string_view message) const;
+ void ErrorCommand(GenT genType, cm::string_view message,
+ std::vector<std::string> const& command,
+ std::string const& output) const;
+
+ private:
+ static std::string HeadLine(cm::string_view title);
+
+ mutable std::mutex Mutex_;
+ unsigned int Verbosity_ = 0;
+ bool ColorOutput_ = false;
+ };
+
+ /** Project directories. */
+ struct ProjectDirsT
+ {
+ std::string Source;
+ std::string Binary;
+ std::string CurrentSource;
+ std::string CurrentBinary;
+ };
+
+ // -- File system methods
+ static bool MakeParentDirectory(std::string const& filename);
+ static bool FileRead(std::string& content, std::string const& filename,
+ std::string* error = nullptr);
+ static bool FileWrite(std::string const& filename,
+ std::string const& content,
+ std::string* error = nullptr);
+ static bool FileDiffers(std::string const& filename,
+ std::string const& content);
+
+ // -- Constructors
+ cmQtAutoGenerator(GenT genType);
+ virtual ~cmQtAutoGenerator();
+
+ cmQtAutoGenerator(cmQtAutoGenerator const&) = delete;
+ cmQtAutoGenerator& operator=(cmQtAutoGenerator const&) = delete;
+
+ // -- Info options
+ std::string const& InfoFile() const { return this->InfoFile_; }
+ std::string const& InfoDir() const { return this->InfoDir_; }
+ cmFileTime const& InfoFileTime() const { return this->InfoFileTime_; }
+ std::string const& InfoConfig() const { return this->InfoConfig_; }
+
+ // -- Info file parsing
+ /** Info file reader class. */
+ class InfoT
+ {
+ public:
+ InfoT(cmQtAutoGenerator& gen)
+ : Gen_(gen)
+ {
+ }
+
+ /** Read json data from a stream. */
+ bool Read(std::istream& istr);
+
+ /** Returns false if the JSON value isn't a string. */
+ bool GetString(std::string const& key, std::string& value,
+ bool required) const;
+ bool GetStringConfig(std::string const& key, std::string& value,
+ bool required) const;
+ bool GetBool(std::string const& key, bool& value, bool required) const;
+ bool GetUInt(std::string const& key, unsigned int& value,
+ bool required) const;
+ /** Returns false if the JSON value isn't an array. */
+ bool GetArray(std::string const& key, std::vector<std::string>& list,
+ bool required) const;
+ bool GetArray(std::string const& key,
+ std::unordered_set<std::string>& list, bool required) const;
+ bool GetArrayConfig(std::string const& key, std::vector<std::string>& list,
+ bool required) const;
+
+ Json::Value const& GetValue(std::string const& key) const
+ {
+ return this->Json_[key];
+ }
+
+ /** Returns true if strings were appended to the list. */
+ static bool GetJsonArray(std::vector<std::string>& list,
+ Json::Value const& jval);
+ /** Returns true if strings were found in the JSON array. */
+ static bool GetJsonArray(std::unordered_set<std::string>& list,
+ Json::Value const& jval);
+
+ bool LogError(GenT genType, cm::string_view message) const;
+ bool LogError(cm::string_view message) const;
+
+ private:
+ std::string ConfigKey(cm::string_view key) const;
+
+ Json::Value Json_;
+ cmQtAutoGenerator& Gen_;
+ };
+
+ // -- Settings file
+ static std::string SettingsFind(cm::string_view content,
+ cm::string_view key);
+
+ // -- Directories
+ ProjectDirsT const& ProjectDirs() const { return this->ProjectDirs_; }
+ std::string MessagePath(cm::string_view path) const;
+
+ // -- Run
+ bool Run(cm::string_view infoFile, cm::string_view config);
+
+protected:
+ // -- Abstract processing interface
+ virtual bool InitFromInfo(InfoT const& info) = 0;
+ virtual bool Process() = 0;
+ // - Utility classes
+ Logger const& Log() const { return this->Logger_; }
+
+private:
+ // -- Generator type
+ GenT GenType_;
+ // -- Logging
+ Logger Logger_;
+ // -- Info file
+ std::string InfoFile_;
+ std::string InfoDir_;
+ cmFileTime InfoFileTime_;
+ std::string InfoConfig_;
+ // -- Directories
+ ProjectDirsT ProjectDirs_;
+};
diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx
new file mode 100644
index 0000000..c32c965
--- /dev/null
+++ b/Source/cmQtAutoMocUic.cxx
@@ -0,0 +1,2999 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmQtAutoMocUic.h"
+
+#include <algorithm>
+#include <atomic>
+#include <cstddef>
+#include <map>
+#include <mutex>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/algorithm>
+
+#include <cm3p/json/value.h>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCryptoHash.h"
+#include "cmFileTime.h"
+#include "cmGccDepfileReader.h"
+#include "cmGeneratedFileStream.h"
+#include "cmQtAutoGen.h"
+#include "cmQtAutoGenerator.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmWorkerPool.h"
+
+#if defined(__APPLE__)
+# include <unistd.h>
+#endif
+
+namespace {
+
+constexpr std::size_t MocUnderscoreLength = 4; // Length of "moc_"
+constexpr std::size_t UiUnderscoreLength = 3; // Length of "ui_"
+
+/** \class cmQtAutoMocUicT
+ * \brief AUTOMOC and AUTOUIC generator
+ */
+class cmQtAutoMocUicT : public cmQtAutoGenerator
+{
+public:
+ cmQtAutoMocUicT();
+ ~cmQtAutoMocUicT() override;
+
+ cmQtAutoMocUicT(cmQtAutoMocUicT const&) = delete;
+ cmQtAutoMocUicT& operator=(cmQtAutoMocUicT const&) = delete;
+
+ // -- Types
+
+ /** Include string with sub parts. */
+ struct IncludeKeyT
+ {
+ IncludeKeyT(std::string const& key, std::size_t basePrefixLength);
+
+ std::string Key; // Full include string
+ std::string Dir; // Include directory
+ std::string Base; // Base part of the include file name
+ };
+
+ /** Search key plus regular expression pair. */
+ struct KeyExpT
+ {
+ KeyExpT(std::string key, std::string const& exp)
+ : Key(std::move(key))
+ , Exp(exp)
+ {
+ }
+
+ std::string Key;
+ cmsys::RegularExpression Exp;
+ };
+
+ /** Source file parsing cache. */
+ class ParseCacheT
+ {
+ public:
+ // -- Types
+
+ /** Entry of the file parsing cache. */
+ struct FileT
+ {
+ void Clear();
+
+ struct MocT
+ {
+ std::string Macro;
+ struct IncludeT
+ {
+ std::vector<IncludeKeyT> Underscore;
+ std::vector<IncludeKeyT> Dot;
+ } Include;
+ std::vector<std::string> Depends;
+ } Moc;
+
+ struct UicT
+ {
+ std::vector<IncludeKeyT> Include;
+ std::vector<std::string> Depends;
+ } Uic;
+ };
+ using FileHandleT = std::shared_ptr<FileT>;
+ using GetOrInsertT = std::pair<FileHandleT, bool>;
+
+ ParseCacheT();
+ ~ParseCacheT();
+
+ bool ReadFromFile(std::string const& fileName);
+ bool WriteToFile(std::string const& fileName);
+
+ //! Always returns a valid handle
+ GetOrInsertT GetOrInsert(std::string const& fileName);
+
+ private:
+ std::unordered_map<std::string, FileHandleT> Map_;
+ };
+
+ /** Source file data. */
+ class SourceFileT
+ {
+ public:
+ SourceFileT(std::string fileName)
+ : FileName(std::move(fileName))
+ {
+ }
+
+ std::string FileName;
+ cmFileTime FileTime;
+ ParseCacheT::FileHandleT ParseData;
+ std::string BuildPath;
+ bool IsHeader = false;
+ bool Moc = false;
+ bool Uic = false;
+ };
+ using SourceFileHandleT = std::shared_ptr<SourceFileT>;
+ using SourceFileMapT = std::map<std::string, SourceFileHandleT>;
+
+ /** Meta compiler file mapping information. */
+ struct MappingT
+ {
+ SourceFileHandleT SourceFile;
+ std::string OutputFile;
+ std::string IncludeString;
+ std::vector<SourceFileHandleT> IncluderFiles;
+ };
+ using MappingHandleT = std::shared_ptr<MappingT>;
+ using MappingMapT = std::map<std::string, MappingHandleT>;
+
+ /** Common settings. */
+ class BaseSettingsT
+ {
+ public:
+ // -- Constructors
+ BaseSettingsT();
+ ~BaseSettingsT();
+
+ BaseSettingsT(BaseSettingsT const&) = delete;
+ BaseSettingsT& operator=(BaseSettingsT const&) = delete;
+
+ // -- Attributes
+ // - Config
+ bool MultiConfig = false;
+ IntegerVersion QtVersion = { 4, 0 };
+ unsigned int ThreadCount = 0;
+ // - Directories
+ std::string AutogenBuildDir;
+ std::string AutogenIncludeDir;
+ // - Files
+ std::string CMakeExecutable;
+ cmFileTime CMakeExecutableTime;
+ std::string ParseCacheFile;
+ std::string DepFile;
+ std::string DepFileRuleName;
+ std::vector<std::string> HeaderExtensions;
+ std::vector<std::string> ListFiles;
+ };
+
+ /** Shared common variables. */
+ class BaseEvalT
+ {
+ public:
+ // -- Parse Cache
+ std::atomic<bool> ParseCacheChanged = ATOMIC_VAR_INIT(false);
+ cmFileTime ParseCacheTime;
+ ParseCacheT ParseCache;
+
+ // -- Sources
+ SourceFileMapT Headers;
+ SourceFileMapT Sources;
+ };
+
+ /** Moc settings. */
+ class MocSettingsT
+ {
+ public:
+ // -- Constructors
+ MocSettingsT();
+ ~MocSettingsT();
+
+ MocSettingsT(MocSettingsT const&) = delete;
+ MocSettingsT& operator=(MocSettingsT const&) = delete;
+
+ // -- Const methods
+ bool skipped(std::string const& fileName) const;
+ std::string MacrosString() const;
+
+ // -- Attributes
+ bool Enabled = false;
+ bool SettingsChanged = false;
+ bool RelaxedMode = false;
+ bool PathPrefix = false;
+ bool CanOutputDependencies = false;
+ cmFileTime ExecutableTime;
+ std::string Executable;
+ std::string CompFileAbs;
+ std::string PredefsFileAbs;
+ std::unordered_set<std::string> SkipList;
+ std::vector<std::string> IncludePaths;
+ std::vector<std::string> Definitions;
+ std::vector<std::string> OptionsIncludes;
+ std::vector<std::string> OptionsDefinitions;
+ std::vector<std::string> OptionsExtra;
+ std::vector<std::string> PredefsCmd;
+ std::vector<KeyExpT> DependFilters;
+ std::vector<KeyExpT> MacroFilters;
+ cmsys::RegularExpression RegExpInclude;
+ };
+
+ /** Moc shared variables. */
+ class MocEvalT
+ {
+ public:
+ // -- predefines file
+ cmFileTime PredefsTime;
+ // -- Mappings
+ MappingMapT HeaderMappings;
+ MappingMapT SourceMappings;
+ MappingMapT Includes;
+ // -- Discovered files
+ SourceFileMapT HeadersDiscovered;
+ // -- Output directories
+ std::unordered_set<std::string> OutputDirs;
+ // -- Mocs compilation
+ bool CompUpdated = false;
+ std::vector<std::string> CompFiles;
+ };
+
+ /** Uic settings. */
+ class UicSettingsT
+ {
+ public:
+ struct UiFile
+ {
+ std::vector<std::string> Options;
+ };
+
+ UicSettingsT();
+ ~UicSettingsT();
+
+ UicSettingsT(UicSettingsT const&) = delete;
+ UicSettingsT& operator=(UicSettingsT const&) = delete;
+
+ // -- Const methods
+ bool skipped(std::string const& fileName) const;
+
+ // -- Attributes
+ bool Enabled = false;
+ bool SettingsChanged = false;
+ cmFileTime ExecutableTime;
+ std::string Executable;
+ std::unordered_set<std::string> SkipList;
+ std::vector<std::string> Options;
+ std::unordered_map<std::string, UiFile> UiFiles;
+ std::vector<std::string> SearchPaths;
+ cmsys::RegularExpression RegExpInclude;
+ };
+
+ /** Uic shared variables. */
+ class UicEvalT
+ {
+ public:
+ // -- Discovered files
+ SourceFileMapT UiFiles;
+ // -- Mappings
+ MappingMapT Includes;
+ // -- Output directories
+ std::unordered_set<std::string> OutputDirs;
+ };
+
+ /** Abstract job class for concurrent job processing. */
+ class JobT : public cmWorkerPool::JobT
+ {
+ protected:
+ /** Protected default constructor. */
+ JobT(bool fence = false)
+ : cmWorkerPool::JobT(fence)
+ {
+ }
+
+ //! Get the generator. Only valid during Process() call!
+ cmQtAutoMocUicT* Gen() const
+ {
+ return static_cast<cmQtAutoMocUicT*>(this->UserData());
+ };
+
+ // -- Accessors. Only valid during Process() call!
+ Logger const& Log() const { return this->Gen()->Log(); }
+ BaseSettingsT const& BaseConst() const { return this->Gen()->BaseConst(); }
+ BaseEvalT& BaseEval() const { return this->Gen()->BaseEval(); }
+ MocSettingsT const& MocConst() const { return this->Gen()->MocConst(); }
+ MocEvalT& MocEval() const { return this->Gen()->MocEval(); }
+ UicSettingsT const& UicConst() const { return this->Gen()->UicConst(); }
+ UicEvalT& UicEval() const { return this->Gen()->UicEval(); }
+
+ // -- Logging
+ std::string MessagePath(cm::string_view path) const
+ {
+ return this->Gen()->MessagePath(path);
+ }
+ // - Error logging with automatic abort
+ void LogError(GenT genType, cm::string_view message) const;
+ void LogCommandError(GenT genType, cm::string_view message,
+ std::vector<std::string> const& command,
+ std::string const& output) const;
+
+ /** @brief Run an external process. Use only during Process() call! */
+ bool RunProcess(GenT genType, cmWorkerPool::ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string* infoMessage = nullptr);
+ };
+
+ /** Fence job utility class. */
+ class JobFenceT : public JobT
+ {
+ public:
+ JobFenceT()
+ : JobT(true)
+ {
+ }
+ void Process() override{};
+ };
+
+ /** Generate moc_predefs.h. */
+ class JobMocPredefsT : public JobFenceT
+ {
+ void Process() override;
+ bool Update(std::string* reason) const;
+ };
+
+ /** File parse job base class. */
+ class JobParseT : public JobT
+ {
+ public:
+ JobParseT(SourceFileHandleT fileHandle)
+ : FileHandle(std::move(fileHandle))
+ {
+ }
+
+ protected:
+ bool ReadFile();
+ void CreateKeys(std::vector<IncludeKeyT>& container,
+ std::set<std::string> const& source,
+ std::size_t basePrefixLength);
+ void MocMacro();
+ void MocDependecies();
+ void MocIncludes();
+ void UicIncludes();
+
+ SourceFileHandleT FileHandle;
+ std::string Content;
+ };
+
+ /** Header file parse job. */
+ class JobParseHeaderT : public JobParseT
+ {
+ public:
+ using JobParseT::JobParseT;
+ void Process() override;
+ };
+
+ /** Source file parse job. */
+ class JobParseSourceT : public JobParseT
+ {
+ public:
+ using JobParseT::JobParseT;
+ void Process() override;
+ };
+
+ /** Evaluate cached file parse data - moc. */
+ class JobEvalCacheT : public JobT
+ {
+ protected:
+ std::string MessageSearchLocations() const;
+ std::vector<std::string> SearchLocations;
+ };
+
+ /** Evaluate cached file parse data - moc. */
+ class JobEvalCacheMocT : public JobEvalCacheT
+ {
+ void Process() override;
+ bool EvalHeader(SourceFileHandleT source);
+ bool EvalSource(SourceFileHandleT const& source);
+ bool FindIncludedHeader(SourceFileHandleT& headerHandle,
+ cm::string_view includerDir,
+ cm::string_view includeBase);
+ bool RegisterIncluded(std::string const& includeString,
+ SourceFileHandleT includerFileHandle,
+ SourceFileHandleT sourceFileHandle) const;
+ void RegisterMapping(MappingHandleT mappingHandle) const;
+ std::string MessageHeader(cm::string_view headerBase) const;
+ };
+
+ /** Evaluate cached file parse data - uic. */
+ class JobEvalCacheUicT : public JobEvalCacheT
+ {
+ void Process() override;
+ bool EvalFile(SourceFileHandleT const& sourceFileHandle);
+ bool FindIncludedUi(cm::string_view sourceDirPrefix,
+ cm::string_view includePrefix);
+ bool RegisterMapping(std::string const& includeString,
+ SourceFileHandleT includerFileHandle);
+
+ std::string UiName;
+ SourceFileHandleT UiFileHandle;
+ };
+
+ /** Evaluate cached file parse data - finish */
+ class JobEvalCacheFinishT : public JobFenceT
+ {
+ void Process() override;
+ };
+
+ /** Dependency probing base job. */
+ class JobProbeDepsT : public JobT
+ {
+ };
+
+ /** Probes file dependencies and generates moc compile jobs. */
+ class JobProbeDepsMocT : public JobProbeDepsT
+ {
+ void Process() override;
+ bool Generate(MappingHandleT const& mapping, bool compFile) const;
+ bool Probe(MappingT const& mapping, std::string* reason) const;
+ std::pair<std::string, cmFileTime> FindDependency(
+ std::string const& sourceDir, std::string const& includeString) const;
+ };
+
+ /** Probes file dependencies and generates uic compile jobs. */
+ class JobProbeDepsUicT : public JobProbeDepsT
+ {
+ void Process() override;
+ bool Probe(MappingT const& mapping, std::string* reason) const;
+ };
+
+ /** Dependency probing finish job. */
+ class JobProbeDepsFinishT : public JobFenceT
+ {
+ void Process() override;
+ };
+
+ /** Meta compiler base job. */
+ class JobCompileT : public JobT
+ {
+ public:
+ JobCompileT(MappingHandleT uicMapping, std::unique_ptr<std::string> reason)
+ : Mapping(std::move(uicMapping))
+ , Reason(std::move(reason))
+ {
+ }
+
+ protected:
+ MappingHandleT Mapping;
+ std::unique_ptr<std::string> Reason;
+ };
+
+ /** moc compiles a file. */
+ class JobCompileMocT : public JobCompileT
+ {
+ public:
+ JobCompileMocT(MappingHandleT uicMapping,
+ std::unique_ptr<std::string> reason,
+ ParseCacheT::FileHandleT cacheEntry)
+ : JobCompileT(std::move(uicMapping), std::move(reason))
+ , CacheEntry(std::move(cacheEntry))
+ {
+ }
+ void Process() override;
+
+ protected:
+ ParseCacheT::FileHandleT CacheEntry;
+ };
+
+ /** uic compiles a file. */
+ class JobCompileUicT : public JobCompileT
+ {
+ public:
+ using JobCompileT::JobCompileT;
+ void Process() override;
+ };
+
+ /** Generate mocs_compilation.cpp. */
+ class JobMocsCompilationT : public JobFenceT
+ {
+ private:
+ void Process() override;
+ };
+
+ class JobDepFilesMergeT : public JobFenceT
+ {
+ private:
+ std::vector<std::string> initialDependencies() const;
+ void Process() override;
+ };
+
+ /** @brief The last job. */
+ class JobFinishT : public JobFenceT
+ {
+ private:
+ void Process() override;
+ };
+
+ // -- Const settings interface
+ BaseSettingsT const& BaseConst() const { return this->BaseConst_; }
+ BaseEvalT& BaseEval() { return this->BaseEval_; }
+ MocSettingsT const& MocConst() const { return this->MocConst_; }
+ MocEvalT& MocEval() { return this->MocEval_; }
+ UicSettingsT const& UicConst() const { return this->UicConst_; }
+ UicEvalT& UicEval() { return this->UicEval_; }
+
+ // -- Parallel job processing interface
+ cmWorkerPool& WorkerPool() { return this->WorkerPool_; }
+ void AbortError() { this->Abort(true); }
+ void AbortSuccess() { this->Abort(false); }
+
+ // -- Utility
+ std::string AbsoluteBuildPath(cm::string_view relativePath) const;
+ std::string AbsoluteIncludePath(cm::string_view relativePath) const;
+ template <class JOBTYPE>
+ void CreateParseJobs(SourceFileMapT const& sourceMap);
+ std::string CollapseFullPathTS(std::string const& path) const;
+
+private:
+ // -- Abstract processing interface
+ bool InitFromInfo(InfoT const& info) override;
+ void InitJobs();
+ bool Process() override;
+ // -- Settings file
+ void SettingsFileRead();
+ bool SettingsFileWrite();
+ // -- Parse cache
+ void ParseCacheRead();
+ bool ParseCacheWrite();
+ // -- Thread processing
+ void Abort(bool error);
+ // -- Generation
+ bool CreateDirectories();
+ // -- Support for depfiles
+ static std::vector<std::string> dependenciesFromDepFile(
+ const char* filePath);
+
+ // -- Settings
+ BaseSettingsT BaseConst_;
+ BaseEvalT BaseEval_;
+ MocSettingsT MocConst_;
+ MocEvalT MocEval_;
+ UicSettingsT UicConst_;
+ UicEvalT UicEval_;
+ // -- Settings file
+ std::string SettingsFile_;
+ std::string SettingsStringMoc_;
+ std::string SettingsStringUic_;
+ // -- Worker thread pool
+ std::atomic<bool> JobError_ = ATOMIC_VAR_INIT(false);
+ cmWorkerPool WorkerPool_;
+ // -- Concurrent processing
+ mutable std::mutex CMakeLibMutex_;
+};
+
+cmQtAutoMocUicT::IncludeKeyT::IncludeKeyT(std::string const& key,
+ std::size_t basePrefixLength)
+ : Key(key)
+ , Dir(SubDirPrefix(key))
+ , Base(cmSystemTools::GetFilenameWithoutLastExtension(key))
+{
+ if (basePrefixLength != 0) {
+ this->Base = this->Base.substr(basePrefixLength);
+ }
+}
+
+void cmQtAutoMocUicT::ParseCacheT::FileT::Clear()
+{
+ this->Moc.Macro.clear();
+ this->Moc.Include.Underscore.clear();
+ this->Moc.Include.Dot.clear();
+ this->Moc.Depends.clear();
+
+ this->Uic.Include.clear();
+ this->Uic.Depends.clear();
+}
+
+cmQtAutoMocUicT::ParseCacheT::GetOrInsertT
+cmQtAutoMocUicT::ParseCacheT::GetOrInsert(std::string const& fileName)
+{
+ // Find existing entry
+ {
+ auto it = this->Map_.find(fileName);
+ if (it != this->Map_.end()) {
+ return GetOrInsertT{ it->second, false };
+ }
+ }
+
+ // Insert new entry
+ return GetOrInsertT{
+ this->Map_.emplace(fileName, std::make_shared<FileT>()).first->second, true
+ };
+}
+
+cmQtAutoMocUicT::ParseCacheT::ParseCacheT() = default;
+cmQtAutoMocUicT::ParseCacheT::~ParseCacheT() = default;
+
+bool cmQtAutoMocUicT::ParseCacheT::ReadFromFile(std::string const& fileName)
+{
+ cmsys::ifstream fin(fileName.c_str());
+ if (!fin) {
+ return false;
+ }
+ FileHandleT fileHandle;
+
+ std::string line;
+ while (std::getline(fin, line)) {
+ // Check if this an empty or a comment line
+ if (line.empty() || line.front() == '#') {
+ continue;
+ }
+ // Drop carriage return character at the end
+ if (line.back() == '\r') {
+ line.pop_back();
+ if (line.empty()) {
+ continue;
+ }
+ }
+ // Check if this a file name line
+ if (line.front() != ' ') {
+ fileHandle = this->GetOrInsert(line).first;
+ continue;
+ }
+
+ // Bad line or bad file handle
+ if (!fileHandle || (line.size() < 6)) {
+ continue;
+ }
+
+ constexpr std::size_t offset = 5;
+ if (cmHasLiteralPrefix(line, " mmc:")) {
+ fileHandle->Moc.Macro = line.substr(offset);
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " miu:")) {
+ fileHandle->Moc.Include.Underscore.emplace_back(line.substr(offset),
+ MocUnderscoreLength);
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " mid:")) {
+ fileHandle->Moc.Include.Dot.emplace_back(line.substr(offset), 0);
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " mdp:")) {
+ fileHandle->Moc.Depends.emplace_back(line.substr(offset));
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " uic:")) {
+ fileHandle->Uic.Include.emplace_back(line.substr(offset),
+ UiUnderscoreLength);
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " udp:")) {
+ fileHandle->Uic.Depends.emplace_back(line.substr(offset));
+ continue;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoMocUicT::ParseCacheT::WriteToFile(std::string const& fileName)
+{
+ cmGeneratedFileStream ofs(fileName);
+ if (!ofs) {
+ return false;
+ }
+ ofs << "# Generated by CMake. Changes will be overwritten.\n";
+ for (auto const& pair : this->Map_) {
+ ofs << pair.first << '\n';
+ FileT const& file = *pair.second;
+ if (!file.Moc.Macro.empty()) {
+ ofs << " mmc:" << file.Moc.Macro << '\n';
+ }
+ for (IncludeKeyT const& item : file.Moc.Include.Underscore) {
+ ofs << " miu:" << item.Key << '\n';
+ }
+ for (IncludeKeyT const& item : file.Moc.Include.Dot) {
+ ofs << " mid:" << item.Key << '\n';
+ }
+ for (std::string const& item : file.Moc.Depends) {
+ ofs << " mdp:" << item << '\n';
+ }
+ for (IncludeKeyT const& item : file.Uic.Include) {
+ ofs << " uic:" << item.Key << '\n';
+ }
+ for (std::string const& item : file.Uic.Depends) {
+ ofs << " udp:" << item << '\n';
+ }
+ }
+ return ofs.Close();
+}
+
+cmQtAutoMocUicT::BaseSettingsT::BaseSettingsT() = default;
+cmQtAutoMocUicT::BaseSettingsT::~BaseSettingsT() = default;
+
+cmQtAutoMocUicT::MocSettingsT::MocSettingsT()
+{
+ this->RegExpInclude.compile(
+ "(^|\n)[ \t]*#[ \t]*include[ \t]+"
+ "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
+}
+
+cmQtAutoMocUicT::MocSettingsT::~MocSettingsT() = default;
+
+bool cmQtAutoMocUicT::MocSettingsT::skipped(std::string const& fileName) const
+{
+ return (!this->Enabled ||
+ (this->SkipList.find(fileName) != this->SkipList.end()));
+}
+
+std::string cmQtAutoMocUicT::MocSettingsT::MacrosString() const
+{
+ std::string res;
+ const auto itB = this->MacroFilters.cbegin();
+ const auto itE = this->MacroFilters.cend();
+ const auto itL = itE - 1;
+ auto itC = itB;
+ for (; itC != itE; ++itC) {
+ // Separator
+ if (itC != itB) {
+ if (itC != itL) {
+ res += ", ";
+ } else {
+ res += " or ";
+ }
+ }
+ // Key
+ res += itC->Key;
+ }
+ return res;
+}
+
+cmQtAutoMocUicT::UicSettingsT::UicSettingsT()
+{
+ this->RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+"
+ "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
+}
+
+cmQtAutoMocUicT::UicSettingsT::~UicSettingsT() = default;
+
+bool cmQtAutoMocUicT::UicSettingsT::skipped(std::string const& fileName) const
+{
+ return (!this->Enabled ||
+ (this->SkipList.find(fileName) != this->SkipList.end()));
+}
+
+void cmQtAutoMocUicT::JobT::LogError(GenT genType,
+ cm::string_view message) const
+{
+ this->Gen()->AbortError();
+ this->Gen()->Log().Error(genType, message);
+}
+
+void cmQtAutoMocUicT::JobT::LogCommandError(
+ GenT genType, cm::string_view message,
+ std::vector<std::string> const& command, std::string const& output) const
+{
+ this->Gen()->AbortError();
+ this->Gen()->Log().ErrorCommand(genType, message, command, output);
+}
+
+bool cmQtAutoMocUicT::JobT::RunProcess(GenT genType,
+ cmWorkerPool::ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string* infoMessage)
+{
+ // Log command
+ if (this->Log().Verbose()) {
+ cm::string_view info;
+ if (infoMessage != nullptr) {
+ info = *infoMessage;
+ }
+ this->Log().Info(
+ genType,
+ cmStrCat(info, info.empty() || cmHasSuffix(info, '\n') ? "" : "\n",
+ QuotedCommand(command), '\n'));
+ }
+ // Run command
+ return this->cmWorkerPool::JobT::RunProcess(
+ result, command, this->BaseConst().AutogenBuildDir);
+}
+
+void cmQtAutoMocUicT::JobMocPredefsT::Process()
+{
+ // (Re)generate moc_predefs.h on demand
+ std::unique_ptr<std::string> reason;
+ if (this->Log().Verbose()) {
+ reason = cm::make_unique<std::string>();
+ }
+ if (!this->Update(reason.get())) {
+ return;
+ }
+ std::string const& predefsFileAbs = this->MocConst().PredefsFileAbs;
+ {
+ cmWorkerPool::ProcessResultT result;
+ {
+ // Compose command
+ std::vector<std::string> cmd = this->MocConst().PredefsCmd;
+ // Add definitions
+ cm::append(cmd, this->MocConst().OptionsDefinitions);
+ // Add includes
+ cm::append(cmd, this->MocConst().OptionsIncludes);
+ // Execute command
+ if (!this->RunProcess(GenT::MOC, result, cmd, reason.get())) {
+ this->LogCommandError(GenT::MOC,
+ cmStrCat("The content generation command for ",
+ this->MessagePath(predefsFileAbs),
+ " failed.\n", result.ErrorMessage),
+ cmd, result.StdOut);
+ return;
+ }
+ }
+
+ // (Re)write predefs file only on demand
+ if (cmQtAutoGenerator::FileDiffers(predefsFileAbs, result.StdOut)) {
+ if (!cmQtAutoGenerator::FileWrite(predefsFileAbs, result.StdOut)) {
+ this->LogError(
+ GenT::MOC,
+ cmStrCat("Writing ", this->MessagePath(predefsFileAbs), " failed."));
+ return;
+ }
+ } else {
+ // Touch to update the time stamp
+ if (this->Log().Verbose()) {
+ this->Log().Info(GenT::MOC,
+ "Touching " + this->MessagePath(predefsFileAbs));
+ }
+ if (!cmSystemTools::Touch(predefsFileAbs, false)) {
+ this->LogError(GenT::MOC,
+ cmStrCat("Touching ", this->MessagePath(predefsFileAbs),
+ " failed."));
+ return;
+ }
+ }
+ }
+
+ // Read file time afterwards
+ if (!this->MocEval().PredefsTime.Load(predefsFileAbs)) {
+ this->LogError(GenT::MOC,
+ cmStrCat("Reading the file time of ",
+ this->MessagePath(predefsFileAbs), " failed."));
+ return;
+ }
+}
+
+bool cmQtAutoMocUicT::JobMocPredefsT::Update(std::string* reason) const
+{
+ // Test if the file exists
+ if (!this->MocEval().PredefsTime.Load(this->MocConst().PredefsFileAbs)) {
+ if (reason != nullptr) {
+ *reason = cmStrCat("Generating ",
+ this->MessagePath(this->MocConst().PredefsFileAbs),
+ ", because it doesn't exist.");
+ }
+ return true;
+ }
+
+ // Test if the settings changed
+ if (this->MocConst().SettingsChanged) {
+ if (reason != nullptr) {
+ *reason = cmStrCat("Generating ",
+ this->MessagePath(this->MocConst().PredefsFileAbs),
+ ", because the moc settings changed.");
+ }
+ return true;
+ }
+
+ // Test if the executable is newer
+ {
+ std::string const& exec = this->MocConst().PredefsCmd.at(0);
+ cmFileTime execTime;
+ if (execTime.Load(exec)) {
+ if (this->MocEval().PredefsTime.Older(execTime)) {
+ if (reason != nullptr) {
+ *reason = cmStrCat(
+ "Generating ", this->MessagePath(this->MocConst().PredefsFileAbs),
+ " because it is older than ", this->MessagePath(exec), '.');
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool cmQtAutoMocUicT::JobParseT::ReadFile()
+{
+ // Clear old parse information
+ this->FileHandle->ParseData->Clear();
+ std::string const& fileName = this->FileHandle->FileName;
+ // Write info
+ if (this->Log().Verbose()) {
+ this->Log().Info(GenT::GEN,
+ cmStrCat("Parsing ", this->MessagePath(fileName)));
+ }
+ // Read file content
+ {
+ std::string error;
+ if (!cmQtAutoGenerator::FileRead(this->Content, fileName, &error)) {
+ this->LogError(GenT::GEN,
+ cmStrCat("Could not read ", this->MessagePath(fileName),
+ ".\n", error));
+ return false;
+ }
+ }
+ // Warn if empty
+ if (this->Content.empty()) {
+ this->Log().Warning(GenT::GEN,
+ cmStrCat(this->MessagePath(fileName), " is empty."));
+ return false;
+ }
+ return true;
+}
+
+void cmQtAutoMocUicT::JobParseT::CreateKeys(
+ std::vector<IncludeKeyT>& container, std::set<std::string> const& source,
+ std::size_t basePrefixLength)
+{
+ if (source.empty()) {
+ return;
+ }
+ container.reserve(source.size());
+ for (std::string const& src : source) {
+ container.emplace_back(src, basePrefixLength);
+ }
+}
+
+void cmQtAutoMocUicT::JobParseT::MocMacro()
+{
+ for (KeyExpT const& filter : this->MocConst().MacroFilters) {
+ // Run a simple find string check
+ if (this->Content.find(filter.Key) == std::string::npos) {
+ continue;
+ }
+ // Run the expensive regular expression check loop
+ cmsys::RegularExpressionMatch match;
+ if (filter.Exp.find(this->Content.c_str(), match)) {
+ // Keep detected macro name
+ this->FileHandle->ParseData->Moc.Macro = filter.Key;
+ return;
+ }
+ }
+}
+
+void cmQtAutoMocUicT::JobParseT::MocDependecies()
+{
+ if (this->MocConst().DependFilters.empty() ||
+ this->MocConst().CanOutputDependencies) {
+ return;
+ }
+
+ // Find dependency strings
+ std::set<std::string> parseDepends;
+ for (KeyExpT const& filter : this->MocConst().DependFilters) {
+ // Run a simple find string check
+ if (this->Content.find(filter.Key) == std::string::npos) {
+ continue;
+ }
+ // Run the expensive regular expression check loop
+ const char* contentChars = this->Content.c_str();
+ cmsys::RegularExpressionMatch match;
+ while (filter.Exp.find(contentChars, match)) {
+ {
+ std::string dep = match.match(1);
+ if (!dep.empty()) {
+ parseDepends.emplace(std::move(dep));
+ }
+ }
+ contentChars += match.end();
+ }
+ }
+
+ // Store dependency strings
+ {
+ auto& Depends = this->FileHandle->ParseData->Moc.Depends;
+ Depends.reserve(parseDepends.size());
+ for (std::string const& item : parseDepends) {
+ Depends.emplace_back(item);
+ // Replace end of line characters in filenames
+ std::string& path = Depends.back();
+ std::replace(path.begin(), path.end(), '\n', ' ');
+ std::replace(path.begin(), path.end(), '\r', ' ');
+ }
+ }
+}
+
+void cmQtAutoMocUicT::JobParseT::MocIncludes()
+{
+ if (this->Content.find("moc") == std::string::npos) {
+ return;
+ }
+
+ std::set<std::string> underscore;
+ std::set<std::string> dot;
+ {
+ const char* contentChars = this->Content.c_str();
+ cmsys::RegularExpression const& regExp = this->MocConst().RegExpInclude;
+ cmsys::RegularExpressionMatch match;
+ while (regExp.find(contentChars, match)) {
+ std::string incString = match.match(2);
+ std::string const incBase =
+ cmSystemTools::GetFilenameWithoutLastExtension(incString);
+ if (cmHasLiteralPrefix(incBase, "moc_")) {
+ // moc_<BASE>.cpp
+ // Remove the moc_ part from the base name
+ underscore.emplace(std::move(incString));
+ } else {
+ // <BASE>.moc
+ dot.emplace(std::move(incString));
+ }
+ // Forward content pointer
+ contentChars += match.end();
+ }
+ }
+ auto& Include = this->FileHandle->ParseData->Moc.Include;
+ this->CreateKeys(Include.Underscore, underscore, MocUnderscoreLength);
+ this->CreateKeys(Include.Dot, dot, 0);
+}
+
+void cmQtAutoMocUicT::JobParseT::UicIncludes()
+{
+ if (this->Content.find("ui_") == std::string::npos) {
+ return;
+ }
+
+ std::set<std::string> includes;
+ {
+ const char* contentChars = this->Content.c_str();
+ cmsys::RegularExpression const& regExp = this->UicConst().RegExpInclude;
+ cmsys::RegularExpressionMatch match;
+ while (regExp.find(contentChars, match)) {
+ includes.emplace(match.match(2));
+ // Forward content pointer
+ contentChars += match.end();
+ }
+ }
+ this->CreateKeys(this->FileHandle->ParseData->Uic.Include, includes,
+ UiUnderscoreLength);
+}
+
+void cmQtAutoMocUicT::JobParseHeaderT::Process()
+{
+ if (!this->ReadFile()) {
+ return;
+ }
+ // Moc parsing
+ if (this->FileHandle->Moc) {
+ this->MocMacro();
+ this->MocDependecies();
+ }
+ // Uic parsing
+ if (this->FileHandle->Uic) {
+ this->UicIncludes();
+ }
+}
+
+void cmQtAutoMocUicT::JobParseSourceT::Process()
+{
+ if (!this->ReadFile()) {
+ return;
+ }
+ // Moc parsing
+ if (this->FileHandle->Moc) {
+ this->MocMacro();
+ this->MocDependecies();
+ this->MocIncludes();
+ }
+ // Uic parsing
+ if (this->FileHandle->Uic) {
+ this->UicIncludes();
+ }
+}
+
+std::string cmQtAutoMocUicT::JobEvalCacheT::MessageSearchLocations() const
+{
+ std::string res;
+ res.reserve(512);
+ for (std::string const& path : this->SearchLocations) {
+ res += " ";
+ res += this->MessagePath(path);
+ res += '\n';
+ }
+ return res;
+}
+
+void cmQtAutoMocUicT::JobEvalCacheMocT::Process()
+{
+ // Evaluate headers
+ for (auto const& pair : this->BaseEval().Headers) {
+ if (!this->EvalHeader(pair.second)) {
+ return;
+ }
+ }
+ // Evaluate sources
+ for (auto const& pair : this->BaseEval().Sources) {
+ if (!this->EvalSource(pair.second)) {
+ return;
+ }
+ }
+}
+
+bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalHeader(SourceFileHandleT source)
+{
+ SourceFileT const& sourceFile = *source;
+ auto const& parseData = sourceFile.ParseData->Moc;
+ if (!source->Moc) {
+ return true;
+ }
+
+ if (!parseData.Macro.empty()) {
+ // Create a new mapping
+ MappingHandleT handle = std::make_shared<MappingT>();
+ handle->SourceFile = std::move(source);
+
+ // Absolute build path
+ if (this->BaseConst().MultiConfig) {
+ handle->OutputFile =
+ this->Gen()->AbsoluteIncludePath(sourceFile.BuildPath);
+ } else {
+ handle->OutputFile =
+ this->Gen()->AbsoluteBuildPath(sourceFile.BuildPath);
+ }
+
+ // Register mapping in headers map
+ this->RegisterMapping(handle);
+ }
+
+ return true;
+}
+
+bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource(
+ SourceFileHandleT const& source)
+{
+ SourceFileT const& sourceFile = *source;
+ auto const& parseData = sourceFile.ParseData->Moc;
+ if (!sourceFile.Moc ||
+ (parseData.Macro.empty() && parseData.Include.Underscore.empty() &&
+ parseData.Include.Dot.empty())) {
+ return true;
+ }
+
+ std::string const sourceDirPrefix = SubDirPrefix(sourceFile.FileName);
+ std::string const sourceBase =
+ cmSystemTools::GetFilenameWithoutLastExtension(sourceFile.FileName);
+
+ // For relaxed mode check if the own "moc_" or ".moc" file is included
+ bool const relaxedMode = this->MocConst().RelaxedMode;
+ bool sourceIncludesMocUnderscore = false;
+ bool sourceIncludesDotMoc = false;
+ // Check if the sources own "moc_" or ".moc" file is included
+ if (relaxedMode) {
+ for (IncludeKeyT const& incKey : parseData.Include.Underscore) {
+ if (incKey.Base == sourceBase) {
+ sourceIncludesMocUnderscore = true;
+ break;
+ }
+ }
+ }
+ for (IncludeKeyT const& incKey : parseData.Include.Dot) {
+ if (incKey.Base == sourceBase) {
+ sourceIncludesDotMoc = true;
+ break;
+ }
+ }
+
+ // Check if this source needs to be moc processed but doesn't.
+ if (!sourceIncludesDotMoc && !parseData.Macro.empty() &&
+ !(relaxedMode && sourceIncludesMocUnderscore)) {
+ this->LogError(GenT::MOC,
+ cmStrCat(this->MessagePath(sourceFile.FileName),
+ "\ncontains a ", Quoted(parseData.Macro),
+ " macro, but does not include ",
+ this->MessagePath(sourceBase + ".moc"),
+ "!\nConsider to\n - add #include \"", sourceBase,
+ ".moc\"\n - enable SKIP_AUTOMOC for this file"));
+ return false;
+ }
+
+ // Evaluate "moc_" includes
+ for (IncludeKeyT const& incKey : parseData.Include.Underscore) {
+ SourceFileHandleT headerHandle;
+ {
+ std::string const headerBase = cmStrCat(incKey.Dir, incKey.Base);
+ if (!this->FindIncludedHeader(headerHandle, sourceDirPrefix,
+ headerBase)) {
+ this->LogError(
+ GenT::MOC,
+ cmStrCat(this->MessagePath(sourceFile.FileName),
+ "\nincludes the moc file ", this->MessagePath(incKey.Key),
+ ",\nbut a header ", this->MessageHeader(headerBase),
+ "\ncould not be found "
+ "in the following directories\n",
+ this->MessageSearchLocations()));
+ return false;
+ }
+ }
+ // The include might be handled differently in relaxed mode
+ if (relaxedMode && !sourceIncludesDotMoc && !parseData.Macro.empty() &&
+ (incKey.Base == sourceBase)) {
+ // The <BASE>.cpp file includes a Qt macro but does not include the
+ // <BASE>.moc file. In this case, the moc_<BASE>.cpp should probably
+ // be generated from <BASE>.cpp instead of <BASE>.h, because otherwise
+ // it won't build. But warn, since this is not how it is supposed to be
+ // used. This is for KDE4 compatibility.
+
+ // Issue a warning
+ this->Log().Warning(
+ GenT::MOC,
+ cmStrCat(this->MessagePath(sourceFile.FileName), "\ncontains a ",
+ Quoted(parseData.Macro), " macro, but does not include ",
+ this->MessagePath(sourceBase + ".moc"),
+ ".\nInstead it includes ", this->MessagePath(incKey.Key),
+ ".\nRunning moc on the source\n ",
+ this->MessagePath(sourceFile.FileName), "!\nBetter include ",
+ this->MessagePath(sourceBase + ".moc"),
+ " for compatibility with regular mode.\n",
+ "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n"));
+
+ // Create mapping
+ if (!this->RegisterIncluded(incKey.Key, source, source)) {
+ return false;
+ }
+ continue;
+ }
+
+ // Check if header is skipped
+ if (this->MocConst().skipped(headerHandle->FileName)) {
+ continue;
+ }
+ // Create mapping
+ if (!this->RegisterIncluded(incKey.Key, source, std::move(headerHandle))) {
+ return false;
+ }
+ }
+
+ // Evaluate ".moc" includes
+ if (relaxedMode) {
+ // Relaxed mode
+ for (IncludeKeyT const& incKey : parseData.Include.Dot) {
+ // Check if this is the sources own .moc file
+ bool const ownMoc = (incKey.Base == sourceBase);
+ if (ownMoc && !parseData.Macro.empty()) {
+ // Create mapping for the regular use case
+ if (!this->RegisterIncluded(incKey.Key, source, source)) {
+ return false;
+ }
+ continue;
+ }
+ // Try to find a header instead but issue a warning.
+ // This is for KDE4 compatibility.
+ SourceFileHandleT headerHandle;
+ {
+ std::string const headerBase = cmStrCat(incKey.Dir, incKey.Base);
+ if (!this->FindIncludedHeader(headerHandle, sourceDirPrefix,
+ headerBase)) {
+ this->LogError(
+ GenT::MOC,
+ cmStrCat(
+ this->MessagePath(sourceFile.FileName),
+ "\nincludes the moc file ", this->MessagePath(incKey.Key),
+ ",\nwhich seems to be the moc file from a different source "
+ "file.\nCMAKE_AUTOMOC_RELAXED_MODE:\nAlso a matching header ",
+ this->MessageHeader(headerBase),
+ "\ncould not be found in the following directories\n",
+ this->MessageSearchLocations()));
+ return false;
+ }
+ }
+ // Check if header is skipped
+ if (this->MocConst().skipped(headerHandle->FileName)) {
+ continue;
+ }
+ // Issue a warning
+ if (ownMoc && parseData.Macro.empty()) {
+ this->Log().Warning(
+ GenT::MOC,
+ cmStrCat(
+ this->MessagePath(sourceFile.FileName), "\nincludes the moc file ",
+ this->MessagePath(incKey.Key), ", but does not contain a\n",
+ this->MocConst().MacrosString(),
+ " macro.\nRunning moc on the header\n ",
+ this->MessagePath(headerHandle->FileName), "!\nBetter include ",
+ this->MessagePath("moc_" + incKey.Base + ".cpp"),
+ " for a compatibility with regular mode.\n",
+ "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n"));
+ } else {
+ this->Log().Warning(
+ GenT::MOC,
+ cmStrCat(
+ this->MessagePath(sourceFile.FileName), "\nincludes the moc file ",
+ this->MessagePath(incKey.Key), " instead of ",
+ this->MessagePath("moc_" + incKey.Base + ".cpp"),
+ ".\nRunning moc on the header\n ",
+ this->MessagePath(headerHandle->FileName), "!\nBetter include ",
+ this->MessagePath("moc_" + incKey.Base + ".cpp"),
+ " for compatibility with regular mode.\n",
+ "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n"));
+ }
+ // Create mapping
+ if (!this->RegisterIncluded(incKey.Key, source,
+ std::move(headerHandle))) {
+ return false;
+ }
+ }
+ } else {
+ // Strict mode
+ for (IncludeKeyT const& incKey : parseData.Include.Dot) {
+ // Check if this is the sources own .moc file
+ bool const ownMoc = (incKey.Base == sourceBase);
+ if (!ownMoc) {
+ // Don't allow <BASE>.moc include other than own in regular mode
+ this->LogError(
+ GenT::MOC,
+ cmStrCat(this->MessagePath(sourceFile.FileName),
+ "\nincludes the moc file ", this->MessagePath(incKey.Key),
+ ",\nwhich seems to be the moc file from a different "
+ "source file.\nThis is not supported. Include ",
+ this->MessagePath(sourceBase + ".moc"),
+ " to run moc on this source file."));
+ return false;
+ }
+ // Accept but issue a warning if moc isn't required
+ if (parseData.Macro.empty()) {
+ this->Log().Warning(
+ GenT::MOC,
+ cmStrCat(this->MessagePath(sourceFile.FileName),
+ "\nincludes the moc file ", this->MessagePath(incKey.Key),
+ ", but does not contain a ",
+ this->MocConst().MacrosString(), " macro."));
+ }
+ // Create mapping
+ if (!this->RegisterIncluded(incKey.Key, source, source)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool cmQtAutoMocUicT::JobEvalCacheMocT::FindIncludedHeader(
+ SourceFileHandleT& headerHandle, cm::string_view includerDir,
+ cm::string_view includeBase)
+{
+ // Clear search locations
+ this->SearchLocations.clear();
+
+ auto findHeader = [this,
+ &headerHandle](std::string const& basePath) -> bool {
+ bool found = false;
+ for (std::string const& ext : this->BaseConst().HeaderExtensions) {
+ std::string const testPath =
+ this->Gen()->CollapseFullPathTS(cmStrCat(basePath, '.', ext));
+ cmFileTime fileTime;
+ if (!fileTime.Load(testPath)) {
+ // File not found
+ continue;
+ }
+
+ // Return a known file if it exists already
+ {
+ auto it = this->BaseEval().Headers.find(testPath);
+ if (it != this->BaseEval().Headers.end()) {
+ headerHandle = it->second;
+ found = true;
+ break;
+ }
+ }
+
+ // Created and return discovered file entry
+ {
+ SourceFileHandleT& handle =
+ this->MocEval().HeadersDiscovered[testPath];
+ if (!handle) {
+ handle = std::make_shared<SourceFileT>(testPath);
+ handle->FileTime = fileTime;
+ handle->IsHeader = true;
+ handle->Moc = true;
+ }
+ headerHandle = handle;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ this->SearchLocations.emplace_back(cmQtAutoGen::ParentDir(basePath));
+ }
+ return found;
+ };
+
+ // Search in vicinity of the source
+ if (findHeader(cmStrCat(includerDir, includeBase))) {
+ return true;
+ }
+ // Search in include directories
+ auto const& includePaths = this->MocConst().IncludePaths;
+ return std::any_of(
+ includePaths.begin(), includePaths.end(),
+ [&findHeader, &includeBase](std::string const& path) -> bool {
+ return findHeader(cmStrCat(path, '/', includeBase));
+ });
+}
+
+bool cmQtAutoMocUicT::JobEvalCacheMocT::RegisterIncluded(
+ std::string const& includeString, SourceFileHandleT includerFileHandle,
+ SourceFileHandleT sourceFileHandle) const
+{
+ // Check if this file is already included
+ MappingHandleT& handle = this->MocEval().Includes[includeString];
+ if (handle) {
+ // Check if the output file would be generated from different source files
+ if (handle->SourceFile != sourceFileHandle) {
+ std::string files =
+ cmStrCat(" ", this->MessagePath(includerFileHandle->FileName), '\n');
+ for (auto const& item : handle->IncluderFiles) {
+ files += cmStrCat(" ", this->MessagePath(item->FileName), '\n');
+ }
+ this->LogError(
+ GenT::MOC,
+ cmStrCat("The source files\n", files,
+ "contain the same include string ",
+ this->MessagePath(includeString),
+ ", but\nthe moc file would be generated from different "
+ "source files\n ",
+ this->MessagePath(sourceFileHandle->FileName), " and\n ",
+ this->MessagePath(handle->SourceFile->FileName),
+ ".\nConsider to\n"
+ " - not include the \"moc_<NAME>.cpp\" file\n"
+ " - add a directory prefix to a \"<NAME>.moc\" include "
+ "(e.g \"sub/<NAME>.moc\")\n"
+ " - rename the source file(s)\n"));
+ return false;
+ }
+
+ // The same mapping already exists. Just add to the includers list.
+ handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
+ return true;
+ }
+
+ // Create a new mapping
+ handle = std::make_shared<MappingT>();
+ handle->IncludeString = includeString;
+ handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
+ handle->SourceFile = std::move(sourceFileHandle);
+ handle->OutputFile = this->Gen()->AbsoluteIncludePath(includeString);
+
+ // Register mapping in sources/headers map
+ this->RegisterMapping(handle);
+ return true;
+}
+
+void cmQtAutoMocUicT::JobEvalCacheMocT::RegisterMapping(
+ MappingHandleT mappingHandle) const
+{
+ auto& regMap = mappingHandle->SourceFile->IsHeader
+ ? this->MocEval().HeaderMappings
+ : this->MocEval().SourceMappings;
+ // Check if source file already gets mapped
+ auto& regHandle = regMap[mappingHandle->SourceFile->FileName];
+ if (!regHandle) {
+ // Yet unknown mapping
+ regHandle = std::move(mappingHandle);
+ } else {
+ // Mappings with include string override those without
+ if (!mappingHandle->IncludeString.empty()) {
+ regHandle = std::move(mappingHandle);
+ }
+ }
+}
+
+std::string cmQtAutoMocUicT::JobEvalCacheMocT::MessageHeader(
+ cm::string_view headerBase) const
+{
+ return this->MessagePath(cmStrCat(
+ headerBase, ".{", cmJoin(this->BaseConst().HeaderExtensions, ","), '}'));
+}
+
+void cmQtAutoMocUicT::JobEvalCacheUicT::Process()
+{
+ // Prepare buffers
+ this->SearchLocations.reserve((this->UicConst().SearchPaths.size() + 1) * 2);
+
+ // Evaluate headers
+ for (auto const& pair : this->BaseEval().Headers) {
+ if (!this->EvalFile(pair.second)) {
+ return;
+ }
+ }
+ // Evaluate sources
+ for (auto const& pair : this->BaseEval().Sources) {
+ if (!this->EvalFile(pair.second)) {
+ return;
+ }
+ }
+}
+
+bool cmQtAutoMocUicT::JobEvalCacheUicT::EvalFile(
+ SourceFileHandleT const& sourceFileHandle)
+{
+ SourceFileT const& sourceFile = *sourceFileHandle;
+ auto const& Include = sourceFile.ParseData->Uic.Include;
+ if (!sourceFile.Uic || Include.empty()) {
+ return true;
+ }
+
+ std::string const sourceDirPrefix = SubDirPrefix(sourceFile.FileName);
+ return std::all_of(
+ Include.begin(), Include.end(),
+ [this, &sourceDirPrefix, &sourceFile,
+ &sourceFileHandle](IncludeKeyT const& incKey) -> bool {
+ // Find .ui file
+ this->UiName = cmStrCat(incKey.Base, ".ui");
+ if (!this->FindIncludedUi(sourceDirPrefix, incKey.Dir)) {
+ this->LogError(
+ GenT::UIC,
+ cmStrCat(this->MessagePath(sourceFile.FileName),
+ "\nincludes the uic file ", this->MessagePath(incKey.Key),
+ ",\nbut the user interface file ",
+ this->MessagePath(this->UiName),
+ "\ncould not be found in the following directories\n",
+ this->MessageSearchLocations()));
+ return false;
+ }
+ // Check if the file is skipped
+ if (this->UicConst().skipped(this->UiFileHandle->FileName)) {
+ return true;
+ }
+ // Register mapping
+ return this->RegisterMapping(incKey.Key, sourceFileHandle);
+ });
+}
+
+bool cmQtAutoMocUicT::JobEvalCacheUicT::FindIncludedUi(
+ cm::string_view sourceDirPrefix, cm::string_view includePrefix)
+{
+ // Clear locations buffer
+ this->SearchLocations.clear();
+
+ auto findUi = [this](std::string const& testPath) -> bool {
+ std::string const fullPath = this->Gen()->CollapseFullPathTS(testPath);
+ cmFileTime fileTime;
+ if (!fileTime.Load(fullPath)) {
+ this->SearchLocations.emplace_back(cmQtAutoGen::ParentDir(fullPath));
+ return false;
+ }
+ // .ui file found in files system!
+ // Get or create .ui file handle
+ SourceFileHandleT& handle = this->UicEval().UiFiles[fullPath];
+ if (!handle) {
+ // The file wasn't registered, yet
+ handle = std::make_shared<SourceFileT>(fullPath);
+ handle->FileTime = fileTime;
+ }
+ this->UiFileHandle = handle;
+ return true;
+ };
+
+ // Vicinity of the source
+ if (!includePrefix.empty()) {
+ if (findUi(cmStrCat(sourceDirPrefix, includePrefix, this->UiName))) {
+ return true;
+ }
+ }
+ if (findUi(cmStrCat(sourceDirPrefix, this->UiName))) {
+ return true;
+ }
+ // Additional AUTOUIC search paths
+ auto const& searchPaths = this->UicConst().SearchPaths;
+ if (!searchPaths.empty()) {
+ for (std::string const& sPath : searchPaths) {
+ if (findUi(cmStrCat(sPath, '/', this->UiName))) {
+ return true;
+ }
+ }
+ if (!includePrefix.empty()) {
+ for (std::string const& sPath : searchPaths) {
+ if (findUi(cmStrCat(sPath, '/', includePrefix, this->UiName))) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool cmQtAutoMocUicT::JobEvalCacheUicT::RegisterMapping(
+ std::string const& includeString, SourceFileHandleT includerFileHandle)
+{
+ auto& Includes = this->Gen()->UicEval().Includes;
+ auto it = Includes.find(includeString);
+ if (it != Includes.end()) {
+ MappingHandleT const& handle = it->second;
+ if (handle->SourceFile != this->UiFileHandle) {
+ // The output file already gets generated - from a different .ui file!
+ std::string files =
+ cmStrCat(" ", this->MessagePath(includerFileHandle->FileName), '\n');
+ for (auto const& item : handle->IncluderFiles) {
+ files += cmStrCat(" ", this->MessagePath(item->FileName), '\n');
+ }
+ this->LogError(
+ GenT::UIC,
+ cmStrCat(
+ "The source files\n", files, "contain the same include string ",
+ Quoted(includeString),
+ ", but\nthe uic file would be generated from different "
+ "user interface files\n ",
+ this->MessagePath(this->UiFileHandle->FileName), " and\n ",
+ this->MessagePath(handle->SourceFile->FileName),
+ ".\nConsider to\n"
+ " - add a directory prefix to a \"ui_<NAME>.h\" include "
+ "(e.g \"sub/ui_<NAME>.h\")\n"
+ " - rename the <NAME>.ui file(s) and adjust the \"ui_<NAME>.h\" "
+ "include(s)\n"));
+ return false;
+ }
+ // Add includer file to existing mapping
+ handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
+ } else {
+ // New mapping handle
+ MappingHandleT handle = std::make_shared<MappingT>();
+ handle->IncludeString = includeString;
+ handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
+ handle->SourceFile = this->UiFileHandle;
+ handle->OutputFile = this->Gen()->AbsoluteIncludePath(includeString);
+ // Register mapping
+ Includes.emplace(includeString, std::move(handle));
+ }
+ return true;
+}
+
+void cmQtAutoMocUicT::JobEvalCacheFinishT::Process()
+{
+ // Add discovered header parse jobs
+ this->Gen()->CreateParseJobs<JobParseHeaderT>(
+ this->MocEval().HeadersDiscovered);
+
+ // Add dependency probing jobs
+ {
+ // Add fence job to ensure all parsing has finished
+ this->Gen()->WorkerPool().EmplaceJob<JobFenceT>();
+ if (this->MocConst().Enabled) {
+ this->Gen()->WorkerPool().EmplaceJob<JobProbeDepsMocT>();
+ }
+ if (this->UicConst().Enabled) {
+ this->Gen()->WorkerPool().EmplaceJob<JobProbeDepsUicT>();
+ }
+ // Add probe finish job
+ this->Gen()->WorkerPool().EmplaceJob<JobProbeDepsFinishT>();
+ }
+}
+
+void cmQtAutoMocUicT::JobProbeDepsMocT::Process()
+{
+ // Create moc header jobs
+ for (auto const& pair : this->MocEval().HeaderMappings) {
+ // Register if this mapping is a candidate for mocs_compilation.cpp
+ bool const compFile = pair.second->IncludeString.empty();
+ if (compFile) {
+ this->MocEval().CompFiles.emplace_back(
+ pair.second->SourceFile->BuildPath);
+ }
+ if (!this->Generate(pair.second, compFile)) {
+ return;
+ }
+ }
+
+ // Create moc source jobs
+ for (auto const& pair : this->MocEval().SourceMappings) {
+ if (!this->Generate(pair.second, false)) {
+ return;
+ }
+ }
+}
+
+bool cmQtAutoMocUicT::JobProbeDepsMocT::Generate(MappingHandleT const& mapping,
+ bool compFile) const
+{
+ std::unique_ptr<std::string> reason;
+ if (this->Log().Verbose()) {
+ reason = cm::make_unique<std::string>();
+ }
+ if (this->Probe(*mapping, reason.get())) {
+ // Register the parent directory for creation
+ this->MocEval().OutputDirs.emplace(
+ cmQtAutoGen::ParentDir(mapping->OutputFile));
+ // Fetch the cache entry for the source file
+ std::string const& sourceFile = mapping->SourceFile->FileName;
+ ParseCacheT::GetOrInsertT cacheEntry =
+ this->BaseEval().ParseCache.GetOrInsert(sourceFile);
+ // Add moc job
+ this->Gen()->WorkerPool().EmplaceJob<JobCompileMocT>(
+ mapping, std::move(reason), std::move(cacheEntry.first));
+ // Check if a moc job for a mocs_compilation.cpp entry was generated
+ if (compFile) {
+ this->MocEval().CompUpdated = true;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoMocUicT::JobProbeDepsMocT::Probe(MappingT const& mapping,
+ std::string* reason) const
+{
+ std::string const& sourceFile = mapping.SourceFile->FileName;
+ std::string const& outputFile = mapping.OutputFile;
+
+ // Test if the output file exists
+ cmFileTime outputFileTime;
+ if (!outputFileTime.Load(outputFile)) {
+ if (reason != nullptr) {
+ *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
+ ", because it doesn't exist, from ",
+ this->MessagePath(sourceFile));
+ }
+ return true;
+ }
+
+ // Test if any setting changed
+ if (this->MocConst().SettingsChanged) {
+ if (reason != nullptr) {
+ *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
+ ", because the uic settings changed, from ",
+ this->MessagePath(sourceFile));
+ }
+ return true;
+ }
+
+ // Test if the source file is newer
+ if (outputFileTime.Older(mapping.SourceFile->FileTime)) {
+ if (reason != nullptr) {
+ *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
+ ", because it's older than its source file, from ",
+ this->MessagePath(sourceFile));
+ }
+ return true;
+ }
+
+ // Test if the moc_predefs file is newer
+ if (!this->MocConst().PredefsFileAbs.empty()) {
+ if (outputFileTime.Older(this->MocEval().PredefsTime)) {
+ if (reason != nullptr) {
+ *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
+ ", because it's older than ",
+ this->MessagePath(this->MocConst().PredefsFileAbs),
+ ", from ", this->MessagePath(sourceFile));
+ }
+ return true;
+ }
+ }
+
+ // Test if the moc executable is newer
+ if (outputFileTime.Older(this->MocConst().ExecutableTime)) {
+ if (reason != nullptr) {
+ *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
+ ", because it's older than the moc executable, from ",
+ this->MessagePath(sourceFile));
+ }
+ return true;
+ }
+
+ // Test if a dependency file is newer
+ {
+ // Check dependency timestamps
+ std::string const sourceDir = SubDirPrefix(sourceFile);
+ auto& dependencies = mapping.SourceFile->ParseData->Moc.Depends;
+ for (auto it = dependencies.begin(); it != dependencies.end(); ++it) {
+ auto& dep = *it;
+
+ // Find dependency file
+ auto const depMatch = this->FindDependency(sourceDir, dep);
+ if (depMatch.first.empty()) {
+ if (reason != nullptr) {
+ *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
+ " from ", this->MessagePath(sourceFile),
+ ", because its dependency ",
+ this->MessagePath(dep), " vanished.");
+ }
+ dependencies.erase(it);
+ this->BaseEval().ParseCacheChanged = true;
+ return true;
+ }
+
+ // Test if dependency file is older
+ if (outputFileTime.Older(depMatch.second)) {
+ if (reason != nullptr) {
+ *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
+ ", because it's older than its dependency file ",
+ this->MessagePath(depMatch.first), ", from ",
+ this->MessagePath(sourceFile));
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+std::pair<std::string, cmFileTime>
+cmQtAutoMocUicT::JobProbeDepsMocT::FindDependency(
+ std::string const& sourceDir, std::string const& includeString) const
+{
+ using ResPair = std::pair<std::string, cmFileTime>;
+ // moc's dependency file contains absolute paths
+ if (this->MocConst().CanOutputDependencies) {
+ ResPair res{ includeString, {} };
+ if (res.second.Load(res.first)) {
+ return res;
+ }
+ return {};
+ }
+ // Search in vicinity of the source
+ {
+ ResPair res{ sourceDir + includeString, {} };
+ if (res.second.Load(res.first)) {
+ return res;
+ }
+ }
+ // Search in include directories
+ for (std::string const& includePath : this->MocConst().IncludePaths) {
+ ResPair res{ cmStrCat(includePath, '/', includeString), {} };
+ if (res.second.Load(res.first)) {
+ return res;
+ }
+ }
+ // Return empty
+ return ResPair();
+}
+
+void cmQtAutoMocUicT::JobProbeDepsUicT::Process()
+{
+ for (auto const& pair : this->Gen()->UicEval().Includes) {
+ MappingHandleT const& mapping = pair.second;
+ std::unique_ptr<std::string> reason;
+ if (this->Log().Verbose()) {
+ reason = cm::make_unique<std::string>();
+ }
+ if (!this->Probe(*mapping, reason.get())) {
+ continue;
+ }
+
+ // Register the parent directory for creation
+ this->UicEval().OutputDirs.emplace(
+ cmQtAutoGen::ParentDir(mapping->OutputFile));
+ // Add uic job
+ this->Gen()->WorkerPool().EmplaceJob<JobCompileUicT>(mapping,
+ std::move(reason));
+ }
+}
+
+bool cmQtAutoMocUicT::JobProbeDepsUicT::Probe(MappingT const& mapping,
+ std::string* reason) const
+{
+ std::string const& sourceFile = mapping.SourceFile->FileName;
+ std::string const& outputFile = mapping.OutputFile;
+
+ // Test if the build file exists
+ cmFileTime outputFileTime;
+ if (!outputFileTime.Load(outputFile)) {
+ if (reason != nullptr) {
+ *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
+ ", because it doesn't exist, from ",
+ this->MessagePath(sourceFile));
+ }
+ return true;
+ }
+
+ // Test if the uic settings changed
+ if (this->UicConst().SettingsChanged) {
+ if (reason != nullptr) {
+ *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
+ ", because the uic settings changed, from ",
+ this->MessagePath(sourceFile));
+ }
+ return true;
+ }
+
+ // Test if the source file is newer
+ if (outputFileTime.Older(mapping.SourceFile->FileTime)) {
+ if (reason != nullptr) {
+ *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
+ " because it's older than the source file ",
+ this->MessagePath(sourceFile));
+ }
+ return true;
+ }
+
+ // Test if the uic executable is newer
+ if (outputFileTime.Older(this->UicConst().ExecutableTime)) {
+ if (reason != nullptr) {
+ *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
+ ", because it's older than the uic executable, from ",
+ this->MessagePath(sourceFile));
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void cmQtAutoMocUicT::JobProbeDepsFinishT::Process()
+{
+ // Create output directories
+ {
+ using StringSet = std::unordered_set<std::string>;
+ auto createDirs = [this](GenT genType, StringSet const& dirSet) {
+ for (std::string const& dirName : dirSet) {
+ if (!cmSystemTools::MakeDirectory(dirName)) {
+ this->LogError(genType,
+ cmStrCat("Creating directory ",
+ this->MessagePath(dirName), " failed."));
+ return;
+ }
+ }
+ };
+ if (this->MocConst().Enabled && this->UicConst().Enabled) {
+ StringSet outputDirs = this->MocEval().OutputDirs;
+ outputDirs.insert(this->UicEval().OutputDirs.begin(),
+ this->UicEval().OutputDirs.end());
+ createDirs(GenT::GEN, outputDirs);
+ } else if (this->MocConst().Enabled) {
+ createDirs(GenT::MOC, this->MocEval().OutputDirs);
+ } else if (this->UicConst().Enabled) {
+ createDirs(GenT::UIC, this->UicEval().OutputDirs);
+ }
+ }
+
+ if (this->MocConst().Enabled) {
+ // Add mocs compilations job
+ this->Gen()->WorkerPool().EmplaceJob<JobMocsCompilationT>();
+ }
+
+ if (!this->BaseConst().DepFile.empty()) {
+ // Add job to merge dep files
+ this->Gen()->WorkerPool().EmplaceJob<JobDepFilesMergeT>();
+ }
+
+ // Add finish job
+ this->Gen()->WorkerPool().EmplaceJob<JobFinishT>();
+}
+
+void cmQtAutoMocUicT::JobCompileMocT::Process()
+{
+ std::string const& sourceFile = this->Mapping->SourceFile->FileName;
+ std::string const& outputFile = this->Mapping->OutputFile;
+
+ // Compose moc command
+ std::vector<std::string> cmd;
+ {
+ // Reserve large enough
+ cmd.reserve(this->MocConst().OptionsDefinitions.size() +
+ this->MocConst().OptionsIncludes.size() +
+ this->MocConst().OptionsExtra.size() + 16);
+ cmd.push_back(this->MocConst().Executable);
+ // Add definitions
+ cm::append(cmd, this->MocConst().OptionsDefinitions);
+ // Add includes
+ cm::append(cmd, this->MocConst().OptionsIncludes);
+ // Add predefs include
+ if (!this->MocConst().PredefsFileAbs.empty()) {
+ cmd.emplace_back("--include");
+ cmd.push_back(this->MocConst().PredefsFileAbs);
+ }
+ // Add path prefix on demand
+ if (this->MocConst().PathPrefix && this->Mapping->SourceFile->IsHeader) {
+ for (std::string const& dir : this->MocConst().IncludePaths) {
+ cm::string_view prefix = sourceFile;
+ if (cmHasPrefix(prefix, dir)) {
+ prefix.remove_prefix(dir.size());
+ if (cmHasPrefix(prefix, '/')) {
+ prefix.remove_prefix(1);
+ auto slashPos = prefix.rfind('/');
+ if (slashPos != cm::string_view::npos) {
+ cmd.emplace_back("-p");
+ cmd.emplace_back(prefix.substr(0, slashPos));
+ } else {
+ cmd.emplace_back("-p");
+ cmd.emplace_back("./");
+ }
+ break;
+ }
+ }
+ }
+ }
+ // Add extra options
+ cm::append(cmd, this->MocConst().OptionsExtra);
+ if (this->MocConst().CanOutputDependencies) {
+ cmd.emplace_back("--output-dep-file");
+ }
+ // Add output file
+ cmd.emplace_back("-o");
+ cmd.push_back(outputFile);
+ // Add source file
+ cmd.push_back(sourceFile);
+ }
+
+ // Execute moc command
+ cmWorkerPool::ProcessResultT result;
+ if (!this->RunProcess(GenT::MOC, result, cmd, this->Reason.get())) {
+ // Moc command failed
+ std::string includers;
+ if (!this->Mapping->IncluderFiles.empty()) {
+ includers = "included by\n";
+ for (auto const& item : this->Mapping->IncluderFiles) {
+ includers += cmStrCat(" ", this->MessagePath(item->FileName), '\n');
+ }
+ }
+ this->LogCommandError(GenT::MOC,
+ cmStrCat("The moc process failed to compile\n ",
+ this->MessagePath(sourceFile), "\ninto\n ",
+ this->MessagePath(outputFile), '\n',
+ includers, result.ErrorMessage),
+ cmd, result.StdOut);
+ return;
+ }
+
+ // Moc command success. Print moc output.
+ if (!result.StdOut.empty()) {
+ this->Log().Info(GenT::MOC, result.StdOut);
+ }
+
+ // Extract dependencies from the dep file moc generated for us
+ if (this->MocConst().CanOutputDependencies) {
+ const std::string depfile = outputFile + ".d";
+ if (this->Log().Verbose()) {
+ this->Log().Info(
+ GenT::MOC, "Reading dependencies from " + this->MessagePath(depfile));
+ }
+ if (!cmSystemTools::FileExists(depfile)) {
+ this->Log().Warning(GenT::MOC,
+ "Dependency file " + this->MessagePath(depfile) +
+ " does not exist.");
+ return;
+ }
+ this->CacheEntry->Moc.Depends = dependenciesFromDepFile(depfile.c_str());
+ }
+}
+
+void cmQtAutoMocUicT::JobCompileUicT::Process()
+{
+ std::string const& sourceFile = this->Mapping->SourceFile->FileName;
+ std::string const& outputFile = this->Mapping->OutputFile;
+
+ // Compose uic command
+ std::vector<std::string> cmd;
+ cmd.push_back(this->UicConst().Executable);
+ {
+ std::vector<std::string> allOpts = this->UicConst().Options;
+ auto optionIt = this->UicConst().UiFiles.find(sourceFile);
+ if (optionIt != this->UicConst().UiFiles.end()) {
+ UicMergeOptions(allOpts, optionIt->second.Options,
+ (this->BaseConst().QtVersion.Major == 5));
+ }
+ cm::append(cmd, allOpts);
+ }
+ cmd.emplace_back("-o");
+ cmd.emplace_back(outputFile);
+ cmd.emplace_back(sourceFile);
+
+ cmWorkerPool::ProcessResultT result;
+ if (this->RunProcess(GenT::UIC, result, cmd, this->Reason.get())) {
+ // Uic command success
+ // Print uic output
+ if (!result.StdOut.empty()) {
+ this->Log().Info(GenT::UIC, result.StdOut);
+ }
+ } else {
+ // Uic command failed
+ std::string includers;
+ for (auto const& item : this->Mapping->IncluderFiles) {
+ includers += cmStrCat(" ", this->MessagePath(item->FileName), '\n');
+ }
+ this->LogCommandError(GenT::UIC,
+ cmStrCat("The uic process failed to compile\n ",
+ this->MessagePath(sourceFile), "\ninto\n ",
+ this->MessagePath(outputFile),
+ "\nincluded by\n", includers,
+ result.ErrorMessage),
+ cmd, result.StdOut);
+ }
+}
+
+void cmQtAutoMocUicT::JobMocsCompilationT::Process()
+{
+ // Compose mocs compilation file content
+ std::string content =
+ "// This file is autogenerated. Changes will be overwritten.\n";
+
+ if (this->MocEval().CompFiles.empty()) {
+ // Placeholder content
+ content += "// No files found that require moc or the moc files are "
+ "included\n"
+ "enum some_compilers { need_more_than_nothing };\n";
+ } else {
+ // Valid content
+ const bool mc = this->BaseConst().MultiConfig;
+ cm::string_view const wrapFront = mc ? "#include <" : "#include \"";
+ cm::string_view const wrapBack = mc ? ">\n" : "\"\n";
+ content += cmWrap(wrapFront, this->MocEval().CompFiles, wrapBack, "");
+ }
+
+ std::string const& compAbs = this->MocConst().CompFileAbs;
+ if (cmQtAutoGenerator::FileDiffers(compAbs, content)) {
+ // Actually write mocs compilation file
+ if (this->Log().Verbose()) {
+ this->Log().Info(
+ GenT::MOC, "Generating MOC compilation " + this->MessagePath(compAbs));
+ }
+ if (!FileWrite(compAbs, content)) {
+ this->LogError(GenT::MOC,
+ cmStrCat("Writing MOC compilation ",
+ this->MessagePath(compAbs), " failed."));
+ }
+ } else if (this->MocEval().CompUpdated) {
+ // Only touch mocs compilation file
+ if (this->Log().Verbose()) {
+ this->Log().Info(
+ GenT::MOC, "Touching MOC compilation " + this->MessagePath(compAbs));
+ }
+ if (!cmSystemTools::Touch(compAbs, false)) {
+ this->LogError(GenT::MOC,
+ cmStrCat("Touching MOC compilation ",
+ this->MessagePath(compAbs), " failed."));
+ }
+ }
+}
+
+/*
+ * Escapes paths for Ninja depfiles.
+ * This is a re-implementation of what moc does when writing depfiles.
+ */
+std::string escapeDependencyPath(cm::string_view path)
+{
+ std::string escapedPath;
+ escapedPath.reserve(path.size());
+ const size_t s = path.size();
+ int backslashCount = 0;
+ for (size_t i = 0; i < s; ++i) {
+ if (path[i] == '\\') {
+ ++backslashCount;
+ } else {
+ if (path[i] == '$') {
+ escapedPath.push_back('$');
+ } else if (path[i] == '#') {
+ escapedPath.push_back('\\');
+ } else if (path[i] == ' ') {
+ // Double the amount of written backslashes,
+ // and add one more to escape the space.
+ while (backslashCount-- >= 0) {
+ escapedPath.push_back('\\');
+ }
+ }
+ backslashCount = 0;
+ }
+ escapedPath.push_back(path[i]);
+ }
+ return escapedPath;
+}
+
+/*
+ * Return the initial dependencies of the merged depfile.
+ * Those are dependencies from the project files, not from moc runs.
+ */
+std::vector<std::string>
+cmQtAutoMocUicT::JobDepFilesMergeT::initialDependencies() const
+{
+ std::vector<std::string> dependencies;
+ dependencies.reserve(this->BaseConst().ListFiles.size() +
+ this->BaseEval().Headers.size() +
+ this->BaseEval().Sources.size());
+ cm::append(dependencies, this->BaseConst().ListFiles);
+ auto append_file_path =
+ [&dependencies](const SourceFileMapT::value_type& p) {
+ dependencies.push_back(p.first);
+ };
+ std::for_each(this->BaseEval().Headers.begin(),
+ this->BaseEval().Headers.end(), append_file_path);
+ std::for_each(this->BaseEval().Sources.begin(),
+ this->BaseEval().Sources.end(), append_file_path);
+ return dependencies;
+}
+
+void cmQtAutoMocUicT::JobDepFilesMergeT::Process()
+{
+ if (this->Log().Verbose()) {
+ this->Log().Info(
+ GenT::MOC,
+ cmStrCat("Merging MOC dependencies into ",
+ this->MessagePath(this->BaseConst().DepFile.c_str())));
+ }
+ auto processDepFile =
+ [](const std::string& mocOutputFile) -> std::vector<std::string> {
+ std::string f = mocOutputFile + ".d";
+ if (!cmSystemTools::FileExists(f)) {
+ return {};
+ }
+ return dependenciesFromDepFile(f.c_str());
+ };
+
+ std::vector<std::string> dependencies = this->initialDependencies();
+ ParseCacheT& parseCache = this->BaseEval().ParseCache;
+ auto processMappingEntry = [&](const MappingMapT::value_type& m) {
+ auto cacheEntry = parseCache.GetOrInsert(m.first);
+ if (cacheEntry.first->Moc.Depends.empty()) {
+ cacheEntry.first->Moc.Depends = processDepFile(m.second->OutputFile);
+ }
+ dependencies.insert(dependencies.end(),
+ cacheEntry.first->Moc.Depends.begin(),
+ cacheEntry.first->Moc.Depends.end());
+ };
+
+ std::for_each(this->MocEval().HeaderMappings.begin(),
+ this->MocEval().HeaderMappings.end(), processMappingEntry);
+ std::for_each(this->MocEval().SourceMappings.begin(),
+ this->MocEval().SourceMappings.end(), processMappingEntry);
+
+ // Remove SKIP_AUTOMOC files
+ dependencies.erase(std::remove_if(dependencies.begin(), dependencies.end(),
+ [this](const std::string& dep) {
+ return this->MocConst().skipped(dep);
+ }),
+ dependencies.end());
+
+ // Remove duplicates to make the depfile smaller
+ std::sort(dependencies.begin(), dependencies.end());
+ dependencies.erase(std::unique(dependencies.begin(), dependencies.end()),
+ dependencies.end());
+
+ // Add form files
+ for (const auto& uif : this->UicEval().UiFiles) {
+ dependencies.push_back(uif.first);
+ }
+
+ // Write the file
+ cmsys::ofstream ofs;
+ ofs.open(this->BaseConst().DepFile.c_str(),
+ (std::ios::out | std::ios::binary | std::ios::trunc));
+ if (!ofs) {
+ this->LogError(GenT::GEN,
+ cmStrCat("Cannot open ",
+ this->MessagePath(this->BaseConst().DepFile),
+ " for writing."));
+ return;
+ }
+ ofs << this->BaseConst().DepFileRuleName << ": \\\n";
+ for (const std::string& file : dependencies) {
+ ofs << '\t' << escapeDependencyPath(file) << " \\\n";
+ if (!ofs.good()) {
+ this->LogError(GenT::GEN,
+ cmStrCat("Writing depfile",
+ this->MessagePath(this->BaseConst().DepFile),
+ " failed."));
+ return;
+ }
+ }
+
+ // Add the CMake executable to re-new cache data if necessary.
+ // Also, this is the last entry, so don't add a backslash.
+ ofs << '\t' << escapeDependencyPath(this->BaseConst().CMakeExecutable)
+ << '\n';
+}
+
+void cmQtAutoMocUicT::JobFinishT::Process()
+{
+ this->Gen()->AbortSuccess();
+}
+
+cmQtAutoMocUicT::cmQtAutoMocUicT()
+ : cmQtAutoGenerator(GenT::GEN)
+{
+}
+cmQtAutoMocUicT::~cmQtAutoMocUicT() = default;
+
+bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
+{
+ // -- Required settings
+ if (!info.GetBool("MULTI_CONFIG", this->BaseConst_.MultiConfig, true) ||
+ !info.GetUInt("QT_VERSION_MAJOR", this->BaseConst_.QtVersion.Major,
+ true) ||
+ !info.GetUInt("QT_VERSION_MINOR", this->BaseConst_.QtVersion.Minor,
+ true) ||
+ !info.GetUInt("PARALLEL", this->BaseConst_.ThreadCount, false) ||
+ !info.GetString("BUILD_DIR", this->BaseConst_.AutogenBuildDir, true) ||
+ !info.GetStringConfig("INCLUDE_DIR", this->BaseConst_.AutogenIncludeDir,
+ true) ||
+ !info.GetString("CMAKE_EXECUTABLE", this->BaseConst_.CMakeExecutable,
+ true) ||
+ !info.GetStringConfig("PARSE_CACHE_FILE",
+ this->BaseConst_.ParseCacheFile, true) ||
+ !info.GetString("DEP_FILE", this->BaseConst_.DepFile, false) ||
+ !info.GetString("DEP_FILE_RULE_NAME", this->BaseConst_.DepFileRuleName,
+ false) ||
+ !info.GetStringConfig("SETTINGS_FILE", this->SettingsFile_, true) ||
+ !info.GetArray("CMAKE_LIST_FILES", this->BaseConst_.ListFiles, true) ||
+ !info.GetArray("HEADER_EXTENSIONS", this->BaseConst_.HeaderExtensions,
+ true) ||
+ !info.GetString("QT_MOC_EXECUTABLE", this->MocConst_.Executable,
+ false) ||
+ !info.GetString("QT_UIC_EXECUTABLE", this->UicConst_.Executable,
+ false)) {
+ return false;
+ }
+
+ // -- Checks
+ if (!this->BaseConst_.CMakeExecutableTime.Load(
+ this->BaseConst_.CMakeExecutable)) {
+ return info.LogError(
+ cmStrCat("The CMake executable ",
+ this->MessagePath(this->BaseConst_.CMakeExecutable),
+ " does not exist."));
+ }
+
+ // -- Evaluate values
+ this->BaseConst_.ThreadCount =
+ std::min(this->BaseConst_.ThreadCount, ParallelMax);
+ this->WorkerPool_.SetThreadCount(this->BaseConst_.ThreadCount);
+
+ // -- Moc
+ if (!this->MocConst_.Executable.empty()) {
+ // -- Moc is enabled
+ this->MocConst_.Enabled = true;
+
+ // -- Temporary buffers
+ struct
+ {
+ std::vector<std::string> MacroNames;
+ std::vector<std::string> DependFilters;
+ } tmp;
+
+ // -- Required settings
+ if (!info.GetBool("MOC_RELAXED_MODE", this->MocConst_.RelaxedMode,
+ false) ||
+ !info.GetBool("MOC_PATH_PREFIX", this->MocConst_.PathPrefix, true) ||
+ !info.GetArray("MOC_SKIP", this->MocConst_.SkipList, false) ||
+ !info.GetArrayConfig("MOC_DEFINITIONS", this->MocConst_.Definitions,
+ false) ||
+ !info.GetArrayConfig("MOC_INCLUDES", this->MocConst_.IncludePaths,
+ false) ||
+ !info.GetArray("MOC_OPTIONS", this->MocConst_.OptionsExtra, false) ||
+ !info.GetStringConfig("MOC_COMPILATION_FILE",
+ this->MocConst_.CompFileAbs, true) ||
+ !info.GetArray("MOC_PREDEFS_CMD", this->MocConst_.PredefsCmd, false) ||
+ !info.GetStringConfig("MOC_PREDEFS_FILE",
+ this->MocConst_.PredefsFileAbs,
+ !this->MocConst_.PredefsCmd.empty()) ||
+ !info.GetArray("MOC_MACRO_NAMES", tmp.MacroNames, true) ||
+ !info.GetArray("MOC_DEPEND_FILTERS", tmp.DependFilters, false)) {
+ return false;
+ }
+
+ // -- Evaluate settings
+ for (std::string const& item : tmp.MacroNames) {
+ this->MocConst_.MacroFilters.emplace_back(
+ item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
+ }
+ // Can moc output dependencies or do we need to setup dependency filters?
+ if (this->BaseConst_.QtVersion >= IntegerVersion(5, 15)) {
+ this->MocConst_.CanOutputDependencies = true;
+ } else {
+ Json::Value const& val = info.GetValue("MOC_DEPEND_FILTERS");
+ if (!val.isArray()) {
+ return info.LogError("MOC_DEPEND_FILTERS JSON value is not an array.");
+ }
+ Json::ArrayIndex const arraySize = val.size();
+ for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) {
+ // Test entry closure
+ auto testEntry = [&info, ii](bool test, cm::string_view msg) -> bool {
+ if (!test) {
+ info.LogError(
+ cmStrCat("MOC_DEPEND_FILTERS filter ", ii, ": ", msg));
+ }
+ return !test;
+ };
+
+ Json::Value const& pairVal = val[ii];
+
+ if (testEntry(pairVal.isArray(), "JSON value is not an array.") ||
+ testEntry(pairVal.size() == 2, "JSON array size invalid.")) {
+ return false;
+ }
+
+ Json::Value const& keyVal = pairVal[0u];
+ Json::Value const& expVal = pairVal[1u];
+ if (testEntry(keyVal.isString(),
+ "JSON value for keyword is not a string.") ||
+ testEntry(expVal.isString(),
+ "JSON value for regular expression is not a string.")) {
+ return false;
+ }
+
+ std::string const key = keyVal.asString();
+ std::string const exp = expVal.asString();
+ if (testEntry(!key.empty(), "Keyword is empty.") ||
+ testEntry(!exp.empty(), "Regular expression is empty.")) {
+ return false;
+ }
+
+ this->MocConst_.DependFilters.emplace_back(key, exp);
+ if (testEntry(
+ this->MocConst_.DependFilters.back().Exp.is_valid(),
+ cmStrCat("Regular expression compilation failed.\nKeyword: ",
+ Quoted(key), "\nExpression: ", Quoted(exp)))) {
+ return false;
+ }
+ }
+ }
+ // Check if moc executable exists (by reading the file time)
+ if (!this->MocConst_.ExecutableTime.Load(this->MocConst_.Executable)) {
+ return info.LogError(cmStrCat(
+ "The moc executable ", this->MessagePath(this->MocConst_.Executable),
+ " does not exist."));
+ }
+ }
+
+ // -- Uic
+ if (!this->UicConst_.Executable.empty()) {
+ // Uic is enabled
+ this->UicConst_.Enabled = true;
+
+ // -- Required settings
+ if (!info.GetArray("UIC_SKIP", this->UicConst_.SkipList, false) ||
+ !info.GetArray("UIC_SEARCH_PATHS", this->UicConst_.SearchPaths,
+ false) ||
+ !info.GetArrayConfig("UIC_OPTIONS", this->UicConst_.Options, false)) {
+ return false;
+ }
+ // .ui files
+ {
+ Json::Value const& val = info.GetValue("UIC_UI_FILES");
+ if (!val.isArray()) {
+ return info.LogError("UIC_UI_FILES JSON value is not an array.");
+ }
+ Json::ArrayIndex const arraySize = val.size();
+ for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) {
+ // Test entry closure
+ auto testEntry = [&info, ii](bool test, cm::string_view msg) -> bool {
+ if (!test) {
+ info.LogError(cmStrCat("UIC_UI_FILES entry ", ii, ": ", msg));
+ }
+ return !test;
+ };
+
+ Json::Value const& entry = val[ii];
+ if (testEntry(entry.isArray(), "JSON value is not an array.") ||
+ testEntry(entry.size() == 2, "JSON array size invalid.")) {
+ return false;
+ }
+
+ Json::Value const& entryName = entry[0u];
+ Json::Value const& entryOptions = entry[1u];
+ if (testEntry(entryName.isString(),
+ "JSON value for name is not a string.") ||
+ testEntry(entryOptions.isArray(),
+ "JSON value for options is not an array.")) {
+ return false;
+ }
+
+ auto& uiFile = this->UicConst_.UiFiles[entryName.asString()];
+ InfoT::GetJsonArray(uiFile.Options, entryOptions);
+ }
+ }
+
+ // -- Evaluate settings
+ // Check if uic executable exists (by reading the file time)
+ if (!this->UicConst_.ExecutableTime.Load(this->UicConst_.Executable)) {
+ return info.LogError(cmStrCat(
+ "The uic executable ", this->MessagePath(this->UicConst_.Executable),
+ " does not exist."));
+ }
+ }
+
+ // -- Headers
+ {
+ Json::Value const& val = info.GetValue("HEADERS");
+ if (!val.isArray()) {
+ return info.LogError("HEADERS JSON value is not an array.");
+ }
+ Json::ArrayIndex const arraySize = val.size();
+ for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) {
+ // Test entry closure
+ auto testEntry = [&info, ii](bool test, cm::string_view msg) -> bool {
+ if (!test) {
+ info.LogError(cmStrCat("HEADERS entry ", ii, ": ", msg));
+ }
+ return !test;
+ };
+
+ Json::Value const& entry = val[ii];
+ if (testEntry(entry.isArray(), "JSON value is not an array.") ||
+ testEntry(entry.size() == 4, "JSON array size invalid.")) {
+ return false;
+ }
+
+ Json::Value const& entryName = entry[0u];
+ Json::Value const& entryFlags = entry[1u];
+ Json::Value const& entryBuild = entry[2u];
+ Json::Value const& entryConfigs = entry[3u];
+ if (testEntry(entryName.isString(),
+ "JSON value for name is not a string.") ||
+ testEntry(entryFlags.isString(),
+ "JSON value for flags is not a string.") ||
+ testEntry(entryConfigs.isNull() || entryConfigs.isArray(),
+ "JSON value for configs is not null or array.") ||
+ testEntry(entryBuild.isString(),
+ "JSON value for build path is not a string.")) {
+ return false;
+ }
+
+ std::string name = entryName.asString();
+ std::string flags = entryFlags.asString();
+ std::string build = entryBuild.asString();
+ if (testEntry(flags.size() == 2, "Invalid flags string size")) {
+ return false;
+ }
+
+ if (entryConfigs.isArray()) {
+ bool configFound = false;
+ Json::ArrayIndex const configArraySize = entryConfigs.size();
+ for (Json::ArrayIndex ci = 0; ci != configArraySize; ++ci) {
+ Json::Value const& config = entryConfigs[ci];
+ if (testEntry(config.isString(),
+ "JSON value in config array is not a string.")) {
+ return false;
+ }
+ configFound = configFound || config.asString() == this->InfoConfig();
+ }
+ if (!configFound) {
+ continue;
+ }
+ }
+
+ cmFileTime fileTime;
+ if (!fileTime.Load(name)) {
+ return info.LogError(cmStrCat(
+ "The header file ", this->MessagePath(name), " does not exist."));
+ }
+
+ SourceFileHandleT sourceHandle = std::make_shared<SourceFileT>(name);
+ sourceHandle->FileTime = fileTime;
+ sourceHandle->IsHeader = true;
+ sourceHandle->Moc = (flags[0] == 'M');
+ sourceHandle->Uic = (flags[1] == 'U');
+ if (sourceHandle->Moc && this->MocConst().Enabled) {
+ if (build.empty()) {
+ return info.LogError(
+ cmStrCat("Header file ", ii, " build path is empty"));
+ }
+ sourceHandle->BuildPath = std::move(build);
+ }
+ this->BaseEval().Headers.emplace(std::move(name),
+ std::move(sourceHandle));
+ }
+ }
+
+ // -- Sources
+ {
+ Json::Value const& val = info.GetValue("SOURCES");
+ if (!val.isArray()) {
+ return info.LogError("SOURCES JSON value is not an array.");
+ }
+ Json::ArrayIndex const arraySize = val.size();
+ for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) {
+ // Test entry closure
+ auto testEntry = [&info, ii](bool test, cm::string_view msg) -> bool {
+ if (!test) {
+ info.LogError(cmStrCat("SOURCES entry ", ii, ": ", msg));
+ }
+ return !test;
+ };
+
+ Json::Value const& entry = val[ii];
+ if (testEntry(entry.isArray(), "JSON value is not an array.") ||
+ testEntry(entry.size() == 3, "JSON array size invalid.")) {
+ return false;
+ }
+
+ Json::Value const& entryName = entry[0u];
+ Json::Value const& entryFlags = entry[1u];
+ Json::Value const& entryConfigs = entry[2u];
+ if (testEntry(entryName.isString(),
+ "JSON value for name is not a string.") ||
+ testEntry(entryFlags.isString(),
+ "JSON value for flags is not a string.") ||
+ testEntry(entryConfigs.isNull() || entryConfigs.isArray(),
+ "JSON value for configs is not null or array.")) {
+ return false;
+ }
+
+ std::string name = entryName.asString();
+ std::string flags = entryFlags.asString();
+ if (testEntry(flags.size() == 2, "Invalid flags string size")) {
+ return false;
+ }
+
+ if (entryConfigs.isArray()) {
+ bool configFound = false;
+ Json::ArrayIndex const configArraySize = entryConfigs.size();
+ for (Json::ArrayIndex ci = 0; ci != configArraySize; ++ci) {
+ Json::Value const& config = entryConfigs[ci];
+ if (testEntry(config.isString(),
+ "JSON value in config array is not a string.")) {
+ return false;
+ }
+ configFound = configFound || config.asString() == this->InfoConfig();
+ }
+ if (!configFound) {
+ continue;
+ }
+ }
+
+ cmFileTime fileTime;
+ if (!fileTime.Load(name)) {
+ return info.LogError(cmStrCat(
+ "The source file ", this->MessagePath(name), " does not exist."));
+ }
+
+ SourceFileHandleT sourceHandle = std::make_shared<SourceFileT>(name);
+ sourceHandle->FileTime = fileTime;
+ sourceHandle->IsHeader = false;
+ sourceHandle->Moc = (flags[0] == 'M');
+ sourceHandle->Uic = (flags[1] == 'U');
+ this->BaseEval().Sources.emplace(std::move(name),
+ std::move(sourceHandle));
+ }
+ }
+
+ // -- Init derived information
+ // Moc variables
+ if (this->MocConst().Enabled) {
+ // Compose moc includes list
+ {
+ // Compute framework paths
+ std::set<std::string> frameworkPaths;
+ for (std::string const& path : this->MocConst().IncludePaths) {
+ // Extract framework path
+ if (cmHasLiteralSuffix(path, ".framework/Headers")) {
+ // Go up twice to get to the framework root
+ std::vector<std::string> pathComponents;
+ cmSystemTools::SplitPath(path, pathComponents);
+ frameworkPaths.emplace(cmSystemTools::JoinPath(
+ pathComponents.begin(), pathComponents.end() - 2));
+ }
+ }
+ // Reserve options
+ this->MocConst_.OptionsIncludes.reserve(
+ this->MocConst().IncludePaths.size() + frameworkPaths.size() * 2);
+ // Append includes
+ for (std::string const& path : this->MocConst().IncludePaths) {
+ this->MocConst_.OptionsIncludes.emplace_back("-I" + path);
+ }
+ // Append framework includes
+ for (std::string const& path : frameworkPaths) {
+ this->MocConst_.OptionsIncludes.emplace_back("-F");
+ this->MocConst_.OptionsIncludes.push_back(path);
+ }
+ }
+
+ // Compose moc definitions list
+ {
+ this->MocConst_.OptionsDefinitions.reserve(
+ this->MocConst().Definitions.size());
+ for (std::string const& def : this->MocConst().Definitions) {
+ this->MocConst_.OptionsDefinitions.emplace_back("-D" + def);
+ }
+ }
+ }
+
+ return true;
+}
+
+template <class JOBTYPE>
+void cmQtAutoMocUicT::CreateParseJobs(SourceFileMapT const& sourceMap)
+{
+ cmFileTime const parseCacheTime = this->BaseEval().ParseCacheTime;
+ ParseCacheT& parseCache = this->BaseEval().ParseCache;
+ for (const auto& src : sourceMap) {
+ // Get or create the file parse data reference
+ ParseCacheT::GetOrInsertT cacheEntry = parseCache.GetOrInsert(src.first);
+ src.second->ParseData = std::move(cacheEntry.first);
+ // Create a parse job if the cache file was missing or is older
+ if (cacheEntry.second || src.second->FileTime.Newer(parseCacheTime)) {
+ this->BaseEval().ParseCacheChanged = true;
+ this->WorkerPool().EmplaceJob<JOBTYPE>(src.second);
+ }
+ }
+}
+
+/** Concurrently callable implementation of cmSystemTools::CollapseFullPath */
+std::string cmQtAutoMocUicT::CollapseFullPathTS(std::string const& path) const
+{
+ std::lock_guard<std::mutex> guard(this->CMakeLibMutex_);
+ return cmSystemTools::CollapseFullPath(path,
+ this->ProjectDirs().CurrentSource);
+}
+
+void cmQtAutoMocUicT::InitJobs()
+{
+ // Add moc_predefs.h job
+ if (this->MocConst().Enabled && !this->MocConst().PredefsCmd.empty()) {
+ this->WorkerPool().EmplaceJob<JobMocPredefsT>();
+ }
+
+ // Add header parse jobs
+ this->CreateParseJobs<JobParseHeaderT>(this->BaseEval().Headers);
+ // Add source parse jobs
+ this->CreateParseJobs<JobParseSourceT>(this->BaseEval().Sources);
+
+ // Add parse cache evaluations jobs
+ {
+ // Add a fence job to ensure all parsing has finished
+ this->WorkerPool().EmplaceJob<JobFenceT>();
+ if (this->MocConst().Enabled) {
+ this->WorkerPool().EmplaceJob<JobEvalCacheMocT>();
+ }
+ if (this->UicConst().Enabled) {
+ this->WorkerPool().EmplaceJob<JobEvalCacheUicT>();
+ }
+ // Add evaluate job
+ this->WorkerPool().EmplaceJob<JobEvalCacheFinishT>();
+ }
+}
+
+bool cmQtAutoMocUicT::Process()
+{
+ this->SettingsFileRead();
+ this->ParseCacheRead();
+ if (!this->CreateDirectories()) {
+ return false;
+ }
+ this->InitJobs();
+ if (!this->WorkerPool_.Process(this)) {
+ return false;
+ }
+ if (this->JobError_) {
+ return false;
+ }
+ if (!this->ParseCacheWrite()) {
+ return false;
+ }
+ if (!this->SettingsFileWrite()) {
+ return false;
+ }
+ return true;
+}
+
+void cmQtAutoMocUicT::SettingsFileRead()
+{
+ // Compose current settings strings
+ {
+ cmCryptoHash cryptoHash(cmCryptoHash::AlgoSHA256);
+ auto cha = [&cryptoHash](cm::string_view value) {
+ cryptoHash.Append(value);
+ cryptoHash.Append(";");
+ };
+
+ if (this->MocConst_.Enabled) {
+ cryptoHash.Initialize();
+ cha(this->MocConst().Executable);
+ for (auto const& item : this->MocConst().OptionsDefinitions) {
+ cha(item);
+ }
+ for (auto const& item : this->MocConst().OptionsIncludes) {
+ cha(item);
+ }
+ for (auto const& item : this->MocConst().OptionsExtra) {
+ cha(item);
+ }
+ for (auto const& item : this->MocConst().PredefsCmd) {
+ cha(item);
+ }
+ for (auto const& filter : this->MocConst().DependFilters) {
+ cha(filter.Key);
+ }
+ for (auto const& filter : this->MocConst().MacroFilters) {
+ cha(filter.Key);
+ }
+ this->SettingsStringMoc_ = cryptoHash.FinalizeHex();
+ }
+
+ if (this->UicConst().Enabled) {
+ cryptoHash.Initialize();
+ cha(this->UicConst().Executable);
+ std::for_each(this->UicConst().Options.begin(),
+ this->UicConst().Options.end(), cha);
+ for (const auto& item : this->UicConst().UiFiles) {
+ cha(item.first);
+ auto const& opts = item.second.Options;
+ std::for_each(opts.begin(), opts.end(), cha);
+ }
+ this->SettingsStringUic_ = cryptoHash.FinalizeHex();
+ }
+ }
+
+ // Read old settings and compare
+ {
+ std::string content;
+ if (cmQtAutoGenerator::FileRead(content, this->SettingsFile_)) {
+ if (this->MocConst().Enabled) {
+ if (this->SettingsStringMoc_ != SettingsFind(content, "moc")) {
+ this->MocConst_.SettingsChanged = true;
+ }
+ }
+ if (this->UicConst().Enabled) {
+ if (this->SettingsStringUic_ != SettingsFind(content, "uic")) {
+ this->UicConst_.SettingsChanged = true;
+ }
+ }
+ // In case any setting changed remove the old settings file.
+ // This triggers a full rebuild on the next run if the current
+ // build is aborted before writing the current settings in the end.
+ if (this->MocConst().SettingsChanged ||
+ this->UicConst().SettingsChanged) {
+ cmSystemTools::RemoveFile(this->SettingsFile_);
+ }
+ } else {
+ // Settings file read failed
+ if (this->MocConst().Enabled) {
+ this->MocConst_.SettingsChanged = true;
+ }
+ if (this->UicConst().Enabled) {
+ this->UicConst_.SettingsChanged = true;
+ }
+ }
+ }
+}
+
+bool cmQtAutoMocUicT::SettingsFileWrite()
+{
+ // Only write if any setting changed
+ if (this->MocConst().SettingsChanged || this->UicConst().SettingsChanged) {
+ if (this->Log().Verbose()) {
+ this->Log().Info(GenT::GEN,
+ cmStrCat("Writing the settings file ",
+ this->MessagePath(this->SettingsFile_)));
+ }
+ // Compose settings file content
+ std::string content;
+ {
+ auto SettingAppend = [&content](cm::string_view key,
+ cm::string_view value) {
+ if (!value.empty()) {
+ content += cmStrCat(key, ':', value, '\n');
+ }
+ };
+ SettingAppend("moc", this->SettingsStringMoc_);
+ SettingAppend("uic", this->SettingsStringUic_);
+ }
+ // Write settings file
+ std::string error;
+ if (!cmQtAutoGenerator::FileWrite(this->SettingsFile_, content, &error)) {
+ this->Log().Error(GenT::GEN,
+ cmStrCat("Writing the settings file ",
+ this->MessagePath(this->SettingsFile_),
+ " failed.\n", error));
+ // Remove old settings file to trigger a full rebuild on the next run
+ cmSystemTools::RemoveFile(this->SettingsFile_);
+ return false;
+ }
+ }
+ return true;
+}
+
+void cmQtAutoMocUicT::ParseCacheRead()
+{
+ cm::string_view reason;
+ // Don't read the cache if it is invalid
+ if (!this->BaseEval().ParseCacheTime.Load(
+ this->BaseConst().ParseCacheFile)) {
+ reason = "Refreshing parse cache because it doesn't exist.";
+ } else if (this->MocConst().SettingsChanged ||
+ this->UicConst().SettingsChanged) {
+ reason = "Refreshing parse cache because the settings changed.";
+ } else if (this->BaseEval().ParseCacheTime.Older(
+ this->BaseConst().CMakeExecutableTime)) {
+ reason =
+ "Refreshing parse cache because it is older than the CMake executable.";
+ }
+
+ if (!reason.empty()) {
+ // Don't read but refresh the complete parse cache
+ if (this->Log().Verbose()) {
+ this->Log().Info(GenT::GEN, reason);
+ }
+ this->BaseEval().ParseCacheChanged = true;
+ } else {
+ // Read parse cache
+ this->BaseEval().ParseCache.ReadFromFile(this->BaseConst().ParseCacheFile);
+ }
+}
+
+bool cmQtAutoMocUicT::ParseCacheWrite()
+{
+ if (this->BaseEval().ParseCacheChanged) {
+ if (this->Log().Verbose()) {
+ this->Log().Info(
+ GenT::GEN,
+ cmStrCat("Writing the parse cache file ",
+ this->MessagePath(this->BaseConst().ParseCacheFile)));
+ }
+ if (!this->BaseEval().ParseCache.WriteToFile(
+ this->BaseConst().ParseCacheFile)) {
+ this->Log().Error(
+ GenT::GEN,
+ cmStrCat("Writing the parse cache file ",
+ this->MessagePath(this->BaseConst().ParseCacheFile),
+ " failed."));
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoMocUicT::CreateDirectories()
+{
+ // Create AUTOGEN include directory
+ if (!cmSystemTools::MakeDirectory(this->BaseConst().AutogenIncludeDir)) {
+ this->Log().Error(
+ GenT::GEN,
+ cmStrCat("Creating the AUTOGEN include directory ",
+ this->MessagePath(this->BaseConst().AutogenIncludeDir),
+ " failed."));
+ return false;
+ }
+ return true;
+}
+
+std::vector<std::string> cmQtAutoMocUicT::dependenciesFromDepFile(
+ const char* filePath)
+{
+ auto const content = cmReadGccDepfile(filePath);
+ if (!content || content->empty()) {
+ return {};
+ }
+
+ // Moc outputs a depfile with exactly one rule.
+ // Discard the rule and return the dependencies.
+ return content->front().paths;
+}
+
+void cmQtAutoMocUicT::Abort(bool error)
+{
+ if (error) {
+ this->JobError_.store(true);
+ }
+ this->WorkerPool_.Abort();
+}
+
+std::string cmQtAutoMocUicT::AbsoluteBuildPath(
+ cm::string_view relativePath) const
+{
+ return cmStrCat(this->BaseConst().AutogenBuildDir, '/', relativePath);
+}
+
+std::string cmQtAutoMocUicT::AbsoluteIncludePath(
+ cm::string_view relativePath) const
+{
+ return cmStrCat(this->BaseConst().AutogenIncludeDir, '/', relativePath);
+}
+
+} // End of unnamed namespace
+
+bool cmQtAutoMocUic(cm::string_view infoFile, cm::string_view config)
+{
+ return cmQtAutoMocUicT().Run(infoFile, config);
+}
diff --git a/Source/cmQtAutoMocUic.h b/Source/cmQtAutoMocUic.h
new file mode 100644
index 0000000..20f9d6e
--- /dev/null
+++ b/Source/cmQtAutoMocUic.h
@@ -0,0 +1,13 @@
+/* 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 <cm/string_view>
+
+/**
+ * Process AUTOMOC and AUTOUIC
+ * @return true on success
+ */
+bool cmQtAutoMocUic(cm::string_view infoFile, cm::string_view config);
diff --git a/Source/cmQtAutoRcc.cxx b/Source/cmQtAutoRcc.cxx
new file mode 100644
index 0000000..414a692
--- /dev/null
+++ b/Source/cmQtAutoRcc.cxx
@@ -0,0 +1,527 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmQtAutoRcc.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include <cmext/algorithm>
+
+#include "cmCryptoHash.h"
+#include "cmDuration.h"
+#include "cmFileLock.h"
+#include "cmFileLockResult.h"
+#include "cmFileTime.h"
+#include "cmProcessOutput.h"
+#include "cmQtAutoGen.h"
+#include "cmQtAutoGenerator.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+
+/** \class cmQtAutoRccT
+ * \brief AUTORCC generator
+ */
+class cmQtAutoRccT : public cmQtAutoGenerator
+{
+public:
+ cmQtAutoRccT();
+ ~cmQtAutoRccT() override;
+
+ cmQtAutoRccT(cmQtAutoRccT const&) = delete;
+ cmQtAutoRccT& operator=(cmQtAutoRccT const&) = delete;
+
+private:
+ // -- Utility
+ bool IsMultiConfig() const { return this->MultiConfig_; }
+ std::string MultiConfigOutput() const;
+
+ // -- Abstract processing interface
+ bool InitFromInfo(InfoT const& info) override;
+ bool Process() override;
+ // -- Settings file
+ bool SettingsFileRead();
+ bool SettingsFileWrite();
+ // -- Tests
+ bool TestQrcRccFiles(bool& generate);
+ bool TestResources(bool& generate);
+ bool TestInfoFile();
+ // -- Generation
+ bool GenerateRcc();
+ bool GenerateWrapper();
+
+ // -- Config settings
+ bool MultiConfig_ = false;
+ // -- Directories
+ std::string AutogenBuildDir_;
+ std::string IncludeDir_;
+ // -- Qt environment
+ std::string RccExecutable_;
+ cmFileTime RccExecutableTime_;
+ std::vector<std::string> RccListOptions_;
+ // -- Job
+ std::string LockFile_;
+ cmFileLock LockFileLock_;
+ std::string QrcFile_;
+ std::string QrcFileName_;
+ std::string QrcFileDir_;
+ cmFileTime QrcFileTime_;
+ std::string RccPathChecksum_;
+ std::string RccFileName_;
+ std::string RccFileOutput_;
+ std::string RccFilePublic_;
+ cmFileTime RccFileTime_;
+ std::string Reason;
+ std::vector<std::string> Options_;
+ std::vector<std::string> Inputs_;
+ // -- Settings file
+ std::string SettingsFile_;
+ std::string SettingsString_;
+ bool SettingsChanged_ = false;
+ bool BuildFileChanged_ = false;
+};
+
+cmQtAutoRccT::cmQtAutoRccT()
+ : cmQtAutoGenerator(GenT::RCC)
+{
+}
+cmQtAutoRccT::~cmQtAutoRccT() = default;
+
+bool cmQtAutoRccT::InitFromInfo(InfoT const& info)
+{
+ // -- Required settings
+ if (!info.GetBool("MULTI_CONFIG", this->MultiConfig_, true) ||
+ !info.GetString("BUILD_DIR", this->AutogenBuildDir_, true) ||
+ !info.GetStringConfig("INCLUDE_DIR", this->IncludeDir_, true) ||
+ !info.GetString("RCC_EXECUTABLE", this->RccExecutable_, true) ||
+ !info.GetArray("RCC_LIST_OPTIONS", this->RccListOptions_, false) ||
+ !info.GetString("LOCK_FILE", this->LockFile_, true) ||
+ !info.GetStringConfig("SETTINGS_FILE", this->SettingsFile_, true) ||
+ !info.GetString("SOURCE", this->QrcFile_, true) ||
+ !info.GetString("OUTPUT_CHECKSUM", this->RccPathChecksum_, true) ||
+ !info.GetString("OUTPUT_NAME", this->RccFileName_, true) ||
+ !info.GetArray("OPTIONS", this->Options_, false) ||
+ !info.GetArray("INPUTS", this->Inputs_, false)) {
+ return false;
+ }
+
+ // -- Derive information
+ this->QrcFileName_ = cmSystemTools::GetFilenameName(this->QrcFile_);
+ this->QrcFileDir_ = cmSystemTools::GetFilenamePath(this->QrcFile_);
+ this->RccFilePublic_ =
+ cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, '/',
+ this->RccFileName_);
+
+ // rcc output file name
+ if (this->IsMultiConfig()) {
+ this->RccFileOutput_ =
+ cmStrCat(this->IncludeDir_, '/', this->MultiConfigOutput());
+ } else {
+ this->RccFileOutput_ = this->RccFilePublic_;
+ }
+
+ // -- Checks
+ if (!this->RccExecutableTime_.Load(this->RccExecutable_)) {
+ return info.LogError(cmStrCat("The rcc executable ",
+ this->MessagePath(this->RccExecutable_),
+ " does not exist."));
+ }
+
+ return true;
+}
+
+bool cmQtAutoRccT::Process()
+{
+ if (!this->SettingsFileRead()) {
+ return false;
+ }
+
+ // Test if the rcc output needs to be regenerated
+ bool generate = false;
+ if (!this->TestQrcRccFiles(generate)) {
+ return false;
+ }
+ if (!generate && !this->TestResources(generate)) {
+ return false;
+ }
+ // Generate on demand
+ if (generate) {
+ if (!this->GenerateRcc()) {
+ return false;
+ }
+ } else {
+ // Test if the info file is newer than the output file
+ if (!this->TestInfoFile()) {
+ return false;
+ }
+ }
+
+ if (!this->GenerateWrapper()) {
+ return false;
+ }
+
+ return this->SettingsFileWrite();
+}
+
+std::string cmQtAutoRccT::MultiConfigOutput() const
+{
+ return cmStrCat(this->RccPathChecksum_, '/',
+ AppendFilenameSuffix(this->RccFileName_, "_CMAKE_"));
+}
+
+bool cmQtAutoRccT::SettingsFileRead()
+{
+ // Compose current settings strings
+ {
+ cmCryptoHash cryptoHash(cmCryptoHash::AlgoSHA256);
+ auto cha = [&cryptoHash](cm::string_view value) {
+ cryptoHash.Append(value);
+ cryptoHash.Append(";");
+ };
+ cha(this->RccExecutable_);
+ std::for_each(this->RccListOptions_.begin(), this->RccListOptions_.end(),
+ cha);
+ cha(this->QrcFile_);
+ cha(this->RccPathChecksum_);
+ cha(this->RccFileName_);
+ std::for_each(this->Options_.begin(), this->Options_.end(), cha);
+ std::for_each(this->Inputs_.begin(), this->Inputs_.end(), cha);
+ this->SettingsString_ = cryptoHash.FinalizeHex();
+ }
+
+ // Make sure the settings file exists
+ if (!cmSystemTools::FileExists(this->SettingsFile_, true)) {
+ // Touch the settings file to make sure it exists
+ if (!cmSystemTools::Touch(this->SettingsFile_, true)) {
+ this->Log().Error(GenT::RCC,
+ cmStrCat("Touching the settings file ",
+ this->MessagePath(this->SettingsFile_),
+ " failed."));
+ return false;
+ }
+ }
+
+ // Lock the lock file
+ {
+ // Make sure the lock file exists
+ if (!cmSystemTools::FileExists(this->LockFile_, true)) {
+ if (!cmSystemTools::Touch(this->LockFile_, true)) {
+ this->Log().Error(GenT::RCC,
+ cmStrCat("Touching the lock file ",
+ this->MessagePath(this->LockFile_),
+ " failed."));
+ return false;
+ }
+ }
+ // Lock the lock file
+ cmFileLockResult lockResult = this->LockFileLock_.Lock(
+ this->LockFile_, static_cast<unsigned long>(-1));
+ if (!lockResult.IsOk()) {
+ this->Log().Error(GenT::RCC,
+ cmStrCat("Locking of the lock file ",
+ this->MessagePath(this->LockFile_),
+ " failed.\n", lockResult.GetOutputMessage()));
+ return false;
+ }
+ }
+
+ // Read old settings
+ {
+ std::string content;
+ if (FileRead(content, this->SettingsFile_)) {
+ this->SettingsChanged_ =
+ (this->SettingsString_ != SettingsFind(content, "rcc"));
+ // In case any setting changed clear the old settings file.
+ // This triggers a full rebuild on the next run if the current
+ // build is aborted before writing the current settings in the end.
+ if (this->SettingsChanged_) {
+ std::string error;
+ if (!FileWrite(this->SettingsFile_, "", &error)) {
+ this->Log().Error(GenT::RCC,
+ cmStrCat("Clearing of the settings file ",
+ this->MessagePath(this->SettingsFile_),
+ " failed.\n", error));
+ return false;
+ }
+ }
+ } else {
+ this->SettingsChanged_ = true;
+ }
+ }
+
+ return true;
+}
+
+bool cmQtAutoRccT::SettingsFileWrite()
+{
+ // Only write if any setting changed
+ if (this->SettingsChanged_) {
+ if (this->Log().Verbose()) {
+ this->Log().Info(GenT::RCC,
+ "Writing settings file " +
+ this->MessagePath(this->SettingsFile_));
+ }
+ // Write settings file
+ std::string content = cmStrCat("rcc:", this->SettingsString_, '\n');
+ std::string error;
+ if (!FileWrite(this->SettingsFile_, content, &error)) {
+ this->Log().Error(GenT::RCC,
+ cmStrCat("Writing of the settings file ",
+ this->MessagePath(this->SettingsFile_),
+ " failed.\n", error));
+ // Remove old settings file to trigger a full rebuild on the next run
+ cmSystemTools::RemoveFile(this->SettingsFile_);
+ return false;
+ }
+ }
+
+ // Unlock the lock file
+ this->LockFileLock_.Release();
+ return true;
+}
+
+/// Do basic checks if rcc generation is required
+bool cmQtAutoRccT::TestQrcRccFiles(bool& generate)
+{
+ // Test if the rcc input file exists
+ if (!this->QrcFileTime_.Load(this->QrcFile_)) {
+ this->Log().Error(GenT::RCC,
+ cmStrCat("The resources file ",
+ this->MessagePath(this->QrcFile_),
+ " does not exist"));
+ return false;
+ }
+
+ // Test if the rcc output file exists
+ if (!this->RccFileTime_.Load(this->RccFileOutput_)) {
+ if (this->Log().Verbose()) {
+ this->Reason =
+ cmStrCat("Generating ", this->MessagePath(this->RccFileOutput_),
+ ", because it doesn't exist, from ",
+ this->MessagePath(this->QrcFile_));
+ }
+ generate = true;
+ return true;
+ }
+
+ // Test if the settings changed
+ if (this->SettingsChanged_) {
+ if (this->Log().Verbose()) {
+ this->Reason =
+ cmStrCat("Generating ", this->MessagePath(this->RccFileOutput_),
+ ", because the rcc settings changed, from ",
+ this->MessagePath(this->QrcFile_));
+ }
+ generate = true;
+ return true;
+ }
+
+ // Test if the rcc output file is older than the .qrc file
+ if (this->RccFileTime_.Older(this->QrcFileTime_)) {
+ if (this->Log().Verbose()) {
+ this->Reason = cmStrCat(
+ "Generating ", this->MessagePath(this->RccFileOutput_),
+ ", because it is older than ", this->MessagePath(this->QrcFile_),
+ ", from ", this->MessagePath(this->QrcFile_));
+ }
+ generate = true;
+ return true;
+ }
+
+ // Test if the rcc output file is older than the rcc executable
+ if (this->RccFileTime_.Older(this->RccExecutableTime_)) {
+ if (this->Log().Verbose()) {
+ this->Reason =
+ cmStrCat("Generating ", this->MessagePath(this->RccFileOutput_),
+ ", because it is older than the rcc executable, from ",
+ this->MessagePath(this->QrcFile_));
+ }
+ generate = true;
+ return true;
+ }
+
+ return true;
+}
+
+bool cmQtAutoRccT::TestResources(bool& generate)
+{
+ // Read resource files list
+ if (this->Inputs_.empty()) {
+ std::string error;
+ RccLister const lister(this->RccExecutable_, this->RccListOptions_);
+ if (!lister.list(this->QrcFile_, this->Inputs_, error,
+ this->Log().Verbose())) {
+ this->Log().Error(GenT::RCC,
+ cmStrCat("Listing of ",
+ this->MessagePath(this->QrcFile_),
+ " failed.\n", error));
+ return false;
+ }
+ }
+
+ // Check if any resource file is newer than the rcc output file
+ for (std::string const& resFile : this->Inputs_) {
+ // Check if the resource file exists
+ cmFileTime fileTime;
+ if (!fileTime.Load(resFile)) {
+ this->Log().Error(GenT::RCC,
+ cmStrCat("The resource file ",
+ this->MessagePath(resFile), " listed in ",
+ this->MessagePath(this->QrcFile_),
+ " does not exist."));
+ return false;
+ }
+ // Check if the resource file is newer than the rcc output file
+ if (this->RccFileTime_.Older(fileTime)) {
+ if (this->Log().Verbose()) {
+ this->Reason =
+ cmStrCat("Generating ", this->MessagePath(this->RccFileOutput_),
+ ", because it is older than ", this->MessagePath(resFile),
+ ", from ", this->MessagePath(this->QrcFile_));
+ }
+ generate = true;
+ break;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoRccT::TestInfoFile()
+{
+ // Test if the rcc output file is older than the info file
+ if (this->RccFileTime_.Older(this->InfoFileTime())) {
+ if (this->Log().Verbose()) {
+ this->Log().Info(GenT::RCC,
+ cmStrCat("Touching ",
+ this->MessagePath(this->RccFileOutput_),
+ " because it is older than ",
+ this->MessagePath(this->InfoFile())));
+ }
+ // Touch build file
+ if (!cmSystemTools::Touch(this->RccFileOutput_, false)) {
+ this->Log().Error(GenT::RCC,
+ cmStrCat("Touching ",
+ this->MessagePath(this->RccFileOutput_),
+ " failed."));
+ return false;
+ }
+ this->BuildFileChanged_ = true;
+ }
+
+ return true;
+}
+
+bool cmQtAutoRccT::GenerateRcc()
+{
+ // Make parent directory
+ if (!MakeParentDirectory(this->RccFileOutput_)) {
+ this->Log().Error(GenT::RCC,
+ cmStrCat("Could not create parent directory of ",
+ this->MessagePath(this->RccFileOutput_)));
+ return false;
+ }
+
+ // Compose rcc command
+ std::vector<std::string> cmd;
+ cmd.push_back(this->RccExecutable_);
+ cm::append(cmd, this->Options_);
+ cmd.emplace_back("-o");
+ cmd.push_back(this->RccFileOutput_);
+ cmd.push_back(this->QrcFile_);
+
+ // Log reason and command
+ if (this->Log().Verbose()) {
+ this->Log().Info(GenT::RCC,
+ cmStrCat(this->Reason,
+ cmHasSuffix(this->Reason, '\n') ? "" : "\n",
+ QuotedCommand(cmd), '\n'));
+ }
+
+ std::string rccStdOut;
+ std::string rccStdErr;
+ int retVal = 0;
+ bool result = cmSystemTools::RunSingleCommand(
+ cmd, &rccStdOut, &rccStdErr, &retVal, this->AutogenBuildDir_.c_str(),
+ cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto);
+ if (!result || (retVal != 0)) {
+ // rcc process failed
+ this->Log().ErrorCommand(GenT::RCC,
+ cmStrCat("The rcc process failed to compile\n ",
+ this->MessagePath(this->QrcFile_),
+ "\ninto\n ",
+ this->MessagePath(this->RccFileOutput_)),
+ cmd, rccStdOut + rccStdErr);
+ cmSystemTools::RemoveFile(this->RccFileOutput_);
+ return false;
+ }
+
+ // rcc process success
+ // Print rcc output
+ if (!rccStdOut.empty()) {
+ this->Log().Info(GenT::RCC, rccStdOut);
+ }
+ this->BuildFileChanged_ = true;
+
+ return true;
+}
+
+bool cmQtAutoRccT::GenerateWrapper()
+{
+ // Generate a wrapper source file on demand
+ if (this->IsMultiConfig()) {
+ // Wrapper file content
+ std::string content =
+ cmStrCat("// This is an autogenerated configuration wrapper file.\n",
+ "// Changes will be overwritten.\n", "#include <",
+ this->MultiConfigOutput(), ">\n");
+
+ // Compare with existing file content
+ bool fileDiffers = true;
+ {
+ std::string oldContents;
+ if (FileRead(oldContents, this->RccFilePublic_)) {
+ fileDiffers = (oldContents != content);
+ }
+ }
+ if (fileDiffers) {
+ // Write new wrapper file
+ if (this->Log().Verbose()) {
+ this->Log().Info(GenT::RCC,
+ cmStrCat("Generating RCC wrapper file ",
+ this->MessagePath(this->RccFilePublic_)));
+ }
+ std::string error;
+ if (!FileWrite(this->RccFilePublic_, content, &error)) {
+ this->Log().Error(GenT::RCC,
+ cmStrCat("Generating RCC wrapper file ",
+ this->MessagePath(this->RccFilePublic_),
+ " failed.\n", error));
+ return false;
+ }
+ } else if (this->BuildFileChanged_) {
+ // Just touch the wrapper file
+ if (this->Log().Verbose()) {
+ this->Log().Info(GenT::RCC,
+ cmStrCat("Touching RCC wrapper file ",
+ this->MessagePath(this->RccFilePublic_)));
+ }
+ if (!cmSystemTools::Touch(this->RccFilePublic_, false)) {
+ this->Log().Error(GenT::RCC,
+ cmStrCat("Touching RCC wrapper file ",
+ this->MessagePath(this->RccFilePublic_),
+ " failed."));
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+} // End of unnamed namespace
+
+bool cmQtAutoRcc(cm::string_view infoFile, cm::string_view config)
+{
+ return cmQtAutoRccT().Run(infoFile, config);
+}
diff --git a/Source/cmQtAutoRcc.h b/Source/cmQtAutoRcc.h
new file mode 100644
index 0000000..d525efa
--- /dev/null
+++ b/Source/cmQtAutoRcc.h
@@ -0,0 +1,13 @@
+/* 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 <cm/string_view>
+
+/**
+ * Process AUTORCC
+ * @return true on success
+ */
+bool cmQtAutoRcc(cm::string_view infoFile, cm::string_view config);
diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx
new file mode 100644
index 0000000..fce6e80
--- /dev/null
+++ b/Source/cmRST.cxx
@@ -0,0 +1,475 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmRST.h"
+
+#include <algorithm>
+#include <cctype>
+#include <cstddef>
+#include <iterator>
+#include <utility>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmAlgorithms.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+
+cmRST::cmRST(std::ostream& os, std::string docroot)
+ : OS(os)
+ , DocRoot(std::move(docroot))
+ , IncludeDepth(0)
+ , OutputLinePending(false)
+ , LastLineEndedInColonColon(false)
+ , Markup(MarkupNone)
+ , Directive(DirectiveNone)
+ , CMakeDirective("^.. (cmake:)?("
+ "command|envvar|genex|variable"
+ ")::[ \t]+([^ \t\n]+)$")
+ , CMakeModuleDirective("^.. cmake-module::[ \t]+([^ \t\n]+)$")
+ , ParsedLiteralDirective("^.. parsed-literal::[ \t]*(.*)$")
+ , CodeBlockDirective("^.. code-block::[ \t]*(.*)$")
+ , ReplaceDirective("^.. (\\|[^|]+\\|) replace::[ \t]*(.*)$")
+ , IncludeDirective("^.. include::[ \t]+([^ \t\n]+)$")
+ , TocTreeDirective("^.. toctree::[ \t]*(.*)$")
+ , ProductionListDirective("^.. productionlist::[ \t]*(.*)$")
+ , NoteDirective("^.. note::[ \t]*(.*)$")
+ , ModuleRST(R"(^#\[(=*)\[\.rst:$)")
+ , CMakeRole("(:cmake)?:("
+ "command|cpack_gen|generator|genex|"
+ "variable|envvar|module|policy|"
+ "prop_cache|prop_dir|prop_gbl|prop_inst|prop_sf|"
+ "prop_test|prop_tgt|"
+ "manual"
+ "):`(<*([^`<]|[^` \t]<)*)([ \t]+<[^`]*>)?`")
+ , InlineLink("`(<*([^`<]|[^` \t]<)*)([ \t]+<[^`]*>)?`_")
+ , InlineLiteral("``([^`]*)``")
+ , Substitution("(^|[^A-Za-z0-9_])"
+ "((\\|[^| \t\r\n]([^|\r\n]*[^| \t\r\n])?\\|)(__|_|))"
+ "([^A-Za-z0-9_]|$)")
+ , TocTreeLink("^.*[ \t]+<([^>]+)>$")
+{
+ this->Replace["|release|"] = cmVersion::GetCMakeVersion();
+}
+
+bool cmRST::ProcessFile(std::string const& fname, bool isModule)
+{
+ cmsys::ifstream fin(fname.c_str());
+ if (fin) {
+ this->DocDir = cmSystemTools::GetFilenamePath(fname);
+ if (isModule) {
+ this->ProcessModule(fin);
+ } else {
+ this->ProcessRST(fin);
+ }
+ this->OutputLinePending = true;
+ return true;
+ }
+ return false;
+}
+
+void cmRST::ProcessRST(std::istream& is)
+{
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(is, line)) {
+ this->ProcessLine(line);
+ }
+ this->Reset();
+}
+
+void cmRST::ProcessModule(std::istream& is)
+{
+ std::string line;
+ std::string rst;
+ while (cmSystemTools::GetLineFromStream(is, line)) {
+ if (!rst.empty() && rst != "#") {
+ // Bracket mode: check for end bracket
+ std::string::size_type pos = line.find(rst);
+ if (pos == std::string::npos) {
+ this->ProcessLine(line);
+ } else {
+ if (line[0] != '#') {
+ line.resize(pos);
+ this->ProcessLine(line);
+ }
+ rst.clear();
+ this->Reset();
+ this->OutputLinePending = true;
+ }
+ } else {
+ // Line mode: check for .rst start (bracket or line)
+ if (rst == "#") {
+ if (line == "#") {
+ this->ProcessLine("");
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, "# ")) {
+ line.erase(0, 2);
+ this->ProcessLine(line);
+ continue;
+ }
+ rst.clear();
+ this->Reset();
+ this->OutputLinePending = true;
+ }
+ if (line == "#.rst:") {
+ rst = "#";
+ } else if (this->ModuleRST.find(line)) {
+ rst = "]" + this->ModuleRST.match(1) + "]";
+ }
+ }
+ }
+ if (rst == "#") {
+ this->Reset();
+ }
+}
+
+void cmRST::Reset()
+{
+ if (!this->MarkupLines.empty()) {
+ cmRST::UnindentLines(this->MarkupLines);
+ }
+ switch (this->Directive) {
+ case DirectiveNone:
+ break;
+ case DirectiveParsedLiteral:
+ this->ProcessDirectiveParsedLiteral();
+ break;
+ case DirectiveLiteralBlock:
+ this->ProcessDirectiveLiteralBlock();
+ break;
+ case DirectiveCodeBlock:
+ this->ProcessDirectiveCodeBlock();
+ break;
+ case DirectiveReplace:
+ this->ProcessDirectiveReplace();
+ break;
+ case DirectiveTocTree:
+ this->ProcessDirectiveTocTree();
+ break;
+ }
+ this->Markup = MarkupNone;
+ this->Directive = DirectiveNone;
+ this->MarkupLines.clear();
+}
+
+void cmRST::ProcessLine(std::string const& line)
+{
+ bool lastLineEndedInColonColon = this->LastLineEndedInColonColon;
+ this->LastLineEndedInColonColon = false;
+
+ // A line starting in .. is an explicit markup start.
+ if (line == ".." ||
+ (line.size() >= 3 && line[0] == '.' && line[1] == '.' &&
+ isspace(line[2]))) {
+ this->Reset();
+ this->Markup =
+ (line.find_first_not_of(" \t", 2) == std::string::npos ? MarkupEmpty
+ : MarkupNormal);
+ // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
+ // NOLINTNEXTLINE(bugprone-branch-clone)
+ if (this->CMakeDirective.find(line)) {
+ // Output cmake domain directives and their content normally.
+ this->NormalLine(line);
+ } else if (this->CMakeModuleDirective.find(line)) {
+ // Process cmake-module directive: scan .cmake file comments.
+ std::string file = this->CMakeModuleDirective.match(1);
+ if (file.empty() || !this->ProcessInclude(file, IncludeModule)) {
+ this->NormalLine(line);
+ }
+ } else if (this->ParsedLiteralDirective.find(line)) {
+ // Record the literal lines to output after whole block.
+ this->Directive = DirectiveParsedLiteral;
+ this->MarkupLines.push_back(this->ParsedLiteralDirective.match(1));
+ } else if (this->CodeBlockDirective.find(line)) {
+ // Record the literal lines to output after whole block.
+ // Ignore the language spec and record the opening line as blank.
+ this->Directive = DirectiveCodeBlock;
+ this->MarkupLines.emplace_back();
+ } else if (this->ReplaceDirective.find(line)) {
+ // Record the replace directive content.
+ this->Directive = DirectiveReplace;
+ this->ReplaceName = this->ReplaceDirective.match(1);
+ this->MarkupLines.push_back(this->ReplaceDirective.match(2));
+ } else if (this->IncludeDirective.find(line)) {
+ // Process the include directive or output the directive and its
+ // content normally if it fails.
+ std::string file = this->IncludeDirective.match(1);
+ if (file.empty() || !this->ProcessInclude(file, IncludeNormal)) {
+ this->NormalLine(line);
+ }
+ } else if (this->TocTreeDirective.find(line)) {
+ // Record the toctree entries to process after whole block.
+ this->Directive = DirectiveTocTree;
+ this->MarkupLines.push_back(this->TocTreeDirective.match(1));
+ } else if (this->ProductionListDirective.find(line)) {
+ // Output productionlist directives and their content normally.
+ this->NormalLine(line);
+ } else if (this->NoteDirective.find(line)) {
+ // Output note directives and their content normally.
+ this->NormalLine(line);
+ }
+ }
+ // An explicit markup start followed nothing but whitespace and a
+ // blank line does not consume any indented text following.
+ else if (this->Markup == MarkupEmpty && line.empty()) {
+ this->NormalLine(line);
+ }
+ // Indented lines following an explicit markup start are explicit markup.
+ else if (this->Markup && (line.empty() || isspace(line[0]))) {
+ this->Markup = MarkupNormal;
+ // Record markup lines if the start line was recorded.
+ if (!this->MarkupLines.empty()) {
+ this->MarkupLines.push_back(line);
+ }
+ }
+ // A blank line following a paragraph ending in "::" starts a literal block.
+ else if (lastLineEndedInColonColon && line.empty()) {
+ // Record the literal lines to output after whole block.
+ this->Markup = MarkupNormal;
+ this->Directive = DirectiveLiteralBlock;
+ this->MarkupLines.emplace_back();
+ this->OutputLine("", false);
+ }
+ // Print non-markup lines.
+ else {
+ this->NormalLine(line);
+ this->LastLineEndedInColonColon =
+ (line.size() >= 2 && line[line.size() - 2] == ':' && line.back() == ':');
+ }
+}
+
+void cmRST::NormalLine(std::string const& line)
+{
+ this->Reset();
+ this->OutputLine(line, true);
+}
+
+void cmRST::OutputLine(std::string const& line_in, bool inlineMarkup)
+{
+ if (this->OutputLinePending) {
+ this->OS << "\n";
+ this->OutputLinePending = false;
+ }
+ if (inlineMarkup) {
+ std::string line = this->ReplaceSubstitutions(line_in);
+ std::string::size_type pos = 0;
+ for (;;) {
+ std::string::size_type* first = nullptr;
+ std::string::size_type role_start = std::string::npos;
+ std::string::size_type link_start = std::string::npos;
+ std::string::size_type lit_start = std::string::npos;
+ if (this->CMakeRole.find(line.c_str() + pos)) {
+ role_start = this->CMakeRole.start();
+ first = &role_start;
+ }
+ if (this->InlineLiteral.find(line.c_str() + pos)) {
+ lit_start = this->InlineLiteral.start();
+ if (!first || lit_start < *first) {
+ first = &lit_start;
+ }
+ }
+ if (this->InlineLink.find(line.c_str() + pos)) {
+ link_start = this->InlineLink.start();
+ if (!first || link_start < *first) {
+ first = &link_start;
+ }
+ }
+ if (first == &role_start) {
+ this->OS << line.substr(pos, role_start);
+ std::string text = this->CMakeRole.match(3);
+ // If a command reference has no explicit target and
+ // no explicit "(...)" then add "()" to the text.
+ if (this->CMakeRole.match(2) == "command" &&
+ this->CMakeRole.match(5).empty() &&
+ text.find_first_of("()") == std::string::npos) {
+ text += "()";
+ }
+ this->OS << "``" << text << "``";
+ pos += this->CMakeRole.end();
+ } else if (first == &lit_start) {
+ this->OS << line.substr(pos, lit_start);
+ std::string text = this->InlineLiteral.match(1);
+ pos += this->InlineLiteral.end();
+ this->OS << "``" << text << "``";
+ } else if (first == &link_start) {
+ this->OS << line.substr(pos, link_start);
+ std::string text = this->InlineLink.match(1);
+ bool escaped = false;
+ for (char c : text) {
+ if (escaped) {
+ escaped = false;
+ this->OS << c;
+ } else if (c == '\\') {
+ escaped = true;
+ } else {
+ this->OS << c;
+ }
+ }
+ pos += this->InlineLink.end();
+ } else {
+ break;
+ }
+ }
+ this->OS << line.substr(pos) << "\n";
+ } else {
+ this->OS << line_in << "\n";
+ }
+}
+
+std::string cmRST::ReplaceSubstitutions(std::string const& line)
+{
+ std::string out;
+ std::string::size_type pos = 0;
+ while (this->Substitution.find(line.c_str() + pos)) {
+ std::string::size_type start = this->Substitution.start(2);
+ std::string::size_type end = this->Substitution.end(2);
+ std::string substitute = this->Substitution.match(3);
+ auto replace = this->Replace.find(substitute);
+ if (replace != this->Replace.end()) {
+ std::pair<std::set<std::string>::iterator, bool> replaced =
+ this->Replaced.insert(substitute);
+ if (replaced.second) {
+ substitute = this->ReplaceSubstitutions(replace->second);
+ this->Replaced.erase(replaced.first);
+ }
+ }
+ out += line.substr(pos, start);
+ out += substitute;
+ pos += end;
+ }
+ out += line.substr(pos);
+ return out;
+}
+
+void cmRST::OutputMarkupLines(bool inlineMarkup)
+{
+ for (auto line : this->MarkupLines) {
+ if (!line.empty()) {
+ line = cmStrCat(" ", line);
+ }
+ this->OutputLine(line, inlineMarkup);
+ }
+ this->OutputLinePending = true;
+}
+
+bool cmRST::ProcessInclude(std::string file, IncludeType type)
+{
+ bool found = false;
+ if (this->IncludeDepth < 10) {
+ cmRST r(this->OS, this->DocRoot);
+ r.IncludeDepth = this->IncludeDepth + 1;
+ r.OutputLinePending = this->OutputLinePending;
+ if (type != IncludeTocTree) {
+ r.Replace = this->Replace;
+ }
+ if (file[0] == '/') {
+ file = this->DocRoot + file;
+ } else {
+ file = this->DocDir + "/" + file;
+ }
+ found = r.ProcessFile(file, type == IncludeModule);
+ if (type != IncludeTocTree) {
+ this->Replace = r.Replace;
+ }
+ this->OutputLinePending = r.OutputLinePending;
+ }
+ return found;
+}
+
+void cmRST::ProcessDirectiveParsedLiteral()
+{
+ this->OutputMarkupLines(true);
+}
+
+void cmRST::ProcessDirectiveLiteralBlock()
+{
+ this->OutputMarkupLines(false);
+}
+
+void cmRST::ProcessDirectiveCodeBlock()
+{
+ this->OutputMarkupLines(false);
+}
+
+void cmRST::ProcessDirectiveReplace()
+{
+ // Record markup lines as replacement text.
+ std::string& replacement = this->Replace[this->ReplaceName];
+ replacement += cmJoin(this->MarkupLines, " ");
+ this->ReplaceName.clear();
+}
+
+void cmRST::ProcessDirectiveTocTree()
+{
+ // Process documents referenced by toctree directive.
+ for (std::string const& line : this->MarkupLines) {
+ if (!line.empty() && line[0] != ':') {
+ if (this->TocTreeLink.find(line)) {
+ std::string const& link = this->TocTreeLink.match(1);
+ this->ProcessInclude(link + ".rst", IncludeTocTree);
+ } else {
+ this->ProcessInclude(line + ".rst", IncludeTocTree);
+ }
+ }
+ }
+}
+
+void cmRST::UnindentLines(std::vector<std::string>& lines)
+{
+ // Remove the common indentation from the second and later lines.
+ std::string indentText;
+ std::string::size_type indentEnd = 0;
+ bool first = true;
+ for (size_t i = 1; i < lines.size(); ++i) {
+ std::string const& line = lines[i];
+
+ // Do not consider empty lines.
+ if (line.empty()) {
+ continue;
+ }
+
+ // Record indentation on first non-empty line.
+ if (first) {
+ first = false;
+ indentEnd = line.find_first_not_of(" \t");
+ indentText = line.substr(0, indentEnd);
+ continue;
+ }
+
+ // Truncate indentation to match that on this line.
+ indentEnd = std::min(indentEnd, line.size());
+ for (std::string::size_type j = 0; j != indentEnd; ++j) {
+ if (line[j] != indentText[j]) {
+ indentEnd = j;
+ break;
+ }
+ }
+ }
+
+ // Update second and later lines.
+ for (size_t i = 1; i < lines.size(); ++i) {
+ std::string& line = lines[i];
+ if (!line.empty()) {
+ line = line.substr(indentEnd);
+ }
+ }
+
+ auto it = lines.cbegin();
+ size_t leadingEmpty = std::distance(it, cmFindNot(lines, std::string()));
+
+ auto rit = lines.crbegin();
+ size_t trailingEmpty =
+ std::distance(rit, cmFindNot(cmReverseRange(lines), std::string()));
+
+ if ((leadingEmpty + trailingEmpty) >= lines.size()) {
+ // All lines are empty. The markup block is empty. Leave only one.
+ lines.resize(1);
+ return;
+ }
+
+ auto contentEnd = cmRotate(lines.begin(), lines.begin() + leadingEmpty,
+ lines.end() - trailingEmpty);
+ lines.erase(contentEnd, lines.end());
+}
diff --git a/Source/cmRST.h b/Source/cmRST.h
new file mode 100644
index 0000000..17cdfe8
--- /dev/null
+++ b/Source/cmRST.h
@@ -0,0 +1,98 @@
+/* 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 <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+/** \class cmRST
+ * \brief Perform basic .rst processing for command-line help
+ *
+ * This class implements a subset of reStructuredText and Sphinx
+ * document processing. It is used to print command-line help.
+ *
+ * If you modify the capabilities of this class, be sure to update
+ * the Help/manual/cmake-developer.7.rst documentation and to update
+ * the Tests/CMakeLib/testRST.(rst|expect) test input and output.
+ */
+class cmRST
+{
+public:
+ cmRST(std::ostream& os, std::string docroot);
+ bool ProcessFile(std::string const& fname, bool isModule = false);
+
+private:
+ enum IncludeType
+ {
+ IncludeNormal,
+ IncludeModule,
+ IncludeTocTree
+ };
+ enum MarkupType
+ {
+ MarkupNone,
+ MarkupNormal,
+ MarkupEmpty
+ };
+ enum DirectiveType
+ {
+ DirectiveNone,
+ DirectiveParsedLiteral,
+ DirectiveLiteralBlock,
+ DirectiveCodeBlock,
+ DirectiveReplace,
+ DirectiveTocTree
+ };
+
+ void ProcessRST(std::istream& is);
+ void ProcessModule(std::istream& is);
+ void Reset();
+ void ProcessLine(std::string const& line);
+ void NormalLine(std::string const& line);
+ void OutputLine(std::string const& line, bool inlineMarkup);
+ std::string ReplaceSubstitutions(std::string const& line);
+ void OutputMarkupLines(bool inlineMarkup);
+ bool ProcessInclude(std::string file, IncludeType type);
+ void ProcessDirectiveParsedLiteral();
+ void ProcessDirectiveLiteralBlock();
+ void ProcessDirectiveCodeBlock();
+ void ProcessDirectiveReplace();
+ void ProcessDirectiveTocTree();
+ static void UnindentLines(std::vector<std::string>& lines);
+
+ std::ostream& OS;
+ std::string DocRoot;
+ int IncludeDepth;
+ bool OutputLinePending;
+ bool LastLineEndedInColonColon;
+ MarkupType Markup;
+ DirectiveType Directive;
+ cmsys::RegularExpression CMakeDirective;
+ cmsys::RegularExpression CMakeModuleDirective;
+ cmsys::RegularExpression ParsedLiteralDirective;
+ cmsys::RegularExpression CodeBlockDirective;
+ cmsys::RegularExpression ReplaceDirective;
+ cmsys::RegularExpression IncludeDirective;
+ cmsys::RegularExpression TocTreeDirective;
+ cmsys::RegularExpression ProductionListDirective;
+ cmsys::RegularExpression NoteDirective;
+ cmsys::RegularExpression ModuleRST;
+ cmsys::RegularExpression CMakeRole;
+ cmsys::RegularExpression InlineLink;
+ cmsys::RegularExpression InlineLiteral;
+ cmsys::RegularExpression Substitution;
+ cmsys::RegularExpression TocTreeLink;
+
+ std::vector<std::string> MarkupLines;
+ std::string DocDir;
+ std::map<std::string, std::string> Replace;
+ std::set<std::string> Replaced;
+ std::string ReplaceName;
+};
diff --git a/Source/cmRange.h b/Source/cmRange.h
new file mode 100644
index 0000000..30af7d2
--- /dev/null
+++ b/Source/cmRange.h
@@ -0,0 +1,236 @@
+/* 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 <algorithm>
+#include <functional>
+#include <iterator>
+
+namespace RangeIterators {
+
+template <typename Iter, typename UnaryPredicate>
+class FilterIterator
+{
+public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = typename std::iterator_traits<Iter>::value_type;
+ using difference_type = typename std::iterator_traits<Iter>::difference_type;
+ using pointer = typename std::iterator_traits<Iter>::pointer;
+ using reference = typename std::iterator_traits<Iter>::reference;
+
+ FilterIterator(Iter b, Iter e, UnaryPredicate p)
+ : Cur(std::move(b))
+ , End(std::move(e))
+ , Pred(std::move(p))
+ {
+ this->SatisfyPredicate();
+ }
+
+ FilterIterator& operator++()
+ {
+ ++this->Cur;
+ this->SatisfyPredicate();
+ return *this;
+ }
+
+ FilterIterator& operator--()
+ {
+ do {
+ --this->Cur;
+ } while (!this->Pred(*this->Cur));
+ return *this;
+ }
+
+ bool operator==(FilterIterator const& other) const
+ {
+ return this->Cur == other.Cur;
+ }
+
+ bool operator!=(FilterIterator const& other) const
+ {
+ return !this->operator==(other);
+ }
+
+ auto operator*() const -> decltype(*std::declval<Iter>())
+ {
+ return *this->Cur;
+ }
+
+private:
+ void SatisfyPredicate()
+ {
+ while (this->Cur != this->End && !this->Pred(*this->Cur)) {
+ ++this->Cur;
+ }
+ }
+
+ Iter Cur;
+ Iter End;
+ UnaryPredicate Pred;
+};
+
+template <typename Iter, typename UnaryFunction>
+class TransformIterator
+{
+public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type =
+ typename std::remove_cv<typename std::remove_reference<decltype(
+ std::declval<UnaryFunction>()(*std::declval<Iter>()))>::type>::type;
+ using difference_type = typename std::iterator_traits<Iter>::difference_type;
+ using pointer = value_type const*;
+ using reference = value_type const&;
+
+ TransformIterator(Iter i, UnaryFunction f)
+ : Base(std::move(i))
+ , Func(std::move(f))
+ {
+ }
+
+ TransformIterator& operator++()
+ {
+ ++this->Base;
+ return *this;
+ }
+
+ TransformIterator& operator--()
+ {
+ --this->Base;
+ return *this;
+ }
+
+ bool operator==(TransformIterator const& other) const
+ {
+ return this->Base == other.Base;
+ }
+
+ bool operator!=(TransformIterator const& other) const
+ {
+ return !this->operator==(other);
+ }
+
+ auto operator*() const
+ -> decltype(std::declval<UnaryFunction>()(*std::declval<Iter>()))
+ {
+ return this->Func(*this->Base);
+ }
+
+private:
+ Iter Base;
+ UnaryFunction Func;
+};
+
+} // namespace RangeIterators
+
+template <typename Iter>
+class cmRange
+{
+public:
+ using const_iterator = Iter;
+ using value_type = typename std::iterator_traits<Iter>::value_type;
+ using difference_type = typename std::iterator_traits<Iter>::difference_type;
+
+ cmRange(Iter b, Iter e)
+ : Begin(std::move(b))
+ , End(std::move(e))
+ {
+ }
+
+ Iter begin() const { return this->Begin; }
+ Iter end() const { return this->End; }
+ bool empty() const { return this->Begin == this->End; }
+
+ difference_type size() const
+ {
+ return std::distance(this->Begin, this->End);
+ }
+
+ cmRange& advance(difference_type amount) &
+ {
+ std::advance(this->Begin, amount);
+ return *this;
+ }
+
+ cmRange advance(difference_type amount) &&
+ {
+ std::advance(this->Begin, amount);
+ return std::move(*this);
+ }
+
+ cmRange& retreat(difference_type amount) &
+ {
+ std::advance(this->End, -amount);
+ return *this;
+ }
+
+ cmRange retreat(difference_type amount) &&
+ {
+ std::advance(this->End, -amount);
+ return std::move(*this);
+ }
+
+ template <typename UnaryPredicate>
+ bool all_of(UnaryPredicate p) const
+ {
+ return std::all_of(this->Begin, this->End, std::ref(p));
+ }
+
+ template <typename UnaryPredicate>
+ bool any_of(UnaryPredicate p) const
+ {
+ return std::any_of(this->Begin, this->End, std::ref(p));
+ }
+
+ template <typename UnaryPredicate>
+ bool none_of(UnaryPredicate p) const
+ {
+ return std::none_of(this->Begin, this->End, std::ref(p));
+ }
+
+ template <typename UnaryPredicate>
+ auto filter(UnaryPredicate p) const
+ -> cmRange<RangeIterators::FilterIterator<Iter, UnaryPredicate>>
+ {
+ using It = RangeIterators::FilterIterator<Iter, UnaryPredicate>;
+ return { It(this->Begin, this->End, p), It(this->End, this->End, p) };
+ }
+
+ template <typename UnaryFunction>
+ auto transform(UnaryFunction f) const
+ -> cmRange<RangeIterators::TransformIterator<Iter, UnaryFunction>>
+ {
+ using It = RangeIterators::TransformIterator<Iter, UnaryFunction>;
+ return { It(this->Begin, f), It(this->End, f) };
+ }
+
+private:
+ Iter Begin;
+ Iter End;
+};
+
+template <typename Iter1, typename Iter2>
+bool operator==(cmRange<Iter1> const& left, cmRange<Iter2> const& right)
+{
+ return left.size() == right.size() &&
+ std::equal(left.begin(), left.end(), right.begin());
+}
+
+template <typename Iter1, typename Iter2>
+auto cmMakeRange(Iter1 begin, Iter2 end) -> cmRange<Iter1>
+{
+ return { begin, end };
+}
+
+template <typename Range>
+auto cmMakeRange(Range const& range) -> cmRange<decltype(range.begin())>
+{
+ return { range.begin(), range.end() };
+}
+
+template <typename Range>
+auto cmReverseRange(Range const& range) -> cmRange<decltype(range.rbegin())>
+{
+ return { range.rbegin(), range.rend() };
+}
diff --git a/Source/cmRemoveCommand.cxx b/Source/cmRemoveCommand.cxx
new file mode 100644
index 0000000..1345588
--- /dev/null
+++ b/Source/cmRemoveCommand.cxx
@@ -0,0 +1,57 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmRemoveCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStringAlgorithms.h"
+
+// cmRemoveCommand
+bool cmRemoveCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ return true;
+ }
+
+ std::string const& variable = args[0]; // VAR is always first
+ // get the old value
+ cmProp cacheValue = status.GetMakefile().GetDefinition(variable);
+
+ // if there is no old value then return
+ if (!cacheValue) {
+ return true;
+ }
+
+ // expand the variable
+ std::vector<std::string> const varArgsExpanded = cmExpandedList(*cacheValue);
+
+ // expand the args
+ // check for REMOVE(VAR v1 v2 ... vn)
+ std::vector<std::string> const argsExpanded =
+ cmExpandedLists(args.begin() + 1, args.end());
+
+ // now create the new value
+ std::string value;
+ for (std::string const& varArgExpanded : varArgsExpanded) {
+ int found = 0;
+ for (std::string const& argExpanded : argsExpanded) {
+ if (varArgExpanded == argExpanded) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ if (!value.empty()) {
+ value += ";";
+ }
+ value += varArgExpanded;
+ }
+ }
+
+ // add the definition
+ status.GetMakefile().AddDefinition(variable, value);
+
+ return true;
+}
diff --git a/Source/cmRemoveCommand.h b/Source/cmRemoveCommand.h
new file mode 100644
index 0000000..37bfd8c
--- /dev/null
+++ b/Source/cmRemoveCommand.h
@@ -0,0 +1,18 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief remove command
+ *
+ * cmRemoveCommand implements the remove CMake command
+ */
+bool cmRemoveCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmRemoveDefinitionsCommand.cxx b/Source/cmRemoveDefinitionsCommand.cxx
new file mode 100644
index 0000000..339ff9d
--- /dev/null
+++ b/Source/cmRemoveDefinitionsCommand.cxx
@@ -0,0 +1,16 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmRemoveDefinitionsCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+
+bool cmRemoveDefinitionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ cmMakefile& mf = status.GetMakefile();
+ for (std::string const& i : args) {
+ mf.RemoveDefineFlag(i);
+ }
+ return true;
+}
diff --git a/Source/cmRemoveDefinitionsCommand.h b/Source/cmRemoveDefinitionsCommand.h
new file mode 100644
index 0000000..8d0fe18
--- /dev/null
+++ b/Source/cmRemoveDefinitionsCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmRemoveDefinitionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmReturnCommand.cxx b/Source/cmReturnCommand.cxx
new file mode 100644
index 0000000..5905669
--- /dev/null
+++ b/Source/cmReturnCommand.cxx
@@ -0,0 +1,13 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmReturnCommand.h"
+
+#include "cmExecutionStatus.h"
+
+// cmReturnCommand
+bool cmReturnCommand(std::vector<std::string> const&,
+ cmExecutionStatus& status)
+{
+ status.SetReturnInvoked();
+ return true;
+}
diff --git a/Source/cmReturnCommand.h b/Source/cmReturnCommand.h
new file mode 100644
index 0000000..abae1a4
--- /dev/null
+++ b/Source/cmReturnCommand.h
@@ -0,0 +1,14 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/// Return from a directory or function
+bool cmReturnCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx
new file mode 100644
index 0000000..d00bbdf
--- /dev/null
+++ b/Source/cmRulePlaceholderExpander.cxx
@@ -0,0 +1,374 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmRulePlaceholderExpander.h"
+
+#include <cctype>
+#include <utility>
+
+#include "cmOutputConverter.h"
+#include "cmSystemTools.h"
+
+cmRulePlaceholderExpander::cmRulePlaceholderExpander(
+ std::map<std::string, std::string> compilers,
+ std::map<std::string, std::string> variableMappings,
+ std::string compilerSysroot, std::string linkerSysroot)
+ : Compilers(std::move(compilers))
+ , VariableMappings(std::move(variableMappings))
+ , CompilerSysroot(std::move(compilerSysroot))
+ , LinkerSysroot(std::move(linkerSysroot))
+{
+}
+
+std::string cmRulePlaceholderExpander::ExpandRuleVariable(
+ cmOutputConverter* outputConverter, std::string const& variable,
+ const RuleVariables& replaceValues)
+{
+ if (replaceValues.LinkFlags) {
+ if (variable == "LINK_FLAGS") {
+ return replaceValues.LinkFlags;
+ }
+ }
+ if (replaceValues.Manifests) {
+ if (variable == "MANIFESTS") {
+ return replaceValues.Manifests;
+ }
+ }
+ if (replaceValues.Flags) {
+ if (variable == "FLAGS") {
+ return replaceValues.Flags;
+ }
+ }
+
+ if (replaceValues.Source) {
+ if (variable == "SOURCE") {
+ return replaceValues.Source;
+ }
+ }
+ if (replaceValues.DynDepFile) {
+ if (variable == "DYNDEP_FILE") {
+ return replaceValues.DynDepFile;
+ }
+ }
+ if (replaceValues.PreprocessedSource) {
+ if (variable == "PREPROCESSED_SOURCE") {
+ return replaceValues.PreprocessedSource;
+ }
+ }
+ if (replaceValues.AssemblySource) {
+ if (variable == "ASSEMBLY_SOURCE") {
+ return replaceValues.AssemblySource;
+ }
+ }
+ if (replaceValues.Object) {
+ if (variable == "OBJECT") {
+ return replaceValues.Object;
+ }
+ }
+ if (replaceValues.ObjectDir) {
+ if (variable == "OBJECT_DIR") {
+ return replaceValues.ObjectDir;
+ }
+ }
+ if (replaceValues.ObjectFileDir) {
+ if (variable == "OBJECT_FILE_DIR") {
+ return replaceValues.ObjectFileDir;
+ }
+ }
+ if (replaceValues.Objects) {
+ if (variable == "OBJECTS") {
+ return replaceValues.Objects;
+ }
+ }
+ if (replaceValues.ObjectsQuoted) {
+ if (variable == "OBJECTS_QUOTED") {
+ return replaceValues.ObjectsQuoted;
+ }
+ }
+ if (replaceValues.AIXExports) {
+ if (variable == "AIX_EXPORTS") {
+ return replaceValues.AIXExports;
+ }
+ }
+ if (replaceValues.ISPCHeader) {
+ if (variable == "ISPC_HEADER") {
+ return replaceValues.ISPCHeader;
+ }
+ }
+ if (replaceValues.Defines && variable == "DEFINES") {
+ return replaceValues.Defines;
+ }
+ if (replaceValues.Includes && variable == "INCLUDES") {
+ return replaceValues.Includes;
+ }
+ if (replaceValues.SwiftLibraryName) {
+ if (variable == "SWIFT_LIBRARY_NAME") {
+ return replaceValues.SwiftLibraryName;
+ }
+ }
+ if (replaceValues.SwiftModule) {
+ if (variable == "SWIFT_MODULE") {
+ return replaceValues.SwiftModule;
+ }
+ }
+ if (replaceValues.SwiftModuleName) {
+ if (variable == "SWIFT_MODULE_NAME") {
+ return replaceValues.SwiftModuleName;
+ }
+ }
+ if (replaceValues.SwiftOutputFileMap) {
+ if (variable == "SWIFT_OUTPUT_FILE_MAP") {
+ return replaceValues.SwiftOutputFileMap;
+ }
+ }
+ if (replaceValues.SwiftSources) {
+ if (variable == "SWIFT_SOURCES") {
+ return replaceValues.SwiftSources;
+ }
+ }
+ if (replaceValues.TargetPDB) {
+ if (variable == "TARGET_PDB") {
+ return replaceValues.TargetPDB;
+ }
+ }
+ if (replaceValues.TargetCompilePDB) {
+ if (variable == "TARGET_COMPILE_PDB") {
+ return replaceValues.TargetCompilePDB;
+ }
+ }
+ if (replaceValues.DependencyFile) {
+ if (variable == "DEP_FILE") {
+ return replaceValues.DependencyFile;
+ }
+ }
+ if (replaceValues.DependencyTarget) {
+ if (variable == "DEP_TARGET") {
+ return replaceValues.DependencyTarget;
+ }
+ }
+ if (replaceValues.Fatbinary) {
+ if (variable == "FATBINARY") {
+ return replaceValues.Fatbinary;
+ }
+ }
+ if (replaceValues.RegisterFile) {
+ if (variable == "REGISTER_FILE") {
+ return replaceValues.RegisterFile;
+ }
+ }
+
+ if (replaceValues.Target) {
+ if (variable == "TARGET_QUOTED") {
+ std::string targetQuoted = replaceValues.Target;
+ if (!targetQuoted.empty() && targetQuoted.front() != '\"') {
+ targetQuoted = '\"';
+ targetQuoted += replaceValues.Target;
+ targetQuoted += '\"';
+ }
+ return targetQuoted;
+ }
+ if (variable == "TARGET_UNQUOTED") {
+ std::string unquoted = replaceValues.Target;
+ std::string::size_type sz = unquoted.size();
+ if (sz > 2 && unquoted.front() == '\"' && unquoted.back() == '\"') {
+ unquoted = unquoted.substr(1, sz - 2);
+ }
+ return unquoted;
+ }
+ if (replaceValues.LanguageCompileFlags) {
+ if (variable == "LANGUAGE_COMPILE_FLAGS") {
+ return replaceValues.LanguageCompileFlags;
+ }
+ }
+ if (replaceValues.Target) {
+ if (variable == "TARGET") {
+ return replaceValues.Target;
+ }
+ }
+ if (variable == "TARGET_IMPLIB") {
+ return this->TargetImpLib;
+ }
+ if (variable == "TARGET_VERSION_MAJOR") {
+ if (replaceValues.TargetVersionMajor) {
+ return replaceValues.TargetVersionMajor;
+ }
+ return "0";
+ }
+ if (variable == "TARGET_VERSION_MINOR") {
+ if (replaceValues.TargetVersionMinor) {
+ return replaceValues.TargetVersionMinor;
+ }
+ return "0";
+ }
+ if (replaceValues.Target) {
+ if (variable == "TARGET_BASE") {
+ // Strip the last extension off the target name.
+ std::string targetBase = replaceValues.Target;
+ std::string::size_type pos = targetBase.rfind('.');
+ if (pos != std::string::npos) {
+ return targetBase.substr(0, pos);
+ }
+ return targetBase;
+ }
+ }
+ }
+ if (variable == "TARGET_SONAME" || variable == "SONAME_FLAG" ||
+ variable == "TARGET_INSTALLNAME_DIR") {
+ // All these variables depend on TargetSOName
+ if (replaceValues.TargetSOName) {
+ if (variable == "TARGET_SONAME") {
+ return replaceValues.TargetSOName;
+ }
+ if (variable == "SONAME_FLAG" && replaceValues.SONameFlag) {
+ return replaceValues.SONameFlag;
+ }
+ if (replaceValues.TargetInstallNameDir &&
+ variable == "TARGET_INSTALLNAME_DIR") {
+ return replaceValues.TargetInstallNameDir;
+ }
+ }
+ return "";
+ }
+ if (replaceValues.LinkLibraries) {
+ if (variable == "LINK_LIBRARIES") {
+ return replaceValues.LinkLibraries;
+ }
+ }
+ if (replaceValues.Language) {
+ if (variable == "LANGUAGE") {
+ return replaceValues.Language;
+ }
+ }
+ if (replaceValues.CMTargetName) {
+ if (variable == "TARGET_NAME") {
+ return replaceValues.CMTargetName;
+ }
+ }
+ if (replaceValues.CMTargetType) {
+ if (variable == "TARGET_TYPE") {
+ return replaceValues.CMTargetType;
+ }
+ }
+ if (replaceValues.Output) {
+ if (variable == "OUTPUT") {
+ return replaceValues.Output;
+ }
+ }
+ if (variable == "CMAKE_COMMAND") {
+ return outputConverter->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
+ }
+
+ auto compIt = this->Compilers.find(variable);
+
+ if (compIt != this->Compilers.end()) {
+ std::string ret = outputConverter->ConvertToOutputForExisting(
+ this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER"]);
+ std::string const& compilerArg1 =
+ this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER_ARG1"];
+ std::string const& compilerTarget =
+ this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER_TARGET"];
+ std::string const& compilerOptionTarget =
+ this->VariableMappings["CMAKE_" + compIt->second +
+ "_COMPILE_OPTIONS_TARGET"];
+ std::string const& compilerExternalToolchain =
+ this->VariableMappings["CMAKE_" + compIt->second +
+ "_COMPILER_EXTERNAL_TOOLCHAIN"];
+ std::string const& compilerOptionExternalToolchain =
+ this->VariableMappings["CMAKE_" + compIt->second +
+ "_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN"];
+ std::string const& compilerOptionSysroot =
+ this->VariableMappings["CMAKE_" + compIt->second +
+ "_COMPILE_OPTIONS_SYSROOT"];
+
+ // if there are required arguments to the compiler add it
+ // to the compiler string
+ if (!compilerArg1.empty()) {
+ ret += " ";
+ ret += compilerArg1;
+ }
+ if (!compilerTarget.empty() && !compilerOptionTarget.empty()) {
+ ret += " ";
+ ret += compilerOptionTarget;
+ ret += compilerTarget;
+ }
+ if (!compilerExternalToolchain.empty() &&
+ !compilerOptionExternalToolchain.empty()) {
+ ret += " ";
+ ret += compilerOptionExternalToolchain;
+ ret += outputConverter->EscapeForShell(compilerExternalToolchain, true);
+ }
+ std::string sysroot;
+ // Some platforms may use separate sysroots for compiling and linking.
+ // If we detect link flags, then we pass the link sysroot instead.
+ // FIXME: Use a more robust way to detect link line expansion.
+ if (replaceValues.LinkFlags) {
+ sysroot = this->LinkerSysroot;
+ } else {
+ sysroot = this->CompilerSysroot;
+ }
+ if (!sysroot.empty() && !compilerOptionSysroot.empty()) {
+ ret += " ";
+ ret += compilerOptionSysroot;
+ ret += outputConverter->EscapeForShell(sysroot, true);
+ }
+ return ret;
+ }
+
+ auto mapIt = this->VariableMappings.find(variable);
+ if (mapIt != this->VariableMappings.end()) {
+ if (variable.find("_FLAG") == std::string::npos) {
+ return outputConverter->ConvertToOutputForExisting(mapIt->second);
+ }
+ return mapIt->second;
+ }
+ return variable;
+}
+
+void cmRulePlaceholderExpander::ExpandRuleVariables(
+ cmOutputConverter* outputConverter, std::string& s,
+ const RuleVariables& replaceValues)
+{
+ std::string::size_type start = s.find('<');
+ // no variables to expand
+ if (start == std::string::npos) {
+ return;
+ }
+ std::string::size_type pos = 0;
+ std::string expandedInput;
+ while (start != std::string::npos && start < s.size() - 2) {
+ std::string::size_type end = s.find('>', start);
+ // if we find a < with no > we are done
+ if (end == std::string::npos) {
+ return;
+ }
+ char c = s[start + 1];
+ // if the next char after the < is not A-Za-z then
+ // skip it and try to find the next < in the string
+ if (!isalpha(c)) {
+ start = s.find('<', start + 1);
+ } else {
+ // extract the var
+ std::string var = s.substr(start + 1, end - start - 1);
+ std::string replace =
+ this->ExpandRuleVariable(outputConverter, var, replaceValues);
+ expandedInput += s.substr(pos, start - pos);
+
+ // Prevent consecutive whitespace in the output if the rule variable
+ // expands to an empty string.
+ bool consecutive = replace.empty() && start > 0 && s[start - 1] == ' ' &&
+ end + 1 < s.size() && s[end + 1] == ' ';
+ if (consecutive) {
+ expandedInput.pop_back();
+ }
+
+ expandedInput += replace;
+
+ // move to next one
+ start = s.find('<', start + var.size() + 2);
+ pos = end + 1;
+ }
+ }
+ // add the rest of the input
+ expandedInput += s.substr(pos, s.size() - pos);
+ s = expandedInput;
+}
diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h
new file mode 100644
index 0000000..f8dc368
--- /dev/null
+++ b/Source/cmRulePlaceholderExpander.h
@@ -0,0 +1,89 @@
+/* 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 <map>
+#include <string>
+
+class cmOutputConverter;
+
+class cmRulePlaceholderExpander
+{
+public:
+ cmRulePlaceholderExpander(
+ std::map<std::string, std::string> compilers,
+ std::map<std::string, std::string> variableMappings,
+ std::string compilerSysroot, std::string linkerSysroot);
+
+ void SetTargetImpLib(std::string const& targetImpLib)
+ {
+ this->TargetImpLib = targetImpLib;
+ }
+
+ // Create a struct to hold the variables passed into
+ // ExpandRuleVariables
+ struct RuleVariables
+ {
+ const char* CMTargetName = nullptr;
+ const char* CMTargetType = nullptr;
+ const char* TargetPDB = nullptr;
+ const char* TargetCompilePDB = nullptr;
+ const char* TargetVersionMajor = nullptr;
+ const char* TargetVersionMinor = nullptr;
+ const char* Language = nullptr;
+ const char* AIXExports = nullptr;
+ const char* Objects = nullptr;
+ const char* Target = nullptr;
+ const char* LinkLibraries = nullptr;
+ const char* Source = nullptr;
+ const char* AssemblySource = nullptr;
+ const char* PreprocessedSource = nullptr;
+ const char* DynDepFile = nullptr;
+ const char* Output = nullptr;
+ const char* Object = nullptr;
+ const char* ObjectDir = nullptr;
+ const char* ObjectFileDir = nullptr;
+ const char* Flags = nullptr;
+ const char* ObjectsQuoted = nullptr;
+ const char* SONameFlag = nullptr;
+ const char* TargetSOName = nullptr;
+ const char* TargetInstallNameDir = nullptr;
+ const char* LinkFlags = nullptr;
+ const char* Manifests = nullptr;
+ const char* LanguageCompileFlags = nullptr;
+ const char* Defines = nullptr;
+ const char* Includes = nullptr;
+ const char* DependencyFile = nullptr;
+ const char* DependencyTarget = nullptr;
+ const char* FilterPrefix = nullptr;
+ const char* SwiftLibraryName = nullptr;
+ const char* SwiftModule = nullptr;
+ const char* SwiftModuleName = nullptr;
+ const char* SwiftOutputFileMap = nullptr;
+ const char* SwiftSources = nullptr;
+ const char* ISPCHeader = nullptr;
+ const char* Fatbinary = nullptr;
+ const char* RegisterFile = nullptr;
+ };
+
+ // Expand rule variables in CMake of the type found in language rules
+ void ExpandRuleVariables(cmOutputConverter* outputConverter,
+ std::string& string,
+ const RuleVariables& replaceValues);
+
+ // Expand rule variables in a single string
+ std::string ExpandRuleVariable(cmOutputConverter* outputConverter,
+ std::string const& variable,
+ const RuleVariables& replaceValues);
+
+private:
+ std::string TargetImpLib;
+
+ std::map<std::string, std::string> Compilers;
+ std::map<std::string, std::string> VariableMappings;
+ std::string CompilerSysroot;
+ std::string LinkerSysroot;
+};
diff --git a/Source/cmRuntimeDependencyArchive.cxx b/Source/cmRuntimeDependencyArchive.cxx
new file mode 100644
index 0000000..472f234
--- /dev/null
+++ b/Source/cmRuntimeDependencyArchive.cxx
@@ -0,0 +1,378 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmRuntimeDependencyArchive.h"
+
+#include "cmBinUtilsLinuxELFLinker.h"
+#include "cmBinUtilsMacOSMachOLinker.h"
+#include "cmBinUtilsWindowsPELinker.h"
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+#if defined(_WIN32)
+# include "cmGlobalGenerator.h"
+# ifndef CMAKE_BOOTSTRAP
+# include "cmGlobalVisualStudioVersionedGenerator.h"
+# endif
+# include "cmsys/Glob.hxx"
+
+# include "cmVSSetupHelper.h"
+#endif
+
+#include <algorithm>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+
+#if defined(_WIN32)
+static void AddVisualStudioPath(std::vector<std::string>& paths,
+ const std::string& prefix,
+ unsigned int version, cmGlobalGenerator* gg)
+{
+ // If generating for the VS IDE, use the same instance.
+ std::string vsloc;
+ bool found = false;
+# ifndef CMAKE_BOOTSTRAP
+ if (cmHasPrefix(gg->GetName(), prefix)) {
+ cmGlobalVisualStudioVersionedGenerator* vsgen =
+ static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg);
+ if (vsgen->GetVSInstance(vsloc)) {
+ found = true;
+ }
+ }
+# endif
+
+ // Otherwise, find a VS instance ourselves.
+ if (!found) {
+ cmVSSetupAPIHelper vsSetupAPIHelper(version);
+ if (vsSetupAPIHelper.GetVSInstanceInfo(vsloc)) {
+ cmSystemTools::ConvertToUnixSlashes(vsloc);
+ found = true;
+ }
+ }
+
+ if (found) {
+ cmsys::Glob glob;
+ glob.SetListDirs(true);
+ glob.FindFiles(vsloc + "/VC/Tools/MSVC/*");
+ for (auto const& vcdir : glob.GetFiles()) {
+ paths.push_back(vcdir + "/bin/Hostx64/x64");
+ paths.push_back(vcdir + "/bin/Hostx86/x64");
+ paths.push_back(vcdir + "/bin/Hostx64/x86");
+ paths.push_back(vcdir + "/bin/Hostx86/x86");
+ }
+ }
+}
+
+static void AddRegistryPath(std::vector<std::string>& paths,
+ const std::string& path, cmMakefile* mf)
+{
+ // We should view the registry as the target application would view
+ // it.
+ cmSystemTools::KeyWOW64 view = cmSystemTools::KeyWOW64_32;
+ cmSystemTools::KeyWOW64 other_view = cmSystemTools::KeyWOW64_64;
+ if (mf->PlatformIs64Bit()) {
+ view = cmSystemTools::KeyWOW64_64;
+ other_view = cmSystemTools::KeyWOW64_32;
+ }
+
+ // Expand using the view of the target application.
+ std::string expanded = path;
+ cmSystemTools::ExpandRegistryValues(expanded, view);
+ cmSystemTools::GlobDirs(expanded, paths);
+
+ // Executables can be either 32-bit or 64-bit, so expand using the
+ // alternative view.
+ expanded = path;
+ cmSystemTools::ExpandRegistryValues(expanded, other_view);
+ cmSystemTools::GlobDirs(expanded, paths);
+}
+
+static void AddEnvPath(std::vector<std::string>& paths, const std::string& var,
+ const std::string& suffix)
+{
+ std::string value;
+ if (cmSystemTools::GetEnv(var, value)) {
+ paths.push_back(value + suffix);
+ }
+}
+#endif
+
+static cmsys::RegularExpression TransformCompile(const std::string& str)
+{
+ return cmsys::RegularExpression(str);
+}
+
+cmRuntimeDependencyArchive::cmRuntimeDependencyArchive(
+ cmExecutionStatus& status, std::vector<std::string> searchDirectories,
+ std::string bundleExecutable,
+ const std::vector<std::string>& preIncludeRegexes,
+ const std::vector<std::string>& preExcludeRegexes,
+ const std::vector<std::string>& postIncludeRegexes,
+ const std::vector<std::string>& postExcludeRegexes)
+ : Status(status)
+ , SearchDirectories(std::move(searchDirectories))
+ , BundleExecutable(std::move(bundleExecutable))
+ , PreIncludeRegexes(preIncludeRegexes.size())
+ , PreExcludeRegexes(preExcludeRegexes.size())
+ , PostIncludeRegexes(postIncludeRegexes.size())
+ , PostExcludeRegexes(postExcludeRegexes.size())
+{
+ std::transform(preIncludeRegexes.begin(), preIncludeRegexes.end(),
+ this->PreIncludeRegexes.begin(), TransformCompile);
+ std::transform(preExcludeRegexes.begin(), preExcludeRegexes.end(),
+ this->PreExcludeRegexes.begin(), TransformCompile);
+ std::transform(postIncludeRegexes.begin(), postIncludeRegexes.end(),
+ this->PostIncludeRegexes.begin(), TransformCompile);
+ std::transform(postExcludeRegexes.begin(), postExcludeRegexes.end(),
+ this->PostExcludeRegexes.begin(), TransformCompile);
+}
+
+bool cmRuntimeDependencyArchive::Prepare()
+{
+ std::string platform = this->GetMakefile()->GetSafeDefinition(
+ "CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM");
+ if (platform.empty()) {
+ std::string systemName =
+ this->GetMakefile()->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
+ if (systemName == "Windows") {
+ platform = "windows+pe";
+ } else if (systemName == "Darwin") {
+ platform = "macos+macho";
+ } else if (systemName == "Linux") {
+ platform = "linux+elf";
+ }
+ }
+ if (platform == "linux+elf") {
+ this->Linker = cm::make_unique<cmBinUtilsLinuxELFLinker>(this);
+ } else if (platform == "windows+pe") {
+ this->Linker = cm::make_unique<cmBinUtilsWindowsPELinker>(this);
+ } else if (platform == "macos+macho") {
+ this->Linker = cm::make_unique<cmBinUtilsMacOSMachOLinker>(this);
+ } else {
+ std::ostringstream e;
+ e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM: "
+ << platform;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return this->Linker->Prepare();
+}
+
+bool cmRuntimeDependencyArchive::GetRuntimeDependencies(
+ const std::vector<std::string>& executables,
+ const std::vector<std::string>& libraries,
+ const std::vector<std::string>& modules)
+{
+ for (auto const& exe : executables) {
+ if (!this->Linker->ScanDependencies(exe, cmStateEnums::EXECUTABLE)) {
+ return false;
+ }
+ }
+ for (auto const& lib : libraries) {
+ if (!this->Linker->ScanDependencies(lib, cmStateEnums::SHARED_LIBRARY)) {
+ return false;
+ }
+ }
+ return std::all_of(
+ modules.begin(), modules.end(), [this](std::string const& mod) -> bool {
+ return this->Linker->ScanDependencies(mod, cmStateEnums::MODULE_LIBRARY);
+ });
+}
+
+void cmRuntimeDependencyArchive::SetError(const std::string& e)
+{
+ this->Status.SetError(e);
+}
+
+std::string cmRuntimeDependencyArchive::GetBundleExecutable()
+{
+ return this->BundleExecutable;
+}
+
+const std::vector<std::string>&
+cmRuntimeDependencyArchive::GetSearchDirectories()
+{
+ return this->SearchDirectories;
+}
+
+std::string cmRuntimeDependencyArchive::GetGetRuntimeDependenciesTool()
+{
+ return this->GetMakefile()->GetSafeDefinition(
+ "CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL");
+}
+
+bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand(
+ const std::string& search, std::vector<std::string>& command)
+{
+ // First see if it was supplied by the user
+ std::string toolCommand = this->GetMakefile()->GetSafeDefinition(
+ "CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND");
+ if (toolCommand.empty() && search == "objdump") {
+ toolCommand = this->GetMakefile()->GetSafeDefinition("CMAKE_OBJDUMP");
+ }
+ if (!toolCommand.empty()) {
+ cmExpandList(toolCommand, command);
+ return true;
+ }
+
+ // Now go searching for it
+ std::vector<std::string> paths;
+#ifdef _WIN32
+ cmGlobalGenerator* gg = this->GetMakefile()->GetGlobalGenerator();
+
+ // Add newer Visual Studio paths
+ AddVisualStudioPath(paths, "Visual Studio 16 ", 16, gg);
+ AddVisualStudioPath(paths, "Visual Studio 15 ", 15, gg);
+
+ // Add older Visual Studio paths
+ AddRegistryPath(
+ paths,
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0;InstallDir]/"
+ "../../VC/bin",
+ this->GetMakefile());
+ AddEnvPath(paths, "VS140COMNTOOLS", "/../../VC/bin");
+ paths.push_back(
+ "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin");
+ AddRegistryPath(
+ paths,
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0;InstallDir]/"
+ "../../VC/bin",
+ this->GetMakefile());
+ AddEnvPath(paths, "VS120COMNTOOLS", "/../../VC/bin");
+ paths.push_back(
+ "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin");
+ AddRegistryPath(
+ paths,
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0;InstallDir]/"
+ "../../VC/bin",
+ this->GetMakefile());
+ AddEnvPath(paths, "VS110COMNTOOLS", "/../../VC/bin");
+ paths.push_back(
+ "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/bin");
+ AddRegistryPath(
+ paths,
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;InstallDir]/"
+ "../../VC/bin",
+ this->GetMakefile());
+ AddEnvPath(paths, "VS100COMNTOOLS", "/../../VC/bin");
+ paths.push_back(
+ "C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin");
+ AddRegistryPath(
+ paths,
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]/"
+ "../../VC/bin",
+ this->GetMakefile());
+ AddEnvPath(paths, "VS90COMNTOOLS", "/../../VC/bin");
+ paths.push_back("C:/Program Files/Microsoft Visual Studio 9.0/VC/bin");
+ paths.push_back("C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin");
+ AddRegistryPath(
+ paths,
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]/"
+ "../../VC/bin",
+ this->GetMakefile());
+ AddEnvPath(paths, "VS80COMNTOOLS", "/../../VC/bin");
+ paths.push_back("C:/Program Files/Microsoft Visual Studio 8/VC/BIN");
+ paths.push_back("C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN");
+ AddRegistryPath(
+ paths,
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1;InstallDir]/"
+ "../../VC7/bin",
+ this->GetMakefile());
+ AddEnvPath(paths, "VS71COMNTOOLS", "/../../VC7/bin");
+ paths.push_back(
+ "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN");
+ paths.push_back(
+ "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN");
+#endif
+
+ std::string program = cmSystemTools::FindProgram(search, paths);
+ if (!program.empty()) {
+ command = { program };
+ return true;
+ }
+
+ // Couldn't find it
+ return false;
+}
+
+bool cmRuntimeDependencyArchive::IsPreExcluded(const std::string& name)
+{
+ cmsys::RegularExpressionMatch match;
+
+ for (auto const& regex : this->PreIncludeRegexes) {
+ if (regex.find(name.c_str(), match)) {
+ return false;
+ }
+ }
+
+ for (auto const& regex : this->PreExcludeRegexes) {
+ if (regex.find(name.c_str(), match)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string& name)
+{
+ cmsys::RegularExpressionMatch match;
+
+ for (auto const& regex : this->PostIncludeRegexes) {
+ if (regex.find(name.c_str(), match)) {
+ return false;
+ }
+ }
+
+ for (auto const& regex : this->PostExcludeRegexes) {
+ if (regex.find(name.c_str(), match)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void cmRuntimeDependencyArchive::AddResolvedPath(const std::string& name,
+ const std::string& path,
+ bool& unique)
+{
+ auto it = this->ResolvedPaths.emplace(name, std::set<std::string>{}).first;
+ unique = true;
+ for (auto const& other : it->second) {
+ if (cmSystemTools::SameFile(path, other)) {
+ unique = false;
+ break;
+ }
+ }
+ it->second.insert(path);
+}
+
+void cmRuntimeDependencyArchive::AddUnresolvedPath(const std::string& name)
+{
+ this->UnresolvedPaths.insert(name);
+}
+
+cmMakefile* cmRuntimeDependencyArchive::GetMakefile()
+{
+ return &this->Status.GetMakefile();
+}
+
+const std::map<std::string, std::set<std::string>>&
+cmRuntimeDependencyArchive::GetResolvedPaths()
+{
+ return this->ResolvedPaths;
+}
+
+const std::set<std::string>& cmRuntimeDependencyArchive::GetUnresolvedPaths()
+{
+ return this->UnresolvedPaths;
+}
diff --git a/Source/cmRuntimeDependencyArchive.h b/Source/cmRuntimeDependencyArchive.h
new file mode 100644
index 0000000..7f3b8e9
--- /dev/null
+++ b/Source/cmRuntimeDependencyArchive.h
@@ -0,0 +1,67 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmBinUtilsLinker.h"
+
+class cmExecutionStatus;
+class cmMakefile;
+
+class cmRuntimeDependencyArchive
+{
+public:
+ explicit cmRuntimeDependencyArchive(
+ cmExecutionStatus& status, std::vector<std::string> searchDirectories,
+ std::string bundleExecutable,
+ const std::vector<std::string>& preIncludeRegexes,
+ const std::vector<std::string>& preExcludeRegexes,
+ const std::vector<std::string>& postIncludeRegexes,
+ const std::vector<std::string>& postExcludeRegexes);
+ bool Prepare();
+ bool GetRuntimeDependencies(const std::vector<std::string>& executables,
+ const std::vector<std::string>& libraries,
+ const std::vector<std::string>& modules);
+
+ void SetError(const std::string& e);
+
+ std::string GetBundleExecutable();
+ const std::vector<std::string>& GetSearchDirectories();
+ std::string GetGetRuntimeDependenciesTool();
+ bool GetGetRuntimeDependenciesCommand(const std::string& search,
+ std::vector<std::string>& command);
+ bool IsPreExcluded(const std::string& name);
+ bool IsPostExcluded(const std::string& name);
+
+ void AddResolvedPath(const std::string& name, const std::string& path,
+ bool& unique);
+ void AddUnresolvedPath(const std::string& name);
+
+ cmMakefile* GetMakefile();
+ const std::map<std::string, std::set<std::string>>& GetResolvedPaths();
+ const std::set<std::string>& GetUnresolvedPaths();
+
+private:
+ cmExecutionStatus& Status;
+ std::unique_ptr<cmBinUtilsLinker> Linker;
+
+ std::string GetRuntimeDependenciesTool;
+ std::vector<std::string> GetRuntimeDependenciesCommand;
+
+ std::vector<std::string> SearchDirectories;
+ std::string BundleExecutable;
+ std::vector<cmsys::RegularExpression> PreIncludeRegexes;
+ std::vector<cmsys::RegularExpression> PreExcludeRegexes;
+ std::vector<cmsys::RegularExpression> PostIncludeRegexes;
+ std::vector<cmsys::RegularExpression> PostExcludeRegexes;
+ std::map<std::string, std::set<std::string>> ResolvedPaths;
+ std::set<std::string> UnresolvedPaths;
+};
diff --git a/Source/cmScanDepFormat.cxx b/Source/cmScanDepFormat.cxx
new file mode 100644
index 0000000..e046069
--- /dev/null
+++ b/Source/cmScanDepFormat.cxx
@@ -0,0 +1,265 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmScanDepFormat.h"
+
+#include <cctype>
+#include <cstdio>
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+#include <cm3p/json/writer.h>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+static bool ParseFilename(Json::Value const& val, std::string& result)
+{
+ if (val.isString()) {
+ result = val.asString();
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+static Json::Value EncodeFilename(std::string const& path)
+{
+ std::string data;
+ data.reserve(path.size());
+
+ for (auto const& byte : path) {
+ if (std::iscntrl(byte)) {
+ // Control characters.
+ data.append("\\u");
+ char buf[5];
+ std::snprintf(buf, sizeof(buf), "%04x", byte);
+ data.append(buf);
+ } else if (byte == '"' || byte == '\\') {
+ // Special JSON characters.
+ data.push_back('\\');
+ data.push_back(byte);
+ } else {
+ // Other data.
+ data.push_back(byte);
+ }
+ }
+
+ return data;
+}
+
+#define PARSE_BLOB(val, res) \
+ do { \
+ if (!ParseFilename(val, res)) { \
+ cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", \
+ arg_pp, ": invalid blob")); \
+ return false; \
+ } \
+ } while (0)
+
+#define PARSE_FILENAME(val, res) \
+ do { \
+ if (!ParseFilename(val, res)) { \
+ cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", \
+ arg_pp, ": invalid filename")); \
+ return false; \
+ } \
+ \
+ if (!cmSystemTools::FileIsFullPath(res)) { \
+ res = cmStrCat(work_directory, '/', res); \
+ } \
+ } while (0)
+
+bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp, cmSourceInfo* info)
+{
+ Json::Value ppio;
+ Json::Value const& ppi = ppio;
+ cmsys::ifstream ppf(arg_pp.c_str(), std::ios::in | std::ios::binary);
+ {
+ Json::Reader reader;
+ if (!reader.parse(ppf, ppio, false)) {
+ cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
+ arg_pp,
+ reader.getFormattedErrorMessages()));
+ return false;
+ }
+ }
+
+ Json::Value const& version = ppi["version"];
+ if (version.asUInt() != 0) {
+ cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
+ arg_pp, ": version ", version.asString()));
+ return false;
+ }
+
+ Json::Value const& rules = ppi["rules"];
+ if (rules.isArray()) {
+ if (rules.size() != 1) {
+ cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
+ arg_pp, ": expected 1 source entry"));
+ return false;
+ }
+
+ for (auto const& rule : rules) {
+ Json::Value const& workdir = rule["work-directory"];
+ if (!workdir.isString()) {
+ cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
+ arg_pp,
+ ": work-directory is not a string"));
+ return false;
+ }
+ std::string work_directory;
+ PARSE_BLOB(workdir, work_directory);
+
+ Json::Value const& depends = rule["depends"];
+ if (depends.isArray()) {
+ std::string depend_filename;
+ for (auto const& depend : depends) {
+ PARSE_FILENAME(depend, depend_filename);
+ info->Includes.push_back(depend_filename);
+ }
+ }
+
+ if (rule.isMember("future-compile")) {
+ Json::Value const& future_compile = rule["future-compile"];
+
+ if (future_compile.isMember("outputs")) {
+ Json::Value const& outputs = future_compile["outputs"];
+ if (outputs.isArray()) {
+ if (outputs.empty()) {
+ cmSystemTools::Error(
+ cmStrCat("-E cmake_ninja_dyndep failed to parse ", arg_pp,
+ ": expected at least one 1 output"));
+ return false;
+ }
+
+ PARSE_FILENAME(outputs[0], info->PrimaryOutput);
+ }
+ }
+
+ if (future_compile.isMember("provides")) {
+ Json::Value const& provides = future_compile["provides"];
+ if (provides.isArray()) {
+ for (auto const& provide : provides) {
+ cmSourceReqInfo provide_info;
+
+ Json::Value const& logical_name = provide["logical-name"];
+ PARSE_BLOB(logical_name, provide_info.LogicalName);
+
+ if (provide.isMember("compiled-module-path")) {
+ Json::Value const& compiled_module_path =
+ provide["compiled-module-path"];
+ PARSE_FILENAME(compiled_module_path,
+ provide_info.CompiledModulePath);
+ } else {
+ provide_info.CompiledModulePath =
+ cmStrCat(provide_info.LogicalName, ".mod");
+ }
+
+ info->Provides.push_back(provide_info);
+ }
+ }
+ }
+
+ if (future_compile.isMember("requires")) {
+ Json::Value const& reqs = future_compile["requires"];
+ if (reqs.isArray()) {
+ for (auto const& require : reqs) {
+ cmSourceReqInfo require_info;
+
+ Json::Value const& logical_name = require["logical-name"];
+ PARSE_BLOB(logical_name, require_info.LogicalName);
+
+ if (require.isMember("compiled-module-path")) {
+ Json::Value const& compiled_module_path =
+ require["compiled-module-path"];
+ PARSE_FILENAME(compiled_module_path,
+ require_info.CompiledModulePath);
+ }
+
+ info->Requires.push_back(require_info);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool cmScanDepFormat_P1689_Write(std::string const& path,
+ std::string const& input,
+ cmSourceInfo const& info)
+{
+ Json::Value ddi(Json::objectValue);
+ ddi["version"] = 0;
+ ddi["revision"] = 0;
+
+ Json::Value& rules = ddi["rules"] = Json::arrayValue;
+
+ Json::Value rule(Json::objectValue);
+ rule["work-directory"] =
+ EncodeFilename(cmSystemTools::GetCurrentWorkingDirectory());
+ Json::Value& inputs = rule["inputs"] = Json::arrayValue;
+ inputs.append(EncodeFilename(input));
+
+ Json::Value& rule_outputs = rule["outputs"] = Json::arrayValue;
+ rule_outputs.append(EncodeFilename(path));
+
+ Json::Value& depends = rule["depends"] = Json::arrayValue;
+ for (auto const& include : info.Includes) {
+ depends.append(EncodeFilename(include));
+ }
+
+ Json::Value& future_compile = rule["future-compile"] = Json::objectValue;
+
+ Json::Value& outputs = future_compile["outputs"] = Json::arrayValue;
+ outputs.append(info.PrimaryOutput);
+
+ Json::Value& provides = future_compile["provides"] = Json::arrayValue;
+ for (auto const& provide : info.Provides) {
+ Json::Value provide_obj(Json::objectValue);
+ auto const encoded = EncodeFilename(provide.LogicalName);
+ provide_obj["logical-name"] = encoded;
+ if (provide.CompiledModulePath.empty()) {
+ provide_obj["compiled-module-path"] = encoded;
+ } else {
+ provide_obj["compiled-module-path"] =
+ EncodeFilename(provide.CompiledModulePath);
+ }
+
+ // TODO: Source file tracking. See below.
+
+ provides.append(provide_obj);
+ }
+
+ Json::Value& reqs = future_compile["requires"] = Json::arrayValue;
+ for (auto const& require : info.Requires) {
+ Json::Value require_obj(Json::objectValue);
+ auto const encoded = EncodeFilename(require.LogicalName);
+ require_obj["logical-name"] = encoded;
+ if (require.CompiledModulePath.empty()) {
+ require_obj["compiled-module-path"] = encoded;
+ } else {
+ require_obj["compiled-module-path"] =
+ EncodeFilename(require.CompiledModulePath);
+ }
+
+ // TODO: Source filename inclusion. Requires collating with the provides
+ // filenames (as a sanity check if available on both sides).
+
+ reqs.append(require_obj);
+ }
+
+ rules.append(rule);
+
+ cmGeneratedFileStream ddif(path);
+ ddif << ddi;
+
+ return !!ddif;
+}
diff --git a/Source/cmScanDepFormat.h b/Source/cmScanDepFormat.h
new file mode 100644
index 0000000..1ad0ecf
--- /dev/null
+++ b/Source/cmScanDepFormat.h
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+#include <vector>
+
+struct cmSourceReqInfo
+{
+ std::string LogicalName;
+ std::string CompiledModulePath;
+};
+
+struct cmSourceInfo
+{
+ std::string PrimaryOutput;
+
+ // Set of provided and required modules.
+ std::vector<cmSourceReqInfo> Provides;
+ std::vector<cmSourceReqInfo> Requires;
+
+ // Set of files included in the translation unit.
+ std::vector<std::string> Includes;
+};
+
+bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp,
+ cmSourceInfo* info);
+bool cmScanDepFormat_P1689_Write(std::string const& path,
+ std::string const& input,
+ cmSourceInfo const& info);
diff --git a/Source/cmScriptGenerator.cxx b/Source/cmScriptGenerator.cxx
new file mode 100644
index 0000000..5ac7be9
--- /dev/null
+++ b/Source/cmScriptGenerator.cxx
@@ -0,0 +1,176 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmScriptGenerator.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmScriptGenerator::cmScriptGenerator(std::string config_var,
+ std::vector<std::string> configurations)
+ : RuntimeConfigVariable(std::move(config_var))
+ , Configurations(std::move(configurations))
+ , ConfigurationTypes(nullptr)
+ , ActionsPerConfig(false)
+{
+}
+
+cmScriptGenerator::~cmScriptGenerator() = default;
+
+void cmScriptGenerator::Generate(
+ std::ostream& os, const std::string& config,
+ std::vector<std::string> const& configurationTypes)
+{
+ this->ConfigurationName = config;
+ this->ConfigurationTypes = &configurationTypes;
+ this->GenerateScript(os);
+ this->ConfigurationName.clear();
+ this->ConfigurationTypes = nullptr;
+}
+
+static void cmScriptGeneratorEncodeConfig(const std::string& config,
+ std::string& result)
+{
+ for (const char* c = config.c_str(); *c; ++c) {
+ if (*c >= 'a' && *c <= 'z') {
+ result += "[";
+ result += static_cast<char>(*c + 'A' - 'a');
+ result += *c;
+ result += "]";
+ } else if (*c >= 'A' && *c <= 'Z') {
+ result += "[";
+ result += *c;
+ result += static_cast<char>(*c + 'a' - 'A');
+ result += "]";
+ } else {
+ result += *c;
+ }
+ }
+}
+
+std::string cmScriptGenerator::CreateConfigTest(const std::string& config)
+{
+ std::string result =
+ cmStrCat("\"${", this->RuntimeConfigVariable, "}\" MATCHES \"^(");
+ if (!config.empty()) {
+ cmScriptGeneratorEncodeConfig(config, result);
+ }
+ result += ")$\"";
+ return result;
+}
+
+std::string cmScriptGenerator::CreateConfigTest(
+ std::vector<std::string> const& configs)
+{
+ std::string result =
+ cmStrCat("\"${", this->RuntimeConfigVariable, "}\" MATCHES \"^(");
+ const char* sep = "";
+ for (std::string const& config : configs) {
+ result += sep;
+ sep = "|";
+ cmScriptGeneratorEncodeConfig(config, result);
+ }
+ result += ")$\"";
+ return result;
+}
+
+void cmScriptGenerator::GenerateScript(std::ostream& os)
+{
+ // Track indentation.
+ Indent indent;
+
+ // Generate the script possibly with per-configuration code.
+ this->GenerateScriptConfigs(os, indent);
+}
+
+void cmScriptGenerator::GenerateScriptConfigs(std::ostream& os, Indent indent)
+{
+ if (this->ActionsPerConfig) {
+ this->GenerateScriptActionsPerConfig(os, indent);
+ } else {
+ this->GenerateScriptActionsOnce(os, indent);
+ }
+}
+
+void cmScriptGenerator::GenerateScriptActions(std::ostream& os, Indent indent)
+{
+ if (this->ActionsPerConfig) {
+ // This is reached for single-configuration build generators in a
+ // per-config script generator.
+ this->GenerateScriptForConfig(os, this->ConfigurationName, indent);
+ }
+}
+
+void cmScriptGenerator::GenerateScriptForConfig(std::ostream& /*unused*/,
+ const std::string& /*unused*/,
+ Indent /*unused*/)
+{
+ // No actions for this generator.
+}
+
+bool cmScriptGenerator::GeneratesForConfig(const std::string& config)
+{
+ // If this is not a configuration-specific rule then we install.
+ if (this->Configurations.empty()) {
+ return true;
+ }
+
+ // This is a configuration-specific rule. Check if the config
+ // matches this rule.
+ std::string config_upper = cmSystemTools::UpperCase(config);
+ return std::any_of(this->Configurations.begin(), this->Configurations.end(),
+ [&config_upper](std::string const& cfg) -> bool {
+ return cmSystemTools::UpperCase(cfg) == config_upper;
+ });
+}
+
+void cmScriptGenerator::GenerateScriptActionsOnce(std::ostream& os,
+ Indent indent)
+{
+ if (this->Configurations.empty()) {
+ // This rule is for all configurations.
+ this->GenerateScriptActions(os, indent);
+ } else {
+ // Generate a per-configuration block.
+ std::string config_test = this->CreateConfigTest(this->Configurations);
+ os << indent << "if(" << config_test << ")\n";
+ this->GenerateScriptActions(os, indent.Next());
+ os << indent << "endif(" << config_test << ")\n";
+ }
+}
+
+void cmScriptGenerator::GenerateScriptActionsPerConfig(std::ostream& os,
+ Indent indent)
+{
+ if (this->ConfigurationTypes->empty()) {
+ // In a single-configuration generator there is only one action
+ // and it applies if the runtime-requested configuration is among
+ // the rule's allowed configurations. The configuration built in
+ // the tree does not matter for this decision but will be used to
+ // generate proper target file names into the code.
+ this->GenerateScriptActionsOnce(os, indent);
+ } else {
+ // In a multi-configuration generator we produce a separate rule
+ // in a block for each configuration that is built. We restrict
+ // the list of configurations to those to which this rule applies.
+ bool first = true;
+ for (std::string const& cfgType : *this->ConfigurationTypes) {
+ if (this->GeneratesForConfig(cfgType)) {
+ // Generate a per-configuration block.
+ std::string config_test = this->CreateConfigTest(cfgType);
+ os << indent << (first ? "if(" : "elseif(") << config_test << ")\n";
+ this->GenerateScriptForConfig(os, cfgType, indent.Next());
+ first = false;
+ }
+ }
+ if (!first) {
+ if (this->NeedsScriptNoConfig()) {
+ os << indent << "else()\n";
+ this->GenerateScriptNoConfig(os, indent.Next());
+ }
+ os << indent << "endif()\n";
+ }
+ }
+}
diff --git a/Source/cmScriptGenerator.h b/Source/cmScriptGenerator.h
new file mode 100644
index 0000000..46d794c
--- /dev/null
+++ b/Source/cmScriptGenerator.h
@@ -0,0 +1,91 @@
+/* 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 <ostream>
+#include <string>
+#include <vector>
+
+class cmScriptGeneratorIndent
+{
+public:
+ cmScriptGeneratorIndent() = default;
+ cmScriptGeneratorIndent(int level)
+ : Level(level)
+ {
+ }
+ void Write(std::ostream& os) const
+ {
+ for (int i = 0; i < this->Level; ++i) {
+ os << " ";
+ }
+ }
+ cmScriptGeneratorIndent Next(int step = 2) const
+ {
+ return { this->Level + step };
+ }
+
+private:
+ int Level = 0;
+};
+inline std::ostream& operator<<(std::ostream& os,
+ cmScriptGeneratorIndent indent)
+{
+ indent.Write(os);
+ return os;
+}
+
+/** \class cmScriptGenerator
+ * \brief Support class for generating install and test scripts.
+ *
+ */
+class cmScriptGenerator
+{
+public:
+ cmScriptGenerator(std::string config_var,
+ std::vector<std::string> configurations);
+ virtual ~cmScriptGenerator();
+
+ cmScriptGenerator(cmScriptGenerator const&) = delete;
+ cmScriptGenerator& operator=(cmScriptGenerator const&) = delete;
+
+ void Generate(std::ostream& os, const std::string& config,
+ std::vector<std::string> const& configurationTypes);
+
+protected:
+ using Indent = cmScriptGeneratorIndent;
+ virtual void GenerateScript(std::ostream& os);
+ virtual void GenerateScriptConfigs(std::ostream& os, Indent indent);
+ virtual void GenerateScriptActions(std::ostream& os, Indent indent);
+ virtual void GenerateScriptForConfig(std::ostream& os,
+ const std::string& config,
+ Indent indent);
+ virtual void GenerateScriptNoConfig(std::ostream&, Indent) {}
+ virtual bool NeedsScriptNoConfig() const { return false; }
+
+ // Test if this generator does something for a given configuration.
+ bool GeneratesForConfig(const std::string&);
+
+ std::string CreateConfigTest(const std::string& config);
+ std::string CreateConfigTest(std::vector<std::string> const& configs);
+ std::string CreateComponentTest(const std::string& component);
+
+ // Information shared by most generator types.
+ std::string RuntimeConfigVariable;
+ std::vector<std::string> const Configurations;
+
+ // Information used during generation.
+ std::string ConfigurationName;
+ std::vector<std::string> const* ConfigurationTypes;
+
+ // True if the subclass needs to generate an explicit rule for each
+ // configuration. False if the subclass only generates one rule for
+ // all enabled configurations.
+ bool ActionsPerConfig;
+
+private:
+ void GenerateScriptActionsOnce(std::ostream& os, Indent indent);
+ void GenerateScriptActionsPerConfig(std::ostream& os, Indent indent);
+};
diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx
new file mode 100644
index 0000000..a58be62
--- /dev/null
+++ b/Source/cmSearchPath.cxx
@@ -0,0 +1,221 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSearchPath.h"
+
+#include <algorithm>
+#include <cassert>
+#include <utility>
+
+#include "cmFindCommon.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cmSearchPath::cmSearchPath(cmFindCommon* findCmd)
+ : FC(findCmd)
+{
+}
+
+cmSearchPath::~cmSearchPath() = default;
+
+void cmSearchPath::ExtractWithout(const std::set<std::string>& ignore,
+ std::vector<std::string>& outPaths,
+ bool clear) const
+{
+ if (clear) {
+ outPaths.clear();
+ }
+ for (std::string const& path : this->Paths) {
+ if (ignore.count(path) == 0) {
+ outPaths.push_back(path);
+ }
+ }
+}
+
+void cmSearchPath::AddPath(const std::string& path)
+{
+ this->AddPathInternal(path);
+}
+
+void cmSearchPath::AddUserPath(const std::string& path)
+{
+ assert(this->FC != nullptr);
+
+ std::vector<std::string> outPaths;
+
+ // We should view the registry as the target application would view
+ // it.
+ cmSystemTools::KeyWOW64 view = cmSystemTools::KeyWOW64_32;
+ cmSystemTools::KeyWOW64 other_view = cmSystemTools::KeyWOW64_64;
+ if (this->FC->Makefile->PlatformIs64Bit()) {
+ view = cmSystemTools::KeyWOW64_64;
+ other_view = cmSystemTools::KeyWOW64_32;
+ }
+
+ // Expand using the view of the target application.
+ std::string expanded = path;
+ cmSystemTools::ExpandRegistryValues(expanded, view);
+ cmSystemTools::GlobDirs(expanded, outPaths);
+
+ // Executables can be either 32-bit or 64-bit, so expand using the
+ // alternative view.
+ if (expanded != path && this->FC->CMakePathName == "PROGRAM") {
+ expanded = path;
+ cmSystemTools::ExpandRegistryValues(expanded, other_view);
+ cmSystemTools::GlobDirs(expanded, outPaths);
+ }
+
+ // Process them all from the current directory
+ for (std::string const& p : outPaths) {
+ this->AddPathInternal(
+ p, this->FC->Makefile->GetCurrentSourceDirectory().c_str());
+ }
+}
+
+void cmSearchPath::AddCMakePath(const std::string& variable)
+{
+ assert(this->FC != nullptr);
+
+ // Get a path from a CMake variable.
+ if (cmProp value = this->FC->Makefile->GetDefinition(variable)) {
+ std::vector<std::string> expanded = cmExpandedList(*value);
+
+ for (std::string const& p : expanded) {
+ this->AddPathInternal(
+ p, this->FC->Makefile->GetCurrentSourceDirectory().c_str());
+ }
+ }
+}
+
+void cmSearchPath::AddEnvPath(const std::string& variable)
+{
+ std::vector<std::string> expanded;
+ cmSystemTools::GetPath(expanded, variable.c_str());
+ for (std::string const& p : expanded) {
+ this->AddPathInternal(p);
+ }
+}
+
+void cmSearchPath::AddCMakePrefixPath(const std::string& variable)
+{
+ assert(this->FC != nullptr);
+
+ // Get a path from a CMake variable.
+ if (cmProp value = this->FC->Makefile->GetDefinition(variable)) {
+ std::vector<std::string> expanded = cmExpandedList(*value);
+
+ this->AddPrefixPaths(
+ expanded, this->FC->Makefile->GetCurrentSourceDirectory().c_str());
+ }
+}
+
+static std::string cmSearchPathStripBin(std::string const& s)
+{
+ // If the path is a PREFIX/bin case then add its parent instead.
+ if ((cmHasLiteralSuffix(s, "/bin")) || (cmHasLiteralSuffix(s, "/sbin"))) {
+ return cmSystemTools::GetFilenamePath(s);
+ }
+ return s;
+}
+
+void cmSearchPath::AddEnvPrefixPath(const std::string& variable, bool stripBin)
+{
+ std::vector<std::string> expanded;
+ cmSystemTools::GetPath(expanded, variable.c_str());
+ if (stripBin) {
+ std::transform(expanded.begin(), expanded.end(), expanded.begin(),
+ cmSearchPathStripBin);
+ }
+ this->AddPrefixPaths(expanded);
+}
+
+void cmSearchPath::AddSuffixes(const std::vector<std::string>& suffixes)
+{
+ std::vector<std::string> inPaths;
+ inPaths.swap(this->Paths);
+ this->Paths.reserve(inPaths.size() * (suffixes.size() + 1));
+
+ for (std::string& inPath : inPaths) {
+ cmSystemTools::ConvertToUnixSlashes(inPath);
+
+ // if *i is only / then do not add a //
+ // this will get incorrectly considered a network
+ // path on windows and cause huge delays.
+ std::string p = inPath;
+ if (!p.empty() && p.back() != '/') {
+ p += "/";
+ }
+
+ // Combine with all the suffixes
+ for (std::string const& suffix : suffixes) {
+ this->Paths.push_back(p + suffix);
+ }
+
+ // And now the original w/o any suffix
+ this->Paths.push_back(std::move(inPath));
+ }
+}
+
+void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths,
+ const char* base)
+{
+ assert(this->FC != nullptr);
+
+ // default for programs
+ std::string subdir = "bin";
+
+ if (this->FC->CMakePathName == "INCLUDE") {
+ subdir = "include";
+ } else if (this->FC->CMakePathName == "LIBRARY") {
+ subdir = "lib";
+ } else if (this->FC->CMakePathName == "FRAMEWORK") {
+ subdir.clear(); // ? what to do for frameworks ?
+ }
+
+ for (std::string const& path : paths) {
+ std::string dir = path;
+ if (!subdir.empty() && !dir.empty() && dir.back() != '/') {
+ dir += "/";
+ }
+ if (subdir == "include" || subdir == "lib") {
+ cmProp arch =
+ this->FC->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE");
+ if (cmNonempty(arch)) {
+ if (this->FC->Makefile->IsDefinitionSet("CMAKE_SYSROOT") &&
+ this->FC->Makefile->IsDefinitionSet(
+ "CMAKE_PREFIX_LIBRARY_ARCHITECTURE")) {
+ this->AddPathInternal(cmStrCat('/', *arch, dir, subdir), base);
+ } else {
+ this->AddPathInternal(cmStrCat(dir, subdir, '/', *arch), base);
+ }
+ }
+ }
+ std::string add = dir + subdir;
+ if (add != "/") {
+ this->AddPathInternal(add, base);
+ }
+ if (subdir == "bin") {
+ this->AddPathInternal(dir + "sbin", base);
+ }
+ if (!subdir.empty() && path != "/") {
+ this->AddPathInternal(path, base);
+ }
+ }
+}
+
+void cmSearchPath::AddPathInternal(const std::string& path, const char* base)
+{
+ assert(this->FC != nullptr);
+
+ std::string collapsed = cmSystemTools::CollapseFullPath(path, base);
+
+ if (collapsed.empty()) {
+ return;
+ }
+
+ // Insert the path if has not already been emitted.
+ if (this->FC->SearchPathsEmitted.insert(collapsed).second) {
+ this->Paths.push_back(std::move(collapsed));
+ }
+}
diff --git a/Source/cmSearchPath.h b/Source/cmSearchPath.h
new file mode 100644
index 0000000..c15cb97
--- /dev/null
+++ b/Source/cmSearchPath.h
@@ -0,0 +1,51 @@
+/* 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 <cstddef>
+#include <set>
+#include <string>
+#include <vector>
+
+class cmFindCommon;
+
+/** \class cmSearchPath
+ * \brief Container for encapsulating a set of search paths
+ *
+ * cmSearchPath is a container that encapsulates search path construction and
+ * management
+ */
+class cmSearchPath
+{
+public:
+ // cmSearchPath must be initialized from a valid pointer. The only reason
+ // for the default is to allow it to be easily used in stl containers.
+ // Attempting to initialize with a NULL value will fail an assertion
+ cmSearchPath(cmFindCommon* findCmd = nullptr);
+ ~cmSearchPath();
+
+ const std::vector<std::string>& GetPaths() const { return this->Paths; }
+ std::size_t size() const { return this->Paths.size(); }
+
+ void ExtractWithout(const std::set<std::string>& ignore,
+ std::vector<std::string>& outPaths,
+ bool clear = false) const;
+
+ void AddPath(const std::string& path);
+ void AddUserPath(const std::string& path);
+ void AddCMakePath(const std::string& variable);
+ void AddEnvPath(const std::string& variable);
+ void AddCMakePrefixPath(const std::string& variable);
+ void AddEnvPrefixPath(const std::string& variable, bool stripBin = false);
+ void AddSuffixes(const std::vector<std::string>& suffixes);
+ void AddPrefixPaths(const std::vector<std::string>& paths,
+ const char* base = nullptr);
+
+protected:
+ void AddPathInternal(const std::string& path, const char* base = nullptr);
+
+ cmFindCommon* FC;
+ std::vector<std::string> Paths;
+};
diff --git a/Source/cmSeparateArgumentsCommand.cxx b/Source/cmSeparateArgumentsCommand.cxx
new file mode 100644
index 0000000..52b1a44
--- /dev/null
+++ b/Source/cmSeparateArgumentsCommand.cxx
@@ -0,0 +1,165 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSeparateArgumentsCommand.h"
+
+#include <algorithm>
+
+#include <cmext/string_view>
+
+#include "cmArgumentParser.h"
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+// cmSeparateArgumentsCommand
+bool cmSeparateArgumentsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("must be given at least one argument.");
+ return false;
+ }
+
+ std::string const& var = args.front();
+
+ if (args.size() == 1) {
+ // Original space-replacement version of command.
+ if (cmProp def = status.GetMakefile().GetDefinition(var)) {
+ std::string value = *def;
+ std::replace(value.begin(), value.end(), ' ', ';');
+ status.GetMakefile().AddDefinition(var, value);
+ }
+
+ return true;
+ }
+
+ struct Arguments
+ {
+ bool UnixCommand = false;
+ bool WindowsCommand = false;
+ bool NativeCommand = false;
+ bool Program = false;
+ bool SeparateArgs = false;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("UNIX_COMMAND"_s, &Arguments::UnixCommand)
+ .Bind("WINDOWS_COMMAND"_s, &Arguments::WindowsCommand)
+ .Bind("NATIVE_COMMAND"_s, &Arguments::NativeCommand)
+ .Bind("PROGRAM"_s, &Arguments::Program)
+ .Bind("SEPARATE_ARGS"_s, &Arguments::SeparateArgs);
+
+ std::vector<std::string> unparsedArguments;
+ Arguments arguments =
+ parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments);
+
+ if (!arguments.UnixCommand && !arguments.WindowsCommand &&
+ !arguments.NativeCommand) {
+ status.SetError("missing required option: 'UNIX_COMMAND' or "
+ "'WINDOWS_COMMAND' or 'NATIVE_COMMAND'");
+ return false;
+ }
+ if ((arguments.UnixCommand && arguments.WindowsCommand) ||
+ (arguments.UnixCommand && arguments.NativeCommand) ||
+ (arguments.WindowsCommand && arguments.NativeCommand)) {
+ status.SetError("'UNIX_COMMAND', 'WINDOWS_COMMAND' and 'NATIVE_COMMAND' "
+ "are mutually exclusive");
+ return false;
+ }
+ if (arguments.SeparateArgs && !arguments.Program) {
+ status.SetError("`SEPARATE_ARGS` option requires `PROGRAM' option");
+ return false;
+ }
+
+ if (unparsedArguments.size() > 1) {
+ status.SetError("given unexpected argument(s)");
+ return false;
+ }
+
+ if (unparsedArguments.empty()) {
+ status.GetMakefile().AddDefinition(var, {});
+ return true;
+ }
+
+ std::string& command = unparsedArguments.front();
+
+ if (command.empty()) {
+ status.GetMakefile().AddDefinition(var, command);
+ return true;
+ }
+
+ if (arguments.Program && !arguments.SeparateArgs) {
+ std::string program;
+ std::string programArgs;
+
+ // First assume the path to the program was specified with no
+ // arguments and with no quoting or escaping for spaces.
+ // Only bother doing this if there is non-whitespace.
+ if (!cmTrimWhitespace(command).empty()) {
+ program = cmSystemTools::FindProgram(command);
+ }
+
+ // If that failed then assume a command-line string was given
+ // and split the program part from the rest of the arguments.
+ if (program.empty()) {
+ if (cmSystemTools::SplitProgramFromArgs(command, program, programArgs)) {
+ if (!cmSystemTools::FileExists(program)) {
+ program = cmSystemTools::FindProgram(program);
+ }
+ }
+ }
+
+ if (!program.empty()) {
+ program += cmStrCat(';', programArgs);
+ }
+
+ status.GetMakefile().AddDefinition(var, program);
+ return true;
+ }
+
+ // split command given
+ std::vector<std::string> values;
+
+ if (arguments.NativeCommand) {
+#if defined(_WIN32)
+ arguments.WindowsCommand = true;
+#else
+ arguments.UnixCommand = true;
+#endif
+ }
+
+ if (arguments.UnixCommand) {
+ cmSystemTools::ParseUnixCommandLine(command.c_str(), values);
+ } else {
+ cmSystemTools::ParseWindowsCommandLine(command.c_str(), values);
+ }
+
+ if (arguments.Program) {
+ // check program exist
+ if (!cmSystemTools::FileExists(values.front())) {
+ auto result = cmSystemTools::FindProgram(values.front());
+ if (result.empty()) {
+ values.clear();
+ } else {
+ values.front() = result;
+ }
+ }
+ }
+
+ // preserve semicolons in arguments
+ std::for_each(values.begin(), values.end(), [](std::string& value) {
+ std::string::size_type pos = 0;
+ while ((pos = value.find_first_of(';', pos)) != std::string::npos) {
+ value.insert(pos, 1, '\\');
+ pos += 2;
+ }
+ });
+ auto value = cmJoin(values, ";");
+ status.GetMakefile().AddDefinition(var, value);
+
+ return true;
+}
diff --git a/Source/cmSeparateArgumentsCommand.h b/Source/cmSeparateArgumentsCommand.h
new file mode 100644
index 0000000..d284a40
--- /dev/null
+++ b/Source/cmSeparateArgumentsCommand.h
@@ -0,0 +1,18 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief separate_arguments command
+ *
+ * cmSeparateArgumentsCommand implements the separate_arguments CMake command
+ */
+bool cmSeparateArgumentsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx
new file mode 100644
index 0000000..354b4c3
--- /dev/null
+++ b/Source/cmSetCommand.cxx
@@ -0,0 +1,160 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSetCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+// cmSetCommand
+bool cmSetCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // watch for ENV signatures
+ auto const& variable = args[0]; // VAR is always first
+ if (cmHasLiteralPrefix(variable, "ENV{") && variable.size() > 5) {
+ // what is the variable name
+ auto const& varName = variable.substr(4, variable.size() - 5);
+ std::string putEnvArg = varName + "=";
+
+ // what is the current value if any
+ std::string currValue;
+ const bool currValueSet = cmSystemTools::GetEnv(varName, currValue);
+
+ // will it be set to something, then set it
+ if (args.size() > 1 && !args[1].empty()) {
+ // but only if it is different from current value
+ if (!currValueSet || currValue != args[1]) {
+ putEnvArg += args[1];
+ cmSystemTools::PutEnv(putEnvArg);
+ }
+ // if there's extra arguments, warn user
+ // that they are ignored by this command.
+ if (args.size() > 2) {
+ std::string m = "Only the first value argument is used when setting "
+ "an environment variable. Argument '" +
+ args[2] + "' and later are unused.";
+ status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, m);
+ }
+ return true;
+ }
+
+ // if it will be cleared, then clear it if it isn't already clear
+ if (currValueSet) {
+ cmSystemTools::PutEnv(putEnvArg);
+ }
+ return true;
+ }
+
+ // SET (VAR) // Removes the definition of VAR.
+ if (args.size() == 1) {
+ status.GetMakefile().RemoveDefinition(variable);
+ return true;
+ }
+ // SET (VAR PARENT_SCOPE) // Removes the definition of VAR
+ // in the parent scope.
+ if (args.size() == 2 && args.back() == "PARENT_SCOPE") {
+ status.GetMakefile().RaiseScope(variable, nullptr);
+ return true;
+ }
+
+ // here are the remaining options
+ // SET (VAR value )
+ // SET (VAR value PARENT_SCOPE)
+ // SET (VAR CACHE TYPE "doc String" [FORCE])
+ // SET (VAR value CACHE TYPE "doc string" [FORCE])
+ std::string value; // optional
+ bool cache = false; // optional
+ bool force = false; // optional
+ bool parentScope = false;
+ cmStateEnums::CacheEntryType type =
+ cmStateEnums::STRING; // required if cache
+ const char* docstring = nullptr; // required if cache
+
+ unsigned int ignoreLastArgs = 0;
+ // look for PARENT_SCOPE argument
+ if (args.size() > 1 && args.back() == "PARENT_SCOPE") {
+ parentScope = true;
+ ignoreLastArgs++;
+ } else {
+ // look for FORCE argument
+ if (args.size() > 4 && args.back() == "FORCE") {
+ force = true;
+ ignoreLastArgs++;
+ }
+
+ // check for cache signature
+ if (args.size() > 3 &&
+ args[args.size() - 3 - (force ? 1 : 0)] == "CACHE") {
+ cache = true;
+ ignoreLastArgs += 3;
+ }
+ }
+
+ // collect any values into a single semi-colon separated value list
+ value = cmJoin(cmMakeRange(args).advance(1).retreat(ignoreLastArgs), ";");
+
+ if (parentScope) {
+ status.GetMakefile().RaiseScope(variable, value.c_str());
+ return true;
+ }
+
+ // we should be nice and try to catch some simple screwups if the last or
+ // next to last args are CACHE then they screwed up. If they used FORCE
+ // without CACHE they screwed up
+ if ((args.back() == "CACHE") ||
+ (args.size() > 1 && args[args.size() - 2] == "CACHE") ||
+ (force && !cache)) {
+ status.SetError("given invalid arguments for CACHE mode.");
+ return false;
+ }
+
+ if (cache) {
+ std::string::size_type cacheStart = args.size() - 3 - (force ? 1 : 0);
+ if (!cmState::StringToCacheEntryType(args[cacheStart + 1], type)) {
+ std::string m = "implicitly converting '" + args[cacheStart + 1] +
+ "' to 'STRING' type.";
+ status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, m);
+ // Setting this may not be required, since it's
+ // initialized as a string. Keeping this here to
+ // ensure that the type is actually converting to a string.
+ type = cmStateEnums::STRING;
+ }
+ docstring = args[cacheStart + 2].c_str();
+ }
+
+ // see if this is already in the cache
+ cmState* state = status.GetMakefile().GetState();
+ cmProp existingValue = state->GetCacheEntryValue(variable);
+ if (existingValue &&
+ (state->GetCacheEntryType(variable) != cmStateEnums::UNINITIALIZED)) {
+ // if the set is trying to CACHE the value but the value
+ // is already in the cache and the type is not internal
+ // then leave now without setting any definitions in the cache
+ // or the makefile
+ if (cache && type != cmStateEnums::INTERNAL && !force) {
+ return true;
+ }
+ }
+
+ // if it is meant to be in the cache then define it in the cache
+ if (cache) {
+ status.GetMakefile().AddCacheDefinition(variable, value, docstring, type,
+ force);
+ } else {
+ // add the definition
+ status.GetMakefile().AddDefinition(variable, value);
+ }
+ return true;
+}
diff --git a/Source/cmSetCommand.h b/Source/cmSetCommand.h
new file mode 100644
index 0000000..695b185
--- /dev/null
+++ b/Source/cmSetCommand.h
@@ -0,0 +1,18 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Set a CMAKE variable
+ *
+ * cmSetCommand sets a variable to a value with expansion.
+ */
+bool cmSetCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmSetDirectoryPropertiesCommand.cxx b/Source/cmSetDirectoryPropertiesCommand.cxx
new file mode 100644
index 0000000..07ad246
--- /dev/null
+++ b/Source/cmSetDirectoryPropertiesCommand.cxx
@@ -0,0 +1,39 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSetDirectoryPropertiesCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+
+// cmSetDirectoryPropertiesCommand
+bool cmSetDirectoryPropertiesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // PROPERTIES followed by prop value pairs
+ if (args.size() % 2 != 1) {
+ status.SetError("Wrong number of arguments");
+ return false;
+ }
+
+ for (auto iter = args.begin() + 1; iter != args.end(); iter += 2) {
+ const std::string& prop = *iter;
+ if (prop == "VARIABLES") {
+ status.SetError(
+ "Variables and cache variables should be set using SET command");
+ return false;
+ }
+ if (prop == "MACROS") {
+ status.SetError(
+ "Commands and macros cannot be set using SET_CMAKE_PROPERTIES");
+ return false;
+ }
+ status.GetMakefile().SetProperty(prop, (iter + 1)->c_str());
+ }
+
+ return true;
+}
diff --git a/Source/cmSetDirectoryPropertiesCommand.h b/Source/cmSetDirectoryPropertiesCommand.h
new file mode 100644
index 0000000..f5b6406
--- /dev/null
+++ b/Source/cmSetDirectoryPropertiesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmSetDirectoryPropertiesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
new file mode 100644
index 0000000..c899053
--- /dev/null
+++ b/Source/cmSetPropertyCommand.cxx
@@ -0,0 +1,798 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSetPropertyCommand.h"
+
+#include <set>
+#include <sstream>
+#include <unordered_set>
+
+#include "cmExecutionStatus.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstalledFile.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmSourceFile.h"
+#include "cmSourceFileLocation.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTest.h"
+#include "cmake.h"
+
+namespace {
+bool HandleGlobalMode(cmExecutionStatus& status,
+ const std::set<std::string>& names,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove);
+bool HandleDirectoryMode(cmExecutionStatus& status,
+ const std::set<std::string>& names,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove);
+bool HandleTargetMode(cmExecutionStatus& status,
+ const std::set<std::string>& names,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove);
+bool HandleTarget(cmTarget* target, cmMakefile& makefile,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove);
+bool HandleSourceMode(cmExecutionStatus& status,
+ const std::set<std::string>& names,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove,
+ const std::vector<cmMakefile*>& directory_makefiles,
+ bool source_file_paths_should_be_absolute);
+bool HandleSource(cmSourceFile* sf, const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove);
+bool HandleTestMode(cmExecutionStatus& status, std::set<std::string>& names,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove);
+bool HandleTest(cmTest* test, const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove);
+bool HandleCacheMode(cmExecutionStatus& status,
+ const std::set<std::string>& names,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove);
+bool HandleCacheEntry(std::string const& cacheKey, const cmMakefile& makefile,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove);
+bool HandleInstallMode(cmExecutionStatus& status,
+ const std::set<std::string>& names,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove);
+bool HandleInstall(cmInstalledFile* file, cmMakefile& makefile,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove);
+}
+
+namespace SetPropertyCommand {
+bool HandleSourceFileDirectoryScopes(
+ cmExecutionStatus& status, std::vector<std::string>& source_file_directories,
+ std::vector<std::string>& source_file_target_directories,
+ std::vector<cmMakefile*>& directory_makefiles)
+{
+ std::unordered_set<cmMakefile*> directory_makefiles_set;
+
+ cmMakefile* current_dir_mf = &status.GetMakefile();
+ if (!source_file_directories.empty()) {
+ for (const std::string& dir_path : source_file_directories) {
+ const std::string absolute_dir_path = cmSystemTools::CollapseFullPath(
+ dir_path, current_dir_mf->GetCurrentSourceDirectory());
+ cmMakefile* dir_mf =
+ status.GetMakefile().GetGlobalGenerator()->FindMakefile(
+ absolute_dir_path);
+ if (!dir_mf) {
+ status.SetError(cmStrCat("given non-existent DIRECTORY ", dir_path));
+ return false;
+ }
+ if (directory_makefiles_set.find(dir_mf) ==
+ directory_makefiles_set.end()) {
+ directory_makefiles.push_back(dir_mf);
+ directory_makefiles_set.insert(dir_mf);
+ }
+ }
+ }
+
+ if (!source_file_target_directories.empty()) {
+ for (const std::string& target_name : source_file_target_directories) {
+ cmTarget* target = current_dir_mf->FindTargetToUse(target_name);
+ if (!target) {
+ status.SetError(cmStrCat(
+ "given non-existent target for TARGET_DIRECTORY ", target_name));
+ return false;
+ }
+ cmProp target_source_dir = target->GetProperty("BINARY_DIR");
+ cmMakefile* target_dir_mf =
+ status.GetMakefile().GetGlobalGenerator()->FindMakefile(
+ *target_source_dir);
+
+ if (directory_makefiles_set.find(target_dir_mf) ==
+ directory_makefiles_set.end()) {
+ directory_makefiles.push_back(target_dir_mf);
+ directory_makefiles_set.insert(target_dir_mf);
+ }
+ }
+ }
+
+ if (source_file_directories.empty() &&
+ source_file_target_directories.empty()) {
+ directory_makefiles.push_back(current_dir_mf);
+ }
+ return true;
+}
+
+bool HandleSourceFileDirectoryScopeValidation(
+ cmExecutionStatus& status, bool source_file_directory_option_enabled,
+ bool source_file_target_option_enabled,
+ std::vector<std::string>& source_file_directories,
+ std::vector<std::string>& source_file_target_directories)
+{
+ // Validate source file directory scopes.
+ if (source_file_directory_option_enabled &&
+ source_file_directories.empty()) {
+ std::string errors = "called with incorrect number of arguments "
+ "no value provided to the DIRECTORY option";
+ status.SetError(errors);
+ return false;
+ }
+ if (source_file_target_option_enabled &&
+ source_file_target_directories.empty()) {
+ std::string errors = "called with incorrect number of arguments "
+ "no value provided to the TARGET_DIRECTORY option";
+ status.SetError(errors);
+ return false;
+ }
+ return true;
+}
+
+bool HandleAndValidateSourceFileDirectoryScopes(
+ cmExecutionStatus& status, bool source_file_directory_option_enabled,
+ bool source_file_target_option_enabled,
+ std::vector<std::string>& source_file_directories,
+ std::vector<std::string>& source_file_target_directories,
+ std::vector<cmMakefile*>& source_file_directory_makefiles)
+{
+ bool scope_options_valid =
+ SetPropertyCommand::HandleSourceFileDirectoryScopeValidation(
+ status, source_file_directory_option_enabled,
+ source_file_target_option_enabled, source_file_directories,
+ source_file_target_directories);
+ if (!scope_options_valid) {
+ return false;
+ }
+
+ scope_options_valid = SetPropertyCommand::HandleSourceFileDirectoryScopes(
+ status, source_file_directories, source_file_target_directories,
+ source_file_directory_makefiles);
+ return scope_options_valid;
+}
+
+std::string MakeSourceFilePathAbsoluteIfNeeded(
+ cmExecutionStatus& status, const std::string& source_file_path,
+ const bool needed)
+{
+ if (!needed) {
+ return source_file_path;
+ }
+ std::string absolute_file_path = cmSystemTools::CollapseFullPath(
+ source_file_path, status.GetMakefile().GetCurrentSourceDirectory());
+ return absolute_file_path;
+}
+
+void MakeSourceFilePathsAbsoluteIfNeeded(
+ cmExecutionStatus& status,
+ std::vector<std::string>& source_files_absolute_paths,
+ std::vector<std::string>::const_iterator files_it_begin,
+ std::vector<std::string>::const_iterator files_it_end, const bool needed)
+{
+
+ // Make the file paths absolute, so that relative source file paths are
+ // picked up relative to the command calling site, regardless of the
+ // directory scope.
+ std::vector<std::string>::difference_type num_files =
+ files_it_end - files_it_begin;
+ source_files_absolute_paths.reserve(num_files);
+
+ if (!needed) {
+ source_files_absolute_paths.assign(files_it_begin, files_it_end);
+ return;
+ }
+
+ for (; files_it_begin != files_it_end; ++files_it_begin) {
+ const std::string absolute_file_path =
+ MakeSourceFilePathAbsoluteIfNeeded(status, *files_it_begin, true);
+ source_files_absolute_paths.push_back(absolute_file_path);
+ }
+}
+
+bool HandleAndValidateSourceFilePropertyGENERATED(
+ cmSourceFile* sf, std::string const& propertyValue, PropertyOp op)
+{
+ const auto& mf = *sf->GetLocation().GetMakefile();
+ auto policyStatus = mf.GetPolicyStatus(cmPolicies::CMP0118);
+
+ const bool policyWARN = policyStatus == cmPolicies::WARN;
+ const bool policyNEW = policyStatus != cmPolicies::OLD && !policyWARN;
+
+ if (policyWARN) {
+ if (!cmIsOn(propertyValue) && !cmIsOff(propertyValue)) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118),
+ "\nAttempt to set property 'GENERATED' with the following "
+ "non-boolean value (which will be interpreted as \"0\"):\n",
+ propertyValue,
+ "\nThat exact value will not be retrievable. A value of "
+ "\"0\" will be returned instead.\n"
+ "This will be an error under policy CMP0118.\n"));
+ }
+ if (cmIsOff(propertyValue)) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118),
+ "\nUnsetting property 'GENERATED' will not be allowed under "
+ "policy CMP0118!\n"));
+ }
+ if (op == PropertyOp::Append || op == PropertyOp::AppendAsString) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118),
+ "\nAppending to property 'GENERATED' will not be allowed "
+ "under policy CMP0118!\n"));
+ }
+ } else if (policyNEW) {
+ if (!cmIsOn(propertyValue) && !cmIsOff(propertyValue)) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_ERROR,
+ cmStrCat(
+ "Policy CMP0118 is set to NEW and the following non-boolean value "
+ "given for property 'GENERATED' is therefore not allowed:\n",
+ propertyValue, "\nReplace it with a boolean value!\n"));
+ return true;
+ }
+ if (cmIsOff(propertyValue)) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_ERROR,
+ "Unsetting the 'GENERATED' property is not allowed under CMP0118!\n");
+ return true;
+ }
+ if (op == PropertyOp::Append || op == PropertyOp::AppendAsString) {
+ mf.IssueMessage(MessageType::AUTHOR_ERROR,
+ "Policy CMP0118 is set to NEW and appending to the "
+ "'GENERATED' property is therefore not allowed. Only "
+ "setting it to \"1\" is allowed!\n");
+ return true;
+ }
+ }
+
+ // Set property.
+ if (!policyNEW) {
+ // Do it the traditional way.
+ switch (op) {
+ case PropertyOp::Append:
+ sf->AppendProperty("GENERATED", propertyValue, false);
+ break;
+ case PropertyOp::AppendAsString:
+ sf->AppendProperty("GENERATED", propertyValue, true);
+ break;
+ case PropertyOp::Remove:
+ sf->SetProperty("GENERATED", nullptr);
+ break;
+ case PropertyOp::Set:
+ sf->SetProperty("GENERATED", propertyValue.c_str());
+ break;
+ }
+ } else {
+ sf->MarkAsGenerated();
+ }
+ return true;
+}
+
+} // END: namespace SetPropertyCommand
+
+bool cmSetPropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Get the scope on which to set the property.
+ std::string const& scopeName = args.front();
+ cmProperty::ScopeType scope;
+ if (scopeName == "GLOBAL") {
+ scope = cmProperty::GLOBAL;
+ } else if (scopeName == "DIRECTORY") {
+ scope = cmProperty::DIRECTORY;
+ } else if (scopeName == "TARGET") {
+ scope = cmProperty::TARGET;
+ } else if (scopeName == "SOURCE") {
+ scope = cmProperty::SOURCE_FILE;
+ } else if (scopeName == "TEST") {
+ scope = cmProperty::TEST;
+ } else if (scopeName == "CACHE") {
+ scope = cmProperty::CACHE;
+ } else if (scopeName == "INSTALL") {
+ scope = cmProperty::INSTALL;
+ } else {
+ status.SetError(cmStrCat("given invalid scope ", scopeName,
+ ". "
+ "Valid scopes are GLOBAL, DIRECTORY, "
+ "TARGET, SOURCE, TEST, CACHE, INSTALL."));
+ return false;
+ }
+
+ bool appendAsString = false;
+ bool appendMode = false;
+ bool remove = true;
+ std::set<std::string> names;
+ std::string propertyName;
+ std::string propertyValue;
+
+ std::vector<std::string> source_file_directories;
+ std::vector<std::string> source_file_target_directories;
+ bool source_file_directory_option_enabled = false;
+ bool source_file_target_option_enabled = false;
+
+ // Parse the rest of the arguments up to the values.
+ enum Doing
+ {
+ DoingNone,
+ DoingNames,
+ DoingProperty,
+ DoingValues,
+ DoingSourceDirectory,
+ DoingSourceTargetDirectory
+ };
+ Doing doing = DoingNames;
+ const char* sep = "";
+ for (std::string const& arg : cmMakeRange(args).advance(1)) {
+ if (arg == "PROPERTY") {
+ doing = DoingProperty;
+ } else if (arg == "APPEND") {
+ doing = DoingNone;
+ appendMode = true;
+ remove = false;
+ appendAsString = false;
+ } else if (arg == "APPEND_STRING") {
+ doing = DoingNone;
+ appendMode = true;
+ remove = false;
+ appendAsString = true;
+ } else if (doing != DoingProperty && doing != DoingValues &&
+ scope == cmProperty::SOURCE_FILE && arg == "DIRECTORY") {
+ doing = DoingSourceDirectory;
+ source_file_directory_option_enabled = true;
+ } else if (doing != DoingProperty && doing != DoingValues &&
+ scope == cmProperty::SOURCE_FILE && arg == "TARGET_DIRECTORY") {
+ doing = DoingSourceTargetDirectory;
+ source_file_target_option_enabled = true;
+ } else if (doing == DoingNames) {
+ names.insert(arg);
+ } else if (doing == DoingSourceDirectory) {
+ source_file_directories.push_back(arg);
+ } else if (doing == DoingSourceTargetDirectory) {
+ source_file_target_directories.push_back(arg);
+ } else if (doing == DoingProperty) {
+ propertyName = arg;
+ doing = DoingValues;
+ } else if (doing == DoingValues) {
+ propertyValue += sep;
+ sep = ";";
+ propertyValue += arg;
+ remove = false;
+ } else {
+ status.SetError(cmStrCat("given invalid argument \"", arg, "\"."));
+ return false;
+ }
+ }
+
+ // Make sure a property name was found.
+ if (propertyName.empty()) {
+ status.SetError("not given a PROPERTY <name> argument.");
+ return false;
+ }
+
+ std::vector<cmMakefile*> source_file_directory_makefiles;
+ bool file_scopes_handled =
+ SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
+ status, source_file_directory_option_enabled,
+ source_file_target_option_enabled, source_file_directories,
+ source_file_target_directories, source_file_directory_makefiles);
+ if (!file_scopes_handled) {
+ return false;
+ }
+ bool source_file_paths_should_be_absolute =
+ source_file_directory_option_enabled || source_file_target_option_enabled;
+
+ // Dispatch property setting.
+ switch (scope) {
+ case cmProperty::GLOBAL:
+ return HandleGlobalMode(status, names, propertyName, propertyValue,
+ appendAsString, appendMode, remove);
+ case cmProperty::DIRECTORY:
+ return HandleDirectoryMode(status, names, propertyName, propertyValue,
+ appendAsString, appendMode, remove);
+ case cmProperty::TARGET:
+ return HandleTargetMode(status, names, propertyName, propertyValue,
+ appendAsString, appendMode, remove);
+ case cmProperty::SOURCE_FILE:
+ return HandleSourceMode(status, names, propertyName, propertyValue,
+ appendAsString, appendMode, remove,
+ source_file_directory_makefiles,
+ source_file_paths_should_be_absolute);
+ case cmProperty::TEST:
+ return HandleTestMode(status, names, propertyName, propertyValue,
+ appendAsString, appendMode, remove);
+ case cmProperty::CACHE:
+ return HandleCacheMode(status, names, propertyName, propertyValue,
+ appendAsString, appendMode, remove);
+ case cmProperty::INSTALL:
+ return HandleInstallMode(status, names, propertyName, propertyValue,
+ appendAsString, appendMode, remove);
+
+ case cmProperty::VARIABLE:
+ case cmProperty::CACHED_VARIABLE:
+ break; // should never happen
+ }
+ return true;
+}
+
+namespace /* anonymous */ {
+bool HandleGlobalMode(cmExecutionStatus& status,
+ const std::set<std::string>& names,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove)
+{
+ if (!names.empty()) {
+ status.SetError("given names for GLOBAL scope.");
+ return false;
+ }
+
+ // Set or append the property.
+ cmake* cm = status.GetMakefile().GetCMakeInstance();
+ if (appendMode) {
+ cm->AppendProperty(propertyName, propertyValue, appendAsString);
+ } else {
+ if (remove) {
+ cm->SetProperty(propertyName, nullptr);
+ } else {
+ cm->SetProperty(propertyName, propertyValue.c_str());
+ }
+ }
+
+ return true;
+}
+
+bool HandleDirectoryMode(cmExecutionStatus& status,
+ const std::set<std::string>& names,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove)
+{
+ if (names.size() > 1) {
+ status.SetError("allows at most one name for DIRECTORY scope.");
+ return false;
+ }
+
+ // Default to the current directory.
+ cmMakefile* mf = &status.GetMakefile();
+
+ // Lookup the directory if given.
+ if (!names.empty()) {
+ // Construct the directory name. Interpret relative paths with
+ // respect to the current directory.
+ std::string dir = cmSystemTools::CollapseFullPath(
+ *names.begin(), status.GetMakefile().GetCurrentSourceDirectory());
+
+ mf = status.GetMakefile().GetGlobalGenerator()->FindMakefile(dir);
+ if (!mf) {
+ // Could not find the directory.
+ status.SetError(
+ "DIRECTORY scope provided but requested directory was not found. "
+ "This could be because the directory argument was invalid or, "
+ "it is valid but has not been processed yet.");
+ return false;
+ }
+ }
+
+ // Set or append the property.
+ if (appendMode) {
+ mf->AppendProperty(propertyName, propertyValue, appendAsString);
+ } else {
+ if (remove) {
+ mf->SetProperty(propertyName, nullptr);
+ } else {
+ mf->SetProperty(propertyName, propertyValue.c_str());
+ }
+ }
+
+ return true;
+}
+
+bool HandleTargetMode(cmExecutionStatus& status,
+ const std::set<std::string>& names,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove)
+{
+ for (std::string const& name : names) {
+ if (status.GetMakefile().IsAlias(name)) {
+ status.SetError("can not be used on an ALIAS target.");
+ return false;
+ }
+ if (cmTarget* target = status.GetMakefile().FindTargetToUse(name)) {
+ // Handle the current target.
+ if (!HandleTarget(target, status.GetMakefile(), propertyName,
+ propertyValue, appendAsString, appendMode, remove)) {
+ return false;
+ }
+ } else {
+ status.SetError(cmStrCat("could not find TARGET ", name,
+ ". Perhaps it has not yet been created."));
+ return false;
+ }
+ }
+ return true;
+}
+
+bool HandleTarget(cmTarget* target, cmMakefile& makefile,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove)
+{
+ // Set or append the property.
+ if (appendMode) {
+ target->AppendProperty(propertyName, propertyValue, appendAsString);
+ } else {
+ if (remove) {
+ target->SetProperty(propertyName, nullptr);
+ } else {
+ target->SetProperty(propertyName, propertyValue);
+ }
+ }
+
+ // Check the resulting value.
+ target->CheckProperty(propertyName, &makefile);
+
+ return true;
+}
+
+bool HandleSourceMode(cmExecutionStatus& status,
+ const std::set<std::string>& names,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove,
+ const std::vector<cmMakefile*>& directory_makefiles,
+ const bool source_file_paths_should_be_absolute)
+{
+ std::vector<std::string> files_absolute;
+ std::vector<std::string> unique_files(names.begin(), names.end());
+ SetPropertyCommand::MakeSourceFilePathsAbsoluteIfNeeded(
+ status, files_absolute, unique_files.begin(), unique_files.end(),
+ source_file_paths_should_be_absolute);
+
+ for (auto* const mf : directory_makefiles) {
+ for (std::string const& name : files_absolute) {
+ // Get the source file.
+ if (cmSourceFile* sf = mf->GetOrCreateSource(name)) {
+ if (!HandleSource(sf, propertyName, propertyValue, appendAsString,
+ appendMode, remove)) {
+ return false;
+ }
+ } else {
+ status.SetError(cmStrCat(
+ "given SOURCE name that could not be found or created: ", name));
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool HandleSource(cmSourceFile* sf, const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove)
+{
+ // Special validation and handling of GENERATED flag?
+ if (propertyName == "GENERATED") {
+ SetPropertyCommand::PropertyOp op = (remove)
+ ? SetPropertyCommand::PropertyOp::Remove
+ : (appendAsString)
+ ? SetPropertyCommand::PropertyOp::AppendAsString
+ : (appendMode) ? SetPropertyCommand::PropertyOp::Append
+ : SetPropertyCommand::PropertyOp::Set;
+ return SetPropertyCommand::HandleAndValidateSourceFilePropertyGENERATED(
+ sf, propertyValue, op);
+ }
+
+ // Set or append the property.
+ if (appendMode) {
+ sf->AppendProperty(propertyName, propertyValue, appendAsString);
+ } else {
+ if (remove) {
+ sf->SetProperty(propertyName, nullptr);
+ } else {
+ sf->SetProperty(propertyName, propertyValue.c_str());
+ }
+ }
+ return true;
+}
+
+bool HandleTestMode(cmExecutionStatus& status, std::set<std::string>& names,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove)
+{
+ // Look for tests with all names given.
+ std::set<std::string>::iterator next;
+ for (auto ni = names.begin(); ni != names.end(); ni = next) {
+ next = ni;
+ ++next;
+ if (cmTest* test = status.GetMakefile().GetTest(*ni)) {
+ if (HandleTest(test, propertyName, propertyValue, appendAsString,
+ appendMode, remove)) {
+ names.erase(ni);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ // Names that are still left were not found.
+ if (!names.empty()) {
+ std::ostringstream e;
+ e << "given TEST names that do not exist:\n";
+ for (std::string const& name : names) {
+ e << " " << name << "\n";
+ }
+ status.SetError(e.str());
+ return false;
+ }
+ return true;
+}
+
+bool HandleTest(cmTest* test, const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove)
+{
+ // Set or append the property.
+ if (appendMode) {
+ test->AppendProperty(propertyName, propertyValue, appendAsString);
+ } else {
+ if (remove) {
+ test->SetProperty(propertyName, nullptr);
+ } else {
+ test->SetProperty(propertyName, propertyValue.c_str());
+ }
+ }
+
+ return true;
+}
+
+bool HandleCacheMode(cmExecutionStatus& status,
+ const std::set<std::string>& names,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove)
+{
+ if (propertyName == "ADVANCED") {
+ if (!remove && !cmIsOn(propertyValue) && !cmIsOff(propertyValue)) {
+ status.SetError(cmStrCat("given non-boolean value \"", propertyValue,
+ R"(" for CACHE property "ADVANCED". )"));
+ return false;
+ }
+ } else if (propertyName == "TYPE") {
+ if (!cmState::IsCacheEntryType(propertyValue)) {
+ status.SetError(
+ cmStrCat("given invalid CACHE entry TYPE \"", propertyValue, "\""));
+ return false;
+ }
+ } else if (propertyName != "HELPSTRING" && propertyName != "STRINGS" &&
+ propertyName != "VALUE") {
+ status.SetError(
+ cmStrCat("given invalid CACHE property ", propertyName,
+ ". "
+ "Settable CACHE properties are: "
+ "ADVANCED, HELPSTRING, STRINGS, TYPE, and VALUE."));
+ return false;
+ }
+
+ for (std::string const& name : names) {
+ // Get the source file.
+ cmake* cm = status.GetMakefile().GetCMakeInstance();
+ cmProp existingValue = cm->GetState()->GetCacheEntryValue(name);
+ if (existingValue) {
+ if (!HandleCacheEntry(name, status.GetMakefile(), propertyName,
+ propertyValue, appendAsString, appendMode,
+ remove)) {
+ return false;
+ }
+ } else {
+ status.SetError(cmStrCat("could not find CACHE variable ", name,
+ ". Perhaps it has not yet been created."));
+ return false;
+ }
+ }
+ return true;
+}
+
+bool HandleCacheEntry(std::string const& cacheKey, const cmMakefile& makefile,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove)
+{
+ // Set or append the property.
+ cmState* state = makefile.GetState();
+ if (remove) {
+ state->RemoveCacheEntryProperty(cacheKey, propertyName);
+ }
+ if (appendMode) {
+ state->AppendCacheEntryProperty(cacheKey, propertyName, propertyValue,
+ appendAsString);
+ } else {
+ state->SetCacheEntryProperty(cacheKey, propertyName, propertyValue);
+ }
+
+ return true;
+}
+
+bool HandleInstallMode(cmExecutionStatus& status,
+ const std::set<std::string>& names,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove)
+{
+ cmake* cm = status.GetMakefile().GetCMakeInstance();
+
+ for (std::string const& name : names) {
+ if (cmInstalledFile* file =
+ cm->GetOrCreateInstalledFile(&status.GetMakefile(), name)) {
+ if (!HandleInstall(file, status.GetMakefile(), propertyName,
+ propertyValue, appendAsString, appendMode, remove)) {
+ return false;
+ }
+ } else {
+ status.SetError(cmStrCat(
+ "given INSTALL name that could not be found or created: ", name));
+ return false;
+ }
+ }
+ return true;
+}
+
+bool HandleInstall(cmInstalledFile* file, cmMakefile& makefile,
+ const std::string& propertyName,
+ const std::string& propertyValue, bool appendAsString,
+ bool appendMode, bool remove)
+{
+ // Set or append the property.
+ if (remove) {
+ file->RemoveProperty(propertyName);
+ } else if (appendMode) {
+ file->AppendProperty(&makefile, propertyName, propertyValue,
+ appendAsString);
+ } else {
+ file->SetProperty(&makefile, propertyName, propertyValue);
+ }
+ return true;
+}
+}
diff --git a/Source/cmSetPropertyCommand.h b/Source/cmSetPropertyCommand.h
new file mode 100644
index 0000000..05c4873
--- /dev/null
+++ b/Source/cmSetPropertyCommand.h
@@ -0,0 +1,55 @@
+/* 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 <string>
+#include <vector>
+
+class cmMakefile;
+class cmExecutionStatus;
+class cmSourceFile;
+
+bool cmSetPropertyCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
+
+namespace SetPropertyCommand {
+bool HandleSourceFileDirectoryScopes(
+ cmExecutionStatus& status, std::vector<std::string>& source_file_directories,
+ std::vector<std::string>& source_file_target_directories,
+ std::vector<cmMakefile*>& directory_makefiles);
+
+bool HandleSourceFileDirectoryScopeValidation(
+ cmExecutionStatus& status, bool source_file_directory_option_enabled,
+ bool source_file_target_option_enabled,
+ std::vector<std::string>& source_file_directories,
+ std::vector<std::string>& source_file_target_directories);
+
+bool HandleAndValidateSourceFileDirectoryScopes(
+ cmExecutionStatus& status, bool source_directories_option_encountered,
+ bool source_target_directories_option_encountered,
+ std::vector<std::string>& source_directories,
+ std::vector<std::string>& source_target_directories,
+ std::vector<cmMakefile*>& source_file_directory_makefiles);
+
+std::string MakeSourceFilePathAbsoluteIfNeeded(
+ cmExecutionStatus& status, const std::string& source_file_path, bool needed);
+void MakeSourceFilePathsAbsoluteIfNeeded(
+ cmExecutionStatus& status,
+ std::vector<std::string>& source_files_absolute_paths,
+ std::vector<std::string>::const_iterator files_it_begin,
+ std::vector<std::string>::const_iterator files_it_end, bool needed);
+
+enum class PropertyOp
+{
+ Remove,
+ Set,
+ Append,
+ AppendAsString
+};
+
+bool HandleAndValidateSourceFilePropertyGENERATED(
+ cmSourceFile* sf, std::string const& propertyValue,
+ PropertyOp op = PropertyOp::Set);
+}
diff --git a/Source/cmSetSourceFilesPropertiesCommand.cxx b/Source/cmSetSourceFilesPropertiesCommand.cxx
new file mode 100644
index 0000000..237b67f
--- /dev/null
+++ b/Source/cmSetSourceFilesPropertiesCommand.cxx
@@ -0,0 +1,182 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSetSourceFilesPropertiesCommand.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include <cm/string_view>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmSetPropertyCommand.h"
+#include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
+
+static bool RunCommandForScope(
+ cmMakefile* mf, std::vector<std::string>::const_iterator file_begin,
+ std::vector<std::string>::const_iterator file_end,
+ std::vector<std::string>::const_iterator prop_begin,
+ std::vector<std::string>::const_iterator prop_end, std::string& errors);
+
+bool cmSetSourceFilesPropertiesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // break the arguments into source file names and properties
+ // old style allows for specifier before PROPERTIES keyword
+ static const cm::string_view prop_names[] = {
+ "ABSTRACT", "GENERATED", "WRAP_EXCLUDE", "COMPILE_FLAGS",
+ "OBJECT_DEPENDS", "PROPERTIES", "DIRECTORY", "TARGET_DIRECTORY"
+ };
+
+ auto isAPropertyKeyword =
+ [](const std::vector<std::string>::const_iterator& arg_it) {
+ return std::any_of(
+ std::begin(prop_names), std::end(prop_names),
+ [&arg_it](cm::string_view prop_name) { return *arg_it == prop_name; });
+ };
+
+ auto options_begin = std::find_first_of(
+ args.begin(), args.end(), std::begin(prop_names), std::end(prop_names));
+ auto options_it = options_begin;
+
+ // Handle directory options.
+ std::vector<std::string> source_file_directories;
+ std::vector<std::string> source_file_target_directories;
+ bool source_file_directory_option_enabled = false;
+ bool source_file_target_option_enabled = false;
+ std::vector<cmMakefile*> source_file_directory_makefiles;
+
+ enum Doing
+ {
+ DoingNone,
+ DoingSourceDirectory,
+ DoingSourceTargetDirectory
+ };
+ Doing doing = DoingNone;
+ for (; options_it != args.end(); ++options_it) {
+ if (*options_it == "DIRECTORY") {
+ doing = DoingSourceDirectory;
+ source_file_directory_option_enabled = true;
+ } else if (*options_it == "TARGET_DIRECTORY") {
+ doing = DoingSourceTargetDirectory;
+ source_file_target_option_enabled = true;
+ } else if (isAPropertyKeyword(options_it)) {
+ break;
+ } else if (doing == DoingSourceDirectory) {
+ source_file_directories.push_back(*options_it);
+ } else if (doing == DoingSourceTargetDirectory) {
+ source_file_target_directories.push_back(*options_it);
+ } else {
+ status.SetError(
+ cmStrCat("given invalid argument \"", *options_it, "\"."));
+ }
+ }
+
+ const auto props_begin = options_it;
+
+ bool file_scopes_handled =
+ SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
+ status, source_file_directory_option_enabled,
+ source_file_target_option_enabled, source_file_directories,
+ source_file_target_directories, source_file_directory_makefiles);
+ if (!file_scopes_handled) {
+ return false;
+ }
+
+ std::vector<std::string> files;
+ bool source_file_paths_should_be_absolute =
+ source_file_directory_option_enabled || source_file_target_option_enabled;
+ SetPropertyCommand::MakeSourceFilePathsAbsoluteIfNeeded(
+ status, files, args.begin(), options_begin,
+ source_file_paths_should_be_absolute);
+
+ // Now call the worker function for each directory scope represented by a
+ // cmMakefile instance.
+ std::string errors;
+ for (auto* const mf : source_file_directory_makefiles) {
+ bool ret = RunCommandForScope(mf, files.begin(), files.end(), props_begin,
+ args.end(), errors);
+ if (!ret) {
+ status.SetError(errors);
+ return ret;
+ }
+ }
+
+ return true;
+}
+
+static bool RunCommandForScope(
+ cmMakefile* mf, std::vector<std::string>::const_iterator file_begin,
+ std::vector<std::string>::const_iterator file_end,
+ std::vector<std::string>::const_iterator prop_begin,
+ std::vector<std::string>::const_iterator prop_end, std::string& errors)
+{
+ std::vector<std::string> propertyPairs;
+ // build the property pairs
+ for (auto j = prop_begin; j != prop_end; ++j) {
+ // consume old style options
+ if (*j == "ABSTRACT" || *j == "GENERATED" || *j == "WRAP_EXCLUDE") {
+ propertyPairs.emplace_back(*j);
+ propertyPairs.emplace_back("1");
+ } else if (*j == "COMPILE_FLAGS") {
+ propertyPairs.emplace_back("COMPILE_FLAGS");
+ ++j;
+ if (j == prop_end) {
+ errors = "called with incorrect number of arguments "
+ "COMPILE_FLAGS with no flags";
+ return false;
+ }
+ propertyPairs.push_back(*j);
+ } else if (*j == "OBJECT_DEPENDS") {
+ propertyPairs.emplace_back("OBJECT_DEPENDS");
+ ++j;
+ if (j == prop_end) {
+ errors = "called with incorrect number of arguments "
+ "OBJECT_DEPENDS with no dependencies";
+ return false;
+ }
+ propertyPairs.push_back(*j);
+ } else if (*j == "PROPERTIES") {
+ // PROPERTIES is followed by new style prop value pairs
+ cmStringRange newStyleProps{ j + 1, prop_end };
+ if (newStyleProps.size() % 2 != 0) {
+ errors = "called with incorrect number of arguments.";
+ return false;
+ }
+ // set newStyleProps as is.
+ cm::append(propertyPairs, newStyleProps);
+ // break out of the loop.
+ break;
+ } else {
+ errors = "called with illegal arguments, maybe missing a "
+ "PROPERTIES specifier?";
+ return false;
+ }
+ }
+
+ // loop over all the files
+ for (const std::string& sfname : cmStringRange{ file_begin, file_end }) {
+ // get the source file
+ if (cmSourceFile* sf = mf->GetOrCreateSource(sfname)) {
+ // loop through the props and set them
+ for (auto k = propertyPairs.begin(); k != propertyPairs.end(); k += 2) {
+ // Special handling for GENERATED property?
+ if (*k == "GENERATED"_s) {
+ SetPropertyCommand::HandleAndValidateSourceFilePropertyGENERATED(
+ sf, *(k + 1));
+ } else {
+ sf->SetProperty(*k, (k + 1)->c_str());
+ }
+ }
+ }
+ }
+ return true;
+}
diff --git a/Source/cmSetSourceFilesPropertiesCommand.h b/Source/cmSetSourceFilesPropertiesCommand.h
new file mode 100644
index 0000000..8f88522
--- /dev/null
+++ b/Source/cmSetSourceFilesPropertiesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmSetSourceFilesPropertiesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmSetTargetPropertiesCommand.cxx b/Source/cmSetTargetPropertiesCommand.cxx
new file mode 100644
index 0000000..bdc84af
--- /dev/null
+++ b/Source/cmSetTargetPropertiesCommand.cxx
@@ -0,0 +1,55 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSetTargetPropertiesCommand.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmTarget.h"
+
+bool cmSetTargetPropertiesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // first identify the properties arguments
+ auto propsIter = std::find(args.begin(), args.end(), "PROPERTIES");
+ if (propsIter == args.end() || propsIter + 1 == args.end()) {
+ status.SetError("called with illegal arguments, maybe missing a "
+ "PROPERTIES specifier?");
+ return false;
+ }
+
+ if (std::distance(propsIter, args.end()) % 2 != 1) {
+ status.SetError("called with incorrect number of arguments.");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ // loop over all the targets
+ for (const std::string& tname : cmStringRange{ args.begin(), propsIter }) {
+ if (mf.IsAlias(tname)) {
+ status.SetError("can not be used on an ALIAS target.");
+ return false;
+ }
+ if (cmTarget* target = mf.FindTargetToUse(tname)) {
+ // loop through all the props and set them
+ for (auto k = propsIter + 1; k != args.end(); k += 2) {
+ target->SetProperty(*k, *(k + 1));
+ target->CheckProperty(*k, &mf);
+ }
+ } else {
+ status.SetError(
+ cmStrCat("Can not find target to add properties to: ", tname));
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/Source/cmSetTargetPropertiesCommand.h b/Source/cmSetTargetPropertiesCommand.h
new file mode 100644
index 0000000..0c04f31
--- /dev/null
+++ b/Source/cmSetTargetPropertiesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmSetTargetPropertiesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmSetTestsPropertiesCommand.cxx b/Source/cmSetTestsPropertiesCommand.cxx
new file mode 100644
index 0000000..c4bff76
--- /dev/null
+++ b/Source/cmSetTestsPropertiesCommand.cxx
@@ -0,0 +1,50 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSetTestsPropertiesCommand.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmTest.h"
+
+bool cmSetTestsPropertiesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // first identify the properties arguments
+ auto propsIter = std::find(args.begin(), args.end(), "PROPERTIES");
+ if (propsIter == args.end() || propsIter + 1 == args.end()) {
+ status.SetError("called with illegal arguments, maybe missing a "
+ "PROPERTIES specifier?");
+ return false;
+ }
+
+ if (std::distance(propsIter, args.end()) % 2 != 1) {
+ status.SetError("called with incorrect number of arguments.");
+ return false;
+ }
+
+ // loop over all the tests
+ for (const std::string& tname : cmStringRange{ args.begin(), propsIter }) {
+ if (cmTest* test = status.GetMakefile().GetTest(tname)) {
+ // loop through all the props and set them
+ for (auto k = propsIter + 1; k != args.end(); k += 2) {
+ if (!k->empty()) {
+ test->SetProperty(*k, (k + 1)->c_str());
+ }
+ }
+ } else {
+ status.SetError(
+ cmStrCat("Can not find test to add properties to: ", tname));
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/Source/cmSetTestsPropertiesCommand.h b/Source/cmSetTestsPropertiesCommand.h
new file mode 100644
index 0000000..b4f1641
--- /dev/null
+++ b/Source/cmSetTestsPropertiesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmSetTestsPropertiesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmSiteNameCommand.cxx b/Source/cmSiteNameCommand.cxx
new file mode 100644
index 0000000..58af8f0
--- /dev/null
+++ b/Source/cmSiteNameCommand.cxx
@@ -0,0 +1,80 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSiteNameCommand.h"
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+// cmSiteNameCommand
+bool cmSiteNameCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 1) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ std::vector<std::string> paths;
+ paths.emplace_back("/usr/bsd");
+ paths.emplace_back("/usr/sbin");
+ paths.emplace_back("/usr/bin");
+ paths.emplace_back("/bin");
+ paths.emplace_back("/sbin");
+ paths.emplace_back("/usr/local/bin");
+
+ cmProp cacheValue = status.GetMakefile().GetDefinition(args[0]);
+ if (cacheValue) {
+ return true;
+ }
+
+ cmProp temp = status.GetMakefile().GetDefinition("HOSTNAME");
+ std::string hostname_cmd;
+ if (temp) {
+ hostname_cmd = *temp;
+ } else {
+ hostname_cmd = cmSystemTools::FindProgram("hostname", paths);
+ }
+
+ std::string siteName = "unknown";
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ std::string host;
+ if (cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\"
+ "Control\\ComputerName\\ComputerName;ComputerName",
+ host)) {
+ siteName = host;
+ }
+#else
+ // try to find the hostname for this computer
+ if (!cmIsOff(hostname_cmd)) {
+ std::string host;
+ cmSystemTools::RunSingleCommand(hostname_cmd, &host, nullptr, nullptr,
+ nullptr, cmSystemTools::OUTPUT_NONE);
+
+ // got the hostname
+ if (!host.empty()) {
+ // remove any white space from the host name
+ std::string hostRegExp = "[ \t\n\r]*([^\t\n\r ]*)[ \t\n\r]*";
+ cmsys::RegularExpression hostReg(hostRegExp.c_str());
+ if (hostReg.find(host.c_str())) {
+ // strip whitespace
+ host = hostReg.match(1);
+ }
+
+ if (!host.empty()) {
+ siteName = host;
+ }
+ }
+ }
+#endif
+ status.GetMakefile().AddCacheDefinition(
+ args[0], siteName, "Name of the computer/site where compile is being run",
+ cmStateEnums::STRING);
+
+ return true;
+}
diff --git a/Source/cmSiteNameCommand.h b/Source/cmSiteNameCommand.h
new file mode 100644
index 0000000..432ba37
--- /dev/null
+++ b/Source/cmSiteNameCommand.h
@@ -0,0 +1,18 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief site_name command
+ *
+ * cmSiteNameCommand implements the site_name CMake command
+ */
+bool cmSiteNameCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx
new file mode 100644
index 0000000..3f3c8d5
--- /dev/null
+++ b/Source/cmSourceFile.cxx
@@ -0,0 +1,471 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSourceFile.h"
+
+#include <utility>
+
+#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+cmSourceFile::cmSourceFile(cmMakefile* mf, const std::string& name,
+ bool generated, cmSourceFileLocationKind kind)
+ : Location(mf, name, (!generated) ? kind : cmSourceFileLocationKind::Known)
+{
+ if (generated) {
+ this->MarkAsGenerated();
+ }
+}
+
+std::string const& cmSourceFile::GetExtension() const
+{
+ return this->Extension;
+}
+
+const std::string propTRUE = "1";
+const std::string propFALSE = "0";
+const std::string cmSourceFile::propLANGUAGE = "LANGUAGE";
+const std::string cmSourceFile::propLOCATION = "LOCATION";
+const std::string cmSourceFile::propGENERATED = "GENERATED";
+const std::string cmSourceFile::propCOMPILE_DEFINITIONS =
+ "COMPILE_DEFINITIONS";
+const std::string cmSourceFile::propCOMPILE_OPTIONS = "COMPILE_OPTIONS";
+const std::string cmSourceFile::propINCLUDE_DIRECTORIES =
+ "INCLUDE_DIRECTORIES";
+
+void cmSourceFile::SetObjectLibrary(std::string const& objlib)
+{
+ this->ObjectLibrary = objlib;
+}
+
+std::string cmSourceFile::GetObjectLibrary() const
+{
+ return this->ObjectLibrary;
+}
+
+std::string const& cmSourceFile::GetOrDetermineLanguage()
+{
+ // If the language was set explicitly by the user then use it.
+ if (cmProp lang = this->GetProperty(propLANGUAGE)) {
+ // Assign to member in order to return a reference.
+ this->Language = *lang;
+ return this->Language;
+ }
+
+ // Perform computation needed to get the language if necessary.
+ if (this->Language.empty()) {
+ // If a known extension is given or a known full path is given then trust
+ // that the current extension is sufficient to determine the language. This
+ // will fail only if the user specifies a full path to the source but
+ // leaves off the extension, which is kind of weird.
+ if (this->FullPath.empty() && this->Location.ExtensionIsAmbiguous() &&
+ this->Location.DirectoryIsAmbiguous()) {
+ // Finalize the file location to get the extension and set the language.
+ this->ResolveFullPath();
+ } else {
+ // Use the known extension to get the language if possible.
+ std::string ext =
+ cmSystemTools::GetFilenameLastExtension(this->Location.GetName());
+ this->CheckLanguage(ext);
+ }
+ }
+
+ // Use the language determined from the file extension.
+ return this->Language;
+}
+
+std::string cmSourceFile::GetLanguage() const
+{
+ // If the language was set explicitly by the user then use it.
+ if (cmProp lang = this->GetProperty(propLANGUAGE)) {
+ return *lang;
+ }
+
+ // Use the language determined from the file extension.
+ return this->Language;
+}
+
+cmSourceFileLocation const& cmSourceFile::GetLocation() const
+{
+ return this->Location;
+}
+
+std::string const& cmSourceFile::ResolveFullPath(std::string* error,
+ std::string* cmp0115Warning)
+{
+ if (this->FullPath.empty()) {
+ if (this->FindFullPath(error, cmp0115Warning)) {
+ this->CheckExtension();
+ }
+ }
+ return this->FullPath;
+}
+
+std::string const& cmSourceFile::GetFullPath() const
+{
+ return this->FullPath;
+}
+
+bool cmSourceFile::FindFullPath(std::string* error,
+ std::string* cmp0115Warning)
+{
+ // If the file is generated compute the location without checking on disk.
+ // Note: We also check for a locally set GENERATED property, because
+ // it might have been set before policy CMP0118 was set to NEW.
+ if (this->GetIsGenerated(CheckScope::GlobalAndLocal)) {
+ // The file is either already a full path or is relative to the
+ // build directory for the target.
+ this->Location.DirectoryUseBinary();
+ this->FullPath = this->Location.GetFullPath();
+ this->FindFullPathFailed = false;
+ return true;
+ }
+
+ // If this method has already failed once do not try again.
+ if (this->FindFullPathFailed) {
+ return false;
+ }
+
+ // The file is not generated. It must exist on disk.
+ cmMakefile const* makefile = this->Location.GetMakefile();
+ // Location path
+ std::string const& lPath = this->Location.GetFullPath();
+ // List of extension lists
+ std::vector<std::string> exts =
+ makefile->GetCMakeInstance()->GetAllExtensions();
+ auto cmp0115 = makefile->GetPolicyStatus(cmPolicies::CMP0115);
+ auto cmp0118 = makefile->GetPolicyStatus(cmPolicies::CMP0118);
+ bool const cmp0118new =
+ cmp0118 != cmPolicies::OLD && cmp0118 != cmPolicies::WARN;
+
+ // Tries to find the file in a given directory
+ auto findInDir = [this, &exts, &lPath, cmp0115, cmp0115Warning, cmp0118new,
+ makefile](std::string const& dir) -> bool {
+ // Compute full path
+ std::string const fullPath = cmSystemTools::CollapseFullPath(lPath, dir);
+ // Try full path
+ if (cmp0118new &&
+ makefile->GetGlobalGenerator()->IsGeneratedFile(fullPath)) {
+ this->IsGenerated = true;
+ }
+ if (this->IsGenerated || cmSystemTools::FileExists(fullPath)) {
+ this->FullPath = fullPath;
+ return true;
+ }
+ // This has to be an if statement due to a bug in Oracle Developer Studio.
+ // See https://community.oracle.com/tech/developers/discussion/4476246/
+ // for details.
+ if (cmp0115 == cmPolicies::OLD || cmp0115 == cmPolicies::WARN) {
+ // Try full path with extension
+ for (std::string const& ext : exts) {
+ if (!ext.empty()) {
+ std::string extPath = cmStrCat(fullPath, '.', ext);
+ if (cmp0118new &&
+ makefile->GetGlobalGenerator()->IsGeneratedFile(extPath)) {
+ this->IsGenerated = true;
+ }
+ if (this->IsGenerated || cmSystemTools::FileExists(extPath)) {
+ this->FullPath = extPath;
+ if (cmp0115 == cmPolicies::WARN) {
+ std::string warning =
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0115),
+ "\nFile:\n ", extPath);
+ if (cmp0115Warning) {
+ *cmp0115Warning = std::move(warning);
+ } else {
+ makefile->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING, warning);
+ }
+ }
+ return true;
+ }
+ }
+ }
+ }
+ // File not found
+ return false;
+ };
+
+ // Try to find the file in various directories
+ if (this->Location.DirectoryIsAmbiguous()) {
+ if (findInDir(makefile->GetCurrentSourceDirectory()) ||
+ findInDir(makefile->GetCurrentBinaryDirectory())) {
+ return true;
+ }
+ } else {
+ if (findInDir({})) {
+ return true;
+ }
+ }
+
+ // Compose error
+ std::string err = cmStrCat("Cannot find source file:\n ", lPath);
+ switch (cmp0115) {
+ case cmPolicies::OLD:
+ case cmPolicies::WARN:
+ err = cmStrCat(err, "\nTried extensions");
+ for (auto const& ext : exts) {
+ err = cmStrCat(err, " .", ext);
+ }
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ break;
+ }
+ if (error != nullptr) {
+ *error = std::move(err);
+ } else {
+ makefile->IssueMessage(MessageType::FATAL_ERROR, err);
+ }
+ this->FindFullPathFailed = true;
+
+ // File not found
+ return false;
+}
+
+void cmSourceFile::CheckExtension()
+{
+ // Compute the extension.
+ std::string realExt =
+ cmSystemTools::GetFilenameLastExtension(this->FullPath);
+ if (!realExt.empty()) {
+ // Store the extension without the leading '.'.
+ this->Extension = realExt.substr(1);
+ }
+
+ // Look for object files.
+ if (this->Extension == "obj" || this->Extension == "o" ||
+ this->Extension == "lo") {
+ this->SetProperty("EXTERNAL_OBJECT", "1");
+ }
+
+ // Try to identify the source file language from the extension.
+ if (this->Language.empty()) {
+ this->CheckLanguage(this->Extension);
+ }
+}
+
+void cmSourceFile::CheckLanguage(std::string const& ext)
+{
+ // Try to identify the source file language from the extension.
+ cmMakefile const* mf = this->Location.GetMakefile();
+ cmGlobalGenerator* gg = mf->GetGlobalGenerator();
+ std::string l = gg->GetLanguageFromExtension(ext.c_str());
+ if (!l.empty()) {
+ this->Language = l;
+ }
+}
+
+bool cmSourceFile::Matches(cmSourceFileLocation const& loc)
+{
+ return this->Location.Matches(loc);
+}
+
+void cmSourceFile::SetProperty(const std::string& prop, const char* value)
+{
+ if (prop == propINCLUDE_DIRECTORIES) {
+ this->IncludeDirectories.clear();
+ if (value) {
+ cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
+ this->IncludeDirectories.emplace_back(value, lfbt);
+ }
+ } else if (prop == propCOMPILE_OPTIONS) {
+ this->CompileOptions.clear();
+ if (value) {
+ cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
+ this->CompileOptions.emplace_back(value, lfbt);
+ }
+ } else if (prop == propCOMPILE_DEFINITIONS) {
+ this->CompileDefinitions.clear();
+ if (value) {
+ cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
+ this->CompileDefinitions.emplace_back(value, lfbt);
+ }
+ } else {
+ this->Properties.SetProperty(prop, value);
+ }
+}
+
+void cmSourceFile::AppendProperty(const std::string& prop,
+ const std::string& value, bool asString)
+{
+ if (prop == propINCLUDE_DIRECTORIES) {
+ if (!value.empty()) {
+ cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
+ this->IncludeDirectories.emplace_back(value, lfbt);
+ }
+ } else if (prop == propCOMPILE_OPTIONS) {
+ if (!value.empty()) {
+ cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
+ this->CompileOptions.emplace_back(value, lfbt);
+ }
+ } else if (prop == propCOMPILE_DEFINITIONS) {
+ if (!value.empty()) {
+ cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
+ this->CompileDefinitions.emplace_back(value, lfbt);
+ }
+ } else {
+ this->Properties.AppendProperty(prop, value, asString);
+ }
+}
+
+cmProp cmSourceFile::GetPropertyForUser(const std::string& prop)
+{
+ // This method is a consequence of design history and backwards
+ // compatibility. GetProperty is (and should be) a const method.
+ // Computed properties should not be stored back in the property map
+ // but instead reference information already known. If they need to
+ // cache information in a mutable ivar to provide the return string
+ // safely then so be it.
+ //
+ // The LOCATION property is particularly problematic. The CMake
+ // language has very loose restrictions on the names that will match
+ // a given source file (for historical reasons). Implementing
+ // lookups correctly with such loose naming requires the
+ // cmSourceFileLocation class to commit to a particular full path to
+ // the source file as late as possible. If the users requests the
+ // LOCATION property we must commit now.
+ if (prop == propLOCATION) {
+ // Commit to a location.
+ this->ResolveFullPath();
+ }
+
+ // Similarly, LANGUAGE can be determined by the file extension
+ // if it is requested by the user.
+ if (prop == propLANGUAGE) {
+ // The pointer is valid until `this->Language` is modified.
+ return &this->GetOrDetermineLanguage();
+ }
+
+ // Special handling for GENERATED property.
+ if (prop == propGENERATED) {
+ // We need to check policy CMP0118 in order to determine if we need to
+ // possibly consider the value of a locally set GENERATED property, too.
+ auto policyStatus =
+ this->Location.GetMakefile()->GetPolicyStatus(cmPolicies::CMP0118);
+ if (this->GetIsGenerated(
+ (policyStatus == cmPolicies::WARN || policyStatus == cmPolicies::OLD)
+ ? CheckScope::GlobalAndLocal
+ : CheckScope::Global)) {
+ return &propTRUE;
+ }
+ return &propFALSE;
+ }
+
+ // Perform the normal property lookup.
+ return this->GetProperty(prop);
+}
+
+cmProp cmSourceFile::GetProperty(const std::string& prop) const
+{
+ // Check for computed properties.
+ if (prop == propLOCATION) {
+ if (this->FullPath.empty()) {
+ return nullptr;
+ }
+ return &this->FullPath;
+ }
+
+ // Check for the properties with backtraces.
+ if (prop == propINCLUDE_DIRECTORIES) {
+ if (this->IncludeDirectories.empty()) {
+ return nullptr;
+ }
+
+ static std::string output;
+ output = cmJoin(this->IncludeDirectories, ";");
+ return &output;
+ }
+
+ if (prop == propCOMPILE_OPTIONS) {
+ if (this->CompileOptions.empty()) {
+ return nullptr;
+ }
+
+ static std::string output;
+ output = cmJoin(this->CompileOptions, ";");
+ return &output;
+ }
+
+ if (prop == propCOMPILE_DEFINITIONS) {
+ if (this->CompileDefinitions.empty()) {
+ return nullptr;
+ }
+
+ static std::string output;
+ output = cmJoin(this->CompileDefinitions, ";");
+ return &output;
+ }
+
+ cmProp retVal = this->Properties.GetPropertyValue(prop);
+ if (!retVal) {
+ cmMakefile const* mf = this->Location.GetMakefile();
+ const bool chain =
+ mf->GetState()->IsPropertyChained(prop, cmProperty::SOURCE_FILE);
+ if (chain) {
+ return mf->GetProperty(prop, chain);
+ }
+ return nullptr;
+ }
+
+ return retVal;
+}
+
+const std::string& cmSourceFile::GetSafeProperty(const std::string& prop) const
+{
+ cmProp ret = this->GetProperty(prop);
+ if (ret) {
+ return *ret;
+ }
+
+ static std::string const s_empty;
+ return s_empty;
+}
+
+bool cmSourceFile::GetPropertyAsBool(const std::string& prop) const
+{
+ return cmIsOn(this->GetProperty(prop));
+}
+
+void cmSourceFile::MarkAsGenerated()
+{
+ this->IsGenerated = true;
+ const auto& mf = *this->Location.GetMakefile();
+ mf.GetGlobalGenerator()->MarkAsGeneratedFile(this->ResolveFullPath());
+}
+
+bool cmSourceFile::GetIsGenerated(CheckScope checkScope) const
+{
+ if (this->IsGenerated) {
+ // Globally marked as generated!
+ return true;
+ }
+ if (checkScope == CheckScope::GlobalAndLocal) {
+ // Check locally stored properties.
+ return this->GetPropertyAsBool(propGENERATED);
+ }
+ return false;
+}
+
+void cmSourceFile::SetProperties(cmPropertyMap properties)
+{
+ this->Properties = std::move(properties);
+}
+
+cmCustomCommand* cmSourceFile::GetCustomCommand() const
+{
+ return this->CustomCommand.get();
+}
+
+void cmSourceFile::SetCustomCommand(std::unique_ptr<cmCustomCommand> cc)
+{
+ this->CustomCommand = std::move(cc);
+}
diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h
new file mode 100644
index 0000000..32ed687
--- /dev/null
+++ b/Source/cmSourceFile.h
@@ -0,0 +1,183 @@
+/* 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 <memory>
+#include <string>
+#include <vector>
+
+#include "cmCustomCommand.h"
+#include "cmListFileCache.h"
+#include "cmProperty.h"
+#include "cmPropertyMap.h"
+#include "cmSourceFileLocation.h"
+#include "cmSourceFileLocationKind.h"
+
+class cmMakefile;
+
+/** \class cmSourceFile
+ * \brief Represent a class loaded from a makefile.
+ *
+ * cmSourceFile represents a class loaded from a makefile.
+ */
+class cmSourceFile
+{
+public:
+ /**
+ * Construct with the makefile storing the source and the initial name
+ * referencing it. If it shall be marked as generated, this source file's
+ * kind is assumed to be known, regardless of the given value.
+ */
+ cmSourceFile(
+ cmMakefile* mf, const std::string& name, bool generated,
+ cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous);
+
+ /**
+ * Get the custom command for this source file
+ */
+ cmCustomCommand* GetCustomCommand() const;
+ void SetCustomCommand(std::unique_ptr<cmCustomCommand> cc);
+
+ //! Set/Get a property of this source file
+ void SetProperty(const std::string& prop, const char* value);
+ void AppendProperty(const std::string& prop, const std::string& value,
+ bool asString = false);
+ //! Might return a nullptr if the property is not set or invalid
+ cmProp GetProperty(const std::string& prop) const;
+ //! Always returns a valid pointer
+ const std::string& GetSafeProperty(const std::string& prop) const;
+ bool GetPropertyAsBool(const std::string& prop) const;
+
+ /** Implement getting a property when called from a CMake language
+ command like get_property or get_source_file_property. */
+ cmProp GetPropertyForUser(const std::string& prop);
+
+ /// Marks this file as generated
+ /**
+ * This stores this file's path in the global table for all generated source
+ * files.
+ */
+ void MarkAsGenerated();
+ enum class CheckScope
+ {
+ Global,
+ GlobalAndLocal
+ };
+ /// Determines if this source file is marked as generated.
+ /**
+ * This will check if this file's path is stored in the global table of all
+ * generated source files. If that is not the case and checkScope is set to
+ * GlobalAndLocal the value of the possibly existing local GENERATED property
+ * is returned instead.
+ * @param checkScope Determines if alternatively for backwards-compatibility
+ * a local GENERATED property should be considered, too.
+ * @return true if this source file is marked as generated, otherwise false.
+ */
+ bool GetIsGenerated(
+ CheckScope checkScope = CheckScope::GlobalAndLocal) const;
+
+ const std::vector<BT<std::string>>& GetCompileOptions() const
+ {
+ return this->CompileOptions;
+ }
+
+ const std::vector<BT<std::string>>& GetCompileDefinitions() const
+ {
+ return this->CompileDefinitions;
+ }
+
+ const std::vector<BT<std::string>>& GetIncludeDirectories() const
+ {
+ return this->IncludeDirectories;
+ }
+
+ /**
+ * Resolves the full path to the file. Attempts to locate the file on disk
+ * and finalizes its location.
+ */
+ std::string const& ResolveFullPath(std::string* error = nullptr,
+ std::string* cmp0115Warning = nullptr);
+
+ /**
+ * The resolved full path to the file. The returned file name might be empty
+ * if the path has not yet been resolved.
+ */
+ std::string const& GetFullPath() const;
+
+ /**
+ * Get the information currently known about the source file
+ * location without attempting to locate the file as GetFullPath
+ * would. See cmSourceFileLocation documentation.
+ */
+ cmSourceFileLocation const& GetLocation() const;
+
+ /**
+ * Get the file extension of this source file.
+ */
+ std::string const& GetExtension() const;
+
+ /**
+ * Get the language of the compiler to use for this source file.
+ */
+ std::string const& GetOrDetermineLanguage();
+ std::string GetLanguage() const;
+
+ /**
+ * Return the vector that holds the list of dependencies
+ */
+ const std::vector<std::string>& GetDepends() const { return this->Depends; }
+ void AddDepend(const std::string& d) { this->Depends.push_back(d); }
+
+ // Get the properties
+ const cmPropertyMap& GetProperties() const { return this->Properties; }
+ // Set the properties
+ void SetProperties(cmPropertyMap properties);
+
+ /**
+ * Check whether the given source file location could refer to this
+ * source.
+ */
+ bool Matches(cmSourceFileLocation const&);
+
+ void SetObjectLibrary(std::string const& objlib);
+ std::string GetObjectLibrary() const;
+
+private:
+ cmSourceFileLocation Location;
+ cmPropertyMap Properties;
+ std::unique_ptr<cmCustomCommand> CustomCommand;
+ std::string Extension;
+ std::string Language;
+ std::string FullPath;
+ std::string ObjectLibrary;
+ std::vector<std::string> Depends;
+ std::vector<BT<std::string>> CompileOptions;
+ std::vector<BT<std::string>> CompileDefinitions;
+ std::vector<BT<std::string>> IncludeDirectories;
+ bool FindFullPathFailed = false;
+ bool IsGenerated = false;
+
+ bool FindFullPath(std::string* error, std::string* cmp0115Warning);
+ void CheckExtension();
+ void CheckLanguage(std::string const& ext);
+
+ static const std::string propLANGUAGE;
+ static const std::string propLOCATION;
+ static const std::string propGENERATED;
+ static const std::string propCOMPILE_DEFINITIONS;
+ static const std::string propCOMPILE_OPTIONS;
+ static const std::string propINCLUDE_DIRECTORIES;
+};
+
+// TODO: Factor out into platform information modules.
+#define CM_HEADER_REGEX "\\.(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$"
+
+#define CM_SOURCE_REGEX \
+ "\\.(C|F|M|c|c\\+\\+|cc|cpp|mpp|cxx|ixx|cppm|cu|f|f90|for|fpp|ftn|m|mm|" \
+ "rc|def|r|odl|idl|hpj|bat)$"
+
+#define CM_PCH_REGEX "cmake_pch(_[^.]+)?\\.(h|hxx)$"
+
+#define CM_RESOURCE_REGEX "\\.(pdf|plist|png|jpeg|jpg|storyboard|xcassets)$"
diff --git a/Source/cmSourceFileLocation.cxx b/Source/cmSourceFileLocation.cxx
new file mode 100644
index 0000000..8c7154d
--- /dev/null
+++ b/Source/cmSourceFileLocation.cxx
@@ -0,0 +1,235 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSourceFileLocation.h"
+
+#include <cassert>
+
+#include <cm/string_view>
+
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+cmSourceFileLocation::cmSourceFileLocation() = default;
+
+cmSourceFileLocation::cmSourceFileLocation(const cmSourceFileLocation& loc)
+ : Makefile(loc.Makefile)
+{
+ this->AmbiguousDirectory = loc.AmbiguousDirectory;
+ this->AmbiguousExtension = loc.AmbiguousExtension;
+ this->Directory = loc.Directory;
+ this->Name = loc.Name;
+}
+
+cmSourceFileLocation::cmSourceFileLocation(cmMakefile const* mf,
+ const std::string& name,
+ cmSourceFileLocationKind kind)
+ : Makefile(mf)
+{
+ this->AmbiguousDirectory = !cmSystemTools::FileIsFullPath(name);
+ this->AmbiguousExtension = true;
+ this->Directory = cmSystemTools::GetFilenamePath(name);
+ if (cmSystemTools::FileIsFullPath(this->Directory)) {
+ this->Directory = cmSystemTools::CollapseFullPath(this->Directory);
+ }
+ this->Name = cmSystemTools::GetFilenameName(name);
+ if (kind == cmSourceFileLocationKind::Known) {
+ this->DirectoryUseSource();
+ this->AmbiguousExtension = false;
+ } else {
+ this->UpdateExtension(name);
+ }
+}
+
+std::string cmSourceFileLocation::GetFullPath() const
+{
+ std::string path = this->GetDirectory();
+ if (!path.empty()) {
+ path += '/';
+ }
+ path += this->GetName();
+ return path;
+}
+
+void cmSourceFileLocation::Update(cmSourceFileLocation const& loc)
+{
+ if (this->AmbiguousDirectory && !loc.AmbiguousDirectory) {
+ this->Directory = loc.Directory;
+ this->AmbiguousDirectory = false;
+ }
+ if (this->AmbiguousExtension && !loc.AmbiguousExtension) {
+ this->Name = loc.Name;
+ this->AmbiguousExtension = false;
+ }
+}
+
+void cmSourceFileLocation::DirectoryUseSource()
+{
+ assert(this->Makefile);
+ if (this->AmbiguousDirectory) {
+ this->Directory = cmSystemTools::CollapseFullPath(
+ this->Directory, this->Makefile->GetCurrentSourceDirectory());
+ this->AmbiguousDirectory = false;
+ }
+}
+
+void cmSourceFileLocation::DirectoryUseBinary()
+{
+ assert(this->Makefile);
+ if (this->AmbiguousDirectory) {
+ this->Directory = cmSystemTools::CollapseFullPath(
+ this->Directory, this->Makefile->GetCurrentBinaryDirectory());
+ this->AmbiguousDirectory = false;
+ }
+}
+
+void cmSourceFileLocation::UpdateExtension(const std::string& name)
+{
+ assert(this->Makefile);
+ // Check the extension.
+ std::string ext = cmSystemTools::GetFilenameLastExtension(name);
+ if (!ext.empty()) {
+ ext = ext.substr(1);
+ }
+
+ // The global generator checks extensions of enabled languages.
+ cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+ cmMakefile const* mf = this->Makefile;
+ auto* cm = mf->GetCMakeInstance();
+ if (!gg->GetLanguageFromExtension(ext.c_str()).empty() ||
+ cm->IsAKnownExtension(ext)) {
+ // This is a known extension. Use the given filename with extension.
+ this->Name = cmSystemTools::GetFilenameName(name);
+ this->AmbiguousExtension = false;
+ } else {
+ // This is not a known extension. See if the file exists on disk as
+ // named.
+ std::string tryPath;
+ if (this->AmbiguousDirectory) {
+ // Check the source tree only because a file in the build tree should
+ // be specified by full path at least once. We do not want this
+ // detection to depend on whether the project has already been built.
+ tryPath = cmStrCat(this->Makefile->GetCurrentSourceDirectory(), '/');
+ }
+ if (!this->Directory.empty()) {
+ tryPath += this->Directory;
+ tryPath += "/";
+ }
+ tryPath += this->Name;
+ if (cmSystemTools::FileExists(tryPath, true)) {
+ // We found a source file named by the user on disk. Trust it's
+ // extension.
+ this->Name = cmSystemTools::GetFilenameName(name);
+ this->AmbiguousExtension = false;
+
+ // If the directory was ambiguous, it isn't anymore.
+ if (this->AmbiguousDirectory) {
+ this->DirectoryUseSource();
+ }
+ }
+ }
+}
+
+bool cmSourceFileLocation::MatchesAmbiguousExtension(
+ cmSourceFileLocation const& loc) const
+{
+ assert(this->Makefile);
+ // This location's extension is not ambiguous but loc's extension
+ // is. See if the names match as-is.
+ if (this->Name == loc.Name) {
+ return true;
+ }
+
+ // Check if loc's name could possibly be extended to our name by
+ // adding an extension.
+ if (!(this->Name.size() > loc.Name.size() &&
+ this->Name[loc.Name.size()] == '.' &&
+ cmHasPrefix(this->Name, loc.Name))) {
+ return false;
+ }
+
+ // Only a fixed set of extensions will be tried to match a file on
+ // disk. One of these must match if loc refers to this source file.
+ auto ext = cm::string_view(this->Name).substr(loc.Name.size() + 1);
+ cmMakefile const* mf = this->Makefile;
+ auto* cm = mf->GetCMakeInstance();
+ return cm->IsAKnownExtension(ext);
+}
+
+bool cmSourceFileLocation::Matches(cmSourceFileLocation const& loc)
+{
+ assert(this->Makefile);
+ if (this->AmbiguousExtension == loc.AmbiguousExtension) {
+ // Both extensions are similarly ambiguous. Since only the old fixed set
+ // of extensions will be tried, the names must match at this point to be
+ // the same file.
+ if (this->Name.size() != loc.Name.size() ||
+ !cmSystemTools::ComparePath(this->Name, loc.Name)) {
+ return false;
+ }
+ } else {
+ const cmSourceFileLocation* loc1;
+ const cmSourceFileLocation* loc2;
+ if (this->AmbiguousExtension) {
+ // Only "this" extension is ambiguous.
+ loc1 = &loc;
+ loc2 = this;
+ } else {
+ // Only "loc" extension is ambiguous.
+ loc1 = this;
+ loc2 = &loc;
+ }
+ if (!loc1->MatchesAmbiguousExtension(*loc2)) {
+ return false;
+ }
+ }
+
+ if (!this->AmbiguousDirectory && !loc.AmbiguousDirectory) {
+ // Both sides have absolute directories.
+ if (this->Directory != loc.Directory) {
+ return false;
+ }
+ } else if (this->AmbiguousDirectory && loc.AmbiguousDirectory) {
+ if (this->Makefile == loc.Makefile) {
+ // Both sides have directories relative to the same location.
+ if (this->Directory != loc.Directory) {
+ return false;
+ }
+ } else {
+ // Each side has a directory relative to a different location.
+ // This can occur when referencing a source file from a different
+ // directory. This is not yet allowed.
+ this->Makefile->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ "Matches error: Each side has a directory relative to a different "
+ "location. This can occur when referencing a source file from a "
+ "different directory. This is not yet allowed.");
+ return false;
+ }
+ } else if (this->AmbiguousDirectory) {
+ // Compare possible directory combinations.
+ std::string const srcDir = cmSystemTools::CollapseFullPath(
+ this->Directory, this->Makefile->GetCurrentSourceDirectory());
+ std::string const binDir = cmSystemTools::CollapseFullPath(
+ this->Directory, this->Makefile->GetCurrentBinaryDirectory());
+ if (srcDir != loc.Directory && binDir != loc.Directory) {
+ return false;
+ }
+ } else if (loc.AmbiguousDirectory) {
+ // Compare possible directory combinations.
+ std::string const srcDir = cmSystemTools::CollapseFullPath(
+ loc.Directory, loc.Makefile->GetCurrentSourceDirectory());
+ std::string const binDir = cmSystemTools::CollapseFullPath(
+ loc.Directory, loc.Makefile->GetCurrentBinaryDirectory());
+ if (srcDir != this->Directory && binDir != this->Directory) {
+ return false;
+ }
+ }
+
+ // File locations match.
+ this->Update(loc);
+ return true;
+}
diff --git a/Source/cmSourceFileLocation.h b/Source/cmSourceFileLocation.h
new file mode 100644
index 0000000..b373d3d
--- /dev/null
+++ b/Source/cmSourceFileLocation.h
@@ -0,0 +1,103 @@
+/* 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 <string>
+
+#include "cmSourceFileLocationKind.h"
+
+class cmMakefile;
+
+/** \class cmSourceFileLocation
+ * \brief cmSourceFileLocation tracks knowledge about a source file location
+ *
+ * Source files can be referenced by a variety of names. The
+ * directory and/or extension may be omitted leading to a certain
+ * level of ambiguity about the source file location. This class is
+ * used by cmSourceFile to keep track of what is known about the
+ * source file location. Each reference may add some information
+ * about the directory or extension of the file.
+ */
+class cmSourceFileLocation
+{
+public:
+ /**
+ * Construct for a source file created in a given cmMakefile
+ * instance with an initial name.
+ */
+ cmSourceFileLocation(
+ cmMakefile const* mf, const std::string& name,
+ cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous);
+ cmSourceFileLocation();
+ cmSourceFileLocation(const cmSourceFileLocation& loc);
+
+ cmSourceFileLocation& operator=(cmSourceFileLocation const&) = delete;
+
+ /**
+ * Return whether the given source file location could refers to the
+ * same source file as this location given the level of ambiguity in
+ * each location.
+ */
+ bool Matches(cmSourceFileLocation const& loc);
+
+ /**
+ * Explicitly state that the source file is located in the source tree.
+ */
+ void DirectoryUseSource();
+
+ /**
+ * Explicitly state that the source file is located in the build tree.
+ */
+ void DirectoryUseBinary();
+
+ /**
+ * Return whether the directory containing the source is ambiguous.
+ */
+ bool DirectoryIsAmbiguous() const { return this->AmbiguousDirectory; }
+
+ /**
+ * Return whether the extension of the source name is ambiguous.
+ */
+ bool ExtensionIsAmbiguous() const { return this->AmbiguousExtension; }
+
+ /**
+ * Get the directory containing the file as best is currently known.
+ * If DirectoryIsAmbiguous() returns false this will be a full path.
+ * Otherwise it will be a relative path (possibly empty) that is
+ * either with respect to the source or build tree.
+ */
+ const std::string& GetDirectory() const { return this->Directory; }
+
+ /**
+ * Get the file name as best is currently known. If
+ * ExtensionIsAmbiguous() returns true this name may not be the
+ * final name (but could be). Otherwise the returned name is the
+ * final name.
+ */
+ const std::string& GetName() const { return this->Name; }
+
+ /**
+ * Get the full file path composed of GetDirectory() and GetName().
+ */
+ std::string GetFullPath() const;
+
+ /**
+ * Get the cmMakefile instance for which the source file was created.
+ */
+ cmMakefile const* GetMakefile() const { return this->Makefile; }
+
+private:
+ cmMakefile const* const Makefile = nullptr;
+ bool AmbiguousDirectory = true;
+ bool AmbiguousExtension = true;
+ std::string Directory;
+ std::string Name;
+
+ bool MatchesAmbiguousExtension(cmSourceFileLocation const& loc) const;
+
+ // Update the location with additional knowledge.
+ void Update(cmSourceFileLocation const& loc);
+ void UpdateExtension(const std::string& name);
+};
diff --git a/Source/cmSourceFileLocationKind.h b/Source/cmSourceFileLocationKind.h
new file mode 100644
index 0000000..73108f1
--- /dev/null
+++ b/Source/cmSourceFileLocationKind.h
@@ -0,0 +1,12 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+enum class cmSourceFileLocationKind
+{
+ // The location is user-specified and may be ambiguous.
+ Ambiguous,
+ // The location is known to be at the given location; do not try to guess at
+ // extensions or absolute path.
+ Known
+};
diff --git a/Source/cmSourceGroup.cxx b/Source/cmSourceGroup.cxx
new file mode 100644
index 0000000..155068cb
--- /dev/null
+++ b/Source/cmSourceGroup.cxx
@@ -0,0 +1,145 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSourceGroup.h"
+
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmStringAlgorithms.h"
+
+class cmSourceGroupInternals
+{
+public:
+ std::vector<cmSourceGroup> GroupChildren;
+};
+
+cmSourceGroup::cmSourceGroup(std::string name, const char* regex,
+ const char* parentName)
+ : Name(std::move(name))
+{
+ this->Internal = cm::make_unique<cmSourceGroupInternals>();
+ this->SetGroupRegex(regex);
+ if (parentName) {
+ this->FullName = cmStrCat(parentName, '\\');
+ }
+ this->FullName += this->Name;
+}
+
+cmSourceGroup::~cmSourceGroup() = default;
+
+cmSourceGroup::cmSourceGroup(cmSourceGroup const& r)
+{
+ this->Name = r.Name;
+ this->FullName = r.FullName;
+ this->GroupRegex = r.GroupRegex;
+ this->GroupFiles = r.GroupFiles;
+ this->SourceFiles = r.SourceFiles;
+ this->Internal = cm::make_unique<cmSourceGroupInternals>(*r.Internal);
+}
+
+cmSourceGroup& cmSourceGroup::operator=(cmSourceGroup const& r)
+{
+ this->Name = r.Name;
+ this->GroupRegex = r.GroupRegex;
+ this->GroupFiles = r.GroupFiles;
+ this->SourceFiles = r.SourceFiles;
+ *(this->Internal) = *(r.Internal);
+ return *this;
+}
+
+void cmSourceGroup::SetGroupRegex(const char* regex)
+{
+ if (regex) {
+ this->GroupRegex.compile(regex);
+ } else {
+ this->GroupRegex.compile("^$");
+ }
+}
+
+void cmSourceGroup::AddGroupFile(const std::string& name)
+{
+ this->GroupFiles.insert(name);
+}
+
+std::string const& cmSourceGroup::GetName() const
+{
+ return this->Name;
+}
+
+std::string const& cmSourceGroup::GetFullName() const
+{
+ return this->FullName;
+}
+
+bool cmSourceGroup::MatchesRegex(const std::string& name)
+{
+ return this->GroupRegex.find(name);
+}
+
+bool cmSourceGroup::MatchesFiles(const std::string& name) const
+{
+ return this->GroupFiles.find(name) != this->GroupFiles.cend();
+}
+
+void cmSourceGroup::AssignSource(const cmSourceFile* sf)
+{
+ this->SourceFiles.push_back(sf);
+}
+
+const std::vector<const cmSourceFile*>& cmSourceGroup::GetSourceFiles() const
+{
+ return this->SourceFiles;
+}
+
+void cmSourceGroup::AddChild(cmSourceGroup const& child)
+{
+ this->Internal->GroupChildren.push_back(child);
+}
+
+cmSourceGroup* cmSourceGroup::LookupChild(const std::string& name)
+{
+ for (cmSourceGroup& group : this->Internal->GroupChildren) {
+ // look if descenened is the one were looking for
+ if (group.GetName() == name) {
+ return (&group); // if it so return it
+ }
+ }
+
+ // if no child with this name was found return NULL
+ return nullptr;
+}
+
+cmSourceGroup* cmSourceGroup::MatchChildrenFiles(const std::string& name)
+{
+ if (this->MatchesFiles(name)) {
+ return this;
+ }
+ for (cmSourceGroup& group : this->Internal->GroupChildren) {
+ cmSourceGroup* result = group.MatchChildrenFiles(name);
+ if (result) {
+ return result;
+ }
+ }
+ return nullptr;
+}
+
+cmSourceGroup* cmSourceGroup::MatchChildrenRegex(const std::string& name)
+{
+ for (cmSourceGroup& group : this->Internal->GroupChildren) {
+ cmSourceGroup* result = group.MatchChildrenRegex(name);
+ if (result) {
+ return result;
+ }
+ }
+ if (this->MatchesRegex(name)) {
+ return this;
+ }
+
+ return nullptr;
+}
+
+std::vector<cmSourceGroup> const& cmSourceGroup::GetGroupChildren() const
+{
+ return this->Internal->GroupChildren;
+}
diff --git a/Source/cmSourceGroup.h b/Source/cmSourceGroup.h
new file mode 100644
index 0000000..295240d
--- /dev/null
+++ b/Source/cmSourceGroup.h
@@ -0,0 +1,126 @@
+/* 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 <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+class cmSourceFile;
+class cmSourceGroupInternals;
+
+/** \class cmSourceGroup
+ * \brief Hold a group of sources as specified by a SOURCE_GROUP command.
+ *
+ * cmSourceGroup holds a regular expression and a list of files. When
+ * local generators are about to generate the rules for a target's
+ * files, the set of source groups is consulted to group files
+ * together. A file is placed into the last source group that lists
+ * the file by name. If no group lists the file, it is placed into
+ * the last group whose regex matches it.
+ */
+class cmSourceGroup
+{
+public:
+ cmSourceGroup(std::string name, const char* regex,
+ const char* parentName = nullptr);
+ cmSourceGroup(cmSourceGroup const& r);
+ ~cmSourceGroup();
+ cmSourceGroup& operator=(cmSourceGroup const&);
+
+ /**
+ * Set the regular expression for this group.
+ */
+ void SetGroupRegex(const char* regex);
+
+ /**
+ * Add a file name to the explicit list of files for this group.
+ */
+ void AddGroupFile(const std::string& name);
+
+ /**
+ * Add child to this sourcegroup
+ */
+ void AddChild(cmSourceGroup const& child);
+
+ /**
+ * Looks up child and returns it
+ */
+ cmSourceGroup* LookupChild(const std::string& name);
+
+ /**
+ * Get the name of this group.
+ */
+ std::string const& GetName() const;
+
+ /**
+ * Get the full path name for group.
+ */
+ std::string const& GetFullName() const;
+
+ /**
+ * Check if the given name matches this group's regex.
+ */
+ bool MatchesRegex(const std::string& name);
+
+ /**
+ * Check if the given name matches this group's explicit file list.
+ */
+ bool MatchesFiles(const std::string& name) const;
+
+ /**
+ * Check if the given name matches this group's explicit file list
+ * in children.
+ */
+ cmSourceGroup* MatchChildrenFiles(const std::string& name);
+
+ /**
+ * Check if the given name matches this group's regex in children.
+ */
+ cmSourceGroup* MatchChildrenRegex(const std::string& name);
+
+ /**
+ * Assign the given source file to this group. Used only by
+ * generators.
+ */
+ void AssignSource(const cmSourceFile* sf);
+
+ /**
+ * Get the list of the source files that have been assigned to this
+ * source group.
+ */
+ const std::vector<const cmSourceFile*>& GetSourceFiles() const;
+
+ std::vector<cmSourceGroup> const& GetGroupChildren() const;
+
+private:
+ /**
+ * The name of the source group.
+ */
+ std::string Name;
+ // Full path to group
+ std::string FullName;
+
+ /**
+ * The regular expression matching the files in the group.
+ */
+ cmsys::RegularExpression GroupRegex;
+
+ /**
+ * Set of file names explicitly added to this group.
+ */
+ std::set<std::string> GroupFiles;
+
+ /**
+ * Vector of all source files that have been assigned to
+ * this group.
+ */
+ std::vector<const cmSourceFile*> SourceFiles;
+
+ std::unique_ptr<cmSourceGroupInternals> Internal;
+};
diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx
new file mode 100644
index 0000000..bb75a14
--- /dev/null
+++ b/Source/cmSourceGroupCommand.cxx
@@ -0,0 +1,310 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSourceGroupCommand.h"
+
+#include <cstddef>
+#include <map>
+#include <set>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmSourceGroup.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+
+using ParsedArguments = std::map<std::string, std::vector<std::string>>;
+using ExpectedOptions = std::vector<std::string>;
+
+const std::string kTreeOptionName = "TREE";
+const std::string kPrefixOptionName = "PREFIX";
+const std::string kFilesOptionName = "FILES";
+const std::string kRegexOptionName = "REGULAR_EXPRESSION";
+const std::string kSourceGroupOptionName = "<sg_name>";
+
+std::vector<std::string> tokenizePath(const std::string& path)
+{
+ return cmTokenize(path, "\\/");
+}
+
+std::set<std::string> getSourceGroupFilesPaths(
+ const std::string& root, const std::vector<std::string>& files)
+{
+ std::set<std::string> ret;
+ const std::string::size_type rootLength = root.length();
+
+ for (std::string const& file : files) {
+ ret.insert(file.substr(rootLength + 1)); // +1 to also omnit last '/'
+ }
+
+ return ret;
+}
+
+bool rootIsPrefix(const std::string& root,
+ const std::vector<std::string>& files, std::string& error)
+{
+ for (std::string const& file : files) {
+ if (!cmHasPrefix(file, root)) {
+ error = cmStrCat("ROOT: ", root, " is not a prefix of file: ", file);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+std::vector<std::string> prepareFilesPathsForTree(
+ const std::vector<std::string>& filesPaths,
+ const std::string& currentSourceDir)
+{
+ std::vector<std::string> prepared;
+ prepared.reserve(filesPaths.size());
+
+ for (auto const& filePath : filesPaths) {
+ std::string fullPath =
+ cmSystemTools::CollapseFullPath(filePath, currentSourceDir);
+ // If provided file path is actually not a directory, silently ignore it.
+ if (cmSystemTools::FileIsDirectory(fullPath)) {
+ continue;
+ }
+
+ // Handle directory that doesn't exist yet.
+ if (!fullPath.empty() &&
+ (fullPath.back() == '/' || fullPath.back() == '\\')) {
+ continue;
+ }
+
+ prepared.emplace_back(std::move(fullPath));
+ }
+
+ return prepared;
+}
+
+bool addFilesToItsSourceGroups(const std::string& root,
+ const std::set<std::string>& sgFilesPaths,
+ const std::string& prefix, cmMakefile& makefile,
+ std::string& errorMsg)
+{
+ cmSourceGroup* sg;
+
+ for (std::string const& sgFilesPath : sgFilesPaths) {
+
+ std::vector<std::string> tokenizedPath;
+ if (!prefix.empty()) {
+ tokenizedPath = tokenizePath(cmStrCat(prefix, '/', sgFilesPath));
+ } else {
+ tokenizedPath = tokenizePath(sgFilesPath);
+ }
+
+ if (!tokenizedPath.empty()) {
+ tokenizedPath.pop_back();
+
+ if (tokenizedPath.empty()) {
+ tokenizedPath.emplace_back();
+ }
+
+ sg = makefile.GetOrCreateSourceGroup(tokenizedPath);
+
+ if (!sg) {
+ errorMsg = "Could not create source group for file: " + sgFilesPath;
+ return false;
+ }
+ const std::string fullPath =
+ cmSystemTools::CollapseFullPath(sgFilesPath, root);
+ sg->AddGroupFile(fullPath);
+ }
+ }
+
+ return true;
+}
+
+ExpectedOptions getExpectedOptions()
+{
+ ExpectedOptions options;
+
+ options.push_back(kTreeOptionName);
+ options.push_back(kPrefixOptionName);
+ options.push_back(kFilesOptionName);
+ options.push_back(kRegexOptionName);
+
+ return options;
+}
+
+bool isExpectedOption(const std::string& argument,
+ const ExpectedOptions& expectedOptions)
+{
+ return cm::contains(expectedOptions, argument);
+}
+
+void parseArguments(const std::vector<std::string>& args,
+ ParsedArguments& parsedArguments)
+{
+ const ExpectedOptions expectedOptions = getExpectedOptions();
+ size_t i = 0;
+
+ // at this point we know that args vector is not empty
+
+ // if first argument is not one of expected options it's source group name
+ if (!isExpectedOption(args[0], expectedOptions)) {
+ // get source group name and go to next argument
+ parsedArguments[kSourceGroupOptionName].push_back(args[0]);
+ ++i;
+ }
+
+ for (; i < args.size();) {
+ // get current option and increment index to go to next argument
+ const std::string& currentOption = args[i++];
+
+ // create current option entry in parsed arguments
+ std::vector<std::string>& currentOptionArguments =
+ parsedArguments[currentOption];
+
+ // collect option arguments while we won't find another expected option
+ while (i < args.size() && !isExpectedOption(args[i], expectedOptions)) {
+ currentOptionArguments.push_back(args[i++]);
+ }
+ }
+}
+
+} // namespace
+
+static bool checkArgumentsPreconditions(const ParsedArguments& parsedArguments,
+ std::string& errorMsg);
+
+static bool processTree(cmMakefile& mf, ParsedArguments& parsedArguments,
+ std::string& errorMsg);
+
+static bool checkSingleParameterArgumentPreconditions(
+ const std::string& argument, const ParsedArguments& parsedArguments,
+ std::string& errorMsg);
+
+bool cmSourceGroupCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ // If only two arguments are given, the pre-1.8 version of the
+ // command is being invoked.
+ if (args.size() == 2 && args[1] != "FILES") {
+ cmSourceGroup* sg = mf.GetOrCreateSourceGroup(args[0]);
+
+ if (!sg) {
+ status.SetError("Could not create or find source group");
+ return false;
+ }
+
+ sg->SetGroupRegex(args[1].c_str());
+ return true;
+ }
+
+ ParsedArguments parsedArguments;
+ std::string errorMsg;
+
+ parseArguments(args, parsedArguments);
+
+ if (!checkArgumentsPreconditions(parsedArguments, errorMsg)) {
+ return false;
+ }
+
+ if (parsedArguments.find(kTreeOptionName) != parsedArguments.end()) {
+ if (!processTree(mf, parsedArguments, errorMsg)) {
+ status.SetError(errorMsg);
+ return false;
+ }
+ } else {
+ if (parsedArguments.find(kSourceGroupOptionName) ==
+ parsedArguments.end()) {
+ status.SetError("Missing source group name.");
+ return false;
+ }
+
+ cmSourceGroup* sg = mf.GetOrCreateSourceGroup(args[0]);
+
+ if (!sg) {
+ status.SetError("Could not create or find source group");
+ return false;
+ }
+
+ // handle regex
+ if (parsedArguments.find(kRegexOptionName) != parsedArguments.end()) {
+ const std::string& sgRegex = parsedArguments[kRegexOptionName].front();
+ sg->SetGroupRegex(sgRegex.c_str());
+ }
+
+ // handle files
+ const std::vector<std::string>& filesArguments =
+ parsedArguments[kFilesOptionName];
+ for (auto const& filesArg : filesArguments) {
+ std::string src = filesArg;
+ src =
+ cmSystemTools::CollapseFullPath(src, mf.GetCurrentSourceDirectory());
+ sg->AddGroupFile(src);
+ }
+ }
+
+ return true;
+}
+
+static bool checkArgumentsPreconditions(const ParsedArguments& parsedArguments,
+ std::string& errorMsg)
+{
+ return checkSingleParameterArgumentPreconditions(
+ kPrefixOptionName, parsedArguments, errorMsg) &&
+ checkSingleParameterArgumentPreconditions(kTreeOptionName, parsedArguments,
+ errorMsg) &&
+ checkSingleParameterArgumentPreconditions(kRegexOptionName,
+ parsedArguments, errorMsg);
+}
+
+static bool processTree(cmMakefile& mf, ParsedArguments& parsedArguments,
+ std::string& errorMsg)
+{
+ const std::string root =
+ cmSystemTools::CollapseFullPath(parsedArguments[kTreeOptionName].front());
+ std::string prefix = parsedArguments[kPrefixOptionName].empty()
+ ? ""
+ : parsedArguments[kPrefixOptionName].front();
+
+ const std::vector<std::string> filesVector = prepareFilesPathsForTree(
+ parsedArguments[kFilesOptionName], mf.GetCurrentSourceDirectory());
+
+ if (!rootIsPrefix(root, filesVector, errorMsg)) {
+ return false;
+ }
+
+ std::set<std::string> sourceGroupPaths =
+ getSourceGroupFilesPaths(root, filesVector);
+
+ return addFilesToItsSourceGroups(root, sourceGroupPaths, prefix, mf,
+ errorMsg);
+}
+
+static bool checkSingleParameterArgumentPreconditions(
+ const std::string& argument, const ParsedArguments& parsedArguments,
+ std::string& errorMsg)
+{
+ auto foundArgument = parsedArguments.find(argument);
+ if (foundArgument != parsedArguments.end()) {
+ const std::vector<std::string>& optionArguments = foundArgument->second;
+
+ if (optionArguments.empty()) {
+ errorMsg = argument + " argument given without an argument.";
+ return false;
+ }
+ if (optionArguments.size() > 1) {
+ errorMsg = "too many arguments passed to " + argument + ".";
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/Source/cmSourceGroupCommand.h b/Source/cmSourceGroupCommand.h
new file mode 100644
index 0000000..44e1f8e
--- /dev/null
+++ b/Source/cmSourceGroupCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmSourceGroupCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx
new file mode 100644
index 0000000..280e508
--- /dev/null
+++ b/Source/cmStandardLevelResolver.cxx
@@ -0,0 +1,540 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmStandardLevelResolver.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <sstream>
+#include <stdexcept>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <cm/iterator>
+#include <cmext/algorithm>
+
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmStringAlgorithms.h"
+#include "cmTarget.h"
+#include "cmake.h"
+
+namespace {
+
+#define FEATURE_STRING(F) , #F
+const char* const C_FEATURES[] = { nullptr FOR_EACH_C_FEATURE(
+ FEATURE_STRING) };
+
+const char* const CXX_FEATURES[] = { nullptr FOR_EACH_CXX_FEATURE(
+ FEATURE_STRING) };
+
+const char* const CUDA_FEATURES[] = { nullptr FOR_EACH_CUDA_FEATURE(
+ FEATURE_STRING) };
+#undef FEATURE_STRING
+
+struct StandardNeeded
+{
+ int index;
+ int value;
+};
+
+int ParseStd(std::string const& level)
+{
+ try {
+ return std::stoi(level);
+ } catch (std::invalid_argument&) {
+ // Fall through to use an invalid value.
+ }
+ return -1;
+}
+
+struct StanardLevelComputer
+{
+ explicit StanardLevelComputer(std::string lang, std::vector<int> levels,
+ std::vector<std::string> levelsStr)
+ : Language(std::move(lang))
+ , Levels(std::move(levels))
+ , LevelsAsStrings(std::move(levelsStr))
+ {
+ assert(levels.size() == levelsStr.size());
+ }
+
+ std::string GetCompileOptionDef(cmMakefile* makefile,
+ cmGeneratorTarget const* target,
+ std::string const& config) const
+ {
+
+ const auto& stds = this->Levels;
+ const auto& stdsStrings = this->LevelsAsStrings;
+
+ cmProp defaultStd = makefile->GetDefinition(
+ cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT"));
+ if (!cmNonempty(defaultStd)) {
+ // this compiler has no notion of language standard levels
+ return std::string{};
+ }
+
+ bool ext = true;
+ if (cmProp extPropValue = target->GetLanguageExtensions(this->Language)) {
+ if (cmIsOff(*extPropValue)) {
+ ext = false;
+ }
+ }
+
+ cmProp standardProp = target->GetLanguageStandard(this->Language, config);
+ if (!standardProp) {
+ if (ext) {
+ // No language standard is specified and extensions are not disabled.
+ // Check if this compiler needs a flag to enable extensions.
+ return cmStrCat("CMAKE_", this->Language, "_EXTENSION_COMPILE_OPTION");
+ }
+ return std::string{};
+ }
+
+ std::string const type = ext ? "EXTENSION" : "STANDARD";
+
+ if (target->GetLanguageStandardRequired(this->Language)) {
+ std::string option_flag = cmStrCat(
+ "CMAKE_", this->Language, *standardProp, "_", type, "_COMPILE_OPTION");
+
+ cmProp opt = target->Target->GetMakefile()->GetDefinition(option_flag);
+ if (!opt) {
+ std::ostringstream e;
+ e << "Target \"" << target->GetName()
+ << "\" requires the language "
+ "dialect \""
+ << this->Language << *standardProp << "\" "
+ << (ext ? "(with compiler extensions)" : "")
+ << ", but CMake "
+ "does not know the compile flags to use to enable it.";
+ makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ }
+ return option_flag;
+ }
+
+ std::string standardStr(*standardProp);
+ if (this->Language == "CUDA" && standardStr == "98") {
+ standardStr = "03";
+ }
+
+ auto stdIt =
+ std::find(cm::cbegin(stds), cm::cend(stds), ParseStd(standardStr));
+ if (stdIt == cm::cend(stds)) {
+ std::string e =
+ cmStrCat(this->Language, "_STANDARD is set to invalid value '",
+ standardStr, "'");
+ makefile->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e,
+ target->GetBacktrace());
+ return std::string{};
+ }
+
+ auto defaultStdIt =
+ std::find(cm::cbegin(stds), cm::cend(stds), ParseStd(*defaultStd));
+ if (defaultStdIt == cm::cend(stds)) {
+ std::string e = cmStrCat("CMAKE_", this->Language,
+ "_STANDARD_DEFAULT is set to invalid value '",
+ *defaultStd, "'");
+ makefile->IssueMessage(MessageType::INTERNAL_ERROR, e);
+ return std::string{};
+ }
+
+ // If the standard requested is older than the compiler's default
+ // then we need to use a flag to change it.
+ if (stdIt <= defaultStdIt) {
+ auto offset = std::distance(cm::cbegin(stds), stdIt);
+ return cmStrCat("CMAKE_", this->Language, stdsStrings[offset], "_", type,
+ "_COMPILE_OPTION");
+ }
+
+ // The standard requested is at least as new as the compiler's default,
+ // and the standard request is not required. Decay to the newest standard
+ // for which a flag is defined.
+ for (; defaultStdIt < stdIt; --stdIt) {
+ auto offset = std::distance(cm::cbegin(stds), stdIt);
+ std::string option_flag =
+ cmStrCat("CMAKE_", this->Language, stdsStrings[offset], "_", type,
+ "_COMPILE_OPTION");
+ if (target->Target->GetMakefile()->GetDefinition(option_flag)) {
+ return option_flag;
+ }
+ }
+
+ return std::string{};
+ }
+
+ bool GetNewRequiredStandard(cmMakefile* makefile,
+ std::string const& targetName,
+ const std::string& feature,
+ cmProp currentLangStandardValue,
+ std::string& newRequiredStandard,
+ std::string* error) const
+ {
+ if (currentLangStandardValue) {
+ newRequiredStandard = *currentLangStandardValue;
+ } else {
+ newRequiredStandard.clear();
+ }
+
+ auto needed = this->HighestStandardNeeded(makefile, feature);
+
+ cmProp existingStandard = currentLangStandardValue;
+ if (existingStandard == nullptr) {
+ cmProp defaultStandard = makefile->GetDefinition(
+ cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT"));
+ if (cmNonempty(defaultStandard)) {
+ existingStandard = defaultStandard;
+ }
+ }
+
+ auto existingLevelIter = cm::cend(this->Levels);
+ if (existingStandard) {
+ existingLevelIter =
+ std::find(cm::cbegin(this->Levels), cm::cend(this->Levels),
+ ParseStd(*existingStandard));
+ if (existingLevelIter == cm::cend(this->Levels)) {
+ const std::string e =
+ cmStrCat("The ", this->Language, "_STANDARD property on target \"",
+ targetName, "\" contained an invalid value: \"",
+ *existingStandard, "\".");
+ if (error) {
+ *error = e;
+ } else {
+ makefile->IssueMessage(MessageType::FATAL_ERROR, e);
+ }
+ return false;
+ }
+ }
+
+ if (needed.index != -1) {
+ // Ensure the C++ language level is high enough to support
+ // the needed C++ features.
+ if (existingLevelIter == cm::cend(this->Levels) ||
+ existingLevelIter < this->Levels.begin() + needed.index) {
+ newRequiredStandard = this->LevelsAsStrings[needed.index];
+ }
+ }
+
+ return true;
+ }
+
+ bool HaveStandardAvailable(cmMakefile* makefile,
+ cmGeneratorTarget const* target,
+ std::string const& config,
+ std::string const& feature) const
+ {
+ cmProp defaultStandard = makefile->GetDefinition(
+ cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT"));
+ if (!defaultStandard) {
+ makefile->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("CMAKE_", this->Language,
+ "_STANDARD_DEFAULT is not set. COMPILE_FEATURES support "
+ "not fully configured for this compiler."));
+ // Return true so the caller does not try to lookup the default standard.
+ return true;
+ }
+ // convert defaultStandard to an integer
+ if (std::find(cm::cbegin(this->Levels), cm::cend(this->Levels),
+ ParseStd(*defaultStandard)) == cm::cend(this->Levels)) {
+ const std::string e = cmStrCat("The CMAKE_", this->Language,
+ "_STANDARD_DEFAULT variable contains an "
+ "invalid value: \"",
+ *defaultStandard, "\".");
+ makefile->IssueMessage(MessageType::INTERNAL_ERROR, e);
+ return false;
+ }
+
+ cmProp existingStandard =
+ target->GetLanguageStandard(this->Language, config);
+ if (!existingStandard) {
+ existingStandard = defaultStandard;
+ }
+
+ auto existingLevelIter =
+ std::find(cm::cbegin(this->Levels), cm::cend(this->Levels),
+ ParseStd(*existingStandard));
+ if (existingLevelIter == cm::cend(this->Levels)) {
+ const std::string e =
+ cmStrCat("The ", this->Language, "_STANDARD property on target \"",
+ target->GetName(), "\" contained an invalid value: \"",
+ *existingStandard, "\".");
+ makefile->IssueMessage(MessageType::FATAL_ERROR, e);
+ return false;
+ }
+
+ auto needed = this->HighestStandardNeeded(makefile, feature);
+
+ return (needed.index == -1) ||
+ (this->Levels.begin() + needed.index) <= existingLevelIter;
+ }
+
+ StandardNeeded HighestStandardNeeded(cmMakefile* makefile,
+ std::string const& feature) const
+ {
+ std::string prefix = cmStrCat("CMAKE_", this->Language);
+ StandardNeeded maxLevel = { -1, -1 };
+ for (size_t i = 0; i < this->Levels.size(); ++i) {
+ if (cmProp prop = makefile->GetDefinition(
+ cmStrCat(prefix, this->LevelsAsStrings[i], "_COMPILE_FEATURES"))) {
+ std::vector<std::string> props = cmExpandedList(*prop);
+ if (cm::contains(props, feature)) {
+ maxLevel = { static_cast<int>(i), this->Levels[i] };
+ }
+ }
+ }
+ return maxLevel;
+ }
+
+ bool IsLaterStandard(int lhs, int rhs) const
+ {
+ auto rhsIt =
+ std::find(cm::cbegin(this->Levels), cm::cend(this->Levels), rhs);
+
+ return std::find(rhsIt, cm::cend(this->Levels), lhs) !=
+ cm::cend(this->Levels);
+ }
+
+ std::string Language;
+ std::vector<int> Levels;
+ std::vector<std::string> LevelsAsStrings;
+};
+
+std::unordered_map<std::string, StanardLevelComputer> StandardComputerMapping =
+ {
+ { "C",
+ StanardLevelComputer{
+ "C", std::vector<int>{ 90, 99, 11, 17, 23 },
+ std::vector<std::string>{ "90", "99", "11", "17", "23" } } },
+ { "CXX",
+ StanardLevelComputer{
+ "CXX", std::vector<int>{ 98, 11, 14, 17, 20, 23 },
+ std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } },
+ { "CUDA",
+ StanardLevelComputer{
+ "CUDA", std::vector<int>{ 03, 11, 14, 17, 20, 23 },
+ std::vector<std::string>{ "03", "11", "14", "17", "20", "23" } } },
+ { "OBJC",
+ StanardLevelComputer{ "OBJC", std::vector<int>{ 90, 99, 11 },
+ std::vector<std::string>{ "90", "99", "11" } } },
+ { "OBJCXX",
+ StanardLevelComputer{
+ "OBJCXX", std::vector<int>{ 98, 11, 14, 17, 20, 23 },
+ std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } },
+ };
+}
+
+std::string cmStandardLevelResolver::GetCompileOptionDef(
+ cmGeneratorTarget const* target, std::string const& lang,
+ std::string const& config) const
+{
+ const auto& mapping = StandardComputerMapping.find(lang);
+ if (mapping == cm::cend(StandardComputerMapping)) {
+ return std::string{};
+ }
+
+ return mapping->second.GetCompileOptionDef(this->Makefile, target, config);
+}
+
+bool cmStandardLevelResolver::AddRequiredTargetFeature(
+ cmTarget* target, const std::string& feature, std::string* error) const
+{
+ if (cmGeneratorExpression::Find(feature) != std::string::npos) {
+ target->AppendProperty("COMPILE_FEATURES", feature);
+ return true;
+ }
+
+ std::string lang;
+ if (!this->CheckCompileFeaturesAvailable(target->GetName(), feature, lang,
+ error)) {
+ return false;
+ }
+
+ target->AppendProperty("COMPILE_FEATURES", feature);
+
+ // FIXME: Add a policy to avoid updating the <LANG>_STANDARD target
+ // property due to COMPILE_FEATURES. The language standard selection
+ // should be done purely at generate time based on whatever the project
+ // code put in these properties explicitly. That is mostly true now,
+ // but for compatibility we need to continue updating the property here.
+ std::string newRequiredStandard;
+ bool newRequired = this->GetNewRequiredStandard(
+ target->GetName(), feature,
+ target->GetProperty(cmStrCat(lang, "_STANDARD")), newRequiredStandard,
+ error);
+ if (!newRequiredStandard.empty()) {
+ target->SetProperty(cmStrCat(lang, "_STANDARD"), newRequiredStandard);
+ }
+ return newRequired;
+}
+
+bool cmStandardLevelResolver::CheckCompileFeaturesAvailable(
+ const std::string& targetName, const std::string& feature, std::string& lang,
+ std::string* error) const
+{
+ if (!this->CompileFeatureKnown(targetName, feature, lang, error)) {
+ return false;
+ }
+
+ const char* features = this->CompileFeaturesAvailable(lang, error);
+ if (!features) {
+ return false;
+ }
+
+ std::vector<std::string> availableFeatures = cmExpandedList(features);
+ if (!cm::contains(availableFeatures, feature)) {
+ std::ostringstream e;
+ e << "The compiler feature \"" << feature << "\" is not known to " << lang
+ << " compiler\n\""
+ << this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_ID")
+ << "\"\nversion "
+ << this->Makefile->GetSafeDefinition("CMAKE_" + lang +
+ "_COMPILER_VERSION")
+ << ".";
+ if (error) {
+ *error = e.str();
+ } else {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool cmStandardLevelResolver::CompileFeatureKnown(
+ const std::string& targetName, const std::string& feature, std::string& lang,
+ std::string* error) const
+{
+ assert(cmGeneratorExpression::Find(feature) == std::string::npos);
+
+ bool isCFeature =
+ std::find_if(cm::cbegin(C_FEATURES) + 1, cm::cend(C_FEATURES),
+ cmStrCmp(feature)) != cm::cend(C_FEATURES);
+ if (isCFeature) {
+ lang = "C";
+ return true;
+ }
+ bool isCxxFeature =
+ std::find_if(cm::cbegin(CXX_FEATURES) + 1, cm::cend(CXX_FEATURES),
+ cmStrCmp(feature)) != cm::cend(CXX_FEATURES);
+ if (isCxxFeature) {
+ lang = "CXX";
+ return true;
+ }
+ bool isCudaFeature =
+ std::find_if(cm::cbegin(CUDA_FEATURES) + 1, cm::cend(CUDA_FEATURES),
+ cmStrCmp(feature)) != cm::cend(CUDA_FEATURES);
+ if (isCudaFeature) {
+ lang = "CUDA";
+ return true;
+ }
+ std::ostringstream e;
+ if (error) {
+ e << "specified";
+ } else {
+ e << "Specified";
+ }
+ e << " unknown feature \"" << feature
+ << "\" for "
+ "target \""
+ << targetName << "\".";
+ if (error) {
+ *error = e.str();
+ } else {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ }
+ return false;
+}
+
+const char* cmStandardLevelResolver::CompileFeaturesAvailable(
+ const std::string& lang, std::string* error) const
+{
+ if (!this->Makefile->GetGlobalGenerator()->GetLanguageEnabled(lang)) {
+ std::ostringstream e;
+ if (error) {
+ e << "cannot";
+ } else {
+ e << "Cannot";
+ }
+ e << " use features from non-enabled language " << lang;
+ if (error) {
+ *error = e.str();
+ } else {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ }
+ return nullptr;
+ }
+
+ cmProp featuresKnown =
+ this->Makefile->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES");
+
+ if (!cmNonempty(featuresKnown)) {
+ std::ostringstream e;
+ if (error) {
+ e << "no";
+ } else {
+ e << "No";
+ }
+ e << " known features for " << lang << " compiler\n\""
+ << this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_ID")
+ << "\"\nversion "
+ << this->Makefile->GetSafeDefinition("CMAKE_" + lang +
+ "_COMPILER_VERSION")
+ << ".";
+ if (error) {
+ *error = e.str();
+ } else {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ }
+ return nullptr;
+ }
+ return cmToCStr(featuresKnown);
+}
+
+bool cmStandardLevelResolver::GetNewRequiredStandard(
+ const std::string& targetName, const std::string& feature,
+ cmProp currentLangStandardValue, std::string& newRequiredStandard,
+ std::string* error) const
+{
+ std::string lang;
+ if (!this->CheckCompileFeaturesAvailable(targetName, feature, lang, error)) {
+ return false;
+ }
+
+ auto mapping = StandardComputerMapping.find(lang);
+ if (mapping != cm::cend(StandardComputerMapping)) {
+ return mapping->second.GetNewRequiredStandard(
+ this->Makefile, targetName, feature, currentLangStandardValue,
+ newRequiredStandard, error);
+ }
+ return false;
+}
+
+bool cmStandardLevelResolver::HaveStandardAvailable(
+ cmGeneratorTarget const* target, std::string const& lang,
+ std::string const& config, const std::string& feature) const
+{
+ auto mapping = StandardComputerMapping.find(lang);
+ if (mapping != cm::cend(StandardComputerMapping)) {
+ return mapping->second.HaveStandardAvailable(this->Makefile, target,
+ config, feature);
+ }
+ return false;
+}
+
+bool cmStandardLevelResolver::IsLaterStandard(std::string const& lang,
+ std::string const& lhs,
+ std::string const& rhs) const
+{
+ auto mapping = StandardComputerMapping.find(lang);
+ if (mapping != cm::cend(StandardComputerMapping)) {
+ return mapping->second.IsLaterStandard(std::stoi(lhs), std::stoi(rhs));
+ }
+ return false;
+}
diff --git a/Source/cmStandardLevelResolver.h b/Source/cmStandardLevelResolver.h
new file mode 100644
index 0000000..d84fbcb
--- /dev/null
+++ b/Source/cmStandardLevelResolver.h
@@ -0,0 +1,57 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+
+#include "cmProperty.h"
+
+class cmMakefile;
+class cmGeneratorTarget;
+class cmTarget;
+
+class cmStandardLevelResolver
+{
+
+public:
+ explicit cmStandardLevelResolver(cmMakefile* makefile)
+ : Makefile(makefile)
+ {
+ }
+
+ std::string GetCompileOptionDef(cmGeneratorTarget const* target,
+ std::string const& lang,
+ std::string const& config) const;
+
+ bool AddRequiredTargetFeature(cmTarget* target, const std::string& feature,
+ std::string* error = nullptr) const;
+
+ bool CompileFeatureKnown(const std::string& targetName,
+ const std::string& feature, std::string& lang,
+ std::string* error) const;
+
+ const char* CompileFeaturesAvailable(const std::string& lang,
+ std::string* error) const;
+
+ bool GetNewRequiredStandard(const std::string& targetName,
+ const std::string& feature,
+ cmProp currentLangStandardValue,
+ std::string& newRequiredStandard,
+ std::string* error = nullptr) const;
+
+ bool HaveStandardAvailable(cmGeneratorTarget const* target,
+ std::string const& lang,
+ std::string const& config,
+ const std::string& feature) const;
+
+ bool IsLaterStandard(std::string const& lang, std::string const& lhs,
+ std::string const& rhs) const;
+
+private:
+ bool CheckCompileFeaturesAvailable(const std::string& targetName,
+ const std::string& feature,
+ std::string& lang,
+ std::string* error) const;
+
+ cmMakefile* Makefile;
+};
diff --git a/Source/cmStandardLexer.h b/Source/cmStandardLexer.h
new file mode 100644
index 0000000..b871f5f
--- /dev/null
+++ b/Source/cmStandardLexer.h
@@ -0,0 +1,80 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#if defined(__linux)
+/* Needed for glibc < 2.12 */
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
+# define _XOPEN_SOURCE 600
+#endif
+#if !defined(_POSIX_C_SOURCE) && !defined(_WIN32) && !defined(__sun) && \
+ !defined(__OpenBSD__)
+/* POSIX APIs are needed */
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
+# define _POSIX_C_SOURCE 200809L
+#endif
+#if defined(__sun) && defined(__GNUC__) && !defined(__cplusplus)
+/* C sources: for fileno and strdup */
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
+# define _XOPEN_SOURCE 600
+#endif
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+/* For isascii */
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
+# define _XOPEN_SOURCE 700
+#endif
+
+#include "cmsys/Configure.h" // IWYU pragma: keep
+
+/* Disable some warnings. */
+#if defined(_MSC_VER)
+# pragma warning(disable : 4018)
+# pragma warning(disable : 4127)
+# pragma warning(disable : 4131)
+# pragma warning(disable : 4244)
+# pragma warning(disable : 4251)
+# pragma warning(disable : 4267)
+# pragma warning(disable : 4305)
+# pragma warning(disable : 4309)
+# pragma warning(disable : 4706)
+# pragma warning(disable : 4786)
+#endif
+
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
+# if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402
+# pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wsign-compare"
+# endif
+# if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 403
+# pragma GCC diagnostic ignored "-Wsign-conversion"
+# endif
+#endif
+
+/* Make sure isatty is available. */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <io.h>
+# if defined(_MSC_VER)
+# define isatty _isatty
+# endif
+#else
+# include <unistd.h> // IWYU pragma: export
+#endif
+
+/* Make sure malloc and free are available on QNX. */
+#ifdef __QNX__
+# include <malloc.h>
+#endif
+
+/* Disable features we do not need. */
+#define YY_NEVER_INTERACTIVE 1
+#define YY_NO_INPUT 1
+#define YY_NO_UNPUT 1
+#define ECHO
+
+#include <cm3p/kwiml/int.h>
+typedef KWIML_INT_int8_t flex_int8_t;
+typedef KWIML_INT_uint8_t flex_uint8_t;
+typedef KWIML_INT_int16_t flex_int16_t;
+typedef KWIML_INT_uint16_t flex_uint16_t;
+typedef KWIML_INT_int32_t flex_int32_t;
+typedef KWIML_INT_uint32_t flex_uint32_t;
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
new file mode 100644
index 0000000..d97762b
--- /dev/null
+++ b/Source/cmState.cxx
@@ -0,0 +1,1072 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmState.h"
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cstdlib>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCacheManager.h"
+#include "cmCommand.h"
+#include "cmDefinitions.h"
+#include "cmExecutionStatus.h"
+#include "cmGlobVerificationManager.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmStatePrivate.h"
+#include "cmStateSnapshot.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+cmState::cmState()
+{
+ this->CacheManager = cm::make_unique<cmCacheManager>();
+ this->GlobVerificationManager = cm::make_unique<cmGlobVerificationManager>();
+}
+
+cmState::~cmState() = default;
+
+const std::string& cmState::GetTargetTypeName(
+ cmStateEnums::TargetType targetType)
+{
+#define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP
+ MAKE_STATIC_PROP(STATIC_LIBRARY);
+ MAKE_STATIC_PROP(MODULE_LIBRARY);
+ MAKE_STATIC_PROP(SHARED_LIBRARY);
+ MAKE_STATIC_PROP(OBJECT_LIBRARY);
+ MAKE_STATIC_PROP(EXECUTABLE);
+ MAKE_STATIC_PROP(UTILITY);
+ MAKE_STATIC_PROP(GLOBAL_TARGET);
+ MAKE_STATIC_PROP(INTERFACE_LIBRARY);
+ MAKE_STATIC_PROP(UNKNOWN_LIBRARY);
+ static const std::string propEmpty;
+#undef MAKE_STATIC_PROP
+
+ switch (targetType) {
+ case cmStateEnums::STATIC_LIBRARY:
+ return propSTATIC_LIBRARY;
+ case cmStateEnums::MODULE_LIBRARY:
+ return propMODULE_LIBRARY;
+ case cmStateEnums::SHARED_LIBRARY:
+ return propSHARED_LIBRARY;
+ case cmStateEnums::OBJECT_LIBRARY:
+ return propOBJECT_LIBRARY;
+ case cmStateEnums::EXECUTABLE:
+ return propEXECUTABLE;
+ case cmStateEnums::UTILITY:
+ return propUTILITY;
+ case cmStateEnums::GLOBAL_TARGET:
+ return propGLOBAL_TARGET;
+ case cmStateEnums::INTERFACE_LIBRARY:
+ return propINTERFACE_LIBRARY;
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ return propUNKNOWN_LIBRARY;
+ }
+ assert(false && "Unexpected target type");
+ return propEmpty;
+}
+
+static const std::array<std::string, 7> cmCacheEntryTypes = {
+ { "BOOL", "PATH", "FILEPATH", "STRING", "INTERNAL", "STATIC",
+ "UNINITIALIZED" }
+};
+
+const std::string& cmState::CacheEntryTypeToString(
+ cmStateEnums::CacheEntryType type)
+{
+ if (type < cmStateEnums::BOOL || type > cmStateEnums::UNINITIALIZED) {
+ type = cmStateEnums::UNINITIALIZED;
+ }
+ return cmCacheEntryTypes[type];
+}
+
+cmStateEnums::CacheEntryType cmState::StringToCacheEntryType(
+ const std::string& s)
+{
+ cmStateEnums::CacheEntryType type = cmStateEnums::STRING;
+ StringToCacheEntryType(s, type);
+ return type;
+}
+
+bool cmState::StringToCacheEntryType(const std::string& s,
+ cmStateEnums::CacheEntryType& type)
+{
+ for (size_t i = 0; i < cmCacheEntryTypes.size(); ++i) {
+ if (s == cmCacheEntryTypes[i]) {
+ type = static_cast<cmStateEnums::CacheEntryType>(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmState::IsCacheEntryType(std::string const& key)
+{
+ return std::any_of(
+ cmCacheEntryTypes.begin(), cmCacheEntryTypes.end(),
+ [&key](std::string const& i) -> bool { return key == i; });
+}
+
+bool cmState::LoadCache(const std::string& path, bool internal,
+ std::set<std::string>& excludes,
+ std::set<std::string>& includes)
+{
+ return this->CacheManager->LoadCache(path, internal, excludes, includes);
+}
+
+bool cmState::SaveCache(const std::string& path, cmMessenger* messenger)
+{
+ return this->CacheManager->SaveCache(path, messenger);
+}
+
+bool cmState::DeleteCache(const std::string& path)
+{
+ return this->CacheManager->DeleteCache(path);
+}
+
+bool cmState::IsCacheLoaded() const
+{
+ return this->CacheManager->IsCacheLoaded();
+}
+
+std::vector<std::string> cmState::GetCacheEntryKeys() const
+{
+ return this->CacheManager->GetCacheEntryKeys();
+}
+
+cmProp cmState::GetCacheEntryValue(std::string const& key) const
+{
+ return this->CacheManager->GetCacheEntryValue(key);
+}
+
+std::string cmState::GetSafeCacheEntryValue(std::string const& key) const
+{
+ if (cmProp val = this->GetCacheEntryValue(key)) {
+ return *val;
+ }
+ return std::string();
+}
+
+cmProp cmState::GetInitializedCacheValue(std::string const& key) const
+{
+ return this->CacheManager->GetInitializedCacheValue(key);
+}
+
+cmStateEnums::CacheEntryType cmState::GetCacheEntryType(
+ std::string const& key) const
+{
+ return this->CacheManager->GetCacheEntryType(key);
+}
+
+void cmState::SetCacheEntryValue(std::string const& key,
+ std::string const& value)
+{
+ this->CacheManager->SetCacheEntryValue(key, value);
+}
+
+void cmState::SetCacheEntryProperty(std::string const& key,
+ std::string const& propertyName,
+ std::string const& value)
+{
+ this->CacheManager->SetCacheEntryProperty(key, propertyName, value);
+}
+
+void cmState::SetCacheEntryBoolProperty(std::string const& key,
+ std::string const& propertyName,
+ bool value)
+{
+ this->CacheManager->SetCacheEntryBoolProperty(key, propertyName, value);
+}
+
+std::vector<std::string> cmState::GetCacheEntryPropertyList(
+ const std::string& key)
+{
+ return this->CacheManager->GetCacheEntryPropertyList(key);
+}
+
+cmProp cmState::GetCacheEntryProperty(std::string const& key,
+ std::string const& propertyName)
+{
+ return this->CacheManager->GetCacheEntryProperty(key, propertyName);
+}
+
+bool cmState::GetCacheEntryPropertyAsBool(std::string const& key,
+ std::string const& propertyName)
+{
+ return this->CacheManager->GetCacheEntryPropertyAsBool(key, propertyName);
+}
+
+void cmState::AddCacheEntry(const std::string& key, const char* value,
+ const char* helpString,
+ cmStateEnums::CacheEntryType type)
+{
+ this->CacheManager->AddCacheEntry(key, value, helpString, type);
+}
+
+bool cmState::DoWriteGlobVerifyTarget() const
+{
+ return this->GlobVerificationManager->DoWriteVerifyTarget();
+}
+
+std::string const& cmState::GetGlobVerifyScript() const
+{
+ return this->GlobVerificationManager->GetVerifyScript();
+}
+
+std::string const& cmState::GetGlobVerifyStamp() const
+{
+ return this->GlobVerificationManager->GetVerifyStamp();
+}
+
+bool cmState::SaveVerificationScript(const std::string& path)
+{
+ return this->GlobVerificationManager->SaveVerificationScript(path);
+}
+
+void cmState::AddGlobCacheEntry(bool recurse, bool listDirectories,
+ bool followSymlinks,
+ const std::string& relative,
+ const std::string& expression,
+ const std::vector<std::string>& files,
+ const std::string& variable,
+ cmListFileBacktrace const& backtrace)
+{
+ this->GlobVerificationManager->AddCacheEntry(
+ recurse, listDirectories, followSymlinks, relative, expression, files,
+ variable, backtrace);
+}
+
+void cmState::RemoveCacheEntry(std::string const& key)
+{
+ this->CacheManager->RemoveCacheEntry(key);
+}
+
+void cmState::AppendCacheEntryProperty(const std::string& key,
+ const std::string& property,
+ const std::string& value, bool asString)
+{
+ this->CacheManager->AppendCacheEntryProperty(key, property, value, asString);
+}
+
+void cmState::RemoveCacheEntryProperty(std::string const& key,
+ std::string const& propertyName)
+{
+ this->CacheManager->RemoveCacheEntryProperty(key, propertyName);
+}
+
+cmStateSnapshot cmState::Reset()
+{
+ this->GlobalProperties.Clear();
+ this->PropertyDefinitions = {};
+ this->GlobVerificationManager->Reset();
+
+ cmStateDetail::PositionType pos = this->SnapshotData.Truncate();
+ this->ExecutionListFiles.Truncate();
+
+ {
+ cmLinkedTree<cmStateDetail::BuildsystemDirectoryStateType>::iterator it =
+ this->BuildsystemDirectory.Truncate();
+ it->IncludeDirectories.clear();
+ it->IncludeDirectoryBacktraces.clear();
+ it->CompileDefinitions.clear();
+ it->CompileDefinitionsBacktraces.clear();
+ it->CompileOptions.clear();
+ it->CompileOptionsBacktraces.clear();
+ it->LinkOptions.clear();
+ it->LinkOptionsBacktraces.clear();
+ it->LinkDirectories.clear();
+ it->LinkDirectoriesBacktraces.clear();
+ it->DirectoryEnd = pos;
+ it->NormalTargetNames.clear();
+ it->Properties.Clear();
+ it->Children.clear();
+ }
+
+ this->PolicyStack.Clear();
+ pos->Policies = this->PolicyStack.Root();
+ pos->PolicyRoot = this->PolicyStack.Root();
+ pos->PolicyScope = this->PolicyStack.Root();
+ assert(pos->Policies.IsValid());
+ assert(pos->PolicyRoot.IsValid());
+
+ {
+ std::string srcDir =
+ *cmDefinitions::Get("CMAKE_SOURCE_DIR", pos->Vars, pos->Root);
+ std::string binDir =
+ *cmDefinitions::Get("CMAKE_BINARY_DIR", pos->Vars, pos->Root);
+ this->VarTree.Clear();
+ pos->Vars = this->VarTree.Push(this->VarTree.Root());
+ pos->Parent = this->VarTree.Root();
+ pos->Root = this->VarTree.Root();
+
+ pos->Vars->Set("CMAKE_SOURCE_DIR", srcDir);
+ pos->Vars->Set("CMAKE_BINARY_DIR", binDir);
+ }
+
+ this->DefineProperty("RULE_LAUNCH_COMPILE", cmProperty::DIRECTORY, "", "",
+ true);
+ this->DefineProperty("RULE_LAUNCH_LINK", cmProperty::DIRECTORY, "", "",
+ true);
+ this->DefineProperty("RULE_LAUNCH_CUSTOM", cmProperty::DIRECTORY, "", "",
+ true);
+
+ this->DefineProperty("RULE_LAUNCH_COMPILE", cmProperty::TARGET, "", "",
+ true);
+ this->DefineProperty("RULE_LAUNCH_LINK", cmProperty::TARGET, "", "", true);
+ this->DefineProperty("RULE_LAUNCH_CUSTOM", cmProperty::TARGET, "", "", true);
+
+ return { this, pos };
+}
+
+void cmState::DefineProperty(const std::string& name,
+ cmProperty::ScopeType scope,
+ const std::string& ShortDescription,
+ const std::string& FullDescription, bool chained)
+{
+ this->PropertyDefinitions.DefineProperty(name, scope, ShortDescription,
+ FullDescription, chained);
+}
+
+cmPropertyDefinition const* cmState::GetPropertyDefinition(
+ const std::string& name, cmProperty::ScopeType scope) const
+{
+ return this->PropertyDefinitions.GetPropertyDefinition(name, scope);
+}
+
+bool cmState::IsPropertyChained(const std::string& name,
+ cmProperty::ScopeType scope) const
+{
+ if (const auto* def = this->GetPropertyDefinition(name, scope)) {
+ return def->IsChained();
+ }
+ return false;
+}
+
+void cmState::SetLanguageEnabled(std::string const& l)
+{
+ auto it = std::lower_bound(this->EnabledLanguages.begin(),
+ this->EnabledLanguages.end(), l);
+ if (it == this->EnabledLanguages.end() || *it != l) {
+ this->EnabledLanguages.insert(it, l);
+ }
+}
+
+bool cmState::GetLanguageEnabled(std::string const& l) const
+{
+ return std::binary_search(this->EnabledLanguages.begin(),
+ this->EnabledLanguages.end(), l);
+}
+
+std::vector<std::string> cmState::GetEnabledLanguages() const
+{
+ return this->EnabledLanguages;
+}
+
+void cmState::SetEnabledLanguages(std::vector<std::string> const& langs)
+{
+ this->EnabledLanguages = langs;
+}
+
+void cmState::ClearEnabledLanguages()
+{
+ this->EnabledLanguages.clear();
+}
+
+bool cmState::GetIsInTryCompile() const
+{
+ return this->IsInTryCompile;
+}
+
+void cmState::SetIsInTryCompile(bool b)
+{
+ this->IsInTryCompile = b;
+}
+
+bool cmState::GetIsGeneratorMultiConfig() const
+{
+ return this->IsGeneratorMultiConfig;
+}
+
+void cmState::SetIsGeneratorMultiConfig(bool b)
+{
+ this->IsGeneratorMultiConfig = b;
+}
+
+void cmState::AddBuiltinCommand(std::string const& name,
+ std::unique_ptr<cmCommand> command)
+{
+ this->AddBuiltinCommand(name, cmLegacyCommandWrapper(std::move(command)));
+}
+
+void cmState::AddBuiltinCommand(std::string const& name, Command command)
+{
+ assert(name == cmSystemTools::LowerCase(name));
+ assert(this->BuiltinCommands.find(name) == this->BuiltinCommands.end());
+ this->BuiltinCommands.emplace(name, std::move(command));
+}
+
+static bool InvokeBuiltinCommand(cmState::BuiltinCommand command,
+ std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status)
+{
+ cmMakefile& mf = status.GetMakefile();
+ std::vector<std::string> expandedArguments;
+ if (!mf.ExpandArguments(args, expandedArguments)) {
+ // There was an error expanding arguments. It was already
+ // reported, so we can skip this command without error.
+ return true;
+ }
+ return command(expandedArguments, status);
+}
+
+void cmState::AddBuiltinCommand(std::string const& name,
+ BuiltinCommand command)
+{
+ this->AddBuiltinCommand(
+ name,
+ [command](const std::vector<cmListFileArgument>& args,
+ cmExecutionStatus& status) -> bool {
+ return InvokeBuiltinCommand(command, args, status);
+ });
+}
+
+void cmState::AddFlowControlCommand(std::string const& name, Command command)
+{
+ this->FlowControlCommands.insert(name);
+ this->AddBuiltinCommand(name, std::move(command));
+}
+
+void cmState::AddFlowControlCommand(std::string const& name,
+ BuiltinCommand command)
+{
+ this->FlowControlCommands.insert(name);
+ this->AddBuiltinCommand(name, command);
+}
+
+void cmState::AddDisallowedCommand(std::string const& name,
+ BuiltinCommand command,
+ cmPolicies::PolicyID policy,
+ const char* message)
+{
+ this->AddBuiltinCommand(
+ name,
+ [command, policy, message](const std::vector<cmListFileArgument>& args,
+ cmExecutionStatus& status) -> bool {
+ cmMakefile& mf = status.GetMakefile();
+ switch (mf.GetPolicyStatus(policy)) {
+ case cmPolicies::WARN:
+ mf.IssueMessage(MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(policy));
+ break;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ mf.IssueMessage(MessageType::FATAL_ERROR, message);
+ return true;
+ }
+ return InvokeBuiltinCommand(command, args, status);
+ });
+}
+
+void cmState::AddUnexpectedCommand(std::string const& name, const char* error)
+{
+ this->AddFlowControlCommand(
+ name,
+ [name, error](std::vector<cmListFileArgument> const&,
+ cmExecutionStatus& status) -> bool {
+ cmProp versionValue =
+ status.GetMakefile().GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION");
+ if (name == "endif" &&
+ (!versionValue || atof(versionValue->c_str()) <= 1.4)) {
+ return true;
+ }
+ status.SetError(error);
+ return false;
+ });
+}
+
+bool cmState::AddScriptedCommand(std::string const& name, BT<Command> command,
+ cmMakefile& mf)
+{
+ std::string sName = cmSystemTools::LowerCase(name);
+
+ if (this->FlowControlCommands.count(sName)) {
+ mf.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Built-in flow control command \"", sName,
+ "\" cannot be overridden."),
+ command.Backtrace);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ // if the command already exists, give a new name to the old command.
+ if (Command oldCmd = this->GetCommandByExactName(sName)) {
+ this->ScriptedCommands["_" + sName] = oldCmd;
+ }
+
+ this->ScriptedCommands[sName] = std::move(command.Value);
+ return true;
+}
+
+cmState::Command cmState::GetCommand(std::string const& name) const
+{
+ return this->GetCommandByExactName(cmSystemTools::LowerCase(name));
+}
+
+cmState::Command cmState::GetCommandByExactName(std::string const& name) const
+{
+ auto pos = this->ScriptedCommands.find(name);
+ if (pos != this->ScriptedCommands.end()) {
+ return pos->second;
+ }
+ pos = this->BuiltinCommands.find(name);
+ if (pos != this->BuiltinCommands.end()) {
+ return pos->second;
+ }
+ return nullptr;
+}
+
+std::vector<std::string> cmState::GetCommandNames() const
+{
+ std::vector<std::string> commandNames;
+ commandNames.reserve(this->BuiltinCommands.size() +
+ this->ScriptedCommands.size());
+ for (auto const& bc : this->BuiltinCommands) {
+ commandNames.push_back(bc.first);
+ }
+ for (auto const& sc : this->ScriptedCommands) {
+ commandNames.push_back(sc.first);
+ }
+ std::sort(commandNames.begin(), commandNames.end());
+ commandNames.erase(std::unique(commandNames.begin(), commandNames.end()),
+ commandNames.end());
+ return commandNames;
+}
+
+void cmState::RemoveBuiltinCommand(std::string const& name)
+{
+ assert(name == cmSystemTools::LowerCase(name));
+ this->BuiltinCommands.erase(name);
+}
+
+void cmState::RemoveUserDefinedCommands()
+{
+ this->ScriptedCommands.clear();
+}
+
+void cmState::SetGlobalProperty(const std::string& prop, const char* value)
+{
+ this->GlobalProperties.SetProperty(prop, value);
+}
+
+void cmState::AppendGlobalProperty(const std::string& prop,
+ const std::string& value, bool asString)
+{
+ this->GlobalProperties.AppendProperty(prop, value, asString);
+}
+
+cmProp cmState::GetGlobalProperty(const std::string& prop)
+{
+ if (prop == "CACHE_VARIABLES") {
+ std::vector<std::string> cacheKeys = this->GetCacheEntryKeys();
+ this->SetGlobalProperty("CACHE_VARIABLES", cmJoin(cacheKeys, ";").c_str());
+ } else if (prop == "COMMANDS") {
+ std::vector<std::string> commands = this->GetCommandNames();
+ this->SetGlobalProperty("COMMANDS", cmJoin(commands, ";").c_str());
+ } else if (prop == "IN_TRY_COMPILE") {
+ this->SetGlobalProperty("IN_TRY_COMPILE",
+ this->IsInTryCompile ? "1" : "0");
+ } else if (prop == "GENERATOR_IS_MULTI_CONFIG") {
+ this->SetGlobalProperty("GENERATOR_IS_MULTI_CONFIG",
+ this->IsGeneratorMultiConfig ? "1" : "0");
+ } else if (prop == "ENABLED_LANGUAGES") {
+ std::string langs;
+ langs = cmJoin(this->EnabledLanguages, ";");
+ this->SetGlobalProperty("ENABLED_LANGUAGES", langs.c_str());
+ } else if (prop == "CMAKE_ROLE") {
+ std::string mode = this->GetModeString();
+ this->SetGlobalProperty("CMAKE_ROLE", mode.c_str());
+ }
+#define STRING_LIST_ELEMENT(F) ";" #F
+ if (prop == "CMAKE_C_KNOWN_FEATURES") {
+ static const std::string s_out(
+ &FOR_EACH_C_FEATURE(STRING_LIST_ELEMENT)[1]);
+ return &s_out;
+ }
+ if (prop == "CMAKE_C90_KNOWN_FEATURES") {
+ static const std::string s_out(
+ &FOR_EACH_C90_FEATURE(STRING_LIST_ELEMENT)[1]);
+ return &s_out;
+ }
+ if (prop == "CMAKE_C99_KNOWN_FEATURES") {
+ static const std::string s_out(
+ &FOR_EACH_C99_FEATURE(STRING_LIST_ELEMENT)[1]);
+ return &s_out;
+ }
+ if (prop == "CMAKE_C11_KNOWN_FEATURES") {
+ static const std::string s_out(
+ &FOR_EACH_C11_FEATURE(STRING_LIST_ELEMENT)[1]);
+ return &s_out;
+ }
+ if (prop == "CMAKE_CXX_KNOWN_FEATURES") {
+ static const std::string s_out(
+ &FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT)[1]);
+ return &s_out;
+ }
+ if (prop == "CMAKE_CXX98_KNOWN_FEATURES") {
+ static const std::string s_out(
+ &FOR_EACH_CXX98_FEATURE(STRING_LIST_ELEMENT)[1]);
+ return &s_out;
+ }
+ if (prop == "CMAKE_CXX11_KNOWN_FEATURES") {
+ static const std::string s_out(
+ &FOR_EACH_CXX11_FEATURE(STRING_LIST_ELEMENT)[1]);
+ return &s_out;
+ }
+ if (prop == "CMAKE_CXX14_KNOWN_FEATURES") {
+ static const std::string s_out(
+ &FOR_EACH_CXX14_FEATURE(STRING_LIST_ELEMENT)[1]);
+ return &s_out;
+ }
+ if (prop == "CMAKE_CUDA_KNOWN_FEATURES") {
+ static const std::string s_out(
+ &FOR_EACH_CUDA_FEATURE(STRING_LIST_ELEMENT)[1]);
+ return &s_out;
+ }
+
+#undef STRING_LIST_ELEMENT
+ return this->GlobalProperties.GetPropertyValue(prop);
+}
+
+bool cmState::GetGlobalPropertyAsBool(const std::string& prop)
+{
+ return cmIsOn(this->GetGlobalProperty(prop));
+}
+
+void cmState::SetSourceDirectory(std::string const& sourceDirectory)
+{
+ this->SourceDirectory = sourceDirectory;
+ cmSystemTools::ConvertToUnixSlashes(this->SourceDirectory);
+}
+
+std::string const& cmState::GetSourceDirectory() const
+{
+ return this->SourceDirectory;
+}
+
+void cmState::SetBinaryDirectory(std::string const& binaryDirectory)
+{
+ this->BinaryDirectory = binaryDirectory;
+ cmSystemTools::ConvertToUnixSlashes(this->BinaryDirectory);
+}
+
+void cmState::SetWindowsShell(bool windowsShell)
+{
+ this->WindowsShell = windowsShell;
+}
+
+bool cmState::UseWindowsShell() const
+{
+ return this->WindowsShell;
+}
+
+void cmState::SetWindowsVSIDE(bool windowsVSIDE)
+{
+ this->WindowsVSIDE = windowsVSIDE;
+}
+
+bool cmState::UseWindowsVSIDE() const
+{
+ return this->WindowsVSIDE;
+}
+
+void cmState::SetGhsMultiIDE(bool ghsMultiIDE)
+{
+ this->GhsMultiIDE = ghsMultiIDE;
+}
+
+bool cmState::UseGhsMultiIDE() const
+{
+ return this->GhsMultiIDE;
+}
+
+void cmState::SetWatcomWMake(bool watcomWMake)
+{
+ this->WatcomWMake = watcomWMake;
+}
+
+bool cmState::UseWatcomWMake() const
+{
+ return this->WatcomWMake;
+}
+
+void cmState::SetMinGWMake(bool minGWMake)
+{
+ this->MinGWMake = minGWMake;
+}
+
+bool cmState::UseMinGWMake() const
+{
+ return this->MinGWMake;
+}
+
+void cmState::SetNMake(bool nMake)
+{
+ this->NMake = nMake;
+}
+
+bool cmState::UseNMake() const
+{
+ return this->NMake;
+}
+
+void cmState::SetMSYSShell(bool mSYSShell)
+{
+ this->MSYSShell = mSYSShell;
+}
+
+bool cmState::UseMSYSShell() const
+{
+ return this->MSYSShell;
+}
+
+void cmState::SetNinjaMulti(bool ninjaMulti)
+{
+ this->NinjaMulti = ninjaMulti;
+}
+
+bool cmState::UseNinjaMulti() const
+{
+ return this->NinjaMulti;
+}
+
+unsigned int cmState::GetCacheMajorVersion() const
+{
+ return this->CacheManager->GetCacheMajorVersion();
+}
+
+unsigned int cmState::GetCacheMinorVersion() const
+{
+ return this->CacheManager->GetCacheMinorVersion();
+}
+
+cmState::Mode cmState::GetMode() const
+{
+ return this->CurrentMode;
+}
+
+std::string cmState::GetModeString() const
+{
+ return ModeToString(this->CurrentMode);
+}
+
+void cmState::SetMode(cmState::Mode mode)
+{
+ this->CurrentMode = mode;
+}
+
+std::string cmState::ModeToString(cmState::Mode mode)
+{
+ switch (mode) {
+ case Project:
+ return "PROJECT";
+ case Script:
+ return "SCRIPT";
+ case FindPackage:
+ return "FIND_PACKAGE";
+ case CTest:
+ return "CTEST";
+ case CPack:
+ return "CPACK";
+ case Unknown:
+ return "UNKNOWN";
+ }
+ return "UNKNOWN";
+}
+
+std::string const& cmState::GetBinaryDirectory() const
+{
+ return this->BinaryDirectory;
+}
+
+cmStateSnapshot cmState::CreateBaseSnapshot()
+{
+ cmStateDetail::PositionType pos =
+ this->SnapshotData.Push(this->SnapshotData.Root());
+ pos->DirectoryParent = this->SnapshotData.Root();
+ pos->ScopeParent = this->SnapshotData.Root();
+ pos->SnapshotType = cmStateEnums::BaseType;
+ pos->Keep = true;
+ pos->BuildSystemDirectory =
+ this->BuildsystemDirectory.Push(this->BuildsystemDirectory.Root());
+ pos->ExecutionListFile =
+ this->ExecutionListFiles.Push(this->ExecutionListFiles.Root());
+ pos->IncludeDirectoryPosition = 0;
+ pos->CompileDefinitionsPosition = 0;
+ pos->CompileOptionsPosition = 0;
+ pos->LinkOptionsPosition = 0;
+ pos->LinkDirectoriesPosition = 0;
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->Policies = this->PolicyStack.Root();
+ pos->PolicyRoot = this->PolicyStack.Root();
+ pos->PolicyScope = this->PolicyStack.Root();
+ assert(pos->Policies.IsValid());
+ assert(pos->PolicyRoot.IsValid());
+ pos->Vars = this->VarTree.Push(this->VarTree.Root());
+ assert(pos->Vars.IsValid());
+ pos->Parent = this->VarTree.Root();
+ pos->Root = this->VarTree.Root();
+ return { this, pos };
+}
+
+cmStateSnapshot cmState::CreateBuildsystemDirectorySnapshot(
+ cmStateSnapshot const& originSnapshot)
+{
+ assert(originSnapshot.IsValid());
+ cmStateDetail::PositionType pos =
+ this->SnapshotData.Push(originSnapshot.Position);
+ pos->DirectoryParent = originSnapshot.Position;
+ pos->ScopeParent = originSnapshot.Position;
+ pos->SnapshotType = cmStateEnums::BuildsystemDirectoryType;
+ pos->Keep = true;
+ pos->BuildSystemDirectory = this->BuildsystemDirectory.Push(
+ originSnapshot.Position->BuildSystemDirectory);
+ pos->ExecutionListFile =
+ this->ExecutionListFiles.Push(originSnapshot.Position->ExecutionListFile);
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->Policies = originSnapshot.Position->Policies;
+ pos->PolicyRoot = originSnapshot.Position->Policies;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ assert(pos->Policies.IsValid());
+ assert(pos->PolicyRoot.IsValid());
+
+ cmLinkedTree<cmDefinitions>::iterator origin = originSnapshot.Position->Vars;
+ pos->Parent = origin;
+ pos->Root = origin;
+ pos->Vars = this->VarTree.Push(origin);
+
+ cmStateSnapshot snapshot = cmStateSnapshot(this, pos);
+ originSnapshot.Position->BuildSystemDirectory->Children.push_back(snapshot);
+ snapshot.SetDefaultDefinitions();
+ snapshot.InitializeFromParent();
+ snapshot.SetDirectoryDefinitions();
+ 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)
+{
+ cmStateDetail::PositionType pos =
+ this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position);
+ pos->ScopeParent = originSnapshot.Position;
+ pos->SnapshotType = cmStateEnums::FunctionCallType;
+ pos->Keep = false;
+ pos->ExecutionListFile = this->ExecutionListFiles.Push(
+ originSnapshot.Position->ExecutionListFile, fileName);
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ assert(originSnapshot.Position->Vars.IsValid());
+ cmLinkedTree<cmDefinitions>::iterator origin = originSnapshot.Position->Vars;
+ pos->Parent = origin;
+ pos->Vars = this->VarTree.Push(origin);
+ return { this, pos };
+}
+
+cmStateSnapshot cmState::CreateMacroCallSnapshot(
+ cmStateSnapshot const& originSnapshot, std::string const& fileName)
+{
+ cmStateDetail::PositionType pos =
+ this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position);
+ pos->SnapshotType = cmStateEnums::MacroCallType;
+ 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::CreateIncludeFileSnapshot(
+ cmStateSnapshot const& originSnapshot, std::string const& fileName)
+{
+ cmStateDetail::PositionType pos =
+ this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position);
+ pos->SnapshotType = cmStateEnums::IncludeFileType;
+ pos->Keep = true;
+ 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::CreateVariableScopeSnapshot(
+ cmStateSnapshot const& originSnapshot)
+{
+ cmStateDetail::PositionType pos =
+ this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position);
+ pos->ScopeParent = originSnapshot.Position;
+ pos->SnapshotType = cmStateEnums::VariableScopeType;
+ pos->Keep = false;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ assert(originSnapshot.Position->Vars.IsValid());
+
+ cmLinkedTree<cmDefinitions>::iterator origin = originSnapshot.Position->Vars;
+ pos->Parent = origin;
+ pos->Vars = this->VarTree.Push(origin);
+ assert(pos->Vars.IsValid());
+ return { this, pos };
+}
+
+cmStateSnapshot cmState::CreateInlineListFileSnapshot(
+ cmStateSnapshot const& originSnapshot, std::string const& fileName)
+{
+ cmStateDetail::PositionType pos =
+ this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position);
+ pos->SnapshotType = cmStateEnums::InlineListFileType;
+ pos->Keep = true;
+ pos->ExecutionListFile = this->ExecutionListFiles.Push(
+ originSnapshot.Position->ExecutionListFile, fileName);
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ return { this, pos };
+}
+
+cmStateSnapshot cmState::CreatePolicyScopeSnapshot(
+ cmStateSnapshot const& originSnapshot)
+{
+ cmStateDetail::PositionType pos =
+ this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position);
+ pos->SnapshotType = cmStateEnums::PolicyScopeType;
+ pos->Keep = false;
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ return { this, pos };
+}
+
+cmStateSnapshot cmState::Pop(cmStateSnapshot const& originSnapshot)
+{
+ cmStateDetail::PositionType pos = originSnapshot.Position;
+ cmStateDetail::PositionType prevPos = pos;
+ ++prevPos;
+ prevPos->IncludeDirectoryPosition =
+ prevPos->BuildSystemDirectory->IncludeDirectories.size();
+ prevPos->CompileDefinitionsPosition =
+ prevPos->BuildSystemDirectory->CompileDefinitions.size();
+ prevPos->CompileOptionsPosition =
+ prevPos->BuildSystemDirectory->CompileOptions.size();
+ prevPos->LinkOptionsPosition =
+ prevPos->BuildSystemDirectory->LinkOptions.size();
+ prevPos->LinkDirectoriesPosition =
+ prevPos->BuildSystemDirectory->LinkDirectories.size();
+ prevPos->BuildSystemDirectory->DirectoryEnd = prevPos;
+
+ if (!pos->Keep && this->SnapshotData.IsLast(pos)) {
+ if (pos->Vars != prevPos->Vars) {
+ assert(this->VarTree.IsLast(pos->Vars));
+ this->VarTree.Pop(pos->Vars);
+ }
+ if (pos->ExecutionListFile != prevPos->ExecutionListFile) {
+ assert(this->ExecutionListFiles.IsLast(pos->ExecutionListFile));
+ this->ExecutionListFiles.Pop(pos->ExecutionListFile);
+ }
+ this->SnapshotData.Pop(pos);
+ }
+
+ return { this, prevPos };
+}
+
+static bool ParseEntryWithoutType(const std::string& entry, std::string& var,
+ std::string& value)
+{
+ // input line is: key=value
+ static cmsys::RegularExpression reg(
+ "^([^=]*)=(.*[^\r\t ]|[\r\t ]*)[\r\t ]*$");
+ // input line is: "key"=value
+ static cmsys::RegularExpression regQuoted(
+ "^\"([^\"]*)\"=(.*[^\r\t ]|[\r\t ]*)[\r\t ]*$");
+ bool flag = false;
+ if (regQuoted.find(entry)) {
+ var = regQuoted.match(1);
+ value = regQuoted.match(2);
+ flag = true;
+ } else if (reg.find(entry)) {
+ var = reg.match(1);
+ value = reg.match(2);
+ flag = true;
+ }
+
+ // if value is enclosed in single quotes ('foo') then remove them
+ // it is used to enclose trailing space or tab
+ if (flag && value.size() >= 2 && value.front() == '\'' &&
+ value.back() == '\'') {
+ value = value.substr(1, value.size() - 2);
+ }
+
+ return flag;
+}
+
+bool cmState::ParseCacheEntry(const std::string& entry, std::string& var,
+ std::string& value,
+ cmStateEnums::CacheEntryType& type)
+{
+ // input line is: key:type=value
+ static cmsys::RegularExpression reg(
+ "^([^=:]*):([^=]*)=(.*[^\r\t ]|[\r\t ]*)[\r\t ]*$");
+ // input line is: "key":type=value
+ static cmsys::RegularExpression regQuoted(
+ "^\"([^\"]*)\":([^=]*)=(.*[^\r\t ]|[\r\t ]*)[\r\t ]*$");
+ bool flag = false;
+ if (regQuoted.find(entry)) {
+ var = regQuoted.match(1);
+ type = cmState::StringToCacheEntryType(regQuoted.match(2));
+ value = regQuoted.match(3);
+ flag = true;
+ } else if (reg.find(entry)) {
+ var = reg.match(1);
+ type = cmState::StringToCacheEntryType(reg.match(2));
+ value = reg.match(3);
+ flag = true;
+ }
+
+ // if value is enclosed in single quotes ('foo') then remove them
+ // it is used to enclose trailing space or tab
+ if (flag && value.size() >= 2 && value.front() == '\'' &&
+ value.back() == '\'') {
+ value = value.substr(1, value.size() - 2);
+ }
+
+ if (!flag) {
+ return ParseEntryWithoutType(entry, var, value);
+ }
+
+ return flag;
+}
diff --git a/Source/cmState.h b/Source/cmState.h
new file mode 100644
index 0000000..4e41156
--- /dev/null
+++ b/Source/cmState.h
@@ -0,0 +1,260 @@
+/* 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 <functional>
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "cmDefinitions.h"
+#include "cmLinkedTree.h"
+#include "cmListFileCache.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmPropertyDefinition.h"
+#include "cmPropertyMap.h"
+#include "cmStatePrivate.h"
+#include "cmStateTypes.h"
+
+class cmCacheManager;
+class cmCommand;
+class cmGlobVerificationManager;
+class cmMakefile;
+class cmStateSnapshot;
+class cmMessenger;
+class cmExecutionStatus;
+
+class cmState
+{
+ friend class cmStateSnapshot;
+
+public:
+ cmState();
+ ~cmState();
+
+ cmState(const cmState&) = delete;
+ cmState& operator=(const cmState&) = delete;
+
+ enum Mode
+ {
+ Unknown,
+ Project,
+ Script,
+ FindPackage,
+ CTest,
+ CPack,
+ };
+
+ static const std::string& GetTargetTypeName(
+ cmStateEnums::TargetType targetType);
+
+ 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(
+ cmStateSnapshot const& originSnapshot, std::string const& fileName);
+ cmStateSnapshot CreateIncludeFileSnapshot(
+ cmStateSnapshot const& originSnapshot, std::string const& fileName);
+ cmStateSnapshot CreateVariableScopeSnapshot(
+ cmStateSnapshot const& originSnapshot);
+ cmStateSnapshot CreateInlineListFileSnapshot(
+ cmStateSnapshot const& originSnapshot, std::string const& fileName);
+ cmStateSnapshot CreatePolicyScopeSnapshot(
+ cmStateSnapshot const& originSnapshot);
+ cmStateSnapshot Pop(cmStateSnapshot const& originSnapshot);
+
+ static cmStateEnums::CacheEntryType StringToCacheEntryType(
+ const std::string&);
+ static bool StringToCacheEntryType(const std::string&,
+ cmStateEnums::CacheEntryType& type);
+ static const std::string& CacheEntryTypeToString(
+ cmStateEnums::CacheEntryType);
+ static bool IsCacheEntryType(std::string const& key);
+
+ bool LoadCache(const std::string& path, bool internal,
+ std::set<std::string>& excludes,
+ std::set<std::string>& includes);
+
+ bool SaveCache(const std::string& path, cmMessenger* messenger);
+
+ bool DeleteCache(const std::string& path);
+
+ bool IsCacheLoaded() const;
+
+ std::vector<std::string> GetCacheEntryKeys() const;
+ cmProp GetCacheEntryValue(std::string const& key) const;
+ std::string GetSafeCacheEntryValue(std::string const& key) const;
+ cmProp GetInitializedCacheValue(std::string const& key) const;
+ cmStateEnums::CacheEntryType GetCacheEntryType(std::string const& key) const;
+ void SetCacheEntryValue(std::string const& key, std::string const& value);
+
+ void RemoveCacheEntry(std::string const& key);
+
+ void SetCacheEntryProperty(std::string const& key,
+ std::string const& propertyName,
+ std::string const& value);
+ void SetCacheEntryBoolProperty(std::string const& key,
+ std::string const& propertyName, bool value);
+ std::vector<std::string> GetCacheEntryPropertyList(std::string const& key);
+ cmProp GetCacheEntryProperty(std::string const& key,
+ std::string const& propertyName);
+ bool GetCacheEntryPropertyAsBool(std::string const& key,
+ std::string const& propertyName);
+ void AppendCacheEntryProperty(std::string const& key,
+ const std::string& property,
+ const std::string& value,
+ bool asString = false);
+ void RemoveCacheEntryProperty(std::string const& key,
+ std::string const& propertyName);
+
+ //! Break up a line like VAR:type="value" into var, type and value
+ static bool ParseCacheEntry(const std::string& entry, std::string& var,
+ std::string& value,
+ cmStateEnums::CacheEntryType& type);
+
+ cmStateSnapshot Reset();
+ // Define a property
+ void DefineProperty(const std::string& name, cmProperty::ScopeType scope,
+ const std::string& ShortDescription,
+ const std::string& FullDescription, bool chain = false);
+
+ // get property definition
+ cmPropertyDefinition const* GetPropertyDefinition(
+ const std::string& name, cmProperty::ScopeType scope) const;
+
+ bool IsPropertyChained(const std::string& name,
+ cmProperty::ScopeType scope) const;
+
+ void SetLanguageEnabled(std::string const& l);
+ bool GetLanguageEnabled(std::string const& l) const;
+ std::vector<std::string> GetEnabledLanguages() const;
+ void SetEnabledLanguages(std::vector<std::string> const& langs);
+ void ClearEnabledLanguages();
+
+ bool GetIsInTryCompile() const;
+ void SetIsInTryCompile(bool b);
+
+ bool GetIsGeneratorMultiConfig() const;
+ void SetIsGeneratorMultiConfig(bool b);
+
+ using Command = std::function<bool(std::vector<cmListFileArgument> const&,
+ cmExecutionStatus&)>;
+ using BuiltinCommand = bool (*)(std::vector<std::string> const&,
+ cmExecutionStatus&);
+
+ // Returns a command from its name, case insensitive, or nullptr
+ Command GetCommand(std::string const& name) const;
+ // Returns a command from its name, or nullptr
+ Command GetCommandByExactName(std::string const& name) const;
+
+ void AddBuiltinCommand(std::string const& name,
+ std::unique_ptr<cmCommand> command);
+ void AddBuiltinCommand(std::string const& name, Command command);
+ void AddBuiltinCommand(std::string const& name, BuiltinCommand command);
+ void AddFlowControlCommand(std::string const& name, Command command);
+ void AddFlowControlCommand(std::string const& name, BuiltinCommand command);
+ void AddDisallowedCommand(std::string const& name, BuiltinCommand command,
+ cmPolicies::PolicyID policy, const char* message);
+ void AddUnexpectedCommand(std::string const& name, const char* error);
+ bool AddScriptedCommand(std::string const& name, BT<Command> command,
+ cmMakefile& mf);
+ void RemoveBuiltinCommand(std::string const& name);
+ void RemoveUserDefinedCommands();
+ std::vector<std::string> GetCommandNames() const;
+
+ void SetGlobalProperty(const std::string& prop, const char* value);
+ void AppendGlobalProperty(const std::string& prop, const std::string& value,
+ bool asString = false);
+ cmProp GetGlobalProperty(const std::string& prop);
+ bool GetGlobalPropertyAsBool(const std::string& prop);
+
+ std::string const& GetSourceDirectory() const;
+ void SetSourceDirectory(std::string const& sourceDirectory);
+ std::string const& GetBinaryDirectory() const;
+ void SetBinaryDirectory(std::string const& binaryDirectory);
+
+ void SetWindowsShell(bool windowsShell);
+ bool UseWindowsShell() const;
+ void SetWindowsVSIDE(bool windowsVSIDE);
+ bool UseWindowsVSIDE() const;
+ void SetGhsMultiIDE(bool ghsMultiIDE);
+ bool UseGhsMultiIDE() const;
+ void SetWatcomWMake(bool watcomWMake);
+ bool UseWatcomWMake() const;
+ void SetMinGWMake(bool minGWMake);
+ bool UseMinGWMake() const;
+ void SetNMake(bool nMake);
+ bool UseNMake() const;
+ void SetMSYSShell(bool mSYSShell);
+ bool UseMSYSShell() const;
+ void SetNinjaMulti(bool ninjaMulti);
+ bool UseNinjaMulti() const;
+
+ unsigned int GetCacheMajorVersion() const;
+ unsigned int GetCacheMinorVersion() const;
+
+ Mode GetMode() const;
+ std::string GetModeString() const;
+ void SetMode(Mode mode);
+
+ static std::string ModeToString(Mode mode);
+
+private:
+ friend class cmake;
+ void AddCacheEntry(const std::string& key, const char* value,
+ const char* helpString,
+ cmStateEnums::CacheEntryType type);
+
+ bool DoWriteGlobVerifyTarget() const;
+ std::string const& GetGlobVerifyScript() const;
+ std::string const& GetGlobVerifyStamp() const;
+ bool SaveVerificationScript(const std::string& path);
+ void AddGlobCacheEntry(bool recurse, bool listDirectories,
+ bool followSymlinks, const std::string& relative,
+ const std::string& expression,
+ const std::vector<std::string>& files,
+ const std::string& variable,
+ cmListFileBacktrace const& bt);
+
+ cmPropertyDefinitionMap PropertyDefinitions;
+ std::vector<std::string> EnabledLanguages;
+ std::unordered_map<std::string, Command> BuiltinCommands;
+ std::unordered_map<std::string, Command> ScriptedCommands;
+ std::unordered_set<std::string> FlowControlCommands;
+ cmPropertyMap GlobalProperties;
+ std::unique_ptr<cmCacheManager> CacheManager;
+ std::unique_ptr<cmGlobVerificationManager> GlobVerificationManager;
+
+ cmLinkedTree<cmStateDetail::BuildsystemDirectoryStateType>
+ BuildsystemDirectory;
+
+ cmLinkedTree<std::string> ExecutionListFiles;
+
+ cmLinkedTree<cmStateDetail::PolicyStackEntry> PolicyStack;
+ cmLinkedTree<cmStateDetail::SnapshotDataType> SnapshotData;
+ cmLinkedTree<cmDefinitions> VarTree;
+
+ std::string SourceDirectory;
+ std::string BinaryDirectory;
+ bool IsInTryCompile = false;
+ bool IsGeneratorMultiConfig = false;
+ bool WindowsShell = false;
+ bool WindowsVSIDE = false;
+ bool GhsMultiIDE = false;
+ bool WatcomWMake = false;
+ bool MinGWMake = false;
+ bool NMake = false;
+ bool MSYSShell = false;
+ bool NinjaMulti = false;
+ Mode CurrentMode = Unknown;
+};
diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx
new file mode 100644
index 0000000..7ce362a
--- /dev/null
+++ b/Source/cmStateDirectory.cxx
@@ -0,0 +1,664 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmStateDirectory.h"
+
+#include <algorithm>
+#include <cassert>
+#include <vector>
+
+#include <cm/iterator>
+#include <cmext/algorithm>
+
+#include "cmAlgorithms.h"
+#include "cmProperty.h"
+#include "cmPropertyMap.h"
+#include "cmRange.h"
+#include "cmState.h"
+#include "cmStatePrivate.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
+
+static std::string const kBINARY_DIR = "BINARY_DIR";
+static std::string const kBUILDSYSTEM_TARGETS = "BUILDSYSTEM_TARGETS";
+static std::string const kSOURCE_DIR = "SOURCE_DIR";
+static std::string const kSUBDIRECTORIES = "SUBDIRECTORIES";
+
+void cmStateDirectory::ComputeRelativePathTopSource()
+{
+ // Relative path conversion inside the source tree is not used to
+ // construct relative paths passed to build tools so it is safe to use
+ // even when the source is a network path.
+
+ cmStateSnapshot snapshot = this->Snapshot_;
+ std::vector<cmStateSnapshot> snapshots;
+ snapshots.push_back(snapshot);
+ while (true) {
+ snapshot = snapshot.GetBuildsystemDirectoryParent();
+ if (snapshot.IsValid()) {
+ snapshots.push_back(snapshot);
+ } else {
+ break;
+ }
+ }
+
+ std::string result = snapshots.front().GetDirectory().GetCurrentSource();
+
+ for (cmStateSnapshot const& snp : cmMakeRange(snapshots).advance(1)) {
+ std::string currentSource = snp.GetDirectory().GetCurrentSource();
+ if (cmSystemTools::IsSubDirectory(result, currentSource)) {
+ result = currentSource;
+ }
+ }
+ this->DirectoryState->RelativePathTopSource = result;
+}
+
+void cmStateDirectory::ComputeRelativePathTopBinary()
+{
+ cmStateSnapshot snapshot = this->Snapshot_;
+ std::vector<cmStateSnapshot> snapshots;
+ snapshots.push_back(snapshot);
+ while (true) {
+ snapshot = snapshot.GetBuildsystemDirectoryParent();
+ if (snapshot.IsValid()) {
+ snapshots.push_back(snapshot);
+ } else {
+ break;
+ }
+ }
+
+ std::string result = snapshots.front().GetDirectory().GetCurrentBinary();
+
+ for (cmStateSnapshot const& snp : cmMakeRange(snapshots).advance(1)) {
+ std::string currentBinary = snp.GetDirectory().GetCurrentBinary();
+ if (cmSystemTools::IsSubDirectory(result, currentBinary)) {
+ result = currentBinary;
+ }
+ }
+
+ // The current working directory on Windows cannot be a network
+ // path. Therefore relative paths cannot work when the binary tree
+ // is a network path.
+ if (result.size() < 2 || result.substr(0, 2) != "//") {
+ this->DirectoryState->RelativePathTopBinary = result;
+ } else {
+ this->DirectoryState->RelativePathTopBinary.clear();
+ }
+}
+
+std::string const& cmStateDirectory::GetCurrentSource() const
+{
+ return this->DirectoryState->Location;
+}
+
+void cmStateDirectory::SetCurrentSource(std::string const& dir)
+{
+ std::string& loc = this->DirectoryState->Location;
+ loc = dir;
+ cmSystemTools::ConvertToUnixSlashes(loc);
+ loc = cmSystemTools::CollapseFullPath(loc);
+
+ this->ComputeRelativePathTopSource();
+
+ this->Snapshot_.SetDefinition("CMAKE_CURRENT_SOURCE_DIR", loc);
+}
+
+std::string const& cmStateDirectory::GetCurrentBinary() const
+{
+ return this->DirectoryState->OutputLocation;
+}
+
+void cmStateDirectory::SetCurrentBinary(std::string const& dir)
+{
+ std::string& loc = this->DirectoryState->OutputLocation;
+ loc = dir;
+ cmSystemTools::ConvertToUnixSlashes(loc);
+ loc = cmSystemTools::CollapseFullPath(loc);
+
+ this->ComputeRelativePathTopBinary();
+
+ this->Snapshot_.SetDefinition("CMAKE_CURRENT_BINARY_DIR", loc);
+}
+
+std::string const& cmStateDirectory::GetRelativePathTopSource() const
+{
+ return this->DirectoryState->RelativePathTopSource;
+}
+
+std::string const& cmStateDirectory::GetRelativePathTopBinary() const
+{
+ return this->DirectoryState->RelativePathTopBinary;
+}
+
+void cmStateDirectory::SetRelativePathTopSource(const char* dir)
+{
+ this->DirectoryState->RelativePathTopSource = dir;
+}
+
+void cmStateDirectory::SetRelativePathTopBinary(const char* dir)
+{
+ this->DirectoryState->RelativePathTopBinary = dir;
+}
+
+bool cmStateDirectory::ContainsBoth(std::string const& local_path,
+ std::string const& remote_path) const
+{
+ auto PathEqOrSubDir = [](std::string const& a, std::string const& b) {
+ return (cmSystemTools::ComparePath(a, b) ||
+ cmSystemTools::IsSubDirectory(a, b));
+ };
+
+ bool bothInBinary =
+ PathEqOrSubDir(local_path, this->GetRelativePathTopBinary()) &&
+ PathEqOrSubDir(remote_path, this->GetRelativePathTopBinary());
+
+ bool bothInSource =
+ PathEqOrSubDir(local_path, this->GetRelativePathTopSource()) &&
+ PathEqOrSubDir(remote_path, this->GetRelativePathTopSource());
+
+ return bothInBinary || bothInSource;
+}
+
+std::string cmStateDirectory::ConvertToRelPathIfNotContained(
+ std::string const& local_path, std::string const& remote_path) const
+{
+ if (!this->ContainsBoth(local_path, remote_path)) {
+ return remote_path;
+ }
+ return cmSystemTools::ForceToRelativePath(local_path, remote_path);
+}
+
+cmStateDirectory::cmStateDirectory(
+ cmLinkedTree<cmStateDetail::BuildsystemDirectoryStateType>::iterator iter,
+ const cmStateSnapshot& snapshot)
+ : DirectoryState(iter)
+ , Snapshot_(snapshot)
+{
+}
+
+template <typename T, typename U>
+cmStringRange GetPropertyContent(T const& content, U contentEndPosition)
+{
+ auto end = content.begin() + contentEndPosition;
+
+ auto rbegin = cm::make_reverse_iterator(end);
+ rbegin = std::find(rbegin, content.rend(), cmPropertySentinal);
+
+ return cmMakeRange(rbegin.base(), end);
+}
+
+template <typename T, typename U, typename V>
+cmBacktraceRange GetPropertyBacktraces(T const& content, U const& backtraces,
+ V contentEndPosition)
+{
+ auto entryEnd = content.begin() + contentEndPosition;
+
+ auto rbegin = cm::make_reverse_iterator(entryEnd);
+ rbegin = std::find(rbegin, content.rend(), cmPropertySentinal);
+
+ auto it = backtraces.begin() + std::distance(content.begin(), rbegin.base());
+
+ auto end = backtraces.end();
+ return cmMakeRange(it, end);
+}
+
+template <typename T, typename U, typename V>
+void AppendEntry(T& content, U& backtraces, V& endContentPosition,
+ const std::string& value, const cmListFileBacktrace& lfbt)
+{
+ if (value.empty()) {
+ return;
+ }
+
+ assert(endContentPosition == content.size());
+
+ content.push_back(value);
+ backtraces.push_back(lfbt);
+
+ endContentPosition = content.size();
+}
+
+template <typename T, typename U, typename V>
+void SetContent(T& content, U& backtraces, V& endContentPosition,
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ assert(endContentPosition == content.size());
+
+ content.resize(content.size() + 2);
+ backtraces.resize(backtraces.size() + 2);
+
+ content.back() = vec;
+ backtraces.back() = lfbt;
+
+ endContentPosition = content.size();
+}
+
+template <typename T, typename U, typename V>
+void ClearContent(T& content, U& backtraces, V& endContentPosition)
+{
+ assert(endContentPosition == content.size());
+
+ content.resize(content.size() + 1);
+ backtraces.resize(backtraces.size() + 1);
+
+ endContentPosition = content.size();
+}
+
+cmStringRange cmStateDirectory::GetIncludeDirectoriesEntries() const
+{
+ return GetPropertyContent(
+ this->DirectoryState->IncludeDirectories,
+ this->Snapshot_.Position->IncludeDirectoryPosition);
+}
+
+cmBacktraceRange cmStateDirectory::GetIncludeDirectoriesEntryBacktraces() const
+{
+ return GetPropertyBacktraces(
+ this->DirectoryState->IncludeDirectories,
+ this->DirectoryState->IncludeDirectoryBacktraces,
+ this->Snapshot_.Position->IncludeDirectoryPosition);
+}
+
+void cmStateDirectory::AppendIncludeDirectoriesEntry(
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ AppendEntry(this->DirectoryState->IncludeDirectories,
+ this->DirectoryState->IncludeDirectoryBacktraces,
+ this->Snapshot_.Position->IncludeDirectoryPosition, vec, lfbt);
+}
+
+void cmStateDirectory::PrependIncludeDirectoriesEntry(
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ auto entryEnd = this->DirectoryState->IncludeDirectories.begin() +
+ this->Snapshot_.Position->IncludeDirectoryPosition;
+
+ auto rend = this->DirectoryState->IncludeDirectories.rend();
+ auto rbegin = cm::make_reverse_iterator(entryEnd);
+ rbegin = std::find(rbegin, rend, cmPropertySentinal);
+
+ auto entryIt = rbegin.base();
+ auto entryBegin = this->DirectoryState->IncludeDirectories.begin();
+
+ auto btIt = this->DirectoryState->IncludeDirectoryBacktraces.begin() +
+ std::distance(entryBegin, entryIt);
+
+ this->DirectoryState->IncludeDirectories.insert(entryIt, vec);
+ this->DirectoryState->IncludeDirectoryBacktraces.insert(btIt, lfbt);
+
+ this->Snapshot_.Position->IncludeDirectoryPosition =
+ this->DirectoryState->IncludeDirectories.size();
+}
+
+void cmStateDirectory::SetIncludeDirectories(const std::string& vec,
+ const cmListFileBacktrace& lfbt)
+{
+ SetContent(this->DirectoryState->IncludeDirectories,
+ this->DirectoryState->IncludeDirectoryBacktraces,
+ this->Snapshot_.Position->IncludeDirectoryPosition, vec, lfbt);
+}
+
+void cmStateDirectory::ClearIncludeDirectories()
+{
+ ClearContent(this->DirectoryState->IncludeDirectories,
+ this->DirectoryState->IncludeDirectoryBacktraces,
+ this->Snapshot_.Position->IncludeDirectoryPosition);
+}
+
+cmStringRange cmStateDirectory::GetCompileDefinitionsEntries() const
+{
+ return GetPropertyContent(
+ this->DirectoryState->CompileDefinitions,
+ this->Snapshot_.Position->CompileDefinitionsPosition);
+}
+
+cmBacktraceRange cmStateDirectory::GetCompileDefinitionsEntryBacktraces() const
+{
+ return GetPropertyBacktraces(
+ this->DirectoryState->CompileDefinitions,
+ this->DirectoryState->CompileDefinitionsBacktraces,
+ this->Snapshot_.Position->CompileDefinitionsPosition);
+}
+
+void cmStateDirectory::AppendCompileDefinitionsEntry(
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ AppendEntry(this->DirectoryState->CompileDefinitions,
+ this->DirectoryState->CompileDefinitionsBacktraces,
+ this->Snapshot_.Position->CompileDefinitionsPosition, vec, lfbt);
+}
+
+void cmStateDirectory::SetCompileDefinitions(const std::string& vec,
+ const cmListFileBacktrace& lfbt)
+{
+ SetContent(this->DirectoryState->CompileDefinitions,
+ this->DirectoryState->CompileDefinitionsBacktraces,
+ this->Snapshot_.Position->CompileDefinitionsPosition, vec, lfbt);
+}
+
+void cmStateDirectory::ClearCompileDefinitions()
+{
+ ClearContent(this->DirectoryState->CompileDefinitions,
+ this->DirectoryState->CompileDefinitionsBacktraces,
+ this->Snapshot_.Position->CompileDefinitionsPosition);
+}
+
+cmStringRange cmStateDirectory::GetCompileOptionsEntries() const
+{
+ return GetPropertyContent(this->DirectoryState->CompileOptions,
+ this->Snapshot_.Position->CompileOptionsPosition);
+}
+
+cmBacktraceRange cmStateDirectory::GetCompileOptionsEntryBacktraces() const
+{
+ return GetPropertyBacktraces(
+ this->DirectoryState->CompileOptions,
+ this->DirectoryState->CompileOptionsBacktraces,
+ this->Snapshot_.Position->CompileOptionsPosition);
+}
+
+void cmStateDirectory::AppendCompileOptionsEntry(
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ AppendEntry(this->DirectoryState->CompileOptions,
+ this->DirectoryState->CompileOptionsBacktraces,
+ this->Snapshot_.Position->CompileOptionsPosition, vec, lfbt);
+}
+
+void cmStateDirectory::SetCompileOptions(const std::string& vec,
+ const cmListFileBacktrace& lfbt)
+{
+ SetContent(this->DirectoryState->CompileOptions,
+ this->DirectoryState->CompileOptionsBacktraces,
+ this->Snapshot_.Position->CompileOptionsPosition, vec, lfbt);
+}
+
+void cmStateDirectory::ClearCompileOptions()
+{
+ ClearContent(this->DirectoryState->CompileOptions,
+ this->DirectoryState->CompileOptionsBacktraces,
+ this->Snapshot_.Position->CompileOptionsPosition);
+}
+
+cmStringRange cmStateDirectory::GetLinkOptionsEntries() const
+{
+ return GetPropertyContent(this->DirectoryState->LinkOptions,
+ this->Snapshot_.Position->LinkOptionsPosition);
+}
+
+cmBacktraceRange cmStateDirectory::GetLinkOptionsEntryBacktraces() const
+{
+ return GetPropertyBacktraces(this->DirectoryState->LinkOptions,
+ this->DirectoryState->LinkOptionsBacktraces,
+ this->Snapshot_.Position->LinkOptionsPosition);
+}
+
+void cmStateDirectory::AppendLinkOptionsEntry(const std::string& vec,
+ const cmListFileBacktrace& lfbt)
+{
+ AppendEntry(this->DirectoryState->LinkOptions,
+ this->DirectoryState->LinkOptionsBacktraces,
+ this->Snapshot_.Position->LinkOptionsPosition, vec, lfbt);
+}
+
+void cmStateDirectory::SetLinkOptions(const std::string& vec,
+ const cmListFileBacktrace& lfbt)
+{
+ SetContent(this->DirectoryState->LinkOptions,
+ this->DirectoryState->LinkOptionsBacktraces,
+ this->Snapshot_.Position->LinkOptionsPosition, vec, lfbt);
+}
+
+void cmStateDirectory::ClearLinkOptions()
+{
+ ClearContent(this->DirectoryState->LinkOptions,
+ this->DirectoryState->LinkOptionsBacktraces,
+ this->Snapshot_.Position->LinkOptionsPosition);
+}
+
+cmStringRange cmStateDirectory::GetLinkDirectoriesEntries() const
+{
+ return GetPropertyContent(this->DirectoryState->LinkDirectories,
+ this->Snapshot_.Position->LinkDirectoriesPosition);
+}
+
+cmBacktraceRange cmStateDirectory::GetLinkDirectoriesEntryBacktraces() const
+{
+ return GetPropertyBacktraces(
+ this->DirectoryState->LinkDirectories,
+ this->DirectoryState->LinkDirectoriesBacktraces,
+ this->Snapshot_.Position->LinkDirectoriesPosition);
+}
+
+void cmStateDirectory::AppendLinkDirectoriesEntry(
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ AppendEntry(this->DirectoryState->LinkDirectories,
+ this->DirectoryState->LinkDirectoriesBacktraces,
+ this->Snapshot_.Position->LinkDirectoriesPosition, vec, lfbt);
+}
+void cmStateDirectory::PrependLinkDirectoriesEntry(
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ auto entryEnd = this->DirectoryState->LinkDirectories.begin() +
+ this->Snapshot_.Position->LinkDirectoriesPosition;
+
+ auto rend = this->DirectoryState->LinkDirectories.rend();
+ auto rbegin = cm::make_reverse_iterator(entryEnd);
+ rbegin = std::find(rbegin, rend, cmPropertySentinal);
+
+ auto entryIt = rbegin.base();
+ auto entryBegin = this->DirectoryState->LinkDirectories.begin();
+
+ auto btIt = this->DirectoryState->LinkDirectoriesBacktraces.begin() +
+ std::distance(entryBegin, entryIt);
+
+ this->DirectoryState->LinkDirectories.insert(entryIt, vec);
+ this->DirectoryState->LinkDirectoriesBacktraces.insert(btIt, lfbt);
+
+ this->Snapshot_.Position->LinkDirectoriesPosition =
+ this->DirectoryState->LinkDirectories.size();
+}
+
+void cmStateDirectory::SetLinkDirectories(const std::string& vec,
+ const cmListFileBacktrace& lfbt)
+{
+ SetContent(this->DirectoryState->LinkDirectories,
+ this->DirectoryState->LinkDirectoriesBacktraces,
+ this->Snapshot_.Position->LinkDirectoriesPosition, vec, lfbt);
+}
+
+void cmStateDirectory::ClearLinkDirectories()
+{
+ ClearContent(this->DirectoryState->LinkDirectories,
+ this->DirectoryState->LinkDirectoriesBacktraces,
+ this->Snapshot_.Position->LinkDirectoriesPosition);
+}
+
+void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
+ cmListFileBacktrace const& lfbt)
+{
+ if (prop == "INCLUDE_DIRECTORIES") {
+ if (!value) {
+ this->ClearIncludeDirectories();
+ return;
+ }
+ this->SetIncludeDirectories(value, lfbt);
+ return;
+ }
+ if (prop == "COMPILE_OPTIONS") {
+ if (!value) {
+ this->ClearCompileOptions();
+ return;
+ }
+ this->SetCompileOptions(value, lfbt);
+ return;
+ }
+ if (prop == "COMPILE_DEFINITIONS") {
+ if (!value) {
+ this->ClearCompileDefinitions();
+ return;
+ }
+ this->SetCompileDefinitions(value, lfbt);
+ return;
+ }
+ if (prop == "LINK_OPTIONS") {
+ if (!value) {
+ this->ClearLinkOptions();
+ return;
+ }
+ this->SetLinkOptions(value, lfbt);
+ return;
+ }
+ if (prop == "LINK_DIRECTORIES") {
+ if (!value) {
+ this->ClearLinkDirectories();
+ return;
+ }
+ this->SetLinkDirectories(value, lfbt);
+ return;
+ }
+
+ this->DirectoryState->Properties.SetProperty(prop, value);
+}
+
+void cmStateDirectory::AppendProperty(const std::string& prop,
+ const std::string& value, bool asString,
+ cmListFileBacktrace const& lfbt)
+{
+ if (prop == "INCLUDE_DIRECTORIES") {
+ this->AppendIncludeDirectoriesEntry(value, lfbt);
+ return;
+ }
+ if (prop == "COMPILE_OPTIONS") {
+ this->AppendCompileOptionsEntry(value, lfbt);
+ return;
+ }
+ if (prop == "COMPILE_DEFINITIONS") {
+ this->AppendCompileDefinitionsEntry(value, lfbt);
+ return;
+ }
+ if (prop == "LINK_OPTIONS") {
+ this->AppendLinkOptionsEntry(value, lfbt);
+ return;
+ }
+ if (prop == "LINK_DIRECTORIES") {
+ this->AppendLinkDirectoriesEntry(value, lfbt);
+ return;
+ }
+
+ this->DirectoryState->Properties.AppendProperty(prop, value, asString);
+}
+
+cmProp cmStateDirectory::GetProperty(const std::string& prop) const
+{
+ const bool chain =
+ this->Snapshot_.State->IsPropertyChained(prop, cmProperty::DIRECTORY);
+ return this->GetProperty(prop, chain);
+}
+
+cmProp cmStateDirectory::GetProperty(const std::string& prop, bool chain) const
+{
+ static std::string output;
+ output.clear();
+ if (prop == "PARENT_DIRECTORY") {
+ cmStateSnapshot parent = this->Snapshot_.GetBuildsystemDirectoryParent();
+ if (parent.IsValid()) {
+ return &parent.GetDirectory().GetCurrentSource();
+ }
+ return &output;
+ }
+ if (prop == kBINARY_DIR) {
+ output = this->GetCurrentBinary();
+ return &output;
+ }
+ if (prop == kSOURCE_DIR) {
+ output = this->GetCurrentSource();
+ return &output;
+ }
+ if (prop == kSUBDIRECTORIES) {
+ std::vector<std::string> child_dirs;
+ std::vector<cmStateSnapshot> const& children =
+ this->DirectoryState->Children;
+ child_dirs.reserve(children.size());
+ for (cmStateSnapshot const& ci : children) {
+ child_dirs.push_back(ci.GetDirectory().GetCurrentSource());
+ }
+ output = cmJoin(child_dirs, ";");
+ return &output;
+ }
+ if (prop == kBUILDSYSTEM_TARGETS) {
+ output = cmJoin(this->DirectoryState->NormalTargetNames, ";");
+ return &output;
+ }
+
+ if (prop == "LISTFILE_STACK") {
+ std::vector<std::string> listFiles;
+ cmStateSnapshot snp = this->Snapshot_;
+ while (snp.IsValid()) {
+ listFiles.push_back(snp.GetExecutionListFile());
+ snp = snp.GetCallStackParent();
+ }
+ std::reverse(listFiles.begin(), listFiles.end());
+ output = cmJoin(listFiles, ";");
+ return &output;
+ }
+ if (prop == "CACHE_VARIABLES") {
+ output = cmJoin(this->Snapshot_.State->GetCacheEntryKeys(), ";");
+ return &output;
+ }
+ if (prop == "VARIABLES") {
+ std::vector<std::string> res = this->Snapshot_.ClosureKeys();
+ cm::append(res, this->Snapshot_.State->GetCacheEntryKeys());
+ std::sort(res.begin(), res.end());
+ output = cmJoin(res, ";");
+ return &output;
+ }
+ if (prop == "INCLUDE_DIRECTORIES") {
+ output = cmJoin(this->GetIncludeDirectoriesEntries(), ";");
+ return &output;
+ }
+ if (prop == "COMPILE_OPTIONS") {
+ output = cmJoin(this->GetCompileOptionsEntries(), ";");
+ return &output;
+ }
+ if (prop == "COMPILE_DEFINITIONS") {
+ output = cmJoin(this->GetCompileDefinitionsEntries(), ";");
+ return &output;
+ }
+ if (prop == "LINK_OPTIONS") {
+ output = cmJoin(this->GetLinkOptionsEntries(), ";");
+ return &output;
+ }
+ if (prop == "LINK_DIRECTORIES") {
+ output = cmJoin(this->GetLinkDirectoriesEntries(), ";");
+ return &output;
+ }
+
+ cmProp retVal = this->DirectoryState->Properties.GetPropertyValue(prop);
+ if (!retVal && chain) {
+ cmStateSnapshot parentSnapshot =
+ this->Snapshot_.GetBuildsystemDirectoryParent();
+ if (parentSnapshot.IsValid()) {
+ return parentSnapshot.GetDirectory().GetProperty(prop, chain);
+ }
+ return this->Snapshot_.State->GetGlobalProperty(prop);
+ }
+
+ return retVal;
+}
+
+bool cmStateDirectory::GetPropertyAsBool(const std::string& prop) const
+{
+ return cmIsOn(this->GetProperty(prop));
+}
+
+std::vector<std::string> cmStateDirectory::GetPropertyKeys() const
+{
+ return this->DirectoryState->Properties.GetKeys();
+}
+
+void cmStateDirectory::AddNormalTargetName(std::string const& name)
+{
+ this->DirectoryState->NormalTargetNames.push_back(name);
+}
diff --git a/Source/cmStateDirectory.h b/Source/cmStateDirectory.h
new file mode 100644
index 0000000..70c19bc
--- /dev/null
+++ b/Source/cmStateDirectory.h
@@ -0,0 +1,104 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmAlgorithms.h"
+#include "cmLinkedTree.h"
+#include "cmListFileCache.h"
+#include "cmProperty.h"
+#include "cmStatePrivate.h"
+#include "cmStateSnapshot.h"
+#include "cmStringAlgorithms.h"
+
+class cmStateDirectory
+{
+ cmStateDirectory(
+ cmLinkedTree<cmStateDetail::BuildsystemDirectoryStateType>::iterator iter,
+ cmStateSnapshot const& snapshot);
+
+public:
+ std::string const& GetCurrentSource() const;
+ void SetCurrentSource(std::string const& dir);
+ std::string const& GetCurrentBinary() const;
+ void SetCurrentBinary(std::string const& dir);
+
+ std::string const& GetRelativePathTopSource() const;
+ std::string const& GetRelativePathTopBinary() const;
+ void SetRelativePathTopSource(const char* dir);
+ void SetRelativePathTopBinary(const char* dir);
+
+ bool ContainsBoth(std::string const& local_path,
+ std::string const& remote_path) const;
+
+ std::string ConvertToRelPathIfNotContained(
+ std::string const& local_path, std::string const& remote_path) const;
+
+ cmStringRange GetIncludeDirectoriesEntries() const;
+ cmBacktraceRange GetIncludeDirectoriesEntryBacktraces() const;
+ void AppendIncludeDirectoriesEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void PrependIncludeDirectoriesEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void SetIncludeDirectories(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void ClearIncludeDirectories();
+
+ cmStringRange GetCompileDefinitionsEntries() const;
+ cmBacktraceRange GetCompileDefinitionsEntryBacktraces() const;
+ void AppendCompileDefinitionsEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void SetCompileDefinitions(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void ClearCompileDefinitions();
+
+ cmStringRange GetCompileOptionsEntries() const;
+ cmBacktraceRange GetCompileOptionsEntryBacktraces() const;
+ void AppendCompileOptionsEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void SetCompileOptions(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void ClearCompileOptions();
+
+ cmStringRange GetLinkOptionsEntries() const;
+ cmBacktraceRange GetLinkOptionsEntryBacktraces() const;
+ void AppendLinkOptionsEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void PrependLinkDirectoriesEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void SetLinkOptions(std::string const& vec, cmListFileBacktrace const& lfbt);
+ void ClearLinkOptions();
+
+ cmStringRange GetLinkDirectoriesEntries() const;
+ cmBacktraceRange GetLinkDirectoriesEntryBacktraces() const;
+ void AppendLinkDirectoriesEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void SetLinkDirectories(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void ClearLinkDirectories();
+
+ void SetProperty(const std::string& prop, const char* value,
+ cmListFileBacktrace const& lfbt);
+ void AppendProperty(const std::string& prop, const std::string& value,
+ bool asString, cmListFileBacktrace const& lfbt);
+ cmProp GetProperty(const std::string& prop) const;
+ cmProp GetProperty(const std::string& prop, bool chain) const;
+ bool GetPropertyAsBool(const std::string& prop) const;
+ std::vector<std::string> GetPropertyKeys() const;
+
+ void AddNormalTargetName(std::string const& name);
+
+private:
+ void ComputeRelativePathTopSource();
+ void ComputeRelativePathTopBinary();
+
+ cmLinkedTree<cmStateDetail::BuildsystemDirectoryStateType>::iterator
+ DirectoryState;
+ cmStateSnapshot Snapshot_;
+ friend class cmStateSnapshot;
+};
diff --git a/Source/cmStatePrivate.h b/Source/cmStatePrivate.h
new file mode 100644
index 0000000..4892644
--- /dev/null
+++ b/Source/cmStatePrivate.h
@@ -0,0 +1,100 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmDefinitions.h"
+#include "cmLinkedTree.h"
+#include "cmListFileCache.h"
+#include "cmPolicies.h"
+#include "cmPropertyMap.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+
+namespace cmStateDetail {
+struct BuildsystemDirectoryStateType;
+struct PolicyStackEntry;
+} // namespace cmStateDetail
+
+static const std::string cmPropertySentinal = std::string();
+
+struct cmStateDetail::SnapshotDataType
+{
+ cmStateDetail::PositionType ScopeParent;
+ cmStateDetail::PositionType DirectoryParent;
+ cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator Policies;
+ cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator PolicyRoot;
+ cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator PolicyScope;
+ cmStateEnums::SnapshotType SnapshotType;
+ bool Keep;
+ cmLinkedTree<std::string>::iterator ExecutionListFile;
+ cmLinkedTree<cmStateDetail::BuildsystemDirectoryStateType>::iterator
+ BuildSystemDirectory;
+ cmLinkedTree<cmDefinitions>::iterator Vars;
+ cmLinkedTree<cmDefinitions>::iterator Root;
+ cmLinkedTree<cmDefinitions>::iterator Parent;
+ std::vector<std::string>::size_type IncludeDirectoryPosition;
+ std::vector<std::string>::size_type CompileDefinitionsPosition;
+ std::vector<std::string>::size_type CompileOptionsPosition;
+ std::vector<std::string>::size_type LinkOptionsPosition;
+ std::vector<std::string>::size_type LinkDirectoriesPosition;
+};
+
+struct cmStateDetail::PolicyStackEntry : public cmPolicies::PolicyMap
+{
+ using derived = cmPolicies::PolicyMap;
+ PolicyStackEntry(bool w = false)
+ : Weak(w)
+ {
+ }
+ PolicyStackEntry(derived const& d, bool w)
+ : derived(d)
+ , Weak(w)
+ {
+ }
+ bool Weak;
+};
+
+struct cmStateDetail::BuildsystemDirectoryStateType
+{
+ cmStateDetail::PositionType DirectoryEnd;
+
+ std::string Location;
+ std::string OutputLocation;
+
+ // The top-most directories for relative path conversion. Both the
+ // source and destination location of a relative path conversion
+ // must be underneath one of these directories (both under source or
+ // both under binary) in order for the relative path to be evaluated
+ // safely by the build tools.
+ std::string RelativePathTopSource;
+ std::string RelativePathTopBinary;
+
+ std::vector<std::string> IncludeDirectories;
+ std::vector<cmListFileBacktrace> IncludeDirectoryBacktraces;
+
+ std::vector<std::string> CompileDefinitions;
+ std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces;
+
+ std::vector<std::string> CompileOptions;
+ std::vector<cmListFileBacktrace> CompileOptionsBacktraces;
+
+ std::vector<std::string> LinkOptions;
+ std::vector<cmListFileBacktrace> LinkOptionsBacktraces;
+
+ std::vector<std::string> LinkDirectories;
+ std::vector<cmListFileBacktrace> LinkDirectoriesBacktraces;
+
+ std::vector<std::string> NormalTargetNames;
+
+ std::string ProjectName;
+
+ cmPropertyMap Properties;
+
+ std::vector<cmStateSnapshot> Children;
+};
diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx
new file mode 100644
index 0000000..fbf47ef
--- /dev/null
+++ b/Source/cmStateSnapshot.cxx
@@ -0,0 +1,448 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmStateSnapshot.h"
+
+#include <algorithm>
+#include <cassert>
+#include <string>
+
+#include <cm/iterator>
+
+#include "cmDefinitions.h"
+#include "cmListFileCache.h"
+#include "cmProperty.h"
+#include "cmPropertyMap.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStatePrivate.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+
+cmStateSnapshot::cmStateSnapshot(cmState* state)
+ : State(state)
+{
+}
+
+std::vector<cmStateSnapshot> cmStateSnapshot::GetChildren()
+{
+ return this->Position->BuildSystemDirectory->Children;
+}
+
+cmStateSnapshot::cmStateSnapshot(cmState* state,
+ cmStateDetail::PositionType position)
+ : State(state)
+ , Position(position)
+{
+}
+
+cmStateEnums::SnapshotType cmStateSnapshot::GetType() const
+{
+ return this->Position->SnapshotType;
+}
+
+void cmStateSnapshot::SetListFile(const std::string& listfile)
+{
+ *this->Position->ExecutionListFile = listfile;
+}
+
+std::string const& cmStateSnapshot::GetExecutionListFile() const
+{
+ return *this->Position->ExecutionListFile;
+}
+
+bool cmStateSnapshot::IsValid() const
+{
+ return this->State && this->Position.IsValid()
+ ? this->Position != this->State->SnapshotData.Root()
+ : false;
+}
+
+cmStateSnapshot cmStateSnapshot::GetBuildsystemDirectory() const
+{
+ return { this->State, this->Position->BuildSystemDirectory->DirectoryEnd };
+}
+
+cmStateSnapshot cmStateSnapshot::GetBuildsystemDirectoryParent() const
+{
+ cmStateSnapshot snapshot;
+ if (!this->State || this->Position == this->State->SnapshotData.Root()) {
+ return snapshot;
+ }
+ cmStateDetail::PositionType parentPos = this->Position->DirectoryParent;
+ if (parentPos != this->State->SnapshotData.Root()) {
+ snapshot = cmStateSnapshot(this->State,
+ parentPos->BuildSystemDirectory->DirectoryEnd);
+ }
+
+ return snapshot;
+}
+
+cmStateSnapshot cmStateSnapshot::GetCallStackParent() const
+{
+ assert(this->State);
+ assert(this->Position != this->State->SnapshotData.Root());
+
+ cmStateSnapshot snapshot;
+ cmStateDetail::PositionType parentPos = this->Position;
+ while (parentPos->SnapshotType == cmStateEnums::PolicyScopeType ||
+ parentPos->SnapshotType == cmStateEnums::VariableScopeType) {
+ ++parentPos;
+ }
+ if (parentPos->SnapshotType == cmStateEnums::BuildsystemDirectoryType ||
+ parentPos->SnapshotType == cmStateEnums::BaseType) {
+ return snapshot;
+ }
+
+ ++parentPos;
+ while (parentPos->SnapshotType == cmStateEnums::PolicyScopeType ||
+ parentPos->SnapshotType == cmStateEnums::VariableScopeType) {
+ ++parentPos;
+ }
+
+ if (parentPos == this->State->SnapshotData.Root()) {
+ return snapshot;
+ }
+
+ snapshot = cmStateSnapshot(this->State, parentPos);
+ return snapshot;
+}
+
+cmStateSnapshot cmStateSnapshot::GetCallStackBottom() const
+{
+ assert(this->State);
+ assert(this->Position != this->State->SnapshotData.Root());
+
+ cmStateDetail::PositionType pos = this->Position;
+ while (pos->SnapshotType != cmStateEnums::BaseType &&
+ pos->SnapshotType != cmStateEnums::BuildsystemDirectoryType &&
+ pos != this->State->SnapshotData.Root()) {
+ ++pos;
+ }
+ return { this->State, pos };
+}
+
+void cmStateSnapshot::PushPolicy(cmPolicies::PolicyMap const& entry, bool weak)
+{
+ cmStateDetail::PositionType pos = this->Position;
+ pos->Policies = this->State->PolicyStack.Push(
+ pos->Policies, cmStateDetail::PolicyStackEntry(entry, weak));
+}
+
+bool cmStateSnapshot::PopPolicy()
+{
+ cmStateDetail::PositionType pos = this->Position;
+ if (pos->Policies == pos->PolicyScope) {
+ return false;
+ }
+ pos->Policies = this->State->PolicyStack.Pop(pos->Policies);
+ return true;
+}
+
+bool cmStateSnapshot::CanPopPolicyScope()
+{
+ return this->Position->Policies != this->Position->PolicyScope;
+}
+
+void cmStateSnapshot::SetPolicy(cmPolicies::PolicyID id,
+ cmPolicies::PolicyStatus status)
+{
+ // Update the policy stack from the top to the top-most strong entry.
+ bool previous_was_weak = true;
+ for (cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator psi =
+ this->Position->Policies;
+ previous_was_weak && psi != this->Position->PolicyRoot; ++psi) {
+ psi->Set(id, status);
+ previous_was_weak = psi->Weak;
+ }
+}
+
+cmPolicies::PolicyStatus cmStateSnapshot::GetPolicy(cmPolicies::PolicyID id,
+ bool parent_scope) const
+{
+ cmPolicies::PolicyStatus status = cmPolicies::GetPolicyStatus(id);
+
+ if (status == cmPolicies::REQUIRED_ALWAYS ||
+ status == cmPolicies::REQUIRED_IF_USED) {
+ return status;
+ }
+
+ cmLinkedTree<cmStateDetail::BuildsystemDirectoryStateType>::iterator dir =
+ this->Position->BuildSystemDirectory;
+
+ while (true) {
+ assert(dir.IsValid());
+ cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator leaf =
+ dir->DirectoryEnd->Policies;
+ cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator root =
+ dir->DirectoryEnd->PolicyRoot;
+ for (; leaf != root; ++leaf) {
+ if (parent_scope) {
+ parent_scope = false;
+ continue;
+ }
+ if (leaf->IsDefined(id)) {
+ status = leaf->Get(id);
+ return status;
+ }
+ }
+ cmStateDetail::PositionType e = dir->DirectoryEnd;
+ cmStateDetail::PositionType p = e->DirectoryParent;
+ if (p == this->State->SnapshotData.Root()) {
+ break;
+ }
+ dir = p->BuildSystemDirectory;
+ }
+ return status;
+}
+
+bool cmStateSnapshot::HasDefinedPolicyCMP0011()
+{
+ return !this->Position->Policies->IsEmpty();
+}
+
+std::string const* cmStateSnapshot::GetDefinition(
+ std::string const& name) const
+{
+ assert(this->Position->Vars.IsValid());
+ return cmDefinitions::Get(name, this->Position->Vars, this->Position->Root);
+}
+
+bool cmStateSnapshot::IsInitialized(std::string const& name) const
+{
+ return cmDefinitions::HasKey(name, this->Position->Vars,
+ this->Position->Root);
+}
+
+void cmStateSnapshot::SetDefinition(std::string const& name,
+ cm::string_view value)
+{
+ this->Position->Vars->Set(name, value);
+}
+
+void cmStateSnapshot::RemoveDefinition(std::string const& name)
+{
+ this->Position->Vars->Unset(name);
+}
+
+std::vector<std::string> cmStateSnapshot::ClosureKeys() const
+{
+ return cmDefinitions::ClosureKeys(this->Position->Vars,
+ this->Position->Root);
+}
+
+bool cmStateSnapshot::RaiseScope(std::string const& var, const char* varDef)
+{
+ if (this->Position->ScopeParent == this->Position->DirectoryParent) {
+ cmStateSnapshot parentDir = this->GetBuildsystemDirectoryParent();
+ if (!parentDir.IsValid()) {
+ return false;
+ }
+ // Update the definition in the parent directory top scope. This
+ // directory's scope was initialized by the closure of the parent
+ // scope, so we do not need to localize the definition first.
+ if (varDef) {
+ parentDir.SetDefinition(var, varDef);
+ } else {
+ parentDir.RemoveDefinition(var);
+ }
+ return true;
+ }
+ // First localize the definition in the current scope.
+ cmDefinitions::Raise(var, this->Position->Vars, this->Position->Root);
+
+ // Now update the definition in the parent scope.
+ if (varDef) {
+ this->Position->Parent->Set(var, varDef);
+ } else {
+ this->Position->Parent->Unset(var);
+ }
+ return true;
+}
+
+template <typename T, typename U, typename V>
+void InitializeContentFromParent(T& parentContent, T& thisContent,
+ U& parentBacktraces, U& thisBacktraces,
+ V& contentEndPosition)
+{
+ auto parentBegin = parentContent.begin();
+ auto parentEnd = parentContent.end();
+
+ auto parentRbegin = cm::make_reverse_iterator(parentEnd);
+ auto parentRend = parentContent.rend();
+ parentRbegin = std::find(parentRbegin, parentRend, cmPropertySentinal);
+ auto parentIt = parentRbegin.base();
+
+ thisContent = std::vector<std::string>(parentIt, parentEnd);
+
+ auto btIt = parentBacktraces.begin() + std::distance(parentBegin, parentIt);
+ auto btEnd = parentBacktraces.end();
+
+ thisBacktraces = std::vector<cmListFileBacktrace>(btIt, btEnd);
+
+ contentEndPosition = thisContent.size();
+}
+
+void cmStateSnapshot::SetDefaultDefinitions()
+{
+ /* Up to CMake 2.4 here only WIN32, UNIX and APPLE were set.
+ With CMake must separate between target and host platform. In most cases
+ the tests for WIN32, UNIX and APPLE will be for the target system, so an
+ additional set of variables for the host system is required ->
+ CMAKE_HOST_WIN32, CMAKE_HOST_UNIX, CMAKE_HOST_APPLE.
+ WIN32, UNIX and APPLE are now set in the platform files in
+ Modules/Platforms/.
+ To keep cmake scripts (-P) and custom language and compiler modules
+ working, these variables are still also set here in this place, but they
+ will be reset in CMakeSystemSpecificInformation.cmake before the platform
+ files are executed. */
+ cm::string_view hostSystemName = cmSystemTools::GetSystemName();
+ this->SetDefinition("CMAKE_HOST_SYSTEM_NAME", hostSystemName);
+ if (hostSystemName == "Windows") {
+ this->SetDefinition("WIN32", "1");
+ this->SetDefinition("CMAKE_HOST_WIN32", "1");
+ } else {
+ this->SetDefinition("UNIX", "1");
+ this->SetDefinition("CMAKE_HOST_UNIX", "1");
+ }
+#if defined(__CYGWIN__)
+ std::string legacy;
+ if (cmSystemTools::GetEnv("CMAKE_LEGACY_CYGWIN_WIN32", legacy) &&
+ cmIsOn(legacy)) {
+ this->SetDefinition("WIN32", "1");
+ this->SetDefinition("CMAKE_HOST_WIN32", "1");
+ }
+#endif
+#if defined(__APPLE__)
+ this->SetDefinition("APPLE", "1");
+ this->SetDefinition("CMAKE_HOST_APPLE", "1");
+#endif
+#if defined(__sun__)
+ this->SetDefinition("CMAKE_HOST_SOLARIS", "1");
+#endif
+
+ this->SetDefinition("CMAKE_MAJOR_VERSION",
+ std::to_string(cmVersion::GetMajorVersion()));
+ this->SetDefinition("CMAKE_MINOR_VERSION",
+ std::to_string(cmVersion::GetMinorVersion()));
+ this->SetDefinition("CMAKE_PATCH_VERSION",
+ std::to_string(cmVersion::GetPatchVersion()));
+ this->SetDefinition("CMAKE_TWEAK_VERSION",
+ std::to_string(cmVersion::GetTweakVersion()));
+ this->SetDefinition("CMAKE_VERSION", cmVersion::GetCMakeVersion());
+
+ this->SetDefinition("CMAKE_FILES_DIRECTORY", "/CMakeFiles");
+
+ // Setup the default include file regular expression (match everything).
+ this->Position->BuildSystemDirectory->Properties.SetProperty(
+ "INCLUDE_REGULAR_EXPRESSION", "^.*$");
+}
+
+void cmStateSnapshot::SetDirectoryDefinitions()
+{
+ this->SetDefinition("CMAKE_SOURCE_DIR", this->State->GetSourceDirectory());
+ this->SetDefinition("CMAKE_CURRENT_SOURCE_DIR",
+ this->State->GetSourceDirectory());
+ this->SetDefinition("CMAKE_BINARY_DIR", this->State->GetBinaryDirectory());
+ this->SetDefinition("CMAKE_CURRENT_BINARY_DIR",
+ this->State->GetBinaryDirectory());
+}
+
+void cmStateSnapshot::InitializeFromParent()
+{
+ cmStateDetail::PositionType parent = this->Position->DirectoryParent;
+ assert(this->Position->Vars.IsValid());
+ assert(parent->Vars.IsValid());
+
+ *this->Position->Vars =
+ cmDefinitions::MakeClosure(parent->Vars, parent->Root);
+
+ InitializeContentFromParent(
+ parent->BuildSystemDirectory->IncludeDirectories,
+ this->Position->BuildSystemDirectory->IncludeDirectories,
+ parent->BuildSystemDirectory->IncludeDirectoryBacktraces,
+ this->Position->BuildSystemDirectory->IncludeDirectoryBacktraces,
+ this->Position->IncludeDirectoryPosition);
+
+ InitializeContentFromParent(
+ parent->BuildSystemDirectory->CompileDefinitions,
+ this->Position->BuildSystemDirectory->CompileDefinitions,
+ parent->BuildSystemDirectory->CompileDefinitionsBacktraces,
+ this->Position->BuildSystemDirectory->CompileDefinitionsBacktraces,
+ this->Position->CompileDefinitionsPosition);
+
+ InitializeContentFromParent(
+ parent->BuildSystemDirectory->CompileOptions,
+ this->Position->BuildSystemDirectory->CompileOptions,
+ parent->BuildSystemDirectory->CompileOptionsBacktraces,
+ this->Position->BuildSystemDirectory->CompileOptionsBacktraces,
+ this->Position->CompileOptionsPosition);
+
+ InitializeContentFromParent(
+ parent->BuildSystemDirectory->LinkOptions,
+ this->Position->BuildSystemDirectory->LinkOptions,
+ parent->BuildSystemDirectory->LinkOptionsBacktraces,
+ this->Position->BuildSystemDirectory->LinkOptionsBacktraces,
+ this->Position->LinkOptionsPosition);
+
+ InitializeContentFromParent(
+ parent->BuildSystemDirectory->LinkDirectories,
+ this->Position->BuildSystemDirectory->LinkDirectories,
+ parent->BuildSystemDirectory->LinkDirectoriesBacktraces,
+ this->Position->BuildSystemDirectory->LinkDirectoriesBacktraces,
+ this->Position->LinkDirectoriesPosition);
+
+ cmProp include_regex =
+ parent->BuildSystemDirectory->Properties.GetPropertyValue(
+ "INCLUDE_REGULAR_EXPRESSION");
+ this->Position->BuildSystemDirectory->Properties.SetProperty(
+ "INCLUDE_REGULAR_EXPRESSION", cmToCStr(include_regex));
+}
+
+cmState* cmStateSnapshot::GetState() const
+{
+ return this->State;
+}
+
+cmStateDirectory cmStateSnapshot::GetDirectory() const
+{
+ return { this->Position->BuildSystemDirectory, *this };
+}
+
+void cmStateSnapshot::SetProjectName(const std::string& name)
+{
+ this->Position->BuildSystemDirectory->ProjectName = name;
+}
+
+std::string cmStateSnapshot::GetProjectName() const
+{
+ return this->Position->BuildSystemDirectory->ProjectName;
+}
+
+void cmStateSnapshot::InitializeFromParent_ForSubdirsCommand()
+{
+ std::string currentSrcDir = *this->GetDefinition("CMAKE_CURRENT_SOURCE_DIR");
+ std::string currentBinDir = *this->GetDefinition("CMAKE_CURRENT_BINARY_DIR");
+ this->InitializeFromParent();
+ this->SetDefinition("CMAKE_SOURCE_DIR", this->State->GetSourceDirectory());
+ this->SetDefinition("CMAKE_BINARY_DIR", this->State->GetBinaryDirectory());
+
+ this->SetDefinition("CMAKE_CURRENT_SOURCE_DIR", currentSrcDir);
+ this->SetDefinition("CMAKE_CURRENT_BINARY_DIR", currentBinDir);
+}
+
+bool cmStateSnapshot::StrictWeakOrder::operator()(
+ const cmStateSnapshot& lhs, const cmStateSnapshot& rhs) const
+{
+ return lhs.Position.StrictWeakOrdered(rhs.Position);
+}
+
+bool operator==(const cmStateSnapshot& lhs, const cmStateSnapshot& rhs)
+{
+ return lhs.Position == rhs.Position;
+}
+
+bool operator!=(const cmStateSnapshot& lhs, const cmStateSnapshot& rhs)
+{
+ return lhs.Position != rhs.Position;
+}
diff --git a/Source/cmStateSnapshot.h b/Source/cmStateSnapshot.h
new file mode 100644
index 0000000..d06cba3
--- /dev/null
+++ b/Source/cmStateSnapshot.h
@@ -0,0 +1,88 @@
+/* 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 <string>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmLinkedTree.h"
+#include "cmPolicies.h"
+#include "cmStateTypes.h"
+
+class cmState;
+class cmStateDirectory;
+
+class cmStateSnapshot
+{
+public:
+ cmStateSnapshot(cmState* state = nullptr);
+ cmStateSnapshot(cmState* state, cmStateDetail::PositionType position);
+
+ std::string const* GetDefinition(std::string const& name) const;
+ bool IsInitialized(std::string const& name) const;
+ void SetDefinition(std::string const& name, cm::string_view value);
+ void RemoveDefinition(std::string const& name);
+ std::vector<std::string> ClosureKeys() const;
+ bool RaiseScope(std::string const& var, const char* varDef);
+
+ void SetListFile(std::string const& listfile);
+
+ std::string const& GetExecutionListFile() const;
+
+ std::vector<cmStateSnapshot> GetChildren();
+
+ bool IsValid() const;
+ cmStateSnapshot GetBuildsystemDirectory() const;
+ cmStateSnapshot GetBuildsystemDirectoryParent() const;
+ cmStateSnapshot GetCallStackParent() const;
+ cmStateSnapshot GetCallStackBottom() const;
+ cmStateEnums::SnapshotType GetType() const;
+
+ void SetPolicy(cmPolicies::PolicyID id, cmPolicies::PolicyStatus status);
+ cmPolicies::PolicyStatus GetPolicy(cmPolicies::PolicyID id,
+ bool parent_scope = false) const;
+ bool HasDefinedPolicyCMP0011();
+ void PushPolicy(cmPolicies::PolicyMap const& entry, bool weak);
+ bool PopPolicy();
+ bool CanPopPolicyScope();
+
+ cmState* GetState() const;
+
+ cmStateDirectory GetDirectory() const;
+
+ void SetProjectName(std::string const& name);
+ std::string GetProjectName() const;
+
+ void InitializeFromParent_ForSubdirsCommand();
+
+ struct StrictWeakOrder
+ {
+ bool operator()(const cmStateSnapshot& lhs,
+ const cmStateSnapshot& rhs) const;
+ };
+
+ void SetDirectoryDefinitions();
+ void SetDefaultDefinitions();
+
+private:
+ friend bool operator==(const cmStateSnapshot& lhs,
+ const cmStateSnapshot& rhs);
+ friend bool operator!=(const cmStateSnapshot& lhs,
+ const cmStateSnapshot& rhs);
+ friend class cmState;
+ friend class cmStateDirectory;
+ friend struct StrictWeakOrder;
+
+ void InitializeFromParent();
+
+ cmState* State;
+ cmStateDetail::PositionType Position;
+};
+
+bool operator==(const cmStateSnapshot& lhs, const cmStateSnapshot& rhs);
+bool operator!=(const cmStateSnapshot& lhs, const cmStateSnapshot& rhs);
diff --git a/Source/cmStateTypes.h b/Source/cmStateTypes.h
new file mode 100644
index 0000000..010d7e3
--- /dev/null
+++ b/Source/cmStateTypes.h
@@ -0,0 +1,62 @@
+/* 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 "cmLinkedTree.h"
+
+namespace cmStateDetail {
+struct SnapshotDataType;
+using PositionType = cmLinkedTree<cmStateDetail::SnapshotDataType>::iterator;
+}
+
+namespace cmStateEnums {
+
+enum SnapshotType
+{
+ BaseType,
+ BuildsystemDirectoryType,
+ DeferCallType,
+ FunctionCallType,
+ MacroCallType,
+ IncludeFileType,
+ InlineListFileType,
+ PolicyScopeType,
+ VariableScopeType
+};
+
+// There are multiple overlapping ranges represented here. Be aware that adding
+// a value to this enumeration may cause failures in numerous places which
+// assume details about the ordering.
+enum TargetType
+{
+ EXECUTABLE,
+ STATIC_LIBRARY,
+ SHARED_LIBRARY,
+ MODULE_LIBRARY,
+ OBJECT_LIBRARY,
+ UTILITY,
+ GLOBAL_TARGET,
+ INTERFACE_LIBRARY,
+ UNKNOWN_LIBRARY
+};
+
+enum CacheEntryType
+{
+ BOOL = 0,
+ PATH,
+ FILEPATH,
+ STRING,
+ INTERNAL,
+ STATIC,
+ UNINITIALIZED
+};
+
+enum ArtifactType
+{
+ RuntimeBinaryArtifact,
+ ImportLibraryArtifact
+};
+}
diff --git a/Source/cmString.cxx b/Source/cmString.cxx
new file mode 100644
index 0000000..aefaa64
--- /dev/null
+++ b/Source/cmString.cxx
@@ -0,0 +1,154 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
+#define _SCL_SECURE_NO_WARNINGS
+
+#include "cmString.hxx"
+
+#include <memory>
+#include <ostream>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+
+namespace cm {
+
+static std::string const empty_string_;
+
+void String::internally_mutate_to_stable_string()
+{
+ // We assume that only one thread mutates this instance at
+ // a time even if we point to a shared string buffer referenced
+ // by other threads.
+ *this = String(this->data(), this->size());
+}
+
+bool String::is_stable() const
+{
+ return this->str_if_stable() != nullptr;
+}
+
+void String::stabilize()
+{
+ if (this->is_stable()) {
+ return;
+ }
+ this->internally_mutate_to_stable_string();
+}
+
+std::string const* String::str_if_stable() const
+{
+ if (!this->data()) {
+ // We view no string.
+ // This is stable for the lifetime of our current value.
+ return &empty_string_;
+ }
+
+ if (this->string_ && this->data() == this->string_->data() &&
+ this->size() == this->string_->size()) {
+ // We view an entire string.
+ // This is stable for the lifetime of our current value.
+ return this->string_.get();
+ }
+
+ return nullptr;
+}
+
+std::string const& String::str()
+{
+ if (std::string const* s = this->str_if_stable()) {
+ return *s;
+ }
+ // Mutate to hold a std::string that is stable for the lifetime
+ // of our current value.
+ this->internally_mutate_to_stable_string();
+ return *this->string_;
+}
+
+const char* String::c_str()
+{
+ const char* c = this->data();
+ if (c == nullptr) {
+ return c;
+ }
+
+ // We always point into a null-terminated string so it is safe to
+ // access one past the end. If it is a null byte then we can use
+ // the pointer directly.
+ if (c[this->size()] == '\0') {
+ return c;
+ }
+
+ // Mutate to hold a std::string so we can get a null terminator.
+ this->internally_mutate_to_stable_string();
+ c = this->string_->c_str();
+ return c;
+}
+
+String& String::insert(size_type index, size_type count, char ch)
+{
+ std::string s;
+ s.reserve(this->size() + count);
+ s.assign(this->data(), this->size());
+ s.insert(index, count, ch);
+ return *this = std::move(s);
+}
+
+String& String::erase(size_type index, size_type count)
+{
+ if (index > this->size()) {
+ throw std::out_of_range("Index out of range in String::erase");
+ }
+ size_type const rcount = std::min(count, this->size() - index);
+ size_type const rindex = index + rcount;
+ std::string s;
+ s.reserve(this->size() - rcount);
+ s.assign(this->data(), index);
+ s.append(this->data() + rindex, this->size() - rindex);
+ return *this = std::move(s);
+}
+
+String String::substr(size_type pos, size_type count) const
+{
+ if (pos > this->size()) {
+ throw std::out_of_range("Index out of range in String::substr");
+ }
+ return String(*this, pos, count);
+}
+
+String::String(std::string&& s, Private)
+ : string_(std::make_shared<std::string>(std::move(s)))
+ , view_(this->string_->data(), this->string_->size())
+{
+}
+
+String::size_type String::copy(char* dest, size_type count,
+ size_type pos) const
+{
+ return this->view_.copy(dest, count, pos);
+}
+
+std::ostream& operator<<(std::ostream& os, String const& s)
+{
+ return os.write(s.data(), s.size());
+}
+
+std::string& operator+=(std::string& self, String const& s)
+{
+ return self += s.view();
+}
+
+String IntoString<char*>::into_string(const char* s)
+{
+ if (!s) {
+ return String();
+ }
+ return std::string(s);
+}
+
+string_view AsStringView<String>::view(String const& s)
+{
+ return s.view();
+}
+
+} // namespace cm
diff --git a/Source/cmString.hxx b/Source/cmString.hxx
new file mode 100644
index 0000000..f1e462b
--- /dev/null
+++ b/Source/cmString.hxx
@@ -0,0 +1,937 @@
+/* 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 <algorithm>
+#include <cstddef>
+#include <functional>
+#include <initializer_list>
+#include <memory>
+#include <ostream>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include <cm/string_view>
+#include <cmext/string_view>
+
+namespace cm {
+
+class String;
+
+/**
+ * Trait to convert type T into a String.
+ * Implementations must derive from 'std::true_type'
+ * and define an 'into_string' member that accepts
+ * type T (by value or reference) and returns one of:
+ *
+ * - 'std::string' to construct an owned instance.
+ * - 'cm::string_view' to construct a borrowed or null instances.
+ * The buffer from which the view is borrowed must outlive
+ * all copies of the resulting String, e.g. static storage.
+ * - 'cm::String' for already-constructed instances.
+ */
+template <typename T>
+struct IntoString : std::false_type
+{
+};
+
+template <typename T>
+struct IntoString<T&> : IntoString<T>
+{
+};
+
+template <typename T>
+struct IntoString<T const> : IntoString<T>
+{
+};
+
+template <typename T>
+struct IntoString<T const*> : IntoString<T*>
+{
+};
+
+template <typename T, std::string::size_type N>
+struct IntoString<T const[N]> : IntoString<T[N]>
+{
+};
+
+template <>
+struct IntoString<char*> : std::true_type
+{
+ static String into_string(const char* s);
+};
+
+template <>
+struct IntoString<std::nullptr_t> : std::true_type
+{
+ static string_view into_string(std::nullptr_t) { return string_view(); }
+};
+
+template <std::string::size_type N>
+struct IntoString<char[N]> : std::true_type
+{
+ static std::string into_string(char const (&s)[N])
+ {
+ return std::string(s, N - 1);
+ }
+};
+
+template <>
+struct IntoString<std::string> : std::true_type
+{
+ static std::string into_string(std::string s) { return s; }
+};
+
+template <>
+struct IntoString<char> : std::true_type
+{
+ static std::string into_string(char const& c) { return std::string(1, c); }
+};
+
+/**
+ * Trait to convert type T into a 'cm::string_view'.
+ * Implementations must derive from 'std::true_type' and
+ * define a 'view' member that accepts type T (by reference)
+ * and returns a 'cm::string_view'.
+ */
+template <typename T>
+struct AsStringView : std::false_type
+{
+};
+
+template <typename T>
+struct AsStringView<T&> : AsStringView<T>
+{
+};
+
+template <typename T>
+struct AsStringView<T const> : AsStringView<T>
+{
+};
+
+template <typename T>
+struct AsStringView<T const*> : AsStringView<T*>
+{
+};
+
+template <typename T, std::string::size_type N>
+struct AsStringView<T const[N]> : AsStringView<T[N]>
+{
+};
+
+template <>
+struct AsStringView<char*> : std::true_type
+{
+ static string_view view(const char* s) { return s; }
+};
+
+template <std::string::size_type N>
+struct AsStringView<char[N]> : std::true_type
+{
+ static string_view view(char const (&s)[N]) { return string_view(s, N - 1); }
+};
+
+template <>
+struct AsStringView<std::string> : std::true_type
+{
+ static string_view view(std::string const& s) { return s; }
+};
+
+template <>
+struct AsStringView<char> : std::true_type
+{
+ static string_view view(const char& s) { return string_view(&s, 1); }
+};
+
+template <>
+struct AsStringView<string_view> : std::true_type
+{
+ static string_view view(string_view const& s) { return s; }
+};
+
+template <>
+struct AsStringView<static_string_view> : std::true_type
+{
+ static string_view view(static_string_view const& s) { return s; }
+};
+
+template <>
+struct AsStringView<String> : std::true_type
+{
+ static string_view view(String const& s);
+};
+
+/**
+ * \class String
+ *
+ * A custom string type that holds a view of a string buffer
+ * and optionally shares ownership of the buffer. Instances
+ * may have one of the following states:
+ *
+ * - null: views and owns nothing.
+ * Conversion to 'bool' is 'false'.
+ * 'data()' and 'c_str()' return nullptr.
+ * 'size()' returns 0.
+ * 'str()' returns an empty string.
+ *
+ * - borrowed: views a string but does not own it. This is used
+ * to bind to static storage (e.g. string literals) or for
+ * temporary instances that do not outlive the borrowed buffer.
+ * Copies and substrings still borrow the original buffer.
+ * Mutation allocates a new internal string and converts to
+ * the 'owned' state.
+ * Conversion to 'bool' is 'true'.
+ * 'c_str()' may internally mutate to the 'owned' state.
+ * 'str()' internally mutates to the 'owned' state.
+ *
+ * - owned: views an immutable 'std::string' instance owned internally.
+ * Copies and substrings share ownership of the internal string.
+ * Mutation allocates a new internal string.
+ * Conversion to 'bool' is 'true'.
+ */
+class String
+{
+ enum class Private
+ {
+ };
+
+public:
+ using traits_type = std::string::traits_type;
+ using value_type = string_view::value_type;
+ using pointer = string_view::pointer;
+ using const_pointer = string_view::const_pointer;
+ using reference = string_view::reference;
+ using const_reference = string_view::const_reference;
+ using const_iterator = string_view::const_iterator;
+ using iterator = string_view::const_iterator;
+ using const_reverse_iterator = string_view::const_reverse_iterator;
+ using reverse_iterator = string_view::const_reverse_iterator;
+ using difference_type = string_view::difference_type;
+ using size_type = string_view::size_type;
+
+ static size_type const npos = string_view::npos;
+
+ /** Construct a null string. */
+ String() = default;
+
+ /** Construct from any type implementing the IntoString trait. */
+ template <typename T,
+ typename = typename std::enable_if<IntoString<T>::value>::type>
+ String(T&& s)
+ : String(IntoString<T>::into_string(std::forward<T>(s)), Private())
+ {
+ }
+
+ /**
+ * Construct via static_string_view constructor.
+ * explicit is required to avoid ambiguous overloaded operators (i.e ==,
+ * etc...) with the ones provided by string_view.
+ */
+ explicit String(static_string_view s)
+ : String(s, Private())
+ {
+ }
+ /**
+ * Construct via string_view constructor.
+ * explicit is required to avoid ambiguous overloaded operators (i.e ==,
+ * etc...) with the ones provided by string_view.
+ */
+ explicit String(string_view s)
+ : String(std::string(s), Private())
+ {
+ }
+
+ /** Construct via std::string initializer list constructor. */
+ String(std::initializer_list<char> il)
+ : String(std::string(il))
+ {
+ }
+
+ /** Construct by copying the specified buffer. */
+ String(const char* d, size_type s)
+ : String(std::string(d, s))
+ {
+ }
+
+ /** Construct by copying from input iterator range. */
+ template <typename InputIterator>
+ String(InputIterator first, InputIterator last)
+ : String(std::string(first, last))
+ {
+ }
+
+ /** Construct a string with 'n' copies of character 'c'. */
+ String(size_type n, char c)
+ : String(std::string(n, c))
+ {
+ }
+
+ /** Construct from a substring of another String instance.
+ This shares ownership of the other string's buffer
+ but views only a substring. */
+ String(String const& s, size_type pos, size_type count = npos)
+ : string_(s.string_)
+ , view_(s.data() + pos, std::min(count, s.size() - pos))
+ {
+ }
+
+ /** Construct by moving from another String instance.
+ The other instance is left as a null string. */
+ String(String&& s) noexcept
+ : string_(std::move(s.string_))
+ , view_(s.view_)
+ {
+ s.view_ = string_view();
+ }
+
+ /** Construct by copying from another String instance.
+ This shares ownership of the other string's buffer. */
+ String(String const&) noexcept = default;
+
+ ~String() = default;
+
+ /** Construct by borrowing an externally-owned buffer. The buffer
+ must outlive the returned instance and all copies of it. */
+ static String borrow(string_view v) { return String(v, Private()); }
+
+ /** Assign by moving from another String instance.
+ The other instance is left as a null string. */
+ String& operator=(String&& s) noexcept
+ {
+ this->string_ = std::move(s.string_);
+ this->view_ = s.view_;
+ s.view_ = string_view();
+ return *this;
+ }
+
+ /** Assign by copying from another String instance.
+ This shares ownership of the other string's buffer. */
+ String& operator=(String const&) noexcept = default;
+
+ String& operator=(static_string_view s)
+ {
+ *this = String(s);
+ return *this;
+ }
+ String& operator=(string_view s)
+ {
+ *this = String(s);
+ return *this;
+ }
+
+ /** Assign from any type implementing the IntoString trait. */
+ template <typename T>
+ typename // NOLINT(*)
+ std::enable_if<IntoString<T>::value, String&>::type
+ operator=(T&& s)
+ {
+ *this = String(std::forward<T>(s));
+ return *this;
+ }
+
+ /** Assign via std::string initializer list constructor. */
+ String& operator=(std::initializer_list<char> il)
+ {
+ *this = String(il);
+ return *this;
+ }
+
+ /** Return true if the instance is not a null string. */
+ explicit operator bool() const noexcept { return this->data() != nullptr; }
+
+ /** Return a view of the string. */
+ string_view view() const noexcept { return this->view_; }
+ operator string_view() const noexcept { return this->view(); }
+
+ /** Return true if the instance is an empty stringn or null string. */
+ bool empty() const noexcept { return this->view_.empty(); }
+
+ /** Return a pointer to the start of the string. */
+ const char* data() const noexcept { return this->view_.data(); }
+
+ /** Return the length of the string in bytes. */
+ size_type size() const noexcept { return this->view_.size(); }
+ size_type length() const noexcept { return this->view_.length(); }
+
+ /** Return the character at the given position.
+ No bounds checking is performed. */
+ char operator[](size_type pos) const noexcept { return this->view_[pos]; }
+
+ /** Return the character at the given position.
+ If the position is out of bounds, throws std::out_of_range. */
+ char at(size_type pos) const { return this->view_.at(pos); }
+
+ char front() const noexcept { return this->view_.front(); }
+
+ char back() const noexcept { return this->view_.back(); }
+
+ /** Return true if this instance is stable and otherwise false.
+ An instance is stable if it is in the 'null' state or if it is
+ an 'owned' state not produced by substring operations, or
+ after a call to 'stabilize()' or 'str()'. */
+ bool is_stable() const;
+
+ /** If 'is_stable()' does not return true, mutate so it does. */
+ void stabilize();
+
+ /** Get a pointer to a normal std::string if 'is_stable()' returns
+ true and otherwise nullptr. The pointer is valid until this
+ instance is mutated or destroyed. */
+ std::string const* str_if_stable() const;
+
+ /** Get a reference to a normal std::string. The reference
+ is valid until this instance is mutated or destroyed. */
+ std::string const& str();
+
+ /** Get a pointer to a C-style null-terminated string
+ containing the same value as this instance. The pointer
+ is valid until this instance is mutated, destroyed,
+ or str() is called. */
+ const char* c_str();
+
+ const_iterator begin() const noexcept { return this->view_.begin(); }
+ const_iterator end() const noexcept { return this->view_.end(); }
+ const_iterator cbegin() const noexcept { return this->begin(); }
+ const_iterator cend() const noexcept { return this->end(); }
+
+ const_reverse_iterator rbegin() const noexcept
+ {
+ return this->view_.rbegin();
+ }
+ const_reverse_iterator rend() const noexcept { return this->view_.rend(); }
+ const_reverse_iterator crbegin() const noexcept { return this->rbegin(); }
+ const_reverse_iterator crend() const noexcept { return this->rend(); }
+
+ /** Append to the string using any type that implements the
+ AsStringView trait. */
+ template <typename T>
+ typename std::enable_if<AsStringView<T>::value, String&>::type operator+=(
+ T&& s)
+ {
+ string_view v = AsStringView<T>::view(std::forward<T>(s));
+ std::string r;
+ r.reserve(this->size() + v.size());
+ r.assign(this->data(), this->size());
+ r.append(v.data(), v.size());
+ return *this = std::move(r);
+ }
+
+ /** Assign to an empty string. */
+ void clear() { *this = ""_s; }
+
+ /** Insert 'count' copies of 'ch' at position 'index'. */
+ String& insert(size_type index, size_type count, char ch);
+
+ /** Erase 'count' characters starting at position 'index'. */
+ String& erase(size_type index = 0, size_type count = npos);
+
+ void push_back(char ch)
+ {
+ std::string s;
+ s.reserve(this->size() + 1);
+ s.assign(this->data(), this->size());
+ s.push_back(ch);
+ *this = std::move(s);
+ }
+
+ void pop_back() { *this = String(*this, 0, this->size() - 1); }
+
+ template <typename T>
+ typename std::enable_if<AsStringView<T>::value, String&>::type replace(
+ size_type pos, size_type count, T&& s)
+ {
+ const_iterator first = this->begin() + pos;
+ const_iterator last = first + count;
+ return this->replace(first, last, std::forward<T>(s));
+ }
+
+ template <typename InputIterator>
+ String& replace(const_iterator first, const_iterator last,
+ InputIterator first2, InputIterator last2)
+ {
+ std::string out;
+ out.append(this->view_.begin(), first);
+ out.append(first2, last2);
+ out.append(last, this->view_.end());
+ return *this = std::move(out);
+ }
+
+ template <typename T>
+ typename std::enable_if<AsStringView<T>::value, String&>::type replace(
+ const_iterator first, const_iterator last, T&& s)
+ {
+ string_view v = AsStringView<T>::view(std::forward<T>(s));
+ std::string out;
+ out.reserve((first - this->view_.begin()) + v.size() +
+ (this->view_.end() - last));
+ out.append(this->view_.begin(), first);
+ out.append(v.data(), v.size());
+ out.append(last, this->view_.end());
+ return *this = std::move(out);
+ }
+
+ template <typename T>
+ typename std::enable_if<AsStringView<T>::value, String&>::type replace(
+ size_type pos, size_type count, T&& s, size_type pos2,
+ size_type count2 = npos)
+ {
+ string_view v = AsStringView<T>::view(std::forward<T>(s));
+ v = v.substr(pos2, count2);
+ return this->replace(pos, count, v);
+ }
+
+ String& replace(size_type pos, size_type count, size_type count2, char ch)
+ {
+ const_iterator first = this->begin() + pos;
+ const_iterator last = first + count;
+ return this->replace(first, last, count2, ch);
+ }
+
+ String& replace(const_iterator first, const_iterator last, size_type count2,
+ char ch)
+ {
+ std::string out;
+ out.reserve((first - this->view_.begin()) + count2 +
+ (this->view_.end() - last));
+ out.append(this->view_.begin(), first);
+ out.append(count2, ch);
+ out.append(last, this->view_.end());
+ return *this = std::move(out);
+ }
+
+ size_type copy(char* dest, size_type count, size_type pos = 0) const;
+
+ void resize(size_type count) { this->resize(count, char()); }
+
+ void resize(size_type count, char ch)
+ {
+ std::string s;
+ s.reserve(count);
+ if (count <= this->size()) {
+ s.assign(this->data(), count);
+ } else {
+ s.assign(this->data(), this->size());
+ s.resize(count, ch);
+ }
+ *this = std::move(s);
+ }
+
+ void swap(String& other)
+ {
+ std::swap(this->string_, other.string_);
+ std::swap(this->view_, other.view_);
+ }
+
+ /** Return a substring starting at position 'pos' and
+ consisting of at most 'count' characters. */
+ String substr(size_type pos = 0, size_type count = npos) const;
+
+ template <typename T>
+ typename std::enable_if<AsStringView<T>::value, int>::type compare(
+ T&& s) const
+ {
+ return this->view_.compare(AsStringView<T>::view(std::forward<T>(s)));
+ }
+
+ int compare(size_type pos1, size_type count1, string_view v) const
+ {
+ return this->view_.compare(pos1, count1, v);
+ }
+
+ int compare(size_type pos1, size_type count1, string_view v, size_type pos2,
+ size_type count2) const
+ {
+ return this->view_.compare(pos1, count1, v, pos2, count2);
+ }
+
+ int compare(size_type pos1, size_type count1, const char* s) const
+ {
+ return this->view_.compare(pos1, count1, s);
+ }
+
+ int compare(size_type pos1, size_type count1, const char* s,
+ size_type count2) const
+ {
+ return this->view_.compare(pos1, count1, s, count2);
+ }
+
+ template <typename T>
+ typename std::enable_if<AsStringView<T>::value, size_type>::type find(
+ T&& s, size_type pos = 0) const
+ {
+ string_view v = AsStringView<T>::view(std::forward<T>(s));
+ return this->view_.find(v, pos);
+ }
+
+ size_type find(const char* s, size_type pos, size_type count) const
+ {
+ return this->view_.find(s, pos, count);
+ }
+
+ template <typename T>
+ typename std::enable_if<AsStringView<T>::value, size_type>::type rfind(
+ T&& s, size_type pos = npos) const
+ {
+ string_view v = AsStringView<T>::view(std::forward<T>(s));
+ return this->view_.rfind(v, pos);
+ }
+
+ size_type rfind(const char* s, size_type pos, size_type count) const
+ {
+ return this->view_.rfind(s, pos, count);
+ }
+
+ template <typename T>
+ typename std::enable_if<AsStringView<T>::value, size_type>::type
+ find_first_of(T&& s, size_type pos = 0) const
+ {
+ string_view v = AsStringView<T>::view(std::forward<T>(s));
+ return this->view_.find_first_of(v, pos);
+ }
+
+ size_type find_first_of(const char* s, size_type pos, size_type count) const
+ {
+ return this->view_.find_first_of(s, pos, count);
+ }
+
+ template <typename T>
+ typename std::enable_if<AsStringView<T>::value, size_type>::type
+ find_first_not_of(T&& s, size_type pos = 0) const
+ {
+ string_view v = AsStringView<T>::view(std::forward<T>(s));
+ return this->view_.find_first_not_of(v, pos);
+ }
+
+ size_type find_first_not_of(const char* s, size_type pos,
+ size_type count) const
+ {
+ return this->view_.find_first_not_of(s, pos, count);
+ }
+
+ template <typename T>
+ typename std::enable_if<AsStringView<T>::value, size_type>::type
+ find_last_of(T&& s, size_type pos = npos) const
+ {
+ string_view v = AsStringView<T>::view(std::forward<T>(s));
+ return this->view_.find_last_of(v, pos);
+ }
+
+ size_type find_last_of(const char* s, size_type pos, size_type count) const
+ {
+ return this->view_.find_last_of(s, pos, count);
+ }
+
+ template <typename T>
+ typename std::enable_if<AsStringView<T>::value, size_type>::type
+ find_last_not_of(T&& s, size_type pos = npos) const
+ {
+ string_view v = AsStringView<T>::view(std::forward<T>(s));
+ return this->view_.find_last_not_of(v, pos);
+ }
+
+ size_type find_last_not_of(const char* s, size_type pos,
+ size_type count) const
+ {
+ return this->view_.find_last_not_of(s, pos, count);
+ }
+
+private:
+ // Internal constructor to move from existing String.
+ String(String&& s, Private) noexcept
+ : String(std::move(s))
+ {
+ }
+
+ // Internal constructor for dynamically allocated string.
+ String(std::string&& s, Private);
+
+ // Internal constructor for view of statically allocated string.
+ String(string_view v, Private)
+ : view_(v)
+ {
+ }
+
+ void internally_mutate_to_stable_string();
+
+ std::shared_ptr<std::string const> string_;
+ string_view view_;
+};
+
+/**
+ * Trait for comparable types.
+ */
+template <typename T>
+struct IsComparable : std::false_type
+{
+};
+
+template <typename T>
+struct IsComparable<T&> : IsComparable<T>
+{
+};
+
+template <typename T>
+struct IsComparable<T const> : IsComparable<T>
+{
+};
+
+template <typename T>
+struct IsComparable<T const*> : IsComparable<T*>
+{
+};
+
+template <typename T, std::string::size_type N>
+struct IsComparable<T const[N]> : IsComparable<T[N]>
+{
+};
+
+template <>
+struct IsComparable<char*> : std::true_type
+{
+};
+
+template <std::string::size_type N>
+struct IsComparable<char[N]> : std::true_type
+{
+};
+
+template <>
+struct IsComparable<std::string> : std::true_type
+{
+};
+
+template <>
+struct IsComparable<char> : std::true_type
+{
+};
+
+/** comparison operators */
+inline bool operator==(const String& l, const String& r)
+{
+ return l.view() == r.view();
+}
+template <typename L>
+typename std::enable_if<IsComparable<L>::value, bool>::type operator==(
+ L&& l, const String& r)
+{
+ return AsStringView<L>::view(std::forward<L>(l)) == r.view();
+}
+template <typename R>
+typename std::enable_if<IsComparable<R>::value, bool>::type operator==(
+ const String& l, R&& r)
+{
+ return l.view() == AsStringView<R>::view(std::forward<R>(r));
+}
+
+inline bool operator!=(const String& l, const String& r)
+{
+ return l.view() != r.view();
+}
+template <typename L>
+typename std::enable_if<IsComparable<L>::value, bool>::type operator!=(
+ L&& l, const String& r)
+{
+ return AsStringView<L>::view(std::forward<L>(l)) != r.view();
+}
+template <typename R>
+typename std::enable_if<IsComparable<R>::value, bool>::type operator!=(
+ const String& l, R&& r)
+{
+ return l.view() != AsStringView<R>::view(std::forward<R>(r));
+}
+
+inline bool operator<(const String& l, const String& r)
+{
+ return l.view() < r.view();
+}
+template <typename L>
+typename std::enable_if<IsComparable<L>::value, bool>::type operator<(
+ L&& l, const String& r)
+{
+ return AsStringView<L>::view(std::forward<L>(l)) < r.view();
+}
+template <typename R>
+typename std::enable_if<IsComparable<R>::value, bool>::type operator<(
+ const String& l, R&& r)
+{
+ return l.view() < AsStringView<R>::view(std::forward<R>(r));
+}
+
+inline bool operator<=(const String& l, const String& r)
+{
+ return l.view() <= r.view();
+}
+template <typename L>
+typename std::enable_if<IsComparable<L>::value, bool>::type operator<=(
+ L&& l, const String& r)
+{
+ return AsStringView<L>::view(std::forward<L>(l)) <= r.view();
+}
+template <typename R>
+typename std::enable_if<IsComparable<R>::value, bool>::type operator<=(
+ const String& l, R&& r)
+{
+ return l.view() <= AsStringView<R>::view(std::forward<R>(r));
+}
+
+inline bool operator>(const String& l, const String& r)
+{
+ return l.view() > r.view();
+}
+template <typename L>
+typename std::enable_if<IsComparable<L>::value, bool>::type operator>(
+ L&& l, const String& r)
+{
+ return AsStringView<L>::view(std::forward<L>(l)) > r.view();
+}
+template <typename R>
+typename std::enable_if<IsComparable<R>::value, bool>::type operator>(
+ const String& l, R&& r)
+{
+ return l.view() > AsStringView<R>::view(std::forward<R>(r));
+}
+
+inline bool operator>=(const String& l, const String& r)
+{
+ return l.view() >= r.view();
+}
+template <typename L>
+typename std::enable_if<IsComparable<L>::value, bool>::type operator>=(
+ L&& l, const String& r)
+{
+ return AsStringView<L>::view(std::forward<L>(l)) >= r.view();
+}
+template <typename R>
+typename std::enable_if<IsComparable<R>::value, bool>::type operator>=(
+ const String& l, R&& r)
+{
+ return l.view() >= AsStringView<R>::view(std::forward<R>(r));
+}
+
+std::ostream& operator<<(std::ostream& os, String const& s);
+std::string& operator+=(std::string& self, String const& s);
+
+template <typename L, typename R>
+struct StringOpPlus
+{
+ L l;
+ R r;
+#if defined(__SUNPRO_CC)
+ StringOpPlus(L in_l, R in_r)
+ : l(in_l)
+ , r(in_r)
+ {
+ }
+#endif
+ operator std::string() const;
+ std::string::size_type size() const
+ {
+ return this->l.size() + this->r.size();
+ }
+};
+
+template <typename T>
+struct StringAdd
+{
+ static const bool value = AsStringView<T>::value;
+ using temp_type = string_view;
+ template <typename S>
+ static temp_type temp(S&& s)
+ {
+ return AsStringView<T>::view(std::forward<S>(s));
+ }
+};
+
+template <typename L, typename R>
+struct StringAdd<StringOpPlus<L, R>> : std::true_type
+{
+ using temp_type = StringOpPlus<L, R> const&;
+ static temp_type temp(temp_type s) { return s; }
+};
+
+template <typename L, typename R>
+StringOpPlus<L, R>::operator std::string() const
+{
+ std::string s;
+ s.reserve(this->size());
+ s += *this;
+ return s;
+}
+
+template <typename L, typename R>
+std::string& operator+=(std::string& s, StringOpPlus<L, R> const& a)
+{
+ s.reserve(s.size() + a.size());
+ s += a.l;
+ s += a.r;
+ return s;
+}
+
+template <typename L, typename R>
+String& operator+=(String& s, StringOpPlus<L, R> const& a)
+{
+ std::string r;
+ r.reserve(s.size() + a.size());
+ r.assign(s.data(), s.size());
+ r += a.l;
+ r += a.r;
+ s = std::move(r);
+ return s;
+}
+
+template <typename L, typename R>
+std::ostream& operator<<(std::ostream& os, StringOpPlus<L, R> const& a)
+{
+ return os << a.l << a.r;
+}
+
+template <typename L, typename R>
+struct IntoString<StringOpPlus<L, R>> : std::true_type
+{
+ static std::string into_string(StringOpPlus<L, R> const& a) { return a; }
+};
+
+template <typename L, typename R>
+typename std::enable_if<StringAdd<L>::value && StringAdd<R>::value,
+ StringOpPlus<typename StringAdd<L>::temp_type,
+ typename StringAdd<R>::temp_type>>::type
+operator+(L&& l, R&& r)
+{
+ return { StringAdd<L>::temp(std::forward<L>(l)),
+ StringAdd<R>::temp(std::forward<R>(r)) };
+}
+
+template <typename LL, typename LR, typename R>
+typename std::enable_if<AsStringView<R>::value, bool>::type operator==(
+ StringOpPlus<LL, LR> const& l, R&& r)
+{
+ return std::string(l) == AsStringView<R>::view(std::forward<R>(r));
+}
+
+template <typename L, typename RL, typename RR>
+typename std::enable_if<AsStringView<L>::value, bool>::type operator==(
+ L&& l, StringOpPlus<RL, RR> const& r)
+{
+ return AsStringView<L>::view(std::forward<L>(l)) == std::string(r);
+}
+
+} // namespace cm
+
+namespace std {
+
+template <>
+struct hash<cm::String>
+{
+ using argument_type = cm::String;
+ using result_type = size_t;
+
+ result_type operator()(argument_type const& s) const noexcept
+ {
+ result_type const h(std::hash<cm::string_view>{}(s.view()));
+ return h;
+ }
+};
+}
diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx
new file mode 100644
index 0000000..5bb6e7b
--- /dev/null
+++ b/Source/cmStringAlgorithms.cxx
@@ -0,0 +1,379 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmStringAlgorithms.h"
+
+#include <algorithm>
+#include <cerrno>
+#include <cstddef> // IWYU pragma: keep
+#include <cstdio>
+#include <cstdlib>
+#include <iterator>
+
+std::string cmTrimWhitespace(cm::string_view str)
+{
+ // XXX(clang-tidy): This declaration and the next cannot be `const auto*`
+ // because the qualification of `auto` is platform-dependent.
+ // NOLINTNEXTLINE(readability-qualified-auto)
+ auto start = str.begin();
+ while (start != str.end() && cmIsSpace(*start)) {
+ ++start;
+ }
+ if (start == str.end()) {
+ return std::string();
+ }
+ // NOLINTNEXTLINE(readability-qualified-auto)
+ auto stop = str.end() - 1;
+ while (cmIsSpace(*stop)) {
+ --stop;
+ }
+ return std::string(start, stop + 1);
+}
+
+std::string cmRemoveQuotes(cm::string_view str)
+{
+ // We process only strings that have two quotes at least.
+ // Also front() and back() are only defined behavior on non empty strings.
+ if (str.size() >= 2 && //
+ str.front() == '"' && //
+ str.back() == '"') {
+ // Remove a quote from the front and back
+ str.remove_prefix(1);
+ str.remove_suffix(1);
+ }
+ return std::string(str);
+}
+
+std::string cmEscapeQuotes(cm::string_view str)
+{
+ std::string result;
+ result.reserve(str.size());
+ for (const char ch : str) {
+ if (ch == '"') {
+ result += '\\';
+ }
+ result += ch;
+ }
+ return result;
+}
+
+std::vector<std::string> cmTokenize(cm::string_view str, cm::string_view sep)
+{
+ std::vector<std::string> tokens;
+ cm::string_view::size_type tokend = 0;
+
+ do {
+ cm::string_view::size_type tokstart = str.find_first_not_of(sep, tokend);
+ if (tokstart == cm::string_view::npos) {
+ break; // no more tokens
+ }
+ tokend = str.find_first_of(sep, tokstart);
+ if (tokend == cm::string_view::npos) {
+ tokens.emplace_back(str.substr(tokstart));
+ } else {
+ tokens.emplace_back(str.substr(tokstart, tokend - tokstart));
+ }
+ } while (tokend != cm::string_view::npos);
+
+ if (tokens.empty()) {
+ tokens.emplace_back();
+ }
+ return tokens;
+}
+
+void cmExpandList(cm::string_view arg, std::vector<std::string>& argsOut,
+ bool emptyArgs)
+{
+ // If argument is empty, it is an empty list.
+ if (!emptyArgs && arg.empty()) {
+ return;
+ }
+
+ // if there are no ; in the name then just copy the current string
+ if (arg.find(';') == cm::string_view::npos) {
+ argsOut.emplace_back(arg);
+ return;
+ }
+
+ std::string newArg;
+ // Break the string at non-escaped semicolons not nested in [].
+ int squareNesting = 0;
+ cm::string_view::iterator last = arg.begin();
+ cm::string_view::iterator const cend = arg.end();
+ for (cm::string_view::iterator c = last; c != cend; ++c) {
+ switch (*c) {
+ case '\\': {
+ // We only want to allow escaping of semicolons. Other
+ // escapes should not be processed here.
+ cm::string_view::iterator cnext = c + 1;
+ if ((cnext != cend) && *cnext == ';') {
+ newArg.append(last, c);
+ // Skip over the escape character
+ last = cnext;
+ c = cnext;
+ }
+ } break;
+ case '[': {
+ ++squareNesting;
+ } break;
+ case ']': {
+ --squareNesting;
+ } break;
+ case ';': {
+ // Break the string here if we are not nested inside square
+ // brackets.
+ if (squareNesting == 0) {
+ newArg.append(last, c);
+ // Skip over the semicolon
+ last = c + 1;
+ if (!newArg.empty() || emptyArgs) {
+ // Add the last argument if the string is not empty.
+ argsOut.push_back(newArg);
+ newArg.clear();
+ }
+ }
+ } break;
+ default: {
+ // Just append this character.
+ } break;
+ }
+ }
+ newArg.append(last, cend);
+ if (!newArg.empty() || emptyArgs) {
+ // Add the last argument if the string is not empty.
+ argsOut.push_back(std::move(newArg));
+ }
+}
+
+std::vector<std::string> cmExpandedList(cm::string_view arg, bool emptyArgs)
+{
+ std::vector<std::string> argsOut;
+ cmExpandList(arg, argsOut, emptyArgs);
+ return argsOut;
+}
+
+namespace {
+template <std::size_t N, typename T>
+inline void MakeDigits(cm::string_view& view, char (&digits)[N],
+ const char* pattern, T value)
+{
+ int res = std::snprintf(digits, N, pattern, value);
+ if (res > 0 && res < static_cast<int>(N)) {
+ view = cm::string_view(digits, static_cast<std::size_t>(res));
+ }
+}
+} // unnamed namespace
+
+cmAlphaNum::cmAlphaNum(int val)
+{
+ MakeDigits(this->View_, this->Digits_, "%i", val);
+}
+
+cmAlphaNum::cmAlphaNum(unsigned int val)
+{
+ MakeDigits(this->View_, this->Digits_, "%u", val);
+}
+
+cmAlphaNum::cmAlphaNum(long int val)
+{
+ MakeDigits(this->View_, this->Digits_, "%li", val);
+}
+
+cmAlphaNum::cmAlphaNum(unsigned long int val)
+{
+ MakeDigits(this->View_, this->Digits_, "%lu", val);
+}
+
+cmAlphaNum::cmAlphaNum(long long int val)
+{
+ MakeDigits(this->View_, this->Digits_, "%lli", val);
+}
+
+cmAlphaNum::cmAlphaNum(unsigned long long int val)
+{
+ MakeDigits(this->View_, this->Digits_, "%llu", val);
+}
+
+cmAlphaNum::cmAlphaNum(float val)
+{
+ MakeDigits(this->View_, this->Digits_, "%g", static_cast<double>(val));
+}
+
+cmAlphaNum::cmAlphaNum(double val)
+{
+ MakeDigits(this->View_, this->Digits_, "%g", val);
+}
+
+std::string cmCatViews(std::initializer_list<cm::string_view> views)
+{
+ std::size_t total_size = 0;
+ for (cm::string_view const& view : views) {
+ total_size += view.size();
+ }
+
+ std::string result(total_size, '\0');
+ std::string::iterator sit = result.begin();
+ for (cm::string_view const& view : views) {
+ sit = std::copy_n(view.data(), view.size(), sit);
+ }
+ return result;
+}
+
+bool cmIsInternallyOn(cm::string_view val)
+{
+ return (val.size() == 4) && //
+ (val[0] == 'I' || val[0] == 'i') && //
+ (val[1] == '_') && //
+ (val[2] == 'O' || val[2] == 'o') && //
+ (val[3] == 'N' || val[3] == 'n');
+}
+
+bool cmIsNOTFOUND(cm::string_view val)
+{
+ return (val == "NOTFOUND") || cmHasLiteralSuffix(val, "-NOTFOUND");
+}
+
+bool cmIsOn(cm::string_view val)
+{
+ switch (val.size()) {
+ case 1:
+ return val[0] == '1' || val[0] == 'Y' || val[0] == 'y';
+ case 2:
+ return //
+ (val[0] == 'O' || val[0] == 'o') && //
+ (val[1] == 'N' || val[1] == 'n');
+ case 3:
+ return //
+ (val[0] == 'Y' || val[0] == 'y') && //
+ (val[1] == 'E' || val[1] == 'e') && //
+ (val[2] == 'S' || val[2] == 's');
+ case 4:
+ return //
+ (val[0] == 'T' || val[0] == 't') && //
+ (val[1] == 'R' || val[1] == 'r') && //
+ (val[2] == 'U' || val[2] == 'u') && //
+ (val[3] == 'E' || val[3] == 'e');
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool cmIsOff(cm::string_view val)
+{
+ switch (val.size()) {
+ case 0:
+ return true;
+ case 1:
+ return val[0] == '0' || val[0] == 'N' || val[0] == 'n';
+ case 2:
+ return //
+ (val[0] == 'N' || val[0] == 'n') && //
+ (val[1] == 'O' || val[1] == 'o');
+ case 3:
+ return //
+ (val[0] == 'O' || val[0] == 'o') && //
+ (val[1] == 'F' || val[1] == 'f') && //
+ (val[2] == 'F' || val[2] == 'f');
+ case 5:
+ return //
+ (val[0] == 'F' || val[0] == 'f') && //
+ (val[1] == 'A' || val[1] == 'a') && //
+ (val[2] == 'L' || val[2] == 'l') && //
+ (val[3] == 'S' || val[3] == 's') && //
+ (val[4] == 'E' || val[4] == 'e');
+ case 6:
+ return //
+ (val[0] == 'I' || val[0] == 'i') && //
+ (val[1] == 'G' || val[1] == 'g') && //
+ (val[2] == 'N' || val[2] == 'n') && //
+ (val[3] == 'O' || val[3] == 'o') && //
+ (val[4] == 'R' || val[4] == 'r') && //
+ (val[5] == 'E' || val[5] == 'e');
+ default:
+ break;
+ }
+
+ return cmIsNOTFOUND(val);
+}
+
+bool cmStrToLong(const char* str, long* value)
+{
+ errno = 0;
+ char* endp;
+ *value = strtol(str, &endp, 10);
+ return (*endp == '\0') && (endp != str) && (errno == 0);
+}
+
+bool cmStrToLong(std::string const& str, long* value)
+{
+ return cmStrToLong(str.c_str(), value);
+}
+
+bool cmStrToULong(const char* str, unsigned long* value)
+{
+ errno = 0;
+ char* endp;
+ while (cmIsSpace(*str)) {
+ ++str;
+ }
+ if (*str == '-') {
+ return false;
+ }
+ *value = strtoul(str, &endp, 10);
+ return (*endp == '\0') && (endp != str) && (errno == 0);
+}
+
+bool cmStrToULong(std::string const& str, unsigned long* value)
+{
+ return cmStrToULong(str.c_str(), value);
+}
+
+template <typename Range>
+std::size_t getJoinedLength(Range const& rng, cm::string_view separator)
+{
+ std::size_t rangeLength{};
+ for (auto const& item : rng) {
+ rangeLength += item.size();
+ }
+
+ auto const separatorsLength = (rng.size() - 1) * separator.size();
+
+ return rangeLength + separatorsLength;
+}
+
+template <typename Range>
+std::string cmJoinImpl(Range const& rng, cm::string_view separator,
+ cm::string_view initial)
+{
+ if (rng.empty()) {
+ return { std::begin(initial), std::end(initial) };
+ }
+
+ std::string result;
+ result.reserve(initial.size() + getJoinedLength(rng, separator));
+ result.append(std::begin(initial), std::end(initial));
+
+ auto begin = std::begin(rng);
+ auto end = std::end(rng);
+ result += *begin;
+
+ for (++begin; begin != end; ++begin) {
+ result.append(std::begin(separator), std::end(separator));
+ result += *begin;
+ }
+
+ return result;
+}
+
+std::string cmJoin(std::vector<std::string> const& rng,
+ cm::string_view separator, cm::string_view initial)
+{
+ return cmJoinImpl(rng, separator, initial);
+}
+
+std::string cmJoin(cmStringRange const& rng, cm::string_view separator,
+ cm::string_view initial)
+{
+ return cmJoinImpl(rng, separator, initial);
+}
diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h
new file mode 100644
index 0000000..6b458ec
--- /dev/null
+++ b/Source/cmStringAlgorithms.h
@@ -0,0 +1,325 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <cctype>
+#include <cstring>
+#include <initializer_list>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmRange.h"
+
+/** String range type. */
+using cmStringRange = cmRange<std::vector<std::string>::const_iterator>;
+
+/** Check for non-empty string. */
+inline bool cmNonempty(const char* str)
+{
+ return str && *str;
+}
+inline bool cmNonempty(cm::string_view str)
+{
+ return !str.empty();
+}
+inline bool cmNonempty(std::string const* str)
+{
+ return str && !str->empty();
+}
+
+/** Returns length of a literal string. */
+template <size_t N>
+constexpr size_t cmStrLen(const char (&/*str*/)[N])
+{
+ return N - 1;
+}
+
+/** Callable string comparison struct. */
+struct cmStrCmp
+{
+ cmStrCmp(std::string str)
+ : Test_(std::move(str))
+ {
+ }
+
+ bool operator()(cm::string_view sv) const { return this->Test_ == sv; }
+
+private:
+ std::string const Test_;
+};
+
+/** Returns true if the character @a ch is a whitespace character. **/
+inline bool cmIsSpace(char ch)
+{
+ return ((ch & 0x80) == 0) && std::isspace(ch);
+}
+
+/** Returns a string that has whitespace removed from the start and the end. */
+std::string cmTrimWhitespace(cm::string_view str);
+
+/** Returns a string that has quotes removed from the start and the end. */
+std::string cmRemoveQuotes(cm::string_view str);
+
+/** Escape quotes in a string. */
+std::string cmEscapeQuotes(cm::string_view str);
+
+/** Joins elements of a range with separator into a single string. */
+template <typename Range>
+std::string cmJoin(Range const& rng, cm::string_view separator)
+{
+ if (rng.empty()) {
+ return std::string();
+ }
+
+ std::ostringstream os;
+ auto it = rng.begin();
+ auto const end = rng.end();
+ os << *it;
+ while (++it != end) {
+ os << separator << *it;
+ }
+ return os.str();
+}
+
+/**
+ * Faster overloads for std::string ranges.
+ * If @a initial is provided, it prepends the resulted string without
+ * @a separator between them.
+ */
+std::string cmJoin(std::vector<std::string> const& rng,
+ cm::string_view separator, cm::string_view initial = {});
+
+std::string cmJoin(cmStringRange const& rng, cm::string_view separator,
+ cm::string_view initial = {});
+
+/** Extract tokens that are separated by any of the characters in @a sep. */
+std::vector<std::string> cmTokenize(cm::string_view str, cm::string_view sep);
+
+/**
+ * Expand the ; separated string @a arg into multiple arguments.
+ * All found arguments are appended to @a argsOut.
+ */
+void cmExpandList(cm::string_view arg, std::vector<std::string>& argsOut,
+ bool emptyArgs = false);
+
+/**
+ * Expand out any arguments in the string range [@a first, @a last) that have
+ * ; separated strings into multiple arguments. All found arguments are
+ * appended to @a argsOut.
+ */
+template <class InputIt>
+void cmExpandLists(InputIt first, InputIt last,
+ std::vector<std::string>& argsOut)
+{
+ for (; first != last; ++first) {
+ cmExpandList(*first, argsOut);
+ }
+}
+
+/**
+ * Same as cmExpandList but a new vector is created containing
+ * the expanded arguments from the string @a arg.
+ */
+std::vector<std::string> cmExpandedList(cm::string_view arg,
+ bool emptyArgs = false);
+
+/**
+ * Same as cmExpandList but a new vector is created containing the expanded
+ * versions of all arguments in the string range [@a first, @a last).
+ */
+template <class InputIt>
+std::vector<std::string> cmExpandedLists(InputIt first, InputIt last)
+{
+ std::vector<std::string> argsOut;
+ for (; first != last; ++first) {
+ cmExpandList(*first, argsOut);
+ }
+ return argsOut;
+}
+
+/** Concatenate string pieces into a single string. */
+std::string cmCatViews(std::initializer_list<cm::string_view> views);
+
+/** Utility class for cmStrCat. */
+class cmAlphaNum
+{
+public:
+ cmAlphaNum(cm::string_view view)
+ : View_(view)
+ {
+ }
+ cmAlphaNum(std::string const& str)
+ : View_(str)
+ {
+ }
+ cmAlphaNum(const char* str)
+ : View_(str)
+ {
+ }
+ cmAlphaNum(char ch)
+ : View_(this->Digits_, 1)
+ {
+ this->Digits_[0] = ch;
+ }
+ cmAlphaNum(int val);
+ cmAlphaNum(unsigned int val);
+ cmAlphaNum(long int val);
+ cmAlphaNum(unsigned long int val);
+ cmAlphaNum(long long int val);
+ cmAlphaNum(unsigned long long int val);
+ cmAlphaNum(float val);
+ cmAlphaNum(double val);
+
+ cm::string_view View() const { return this->View_; }
+
+private:
+ cm::string_view View_;
+ char Digits_[32];
+};
+
+/** Concatenate string pieces and numbers into a single string. */
+template <typename... AV>
+inline std::string cmStrCat(cmAlphaNum const& a, cmAlphaNum const& b,
+ AV const&... args)
+{
+ return cmCatViews(
+ { a.View(), b.View(), static_cast<cmAlphaNum const&>(args).View()... });
+}
+
+/** Joins wrapped elements of a range with separator into a single string. */
+template <typename Range>
+std::string cmWrap(cm::string_view prefix, Range const& rng,
+ cm::string_view suffix, cm::string_view sep)
+{
+ if (rng.empty()) {
+ return std::string();
+ }
+ return cmCatViews(
+ { prefix, cmJoin(rng, cmCatViews({ suffix, sep, prefix })), suffix });
+}
+
+/** Joins wrapped elements of a range with separator into a single string. */
+template <typename Range>
+std::string cmWrap(char prefix, Range const& rng, char suffix,
+ cm::string_view sep)
+{
+ return cmWrap(cm::string_view(&prefix, 1), rng, cm::string_view(&suffix, 1),
+ sep);
+}
+
+/**
+ * Does a string indicates that CMake/CPack/CTest internally
+ * forced this value. This is not the same as On, but this
+ * may be considered as "internally switched on".
+ */
+bool cmIsInternallyOn(cm::string_view val);
+inline bool cmIsInternallyOn(const char* val)
+{
+ if (!val) {
+ return false;
+ }
+ return cmIsInternallyOn(cm::string_view(val));
+}
+
+/** Return true if value is NOTFOUND or ends in -NOTFOUND. */
+bool cmIsNOTFOUND(cm::string_view val);
+
+/**
+ * Does a string indicate a true or ON value? This is not the same as ifdef.
+ */
+bool cmIsOn(cm::string_view val);
+inline bool cmIsOn(const char* val)
+{
+ return val && cmIsOn(cm::string_view(val));
+}
+inline bool cmIsOn(std::string const* val)
+{
+ return val && cmIsOn(*val);
+}
+
+/**
+ * Does a string indicate a false or off value ? Note that this is
+ * not the same as !IsOn(...) because there are a number of
+ * ambiguous values such as "/usr/local/bin" a path will result in
+ * IsON and IsOff both returning false. Note that the special path
+ * NOTFOUND, *-NOTFOUND or IGNORE will cause IsOff to return true.
+ */
+bool cmIsOff(cm::string_view val);
+inline bool cmIsOff(const char* val)
+{
+ return !val || cmIsOff(cm::string_view(val));
+}
+inline bool cmIsOff(std::string const* val)
+{
+ return !val || cmIsOff(*val);
+}
+
+/** Returns true if string @a str starts with the character @a prefix. */
+inline bool cmHasPrefix(cm::string_view str, char prefix)
+{
+ return !str.empty() && (str.front() == prefix);
+}
+
+/** Returns true if string @a str starts with string @a prefix. */
+inline bool cmHasPrefix(cm::string_view str, cm::string_view prefix)
+{
+ return str.compare(0, prefix.size(), prefix) == 0;
+}
+
+/** Returns true if string @a str starts with string @a prefix. */
+template <size_t N>
+inline bool cmHasLiteralPrefix(cm::string_view str, const char (&prefix)[N])
+{
+ return cmHasPrefix(str, cm::string_view(prefix, N - 1));
+}
+
+/** Returns true if string @a str ends with the character @a suffix. */
+inline bool cmHasSuffix(cm::string_view str, char suffix)
+{
+ return !str.empty() && (str.back() == suffix);
+}
+
+/** Returns true if string @a str ends with string @a suffix. */
+inline bool cmHasSuffix(cm::string_view str, cm::string_view suffix)
+{
+ return str.size() >= suffix.size() &&
+ str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
+}
+
+/** Returns true if string @a str ends with string @a suffix. */
+template <size_t N>
+inline bool cmHasLiteralSuffix(cm::string_view str, const char (&suffix)[N])
+{
+ return cmHasSuffix(str, cm::string_view(suffix, N - 1));
+}
+
+/** Removes an existing suffix character of from the string @a str. */
+inline void cmStripSuffixIfExists(std::string& str, char suffix)
+{
+ if (cmHasSuffix(str, suffix)) {
+ str.pop_back();
+ }
+}
+
+/** Removes an existing suffix string of from the string @a str. */
+inline void cmStripSuffixIfExists(std::string& str, cm::string_view suffix)
+{
+ if (cmHasSuffix(str, suffix)) {
+ str.resize(str.size() - suffix.size());
+ }
+}
+
+/** Converts a string to long. Expects that the whole string is an integer. */
+bool cmStrToLong(const char* str, long* value);
+bool cmStrToLong(std::string const& str, long* value);
+
+/** Converts a string to unsigned long. Expects that the whole string is an
+ * integer */
+bool cmStrToULong(const char* str, unsigned long* value);
+bool cmStrToULong(std::string const& str, unsigned long* value);
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
new file mode 100644
index 0000000..5fa309d
--- /dev/null
+++ b/Source/cmStringCommand.cxx
@@ -0,0 +1,1280 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
+#define _SCL_SECURE_NO_WARNINGS
+
+#include "cmStringCommand.h"
+
+#include <algorithm>
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <initializer_list>
+#include <limits>
+#include <memory>
+#include <stdexcept>
+#include <utility>
+
+#include <cm/iterator>
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+#include <cm3p/json/writer.h>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCryptoHash.h"
+#include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmStringReplaceHelper.h"
+#include "cmSubcommandTable.h"
+#include "cmSystemTools.h"
+#include "cmTimestamp.h"
+#include "cmUuid.h"
+
+namespace {
+
+bool RegexMatch(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
+bool RegexMatchAll(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
+bool RegexReplace(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
+
+bool joinImpl(std::vector<std::string> const& args, std::string const& glue,
+ size_t varIdx, cmMakefile& makefile);
+
+bool HandleHashCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ if (args.size() != 3) {
+ status.SetError(
+ cmStrCat(args[0], " requires an output variable and an input string"));
+ return false;
+ }
+
+ std::unique_ptr<cmCryptoHash> hash(cmCryptoHash::New(args[0]));
+ if (hash) {
+ std::string out = hash->HashString(args[2]);
+ status.GetMakefile().AddDefinition(args[1], out);
+ return true;
+ }
+ return false;
+#else
+ status.SetError(cmStrCat(args[0], " not available during bootstrap"));
+ return false;
+#endif
+}
+
+bool HandleToUpperLowerCommand(std::vector<std::string> const& args,
+ bool toUpper, cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("no output variable specified");
+ return false;
+ }
+
+ std::string const& outvar = args[2];
+ std::string output;
+
+ if (toUpper) {
+ output = cmSystemTools::UpperCase(args[1]);
+ } else {
+ output = cmSystemTools::LowerCase(args[1]);
+ }
+
+ // Store the output in the provided variable.
+ status.GetMakefile().AddDefinition(outvar, output);
+ return true;
+}
+
+bool HandleToUpperCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleToUpperLowerCommand(args, true, status);
+}
+
+bool HandleToLowerCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleToUpperLowerCommand(args, false, status);
+}
+
+bool HandleAsciiCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("No output variable specified");
+ return false;
+ }
+ std::string::size_type cc;
+ std::string const& outvar = args.back();
+ std::string output;
+ for (cc = 1; cc < args.size() - 1; cc++) {
+ int ch = atoi(args[cc].c_str());
+ if (ch > 0 && ch < 256) {
+ output += static_cast<char>(ch);
+ } else {
+ std::string error =
+ cmStrCat("Character with code ", args[cc], " does not exist.");
+ status.SetError(error);
+ return false;
+ }
+ }
+ // Store the output in the provided variable.
+ status.GetMakefile().AddDefinition(outvar, output);
+ return true;
+}
+
+bool HandleHexCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError("Incorrect number of arguments");
+ return false;
+ }
+ auto const& instr = args[1];
+ auto const& outvar = args[2];
+ std::string output(instr.size() * 2, ' ');
+
+ std::string::size_type hexIndex = 0;
+ for (auto const& c : instr) {
+ sprintf(&output[hexIndex], "%.2x", static_cast<unsigned char>(c) & 0xFF);
+ hexIndex += 2;
+ }
+
+ status.GetMakefile().AddDefinition(outvar, output);
+ return true;
+}
+
+bool HandleConfigureCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("No input string specified.");
+ return false;
+ }
+ if (args.size() < 3) {
+ status.SetError("No output variable specified.");
+ return false;
+ }
+
+ // Parse options.
+ bool escapeQuotes = false;
+ bool atOnly = false;
+ for (unsigned int i = 3; i < args.size(); ++i) {
+ if (args[i] == "@ONLY") {
+ atOnly = true;
+ } else if (args[i] == "ESCAPE_QUOTES") {
+ escapeQuotes = true;
+ } else {
+ status.SetError(cmStrCat("Unrecognized argument \"", args[i], "\""));
+ return false;
+ }
+ }
+
+ // Configure the string.
+ std::string output;
+ status.GetMakefile().ConfigureString(args[1], output, atOnly, escapeQuotes);
+
+ // Store the output in the provided variable.
+ status.GetMakefile().AddDefinition(args[2], output);
+
+ return true;
+}
+
+bool HandleRegexCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("sub-command REGEX requires a mode to be specified.");
+ return false;
+ }
+ std::string const& mode = args[1];
+ if (mode == "MATCH") {
+ if (args.size() < 5) {
+ status.SetError("sub-command REGEX, mode MATCH needs "
+ "at least 5 arguments total to command.");
+ return false;
+ }
+ return RegexMatch(args, status);
+ }
+ if (mode == "MATCHALL") {
+ if (args.size() < 5) {
+ status.SetError("sub-command REGEX, mode MATCHALL needs "
+ "at least 5 arguments total to command.");
+ return false;
+ }
+ return RegexMatchAll(args, status);
+ }
+ if (mode == "REPLACE") {
+ if (args.size() < 6) {
+ status.SetError("sub-command REGEX, mode REPLACE needs "
+ "at least 6 arguments total to command.");
+ return false;
+ }
+ return RegexReplace(args, status);
+ }
+
+ std::string e = "sub-command REGEX does not recognize mode " + mode;
+ status.SetError(e);
+ return false;
+}
+
+bool RegexMatch(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ //"STRING(REGEX MATCH <regular_expression> <output variable>
+ // <input> [<input>...])\n";
+ std::string const& regex = args[2];
+ std::string const& outvar = args[3];
+
+ status.GetMakefile().ClearMatches();
+ // Compile the regular expression.
+ cmsys::RegularExpression re;
+ if (!re.compile(regex)) {
+ std::string e =
+ "sub-command REGEX, mode MATCH failed to compile regex \"" + regex +
+ "\".";
+ status.SetError(e);
+ return false;
+ }
+
+ // Concatenate all the last arguments together.
+ std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
+
+ // Scan through the input for all matches.
+ std::string output;
+ if (re.find(input)) {
+ status.GetMakefile().StoreMatches(re);
+ std::string::size_type l = re.start();
+ std::string::size_type r = re.end();
+ if (r - l == 0) {
+ std::string e = "sub-command REGEX, mode MATCH regex \"" + regex +
+ "\" matched an empty string.";
+ status.SetError(e);
+ return false;
+ }
+ output = input.substr(l, r - l);
+ }
+
+ // Store the output in the provided variable.
+ status.GetMakefile().AddDefinition(outvar, output);
+ return true;
+}
+
+bool RegexMatchAll(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ //"STRING(REGEX MATCHALL <regular_expression> <output variable> <input>
+ // [<input>...])\n";
+ std::string const& regex = args[2];
+ std::string const& outvar = args[3];
+
+ status.GetMakefile().ClearMatches();
+ // Compile the regular expression.
+ cmsys::RegularExpression re;
+ if (!re.compile(regex)) {
+ std::string e =
+ "sub-command REGEX, mode MATCHALL failed to compile regex \"" + regex +
+ "\".";
+ status.SetError(e);
+ return false;
+ }
+
+ // Concatenate all the last arguments together.
+ std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
+
+ // Scan through the input for all matches.
+ std::string output;
+ const char* p = input.c_str();
+ while (re.find(p)) {
+ status.GetMakefile().ClearMatches();
+ status.GetMakefile().StoreMatches(re);
+ std::string::size_type l = re.start();
+ std::string::size_type r = re.end();
+ if (r - l == 0) {
+ std::string e = "sub-command REGEX, mode MATCHALL regex \"" + regex +
+ "\" matched an empty string.";
+ status.SetError(e);
+ return false;
+ }
+ if (!output.empty()) {
+ output += ";";
+ }
+ output += std::string(p + l, r - l);
+ p += r;
+ }
+
+ // Store the output in the provided variable.
+ status.GetMakefile().AddDefinition(outvar, output);
+ return true;
+}
+
+bool RegexReplace(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ //"STRING(REGEX REPLACE <regular_expression> <replace_expression>
+ // <output variable> <input> [<input>...])\n"
+ std::string const& regex = args[2];
+ std::string const& replace = args[3];
+ std::string const& outvar = args[4];
+ cmStringReplaceHelper replaceHelper(regex, replace, &status.GetMakefile());
+
+ if (!replaceHelper.IsReplaceExpressionValid()) {
+ status.SetError(
+ "sub-command REGEX, mode REPLACE: " + replaceHelper.GetError() + ".");
+ return false;
+ }
+
+ status.GetMakefile().ClearMatches();
+
+ if (!replaceHelper.IsRegularExpressionValid()) {
+ std::string e =
+ "sub-command REGEX, mode REPLACE failed to compile regex \"" + regex +
+ "\".";
+ status.SetError(e);
+ return false;
+ }
+
+ // Concatenate all the last arguments together.
+ const std::string input =
+ cmJoin(cmMakeRange(args).advance(5), std::string());
+ std::string output;
+
+ if (!replaceHelper.Replace(input, output)) {
+ status.SetError(
+ "sub-command REGEX, mode REPLACE: " + replaceHelper.GetError() + ".");
+ return false;
+ }
+
+ // Store the output in the provided variable.
+ status.GetMakefile().AddDefinition(outvar, output);
+ return true;
+}
+
+bool HandleFindCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // check if all required parameters were passed
+ if (args.size() < 4 || args.size() > 5) {
+ status.SetError("sub-command FIND requires 3 or 4 parameters.");
+ return false;
+ }
+
+ // check if the reverse flag was set or not
+ bool reverseMode = false;
+ if (args.size() == 5 && args[4] == "REVERSE") {
+ reverseMode = true;
+ }
+
+ // if we have 5 arguments the last one must be REVERSE
+ if (args.size() == 5 && args[4] != "REVERSE") {
+ status.SetError("sub-command FIND: unknown last parameter");
+ return false;
+ }
+
+ // local parameter names.
+ const std::string& sstring = args[1];
+ const std::string& schar = args[2];
+ const std::string& outvar = args[3];
+
+ // ensure that the user cannot accidentally specify REVERSE as a variable
+ if (outvar == "REVERSE") {
+ status.SetError("sub-command FIND does not allow one to select REVERSE as "
+ "the output variable. "
+ "Maybe you missed the actual output variable?");
+ return false;
+ }
+
+ // try to find the character and return its position
+ size_t pos;
+ if (!reverseMode) {
+ pos = sstring.find(schar);
+ } else {
+ pos = sstring.rfind(schar);
+ }
+ if (std::string::npos != pos) {
+ status.GetMakefile().AddDefinition(outvar, std::to_string(pos));
+ return true;
+ }
+
+ // the character was not found, but this is not really an error
+ status.GetMakefile().AddDefinition(outvar, "-1");
+ return true;
+}
+
+bool HandleCompareCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("sub-command COMPARE requires a mode to be specified.");
+ return false;
+ }
+ std::string const& mode = args[1];
+ if ((mode == "EQUAL") || (mode == "NOTEQUAL") || (mode == "LESS") ||
+ (mode == "LESS_EQUAL") || (mode == "GREATER") ||
+ (mode == "GREATER_EQUAL")) {
+ if (args.size() < 5) {
+ std::string e =
+ cmStrCat("sub-command COMPARE, mode ", mode,
+ " needs at least 5 arguments total to command.");
+ status.SetError(e);
+ return false;
+ }
+
+ const std::string& left = args[2];
+ const std::string& right = args[3];
+ const std::string& outvar = args[4];
+ bool result;
+ if (mode == "LESS") {
+ result = (left < right);
+ } else if (mode == "LESS_EQUAL") {
+ result = (left <= right);
+ } else if (mode == "GREATER") {
+ result = (left > right);
+ } else if (mode == "GREATER_EQUAL") {
+ result = (left >= right);
+ } else if (mode == "EQUAL") {
+ result = (left == right);
+ } else // if(mode == "NOTEQUAL")
+ {
+ result = !(left == right);
+ }
+ if (result) {
+ status.GetMakefile().AddDefinition(outvar, "1");
+ } else {
+ status.GetMakefile().AddDefinition(outvar, "0");
+ }
+ return true;
+ }
+ std::string e = "sub-command COMPARE does not recognize mode " + mode;
+ status.SetError(e);
+ return false;
+}
+
+bool HandleReplaceCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 5) {
+ status.SetError("sub-command REPLACE requires at least four arguments.");
+ return false;
+ }
+
+ const std::string& matchExpression = args[1];
+ const std::string& replaceExpression = args[2];
+ const std::string& variableName = args[3];
+
+ std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
+
+ cmsys::SystemTools::ReplaceString(input, matchExpression.c_str(),
+ replaceExpression.c_str());
+
+ status.GetMakefile().AddDefinition(variableName, input);
+ return true;
+}
+
+bool HandleSubstringCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 5) {
+ status.SetError("sub-command SUBSTRING requires four arguments.");
+ return false;
+ }
+
+ const std::string& stringValue = args[1];
+ int begin = atoi(args[2].c_str());
+ int end = atoi(args[3].c_str());
+ const std::string& variableName = args[4];
+
+ size_t stringLength = stringValue.size();
+ int intStringLength = static_cast<int>(stringLength);
+ if (begin < 0 || begin > intStringLength) {
+ status.SetError(
+ cmStrCat("begin index: ", begin, " is out of range 0 - ", stringLength));
+ return false;
+ }
+ if (end < -1) {
+ status.SetError(cmStrCat("end index: ", end, " should be -1 or greater"));
+ return false;
+ }
+
+ status.GetMakefile().AddDefinition(variableName,
+ stringValue.substr(begin, end));
+ return true;
+}
+
+bool HandleLengthCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError("sub-command LENGTH requires two arguments.");
+ return false;
+ }
+
+ const std::string& stringValue = args[1];
+ const std::string& variableName = args[2];
+
+ size_t length = stringValue.size();
+ char buffer[1024];
+ sprintf(buffer, "%d", static_cast<int>(length));
+
+ status.GetMakefile().AddDefinition(variableName, buffer);
+ return true;
+}
+
+bool HandleAppendCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("sub-command APPEND requires at least one argument.");
+ return false;
+ }
+
+ // Skip if nothing to append.
+ if (args.size() < 3) {
+ return true;
+ }
+
+ auto const& variableName = args[1];
+
+ cm::string_view oldView{ status.GetMakefile().GetSafeDefinition(
+ variableName) };
+
+ auto const newValue = cmJoin(cmMakeRange(args).advance(2), {}, oldView);
+ status.GetMakefile().AddDefinition(variableName, newValue);
+
+ return true;
+}
+
+bool HandlePrependCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("sub-command PREPEND requires at least one argument.");
+ return false;
+ }
+
+ // Skip if nothing to prepend.
+ if (args.size() < 3) {
+ return true;
+ }
+
+ const std::string& variable = args[1];
+
+ std::string value = cmJoin(cmMakeRange(args).advance(2), std::string());
+ cmProp oldValue = status.GetMakefile().GetDefinition(variable);
+ if (oldValue) {
+ value += *oldValue;
+ }
+ status.GetMakefile().AddDefinition(variable, value);
+ return true;
+}
+
+bool HandleConcatCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("sub-command CONCAT requires at least one argument.");
+ return false;
+ }
+
+ return joinImpl(args, std::string(), 1, status.GetMakefile());
+}
+
+bool HandleJoinCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("sub-command JOIN requires at least two arguments.");
+ return false;
+ }
+
+ return joinImpl(args, args[1], 2, status.GetMakefile());
+}
+
+bool joinImpl(std::vector<std::string> const& args, std::string const& glue,
+ const size_t varIdx, cmMakefile& makefile)
+{
+ std::string const& variableName = args[varIdx];
+ // NOTE Items to concat/join placed right after the variable for
+ // both `CONCAT` and `JOIN` sub-commands.
+ std::string value = cmJoin(cmMakeRange(args).advance(varIdx + 1), glue);
+
+ makefile.AddDefinition(variableName, value);
+ return true;
+}
+
+bool HandleMakeCIdentifierCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError("sub-command MAKE_C_IDENTIFIER requires two arguments.");
+ return false;
+ }
+
+ const std::string& input = args[1];
+ const std::string& variableName = args[2];
+
+ status.GetMakefile().AddDefinition(variableName,
+ cmSystemTools::MakeCidentifier(input));
+ return true;
+}
+
+bool HandleGenexStripCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError("sub-command GENEX_STRIP requires two arguments.");
+ return false;
+ }
+
+ const std::string& input = args[1];
+
+ std::string result = cmGeneratorExpression::Preprocess(
+ input, cmGeneratorExpression::StripAllGeneratorExpressions);
+
+ const std::string& variableName = args[2];
+
+ status.GetMakefile().AddDefinition(variableName, result);
+ return true;
+}
+
+bool HandleStripCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() != 3) {
+ status.SetError("sub-command STRIP requires two arguments.");
+ return false;
+ }
+
+ const std::string& stringValue = args[1];
+ const std::string& variableName = args[2];
+ size_t inStringLength = stringValue.size();
+ size_t startPos = inStringLength + 1;
+ size_t endPos = 0;
+ const char* ptr = stringValue.c_str();
+ size_t cc;
+ for (cc = 0; cc < inStringLength; ++cc) {
+ if (!isspace(*ptr)) {
+ if (startPos > inStringLength) {
+ startPos = cc;
+ }
+ endPos = cc;
+ }
+ ++ptr;
+ }
+
+ size_t outLength = 0;
+
+ // if the input string didn't contain any non-space characters, return
+ // an empty string
+ if (startPos > inStringLength) {
+ outLength = 0;
+ startPos = 0;
+ } else {
+ outLength = endPos - startPos + 1;
+ }
+
+ status.GetMakefile().AddDefinition(variableName,
+ stringValue.substr(startPos, outLength));
+ return true;
+}
+
+bool HandleRepeatCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ cmMakefile& makefile = status.GetMakefile();
+
+ // `string(REPEAT "<str>" <times> OUTPUT_VARIABLE)`
+ enum ArgPos : std::size_t
+ {
+ SUB_COMMAND,
+ VALUE,
+ TIMES,
+ OUTPUT_VARIABLE,
+ TOTAL_ARGS
+ };
+
+ if (args.size() != ArgPos::TOTAL_ARGS) {
+ makefile.IssueMessage(MessageType::FATAL_ERROR,
+ "sub-command REPEAT requires three arguments.");
+ return true;
+ }
+
+ unsigned long times;
+ if (!cmStrToULong(args[ArgPos::TIMES], &times)) {
+ makefile.IssueMessage(MessageType::FATAL_ERROR,
+ "repeat count is not a positive number.");
+ return true;
+ }
+
+ const auto& stringValue = args[ArgPos::VALUE];
+ const auto& variableName = args[ArgPos::OUTPUT_VARIABLE];
+ const auto inStringLength = stringValue.size();
+
+ std::string result;
+ switch (inStringLength) {
+ case 0u:
+ // Nothing to do for zero length input strings
+ break;
+ case 1u:
+ // NOTE If the string to repeat consists of the only character,
+ // use the appropriate constructor.
+ result = std::string(times, stringValue[0]);
+ break;
+ default:
+ result = std::string(inStringLength * times, char{});
+ for (auto i = 0u; i < times; ++i) {
+ std::copy(cm::cbegin(stringValue), cm::cend(stringValue),
+ &result[i * inStringLength]);
+ }
+ break;
+ }
+
+ makefile.AddDefinition(variableName, result);
+ return true;
+}
+
+bool HandleRandomCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2 || args.size() == 3 || args.size() == 5) {
+ status.SetError("sub-command RANDOM requires at least one argument.");
+ return false;
+ }
+
+ static bool seeded = false;
+ bool force_seed = false;
+ unsigned int seed = 0;
+ int length = 5;
+ const char cmStringCommandDefaultAlphabet[] = "qwertyuiopasdfghjklzxcvbnm"
+ "QWERTYUIOPASDFGHJKLZXCVBNM"
+ "0123456789";
+ std::string alphabet;
+
+ if (args.size() > 3) {
+ size_t i = 1;
+ size_t stopAt = args.size() - 2;
+
+ for (; i < stopAt; ++i) {
+ if (args[i] == "LENGTH") {
+ ++i;
+ length = atoi(args[i].c_str());
+ } else if (args[i] == "ALPHABET") {
+ ++i;
+ alphabet = args[i];
+ } else if (args[i] == "RANDOM_SEED") {
+ ++i;
+ seed = static_cast<unsigned int>(atoi(args[i].c_str()));
+ force_seed = true;
+ }
+ }
+ }
+ if (alphabet.empty()) {
+ alphabet = cmStringCommandDefaultAlphabet;
+ }
+
+ double sizeofAlphabet = static_cast<double>(alphabet.size());
+ if (sizeofAlphabet < 1) {
+ status.SetError("sub-command RANDOM invoked with bad alphabet.");
+ return false;
+ }
+ if (length < 1) {
+ status.SetError("sub-command RANDOM invoked with bad length.");
+ return false;
+ }
+ const std::string& variableName = args.back();
+
+ std::vector<char> result;
+
+ if (!seeded || force_seed) {
+ seeded = true;
+ srand(force_seed ? seed : cmSystemTools::RandomSeed());
+ }
+
+ const char* alphaPtr = alphabet.c_str();
+ for (int cc = 0; cc < length; cc++) {
+ int idx = static_cast<int>(sizeofAlphabet * rand() / (RAND_MAX + 1.0));
+ result.push_back(*(alphaPtr + idx));
+ }
+ result.push_back(0);
+
+ status.GetMakefile().AddDefinition(variableName, result.data());
+ return true;
+}
+
+bool HandleTimestampCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("sub-command TIMESTAMP requires at least one argument.");
+ return false;
+ }
+ if (args.size() > 4) {
+ status.SetError("sub-command TIMESTAMP takes at most three arguments.");
+ return false;
+ }
+
+ unsigned int argsIndex = 1;
+
+ const std::string& outputVariable = args[argsIndex++];
+
+ std::string formatString;
+ if (args.size() > argsIndex && args[argsIndex] != "UTC") {
+ formatString = args[argsIndex++];
+ }
+
+ bool utcFlag = false;
+ if (args.size() > argsIndex) {
+ if (args[argsIndex] == "UTC") {
+ utcFlag = true;
+ } else {
+ std::string e = " TIMESTAMP sub-command does not recognize option " +
+ args[argsIndex] + ".";
+ status.SetError(e);
+ return false;
+ }
+ }
+
+ cmTimestamp timestamp;
+ std::string result = timestamp.CurrentTime(formatString, utcFlag);
+ status.GetMakefile().AddDefinition(outputVariable, result);
+
+ return true;
+}
+
+bool HandleUuidCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ unsigned int argsIndex = 1;
+
+ if (args.size() < 2) {
+ status.SetError("UUID sub-command requires an output variable.");
+ return false;
+ }
+
+ const std::string& outputVariable = args[argsIndex++];
+
+ std::string uuidNamespaceString;
+ std::string uuidName;
+ std::string uuidType;
+ bool uuidUpperCase = false;
+
+ while (args.size() > argsIndex) {
+ if (args[argsIndex] == "NAMESPACE") {
+ ++argsIndex;
+ if (argsIndex >= args.size()) {
+ status.SetError("UUID sub-command, NAMESPACE requires a value.");
+ return false;
+ }
+ uuidNamespaceString = args[argsIndex++];
+ } else if (args[argsIndex] == "NAME") {
+ ++argsIndex;
+ if (argsIndex >= args.size()) {
+ status.SetError("UUID sub-command, NAME requires a value.");
+ return false;
+ }
+ uuidName = args[argsIndex++];
+ } else if (args[argsIndex] == "TYPE") {
+ ++argsIndex;
+ if (argsIndex >= args.size()) {
+ status.SetError("UUID sub-command, TYPE requires a value.");
+ return false;
+ }
+ uuidType = args[argsIndex++];
+ } else if (args[argsIndex] == "UPPER") {
+ ++argsIndex;
+ uuidUpperCase = true;
+ } else {
+ std::string e =
+ "UUID sub-command does not recognize option " + args[argsIndex] + ".";
+ status.SetError(e);
+ return false;
+ }
+ }
+
+ std::string uuid;
+ cmUuid uuidGenerator;
+
+ std::vector<unsigned char> uuidNamespace;
+ if (!uuidGenerator.StringToBinary(uuidNamespaceString, uuidNamespace)) {
+ status.SetError("UUID sub-command, malformed NAMESPACE UUID.");
+ return false;
+ }
+
+ if (uuidType == "MD5") {
+ uuid = uuidGenerator.FromMd5(uuidNamespace, uuidName);
+ } else if (uuidType == "SHA1") {
+ uuid = uuidGenerator.FromSha1(uuidNamespace, uuidName);
+ } else {
+ std::string e = "UUID sub-command, unknown TYPE '" + uuidType + "'.";
+ status.SetError(e);
+ return false;
+ }
+
+ if (uuid.empty()) {
+ status.SetError("UUID sub-command, generation failed.");
+ return false;
+ }
+
+ if (uuidUpperCase) {
+ uuid = cmSystemTools::UpperCase(uuid);
+ }
+
+ status.GetMakefile().AddDefinition(outputVariable, uuid);
+ return true;
+#else
+ status.SetError(cmStrCat(args[0], " not available during bootstrap"));
+ return false;
+#endif
+}
+
+#if !defined(CMAKE_BOOTSTRAP)
+
+// Helpers for string(JSON ...)
+struct Args : cmRange<typename std::vector<std::string>::const_iterator>
+{
+ using cmRange<typename std::vector<std::string>::const_iterator>::cmRange;
+
+ auto PopFront(cm::string_view error) -> const std::string&;
+ auto PopBack(cm::string_view error) -> const std::string&;
+};
+
+class json_error : public std::runtime_error
+{
+public:
+ json_error(std::initializer_list<cm::string_view> message,
+ cm::optional<Args> errorPath = cm::nullopt)
+ : std::runtime_error(cmCatViews(message))
+ , ErrorPath{
+ std::move(errorPath) // NOLINT(performance-move-const-arg)
+ }
+ {
+ }
+ cm::optional<Args> ErrorPath;
+};
+
+const std::string& Args::PopFront(cm::string_view error)
+{
+ if (this->empty()) {
+ throw json_error({ error });
+ }
+ const std::string& res = *this->begin();
+ this->advance(1);
+ return res;
+}
+
+const std::string& Args::PopBack(cm::string_view error)
+{
+ if (this->empty()) {
+ throw json_error({ error });
+ }
+ const std::string& res = *(this->end() - 1);
+ this->retreat(1);
+ return res;
+}
+
+cm::string_view JsonTypeToString(Json::ValueType type)
+{
+ switch (type) {
+ case Json::ValueType::nullValue:
+ return "NULL"_s;
+ case Json::ValueType::intValue:
+ case Json::ValueType::uintValue:
+ case Json::ValueType::realValue:
+ return "NUMBER"_s;
+ case Json::ValueType::stringValue:
+ return "STRING"_s;
+ case Json::ValueType::booleanValue:
+ return "BOOLEAN"_s;
+ case Json::ValueType::arrayValue:
+ return "ARRAY"_s;
+ case Json::ValueType::objectValue:
+ return "OBJECT"_s;
+ }
+ throw json_error({ "invalid JSON type found"_s });
+}
+
+int ParseIndex(
+ const std::string& str, cm::optional<Args> const& progress = cm::nullopt,
+ Json::ArrayIndex max = std::numeric_limits<Json::ArrayIndex>::max())
+{
+ unsigned long lindex;
+ if (!cmStrToULong(str, &lindex)) {
+ throw json_error({ "expected an array index, got: '"_s, str, "'"_s },
+ progress);
+ }
+ Json::ArrayIndex index = static_cast<Json::ArrayIndex>(lindex);
+ if (index >= max) {
+ cmAlphaNum sizeStr{ max };
+ throw json_error({ "expected an index less then "_s, sizeStr.View(),
+ " got '"_s, str, "'"_s },
+ progress);
+ }
+ return index;
+}
+
+Json::Value& ResolvePath(Json::Value& json, Args path)
+{
+ Json::Value* search = &json;
+
+ for (auto curr = path.begin(); curr != path.end(); ++curr) {
+ const std::string& field = *curr;
+ Args progress{ path.begin(), curr + 1 };
+
+ if (search->isArray()) {
+ auto index = ParseIndex(field, progress, search->size());
+ search = &(*search)[index];
+
+ } else if (search->isObject()) {
+ if (!search->isMember(field)) {
+ const auto progressStr = cmJoin(progress, " "_s);
+ throw json_error({ "member '"_s, progressStr, "' not found"_s },
+ progress);
+ }
+ search = &(*search)[field];
+ } else {
+ const auto progressStr = cmJoin(progress, " "_s);
+ throw json_error(
+ { "invalid path '"_s, progressStr,
+ "', need element of OBJECT or ARRAY type to lookup '"_s, field,
+ "' got "_s, JsonTypeToString(search->type()) },
+ progress);
+ }
+ }
+ return *search;
+};
+
+Json::Value ReadJson(const std::string& jsonstr)
+{
+ Json::CharReaderBuilder builder;
+ builder["collectComments"] = false;
+ auto jsonReader = std::unique_ptr<Json::CharReader>(builder.newCharReader());
+ Json::Value json;
+ std::string error;
+ if (!jsonReader->parse(jsonstr.data(), jsonstr.data() + jsonstr.size(),
+ &json, &error)) {
+ throw json_error({ "failed parsing json string: "_s, error });
+ }
+ return json;
+}
+std::string WriteJson(const Json::Value& value)
+{
+ Json::StreamWriterBuilder writer;
+ writer["indentation"] = " ";
+ writer["commentStyle"] = "None";
+ return Json::writeString(writer, value);
+}
+
+#endif
+
+bool HandleJSONCommand(std::vector<std::string> const& arguments,
+ cmExecutionStatus& status)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+
+ auto& makefile = status.GetMakefile();
+ Args args{ arguments.begin() + 1, arguments.end() };
+
+ const std::string* errorVariable = nullptr;
+ const std::string* outputVariable = nullptr;
+ bool success = true;
+
+ try {
+ outputVariable = &args.PopFront("missing out-var argument"_s);
+
+ if (!args.empty() && *args.begin() == "ERROR_VARIABLE"_s) {
+ args.PopFront("");
+ errorVariable = &args.PopFront("missing error-var argument"_s);
+ makefile.AddDefinition(*errorVariable, "NOTFOUND"_s);
+ }
+
+ const auto& mode = args.PopFront("missing mode argument"_s);
+ if (mode != "GET"_s && mode != "TYPE"_s && mode != "MEMBER"_s &&
+ mode != "LENGTH"_s && mode != "REMOVE"_s && mode != "SET"_s &&
+ mode != "EQUAL"_s) {
+ throw json_error(
+ { "got an invalid mode '"_s, mode,
+ "', expected one of GET, GET_ARRAY, TYPE, MEMBER, MEMBERS,"
+ " LENGTH, REMOVE, SET, EQUAL"_s });
+ }
+
+ const auto& jsonstr = args.PopFront("missing json string argument"_s);
+ Json::Value json = ReadJson(jsonstr);
+
+ if (mode == "GET"_s) {
+ const auto& value = ResolvePath(json, args);
+ if (value.isObject() || value.isArray()) {
+ makefile.AddDefinition(*outputVariable, WriteJson(value));
+ } else if (value.isBool()) {
+ makefile.AddDefinitionBool(*outputVariable, value.asBool());
+ } else {
+ makefile.AddDefinition(*outputVariable, value.asString());
+ }
+
+ } else if (mode == "TYPE"_s) {
+ const auto& value = ResolvePath(json, args);
+ makefile.AddDefinition(*outputVariable, JsonTypeToString(value.type()));
+
+ } else if (mode == "MEMBER"_s) {
+ const auto& indexStr = args.PopBack("missing member index"_s);
+ const auto& value = ResolvePath(json, args);
+ if (!value.isObject()) {
+ throw json_error({ "MEMBER needs to be called with an element of "
+ "type OBJECT, got "_s,
+ JsonTypeToString(value.type()) },
+ args);
+ }
+ const auto index = ParseIndex(
+ indexStr, Args{ args.begin(), args.end() + 1 }, value.size());
+ const auto memIt = std::next(value.begin(), index);
+ makefile.AddDefinition(*outputVariable, memIt.name());
+
+ } else if (mode == "LENGTH"_s) {
+ const auto& value = ResolvePath(json, args);
+ if (!value.isArray() && !value.isObject()) {
+ throw json_error({ "LENGTH needs to be called with an "
+ "element of type ARRAY or OBJECT, got "_s,
+ JsonTypeToString(value.type()) },
+ args);
+ }
+
+ cmAlphaNum sizeStr{ value.size() };
+ makefile.AddDefinition(*outputVariable, sizeStr.View());
+
+ } else if (mode == "REMOVE"_s) {
+ const auto& toRemove =
+ args.PopBack("missing member or index to remove"_s);
+ auto& value = ResolvePath(json, args);
+
+ if (value.isArray()) {
+ const auto index = ParseIndex(
+ toRemove, Args{ args.begin(), args.end() + 1 }, value.size());
+ Json::Value removed;
+ value.removeIndex(index, &removed);
+
+ } else if (value.isObject()) {
+ Json::Value removed;
+ value.removeMember(toRemove, &removed);
+
+ } else {
+ throw json_error({ "REMOVE needs to be called with an "
+ "element of type ARRAY or OBJECT, got "_s,
+ JsonTypeToString(value.type()) },
+ args);
+ }
+ makefile.AddDefinition(*outputVariable, WriteJson(json));
+
+ } else if (mode == "SET"_s) {
+ const auto& newValueStr = args.PopBack("missing new value remove"_s);
+ const auto& toAdd = args.PopBack("missing member name to add"_s);
+ auto& value = ResolvePath(json, args);
+
+ Json::Value newValue = ReadJson(newValueStr);
+ if (value.isObject()) {
+ value[toAdd] = newValue;
+ } else if (value.isArray()) {
+ const auto index =
+ ParseIndex(toAdd, Args{ args.begin(), args.end() + 1 });
+ if (value.isValidIndex(index)) {
+ value[static_cast<int>(index)] = newValue;
+ } else {
+ value.append(newValue);
+ }
+ } else {
+ throw json_error({ "SET needs to be called with an "
+ "element of type OBJECT or ARRAY, got "_s,
+ JsonTypeToString(value.type()) });
+ }
+
+ makefile.AddDefinition(*outputVariable, WriteJson(json));
+
+ } else if (mode == "EQUAL"_s) {
+ const auto& jsonstr2 =
+ args.PopFront("missing second json string argument"_s);
+ Json::Value json2 = ReadJson(jsonstr2);
+ makefile.AddDefinitionBool(*outputVariable, json == json2);
+ }
+
+ } catch (const json_error& e) {
+ if (outputVariable && e.ErrorPath) {
+ const auto errorPath = cmJoin(*e.ErrorPath, "-");
+ makefile.AddDefinition(*outputVariable,
+ cmCatViews({ errorPath, "-NOTFOUND"_s }));
+ } else if (outputVariable) {
+ makefile.AddDefinition(*outputVariable, "NOTFOUND"_s);
+ }
+
+ if (errorVariable) {
+ makefile.AddDefinition(*errorVariable, e.what());
+ } else {
+ status.SetError(cmCatViews({ "sub-command JSON "_s, e.what(), "."_s }));
+ success = false;
+ }
+ }
+ return success;
+#else
+ status.SetError(cmStrCat(arguments[0], " not available during bootstrap"_s));
+ return false;
+#endif
+}
+
+} // namespace
+
+bool cmStringCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("must be called with at least one argument.");
+ return false;
+ }
+
+ static cmSubcommandTable const subcommand{
+ { "REGEX"_s, HandleRegexCommand },
+ { "REPLACE"_s, HandleReplaceCommand },
+ { "MD5"_s, HandleHashCommand },
+ { "SHA1"_s, HandleHashCommand },
+ { "SHA224"_s, HandleHashCommand },
+ { "SHA256"_s, HandleHashCommand },
+ { "SHA384"_s, HandleHashCommand },
+ { "SHA512"_s, HandleHashCommand },
+ { "SHA3_224"_s, HandleHashCommand },
+ { "SHA3_256"_s, HandleHashCommand },
+ { "SHA3_384"_s, HandleHashCommand },
+ { "SHA3_512"_s, HandleHashCommand },
+ { "TOLOWER"_s, HandleToLowerCommand },
+ { "TOUPPER"_s, HandleToUpperCommand },
+ { "COMPARE"_s, HandleCompareCommand },
+ { "ASCII"_s, HandleAsciiCommand },
+ { "HEX"_s, HandleHexCommand },
+ { "CONFIGURE"_s, HandleConfigureCommand },
+ { "LENGTH"_s, HandleLengthCommand },
+ { "APPEND"_s, HandleAppendCommand },
+ { "PREPEND"_s, HandlePrependCommand },
+ { "CONCAT"_s, HandleConcatCommand },
+ { "JOIN"_s, HandleJoinCommand },
+ { "SUBSTRING"_s, HandleSubstringCommand },
+ { "STRIP"_s, HandleStripCommand },
+ { "REPEAT"_s, HandleRepeatCommand },
+ { "RANDOM"_s, HandleRandomCommand },
+ { "FIND"_s, HandleFindCommand },
+ { "TIMESTAMP"_s, HandleTimestampCommand },
+ { "MAKE_C_IDENTIFIER"_s, HandleMakeCIdentifierCommand },
+ { "GENEX_STRIP"_s, HandleGenexStripCommand },
+ { "UUID"_s, HandleUuidCommand },
+ { "JSON"_s, HandleJSONCommand },
+ };
+
+ return subcommand(args[0], args, status);
+}
diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h
new file mode 100644
index 0000000..5320ea5
--- /dev/null
+++ b/Source/cmStringCommand.h
@@ -0,0 +1,17 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Common string operations
+ *
+ */
+bool cmStringCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmStringReplaceHelper.cxx b/Source/cmStringReplaceHelper.cxx
new file mode 100644
index 0000000..998c135
--- /dev/null
+++ b/Source/cmStringReplaceHelper.cxx
@@ -0,0 +1,121 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmStringReplaceHelper.h"
+
+#include <sstream>
+#include <utility>
+
+#include "cmMakefile.h"
+
+cmStringReplaceHelper::cmStringReplaceHelper(const std::string& regex,
+ std::string replace_expr,
+ cmMakefile* makefile)
+ : RegExString(regex)
+ , RegularExpression(regex)
+ , ReplaceExpression(std::move(replace_expr))
+ , Makefile(makefile)
+{
+ this->ParseReplaceExpression();
+}
+
+bool cmStringReplaceHelper::Replace(const std::string& input,
+ std::string& output)
+{
+ output.clear();
+
+ // Scan through the input for all matches.
+ std::string::size_type base = 0;
+ while (this->RegularExpression.find(input.c_str() + base)) {
+ if (this->Makefile != nullptr) {
+ this->Makefile->ClearMatches();
+ this->Makefile->StoreMatches(this->RegularExpression);
+ }
+ auto l2 = this->RegularExpression.start();
+ auto r = this->RegularExpression.end();
+
+ // Concatenate the part of the input that was not matched.
+ output += input.substr(base, l2);
+
+ // Make sure the match had some text.
+ if (r - l2 == 0) {
+ std::ostringstream error;
+ error << "regex \"" << this->RegExString << "\" matched an empty string";
+ this->ErrorString = error.str();
+ return false;
+ }
+
+ // Concatenate the replacement for the match.
+ for (const auto& replacement : this->Replacements) {
+ if (replacement.Number < 0) {
+ // This is just a plain-text part of the replacement.
+ output += replacement.Value;
+ } else {
+ // Replace with part of the match.
+ auto n = replacement.Number;
+ auto start = this->RegularExpression.start(n);
+ auto end = this->RegularExpression.end(n);
+ auto len = input.length() - base;
+ if ((start != std::string::npos) && (end != std::string::npos) &&
+ (start <= len) && (end <= len)) {
+ output += input.substr(base + start, end - start);
+ } else {
+ std::ostringstream error;
+ error << "replace expression \"" << this->ReplaceExpression
+ << "\" contains an out-of-range escape for regex \""
+ << this->RegExString << "\"";
+ this->ErrorString = error.str();
+ return false;
+ }
+ }
+ }
+
+ // Move past the match.
+ base += r;
+ }
+
+ // Concatenate the text after the last match.
+ output += input.substr(base, input.length() - base);
+
+ return true;
+}
+
+void cmStringReplaceHelper::ParseReplaceExpression()
+{
+ std::string::size_type l = 0;
+ while (l < this->ReplaceExpression.length()) {
+ auto r = this->ReplaceExpression.find('\\', l);
+ if (r == std::string::npos) {
+ r = this->ReplaceExpression.length();
+ this->Replacements.emplace_back(
+ this->ReplaceExpression.substr(l, r - l));
+ } else {
+ if (r - l > 0) {
+ this->Replacements.emplace_back(
+ this->ReplaceExpression.substr(l, r - l));
+ }
+ if (r == (this->ReplaceExpression.length() - 1)) {
+ this->ValidReplaceExpression = false;
+ this->ErrorString = "replace-expression ends in a backslash";
+ return;
+ }
+ if ((this->ReplaceExpression[r + 1] >= '0') &&
+ (this->ReplaceExpression[r + 1] <= '9')) {
+ this->Replacements.emplace_back(this->ReplaceExpression[r + 1] - '0');
+ } else if (this->ReplaceExpression[r + 1] == 'n') {
+ this->Replacements.emplace_back("\n");
+ } else if (this->ReplaceExpression[r + 1] == '\\') {
+ this->Replacements.emplace_back("\\");
+ } else {
+ this->ValidReplaceExpression = false;
+ std::ostringstream error;
+ error << "Unknown escape \"" << this->ReplaceExpression.substr(r, 2)
+ << "\" in replace-expression";
+ this->ErrorString = error.str();
+ return;
+ }
+ r += 2;
+ }
+ l = r;
+ }
+}
diff --git a/Source/cmStringReplaceHelper.h b/Source/cmStringReplaceHelper.h
new file mode 100644
index 0000000..fd59d17
--- /dev/null
+++ b/Source/cmStringReplaceHelper.h
@@ -0,0 +1,65 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+class cmMakefile;
+
+class cmStringReplaceHelper
+{
+public:
+ cmStringReplaceHelper(const std::string& regex, std::string replace_expr,
+ cmMakefile* makefile = nullptr);
+
+ bool IsRegularExpressionValid() const
+ {
+ return this->RegularExpression.is_valid();
+ }
+ bool IsReplaceExpressionValid() const
+ {
+ return this->ValidReplaceExpression;
+ }
+
+ bool Replace(const std::string& input, std::string& output);
+
+ const std::string& GetError() { return this->ErrorString; }
+
+private:
+ class RegexReplacement
+ {
+ public:
+ RegexReplacement(const char* s)
+ : Number(-1)
+ , Value(s)
+ {
+ }
+ RegexReplacement(std::string s)
+ : Number(-1)
+ , Value(std::move(s))
+ {
+ }
+ RegexReplacement(int n)
+ : Number(n)
+ {
+ }
+ RegexReplacement() = default;
+
+ int Number;
+ std::string Value;
+ };
+
+ void ParseReplaceExpression();
+
+ std::string ErrorString;
+ std::string RegExString;
+ cmsys::RegularExpression RegularExpression;
+ bool ValidReplaceExpression = true;
+ std::string ReplaceExpression;
+ std::vector<RegexReplacement> Replacements;
+ cmMakefile* Makefile = nullptr;
+};
diff --git a/Source/cmSubcommandTable.cxx b/Source/cmSubcommandTable.cxx
new file mode 100644
index 0000000..f6194f8
--- /dev/null
+++ b/Source/cmSubcommandTable.cxx
@@ -0,0 +1,31 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSubcommandTable.h"
+
+#include <algorithm>
+
+#include "cmExecutionStatus.h"
+#include "cmStringAlgorithms.h"
+
+cmSubcommandTable::cmSubcommandTable(std::initializer_list<InitElem> init)
+ : Impl(init.begin(), init.end())
+{
+ std::sort(this->Impl.begin(), this->Impl.end(),
+ [](Elem const& left, Elem const& right) {
+ return left.first < right.first;
+ });
+}
+
+bool cmSubcommandTable::operator()(cm::string_view key,
+ std::vector<std::string> const& args,
+ cmExecutionStatus& status) const
+{
+ auto const it = std::lower_bound(
+ this->Impl.begin(), this->Impl.end(), key,
+ [](Elem const& elem, cm::string_view k) { return elem.first < k; });
+ if (it != this->Impl.end() && it->first == key) {
+ return it->second(args, status);
+ }
+ status.SetError(cmStrCat("does not recognize sub-command ", key));
+ return false;
+}
diff --git a/Source/cmSubcommandTable.h b/Source/cmSubcommandTable.h
new file mode 100644
index 0000000..80d8c6d
--- /dev/null
+++ b/Source/cmSubcommandTable.h
@@ -0,0 +1,33 @@
+/* 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 <initializer_list>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/string_view>
+#include <cmext/string_view>
+
+class cmExecutionStatus;
+
+class cmSubcommandTable
+{
+public:
+ using Command = bool (*)(std::vector<std::string> const&,
+ cmExecutionStatus&);
+
+ using Elem = std::pair<cm::string_view, Command>;
+ using InitElem = std::pair<cm::static_string_view, Command>;
+
+ cmSubcommandTable(std::initializer_list<InitElem> init);
+
+ bool operator()(cm::string_view key, std::vector<std::string> const& args,
+ cmExecutionStatus& status) const;
+
+private:
+ std::vector<Elem> Impl;
+};
diff --git a/Source/cmSubdirCommand.cxx b/Source/cmSubdirCommand.cxx
new file mode 100644
index 0000000..2477d7a
--- /dev/null
+++ b/Source/cmSubdirCommand.cxx
@@ -0,0 +1,51 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSubdirCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+bool cmSubdirCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ bool res = true;
+ bool excludeFromAll = false;
+ cmMakefile& mf = status.GetMakefile();
+
+ for (std::string const& i : args) {
+ if (i == "EXCLUDE_FROM_ALL") {
+ excludeFromAll = true;
+ continue;
+ }
+ if (i == "PREORDER") {
+ // Ignored
+ continue;
+ }
+
+ // if they specified a relative path then compute the full
+ std::string srcPath = mf.GetCurrentSourceDirectory() + "/" + i;
+ if (cmSystemTools::FileIsDirectory(srcPath)) {
+ std::string binPath = mf.GetCurrentBinaryDirectory() + "/" + i;
+ mf.AddSubDirectory(srcPath, binPath, excludeFromAll, false);
+ }
+ // otherwise it is a full path
+ else if (cmSystemTools::FileIsDirectory(i)) {
+ // we must compute the binPath from the srcPath, we just take the last
+ // element from the source path and use that
+ std::string binPath = mf.GetCurrentBinaryDirectory() + "/" +
+ cmSystemTools::GetFilenameName(i);
+ mf.AddSubDirectory(i, binPath, excludeFromAll, false);
+ } else {
+ status.SetError(cmStrCat("Incorrect SUBDIRS command. Directory: ", i,
+ " does not exist."));
+ res = false;
+ }
+ }
+ return res;
+}
diff --git a/Source/cmSubdirCommand.h b/Source/cmSubdirCommand.h
new file mode 100644
index 0000000..6770874
--- /dev/null
+++ b/Source/cmSubdirCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmSubdirCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmSubdirDependsCommand.cxx b/Source/cmSubdirDependsCommand.cxx
new file mode 100644
index 0000000..496c60d
--- /dev/null
+++ b/Source/cmSubdirDependsCommand.cxx
@@ -0,0 +1,11 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmSubdirDependsCommand.h"
+
+class cmExecutionStatus;
+
+bool cmSubdirDependsCommand(std::vector<std::string> const&,
+ cmExecutionStatus&)
+{
+ return true;
+}
diff --git a/Source/cmSubdirDependsCommand.h b/Source/cmSubdirDependsCommand.h
new file mode 100644
index 0000000..133d702
--- /dev/null
+++ b/Source/cmSubdirDependsCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmSubdirDependsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
new file mode 100644
index 0000000..3a438fd
--- /dev/null
+++ b/Source/cmSystemTools.cxx
@@ -0,0 +1,3255 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#if !defined(_WIN32) && !defined(__sun) && !defined(__OpenBSD__)
+// POSIX APIs are needed
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
+# define _POSIX_C_SOURCE 200809L
+#endif
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__QNX__)
+// For isascii
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
+# define _XOPEN_SOURCE 700
+#endif
+
+#include "cmSystemTools.h"
+
+#include <cmext/algorithm>
+
+#include <cm3p/uv.h>
+
+#include "cmDuration.h"
+#include "cmProcessOutput.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+
+#if !defined(CMAKE_BOOTSTRAP)
+# include <cm3p/archive.h>
+# include <cm3p/archive_entry.h>
+
+# include "cmArchiveWrite.h"
+# include "cmLocale.h"
+# ifndef __LA_INT64_T
+# define __LA_INT64_T la_int64_t
+# endif
+# ifndef __LA_SSIZE_T
+# define __LA_SSIZE_T la_ssize_t
+# endif
+#endif
+
+#if !defined(CMAKE_BOOTSTRAP)
+# if defined(_WIN32)
+# include <cm/memory>
+# endif
+# include "cmCryptoHash.h"
+#endif
+
+#if defined(CMake_USE_ELF_PARSER)
+# include "cmELF.h"
+#endif
+
+#if defined(CMake_USE_MACH_PARSER)
+# include "cmMachO.h"
+#endif
+
+#if defined(CMake_USE_XCOFF_PARSER)
+# include "cmXCOFF.h"
+#endif
+
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <iostream>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include <fcntl.h>
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/Encoding.hxx"
+#include "cmsys/FStream.hxx"
+#include "cmsys/RegularExpression.hxx"
+#include "cmsys/System.h"
+#include "cmsys/Terminal.h"
+
+#if defined(_WIN32)
+# include <windows.h>
+// include wincrypt.h after windows.h
+# include <wincrypt.h>
+#else
+# include <unistd.h>
+
+# include <sys/time.h>
+# include <sys/types.h>
+#endif
+
+#if defined(_WIN32) && \
+ (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__MINGW32__))
+# include <io.h>
+#endif
+
+#if defined(__APPLE__)
+# include <mach-o/dyld.h>
+#endif
+
+#ifdef __QNX__
+# include <malloc.h> /* for malloc/free on QNX */
+#endif
+
+#if !defined(_WIN32) && !defined(__ANDROID__)
+# include <sys/utsname.h>
+#endif
+
+namespace {
+
+cmSystemTools::InterruptCallback s_InterruptCallback;
+cmSystemTools::MessageCallback s_MessageCallback;
+cmSystemTools::OutputCallback s_StderrCallback;
+cmSystemTools::OutputCallback s_StdoutCallback;
+
+} // namespace
+
+#if !defined(HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE)
+// For GetEnvironmentVariables
+# if defined(_WIN32)
+extern __declspec(dllimport) char** environ;
+# else
+extern char** environ;
+# endif
+#endif
+
+#if !defined(CMAKE_BOOTSTRAP)
+static std::string cm_archive_entry_pathname(struct archive_entry* entry)
+{
+# if cmsys_STL_HAS_WSTRING
+ return cmsys::Encoding::ToNarrow(archive_entry_pathname_w(entry));
+# else
+ return archive_entry_pathname(entry);
+# endif
+}
+
+static int cm_archive_read_open_file(struct archive* a, const char* file,
+ int block_size)
+{
+# if cmsys_STL_HAS_WSTRING
+ std::wstring wfile = cmsys::Encoding::ToWide(file);
+ return archive_read_open_filename_w(a, wfile.c_str(), block_size);
+# else
+ return archive_read_open_filename(a, file, block_size);
+# endif
+}
+#endif
+
+#ifdef _WIN32
+#elif defined(__APPLE__)
+# include <crt_externs.h>
+
+# define environ (*_NSGetEnviron())
+#endif
+
+namespace {
+void ReportError(std::string* err)
+{
+ if (!err) {
+ return;
+ }
+#ifdef _WIN32
+ LPSTR message = NULL;
+ DWORD size = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&message, 0, NULL);
+ *err = std::string(message, size);
+ LocalFree(message);
+#else
+ *err = strerror(errno);
+#endif
+}
+}
+
+bool cmSystemTools::s_RunCommandHideConsole = false;
+bool cmSystemTools::s_DisableRunCommandOutput = false;
+bool cmSystemTools::s_ErrorOccured = false;
+bool cmSystemTools::s_FatalErrorOccured = false;
+bool cmSystemTools::s_ForceUnixPaths = false;
+
+// replace replace with with as many times as it shows up in source.
+// write the result into source.
+#if defined(_WIN32) && !defined(__CYGWIN__)
+void cmSystemTools::ExpandRegistryValues(std::string& source, KeyWOW64 view)
+{
+ // Regular expression to match anything inside [...] that begins in HKEY.
+ // Note that there is a special rule for regular expressions to match a
+ // close square-bracket inside a list delimited by square brackets.
+ // The "[^]]" part of this expression will match any character except
+ // a close square-bracket. The ']' character must be the first in the
+ // list of characters inside the [^...] block of the expression.
+ cmsys::RegularExpression regEntry("\\[(HKEY[^]]*)\\]");
+
+ // check for black line or comment
+ while (regEntry.find(source)) {
+ // the arguments are the second match
+ std::string key = regEntry.match(1);
+ std::string val;
+ if (ReadRegistryValue(key.c_str(), val, view)) {
+ std::string reg = cmStrCat('[', key, ']');
+ cmSystemTools::ReplaceString(source, reg.c_str(), val.c_str());
+ } else {
+ std::string reg = cmStrCat('[', key, ']');
+ cmSystemTools::ReplaceString(source, reg.c_str(), "/registry");
+ }
+ }
+}
+#else
+void cmSystemTools::ExpandRegistryValues(std::string& source,
+ KeyWOW64 /*unused*/)
+{
+ cmsys::RegularExpression regEntry("\\[(HKEY[^]]*)\\]");
+ while (regEntry.find(source)) {
+ // the arguments are the second match
+ std::string key = regEntry.match(1);
+ std::string reg = cmStrCat('[', key, ']');
+ cmSystemTools::ReplaceString(source, reg.c_str(), "/registry");
+ }
+}
+#endif
+
+std::string cmSystemTools::HelpFileName(cm::string_view str)
+{
+ std::string name(str);
+ cmSystemTools::ReplaceString(name, "<", "");
+ cmSystemTools::ReplaceString(name, ">", "");
+ return name;
+}
+
+void cmSystemTools::Error(const std::string& m)
+{
+ std::string message = "CMake Error: " + m;
+ cmSystemTools::s_ErrorOccured = true;
+ cmSystemTools::Message(message, "Error");
+}
+
+void cmSystemTools::SetInterruptCallback(InterruptCallback f)
+{
+ s_InterruptCallback = std::move(f);
+}
+
+bool cmSystemTools::GetInterruptFlag()
+{
+ if (s_InterruptCallback) {
+ return s_InterruptCallback();
+ }
+ return false;
+}
+
+void cmSystemTools::SetMessageCallback(MessageCallback f)
+{
+ s_MessageCallback = std::move(f);
+}
+
+void cmSystemTools::SetStdoutCallback(OutputCallback f)
+{
+ s_StdoutCallback = std::move(f);
+}
+
+void cmSystemTools::SetStderrCallback(OutputCallback f)
+{
+ s_StderrCallback = std::move(f);
+}
+
+void cmSystemTools::Stderr(const std::string& s)
+{
+ if (s_StderrCallback) {
+ s_StderrCallback(s);
+ } else {
+ std::cerr << s << std::flush;
+ }
+}
+
+void cmSystemTools::Stdout(const std::string& s)
+{
+ if (s_StdoutCallback) {
+ s_StdoutCallback(s);
+ } else {
+ std::cout << s << std::flush;
+ }
+}
+
+void cmSystemTools::Message(const std::string& m, const char* title)
+{
+ if (s_MessageCallback) {
+ s_MessageCallback(m, title);
+ } else {
+ std::cerr << m << std::endl;
+ }
+}
+
+void cmSystemTools::ReportLastSystemError(const char* msg)
+{
+ std::string m =
+ cmStrCat(msg, ": System Error: ", Superclass::GetLastSystemError());
+ cmSystemTools::Error(m);
+}
+
+void cmSystemTools::ParseWindowsCommandLine(const char* command,
+ std::vector<std::string>& args)
+{
+ // See the MSDN document "Parsing C Command-Line Arguments" at
+ // http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx for rules
+ // of parsing the windows command line.
+
+ bool in_argument = false;
+ bool in_quotes = false;
+ int backslashes = 0;
+ std::string arg;
+ for (const char* c = command; *c; ++c) {
+ if (*c == '\\') {
+ ++backslashes;
+ in_argument = true;
+ } else if (*c == '"') {
+ int backslash_pairs = backslashes >> 1;
+ int backslash_escaped = backslashes & 1;
+ arg.append(backslash_pairs, '\\');
+ backslashes = 0;
+ if (backslash_escaped) {
+ /* An odd number of backslashes precede this quote.
+ It is escaped. */
+ arg.append(1, '"');
+ } else {
+ /* An even number of backslashes precede this quote.
+ It is not escaped. */
+ in_quotes = !in_quotes;
+ }
+ in_argument = true;
+ } else {
+ arg.append(backslashes, '\\');
+ backslashes = 0;
+ if (cmIsSpace(*c)) {
+ if (in_quotes) {
+ arg.append(1, *c);
+ } else if (in_argument) {
+ args.push_back(arg);
+ arg.clear();
+ in_argument = false;
+ }
+ } else {
+ in_argument = true;
+ arg.append(1, *c);
+ }
+ }
+ }
+ arg.append(backslashes, '\\');
+ if (in_argument) {
+ args.push_back(arg);
+ }
+}
+
+class cmSystemToolsArgV
+{
+ char** ArgV;
+
+public:
+ cmSystemToolsArgV(char** argv)
+ : ArgV(argv)
+ {
+ }
+ ~cmSystemToolsArgV()
+ {
+ for (char** arg = this->ArgV; arg && *arg; ++arg) {
+ free(*arg);
+ }
+ free(this->ArgV);
+ }
+ cmSystemToolsArgV(const cmSystemToolsArgV&) = delete;
+ cmSystemToolsArgV& operator=(const cmSystemToolsArgV&) = delete;
+ void Store(std::vector<std::string>& args) const
+ {
+ for (char** arg = this->ArgV; arg && *arg; ++arg) {
+ args.emplace_back(*arg);
+ }
+ }
+};
+
+void cmSystemTools::ParseUnixCommandLine(const char* command,
+ std::vector<std::string>& args)
+{
+ // Invoke the underlying parser.
+ cmSystemToolsArgV argv(cmsysSystem_Parse_CommandForUnix(command, 0));
+ argv.Store(args);
+}
+
+std::vector<std::string> cmSystemTools::HandleResponseFile(
+ std::vector<std::string>::const_iterator argBeg,
+ std::vector<std::string>::const_iterator argEnd)
+{
+ std::vector<std::string> arg_full;
+ for (std::string const& arg : cmMakeRange(argBeg, argEnd)) {
+ if (cmHasLiteralPrefix(arg, "@")) {
+ cmsys::ifstream responseFile(arg.substr(1).c_str(), std::ios::in);
+ if (!responseFile) {
+ std::string error = cmStrCat("failed to open for reading (",
+ cmSystemTools::GetLastSystemError(),
+ "):\n ", cm::string_view(arg).substr(1));
+ cmSystemTools::Error(error);
+ } else {
+ std::string line;
+ cmSystemTools::GetLineFromStream(responseFile, line);
+ std::vector<std::string> args2;
+#ifdef _WIN32
+ cmSystemTools::ParseWindowsCommandLine(line.c_str(), args2);
+#else
+ cmSystemTools::ParseUnixCommandLine(line.c_str(), args2);
+#endif
+ cm::append(arg_full, args2);
+ }
+ } else {
+ arg_full.push_back(arg);
+ }
+ }
+ return arg_full;
+}
+
+std::vector<std::string> cmSystemTools::ParseArguments(const std::string& cmd)
+{
+ std::vector<std::string> args;
+ std::string arg;
+
+ bool win_path = false;
+
+ const char* command = cmd.c_str();
+ if (command[0] && command[1] &&
+ ((command[0] != '/' && command[1] == ':' && command[2] == '\\') ||
+ (command[0] == '\"' && command[1] != '/' && command[2] == ':' &&
+ command[3] == '\\') ||
+ (command[0] == '\'' && command[1] != '/' && command[2] == ':' &&
+ command[3] == '\\') ||
+ (command[0] == '\\' && command[1] == '\\'))) {
+ win_path = true;
+ }
+ // Split the command into an argv array.
+ for (const char* c = command; *c;) {
+ // Skip over whitespace.
+ while (*c == ' ' || *c == '\t') {
+ ++c;
+ }
+ arg.clear();
+ if (*c == '"') {
+ // Parse a quoted argument.
+ ++c;
+ while (*c && *c != '"') {
+ arg.append(1, *c);
+ ++c;
+ }
+ if (*c) {
+ ++c;
+ }
+ args.push_back(arg);
+ } else if (*c == '\'') {
+ // Parse a quoted argument.
+ ++c;
+ while (*c && *c != '\'') {
+ arg.append(1, *c);
+ ++c;
+ }
+ if (*c) {
+ ++c;
+ }
+ args.push_back(arg);
+ } else if (*c) {
+ // Parse an unquoted argument.
+ while (*c && *c != ' ' && *c != '\t') {
+ if (*c == '\\' && !win_path) {
+ ++c;
+ if (*c) {
+ arg.append(1, *c);
+ ++c;
+ }
+ } else {
+ arg.append(1, *c);
+ ++c;
+ }
+ }
+ args.push_back(arg);
+ }
+ }
+
+ return args;
+}
+
+bool cmSystemTools::SplitProgramFromArgs(std::string const& command,
+ std::string& program,
+ std::string& args)
+{
+ const char* c = command.c_str();
+
+ // Skip leading whitespace.
+ while (isspace(static_cast<unsigned char>(*c))) {
+ ++c;
+ }
+
+ // Parse one command-line element up to an unquoted space.
+ bool in_escape = false;
+ bool in_double = false;
+ bool in_single = false;
+ for (; *c; ++c) {
+ if (in_single) {
+ if (*c == '\'') {
+ in_single = false;
+ } else {
+ program += *c;
+ }
+ } else if (in_escape) {
+ in_escape = false;
+ program += *c;
+ } else if (*c == '\\') {
+ in_escape = true;
+ } else if (in_double) {
+ if (*c == '"') {
+ in_double = false;
+ } else {
+ program += *c;
+ }
+ } else if (*c == '"') {
+ in_double = true;
+ } else if (*c == '\'') {
+ in_single = true;
+ } else if (isspace(static_cast<unsigned char>(*c))) {
+ break;
+ } else {
+ program += *c;
+ }
+ }
+
+ // The remainder of the command line holds unparsed arguments.
+ args = c;
+
+ return !in_single && !in_escape && !in_double;
+}
+
+size_t cmSystemTools::CalculateCommandLineLengthLimit()
+{
+ size_t sz =
+#ifdef _WIN32
+ // There's a maximum of 65536 bytes and thus 32768 WCHARs on Windows
+ // However, cmd.exe itself can only handle 8191 WCHARs and Ninja for
+ // example uses it to spawn processes.
+ size_t(8191);
+#elif defined(__linux)
+ // MAX_ARG_STRLEN is the maximum length of a string permissible for
+ // the execve() syscall on Linux. It's defined as (PAGE_SIZE * 32)
+ // in Linux's binfmts.h
+ static_cast<size_t>(sysconf(_SC_PAGESIZE) * 32);
+#else
+ size_t(0);
+#endif
+
+#if defined(_SC_ARG_MAX)
+ // ARG_MAX is the maximum size of the command and environment
+ // that can be passed to the exec functions on UNIX.
+ // The value in limits.h does not need to be present and may
+ // depend upon runtime memory constraints, hence sysconf()
+ // should be used to query it.
+ long szArgMax = sysconf(_SC_ARG_MAX);
+ // A return value of -1 signifies an undetermined limit, but
+ // it does not imply an infinite limit, and thus is ignored.
+ if (szArgMax != -1) {
+ // We estimate the size of the environment block to be 1000.
+ // This isn't accurate at all, but leaves some headroom.
+ szArgMax = szArgMax < 1000 ? 0 : szArgMax - 1000;
+# if defined(_WIN32) || defined(__linux)
+ sz = std::min(sz, static_cast<size_t>(szArgMax));
+# else
+ sz = static_cast<size_t>(szArgMax);
+# endif
+ }
+#endif
+ return sz;
+}
+
+bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
+ std::string* captureStdOut,
+ std::string* captureStdErr, int* retVal,
+ const char* dir, OutputOption outputflag,
+ cmDuration timeout, Encoding encoding)
+{
+ std::vector<const char*> argv;
+ argv.reserve(command.size() + 1);
+ for (std::string const& cmd : command) {
+ argv.push_back(cmd.c_str());
+ }
+ argv.push_back(nullptr);
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, argv.data());
+ cmsysProcess_SetWorkingDirectory(cp, dir);
+ if (cmSystemTools::GetRunCommandHideConsole()) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ }
+
+ if (outputflag == OUTPUT_PASSTHROUGH) {
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
+ captureStdOut = nullptr;
+ captureStdErr = nullptr;
+ } else if (outputflag == OUTPUT_MERGE ||
+ (captureStdErr && captureStdErr == captureStdOut)) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_MergeOutput, 1);
+ captureStdErr = nullptr;
+ }
+ assert(!captureStdErr || captureStdErr != captureStdOut);
+
+ cmsysProcess_SetTimeout(cp, timeout.count());
+ cmsysProcess_Execute(cp);
+
+ std::vector<char> tempStdOut;
+ std::vector<char> tempStdErr;
+ char* data;
+ int length;
+ int pipe;
+ cmProcessOutput processOutput(encoding);
+ std::string strdata;
+ if (outputflag != OUTPUT_PASSTHROUGH &&
+ (captureStdOut || captureStdErr || outputflag != OUTPUT_NONE)) {
+ while ((pipe = cmsysProcess_WaitForData(cp, &data, &length, nullptr)) >
+ 0) {
+ // Translate NULL characters in the output into valid text.
+ for (int i = 0; i < length; ++i) {
+ if (data[i] == '\0') {
+ data[i] = ' ';
+ }
+ }
+
+ if (pipe == cmsysProcess_Pipe_STDOUT) {
+ if (outputflag != OUTPUT_NONE) {
+ processOutput.DecodeText(data, length, strdata, 1);
+ cmSystemTools::Stdout(strdata);
+ }
+ if (captureStdOut) {
+ cm::append(tempStdOut, data, data + length);
+ }
+ } else if (pipe == cmsysProcess_Pipe_STDERR) {
+ if (outputflag != OUTPUT_NONE) {
+ processOutput.DecodeText(data, length, strdata, 2);
+ cmSystemTools::Stderr(strdata);
+ }
+ if (captureStdErr) {
+ cm::append(tempStdErr, data, data + length);
+ }
+ }
+ }
+
+ if (outputflag != OUTPUT_NONE) {
+ processOutput.DecodeText(std::string(), strdata, 1);
+ if (!strdata.empty()) {
+ cmSystemTools::Stdout(strdata);
+ }
+ processOutput.DecodeText(std::string(), strdata, 2);
+ if (!strdata.empty()) {
+ cmSystemTools::Stderr(strdata);
+ }
+ }
+ }
+
+ cmsysProcess_WaitForExit(cp, nullptr);
+
+ if (captureStdOut) {
+ captureStdOut->assign(tempStdOut.begin(), tempStdOut.end());
+ processOutput.DecodeText(*captureStdOut, *captureStdOut);
+ }
+ if (captureStdErr) {
+ captureStdErr->assign(tempStdErr.begin(), tempStdErr.end());
+ processOutput.DecodeText(*captureStdErr, *captureStdErr);
+ }
+
+ bool result = true;
+ if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
+ if (retVal) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ } else {
+ if (cmsysProcess_GetExitValue(cp) != 0) {
+ result = false;
+ }
+ }
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) {
+ const char* exception_str = cmsysProcess_GetExceptionString(cp);
+ if (outputflag != OUTPUT_NONE) {
+ std::cerr << exception_str << std::endl;
+ }
+ if (captureStdErr) {
+ captureStdErr->append(exception_str, strlen(exception_str));
+ } else if (captureStdOut) {
+ captureStdOut->append(exception_str, strlen(exception_str));
+ }
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
+ const char* error_str = cmsysProcess_GetErrorString(cp);
+ if (outputflag != OUTPUT_NONE) {
+ std::cerr << error_str << std::endl;
+ }
+ if (captureStdErr) {
+ captureStdErr->append(error_str, strlen(error_str));
+ } else if (captureStdOut) {
+ captureStdOut->append(error_str, strlen(error_str));
+ }
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) {
+ const char* error_str = "Process terminated due to timeout\n";
+ if (outputflag != OUTPUT_NONE) {
+ std::cerr << error_str << std::endl;
+ }
+ if (captureStdErr) {
+ captureStdErr->append(error_str, strlen(error_str));
+ }
+ result = false;
+ }
+
+ cmsysProcess_Delete(cp);
+ return result;
+}
+
+bool cmSystemTools::RunSingleCommand(const std::string& command,
+ std::string* captureStdOut,
+ std::string* captureStdErr, int* retVal,
+ const char* dir, OutputOption outputflag,
+ cmDuration timeout)
+{
+ if (s_DisableRunCommandOutput) {
+ outputflag = OUTPUT_NONE;
+ }
+
+ std::vector<std::string> args = cmSystemTools::ParseArguments(command);
+
+ if (args.empty()) {
+ return false;
+ }
+ return cmSystemTools::RunSingleCommand(args, captureStdOut, captureStdErr,
+ retVal, dir, outputflag, timeout);
+}
+
+std::string cmSystemTools::PrintSingleCommand(
+ std::vector<std::string> const& command)
+{
+ if (command.empty()) {
+ return std::string();
+ }
+
+ return cmWrap('"', command, '"', " ");
+}
+
+bool cmSystemTools::DoesFileExistWithExtensions(
+ const std::string& name, const std::vector<std::string>& headerExts)
+{
+ std::string hname;
+
+ for (std::string const& headerExt : headerExts) {
+ hname = cmStrCat(name, '.', headerExt);
+ if (cmSystemTools::FileExists(hname)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::string cmSystemTools::FileExistsInParentDirectories(
+ const std::string& fname, const std::string& directory,
+ const std::string& toplevel)
+{
+ std::string file = fname;
+ cmSystemTools::ConvertToUnixSlashes(file);
+ std::string dir = directory;
+ cmSystemTools::ConvertToUnixSlashes(dir);
+ std::string prevDir;
+ while (dir != prevDir) {
+ std::string path = cmStrCat(dir, "/", file);
+ if (cmSystemTools::FileExists(path)) {
+ return path;
+ }
+ if (dir.size() < toplevel.size()) {
+ break;
+ }
+ prevDir = dir;
+ dir = cmSystemTools::GetParentDirectory(dir);
+ }
+ return "";
+}
+
+#ifdef _WIN32
+namespace {
+
+/* Helper class to save and restore the specified file (or directory)
+ attribute bits. Instantiate this class as an automatic variable on the
+ stack. Its constructor saves a copy of the file attributes, and then its
+ destructor restores the original attribute settings. */
+class SaveRestoreFileAttributes
+{
+public:
+ SaveRestoreFileAttributes(std::wstring const& path,
+ uint32_t file_attrs_to_set);
+ ~SaveRestoreFileAttributes();
+
+ SaveRestoreFileAttributes(SaveRestoreFileAttributes const&) = delete;
+ SaveRestoreFileAttributes& operator=(SaveRestoreFileAttributes const&) =
+ delete;
+
+ void SetPath(std::wstring const& path) { path_ = path; }
+
+private:
+ std::wstring path_;
+ uint32_t original_attr_bits_;
+};
+
+SaveRestoreFileAttributes::SaveRestoreFileAttributes(
+ std::wstring const& path, uint32_t file_attrs_to_set)
+ : path_(path)
+ , original_attr_bits_(0)
+{
+ // Set the specified attributes for the source file/directory.
+ original_attr_bits_ = GetFileAttributesW(path_.c_str());
+ if ((INVALID_FILE_ATTRIBUTES != original_attr_bits_) &&
+ ((file_attrs_to_set & original_attr_bits_) != file_attrs_to_set)) {
+ SetFileAttributesW(path_.c_str(), original_attr_bits_ | file_attrs_to_set);
+ }
+}
+
+// We set attribute bits. Now we need to restore their original state.
+SaveRestoreFileAttributes::~SaveRestoreFileAttributes()
+{
+ DWORD last_error = GetLastError();
+ // Verify or restore the original attributes.
+ const DWORD source_attr_bits = GetFileAttributesW(path_.c_str());
+ if (INVALID_FILE_ATTRIBUTES != source_attr_bits) {
+ if (original_attr_bits_ != source_attr_bits) {
+ // The file still exists, and its attributes aren't our saved values.
+ // Time to restore them.
+ SetFileAttributesW(path_.c_str(), original_attr_bits_);
+ }
+ }
+ SetLastError(last_error);
+}
+
+struct WindowsFileRetryInit
+{
+ cmSystemTools::WindowsFileRetry Retry;
+ bool Explicit;
+};
+
+WindowsFileRetryInit InitWindowsFileRetry(wchar_t const* const values[2],
+ unsigned int const defaults[2])
+{
+ unsigned int data[2] = { 0, 0 };
+ HKEY const keys[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE };
+ for (int k = 0; k < 2; ++k) {
+ HKEY hKey;
+ if (RegOpenKeyExW(keys[k], L"Software\\Kitware\\CMake\\Config", 0,
+ KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
+ for (int v = 0; v < 2; ++v) {
+ DWORD dwData, dwType, dwSize = 4;
+ if (!data[v] &&
+ RegQueryValueExW(hKey, values[v], 0, &dwType, (BYTE*)&dwData,
+ &dwSize) == ERROR_SUCCESS &&
+ dwType == REG_DWORD && dwSize == 4) {
+ data[v] = static_cast<unsigned int>(dwData);
+ }
+ }
+ RegCloseKey(hKey);
+ }
+ }
+ WindowsFileRetryInit init;
+ init.Explicit = data[0] || data[1];
+ init.Retry.Count = data[0] ? data[0] : defaults[0];
+ init.Retry.Delay = data[1] ? data[1] : defaults[1];
+ return init;
+}
+
+WindowsFileRetryInit InitWindowsFileRetry()
+{
+ static wchar_t const* const values[2] = { L"FilesystemRetryCount",
+ L"FilesystemRetryDelay" };
+ static unsigned int const defaults[2] = { 5, 500 };
+ return InitWindowsFileRetry(values, defaults);
+}
+
+WindowsFileRetryInit InitWindowsDirectoryRetry()
+{
+ static wchar_t const* const values[2] = { L"FilesystemDirectoryRetryCount",
+ L"FilesystemDirectoryRetryDelay" };
+ static unsigned int const defaults[2] = { 120, 500 };
+ WindowsFileRetryInit dirInit = InitWindowsFileRetry(values, defaults);
+ if (dirInit.Explicit) {
+ return dirInit;
+ }
+ WindowsFileRetryInit fileInit = InitWindowsFileRetry();
+ if (fileInit.Explicit) {
+ return fileInit;
+ }
+ return dirInit;
+}
+
+cmSystemTools::WindowsFileRetry GetWindowsRetry(std::wstring const& path)
+{
+ // If we are performing a directory operation, then try and get the
+ // appropriate timing info.
+ DWORD const attrs = GetFileAttributesW(path.c_str());
+ if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
+ return cmSystemTools::GetWindowsDirectoryRetry();
+ }
+ return cmSystemTools::GetWindowsFileRetry();
+}
+
+} // end of anonymous namespace
+
+cmSystemTools::WindowsFileRetry cmSystemTools::GetWindowsFileRetry()
+{
+ static WindowsFileRetry retry = InitWindowsFileRetry().Retry;
+ return retry;
+}
+
+cmSystemTools::WindowsFileRetry cmSystemTools::GetWindowsDirectoryRetry()
+{
+ static cmSystemTools::WindowsFileRetry retry =
+ InitWindowsDirectoryRetry().Retry;
+ return retry;
+}
+#endif
+
+std::string cmSystemTools::GetRealPathResolvingWindowsSubst(
+ const std::string& path, std::string* errorMessage)
+{
+#ifdef _WIN32
+ // uv_fs_realpath uses Windows Vista API so fallback to kwsys if not found
+ std::string resolved_path;
+ uv_fs_t req;
+ int err = uv_fs_realpath(NULL, &req, path.c_str(), NULL);
+ if (!err) {
+ resolved_path = std::string((char*)req.ptr);
+ cmSystemTools::ConvertToUnixSlashes(resolved_path);
+ // Normalize to upper-case drive letter as GetActualCaseForPath does.
+ if (resolved_path.size() > 1 && resolved_path[1] == ':') {
+ resolved_path[0] = toupper(resolved_path[0]);
+ }
+ } else if (err == UV_ENOSYS) {
+ resolved_path = cmsys::SystemTools::GetRealPath(path, errorMessage);
+ } else if (errorMessage) {
+ LPSTR message = NULL;
+ DWORD size = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&message, 0,
+ NULL);
+ *errorMessage = std::string(message, size);
+ LocalFree(message);
+
+ resolved_path = "";
+ } else {
+ resolved_path = path;
+ }
+ return resolved_path;
+#else
+ return cmsys::SystemTools::GetRealPath(path, errorMessage);
+#endif
+}
+
+void cmSystemTools::InitializeLibUV()
+{
+#if defined(_WIN32)
+ // Perform libuv one-time initialization now, and then un-do its
+ // global _fmode setting so that using libuv does not change the
+ // default file text/binary mode. See libuv issue 840.
+ if (uv_loop_t* loop = uv_default_loop()) {
+ uv_loop_close(loop);
+ }
+# ifdef _MSC_VER
+ _set_fmode(_O_TEXT);
+# else
+ _fmode = _O_TEXT;
+# endif
+ // Replace libuv's report handler with our own to suppress popups.
+ cmSystemTools::EnableMSVCDebugHook();
+#endif
+}
+
+#ifdef _WIN32
+namespace {
+bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname,
+ cmSystemTools::Replace replace)
+{
+ // Not only ignore any previous error, but clear any memory of it.
+ SetLastError(0);
+
+ DWORD flags = 0;
+ if (replace == cmSystemTools::Replace::Yes) {
+ // Use MOVEFILE_REPLACE_EXISTING to replace an existing destination file.
+ flags = flags | MOVEFILE_REPLACE_EXISTING;
+ }
+
+ return MoveFileExW(oldname.c_str(), newname.c_str(), flags);
+}
+}
+#endif
+
+bool cmSystemTools::CopySingleFile(const std::string& oldname,
+ const std::string& newname)
+{
+ return cmSystemTools::CopySingleFile(oldname, newname, CopyWhen::Always) ==
+ CopyResult::Success;
+}
+
+cmSystemTools::CopyResult cmSystemTools::CopySingleFile(
+ std::string const& oldname, std::string const& newname, CopyWhen when,
+ std::string* err)
+{
+ switch (when) {
+ case CopyWhen::Always:
+ break;
+ case CopyWhen::OnlyIfDifferent:
+ if (!FilesDiffer(oldname, newname)) {
+ return CopyResult::Success;
+ }
+ break;
+ }
+
+ mode_t perm = 0;
+ bool perms = SystemTools::GetPermissions(oldname, perm);
+
+ // If files are the same do not copy
+ if (SystemTools::SameFile(oldname, newname)) {
+ return CopyResult::Success;
+ }
+
+ if (!cmsys::SystemTools::CloneFileContent(oldname, newname)) {
+ // if cloning did not succeed, fall back to blockwise copy
+ if (!cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname)) {
+ ReportError(err);
+ return CopyResult::Failure;
+ }
+ }
+ if (perms) {
+ if (!SystemTools::SetPermissions(newname, perm)) {
+ ReportError(err);
+ return CopyResult::Failure;
+ }
+ }
+ return CopyResult::Success;
+}
+
+bool cmSystemTools::RenameFile(const std::string& oldname,
+ const std::string& newname)
+{
+ return cmSystemTools::RenameFile(oldname, newname, Replace::Yes) ==
+ RenameResult::Success;
+}
+
+cmSystemTools::RenameResult cmSystemTools::RenameFile(
+ std::string const& oldname, std::string const& newname, Replace replace,
+ std::string* err)
+{
+#ifdef _WIN32
+# ifndef INVALID_FILE_ATTRIBUTES
+# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+# endif
+ std::wstring const oldname_wstr =
+ SystemTools::ConvertToWindowsExtendedPath(oldname);
+ std::wstring const newname_wstr =
+ SystemTools::ConvertToWindowsExtendedPath(newname);
+
+ /* Windows MoveFileEx may not replace read-only or in-use files. If it
+ fails then remove the read-only attribute from any existing destination.
+ Try multiple times since we may be racing against another process
+ creating/opening the destination file just before our MoveFileEx. */
+ WindowsFileRetry retry = GetWindowsRetry(oldname_wstr);
+
+ // Use RAII to set the attribute bit blocking Microsoft Search Indexing,
+ // and restore the previous value upon return.
+ SaveRestoreFileAttributes save_restore_file_attributes(
+ oldname_wstr, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
+
+ DWORD move_last_error = 0;
+ while (!cmMoveFile(oldname_wstr, newname_wstr, replace) && --retry.Count) {
+ move_last_error = GetLastError();
+
+ // There was no error ==> the operation is not yet complete.
+ if (move_last_error == NO_ERROR) {
+ break;
+ }
+
+ // Try again only if failure was due to access/sharing permissions.
+ // Most often ERROR_ACCESS_DENIED (a.k.a. I/O error) for a directory, and
+ // ERROR_SHARING_VIOLATION for a file, are caused by one of the following:
+ // 1) Anti-Virus Software
+ // 2) Windows Search Indexer
+ // 3) Windows Explorer has an associated directory already opened.
+ if (move_last_error != ERROR_ACCESS_DENIED &&
+ move_last_error != ERROR_SHARING_VIOLATION) {
+ if (replace == Replace::No && move_last_error == ERROR_ALREADY_EXISTS) {
+ return RenameResult::NoReplace;
+ }
+ ReportError(err);
+ return RenameResult::Failure;
+ }
+
+ DWORD const attrs = GetFileAttributesW(newname_wstr.c_str());
+ if ((attrs != INVALID_FILE_ATTRIBUTES) &&
+ (attrs & FILE_ATTRIBUTE_READONLY) &&
+ // FILE_ATTRIBUTE_READONLY is not honored on directories.
+ !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
+ // Remove the read-only attribute from the destination file.
+ SetFileAttributesW(newname_wstr.c_str(),
+ attrs & ~FILE_ATTRIBUTE_READONLY);
+ } else {
+ // The file may be temporarily in use so wait a bit.
+ cmSystemTools::Delay(retry.Delay);
+ }
+ }
+
+ // If we were successful, then there was no error.
+ if (retry.Count > 0) {
+ move_last_error = 0;
+ // Restore the attributes on the new name.
+ save_restore_file_attributes.SetPath(newname_wstr);
+ }
+ SetLastError(move_last_error);
+ if (retry.Count > 0) {
+ return RenameResult::Success;
+ }
+ if (replace == Replace::No && GetLastError() == ERROR_ALREADY_EXISTS) {
+ return RenameResult::NoReplace;
+ }
+ ReportError(err);
+ return RenameResult::Failure;
+#else
+ // On UNIX we have OS-provided calls to create 'newname' atomically.
+ if (replace == Replace::No) {
+ if (link(oldname.c_str(), newname.c_str()) == 0) {
+ return RenameResult::Success;
+ }
+ if (errno == EEXIST) {
+ return RenameResult::NoReplace;
+ }
+ ReportError(err);
+ return RenameResult::Failure;
+ }
+ if (rename(oldname.c_str(), newname.c_str()) == 0) {
+ return RenameResult::Success;
+ }
+ ReportError(err);
+ return RenameResult::Failure;
+#endif
+}
+
+void cmSystemTools::MoveFileIfDifferent(const std::string& source,
+ const std::string& destination)
+{
+ if (FilesDiffer(source, destination)) {
+ if (RenameFile(source, destination)) {
+ return;
+ }
+ CopyFileAlways(source, destination);
+ }
+ RemoveFile(source);
+}
+
+std::string cmSystemTools::ComputeFileHash(const std::string& source,
+ cmCryptoHash::Algo algo)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ cmCryptoHash hash(algo);
+ return hash.HashFile(source);
+#else
+ (void)source;
+ cmSystemTools::Message("hashsum not supported in bootstrapping mode",
+ "Error");
+ return std::string();
+#endif
+}
+
+std::string cmSystemTools::ComputeStringMD5(const std::string& input)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ cmCryptoHash md5(cmCryptoHash::AlgoMD5);
+ return md5.HashString(input);
+#else
+ (void)input;
+ cmSystemTools::Message("md5sum not supported in bootstrapping mode",
+ "Error");
+ return "";
+#endif
+}
+
+std::string cmSystemTools::ComputeCertificateThumbprint(
+ const std::string& source)
+{
+ std::string thumbprint;
+
+#if !defined(CMAKE_BOOTSTRAP) && defined(_WIN32)
+ CRYPT_INTEGER_BLOB cryptBlob;
+ HCERTSTORE certStore = NULL;
+ PCCERT_CONTEXT certContext = NULL;
+
+ HANDLE certFile = CreateFileW(
+ cmsys::Encoding::ToWide(source.c_str()).c_str(), GENERIC_READ,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (certFile != INVALID_HANDLE_VALUE && certFile != NULL) {
+ DWORD fileSize = GetFileSize(certFile, NULL);
+ if (fileSize != INVALID_FILE_SIZE) {
+ auto certData = cm::make_unique<BYTE[]>(fileSize);
+ if (certData != NULL) {
+ DWORD dwRead = 0;
+ if (ReadFile(certFile, certData.get(), fileSize, &dwRead, NULL)) {
+ cryptBlob.cbData = fileSize;
+ cryptBlob.pbData = certData.get();
+
+ // Verify that this is a valid cert
+ if (PFXIsPFXBlob(&cryptBlob)) {
+ // Open the certificate as a store
+ certStore = PFXImportCertStore(&cryptBlob, NULL, CRYPT_EXPORTABLE);
+ if (certStore != NULL) {
+ // There should only be 1 cert.
+ certContext =
+ CertEnumCertificatesInStore(certStore, certContext);
+ if (certContext != NULL) {
+ // The hash is 20 bytes
+ BYTE hashData[20];
+ DWORD hashLength = 20;
+
+ // Buffer to print the hash. Each byte takes 2 chars +
+ // terminating character
+ char hashPrint[41];
+ char* pHashPrint = hashPrint;
+ // Get the hash property from the certificate
+ if (CertGetCertificateContextProperty(
+ certContext, CERT_HASH_PROP_ID, hashData, &hashLength)) {
+ for (DWORD i = 0; i < hashLength; i++) {
+ // Convert each byte to hexadecimal
+ sprintf(pHashPrint, "%02X", hashData[i]);
+ pHashPrint += 2;
+ }
+ *pHashPrint = '\0';
+ thumbprint = hashPrint;
+ }
+ CertFreeCertificateContext(certContext);
+ }
+ CertCloseStore(certStore, 0);
+ }
+ }
+ }
+ }
+ }
+ CloseHandle(certFile);
+ }
+#else
+ (void)source;
+ cmSystemTools::Message("ComputeCertificateThumbprint is not implemented",
+ "Error");
+#endif
+
+ return thumbprint;
+}
+
+void cmSystemTools::Glob(const std::string& directory,
+ const std::string& regexp,
+ std::vector<std::string>& files)
+{
+ cmsys::Directory d;
+ cmsys::RegularExpression reg(regexp.c_str());
+
+ if (d.Load(directory)) {
+ size_t numf;
+ unsigned int i;
+ numf = d.GetNumberOfFiles();
+ for (i = 0; i < numf; i++) {
+ std::string fname = d.GetFile(i);
+ if (reg.find(fname)) {
+ files.push_back(std::move(fname));
+ }
+ }
+ }
+}
+
+void cmSystemTools::GlobDirs(const std::string& path,
+ std::vector<std::string>& files)
+{
+ std::string::size_type pos = path.find("/*");
+ if (pos == std::string::npos) {
+ files.push_back(path);
+ return;
+ }
+ std::string startPath = path.substr(0, pos);
+ std::string finishPath = path.substr(pos + 2);
+
+ cmsys::Directory d;
+ if (d.Load(startPath)) {
+ for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i) {
+ if ((std::string(d.GetFile(i)) != ".") &&
+ (std::string(d.GetFile(i)) != "..")) {
+ std::string fname = cmStrCat(startPath, '/', d.GetFile(i));
+ if (cmSystemTools::FileIsDirectory(fname)) {
+ fname += finishPath;
+ cmSystemTools::GlobDirs(fname, files);
+ }
+ }
+ }
+ }
+}
+
+bool cmSystemTools::SimpleGlob(const std::string& glob,
+ std::vector<std::string>& files,
+ int type /* = 0 */)
+{
+ files.clear();
+ if (glob.back() != '*') {
+ return false;
+ }
+ std::string path = cmSystemTools::GetFilenamePath(glob);
+ std::string ppath = cmSystemTools::GetFilenameName(glob);
+ ppath = ppath.substr(0, ppath.size() - 1);
+ if (path.empty()) {
+ path = "/";
+ }
+
+ bool res = false;
+ cmsys::Directory d;
+ if (d.Load(path)) {
+ for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i) {
+ if ((std::string(d.GetFile(i)) != ".") &&
+ (std::string(d.GetFile(i)) != "..")) {
+ std::string fname = path;
+ if (path.back() != '/') {
+ fname += "/";
+ }
+ fname += d.GetFile(i);
+ std::string sfname = d.GetFile(i);
+ if (type > 0 && cmSystemTools::FileIsDirectory(fname)) {
+ continue;
+ }
+ if (type < 0 && !cmSystemTools::FileIsDirectory(fname)) {
+ continue;
+ }
+ if (cmHasPrefix(sfname, ppath)) {
+ files.push_back(fname);
+ res = true;
+ }
+ }
+ }
+ }
+ return res;
+}
+
+std::string cmSystemTools::ConvertToOutputPath(std::string const& path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (s_ForceUnixPaths) {
+ return cmSystemTools::ConvertToUnixOutputPath(path);
+ }
+ return cmSystemTools::ConvertToWindowsOutputPath(path);
+#else
+ return cmSystemTools::ConvertToUnixOutputPath(path);
+#endif
+}
+
+void cmSystemTools::ConvertToOutputSlashes(std::string& path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (!s_ForceUnixPaths) {
+ // Convert to windows slashes.
+ std::string::size_type pos = 0;
+ while ((pos = path.find('/', pos)) != std::string::npos) {
+ path[pos++] = '\\';
+ }
+ }
+#else
+ static_cast<void>(path);
+#endif
+}
+
+void cmSystemTools::ConvertToLongPath(std::string& path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // Try to convert path to a long path only if the path contains character '~'
+ if (path.find('~') == std::string::npos) {
+ return;
+ }
+
+ std::wstring wPath = cmsys::Encoding::ToWide(path);
+ DWORD ret = GetLongPathNameW(wPath.c_str(), nullptr, 0);
+ std::vector<wchar_t> buffer(ret);
+ if (ret != 0) {
+ ret = GetLongPathNameW(wPath.c_str(), buffer.data(),
+ static_cast<DWORD>(buffer.size()));
+ }
+
+ if (ret != 0) {
+ path = cmsys::Encoding::ToNarrow(buffer.data());
+ }
+#else
+ static_cast<void>(path);
+#endif
+}
+
+std::string cmSystemTools::ConvertToRunCommandPath(const std::string& path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ return cmSystemTools::ConvertToWindowsOutputPath(path);
+#else
+ return cmSystemTools::ConvertToUnixOutputPath(path);
+#endif
+}
+
+// compute the relative path from here to there
+std::string cmSystemTools::RelativePath(std::string const& local,
+ std::string const& remote)
+{
+ if (!cmSystemTools::FileIsFullPath(local)) {
+ cmSystemTools::Error("RelativePath must be passed a full path to local: " +
+ local);
+ }
+ if (!cmSystemTools::FileIsFullPath(remote)) {
+ cmSystemTools::Error(
+ "RelativePath must be passed a full path to remote: " + remote);
+ }
+ return cmsys::SystemTools::RelativePath(local, remote);
+}
+
+std::string cmSystemTools::ForceToRelativePath(std::string const& local_path,
+ std::string const& remote_path)
+{
+ // The paths should never be quoted.
+ assert(local_path.front() != '\"');
+ assert(remote_path.front() != '\"');
+
+ // The local path should never have a trailing slash except if it is just the
+ // bare root directory
+ assert(local_path.empty() || local_path.back() != '/' ||
+ local_path.size() == 1 ||
+ (local_path.size() == 3 && local_path[1] == ':' &&
+ ((local_path[0] >= 'A' && local_path[0] <= 'Z') ||
+ (local_path[0] >= 'a' && local_path[0] <= 'z'))));
+
+ // If the path is already relative then just return the path.
+ if (!cmSystemTools::FileIsFullPath(remote_path)) {
+ return remote_path;
+ }
+
+ // Identify the longest shared path component between the remote
+ // path and the local path.
+ std::vector<std::string> local;
+ cmSystemTools::SplitPath(local_path, local);
+ std::vector<std::string> remote;
+ cmSystemTools::SplitPath(remote_path, remote);
+ unsigned int common = 0;
+ while (common < remote.size() && common < local.size() &&
+ cmSystemTools::ComparePath(remote[common], local[common])) {
+ ++common;
+ }
+
+ // If no part of the path is in common then return the full path.
+ if (common == 0) {
+ return remote_path;
+ }
+
+ // If the entire path is in common then just return a ".".
+ if (common == remote.size() && common == local.size()) {
+ return ".";
+ }
+
+ // If the entire path is in common except for a trailing slash then
+ // just return a "./".
+ if (common + 1 == remote.size() && remote[common].empty() &&
+ common == local.size()) {
+ return "./";
+ }
+
+ // Construct the relative path.
+ std::string relative;
+
+ // First add enough ../ to get up to the level of the shared portion
+ // of the path. Leave off the trailing slash. Note that the last
+ // component of local will never be empty because local should never
+ // have a trailing slash.
+ for (unsigned int i = common; i < local.size(); ++i) {
+ relative += "..";
+ if (i < local.size() - 1) {
+ relative += "/";
+ }
+ }
+
+ // Now add the portion of the destination path that is not included
+ // in the shared portion of the path. Add a slash the first time
+ // only if there was already something in the path. If there was a
+ // trailing slash in the input then the last iteration of the loop
+ // will add a slash followed by an empty string which will preserve
+ // the trailing slash in the output.
+
+ if (!relative.empty() && !remote.empty()) {
+ relative += "/";
+ }
+ relative += cmJoin(cmMakeRange(remote).advance(common), "/");
+
+ // Finally return the path.
+ return relative;
+}
+
+#ifndef CMAKE_BOOTSTRAP
+bool cmSystemTools::UnsetEnv(const char* value)
+{
+# if !defined(HAVE_UNSETENV)
+ std::string var = cmStrCat(value, '=');
+ return cmSystemTools::PutEnv(var);
+# else
+ unsetenv(value);
+ return true;
+# endif
+}
+
+std::vector<std::string> cmSystemTools::GetEnvironmentVariables()
+{
+ std::vector<std::string> env;
+ int cc;
+ for (cc = 0; environ[cc]; ++cc) {
+ env.emplace_back(environ[cc]);
+ }
+ return env;
+}
+
+void cmSystemTools::AppendEnv(std::vector<std::string> const& env)
+{
+ for (std::string const& eit : env) {
+ cmSystemTools::PutEnv(eit);
+ }
+}
+
+cmSystemTools::SaveRestoreEnvironment::SaveRestoreEnvironment()
+{
+ this->Env = cmSystemTools::GetEnvironmentVariables();
+}
+
+cmSystemTools::SaveRestoreEnvironment::~SaveRestoreEnvironment()
+{
+ // First clear everything in the current environment:
+ std::vector<std::string> currentEnv = GetEnvironmentVariables();
+ for (std::string var : currentEnv) {
+ std::string::size_type pos = var.find('=');
+ if (pos != std::string::npos) {
+ var = var.substr(0, pos);
+ }
+
+ cmSystemTools::UnsetEnv(var.c_str());
+ }
+
+ // Then put back each entry from the original environment:
+ cmSystemTools::AppendEnv(this->Env);
+}
+#endif
+
+void cmSystemTools::EnableVSConsoleOutput()
+{
+#ifdef _WIN32
+ // Visual Studio tools like devenv may not
+ // display output to the console unless this environment variable is
+ // set. We need it to capture the output of these build tools.
+ // Note for future work that one could pass "/out \\.\pipe\NAME" to
+ // either of these executables where NAME is created with
+ // CreateNamedPipe. This would bypass the internal buffering of the
+ // output and allow it to be captured on the fly.
+ cmSystemTools::PutEnv("vsconsoleoutput=1");
+
+# ifndef CMAKE_BOOTSTRAP
+ // VS sets an environment variable to tell MS tools like "cl" to report
+ // output through a backdoor pipe instead of stdout/stderr. Unset the
+ // environment variable to close this backdoor for any path of process
+ // invocations that passes through CMake so we can capture the output.
+ cmSystemTools::UnsetEnv("VS_UNICODE_OUTPUT");
+# endif
+#endif
+}
+
+bool cmSystemTools::IsPathToFramework(const std::string& path)
+{
+ return (cmSystemTools::FileIsFullPath(path) &&
+ cmHasLiteralSuffix(path, ".framework"));
+}
+
+bool cmSystemTools::CreateTar(const std::string& outFileName,
+ const std::vector<std::string>& files,
+ cmTarCompression compressType, bool verbose,
+ std::string const& mtime,
+ std::string const& format, int compressionLevel)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ cmsys::ofstream fout(outFileName.c_str(), std::ios::out | std::ios::binary);
+ if (!fout) {
+ std::string e = cmStrCat("Cannot open output file \"", outFileName,
+ "\": ", cmSystemTools::GetLastSystemError());
+ cmSystemTools::Error(e);
+ return false;
+ }
+ cmArchiveWrite::Compress compress = cmArchiveWrite::CompressNone;
+ switch (compressType) {
+ case TarCompressGZip:
+ compress = cmArchiveWrite::CompressGZip;
+ break;
+ case TarCompressBZip2:
+ compress = cmArchiveWrite::CompressBZip2;
+ break;
+ case TarCompressXZ:
+ compress = cmArchiveWrite::CompressXZ;
+ break;
+ case TarCompressZstd:
+ compress = cmArchiveWrite::CompressZstd;
+ break;
+ case TarCompressNone:
+ compress = cmArchiveWrite::CompressNone;
+ break;
+ }
+
+ cmArchiveWrite a(fout, compress, format.empty() ? "paxr" : format,
+ compressionLevel);
+
+ a.Open();
+ a.SetMTime(mtime);
+ a.SetVerbose(verbose);
+ bool tarCreatedSuccessfully = true;
+ for (auto path : files) {
+ if (cmSystemTools::FileIsFullPath(path)) {
+ // Get the relative path to the file.
+ path = cmSystemTools::RelativePath(cwd, path);
+ }
+ if (!a.Add(path)) {
+ cmSystemTools::Error(a.GetError());
+ tarCreatedSuccessfully = false;
+ }
+ }
+ return tarCreatedSuccessfully;
+#else
+ (void)outFileName;
+ (void)files;
+ (void)verbose;
+ return false;
+#endif
+}
+
+#if !defined(CMAKE_BOOTSTRAP)
+namespace {
+# define BSDTAR_FILESIZE_PRINTF "%lu"
+# define BSDTAR_FILESIZE_TYPE unsigned long
+void list_item_verbose(FILE* out, struct archive_entry* entry)
+{
+ char tmp[100];
+ size_t w;
+ const char* p;
+ const char* fmt;
+ time_t tim;
+ static time_t now;
+ size_t u_width = 6;
+ size_t gs_width = 13;
+
+ /*
+ * We avoid collecting the entire list in memory at once by
+ * listing things as we see them. However, that also means we can't
+ * just pre-compute the field widths. Instead, we start with guesses
+ * and just widen them as necessary. These numbers are completely
+ * arbitrary.
+ */
+ if (!now) {
+ time(&now);
+ }
+ fprintf(out, "%s %d ", archive_entry_strmode(entry),
+ archive_entry_nlink(entry));
+
+ /* Use uname if it's present, else uid. */
+ p = archive_entry_uname(entry);
+ if ((p == nullptr) || (*p == '\0')) {
+ sprintf(tmp, "%lu ", static_cast<unsigned long>(archive_entry_uid(entry)));
+ p = tmp;
+ }
+ w = strlen(p);
+ if (w > u_width) {
+ u_width = w;
+ }
+ fprintf(out, "%-*s ", static_cast<int>(u_width), p);
+ /* Use gname if it's present, else gid. */
+ p = archive_entry_gname(entry);
+ if (p != nullptr && p[0] != '\0') {
+ fprintf(out, "%s", p);
+ w = strlen(p);
+ } else {
+ sprintf(tmp, "%lu", static_cast<unsigned long>(archive_entry_gid(entry)));
+ w = strlen(tmp);
+ fprintf(out, "%s", tmp);
+ }
+
+ /*
+ * Print device number or file size, right-aligned so as to make
+ * total width of group and devnum/filesize fields be gs_width.
+ * If gs_width is too small, grow it.
+ */
+ if (archive_entry_filetype(entry) == AE_IFCHR ||
+ archive_entry_filetype(entry) == AE_IFBLK) {
+ unsigned long rdevmajor = archive_entry_rdevmajor(entry);
+ unsigned long rdevminor = archive_entry_rdevminor(entry);
+ sprintf(tmp, "%lu,%lu", rdevmajor, rdevminor);
+ } else {
+ /*
+ * Note the use of platform-dependent macros to format
+ * the filesize here. We need the format string and the
+ * corresponding type for the cast.
+ */
+ sprintf(tmp, BSDTAR_FILESIZE_PRINTF,
+ static_cast<BSDTAR_FILESIZE_TYPE>(archive_entry_size(entry)));
+ }
+ if (w + strlen(tmp) >= gs_width) {
+ gs_width = w + strlen(tmp) + 1;
+ }
+ fprintf(out, "%*s", static_cast<int>(gs_width - w), tmp);
+
+ /* Format the time using 'ls -l' conventions. */
+ tim = archive_entry_mtime(entry);
+# define HALF_YEAR ((time_t)365 * 86400 / 2)
+# if defined(_WIN32) && !defined(__CYGWIN__)
+/* Windows' strftime function does not support %e format. */
+# define DAY_FMT "%d"
+# else
+# define DAY_FMT "%e" /* Day number without leading zeros */
+# endif
+ if (tim < now - HALF_YEAR || tim > now + HALF_YEAR) {
+ fmt = DAY_FMT " %b %Y";
+ } else {
+ fmt = DAY_FMT " %b %H:%M";
+ }
+ strftime(tmp, sizeof(tmp), fmt, localtime(&tim));
+ fprintf(out, " %s ", tmp);
+ fprintf(out, "%s", cm_archive_entry_pathname(entry).c_str());
+
+ /* Extra information for links. */
+ if (archive_entry_hardlink(entry)) /* Hard link */
+ {
+ fprintf(out, " link to %s", archive_entry_hardlink(entry));
+ } else if (archive_entry_symlink(entry)) /* Symbolic link */
+ {
+ fprintf(out, " -> %s", archive_entry_symlink(entry));
+ }
+ fflush(out);
+}
+
+void ArchiveError(const char* m1, struct archive* a)
+{
+ std::string message(m1);
+ const char* m2 = archive_error_string(a);
+ if (m2) {
+ message += m2;
+ }
+ cmSystemTools::Error(message);
+}
+
+bool la_diagnostic(struct archive* ar, __LA_SSIZE_T r)
+{
+ // See archive.h definition of ARCHIVE_OK for return values.
+
+ if (r >= ARCHIVE_OK) {
+ return true;
+ }
+
+ if (r >= ARCHIVE_WARN) {
+ const char* warn = archive_error_string(ar);
+ if (!warn) {
+ warn = "unknown warning";
+ }
+ std::cerr << "cmake -E tar: warning: " << warn << '\n';
+ return true;
+ }
+
+ // Error.
+ const char* err = archive_error_string(ar);
+ if (!err) {
+ err = "unknown error";
+ }
+ std::cerr << "cmake -E tar: error: " << err << '\n';
+ return false;
+}
+
+// Return 'true' on success
+bool copy_data(struct archive* ar, struct archive* aw)
+{
+ long r;
+ const void* buff;
+ size_t size;
+# if defined(ARCHIVE_VERSION_NUMBER) && ARCHIVE_VERSION_NUMBER >= 3000000
+ __LA_INT64_T offset;
+# else
+ off_t offset;
+# endif
+
+ for (;;) {
+ // See archive.h definition of ARCHIVE_OK for return values.
+ r = archive_read_data_block(ar, &buff, &size, &offset);
+ if (r == ARCHIVE_EOF) {
+ return true;
+ }
+ if (!la_diagnostic(ar, r)) {
+ return false;
+ }
+ // See archive.h definition of ARCHIVE_OK for return values.
+ __LA_SSIZE_T const w = archive_write_data_block(aw, buff, size, offset);
+ if (!la_diagnostic(ar, w)) {
+ return false;
+ }
+ }
+# if !defined(__clang__) && !defined(__HP_aCC)
+ return false; /* this should not happen but it quiets some compilers */
+# endif
+}
+
+bool extract_tar(const std::string& outFileName,
+ const std::vector<std::string>& files, bool verbose,
+ bool extract)
+{
+ cmLocaleRAII localeRAII;
+ static_cast<void>(localeRAII);
+ struct archive* a = archive_read_new();
+ struct archive* ext = archive_write_disk_new();
+ archive_read_support_filter_all(a);
+ archive_read_support_format_all(a);
+ struct archive_entry* entry;
+
+ struct archive* matching = archive_match_new();
+ if (matching == nullptr) {
+ cmSystemTools::Error("Out of memory");
+ return false;
+ }
+
+ for (const auto& filename : files) {
+ if (archive_match_include_pattern(matching, filename.c_str()) !=
+ ARCHIVE_OK) {
+ cmSystemTools::Error("Failed to add to inclusion list: " + filename);
+ return false;
+ }
+ }
+
+ int r = cm_archive_read_open_file(a, outFileName.c_str(), 10240);
+ if (r) {
+ ArchiveError("Problem with archive_read_open_file(): ", a);
+ archive_write_free(ext);
+ archive_read_close(a);
+ return false;
+ }
+ for (;;) {
+ r = archive_read_next_header(a, &entry);
+ if (r == ARCHIVE_EOF) {
+ break;
+ }
+ if (r != ARCHIVE_OK) {
+ ArchiveError("Problem with archive_read_next_header(): ", a);
+ break;
+ }
+
+ if (archive_match_excluded(matching, entry)) {
+ continue;
+ }
+
+ if (verbose) {
+ if (extract) {
+ cmSystemTools::Stdout("x ");
+ cmSystemTools::Stdout(cm_archive_entry_pathname(entry));
+ } else {
+ list_item_verbose(stdout, entry);
+ }
+ cmSystemTools::Stdout("\n");
+ } else if (!extract) {
+ cmSystemTools::Stdout(cm_archive_entry_pathname(entry));
+ cmSystemTools::Stdout("\n");
+ }
+ if (extract) {
+ r = archive_write_disk_set_options(ext, ARCHIVE_EXTRACT_TIME);
+ if (r != ARCHIVE_OK) {
+ ArchiveError("Problem with archive_write_disk_set_options(): ", ext);
+ break;
+ }
+
+ r = archive_write_header(ext, entry);
+ if (r == ARCHIVE_OK) {
+ if (!copy_data(a, ext)) {
+ break;
+ }
+ r = archive_write_finish_entry(ext);
+ if (r != ARCHIVE_OK) {
+ ArchiveError("Problem with archive_write_finish_entry(): ", ext);
+ break;
+ }
+ }
+# ifdef _WIN32
+ else if (const char* linktext = archive_entry_symlink(entry)) {
+ std::cerr << "cmake -E tar: warning: skipping symbolic link \""
+ << cm_archive_entry_pathname(entry) << "\" -> \"" << linktext
+ << "\"." << std::endl;
+ }
+# endif
+ else {
+ ArchiveError("Problem with archive_write_header(): ", ext);
+ cmSystemTools::Error("Current file: " +
+ cm_archive_entry_pathname(entry));
+ break;
+ }
+ }
+ }
+
+ bool error_occured = false;
+ if (matching != nullptr) {
+ const char* p;
+ int ar;
+
+ while ((ar = archive_match_path_unmatched_inclusions_next(matching, &p)) ==
+ ARCHIVE_OK) {
+ cmSystemTools::Error("tar: " + std::string(p) +
+ ": Not found in archive");
+ error_occured = true;
+ }
+ if (error_occured) {
+ return false;
+ }
+ if (ar == ARCHIVE_FATAL) {
+ cmSystemTools::Error("tar: Out of memory");
+ return false;
+ }
+ }
+ archive_match_free(matching);
+ archive_write_free(ext);
+ archive_read_close(a);
+ archive_read_free(a);
+ return r == ARCHIVE_EOF || r == ARCHIVE_OK;
+}
+}
+#endif
+
+bool cmSystemTools::ExtractTar(const std::string& outFileName,
+ const std::vector<std::string>& files,
+ bool verbose)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ return extract_tar(outFileName, files, verbose, true);
+#else
+ (void)outFileName;
+ (void)files;
+ (void)verbose;
+ return false;
+#endif
+}
+
+bool cmSystemTools::ListTar(const std::string& outFileName,
+ const std::vector<std::string>& files,
+ bool verbose)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ return extract_tar(outFileName, files, verbose, false);
+#else
+ (void)outFileName;
+ (void)files;
+ (void)verbose;
+ return false;
+#endif
+}
+
+int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
+ cmDuration timeout, std::vector<char>& out,
+ std::vector<char>& err)
+{
+ line.clear();
+ auto outiter = out.begin();
+ auto erriter = err.begin();
+ cmProcessOutput processOutput;
+ std::string strdata;
+ while (true) {
+ // Check for a newline in stdout.
+ for (; outiter != out.end(); ++outiter) {
+ if ((*outiter == '\r') && ((outiter + 1) == out.end())) {
+ break;
+ }
+ if (*outiter == '\n' || *outiter == '\0') {
+ std::vector<char>::size_type length = outiter - out.begin();
+ if (length > 1 && *(outiter - 1) == '\r') {
+ --length;
+ }
+ if (length > 0) {
+ line.append(&out[0], length);
+ }
+ out.erase(out.begin(), outiter + 1);
+ return cmsysProcess_Pipe_STDOUT;
+ }
+ }
+
+ // Check for a newline in stderr.
+ for (; erriter != err.end(); ++erriter) {
+ if ((*erriter == '\r') && ((erriter + 1) == err.end())) {
+ break;
+ }
+ if (*erriter == '\n' || *erriter == '\0') {
+ std::vector<char>::size_type length = erriter - err.begin();
+ if (length > 1 && *(erriter - 1) == '\r') {
+ --length;
+ }
+ if (length > 0) {
+ line.append(&err[0], length);
+ }
+ err.erase(err.begin(), erriter + 1);
+ return cmsysProcess_Pipe_STDERR;
+ }
+ }
+
+ // No newlines found. Wait for more data from the process.
+ int length;
+ char* data;
+ double timeoutAsDbl = timeout.count();
+ int pipe =
+ cmsysProcess_WaitForData(process, &data, &length, &timeoutAsDbl);
+ if (pipe == cmsysProcess_Pipe_Timeout) {
+ // Timeout has been exceeded.
+ return pipe;
+ }
+ if (pipe == cmsysProcess_Pipe_STDOUT) {
+ processOutput.DecodeText(data, length, strdata, 1);
+ // Append to the stdout buffer.
+ std::vector<char>::size_type size = out.size();
+ cm::append(out, strdata);
+ outiter = out.begin() + size;
+ } else if (pipe == cmsysProcess_Pipe_STDERR) {
+ processOutput.DecodeText(data, length, strdata, 2);
+ // Append to the stderr buffer.
+ std::vector<char>::size_type size = err.size();
+ cm::append(err, strdata);
+ erriter = err.begin() + size;
+ } else if (pipe == cmsysProcess_Pipe_None) {
+ // Both stdout and stderr pipes have broken. Return leftover data.
+ processOutput.DecodeText(std::string(), strdata, 1);
+ if (!strdata.empty()) {
+ std::vector<char>::size_type size = out.size();
+ cm::append(out, strdata);
+ outiter = out.begin() + size;
+ }
+ processOutput.DecodeText(std::string(), strdata, 2);
+ if (!strdata.empty()) {
+ std::vector<char>::size_type size = err.size();
+ cm::append(err, strdata);
+ erriter = err.begin() + size;
+ }
+ if (!out.empty()) {
+ line.append(&out[0], outiter - out.begin());
+ out.erase(out.begin(), out.end());
+ return cmsysProcess_Pipe_STDOUT;
+ }
+ if (!err.empty()) {
+ line.append(&err[0], erriter - err.begin());
+ err.erase(err.begin(), err.end());
+ return cmsysProcess_Pipe_STDERR;
+ }
+ return cmsysProcess_Pipe_None;
+ }
+ }
+}
+
+#ifdef _WIN32
+static void EnsureStdPipe(DWORD fd)
+{
+ if (GetStdHandle(fd) != INVALID_HANDLE_VALUE) {
+ return;
+ }
+ SECURITY_ATTRIBUTES sa;
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ HANDLE h = CreateFileW(
+ L"NUL",
+ fd == STD_INPUT_HANDLE ? FILE_GENERIC_READ
+ : FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ LPSTR message = NULL;
+ DWORD size = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&message, 0, NULL);
+ std::string msg = std::string(message, size);
+ LocalFree(message);
+ std::cerr << "failed to open NUL for missing stdio pipe: " << msg;
+ abort();
+ }
+
+ SetStdHandle(fd, h);
+}
+
+void cmSystemTools::EnsureStdPipes()
+{
+ EnsureStdPipe(STD_INPUT_HANDLE);
+ EnsureStdPipe(STD_OUTPUT_HANDLE);
+ EnsureStdPipe(STD_ERROR_HANDLE);
+}
+#else
+static void EnsureStdPipe(int fd)
+{
+ if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) {
+ return;
+ }
+
+ int f = open("/dev/null", fd == STDIN_FILENO ? O_RDONLY : O_WRONLY);
+ if (f == -1) {
+ perror("failed to open /dev/null for missing stdio pipe");
+ abort();
+ }
+ if (f != fd) {
+ dup2(f, fd);
+ close(f);
+ }
+}
+
+void cmSystemTools::EnsureStdPipes()
+{
+ EnsureStdPipe(STDIN_FILENO);
+ EnsureStdPipe(STDOUT_FILENO);
+ EnsureStdPipe(STDERR_FILENO);
+}
+#endif
+
+void cmSystemTools::DoNotInheritStdPipes()
+{
+#ifdef _WIN32
+ // Check to see if we are attached to a console
+ // if so, then do not stop the inherited pipes
+ // or stdout and stderr will not show up in dos
+ // shell windows
+ CONSOLE_SCREEN_BUFFER_INFO hOutInfo;
+ HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (GetConsoleScreenBufferInfo(hOut, &hOutInfo)) {
+ return;
+ }
+ {
+ HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
+ DuplicateHandle(GetCurrentProcess(), out, GetCurrentProcess(), &out, 0,
+ FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
+ SetStdHandle(STD_OUTPUT_HANDLE, out);
+ }
+ {
+ HANDLE out = GetStdHandle(STD_ERROR_HANDLE);
+ DuplicateHandle(GetCurrentProcess(), out, GetCurrentProcess(), &out, 0,
+ FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
+ SetStdHandle(STD_ERROR_HANDLE, out);
+ }
+#endif
+}
+
+#ifdef _WIN32
+# ifndef CRYPT_SILENT
+# define CRYPT_SILENT 0x40 /* Not defined by VS 6 version of header. */
+# endif
+static int WinCryptRandom(void* data, size_t size)
+{
+ int result = 0;
+ HCRYPTPROV hProvider = 0;
+ if (CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
+ result = CryptGenRandom(hProvider, (DWORD)size, (BYTE*)data) ? 1 : 0;
+ CryptReleaseContext(hProvider, 0);
+ }
+ return result;
+}
+#endif
+
+unsigned int cmSystemTools::RandomSeed()
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ unsigned int seed = 0;
+
+ // Try using a real random source.
+ if (WinCryptRandom(&seed, sizeof(seed))) {
+ return seed;
+ }
+
+ // Fall back to the time and pid.
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft);
+ unsigned int t1 = static_cast<unsigned int>(ft.dwHighDateTime);
+ unsigned int t2 = static_cast<unsigned int>(ft.dwLowDateTime);
+ unsigned int pid = static_cast<unsigned int>(GetCurrentProcessId());
+ return t1 ^ t2 ^ pid;
+#else
+ union
+ {
+ unsigned int integer;
+ char bytes[sizeof(unsigned int)];
+ } seed;
+
+ // Try using a real random source.
+ cmsys::ifstream fin;
+ fin.rdbuf()->pubsetbuf(nullptr, 0); // Unbuffered read.
+ fin.open("/dev/urandom");
+ if (fin.good() && fin.read(seed.bytes, sizeof(seed)) &&
+ fin.gcount() == sizeof(seed)) {
+ return seed.integer;
+ }
+
+ // Fall back to the time and pid.
+ struct timeval t;
+ gettimeofday(&t, nullptr);
+ unsigned int pid = static_cast<unsigned int>(getpid());
+ unsigned int tv_sec = static_cast<unsigned int>(t.tv_sec);
+ unsigned int tv_usec = static_cast<unsigned int>(t.tv_usec);
+ // Since tv_usec never fills more than 11 bits we shift it to fill
+ // in the slow-changing high-order bits of tv_sec.
+ return tv_sec ^ (tv_usec << 21) ^ pid;
+#endif
+}
+
+static std::string cmSystemToolsCMakeCommand;
+static std::string cmSystemToolsCTestCommand;
+static std::string cmSystemToolsCPackCommand;
+static std::string cmSystemToolsCMakeCursesCommand;
+static std::string cmSystemToolsCMakeGUICommand;
+static std::string cmSystemToolsCMClDepsCommand;
+static std::string cmSystemToolsCMakeRoot;
+static std::string cmSystemToolsHTMLDoc;
+void cmSystemTools::FindCMakeResources(const char* argv0)
+{
+ std::string exe_dir;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ (void)argv0; // ignore this on windows
+ wchar_t modulepath[_MAX_PATH];
+ ::GetModuleFileNameW(NULL, modulepath, sizeof(modulepath));
+ std::string path = cmsys::Encoding::ToNarrow(modulepath);
+ std::string realPath =
+ cmSystemTools::GetRealPathResolvingWindowsSubst(path, NULL);
+ if (realPath.empty()) {
+ realPath = path;
+ }
+ exe_dir = cmSystemTools::GetFilenamePath(realPath);
+#elif defined(__APPLE__)
+ (void)argv0; // ignore this on OS X
+# define CM_EXE_PATH_LOCAL_SIZE 16384
+ char exe_path_local[CM_EXE_PATH_LOCAL_SIZE];
+# if defined(MAC_OS_X_VERSION_10_3) && !defined(MAC_OS_X_VERSION_10_4)
+ unsigned long exe_path_size = CM_EXE_PATH_LOCAL_SIZE;
+# else
+ uint32_t exe_path_size = CM_EXE_PATH_LOCAL_SIZE;
+# endif
+# undef CM_EXE_PATH_LOCAL_SIZE
+ char* exe_path = exe_path_local;
+ if (_NSGetExecutablePath(exe_path, &exe_path_size) < 0) {
+ exe_path = static_cast<char*>(malloc(exe_path_size));
+ _NSGetExecutablePath(exe_path, &exe_path_size);
+ }
+ exe_dir =
+ cmSystemTools::GetFilenamePath(cmSystemTools::GetRealPath(exe_path));
+ if (exe_path != exe_path_local) {
+ free(exe_path);
+ }
+ if (cmSystemTools::GetFilenameName(exe_dir) == "MacOS") {
+ // The executable is inside an application bundle.
+ // Look for ..<CMAKE_BIN_DIR> (install tree) and then fall back to
+ // ../../../bin (build tree).
+ exe_dir = cmSystemTools::GetFilenamePath(exe_dir);
+ if (cmSystemTools::FileExists(exe_dir + CMAKE_BIN_DIR "/cmake")) {
+ exe_dir += CMAKE_BIN_DIR;
+ } else {
+ exe_dir = cmSystemTools::GetFilenamePath(exe_dir);
+ exe_dir = cmSystemTools::GetFilenamePath(exe_dir);
+ }
+ }
+#else
+ std::string errorMsg;
+ std::string exe;
+ if (cmSystemTools::FindProgramPath(argv0, exe, errorMsg)) {
+ // remove symlinks
+ exe = cmSystemTools::GetRealPath(exe);
+ exe_dir = cmSystemTools::GetFilenamePath(exe);
+ } else {
+ // ???
+ }
+#endif
+ exe_dir = cmSystemTools::GetActualCaseForPath(exe_dir);
+ cmSystemToolsCMakeCommand =
+ cmStrCat(exe_dir, "/cmake", cmSystemTools::GetExecutableExtension());
+#ifdef CMAKE_BOOTSTRAP
+ // The bootstrap cmake does not provide the other tools,
+ // so use the directory where they are about to be built.
+ exe_dir = CMAKE_BOOTSTRAP_BINARY_DIR "/bin";
+#endif
+ cmSystemToolsCTestCommand =
+ cmStrCat(exe_dir, "/ctest", cmSystemTools::GetExecutableExtension());
+ cmSystemToolsCPackCommand =
+ cmStrCat(exe_dir, "/cpack", cmSystemTools::GetExecutableExtension());
+ cmSystemToolsCMakeGUICommand =
+ cmStrCat(exe_dir, "/cmake-gui", cmSystemTools::GetExecutableExtension());
+ if (!cmSystemTools::FileExists(cmSystemToolsCMakeGUICommand)) {
+ cmSystemToolsCMakeGUICommand.clear();
+ }
+ cmSystemToolsCMakeCursesCommand =
+ cmStrCat(exe_dir, "/ccmake", cmSystemTools::GetExecutableExtension());
+ if (!cmSystemTools::FileExists(cmSystemToolsCMakeCursesCommand)) {
+ cmSystemToolsCMakeCursesCommand.clear();
+ }
+ cmSystemToolsCMClDepsCommand =
+ cmStrCat(exe_dir, "/cmcldeps", cmSystemTools::GetExecutableExtension());
+ if (!cmSystemTools::FileExists(cmSystemToolsCMClDepsCommand)) {
+ cmSystemToolsCMClDepsCommand.clear();
+ }
+
+#ifndef CMAKE_BOOTSTRAP
+ // Install tree has
+ // - "<prefix><CMAKE_BIN_DIR>/cmake"
+ // - "<prefix><CMAKE_DATA_DIR>"
+ // - "<prefix><CMAKE_DOC_DIR>"
+ if (cmHasLiteralSuffix(exe_dir, CMAKE_BIN_DIR)) {
+ std::string const prefix =
+ exe_dir.substr(0, exe_dir.size() - cmStrLen(CMAKE_BIN_DIR));
+ cmSystemToolsCMakeRoot = cmStrCat(prefix, CMAKE_DATA_DIR);
+ if (cmSystemTools::FileExists(
+ cmStrCat(prefix, CMAKE_DOC_DIR "/html/index.html"))) {
+ cmSystemToolsHTMLDoc = cmStrCat(prefix, CMAKE_DOC_DIR "/html");
+ }
+ }
+ if (cmSystemToolsCMakeRoot.empty() ||
+ !cmSystemTools::FileExists(
+ cmStrCat(cmSystemToolsCMakeRoot, "/Modules/CMake.cmake"))) {
+ // Build tree has "<build>/bin[/<config>]/cmake" and
+ // "<build>/CMakeFiles/CMakeSourceDir.txt".
+ std::string dir = cmSystemTools::GetFilenamePath(exe_dir);
+ std::string src_dir_txt = cmStrCat(dir, "/CMakeFiles/CMakeSourceDir.txt");
+ cmsys::ifstream fin(src_dir_txt.c_str());
+ std::string src_dir;
+ if (fin && cmSystemTools::GetLineFromStream(fin, src_dir) &&
+ cmSystemTools::FileIsDirectory(src_dir)) {
+ cmSystemToolsCMakeRoot = src_dir;
+ } else {
+ dir = cmSystemTools::GetFilenamePath(dir);
+ src_dir_txt = cmStrCat(dir, "/CMakeFiles/CMakeSourceDir.txt");
+ cmsys::ifstream fin2(src_dir_txt.c_str());
+ if (fin2 && cmSystemTools::GetLineFromStream(fin2, src_dir) &&
+ cmSystemTools::FileIsDirectory(src_dir)) {
+ cmSystemToolsCMakeRoot = src_dir;
+ }
+ }
+ if (!cmSystemToolsCMakeRoot.empty() && cmSystemToolsHTMLDoc.empty() &&
+ cmSystemTools::FileExists(
+ cmStrCat(dir, "/Utilities/Sphinx/html/index.html"))) {
+ cmSystemToolsHTMLDoc = cmStrCat(dir, "/Utilities/Sphinx/html");
+ }
+ }
+#else
+ // Bootstrap build knows its source.
+ cmSystemToolsCMakeRoot = CMAKE_BOOTSTRAP_SOURCE_DIR;
+#endif
+}
+
+std::string const& cmSystemTools::GetCMakeCommand()
+{
+ return cmSystemToolsCMakeCommand;
+}
+
+std::string const& cmSystemTools::GetCTestCommand()
+{
+ return cmSystemToolsCTestCommand;
+}
+
+std::string const& cmSystemTools::GetCPackCommand()
+{
+ return cmSystemToolsCPackCommand;
+}
+
+std::string const& cmSystemTools::GetCMakeCursesCommand()
+{
+ return cmSystemToolsCMakeCursesCommand;
+}
+
+std::string const& cmSystemTools::GetCMakeGUICommand()
+{
+ return cmSystemToolsCMakeGUICommand;
+}
+
+std::string const& cmSystemTools::GetCMClDepsCommand()
+{
+ return cmSystemToolsCMClDepsCommand;
+}
+
+std::string const& cmSystemTools::GetCMakeRoot()
+{
+ return cmSystemToolsCMakeRoot;
+}
+
+std::string const& cmSystemTools::GetHTMLDoc()
+{
+ return cmSystemToolsHTMLDoc;
+}
+
+std::string cmSystemTools::GetCurrentWorkingDirectory()
+{
+ return cmSystemTools::CollapseFullPath(
+ cmsys::SystemTools::GetCurrentWorkingDirectory());
+}
+
+void cmSystemTools::MakefileColorEcho(int color, const char* message,
+ bool newline, bool enabled)
+{
+ // On some platforms (an MSYS prompt) cmsysTerminal may not be able
+ // to determine whether the stream is displayed on a tty. In this
+ // case it assumes no unless we tell it otherwise. Since we want
+ // color messages to be displayed for users we will assume yes.
+ // However, we can test for some situations when the answer is most
+ // likely no.
+ int assumeTTY = cmsysTerminal_Color_AssumeTTY;
+ if (cmSystemTools::HasEnv("DART_TEST_FROM_DART") ||
+ cmSystemTools::HasEnv("DASHBOARD_TEST_FROM_CTEST") ||
+ cmSystemTools::HasEnv("CTEST_INTERACTIVE_DEBUG_MODE")) {
+ // Avoid printing color escapes during dashboard builds.
+ assumeTTY = 0;
+ }
+
+ if (enabled && color != cmsysTerminal_Color_Normal) {
+ // Print with color. Delay the newline until later so that
+ // all color restore sequences appear before it.
+ cmsysTerminal_cfprintf(color | assumeTTY, stdout, "%s", message);
+ } else {
+ // Color is disabled. Print without color.
+ fprintf(stdout, "%s", message);
+ }
+
+ if (newline) {
+ fprintf(stdout, "\n");
+ }
+}
+
+bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath,
+ std::string& soname)
+{
+// For ELF shared libraries use a real parser to get the correct
+// soname.
+#if defined(CMake_USE_ELF_PARSER)
+ cmELF elf(fullPath.c_str());
+ if (elf) {
+ return elf.GetSOName(soname);
+ }
+#endif
+
+ // If the file is not a symlink we have no guess for its soname.
+ if (!cmSystemTools::FileIsSymlink(fullPath)) {
+ return false;
+ }
+ if (!cmSystemTools::ReadSymlink(fullPath, soname)) {
+ return false;
+ }
+
+ // If the symlink has a path component we have no guess for the soname.
+ if (!cmSystemTools::GetFilenamePath(soname).empty()) {
+ return false;
+ }
+
+ // If the symlink points at an extended version of the same name
+ // assume it is the soname.
+ std::string name = cmSystemTools::GetFilenameName(fullPath);
+ return soname.length() > name.length() &&
+ soname.compare(0, name.length(), name) == 0;
+}
+
+bool cmSystemTools::GuessLibraryInstallName(std::string const& fullPath,
+ std::string& soname)
+{
+#if defined(CMake_USE_MACH_PARSER)
+ cmMachO macho(fullPath.c_str());
+ if (macho) {
+ return macho.GetInstallName(soname);
+ }
+#else
+ (void)fullPath;
+ (void)soname;
+#endif
+
+ return false;
+}
+
+#if defined(CMake_USE_ELF_PARSER) || defined(CMake_USE_XCOFF_PARSER)
+std::string::size_type cmSystemToolsFindRPath(cm::string_view const& have,
+ cm::string_view const& want)
+{
+ std::string::size_type pos = 0;
+ while (pos < have.size()) {
+ // Look for an occurrence of the string.
+ std::string::size_type const beg = have.find(want, pos);
+ if (beg == std::string::npos) {
+ return std::string::npos;
+ }
+
+ // Make sure it is separated from preceding entries.
+ if (beg > 0 && have[beg - 1] != ':') {
+ pos = beg + 1;
+ continue;
+ }
+
+ // Make sure it is separated from following entries.
+ std::string::size_type const end = beg + want.size();
+ if (end < have.size() && have[end] != ':') {
+ pos = beg + 1;
+ continue;
+ }
+
+ // Return the position of the path portion.
+ return beg;
+ }
+
+ // The desired rpath was not found.
+ return std::string::npos;
+}
+#endif
+
+#if defined(CMake_USE_ELF_PARSER)
+struct cmSystemToolsRPathInfo
+{
+ unsigned long Position;
+ unsigned long Size;
+ std::string Name;
+ std::string Value;
+};
+#endif
+
+// FIXME: Dispatch if multiple formats are supported.
+#if defined(CMake_USE_ELF_PARSER)
+bool cmSystemTools::ChangeRPath(std::string const& file,
+ std::string const& oldRPath,
+ std::string const& newRPath,
+ bool removeEnvironmentRPath, std::string* emsg,
+ bool* changed)
+{
+ if (changed) {
+ *changed = false;
+ }
+ int rp_count = 0;
+ bool remove_rpath = true;
+ cmSystemToolsRPathInfo rp[2];
+ {
+ // Parse the ELF binary.
+ cmELF elf(file.c_str());
+
+ // Get the RPATH and RUNPATH entries from it.
+ int se_count = 0;
+ cmELF::StringEntry const* se[2] = { nullptr, nullptr };
+ const char* se_name[2] = { nullptr, nullptr };
+ if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) {
+ se[se_count] = se_rpath;
+ se_name[se_count] = "RPATH";
+ ++se_count;
+ }
+ if (cmELF::StringEntry const* se_runpath = elf.GetRunPath()) {
+ se[se_count] = se_runpath;
+ se_name[se_count] = "RUNPATH";
+ ++se_count;
+ }
+ if (se_count == 0) {
+ if (newRPath.empty()) {
+ // The new rpath is empty and there is no rpath anyway so it is
+ // okay.
+ return true;
+ }
+ if (emsg) {
+ *emsg =
+ cmStrCat("No valid ELF RPATH or RUNPATH entry exists in the file; ",
+ elf.GetErrorMessage());
+ }
+ return false;
+ }
+
+ for (int i = 0; i < se_count; ++i) {
+ // If both RPATH and RUNPATH refer to the same string literal it
+ // needs to be changed only once.
+ if (rp_count && rp[0].Position == se[i]->Position) {
+ continue;
+ }
+
+ // Make sure the current rpath contains the old rpath.
+ std::string::size_type pos =
+ cmSystemToolsFindRPath(se[i]->Value, oldRPath);
+ if (pos == std::string::npos) {
+ // If it contains the new rpath instead then it is okay.
+ if (cmSystemToolsFindRPath(se[i]->Value, newRPath) !=
+ std::string::npos) {
+ remove_rpath = false;
+ continue;
+ }
+ if (emsg) {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "The current " << se_name[i] << " is:\n"
+ << " " << se[i]->Value << "\n"
+ << "which does not contain:\n"
+ << " " << oldRPath << "\n"
+ << "as was expected.";
+ /* clang-format on */
+ *emsg = e.str();
+ }
+ return false;
+ }
+
+ // Store information about the entry in the file.
+ rp[rp_count].Position = se[i]->Position;
+ rp[rp_count].Size = se[i]->Size;
+ rp[rp_count].Name = se_name[i];
+
+ std::string::size_type prefix_len = pos;
+
+ // If oldRPath was at the end of the file's RPath, and newRPath is empty,
+ // we should remove the unnecessary ':' at the end.
+ if (newRPath.empty() && pos > 0 && se[i]->Value[pos - 1] == ':' &&
+ pos + oldRPath.length() == se[i]->Value.length()) {
+ prefix_len--;
+ }
+
+ // Construct the new value which preserves the part of the path
+ // not being changed.
+ if (!removeEnvironmentRPath) {
+ rp[rp_count].Value = se[i]->Value.substr(0, prefix_len);
+ }
+ rp[rp_count].Value += newRPath;
+ rp[rp_count].Value += se[i]->Value.substr(pos + oldRPath.length());
+
+ if (!rp[rp_count].Value.empty()) {
+ remove_rpath = false;
+ }
+
+ // Make sure there is enough room to store the new rpath and at
+ // least one null terminator.
+ if (rp[rp_count].Size < rp[rp_count].Value.length() + 1) {
+ if (emsg) {
+ *emsg = cmStrCat("The replacement path is too long for the ",
+ se_name[i], " entry.");
+ }
+ return false;
+ }
+
+ // This entry is ready for update.
+ ++rp_count;
+ }
+ }
+
+ // If no runtime path needs to be changed, we are done.
+ if (rp_count == 0) {
+ return true;
+ }
+
+ // If the resulting rpath is empty, just remove the entire entry instead.
+ if (remove_rpath) {
+ return cmSystemTools::RemoveRPath(file, emsg, changed);
+ }
+
+ {
+ // Open the file for update.
+ cmsys::ofstream f(file.c_str(),
+ std::ios::in | std::ios::out | std::ios::binary);
+ if (!f) {
+ if (emsg) {
+ *emsg = "Error opening file for update.";
+ }
+ return false;
+ }
+
+ // Store the new RPATH and RUNPATH strings.
+ for (int i = 0; i < rp_count; ++i) {
+ // Seek to the RPATH position.
+ if (!f.seekp(rp[i].Position)) {
+ if (emsg) {
+ *emsg = cmStrCat("Error seeking to ", rp[i].Name, " position.");
+ }
+ return false;
+ }
+
+ // Write the new rpath. Follow it with enough null terminators to
+ // fill the string table entry.
+ f << rp[i].Value;
+ for (unsigned long j = rp[i].Value.length(); j < rp[i].Size; ++j) {
+ f << '\0';
+ }
+
+ // Make sure it wrote correctly.
+ if (!f) {
+ if (emsg) {
+ *emsg = cmStrCat("Error writing the new ", rp[i].Name,
+ " string to the file.");
+ }
+ return false;
+ }
+ }
+ }
+
+ // Everything was updated successfully.
+ if (changed) {
+ *changed = true;
+ }
+ return true;
+}
+#elif defined(CMake_USE_XCOFF_PARSER)
+bool cmSystemTools::ChangeRPath(std::string const& file,
+ std::string const& oldRPath,
+ std::string const& newRPath,
+ bool removeEnvironmentRPath, std::string* emsg,
+ bool* changed)
+{
+ if (changed) {
+ *changed = false;
+ }
+
+ bool chg = false;
+ cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite);
+ if (cm::optional<cm::string_view> maybeLibPath = xcoff.GetLibPath()) {
+ cm::string_view libPath = *maybeLibPath;
+ // Make sure the current rpath contains the old rpath.
+ std::string::size_type pos = cmSystemToolsFindRPath(libPath, oldRPath);
+ if (pos == std::string::npos) {
+ // If it contains the new rpath instead then it is okay.
+ if (cmSystemToolsFindRPath(libPath, newRPath) != std::string::npos) {
+ return true;
+ }
+ if (emsg) {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "The current RPATH is:\n"
+ << " " << libPath << "\n"
+ << "which does not contain:\n"
+ << " " << oldRPath << "\n"
+ << "as was expected.";
+ /* clang-format on */
+ *emsg = e.str();
+ }
+ return false;
+ }
+
+ // The prefix is either empty or ends in a ':'.
+ cm::string_view prefix = libPath.substr(0, pos);
+ if (newRPath.empty() && !prefix.empty()) {
+ prefix.remove_suffix(1);
+ }
+
+ // The suffix is either empty or starts in a ':'.
+ cm::string_view suffix = libPath.substr(pos + oldRPath.length());
+
+ // Construct the new value which preserves the part of the path
+ // not being changed.
+ std::string newLibPath;
+ if (!removeEnvironmentRPath) {
+ newLibPath = std::string(prefix);
+ }
+ newLibPath += newRPath;
+ newLibPath += suffix;
+
+ chg = xcoff.SetLibPath(newLibPath);
+ }
+ if (!xcoff) {
+ if (emsg) {
+ *emsg = xcoff.GetErrorMessage();
+ }
+ return false;
+ }
+
+ // Everything was updated successfully.
+ if (changed) {
+ *changed = chg;
+ }
+ return true;
+}
+#else
+bool cmSystemTools::ChangeRPath(std::string const& /*file*/,
+ std::string const& /*oldRPath*/,
+ std::string const& /*newRPath*/,
+ bool /*removeEnvironmentRPath*/,
+ std::string* /*emsg*/, bool* /*changed*/)
+{
+ return false;
+}
+#endif
+
+bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op,
+ const char* lhss, const char* rhss)
+{
+ const char* endl = lhss;
+ const char* endr = rhss;
+ unsigned long lhs;
+ unsigned long rhs;
+
+ while (((*endl >= '0') && (*endl <= '9')) ||
+ ((*endr >= '0') && (*endr <= '9'))) {
+ // Do component-wise comparison.
+ lhs = strtoul(endl, const_cast<char**>(&endl), 10);
+ rhs = strtoul(endr, const_cast<char**>(&endr), 10);
+
+ if (lhs < rhs) {
+ // lhs < rhs, so true if operation is LESS
+ return (op & cmSystemTools::OP_LESS) != 0;
+ }
+ if (lhs > rhs) {
+ // lhs > rhs, so true if operation is GREATER
+ return (op & cmSystemTools::OP_GREATER) != 0;
+ }
+
+ if (*endr == '.') {
+ endr++;
+ }
+
+ if (*endl == '.') {
+ endl++;
+ }
+ }
+ // lhs == rhs, so true if operation is EQUAL
+ return (op & cmSystemTools::OP_EQUAL) != 0;
+}
+
+bool cmSystemTools::VersionCompareEqual(std::string const& lhs,
+ std::string const& rhs)
+{
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, lhs.c_str(),
+ rhs.c_str());
+}
+
+bool cmSystemTools::VersionCompareGreater(std::string const& lhs,
+ std::string const& rhs)
+{
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, lhs.c_str(),
+ rhs.c_str());
+}
+
+bool cmSystemTools::VersionCompareGreaterEq(std::string const& lhs,
+ std::string const& rhs)
+{
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
+ lhs.c_str(), rhs.c_str());
+}
+
+static size_t cm_strverscmp_find_first_difference_or_end(const char* lhs,
+ const char* rhs)
+{
+ size_t i = 0;
+ /* Step forward until we find a difference or both strings end together.
+ The difference may lie on the null-terminator of one string. */
+ while (lhs[i] == rhs[i] && lhs[i] != 0) {
+ ++i;
+ }
+ return i;
+}
+
+static size_t cm_strverscmp_find_digits_begin(const char* s, size_t i)
+{
+ /* Step back until we are not preceded by a digit. */
+ while (i > 0 && isdigit(s[i - 1])) {
+ --i;
+ }
+ return i;
+}
+
+static size_t cm_strverscmp_find_digits_end(const char* s, size_t i)
+{
+ /* Step forward over digits. */
+ while (isdigit(s[i])) {
+ ++i;
+ }
+ return i;
+}
+
+static size_t cm_strverscmp_count_leading_zeros(const char* s, size_t b)
+{
+ size_t i = b;
+ /* Step forward over zeros that are followed by another digit. */
+ while (s[i] == '0' && isdigit(s[i + 1])) {
+ ++i;
+ }
+ return i - b;
+}
+
+static int cm_strverscmp(const char* lhs, const char* rhs)
+{
+ size_t const i = cm_strverscmp_find_first_difference_or_end(lhs, rhs);
+ if (lhs[i] != rhs[i]) {
+ /* The strings differ starting at 'i'. Check for a digit sequence. */
+ size_t const b = cm_strverscmp_find_digits_begin(lhs, i);
+ if (b != i || (isdigit(lhs[i]) && isdigit(rhs[i]))) {
+ /* A digit sequence starts at 'b', preceding or at 'i'. */
+
+ /* Look for leading zeros, implying a leading decimal point. */
+ size_t const lhs_zeros = cm_strverscmp_count_leading_zeros(lhs, b);
+ size_t const rhs_zeros = cm_strverscmp_count_leading_zeros(rhs, b);
+ if (lhs_zeros != rhs_zeros) {
+ /* The side with more leading zeros orders first. */
+ return rhs_zeros > lhs_zeros ? 1 : -1;
+ }
+ if (lhs_zeros == 0) {
+ /* No leading zeros; compare digit sequence lengths. */
+ size_t const lhs_end = cm_strverscmp_find_digits_end(lhs, i);
+ size_t const rhs_end = cm_strverscmp_find_digits_end(rhs, i);
+ if (lhs_end != rhs_end) {
+ /* The side with fewer digits orders first. */
+ return lhs_end > rhs_end ? 1 : -1;
+ }
+ }
+ }
+ }
+
+ /* Ordering was not decided by digit sequence lengths; compare bytes. */
+ return lhs[i] - rhs[i];
+}
+
+int cmSystemTools::strverscmp(std::string const& lhs, std::string const& rhs)
+{
+ return cm_strverscmp(lhs.c_str(), rhs.c_str());
+}
+
+// FIXME: Dispatch if multiple formats are supported.
+#if defined(CMake_USE_ELF_PARSER)
+bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
+ bool* removed)
+{
+ if (removed) {
+ *removed = false;
+ }
+ int zeroCount = 0;
+ unsigned long zeroPosition[2] = { 0, 0 };
+ unsigned long zeroSize[2] = { 0, 0 };
+ unsigned long bytesBegin = 0;
+ std::vector<char> bytes;
+ {
+ // Parse the ELF binary.
+ cmELF elf(file.c_str());
+
+ // Get the RPATH and RUNPATH entries from it and sort them by index
+ // in the dynamic section header.
+ int se_count = 0;
+ cmELF::StringEntry const* se[2] = { nullptr, nullptr };
+ if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) {
+ se[se_count++] = se_rpath;
+ }
+ if (cmELF::StringEntry const* se_runpath = elf.GetRunPath()) {
+ se[se_count++] = se_runpath;
+ }
+ if (se_count == 0) {
+ // There is no RPATH or RUNPATH anyway.
+ return true;
+ }
+ if (se_count == 2 && se[1]->IndexInSection < se[0]->IndexInSection) {
+ std::swap(se[0], se[1]);
+ }
+
+ // Obtain a copy of the dynamic entries
+ cmELF::DynamicEntryList dentries = elf.GetDynamicEntries();
+ if (dentries.empty()) {
+ // This should happen only for invalid ELF files where a DT_NULL
+ // appears before the end of the table.
+ if (emsg) {
+ *emsg = "DYNAMIC section contains a DT_NULL before the end.";
+ }
+ return false;
+ }
+
+ // Save information about the string entries to be zeroed.
+ zeroCount = se_count;
+ for (int i = 0; i < se_count; ++i) {
+ zeroPosition[i] = se[i]->Position;
+ zeroSize[i] = se[i]->Size;
+ }
+
+ // Get size of one DYNAMIC entry
+ unsigned long const sizeof_dentry =
+ elf.GetDynamicEntryPosition(1) - elf.GetDynamicEntryPosition(0);
+
+ // Adjust the entry list as necessary to remove the run path
+ unsigned long entriesErased = 0;
+ for (auto it = dentries.begin(); it != dentries.end();) {
+ if (it->first == cmELF::TagRPath || it->first == cmELF::TagRunPath) {
+ it = dentries.erase(it);
+ entriesErased++;
+ continue;
+ }
+ if (cmELF::TagMipsRldMapRel != 0 &&
+ it->first == cmELF::TagMipsRldMapRel) {
+ // Background: debuggers need to know the "linker map" which contains
+ // the addresses each dynamic object is loaded at. Most arches use
+ // the DT_DEBUG tag which the dynamic linker writes to (directly) and
+ // contain the location of the linker map, however on MIPS the
+ // .dynamic section is always read-only so this is not possible. MIPS
+ // objects instead contain a DT_MIPS_RLD_MAP tag which contains the
+ // address where the dynamic linker will write to (an indirect
+ // version of DT_DEBUG). Since this doesn't work when using PIE, a
+ // relative equivalent was created - DT_MIPS_RLD_MAP_REL. Since this
+ // version contains a relative offset, moving it changes the
+ // calculated address. This may cause the dynamic linker to write
+ // into memory it should not be changing.
+ //
+ // To fix this, we adjust the value of DT_MIPS_RLD_MAP_REL here. If
+ // we move it up by n bytes, we add n bytes to the value of this tag.
+ it->second += entriesErased * sizeof_dentry;
+ }
+
+ it++;
+ }
+
+ // Encode new entries list
+ bytes = elf.EncodeDynamicEntries(dentries);
+ bytesBegin = elf.GetDynamicEntryPosition(0);
+ }
+
+ // Open the file for update.
+ cmsys::ofstream f(file.c_str(),
+ std::ios::in | std::ios::out | std::ios::binary);
+ if (!f) {
+ if (emsg) {
+ *emsg = "Error opening file for update.";
+ }
+ return false;
+ }
+
+ // Write the new DYNAMIC table header.
+ if (!f.seekp(bytesBegin)) {
+ if (emsg) {
+ *emsg = "Error seeking to DYNAMIC table header for RPATH.";
+ }
+ return false;
+ }
+ if (!f.write(&bytes[0], bytes.size())) {
+ if (emsg) {
+ *emsg = "Error replacing DYNAMIC table header.";
+ }
+ return false;
+ }
+
+ // Fill the RPATH and RUNPATH strings with zero bytes.
+ for (int i = 0; i < zeroCount; ++i) {
+ if (!f.seekp(zeroPosition[i])) {
+ if (emsg) {
+ *emsg = "Error seeking to RPATH position.";
+ }
+ return false;
+ }
+ for (unsigned long j = 0; j < zeroSize[i]; ++j) {
+ f << '\0';
+ }
+ if (!f) {
+ if (emsg) {
+ *emsg = "Error writing the empty rpath string to the file.";
+ }
+ return false;
+ }
+ }
+
+ // Everything was updated successfully.
+ if (removed) {
+ *removed = true;
+ }
+ return true;
+}
+#elif defined(CMake_USE_XCOFF_PARSER)
+bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
+ bool* removed)
+{
+ if (removed) {
+ *removed = false;
+ }
+
+ cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite);
+ bool rm = xcoff.RemoveLibPath();
+ if (!xcoff) {
+ if (emsg) {
+ *emsg = xcoff.GetErrorMessage();
+ }
+ return false;
+ }
+
+ if (removed) {
+ *removed = rm;
+ }
+ return true;
+}
+#else
+bool cmSystemTools::RemoveRPath(std::string const& /*file*/,
+ std::string* /*emsg*/, bool* /*removed*/)
+{
+ return false;
+}
+#endif
+
+// FIXME: Dispatch if multiple formats are supported.
+bool cmSystemTools::CheckRPath(std::string const& file,
+ std::string const& newRPath)
+{
+#if defined(CMake_USE_ELF_PARSER)
+ // Parse the ELF binary.
+ cmELF elf(file.c_str());
+
+ // Get the RPATH or RUNPATH entry from it.
+ cmELF::StringEntry const* se = elf.GetRPath();
+ if (!se) {
+ se = elf.GetRunPath();
+ }
+
+ // Make sure the current rpath contains the new rpath.
+ if (newRPath.empty()) {
+ if (!se) {
+ return true;
+ }
+ } else {
+ if (se &&
+ cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+#elif defined(CMake_USE_XCOFF_PARSER)
+ // Parse the XCOFF binary.
+ cmXCOFF xcoff(file.c_str());
+ if (cm::optional<cm::string_view> libPath = xcoff.GetLibPath()) {
+ if (cmSystemToolsFindRPath(*libPath, newRPath) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+#else
+ (void)file;
+ (void)newRPath;
+ return false;
+#endif
+}
+
+bool cmSystemTools::RepeatedRemoveDirectory(const std::string& dir)
+{
+#ifdef _WIN32
+ // Windows sometimes locks files temporarily so try a few times.
+ WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry();
+
+ for (unsigned int i = 0; i < retry.Count; ++i) {
+ if (cmSystemTools::RemoveADirectory(dir)) {
+ return true;
+ }
+ cmSystemTools::Delay(retry.Delay);
+ }
+ return false;
+#else
+ return cmSystemTools::RemoveADirectory(dir);
+#endif
+}
+
+std::string cmSystemTools::EncodeURL(std::string const& in, bool escapeSlashes)
+{
+ std::string out;
+ for (char c : in) {
+ char hexCh[4] = { 0, 0, 0, 0 };
+ hexCh[0] = c;
+ switch (c) {
+ case '+':
+ case '?':
+ case '\\':
+ case '&':
+ case ' ':
+ case '=':
+ case '%':
+ sprintf(hexCh, "%%%02X", static_cast<int>(c));
+ break;
+ case '/':
+ if (escapeSlashes) {
+ strcpy(hexCh, "%2F");
+ }
+ break;
+ default:
+ break;
+ }
+ out.append(hexCh);
+ }
+ return out;
+}
+
+bool cmSystemTools::CreateSymlink(const std::string& origName,
+ const std::string& newName,
+ std::string* errorMessage)
+{
+ uv_fs_t req;
+ int flags = 0;
+#if defined(_WIN32)
+ if (cmsys::SystemTools::FileIsDirectory(origName)) {
+ flags |= UV_FS_SYMLINK_DIR;
+ }
+#endif
+ int err = uv_fs_symlink(nullptr, &req, origName.c_str(), newName.c_str(),
+ flags, nullptr);
+ if (err) {
+ std::string e =
+ "failed to create symbolic link '" + newName + "': " + uv_strerror(err);
+ if (errorMessage) {
+ *errorMessage = std::move(e);
+ } else {
+ cmSystemTools::Error(e);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool cmSystemTools::CreateLink(const std::string& origName,
+ const std::string& newName,
+ std::string* errorMessage)
+{
+ uv_fs_t req;
+ int err =
+ uv_fs_link(nullptr, &req, origName.c_str(), newName.c_str(), nullptr);
+ if (err) {
+ std::string e =
+ "failed to create link '" + newName + "': " + uv_strerror(err);
+ if (errorMessage) {
+ *errorMessage = std::move(e);
+ } else {
+ cmSystemTools::Error(e);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+cm::string_view cmSystemTools::GetSystemName()
+{
+#if defined(_WIN32)
+ return "Windows";
+#elif defined(__ANDROID__)
+ return "Android";
+#else
+ static struct utsname uts_name;
+ static bool initialized = false;
+ static cm::string_view systemName;
+ if (initialized) {
+ return systemName;
+ }
+ if (uname(&uts_name) >= 0) {
+ initialized = true;
+ systemName = uts_name.sysname;
+
+ if (cmIsOff(systemName)) {
+ systemName = "UnknownOS";
+ }
+
+ // fix for BSD/OS, remove the /
+ static const cmsys::RegularExpression bsdOsRegex("BSD.OS");
+ cmsys::RegularExpressionMatch match;
+ if (bsdOsRegex.find(uts_name.sysname, match)) {
+ systemName = "BSDOS";
+ }
+
+ // fix for GNU/kFreeBSD, remove the GNU/
+ if (systemName.find("kFreeBSD") != cm::string_view::npos) {
+ systemName = "kFreeBSD";
+ }
+
+ // fix for CYGWIN which has windows version in it
+ if (systemName.find("CYGWIN") != cm::string_view::npos) {
+ systemName = "CYGWIN";
+ }
+ return systemName;
+ }
+ return "";
+#endif
+}
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
new file mode 100644
index 0000000..5620899
--- /dev/null
+++ b/Source/cmSystemTools.h
@@ -0,0 +1,510 @@
+/* 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 <cstddef>
+#include <functional>
+#include <string>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmsys/Process.h"
+#include "cmsys/SystemTools.hxx" // IWYU pragma: export
+
+#include "cmCryptoHash.h"
+#include "cmDuration.h"
+#include "cmProcessOutput.h"
+
+/** \class cmSystemTools
+ * \brief A collection of useful functions for CMake.
+ *
+ * cmSystemTools is a class that provides helper functions
+ * for the CMake build system.
+ */
+class cmSystemTools : public cmsys::SystemTools
+{
+public:
+ using Superclass = cmsys::SystemTools;
+ using Encoding = cmProcessOutput::Encoding;
+
+ /**
+ * Look for and replace registry values in a string
+ */
+ static void ExpandRegistryValues(std::string& source,
+ KeyWOW64 view = KeyWOW64_Default);
+
+ /** Map help document name to file name. */
+ static std::string HelpFileName(cm::string_view);
+
+ using MessageCallback = std::function<void(const std::string&, const char*)>;
+ /**
+ * Set the function used by GUIs to display error messages
+ * Function gets passed: message as a const char*,
+ * title as a const char*.
+ */
+ static void SetMessageCallback(MessageCallback f);
+
+ /**
+ * Display an error message.
+ */
+ static void Error(const std::string& m);
+
+ /**
+ * Display a message.
+ */
+ static void Message(const std::string& m, const char* title = nullptr);
+
+ using OutputCallback = std::function<void(std::string const&)>;
+
+ //! Send a string to stdout
+ static void Stdout(const std::string& s);
+ static void SetStdoutCallback(OutputCallback f);
+
+ //! Send a string to stderr
+ static void Stderr(const std::string& s);
+ static void SetStderrCallback(OutputCallback f);
+
+ using InterruptCallback = std::function<bool()>;
+ static void SetInterruptCallback(InterruptCallback f);
+ static bool GetInterruptFlag();
+
+ //! Return true if there was an error at any point.
+ static bool GetErrorOccuredFlag()
+ {
+ return cmSystemTools::s_ErrorOccured ||
+ cmSystemTools::s_FatalErrorOccured || GetInterruptFlag();
+ }
+ //! If this is set to true, cmake stops processing commands.
+ static void SetFatalErrorOccured()
+ {
+ cmSystemTools::s_FatalErrorOccured = true;
+ }
+ static void SetErrorOccured() { cmSystemTools::s_ErrorOccured = true; }
+ //! Return true if there was an error at any point.
+ static bool GetFatalErrorOccured()
+ {
+ return cmSystemTools::s_FatalErrorOccured || GetInterruptFlag();
+ }
+
+ //! Set the error occurred flag and fatal error back to false
+ static void ResetErrorOccuredFlag()
+ {
+ cmSystemTools::s_FatalErrorOccured = false;
+ cmSystemTools::s_ErrorOccured = false;
+ }
+
+ //! Return true if the path is a framework
+ static bool IsPathToFramework(const std::string& value);
+
+ static bool DoesFileExistWithExtensions(
+ const std::string& name, const std::vector<std::string>& sourceExts);
+
+ /**
+ * Check if the given file exists in one of the parent directory of the
+ * given file or directory and if it does, return the name of the file.
+ * Toplevel specifies the top-most directory to where it will look.
+ */
+ static std::string FileExistsInParentDirectories(
+ const std::string& fname, const std::string& directory,
+ const std::string& toplevel);
+
+ static void Glob(const std::string& directory, const std::string& regexp,
+ std::vector<std::string>& files);
+ static void GlobDirs(const std::string& fullPath,
+ std::vector<std::string>& files);
+
+ /**
+ * Try to find a list of files that match the "simple" globbing
+ * expression. At this point in time the globbing expressions have
+ * to be in form: /directory/partial_file_name*. The * character has
+ * to be at the end of the string and it does not support ?
+ * []... The optional argument type specifies what kind of files you
+ * want to find. 0 means all files, -1 means directories, 1 means
+ * files only. This method returns true if search was successful.
+ */
+ static bool SimpleGlob(const std::string& glob,
+ std::vector<std::string>& files, int type = 0);
+
+ enum class CopyWhen
+ {
+ Always,
+ OnlyIfDifferent,
+ };
+ enum class CopyResult
+ {
+ Success,
+ Failure,
+ };
+
+ /** Copy a file. */
+ static bool CopySingleFile(const std::string& oldname,
+ const std::string& newname);
+ static CopyResult CopySingleFile(std::string const& oldname,
+ std::string const& newname, CopyWhen when,
+ std::string* err = nullptr);
+
+ enum class Replace
+ {
+ Yes,
+ No,
+ };
+ enum class RenameResult
+ {
+ Success,
+ NoReplace,
+ Failure,
+ };
+
+ /** Rename a file or directory within a single disk volume (atomic
+ if possible). */
+ static bool RenameFile(const std::string& oldname,
+ const std::string& newname);
+ static RenameResult RenameFile(std::string const& oldname,
+ std::string const& newname, Replace replace,
+ std::string* err = nullptr);
+
+ //! Rename a file if contents are different, delete the source otherwise
+ static void MoveFileIfDifferent(const std::string& source,
+ const std::string& destination);
+
+ //! Compute the hash of a file
+ static std::string ComputeFileHash(const std::string& source,
+ cmCryptoHash::Algo algo);
+
+ /** Compute the md5sum of a string. */
+ static std::string ComputeStringMD5(const std::string& input);
+
+ //! Get the SHA thumbprint for a certificate file
+ static std::string ComputeCertificateThumbprint(const std::string& source);
+
+ /**
+ * Run a single executable command
+ *
+ * Output is controlled with outputflag. If outputflag is OUTPUT_NONE, no
+ * user-viewable output from the program being run will be generated.
+ * OUTPUT_MERGE is the legacy behaviour where stdout and stderr are merged
+ * into stdout. OUTPUT_FORWARD copies the output to stdout/stderr as
+ * it was received. OUTPUT_PASSTHROUGH passes through the original handles.
+ *
+ * If timeout is specified, the command will be terminated after
+ * timeout expires. Timeout is specified in seconds.
+ *
+ * Argument retVal should be a pointer to the location where the
+ * exit code will be stored. If the retVal is not specified and
+ * the program exits with a code other than 0, then the this
+ * function will return false.
+ *
+ * If the command has spaces in the path the caller MUST call
+ * cmSystemTools::ConvertToRunCommandPath on the command before passing
+ * it into this function or it will not work. The command must be correctly
+ * escaped for this to with spaces.
+ */
+ enum OutputOption
+ {
+ OUTPUT_NONE = 0,
+ OUTPUT_MERGE,
+ OUTPUT_FORWARD,
+ OUTPUT_PASSTHROUGH
+ };
+ static bool RunSingleCommand(const std::string& command,
+ std::string* captureStdOut = nullptr,
+ std::string* captureStdErr = nullptr,
+ int* retVal = nullptr,
+ const char* dir = nullptr,
+ OutputOption outputflag = OUTPUT_MERGE,
+ cmDuration timeout = cmDuration::zero());
+ /**
+ * In this version of RunSingleCommand, command[0] should be
+ * the command to run, and each argument to the command should
+ * be in command[1]...command[command.size()]
+ */
+ static bool RunSingleCommand(std::vector<std::string> const& command,
+ std::string* captureStdOut = nullptr,
+ std::string* captureStdErr = nullptr,
+ int* retVal = nullptr,
+ const char* dir = nullptr,
+ OutputOption outputflag = OUTPUT_MERGE,
+ cmDuration timeout = cmDuration::zero(),
+ Encoding encoding = cmProcessOutput::Auto);
+
+ static std::string PrintSingleCommand(std::vector<std::string> const&);
+
+ /**
+ * Parse arguments out of a single string command
+ */
+ static std::vector<std::string> ParseArguments(const std::string& command);
+
+ /** Parse arguments out of a windows command line string. */
+ static void ParseWindowsCommandLine(const char* command,
+ std::vector<std::string>& args);
+
+ /** Parse arguments out of a unix command line string. */
+ static void ParseUnixCommandLine(const char* command,
+ std::vector<std::string>& args);
+
+ /** Split a command-line string into the parsed command and the unparsed
+ arguments. Returns false on unfinished quoting or escaping. */
+ static bool SplitProgramFromArgs(std::string const& command,
+ std::string& program, std::string& args);
+
+ /**
+ * Handle response file in an argument list and return a new argument list
+ * **/
+ static std::vector<std::string> HandleResponseFile(
+ std::vector<std::string>::const_iterator argBeg,
+ std::vector<std::string>::const_iterator argEnd);
+
+ static size_t CalculateCommandLineLengthLimit();
+
+ static void DisableRunCommandOutput() { s_DisableRunCommandOutput = true; }
+ static void EnableRunCommandOutput() { s_DisableRunCommandOutput = false; }
+ static bool GetRunCommandOutput() { return s_DisableRunCommandOutput; }
+
+ enum CompareOp
+ {
+ OP_EQUAL = 1,
+ OP_LESS = 2,
+ OP_GREATER = 4,
+ OP_LESS_EQUAL = OP_LESS | OP_EQUAL,
+ OP_GREATER_EQUAL = OP_GREATER | OP_EQUAL
+ };
+
+ /**
+ * Compare versions
+ */
+ static bool VersionCompare(CompareOp op, const char* lhs, const char* rhs);
+ static bool VersionCompareEqual(std::string const& lhs,
+ std::string const& rhs);
+ static bool VersionCompareGreater(std::string const& lhs,
+ std::string const& rhs);
+ static bool VersionCompareGreaterEq(std::string const& lhs,
+ std::string const& rhs);
+
+ /**
+ * Compare two ASCII strings using natural versioning order.
+ * Non-numerical characters are compared directly.
+ * Numerical characters are first globbed such that, e.g.
+ * `test000 < test01 < test0 < test1 < test10`.
+ * Return a value less than, equal to, or greater than zero if lhs
+ * precedes, equals, or succeeds rhs in the defined ordering.
+ */
+ static int strverscmp(std::string const& lhs, std::string const& rhs);
+
+ /** Windows if this is true, the CreateProcess in RunCommand will
+ * not show new console windows when running programs.
+ */
+ static void SetRunCommandHideConsole(bool v) { s_RunCommandHideConsole = v; }
+ static bool GetRunCommandHideConsole() { return s_RunCommandHideConsole; }
+ /** Call cmSystemTools::Error with the message m, plus the
+ * result of strerror(errno)
+ */
+ static void ReportLastSystemError(const char* m);
+
+ /** a general output handler for cmsysProcess */
+ static int WaitForLine(cmsysProcess* process, std::string& line,
+ cmDuration timeout, std::vector<char>& out,
+ std::vector<char>& err);
+
+ static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; }
+ static bool GetForceUnixPaths() { return s_ForceUnixPaths; }
+
+ // ConvertToOutputPath use s_ForceUnixPaths
+ static std::string ConvertToOutputPath(std::string const& path);
+ static void ConvertToOutputSlashes(std::string& path);
+
+ // ConvertToRunCommandPath does not use s_ForceUnixPaths and should
+ // be used when RunCommand is called from cmake, because the
+ // running cmake needs paths to be in its format
+ static std::string ConvertToRunCommandPath(const std::string& path);
+
+ /**
+ * For windows computes the long path for the given path,
+ * For Unix, it is a noop
+ */
+ static void ConvertToLongPath(std::string& path);
+
+ /** compute the relative path from local to remote. local must
+ be a directory. remote can be a file or a directory.
+ Both remote and local must be full paths. Basically, if
+ you are in directory local and you want to access the file in remote
+ what is the relative path to do that. For example:
+ /a/b/c/d to /a/b/c1/d1 -> ../../c1/d1
+ from /usr/src to /usr/src/test/blah/foo.cpp -> test/blah/foo.cpp
+ */
+ static std::string RelativePath(std::string const& local,
+ std::string const& remote);
+
+ /**
+ * Convert the given remote path to a relative path with respect to
+ * the given local path. Both paths must use forward slashes and not
+ * already be escaped or quoted.
+ */
+ static std::string ForceToRelativePath(std::string const& local_path,
+ std::string const& remote_path);
+
+#ifndef CMAKE_BOOTSTRAP
+ /** Remove an environment variable */
+ static bool UnsetEnv(const char* value);
+
+ /** Get the list of all environment variables */
+ static std::vector<std::string> GetEnvironmentVariables();
+
+ /** Append multiple variables to the current environment. */
+ static void AppendEnv(std::vector<std::string> const& env);
+
+ /** Helper class to save and restore the environment.
+ Instantiate this class as an automatic variable on
+ the stack. Its constructor saves a copy of the current
+ environment and then its destructor restores the
+ original environment. */
+ class SaveRestoreEnvironment
+ {
+ public:
+ SaveRestoreEnvironment();
+ ~SaveRestoreEnvironment();
+
+ SaveRestoreEnvironment(SaveRestoreEnvironment const&) = delete;
+ SaveRestoreEnvironment& operator=(SaveRestoreEnvironment const&) = delete;
+
+ private:
+ std::vector<std::string> Env;
+ };
+#endif
+
+ /** Setup the environment to enable VS 8 IDE output. */
+ static void EnableVSConsoleOutput();
+
+ enum cmTarAction
+ {
+ TarActionCreate,
+ TarActionList,
+ TarActionExtract,
+ TarActionNone
+ };
+
+ /** Create tar */
+ enum cmTarCompression
+ {
+ TarCompressGZip,
+ TarCompressBZip2,
+ TarCompressXZ,
+ TarCompressZstd,
+ TarCompressNone
+ };
+
+ static bool ListTar(const std::string& outFileName,
+ const std::vector<std::string>& files, bool verbose);
+ static bool CreateTar(const std::string& outFileName,
+ const std::vector<std::string>& files,
+ cmTarCompression compressType, bool verbose,
+ std::string const& mtime = std::string(),
+ std::string const& format = std::string(),
+ int compressionLevel = 0);
+ static bool ExtractTar(const std::string& inFileName,
+ const std::vector<std::string>& files, bool verbose);
+ // This should be called first thing in main
+ // it will keep child processes from inheriting the
+ // stdin and stdout of this process. This is important
+ // if you want to be able to kill child processes and
+ // not get stuck waiting for all the output on the pipes.
+ static void DoNotInheritStdPipes();
+
+ static void EnsureStdPipes();
+
+ /** Random seed generation. */
+ static unsigned int RandomSeed();
+
+ /** Find the directory containing CMake executables. */
+ static void FindCMakeResources(const char* argv0);
+
+ /** Get the CMake resource paths, after FindCMakeResources. */
+ static std::string const& GetCTestCommand();
+ static std::string const& GetCPackCommand();
+ static std::string const& GetCMakeCommand();
+ static std::string const& GetCMakeGUICommand();
+ static std::string const& GetCMakeCursesCommand();
+ static std::string const& GetCMClDepsCommand();
+ static std::string const& GetCMakeRoot();
+ static std::string const& GetHTMLDoc();
+
+ /** Get the CWD mapped through the KWSys translation map. */
+ static std::string GetCurrentWorkingDirectory();
+
+ /** Echo a message in color using KWSys's Terminal cprintf. */
+ static void MakefileColorEcho(int color, const char* message, bool newLine,
+ bool enabled);
+
+ /** Try to guess the soname of a shared library. */
+ static bool GuessLibrarySOName(std::string const& fullPath,
+ std::string& soname);
+
+ /** Try to guess the install name of a shared library. */
+ static bool GuessLibraryInstallName(std::string const& fullPath,
+ std::string& soname);
+
+ /** Try to set the RPATH in an ELF binary. */
+ static bool ChangeRPath(std::string const& file, std::string const& oldRPath,
+ std::string const& newRPath,
+ bool removeEnvironmentRPath,
+ std::string* emsg = nullptr,
+ bool* changed = nullptr);
+
+ /** Try to remove the RPATH from an ELF binary. */
+ static bool RemoveRPath(std::string const& file, std::string* emsg = nullptr,
+ bool* removed = nullptr);
+
+ /** Check whether the RPATH in an ELF binary contains the path
+ given. */
+ static bool CheckRPath(std::string const& file, std::string const& newRPath);
+
+ /** Remove a directory; repeat a few times in case of locked files. */
+ static bool RepeatedRemoveDirectory(const std::string& dir);
+
+ /** Encode a string as a URL. */
+ static std::string EncodeURL(std::string const& in,
+ bool escapeSlashes = true);
+
+#ifdef _WIN32
+ struct WindowsFileRetry
+ {
+ unsigned int Count;
+ unsigned int Delay;
+ };
+ static WindowsFileRetry GetWindowsFileRetry();
+ static WindowsFileRetry GetWindowsDirectoryRetry();
+#endif
+
+ /** Get the real path for a given path, removing all symlinks.
+ This variant of GetRealPath also works on Windows but will
+ resolve subst drives too. */
+ static std::string GetRealPathResolvingWindowsSubst(
+ const std::string& path, std::string* errorMessage = nullptr);
+
+ /** Perform one-time initialization of libuv. */
+ static void InitializeLibUV();
+
+ /** Create a symbolic link if the platform supports it. Returns whether
+ creation succeeded. */
+ static bool CreateSymlink(const std::string& origName,
+ const std::string& newName,
+ std::string* errorMessage = nullptr);
+
+ /** Create a hard link if the platform supports it. Returns whether
+ creation succeeded. */
+ static bool CreateLink(const std::string& origName,
+ const std::string& newName,
+ std::string* errorMessage = nullptr);
+
+ /** Get the system name. */
+ static cm::string_view GetSystemName();
+
+private:
+ static bool s_ForceUnixPaths;
+ static bool s_RunCommandHideConsole;
+ static bool s_ErrorOccured;
+ static bool s_FatalErrorOccured;
+ static bool s_DisableRunCommandOutput;
+};
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
new file mode 100644
index 0000000..91dcd0e
--- /dev/null
+++ b/Source/cmTarget.cxx
@@ -0,0 +1,2262 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTarget.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <map>
+#include <set>
+#include <sstream>
+#include <unordered_set>
+
+#include <cm/memory>
+#include <cmext/algorithm>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmAlgorithms.h"
+#include "cmCustomCommand.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmMessenger.h"
+#include "cmProperty.h"
+#include "cmPropertyMap.h"
+#include "cmRange.h"
+#include "cmSourceFile.h"
+#include "cmSourceFileLocation.h"
+#include "cmSourceFileLocationKind.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmSystemTools.h"
+#include "cmTargetPropertyComputer.h"
+#include "cmake.h"
+
+template <>
+const std::string& cmTargetPropertyComputer::ComputeLocationForBuild<cmTarget>(
+ cmTarget const* tgt)
+{
+ static std::string loc;
+ if (tgt->IsImported()) {
+ loc = tgt->ImportedGetFullPath("", cmStateEnums::RuntimeBinaryArtifact);
+ return loc;
+ }
+
+ cmGlobalGenerator* gg = tgt->GetGlobalGenerator();
+ if (!gg->GetConfigureDoneCMP0026()) {
+ gg->CreateGenerationObjects();
+ }
+ cmGeneratorTarget* gt = gg->FindGeneratorTarget(tgt->GetName());
+ loc = gt->GetLocationForBuild();
+ return loc;
+}
+
+template <>
+const std::string& cmTargetPropertyComputer::ComputeLocation<cmTarget>(
+ cmTarget const* tgt, const std::string& config)
+{
+ static std::string loc;
+ if (tgt->IsImported()) {
+ loc =
+ tgt->ImportedGetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
+ return loc;
+ }
+
+ cmGlobalGenerator* gg = tgt->GetGlobalGenerator();
+ if (!gg->GetConfigureDoneCMP0026()) {
+ gg->CreateGenerationObjects();
+ }
+ cmGeneratorTarget* gt = gg->FindGeneratorTarget(tgt->GetName());
+ loc = gt->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
+ return loc;
+}
+
+template <>
+cmProp cmTargetPropertyComputer::GetSources<cmTarget>(
+ cmTarget const* tgt, cmMessenger* messenger,
+ cmListFileBacktrace const& context)
+{
+ cmStringRange entries = tgt->GetSourceEntries();
+ if (entries.empty()) {
+ return nullptr;
+ }
+
+ std::ostringstream ss;
+ const char* sep = "";
+ for (std::string const& entry : entries) {
+ std::vector<std::string> files = cmExpandedList(entry);
+ for (std::string const& file : files) {
+ if (cmHasLiteralPrefix(file, "$<TARGET_OBJECTS:") &&
+ file.back() == '>') {
+ std::string objLibName = file.substr(17, file.size() - 18);
+
+ if (cmGeneratorExpression::Find(objLibName) != std::string::npos) {
+ ss << sep;
+ sep = ";";
+ ss << file;
+ continue;
+ }
+
+ bool addContent = false;
+ bool noMessage = true;
+ std::ostringstream e;
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+ switch (context.GetBottom().GetPolicy(cmPolicies::CMP0051)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0051) << "\n";
+ noMessage = false;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ addContent = true;
+ }
+ if (!noMessage) {
+ e << "Target \"" << tgt->GetName()
+ << "\" contains $<TARGET_OBJECTS> generator expression in its "
+ "sources list. This content was not previously part of the "
+ "SOURCES property when that property was read at configure "
+ "time. Code reading that property needs to be adapted to "
+ "ignore the generator expression using the string(GENEX_STRIP) "
+ "command.";
+ messenger->IssueMessage(messageType, e.str(), context);
+ }
+ if (addContent) {
+ ss << sep;
+ sep = ";";
+ ss << file;
+ }
+ } else if (cmGeneratorExpression::Find(file) == std::string::npos) {
+ ss << sep;
+ sep = ";";
+ ss << file;
+ } else {
+ cmSourceFile* sf = tgt->GetMakefile()->GetOrCreateSource(file);
+ // Construct what is known about this source file location.
+ cmSourceFileLocation const& location = sf->GetLocation();
+ std::string sname = location.GetDirectory();
+ if (!sname.empty()) {
+ sname += "/";
+ }
+ sname += location.GetName();
+
+ ss << sep;
+ sep = ";";
+ // Append this list entry.
+ ss << sname;
+ }
+ }
+ }
+ static std::string srcs;
+ srcs = ss.str();
+ return &srcs;
+}
+
+class cmTargetInternals
+{
+public:
+ cmStateEnums::TargetType TargetType;
+ cmMakefile* Makefile;
+ cmPolicies::PolicyMap PolicyMap;
+ std::string Name;
+ std::string InstallPath;
+ std::string RuntimeInstallPath;
+ cmPropertyMap Properties;
+ bool IsGeneratorProvided;
+ bool HaveInstallRule;
+ bool IsDLLPlatform;
+ bool IsAIX;
+ bool IsAndroid;
+ bool IsImportedTarget;
+ bool ImportedGloballyVisible;
+ bool BuildInterfaceIncludesAppended;
+ bool PerConfig;
+ std::set<BT<std::pair<std::string, bool>>> Utilities;
+ std::vector<cmCustomCommand> PreBuildCommands;
+ std::vector<cmCustomCommand> PreLinkCommands;
+ std::vector<cmCustomCommand> PostBuildCommands;
+ std::vector<cmInstallTargetGenerator*> InstallGenerators;
+ std::set<std::string> SystemIncludeDirectories;
+ cmTarget::LinkLibraryVectorType OriginalLinkLibraries;
+ std::map<std::string, BTs<std::string>> LanguageStandardProperties;
+ std::vector<std::string> IncludeDirectoriesEntries;
+ std::vector<cmListFileBacktrace> IncludeDirectoriesBacktraces;
+ std::vector<std::string> CompileOptionsEntries;
+ std::vector<cmListFileBacktrace> CompileOptionsBacktraces;
+ std::vector<std::string> CompileFeaturesEntries;
+ std::vector<cmListFileBacktrace> CompileFeaturesBacktraces;
+ std::vector<std::string> CompileDefinitionsEntries;
+ std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces;
+ std::vector<std::string> PrecompileHeadersEntries;
+ std::vector<cmListFileBacktrace> PrecompileHeadersBacktraces;
+ std::vector<std::string> SourceEntries;
+ std::vector<cmListFileBacktrace> SourceBacktraces;
+ std::vector<std::string> LinkOptionsEntries;
+ std::vector<cmListFileBacktrace> LinkOptionsBacktraces;
+ std::vector<std::string> LinkDirectoriesEntries;
+ std::vector<cmListFileBacktrace> LinkDirectoriesBacktraces;
+ std::vector<std::string> LinkImplementationPropertyEntries;
+ std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces;
+ std::vector<std::pair<cmTarget::TLLSignature, cmListFileContext>>
+ TLLCommands;
+ cmListFileBacktrace Backtrace;
+
+ bool CheckImportedLibName(std::string const& prop,
+ std::string const& value) const;
+
+ std::string ProcessSourceItemCMP0049(const std::string& s) const;
+};
+
+namespace {
+#define SETUP_COMMON_LANGUAGE_PROPERTIES(lang) \
+ initProp(#lang "_COMPILER_LAUNCHER"); \
+ initProp(#lang "_STANDARD"); \
+ initProp(#lang "_STANDARD_REQUIRED"); \
+ initProp(#lang "_EXTENSIONS"); \
+ initProp(#lang "_VISIBILITY_PRESET")
+}
+
+cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
+ Visibility vis, cmMakefile* mf, PerConfig perConfig)
+ : impl(cm::make_unique<cmTargetInternals>())
+{
+ assert(mf);
+ this->impl->TargetType = type;
+ this->impl->Makefile = mf;
+ this->impl->Name = name;
+ this->impl->IsGeneratorProvided = false;
+ this->impl->HaveInstallRule = false;
+ this->impl->IsDLLPlatform = false;
+ this->impl->IsAIX = false;
+ this->impl->IsAndroid = false;
+ this->impl->IsImportedTarget =
+ (vis == VisibilityImported || vis == VisibilityImportedGlobally);
+ this->impl->ImportedGloballyVisible = vis == VisibilityImportedGlobally;
+ this->impl->BuildInterfaceIncludesAppended = false;
+ this->impl->PerConfig = (perConfig == PerConfig::Yes);
+
+ // Check whether this is a DLL platform.
+ this->impl->IsDLLPlatform =
+ !this->impl->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")
+ .empty();
+
+ // Check whether we are targeting AIX.
+ {
+ std::string const& systemName =
+ this->impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME");
+ this->impl->IsAIX = (systemName == "AIX" || systemName == "OS400");
+ }
+
+ // Check whether we are targeting an Android platform.
+ this->impl->IsAndroid = (this->impl->Makefile->GetSafeDefinition(
+ "CMAKE_SYSTEM_NAME") == "Android");
+
+ std::string defKey;
+ defKey.reserve(128);
+ defKey += "CMAKE_";
+ auto initProp = [this, mf, &defKey](const std::string& property) {
+ // Replace everything after "CMAKE_"
+ defKey.replace(defKey.begin() + 6, defKey.end(), property);
+ if (cmProp value = mf->GetDefinition(defKey)) {
+ this->SetProperty(property, *value);
+ }
+ };
+ auto initPropValue = [this, mf, &defKey](const std::string& property,
+ const char* default_value) {
+ // Replace everything after "CMAKE_"
+ defKey.replace(defKey.begin() + 6, defKey.end(), property);
+ if (cmProp value = mf->GetDefinition(defKey)) {
+ this->SetProperty(property, *value);
+ } else if (default_value) {
+ this->SetProperty(property, default_value);
+ }
+ };
+
+ // Setup default property values.
+ if (this->CanCompileSources()) {
+
+ SETUP_COMMON_LANGUAGE_PROPERTIES(C);
+ SETUP_COMMON_LANGUAGE_PROPERTIES(OBJC);
+ SETUP_COMMON_LANGUAGE_PROPERTIES(CXX);
+ SETUP_COMMON_LANGUAGE_PROPERTIES(OBJCXX);
+ SETUP_COMMON_LANGUAGE_PROPERTIES(CUDA);
+
+ initProp("ANDROID_API");
+ initProp("ANDROID_API_MIN");
+ initProp("ANDROID_ARCH");
+ initProp("ANDROID_STL_TYPE");
+ initProp("ANDROID_SKIP_ANT_STEP");
+ initProp("ANDROID_PROCESS_MAX");
+ initProp("ANDROID_PROGUARD");
+ initProp("ANDROID_PROGUARD_CONFIG_PATH");
+ initProp("ANDROID_SECURE_PROPS_PATH");
+ initProp("ANDROID_NATIVE_LIB_DIRECTORIES");
+ initProp("ANDROID_NATIVE_LIB_DEPENDENCIES");
+ initProp("ANDROID_JAVA_SOURCE_DIR");
+ initProp("ANDROID_JAR_DIRECTORIES");
+ initProp("ANDROID_JAR_DEPENDENCIES");
+ initProp("ANDROID_ASSETS_DIRECTORIES");
+ initProp("ANDROID_ANT_ADDITIONAL_OPTIONS");
+ initProp("BUILD_RPATH");
+ initProp("BUILD_RPATH_USE_ORIGIN");
+ initProp("INSTALL_NAME_DIR");
+ initProp("INSTALL_REMOVE_ENVIRONMENT_RPATH");
+ initPropValue("INSTALL_RPATH", "");
+ initPropValue("INSTALL_RPATH_USE_LINK_PATH", "OFF");
+ initProp("INTERPROCEDURAL_OPTIMIZATION");
+ initPropValue("SKIP_BUILD_RPATH", "OFF");
+ initPropValue("BUILD_WITH_INSTALL_RPATH", "OFF");
+ initProp("ARCHIVE_OUTPUT_DIRECTORY");
+ initProp("LIBRARY_OUTPUT_DIRECTORY");
+ initProp("RUNTIME_OUTPUT_DIRECTORY");
+ initProp("PDB_OUTPUT_DIRECTORY");
+ initProp("COMPILE_PDB_OUTPUT_DIRECTORY");
+ initProp("FRAMEWORK");
+ initProp("FRAMEWORK_MULTI_CONFIG_POSTFIX");
+ initProp("Fortran_FORMAT");
+ initProp("Fortran_MODULE_DIRECTORY");
+ initProp("Fortran_COMPILER_LAUNCHER");
+ initProp("Fortran_PREPROCESS");
+ initProp("Fortran_VISIBILITY_PRESET");
+ initProp("GNUtoMS");
+ initProp("OSX_ARCHITECTURES");
+ initProp("IOS_INSTALL_COMBINED");
+ initProp("AUTOMOC");
+ initProp("AUTOUIC");
+ initProp("AUTORCC");
+ initProp("AUTOGEN_ORIGIN_DEPENDS");
+ initProp("AUTOGEN_PARALLEL");
+ initProp("AUTOMOC_COMPILER_PREDEFINES");
+ initProp("AUTOMOC_DEPEND_FILTERS");
+ initProp("AUTOMOC_MACRO_NAMES");
+ initProp("AUTOMOC_MOC_OPTIONS");
+ initProp("AUTOUIC_OPTIONS");
+ initProp("AUTOMOC_PATH_PREFIX");
+ initProp("AUTOUIC_SEARCH_PATHS");
+ initProp("AUTORCC_OPTIONS");
+ initProp("LINK_DEPENDS_NO_SHARED");
+ initProp("LINK_INTERFACE_LIBRARIES");
+ initProp("MSVC_RUNTIME_LIBRARY");
+ initProp("WIN32_EXECUTABLE");
+ initProp("MACOSX_BUNDLE");
+ initProp("MACOSX_RPATH");
+ initProp("NO_SYSTEM_FROM_IMPORTED");
+ initProp("BUILD_WITH_INSTALL_NAME_DIR");
+ initProp("C_CLANG_TIDY");
+ initProp("C_CPPLINT");
+ initProp("C_CPPCHECK");
+ initProp("C_INCLUDE_WHAT_YOU_USE");
+ initProp("LINK_WHAT_YOU_USE");
+ initProp("CXX_CLANG_TIDY");
+ initProp("CXX_CPPLINT");
+ initProp("CXX_CPPCHECK");
+ initProp("CXX_INCLUDE_WHAT_YOU_USE");
+ initProp("CUDA_SEPARABLE_COMPILATION");
+ initProp("CUDA_RESOLVE_DEVICE_SYMBOLS");
+ initProp("CUDA_RUNTIME_LIBRARY");
+ initProp("CUDA_ARCHITECTURES");
+ initProp("VISIBILITY_INLINES_HIDDEN");
+ initProp("JOB_POOL_COMPILE");
+ initProp("JOB_POOL_LINK");
+ initProp("JOB_POOL_PRECOMPILE_HEADER");
+ initProp("ISPC_COMPILER_LAUNCHER");
+ initProp("ISPC_HEADER_DIRECTORY");
+ initPropValue("ISPC_HEADER_SUFFIX", "_ispc.h");
+ initProp("ISPC_INSTRUCTION_SETS");
+ initProp("LINK_SEARCH_START_STATIC");
+ initProp("LINK_SEARCH_END_STATIC");
+ initProp("OBJC_CLANG_TIDY");
+ initProp("OBJCXX_CLANG_TIDY");
+ initProp("Swift_LANGUAGE_VERSION");
+ initProp("Swift_MODULE_DIRECTORY");
+ initProp("VS_JUST_MY_CODE_DEBUGGING");
+ initProp("DISABLE_PRECOMPILE_HEADERS");
+ initProp("UNITY_BUILD");
+ initProp("UNITY_BUILD_UNIQUE_ID");
+ initProp("OPTIMIZE_DEPENDENCIES");
+ initProp("EXPORT_COMPILE_COMMANDS");
+ initPropValue("UNITY_BUILD_BATCH_SIZE", "8");
+ initPropValue("UNITY_BUILD_MODE", "BATCH");
+ initPropValue("PCH_WARN_INVALID", "ON");
+ initPropValue("PCH_INSTANTIATE_TEMPLATES", "ON");
+
+#ifdef __APPLE__
+ if (this->GetGlobalGenerator()->IsXcode()) {
+ initProp("XCODE_SCHEME_ADDRESS_SANITIZER");
+ initProp("XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN");
+ initProp("XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING");
+ initProp("XCODE_SCHEME_THREAD_SANITIZER");
+ initProp("XCODE_SCHEME_THREAD_SANITIZER_STOP");
+ initProp("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER");
+ initProp("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP");
+ initProp("XCODE_SCHEME_WORKING_DIRECTORY");
+ initProp("XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER");
+ initProp("XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP");
+ initProp("XCODE_SCHEME_MALLOC_SCRIBBLE");
+ initProp("XCODE_SCHEME_MALLOC_GUARD_EDGES");
+ initProp("XCODE_SCHEME_GUARD_MALLOC");
+ initProp("XCODE_SCHEME_ZOMBIE_OBJECTS");
+ initProp("XCODE_SCHEME_MALLOC_STACK");
+ initProp("XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE");
+ initProp("XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS");
+ initProp("XCODE_SCHEME_ENVIRONMENT");
+ initPropValue("XCODE_LINK_BUILD_PHASE_MODE", "NONE");
+ }
+#endif
+ }
+
+ initProp("FOLDER");
+
+ if (this->GetGlobalGenerator()->IsXcode()) {
+ initProp("XCODE_GENERATE_SCHEME");
+ }
+
+ // Setup per-configuration property default values.
+ if (this->GetType() != cmStateEnums::UTILITY &&
+ this->GetType() != cmStateEnums::GLOBAL_TARGET) {
+ static const auto configProps = {
+ /* clang-format needs this comment to break after the opening brace */
+ "ARCHIVE_OUTPUT_DIRECTORY_", "LIBRARY_OUTPUT_DIRECTORY_",
+ "RUNTIME_OUTPUT_DIRECTORY_", "PDB_OUTPUT_DIRECTORY_",
+ "COMPILE_PDB_OUTPUT_DIRECTORY_", "MAP_IMPORTED_CONFIG_",
+ "INTERPROCEDURAL_OPTIMIZATION_"
+ };
+ // Collect the set of configuration types.
+ std::vector<std::string> configNames =
+ mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
+ for (std::string const& configName : configNames) {
+ std::string configUpper = cmSystemTools::UpperCase(configName);
+ for (auto const& prop : configProps) {
+ // Interface libraries have no output locations, so honor only
+ // the configuration map.
+ if (this->impl->TargetType == cmStateEnums::INTERFACE_LIBRARY &&
+ strcmp(prop, "MAP_IMPORTED_CONFIG_") != 0) {
+ continue;
+ }
+ std::string property = cmStrCat(prop, configUpper);
+ initProp(property);
+ }
+
+ // Initialize per-configuration name postfix property from the
+ // variable only for non-executable targets. This preserves
+ // compatibility with previous CMake versions in which executables
+ // did not support this variable. Projects may still specify the
+ // property directly.
+ if (this->impl->TargetType != cmStateEnums::EXECUTABLE &&
+ this->impl->TargetType != cmStateEnums::INTERFACE_LIBRARY) {
+ std::string property =
+ cmStrCat(cmSystemTools::UpperCase(configName), "_POSTFIX");
+ initProp(property);
+ }
+
+ if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
+ this->impl->TargetType == cmStateEnums::STATIC_LIBRARY) {
+ std::string property = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_",
+ cmSystemTools::UpperCase(configName));
+ initProp(property);
+ }
+ }
+ }
+
+ // Save the backtrace of target construction.
+ this->impl->Backtrace = this->impl->Makefile->GetBacktrace();
+
+ if (!this->IsImported()) {
+ // Initialize the INCLUDE_DIRECTORIES property based on the current value
+ // of the same directory property:
+ cm::append(this->impl->IncludeDirectoriesEntries,
+ this->impl->Makefile->GetIncludeDirectoriesEntries());
+ cm::append(this->impl->IncludeDirectoriesBacktraces,
+ this->impl->Makefile->GetIncludeDirectoriesBacktraces());
+
+ {
+ auto const& sysInc = this->impl->Makefile->GetSystemIncludeDirectories();
+ this->impl->SystemIncludeDirectories.insert(sysInc.begin(),
+ sysInc.end());
+ }
+
+ cm::append(this->impl->CompileOptionsEntries,
+ this->impl->Makefile->GetCompileOptionsEntries());
+ cm::append(this->impl->CompileOptionsBacktraces,
+ this->impl->Makefile->GetCompileOptionsBacktraces());
+
+ cm::append(this->impl->LinkOptionsEntries,
+ this->impl->Makefile->GetLinkOptionsEntries());
+ cm::append(this->impl->LinkOptionsBacktraces,
+ this->impl->Makefile->GetLinkOptionsBacktraces());
+
+ cm::append(this->impl->LinkDirectoriesEntries,
+ this->impl->Makefile->GetLinkDirectoriesEntries());
+ cm::append(this->impl->LinkDirectoriesBacktraces,
+ this->impl->Makefile->GetLinkDirectoriesBacktraces());
+ }
+
+ if (this->impl->TargetType == cmStateEnums::EXECUTABLE) {
+ initProp("ANDROID_GUI");
+ initProp("CROSSCOMPILING_EMULATOR");
+ initProp("ENABLE_EXPORTS");
+ }
+ if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
+ this->impl->TargetType == cmStateEnums::MODULE_LIBRARY) {
+ this->SetProperty("POSITION_INDEPENDENT_CODE", "True");
+ } else if (this->CanCompileSources()) {
+ initProp("POSITION_INDEPENDENT_CODE");
+ }
+ if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
+ this->impl->TargetType == cmStateEnums::EXECUTABLE) {
+ initProp("AIX_EXPORT_ALL_SYMBOLS");
+ initProp("WINDOWS_EXPORT_ALL_SYMBOLS");
+ }
+
+ // Record current policies for later use.
+ this->impl->Makefile->RecordPolicies(this->impl->PolicyMap);
+
+ if (this->impl->TargetType == cmStateEnums::INTERFACE_LIBRARY) {
+ // This policy is checked in a few conditions. The properties relevant
+ // to the policy are always ignored for cmStateEnums::INTERFACE_LIBRARY
+ // targets,
+ // so ensure that the conditions don't lead to nonsense.
+ this->impl->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
+ }
+
+ if (this->impl->TargetType <= cmStateEnums::GLOBAL_TARGET) {
+ initProp("DOTNET_TARGET_FRAMEWORK");
+ initProp("DOTNET_TARGET_FRAMEWORK_VERSION");
+ }
+
+ // check for "CMAKE_VS_GLOBALS" variable and set up target properties
+ // if any
+ cmProp globals = mf->GetDefinition("CMAKE_VS_GLOBALS");
+ if (globals) {
+ const std::string genName = mf->GetGlobalGenerator()->GetName();
+ if (cmHasLiteralPrefix(genName, "Visual Studio")) {
+ std::vector<std::string> props = cmExpandedList(*globals);
+ const std::string vsGlobal = "VS_GLOBAL_";
+ for (const std::string& i : props) {
+ // split NAME=VALUE
+ const std::string::size_type assignment = i.find('=');
+ if (assignment != std::string::npos) {
+ const std::string propName = vsGlobal + i.substr(0, assignment);
+ const std::string propValue = i.substr(assignment + 1);
+ initPropValue(propName, propValue.c_str());
+ }
+ }
+ }
+ }
+}
+
+cmTarget::cmTarget(cmTarget&&) noexcept = default;
+cmTarget::~cmTarget() = default;
+
+cmTarget& cmTarget::operator=(cmTarget&&) noexcept = default;
+
+cmStateEnums::TargetType cmTarget::GetType() const
+{
+ return this->impl->TargetType;
+}
+
+cmMakefile* cmTarget::GetMakefile() const
+{
+ return this->impl->Makefile;
+}
+
+cmPolicies::PolicyMap const& cmTarget::GetPolicyMap() const
+{
+ return this->impl->PolicyMap;
+}
+
+const std::string& cmTarget::GetName() const
+{
+ return this->impl->Name;
+}
+
+cmPolicies::PolicyStatus cmTarget::GetPolicyStatus(
+ cmPolicies::PolicyID policy) const
+{
+ return this->impl->PolicyMap.Get(policy);
+}
+
+cmGlobalGenerator* cmTarget::GetGlobalGenerator() const
+{
+ return this->impl->Makefile->GetGlobalGenerator();
+}
+
+BTs<std::string> const* cmTarget::GetLanguageStandardProperty(
+ const std::string& propertyName) const
+{
+ auto entry = this->impl->LanguageStandardProperties.find(propertyName);
+ if (entry != this->impl->LanguageStandardProperties.end()) {
+ return &entry->second;
+ }
+
+ return nullptr;
+}
+
+void cmTarget::SetLanguageStandardProperty(std::string const& lang,
+ std::string const& value,
+ const std::string& feature)
+{
+ cmListFileBacktrace featureBacktrace;
+ for (size_t i = 0; i < this->impl->CompileFeaturesEntries.size(); i++) {
+ if (this->impl->CompileFeaturesEntries[i] == feature) {
+ if (i < this->impl->CompileFeaturesBacktraces.size()) {
+ featureBacktrace = this->impl->CompileFeaturesBacktraces[i];
+ }
+ break;
+ }
+ }
+
+ BTs<std::string>& languageStandardProperty =
+ this->impl->LanguageStandardProperties[cmStrCat(lang, "_STANDARD")];
+ if (languageStandardProperty.Value != value) {
+ languageStandardProperty.Value = value;
+ languageStandardProperty.Backtraces.clear();
+ }
+ languageStandardProperty.Backtraces.emplace_back(featureBacktrace);
+}
+
+void cmTarget::AddUtility(std::string const& name, bool cross, cmMakefile* mf)
+{
+ this->impl->Utilities.insert(BT<std::pair<std::string, bool>>(
+ { name, cross }, mf ? mf->GetBacktrace() : cmListFileBacktrace()));
+}
+
+void cmTarget::AddUtility(BT<std::pair<std::string, bool>> util)
+{
+ this->impl->Utilities.emplace(std::move(util));
+}
+
+std::set<BT<std::pair<std::string, bool>>> const& cmTarget::GetUtilities()
+ const
+{
+ return this->impl->Utilities;
+}
+
+cmListFileBacktrace const& cmTarget::GetBacktrace() const
+{
+ return this->impl->Backtrace;
+}
+
+bool cmTarget::IsExecutableWithExports() const
+{
+ return (this->GetType() == cmStateEnums::EXECUTABLE &&
+ this->GetPropertyAsBool("ENABLE_EXPORTS"));
+}
+
+bool cmTarget::IsFrameworkOnApple() const
+{
+ return ((this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GetType() == cmStateEnums::STATIC_LIBRARY) &&
+ this->impl->Makefile->IsOn("APPLE") &&
+ this->GetPropertyAsBool("FRAMEWORK"));
+}
+
+bool cmTarget::IsAppBundleOnApple() const
+{
+ return (this->GetType() == cmStateEnums::EXECUTABLE &&
+ this->impl->Makefile->IsOn("APPLE") &&
+ this->GetPropertyAsBool("MACOSX_BUNDLE"));
+}
+
+bool cmTarget::IsAndroidGuiExecutable() const
+{
+ return (this->GetType() == cmStateEnums::EXECUTABLE &&
+ this->impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI"));
+}
+
+std::vector<cmCustomCommand> const& cmTarget::GetPreBuildCommands() const
+{
+ return this->impl->PreBuildCommands;
+}
+
+void cmTarget::AddPreBuildCommand(cmCustomCommand const& cmd)
+{
+ this->impl->PreBuildCommands.push_back(cmd);
+}
+
+void cmTarget::AddPreBuildCommand(cmCustomCommand&& cmd)
+{
+ this->impl->PreBuildCommands.push_back(std::move(cmd));
+}
+
+std::vector<cmCustomCommand> const& cmTarget::GetPreLinkCommands() const
+{
+ return this->impl->PreLinkCommands;
+}
+
+void cmTarget::AddPreLinkCommand(cmCustomCommand const& cmd)
+{
+ this->impl->PreLinkCommands.push_back(cmd);
+}
+
+void cmTarget::AddPreLinkCommand(cmCustomCommand&& cmd)
+{
+ this->impl->PreLinkCommands.push_back(std::move(cmd));
+}
+
+std::vector<cmCustomCommand> const& cmTarget::GetPostBuildCommands() const
+{
+ return this->impl->PostBuildCommands;
+}
+
+void cmTarget::AddPostBuildCommand(cmCustomCommand const& cmd)
+{
+ this->impl->PostBuildCommands.push_back(cmd);
+}
+
+void cmTarget::AddPostBuildCommand(cmCustomCommand&& cmd)
+{
+ this->impl->PostBuildCommands.push_back(std::move(cmd));
+}
+
+void cmTarget::AddTracedSources(std::vector<std::string> const& srcs)
+{
+ if (!srcs.empty()) {
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->SourceEntries.push_back(cmJoin(srcs, ";"));
+ this->impl->SourceBacktraces.push_back(lfbt);
+ }
+}
+
+void cmTarget::AddSources(std::vector<std::string> const& srcs)
+{
+ std::string srcFiles;
+ const char* sep = "";
+ for (auto filename : srcs) {
+ if (!cmGeneratorExpression::StartsWithGeneratorExpression(filename)) {
+ if (!filename.empty()) {
+ filename = this->impl->ProcessSourceItemCMP0049(filename);
+ if (filename.empty()) {
+ return;
+ }
+ }
+ this->impl->Makefile->GetOrCreateSource(filename);
+ }
+ srcFiles += sep;
+ srcFiles += filename;
+ sep = ";";
+ }
+ if (!srcFiles.empty()) {
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->SourceEntries.push_back(std::move(srcFiles));
+ this->impl->SourceBacktraces.push_back(lfbt);
+ }
+}
+
+std::string cmTargetInternals::ProcessSourceItemCMP0049(
+ const std::string& s) const
+{
+ std::string src = s;
+
+ // For backwards compatibility replace variables in source names.
+ // This should eventually be removed.
+ this->Makefile->ExpandVariablesInString(src);
+ if (src != s) {
+ std::ostringstream e;
+ bool noMessage = false;
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0049)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0049) << "\n";
+ break;
+ case cmPolicies::OLD:
+ noMessage = true;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ messageType = MessageType::FATAL_ERROR;
+ }
+ if (!noMessage) {
+ e << "Legacy variable expansion in source file \"" << s
+ << "\" expanded to \"" << src << "\" in target \"" << this->Name
+ << "\". This behavior will be removed in a "
+ "future version of CMake.";
+ this->Makefile->IssueMessage(messageType, e.str());
+ if (messageType == MessageType::FATAL_ERROR) {
+ return "";
+ }
+ }
+ }
+ return src;
+}
+
+std::string cmTarget::GetSourceCMP0049(const std::string& s)
+{
+ return this->impl->ProcessSourceItemCMP0049(s);
+}
+
+struct CreateLocation
+{
+ cmMakefile const* Makefile;
+
+ CreateLocation(cmMakefile const* mf)
+ : Makefile(mf)
+ {
+ }
+
+ cmSourceFileLocation operator()(const std::string& filename) const
+ {
+ return cmSourceFileLocation(this->Makefile, filename);
+ }
+};
+
+struct LocationMatcher
+{
+ const cmSourceFileLocation& Needle;
+
+ LocationMatcher(const cmSourceFileLocation& needle)
+ : Needle(needle)
+ {
+ }
+
+ bool operator()(cmSourceFileLocation& loc)
+ {
+ return loc.Matches(this->Needle);
+ }
+};
+
+struct TargetPropertyEntryFinder
+{
+private:
+ const cmSourceFileLocation& Needle;
+
+public:
+ TargetPropertyEntryFinder(const cmSourceFileLocation& needle)
+ : Needle(needle)
+ {
+ }
+
+ bool operator()(std::string const& entry)
+ {
+ std::vector<std::string> files = cmExpandedList(entry);
+ std::vector<cmSourceFileLocation> locations;
+ locations.reserve(files.size());
+ std::transform(files.begin(), files.end(), std::back_inserter(locations),
+ CreateLocation(this->Needle.GetMakefile()));
+
+ return std::find_if(locations.begin(), locations.end(),
+ LocationMatcher(this->Needle)) != locations.end();
+ }
+};
+
+cmSourceFile* cmTarget::AddSource(const std::string& src, bool before)
+{
+ cmSourceFileLocation sfl(this->impl->Makefile, src,
+ cmSourceFileLocationKind::Known);
+ if (std::find_if(
+ this->impl->SourceEntries.begin(), this->impl->SourceEntries.end(),
+ TargetPropertyEntryFinder(sfl)) == this->impl->SourceEntries.end()) {
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->SourceEntries.insert(before ? this->impl->SourceEntries.begin()
+ : this->impl->SourceEntries.end(),
+ src);
+ this->impl->SourceBacktraces.insert(
+ before ? this->impl->SourceBacktraces.begin()
+ : this->impl->SourceBacktraces.end(),
+ lfbt);
+ }
+ if (cmGeneratorExpression::Find(src) != std::string::npos) {
+ return nullptr;
+ }
+ return this->impl->Makefile->GetOrCreateSource(
+ src, false, cmSourceFileLocationKind::Known);
+}
+
+void cmTarget::ClearDependencyInformation(cmMakefile& mf) const
+{
+ std::string depname = cmStrCat(this->GetName(), "_LIB_DEPENDS");
+ mf.RemoveCacheDefinition(depname);
+}
+
+std::string cmTarget::GetDebugGeneratorExpressions(
+ const std::string& value, cmTargetLinkLibraryType llt) const
+{
+ if (llt == GENERAL_LibraryType) {
+ return value;
+ }
+
+ // Get the list of configurations considered to be DEBUG.
+ std::vector<std::string> debugConfigs =
+ this->impl->Makefile->GetCMakeInstance()->GetDebugConfigs();
+
+ std::string configString = "$<CONFIG:" + debugConfigs[0] + ">";
+
+ if (debugConfigs.size() > 1) {
+ for (std::string const& conf : cmMakeRange(debugConfigs).advance(1)) {
+ configString += ",$<CONFIG:" + conf + ">";
+ }
+ configString = "$<OR:" + configString + ">";
+ }
+
+ if (llt == OPTIMIZED_LibraryType) {
+ configString = "$<NOT:" + configString + ">";
+ }
+ return "$<" + configString + ":" + value + ">";
+}
+
+static std::string targetNameGenex(const std::string& lib)
+{
+ return "$<TARGET_NAME:" + lib + ">";
+}
+
+bool cmTarget::PushTLLCommandTrace(TLLSignature signature,
+ cmListFileContext const& lfc)
+{
+ bool ret = true;
+ if (!this->impl->TLLCommands.empty()) {
+ if (this->impl->TLLCommands.back().first != signature) {
+ ret = false;
+ }
+ }
+ if (this->impl->TLLCommands.empty() ||
+ this->impl->TLLCommands.back().second != lfc) {
+ this->impl->TLLCommands.emplace_back(signature, lfc);
+ }
+ return ret;
+}
+
+void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const
+{
+ const char* sigString =
+ (sig == cmTarget::KeywordTLLSignature ? "keyword" : "plain");
+ s << "The uses of the " << sigString << " signature are here:\n";
+ cmStateDirectory cmDir =
+ this->impl->Makefile->GetStateSnapshot().GetDirectory();
+ for (auto const& cmd : this->impl->TLLCommands) {
+ if (cmd.first == sig) {
+ cmListFileContext lfc = cmd.second;
+ lfc.FilePath = cmDir.ConvertToRelPathIfNotContained(
+ this->impl->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath);
+ s << " * " << lfc << '\n';
+ }
+ }
+}
+
+std::string const& cmTarget::GetInstallPath() const
+{
+ return this->impl->InstallPath;
+}
+
+void cmTarget::SetInstallPath(std::string const& name)
+{
+ this->impl->InstallPath = name;
+}
+
+std::string const& cmTarget::GetRuntimeInstallPath() const
+{
+ return this->impl->RuntimeInstallPath;
+}
+
+void cmTarget::SetRuntimeInstallPath(std::string const& name)
+{
+ this->impl->RuntimeInstallPath = name;
+}
+
+bool cmTarget::GetHaveInstallRule() const
+{
+ return this->impl->HaveInstallRule;
+}
+
+void cmTarget::SetHaveInstallRule(bool hir)
+{
+ this->impl->HaveInstallRule = hir;
+}
+
+void cmTarget::AddInstallGenerator(cmInstallTargetGenerator* g)
+{
+ this->impl->InstallGenerators.emplace_back(g);
+}
+
+std::vector<cmInstallTargetGenerator*> const& cmTarget::GetInstallGenerators()
+ const
+{
+ return this->impl->InstallGenerators;
+}
+
+bool cmTarget::GetIsGeneratorProvided() const
+{
+ return this->impl->IsGeneratorProvided;
+}
+
+void cmTarget::SetIsGeneratorProvided(bool igp)
+{
+ this->impl->IsGeneratorProvided = igp;
+}
+
+cmTarget::LinkLibraryVectorType const& cmTarget::GetOriginalLinkLibraries()
+ const
+{
+ return this->impl->OriginalLinkLibraries;
+}
+
+void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
+ cmTargetLinkLibraryType llt)
+{
+ cmTarget* tgt = mf.FindTargetToUse(lib);
+ {
+ const bool isNonImportedTarget = tgt && !tgt->IsImported();
+
+ const std::string libName =
+ (isNonImportedTarget && llt != GENERAL_LibraryType)
+ ? targetNameGenex(lib)
+ : lib;
+ this->AppendProperty("LINK_LIBRARIES",
+ this->GetDebugGeneratorExpressions(libName, llt));
+ }
+
+ if (cmGeneratorExpression::Find(lib) != std::string::npos ||
+ (tgt &&
+ (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) ||
+ (this->impl->Name == lib)) {
+ return;
+ }
+
+ this->impl->OriginalLinkLibraries.emplace_back(lib, llt);
+
+ // Add the explicit dependency information for libraries. This is
+ // simply a set of libraries separated by ";". There should always
+ // be a trailing ";". These library names are not canonical, in that
+ // they may be "-framework x", "-ly", "/path/libz.a", etc.
+ // We shouldn't remove duplicates here because external libraries
+ // may be purposefully duplicated to handle recursive dependencies,
+ // and we removing one instance will break the link line. Duplicates
+ // will be appropriately eliminated at emit time.
+ if (this->impl->TargetType >= cmStateEnums::STATIC_LIBRARY &&
+ this->impl->TargetType <= cmStateEnums::MODULE_LIBRARY &&
+ (this->GetPolicyStatusCMP0073() == cmPolicies::OLD ||
+ this->GetPolicyStatusCMP0073() == cmPolicies::WARN)) {
+ std::string targetEntry = cmStrCat(this->impl->Name, "_LIB_DEPENDS");
+ std::string dependencies;
+ cmProp old_val = mf.GetDefinition(targetEntry);
+ if (old_val) {
+ dependencies += *old_val;
+ }
+ switch (llt) {
+ case GENERAL_LibraryType:
+ dependencies += "general";
+ break;
+ case DEBUG_LibraryType:
+ dependencies += "debug";
+ break;
+ case OPTIMIZED_LibraryType:
+ dependencies += "optimized";
+ break;
+ }
+ dependencies += ";";
+ dependencies += lib;
+ dependencies += ";";
+ mf.AddCacheDefinition(targetEntry, dependencies,
+ "Dependencies for the target", cmStateEnums::STATIC);
+ }
+}
+
+void cmTarget::AddSystemIncludeDirectories(const std::set<std::string>& incs)
+{
+ this->impl->SystemIncludeDirectories.insert(incs.begin(), incs.end());
+}
+
+std::set<std::string> const& cmTarget::GetSystemIncludeDirectories() const
+{
+ return this->impl->SystemIncludeDirectories;
+}
+
+cmStringRange cmTarget::GetIncludeDirectoriesEntries() const
+{
+ return cmMakeRange(this->impl->IncludeDirectoriesEntries);
+}
+
+cmBacktraceRange cmTarget::GetIncludeDirectoriesBacktraces() const
+{
+ return cmMakeRange(this->impl->IncludeDirectoriesBacktraces);
+}
+
+cmStringRange cmTarget::GetCompileOptionsEntries() const
+{
+ return cmMakeRange(this->impl->CompileOptionsEntries);
+}
+
+cmBacktraceRange cmTarget::GetCompileOptionsBacktraces() const
+{
+ return cmMakeRange(this->impl->CompileOptionsBacktraces);
+}
+
+cmStringRange cmTarget::GetCompileFeaturesEntries() const
+{
+ return cmMakeRange(this->impl->CompileFeaturesEntries);
+}
+
+cmBacktraceRange cmTarget::GetCompileFeaturesBacktraces() const
+{
+ return cmMakeRange(this->impl->CompileFeaturesBacktraces);
+}
+
+cmStringRange cmTarget::GetCompileDefinitionsEntries() const
+{
+ return cmMakeRange(this->impl->CompileDefinitionsEntries);
+}
+
+cmBacktraceRange cmTarget::GetCompileDefinitionsBacktraces() const
+{
+ return cmMakeRange(this->impl->CompileDefinitionsBacktraces);
+}
+
+cmStringRange cmTarget::GetPrecompileHeadersEntries() const
+{
+ return cmMakeRange(this->impl->PrecompileHeadersEntries);
+}
+
+cmBacktraceRange cmTarget::GetPrecompileHeadersBacktraces() const
+{
+ return cmMakeRange(this->impl->PrecompileHeadersBacktraces);
+}
+
+cmStringRange cmTarget::GetSourceEntries() const
+{
+ return cmMakeRange(this->impl->SourceEntries);
+}
+
+cmBacktraceRange cmTarget::GetSourceBacktraces() const
+{
+ return cmMakeRange(this->impl->SourceBacktraces);
+}
+
+cmStringRange cmTarget::GetLinkOptionsEntries() const
+{
+ return cmMakeRange(this->impl->LinkOptionsEntries);
+}
+
+cmBacktraceRange cmTarget::GetLinkOptionsBacktraces() const
+{
+ return cmMakeRange(this->impl->LinkOptionsBacktraces);
+}
+
+cmStringRange cmTarget::GetLinkDirectoriesEntries() const
+{
+ return cmMakeRange(this->impl->LinkDirectoriesEntries);
+}
+
+cmBacktraceRange cmTarget::GetLinkDirectoriesBacktraces() const
+{
+ return cmMakeRange(this->impl->LinkDirectoriesBacktraces);
+}
+
+cmStringRange cmTarget::GetLinkImplementationEntries() const
+{
+ return cmMakeRange(this->impl->LinkImplementationPropertyEntries);
+}
+
+cmBacktraceRange cmTarget::GetLinkImplementationBacktraces() const
+{
+ return cmMakeRange(this->impl->LinkImplementationPropertyBacktraces);
+}
+
+void cmTarget::SetProperty(const std::string& prop, const char* value)
+{
+#define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP
+ MAKE_STATIC_PROP(C_STANDARD);
+ MAKE_STATIC_PROP(CXX_STANDARD);
+ MAKE_STATIC_PROP(CUDA_STANDARD);
+ MAKE_STATIC_PROP(OBJC_STANDARD);
+ MAKE_STATIC_PROP(OBJCXX_STANDARD);
+ MAKE_STATIC_PROP(COMPILE_DEFINITIONS);
+ MAKE_STATIC_PROP(COMPILE_FEATURES);
+ MAKE_STATIC_PROP(COMPILE_OPTIONS);
+ MAKE_STATIC_PROP(PRECOMPILE_HEADERS);
+ MAKE_STATIC_PROP(PRECOMPILE_HEADERS_REUSE_FROM);
+ MAKE_STATIC_PROP(CUDA_PTX_COMPILATION);
+ MAKE_STATIC_PROP(EXPORT_NAME);
+ MAKE_STATIC_PROP(IMPORTED_GLOBAL);
+ MAKE_STATIC_PROP(INCLUDE_DIRECTORIES);
+ MAKE_STATIC_PROP(LINK_OPTIONS);
+ MAKE_STATIC_PROP(LINK_DIRECTORIES);
+ MAKE_STATIC_PROP(LINK_LIBRARIES);
+ MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES);
+ MAKE_STATIC_PROP(NAME);
+ MAKE_STATIC_PROP(SOURCES);
+ MAKE_STATIC_PROP(TYPE);
+#undef MAKE_STATIC_PROP
+ if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
+ this->impl->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "MANUALLY_ADDED_DEPENDENCIES property is read-only\n");
+ return;
+ }
+ if (prop == propNAME) {
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ "NAME property is read-only\n");
+ return;
+ }
+ if (prop == propTYPE) {
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ "TYPE property is read-only\n");
+ return;
+ }
+ if (prop == propEXPORT_NAME && this->IsImported()) {
+ std::ostringstream e;
+ e << "EXPORT_NAME property can't be set on imported targets (\""
+ << this->impl->Name << "\")\n";
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+ if (prop == propSOURCES && this->IsImported()) {
+ std::ostringstream e;
+ e << "SOURCES property can't be set on imported targets (\""
+ << this->impl->Name << "\")\n";
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+ if (prop == propIMPORTED_GLOBAL && !this->IsImported()) {
+ std::ostringstream e;
+ e << "IMPORTED_GLOBAL property can't be set on non-imported targets (\""
+ << this->impl->Name << "\")\n";
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+
+ if (prop == propINCLUDE_DIRECTORIES) {
+ this->impl->IncludeDirectoriesEntries.clear();
+ this->impl->IncludeDirectoriesBacktraces.clear();
+ if (value) {
+ this->impl->IncludeDirectoriesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->IncludeDirectoriesBacktraces.push_back(lfbt);
+ }
+ } else if (prop == propCOMPILE_OPTIONS) {
+ this->impl->CompileOptionsEntries.clear();
+ this->impl->CompileOptionsBacktraces.clear();
+ if (value) {
+ this->impl->CompileOptionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->CompileOptionsBacktraces.push_back(lfbt);
+ }
+ } else if (prop == propCOMPILE_FEATURES) {
+ this->impl->CompileFeaturesEntries.clear();
+ this->impl->CompileFeaturesBacktraces.clear();
+ if (value) {
+ this->impl->CompileFeaturesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->CompileFeaturesBacktraces.push_back(lfbt);
+ }
+ } else if (prop == propCOMPILE_DEFINITIONS) {
+ this->impl->CompileDefinitionsEntries.clear();
+ this->impl->CompileDefinitionsBacktraces.clear();
+ if (value) {
+ this->impl->CompileDefinitionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->CompileDefinitionsBacktraces.push_back(lfbt);
+ }
+ } else if (prop == propLINK_OPTIONS) {
+ this->impl->LinkOptionsEntries.clear();
+ this->impl->LinkOptionsBacktraces.clear();
+ if (value) {
+ this->impl->LinkOptionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->LinkOptionsBacktraces.push_back(lfbt);
+ }
+ } else if (prop == propLINK_DIRECTORIES) {
+ this->impl->LinkDirectoriesEntries.clear();
+ this->impl->LinkDirectoriesBacktraces.clear();
+ if (value) {
+ this->impl->LinkDirectoriesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->LinkDirectoriesBacktraces.push_back(lfbt);
+ }
+ } else if (prop == propPRECOMPILE_HEADERS) {
+ this->impl->PrecompileHeadersEntries.clear();
+ this->impl->PrecompileHeadersBacktraces.clear();
+ if (value) {
+ this->impl->PrecompileHeadersEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->PrecompileHeadersBacktraces.push_back(lfbt);
+ }
+ } else if (prop == propLINK_LIBRARIES) {
+ this->impl->LinkImplementationPropertyEntries.clear();
+ this->impl->LinkImplementationPropertyBacktraces.clear();
+ if (value) {
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->LinkImplementationPropertyEntries.emplace_back(value);
+ this->impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
+ }
+ } else if (prop == propSOURCES) {
+ this->impl->SourceEntries.clear();
+ this->impl->SourceBacktraces.clear();
+ if (value) {
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->SourceEntries.emplace_back(value);
+ this->impl->SourceBacktraces.push_back(lfbt);
+ }
+ } else if (prop == propIMPORTED_GLOBAL) {
+ if (!cmIsOn(value)) {
+ std::ostringstream e;
+ e << "IMPORTED_GLOBAL property can't be set to FALSE on targets (\""
+ << this->impl->Name << "\")\n";
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+ /* no need to change anything if value does not change */
+ if (!this->impl->ImportedGloballyVisible) {
+ this->impl->ImportedGloballyVisible = true;
+ this->GetGlobalGenerator()->IndexTarget(this);
+ }
+ } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME") &&
+ !this->impl->CheckImportedLibName(prop, value ? value : "")) {
+ /* error was reported by check method */
+ } else if (prop == propCUDA_PTX_COMPILATION &&
+ this->GetType() != cmStateEnums::OBJECT_LIBRARY) {
+ std::ostringstream e;
+ e << "CUDA_PTX_COMPILATION property can only be applied to OBJECT "
+ "targets (\""
+ << this->impl->Name << "\")\n";
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ } else if (prop == propPRECOMPILE_HEADERS_REUSE_FROM) {
+ if (this->GetProperty("PRECOMPILE_HEADERS")) {
+ std::ostringstream e;
+ e << "PRECOMPILE_HEADERS property is already set on target (\""
+ << this->impl->Name << "\")\n";
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+ auto* reusedTarget = this->impl->Makefile->GetCMakeInstance()
+ ->GetGlobalGenerator()
+ ->FindTarget(value);
+ if (!reusedTarget) {
+ const std::string e(
+ "PRECOMPILE_HEADERS_REUSE_FROM set with non existing target");
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
+ return;
+ }
+
+ std::string reusedFrom = reusedTarget->GetSafeProperty(prop);
+ if (reusedFrom.empty()) {
+ reusedFrom = value;
+ }
+
+ this->impl->Properties.SetProperty(prop, reusedFrom.c_str());
+
+ reusedTarget->SetProperty("COMPILE_PDB_NAME", reusedFrom);
+ reusedTarget->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
+ cmStrCat(reusedFrom, ".dir/"));
+
+ cmProp tmp = reusedTarget->GetProperty("COMPILE_PDB_NAME");
+ this->SetProperty("COMPILE_PDB_NAME", cmToCStr(tmp));
+ this->AddUtility(reusedFrom, false, this->impl->Makefile);
+ } else if (prop == propC_STANDARD || prop == propCXX_STANDARD ||
+ prop == propCUDA_STANDARD || prop == propOBJC_STANDARD ||
+ prop == propOBJCXX_STANDARD) {
+ if (value) {
+ this->impl->LanguageStandardProperties[prop] =
+ BTs<std::string>(value, this->impl->Makefile->GetBacktrace());
+ } else {
+ this->impl->LanguageStandardProperties.erase(prop);
+ }
+ } else {
+ this->impl->Properties.SetProperty(prop, value);
+ }
+}
+
+void cmTarget::AppendProperty(const std::string& prop,
+ const std::string& value, bool asString)
+{
+ if (prop == "NAME") {
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ "NAME property is read-only\n");
+ return;
+ }
+ if (prop == "EXPORT_NAME" && this->IsImported()) {
+ std::ostringstream e;
+ e << "EXPORT_NAME property can't be set on imported targets (\""
+ << this->impl->Name << "\")\n";
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+ if (prop == "SOURCES" && this->IsImported()) {
+ std::ostringstream e;
+ e << "SOURCES property can't be set on imported targets (\""
+ << this->impl->Name << "\")\n";
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+ if (prop == "IMPORTED_GLOBAL") {
+ std::ostringstream e;
+ e << "IMPORTED_GLOBAL property can't be appended, only set on imported "
+ "targets (\""
+ << this->impl->Name << "\")\n";
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+ if (prop == "INCLUDE_DIRECTORIES") {
+ if (!value.empty()) {
+ this->impl->IncludeDirectoriesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->IncludeDirectoriesBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "COMPILE_OPTIONS") {
+ if (!value.empty()) {
+ this->impl->CompileOptionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->CompileOptionsBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "COMPILE_FEATURES") {
+ if (!value.empty()) {
+ this->impl->CompileFeaturesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->CompileFeaturesBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "COMPILE_DEFINITIONS") {
+ if (!value.empty()) {
+ this->impl->CompileDefinitionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->CompileDefinitionsBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "LINK_OPTIONS") {
+ if (!value.empty()) {
+ this->impl->LinkOptionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->LinkOptionsBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "LINK_DIRECTORIES") {
+ if (!value.empty()) {
+ this->impl->LinkDirectoriesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->LinkDirectoriesBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "PRECOMPILE_HEADERS") {
+ if (this->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
+ std::ostringstream e;
+ e << "PRECOMPILE_HEADERS_REUSE_FROM property is already set on target "
+ "(\""
+ << this->impl->Name << "\")\n";
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return;
+ }
+ if (!value.empty()) {
+ this->impl->PrecompileHeadersEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->PrecompileHeadersBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "LINK_LIBRARIES") {
+ if (!value.empty()) {
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->LinkImplementationPropertyEntries.emplace_back(value);
+ this->impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
+ }
+ } else if (prop == "SOURCES") {
+ cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ this->impl->SourceEntries.emplace_back(value);
+ this->impl->SourceBacktraces.push_back(lfbt);
+ } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME")) {
+ this->impl->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR, prop + " property may not be APPENDed.");
+ } else if (prop == "C_STANDARD" || prop == "CXX_STANDARD" ||
+ prop == "CUDA_STANDARD" || prop == "OBJC_STANDARD" ||
+ prop == "OBJCXX_STANDARD") {
+ this->impl->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR, prop + " property may not be appended.");
+ } else {
+ this->impl->Properties.AppendProperty(prop, value, asString);
+ }
+}
+
+void cmTarget::AppendBuildInterfaceIncludes()
+{
+ if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
+ !this->IsExecutableWithExports()) {
+ return;
+ }
+ if (this->impl->BuildInterfaceIncludesAppended) {
+ return;
+ }
+ this->impl->BuildInterfaceIncludesAppended = true;
+
+ if (this->impl->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")) {
+ std::string dirs = this->impl->Makefile->GetCurrentBinaryDirectory();
+ if (!dirs.empty()) {
+ dirs += ';';
+ }
+ dirs += this->impl->Makefile->GetCurrentSourceDirectory();
+ if (!dirs.empty()) {
+ this->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
+ ("$<BUILD_INTERFACE:" + dirs + ">"));
+ }
+ }
+}
+
+void cmTarget::InsertInclude(std::string const& entry,
+ cmListFileBacktrace const& bt, bool before)
+{
+ auto position = before ? this->impl->IncludeDirectoriesEntries.begin()
+ : this->impl->IncludeDirectoriesEntries.end();
+
+ auto btPosition = before ? this->impl->IncludeDirectoriesBacktraces.begin()
+ : this->impl->IncludeDirectoriesBacktraces.end();
+
+ this->impl->IncludeDirectoriesEntries.insert(position, entry);
+ this->impl->IncludeDirectoriesBacktraces.insert(btPosition, bt);
+}
+
+void cmTarget::InsertCompileOption(std::string const& entry,
+ cmListFileBacktrace const& bt, bool before)
+{
+ auto position = before ? this->impl->CompileOptionsEntries.begin()
+ : this->impl->CompileOptionsEntries.end();
+
+ auto btPosition = before ? this->impl->CompileOptionsBacktraces.begin()
+ : this->impl->CompileOptionsBacktraces.end();
+
+ this->impl->CompileOptionsEntries.insert(position, entry);
+ this->impl->CompileOptionsBacktraces.insert(btPosition, bt);
+}
+
+void cmTarget::InsertCompileDefinition(std::string const& entry,
+ cmListFileBacktrace const& bt)
+{
+ this->impl->CompileDefinitionsEntries.push_back(entry);
+ this->impl->CompileDefinitionsBacktraces.push_back(bt);
+}
+
+void cmTarget::InsertLinkOption(std::string const& entry,
+ cmListFileBacktrace const& bt, bool before)
+{
+ auto position = before ? this->impl->LinkOptionsEntries.begin()
+ : this->impl->LinkOptionsEntries.end();
+
+ auto btPosition = before ? this->impl->LinkOptionsBacktraces.begin()
+ : this->impl->LinkOptionsBacktraces.end();
+
+ this->impl->LinkOptionsEntries.insert(position, entry);
+ this->impl->LinkOptionsBacktraces.insert(btPosition, bt);
+}
+
+void cmTarget::InsertLinkDirectory(std::string const& entry,
+ cmListFileBacktrace const& bt, bool before)
+{
+ auto position = before ? this->impl->LinkDirectoriesEntries.begin()
+ : this->impl->LinkDirectoriesEntries.end();
+
+ auto btPosition = before ? this->impl->LinkDirectoriesBacktraces.begin()
+ : this->impl->LinkDirectoriesBacktraces.end();
+
+ this->impl->LinkDirectoriesEntries.insert(position, entry);
+ this->impl->LinkDirectoriesBacktraces.insert(btPosition, bt);
+}
+
+void cmTarget::InsertPrecompileHeader(std::string const& entry,
+ cmListFileBacktrace const& bt)
+{
+ this->impl->PrecompileHeadersEntries.push_back(entry);
+ this->impl->PrecompileHeadersBacktraces.push_back(bt);
+}
+
+static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop,
+ const std::string& value,
+ cmMakefile* context,
+ bool imported)
+{
+ // Look for link-type keywords in the value.
+ static cmsys::RegularExpression keys("(^|;)(debug|optimized|general)(;|$)");
+ if (!keys.find(value)) {
+ return;
+ }
+
+ // Support imported and non-imported versions of the property.
+ const char* base = (imported ? "IMPORTED_LINK_INTERFACE_LIBRARIES"
+ : "LINK_INTERFACE_LIBRARIES");
+
+ // Report an error.
+ std::ostringstream e;
+ e << "Property " << prop << " may not contain link-type keyword \""
+ << keys.match(2) << "\". "
+ << "The " << base << " property has a per-configuration "
+ << "version called " << base << "_<CONFIG> which may be "
+ << "used to specify per-configuration rules.";
+ if (!imported) {
+ e << " "
+ << "Alternatively, an IMPORTED library may be created, configured "
+ << "with a per-configuration location, and then named in the "
+ << "property value. "
+ << "See the add_library command's IMPORTED mode for details."
+ << "\n"
+ << "If you have a list of libraries that already contains the "
+ << "keyword, use the target_link_libraries command with its "
+ << "LINK_INTERFACE_LIBRARIES mode to set the property. "
+ << "The command automatically recognizes link-type keywords and sets "
+ << "the LINK_INTERFACE_LIBRARIES and LINK_INTERFACE_LIBRARIES_DEBUG "
+ << "properties accordingly.";
+ }
+ context->IssueMessage(MessageType::FATAL_ERROR, e.str());
+}
+
+static void cmTargetCheckINTERFACE_LINK_LIBRARIES(const std::string& value,
+ cmMakefile* context)
+{
+ // Look for link-type keywords in the value.
+ static cmsys::RegularExpression keys("(^|;)(debug|optimized|general)(;|$)");
+ if (!keys.find(value)) {
+ return;
+ }
+
+ // Report an error.
+ std::ostringstream e;
+
+ e << "Property INTERFACE_LINK_LIBRARIES may not contain link-type "
+ "keyword \""
+ << keys.match(2)
+ << "\". The INTERFACE_LINK_LIBRARIES "
+ "property may contain configuration-sensitive generator-expressions "
+ "which may be used to specify per-configuration rules.";
+
+ context->IssueMessage(MessageType::FATAL_ERROR, e.str());
+}
+
+static void cmTargetCheckIMPORTED_GLOBAL(const cmTarget* target,
+ cmMakefile* context)
+{
+ const auto& targets = context->GetOwnedImportedTargets();
+ auto it =
+ std::find_if(targets.begin(), targets.end(),
+ [&](const std::unique_ptr<cmTarget>& importTarget) -> bool {
+ return target == importTarget.get();
+ });
+ if (it == targets.end()) {
+ std::ostringstream e;
+ e << "Attempt to promote imported target \"" << target->GetName()
+ << "\" to global scope (by setting IMPORTED_GLOBAL) "
+ "which is not built in this directory.";
+ context->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ }
+}
+
+void cmTarget::CheckProperty(const std::string& prop,
+ cmMakefile* context) const
+{
+ // Certain properties need checking.
+ if (cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES")) {
+ if (cmProp value = this->GetProperty(prop)) {
+ cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, *value, context, false);
+ }
+ }
+ if (cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES")) {
+ if (cmProp value = this->GetProperty(prop)) {
+ cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, *value, context, true);
+ }
+ }
+ if (prop == "INTERFACE_LINK_LIBRARIES") {
+ if (cmProp value = this->GetProperty(prop)) {
+ cmTargetCheckINTERFACE_LINK_LIBRARIES(*value, context);
+ }
+ }
+ if (prop == "IMPORTED_GLOBAL") {
+ if (this->IsImported()) {
+ cmTargetCheckIMPORTED_GLOBAL(this, context);
+ }
+ }
+}
+
+cmProp cmTarget::GetComputedProperty(const std::string& prop,
+ cmMessenger* messenger,
+ cmListFileBacktrace const& context) const
+{
+ return cmTargetPropertyComputer::GetProperty(this, prop, messenger, context);
+}
+
+cmProp cmTarget::GetProperty(const std::string& prop) const
+{
+#define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP
+ MAKE_STATIC_PROP(C_STANDARD);
+ MAKE_STATIC_PROP(CXX_STANDARD);
+ MAKE_STATIC_PROP(CUDA_STANDARD);
+ MAKE_STATIC_PROP(OBJC_STANDARD);
+ MAKE_STATIC_PROP(OBJCXX_STANDARD);
+ MAKE_STATIC_PROP(LINK_LIBRARIES);
+ MAKE_STATIC_PROP(TYPE);
+ MAKE_STATIC_PROP(INCLUDE_DIRECTORIES);
+ MAKE_STATIC_PROP(COMPILE_FEATURES);
+ MAKE_STATIC_PROP(COMPILE_OPTIONS);
+ MAKE_STATIC_PROP(COMPILE_DEFINITIONS);
+ MAKE_STATIC_PROP(LINK_OPTIONS);
+ MAKE_STATIC_PROP(LINK_DIRECTORIES);
+ MAKE_STATIC_PROP(PRECOMPILE_HEADERS);
+ MAKE_STATIC_PROP(IMPORTED);
+ MAKE_STATIC_PROP(IMPORTED_GLOBAL);
+ MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES);
+ MAKE_STATIC_PROP(NAME);
+ MAKE_STATIC_PROP(BINARY_DIR);
+ MAKE_STATIC_PROP(SOURCE_DIR);
+ MAKE_STATIC_PROP(SOURCES);
+ MAKE_STATIC_PROP(FALSE);
+ MAKE_STATIC_PROP(TRUE);
+#undef MAKE_STATIC_PROP
+ static std::unordered_set<std::string> const specialProps{
+ propC_STANDARD,
+ propCXX_STANDARD,
+ propCUDA_STANDARD,
+ propOBJC_STANDARD,
+ propOBJCXX_STANDARD,
+ propLINK_LIBRARIES,
+ propTYPE,
+ propINCLUDE_DIRECTORIES,
+ propCOMPILE_FEATURES,
+ propCOMPILE_OPTIONS,
+ propCOMPILE_DEFINITIONS,
+ propPRECOMPILE_HEADERS,
+ propLINK_OPTIONS,
+ propLINK_DIRECTORIES,
+ propIMPORTED,
+ propIMPORTED_GLOBAL,
+ propMANUALLY_ADDED_DEPENDENCIES,
+ propNAME,
+ propBINARY_DIR,
+ propSOURCE_DIR,
+ propSOURCES
+ };
+ if (specialProps.count(prop)) {
+ if (prop == propC_STANDARD || prop == propCXX_STANDARD ||
+ prop == propCUDA_STANDARD || prop == propOBJC_STANDARD ||
+ prop == propOBJCXX_STANDARD) {
+ auto propertyIter = this->impl->LanguageStandardProperties.find(prop);
+ if (propertyIter == this->impl->LanguageStandardProperties.end()) {
+ return nullptr;
+ }
+ return &(propertyIter->second.Value);
+ }
+ if (prop == propLINK_LIBRARIES) {
+ if (this->impl->LinkImplementationPropertyEntries.empty()) {
+ return nullptr;
+ }
+
+ static std::string output;
+ output = cmJoin(this->impl->LinkImplementationPropertyEntries, ";");
+ return &output;
+ }
+ // the type property returns what type the target is
+ if (prop == propTYPE) {
+ return &cmState::GetTargetTypeName(this->GetType());
+ }
+ if (prop == propINCLUDE_DIRECTORIES) {
+ if (this->impl->IncludeDirectoriesEntries.empty()) {
+ return nullptr;
+ }
+
+ static std::string output;
+ output = cmJoin(this->impl->IncludeDirectoriesEntries, ";");
+ return &output;
+ }
+ if (prop == propCOMPILE_FEATURES) {
+ if (this->impl->CompileFeaturesEntries.empty()) {
+ return nullptr;
+ }
+
+ static std::string output;
+ output = cmJoin(this->impl->CompileFeaturesEntries, ";");
+ return &output;
+ }
+ if (prop == propCOMPILE_OPTIONS) {
+ if (this->impl->CompileOptionsEntries.empty()) {
+ return nullptr;
+ }
+
+ static std::string output;
+ output = cmJoin(this->impl->CompileOptionsEntries, ";");
+ return &output;
+ }
+ if (prop == propCOMPILE_DEFINITIONS) {
+ if (this->impl->CompileDefinitionsEntries.empty()) {
+ return nullptr;
+ }
+
+ static std::string output;
+ output = cmJoin(this->impl->CompileDefinitionsEntries, ";");
+ return &output;
+ }
+ if (prop == propLINK_OPTIONS) {
+ if (this->impl->LinkOptionsEntries.empty()) {
+ return nullptr;
+ }
+
+ static std::string output;
+ output = cmJoin(this->impl->LinkOptionsEntries, ";");
+ return &output;
+ }
+ if (prop == propLINK_DIRECTORIES) {
+ if (this->impl->LinkDirectoriesEntries.empty()) {
+ return nullptr;
+ }
+
+ static std::string output;
+ output = cmJoin(this->impl->LinkDirectoriesEntries, ";");
+
+ return &output;
+ }
+ if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
+ if (this->impl->Utilities.empty()) {
+ return nullptr;
+ }
+
+ static std::string output;
+ static std::vector<std::string> utilities;
+ utilities.resize(this->impl->Utilities.size());
+ std::transform(
+ this->impl->Utilities.cbegin(), this->impl->Utilities.cend(),
+ utilities.begin(),
+ [](const BT<std::pair<std::string, bool>>& item) -> std::string {
+ return item.Value.first;
+ });
+ output = cmJoin(utilities, ";");
+ return &output;
+ }
+ if (prop == propPRECOMPILE_HEADERS) {
+ if (this->impl->PrecompileHeadersEntries.empty()) {
+ return nullptr;
+ }
+
+ static std::string output;
+ output = cmJoin(this->impl->PrecompileHeadersEntries, ";");
+ return &output;
+ }
+ if (prop == propIMPORTED) {
+ return this->IsImported() ? &propTRUE : &propFALSE;
+ }
+ if (prop == propIMPORTED_GLOBAL) {
+ return this->IsImportedGloballyVisible() ? &propTRUE : &propFALSE;
+ }
+ if (prop == propNAME) {
+ return &this->GetName();
+ }
+ if (prop == propBINARY_DIR) {
+ return &this->impl->Makefile->GetStateSnapshot()
+ .GetDirectory()
+ .GetCurrentBinary();
+ }
+ if (prop == propSOURCE_DIR) {
+ return &this->impl->Makefile->GetStateSnapshot()
+ .GetDirectory()
+ .GetCurrentSource();
+ }
+ }
+
+ cmProp retVal = this->impl->Properties.GetPropertyValue(prop);
+ if (!retVal) {
+ const bool chain = this->impl->Makefile->GetState()->IsPropertyChained(
+ prop, cmProperty::TARGET);
+ if (chain) {
+ return this->impl->Makefile->GetStateSnapshot()
+ .GetDirectory()
+ .GetProperty(prop, chain);
+ }
+ return nullptr;
+ }
+ return retVal;
+}
+
+std::string const& cmTarget::GetSafeProperty(std::string const& prop) const
+{
+ cmProp ret = this->GetProperty(prop);
+ if (ret) {
+ return *ret;
+ }
+
+ static std::string const s_empty;
+ return s_empty;
+}
+
+bool cmTarget::GetPropertyAsBool(const std::string& prop) const
+{
+ return cmIsOn(this->GetProperty(prop));
+}
+
+cmPropertyMap const& cmTarget::GetProperties() const
+{
+ return this->impl->Properties;
+}
+
+bool cmTarget::IsDLLPlatform() const
+{
+ return this->impl->IsDLLPlatform;
+}
+
+bool cmTarget::IsAIX() const
+{
+ return this->impl->IsAIX;
+}
+
+bool cmTarget::IsImported() const
+{
+ return this->impl->IsImportedTarget;
+}
+
+bool cmTarget::IsImportedGloballyVisible() const
+{
+ return this->impl->ImportedGloballyVisible;
+}
+
+bool cmTarget::IsPerConfig() const
+{
+ return this->impl->PerConfig;
+}
+
+bool cmTarget::CanCompileSources() const
+{
+ if (this->IsImported()) {
+ return false;
+ }
+ switch (this->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::OBJECT_LIBRARY:
+ return true;
+ case cmStateEnums::UTILITY:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ case cmStateEnums::GLOBAL_TARGET:
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ break;
+ }
+ return false;
+}
+
+const char* cmTarget::GetSuffixVariableInternal(
+ cmStateEnums::ArtifactType artifact) const
+{
+ switch (this->GetType()) {
+ case cmStateEnums::STATIC_LIBRARY:
+ return "CMAKE_STATIC_LIBRARY_SUFFIX";
+ case cmStateEnums::SHARED_LIBRARY:
+ switch (artifact) {
+ case cmStateEnums::RuntimeBinaryArtifact:
+ return "CMAKE_SHARED_LIBRARY_SUFFIX";
+ case cmStateEnums::ImportLibraryArtifact:
+ return "CMAKE_IMPORT_LIBRARY_SUFFIX";
+ }
+ break;
+ case cmStateEnums::MODULE_LIBRARY:
+ switch (artifact) {
+ case cmStateEnums::RuntimeBinaryArtifact:
+ return "CMAKE_SHARED_MODULE_SUFFIX";
+ case cmStateEnums::ImportLibraryArtifact:
+ return "CMAKE_IMPORT_LIBRARY_SUFFIX";
+ }
+ break;
+ case cmStateEnums::EXECUTABLE:
+ switch (artifact) {
+ case cmStateEnums::RuntimeBinaryArtifact:
+ // Android GUI application packages store the native
+ // binary as a shared library.
+ return (this->IsAndroidGuiExecutable()
+ ? "CMAKE_SHARED_LIBRARY_SUFFIX"
+ : "CMAKE_EXECUTABLE_SUFFIX");
+ case cmStateEnums::ImportLibraryArtifact:
+ return (this->impl->IsAIX ? "CMAKE_AIX_IMPORT_FILE_SUFFIX"
+ : "CMAKE_IMPORT_LIBRARY_SUFFIX");
+ }
+ break;
+ default:
+ break;
+ }
+ return "";
+}
+
+const char* cmTarget::GetPrefixVariableInternal(
+ cmStateEnums::ArtifactType artifact) const
+{
+ switch (this->GetType()) {
+ case cmStateEnums::STATIC_LIBRARY:
+ return "CMAKE_STATIC_LIBRARY_PREFIX";
+ case cmStateEnums::SHARED_LIBRARY:
+ switch (artifact) {
+ case cmStateEnums::RuntimeBinaryArtifact:
+ return "CMAKE_SHARED_LIBRARY_PREFIX";
+ case cmStateEnums::ImportLibraryArtifact:
+ return "CMAKE_IMPORT_LIBRARY_PREFIX";
+ }
+ break;
+ case cmStateEnums::MODULE_LIBRARY:
+ switch (artifact) {
+ case cmStateEnums::RuntimeBinaryArtifact:
+ return "CMAKE_SHARED_MODULE_PREFIX";
+ case cmStateEnums::ImportLibraryArtifact:
+ return "CMAKE_IMPORT_LIBRARY_PREFIX";
+ }
+ break;
+ case cmStateEnums::EXECUTABLE:
+ switch (artifact) {
+ case cmStateEnums::RuntimeBinaryArtifact:
+ // Android GUI application packages store the native
+ // binary as a shared library.
+ return (this->IsAndroidGuiExecutable()
+ ? "CMAKE_SHARED_LIBRARY_PREFIX"
+ : "");
+ case cmStateEnums::ImportLibraryArtifact:
+ return (this->impl->IsAIX ? "CMAKE_AIX_IMPORT_FILE_PREFIX"
+ : "CMAKE_IMPORT_LIBRARY_PREFIX");
+ }
+ break;
+ default:
+ break;
+ }
+ return "";
+}
+
+std::string cmTarget::ImportedGetFullPath(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ assert(this->IsImported());
+
+ // Lookup/compute/cache the import information for this
+ // configuration.
+ std::string desired_config = config;
+ if (config.empty()) {
+ desired_config = "NOCONFIG";
+ }
+
+ std::string result;
+
+ cmProp loc = nullptr;
+ cmProp imp = nullptr;
+ std::string suffix;
+
+ if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
+ this->GetMappedConfig(desired_config, loc, imp, suffix)) {
+ switch (artifact) {
+ case cmStateEnums::RuntimeBinaryArtifact:
+ if (loc) {
+ result = *loc;
+ } else {
+ std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix);
+ if (cmProp config_location = this->GetProperty(impProp)) {
+ result = *config_location;
+ } else if (cmProp location =
+ this->GetProperty("IMPORTED_LOCATION")) {
+ result = *location;
+ }
+ }
+ break;
+
+ case cmStateEnums::ImportLibraryArtifact:
+ if (imp) {
+ result = *imp;
+ } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->IsExecutableWithExports()) {
+ std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
+ if (cmProp config_implib = this->GetProperty(impProp)) {
+ result = *config_implib;
+ } else if (cmProp implib = this->GetProperty("IMPORTED_IMPLIB")) {
+ result = *implib;
+ }
+ }
+ break;
+ }
+ }
+
+ if (result.empty()) {
+ if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+ auto message = [&]() -> std::string {
+ std::string unset;
+ std::string configuration;
+
+ if (artifact == cmStateEnums::RuntimeBinaryArtifact) {
+ unset = "IMPORTED_LOCATION";
+ } else if (artifact == cmStateEnums::ImportLibraryArtifact) {
+ unset = "IMPORTED_IMPLIB";
+ }
+
+ if (!config.empty()) {
+ configuration = cmStrCat(" configuration \"", config, "\"");
+ }
+
+ return cmStrCat(unset, " not set for imported target \"",
+ this->GetName(), "\"", configuration, ".");
+ };
+
+ switch (this->GetPolicyStatus(cmPolicies::CMP0111)) {
+ case cmPolicies::WARN:
+ this->impl->Makefile->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0111) + "\n" +
+ message());
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ break;
+ default:
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ message());
+ }
+ }
+
+ result = cmStrCat(this->GetName(), "-NOTFOUND");
+ }
+ return result;
+}
+
+bool cmTargetInternals::CheckImportedLibName(std::string const& prop,
+ std::string const& value) const
+{
+ if (this->TargetType != cmStateEnums::INTERFACE_LIBRARY ||
+ !this->IsImportedTarget) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ prop +
+ " property may be set only on imported INTERFACE library targets.");
+ return false;
+ }
+ if (!value.empty()) {
+ if (value[0] == '-') {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ prop + " property value\n " + value +
+ "\nmay not start with '-'.");
+ return false;
+ }
+ std::string::size_type bad = value.find_first_of(":/\\;");
+ if (bad != std::string::npos) {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ prop + " property value\n " + value +
+ "\nmay not contain '" +
+ value.substr(bad, 1) + "'.");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmTarget::GetMappedConfig(std::string const& desired_config, cmProp& loc,
+ cmProp& imp, std::string& suffix) const
+{
+ std::string config_upper;
+ if (!desired_config.empty()) {
+ config_upper = cmSystemTools::UpperCase(desired_config);
+ }
+
+ std::string locPropBase;
+ if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ locPropBase = "IMPORTED_LIBNAME";
+ } else if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ locPropBase = "IMPORTED_OBJECTS";
+ } else {
+ locPropBase = "IMPORTED_LOCATION";
+ }
+
+ // Track the configuration-specific property suffix.
+ suffix = cmStrCat('_', config_upper);
+
+ std::vector<std::string> mappedConfigs;
+ {
+ std::string mapProp = cmStrCat("MAP_IMPORTED_CONFIG_", config_upper);
+ if (cmProp mapValue = this->GetProperty(mapProp)) {
+ cmExpandList(*mapValue, mappedConfigs, true);
+ }
+ }
+
+ // If we needed to find one of the mapped configurations but did not
+ // On a DLL platform there may be only IMPORTED_IMPLIB for a shared
+ // library or an executable with exports.
+ bool allowImp = (this->IsDLLPlatform() &&
+ (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->IsExecutableWithExports())) ||
+ (this->IsAIX() && this->IsExecutableWithExports());
+
+ // If a mapping was found, check its configurations.
+ for (auto mci = mappedConfigs.begin();
+ !loc && !imp && mci != mappedConfigs.end(); ++mci) {
+ // Look for this configuration.
+ if (mci->empty()) {
+ // An empty string in the mapping has a special meaning:
+ // look up the config-less properties.
+ loc = this->GetProperty(locPropBase);
+ if (allowImp) {
+ imp = this->GetProperty("IMPORTED_IMPLIB");
+ }
+ // If it was found, set the suffix.
+ if (loc || imp) {
+ suffix.clear();
+ }
+ } else {
+ std::string mcUpper = cmSystemTools::UpperCase(*mci);
+ std::string locProp = cmStrCat(locPropBase, '_', mcUpper);
+ loc = this->GetProperty(locProp);
+ if (allowImp) {
+ std::string impProp = cmStrCat("IMPORTED_IMPLIB_", mcUpper);
+ imp = this->GetProperty(impProp);
+ }
+
+ // If it was found, use it for all properties below.
+ if (loc || imp) {
+ suffix = cmStrCat('_', mcUpper);
+ }
+ }
+ }
+
+ // If we needed to find one of the mapped configurations but did not
+ // then the target location is not found. The project does not want
+ // any other configuration.
+ if (!mappedConfigs.empty() && !loc && !imp) {
+ // Interface libraries are always available because their
+ // library name is optional so it is okay to leave loc empty.
+ return this->GetType() == cmStateEnums::INTERFACE_LIBRARY;
+ }
+
+ // If we have not yet found it then there are no mapped
+ // configurations. Look for an exact-match.
+ if (!loc && !imp) {
+ std::string locProp = cmStrCat(locPropBase, suffix);
+ loc = this->GetProperty(locProp);
+ if (allowImp) {
+ std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
+ imp = this->GetProperty(impProp);
+ }
+ }
+
+ // If we have not yet found it then there are no mapped
+ // configurations and no exact match.
+ if (!loc && !imp) {
+ // The suffix computed above is not useful.
+ suffix.clear();
+
+ // Look for a configuration-less location. This may be set by
+ // manually-written code.
+ loc = this->GetProperty(locPropBase);
+ if (allowImp) {
+ imp = this->GetProperty("IMPORTED_IMPLIB");
+ }
+ }
+
+ // If we have not yet found it then the project is willing to try
+ // any available configuration.
+ if (!loc && !imp) {
+ std::vector<std::string> availableConfigs;
+ if (cmProp iconfigs = this->GetProperty("IMPORTED_CONFIGURATIONS")) {
+ cmExpandList(*iconfigs, availableConfigs);
+ }
+ for (auto aci = availableConfigs.begin();
+ !loc && !imp && aci != availableConfigs.end(); ++aci) {
+ suffix = cmStrCat('_', cmSystemTools::UpperCase(*aci));
+ std::string locProp = cmStrCat(locPropBase, suffix);
+ loc = this->GetProperty(locProp);
+ if (allowImp) {
+ std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
+ imp = this->GetProperty(impProp);
+ }
+ }
+ }
+ // If we have not yet found it then the target location is not available.
+ if (!loc && !imp) {
+ // Interface libraries are always available because their
+ // library name is optional so it is okay to leave loc empty.
+ return this->GetType() == cmStateEnums::INTERFACE_LIBRARY;
+ }
+
+ return true;
+}
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
new file mode 100644
index 0000000..30d9f5d
--- /dev/null
+++ b/Source/cmTarget.h
@@ -0,0 +1,292 @@
+/* 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 <iosfwd>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmAlgorithms.h"
+#include "cmListFileCache.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmTargetLinkLibraryType.h"
+
+class cmCustomCommand;
+class cmGlobalGenerator;
+class cmInstallTargetGenerator;
+class cmMakefile;
+class cmMessenger;
+class cmPropertyMap;
+class cmSourceFile;
+class cmTargetInternals;
+
+/** \class cmTarget
+ * \brief Represent a library or executable target loaded from a makefile.
+ *
+ * cmTarget represents a target loaded from a makefile.
+ */
+class cmTarget
+{
+public:
+ enum Visibility
+ {
+ VisibilityNormal,
+ VisibilityImported,
+ VisibilityImportedGlobally
+ };
+
+ enum class PerConfig
+ {
+ Yes,
+ No
+ };
+
+ cmTarget(std::string const& name, cmStateEnums::TargetType type,
+ Visibility vis, cmMakefile* mf, PerConfig perConfig);
+
+ cmTarget(cmTarget const&) = delete;
+ cmTarget(cmTarget&&) noexcept;
+ ~cmTarget();
+
+ cmTarget& operator=(cmTarget const&) = delete;
+ cmTarget& operator=(cmTarget&&) noexcept;
+
+ //! Return the type of target.
+ cmStateEnums::TargetType GetType() const;
+
+ //! Get the cmMakefile that owns this target.
+ cmMakefile* GetMakefile() const;
+
+ //! Return the global generator.
+ cmGlobalGenerator* GetGlobalGenerator() const;
+
+ //! Set/Get the name of the target
+ const std::string& GetName() const;
+
+ //! Get the policy map
+ cmPolicies::PolicyMap const& GetPolicyMap() const;
+
+ //! Get policy status
+ cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID policy) const;
+
+#define DECLARE_TARGET_POLICY(POLICY) \
+ cmPolicies::PolicyStatus GetPolicyStatus##POLICY() const \
+ { \
+ return this->GetPolicyStatus(cmPolicies::POLICY); \
+ }
+
+ CM_FOR_EACH_TARGET_POLICY(DECLARE_TARGET_POLICY)
+
+#undef DECLARE_TARGET_POLICY
+
+ //! Get the list of the PRE_BUILD custom commands for this target
+ std::vector<cmCustomCommand> const& GetPreBuildCommands() const;
+ void AddPreBuildCommand(cmCustomCommand const& cmd);
+ void AddPreBuildCommand(cmCustomCommand&& cmd);
+
+ //! Get the list of the PRE_LINK custom commands for this target
+ std::vector<cmCustomCommand> const& GetPreLinkCommands() const;
+ void AddPreLinkCommand(cmCustomCommand const& cmd);
+ void AddPreLinkCommand(cmCustomCommand&& cmd);
+
+ //! Get the list of the POST_BUILD custom commands for this target
+ std::vector<cmCustomCommand> const& GetPostBuildCommands() const;
+ void AddPostBuildCommand(cmCustomCommand const& cmd);
+ void AddPostBuildCommand(cmCustomCommand&& cmd);
+
+ //! Add sources to the target.
+ void AddSources(std::vector<std::string> const& srcs);
+ void AddTracedSources(std::vector<std::string> const& srcs);
+ std::string GetSourceCMP0049(const std::string& src);
+ cmSourceFile* AddSource(const std::string& src, bool before = false);
+
+ //! how we identify a library, by name and type
+ using LibraryID = std::pair<std::string, cmTargetLinkLibraryType>;
+ using LinkLibraryVectorType = std::vector<LibraryID>;
+ LinkLibraryVectorType const& GetOriginalLinkLibraries() const;
+
+ //! Clear the dependency information recorded for this target, if any.
+ void ClearDependencyInformation(cmMakefile& mf) const;
+
+ void AddLinkLibrary(cmMakefile& mf, std::string const& lib,
+ cmTargetLinkLibraryType llt);
+
+ enum TLLSignature
+ {
+ KeywordTLLSignature,
+ PlainTLLSignature
+ };
+ bool PushTLLCommandTrace(TLLSignature signature,
+ cmListFileContext const& lfc);
+ void GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const;
+
+ /**
+ * Set the path where this target should be installed. This is relative to
+ * INSTALL_PREFIX
+ */
+ std::string const& GetInstallPath() const;
+ void SetInstallPath(std::string const& name);
+
+ /**
+ * Set the path where this target (if it has a runtime part) should be
+ * installed. This is relative to INSTALL_PREFIX
+ */
+ std::string const& GetRuntimeInstallPath() const;
+ void SetRuntimeInstallPath(std::string const& name);
+
+ /**
+ * Get/Set whether there is an install rule for this target.
+ */
+ bool GetHaveInstallRule() const;
+ void SetHaveInstallRule(bool hir);
+
+ void AddInstallGenerator(cmInstallTargetGenerator* g);
+ std::vector<cmInstallTargetGenerator*> const& GetInstallGenerators() const;
+
+ /**
+ * Get/Set whether this target was auto-created by a generator.
+ */
+ bool GetIsGeneratorProvided() const;
+ void SetIsGeneratorProvided(bool igp);
+
+ /**
+ * Add a utility on which this project depends. A utility is an executable
+ * name as would be specified to the ADD_EXECUTABLE or UTILITY_SOURCE
+ * commands. It is not a full path nor does it have an extension.
+ */
+ void AddUtility(std::string const& name, bool cross,
+ cmMakefile* mf = nullptr);
+ void AddUtility(BT<std::pair<std::string, bool>> util);
+ //! Get the utilities used by this target
+ std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const;
+
+ //! Set/Get a property of this target file
+ void SetProperty(const std::string& prop, const char* value);
+ void SetProperty(const std::string& prop, const std::string& value)
+ {
+ this->SetProperty(prop, value.c_str());
+ }
+ void AppendProperty(const std::string& prop, const std::string& value,
+ bool asString = false);
+ //! Might return a nullptr if the property is not set or invalid
+ cmProp GetProperty(const std::string& prop) const;
+ //! Always returns a valid pointer
+ std::string const& GetSafeProperty(std::string const& prop) const;
+ bool GetPropertyAsBool(const std::string& prop) const;
+ void CheckProperty(const std::string& prop, cmMakefile* context) const;
+ cmProp GetComputedProperty(const std::string& prop, cmMessenger* messenger,
+ cmListFileBacktrace const& context) const;
+ //! Get all properties
+ cmPropertyMap const& GetProperties() const;
+
+ //! Return whether or not the target is for a DLL platform.
+ bool IsDLLPlatform() const;
+
+ //! Return whether or not we are targeting AIX.
+ bool IsAIX() const;
+
+ bool IsImported() const;
+ bool IsImportedGloballyVisible() const;
+ bool IsPerConfig() const;
+ bool CanCompileSources() const;
+
+ bool GetMappedConfig(std::string const& desired_config, cmProp& loc,
+ cmProp& imp, std::string& suffix) const;
+
+ //! Return whether this target is an executable with symbol exports enabled.
+ bool IsExecutableWithExports() const;
+
+ //! Return whether this target is a shared library Framework on Apple.
+ bool IsFrameworkOnApple() const;
+
+ //! Return whether this target is an executable Bundle on Apple.
+ bool IsAppBundleOnApple() const;
+
+ //! Return whether this target is a GUI executable on Android.
+ bool IsAndroidGuiExecutable() const;
+
+ //! Get a backtrace from the creation of the target.
+ cmListFileBacktrace const& GetBacktrace() const;
+
+ void InsertInclude(std::string const& entry, cmListFileBacktrace const& bt,
+ bool before = false);
+ void InsertCompileOption(std::string const& entry,
+ cmListFileBacktrace const& bt, bool before = false);
+ void InsertCompileDefinition(std::string const& entry,
+ cmListFileBacktrace const& bt);
+ void InsertLinkOption(std::string const& entry,
+ cmListFileBacktrace const& bt, bool before = false);
+ void InsertLinkDirectory(std::string const& entry,
+ cmListFileBacktrace const& bt, bool before = false);
+ void InsertPrecompileHeader(std::string const& entry,
+ cmListFileBacktrace const& bt);
+
+ void AppendBuildInterfaceIncludes();
+
+ std::string GetDebugGeneratorExpressions(const std::string& value,
+ cmTargetLinkLibraryType llt) const;
+
+ void AddSystemIncludeDirectories(std::set<std::string> const& incs);
+ std::set<std::string> const& GetSystemIncludeDirectories() const;
+
+ BTs<std::string> const* GetLanguageStandardProperty(
+ const std::string& propertyName) const;
+
+ void SetLanguageStandardProperty(std::string const& lang,
+ std::string const& value,
+ const std::string& feature);
+
+ cmStringRange GetIncludeDirectoriesEntries() const;
+ cmBacktraceRange GetIncludeDirectoriesBacktraces() const;
+
+ cmStringRange GetCompileOptionsEntries() const;
+ cmBacktraceRange GetCompileOptionsBacktraces() const;
+
+ cmStringRange GetCompileFeaturesEntries() const;
+ cmBacktraceRange GetCompileFeaturesBacktraces() const;
+
+ cmStringRange GetCompileDefinitionsEntries() const;
+ cmBacktraceRange GetCompileDefinitionsBacktraces() const;
+
+ cmStringRange GetPrecompileHeadersEntries() const;
+ cmBacktraceRange GetPrecompileHeadersBacktraces() const;
+
+ cmStringRange GetSourceEntries() const;
+ cmBacktraceRange GetSourceBacktraces() const;
+
+ cmStringRange GetLinkOptionsEntries() const;
+ cmBacktraceRange GetLinkOptionsBacktraces() const;
+
+ cmStringRange GetLinkDirectoriesEntries() const;
+ cmBacktraceRange GetLinkDirectoriesBacktraces() const;
+
+ cmStringRange GetLinkImplementationEntries() const;
+ cmBacktraceRange GetLinkImplementationBacktraces() const;
+
+ std::string ImportedGetFullPath(const std::string& config,
+ cmStateEnums::ArtifactType artifact) const;
+
+ struct StrictTargetComparison
+ {
+ bool operator()(cmTarget const* t1, cmTarget const* t2) const;
+ };
+
+private:
+ // Internal representation details.
+ friend class cmGeneratorTarget;
+
+ const char* GetSuffixVariableInternal(
+ cmStateEnums::ArtifactType artifact) const;
+ const char* GetPrefixVariableInternal(
+ cmStateEnums::ArtifactType artifact) const;
+
+ std::unique_ptr<cmTargetInternals> impl;
+};
diff --git a/Source/cmTargetCompileDefinitionsCommand.cxx b/Source/cmTargetCompileDefinitionsCommand.cxx
new file mode 100644
index 0000000..b56b245
--- /dev/null
+++ b/Source/cmTargetCompileDefinitionsCommand.cxx
@@ -0,0 +1,58 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTargetCompileDefinitionsCommand.h"
+
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmStringAlgorithms.h"
+#include "cmTarget.h"
+#include "cmTargetPropCommandBase.h"
+
+namespace {
+
+class TargetCompileDefinitionsImpl : public cmTargetPropCommandBase
+{
+public:
+ using cmTargetPropCommandBase::cmTargetPropCommandBase;
+
+private:
+ void HandleMissingTarget(const std::string& name) override
+ {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Cannot specify compile definitions for target \"", name,
+ "\" which is not built by this project."));
+ }
+
+ bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool /*prepend*/, bool /*system*/) override
+ {
+ tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content));
+ return true; // Successfully handled.
+ }
+
+ std::string Join(const std::vector<std::string>& content) override
+ {
+ std::string defs;
+ std::string sep;
+ for (std::string const& it : content) {
+ if (cmHasLiteralPrefix(it, "-D")) {
+ defs += sep + it.substr(2);
+ } else {
+ defs += sep + it;
+ }
+ sep = ";";
+ }
+ return defs;
+ }
+};
+
+} // namespace
+
+bool cmTargetCompileDefinitionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return TargetCompileDefinitionsImpl(status).HandleArguments(
+ args, "COMPILE_DEFINITIONS");
+}
diff --git a/Source/cmTargetCompileDefinitionsCommand.h b/Source/cmTargetCompileDefinitionsCommand.h
new file mode 100644
index 0000000..54a20fd
--- /dev/null
+++ b/Source/cmTargetCompileDefinitionsCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmTargetCompileDefinitionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmTargetCompileFeaturesCommand.cxx b/Source/cmTargetCompileFeaturesCommand.cxx
new file mode 100644
index 0000000..aa1abdd
--- /dev/null
+++ b/Source/cmTargetCompileFeaturesCommand.cxx
@@ -0,0 +1,57 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTargetCompileFeaturesCommand.h"
+
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmStandardLevelResolver.h"
+#include "cmStringAlgorithms.h"
+#include "cmTargetPropCommandBase.h"
+
+class cmTarget;
+
+namespace {
+
+class TargetCompileFeaturesImpl : public cmTargetPropCommandBase
+{
+public:
+ using cmTargetPropCommandBase::cmTargetPropCommandBase;
+
+private:
+ void HandleMissingTarget(const std::string& name) override
+ {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Cannot specify compile features for target \"", name,
+ "\" which is not built by this project."));
+ }
+
+ bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool /*prepend*/, bool /*system*/) override
+ {
+ cmStandardLevelResolver standardResolver(this->Makefile);
+ for (std::string const& it : content) {
+ std::string error;
+ if (!standardResolver.AddRequiredTargetFeature(tgt, it, &error)) {
+ this->SetError(error);
+ return false; // Not (successfully) handled.
+ }
+ }
+ return true; // Successfully handled.
+ }
+
+ std::string Join(const std::vector<std::string>& content) override
+ {
+ return cmJoin(content, ";");
+ }
+};
+
+} // namespace
+
+bool cmTargetCompileFeaturesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return TargetCompileFeaturesImpl(status).HandleArguments(args,
+ "COMPILE_FEATURES");
+}
diff --git a/Source/cmTargetCompileFeaturesCommand.h b/Source/cmTargetCompileFeaturesCommand.h
new file mode 100644
index 0000000..9dbf486
--- /dev/null
+++ b/Source/cmTargetCompileFeaturesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmTargetCompileFeaturesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmTargetCompileOptionsCommand.cxx b/Source/cmTargetCompileOptionsCommand.cxx
new file mode 100644
index 0000000..dee2c10
--- /dev/null
+++ b/Source/cmTargetCompileOptionsCommand.cxx
@@ -0,0 +1,57 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTargetCompileOptionsCommand.h"
+
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmStringAlgorithms.h"
+#include "cmTarget.h"
+#include "cmTargetPropCommandBase.h"
+
+namespace {
+
+class TargetCompileOptionsImpl : public cmTargetPropCommandBase
+{
+public:
+ using cmTargetPropCommandBase::cmTargetPropCommandBase;
+
+private:
+ void HandleMissingTarget(const std::string& name) override
+ {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Cannot specify compile options for target \"", name,
+ "\" which is not built by this project."));
+ }
+
+ bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool /*system*/) override
+ {
+ cmPolicies::PolicyStatus policyStatus =
+ this->Makefile->GetPolicyStatus(cmPolicies::CMP0101);
+ if (policyStatus == cmPolicies::OLD || policyStatus == cmPolicies::WARN) {
+ prepend = false;
+ }
+
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ tgt->InsertCompileOption(this->Join(content), lfbt, prepend);
+ return true; // Successfully handled.
+ }
+
+ std::string Join(const std::vector<std::string>& content) override
+ {
+ return cmJoin(content, ";");
+ }
+};
+
+} // namespace
+
+bool cmTargetCompileOptionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return TargetCompileOptionsImpl(status).HandleArguments(
+ args, "COMPILE_OPTIONS", TargetCompileOptionsImpl::PROCESS_BEFORE);
+}
diff --git a/Source/cmTargetCompileOptionsCommand.h b/Source/cmTargetCompileOptionsCommand.h
new file mode 100644
index 0000000..1f7c684
--- /dev/null
+++ b/Source/cmTargetCompileOptionsCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmTargetCompileOptionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmTargetDepend.h b/Source/cmTargetDepend.h
new file mode 100644
index 0000000..36702bd
--- /dev/null
+++ b/Source/cmTargetDepend.h
@@ -0,0 +1,61 @@
+/* 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>
+
+class cmGeneratorTarget;
+
+/** One edge in the global target dependency graph.
+ It may be marked as a 'link' or 'util' edge or both. */
+class cmTargetDepend
+{
+ cmGeneratorTarget const* Target;
+
+ // The set order depends only on the Target, so we use
+ // mutable members to achieve a map with set syntax.
+ mutable bool Link;
+ mutable bool Util;
+ mutable bool Cross;
+ mutable cmListFileBacktrace Backtrace;
+
+public:
+ cmTargetDepend(cmGeneratorTarget const* t)
+ : Target(t)
+ , Link(false)
+ , Util(false)
+ , Cross(false)
+ {
+ }
+ operator cmGeneratorTarget const*() const { return this->Target; }
+ cmGeneratorTarget const* operator->() const { return this->Target; }
+ cmGeneratorTarget const& operator*() const { return *this->Target; }
+ friend bool operator<(cmTargetDepend const& l, cmTargetDepend const& r)
+ {
+ return l.Target < r.Target;
+ }
+ void SetType(bool strong) const
+ {
+ if (strong) {
+ this->Util = true;
+ } else {
+ this->Link = true;
+ }
+ }
+ void SetCross(bool cross) const { this->Cross = cross; }
+ void SetBacktrace(cmListFileBacktrace const& bt) const
+ {
+ this->Backtrace = bt;
+ }
+ bool IsLink() const { return this->Link; }
+ bool IsUtil() const { return this->Util; }
+ bool IsCross() const { return this->Cross; }
+ cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; }
+};
+
+/** Unordered set of (direct) dependencies of a target. */
+class cmTargetDependSet : public std::set<cmTargetDepend>
+{
+};
diff --git a/Source/cmTargetExport.h b/Source/cmTargetExport.h
new file mode 100644
index 0000000..1e38d84
--- /dev/null
+++ b/Source/cmTargetExport.h
@@ -0,0 +1,36 @@
+/* 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 <string>
+
+class cmGeneratorTarget;
+class cmInstallFilesGenerator;
+class cmInstallTargetGenerator;
+
+/** \brief A member of an ExportSet
+ *
+ * This struct holds pointers to target and all relevant generators.
+ */
+class cmTargetExport
+{
+public:
+ std::string TargetName;
+ cmGeneratorTarget* Target;
+
+ ///@name Generators
+ ///@{
+ cmInstallTargetGenerator* ArchiveGenerator;
+ cmInstallTargetGenerator* RuntimeGenerator;
+ cmInstallTargetGenerator* LibraryGenerator;
+ cmInstallTargetGenerator* ObjectsGenerator;
+ cmInstallTargetGenerator* FrameworkGenerator;
+ cmInstallTargetGenerator* BundleGenerator;
+ cmInstallFilesGenerator* HeaderGenerator;
+ std::string InterfaceIncludeDirectories;
+ ///@}
+
+ bool NamelinkOnly = false;
+};
diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx
new file mode 100644
index 0000000..3897499
--- /dev/null
+++ b/Source/cmTargetIncludeDirectoriesCommand.cxx
@@ -0,0 +1,106 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTargetIncludeDirectoriesCommand.h"
+
+#include <set>
+
+#include "cmGeneratorExpression.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetPropCommandBase.h"
+
+namespace {
+
+class TargetIncludeDirectoriesImpl : public cmTargetPropCommandBase
+{
+public:
+ using cmTargetPropCommandBase::cmTargetPropCommandBase;
+
+private:
+ void HandleMissingTarget(const std::string& name) override
+ {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Cannot specify include directories for target \"", name,
+ "\" which is not built by this project."));
+ }
+
+ bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) override;
+
+ void HandleInterfaceContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) override;
+
+ std::string Join(const std::vector<std::string>& content) override;
+};
+
+std::string TargetIncludeDirectoriesImpl::Join(
+ const std::vector<std::string>& content)
+{
+ std::string dirs;
+ std::string sep;
+ std::string prefix = this->Makefile->GetCurrentSourceDirectory() + "/";
+ for (std::string const& it : content) {
+ if (cmSystemTools::FileIsFullPath(it) ||
+ cmGeneratorExpression::Find(it) == 0) {
+ dirs += cmStrCat(sep, it);
+ } else {
+ dirs += cmStrCat(sep, prefix, it);
+ }
+ sep = ";";
+ }
+ return dirs;
+}
+
+bool TargetIncludeDirectoriesImpl::HandleDirectContent(
+ cmTarget* tgt, const std::vector<std::string>& content, bool prepend,
+ bool system)
+{
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ tgt->InsertInclude(this->Join(content), lfbt, prepend);
+ if (system) {
+ std::string prefix = this->Makefile->GetCurrentSourceDirectory() + "/";
+ std::set<std::string> sdirs;
+ for (std::string const& it : content) {
+ if (cmSystemTools::FileIsFullPath(it) ||
+ cmGeneratorExpression::Find(it) == 0) {
+ sdirs.insert(it);
+ } else {
+ sdirs.insert(prefix + it);
+ }
+ }
+ tgt->AddSystemIncludeDirectories(sdirs);
+ }
+ return true; // Successfully handled.
+}
+
+void TargetIncludeDirectoriesImpl::HandleInterfaceContent(
+ cmTarget* tgt, const std::vector<std::string>& content, bool prepend,
+ bool system)
+{
+ this->cmTargetPropCommandBase::HandleInterfaceContent(tgt, content, prepend,
+ system);
+ if (system) {
+ std::string joined = this->Join(content);
+ tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", joined);
+ }
+}
+
+} // namespace
+
+bool cmTargetIncludeDirectoriesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return TargetIncludeDirectoriesImpl(status).HandleArguments(
+ args, "INCLUDE_DIRECTORIES",
+ TargetIncludeDirectoriesImpl::ArgumentFlags(
+ TargetIncludeDirectoriesImpl::PROCESS_BEFORE |
+ TargetIncludeDirectoriesImpl::PROCESS_AFTER |
+ TargetIncludeDirectoriesImpl::PROCESS_SYSTEM));
+}
diff --git a/Source/cmTargetIncludeDirectoriesCommand.h b/Source/cmTargetIncludeDirectoriesCommand.h
new file mode 100644
index 0000000..223da7d
--- /dev/null
+++ b/Source/cmTargetIncludeDirectoriesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmTargetIncludeDirectoriesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmTargetLinkDirectoriesCommand.cxx b/Source/cmTargetLinkDirectoriesCommand.cxx
new file mode 100644
index 0000000..0c68d60
--- /dev/null
+++ b/Source/cmTargetLinkDirectoriesCommand.cxx
@@ -0,0 +1,70 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTargetLinkDirectoriesCommand.h"
+
+#include "cmGeneratorExpression.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetPropCommandBase.h"
+
+namespace {
+
+class TargetLinkDirectoriesImpl : public cmTargetPropCommandBase
+{
+public:
+ using cmTargetPropCommandBase::cmTargetPropCommandBase;
+
+private:
+ void HandleMissingTarget(const std::string& name) override
+ {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Cannot specify link directories for target \"", name,
+ "\" which is not built by this project."));
+ }
+
+ std::string Join(const std::vector<std::string>& content) override;
+
+ bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool /*system*/) override
+ {
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ tgt->InsertLinkDirectory(this->Join(content), lfbt, prepend);
+ return true; // Successfully handled.
+ }
+};
+
+std::string TargetLinkDirectoriesImpl::Join(
+ const std::vector<std::string>& content)
+{
+ std::vector<std::string> directories;
+
+ for (const auto& dir : content) {
+ auto unixPath = dir;
+ cmSystemTools::ConvertToUnixSlashes(unixPath);
+ if (!cmSystemTools::FileIsFullPath(unixPath) &&
+ !cmGeneratorExpression::StartsWithGeneratorExpression(unixPath)) {
+ auto tmp = this->Makefile->GetCurrentSourceDirectory();
+ tmp += "/";
+ tmp += unixPath;
+ unixPath = tmp;
+ }
+ directories.push_back(unixPath);
+ }
+
+ return cmJoin(directories, ";");
+}
+
+} // namespace
+
+bool cmTargetLinkDirectoriesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return TargetLinkDirectoriesImpl(status).HandleArguments(
+ args, "LINK_DIRECTORIES", TargetLinkDirectoriesImpl::PROCESS_BEFORE);
+}
diff --git a/Source/cmTargetLinkDirectoriesCommand.h b/Source/cmTargetLinkDirectoriesCommand.h
new file mode 100644
index 0000000..e305709
--- /dev/null
+++ b/Source/cmTargetLinkDirectoriesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmTargetLinkDirectoriesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
new file mode 100644
index 0000000..aecc18e
--- /dev/null
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -0,0 +1,582 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTargetLinkLibrariesCommand.h"
+
+#include <memory>
+#include <sstream>
+#include <unordered_set>
+#include <utility>
+
+#include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
+#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetLinkLibraryType.h"
+#include "cmake.h"
+
+namespace {
+
+enum ProcessingState
+{
+ ProcessingLinkLibraries,
+ ProcessingPlainLinkInterface,
+ ProcessingKeywordLinkInterface,
+ ProcessingPlainPublicInterface,
+ ProcessingKeywordPublicInterface,
+ ProcessingPlainPrivateInterface,
+ ProcessingKeywordPrivateInterface
+};
+
+const char* LinkLibraryTypeNames[3] = { "general", "debug", "optimized" };
+
+struct TLL
+{
+ cmMakefile& Makefile;
+ cmTarget* Target;
+ bool WarnRemoteInterface = false;
+ bool RejectRemoteLinking = false;
+ bool EncodeRemoteReference = false;
+ std::string DirectoryId;
+ std::unordered_set<std::string> Props;
+
+ TLL(cmMakefile& mf, cmTarget* target);
+ ~TLL();
+
+ bool HandleLibrary(ProcessingState currentProcessingState,
+ const std::string& lib, cmTargetLinkLibraryType llt);
+ void AppendProperty(std::string const& prop, std::string const& value);
+ void AffectsProperty(std::string const& prop);
+};
+
+} // namespace
+
+static void LinkLibraryTypeSpecifierWarning(cmMakefile& mf, int left,
+ int right);
+
+bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // Must have at least one argument.
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ // Alias targets cannot be on the LHS of this command.
+ if (mf.IsAlias(args[0])) {
+ status.SetError("can not be used on an ALIAS target.");
+ return false;
+ }
+
+ // Lookup the target for which libraries are specified.
+ cmTarget* target =
+ mf.GetCMakeInstance()->GetGlobalGenerator()->FindTarget(args[0]);
+ if (!target) {
+ for (const auto& importedTarget : mf.GetOwnedImportedTargets()) {
+ if (importedTarget->GetName() == args[0]) {
+ target = importedTarget.get();
+ break;
+ }
+ }
+ }
+ if (!target) {
+ MessageType t = MessageType::FATAL_ERROR; // fail by default
+ std::ostringstream e;
+ e << "Cannot specify link libraries for target \"" << args[0] << "\" "
+ << "which is not built by this project.";
+ // The bad target is the only argument. Check how policy CMP0016 is set,
+ // and accept, warn or fail respectively:
+ if (args.size() < 2) {
+ switch (mf.GetPolicyStatus(cmPolicies::CMP0016)) {
+ case cmPolicies::WARN:
+ t = MessageType::AUTHOR_WARNING;
+ // Print the warning.
+ e << "\n"
+ << "CMake does not support this but it used to work accidentally "
+ << "and is being allowed for compatibility."
+ << "\n"
+ << cmPolicies::GetPolicyWarning(cmPolicies::CMP0016);
+ break;
+ case cmPolicies::OLD: // OLD behavior does not warn.
+ t = MessageType::MESSAGE;
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ e << "\n" << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0016);
+ break;
+ case cmPolicies::NEW: // NEW behavior prints the error.
+ break;
+ }
+ }
+ // Now actually print the message.
+ switch (t) {
+ case MessageType::AUTHOR_WARNING:
+ mf.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+ break;
+ case MessageType::FATAL_ERROR:
+ mf.IssueMessage(MessageType::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ // Having a UTILITY library on the LHS is a bug.
+ if (target->GetType() == cmStateEnums::UTILITY) {
+ std::ostringstream e;
+ const char* modal = nullptr;
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+ switch (mf.GetPolicyStatus(cmPolicies::CMP0039)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0039) << "\n";
+ modal = "should";
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ modal = "must";
+ messageType = MessageType::FATAL_ERROR;
+ }
+ if (modal) {
+ e << "Utility target \"" << target->GetName() << "\" " << modal
+ << " not be used as the target of a target_link_libraries call.";
+ mf.IssueMessage(messageType, e.str());
+ if (messageType == MessageType::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+
+ // But we might not have any libs after variable expansion.
+ if (args.size() < 2) {
+ return true;
+ }
+
+ TLL tll(mf, target);
+
+ // Keep track of link configuration specifiers.
+ cmTargetLinkLibraryType llt = GENERAL_LibraryType;
+ bool haveLLT = false;
+
+ // Start with primary linking and switch to link interface
+ // specification if the keyword is encountered as the first argument.
+ ProcessingState currentProcessingState = ProcessingLinkLibraries;
+
+ // Add libraries, note that there is an optional prefix
+ // of debug and optimized that can be used.
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "LINK_INTERFACE_LIBRARIES") {
+ currentProcessingState = ProcessingPlainLinkInterface;
+ if (i != 1) {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "The LINK_INTERFACE_LIBRARIES option must appear as the second "
+ "argument, just after the target name.");
+ return true;
+ }
+ } else if (args[i] == "INTERFACE") {
+ if (i != 1 &&
+ currentProcessingState != ProcessingKeywordPrivateInterface &&
+ currentProcessingState != ProcessingKeywordPublicInterface &&
+ currentProcessingState != ProcessingKeywordLinkInterface) {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "The INTERFACE, PUBLIC or PRIVATE option must appear as the second "
+ "argument, just after the target name.");
+ return true;
+ }
+ currentProcessingState = ProcessingKeywordLinkInterface;
+ } else if (args[i] == "LINK_PUBLIC") {
+ if (i != 1 &&
+ currentProcessingState != ProcessingPlainPrivateInterface &&
+ currentProcessingState != ProcessingPlainPublicInterface) {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "The LINK_PUBLIC or LINK_PRIVATE option must appear as the second "
+ "argument, just after the target name.");
+ return true;
+ }
+ currentProcessingState = ProcessingPlainPublicInterface;
+ } else if (args[i] == "PUBLIC") {
+ if (i != 1 &&
+ currentProcessingState != ProcessingKeywordPrivateInterface &&
+ currentProcessingState != ProcessingKeywordPublicInterface &&
+ currentProcessingState != ProcessingKeywordLinkInterface) {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "The INTERFACE, PUBLIC or PRIVATE option must appear as the second "
+ "argument, just after the target name.");
+ return true;
+ }
+ currentProcessingState = ProcessingKeywordPublicInterface;
+ } else if (args[i] == "LINK_PRIVATE") {
+ if (i != 1 && currentProcessingState != ProcessingPlainPublicInterface &&
+ currentProcessingState != ProcessingPlainPrivateInterface) {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "The LINK_PUBLIC or LINK_PRIVATE option must appear as the second "
+ "argument, just after the target name.");
+ return true;
+ }
+ currentProcessingState = ProcessingPlainPrivateInterface;
+ } else if (args[i] == "PRIVATE") {
+ if (i != 1 &&
+ currentProcessingState != ProcessingKeywordPrivateInterface &&
+ currentProcessingState != ProcessingKeywordPublicInterface &&
+ currentProcessingState != ProcessingKeywordLinkInterface) {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "The INTERFACE, PUBLIC or PRIVATE option must appear as the second "
+ "argument, just after the target name.");
+ return true;
+ }
+ currentProcessingState = ProcessingKeywordPrivateInterface;
+ } else if (args[i] == "debug") {
+ if (haveLLT) {
+ LinkLibraryTypeSpecifierWarning(mf, llt, DEBUG_LibraryType);
+ }
+ llt = DEBUG_LibraryType;
+ haveLLT = true;
+ } else if (args[i] == "optimized") {
+ if (haveLLT) {
+ LinkLibraryTypeSpecifierWarning(mf, llt, OPTIMIZED_LibraryType);
+ }
+ llt = OPTIMIZED_LibraryType;
+ haveLLT = true;
+ } else if (args[i] == "general") {
+ if (haveLLT) {
+ LinkLibraryTypeSpecifierWarning(mf, llt, GENERAL_LibraryType);
+ }
+ llt = GENERAL_LibraryType;
+ haveLLT = true;
+ } else if (haveLLT) {
+ // The link type was specified by the previous argument.
+ haveLLT = false;
+ if (!tll.HandleLibrary(currentProcessingState, args[i], llt)) {
+ return false;
+ }
+ } else {
+ // Lookup old-style cache entry if type is unspecified. So if you
+ // do a target_link_libraries(foo optimized bar) it will stay optimized
+ // and not use the lookup. As there may be the case where someone has
+ // specified that a library is both debug and optimized. (this check is
+ // only there for backwards compatibility when mixing projects built
+ // with old versions of CMake and new)
+ llt = GENERAL_LibraryType;
+ std::string linkType = cmStrCat(args[0], "_LINK_TYPE");
+ cmProp linkTypeString = mf.GetDefinition(linkType);
+ if (linkTypeString) {
+ if (*linkTypeString == "debug") {
+ llt = DEBUG_LibraryType;
+ }
+ if (*linkTypeString == "optimized") {
+ llt = OPTIMIZED_LibraryType;
+ }
+ }
+ if (!tll.HandleLibrary(currentProcessingState, args[i], llt)) {
+ return false;
+ }
+ }
+ }
+
+ // Make sure the last argument was not a library type specifier.
+ if (haveLLT) {
+ mf.IssueMessage(MessageType::FATAL_ERROR,
+ cmStrCat("The \"", LinkLibraryTypeNames[llt],
+ "\" argument must be followed by a library."));
+ cmSystemTools::SetFatalErrorOccured();
+ }
+
+ const cmPolicies::PolicyStatus policy22Status =
+ target->GetPolicyStatusCMP0022();
+
+ // If any of the LINK_ options were given, make sure the
+ // LINK_INTERFACE_LIBRARIES target property exists.
+ // Use of any of the new keywords implies awareness of
+ // this property. And if no libraries are named, it should
+ // result in an empty link interface.
+ if ((policy22Status == cmPolicies::OLD ||
+ policy22Status == cmPolicies::WARN) &&
+ currentProcessingState != ProcessingLinkLibraries &&
+ !target->GetProperty("LINK_INTERFACE_LIBRARIES")) {
+ target->SetProperty("LINK_INTERFACE_LIBRARIES", "");
+ }
+
+ return true;
+}
+
+static void LinkLibraryTypeSpecifierWarning(cmMakefile& mf, int left,
+ int right)
+{
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(
+ "Link library type specifier \"", LinkLibraryTypeNames[left],
+ "\" is followed by specifier \"", LinkLibraryTypeNames[right],
+ "\" instead of a library name. The first specifier will be ignored."));
+}
+
+namespace {
+
+TLL::TLL(cmMakefile& mf, cmTarget* target)
+ : Makefile(mf)
+ , Target(target)
+{
+ if (&this->Makefile != this->Target->GetMakefile()) {
+ // The LHS target was created in another directory.
+ switch (this->Makefile.GetPolicyStatus(cmPolicies::CMP0079)) {
+ case cmPolicies::WARN:
+ this->WarnRemoteInterface = true;
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ this->RejectRemoteLinking = true;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ this->EncodeRemoteReference = true;
+ break;
+ }
+ }
+ if (this->EncodeRemoteReference) {
+ cmDirectoryId const dirId = this->Makefile.GetDirectoryId();
+ this->DirectoryId = cmStrCat(CMAKE_DIRECTORY_ID_SEP, dirId.String);
+ }
+}
+
+bool TLL::HandleLibrary(ProcessingState currentProcessingState,
+ const std::string& lib, cmTargetLinkLibraryType llt)
+{
+ if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY &&
+ currentProcessingState != ProcessingKeywordLinkInterface) {
+ this->Makefile.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "INTERFACE library can only be used with the INTERFACE keyword of "
+ "target_link_libraries");
+ return false;
+ }
+ if (this->Target->IsImported() &&
+ currentProcessingState != ProcessingKeywordLinkInterface) {
+ this->Makefile.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "IMPORTED library can only be used with the INTERFACE keyword of "
+ "target_link_libraries");
+ return false;
+ }
+
+ cmTarget::TLLSignature sig =
+ (currentProcessingState == ProcessingPlainPrivateInterface ||
+ currentProcessingState == ProcessingPlainPublicInterface ||
+ currentProcessingState == ProcessingKeywordPrivateInterface ||
+ currentProcessingState == ProcessingKeywordPublicInterface ||
+ currentProcessingState == ProcessingKeywordLinkInterface)
+ ? cmTarget::KeywordTLLSignature
+ : cmTarget::PlainTLLSignature;
+ if (!this->Target->PushTLLCommandTrace(
+ sig, this->Makefile.GetBacktrace().Top())) {
+ std::ostringstream e;
+ const char* modal = nullptr;
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+ switch (this->Makefile.GetPolicyStatus(cmPolicies::CMP0023)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0023) << "\n";
+ modal = "should";
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ modal = "must";
+ messageType = MessageType::FATAL_ERROR;
+ }
+
+ if (modal) {
+ // If the sig is a keyword form and there is a conflict, the existing
+ // form must be the plain form.
+ const char* existingSig =
+ (sig == cmTarget::KeywordTLLSignature ? "plain" : "keyword");
+ e << "The " << existingSig
+ << " signature for target_link_libraries has "
+ "already been used with the target \""
+ << this->Target->GetName()
+ << "\". All uses of target_link_libraries with a target " << modal
+ << " be either all-keyword or all-plain.\n";
+ this->Target->GetTllSignatureTraces(e,
+ sig == cmTarget::KeywordTLLSignature
+ ? cmTarget::PlainTLLSignature
+ : cmTarget::KeywordTLLSignature);
+ this->Makefile.IssueMessage(messageType, e.str());
+ if (messageType == MessageType::FATAL_ERROR) {
+ return false;
+ }
+ }
+ }
+
+ // Handle normal case where the command was called with another keyword than
+ // INTERFACE / LINK_INTERFACE_LIBRARIES or none at all. (The "LINK_LIBRARIES"
+ // property of the target on the LHS shall be populated.)
+ if (currentProcessingState != ProcessingKeywordLinkInterface &&
+ currentProcessingState != ProcessingPlainLinkInterface) {
+
+ if (this->RejectRemoteLinking) {
+ this->Makefile.IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Attempt to add link library \"", lib, "\" to target \"",
+ this->Target->GetName(),
+ "\" which is not built in this "
+ "directory.\nThis is allowed only when policy CMP0079 "
+ "is set to NEW."));
+ return false;
+ }
+
+ cmTarget* tgt = this->Makefile.GetGlobalGenerator()->FindTarget(lib);
+
+ if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) &&
+ (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) &&
+ (tgt->GetType() != cmStateEnums::UNKNOWN_LIBRARY) &&
+ (tgt->GetType() != cmStateEnums::OBJECT_LIBRARY) &&
+ (tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) &&
+ !tgt->IsExecutableWithExports()) {
+ this->Makefile.IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(
+ "Target \"", lib, "\" of type ",
+ cmState::GetTargetTypeName(tgt->GetType()),
+ " may not be linked into another target. One may link only to "
+ "INTERFACE, OBJECT, STATIC or SHARED libraries, or to ",
+ "executables with the ENABLE_EXPORTS property set."));
+ }
+
+ this->AffectsProperty("LINK_LIBRARIES");
+ this->Target->AddLinkLibrary(this->Makefile, lib, llt);
+ }
+
+ if (this->WarnRemoteInterface) {
+ this->Makefile.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0079), "\nTarget\n ",
+ this->Target->GetName(),
+ "\nis not created in this "
+ "directory. For compatibility with older versions of CMake, link "
+ "library\n ",
+ lib,
+ "\nwill be looked up in the directory in which "
+ "the target was created rather than in this calling directory."));
+ }
+
+ // Handle (additional) case where the command was called with PRIVATE /
+ // LINK_PRIVATE and stop its processing. (The "INTERFACE_LINK_LIBRARIES"
+ // property of the target on the LHS shall only be populated if it is a
+ // STATIC library.)
+ if (currentProcessingState == ProcessingKeywordPrivateInterface ||
+ currentProcessingState == ProcessingPlainPrivateInterface) {
+ if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ std::string configLib =
+ this->Target->GetDebugGeneratorExpressions(lib, llt);
+ if (cmGeneratorExpression::IsValidTargetName(lib) ||
+ cmGeneratorExpression::Find(lib) != std::string::npos) {
+ configLib = "$<LINK_ONLY:" + configLib + ">";
+ }
+ this->AppendProperty("INTERFACE_LINK_LIBRARIES", configLib);
+ }
+ return true;
+ }
+
+ // Handle general case where the command was called with another keyword than
+ // PRIVATE / LINK_PRIVATE or none at all. (The "INTERFACE_LINK_LIBRARIES"
+ // property of the target on the LHS shall be populated.)
+ this->AppendProperty("INTERFACE_LINK_LIBRARIES",
+ this->Target->GetDebugGeneratorExpressions(lib, llt));
+
+ // Stop processing if called without any keyword.
+ if (currentProcessingState == ProcessingLinkLibraries) {
+ return true;
+ }
+ // Stop processing if policy CMP0022 is set to NEW.
+ const cmPolicies::PolicyStatus policy22Status =
+ this->Target->GetPolicyStatusCMP0022();
+ if (policy22Status != cmPolicies::OLD &&
+ policy22Status != cmPolicies::WARN) {
+ return true;
+ }
+ // Stop processing if called with an INTERFACE library on the LHS.
+ if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ return true;
+ }
+
+ // Handle (additional) backward-compatibility case where the command was
+ // called with PUBLIC / INTERFACE / LINK_PUBLIC / LINK_INTERFACE_LIBRARIES.
+ // (The policy CMP0022 is not set to NEW.)
+ {
+ // Get the list of configurations considered to be DEBUG.
+ std::vector<std::string> debugConfigs =
+ this->Makefile.GetCMakeInstance()->GetDebugConfigs();
+ std::string prop;
+
+ // Include this library in the link interface for the target.
+ if (llt == DEBUG_LibraryType || llt == GENERAL_LibraryType) {
+ // Put in the DEBUG configuration interfaces.
+ for (std::string const& dc : debugConfigs) {
+ prop = cmStrCat("LINK_INTERFACE_LIBRARIES_", dc);
+ this->AppendProperty(prop, lib);
+ }
+ }
+ if (llt == OPTIMIZED_LibraryType || llt == GENERAL_LibraryType) {
+ // Put in the non-DEBUG configuration interfaces.
+ this->AppendProperty("LINK_INTERFACE_LIBRARIES", lib);
+
+ // Make sure the DEBUG configuration interfaces exist so that the
+ // general one will not be used as a fall-back.
+ for (std::string const& dc : debugConfigs) {
+ prop = cmStrCat("LINK_INTERFACE_LIBRARIES_", dc);
+ if (!this->Target->GetProperty(prop)) {
+ this->Target->SetProperty(prop, "");
+ }
+ }
+ }
+ }
+ return true;
+}
+
+void TLL::AppendProperty(std::string const& prop, std::string const& value)
+{
+ this->AffectsProperty(prop);
+ this->Target->AppendProperty(prop, value);
+}
+
+void TLL::AffectsProperty(std::string const& prop)
+{
+ if (!this->EncodeRemoteReference) {
+ return;
+ }
+ // Add a wrapper to the expression to tell LookupLinkItems to look up
+ // names in the caller's directory.
+ if (this->Props.insert(prop).second) {
+ this->Target->AppendProperty(prop, this->DirectoryId);
+ }
+}
+
+TLL::~TLL()
+{
+ for (std::string const& prop : this->Props) {
+ this->Target->AppendProperty(prop, CMAKE_DIRECTORY_ID_SEP);
+ }
+}
+
+} // namespace
diff --git a/Source/cmTargetLinkLibrariesCommand.h b/Source/cmTargetLinkLibrariesCommand.h
new file mode 100644
index 0000000..bc76f3e
--- /dev/null
+++ b/Source/cmTargetLinkLibrariesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmTargetLinkLibraryType.h b/Source/cmTargetLinkLibraryType.h
new file mode 100644
index 0000000..16ac41a
--- /dev/null
+++ b/Source/cmTargetLinkLibraryType.h
@@ -0,0 +1,10 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+enum cmTargetLinkLibraryType
+{
+ GENERAL_LibraryType,
+ DEBUG_LibraryType,
+ OPTIMIZED_LibraryType
+};
diff --git a/Source/cmTargetLinkOptionsCommand.cxx b/Source/cmTargetLinkOptionsCommand.cxx
new file mode 100644
index 0000000..df9416f
--- /dev/null
+++ b/Source/cmTargetLinkOptionsCommand.cxx
@@ -0,0 +1,50 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTargetLinkOptionsCommand.h"
+
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmStringAlgorithms.h"
+#include "cmTarget.h"
+#include "cmTargetPropCommandBase.h"
+
+namespace {
+
+class TargetLinkOptionsImpl : public cmTargetPropCommandBase
+{
+public:
+ using cmTargetPropCommandBase::cmTargetPropCommandBase;
+
+private:
+ void HandleMissingTarget(const std::string& name) override
+ {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Cannot specify link options for target \"", name,
+ "\" which is not built by this project."));
+ }
+
+ bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool /*system*/) override
+ {
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ tgt->InsertLinkOption(this->Join(content), lfbt, prepend);
+ return true; // Successfully handled.
+ }
+
+ std::string Join(const std::vector<std::string>& content) override
+ {
+ return cmJoin(content, ";");
+ }
+};
+
+} // namespace
+
+bool cmTargetLinkOptionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return TargetLinkOptionsImpl(status).HandleArguments(
+ args, "LINK_OPTIONS", TargetLinkOptionsImpl::PROCESS_BEFORE);
+}
diff --git a/Source/cmTargetLinkOptionsCommand.h b/Source/cmTargetLinkOptionsCommand.h
new file mode 100644
index 0000000..fbe7d49
--- /dev/null
+++ b/Source/cmTargetLinkOptionsCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmTargetLinkOptionsCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmTargetPrecompileHeadersCommand.cxx b/Source/cmTargetPrecompileHeadersCommand.cxx
new file mode 100644
index 0000000..a5066cc
--- /dev/null
+++ b/Source/cmTargetPrecompileHeadersCommand.cxx
@@ -0,0 +1,86 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTargetPrecompileHeadersCommand.h"
+
+#include <utility>
+
+#include "cmGeneratorExpression.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetPropCommandBase.h"
+
+namespace {
+
+std::vector<std::string> ConvertToAbsoluteContent(
+ const std::vector<std::string>& content, std::string const& baseDir)
+{
+ std::vector<std::string> absoluteContent;
+ absoluteContent.reserve(content.size());
+ for (std::string const& src : content) {
+ std::string absoluteSrc;
+ // Use '<foo.h>' and '"foo.h"' includes and absolute paths as-is.
+ // Interpret relative paths with respect to the source directory.
+ // If the path starts in a generator expression, assume it is absolute.
+ if (cmHasLiteralPrefix(src, "<") || cmHasLiteralPrefix(src, "\"") ||
+ cmSystemTools::FileIsFullPath(src) ||
+ cmGeneratorExpression::Find(src) == 0) {
+ absoluteSrc = src;
+ } else {
+ absoluteSrc = cmStrCat(baseDir, '/', src);
+ }
+ absoluteContent.emplace_back(std::move(absoluteSrc));
+ }
+ return absoluteContent;
+}
+
+class TargetPrecompileHeadersImpl : public cmTargetPropCommandBase
+{
+public:
+ using cmTargetPropCommandBase::cmTargetPropCommandBase;
+
+private:
+ bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool /*prepend*/, bool /*system*/) override
+ {
+ std::string const& base = this->Makefile->GetCurrentSourceDirectory();
+ tgt->AppendProperty("PRECOMPILE_HEADERS",
+ this->Join(ConvertToAbsoluteContent(content, base)));
+ return true;
+ }
+
+ void HandleInterfaceContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) override
+ {
+ std::string const& base = this->Makefile->GetCurrentSourceDirectory();
+ this->cmTargetPropCommandBase::HandleInterfaceContent(
+ tgt, ConvertToAbsoluteContent(content, base), prepend, system);
+ }
+
+ void HandleMissingTarget(const std::string& name) override
+ {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Cannot specify precompile headers for target \"", name,
+ "\" which is not built by this project."));
+ }
+
+ std::string Join(const std::vector<std::string>& content) override
+ {
+ return cmJoin(content, ";");
+ }
+};
+
+} // namespace
+
+bool cmTargetPrecompileHeadersCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return TargetPrecompileHeadersImpl(status).HandleArguments(
+ args, "PRECOMPILE_HEADERS",
+ TargetPrecompileHeadersImpl::PROCESS_REUSE_FROM);
+}
diff --git a/Source/cmTargetPrecompileHeadersCommand.h b/Source/cmTargetPrecompileHeadersCommand.h
new file mode 100644
index 0000000..dd08a6d
--- /dev/null
+++ b/Source/cmTargetPrecompileHeadersCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmTargetPrecompileHeadersCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx
new file mode 100644
index 0000000..e41714a
--- /dev/null
+++ b/Source/cmTargetPropCommandBase.cxx
@@ -0,0 +1,191 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTargetPropCommandBase.h"
+
+#include "cmExecutionStatus.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmStateTypes.h"
+#include "cmTarget.h"
+#include "cmake.h"
+
+cmTargetPropCommandBase::cmTargetPropCommandBase(cmExecutionStatus& status)
+ : Makefile(&status.GetMakefile())
+ , Status(status)
+{
+}
+
+void cmTargetPropCommandBase::SetError(std::string const& e)
+{
+ this->Status.SetError(e);
+}
+
+bool cmTargetPropCommandBase::HandleArguments(
+ std::vector<std::string> const& args, const std::string& prop,
+ ArgumentFlags flags)
+{
+ if (args.size() < 2) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ if (this->Makefile->IsAlias(args[0])) {
+ this->SetError("can not be used on an ALIAS target.");
+ return false;
+ }
+ // Lookup the target for which property-values are specified.
+ this->Target =
+ this->Makefile->GetCMakeInstance()->GetGlobalGenerator()->FindTarget(
+ args[0]);
+ if (!this->Target) {
+ this->Target = this->Makefile->FindTargetToUse(args[0]);
+ }
+ if (!this->Target) {
+ this->HandleMissingTarget(args[0]);
+ return false;
+ }
+ const bool isRegularTarget =
+ (this->Target->GetType() == cmStateEnums::EXECUTABLE) ||
+ (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY) ||
+ (this->Target->GetType() == cmStateEnums::SHARED_LIBRARY) ||
+ (this->Target->GetType() == cmStateEnums::MODULE_LIBRARY) ||
+ (this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) ||
+ (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) ||
+ (this->Target->GetType() == cmStateEnums::UNKNOWN_LIBRARY);
+ const bool isCustomTarget = this->Target->GetType() == cmStateEnums::UTILITY;
+
+ if (prop == "SOURCES") {
+ if (!isRegularTarget && !isCustomTarget) {
+ this->SetError("called with non-compilable target type");
+ return false;
+ }
+ } else {
+ if (!isRegularTarget) {
+ this->SetError("called with non-compilable target type");
+ return false;
+ }
+ }
+
+ bool system = false;
+ unsigned int argIndex = 1;
+
+ if ((flags & PROCESS_SYSTEM) && args[argIndex] == "SYSTEM") {
+ if (args.size() < 3) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ system = true;
+ ++argIndex;
+ }
+
+ bool prepend = false;
+ if ((flags & PROCESS_BEFORE) && args[argIndex] == "BEFORE") {
+ if (args.size() < 3) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ prepend = true;
+ ++argIndex;
+ } else if ((flags & PROCESS_AFTER) && args[argIndex] == "AFTER") {
+ if (args.size() < 3) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ prepend = false;
+ ++argIndex;
+ }
+
+ if ((flags & PROCESS_REUSE_FROM) && args[argIndex] == "REUSE_FROM") {
+ if (args.size() != 3) {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+ ++argIndex;
+
+ this->Target->SetProperty("PRECOMPILE_HEADERS_REUSE_FROM", args[argIndex]);
+ ++argIndex;
+ }
+
+ this->Property = prop;
+
+ while (argIndex < args.size()) {
+ if (!this->ProcessContentArgs(args, argIndex, prepend, system)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmTargetPropCommandBase::ProcessContentArgs(
+ std::vector<std::string> const& args, unsigned int& argIndex, bool prepend,
+ bool system)
+{
+ std::string const& scope = args[argIndex];
+
+ if (scope != "PUBLIC" && scope != "PRIVATE" && scope != "INTERFACE") {
+ this->SetError("called with invalid arguments");
+ return false;
+ }
+
+ ++argIndex;
+
+ std::vector<std::string> content;
+
+ for (unsigned int i = argIndex; i < args.size(); ++i, ++argIndex) {
+ if (args[i] == "PUBLIC" || args[i] == "PRIVATE" ||
+ args[i] == "INTERFACE") {
+ break;
+ }
+ content.push_back(args[i]);
+ }
+ if (!content.empty()) {
+ if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY &&
+ scope != "INTERFACE" && this->Property != "SOURCES") {
+ this->SetError("may only set INTERFACE properties on INTERFACE targets");
+ return false;
+ }
+ if (this->Target->IsImported() && scope != "INTERFACE") {
+ this->SetError("may only set INTERFACE properties on IMPORTED targets");
+ return false;
+ }
+ if (this->Target->GetType() == cmStateEnums::UTILITY &&
+ scope != "PRIVATE") {
+ this->SetError("may only set PRIVATE properties on custom targets");
+ return false;
+ }
+ }
+ return this->PopulateTargetProperies(scope, content, prepend, system);
+}
+
+bool cmTargetPropCommandBase::PopulateTargetProperies(
+ const std::string& scope, const std::vector<std::string>& content,
+ bool prepend, bool system)
+{
+ if (content.empty()) {
+ return true;
+ }
+ if (scope == "PRIVATE" || scope == "PUBLIC") {
+ if (!this->HandleDirectContent(this->Target, content, prepend, system)) {
+ return false;
+ }
+ }
+ if (scope == "INTERFACE" || scope == "PUBLIC") {
+ this->HandleInterfaceContent(this->Target, content, prepend, system);
+ }
+ return true;
+}
+
+void cmTargetPropCommandBase::HandleInterfaceContent(
+ cmTarget* tgt, const std::vector<std::string>& content, bool prepend, bool)
+{
+ if (prepend) {
+ const std::string propName = std::string("INTERFACE_") + this->Property;
+ cmProp propValue = tgt->GetProperty(propName);
+ const std::string totalContent =
+ this->Join(content) + (propValue ? (";" + *propValue) : std::string());
+ tgt->SetProperty(propName, totalContent);
+ } else {
+ tgt->AppendProperty("INTERFACE_" + this->Property, this->Join(content));
+ }
+}
diff --git a/Source/cmTargetPropCommandBase.h b/Source/cmTargetPropCommandBase.h
new file mode 100644
index 0000000..fc24fe8
--- /dev/null
+++ b/Source/cmTargetPropCommandBase.h
@@ -0,0 +1,60 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+class cmExecutionStatus;
+class cmMakefile;
+class cmTarget;
+
+class cmTargetPropCommandBase
+{
+public:
+ cmTargetPropCommandBase(cmExecutionStatus& status);
+ virtual ~cmTargetPropCommandBase() = default;
+
+ void SetError(std::string const& e);
+
+ enum ArgumentFlags
+ {
+ NO_FLAGS = 0x0,
+ PROCESS_BEFORE = 0x1,
+ PROCESS_AFTER = 0x2,
+ PROCESS_SYSTEM = 0x3,
+ PROCESS_REUSE_FROM = 0x4
+ };
+
+ bool HandleArguments(std::vector<std::string> const& args,
+ const std::string& prop,
+ ArgumentFlags flags = NO_FLAGS);
+
+protected:
+ std::string Property;
+ cmTarget* Target = nullptr;
+ cmMakefile* Makefile;
+
+ virtual void HandleInterfaceContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system);
+
+private:
+ virtual void HandleMissingTarget(const std::string& name) = 0;
+
+ virtual bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) = 0;
+
+ virtual std::string Join(const std::vector<std::string>& content) = 0;
+
+ bool ProcessContentArgs(std::vector<std::string> const& args,
+ unsigned int& argIndex, bool prepend, bool system);
+ bool PopulateTargetProperies(const std::string& scope,
+ const std::vector<std::string>& content,
+ bool prepend, bool system);
+
+ cmExecutionStatus& Status;
+};
diff --git a/Source/cmTargetPropertyComputer.cxx b/Source/cmTargetPropertyComputer.cxx
new file mode 100644
index 0000000..b9c9365
--- /dev/null
+++ b/Source/cmTargetPropertyComputer.cxx
@@ -0,0 +1,43 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmTargetPropertyComputer.h"
+
+#include <sstream>
+
+#include "cmMessageType.h"
+#include "cmMessenger.h"
+#include "cmPolicies.h"
+#include "cmStateSnapshot.h"
+
+bool cmTargetPropertyComputer::HandleLocationPropertyPolicy(
+ std::string const& tgtName, cmMessenger* messenger,
+ cmListFileBacktrace const& context)
+{
+ std::ostringstream e;
+ const char* modal = nullptr;
+ MessageType messageType = MessageType::AUTHOR_WARNING;
+ switch (context.GetBottom().GetPolicy(cmPolicies::CMP0026)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0026) << "\n";
+ modal = "should";
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ modal = "may";
+ messageType = MessageType::FATAL_ERROR;
+ }
+
+ if (modal) {
+ e << "The LOCATION property " << modal << " not be read from target \""
+ << tgtName
+ << "\". Use the target name directly with "
+ "add_custom_command, or use the generator expression $<TARGET_FILE>, "
+ "as appropriate.\n";
+ messenger->IssueMessage(messageType, e.str(), context);
+ }
+
+ return messageType != MessageType::FATAL_ERROR;
+}
diff --git a/Source/cmTargetPropertyComputer.h b/Source/cmTargetPropertyComputer.h
new file mode 100644
index 0000000..f2be318
--- /dev/null
+++ b/Source/cmTargetPropertyComputer.h
@@ -0,0 +1,102 @@
+/* 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 <string>
+
+#include "cmListFileCache.h"
+#include "cmProperty.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+class cmMessenger;
+
+class cmTargetPropertyComputer
+{
+public:
+ template <typename Target>
+ static cmProp GetProperty(Target const* tgt, const std::string& prop,
+ cmMessenger* messenger,
+ cmListFileBacktrace const& context)
+ {
+ if (cmProp loc = GetLocation(tgt, prop, messenger, context)) {
+ return loc;
+ }
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ return nullptr;
+ }
+ if (prop == "SOURCES") {
+ return GetSources(tgt, messenger, context);
+ }
+ return nullptr;
+ }
+
+private:
+ static bool HandleLocationPropertyPolicy(std::string const& tgtName,
+ cmMessenger* messenger,
+ cmListFileBacktrace const& context);
+
+ template <typename Target>
+ static const std::string& ComputeLocationForBuild(Target const* tgt);
+ template <typename Target>
+ static const std::string& ComputeLocation(Target const* tgt,
+ std::string const& config);
+
+ template <typename Target>
+ static cmProp GetLocation(Target const* tgt, std::string const& prop,
+ cmMessenger* messenger,
+ cmListFileBacktrace const& context)
+
+ {
+ // Watch for special "computed" properties that are dependent on
+ // other properties or variables. Always recompute them.
+ if (tgt->GetType() == cmStateEnums::EXECUTABLE ||
+ tgt->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ tgt->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ tgt->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ tgt->GetType() == cmStateEnums::UNKNOWN_LIBRARY) {
+ static const std::string propLOCATION = "LOCATION";
+ if (prop == propLOCATION) {
+ if (!tgt->IsImported() &&
+ !HandleLocationPropertyPolicy(tgt->GetName(), messenger,
+ context)) {
+ return nullptr;
+ }
+ return &ComputeLocationForBuild(tgt);
+ }
+
+ // Support "LOCATION_<CONFIG>".
+ if (cmHasLiteralPrefix(prop, "LOCATION_")) {
+ if (!tgt->IsImported() &&
+ !HandleLocationPropertyPolicy(tgt->GetName(), messenger,
+ context)) {
+ return nullptr;
+ }
+ std::string configName = prop.substr(9);
+ return &ComputeLocation(tgt, configName);
+ }
+
+ // Support "<CONFIG>_LOCATION".
+ if (cmHasLiteralSuffix(prop, "_LOCATION") &&
+ !cmHasLiteralPrefix(prop, "XCODE_ATTRIBUTE_")) {
+ std::string configName(prop.c_str(), prop.size() - 9);
+ if (configName != "IMPORTED") {
+ if (!tgt->IsImported() &&
+ !HandleLocationPropertyPolicy(tgt->GetName(), messenger,
+ context)) {
+ return nullptr;
+ }
+ return &ComputeLocation(tgt, configName);
+ }
+ }
+ }
+ return nullptr;
+ }
+
+ template <typename Target>
+ static cmProp GetSources(Target const* tgt, cmMessenger* messenger,
+ cmListFileBacktrace const& context);
+};
diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx
new file mode 100644
index 0000000..26282ef
--- /dev/null
+++ b/Source/cmTargetSourcesCommand.cxx
@@ -0,0 +1,138 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTargetSourcesCommand.h"
+
+#include <sstream>
+
+#include "cmGeneratorExpression.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetPropCommandBase.h"
+
+namespace {
+
+class TargetSourcesImpl : public cmTargetPropCommandBase
+{
+public:
+ using cmTargetPropCommandBase::cmTargetPropCommandBase;
+
+protected:
+ void HandleInterfaceContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) override
+ {
+ this->cmTargetPropCommandBase::HandleInterfaceContent(
+ tgt, this->ConvertToAbsoluteContent(tgt, content, true), prepend,
+ system);
+ }
+
+private:
+ void HandleMissingTarget(const std::string& name) override
+ {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Cannot specify sources for target \"", name,
+ "\" which is not built by this project."));
+ }
+
+ bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool /*prepend*/, bool /*system*/) override
+ {
+ tgt->AppendProperty(
+ "SOURCES",
+ this->Join(this->ConvertToAbsoluteContent(tgt, content, false)));
+ return true; // Successfully handled.
+ }
+
+ std::string Join(const std::vector<std::string>& content) override
+ {
+ return cmJoin(content, ";");
+ }
+
+ std::vector<std::string> ConvertToAbsoluteContent(
+ cmTarget* tgt, const std::vector<std::string>& content,
+ bool isInterfaceContent);
+};
+
+std::vector<std::string> TargetSourcesImpl::ConvertToAbsoluteContent(
+ cmTarget* tgt, const std::vector<std::string>& content,
+ bool isInterfaceContent)
+{
+ // Skip conversion in case old behavior has been explicitly requested
+ if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0076) ==
+ cmPolicies::OLD) {
+ return content;
+ }
+
+ bool changedPath = false;
+ std::vector<std::string> absoluteContent;
+ absoluteContent.reserve(content.size());
+ for (std::string const& src : content) {
+ std::string absoluteSrc;
+ if (cmSystemTools::FileIsFullPath(src) ||
+ cmGeneratorExpression::Find(src) == 0 ||
+ (!isInterfaceContent &&
+ (this->Makefile->GetCurrentSourceDirectory() ==
+ tgt->GetMakefile()->GetCurrentSourceDirectory()))) {
+ absoluteSrc = src;
+ } else {
+ changedPath = true;
+ absoluteSrc =
+ cmStrCat(this->Makefile->GetCurrentSourceDirectory(), '/', src);
+ }
+ absoluteContent.push_back(absoluteSrc);
+ }
+
+ if (!changedPath) {
+ return content;
+ }
+
+ bool issueMessage = true;
+ bool useAbsoluteContent = false;
+ std::ostringstream e;
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0076)) {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0076) << "\n";
+ break;
+ case cmPolicies::OLD:
+ issueMessage = false;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0076));
+ break;
+ case cmPolicies::NEW: {
+ issueMessage = false;
+ useAbsoluteContent = true;
+ break;
+ }
+ }
+
+ if (issueMessage) {
+ if (isInterfaceContent) {
+ e << "An interface source of target \"" << tgt->GetName()
+ << "\" has a relative path.";
+ } else {
+ e << "A private source from a directory other than that of target \""
+ << tgt->GetName() << "\" has a relative path.";
+ }
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+ }
+
+ return useAbsoluteContent ? absoluteContent : content;
+}
+
+} // namespace
+
+bool cmTargetSourcesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return TargetSourcesImpl(status).HandleArguments(args, "SOURCES");
+}
diff --git a/Source/cmTargetSourcesCommand.h b/Source/cmTargetSourcesCommand.h
new file mode 100644
index 0000000..306226c
--- /dev/null
+++ b/Source/cmTargetSourcesCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmTargetSourcesCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx
new file mode 100644
index 0000000..a26bef3
--- /dev/null
+++ b/Source/cmTest.cxx
@@ -0,0 +1,75 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTest.h"
+
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+
+cmTest::cmTest(cmMakefile* mf)
+ : CommandExpandLists(false)
+ , Backtrace(mf->GetBacktrace())
+{
+ this->Makefile = mf;
+ this->OldStyle = true;
+}
+
+cmTest::~cmTest() = default;
+
+cmListFileBacktrace const& cmTest::GetBacktrace() const
+{
+ return this->Backtrace;
+}
+
+void cmTest::SetName(const std::string& name)
+{
+ this->Name = name;
+}
+
+void cmTest::SetCommand(std::vector<std::string> const& command)
+{
+ this->Command = command;
+}
+
+const char* cmTest::GetProperty(const std::string& prop) const
+{
+ cmProp retVal = this->Properties.GetPropertyValue(prop);
+ if (!retVal) {
+ const bool chain =
+ this->Makefile->GetState()->IsPropertyChained(prop, cmProperty::TEST);
+ if (chain) {
+ if (cmProp p = this->Makefile->GetProperty(prop, chain)) {
+ return p->c_str();
+ }
+ }
+ return nullptr;
+ }
+ return retVal->c_str();
+}
+
+bool cmTest::GetPropertyAsBool(const std::string& prop) const
+{
+ return cmIsOn(this->GetProperty(prop));
+}
+
+void cmTest::SetProperty(const std::string& prop, const char* value)
+{
+ this->Properties.SetProperty(prop, value);
+}
+
+void cmTest::AppendProperty(const std::string& prop, const std::string& value,
+ bool asString)
+{
+ this->Properties.AppendProperty(prop, value, asString);
+}
+
+bool cmTest::GetCommandExpandLists() const
+{
+ return this->CommandExpandLists;
+}
+
+void cmTest::SetCommandExpandLists(bool b)
+{
+ this->CommandExpandLists = b;
+}
diff --git a/Source/cmTest.h b/Source/cmTest.h
new file mode 100644
index 0000000..f33b7e2
--- /dev/null
+++ b/Source/cmTest.h
@@ -0,0 +1,67 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmListFileCache.h"
+#include "cmPropertyMap.h"
+
+class cmMakefile;
+
+/** \class cmTest
+ * \brief Represent a test
+ *
+ * cmTest is representation of a test.
+ */
+class cmTest
+{
+public:
+ /**
+ */
+ cmTest(cmMakefile* mf);
+ ~cmTest();
+
+ //! Set the test name
+ void SetName(const std::string& name);
+ std::string GetName() const { return this->Name; }
+
+ void SetCommand(std::vector<std::string> const& command);
+ std::vector<std::string> const& GetCommand() const { return this->Command; }
+
+ //! Set/Get a property of this source file
+ void SetProperty(const std::string& prop, const char* value);
+ void AppendProperty(const std::string& prop, const std::string& value,
+ bool asString = false);
+ const char* GetProperty(const std::string& prop) const;
+ bool GetPropertyAsBool(const std::string& prop) const;
+ cmPropertyMap& GetProperties() { return this->Properties; }
+
+ /** Get the cmMakefile instance that owns this test. */
+ cmMakefile* GetMakefile() { return this->Makefile; }
+
+ /** Get the backtrace of the command that created this test. */
+ cmListFileBacktrace const& GetBacktrace() const;
+
+ /** Get/Set whether this is an old-style test. */
+ bool GetOldStyle() const { return this->OldStyle; }
+ void SetOldStyle(bool b) { this->OldStyle = b; }
+
+ /** Set/Get whether lists in command lines should be expanded. */
+ bool GetCommandExpandLists() const;
+ void SetCommandExpandLists(bool b);
+
+private:
+ cmPropertyMap Properties;
+ std::string Name;
+ std::vector<std::string> Command;
+ bool CommandExpandLists;
+
+ bool OldStyle;
+
+ cmMakefile* Makefile;
+ cmListFileBacktrace Backtrace;
+};
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
new file mode 100644
index 0000000..7022c4e
--- /dev/null
+++ b/Source/cmTestGenerator.cxx
@@ -0,0 +1,334 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTestGenerator.h"
+
+#include <algorithm>
+#include <cstddef> // IWYU pragma: keep
+#include <iterator>
+#include <memory>
+#include <ostream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmPolicies.h"
+#include "cmProperty.h"
+#include "cmPropertyMap.h"
+#include "cmRange.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTest.h"
+
+namespace /* anonymous */
+{
+
+bool needToQuoteTestName(const cmMakefile& mf, const std::string& name)
+{
+ // Determine if policy CMP0110 is set to NEW.
+ switch (mf.GetPolicyStatus(cmPolicies::CMP0110)) {
+ case cmPolicies::WARN:
+ // Only warn if a forbidden character is used in the name.
+ if (name.find_first_of("$[] #;\t\n\"\\") != std::string::npos) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0110),
+ "\nThe following name given to add_test() is invalid if "
+ "CMP0110 is not set or set to OLD:\n `",
+ name, "´\n"));
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior is to not quote the test's name.
+ return false;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ default:
+ // NEW behavior is to quote the test's name.
+ return true;
+ }
+}
+
+std::size_t countMaxConsecutiveEqualSigns(const std::string& name)
+{
+ std::size_t max = 0;
+ auto startIt = find(name.begin(), name.end(), '=');
+ auto endIt = startIt;
+ for (; startIt != name.end(); startIt = find(endIt, name.end(), '=')) {
+ endIt =
+ find_if_not(startIt + 1, name.end(), [](char c) { return c == '='; });
+ max =
+ std::max(max, static_cast<std::size_t>(std::distance(startIt, endIt)));
+ }
+ return max;
+}
+
+} // End: anonymous namespace
+
+cmTestGenerator::cmTestGenerator(
+ cmTest* test, std::vector<std::string> const& configurations)
+ : cmScriptGenerator("CTEST_CONFIGURATION_TYPE", configurations)
+ , Test(test)
+{
+ this->ActionsPerConfig = !test->GetOldStyle();
+ this->TestGenerated = false;
+ this->LG = nullptr;
+}
+
+cmTestGenerator::~cmTestGenerator() = default;
+
+void cmTestGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LG = lg;
+}
+
+bool cmTestGenerator::TestsForConfig(const std::string& config)
+{
+ return this->GeneratesForConfig(config);
+}
+
+cmTest* cmTestGenerator::GetTest() const
+{
+ return this->Test;
+}
+
+void cmTestGenerator::GenerateScriptConfigs(std::ostream& os, Indent indent)
+{
+ // Create the tests.
+ this->cmScriptGenerator::GenerateScriptConfigs(os, indent);
+}
+
+void cmTestGenerator::GenerateScriptActions(std::ostream& os, Indent indent)
+{
+ if (this->ActionsPerConfig) {
+ // This is the per-config generation in a single-configuration
+ // build generator case. The superclass will call our per-config
+ // method.
+ this->cmScriptGenerator::GenerateScriptActions(os, indent);
+ } else {
+ // This is an old-style test, so there is only one config.
+ // assert(this->Test->GetOldStyle());
+ this->GenerateOldStyle(os, indent);
+ }
+}
+
+void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
+ const std::string& config,
+ Indent indent)
+{
+ this->TestGenerated = true;
+
+ // Set up generator expression evaluation context.
+ cmGeneratorExpression ge(this->Test->GetBacktrace());
+
+ // Determine if policy CMP0110 is set to NEW.
+ const bool quote_test_name =
+ needToQuoteTestName(*this->Test->GetMakefile(), this->Test->GetName());
+ // Determine the number of equal-signs needed for quoting test name with
+ // [==[...]==] syntax.
+ const std::string equalSigns(
+ 1 + countMaxConsecutiveEqualSigns(this->Test->GetName()), '=');
+
+ // Start the test command.
+ if (quote_test_name) {
+ os << indent << "add_test([" << equalSigns << "[" << this->Test->GetName()
+ << "]" << equalSigns << "] ";
+ } else {
+ os << indent << "add_test(" << this->Test->GetName() << " ";
+ }
+
+ // Evaluate command line arguments
+ std::vector<std::string> argv =
+ this->EvaluateCommandLineArguments(this->Test->GetCommand(), ge, config);
+
+ // Expand arguments if COMMAND_EXPAND_LISTS is set
+ if (this->Test->GetCommandExpandLists()) {
+ argv = cmExpandedLists(argv.begin(), argv.end());
+ // Expanding lists on an empty command may have left it empty
+ if (argv.empty()) {
+ argv.emplace_back();
+ }
+ }
+
+ // Check whether the command executable is a target whose name is to
+ // be translated.
+ std::string exe = argv[0];
+ cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(exe);
+ if (target && target->GetType() == cmStateEnums::EXECUTABLE) {
+ // Use the target file on disk.
+ exe = target->GetFullPath(config);
+
+ // Prepend with the emulator when cross compiling if required.
+ cmProp emulator = target->GetProperty("CROSSCOMPILING_EMULATOR");
+ if (cmNonempty(emulator)) {
+ std::vector<std::string> emulatorWithArgs = cmExpandedList(*emulator);
+ std::string emulatorExe(emulatorWithArgs[0]);
+ cmSystemTools::ConvertToUnixSlashes(emulatorExe);
+ os << cmOutputConverter::EscapeForCMake(emulatorExe) << " ";
+ for (std::string const& arg : cmMakeRange(emulatorWithArgs).advance(1)) {
+ os << cmOutputConverter::EscapeForCMake(arg) << " ";
+ }
+ }
+ } else {
+ // Use the command name given.
+ cmSystemTools::ConvertToUnixSlashes(exe);
+ }
+
+ // Generate the command line with full escapes.
+ os << cmOutputConverter::EscapeForCMake(exe);
+
+ for (auto const& arg : cmMakeRange(argv).advance(1)) {
+ os << " " << cmOutputConverter::EscapeForCMake(arg);
+ }
+
+ // Finish the test command.
+ os << ")\n";
+
+ // Output properties for the test.
+ if (quote_test_name) {
+ os << indent << "set_tests_properties([" << equalSigns << "["
+ << this->Test->GetName() << "]" << equalSigns << "] PROPERTIES ";
+ } else {
+ os << indent << "set_tests_properties(" << this->Test->GetName()
+ << " PROPERTIES ";
+ }
+ for (auto const& i : this->Test->GetProperties().GetList()) {
+ os << " " << i.first << " "
+ << cmOutputConverter::EscapeForCMake(
+ ge.Parse(i.second)->Evaluate(this->LG, config));
+ }
+ this->GenerateInternalProperties(os);
+ os << ")\n";
+}
+
+void cmTestGenerator::GenerateScriptNoConfig(std::ostream& os, Indent indent)
+{
+ // Determine if policy CMP0110 is set to NEW.
+ const bool quote_test_name =
+ needToQuoteTestName(*this->Test->GetMakefile(), this->Test->GetName());
+ // Determine the number of equal-signs needed for quoting test name with
+ // [==[...]==] syntax.
+ const std::string equalSigns(
+ 1 + countMaxConsecutiveEqualSigns(this->Test->GetName()), '=');
+
+ if (quote_test_name) {
+ os << indent << "add_test([" << equalSigns << "[" << this->Test->GetName()
+ << "]" << equalSigns << "] NOT_AVAILABLE)\n";
+ } else {
+ os << indent << "add_test(" << this->Test->GetName()
+ << " NOT_AVAILABLE)\n";
+ }
+}
+
+bool cmTestGenerator::NeedsScriptNoConfig() const
+{
+ return (this->TestGenerated && // test generated for at least one config
+ this->ActionsPerConfig && // test is config-aware
+ this->Configurations.empty() && // test runs in all configs
+ !this->ConfigurationTypes->empty()); // config-dependent command
+}
+
+void cmTestGenerator::GenerateOldStyle(std::ostream& fout, Indent indent)
+{
+ this->TestGenerated = true;
+
+ // Determine if policy CMP0110 is set to NEW.
+ const bool quote_test_name =
+ needToQuoteTestName(*this->Test->GetMakefile(), this->Test->GetName());
+ // Determine the number of equal-signs needed for quoting test name with
+ // [==[...]==] syntax.
+ const std::string equalSigns(
+ 1 + countMaxConsecutiveEqualSigns(this->Test->GetName()), '=');
+
+ // Get the test command line to be executed.
+ std::vector<std::string> const& command = this->Test->GetCommand();
+
+ std::string exe = command[0];
+ cmSystemTools::ConvertToUnixSlashes(exe);
+ if (quote_test_name) {
+ fout << indent << "add_test([" << equalSigns << "["
+ << this->Test->GetName() << "]" << equalSigns << "] \"" << exe
+ << "\"";
+ } else {
+ fout << indent << "add_test(" << this->Test->GetName() << " \"" << exe
+ << "\"";
+ }
+
+ for (std::string const& arg : cmMakeRange(command).advance(1)) {
+ // Just double-quote all arguments so they are re-parsed
+ // correctly by the test system.
+ fout << " \"";
+ for (char c : arg) {
+ // Escape quotes within arguments. We should escape
+ // backslashes too but we cannot because it makes the result
+ // inconsistent with previous behavior of this command.
+ if (c == '"') {
+ fout << '\\';
+ }
+ fout << c;
+ }
+ fout << '"';
+ }
+ fout << ")\n";
+
+ // Output properties for the test.
+ if (quote_test_name) {
+ fout << indent << "set_tests_properties([" << equalSigns << "["
+ << this->Test->GetName() << "]" << equalSigns << "] PROPERTIES ";
+ } else {
+ fout << indent << "set_tests_properties(" << this->Test->GetName()
+ << " PROPERTIES ";
+ }
+ for (auto const& i : this->Test->GetProperties().GetList()) {
+ fout << " " << i.first << " "
+ << cmOutputConverter::EscapeForCMake(i.second);
+ }
+ this->GenerateInternalProperties(fout);
+ fout << ")\n";
+}
+
+void cmTestGenerator::GenerateInternalProperties(std::ostream& os)
+{
+ cmListFileBacktrace bt = this->Test->GetBacktrace();
+ if (bt.Empty()) {
+ return;
+ }
+
+ os << " "
+ << "_BACKTRACE_TRIPLES"
+ << " \"";
+
+ bool prependTripleSeparator = false;
+ while (!bt.Empty()) {
+ const auto& entry = bt.Top();
+ if (prependTripleSeparator) {
+ os << ";";
+ }
+ os << entry.FilePath << ";" << entry.Line << ";" << entry.Name;
+ bt = bt.Pop();
+ prependTripleSeparator = true;
+ }
+
+ os << '"';
+}
+
+std::vector<std::string> cmTestGenerator::EvaluateCommandLineArguments(
+ const std::vector<std::string>& argv, cmGeneratorExpression& ge,
+ const std::string& config) const
+{
+ // Evaluate executable name and arguments
+ auto evaluatedRange =
+ cmMakeRange(argv).transform([&](const std::string& arg) {
+ return ge.Parse(arg)->Evaluate(this->LG, config);
+ });
+
+ return { evaluatedRange.begin(), evaluatedRange.end() };
+}
diff --git a/Source/cmTestGenerator.h b/Source/cmTestGenerator.h
new file mode 100644
index 0000000..6903140
--- /dev/null
+++ b/Source/cmTestGenerator.h
@@ -0,0 +1,57 @@
+/* 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 <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmScriptGenerator.h"
+
+class cmGeneratorExpression;
+class cmLocalGenerator;
+class cmTest;
+
+/** \class cmTestGenerator
+ * \brief Support class for generating install scripts.
+ *
+ */
+class cmTestGenerator : public cmScriptGenerator
+{
+public:
+ cmTestGenerator(cmTest* test,
+ std::vector<std::string> const& configurations =
+ std::vector<std::string>());
+ ~cmTestGenerator() override;
+
+ cmTestGenerator(cmTestGenerator const&) = delete;
+ cmTestGenerator& operator=(cmTestGenerator const&) = delete;
+
+ void Compute(cmLocalGenerator* lg);
+
+ /** Test if this generator installs the test for a given configuration. */
+ bool TestsForConfig(const std::string& config);
+
+ cmTest* GetTest() const;
+
+private:
+ void GenerateInternalProperties(std::ostream& os);
+ std::vector<std::string> EvaluateCommandLineArguments(
+ const std::vector<std::string>& argv, cmGeneratorExpression& ge,
+ const std::string& config) const;
+
+protected:
+ void GenerateScriptConfigs(std::ostream& os, Indent indent) override;
+ void GenerateScriptActions(std::ostream& os, Indent indent) override;
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent indent) override;
+ void GenerateScriptNoConfig(std::ostream& os, Indent indent) override;
+ bool NeedsScriptNoConfig() const override;
+ void GenerateOldStyle(std::ostream& os, Indent indent);
+
+ cmLocalGenerator* LG;
+ cmTest* Test;
+ bool TestGenerated;
+};
diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx
new file mode 100644
index 0000000..056696d
--- /dev/null
+++ b/Source/cmTimestamp.cxx
@@ -0,0 +1,196 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#if !defined(_WIN32) && !defined(__sun) && !defined(__OpenBSD__)
+// POSIX APIs are needed
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
+# define _POSIX_C_SOURCE 200809L
+#endif
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__QNX__)
+// For isascii
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
+# define _XOPEN_SOURCE 700
+#endif
+
+#include "cmTimestamp.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <sstream>
+
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+std::string cmTimestamp::CurrentTime(const std::string& formatString,
+ bool utcFlag) const
+{
+ time_t currentTimeT = time(nullptr);
+ std::string source_date_epoch;
+ cmSystemTools::GetEnv("SOURCE_DATE_EPOCH", source_date_epoch);
+ if (!source_date_epoch.empty()) {
+ std::istringstream iss(source_date_epoch);
+ iss >> currentTimeT;
+ if (iss.fail() || !iss.eof()) {
+ cmSystemTools::Error("Cannot parse SOURCE_DATE_EPOCH as integer");
+ exit(27);
+ }
+ }
+ if (currentTimeT == time_t(-1)) {
+ return std::string();
+ }
+
+ return this->CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag);
+}
+
+std::string cmTimestamp::FileModificationTime(const char* path,
+ const std::string& formatString,
+ bool utcFlag) const
+{
+ std::string real_path =
+ cmSystemTools::GetRealPathResolvingWindowsSubst(path);
+
+ if (!cmsys::SystemTools::FileExists(real_path)) {
+ return std::string();
+ }
+
+ time_t mtime = cmsys::SystemTools::ModifiedTime(real_path);
+ return this->CreateTimestampFromTimeT(mtime, formatString, utcFlag);
+}
+
+std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
+ std::string formatString,
+ bool utcFlag) const
+{
+ if (formatString.empty()) {
+ formatString = "%Y-%m-%dT%H:%M:%S";
+ if (utcFlag) {
+ formatString += "Z";
+ }
+ }
+
+ struct tm timeStruct;
+ memset(&timeStruct, 0, sizeof(timeStruct));
+
+ struct tm* ptr = nullptr;
+ if (utcFlag) {
+ ptr = gmtime(&timeT);
+ } else {
+ ptr = localtime(&timeT);
+ }
+
+ if (ptr == nullptr) {
+ return std::string();
+ }
+
+ timeStruct = *ptr;
+
+ std::string result;
+ for (std::string::size_type i = 0; i < formatString.size(); ++i) {
+ char c1 = formatString[i];
+ char c2 = (i + 1 < formatString.size()) ? formatString[i + 1]
+ : static_cast<char>(0);
+
+ if (c1 == '%' && c2 != 0) {
+ result += this->AddTimestampComponent(c2, timeStruct, timeT);
+ ++i;
+ } else {
+ result += c1;
+ }
+ }
+
+ return result;
+}
+
+time_t cmTimestamp::CreateUtcTimeTFromTm(struct tm& tm) const
+{
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ return _mkgmtime(&tm);
+#else
+ // From Linux timegm() manpage.
+
+ std::string tz_old;
+ bool const tz_was_set = cmSystemTools::GetEnv("TZ", tz_old);
+ tz_old = "TZ=" + tz_old;
+
+ // The standard says that "TZ=" or "TZ=[UNRECOGNIZED_TZ]" means UTC.
+ // It seems that "TZ=" does NOT work, at least under Windows
+ // with neither MSVC nor MinGW, so let's use explicit "TZ=UTC"
+
+ cmSystemTools::PutEnv("TZ=UTC");
+
+ tzset();
+
+ time_t result = mktime(&tm);
+
+# ifndef CMAKE_BOOTSTRAP
+ if (tz_was_set) {
+ cmSystemTools::PutEnv(tz_old);
+ } else {
+ cmSystemTools::UnsetEnv("TZ");
+ }
+# else
+ // No UnsetEnv during bootstrap. This is good enough for CMake itself.
+ cmSystemTools::PutEnv(tz_old);
+ static_cast<void>(tz_was_set);
+# endif
+
+ tzset();
+
+ return result;
+#endif
+}
+
+std::string cmTimestamp::AddTimestampComponent(char flag,
+ struct tm& timeStruct,
+ const time_t timeT) const
+{
+ std::string formatString = cmStrCat('%', flag);
+
+ switch (flag) {
+ case 'a':
+ case 'A':
+ case 'b':
+ case 'B':
+ case 'd':
+ case 'H':
+ case 'I':
+ case 'j':
+ case 'm':
+ case 'M':
+ case 'S':
+ case 'U':
+ case 'w':
+ case 'y':
+ case 'Y':
+ case '%':
+ break;
+ case 's': // Seconds since UNIX epoch (midnight 1-jan-1970)
+ {
+ // Build a time_t for UNIX epoch and subtract from the input "timeT":
+ struct tm tmUnixEpoch;
+ memset(&tmUnixEpoch, 0, sizeof(tmUnixEpoch));
+ tmUnixEpoch.tm_mday = 1;
+ tmUnixEpoch.tm_year = 1970 - 1900;
+
+ const time_t unixEpoch = this->CreateUtcTimeTFromTm(tmUnixEpoch);
+ if (unixEpoch == -1) {
+ cmSystemTools::Error(
+ "Error generating UNIX epoch in "
+ "STRING(TIMESTAMP ...). Please, file a bug report against CMake");
+ return std::string();
+ }
+
+ return std::to_string(static_cast<long int>(difftime(timeT, unixEpoch)));
+ }
+ default: {
+ return formatString;
+ }
+ }
+
+ char buffer[16];
+
+ size_t size =
+ strftime(buffer, sizeof(buffer), formatString.c_str(), &timeStruct);
+
+ return std::string(buffer, size);
+}
diff --git a/Source/cmTimestamp.h b/Source/cmTimestamp.h
new file mode 100644
index 0000000..0e2c200
--- /dev/null
+++ b/Source/cmTimestamp.h
@@ -0,0 +1,31 @@
+/* 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 <ctime>
+#include <string>
+
+/** \class cmTimestamp
+ * \brief Utility class to generate string representation of a timestamp
+ *
+ */
+class cmTimestamp
+{
+public:
+ std::string CurrentTime(const std::string& formatString, bool utcFlag) const;
+
+ std::string FileModificationTime(const char* path,
+ const std::string& formatString,
+ bool utcFlag) const;
+
+ std::string CreateTimestampFromTimeT(time_t timeT, std::string formatString,
+ bool utcFlag) const;
+
+private:
+ time_t CreateUtcTimeTFromTm(struct tm& timeStruct) const;
+
+ std::string AddTimestampComponent(char flag, struct tm& timeStruct,
+ time_t timeT) const;
+};
diff --git a/Source/cmTransformDepfile.cxx b/Source/cmTransformDepfile.cxx
new file mode 100644
index 0000000..78aa4b2
--- /dev/null
+++ b/Source/cmTransformDepfile.cxx
@@ -0,0 +1,122 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTransformDepfile.h"
+
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmGccDepfileReader.h"
+#include "cmGccDepfileReaderTypes.h"
+#include "cmLocalGenerator.h"
+#include "cmSystemTools.h"
+
+namespace {
+void WriteFilenameGcc(cmsys::ofstream& fout, const std::string& filename)
+{
+ for (auto c : filename) {
+ switch (c) {
+ case ' ':
+ fout << "\\ ";
+ break;
+ case '\\':
+ fout << "\\\\";
+ break;
+ default:
+ fout << c;
+ break;
+ }
+ }
+}
+
+void WriteGccDepfile(cmsys::ofstream& fout, const cmLocalGenerator& lg,
+ const cmGccDepfileContent& content)
+{
+ const auto& binDir = lg.GetBinaryDirectory();
+
+ for (auto const& dep : content) {
+ bool first = true;
+ for (auto const& rule : dep.rules) {
+ if (!first) {
+ fout << " \\\n ";
+ }
+ first = false;
+ WriteFilenameGcc(fout, lg.MaybeConvertToRelativePath(binDir, rule));
+ }
+ fout << ':';
+ for (auto const& path : dep.paths) {
+ fout << " \\\n ";
+ WriteFilenameGcc(fout, lg.MaybeConvertToRelativePath(binDir, path));
+ }
+ fout << '\n';
+ }
+}
+
+// tlog format : always windows paths on Windows regardless the generator
+std::string ConvertToTLogOutputPath(const std::string& path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ return cmSystemTools::ConvertToWindowsOutputPath(path);
+#else
+ return cmSystemTools::ConvertToOutputPath(path);
+#endif
+}
+
+void WriteVsTlog(cmsys::ofstream& fout, const cmLocalGenerator& lg,
+ const cmGccDepfileContent& content)
+{
+ const auto& binDir = lg.GetBinaryDirectory();
+
+ for (auto const& dep : content) {
+ fout << '^';
+ bool first = true;
+ for (auto const& rule : dep.rules) {
+ if (!first) {
+ fout << '|';
+ }
+ first = false;
+ fout << ConvertToTLogOutputPath(
+ lg.MaybeConvertToRelativePath(binDir, rule));
+ }
+ fout << "\r\n";
+ for (auto const& path : dep.paths) {
+ fout << ConvertToTLogOutputPath(
+ lg.MaybeConvertToRelativePath(binDir, path))
+ << "\r\n";
+ }
+ }
+}
+}
+
+bool cmTransformDepfile(cmDepfileFormat format, const cmLocalGenerator& lg,
+ const std::string& infile, const std::string& outfile)
+{
+ cmGccDepfileContent content;
+ if (cmSystemTools::FileExists(infile)) {
+ auto result =
+ cmReadGccDepfile(infile.c_str(), lg.GetCurrentBinaryDirectory());
+ if (!result) {
+ return false;
+ }
+ content = *std::move(result);
+ }
+
+ cmsys::ofstream fout(outfile.c_str());
+ if (!fout) {
+ return false;
+ }
+ switch (format) {
+ case cmDepfileFormat::GccDepfile:
+ WriteGccDepfile(fout, lg, content);
+ break;
+ case cmDepfileFormat::VsTlog:
+ WriteVsTlog(fout, lg, content);
+ break;
+ }
+ return true;
+}
diff --git a/Source/cmTransformDepfile.h b/Source/cmTransformDepfile.h
new file mode 100644
index 0000000..c43a45f
--- /dev/null
+++ b/Source/cmTransformDepfile.h
@@ -0,0 +1,16 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+
+enum class cmDepfileFormat
+{
+ GccDepfile,
+ VsTlog,
+};
+
+class cmLocalGenerator;
+
+bool cmTransformDepfile(cmDepfileFormat format, const cmLocalGenerator& lg,
+ const std::string& infile, const std::string& outfile);
diff --git a/Source/cmTryCompileCommand.cxx b/Source/cmTryCompileCommand.cxx
new file mode 100644
index 0000000..05b3f05
--- /dev/null
+++ b/Source/cmTryCompileCommand.cxx
@@ -0,0 +1,36 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTryCompileCommand.h"
+
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmake.h"
+
+class cmExecutionStatus;
+
+// cmTryCompileCommand
+bool cmTryCompileCommand::InitialPass(std::vector<std::string> const& argv,
+ cmExecutionStatus&)
+{
+ if (argv.size() < 3) {
+ return false;
+ }
+
+ if (this->Makefile->GetCMakeInstance()->GetWorkingMode() ==
+ cmake::FIND_PACKAGE_MODE) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "The TRY_COMPILE() command is not supported in --find-package mode.");
+ return false;
+ }
+
+ this->TryCompileCode(argv, false);
+
+ // if They specified clean then we clean up what we can
+ if (this->SrcFileSignature) {
+ if (!this->Makefile->GetCMakeInstance()->GetDebugTryCompile()) {
+ this->CleanupFiles(this->BinaryDirectory);
+ }
+ }
+ return true;
+}
diff --git a/Source/cmTryCompileCommand.h b/Source/cmTryCompileCommand.h
new file mode 100644
index 0000000..d8cc16e
--- /dev/null
+++ b/Source/cmTryCompileCommand.h
@@ -0,0 +1,39 @@
+/* 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 <string>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmCommand.h"
+#include "cmCoreTryCompile.h"
+
+class cmExecutionStatus;
+
+/** \class cmTryCompileCommand
+ * \brief Specifies where to install some files
+ *
+ * cmTryCompileCommand is used to test if source code can be compiled
+ */
+class cmTryCompileCommand : public cmCoreTryCompile
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ return cm::make_unique<cmTryCompileCommand>();
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) override;
+};
diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx
new file mode 100644
index 0000000..8cac74d
--- /dev/null
+++ b/Source/cmTryRunCommand.cxx
@@ -0,0 +1,376 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTryRunCommand.h"
+
+#include <cstdio>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmDuration.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmRange.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+class cmExecutionStatus;
+
+// cmTryRunCommand
+bool cmTryRunCommand::InitialPass(std::vector<std::string> const& argv,
+ cmExecutionStatus&)
+{
+ if (argv.size() < 4) {
+ return false;
+ }
+
+ if (this->Makefile->GetCMakeInstance()->GetWorkingMode() ==
+ cmake::FIND_PACKAGE_MODE) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "The TRY_RUN() command is not supported in --find-package mode.");
+ return false;
+ }
+
+ // build an arg list for TryCompile and extract the runArgs,
+ std::vector<std::string> tryCompile;
+
+ this->CompileResultVariable.clear();
+ this->RunResultVariable.clear();
+ this->OutputVariable.clear();
+ this->RunOutputVariable.clear();
+ this->CompileOutputVariable.clear();
+
+ std::string runArgs;
+ unsigned int i;
+ for (i = 1; i < argv.size(); ++i) {
+ if (argv[i] == "ARGS") {
+ ++i;
+ while (i < argv.size() && argv[i] != "COMPILE_DEFINITIONS" &&
+ argv[i] != "CMAKE_FLAGS" && argv[i] != "LINK_OPTIONS" &&
+ argv[i] != "LINK_LIBRARIES") {
+ runArgs += " ";
+ runArgs += argv[i];
+ ++i;
+ }
+ if (i < argv.size()) {
+ tryCompile.push_back(argv[i]);
+ }
+ } else {
+ if (argv[i] == "OUTPUT_VARIABLE") {
+ if (argv.size() <= (i + 1)) {
+ cmSystemTools::Error(
+ "OUTPUT_VARIABLE specified but there is no variable");
+ return false;
+ }
+ i++;
+ this->OutputVariable = argv[i];
+ } else if (argv[i] == "RUN_OUTPUT_VARIABLE") {
+ if (argv.size() <= (i + 1)) {
+ cmSystemTools::Error(
+ "RUN_OUTPUT_VARIABLE specified but there is no variable");
+ return false;
+ }
+ i++;
+ this->RunOutputVariable = argv[i];
+ } else if (argv[i] == "COMPILE_OUTPUT_VARIABLE") {
+ if (argv.size() <= (i + 1)) {
+ cmSystemTools::Error(
+ "COMPILE_OUTPUT_VARIABLE specified but there is no variable");
+ return false;
+ }
+ i++;
+ this->CompileOutputVariable = argv[i];
+ } else if (argv[i] == "WORKING_DIRECTORY") {
+ if (argv.size() <= (i + 1)) {
+ cmSystemTools::Error(
+ "WORKING_DIRECTORY specified but there is no variable");
+ return false;
+ }
+ i++;
+ this->WorkingDirectory = argv[i];
+ } else {
+ tryCompile.push_back(argv[i]);
+ }
+ }
+ }
+
+ // although they could be used together, don't allow it, because
+ // using OUTPUT_VARIABLE makes crosscompiling harder
+ if (!this->OutputVariable.empty() &&
+ (!this->RunOutputVariable.empty() ||
+ !this->CompileOutputVariable.empty())) {
+ cmSystemTools::Error(
+ "You cannot use OUTPUT_VARIABLE together with COMPILE_OUTPUT_VARIABLE "
+ "or RUN_OUTPUT_VARIABLE. Please use only COMPILE_OUTPUT_VARIABLE and/or "
+ "RUN_OUTPUT_VARIABLE.");
+ return false;
+ }
+
+ if (!this->WorkingDirectory.empty()) {
+ if (!cmSystemTools::MakeDirectory(this->WorkingDirectory)) {
+ cmSystemTools::Error(cmStrCat("Error creating working directory \"",
+ this->WorkingDirectory, "\"."));
+ return false;
+ }
+ }
+
+ bool captureRunOutput = false;
+ if (!this->OutputVariable.empty()) {
+ captureRunOutput = true;
+ tryCompile.emplace_back("OUTPUT_VARIABLE");
+ tryCompile.push_back(this->OutputVariable);
+ }
+ if (!this->CompileOutputVariable.empty()) {
+ tryCompile.emplace_back("OUTPUT_VARIABLE");
+ tryCompile.push_back(this->CompileOutputVariable);
+ }
+ if (!this->RunOutputVariable.empty()) {
+ captureRunOutput = true;
+ }
+
+ this->RunResultVariable = argv[0];
+ this->CompileResultVariable = argv[1];
+
+ // do the try compile
+ int res = this->TryCompileCode(tryCompile, true);
+
+ // now try running the command if it compiled
+ if (!res) {
+ if (this->OutputFile.empty()) {
+ cmSystemTools::Error(this->FindErrorMessage);
+ } else {
+ // "run" it and capture the output
+ std::string runOutputContents;
+ if (this->Makefile->IsOn("CMAKE_CROSSCOMPILING") &&
+ !this->Makefile->IsDefinitionSet("CMAKE_CROSSCOMPILING_EMULATOR")) {
+ this->DoNotRunExecutable(
+ runArgs, argv[3], captureRunOutput ? &runOutputContents : nullptr);
+ } else {
+ this->RunExecutable(runArgs, &runOutputContents);
+ }
+
+ // now put the output into the variables
+ if (!this->RunOutputVariable.empty()) {
+ this->Makefile->AddDefinition(this->RunOutputVariable,
+ runOutputContents);
+ }
+
+ if (!this->OutputVariable.empty()) {
+ // if the TryCompileCore saved output in this outputVariable then
+ // prepend that output to this output
+ cmProp compileOutput =
+ this->Makefile->GetDefinition(this->OutputVariable);
+ if (compileOutput) {
+ runOutputContents = *compileOutput + runOutputContents;
+ }
+ this->Makefile->AddDefinition(this->OutputVariable, runOutputContents);
+ }
+ }
+ }
+
+ // if we created a directory etc, then cleanup after ourselves
+ if (!this->Makefile->GetCMakeInstance()->GetDebugTryCompile()) {
+ this->CleanupFiles(this->BinaryDirectory);
+ }
+ return true;
+}
+
+void cmTryRunCommand::RunExecutable(const std::string& runArgs,
+ std::string* out)
+{
+ int retVal = -1;
+
+ std::string finalCommand;
+ const std::string& emulator =
+ this->Makefile->GetSafeDefinition("CMAKE_CROSSCOMPILING_EMULATOR");
+ if (!emulator.empty()) {
+ std::vector<std::string> emulatorWithArgs = cmExpandedList(emulator);
+ finalCommand +=
+ cmSystemTools::ConvertToRunCommandPath(emulatorWithArgs[0]);
+ finalCommand += " ";
+ for (std::string const& arg : cmMakeRange(emulatorWithArgs).advance(1)) {
+ finalCommand += "\"";
+ finalCommand += arg;
+ finalCommand += "\"";
+ finalCommand += " ";
+ }
+ }
+ finalCommand += cmSystemTools::ConvertToRunCommandPath(this->OutputFile);
+ if (!runArgs.empty()) {
+ finalCommand += runArgs;
+ }
+ bool worked = cmSystemTools::RunSingleCommand(
+ finalCommand, out, out, &retVal,
+ this->WorkingDirectory.empty() ? nullptr : this->WorkingDirectory.c_str(),
+ cmSystemTools::OUTPUT_NONE, cmDuration::zero());
+ // set the run var
+ char retChar[16];
+ const char* retStr;
+ if (worked) {
+ sprintf(retChar, "%i", retVal);
+ retStr = retChar;
+ } else {
+ retStr = "FAILED_TO_RUN";
+ }
+ this->Makefile->AddCacheDefinition(this->RunResultVariable, retStr,
+ "Result of TRY_RUN",
+ cmStateEnums::INTERNAL);
+}
+
+/* This is only used when cross compiling. Instead of running the
+ executable, two cache variables are created which will hold the results
+ the executable would have produced.
+*/
+void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
+ const std::string& srcFile,
+ std::string* out)
+{
+ // copy the executable out of the CMakeFiles/ directory, so it is not
+ // removed at the end of TRY_RUN and the user can run it manually
+ // on the target platform.
+ std::string copyDest =
+ cmStrCat(this->Makefile->GetHomeOutputDirectory(), "/CMakeFiles/",
+ cmSystemTools::GetFilenameWithoutExtension(this->OutputFile), '-',
+ this->RunResultVariable,
+ cmSystemTools::GetFilenameExtension(this->OutputFile));
+ cmSystemTools::CopyFileAlways(this->OutputFile, copyDest);
+
+ std::string resultFileName =
+ cmStrCat(this->Makefile->GetHomeOutputDirectory(), "/TryRunResults.cmake");
+
+ std::string detailsString = cmStrCat("For details see ", resultFileName);
+
+ std::string internalRunOutputName =
+ this->RunResultVariable + "__TRYRUN_OUTPUT";
+ bool error = false;
+
+ if (!this->Makefile->GetDefinition(this->RunResultVariable)) {
+ // if the variables doesn't exist, create it with a helpful error text
+ // and mark it as advanced
+ std::string comment =
+ cmStrCat("Run result of TRY_RUN(), indicates whether the executable "
+ "would have been able to run on its target platform.\n",
+ detailsString);
+ this->Makefile->AddCacheDefinition(this->RunResultVariable,
+ "PLEASE_FILL_OUT-FAILED_TO_RUN",
+ comment.c_str(), cmStateEnums::STRING);
+
+ cmState* state = this->Makefile->GetState();
+ cmProp existingValue = state->GetCacheEntryValue(this->RunResultVariable);
+ if (existingValue) {
+ state->SetCacheEntryProperty(this->RunResultVariable, "ADVANCED", "1");
+ }
+
+ error = true;
+ }
+
+ // is the output from the executable used ?
+ if (out) {
+ if (!this->Makefile->GetDefinition(internalRunOutputName)) {
+ // if the variables doesn't exist, create it with a helpful error text
+ // and mark it as advanced
+ std::string comment = cmStrCat(
+ "Output of TRY_RUN(), contains the text, which the executable "
+ "would have printed on stdout and stderr on its target platform.\n",
+ detailsString);
+
+ this->Makefile->AddCacheDefinition(
+ internalRunOutputName, "PLEASE_FILL_OUT-NOTFOUND", comment.c_str(),
+ cmStateEnums::STRING);
+ cmState* state = this->Makefile->GetState();
+ cmProp existing = state->GetCacheEntryValue(internalRunOutputName);
+ if (existing) {
+ state->SetCacheEntryProperty(internalRunOutputName, "ADVANCED", "1");
+ }
+
+ error = true;
+ }
+ }
+
+ if (error) {
+ static bool firstTryRun = true;
+ cmsys::ofstream file(resultFileName.c_str(),
+ firstTryRun ? std::ios::out : std::ios::app);
+ if (file) {
+ if (firstTryRun) {
+ /* clang-format off */
+ file << "# This file was generated by CMake because it detected "
+ "TRY_RUN() commands\n"
+ "# in crosscompiling mode. It will be overwritten by the next "
+ "CMake run.\n"
+ "# Copy it to a safe location, set the variables to "
+ "appropriate values\n"
+ "# and use it then to preset the CMake cache (using -C).\n\n";
+ /* clang-format on */
+ }
+
+ std::string comment =
+ cmStrCat('\n', this->RunResultVariable,
+ "\n indicates whether the executable would have been able "
+ "to run on its\n"
+ " target platform. If so, set ",
+ this->RunResultVariable,
+ " to\n"
+ " the exit code (in many cases 0 for success), otherwise "
+ "enter \"FAILED_TO_RUN\".\n");
+ if (out) {
+ comment += internalRunOutputName;
+ comment +=
+ "\n contains the text the executable "
+ "would have printed on stdout and stderr.\n"
+ " If the executable would not have been able to run, set ";
+ comment += internalRunOutputName;
+ comment += " empty.\n"
+ " Otherwise check if the output is evaluated by the "
+ "calling CMake code. If so,\n"
+ " check what the source file would have printed when "
+ "called with the given arguments.\n";
+ }
+ comment += "The ";
+ comment += this->CompileResultVariable;
+ comment += " variable holds the build result for this TRY_RUN().\n\n"
+ "Source file : ";
+ comment += srcFile + "\n";
+ comment += "Executable : ";
+ comment += copyDest + "\n";
+ comment += "Run arguments : ";
+ comment += runArgs;
+ comment += "\n";
+ comment += " Called from: " + this->Makefile->FormatListFileStack();
+ cmsys::SystemTools::ReplaceString(comment, "\n", "\n# ");
+ file << comment << "\n\n";
+
+ file << "set( " << this->RunResultVariable << " \n \""
+ << this->Makefile->GetSafeDefinition(this->RunResultVariable)
+ << "\"\n CACHE STRING \"Result from TRY_RUN\" FORCE)\n\n";
+
+ if (out) {
+ file << "set( " << internalRunOutputName << " \n \""
+ << this->Makefile->GetSafeDefinition(internalRunOutputName)
+ << "\"\n CACHE STRING \"Output from TRY_RUN\" FORCE)\n\n";
+ }
+ file.close();
+ }
+ firstTryRun = false;
+
+ std::string errorMessage =
+ cmStrCat("TRY_RUN() invoked in cross-compiling mode, "
+ "please set the following cache variables "
+ "appropriately:\n ",
+ this->RunResultVariable, " (advanced)\n");
+ if (out) {
+ errorMessage += " " + internalRunOutputName + " (advanced)\n";
+ }
+ errorMessage += detailsString;
+ cmSystemTools::Error(errorMessage);
+ return;
+ }
+
+ if (out) {
+ (*out) = *this->Makefile->GetDefinition(internalRunOutputName);
+ }
+}
diff --git a/Source/cmTryRunCommand.h b/Source/cmTryRunCommand.h
new file mode 100644
index 0000000..d45acd8
--- /dev/null
+++ b/Source/cmTryRunCommand.h
@@ -0,0 +1,53 @@
+/* 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 <string>
+#include <vector>
+
+#include <cm/memory>
+
+#include "cmCommand.h"
+#include "cmCoreTryCompile.h"
+
+class cmExecutionStatus;
+
+/** \class cmTryRunCommand
+ * \brief Specifies where to install some files
+ *
+ * cmTryRunCommand is used to test if source code can be compiled
+ */
+class cmTryRunCommand : public cmCoreTryCompile
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ std::unique_ptr<cmCommand> Clone() override
+ {
+ return cm::make_unique<cmTryRunCommand>();
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) override;
+
+private:
+ void RunExecutable(const std::string& runArgs,
+ std::string* runOutputContents);
+ void DoNotRunExecutable(const std::string& runArgs,
+ const std::string& srcFile,
+ std::string* runOutputContents);
+
+ std::string CompileResultVariable;
+ std::string RunResultVariable;
+ std::string OutputVariable;
+ std::string RunOutputVariable;
+ std::string CompileOutputVariable;
+ std::string WorkingDirectory;
+};
diff --git a/Source/cmUVHandlePtr.cxx b/Source/cmUVHandlePtr.cxx
new file mode 100644
index 0000000..8ea1942
--- /dev/null
+++ b/Source/cmUVHandlePtr.cxx
@@ -0,0 +1,269 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#define cmUVHandlePtr_cxx
+#include "cmUVHandlePtr.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <mutex>
+
+#include <cm3p/uv.h>
+
+namespace cm {
+
+struct uv_loop_deleter
+{
+ void operator()(uv_loop_t* loop) const;
+};
+
+void uv_loop_deleter::operator()(uv_loop_t* loop) const
+{
+ uv_run(loop, UV_RUN_DEFAULT);
+ int result = uv_loop_close(loop);
+ (void)result;
+ assert(result >= 0);
+ free(loop);
+}
+
+int uv_loop_ptr::init(void* data)
+{
+ this->reset();
+
+ this->loop.reset(static_cast<uv_loop_t*>(calloc(1, sizeof(uv_loop_t))),
+ uv_loop_deleter());
+ this->loop->data = data;
+
+ return uv_loop_init(this->loop.get());
+}
+
+void uv_loop_ptr::reset()
+{
+ this->loop.reset();
+}
+
+uv_loop_ptr::operator uv_loop_t*()
+{
+ return this->loop.get();
+}
+
+uv_loop_t* uv_loop_ptr::operator->() const noexcept
+{
+ return this->loop.get();
+}
+
+uv_loop_t* uv_loop_ptr::get() const
+{
+ return this->loop.get();
+}
+
+template <typename T>
+static void handle_default_delete(T* type_handle)
+{
+ auto* handle = reinterpret_cast<uv_handle_t*>(type_handle);
+ if (handle) {
+ assert(!uv_is_closing(handle));
+ if (!uv_is_closing(handle)) {
+ uv_close(handle, [](uv_handle_t* h) { free(h); });
+ }
+ }
+}
+
+/**
+ * Encapsulates delete logic for a given handle type T
+ */
+template <typename T>
+struct uv_handle_deleter
+{
+ void operator()(T* type_handle) const { handle_default_delete(type_handle); }
+};
+
+template <typename T>
+void uv_handle_ptr_base_<T>::allocate(void* data)
+{
+ this->reset();
+
+ /*
+ We use calloc since we know all these types are c structs
+ and we just want to 0 init them. New would do the same thing;
+ but casting from uv_handle_t to certain other types -- namely
+ uv_timer_t -- triggers a cast_align warning on certain systems.
+ */
+ this->handle.reset(static_cast<T*>(calloc(1, sizeof(T))),
+ uv_handle_deleter<T>());
+ this->handle->data = data;
+}
+
+template <typename T>
+void uv_handle_ptr_base_<T>::reset()
+{
+ this->handle.reset();
+}
+
+template <typename T>
+uv_handle_ptr_base_<T>::operator uv_handle_t*()
+{
+ return reinterpret_cast<uv_handle_t*>(this->handle.get());
+}
+
+template <typename T>
+T* uv_handle_ptr_base_<T>::operator->() const noexcept
+{
+ return this->handle.get();
+}
+
+template <typename T>
+T* uv_handle_ptr_base_<T>::get() const
+{
+ return this->handle.get();
+}
+
+template <typename T>
+uv_handle_ptr_<T>::operator T*() const
+{
+ return this->handle.get();
+}
+
+#ifndef CMAKE_BOOTSTRAP
+template <>
+struct uv_handle_deleter<uv_async_t>
+{
+ /***
+ * Wile uv_async_send is itself thread-safe, there are
+ * no strong guarantees that close hasn't already been
+ * called on the handle; and that it might be deleted
+ * as the send call goes through. This mutex guards
+ * against that.
+ *
+ * The shared_ptr here is to allow for copy construction
+ * which is mandated by the standard for Deleter on
+ * shared_ptrs.
+ */
+ std::shared_ptr<std::mutex> handleMutex;
+
+ uv_handle_deleter()
+ : handleMutex(std::make_shared<std::mutex>())
+ {
+ }
+
+ void operator()(uv_async_t* handle)
+ {
+ std::lock_guard<std::mutex> lock(*this->handleMutex);
+ handle_default_delete(handle);
+ }
+};
+
+void uv_async_ptr::send()
+{
+ auto* deleter =
+ std::get_deleter<uv_handle_deleter<uv_async_t>>(this->handle);
+ assert(deleter);
+
+ std::lock_guard<std::mutex> lock(*deleter->handleMutex);
+ if (this->handle) {
+ uv_async_send(*this);
+ }
+}
+
+int uv_async_ptr::init(uv_loop_t& loop, uv_async_cb async_cb, void* data)
+{
+ this->allocate(data);
+ return uv_async_init(&loop, this->handle.get(), async_cb);
+}
+#endif
+
+template <>
+struct uv_handle_deleter<uv_signal_t>
+{
+ void operator()(uv_signal_t* handle) const
+ {
+ if (handle) {
+ uv_signal_stop(handle);
+ handle_default_delete(handle);
+ }
+ }
+};
+
+int uv_signal_ptr::init(uv_loop_t& loop, void* data)
+{
+ this->allocate(data);
+ return uv_signal_init(&loop, this->handle.get());
+}
+
+int uv_signal_ptr::start(uv_signal_cb cb, int signum)
+{
+ assert(this->handle);
+ return uv_signal_start(*this, cb, signum);
+}
+
+void uv_signal_ptr::stop()
+{
+ if (this->handle) {
+ uv_signal_stop(*this);
+ }
+}
+
+int uv_pipe_ptr::init(uv_loop_t& loop, int ipc, void* data)
+{
+ this->allocate(data);
+ return uv_pipe_init(&loop, *this, ipc);
+}
+
+uv_pipe_ptr::operator uv_stream_t*() const
+{
+ return reinterpret_cast<uv_stream_t*>(this->handle.get());
+}
+
+int uv_process_ptr::spawn(uv_loop_t& loop, uv_process_options_t const& options,
+ void* data)
+{
+ this->allocate(data);
+ return uv_spawn(&loop, *this, &options);
+}
+
+int uv_timer_ptr::init(uv_loop_t& loop, void* data)
+{
+ this->allocate(data);
+ return uv_timer_init(&loop, *this);
+}
+
+int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat)
+{
+ assert(this->handle);
+ return uv_timer_start(*this, cb, timeout, repeat);
+}
+
+#ifndef CMAKE_BOOTSTRAP
+uv_tty_ptr::operator uv_stream_t*() const
+{
+ return reinterpret_cast<uv_stream_t*>(this->handle.get());
+}
+
+int uv_tty_ptr::init(uv_loop_t& loop, int fd, int readable, void* data)
+{
+ this->allocate(data);
+ return uv_tty_init(&loop, *this, fd, readable);
+}
+#endif
+
+template class uv_handle_ptr_base_<uv_handle_t>;
+
+#define UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(NAME) \
+ template class uv_handle_ptr_base_<uv_##NAME##_t>; \
+ template class uv_handle_ptr_<uv_##NAME##_t>;
+
+UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(signal)
+
+UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(pipe)
+
+UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(stream)
+
+UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(process)
+
+UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(timer)
+
+#ifndef CMAKE_BOOTSTRAP
+UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(async)
+
+UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(tty)
+#endif
+}
diff --git a/Source/cmUVHandlePtr.h b/Source/cmUVHandlePtr.h
new file mode 100644
index 0000000..8c5ad59
--- /dev/null
+++ b/Source/cmUVHandlePtr.h
@@ -0,0 +1,271 @@
+/* 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 <cstddef>
+#include <cstdint>
+#include <memory>
+#include <type_traits>
+
+#include <cm3p/uv.h>
+
+#if defined(__SUNPRO_CC)
+
+# include <utility>
+
+# define CM_INHERIT_CTOR(Class, Base, Tpl) \
+ template <typename... Args> \
+ Class(Args&&... args) \
+ : Base Tpl(std::forward<Args>(args)...) \
+ { \
+ }
+
+#else
+
+# define CM_INHERIT_CTOR(Class, Base, Tpl) using Base Tpl ::Base;
+
+#endif
+
+namespace cm {
+
+/***
+ * RAII class to simplify and ensure the safe usage of uv_loop_t. This includes
+ * making sure resources are properly freed.
+ */
+class uv_loop_ptr
+{
+protected:
+ std::shared_ptr<uv_loop_t> loop;
+
+public:
+ uv_loop_ptr(uv_loop_ptr const&) = delete;
+ uv_loop_ptr& operator=(uv_loop_ptr const&) = delete;
+ uv_loop_ptr(uv_loop_ptr&&) noexcept;
+ uv_loop_ptr& operator=(uv_loop_ptr&&) noexcept;
+
+ // Dtor and ctor need to be inline defined like this for default ctors and
+ // dtors to work. Some compilers do not like '= default' here.
+ uv_loop_ptr() {} // NOLINT(modernize-use-equals-default)
+ uv_loop_ptr(std::nullptr_t) {}
+ ~uv_loop_ptr() { this->reset(); }
+
+ int init(void* data = nullptr);
+
+ /**
+ * Properly close the handle if needed and sets the inner handle to nullptr
+ */
+ void reset();
+
+ /**
+ * Allow less verbose calling of uv_loop_* functions
+ * @return reinterpreted handle
+ */
+ operator uv_loop_t*();
+
+ uv_loop_t* get() const;
+ uv_loop_t* operator->() const noexcept;
+};
+
+/***
+ * RAII class to simplify and ensure the safe usage of uv_*_t types. This
+ * includes making sure resources are properly freed and contains casting
+ * operators which allow for passing into relevant uv_* functions.
+ *
+ *@tparam T actual uv_*_t type represented.
+ */
+template <typename T>
+class uv_handle_ptr_base_
+{
+protected:
+ template <typename U>
+ friend class uv_handle_ptr_base_;
+
+ /**
+ * This must be a pointer type since the handle can outlive this class.
+ * When uv_close is eventually called on the handle, the memory the
+ * handle inhabits must be valid until the close callback is called
+ * which can be later on in the loop.
+ */
+ std::shared_ptr<T> handle;
+
+ /**
+ * Allocate memory for the type and optionally set it's 'data' pointer.
+ * Protected since this should only be called for an appropriate 'init'
+ * call.
+ *
+ * @param data data pointer to set
+ */
+ void allocate(void* data = nullptr);
+
+public:
+ uv_handle_ptr_base_(uv_handle_ptr_base_ const&) = delete;
+ uv_handle_ptr_base_& operator=(uv_handle_ptr_base_ const&) = delete;
+ uv_handle_ptr_base_(uv_handle_ptr_base_&&) noexcept;
+ uv_handle_ptr_base_& operator=(uv_handle_ptr_base_&&) noexcept;
+
+ /**
+ * This move constructor allows us to move out of a more specialized
+ * uv type into a less specialized one. The only constraint is that
+ * the right hand side is castable to T.
+ *
+ * This allows you to return uv_handle_ptr or uv_stream_ptr from a function
+ * that initializes something like uv_pipe_ptr or uv_tcp_ptr and interact
+ * and clean up after it without caring about the exact type.
+ */
+ template <typename S,
+ typename = typename std::enable_if<
+ std::is_rvalue_reference<S&&>::value>::type>
+ uv_handle_ptr_base_(S&& rhs)
+ {
+ // This will force a compiler error if rhs doesn't have a casting
+ // operator to get T*
+ this->handle = std::shared_ptr<T>(rhs.handle, rhs);
+ rhs.handle.reset();
+ }
+
+ // Dtor and ctor need to be inline defined like this for default ctors and
+ // dtors to work. Some compilers do not like '= default' here.
+ uv_handle_ptr_base_() {} // NOLINT(modernize-use-equals-default)
+ uv_handle_ptr_base_(std::nullptr_t) {}
+ ~uv_handle_ptr_base_() { this->reset(); }
+
+ /**
+ * Properly close the handle if needed and sets the inner handle to nullptr
+ */
+ void reset();
+
+ /**
+ * Allow less verbose calling of uv_handle_* functions
+ * @return reinterpreted handle
+ */
+ operator uv_handle_t*();
+
+ T* get() const;
+ T* operator->() const noexcept;
+};
+
+template <typename T>
+inline uv_handle_ptr_base_<T>::uv_handle_ptr_base_(
+ uv_handle_ptr_base_<T>&&) noexcept = default;
+template <typename T>
+inline uv_handle_ptr_base_<T>& uv_handle_ptr_base_<T>::operator=(
+ uv_handle_ptr_base_<T>&&) noexcept = default;
+
+/**
+ * While uv_handle_ptr_base_ only exposes uv_handle_t*, this exposes uv_T_t*
+ * too. It is broken out like this so we can reuse most of the code for the
+ * uv_handle_ptr class.
+ */
+template <typename T>
+class uv_handle_ptr_ : public uv_handle_ptr_base_<T>
+{
+ template <typename U>
+ friend class uv_handle_ptr_;
+
+public:
+ CM_INHERIT_CTOR(uv_handle_ptr_, uv_handle_ptr_base_, <T>);
+
+ /***
+ * Allow less verbose calling of uv_<T> functions
+ * @return reinterpreted handle
+ */
+ operator T*() const;
+};
+
+/***
+ * This specialization is required to avoid duplicate 'operator uv_handle_t*()'
+ * declarations
+ */
+template <>
+class uv_handle_ptr_<uv_handle_t> : public uv_handle_ptr_base_<uv_handle_t>
+{
+public:
+ CM_INHERIT_CTOR(uv_handle_ptr_, uv_handle_ptr_base_, <uv_handle_t>);
+};
+
+class uv_async_ptr : public uv_handle_ptr_<uv_async_t>
+{
+public:
+ CM_INHERIT_CTOR(uv_async_ptr, uv_handle_ptr_, <uv_async_t>);
+
+ int init(uv_loop_t& loop, uv_async_cb async_cb, void* data = nullptr);
+
+ void send();
+};
+
+struct uv_signal_ptr : public uv_handle_ptr_<uv_signal_t>
+{
+ CM_INHERIT_CTOR(uv_signal_ptr, uv_handle_ptr_, <uv_signal_t>);
+
+ int init(uv_loop_t& loop, void* data = nullptr);
+
+ int start(uv_signal_cb cb, int signum);
+
+ void stop();
+};
+
+struct uv_pipe_ptr : public uv_handle_ptr_<uv_pipe_t>
+{
+ CM_INHERIT_CTOR(uv_pipe_ptr, uv_handle_ptr_, <uv_pipe_t>);
+
+ operator uv_stream_t*() const;
+
+ int init(uv_loop_t& loop, int ipc, void* data = nullptr);
+};
+
+struct uv_process_ptr : public uv_handle_ptr_<uv_process_t>
+{
+ CM_INHERIT_CTOR(uv_process_ptr, uv_handle_ptr_, <uv_process_t>);
+
+ int spawn(uv_loop_t& loop, uv_process_options_t const& options,
+ void* data = nullptr);
+};
+
+struct uv_timer_ptr : public uv_handle_ptr_<uv_timer_t>
+{
+ CM_INHERIT_CTOR(uv_timer_ptr, uv_handle_ptr_, <uv_timer_t>);
+
+ int init(uv_loop_t& loop, void* data = nullptr);
+
+ int start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat);
+};
+
+struct uv_tty_ptr : public uv_handle_ptr_<uv_tty_t>
+{
+ CM_INHERIT_CTOR(uv_tty_ptr, uv_handle_ptr_, <uv_tty_t>);
+
+ operator uv_stream_t*() const;
+
+ int init(uv_loop_t& loop, int fd, int readable, void* data = nullptr);
+};
+
+using uv_stream_ptr = uv_handle_ptr_<uv_stream_t>;
+using uv_handle_ptr = uv_handle_ptr_<uv_handle_t>;
+
+#ifndef cmUVHandlePtr_cxx
+
+extern template class uv_handle_ptr_base_<uv_handle_t>;
+
+# define UV_HANDLE_PTR_INSTANTIATE_EXTERN(NAME) \
+ extern template class uv_handle_ptr_base_<uv_##NAME##_t>; \
+ extern template class uv_handle_ptr_<uv_##NAME##_t>;
+
+UV_HANDLE_PTR_INSTANTIATE_EXTERN(async)
+
+UV_HANDLE_PTR_INSTANTIATE_EXTERN(signal)
+
+UV_HANDLE_PTR_INSTANTIATE_EXTERN(pipe)
+
+UV_HANDLE_PTR_INSTANTIATE_EXTERN(process)
+
+UV_HANDLE_PTR_INSTANTIATE_EXTERN(stream)
+
+UV_HANDLE_PTR_INSTANTIATE_EXTERN(timer)
+
+UV_HANDLE_PTR_INSTANTIATE_EXTERN(tty)
+
+# undef UV_HANDLE_PTR_INSTANTIATE_EXTERN
+
+#endif
+}
diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx
new file mode 100644
index 0000000..6040fd8
--- /dev/null
+++ b/Source/cmUVProcessChain.cxx
@@ -0,0 +1,396 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmUVProcessChain.h"
+
+#include <cassert>
+#include <istream> // IWYU pragma: keep
+#include <iterator>
+#include <utility>
+
+#include <cm/memory>
+
+#include <cm3p/uv.h>
+
+#include "cmGetPipes.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVStreambuf.h"
+
+struct cmUVProcessChain::InternalData
+{
+ struct BasicStreamData
+ {
+ cmUVStreambuf Streambuf;
+ cm::uv_pipe_ptr BuiltinStream;
+ uv_stdio_container_t Stdio;
+ };
+
+ template <typename IOStream>
+ struct StreamData : public BasicStreamData
+ {
+ StreamData()
+ : BuiltinIOStream(&this->Streambuf)
+ {
+ }
+
+ IOStream BuiltinIOStream;
+
+ IOStream* GetBuiltinStream()
+ {
+ if (this->BuiltinStream.get()) {
+ return &this->BuiltinIOStream;
+ }
+ return nullptr;
+ }
+ };
+
+ struct ProcessData
+ {
+ cmUVProcessChain::InternalData* Data;
+ cm::uv_process_ptr Process;
+ cm::uv_pipe_ptr OutputPipe;
+ bool Finished = false;
+ Status ProcessStatus;
+ };
+
+ const cmUVProcessChainBuilder* Builder = nullptr;
+
+ bool Valid = false;
+
+ cm::uv_loop_ptr Loop;
+
+ StreamData<std::istream> OutputStreamData;
+ StreamData<std::istream> ErrorStreamData;
+
+ unsigned int ProcessesCompleted = 0;
+ std::vector<std::unique_ptr<ProcessData>> Processes;
+
+ bool Prepare(const cmUVProcessChainBuilder* builder);
+ bool AddCommand(const cmUVProcessChainBuilder::ProcessConfiguration& config,
+ bool first, bool last);
+ bool Finish();
+
+ static const Status* GetStatus(const ProcessData& data);
+};
+
+cmUVProcessChainBuilder::cmUVProcessChainBuilder()
+{
+ this->SetNoStream(Stream_INPUT)
+ .SetNoStream(Stream_OUTPUT)
+ .SetNoStream(Stream_ERROR);
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::AddCommand(
+ const std::vector<std::string>& arguments)
+{
+ if (!arguments.empty()) {
+ this->Processes.emplace_back();
+ this->Processes.back().Arguments = arguments;
+ }
+ return *this;
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetNoStream(Stream stdio)
+{
+ switch (stdio) {
+ case Stream_INPUT:
+ case Stream_OUTPUT:
+ case Stream_ERROR: {
+ auto& streamData = this->Stdio[stdio];
+ streamData.Type = None;
+ break;
+ }
+ }
+ return *this;
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetBuiltinStream(
+ Stream stdio)
+{
+ switch (stdio) {
+ case Stream_INPUT:
+ // FIXME
+ break;
+
+ case Stream_OUTPUT:
+ case Stream_ERROR: {
+ auto& streamData = this->Stdio[stdio];
+ streamData.Type = Builtin;
+ break;
+ }
+ }
+ return *this;
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalStream(
+ Stream stdio, int fd)
+{
+ switch (stdio) {
+ case Stream_INPUT:
+ // FIXME
+ break;
+
+ case Stream_OUTPUT:
+ case Stream_ERROR: {
+ auto& streamData = this->Stdio[stdio];
+ streamData.Type = External;
+ streamData.FileDescriptor = fd;
+ break;
+ }
+ }
+ return *this;
+}
+
+cmUVProcessChain cmUVProcessChainBuilder::Start() const
+{
+ cmUVProcessChain chain;
+
+ if (!chain.Data->Prepare(this)) {
+ return chain;
+ }
+
+ for (auto it = this->Processes.begin(); it != this->Processes.end(); ++it) {
+ if (!chain.Data->AddCommand(*it, it == this->Processes.begin(),
+ it == std::prev(this->Processes.end()))) {
+ return chain;
+ }
+ }
+
+ chain.Data->Finish();
+
+ return chain;
+}
+
+const cmUVProcessChain::Status* cmUVProcessChain::InternalData::GetStatus(
+ const cmUVProcessChain::InternalData::ProcessData& data)
+{
+ if (data.Finished) {
+ return &data.ProcessStatus;
+ }
+ return nullptr;
+}
+
+bool cmUVProcessChain::InternalData::Prepare(
+ const cmUVProcessChainBuilder* builder)
+{
+ this->Builder = builder;
+
+ auto const& output =
+ this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT];
+ auto& outputData = this->OutputStreamData;
+ switch (output.Type) {
+ case cmUVProcessChainBuilder::None:
+ outputData.Stdio.flags = UV_IGNORE;
+ break;
+
+ case cmUVProcessChainBuilder::Builtin:
+ outputData.BuiltinStream.init(*this->Loop, 0);
+ outputData.Stdio.flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ outputData.Stdio.data.stream = outputData.BuiltinStream;
+ break;
+
+ case cmUVProcessChainBuilder::External:
+ outputData.Stdio.flags = UV_INHERIT_FD;
+ outputData.Stdio.data.fd = output.FileDescriptor;
+ break;
+ }
+
+ auto const& error =
+ this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR];
+ auto& errorData = this->ErrorStreamData;
+ switch (error.Type) {
+ case cmUVProcessChainBuilder::None:
+ errorData.Stdio.flags = UV_IGNORE;
+ break;
+
+ case cmUVProcessChainBuilder::Builtin: {
+ int pipeFd[2];
+ if (cmGetPipes(pipeFd) < 0) {
+ return false;
+ }
+
+ errorData.BuiltinStream.init(*this->Loop, 0);
+ if (uv_pipe_open(errorData.BuiltinStream, pipeFd[0]) < 0) {
+ return false;
+ }
+ errorData.Stdio.flags = UV_INHERIT_FD;
+ errorData.Stdio.data.fd = pipeFd[1];
+ break;
+ }
+
+ case cmUVProcessChainBuilder::External:
+ errorData.Stdio.flags = UV_INHERIT_FD;
+ errorData.Stdio.data.fd = error.FileDescriptor;
+ break;
+ }
+
+ return true;
+}
+
+bool cmUVProcessChain::InternalData::AddCommand(
+ const cmUVProcessChainBuilder::ProcessConfiguration& config, bool first,
+ bool last)
+{
+ this->Processes.emplace_back(cm::make_unique<ProcessData>());
+ auto& process = *this->Processes.back();
+ process.Data = this;
+
+ auto options = uv_process_options_t();
+
+ // Bounds were checked at add time, first element is guaranteed to exist
+ options.file = config.Arguments[0].c_str();
+
+ std::vector<const char*> arguments;
+ for (auto const& arg : config.Arguments) {
+ arguments.push_back(arg.c_str());
+ }
+ arguments.push_back(nullptr);
+ options.args = const_cast<char**>(arguments.data());
+ options.flags = UV_PROCESS_WINDOWS_HIDE;
+
+ std::array<uv_stdio_container_t, 3> stdio;
+ stdio[0] = uv_stdio_container_t();
+ if (first) {
+ stdio[0].flags = UV_IGNORE;
+ } else {
+ assert(this->Processes.size() >= 2);
+ auto& prev = *this->Processes[this->Processes.size() - 2];
+ stdio[0].flags = UV_INHERIT_STREAM;
+ stdio[0].data.stream = prev.OutputPipe;
+ }
+ if (last) {
+ stdio[1] = this->OutputStreamData.Stdio;
+ } else {
+ if (process.OutputPipe.init(*this->Loop, 0) < 0) {
+ return false;
+ }
+ stdio[1] = uv_stdio_container_t();
+ stdio[1].flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ stdio[1].data.stream = process.OutputPipe;
+ }
+ stdio[2] = this->ErrorStreamData.Stdio;
+
+ options.stdio = stdio.data();
+ options.stdio_count = 3;
+ options.exit_cb = [](uv_process_t* handle, int64_t exitStatus,
+ int termSignal) {
+ auto* processData = static_cast<ProcessData*>(handle->data);
+ processData->Finished = true;
+ processData->ProcessStatus.ExitStatus = exitStatus;
+ processData->ProcessStatus.TermSignal = termSignal;
+ processData->Data->ProcessesCompleted++;
+ };
+
+ return process.Process.spawn(*this->Loop, options, &process) >= 0;
+}
+
+bool cmUVProcessChain::InternalData::Finish()
+{
+ if (this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT].Type ==
+ cmUVProcessChainBuilder::Builtin) {
+ this->OutputStreamData.Streambuf.open(
+ this->OutputStreamData.BuiltinStream);
+ }
+
+ if (this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR].Type ==
+ cmUVProcessChainBuilder::Builtin) {
+ cm::uv_pipe_ptr tmpPipe;
+ if (tmpPipe.init(*this->Loop, 0) < 0) {
+ return false;
+ }
+ if (uv_pipe_open(tmpPipe, this->ErrorStreamData.Stdio.data.fd) < 0) {
+ return false;
+ }
+ tmpPipe.reset();
+
+ this->ErrorStreamData.Streambuf.open(this->ErrorStreamData.BuiltinStream);
+ }
+
+ this->Valid = true;
+ return true;
+}
+
+cmUVProcessChain::cmUVProcessChain()
+ : Data(cm::make_unique<InternalData>())
+{
+ this->Data->Loop.init();
+}
+
+cmUVProcessChain::cmUVProcessChain(cmUVProcessChain&& other) noexcept
+ : Data(std::move(other.Data))
+{
+}
+
+cmUVProcessChain::~cmUVProcessChain() = default;
+
+cmUVProcessChain& cmUVProcessChain::operator=(
+ cmUVProcessChain&& other) noexcept
+{
+ this->Data = std::move(other.Data);
+ return *this;
+}
+
+uv_loop_t& cmUVProcessChain::GetLoop()
+{
+ return *this->Data->Loop;
+}
+
+std::istream* cmUVProcessChain::OutputStream()
+{
+ return this->Data->OutputStreamData.GetBuiltinStream();
+}
+
+std::istream* cmUVProcessChain::ErrorStream()
+{
+ return this->Data->ErrorStreamData.GetBuiltinStream();
+}
+
+bool cmUVProcessChain::Valid() const
+{
+ return this->Data->Valid;
+}
+
+bool cmUVProcessChain::Wait(int64_t milliseconds)
+{
+ bool timeout = false;
+ cm::uv_timer_ptr timer;
+
+ if (milliseconds >= 0) {
+ timer.init(*this->Data->Loop, &timeout);
+ timer.start(
+ [](uv_timer_t* handle) {
+ auto* timeoutPtr = static_cast<bool*>(handle->data);
+ *timeoutPtr = true;
+ },
+ milliseconds, 0);
+ }
+
+ while (!timeout &&
+ this->Data->ProcessesCompleted < this->Data->Processes.size()) {
+ uv_run(this->Data->Loop, UV_RUN_ONCE);
+ }
+
+ return !timeout;
+}
+
+std::vector<const cmUVProcessChain::Status*> cmUVProcessChain::GetStatus()
+ const
+{
+ std::vector<const cmUVProcessChain::Status*> statuses(
+ this->Data->Processes.size(), nullptr);
+ for (std::size_t i = 0; i < statuses.size(); i++) {
+ statuses[i] = this->GetStatus(i);
+ }
+ return statuses;
+}
+
+const cmUVProcessChain::Status* cmUVProcessChain::GetStatus(
+ std::size_t index) const
+{
+ auto const& process = *this->Data->Processes[index];
+ if (process.Finished) {
+ return &process.ProcessStatus;
+ }
+ return nullptr;
+}
diff --git a/Source/cmUVProcessChain.h b/Source/cmUVProcessChain.h
new file mode 100644
index 0000000..5e8e7e6
--- /dev/null
+++ b/Source/cmUVProcessChain.h
@@ -0,0 +1,97 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <array>
+#include <cstddef> // IWYU pragma: keep
+#include <cstdint>
+#include <iosfwd>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm3p/uv.h>
+
+class cmUVProcessChain;
+
+class cmUVProcessChainBuilder
+{
+public:
+ enum Stream
+ {
+ Stream_INPUT = 0,
+ Stream_OUTPUT = 1,
+ Stream_ERROR = 2,
+ };
+
+ cmUVProcessChainBuilder();
+
+ cmUVProcessChainBuilder& AddCommand(
+ const std::vector<std::string>& arguments);
+ cmUVProcessChainBuilder& SetNoStream(Stream stdio);
+ cmUVProcessChainBuilder& SetBuiltinStream(Stream stdio);
+ cmUVProcessChainBuilder& SetExternalStream(Stream stdio, int fd);
+
+ cmUVProcessChain Start() const;
+
+private:
+ enum StdioType
+ {
+ None,
+ Builtin,
+ External,
+ };
+
+ friend class cmUVProcessChain;
+
+ struct StdioConfiguration
+ {
+ StdioType Type;
+ int FileDescriptor;
+ };
+
+ struct ProcessConfiguration
+ {
+ std::vector<std::string> Arguments;
+ };
+
+ std::array<StdioConfiguration, 3> Stdio;
+ std::vector<ProcessConfiguration> Processes;
+};
+
+class cmUVProcessChain
+{
+public:
+ struct Status
+ {
+ int64_t ExitStatus;
+ int TermSignal;
+ };
+
+ cmUVProcessChain(const cmUVProcessChain& other) = delete;
+ cmUVProcessChain(cmUVProcessChain&& other) noexcept;
+
+ ~cmUVProcessChain();
+
+ cmUVProcessChain& operator=(const cmUVProcessChain& other) = delete;
+ cmUVProcessChain& operator=(cmUVProcessChain&& other) noexcept;
+
+ uv_loop_t& GetLoop();
+
+ // FIXME: Add stdin support
+ std::istream* OutputStream();
+ std::istream* ErrorStream();
+
+ bool Valid() const;
+ bool Wait(int64_t milliseconds = -1);
+ std::vector<const Status*> GetStatus() const;
+ const Status* GetStatus(std::size_t index) const;
+
+private:
+ friend class cmUVProcessChainBuilder;
+
+ cmUVProcessChain();
+
+ struct InternalData;
+ std::unique_ptr<InternalData> Data;
+};
diff --git a/Source/cmUVSignalHackRAII.h b/Source/cmUVSignalHackRAII.h
new file mode 100644
index 0000000..60e4ca8
--- /dev/null
+++ b/Source/cmUVSignalHackRAII.h
@@ -0,0 +1,45 @@
+/* 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 <cm3p/uv.h>
+
+#if defined(CMAKE_USE_SYSTEM_LIBUV) && !defined(_WIN32) && \
+ UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR < 19
+# define CMAKE_UV_SIGNAL_HACK
+# include "cmUVHandlePtr.h"
+/*
+ libuv does not use SA_RESTART on its signal handler, but C++ streams
+ depend on it for reliable i/o operations. This RAII helper convinces
+ libuv to install its handler, and then revises the handler to add the
+ SA_RESTART flag. We use a distinct uv loop that never runs to avoid
+ ever really getting a callback. libuv may fill the hack loop's signal
+ pipe and then stop writing, but that won't break any real loops.
+ */
+class cmUVSignalHackRAII
+{
+ uv_loop_t HackLoop;
+ cm::uv_signal_ptr HackSignal;
+ static void HackCB(uv_signal_t*, int) {}
+
+public:
+ cmUVSignalHackRAII()
+ {
+ uv_loop_init(&this->HackLoop);
+ this->HackSignal.init(this->HackLoop);
+ this->HackSignal.start(HackCB, SIGCHLD);
+ struct sigaction hack_sa;
+ sigaction(SIGCHLD, nullptr, &hack_sa);
+ if (!(hack_sa.sa_flags & SA_RESTART)) {
+ hack_sa.sa_flags |= SA_RESTART;
+ sigaction(SIGCHLD, &hack_sa, nullptr);
+ }
+ }
+ ~cmUVSignalHackRAII()
+ {
+ this->HackSignal.stop();
+ uv_loop_close(&this->HackLoop);
+ }
+};
+#endif
diff --git a/Source/cmUVStreambuf.h b/Source/cmUVStreambuf.h
new file mode 100644
index 0000000..efe45de
--- /dev/null
+++ b/Source/cmUVStreambuf.h
@@ -0,0 +1,216 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <algorithm>
+#include <cstring>
+#include <streambuf>
+#include <vector>
+
+#include <cm3p/uv.h>
+
+#include "cmUVHandlePtr.h"
+
+/*
+ * This file is based on example code from:
+ *
+ * http://www.voidcn.com/article/p-vjnlygmc-gy.html
+ *
+ * The example code was distributed under the following license:
+ *
+ * Copyright 2007 Edd Dawson.
+ * Distributed under the Boost Software License, Version 1.0.
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+template <typename CharT, typename Traits = std::char_traits<CharT>>
+class cmBasicUVStreambuf : public std::basic_streambuf<CharT, Traits>
+{
+public:
+ cmBasicUVStreambuf(std::size_t bufSize = 256, std::size_t putBack = 8);
+ ~cmBasicUVStreambuf() override;
+
+ bool is_open() const;
+
+ cmBasicUVStreambuf* open(uv_stream_t* stream);
+
+ cmBasicUVStreambuf* close();
+
+protected:
+ typename cmBasicUVStreambuf<CharT, Traits>::int_type underflow() override;
+ std::streamsize showmanyc() override;
+
+ // FIXME: Add write support
+
+private:
+ uv_stream_t* Stream = nullptr;
+ void* OldStreamData = nullptr;
+ const std::size_t PutBack = 0;
+ std::vector<CharT> InputBuffer;
+ bool EndOfFile = false;
+
+ void StreamReadStartStop();
+
+ void StreamRead(ssize_t nread);
+ void HandleAlloc(uv_buf_t* buf);
+};
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>::cmBasicUVStreambuf(std::size_t bufSize,
+ std::size_t putBack)
+ : PutBack(std::max<std::size_t>(putBack, 1))
+ , InputBuffer(std::max<std::size_t>(this->PutBack, bufSize) + this->PutBack)
+{
+ this->close();
+}
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>::~cmBasicUVStreambuf()
+{
+ this->close();
+}
+
+template <typename CharT, typename Traits>
+bool cmBasicUVStreambuf<CharT, Traits>::is_open() const
+{
+ return this->Stream != nullptr;
+}
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>* cmBasicUVStreambuf<CharT, Traits>::open(
+ uv_stream_t* stream)
+{
+ this->close();
+ this->Stream = stream;
+ this->EndOfFile = false;
+ if (this->Stream) {
+ this->OldStreamData = this->Stream->data;
+ this->Stream->data = this;
+ }
+ this->StreamReadStartStop();
+ return this;
+}
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>* cmBasicUVStreambuf<CharT, Traits>::close()
+{
+ if (this->Stream) {
+ uv_read_stop(this->Stream);
+ this->Stream->data = this->OldStreamData;
+ }
+ this->Stream = nullptr;
+ CharT* readEnd = this->InputBuffer.data() + this->InputBuffer.size();
+ this->setg(readEnd, readEnd, readEnd);
+ return this;
+}
+
+template <typename CharT, typename Traits>
+typename cmBasicUVStreambuf<CharT, Traits>::int_type
+cmBasicUVStreambuf<CharT, Traits>::underflow()
+{
+ if (!this->is_open()) {
+ return Traits::eof();
+ }
+
+ if (this->gptr() < this->egptr()) {
+ return Traits::to_int_type(*this->gptr());
+ }
+
+ this->StreamReadStartStop();
+ while (this->in_avail() == 0) {
+ uv_run(this->Stream->loop, UV_RUN_ONCE);
+ }
+ if (this->in_avail() == -1) {
+ return Traits::eof();
+ }
+ return Traits::to_int_type(*this->gptr());
+}
+
+template <typename CharT, typename Traits>
+std::streamsize cmBasicUVStreambuf<CharT, Traits>::showmanyc()
+{
+ if (!this->is_open() || this->EndOfFile) {
+ return -1;
+ }
+ return 0;
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVStreambuf<CharT, Traits>::StreamReadStartStop()
+{
+ if (this->Stream) {
+ uv_read_stop(this->Stream);
+ if (this->gptr() >= this->egptr()) {
+ uv_read_start(
+ this->Stream,
+ [](uv_handle_t* handle, size_t /* unused */, uv_buf_t* buf) {
+ auto streambuf =
+ static_cast<cmBasicUVStreambuf<CharT, Traits>*>(handle->data);
+ streambuf->HandleAlloc(buf);
+ },
+ [](uv_stream_t* stream2, ssize_t nread, const uv_buf_t* /* unused */) {
+ auto streambuf =
+ static_cast<cmBasicUVStreambuf<CharT, Traits>*>(stream2->data);
+ streambuf->StreamRead(nread);
+ });
+ }
+ }
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVStreambuf<CharT, Traits>::HandleAlloc(uv_buf_t* buf)
+{
+ auto size = this->egptr() - this->gptr();
+ std::memmove(this->InputBuffer.data(), this->gptr(),
+ this->egptr() - this->gptr());
+ this->setg(this->InputBuffer.data(), this->InputBuffer.data(),
+ this->InputBuffer.data() + size);
+ buf->base = this->egptr();
+#ifdef _WIN32
+# define BUF_LEN_TYPE ULONG
+#else
+# define BUF_LEN_TYPE size_t
+#endif
+ buf->len = BUF_LEN_TYPE(
+ (this->InputBuffer.data() + this->InputBuffer.size() - this->egptr()) *
+ sizeof(CharT));
+#undef BUF_LEN_TYPE
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVStreambuf<CharT, Traits>::StreamRead(ssize_t nread)
+{
+ if (nread > 0) {
+ this->setg(this->eback(), this->gptr(),
+ this->egptr() + nread / sizeof(CharT));
+ uv_read_stop(this->Stream);
+ } else if (nread < 0 /*|| nread == UV_EOF*/) {
+ this->EndOfFile = true;
+ uv_read_stop(this->Stream);
+ }
+}
+
+using cmUVStreambuf = cmBasicUVStreambuf<char>;
diff --git a/Source/cmUnsetCommand.cxx b/Source/cmUnsetCommand.cxx
new file mode 100644
index 0000000..3ba95e9
--- /dev/null
+++ b/Source/cmUnsetCommand.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 "cmUnsetCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+// cmUnsetCommand
+bool cmUnsetCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty() || args.size() > 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ auto const& variable = args[0];
+
+ // unset(ENV{VAR})
+ if (cmHasLiteralPrefix(variable, "ENV{") && variable.size() > 5) {
+ // what is the variable name
+ auto const& envVarName = variable.substr(4, variable.size() - 5);
+
+#ifndef CMAKE_BOOTSTRAP
+ cmSystemTools::UnsetEnv(envVarName.c_str());
+#endif
+ return true;
+ }
+ // unset(VAR)
+ if (args.size() == 1) {
+ status.GetMakefile().RemoveDefinition(variable);
+ return true;
+ }
+ // unset(VAR CACHE)
+ if ((args.size() == 2) && (args[1] == "CACHE")) {
+ status.GetMakefile().RemoveCacheDefinition(variable);
+ return true;
+ }
+ // unset(VAR PARENT_SCOPE)
+ if ((args.size() == 2) && (args[1] == "PARENT_SCOPE")) {
+ status.GetMakefile().RaiseScope(variable, nullptr);
+ return true;
+ }
+ // ERROR: second argument isn't CACHE or PARENT_SCOPE
+ status.SetError("called with an invalid second argument");
+ return false;
+}
diff --git a/Source/cmUnsetCommand.h b/Source/cmUnsetCommand.h
new file mode 100644
index 0000000..3faa053
--- /dev/null
+++ b/Source/cmUnsetCommand.h
@@ -0,0 +1,18 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Unset a CMAKE variable
+ *
+ * cmUnsetCommand unsets or removes a variable.
+ */
+bool cmUnsetCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmUseMangledMesaCommand.cxx b/Source/cmUseMangledMesaCommand.cxx
new file mode 100644
index 0000000..1fd386b
--- /dev/null
+++ b/Source/cmUseMangledMesaCommand.cxx
@@ -0,0 +1,103 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmUseMangledMesaCommand.h"
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmExecutionStatus.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+void CopyAndFullPathMesaHeader(const std::string& source,
+ const std::string& outdir);
+}
+
+bool cmUseMangledMesaCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // expected two arguments:
+ // argument one: the full path to gl_mangle.h
+ // argument two : directory for output of edited headers
+ if (args.size() != 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ const std::string& inputDir = args[0];
+ std::string glh = cmStrCat(inputDir, "/gl.h");
+ if (!cmSystemTools::FileExists(glh)) {
+ std::string e = cmStrCat("Bad path to Mesa, could not find: ", glh, ' ');
+ status.SetError(e);
+ return false;
+ }
+ const std::string& destDir = args[1];
+ std::vector<std::string> files;
+ cmSystemTools::Glob(inputDir, "\\.h$", files);
+ if (files.empty()) {
+ cmSystemTools::Error("Could not open Mesa Directory " + inputDir);
+ return false;
+ }
+ cmSystemTools::MakeDirectory(destDir);
+ for (std::string const& f : files) {
+ std::string path = cmStrCat(inputDir, '/', f);
+ CopyAndFullPathMesaHeader(path, destDir);
+ }
+
+ return true;
+}
+
+namespace {
+void CopyAndFullPathMesaHeader(const std::string& source,
+ const std::string& outdir)
+{
+ std::string dir;
+ std::string file;
+ cmSystemTools::SplitProgramPath(source, dir, file);
+ std::string outFile = cmStrCat(outdir, '/', file);
+ std::string tempOutputFile = cmStrCat(outFile, ".tmp");
+ cmsys::ofstream fout(tempOutputFile.c_str());
+ if (!fout) {
+ cmSystemTools::Error("Could not open file for write in copy operation: " +
+ tempOutputFile + outdir);
+ cmSystemTools::ReportLastSystemError("");
+ return;
+ }
+ cmsys::ifstream fin(source.c_str());
+ if (!fin) {
+ cmSystemTools::Error("Could not open file for read in copy operation" +
+ source);
+ return;
+ }
+ // now copy input to output and expand variables in the
+ // input file at the same time
+ std::string inLine;
+ // regular expression for any #include line
+ cmsys::RegularExpression includeLine(
+ "^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)[\">]");
+ // regular expression for gl/ or GL/ in a file (match(1) of above)
+ cmsys::RegularExpression glDirLine(R"((gl|GL)(/|\\)([^<"]+))");
+ // regular expression for gl GL or xmesa in a file (match(1) of above)
+ cmsys::RegularExpression glLine("(gl|GL|xmesa)");
+ while (cmSystemTools::GetLineFromStream(fin, inLine)) {
+ if (includeLine.find(inLine)) {
+ std::string includeFile = includeLine.match(1);
+ if (glDirLine.find(includeFile)) {
+ std::string gfile = glDirLine.match(3);
+ fout << "#include \"" << outdir << "/" << gfile << "\"\n";
+ } else if (glLine.find(includeFile)) {
+ fout << "#include \"" << outdir << "/" << includeLine.match(1)
+ << "\"\n";
+ } else {
+ fout << inLine << "\n";
+ }
+ } else {
+ fout << inLine << "\n";
+ }
+ }
+ // close the files before attempting to copy
+ fin.close();
+ fout.close();
+ cmSystemTools::MoveFileIfDifferent(tempOutputFile, outFile);
+}
+}
diff --git a/Source/cmUseMangledMesaCommand.h b/Source/cmUseMangledMesaCommand.h
new file mode 100644
index 0000000..5670c5d
--- /dev/null
+++ b/Source/cmUseMangledMesaCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmUseMangledMesaCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmUtilitySourceCommand.cxx b/Source/cmUtilitySourceCommand.cxx
new file mode 100644
index 0000000..d276c8a
--- /dev/null
+++ b/Source/cmUtilitySourceCommand.cxx
@@ -0,0 +1,118 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmUtilitySourceCommand.h"
+
+#include <cstring>
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+// cmUtilitySourceCommand
+bool cmUtilitySourceCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ auto arg = args.begin();
+
+ // The first argument is the cache entry name.
+ std::string const& cacheEntry = *arg++;
+ cmProp cacheValue = status.GetMakefile().GetDefinition(cacheEntry);
+ // If it exists already and appears up to date then we are done. If
+ // the string contains "(IntDir)" but that is not the
+ // CMAKE_CFG_INTDIR setting then the value is out of date.
+ std::string const& intDir =
+ status.GetMakefile().GetRequiredDefinition("CMAKE_CFG_INTDIR");
+
+ bool haveCacheValue = false;
+ if (status.GetMakefile().IsOn("CMAKE_CROSSCOMPILING")) {
+ haveCacheValue = (cacheValue != nullptr);
+ if (!haveCacheValue) {
+ std::string msg = cmStrCat(
+ "UTILITY_SOURCE is used in cross compiling mode for ", cacheEntry,
+ ". If your intention is to run this executable, you need to "
+ "preload the cache with the full path to a version of that "
+ "program, which runs on this build machine.");
+ cmSystemTools::Message(msg, "Warning");
+ }
+ } else {
+ cmState* state = status.GetMakefile().GetState();
+ haveCacheValue = (cacheValue &&
+ (strstr(cacheValue->c_str(), "(IntDir)") == nullptr ||
+ (intDir == "$(IntDir)")) &&
+ (state->GetCacheMajorVersion() != 0 &&
+ state->GetCacheMinorVersion() != 0));
+ }
+
+ if (haveCacheValue) {
+ return true;
+ }
+
+ // The second argument is the utility's executable name, which will be
+ // needed later.
+ std::string const& utilityName = *arg++;
+
+ // The third argument specifies the relative directory of the source
+ // of the utility.
+ std::string const& relativeSource = *arg++;
+ std::string utilitySource = status.GetMakefile().GetCurrentSourceDirectory();
+ utilitySource = utilitySource + "/" + relativeSource;
+
+ // If the directory doesn't exist, the source has not been included.
+ if (!cmSystemTools::FileExists(utilitySource)) {
+ return true;
+ }
+
+ // Make sure all the files exist in the source directory.
+ while (arg != args.end()) {
+ std::string file = utilitySource + "/" + *arg++;
+ if (!cmSystemTools::FileExists(file)) {
+ return true;
+ }
+ }
+
+ // The source exists.
+ const std::string& cmakeCFGout =
+ status.GetMakefile().GetRequiredDefinition("CMAKE_CFG_INTDIR");
+ std::string utilityDirectory =
+ status.GetMakefile().GetCurrentBinaryDirectory();
+ std::string exePath;
+ if (cmProp d =
+ status.GetMakefile().GetDefinition("EXECUTABLE_OUTPUT_PATH")) {
+ exePath = *d;
+ }
+ if (!exePath.empty()) {
+ utilityDirectory = exePath;
+ } else {
+ utilityDirectory += "/" + relativeSource;
+ }
+
+ // Construct the cache entry for the executable's location.
+ std::string utilityExecutable = utilityDirectory + "/" + cmakeCFGout + "/" +
+ utilityName +
+ *status.GetMakefile().GetDefinition("CMAKE_EXECUTABLE_SUFFIX");
+
+ // make sure we remove any /./ in the name
+ cmSystemTools::ReplaceString(utilityExecutable, "/./", "/");
+
+ // Enter the value into the cache.
+ status.GetMakefile().AddCacheDefinition(cacheEntry, utilityExecutable,
+ "Path to an internal program.",
+ cmStateEnums::FILEPATH);
+ // add a value into the cache that maps from the
+ // full path to the name of the project
+ cmSystemTools::ConvertToUnixSlashes(utilityExecutable);
+ status.GetMakefile().AddCacheDefinition(utilityExecutable, utilityName,
+ "Executable to project name.",
+ cmStateEnums::INTERNAL);
+
+ return true;
+}
diff --git a/Source/cmUtilitySourceCommand.h b/Source/cmUtilitySourceCommand.h
new file mode 100644
index 0000000..8cf7e7f
--- /dev/null
+++ b/Source/cmUtilitySourceCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmUtilitySourceCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmUtils.hxx b/Source/cmUtils.hxx
new file mode 100644
index 0000000..733e72f
--- /dev/null
+++ b/Source/cmUtils.hxx
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmsys/SystemTools.hxx"
+
+// Use the make system's VERBOSE environment variable to enable
+// verbose output. This can be skipped by also setting CMAKE_NO_VERBOSE
+// (which is set by the Eclipse generator).
+inline bool isCMakeVerbose()
+{
+ return (cmSystemTools::HasEnv("VERBOSE") &&
+ !cmSystemTools::HasEnv("CMAKE_NO_VERBOSE"));
+}
diff --git a/Source/cmUuid.cxx b/Source/cmUuid.cxx
new file mode 100644
index 0000000..2513303
--- /dev/null
+++ b/Source/cmUuid.cxx
@@ -0,0 +1,167 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmUuid.h"
+
+#include <array>
+#include <cstring>
+
+#include "cmCryptoHash.h"
+
+static const std::array<int, 5> kUuidGroups = { { 4, 2, 2, 2, 6 } };
+
+std::string cmUuid::FromMd5(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name) const
+{
+ std::vector<unsigned char> hashInput;
+ this->CreateHashInput(uuidNamespace, name, hashInput);
+
+ cmCryptoHash md5(cmCryptoHash::AlgoMD5);
+ md5.Initialize();
+ md5.Append(&hashInput[0], hashInput.size());
+ std::vector<unsigned char> digest = md5.Finalize();
+
+ return this->FromDigest(&digest[0], 3);
+}
+
+std::string cmUuid::FromSha1(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name) const
+{
+ std::vector<unsigned char> hashInput;
+ this->CreateHashInput(uuidNamespace, name, hashInput);
+
+ cmCryptoHash sha1(cmCryptoHash::AlgoSHA1);
+ sha1.Initialize();
+ sha1.Append(&hashInput[0], hashInput.size());
+ std::vector<unsigned char> digest = sha1.Finalize();
+
+ return this->FromDigest(&digest[0], 5);
+}
+
+void cmUuid::CreateHashInput(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name,
+ std::vector<unsigned char>& output) const
+{
+ output = uuidNamespace;
+
+ if (!name.empty()) {
+ output.resize(output.size() + name.size());
+
+ memcpy(&output[0] + uuidNamespace.size(), name.c_str(), name.size());
+ }
+}
+
+std::string cmUuid::FromDigest(const unsigned char* digest,
+ unsigned char version) const
+{
+ using byte_t = unsigned char;
+
+ byte_t uuid[16] = { 0 };
+ memcpy(uuid, digest, 16);
+
+ uuid[6] &= 0xF;
+ uuid[6] |= byte_t(version << 4);
+
+ uuid[8] &= 0x3F;
+ uuid[8] |= 0x80;
+
+ return this->BinaryToString(uuid);
+}
+
+bool cmUuid::StringToBinary(std::string const& input,
+ std::vector<unsigned char>& output) const
+{
+ output.clear();
+ output.reserve(16);
+
+ if (input.length() != 36) {
+ return false;
+ }
+ size_t index = 0;
+ for (size_t i = 0; i < kUuidGroups.size(); ++i) {
+ if (i != 0 && input[index++] != '-') {
+ return false;
+ }
+ size_t digits = kUuidGroups[i] * 2;
+ if (!this->StringToBinaryImpl(input.substr(index, digits), output)) {
+ return false;
+ }
+
+ index += digits;
+ }
+
+ return true;
+}
+
+std::string cmUuid::BinaryToString(const unsigned char* input) const
+{
+ std::string output;
+
+ size_t inputIndex = 0;
+ for (size_t i = 0; i < kUuidGroups.size(); ++i) {
+ if (i != 0) {
+ output += '-';
+ }
+
+ size_t bytes = kUuidGroups[i];
+ for (size_t j = 0; j < bytes; ++j) {
+ unsigned char byte = input[inputIndex++];
+ output += this->ByteToHex(byte);
+ }
+ }
+
+ return output;
+}
+
+std::string cmUuid::ByteToHex(unsigned char byte) const
+{
+ std::string result(" ");
+ for (int i = 0; i < 2; ++i) {
+ unsigned char rest = byte % 16;
+ byte /= 16;
+ char c = (rest < 0xA) ? char('0' + rest) : char('a' + (rest - 0xA));
+ result.at(1 - i) = c;
+ }
+
+ return result;
+}
+
+bool cmUuid::StringToBinaryImpl(std::string const& input,
+ std::vector<unsigned char>& output) const
+{
+ if (input.size() % 2) {
+ return false;
+ }
+
+ for (size_t i = 0; i < input.size(); i += 2) {
+ char c1 = 0;
+ if (!this->IntFromHexDigit(input[i], c1)) {
+ return false;
+ }
+
+ char c2 = 0;
+ if (!this->IntFromHexDigit(input[i + 1], c2)) {
+ return false;
+ }
+
+ output.push_back(char(c1 << 4 | c2));
+ }
+
+ return true;
+}
+
+bool cmUuid::IntFromHexDigit(char input, char& output) const
+{
+ if (input >= '0' && input <= '9') {
+ output = char(input - '0');
+ return true;
+ }
+ if (input >= 'a' && input <= 'f') {
+ output = char(input - 'a' + 0xA);
+ return true;
+ }
+ if (input >= 'A' && input <= 'F') {
+ output = char(input - 'A' + 0xA);
+ return true;
+ }
+ return false;
+}
diff --git a/Source/cmUuid.h b/Source/cmUuid.h
new file mode 100644
index 0000000..f5f724d
--- /dev/null
+++ b/Source/cmUuid.h
@@ -0,0 +1,42 @@
+/* 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 <string>
+#include <vector>
+
+/** \class cmUuid
+ * \brief Utility class to generate UUIDs as defined by RFC4122
+ *
+ */
+class cmUuid
+{
+public:
+ std::string FromMd5(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name) const;
+
+ std::string FromSha1(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name) const;
+
+ bool StringToBinary(std::string const& input,
+ std::vector<unsigned char>& output) const;
+
+private:
+ std::string ByteToHex(unsigned char byte) const;
+
+ void CreateHashInput(std::vector<unsigned char> const& uuidNamespace,
+ std::string const& name,
+ std::vector<unsigned char>& output) const;
+
+ std::string FromDigest(const unsigned char* digest,
+ unsigned char version) const;
+
+ bool StringToBinaryImpl(std::string const& input,
+ std::vector<unsigned char>& output) const;
+
+ std::string BinaryToString(const unsigned char* input) const;
+
+ bool IntFromHexDigit(char input, char& output) const;
+};
diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx
new file mode 100644
index 0000000..9626599
--- /dev/null
+++ b/Source/cmVSSetupHelper.cxx
@@ -0,0 +1,493 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmVSSetupHelper.h"
+
+#include "cmsys/Encoding.hxx"
+#include "cmsys/FStream.hxx"
+
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+#ifndef VSSetupConstants
+# define VSSetupConstants
+/* clang-format off */
+const IID IID_ISetupConfiguration = {
+ 0x42843719, 0xDB4C, 0x46C2,
+ { 0x8E, 0x7C, 0x64, 0xF1, 0x81, 0x6E, 0xFD, 0x5B }
+};
+const IID IID_ISetupConfiguration2 = {
+ 0x26AAB78C, 0x4A60, 0x49D6,
+ { 0xAF, 0x3B, 0x3C, 0x35, 0xBC, 0x93, 0x36, 0x5D }
+};
+const IID IID_ISetupPackageReference = {
+ 0xda8d8a16, 0xb2b6, 0x4487,
+ { 0xa2, 0xf1, 0x59, 0x4c, 0xcc, 0xcd, 0x6b, 0xf5 }
+};
+const IID IID_ISetupHelper = {
+ 0x42b21b78, 0x6192, 0x463e,
+ { 0x87, 0xbf, 0xd5, 0x77, 0x83, 0x8f, 0x1d, 0x5c }
+};
+const IID IID_IEnumSetupInstances = {
+ 0x6380BCFF, 0x41D3, 0x4B2E,
+ { 0x8B, 0x2E, 0xBF, 0x8A, 0x68, 0x10, 0xC8, 0x48 }
+};
+const IID IID_ISetupInstance2 = {
+ 0x89143C9A, 0x05AF, 0x49B0,
+ { 0xB7, 0x17, 0x72, 0xE2, 0x18, 0xA2, 0x18, 0x5C }
+};
+const IID IID_ISetupInstance = {
+ 0xB41463C3, 0x8866, 0x43B5,
+ { 0xBC, 0x33, 0x2B, 0x06, 0x76, 0xF7, 0xF4, 0x2E }
+};
+const CLSID CLSID_SetupConfiguration = {
+ 0x177F0C4A, 0x1CD3, 0x4DE7,
+ { 0xA3, 0x2C, 0x71, 0xDB, 0xBB, 0x9F, 0xA3, 0x6D }
+};
+/* clang-format on */
+#endif
+
+const WCHAR* Win10SDKComponent =
+ L"Microsoft.VisualStudio.Component.Windows10SDK";
+const WCHAR* Win81SDKComponent =
+ L"Microsoft.VisualStudio.Component.Windows81SDK";
+const WCHAR* ComponentType = L"Component";
+
+std::string VSInstanceInfo::GetInstallLocation() const
+{
+ std::string loc = cmsys::Encoding::ToNarrow(this->VSInstallLocation);
+ cmSystemTools::ConvertToUnixSlashes(loc);
+ return loc;
+}
+
+cmVSSetupAPIHelper::cmVSSetupAPIHelper(unsigned int version)
+ : Version(version)
+ , setupConfig(NULL)
+ , setupConfig2(NULL)
+ , setupHelper(NULL)
+ , initializationFailure(false)
+{
+ comInitialized = CoInitializeEx(NULL, 0);
+ if (SUCCEEDED(comInitialized)) {
+ Initialize();
+ } else {
+ initializationFailure = true;
+ }
+}
+
+cmVSSetupAPIHelper::~cmVSSetupAPIHelper()
+{
+ setupHelper = NULL;
+ setupConfig2 = NULL;
+ setupConfig = NULL;
+ if (SUCCEEDED(comInitialized))
+ CoUninitialize();
+}
+
+bool cmVSSetupAPIHelper::SetVSInstance(std::string const& vsInstallLocation)
+{
+ this->SpecifiedVSInstallLocation = vsInstallLocation;
+ cmSystemTools::ConvertToUnixSlashes(this->SpecifiedVSInstallLocation);
+ chosenInstanceInfo = VSInstanceInfo();
+ return this->EnumerateAndChooseVSInstance();
+}
+
+bool cmVSSetupAPIHelper::IsVSInstalled()
+{
+ return this->EnumerateAndChooseVSInstance();
+}
+
+bool cmVSSetupAPIHelper::IsWin10SDKInstalled()
+{
+ return (this->EnumerateAndChooseVSInstance() &&
+ chosenInstanceInfo.IsWin10SDKInstalled);
+}
+
+bool cmVSSetupAPIHelper::IsWin81SDKInstalled()
+{
+ return (this->EnumerateAndChooseVSInstance() &&
+ chosenInstanceInfo.IsWin81SDKInstalled);
+}
+
+bool cmVSSetupAPIHelper::CheckInstalledComponent(
+ SmartCOMPtr<ISetupPackageReference> package, bool& bWin10SDK,
+ bool& bWin81SDK)
+{
+ bool ret = false;
+ bWin10SDK = bWin81SDK = false;
+ SmartBSTR bstrId;
+ if (FAILED(package->GetId(&bstrId))) {
+ return ret;
+ }
+
+ SmartBSTR bstrType;
+ if (FAILED(package->GetType(&bstrType))) {
+ return ret;
+ }
+
+ std::wstring id = std::wstring(bstrId);
+ std::wstring type = std::wstring(bstrType);
+
+ // Checks for any version of Win10 SDK. The version is appended at the end of
+ // the
+ // component name ex: Microsoft.VisualStudio.Component.Windows10SDK.10240
+ if (id.find(Win10SDKComponent) != std::wstring::npos &&
+ type.compare(ComponentType) == 0) {
+ bWin10SDK = true;
+ ret = true;
+ }
+
+ if (id.compare(Win81SDKComponent) == 0 && type.compare(ComponentType) == 0) {
+ bWin81SDK = true;
+ ret = true;
+ }
+
+ return ret;
+}
+
+// Gather additional info such as if VCToolset, WinSDKs are installed, location
+// of VS and version information.
+bool cmVSSetupAPIHelper::GetVSInstanceInfo(
+ SmartCOMPtr<ISetupInstance2> pInstance, VSInstanceInfo& vsInstanceInfo)
+{
+ if (pInstance == NULL)
+ return false;
+
+ SmartBSTR bstrId;
+ if (SUCCEEDED(pInstance->GetInstanceId(&bstrId))) {
+ vsInstanceInfo.InstanceId = std::wstring(bstrId);
+ } else {
+ return false;
+ }
+
+ InstanceState state;
+ if (FAILED(pInstance->GetState(&state))) {
+ return false;
+ }
+
+ ULONGLONG ullVersion = 0;
+ SmartBSTR bstrVersion;
+ if (FAILED(pInstance->GetInstallationVersion(&bstrVersion))) {
+ return false;
+ } else {
+ vsInstanceInfo.Version = std::wstring(bstrVersion);
+ if (FAILED(setupHelper->ParseVersion(bstrVersion, &ullVersion))) {
+ vsInstanceInfo.ullVersion = 0;
+ } else {
+ vsInstanceInfo.ullVersion = ullVersion;
+ }
+ }
+
+ // Reboot may have been required before the installation path was created.
+ SmartBSTR bstrInstallationPath;
+ if ((eLocal & state) == eLocal) {
+ if (FAILED(pInstance->GetInstallationPath(&bstrInstallationPath))) {
+ return false;
+ } else {
+ vsInstanceInfo.VSInstallLocation = std::wstring(bstrInstallationPath);
+ }
+ }
+
+ // Check if a compiler is installed with this instance.
+ {
+ std::string const vcRoot = vsInstanceInfo.GetInstallLocation();
+ std::string vcToolsVersionFile =
+ vcRoot + "/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt";
+ std::string vcToolsVersion;
+ cmsys::ifstream fin(vcToolsVersionFile.c_str());
+ if (!fin || !cmSystemTools::GetLineFromStream(fin, vcToolsVersion)) {
+ return false;
+ }
+ vcToolsVersion = cmTrimWhitespace(vcToolsVersion);
+ std::string const vcToolsDir = vcRoot + "/VC/Tools/MSVC/" + vcToolsVersion;
+ if (!cmSystemTools::FileIsDirectory(vcToolsDir)) {
+ return false;
+ }
+ vsInstanceInfo.VCToolsetVersion = vcToolsVersion;
+ }
+
+ // Reboot may have been required before the product package was registered
+ // (last).
+ if ((eRegistered & state) == eRegistered) {
+ SmartCOMPtr<ISetupPackageReference> product;
+ if (FAILED(pInstance->GetProduct(&product)) || !product) {
+ return false;
+ }
+
+ LPSAFEARRAY lpsaPackages;
+ if (FAILED(pInstance->GetPackages(&lpsaPackages)) ||
+ lpsaPackages == NULL) {
+ return false;
+ }
+
+ int lower = lpsaPackages->rgsabound[0].lLbound;
+ int upper = lpsaPackages->rgsabound[0].cElements + lower;
+
+ IUnknown** ppData = (IUnknown**)lpsaPackages->pvData;
+ for (int i = lower; i < upper; i++) {
+ SmartCOMPtr<ISetupPackageReference> package = NULL;
+ if (FAILED(ppData[i]->QueryInterface(IID_ISetupPackageReference,
+ (void**)&package)) ||
+ package == NULL)
+ continue;
+
+ bool win10SDKInstalled = false;
+ bool win81SDkInstalled = false;
+ bool ret =
+ CheckInstalledComponent(package, win10SDKInstalled, win81SDkInstalled);
+ if (ret) {
+ vsInstanceInfo.IsWin10SDKInstalled |= win10SDKInstalled;
+ vsInstanceInfo.IsWin81SDKInstalled |= win81SDkInstalled;
+ }
+ }
+
+ SafeArrayDestroy(lpsaPackages);
+ }
+
+ return true;
+}
+
+bool cmVSSetupAPIHelper::GetVSInstanceInfo(std::string& vsInstallLocation)
+{
+ vsInstallLocation.clear();
+ bool isInstalled = this->EnumerateAndChooseVSInstance();
+
+ if (isInstalled) {
+ vsInstallLocation = chosenInstanceInfo.GetInstallLocation();
+ }
+
+ return isInstalled;
+}
+
+bool cmVSSetupAPIHelper::GetVSInstanceVersion(
+ unsigned long long& vsInstanceVersion)
+{
+ vsInstanceVersion = 0;
+ bool isInstalled = this->EnumerateAndChooseVSInstance();
+
+ if (isInstalled) {
+ vsInstanceVersion =
+ static_cast<unsigned long long>(chosenInstanceInfo.ullVersion);
+ }
+
+ return isInstalled;
+}
+
+bool cmVSSetupAPIHelper::GetVCToolsetVersion(std::string& vsToolsetVersion)
+{
+ vsToolsetVersion.clear();
+ bool isInstalled = this->EnumerateAndChooseVSInstance();
+
+ if (isInstalled) {
+ vsToolsetVersion = chosenInstanceInfo.VCToolsetVersion;
+ }
+
+ return isInstalled && !vsToolsetVersion.empty();
+}
+
+bool cmVSSetupAPIHelper::IsEWDKEnabled()
+{
+ std::string envEnterpriseWDK, envDisableRegistryUse;
+ cmSystemTools::GetEnv("EnterpriseWDK", envEnterpriseWDK);
+ cmSystemTools::GetEnv("DisableRegistryUse", envDisableRegistryUse);
+ if (!cmSystemTools::Strucmp(envEnterpriseWDK.c_str(), "True") &&
+ !cmSystemTools::Strucmp(envDisableRegistryUse.c_str(), "True")) {
+ return true;
+ }
+
+ return false;
+}
+
+bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance()
+{
+ bool isVSInstanceExists = false;
+ if (chosenInstanceInfo.VSInstallLocation.compare(L"") != 0) {
+ return true;
+ }
+
+ if (this->IsEWDKEnabled()) {
+ std::string envWindowsSdkDir81, envVSVersion, envVsInstallDir;
+
+ cmSystemTools::GetEnv("WindowsSdkDir_81", envWindowsSdkDir81);
+ cmSystemTools::GetEnv("VisualStudioVersion", envVSVersion);
+ cmSystemTools::GetEnv("VSINSTALLDIR", envVsInstallDir);
+ if (envVSVersion.empty() || envVsInstallDir.empty())
+ return false;
+
+ chosenInstanceInfo.VSInstallLocation =
+ std::wstring(envVsInstallDir.begin(), envVsInstallDir.end());
+ chosenInstanceInfo.Version =
+ std::wstring(envVSVersion.begin(), envVSVersion.end());
+ chosenInstanceInfo.VCToolsetVersion = envVSVersion;
+ chosenInstanceInfo.ullVersion = std::stoi(envVSVersion);
+ chosenInstanceInfo.IsWin10SDKInstalled = true;
+ chosenInstanceInfo.IsWin81SDKInstalled = !envWindowsSdkDir81.empty();
+ return true;
+ }
+
+ if (initializationFailure || setupConfig == NULL || setupConfig2 == NULL ||
+ setupHelper == NULL)
+ return false;
+
+ std::string envVSCommonToolsDir;
+ std::string envVSCommonToolsDirEnvName =
+ "VS" + std::to_string(this->Version) + "0COMNTOOLS";
+
+ if (cmSystemTools::GetEnv(envVSCommonToolsDirEnvName.c_str(),
+ envVSCommonToolsDir)) {
+ cmSystemTools::ConvertToUnixSlashes(envVSCommonToolsDir);
+ }
+
+ std::vector<VSInstanceInfo> vecVSInstances;
+ SmartCOMPtr<IEnumSetupInstances> enumInstances = NULL;
+ if (FAILED(
+ setupConfig2->EnumInstances((IEnumSetupInstances**)&enumInstances)) ||
+ !enumInstances) {
+ return false;
+ }
+
+ std::wstring const wantVersion = std::to_wstring(this->Version) + L'.';
+
+ SmartCOMPtr<ISetupInstance> instance;
+ while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) {
+ SmartCOMPtr<ISetupInstance2> instance2 = NULL;
+ if (FAILED(
+ instance->QueryInterface(IID_ISetupInstance2, (void**)&instance2)) ||
+ !instance2) {
+ instance = NULL;
+ continue;
+ }
+
+ VSInstanceInfo instanceInfo;
+ bool isInstalled = GetVSInstanceInfo(instance2, instanceInfo);
+ instance = instance2 = NULL;
+
+ if (isInstalled) {
+ // We are looking for a specific major version.
+ if (instanceInfo.Version.size() < wantVersion.size() ||
+ instanceInfo.Version.substr(0, wantVersion.size()) != wantVersion) {
+ continue;
+ }
+
+ if (!this->SpecifiedVSInstallLocation.empty()) {
+ // We are looking for a specific instance.
+ std::string currentVSLocation = instanceInfo.GetInstallLocation();
+ if (cmSystemTools::ComparePath(currentVSLocation,
+ this->SpecifiedVSInstallLocation)) {
+ chosenInstanceInfo = instanceInfo;
+ return true;
+ }
+ } else {
+ // We are not looking for a specific instance.
+ // If we've been given a hint then use it.
+ if (!envVSCommonToolsDir.empty()) {
+ std::string currentVSLocation =
+ cmStrCat(instanceInfo.GetInstallLocation(), "/Common7/Tools");
+ if (cmSystemTools::ComparePath(currentVSLocation,
+ envVSCommonToolsDir)) {
+ chosenInstanceInfo = instanceInfo;
+ return true;
+ }
+ }
+ // Otherwise, add this to the list of candidates.
+ vecVSInstances.push_back(instanceInfo);
+ }
+ }
+ }
+
+ if (vecVSInstances.size() > 0) {
+ isVSInstanceExists = true;
+ int index = ChooseVSInstance(vecVSInstances);
+ chosenInstanceInfo = vecVSInstances[index];
+ }
+
+ return isVSInstanceExists;
+}
+
+int cmVSSetupAPIHelper::ChooseVSInstance(
+ const std::vector<VSInstanceInfo>& vecVSInstances)
+{
+ if (vecVSInstances.size() == 0)
+ return -1;
+
+ if (vecVSInstances.size() == 1)
+ return 0;
+
+ unsigned int chosenIndex = 0;
+ for (unsigned int i = 1; i < vecVSInstances.size(); i++) {
+ // If the current has Win10 SDK but not the chosen one, then choose the
+ // current VS instance
+ if (!vecVSInstances[chosenIndex].IsWin10SDKInstalled &&
+ vecVSInstances[i].IsWin10SDKInstalled) {
+ chosenIndex = i;
+ continue;
+ }
+
+ // If the chosen one has Win10 SDK but the current one is not, then look at
+ // the next VS instance even the current
+ // instance version may be higher
+ if (vecVSInstances[chosenIndex].IsWin10SDKInstalled &&
+ !vecVSInstances[i].IsWin10SDKInstalled) {
+ continue;
+ }
+
+ // If both chosen one and current one doesn't have Win10 SDK but the
+ // current one has Win8.1 SDK installed,
+ // then choose the current one
+ if (!vecVSInstances[chosenIndex].IsWin10SDKInstalled &&
+ !vecVSInstances[i].IsWin10SDKInstalled &&
+ !vecVSInstances[chosenIndex].IsWin81SDKInstalled &&
+ vecVSInstances[i].IsWin81SDKInstalled) {
+ chosenIndex = i;
+ continue;
+ }
+
+ // If there is no difference in WinSDKs then look for the highest version
+ // of installed VS
+ if ((vecVSInstances[chosenIndex].IsWin10SDKInstalled ==
+ vecVSInstances[i].IsWin10SDKInstalled) &&
+ (vecVSInstances[chosenIndex].IsWin81SDKInstalled ==
+ vecVSInstances[i].IsWin81SDKInstalled) &&
+ vecVSInstances[chosenIndex].Version < vecVSInstances[i].Version) {
+ chosenIndex = i;
+ continue;
+ }
+ }
+
+ return chosenIndex;
+}
+
+bool cmVSSetupAPIHelper::Initialize()
+{
+ if (initializationFailure)
+ return false;
+
+ if (FAILED(comInitialized)) {
+ initializationFailure = true;
+ return false;
+ }
+
+ if (FAILED(setupConfig.CoCreateInstance(CLSID_SetupConfiguration, NULL,
+ IID_ISetupConfiguration,
+ CLSCTX_INPROC_SERVER)) ||
+ setupConfig == NULL) {
+ initializationFailure = true;
+ return false;
+ }
+
+ if (FAILED(setupConfig.QueryInterface(IID_ISetupConfiguration2,
+ (void**)&setupConfig2)) ||
+ setupConfig2 == NULL) {
+ initializationFailure = true;
+ return false;
+ }
+
+ if (FAILED(
+ setupConfig.QueryInterface(IID_ISetupHelper, (void**)&setupHelper)) ||
+ setupHelper == NULL) {
+ initializationFailure = true;
+ return false;
+ }
+
+ initializationFailure = false;
+ return true;
+}
diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h
new file mode 100644
index 0000000..04ea46d
--- /dev/null
+++ b/Source/cmVSSetupHelper.h
@@ -0,0 +1,137 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#ifndef NOMINMAX
+# define NOMINMAX // Undefine min and max defined by windows.h
+#endif
+
+// Published by Visual Studio Setup team
+#include <cm3p/Setup.Configuration.h>
+#include <string>
+#include <vector>
+
+#include <windows.h>
+
+template <class T>
+class SmartCOMPtr
+{
+public:
+ SmartCOMPtr() { ptr = NULL; }
+ SmartCOMPtr(T* p)
+ {
+ ptr = p;
+ if (ptr != NULL)
+ ptr->AddRef();
+ }
+ SmartCOMPtr(const SmartCOMPtr<T>& sptr)
+ {
+ ptr = sptr.ptr;
+ if (ptr != NULL)
+ ptr->AddRef();
+ }
+ T** operator&() { return &ptr; }
+ T* operator->() { return ptr; }
+ T* operator=(T* p)
+ {
+ if (*this != p) {
+ ptr = p;
+ if (ptr != NULL)
+ ptr->AddRef();
+ }
+ return *this;
+ }
+ operator T*() const { return ptr; }
+ template <class I>
+ HRESULT QueryInterface(REFCLSID rclsid, I** pp)
+ {
+ if (pp != NULL) {
+ return ptr->QueryInterface(rclsid, (void**)pp);
+ } else {
+ return E_FAIL;
+ }
+ }
+ HRESULT CoCreateInstance(REFCLSID clsid, IUnknown* pUnknown,
+ REFIID interfaceId, DWORD dwClsContext = CLSCTX_ALL)
+ {
+ HRESULT hr = ::CoCreateInstance(clsid, pUnknown, dwClsContext, interfaceId,
+ (void**)&ptr);
+ return hr;
+ }
+ ~SmartCOMPtr()
+ {
+ if (ptr != NULL)
+ ptr->Release();
+ }
+
+private:
+ T* ptr;
+};
+
+class SmartBSTR
+{
+public:
+ SmartBSTR() { str = NULL; }
+ SmartBSTR(const SmartBSTR& src) = delete;
+ SmartBSTR& operator=(const SmartBSTR& src) = delete;
+ operator BSTR() const { return str; }
+ BSTR* operator&() throw() { return &str; }
+ ~SmartBSTR() throw() { ::SysFreeString(str); }
+
+private:
+ BSTR str;
+};
+
+struct VSInstanceInfo
+{
+ std::wstring InstanceId;
+ std::wstring VSInstallLocation;
+ std::wstring Version;
+ std::string VCToolsetVersion;
+ ULONGLONG ullVersion = 0;
+ bool IsWin10SDKInstalled = false;
+ bool IsWin81SDKInstalled = false;
+
+ std::string GetInstallLocation() const;
+};
+
+class cmVSSetupAPIHelper
+{
+public:
+ cmVSSetupAPIHelper(unsigned int version);
+ ~cmVSSetupAPIHelper();
+
+ bool SetVSInstance(std::string const& vsInstallLocation);
+
+ bool IsVSInstalled();
+ bool GetVSInstanceInfo(std::string& vsInstallLocation);
+ bool GetVSInstanceVersion(unsigned long long& vsInstanceVersion);
+ bool GetVCToolsetVersion(std::string& vsToolsetVersion);
+ bool IsWin10SDKInstalled();
+ bool IsWin81SDKInstalled();
+
+private:
+ bool Initialize();
+ bool GetVSInstanceInfo(SmartCOMPtr<ISetupInstance2> instance2,
+ VSInstanceInfo& vsInstanceInfo);
+ bool CheckInstalledComponent(SmartCOMPtr<ISetupPackageReference> package,
+ bool& bWin10SDK, bool& bWin81SDK);
+ int ChooseVSInstance(const std::vector<VSInstanceInfo>& vecVSInstances);
+ bool EnumerateAndChooseVSInstance();
+
+ unsigned int Version;
+
+ // COM ptrs to query about VS instances
+ SmartCOMPtr<ISetupConfiguration> setupConfig;
+ SmartCOMPtr<ISetupConfiguration2> setupConfig2;
+ SmartCOMPtr<ISetupHelper> setupHelper;
+ // used to indicate failure in Initialize(), so we don't have to call again
+ bool initializationFailure;
+ // indicated if COM initialization is successful
+ HRESULT comInitialized;
+ // current best instance of VS selected
+ VSInstanceInfo chosenInstanceInfo;
+ bool IsEWDKEnabled();
+
+ std::string SpecifiedVSInstallLocation;
+};
diff --git a/Source/cmVariableRequiresCommand.cxx b/Source/cmVariableRequiresCommand.cxx
new file mode 100644
index 0000000..1fe03ab
--- /dev/null
+++ b/Source/cmVariableRequiresCommand.cxx
@@ -0,0 +1,64 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmVariableRequiresCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+// cmLibraryCommand
+bool cmVariableRequiresCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 3) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ std::string const& testVariable = args[0];
+ if (!status.GetMakefile().IsOn(testVariable)) {
+ return true;
+ }
+ std::string const& resultVariable = args[1];
+ bool requirementsMet = true;
+ std::string notSet;
+ bool hasAdvanced = false;
+ cmState* state = status.GetMakefile().GetState();
+ for (unsigned int i = 2; i < args.size(); ++i) {
+ if (!status.GetMakefile().IsOn(args[i])) {
+ requirementsMet = false;
+ notSet += args[i];
+ notSet += "\n";
+ if (state->GetCacheEntryValue(args[i]) &&
+ state->GetCacheEntryPropertyAsBool(args[i], "ADVANCED")) {
+ hasAdvanced = true;
+ }
+ }
+ }
+ cmProp reqVar = status.GetMakefile().GetDefinition(resultVariable);
+ // if reqVar is unset, then set it to requirementsMet
+ // if reqVar is set to true, but requirementsMet is false , then
+ // set reqVar to false.
+ if (!reqVar || (!requirementsMet && status.GetMakefile().IsOn(*reqVar))) {
+ status.GetMakefile().AddDefinitionBool(resultVariable, requirementsMet);
+ }
+
+ if (!requirementsMet) {
+ std::string message =
+ cmStrCat("Variable assertion failed:\n", testVariable,
+ " Requires that the following unset variables are set:\n",
+ notSet, "\nPlease set them, or set ", testVariable,
+ " to false, and re-configure.\n");
+ if (hasAdvanced) {
+ message +=
+ "One or more of the required variables is advanced."
+ " To set the variable, you must turn on advanced mode in cmake.";
+ }
+ cmSystemTools::Error(message);
+ }
+
+ return true;
+}
diff --git a/Source/cmVariableRequiresCommand.h b/Source/cmVariableRequiresCommand.h
new file mode 100644
index 0000000..c6bfe8a
--- /dev/null
+++ b/Source/cmVariableRequiresCommand.h
@@ -0,0 +1,13 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+bool cmVariableRequiresCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmVariableWatch.cxx b/Source/cmVariableWatch.cxx
new file mode 100644
index 0000000..35e1c8c
--- /dev/null
+++ b/Source/cmVariableWatch.cxx
@@ -0,0 +1,86 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmVariableWatch.h"
+
+#include <array>
+#include <memory>
+#include <utility>
+#include <vector>
+
+const std::string& cmVariableWatch::GetAccessAsString(int access_type)
+{
+ static const std::array<std::string, 6> cmVariableWatchAccessStrings = {
+ { "READ_ACCESS", "UNKNOWN_READ_ACCESS", "UNKNOWN_DEFINED_ACCESS",
+ "MODIFIED_ACCESS", "REMOVED_ACCESS", "NO_ACCESS" }
+ };
+ if (access_type < 0 || access_type >= cmVariableWatch::NO_ACCESS) {
+ access_type = cmVariableWatch::NO_ACCESS;
+ }
+ return cmVariableWatchAccessStrings[access_type];
+}
+
+cmVariableWatch::cmVariableWatch() = default;
+
+cmVariableWatch::~cmVariableWatch() = default;
+
+bool cmVariableWatch::AddWatch(const std::string& variable, WatchMethod method,
+ void* client_data /*=0*/,
+ DeleteData delete_data /*=0*/)
+{
+ auto p = std::make_shared<cmVariableWatch::Pair>();
+ p->Method = method;
+ p->ClientData = client_data;
+ p->DeleteDataCall = delete_data;
+ cmVariableWatch::VectorOfPairs& vp = this->WatchMap[variable];
+ for (auto& pair : vp) {
+ if (pair->Method == method && client_data &&
+ client_data == pair->ClientData) {
+ // Callback already exists
+ return false;
+ }
+ }
+ vp.push_back(std::move(p));
+ return true;
+}
+
+void cmVariableWatch::RemoveWatch(const std::string& variable,
+ WatchMethod method, void* client_data /*=0*/)
+{
+ if (!this->WatchMap.count(variable)) {
+ return;
+ }
+ cmVariableWatch::VectorOfPairs* vp = &this->WatchMap[variable];
+ cmVariableWatch::VectorOfPairs::iterator it;
+ for (it = vp->begin(); it != vp->end(); ++it) {
+ if ((*it)->Method == method &&
+ // If client_data is NULL, we want to disconnect all watches against
+ // the given method; otherwise match ClientData as well.
+ (!client_data || (client_data == (*it)->ClientData))) {
+ vp->erase(it);
+ return;
+ }
+ }
+}
+
+bool cmVariableWatch::VariableAccessed(const std::string& variable,
+ int access_type, const char* newValue,
+ const cmMakefile* mf) const
+{
+ auto mit = this->WatchMap.find(variable);
+ if (mit != this->WatchMap.end()) {
+ // The strategy here is to copy the list of callbacks, and ignore
+ // new callbacks that existing ones may add.
+ std::vector<std::weak_ptr<Pair>> vp(mit->second.begin(),
+ mit->second.end());
+ for (auto& weak_it : vp) {
+ // In the case where a callback was removed, the weak_ptr will not be
+ // lockable, and so this ensures we don't attempt to call into freed
+ // memory
+ if (auto it = weak_it.lock()) {
+ it->Method(variable, access_type, it->ClientData, newValue, mf);
+ }
+ }
+ return true;
+ }
+ return false;
+}
diff --git a/Source/cmVariableWatch.h b/Source/cmVariableWatch.h
new file mode 100644
index 0000000..349ce0e
--- /dev/null
+++ b/Source/cmVariableWatch.h
@@ -0,0 +1,82 @@
+/* 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 <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+class cmMakefile;
+
+/** \class cmVariableWatch
+ * \brief Helper class for watching of variable accesses.
+ *
+ * Calls function when variable is accessed
+ */
+class cmVariableWatch
+{
+public:
+ using WatchMethod = void (*)(const std::string&, int, void*, const char*,
+ const cmMakefile*);
+ using DeleteData = void (*)(void*);
+
+ cmVariableWatch();
+ ~cmVariableWatch();
+
+ /**
+ * Add watch to the variable
+ */
+ bool AddWatch(const std::string& variable, WatchMethod method,
+ void* client_data = nullptr, DeleteData delete_data = nullptr);
+ void RemoveWatch(const std::string& variable, WatchMethod method,
+ void* client_data = nullptr);
+
+ /**
+ * This method is called when variable is accessed
+ */
+ bool VariableAccessed(const std::string& variable, int access_type,
+ const char* newValue, const cmMakefile* mf) const;
+
+ /**
+ * Different access types.
+ */
+ enum
+ {
+ VARIABLE_READ_ACCESS,
+ UNKNOWN_VARIABLE_READ_ACCESS,
+ UNKNOWN_VARIABLE_DEFINED_ACCESS,
+ VARIABLE_MODIFIED_ACCESS,
+ VARIABLE_REMOVED_ACCESS,
+ NO_ACCESS
+ };
+
+ /**
+ * Return the access as string
+ */
+ static const std::string& GetAccessAsString(int access_type);
+
+protected:
+ struct Pair
+ {
+ WatchMethod Method = nullptr;
+ void* ClientData = nullptr;
+ DeleteData DeleteDataCall = nullptr;
+ ~Pair()
+ {
+ if (this->DeleteDataCall && this->ClientData) {
+ this->DeleteDataCall(this->ClientData);
+ }
+ }
+ Pair() = default;
+ Pair(const Pair&) = delete;
+ Pair& operator=(const Pair&) = delete;
+ };
+
+ using VectorOfPairs = std::vector<std::shared_ptr<Pair>>;
+ using StringToVectorOfPairs = std::map<std::string, VectorOfPairs>;
+
+ StringToVectorOfPairs WatchMap;
+};
diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx
new file mode 100644
index 0000000..7c7fbca
--- /dev/null
+++ b/Source/cmVariableWatchCommand.cxx
@@ -0,0 +1,155 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmVariableWatchCommand.h"
+
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "cmExecutionStatus.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmVariableWatch.h"
+#include "cmake.h"
+
+class cmLocalGenerator;
+
+namespace {
+struct cmVariableWatchCallbackData
+{
+ bool InCallback;
+ std::string Command;
+};
+
+void cmVariableWatchCommandVariableAccessed(const std::string& variable,
+ int access_type, void* client_data,
+ const char* newValue,
+ const cmMakefile* mf)
+{
+ cmVariableWatchCallbackData* data =
+ static_cast<cmVariableWatchCallbackData*>(client_data);
+
+ if (data->InCallback) {
+ return;
+ }
+ data->InCallback = true;
+
+ auto accessString = cmVariableWatch::GetAccessAsString(access_type);
+
+ /// Ultra bad!!
+ cmMakefile* makefile = const_cast<cmMakefile*>(mf);
+
+ std::string stack = *mf->GetProperty("LISTFILE_STACK");
+ if (!data->Command.empty()) {
+ cmProp const currentListFile =
+ mf->GetDefinition("CMAKE_CURRENT_LIST_FILE");
+ const auto fakeLineNo =
+ std::numeric_limits<decltype(cmListFileArgument::Line)>::max();
+
+ std::vector<cmListFileArgument> newLFFArgs{
+ { variable, cmListFileArgument::Quoted, fakeLineNo },
+ { accessString, cmListFileArgument::Quoted, fakeLineNo },
+ { newValue ? newValue : "", cmListFileArgument::Quoted, fakeLineNo },
+ { *currentListFile, cmListFileArgument::Quoted, fakeLineNo },
+ { stack, cmListFileArgument::Quoted, fakeLineNo }
+ };
+
+ cmListFileFunction newLFF{ data->Command, fakeLineNo,
+ std::move(newLFFArgs) };
+ cmExecutionStatus status(*makefile);
+ if (!makefile->ExecuteCommand(newLFF, status)) {
+ cmSystemTools::Error(
+ cmStrCat("Error in cmake code at\nUnknown:0:\nA command failed "
+ "during the invocation of callback \"",
+ data->Command, "\"."));
+ }
+ } else {
+ makefile->IssueMessage(
+ MessageType::LOG,
+ cmStrCat("Variable \"", variable, "\" was accessed using ", accessString,
+ " with value \"", (newValue ? newValue : ""), "\"."));
+ }
+
+ data->InCallback = false;
+}
+
+void deleteVariableWatchCallbackData(void* client_data)
+{
+ cmVariableWatchCallbackData* data =
+ static_cast<cmVariableWatchCallbackData*>(client_data);
+ delete data;
+}
+
+/** This command does not really have a final pass but it needs to
+ stay alive since it owns variable watch callback information. */
+class FinalAction
+{
+public:
+ /* NOLINTNEXTLINE(performance-unnecessary-value-param) */
+ FinalAction(cmMakefile* makefile, std::string variable)
+ : Action{ std::make_shared<Impl>(makefile, std::move(variable)) }
+ {
+ }
+
+ void operator()(cmLocalGenerator&, const cmListFileBacktrace&) const {}
+
+private:
+ struct Impl
+ {
+ Impl(cmMakefile* makefile, std::string variable)
+ : Makefile{ makefile }
+ , Variable{ std::move(variable) }
+ {
+ }
+
+ ~Impl()
+ {
+ this->Makefile->GetCMakeInstance()->GetVariableWatch()->RemoveWatch(
+ this->Variable, cmVariableWatchCommandVariableAccessed);
+ }
+
+ cmMakefile* const Makefile;
+ std::string const Variable;
+ };
+
+ std::shared_ptr<Impl const> Action;
+};
+} // anonymous namespace
+
+bool cmVariableWatchCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("must be called with at least one argument.");
+ return false;
+ }
+ std::string const& variable = args[0];
+ std::string command;
+ if (args.size() > 1) {
+ command = args[1];
+ }
+ if (variable == "CMAKE_CURRENT_LIST_FILE") {
+ status.SetError(cmStrCat("cannot be set on the variable: ", variable));
+ return false;
+ }
+
+ auto* const data = new cmVariableWatchCallbackData;
+
+ data->InCallback = false;
+ data->Command = std::move(command);
+
+ if (!status.GetMakefile().GetCMakeInstance()->GetVariableWatch()->AddWatch(
+ variable, cmVariableWatchCommandVariableAccessed, data,
+ deleteVariableWatchCallbackData)) {
+ deleteVariableWatchCallbackData(data);
+ return false;
+ }
+
+ status.GetMakefile().AddGeneratorAction(
+ FinalAction{ &status.GetMakefile(), variable });
+ return true;
+}
diff --git a/Source/cmVariableWatchCommand.h b/Source/cmVariableWatchCommand.h
new file mode 100644
index 0000000..4477cb7
--- /dev/null
+++ b/Source/cmVariableWatchCommand.h
@@ -0,0 +1,17 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Watch when the variable changes and invoke command
+ *
+ */
+bool cmVariableWatchCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmVersion.cxx b/Source/cmVersion.cxx
new file mode 100644
index 0000000..a091b91
--- /dev/null
+++ b/Source/cmVersion.cxx
@@ -0,0 +1,27 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmVersion.h"
+
+#include "cmVersionConfig.h"
+
+unsigned int cmVersion::GetMajorVersion()
+{
+ return CMake_VERSION_MAJOR;
+}
+unsigned int cmVersion::GetMinorVersion()
+{
+ return CMake_VERSION_MINOR;
+}
+unsigned int cmVersion::GetPatchVersion()
+{
+ return CMake_VERSION_PATCH;
+}
+unsigned int cmVersion::GetTweakVersion()
+{
+ return 0;
+}
+
+const char* cmVersion::GetCMakeVersion()
+{
+ return CMake_VERSION;
+}
diff --git a/Source/cmVersion.h b/Source/cmVersion.h
new file mode 100644
index 0000000..456428c
--- /dev/null
+++ b/Source/cmVersion.h
@@ -0,0 +1,31 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <cm3p/kwiml/int.h>
+
+/** \class cmVersion
+ * \brief Helper class for providing CMake and CTest version information.
+ *
+ * Finds all version related information.
+ */
+class cmVersion
+{
+public:
+ /**
+ * Return major and minor version numbers for cmake.
+ */
+ static unsigned int GetMajorVersion();
+ static unsigned int GetMinorVersion();
+ static unsigned int GetPatchVersion();
+ static unsigned int GetTweakVersion();
+ static const char* GetCMakeVersion();
+};
+
+/* Encode with room for up to 1000 minor releases between major releases
+ and to encode dates until the year 10000 in the patch level. */
+#define CMake_VERSION_ENCODE_BASE KWIML_INT_UINT64_C(100000000)
+#define CMake_VERSION_ENCODE(major, minor, patch) \
+ ((((major)*1000u) * CMake_VERSION_ENCODE_BASE) + \
+ (((minor) % 1000u) * CMake_VERSION_ENCODE_BASE) + \
+ (((patch) % CMake_VERSION_ENCODE_BASE)))
diff --git a/Source/cmVersionConfig.h.in b/Source/cmVersionConfig.h.in
new file mode 100644
index 0000000..06251f3
--- /dev/null
+++ b/Source/cmVersionConfig.h.in
@@ -0,0 +1,8 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#define CMake_VERSION_MAJOR @CMake_VERSION_MAJOR@
+#define CMake_VERSION_MINOR @CMake_VERSION_MINOR@
+#define CMake_VERSION_PATCH @CMake_VERSION_PATCH@
+#define CMake_VERSION_SUFFIX "@CMake_VERSION_SUFFIX@"
+#define CMake_VERSION_IS_DIRTY @CMake_VERSION_IS_DIRTY@
+#define CMake_VERSION "@CMake_VERSION@"
diff --git a/Source/cmVersionMacros.h b/Source/cmVersionMacros.h
new file mode 100644
index 0000000..f33f0df
--- /dev/null
+++ b/Source/cmVersionMacros.h
@@ -0,0 +1,10 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmVersionConfig.h"
+
+#define CMake_VERSION_PATCH_IS_RELEASE(patch) ((patch) < 20000000)
+#if CMake_VERSION_PATCH_IS_RELEASE(CMake_VERSION_PATCH)
+# define CMake_VERSION_IS_RELEASE 1
+#endif
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
new file mode 100644
index 0000000..0255d60
--- /dev/null
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -0,0 +1,5088 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmVisualStudio10TargetGenerator.h"
+
+#include <iterator>
+#include <set>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cm/vector>
+#include <cmext/algorithm>
+
+#include "windows.h"
+
+#include "cmComputeLinkInformation.h"
+#include "cmCustomCommand.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalVisualStudio10Generator.h"
+#include "cmGlobalVisualStudioVersionedGenerator.h"
+#include "cmLinkLineDeviceComputer.h"
+#include "cmLocalVisualStudio10Generator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmVisualStudioGeneratorOptions.h"
+
+static void ConvertToWindowsSlash(std::string& s);
+
+static std::string cmVS10EscapeXML(std::string arg)
+{
+ cmSystemTools::ReplaceString(arg, "&", "&amp;");
+ cmSystemTools::ReplaceString(arg, "<", "&lt;");
+ cmSystemTools::ReplaceString(arg, ">", "&gt;");
+ return arg;
+}
+
+static std::string cmVS10EscapeAttr(std::string arg)
+{
+ cmSystemTools::ReplaceString(arg, "&", "&amp;");
+ cmSystemTools::ReplaceString(arg, "<", "&lt;");
+ cmSystemTools::ReplaceString(arg, ">", "&gt;");
+ cmSystemTools::ReplaceString(arg, "\"", "&quot;");
+ cmSystemTools::ReplaceString(arg, "\n", "&#10;");
+ return arg;
+}
+
+struct cmVisualStudio10TargetGenerator::Elem
+{
+ std::ostream& S;
+ const int Indent;
+ bool HasElements = false;
+ bool HasContent = false;
+ std::string Tag;
+
+ Elem(std::ostream& s, const std::string& tag)
+ : S(s)
+ , Indent(0)
+ , Tag(tag)
+ {
+ this->StartElement();
+ }
+ Elem(const Elem&) = delete;
+ Elem(Elem& par, cm::string_view tag)
+ : S(par.S)
+ , Indent(par.Indent + 1)
+ , Tag(std::string(tag))
+ {
+ par.SetHasElements();
+ this->StartElement();
+ }
+ void SetHasElements()
+ {
+ if (!HasElements) {
+ this->S << ">";
+ HasElements = true;
+ }
+ }
+ std::ostream& WriteString(const char* line);
+ void StartElement() { this->WriteString("<") << this->Tag; }
+ void Element(cm::string_view tag, std::string val)
+ {
+ Elem(*this, tag).Content(std::move(val));
+ }
+ Elem& Attribute(const char* an, std::string av)
+ {
+ this->S << " " << an << "=\"" << cmVS10EscapeAttr(std::move(av)) << "\"";
+ return *this;
+ }
+ void Content(std::string val)
+ {
+ if (!this->HasContent) {
+ this->S << ">";
+ this->HasContent = true;
+ }
+ this->S << cmVS10EscapeXML(std::move(val));
+ }
+ ~Elem()
+ {
+ // Do not emit element which has not been started
+ if (Tag.empty()) {
+ return;
+ }
+
+ if (HasElements) {
+ this->WriteString("</") << this->Tag << ">";
+ } else if (HasContent) {
+ this->S << "</" << this->Tag << ">";
+ } else {
+ this->S << " />";
+ }
+ }
+
+ void WritePlatformConfigTag(const std::string& tag, const std::string& cond,
+ const std::string& content);
+};
+
+class cmVS10GeneratorOptions : public cmVisualStudioGeneratorOptions
+{
+public:
+ using Elem = cmVisualStudio10TargetGenerator::Elem;
+ cmVS10GeneratorOptions(cmLocalVisualStudioGenerator* lg, Tool tool,
+ cmVS7FlagTable const* table,
+ cmVisualStudio10TargetGenerator* g = nullptr)
+ : cmVisualStudioGeneratorOptions(lg, tool, table)
+ , TargetGenerator(g)
+ {
+ }
+
+ void OutputFlag(std::ostream& /*fout*/, int /*indent*/,
+ const std::string& tag, const std::string& content) override
+ {
+ if (!this->GetConfiguration().empty()) {
+ // if there are configuration specific flags, then
+ // use the configuration specific tag for PreprocessorDefinitions
+ const std::string cond =
+ this->TargetGenerator->CalcCondition(this->GetConfiguration());
+ this->Parent->WritePlatformConfigTag(tag, cond, content);
+ } else {
+ this->Parent->Element(tag, content);
+ }
+ }
+
+private:
+ cmVisualStudio10TargetGenerator* const TargetGenerator;
+ Elem* Parent = nullptr;
+ friend cmVisualStudio10TargetGenerator::OptionsHelper;
+};
+
+struct cmVisualStudio10TargetGenerator::OptionsHelper
+{
+ cmVS10GeneratorOptions& O;
+ OptionsHelper(cmVS10GeneratorOptions& o, Elem& e)
+ : O(o)
+ {
+ O.Parent = &e;
+ }
+ ~OptionsHelper() { O.Parent = nullptr; }
+
+ void OutputPreprocessorDefinitions(const std::string& lang)
+ {
+ O.OutputPreprocessorDefinitions(O.Parent->S, O.Parent->Indent + 1, lang);
+ }
+ void OutputAdditionalIncludeDirectories(const std::string& lang)
+ {
+ O.OutputAdditionalIncludeDirectories(O.Parent->S, O.Parent->Indent + 1,
+ lang);
+ }
+ void OutputFlagMap() { O.OutputFlagMap(O.Parent->S, O.Parent->Indent + 1); }
+ void PrependInheritedString(std::string const& key)
+ {
+ O.PrependInheritedString(key);
+ }
+};
+
+static std::string cmVS10EscapeComment(std::string comment)
+{
+ // MSBuild takes the CDATA of a <Message></Message> element and just
+ // does "echo $CDATA" with no escapes. We must encode the string.
+ // http://technet.microsoft.com/en-us/library/cc772462%28WS.10%29.aspx
+ std::string echoable;
+ for (char c : comment) {
+ switch (c) {
+ case '\r':
+ break;
+ case '\n':
+ echoable += '\t';
+ break;
+ case '"': /* no break */
+ case '|': /* no break */
+ case '&': /* no break */
+ case '<': /* no break */
+ case '>': /* no break */
+ case '^':
+ echoable += '^'; /* no break */
+ CM_FALLTHROUGH;
+ default:
+ echoable += c;
+ break;
+ }
+ }
+ return echoable;
+}
+
+static bool cmVS10IsTargetsFile(std::string const& path)
+{
+ std::string const ext = cmSystemTools::GetFilenameLastExtension(path);
+ return cmSystemTools::Strucmp(ext.c_str(), ".targets") == 0;
+}
+
+static std::string computeProjectFileExtension(cmGeneratorTarget const* t)
+{
+ std::string res;
+ res = ".vcxproj";
+ if (t->IsCSharpOnly()) {
+ res = ".csproj";
+ }
+ return res;
+}
+
+cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator(
+ cmGeneratorTarget* target, cmGlobalVisualStudio10Generator* gg)
+ : GeneratorTarget(target)
+ , Makefile(target->Target->GetMakefile())
+ , Platform(gg->GetPlatformName())
+ , Name(target->GetName())
+ , GUID(gg->GetGUID(this->Name))
+ , GlobalGenerator(gg)
+ , LocalGenerator(
+ (cmLocalVisualStudio10Generator*)target->GetLocalGenerator())
+{
+ this->Configurations =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
+ this->NsightTegra = gg->IsNsightTegra();
+ this->Android = gg->TargetsAndroid();
+ for (int i = 0; i < 4; ++i) {
+ this->NsightTegraVersion[i] = 0;
+ }
+ sscanf(gg->GetNsightTegraVersion().c_str(), "%u.%u.%u.%u",
+ &this->NsightTegraVersion[0], &this->NsightTegraVersion[1],
+ &this->NsightTegraVersion[2], &this->NsightTegraVersion[3]);
+ this->MSTools = !this->NsightTegra && !this->Android;
+ this->Managed = false;
+ this->TargetCompileAsWinRT = false;
+ this->IsMissingFiles = false;
+ this->DefaultArtifactDir =
+ this->LocalGenerator->GetCurrentBinaryDirectory() + "/" +
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ this->InSourceBuild = (this->Makefile->GetCurrentSourceDirectory() ==
+ this->Makefile->GetCurrentBinaryDirectory());
+ this->ClassifyAllConfigSources();
+}
+
+cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator()
+{
+}
+
+std::string cmVisualStudio10TargetGenerator::CalcCondition(
+ const std::string& config) const
+{
+ std::ostringstream oss;
+ oss << "'$(Configuration)|$(Platform)'=='";
+ oss << config << "|" << this->Platform;
+ oss << "'";
+ // handle special case for 32 bit C# targets
+ if (this->ProjectType == csproj && this->Platform == "Win32") {
+ oss << " Or ";
+ oss << "'$(Configuration)|$(Platform)'=='";
+ oss << config << "|x86";
+ oss << "'";
+ }
+ return oss.str();
+}
+
+void cmVisualStudio10TargetGenerator::Elem::WritePlatformConfigTag(
+ const std::string& tag, const std::string& cond, const std::string& content)
+{
+ Elem(*this, tag).Attribute("Condition", cond).Content(content);
+}
+
+std::ostream& cmVisualStudio10TargetGenerator::Elem::WriteString(
+ const char* line)
+{
+ this->S << '\n';
+ this->S.fill(' ');
+ this->S.width(this->Indent * 2);
+ // write an empty string to get the fill level indent to print
+ this->S << "";
+ this->S << line;
+ return this->S;
+}
+
+#define VS10_CXX_DEFAULT_PROPS "$(VCTargetsPath)\\Microsoft.Cpp.Default.props"
+#define VS10_CXX_PROPS "$(VCTargetsPath)\\Microsoft.Cpp.props"
+#define VS10_CXX_USER_PROPS \
+ "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props"
+#define VS10_CXX_TARGETS "$(VCTargetsPath)\\Microsoft.Cpp.targets"
+
+#define VS10_CSharp_DEFAULT_PROPS \
+ "$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props"
+// This does not seem to exist by default, it's just provided for consistency
+// in case users want to have default custom props for C# targets
+#define VS10_CSharp_USER_PROPS \
+ "$(UserRootDir)\\Microsoft.CSharp.$(Platform).user.props"
+#define VS10_CSharp_TARGETS "$(MSBuildToolsPath)\\Microsoft.CSharp.targets"
+
+#define VS10_CSharp_NETCF_TARGETS \
+ "$(MSBuildExtensionsPath)\\Microsoft\\$(TargetFrameworkIdentifier)\\" \
+ "$(TargetFrameworkTargetsVersion)\\Microsoft.$(TargetFrameworkIdentifier)" \
+ ".CSharp.targets"
+
+void cmVisualStudio10TargetGenerator::Generate()
+{
+ const std::string ProjectFileExtension =
+ computeProjectFileExtension(this->GeneratorTarget);
+ if (ProjectFileExtension == ".vcxproj") {
+ this->ProjectType = vcxproj;
+ this->Managed = false;
+ } else if (ProjectFileExtension == ".csproj") {
+ if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ std::string message = "The C# target \"" +
+ this->GeneratorTarget->GetName() +
+ "\" is of type STATIC_LIBRARY. This is discouraged (and may be "
+ "disabled in future). Make it a SHARED library instead.";
+ this->Makefile->IssueMessage(MessageType::DEPRECATION_WARNING, message);
+ }
+ this->ProjectType = csproj;
+ this->Managed = true;
+ }
+
+ if (this->Android &&
+ this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE &&
+ !this->GeneratorTarget->Target->IsAndroidGuiExecutable()) {
+ this->GlobalGenerator->AddAndroidExecutableWarning(this->Name);
+ }
+
+ // Tell the global generator the name of the project file
+ this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME",
+ this->Name);
+ this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME_EXT",
+ ProjectFileExtension);
+ this->DotNetHintReferences.clear();
+ this->AdditionalUsingDirectories.clear();
+ if (this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
+ if (!this->ComputeClOptions()) {
+ return;
+ }
+ if (!this->ComputeRcOptions()) {
+ return;
+ }
+ if (!this->ComputeCudaOptions()) {
+ return;
+ }
+ if (!this->ComputeCudaLinkOptions()) {
+ return;
+ }
+ if (!this->ComputeMasmOptions()) {
+ return;
+ }
+ if (!this->ComputeNasmOptions()) {
+ return;
+ }
+ if (!this->ComputeLinkOptions()) {
+ return;
+ }
+ if (!this->ComputeLibOptions()) {
+ return;
+ }
+ }
+ std::string path =
+ cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
+ this->Name, ProjectFileExtension);
+ cmGeneratedFileStream BuildFileStream(path);
+ const std::string PathToProjectFile = path;
+ BuildFileStream.SetCopyIfDifferent(true);
+
+ // Write the encoding header into the file
+ char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
+ BuildFileStream.write(magic, 3);
+ BuildFileStream << "<?xml version=\"1.0\" encoding=\""
+ << this->GlobalGenerator->Encoding() << "\"?>";
+ {
+ Elem e0(BuildFileStream, "Project");
+ e0.Attribute("DefaultTargets", "Build");
+ const char* toolsVersion = this->GlobalGenerator->GetToolsVersion();
+ if (this->GlobalGenerator->GetVersion() ==
+ cmGlobalVisualStudioGenerator::VS12 &&
+ this->GlobalGenerator->TargetsWindowsCE()) {
+ toolsVersion = "4.0";
+ }
+ e0.Attribute("ToolsVersion", toolsVersion);
+ e0.Attribute("xmlns",
+ "http://schemas.microsoft.com/developer/msbuild/2003");
+
+ if (this->NsightTegra) {
+ Elem e1(e0, "PropertyGroup");
+ e1.Attribute("Label", "NsightTegraProject");
+ const unsigned int nsightTegraMajorVersion = this->NsightTegraVersion[0];
+ const unsigned int nsightTegraMinorVersion = this->NsightTegraVersion[1];
+ if (nsightTegraMajorVersion >= 2) {
+ if (nsightTegraMajorVersion > 3 ||
+ (nsightTegraMajorVersion == 3 && nsightTegraMinorVersion >= 1)) {
+ e1.Element("NsightTegraProjectRevisionNumber", "11");
+ } else {
+ // Nsight Tegra 2.0 uses project revision 9.
+ e1.Element("NsightTegraProjectRevisionNumber", "9");
+ }
+ // Tell newer versions to upgrade silently when loading.
+ e1.Element("NsightTegraUpgradeOnceWithoutPrompt", "true");
+ } else {
+ // Require Nsight Tegra 1.6 for JCompile support.
+ e1.Element("NsightTegraProjectRevisionNumber", "7");
+ }
+ }
+
+ if (const char* hostArch =
+ this->GlobalGenerator->GetPlatformToolsetHostArchitecture()) {
+ Elem e1(e0, "PropertyGroup");
+ e1.Element("PreferredToolArchitecture", hostArch);
+ }
+
+ if (this->ProjectType != csproj) {
+ this->WriteProjectConfigurations(e0);
+ }
+
+ {
+ Elem e1(e0, "PropertyGroup");
+ e1.Attribute("Label", "Globals");
+ e1.Element("ProjectGuid", "{" + this->GUID + "}");
+
+ if ((this->MSTools || this->Android) &&
+ this->GeneratorTarget->IsInBuildSystem()) {
+ this->WriteApplicationTypeSettings(e1);
+ this->VerifyNecessaryFiles();
+ }
+
+ cmProp vsProjectTypes =
+ this->GeneratorTarget->GetProperty("VS_GLOBAL_PROJECT_TYPES");
+ if (vsProjectTypes) {
+ const char* tagName = "ProjectTypes";
+ if (this->ProjectType == csproj) {
+ tagName = "ProjectTypeGuids";
+ }
+ e1.Element(tagName, *vsProjectTypes);
+ }
+
+ cmProp vsProjectName =
+ this->GeneratorTarget->GetProperty("VS_SCC_PROJECTNAME");
+ cmProp vsLocalPath =
+ this->GeneratorTarget->GetProperty("VS_SCC_LOCALPATH");
+ cmProp vsProvider =
+ this->GeneratorTarget->GetProperty("VS_SCC_PROVIDER");
+
+ if (vsProjectName && vsLocalPath && vsProvider) {
+ e1.Element("SccProjectName", *vsProjectName);
+ e1.Element("SccLocalPath", *vsLocalPath);
+ e1.Element("SccProvider", *vsProvider);
+
+ cmProp vsAuxPath =
+ this->GeneratorTarget->GetProperty("VS_SCC_AUXPATH");
+ if (vsAuxPath) {
+ e1.Element("SccAuxPath", *vsAuxPath);
+ }
+ }
+
+ if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT")) {
+ e1.Element("WinMDAssembly", "true");
+ }
+
+ cmProp vsGlobalKeyword =
+ this->GeneratorTarget->GetProperty("VS_GLOBAL_KEYWORD");
+ if (!vsGlobalKeyword) {
+ if (this->GlobalGenerator->TargetsAndroid()) {
+ e1.Element("Keyword", "Android");
+ } else {
+ e1.Element("Keyword", "Win32Proj");
+ }
+ } else {
+ e1.Element("Keyword", *vsGlobalKeyword);
+ }
+
+ cmProp vsGlobalRootNamespace =
+ this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE");
+ if (vsGlobalRootNamespace) {
+ e1.Element("RootNamespace", *vsGlobalRootNamespace);
+ }
+
+ e1.Element("Platform", this->Platform);
+ cmProp projLabel = this->GeneratorTarget->GetProperty("PROJECT_LABEL");
+ if (!projLabel) {
+ projLabel = &this->Name;
+ }
+ e1.Element("ProjectName", *projLabel);
+ {
+ cmProp targetFramework =
+ this->GeneratorTarget->GetProperty("DOTNET_TARGET_FRAMEWORK");
+ if (targetFramework) {
+ if (std::strchr(targetFramework->c_str(), ';') != nullptr) {
+ e1.Element("TargetFrameworks", *targetFramework);
+ } else {
+ e1.Element("TargetFramework", *targetFramework);
+ }
+ } else {
+ // TODO: add deprecation warning for VS_* property?
+ cmProp p = this->GeneratorTarget->GetProperty(
+ "VS_DOTNET_TARGET_FRAMEWORK_VERSION");
+ if (!p) {
+ p = this->GeneratorTarget->GetProperty(
+ "DOTNET_TARGET_FRAMEWORK_VERSION");
+ }
+ const char* targetFrameworkVersion = cmToCStr(p);
+ if (!targetFrameworkVersion && this->ProjectType == csproj &&
+ this->GlobalGenerator->TargetsWindowsCE() &&
+ this->GlobalGenerator->GetVersion() ==
+ cmGlobalVisualStudioGenerator::VS12) {
+ // VS12 .NETCF default to .NET framework 3.9
+ targetFrameworkVersion = "v3.9";
+ }
+ if (targetFrameworkVersion) {
+ e1.Element("TargetFrameworkVersion", targetFrameworkVersion);
+ }
+ }
+ if (this->ProjectType == vcxproj &&
+ this->GlobalGenerator->TargetsWindowsCE()) {
+ e1.Element("EnableRedirectPlatform", "true");
+ e1.Element("RedirectPlatformValue", this->Platform);
+ }
+ if (this->ProjectType == csproj &&
+ this->GlobalGenerator->TargetsWindowsCE()) {
+ cmProp targetFrameworkId = this->GeneratorTarget->GetProperty(
+ "VS_TARGET_FRAMEWORK_IDENTIFIER");
+ e1.Element("TargetFrameworkIdentifier",
+ targetFrameworkId ? *targetFrameworkId
+ : "WindowsEmbeddedCompact");
+ cmProp targetFrameworkVer = this->GeneratorTarget->GetProperty(
+ "VS_TARGET_FRAMEWORKS_TARGET_VERSION");
+ e1.Element("TargetFrameworkTargetsVersion",
+ targetFrameworkVer ? *targetFrameworkVer : "v8.0");
+ }
+ if (!this->GlobalGenerator->GetPlatformToolsetCudaCustomDirString()
+ .empty()) {
+ e1.Element(
+ "CudaToolkitCustomDir",
+ this->GlobalGenerator->GetPlatformToolsetCudaCustomDirString() +
+ this->GlobalGenerator->GetPlatformToolsetCudaNvccSubdirString());
+ }
+ }
+
+ // Disable the project upgrade prompt that is displayed the first time a
+ // project using an older toolset version is opened in a newer version of
+ // the IDE (respected by VS 2013 and above).
+ if (this->GlobalGenerator->GetVersion() >=
+ cmGlobalVisualStudioGenerator::VS12) {
+ e1.Element("VCProjectUpgraderObjectName", "NoUpgrade");
+ }
+
+ if (const char* vcTargetsPath =
+ this->GlobalGenerator->GetCustomVCTargetsPath()) {
+ e1.Element("VCTargetsPath", vcTargetsPath);
+ }
+
+ std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys();
+ for (std::string const& keyIt : keys) {
+ static const cm::string_view prefix = "VS_GLOBAL_";
+ if (!cmHasPrefix(keyIt, prefix))
+ continue;
+ cm::string_view globalKey =
+ cm::string_view(keyIt).substr(prefix.length());
+ // Skip invalid or separately-handled properties.
+ if (globalKey.empty() || globalKey == "PROJECT_TYPES" ||
+ globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") {
+ continue;
+ }
+ cmProp value = this->GeneratorTarget->GetProperty(keyIt);
+ if (!value)
+ continue;
+ e1.Element(globalKey, *value);
+ }
+
+ if (this->Managed) {
+ std::string outputType;
+ switch (this->GeneratorTarget->GetType()) {
+ case cmStateEnums::OBJECT_LIBRARY:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::SHARED_LIBRARY:
+ outputType = "Library";
+ break;
+ case cmStateEnums::MODULE_LIBRARY:
+ outputType = "Module";
+ break;
+ case cmStateEnums::EXECUTABLE: {
+ auto const win32 =
+ this->GeneratorTarget->GetSafeProperty("WIN32_EXECUTABLE");
+ if (win32.find("$<") != std::string::npos) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(
+ "Target \"", this->GeneratorTarget->GetName(),
+ "\" has a generator expression in its WIN32_EXECUTABLE "
+ "property. This is not supported on managed executables."));
+ return;
+ }
+ if (cmIsOn(win32)) {
+ outputType = "WinExe";
+ } else {
+ outputType = "Exe";
+ }
+ } break;
+ case cmStateEnums::UTILITY:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ case cmStateEnums::GLOBAL_TARGET:
+ outputType = "Utility";
+ break;
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ break;
+ }
+ e1.Element("OutputType", outputType);
+ e1.Element("AppDesignerFolder", "Properties");
+ }
+ }
+
+ switch (this->ProjectType) {
+ case vcxproj: {
+ std::string const& props =
+ this->GlobalGenerator->GetPlatformToolsetVersionProps();
+ if (!props.empty()) {
+ Elem(e0, "Import").Attribute("Project", props);
+ }
+ Elem(e0, "Import").Attribute("Project", VS10_CXX_DEFAULT_PROPS);
+ } break;
+ case csproj:
+ Elem(e0, "Import")
+ .Attribute("Project", VS10_CSharp_DEFAULT_PROPS)
+ .Attribute("Condition", "Exists('" VS10_CSharp_DEFAULT_PROPS "')");
+ break;
+ }
+
+ this->WriteProjectConfigurationValues(e0);
+
+ if (this->ProjectType == vcxproj) {
+ Elem(e0, "Import").Attribute("Project", VS10_CXX_PROPS);
+ }
+ {
+ Elem e1(e0, "ImportGroup");
+ e1.Attribute("Label", "ExtensionSettings");
+ e1.SetHasElements();
+
+ if (this->GlobalGenerator->IsCudaEnabled()) {
+ auto customDir =
+ this->GlobalGenerator->GetPlatformToolsetCudaCustomDirString();
+ std::string cudaPath = customDir.empty()
+ ? "$(VCTargetsPath)\\BuildCustomizations\\"
+ : customDir +
+ this->GlobalGenerator
+ ->GetPlatformToolsetCudaVSIntegrationSubdirString() +
+ "extras\\visual_studio_integration\\MSBuildExtensions\\";
+ Elem(e1, "Import")
+ .Attribute("Project",
+ std::move(cudaPath) + "CUDA " +
+ this->GlobalGenerator->GetPlatformToolsetCuda() +
+ ".props");
+ }
+ if (this->GlobalGenerator->IsMasmEnabled()) {
+ Elem(e1, "Import")
+ .Attribute("Project",
+ "$(VCTargetsPath)\\BuildCustomizations\\masm.props");
+ }
+ if (this->GlobalGenerator->IsNasmEnabled()) {
+ // Always search in the standard modules location.
+ std::string propsTemplate =
+ GetCMakeFilePath("Templates/MSBuild/nasm.props.in");
+
+ std::string propsLocal =
+ cmStrCat(this->DefaultArtifactDir, "\\nasm.props");
+ ConvertToWindowsSlash(propsLocal);
+ this->Makefile->ConfigureFile(propsTemplate, propsLocal, false, true,
+ true);
+ Elem(e1, "Import").Attribute("Project", propsLocal);
+ }
+ }
+ {
+ Elem e1(e0, "ImportGroup");
+ e1.Attribute("Label", "PropertySheets");
+ std::string props;
+ switch (this->ProjectType) {
+ case vcxproj:
+ props = VS10_CXX_USER_PROPS;
+ break;
+ case csproj:
+ props = VS10_CSharp_USER_PROPS;
+ break;
+ }
+ if (cmProp p = this->GeneratorTarget->GetProperty("VS_USER_PROPS")) {
+ props = *p;
+ }
+ if (!props.empty()) {
+ ConvertToWindowsSlash(props);
+ Elem(e1, "Import")
+ .Attribute("Project", props)
+ .Attribute("Condition", "exists('" + props + "')")
+ .Attribute("Label", "LocalAppDataPlatform");
+ }
+
+ this->WritePlatformExtensions(e1);
+ }
+
+ this->WriteDotNetDocumentationFile(e0);
+ Elem(e0, "PropertyGroup").Attribute("Label", "UserMacros");
+ this->WriteWinRTPackageCertificateKeyFile(e0);
+ this->WritePathAndIncrementalLinkOptions(e0);
+ this->WriteCEDebugProjectConfigurationValues(e0);
+ this->WriteItemDefinitionGroups(e0);
+ this->WriteCustomCommands(e0);
+ this->WriteAllSources(e0);
+ this->WriteDotNetReferences(e0);
+ this->WritePackageReferences(e0);
+ this->WriteImports(e0);
+ this->WriteEmbeddedResourceGroup(e0);
+ this->WriteXamlFilesGroup(e0);
+ this->WriteWinRTReferences(e0);
+ this->WriteProjectReferences(e0);
+ this->WriteSDKReferences(e0);
+ switch (this->ProjectType) {
+ case vcxproj:
+ Elem(e0, "Import").Attribute("Project", VS10_CXX_TARGETS);
+ break;
+ case csproj:
+ if (this->GlobalGenerator->TargetsWindowsCE()) {
+ Elem(e0, "Import").Attribute("Project", VS10_CSharp_NETCF_TARGETS);
+ } else {
+ Elem(e0, "Import").Attribute("Project", VS10_CSharp_TARGETS);
+ }
+ break;
+ }
+
+ this->WriteTargetSpecificReferences(e0);
+ {
+ Elem e1(e0, "ImportGroup");
+ e1.Attribute("Label", "ExtensionTargets");
+ e1.SetHasElements();
+ this->WriteTargetsFileReferences(e1);
+ if (this->GlobalGenerator->IsCudaEnabled()) {
+ auto customDir =
+ this->GlobalGenerator->GetPlatformToolsetCudaCustomDirString();
+ std::string cudaPath = customDir.empty()
+ ? "$(VCTargetsPath)\\BuildCustomizations\\"
+ : customDir +
+ this->GlobalGenerator
+ ->GetPlatformToolsetCudaVSIntegrationSubdirString() +
+ "extras\\visual_studio_integration\\MSBuildExtensions\\";
+ Elem(e1, "Import")
+ .Attribute("Project",
+ std::move(cudaPath) + "CUDA " +
+ this->GlobalGenerator->GetPlatformToolsetCuda() +
+ ".targets");
+ }
+ if (this->GlobalGenerator->IsMasmEnabled()) {
+ Elem(e1, "Import")
+ .Attribute("Project",
+ "$(VCTargetsPath)\\BuildCustomizations\\masm.targets");
+ }
+ if (this->GlobalGenerator->IsNasmEnabled()) {
+ std::string nasmTargets =
+ GetCMakeFilePath("Templates/MSBuild/nasm.targets");
+ Elem(e1, "Import").Attribute("Project", nasmTargets);
+ }
+ }
+ if (this->ProjectType == csproj) {
+ for (std::string const& c : this->Configurations) {
+ Elem e1(e0, "PropertyGroup");
+ e1.Attribute("Condition", "'$(Configuration)' == '" + c + "'");
+ e1.SetHasElements();
+ this->WriteEvents(e1, c);
+ }
+ // make sure custom commands are executed before build (if necessary)
+ {
+ Elem e1(e0, "PropertyGroup");
+ std::ostringstream oss;
+ oss << "\n";
+ for (std::string const& i : this->CSharpCustomCommandNames) {
+ oss << " " << i << ";\n";
+ }
+ oss << " "
+ << "$(BuildDependsOn)\n";
+ e1.Element("BuildDependsOn", oss.str());
+ }
+ }
+ }
+
+ if (BuildFileStream.Close()) {
+ this->GlobalGenerator->FileReplacedDuringGenerate(PathToProjectFile);
+ }
+
+ // The groups are stored in a separate file for VS 10
+ this->WriteGroups();
+}
+
+void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0)
+{
+ std::vector<std::string> packageReferences;
+ if (cmProp vsPackageReferences =
+ this->GeneratorTarget->GetProperty("VS_PACKAGE_REFERENCES")) {
+ cmExpandList(*vsPackageReferences, packageReferences);
+ }
+ if (!packageReferences.empty()) {
+ Elem e1(e0, "ItemGroup");
+ for (std::string const& ri : packageReferences) {
+ size_t versionIndex = ri.find_last_of('_');
+ if (versionIndex != std::string::npos) {
+ Elem e2(e1, "PackageReference");
+ e2.Attribute("Include", ri.substr(0, versionIndex));
+ e2.Attribute("Version", ri.substr(versionIndex + 1));
+ }
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteDotNetReferences(Elem& e0)
+{
+ std::vector<std::string> references;
+ if (cmProp vsDotNetReferences =
+ this->GeneratorTarget->GetProperty("VS_DOTNET_REFERENCES")) {
+ cmExpandList(*vsDotNetReferences, references);
+ }
+ cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties();
+ for (auto const& i : props.GetList()) {
+ static const cm::string_view vsDnRef = "VS_DOTNET_REFERENCE_";
+ if (cmHasPrefix(i.first, vsDnRef)) {
+ std::string path = i.second;
+ if (!cmsys::SystemTools::FileIsFullPath(path)) {
+ path = this->Makefile->GetCurrentSourceDirectory() + "/" + path;
+ }
+ ConvertToWindowsSlash(path);
+ this->DotNetHintReferences[""].emplace_back(
+ DotNetHintReference(i.first.substr(vsDnRef.length()), path));
+ }
+ }
+ if (!references.empty() || !this->DotNetHintReferences.empty()) {
+ Elem e1(e0, "ItemGroup");
+ for (std::string const& ri : references) {
+ // if the entry from VS_DOTNET_REFERENCES is an existing file, generate
+ // a new hint-reference and name it from the filename
+ if (cmsys::SystemTools::FileExists(ri, true)) {
+ std::string name =
+ cmsys::SystemTools::GetFilenameWithoutLastExtension(ri);
+ std::string path = ri;
+ ConvertToWindowsSlash(path);
+ this->DotNetHintReferences[""].emplace_back(
+ DotNetHintReference(name, path));
+ } else {
+ this->WriteDotNetReference(e1, ri, "", "");
+ }
+ }
+ for (const auto& h : this->DotNetHintReferences) {
+ // DotNetHintReferences is also populated from AddLibraries().
+ // The configuration specific hint references are added there.
+ for (const auto& i : h.second) {
+ this->WriteDotNetReference(e1, i.first, i.second, h.first);
+ }
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteDotNetReference(
+ Elem& e1, std::string const& ref, std::string const& hint,
+ std::string const& config)
+{
+ Elem e2(e1, "Reference");
+ // If 'config' is not empty, the reference is only added for the given
+ // configuration. This is used when referencing imported managed assemblies.
+ // See also cmVisualStudio10TargetGenerator::AddLibraries().
+ if (!config.empty()) {
+ e2.Attribute("Condition", this->CalcCondition(config));
+ }
+ e2.Attribute("Include", ref);
+ e2.Element("CopyLocalSatelliteAssemblies", "true");
+ e2.Element("ReferenceOutputAssembly", "true");
+ if (!hint.empty()) {
+ const char* privateReference = "True";
+ if (cmProp value = this->GeneratorTarget->GetProperty(
+ "VS_DOTNET_REFERENCES_COPY_LOCAL")) {
+ if (cmIsOff(*value)) {
+ privateReference = "False";
+ }
+ }
+ e2.Element("Private", privateReference);
+ e2.Element("HintPath", hint);
+ }
+ this->WriteDotNetReferenceCustomTags(e2, ref);
+}
+
+void cmVisualStudio10TargetGenerator::WriteImports(Elem& e0)
+{
+ cmProp imports =
+ this->GeneratorTarget->Target->GetProperty("VS_PROJECT_IMPORT");
+ if (imports) {
+ std::vector<std::string> argsSplit = cmExpandedList(*imports, false);
+ for (auto& path : argsSplit) {
+ if (!cmsys::SystemTools::FileIsFullPath(path)) {
+ path = this->Makefile->GetCurrentSourceDirectory() + "/" + path;
+ }
+ ConvertToWindowsSlash(path);
+ Elem e1(e0, "Import");
+ e1.Attribute("Project", path);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteDotNetReferenceCustomTags(
+ Elem& e2, std::string const& ref)
+{
+
+ static const std::string refpropPrefix = "VS_DOTNET_REFERENCEPROP_";
+ static const std::string refpropInfix = "_TAG_";
+ const std::string refPropFullPrefix = refpropPrefix + ref + refpropInfix;
+ using CustomTags = std::map<std::string, std::string>;
+ CustomTags tags;
+ cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties();
+ for (const auto& i : props.GetList()) {
+ if (cmHasPrefix(i.first, refPropFullPrefix) && !i.second.empty()) {
+ tags[i.first.substr(refPropFullPrefix.length())] = i.second;
+ }
+ }
+ for (auto const& tag : tags) {
+ e2.Element(tag.first, tag.second);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteDotNetDocumentationFile(Elem& e0)
+{
+ std::string const& documentationFile =
+ this->GeneratorTarget->GetSafeProperty("VS_DOTNET_DOCUMENTATION_FILE");
+
+ if (this->ProjectType == csproj && !documentationFile.empty()) {
+ Elem e1(e0, "PropertyGroup");
+ Elem e2(e1, "DocumentationFile");
+ e2.Content(documentationFile);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0)
+{
+ if (!this->ResxObjs.empty()) {
+ Elem e1(e0, "ItemGroup");
+ std::string srcDir = this->Makefile->GetCurrentSourceDirectory();
+ ConvertToWindowsSlash(srcDir);
+ for (cmSourceFile const* oi : this->ResxObjs) {
+ std::string obj = oi->GetFullPath();
+ ConvertToWindowsSlash(obj);
+ bool useRelativePath = false;
+ if (this->ProjectType == csproj && this->InSourceBuild) {
+ // If we do an in-source build and the resource file is in a
+ // subdirectory
+ // of the .csproj file, we have to use relative pathnames, otherwise
+ // visual studio does not show the file in the IDE. Sorry.
+ if (cmHasPrefix(obj, srcDir)) {
+ obj = this->ConvertPath(obj, true);
+ ConvertToWindowsSlash(obj);
+ useRelativePath = true;
+ }
+ }
+ Elem e2(e1, "EmbeddedResource");
+ e2.Attribute("Include", obj);
+
+ if (this->ProjectType != csproj) {
+ std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h";
+ e2.Element("DependentUpon", hFileName);
+
+ for (std::string const& c : this->Configurations) {
+ std::string s;
+ if (this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE") ||
+ // Handle variant of VS_GLOBAL_<variable> for RootNamespace.
+ this->GeneratorTarget->GetProperty("VS_GLOBAL_RootNamespace")) {
+ s = "$(RootNamespace).";
+ }
+ s += "%(Filename).resources";
+ e2.WritePlatformConfigTag("LogicalName", this->CalcCondition(c), s);
+ }
+ } else {
+ std::string binDir = this->Makefile->GetCurrentBinaryDirectory();
+ ConvertToWindowsSlash(binDir);
+ // If the resource was NOT added using a relative path (which should
+ // be the default), we have to provide a link here
+ if (!useRelativePath) {
+ std::string link = this->GetCSharpSourceLink(oi);
+ if (link.empty()) {
+ link = cmsys::SystemTools::GetFilenameName(obj);
+ }
+ e2.Element("Link", link);
+ }
+ // Determine if this is a generated resource from a .Designer.cs file
+ std::string designerResource =
+ cmSystemTools::GetFilenamePath(oi->GetFullPath()) + "/" +
+ cmSystemTools::GetFilenameWithoutLastExtension(oi->GetFullPath()) +
+ ".Designer.cs";
+ if (cmsys::SystemTools::FileExists(designerResource)) {
+ std::string generator = "PublicResXFileCodeGenerator";
+ if (cmProp g = oi->GetProperty("VS_RESOURCE_GENERATOR")) {
+ generator = *g;
+ }
+ if (!generator.empty()) {
+ e2.Element("Generator", generator);
+ if (cmHasPrefix(designerResource, srcDir)) {
+ designerResource.erase(0, srcDir.length());
+ } else if (cmHasPrefix(designerResource, binDir)) {
+ designerResource.erase(0, binDir.length());
+ } else {
+ designerResource =
+ cmsys::SystemTools::GetFilenameName(designerResource);
+ }
+ ConvertToWindowsSlash(designerResource);
+ e2.Element("LastGenOutput", designerResource);
+ }
+ }
+ const cmPropertyMap& props = oi->GetProperties();
+ for (const std::string& p : props.GetKeys()) {
+ static const cm::string_view propNamePrefix = "VS_CSHARP_";
+ if (cmHasPrefix(p, propNamePrefix)) {
+ cm::string_view tagName =
+ cm::string_view(p).substr(propNamePrefix.length());
+ if (!tagName.empty()) {
+ cmProp value = props.GetPropertyValue(p);
+ if (cmNonempty(value)) {
+ e2.Element(tagName, *value);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup(Elem& e0)
+{
+ if (!this->XamlObjs.empty()) {
+ Elem e1(e0, "ItemGroup");
+ for (cmSourceFile const* oi : this->XamlObjs) {
+ std::string obj = oi->GetFullPath();
+ std::string xamlType;
+ cmProp xamlTypeProperty = oi->GetProperty("VS_XAML_TYPE");
+ if (xamlTypeProperty) {
+ xamlType = *xamlTypeProperty;
+ } else {
+ xamlType = "Page";
+ }
+
+ Elem e2(e1, xamlType);
+ this->WriteSource(e2, oi);
+ e2.SetHasElements();
+ e2.Element("SubType", "Designer");
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteTargetSpecificReferences(Elem& e0)
+{
+ if (this->MSTools) {
+ if (this->GlobalGenerator->TargetsWindowsPhone() &&
+ this->GlobalGenerator->GetSystemVersion() == "8.0") {
+ Elem(e0, "Import")
+ .Attribute("Project",
+ "$(MSBuildExtensionsPath)\\Microsoft\\WindowsPhone\\v"
+ "$(TargetPlatformVersion)\\Microsoft.Cpp.WindowsPhone."
+ "$(TargetPlatformVersion).targets");
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteTargetsFileReferences(Elem& e1)
+{
+ for (TargetsFileAndConfigs const& tac : this->TargetsFileAndConfigsVec) {
+ std::ostringstream oss;
+ oss << "Exists('" << tac.File << "')";
+ if (!tac.Configs.empty()) {
+ oss << " And (";
+ for (size_t j = 0; j < tac.Configs.size(); ++j) {
+ if (j > 0) {
+ oss << " Or ";
+ }
+ oss << "'$(Configuration)'=='" << tac.Configs[j] << "'";
+ }
+ oss << ")";
+ }
+
+ Elem(e1, "Import")
+ .Attribute("Project", tac.File)
+ .Attribute("Condition", oss.str());
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteWinRTReferences(Elem& e0)
+{
+ std::vector<std::string> references;
+ if (cmProp vsWinRTReferences =
+ this->GeneratorTarget->GetProperty("VS_WINRT_REFERENCES")) {
+ cmExpandList(*vsWinRTReferences, references);
+ }
+
+ if (this->GlobalGenerator->TargetsWindowsPhone() &&
+ this->GlobalGenerator->GetSystemVersion() == "8.0" &&
+ references.empty()) {
+ references.push_back("platform.winmd");
+ }
+ if (!references.empty()) {
+ Elem e1(e0, "ItemGroup");
+ for (std::string const& ri : references) {
+ Elem e2(e1, "Reference");
+ e2.Attribute("Include", ri);
+ e2.Element("IsWinMDFile", "true");
+ }
+ }
+}
+
+// ConfigurationType Application, Utility StaticLibrary DynamicLibrary
+
+void cmVisualStudio10TargetGenerator::WriteProjectConfigurations(Elem& e0)
+{
+ Elem e1(e0, "ItemGroup");
+ e1.Attribute("Label", "ProjectConfigurations");
+ for (std::string const& c : this->Configurations) {
+ Elem e2(e1, "ProjectConfiguration");
+ e2.Attribute("Include", c + "|" + this->Platform);
+ e2.Element("Configuration", c);
+ e2.Element("Platform", this->Platform);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues(Elem& e0)
+{
+ for (std::string const& c : this->Configurations) {
+ Elem e1(e0, "PropertyGroup");
+ e1.Attribute("Condition", this->CalcCondition(c));
+ e1.Attribute("Label", "Configuration");
+
+ if (this->ProjectType != csproj) {
+ std::string configType;
+ if (cmProp vsConfigurationType =
+ this->GeneratorTarget->GetProperty("VS_CONFIGURATION_TYPE")) {
+ configType = cmGeneratorExpression::Evaluate(*vsConfigurationType,
+ this->LocalGenerator, c);
+ } else {
+ switch (this->GeneratorTarget->GetType()) {
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ configType = "DynamicLibrary";
+ break;
+ case cmStateEnums::OBJECT_LIBRARY:
+ case cmStateEnums::STATIC_LIBRARY:
+ configType = "StaticLibrary";
+ break;
+ case cmStateEnums::EXECUTABLE:
+ if (this->NsightTegra &&
+ !this->GeneratorTarget->Target->IsAndroidGuiExecutable()) {
+ // Android executables are .so too.
+ configType = "DynamicLibrary";
+ } else if (this->Android) {
+ configType = "DynamicLibrary";
+ } else {
+ configType = "Application";
+ }
+ break;
+ case cmStateEnums::UTILITY:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ case cmStateEnums::GLOBAL_TARGET:
+ if (this->NsightTegra) {
+ // Tegra-Android platform does not understand "Utility".
+ configType = "StaticLibrary";
+ } else {
+ configType = "Utility";
+ }
+ break;
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ break;
+ }
+ }
+ e1.Element("ConfigurationType", configType);
+ }
+
+ if (this->MSTools) {
+ if (!this->Managed) {
+ this->WriteMSToolConfigurationValues(e1, c);
+ } else {
+ this->WriteMSToolConfigurationValuesManaged(e1, c);
+ }
+ } else if (this->NsightTegra) {
+ this->WriteNsightTegraConfigurationValues(e1, c);
+ } else if (this->Android) {
+ this->WriteAndroidConfigurationValues(e1, c);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteCEDebugProjectConfigurationValues(
+ Elem& e0)
+{
+ if (!this->GlobalGenerator->TargetsWindowsCE()) {
+ return;
+ }
+ cmProp additionalFiles =
+ this->GeneratorTarget->GetProperty("DEPLOYMENT_ADDITIONAL_FILES");
+ cmProp remoteDirectory =
+ this->GeneratorTarget->GetProperty("DEPLOYMENT_REMOTE_DIRECTORY");
+ if (!(additionalFiles || remoteDirectory)) {
+ return;
+ }
+ for (std::string const& c : this->Configurations) {
+ Elem e1(e0, "PropertyGroup");
+ e1.Attribute("Condition", this->CalcCondition(c));
+
+ if (remoteDirectory) {
+ e1.Element("RemoteDirectory", *remoteDirectory);
+ }
+ if (additionalFiles) {
+ e1.Element("CEAdditionalFiles", *additionalFiles);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues(
+ Elem& e1, std::string const& config)
+{
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+ cmProp mfcFlag = this->Makefile->GetDefinition("CMAKE_MFC_FLAG");
+ if (mfcFlag) {
+ std::string const mfcFlagValue =
+ cmGeneratorExpression::Evaluate(*mfcFlag, this->LocalGenerator, config);
+
+ std::string useOfMfcValue = "false";
+ if (this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
+ if (mfcFlagValue == "1") {
+ useOfMfcValue = "Static";
+ } else if (mfcFlagValue == "2") {
+ useOfMfcValue = "Dynamic";
+ }
+ }
+ e1.Element("UseOfMfc", useOfMfcValue);
+ }
+
+ if ((this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY &&
+ this->ClOptions[config]->UsingUnicode()) ||
+ this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT") ||
+ this->GlobalGenerator->TargetsWindowsPhone() ||
+ this->GlobalGenerator->TargetsWindowsStore() ||
+ this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) {
+ e1.Element("CharacterSet", "Unicode");
+ } else if (this->GeneratorTarget->GetType() <=
+ cmStateEnums::OBJECT_LIBRARY &&
+ this->ClOptions[config]->UsingSBCS()) {
+ e1.Element("CharacterSet", "NotSet");
+ } else {
+ e1.Element("CharacterSet", "MultiByte");
+ }
+ if (cmProp projectToolsetOverride =
+ this->GeneratorTarget->GetProperty("VS_PLATFORM_TOOLSET")) {
+ e1.Element("PlatformToolset", *projectToolsetOverride);
+ } else if (const char* toolset = gg->GetPlatformToolset()) {
+ e1.Element("PlatformToolset", toolset);
+ }
+ if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT") ||
+ this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) {
+ e1.Element("WindowsAppContainer", "true");
+ }
+ if (this->IPOEnabledConfigurations.count(config) > 0) {
+ e1.Element("WholeProgramOptimization", "true");
+ }
+ {
+ auto s = this->SpectreMitigation.find(config);
+ if (s != this->SpectreMitigation.end()) {
+ e1.Element("SpectreMitigation", s->second);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged(
+ Elem& e1, std::string const& config)
+{
+ if (this->GeneratorTarget->GetType() > cmStateEnums::OBJECT_LIBRARY) {
+ return;
+ }
+
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+
+ Options& o = *(this->ClOptions[config]);
+
+ if (o.IsDebug()) {
+ e1.Element("DebugSymbols", "true");
+ e1.Element("DefineDebug", "true");
+ }
+
+ std::string outDir = this->GeneratorTarget->GetDirectory(config) + "/";
+ ConvertToWindowsSlash(outDir);
+ e1.Element("OutputPath", outDir);
+
+ if (o.HasFlag("Platform")) {
+ e1.Element("PlatformTarget", o.GetFlag("Platform"));
+ o.RemoveFlag("Platform");
+ }
+
+ if (cmProp projectToolsetOverride =
+ this->GeneratorTarget->GetProperty("VS_PLATFORM_TOOLSET")) {
+ e1.Element("PlatformToolset", *projectToolsetOverride);
+ } else if (const char* toolset = gg->GetPlatformToolset()) {
+ e1.Element("PlatformToolset", toolset);
+ }
+
+ std::string postfixName =
+ cmStrCat(cmSystemTools::UpperCase(config), "_POSTFIX");
+ std::string assemblyName = this->GeneratorTarget->GetOutputName(
+ config, cmStateEnums::RuntimeBinaryArtifact);
+ if (cmProp postfix = this->GeneratorTarget->GetProperty(postfixName)) {
+ assemblyName += *postfix;
+ }
+ e1.Element("AssemblyName", assemblyName);
+
+ if (cmStateEnums::EXECUTABLE == this->GeneratorTarget->GetType()) {
+ e1.Element("StartAction", "Program");
+ e1.Element("StartProgram", outDir + assemblyName + ".exe");
+ }
+
+ OptionsHelper oh(o, e1);
+ oh.OutputFlagMap();
+}
+
+//----------------------------------------------------------------------------
+void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues(
+ Elem& e1, std::string const&)
+{
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+ const char* toolset = gg->GetPlatformToolset();
+ e1.Element("NdkToolchainVersion", toolset ? toolset : "Default");
+ if (cmProp minApi = this->GeneratorTarget->GetProperty("ANDROID_API_MIN")) {
+ e1.Element("AndroidMinAPI", "android-" + *minApi);
+ }
+ if (cmProp api = this->GeneratorTarget->GetProperty("ANDROID_API")) {
+ e1.Element("AndroidTargetAPI", "android-" + *api);
+ }
+
+ if (cmProp cpuArch = this->GeneratorTarget->GetProperty("ANDROID_ARCH")) {
+ e1.Element("AndroidArch", *cpuArch);
+ }
+
+ if (cmProp stlType =
+ this->GeneratorTarget->GetProperty("ANDROID_STL_TYPE")) {
+ e1.Element("AndroidStlType", *stlType);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteAndroidConfigurationValues(
+ Elem& e1, std::string const&)
+{
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+ if (cmProp projectToolsetOverride =
+ this->GeneratorTarget->GetProperty("VS_PLATFORM_TOOLSET")) {
+ e1.Element("PlatformToolset", *projectToolsetOverride);
+ } else if (const char* toolset = gg->GetPlatformToolset()) {
+ e1.Element("PlatformToolset", toolset);
+ }
+ if (cmProp stlType =
+ this->GeneratorTarget->GetProperty("ANDROID_STL_TYPE")) {
+ if (*stlType != "none") {
+ e1.Element("UseOfStl", *stlType);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteCustomCommands(Elem& e0)
+{
+ this->CSharpCustomCommandNames.clear();
+
+ cmSourceFile const* srcCMakeLists =
+ this->LocalGenerator->CreateVCProjBuildRule();
+
+ for (cmGeneratorTarget::AllConfigSource const& si :
+ this->GeneratorTarget->GetAllConfigSources()) {
+ if (si.Source == srcCMakeLists) {
+ // Skip explicit reference to CMakeLists.txt source.
+ continue;
+ }
+ this->WriteCustomCommand(e0, si.Source);
+ }
+
+ // Add CMakeLists.txt file with rule to re-run CMake for user convenience.
+ if (this->GeneratorTarget->GetType() != cmStateEnums::GLOBAL_TARGET &&
+ this->GeneratorTarget->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
+ if (srcCMakeLists) {
+ // Write directly rather than through WriteCustomCommand because
+ // we do not want the de-duplication and it has no dependencies.
+ if (cmCustomCommand const* command = srcCMakeLists->GetCustomCommand()) {
+ this->WriteCustomRule(e0, srcCMakeLists, *command);
+ }
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteCustomCommand(
+ Elem& e0, cmSourceFile const* sf)
+{
+ if (this->LocalGenerator->GetSourcesVisited(this->GeneratorTarget)
+ .insert(sf)
+ .second) {
+ if (std::vector<cmSourceFile*> const* depends =
+ this->GeneratorTarget->GetSourceDepends(sf)) {
+ for (cmSourceFile const* di : *depends) {
+ this->WriteCustomCommand(e0, di);
+ }
+ }
+ if (cmCustomCommand const* command = sf->GetCustomCommand()) {
+ // C# projects write their <Target> within WriteCustomRule()
+ this->WriteCustomRule(e0, sf, *command);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteCustomRule(
+ Elem& e0, cmSourceFile const* source, cmCustomCommand const& command)
+{
+ std::string sourcePath = source->GetFullPath();
+ // VS 10 will always rebuild a custom command attached to a .rule
+ // file that doesn't exist so create the file explicitly.
+ if (source->GetPropertyAsBool("__CMAKE_RULE")) {
+ if (!cmSystemTools::FileExists(sourcePath)) {
+ // Make sure the path exists for the file
+ std::string path = cmSystemTools::GetFilenamePath(sourcePath);
+ cmSystemTools::MakeDirectory(path);
+ cmsys::ofstream fout(sourcePath.c_str());
+ if (fout) {
+ fout << "# generated from CMake\n";
+ fout.flush();
+ fout.close();
+ // Force given file to have a very old timestamp, thus
+ // preventing dependent rebuilds.
+ this->ForceOld(sourcePath);
+ } else {
+ std::string error =
+ cmStrCat("Could not create file: [", sourcePath, "] ");
+ cmSystemTools::Error(error + cmSystemTools::GetLastSystemError());
+ }
+ }
+ }
+ cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
+
+ std::unique_ptr<Elem> spe1;
+ std::unique_ptr<Elem> spe2;
+ if (this->ProjectType != csproj) {
+ spe1 = cm::make_unique<Elem>(e0, "ItemGroup");
+ spe2 = cm::make_unique<Elem>(*spe1, "CustomBuild");
+ this->WriteSource(*spe2, source);
+ spe2->SetHasElements();
+ if (command.GetStdPipesUTF8()) {
+ this->WriteStdOutEncodingUtf8(*spe2);
+ }
+ } else {
+ Elem e1(e0, "ItemGroup");
+ Elem e2(e1, "None");
+ this->WriteSource(e2, source);
+ e2.SetHasElements();
+ }
+ for (std::string const& c : this->Configurations) {
+ cmCustomCommandGenerator ccg(command, c, lg);
+ std::string comment = lg->ConstructComment(ccg);
+ comment = cmVS10EscapeComment(comment);
+ std::string script = lg->ConstructScript(ccg);
+ bool symbolic = false;
+ // input files for custom command
+ std::stringstream additional_inputs;
+ {
+ const char* sep = "";
+ if (this->ProjectType == csproj) {
+ // csproj files do not attach the command to a specific file
+ // so the primary input must be listed explicitly.
+ additional_inputs << source->GetFullPath();
+ sep = ";";
+ }
+
+ // Avoid listing an input more than once.
+ std::set<std::string> unique_inputs;
+ // The source is either implicit an input or has been added above.
+ unique_inputs.insert(source->GetFullPath());
+
+ for (std::string const& d : ccg.GetDepends()) {
+ std::string dep;
+ if (lg->GetRealDependency(d, c, dep)) {
+ if (!unique_inputs.insert(dep).second) {
+ // already listed
+ continue;
+ }
+ ConvertToWindowsSlash(dep);
+ additional_inputs << sep << dep;
+ sep = ";";
+ if (!symbolic) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(
+ dep, cmSourceFileLocationKind::Known)) {
+ symbolic = sf->GetPropertyAsBool("SYMBOLIC");
+ }
+ }
+ }
+ }
+ if (this->ProjectType != csproj) {
+ additional_inputs << sep << "%(AdditionalInputs)";
+ }
+ }
+ // output files for custom command
+ std::stringstream outputs;
+ {
+ const char* sep = "";
+ for (std::string const& o : ccg.GetOutputs()) {
+ std::string out = o;
+ ConvertToWindowsSlash(out);
+ outputs << sep << out;
+ sep = ";";
+ if (!symbolic) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(
+ o, cmSourceFileLocationKind::Known)) {
+ symbolic = sf->GetPropertyAsBool("SYMBOLIC");
+ }
+ }
+ }
+ }
+ if (this->ProjectType == csproj) {
+ std::string name = "CustomCommand_" + c + "_" +
+ cmSystemTools::ComputeStringMD5(sourcePath);
+ this->WriteCustomRuleCSharp(e0, c, name, script, additional_inputs.str(),
+ outputs.str(), comment);
+ } else {
+ this->WriteCustomRuleCpp(*spe2, c, script, additional_inputs.str(),
+ outputs.str(), comment, symbolic);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteCustomRuleCpp(
+ Elem& e2, std::string const& config, std::string const& script,
+ std::string const& additional_inputs, std::string const& outputs,
+ std::string const& comment, bool symbolic)
+{
+ const std::string cond = this->CalcCondition(config);
+ e2.WritePlatformConfigTag("Message", cond, comment);
+ e2.WritePlatformConfigTag("Command", cond, script);
+ e2.WritePlatformConfigTag("AdditionalInputs", cond, additional_inputs);
+ e2.WritePlatformConfigTag("Outputs", cond, outputs);
+ if (this->LocalGenerator->GetVersion() >
+ cmGlobalVisualStudioGenerator::VS10) {
+ // VS >= 11 let us turn off linking of custom command outputs.
+ e2.WritePlatformConfigTag("LinkObjects", cond, "false");
+ }
+ if (symbolic &&
+ this->LocalGenerator->GetVersion() >=
+ cmGlobalVisualStudioGenerator::VS16) {
+ // VS >= 16.4 warn if outputs are not created, but one of our
+ // outputs is marked SYMBOLIC and not expected to be created.
+ e2.WritePlatformConfigTag("VerifyInputsAndOutputsExist", cond, "false");
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteCustomRuleCSharp(
+ Elem& e0, std::string const& config, std::string const& name,
+ std::string const& script, std::string const& inputs,
+ std::string const& outputs, std::string const& comment)
+{
+ this->CSharpCustomCommandNames.insert(name);
+ Elem e1(e0, "Target");
+ e1.Attribute("Condition", this->CalcCondition(config));
+ e1.S << "\n Name=\"" << name << "\"";
+ e1.S << "\n Inputs=\"" << cmVS10EscapeAttr(inputs) << "\"";
+ e1.S << "\n Outputs=\"" << cmVS10EscapeAttr(outputs) << "\"";
+ if (!comment.empty()) {
+ Elem(e1, "Exec").Attribute("Command", "echo " + comment);
+ }
+ Elem(e1, "Exec").Attribute("Command", script);
+}
+
+std::string cmVisualStudio10TargetGenerator::ConvertPath(
+ std::string const& path, bool forceRelative)
+{
+ return forceRelative
+ ? cmSystemTools::RelativePath(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), path)
+ : path;
+}
+
+static void ConvertToWindowsSlash(std::string& s)
+{
+ // first convert all of the slashes
+ for (auto& ch : s) {
+ if (ch == '/') {
+ ch = '\\';
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteGroups()
+{
+ if (this->ProjectType == csproj) {
+ return;
+ }
+
+ // collect up group information
+ std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
+
+ std::vector<cmGeneratorTarget::AllConfigSource> const& sources =
+ this->GeneratorTarget->GetAllConfigSources();
+
+ std::set<cmSourceGroup const*> groupsUsed;
+ for (cmGeneratorTarget::AllConfigSource const& si : sources) {
+ std::string const& source = si.Source->GetFullPath();
+ cmSourceGroup* sourceGroup =
+ this->Makefile->FindSourceGroup(source, sourceGroups);
+ groupsUsed.insert(sourceGroup);
+ }
+
+ if (cmSourceFile const* srcCMakeLists =
+ this->LocalGenerator->CreateVCProjBuildRule()) {
+ std::string const& source = srcCMakeLists->GetFullPath();
+ cmSourceGroup* sourceGroup =
+ this->Makefile->FindSourceGroup(source, sourceGroups);
+ groupsUsed.insert(sourceGroup);
+ }
+
+ this->AddMissingSourceGroups(groupsUsed, sourceGroups);
+
+ // Write out group file
+ std::string path = cmStrCat(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), '/', this->Name,
+ computeProjectFileExtension(this->GeneratorTarget), ".filters");
+ cmGeneratedFileStream fout(path);
+ fout.SetCopyIfDifferent(true);
+ char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
+ fout.write(magic, 3);
+
+ fout << "<?xml version=\"1.0\" encoding=\""
+ << this->GlobalGenerator->Encoding() << "\"?>";
+ {
+ Elem e0(fout, "Project");
+ e0.Attribute("ToolsVersion", this->GlobalGenerator->GetToolsVersion());
+ e0.Attribute("xmlns",
+ "http://schemas.microsoft.com/developer/msbuild/2003");
+
+ for (auto const& ti : this->Tools) {
+ this->WriteGroupSources(e0, ti.first, ti.second, sourceGroups);
+ }
+
+ // Added files are images and the manifest.
+ if (!this->AddedFiles.empty()) {
+ Elem e1(e0, "ItemGroup");
+ e1.SetHasElements();
+ for (std::string const& oi : this->AddedFiles) {
+ std::string fileName =
+ cmSystemTools::LowerCase(cmSystemTools::GetFilenameName(oi));
+ if (fileName == "wmappmanifest.xml") {
+ Elem e2(e1, "XML");
+ e2.Attribute("Include", oi);
+ e2.Element("Filter", "Resource Files");
+ } else if (cmSystemTools::GetFilenameExtension(fileName) ==
+ ".appxmanifest") {
+ Elem e2(e1, "AppxManifest");
+ e2.Attribute("Include", oi);
+ e2.Element("Filter", "Resource Files");
+ } else if (cmSystemTools::GetFilenameExtension(fileName) == ".pfx") {
+ Elem e2(e1, "None");
+ e2.Attribute("Include", oi);
+ e2.Element("Filter", "Resource Files");
+ } else {
+ Elem e2(e1, "Image");
+ e2.Attribute("Include", oi);
+ e2.Element("Filter", "Resource Files");
+ }
+ }
+ }
+
+ if (!this->ResxObjs.empty()) {
+ Elem e1(e0, "ItemGroup");
+ for (cmSourceFile const* oi : this->ResxObjs) {
+ std::string obj = oi->GetFullPath();
+ ConvertToWindowsSlash(obj);
+ Elem e2(e1, "EmbeddedResource");
+ e2.Attribute("Include", obj);
+ e2.Element("Filter", "Resource Files");
+ }
+ }
+ {
+ Elem e1(e0, "ItemGroup");
+ e1.SetHasElements();
+ std::vector<cmSourceGroup const*> groupsVec(groupsUsed.begin(),
+ groupsUsed.end());
+ std::sort(groupsVec.begin(), groupsVec.end(),
+ [](cmSourceGroup const* l, cmSourceGroup const* r) {
+ return l->GetFullName() < r->GetFullName();
+ });
+ for (cmSourceGroup const* sg : groupsVec) {
+ std::string const& name = sg->GetFullName();
+ if (!name.empty()) {
+ std::string guidName = "SG_Filter_" + name;
+ std::string guid = this->GlobalGenerator->GetGUID(guidName);
+ Elem e2(e1, "Filter");
+ e2.Attribute("Include", name);
+ e2.Element("UniqueIdentifier", "{" + guid + "}");
+ }
+ }
+
+ if (!this->ResxObjs.empty() || !this->AddedFiles.empty()) {
+ std::string guidName = "SG_Filter_Resource Files";
+ std::string guid = this->GlobalGenerator->GetGUID(guidName);
+ Elem e2(e1, "Filter");
+ e2.Attribute("Include", "Resource Files");
+ e2.Element("UniqueIdentifier", "{" + guid + "}");
+ e2.Element("Extensions",
+ "rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;"
+ "gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms");
+ }
+ }
+ }
+ fout << '\n';
+
+ if (fout.Close()) {
+ this->GlobalGenerator->FileReplacedDuringGenerate(path);
+ }
+}
+
+// Add to groupsUsed empty source groups that have non-empty children.
+void cmVisualStudio10TargetGenerator::AddMissingSourceGroups(
+ std::set<cmSourceGroup const*>& groupsUsed,
+ const std::vector<cmSourceGroup>& allGroups)
+{
+ for (cmSourceGroup const& current : allGroups) {
+ std::vector<cmSourceGroup> const& children = current.GetGroupChildren();
+ if (children.empty()) {
+ continue; // the group is really empty
+ }
+
+ this->AddMissingSourceGroups(groupsUsed, children);
+
+ if (groupsUsed.count(&current) > 0) {
+ continue; // group has already been added to set
+ }
+
+ // check if it least one of the group's descendants is not empty
+ // (at least one child must already have been added)
+ auto child_it = children.begin();
+ while (child_it != children.end()) {
+ if (groupsUsed.count(&(*child_it)) > 0) {
+ break; // found a child that was already added => add current group too
+ }
+ child_it++;
+ }
+
+ if (child_it == children.end()) {
+ continue; // no descendants have source files => ignore this group
+ }
+
+ groupsUsed.insert(&current);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteGroupSources(
+ Elem& e0, std::string const& name, ToolSources const& sources,
+ std::vector<cmSourceGroup>& sourceGroups)
+{
+ Elem e1(e0, "ItemGroup");
+ e1.SetHasElements();
+ for (ToolSource const& s : sources) {
+ cmSourceFile const* sf = s.SourceFile;
+ std::string const& source = sf->GetFullPath();
+ cmSourceGroup* sourceGroup =
+ this->Makefile->FindSourceGroup(source, sourceGroups);
+ std::string const& filter = sourceGroup->GetFullName();
+ std::string path = this->ConvertPath(source, s.RelativePath);
+ ConvertToWindowsSlash(path);
+ Elem e2(e1, name);
+ e2.Attribute("Include", path);
+ if (!filter.empty()) {
+ e2.Element("Filter", filter);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteHeaderSource(Elem& e1,
+ cmSourceFile const* sf)
+{
+ std::string const& fileName = sf->GetFullPath();
+ Elem e2(e1, "ClInclude");
+ this->WriteSource(e2, sf);
+ if (this->IsResxHeader(fileName)) {
+ e2.Element("FileType", "CppForm");
+ } else if (this->IsXamlHeader(fileName)) {
+ e2.Element("DependentUpon",
+ fileName.substr(0, fileName.find_last_of(".")));
+ }
+}
+
+void cmVisualStudio10TargetGenerator::ParseSettingsProperty(
+ const std::string& settingsPropertyValue, ConfigToSettings& toolSettings)
+{
+ if (!settingsPropertyValue.empty()) {
+ cmGeneratorExpression ge;
+
+ std::unique_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(settingsPropertyValue);
+
+ for (const std::string& config : this->Configurations) {
+ std::string evaluated = cge->Evaluate(this->LocalGenerator, config);
+
+ std::vector<std::string> settings = cmExpandedList(evaluated);
+ for (const std::string& setting : settings) {
+ const std::string::size_type assignment = setting.find('=');
+ if (assignment != std::string::npos) {
+ const std::string propName = setting.substr(0, assignment);
+ const std::string propValue = setting.substr(assignment + 1);
+
+ if (!propValue.empty()) {
+ toolSettings[config][propName] = propValue;
+ }
+ }
+ }
+ }
+ }
+}
+
+bool cmVisualStudio10TargetGenerator::PropertyIsSameInAllConfigs(
+ const ConfigToSettings& toolSettings, const std::string& propName)
+{
+ std::string firstPropValue = "";
+ for (const auto& configToSettings : toolSettings) {
+ const std::unordered_map<std::string, std::string>& settings =
+ configToSettings.second;
+
+ if (firstPropValue.empty()) {
+ if (settings.find(propName) != settings.end()) {
+ firstPropValue = settings.find(propName)->second;
+ }
+ }
+
+ if (settings.find(propName) == settings.end()) {
+ return false;
+ }
+
+ if (settings.find(propName)->second != firstPropValue) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
+ cmSourceFile const* sf)
+{
+ bool toolHasSettings = false;
+ const char* tool = "None";
+ std::string settingsGenerator;
+ std::string settingsLastGenOutput;
+ std::string sourceLink;
+ std::string subType;
+ std::string copyToOutDir;
+ std::string includeInVsix;
+ std::string ext = cmSystemTools::LowerCase(sf->GetExtension());
+ ConfigToSettings toolSettings;
+ for (const auto& config : this->Configurations) {
+ toolSettings[config];
+ }
+
+ if (this->ProjectType == csproj && !this->InSourceBuild) {
+ toolHasSettings = true;
+ }
+ if (ext == "hlsl") {
+ tool = "FXCompile";
+ // Figure out the type of shader compiler to use.
+ if (cmProp st = sf->GetProperty("VS_SHADER_TYPE")) {
+ for (const std::string& config : this->Configurations) {
+ toolSettings[config]["ShaderType"] = *st;
+ }
+ }
+ // Figure out which entry point to use if any
+ if (cmProp se = sf->GetProperty("VS_SHADER_ENTRYPOINT")) {
+ for (const std::string& config : this->Configurations) {
+ toolSettings[config]["EntryPointName"] = *se;
+ }
+ }
+ // Figure out which shader model to use if any
+ if (cmProp sm = sf->GetProperty("VS_SHADER_MODEL")) {
+ for (const std::string& config : this->Configurations) {
+ toolSettings[config]["ShaderModel"] = *sm;
+ }
+ }
+ // Figure out which output header file to use if any
+ if (cmProp ohf = sf->GetProperty("VS_SHADER_OUTPUT_HEADER_FILE")) {
+ for (const std::string& config : this->Configurations) {
+ toolSettings[config]["HeaderFileOutput"] = *ohf;
+ }
+ }
+ // Figure out which variable name to use if any
+ if (cmProp vn = sf->GetProperty("VS_SHADER_VARIABLE_NAME")) {
+ for (const std::string& config : this->Configurations) {
+ toolSettings[config]["VariableName"] = *vn;
+ }
+ }
+ // Figure out if there's any additional flags to use
+ if (cmProp saf = sf->GetProperty("VS_SHADER_FLAGS")) {
+ cmGeneratorExpression ge;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*saf);
+
+ for (const std::string& config : this->Configurations) {
+ std::string evaluated = cge->Evaluate(this->LocalGenerator, config);
+
+ if (!evaluated.empty()) {
+ toolSettings[config]["AdditionalOptions"] = evaluated;
+ }
+ }
+ }
+ // Figure out if debug information should be generated
+ if (cmProp sed = sf->GetProperty("VS_SHADER_ENABLE_DEBUG")) {
+ cmGeneratorExpression ge;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*sed);
+
+ for (const std::string& config : this->Configurations) {
+ std::string evaluated = cge->Evaluate(this->LocalGenerator, config);
+
+ if (!evaluated.empty()) {
+ toolSettings[config]["EnableDebuggingInformation"] =
+ cmIsOn(evaluated) ? "true" : "false";
+ }
+ }
+ }
+ // Figure out if optimizations should be disabled
+ if (cmProp sdo = sf->GetProperty("VS_SHADER_DISABLE_OPTIMIZATIONS")) {
+ cmGeneratorExpression ge;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*sdo);
+
+ for (const std::string& config : this->Configurations) {
+ std::string evaluated = cge->Evaluate(this->LocalGenerator, config);
+
+ if (!evaluated.empty()) {
+ toolSettings[config]["DisableOptimizations"] =
+ cmIsOn(evaluated) ? "true" : "false";
+ }
+ }
+ }
+ if (cmProp sofn = sf->GetProperty("VS_SHADER_OBJECT_FILE_NAME")) {
+ for (const std::string& config : this->Configurations) {
+ toolSettings[config]["ObjectFileOutput"] = *sofn;
+ }
+ }
+ } else if (ext == "jpg" || ext == "png") {
+ tool = "Image";
+ } else if (ext == "resw") {
+ tool = "PRIResource";
+ } else if (ext == "xml") {
+ tool = "XML";
+ } else if (ext == "natvis") {
+ tool = "Natvis";
+ } else if (ext == "settings") {
+ settingsLastGenOutput =
+ cmsys::SystemTools::GetFilenameName(sf->GetFullPath());
+ std::size_t pos = settingsLastGenOutput.find(".settings");
+ settingsLastGenOutput.replace(pos, 9, ".Designer.cs");
+ settingsGenerator = "SettingsSingleFileGenerator";
+ toolHasSettings = true;
+ } else if (ext == "vsixmanifest") {
+ subType = "Designer";
+ }
+ if (cmProp c = sf->GetProperty("VS_COPY_TO_OUT_DIR")) {
+ tool = "Content";
+ copyToOutDir = *c;
+ toolHasSettings = true;
+ }
+ if (sf->GetPropertyAsBool("VS_INCLUDE_IN_VSIX")) {
+ includeInVsix = "True";
+ tool = "Content";
+ toolHasSettings = true;
+ }
+
+ // Collect VS_CSHARP_* property values (if some are set)
+ std::map<std::string, std::string> sourceFileTags;
+ this->GetCSharpSourceProperties(sf, sourceFileTags);
+
+ if (this->NsightTegra) {
+ // Nsight Tegra needs specific file types to check up-to-dateness.
+ std::string name = cmSystemTools::LowerCase(sf->GetLocation().GetName());
+ if (name == "androidmanifest.xml" || name == "build.xml" ||
+ name == "proguard.cfg" || name == "proguard-project.txt" ||
+ ext == "properties") {
+ tool = "AndroidBuild";
+ } else if (ext == "java") {
+ tool = "JCompile";
+ } else if (ext == "asm" || ext == "s") {
+ tool = "ClCompile";
+ }
+ }
+
+ cmProp toolOverride = sf->GetProperty("VS_TOOL_OVERRIDE");
+ if (cmNonempty(toolOverride)) {
+ tool = toolOverride->c_str();
+ }
+
+ std::string deployContent;
+ std::string deployLocation;
+ if (this->GlobalGenerator->TargetsWindowsPhone() ||
+ this->GlobalGenerator->TargetsWindowsStore()) {
+ cmProp content = sf->GetProperty("VS_DEPLOYMENT_CONTENT");
+ if (cmNonempty(content)) {
+ toolHasSettings = true;
+ deployContent = *content;
+
+ cmProp location = sf->GetProperty("VS_DEPLOYMENT_LOCATION");
+ if (cmNonempty(location)) {
+ deployLocation = *location;
+ }
+ }
+ }
+
+ if (ParsedToolTargetSettings.find(tool) == ParsedToolTargetSettings.end()) {
+ cmProp toolTargetProperty = this->GeneratorTarget->Target->GetProperty(
+ "VS_SOURCE_SETTINGS_" + std::string(tool));
+ ConfigToSettings toolTargetSettings;
+ if (toolTargetProperty) {
+ ParseSettingsProperty(*toolTargetProperty, toolTargetSettings);
+ }
+
+ ParsedToolTargetSettings[tool] = toolTargetSettings;
+ }
+
+ for (const auto& configToSetting : ParsedToolTargetSettings[tool]) {
+ for (const auto& setting : configToSetting.second) {
+ toolSettings[configToSetting.first][setting.first] = setting.second;
+ }
+ }
+
+ if (cmProp p = sf->GetProperty("VS_SETTINGS")) {
+ ParseSettingsProperty(*p, toolSettings);
+ }
+
+ if (!toolSettings.empty()) {
+ toolHasSettings = true;
+ }
+
+ Elem e2(e1, tool);
+ this->WriteSource(e2, sf);
+ if (toolHasSettings) {
+ e2.SetHasElements();
+
+ std::vector<std::string> writtenSettings;
+ for (const auto& configSettings : toolSettings) {
+ for (const auto& setting : configSettings.second) {
+
+ if (std::find(writtenSettings.begin(), writtenSettings.end(),
+ setting.first) != writtenSettings.end()) {
+ continue;
+ }
+
+ if (PropertyIsSameInAllConfigs(toolSettings, setting.first)) {
+ e2.Element(setting.first, setting.second);
+ writtenSettings.push_back(setting.first);
+ } else {
+ e2.WritePlatformConfigTag(setting.first,
+ "'$(Configuration)|$(Platform)'=='" +
+ configSettings.first + "|" +
+ this->Platform + "'",
+ setting.second);
+ }
+ }
+ }
+
+ if (!deployContent.empty()) {
+ cmGeneratorExpression ge;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(deployContent);
+ // Deployment location cannot be set on a configuration basis
+ if (!deployLocation.empty()) {
+ e2.Element("Link", deployLocation + "\\%(FileName)%(Extension)");
+ }
+ for (size_t i = 0; i != this->Configurations.size(); ++i) {
+ if (cge->Evaluate(this->LocalGenerator, this->Configurations[i]) ==
+ "1") {
+ e2.WritePlatformConfigTag("DeploymentContent",
+ "'$(Configuration)|$(Platform)'=='" +
+ this->Configurations[i] + "|" +
+ this->Platform + "'",
+ "true");
+ } else {
+ e2.WritePlatformConfigTag("ExcludedFromBuild",
+ "'$(Configuration)|$(Platform)'=='" +
+ this->Configurations[i] + "|" +
+ this->Platform + "'",
+ "true");
+ }
+ }
+ }
+
+ if (!settingsGenerator.empty()) {
+ e2.Element("Generator", settingsGenerator);
+ }
+ if (!settingsLastGenOutput.empty()) {
+ e2.Element("LastGenOutput", settingsLastGenOutput);
+ }
+ if (!subType.empty()) {
+ e2.Element("SubType", subType);
+ }
+ if (!copyToOutDir.empty()) {
+ e2.Element("CopyToOutputDirectory", copyToOutDir);
+ }
+ if (!includeInVsix.empty()) {
+ e2.Element("IncludeInVSIX", includeInVsix);
+ }
+ // write source file specific tags
+ this->WriteCSharpSourceProperties(e2, sourceFileTags);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteSource(Elem& e2,
+ cmSourceFile const* sf)
+{
+ // Visual Studio tools append relative paths to the current dir, as in:
+ //
+ // c:\path\to\current\dir\..\..\..\relative\path\to\source.c
+ //
+ // and fail if this exceeds the maximum allowed path length. Our path
+ // conversion uses full paths when possible to allow deeper trees.
+ // However, CUDA 8.0 msbuild rules fail on absolute paths so for CUDA
+ // we must use relative paths.
+ bool forceRelative = sf->GetLanguage() == "CUDA";
+ std::string sourceFile = this->ConvertPath(sf->GetFullPath(), forceRelative);
+ if (this->LocalGenerator->GetVersion() ==
+ cmGlobalVisualStudioGenerator::VS10 &&
+ cmSystemTools::FileIsFullPath(sourceFile)) {
+ // Normal path conversion resulted in a full path. VS 10 (but not 11)
+ // refuses to show the property page in the IDE for a source file with a
+ // full path (not starting in a '.' or '/' AFAICT). CMake <= 2.8.4 used a
+ // relative path but to allow deeper build trees CMake 2.8.[5678] used a
+ // full path except for custom commands. Custom commands do not work
+ // without a relative path, but they do not seem to be involved in tools
+ // with the above behavior. For other sources we now use a relative path
+ // when the combined path will not be too long so property pages appear.
+ std::string sourceRel = this->ConvertPath(sf->GetFullPath(), true);
+ size_t const maxLen = 250;
+ if (sf->GetCustomCommand() ||
+ ((this->LocalGenerator->GetCurrentBinaryDirectory().length() + 1 +
+ sourceRel.length()) <= maxLen)) {
+ forceRelative = true;
+ sourceFile = sourceRel;
+ } else {
+ this->GlobalGenerator->PathTooLong(this->GeneratorTarget, sf, sourceRel);
+ }
+ }
+ ConvertToWindowsSlash(sourceFile);
+ e2.Attribute("Include", sourceFile);
+
+ if (this->ProjectType == csproj && !this->InSourceBuild) {
+ // For out of source projects we have to provide a link (if not specified
+ // via property) for every source file (besides .cs files) otherwise they
+ // will not be visible in VS at all.
+ // First we check if the file is in a source group, then we check if the
+ // file path is relative to current source- or binary-dir, otherwise it is
+ // added with the plain filename without any path. This means the file will
+ // show up at root-level of the csproj (where CMakeLists.txt etc. are).
+ std::string link = this->GetCSharpSourceLink(sf);
+ if (link.empty())
+ link = cmsys::SystemTools::GetFilenameName(sf->GetFullPath());
+ e2.Element("Link", link);
+ }
+
+ ToolSource toolSource = { sf, forceRelative };
+ this->Tools[e2.Tag].push_back(toolSource);
+}
+
+void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0)
+{
+ if (this->GeneratorTarget->GetType() == cmStateEnums::GLOBAL_TARGET) {
+ return;
+ }
+
+ const bool haveUnityBuild =
+ this->GeneratorTarget->GetPropertyAsBool("UNITY_BUILD");
+
+ if (haveUnityBuild && this->GlobalGenerator->GetSupportsUnityBuilds()) {
+ Elem e1(e0, "PropertyGroup");
+ e1.Element("EnableUnitySupport", "true");
+ }
+
+ Elem e1(e0, "ItemGroup");
+ e1.SetHasElements();
+
+ std::vector<size_t> all_configs;
+ for (size_t ci = 0; ci < this->Configurations.size(); ++ci) {
+ all_configs.push_back(ci);
+ }
+
+ std::vector<cmGeneratorTarget::AllConfigSource> const& sources =
+ this->GeneratorTarget->GetAllConfigSources();
+
+ cmSourceFile const* srcCMakeLists =
+ this->LocalGenerator->CreateVCProjBuildRule();
+
+ for (cmGeneratorTarget::AllConfigSource const& si : sources) {
+ if (si.Source == srcCMakeLists) {
+ // Skip explicit reference to CMakeLists.txt source.
+ continue;
+ }
+ const char* tool = nullptr;
+ switch (si.Kind) {
+ case cmGeneratorTarget::SourceKindAppManifest:
+ tool = "AppxManifest";
+ break;
+ case cmGeneratorTarget::SourceKindCertificate:
+ tool = "None";
+ break;
+ case cmGeneratorTarget::SourceKindCustomCommand:
+ // Handled elsewhere.
+ break;
+ case cmGeneratorTarget::SourceKindExternalObject:
+ tool = "Object";
+ if (this->LocalGenerator->GetVersion() <
+ cmGlobalVisualStudioGenerator::VS11) {
+ // For VS == 10 we cannot use LinkObjects to avoid linking custom
+ // command outputs. If an object file is generated in this target,
+ // then vs10 will use it in the build, and we have to list it as
+ // None instead of Object.
+ std::vector<cmSourceFile*> const* d =
+ this->GeneratorTarget->GetSourceDepends(si.Source);
+ if (d && !d->empty()) {
+ tool = "None";
+ }
+ }
+ break;
+ case cmGeneratorTarget::SourceKindExtra:
+ this->WriteExtraSource(e1, si.Source);
+ break;
+ case cmGeneratorTarget::SourceKindHeader:
+ this->WriteHeaderSource(e1, si.Source);
+ break;
+ case cmGeneratorTarget::SourceKindIDL:
+ tool = "Midl";
+ break;
+ case cmGeneratorTarget::SourceKindManifest:
+ // Handled elsewhere.
+ break;
+ case cmGeneratorTarget::SourceKindModuleDefinition:
+ tool = "None";
+ break;
+ case cmGeneratorTarget::SourceKindUnityBatched:
+ case cmGeneratorTarget::SourceKindObjectSource: {
+ const std::string& lang = si.Source->GetLanguage();
+ if (lang == "C" || lang == "CXX") {
+ tool = "ClCompile";
+ } else if (lang == "ASM_MASM" &&
+ this->GlobalGenerator->IsMasmEnabled()) {
+ tool = "MASM";
+ } else if (lang == "ASM_NASM" &&
+ this->GlobalGenerator->IsNasmEnabled()) {
+ tool = "NASM";
+ } else if (lang == "RC") {
+ tool = "ResourceCompile";
+ } else if (lang == "CSharp") {
+ tool = "Compile";
+ } else if (lang == "CUDA" && this->GlobalGenerator->IsCudaEnabled()) {
+ tool = "CudaCompile";
+ } else {
+ tool = "None";
+ }
+ } break;
+ case cmGeneratorTarget::SourceKindResx:
+ this->ResxObjs.push_back(si.Source);
+ break;
+ case cmGeneratorTarget::SourceKindXaml:
+ this->XamlObjs.push_back(si.Source);
+ break;
+ }
+
+ if (tool) {
+ // Compute set of configurations to exclude, if any.
+ std::vector<size_t> const& include_configs = si.Configs;
+ std::vector<size_t> exclude_configs;
+ std::set_difference(all_configs.begin(), all_configs.end(),
+ include_configs.begin(), include_configs.end(),
+ std::back_inserter(exclude_configs));
+
+ Elem e2(e1, tool);
+ this->WriteSource(e2, si.Source);
+
+ bool useNativeUnityBuild = false;
+ if (haveUnityBuild && this->GlobalGenerator->GetSupportsUnityBuilds()) {
+ // Magic value taken from cmGlobalVisualStudioVersionedGenerator.cxx
+ static const std::string vs15 = "141";
+ std::string toolset =
+ this->GlobalGenerator->GetPlatformToolsetString();
+ cmSystemTools::ReplaceString(toolset, "v", "");
+
+ if (toolset.empty() ||
+ cmSystemTools::VersionCompareGreaterEq(toolset, vs15)) {
+ useNativeUnityBuild = true;
+ }
+ }
+
+ if (haveUnityBuild && strcmp(tool, "ClCompile") == 0 &&
+ si.Source->GetProperty("UNITY_SOURCE_FILE")) {
+ if (useNativeUnityBuild) {
+ e2.Attribute(
+ "IncludeInUnityFile",
+ si.Source->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION")
+ ? "false"
+ : "true");
+ e2.Attribute("CustomUnityFile", "true");
+
+ std::string unityDir = cmSystemTools::GetFilenamePath(
+ *si.Source->GetProperty("UNITY_SOURCE_FILE"));
+ e2.Attribute("UnityFilesDirectory", unityDir);
+ } else {
+ // Visual Studio versions prior to 2017 15.8 do not know about unity
+ // builds, thus we exclude the files already part of unity sources.
+ if (!si.Source->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION")) {
+ exclude_configs = si.Configs;
+ }
+ }
+ }
+
+ if (si.Kind == cmGeneratorTarget::SourceKindObjectSource) {
+ this->OutputSourceSpecificFlags(e2, si.Source);
+ }
+ if (si.Source->GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS")) {
+ e2.Element("PrecompiledHeader", "NotUsing");
+ }
+ if (!exclude_configs.empty()) {
+ this->WriteExcludeFromBuild(e2, exclude_configs);
+ }
+ }
+ }
+
+ if (this->IsMissingFiles) {
+ this->WriteMissingFiles(e1);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
+ Elem& e2, cmSourceFile const* source)
+{
+ cmSourceFile const& sf = *source;
+
+ std::string objectName;
+ if (this->GeneratorTarget->HasExplicitObjectName(&sf)) {
+ objectName = this->GeneratorTarget->GetObjectName(&sf);
+ }
+ std::string flags;
+ bool configDependentFlags = false;
+ std::string options;
+ bool configDependentOptions = false;
+ std::string defines;
+ bool configDependentDefines = false;
+ std::string includes;
+ bool configDependentIncludes = false;
+ if (cmProp cflags = sf.GetProperty("COMPILE_FLAGS")) {
+ configDependentFlags =
+ cmGeneratorExpression::Find(*cflags) != std::string::npos;
+ flags += *cflags;
+ }
+ if (cmProp coptions = sf.GetProperty("COMPILE_OPTIONS")) {
+ configDependentOptions =
+ cmGeneratorExpression::Find(*coptions) != std::string::npos;
+ options += *coptions;
+ }
+ if (cmProp cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) {
+ configDependentDefines =
+ cmGeneratorExpression::Find(*cdefs) != std::string::npos;
+ defines += *cdefs;
+ }
+ if (cmProp cincludes = sf.GetProperty("INCLUDE_DIRECTORIES")) {
+ configDependentIncludes =
+ cmGeneratorExpression::Find(*cincludes) != std::string::npos;
+ includes += *cincludes;
+ }
+
+ // Force language if the file extension does not match.
+ // Note that MSVC treats the upper-case '.C' extension as C and not C++.
+ std::string const ext = sf.GetExtension();
+ std::string const extLang = ext == "C"
+ ? "C"
+ : this->GlobalGenerator->GetLanguageFromExtension(ext.c_str());
+ std::string lang = this->LocalGenerator->GetSourceFileLanguage(sf);
+ const char* compileAs = 0;
+ if (lang != extLang) {
+ if (lang == "CXX") {
+ // force a C++ file type
+ compileAs = "CompileAsCpp";
+ } else if (lang == "C") {
+ // force to c
+ compileAs = "CompileAsC";
+ }
+ }
+
+ bool noWinRT = this->TargetCompileAsWinRT && lang == "C";
+ // for the first time we need a new line if there is something
+ // produced here.
+ if (!objectName.empty()) {
+ if (lang == "CUDA") {
+ e2.Element("CompileOut", "$(IntDir)/" + objectName);
+ } else {
+ e2.Element("ObjectFileName", "$(IntDir)/" + objectName);
+ }
+ }
+ for (std::string const& config : this->Configurations) {
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ std::string configDefines = defines;
+ std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", configUpper);
+ if (cmProp ccdefs = sf.GetProperty(defPropName)) {
+ if (!configDefines.empty()) {
+ configDefines += ";";
+ }
+ configDependentDefines |=
+ cmGeneratorExpression::Find(*ccdefs) != std::string::npos;
+ configDefines += *ccdefs;
+ }
+
+ // We have pch state in the following situation:
+ // 1. We have SKIP_PRECOMPILE_HEADERS == true
+ // 2. We are creating the pre-compiled header
+ // 3. We are a different language than the linker language AND pch is
+ // enabled.
+ std::string const& linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(config);
+ std::string const& pchSource =
+ this->GeneratorTarget->GetPchSource(config, lang);
+ const bool skipPCH =
+ pchSource.empty() || sf.GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS");
+ const bool makePCH = (sf.GetFullPath() == pchSource);
+ const bool useSharedPCH = !skipPCH && (lang == linkLanguage);
+ const bool useDifferentLangPCH = !skipPCH && (lang != linkLanguage);
+ const bool useNoPCH = skipPCH && (lang != linkLanguage) &&
+ !this->GeneratorTarget->GetPchHeader(config, linkLanguage).empty();
+ const bool needsPCHFlags =
+ (makePCH || useSharedPCH || useDifferentLangPCH || useNoPCH);
+
+ // if we have flags or defines for this config then
+ // use them
+ if (!flags.empty() || !options.empty() || !configDefines.empty() ||
+ !includes.empty() || compileAs || noWinRT || !options.empty() ||
+ needsPCHFlags) {
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+ cmIDEFlagTable const* flagtable = nullptr;
+ const std::string& srclang = source->GetLanguage();
+ if (srclang == "C" || srclang == "CXX") {
+ flagtable = gg->GetClFlagTable();
+ } else if (srclang == "ASM_MASM" &&
+ this->GlobalGenerator->IsMasmEnabled()) {
+ flagtable = gg->GetMasmFlagTable();
+ } else if (lang == "ASM_NASM" &&
+ this->GlobalGenerator->IsNasmEnabled()) {
+ flagtable = gg->GetNasmFlagTable();
+ } else if (srclang == "RC") {
+ flagtable = gg->GetRcFlagTable();
+ } else if (srclang == "CSharp") {
+ flagtable = gg->GetCSharpFlagTable();
+ }
+ cmGeneratorExpressionInterpreter genexInterpreter(
+ this->LocalGenerator, config, this->GeneratorTarget, lang);
+ cmVS10GeneratorOptions clOptions(
+ this->LocalGenerator, cmVisualStudioGeneratorOptions::Compiler,
+ flagtable, this);
+ if (compileAs) {
+ clOptions.AddFlag("CompileAs", compileAs);
+ }
+ if (noWinRT) {
+ clOptions.AddFlag("CompileAsWinRT", "false");
+ }
+ if (configDependentFlags) {
+ clOptions.Parse(genexInterpreter.Evaluate(flags, "COMPILE_FLAGS"));
+ } else {
+ clOptions.Parse(flags);
+ }
+
+ if (needsPCHFlags) {
+ // Add precompile headers compile options.
+ std::string expandedOptions;
+ std::string pchOptions;
+ if (makePCH) {
+ pchOptions =
+ this->GeneratorTarget->GetPchCreateCompileOptions(config, lang);
+ } else if (useNoPCH) {
+ clOptions.AddFlag("PrecompiledHeader", "NotUsing");
+ } else if (useSharedPCH) {
+ std::string pchHeader =
+ this->GeneratorTarget->GetPchHeader(config, lang);
+ clOptions.AddFlag("ForcedIncludeFiles", pchHeader);
+ } else if (useDifferentLangPCH) {
+ pchOptions =
+ this->GeneratorTarget->GetPchUseCompileOptions(config, lang);
+ }
+ this->LocalGenerator->AppendCompileOptions(expandedOptions,
+ pchOptions);
+ clOptions.Parse(expandedOptions);
+ }
+
+ if (!options.empty()) {
+ std::string expandedOptions;
+ if (configDependentOptions) {
+ this->LocalGenerator->AppendCompileOptions(
+ expandedOptions,
+ genexInterpreter.Evaluate(options, "COMPILE_OPTIONS"));
+ } else {
+ this->LocalGenerator->AppendCompileOptions(expandedOptions, options);
+ }
+ clOptions.Parse(expandedOptions);
+ }
+ if (clOptions.HasFlag("DisableSpecificWarnings")) {
+ clOptions.AppendFlag("DisableSpecificWarnings",
+ "%(DisableSpecificWarnings)");
+ }
+ if (clOptions.HasFlag("ForcedIncludeFiles")) {
+ clOptions.AppendFlag("ForcedIncludeFiles", "%(ForcedIncludeFiles)");
+ }
+ if (configDependentDefines) {
+ clOptions.AddDefines(
+ genexInterpreter.Evaluate(configDefines, "COMPILE_DEFINITIONS"));
+ } else {
+ clOptions.AddDefines(configDefines);
+ }
+ std::vector<std::string> includeList;
+ if (configDependentIncludes) {
+ this->LocalGenerator->AppendIncludeDirectories(
+ includeList,
+ genexInterpreter.Evaluate(includes, "INCLUDE_DIRECTORIES"), *source);
+ } else {
+ this->LocalGenerator->AppendIncludeDirectories(includeList, includes,
+ *source);
+ }
+ clOptions.AddIncludes(includeList);
+ clOptions.SetConfiguration(config);
+ OptionsHelper oh(clOptions, e2);
+ oh.PrependInheritedString("AdditionalOptions");
+ oh.OutputAdditionalIncludeDirectories(lang);
+ oh.OutputFlagMap();
+ oh.OutputPreprocessorDefinitions(lang);
+ }
+ }
+ if (this->IsXamlSource(source->GetFullPath())) {
+ const std::string& fileName = source->GetFullPath();
+ e2.Element("DependentUpon",
+ fileName.substr(0, fileName.find_last_of(".")));
+ }
+ if (this->ProjectType == csproj) {
+ std::string f = source->GetFullPath();
+ using CsPropMap = std::map<std::string, std::string>;
+ CsPropMap sourceFileTags;
+ this->GetCSharpSourceProperties(&sf, sourceFileTags);
+ // write source file specific tags
+ if (!sourceFileTags.empty()) {
+ this->WriteCSharpSourceProperties(e2, sourceFileTags);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteExcludeFromBuild(
+ Elem& e2, std::vector<size_t> const& exclude_configs)
+{
+ for (size_t ci : exclude_configs) {
+ e2.WritePlatformConfigTag("ExcludedFromBuild",
+ "'$(Configuration)|$(Platform)'=='" +
+ this->Configurations[ci] + "|" +
+ this->Platform + "'",
+ "true");
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions(
+ Elem& e0)
+{
+ cmStateEnums::TargetType ttype = this->GeneratorTarget->GetType();
+ if (ttype > cmStateEnums::GLOBAL_TARGET) {
+ return;
+ }
+ if (this->ProjectType == csproj) {
+ return;
+ }
+
+ Elem e1(e0, "PropertyGroup");
+ e1.Element("_ProjectFileVersion", "10.0.20506.1");
+ for (std::string const& config : this->Configurations) {
+ const std::string cond = this->CalcCondition(config);
+
+ if (ttype <= cmStateEnums::UTILITY) {
+ if (cmProp workingDir = this->GeneratorTarget->GetProperty(
+ "VS_DEBUGGER_WORKING_DIRECTORY")) {
+ std::string genWorkingDir = cmGeneratorExpression::Evaluate(
+ *workingDir, this->LocalGenerator, config);
+ e1.WritePlatformConfigTag("LocalDebuggerWorkingDirectory", cond,
+ genWorkingDir);
+ }
+
+ if (cmProp environment =
+ this->GeneratorTarget->GetProperty("VS_DEBUGGER_ENVIRONMENT")) {
+ std::string genEnvironment = cmGeneratorExpression::Evaluate(
+ *environment, this->LocalGenerator, config);
+ e1.WritePlatformConfigTag("LocalDebuggerEnvironment", cond,
+ genEnvironment);
+ }
+
+ if (cmProp debuggerCommand =
+ this->GeneratorTarget->GetProperty("VS_DEBUGGER_COMMAND")) {
+ std::string genDebuggerCommand = cmGeneratorExpression::Evaluate(
+ *debuggerCommand, this->LocalGenerator, config);
+ e1.WritePlatformConfigTag("LocalDebuggerCommand", cond,
+ genDebuggerCommand);
+ }
+
+ if (cmProp commandArguments = this->GeneratorTarget->GetProperty(
+ "VS_DEBUGGER_COMMAND_ARGUMENTS")) {
+ std::string genCommandArguments = cmGeneratorExpression::Evaluate(
+ *commandArguments, this->LocalGenerator, config);
+ e1.WritePlatformConfigTag("LocalDebuggerCommandArguments", cond,
+ genCommandArguments);
+ }
+ }
+
+ if (ttype >= cmStateEnums::UTILITY) {
+ e1.WritePlatformConfigTag(
+ "IntDir", cond, "$(Platform)\\$(Configuration)\\$(ProjectName)\\");
+ } else {
+ std::string intermediateDir = cmStrCat(
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), '/',
+ config, '/');
+ std::string outDir;
+ std::string targetNameFull;
+ if (ttype == cmStateEnums::OBJECT_LIBRARY) {
+ outDir = intermediateDir;
+ targetNameFull = cmStrCat(this->GeneratorTarget->GetName(), ".lib");
+ } else {
+ outDir = this->GeneratorTarget->GetDirectory(config) + "/";
+ targetNameFull = this->GeneratorTarget->GetFullName(config);
+ }
+ ConvertToWindowsSlash(intermediateDir);
+ ConvertToWindowsSlash(outDir);
+
+ e1.WritePlatformConfigTag("OutDir", cond, outDir);
+
+ e1.WritePlatformConfigTag("IntDir", cond, intermediateDir);
+
+ if (cmProp sdkExecutableDirectories = this->Makefile->GetDefinition(
+ "CMAKE_VS_SDK_EXECUTABLE_DIRECTORIES")) {
+ e1.WritePlatformConfigTag("ExecutablePath", cond,
+ *sdkExecutableDirectories);
+ }
+
+ if (cmProp sdkIncludeDirectories = this->Makefile->GetDefinition(
+ "CMAKE_VS_SDK_INCLUDE_DIRECTORIES")) {
+ e1.WritePlatformConfigTag("IncludePath", cond, *sdkIncludeDirectories);
+ }
+
+ if (cmProp sdkReferenceDirectories = this->Makefile->GetDefinition(
+ "CMAKE_VS_SDK_REFERENCE_DIRECTORIES")) {
+ e1.WritePlatformConfigTag("ReferencePath", cond,
+ *sdkReferenceDirectories);
+ }
+
+ if (cmProp sdkLibraryDirectories = this->Makefile->GetDefinition(
+ "CMAKE_VS_SDK_LIBRARY_DIRECTORIES")) {
+ e1.WritePlatformConfigTag("LibraryPath", cond, *sdkLibraryDirectories);
+ }
+
+ if (cmProp sdkLibraryWDirectories = this->Makefile->GetDefinition(
+ "CMAKE_VS_SDK_LIBRARY_WINRT_DIRECTORIES")) {
+ e1.WritePlatformConfigTag("LibraryWPath", cond,
+ *sdkLibraryWDirectories);
+ }
+
+ if (cmProp sdkSourceDirectories =
+ this->Makefile->GetDefinition("CMAKE_VS_SDK_SOURCE_DIRECTORIES")) {
+ e1.WritePlatformConfigTag("SourcePath", cond, *sdkSourceDirectories);
+ }
+
+ if (cmProp sdkExcludeDirectories = this->Makefile->GetDefinition(
+ "CMAKE_VS_SDK_EXCLUDE_DIRECTORIES")) {
+ e1.WritePlatformConfigTag("ExcludePath", cond, *sdkExcludeDirectories);
+ }
+
+ std::string name =
+ cmSystemTools::GetFilenameWithoutLastExtension(targetNameFull);
+ e1.WritePlatformConfigTag("TargetName", cond, name);
+
+ std::string ext =
+ cmSystemTools::GetFilenameLastExtension(targetNameFull);
+ if (ext.empty()) {
+ // An empty TargetExt causes a default extension to be used.
+ // A single "." appears to be treated as an empty extension.
+ ext = ".";
+ }
+ e1.WritePlatformConfigTag("TargetExt", cond, ext);
+
+ this->OutputLinkIncremental(e1, config);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::OutputLinkIncremental(
+ Elem& e1, std::string const& configName)
+{
+ if (!this->MSTools) {
+ return;
+ }
+ if (this->ProjectType == csproj) {
+ return;
+ }
+ // static libraries and things greater than modules do not need
+ // to set this option
+ if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ this->GeneratorTarget->GetType() > cmStateEnums::MODULE_LIBRARY) {
+ return;
+ }
+ Options& linkOptions = *(this->LinkOptions[configName]);
+ const std::string cond = this->CalcCondition(configName);
+
+ if (this->IPOEnabledConfigurations.count(configName) == 0) {
+ const char* incremental = linkOptions.GetFlag("LinkIncremental");
+ e1.WritePlatformConfigTag("LinkIncremental", cond,
+ (incremental ? incremental : "true"));
+ }
+ linkOptions.RemoveFlag("LinkIncremental");
+
+ const char* manifest = linkOptions.GetFlag("GenerateManifest");
+ e1.WritePlatformConfigTag("GenerateManifest", cond,
+ (manifest ? manifest : "true"));
+ linkOptions.RemoveFlag("GenerateManifest");
+
+ // Some link options belong here. Use them now and remove them so that
+ // WriteLinkOptions does not use them.
+ static const std::vector<std::string> flags{ "LinkDelaySign",
+ "LinkKeyFile" };
+ for (const std::string& flag : flags) {
+ if (const char* value = linkOptions.GetFlag(flag)) {
+ e1.WritePlatformConfigTag(flag, cond, value);
+ linkOptions.RemoveFlag(flag);
+ }
+ }
+}
+
+std::vector<std::string> cmVisualStudio10TargetGenerator::GetIncludes(
+ std::string const& config, std::string const& lang) const
+{
+ std::vector<std::string> includes;
+ this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
+ lang, config);
+ for (std::string& i : includes) {
+ ConvertToWindowsSlash(i);
+ }
+ return includes;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeClOptions()
+{
+ for (std::string const& c : this->Configurations) {
+ if (!this->ComputeClOptions(c)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeClOptions(
+ std::string const& configName)
+{
+ // much of this was copied from here:
+ // copied from cmLocalVisualStudio7Generator.cxx 805
+ // TODO: Integrate code below with cmLocalVisualStudio7Generator.
+
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+ std::unique_ptr<Options> pOptions;
+ switch (this->ProjectType) {
+ case vcxproj:
+ pOptions = cm::make_unique<Options>(
+ this->LocalGenerator, Options::Compiler, gg->GetClFlagTable());
+ break;
+ case csproj:
+ pOptions =
+ cm::make_unique<Options>(this->LocalGenerator, Options::CSharpCompiler,
+ gg->GetCSharpFlagTable());
+ break;
+ }
+ Options& clOptions = *pOptions;
+
+ std::string flags;
+ const std::string& linkLanguage =
+ this->GeneratorTarget->GetLinkerLanguage(configName);
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error(
+ "CMake can not determine linker language for target: " + this->Name);
+ return false;
+ }
+
+ // Choose a language whose flags to use for ClCompile.
+ static const char* clLangs[] = { "CXX", "C", "Fortran" };
+ std::string langForClCompile;
+ if (this->ProjectType == csproj) {
+ langForClCompile = "CSharp";
+ } else if (cm::contains(clLangs, linkLanguage)) {
+ langForClCompile = linkLanguage;
+ } else {
+ std::set<std::string> languages;
+ this->GeneratorTarget->GetLanguages(languages, configName);
+ for (const char* l : clLangs) {
+ if (languages.count(l)) {
+ langForClCompile = l;
+ break;
+ }
+ }
+ }
+ this->LangForClCompile = langForClCompile;
+ if (!langForClCompile.empty()) {
+ this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+ langForClCompile, configName);
+ this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
+ langForClCompile, configName);
+ }
+
+ // Put the IPO enabled configurations into a set.
+ if (this->GeneratorTarget->IsIPOEnabled(linkLanguage, configName)) {
+ this->IPOEnabledConfigurations.insert(configName);
+ }
+
+ // Precompile Headers
+ std::string pchHeader =
+ this->GeneratorTarget->GetPchHeader(configName, linkLanguage);
+ if (this->MSTools && vcxproj == this->ProjectType && pchHeader.empty()) {
+ clOptions.AddFlag("PrecompiledHeader", "NotUsing");
+ } else if (this->MSTools && vcxproj == this->ProjectType &&
+ !pchHeader.empty()) {
+ clOptions.AddFlag("PrecompiledHeader", "Use");
+ clOptions.AddFlag("PrecompiledHeaderFile", pchHeader);
+ std::string pchFile =
+ this->GeneratorTarget->GetPchFile(configName, linkLanguage);
+ clOptions.AddFlag("PrecompiledHeaderOutputFile", pchFile);
+ }
+
+ // Get preprocessor definitions for this directory.
+ std::string defineFlags = this->Makefile->GetDefineFlags();
+ if (this->MSTools) {
+ if (this->ProjectType == vcxproj) {
+ clOptions.FixExceptionHandlingDefault();
+ if (this->GlobalGenerator->GetVersion() >=
+ cmGlobalVisualStudioGenerator::VS15) {
+ // Toolsets that come with VS 2017 may now enable UseFullPaths
+ // by default and there is no negative /FC option that projects
+ // can use to switch it back. Older toolsets disable this by
+ // default anyway so this will not hurt them. If the project
+ // is using an explicit /FC option then parsing flags will
+ // replace this setting with "true" below.
+ clOptions.AddFlag("UseFullPaths", "false");
+ }
+ clOptions.AddFlag("AssemblerListingLocation", "$(IntDir)");
+ }
+ }
+
+ // check for managed C++ assembly compiler flag. This overrides any
+ // /clr* compiler flags which may be defined in the flags variable(s).
+ if (this->ProjectType != csproj) {
+ // Warn if /clr was added manually. This should not be done
+ // anymore, because cmGeneratorTarget may not be aware that the
+ // target uses C++/CLI.
+ if (flags.find("/clr") != std::string::npos ||
+ defineFlags.find("/clr") != std::string::npos) {
+ if (configName == this->Configurations[0]) {
+ std::string message = "For the target \"" +
+ this->GeneratorTarget->GetName() +
+ "\" the /clr compiler flag was added manually. " +
+ "Set usage of C++/CLI by setting COMMON_LANGUAGE_RUNTIME "
+ "target property.";
+ this->Makefile->IssueMessage(MessageType::WARNING, message);
+ }
+ }
+ if (cmProp clr =
+ this->GeneratorTarget->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
+ std::string clrString = *clr;
+ if (!clrString.empty()) {
+ clrString = ":" + clrString;
+ }
+ flags += " /clr" + clrString;
+ }
+ }
+
+ clOptions.Parse(flags);
+ clOptions.Parse(defineFlags);
+ std::vector<std::string> targetDefines;
+ switch (this->ProjectType) {
+ case vcxproj:
+ if (!langForClCompile.empty()) {
+ this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName,
+ langForClCompile);
+ }
+ break;
+ case csproj:
+ this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName,
+ "CSharp");
+ cm::erase_if(targetDefines, [](std::string const& def) {
+ return def.find('=') != std::string::npos;
+ });
+ break;
+ }
+ clOptions.AddDefines(targetDefines);
+
+ if (this->ProjectType == csproj) {
+ clOptions.AppendFlag("DefineConstants", targetDefines);
+ }
+
+ // Get includes for this target
+ if (!this->LangForClCompile.empty()) {
+ clOptions.AddIncludes(
+ this->GetIncludes(configName, this->LangForClCompile));
+ }
+
+ if (this->MSTools) {
+ clOptions.SetVerboseMakefile(
+ 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);
+ if (const std::string* exportMacro =
+ this->GeneratorTarget->GetExportMacro()) {
+ clOptions.AddDefine(*exportMacro);
+ }
+
+ if (this->MSTools) {
+ // If we have the VS_WINRT_COMPONENT set then force Compile as WinRT
+ if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT")) {
+ clOptions.AddFlag("CompileAsWinRT", "true");
+ // For WinRT components, add the _WINRT_DLL define to produce a lib
+ if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ clOptions.AddDefine("_WINRT_DLL");
+ }
+ } else if (this->GlobalGenerator->TargetsWindowsStore() ||
+ this->GlobalGenerator->TargetsWindowsPhone() ||
+ this->Makefile->IsOn("CMAKE_VS_WINRT_BY_DEFAULT")) {
+ if (!clOptions.IsWinRt()) {
+ clOptions.AddFlag("CompileAsWinRT", "false");
+ }
+ }
+ if (const char* winRT = clOptions.GetFlag("CompileAsWinRT")) {
+ if (cmIsOn(winRT)) {
+ this->TargetCompileAsWinRT = true;
+ }
+ }
+ }
+
+ if (this->ProjectType != csproj && clOptions.IsManaged()) {
+ this->Managed = true;
+ std::string managedType = clOptions.GetFlag("CompileAsManaged");
+ if (managedType == "Safe" || managedType == "Pure") {
+ // force empty calling convention if safe clr is used
+ clOptions.AddFlag("CallingConvention", "");
+ }
+ // The default values of these flags are incompatible to
+ // managed assemblies. We have to force valid values if
+ // the target is a managed C++ target.
+ clOptions.AddFlag("ExceptionHandling", "Async");
+ clOptions.AddFlag("BasicRuntimeChecks", "Default");
+ }
+ if (this->ProjectType == csproj) {
+ // /nowin32manifest overrides /win32manifest: parameter
+ if (clOptions.HasFlag("NoWin32Manifest")) {
+ clOptions.RemoveFlag("ApplicationManifest");
+ }
+ }
+
+ if (const char* s = clOptions.GetFlag("SpectreMitigation")) {
+ this->SpectreMitigation[configName] = s;
+ clOptions.RemoveFlag("SpectreMitigation");
+ }
+
+ // Remove any target-wide -TC or -TP flag added by the project.
+ // Such flags are unnecessary and break our model of language selection.
+ if (langForClCompile == "C" || langForClCompile == "CXX") {
+ clOptions.RemoveFlag("CompileAs");
+ }
+
+ this->ClOptions[configName] = std::move(pOptions);
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteClOptions(
+ Elem& e1, std::string const& configName)
+{
+ Options& clOptions = *(this->ClOptions[configName]);
+ if (this->ProjectType == csproj) {
+ return;
+ }
+ Elem e2(e1, "ClCompile");
+ OptionsHelper oh(clOptions, e2);
+ oh.PrependInheritedString("AdditionalOptions");
+ oh.OutputAdditionalIncludeDirectories(this->LangForClCompile);
+ oh.OutputFlagMap();
+ oh.OutputPreprocessorDefinitions(this->LangForClCompile);
+
+ if (this->NsightTegra) {
+ if (cmProp processMax =
+ this->GeneratorTarget->GetProperty("ANDROID_PROCESS_MAX")) {
+ e2.Element("ProcessMax", *processMax);
+ }
+ }
+
+ if (this->Android) {
+ e2.Element("ObjectFileName", "$(IntDir)%(filename).o");
+ } else if (this->MSTools) {
+ cmsys::RegularExpression clangToolset("v[0-9]+_clang_.*");
+ const char* toolset = this->GlobalGenerator->GetPlatformToolset();
+ if (toolset && clangToolset.find(toolset)) {
+ e2.Element("ObjectFileName", "$(IntDir)%(filename).obj");
+ } else {
+ e2.Element("ObjectFileName", "$(IntDir)");
+ }
+
+ // If not in debug mode, write the DebugInformationFormat field
+ // without value so PDBs don't get generated uselessly. Each tag
+ // goes on its own line because Visual Studio corrects it this
+ // way when saving the project after CMake generates it.
+ if (!clOptions.IsDebug()) {
+ Elem e3(e2, "DebugInformationFormat");
+ e3.SetHasElements();
+ }
+
+ // Specify the compiler program database file if configured.
+ std::string pdb = this->GeneratorTarget->GetCompilePDBPath(configName);
+ if (!pdb.empty()) {
+ if (this->GlobalGenerator->IsCudaEnabled()) {
+ // CUDA does not quote paths with spaces correctly when forwarding
+ // this to the host compiler. Use a relative path to avoid spaces.
+ // FIXME: We can likely do this even when CUDA is not involved,
+ // but for now we will make a minimal change.
+ pdb = this->ConvertPath(pdb, true);
+ }
+ ConvertToWindowsSlash(pdb);
+ e2.Element("ProgramDataBaseFileName", pdb);
+ }
+
+ // add AdditionalUsingDirectories
+ if (this->AdditionalUsingDirectories.count(configName) > 0) {
+ std::string dirs;
+ for (auto u : this->AdditionalUsingDirectories[configName]) {
+ if (!dirs.empty()) {
+ dirs.append(";");
+ }
+ dirs.append(u);
+ }
+ e2.Element("AdditionalUsingDirectories", dirs);
+ }
+ }
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeRcOptions()
+{
+ for (std::string const& c : this->Configurations) {
+ if (!this->ComputeRcOptions(c)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeRcOptions(
+ std::string const& configName)
+{
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+ auto pOptions = cm::make_unique<Options>(
+ this->LocalGenerator, Options::ResourceCompiler, gg->GetRcFlagTable());
+ Options& rcOptions = *pOptions;
+
+ std::string CONFIG = cmSystemTools::UpperCase(configName);
+ std::string rcConfigFlagsVar = "CMAKE_RC_FLAGS_" + CONFIG;
+ std::string flags = this->Makefile->GetSafeDefinition("CMAKE_RC_FLAGS") +
+ " " + this->Makefile->GetSafeDefinition(rcConfigFlagsVar);
+
+ rcOptions.Parse(flags);
+
+ // For historical reasons, add the C preprocessor defines to RC.
+ Options& clOptions = *(this->ClOptions[configName]);
+ rcOptions.AddDefines(clOptions.GetDefines());
+
+ // Get includes for this target
+ rcOptions.AddIncludes(this->GetIncludes(configName, "RC"));
+
+ this->RcOptions[configName] = std::move(pOptions);
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteRCOptions(
+ Elem& e1, std::string const& configName)
+{
+ if (!this->MSTools) {
+ return;
+ }
+ Elem e2(e1, "ResourceCompile");
+
+ OptionsHelper rcOptions(*(this->RcOptions[configName]), e2);
+ rcOptions.OutputPreprocessorDefinitions("RC");
+ rcOptions.OutputAdditionalIncludeDirectories("RC");
+ rcOptions.PrependInheritedString("AdditionalOptions");
+ rcOptions.OutputFlagMap();
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeCudaOptions()
+{
+ if (!this->GlobalGenerator->IsCudaEnabled()) {
+ return true;
+ }
+ for (std::string const& c : this->Configurations) {
+ if (this->GeneratorTarget->IsLanguageUsed("CUDA", c) &&
+ !this->ComputeCudaOptions(c)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
+ std::string const& configName)
+{
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+ auto pOptions = cm::make_unique<Options>(
+ this->LocalGenerator, Options::CudaCompiler, gg->GetCudaFlagTable());
+ Options& cudaOptions = *pOptions;
+
+ // Get compile flags for CUDA in this directory.
+ std::string flags;
+ this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, "CUDA",
+ configName);
+ this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, "CUDA",
+ configName);
+
+ // Get preprocessor definitions for this directory.
+ std::string defineFlags = this->Makefile->GetDefineFlags();
+
+ cudaOptions.Parse(flags);
+ cudaOptions.Parse(defineFlags);
+ cudaOptions.ParseFinish();
+
+ // If we haven't explicitly enabled GPU debug information
+ // explicitly disable it
+ if (!cudaOptions.HasFlag("GPUDebugInfo")) {
+ cudaOptions.AddFlag("GPUDebugInfo", "false");
+ }
+
+ // The extension on object libraries the CUDA gives isn't
+ // consistent with how MSVC generates object libraries for C+, so set
+ // the default to not have any extension
+ cudaOptions.AddFlag("CompileOut", "$(IntDir)%(Filename).obj");
+
+ bool notPtx = true;
+ if (this->GeneratorTarget->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION")) {
+ cudaOptions.AddFlag("GenerateRelocatableDeviceCode", "true");
+ } else if (this->GeneratorTarget->GetPropertyAsBool(
+ "CUDA_PTX_COMPILATION")) {
+ cudaOptions.AddFlag("NvccCompilation", "ptx");
+ // We drop the %(Extension) component as CMake expects all PTX files
+ // to not have the source file extension at all
+ cudaOptions.AddFlag("CompileOut", "$(IntDir)%(Filename).ptx");
+ notPtx = false;
+ }
+
+ if (notPtx &&
+ cmSystemTools::VersionCompareGreaterEq(
+ "8.0", this->GlobalGenerator->GetPlatformToolsetCudaString())) {
+ // Explicitly state that we want this file to be treated as a
+ // CUDA file no matter what the file extensions is
+ // This is only needed for < CUDA 9
+ cudaOptions.AppendFlagString("AdditionalOptions", "-x cu");
+ }
+
+ // Specify the compiler program database file if configured.
+ std::string pdb = this->GeneratorTarget->GetCompilePDBPath(configName);
+ if (!pdb.empty()) {
+ // CUDA does not make the directory if it is non-standard.
+ std::string const pdbDir = cmSystemTools::GetFilenamePath(pdb);
+ cmSystemTools::MakeDirectory(pdbDir);
+ if (cmSystemTools::VersionCompareGreaterEq(
+ "9.2", this->GlobalGenerator->GetPlatformToolsetCudaString())) {
+ // CUDA does not have a field for this and does not honor the
+ // ProgramDataBaseFileName field in ClCompile. Work around this
+ // limitation by creating the directory and passing the flag ourselves.
+ pdb = this->ConvertPath(pdb, true);
+ ConvertToWindowsSlash(pdb);
+ std::string const clFd = "-Xcompiler=\"-Fd\\\"" + pdb + "\\\"\"";
+ cudaOptions.AppendFlagString("AdditionalOptions", clFd);
+ }
+ }
+
+ // CUDA automatically passes the proper '--machine' flag to nvcc
+ // for the current architecture, but does not reflect this default
+ // in the user-visible IDE settings. Set it explicitly.
+ if (this->Platform == "x64") {
+ cudaOptions.AddFlag("TargetMachinePlatform", "64");
+ }
+
+ // Convert the host compiler options to the toolset's abstractions
+ // using a secondary flag table.
+ cudaOptions.ClearTables();
+ cudaOptions.AddTable(gg->GetCudaHostFlagTable());
+ cudaOptions.Reparse("AdditionalCompilerOptions");
+
+ // `CUDA 8.0.targets` places AdditionalCompilerOptions before nvcc!
+ // Pass them through -Xcompiler in AdditionalOptions instead.
+ if (const char* acoPtr = cudaOptions.GetFlag("AdditionalCompilerOptions")) {
+ std::string aco = acoPtr;
+ cudaOptions.RemoveFlag("AdditionalCompilerOptions");
+ if (!aco.empty()) {
+ aco = this->LocalGenerator->EscapeForShell(aco, false);
+ cudaOptions.AppendFlagString("AdditionalOptions", "-Xcompiler=" + aco);
+ }
+ }
+
+ cudaOptions.FixCudaCodeGeneration();
+
+ std::vector<std::string> targetDefines;
+ this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName,
+ "CUDA");
+ cudaOptions.AddDefines(targetDefines);
+
+ // Add a definition for the configuration name.
+ std::string configDefine = cmStrCat("CMAKE_INTDIR=\"", configName, '"');
+ cudaOptions.AddDefine(configDefine);
+ if (const std::string* exportMacro =
+ this->GeneratorTarget->GetExportMacro()) {
+ cudaOptions.AddDefine(*exportMacro);
+ }
+
+ // Get includes for this target
+ cudaOptions.AddIncludes(this->GetIncludes(configName, "CUDA"));
+ cudaOptions.AddFlag("UseHostInclude", "false");
+
+ // Add runtime library selection flag.
+ std::string const& cudaRuntime =
+ this->GeneratorTarget->GetRuntimeLinkLibrary("CUDA", configName);
+ if (cudaRuntime == "STATIC") {
+ cudaOptions.AddFlag("CudaRuntime", "Static");
+ } else if (cudaRuntime == "SHARED") {
+ cudaOptions.AddFlag("CudaRuntime", "Shared");
+ } else if (cudaRuntime == "NONE") {
+ cudaOptions.AddFlag("CudaRuntime", "None");
+ }
+
+ this->CudaOptions[configName] = std::move(pOptions);
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteCudaOptions(
+ Elem& e1, std::string const& configName)
+{
+ if (!this->MSTools || !this->GlobalGenerator->IsCudaEnabled() ||
+ !this->GeneratorTarget->IsLanguageUsed("CUDA", configName)) {
+ return;
+ }
+ Elem e2(e1, "CudaCompile");
+
+ OptionsHelper cudaOptions(*(this->CudaOptions[configName]), e2);
+ cudaOptions.OutputAdditionalIncludeDirectories("CUDA");
+ cudaOptions.OutputPreprocessorDefinitions("CUDA");
+ cudaOptions.PrependInheritedString("AdditionalOptions");
+ cudaOptions.OutputFlagMap();
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions()
+{
+ if (!this->GlobalGenerator->IsCudaEnabled()) {
+ return true;
+ }
+ for (std::string const& c : this->Configurations) {
+ if (!this->ComputeCudaLinkOptions(c)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions(
+ std::string const& configName)
+{
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+ auto pOptions = cm::make_unique<Options>(
+ this->LocalGenerator, Options::CudaCompiler, gg->GetCudaFlagTable());
+ Options& cudaLinkOptions = *pOptions;
+
+ cmGeneratorTarget::DeviceLinkSetter setter(*this->GeneratorTarget);
+
+ // Determine if we need to do a device link
+ const bool doDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, configName);
+
+ cudaLinkOptions.AddFlag("PerformDeviceLink",
+ doDeviceLinking ? "true" : "false");
+
+ // Add extra flags for device linking
+ cudaLinkOptions.AppendFlagString(
+ "AdditionalOptions",
+ this->Makefile->GetSafeDefinition("_CMAKE_CUDA_EXTRA_FLAGS"));
+ cudaLinkOptions.AppendFlagString(
+ "AdditionalOptions",
+ this->Makefile->GetSafeDefinition("_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS"));
+
+ std::vector<std::string> linkOpts;
+ std::string linkFlags;
+ this->GeneratorTarget->GetLinkOptions(linkOpts, configName, "CUDA");
+ // LINK_OPTIONS are escaped.
+ this->LocalGenerator->AppendCompileOptions(linkFlags, linkOpts);
+ cudaLinkOptions.AppendFlagString("AdditionalOptions", linkFlags);
+
+ // For static libraries that have device linking enabled compute
+ // the libraries
+ if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY &&
+ doDeviceLinking) {
+ cmComputeLinkInformation* pcli =
+ this->GeneratorTarget->GetLinkInformation(configName);
+ if (!pcli) {
+ cmSystemTools::Error(
+ "CMake can not compute cmComputeLinkInformation for target: " +
+ this->Name);
+ return false;
+ }
+
+ // Would like to use:
+ // cmLinkLineDeviceComputer computer(this->LocalGenerator,
+ // this->LocalGenerator->GetStateSnapshot().GetDirectory());
+ // std::string computed_libs = computer.ComputeLinkLibraries(cli,
+ // std::string{}); but it outputs in "<libA> <libB>" format instead of
+ // "<libA>;<libB>"
+ // Note:
+ // Any modification of this algorithm should be reflected also in
+ // cmLinkLineDeviceComputer
+ cmComputeLinkInformation& cli = *pcli;
+ std::vector<std::string> libVec;
+ const std::string currentBinDir =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+ const auto& libs = cli.GetItems();
+ for (cmComputeLinkInformation::Item const& l : libs) {
+
+ if (l.Target) {
+ auto managedType = l.Target->GetManagedType(configName);
+ // Do not allow C# targets to be added to the LIB listing. LIB files
+ // are used for linking C++ dependencies. C# libraries do not have lib
+ // files. Instead, they compile down to C# reference libraries (DLL
+ // files). The
+ // `<ProjectReference>` elements added to the vcxproj are enough for
+ // the IDE to deduce the DLL file required by other C# projects that
+ // need its reference library.
+ if (managedType == cmGeneratorTarget::ManagedType::Managed) {
+ continue;
+ }
+ const auto type = l.Target->GetType();
+
+ bool skip = false;
+ switch (type) {
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ skip = true;
+ break;
+ case cmStateEnums::STATIC_LIBRARY:
+ skip = l.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS");
+ break;
+ default:
+ break;
+ }
+ if (skip) {
+ continue;
+ }
+ }
+
+ if (l.IsPath) {
+ std::string path = this->LocalGenerator->MaybeConvertToRelativePath(
+ currentBinDir, l.Value.Value);
+ ConvertToWindowsSlash(path);
+ if (!cmVS10IsTargetsFile(l.Value.Value)) {
+ libVec.push_back(path);
+ }
+ } else {
+ libVec.push_back(l.Value.Value);
+ }
+ }
+
+ cudaLinkOptions.AddFlag("AdditionalDependencies", libVec);
+ }
+
+ this->CudaLinkOptions[configName] = std::move(pOptions);
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteCudaLinkOptions(
+ Elem& e1, std::string const& configName)
+{
+ if (this->GeneratorTarget->GetType() > cmStateEnums::MODULE_LIBRARY) {
+ return;
+ }
+
+ if (!this->MSTools || !this->GlobalGenerator->IsCudaEnabled()) {
+ return;
+ }
+
+ Elem e2(e1, "CudaLink");
+ OptionsHelper cudaLinkOptions(*(this->CudaLinkOptions[configName]), e2);
+ cudaLinkOptions.OutputFlagMap();
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeMasmOptions()
+{
+ if (!this->GlobalGenerator->IsMasmEnabled()) {
+ return true;
+ }
+ for (std::string const& c : this->Configurations) {
+ if (!this->ComputeMasmOptions(c)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeMasmOptions(
+ std::string const& configName)
+{
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+ auto pOptions = cm::make_unique<Options>(
+ this->LocalGenerator, Options::MasmCompiler, gg->GetMasmFlagTable());
+ Options& masmOptions = *pOptions;
+
+ std::string flags;
+ this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+ "ASM_MASM", configName);
+
+ masmOptions.Parse(flags);
+
+ // Get includes for this target
+ masmOptions.AddIncludes(this->GetIncludes(configName, "ASM_MASM"));
+
+ this->MasmOptions[configName] = std::move(pOptions);
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteMasmOptions(
+ Elem& e1, std::string const& configName)
+{
+ if (!this->MSTools || !this->GlobalGenerator->IsMasmEnabled()) {
+ return;
+ }
+ Elem e2(e1, "MASM");
+
+ // Preprocessor definitions and includes are shared with clOptions.
+ OptionsHelper clOptions(*(this->ClOptions[configName]), e2);
+ clOptions.OutputPreprocessorDefinitions("ASM_MASM");
+
+ OptionsHelper masmOptions(*(this->MasmOptions[configName]), e2);
+ masmOptions.OutputAdditionalIncludeDirectories("ASM_MASM");
+ masmOptions.PrependInheritedString("AdditionalOptions");
+ masmOptions.OutputFlagMap();
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeNasmOptions()
+{
+ if (!this->GlobalGenerator->IsNasmEnabled()) {
+ return true;
+ }
+ for (std::string const& c : this->Configurations) {
+ if (!this->ComputeNasmOptions(c)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeNasmOptions(
+ std::string const& configName)
+{
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+ auto pOptions = cm::make_unique<Options>(
+ this->LocalGenerator, Options::NasmCompiler, gg->GetNasmFlagTable());
+ Options& nasmOptions = *pOptions;
+
+ std::string flags;
+ this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+ "ASM_NASM", configName);
+ flags += " -f";
+ flags += this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_OBJECT_FORMAT");
+ nasmOptions.Parse(flags);
+
+ // Get includes for this target
+ nasmOptions.AddIncludes(this->GetIncludes(configName, "ASM_NASM"));
+
+ this->NasmOptions[configName] = std::move(pOptions);
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteNasmOptions(
+ Elem& e1, std::string const& configName)
+{
+ if (!this->GlobalGenerator->IsNasmEnabled()) {
+ return;
+ }
+ Elem e2(e1, "NASM");
+
+ std::vector<std::string> includes =
+ this->GetIncludes(configName, "ASM_NASM");
+ OptionsHelper nasmOptions(*(this->NasmOptions[configName]), e2);
+ nasmOptions.OutputAdditionalIncludeDirectories("ASM_NASM");
+ nasmOptions.OutputFlagMap();
+ nasmOptions.PrependInheritedString("AdditionalOptions");
+ nasmOptions.OutputPreprocessorDefinitions("ASM_NASM");
+
+ // Preprocessor definitions and includes are shared with clOptions.
+ OptionsHelper clOptions(*(this->ClOptions[configName]), e2);
+ clOptions.OutputPreprocessorDefinitions("ASM_NASM");
+}
+
+void cmVisualStudio10TargetGenerator::WriteLibOptions(
+ Elem& e1, std::string const& config)
+{
+ if (this->GeneratorTarget->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ this->GeneratorTarget->GetType() != cmStateEnums::OBJECT_LIBRARY) {
+ return;
+ }
+
+ const std::string& linkLanguage =
+ this->GeneratorTarget->GetLinkClosure(config)->LinkerLanguage;
+
+ std::string libflags;
+ this->LocalGenerator->GetStaticLibraryFlags(libflags, config, linkLanguage,
+ this->GeneratorTarget);
+ if (!libflags.empty()) {
+ Elem e2(e1, "Lib");
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+ cmVS10GeneratorOptions libOptions(this->LocalGenerator,
+ cmVisualStudioGeneratorOptions::Linker,
+ gg->GetLibFlagTable(), this);
+ libOptions.Parse(libflags);
+ OptionsHelper oh(libOptions, e2);
+ oh.PrependInheritedString("AdditionalOptions");
+ oh.OutputFlagMap();
+ }
+
+ // We cannot generate metadata for static libraries. WindowsPhone
+ // and WindowsStore tools look at GenerateWindowsMetadata in the
+ // Link tool options even for static libraries.
+ if (this->GlobalGenerator->TargetsWindowsPhone() ||
+ this->GlobalGenerator->TargetsWindowsStore()) {
+ Elem e2(e1, "Link");
+ e2.Element("GenerateWindowsMetadata", "false");
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteManifestOptions(
+ Elem& e1, std::string const& config)
+{
+ if (this->GeneratorTarget->GetType() != cmStateEnums::EXECUTABLE &&
+ this->GeneratorTarget->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GeneratorTarget->GetType() != cmStateEnums::MODULE_LIBRARY) {
+ return;
+ }
+
+ std::vector<cmSourceFile const*> manifest_srcs;
+ this->GeneratorTarget->GetManifests(manifest_srcs, config);
+
+ cmProp dpiAware = this->GeneratorTarget->GetProperty("VS_DPI_AWARE");
+
+ if (!manifest_srcs.empty() || dpiAware) {
+ Elem e2(e1, "Manifest");
+ if (!manifest_srcs.empty()) {
+ std::ostringstream oss;
+ for (cmSourceFile const* mi : manifest_srcs) {
+ std::string m = this->ConvertPath(mi->GetFullPath(), false);
+ ConvertToWindowsSlash(m);
+ oss << m << ";";
+ }
+ e2.Element("AdditionalManifestFiles", oss.str());
+ }
+ if (dpiAware) {
+ if (*dpiAware == "PerMonitor") {
+ e2.Element("EnableDpiAwareness", "PerMonitorHighDPIAware");
+ } else if (cmIsOn(*dpiAware)) {
+ e2.Element("EnableDpiAwareness", "true");
+ } else if (cmIsOff(*dpiAware)) {
+ e2.Element("EnableDpiAwareness", "false");
+ } else {
+ cmSystemTools::Error("Bad parameter for VS_DPI_AWARE: " + *dpiAware);
+ }
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteAntBuildOptions(
+ Elem& e1, std::string const& configName)
+{
+ // Look through the sources for AndroidManifest.xml and use
+ // its location as the root source directory.
+ std::string rootDir = this->LocalGenerator->GetCurrentSourceDirectory();
+ {
+ for (cmGeneratorTarget::AllConfigSource const& source :
+ this->GeneratorTarget->GetAllConfigSources()) {
+ if (source.Kind == cmGeneratorTarget::SourceKindExtra &&
+ "androidmanifest.xml" ==
+ cmSystemTools::LowerCase(source.Source->GetLocation().GetName())) {
+ rootDir = source.Source->GetLocation().GetDirectory();
+ break;
+ }
+ }
+ }
+
+ // Tell MSBuild to launch Ant.
+ Elem e2(e1, "AntBuild");
+ {
+ std::string antBuildPath = rootDir;
+ ConvertToWindowsSlash(antBuildPath);
+ e2.Element("AntBuildPath", antBuildPath);
+ }
+
+ if (this->GeneratorTarget->GetPropertyAsBool("ANDROID_SKIP_ANT_STEP")) {
+ e2.Element("SkipAntStep", "true");
+ }
+
+ if (this->GeneratorTarget->GetPropertyAsBool("ANDROID_PROGUARD")) {
+ e2.Element("EnableProGuard", "true");
+ }
+
+ if (cmProp proGuardConfigLocation =
+ this->GeneratorTarget->GetProperty("ANDROID_PROGUARD_CONFIG_PATH")) {
+ e2.Element("ProGuardConfigLocation", *proGuardConfigLocation);
+ }
+
+ if (cmProp securePropertiesLocation =
+ this->GeneratorTarget->GetProperty("ANDROID_SECURE_PROPS_PATH")) {
+ e2.Element("SecurePropertiesLocation", *securePropertiesLocation);
+ }
+
+ if (cmProp nativeLibDirectoriesExpression =
+ this->GeneratorTarget->GetProperty("ANDROID_NATIVE_LIB_DIRECTORIES")) {
+ std::string nativeLibDirs = cmGeneratorExpression::Evaluate(
+ *nativeLibDirectoriesExpression, this->LocalGenerator, configName);
+ e2.Element("NativeLibDirectories", nativeLibDirs);
+ }
+
+ if (cmProp nativeLibDependenciesExpression =
+ this->GeneratorTarget->GetProperty(
+ "ANDROID_NATIVE_LIB_DEPENDENCIES")) {
+ std::string nativeLibDeps = cmGeneratorExpression::Evaluate(
+ *nativeLibDependenciesExpression, this->LocalGenerator, configName);
+ e2.Element("NativeLibDependencies", nativeLibDeps);
+ }
+
+ if (cmProp javaSourceDir =
+ this->GeneratorTarget->GetProperty("ANDROID_JAVA_SOURCE_DIR")) {
+ e2.Element("JavaSourceDir", *javaSourceDir);
+ }
+
+ if (cmProp jarDirectoriesExpression =
+ this->GeneratorTarget->GetProperty("ANDROID_JAR_DIRECTORIES")) {
+ std::string jarDirectories = cmGeneratorExpression::Evaluate(
+ *jarDirectoriesExpression, this->LocalGenerator, configName);
+ e2.Element("JarDirectories", jarDirectories);
+ }
+
+ if (cmProp jarDeps =
+ this->GeneratorTarget->GetProperty("ANDROID_JAR_DEPENDENCIES")) {
+ e2.Element("JarDependencies", *jarDeps);
+ }
+
+ if (cmProp assetsDirectories =
+ this->GeneratorTarget->GetProperty("ANDROID_ASSETS_DIRECTORIES")) {
+ e2.Element("AssetsDirectories", *assetsDirectories);
+ }
+
+ {
+ std::string manifest_xml = rootDir + "/AndroidManifest.xml";
+ ConvertToWindowsSlash(manifest_xml);
+ e2.Element("AndroidManifestLocation", manifest_xml);
+ }
+
+ if (cmProp antAdditionalOptions =
+ this->GeneratorTarget->GetProperty("ANDROID_ANT_ADDITIONAL_OPTIONS")) {
+ e2.Element("AdditionalOptions",
+ *antAdditionalOptions + " %(AdditionalOptions)");
+ }
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeLinkOptions()
+{
+ if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE ||
+ this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ for (std::string const& c : this->Configurations) {
+ if (!this->ComputeLinkOptions(c)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
+ std::string const& config)
+{
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+ auto pOptions = cm::make_unique<Options>(
+ this->LocalGenerator, Options::Linker, gg->GetLinkFlagTable(), this);
+ Options& linkOptions = *pOptions;
+
+ cmGeneratorTarget::LinkClosure const* linkClosure =
+ this->GeneratorTarget->GetLinkClosure(config);
+
+ const std::string& linkLanguage = linkClosure->LinkerLanguage;
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error(
+ "CMake can not determine linker language for target: " + this->Name);
+ return false;
+ }
+
+ std::string CONFIG = cmSystemTools::UpperCase(config);
+
+ const char* linkType = "SHARED";
+ if (this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
+ linkType = "MODULE";
+ }
+ if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
+ linkType = "EXE";
+ }
+ std::string flags;
+ std::string linkFlagVarBase = cmStrCat("CMAKE_", linkType, "_LINKER_FLAGS");
+ flags += " ";
+ flags += this->Makefile->GetRequiredDefinition(linkFlagVarBase);
+ std::string linkFlagVar = linkFlagVarBase + "_" + CONFIG;
+ flags += " ";
+ flags += this->Makefile->GetRequiredDefinition(linkFlagVar);
+ cmProp targetLinkFlags = this->GeneratorTarget->GetProperty("LINK_FLAGS");
+ if (targetLinkFlags) {
+ flags += " ";
+ flags += *targetLinkFlags;
+ }
+ std::string flagsProp = cmStrCat("LINK_FLAGS_", CONFIG);
+ if (cmProp flagsConfig = this->GeneratorTarget->GetProperty(flagsProp)) {
+ flags += " ";
+ flags += *flagsConfig;
+ }
+
+ std::vector<std::string> opts;
+ this->GeneratorTarget->GetLinkOptions(opts, config, linkLanguage);
+ // LINK_OPTIONS are escaped.
+ this->LocalGenerator->AppendCompileOptions(flags, opts);
+
+ cmComputeLinkInformation* pcli =
+ this->GeneratorTarget->GetLinkInformation(config);
+ if (!pcli) {
+ cmSystemTools::Error(
+ "CMake can not compute cmComputeLinkInformation for target: " +
+ this->Name);
+ return false;
+ }
+ cmComputeLinkInformation& cli = *pcli;
+
+ std::vector<std::string> libVec;
+ std::vector<std::string> vsTargetVec;
+ this->AddLibraries(cli, libVec, vsTargetVec, config);
+ std::string standardLibsVar =
+ cmStrCat("CMAKE_", linkLanguage, "_STANDARD_LIBRARIES");
+ std::string const& libs = this->Makefile->GetSafeDefinition(standardLibsVar);
+ cmSystemTools::ParseWindowsCommandLine(libs.c_str(), libVec);
+ linkOptions.AddFlag("AdditionalDependencies", libVec);
+
+ // Populate TargetsFileAndConfigsVec
+ for (std::string const& ti : vsTargetVec) {
+ this->AddTargetsFileAndConfigPair(ti, config);
+ }
+
+ std::vector<std::string> const& ldirs = cli.GetDirectories();
+ std::vector<std::string> linkDirs;
+ for (std::string const& d : ldirs) {
+ // first just full path
+ linkDirs.push_back(d);
+ // next path with configuration type Debug, Release, etc
+ linkDirs.push_back(d + "/$(Configuration)");
+ }
+ linkDirs.push_back("%(AdditionalLibraryDirectories)");
+ linkOptions.AddFlag("AdditionalLibraryDirectories", linkDirs);
+
+ cmGeneratorTarget::Names targetNames;
+ if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
+ targetNames = this->GeneratorTarget->GetExecutableNames(config);
+ } else {
+ targetNames = this->GeneratorTarget->GetLibraryNames(config);
+ }
+
+ if (this->MSTools) {
+ if (this->GeneratorTarget->IsWin32Executable(config)) {
+ if (this->GlobalGenerator->TargetsWindowsCE()) {
+ linkOptions.AddFlag("SubSystem", "WindowsCE");
+ if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
+ if (this->ClOptions[config]->UsingUnicode()) {
+ linkOptions.AddFlag("EntryPointSymbol", "wWinMainCRTStartup");
+ } else {
+ linkOptions.AddFlag("EntryPointSymbol", "WinMainCRTStartup");
+ }
+ }
+ } else {
+ linkOptions.AddFlag("SubSystem", "Windows");
+ }
+ } else {
+ if (this->GlobalGenerator->TargetsWindowsCE()) {
+ linkOptions.AddFlag("SubSystem", "WindowsCE");
+ if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
+ if (this->ClOptions[config]->UsingUnicode()) {
+ linkOptions.AddFlag("EntryPointSymbol", "mainWCRTStartup");
+ } else {
+ linkOptions.AddFlag("EntryPointSymbol", "mainACRTStartup");
+ }
+ }
+ } else {
+ linkOptions.AddFlag("SubSystem", "Console");
+ };
+ }
+
+ if (cmProp stackVal = this->Makefile->GetDefinition(
+ "CMAKE_" + linkLanguage + "_STACK_SIZE")) {
+ linkOptions.AddFlag("StackReserveSize", *stackVal);
+ }
+
+ linkOptions.AddFlag("GenerateDebugInformation", "false");
+
+ std::string pdb = cmStrCat(this->GeneratorTarget->GetPDBDirectory(config),
+ '/', targetNames.PDB);
+ if (!targetNames.ImportLibrary.empty()) {
+ std::string imLib =
+ cmStrCat(this->GeneratorTarget->GetDirectory(
+ config, cmStateEnums::ImportLibraryArtifact),
+ '/', targetNames.ImportLibrary);
+
+ linkOptions.AddFlag("ImportLibrary", imLib);
+ }
+ linkOptions.AddFlag("ProgramDataBaseFile", pdb);
+
+ // A Windows Runtime component uses internal .NET metadata,
+ // so does not have an import library.
+ if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT") &&
+ this->GeneratorTarget->GetType() != cmStateEnums::EXECUTABLE) {
+ linkOptions.AddFlag("GenerateWindowsMetadata", "true");
+ } else if (this->GlobalGenerator->TargetsWindowsPhone() ||
+ this->GlobalGenerator->TargetsWindowsStore()) {
+ // WindowsPhone and WindowsStore components are in an app container
+ // and produce WindowsMetadata. If we are not producing a WINRT
+ // component, then do not generate the metadata here.
+ linkOptions.AddFlag("GenerateWindowsMetadata", "false");
+ }
+
+ if (this->GlobalGenerator->TargetsWindowsPhone() &&
+ this->GlobalGenerator->GetSystemVersion() == "8.0") {
+ // WindowsPhone 8.0 does not have ole32.
+ linkOptions.AppendFlag("IgnoreSpecificDefaultLibraries", "ole32.lib");
+ }
+ } else if (this->NsightTegra) {
+ linkOptions.AddFlag("SoName", targetNames.SharedObject);
+ }
+
+ linkOptions.Parse(flags);
+ linkOptions.FixManifestUACFlags();
+
+ if (this->MSTools) {
+ cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
+ this->GeneratorTarget->GetModuleDefinitionInfo(config);
+ if (mdi && !mdi->DefFile.empty()) {
+ linkOptions.AddFlag("ModuleDefinitionFile", mdi->DefFile);
+ }
+ linkOptions.AppendFlag("IgnoreSpecificDefaultLibraries",
+ "%(IgnoreSpecificDefaultLibraries)");
+ }
+
+ // VS 2015 without all updates has a v140 toolset whose
+ // GenerateDebugInformation expects No/Debug instead of false/true.
+ if (gg->GetPlatformToolsetNeedsDebugEnum()) {
+ if (const char* debug = linkOptions.GetFlag("GenerateDebugInformation")) {
+ if (strcmp(debug, "false") == 0) {
+ linkOptions.AddFlag("GenerateDebugInformation", "No");
+ } else if (strcmp(debug, "true") == 0) {
+ linkOptions.AddFlag("GenerateDebugInformation", "Debug");
+ }
+ }
+ }
+
+ // Managed code cannot be linked with /DEBUG:FASTLINK
+ if (this->Managed) {
+ if (const char* debug = linkOptions.GetFlag("GenerateDebugInformation")) {
+ if (strcmp(debug, "DebugFastLink") == 0) {
+ linkOptions.AddFlag("GenerateDebugInformation", "Debug");
+ }
+ }
+ }
+
+ this->LinkOptions[config] = std::move(pOptions);
+ return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeLibOptions()
+{
+ if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ for (std::string const& c : this->Configurations) {
+ if (!this->ComputeLibOptions(c)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeLibOptions(
+ std::string const& config)
+{
+ cmComputeLinkInformation* pcli =
+ this->GeneratorTarget->GetLinkInformation(config);
+ if (!pcli) {
+ cmSystemTools::Error(
+ "CMake can not compute cmComputeLinkInformation for target: " +
+ this->Name);
+ return false;
+ }
+
+ cmComputeLinkInformation& cli = *pcli;
+ using ItemVector = cmComputeLinkInformation::ItemVector;
+ const ItemVector& libs = cli.GetItems();
+ std::string currentBinDir =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+ for (cmComputeLinkInformation::Item const& l : libs) {
+ if (l.IsPath && cmVS10IsTargetsFile(l.Value.Value)) {
+ std::string path = this->LocalGenerator->MaybeConvertToRelativePath(
+ currentBinDir, l.Value.Value);
+ ConvertToWindowsSlash(path);
+ this->AddTargetsFileAndConfigPair(path, config);
+ }
+ }
+
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteLinkOptions(
+ Elem& e1, std::string const& config)
+{
+ if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ this->GeneratorTarget->GetType() > cmStateEnums::MODULE_LIBRARY) {
+ return;
+ }
+ if (this->ProjectType == csproj) {
+ return;
+ }
+
+ {
+ Elem e2(e1, "Link");
+ OptionsHelper linkOptions(*(this->LinkOptions[config]), e2);
+ linkOptions.PrependInheritedString("AdditionalOptions");
+ linkOptions.OutputFlagMap();
+ }
+
+ if (!this->GlobalGenerator->NeedLinkLibraryDependencies(
+ this->GeneratorTarget)) {
+ Elem e2(e1, "ProjectReference");
+ e2.Element("LinkLibraryDependencies", "false");
+ }
+}
+
+void cmVisualStudio10TargetGenerator::AddLibraries(
+ const cmComputeLinkInformation& cli, std::vector<std::string>& libVec,
+ std::vector<std::string>& vsTargetVec, const std::string& config)
+{
+ using ItemVector = cmComputeLinkInformation::ItemVector;
+ ItemVector const& libs = cli.GetItems();
+ std::string currentBinDir =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+ for (cmComputeLinkInformation::Item const& l : libs) {
+ if (l.Target) {
+ auto managedType = l.Target->GetManagedType(config);
+ if (managedType != cmGeneratorTarget::ManagedType::Native &&
+ this->GeneratorTarget->GetManagedType(config) !=
+ cmGeneratorTarget::ManagedType::Native &&
+ l.Target->IsImported() &&
+ l.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+ auto location = l.Target->GetFullPath(config);
+ if (!location.empty()) {
+ ConvertToWindowsSlash(location);
+ switch (this->ProjectType) {
+ case csproj:
+ // If the target we want to "link" to is an imported managed
+ // target and this is a C# project, we add a hint reference. This
+ // reference is written to project file in
+ // WriteDotNetReferences().
+ this->DotNetHintReferences[config].push_back(
+ DotNetHintReference(l.Target->GetName(), location));
+ break;
+ case vcxproj:
+ // Add path of assembly to list of using-directories, so the
+ // managed assembly can be used by '#using <assembly.dll>' in
+ // code.
+ this->AdditionalUsingDirectories[config].insert(
+ cmSystemTools::GetFilenamePath(location));
+ break;
+ }
+ }
+ }
+ // Do not allow C# targets to be added to the LIB listing. LIB files are
+ // used for linking C++ dependencies. C# libraries do not have lib files.
+ // Instead, they compile down to C# reference libraries (DLL files). The
+ // `<ProjectReference>` elements added to the vcxproj are enough for the
+ // IDE to deduce the DLL file required by other C# projects that need its
+ // reference library.
+ if (managedType == cmGeneratorTarget::ManagedType::Managed) {
+ continue;
+ }
+ }
+
+ if (l.IsPath) {
+ std::string path = this->LocalGenerator->MaybeConvertToRelativePath(
+ currentBinDir, l.Value.Value);
+ ConvertToWindowsSlash(path);
+ if (cmVS10IsTargetsFile(l.Value.Value)) {
+ vsTargetVec.push_back(path);
+ } else {
+ libVec.push_back(path);
+ }
+ } else if (!l.Target ||
+ l.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+ libVec.push_back(l.Value.Value);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::AddTargetsFileAndConfigPair(
+ std::string const& targetsFile, std::string const& config)
+{
+ for (TargetsFileAndConfigs& i : this->TargetsFileAndConfigsVec) {
+ if (cmSystemTools::ComparePath(targetsFile, i.File)) {
+ if (!cm::contains(i.Configs, config)) {
+ i.Configs.push_back(config);
+ }
+ return;
+ }
+ }
+ TargetsFileAndConfigs entry;
+ entry.File = targetsFile;
+ entry.Configs.push_back(config);
+ this->TargetsFileAndConfigsVec.push_back(entry);
+}
+
+void cmVisualStudio10TargetGenerator::WriteMidlOptions(
+ Elem& e1, std::string const& configName)
+{
+ if (!this->MSTools) {
+ return;
+ }
+ if (this->ProjectType == csproj) {
+ return;
+ }
+
+ // This processes *any* of the .idl files specified in the project's file
+ // list (and passed as the item metadata %(Filename) expressing the rule
+ // input filename) into output files at the per-config *build* dir
+ // ($(IntDir)) each.
+ //
+ // IOW, this MIDL section is intended to provide a fully generic syntax
+ // content suitable for most cases (read: if you get errors, then it's quite
+ // probable that the error is on your side of the .idl setup).
+ //
+ // Also, note that the marked-as-generated _i.c file in the Visual Studio
+ // generator case needs to be referred to as $(IntDir)\foo_i.c at the
+ // project's file list, otherwise the compiler-side processing won't pick it
+ // up (for non-directory form, it ends up looking in project binary dir
+ // only). Perhaps there's something to be done to make this more automatic
+ // on the CMake side?
+ std::vector<std::string> const includes =
+ this->GetIncludes(configName, "MIDL");
+ std::ostringstream oss;
+ for (std::string const& i : includes) {
+ oss << i << ";";
+ }
+ oss << "%(AdditionalIncludeDirectories)";
+
+ Elem e2(e1, "Midl");
+ e2.Element("AdditionalIncludeDirectories", oss.str());
+ e2.Element("OutputDirectory", "$(ProjectDir)/$(IntDir)");
+ e2.Element("HeaderFileName", "%(Filename).h");
+ e2.Element("TypeLibraryName", "%(Filename).tlb");
+ e2.Element("InterfaceIdentifierFileName", "%(Filename)_i.c");
+ e2.Element("ProxyFileName", "%(Filename)_p.c");
+}
+
+void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups(Elem& e0)
+{
+ if (this->ProjectType == csproj) {
+ return;
+ }
+ for (const std::string& c : this->Configurations) {
+ Elem e1(e0, "ItemDefinitionGroup");
+ e1.Attribute("Condition", this->CalcCondition(c));
+
+ // output cl compile flags <ClCompile></ClCompile>
+ if (this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
+ this->WriteClOptions(e1, c);
+ // output rc compile flags <ResourceCompile></ResourceCompile>
+ this->WriteRCOptions(e1, c);
+ this->WriteCudaOptions(e1, c);
+ this->WriteMasmOptions(e1, c);
+ this->WriteNasmOptions(e1, c);
+ }
+ // output midl flags <Midl></Midl>
+ this->WriteMidlOptions(e1, c);
+ // write events
+ if (this->ProjectType != csproj) {
+ this->WriteEvents(e1, c);
+ }
+ // output link flags <Link></Link>
+ this->WriteLinkOptions(e1, c);
+ this->WriteCudaLinkOptions(e1, c);
+ // output lib flags <Lib></Lib>
+ this->WriteLibOptions(e1, c);
+ // output manifest flags <Manifest></Manifest>
+ this->WriteManifestOptions(e1, c);
+ if (this->NsightTegra &&
+ this->GeneratorTarget->Target->IsAndroidGuiExecutable()) {
+ this->WriteAntBuildOptions(e1, c);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteEvents(
+ Elem& e1, std::string const& configName)
+{
+ bool addedPrelink = false;
+ cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
+ this->GeneratorTarget->GetModuleDefinitionInfo(configName);
+ if (mdi && mdi->DefFileGenerated) {
+ addedPrelink = true;
+ std::vector<cmCustomCommand> commands =
+ this->GeneratorTarget->GetPreLinkCommands();
+ this->GlobalGenerator->AddSymbolExportCommand(this->GeneratorTarget,
+ commands, configName);
+ this->WriteEvent(e1, "PreLinkEvent", commands, configName);
+ }
+ if (!addedPrelink) {
+ this->WriteEvent(e1, "PreLinkEvent",
+ this->GeneratorTarget->GetPreLinkCommands(), configName);
+ }
+ this->WriteEvent(e1, "PreBuildEvent",
+ this->GeneratorTarget->GetPreBuildCommands(), configName);
+ this->WriteEvent(e1, "PostBuildEvent",
+ this->GeneratorTarget->GetPostBuildCommands(), configName);
+}
+
+void cmVisualStudio10TargetGenerator::WriteEvent(
+ Elem& e1, const std::string& name,
+ std::vector<cmCustomCommand> const& commands, std::string const& configName)
+{
+ if (commands.empty()) {
+ return;
+ }
+ cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
+ std::string script;
+ const char* pre = "";
+ std::string comment;
+ bool stdPipesUTF8 = false;
+ for (cmCustomCommand const& cc : commands) {
+ cmCustomCommandGenerator ccg(cc, configName, lg);
+ if (!ccg.HasOnlyEmptyCommandLines()) {
+ comment += pre;
+ comment += lg->ConstructComment(ccg);
+ script += pre;
+ pre = "\n";
+ script += lg->ConstructScript(ccg);
+
+ stdPipesUTF8 = stdPipesUTF8 || cc.GetStdPipesUTF8();
+ }
+ }
+ comment = cmVS10EscapeComment(comment);
+ if (this->ProjectType != csproj) {
+ Elem e2(e1, name);
+ if (stdPipesUTF8) {
+ this->WriteStdOutEncodingUtf8(e2);
+ }
+ e2.Element("Message", comment);
+ e2.Element("Command", script);
+ } else {
+ std::string strippedComment = comment;
+ strippedComment.erase(
+ std::remove(strippedComment.begin(), strippedComment.end(), '\t'),
+ strippedComment.end());
+ std::ostringstream oss;
+ if (!comment.empty() && !strippedComment.empty()) {
+ oss << "echo " << comment << "\n";
+ }
+ oss << script << "\n";
+ e1.Element(name, oss.str());
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteProjectReferences(Elem& e0)
+{
+ cmGlobalGenerator::TargetDependSet const& unordered =
+ this->GlobalGenerator->GetTargetDirectDepends(this->GeneratorTarget);
+ using OrderedTargetDependSet =
+ cmGlobalVisualStudioGenerator::OrderedTargetDependSet;
+ OrderedTargetDependSet depends(unordered, CMAKE_CHECK_BUILD_SYSTEM_TARGET);
+ Elem e1(e0, "ItemGroup");
+ e1.SetHasElements();
+ for (cmGeneratorTarget const* dt : depends) {
+ if (!dt->IsInBuildSystem()) {
+ continue;
+ }
+ // skip fortran targets as they can not be processed by MSBuild
+ // the only reference will be in the .sln file
+ if (this->GlobalGenerator->TargetIsFortranOnly(dt)) {
+ continue;
+ }
+ cmLocalGenerator* lg = dt->GetLocalGenerator();
+ std::string name = dt->GetName();
+ std::string path;
+ if (cmProp p = dt->GetProperty("EXTERNAL_MSPROJECT")) {
+ path = *p;
+ } else {
+ path = cmStrCat(lg->GetCurrentBinaryDirectory(), '/', dt->GetName(),
+ computeProjectFileExtension(dt));
+ }
+ ConvertToWindowsSlash(path);
+ Elem e2(e1, "ProjectReference");
+ e2.Attribute("Include", path);
+ e2.Element("Project", "{" + this->GlobalGenerator->GetGUID(name) + "}");
+ e2.Element("Name", name);
+ this->WriteDotNetReferenceCustomTags(e2, name);
+ if (dt->IsCSharpOnly() || cmHasLiteralSuffix(path, "csproj")) {
+ e2.Element("SkipGetTargetFrameworkProperties", "true");
+ }
+
+ // Don't reference targets that don't produce any output.
+ if (this->Configurations.empty() ||
+ dt->GetManagedType(this->Configurations[0]) ==
+ cmGeneratorTarget::ManagedType::Undefined) {
+ e2.Element("ReferenceOutputAssembly", "false");
+ e2.Element("CopyToOutputDirectory", "Never");
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WritePlatformExtensions(Elem& e1)
+{
+ // This only applies to Windows 10 apps
+ if (this->GlobalGenerator->TargetsWindowsStore() &&
+ cmHasLiteralPrefix(this->GlobalGenerator->GetSystemVersion(), "10.0")) {
+ cmProp desktopExtensionsVersion =
+ this->GeneratorTarget->GetProperty("VS_DESKTOP_EXTENSIONS_VERSION");
+ if (desktopExtensionsVersion) {
+ this->WriteSinglePlatformExtension(e1, "WindowsDesktop",
+ *desktopExtensionsVersion);
+ }
+ cmProp mobileExtensionsVersion =
+ this->GeneratorTarget->GetProperty("VS_MOBILE_EXTENSIONS_VERSION");
+ if (mobileExtensionsVersion) {
+ this->WriteSinglePlatformExtension(e1, "WindowsMobile",
+ *mobileExtensionsVersion);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteSinglePlatformExtension(
+ Elem& e1, std::string const& extension, std::string const& version)
+{
+ const std::string s = "$([Microsoft.Build.Utilities.ToolLocationHelper]"
+ "::GetPlatformExtensionSDKLocation(`" +
+ extension + ", Version=" + version +
+ "`, $(TargetPlatformIdentifier), $(TargetPlatformVersion), null, "
+ "$(ExtensionSDKDirectoryRoot), null))"
+ "\\DesignTime\\CommonConfiguration\\Neutral\\" +
+ extension + ".props";
+
+ Elem e2(e1, "Import");
+ e2.Attribute("Project", s);
+ e2.Attribute("Condition", "exists('" + s + "')");
+}
+
+void cmVisualStudio10TargetGenerator::WriteSDKReferences(Elem& e0)
+{
+ std::vector<std::string> sdkReferences;
+ std::unique_ptr<Elem> spe1;
+ if (cmProp vsSDKReferences =
+ this->GeneratorTarget->GetProperty("VS_SDK_REFERENCES")) {
+ cmExpandList(*vsSDKReferences, sdkReferences);
+ spe1 = cm::make_unique<Elem>(e0, "ItemGroup");
+ for (std::string const& ri : sdkReferences) {
+ Elem(*spe1, "SDKReference").Attribute("Include", ri);
+ }
+ }
+
+ // This only applies to Windows 10 apps
+ if (this->GlobalGenerator->TargetsWindowsStore() &&
+ cmHasLiteralPrefix(this->GlobalGenerator->GetSystemVersion(), "10.0")) {
+ cmProp desktopExtensionsVersion =
+ this->GeneratorTarget->GetProperty("VS_DESKTOP_EXTENSIONS_VERSION");
+ cmProp mobileExtensionsVersion =
+ this->GeneratorTarget->GetProperty("VS_MOBILE_EXTENSIONS_VERSION");
+ cmProp iotExtensionsVersion =
+ this->GeneratorTarget->GetProperty("VS_IOT_EXTENSIONS_VERSION");
+
+ if (desktopExtensionsVersion || mobileExtensionsVersion ||
+ iotExtensionsVersion) {
+ if (!spe1) {
+ spe1 = cm::make_unique<Elem>(e0, "ItemGroup");
+ }
+ if (desktopExtensionsVersion) {
+ this->WriteSingleSDKReference(*spe1, "WindowsDesktop",
+ *desktopExtensionsVersion);
+ }
+ if (mobileExtensionsVersion) {
+ this->WriteSingleSDKReference(*spe1, "WindowsMobile",
+ *mobileExtensionsVersion);
+ }
+ if (iotExtensionsVersion) {
+ this->WriteSingleSDKReference(*spe1, "WindowsIoT",
+ *iotExtensionsVersion);
+ }
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteSingleSDKReference(
+ Elem& e1, std::string const& extension, std::string const& version)
+{
+ Elem(e1, "SDKReference")
+ .Attribute("Include", extension + ", Version=" + version);
+}
+
+void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile(
+ Elem& e0)
+{
+ if ((this->GlobalGenerator->TargetsWindowsStore() ||
+ this->GlobalGenerator->TargetsWindowsPhone()) &&
+ (cmStateEnums::EXECUTABLE == this->GeneratorTarget->GetType())) {
+ std::string pfxFile;
+ for (cmGeneratorTarget::AllConfigSource const& source :
+ this->GeneratorTarget->GetAllConfigSources()) {
+ if (source.Kind == cmGeneratorTarget::SourceKindCertificate) {
+ pfxFile = this->ConvertPath(source.Source->GetFullPath(), false);
+ ConvertToWindowsSlash(pfxFile);
+ break;
+ }
+ }
+
+ if (this->IsMissingFiles &&
+ !(this->GlobalGenerator->TargetsWindowsPhone() &&
+ this->GlobalGenerator->GetSystemVersion() == "8.0")) {
+ // Move the manifest to a project directory to avoid clashes
+ std::string artifactDir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ ConvertToWindowsSlash(artifactDir);
+ Elem e1(e0, "PropertyGroup");
+ e1.Element("AppxPackageArtifactsDir", artifactDir + "\\");
+ std::string resourcePriFile =
+ this->DefaultArtifactDir + "/resources.pri";
+ ConvertToWindowsSlash(resourcePriFile);
+ e1.Element("ProjectPriFullPath", resourcePriFile);
+
+ // If we are missing files and we don't have a certificate and
+ // aren't targeting WP8.0, add a default certificate
+ if (pfxFile.empty()) {
+ std::string templateFolder =
+ cmSystemTools::GetCMakeRoot() + "/Templates/Windows";
+ pfxFile = this->DefaultArtifactDir + "/Windows_TemporaryKey.pfx";
+ cmSystemTools::CopyAFile(templateFolder + "/Windows_TemporaryKey.pfx",
+ pfxFile, false);
+ ConvertToWindowsSlash(pfxFile);
+ this->AddedFiles.push_back(pfxFile);
+ this->AddedDefaultCertificate = true;
+ }
+
+ e1.Element("PackageCertificateKeyFile", pfxFile);
+ std::string thumb = cmSystemTools::ComputeCertificateThumbprint(pfxFile);
+ if (!thumb.empty()) {
+ e1.Element("PackageCertificateThumbprint", thumb);
+ }
+ } else if (!pfxFile.empty()) {
+ Elem e1(e0, "PropertyGroup");
+ e1.Element("PackageCertificateKeyFile", pfxFile);
+ std::string thumb = cmSystemTools::ComputeCertificateThumbprint(pfxFile);
+ if (!thumb.empty()) {
+ e1.Element("PackageCertificateThumbprint", thumb);
+ }
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::ClassifyAllConfigSources()
+{
+ for (cmGeneratorTarget::AllConfigSource const& source :
+ this->GeneratorTarget->GetAllConfigSources()) {
+ this->ClassifyAllConfigSource(source);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::ClassifyAllConfigSource(
+ cmGeneratorTarget::AllConfigSource const& acs)
+{
+ switch (acs.Kind) {
+ case cmGeneratorTarget::SourceKindResx: {
+ // Build and save the name of the corresponding .h file
+ // This relationship will be used later when building the project files.
+ // Both names would have been auto generated from Visual Studio
+ // where the user supplied the file name and Visual Studio
+ // appended the suffix.
+ std::string resx = acs.Source->ResolveFullPath();
+ std::string hFileName = resx.substr(0, resx.find_last_of('.')) + ".h";
+ this->ExpectedResxHeaders.insert(hFileName);
+ } break;
+ case cmGeneratorTarget::SourceKindXaml: {
+ // Build and save the name of the corresponding .h and .cpp file
+ // This relationship will be used later when building the project files.
+ // Both names would have been auto generated from Visual Studio
+ // where the user supplied the file name and Visual Studio
+ // appended the suffix.
+ std::string xaml = acs.Source->ResolveFullPath();
+ std::string hFileName = xaml + ".h";
+ std::string cppFileName = xaml + ".cpp";
+ this->ExpectedXamlHeaders.insert(hFileName);
+ this->ExpectedXamlSources.insert(cppFileName);
+ } break;
+ default:
+ break;
+ }
+}
+
+bool cmVisualStudio10TargetGenerator::IsResxHeader(
+ const std::string& headerFile)
+{
+ return this->ExpectedResxHeaders.count(headerFile) > 0;
+}
+
+bool cmVisualStudio10TargetGenerator::IsXamlHeader(
+ const std::string& headerFile)
+{
+ return this->ExpectedXamlHeaders.count(headerFile) > 0;
+}
+
+bool cmVisualStudio10TargetGenerator::IsXamlSource(
+ const std::string& sourceFile)
+{
+ return this->ExpectedXamlSources.count(sourceFile) > 0;
+}
+
+void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings(Elem& e1)
+{
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+ bool isAppContainer = false;
+ bool const isWindowsPhone = this->GlobalGenerator->TargetsWindowsPhone();
+ bool const isWindowsStore = this->GlobalGenerator->TargetsWindowsStore();
+ bool const isAndroid = this->GlobalGenerator->TargetsAndroid();
+ std::string const& rev = this->GlobalGenerator->GetApplicationTypeRevision();
+ if (isWindowsPhone || isWindowsStore) {
+ e1.Element("ApplicationType",
+ (isWindowsPhone ? "Windows Phone" : "Windows Store"));
+ e1.Element("DefaultLanguage", "en-US");
+ if (rev == "10.0") {
+ e1.Element("ApplicationTypeRevision", rev);
+ // Visual Studio 14.0 is necessary for building 10.0 apps
+ e1.Element("MinimumVisualStudioVersion", "14.0");
+
+ if (this->GeneratorTarget->GetType() < cmStateEnums::UTILITY) {
+ isAppContainer = true;
+ }
+ } else if (rev == "8.1") {
+ e1.Element("ApplicationTypeRevision", rev);
+ // Visual Studio 12.0 is necessary for building 8.1 apps
+ e1.Element("MinimumVisualStudioVersion", "12.0");
+
+ if (this->GeneratorTarget->GetType() < cmStateEnums::UTILITY) {
+ isAppContainer = true;
+ }
+ } else if (rev == "8.0") {
+ e1.Element("ApplicationTypeRevision", rev);
+ // Visual Studio 11.0 is necessary for building 8.0 apps
+ e1.Element("MinimumVisualStudioVersion", "11.0");
+
+ if (isWindowsStore &&
+ this->GeneratorTarget->GetType() < cmStateEnums::UTILITY) {
+ isAppContainer = true;
+ } else if (isWindowsPhone &&
+ this->GeneratorTarget->GetType() ==
+ cmStateEnums::EXECUTABLE) {
+ e1.Element("XapOutputs", "true");
+ e1.Element("XapFilename",
+ this->Name + "_$(Configuration)_$(Platform).xap");
+ }
+ }
+ } else if (isAndroid) {
+ e1.Element("ApplicationType", "Android");
+ e1.Element("ApplicationTypeRevision",
+ gg->GetAndroidApplicationTypeRevision());
+ }
+ if (isAppContainer) {
+ e1.Element("AppContainerApplication", "true");
+ } else if (!isAndroid) {
+ if (this->Platform == "ARM64") {
+ e1.Element("WindowsSDKDesktopARM64Support", "true");
+ } else if (this->Platform == "ARM") {
+ e1.Element("WindowsSDKDesktopARMSupport", "true");
+ }
+ }
+ std::string const& targetPlatformVersion =
+ gg->GetWindowsTargetPlatformVersion();
+ if (!targetPlatformVersion.empty()) {
+ e1.Element("WindowsTargetPlatformVersion", targetPlatformVersion);
+ }
+ cmProp targetPlatformMinVersion = this->GeneratorTarget->GetProperty(
+ "VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION");
+ if (targetPlatformMinVersion) {
+ e1.Element("WindowsTargetPlatformMinVersion", *targetPlatformMinVersion);
+ } else if (isWindowsStore && rev == "10.0") {
+ // If the min version is not set, then use the TargetPlatformVersion
+ if (!targetPlatformVersion.empty()) {
+ e1.Element("WindowsTargetPlatformMinVersion", targetPlatformVersion);
+ }
+ }
+
+ // Added IoT Startup Task support
+ if (this->GeneratorTarget->GetPropertyAsBool("VS_IOT_STARTUP_TASK")) {
+ e1.Element("ContainsStartupTask", "true");
+ }
+}
+
+void cmVisualStudio10TargetGenerator::VerifyNecessaryFiles()
+{
+ // For Windows and Windows Phone executables, we will assume that if a
+ // manifest is not present that we need to add all the necessary files
+ if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
+ std::vector<cmGeneratorTarget::AllConfigSource> manifestSources =
+ this->GeneratorTarget->GetAllConfigSources(
+ cmGeneratorTarget::SourceKindAppManifest);
+ std::string const& v = this->GlobalGenerator->GetSystemVersion();
+ if (this->GlobalGenerator->TargetsWindowsPhone()) {
+ if (v == "8.0") {
+ // Look through the sources for WMAppManifest.xml
+ bool foundManifest = false;
+ for (cmGeneratorTarget::AllConfigSource const& source :
+ this->GeneratorTarget->GetAllConfigSources()) {
+ if (source.Kind == cmGeneratorTarget::SourceKindExtra &&
+ "wmappmanifest.xml" ==
+ cmSystemTools::LowerCase(
+ source.Source->GetLocation().GetName())) {
+ foundManifest = true;
+ break;
+ }
+ }
+ if (!foundManifest) {
+ this->IsMissingFiles = true;
+ }
+ } else if (v == "8.1") {
+ if (manifestSources.empty()) {
+ this->IsMissingFiles = true;
+ }
+ }
+ } else if (this->GlobalGenerator->TargetsWindowsStore()) {
+ if (manifestSources.empty()) {
+ if (v == "8.0") {
+ this->IsMissingFiles = true;
+ } else if (v == "8.1" || cmHasLiteralPrefix(v, "10.0")) {
+ this->IsMissingFiles = true;
+ }
+ }
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteMissingFiles(Elem& e1)
+{
+ std::string const& v = this->GlobalGenerator->GetSystemVersion();
+ if (this->GlobalGenerator->TargetsWindowsPhone()) {
+ if (v == "8.0") {
+ this->WriteMissingFilesWP80(e1);
+ } else if (v == "8.1") {
+ this->WriteMissingFilesWP81(e1);
+ }
+ } else if (this->GlobalGenerator->TargetsWindowsStore()) {
+ if (v == "8.0") {
+ this->WriteMissingFilesWS80(e1);
+ } else if (v == "8.1") {
+ this->WriteMissingFilesWS81(e1);
+ } else if (cmHasLiteralPrefix(v, "10.0")) {
+ this->WriteMissingFilesWS10_0(e1);
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteMissingFilesWP80(Elem& e1)
+{
+ std::string templateFolder =
+ cmSystemTools::GetCMakeRoot() + "/Templates/Windows";
+
+ // For WP80, the manifest needs to be in the same folder as the project
+ // this can cause an overwrite problem if projects aren't organized in
+ // folders
+ std::string manifestFile =
+ this->LocalGenerator->GetCurrentBinaryDirectory() + "/WMAppManifest.xml";
+ std::string artifactDir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ ConvertToWindowsSlash(artifactDir);
+ std::string artifactDirXML = cmVS10EscapeXML(artifactDir);
+ std::string targetNameXML =
+ cmVS10EscapeXML(this->GeneratorTarget->GetName());
+
+ cmGeneratedFileStream fout(manifestFile);
+ fout.SetCopyIfDifferent(true);
+
+ /* clang-format off */
+ fout <<
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<Deployment"
+ " xmlns=\"http://schemas.microsoft.com/windowsphone/2012/deployment\""
+ " AppPlatformVersion=\"8.0\">\n"
+ "\t<DefaultLanguage xmlns=\"\" code=\"en-US\"/>\n"
+ "\t<App xmlns=\"\" ProductID=\"{" << this->GUID << "}\""
+ " Title=\"CMake Test Program\" RuntimeType=\"Modern Native\""
+ " Version=\"1.0.0.0\" Genre=\"apps.normal\" Author=\"CMake\""
+ " Description=\"Default CMake App\" Publisher=\"CMake\""
+ " PublisherID=\"{" << this->GUID << "}\">\n"
+ "\t\t<IconPath IsRelative=\"true\" IsResource=\"false\">"
+ << artifactDirXML << "\\ApplicationIcon.png</IconPath>\n"
+ "\t\t<Capabilities/>\n"
+ "\t\t<Tasks>\n"
+ "\t\t\t<DefaultTask Name=\"_default\""
+ " ImagePath=\"" << targetNameXML << ".exe\" ImageParams=\"\" />\n"
+ "\t\t</Tasks>\n"
+ "\t\t<Tokens>\n"
+ "\t\t\t<PrimaryToken TokenID=\"" << targetNameXML << "Token\""
+ " TaskName=\"_default\">\n"
+ "\t\t\t\t<TemplateFlip>\n"
+ "\t\t\t\t\t<SmallImageURI IsRelative=\"true\" IsResource=\"false\">"
+ << artifactDirXML << "\\SmallLogo.png</SmallImageURI>\n"
+ "\t\t\t\t\t<Count>0</Count>\n"
+ "\t\t\t\t\t<BackgroundImageURI IsRelative=\"true\" IsResource=\"false\">"
+ << artifactDirXML << "\\Logo.png</BackgroundImageURI>\n"
+ "\t\t\t\t</TemplateFlip>\n"
+ "\t\t\t</PrimaryToken>\n"
+ "\t\t</Tokens>\n"
+ "\t\t<ScreenResolutions>\n"
+ "\t\t\t<ScreenResolution Name=\"ID_RESOLUTION_WVGA\" />\n"
+ "\t\t</ScreenResolutions>\n"
+ "\t</App>\n"
+ "</Deployment>\n";
+ /* clang-format on */
+
+ std::string sourceFile = this->ConvertPath(manifestFile, false);
+ ConvertToWindowsSlash(sourceFile);
+ {
+ Elem e2(e1, "Xml");
+ e2.Attribute("Include", sourceFile);
+ e2.Element("SubType", "Designer");
+ }
+ this->AddedFiles.push_back(sourceFile);
+
+ std::string smallLogo = this->DefaultArtifactDir + "/SmallLogo.png";
+ cmSystemTools::CopyAFile(templateFolder + "/SmallLogo.png", smallLogo,
+ false);
+ ConvertToWindowsSlash(smallLogo);
+ Elem(e1, "Image").Attribute("Include", smallLogo);
+ this->AddedFiles.push_back(smallLogo);
+
+ std::string logo = this->DefaultArtifactDir + "/Logo.png";
+ cmSystemTools::CopyAFile(templateFolder + "/Logo.png", logo, false);
+ ConvertToWindowsSlash(logo);
+ Elem(e1, "Image").Attribute("Include", logo);
+ this->AddedFiles.push_back(logo);
+
+ std::string applicationIcon =
+ this->DefaultArtifactDir + "/ApplicationIcon.png";
+ cmSystemTools::CopyAFile(templateFolder + "/ApplicationIcon.png",
+ applicationIcon, false);
+ ConvertToWindowsSlash(applicationIcon);
+ Elem(e1, "Image").Attribute("Include", applicationIcon);
+ this->AddedFiles.push_back(applicationIcon);
+}
+
+void cmVisualStudio10TargetGenerator::WriteMissingFilesWP81(Elem& e1)
+{
+ std::string manifestFile =
+ this->DefaultArtifactDir + "/package.appxManifest";
+ std::string artifactDir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ ConvertToWindowsSlash(artifactDir);
+ std::string artifactDirXML = cmVS10EscapeXML(artifactDir);
+ std::string targetNameXML =
+ cmVS10EscapeXML(this->GeneratorTarget->GetName());
+
+ cmGeneratedFileStream fout(manifestFile);
+ fout.SetCopyIfDifferent(true);
+
+ /* clang-format off */
+ fout <<
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<Package xmlns=\"http://schemas.microsoft.com/appx/2010/manifest\""
+ " xmlns:m2=\"http://schemas.microsoft.com/appx/2013/manifest\""
+ " xmlns:mp=\"http://schemas.microsoft.com/appx/2014/phone/manifest\">\n"
+ "\t<Identity Name=\"" << this->GUID << "\" Publisher=\"CN=CMake\""
+ " Version=\"1.0.0.0\" />\n"
+ "\t<mp:PhoneIdentity PhoneProductId=\"" << this->GUID << "\""
+ " PhonePublisherId=\"00000000-0000-0000-0000-000000000000\"/>\n"
+ "\t<Properties>\n"
+ "\t\t<DisplayName>" << targetNameXML << "</DisplayName>\n"
+ "\t\t<PublisherDisplayName>CMake</PublisherDisplayName>\n"
+ "\t\t<Logo>" << artifactDirXML << "\\StoreLogo.png</Logo>\n"
+ "\t</Properties>\n"
+ "\t<Prerequisites>\n"
+ "\t\t<OSMinVersion>6.3.1</OSMinVersion>\n"
+ "\t\t<OSMaxVersionTested>6.3.1</OSMaxVersionTested>\n"
+ "\t</Prerequisites>\n"
+ "\t<Resources>\n"
+ "\t\t<Resource Language=\"x-generate\" />\n"
+ "\t</Resources>\n"
+ "\t<Applications>\n"
+ "\t\t<Application Id=\"App\""
+ " Executable=\"" << targetNameXML << ".exe\""
+ " EntryPoint=\"" << targetNameXML << ".App\">\n"
+ "\t\t\t<m2:VisualElements\n"
+ "\t\t\t\tDisplayName=\"" << targetNameXML << "\"\n"
+ "\t\t\t\tDescription=\"" << targetNameXML << "\"\n"
+ "\t\t\t\tBackgroundColor=\"#336699\"\n"
+ "\t\t\t\tForegroundText=\"light\"\n"
+ "\t\t\t\tSquare150x150Logo=\"" << artifactDirXML << "\\Logo.png\"\n"
+ "\t\t\t\tSquare30x30Logo=\"" << artifactDirXML << "\\SmallLogo.png\">\n"
+ "\t\t\t\t<m2:DefaultTile ShortName=\"" << targetNameXML << "\">\n"
+ "\t\t\t\t\t<m2:ShowNameOnTiles>\n"
+ "\t\t\t\t\t\t<m2:ShowOn Tile=\"square150x150Logo\" />\n"
+ "\t\t\t\t\t</m2:ShowNameOnTiles>\n"
+ "\t\t\t\t</m2:DefaultTile>\n"
+ "\t\t\t\t<m2:SplashScreen"
+ " Image=\"" << artifactDirXML << "\\SplashScreen.png\" />\n"
+ "\t\t\t</m2:VisualElements>\n"
+ "\t\t</Application>\n"
+ "\t</Applications>\n"
+ "</Package>\n";
+ /* clang-format on */
+
+ this->WriteCommonMissingFiles(e1, manifestFile);
+}
+
+void cmVisualStudio10TargetGenerator::WriteMissingFilesWS80(Elem& e1)
+{
+ std::string manifestFile =
+ this->DefaultArtifactDir + "/package.appxManifest";
+ std::string artifactDir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ ConvertToWindowsSlash(artifactDir);
+ std::string artifactDirXML = cmVS10EscapeXML(artifactDir);
+ std::string targetNameXML =
+ cmVS10EscapeXML(this->GeneratorTarget->GetName());
+
+ cmGeneratedFileStream fout(manifestFile);
+ fout.SetCopyIfDifferent(true);
+
+ /* clang-format off */
+ fout <<
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<Package xmlns=\"http://schemas.microsoft.com/appx/2010/manifest\">\n"
+ "\t<Identity Name=\"" << this->GUID << "\" Publisher=\"CN=CMake\""
+ " Version=\"1.0.0.0\" />\n"
+ "\t<Properties>\n"
+ "\t\t<DisplayName>" << targetNameXML << "</DisplayName>\n"
+ "\t\t<PublisherDisplayName>CMake</PublisherDisplayName>\n"
+ "\t\t<Logo>" << artifactDirXML << "\\StoreLogo.png</Logo>\n"
+ "\t</Properties>\n"
+ "\t<Prerequisites>\n"
+ "\t\t<OSMinVersion>6.2.1</OSMinVersion>\n"
+ "\t\t<OSMaxVersionTested>6.2.1</OSMaxVersionTested>\n"
+ "\t</Prerequisites>\n"
+ "\t<Resources>\n"
+ "\t\t<Resource Language=\"x-generate\" />\n"
+ "\t</Resources>\n"
+ "\t<Applications>\n"
+ "\t\t<Application Id=\"App\""
+ " Executable=\"" << targetNameXML << ".exe\""
+ " EntryPoint=\"" << targetNameXML << ".App\">\n"
+ "\t\t\t<VisualElements"
+ " DisplayName=\"" << targetNameXML << "\""
+ " Description=\"" << targetNameXML << "\""
+ " BackgroundColor=\"#336699\" ForegroundText=\"light\""
+ " Logo=\"" << artifactDirXML << "\\Logo.png\""
+ " SmallLogo=\"" << artifactDirXML << "\\SmallLogo.png\">\n"
+ "\t\t\t\t<DefaultTile ShowName=\"allLogos\""
+ " ShortName=\"" << targetNameXML << "\" />\n"
+ "\t\t\t\t<SplashScreen"
+ " Image=\"" << artifactDirXML << "\\SplashScreen.png\" />\n"
+ "\t\t\t</VisualElements>\n"
+ "\t\t</Application>\n"
+ "\t</Applications>\n"
+ "</Package>\n";
+ /* clang-format on */
+
+ this->WriteCommonMissingFiles(e1, manifestFile);
+}
+
+void cmVisualStudio10TargetGenerator::WriteMissingFilesWS81(Elem& e1)
+{
+ std::string manifestFile =
+ this->DefaultArtifactDir + "/package.appxManifest";
+ std::string artifactDir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ ConvertToWindowsSlash(artifactDir);
+ std::string artifactDirXML = cmVS10EscapeXML(artifactDir);
+ std::string targetNameXML =
+ cmVS10EscapeXML(this->GeneratorTarget->GetName());
+
+ cmGeneratedFileStream fout(manifestFile);
+ fout.SetCopyIfDifferent(true);
+
+ /* clang-format off */
+ fout <<
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<Package xmlns=\"http://schemas.microsoft.com/appx/2010/manifest\""
+ " xmlns:m2=\"http://schemas.microsoft.com/appx/2013/manifest\">\n"
+ "\t<Identity Name=\"" << this->GUID << "\" Publisher=\"CN=CMake\""
+ " Version=\"1.0.0.0\" />\n"
+ "\t<Properties>\n"
+ "\t\t<DisplayName>" << targetNameXML << "</DisplayName>\n"
+ "\t\t<PublisherDisplayName>CMake</PublisherDisplayName>\n"
+ "\t\t<Logo>" << artifactDirXML << "\\StoreLogo.png</Logo>\n"
+ "\t</Properties>\n"
+ "\t<Prerequisites>\n"
+ "\t\t<OSMinVersion>6.3</OSMinVersion>\n"
+ "\t\t<OSMaxVersionTested>6.3</OSMaxVersionTested>\n"
+ "\t</Prerequisites>\n"
+ "\t<Resources>\n"
+ "\t\t<Resource Language=\"x-generate\" />\n"
+ "\t</Resources>\n"
+ "\t<Applications>\n"
+ "\t\t<Application Id=\"App\""
+ " Executable=\"" << targetNameXML << ".exe\""
+ " EntryPoint=\"" << targetNameXML << ".App\">\n"
+ "\t\t\t<m2:VisualElements\n"
+ "\t\t\t\tDisplayName=\"" << targetNameXML << "\"\n"
+ "\t\t\t\tDescription=\"" << targetNameXML << "\"\n"
+ "\t\t\t\tBackgroundColor=\"#336699\"\n"
+ "\t\t\t\tForegroundText=\"light\"\n"
+ "\t\t\t\tSquare150x150Logo=\"" << artifactDirXML << "\\Logo.png\"\n"
+ "\t\t\t\tSquare30x30Logo=\"" << artifactDirXML << "\\SmallLogo.png\">\n"
+ "\t\t\t\t<m2:DefaultTile ShortName=\"" << targetNameXML << "\">\n"
+ "\t\t\t\t\t<m2:ShowNameOnTiles>\n"
+ "\t\t\t\t\t\t<m2:ShowOn Tile=\"square150x150Logo\" />\n"
+ "\t\t\t\t\t</m2:ShowNameOnTiles>\n"
+ "\t\t\t\t</m2:DefaultTile>\n"
+ "\t\t\t\t<m2:SplashScreen"
+ " Image=\"" << artifactDirXML << "\\SplashScreen.png\" />\n"
+ "\t\t\t</m2:VisualElements>\n"
+ "\t\t</Application>\n"
+ "\t</Applications>\n"
+ "</Package>\n";
+ /* clang-format on */
+
+ this->WriteCommonMissingFiles(e1, manifestFile);
+}
+
+void cmVisualStudio10TargetGenerator::WriteMissingFilesWS10_0(Elem& e1)
+{
+ std::string manifestFile =
+ this->DefaultArtifactDir + "/package.appxManifest";
+ std::string artifactDir =
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ ConvertToWindowsSlash(artifactDir);
+ std::string artifactDirXML = cmVS10EscapeXML(artifactDir);
+ std::string targetNameXML =
+ cmVS10EscapeXML(this->GeneratorTarget->GetName());
+
+ cmGeneratedFileStream fout(manifestFile);
+ fout.SetCopyIfDifferent(true);
+
+ /* clang-format off */
+ fout <<
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<Package\n\t"
+ "xmlns=\"http://schemas.microsoft.com/appx/manifest/foundation/windows10\""
+ "\txmlns:mp=\"http://schemas.microsoft.com/appx/2014/phone/manifest\"\n"
+ "\txmlns:uap=\"http://schemas.microsoft.com/appx/manifest/uap/windows10\""
+ "\n\tIgnorableNamespaces=\"uap mp\">\n\n"
+ "\t<Identity Name=\"" << this->GUID << "\" Publisher=\"CN=CMake\""
+ " Version=\"1.0.0.0\" />\n"
+ "\t<mp:PhoneIdentity PhoneProductId=\"" << this->GUID <<
+ "\" PhonePublisherId=\"00000000-0000-0000-0000-000000000000\"/>\n"
+ "\t<Properties>\n"
+ "\t\t<DisplayName>" << targetNameXML << "</DisplayName>\n"
+ "\t\t<PublisherDisplayName>CMake</PublisherDisplayName>\n"
+ "\t\t<Logo>" << artifactDirXML << "\\StoreLogo.png</Logo>\n"
+ "\t</Properties>\n"
+ "\t<Dependencies>\n"
+ "\t\t<TargetDeviceFamily Name=\"Windows.Universal\" "
+ "MinVersion=\"10.0.0.0\" MaxVersionTested=\"10.0.0.0\" />\n"
+ "\t</Dependencies>\n"
+
+ "\t<Resources>\n"
+ "\t\t<Resource Language=\"x-generate\" />\n"
+ "\t</Resources>\n"
+ "\t<Applications>\n"
+ "\t\t<Application Id=\"App\""
+ " Executable=\"" << targetNameXML << ".exe\""
+ " EntryPoint=\"" << targetNameXML << ".App\">\n"
+ "\t\t\t<uap:VisualElements\n"
+ "\t\t\t\tDisplayName=\"" << targetNameXML << "\"\n"
+ "\t\t\t\tDescription=\"" << targetNameXML << "\"\n"
+ "\t\t\t\tBackgroundColor=\"#336699\"\n"
+ "\t\t\t\tSquare150x150Logo=\"" << artifactDirXML << "\\Logo.png\"\n"
+ "\t\t\t\tSquare44x44Logo=\"" << artifactDirXML <<
+ "\\SmallLogo44x44.png\">\n"
+ "\t\t\t\t<uap:SplashScreen"
+ " Image=\"" << artifactDirXML << "\\SplashScreen.png\" />\n"
+ "\t\t\t</uap:VisualElements>\n"
+ "\t\t</Application>\n"
+ "\t</Applications>\n"
+ "</Package>\n";
+ /* clang-format on */
+
+ this->WriteCommonMissingFiles(e1, manifestFile);
+}
+
+void cmVisualStudio10TargetGenerator::WriteCommonMissingFiles(
+ Elem& e1, const std::string& manifestFile)
+{
+ std::string templateFolder =
+ cmSystemTools::GetCMakeRoot() + "/Templates/Windows";
+
+ std::string sourceFile = this->ConvertPath(manifestFile, false);
+ ConvertToWindowsSlash(sourceFile);
+ {
+ Elem e2(e1, "AppxManifest");
+ e2.Attribute("Include", sourceFile);
+ e2.Element("SubType", "Designer");
+ }
+ this->AddedFiles.push_back(sourceFile);
+
+ std::string smallLogo = this->DefaultArtifactDir + "/SmallLogo.png";
+ cmSystemTools::CopyAFile(templateFolder + "/SmallLogo.png", smallLogo,
+ false);
+ ConvertToWindowsSlash(smallLogo);
+ Elem(e1, "Image").Attribute("Include", smallLogo);
+ this->AddedFiles.push_back(smallLogo);
+
+ std::string smallLogo44 = this->DefaultArtifactDir + "/SmallLogo44x44.png";
+ cmSystemTools::CopyAFile(templateFolder + "/SmallLogo44x44.png", smallLogo44,
+ false);
+ ConvertToWindowsSlash(smallLogo44);
+ Elem(e1, "Image").Attribute("Include", smallLogo44);
+ this->AddedFiles.push_back(smallLogo44);
+
+ std::string logo = this->DefaultArtifactDir + "/Logo.png";
+ cmSystemTools::CopyAFile(templateFolder + "/Logo.png", logo, false);
+ ConvertToWindowsSlash(logo);
+ Elem(e1, "Image").Attribute("Include", logo);
+ this->AddedFiles.push_back(logo);
+
+ std::string storeLogo = this->DefaultArtifactDir + "/StoreLogo.png";
+ cmSystemTools::CopyAFile(templateFolder + "/StoreLogo.png", storeLogo,
+ false);
+ ConvertToWindowsSlash(storeLogo);
+ Elem(e1, "Image").Attribute("Include", storeLogo);
+ this->AddedFiles.push_back(storeLogo);
+
+ std::string splashScreen = this->DefaultArtifactDir + "/SplashScreen.png";
+ cmSystemTools::CopyAFile(templateFolder + "/SplashScreen.png", splashScreen,
+ false);
+ ConvertToWindowsSlash(splashScreen);
+ Elem(e1, "Image").Attribute("Include", splashScreen);
+ this->AddedFiles.push_back(splashScreen);
+
+ if (this->AddedDefaultCertificate) {
+ // This file has already been added to the build so don't copy it
+ std::string keyFile =
+ this->DefaultArtifactDir + "/Windows_TemporaryKey.pfx";
+ ConvertToWindowsSlash(keyFile);
+ Elem(e1, "None").Attribute("Include", keyFile);
+ }
+}
+
+bool cmVisualStudio10TargetGenerator::ForceOld(const std::string& source) const
+{
+ HANDLE h =
+ CreateFileW(cmSystemTools::ConvertToWindowsExtendedPath(source).c_str(),
+ FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, 0);
+ if (!h) {
+ return false;
+ }
+
+ FILETIME const ftime_20010101 = { 3365781504u, 29389701u };
+ if (!SetFileTime(h, &ftime_20010101, &ftime_20010101, &ftime_20010101)) {
+ CloseHandle(h);
+ return false;
+ }
+
+ CloseHandle(h);
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::GetCSharpSourceProperties(
+ cmSourceFile const* sf, std::map<std::string, std::string>& tags)
+{
+ if (this->ProjectType == csproj) {
+ const cmPropertyMap& props = sf->GetProperties();
+ for (const std::string& p : props.GetKeys()) {
+ static const cm::string_view propNamePrefix = "VS_CSHARP_";
+ if (cmHasPrefix(p, propNamePrefix)) {
+ std::string tagName = p.substr(propNamePrefix.length());
+ if (!tagName.empty()) {
+ cmProp val = props.GetPropertyValue(p);
+ if (cmNonempty(val)) {
+ tags[tagName] = *val;
+ } else {
+ tags.erase(tagName);
+ }
+ }
+ }
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WriteCSharpSourceProperties(
+ Elem& e2, const std::map<std::string, std::string>& tags)
+{
+ for (const auto& i : tags) {
+ e2.Element(i.first, i.second);
+ }
+}
+
+std::string cmVisualStudio10TargetGenerator::GetCSharpSourceLink(
+ cmSourceFile const* source)
+{
+ // For out of source files, we first check if a matching source group
+ // for this file exists, otherwise we check if the path relative to current
+ // source- or binary-dir is used within the link and return that
+ std::string link;
+ std::string sourceGroupedFile;
+ std::string const& fullFileName = source->GetFullPath();
+ std::string const& srcDir = this->Makefile->GetCurrentSourceDirectory();
+ std::string const& binDir = this->Makefile->GetCurrentBinaryDirectory();
+ // unfortunately we have to copy the source groups, because
+ // FindSourceGroup uses a regex which is modifying the group
+ std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
+ cmSourceGroup* sourceGroup =
+ this->Makefile->FindSourceGroup(fullFileName, sourceGroups);
+ if (sourceGroup && !sourceGroup->GetFullName().empty()) {
+ sourceGroupedFile = sourceGroup->GetFullName() + "/" +
+ cmsys::SystemTools::GetFilenameName(fullFileName);
+ cmsys::SystemTools::ConvertToUnixSlashes(sourceGroupedFile);
+ }
+
+ if (!sourceGroupedFile.empty() &&
+ cmHasSuffix(fullFileName, sourceGroupedFile)) {
+ link = sourceGroupedFile;
+ } else if (cmHasPrefix(fullFileName, srcDir)) {
+ link = fullFileName.substr(srcDir.length() + 1);
+ } else if (cmHasPrefix(fullFileName, binDir)) {
+ link = fullFileName.substr(binDir.length() + 1);
+ } else if (cmProp l = source->GetProperty("VS_CSHARP_Link")) {
+ link = *l;
+ }
+
+ ConvertToWindowsSlash(link);
+ return link;
+}
+
+std::string cmVisualStudio10TargetGenerator::GetCMakeFilePath(
+ const char* relativeFilePath) const
+{
+ // Always search in the standard modules location.
+ std::string path =
+ cmStrCat(cmSystemTools::GetCMakeRoot(), '/', relativeFilePath);
+ ConvertToWindowsSlash(path);
+
+ return path;
+}
+
+void cmVisualStudio10TargetGenerator::WriteStdOutEncodingUtf8(Elem& e1)
+{
+ if (this->GlobalGenerator->IsStdOutEncodingSupported()) {
+ e1.Element("StdOutEncoding", "UTF-8");
+ }
+}
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
new file mode 100644
index 0000000..35dbba8
--- /dev/null
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -0,0 +1,260 @@
+/* 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 <iosfwd>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "cmGeneratorTarget.h"
+
+class cmComputeLinkInformation;
+class cmCustomCommand;
+class cmGeneratedFileStream;
+class cmGlobalVisualStudio10Generator;
+class cmLocalVisualStudio10Generator;
+class cmMakefile;
+class cmSourceFile;
+class cmSourceGroup;
+class cmVS10GeneratorOptions;
+
+class cmVisualStudio10TargetGenerator
+{
+public:
+ cmVisualStudio10TargetGenerator(cmGeneratorTarget* target,
+ cmGlobalVisualStudio10Generator* gg);
+ ~cmVisualStudio10TargetGenerator();
+
+ cmVisualStudio10TargetGenerator(cmVisualStudio10TargetGenerator const&) =
+ delete;
+ cmVisualStudio10TargetGenerator& operator=(
+ cmVisualStudio10TargetGenerator const&) = delete;
+
+ void Generate();
+
+private:
+ struct ToolSource
+ {
+ cmSourceFile const* SourceFile;
+ bool RelativePath;
+ };
+ struct ToolSources : public std::vector<ToolSource>
+ {
+ };
+
+ struct TargetsFileAndConfigs
+ {
+ std::string File;
+ std::vector<std::string> Configs;
+ };
+
+ struct Elem;
+ struct OptionsHelper;
+
+ std::string ConvertPath(std::string const& path, bool forceRelative);
+ std::string CalcCondition(const std::string& config) const;
+ void WriteProjectConfigurations(Elem& e0);
+ void WriteProjectConfigurationValues(Elem& e0);
+ void WriteMSToolConfigurationValues(Elem& e1, std::string const& config);
+ void WriteCEDebugProjectConfigurationValues(Elem& e0);
+ void WriteMSToolConfigurationValuesManaged(Elem& e1,
+ std::string const& config);
+ void WriteHeaderSource(Elem& e1, cmSourceFile const* sf);
+ void WriteExtraSource(Elem& e1, cmSourceFile const* sf);
+ void WriteNsightTegraConfigurationValues(Elem& e1,
+ std::string const& config);
+ void WriteAndroidConfigurationValues(Elem& e1, std::string const& config);
+ void WriteSource(Elem& e2, cmSourceFile const* sf);
+ void WriteExcludeFromBuild(Elem& e2,
+ std::vector<size_t> const& exclude_configs);
+ void WriteAllSources(Elem& e0);
+ void WritePackageReferences(Elem& e0);
+ void WriteDotNetReferences(Elem& e0);
+ void WriteDotNetReference(Elem& e1, std::string const& ref,
+ std::string const& hint,
+ std::string const& config);
+ void WriteDotNetDocumentationFile(Elem& e0);
+ void WriteImports(Elem& e0);
+ void WriteDotNetReferenceCustomTags(Elem& e2, std::string const& ref);
+ void WriteEmbeddedResourceGroup(Elem& e0);
+ void WriteWinRTReferences(Elem& e0);
+ void WriteWinRTPackageCertificateKeyFile(Elem& e0);
+ void WriteXamlFilesGroup(Elem& e0);
+ void WritePathAndIncrementalLinkOptions(Elem& e0);
+ void WriteItemDefinitionGroups(Elem& e0);
+ void VerifyNecessaryFiles();
+ void WriteMissingFiles(Elem& e1);
+ void WriteMissingFilesWP80(Elem& e1);
+ void WriteMissingFilesWP81(Elem& e1);
+ void WriteMissingFilesWS80(Elem& e1);
+ void WriteMissingFilesWS81(Elem& e1);
+ void WriteMissingFilesWS10_0(Elem& e1);
+ void WritePlatformExtensions(Elem& e1);
+ void WriteSinglePlatformExtension(Elem& e1, std::string const& extension,
+ std::string const& version);
+ void WriteSDKReferences(Elem& e0);
+ void WriteSingleSDKReference(Elem& e1, std::string const& extension,
+ std::string const& version);
+ void WriteCommonMissingFiles(Elem& e1, const std::string& manifestFile);
+ void WriteTargetSpecificReferences(Elem& e0);
+ void WriteTargetsFileReferences(Elem& e1);
+
+ std::vector<std::string> GetIncludes(std::string const& config,
+ std::string const& lang) const;
+
+ bool ComputeClOptions();
+ bool ComputeClOptions(std::string const& configName);
+ void WriteClOptions(Elem& e1, std::string const& config);
+ bool ComputeRcOptions();
+ bool ComputeRcOptions(std::string const& config);
+ void WriteRCOptions(Elem& e1, std::string const& config);
+ bool ComputeCudaOptions();
+ bool ComputeCudaOptions(std::string const& config);
+ void WriteCudaOptions(Elem& e1, std::string const& config);
+
+ bool ComputeCudaLinkOptions();
+ bool ComputeCudaLinkOptions(std::string const& config);
+ void WriteCudaLinkOptions(Elem& e1, std::string const& config);
+
+ bool ComputeMasmOptions();
+ bool ComputeMasmOptions(std::string const& config);
+ void WriteMasmOptions(Elem& e1, std::string const& config);
+ bool ComputeNasmOptions();
+ bool ComputeNasmOptions(std::string const& config);
+ void WriteNasmOptions(Elem& e1, std::string const& config);
+
+ bool ComputeLinkOptions();
+ bool ComputeLinkOptions(std::string const& config);
+ bool ComputeLibOptions();
+ bool ComputeLibOptions(std::string const& config);
+ void WriteLinkOptions(Elem& e1, std::string const& config);
+ void WriteMidlOptions(Elem& e1, std::string const& config);
+ void WriteAntBuildOptions(Elem& e1, std::string const& config);
+ void OutputLinkIncremental(Elem& e1, std::string const& configName);
+ void WriteCustomRule(Elem& e0, cmSourceFile const* source,
+ cmCustomCommand const& command);
+ void WriteCustomRuleCpp(Elem& e2, std::string const& config,
+ std::string const& script,
+ std::string const& additional_inputs,
+ std::string const& outputs,
+ std::string const& comment, bool symbolic);
+ void WriteCustomRuleCSharp(Elem& e0, std::string const& config,
+ std::string const& commandName,
+ std::string const& script,
+ std::string const& inputs,
+ std::string const& outputs,
+ std::string const& comment);
+ void WriteCustomCommands(Elem& e0);
+ void WriteCustomCommand(Elem& e0, cmSourceFile const* sf);
+ void WriteGroups();
+ void WriteProjectReferences(Elem& e0);
+ void WriteApplicationTypeSettings(Elem& e1);
+ void OutputSourceSpecificFlags(Elem& e2, cmSourceFile const* source);
+ void AddLibraries(const cmComputeLinkInformation& cli,
+ std::vector<std::string>& libVec,
+ std::vector<std::string>& vsTargetVec,
+ const std::string& config);
+ void AddTargetsFileAndConfigPair(std::string const& targetsFile,
+ std::string const& config);
+ void WriteLibOptions(Elem& e1, std::string const& config);
+ void WriteManifestOptions(Elem& e1, std::string const& config);
+ void WriteEvents(Elem& e1, std::string const& configName);
+ void WriteEvent(Elem& e1, std::string const& name,
+ std::vector<cmCustomCommand> const& commands,
+ std::string const& configName);
+ void WriteGroupSources(Elem& e0, std::string const& name,
+ ToolSources const& sources,
+ std::vector<cmSourceGroup>&);
+ void AddMissingSourceGroups(std::set<cmSourceGroup const*>& groupsUsed,
+ const std::vector<cmSourceGroup>& allGroups);
+ bool IsResxHeader(const std::string& headerFile);
+ bool IsXamlHeader(const std::string& headerFile);
+ bool IsXamlSource(const std::string& headerFile);
+
+ bool ForceOld(const std::string& source) const;
+
+ void GetCSharpSourceProperties(cmSourceFile const* sf,
+ std::map<std::string, std::string>& tags);
+ void WriteCSharpSourceProperties(
+ Elem& e2, const std::map<std::string, std::string>& tags);
+ std::string GetCSharpSourceLink(cmSourceFile const* source);
+
+ void WriteStdOutEncodingUtf8(Elem& e1);
+
+private:
+ friend class cmVS10GeneratorOptions;
+ using Options = cmVS10GeneratorOptions;
+ using OptionsMap = std::map<std::string, std::unique_ptr<Options>>;
+ OptionsMap ClOptions;
+ OptionsMap RcOptions;
+ OptionsMap CudaOptions;
+ OptionsMap CudaLinkOptions;
+ OptionsMap MasmOptions;
+ OptionsMap NasmOptions;
+ OptionsMap LinkOptions;
+ std::string LangForClCompile;
+ enum VsProjectType
+ {
+ vcxproj,
+ csproj
+ } ProjectType;
+ bool InSourceBuild;
+ std::vector<std::string> Configurations;
+ std::vector<TargetsFileAndConfigs> TargetsFileAndConfigsVec;
+ cmGeneratorTarget* const GeneratorTarget;
+ cmMakefile* const Makefile;
+ std::string const Platform;
+ std::string const Name;
+ std::string const GUID;
+ bool MSTools;
+ bool Managed;
+ bool NsightTegra;
+ bool Android;
+ unsigned int NsightTegraVersion[4];
+ bool TargetCompileAsWinRT;
+ std::set<std::string> IPOEnabledConfigurations;
+ std::map<std::string, std::string> SpectreMitigation;
+ cmGlobalVisualStudio10Generator* const GlobalGenerator;
+ cmLocalVisualStudio10Generator* const LocalGenerator;
+ std::set<std::string> CSharpCustomCommandNames;
+ bool IsMissingFiles;
+ std::vector<std::string> AddedFiles;
+ std::string DefaultArtifactDir;
+ bool AddedDefaultCertificate = false;
+ // managed C++/C# relevant members
+ using DotNetHintReference = std::pair<std::string, std::string>;
+ using DotNetHintReferenceList = std::vector<DotNetHintReference>;
+ using DotNetHintReferenceMap =
+ std::map<std::string, DotNetHintReferenceList>;
+ DotNetHintReferenceMap DotNetHintReferences;
+ using UsingDirectories = std::set<std::string>;
+ using UsingDirectoriesMap = std::map<std::string, UsingDirectories>;
+ UsingDirectoriesMap AdditionalUsingDirectories;
+
+ using ToolSourceMap = std::map<std::string, ToolSources>;
+ ToolSourceMap Tools;
+
+ std::set<std::string> ExpectedResxHeaders;
+ std::set<std::string> ExpectedXamlHeaders;
+ std::set<std::string> ExpectedXamlSources;
+ std::vector<cmSourceFile const*> ResxObjs;
+ std::vector<cmSourceFile const*> XamlObjs;
+ void ClassifyAllConfigSources();
+ void ClassifyAllConfigSource(cmGeneratorTarget::AllConfigSource const& acs);
+
+ using ConfigToSettings =
+ std::unordered_map<std::string,
+ std::unordered_map<std::string, std::string>>;
+ std::unordered_map<std::string, ConfigToSettings> ParsedToolTargetSettings;
+ bool PropertyIsSameInAllConfigs(const ConfigToSettings& toolSettings,
+ const std::string& propName);
+ void ParseSettingsProperty(const std::string& settingsPropertyValue,
+ ConfigToSettings& toolSettings);
+ std::string GetCMakeFilePath(const char* name) const;
+};
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
new file mode 100644
index 0000000..937b4ce
--- /dev/null
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -0,0 +1,514 @@
+#include "cmVisualStudioGeneratorOptions.h"
+
+#include <cm/iterator>
+
+#include "cmAlgorithms.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalVisualStudioGenerator.h"
+#include "cmOutputConverter.h"
+#include "cmSystemTools.h"
+
+static void cmVS10EscapeForMSBuild(std::string& ret)
+{
+ cmSystemTools::ReplaceString(ret, ";", "%3B");
+}
+
+cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions(
+ cmLocalVisualStudioGenerator* lg, Tool tool, cmVS7FlagTable const* table,
+ cmVS7FlagTable const* extraTable)
+ : cmIDEOptions()
+ , LocalGenerator(lg)
+ , Version(lg->GetVersion())
+ , CurrentTool(tool)
+{
+ // Store the given flag tables.
+ this->AddTable(table);
+ this->AddTable(extraTable);
+
+ // Preprocessor definitions are not allowed for linker tools.
+ this->AllowDefine = (tool != Linker);
+
+ // include directories are not allowed for linker tools.
+ this->AllowInclude = (tool != Linker);
+
+ // Slash options are allowed for VS.
+ this->AllowSlash = true;
+
+ this->FortranRuntimeDebug = false;
+ this->FortranRuntimeDLL = false;
+ this->FortranRuntimeMT = false;
+
+ this->UnknownFlagField = "AdditionalOptions";
+}
+
+void cmVisualStudioGeneratorOptions::AddTable(cmVS7FlagTable const* table)
+{
+ if (table) {
+ for (int i = 0; i < FlagTableCount; ++i) {
+ if (!this->FlagTable[i]) {
+ this->FlagTable[i] = table;
+ break;
+ }
+ }
+ }
+}
+
+void cmVisualStudioGeneratorOptions::ClearTables()
+{
+ for (int i = 0; i < FlagTableCount; ++i) {
+ this->FlagTable[i] = nullptr;
+ }
+}
+
+void cmVisualStudioGeneratorOptions::FixExceptionHandlingDefault()
+{
+ // Exception handling is on by default because the platform file has
+ // "/EHsc" in the flags. Normally, that will override this
+ // initialization to off, but the user has the option of removing
+ // the flag to disable exception handling. When the user does
+ // remove the flag we need to override the IDE default of on.
+ switch (this->Version) {
+ case cmGlobalVisualStudioGenerator::VS10:
+ case cmGlobalVisualStudioGenerator::VS11:
+ case cmGlobalVisualStudioGenerator::VS12:
+ case cmGlobalVisualStudioGenerator::VS14:
+ case cmGlobalVisualStudioGenerator::VS15:
+ case cmGlobalVisualStudioGenerator::VS16:
+ // by default VS puts <ExceptionHandling></ExceptionHandling> empty
+ // for a project, to make our projects look the same put a new line
+ // and space over for the closing </ExceptionHandling> as the default
+ // value
+ this->FlagMap["ExceptionHandling"] = "\n ";
+ break;
+ default:
+ this->FlagMap["ExceptionHandling"] = "0";
+ break;
+ }
+}
+
+void cmVisualStudioGeneratorOptions::SetVerboseMakefile(bool verbose)
+{
+ // If verbose makefiles have been requested and the /nologo option
+ // was not given explicitly in the flags we want to add an attribute
+ // to the generated project to disable logo suppression. Otherwise
+ // the GUI default is to enable suppression.
+ //
+ // On Visual Studio 10 (and later!), the value of this attribute should be
+ // an empty string, instead of "FALSE", in order to avoid a warning:
+ // "cl ... warning D9035: option 'nologo-' has been deprecated"
+ //
+ if (verbose &&
+ this->FlagMap.find("SuppressStartupBanner") == this->FlagMap.end()) {
+ this->FlagMap["SuppressStartupBanner"] =
+ this->Version < cmGlobalVisualStudioGenerator::VS10 ? "FALSE" : "";
+ }
+}
+
+bool cmVisualStudioGeneratorOptions::IsDebug() const
+{
+ if (this->CurrentTool != CSharpCompiler) {
+ return this->FlagMap.find("DebugInformationFormat") != this->FlagMap.end();
+ }
+ std::map<std::string, FlagValue>::const_iterator i =
+ this->FlagMap.find("DebugType");
+ if (i != this->FlagMap.end()) {
+ if (i->second.size() == 1) {
+ return i->second[0] != "none";
+ }
+ }
+ return false;
+}
+
+bool cmVisualStudioGeneratorOptions::IsWinRt() const
+{
+ return this->FlagMap.find("CompileAsWinRT") != this->FlagMap.end();
+}
+
+bool cmVisualStudioGeneratorOptions::IsManaged() const
+{
+ return this->FlagMap.find("CompileAsManaged") != this->FlagMap.end();
+}
+
+bool cmVisualStudioGeneratorOptions::UsingUnicode() const
+{
+ // Look for a _UNICODE definition.
+ for (std::string const& di : this->Defines) {
+ if (di == "_UNICODE") {
+ return true;
+ }
+ }
+ return false;
+}
+bool cmVisualStudioGeneratorOptions::UsingSBCS() const
+{
+ // Look for a _SBCS definition.
+ for (std::string const& di : this->Defines) {
+ if (di == "_SBCS") {
+ return true;
+ }
+ }
+ return false;
+}
+
+void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration()
+{
+ // Extract temporary values stored by our flag table.
+ FlagValue arch = this->TakeFlag("cmake-temp-arch");
+ FlagValue code = this->TakeFlag("cmake-temp-code");
+ FlagValue gencode = this->TakeFlag("cmake-temp-gencode");
+
+ // No -code allowed without -arch.
+ if (arch.empty()) {
+ code.clear();
+ }
+
+ if (arch.empty() && gencode.empty()) {
+ return;
+ }
+
+ // Create a CodeGeneration field with [arch],[code] syntax in each entry.
+ // CUDA will convert it to `-gencode=arch=[arch],code="[code],[arch]"`.
+ FlagValue& result = this->FlagMap["CodeGeneration"];
+
+ // First entries for the -arch=<arch> [-code=<code>,...] pair.
+ if (!arch.empty()) {
+ std::string arch_name = arch[0];
+ std::vector<std::string> codes;
+ if (!code.empty()) {
+ codes = cmTokenize(code[0], ",");
+ }
+ if (codes.empty()) {
+ codes.push_back(arch_name);
+ // nvcc -arch=<arch> has a special case that allows a real
+ // architecture to be specified instead of a virtual arch.
+ // It translates to -arch=<virtual> -code=<real>.
+ cmSystemTools::ReplaceString(arch_name, "sm_", "compute_");
+ }
+ for (std::string const& c : codes) {
+ std::string entry = arch_name + "," + c;
+ result.push_back(entry);
+ }
+ }
+
+ // Now add entries for the following signatures:
+ // -gencode=<arch>,<code>
+ // -gencode=<arch>,[<code1>,<code2>]
+ // -gencode=<arch>,"<code1>,<code2>"
+ for (std::string const& e : gencode) {
+ std::string entry = e;
+ cmSystemTools::ReplaceString(entry, "arch=", "");
+ cmSystemTools::ReplaceString(entry, "code=", "");
+ cmSystemTools::ReplaceString(entry, "[", "");
+ cmSystemTools::ReplaceString(entry, "]", "");
+ cmSystemTools::ReplaceString(entry, "\"", "");
+
+ std::vector<std::string> codes = cmTokenize(entry, ",");
+ if (codes.size() >= 2) {
+ auto gencode_arch = cm::cbegin(codes);
+ for (auto ci = gencode_arch + 1; ci != cm::cend(codes); ++ci) {
+ std::string code_entry = *gencode_arch + "," + *ci;
+ result.push_back(code_entry);
+ }
+ }
+ }
+}
+
+void cmVisualStudioGeneratorOptions::FixManifestUACFlags()
+{
+ static std::string const ENABLE_UAC = "EnableUAC";
+ if (!HasFlag(ENABLE_UAC)) {
+ return;
+ }
+
+ const std::string uacFlag = GetFlag(ENABLE_UAC);
+ std::vector<std::string> subOptions;
+ cmsys::SystemTools::Split(uacFlag, subOptions, ' ');
+ if (subOptions.empty()) {
+ AddFlag(ENABLE_UAC, "true");
+ return;
+ }
+
+ if (subOptions.size() == 1 && subOptions[0] == "NO") {
+ AddFlag(ENABLE_UAC, "false");
+ return;
+ }
+
+ std::map<std::string, std::string> uacMap;
+ uacMap["level"] = "UACExecutionLevel";
+ uacMap["uiAccess"] = "UACUIAccess";
+
+ std::map<std::string, std::string> uacExecuteLevelMap;
+ uacExecuteLevelMap["asInvoker"] = "AsInvoker";
+ uacExecuteLevelMap["highestAvailable"] = "HighestAvailable";
+ uacExecuteLevelMap["requireAdministrator"] = "RequireAdministrator";
+
+ for (std::string const& subopt : subOptions) {
+ std::vector<std::string> keyValue;
+ cmsys::SystemTools::Split(subopt, keyValue, '=');
+ if (keyValue.size() != 2 || (uacMap.find(keyValue[0]) == uacMap.end())) {
+ // ignore none key=value option or unknown flags
+ continue;
+ }
+
+ if (keyValue[1].front() == '\'' && keyValue[1].back() == '\'') {
+ keyValue[1] = keyValue[1].substr(
+ 1, std::max(std::string::size_type(0), keyValue[1].length() - 2));
+ }
+
+ if (keyValue[0] == "level") {
+ if (uacExecuteLevelMap.find(keyValue[1]) == uacExecuteLevelMap.end()) {
+ // unknown level value
+ continue;
+ }
+
+ AddFlag(uacMap[keyValue[0]], uacExecuteLevelMap[keyValue[1]]);
+ continue;
+ }
+
+ if (keyValue[0] == "uiAccess") {
+ if (keyValue[1] != "true" && keyValue[1] != "false") {
+ // unknown uiAccess value
+ continue;
+ }
+ AddFlag(uacMap[keyValue[0]], keyValue[1]);
+ continue;
+ }
+
+ // unknown sub option
+ }
+
+ AddFlag(ENABLE_UAC, "true");
+}
+
+void cmVisualStudioGeneratorOptions::Parse(const std::string& flags)
+{
+ // Parse the input string as a windows command line since the string
+ // is intended for writing directly into the build files.
+ std::vector<std::string> args;
+ cmSystemTools::ParseWindowsCommandLine(flags.c_str(), args);
+
+ // Process flags that need to be represented specially in the IDE
+ // project file.
+ for (std::string const& ai : args) {
+ this->HandleFlag(ai);
+ }
+}
+
+void cmVisualStudioGeneratorOptions::ParseFinish()
+{
+ if (this->CurrentTool == FortranCompiler) {
+ // "RuntimeLibrary" attribute values:
+ // "rtMultiThreaded", "0", /threads /libs:static
+ // "rtMultiThreadedDLL", "2", /threads /libs:dll
+ // "rtMultiThreadedDebug", "1", /threads /dbglibs /libs:static
+ // "rtMultiThreadedDebugDLL", "3", /threads /dbglibs /libs:dll
+ // These seem unimplemented by the IDE:
+ // "rtSingleThreaded", "4", /libs:static
+ // "rtSingleThreadedDLL", "10", /libs:dll
+ // "rtSingleThreadedDebug", "5", /dbglibs /libs:static
+ // "rtSingleThreadedDebugDLL", "11", /dbglibs /libs:dll
+ std::string rl =
+ cmStrCat("rtMultiThreaded", this->FortranRuntimeDebug ? "Debug" : "",
+ this->FortranRuntimeDLL ? "DLL" : "");
+ this->FlagMap["RuntimeLibrary"] = rl;
+ }
+
+ if (this->CurrentTool == CudaCompiler) {
+ std::map<std::string, FlagValue>::iterator i =
+ this->FlagMap.find("CudaRuntime");
+ if (i != this->FlagMap.end() && i->second.size() == 1) {
+ std::string& cudaRuntime = i->second[0];
+ if (cudaRuntime == "static") {
+ cudaRuntime = "Static";
+ } else if (cudaRuntime == "shared") {
+ cudaRuntime = "Shared";
+ } else if (cudaRuntime == "none") {
+ cudaRuntime = "None";
+ }
+ }
+ }
+}
+
+void cmVisualStudioGeneratorOptions::PrependInheritedString(
+ std::string const& key)
+{
+ std::map<std::string, FlagValue>::iterator i = this->FlagMap.find(key);
+ if (i == this->FlagMap.end() || i->second.size() != 1) {
+ return;
+ }
+ std::string& value = i->second[0];
+ value = "%(" + key + ") " + value;
+}
+
+void cmVisualStudioGeneratorOptions::Reparse(std::string const& key)
+{
+ std::map<std::string, FlagValue>::iterator i = this->FlagMap.find(key);
+ if (i == this->FlagMap.end() || i->second.size() != 1) {
+ return;
+ }
+ std::string const original = i->second[0];
+ i->second[0] = "";
+ this->UnknownFlagField = key;
+ this->Parse(original);
+}
+
+void cmVisualStudioGeneratorOptions::StoreUnknownFlag(std::string const& flag)
+{
+ // Look for Intel Fortran flags that do not map well in the flag table.
+ if (this->CurrentTool == FortranCompiler) {
+ if (flag == "/dbglibs" || flag == "-dbglibs") {
+ this->FortranRuntimeDebug = true;
+ return;
+ }
+ if (flag == "/threads" || flag == "-threads") {
+ this->FortranRuntimeMT = true;
+ return;
+ }
+ if (flag == "/libs:dll" || flag == "-libs:dll") {
+ this->FortranRuntimeDLL = true;
+ return;
+ }
+ if (flag == "/libs:static" || flag == "-libs:static") {
+ this->FortranRuntimeDLL = false;
+ return;
+ }
+ }
+
+ // This option is not known. Store it in the output flags.
+ std::string const opts = cmOutputConverter::EscapeWindowsShellArgument(
+ flag.c_str(),
+ cmOutputConverter::Shell_Flag_AllowMakeVariables |
+ cmOutputConverter::Shell_Flag_VSIDE);
+ this->AppendFlagString(this->UnknownFlagField, opts);
+}
+
+cmIDEOptions::FlagValue cmVisualStudioGeneratorOptions::TakeFlag(
+ std::string const& key)
+{
+ FlagValue value;
+ std::map<std::string, FlagValue>::iterator i = this->FlagMap.find(key);
+ if (i != this->FlagMap.end()) {
+ value = i->second;
+ this->FlagMap.erase(i);
+ }
+ return value;
+}
+
+void cmVisualStudioGeneratorOptions::SetConfiguration(
+ const std::string& config)
+{
+ this->Configuration = config;
+}
+
+const std::string& cmVisualStudioGeneratorOptions::GetConfiguration() const
+{
+ return this->Configuration;
+}
+
+void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions(
+ std::ostream& fout, int indent, const std::string& lang)
+{
+ if (this->Defines.empty()) {
+ return;
+ }
+ std::string tag = "PreprocessorDefinitions";
+ if (lang == "CUDA") {
+ tag = "Defines";
+ }
+
+ std::ostringstream oss;
+ const char* sep = "";
+ std::vector<std::string>::const_iterator de =
+ cmRemoveDuplicates(this->Defines);
+ for (std::string const& di : cmMakeRange(this->Defines.cbegin(), de)) {
+ // Escape the definition for the compiler.
+ std::string define;
+ if (this->Version < cmGlobalVisualStudioGenerator::VS10) {
+ define = this->LocalGenerator->EscapeForShell(di, true);
+ } else {
+ define = di;
+ }
+ // Escape this flag for the MSBuild.
+ if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
+ cmVS10EscapeForMSBuild(define);
+ if (lang == "RC") {
+ cmSystemTools::ReplaceString(define, "\"", "\\\"");
+ }
+ }
+ // Store the flag in the project file.
+ oss << sep << define;
+ sep = ";";
+ }
+ if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
+ oss << ";%(" << tag << ")";
+ }
+
+ this->OutputFlag(fout, indent, tag, oss.str());
+}
+
+void cmVisualStudioGeneratorOptions::OutputAdditionalIncludeDirectories(
+ std::ostream& fout, int indent, const std::string& lang)
+{
+ if (this->Includes.empty()) {
+ return;
+ }
+
+ std::string tag = "AdditionalIncludeDirectories";
+ if (lang == "CUDA") {
+ tag = "Include";
+ } else if (lang == "ASM_MASM" || lang == "ASM_NASM") {
+ tag = "IncludePaths";
+ }
+
+ std::ostringstream oss;
+ const char* sep = "";
+ for (std::string include : this->Includes) {
+ // first convert all of the slashes
+ std::string::size_type pos = 0;
+ while ((pos = include.find('/', pos)) != std::string::npos) {
+ include[pos] = '\\';
+ pos++;
+ }
+
+ if (lang == "ASM_NASM") {
+ include += "\\";
+ }
+
+ // Escape this include for the MSBuild.
+ if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
+ cmVS10EscapeForMSBuild(include);
+ }
+ oss << sep << include;
+ sep = ";";
+
+ if (lang == "Fortran") {
+ include += "/$(ConfigurationName)";
+ oss << sep << include;
+ }
+ }
+
+ if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
+ oss << sep << "%(" << tag << ")";
+ }
+
+ this->OutputFlag(fout, indent, tag, oss.str());
+}
+
+void cmVisualStudioGeneratorOptions::OutputFlagMap(std::ostream& fout,
+ int indent)
+{
+ for (auto const& m : this->FlagMap) {
+ std::ostringstream oss;
+ const char* sep = "";
+ for (std::string i : m.second) {
+ if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
+ cmVS10EscapeForMSBuild(i);
+ }
+ oss << sep << i;
+ sep = ";";
+ }
+
+ this->OutputFlag(fout, indent, m.first, oss.str());
+ }
+}
diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h
new file mode 100644
index 0000000..b123019
--- /dev/null
+++ b/Source/cmVisualStudioGeneratorOptions.h
@@ -0,0 +1,101 @@
+/* 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 <iosfwd>
+#include <string>
+
+#include "cmGlobalVisualStudioGenerator.h"
+#include "cmIDEFlagTable.h"
+#include "cmIDEOptions.h"
+
+class cmLocalVisualStudioGenerator;
+class cmGeneratorTarget;
+
+using cmVS7FlagTable = cmIDEFlagTable;
+
+class cmVisualStudioGeneratorOptions : public cmIDEOptions
+{
+public:
+ // Construct an options table for a given tool.
+ enum Tool
+ {
+ Compiler,
+ ResourceCompiler,
+ CudaCompiler,
+ MasmCompiler,
+ NasmCompiler,
+ Linker,
+ FortranCompiler,
+ CSharpCompiler
+ };
+ cmVisualStudioGeneratorOptions(cmLocalVisualStudioGenerator* lg, Tool tool,
+ cmVS7FlagTable const* table = nullptr,
+ cmVS7FlagTable const* extraTable = nullptr);
+
+ // Add a table of flags.
+ void AddTable(cmVS7FlagTable const* table);
+
+ // Clear the flag tables.
+ void ClearTables();
+
+ // Store options from command line flags.
+ void Parse(const std::string& flags);
+ void ParseFinish();
+
+ void PrependInheritedString(std::string const& key);
+
+ // Parse the content of the given flag table entry again to extract
+ // known flags and leave the rest in the original entry.
+ void Reparse(std::string const& key);
+
+ // Fix the ExceptionHandling option to default to off.
+ void FixExceptionHandlingDefault();
+
+ // Store options for verbose builds.
+ void SetVerboseMakefile(bool verbose);
+
+ // Check for specific options.
+ bool UsingUnicode() const;
+ bool UsingSBCS() const;
+
+ void FixCudaCodeGeneration();
+
+ void FixManifestUACFlags();
+
+ bool IsDebug() const;
+ bool IsWinRt() const;
+ bool IsManaged() const;
+ // Write options to output.
+ void OutputPreprocessorDefinitions(std::ostream& fout, int indent,
+ const std::string& lang);
+ void OutputAdditionalIncludeDirectories(std::ostream& fout, int indent,
+ const std::string& lang);
+ void OutputFlagMap(std::ostream& fout, int indent);
+ void SetConfiguration(const std::string& config);
+ const std::string& GetConfiguration() const;
+
+protected:
+ virtual void OutputFlag(std::ostream& fout, int indent,
+ const std::string& tag,
+ const std::string& content) = 0;
+
+private:
+ cmLocalVisualStudioGenerator* LocalGenerator;
+ cmGlobalVisualStudioGenerator::VSVersion Version;
+
+ std::string Configuration;
+ Tool CurrentTool;
+
+ bool FortranRuntimeDebug;
+ bool FortranRuntimeDLL;
+ bool FortranRuntimeMT;
+
+ std::string UnknownFlagField;
+
+ void StoreUnknownFlag(std::string const& flag) override;
+
+ FlagValue TakeFlag(std::string const& key);
+};
diff --git a/Source/cmVisualStudioSlnData.cxx b/Source/cmVisualStudioSlnData.cxx
new file mode 100644
index 0000000..48112dd
--- /dev/null
+++ b/Source/cmVisualStudioSlnData.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 "cmVisualStudioSlnData.h"
+
+const cmSlnProjectEntry* cmSlnData::GetProjectByGUID(
+ const std::string& projectGUID) const
+{
+ ProjectStorage::const_iterator it(ProjectsByGUID.find(projectGUID));
+ if (it != ProjectsByGUID.end())
+ return &it->second;
+ else
+ return NULL;
+}
+
+const cmSlnProjectEntry* cmSlnData::GetProjectByName(
+ const std::string& projectName) const
+{
+ ProjectStringIndex::const_iterator it(ProjectNameIndex.find(projectName));
+ if (it != ProjectNameIndex.end())
+ return &it->second->second;
+ else
+ return NULL;
+}
+
+std::vector<cmSlnProjectEntry> cmSlnData::GetProjects() const
+{
+ ProjectStringIndex::const_iterator it(this->ProjectNameIndex.begin()),
+ itEnd(this->ProjectNameIndex.end());
+ std::vector<cmSlnProjectEntry> result;
+ for (; it != itEnd; ++it)
+ result.push_back(it->second->second);
+ return result;
+}
+
+cmSlnProjectEntry* cmSlnData::AddProject(
+ const std::string& projectGUID, const std::string& projectName,
+ const std::string& projectRelativePath)
+{
+ ProjectStorage::iterator it(ProjectsByGUID.find(projectGUID));
+ if (it != ProjectsByGUID.end())
+ return NULL;
+ it = ProjectsByGUID
+ .insert(ProjectStorage::value_type(
+ projectGUID,
+ cmSlnProjectEntry(projectGUID, projectName, projectRelativePath)))
+ .first;
+ ProjectNameIndex[projectName] = it;
+ return &it->second;
+}
diff --git a/Source/cmVisualStudioSlnData.h b/Source/cmVisualStudioSlnData.h
new file mode 100644
index 0000000..b217bd8
--- /dev/null
+++ b/Source/cmVisualStudioSlnData.h
@@ -0,0 +1,51 @@
+/* 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 <map>
+#include <string>
+#include <vector>
+
+class cmSlnProjectEntry
+{
+public:
+ cmSlnProjectEntry() {}
+ cmSlnProjectEntry(const std::string& guid, const std::string& name,
+ const std::string& relativePath)
+ : Guid(guid)
+ , Name(name)
+ , RelativePath(relativePath)
+ {
+ }
+
+ std::string GetGUID() const { return Guid; }
+ std::string GetName() const { return Name; }
+ std::string GetRelativePath() const { return RelativePath; }
+
+private:
+ std::string Guid, Name, RelativePath;
+};
+
+class cmSlnData
+{
+public:
+ const cmSlnProjectEntry* GetProjectByGUID(
+ const std::string& projectGUID) const;
+
+ const cmSlnProjectEntry* GetProjectByName(
+ const std::string& projectName) const;
+
+ std::vector<cmSlnProjectEntry> GetProjects() const;
+
+ cmSlnProjectEntry* AddProject(const std::string& projectGUID,
+ const std::string& projectName,
+ const std::string& projectRelativePath);
+
+private:
+ using ProjectStorage = std::map<std::string, cmSlnProjectEntry>;
+ ProjectStorage ProjectsByGUID;
+ using ProjectStringIndex = std::map<std::string, ProjectStorage::iterator>;
+ ProjectStringIndex ProjectNameIndex;
+};
diff --git a/Source/cmVisualStudioSlnParser.cxx b/Source/cmVisualStudioSlnParser.cxx
new file mode 100644
index 0000000..d7822b1
--- /dev/null
+++ b/Source/cmVisualStudioSlnParser.cxx
@@ -0,0 +1,629 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmVisualStudioSlnParser.h"
+
+#include <cassert>
+#include <stack>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmVisualStudioSlnData.h"
+
+namespace {
+enum LineFormat
+{
+ LineMultiValueTag,
+ LineSingleValueTag,
+ LineKeyValuePair,
+ LineVerbatim
+};
+}
+
+class cmVisualStudioSlnParser::ParsedLine
+{
+public:
+ bool IsComment() const;
+ bool IsKeyValuePair() const;
+
+ const std::string& GetTag() const { return this->Tag; }
+ const std::string& GetArg() const { return this->Arg.first; }
+ std::string GetArgVerbatim() const;
+ size_t GetValueCount() const { return this->Values.size(); }
+ const std::string& GetValue(size_t idxValue) const;
+ std::string GetValueVerbatim(size_t idxValue) const;
+
+ void SetTag(const std::string& tag) { this->Tag = tag; }
+ void SetArg(const std::string& arg) { this->Arg = StringData(arg, false); }
+ void SetQuotedArg(const std::string& arg)
+ {
+ this->Arg = StringData(arg, true);
+ }
+ void AddValue(const std::string& value)
+ {
+ this->Values.push_back(StringData(value, false));
+ }
+ void AddQuotedValue(const std::string& value)
+ {
+ this->Values.push_back(StringData(value, true));
+ }
+
+ void CopyVerbatim(const std::string& line) { this->Tag = line; }
+
+private:
+ using StringData = std::pair<std::string, bool>;
+ std::string Tag;
+ StringData Arg;
+ std::vector<StringData> Values;
+ static const std::string BadString;
+ static const std::string Quote;
+};
+
+const std::string cmVisualStudioSlnParser::ParsedLine::BadString;
+const std::string cmVisualStudioSlnParser::ParsedLine::Quote("\"");
+
+bool cmVisualStudioSlnParser::ParsedLine::IsComment() const
+{
+ assert(!this->Tag.empty());
+ return (this->Tag[0] == '#');
+}
+
+bool cmVisualStudioSlnParser::ParsedLine::IsKeyValuePair() const
+{
+ assert(!this->Tag.empty());
+ return this->Arg.first.empty() && this->Values.size() == 1;
+}
+
+std::string cmVisualStudioSlnParser::ParsedLine::GetArgVerbatim() const
+{
+ if (this->Arg.second)
+ return Quote + this->Arg.first + Quote;
+ else
+ return this->Arg.first;
+}
+
+const std::string& cmVisualStudioSlnParser::ParsedLine::GetValue(
+ size_t idxValue) const
+{
+ if (idxValue < this->Values.size())
+ return this->Values[idxValue].first;
+ else
+ return BadString;
+}
+
+std::string cmVisualStudioSlnParser::ParsedLine::GetValueVerbatim(
+ size_t idxValue) const
+{
+ if (idxValue < this->Values.size()) {
+ const StringData& data = this->Values[idxValue];
+ if (data.second)
+ return Quote + data.first + Quote;
+ else
+ return data.first;
+ } else
+ return BadString;
+}
+
+class cmVisualStudioSlnParser::State
+{
+public:
+ explicit State(DataGroupSet requestedData);
+
+ size_t GetCurrentLine() const { return this->CurrentLine; }
+ bool ReadLine(std::istream& input, std::string& line);
+
+ LineFormat NextLineFormat() const;
+
+ bool Process(const cmVisualStudioSlnParser::ParsedLine& line,
+ cmSlnData& output, cmVisualStudioSlnParser::ResultData& result);
+
+ bool Finished(cmVisualStudioSlnParser::ResultData& result);
+
+private:
+ enum FileState
+ {
+ FileStateStart,
+ FileStateTopLevel,
+ FileStateProject,
+ FileStateProjectDependencies,
+ FileStateGlobal,
+ FileStateSolutionConfigurations,
+ FileStateProjectConfigurations,
+ FileStateSolutionFilters,
+ FileStateGlobalSection,
+ FileStateIgnore
+ };
+ std::stack<FileState> Stack;
+ std::string EndIgnoreTag;
+ DataGroupSet RequestedData;
+ size_t CurrentLine;
+
+ void IgnoreUntilTag(const std::string& endTag);
+};
+
+cmVisualStudioSlnParser::State::State(DataGroupSet requestedData)
+ : RequestedData(requestedData)
+ , CurrentLine(0)
+{
+ if (this->RequestedData.test(DataGroupProjectDependenciesBit))
+ this->RequestedData.set(DataGroupProjectsBit);
+ this->Stack.push(FileStateStart);
+}
+
+bool cmVisualStudioSlnParser::State::ReadLine(std::istream& input,
+ std::string& line)
+{
+ ++this->CurrentLine;
+ return !std::getline(input, line).fail();
+}
+
+LineFormat cmVisualStudioSlnParser::State::NextLineFormat() const
+{
+ switch (this->Stack.top()) {
+ case FileStateStart:
+ return LineVerbatim;
+ case FileStateTopLevel:
+ return LineMultiValueTag;
+ case FileStateProject:
+ return LineSingleValueTag;
+ case FileStateProjectDependencies:
+ return LineKeyValuePair;
+ case FileStateGlobal:
+ return LineSingleValueTag;
+ case FileStateSolutionConfigurations:
+ return LineKeyValuePair;
+ case FileStateProjectConfigurations:
+ return LineKeyValuePair;
+ case FileStateSolutionFilters:
+ return LineKeyValuePair;
+ case FileStateGlobalSection:
+ return LineKeyValuePair;
+ case FileStateIgnore:
+ return LineVerbatim;
+ default:
+ assert(false);
+ return LineVerbatim;
+ }
+}
+
+bool cmVisualStudioSlnParser::State::Process(
+ const cmVisualStudioSlnParser::ParsedLine& line, cmSlnData& output,
+ cmVisualStudioSlnParser::ResultData& result)
+{
+ assert(!line.IsComment());
+ switch (this->Stack.top()) {
+ case FileStateStart:
+ if (!cmHasLiteralPrefix(line.GetTag(),
+ "Microsoft Visual Studio Solution File")) {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ this->Stack.pop();
+ this->Stack.push(FileStateTopLevel);
+ break;
+ case FileStateTopLevel:
+ if (line.GetTag().compare("Project") == 0) {
+ if (line.GetValueCount() != 3) {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ if (this->RequestedData.test(DataGroupProjectsBit)) {
+ if (!output.AddProject(line.GetValue(2), line.GetValue(0),
+ line.GetValue(1))) {
+ result.SetError(ResultErrorInputData, this->GetCurrentLine());
+ return false;
+ }
+ this->Stack.push(FileStateProject);
+ } else
+ this->IgnoreUntilTag("EndProject");
+ } else if (line.GetTag().compare("Global") == 0)
+ this->Stack.push(FileStateGlobal);
+ else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateProject:
+ if (line.GetTag().compare("EndProject") == 0)
+ this->Stack.pop();
+ else if (line.GetTag().compare("ProjectSection") == 0) {
+ if (line.GetArg().compare("ProjectDependencies") == 0 &&
+ line.GetValue(0).compare("postProject") == 0) {
+ if (this->RequestedData.test(DataGroupProjectDependenciesBit))
+ this->Stack.push(FileStateProjectDependencies);
+ else
+ this->IgnoreUntilTag("EndProjectSection");
+ } else
+ this->IgnoreUntilTag("EndProjectSection");
+ } else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateProjectDependencies:
+ if (line.GetTag().compare("EndProjectSection") == 0)
+ this->Stack.pop();
+ else if (line.IsKeyValuePair())
+ // implement dependency storing here, once needed
+ ;
+ else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateGlobal:
+ if (line.GetTag().compare("EndGlobal") == 0)
+ this->Stack.pop();
+ else if (line.GetTag().compare("GlobalSection") == 0) {
+ if (line.GetArg().compare("SolutionConfigurationPlatforms") == 0 &&
+ line.GetValue(0).compare("preSolution") == 0) {
+ if (this->RequestedData.test(DataGroupSolutionConfigurationsBit))
+ this->Stack.push(FileStateSolutionConfigurations);
+ else
+ this->IgnoreUntilTag("EndGlobalSection");
+ } else if (line.GetArg().compare("ProjectConfigurationPlatforms") ==
+ 0 &&
+ line.GetValue(0).compare("postSolution") == 0) {
+ if (this->RequestedData.test(DataGroupProjectConfigurationsBit))
+ this->Stack.push(FileStateProjectConfigurations);
+ else
+ this->IgnoreUntilTag("EndGlobalSection");
+ } else if (line.GetArg().compare("NestedProjects") == 0 &&
+ line.GetValue(0).compare("preSolution") == 0) {
+ if (this->RequestedData.test(DataGroupSolutionFiltersBit))
+ this->Stack.push(FileStateSolutionFilters);
+ else
+ this->IgnoreUntilTag("EndGlobalSection");
+ } else if (this->RequestedData.test(DataGroupGenericGlobalSectionsBit))
+ this->Stack.push(FileStateGlobalSection);
+ else
+ this->IgnoreUntilTag("EndGlobalSection");
+ } else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateSolutionConfigurations:
+ if (line.GetTag().compare("EndGlobalSection") == 0)
+ this->Stack.pop();
+ else if (line.IsKeyValuePair())
+ // implement configuration storing here, once needed
+ ;
+ else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateProjectConfigurations:
+ if (line.GetTag().compare("EndGlobalSection") == 0)
+ this->Stack.pop();
+ else if (line.IsKeyValuePair())
+ // implement configuration storing here, once needed
+ ;
+ else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateSolutionFilters:
+ if (line.GetTag().compare("EndGlobalSection") == 0)
+ this->Stack.pop();
+ else if (line.IsKeyValuePair())
+ // implement filter storing here, once needed
+ ;
+ else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateGlobalSection:
+ if (line.GetTag().compare("EndGlobalSection") == 0)
+ this->Stack.pop();
+ else if (line.IsKeyValuePair())
+ // implement section storing here, once needed
+ ;
+ else {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ break;
+ case FileStateIgnore:
+ if (line.GetTag() == this->EndIgnoreTag) {
+ this->Stack.pop();
+ this->EndIgnoreTag.clear();
+ }
+ break;
+ default:
+ result.SetError(ResultErrorBadInternalState, this->GetCurrentLine());
+ return false;
+ }
+ return true;
+}
+
+bool cmVisualStudioSlnParser::State::Finished(
+ cmVisualStudioSlnParser::ResultData& result)
+{
+ if (this->Stack.top() != FileStateTopLevel) {
+ result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
+ return false;
+ }
+ result.Result = ResultOK;
+ return true;
+}
+
+void cmVisualStudioSlnParser::State::IgnoreUntilTag(const std::string& endTag)
+{
+ this->Stack.push(FileStateIgnore);
+ this->EndIgnoreTag = endTag;
+}
+
+cmVisualStudioSlnParser::ResultData::ResultData()
+ : Result(ResultOK)
+ , ResultLine(0)
+{
+}
+
+void cmVisualStudioSlnParser::ResultData::Clear()
+{
+ *this = ResultData();
+}
+
+void cmVisualStudioSlnParser::ResultData::SetError(ParseResult error,
+ size_t line)
+{
+ this->Result = error;
+ this->ResultLine = line;
+}
+
+const cmVisualStudioSlnParser::DataGroupSet
+ cmVisualStudioSlnParser::DataGroupProjects(
+ 1 << cmVisualStudioSlnParser::DataGroupProjectsBit);
+
+const cmVisualStudioSlnParser::DataGroupSet
+ cmVisualStudioSlnParser::DataGroupProjectDependencies(
+ 1 << cmVisualStudioSlnParser::DataGroupProjectDependenciesBit);
+
+const cmVisualStudioSlnParser::DataGroupSet
+ cmVisualStudioSlnParser::DataGroupSolutionConfigurations(
+ 1 << cmVisualStudioSlnParser::DataGroupSolutionConfigurationsBit);
+
+const cmVisualStudioSlnParser::DataGroupSet
+ cmVisualStudioSlnParser::DataGroupProjectConfigurations(
+ 1 << cmVisualStudioSlnParser::DataGroupProjectConfigurationsBit);
+
+const cmVisualStudioSlnParser::DataGroupSet
+ cmVisualStudioSlnParser::DataGroupSolutionFilters(
+ 1 << cmVisualStudioSlnParser::DataGroupSolutionFiltersBit);
+
+const cmVisualStudioSlnParser::DataGroupSet
+ cmVisualStudioSlnParser::DataGroupGenericGlobalSections(
+ 1 << cmVisualStudioSlnParser::DataGroupGenericGlobalSectionsBit);
+
+const cmVisualStudioSlnParser::DataGroupSet
+ cmVisualStudioSlnParser::DataGroupAll(~0);
+
+bool cmVisualStudioSlnParser::Parse(std::istream& input, cmSlnData& output,
+ DataGroupSet dataGroups)
+{
+ this->LastResult.Clear();
+ if (!this->IsDataGroupSetSupported(dataGroups)) {
+ this->LastResult.SetError(ResultErrorUnsupportedDataGroup, 0);
+ return false;
+ }
+ State state(dataGroups);
+ return this->ParseImpl(input, output, state);
+}
+
+bool cmVisualStudioSlnParser::ParseFile(const std::string& file,
+ cmSlnData& output,
+ DataGroupSet dataGroups)
+{
+ this->LastResult.Clear();
+ if (!this->IsDataGroupSetSupported(dataGroups)) {
+ this->LastResult.SetError(ResultErrorUnsupportedDataGroup, 0);
+ return false;
+ }
+ cmsys::ifstream f(file.c_str());
+ if (!f) {
+ this->LastResult.SetError(ResultErrorOpeningInput, 0);
+ return false;
+ }
+ State state(dataGroups);
+ return this->ParseImpl(f, output, state);
+}
+
+cmVisualStudioSlnParser::ParseResult cmVisualStudioSlnParser::GetParseResult()
+ const
+{
+ return this->LastResult.Result;
+}
+
+size_t cmVisualStudioSlnParser::GetParseResultLine() const
+{
+ return this->LastResult.ResultLine;
+}
+
+bool cmVisualStudioSlnParser::GetParseHadBOM() const
+{
+ return this->LastResult.HadBOM;
+}
+
+bool cmVisualStudioSlnParser::IsDataGroupSetSupported(
+ DataGroupSet dataGroups) const
+{
+ return (dataGroups & DataGroupProjects) == dataGroups;
+ // only supporting DataGroupProjects for now
+}
+
+bool cmVisualStudioSlnParser::ParseImpl(std::istream& input, cmSlnData& output,
+ State& state)
+{
+ std::string line;
+ // Does the .sln start with a Byte Order Mark?
+ if (!this->ParseBOM(input, line, state))
+ return false;
+ do {
+ line = cmTrimWhitespace(line);
+ if (line.empty())
+ continue;
+ ParsedLine parsedLine;
+ switch (state.NextLineFormat()) {
+ case LineMultiValueTag:
+ if (!this->ParseMultiValueTag(line, parsedLine, state))
+ return false;
+ break;
+ case LineSingleValueTag:
+ if (!this->ParseSingleValueTag(line, parsedLine, state))
+ return false;
+ break;
+ case LineKeyValuePair:
+ if (!this->ParseKeyValuePair(line, parsedLine, state))
+ return false;
+ break;
+ case LineVerbatim:
+ parsedLine.CopyVerbatim(line);
+ break;
+ }
+ if (parsedLine.IsComment())
+ continue;
+ if (!state.Process(parsedLine, output, this->LastResult))
+ return false;
+ } while (state.ReadLine(input, line));
+ return state.Finished(this->LastResult);
+}
+
+bool cmVisualStudioSlnParser::ParseBOM(std::istream& input, std::string& line,
+ State& state)
+{
+ char bom[4];
+ if (!input.get(bom, 4)) {
+ this->LastResult.SetError(ResultErrorReadingInput, 1);
+ return false;
+ }
+ this->LastResult.HadBOM =
+ (bom[0] == char(0xEF) && bom[1] == char(0xBB) && bom[2] == char(0xBF));
+ if (!state.ReadLine(input, line)) {
+ this->LastResult.SetError(ResultErrorReadingInput, 1);
+ return false;
+ }
+ if (!this->LastResult.HadBOM)
+ line = bom + line; // it wasn't a BOM, prepend it to first line
+ return true;
+}
+
+bool cmVisualStudioSlnParser::ParseMultiValueTag(const std::string& line,
+ ParsedLine& parsedLine,
+ State& state)
+{
+ size_t idxEqualSign = line.find('=');
+ auto fullTag = cm::string_view(line).substr(0, idxEqualSign);
+ if (!this->ParseTag(fullTag, parsedLine, state))
+ return false;
+ if (idxEqualSign != line.npos) {
+ size_t idxFieldStart = idxEqualSign + 1;
+ if (idxFieldStart < line.size()) {
+ size_t idxParsing = idxFieldStart;
+ bool inQuotes = false;
+ for (;;) {
+ idxParsing = line.find_first_of(",\"", idxParsing);
+ bool fieldOver = false;
+ if (idxParsing == line.npos) {
+ fieldOver = true;
+ if (inQuotes) {
+ this->LastResult.SetError(ResultErrorInputStructure,
+ state.GetCurrentLine());
+ return false;
+ }
+ } else if (line[idxParsing] == ',' && !inQuotes)
+ fieldOver = true;
+ else if (line[idxParsing] == '"')
+ inQuotes = !inQuotes;
+ if (fieldOver) {
+ if (!this->ParseValue(
+ line.substr(idxFieldStart, idxParsing - idxFieldStart),
+ parsedLine))
+ return false;
+ if (idxParsing == line.npos)
+ break; // end of last field
+ idxFieldStart = idxParsing + 1;
+ }
+ ++idxParsing;
+ }
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudioSlnParser::ParseSingleValueTag(const std::string& line,
+ ParsedLine& parsedLine,
+ State& state)
+{
+ size_t idxEqualSign = line.find('=');
+ auto fullTag = cm::string_view(line).substr(0, idxEqualSign);
+ if (!this->ParseTag(fullTag, parsedLine, state))
+ return false;
+ if (idxEqualSign != line.npos) {
+ if (!this->ParseValue(line.substr(idxEqualSign + 1), parsedLine))
+ return false;
+ }
+ return true;
+}
+
+bool cmVisualStudioSlnParser::ParseKeyValuePair(const std::string& line,
+ ParsedLine& parsedLine,
+ State& /*state*/)
+{
+ size_t idxEqualSign = line.find('=');
+ if (idxEqualSign == line.npos) {
+ parsedLine.CopyVerbatim(line);
+ return true;
+ }
+ const std::string& key = line.substr(0, idxEqualSign);
+ parsedLine.SetTag(cmTrimWhitespace(key));
+ const std::string& value = line.substr(idxEqualSign + 1);
+ parsedLine.AddValue(cmTrimWhitespace(value));
+ return true;
+}
+
+bool cmVisualStudioSlnParser::ParseTag(cm::string_view fullTag,
+ ParsedLine& parsedLine, State& state)
+{
+ size_t idxLeftParen = fullTag.find('(');
+ if (idxLeftParen == cm::string_view::npos) {
+ parsedLine.SetTag(cmTrimWhitespace(fullTag));
+ return true;
+ }
+ parsedLine.SetTag(cmTrimWhitespace(fullTag.substr(0, idxLeftParen)));
+ size_t idxRightParen = fullTag.rfind(')');
+ if (idxRightParen == cm::string_view::npos) {
+ this->LastResult.SetError(ResultErrorInputStructure,
+ state.GetCurrentLine());
+ return false;
+ }
+ const std::string& arg = cmTrimWhitespace(
+ fullTag.substr(idxLeftParen + 1, idxRightParen - idxLeftParen - 1));
+ if (arg.front() == '"') {
+ if (arg.back() != '"') {
+ this->LastResult.SetError(ResultErrorInputStructure,
+ state.GetCurrentLine());
+ return false;
+ }
+ parsedLine.SetQuotedArg(arg.substr(1, arg.size() - 2));
+ } else
+ parsedLine.SetArg(arg);
+ return true;
+}
+
+bool cmVisualStudioSlnParser::ParseValue(const std::string& value,
+ ParsedLine& parsedLine)
+{
+ const std::string& trimmed = cmTrimWhitespace(value);
+ if (trimmed.empty())
+ parsedLine.AddValue(trimmed);
+ else if (trimmed.front() == '"' && trimmed.back() == '"')
+ parsedLine.AddQuotedValue(trimmed.substr(1, trimmed.size() - 2));
+ else
+ parsedLine.AddValue(trimmed);
+ return true;
+}
diff --git a/Source/cmVisualStudioSlnParser.h b/Source/cmVisualStudioSlnParser.h
new file mode 100644
index 0000000..1c33759
--- /dev/null
+++ b/Source/cmVisualStudioSlnParser.h
@@ -0,0 +1,104 @@
+/* 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 <bitset>
+#include <iosfwd>
+#include <string>
+
+#include <cm/string_view>
+
+#include <stddef.h>
+
+class cmSlnData;
+
+class cmVisualStudioSlnParser
+{
+public:
+ enum ParseResult
+ {
+ ResultOK = 0,
+
+ ResultInternalError = -1,
+ ResultExternalError = 1,
+
+ ResultErrorOpeningInput = ResultExternalError,
+ ResultErrorReadingInput,
+ ResultErrorInputStructure,
+ ResultErrorInputData,
+
+ ResultErrorBadInternalState = ResultInternalError,
+ ResultErrorUnsupportedDataGroup = ResultInternalError - 1
+ };
+
+ enum DataGroup
+ {
+ DataGroupProjectsBit,
+ DataGroupProjectDependenciesBit,
+ DataGroupSolutionConfigurationsBit,
+ DataGroupProjectConfigurationsBit,
+ DataGroupSolutionFiltersBit,
+ DataGroupGenericGlobalSectionsBit,
+ DataGroupCount
+ };
+
+ using DataGroupSet = std::bitset<DataGroupCount>;
+
+ static const DataGroupSet DataGroupProjects;
+ static const DataGroupSet DataGroupProjectDependencies;
+ static const DataGroupSet DataGroupSolutionConfigurations;
+ static const DataGroupSet DataGroupProjectConfigurations;
+ static const DataGroupSet DataGroupSolutionFilters;
+ static const DataGroupSet DataGroupGenericGlobalSections;
+ static const DataGroupSet DataGroupAll;
+
+ bool Parse(std::istream& input, cmSlnData& output,
+ DataGroupSet dataGroups = DataGroupAll);
+
+ bool ParseFile(const std::string& file, cmSlnData& output,
+ DataGroupSet dataGroups = DataGroupAll);
+
+ ParseResult GetParseResult() const;
+
+ size_t GetParseResultLine() const;
+
+ bool GetParseHadBOM() const;
+
+protected:
+ class State;
+
+ friend class State;
+ class ParsedLine;
+
+ struct ResultData
+ {
+ ParseResult Result;
+ size_t ResultLine;
+ bool HadBOM;
+
+ ResultData();
+ void Clear();
+ void SetError(ParseResult error, size_t line);
+ } LastResult;
+
+ bool IsDataGroupSetSupported(DataGroupSet dataGroups) const;
+
+ bool ParseImpl(std::istream& input, cmSlnData& output, State& state);
+
+ bool ParseBOM(std::istream& input, std::string& line, State& state);
+
+ bool ParseMultiValueTag(const std::string& line, ParsedLine& parsedLine,
+ State& state);
+
+ bool ParseSingleValueTag(const std::string& line, ParsedLine& parsedLine,
+ State& state);
+
+ bool ParseKeyValuePair(const std::string& line, ParsedLine& parsedLine,
+ State& state);
+
+ bool ParseTag(cm::string_view fullTag, ParsedLine& parsedLine, State& state);
+
+ bool ParseValue(const std::string& value, ParsedLine& parsedLine);
+};
diff --git a/Source/cmVisualStudioWCEPlatformParser.cxx b/Source/cmVisualStudioWCEPlatformParser.cxx
new file mode 100644
index 0000000..3b113aa
--- /dev/null
+++ b/Source/cmVisualStudioWCEPlatformParser.cxx
@@ -0,0 +1,139 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmVisualStudioWCEPlatformParser.h"
+
+#include "cmGlobalVisualStudioGenerator.h"
+#include "cmXMLParser.h"
+
+int cmVisualStudioWCEPlatformParser::ParseVersion(const char* version)
+{
+ const std::string registryBase =
+ cmGlobalVisualStudioGenerator::GetRegistryBase(version);
+ const std::string vckey = registryBase + "\\Setup\\VC;ProductDir";
+ const std::string vskey = registryBase + "\\Setup\\VS;ProductDir";
+
+ if (!cmSystemTools::ReadRegistryValue(vckey.c_str(), this->VcInstallDir,
+ cmSystemTools::KeyWOW64_32) ||
+ !cmSystemTools::ReadRegistryValue(vskey.c_str(), this->VsInstallDir,
+ cmSystemTools::KeyWOW64_32)) {
+ return 0;
+ }
+ cmSystemTools::ConvertToUnixSlashes(this->VcInstallDir);
+ cmSystemTools::ConvertToUnixSlashes(this->VsInstallDir);
+ this->VcInstallDir.append("/");
+ this->VsInstallDir.append("/");
+
+ const std::string configFilename =
+ this->VcInstallDir + "vcpackages/WCE.VCPlatform.config";
+
+ return this->ParseFile(configFilename.c_str());
+}
+
+std::string cmVisualStudioWCEPlatformParser::GetOSVersion() const
+{
+ if (this->OSMinorVersion.empty()) {
+ return OSMajorVersion;
+ }
+
+ return OSMajorVersion + "." + OSMinorVersion;
+}
+
+const char* cmVisualStudioWCEPlatformParser::GetArchitectureFamily() const
+{
+ std::map<std::string, std::string>::const_iterator it =
+ this->Macros.find("ARCHFAM");
+ if (it != this->Macros.end()) {
+ return it->second.c_str();
+ }
+
+ return 0;
+}
+
+void cmVisualStudioWCEPlatformParser::StartElement(const std::string& name,
+ const char** attributes)
+{
+ if (this->FoundRequiredName) {
+ return;
+ }
+
+ this->CharacterData.clear();
+
+ if (name == "PlatformData") {
+ this->PlatformName.clear();
+ this->OSMajorVersion.clear();
+ this->OSMinorVersion.clear();
+ this->Macros.clear();
+ }
+
+ if (name == "Macro") {
+ std::string macroName;
+ std::string macroValue;
+
+ for (const char** attr = attributes; *attr; attr += 2) {
+ if (strcmp(attr[0], "Name") == 0) {
+ macroName = attr[1];
+ } else if (strcmp(attr[0], "Value") == 0) {
+ macroValue = attr[1];
+ }
+ }
+
+ if (!macroName.empty()) {
+ this->Macros[macroName] = macroValue;
+ }
+ } else if (name == "Directories") {
+ for (const char** attr = attributes; *attr; attr += 2) {
+ if (strcmp(attr[0], "Include") == 0) {
+ this->Include = attr[1];
+ } else if (strcmp(attr[0], "Library") == 0) {
+ this->Library = attr[1];
+ } else if (strcmp(attr[0], "Path") == 0) {
+ this->Path = attr[1];
+ }
+ }
+ }
+}
+
+void cmVisualStudioWCEPlatformParser::EndElement(const std::string& name)
+{
+ if (!this->RequiredName) {
+ if (name == "PlatformName") {
+ this->AvailablePlatforms.push_back(this->CharacterData);
+ }
+ return;
+ }
+
+ if (this->FoundRequiredName) {
+ return;
+ }
+
+ if (name == "PlatformName") {
+ this->PlatformName = this->CharacterData;
+ } else if (name == "OSMajorVersion") {
+ this->OSMajorVersion = this->CharacterData;
+ } else if (name == "OSMinorVersion") {
+ this->OSMinorVersion = this->CharacterData;
+ } else if (name == "Platform") {
+ if (this->PlatformName == this->RequiredName) {
+ this->FoundRequiredName = true;
+ }
+ }
+}
+
+void cmVisualStudioWCEPlatformParser::CharacterDataHandler(const char* data,
+ int length)
+{
+ this->CharacterData.append(data, length);
+}
+
+std::string cmVisualStudioWCEPlatformParser::FixPaths(
+ const std::string& paths) const
+{
+ std::string ret = paths;
+ cmSystemTools::ReplaceString(ret, "$(PATH)", "%PATH%");
+ cmSystemTools::ReplaceString(ret, "$(VCInstallDir)", VcInstallDir.c_str());
+ cmSystemTools::ReplaceString(ret, "$(VSInstallDir)", VsInstallDir.c_str());
+ std::replace(ret.begin(), ret.end(), '\\', '/');
+ cmSystemTools::ReplaceString(ret, "//", "/");
+ std::replace(ret.begin(), ret.end(), '/', '\\');
+ return ret;
+}
diff --git a/Source/cmVisualStudioWCEPlatformParser.h b/Source/cmVisualStudioWCEPlatformParser.h
new file mode 100644
index 0000000..eb4e978
--- /dev/null
+++ b/Source/cmVisualStudioWCEPlatformParser.h
@@ -0,0 +1,68 @@
+/* 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 <map>
+#include <string>
+#include <vector>
+
+#include <stddef.h>
+
+#include "cmXMLParser.h"
+
+// This class is used to parse XML with configuration
+// of installed SDKs in system
+class cmVisualStudioWCEPlatformParser : public cmXMLParser
+{
+public:
+ cmVisualStudioWCEPlatformParser(const char* name = NULL)
+ : RequiredName(name)
+ , FoundRequiredName(false)
+ {
+ }
+
+ int ParseVersion(const char* version);
+
+ bool Found() const { return this->FoundRequiredName; }
+ const char* GetArchitectureFamily() const;
+ std::string GetOSVersion() const;
+ std::string GetIncludeDirectories() const
+ {
+ return this->FixPaths(this->Include);
+ }
+ std::string GetLibraryDirectories() const
+ {
+ return this->FixPaths(this->Library);
+ }
+ std::string GetPathDirectories() const { return this->FixPaths(this->Path); }
+ const std::vector<std::string>& GetAvailablePlatforms() const
+ {
+ return this->AvailablePlatforms;
+ }
+
+protected:
+ virtual void StartElement(const std::string& name, const char** attributes);
+ void EndElement(const std::string& name);
+ void CharacterDataHandler(const char* data, int length);
+
+private:
+ std::string FixPaths(const std::string& paths) const;
+
+ std::string CharacterData;
+
+ std::string Include;
+ std::string Library;
+ std::string Path;
+ std::string PlatformName;
+ std::string OSMajorVersion;
+ std::string OSMinorVersion;
+ std::map<std::string, std::string> Macros;
+ std::vector<std::string> AvailablePlatforms;
+
+ const char* RequiredName;
+ bool FoundRequiredName;
+ std::string VcInstallDir;
+ std::string VsInstallDir;
+};
diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx
new file mode 100644
index 0000000..327c1c7
--- /dev/null
+++ b/Source/cmWhileCommand.cxx
@@ -0,0 +1,138 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmWhileCommand.h"
+
+#include <string>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmConditionEvaluator.h"
+#include "cmExecutionStatus.h"
+#include "cmExpandedCommandArgument.h"
+#include "cmFunctionBlocker.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+class cmWhileFunctionBlocker : public cmFunctionBlocker
+{
+public:
+ cmWhileFunctionBlocker(cmMakefile* mf);
+ ~cmWhileFunctionBlocker() override;
+
+ cm::string_view StartCommandName() const override { return "while"_s; }
+ cm::string_view EndCommandName() const override { return "endwhile"_s; }
+
+ bool ArgumentsMatch(cmListFileFunction const& lff,
+ cmMakefile& mf) const override;
+
+ bool Replay(std::vector<cmListFileFunction> functions,
+ cmExecutionStatus& inStatus) override;
+
+ std::vector<cmListFileArgument> Args;
+
+private:
+ cmMakefile* Makefile;
+};
+
+cmWhileFunctionBlocker::cmWhileFunctionBlocker(cmMakefile* mf)
+ : Makefile(mf)
+{
+ this->Makefile->PushLoopBlock();
+}
+
+cmWhileFunctionBlocker::~cmWhileFunctionBlocker()
+{
+ this->Makefile->PopLoopBlock();
+}
+
+bool cmWhileFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
+ cmMakefile&) const
+{
+ return lff.Arguments().empty() || lff.Arguments() == this->Args;
+}
+
+bool cmWhileFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
+ cmExecutionStatus& inStatus)
+{
+ cmMakefile& mf = inStatus.GetMakefile();
+ std::string errorString;
+
+ std::vector<cmExpandedCommandArgument> expandedArguments;
+ mf.ExpandArguments(this->Args, expandedArguments);
+ MessageType messageType;
+
+ cmListFileBacktrace whileBT =
+ mf.GetBacktrace().Push(this->GetStartingContext());
+ cmConditionEvaluator conditionEvaluator(mf, whileBT);
+
+ bool isTrue =
+ conditionEvaluator.IsTrue(expandedArguments, errorString, messageType);
+
+ while (isTrue) {
+ if (!errorString.empty()) {
+ std::string err = "had incorrect arguments: ";
+ for (cmListFileArgument const& arg : this->Args) {
+ err += (arg.Delim ? "\"" : "");
+ err += arg.Value;
+ err += (arg.Delim ? "\"" : "");
+ err += " ";
+ }
+ err += "(";
+ err += errorString;
+ err += ").";
+ mf.GetCMakeInstance()->IssueMessage(messageType, err, whileBT);
+ if (messageType == MessageType::FATAL_ERROR) {
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ }
+
+ // Invoke all the functions that were collected in the block.
+ for (cmListFileFunction const& fn : functions) {
+ cmExecutionStatus status(mf);
+ mf.ExecuteCommand(fn, status);
+ if (status.GetReturnInvoked()) {
+ inStatus.SetReturnInvoked();
+ return true;
+ }
+ if (status.GetBreakInvoked()) {
+ return true;
+ }
+ if (status.GetContinueInvoked()) {
+ break;
+ }
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ return true;
+ }
+ }
+ expandedArguments.clear();
+ mf.ExpandArguments(this->Args, expandedArguments);
+ isTrue =
+ conditionEvaluator.IsTrue(expandedArguments, errorString, messageType);
+ }
+ return true;
+}
+
+bool cmWhileCommand(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // create a function blocker
+ {
+ cmMakefile& makefile = status.GetMakefile();
+ auto fb = cm::make_unique<cmWhileFunctionBlocker>(&makefile);
+ fb->Args = args;
+ makefile.AddFunctionBlocker(std::move(fb));
+ }
+ return true;
+}
diff --git a/Source/cmWhileCommand.h b/Source/cmWhileCommand.h
new file mode 100644
index 0000000..5b8f078
--- /dev/null
+++ b/Source/cmWhileCommand.h
@@ -0,0 +1,14 @@
+/* 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 <vector>
+
+class cmExecutionStatus;
+struct cmListFileArgument;
+
+/// \brief Starts a while loop
+bool cmWhileCommand(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmWorkerPool.cxx b/Source/cmWorkerPool.cxx
new file mode 100644
index 0000000..1d15c27
--- /dev/null
+++ b/Source/cmWorkerPool.cxx
@@ -0,0 +1,781 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmWorkerPool.h"
+
+#include <algorithm>
+#include <array>
+#include <condition_variable>
+#include <cstddef>
+#include <deque>
+#include <functional>
+#include <mutex>
+#include <thread>
+
+#include <cm/memory>
+
+#include <cm3p/uv.h>
+
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVSignalHackRAII.h" // IWYU pragma: keep
+
+/**
+ * @brief libuv pipe buffer class
+ */
+class cmUVPipeBuffer
+{
+public:
+ using DataRange = cmRange<const char*>;
+ using DataFunction = std::function<void(DataRange)>;
+ /// On error the ssize_t argument is a non zero libuv error code
+ using EndFunction = std::function<void(ssize_t)>;
+
+ /**
+ * Reset to construction state
+ */
+ void reset();
+
+ /**
+ * Initializes uv_pipe(), uv_stream() and uv_handle()
+ * @return true on success
+ */
+ bool init(uv_loop_t* uv_loop);
+
+ /**
+ * Start reading
+ * @return true on success
+ */
+ bool startRead(DataFunction dataFunction, EndFunction endFunction);
+
+ //! libuv pipe
+ uv_pipe_t* uv_pipe() const { return this->UVPipe_.get(); }
+ //! uv_pipe() casted to libuv stream
+ uv_stream_t* uv_stream() const
+ {
+ return static_cast<uv_stream_t*>(this->UVPipe_);
+ }
+ //! uv_pipe() casted to libuv handle
+ uv_handle_t* uv_handle() { return static_cast<uv_handle_t*>(this->UVPipe_); }
+
+private:
+ // -- Libuv callbacks
+ static void UVAlloc(uv_handle_t* handle, size_t suggestedSize,
+ uv_buf_t* buf);
+ static void UVData(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
+
+ cm::uv_pipe_ptr UVPipe_;
+ std::vector<char> Buffer_;
+ DataFunction DataFunction_;
+ EndFunction EndFunction_;
+};
+
+void cmUVPipeBuffer::reset()
+{
+ if (this->UVPipe_.get() != nullptr) {
+ this->EndFunction_ = nullptr;
+ this->DataFunction_ = nullptr;
+ this->Buffer_.clear();
+ this->Buffer_.shrink_to_fit();
+ this->UVPipe_.reset();
+ }
+}
+
+bool cmUVPipeBuffer::init(uv_loop_t* uv_loop)
+{
+ this->reset();
+ if (uv_loop == nullptr) {
+ return false;
+ }
+ int ret = this->UVPipe_.init(*uv_loop, 0, this);
+ return (ret == 0);
+}
+
+bool cmUVPipeBuffer::startRead(DataFunction dataFunction,
+ EndFunction endFunction)
+{
+ if (this->UVPipe_.get() == nullptr) {
+ return false;
+ }
+ if (!dataFunction || !endFunction) {
+ return false;
+ }
+ this->DataFunction_ = std::move(dataFunction);
+ this->EndFunction_ = std::move(endFunction);
+ int ret = uv_read_start(this->uv_stream(), &cmUVPipeBuffer::UVAlloc,
+ &cmUVPipeBuffer::UVData);
+ return (ret == 0);
+}
+
+void cmUVPipeBuffer::UVAlloc(uv_handle_t* handle, size_t suggestedSize,
+ uv_buf_t* buf)
+{
+ auto& pipe = *reinterpret_cast<cmUVPipeBuffer*>(handle->data);
+ pipe.Buffer_.resize(suggestedSize);
+ buf->base = pipe.Buffer_.data();
+ buf->len = static_cast<unsigned long>(pipe.Buffer_.size());
+}
+
+void cmUVPipeBuffer::UVData(uv_stream_t* stream, ssize_t nread,
+ const uv_buf_t* buf)
+{
+ auto& pipe = *reinterpret_cast<cmUVPipeBuffer*>(stream->data);
+ if (nread > 0) {
+ if (buf->base != nullptr) {
+ // Call data function
+ pipe.DataFunction_(DataRange(buf->base, buf->base + nread));
+ }
+ } else if (nread < 0) {
+ // Save the end function on the stack before resetting the pipe
+ EndFunction efunc;
+ efunc.swap(pipe.EndFunction_);
+ // Reset pipe before calling the end function
+ pipe.reset();
+ // Call end function
+ efunc((nread == UV_EOF) ? 0 : nread);
+ }
+}
+
+/**
+ * @brief External process management class
+ */
+class cmUVReadOnlyProcess
+{
+public:
+ // -- Types
+ //! @brief Process settings
+ struct SetupT
+ {
+ std::string WorkingDirectory;
+ std::vector<std::string> Command;
+ cmWorkerPool::ProcessResultT* Result = nullptr;
+ bool MergedOutput = false;
+ };
+
+ // -- Const accessors
+ SetupT const& Setup() const { return this->Setup_; }
+ cmWorkerPool::ProcessResultT* Result() const { return this->Setup_.Result; }
+ bool IsStarted() const { return this->IsStarted_; }
+ bool IsFinished() const { return this->IsFinished_; }
+
+ // -- Runtime
+ void setup(cmWorkerPool::ProcessResultT* result, bool mergedOutput,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory = std::string());
+ bool start(uv_loop_t* uv_loop, std::function<void()> finishedCallback);
+
+private:
+ // -- Libuv callbacks
+ static void UVExit(uv_process_t* handle, int64_t exitStatus, int termSignal);
+ void UVPipeOutData(cmUVPipeBuffer::DataRange data) const;
+ void UVPipeOutEnd(ssize_t error);
+ void UVPipeErrData(cmUVPipeBuffer::DataRange data) const;
+ void UVPipeErrEnd(ssize_t error);
+ void UVTryFinish();
+
+ // -- Setup
+ SetupT Setup_;
+ // -- Runtime
+ bool IsStarted_ = false;
+ bool IsFinished_ = false;
+ std::function<void()> FinishedCallback_;
+ std::vector<const char*> CommandPtr_;
+ std::array<uv_stdio_container_t, 3> UVOptionsStdIO_;
+ uv_process_options_t UVOptions_;
+ cm::uv_process_ptr UVProcess_;
+ cmUVPipeBuffer UVPipeOut_;
+ cmUVPipeBuffer UVPipeErr_;
+};
+
+void cmUVReadOnlyProcess::setup(cmWorkerPool::ProcessResultT* result,
+ bool mergedOutput,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory)
+{
+ this->Setup_.WorkingDirectory = workingDirectory;
+ this->Setup_.Command = command;
+ this->Setup_.Result = result;
+ this->Setup_.MergedOutput = mergedOutput;
+}
+
+bool cmUVReadOnlyProcess::start(uv_loop_t* uv_loop,
+ std::function<void()> finishedCallback)
+{
+ if (this->IsStarted() || (this->Result() == nullptr)) {
+ return false;
+ }
+
+ // Reset result before the start
+ this->Result()->reset();
+
+ // Fill command string pointers
+ if (!this->Setup().Command.empty()) {
+ this->CommandPtr_.reserve(this->Setup().Command.size() + 1);
+ for (std::string const& arg : this->Setup().Command) {
+ this->CommandPtr_.push_back(arg.c_str());
+ }
+ this->CommandPtr_.push_back(nullptr);
+ } else {
+ this->Result()->ErrorMessage = "Empty command";
+ }
+
+ if (!this->Result()->error()) {
+ if (!this->UVPipeOut_.init(uv_loop)) {
+ this->Result()->ErrorMessage = "libuv stdout pipe initialization failed";
+ }
+ }
+ if (!this->Result()->error()) {
+ if (!this->UVPipeErr_.init(uv_loop)) {
+ this->Result()->ErrorMessage = "libuv stderr pipe initialization failed";
+ }
+ }
+ if (!this->Result()->error()) {
+ // -- Setup process stdio options
+ // stdin
+ this->UVOptionsStdIO_[0].flags = UV_IGNORE;
+ this->UVOptionsStdIO_[0].data.stream = nullptr;
+ // stdout
+ this->UVOptionsStdIO_[1].flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ this->UVOptionsStdIO_[1].data.stream = this->UVPipeOut_.uv_stream();
+ // stderr
+ this->UVOptionsStdIO_[2].flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ this->UVOptionsStdIO_[2].data.stream = this->UVPipeErr_.uv_stream();
+
+ // -- Setup process options
+ std::fill_n(reinterpret_cast<char*>(&this->UVOptions_),
+ sizeof(this->UVOptions_), 0);
+ this->UVOptions_.exit_cb = &cmUVReadOnlyProcess::UVExit;
+ this->UVOptions_.file = this->CommandPtr_[0];
+ this->UVOptions_.args = const_cast<char**>(this->CommandPtr_.data());
+ this->UVOptions_.cwd = this->Setup_.WorkingDirectory.c_str();
+ this->UVOptions_.flags = UV_PROCESS_WINDOWS_HIDE;
+ this->UVOptions_.stdio_count =
+ static_cast<int>(this->UVOptionsStdIO_.size());
+ this->UVOptions_.stdio = this->UVOptionsStdIO_.data();
+
+ // -- Spawn process
+ int uvErrorCode = this->UVProcess_.spawn(*uv_loop, this->UVOptions_, this);
+ if (uvErrorCode != 0) {
+ this->Result()->ErrorMessage = "libuv process spawn failed";
+ if (const char* uvErr = uv_strerror(uvErrorCode)) {
+ this->Result()->ErrorMessage += ": ";
+ this->Result()->ErrorMessage += uvErr;
+ }
+ }
+ }
+ // -- Start reading from stdio streams
+ if (!this->Result()->error()) {
+ if (!this->UVPipeOut_.startRead(
+ [this](cmUVPipeBuffer::DataRange range) {
+ this->UVPipeOutData(range);
+ },
+ [this](ssize_t error) { this->UVPipeOutEnd(error); })) {
+ this->Result()->ErrorMessage =
+ "libuv start reading from stdout pipe failed";
+ }
+ }
+ if (!this->Result()->error()) {
+ if (!this->UVPipeErr_.startRead(
+ [this](cmUVPipeBuffer::DataRange range) {
+ this->UVPipeErrData(range);
+ },
+ [this](ssize_t error) { this->UVPipeErrEnd(error); })) {
+ this->Result()->ErrorMessage =
+ "libuv start reading from stderr pipe failed";
+ }
+ }
+
+ if (!this->Result()->error()) {
+ this->IsStarted_ = true;
+ this->FinishedCallback_ = std::move(finishedCallback);
+ } else {
+ // Clear libuv handles and finish
+ this->UVProcess_.reset();
+ this->UVPipeOut_.reset();
+ this->UVPipeErr_.reset();
+ this->CommandPtr_.clear();
+ }
+
+ return this->IsStarted();
+}
+
+void cmUVReadOnlyProcess::UVExit(uv_process_t* handle, int64_t exitStatus,
+ int termSignal)
+{
+ auto& proc = *reinterpret_cast<cmUVReadOnlyProcess*>(handle->data);
+ if (proc.IsStarted() && !proc.IsFinished()) {
+ // Set error message on demand
+ proc.Result()->ExitStatus = exitStatus;
+ proc.Result()->TermSignal = termSignal;
+ if (!proc.Result()->error()) {
+ if (termSignal != 0) {
+ proc.Result()->ErrorMessage = cmStrCat(
+ "Process was terminated by signal ", proc.Result()->TermSignal);
+ } else if (exitStatus != 0) {
+ proc.Result()->ErrorMessage = cmStrCat(
+ "Process failed with return value ", proc.Result()->ExitStatus);
+ }
+ }
+
+ // Reset process handle
+ proc.UVProcess_.reset();
+ // Try finish
+ proc.UVTryFinish();
+ }
+}
+
+void cmUVReadOnlyProcess::UVPipeOutData(cmUVPipeBuffer::DataRange data) const
+{
+ this->Result()->StdOut.append(data.begin(), data.end());
+}
+
+void cmUVReadOnlyProcess::UVPipeOutEnd(ssize_t error)
+{
+ // Process pipe error
+ if ((error != 0) && !this->Result()->error()) {
+ this->Result()->ErrorMessage = cmStrCat(
+ "Reading from stdout pipe failed with libuv error code ", error);
+ }
+ // Try finish
+ this->UVTryFinish();
+}
+
+void cmUVReadOnlyProcess::UVPipeErrData(cmUVPipeBuffer::DataRange data) const
+{
+ std::string* str = this->Setup_.MergedOutput ? &this->Result()->StdOut
+ : &this->Result()->StdErr;
+ str->append(data.begin(), data.end());
+}
+
+void cmUVReadOnlyProcess::UVPipeErrEnd(ssize_t error)
+{
+ // Process pipe error
+ if ((error != 0) && !this->Result()->error()) {
+ this->Result()->ErrorMessage = cmStrCat(
+ "Reading from stderr pipe failed with libuv error code ", error);
+ }
+ // Try finish
+ this->UVTryFinish();
+}
+
+void cmUVReadOnlyProcess::UVTryFinish()
+{
+ // There still might be data in the pipes after the process has finished.
+ // Therefore check if the process is finished AND all pipes are closed
+ // before signaling the worker thread to continue.
+ if ((this->UVProcess_.get() != nullptr) ||
+ (this->UVPipeOut_.uv_pipe() != nullptr) ||
+ (this->UVPipeErr_.uv_pipe() != nullptr)) {
+ return;
+ }
+ this->IsFinished_ = true;
+ this->FinishedCallback_();
+}
+
+/**
+ * @brief Worker pool worker thread
+ */
+class cmWorkerPoolWorker
+{
+public:
+ cmWorkerPoolWorker(uv_loop_t& uvLoop);
+ ~cmWorkerPoolWorker();
+
+ cmWorkerPoolWorker(cmWorkerPoolWorker const&) = delete;
+ cmWorkerPoolWorker& operator=(cmWorkerPoolWorker const&) = delete;
+
+ /**
+ * Set the internal thread
+ */
+ void SetThread(std::thread&& aThread) { this->Thread_ = std::move(aThread); }
+
+ /**
+ * Run an external process
+ */
+ bool RunProcess(cmWorkerPool::ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory);
+
+private:
+ // -- Libuv callbacks
+ static void UVProcessStart(uv_async_t* handle);
+ void UVProcessFinished();
+
+ // -- Process management
+ struct
+ {
+ std::mutex Mutex;
+ cm::uv_async_ptr Request;
+ std::condition_variable Condition;
+ std::unique_ptr<cmUVReadOnlyProcess> ROP;
+ } Proc_;
+ // -- System thread
+ std::thread Thread_;
+};
+
+cmWorkerPoolWorker::cmWorkerPoolWorker(uv_loop_t& uvLoop)
+{
+ this->Proc_.Request.init(uvLoop, &cmWorkerPoolWorker::UVProcessStart, this);
+}
+
+cmWorkerPoolWorker::~cmWorkerPoolWorker()
+{
+ if (this->Thread_.joinable()) {
+ this->Thread_.join();
+ }
+}
+
+bool cmWorkerPoolWorker::RunProcess(cmWorkerPool::ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory)
+{
+ if (command.empty()) {
+ return false;
+ }
+ // Create process instance
+ {
+ std::lock_guard<std::mutex> lock(this->Proc_.Mutex);
+ this->Proc_.ROP = cm::make_unique<cmUVReadOnlyProcess>();
+ this->Proc_.ROP->setup(&result, true, command, workingDirectory);
+ }
+ // Send asynchronous process start request to libuv loop
+ this->Proc_.Request.send();
+ // Wait until the process has been finished and destroyed
+ {
+ std::unique_lock<std::mutex> ulock(this->Proc_.Mutex);
+ while (this->Proc_.ROP) {
+ this->Proc_.Condition.wait(ulock);
+ }
+ }
+ return !result.error();
+}
+
+void cmWorkerPoolWorker::UVProcessStart(uv_async_t* handle)
+{
+ auto* wrk = reinterpret_cast<cmWorkerPoolWorker*>(handle->data);
+ bool startFailed = false;
+ {
+ auto& Proc = wrk->Proc_;
+ std::lock_guard<std::mutex> lock(Proc.Mutex);
+ if (Proc.ROP && !Proc.ROP->IsStarted()) {
+ startFailed =
+ !Proc.ROP->start(handle->loop, [wrk] { wrk->UVProcessFinished(); });
+ }
+ }
+ // Clean up if starting of the process failed
+ if (startFailed) {
+ wrk->UVProcessFinished();
+ }
+}
+
+void cmWorkerPoolWorker::UVProcessFinished()
+{
+ std::lock_guard<std::mutex> lock(this->Proc_.Mutex);
+ if (this->Proc_.ROP &&
+ (this->Proc_.ROP->IsFinished() || !this->Proc_.ROP->IsStarted())) {
+ this->Proc_.ROP.reset();
+ }
+ // Notify idling thread
+ this->Proc_.Condition.notify_one();
+}
+
+/**
+ * @brief Private worker pool internals
+ */
+class cmWorkerPoolInternal
+{
+public:
+ // -- Constructors
+ cmWorkerPoolInternal(cmWorkerPool* pool);
+ ~cmWorkerPoolInternal();
+
+ /**
+ * Runs the libuv loop.
+ */
+ bool Process();
+
+ /**
+ * Clear queue and abort threads.
+ */
+ void Abort();
+
+ /**
+ * Push a job to the queue and notify a worker.
+ */
+ bool PushJob(cmWorkerPool::JobHandleT&& jobHandle);
+
+ /**
+ * Worker thread main loop method.
+ */
+ void Work(unsigned int workerIndex);
+
+ // -- Request slots
+ static void UVSlotBegin(uv_async_t* handle);
+ static void UVSlotEnd(uv_async_t* handle);
+
+ // -- UV loop
+#ifdef CMAKE_UV_SIGNAL_HACK
+ std::unique_ptr<cmUVSignalHackRAII> UVHackRAII;
+#endif
+ std::unique_ptr<uv_loop_t> UVLoop;
+ cm::uv_async_ptr UVRequestBegin;
+ cm::uv_async_ptr UVRequestEnd;
+
+ // -- Thread pool and job queue
+ std::mutex Mutex;
+ bool Processing = false;
+ bool Aborting = false;
+ bool FenceProcessing = false;
+ unsigned int WorkersRunning = 0;
+ unsigned int WorkersIdle = 0;
+ unsigned int JobsProcessing = 0;
+ std::deque<cmWorkerPool::JobHandleT> Queue;
+ std::condition_variable Condition;
+ std::condition_variable ConditionFence;
+ std::vector<std::unique_ptr<cmWorkerPoolWorker>> Workers;
+
+ // -- References
+ cmWorkerPool* Pool = nullptr;
+};
+
+void cmWorkerPool::ProcessResultT::reset()
+{
+ this->ExitStatus = 0;
+ this->TermSignal = 0;
+ if (!this->StdOut.empty()) {
+ this->StdOut.clear();
+ this->StdOut.shrink_to_fit();
+ }
+ if (!this->StdErr.empty()) {
+ this->StdErr.clear();
+ this->StdErr.shrink_to_fit();
+ }
+ if (!this->ErrorMessage.empty()) {
+ this->ErrorMessage.clear();
+ this->ErrorMessage.shrink_to_fit();
+ }
+}
+
+cmWorkerPoolInternal::cmWorkerPoolInternal(cmWorkerPool* pool)
+ : Pool(pool)
+{
+ // Initialize libuv loop
+ uv_disable_stdio_inheritance();
+#ifdef CMAKE_UV_SIGNAL_HACK
+ UVHackRAII = cm::make_unique<cmUVSignalHackRAII>();
+#endif
+ this->UVLoop = cm::make_unique<uv_loop_t>();
+ uv_loop_init(this->UVLoop.get());
+}
+
+cmWorkerPoolInternal::~cmWorkerPoolInternal()
+{
+ uv_loop_close(this->UVLoop.get());
+}
+
+bool cmWorkerPoolInternal::Process()
+{
+ // Reset state flags
+ this->Processing = true;
+ this->Aborting = false;
+ // Initialize libuv asynchronous request
+ this->UVRequestBegin.init(*this->UVLoop, &cmWorkerPoolInternal::UVSlotBegin,
+ this);
+ this->UVRequestEnd.init(*this->UVLoop, &cmWorkerPoolInternal::UVSlotEnd,
+ this);
+ // Send begin request
+ this->UVRequestBegin.send();
+ // Run libuv loop
+ bool success = (uv_run(this->UVLoop.get(), UV_RUN_DEFAULT) == 0);
+ // Update state flags
+ this->Processing = false;
+ this->Aborting = false;
+ return success;
+}
+
+void cmWorkerPoolInternal::Abort()
+{
+ // Clear all jobs and set abort flag
+ std::lock_guard<std::mutex> guard(this->Mutex);
+ if (!this->Aborting) {
+ // Register abort and clear queue
+ this->Aborting = true;
+ this->Queue.clear();
+ this->Condition.notify_all();
+ }
+}
+
+inline bool cmWorkerPoolInternal::PushJob(cmWorkerPool::JobHandleT&& jobHandle)
+{
+ std::lock_guard<std::mutex> guard(this->Mutex);
+ if (this->Aborting) {
+ return false;
+ }
+ // Append the job to the queue
+ this->Queue.emplace_back(std::move(jobHandle));
+ // Notify an idle worker if there's one
+ if (this->WorkersIdle != 0) {
+ this->Condition.notify_one();
+ }
+ // Return success
+ return true;
+}
+
+void cmWorkerPoolInternal::UVSlotBegin(uv_async_t* handle)
+{
+ auto& gint = *reinterpret_cast<cmWorkerPoolInternal*>(handle->data);
+ // Create worker threads
+ {
+ unsigned int const num = gint.Pool->ThreadCount();
+ // Create workers
+ gint.Workers.reserve(num);
+ for (unsigned int ii = 0; ii != num; ++ii) {
+ gint.Workers.emplace_back(
+ cm::make_unique<cmWorkerPoolWorker>(*gint.UVLoop));
+ }
+ // Start worker threads
+ for (unsigned int ii = 0; ii != num; ++ii) {
+ gint.Workers[ii]->SetThread(
+ std::thread(&cmWorkerPoolInternal::Work, &gint, ii));
+ }
+ }
+ // Destroy begin request
+ gint.UVRequestBegin.reset();
+}
+
+void cmWorkerPoolInternal::UVSlotEnd(uv_async_t* handle)
+{
+ auto& gint = *reinterpret_cast<cmWorkerPoolInternal*>(handle->data);
+ // Join and destroy worker threads
+ gint.Workers.clear();
+ // Destroy end request
+ gint.UVRequestEnd.reset();
+}
+
+void cmWorkerPoolInternal::Work(unsigned int workerIndex)
+{
+ cmWorkerPool::JobHandleT jobHandle;
+ std::unique_lock<std::mutex> uLock(this->Mutex);
+ // Increment running workers count
+ ++this->WorkersRunning;
+ // Enter worker main loop
+ while (true) {
+ // Abort on request
+ if (this->Aborting) {
+ break;
+ }
+ // Wait for new jobs on the main CV
+ if (this->Queue.empty()) {
+ ++this->WorkersIdle;
+ this->Condition.wait(uLock);
+ --this->WorkersIdle;
+ continue;
+ }
+
+ // If there is a fence currently active or waiting,
+ // sleep on the main CV and try again.
+ if (this->FenceProcessing) {
+ this->Condition.wait(uLock);
+ continue;
+ }
+
+ // Pop next job from queue
+ jobHandle = std::move(this->Queue.front());
+ this->Queue.pop_front();
+
+ // Check for fence jobs
+ bool raisedFence = false;
+ if (jobHandle->IsFence()) {
+ this->FenceProcessing = true;
+ raisedFence = true;
+ // Wait on the Fence CV until all pending jobs are done.
+ while (this->JobsProcessing != 0 && !this->Aborting) {
+ this->ConditionFence.wait(uLock);
+ }
+ // When aborting, explicitly kick all threads alive once more.
+ if (this->Aborting) {
+ this->FenceProcessing = false;
+ this->Condition.notify_all();
+ break;
+ }
+ }
+
+ // Unlocked scope for job processing
+ ++this->JobsProcessing;
+ {
+ uLock.unlock();
+ jobHandle->Work(this->Pool, workerIndex); // Process job
+ jobHandle.reset(); // Destroy job
+ uLock.lock();
+ }
+ --this->JobsProcessing;
+
+ // If this was the thread that entered fence processing
+ // originally, notify all idling workers that the fence
+ // is done.
+ if (raisedFence) {
+ this->FenceProcessing = false;
+ this->Condition.notify_all();
+ }
+ // If fence processing is still not done, notify the
+ // the fencing worker when all active jobs are done.
+ if (this->FenceProcessing && this->JobsProcessing == 0) {
+ this->ConditionFence.notify_all();
+ }
+ }
+
+ // Decrement running workers count
+ if (--this->WorkersRunning == 0) {
+ // Last worker thread about to finish. Send libuv event.
+ this->UVRequestEnd.send();
+ }
+}
+
+cmWorkerPool::JobT::~JobT() = default;
+
+bool cmWorkerPool::JobT::RunProcess(ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory)
+{
+ // Get worker by index
+ auto* wrk = this->Pool_->Int_->Workers.at(this->WorkerIndex_).get();
+ return wrk->RunProcess(result, command, workingDirectory);
+}
+
+cmWorkerPool::cmWorkerPool()
+ : Int_(cm::make_unique<cmWorkerPoolInternal>(this))
+{
+}
+
+cmWorkerPool::~cmWorkerPool() = default;
+
+void cmWorkerPool::SetThreadCount(unsigned int threadCount)
+{
+ if (!this->Int_->Processing) {
+ this->ThreadCount_ = (threadCount > 0) ? threadCount : 1u;
+ }
+}
+
+bool cmWorkerPool::Process(void* userData)
+{
+ // Setup user data
+ this->UserData_ = userData;
+ // Run libuv loop
+ bool success = this->Int_->Process();
+ // Clear user data
+ this->UserData_ = nullptr;
+ // Return
+ return success;
+}
+
+bool cmWorkerPool::PushJob(JobHandleT&& jobHandle)
+{
+ return this->Int_->PushJob(std::move(jobHandle));
+}
+
+void cmWorkerPool::Abort()
+{
+ this->Int_->Abort();
+}
diff --git a/Source/cmWorkerPool.h b/Source/cmWorkerPool.h
new file mode 100644
index 0000000..ff25526
--- /dev/null
+++ b/Source/cmWorkerPool.h
@@ -0,0 +1,221 @@
+/* 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 <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+
+// -- Types
+class cmWorkerPoolInternal;
+
+/** @class cmWorkerPool
+ * @brief Thread pool with job queue
+ */
+class cmWorkerPool
+{
+public:
+ /**
+ * Return value and output of an external process.
+ */
+ struct ProcessResultT
+ {
+ void reset();
+ bool error() const
+ {
+ return (this->ExitStatus != 0) || (this->TermSignal != 0) ||
+ !this->ErrorMessage.empty();
+ }
+
+ std::int64_t ExitStatus = 0;
+ int TermSignal = 0;
+ std::string StdOut;
+ std::string StdErr;
+ std::string ErrorMessage;
+ };
+
+ /**
+ * Abstract job class for concurrent job processing.
+ */
+ class JobT
+ {
+ public:
+ JobT(JobT const&) = delete;
+ JobT& operator=(JobT const&) = delete;
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~JobT();
+
+ /**
+ * Fence job flag
+ *
+ * Fence jobs require that:
+ * - all jobs before in the queue have been processed
+ * - no jobs later in the queue will be processed before this job was
+ * processed
+ */
+ bool IsFence() const { return this->Fence_; }
+
+ protected:
+ /**
+ * Protected default constructor
+ */
+ JobT(bool fence = false)
+ : Fence_(fence)
+ {
+ }
+
+ /**
+ * Abstract processing interface that must be implement in derived classes.
+ */
+ virtual void Process() = 0;
+
+ /**
+ * Get the worker pool.
+ * Only valid during the JobT::Process() call!
+ */
+ cmWorkerPool* Pool() const { return this->Pool_; }
+
+ /**
+ * Get the user data.
+ * Only valid during the JobT::Process() call!
+ */
+ void* UserData() const { return this->Pool_->UserData(); };
+
+ /**
+ * Get the worker index.
+ * This is the index of the thread processing this job and is in the range
+ * [0..ThreadCount).
+ * Concurrently processing jobs will never have the same WorkerIndex().
+ * Only valid during the JobT::Process() call!
+ */
+ unsigned int WorkerIndex() const { return this->WorkerIndex_; }
+
+ /**
+ * Run an external read only process.
+ * Use only during JobT::Process() call!
+ */
+ bool RunProcess(ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory);
+
+ private:
+ //! Needs access to Work()
+ friend class cmWorkerPoolInternal;
+ //! Worker thread entry method.
+ void Work(cmWorkerPool* pool, unsigned int workerIndex)
+ {
+ this->Pool_ = pool;
+ this->WorkerIndex_ = workerIndex;
+ this->Process();
+ }
+
+ cmWorkerPool* Pool_ = nullptr;
+ unsigned int WorkerIndex_ = 0;
+ bool Fence_ = false;
+ };
+
+ /**
+ * Job handle type
+ */
+ using JobHandleT = std::unique_ptr<JobT>;
+
+ /**
+ * Fence job base class
+ */
+ class JobFenceT : public JobT
+ {
+ public:
+ JobFenceT()
+ : JobT(true)
+ {
+ }
+ //! Does nothing
+ void Process() override{};
+ };
+
+ /**
+ * Fence job that aborts the worker pool.
+ *
+ * Useful as the last job in the job queue.
+ */
+ class JobEndT : JobFenceT
+ {
+ public:
+ //! Does nothing
+ void Process() override { this->Pool()->Abort(); }
+ };
+
+ // -- Methods
+ cmWorkerPool();
+ ~cmWorkerPool();
+
+ /**
+ * Number of worker threads.
+ */
+ unsigned int ThreadCount() const { return this->ThreadCount_; }
+
+ /**
+ * Set the number of worker threads.
+ *
+ * Calling this method during Process() has no effect.
+ */
+ void SetThreadCount(unsigned int threadCount);
+
+ /**
+ * Blocking function that starts threads to process all Jobs in the queue.
+ *
+ * This method blocks until a job calls the Abort() method.
+ * @arg threadCount Number of threads to process jobs.
+ * @arg userData Common user data pointer available in all Jobs.
+ */
+ bool Process(void* userData = nullptr);
+
+ /**
+ * User data reference passed to Process().
+ *
+ * Only valid during Process().
+ */
+ void* UserData() const { return this->UserData_; }
+
+ // -- Job processing interface
+
+ /**
+ * Clears the job queue and aborts all worker threads.
+ *
+ * This method is thread safe and can be called from inside a job.
+ */
+ void Abort();
+
+ /**
+ * Push job to the queue.
+ *
+ * This method is thread safe and can be called from inside a job or before
+ * Process().
+ */
+ bool PushJob(JobHandleT&& jobHandle);
+
+ /**
+ * Push job to the queue
+ *
+ * This method is thread safe and can be called from inside a job or before
+ * Process().
+ */
+ template <class T, typename... Args>
+ bool EmplaceJob(Args&&... args)
+ {
+ return this->PushJob(cm::make_unique<T>(std::forward<Args>(args)...));
+ }
+
+private:
+ void* UserData_ = nullptr;
+ unsigned int ThreadCount_ = 1;
+ std::unique_ptr<cmWorkerPoolInternal> Int_;
+};
diff --git a/Source/cmWorkingDirectory.cxx b/Source/cmWorkingDirectory.cxx
new file mode 100644
index 0000000..5700b1c
--- /dev/null
+++ b/Source/cmWorkingDirectory.cxx
@@ -0,0 +1,36 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmWorkingDirectory.h"
+
+#include <cerrno>
+
+#include "cmSystemTools.h"
+
+cmWorkingDirectory::cmWorkingDirectory(std::string const& newdir)
+{
+ this->OldDir = cmSystemTools::GetCurrentWorkingDirectory();
+ this->SetDirectory(newdir);
+}
+
+cmWorkingDirectory::~cmWorkingDirectory()
+{
+ this->Pop();
+}
+
+bool cmWorkingDirectory::SetDirectory(std::string const& newdir)
+{
+ if (cmSystemTools::ChangeDirectory(newdir) == 0) {
+ this->ResultCode = 0;
+ return true;
+ }
+ this->ResultCode = errno;
+ return false;
+}
+
+void cmWorkingDirectory::Pop()
+{
+ if (!this->OldDir.empty()) {
+ this->SetDirectory(this->OldDir);
+ this->OldDir.clear();
+ }
+}
diff --git a/Source/cmWorkingDirectory.h b/Source/cmWorkingDirectory.h
new file mode 100644
index 0000000..e593621
--- /dev/null
+++ b/Source/cmWorkingDirectory.h
@@ -0,0 +1,44 @@
+/* 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 <string>
+
+/** \class cmWorkingDirectory
+ * \brief An RAII class to manipulate the working directory.
+ *
+ * The current working directory is set to the location given to the
+ * constructor. The working directory can be changed again as needed
+ * by calling SetDirectory(). When the object is destroyed, the destructor
+ * will restore the working directory to what it was when the object was
+ * created, regardless of any calls to SetDirectory() in the meantime.
+ */
+class cmWorkingDirectory
+{
+public:
+ cmWorkingDirectory(std::string const& newdir);
+ ~cmWorkingDirectory();
+
+ cmWorkingDirectory(const cmWorkingDirectory&) = delete;
+ cmWorkingDirectory& operator=(const cmWorkingDirectory&) = delete;
+
+ bool SetDirectory(std::string const& newdir);
+ void Pop();
+ bool Failed() const { return this->ResultCode != 0; }
+
+ /** \return 0 if the last attempt to set the working directory was
+ * successful. If it failed, the value returned will be the
+ * \c errno value associated with the failure. A description
+ * of the error code can be obtained by passing the result
+ * to \c std::strerror().
+ */
+ int GetLastResult() const { return this->ResultCode; }
+
+ std::string const& GetOldDirectory() const { return this->OldDir; }
+
+private:
+ std::string OldDir;
+ int ResultCode;
+};
diff --git a/Source/cmWriteFileCommand.cxx b/Source/cmWriteFileCommand.cxx
new file mode 100644
index 0000000..666ba87
--- /dev/null
+++ b/Source/cmWriteFileCommand.cxx
@@ -0,0 +1,82 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmWriteFileCommand.h"
+
+#include "cmsys/FStream.hxx"
+
+#include "cm_sys_stat.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+// cmLibraryCommand
+bool cmWriteFileCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+ std::string message;
+ auto i = args.begin();
+
+ std::string const& fileName = *i;
+ bool overwrite = true;
+ i++;
+
+ for (; i != args.end(); ++i) {
+ if (*i == "APPEND") {
+ overwrite = false;
+ } else {
+ message += *i;
+ }
+ }
+
+ if (!status.GetMakefile().CanIWriteThisFile(fileName)) {
+ std::string e =
+ "attempted to write a file: " + fileName + " into a source directory.";
+ status.SetError(e);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ std::string dir = cmSystemTools::GetFilenamePath(fileName);
+ cmSystemTools::MakeDirectory(dir);
+
+ mode_t mode = 0;
+ bool writable = false;
+
+ // Set permissions to writable
+ if (cmSystemTools::GetPermissions(fileName.c_str(), mode)) {
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ writable = (mode & S_IWRITE) != 0;
+ mode_t newMode = mode | S_IWRITE;
+#else
+ writable = mode & S_IWUSR;
+ mode_t newMode = mode | S_IWUSR | S_IWGRP;
+#endif
+ if (!writable) {
+ cmSystemTools::SetPermissions(fileName.c_str(), newMode);
+ }
+ }
+ // If GetPermissions fails, pretend like it is ok. File open will fail if
+ // the file is not writable
+ cmsys::ofstream file(fileName.c_str(),
+ overwrite ? std::ios::out : std::ios::app);
+ if (!file) {
+ std::string error =
+ cmStrCat("Internal CMake error when trying to open file: ", fileName,
+ " for writing.");
+ status.SetError(error);
+ return false;
+ }
+ file << message << '\n';
+ file.close();
+ if (mode && !writable) {
+ cmSystemTools::SetPermissions(fileName.c_str(), mode);
+ }
+
+ return true;
+}
diff --git a/Source/cmWriteFileCommand.h b/Source/cmWriteFileCommand.h
new file mode 100644
index 0000000..0225e4f
--- /dev/null
+++ b/Source/cmWriteFileCommand.h
@@ -0,0 +1,17 @@
+/* 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 <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/**
+ * \brief Writes a message to a file
+ *
+ */
+bool cmWriteFileCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmXCOFF.cxx b/Source/cmXCOFF.cxx
new file mode 100644
index 0000000..890636e
--- /dev/null
+++ b/Source/cmXCOFF.cxx
@@ -0,0 +1,356 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmXCOFF.h"
+
+#include <algorithm>
+#include <cstddef>
+
+#include <cm/memory>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmStringAlgorithms.h"
+
+// Include the XCOFF format information system header.
+#ifdef _AIX
+# define __XCOFF32__
+# define __XCOFF64__
+# include <xcoff.h>
+#else
+# error "This source may be compiled only on AIX."
+#endif
+
+class cmXCOFFInternal
+{
+public:
+ // Construct and take ownership of the file stream object.
+ cmXCOFFInternal(cmXCOFF* external, std::unique_ptr<std::iostream> fin,
+ cmXCOFF::Mode mode)
+ : External(external)
+ , Stream(std::move(fin))
+ , Mode(mode)
+ {
+ }
+
+ // Destruct and delete the file stream object.
+ virtual ~cmXCOFFInternal() = default;
+
+ cmXCOFF::Mode GetMode() const { return this->Mode; }
+
+ virtual cm::optional<cm::string_view> GetLibPath() = 0;
+
+ virtual bool SetLibPath(cm::string_view libPath) = 0;
+ virtual bool RemoveLibPath() = 0;
+
+protected:
+ // Data common to all ELF class implementations.
+
+ // The external cmXCOFF object.
+ cmXCOFF* External;
+
+ // The stream from which to read.
+ std::unique_ptr<std::iostream> Stream;
+
+ cmXCOFF::Mode Mode;
+
+ // Helper methods for subclasses.
+ void SetErrorMessage(const char* msg) { this->External->ErrorMessage = msg; }
+};
+
+namespace {
+
+struct XCOFF32
+{
+ typedef struct filehdr filehdr;
+ typedef struct aouthdr aouthdr;
+ typedef struct scnhdr scnhdr;
+ typedef struct ldhdr ldhdr;
+ static const std::size_t aouthdr_size = _AOUTHSZ_EXEC;
+};
+const unsigned char xcoff32_magic[] = { 0x01, 0xDF };
+
+struct XCOFF64
+{
+ typedef struct filehdr_64 filehdr;
+ typedef struct aouthdr_64 aouthdr;
+ typedef struct scnhdr_64 scnhdr;
+ typedef struct ldhdr_64 ldhdr;
+ static const std::size_t aouthdr_size = _AOUTHSZ_EXEC_64;
+};
+const unsigned char xcoff64_magic[] = { 0x01, 0xF7 };
+
+template <typename XCOFF>
+class Impl : public cmXCOFFInternal
+{
+ static_assert(sizeof(typename XCOFF::aouthdr) == XCOFF::aouthdr_size,
+ "aouthdr structure size matches _AOUTHSZ_EXEC macro");
+
+ typename XCOFF::filehdr FileHeader;
+ typename XCOFF::aouthdr AuxHeader;
+ typename XCOFF::scnhdr LoaderSectionHeader;
+ typename XCOFF::ldhdr LoaderHeader;
+
+ std::streamoff LoaderImportFileTablePos = 0;
+ std::vector<char> LoaderImportFileTable;
+
+ bool Read(typename XCOFF::filehdr& x)
+ {
+ // FIXME: Add byte swapping if needed.
+ return static_cast<bool>(
+ this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)));
+ }
+
+ bool Read(typename XCOFF::aouthdr& x)
+ {
+ // FIXME: Add byte swapping if needed.
+ return static_cast<bool>(
+ this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)));
+ }
+
+ bool Read(typename XCOFF::scnhdr& x)
+ {
+ // FIXME: Add byte swapping if needed.
+ return static_cast<bool>(
+ this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)));
+ }
+
+ bool Read(typename XCOFF::ldhdr& x)
+ {
+ // FIXME: Add byte swapping if needed.
+ return static_cast<bool>(
+ this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)));
+ }
+
+ bool WriteLoaderImportFileTableLength(decltype(XCOFF::ldhdr::l_istlen) x)
+ {
+ // FIXME: Add byte swapping if needed.
+ return static_cast<bool>(
+ this->Stream->write(reinterpret_cast<char const*>(&x), sizeof(x)));
+ }
+
+public:
+ Impl(cmXCOFF* external, std::unique_ptr<std::iostream> fin,
+ cmXCOFF::Mode mode);
+
+ cm::optional<cm::string_view> GetLibPath() override;
+ bool SetLibPath(cm::string_view libPath) override;
+ bool RemoveLibPath() override;
+};
+
+template <typename XCOFF>
+Impl<XCOFF>::Impl(cmXCOFF* external, std::unique_ptr<std::iostream> fin,
+ cmXCOFF::Mode mode)
+ : cmXCOFFInternal(external, std::move(fin), mode)
+{
+ if (!this->Read(this->FileHeader)) {
+ this->SetErrorMessage("Failed to read XCOFF file header.");
+ return;
+ }
+ if (this->FileHeader.f_opthdr != XCOFF::aouthdr_size) {
+ this->SetErrorMessage("XCOFF auxiliary header missing.");
+ return;
+ }
+ if (!this->Read(this->AuxHeader)) {
+ this->SetErrorMessage("Failed to read XCOFF auxiliary header.");
+ return;
+ }
+ if (this->AuxHeader.o_snloader == 0) {
+ this->SetErrorMessage("XCOFF loader section missing.");
+ return;
+ }
+ if (!this->Stream->seekg((this->AuxHeader.o_snloader - 1) *
+ sizeof(typename XCOFF::scnhdr),
+ std::ios::cur)) {
+ this->SetErrorMessage("Failed to seek to XCOFF loader section header.");
+ return;
+ }
+ if (!this->Read(this->LoaderSectionHeader)) {
+ this->SetErrorMessage("Failed to read XCOFF loader section header.");
+ return;
+ }
+ if ((this->LoaderSectionHeader.s_flags & STYP_LOADER) == 0) {
+ this->SetErrorMessage("XCOFF loader section header missing STYP_LOADER.");
+ return;
+ }
+ if (!this->Stream->seekg(this->LoaderSectionHeader.s_scnptr,
+ std::ios::beg)) {
+ this->SetErrorMessage("Failed to seek to XCOFF loader header.");
+ return;
+ }
+ if (!this->Read(this->LoaderHeader)) {
+ this->SetErrorMessage("Failed to read XCOFF loader header.");
+ return;
+ }
+ this->LoaderImportFileTablePos =
+ this->LoaderSectionHeader.s_scnptr + this->LoaderHeader.l_impoff;
+ if (!this->Stream->seekg(this->LoaderImportFileTablePos)) {
+ this->SetErrorMessage(
+ "Failed to seek to XCOFF loader import file id table.");
+ return;
+ }
+ this->LoaderImportFileTable.resize(this->LoaderHeader.l_istlen);
+ if (!this->Stream->read(this->LoaderImportFileTable.data(),
+ this->LoaderImportFileTable.size())) {
+ this->SetErrorMessage("Failed to read XCOFF loader import file id table.");
+ return;
+ }
+}
+
+template <typename XCOFF>
+cm::optional<cm::string_view> Impl<XCOFF>::GetLibPath()
+{
+ cm::optional<cm::string_view> result;
+ auto end = std::find(this->LoaderImportFileTable.begin(),
+ this->LoaderImportFileTable.end(), '\0');
+ if (end != this->LoaderImportFileTable.end()) {
+ result = cm::string_view(this->LoaderImportFileTable.data(),
+ end - this->LoaderImportFileTable.begin());
+ }
+ return result;
+}
+
+template <typename XCOFF>
+bool Impl<XCOFF>::SetLibPath(cm::string_view libPath)
+{
+ // The new LIBPATH must end in the standard AIX LIBPATH.
+#define CM_AIX_LIBPATH "/usr/lib:/lib"
+ std::string libPathBuf;
+ if (libPath != CM_AIX_LIBPATH &&
+ !cmHasLiteralSuffix(libPath, ":" CM_AIX_LIBPATH)) {
+ libPathBuf = std::string(libPath);
+ if (!libPathBuf.empty() && libPathBuf.back() != ':') {
+ libPathBuf.push_back(':');
+ }
+ libPathBuf += CM_AIX_LIBPATH;
+ libPath = libPathBuf;
+ }
+#undef CM_AIX_LIBPATH
+
+ auto oldEnd = std::find(this->LoaderImportFileTable.begin(),
+ this->LoaderImportFileTable.end(), '\0');
+ if (oldEnd == this->LoaderImportFileTable.end()) {
+ this->SetErrorMessage("XCOFF loader import file id table is invalid.");
+ return false;
+ }
+ if ((this->LoaderImportFileTable.begin() + libPath.size()) > oldEnd) {
+ this->SetErrorMessage("XCOFF loader import file id table is too small.");
+ return false;
+ }
+
+ {
+ std::vector<char> ift;
+ ift.reserve(this->LoaderImportFileTable.size());
+ // Start with the new LIBPATH.
+ ift.insert(ift.end(), libPath.begin(), libPath.end());
+ // Add the rest of the original table.
+ ift.insert(ift.end(), oldEnd, this->LoaderImportFileTable.end());
+ // If the new table is shorter, zero out the leftover space.
+ ift.resize(this->LoaderImportFileTable.size(), 0);
+ this->LoaderHeader.l_istlen =
+ static_cast<decltype(XCOFF::ldhdr::l_istlen)>(ift.size());
+ this->LoaderImportFileTable = std::move(ift);
+ }
+
+ if (!this->Stream->seekp(this->LoaderSectionHeader.s_scnptr +
+ offsetof(typename XCOFF::ldhdr, l_istlen),
+ std::ios::beg)) {
+ this->SetErrorMessage(
+ "Failed to seek to XCOFF loader header import file id table length.");
+ return false;
+ }
+ if (!this->WriteLoaderImportFileTableLength(this->LoaderHeader.l_istlen)) {
+ this->SetErrorMessage(
+ "Failed to write XCOFF loader header import file id table length.");
+ return false;
+ }
+ if (!this->Stream->seekp(this->LoaderImportFileTablePos, std::ios::beg)) {
+ this->SetErrorMessage(
+ "Failed to seek to XCOFF loader import file id table.");
+ return false;
+ }
+ if (!this->Stream->write(this->LoaderImportFileTable.data(),
+ this->LoaderImportFileTable.size())) {
+ this->SetErrorMessage(
+ "Failed to write XCOFF loader import file id table.");
+ return false;
+ }
+
+ return true;
+}
+
+template <typename XCOFF>
+bool Impl<XCOFF>::RemoveLibPath()
+{
+ return this->SetLibPath({});
+}
+}
+
+//============================================================================
+// External class implementation.
+
+cmXCOFF::cmXCOFF(const char* fname, Mode mode)
+{
+ // Try to open the file.
+ std::ios::openmode fmode = std::ios::in | std::ios::binary;
+ if (mode == Mode::ReadWrite) {
+ fmode |= std::ios::out;
+ }
+ auto f = cm::make_unique<cmsys::fstream>(fname, fmode);
+
+ // Quit now if the file could not be opened.
+ if (!f || !*f) {
+ this->ErrorMessage = "Error opening input file.";
+ return;
+ }
+
+ // Read the XCOFF magic number.
+ unsigned char magic[2];
+ if (!f->read(reinterpret_cast<char*>(magic), sizeof(magic))) {
+ this->ErrorMessage = "Error reading XCOFF magic number.";
+ return;
+ }
+ if (!f->seekg(0)) {
+ this->ErrorMessage = "Error seeking to beginning of file.";
+ return;
+ }
+
+ // Check the XCOFF type.
+ if (magic[0] == xcoff32_magic[0] && magic[1] == xcoff32_magic[1]) {
+ this->Internal = cm::make_unique<Impl<XCOFF32>>(this, std::move(f), mode);
+ } else if (magic[0] == xcoff64_magic[0] && magic[1] == xcoff64_magic[1]) {
+ this->Internal = cm::make_unique<Impl<XCOFF64>>(this, std::move(f), mode);
+ } else {
+ this->ErrorMessage = "File is not a XCOFF32 or XCOFF64 binary.";
+ }
+}
+
+cmXCOFF::~cmXCOFF() = default;
+
+cmXCOFF::cmXCOFF(cmXCOFF&&) = default;
+cmXCOFF& cmXCOFF::operator=(cmXCOFF&&) = default;
+
+bool cmXCOFF::Valid() const
+{
+ return this->Internal && this->ErrorMessage.empty();
+}
+
+cm::optional<cm::string_view> cmXCOFF::GetLibPath() const
+{
+ cm::optional<cm::string_view> result;
+ if (this->Valid()) {
+ result = this->Internal->GetLibPath();
+ }
+ return result;
+}
+
+bool cmXCOFF::SetLibPath(cm::string_view libPath)
+{
+ return this->Valid() && this->Internal->GetMode() == Mode::ReadWrite &&
+ this->Internal->SetLibPath(libPath);
+}
+
+bool cmXCOFF::RemoveLibPath()
+{
+ return this->Valid() && this->Internal->GetMode() == Mode::ReadWrite &&
+ this->Internal->RemoveLibPath();
+}
diff --git a/Source/cmXCOFF.h b/Source/cmXCOFF.h
new file mode 100644
index 0000000..16cda9d
--- /dev/null
+++ b/Source/cmXCOFF.h
@@ -0,0 +1,65 @@
+/* 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 <iosfwd>
+#include <memory>
+#include <string>
+
+#include <cm/optional>
+#include <cm/string_view>
+
+#if !defined(CMake_USE_XCOFF_PARSER)
+# error "This file may be included only if CMake_USE_XCOFF_PARSER is enabled."
+#endif
+
+class cmXCOFFInternal;
+
+/** \class cmXCOFF
+ * \brief XCOFF parser.
+ */
+class cmXCOFF
+{
+public:
+ enum class Mode
+ {
+ ReadOnly,
+ ReadWrite
+ };
+
+ /** Construct with the name of the XCOFF input file to parse. */
+ cmXCOFF(const char* fname, Mode = Mode::ReadOnly);
+
+ /** Destruct. */
+ ~cmXCOFF();
+
+ cmXCOFF(cmXCOFF&&);
+ cmXCOFF(cmXCOFF const&) = delete;
+ cmXCOFF& operator=(cmXCOFF&&);
+ cmXCOFF& operator=(cmXCOFF const&) = delete;
+
+ /** Get the error message if any. */
+ std::string const& GetErrorMessage() const { return this->ErrorMessage; }
+
+ /** Boolean conversion. True if the XCOFF file is valid. */
+ explicit operator bool() const { return this->Valid(); }
+
+ /** Get the LIBPATH (RPATH) parsed from the file, if any. */
+ cm::optional<cm::string_view> GetLibPath() const;
+
+ /** Set the LIBPATH (RPATH).
+ Works only if cmXCOFF was constructed with Mode::ReadWrite. */
+ bool SetLibPath(cm::string_view libPath);
+
+ /** Remove the LIBPATH (RPATH).
+ Works only if cmXCOFF was constructed with Mode::ReadWrite. */
+ bool RemoveLibPath();
+
+private:
+ friend class cmXCOFFInternal;
+ bool Valid() const;
+ std::unique_ptr<cmXCOFFInternal> Internal;
+ std::string ErrorMessage;
+};
diff --git a/Source/cmXCode21Object.cxx b/Source/cmXCode21Object.cxx
new file mode 100644
index 0000000..9b0dc58
--- /dev/null
+++ b/Source/cmXCode21Object.cxx
@@ -0,0 +1,88 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmXCode21Object.h"
+
+#include <ostream>
+#include <string>
+#include <utility>
+
+#include "cmSystemTools.h"
+
+cmXCode21Object::cmXCode21Object(PBXType ptype, Type type, std::string id)
+ : cmXCodeObject(ptype, type, std::move(id))
+{
+ this->Version = 21;
+}
+
+void cmXCode21Object::PrintComment(std::ostream& out)
+{
+ if (this->Comment.empty()) {
+ cmXCodeObject* n = this->GetAttribute("name");
+ if (n) {
+ this->Comment = n->GetString();
+ cmSystemTools::ReplaceString(this->Comment, "\"", "");
+ }
+ }
+ if (this->Comment.empty()) {
+ return;
+ }
+ out << " /* ";
+ out << this->Comment;
+ out << " */";
+}
+
+void cmXCode21Object::PrintList(
+ std::vector<std::unique_ptr<cmXCodeObject>> const& v, std::ostream& out,
+ PBXType t)
+{
+ bool hasOne = false;
+ for (const auto& obj : v) {
+ if (obj->GetType() == OBJECT && obj->GetIsA() == t) {
+ hasOne = true;
+ break;
+ }
+ }
+ if (!hasOne) {
+ return;
+ }
+ out << "\n/* Begin " << PBXTypeNames[t] << " section */\n";
+ for (const auto& obj : v) {
+ if (obj->GetType() == OBJECT && obj->GetIsA() == t) {
+ obj->Print(out);
+ }
+ }
+ out << "/* End " << PBXTypeNames[t] << " section */\n";
+}
+
+void cmXCode21Object::PrintList(
+ std::vector<std::unique_ptr<cmXCodeObject>> const& v, std::ostream& out)
+{
+ cmXCodeObject::Indent(1, out);
+ out << "objects = {\n";
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXAggregateTarget);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXBuildFile);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXBuildStyle);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXContainerItemProxy);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXFileReference);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXFrameworksBuildPhase);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXGroup);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXHeadersBuildPhase);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXNativeTarget);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXProject);
+ cmXCode21Object::PrintList(v, out,
+ cmXCode21Object::PBXShellScriptBuildPhase);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXResourcesBuildPhase);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXSourcesBuildPhase);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXCopyFilesBuildPhase);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXApplicationReference);
+ cmXCode21Object::PrintList(v, out,
+ cmXCode21Object::PBXExecutableFileReference);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXLibraryReference);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXToolTarget);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXLibraryTarget);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::PBXTargetDependency);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::XCBuildConfiguration);
+ cmXCode21Object::PrintList(v, out, cmXCode21Object::XCConfigurationList);
+ cmXCodeObject::Indent(1, out);
+ out << "};\n";
+}
diff --git a/Source/cmXCode21Object.h b/Source/cmXCode21Object.h
new file mode 100644
index 0000000..f3fc438
--- /dev/null
+++ b/Source/cmXCode21Object.h
@@ -0,0 +1,22 @@
+/* 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 <iosfwd>
+#include <memory>
+#include <vector>
+
+#include "cmXCodeObject.h"
+
+class cmXCode21Object : public cmXCodeObject
+{
+public:
+ cmXCode21Object(PBXType ptype, Type type, std::string id);
+ void PrintComment(std::ostream&) override;
+ static void PrintList(std::vector<std::unique_ptr<cmXCodeObject>> const&,
+ std::ostream& out, PBXType t);
+ static void PrintList(std::vector<std::unique_ptr<cmXCodeObject>> const&,
+ std::ostream& out);
+};
diff --git a/Source/cmXCodeObject.cxx b/Source/cmXCodeObject.cxx
new file mode 100644
index 0000000..d5c5275
--- /dev/null
+++ b/Source/cmXCodeObject.cxx
@@ -0,0 +1,233 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmXCodeObject.h"
+
+#include <ostream>
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "cmSystemTools.h"
+
+const char* cmXCodeObject::PBXTypeNames[] = {
+ /* clang-format needs this comment to break after the opening brace */
+ "PBXGroup",
+ "PBXBuildStyle",
+ "PBXProject",
+ "PBXHeadersBuildPhase",
+ "PBXSourcesBuildPhase",
+ "PBXFrameworksBuildPhase",
+ "PBXNativeTarget",
+ "PBXFileReference",
+ "PBXBuildFile",
+ "PBXContainerItemProxy",
+ "PBXTargetDependency",
+ "PBXShellScriptBuildPhase",
+ "PBXResourcesBuildPhase",
+ "PBXApplicationReference",
+ "PBXExecutableFileReference",
+ "PBXLibraryReference",
+ "PBXToolTarget",
+ "PBXLibraryTarget",
+ "PBXAggregateTarget",
+ "XCBuildConfiguration",
+ "XCConfigurationList",
+ "PBXCopyFilesBuildPhase",
+ "None"
+};
+
+cmXCodeObject::~cmXCodeObject()
+{
+ this->Version = 15;
+}
+
+cmXCodeObject::cmXCodeObject(PBXType ptype, Type type, std::string id)
+{
+ this->Version = 15;
+ this->Target = nullptr;
+ this->Object = nullptr;
+
+ this->IsA = ptype;
+
+ this->Id = std::move(id);
+
+ this->TypeValue = type;
+ if (this->TypeValue == OBJECT) {
+ this->AddAttribute("isa", nullptr);
+ }
+}
+
+bool cmXCodeObject::IsEmpty() const
+{
+ switch (this->TypeValue) {
+ case OBJECT_LIST:
+ return this->List.empty();
+ case STRING:
+ return this->String.empty();
+ case ATTRIBUTE_GROUP:
+ return this->ObjectAttributes.empty();
+ case OBJECT_REF:
+ case OBJECT:
+ return this->Object == nullptr;
+ }
+ return true; // unreachable, but quiets warnings
+}
+
+void cmXCodeObject::Indent(int level, std::ostream& out)
+{
+ while (level) {
+ out << "\t";
+ level--;
+ }
+}
+
+void cmXCodeObject::Print(std::ostream& out)
+{
+ std::string separator = "\n";
+ int indentFactor = 1;
+ cmXCodeObject::Indent(2 * indentFactor, out);
+ if (this->Version > 15 &&
+ (this->IsA == PBXFileReference || this->IsA == PBXBuildFile)) {
+ separator = " ";
+ indentFactor = 0;
+ }
+ out << this->Id;
+ this->PrintComment(out);
+ out << " = {";
+ if (separator == "\n") {
+ out << separator;
+ }
+ cmXCodeObject::Indent(3 * indentFactor, out);
+ out << "isa = " << PBXTypeNames[this->IsA] << ";" << separator;
+ for (const auto& keyVal : this->ObjectAttributes) {
+ if (keyVal.first == "isa") {
+ continue;
+ }
+
+ PrintAttribute(out, 3, separator, indentFactor, keyVal.first,
+ keyVal.second, this);
+ }
+ cmXCodeObject::Indent(2 * indentFactor, out);
+ out << "};\n";
+}
+
+void cmXCodeObject::PrintAttribute(std::ostream& out, int level,
+ const std::string& separator, int factor,
+ const std::string& name,
+ const cmXCodeObject* object,
+ const cmXCodeObject* parent)
+{
+ cmXCodeObject::Indent(level * factor, out);
+ switch (object->TypeValue) {
+ case OBJECT_LIST: {
+ out << name << " = (";
+ if (parent->TypeValue != ATTRIBUTE_GROUP) {
+ out << separator;
+ }
+ for (unsigned int i = 0; i < object->List.size(); ++i) {
+ if (object->List[i]->TypeValue == STRING) {
+ object->List[i]->PrintString(out);
+ if (i + 1 < object->List.size()) {
+ out << ",";
+ }
+ } else {
+ cmXCodeObject::Indent((level + 1) * factor, out);
+ out << object->List[i]->Id;
+ object->List[i]->PrintComment(out);
+ out << "," << separator;
+ }
+ }
+ if (parent->TypeValue != ATTRIBUTE_GROUP) {
+ cmXCodeObject::Indent(level * factor, out);
+ }
+ out << ");" << separator;
+ } break;
+
+ case ATTRIBUTE_GROUP: {
+ out << name << " = {";
+ if (separator == "\n") {
+ out << separator;
+ }
+ for (const auto& keyVal : object->ObjectAttributes) {
+ PrintAttribute(out, (level + 1) * factor, separator, factor,
+ keyVal.first, keyVal.second, object);
+ }
+ cmXCodeObject::Indent(level * factor, out);
+ out << "};" << separator;
+ } break;
+
+ case OBJECT_REF: {
+ cmXCodeObject::PrintString(out, name);
+ out << " = " << object->Object->Id;
+ if (object->Object->HasComment() && name != "remoteGlobalIDString") {
+ object->Object->PrintComment(out);
+ }
+ out << ";" << separator;
+ } break;
+
+ case STRING: {
+ cmXCodeObject::PrintString(out, name);
+ out << " = ";
+ object->PrintString(out);
+ out << ";" << separator;
+ } break;
+
+ default: {
+ break;
+ }
+ }
+}
+
+void cmXCodeObject::PrintList(std::vector<cmXCodeObject*> const& objs,
+ std::ostream& out)
+{
+ cmXCodeObject::Indent(1, out);
+ out << "objects = {\n";
+ for (auto obj : objs) {
+ if (obj->TypeValue == OBJECT) {
+ obj->Print(out);
+ }
+ }
+ cmXCodeObject::Indent(1, out);
+ out << "};\n";
+}
+
+void cmXCodeObject::CopyAttributes(cmXCodeObject* copy)
+{
+ this->ObjectAttributes = copy->ObjectAttributes;
+ this->List = copy->List;
+ this->String = copy->String;
+ this->Object = copy->Object;
+}
+
+void cmXCodeObject::PrintString(std::ostream& os, const std::string& String)
+{
+ // The string needs to be quoted if it contains any characters
+ // considered special by the Xcode project file parser.
+ bool needQuote = (String.empty() || String.find("//") != std::string::npos ||
+ String.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "$_./") != std::string::npos);
+ const char* quote = needQuote ? "\"" : "";
+
+ // Print the string, quoted and escaped as necessary.
+ os << quote;
+ for (auto c : String) {
+ if (c == '"' || c == '\\') {
+ // Escape double-quotes and backslashes.
+ os << '\\';
+ }
+ os << c;
+ }
+ os << quote;
+}
+
+void cmXCodeObject::PrintString(std::ostream& os) const
+{
+ cmXCodeObject::PrintString(os, this->String);
+}
+
+void cmXCodeObject::SetString(const std::string& s)
+{
+ this->String = s;
+}
diff --git a/Source/cmXCodeObject.h b/Source/cmXCodeObject.h
new file mode 100644
index 0000000..dd5e86e
--- /dev/null
+++ b/Source/cmXCodeObject.h
@@ -0,0 +1,179 @@
+/* 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 <algorithm>
+#include <iosfwd>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cmext/algorithm>
+
+class cmGeneratorTarget;
+
+class cmXCodeObject
+{
+public:
+ enum Type
+ {
+ OBJECT_LIST,
+ STRING,
+ ATTRIBUTE_GROUP,
+ OBJECT_REF,
+ OBJECT
+ };
+ enum PBXType
+ {
+ PBXGroup,
+ PBXBuildStyle,
+ PBXProject,
+ PBXHeadersBuildPhase,
+ PBXSourcesBuildPhase,
+ PBXFrameworksBuildPhase,
+ PBXNativeTarget,
+ PBXFileReference,
+ PBXBuildFile,
+ PBXContainerItemProxy,
+ PBXTargetDependency,
+ PBXShellScriptBuildPhase,
+ PBXResourcesBuildPhase,
+ PBXApplicationReference,
+ PBXExecutableFileReference,
+ PBXLibraryReference,
+ PBXToolTarget,
+ PBXLibraryTarget,
+ PBXAggregateTarget,
+ XCBuildConfiguration,
+ XCConfigurationList,
+ PBXCopyFilesBuildPhase,
+ None
+ };
+ class StringVec : public std::vector<std::string>
+ {
+ };
+ static const char* PBXTypeNames[];
+ virtual ~cmXCodeObject();
+ cmXCodeObject(PBXType ptype, Type type, std::string id);
+ Type GetType() const { return this->TypeValue; }
+ PBXType GetIsA() const { return this->IsA; }
+
+ bool IsEmpty() const;
+
+ void SetString(const std::string& s);
+ const std::string& GetString() const { return this->String; }
+
+ void AddAttribute(const std::string& name, cmXCodeObject* value)
+ {
+ this->ObjectAttributes[name] = value;
+ }
+
+ void AddAttributeIfNotEmpty(const std::string& name, cmXCodeObject* value)
+ {
+ if (value && !value->IsEmpty()) {
+ AddAttribute(name, value);
+ }
+ }
+
+ void SetObject(cmXCodeObject* value) { this->Object = value; }
+ cmXCodeObject* GetObject() { return this->Object; }
+ void AddObject(cmXCodeObject* value) { this->List.push_back(value); }
+ size_t GetObjectCount() { return this->List.size(); }
+ void InsertObject(size_t position, cmXCodeObject* value)
+ {
+ if (position < GetObjectCount()) {
+ this->List.insert(this->List.begin() + position, value);
+ }
+ }
+ void PrependObject(cmXCodeObject* value)
+ {
+ this->List.insert(this->List.begin(), value);
+ }
+ bool HasObject(cmXCodeObject* o) const
+ {
+ return cm::contains(this->List, o);
+ }
+ void AddUniqueObject(cmXCodeObject* value)
+ {
+ if (!cm::contains(this->List, value)) {
+ this->List.push_back(value);
+ }
+ }
+ static void Indent(int level, std::ostream& out);
+ void Print(std::ostream& out);
+ void PrintAttribute(std::ostream& out, int level,
+ const std::string& separator, int factor,
+ const std::string& name, const cmXCodeObject* object,
+ const cmXCodeObject* parent);
+ virtual void PrintComment(std::ostream&) {}
+
+ static void PrintList(std::vector<cmXCodeObject*> const&, std::ostream& out);
+ const std::string& GetId() const { return this->Id; }
+ void SetId(const std::string& id) { this->Id = id; }
+ cmGeneratorTarget* GetTarget() const { return this->Target; }
+ void SetTarget(cmGeneratorTarget* t) { this->Target = t; }
+ const std::string& GetComment() const { return this->Comment; }
+ bool HasComment() const { return (!this->Comment.empty()); }
+ cmXCodeObject* GetAttribute(const char* name) const
+ {
+ auto const i = this->ObjectAttributes.find(name);
+ if (i != this->ObjectAttributes.end()) {
+ return i->second;
+ }
+ return nullptr;
+ }
+ // search the attribute list for an object of the specified type
+ cmXCodeObject* GetObject(cmXCodeObject::PBXType t) const
+ {
+ for (auto o : this->List) {
+ if (o->IsA == t) {
+ return o;
+ }
+ }
+ return nullptr;
+ }
+
+ void CopyAttributes(cmXCodeObject*);
+
+ void AddDependLibrary(const std::string& configName, const std::string& l)
+ {
+ this->DependLibraries[configName].push_back(l);
+ }
+ std::map<std::string, StringVec> const& GetDependLibraries() const
+ {
+ return this->DependLibraries;
+ }
+ void AddDependTarget(const std::string& configName, const std::string& tName)
+ {
+ this->DependTargets[configName].push_back(tName);
+ }
+ std::map<std::string, StringVec> const& GetDependTargets() const
+ {
+ return this->DependTargets;
+ }
+ std::vector<cmXCodeObject*> const& GetObjectList() const
+ {
+ return this->List;
+ }
+ void SetComment(const std::string& c) { this->Comment = c; }
+ static void PrintString(std::ostream& os, const std::string& String);
+
+protected:
+ void PrintString(std::ostream& os) const;
+
+ cmGeneratorTarget* Target;
+ Type TypeValue;
+ std::string Id;
+ PBXType IsA;
+ int Version;
+ std::string Comment;
+ std::string String;
+ cmXCodeObject* Object;
+ std::vector<cmXCodeObject*> List;
+ std::map<std::string, StringVec> DependLibraries;
+ std::map<std::string, StringVec> DependTargets;
+ std::map<std::string, cmXCodeObject*> ObjectAttributes;
+};
diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx
new file mode 100644
index 0000000..55e941d
--- /dev/null
+++ b/Source/cmXCodeScheme.cxx
@@ -0,0 +1,455 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmXCodeScheme.h"
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <utility>
+
+#include <cmext/algorithm>
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmXMLSafe.h"
+
+cmXCodeScheme::cmXCodeScheme(cmLocalGenerator* lg, cmXCodeObject* xcObj,
+ TestObjects tests,
+ const std::vector<std::string>& configList,
+ unsigned int xcVersion)
+ : LocalGenerator(lg)
+ , Target(xcObj)
+ , Tests(std::move(tests))
+ , TargetName(xcObj->GetTarget()->GetName())
+ , ConfigList(configList)
+ , XcodeVersion(xcVersion)
+{
+}
+
+void cmXCodeScheme::WriteXCodeSharedScheme(const std::string& xcProjDir,
+ const std::string& container)
+{
+ // Create shared scheme sub-directory tree
+ //
+ std::string xcodeSchemeDir = cmStrCat(xcProjDir, "/xcshareddata/xcschemes");
+ cmSystemTools::MakeDirectory(xcodeSchemeDir);
+
+ std::string xcodeSchemeFile =
+ cmStrCat(xcodeSchemeDir, '/', this->TargetName, ".xcscheme");
+
+ cmGeneratedFileStream fout(xcodeSchemeFile);
+ fout.SetCopyIfDifferent(true);
+ if (!fout) {
+ return;
+ }
+
+ WriteXCodeXCScheme(fout, container);
+}
+
+void cmXCodeScheme::WriteXCodeXCScheme(std::ostream& fout,
+ const std::string& container)
+{
+ cmXMLWriter xout(fout);
+ xout.SetIndentationElement(std::string(3, ' '));
+ xout.StartDocument();
+
+ xout.StartElement("Scheme");
+ xout.BreakAttributes();
+ xout.Attribute("LastUpgradeVersion", WriteVersionString());
+ xout.Attribute("version", "1.3");
+
+ WriteBuildAction(xout, container);
+ WriteTestAction(xout, FindConfiguration("Debug"), container);
+ WriteLaunchAction(xout, FindConfiguration("Debug"), container);
+ WriteProfileAction(xout, FindConfiguration("Release"));
+ WriteAnalyzeAction(xout, FindConfiguration("Debug"));
+ WriteArchiveAction(xout, FindConfiguration("Release"));
+
+ xout.EndElement();
+}
+
+void cmXCodeScheme::WriteBuildAction(cmXMLWriter& xout,
+ const std::string& container)
+{
+ xout.StartElement("BuildAction");
+ xout.BreakAttributes();
+ xout.Attribute("parallelizeBuildables", "YES");
+ xout.Attribute("buildImplicitDependencies", "YES");
+
+ xout.StartElement("BuildActionEntries");
+ xout.StartElement("BuildActionEntry");
+ xout.BreakAttributes();
+ xout.Attribute("buildForTesting", "YES");
+ xout.Attribute("buildForRunning", "YES");
+ xout.Attribute("buildForProfiling", "YES");
+ xout.Attribute("buildForArchiving", "YES");
+ xout.Attribute("buildForAnalyzing", "YES");
+
+ WriteBuildableReference(xout, this->Target, container);
+
+ xout.EndElement(); // BuildActionEntry
+ xout.EndElement(); // BuildActionEntries
+ xout.EndElement(); // BuildAction
+}
+
+void cmXCodeScheme::WriteTestAction(cmXMLWriter& xout,
+ const std::string& configuration,
+ const std::string& container)
+{
+ xout.StartElement("TestAction");
+ xout.BreakAttributes();
+ xout.Attribute("buildConfiguration", configuration);
+ xout.Attribute("selectedDebuggerIdentifier",
+ "Xcode.DebuggerFoundation.Debugger.LLDB");
+ xout.Attribute("selectedLauncherIdentifier",
+ "Xcode.DebuggerFoundation.Launcher.LLDB");
+ xout.Attribute("shouldUseLaunchSchemeArgsEnv", "YES");
+
+ xout.StartElement("Testables");
+ for (auto test : this->Tests) {
+ xout.StartElement("TestableReference");
+ xout.BreakAttributes();
+ xout.Attribute("skipped", "NO");
+ WriteBuildableReference(xout, test, container);
+ xout.EndElement(); // TestableReference
+ }
+ xout.EndElement();
+
+ if (IsTestable()) {
+ xout.StartElement("MacroExpansion");
+ WriteBuildableReference(xout, this->Target, container);
+ xout.EndElement(); // MacroExpansion
+ }
+
+ xout.StartElement("AdditionalOptions");
+ xout.EndElement();
+
+ xout.EndElement(); // TestAction
+}
+
+void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout,
+ const std::string& configuration,
+ const std::string& container)
+{
+ xout.StartElement("LaunchAction");
+ xout.BreakAttributes();
+ xout.Attribute("buildConfiguration", configuration);
+ xout.Attribute("selectedDebuggerIdentifier",
+ "Xcode.DebuggerFoundation.Debugger.LLDB");
+ xout.Attribute("selectedLauncherIdentifier",
+ "Xcode.DebuggerFoundation.Launcher.LLDB");
+ xout.Attribute("launchStyle", "0");
+ WriteCustomWorkingDirectory(xout, configuration);
+
+ xout.Attribute("ignoresPersistentStateOnLaunch", "NO");
+ WriteLaunchActionBooleanAttribute(xout, "debugDocumentVersioning",
+ "XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING",
+ true);
+ xout.Attribute("debugServiceExtension", "internal");
+ xout.Attribute("allowLocationSimulation", "YES");
+
+ // Diagnostics tab begin
+
+ bool useAddressSanitizer = WriteLaunchActionAttribute(
+ xout, "enableAddressSanitizer",
+ "XCODE_SCHEME_ADDRESS_SANITIZER"); // not allowed with
+ // enableThreadSanitizer=YES
+ WriteLaunchActionAttribute(
+ xout, "enableASanStackUseAfterReturn",
+ "XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN");
+
+ bool useThreadSanitizer = false;
+ if (!useAddressSanitizer) {
+ useThreadSanitizer = WriteLaunchActionAttribute(
+ xout, "enableThreadSanitizer",
+ "XCODE_SCHEME_THREAD_SANITIZER"); // not allowed with
+ // enableAddressSanitizer=YES
+ }
+
+ WriteLaunchActionAttribute(xout, "stopOnEveryThreadSanitizerIssue",
+ "XCODE_SCHEME_THREAD_SANITIZER_STOP");
+
+ WriteLaunchActionAttribute(xout, "enableUBSanitizer",
+ "XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER");
+ WriteLaunchActionAttribute(
+ xout, "stopOnEveryUBSanitizerIssue",
+ "XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP");
+
+ WriteLaunchActionAttribute(
+ xout, "disableMainThreadChecker",
+ "XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER"); // negative enabled!
+ WriteLaunchActionAttribute(xout, "stopOnEveryMainThreadCheckerIssue",
+ "XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP");
+
+ if (this->Target->GetTarget()->GetPropertyAsBool(
+ "XCODE_SCHEME_DEBUG_AS_ROOT")) {
+ xout.Attribute("debugAsWhichUser", "root");
+ }
+
+ // Diagnostics tab end
+
+ if (IsExecutable(this->Target)) {
+ xout.StartElement("BuildableProductRunnable");
+ xout.BreakAttributes();
+ xout.Attribute("runnableDebuggingMode", "0");
+
+ } else {
+ xout.StartElement("MacroExpansion");
+ }
+
+ WriteBuildableReference(xout, this->Target, container);
+
+ xout.EndElement(); // MacroExpansion
+
+ // Info tab begin
+
+ if (cmProp exe =
+ this->Target->GetTarget()->GetProperty("XCODE_SCHEME_EXECUTABLE")) {
+
+ xout.StartElement("PathRunnable");
+ xout.BreakAttributes();
+
+ xout.Attribute("runnableDebuggingMode", "0");
+ xout.Attribute("FilePath", *exe);
+
+ xout.EndElement(); // PathRunnable
+ }
+
+ // Info tab end
+
+ // Arguments tab begin
+
+ if (cmProp argList =
+ this->Target->GetTarget()->GetProperty("XCODE_SCHEME_ARGUMENTS")) {
+ std::vector<std::string> arguments = cmExpandedList(*argList);
+ if (!arguments.empty()) {
+ xout.StartElement("CommandLineArguments");
+
+ for (auto const& argument : arguments) {
+ xout.StartElement("CommandLineArgument");
+ xout.BreakAttributes();
+
+ xout.Attribute("argument", argument);
+ xout.Attribute("isEnabled", "YES");
+
+ xout.EndElement(); // CommandLineArgument
+ }
+
+ xout.EndElement(); // CommandLineArguments
+ }
+ }
+
+ if (cmProp envList =
+ this->Target->GetTarget()->GetProperty("XCODE_SCHEME_ENVIRONMENT")) {
+ std::vector<std::string> envs = cmExpandedList(*envList);
+ if (!envs.empty()) {
+ xout.StartElement("EnvironmentVariables");
+
+ for (auto env : envs) {
+
+ xout.StartElement("EnvironmentVariable");
+ xout.BreakAttributes();
+
+ std::string envValue;
+ const auto p = env.find_first_of('=');
+ if (p != std::string::npos) {
+ envValue = env.substr(p + 1);
+ env.resize(p);
+ }
+
+ xout.Attribute("key", env);
+ xout.Attribute("value", envValue);
+ xout.Attribute("isEnabled", "YES");
+
+ xout.EndElement(); // EnvironmentVariable
+ }
+
+ xout.EndElement(); // EnvironmentVariables
+ }
+ }
+
+ // Arguments tab end
+
+ xout.StartElement("AdditionalOptions");
+
+ if (!useThreadSanitizer) {
+ WriteLaunchActionAdditionalOption(xout, "MallocScribble", "",
+ "XCODE_SCHEME_MALLOC_SCRIBBLE");
+ }
+
+ if (!useThreadSanitizer && !useAddressSanitizer) {
+ WriteLaunchActionAdditionalOption(xout, "MallocGuardEdges", "",
+ "XCODE_SCHEME_MALLOC_GUARD_EDGES");
+ }
+
+ if (!useThreadSanitizer && !useAddressSanitizer) {
+ WriteLaunchActionAdditionalOption(xout, "DYLD_INSERT_LIBRARIES",
+ "/usr/lib/libgmalloc.dylib",
+ "XCODE_SCHEME_GUARD_MALLOC");
+ }
+
+ WriteLaunchActionAdditionalOption(xout, "NSZombieEnabled", "YES",
+ "XCODE_SCHEME_ZOMBIE_OBJECTS");
+
+ if (!useThreadSanitizer && !useAddressSanitizer) {
+ WriteLaunchActionAdditionalOption(xout, "MallocStackLogging", "",
+ "XCODE_SCHEME_MALLOC_STACK");
+ }
+
+ WriteLaunchActionAdditionalOption(xout, "DYLD_PRINT_APIS", "",
+ "XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE");
+
+ WriteLaunchActionAdditionalOption(xout, "DYLD_PRINT_LIBRARIES", "",
+ "XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS");
+
+ xout.EndElement();
+
+ xout.EndElement(); // LaunchAction
+}
+
+bool cmXCodeScheme::WriteLaunchActionAttribute(cmXMLWriter& xout,
+ const std::string& attrName,
+ const std::string& varName)
+{
+ if (Target->GetTarget()->GetPropertyAsBool(varName)) {
+ xout.Attribute(attrName.c_str(), "YES");
+ return true;
+ }
+ return false;
+}
+
+bool cmXCodeScheme::WriteLaunchActionBooleanAttribute(
+ cmXMLWriter& xout, const std::string& attrName, const std::string& varName,
+ bool defaultValue)
+{
+ cmProp property = Target->GetTarget()->GetProperty(varName);
+ bool isOn = (property == nullptr && defaultValue) || cmIsOn(property);
+
+ if (isOn) {
+ xout.Attribute(attrName.c_str(), "YES");
+ } else {
+ xout.Attribute(attrName.c_str(), "NO");
+ }
+ return isOn;
+}
+
+bool cmXCodeScheme::WriteLaunchActionAdditionalOption(
+ cmXMLWriter& xout, const std::string& key, const std::string& value,
+ const std::string& varName)
+{
+ if (Target->GetTarget()->GetPropertyAsBool(varName)) {
+ xout.StartElement("AdditionalOption");
+ xout.BreakAttributes();
+
+ xout.Attribute("key", key);
+ xout.Attribute("value", value);
+ xout.Attribute("isEnabled", "YES");
+
+ xout.EndElement(); // AdditionalOption
+
+ return true;
+ }
+ return false;
+}
+
+void cmXCodeScheme::WriteProfileAction(cmXMLWriter& xout,
+ const std::string& configuration)
+{
+ xout.StartElement("ProfileAction");
+ xout.BreakAttributes();
+ xout.Attribute("buildConfiguration", configuration);
+ xout.Attribute("shouldUseLaunchSchemeArgsEnv", "YES");
+ xout.Attribute("savedToolIdentifier", "");
+ WriteCustomWorkingDirectory(xout, configuration);
+ WriteLaunchActionBooleanAttribute(xout, "debugDocumentVersioning",
+ "XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING",
+ true);
+ xout.EndElement();
+}
+
+void cmXCodeScheme::WriteAnalyzeAction(cmXMLWriter& xout,
+ const std::string& configuration)
+{
+ xout.StartElement("AnalyzeAction");
+ xout.BreakAttributes();
+ xout.Attribute("buildConfiguration", configuration);
+ xout.EndElement();
+}
+
+void cmXCodeScheme::WriteArchiveAction(cmXMLWriter& xout,
+ const std::string& configuration)
+{
+ xout.StartElement("ArchiveAction");
+ xout.BreakAttributes();
+ xout.Attribute("buildConfiguration", configuration);
+ xout.Attribute("revealArchiveInOrganizer", "YES");
+ xout.EndElement();
+}
+
+void cmXCodeScheme::WriteBuildableReference(cmXMLWriter& xout,
+ const cmXCodeObject* xcObj,
+ const std::string& container)
+{
+ xout.StartElement("BuildableReference");
+ xout.BreakAttributes();
+ xout.Attribute("BuildableIdentifier", "primary");
+ xout.Attribute("BlueprintIdentifier", xcObj->GetId());
+ std::string const noConfig; // FIXME: What config to use here?
+ xout.Attribute("BuildableName", xcObj->GetTarget()->GetFullName(noConfig));
+ xout.Attribute("BlueprintName", xcObj->GetTarget()->GetName());
+ xout.Attribute("ReferencedContainer", "container:" + container);
+ xout.EndElement();
+}
+
+void cmXCodeScheme::WriteCustomWorkingDirectory(
+ cmXMLWriter& xout, const std::string& configuration)
+{
+ std::string const& propertyValue =
+ this->Target->GetTarget()->GetSafeProperty(
+ "XCODE_SCHEME_WORKING_DIRECTORY");
+ if (propertyValue.empty()) {
+ xout.Attribute("useCustomWorkingDirectory", "NO");
+ } else {
+ xout.Attribute("useCustomWorkingDirectory", "YES");
+
+ auto customWorkingDirectory = cmGeneratorExpression::Evaluate(
+ propertyValue, this->LocalGenerator, configuration);
+ xout.Attribute("customWorkingDirectory", customWorkingDirectory);
+ }
+}
+
+std::string cmXCodeScheme::WriteVersionString()
+{
+ std::ostringstream v;
+ v << std::setfill('0') << std::setw(4) << this->XcodeVersion * 10;
+ return v.str();
+}
+
+std::string cmXCodeScheme::FindConfiguration(const std::string& name)
+{
+ // Try to find the desired configuration by name,
+ // and if it's not found return first from the list
+ //
+ if (!cm::contains(this->ConfigList, name) && !this->ConfigList.empty()) {
+ return this->ConfigList[0];
+ }
+
+ return name;
+}
+
+bool cmXCodeScheme::IsTestable() const
+{
+ return !this->Tests.empty() || IsExecutable(this->Target);
+}
+
+bool cmXCodeScheme::IsExecutable(const cmXCodeObject* target)
+{
+ cmGeneratorTarget* gt = target->GetTarget();
+ if (!gt) {
+ cmSystemTools::Error("Error no target on xobject\n");
+ return false;
+ }
+
+ return gt->GetType() == cmStateEnums::EXECUTABLE;
+}
diff --git a/Source/cmXCodeScheme.h b/Source/cmXCodeScheme.h
new file mode 100644
index 0000000..11f043e
--- /dev/null
+++ b/Source/cmXCodeScheme.h
@@ -0,0 +1,75 @@
+/* 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 <vector>
+
+#include "cmGlobalXCodeGenerator.h"
+#include "cmSystemTools.h"
+#include "cmXCodeObject.h"
+#include "cmXMLWriter.h"
+
+/** \class cmXCodeScheme
+ * \brief Write shared schemes for native targets in Xcode project.
+ */
+class cmXCodeScheme
+{
+public:
+ using TestObjects = std::vector<const cmXCodeObject*>;
+
+ cmXCodeScheme(cmLocalGenerator* lg, cmXCodeObject* xcObj, TestObjects tests,
+ const std::vector<std::string>& configList,
+ unsigned int xcVersion);
+
+ void WriteXCodeSharedScheme(const std::string& xcProjDir,
+ const std::string& container);
+
+private:
+ cmLocalGenerator* const LocalGenerator;
+ const cmXCodeObject* const Target;
+ const TestObjects Tests;
+ const std::string& TargetName;
+ const std::vector<std::string>& ConfigList;
+ const unsigned int XcodeVersion;
+
+ void WriteXCodeXCScheme(std::ostream& fout, const std::string& container);
+
+ void WriteBuildAction(cmXMLWriter& xout, const std::string& container);
+ void WriteTestAction(cmXMLWriter& xout, const std::string& configuration,
+ const std::string& container);
+ void WriteLaunchAction(cmXMLWriter& xout, const std::string& configuration,
+ const std::string& container);
+
+ bool WriteLaunchActionAttribute(cmXMLWriter& xout,
+ const std::string& attrName,
+ const std::string& varName);
+
+ bool WriteLaunchActionBooleanAttribute(cmXMLWriter& xout,
+ const std::string& attrName,
+ const std::string& varName,
+ bool defaultValue);
+
+ bool WriteLaunchActionAdditionalOption(cmXMLWriter& xout,
+ const std::string& attrName,
+ const std::string& value,
+ const std::string& varName);
+
+ void WriteProfileAction(cmXMLWriter& xout, const std::string& configuration);
+ void WriteAnalyzeAction(cmXMLWriter& xout, const std::string& configuration);
+ void WriteArchiveAction(cmXMLWriter& xout, const std::string& configuration);
+
+ void WriteBuildableReference(cmXMLWriter& xout, const cmXCodeObject* xcObj,
+ const std::string& container);
+
+ void WriteCustomWorkingDirectory(cmXMLWriter& xout,
+ const std::string& configuration);
+
+ std::string WriteVersionString();
+ std::string FindConfiguration(const std::string& name);
+
+ bool IsTestable() const;
+
+ static bool IsExecutable(const cmXCodeObject* target);
+};
diff --git a/Source/cmXMLParser.cxx b/Source/cmXMLParser.cxx
new file mode 100644
index 0000000..24da8c6
--- /dev/null
+++ b/Source/cmXMLParser.cxx
@@ -0,0 +1,204 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmXMLParser.h"
+
+#include <cctype>
+#include <cstring>
+#include <iostream>
+#include <sstream>
+
+#include <cm3p/expat.h>
+
+#include "cmsys/FStream.hxx"
+
+cmXMLParser::cmXMLParser()
+{
+ this->Parser = nullptr;
+ this->ParseError = 0;
+ this->ReportCallback = nullptr;
+ this->ReportCallbackData = nullptr;
+}
+
+cmXMLParser::~cmXMLParser()
+{
+ if (this->Parser) {
+ this->CleanupParser();
+ }
+}
+
+int cmXMLParser::Parse(const char* string)
+{
+ return this->InitializeParser() &&
+ this->ParseChunk(string, strlen(string)) && this->CleanupParser();
+}
+
+int cmXMLParser::ParseFile(const char* file)
+{
+ if (!file) {
+ return 0;
+ }
+
+ cmsys::ifstream ifs(file);
+ if (!ifs) {
+ return 0;
+ }
+
+ std::ostringstream str;
+ str << ifs.rdbuf();
+ return this->Parse(str.str().c_str());
+}
+
+int cmXMLParser::InitializeParser()
+{
+ if (this->Parser) {
+ std::cerr << "Parser already initialized" << std::endl;
+ this->ParseError = 1;
+ return 0;
+ }
+
+ // Create the expat XML parser.
+ this->Parser = XML_ParserCreate(nullptr);
+ XML_SetElementHandler(static_cast<XML_Parser>(this->Parser),
+ &cmXMLParserStartElement, &cmXMLParserEndElement);
+ XML_SetCharacterDataHandler(static_cast<XML_Parser>(this->Parser),
+ &cmXMLParserCharacterDataHandler);
+ XML_SetUserData(static_cast<XML_Parser>(this->Parser), this);
+ this->ParseError = 0;
+ return 1;
+}
+
+int cmXMLParser::ParseChunk(const char* inputString,
+ std::string::size_type length)
+{
+ if (!this->Parser) {
+ std::cerr << "Parser not initialized" << std::endl;
+ this->ParseError = 1;
+ return 0;
+ }
+ int res;
+ res = this->ParseBuffer(inputString, length);
+ if (res == 0) {
+ this->ParseError = 1;
+ }
+ return res;
+}
+
+int cmXMLParser::CleanupParser()
+{
+ if (!this->Parser) {
+ std::cerr << "Parser not initialized" << std::endl;
+ this->ParseError = 1;
+ return 0;
+ }
+ int result = !this->ParseError;
+ if (result) {
+ // Tell the expat XML parser about the end-of-input.
+ if (!XML_Parse(static_cast<XML_Parser>(this->Parser), "", 0, 1)) {
+ this->ReportXmlParseError();
+ result = 0;
+ }
+ }
+
+ // Clean up the parser.
+ XML_ParserFree(static_cast<XML_Parser>(this->Parser));
+ this->Parser = nullptr;
+
+ return result;
+}
+
+int cmXMLParser::ParseBuffer(const char* buffer, std::string::size_type count)
+{
+ // Pass the buffer to the expat XML parser.
+ if (!XML_Parse(static_cast<XML_Parser>(this->Parser), buffer,
+ static_cast<int>(count), 0)) {
+ this->ReportXmlParseError();
+ return 0;
+ }
+ return 1;
+}
+
+int cmXMLParser::ParseBuffer(const char* buffer)
+{
+ return this->ParseBuffer(buffer, static_cast<int>(strlen(buffer)));
+}
+
+int cmXMLParser::ParsingComplete()
+{
+ // Default behavior is to parse to end of stream.
+ return 0;
+}
+
+void cmXMLParser::StartElement(const std::string& name, const char** /*atts*/)
+{
+ std::cout << "Start element: " << name << std::endl;
+}
+
+void cmXMLParser::EndElement(const std::string& name)
+{
+ std::cout << "End element: " << name << std::endl;
+}
+
+void cmXMLParser::CharacterDataHandler(const char* /*inData*/,
+ int /*inLength*/)
+{
+}
+
+int cmXMLParser::IsSpace(char c)
+{
+ return isspace(c);
+}
+
+const char* cmXMLParser::FindAttribute(const char** atts,
+ const char* attribute)
+{
+ if (atts && attribute) {
+ for (const char** a = atts; *a && *(a + 1); a += 2) {
+ if (strcmp(*a, attribute) == 0) {
+ return *(a + 1);
+ }
+ }
+ }
+ return nullptr;
+}
+
+void cmXMLParserStartElement(void* parser, const char* name, const char** atts)
+{
+ // Begin element handler that is registered with the XML_Parser.
+ // This just casts the user data to a cmXMLParser and calls
+ // StartElement.
+ static_cast<cmXMLParser*>(parser)->StartElement(name, atts);
+}
+
+void cmXMLParserEndElement(void* parser, const char* name)
+{
+ // End element handler that is registered with the XML_Parser. This
+ // just casts the user data to a cmXMLParser and calls EndElement.
+ static_cast<cmXMLParser*>(parser)->EndElement(name);
+}
+
+void cmXMLParserCharacterDataHandler(void* parser, const char* data,
+ int length)
+{
+ // Character data handler that is registered with the XML_Parser.
+ // This just casts the user data to a cmXMLParser and calls
+ // CharacterDataHandler.
+ static_cast<cmXMLParser*>(parser)->CharacterDataHandler(data, length);
+}
+
+void cmXMLParser::ReportXmlParseError()
+{
+ XML_Parser parser = static_cast<XML_Parser>(this->Parser);
+ this->ReportError(static_cast<int>(XML_GetCurrentLineNumber(parser)),
+ static_cast<int>(XML_GetCurrentColumnNumber(parser)),
+ XML_ErrorString(XML_GetErrorCode(parser)));
+}
+
+void cmXMLParser::ReportError(int line, int /*unused*/, const char* msg)
+{
+ if (this->ReportCallback) {
+ this->ReportCallback(line, msg, this->ReportCallbackData);
+ } else {
+ std::cerr << "Error parsing XML in stream at line " << line << ": " << msg
+ << std::endl;
+ }
+}
diff --git a/Source/cmXMLParser.h b/Source/cmXMLParser.h
new file mode 100644
index 0000000..7e805d7
--- /dev/null
+++ b/Source/cmXMLParser.h
@@ -0,0 +1,108 @@
+/* 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 <string>
+
+extern "C" {
+void cmXMLParserStartElement(void*, const char*, const char**);
+void cmXMLParserEndElement(void*, const char*);
+void cmXMLParserCharacterDataHandler(void*, const char*, int);
+}
+
+/** \class cmXMLParser
+ * \brief Helper class for performing XML parsing
+ *
+ * Superclass for all XML parsers.
+ */
+class cmXMLParser
+{
+public:
+ cmXMLParser();
+ virtual ~cmXMLParser();
+
+ //! Parse given XML string
+ virtual int Parse(const char* string);
+
+ //! Parse given XML file
+ virtual int ParseFile(const char* file);
+
+ /**
+ * When parsing fragments of XML or streaming XML, use the following
+ * three methods. InitializeParser method initialize parser but does
+ * not perform any actual parsing. ParseChunk parses framgent of
+ * XML. This has to match to what was already parsed. CleanupParser
+ * finishes parsing. If there were errors, CleanupParser will report
+ * them.
+ */
+ virtual int InitializeParser();
+ virtual int ParseChunk(const char* inputString,
+ std::string::size_type length);
+ virtual int CleanupParser();
+ using ReportFunction = void (*)(int, const char*, void*);
+ void SetErrorCallback(ReportFunction f, void* d)
+ {
+ this->ReportCallback = f;
+ this->ReportCallbackData = d;
+ }
+
+protected:
+ //! This variable is true if there was a parse error while parsing in
+ // chunks.
+ int ParseError;
+ ReportFunction ReportCallback;
+ void* ReportCallbackData;
+
+ // 1 Expat parser structure. Exists only during call to Parse().
+ void* Parser;
+
+ /**
+ * Called before each block of input is read from the stream to check if
+ * parsing is complete. Can be replaced by subclasses to change the
+ * terminating condition for parsing. Parsing always stops when the end of
+ * file is reached in the stream.
+ */
+
+ virtual int ParsingComplete();
+
+ /**
+ * Called when a new element is opened in the XML source. Should be
+ * replaced by subclasses to handle each element. name = Name of new
+ * element. atts = Null-terminated array of attribute name/value pairs.
+ * Even indices are attribute names, and odd indices are values.
+ */
+ virtual void StartElement(const std::string& name, const char** atts);
+
+ //! Called at the end of an element in the XML source opened when
+ // StartElement was called.
+ virtual void EndElement(const std::string& name);
+
+ //! Called when there is character data to handle.
+ virtual void CharacterDataHandler(const char* data, int length);
+
+ //! Called by Parse to report an XML syntax error.
+ virtual void ReportXmlParseError();
+
+ /** Called by ReportXmlParseError with basic error info. */
+ virtual void ReportError(int line, int column, const char* msg);
+
+ //! Utility for convenience of subclasses. Wraps isspace C library
+ // routine.
+ static int IsSpace(char c);
+
+ //! Send the given buffer to the XML parser.
+ virtual int ParseBuffer(const char* buffer, std::string::size_type length);
+
+ //! Send the given c-style string to the XML parser.
+ int ParseBuffer(const char* buffer);
+
+ /** Helps subclasses search for attributes on elements. */
+ static const char* FindAttribute(const char** atts, const char* attribute);
+
+ //! Callbacks for the expat
+ friend void cmXMLParserStartElement(void*, const char*, const char**);
+ friend void cmXMLParserEndElement(void*, const char*);
+ friend void cmXMLParserCharacterDataHandler(void*, const char*, int);
+};
diff --git a/Source/cmXMLSafe.cxx b/Source/cmXMLSafe.cxx
new file mode 100644
index 0000000..d31a239
--- /dev/null
+++ b/Source/cmXMLSafe.cxx
@@ -0,0 +1,90 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmXMLSafe.h"
+
+#include <cstdio>
+#include <cstring>
+#include <sstream>
+
+#include "cm_utf8.h"
+
+cmXMLSafe::cmXMLSafe(const char* s)
+ : Data(s)
+ , Size(static_cast<unsigned long>(strlen(s)))
+ , DoQuotes(true)
+{
+}
+
+cmXMLSafe::cmXMLSafe(std::string const& s)
+ : Data(s.c_str())
+ , Size(static_cast<unsigned long>(s.length()))
+ , DoQuotes(true)
+{
+}
+
+cmXMLSafe& cmXMLSafe::Quotes(bool b)
+{
+ this->DoQuotes = b;
+ return *this;
+}
+
+std::string cmXMLSafe::str() const
+{
+ std::ostringstream ss;
+ ss << *this;
+ return ss.str();
+}
+
+std::ostream& operator<<(std::ostream& os, cmXMLSafe const& self)
+{
+ char const* first = self.Data;
+ char const* last = self.Data + self.Size;
+ while (first != last) {
+ unsigned int ch;
+ if (const char* next = cm_utf8_decode_character(first, last, &ch)) {
+ // http://www.w3.org/TR/REC-xml/#NT-Char
+ if ((ch >= 0x20 && ch <= 0xD7FF) || (ch >= 0xE000 && ch <= 0xFFFD) ||
+ (ch >= 0x10000 && ch <= 0x10FFFF) || ch == 0x9 || ch == 0xA ||
+ ch == 0xD) {
+ switch (ch) {
+ // Escape XML control characters.
+ case '&':
+ os << "&amp;";
+ break;
+ case '<':
+ os << "&lt;";
+ break;
+ case '>':
+ os << "&gt;";
+ break;
+ case '"':
+ os << (self.DoQuotes ? "&quot;" : "\"");
+ break;
+ case '\'':
+ os << (self.DoQuotes ? "&apos;" : "'");
+ break;
+ case '\r':
+ break; // Ignore CR
+ // Print the UTF-8 character.
+ default:
+ os.write(first, next - first);
+ break;
+ }
+ } else {
+ // Use a human-readable hex value for this invalid character.
+ char buf[16];
+ sprintf(buf, "%X", ch);
+ os << "[NON-XML-CHAR-0x" << buf << "]";
+ }
+
+ first = next;
+ } else {
+ ch = static_cast<unsigned char>(*first++);
+ // Use a human-readable hex value for this invalid byte.
+ char buf[16];
+ sprintf(buf, "%X", ch);
+ os << "[NON-UTF-8-BYTE-0x" << buf << "]";
+ }
+ }
+ return os;
+}
diff --git a/Source/cmXMLSafe.h b/Source/cmXMLSafe.h
new file mode 100644
index 0000000..21bd19a
--- /dev/null
+++ b/Source/cmXMLSafe.h
@@ -0,0 +1,34 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <string>
+
+/** \class cmXMLSafe
+ * \brief Write strings to XML with proper escapes
+ */
+class cmXMLSafe
+{
+public:
+ /** Construct with the data to be written. This assumes the data
+ will exist for the duration of this object's life. */
+ cmXMLSafe(const char* s);
+ cmXMLSafe(std::string const& s);
+
+ /** Specify whether to escape quotes too. This is needed when
+ writing the content of an attribute value. By default quotes
+ are escaped. */
+ cmXMLSafe& Quotes(bool b = true);
+
+ /** Get the escaped data as a string. */
+ std::string str() const;
+
+private:
+ char const* Data;
+ unsigned long Size;
+ bool DoQuotes;
+ friend std::ostream& operator<<(std::ostream&, cmXMLSafe const&);
+};
diff --git a/Source/cmXMLWriter.cxx b/Source/cmXMLWriter.cxx
new file mode 100644
index 0000000..0811bd0
--- /dev/null
+++ b/Source/cmXMLWriter.cxx
@@ -0,0 +1,145 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmXMLWriter.h"
+
+#include <cassert>
+
+#include "cmsys/FStream.hxx"
+
+cmXMLWriter::cmXMLWriter(std::ostream& output, std::size_t level)
+ : Output(output)
+ , IndentationElement(1, '\t')
+ , Level(level)
+ , Indent(0)
+ , ElementOpen(false)
+ , BreakAttrib(false)
+ , IsContent(false)
+{
+}
+
+cmXMLWriter::~cmXMLWriter()
+{
+ assert(this->Indent == 0);
+}
+
+void cmXMLWriter::StartDocument(const char* encoding)
+{
+ this->Output << R"(<?xml version="1.0" encoding=")" << encoding << "\"?>";
+}
+
+void cmXMLWriter::EndDocument()
+{
+ assert(this->Indent == 0);
+ this->Output << '\n';
+}
+
+void cmXMLWriter::StartElement(std::string const& name)
+{
+ this->CloseStartElement();
+ this->ConditionalLineBreak(!this->IsContent);
+ this->Output << '<' << name;
+ this->Elements.push(name);
+ ++this->Indent;
+ this->ElementOpen = true;
+ this->BreakAttrib = false;
+}
+
+void cmXMLWriter::EndElement()
+{
+ assert(this->Indent > 0);
+ --this->Indent;
+ if (this->ElementOpen) {
+ this->Output << "/>";
+ } else {
+ this->ConditionalLineBreak(!this->IsContent);
+ this->IsContent = false;
+ this->Output << "</" << this->Elements.top() << '>';
+ }
+ this->Elements.pop();
+ this->ElementOpen = false;
+}
+
+void cmXMLWriter::Element(const char* name)
+{
+ this->CloseStartElement();
+ this->ConditionalLineBreak(!this->IsContent);
+ this->Output << '<' << name << "/>";
+}
+
+void cmXMLWriter::BreakAttributes()
+{
+ this->BreakAttrib = true;
+}
+
+void cmXMLWriter::Comment(const char* comment)
+{
+ this->CloseStartElement();
+ this->ConditionalLineBreak(!this->IsContent);
+ this->Output << "<!-- " << comment << " -->";
+}
+
+void cmXMLWriter::CData(std::string const& data)
+{
+ this->PreContent();
+ this->Output << "<![CDATA[" << data << "]]>";
+}
+
+void cmXMLWriter::Doctype(const char* doctype)
+{
+ this->CloseStartElement();
+ this->ConditionalLineBreak(!this->IsContent);
+ this->Output << "<!DOCTYPE " << doctype << ">";
+}
+
+void cmXMLWriter::ProcessingInstruction(const char* target, const char* data)
+{
+ this->CloseStartElement();
+ this->ConditionalLineBreak(!this->IsContent);
+ this->Output << "<?" << target << ' ' << data << "?>";
+}
+
+void cmXMLWriter::FragmentFile(const char* fname)
+{
+ this->CloseStartElement();
+ cmsys::ifstream fin(fname, std::ios::in | std::ios::binary);
+ this->Output << fin.rdbuf();
+}
+
+void cmXMLWriter::SetIndentationElement(std::string const& element)
+{
+ this->IndentationElement = element;
+}
+
+void cmXMLWriter::ConditionalLineBreak(bool condition)
+{
+ if (condition) {
+ this->Output << '\n';
+ for (std::size_t i = 0; i < this->Indent + this->Level; ++i) {
+ this->Output << this->IndentationElement;
+ }
+ }
+}
+
+void cmXMLWriter::PreAttribute()
+{
+ assert(this->ElementOpen);
+ this->ConditionalLineBreak(this->BreakAttrib);
+ if (!this->BreakAttrib) {
+ this->Output << ' ';
+ }
+}
+
+void cmXMLWriter::PreContent()
+{
+ this->CloseStartElement();
+ this->IsContent = true;
+}
+
+void cmXMLWriter::CloseStartElement()
+{
+ if (this->ElementOpen) {
+ this->ConditionalLineBreak(this->BreakAttrib);
+ this->Output << '>';
+ this->ElementOpen = false;
+ }
+}
diff --git a/Source/cmXMLWriter.h b/Source/cmXMLWriter.h
new file mode 100644
index 0000000..6e8eeb7
--- /dev/null
+++ b/Source/cmXMLWriter.h
@@ -0,0 +1,195 @@
+/* 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 <chrono>
+#include <cstddef> // IWYU pragma: keep
+#include <ctime>
+#include <ostream>
+#include <stack>
+#include <string>
+#include <vector>
+
+#include "cmXMLSafe.h"
+
+class cmXMLWriter
+{
+public:
+ cmXMLWriter(std::ostream& output, std::size_t level = 0);
+ ~cmXMLWriter();
+
+ cmXMLWriter(cmXMLWriter const&) = delete;
+ cmXMLWriter& operator=(cmXMLWriter const&) = delete;
+
+ void StartDocument(const char* encoding = "UTF-8");
+ void EndDocument();
+
+ void StartElement(std::string const& name);
+ void EndElement();
+
+ void BreakAttributes();
+
+ template <typename T>
+ void Attribute(const char* name, T const& value)
+ {
+ this->PreAttribute();
+ this->Output << name << "=\"" << SafeAttribute(value) << '"';
+ }
+
+ void Element(const char* name);
+
+ template <typename T>
+ void Element(std::string const& name, T const& value)
+ {
+ this->StartElement(name);
+ this->Content(value);
+ this->EndElement();
+ }
+
+ template <typename T>
+ void Content(T const& content)
+ {
+ this->PreContent();
+ this->Output << SafeContent(content);
+ }
+
+ void Comment(const char* comment);
+
+ void CData(std::string const& data);
+
+ void Doctype(const char* doctype);
+
+ void ProcessingInstruction(const char* target, const char* data);
+
+ void FragmentFile(const char* fname);
+
+ void SetIndentationElement(std::string const& element);
+
+private:
+ void ConditionalLineBreak(bool condition);
+
+ void PreAttribute();
+ void PreContent();
+
+ void CloseStartElement();
+
+ static cmXMLSafe SafeAttribute(const char* value) { return { value }; }
+
+ static cmXMLSafe SafeAttribute(std::string const& value)
+ {
+ return { value };
+ }
+
+ template <typename T>
+ static T SafeAttribute(T value)
+ {
+ return value;
+ }
+
+ static cmXMLSafe SafeContent(const char* value)
+ {
+ return cmXMLSafe(value).Quotes(false);
+ }
+
+ static cmXMLSafe SafeContent(std::string const& value)
+ {
+ return cmXMLSafe(value).Quotes(false);
+ }
+
+ /*
+ * Convert a std::chrono::system::time_point to the number of seconds since
+ * the UN*X epoch.
+ *
+ * It would be tempting to convert a time_point to number of seconds by
+ * using time_since_epoch(). Unfortunately the C++11 standard does not
+ * specify what the epoch of the system_clock must be.
+ * Therefore we must assume it is an arbitrary point in time. Instead of this
+ * method, it is recommended to convert it by means of the to_time_t method.
+ */
+ static std::time_t SafeContent(
+ std::chrono::system_clock::time_point const& value)
+ {
+ return std::chrono::system_clock::to_time_t(value);
+ }
+
+ template <typename T>
+ static T SafeContent(T value)
+ {
+ return value;
+ }
+
+ std::ostream& Output;
+ std::stack<std::string, std::vector<std::string>> Elements;
+ std::string IndentationElement;
+ std::size_t Level;
+ std::size_t Indent;
+ bool ElementOpen;
+ bool BreakAttrib;
+ bool IsContent;
+};
+
+class cmXMLElement; // IWYU pragma: keep
+
+class cmXMLDocument
+{
+public:
+ cmXMLDocument(cmXMLWriter& xml)
+ : xmlwr(xml)
+ {
+ this->xmlwr.StartDocument();
+ }
+ ~cmXMLDocument() { this->xmlwr.EndDocument(); }
+ cmXMLDocument(const cmXMLDocument&) = delete;
+ cmXMLDocument& operator=(const cmXMLDocument&) = delete;
+
+private:
+ friend class cmXMLElement;
+ cmXMLWriter& xmlwr;
+};
+
+class cmXMLElement
+{
+public:
+ cmXMLElement(cmXMLWriter& xml, const char* tag)
+ : xmlwr(xml)
+ {
+ this->xmlwr.StartElement(tag);
+ }
+ cmXMLElement(cmXMLElement& par, const char* tag)
+ : xmlwr(par.xmlwr)
+ {
+ this->xmlwr.StartElement(tag);
+ }
+ cmXMLElement(cmXMLDocument& doc, const char* tag)
+ : xmlwr(doc.xmlwr)
+ {
+ this->xmlwr.StartElement(tag);
+ }
+ ~cmXMLElement() { this->xmlwr.EndElement(); }
+
+ cmXMLElement(const cmXMLElement&) = delete;
+ cmXMLElement& operator=(const cmXMLElement&) = delete;
+
+ template <typename T>
+ cmXMLElement& Attribute(const char* name, T const& value)
+ {
+ this->xmlwr.Attribute(name, value);
+ return *this;
+ }
+ template <typename T>
+ void Content(T const& content)
+ {
+ this->xmlwr.Content(content);
+ }
+ template <typename T>
+ void Element(std::string const& name, T const& value)
+ {
+ this->xmlwr.Element(name, value);
+ }
+ void Comment(const char* comment) { this->xmlwr.Comment(comment); }
+
+private:
+ cmXMLWriter& xmlwr;
+};
diff --git a/Source/cm_codecvt.cxx b/Source/cm_codecvt.cxx
new file mode 100644
index 0000000..15f83e0
--- /dev/null
+++ b/Source/cm_codecvt.cxx
@@ -0,0 +1,244 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cm_codecvt.hxx"
+
+#if defined(_WIN32)
+# include <windows.h>
+
+# include <assert.h>
+# include <string.h>
+# undef max
+# include "cmsys/Encoding.hxx"
+#endif
+
+#if defined(_WIN32)
+/* Number of leading ones before a zero in the byte (see cm_utf8.c). */
+extern "C" unsigned char const cm_utf8_ones[256];
+#endif
+
+codecvt::codecvt(Encoding e)
+#if defined(_WIN32)
+ : m_codepage(0)
+#endif
+{
+ switch (e) {
+ case codecvt::ANSI:
+#if defined(_WIN32)
+ m_noconv = false;
+ m_codepage = CP_ACP;
+ break;
+#endif
+ // We don't know which ANSI encoding to use for other platforms than
+ // Windows so we don't do any conversion there
+ case codecvt::UTF8:
+ // Assume internal encoding is UTF-8
+ case codecvt::None:
+ // No encoding
+ default:
+ this->m_noconv = true;
+ }
+}
+
+codecvt::~codecvt() = default;
+
+bool codecvt::do_always_noconv() const throw()
+{
+ return this->m_noconv;
+}
+
+std::codecvt_base::result codecvt::do_out(mbstate_t& state, const char* from,
+ const char* from_end,
+ const char*& from_next, char* to,
+ char* to_end, char*& to_next) const
+{
+ from_next = from;
+ to_next = to;
+ if (this->m_noconv) {
+ return std::codecvt_base::noconv;
+ }
+#if defined(_WIN32)
+ // Use a const view of the state because we should not modify it until we
+ // have fully processed and consume a byte (with sufficient space in the
+ // output buffer). We call helpers to re-cast and modify the state
+ State const& lstate = reinterpret_cast<State&>(state);
+
+ while (from_next != from_end) {
+ // Count leading ones in the bits of the next byte.
+ unsigned char const ones =
+ cm_utf8_ones[static_cast<unsigned char>(*from_next)];
+
+ if (ones != 1 && lstate.buffered != 0) {
+ // We have a buffered partial codepoint that we never completed.
+ return std::codecvt_base::error;
+ } else if (ones == 1 && lstate.buffered == 0) {
+ // This is a continuation of a codepoint that never started.
+ return std::codecvt_base::error;
+ }
+
+ // Compute the number of bytes in the current codepoint.
+ int need = 0;
+ switch (ones) {
+ case 0: // 0xxx xxxx: new codepoint of size 1
+ need = 1;
+ break;
+ case 1: // 10xx xxxx: continues a codepoint
+ assert(lstate.size != 0);
+ need = lstate.size;
+ break;
+ case 2: // 110x xxxx: new codepoint of size 2
+ need = 2;
+ break;
+ case 3: // 1110 xxxx: new codepoint of size 3
+ need = 3;
+ break;
+ case 4: // 1111 0xxx: new codepoint of size 4
+ need = 4;
+ break;
+ default: // invalid byte
+ return std::codecvt_base::error;
+ }
+ assert(need > 0);
+
+ if (lstate.buffered + 1 == need) {
+ // This byte completes a codepoint.
+ std::codecvt_base::result decode_result =
+ this->Decode(state, need, from_next, to_next, to_end);
+ if (decode_result != std::codecvt_base::ok) {
+ return decode_result;
+ }
+ } else {
+ // This byte does not complete a codepoint.
+ this->BufferPartial(state, need, from_next);
+ }
+ }
+
+ return std::codecvt_base::ok;
+#else
+ static_cast<void>(state);
+ static_cast<void>(from);
+ static_cast<void>(from_end);
+ static_cast<void>(from_next);
+ static_cast<void>(to);
+ static_cast<void>(to_end);
+ static_cast<void>(to_next);
+ return std::codecvt_base::noconv;
+#endif
+}
+
+std::codecvt_base::result codecvt::do_unshift(mbstate_t& state, char* to,
+ char* to_end,
+ char*& to_next) const
+{
+ to_next = to;
+ if (this->m_noconv) {
+ return std::codecvt_base::noconv;
+ }
+#if defined(_WIN32)
+ State& lstate = reinterpret_cast<State&>(state);
+ if (lstate.buffered != 0) {
+ return this->DecodePartial(state, to_next, to_end);
+ }
+ return std::codecvt_base::ok;
+#else
+ static_cast<void>(state);
+ static_cast<void>(to_end);
+ return std::codecvt_base::ok;
+#endif
+}
+
+#if defined(_WIN32)
+std::codecvt_base::result codecvt::Decode(mbstate_t& state, int size,
+ const char*& from_next,
+ char*& to_next, char* to_end) const
+{
+ State& lstate = reinterpret_cast<State&>(state);
+
+ // Collect all the bytes for this codepoint.
+ char buf[4];
+ memcpy(buf, lstate.partial, lstate.buffered);
+ buf[lstate.buffered] = *from_next;
+
+ // Convert the encoding.
+ wchar_t wbuf[2];
+ int wlen =
+ MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, buf, size, wbuf, 2);
+ if (wlen <= 0) {
+ return std::codecvt_base::error;
+ }
+
+ int tlen = WideCharToMultiByte(m_codepage, 0, wbuf, wlen, to_next,
+ to_end - to_next, NULL, NULL);
+ if (tlen <= 0) {
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ return std::codecvt_base::partial;
+ }
+ return std::codecvt_base::error;
+ }
+
+ // Move past the now-consumed byte in the input buffer.
+ ++from_next;
+
+ // Move past the converted codepoint in the output buffer.
+ to_next += tlen;
+
+ // Re-initialize the state for the next codepoint to start.
+ lstate = State();
+
+ return std::codecvt_base::ok;
+}
+
+std::codecvt_base::result codecvt::DecodePartial(mbstate_t& state,
+ char*& to_next,
+ char* to_end) const
+{
+ State& lstate = reinterpret_cast<State&>(state);
+
+ // Try converting the partial codepoint.
+ wchar_t wbuf[2];
+ int wlen = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, lstate.partial,
+ lstate.buffered, wbuf, 2);
+ if (wlen <= 0) {
+ return std::codecvt_base::error;
+ }
+
+ int tlen = WideCharToMultiByte(m_codepage, 0, wbuf, wlen, to_next,
+ to_end - to_next, NULL, NULL);
+ if (tlen <= 0) {
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ return std::codecvt_base::partial;
+ }
+ return std::codecvt_base::error;
+ }
+
+ // Move past the converted codepoint in the output buffer.
+ to_next += tlen;
+
+ // Re-initialize the state for the next codepoint to start.
+ lstate = State();
+
+ return std::codecvt_base::ok;
+}
+
+void codecvt::BufferPartial(mbstate_t& state, int size,
+ const char*& from_next) const
+{
+ State& lstate = reinterpret_cast<State&>(state);
+
+ // Save the byte in our buffer for later.
+ lstate.partial[lstate.buffered++] = *from_next;
+ lstate.size = size;
+
+ // Move past the now-consumed byte in the input buffer.
+ ++from_next;
+}
+#endif
+
+int codecvt::do_max_length() const throw()
+{
+ return 4;
+}
+
+int codecvt::do_encoding() const throw()
+{
+ return 0;
+}
diff --git a/Source/cm_codecvt.hxx b/Source/cm_codecvt.hxx
new file mode 100644
index 0000000..1860211
--- /dev/null
+++ b/Source/cm_codecvt.hxx
@@ -0,0 +1,63 @@
+/* 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 <cwchar>
+#include <locale>
+
+class codecvt : public std::codecvt<char, char, mbstate_t>
+{
+public:
+ enum Encoding
+ {
+ None,
+ UTF8,
+ ANSI
+ };
+
+#ifndef CMAKE_BOOTSTRAP
+
+ codecvt(Encoding e);
+
+protected:
+ ~codecvt() override;
+ bool do_always_noconv() const throw() override;
+ result do_out(mbstate_t& state, const char* from, const char* from_end,
+ const char*& from_next, char* to, char* to_end,
+ char*& to_next) const override;
+ result do_unshift(mbstate_t& state, char* to, char*,
+ char*& to_next) const override;
+ int do_max_length() const throw() override;
+ int do_encoding() const throw() override;
+
+private:
+ // The mbstate_t argument to do_out and do_unshift is responsible
+ // for storing state between calls. We cannot control the type
+ // since we want to imbue on standard streams. However, we do
+ // know that it is a trivial type. Define our own type to overlay
+ // on it safely with no alignment requirements.
+ struct State
+ {
+ // Buffer bytes we have consumed from a partial codepoint.
+ char partial[3];
+
+ // Number of bytes we have buffered from a partial codepoint.
+ unsigned char buffered : 4;
+
+ // Size of the current codepoint in bytes.
+ unsigned char size : 4;
+ };
+
+ bool m_noconv;
+# if defined(_WIN32)
+ unsigned int m_codepage;
+ result Decode(mbstate_t& state, int need, const char*& from_next,
+ char*& to_next, char* to_end) const;
+ result DecodePartial(mbstate_t& state, char*& to_next, char* to_end) const;
+ void BufferPartial(mbstate_t& state, int need, const char*& from_next) const;
+# endif
+
+#endif
+};
diff --git a/Source/cm_get_date.c b/Source/cm_get_date.c
new file mode 100644
index 0000000..49f5577
--- /dev/null
+++ b/Source/cm_get_date.c
@@ -0,0 +1,11 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cm_get_date.h"
+
+// FIXME: This suppresses use of localtime_r because archive_getdate.c
+// depends the rest of libarchive's checks for that.
+#define CM_GET_DATE
+
+#define __archive_get_date cm_get_date
+
+#include "../Utilities/cmlibarchive/libarchive/archive_getdate.c"
diff --git a/Source/cm_get_date.h b/Source/cm_get_date.h
new file mode 100644
index 0000000..65722df
--- /dev/null
+++ b/Source/cm_get_date.h
@@ -0,0 +1,16 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <time.h> /* NOLINT(modernize-deprecated-headers) */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Parse a date/time string. Treat relative times with respect to 'now'. */
+time_t cm_get_date(time_t now, const char* str);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
diff --git a/Source/cm_sys_stat.h b/Source/cm_sys_stat.h
new file mode 100644
index 0000000..c4e3d84
--- /dev/null
+++ b/Source/cm_sys_stat.h
@@ -0,0 +1,11 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#if defined(_MSC_VER)
+using mode_t = unsigned short;
+#endif
+
+#include <sys/types.h>
+// include sys/stat.h after sys/types.h
+#include <sys/stat.h> // IWYU pragma: export
diff --git a/Source/cm_utf8.c b/Source/cm_utf8.c
new file mode 100644
index 0000000..62e7e8c
--- /dev/null
+++ b/Source/cm_utf8.c
@@ -0,0 +1,106 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cm_utf8.h"
+
+#include <string.h>
+
+/*
+ RFC 3629
+ 07-bit: 0xxxxxxx
+ 11-bit: 110xxxxx 10xxxxxx
+ 16-bit: 1110xxxx 10xxxxxx 10xxxxxx
+ 21-bit: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+
+ Pre-RFC Compatibility
+ 26-bit: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ 31-bit: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+*/
+
+/* Number of leading ones before a zero in the byte. */
+unsigned char const cm_utf8_ones[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8
+};
+
+/* Mask away control bits from bytes with n leading ones. */
+static unsigned char const cm_utf8_mask[7] = { 0xEF, 0x3F, 0x1F, 0x0F,
+ 0x07, 0x03, 0x01 };
+
+/* Minimum allowed value when first byte has n leading ones. */
+static unsigned int const cm_utf8_min[7] = {
+ 0, 0, 1u << 7, 1u << 11, 1u << 16, 1u << 21, 1u << 26 /*, 1u<<31 */
+};
+
+const char* cm_utf8_decode_character(const char* first, const char* last,
+ unsigned int* pc)
+{
+ /* Count leading ones in the first byte. */
+ unsigned char c = (unsigned char)*first++;
+ unsigned char const ones = cm_utf8_ones[c];
+ switch (ones) {
+ case 0:
+ *pc = c;
+ return first; /* One-byte character. */
+ case 1:
+ case 7:
+ case 8:
+ return 0; /* Invalid leading byte. */
+ default:
+ break;
+ }
+
+ /* Extract bits from this multi-byte character. */
+ {
+ unsigned int uc = c & cm_utf8_mask[ones];
+ int left;
+ for (left = ones - 1; left && first != last; --left) {
+ c = (unsigned char)*first++;
+ if (cm_utf8_ones[c] != 1) {
+ return 0;
+ }
+ uc = (uc << 6) | (c & cm_utf8_mask[1]);
+ }
+
+ if (left > 0 || uc < cm_utf8_min[ones]) {
+ return 0;
+ }
+
+ /* UTF-16 surrogate halves. */
+ if (0xD800 <= uc && uc <= 0xDFFF) {
+ return 0;
+ }
+
+ /* Invalid codepoints. */
+ if (0x10FFFF < uc) {
+ return 0;
+ }
+
+ *pc = uc;
+ return first;
+ }
+}
+
+int cm_utf8_is_valid(const char* s)
+{
+ if (!s) {
+ return 0;
+ }
+
+ const char* last = s + strlen(s);
+ const char* pos = s;
+ unsigned int pc;
+
+ while (pos != last && (pos = cm_utf8_decode_character(pos, last, &pc))) {
+ /* Nothing to do. */
+ }
+
+ return pos == last;
+}
diff --git a/Source/cm_utf8.h b/Source/cm_utf8.h
new file mode 100644
index 0000000..fa9ed3a
--- /dev/null
+++ b/Source/cm_utf8.h
@@ -0,0 +1,21 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Decode one UTF-8 character from the input byte range. On success,
+ stores the unicode character number in *pc and returns the first
+ position not extracted. On failure, returns 0. */
+const char* cm_utf8_decode_character(const char* first, const char* last,
+ unsigned int* pc);
+
+/** Returns whether a C string is a sequence of valid UTF-8 encoded Unicode
+ codepoints. Returns non-zero on success. */
+int cm_utf8_is_valid(const char* s);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
new file mode 100644
index 0000000..1d4bbf4
--- /dev/null
+++ b/Source/cmake.cxx
@@ -0,0 +1,3557 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmake.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <initializer_list>
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <utility>
+
+#include <cm/memory>
+#include <cm/optional>
+#include <cm/string_view>
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
+# include <cm/iterator>
+#endif
+
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cm_sys_stat.h"
+
+#include "cmCMakePath.h"
+#include "cmCMakePresetsFile.h"
+#include "cmCommandLineArgument.h"
+#include "cmCommands.h"
+#include "cmDocumentation.h"
+#include "cmDocumentationEntry.h"
+#include "cmDocumentationFormatter.h"
+#include "cmDuration.h"
+#include "cmExternalMakefileProjectGenerator.h"
+#include "cmFileTimeCache.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmGlobalGeneratorFactory.h"
+#include "cmLinkLineComputer.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#if !defined(CMAKE_BOOTSTRAP)
+# include "cmMakefileProfilingData.h"
+#endif
+#include "cmMessenger.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetLinkLibraryType.h"
+#include "cmUtils.hxx"
+#include "cmVersionConfig.h"
+#include "cmWorkingDirectory.h"
+
+#if !defined(CMAKE_BOOTSTRAP)
+# include <unordered_map>
+
+# include <cm3p/json/writer.h>
+
+# include "cmFileAPI.h"
+# include "cmGraphVizWriter.h"
+# include "cmVariableWatch.h"
+#endif
+
+#if defined(__MINGW32__) && defined(CMAKE_BOOTSTRAP)
+# define CMAKE_BOOT_MINGW
+#endif
+
+// include the generator
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# if !defined(CMAKE_BOOT_MINGW)
+# include <cmext/memory>
+
+# include "cmGlobalBorlandMakefileGenerator.h"
+# include "cmGlobalJOMMakefileGenerator.h"
+# include "cmGlobalNMakeMakefileGenerator.h"
+# include "cmGlobalVisualStudio10Generator.h"
+# include "cmGlobalVisualStudio11Generator.h"
+# include "cmGlobalVisualStudio12Generator.h"
+# include "cmGlobalVisualStudio14Generator.h"
+# include "cmGlobalVisualStudio9Generator.h"
+# include "cmGlobalVisualStudioVersionedGenerator.h"
+# include "cmVSSetupHelper.h"
+
+# define CMAKE_HAVE_VS_GENERATORS
+# endif
+# include "cmGlobalMSYSMakefileGenerator.h"
+# include "cmGlobalMinGWMakefileGenerator.h"
+#else
+#endif
+#if defined(CMAKE_USE_WMAKE)
+# include "cmGlobalWatcomWMakeGenerator.h"
+#endif
+#if !defined(CMAKE_BOOTSTRAP)
+# include "cmGlobalNinjaGenerator.h"
+# include "cmGlobalUnixMakefileGenerator3.h"
+#elif defined(CMAKE_BOOTSTRAP_MAKEFILES)
+# include "cmGlobalUnixMakefileGenerator3.h"
+#elif defined(CMAKE_BOOTSTRAP_NINJA)
+# include "cmGlobalNinjaGenerator.h"
+#endif
+
+#if !defined(CMAKE_BOOTSTRAP)
+# include "cmExtraCodeBlocksGenerator.h"
+# include "cmExtraCodeLiteGenerator.h"
+# include "cmExtraEclipseCDT4Generator.h"
+# include "cmExtraKateGenerator.h"
+# include "cmExtraSublimeTextGenerator.h"
+#endif
+
+#if defined(__linux__) || defined(_WIN32)
+# include "cmGlobalGhsMultiGenerator.h"
+#endif
+
+#if defined(__APPLE__)
+# if !defined(CMAKE_BOOTSTRAP)
+# include "cmGlobalXCodeGenerator.h"
+
+# define CMAKE_USE_XCODE 1
+# endif
+# include <sys/resource.h>
+# include <sys/time.h>
+#endif
+
+namespace {
+
+#if !defined(CMAKE_BOOTSTRAP)
+using JsonValueMapType = std::unordered_map<std::string, Json::Value>;
+#endif
+
+auto IgnoreAndTrueLambda = [](std::string const&, cmake*) -> bool {
+ return true;
+};
+
+using CommandArgument =
+ cmCommandLineArgument<bool(std::string const& value, cmake* state)>;
+
+} // namespace
+
+static bool cmakeCheckStampFile(const std::string& stampName);
+static bool cmakeCheckStampList(const std::string& stampList);
+
+#ifndef CMAKE_BOOTSTRAP
+static void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/,
+ void* ctx, const char* /*unused*/,
+ const cmMakefile* /*unused*/)
+{
+ cmake* cm = reinterpret_cast<cmake*>(ctx);
+ cm->MarkCliAsUsed(variable);
+}
+#endif
+
+cmake::cmake(Role role, cmState::Mode mode)
+ : FileTimeCache(cm::make_unique<cmFileTimeCache>())
+#ifndef CMAKE_BOOTSTRAP
+ , VariableWatch(cm::make_unique<cmVariableWatch>())
+#endif
+ , State(cm::make_unique<cmState>())
+ , Messenger(cm::make_unique<cmMessenger>())
+{
+ this->TraceFile.close();
+ this->State->SetMode(mode);
+ this->CurrentSnapshot = this->State->CreateBaseSnapshot();
+
+#ifdef __APPLE__
+ struct rlimit rlp;
+ if (!getrlimit(RLIMIT_STACK, &rlp)) {
+ if (rlp.rlim_cur != rlp.rlim_max) {
+ rlp.rlim_cur = rlp.rlim_max;
+ setrlimit(RLIMIT_STACK, &rlp);
+ }
+ }
+#endif
+
+ this->AddDefaultGenerators();
+ this->AddDefaultExtraGenerators();
+ if (role == RoleScript || role == RoleProject) {
+ this->AddScriptingCommands();
+ }
+ if (role == RoleProject) {
+ this->AddProjectCommands();
+ }
+
+ if (mode == cmState::Project) {
+ this->LoadEnvironmentPresets();
+ }
+
+ // Make sure we can capture the build tool output.
+ cmSystemTools::EnableVSConsoleOutput();
+
+ // Set up a list of source and header extensions.
+ // These are used to find files when the extension is not given.
+ {
+ auto setupExts = [](FileExtensions& exts,
+ std::initializer_list<cm::string_view> extList) {
+ // Fill ordered vector
+ exts.ordered.reserve(extList.size());
+ for (cm::string_view ext : extList) {
+ exts.ordered.emplace_back(ext);
+ };
+ // Fill unordered set
+ exts.unordered.insert(exts.ordered.begin(), exts.ordered.end());
+ };
+
+ // The "c" extension MUST precede the "C" extension.
+ setupExts(this->CLikeSourceFileExtensions,
+ { "c", "C", "c++", "cc", "cpp", "cxx", "cu", "mpp", "m", "M",
+ "mm", "ixx", "cppm" });
+ setupExts(this->HeaderFileExtensions,
+ { "h", "hh", "h++", "hm", "hpp", "hxx", "in", "txx" });
+ setupExts(this->CudaFileExtensions, { "cu" });
+ setupExts(this->FortranFileExtensions,
+ { "f", "F", "for", "f77", "f90", "f95", "f03" });
+ setupExts(this->ISPCFileExtensions, { "ispc" });
+ }
+}
+
+cmake::~cmake() = default;
+
+#if !defined(CMAKE_BOOTSTRAP)
+Json::Value cmake::ReportVersionJson() const
+{
+ Json::Value version = Json::objectValue;
+ version["string"] = CMake_VERSION;
+ version["major"] = CMake_VERSION_MAJOR;
+ version["minor"] = CMake_VERSION_MINOR;
+ version["suffix"] = CMake_VERSION_SUFFIX;
+ version["isDirty"] = (CMake_VERSION_IS_DIRTY == 1);
+ version["patch"] = CMake_VERSION_PATCH;
+ return version;
+}
+
+Json::Value cmake::ReportCapabilitiesJson() const
+{
+ Json::Value obj = Json::objectValue;
+
+ // Version information:
+ obj["version"] = this->ReportVersionJson();
+
+ // Generators:
+ std::vector<cmake::GeneratorInfo> generatorInfoList;
+ this->GetRegisteredGenerators(generatorInfoList);
+
+ JsonValueMapType generatorMap;
+ for (cmake::GeneratorInfo const& gi : generatorInfoList) {
+ if (gi.isAlias) { // skip aliases, they are there for compatibility reasons
+ // only
+ continue;
+ }
+
+ if (gi.extraName.empty()) {
+ Json::Value gen = Json::objectValue;
+ gen["name"] = gi.name;
+ gen["toolsetSupport"] = gi.supportsToolset;
+ gen["platformSupport"] = gi.supportsPlatform;
+ gen["extraGenerators"] = Json::arrayValue;
+ generatorMap[gi.name] = gen;
+ } else {
+ Json::Value& gen = generatorMap[gi.baseName];
+ gen["extraGenerators"].append(gi.extraName);
+ }
+ }
+
+ Json::Value generators = Json::arrayValue;
+ for (auto const& i : generatorMap) {
+ generators.append(i.second);
+ }
+ obj["generators"] = generators;
+ obj["fileApi"] = cmFileAPI::ReportCapabilities();
+ obj["serverMode"] = false;
+
+ return obj;
+}
+#endif
+
+std::string cmake::ReportCapabilities() const
+{
+ std::string result;
+#if !defined(CMAKE_BOOTSTRAP)
+ Json::FastWriter writer;
+ result = writer.write(this->ReportCapabilitiesJson());
+#else
+ result = "Not supported";
+#endif
+ return result;
+}
+
+void cmake::CleanupCommandsAndMacros()
+{
+ this->CurrentSnapshot = this->State->Reset();
+ this->State->RemoveUserDefinedCommands();
+ this->CurrentSnapshot.SetDefaultDefinitions();
+ // FIXME: InstalledFiles probably belongs in the global generator.
+ this->InstalledFiles.clear();
+}
+
+#ifndef CMAKE_BOOTSTRAP
+void cmake::SetWarningFromPreset(const std::string& name,
+ const cm::optional<bool>& warning,
+ const cm::optional<bool>& error)
+{
+ if (warning) {
+ if (*warning) {
+ this->DiagLevels[name] = std::max(this->DiagLevels[name], DIAG_WARN);
+ } else {
+ this->DiagLevels[name] = DIAG_IGNORE;
+ }
+ }
+ if (error) {
+ if (*error) {
+ this->DiagLevels[name] = DIAG_ERROR;
+ } else {
+ this->DiagLevels[name] = std::min(this->DiagLevels[name], DIAG_WARN);
+ }
+ }
+}
+
+void cmake::ProcessPresetVariables()
+{
+ for (auto const& var : this->UnprocessedPresetVariables) {
+ if (!var.second) {
+ continue;
+ }
+ cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
+ if (!var.second->Type.empty()) {
+ type = cmState::StringToCacheEntryType(var.second->Type);
+ }
+ this->ProcessCacheArg(var.first, var.second->Value, type);
+ }
+}
+
+void cmake::PrintPresetVariables()
+{
+ bool first = true;
+ for (auto const& var : this->UnprocessedPresetVariables) {
+ if (!var.second) {
+ continue;
+ }
+ cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
+ if (!var.second->Type.empty()) {
+ type = cmState::StringToCacheEntryType(var.second->Type);
+ }
+ if (first) {
+ std::cout << "Preset CMake variables:\n\n";
+ first = false;
+ }
+ std::cout << " " << var.first;
+ if (type != cmStateEnums::UNINITIALIZED) {
+ std::cout << ':' << cmState::CacheEntryTypeToString(type);
+ }
+ std::cout << "=\"" << var.second->Value << "\"\n";
+ }
+ if (!first) {
+ std::cout << '\n';
+ }
+ this->UnprocessedPresetVariables.clear();
+}
+
+void cmake::ProcessPresetEnvironment()
+{
+ for (auto const& var : this->UnprocessedPresetEnvironment) {
+ if (var.second) {
+ cmSystemTools::PutEnv(cmStrCat(var.first, '=', *var.second));
+ }
+ }
+}
+
+void cmake::PrintPresetEnvironment()
+{
+ bool first = true;
+ for (auto const& var : this->UnprocessedPresetEnvironment) {
+ if (!var.second) {
+ continue;
+ }
+ if (first) {
+ std::cout << "Preset environment variables:\n\n";
+ first = false;
+ }
+ std::cout << " " << var.first << "=\"" << *var.second << "\"\n";
+ }
+ if (!first) {
+ std::cout << '\n';
+ }
+ this->UnprocessedPresetEnvironment.clear();
+}
+#endif
+
+// Parse the args
+bool cmake::SetCacheArgs(const std::vector<std::string>& args)
+{
+ auto findPackageMode = false;
+ auto seenScriptOption = false;
+
+ auto DefineLambda = [](std::string const& entry, cmake* state) -> bool {
+ std::string var;
+ std::string value;
+ cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
+ if (cmState::ParseCacheEntry(entry, var, value, type)) {
+#ifndef CMAKE_BOOTSTRAP
+ state->UnprocessedPresetVariables.erase(var);
+#endif
+ state->ProcessCacheArg(var, value, type);
+ } else {
+ cmSystemTools::Error(cmStrCat("Parse error in command line argument: ",
+ entry, "\n Should be: VAR:type=value\n"));
+ return false;
+ }
+ return true;
+ };
+
+ auto WarningLambda = [](cm::string_view entry, cmake* state) -> bool {
+ bool foundNo = false;
+ bool foundError = false;
+
+ if (cmHasLiteralPrefix(entry, "no-")) {
+ foundNo = true;
+ entry.remove_prefix(3);
+ }
+
+ if (cmHasLiteralPrefix(entry, "error=")) {
+ foundError = true;
+ entry.remove_prefix(6);
+ }
+
+ if (entry.empty()) {
+ cmSystemTools::Error("No warning name provided.");
+ return false;
+ }
+
+ std::string const name = std::string(entry);
+ if (!foundNo && !foundError) {
+ // -W<name>
+ state->DiagLevels[name] = std::max(state->DiagLevels[name], DIAG_WARN);
+ } else if (foundNo && !foundError) {
+ // -Wno<name>
+ state->DiagLevels[name] = DIAG_IGNORE;
+ } else if (!foundNo && foundError) {
+ // -Werror=<name>
+ state->DiagLevels[name] = DIAG_ERROR;
+ } else {
+ // -Wno-error=<name>
+ // This can downgrade an error to a warning, but should not enable
+ // or disable a warning in the first place.
+ auto dli = state->DiagLevels.find(name);
+ if (dli != state->DiagLevels.end()) {
+ dli->second = std::min(dli->second, DIAG_WARN);
+ }
+ }
+ return true;
+ };
+
+ auto UnSetLambda = [](std::string const& entryPattern,
+ cmake* state) -> bool {
+ cmsys::RegularExpression regex(
+ cmsys::Glob::PatternToRegex(entryPattern, true, true));
+ // go through all cache entries and collect the vars which will be
+ // removed
+ std::vector<std::string> entriesToDelete;
+ std::vector<std::string> cacheKeys = state->State->GetCacheEntryKeys();
+ for (std::string const& ck : cacheKeys) {
+ cmStateEnums::CacheEntryType t = state->State->GetCacheEntryType(ck);
+ if (t != cmStateEnums::STATIC) {
+ if (regex.find(ck)) {
+ entriesToDelete.push_back(ck);
+ }
+ }
+ }
+
+ // now remove them from the cache
+ for (std::string const& currentEntry : entriesToDelete) {
+#ifndef CMAKE_BOOTSTRAP
+ state->UnprocessedPresetVariables.erase(currentEntry);
+#endif
+ state->State->RemoveCacheEntry(currentEntry);
+ }
+ return true;
+ };
+
+ auto ScriptLambda = [&](std::string const& path, cmake* state) -> bool {
+ // Register fake project commands that hint misuse in script mode.
+ GetProjectCommandsInScriptMode(state->GetState());
+ // Documented behaviour of CMAKE{,_CURRENT}_{SOURCE,BINARY}_DIR is to be
+ // set to $PWD for -P mode.
+ state->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ state->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ state->ReadListFile(args, path);
+ seenScriptOption = true;
+ return true;
+ };
+
+ auto PrefixLambda = [&](std::string const& path, cmake* state) -> bool {
+ const std::string var = "CMAKE_INSTALL_PREFIX";
+ cmStateEnums::CacheEntryType type = cmStateEnums::PATH;
+ cmCMakePath absolutePath(path);
+ if (absolutePath.IsAbsolute()) {
+#ifndef CMAKE_BOOTSTRAP
+ state->UnprocessedPresetVariables.erase(var);
+#endif
+ state->ProcessCacheArg(var, path, type);
+ return true;
+ }
+ cmSystemTools::Error("Absolute paths are required for --install-prefix");
+ return false;
+ };
+
+ std::vector<CommandArgument> arguments = {
+ CommandArgument{ "-D", "-D must be followed with VAR=VALUE.",
+ CommandArgument::Values::One, DefineLambda },
+ CommandArgument{ "-W", "-W must be followed with [no-]<name>.",
+ CommandArgument::Values::One, WarningLambda },
+ CommandArgument{ "-U", "-U must be followed with VAR.",
+ CommandArgument::Values::One, UnSetLambda },
+ CommandArgument{ "-C", "-C must be followed by a file name.",
+ CommandArgument::Values::One,
+ [&](std::string const& value, cmake* state) -> bool {
+ cmSystemTools::Stdout("loading initial cache file " +
+ value + "\n");
+ // Resolve script path specified on command line
+ // relative to $PWD.
+ auto path = cmSystemTools::CollapseFullPath(value);
+ state->ReadListFile(args, path);
+ return true;
+ } },
+
+ CommandArgument{ "-P", "-P must be followed by a file name.",
+ CommandArgument::Values::One, ScriptLambda },
+ CommandArgument{ "--install-prefix",
+ "No install directory specified for --install-prefix",
+ CommandArgument::Values::One, PrefixLambda },
+ CommandArgument{ "--find-package", CommandArgument::Values::Zero,
+ [&](std::string const&, cmake*) -> bool {
+ findPackageMode = true;
+ return true;
+ } },
+ };
+ for (decltype(args.size()) i = 1; i < args.size(); ++i) {
+ std::string const& arg = args[i];
+
+ if (arg == "--" && seenScriptOption) {
+ // Stop processing CMake args and avoid possible errors
+ // when arbitrary args are given to CMake script.
+ break;
+ }
+ for (auto const& m : arguments) {
+ if (m.matches(arg)) {
+ const bool parsedCorrectly = m.parse(arg, i, args, this);
+ if (!parsedCorrectly) {
+ return false;
+ }
+ }
+ }
+ }
+
+ if (findPackageMode) {
+ return this->FindPackage(args);
+ }
+
+ return true;
+}
+
+void cmake::ProcessCacheArg(const std::string& var, const std::string& value,
+ cmStateEnums::CacheEntryType type)
+{
+ // The value is transformed if it is a filepath for example, so
+ // we can't compare whether the value is already in the cache until
+ // after we call AddCacheEntry.
+ bool haveValue = false;
+ std::string cachedValue;
+ if (this->WarnUnusedCli) {
+ if (cmProp v = this->State->GetInitializedCacheValue(var)) {
+ haveValue = true;
+ cachedValue = *v;
+ }
+ }
+
+ this->AddCacheEntry(var, value.c_str(),
+ "No help, variable specified on the command line.",
+ type);
+
+ if (this->WarnUnusedCli) {
+ if (!haveValue ||
+ cachedValue != *this->State->GetInitializedCacheValue(var)) {
+ this->WatchUnusedCli(var);
+ }
+ }
+}
+
+void cmake::ReadListFile(const std::vector<std::string>& args,
+ const std::string& path)
+{
+ // if a generator was not yet created, temporarily create one
+ cmGlobalGenerator* gg = this->GetGlobalGenerator();
+
+ // if a generator was not specified use a generic one
+ std::unique_ptr<cmGlobalGenerator> gen;
+ if (!gg) {
+ gen = cm::make_unique<cmGlobalGenerator>(this);
+ gg = gen.get();
+ }
+
+ // read in the list file to fill the cache
+ if (!path.empty()) {
+ this->CurrentSnapshot = this->State->Reset();
+ cmStateSnapshot snapshot = this->GetCurrentSnapshot();
+ snapshot.GetDirectory().SetCurrentBinary(this->GetHomeOutputDirectory());
+ snapshot.GetDirectory().SetCurrentSource(this->GetHomeDirectory());
+ snapshot.SetDefaultDefinitions();
+ cmMakefile mf(gg, snapshot);
+ if (this->GetWorkingMode() != NORMAL_MODE) {
+ std::string file(cmSystemTools::CollapseFullPath(path));
+ cmSystemTools::ConvertToUnixSlashes(file);
+ mf.SetScriptModeFile(file);
+
+ mf.SetArgcArgv(args);
+ }
+ if (!mf.ReadListFile(path)) {
+ cmSystemTools::Error("Error processing file: " + path);
+ }
+ }
+}
+
+bool cmake::FindPackage(const std::vector<std::string>& args)
+{
+ this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+
+ this->SetGlobalGenerator(cm::make_unique<cmGlobalGenerator>(this));
+
+ cmStateSnapshot snapshot = this->GetCurrentSnapshot();
+ snapshot.GetDirectory().SetCurrentBinary(
+ cmSystemTools::GetCurrentWorkingDirectory());
+ snapshot.GetDirectory().SetCurrentSource(
+ cmSystemTools::GetCurrentWorkingDirectory());
+ // read in the list file to fill the cache
+ snapshot.SetDefaultDefinitions();
+ auto mfu = cm::make_unique<cmMakefile>(this->GetGlobalGenerator(), snapshot);
+ cmMakefile* mf = mfu.get();
+ this->GlobalGenerator->AddMakefile(std::move(mfu));
+
+ mf->SetArgcArgv(args);
+
+ std::string systemFile = mf->GetModulesFile("CMakeFindPackageMode.cmake");
+ mf->ReadListFile(systemFile);
+
+ std::string language = mf->GetSafeDefinition("LANGUAGE");
+ std::string mode = mf->GetSafeDefinition("MODE");
+ std::string packageName = mf->GetSafeDefinition("NAME");
+ bool packageFound = mf->IsOn("PACKAGE_FOUND");
+ bool quiet = mf->IsOn("PACKAGE_QUIET");
+
+ if (!packageFound) {
+ if (!quiet) {
+ printf("%s not found.\n", packageName.c_str());
+ }
+ } else if (mode == "EXIST"_s) {
+ if (!quiet) {
+ printf("%s found.\n", packageName.c_str());
+ }
+ } else if (mode == "COMPILE"_s) {
+ std::string includes = mf->GetSafeDefinition("PACKAGE_INCLUDE_DIRS");
+ std::vector<std::string> includeDirs = cmExpandedList(includes);
+
+ this->GlobalGenerator->CreateGenerationObjects();
+ const auto& lg = this->GlobalGenerator->LocalGenerators[0];
+ std::string includeFlags =
+ lg->GetIncludeFlags(includeDirs, nullptr, language, std::string());
+
+ std::string definitions = mf->GetSafeDefinition("PACKAGE_DEFINITIONS");
+ printf("%s %s\n", includeFlags.c_str(), definitions.c_str());
+ } else if (mode == "LINK"_s) {
+ const char* targetName = "dummy";
+ std::vector<std::string> srcs;
+ cmTarget* tgt = mf->AddExecutable(targetName, srcs, true);
+ tgt->SetProperty("LINKER_LANGUAGE", language);
+
+ std::string libs = mf->GetSafeDefinition("PACKAGE_LIBRARIES");
+ std::vector<std::string> libList = cmExpandedList(libs);
+ for (std::string const& lib : libList) {
+ tgt->AddLinkLibrary(*mf, lib, GENERAL_LibraryType);
+ }
+
+ std::string buildType = mf->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ buildType = cmSystemTools::UpperCase(buildType);
+
+ std::string linkLibs;
+ std::string frameworkPath;
+ std::string linkPath;
+ std::string flags;
+ std::string linkFlags;
+ this->GlobalGenerator->CreateGenerationObjects();
+ cmGeneratorTarget* gtgt =
+ this->GlobalGenerator->FindGeneratorTarget(tgt->GetName());
+ cmLocalGenerator* lg = gtgt->GetLocalGenerator();
+ cmLinkLineComputer linkLineComputer(lg,
+ lg->GetStateSnapshot().GetDirectory());
+ lg->GetTargetFlags(&linkLineComputer, buildType, linkLibs, flags,
+ linkFlags, frameworkPath, linkPath, gtgt);
+ linkLibs = frameworkPath + linkPath + linkLibs;
+
+ printf("%s\n", linkLibs.c_str());
+
+ /* if ( use_win32 )
+ {
+ tgt->SetProperty("WIN32_EXECUTABLE", "ON");
+ }
+ if ( use_macbundle)
+ {
+ tgt->SetProperty("MACOSX_BUNDLE", "ON");
+ }*/
+ }
+
+ return packageFound;
+}
+
+void cmake::LoadEnvironmentPresets()
+{
+ std::string envGenVar;
+ bool hasEnvironmentGenerator = false;
+ if (cmSystemTools::GetEnv("CMAKE_GENERATOR", envGenVar)) {
+ hasEnvironmentGenerator = true;
+ this->EnvironmentGenerator = envGenVar;
+ }
+
+ auto readGeneratorVar = [&](std::string const& name, std::string& key) {
+ std::string varValue;
+ if (cmSystemTools::GetEnv(name, varValue)) {
+ if (hasEnvironmentGenerator) {
+ key = varValue;
+ } else if (!this->GetIsInTryCompile()) {
+ std::string message =
+ cmStrCat("Warning: Environment variable ", name,
+ " will be ignored, because CMAKE_GENERATOR is not set.");
+ cmSystemTools::Message(message, "Warning");
+ }
+ }
+ };
+
+ readGeneratorVar("CMAKE_GENERATOR_INSTANCE", this->GeneratorInstance);
+ readGeneratorVar("CMAKE_GENERATOR_PLATFORM", this->GeneratorPlatform);
+ readGeneratorVar("CMAKE_GENERATOR_TOOLSET", this->GeneratorToolset);
+}
+
+namespace {
+enum class ListPresets
+{
+ None,
+ Configure,
+ Build,
+ Test,
+ All,
+};
+}
+
+// Parse the args
+void cmake::SetArgs(const std::vector<std::string>& args)
+{
+ bool haveToolset = false;
+ bool havePlatform = false;
+ bool haveBArg = false;
+ bool scriptMode = false;
+ std::string possibleUnknownArg;
+#if !defined(CMAKE_BOOTSTRAP)
+ std::string profilingFormat;
+ std::string profilingOutput;
+ std::string presetName;
+
+ ListPresets listPresets = ListPresets::None;
+#endif
+
+ auto SourceArgLambda = [](std::string const& value, cmake* state) -> bool {
+ std::string path = cmSystemTools::CollapseFullPath(value);
+ cmSystemTools::ConvertToUnixSlashes(path);
+ state->SetHomeDirectory(path);
+ return true;
+ };
+
+ auto BuildArgLambda = [&](std::string const& value, cmake* state) -> bool {
+ std::string path = cmSystemTools::CollapseFullPath(value);
+ cmSystemTools::ConvertToUnixSlashes(path);
+ state->SetHomeOutputDirectory(path);
+ haveBArg = true;
+ return true;
+ };
+
+ auto PlatformLambda = [&](std::string const& value, cmake* state) -> bool {
+ if (havePlatform) {
+ cmSystemTools::Error("Multiple -A options not allowed");
+ return false;
+ }
+ state->SetGeneratorPlatform(value);
+ havePlatform = true;
+ return true;
+ };
+
+ auto ToolsetLamda = [&](std::string const& value, cmake* state) -> bool {
+ if (haveToolset) {
+ cmSystemTools::Error("Multiple -T options not allowed");
+ return false;
+ }
+ state->SetGeneratorToolset(value);
+ haveToolset = true;
+ return true;
+ };
+
+ std::vector<CommandArgument> arguments = {
+ CommandArgument{ "-S", "No source directory specified for -S",
+ CommandArgument::Values::One, SourceArgLambda },
+ CommandArgument{ "-H", "No source directory specified for -H",
+ CommandArgument::Values::One, SourceArgLambda },
+ CommandArgument{ "-O", CommandArgument::Values::Zero,
+ IgnoreAndTrueLambda },
+ CommandArgument{ "-B", "No build directory specified for -B",
+ CommandArgument::Values::One, BuildArgLambda },
+ CommandArgument{ "-P", "-P must be followed by a file name.",
+ CommandArgument::Values::One,
+ [&](std::string const&, cmake*) -> bool {
+ scriptMode = true;
+ return true;
+ } },
+ CommandArgument{ "-D", "-D must be followed with VAR=VALUE.",
+ CommandArgument::Values::One, IgnoreAndTrueLambda },
+ CommandArgument{ "-C", "-C must be followed by a file name.",
+ CommandArgument::Values::One, IgnoreAndTrueLambda },
+ CommandArgument{ "-U", "-U must be followed with VAR.",
+ CommandArgument::Values::One, IgnoreAndTrueLambda },
+ CommandArgument{ "-W", "-W must be followed with [no-]<name>.",
+ CommandArgument::Values::One, IgnoreAndTrueLambda },
+ CommandArgument{ "-A", "No platform specified for -A",
+ CommandArgument::Values::One, PlatformLambda },
+ CommandArgument{ "-T", "No toolset specified for -T",
+ CommandArgument::Values::One, ToolsetLamda },
+ CommandArgument{ "--install-prefix",
+ "No install directory specified for --install-prefix",
+ CommandArgument::Values::One, IgnoreAndTrueLambda },
+
+ CommandArgument{ "--check-build-system", CommandArgument::Values::Two,
+ [](std::string const& value, cmake* state) -> bool {
+ std::vector<std::string> values = cmExpandedList(value);
+ state->CheckBuildSystemArgument = values[0];
+ state->ClearBuildSystem = (atoi(values[1].c_str()) > 0);
+ return true;
+ } },
+ CommandArgument{ "--check-stamp-file", CommandArgument::Values::One,
+ [](std::string const& value, cmake* state) -> bool {
+ state->CheckStampFile = value;
+ return true;
+ } },
+ CommandArgument{ "--check-stamp-list", CommandArgument::Values::One,
+ [](std::string const& value, cmake* state) -> bool {
+ state->CheckStampList = value;
+ return true;
+ } },
+ CommandArgument{ "--regenerate-during-build",
+ CommandArgument::Values::Zero,
+ [](std::string const&, cmake* state) -> bool {
+ state->RegenerateDuringBuild = true;
+ return true;
+ } },
+
+ CommandArgument{ "--find-package", CommandArgument::Values::Zero,
+ IgnoreAndTrueLambda },
+
+ CommandArgument{ "--graphviz", "No file specified for --graphviz",
+ CommandArgument::Values::One,
+ [](std::string const& value, cmake* state) -> bool {
+ std::string path =
+ cmSystemTools::CollapseFullPath(value);
+ cmSystemTools::ConvertToUnixSlashes(path);
+ state->GraphVizFile = path;
+ return true;
+ } },
+
+ CommandArgument{ "--debug-trycompile", CommandArgument::Values::Zero,
+ [](std::string const&, cmake* state) -> bool {
+ std::cout << "debug trycompile on\n";
+ state->DebugTryCompileOn();
+ return true;
+ } },
+ CommandArgument{ "--debug-output", CommandArgument::Values::Zero,
+ [](std::string const&, cmake* state) -> bool {
+ std::cout << "Running with debug output on.\n";
+ state->SetDebugOutputOn(true);
+ return true;
+ } },
+
+ CommandArgument{ "--log-level", "Invalid level specified for --log-level",
+ CommandArgument::Values::One,
+ [](std::string const& value, cmake* state) -> bool {
+ const auto logLevel = StringToLogLevel(value);
+ if (logLevel == LogLevel::LOG_UNDEFINED) {
+ cmSystemTools::Error(
+ "Invalid level specified for --log-level");
+ return false;
+ }
+ state->SetLogLevel(logLevel);
+ state->LogLevelWasSetViaCLI = true;
+ return true;
+ } },
+ // This is supported for backward compatibility. This option only
+ // appeared in the 3.15.x release series and was renamed to
+ // --log-level in 3.16.0
+ CommandArgument{ "--loglevel", "Invalid level specified for --loglevel",
+ CommandArgument::Values::One,
+ [](std::string const& value, cmake* state) -> bool {
+ const auto logLevel = StringToLogLevel(value);
+ if (logLevel == LogLevel::LOG_UNDEFINED) {
+ cmSystemTools::Error(
+ "Invalid level specified for --loglevel");
+ return false;
+ }
+ state->SetLogLevel(logLevel);
+ state->LogLevelWasSetViaCLI = true;
+ return true;
+ } },
+
+ CommandArgument{ "--log-context", CommandArgument::Values::Zero,
+ [](std::string const&, cmake* state) -> bool {
+ state->SetShowLogContext(true);
+ return true;
+ } },
+ CommandArgument{
+ "--debug-find", CommandArgument::Values::Zero,
+ [](std::string const&, cmake* state) -> bool {
+ std::cout << "Running with debug output on for the `find` commands.\n";
+ state->SetDebugFindOutputOn(true);
+ return true;
+ } },
+ CommandArgument{ "--trace-expand", CommandArgument::Values::Zero,
+ [](std::string const&, cmake* state) -> bool {
+ std::cout << "Running with expanded trace output on.\n";
+ state->SetTrace(true);
+ state->SetTraceExpand(true);
+ return true;
+ } },
+ CommandArgument{ "--trace-format", CommandArgument::Values::One,
+ [](std::string const& value, cmake* state) -> bool {
+ state->SetTrace(true);
+ const auto traceFormat = StringToTraceFormat(value);
+ if (traceFormat == TraceFormat::TRACE_UNDEFINED) {
+ cmSystemTools::Error(
+ "Invalid format specified for --trace-format. "
+ "Valid formats are human, json-v1.");
+ return false;
+ }
+ state->SetTraceFormat(traceFormat);
+ return true;
+ } },
+ CommandArgument{ "--trace-source", CommandArgument::Values::One,
+ [](std::string const& value, cmake* state) -> bool {
+ std::string file(value);
+ cmSystemTools::ConvertToUnixSlashes(file);
+ state->AddTraceSource(file);
+ state->SetTrace(true);
+ return true;
+ } },
+ CommandArgument{ "--trace-redirect", CommandArgument::Values::One,
+ [](std::string const& value, cmake* state) -> bool {
+ std::string file(value);
+ cmSystemTools::ConvertToUnixSlashes(file);
+ state->SetTraceFile(file);
+ state->SetTrace(true);
+ return true;
+ } },
+ CommandArgument{ "--trace", CommandArgument::Values::Zero,
+ [](std::string const&, cmake* state) -> bool {
+ std::cout << "Running with trace output on.\n";
+ state->SetTrace(true);
+ state->SetTraceExpand(false);
+ return true;
+ } },
+ CommandArgument{ "--warn-uninitialized", CommandArgument::Values::Zero,
+ [](std::string const&, cmake* state) -> bool {
+ std::cout << "Warn about uninitialized values.\n";
+ state->SetWarnUninitialized(true);
+ return true;
+ } },
+ CommandArgument{ "--warn-unused-vars", CommandArgument::Values::Zero,
+ IgnoreAndTrueLambda }, // Option was removed.
+ CommandArgument{ "--no-warn-unused-cli", CommandArgument::Values::Zero,
+ [](std::string const&, cmake* state) -> bool {
+ std::cout
+ << "Not searching for unused variables given on the "
+ << "command line.\n";
+ state->SetWarnUnusedCli(false);
+ return true;
+ } },
+ CommandArgument{
+ "--check-system-vars", CommandArgument::Values::Zero,
+ [](std::string const&, cmake* state) -> bool {
+ std::cout << "Also check system files when warning about unused and "
+ << "uninitialized variables.\n";
+ state->SetCheckSystemVars(true);
+ return true;
+ } }
+ };
+
+#if defined(CMAKE_HAVE_VS_GENERATORS)
+ arguments.emplace_back("--vs-solution-file", CommandArgument::Values::One,
+ [](std::string const& value, cmake* state) -> bool {
+ state->VSSolutionFile = value;
+ return true;
+ });
+#endif
+
+#if !defined(CMAKE_BOOTSTRAP)
+ arguments.emplace_back("--profiling-format",
+ "No format specified for --profiling-format",
+ CommandArgument::Values::One,
+ [&](std::string const& value, cmake*) -> bool {
+ profilingFormat = value;
+ return true;
+ });
+ arguments.emplace_back(
+ "--profiling-output", "No path specified for --profiling-output",
+ CommandArgument::Values::One,
+ [&](std::string const& value, cmake*) -> bool {
+ profilingOutput = cmSystemTools::CollapseFullPath(value);
+ cmSystemTools::ConvertToUnixSlashes(profilingOutput);
+ return true;
+ });
+ arguments.emplace_back("--preset", "No preset specified for --preset",
+ CommandArgument::Values::One,
+ [&](std::string const& value, cmake*) -> bool {
+ presetName = value;
+ return true;
+ });
+ arguments.emplace_back(
+ "--list-presets", CommandArgument::Values::ZeroOrOne,
+ [&](std::string const& value, cmake*) -> bool {
+ if (value.empty() || value == "configure") {
+ listPresets = ListPresets::Configure;
+ } else if (value == "build") {
+ listPresets = ListPresets::Build;
+ } else if (value == "test") {
+ listPresets = ListPresets::Test;
+ } else if (value == "all") {
+ listPresets = ListPresets::All;
+ } else {
+ cmSystemTools::Error(
+ "Invalid value specified for --list-presets.\n"
+ "Valid values are configure, build, test, or all. "
+ "When no value is passed the default is configure.");
+ return false;
+ }
+
+ return true;
+ });
+
+#endif
+
+ bool badGeneratorName = false;
+ CommandArgument generatorCommand(
+ "-G", "No generator specified for -G", CommandArgument::Values::One,
+ [&](std::string const& value, cmake* state) -> bool {
+ bool valid = state->CreateAndSetGlobalGenerator(value, true);
+ badGeneratorName = !valid;
+ return valid;
+ });
+
+ for (decltype(args.size()) i = 1; i < args.size(); ++i) {
+ // iterate each argument
+ std::string const& arg = args[i];
+
+ // Generator flag has special handling for when to print help
+ // so it becomes the exception
+ if (generatorCommand.matches(arg)) {
+ bool parsed = generatorCommand.parse(arg, i, args, this);
+ if (!parsed && !badGeneratorName) {
+ this->PrintGeneratorList();
+ return;
+ }
+ continue;
+ }
+
+ bool matched = false;
+ bool parsedCorrectly = true; // needs to be true so we can ignore
+ // arguments so as -E
+ for (auto const& m : arguments) {
+ if (m.matches(arg)) {
+ matched = true;
+ parsedCorrectly = m.parse(arg, i, args, this);
+ break;
+ }
+ }
+
+ // We have an issue where arguments to a "-P" script mode
+ // can be provided before the "-P" argument. This means
+ // that we need to lazily check this argument after checking
+ // all args.
+ // Additionally it can't be the source/binary tree location
+ if (!parsedCorrectly) {
+ cmSystemTools::Error("Run 'cmake --help' for all supported options.");
+ exit(1);
+ } else if (!matched && cmHasLiteralPrefix(arg, "-")) {
+ possibleUnknownArg = arg;
+ } else if (!matched) {
+ this->SetDirectoriesFromFile(arg);
+ }
+ }
+
+ if (!possibleUnknownArg.empty() && !scriptMode) {
+ cmSystemTools::Error(cmStrCat("Unknown argument ", possibleUnknownArg));
+ cmSystemTools::Error("Run 'cmake --help' for all supported options.");
+ exit(1);
+ }
+
+ // Empty instance, platform and toolset if only a generator is specified
+ if (this->GlobalGenerator) {
+ this->GeneratorInstance = "";
+ if (!this->GeneratorPlatformSet) {
+ this->GeneratorPlatform = "";
+ }
+ if (!this->GeneratorToolsetSet) {
+ this->GeneratorToolset = "";
+ }
+ }
+
+#if !defined(CMAKE_BOOTSTRAP)
+ if (!profilingOutput.empty() || !profilingFormat.empty()) {
+ if (profilingOutput.empty()) {
+ cmSystemTools::Error(
+ "--profiling-format specified but no --profiling-output!");
+ return;
+ }
+ if (profilingFormat == "google-trace"_s) {
+ try {
+ this->ProfilingOutput =
+ cm::make_unique<cmMakefileProfilingData>(profilingOutput);
+ } catch (std::runtime_error& e) {
+ cmSystemTools::Error(
+ cmStrCat("Could not start profiling: ", e.what()));
+ return;
+ }
+ } else {
+ cmSystemTools::Error("Invalid format specified for --profiling-format");
+ return;
+ }
+ }
+#endif
+
+ const bool haveSourceDir = !this->GetHomeDirectory().empty();
+ const bool haveBinaryDir = !this->GetHomeOutputDirectory().empty();
+ const bool havePreset =
+#ifdef CMAKE_BOOTSTRAP
+ false;
+#else
+ !presetName.empty();
+#endif
+
+ if (this->CurrentWorkingMode == cmake::NORMAL_MODE && !haveSourceDir &&
+ !haveBinaryDir && !havePreset) {
+ this->IssueMessage(
+ MessageType::WARNING,
+ "No source or binary directory provided. Both will be assumed to be "
+ "the same as the current working directory, but note that this "
+ "warning will become a fatal error in future CMake releases.");
+ }
+
+ if (!haveSourceDir) {
+ this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ }
+ if (!haveBinaryDir) {
+ this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ }
+
+#if !defined(CMAKE_BOOTSTRAP)
+ if (listPresets != ListPresets::None || !presetName.empty()) {
+ cmCMakePresetsFile settingsFile;
+ auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory());
+ if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) {
+ cmSystemTools::Error(
+ cmStrCat("Could not read presets from ", this->GetHomeDirectory(),
+ ": ", cmCMakePresetsFile::ResultToString(result)));
+ return;
+ }
+
+ if (listPresets != ListPresets::None) {
+ if (listPresets == ListPresets::Configure) {
+ this->PrintPresetList(settingsFile);
+ } else if (listPresets == ListPresets::Build) {
+ settingsFile.PrintBuildPresetList();
+ } else if (listPresets == ListPresets::Test) {
+ settingsFile.PrintTestPresetList();
+ } else if (listPresets == ListPresets::All) {
+ settingsFile.PrintAllPresets();
+ }
+
+ this->SetWorkingMode(WorkingMode::HELP_MODE);
+ return;
+ }
+
+ auto preset = settingsFile.ConfigurePresets.find(presetName);
+ if (preset == settingsFile.ConfigurePresets.end()) {
+ cmSystemTools::Error(cmStrCat("No such preset in ",
+ this->GetHomeDirectory(), ": \"",
+ presetName, '"'));
+ this->PrintPresetList(settingsFile);
+ return;
+ }
+ if (preset->second.Unexpanded.Hidden) {
+ cmSystemTools::Error(cmStrCat("Cannot use hidden preset in ",
+ this->GetHomeDirectory(), ": \"",
+ presetName, '"'));
+ this->PrintPresetList(settingsFile);
+ return;
+ }
+ auto const& expandedPreset = preset->second.Expanded;
+ if (!expandedPreset) {
+ cmSystemTools::Error(cmStrCat("Could not evaluate preset \"",
+ preset->second.Unexpanded.Name,
+ "\": Invalid macro expansion"));
+ return;
+ }
+ if (!expandedPreset->ConditionResult) {
+ cmSystemTools::Error(cmStrCat("Could not use disabled preset \"",
+ preset->second.Unexpanded.Name, "\""));
+ return;
+ }
+
+ if (!this->State->IsCacheLoaded() && !haveBArg &&
+ !expandedPreset->BinaryDir.empty()) {
+ this->SetHomeOutputDirectory(expandedPreset->BinaryDir);
+ }
+ if (!this->GlobalGenerator && !expandedPreset->Generator.empty()) {
+ if (!this->CreateAndSetGlobalGenerator(expandedPreset->Generator,
+ false)) {
+ return;
+ }
+ }
+ this->UnprocessedPresetVariables = expandedPreset->CacheVariables;
+ this->UnprocessedPresetEnvironment = expandedPreset->Environment;
+
+ if (!expandedPreset->InstallDir.empty() &&
+ this->State->GetInitializedCacheValue("CMAKE_INSTALL_PREFIX") ==
+ nullptr) {
+ this->UnprocessedPresetVariables["CMAKE_INSTALL_PREFIX"] = {
+ "PATH", expandedPreset->InstallDir
+ };
+ }
+
+ if (!expandedPreset->ArchitectureStrategy ||
+ expandedPreset->ArchitectureStrategy ==
+ cmCMakePresetsFile::ArchToolsetStrategy::Set) {
+ if (!this->GeneratorPlatformSet) {
+ this->SetGeneratorPlatform(expandedPreset->Architecture);
+ }
+ }
+ if (!expandedPreset->ToolsetStrategy ||
+ expandedPreset->ToolsetStrategy ==
+ cmCMakePresetsFile::ArchToolsetStrategy::Set) {
+ if (!this->GeneratorToolsetSet) {
+ this->SetGeneratorToolset(expandedPreset->Toolset);
+ }
+ }
+
+ this->SetWarningFromPreset("dev", expandedPreset->WarnDev,
+ expandedPreset->ErrorDev);
+ this->SetWarningFromPreset("deprecated", expandedPreset->WarnDeprecated,
+ expandedPreset->ErrorDeprecated);
+ if (expandedPreset->WarnUninitialized == true) {
+ this->SetWarnUninitialized(true);
+ }
+ if (expandedPreset->WarnUnusedCli == false) {
+ this->SetWarnUnusedCli(false);
+ }
+ if (expandedPreset->WarnSystemVars == true) {
+ this->SetCheckSystemVars(true);
+ }
+ if (expandedPreset->DebugOutput == true) {
+ this->SetDebugOutputOn(true);
+ }
+ if (expandedPreset->DebugTryCompile == true) {
+ this->DebugTryCompileOn();
+ }
+ if (expandedPreset->DebugFind == true) {
+ this->SetDebugFindOutputOn(true);
+ }
+ }
+#endif
+}
+
+cmake::LogLevel cmake::StringToLogLevel(const std::string& levelStr)
+{
+ using LevelsPair = std::pair<std::string, LogLevel>;
+ static const std::vector<LevelsPair> levels = {
+ { "error", LogLevel::LOG_ERROR }, { "warning", LogLevel::LOG_WARNING },
+ { "notice", LogLevel::LOG_NOTICE }, { "status", LogLevel::LOG_STATUS },
+ { "verbose", LogLevel::LOG_VERBOSE }, { "debug", LogLevel::LOG_DEBUG },
+ { "trace", LogLevel::LOG_TRACE }
+ };
+
+ const auto levelStrLowCase = cmSystemTools::LowerCase(levelStr);
+
+ const auto it = std::find_if(levels.cbegin(), levels.cend(),
+ [&levelStrLowCase](const LevelsPair& p) {
+ return p.first == levelStrLowCase;
+ });
+ return (it != levels.cend()) ? it->second : LogLevel::LOG_UNDEFINED;
+}
+
+cmake::TraceFormat cmake::StringToTraceFormat(const std::string& traceStr)
+{
+ using TracePair = std::pair<std::string, TraceFormat>;
+ static const std::vector<TracePair> levels = {
+ { "human", TraceFormat::TRACE_HUMAN },
+ { "json-v1", TraceFormat::TRACE_JSON_V1 },
+ };
+
+ const auto traceStrLowCase = cmSystemTools::LowerCase(traceStr);
+
+ const auto it = std::find_if(levels.cbegin(), levels.cend(),
+ [&traceStrLowCase](const TracePair& p) {
+ return p.first == traceStrLowCase;
+ });
+ return (it != levels.cend()) ? it->second : TraceFormat::TRACE_UNDEFINED;
+}
+
+void cmake::SetTraceFile(const std::string& file)
+{
+ this->TraceFile.close();
+ this->TraceFile.open(file.c_str());
+ if (!this->TraceFile) {
+ std::stringstream ss;
+ ss << "Error opening trace file " << file << ": "
+ << cmSystemTools::GetLastSystemError();
+ cmSystemTools::Error(ss.str());
+ return;
+ }
+ std::cout << "Trace will be written to " << file << "\n";
+}
+
+void cmake::PrintTraceFormatVersion()
+{
+ if (!this->GetTrace()) {
+ return;
+ }
+
+ std::string msg;
+
+ switch (this->GetTraceFormat()) {
+ case TraceFormat::TRACE_JSON_V1: {
+#ifndef CMAKE_BOOTSTRAP
+ Json::Value val;
+ Json::Value version;
+ Json::StreamWriterBuilder builder;
+ builder["indentation"] = "";
+ version["major"] = 1;
+ version["minor"] = 1;
+ val["version"] = version;
+ msg = Json::writeString(builder, val);
+#endif
+ break;
+ }
+ case TraceFormat::TRACE_HUMAN:
+ msg = "";
+ break;
+ case TraceFormat::TRACE_UNDEFINED:
+ msg = "INTERNAL ERROR: Trace format is TRACE_UNDEFINED";
+ break;
+ }
+
+ if (msg.empty()) {
+ return;
+ }
+
+ auto& f = this->GetTraceFile();
+ if (f) {
+ f << msg << '\n';
+ } else {
+ cmSystemTools::Message(msg);
+ }
+}
+
+void cmake::SetDirectoriesFromFile(const std::string& arg)
+{
+ // Check if the argument refers to a CMakeCache.txt or
+ // CMakeLists.txt file.
+ std::string listPath;
+ std::string cachePath;
+ bool argIsFile = false;
+ if (cmSystemTools::FileIsDirectory(arg)) {
+ std::string path = cmSystemTools::CollapseFullPath(arg);
+ cmSystemTools::ConvertToUnixSlashes(path);
+ std::string cacheFile = cmStrCat(path, "/CMakeCache.txt");
+ std::string listFile = cmStrCat(path, "/CMakeLists.txt");
+ if (cmSystemTools::FileExists(cacheFile)) {
+ cachePath = path;
+ }
+ if (cmSystemTools::FileExists(listFile)) {
+ listPath = path;
+ }
+ } else if (cmSystemTools::FileExists(arg)) {
+ argIsFile = true;
+ std::string fullPath = cmSystemTools::CollapseFullPath(arg);
+ std::string name = cmSystemTools::GetFilenameName(fullPath);
+ name = cmSystemTools::LowerCase(name);
+ if (name == "cmakecache.txt"_s) {
+ cachePath = cmSystemTools::GetFilenamePath(fullPath);
+ } else if (name == "cmakelists.txt"_s) {
+ listPath = cmSystemTools::GetFilenamePath(fullPath);
+ }
+ } else {
+ // Specified file or directory does not exist. Try to set things
+ // up to produce a meaningful error message.
+ std::string fullPath = cmSystemTools::CollapseFullPath(arg);
+ std::string name = cmSystemTools::GetFilenameName(fullPath);
+ name = cmSystemTools::LowerCase(name);
+ if (name == "cmakecache.txt"_s || name == "cmakelists.txt"_s) {
+ argIsFile = true;
+ listPath = cmSystemTools::GetFilenamePath(fullPath);
+ } else {
+ listPath = fullPath;
+ }
+ }
+
+ // If there is a CMakeCache.txt file, use its settings.
+ if (!cachePath.empty()) {
+ if (this->LoadCache(cachePath)) {
+ cmProp existingValue =
+ this->State->GetCacheEntryValue("CMAKE_HOME_DIRECTORY");
+ if (existingValue) {
+ this->SetHomeOutputDirectory(cachePath);
+ this->SetHomeDirectory(*existingValue);
+ return;
+ }
+ }
+ }
+
+ // If there is a CMakeLists.txt file, use it as the source tree.
+ if (!listPath.empty()) {
+ this->SetHomeDirectory(listPath);
+
+ if (argIsFile) {
+ // Source CMakeLists.txt file given. It was probably dropped
+ // onto the executable in a GUI. Default to an in-source build.
+ this->SetHomeOutputDirectory(listPath);
+ } else {
+ // Source directory given on command line. Use current working
+ // directory as build tree if -B hasn't been given already
+ if (this->GetHomeOutputDirectory().empty()) {
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ this->SetHomeOutputDirectory(cwd);
+ }
+ }
+ return;
+ }
+
+ if (this->GetHomeDirectory().empty()) {
+ // We didn't find a CMakeLists.txt and it wasn't specified
+ // with -S. Assume it is the path to the source tree
+ std::string full = cmSystemTools::CollapseFullPath(arg);
+ this->SetHomeDirectory(full);
+ }
+ if (this->GetHomeOutputDirectory().empty()) {
+ // We didn't find a CMakeCache.txt and it wasn't specified
+ // with -B. Assume the current working directory as the build tree.
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ this->SetHomeOutputDirectory(cwd);
+ }
+}
+
+// at the end of this CMAKE_ROOT and CMAKE_COMMAND should be added to the
+// cache
+int cmake::AddCMakePaths()
+{
+ // Save the value in the cache
+ this->AddCacheEntry("CMAKE_COMMAND",
+ cmSystemTools::GetCMakeCommand().c_str(),
+ "Path to CMake executable.", cmStateEnums::INTERNAL);
+#ifndef CMAKE_BOOTSTRAP
+ this->AddCacheEntry(
+ "CMAKE_CTEST_COMMAND", cmSystemTools::GetCTestCommand().c_str(),
+ "Path to ctest program executable.", cmStateEnums::INTERNAL);
+ this->AddCacheEntry(
+ "CMAKE_CPACK_COMMAND", cmSystemTools::GetCPackCommand().c_str(),
+ "Path to cpack program executable.", cmStateEnums::INTERNAL);
+#endif
+ if (!cmSystemTools::FileExists(
+ (cmSystemTools::GetCMakeRoot() + "/Modules/CMake.cmake"))) {
+ // couldn't find modules
+ cmSystemTools::Error(
+ "Could not find CMAKE_ROOT !!!\n"
+ "CMake has most likely not been installed correctly.\n"
+ "Modules directory not found in\n" +
+ cmSystemTools::GetCMakeRoot());
+ return 0;
+ }
+ this->AddCacheEntry("CMAKE_ROOT", cmSystemTools::GetCMakeRoot().c_str(),
+ "Path to CMake installation.", cmStateEnums::INTERNAL);
+
+ return 1;
+}
+
+void cmake::AddDefaultExtraGenerators()
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ this->ExtraGenerators.push_back(cmExtraCodeBlocksGenerator::GetFactory());
+ this->ExtraGenerators.push_back(cmExtraCodeLiteGenerator::GetFactory());
+ this->ExtraGenerators.push_back(cmExtraEclipseCDT4Generator::GetFactory());
+ this->ExtraGenerators.push_back(cmExtraKateGenerator::GetFactory());
+ this->ExtraGenerators.push_back(cmExtraSublimeTextGenerator::GetFactory());
+#endif
+}
+
+void cmake::GetRegisteredGenerators(std::vector<GeneratorInfo>& generators,
+ bool includeNamesWithPlatform) const
+{
+ for (const auto& gen : this->Generators) {
+ std::vector<std::string> names = gen->GetGeneratorNames();
+
+ if (includeNamesWithPlatform) {
+ cm::append(names, gen->GetGeneratorNamesWithPlatform());
+ }
+
+ for (std::string const& name : names) {
+ GeneratorInfo info;
+ info.supportsToolset = gen->SupportsToolset();
+ info.supportsPlatform = gen->SupportsPlatform();
+ info.supportedPlatforms = gen->GetKnownPlatforms();
+ info.defaultPlatform = gen->GetDefaultPlatformName();
+ info.name = name;
+ info.baseName = name;
+ info.isAlias = false;
+ generators.push_back(std::move(info));
+ }
+ }
+
+ for (cmExternalMakefileProjectGeneratorFactory* eg : this->ExtraGenerators) {
+ const std::vector<std::string> genList =
+ eg->GetSupportedGlobalGenerators();
+ for (std::string const& gen : genList) {
+ GeneratorInfo info;
+ info.name = cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
+ gen, eg->GetName());
+ info.baseName = gen;
+ info.extraName = eg->GetName();
+ info.supportsPlatform = false;
+ info.supportsToolset = false;
+ info.isAlias = false;
+ generators.push_back(std::move(info));
+ }
+ for (std::string const& a : eg->Aliases) {
+ GeneratorInfo info;
+ info.name = a;
+ if (!genList.empty()) {
+ info.baseName = genList.at(0);
+ }
+ info.extraName = eg->GetName();
+ info.supportsPlatform = false;
+ info.supportsToolset = false;
+ info.isAlias = true;
+ generators.push_back(std::move(info));
+ }
+ }
+}
+
+static std::pair<std::unique_ptr<cmExternalMakefileProjectGenerator>,
+ std::string>
+createExtraGenerator(
+ const std::vector<cmExternalMakefileProjectGeneratorFactory*>& in,
+ const std::string& name)
+{
+ for (cmExternalMakefileProjectGeneratorFactory* i : in) {
+ const std::vector<std::string> generators =
+ i->GetSupportedGlobalGenerators();
+ if (i->GetName() == name) { // Match aliases
+ return { i->CreateExternalMakefileProjectGenerator(), generators.at(0) };
+ }
+ for (std::string const& g : generators) {
+ const std::string fullName =
+ cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
+ g, i->GetName());
+ if (fullName == name) {
+ return { i->CreateExternalMakefileProjectGenerator(), g };
+ }
+ }
+ }
+ return { nullptr, name };
+}
+
+std::unique_ptr<cmGlobalGenerator> cmake::CreateGlobalGenerator(
+ const std::string& gname, bool allowArch)
+{
+ std::pair<std::unique_ptr<cmExternalMakefileProjectGenerator>, std::string>
+ extra = createExtraGenerator(this->ExtraGenerators, gname);
+ std::unique_ptr<cmExternalMakefileProjectGenerator>& extraGenerator =
+ extra.first;
+ const std::string& name = extra.second;
+
+ std::unique_ptr<cmGlobalGenerator> generator;
+ for (const auto& g : this->Generators) {
+ generator = g->CreateGlobalGenerator(name, allowArch, this);
+ if (generator) {
+ break;
+ }
+ }
+
+ if (generator) {
+ generator->SetExternalMakefileProjectGenerator(std::move(extraGenerator));
+ }
+
+ return generator;
+}
+
+bool cmake::CreateAndSetGlobalGenerator(const std::string& name,
+ bool allowArch)
+{
+ auto gen = this->CreateGlobalGenerator(name, allowArch);
+ if (!gen) {
+ std::string kdevError;
+ std::string vsError;
+ if (name.find("KDevelop3", 0) != std::string::npos) {
+ kdevError = "\nThe KDevelop3 generator is not supported anymore.";
+ }
+ if (!allowArch && cmHasLiteralPrefix(name, "Visual Studio ") &&
+ name.length() >= cmStrLen("Visual Studio xx xxxx ")) {
+ vsError = "\nUsing platforms in Visual Studio generator names is not "
+ "supported in CMakePresets.json.";
+ }
+
+ cmSystemTools::Error(
+ cmStrCat("Could not create named generator ", name, kdevError, vsError));
+ this->PrintGeneratorList();
+ return false;
+ }
+
+ this->SetGlobalGenerator(std::move(gen));
+ return true;
+}
+
+#ifndef CMAKE_BOOTSTRAP
+void cmake::PrintPresetList(const cmCMakePresetsFile& file) const
+{
+ std::vector<GeneratorInfo> generators;
+ this->GetRegisteredGenerators(generators, false);
+ auto filter =
+ [&generators](const cmCMakePresetsFile::ConfigurePreset& preset) -> bool {
+ auto condition = [&preset](const GeneratorInfo& info) -> bool {
+ return info.name == preset.Generator;
+ };
+ auto it = std::find_if(generators.begin(), generators.end(), condition);
+ return it != generators.end();
+ };
+
+ file.PrintConfigurePresetList(filter);
+}
+#endif
+
+void cmake::SetHomeDirectory(const std::string& dir)
+{
+ this->State->SetSourceDirectory(dir);
+ if (this->CurrentSnapshot.IsValid()) {
+ this->CurrentSnapshot.SetDefinition("CMAKE_SOURCE_DIR", dir);
+ }
+}
+
+std::string const& cmake::GetHomeDirectory() const
+{
+ return this->State->GetSourceDirectory();
+}
+
+void cmake::SetHomeOutputDirectory(const std::string& dir)
+{
+ this->State->SetBinaryDirectory(dir);
+ if (this->CurrentSnapshot.IsValid()) {
+ this->CurrentSnapshot.SetDefinition("CMAKE_BINARY_DIR", dir);
+ }
+}
+
+std::string const& cmake::GetHomeOutputDirectory() const
+{
+ return this->State->GetBinaryDirectory();
+}
+
+std::string cmake::FindCacheFile(const std::string& binaryDir)
+{
+ std::string cachePath = binaryDir;
+ cmSystemTools::ConvertToUnixSlashes(cachePath);
+ std::string cacheFile = cmStrCat(cachePath, "/CMakeCache.txt");
+ if (!cmSystemTools::FileExists(cacheFile)) {
+ // search in parent directories for cache
+ std::string cmakeFiles = cmStrCat(cachePath, "/CMakeFiles");
+ if (cmSystemTools::FileExists(cmakeFiles)) {
+ std::string cachePathFound =
+ cmSystemTools::FileExistsInParentDirectories("CMakeCache.txt",
+ cachePath, "/");
+ if (!cachePathFound.empty()) {
+ cachePath = cmSystemTools::GetFilenamePath(cachePathFound);
+ }
+ }
+ }
+ return cachePath;
+}
+
+void cmake::SetGlobalGenerator(std::unique_ptr<cmGlobalGenerator> gg)
+{
+ if (!gg) {
+ cmSystemTools::Error("Error SetGlobalGenerator called with null");
+ return;
+ }
+ if (this->GlobalGenerator) {
+ // restore the original environment variables CXX and CC
+ // Restore CC
+ std::string env = "CC=";
+ if (!this->CCEnvironment.empty()) {
+ env += this->CCEnvironment;
+ }
+ cmSystemTools::PutEnv(env);
+ env = "CXX=";
+ if (!this->CXXEnvironment.empty()) {
+ env += this->CXXEnvironment;
+ }
+ cmSystemTools::PutEnv(env);
+ }
+
+ // set the new
+ this->GlobalGenerator = std::move(gg);
+
+ // set the global flag for unix style paths on cmSystemTools as soon as
+ // the generator is set. This allows gmake to be used on windows.
+ cmSystemTools::SetForceUnixPaths(this->GlobalGenerator->GetForceUnixPaths());
+
+ // Save the environment variables CXX and CC
+ if (!cmSystemTools::GetEnv("CXX", this->CXXEnvironment)) {
+ this->CXXEnvironment.clear();
+ }
+ if (!cmSystemTools::GetEnv("CC", this->CCEnvironment)) {
+ this->CCEnvironment.clear();
+ }
+}
+
+int cmake::DoPreConfigureChecks()
+{
+ // Make sure the Source directory contains a CMakeLists.txt file.
+ std::string srcList = cmStrCat(this->GetHomeDirectory(), "/CMakeLists.txt");
+ if (!cmSystemTools::FileExists(srcList)) {
+ std::ostringstream err;
+ if (cmSystemTools::FileIsDirectory(this->GetHomeDirectory())) {
+ err << "The source directory \"" << this->GetHomeDirectory()
+ << "\" does not appear to contain CMakeLists.txt.\n";
+ } else if (cmSystemTools::FileExists(this->GetHomeDirectory())) {
+ err << "The source directory \"" << this->GetHomeDirectory()
+ << "\" is a file, not a directory.\n";
+ } else {
+ err << "The source directory \"" << this->GetHomeDirectory()
+ << "\" does not exist.\n";
+ }
+ err << "Specify --help for usage, or press the help button on the CMake "
+ "GUI.";
+ cmSystemTools::Error(err.str());
+ return -2;
+ }
+
+ // do a sanity check on some values
+ if (this->State->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY")) {
+ std::string cacheStart =
+ cmStrCat(*this->State->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY"),
+ "/CMakeLists.txt");
+ std::string currentStart =
+ cmStrCat(this->GetHomeDirectory(), "/CMakeLists.txt");
+ if (!cmSystemTools::SameFile(cacheStart, currentStart)) {
+ std::string message =
+ cmStrCat("The source \"", currentStart,
+ "\" does not match the source \"", cacheStart,
+ "\" used to generate cache. Re-run cmake with a different "
+ "source directory.");
+ cmSystemTools::Error(message);
+ return -2;
+ }
+ } else {
+ return 0;
+ }
+ return 1;
+}
+struct SaveCacheEntry
+{
+ std::string key;
+ std::string value;
+ std::string help;
+ cmStateEnums::CacheEntryType type;
+};
+
+int cmake::HandleDeleteCacheVariables(const std::string& var)
+{
+ std::vector<std::string> argsSplit = cmExpandedList(var, true);
+ // erase the property to avoid infinite recursion
+ this->State->SetGlobalProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_", "");
+ if (this->State->GetIsInTryCompile()) {
+ return 0;
+ }
+ std::vector<SaveCacheEntry> saved;
+ std::ostringstream warning;
+ /* clang-format off */
+ warning
+ << "You have changed variables that require your cache to be deleted.\n"
+ << "Configure will be re-run and you may have to reset some variables.\n"
+ << "The following variables have changed:\n";
+ /* clang-format on */
+ for (auto i = argsSplit.begin(); i != argsSplit.end(); ++i) {
+ SaveCacheEntry save;
+ save.key = *i;
+ warning << *i << "= ";
+ i++;
+ if (i != argsSplit.end()) {
+ save.value = *i;
+ warning << *i << "\n";
+ } else {
+ warning << "\n";
+ i -= 1;
+ }
+ cmProp existingValue = this->State->GetCacheEntryValue(save.key);
+ if (existingValue) {
+ save.type = this->State->GetCacheEntryType(save.key);
+ if (cmProp help =
+ this->State->GetCacheEntryProperty(save.key, "HELPSTRING")) {
+ save.help = *help;
+ }
+ } else {
+ save.type = cmStateEnums::CacheEntryType::UNINITIALIZED;
+ }
+ saved.push_back(std::move(save));
+ }
+
+ // remove the cache
+ this->DeleteCache(this->GetHomeOutputDirectory());
+ // load the empty cache
+ this->LoadCache();
+ // restore the changed compilers
+ for (SaveCacheEntry const& i : saved) {
+ this->AddCacheEntry(i.key, i.value.c_str(), i.help.c_str(), i.type);
+ }
+ cmSystemTools::Message(warning.str());
+ // avoid reconfigure if there were errors
+ if (!cmSystemTools::GetErrorOccuredFlag()) {
+ // re-run configure
+ return this->Configure();
+ }
+ return 0;
+}
+
+int cmake::Configure()
+{
+ DiagLevel diagLevel;
+
+ if (this->DiagLevels.count("deprecated") == 1) {
+
+ diagLevel = this->DiagLevels["deprecated"];
+ if (diagLevel == DIAG_IGNORE) {
+ this->SetSuppressDeprecatedWarnings(true);
+ this->SetDeprecatedWarningsAsErrors(false);
+ } else if (diagLevel == DIAG_WARN) {
+ this->SetSuppressDeprecatedWarnings(false);
+ this->SetDeprecatedWarningsAsErrors(false);
+ } else if (diagLevel == DIAG_ERROR) {
+ this->SetSuppressDeprecatedWarnings(false);
+ this->SetDeprecatedWarningsAsErrors(true);
+ }
+ }
+
+ if (this->DiagLevels.count("dev") == 1) {
+ bool setDeprecatedVariables = false;
+
+ cmProp cachedWarnDeprecated =
+ this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED");
+ cmProp cachedErrorDeprecated =
+ this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED");
+
+ // don't overwrite deprecated warning setting from a previous invocation
+ if (!cachedWarnDeprecated && !cachedErrorDeprecated) {
+ setDeprecatedVariables = true;
+ }
+
+ diagLevel = this->DiagLevels["dev"];
+ if (diagLevel == DIAG_IGNORE) {
+ this->SetSuppressDevWarnings(true);
+ this->SetDevWarningsAsErrors(false);
+
+ if (setDeprecatedVariables) {
+ this->SetSuppressDeprecatedWarnings(true);
+ this->SetDeprecatedWarningsAsErrors(false);
+ }
+ } else if (diagLevel == DIAG_WARN) {
+ this->SetSuppressDevWarnings(false);
+ this->SetDevWarningsAsErrors(false);
+
+ if (setDeprecatedVariables) {
+ this->SetSuppressDeprecatedWarnings(false);
+ this->SetDeprecatedWarningsAsErrors(false);
+ }
+ } else if (diagLevel == DIAG_ERROR) {
+ this->SetSuppressDevWarnings(false);
+ this->SetDevWarningsAsErrors(true);
+
+ if (setDeprecatedVariables) {
+ this->SetSuppressDeprecatedWarnings(false);
+ this->SetDeprecatedWarningsAsErrors(true);
+ }
+ }
+ }
+
+ // Cache variables may have already been set by a previous invocation,
+ // so we cannot rely on command line options alone. Always ensure our
+ // messenger is in sync with the cache.
+ cmProp value = this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED");
+ this->Messenger->SetSuppressDeprecatedWarnings(value && cmIsOff(*value));
+
+ value = this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED");
+ this->Messenger->SetDeprecatedWarningsAsErrors(cmIsOn(value));
+
+ value = this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_WARNINGS");
+ this->Messenger->SetSuppressDevWarnings(cmIsOn(value));
+
+ value = this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_ERRORS");
+ this->Messenger->SetDevWarningsAsErrors(value && cmIsOff(*value));
+
+ int ret = this->ActualConfigure();
+ cmProp delCacheVars =
+ this->State->GetGlobalProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_");
+ if (delCacheVars && !delCacheVars->empty()) {
+ return this->HandleDeleteCacheVariables(*delCacheVars);
+ }
+ return ret;
+}
+
+int cmake::ActualConfigure()
+{
+ // Construct right now our path conversion table before it's too late:
+ this->UpdateConversionPathTable();
+ this->CleanupCommandsAndMacros();
+
+ int res = this->DoPreConfigureChecks();
+ if (res < 0) {
+ return -2;
+ }
+ if (!res) {
+ this->AddCacheEntry(
+ "CMAKE_HOME_DIRECTORY", this->GetHomeDirectory().c_str(),
+ "Source directory with the top level CMakeLists.txt file for this "
+ "project",
+ cmStateEnums::INTERNAL);
+ }
+
+ // no generator specified on the command line
+ if (!this->GlobalGenerator) {
+ cmProp genName = this->State->GetInitializedCacheValue("CMAKE_GENERATOR");
+ cmProp extraGenName =
+ this->State->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
+ if (genName) {
+ std::string fullName =
+ cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
+ *genName, extraGenName ? *extraGenName : "");
+ this->GlobalGenerator = this->CreateGlobalGenerator(fullName);
+ }
+ if (this->GlobalGenerator) {
+ // set the global flag for unix style paths on cmSystemTools as
+ // soon as the generator is set. This allows gmake to be used
+ // on windows.
+ cmSystemTools::SetForceUnixPaths(
+ this->GlobalGenerator->GetForceUnixPaths());
+ } else {
+ this->CreateDefaultGlobalGenerator();
+ }
+ if (!this->GlobalGenerator) {
+ cmSystemTools::Error("Could not create generator");
+ return -1;
+ }
+ }
+
+ cmProp genName = this->State->GetInitializedCacheValue("CMAKE_GENERATOR");
+ if (genName) {
+ if (!this->GlobalGenerator->MatchesGeneratorName(*genName)) {
+ std::string message =
+ cmStrCat("Error: generator : ", this->GlobalGenerator->GetName(),
+ "\nDoes not match the generator used previously: ", *genName,
+ "\nEither remove the CMakeCache.txt file and CMakeFiles "
+ "directory or choose a different binary directory.");
+ cmSystemTools::Error(message);
+ return -2;
+ }
+ }
+ if (!this->State->GetInitializedCacheValue("CMAKE_GENERATOR")) {
+ this->AddCacheEntry("CMAKE_GENERATOR",
+ this->GlobalGenerator->GetName().c_str(),
+ "Name of generator.", cmStateEnums::INTERNAL);
+ this->AddCacheEntry("CMAKE_EXTRA_GENERATOR",
+ this->GlobalGenerator->GetExtraGeneratorName().c_str(),
+ "Name of external makefile project generator.",
+ cmStateEnums::INTERNAL);
+ }
+
+ if (cmProp instance =
+ this->State->GetInitializedCacheValue("CMAKE_GENERATOR_INSTANCE")) {
+ if (this->GeneratorInstanceSet && this->GeneratorInstance != *instance) {
+ std::string message =
+ cmStrCat("Error: generator instance: ", this->GeneratorInstance,
+ "\nDoes not match the instance used previously: ", *instance,
+ "\nEither remove the CMakeCache.txt file and CMakeFiles "
+ "directory or choose a different binary directory.");
+ cmSystemTools::Error(message);
+ return -2;
+ }
+ } else {
+ this->AddCacheEntry(
+ "CMAKE_GENERATOR_INSTANCE", this->GeneratorInstance.c_str(),
+ "Generator instance identifier.", cmStateEnums::INTERNAL);
+ }
+
+ if (cmProp platformName =
+ this->State->GetInitializedCacheValue("CMAKE_GENERATOR_PLATFORM")) {
+ if (this->GeneratorPlatformSet &&
+ this->GeneratorPlatform != *platformName) {
+ std::string message = cmStrCat(
+ "Error: generator platform: ", this->GeneratorPlatform,
+ "\nDoes not match the platform used previously: ", *platformName,
+ "\nEither remove the CMakeCache.txt file and CMakeFiles "
+ "directory or choose a different binary directory.");
+ cmSystemTools::Error(message);
+ return -2;
+ }
+ } else {
+ this->AddCacheEntry("CMAKE_GENERATOR_PLATFORM",
+ this->GeneratorPlatform.c_str(),
+ "Name of generator platform.", cmStateEnums::INTERNAL);
+ }
+
+ if (cmProp tsName =
+ this->State->GetInitializedCacheValue("CMAKE_GENERATOR_TOOLSET")) {
+ if (this->GeneratorToolsetSet && this->GeneratorToolset != *tsName) {
+ std::string message =
+ cmStrCat("Error: generator toolset: ", this->GeneratorToolset,
+ "\nDoes not match the toolset used previously: ", *tsName,
+ "\nEither remove the CMakeCache.txt file and CMakeFiles "
+ "directory or choose a different binary directory.");
+ cmSystemTools::Error(message);
+ return -2;
+ }
+ } else {
+ this->AddCacheEntry("CMAKE_GENERATOR_TOOLSET",
+ this->GeneratorToolset.c_str(),
+ "Name of generator toolset.", cmStateEnums::INTERNAL);
+ }
+
+ // reset any system configuration information, except for when we are
+ // InTryCompile. With TryCompile the system info is taken from the parent's
+ // info to save time
+ if (!this->State->GetIsInTryCompile()) {
+ this->GlobalGenerator->ClearEnabledLanguages();
+
+ this->TruncateOutputLog("CMakeOutput.log");
+ this->TruncateOutputLog("CMakeError.log");
+ }
+
+#if !defined(CMAKE_BOOTSTRAP)
+ this->FileAPI = cm::make_unique<cmFileAPI>(this);
+ this->FileAPI->ReadQueries();
+#endif
+
+ // actually do the configure
+ this->GlobalGenerator->Configure();
+ // Before saving the cache
+ // if the project did not define one of the entries below, add them now
+ // so users can edit the values in the cache:
+
+ // We used to always present LIBRARY_OUTPUT_PATH and
+ // EXECUTABLE_OUTPUT_PATH. They are now documented as old-style and
+ // should no longer be used. Therefore we present them only if the
+ // project requires compatibility with CMake 2.4. We detect this
+ // here by looking for the old CMAKE_BACKWARDS_COMPATIBILITY
+ // variable created when CMP0001 is not set to NEW.
+ if (this->State->GetInitializedCacheValue("CMAKE_BACKWARDS_COMPATIBILITY")) {
+ if (!this->State->GetInitializedCacheValue("LIBRARY_OUTPUT_PATH")) {
+ this->AddCacheEntry(
+ "LIBRARY_OUTPUT_PATH", "",
+ "Single output directory for building all libraries.",
+ cmStateEnums::PATH);
+ }
+ if (!this->State->GetInitializedCacheValue("EXECUTABLE_OUTPUT_PATH")) {
+ this->AddCacheEntry(
+ "EXECUTABLE_OUTPUT_PATH", "",
+ "Single output directory for building all executables.",
+ cmStateEnums::PATH);
+ }
+ }
+
+ const auto& mf = this->GlobalGenerator->GetMakefiles()[0];
+ if (mf->IsOn("CTEST_USE_LAUNCHERS") &&
+ !this->State->GetGlobalProperty("RULE_LAUNCH_COMPILE")) {
+ cmSystemTools::Error(
+ "CTEST_USE_LAUNCHERS is enabled, but the "
+ "RULE_LAUNCH_COMPILE global property is not defined.\n"
+ "Did you forget to include(CTest) in the toplevel "
+ "CMakeLists.txt ?");
+ }
+
+ this->State->SaveVerificationScript(this->GetHomeOutputDirectory());
+ this->SaveCache(this->GetHomeOutputDirectory());
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return -1;
+ }
+ return 0;
+}
+
+std::unique_ptr<cmGlobalGenerator> cmake::EvaluateDefaultGlobalGenerator()
+{
+ if (!this->EnvironmentGenerator.empty()) {
+ auto gen = this->CreateGlobalGenerator(this->EnvironmentGenerator);
+ if (!gen) {
+ cmSystemTools::Error("CMAKE_GENERATOR was set but the specified "
+ "generator doesn't exist. Using CMake default.");
+ } else {
+ return gen;
+ }
+ }
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
+ std::string found;
+ // Try to find the newest VS installed on the computer and
+ // use that as a default if -G is not specified
+ const std::string vsregBase = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\";
+ static const char* const vsVariants[] = {
+ /* clang-format needs this comment to break after the opening brace */
+ "VisualStudio\\", "VCExpress\\", "WDExpress\\"
+ };
+ struct VSVersionedGenerator
+ {
+ const char* MSVersion;
+ const char* GeneratorName;
+ };
+ static VSVersionedGenerator const vsGenerators[] = {
+ { "14.0", "Visual Studio 14 2015" }, //
+ { "12.0", "Visual Studio 12 2013" }, //
+ { "11.0", "Visual Studio 11 2012" }, //
+ { "10.0", "Visual Studio 10 2010" }, //
+ { "9.0", "Visual Studio 9 2008" }
+ };
+ static const char* const vsEntries[] = {
+ "\\Setup\\VC;ProductDir", //
+ ";InstallDir" //
+ };
+ if (cmVSSetupAPIHelper(16).IsVSInstalled()) {
+ found = "Visual Studio 16 2019";
+ } else if (cmVSSetupAPIHelper(15).IsVSInstalled()) {
+ found = "Visual Studio 15 2017";
+ } else {
+ for (VSVersionedGenerator const* g = cm::cbegin(vsGenerators);
+ found.empty() && g != cm::cend(vsGenerators); ++g) {
+ for (const char* const* v = cm::cbegin(vsVariants);
+ found.empty() && v != cm::cend(vsVariants); ++v) {
+ for (const char* const* e = cm::cbegin(vsEntries);
+ found.empty() && e != cm::cend(vsEntries); ++e) {
+ std::string const reg = vsregBase + *v + g->MSVersion + *e;
+ std::string dir;
+ if (cmSystemTools::ReadRegistryValue(reg, dir,
+ cmSystemTools::KeyWOW64_32) &&
+ cmSystemTools::PathExists(dir)) {
+ found = g->GeneratorName;
+ }
+ }
+ }
+ }
+ }
+ auto gen = this->CreateGlobalGenerator(found);
+ if (!gen) {
+ gen = cm::make_unique<cmGlobalNMakeMakefileGenerator>(this);
+ }
+ return std::unique_ptr<cmGlobalGenerator>(std::move(gen));
+#elif defined(CMAKE_BOOTSTRAP_NINJA)
+ return std::unique_ptr<cmGlobalGenerator>(
+ cm::make_unique<cmGlobalNinjaGenerator>(this));
+#else
+ return std::unique_ptr<cmGlobalGenerator>(
+ cm::make_unique<cmGlobalUnixMakefileGenerator3>(this));
+#endif
+}
+
+void cmake::CreateDefaultGlobalGenerator()
+{
+ auto gen = this->EvaluateDefaultGlobalGenerator();
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
+ // This print could be unified for all platforms
+ std::cout << "-- Building for: " << gen->GetName() << "\n";
+#endif
+ this->SetGlobalGenerator(std::move(gen));
+}
+
+void cmake::PreLoadCMakeFiles()
+{
+ std::vector<std::string> args;
+ std::string pre_load = this->GetHomeDirectory();
+ if (!pre_load.empty()) {
+ pre_load += "/PreLoad.cmake";
+ if (cmSystemTools::FileExists(pre_load)) {
+ this->ReadListFile(args, pre_load);
+ }
+ }
+ pre_load = this->GetHomeOutputDirectory();
+ if (!pre_load.empty()) {
+ pre_load += "/PreLoad.cmake";
+ if (cmSystemTools::FileExists(pre_load)) {
+ this->ReadListFile(args, pre_load);
+ }
+ }
+}
+
+// handle a command line invocation
+int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
+{
+ // Process the arguments
+ this->SetArgs(args);
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return -1;
+ }
+ if (this->GetWorkingMode() == HELP_MODE) {
+ return 0;
+ }
+
+ // Log the trace format version to the desired output
+ if (this->GetTrace()) {
+ this->PrintTraceFormatVersion();
+ }
+
+ // If we are given a stamp list file check if it is really out of date.
+ if (!this->CheckStampList.empty() &&
+ cmakeCheckStampList(this->CheckStampList)) {
+ return 0;
+ }
+
+ // If we are given a stamp file check if it is really out of date.
+ if (!this->CheckStampFile.empty() &&
+ cmakeCheckStampFile(this->CheckStampFile)) {
+ return 0;
+ }
+
+ if (this->GetWorkingMode() == NORMAL_MODE) {
+ // load the cache
+ if (this->LoadCache() < 0) {
+ cmSystemTools::Error("Error executing cmake::LoadCache(). Aborting.\n");
+ return -1;
+ }
+ } else {
+ this->AddCMakePaths();
+ }
+
+#ifndef CMAKE_BOOTSTRAP
+ this->ProcessPresetVariables();
+ this->ProcessPresetEnvironment();
+#endif
+ // Add any cache args
+ if (!this->SetCacheArgs(args)) {
+ cmSystemTools::Error("Run 'cmake --help' for all supported options.");
+ return -1;
+ }
+#ifndef CMAKE_BOOTSTRAP
+ this->PrintPresetVariables();
+ this->PrintPresetEnvironment();
+#endif
+
+ // In script mode we terminate after running the script.
+ if (this->GetWorkingMode() != NORMAL_MODE) {
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return -1;
+ }
+ return 0;
+ }
+
+ // If MAKEFLAGS are given in the environment, remove the environment
+ // variable. This will prevent try-compile from succeeding when it
+ // should fail (if "-i" is an option). We cannot simply test
+ // whether "-i" is given and remove it because some make programs
+ // encode the MAKEFLAGS variable in a strange way.
+ if (cmSystemTools::HasEnv("MAKEFLAGS")) {
+ cmSystemTools::PutEnv("MAKEFLAGS=");
+ }
+
+ this->PreLoadCMakeFiles();
+
+ if (noconfigure) {
+ return 0;
+ }
+
+ // now run the global generate
+ // Check the state of the build system to see if we need to regenerate.
+ if (!this->CheckBuildSystem()) {
+ return 0;
+ }
+
+ int ret = this->Configure();
+ if (ret) {
+#if defined(CMAKE_HAVE_VS_GENERATORS)
+ if (!this->VSSolutionFile.empty() && this->GlobalGenerator) {
+ // CMake is running to regenerate a Visual Studio build tree
+ // during a build from the VS IDE. The build files cannot be
+ // regenerated, so we should stop the build.
+ cmSystemTools::Message("CMake Configure step failed. "
+ "Build files cannot be regenerated correctly. "
+ "Attempting to stop IDE build.");
+ cmGlobalVisualStudioGenerator& gg =
+ cm::static_reference_cast<cmGlobalVisualStudioGenerator>(
+ this->GlobalGenerator);
+ gg.CallVisualStudioMacro(cmGlobalVisualStudioGenerator::MacroStop,
+ this->VSSolutionFile);
+ }
+#endif
+ return ret;
+ }
+ ret = this->Generate();
+ if (ret) {
+ cmSystemTools::Message("CMake Generate step failed. "
+ "Build files cannot be regenerated correctly.");
+ return ret;
+ }
+ std::string message = cmStrCat("Build files have been written to: ",
+ this->GetHomeOutputDirectory());
+ this->UpdateProgress(message, -1);
+ return ret;
+}
+
+int cmake::Generate()
+{
+ if (!this->GlobalGenerator) {
+ return -1;
+ }
+ if (!this->GlobalGenerator->Compute()) {
+ return -1;
+ }
+ this->GlobalGenerator->Generate();
+ if (!this->GraphVizFile.empty()) {
+ std::cout << "Generate graphviz: " << this->GraphVizFile << std::endl;
+ this->GenerateGraphViz(this->GraphVizFile);
+ }
+ if (this->WarnUnusedCli) {
+ this->RunCheckForUnusedVariables();
+ }
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return -1;
+ }
+ // Save the cache again after a successful Generate so that any internal
+ // variables created during Generate are saved. (Specifically target GUIDs
+ // for the Visual Studio and Xcode generators.)
+ this->SaveCache(this->GetHomeOutputDirectory());
+
+#if !defined(CMAKE_BOOTSTRAP)
+ this->FileAPI->WriteReplies();
+#endif
+
+ return 0;
+}
+
+void cmake::AddCacheEntry(const std::string& key, const char* value,
+ const char* helpString, int type)
+{
+ this->State->AddCacheEntry(key, value, helpString,
+ cmStateEnums::CacheEntryType(type));
+ this->UnwatchUnusedCli(key);
+
+ if (key == "CMAKE_WARN_DEPRECATED"_s) {
+ this->Messenger->SetSuppressDeprecatedWarnings(value && cmIsOff(value));
+ } else if (key == "CMAKE_ERROR_DEPRECATED"_s) {
+ this->Messenger->SetDeprecatedWarningsAsErrors(cmIsOn(value));
+ } else if (key == "CMAKE_SUPPRESS_DEVELOPER_WARNINGS"_s) {
+ this->Messenger->SetSuppressDevWarnings(cmIsOn(value));
+ } else if (key == "CMAKE_SUPPRESS_DEVELOPER_ERRORS"_s) {
+ this->Messenger->SetDevWarningsAsErrors(value && cmIsOff(value));
+ }
+}
+
+bool cmake::DoWriteGlobVerifyTarget() const
+{
+ return this->State->DoWriteGlobVerifyTarget();
+}
+
+std::string const& cmake::GetGlobVerifyScript() const
+{
+ return this->State->GetGlobVerifyScript();
+}
+
+std::string const& cmake::GetGlobVerifyStamp() const
+{
+ return this->State->GetGlobVerifyStamp();
+}
+
+void cmake::AddGlobCacheEntry(bool recurse, bool listDirectories,
+ bool followSymlinks, const std::string& relative,
+ const std::string& expression,
+ const std::vector<std::string>& files,
+ const std::string& variable,
+ cmListFileBacktrace const& backtrace)
+{
+ this->State->AddGlobCacheEntry(recurse, listDirectories, followSymlinks,
+ relative, expression, files, variable,
+ backtrace);
+}
+
+std::vector<std::string> cmake::GetAllExtensions() const
+{
+ std::vector<std::string> allExt = this->CLikeSourceFileExtensions.ordered;
+ allExt.insert(allExt.end(), this->HeaderFileExtensions.ordered.begin(),
+ this->HeaderFileExtensions.ordered.end());
+ // cuda extensions are also in SourceFileExtensions so we ignore it here
+ allExt.insert(allExt.end(), this->FortranFileExtensions.ordered.begin(),
+ this->FortranFileExtensions.ordered.end());
+ allExt.insert(allExt.end(), this->ISPCFileExtensions.ordered.begin(),
+ this->ISPCFileExtensions.ordered.end());
+ return allExt;
+}
+
+std::string cmake::StripExtension(const std::string& file) const
+{
+ auto dotpos = file.rfind('.');
+ if (dotpos != std::string::npos) {
+#if defined(_WIN32) || defined(__APPLE__)
+ auto ext = cmSystemTools::LowerCase(file.substr(dotpos + 1));
+#else
+ auto ext = cm::string_view(file).substr(dotpos + 1);
+#endif
+ if (this->IsAKnownExtension(ext)) {
+ return file.substr(0, dotpos);
+ }
+ }
+ return file;
+}
+
+cmProp cmake::GetCacheDefinition(const std::string& name) const
+{
+ return this->State->GetInitializedCacheValue(name);
+}
+
+void cmake::AddScriptingCommands() const
+{
+ GetScriptingCommands(this->GetState());
+}
+
+void cmake::AddProjectCommands() const
+{
+ GetProjectCommands(this->GetState());
+}
+
+void cmake::AddDefaultGenerators()
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# if !defined(CMAKE_BOOT_MINGW)
+ this->Generators.push_back(
+ cmGlobalVisualStudioVersionedGenerator::NewFactory16());
+ this->Generators.push_back(
+ cmGlobalVisualStudioVersionedGenerator::NewFactory15());
+ this->Generators.push_back(cmGlobalVisualStudio14Generator::NewFactory());
+ this->Generators.push_back(cmGlobalVisualStudio12Generator::NewFactory());
+ this->Generators.push_back(cmGlobalVisualStudio11Generator::NewFactory());
+ this->Generators.push_back(cmGlobalVisualStudio10Generator::NewFactory());
+ this->Generators.push_back(cmGlobalVisualStudio9Generator::NewFactory());
+ this->Generators.push_back(cmGlobalBorlandMakefileGenerator::NewFactory());
+ this->Generators.push_back(cmGlobalNMakeMakefileGenerator::NewFactory());
+ this->Generators.push_back(cmGlobalJOMMakefileGenerator::NewFactory());
+# endif
+ this->Generators.push_back(cmGlobalMSYSMakefileGenerator::NewFactory());
+ this->Generators.push_back(cmGlobalMinGWMakefileGenerator::NewFactory());
+#endif
+#if !defined(CMAKE_BOOTSTRAP)
+# if defined(__linux__) || defined(_WIN32)
+ this->Generators.push_back(cmGlobalGhsMultiGenerator::NewFactory());
+# endif
+ this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory());
+ this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory());
+ this->Generators.push_back(cmGlobalNinjaMultiGenerator::NewFactory());
+#elif defined(CMAKE_BOOTSTRAP_NINJA)
+ this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory());
+#elif defined(CMAKE_BOOTSTRAP_MAKEFILES)
+ this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory());
+#endif
+#if defined(CMAKE_USE_WMAKE)
+ this->Generators.push_back(cmGlobalWatcomWMakeGenerator::NewFactory());
+#endif
+#ifdef CMAKE_USE_XCODE
+ this->Generators.push_back(cmGlobalXCodeGenerator::NewFactory());
+#endif
+}
+
+bool cmake::ParseCacheEntry(const std::string& entry, std::string& var,
+ std::string& value,
+ cmStateEnums::CacheEntryType& type)
+{
+ return cmState::ParseCacheEntry(entry, var, value, type);
+}
+
+int cmake::LoadCache()
+{
+ // could we not read the cache
+ if (!this->LoadCache(this->GetHomeOutputDirectory())) {
+ // if it does exist, but isn't readable then warn the user
+ std::string cacheFile =
+ cmStrCat(this->GetHomeOutputDirectory(), "/CMakeCache.txt");
+ if (cmSystemTools::FileExists(cacheFile)) {
+ cmSystemTools::Error(
+ "There is a CMakeCache.txt file for the current binary tree but "
+ "cmake does not have permission to read it. Please check the "
+ "permissions of the directory you are trying to run CMake on.");
+ return -1;
+ }
+ }
+
+ // setup CMAKE_ROOT and CMAKE_COMMAND
+ if (!this->AddCMakePaths()) {
+ return -3;
+ }
+ return 0;
+}
+
+bool cmake::LoadCache(const std::string& path)
+{
+ std::set<std::string> emptySet;
+ return this->LoadCache(path, true, emptySet, emptySet);
+}
+
+bool cmake::LoadCache(const std::string& path, bool internal,
+ std::set<std::string>& excludes,
+ std::set<std::string>& includes)
+{
+ bool result = this->State->LoadCache(path, internal, excludes, includes);
+ static const auto entries = { "CMAKE_CACHE_MAJOR_VERSION",
+ "CMAKE_CACHE_MINOR_VERSION" };
+ for (auto const& entry : entries) {
+ this->UnwatchUnusedCli(entry);
+ }
+ return result;
+}
+
+bool cmake::SaveCache(const std::string& path)
+{
+ bool result = this->State->SaveCache(path, this->GetMessenger());
+ static const auto entries = { "CMAKE_CACHE_MAJOR_VERSION",
+ "CMAKE_CACHE_MINOR_VERSION",
+ "CMAKE_CACHE_PATCH_VERSION",
+ "CMAKE_CACHEFILE_DIR" };
+ for (auto const& entry : entries) {
+ this->UnwatchUnusedCli(entry);
+ }
+ return result;
+}
+
+bool cmake::DeleteCache(const std::string& path)
+{
+ return this->State->DeleteCache(path);
+}
+
+void cmake::SetProgressCallback(ProgressCallbackType f)
+{
+ this->ProgressCallback = std::move(f);
+}
+
+void cmake::UpdateProgress(const std::string& msg, float prog)
+{
+ if (this->ProgressCallback && !this->State->GetIsInTryCompile()) {
+ this->ProgressCallback(msg, prog);
+ }
+}
+
+bool cmake::GetIsInTryCompile() const
+{
+ return this->State->GetIsInTryCompile();
+}
+
+void cmake::SetIsInTryCompile(bool b)
+{
+ this->State->SetIsInTryCompile(b);
+}
+
+void cmake::AppendGlobalGeneratorsDocumentation(
+ std::vector<cmDocumentationEntry>& v)
+{
+ const auto defaultGenerator = this->EvaluateDefaultGlobalGenerator();
+ const std::string defaultName = defaultGenerator->GetName();
+ bool foundDefaultOne = false;
+
+ for (const auto& g : this->Generators) {
+ cmDocumentationEntry e;
+ g->GetDocumentation(e);
+ if (!foundDefaultOne && cmHasPrefix(e.Name, defaultName)) {
+ e.CustomNamePrefix = '*';
+ foundDefaultOne = true;
+ }
+ v.push_back(std::move(e));
+ }
+}
+
+void cmake::AppendExtraGeneratorsDocumentation(
+ std::vector<cmDocumentationEntry>& v)
+{
+ for (cmExternalMakefileProjectGeneratorFactory* eg : this->ExtraGenerators) {
+ const std::string doc = eg->GetDocumentation();
+ const std::string name = eg->GetName();
+
+ // Aliases:
+ for (std::string const& a : eg->Aliases) {
+ cmDocumentationEntry e;
+ e.Name = a;
+ e.Brief = doc;
+ v.push_back(std::move(e));
+ }
+
+ // Full names:
+ const std::vector<std::string> generators =
+ eg->GetSupportedGlobalGenerators();
+ for (std::string const& g : generators) {
+ cmDocumentationEntry e;
+ e.Name =
+ cmExternalMakefileProjectGenerator::CreateFullGeneratorName(g, name);
+ e.Brief = doc;
+ v.push_back(std::move(e));
+ }
+ }
+}
+
+std::vector<cmDocumentationEntry> cmake::GetGeneratorsDocumentation()
+{
+ std::vector<cmDocumentationEntry> v;
+ this->AppendGlobalGeneratorsDocumentation(v);
+ this->AppendExtraGeneratorsDocumentation(v);
+ return v;
+}
+
+void cmake::PrintGeneratorList()
+{
+#ifndef CMAKE_BOOTSTRAP
+ cmDocumentation doc;
+ auto generators = this->GetGeneratorsDocumentation();
+ doc.AppendSection("Generators", generators);
+ std::cerr << "\n";
+ doc.PrintDocumentation(cmDocumentation::ListGenerators, std::cerr);
+#endif
+}
+
+void cmake::UpdateConversionPathTable()
+{
+ // Update the path conversion table with any specified file:
+ cmProp tablepath =
+ this->State->GetInitializedCacheValue("CMAKE_PATH_TRANSLATION_FILE");
+
+ if (tablepath) {
+ cmsys::ifstream table(tablepath->c_str());
+ if (!table) {
+ cmSystemTools::Error("CMAKE_PATH_TRANSLATION_FILE set to " + *tablepath +
+ ". CMake can not open file.");
+ cmSystemTools::ReportLastSystemError("CMake can not open file.");
+ } else {
+ std::string a;
+ std::string b;
+ while (!table.eof()) {
+ // two entries per line
+ table >> a;
+ table >> b;
+ cmSystemTools::AddTranslationPath(a, b);
+ }
+ }
+ }
+}
+
+int cmake::CheckBuildSystem()
+{
+ // We do not need to rerun CMake. Check dependency integrity.
+ const bool verbose = isCMakeVerbose();
+
+ // This method will check the integrity of the build system if the
+ // option was given on the command line. It reads the given file to
+ // determine whether CMake should rerun.
+
+ // If no file is provided for the check, we have to rerun.
+ if (this->CheckBuildSystemArgument.empty()) {
+ if (verbose) {
+ cmSystemTools::Stdout("Re-run cmake no build system arguments\n");
+ }
+ return 1;
+ }
+
+ // If the file provided does not exist, we have to rerun.
+ if (!cmSystemTools::FileExists(this->CheckBuildSystemArgument)) {
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Re-run cmake missing file: " << this->CheckBuildSystemArgument
+ << "\n";
+ cmSystemTools::Stdout(msg.str());
+ }
+ return 1;
+ }
+
+ // Read the rerun check file and use it to decide whether to do the
+ // global generate.
+ // Actually, all we need is the `set` command.
+ cmake cm(RoleScript, cmState::Unknown);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator gg(&cm);
+ cmMakefile mf(&gg, cm.GetCurrentSnapshot());
+ if (!mf.ReadListFile(this->CheckBuildSystemArgument) ||
+ cmSystemTools::GetErrorOccuredFlag()) {
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Re-run cmake error reading : " << this->CheckBuildSystemArgument
+ << "\n";
+ cmSystemTools::Stdout(msg.str());
+ }
+ // There was an error reading the file. Just rerun.
+ return 1;
+ }
+
+ if (this->ClearBuildSystem) {
+ // Get the generator used for this build system.
+ std::string genName = mf.GetSafeDefinition("CMAKE_DEPENDS_GENERATOR");
+ if (!cmNonempty(genName)) {
+ genName = "Unix Makefiles";
+ }
+
+ // Create the generator and use it to clear the dependencies.
+ std::unique_ptr<cmGlobalGenerator> ggd =
+ this->CreateGlobalGenerator(genName);
+ if (ggd) {
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmMakefile mfd(ggd.get(), cm.GetCurrentSnapshot());
+ auto lgd = ggd->CreateLocalGenerator(&mfd);
+ lgd->ClearDependencies(&mfd, verbose);
+ }
+ }
+
+ // If any byproduct of makefile generation is missing we must re-run.
+ std::vector<std::string> products;
+ mf.GetDefExpandList("CMAKE_MAKEFILE_PRODUCTS", products);
+ for (std::string const& p : products) {
+ if (!(cmSystemTools::FileExists(p) || cmSystemTools::FileIsSymlink(p))) {
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Re-run cmake, missing byproduct: " << p << "\n";
+ cmSystemTools::Stdout(msg.str());
+ }
+ return 1;
+ }
+ }
+
+ // Get the set of dependencies and outputs.
+ std::vector<std::string> depends;
+ std::vector<std::string> outputs;
+ if (mf.GetDefExpandList("CMAKE_MAKEFILE_DEPENDS", depends)) {
+ mf.GetDefExpandList("CMAKE_MAKEFILE_OUTPUTS", outputs);
+ }
+ if (depends.empty() || outputs.empty()) {
+ // Not enough information was provided to do the test. Just rerun.
+ if (verbose) {
+ cmSystemTools::Stdout("Re-run cmake no CMAKE_MAKEFILE_DEPENDS "
+ "or CMAKE_MAKEFILE_OUTPUTS :\n");
+ }
+ return 1;
+ }
+
+ // Find the newest dependency.
+ auto dep = depends.begin();
+ std::string dep_newest = *dep++;
+ for (; dep != depends.end(); ++dep) {
+ int result = 0;
+ if (this->FileTimeCache->Compare(dep_newest, *dep, &result)) {
+ if (result < 0) {
+ dep_newest = *dep;
+ }
+ } else {
+ if (verbose) {
+ cmSystemTools::Stdout(
+ "Re-run cmake: build system dependency is missing\n");
+ }
+ return 1;
+ }
+ }
+
+ // Find the oldest output.
+ auto out = outputs.begin();
+ std::string out_oldest = *out++;
+ for (; out != outputs.end(); ++out) {
+ int result = 0;
+ if (this->FileTimeCache->Compare(out_oldest, *out, &result)) {
+ if (result > 0) {
+ out_oldest = *out;
+ }
+ } else {
+ if (verbose) {
+ cmSystemTools::Stdout(
+ "Re-run cmake: build system output is missing\n");
+ }
+ return 1;
+ }
+ }
+
+ // If any output is older than any dependency then rerun.
+ {
+ int result = 0;
+ if (!this->FileTimeCache->Compare(out_oldest, dep_newest, &result) ||
+ result < 0) {
+ if (verbose) {
+ std::ostringstream msg;
+ msg << "Re-run cmake file: " << out_oldest
+ << " older than: " << dep_newest << "\n";
+ cmSystemTools::Stdout(msg.str());
+ }
+ return 1;
+ }
+ }
+
+ // No need to rerun.
+ return 0;
+}
+
+void cmake::TruncateOutputLog(const char* fname)
+{
+ std::string fullPath = cmStrCat(this->GetHomeOutputDirectory(), '/', fname);
+ struct stat st;
+ if (::stat(fullPath.c_str(), &st)) {
+ return;
+ }
+ if (!this->State->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR")) {
+ cmSystemTools::RemoveFile(fullPath);
+ return;
+ }
+ off_t fsize = st.st_size;
+ const off_t maxFileSize = 50 * 1024;
+ if (fsize < maxFileSize) {
+ // TODO: truncate file
+ return;
+ }
+}
+
+void cmake::MarkCliAsUsed(const std::string& variable)
+{
+ this->UsedCliVariables[variable] = true;
+}
+
+void cmake::GenerateGraphViz(const std::string& fileName) const
+{
+#ifndef CMAKE_BOOTSTRAP
+ cmGraphVizWriter gvWriter(fileName, this->GetGlobalGenerator());
+
+ std::string settingsFile =
+ cmStrCat(this->GetHomeOutputDirectory(), "/CMakeGraphVizOptions.cmake");
+ std::string fallbackSettingsFile =
+ cmStrCat(this->GetHomeDirectory(), "/CMakeGraphVizOptions.cmake");
+
+ gvWriter.ReadSettings(settingsFile, fallbackSettingsFile);
+
+ gvWriter.Write();
+
+#endif
+}
+
+void cmake::SetProperty(const std::string& prop, const char* value)
+{
+ this->State->SetGlobalProperty(prop, value);
+}
+
+void cmake::AppendProperty(const std::string& prop, const std::string& value,
+ bool asString)
+{
+ this->State->AppendGlobalProperty(prop, value, asString);
+}
+
+cmProp cmake::GetProperty(const std::string& prop)
+{
+ return this->State->GetGlobalProperty(prop);
+}
+
+bool cmake::GetPropertyAsBool(const std::string& prop)
+{
+ return this->State->GetGlobalPropertyAsBool(prop);
+}
+
+cmInstalledFile* cmake::GetOrCreateInstalledFile(cmMakefile* mf,
+ const std::string& name)
+{
+ auto i = this->InstalledFiles.find(name);
+
+ if (i != this->InstalledFiles.end()) {
+ cmInstalledFile& file = i->second;
+ return &file;
+ }
+ cmInstalledFile& file = this->InstalledFiles[name];
+ file.SetName(mf, name);
+ return &file;
+}
+
+cmInstalledFile const* cmake::GetInstalledFile(const std::string& name) const
+{
+ auto i = this->InstalledFiles.find(name);
+
+ if (i != this->InstalledFiles.end()) {
+ cmInstalledFile const& file = i->second;
+ return &file;
+ }
+ return nullptr;
+}
+
+int cmake::GetSystemInformation(std::vector<std::string>& args)
+{
+ // so create the directory
+ std::string resultFile;
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ std::string destPath = cwd + "/__cmake_systeminformation";
+ cmSystemTools::RemoveADirectory(destPath);
+ if (!cmSystemTools::MakeDirectory(destPath)) {
+ std::cerr << "Error: --system-information must be run from a "
+ "writable directory!\n";
+ return 1;
+ }
+
+ // process the arguments
+ bool writeToStdout = true;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ std::string const& arg = args[i];
+ if (cmHasLiteralPrefix(arg, "-G")) {
+ std::string value = arg.substr(2);
+ if (value.empty()) {
+ ++i;
+ if (i >= args.size()) {
+ cmSystemTools::Error("No generator specified for -G");
+ this->PrintGeneratorList();
+ return -1;
+ }
+ value = args[i];
+ }
+ auto gen = this->CreateGlobalGenerator(value);
+ if (!gen) {
+ cmSystemTools::Error("Could not create named generator " + value);
+ this->PrintGeneratorList();
+ } else {
+ this->SetGlobalGenerator(std::move(gen));
+ }
+ }
+ // no option assume it is the output file
+ else {
+ if (!cmSystemTools::FileIsFullPath(arg)) {
+ resultFile = cmStrCat(cwd, '/');
+ }
+ resultFile += arg;
+ writeToStdout = false;
+ }
+ }
+
+ // we have to find the module directory, so we can copy the files
+ this->AddCMakePaths();
+ std::string modulesPath =
+ cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules");
+ std::string inFile = cmStrCat(modulesPath, "/SystemInformation.cmake");
+ std::string outFile = cmStrCat(destPath, "/CMakeLists.txt");
+
+ // Copy file
+ if (!cmsys::SystemTools::CopyFileAlways(inFile, outFile)) {
+ std::cerr << "Error copying file \"" << inFile << "\" to \"" << outFile
+ << "\".\n";
+ return 1;
+ }
+
+ // do we write to a file or to stdout?
+ if (resultFile.empty()) {
+ resultFile = cmStrCat(cwd, "/__cmake_systeminformation/results.txt");
+ }
+
+ {
+ // now run cmake on the CMakeLists file
+ cmWorkingDirectory workdir(destPath);
+ if (workdir.Failed()) {
+ // We created the directory and we were able to copy the CMakeLists.txt
+ // file to it, so we wouldn't expect to get here unless the default
+ // permissions are questionable or some other process has deleted the
+ // directory
+ std::cerr << "Failed to change to directory " << destPath << " : "
+ << std::strerror(workdir.GetLastResult()) << std::endl;
+ return 1;
+ }
+ std::vector<std::string> args2;
+ args2.push_back(args[0]);
+ args2.push_back(destPath);
+ args2.push_back("-DRESULT_FILE=" + resultFile);
+ int res = this->Run(args2, false);
+
+ if (res != 0) {
+ std::cerr << "Error: --system-information failed on internal CMake!\n";
+ return res;
+ }
+ }
+
+ // echo results to stdout if needed
+ if (writeToStdout) {
+ FILE* fin = cmsys::SystemTools::Fopen(resultFile, "r");
+ if (fin) {
+ const int bufferSize = 4096;
+ char buffer[bufferSize];
+ size_t n;
+ while ((n = fread(buffer, 1, bufferSize, fin)) > 0) {
+ for (char* c = buffer; c < buffer + n; ++c) {
+ putc(*c, stdout);
+ }
+ fflush(stdout);
+ }
+ fclose(fin);
+ }
+ }
+
+ // clean up the directory
+ cmSystemTools::RemoveADirectory(destPath);
+ return 0;
+}
+
+static bool cmakeCheckStampFile(const std::string& stampName)
+{
+ // The stamp file does not exist. Use the stamp dependencies to
+ // determine whether it is really out of date. This works in
+ // conjunction with cmLocalVisualStudio7Generator to avoid
+ // repeatedly re-running CMake when the user rebuilds the entire
+ // solution.
+ std::string stampDepends = cmStrCat(stampName, ".depend");
+#if defined(_WIN32) || defined(__CYGWIN__)
+ cmsys::ifstream fin(stampDepends.c_str(), std::ios::in | std::ios::binary);
+#else
+ cmsys::ifstream fin(stampDepends.c_str());
+#endif
+ if (!fin) {
+ // The stamp dependencies file cannot be read. Just assume the
+ // build system is really out of date.
+ std::cout << "CMake is re-running because " << stampName
+ << " dependency file is missing.\n";
+ return false;
+ }
+
+ // Compare the stamp dependencies against the dependency file itself.
+ {
+ cmFileTimeCache ftc;
+ std::string dep;
+ while (cmSystemTools::GetLineFromStream(fin, dep)) {
+ int result;
+ if (!dep.empty() && dep[0] != '#' &&
+ (!ftc.Compare(stampDepends, dep, &result) || result < 0)) {
+ // The stamp depends file is older than this dependency. The
+ // build system is really out of date.
+ std::cout << "CMake is re-running because " << stampName
+ << " is out-of-date.\n";
+ std::cout << " the file '" << dep << "'\n";
+ std::cout << " is newer than '" << stampDepends << "'\n";
+ std::cout << " result='" << result << "'\n";
+ return false;
+ }
+ }
+ }
+
+ // The build system is up to date. The stamp file has been removed
+ // by the VS IDE due to a "rebuild" request. Restore it atomically.
+ std::ostringstream stampTempStream;
+ stampTempStream << stampName << ".tmp" << cmSystemTools::RandomSeed();
+ std::string stampTemp = stampTempStream.str();
+ {
+ // TODO: Teach cmGeneratedFileStream to use a random temp file (with
+ // multiple tries in unlikely case of conflict) and use that here.
+ cmsys::ofstream stamp(stampTemp.c_str());
+ stamp << "# CMake generation timestamp file for this directory.\n";
+ }
+ if (cmSystemTools::RenameFile(stampTemp, stampName)) {
+ // CMake does not need to re-run because the stamp file is up-to-date.
+ return true;
+ }
+ cmSystemTools::RemoveFile(stampTemp);
+ cmSystemTools::Error("Cannot restore timestamp " + stampName);
+ return false;
+}
+
+static bool cmakeCheckStampList(const std::string& stampList)
+{
+ // If the stamp list does not exist CMake must rerun to generate it.
+ if (!cmSystemTools::FileExists(stampList)) {
+ std::cout << "CMake is re-running because generate.stamp.list "
+ << "is missing.\n";
+ return false;
+ }
+ cmsys::ifstream fin(stampList.c_str());
+ if (!fin) {
+ std::cout << "CMake is re-running because generate.stamp.list "
+ << "could not be read.\n";
+ return false;
+ }
+
+ // Check each stamp.
+ std::string stampName;
+ while (cmSystemTools::GetLineFromStream(fin, stampName)) {
+ if (!cmakeCheckStampFile(stampName)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void cmake::IssueMessage(MessageType t, std::string const& text,
+ cmListFileBacktrace const& backtrace) const
+{
+ this->Messenger->IssueMessage(t, text, backtrace);
+}
+
+std::vector<std::string> cmake::GetDebugConfigs()
+{
+ std::vector<std::string> configs;
+ if (cmProp config_list =
+ this->State->GetGlobalProperty("DEBUG_CONFIGURATIONS")) {
+ // Expand the specified list and convert to upper-case.
+ cmExpandList(*config_list, configs);
+ std::transform(configs.begin(), configs.end(), configs.begin(),
+ cmSystemTools::UpperCase);
+ }
+ // If no configurations were specified, use a default list.
+ if (configs.empty()) {
+ configs.emplace_back("DEBUG");
+ }
+ return configs;
+}
+
+int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
+ std::string config, std::vector<std::string> nativeOptions,
+ bool clean, bool verbose, const std::string& presetName,
+ bool listPresets)
+{
+ this->SetHomeDirectory("");
+ this->SetHomeOutputDirectory("");
+
+#if !defined(CMAKE_BOOTSTRAP)
+ if (!presetName.empty() || listPresets) {
+ this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+
+ cmCMakePresetsFile settingsFile;
+ auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory());
+ if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) {
+ cmSystemTools::Error(
+ cmStrCat("Could not read presets from ", this->GetHomeDirectory(),
+ ": ", cmCMakePresetsFile::ResultToString(result)));
+ return 1;
+ }
+
+ if (listPresets) {
+ settingsFile.PrintBuildPresetList();
+ return 0;
+ }
+
+ auto presetPair = settingsFile.BuildPresets.find(presetName);
+ if (presetPair == settingsFile.BuildPresets.end()) {
+ cmSystemTools::Error(cmStrCat("No such build preset in ",
+ this->GetHomeDirectory(), ": \"",
+ presetName, '"'));
+ settingsFile.PrintBuildPresetList();
+ return 1;
+ }
+
+ if (presetPair->second.Unexpanded.Hidden) {
+ cmSystemTools::Error(cmStrCat("Cannot use hidden build preset in ",
+ this->GetHomeDirectory(), ": \"",
+ presetName, '"'));
+ settingsFile.PrintBuildPresetList();
+ return 1;
+ }
+
+ auto const& expandedPreset = presetPair->second.Expanded;
+ if (!expandedPreset) {
+ cmSystemTools::Error(cmStrCat("Could not evaluate build preset \"",
+ presetName,
+ "\": Invalid macro expansion"));
+ settingsFile.PrintBuildPresetList();
+ return 1;
+ }
+
+ if (!expandedPreset->ConditionResult) {
+ cmSystemTools::Error(cmStrCat("Cannot use disabled build preset in ",
+ this->GetHomeDirectory(), ": \"",
+ presetName, '"'));
+ settingsFile.PrintBuildPresetList();
+ return 1;
+ }
+
+ auto configurePresetPair =
+ settingsFile.ConfigurePresets.find(expandedPreset->ConfigurePreset);
+ if (configurePresetPair == settingsFile.ConfigurePresets.end()) {
+ cmSystemTools::Error(cmStrCat("No such configure preset in ",
+ this->GetHomeDirectory(), ": \"",
+ expandedPreset->ConfigurePreset, '"'));
+ this->PrintPresetList(settingsFile);
+ return 1;
+ }
+
+ if (configurePresetPair->second.Unexpanded.Hidden) {
+ cmSystemTools::Error(cmStrCat("Cannot use hidden configure preset in ",
+ this->GetHomeDirectory(), ": \"",
+ expandedPreset->ConfigurePreset, '"'));
+ this->PrintPresetList(settingsFile);
+ return 1;
+ }
+
+ auto const& expandedConfigurePreset = configurePresetPair->second.Expanded;
+ if (!expandedConfigurePreset) {
+ cmSystemTools::Error(cmStrCat("Could not evaluate configure preset \"",
+ expandedPreset->ConfigurePreset,
+ "\": Invalid macro expansion"));
+ return 1;
+ }
+
+ if (!expandedConfigurePreset->BinaryDir.empty()) {
+ dir = expandedConfigurePreset->BinaryDir;
+ }
+
+ this->UnprocessedPresetEnvironment = expandedPreset->Environment;
+ this->ProcessPresetEnvironment();
+
+ if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL && expandedPreset->Jobs) {
+ jobs = *expandedPreset->Jobs;
+ }
+
+ if (targets.empty()) {
+ targets.insert(targets.begin(), expandedPreset->Targets.begin(),
+ expandedPreset->Targets.end());
+ }
+
+ if (config.empty()) {
+ config = expandedPreset->Configuration;
+ }
+
+ if (!clean && expandedPreset->CleanFirst) {
+ clean = *expandedPreset->CleanFirst;
+ }
+
+ if (!verbose && expandedPreset->Verbose) {
+ verbose = *expandedPreset->Verbose;
+ }
+
+ if (nativeOptions.empty()) {
+ nativeOptions.insert(nativeOptions.begin(),
+ expandedPreset->NativeToolOptions.begin(),
+ expandedPreset->NativeToolOptions.end());
+ }
+ }
+#endif
+
+ if (!cmSystemTools::FileIsDirectory(dir)) {
+ std::cerr << "Error: " << dir << " is not a directory\n";
+ return 1;
+ }
+
+ std::string cachePath = FindCacheFile(dir);
+ if (!this->LoadCache(cachePath)) {
+ std::cerr << "Error: could not load cache\n";
+ return 1;
+ }
+ cmProp cachedGenerator = this->State->GetCacheEntryValue("CMAKE_GENERATOR");
+ if (!cachedGenerator) {
+ std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n";
+ return 1;
+ }
+ auto gen = this->CreateGlobalGenerator(*cachedGenerator);
+ if (!gen) {
+ std::cerr << "Error: could create CMAKE_GENERATOR \"" << *cachedGenerator
+ << "\"\n";
+ return 1;
+ }
+ this->SetGlobalGenerator(std::move(gen));
+ cmProp cachedGeneratorInstance =
+ this->State->GetCacheEntryValue("CMAKE_GENERATOR_INSTANCE");
+ if (cachedGeneratorInstance) {
+ cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot());
+ if (!this->GlobalGenerator->SetGeneratorInstance(*cachedGeneratorInstance,
+ &mf)) {
+ return 1;
+ }
+ }
+ cmProp cachedGeneratorPlatform =
+ this->State->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM");
+ if (cachedGeneratorPlatform) {
+ cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot());
+ if (!this->GlobalGenerator->SetGeneratorPlatform(*cachedGeneratorPlatform,
+ &mf)) {
+ return 1;
+ }
+ }
+ cmProp cachedGeneratorToolset =
+ this->State->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET");
+ if (cachedGeneratorToolset) {
+ cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot());
+ if (!this->GlobalGenerator->SetGeneratorToolset(*cachedGeneratorToolset,
+ true, &mf)) {
+ return 1;
+ }
+ }
+ std::string output;
+ std::string projName;
+ cmProp cachedProjectName =
+ this->State->GetCacheEntryValue("CMAKE_PROJECT_NAME");
+ if (!cachedProjectName) {
+ std::cerr << "Error: could not find CMAKE_PROJECT_NAME in Cache\n";
+ return 1;
+ }
+ projName = *cachedProjectName;
+
+ if (cmIsOn(this->State->GetCacheEntryValue("CMAKE_VERBOSE_MAKEFILE"))) {
+ verbose = true;
+ }
+
+#ifdef CMAKE_HAVE_VS_GENERATORS
+ // For VS generators, explicitly check if regeneration is necessary before
+ // actually starting the build. If not done separately from the build
+ // itself, there is the risk of building an out-of-date solution file due
+ // to limitations of the underlying build system.
+ std::string const stampList = cachePath + "/" + "CMakeFiles/" +
+ cmGlobalVisualStudio9Generator::GetGenerateStampList();
+
+ // Note that the stampList file only exists for VS generators.
+ if (cmSystemTools::FileExists(stampList)) {
+
+ // Check if running for Visual Studio 9 - we need to explicitly run
+ // the glob verification script before starting the build
+ this->AddScriptingCommands();
+ if (this->GlobalGenerator->MatchesGeneratorName("Visual Studio 9 2008")) {
+ std::string const globVerifyScript =
+ cachePath + "/" + "CMakeFiles/" + "VerifyGlobs.cmake";
+ if (cmSystemTools::FileExists(globVerifyScript)) {
+ std::vector<std::string> args;
+ this->ReadListFile(args, globVerifyScript);
+ }
+ }
+
+ if (!cmakeCheckStampList(stampList)) {
+ // Correctly initialize the home (=source) and home output (=binary)
+ // directories, which is required for running the generation step.
+ std::string homeOrig = this->GetHomeDirectory();
+ std::string homeOutputOrig = this->GetHomeOutputDirectory();
+ this->SetDirectoriesFromFile(cachePath);
+
+ this->AddProjectCommands();
+
+ int ret = this->Configure();
+ if (ret) {
+ cmSystemTools::Message("CMake Configure step failed. "
+ "Build files cannot be regenerated correctly.");
+ return ret;
+ }
+ ret = this->Generate();
+ if (ret) {
+ cmSystemTools::Message("CMake Generate step failed. "
+ "Build files cannot be regenerated correctly.");
+ return ret;
+ }
+ std::string message = cmStrCat("Build files have been written to: ",
+ this->GetHomeOutputDirectory());
+ this->UpdateProgress(message, -1);
+
+ // Restore the previously set directories to their original value.
+ this->SetHomeDirectory(homeOrig);
+ this->SetHomeOutputDirectory(homeOutputOrig);
+ }
+ }
+#endif
+
+ if (!this->GlobalGenerator->ReadCacheEntriesForBuild(*this->State)) {
+ return 1;
+ }
+
+ this->GlobalGenerator->PrintBuildCommandAdvice(std::cerr, jobs);
+ return this->GlobalGenerator->Build(
+ jobs, "", dir, projName, targets, output, "", config, clean, false,
+ verbose, cmDuration::zero(), cmSystemTools::OUTPUT_PASSTHROUGH,
+ nativeOptions);
+}
+
+bool cmake::Open(const std::string& dir, bool dryRun)
+{
+ this->SetHomeDirectory("");
+ this->SetHomeOutputDirectory("");
+ if (!cmSystemTools::FileIsDirectory(dir)) {
+ std::cerr << "Error: " << dir << " is not a directory\n";
+ return false;
+ }
+
+ std::string cachePath = FindCacheFile(dir);
+ if (!this->LoadCache(cachePath)) {
+ std::cerr << "Error: could not load cache\n";
+ return false;
+ }
+ cmProp genName = this->State->GetCacheEntryValue("CMAKE_GENERATOR");
+ if (!genName) {
+ std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n";
+ return false;
+ }
+ cmProp extraGenName =
+ this->State->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
+ std::string fullName =
+ cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
+ *genName, extraGenName ? *extraGenName : "");
+
+ std::unique_ptr<cmGlobalGenerator> gen =
+ this->CreateGlobalGenerator(fullName);
+ if (!gen) {
+ std::cerr << "Error: could create CMAKE_GENERATOR \"" << fullName
+ << "\"\n";
+ return false;
+ }
+
+ cmProp cachedProjectName =
+ this->State->GetCacheEntryValue("CMAKE_PROJECT_NAME");
+ if (!cachedProjectName) {
+ std::cerr << "Error: could not find CMAKE_PROJECT_NAME in Cache\n";
+ return false;
+ }
+
+ return gen->Open(dir, *cachedProjectName, dryRun);
+}
+
+void cmake::WatchUnusedCli(const std::string& var)
+{
+#ifndef CMAKE_BOOTSTRAP
+ this->VariableWatch->AddWatch(var, cmWarnUnusedCliWarning, this);
+ if (!cm::contains(this->UsedCliVariables, var)) {
+ this->UsedCliVariables[var] = false;
+ }
+#endif
+}
+
+void cmake::UnwatchUnusedCli(const std::string& var)
+{
+#ifndef CMAKE_BOOTSTRAP
+ this->VariableWatch->RemoveWatch(var, cmWarnUnusedCliWarning);
+ this->UsedCliVariables.erase(var);
+#endif
+}
+
+void cmake::RunCheckForUnusedVariables()
+{
+#ifndef CMAKE_BOOTSTRAP
+ bool haveUnused = false;
+ std::ostringstream msg;
+ msg << "Manually-specified variables were not used by the project:";
+ for (auto const& it : this->UsedCliVariables) {
+ if (!it.second) {
+ haveUnused = true;
+ msg << "\n " << it.first;
+ }
+ }
+ if (haveUnused) {
+ this->IssueMessage(MessageType::WARNING, msg.str());
+ }
+#endif
+}
+
+bool cmake::GetSuppressDevWarnings() const
+{
+ return this->Messenger->GetSuppressDevWarnings();
+}
+
+void cmake::SetSuppressDevWarnings(bool b)
+{
+ std::string value;
+
+ // equivalent to -Wno-dev
+ if (b) {
+ value = "TRUE";
+ }
+ // equivalent to -Wdev
+ else {
+ value = "FALSE";
+ }
+
+ this->AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", value.c_str(),
+ "Suppress Warnings that are meant for"
+ " the author of the CMakeLists.txt files.",
+ cmStateEnums::INTERNAL);
+}
+
+bool cmake::GetSuppressDeprecatedWarnings() const
+{
+ return this->Messenger->GetSuppressDeprecatedWarnings();
+}
+
+void cmake::SetSuppressDeprecatedWarnings(bool b)
+{
+ std::string value;
+
+ // equivalent to -Wno-deprecated
+ if (b) {
+ value = "FALSE";
+ }
+ // equivalent to -Wdeprecated
+ else {
+ value = "TRUE";
+ }
+
+ this->AddCacheEntry("CMAKE_WARN_DEPRECATED", value.c_str(),
+ "Whether to issue warnings for deprecated "
+ "functionality.",
+ cmStateEnums::INTERNAL);
+}
+
+bool cmake::GetDevWarningsAsErrors() const
+{
+ return this->Messenger->GetDevWarningsAsErrors();
+}
+
+void cmake::SetDevWarningsAsErrors(bool b)
+{
+ std::string value;
+
+ // equivalent to -Werror=dev
+ if (b) {
+ value = "FALSE";
+ }
+ // equivalent to -Wno-error=dev
+ else {
+ value = "TRUE";
+ }
+
+ this->AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_ERRORS", value.c_str(),
+ "Suppress errors that are meant for"
+ " the author of the CMakeLists.txt files.",
+ cmStateEnums::INTERNAL);
+}
+
+bool cmake::GetDeprecatedWarningsAsErrors() const
+{
+ return this->Messenger->GetDeprecatedWarningsAsErrors();
+}
+
+void cmake::SetDeprecatedWarningsAsErrors(bool b)
+{
+ std::string value;
+
+ // equivalent to -Werror=deprecated
+ if (b) {
+ value = "TRUE";
+ }
+ // equivalent to -Wno-error=deprecated
+ else {
+ value = "FALSE";
+ }
+
+ this->AddCacheEntry("CMAKE_ERROR_DEPRECATED", value.c_str(),
+ "Whether to issue deprecation errors for macros"
+ " and functions.",
+ cmStateEnums::INTERNAL);
+}
+
+#if !defined(CMAKE_BOOTSTRAP)
+cmMakefileProfilingData& cmake::GetProfilingOutput()
+{
+ return *(this->ProfilingOutput);
+}
+
+bool cmake::IsProfilingEnabled() const
+{
+ return static_cast<bool>(this->ProfilingOutput);
+}
+#endif
diff --git a/Source/cmake.h b/Source/cmake.h
new file mode 100644
index 0000000..ab2ed21
--- /dev/null
+++ b/Source/cmake.h
@@ -0,0 +1,829 @@
+/* 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 <cstddef>
+#include <functional>
+#include <map>
+#include <memory>
+#include <set>
+#include <stack>
+#include <string>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmGeneratedFileStream.h"
+#include "cmInstalledFile.h"
+#include "cmListFileCache.h"
+#include "cmMessageType.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+
+#if !defined(CMAKE_BOOTSTRAP)
+# include <cm/optional>
+
+# include <cm3p/json/value.h>
+
+# include "cmCMakePresetsFile.h"
+#endif
+
+class cmExternalMakefileProjectGeneratorFactory;
+class cmFileAPI;
+class cmFileTimeCache;
+class cmGlobalGenerator;
+class cmGlobalGeneratorFactory;
+class cmMakefile;
+#if !defined(CMAKE_BOOTSTRAP)
+class cmMakefileProfilingData;
+#endif
+class cmMessenger;
+class cmVariableWatch;
+struct cmDocumentationEntry;
+
+/** \brief Represents a cmake invocation.
+ *
+ * This class represents a cmake invocation. It is the top level class when
+ * running cmake. Most cmake based GUIs should primarily create an instance
+ * of this class and communicate with it.
+ *
+ * The basic process for a GUI is as follows:
+ *
+ * -# Create a cmake instance
+ * -# Set the Home directories, generator, and cmake command. this
+ * can be done using the Set methods or by using SetArgs and passing in
+ * command line arguments.
+ * -# Load the cache by calling LoadCache (duh)
+ * -# if you are using command line arguments with -D or -C flags then
+ * call SetCacheArgs (or if for some other reason you want to modify the
+ * cache), do it now.
+ * -# Finally call Configure
+ * -# Let the user change values and go back to step 5
+ * -# call Generate
+
+ * If your GUI allows the user to change the home directories then
+ * you must at a minimum redo steps 2 through 7.
+ */
+
+class cmake
+{
+public:
+ enum Role
+ {
+ RoleInternal, // no commands
+ RoleScript, // script commands
+ RoleProject // all commands
+ };
+
+ enum DiagLevel
+ {
+ DIAG_IGNORE,
+ DIAG_WARN,
+ DIAG_ERROR
+ };
+
+ /** \brief Describes the working modes of cmake */
+ enum WorkingMode
+ {
+ NORMAL_MODE, ///< Cmake runs to create project files
+
+ /** \brief Script mode (started by using -P).
+ *
+ * In script mode there is no generator and no cache. Also,
+ * languages are not enabled, so add_executable and things do
+ * nothing.
+ */
+ SCRIPT_MODE,
+
+ /** \brief Help mode
+ *
+ * Used to print help for things that can only be determined after finding
+ * the source directory, for example, the list of presets.
+ */
+ HELP_MODE,
+
+ /** \brief A pkg-config like mode
+ *
+ * In this mode cmake just searches for a package and prints the results to
+ * stdout. This is similar to SCRIPT_MODE, but commands like add_library()
+ * work too, since they may be used e.g. in exported target files. Started
+ * via --find-package.
+ */
+ FIND_PACKAGE_MODE
+ };
+
+ /** \brief Define log level constants. */
+ enum LogLevel
+ {
+ LOG_UNDEFINED,
+ LOG_ERROR,
+ LOG_WARNING,
+ LOG_NOTICE,
+ LOG_STATUS,
+ LOG_VERBOSE,
+ LOG_DEBUG,
+ LOG_TRACE
+ };
+
+ /** \brief Define supported trace formats **/
+ enum TraceFormat
+ {
+ TRACE_UNDEFINED,
+ TRACE_HUMAN,
+ TRACE_JSON_V1,
+ };
+
+ struct GeneratorInfo
+ {
+ std::string name;
+ std::string baseName;
+ std::string extraName;
+ bool supportsToolset;
+ bool supportsPlatform;
+ std::vector<std::string> supportedPlatforms;
+ std::string defaultPlatform;
+ bool isAlias;
+ };
+
+ struct FileExtensions
+ {
+ bool Test(cm::string_view ext) const
+ {
+ return (this->unordered.find(ext) != this->unordered.end());
+ }
+
+ std::vector<std::string> ordered;
+ std::unordered_set<cm::string_view> unordered;
+ };
+
+ using InstalledFilesMap = std::map<std::string, cmInstalledFile>;
+
+ static const int NO_BUILD_PARALLEL_LEVEL = -1;
+ static const int DEFAULT_BUILD_PARALLEL_LEVEL = 0;
+
+ /// Default constructor
+ cmake(Role role, cmState::Mode mode);
+ /// Destructor
+ ~cmake();
+
+ cmake(cmake const&) = delete;
+ cmake& operator=(cmake const&) = delete;
+
+#if !defined(CMAKE_BOOTSTRAP)
+ Json::Value ReportVersionJson() const;
+ Json::Value ReportCapabilitiesJson() const;
+#endif
+ std::string ReportCapabilities() const;
+
+ //@{
+ /**
+ * Set/Get the home directory (or output directory) in the project. The
+ * home directory is the top directory of the project. It is the
+ * path-to-source cmake was run with.
+ */
+ void SetHomeDirectory(const std::string& dir);
+ std::string const& GetHomeDirectory() const;
+ void SetHomeOutputDirectory(const std::string& dir);
+ std::string const& GetHomeOutputDirectory() const;
+ //@}
+
+ /**
+ * Handle a command line invocation of cmake.
+ */
+ int Run(const std::vector<std::string>& args)
+ {
+ return this->Run(args, false);
+ }
+ int Run(const std::vector<std::string>& args, bool noconfigure);
+
+ /**
+ * Run the global generator Generate step.
+ */
+ int Generate();
+
+ /**
+ * Configure the cmMakefiles. This routine will create a GlobalGenerator if
+ * one has not already been set. It will then Call Configure on the
+ * GlobalGenerator. This in turn will read in an process all the CMakeList
+ * files for the tree. It will not produce any actual Makefiles, or
+ * workspaces. Generate does that. */
+ int Configure();
+ int ActualConfigure();
+
+ //! Break up a line like VAR:type="value" into var, type and value
+ static bool ParseCacheEntry(const std::string& entry, std::string& var,
+ std::string& value,
+ cmStateEnums::CacheEntryType& type);
+
+ int LoadCache();
+ bool LoadCache(const std::string& path);
+ bool LoadCache(const std::string& path, bool internal,
+ std::set<std::string>& excludes,
+ std::set<std::string>& includes);
+ bool SaveCache(const std::string& path);
+ bool DeleteCache(const std::string& path);
+ void PreLoadCMakeFiles();
+
+ //! Create a GlobalGenerator
+ std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+ const std::string& name, bool allowArch = true);
+
+ //! Create a GlobalGenerator and set it as our own
+ bool CreateAndSetGlobalGenerator(const std::string& name, bool allowArch);
+
+#ifndef CMAKE_BOOTSTRAP
+ //! Print list of configure presets
+ void PrintPresetList(const cmCMakePresetsFile& file) const;
+#endif
+
+ //! Return the global generator assigned to this instance of cmake
+ cmGlobalGenerator* GetGlobalGenerator()
+ {
+ return this->GlobalGenerator.get();
+ }
+ //! Return the global generator assigned to this instance of cmake, const
+ const cmGlobalGenerator* GetGlobalGenerator() const
+ {
+ return this->GlobalGenerator.get();
+ }
+
+ //! Return the full path to where the CMakeCache.txt file should be.
+ static std::string FindCacheFile(const std::string& binaryDir);
+
+ //! Return the global generator assigned to this instance of cmake
+ void SetGlobalGenerator(std::unique_ptr<cmGlobalGenerator>);
+
+ //! Get the names of the current registered generators
+ void GetRegisteredGenerators(std::vector<GeneratorInfo>& generators,
+ bool includeNamesWithPlatform = true) const;
+
+ //! Set the name of the selected generator-specific instance.
+ void SetGeneratorInstance(std::string const& instance)
+ {
+ this->GeneratorInstance = instance;
+ this->GeneratorInstanceSet = true;
+ }
+
+ //! Set the name of the selected generator-specific platform.
+ void SetGeneratorPlatform(std::string const& ts)
+ {
+ this->GeneratorPlatform = ts;
+ this->GeneratorPlatformSet = true;
+ }
+
+ //! Set the name of the selected generator-specific toolset.
+ void SetGeneratorToolset(std::string const& ts)
+ {
+ this->GeneratorToolset = ts;
+ this->GeneratorToolsetSet = true;
+ }
+
+ bool IsAKnownSourceExtension(cm::string_view ext) const
+ {
+ return this->CLikeSourceFileExtensions.Test(ext) ||
+ this->CudaFileExtensions.Test(ext) ||
+ this->FortranFileExtensions.Test(ext) ||
+ this->ISPCFileExtensions.Test(ext);
+ }
+
+ bool IsACLikeSourceExtension(cm::string_view ext) const
+ {
+ return this->CLikeSourceFileExtensions.Test(ext);
+ }
+
+ bool IsAKnownExtension(cm::string_view ext) const
+ {
+ return this->IsAKnownSourceExtension(ext) || this->IsAHeaderExtension(ext);
+ }
+
+ std::vector<std::string> GetAllExtensions() const;
+
+ const std::vector<std::string>& GetHeaderExtensions() const
+ {
+ return this->HeaderFileExtensions.ordered;
+ }
+
+ bool IsAHeaderExtension(cm::string_view ext) const
+ {
+ return this->HeaderFileExtensions.Test(ext);
+ }
+
+ // Strips the extension (if present and known) from a filename
+ std::string StripExtension(const std::string& file) const;
+
+ /**
+ * Given a variable name, return its value (as a string).
+ */
+ 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);
+
+ bool DoWriteGlobVerifyTarget() const;
+ std::string const& GetGlobVerifyScript() const;
+ std::string const& GetGlobVerifyStamp() const;
+ void AddGlobCacheEntry(bool recurse, bool listDirectories,
+ bool followSymlinks, const std::string& relative,
+ const std::string& expression,
+ const std::vector<std::string>& files,
+ const std::string& variable,
+ cmListFileBacktrace const& bt);
+
+ /**
+ * Get the system information and write it to the file specified
+ */
+ int GetSystemInformation(std::vector<std::string>&);
+
+ //! Parse environment variables
+ void LoadEnvironmentPresets();
+
+ //! Parse command line arguments
+ void SetArgs(const std::vector<std::string>& args);
+
+ //! Is this cmake running as a result of a TRY_COMPILE command
+ bool GetIsInTryCompile() const;
+ void SetIsInTryCompile(bool b);
+
+#ifndef CMAKE_BOOTSTRAP
+ void SetWarningFromPreset(const std::string& name,
+ const cm::optional<bool>& warning,
+ const cm::optional<bool>& error);
+ void ProcessPresetVariables();
+ void PrintPresetVariables();
+ void ProcessPresetEnvironment();
+ void PrintPresetEnvironment();
+#endif
+
+ //! Parse command line arguments that might set cache values
+ bool SetCacheArgs(const std::vector<std::string>&);
+
+ void ProcessCacheArg(const std::string& var, const std::string& value,
+ cmStateEnums::CacheEntryType type);
+
+ using ProgressCallbackType = std::function<void(const std::string&, float)>;
+ /**
+ * Set the function used by GUIs to receive progress updates
+ * Function gets passed: message as a const char*, a progress
+ * amount ranging from 0 to 1.0 and client data. The progress
+ * number provided may be negative in cases where a message is
+ * to be displayed without any progress percentage.
+ */
+ void SetProgressCallback(ProgressCallbackType f);
+
+ //! this is called by generators to update the progress
+ void UpdateProgress(const std::string& msg, float prog);
+
+#if !defined(CMAKE_BOOTSTRAP)
+ //! Get the variable watch object
+ cmVariableWatch* GetVariableWatch() { return this->VariableWatch.get(); }
+#endif
+
+ std::vector<cmDocumentationEntry> GetGeneratorsDocumentation();
+
+ //! Set/Get a property of this target file
+ void SetProperty(const std::string& prop, const char* value);
+ void AppendProperty(const std::string& prop, const std::string& value,
+ bool asString = false);
+ cmProp GetProperty(const std::string& prop);
+ bool GetPropertyAsBool(const std::string& prop);
+
+ //! Get or create an cmInstalledFile instance and return a pointer to it
+ cmInstalledFile* GetOrCreateInstalledFile(cmMakefile* mf,
+ const std::string& name);
+
+ cmInstalledFile const* GetInstalledFile(const std::string& name) const;
+
+ InstalledFilesMap const& GetInstalledFiles() const
+ {
+ return this->InstalledFiles;
+ }
+
+ //! Do all the checks before running configure
+ int DoPreConfigureChecks();
+
+ void SetWorkingMode(WorkingMode mode) { this->CurrentWorkingMode = mode; }
+ WorkingMode GetWorkingMode() { return this->CurrentWorkingMode; }
+
+ //! Debug the try compile stuff by not deleting the files
+ bool GetDebugTryCompile() const { return this->DebugTryCompile; }
+ void DebugTryCompileOn() { this->DebugTryCompile = true; }
+
+ /**
+ * Generate CMAKE_ROOT and CMAKE_COMMAND cache entries
+ */
+ int AddCMakePaths();
+
+ /**
+ * Get the file comparison class
+ */
+ cmFileTimeCache* GetFileTimeCache() { return this->FileTimeCache.get(); }
+
+ bool WasLogLevelSetViaCLI() const { return this->LogLevelWasSetViaCLI; }
+
+ //! Get the selected log level for `message()` commands during the cmake run.
+ LogLevel GetLogLevel() const { return this->MessageLogLevel; }
+ void SetLogLevel(LogLevel level) { this->MessageLogLevel = level; }
+ static LogLevel StringToLogLevel(const std::string& levelStr);
+ static TraceFormat StringToTraceFormat(const std::string& levelStr);
+
+ bool HasCheckInProgress() const
+ {
+ return !this->CheckInProgressMessages.empty();
+ }
+ std::size_t GetCheckInProgressSize() const
+ {
+ return this->CheckInProgressMessages.size();
+ }
+ std::string GetTopCheckInProgressMessage()
+ {
+ auto message = this->CheckInProgressMessages.top();
+ this->CheckInProgressMessages.pop();
+ return message;
+ }
+ void PushCheckInProgressMessage(std::string message)
+ {
+ this->CheckInProgressMessages.emplace(std::move(message));
+ }
+
+ //! Should `message` command display context.
+ bool GetShowLogContext() const { return this->LogContext; }
+ void SetShowLogContext(bool b) { this->LogContext = b; }
+
+ //! Do we want debug output during the cmake run.
+ bool GetDebugOutput() const { return this->DebugOutput; }
+ void SetDebugOutputOn(bool b) { this->DebugOutput = b; }
+
+ //! Do we want debug output from the find commands during the cmake run.
+ bool GetDebugFindOutput() const { return this->DebugFindOutput; }
+ void SetDebugFindOutputOn(bool b) { this->DebugFindOutput = b; }
+
+ //! Do we want trace output during the cmake run.
+ bool GetTrace() const { return this->Trace; }
+ void SetTrace(bool b) { this->Trace = b; }
+ bool GetTraceExpand() const { return this->TraceExpand; }
+ void SetTraceExpand(bool b) { this->TraceExpand = b; }
+ TraceFormat GetTraceFormat() const { return this->TraceFormatVar; }
+ void SetTraceFormat(TraceFormat f) { this->TraceFormatVar = f; }
+ void AddTraceSource(std::string const& file)
+ {
+ this->TraceOnlyThisSources.push_back(file);
+ }
+ std::vector<std::string> const& GetTraceSources() const
+ {
+ return this->TraceOnlyThisSources;
+ }
+ cmGeneratedFileStream& GetTraceFile() { return this->TraceFile; }
+ void SetTraceFile(std::string const& file);
+ void PrintTraceFormatVersion();
+
+ bool GetWarnUninitialized() const { return this->WarnUninitialized; }
+ void SetWarnUninitialized(bool b) { this->WarnUninitialized = b; }
+ bool GetWarnUnusedCli() const { return this->WarnUnusedCli; }
+ void SetWarnUnusedCli(bool b) { this->WarnUnusedCli = b; }
+ bool GetCheckSystemVars() const { return this->CheckSystemVars; }
+ void SetCheckSystemVars(bool b) { this->CheckSystemVars = b; }
+
+ void MarkCliAsUsed(const std::string& variable);
+
+ /** Get the list of configurations (in upper case) considered to be
+ debugging configurations.*/
+ std::vector<std::string> GetDebugConfigs();
+
+ void SetCMakeEditCommand(std::string const& s)
+ {
+ this->CMakeEditCommand = s;
+ }
+ std::string const& GetCMakeEditCommand() const
+ {
+ return this->CMakeEditCommand;
+ }
+
+ cmMessenger* GetMessenger() const { return this->Messenger.get(); }
+
+ /**
+ * Get the state of the suppression of developer (author) warnings.
+ * Returns false, by default, if developer warnings should be shown, true
+ * otherwise.
+ */
+ bool GetSuppressDevWarnings() const;
+ /**
+ * Set the state of the suppression of developer (author) warnings.
+ */
+ void SetSuppressDevWarnings(bool v);
+
+ /**
+ * Get the state of the suppression of deprecated warnings.
+ * Returns false, by default, if deprecated warnings should be shown, true
+ * otherwise.
+ */
+ bool GetSuppressDeprecatedWarnings() const;
+ /**
+ * Set the state of the suppression of deprecated warnings.
+ */
+ void SetSuppressDeprecatedWarnings(bool v);
+
+ /**
+ * Get the state of treating developer (author) warnings as errors.
+ * Returns false, by default, if warnings should not be treated as errors,
+ * true otherwise.
+ */
+ bool GetDevWarningsAsErrors() const;
+ /**
+ * Set the state of treating developer (author) warnings as errors.
+ */
+ void SetDevWarningsAsErrors(bool v);
+
+ /**
+ * Get the state of treating deprecated warnings as errors.
+ * Returns false, by default, if warnings should not be treated as errors,
+ * true otherwise.
+ */
+ bool GetDeprecatedWarningsAsErrors() const;
+ /**
+ * Set the state of treating developer (author) warnings as errors.
+ */
+ void SetDeprecatedWarningsAsErrors(bool v);
+
+ /** Display a message to the user. */
+ void IssueMessage(
+ MessageType t, std::string const& text,
+ cmListFileBacktrace const& backtrace = cmListFileBacktrace()) const;
+
+ //! run the --build option
+ int Build(int jobs, std::string dir, std::vector<std::string> targets,
+ std::string config, std::vector<std::string> nativeOptions,
+ bool clean, bool verbose, const std::string& presetName,
+ bool listPresets);
+
+ //! run the --open option
+ bool Open(const std::string& dir, bool dryRun);
+
+ void UnwatchUnusedCli(const std::string& var);
+ void WatchUnusedCli(const std::string& var);
+
+ cmState* GetState() const { return this->State.get(); }
+ void SetCurrentSnapshot(cmStateSnapshot const& snapshot)
+ {
+ this->CurrentSnapshot = snapshot;
+ }
+ cmStateSnapshot GetCurrentSnapshot() const { return this->CurrentSnapshot; }
+
+ bool GetRegenerateDuringBuild() const { return this->RegenerateDuringBuild; }
+
+#if !defined(CMAKE_BOOTSTRAP)
+ cmMakefileProfilingData& GetProfilingOutput();
+ bool IsProfilingEnabled() const;
+#endif
+
+protected:
+ void RunCheckForUnusedVariables();
+ int HandleDeleteCacheVariables(const std::string& var);
+
+ using RegisteredGeneratorsVector =
+ std::vector<std::unique_ptr<cmGlobalGeneratorFactory>>;
+ RegisteredGeneratorsVector Generators;
+ using RegisteredExtraGeneratorsVector =
+ std::vector<cmExternalMakefileProjectGeneratorFactory*>;
+ RegisteredExtraGeneratorsVector ExtraGenerators;
+ void AddScriptingCommands() const;
+ void AddProjectCommands() const;
+ void AddDefaultGenerators();
+ void AddDefaultExtraGenerators();
+
+ std::map<std::string, DiagLevel> DiagLevels;
+ std::string GeneratorInstance;
+ std::string GeneratorPlatform;
+ std::string GeneratorToolset;
+ bool GeneratorInstanceSet = false;
+ bool GeneratorPlatformSet = false;
+ bool GeneratorToolsetSet = false;
+
+ //! read in a cmake list file to initialize the cache
+ void ReadListFile(const std::vector<std::string>& args,
+ const std::string& path);
+ bool FindPackage(const std::vector<std::string>& args);
+
+ //! Check if CMAKE_CACHEFILE_DIR is set. If it is not, delete the log file.
+ /// If it is set, truncate it to 50kb
+ void TruncateOutputLog(const char* fname);
+
+ /**
+ * Method called to check build system integrity at build time.
+ * Returns 1 if CMake should rerun and 0 otherwise.
+ */
+ int CheckBuildSystem();
+
+ void SetDirectoriesFromFile(const std::string& arg);
+
+ //! Make sure all commands are what they say they are and there is no
+ /// macros.
+ void CleanupCommandsAndMacros();
+
+ void GenerateGraphViz(const std::string& fileName) const;
+
+private:
+ ProgressCallbackType ProgressCallback;
+ WorkingMode CurrentWorkingMode = NORMAL_MODE;
+ bool DebugOutput = false;
+ bool DebugFindOutput = false;
+ bool Trace = false;
+ bool TraceExpand = false;
+ TraceFormat TraceFormatVar = TRACE_HUMAN;
+ cmGeneratedFileStream TraceFile;
+ bool WarnUninitialized = false;
+ bool WarnUnusedCli = true;
+ bool CheckSystemVars = false;
+ std::map<std::string, bool> UsedCliVariables;
+ std::string CMakeEditCommand;
+ std::string CXXEnvironment;
+ std::string CCEnvironment;
+ std::string CheckBuildSystemArgument;
+ std::string CheckStampFile;
+ std::string CheckStampList;
+ std::string VSSolutionFile;
+ std::string EnvironmentGenerator;
+ FileExtensions CLikeSourceFileExtensions;
+ FileExtensions HeaderFileExtensions;
+ FileExtensions CudaFileExtensions;
+ FileExtensions ISPCFileExtensions;
+ FileExtensions FortranFileExtensions;
+ bool ClearBuildSystem = false;
+ bool DebugTryCompile = false;
+ bool RegenerateDuringBuild = false;
+ std::unique_ptr<cmFileTimeCache> FileTimeCache;
+ std::string GraphVizFile;
+ InstalledFilesMap InstalledFiles;
+#ifndef CMAKE_BOOTSTRAP
+ std::map<std::string, cm::optional<cmCMakePresetsFile::CacheVariable>>
+ UnprocessedPresetVariables;
+ std::map<std::string, cm::optional<std::string>>
+ UnprocessedPresetEnvironment;
+#endif
+
+#if !defined(CMAKE_BOOTSTRAP)
+ std::unique_ptr<cmVariableWatch> VariableWatch;
+ std::unique_ptr<cmFileAPI> FileAPI;
+#endif
+
+ std::unique_ptr<cmState> State;
+ cmStateSnapshot CurrentSnapshot;
+ std::unique_ptr<cmMessenger> Messenger;
+
+ std::vector<std::string> TraceOnlyThisSources;
+
+ LogLevel MessageLogLevel = LogLevel::LOG_STATUS;
+ bool LogLevelWasSetViaCLI = false;
+ bool LogContext = false;
+
+ std::stack<std::string> CheckInProgressMessages;
+
+ std::unique_ptr<cmGlobalGenerator> GlobalGenerator;
+
+ void UpdateConversionPathTable();
+
+ //! Print a list of valid generators to stderr.
+ void PrintGeneratorList();
+
+ std::unique_ptr<cmGlobalGenerator> EvaluateDefaultGlobalGenerator();
+ void CreateDefaultGlobalGenerator();
+
+ void AppendGlobalGeneratorsDocumentation(std::vector<cmDocumentationEntry>&);
+ void AppendExtraGeneratorsDocumentation(std::vector<cmDocumentationEntry>&);
+
+#if !defined(CMAKE_BOOTSTRAP)
+ std::unique_ptr<cmMakefileProfilingData> ProfilingOutput;
+#endif
+};
+
+#define CMAKE_STANDARD_OPTIONS_TABLE \
+ { "-S <path-to-source>", "Explicitly specify a source directory." }, \
+ { "-B <path-to-build>", "Explicitly specify a build directory." }, \
+ { "-C <initial-cache>", "Pre-load a script to populate the cache." }, \
+ { "-D <var>[:<type>]=<value>", "Create or update a cmake cache entry." }, \
+ { "-U <globbing_expr>", "Remove matching entries from CMake cache." }, \
+ { "-G <generator-name>", "Specify a build system generator." }, \
+ { "-T <toolset-name>", \
+ "Specify toolset name if supported by generator." }, \
+ { "-A <platform-name>", \
+ "Specify platform name if supported by generator." }, \
+ { "--install-prefix <directory>", \
+ "Specify install directory [CMAKE_INSTALL_PREFIX]." }, \
+ { "-Wdev", "Enable developer warnings." }, \
+ { "-Wno-dev", "Suppress developer warnings." }, \
+ { "-Werror=dev", "Make developer warnings errors." }, \
+ { "-Wno-error=dev", "Make developer warnings not errors." }, \
+ { "-Wdeprecated", "Enable deprecation warnings." }, \
+ { "-Wno-deprecated", "Suppress deprecation warnings." }, \
+ { "-Werror=deprecated", \
+ "Make deprecated macro and function warnings " \
+ "errors." }, \
+ { \
+ "-Wno-error=deprecated", \
+ "Make deprecated macro and function warnings " \
+ "not errors." \
+ }
+
+#define FOR_EACH_C90_FEATURE(F) F(c_function_prototypes)
+
+#define FOR_EACH_C99_FEATURE(F) \
+ F(c_restrict) \
+ F(c_variadic_macros)
+
+#define FOR_EACH_C11_FEATURE(F) F(c_static_assert)
+
+#define FOR_EACH_C_FEATURE(F) \
+ F(c_std_90) \
+ F(c_std_99) \
+ F(c_std_11) \
+ F(c_std_17) \
+ F(c_std_23) \
+ FOR_EACH_C90_FEATURE(F) \
+ FOR_EACH_C99_FEATURE(F) \
+ FOR_EACH_C11_FEATURE(F)
+
+#define FOR_EACH_CXX98_FEATURE(F) F(cxx_template_template_parameters)
+
+#define FOR_EACH_CXX11_FEATURE(F) \
+ F(cxx_alias_templates) \
+ F(cxx_alignas) \
+ F(cxx_alignof) \
+ F(cxx_attributes) \
+ F(cxx_auto_type) \
+ F(cxx_constexpr) \
+ F(cxx_decltype) \
+ F(cxx_decltype_incomplete_return_types) \
+ F(cxx_default_function_template_args) \
+ F(cxx_defaulted_functions) \
+ F(cxx_defaulted_move_initializers) \
+ F(cxx_delegating_constructors) \
+ F(cxx_deleted_functions) \
+ F(cxx_enum_forward_declarations) \
+ F(cxx_explicit_conversions) \
+ F(cxx_extended_friend_declarations) \
+ F(cxx_extern_templates) \
+ F(cxx_final) \
+ F(cxx_func_identifier) \
+ F(cxx_generalized_initializers) \
+ F(cxx_inheriting_constructors) \
+ F(cxx_inline_namespaces) \
+ F(cxx_lambdas) \
+ F(cxx_local_type_template_args) \
+ F(cxx_long_long_type) \
+ F(cxx_noexcept) \
+ F(cxx_nonstatic_member_init) \
+ F(cxx_nullptr) \
+ F(cxx_override) \
+ F(cxx_range_for) \
+ F(cxx_raw_string_literals) \
+ F(cxx_reference_qualified_functions) \
+ F(cxx_right_angle_brackets) \
+ F(cxx_rvalue_references) \
+ F(cxx_sizeof_member) \
+ F(cxx_static_assert) \
+ F(cxx_strong_enums) \
+ F(cxx_thread_local) \
+ F(cxx_trailing_return_types) \
+ F(cxx_unicode_literals) \
+ F(cxx_uniform_initialization) \
+ F(cxx_unrestricted_unions) \
+ F(cxx_user_literals) \
+ F(cxx_variadic_macros) \
+ F(cxx_variadic_templates)
+
+#define FOR_EACH_CXX14_FEATURE(F) \
+ F(cxx_aggregate_default_initializers) \
+ F(cxx_attribute_deprecated) \
+ F(cxx_binary_literals) \
+ F(cxx_contextual_conversions) \
+ F(cxx_decltype_auto) \
+ F(cxx_digit_separators) \
+ F(cxx_generic_lambdas) \
+ F(cxx_lambda_init_captures) \
+ F(cxx_relaxed_constexpr) \
+ F(cxx_return_type_deduction) \
+ F(cxx_variable_templates)
+
+#define FOR_EACH_CXX_FEATURE(F) \
+ F(cxx_std_98) \
+ F(cxx_std_11) \
+ F(cxx_std_14) \
+ F(cxx_std_17) \
+ F(cxx_std_20) \
+ F(cxx_std_23) \
+ FOR_EACH_CXX98_FEATURE(F) \
+ FOR_EACH_CXX11_FEATURE(F) \
+ FOR_EACH_CXX14_FEATURE(F)
+
+#define FOR_EACH_CUDA_FEATURE(F) \
+ F(cuda_std_03) \
+ F(cuda_std_11) \
+ F(cuda_std_14) \
+ F(cuda_std_17) \
+ F(cuda_std_20) \
+ F(cuda_std_23)
diff --git a/Source/cmake.version.manifest b/Source/cmake.version.manifest
new file mode 100644
index 0000000..e7010c9
--- /dev/null
+++ b/Source/cmake.version.manifest
@@ -0,0 +1,18 @@
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+ manifestVersion="1.0"
+ xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!-- Windows Vista -->
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+ <!-- Windows 7 -->
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ <!-- Windows 8 -->
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+ <!-- Windows 8.1 -->
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+ <!-- Windows 10 -->
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+ </application>
+ </compatibility>
+</assembly>
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
new file mode 100644
index 0000000..88ba011
--- /dev/null
+++ b/Source/cmakemain.cxx
@@ -0,0 +1,967 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <algorithm>
+#include <cassert>
+#include <climits>
+#include <cstring>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cmext/algorithm>
+
+#include <cm3p/uv.h>
+
+#include "cmCommandLineArgument.h"
+#include "cmConsoleBuf.h"
+#include "cmDocumentationEntry.h" // IWYU pragma: keep
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+#include "cmcmd.h"
+
+#ifndef CMAKE_BOOTSTRAP
+# include "cmDocumentation.h"
+# include "cmDynamicLoader.h"
+#endif
+
+#include "cmsys/Encoding.hxx"
+
+namespace {
+#ifndef CMAKE_BOOTSTRAP
+const char* cmDocumentationName[][2] = {
+ { nullptr, " cmake - Cross-Platform Makefile Generator." },
+ { nullptr, nullptr }
+};
+
+const char* cmDocumentationUsage[][2] = {
+ { nullptr,
+ " cmake [options] <path-to-source>\n"
+ " cmake [options] <path-to-existing-build>\n"
+ " cmake [options] -S <path-to-source> -B <path-to-build>" },
+ { nullptr,
+ "Specify a source directory to (re-)generate a build system for "
+ "it in the current working directory. Specify an existing build "
+ "directory to re-generate its build system." },
+ { nullptr, nullptr }
+};
+
+const char* cmDocumentationUsageNote[][2] = {
+ { nullptr, "Run 'cmake --help' for more information." },
+ { nullptr, nullptr }
+};
+
+const char* cmDocumentationOptions[][2] = {
+ CMAKE_STANDARD_OPTIONS_TABLE,
+ { "--preset <preset>,--preset=<preset>", "Specify a configure preset." },
+ { "--list-presets", "List available presets." },
+ { "-E", "CMake command mode." },
+ { "-L[A][H]", "List non-advanced cached variables." },
+ { "--build <dir>", "Build a CMake-generated project binary tree." },
+ { "--install <dir>", "Install a CMake-generated project binary tree." },
+ { "--open <dir>", "Open generated project in the associated application." },
+ { "-N", "View mode only." },
+ { "-P <file>", "Process script mode." },
+ { "--find-package", "Legacy pkg-config like mode. Do not use." },
+ { "--graphviz=[file]",
+ "Generate graphviz of dependencies, see "
+ "CMakeGraphVizOptions.cmake for more." },
+ { "--system-information [file]", "Dump information about this system." },
+ { "--log-level=<ERROR|WARNING|NOTICE|STATUS|VERBOSE|DEBUG|TRACE>",
+ "Set the verbosity of messages from CMake files. "
+ "--loglevel is also accepted for backward compatibility reasons." },
+ { "--log-context", "Prepend log messages with context, if given" },
+ { "--debug-trycompile",
+ "Do not delete the try_compile build tree. Only "
+ "useful on one try_compile at a time." },
+ { "--debug-output", "Put cmake in a debug mode." },
+ { "--debug-find", "Put cmake find in a debug mode." },
+ { "--trace", "Put cmake in trace mode." },
+ { "--trace-expand", "Put cmake in trace mode with variable expansion." },
+ { "--trace-format=<human|json-v1>", "Set the output format of the trace." },
+ { "--trace-source=<file>",
+ "Trace only this CMake file/module. Multiple options allowed." },
+ { "--trace-redirect=<file>",
+ "Redirect trace output to a file instead of stderr." },
+ { "--warn-uninitialized", "Warn about uninitialized values." },
+ { "--no-warn-unused-cli", "Don't warn about command line options." },
+ { "--check-system-vars",
+ "Find problems with variable usage in system "
+ "files." },
+# if !defined(CMAKE_BOOTSTRAP)
+ { "--profiling-format=<fmt>",
+ "Output data for profiling CMake scripts. Supported formats: "
+ "google-trace" },
+ { "--profiling-output=<file>",
+ "Select an output path for the profiling data enabled through "
+ "--profiling-format." },
+# endif
+ { nullptr, nullptr }
+};
+
+#endif
+
+int do_command(int ac, char const* const* av,
+ std::unique_ptr<cmConsoleBuf> consoleBuf)
+{
+ std::vector<std::string> args;
+ args.reserve(ac - 1);
+ args.emplace_back(av[0]);
+ cm::append(args, av + 2, av + ac);
+ return cmcmd::ExecuteCMakeCommand(args, std::move(consoleBuf));
+}
+
+cmMakefile* cmakemainGetMakefile(cmake* cm)
+{
+ if (cm && cm->GetDebugOutput()) {
+ cmGlobalGenerator* gg = cm->GetGlobalGenerator();
+ if (gg) {
+ return gg->GetCurrentMakefile();
+ }
+ }
+ return nullptr;
+}
+
+std::string cmakemainGetStack(cmake* cm)
+{
+ std::string msg;
+ cmMakefile* mf = cmakemainGetMakefile(cm);
+ if (mf) {
+ msg = mf->FormatListFileStack();
+ if (!msg.empty()) {
+ msg = "\n Called from: " + msg;
+ }
+ }
+
+ return msg;
+}
+
+void cmakemainMessageCallback(const std::string& m, const char* /*unused*/,
+ cmake* cm)
+{
+ std::cerr << m << cmakemainGetStack(cm) << std::endl;
+}
+
+void cmakemainProgressCallback(const std::string& m, float prog, cmake* cm)
+{
+ cmMakefile* mf = cmakemainGetMakefile(cm);
+ std::string dir;
+ if (mf && cmHasLiteralPrefix(m, "Configuring") && (prog < 0)) {
+ dir = cmStrCat(' ', mf->GetCurrentSourceDirectory());
+ } else if (mf && cmHasLiteralPrefix(m, "Generating")) {
+ dir = cmStrCat(' ', mf->GetCurrentBinaryDirectory());
+ }
+
+ if ((prog < 0) || (!dir.empty())) {
+ std::cout << "-- " << m << dir << cmakemainGetStack(cm) << std::endl;
+ }
+}
+
+int do_cmake(int ac, char const* const* av)
+{
+ if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
+ std::cerr << "Current working directory cannot be established."
+ << std::endl;
+ return 1;
+ }
+
+#ifndef CMAKE_BOOTSTRAP
+ cmDocumentation doc;
+ doc.addCMakeStandardDocSections();
+ if (doc.CheckOptions(ac, av)) {
+ // Construct and print requested documentation.
+ cmake hcm(cmake::RoleInternal, cmState::Unknown);
+ hcm.SetHomeDirectory("");
+ hcm.SetHomeOutputDirectory("");
+ hcm.AddCMakePaths();
+
+ // the command line args are processed here so that you can do
+ // -DCMAKE_MODULE_PATH=/some/path and have this value accessible here
+ std::vector<std::string> args(av, av + ac);
+ hcm.SetCacheArgs(args);
+
+ auto generators = hcm.GetGeneratorsDocumentation();
+
+ doc.SetName("cmake");
+ doc.SetSection("Name", cmDocumentationName);
+ doc.SetSection("Usage", cmDocumentationUsage);
+ if (ac == 1) {
+ doc.AppendSection("Usage", cmDocumentationUsageNote);
+ }
+ doc.AppendSection("Generators", generators);
+ doc.PrependSection("Options", cmDocumentationOptions);
+
+ return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
+ }
+#else
+ if (ac == 1) {
+ std::cout
+ << "Bootstrap CMake should not be used outside CMake build process."
+ << std::endl;
+ return 0;
+ }
+#endif
+
+ bool wizard_mode = false;
+ bool sysinfo = false;
+ bool list_cached = false;
+ bool list_all_cached = false;
+ bool list_help = false;
+ bool view_only = false;
+ cmake::WorkingMode workingMode = cmake::NORMAL_MODE;
+ std::vector<std::string> parsedArgs;
+
+ using CommandArgument =
+ cmCommandLineArgument<bool(std::string const& value)>;
+ std::vector<CommandArgument> arguments = {
+ CommandArgument{
+ "-i", CommandArgument::Values::Zero,
+ [&wizard_mode](std::string const&) -> bool {
+ /* clang-format off */
+ std::cerr <<
+ "The \"cmake -i\" wizard mode is no longer supported.\n"
+ "Use the -D option to set cache values on the command line.\n"
+ "Use cmake-gui or ccmake for an interactive dialog.\n";
+ /* clang-format on */
+ wizard_mode = true;
+ return true;
+ } },
+ CommandArgument{ "--system-information", CommandArgument::Values::Zero,
+ [&](std::string const&) -> bool {
+ sysinfo = true;
+ return true;
+ } },
+ CommandArgument{ "-N", CommandArgument::Values::Zero,
+ [&](std::string const&) -> bool {
+ view_only = true;
+ return true;
+ } },
+ CommandArgument{ "-LAH", CommandArgument::Values::Zero,
+ [&](std::string const&) -> bool {
+ list_all_cached = true;
+ list_help = true;
+ return true;
+ } },
+ CommandArgument{ "-LA", CommandArgument::Values::Zero,
+ [&](std::string const&) -> bool {
+ list_all_cached = true;
+ return true;
+ } },
+ CommandArgument{ "-LH", CommandArgument::Values::Zero,
+ [&](std::string const&) -> bool {
+ list_cached = true;
+ list_help = true;
+ return true;
+ } },
+ CommandArgument{ "-L", CommandArgument::Values::Zero,
+ [&](std::string const&) -> bool {
+ list_cached = true;
+ return true;
+ } },
+ CommandArgument{ "-P", "No script specified for argument -P",
+ CommandArgument::Values::One,
+ [&](std::string const& value) -> bool {
+ workingMode = cmake::SCRIPT_MODE;
+ parsedArgs.emplace_back("-P");
+ parsedArgs.push_back(value);
+ return true;
+ } },
+ CommandArgument{ "--find-package", CommandArgument::Values::Zero,
+ [&](std::string const&) -> bool {
+ workingMode = cmake::FIND_PACKAGE_MODE;
+ parsedArgs.emplace_back("--find-package");
+ return true;
+ } },
+ CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
+ [&](std::string const&) -> bool {
+ workingMode = cmake::HELP_MODE;
+ parsedArgs.emplace_back("--list-presets");
+ return true;
+ } },
+ };
+
+ std::vector<std::string> inputArgs;
+ inputArgs.reserve(ac);
+ cm::append(inputArgs, av, av + ac);
+
+ for (decltype(inputArgs.size()) i = 0; i < inputArgs.size(); ++i) {
+ std::string const& arg = inputArgs[i];
+ bool matched = false;
+ for (auto const& m : arguments) {
+ if (m.matches(arg)) {
+ matched = true;
+ if (m.parse(arg, i, inputArgs)) {
+ break;
+ }
+ return 1; // failed to parse
+ }
+ }
+ if (!matched) {
+ parsedArgs.emplace_back(av[i]);
+ }
+ }
+
+ if (wizard_mode) {
+ return 1;
+ }
+
+ if (sysinfo) {
+ cmake cm(cmake::RoleProject, cmState::Project);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ int ret = cm.GetSystemInformation(parsedArgs);
+ return ret;
+ }
+ cmake::Role const role =
+ workingMode == cmake::SCRIPT_MODE ? cmake::RoleScript : cmake::RoleProject;
+ cmState::Mode mode = cmState::Unknown;
+ switch (workingMode) {
+ case cmake::NORMAL_MODE:
+ case cmake::HELP_MODE:
+ mode = cmState::Project;
+ break;
+ case cmake::SCRIPT_MODE:
+ mode = cmState::Script;
+ break;
+ case cmake::FIND_PACKAGE_MODE:
+ mode = cmState::FindPackage;
+ break;
+ }
+ cmake cm(role, mode);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cmSystemTools::SetMessageCallback(
+ [&cm](const std::string& msg, const char* title) {
+ cmakemainMessageCallback(msg, title, &cm);
+ });
+ cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
+ cmakemainProgressCallback(msg, prog, &cm);
+ });
+ cm.SetWorkingMode(workingMode);
+
+ int res = cm.Run(parsedArgs, view_only);
+ if (list_cached || list_all_cached) {
+ std::cout << "-- Cache values" << std::endl;
+ std::vector<std::string> keys = cm.GetState()->GetCacheEntryKeys();
+ for (std::string const& k : keys) {
+ cmStateEnums::CacheEntryType t = cm.GetState()->GetCacheEntryType(k);
+ if (t != cmStateEnums::INTERNAL && t != cmStateEnums::STATIC &&
+ t != cmStateEnums::UNINITIALIZED) {
+ cmProp advancedProp =
+ cm.GetState()->GetCacheEntryProperty(k, "ADVANCED");
+ if (list_all_cached || !advancedProp) {
+ if (list_help) {
+ cmProp help =
+ cm.GetState()->GetCacheEntryProperty(k, "HELPSTRING");
+ std::cout << "// " << (help ? *help : "") << std::endl;
+ }
+ std::cout << k << ":" << cmState::CacheEntryTypeToString(t) << "="
+ << cm.GetState()->GetSafeCacheEntryValue(k) << std::endl;
+ if (list_help) {
+ std::cout << std::endl;
+ }
+ }
+ }
+ }
+ }
+
+ // Always return a non-negative value. Windows tools do not always
+ // interpret negative return values as errors.
+ if (res != 0) {
+ return 1;
+ }
+ return 0;
+}
+
+#ifndef CMAKE_BOOTSTRAP
+int extract_job_number(std::string const& command,
+ std::string const& jobString)
+{
+ int jobs = -1;
+ unsigned long numJobs = 0;
+ if (jobString.empty()) {
+ jobs = cmake::DEFAULT_BUILD_PARALLEL_LEVEL;
+ } else if (cmStrToULong(jobString, &numJobs)) {
+ if (numJobs == 0) {
+ std::cerr
+ << "The <jobs> value requires a positive integer argument.\n\n";
+ } else if (numJobs > INT_MAX) {
+ std::cerr << "The <jobs> value is too large.\n\n";
+ } else {
+ jobs = int(numJobs);
+ }
+ } else {
+ std::cerr << "'" << command << "' invalid number '" << jobString
+ << "' given.\n\n";
+ }
+ return jobs;
+}
+#endif
+
+int do_build(int ac, char const* const* av)
+{
+#ifdef CMAKE_BOOTSTRAP
+ std::cerr << "This cmake does not support --build\n";
+ return -1;
+#else
+ int jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
+ std::vector<std::string> targets;
+ std::string config;
+ std::string dir;
+ std::vector<std::string> nativeOptions;
+ bool nativeOptionsPassed = false;
+ bool cleanFirst = false;
+ bool foundClean = false;
+ bool foundNonClean = false;
+ bool verbose = cmSystemTools::HasEnv("VERBOSE");
+ std::string presetName;
+ bool listPresets = false;
+
+ auto jLambda = [&](std::string const& value) -> bool {
+ jobs = extract_job_number("-j", value);
+ if (jobs < 0) {
+ dir.clear();
+ }
+ return true;
+ };
+ auto parallelLambda = [&](std::string const& value) -> bool {
+ jobs = extract_job_number("--parallel", value);
+ if (jobs < 0) {
+ dir.clear();
+ }
+ return true;
+ };
+ auto targetLambda = [&](std::string const& value) -> bool {
+ if (!value.empty()) {
+ std::vector<std::string> values = cmExpandedList(value);
+ for (auto const& v : values) {
+ targets.emplace_back(v);
+ if (v == "clean") {
+ foundClean = true;
+ } else {
+ foundNonClean = true;
+ }
+ }
+ return true;
+ }
+ return false;
+ };
+ auto verboseLambda = [&](std::string const&) -> bool {
+ verbose = true;
+ return true;
+ };
+
+ using CommandArgument =
+ cmCommandLineArgument<bool(std::string const& value)>;
+
+ std::vector<CommandArgument> arguments = {
+ CommandArgument{ "--preset", CommandArgument::Values::One,
+ [&](std::string const& value) -> bool {
+ presetName = value;
+ return true;
+ } },
+ CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
+ [&](std::string const&) -> bool {
+ listPresets = true;
+ return true;
+ } },
+ CommandArgument{ "-j", CommandArgument::Values::ZeroOrOne, jLambda },
+ CommandArgument{ "--parallel", CommandArgument::Values::ZeroOrOne,
+ parallelLambda },
+ CommandArgument{ "-t", CommandArgument::Values::OneOrMore, targetLambda },
+ CommandArgument{ "--target", CommandArgument::Values::OneOrMore,
+ targetLambda },
+ CommandArgument{ "--config", CommandArgument::Values::One,
+ [&](std::string const& value) -> bool {
+ config = value;
+ return true;
+ } },
+ CommandArgument{ "--clean-first", CommandArgument::Values::Zero,
+ [&](std::string const&) -> bool {
+ cleanFirst = true;
+ return true;
+ } },
+ CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda },
+ CommandArgument{ "--verbose", CommandArgument::Values::Zero,
+ verboseLambda },
+ /* legacy option no-op*/
+ CommandArgument{ "--use-stderr", CommandArgument::Values::Zero,
+ [](std::string const&) -> bool { return true; } },
+ CommandArgument{ "--", CommandArgument::Values::Zero,
+ [&](std::string const&) -> bool {
+ nativeOptionsPassed = true;
+ return true;
+ } },
+ };
+
+ if (ac >= 3) {
+ std::vector<std::string> inputArgs;
+
+ bool hasPreset = false;
+ for (int i = 2; i < ac; ++i) {
+ if (strcmp(av[i], "--list-presets") == 0 ||
+ cmHasLiteralPrefix(av[i], "--preset=") ||
+ strcmp(av[i], "--preset") == 0) {
+ hasPreset = true;
+ break;
+ }
+ }
+
+ if (hasPreset) {
+ inputArgs.reserve(ac - 2);
+ cm::append(inputArgs, av + 2, av + ac);
+ } else {
+ dir = cmSystemTools::CollapseFullPath(av[2]);
+
+ inputArgs.reserve(ac - 3);
+ cm::append(inputArgs, av + 3, av + ac);
+ }
+
+ decltype(inputArgs.size()) i = 0;
+ for (; i < inputArgs.size() && !nativeOptionsPassed; ++i) {
+
+ std::string const& arg = inputArgs[i];
+ for (auto const& m : arguments) {
+ if (m.matches(arg) && m.parse(arg, i, inputArgs)) {
+ break;
+ }
+ }
+ }
+
+ if (nativeOptionsPassed) {
+ cm::append(nativeOptions, inputArgs.begin() + i, inputArgs.end());
+ }
+ }
+
+ if (foundClean && foundNonClean) {
+ std::cerr << "Error: Building 'clean' and other targets together "
+ "is not supported."
+ << std::endl;
+ dir.clear();
+ }
+
+ if (jobs == cmake::NO_BUILD_PARALLEL_LEVEL) {
+ std::string parallel;
+ if (cmSystemTools::GetEnv("CMAKE_BUILD_PARALLEL_LEVEL", parallel)) {
+ if (parallel.empty()) {
+ jobs = cmake::DEFAULT_BUILD_PARALLEL_LEVEL;
+ } else {
+ unsigned long numJobs = 0;
+ if (cmStrToULong(parallel, &numJobs)) {
+ if (numJobs == 0) {
+ std::cerr << "The CMAKE_BUILD_PARALLEL_LEVEL environment variable "
+ "requires a positive integer argument.\n\n";
+ dir.clear();
+ } else if (numJobs > INT_MAX) {
+ std::cerr << "The CMAKE_BUILD_PARALLEL_LEVEL environment variable "
+ "is too large.\n\n";
+ dir.clear();
+ } else {
+ jobs = int(numJobs);
+ }
+ } else {
+ std::cerr << "'CMAKE_BUILD_PARALLEL_LEVEL' environment variable\n"
+ << "invalid number '" << parallel << "' given.\n\n";
+ dir.clear();
+ }
+ }
+ }
+ }
+
+ if (dir.empty() && presetName.empty() && !listPresets) {
+ /* clang-format off */
+ std::cerr <<
+ "Usage: cmake --build [<dir> | --preset <preset>] [options] [-- [native-options]]\n"
+ "Options:\n"
+ " <dir> = Project binary directory to be built.\n"
+ " --preset <preset>, --preset=<preset>\n"
+ " = Specify a build preset.\n"
+ " --list-presets\n"
+ " = List available build presets.\n"
+ " --parallel [<jobs>], -j [<jobs>]\n"
+ " = Build in parallel using the given number of jobs. \n"
+ " If <jobs> is omitted the native build tool's \n"
+ " default number is used.\n"
+ " The CMAKE_BUILD_PARALLEL_LEVEL environment "
+ "variable\n"
+ " specifies a default parallel level when this "
+ "option\n"
+ " is not given.\n"
+ " --target <tgt>..., -t <tgt>... \n"
+ " = Build <tgt> instead of default targets.\n"
+ " --config <cfg> = For multi-configuration tools, choose <cfg>.\n"
+ " --clean-first = Build target 'clean' first, then build.\n"
+ " (To clean only, use --target 'clean'.)\n"
+ " --verbose, -v = Enable verbose output - if supported - including\n"
+ " the build commands to be executed. \n"
+ " -- = Pass remaining options to the native tool.\n"
+ ;
+ /* clang-format on */
+ return 1;
+ }
+
+ cmake cm(cmake::RoleInternal, cmState::Project);
+ cmSystemTools::SetMessageCallback(
+ [&cm](const std::string& msg, const char* title) {
+ cmakemainMessageCallback(msg, title, &cm);
+ });
+ cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
+ cmakemainProgressCallback(msg, prog, &cm);
+ });
+
+ return cm.Build(jobs, std::move(dir), std::move(targets), std::move(config),
+ std::move(nativeOptions), cleanFirst, verbose, presetName,
+ listPresets);
+#endif
+}
+
+bool parse_default_directory_permissions(const std::string& permissions,
+ std::string& parsedPermissionsVar)
+{
+ std::vector<std::string> parsedPermissions;
+ enum Doing
+ {
+ DoingNone,
+ DoingOwner,
+ DoingGroup,
+ DoingWorld,
+ DoingOwnerAssignment,
+ DoingGroupAssignment,
+ DoingWorldAssignment,
+ };
+ Doing doing = DoingNone;
+
+ auto uniquePushBack = [&parsedPermissions](const std::string& e) {
+ if (std::find(parsedPermissions.begin(), parsedPermissions.end(), e) ==
+ parsedPermissions.end()) {
+ parsedPermissions.push_back(e);
+ }
+ };
+
+ for (auto const& e : permissions) {
+ switch (doing) {
+ case DoingNone:
+ if (e == 'u') {
+ doing = DoingOwner;
+ } else if (e == 'g') {
+ doing = DoingGroup;
+ } else if (e == 'o') {
+ doing = DoingWorld;
+ } else {
+ return false;
+ }
+ break;
+ case DoingOwner:
+ if (e == '=') {
+ doing = DoingOwnerAssignment;
+ } else {
+ return false;
+ }
+ break;
+ case DoingGroup:
+ if (e == '=') {
+ doing = DoingGroupAssignment;
+ } else {
+ return false;
+ }
+ break;
+ case DoingWorld:
+ if (e == '=') {
+ doing = DoingWorldAssignment;
+ } else {
+ return false;
+ }
+ break;
+ case DoingOwnerAssignment:
+ if (e == 'r') {
+ uniquePushBack("OWNER_READ");
+ } else if (e == 'w') {
+ uniquePushBack("OWNER_WRITE");
+ } else if (e == 'x') {
+ uniquePushBack("OWNER_EXECUTE");
+ } else if (e == ',') {
+ doing = DoingNone;
+ } else {
+ return false;
+ }
+ break;
+ case DoingGroupAssignment:
+ if (e == 'r') {
+ uniquePushBack("GROUP_READ");
+ } else if (e == 'w') {
+ uniquePushBack("GROUP_WRITE");
+ } else if (e == 'x') {
+ uniquePushBack("GROUP_EXECUTE");
+ } else if (e == ',') {
+ doing = DoingNone;
+ } else {
+ return false;
+ }
+ break;
+ case DoingWorldAssignment:
+ if (e == 'r') {
+ uniquePushBack("WORLD_READ");
+ } else if (e == 'w') {
+ uniquePushBack("WORLD_WRITE");
+ } else if (e == 'x') {
+ uniquePushBack("WORLD_EXECUTE");
+ } else if (e == ',') {
+ doing = DoingNone;
+ } else {
+ return false;
+ }
+ break;
+ }
+ }
+ if (doing != DoingOwnerAssignment && doing != DoingGroupAssignment &&
+ doing != DoingWorldAssignment) {
+ return false;
+ }
+
+ std::ostringstream oss;
+ for (auto i = 0u; i < parsedPermissions.size(); i++) {
+ if (i != 0) {
+ oss << ";";
+ }
+ oss << parsedPermissions[i];
+ }
+
+ parsedPermissionsVar = oss.str();
+ return true;
+}
+
+int do_install(int ac, char const* const* av)
+{
+#ifdef CMAKE_BOOTSTRAP
+ std::cerr << "This cmake does not support --install\n";
+ return -1;
+#else
+ assert(1 < ac);
+
+ std::string config;
+ std::string component;
+ std::string defaultDirectoryPermissions;
+ std::string prefix;
+ std::string dir;
+ bool strip = false;
+ bool verbose = cmSystemTools::HasEnv("VERBOSE");
+
+ auto verboseLambda = [&](std::string const&) -> bool {
+ verbose = true;
+ return true;
+ };
+
+ using CommandArgument =
+ cmCommandLineArgument<bool(std::string const& value)>;
+
+ std::vector<CommandArgument> arguments = {
+ CommandArgument{ "--config", CommandArgument::Values::One,
+ [&](std::string const& value) -> bool {
+ config = value;
+ return true;
+ } },
+ CommandArgument{ "--component", CommandArgument::Values::One,
+ [&](std::string const& value) -> bool {
+ component = value;
+ return true;
+ } },
+ CommandArgument{ "--default-directory-permissions",
+ CommandArgument::Values::One,
+ [&](std::string const& value) -> bool {
+ defaultDirectoryPermissions = value;
+ return true;
+ } },
+ CommandArgument{ "--prefix", CommandArgument::Values::One,
+ [&](std::string const& value) -> bool {
+ prefix = value;
+ return true;
+ } },
+ CommandArgument{ "--strip", CommandArgument::Values::Zero,
+ [&](std::string const&) -> bool {
+ strip = true;
+ return true;
+ } },
+ CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda },
+ CommandArgument{ "--verbose", CommandArgument::Values::Zero,
+ verboseLambda }
+ };
+
+ if (ac >= 3) {
+ dir = cmSystemTools::CollapseFullPath(av[2]);
+
+ std::vector<std::string> inputArgs;
+ inputArgs.reserve(ac - 3);
+ cm::append(inputArgs, av + 3, av + ac);
+ for (decltype(inputArgs.size()) i = 0; i < inputArgs.size(); ++i) {
+
+ std::string const& arg = inputArgs[i];
+ for (auto const& m : arguments) {
+ if (m.matches(arg) && m.parse(arg, i, inputArgs)) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (dir.empty()) {
+ /* clang-format off */
+ std::cerr <<
+ "Usage: cmake --install <dir> [options]\n"
+ "Options:\n"
+ " <dir> = Project binary directory to install.\n"
+ " --config <cfg> = For multi-configuration tools, choose <cfg>.\n"
+ " --component <comp> = Component-based install. Only install <comp>.\n"
+ " --default-directory-permissions <permission> \n"
+ " Default install permission. Use default permission <permission>.\n"
+ " --prefix <prefix> = The installation prefix CMAKE_INSTALL_PREFIX.\n"
+ " --strip = Performing install/strip.\n"
+ " -v --verbose = Enable verbose output.\n"
+ ;
+ /* clang-format on */
+ return 1;
+ }
+
+ cmake cm(cmake::RoleScript, cmState::Script);
+
+ cmSystemTools::SetMessageCallback(
+ [&cm](const std::string& msg, const char* title) {
+ cmakemainMessageCallback(msg, title, &cm);
+ });
+ cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
+ cmakemainProgressCallback(msg, prog, &cm);
+ });
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.SetDebugOutputOn(verbose);
+ cm.SetWorkingMode(cmake::SCRIPT_MODE);
+
+ std::vector<std::string> args{ av[0] };
+
+ if (!prefix.empty()) {
+ args.emplace_back("-DCMAKE_INSTALL_PREFIX=" + prefix);
+ }
+
+ if (!component.empty()) {
+ args.emplace_back("-DCMAKE_INSTALL_COMPONENT=" + component);
+ }
+
+ if (strip) {
+ args.emplace_back("-DCMAKE_INSTALL_DO_STRIP=1");
+ }
+
+ if (!config.empty()) {
+ args.emplace_back("-DCMAKE_INSTALL_CONFIG_NAME=" + config);
+ }
+
+ if (!defaultDirectoryPermissions.empty()) {
+ std::string parsedPermissionsVar;
+ if (!parse_default_directory_permissions(defaultDirectoryPermissions,
+ parsedPermissionsVar)) {
+ std::cerr << "--default-directory-permissions is in incorrect format"
+ << std::endl;
+ return 1;
+ }
+ args.emplace_back("-DCMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS=" +
+ parsedPermissionsVar);
+ }
+
+ args.emplace_back("-P");
+ args.emplace_back(dir + "/cmake_install.cmake");
+
+ return cm.Run(args) ? 1 : 0;
+#endif
+}
+
+int do_open(int ac, char const* const* av)
+{
+#ifdef CMAKE_BOOTSTRAP
+ std::cerr << "This cmake does not support --open\n";
+ return -1;
+#else
+ std::string dir;
+
+ enum Doing
+ {
+ DoingNone,
+ DoingDir,
+ };
+ Doing doing = DoingDir;
+ for (int i = 2; i < ac; ++i) {
+ switch (doing) {
+ case DoingDir:
+ dir = cmSystemTools::CollapseFullPath(av[i]);
+ doing = DoingNone;
+ break;
+ default:
+ std::cerr << "Unknown argument " << av[i] << std::endl;
+ dir.clear();
+ break;
+ }
+ }
+ if (dir.empty()) {
+ std::cerr << "Usage: cmake --open <dir>\n";
+ return 1;
+ }
+
+ cmake cm(cmake::RoleInternal, cmState::Unknown);
+ cmSystemTools::SetMessageCallback(
+ [&cm](const std::string& msg, const char* title) {
+ cmakemainMessageCallback(msg, title, &cm);
+ });
+ cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
+ cmakemainProgressCallback(msg, prog, &cm);
+ });
+ return cm.Open(dir, false) ? 0 : 1;
+#endif
+}
+} // namespace
+
+int main(int ac, char const* const* av)
+{
+ cmSystemTools::EnsureStdPipes();
+
+ // Replace streambuf so we can output Unicode to console
+ auto consoleBuf = cm::make_unique<cmConsoleBuf>();
+ consoleBuf->SetUTF8Pipes();
+
+ cmsys::Encoding::CommandLineArguments args =
+ cmsys::Encoding::CommandLineArguments::Main(ac, av);
+ ac = args.argc();
+ av = args.argv();
+
+ cmSystemTools::InitializeLibUV();
+ cmSystemTools::FindCMakeResources(av[0]);
+ if (ac > 1) {
+ if (strcmp(av[1], "--build") == 0) {
+ return do_build(ac, av);
+ }
+ if (strcmp(av[1], "--install") == 0) {
+ return do_install(ac, av);
+ }
+ if (strcmp(av[1], "--open") == 0) {
+ return do_open(ac, av);
+ }
+ if (strcmp(av[1], "-E") == 0) {
+ return do_command(ac, av, std::move(consoleBuf));
+ }
+ }
+ int ret = do_cmake(ac, av);
+#ifndef CMAKE_BOOTSTRAP
+ cmDynamicLoader::FlushCache();
+#endif
+ if (uv_loop_t* loop = uv_default_loop()) {
+ uv_loop_close(loop);
+ }
+ return ret;
+}
diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx
new file mode 100644
index 0000000..5c27ac1
--- /dev/null
+++ b/Source/cmcldeps.cxx
@@ -0,0 +1,302 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Wrapper around cl that adds /showIncludes to command line, and uses that to
+// generate .d files that match the style from gcc -MD.
+//
+// /showIncludes is equivalent to -MD, not -MMD, that is, system headers are
+// included.
+
+#include <algorithm>
+#include <sstream>
+
+#include <windows.h>
+
+#include "cmsys/Encoding.hxx"
+
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+// We don't want any wildcard expansion.
+// See http://msdn.microsoft.com/en-us/library/zay8tzh6(v=vs.85).aspx
+void _setargv()
+{
+}
+
+static void Fatal(const char* msg, ...)
+{
+ va_list ap;
+ fprintf(stderr, "ninja: FATAL: ");
+ va_start(ap, msg);
+ vfprintf(stderr, msg, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ // On Windows, some tools may inject extra threads.
+ // exit() may block on locks held by those threads, so forcibly exit.
+ fflush(stderr);
+ fflush(stdout);
+ ExitProcess(1);
+}
+
+static void usage(const char* msg)
+{
+ Fatal("%s\n\nusage:\n "
+ "cmcldeps "
+ "<language C, CXX or RC> "
+ "<source file path> "
+ "<output path for *.d file> "
+ "<output path for *.obj file> "
+ "<prefix of /showIncludes> "
+ "<path to cl.exe> "
+ "<path to tool (cl or rc)> "
+ "<rest of command ...>\n",
+ msg);
+}
+
+static cm::string_view trimLeadingSpace(cm::string_view cmdline)
+{
+ int i = 0;
+ for (; cmdline[i] == ' '; ++i)
+ ;
+ return cmdline.substr(i);
+}
+
+static void replaceAll(std::string& str, const std::string& search,
+ const std::string& repl)
+{
+ std::string::size_type pos = 0;
+ while ((pos = str.find(search, pos)) != std::string::npos) {
+ str.replace(pos, search.size(), repl);
+ pos += repl.size();
+ }
+}
+
+// Strips one argument from the cmdline and returns it. "surrounding quotes"
+// are removed from the argument if there were any.
+static std::string getArg(std::string& cmdline)
+{
+ bool in_quoted = false;
+ unsigned int i = 0;
+
+ cm::string_view cmdview = trimLeadingSpace(cmdline);
+ size_t spaceCnt = cmdline.size() - cmdview.size();
+
+ for (;; ++i) {
+ if (i >= cmdview.size())
+ usage("Couldn't parse arguments.");
+ if (!in_quoted && cmdview[i] == ' ')
+ break; // "a b" "x y"
+ if (cmdview[i] == '"')
+ in_quoted = !in_quoted;
+ }
+
+ cmdview = cmdview.substr(0, i);
+ if (cmdview[0] == '"' && cmdview[i - 1] == '"')
+ cmdview = cmdview.substr(1, i - 2);
+ std::string ret(cmdview);
+ cmdline.erase(0, spaceCnt + i);
+ return ret;
+}
+
+static void parseCommandLine(LPWSTR wincmdline, std::string& lang,
+ std::string& srcfile, std::string& dfile,
+ std::string& objfile, std::string& prefix,
+ std::string& clpath, std::string& binpath,
+ std::string& rest)
+{
+ std::string cmdline = cmsys::Encoding::ToNarrow(wincmdline);
+ /* self */ getArg(cmdline);
+ lang = getArg(cmdline);
+ srcfile = getArg(cmdline);
+ dfile = getArg(cmdline);
+ objfile = getArg(cmdline);
+ prefix = getArg(cmdline);
+ clpath = getArg(cmdline);
+ binpath = getArg(cmdline);
+ rest = std::string(trimLeadingSpace(cmdline));
+}
+
+// Not all backslashes need to be escaped in a depfile, but it's easier that
+// way. See the re2c grammar in ninja's source code for more info.
+static void escapePath(std::string& path)
+{
+ replaceAll(path, "\\", "\\\\");
+ replaceAll(path, " ", "\\ ");
+}
+
+static void outputDepFile(const std::string& dfile, const std::string& objfile,
+ std::vector<std::string>& incs)
+{
+
+ if (dfile.empty())
+ return;
+
+ // strip duplicates
+ std::sort(incs.begin(), incs.end());
+ incs.erase(std::unique(incs.begin(), incs.end()), incs.end());
+
+ FILE* out = cmsys::SystemTools::Fopen(dfile.c_str(), "wb");
+
+ // FIXME should this be fatal or not? delete obj? delete d?
+ if (!out)
+ return;
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ replaceAll(cwd, "/", "\\");
+ cwd += "\\";
+
+ std::string tmp = objfile;
+ escapePath(tmp);
+ fprintf(out, "%s: \\\n", tmp.c_str());
+
+ std::vector<std::string>::iterator it = incs.begin();
+ for (; it != incs.end(); ++it) {
+ tmp = *it;
+ // The paths need to match the ones used to identify build artifacts in the
+ // build.ninja file. Therefore we need to canonicalize the path to use
+ // backward slashes and relativize the path to the build directory.
+ replaceAll(tmp, "/", "\\");
+ if (cmHasPrefix(tmp, cwd))
+ tmp.erase(0, cwd.size());
+ escapePath(tmp);
+ fprintf(out, "%s \\\n", tmp.c_str());
+ }
+
+ fprintf(out, "\n");
+ fclose(out);
+}
+
+bool contains(const std::string& str, const std::string& what)
+{
+ return str.find(what) != std::string::npos;
+}
+
+std::string replace(const std::string& str, const std::string& what,
+ const std::string& replacement)
+{
+ size_t pos = str.find(what);
+ if (pos == std::string::npos)
+ return str;
+ std::string replaced = str;
+ return replaced.replace(pos, what.size(), replacement);
+}
+
+static int process(cm::string_view srcfilename, const std::string& dfile,
+ const std::string& objfile, const std::string& prefix,
+ const std::string& cmd, const std::string& dir = "",
+ bool quiet = false)
+{
+ std::string output;
+ // break up command line into a vector
+ std::vector<std::string> args;
+ cmSystemTools::ParseWindowsCommandLine(cmd.c_str(), args);
+ // convert to correct vector type for RunSingleCommand
+ std::vector<std::string> command;
+ for (std::vector<std::string>::iterator i = args.begin(); i != args.end();
+ ++i) {
+ command.push_back(*i);
+ }
+ // run the command
+ int exit_code = 0;
+ bool run =
+ cmSystemTools::RunSingleCommand(command, &output, &output, &exit_code,
+ dir.c_str(), cmSystemTools::OUTPUT_NONE);
+
+ // process the include directives and output everything else
+ std::istringstream ss(output);
+ std::string line;
+ std::vector<std::string> includes;
+ bool isFirstLine = true; // cl prints always first the source filename
+ while (std::getline(ss, line)) {
+ cm::string_view inc(line);
+ if (cmHasPrefix(inc, prefix)) {
+ inc = trimLeadingSpace(inc.substr(prefix.size()));
+ if (inc.back() == '\r') // blech, stupid \r\n
+ inc = inc.substr(0, inc.size() - 1);
+ includes.emplace_back(std::string(inc));
+ } else {
+ if (!isFirstLine || !cmHasPrefix(inc, srcfilename)) {
+ if (!quiet || exit_code != 0) {
+ fprintf(stdout, "%s\n", line.c_str());
+ }
+ } else {
+ isFirstLine = false;
+ }
+ }
+ }
+
+ // don't update .d until/unless we succeed compilation
+ if (run && exit_code == 0)
+ outputDepFile(dfile, objfile, includes);
+
+ return exit_code;
+}
+
+int main()
+{
+
+ // Use the Win32 API instead of argc/argv so we can avoid interpreting the
+ // rest of command line after the .d and .obj. Custom parsing seemed
+ // preferable to the ugliness you get into in trying to re-escape quotes for
+ // subprocesses, so by avoiding argc/argv, the subprocess is called with
+ // the same command line verbatim.
+
+ std::string lang, srcfile, dfile, objfile, prefix, cl, binpath, rest;
+ parseCommandLine(GetCommandLineW(), lang, srcfile, dfile, objfile, prefix,
+ cl, binpath, rest);
+
+ // needed to suppress filename output of msvc tools
+ cm::string_view srcfilename(srcfile);
+ std::string::size_type pos = srcfile.rfind('\\');
+ if (pos != std::string::npos) {
+ srcfilename = srcfilename.substr(pos + 1);
+ }
+
+ std::string nol = " /nologo ";
+ std::string show = " /showIncludes ";
+ if (lang == "C" || lang == "CXX") {
+ return process(srcfilename, dfile, objfile, prefix,
+ binpath + nol + show + rest);
+ } else if (lang == "RC") {
+ // "misuse" cl.exe to get headers from .rc files
+
+ std::string clrest = rest;
+ // rc: /fo x.dir\x.rc.res -> cl: /out:x.dir\x.rc.res.dep.obj
+ clrest = replace(clrest, "/fo ", "/out:");
+ clrest = replace(clrest, objfile, objfile + ".dep.obj ");
+
+ cl = "\"" + cl + "\" /P /DRC_INVOKED /TC ";
+
+ // call cl in object dir so the .i is generated there
+ std::string objdir;
+ {
+ pos = objfile.rfind("\\");
+ if (pos != std::string::npos) {
+ objdir = objfile.substr(0, pos);
+ }
+ }
+
+ // extract dependencies with cl.exe
+ int exit_code = process(srcfilename, dfile, objfile, prefix,
+ cl + nol + show + clrest, objdir, true);
+
+ if (exit_code != 0)
+ return exit_code;
+
+ // compile rc file with rc.exe
+ return process(srcfilename, "", objfile, prefix, binpath + " " + rest);
+ }
+
+ usage("Invalid language specified.");
+ return 1;
+}
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
new file mode 100644
index 0000000..9ba4b93
--- /dev/null
+++ b/Source/cmcmd.cxx
@@ -0,0 +1,2412 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmcmd.h"
+
+#include <cmext/algorithm>
+
+#include <cm3p/uv.h>
+#include <fcntl.h>
+
+#include "cmConsoleBuf.h"
+#include "cmDuration.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmQtAutoMocUic.h"
+#include "cmQtAutoRcc.h"
+#include "cmRange.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTransformDepfile.h"
+#include "cmUVProcessChain.h"
+#include "cmUtils.hxx"
+#include "cmVersion.h"
+#include "cmake.h"
+
+#if !defined(CMAKE_BOOTSTRAP)
+# include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback.
+# include "cmFileTime.h"
+
+# include "bindexplib.h"
+#endif
+
+#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_MAKEFILES)
+# include <algorithm>
+
+# include "cmCMakePath.h"
+# include "cmProcessTools.h"
+#endif
+
+#if !defined(CMAKE_BOOTSTRAP) && defined(_WIN32) && !defined(__CYGWIN__)
+# include "cmVisualStudioWCEPlatformParser.h"
+#endif
+
+#include <array>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <utility>
+
+#ifdef _WIN32
+# include <fcntl.h> // for _O_BINARY
+# include <io.h> // for _setmode
+# include <stdio.h> // for std{out,err} and fileno
+#endif
+
+#include <cm/string_view>
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+#include "cmsys/Process.h"
+#include "cmsys/RegularExpression.hxx"
+#include "cmsys/Terminal.h"
+
+int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
+ std::vector<std::string>::const_iterator argEnd);
+int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
+ std::vector<std::string>::const_iterator argEnd);
+
+namespace {
+void CMakeCommandUsage(std::string const& program)
+{
+ std::ostringstream errorStream;
+
+#ifndef CMAKE_BOOTSTRAP
+ /* clang-format off */
+ errorStream
+ << "cmake version " << cmVersion::GetCMakeVersion() << "\n";
+/* clang-format on */
+#else
+ /* clang-format off */
+ errorStream
+ << "cmake bootstrap\n";
+/* clang-format on */
+#endif
+ // If you add new commands, change here,
+ // and in cmakemain.cxx in the options table
+ /* clang-format off */
+ errorStream
+ << "Usage: " << program << " -E <command> [arguments...]\n"
+ << "Available commands: \n"
+ << " capabilities - Report capabilities built into cmake "
+ "in JSON format\n"
+ << " cat <files>... - concat the files and print them to the standard output\n"
+ << " chdir dir cmd [args...] - run command in a given directory\n"
+ << " compare_files [--ignore-eol] file1 file2\n"
+ << " - check if file1 is same as file2\n"
+ << " copy <file>... destination - copy files to destination "
+ "(either file or directory)\n"
+ << " copy_directory <dir>... destination - copy content of <dir>... "
+ "directories to 'destination' directory\n"
+ << " copy_if_different <file>... destination - copy files if it has "
+ "changed\n"
+ << " echo [<string>...] - displays arguments as text\n"
+ << " echo_append [<string>...] - displays arguments as text but no new "
+ "line\n"
+ << " env [--unset=NAME]... [NAME=VALUE]... COMMAND [ARG]...\n"
+ << " - run command in a modified environment\n"
+ << " environment - display the current environment\n"
+ << " make_directory <dir>... - create parent and <dir> directories\n"
+ << " md5sum <file>... - create MD5 checksum of files\n"
+ << " sha1sum <file>... - create SHA1 checksum of files\n"
+ << " sha224sum <file>... - create SHA224 checksum of files\n"
+ << " sha256sum <file>... - create SHA256 checksum of files\n"
+ << " sha384sum <file>... - create SHA384 checksum of files\n"
+ << " sha512sum <file>... - create SHA512 checksum of files\n"
+ << " remove [-f] <file>... - remove the file(s), use -f to force "
+ "it (deprecated: use rm instead)\n"
+ << " remove_directory <dir>... - remove directories and their contents (deprecated: use rm instead)\n"
+ << " rename oldname newname - rename a file or directory "
+ "(on one volume)\n"
+ << " rm [-rRf] <file/dir>... - remove files or directories, use -f to "
+ "force it, r or R to remove directories and their contents recursively\n"
+ << " sleep <number>... - sleep for given number of seconds\n"
+ << " tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n"
+ << " - create or extract a tar or zip archive\n"
+ << " time command [args...] - run command and display elapsed time\n"
+ << " touch <file>... - touch a <file>.\n"
+ << " touch_nocreate <file>... - touch a <file> but do not create it.\n"
+ << " create_symlink old new - create a symbolic link new -> old\n"
+ << " create_hardlink old new - create a hard link new -> old\n"
+ << " true - do nothing with an exit code of 0\n"
+ << " false - do nothing with an exit code of 1\n"
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ << "Available on Windows only:\n"
+ << " delete_regv key - delete registry value\n"
+ << " env_vs8_wince sdkname - displays a batch file which sets the "
+ "environment for the provided Windows CE SDK installed in VS2005\n"
+ << " env_vs9_wince sdkname - displays a batch file which sets the "
+ "environment for the provided Windows CE SDK installed in VS2008\n"
+ << " write_regv key value - write registry value\n"
+#endif
+ ;
+ /* clang-format on */
+
+ cmSystemTools::Error(errorStream.str());
+}
+
+bool cmTarFilesFrom(std::string const& file, std::vector<std::string>& files)
+{
+ if (cmSystemTools::FileIsDirectory(file)) {
+ std::ostringstream e;
+ e << "-E tar --files-from= file '" << file << "' is a directory";
+ cmSystemTools::Error(e.str());
+ return false;
+ }
+ cmsys::ifstream fin(file.c_str());
+ if (!fin) {
+ std::ostringstream e;
+ e << "-E tar --files-from= file '" << file << "' not found";
+ cmSystemTools::Error(e.str());
+ return false;
+ }
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (line.empty()) {
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, "--add-file=")) {
+ files.push_back(line.substr(11));
+ } else if (cmHasLiteralPrefix(line, "-")) {
+ std::ostringstream e;
+ e << "-E tar --files-from='" << file << "' file invalid line:\n"
+ << line << "\n";
+ cmSystemTools::Error(e.str());
+ return false;
+ } else {
+ files.push_back(line);
+ }
+ }
+ return true;
+}
+
+void cmCatFile(const std::string& fileToAppend)
+{
+#ifdef _WIN32
+ _setmode(fileno(stdout), _O_BINARY);
+#endif
+ cmsys::ifstream source(fileToAppend.c_str(),
+ (std::ios::binary | std::ios::in));
+ std::cout << source.rdbuf();
+}
+
+bool cmRemoveDirectory(const std::string& dir, bool recursive = true)
+{
+ if (cmSystemTools::FileIsSymlink(dir)) {
+ if (!cmSystemTools::RemoveFile(dir)) {
+ std::cerr << "Error removing directory symlink \"" << dir << "\".\n";
+ return false;
+ }
+ } else if (!recursive) {
+ std::cerr << "Error removing directory \"" << dir
+ << "\" without recursive option.\n";
+ return false;
+ } else if (!cmSystemTools::RemoveADirectory(dir)) {
+ std::cerr << "Error removing directory \"" << dir << "\".\n";
+ return false;
+ }
+ return true;
+}
+
+#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_MAKEFILES)
+class CLIncludeParser : public cmProcessTools::LineParser
+{
+public:
+ CLIncludeParser(cm::string_view includePrefix, cmsys::ofstream& depFile,
+ std::ostream& output)
+ : IncludePrefix(includePrefix)
+ , DepFile(depFile)
+ , Output(output)
+ {
+ }
+
+private:
+ bool ProcessLine() override
+ {
+ if (cmHasPrefix(this->Line, this->IncludePrefix)) {
+ auto path =
+ cmTrimWhitespace(this->Line.c_str() + this->IncludePrefix.size());
+ cmSystemTools::ConvertToLongPath(path);
+ this->DepFile << cmCMakePath(path).GenericString() << std::endl;
+ } else {
+ this->Output << this->Line << std::endl << std::flush;
+ }
+
+ return true;
+ }
+
+ cm::string_view IncludePrefix;
+ cmsys::ofstream& DepFile;
+ std::ostream& Output;
+};
+
+class CLOutputLogger : public cmProcessTools::OutputLogger
+{
+public:
+ CLOutputLogger(std::ostream& log)
+ : cmProcessTools::OutputLogger(log)
+ {
+ }
+
+ bool ProcessLine() override
+ {
+ *this->Log << std::flush;
+ return true;
+ }
+};
+
+int CLCompileAndDependencies(const std::vector<std::string>& args)
+{
+ std::string depFile;
+ std::string currentBinaryDir;
+ std::string filterPrefix;
+ std::vector<std::string> command;
+ for (auto it = args.cbegin() + 2; it != args.cend(); it++) {
+ if (cmHasLiteralPrefix(*it, "--dep-file=")) {
+ depFile = it->substr(11);
+ } else if (cmHasLiteralPrefix(*it, "--working-dir=")) {
+ currentBinaryDir = it->substr(14);
+ } else if (cmHasLiteralPrefix(*it, "--filter-prefix=")) {
+ filterPrefix = it->substr(16);
+ } else if (*it == "--") {
+ command.insert(command.begin(), ++it, args.cend());
+ break;
+ } else {
+ return 1;
+ }
+ }
+
+ std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp(
+ cmsysProcess_New(), cmsysProcess_Delete);
+ std::vector<const char*> argv(command.size() + 1);
+ std::transform(command.begin(), command.end(), argv.begin(),
+ [](std::string const& s) { return s.c_str(); });
+ argv.back() = nullptr;
+ cmsysProcess_SetCommand(cp.get(), argv.data());
+ cmsysProcess_SetWorkingDirectory(cp.get(), currentBinaryDir.c_str());
+
+ cmsys::ofstream fout(depFile.c_str());
+ if (!fout) {
+ return 3;
+ }
+
+ CLIncludeParser includeParser(filterPrefix, fout, std::cout);
+ CLOutputLogger errLogger(std::cerr);
+
+ // Start the process.
+ cmProcessTools::RunProcess(cp.get(), &includeParser, &errLogger);
+
+ int status = 0;
+ // handle status of process
+ switch (cmsysProcess_GetState(cp.get())) {
+ case cmsysProcess_State_Exited:
+ status = cmsysProcess_GetExitValue(cp.get());
+ break;
+ case cmsysProcess_State_Exception:
+ status = 1;
+ break;
+ case cmsysProcess_State_Error:
+ status = 2;
+ break;
+ default:
+ break;
+ }
+
+ if (status != 0) {
+ // remove the dependencies file because potentially invalid
+ fout.close();
+ cmSystemTools::RemoveFile(depFile);
+ }
+
+ return status;
+}
+#endif
+
+int HandleIWYU(const std::string& runCmd, const std::string& /* sourceFile */,
+ const std::vector<std::string>& orig_cmd)
+{
+ // Construct the iwyu command line by taking what was given
+ // and adding all the arguments we give to the compiler.
+ std::vector<std::string> iwyu_cmd = cmExpandedList(runCmd, true);
+ cm::append(iwyu_cmd, orig_cmd.begin() + 1, orig_cmd.end());
+ // Run the iwyu command line. Capture its stderr and hide its stdout.
+ // Ignore its return code because the tool always returns non-zero.
+ std::string stdErr;
+ int ret;
+ if (!cmSystemTools::RunSingleCommand(iwyu_cmd, nullptr, &stdErr, &ret,
+ nullptr, cmSystemTools::OUTPUT_NONE)) {
+ std::cerr << "Error running '" << iwyu_cmd[0] << "': " << stdErr << "\n";
+ return 1;
+ }
+ // Warn if iwyu reported anything.
+ if (stdErr.find("should remove these lines:") != std::string::npos ||
+ stdErr.find("should add these lines:") != std::string::npos) {
+ std::cerr << "Warning: include-what-you-use reported diagnostics:\n"
+ << stdErr << "\n";
+ }
+ // always return 0 we don't want to break the compile
+ return 0;
+}
+
+int HandleTidy(const std::string& runCmd, const std::string& sourceFile,
+ const std::vector<std::string>& orig_cmd)
+{
+ // Construct the clang-tidy command line by taking what was given
+ // and adding our compiler command line. The clang-tidy tool will
+ // automatically skip over the compiler itself and extract the
+ // options.
+ int ret;
+ std::vector<std::string> tidy_cmd = cmExpandedList(runCmd, true);
+ tidy_cmd.push_back(sourceFile);
+ tidy_cmd.emplace_back("--");
+ cm::append(tidy_cmd, orig_cmd);
+
+ // Run the tidy command line. Capture its stdout and hide its stderr.
+ std::string stdOut;
+ std::string stdErr;
+ if (!cmSystemTools::RunSingleCommand(tidy_cmd, &stdOut, &stdErr, &ret,
+ nullptr, cmSystemTools::OUTPUT_NONE)) {
+ std::cerr << "Error running '" << tidy_cmd[0] << "': " << stdErr << "\n";
+ return 1;
+ }
+ // Output the stdout from clang-tidy to stderr
+ std::cerr << stdOut;
+ // If clang-tidy exited with an error do the same.
+ if (ret != 0) {
+ std::cerr << stdErr;
+ }
+ return ret;
+}
+
+int HandleLWYU(const std::string& runCmd, const std::string& /* sourceFile */,
+ const std::vector<std::string>&)
+{
+ // Construct the ldd -r -u (link what you use lwyu) command line
+ // ldd -u -r lwuy target
+ std::vector<std::string> lwyu_cmd;
+ lwyu_cmd.emplace_back("ldd");
+ lwyu_cmd.emplace_back("-u");
+ lwyu_cmd.emplace_back("-r");
+ lwyu_cmd.push_back(runCmd);
+
+ // Run the ldd -u -r command line.
+ // Capture its stdout and hide its stderr.
+ // Ignore its return code because the tool always returns non-zero
+ // if there are any warnings, but we just want to warn.
+ std::string stdOut;
+ std::string stdErr;
+ int ret;
+ if (!cmSystemTools::RunSingleCommand(lwyu_cmd, &stdOut, &stdErr, &ret,
+ nullptr, cmSystemTools::OUTPUT_NONE)) {
+ std::cerr << "Error running '" << lwyu_cmd[0] << "': " << stdErr << "\n";
+ return 1;
+ }
+
+ // Output the stdout from ldd -r -u to stderr
+ // Warn if lwyu reported anything.
+ if (stdOut.find("Unused direct dependencies:") != std::string::npos) {
+ std::cerr << "Warning: " << stdOut;
+ }
+ return 0;
+}
+
+int HandleCppLint(const std::string& runCmd, const std::string& sourceFile,
+ const std::vector<std::string>&)
+{
+ // Construct the cpplint command line.
+ std::vector<std::string> cpplint_cmd = cmExpandedList(runCmd, true);
+ cpplint_cmd.push_back(sourceFile);
+
+ // Run the cpplint command line. Capture its output.
+ std::string stdOut;
+ int ret;
+ if (!cmSystemTools::RunSingleCommand(cpplint_cmd, &stdOut, &stdOut, &ret,
+ nullptr, cmSystemTools::OUTPUT_NONE)) {
+ std::cerr << "Error running '" << cpplint_cmd[0] << "': " << stdOut
+ << "\n";
+ return 1;
+ }
+ if (!stdOut.empty()) {
+ std::cerr << "Warning: cpplint diagnostics:\n";
+ // Output the output from cpplint to stderr
+ std::cerr << stdOut;
+ }
+
+ // always return 0 so the build can continue as cpplint returns non-zero
+ // for any warning
+ return 0;
+}
+
+int HandleCppCheck(const std::string& runCmd, const std::string& sourceFile,
+ const std::vector<std::string>& orig_cmd)
+{
+ // Construct the cpplint command line.
+ std::vector<std::string> cppcheck_cmd = cmExpandedList(runCmd, true);
+ // extract all the -D, -U, and -I options from the compile line
+ for (auto const& opt : orig_cmd) {
+ if (opt.size() > 2) {
+ if ((opt[0] == '-') &&
+ ((opt[1] == 'D') || (opt[1] == 'I') || (opt[1] == 'U'))) {
+ cppcheck_cmd.push_back(opt);
+// convert cl / options to - options if needed
+#if defined(_WIN32)
+ } else if ((opt[0] == '/') &&
+ ((opt[1] == 'D') || (opt[1] == 'I') || (opt[1] == 'U'))) {
+ std::string optcopy = opt;
+ optcopy[0] = '-';
+ cppcheck_cmd.push_back(optcopy);
+#endif
+ }
+ }
+ }
+ // add the source file
+ cppcheck_cmd.push_back(sourceFile);
+
+ // Run the cpplint command line. Capture its output.
+ std::string stdOut;
+ std::string stdErr;
+ int ret;
+ if (!cmSystemTools::RunSingleCommand(cppcheck_cmd, &stdOut, &stdErr, &ret,
+ nullptr, cmSystemTools::OUTPUT_NONE)) {
+ std::cerr << "Error running '" << cppcheck_cmd[0] << "': " << stdOut
+ << "\n";
+ return 1;
+ }
+ std::cerr << stdOut;
+ // Output the output from cpplint to stderr
+ if (stdErr.find("(error)") != std::string::npos ||
+ stdErr.find("(warning)") != std::string::npos ||
+ stdErr.find("(style)") != std::string::npos ||
+ stdErr.find("(performance)") != std::string::npos ||
+ stdErr.find("(portability)") != std::string::npos ||
+ stdErr.find("(information)") != std::string::npos) {
+ if (ret == 0) {
+ std::cerr << "Warning: cppcheck reported diagnostics:\n";
+ } else {
+ std::cerr << "Error: cppcheck reported failure:\n";
+ }
+ }
+ std::cerr << stdErr;
+
+ return ret;
+}
+
+using CoCompileHandler = int (*)(const std::string&, const std::string&,
+ const std::vector<std::string>&);
+
+struct CoCompiler
+{
+ const char* Option;
+ CoCompileHandler Handler;
+ bool NoOriginalCommand;
+};
+
+const std::array<CoCompiler, 5> CoCompilers = {
+ { // Table of options and handlers.
+ { "--cppcheck=", HandleCppCheck, false },
+ { "--cpplint=", HandleCppLint, false },
+ { "--iwyu=", HandleIWYU, false },
+ { "--lwyu=", HandleLWYU, true },
+ { "--tidy=", HandleTidy, false } }
+};
+
+struct CoCompileJob
+{
+ std::string Command;
+ CoCompileHandler Handler;
+};
+}
+
+// called when args[0] == "__run_co_compile"
+int cmcmd::HandleCoCompileCommands(std::vector<std::string> const& args)
+{
+ std::vector<CoCompileJob> jobs;
+ std::string sourceFile; // store --source=
+ std::vector<std::string> launchers; // store --launcher=
+
+ // Default is to run the original command found after -- if the option
+ // does not need to do that, it should be specified here, currently only
+ // lwyu does that.
+ bool runOriginalCmd = true;
+
+ std::vector<std::string> orig_cmd;
+ bool doing_options = true;
+ for (std::string const& arg : cmMakeRange(args).advance(2)) {
+ // if the arg is -- then the rest of the args after
+ // go into orig_cmd
+ if (arg == "--") {
+ doing_options = false;
+ } else if (doing_options) {
+ bool optionFound = false;
+ for (CoCompiler const& cc : CoCompilers) {
+ size_t optionLen = strlen(cc.Option);
+ if (arg.compare(0, optionLen, cc.Option) == 0) {
+ optionFound = true;
+ CoCompileJob job;
+ job.Command = arg.substr(optionLen);
+ job.Handler = cc.Handler;
+ jobs.push_back(std::move(job));
+ if (cc.NoOriginalCommand) {
+ runOriginalCmd = false;
+ }
+ }
+ }
+ if (!optionFound) {
+ if (cmHasLiteralPrefix(arg, "--source=")) {
+ sourceFile = arg.substr(9);
+ } else if (cmHasLiteralPrefix(arg, "--launcher=")) {
+ cmExpandList(arg.substr(11), launchers, true);
+ } else {
+ // if it was not a co-compiler or --source/--launcher then error
+ std::cerr << "__run_co_compile given unknown argument: " << arg
+ << "\n";
+ return 1;
+ }
+ }
+ } else { // if not doing_options then push to orig_cmd
+ orig_cmd.push_back(arg);
+ }
+ }
+ if (jobs.empty()) {
+ std::cerr << "__run_co_compile missing command to run. "
+ "Looking for one or more of the following:\n";
+ for (CoCompiler const& cc : CoCompilers) {
+ std::cerr << cc.Option << "\n";
+ }
+ return 1;
+ }
+
+ if (runOriginalCmd && orig_cmd.empty()) {
+ std::cerr << "__run_co_compile missing compile command after --\n";
+ return 1;
+ }
+
+ for (CoCompileJob const& job : jobs) {
+ // call the command handler here
+ int ret = job.Handler(job.Command, sourceFile, orig_cmd);
+
+ // if the command returns non-zero then return and fail.
+ // for commands that do not want to break the build, they should return
+ // 0 no matter what.
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ // if there is no original command to run return now
+ if (!runOriginalCmd) {
+ return 0;
+ }
+
+ // Prepend launcher argument(s), if any
+ if (!launchers.empty()) {
+ orig_cmd.insert(orig_cmd.begin(), launchers.begin(), launchers.end());
+ }
+
+ // Now run the real compiler command and return its result value
+ int ret;
+ if (!cmSystemTools::RunSingleCommand(orig_cmd, nullptr, nullptr, &ret,
+ nullptr,
+ cmSystemTools::OUTPUT_PASSTHROUGH)) {
+ std::cerr << "Error running '" << orig_cmd[0] << "'\n";
+ return 1;
+ }
+ // return the return value from the original compiler command
+ return ret;
+}
+
+int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
+ std::unique_ptr<cmConsoleBuf> consoleBuf)
+{
+ // IF YOU ADD A NEW COMMAND, DOCUMENT IT ABOVE and in cmakemain.cxx
+ if (args.size() > 1) {
+ // Copy file
+ if (args[1] == "copy" && args.size() > 3) {
+ // If multiple source files specified,
+ // then destination must be directory
+ if ((args.size() > 4) &&
+ (!cmSystemTools::FileIsDirectory(args.back()))) {
+ std::cerr << "Error: Target (for copy command) \"" << args.back()
+ << "\" is not a directory.\n";
+ return 1;
+ }
+ // If error occurs we want to continue copying next files.
+ bool return_value = false;
+ for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
+ if (!cmsys::SystemTools::CopyFileAlways(arg, args.back())) {
+ std::cerr << "Error copying file \"" << arg << "\" to \""
+ << args.back() << "\".\n";
+ return_value = true;
+ }
+ }
+ return return_value;
+ }
+
+ // Copy file if different.
+ if (args[1] == "copy_if_different" && args.size() > 3) {
+ // If multiple source files specified,
+ // then destination must be directory
+ if ((args.size() > 4) &&
+ (!cmSystemTools::FileIsDirectory(args.back()))) {
+ std::cerr << "Error: Target (for copy_if_different command) \""
+ << args.back() << "\" is not a directory.\n";
+ return 1;
+ }
+ // If error occurs we want to continue copying next files.
+ bool return_value = false;
+ for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
+ if (!cmSystemTools::CopyFileIfDifferent(arg, args.back())) {
+ std::cerr << "Error copying file (if different) from \"" << arg
+ << "\" to \"" << args.back() << "\".\n";
+ return_value = true;
+ }
+ }
+ return return_value;
+ }
+
+ // Copy directory content
+ if (args[1] == "copy_directory" && args.size() > 3) {
+ // If error occurs we want to continue copying next files.
+ bool return_value = false;
+ for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
+ if (!cmSystemTools::CopyADirectory(arg, args.back())) {
+ std::cerr << "Error copying directory from \"" << arg << "\" to \""
+ << args.back() << "\".\n";
+ return_value = true;
+ }
+ }
+ return return_value;
+ }
+
+ // Rename a file or directory
+ if (args[1] == "rename" && args.size() == 4) {
+ if (!cmSystemTools::RenameFile(args[2], args[3])) {
+ std::string e = cmSystemTools::GetLastSystemError();
+ std::cerr << "Error renaming from \"" << args[2] << "\" to \""
+ << args[3] << "\": " << e << "\n";
+ return 1;
+ }
+ return 0;
+ }
+
+ // Compare files
+ if (args[1] == "compare_files" && (args.size() == 4 || args.size() == 5)) {
+ bool filesDiffer;
+ if (args.size() == 4) {
+ filesDiffer = cmSystemTools::FilesDiffer(args[2], args[3]);
+ } else if (args[2] == "--ignore-eol") {
+ filesDiffer = cmsys::SystemTools::TextFilesDiffer(args[3], args[4]);
+ } else {
+ CMakeCommandUsage(args[0]);
+ return 2;
+ }
+
+ if (filesDiffer) {
+ return 1;
+ }
+ return 0;
+ }
+
+#if !defined(CMAKE_BOOTSTRAP)
+ if (args[1] == "__create_def") {
+ if (args.size() < 4) {
+ std::cerr << "__create_def Usage: -E __create_def outfile.def "
+ "objlistfile [--nm=nm-path]\n";
+ return 1;
+ }
+ cmsys::ifstream fin(args[3].c_str(), std::ios::in | std::ios::binary);
+ if (!fin) {
+ std::cerr << "could not open object list file: " << args[3] << "\n";
+ return 1;
+ }
+ std::vector<std::string> files;
+ {
+ std::string file;
+ cmFileTime outTime;
+ bool outValid = outTime.Load(args[2]);
+ while (cmSystemTools::GetLineFromStream(fin, file)) {
+ files.push_back(file);
+ if (outValid) {
+ cmFileTime inTime;
+ outValid = inTime.Load(file) && inTime.Older(outTime);
+ }
+ }
+ if (outValid) {
+ // The def file already exists and all input files are older than
+ // the existing def file.
+ return 0;
+ }
+ }
+ FILE* fout = cmsys::SystemTools::Fopen(args[2], "w+");
+ if (!fout) {
+ std::cerr << "could not open output .def file: " << args[2] << "\n";
+ return 1;
+ }
+ bindexplib deffile;
+ if (args.size() >= 5) {
+ std::string const& a = args[4];
+ if (cmHasLiteralPrefix(a, "--nm=")) {
+ deffile.SetNmPath(a.substr(5));
+ } else {
+ std::cerr << "unknown argument: " << a << "\n";
+ }
+ }
+ for (std::string const& file : files) {
+ std::string const& ext = cmSystemTools::GetFilenameLastExtension(file);
+ if (cmSystemTools::LowerCase(ext) == ".def") {
+ if (!deffile.AddDefinitionFile(file.c_str())) {
+ return 1;
+ }
+ } else {
+ if (!deffile.AddObjectFile(file.c_str())) {
+ return 1;
+ }
+ }
+ }
+ deffile.WriteFile(fout);
+ fclose(fout);
+ return 0;
+ }
+#endif
+ if (args[1] == "__run_co_compile") {
+ return cmcmd::HandleCoCompileCommands(args);
+ }
+
+ // Echo string
+ if (args[1] == "echo") {
+ std::cout << cmJoin(cmMakeRange(args).advance(2), " ") << std::endl;
+ return 0;
+ }
+
+ // Echo string no new line
+ if (args[1] == "echo_append") {
+ std::cout << cmJoin(cmMakeRange(args).advance(2), " ");
+ return 0;
+ }
+
+ if (args[1] == "env") {
+ auto ai = args.cbegin() + 2;
+ auto ae = args.cend();
+ for (; ai != ae; ++ai) {
+ std::string const& a = *ai;
+ if (cmHasLiteralPrefix(a, "--unset=")) {
+ // Unset environment variable.
+ cmSystemTools::UnPutEnv(a.substr(8));
+ } else if (!a.empty() && a[0] == '-') {
+ // Environment variable and command names cannot start in '-',
+ // so this must be an unknown option.
+ std::cerr << "cmake -E env: unknown option '" << a << '\''
+ << std::endl;
+ return 1;
+ } else if (a.find('=') != std::string::npos) {
+ // Set environment variable.
+ cmSystemTools::PutEnv(a);
+ } else {
+ // This is the beginning of the command.
+ break;
+ }
+ }
+
+ if (ai == ae) {
+ std::cerr << "cmake -E env: no command given" << std::endl;
+ return 1;
+ }
+
+ // Execute command from remaining arguments.
+ std::vector<std::string> cmd(ai, ae);
+ int retval;
+ if (cmSystemTools::RunSingleCommand(cmd, nullptr, nullptr, &retval,
+ nullptr,
+ cmSystemTools::OUTPUT_PASSTHROUGH)) {
+ return retval;
+ }
+ return 1;
+ }
+
+#if !defined(CMAKE_BOOTSTRAP)
+ if (args[1] == "environment") {
+ for (auto const& env : cmSystemTools::GetEnvironmentVariables()) {
+ std::cout << env << std::endl;
+ }
+ return 0;
+ }
+#endif
+
+ if (args[1] == "make_directory" && args.size() > 2) {
+ // If an error occurs, we want to continue making directories.
+ bool return_value = false;
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (!cmSystemTools::MakeDirectory(arg)) {
+ std::cerr << "Error creating directory \"" << arg << "\".\n";
+ return_value = true;
+ }
+ }
+ return return_value;
+ }
+
+ if (args[1] == "remove_directory" && args.size() > 2) {
+ // If an error occurs, we want to continue removing directories.
+ bool return_value = false;
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (cmSystemTools::FileIsDirectory(arg)) {
+ if (!cmRemoveDirectory(arg)) {
+ return_value = true;
+ }
+ }
+ }
+ return return_value;
+ }
+
+ // Remove file
+ if (args[1] == "remove" && args.size() > 2) {
+ bool force = false;
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (arg == "\\-f" || arg == "-f") {
+ force = true;
+ } else {
+ // Complain if the file could not be removed, still exists,
+ // and the -f option was not given.
+ if (!cmSystemTools::RemoveFile(arg) && !force &&
+ cmSystemTools::FileExists(arg)) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+ }
+
+ // Remove directories or files with rm
+ if (args[1] == "rm" && args.size() > 2) {
+ // If an error occurs, we want to continue removing the remaining
+ // files/directories.
+ int return_value = 0;
+ bool force = false;
+ bool recursive = false;
+ bool doing_options = true;
+ bool at_least_one_file = false;
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (doing_options && cmHasLiteralPrefix(arg, "-")) {
+ if (arg == "--") {
+ doing_options = false;
+ }
+ if (arg.find('f') != std::string::npos) {
+ force = true;
+ }
+ if (arg.find_first_of("rR") != std::string::npos) {
+ recursive = true;
+ }
+ if (arg.find_first_not_of("-frR") != std::string::npos) {
+ cmSystemTools::Error("Unknown -E rm argument: " + arg);
+ return 1;
+ }
+ } else {
+ if (arg.empty()) {
+ continue;
+ }
+ at_least_one_file = true;
+ // Complain if the -f option was not given and
+ // either file does not exist or
+ // file could not be removed and still exists
+ bool file_exists_or_forced_remove = cmSystemTools::FileExists(arg) ||
+ cmSystemTools::FileIsSymlink(arg) || force;
+ if (cmSystemTools::FileIsDirectory(arg)) {
+ if (!cmRemoveDirectory(arg, recursive)) {
+ return_value = 1;
+ }
+ } else if ((!file_exists_or_forced_remove) ||
+ (!cmSystemTools::RemoveFile(arg) &&
+ cmSystemTools::FileExists(arg))) {
+ if (!file_exists_or_forced_remove) {
+ cmSystemTools::Error(
+ "File to remove does not exist and force is not set: " + arg);
+ } else {
+ cmSystemTools::Error("File can't be removed and still exist: " +
+ arg);
+ }
+ return_value = 1;
+ }
+ }
+ }
+ if (!at_least_one_file) {
+ cmSystemTools::Error("Missing file/directory to remove");
+ return 1;
+ }
+ return return_value;
+ }
+
+ // Touch file
+ if (args[1] == "touch" && args.size() > 2) {
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (!cmSystemTools::Touch(arg, true)) {
+ std::cerr << "cmake -E touch: failed to update \"";
+ std::cerr << arg << "\".\n";
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ // Touch file
+ if (args[1] == "touch_nocreate" && args.size() > 2) {
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (!cmSystemTools::Touch(arg, false)) {
+ std::cerr << "cmake -E touch_nocreate: failed to update \"";
+ std::cerr << arg << "\".\n";
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ // capabilities
+ if (args[1] == "capabilities") {
+ if (args.size() > 2) {
+ std::cerr << "-E capabilities accepts no additional arguments\n";
+ return 1;
+ }
+ cmake cm(cmake::RoleInternal, cmState::Unknown);
+ std::cout << cm.ReportCapabilities();
+ return 0;
+ }
+
+ // Sleep command
+ if (args[1] == "sleep" && args.size() > 2) {
+ double total = 0;
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ double num = 0.0;
+ char unit;
+ char extra;
+ int n = sscanf(arg.c_str(), "%lg%c%c", &num, &unit, &extra);
+ if ((n == 1 || (n == 2 && unit == 's')) && num >= 0) {
+ total += num;
+ } else {
+ std::cerr << "Unknown sleep time format \"" << arg << "\".\n";
+ return 1;
+ }
+ }
+ if (total > 0) {
+ cmSystemTools::Delay(static_cast<unsigned int>(total * 1000));
+ }
+ return 0;
+ }
+
+ // Clock command
+ if (args[1] == "time" && args.size() > 2) {
+ std::vector<std::string> command(args.begin() + 2, args.end());
+
+ clock_t clock_start;
+ clock_t clock_finish;
+ time_t time_start;
+ time_t time_finish;
+
+ time(&time_start);
+ clock_start = clock();
+ int ret = 0;
+ cmSystemTools::RunSingleCommand(command, nullptr, nullptr, &ret);
+
+ clock_finish = clock();
+ time(&time_finish);
+
+ double clocks_per_sec = static_cast<double>(CLOCKS_PER_SEC);
+ std::cout << "Elapsed time: "
+ << static_cast<long>(time_finish - time_start) << " s. (time)"
+ << ", "
+ << static_cast<double>(clock_finish - clock_start) /
+ clocks_per_sec
+ << " s. (clock)"
+ << "\n";
+ return ret;
+ }
+
+ // Command to calculate the md5sum of a file
+ if (args[1] == "md5sum" && args.size() >= 3) {
+ return HashSumFile(args, cmCryptoHash::AlgoMD5);
+ }
+
+ // Command to calculate the sha1sum of a file
+ if (args[1] == "sha1sum" && args.size() >= 3) {
+ return HashSumFile(args, cmCryptoHash::AlgoSHA1);
+ }
+
+ if (args[1] == "sha224sum" && args.size() >= 3) {
+ return HashSumFile(args, cmCryptoHash::AlgoSHA224);
+ }
+
+ if (args[1] == "sha256sum" && args.size() >= 3) {
+ return HashSumFile(args, cmCryptoHash::AlgoSHA256);
+ }
+
+ if (args[1] == "sha384sum" && args.size() >= 3) {
+ return HashSumFile(args, cmCryptoHash::AlgoSHA384);
+ }
+
+ if (args[1] == "sha512sum" && args.size() >= 3) {
+ return HashSumFile(args, cmCryptoHash::AlgoSHA512);
+ }
+
+ // Command to concat files into one
+ if (args[1] == "cat" && args.size() >= 3) {
+ int return_value = 0;
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (cmHasLiteralPrefix(arg, "-")) {
+ if (arg != "--") {
+ cmSystemTools::Error(arg + ": option not handled");
+ return_value = 1;
+ }
+ } else if (!cmSystemTools::TestFileAccess(arg,
+ cmsys::TEST_FILE_READ) &&
+ cmSystemTools::TestFileAccess(arg, cmsys::TEST_FILE_OK)) {
+ cmSystemTools::Error(arg + ": permission denied (ignoring)");
+ return_value = 1;
+ } else if (cmSystemTools::FileIsDirectory(arg)) {
+ cmSystemTools::Error(arg + ": is a directory (ignoring)");
+ return_value = 1;
+ } else if (!cmSystemTools::FileExists(arg)) {
+ cmSystemTools::Error(arg + ": no such file or directory (ignoring)");
+ return_value = 1;
+ } else {
+ // Destroy console buffers to drop cout/cerr encoding transform.
+ consoleBuf.reset();
+ cmCatFile(arg);
+ }
+ }
+ return return_value;
+ }
+
+ // Command to change directory and run a program.
+ if (args[1] == "chdir" && args.size() >= 4) {
+ std::string const& directory = args[2];
+ if (!cmSystemTools::FileExists(directory)) {
+ cmSystemTools::Error("Directory does not exist for chdir command: " +
+ directory);
+ return 1;
+ }
+
+ std::string command =
+ cmWrap('"', cmMakeRange(args).advance(3), '"', " ");
+ int retval = 0;
+ if (cmSystemTools::RunSingleCommand(
+ command, nullptr, nullptr, &retval, directory.c_str(),
+ cmSystemTools::OUTPUT_PASSTHROUGH, cmDuration::zero())) {
+ return retval;
+ }
+
+ return 1;
+ }
+
+ // Command to start progress for a build
+ if (args[1] == "cmake_progress_start" && args.size() == 4) {
+ // basically remove the directory
+ std::string dirName = cmStrCat(args[2], "/Progress");
+ cmSystemTools::RemoveADirectory(dirName);
+
+ // is the last argument a filename that exists?
+ FILE* countFile = cmsys::SystemTools::Fopen(args[3], "r");
+ int count;
+ if (countFile) {
+ if (1 != fscanf(countFile, "%i", &count)) {
+ cmSystemTools::Message("Could not read from count file.");
+ }
+ fclose(countFile);
+ } else {
+ count = atoi(args[3].c_str());
+ }
+ if (count) {
+ cmSystemTools::MakeDirectory(dirName);
+ // write the count into the directory
+ std::string fName = cmStrCat(dirName, "/count.txt");
+ FILE* progFile = cmsys::SystemTools::Fopen(fName, "w");
+ if (progFile) {
+ fprintf(progFile, "%i\n", count);
+ fclose(progFile);
+ }
+ }
+ return 0;
+ }
+
+ // Command to report progress for a build
+ if (args[1] == "cmake_progress_report" && args.size() >= 3) {
+ // This has been superseded by cmake_echo_color --progress-*
+ // options. We leave it here to avoid errors if somehow this
+ // is invoked by an existing makefile without regenerating.
+ return 0;
+ }
+
+ // Command to create a symbolic link. Fails on platforms not
+ // supporting them.
+ if (args[1] == "create_symlink" && args.size() == 4) {
+ std::string const& destinationFileName = args[3];
+ if ((cmSystemTools::FileExists(destinationFileName) ||
+ cmSystemTools::FileIsSymlink(destinationFileName)) &&
+ !cmSystemTools::RemoveFile(destinationFileName)) {
+ std::string emsg = cmSystemTools::GetLastSystemError();
+ std::cerr << "failed to create symbolic link '" << destinationFileName
+ << "' because existing path cannot be removed: " << emsg
+ << "\n";
+ return 1;
+ }
+ if (!cmSystemTools::CreateSymlink(args[2], destinationFileName)) {
+ return 1;
+ }
+ return 0;
+ }
+
+ // Command to create a hard link. Fails on platforms not
+ // supporting them.
+ if (args[1] == "create_hardlink" && args.size() == 4) {
+ std::string const& sourceFileName = args[2];
+ std::string const& destinationFileName = args[3];
+
+ if (!cmSystemTools::FileExists(sourceFileName)) {
+ std::cerr << "failed to create hard link because source path '"
+ << sourceFileName << "' does not exist \n";
+ return 1;
+ }
+
+ if ((cmSystemTools::FileExists(destinationFileName) ||
+ cmSystemTools::FileIsSymlink(destinationFileName)) &&
+ !cmSystemTools::RemoveFile(destinationFileName)) {
+ std::string emsg = cmSystemTools::GetLastSystemError();
+ std::cerr << "failed to create hard link '" << destinationFileName
+ << "' because existing path cannot be removed: " << emsg
+ << "\n";
+ return 1;
+ }
+
+ if (!cmSystemTools::CreateLink(sourceFileName, destinationFileName)) {
+ return 1;
+ }
+ return 0;
+ }
+
+ // Command to do nothing with an exit code of 0.
+ if (args[1] == "true") {
+ return 0;
+ }
+
+ // Command to do nothing with an exit code of 1.
+ if (args[1] == "false") {
+ return 1;
+ }
+
+ // Internal CMake shared library support.
+ if (args[1] == "cmake_symlink_library" && args.size() == 5) {
+ return cmcmd::SymlinkLibrary(args);
+ }
+
+ // Internal CMake versioned executable support.
+ if (args[1] == "cmake_symlink_executable" && args.size() == 4) {
+ return cmcmd::SymlinkExecutable(args);
+ }
+
+ // Internal CMake dependency scanning support.
+ if (args[1] == "cmake_depends" && args.size() >= 6) {
+ const bool verbose = isCMakeVerbose();
+
+ // Create a cmake object instance to process dependencies.
+ // All we need is the `set` command.
+ cmake cm(cmake::RoleScript, cmState::Unknown);
+ std::string gen;
+ std::string homeDir;
+ std::string startDir;
+ std::string homeOutDir;
+ std::string startOutDir;
+ std::string depInfo;
+ bool color = false;
+ if (args.size() >= 8) {
+ // Full signature:
+ //
+ // -E cmake_depends <generator>
+ // <home-src-dir> <start-src-dir>
+ // <home-out-dir> <start-out-dir>
+ // <dep-info> [--color=$(COLOR)]
+ //
+ // All paths are provided.
+ gen = args[2];
+ homeDir = args[3];
+ startDir = args[4];
+ homeOutDir = args[5];
+ startOutDir = args[6];
+ depInfo = args[7];
+ if (args.size() >= 9 && cmHasLiteralPrefix(args[8], "--color=")) {
+ // Enable or disable color based on the switch value.
+ color = (args[8].size() == 8 || cmIsOn(args[8].substr(8)));
+ }
+ } else {
+ // Support older signature for existing makefiles:
+ //
+ // -E cmake_depends <generator>
+ // <home-out-dir> <start-out-dir>
+ // <dep-info>
+ //
+ // Just pretend the source directories are the same as the
+ // binary directories so at least scanning will work.
+ gen = args[2];
+ homeDir = args[3];
+ startDir = args[4];
+ homeOutDir = args[3];
+ startOutDir = args[3];
+ depInfo = args[5];
+ }
+
+ // Create a local generator configured for the directory in
+ // which dependencies will be scanned.
+ homeDir = cmSystemTools::CollapseFullPath(homeDir);
+ startDir = cmSystemTools::CollapseFullPath(startDir);
+ homeOutDir = cmSystemTools::CollapseFullPath(homeOutDir);
+ startOutDir = cmSystemTools::CollapseFullPath(startOutDir);
+ cm.SetHomeDirectory(homeDir);
+ cm.SetHomeOutputDirectory(homeOutDir);
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ if (auto ggd = cm.CreateGlobalGenerator(gen)) {
+ cm.SetGlobalGenerator(std::move(ggd));
+ cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
+ snapshot.GetDirectory().SetCurrentBinary(startOutDir);
+ snapshot.GetDirectory().SetCurrentSource(startDir);
+ snapshot.GetDirectory().SetRelativePathTopSource(homeDir.c_str());
+ snapshot.GetDirectory().SetRelativePathTopBinary(homeOutDir.c_str());
+ cmMakefile mf(cm.GetGlobalGenerator(), snapshot);
+ auto lgd = cm.GetGlobalGenerator()->CreateLocalGenerator(&mf);
+
+ // Actually scan dependencies.
+ return lgd->UpdateDependencies(depInfo, verbose, color) ? 0 : 2;
+ }
+ return 1;
+ }
+
+#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_MAKEFILES)
+ // Internal CMake compiler dependencies filtering
+ if (args[1] == "cmake_cl_compile_depends") {
+ return CLCompileAndDependencies(args);
+ }
+#endif
+
+ // Internal CMake link script support.
+ if (args[1] == "cmake_link_script" && args.size() >= 3) {
+ return cmcmd::ExecuteLinkScript(args);
+ }
+
+#if !defined(CMAKE_BOOTSTRAP)
+ // Internal CMake ninja dependency scanning support.
+ if (args[1] == "cmake_ninja_depends") {
+ return cmcmd_cmake_ninja_depends(args.begin() + 2, args.end());
+ }
+
+ // Internal CMake ninja dyndep support.
+ if (args[1] == "cmake_ninja_dyndep") {
+ return cmcmd_cmake_ninja_dyndep(args.begin() + 2, args.end());
+ }
+#endif
+
+ // Internal CMake unimplemented feature notification.
+ if (args[1] == "cmake_unimplemented_variable") {
+ std::cerr << "Feature not implemented for this platform.";
+ if (args.size() == 3) {
+ std::cerr << " Variable " << args[2] << " is not set.";
+ }
+ std::cerr << std::endl;
+ return 1;
+ }
+
+ if (args[1] == "vs_link_exe") {
+ return cmcmd::VisualStudioLink(args, 1);
+ }
+
+ if (args[1] == "vs_link_dll") {
+ return cmcmd::VisualStudioLink(args, 2);
+ }
+
+ if (args[1] == "cmake_llvm_rc") {
+ return cmcmd::RunLLVMRC(args);
+ }
+
+ // Internal CMake color makefile support.
+ if (args[1] == "cmake_echo_color") {
+ return cmcmd::ExecuteEchoColor(args);
+ }
+
+#ifndef CMAKE_BOOTSTRAP
+ if ((args[1] == "cmake_autogen") && (args.size() >= 4)) {
+ cm::string_view const infoFile = args[2];
+ cm::string_view const config = args[3];
+ return cmQtAutoMocUic(infoFile, config) ? 0 : 1;
+ }
+ if ((args[1] == "cmake_autorcc") && (args.size() >= 3)) {
+ cm::string_view const infoFile = args[2];
+ cm::string_view const config =
+ (args.size() > 3) ? cm::string_view(args[3]) : cm::string_view();
+ return cmQtAutoRcc(infoFile, config) ? 0 : 1;
+ }
+#endif
+
+ // Tar files
+ if (args[1] == "tar" && args.size() > 3) {
+ const char* knownFormats[] = { "7zip", "gnutar", "pax", "paxr", "zip" };
+
+ std::string const& flags = args[2];
+ std::string const& outFile = args[3];
+ std::vector<std::string> files;
+ std::string mtime;
+ std::string format;
+ cmSystemTools::cmTarCompression compress =
+ cmSystemTools::TarCompressNone;
+ int nCompress = 0;
+ bool doing_options = true;
+ for (auto const& arg : cmMakeRange(args).advance(4)) {
+ if (doing_options && cmHasLiteralPrefix(arg, "--")) {
+ if (arg == "--") {
+ doing_options = false;
+ } else if (arg == "--zstd") {
+ compress = cmSystemTools::TarCompressZstd;
+ ++nCompress;
+ } else if (cmHasLiteralPrefix(arg, "--mtime=")) {
+ mtime = arg.substr(8);
+ } else if (cmHasLiteralPrefix(arg, "--files-from=")) {
+ std::string const& files_from = arg.substr(13);
+ if (!cmTarFilesFrom(files_from, files)) {
+ return 1;
+ }
+ } else if (cmHasLiteralPrefix(arg, "--format=")) {
+ format = arg.substr(9);
+ if (!cm::contains(knownFormats, format)) {
+ cmSystemTools::Error("Unknown -E tar --format= argument: " +
+ format);
+ return 1;
+ }
+ } else {
+ cmSystemTools::Error("Unknown option to -E tar: " + arg);
+ return 1;
+ }
+ } else {
+ files.push_back(arg);
+ }
+ }
+ cmSystemTools::cmTarAction action = cmSystemTools::TarActionNone;
+ bool verbose = false;
+
+ for (auto flag : flags) {
+ switch (flag) {
+ case '-':
+ case 'f': {
+ // Keep for backward compatibility. Ignored
+ } break;
+ case 'j': {
+ compress = cmSystemTools::TarCompressBZip2;
+ ++nCompress;
+ } break;
+ case 'J': {
+ compress = cmSystemTools::TarCompressXZ;
+ ++nCompress;
+ } break;
+ case 'z': {
+ compress = cmSystemTools::TarCompressGZip;
+ ++nCompress;
+ } break;
+ case 'v': {
+ verbose = true;
+ } break;
+ case 't': {
+ action = cmSystemTools::TarActionList;
+ } break;
+ case 'c': {
+ action = cmSystemTools::TarActionCreate;
+ } break;
+ case 'x': {
+ action = cmSystemTools::TarActionExtract;
+ } break;
+ default: {
+ cmSystemTools::Message(
+ std::string("tar: Unknown argument: ") + flag, "Warning");
+ }
+ }
+ }
+ if ((format == "7zip" || format == "zip") && nCompress > 0) {
+ cmSystemTools::Error("Can not use compression flags with format: " +
+ format);
+ return 1;
+ }
+ if (nCompress > 1) {
+ cmSystemTools::Error("Can only compress a tar file one way; "
+ "at most one flag of z, j, or J may be used");
+ return 1;
+ }
+ if (action == cmSystemTools::TarActionList) {
+ if (!cmSystemTools::ListTar(outFile, files, verbose)) {
+ cmSystemTools::Error("Problem listing tar: " + outFile);
+ return 1;
+ }
+ } else if (action == cmSystemTools::TarActionCreate) {
+ if (files.empty()) {
+ cmSystemTools::Message("tar: No files or directories specified",
+ "Warning");
+ }
+ if (!cmSystemTools::CreateTar(outFile, files, compress, verbose, mtime,
+ format)) {
+ cmSystemTools::Error("Problem creating tar: " + outFile);
+ return 1;
+ }
+ } else if (action == cmSystemTools::TarActionExtract) {
+ if (!cmSystemTools::ExtractTar(outFile, files, verbose)) {
+ cmSystemTools::Error("Problem extracting tar: " + outFile);
+ return 1;
+ }
+#ifdef WIN32
+ // OK, on windows 7 after we untar some files,
+ // sometimes we can not rename the directory after
+ // the untar is done. This breaks the external project
+ // untar and rename code. So, by default we will wait
+ // 1/10th of a second after the untar. If CMAKE_UNTAR_DELAY
+ // is set in the env, its value will be used instead of 100.
+ int delay = 100;
+ std::string delayVar;
+ if (cmSystemTools::GetEnv("CMAKE_UNTAR_DELAY", delayVar)) {
+ delay = atoi(delayVar.c_str());
+ }
+ if (delay) {
+ cmSystemTools::Delay(delay);
+ }
+#endif
+ } else {
+ cmSystemTools::Error("tar: No action specified. Please choose: 't' "
+ "(list), 'c' (create) or 'x' (extract)");
+ return 1;
+ }
+ return 0;
+ }
+
+ if (args[1] == "server") {
+ cmSystemTools::Error(
+ "CMake server mode has been removed in favor of the file-api.");
+ return 1;
+ }
+
+#if !defined(CMAKE_BOOTSTRAP)
+ // Internal CMake Fortran module support.
+ if (args[1] == "cmake_copy_f90_mod" && args.size() >= 4) {
+ return cmDependsFortran::CopyModule(args) ? 0 : 1;
+ }
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // Write registry value
+ if (args[1] == "write_regv" && args.size() > 3) {
+ return cmSystemTools::WriteRegistryValue(args[2], args[3]) ? 0 : 1;
+ }
+
+ // Delete registry value
+ if (args[1] == "delete_regv" && args.size() > 2) {
+ return cmSystemTools::DeleteRegistryValue(args[2]) ? 0 : 1;
+ }
+
+ // Remove file
+ if (args[1] == "comspec" && args.size() > 2) {
+ std::cerr << "Win9x helper \"cmake -E comspec\" no longer supported\n";
+ return 1;
+ }
+
+ if (args[1] == "env_vs8_wince" && args.size() == 3) {
+ return cmcmd::WindowsCEEnvironment("8.0", args[2]);
+ }
+
+ if (args[1] == "env_vs9_wince" && args.size() == 3) {
+ return cmcmd::WindowsCEEnvironment("9.0", args[2]);
+ }
+#endif
+
+ // Internal depfile transformation
+ if (args[1] == "cmake_transform_depfile" && args.size() == 10) {
+ auto format = cmDepfileFormat::GccDepfile;
+ if (args[3] == "gccdepfile") {
+ format = cmDepfileFormat::GccDepfile;
+ } else if (args[3] == "vstlog") {
+ format = cmDepfileFormat::VsTlog;
+ } else {
+ return 1;
+ }
+ // Create a cmake object instance to process dependencies.
+ // All we need is the `set` command.
+ cmake cm(cmake::RoleScript, cmState::Unknown);
+ std::string homeDir;
+ std::string startDir;
+ std::string homeOutDir;
+ std::string startOutDir;
+ homeDir = cmSystemTools::CollapseFullPath(args[4]);
+ startDir = cmSystemTools::CollapseFullPath(args[5]);
+ homeOutDir = cmSystemTools::CollapseFullPath(args[6]);
+ startOutDir = cmSystemTools::CollapseFullPath(args[7]);
+ cm.SetHomeDirectory(homeDir);
+ cm.SetHomeOutputDirectory(homeOutDir);
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ if (auto ggd = cm.CreateGlobalGenerator(args[2])) {
+ cm.SetGlobalGenerator(std::move(ggd));
+ cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
+ snapshot.GetDirectory().SetCurrentBinary(startOutDir);
+ snapshot.GetDirectory().SetCurrentSource(startDir);
+ snapshot.GetDirectory().SetRelativePathTopSource(homeDir.c_str());
+ snapshot.GetDirectory().SetRelativePathTopBinary(homeOutDir.c_str());
+ cmMakefile mf(cm.GetGlobalGenerator(), snapshot);
+ auto lgd = cm.GetGlobalGenerator()->CreateLocalGenerator(&mf);
+
+ return cmTransformDepfile(format, *lgd, args[8], args[9]) ? 0 : 2;
+ }
+ return 1;
+ }
+ }
+
+ CMakeCommandUsage(args[0]);
+ return 1;
+}
+
+int cmcmd::HashSumFile(std::vector<std::string> const& args,
+ cmCryptoHash::Algo algo)
+{
+ if (args.size() < 3) {
+ return -1;
+ }
+ int retval = 0;
+
+ for (auto const& filename : cmMakeRange(args).advance(2)) {
+ // Cannot compute sum of a directory
+ if (cmSystemTools::FileIsDirectory(filename)) {
+ std::cerr << "Error: " << filename << " is a directory" << std::endl;
+ retval++;
+ } else {
+ std::string value = cmSystemTools::ComputeFileHash(filename, algo);
+ if (value.empty()) {
+ // To mimic "md5sum/shasum" behavior in a shell:
+ std::cerr << filename << ": No such file or directory" << std::endl;
+ retval++;
+ } else {
+ std::cout << value << " " << filename << std::endl;
+ }
+ }
+ }
+ return retval;
+}
+
+int cmcmd::SymlinkLibrary(std::vector<std::string> const& args)
+{
+ int result = 0;
+ std::string realName = args[2];
+ std::string soName = args[3];
+ std::string name = args[4];
+ cmSystemTools::ConvertToUnixSlashes(realName);
+ cmSystemTools::ConvertToUnixSlashes(soName);
+ cmSystemTools::ConvertToUnixSlashes(name);
+ if (soName != realName) {
+ if (!cmcmd::SymlinkInternal(realName, soName)) {
+ cmSystemTools::ReportLastSystemError("cmake_symlink_library");
+ result = 1;
+ }
+ }
+ if (name != soName) {
+ if (!cmcmd::SymlinkInternal(soName, name)) {
+ cmSystemTools::ReportLastSystemError("cmake_symlink_library");
+ result = 1;
+ }
+ }
+ return result;
+}
+
+int cmcmd::SymlinkExecutable(std::vector<std::string> const& args)
+{
+ int result = 0;
+ std::string const& realName = args[2];
+ std::string const& name = args[3];
+ if (name != realName) {
+ if (!cmcmd::SymlinkInternal(realName, name)) {
+ cmSystemTools::ReportLastSystemError("cmake_symlink_executable");
+ result = 1;
+ }
+ }
+ return result;
+}
+
+bool cmcmd::SymlinkInternal(std::string const& file, std::string const& link)
+{
+ if (cmSystemTools::FileExists(link) || cmSystemTools::FileIsSymlink(link)) {
+ cmSystemTools::RemoveFile(link);
+ }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ return cmSystemTools::CopyFileAlways(file, link);
+#else
+ std::string linktext = cmSystemTools::GetFilenameName(file);
+ return cmSystemTools::CreateSymlink(linktext, link);
+#endif
+}
+
+static void cmcmdProgressReport(std::string const& dir, std::string const& num)
+{
+ std::string dirName = cmStrCat(dir, "/Progress");
+ std::string fName;
+ FILE* progFile;
+
+ // read the count
+ fName = cmStrCat(dirName, "/count.txt");
+ progFile = cmsys::SystemTools::Fopen(fName, "r");
+ int count = 0;
+ if (!progFile) {
+ return;
+ }
+ if (1 != fscanf(progFile, "%i", &count)) {
+ cmSystemTools::Message("Could not read from progress file.");
+ }
+ fclose(progFile);
+
+ const char* last = num.c_str();
+ for (const char* c = last;; ++c) {
+ if (*c == ',' || *c == '\0') {
+ if (c != last) {
+ fName = cmStrCat(dirName, '/');
+ fName.append(last, c - last);
+ progFile = cmsys::SystemTools::Fopen(fName, "w");
+ if (progFile) {
+ fprintf(progFile, "empty");
+ fclose(progFile);
+ }
+ }
+ if (*c == '\0') {
+ break;
+ }
+ last = c + 1;
+ }
+ }
+ int fileNum =
+ static_cast<int>(cmsys::Directory::GetNumberOfFilesInDirectory(dirName));
+ if (count > 0) {
+ // print the progress
+ fprintf(stdout, "[%3i%%] ", ((fileNum - 3) * 100) / count);
+ }
+}
+
+int cmcmd::ExecuteEchoColor(std::vector<std::string> const& args)
+{
+ // The arguments are
+ // args[0] == <cmake-executable>
+ // args[1] == cmake_echo_color
+
+ bool enabled = true;
+ int color = cmsysTerminal_Color_Normal;
+ bool newline = true;
+ std::string progressDir;
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (cmHasLiteralPrefix(arg, "--switch=")) {
+ // Enable or disable color based on the switch value.
+ std::string value = arg.substr(9);
+ if (!value.empty()) {
+ enabled = cmIsOn(value);
+ }
+ } else if (cmHasLiteralPrefix(arg, "--progress-dir=")) {
+ progressDir = arg.substr(15);
+ } else if (cmHasLiteralPrefix(arg, "--progress-num=")) {
+ if (!progressDir.empty()) {
+ std::string const& progressNum = arg.substr(15);
+ cmcmdProgressReport(progressDir, progressNum);
+ }
+ } else if (arg == "--normal") {
+ color = cmsysTerminal_Color_Normal;
+ } else if (arg == "--black") {
+ color = cmsysTerminal_Color_ForegroundBlack;
+ } else if (arg == "--red") {
+ color = cmsysTerminal_Color_ForegroundRed;
+ } else if (arg == "--green") {
+ color = cmsysTerminal_Color_ForegroundGreen;
+ } else if (arg == "--yellow") {
+ color = cmsysTerminal_Color_ForegroundYellow;
+ } else if (arg == "--blue") {
+ color = cmsysTerminal_Color_ForegroundBlue;
+ } else if (arg == "--magenta") {
+ color = cmsysTerminal_Color_ForegroundMagenta;
+ } else if (arg == "--cyan") {
+ color = cmsysTerminal_Color_ForegroundCyan;
+ } else if (arg == "--white") {
+ color = cmsysTerminal_Color_ForegroundWhite;
+ } else if (arg == "--bold") {
+ color |= cmsysTerminal_Color_ForegroundBold;
+ } else if (arg == "--no-newline") {
+ newline = false;
+ } else if (arg == "--newline") {
+ newline = true;
+ } else {
+ // Color is enabled. Print with the current color.
+ cmSystemTools::MakefileColorEcho(color, arg.c_str(), newline, enabled);
+ }
+ }
+
+ return 0;
+}
+
+int cmcmd::ExecuteLinkScript(std::vector<std::string> const& args)
+{
+ // The arguments are
+ // args[0] == <cmake-executable>
+ // args[1] == cmake_link_script
+ // args[2] == <link-script-name>
+ // args[3] == --verbose=?
+ bool verbose = false;
+ if (args.size() >= 4) {
+ if (cmHasLiteralPrefix(args[3], "--verbose=")) {
+ if (!cmIsOff(args[3].substr(10))) {
+ verbose = true;
+ }
+ }
+ }
+
+ // Allocate a process instance.
+ cmsysProcess* cp = cmsysProcess_New();
+ if (!cp) {
+ std::cerr << "Error allocating process instance in link script."
+ << std::endl;
+ return 1;
+ }
+
+ // Children should share stdout and stderr with this process.
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
+
+ // Run the command lines verbatim.
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);
+
+ // Read command lines from the script.
+ cmsys::ifstream fin(args[2].c_str());
+ if (!fin) {
+ std::cerr << "Error opening link script \"" << args[2] << "\""
+ << std::endl;
+ return 1;
+ }
+
+ // Run one command at a time.
+ std::string command;
+ int result = 0;
+ while (result == 0 && cmSystemTools::GetLineFromStream(fin, command)) {
+ // Skip empty command lines.
+ if (command.find_first_not_of(" \t") == std::string::npos) {
+ continue;
+ }
+
+ // Setup this command line.
+ const char* cmd[2] = { command.c_str(), nullptr };
+ cmsysProcess_SetCommand(cp, cmd);
+
+ // Report the command if verbose output is enabled.
+ if (verbose) {
+ std::cout << command << std::endl;
+ }
+
+ // Run the command and wait for it to exit.
+ cmsysProcess_Execute(cp);
+ cmsysProcess_WaitForExit(cp, nullptr);
+
+ // Report failure if any.
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Exited: {
+ int value = cmsysProcess_GetExitValue(cp);
+ if (value != 0) {
+ result = value;
+ }
+ } break;
+ case cmsysProcess_State_Exception:
+ std::cerr << "Error running link command: "
+ << cmsysProcess_GetExceptionString(cp) << std::endl;
+ result = 1;
+ break;
+ case cmsysProcess_State_Error:
+ std::cerr << "Error running link command: "
+ << cmsysProcess_GetErrorString(cp) << std::endl;
+ result = 2;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Free the process instance.
+ cmsysProcess_Delete(cp);
+
+ // Return the final resulting return value.
+ return result;
+}
+
+int cmcmd::WindowsCEEnvironment(const char* version, const std::string& name)
+{
+#if !defined(CMAKE_BOOTSTRAP) && defined(_WIN32) && !defined(__CYGWIN__)
+ cmVisualStudioWCEPlatformParser parser(name.c_str());
+ parser.ParseVersion(version);
+ if (parser.Found()) {
+ /* clang-format off */
+ std::cout << "@echo off\n"
+ "echo Environment Selection: " << name << "\n"
+ "set PATH=" << parser.GetPathDirectories() << "\n"
+ "set INCLUDE=" << parser.GetIncludeDirectories() << "\n"
+ "set LIB=" << parser.GetLibraryDirectories() << std::endl;
+ /* clang-format on */
+ return 0;
+ }
+#else
+ (void)version;
+#endif
+
+ std::cerr << "Could not find " << name;
+ return -1;
+}
+
+int cmcmd::RunPreprocessor(const std::vector<std::string>& command,
+ const std::string& intermediate_file)
+{
+ cmUVProcessChainBuilder builder;
+
+ uv_fs_t fs_req;
+ int preprocessedFile =
+ uv_fs_open(nullptr, &fs_req, intermediate_file.c_str(), O_CREAT | O_RDWR,
+ 0644, nullptr);
+ uv_fs_req_cleanup(&fs_req);
+
+ builder
+ .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT,
+ preprocessedFile)
+ .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR)
+ .AddCommand(command);
+ auto process = builder.Start();
+ if (!process.Valid()) {
+ std::cerr << "Failed to start preprocessor.";
+ return 1;
+ }
+ if (!process.Wait()) {
+ std::cerr << "Failed to wait for preprocessor";
+ return 1;
+ }
+ auto status = process.GetStatus();
+ if (!status[0] || status[0]->ExitStatus != 0) {
+ auto* errorStream = process.ErrorStream();
+ if (errorStream) {
+ std::cerr << errorStream->rdbuf();
+ }
+
+ return 1;
+ }
+ return 0;
+}
+
+int cmcmd::RunLLVMRC(std::vector<std::string> const& args)
+{
+ // The arguments are
+ // args[0] == <cmake-executable>
+ // args[1] == cmake_llvm_rc
+ // args[2] == source_file_path
+ // args[3] == intermediate_file
+ // args[4..n] == preprocess+args
+ // args[n+1] == ++
+ // args[n+2...] == llvm-rc+args
+ if (args.size() < 3) {
+ std::cerr << "Invalid cmake_llvm_rc arguments";
+ return 1;
+ }
+
+ const std::string& intermediate_file = args[3];
+ const std::string& source_file = args[2];
+ std::vector<std::string> preprocess;
+ std::vector<std::string> resource_compile;
+ std::vector<std::string>* pArgTgt = &preprocess;
+
+ static const cmsys::RegularExpression llvm_rc_only_single_arg("^[-/](N|Y)");
+ static const cmsys::RegularExpression llvm_rc_only_double_arg(
+ "^[-/](C|LN|L)(.)?");
+ static const cmsys::RegularExpression common_double_arg(
+ "^[-/](D|U|I|FO|fo|Fo)(.)?");
+ bool acceptNextArg = false;
+ bool skipNextArg = false;
+ for (std::string const& arg : cmMakeRange(args).advance(4)) {
+ if (skipNextArg) {
+ skipNextArg = false;
+ continue;
+ }
+ // We use ++ as seperator between the preprocessing step definition and
+ // the rc compilation step becase we need to prepend a -- to seperate the
+ // source file properly from other options when using clang-cl for
+ // preprocessing.
+ if (arg == "++") {
+ pArgTgt = &resource_compile;
+ skipNextArg = false;
+ acceptNextArg = true;
+ } else {
+ cmsys::RegularExpressionMatch match;
+ if (!acceptNextArg) {
+ if (common_double_arg.find(arg.c_str(), match)) {
+ acceptNextArg = match.match(2).empty();
+ } else {
+ if (llvm_rc_only_single_arg.find(arg.c_str(), match)) {
+ if (pArgTgt == &preprocess) {
+ continue;
+ }
+ } else if (llvm_rc_only_double_arg.find(arg.c_str(), match)) {
+ if (pArgTgt == &preprocess) {
+ skipNextArg = match.match(2).empty();
+ continue;
+ }
+ acceptNextArg = match.match(2).empty();
+ } else if (pArgTgt == &resource_compile) {
+ continue;
+ }
+ }
+ } else {
+ acceptNextArg = false;
+ }
+ if (arg.find("SOURCE_DIR") != std::string::npos) {
+ std::string sourceDirArg = arg;
+ cmSystemTools::ReplaceString(
+ sourceDirArg, "SOURCE_DIR",
+ cmSystemTools::GetFilenamePath(source_file));
+ pArgTgt->push_back(sourceDirArg);
+ } else {
+ pArgTgt->push_back(arg);
+ }
+ }
+ }
+ if (preprocess.empty()) {
+ std::cerr << "Empty preprocessing command";
+ return 1;
+ }
+ if (resource_compile.empty()) {
+ std::cerr << "Empty resource compilation command";
+ return 1;
+ }
+ // Since we might have skipped the last argument to llvm-rc
+ // we need to make sure the llvm-rc source file is present in the
+ // commandline
+ if (resource_compile.back() != intermediate_file) {
+ resource_compile.push_back(intermediate_file);
+ }
+
+ auto result = RunPreprocessor(preprocess, intermediate_file);
+ if (result != 0) {
+ cmSystemTools::RemoveFile(intermediate_file);
+ return result;
+ }
+ cmUVProcessChainBuilder builder;
+
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
+ .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR)
+ .AddCommand(resource_compile);
+ auto process = builder.Start();
+ result = 0;
+ if (!process.Valid()) {
+ std::cerr << "Failed to start resource compiler.";
+ result = 1;
+ } else {
+ if (!process.Wait()) {
+ std::cerr << "Failed to wait for resource compiler";
+ result = 1;
+ }
+ }
+
+ cmSystemTools::RemoveFile(intermediate_file);
+ if (result != 0) {
+ return result;
+ }
+ auto status = process.GetStatus();
+ if (!status[0] || status[0]->ExitStatus != 0) {
+ auto* errorStream = process.ErrorStream();
+ if (errorStream) {
+ std::cerr << errorStream->rdbuf();
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+class cmVSLink
+{
+ int Type;
+ bool Verbose;
+ bool Incremental;
+ bool LinkGeneratesManifest;
+ std::vector<std::string> LinkCommand;
+ std::vector<std::string> UserManifests;
+ std::string LinkerManifestFile;
+ std::string ManifestFile;
+ std::string ManifestFileRC;
+ std::string ManifestFileRes;
+ std::string TargetFile;
+ std::string MtPath;
+ std::string RcPath;
+
+public:
+ cmVSLink(int type, bool verbose)
+ : Type(type)
+ , Verbose(verbose)
+ , Incremental(false)
+ , LinkGeneratesManifest(true)
+ {
+ }
+ bool Parse(std::vector<std::string>::const_iterator argBeg,
+ std::vector<std::string>::const_iterator argEnd);
+ int Link();
+
+private:
+ int LinkIncremental();
+ int LinkNonIncremental();
+ int RunMT(std::string const& out, bool notify);
+};
+
+// For visual studio 2005 and newer manifest files need to be embedded into
+// exe and dll's. This code does that in such a way that incremental linking
+// still works.
+int cmcmd::VisualStudioLink(std::vector<std::string> const& args, int type)
+{
+ // Replace streambuf so we output in the system codepage. CMake is set up
+ // to output in Unicode (see SetUTF8Pipes) but the Visual Studio linker
+ // outputs using the system codepage so we need to change behavior when
+ // we run the link command.
+ cmConsoleBuf consoleBuf;
+
+ if (args.size() < 2) {
+ return -1;
+ }
+ const bool verbose = cmSystemTools::HasEnv("VERBOSE");
+ std::vector<std::string> expandedArgs;
+ for (std::string const& i : args) {
+ // check for nmake temporary files
+ if (i[0] == '@' && !cmHasLiteralPrefix(i, "@CMakeFiles")) {
+ cmsys::ifstream fin(i.substr(1).c_str());
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ cmSystemTools::ParseWindowsCommandLine(line.c_str(), expandedArgs);
+ }
+ } else {
+ expandedArgs.push_back(i);
+ }
+ }
+
+ cmVSLink vsLink(type, verbose);
+ if (!vsLink.Parse(expandedArgs.begin() + 2, expandedArgs.end())) {
+ return -1;
+ }
+ return vsLink.Link();
+}
+
+enum NumberFormat
+{
+ FORMAT_DECIMAL,
+ FORMAT_HEX
+};
+struct NumberFormatter
+{
+ NumberFormat Format;
+ int Value;
+ NumberFormatter(NumberFormat format, int value)
+ : Format(format)
+ , Value(value)
+ {
+ }
+};
+std::ostream& operator<<(std::ostream& stream,
+ NumberFormatter const& formatter)
+{
+ auto const& flags = stream.flags();
+ if (formatter.Format == FORMAT_DECIMAL) {
+ stream << std::dec << formatter.Value;
+ } else {
+ stream << "0x" << std::hex << formatter.Value;
+ }
+ stream.flags(flags);
+ return stream;
+}
+
+static bool RunCommand(const char* comment,
+ std::vector<std::string> const& command, bool verbose,
+ NumberFormat exitFormat, int* retCodeOut = nullptr,
+ bool (*retCodeOkay)(int) = nullptr)
+{
+ if (verbose) {
+ std::cout << comment << ":\n";
+ std::cout << cmJoin(command, " ") << "\n";
+ }
+ std::string output;
+ int retCode = 0;
+ bool commandResult = cmSystemTools::RunSingleCommand(
+ command, &output, &output, &retCode, nullptr, cmSystemTools::OUTPUT_NONE);
+ bool const retCodeSuccess =
+ retCode == 0 || (retCodeOkay && retCodeOkay(retCode));
+ bool const success = commandResult && retCodeSuccess;
+ if (retCodeOut) {
+ if (commandResult || !retCodeSuccess) {
+ *retCodeOut = retCode;
+ } else {
+ *retCodeOut = -1;
+ }
+ }
+ if (!success) {
+ std::cout << comment << ": command \"" << cmJoin(command, " ")
+ << "\" failed (exit code "
+ << NumberFormatter(exitFormat, retCode)
+ << ") with the following output:\n"
+ << output;
+ } else if (verbose) {
+ // always print the output of the command, unless
+ // it is the dumb rc command banner
+ if (output.find("Resource Compiler Version") == std::string::npos) {
+ std::cout << output;
+ }
+ }
+ return success;
+}
+
+bool cmVSLink::Parse(std::vector<std::string>::const_iterator argBeg,
+ std::vector<std::string>::const_iterator argEnd)
+{
+ // Parse our own arguments.
+ std::string intDir;
+ auto arg = argBeg;
+ while (arg != argEnd && cmHasLiteralPrefix(*arg, "-")) {
+ if (*arg == "--") {
+ ++arg;
+ break;
+ }
+ if (*arg == "--manifests") {
+ for (++arg; arg != argEnd && !cmHasLiteralPrefix(*arg, "-"); ++arg) {
+ this->UserManifests.push_back(*arg);
+ }
+ } else if (cmHasLiteralPrefix(*arg, "--intdir=")) {
+ intDir = arg->substr(9);
+ ++arg;
+ } else if (cmHasLiteralPrefix(*arg, "--rc=")) {
+ this->RcPath = arg->substr(5);
+ ++arg;
+ } else if (cmHasLiteralPrefix(*arg, "--mt=")) {
+ this->MtPath = arg->substr(5);
+ ++arg;
+ } else {
+ std::cerr << "unknown argument '" << *arg << "'\n";
+ return false;
+ }
+ }
+ if (intDir.empty()) {
+ return false;
+ }
+
+ // The rest of the arguments form the link command.
+ if (arg == argEnd) {
+ return false;
+ }
+ this->LinkCommand.insert(this->LinkCommand.begin(), arg, argEnd);
+
+ // Parse the link command to extract information we need.
+ for (; arg != argEnd; ++arg) {
+ if (cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL:YES") == 0 ||
+ cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL") == 0) {
+ this->Incremental = true;
+ } else if (cmSystemTools::Strucmp(arg->c_str(), "/MANIFEST:NO") == 0) {
+ this->LinkGeneratesManifest = false;
+ } else if (cmHasLiteralPrefix(*arg, "/Fe")) {
+ this->TargetFile = arg->substr(3);
+ } else if (cmHasLiteralPrefix(*arg, "/out:")) {
+ this->TargetFile = arg->substr(5);
+ }
+ }
+
+ if (this->TargetFile.empty()) {
+ return false;
+ }
+
+ this->ManifestFile = intDir + "/embed.manifest";
+ this->LinkerManifestFile = intDir + "/intermediate.manifest";
+
+ if (this->Incremental) {
+ // We will compile a resource containing the manifest and
+ // pass it to the link command.
+ this->ManifestFileRC = intDir + "/manifest.rc";
+ this->ManifestFileRes = intDir + "/manifest.res";
+ } else if (this->UserManifests.empty()) {
+ // Prior to support for user-specified manifests CMake placed the
+ // linker-generated manifest next to the binary (as if it were not to be
+ // embedded) when not linking incrementally. Preserve this behavior.
+ this->ManifestFile = this->TargetFile + ".manifest";
+ this->LinkerManifestFile = this->ManifestFile;
+ }
+
+ if (this->LinkGeneratesManifest) {
+ this->LinkCommand.emplace_back("/MANIFEST");
+ this->LinkCommand.push_back("/MANIFESTFILE:" + this->LinkerManifestFile);
+ }
+
+ return true;
+}
+
+int cmVSLink::Link()
+{
+ if (this->Incremental &&
+ (this->LinkGeneratesManifest || !this->UserManifests.empty())) {
+ if (this->Verbose) {
+ std::cout << "Visual Studio Incremental Link with embedded manifests\n";
+ }
+ return this->LinkIncremental();
+ }
+ if (this->Verbose) {
+ if (!this->Incremental) {
+ std::cout << "Visual Studio Non-Incremental Link\n";
+ } else {
+ std::cout << "Visual Studio Incremental Link without manifests\n";
+ }
+ }
+ return this->LinkNonIncremental();
+}
+
+static bool mtRetIsUpdate(int mtRet)
+{
+ // 'mt /notify_update' returns a special value (differing between
+ // Windows and POSIX hosts) when it updated the manifest file.
+ return mtRet == 0x41020001 || mtRet == 0xbb;
+}
+
+int cmVSLink::LinkIncremental()
+{
+ // This follows the steps listed here:
+ // http://blogs.msdn.com/zakramer/archive/2006/05/22/603558.aspx
+
+ // 1. Compiler compiles the application and generates the *.obj files.
+ // 2. An empty manifest file is generated if this is a clean build and
+ // if not the previous one is reused.
+ // 3. The resource compiler (rc.exe) compiles the *.manifest file to a
+ // *.res file.
+ // 4. Linker generates the binary (EXE or DLL) with the /incremental
+ // switch and embeds the dummy manifest file. The linker also generates
+ // the real manifest file based on the binaries that your binary depends
+ // on.
+ // 5. The manifest tool (mt.exe) is then used to generate the final
+ // manifest.
+
+ // If the final manifest is changed, then 6 and 7 are run, if not
+ // they are skipped, and it is done.
+
+ // 6. The resource compiler is invoked one more time.
+ // 7. Finally, the Linker does another incremental link, but since the
+ // only thing that has changed is the *.res file that contains the
+ // manifest it is a short link.
+
+ // Create a resource file referencing the manifest.
+ std::string absManifestFile =
+ cmSystemTools::CollapseFullPath(this->ManifestFile);
+ if (this->Verbose) {
+ std::cout << "Create " << this->ManifestFileRC << "\n";
+ }
+ {
+ cmsys::ofstream fout(this->ManifestFileRC.c_str());
+ if (!fout) {
+ return -1;
+ }
+ // Insert a pragma statement to specify utf-8 encoding.
+ fout << "#pragma code_page(65001)\n";
+ fout << this->Type
+ << " /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ "
+ "24 /* RT_MANIFEST */ \""
+ << absManifestFile << "\"";
+ }
+
+ // If we have not previously generated a manifest file,
+ // generate a manifest file so the resource compiler succeeds.
+ if (!cmSystemTools::FileExists(this->ManifestFile)) {
+ if (this->Verbose) {
+ std::cout << "Create empty: " << this->ManifestFile << "\n";
+ }
+ if (this->UserManifests.empty()) {
+ // generate an empty manifest because there are no user provided
+ // manifest files.
+ cmsys::ofstream foutTmp(this->ManifestFile.c_str());
+ } else {
+ this->RunMT("/out:" + this->ManifestFile, false);
+ }
+ }
+
+ // Compile the resource file.
+ std::vector<std::string> rcCommand;
+ rcCommand.push_back(this->RcPath.empty() ? "rc" : this->RcPath);
+ rcCommand.emplace_back("/fo");
+ rcCommand.push_back(this->ManifestFileRes);
+ rcCommand.push_back(this->ManifestFileRC);
+ if (!RunCommand("RC Pass 1", rcCommand, this->Verbose, FORMAT_DECIMAL)) {
+ return -1;
+ }
+
+ // Tell the linker to use our manifest compiled into a resource.
+ this->LinkCommand.push_back(this->ManifestFileRes);
+
+ // Run the link command (possibly generates intermediate manifest).
+ if (!RunCommand("LINK Pass 1", this->LinkCommand, this->Verbose,
+ FORMAT_DECIMAL)) {
+ return -1;
+ }
+
+ // Run the manifest tool to create the final manifest.
+ int mtRet = this->RunMT("/out:" + this->ManifestFile, true);
+
+ // If mt returns a special value then it updated the manifest file so
+ // we need to embed it again. Otherwise we are done.
+ if (!mtRetIsUpdate(mtRet)) {
+ return mtRet;
+ }
+
+ // Compile the resource file again.
+ if (!RunCommand("RC Pass 2", rcCommand, this->Verbose, FORMAT_DECIMAL)) {
+ return -1;
+ }
+
+ // Link incrementally again to use the updated resource.
+ if (!RunCommand("FINAL LINK", this->LinkCommand, this->Verbose,
+ FORMAT_DECIMAL)) {
+ return -1;
+ }
+ return 0;
+}
+
+int cmVSLink::LinkNonIncremental()
+{
+ // Run the link command (possibly generates intermediate manifest).
+ if (!RunCommand("LINK", this->LinkCommand, this->Verbose, FORMAT_DECIMAL)) {
+ return -1;
+ }
+
+ // If we have no manifest files we are done.
+ if (!this->LinkGeneratesManifest && this->UserManifests.empty()) {
+ return 0;
+ }
+
+ // Run the manifest tool to embed the final manifest in the binary.
+ std::string mtOut =
+ "/outputresource:" + this->TargetFile + (this->Type == 1 ? ";#1" : ";#2");
+ return this->RunMT(mtOut, false);
+}
+
+int cmVSLink::RunMT(std::string const& out, bool notify)
+{
+ std::vector<std::string> mtCommand;
+ mtCommand.push_back(this->MtPath.empty() ? "mt" : this->MtPath);
+ mtCommand.emplace_back("/nologo");
+ mtCommand.emplace_back("/manifest");
+
+ // add the linker generated manifest if the file exists.
+ if (this->LinkGeneratesManifest &&
+ cmSystemTools::FileExists(this->LinkerManifestFile)) {
+ mtCommand.push_back(this->LinkerManifestFile);
+ }
+ cm::append(mtCommand, this->UserManifests);
+ mtCommand.push_back(out);
+ if (notify) {
+ // Add an undocumented option that enables a special return
+ // code to notify us when the manifest is modified.
+ mtCommand.emplace_back("/notify_update");
+ }
+ int mtRet = 0;
+ if (!RunCommand("MT", mtCommand, this->Verbose, FORMAT_HEX, &mtRet,
+ mtRetIsUpdate)) {
+ return -1;
+ }
+ return mtRet;
+}
diff --git a/Source/cmcmd.h b/Source/cmcmd.h
new file mode 100644
index 0000000..a2e0b1e
--- /dev/null
+++ b/Source/cmcmd.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 "cmConfigure.h" // IWYU pragma: keep
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "cmCryptoHash.h"
+
+class cmConsoleBuf;
+
+class cmcmd
+{
+public:
+ /**
+ * Execute commands during the build process. Supports options such
+ * as echo, remove file etc.
+ */
+ static int ExecuteCMakeCommand(std::vector<std::string> const&,
+ std::unique_ptr<cmConsoleBuf> consoleBuf);
+
+protected:
+ static int HandleCoCompileCommands(std::vector<std::string> const& args);
+ static int HashSumFile(std::vector<std::string> const& args,
+ cmCryptoHash::Algo algo);
+ static int SymlinkLibrary(std::vector<std::string> const& args);
+ static int SymlinkExecutable(std::vector<std::string> const& args);
+ static bool SymlinkInternal(std::string const& file,
+ std::string const& link);
+ static int ExecuteEchoColor(std::vector<std::string> const& args);
+ static int ExecuteLinkScript(std::vector<std::string> const& args);
+ static int WindowsCEEnvironment(const char* version,
+ const std::string& name);
+ static int RunPreprocessor(const std::vector<std::string>& command,
+ const std::string& intermediate_file);
+ static int RunLLVMRC(std::vector<std::string> const& args);
+ static int VisualStudioLink(std::vector<std::string> const& args, int type);
+};
diff --git a/Source/ctest.cxx b/Source/ctest.cxx
new file mode 100644
index 0000000..a4b85ae
--- /dev/null
+++ b/Source/ctest.cxx
@@ -0,0 +1,231 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <cstring>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "cmsys/Encoding.hxx"
+
+#include "cmCTest.h"
+#include "cmConsoleBuf.h"
+#include "cmDocumentation.h"
+#include "cmSystemTools.h"
+
+#include "CTest/cmCTestLaunch.h"
+#include "CTest/cmCTestScriptHandler.h"
+
+static const char* cmDocumentationName[][2] = {
+ { nullptr, " ctest - Testing driver provided by CMake." },
+ { nullptr, nullptr }
+};
+
+static const char* cmDocumentationUsage[][2] = { { nullptr,
+ " ctest [options]" },
+ { nullptr, nullptr } };
+
+static const char* cmDocumentationOptions[][2] = {
+ { "--preset <preset>, --preset=<preset>",
+ "Read arguments from a test preset." },
+ { "--list-presets", "List available test presets." },
+ { "-C <cfg>, --build-config <cfg>", "Choose configuration to test." },
+ { "--progress", "Enable short progress output from tests." },
+ { "-V,--verbose", "Enable verbose output from tests." },
+ { "-VV,--extra-verbose", "Enable more verbose output from tests." },
+ { "--debug", "Displaying more verbose internals of CTest." },
+ { "--output-on-failure",
+ "Output anything outputted by the test program "
+ "if the test should fail." },
+ { "--stop-on-failure", "Stop running the tests after one has failed." },
+ { "--test-output-size-passed <size>",
+ "Limit the output for passed tests "
+ "to <size> bytes" },
+ { "--test-output-size-failed <size>",
+ "Limit the output for failed tests "
+ "to <size> bytes" },
+ { "-F", "Enable failover." },
+ { "-j <jobs>, --parallel <jobs>",
+ "Run the tests in parallel using the "
+ "given number of jobs." },
+ { "-Q,--quiet", "Make ctest quiet." },
+ { "-O <file>, --output-log <file>", "Output to log file" },
+ { "-N,--show-only[=format]",
+ "Disable actual execution of tests. The optional 'format' defines the "
+ "format of the test information and can be 'human' for the current text "
+ "format or 'json-v1' for json format. Defaults to 'human'." },
+ { "-L <regex>, --label-regex <regex>",
+ "Run tests with labels matching regular expression. "
+ "With multiple -L, run tests where each "
+ "regular expression matches at least one label." },
+ { "-R <regex>, --tests-regex <regex>",
+ "Run tests matching regular "
+ "expression." },
+ { "-E <regex>, --exclude-regex <regex>",
+ "Exclude tests matching regular "
+ "expression." },
+ { "-LE <regex>, --label-exclude <regex>",
+ "Exclude tests with labels matching regular expression. "
+ "With multiple -LE, exclude tests where each "
+ "regular expression matches at least one label." },
+ { "-FA <regex>, --fixture-exclude-any <regex>",
+ "Do not automatically "
+ "add any tests for "
+ "fixtures matching "
+ "regular expression." },
+ { "-FS <regex>, --fixture-exclude-setup <regex>",
+ "Do not automatically "
+ "add setup tests for "
+ "fixtures matching "
+ "regular expression." },
+ { "-FC <regex>, --fixture-exclude-cleanup <regex>",
+ "Do not automatically "
+ "add cleanup tests for "
+ "fixtures matching "
+ "regular expression." },
+ { "-D <dashboard>, --dashboard <dashboard>", "Execute dashboard test" },
+ { "-D <var>:<type>=<value>", "Define a variable for script mode" },
+ { "-M <model>, --test-model <model>", "Sets the model for a dashboard" },
+ { "-T <action>, --test-action <action>",
+ "Sets the dashboard action to "
+ "perform" },
+ { "--group <group>",
+ "Specify what build group on the dashboard you'd like to "
+ "submit results to." },
+ { "-S <script>, --script <script>",
+ "Execute a dashboard for a "
+ "configuration" },
+ { "-SP <script>, --script-new-process <script>",
+ "Execute a dashboard for a "
+ "configuration" },
+ { "-A <file>, --add-notes <file>", "Add a notes file with submission" },
+ { "-I [Start,End,Stride,test#,test#|Test file], --tests-information",
+ "Run a specific number of tests by number." },
+ { "-U, --union", "Take the Union of -I and -R" },
+ { "--rerun-failed", "Run only the tests that failed previously" },
+ { "--repeat until-fail:<n>, --repeat-until-fail <n>",
+ "Require each test to run <n> times without failing in order to pass" },
+ { "--repeat until-pass:<n>",
+ "Allow each test to run up to <n> times in order to pass" },
+ { "--repeat after-timeout:<n>",
+ "Allow each test to run up to <n> times if it times out" },
+ { "--max-width <width>", "Set the max width for a test name to output" },
+ { "--interactive-debug-mode [0|1]", "Set the interactive mode to 0 or 1." },
+ { "--resource-spec-file <file>", "Set the resource spec file to use." },
+ { "--no-label-summary", "Disable timing summary information for labels." },
+ { "--no-subproject-summary",
+ "Disable timing summary information for "
+ "subprojects." },
+ { "--test-dir <dir>", "Specify the directory in which to look for tests." },
+ { "--build-and-test", "Configure, build and run a test." },
+ { "--build-target", "Specify a specific target to build." },
+ { "--build-nocmake", "Run the build without running cmake first." },
+ { "--build-run-dir", "Specify directory to run programs from." },
+ { "--build-two-config", "Run CMake twice" },
+ { "--build-exe-dir", "Specify the directory for the executable." },
+ { "--build-generator", "Specify the generator to use." },
+ { "--build-generator-platform", "Specify the generator-specific platform." },
+ { "--build-generator-toolset", "Specify the generator-specific toolset." },
+ { "--build-project", "Specify the name of the project to build." },
+ { "--build-makeprogram", "Specify the make program to use." },
+ { "--build-noclean", "Skip the make clean step." },
+ { "--build-config-sample",
+ "A sample executable to use to determine the configuration" },
+ { "--build-options", "Add extra options to the build step." },
+
+ { "--test-command", "The test to run with the --build-and-test option." },
+ { "--test-timeout", "The time limit in seconds, internal use only." },
+ { "--test-load", "CPU load threshold for starting new parallel tests." },
+ { "--tomorrow-tag", "Nightly or experimental starts with next day tag." },
+ { "--overwrite", "Overwrite CTest configuration option." },
+ { "--extra-submit <file>[;<file>]", "Submit extra files to the dashboard." },
+ { "--force-new-ctest-process",
+ "Run child CTest instances as new processes" },
+ { "--schedule-random", "Use a random order for scheduling tests" },
+ { "--submit-index",
+ "Submit individual dashboard tests with specific index" },
+ { "--timeout <seconds>", "Set the default test timeout." },
+ { "--stop-time <time>",
+ "Set a time at which all tests should stop running." },
+ { "--http1.0", "Submit using HTTP 1.0." },
+ { "--no-compress-output", "Do not compress test output when submitting." },
+ { "--print-labels", "Print all available test labels." },
+ { "--no-tests=<[error|ignore]>",
+ "Regard no tests found either as 'error' or 'ignore' it." },
+ { nullptr, nullptr }
+};
+
+// this is a test driver program for cmCTest.
+int main(int argc, char const* const* argv)
+{
+ cmSystemTools::EnsureStdPipes();
+
+ // Replace streambuf so we can output Unicode to console
+ cmConsoleBuf consoleBuf;
+ consoleBuf.SetUTF8Pipes();
+
+ cmsys::Encoding::CommandLineArguments encoding_args =
+ cmsys::Encoding::CommandLineArguments::Main(argc, argv);
+ argc = encoding_args.argc();
+ argv = encoding_args.argv();
+
+ cmSystemTools::DoNotInheritStdPipes();
+ cmSystemTools::InitializeLibUV();
+ cmSystemTools::FindCMakeResources(argv[0]);
+
+ // Dispatch 'ctest --launch' mode directly.
+ if (argc >= 2 && strcmp(argv[1], "--launch") == 0) {
+ return cmCTestLaunch::Main(argc, argv);
+ }
+
+ cmCTest inst;
+
+ if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
+ cmCTestLog(&inst, ERROR_MESSAGE,
+ "Current working directory cannot be established."
+ << std::endl);
+ return 1;
+ }
+
+ // If there is a testing input file, check for documentation options
+ // only if there are actually arguments. We want running without
+ // arguments to run tests.
+ if (argc > 1 ||
+ !(cmSystemTools::FileExists("CTestTestfile.cmake") ||
+ cmSystemTools::FileExists("DartTestfile.txt"))) {
+ if (argc == 1) {
+ cmCTestLog(&inst, ERROR_MESSAGE,
+ "*********************************"
+ << std::endl
+ << "No test configuration file found!" << std::endl
+ << "*********************************" << std::endl);
+ }
+ cmDocumentation doc;
+ doc.addCTestStandardDocSections();
+ if (doc.CheckOptions(argc, argv)) {
+ // Construct and print requested documentation.
+ cmCTestScriptHandler* ch = inst.GetScriptHandler();
+ ch->CreateCMake();
+
+ doc.SetShowGenerators(false);
+ doc.SetName("ctest");
+ doc.SetSection("Name", cmDocumentationName);
+ doc.SetSection("Usage", cmDocumentationUsage);
+ doc.PrependSection("Options", cmDocumentationOptions);
+ return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
+ }
+ }
+
+ // copy the args to a vector
+ std::vector<std::string> args;
+ args.reserve(argc);
+ for (int i = 0; i < argc; ++i) {
+ args.emplace_back(argv[i]);
+ }
+ // run ctest
+ std::string output;
+ int res = inst.Run(args, &output);
+ cmCTestLog(&inst, OUTPUT, output);
+
+ return res;
+}
diff --git a/Source/dir.dox b/Source/dir.dox
new file mode 100644
index 0000000..66e3de7
--- /dev/null
+++ b/Source/dir.dox
@@ -0,0 +1,7 @@
+/*!
+
+\dir
+
+\brief Root \c ${CMake_SOURCE_DIR}/Source directory
+
+*/
diff --git a/Source/dir.dox.in b/Source/dir.dox.in
new file mode 100644
index 0000000..78cf58d
--- /dev/null
+++ b/Source/dir.dox.in
@@ -0,0 +1,7 @@
+/*!
+
+\dir
+
+\brief Generated \c ${CMake_BINARY_DIR}/Source directory
+
+*/
diff --git a/Source/kwsys/.gitattributes b/Source/kwsys/.gitattributes
new file mode 100644
index 0000000..7065eb5
--- /dev/null
+++ b/Source/kwsys/.gitattributes
@@ -0,0 +1,13 @@
+.git* export-ignore
+
+*.c kwsys-c-style
+*.c.in kwsys-c-style
+*.cxx kwsys-c-style
+*.h kwsys-c-style
+*.h.in kwsys-c-style
+*.hxx kwsys-c-style
+*.hxx.in kwsys-c-style
+
+*.cmake whitespace=tab-in-indent
+*.rst whitespace=tab-in-indent conflict-marker-size=79
+*.txt whitespace=tab-in-indent
diff --git a/Base64.c b/Source/kwsys/Base64.c
index 4265018..4265018 100644
--- a/Base64.c
+++ b/Source/kwsys/Base64.c
diff --git a/Base64.h.in b/Source/kwsys/Base64.h.in
index 729f972..729f972 100644
--- a/Base64.h.in
+++ b/Source/kwsys/Base64.h.in
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
new file mode 100644
index 0000000..bf8543e
--- /dev/null
+++ b/Source/kwsys/CMakeLists.txt
@@ -0,0 +1,1147 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing#kwsys for details.
+
+# The Kitware System Library is intended to be included in other
+# projects. It is completely configurable in that the library's
+# namespace can be configured and the components that are included can
+# be selected invididually.
+
+# Typical usage is to import the kwsys directory tree into a
+# subdirectory under a parent project and enable the classes that will
+# be used. All classes are disabled by default. The CMake listfile
+# above this one configures the library as follows:
+#
+# set(KWSYS_NAMESPACE foosys)
+# set(KWSYS_USE_Directory 1) # Enable Directory class.
+# add_subdirectory(kwsys)
+#
+# Optional settings are as follows:
+#
+# KWSYS_HEADER_ROOT = The directory into which to generate the kwsys headers.
+# A directory called "${KWSYS_NAMESPACE}" will be
+# created under this root directory to hold the files.
+# KWSYS_SPLIT_OBJECTS_FROM_INTERFACE
+# = Instead of creating a single ${KWSYS_NAMESPACE} library
+# target, create three separate targets:
+# ${KWSYS_NAMESPACE}
+# - An INTERFACE library only containing usage
+# requirements.
+# ${KWSYS_NAMESPACE}_objects
+# - An OBJECT library for the built kwsys objects.
+# Note: This is omitted from the install rules
+# ${KWSYS_NAMESPACE}_private
+# - An INTERFACE library combining both that is
+# appropriate for use with PRIVATE linking in
+# target_link_libraries. Because of how interface
+# properties propagate, this target is not suitable
+# for use with PUBLIC or INTERFACE linking.
+# KWSYS_ALIAS_TARGET = The name of an alias target to create to the actual target.
+#
+# Example:
+#
+# set(KWSYS_HEADER_ROOT ${PROJECT_BINARY_DIR})
+# include_directories(${PROJECT_BINARY_DIR})
+#
+# KWSYS_CXX_STANDARD = A value for CMAKE_CXX_STANDARD within KWSys.
+# Set to empty string to use no default value.
+# KWSYS_CXX_COMPILE_FEATURES = target_compile_features arguments for KWSys.
+#
+# Optional settings to setup install rules are as follows:
+#
+# KWSYS_INSTALL_BIN_DIR = The installation target directories into
+# KWSYS_INSTALL_LIB_DIR which the libraries and headers from
+# KWSYS_INSTALL_INCLUDE_DIR kwsys should be installed by a "make install".
+# The values should be specified relative to
+# the installation prefix and NOT start with '/'.
+# KWSYS_INSTALL_DOC_DIR = The installation target directory for documentation
+# such as copyright information.
+#
+# KWSYS_INSTALL_COMPONENT_NAME_RUNTIME = Name of runtime and development
+# KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT installation components.
+# If not given the install rules
+# will not be in any component.
+#
+# KWSYS_INSTALL_EXPORT_NAME = The EXPORT option value for install(TARGETS) calls.
+#
+# Example:
+#
+# set(KWSYS_INSTALL_BIN_DIR bin)
+# set(KWSYS_INSTALL_LIB_DIR lib)
+# set(KWSYS_INSTALL_INCLUDE_DIR include)
+# set(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME Runtime)
+# set(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT Development)
+
+# Once configured, kwsys should be used as follows from C or C++ code:
+#
+# #include <foosys/Directory.hxx>
+# ...
+# foosys::Directory directory;
+#
+
+# NOTE: This library is intended for internal use by Kitware-driven
+# projects. In order to keep it simple no attempt will be made to
+# maintain backward compatibility when changes are made to KWSys.
+# When an incompatible change is made Kitware's projects that use
+# KWSys will be fixed, but no notification will necessarily be sent to
+# any outside mailing list and no documentation of the change will be
+# written.
+
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+foreach(p
+ CMP0056 # CMake 3.2, Honor link flags in try_compile() source-file signature.
+ CMP0063 # CMake 3.3, Honor visibility properties for all target types.
+ CMP0067 # CMake 3.8, Honor language standard in try_compile source-file signature.
+ CMP0069 # CMake 3.9, INTERPROCEDURAL_OPTIMIZATION is enforced when enabled.
+ )
+ if(POLICY ${p})
+ cmake_policy(SET ${p} NEW)
+ endif()
+endforeach()
+
+#-----------------------------------------------------------------------------
+# If a namespace is not specified, use "kwsys" and enable testing.
+# This should be the case only when kwsys is not included inside
+# another project and is being tested.
+if(NOT KWSYS_NAMESPACE)
+ set(KWSYS_NAMESPACE "kwsys")
+ set(KWSYS_STANDALONE 1)
+endif()
+
+#-----------------------------------------------------------------------------
+# The project name is that of the specified namespace.
+project(${KWSYS_NAMESPACE})
+
+# Tell CMake how to follow dependencies of sources in this directory.
+set_property(DIRECTORY
+ PROPERTY IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
+ "KWSYS_HEADER(%)=<${KWSYS_NAMESPACE}/%>"
+ )
+
+if(KWSYS_CXX_STANDARD)
+ set(CMAKE_CXX_STANDARD "${KWSYS_CXX_STANDARD}")
+elseif(NOT DEFINED CMAKE_CXX_STANDARD AND NOT DEFINED KWSYS_CXX_STANDARD)
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
+ AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC"
+ AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU"
+ )
+ set(CMAKE_CXX_STANDARD 14)
+ else()
+ set(CMAKE_CXX_STANDARD 11)
+ endif()
+endif()
+
+# Select library components.
+if(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
+ set(KWSYS_ENABLE_C 1)
+ # Enable all components.
+ set(KWSYS_USE_Base64 1)
+ set(KWSYS_USE_Directory 1)
+ set(KWSYS_USE_DynamicLoader 1)
+ set(KWSYS_USE_Encoding 1)
+ set(KWSYS_USE_Glob 1)
+ set(KWSYS_USE_MD5 1)
+ set(KWSYS_USE_Process 1)
+ set(KWSYS_USE_RegularExpression 1)
+ set(KWSYS_USE_Status 1)
+ set(KWSYS_USE_System 1)
+ set(KWSYS_USE_SystemTools 1)
+ set(KWSYS_USE_CommandLineArguments 1)
+ set(KWSYS_USE_Terminal 1)
+ set(KWSYS_USE_FStream 1)
+ set(KWSYS_USE_String 1)
+ set(KWSYS_USE_SystemInformation 1)
+ set(KWSYS_USE_ConsoleBuf 1)
+endif()
+
+# Enforce component dependencies.
+if(KWSYS_USE_SystemTools)
+ set(KWSYS_USE_Directory 1)
+ set(KWSYS_USE_FStream 1)
+ set(KWSYS_USE_Encoding 1)
+ set(KWSYS_USE_Status 1)
+endif()
+if(KWSYS_USE_Glob)
+ set(KWSYS_USE_Directory 1)
+ set(KWSYS_USE_SystemTools 1)
+ set(KWSYS_USE_RegularExpression 1)
+ set(KWSYS_USE_FStream 1)
+ set(KWSYS_USE_Encoding 1)
+endif()
+if(KWSYS_USE_Process)
+ set(KWSYS_USE_System 1)
+ set(KWSYS_USE_Encoding 1)
+endif()
+if(KWSYS_USE_SystemInformation)
+ set(KWSYS_USE_Process 1)
+endif()
+if(KWSYS_USE_System)
+ set(KWSYS_USE_Encoding 1)
+endif()
+if(KWSYS_USE_Directory)
+ set(KWSYS_USE_Encoding 1)
+ set(KWSYS_USE_Status 1)
+endif()
+if(KWSYS_USE_DynamicLoader)
+ set(KWSYS_USE_Encoding 1)
+endif()
+if(KWSYS_USE_FStream)
+ set(KWSYS_USE_Encoding 1)
+endif()
+if(KWSYS_USE_ConsoleBuf)
+ set(KWSYS_USE_Encoding 1)
+endif()
+
+# Specify default 8 bit encoding for Windows
+if(NOT KWSYS_ENCODING_DEFAULT_CODEPAGE)
+ set(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_ACP)
+endif()
+
+# Enable testing if building standalone.
+if(KWSYS_STANDALONE)
+ include(Dart)
+ mark_as_advanced(BUILD_TESTING DART_ROOT TCL_TCLSH)
+ if(BUILD_TESTING)
+ enable_testing()
+ endif()
+endif()
+
+# Choose default shared/static build if not specified.
+if(NOT DEFINED KWSYS_BUILD_SHARED)
+ set(KWSYS_BUILD_SHARED ${BUILD_SHARED_LIBS})
+endif()
+
+# Include helper macros.
+include(${CMAKE_CURRENT_SOURCE_DIR}/kwsysPlatformTests.cmake)
+include(CheckTypeSize)
+
+# Do full dependency headers.
+include_regular_expression("^.*$")
+
+# Use new KWSYS_INSTALL_*_DIR variable names to control installation.
+# Take defaults from the old names. Note that there was no old name
+# for the bin dir, so we take the old lib dir name so DLLs will be
+# installed in a compatible way for old code.
+if(NOT KWSYS_INSTALL_INCLUDE_DIR)
+ string(REGEX REPLACE "^/" "" KWSYS_INSTALL_INCLUDE_DIR
+ "${KWSYS_HEADER_INSTALL_DIR}")
+endif()
+if(NOT KWSYS_INSTALL_LIB_DIR)
+ string(REGEX REPLACE "^/" "" KWSYS_INSTALL_LIB_DIR
+ "${KWSYS_LIBRARY_INSTALL_DIR}")
+endif()
+if(NOT KWSYS_INSTALL_BIN_DIR)
+ string(REGEX REPLACE "^/" "" KWSYS_INSTALL_BIN_DIR
+ "${KWSYS_LIBRARY_INSTALL_DIR}")
+endif()
+
+# Setup header install rules.
+set(KWSYS_INSTALL_INCLUDE_OPTIONS)
+if(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT)
+ set(KWSYS_INSTALL_INCLUDE_OPTIONS ${KWSYS_INSTALL_INCLUDE_OPTIONS}
+ COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT}
+ )
+endif()
+
+# Setup library install rules.
+set(KWSYS_INSTALL_LIBRARY_RULE)
+set(KWSYS_INSTALL_NAMELINK_RULE)
+if(KWSYS_INSTALL_LIB_DIR)
+ if(KWSYS_INSTALL_EXPORT_NAME)
+ list(APPEND KWSYS_INSTALL_LIBRARY_RULE EXPORT ${KWSYS_INSTALL_EXPORT_NAME})
+ endif()
+ # Install the shared library to the lib directory.
+ set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+ LIBRARY DESTINATION ${KWSYS_INSTALL_LIB_DIR} NAMELINK_SKIP
+ )
+ # Assign the shared library to the runtime component.
+ if(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME)
+ set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+ COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME}
+ )
+ endif()
+ if(KWSYS_BUILD_SHARED)
+ set(KWSYS_INSTALL_NAMELINK_RULE ${KWSYS_INSTALL_NAMELINK_RULE}
+ LIBRARY DESTINATION ${KWSYS_INSTALL_LIB_DIR} NAMELINK_ONLY
+ )
+ # Assign the namelink to the development component.
+ if(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT)
+ set(KWSYS_INSTALL_NAMELINK_RULE ${KWSYS_INSTALL_NAMELINK_RULE}
+ COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT}
+ )
+ endif()
+ endif()
+
+ # Install the archive to the lib directory.
+ set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+ ARCHIVE DESTINATION ${KWSYS_INSTALL_LIB_DIR}
+ )
+ # Assign the archive to the development component.
+ if(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT)
+ set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+ COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT}
+ )
+ endif()
+endif()
+if(KWSYS_INSTALL_BIN_DIR)
+ # Install the runtime library to the bin directory.
+ set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+ RUNTIME DESTINATION ${KWSYS_INSTALL_BIN_DIR}
+ )
+ # Assign the runtime library to the runtime component.
+ if(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME)
+ set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+ COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME}
+ )
+ endif()
+endif()
+
+# Do not support old KWSYS_*a_INSTALL_DIR variable names.
+set(KWSYS_HEADER_INSTALL_DIR)
+set(KWSYS_LIBRARY_INSTALL_DIR)
+
+# Generated source files will need this header.
+string(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}"
+ KWSYS_IN_SOURCE_BUILD)
+if(NOT KWSYS_IN_SOURCE_BUILD)
+ configure_file(${PROJECT_SOURCE_DIR}/kwsysPrivate.h
+ ${PROJECT_BINARY_DIR}/kwsysPrivate.h COPYONLY IMMEDIATE)
+endif()
+
+# Select plugin module file name convention.
+if(NOT KWSYS_DynamicLoader_PREFIX)
+ set(KWSYS_DynamicLoader_PREFIX ${CMAKE_SHARED_MODULE_PREFIX})
+endif()
+if(NOT KWSYS_DynamicLoader_SUFFIX)
+ set(KWSYS_DynamicLoader_SUFFIX ${CMAKE_SHARED_MODULE_SUFFIX})
+endif()
+
+#-----------------------------------------------------------------------------
+# We require ANSI support from the C compiler. Add any needed flags.
+if(CMAKE_ANSI_CFLAGS)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ANSI_CFLAGS}")
+endif()
+
+#-----------------------------------------------------------------------------
+# Adjust compiler flags for some platforms.
+if(NOT CMAKE_COMPILER_IS_GNUCXX)
+ if(CMAKE_SYSTEM MATCHES "OSF1-V.*")
+ string(REGEX MATCH "-timplicit_local"
+ KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL "${CMAKE_CXX_FLAGS}")
+ string(REGEX MATCH "-no_implicit_include"
+ KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE "${CMAKE_CXX_FLAGS}")
+ if(NOT KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -timplicit_local")
+ endif()
+ if(NOT KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no_implicit_include")
+ endif()
+ endif()
+ if(CMAKE_SYSTEM MATCHES "HP-UX")
+ set(KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS "+p")
+ if(CMAKE_CXX_COMPILER_ID MATCHES "HP")
+ # it is known that version 3.85 fails and 6.25 works without these flags
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4)
+ # use new C++ library and improved template support
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -AA +hpxstd98")
+ endif()
+ endif()
+ endif()
+endif()
+if(KWSYS_STANDALONE)
+ if(CMAKE_CXX_COMPILER_ID STREQUAL SunPro)
+ if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03")
+ else()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=stlport4")
+ endif()
+ endif()
+endif()
+
+#-----------------------------------------------------------------------------
+# Configure the standard library header wrappers based on compiler's
+# capabilities and parent project's request. Enforce 0/1 as only
+# possible values for configuration into Configure.hxx.
+
+if(KWSYS_USE_Encoding)
+ # Look for type size helper macros.
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_WSTRING
+ "Checking whether wstring is available" DIRECT)
+endif()
+
+if(KWSYS_NAMESPACE MATCHES "^kwsys$")
+ set(KWSYS_NAME_IS_KWSYS 1)
+else()
+ set(KWSYS_NAME_IS_KWSYS 0)
+endif()
+
+if(KWSYS_BUILD_SHARED)
+ set(KWSYS_BUILD_SHARED 1)
+ set(KWSYS_LIBRARY_TYPE SHARED)
+else()
+ set(KWSYS_BUILD_SHARED 0)
+ set(KWSYS_LIBRARY_TYPE STATIC)
+endif()
+
+if(NOT DEFINED KWSYS_BUILD_PIC)
+ set(KWSYS_BUILD_PIC 0)
+endif()
+
+#-----------------------------------------------------------------------------
+# Configure some implementation details.
+
+KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_PTRDIFF_T
+ "Checking whether C compiler has ptrdiff_t in stddef.h" DIRECT)
+KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_SSIZE_T
+ "Checking whether C compiler has ssize_t in unistd.h" DIRECT)
+if(KWSYS_USE_Process)
+ KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC
+ "Checking whether C compiler has clock_gettime" DIRECT)
+endif()
+
+set_source_files_properties(ProcessUNIX.c System.c PROPERTIES
+ COMPILE_FLAGS "-DKWSYS_C_HAS_PTRDIFF_T=${KWSYS_C_HAS_PTRDIFF_T} -DKWSYS_C_HAS_SSIZE_T=${KWSYS_C_HAS_SSIZE_T} -DKWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC=${KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC}"
+ )
+
+if(DEFINED KWSYS_PROCESS_USE_SELECT)
+ get_property(ProcessUNIX_FLAGS SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS)
+ set_property(SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS "${ProcessUNIX_FLAGS} -DKWSYSPE_USE_SELECT=${KWSYSPE_USE_SELECT}")
+endif()
+
+if(KWSYS_USE_DynamicLoader)
+ get_property(KWSYS_SUPPORTS_SHARED_LIBS GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS)
+ if(KWSYS_SUPPORTS_SHARED_LIBS)
+ set(KWSYS_SUPPORTS_SHARED_LIBS 1)
+ else()
+ set(KWSYS_SUPPORTS_SHARED_LIBS 0)
+ endif()
+ set_property(SOURCE DynamicLoader.cxx APPEND PROPERTY COMPILE_DEFINITIONS
+ KWSYS_SUPPORTS_SHARED_LIBS=${KWSYS_SUPPORTS_SHARED_LIBS})
+endif()
+
+if(KWSYS_USE_SystemTools)
+ if (NOT DEFINED KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP)
+ set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1)
+ endif ()
+ if (KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP)
+ set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1)
+ else ()
+ set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 0)
+ endif ()
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_SETENV
+ "Checking whether CXX compiler has setenv" DIRECT)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UNSETENV
+ "Checking whether CXX compiler has unsetenv" DIRECT)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
+ "Checking whether CXX compiler has environ in stdlib.h" DIRECT)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMES
+ "Checking whether CXX compiler has utimes" DIRECT)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMENSAT
+ "Checking whether CXX compiler has utimensat" DIRECT)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIM
+ "Checking whether CXX compiler struct stat has st_mtim member" DIRECT)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIMESPEC
+ "Checking whether CXX compiler struct stat has st_mtimespec member" DIRECT)
+ set_property(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS
+ KWSYS_CXX_HAS_SETENV=${KWSYS_CXX_HAS_SETENV}
+ KWSYS_CXX_HAS_UNSETENV=${KWSYS_CXX_HAS_UNSETENV}
+ KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=${KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H}
+ KWSYS_CXX_HAS_UTIMES=${KWSYS_CXX_HAS_UTIMES}
+ KWSYS_CXX_HAS_UTIMENSAT=${KWSYS_CXX_HAS_UTIMENSAT}
+ KWSYS_CXX_STAT_HAS_ST_MTIM=${KWSYS_CXX_STAT_HAS_ST_MTIM}
+ KWSYS_CXX_STAT_HAS_ST_MTIMESPEC=${KWSYS_CXX_STAT_HAS_ST_MTIMESPEC}
+ )
+ if(NOT WIN32)
+ if(KWSYS_STANDALONE)
+ option(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES "If true, Windows paths will be supported on Unix as well" ON)
+ endif()
+ if(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES)
+ set_property(SOURCE SystemTools.cxx testSystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS
+ KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES
+ )
+ endif()
+ endif()
+
+ # Disable getpwnam for static linux builds since it depends on shared glibc
+ get_property(SHARED_LIBS_SUPPORTED GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS)
+ if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT SHARED_LIBS_SUPPORTED)
+ set_property(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS
+ HAVE_GETPWNAM=0
+ )
+ endif()
+endif()
+
+if(KWSYS_USE_SystemInformation)
+ set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS SIZEOF_VOID_P=${CMAKE_SIZEOF_VOID_P})
+ if(NOT CYGWIN)
+ include(CheckIncludeFiles)
+ CHECK_INCLUDE_FILES("sys/types.h;ifaddrs.h" KWSYS_SYS_HAS_IFADDRS_H)
+ if(KWSYS_SYS_HAS_IFADDRS_H)
+ set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_SYS_HAS_IFADDRS_H=1)
+ endif()
+ endif()
+ if(WIN32)
+ include(CheckSymbolExists)
+ set(CMAKE_REQUIRED_LIBRARIES psapi)
+ CHECK_SYMBOL_EXISTS(GetProcessMemoryInfo "windows.h;psapi.h" KWSYS_SYS_HAS_PSAPI)
+ unset(CMAKE_REQUIRED_LIBRARIES)
+ if(KWSYS_SYS_HAS_PSAPI)
+ set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_SYS_HAS_PSAPI=1)
+ if(MSVC70 OR MSVC71)
+ # Suppress LNK4089: all references to 'PSAPI.DLL' discarded by /OPT:REF
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /IGNORE:4089")
+ endif()
+ endif()
+ endif()
+ if(CMAKE_SYSTEM MATCHES "HP-UX")
+ CHECK_INCLUDE_FILES("sys/mpctl.h" KWSYS_SYS_HAS_MPCTL_H)
+ if(KWSYS_SYS_HAS_MPCTL_H)
+ set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_SYS_HAS_MPCTL_H=1)
+ endif()
+ endif()
+ if(CMAKE_SYSTEM MATCHES "BSD")
+ CHECK_INCLUDE_FILES("machine/cpu.h" KWSYS_SYS_HAS_MACHINE_CPU_H)
+ if(KWSYS_SYS_HAS_MACHINE_CPU_H)
+ set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_SYS_HAS_MACHINE_CPU_H=1)
+ endif()
+ endif()
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_RLIMIT64
+ "Checking whether CXX compiler has rlimit64" DIRECT)
+ set(KWSYS_PLATFORM_CXX_TEST_DEFINES)
+ if(KWSYS_CXX_HAS_RLIMIT64)
+ set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_CXX_HAS_RLIMIT64=1)
+ endif()
+ if(UNIX)
+ include(CheckIncludeFileCXX)
+ # check for simple stack trace
+ # usually it's in libc but on FreeBSD
+ # it's in libexecinfo
+ find_library(EXECINFO_LIB "execinfo")
+ mark_as_advanced(EXECINFO_LIB)
+ if (NOT EXECINFO_LIB)
+ set(EXECINFO_LIB "")
+ endif()
+ CHECK_INCLUDE_FILE_CXX("execinfo.h" KWSYS_CXX_HAS_EXECINFOH)
+ if (KWSYS_CXX_HAS_EXECINFOH)
+ # we have the backtrace header check if it
+ # can be used with this compiler
+ set(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${EXECINFO_LIB})
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BACKTRACE
+ "Checking whether backtrace works with this C++ compiler" DIRECT)
+ set(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES)
+ if (KWSYS_CXX_HAS_BACKTRACE)
+ # backtrace is supported by this system and compiler.
+ # now check for the more advanced capabilities.
+ set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE=1)
+ # check for symbol lookup using dladdr
+ CHECK_INCLUDE_FILE_CXX("dlfcn.h" KWSYS_CXX_HAS_DLFCNH)
+ if (KWSYS_CXX_HAS_DLFCNH)
+ # we have symbol lookup libraries and headers
+ # check if they can be used with this compiler
+ set(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${CMAKE_DL_LIBS})
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_DLADDR
+ "Checking whether dladdr works with this C++ compiler" DIRECT)
+ set(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES)
+ if (KWSYS_CXX_HAS_DLADDR)
+ # symbol lookup is supported by this system
+ # and compiler.
+ set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP=1)
+ endif()
+ endif()
+ # c++ demangling support
+ # check for cxxabi headers
+ CHECK_INCLUDE_FILE_CXX("cxxabi.h" KWSYS_CXX_HAS_CXXABIH)
+ if (KWSYS_CXX_HAS_CXXABIH)
+ # check if cxxabi can be used with this
+ # system and compiler.
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CXXABI
+ "Checking whether cxxabi works with this C++ compiler" DIRECT)
+ if (KWSYS_CXX_HAS_CXXABI)
+ # c++ demangle using cxxabi is supported with
+ # this system and compiler
+ set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE=1)
+ endif()
+ endif()
+ # basic backtrace works better with release build
+ # don't bother with advanced features for release
+ set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS_DEBUG KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1)
+ set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS_RELWITHDEBINFO KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1)
+ endif()
+ endif()
+ endif()
+ if(KWSYS_BUILD_SHARED)
+ set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_BUILD_SHARED=1)
+ endif()
+
+ if(UNIX AND NOT CYGWIN)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_GETLOADAVG
+ "Checking whether CXX compiler has getloadavg" DIRECT)
+ if(KWSYS_CXX_HAS_GETLOADAVG)
+ set_property(SOURCE SystemInformation.cxx APPEND PROPERTY
+ COMPILE_DEFINITIONS KWSYS_CXX_HAS_GETLOADAVG=1)
+ endif()
+ endif()
+endif()
+
+if(KWSYS_USE_FStream)
+ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H
+ "Checking whether <ext/stdio_filebuf.h> is available" DIRECT)
+endif()
+
+#-----------------------------------------------------------------------------
+# Choose a directory for the generated headers.
+if(NOT KWSYS_HEADER_ROOT)
+ set(KWSYS_HEADER_ROOT "${PROJECT_BINARY_DIR}")
+endif()
+set(KWSYS_HEADER_DIR "${KWSYS_HEADER_ROOT}/${KWSYS_NAMESPACE}")
+include_directories(${KWSYS_HEADER_ROOT})
+
+#-----------------------------------------------------------------------------
+if(KWSYS_INSTALL_DOC_DIR)
+ # Assign the license to the runtime component since it must be
+ # distributed with binary forms of this software.
+ if(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME)
+ set(KWSYS_INSTALL_LICENSE_OPTIONS ${KWSYS_INSTALL_LICENSE_OPTIONS}
+ COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME}
+ )
+ endif()
+
+ # Install the license under the documentation directory.
+ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/Copyright.txt
+ DESTINATION ${KWSYS_INSTALL_DOC_DIR}/${KWSYS_NAMESPACE}
+ ${KWSYS_INSTALL_LICENSE_OPTIONS})
+endif()
+
+#-----------------------------------------------------------------------------
+# Build a list of classes and headers we need to implement the
+# selected components. Initialize with required components.
+set(KWSYS_CLASSES)
+set(KWSYS_H_FILES Configure SharedForward)
+set(KWSYS_HXX_FILES Configure String)
+
+# Add selected C++ classes.
+set(cppclasses
+ Directory DynamicLoader Encoding Glob RegularExpression SystemTools
+ CommandLineArguments FStream SystemInformation ConsoleBuf Status
+ )
+foreach(cpp ${cppclasses})
+ if(KWSYS_USE_${cpp})
+ # Use the corresponding class.
+ set(KWSYS_CLASSES ${KWSYS_CLASSES} ${cpp})
+
+ # Load component-specific CMake code.
+ if(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake)
+ include(${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake)
+ endif()
+ endif()
+endforeach()
+
+# Add selected C components.
+foreach(c
+ Process Base64 Encoding MD5 Terminal System String
+ )
+ if(KWSYS_USE_${c})
+ # Use the corresponding header file.
+ set(KWSYS_H_FILES ${KWSYS_H_FILES} ${c})
+
+ # Load component-specific CMake code.
+ if(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${c}.cmake)
+ include(${PROJECT_SOURCE_DIR}/kwsys${c}.cmake)
+ endif()
+ endif()
+endforeach()
+
+#-----------------------------------------------------------------------------
+# Build a list of sources for the library based on components that are
+# included.
+set(KWSYS_C_SRCS)
+set(KWSYS_CXX_SRCS)
+
+# Add the proper sources for this platform's Process implementation.
+if(KWSYS_USE_Process)
+ if(NOT UNIX)
+ # Use the Windows implementation.
+ set(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessWin32.c)
+ else()
+ # Use the UNIX implementation.
+ set(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessUNIX.c)
+ endif()
+endif()
+
+# Add selected C sources.
+foreach(c Base64 Encoding MD5 Terminal System String)
+ if(KWSYS_USE_${c})
+ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}C.c)
+ list(APPEND KWSYS_C_SRCS ${c}C.c)
+ else()
+ list(APPEND KWSYS_C_SRCS ${c}.c)
+ endif()
+ endif()
+endforeach()
+
+# Configure headers of C++ classes and construct the list of sources.
+foreach(c ${KWSYS_CLASSES})
+ # Add this source to the list of source files for the library.
+ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}CXX.cxx)
+ list(APPEND KWSYS_CXX_SRCS ${c}CXX.cxx)
+ elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}.cxx)
+ list(APPEND KWSYS_CXX_SRCS ${c}.cxx)
+ endif()
+
+ # Configure the header for this class.
+ configure_file(${PROJECT_SOURCE_DIR}/${c}.hxx.in ${KWSYS_HEADER_DIR}/${c}.hxx
+ @ONLY IMMEDIATE)
+ set(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${c}.hxx)
+
+ # Create an install target for the header.
+ if(KWSYS_INSTALL_INCLUDE_DIR)
+ install(FILES ${KWSYS_HEADER_DIR}/${c}.hxx
+ DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
+ ${KWSYS_INSTALL_INCLUDE_OPTIONS})
+ endif()
+endforeach()
+
+# Configure C headers.
+foreach(h ${KWSYS_H_FILES})
+ # Configure the header into the given directory.
+ configure_file(${PROJECT_SOURCE_DIR}/${h}.h.in ${KWSYS_HEADER_DIR}/${h}.h
+ @ONLY IMMEDIATE)
+ set(KWSYS_C_SRCS ${KWSYS_C_SRCS} ${KWSYS_HEADER_DIR}/${h}.h)
+
+ # Create an install target for the header.
+ if(KWSYS_INSTALL_INCLUDE_DIR)
+ install(FILES ${KWSYS_HEADER_DIR}/${h}.h
+ DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
+ ${KWSYS_INSTALL_INCLUDE_OPTIONS})
+ endif()
+endforeach()
+
+# Configure other C++ headers.
+foreach(h ${KWSYS_HXX_FILES})
+ # Configure the header into the given directory.
+ configure_file(${PROJECT_SOURCE_DIR}/${h}.hxx.in ${KWSYS_HEADER_DIR}/${h}.hxx
+ @ONLY IMMEDIATE)
+ set(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${h}.hxx)
+
+ # Create an install target for the header.
+ if(KWSYS_INSTALL_INCLUDE_DIR)
+ install(FILES ${KWSYS_HEADER_DIR}/${h}.hxx
+ DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
+ ${KWSYS_INSTALL_INCLUDE_OPTIONS})
+ endif()
+endforeach()
+
+#-----------------------------------------------------------------------------
+# Add the library with the configured name and list of sources.
+if(KWSYS_C_SRCS OR KWSYS_CXX_SRCS)
+ if(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE)
+ set(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE})
+ set(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE}_objects)
+ set(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE}_private)
+ set(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_INTERFACE} ${KWSYS_TARGET_LINK})
+ set(KWSYS_LINK_DEPENDENCY INTERFACE)
+ add_library(${KWSYS_TARGET_OBJECT} OBJECT
+ ${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS})
+ if(KWSYS_BUILD_SHARED OR KWSYS_BUILD_PIC)
+ set_property(TARGET ${KWSYS_TARGET_OBJECT} PROPERTY
+ POSITION_INDEPENDENT_CODE TRUE)
+ endif()
+ add_library(${KWSYS_TARGET_INTERFACE} INTERFACE)
+ add_library(${KWSYS_TARGET_LINK} INTERFACE)
+ target_link_libraries(${KWSYS_TARGET_LINK} INTERFACE
+ ${KWSYS_TARGET_INTERFACE})
+ target_sources(${KWSYS_TARGET_LINK} INTERFACE
+ $<TARGET_OBJECTS:${KWSYS_TARGET_OBJECT}>)
+ target_compile_features(${KWSYS_TARGET_OBJECT} PRIVATE ${KWSYS_CXX_COMPILE_FEATURES})
+ target_compile_features(${KWSYS_TARGET_INTERFACE} INTERFACE ${KWSYS_CXX_COMPILE_FEATURES})
+ else()
+ set(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE})
+ set(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE})
+ set(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE})
+ set(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_LINK})
+ set(KWSYS_LINK_DEPENDENCY PUBLIC)
+ add_library(${KWSYS_TARGET_INTERFACE} ${KWSYS_LIBRARY_TYPE}
+ ${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS})
+ target_compile_features(${KWSYS_TARGET_INTERFACE} PUBLIC ${KWSYS_CXX_COMPILE_FEATURES})
+ endif()
+ if (KWSYS_ALIAS_TARGET)
+ add_library(${KWSYS_ALIAS_TARGET} ALIAS ${KWSYS_TARGET_INTERFACE})
+ endif ()
+ set_target_properties(${KWSYS_TARGET_OBJECT} PROPERTIES
+ C_CLANG_TIDY ""
+ CXX_CLANG_TIDY ""
+ C_INCLUDE_WHAT_YOU_USE ""
+ CXX_INCLUDE_WHAT_YOU_USE ""
+ LABELS "${KWSYS_LABELS_LIB}")
+ if(KWSYS_USE_DynamicLoader)
+ if(UNIX)
+ target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
+ ${CMAKE_DL_LIBS})
+ endif()
+ endif()
+
+ if(KWSYS_USE_SystemInformation)
+ if(WIN32)
+ target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} ws2_32)
+ # link in dbghelp.dll for symbol lookup if MSVC 1800 or later
+ # Note that the dbghelp runtime is part of MS Windows OS
+ if(MSVC_VERSION AND NOT MSVC_VERSION VERSION_LESS 1800)
+ target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} dbghelp)
+ endif()
+ if(KWSYS_SYS_HAS_PSAPI)
+ target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
+ psapi)
+ endif()
+ elseif(UNIX)
+ if (EXECINFO_LIB AND KWSYS_CXX_HAS_BACKTRACE)
+ # backtrace on FreeBSD is not in libc
+ target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
+ ${EXECINFO_LIB})
+ endif()
+ if (KWSYS_CXX_HAS_DLADDR)
+ # for symbol lookup using dladdr
+ target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
+ ${CMAKE_DL_LIBS})
+ endif()
+ if (CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+ target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
+ socket)
+ endif()
+ endif()
+ endif()
+
+ # Apply user-defined target properties to the library.
+ if(KWSYS_PROPERTIES_CXX)
+ set_target_properties(${KWSYS_TARGET_INTERFACE} PROPERTIES
+ ${KWSYS_PROPERTIES_CXX})
+ endif()
+
+ # Set up include usage requirement
+ if(COMMAND TARGET_INCLUDE_DIRECTORIES)
+ target_include_directories(${KWSYS_TARGET_INTERFACE} INTERFACE
+ $<BUILD_INTERFACE:${KWSYS_HEADER_ROOT}>)
+ if(KWSYS_INSTALL_INCLUDE_DIR)
+ target_include_directories(${KWSYS_TARGET_INTERFACE} INTERFACE
+ $<INSTALL_INTERFACE:${KWSYS_INSTALL_INCLUDE_DIR}>)
+ endif()
+ endif()
+
+ # Create an install target for the library.
+ if(KWSYS_INSTALL_LIBRARY_RULE)
+ install(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_LIBRARY_RULE})
+ endif()
+ if(KWSYS_INSTALL_NAMELINK_RULE)
+ install(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_NAMELINK_RULE})
+ endif()
+endif()
+
+# Add a C-only library if requested.
+if(KWSYS_ENABLE_C AND KWSYS_C_SRCS)
+ if(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE)
+ set(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c)
+ set(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c_objects)
+ set(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c_private)
+ set(KWSYS_TARGET_C_INSTALL
+ ${KWSYS_TARGET_C_INTERFACE} ${KWSYS_TARGET_C_LINK})
+ set(KWSYS_LINK_DEPENDENCY INTERFACE)
+ add_library(${KWSYS_TARGET_C_OBJECT} OBJECT ${KWSYS_C_SRCS})
+ if(KWSYS_BUILD_SHARED OR KWSYS_BUILD_PIC)
+ set_property(TARGET ${KWSYS_TARGET_C_OBJECT} PROPERTY
+ POSITION_INDEPENDENT_CODE TRUE)
+ endif()
+ add_library(${KWSYS_TARGET_C_INTERFACE} INTERFACE)
+ add_library(${KWSYS_TARGET_C_LINK} INTERFACE)
+ target_link_libraries(${KWSYS_TARGET_C_LINK} INTERFACE
+ ${KWSYS_TARGET_C_INTERFACE})
+ target_sources(${KWSYS_TARGET_C_LINK} INTERFACE
+ $<TARGET_OBJECTS:${KWSYS_TARGET_C_OBJECT}>)
+ else()
+ set(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c)
+ set(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c)
+ set(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c)
+ set(KWSYS_TARGET_C_INSTALL ${KWSYS_TARGET_C_LINK})
+ set(KWSYS_LINK_DEPENDENCY PUBLIC)
+ add_library(${KWSYS_TARGET_C_INTERFACE} ${KWSYS_LIBRARY_TYPE}
+ ${KWSYS_C_SRCS})
+ endif()
+ set_target_properties(${KWSYS_TARGET_C_OBJECT} PROPERTIES
+ LABELS "${KWSYS_LABELS_LIB}")
+
+ # Apply user-defined target properties to the library.
+ if(KWSYS_PROPERTIES_C)
+ set_target_properties(${KWSYS_TARGET_C_INTERFACE} PROPERTIES
+ ${KWSYS_PROPERTIES_C})
+ endif()
+
+ # Set up include usage requirement
+ if(COMMAND TARGET_INCLUDE_DIRECTORIES)
+ target_include_directories(${KWSYS_TARGET_C_INTERFACE} INTERFACE
+ $<BUILD_INTERFACE:${KWSYS_HEADER_ROOT}>)
+ if(KWSYS_INSTALL_INCLUDE_DIR)
+ target_include_directories(${KWSYS_TARGET_C_INTERFACE} INTERFACE
+ $<INSTALL_INTERFACE:${KWSYS_INSTALL_INCLUDE_DIR}>)
+ endif()
+ endif()
+
+ # Create an install target for the library.
+ if(KWSYS_INSTALL_LIBRARY_RULE)
+ install(TARGETS ${KWSYS_TARGET_C_INSTALL})
+ endif()
+endif()
+
+# For building kwsys itself, we use a macro defined on the command
+# line to configure the namespace in the C and C++ source files.
+add_definitions("-DKWSYS_NAMESPACE=${KWSYS_NAMESPACE}")
+
+# Disable deprecation warnings for standard C functions.
+if(MSVC OR (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "Intel" OR
+ (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC"))))
+ add_definitions(
+ -D_CRT_NONSTDC_NO_DEPRECATE
+ -D_CRT_SECURE_NO_DEPRECATE
+ -D_CRT_SECURE_NO_WARNINGS
+ -D_SCL_SECURE_NO_DEPRECATE
+ )
+endif()
+
+if(WIN32)
+ # Help enforce the use of wide Windows apis.
+ add_definitions(-DUNICODE -D_UNICODE)
+endif()
+
+if(KWSYS_USE_String)
+ # Activate code in "String.c". See the comment in the source.
+ set_source_files_properties(String.c PROPERTIES
+ COMPILE_FLAGS "-DKWSYS_STRING_C")
+endif()
+
+if(KWSYS_USE_Encoding)
+ # Set default 8 bit encoding in "EndcodingC.c".
+ set_property(SOURCE EncodingC.c EncodingCXX.cxx APPEND PROPERTY COMPILE_DEFINITIONS
+ KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
+endif()
+
+#-----------------------------------------------------------------------------
+# Setup testing if not being built as part of another project.
+if(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
+ if(BUILD_TESTING)
+ # Compute the location of executables.
+ set(EXEC_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+ if(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
+ set(EXEC_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
+ endif()
+
+ # C tests
+ set(KWSYS_C_TESTS
+ testEncode.c
+ testTerminal.c
+ )
+ if(KWSYS_STANDALONE)
+ set(KWSYS_C_TESTS ${KWSYS_C_TESTS} testFail.c)
+ endif()
+ create_test_sourcelist(
+ KWSYS_C_TEST_SRCS ${KWSYS_NAMESPACE}TestsC.c
+ ${KWSYS_C_TESTS}
+ )
+ add_executable(${KWSYS_NAMESPACE}TestsC ${KWSYS_C_TEST_SRCS})
+ set_property(TARGET ${KWSYS_NAMESPACE}TestsC PROPERTY LABELS ${KWSYS_LABELS_EXE})
+ target_link_libraries(${KWSYS_NAMESPACE}TestsC ${KWSYS_TARGET_C_LINK})
+ foreach(testfile ${KWSYS_C_TESTS})
+ get_filename_component(test "${testfile}" NAME_WE)
+ add_test(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsC ${test} ${KWSYS_TEST_ARGS_${test}})
+ set_property(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST})
+ endforeach()
+
+ # C++ tests
+ set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
+ testConfigure.cxx
+ testStatus.cxx
+ testSystemTools.cxx
+ testCommandLineArguments.cxx
+ testCommandLineArguments1.cxx
+ testDirectory.cxx
+ )
+ if(KWSYS_STL_HAS_WSTRING)
+ set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
+ testEncoding.cxx
+ )
+ endif()
+ if(KWSYS_USE_FStream)
+ set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
+ testFStream.cxx
+ )
+ endif()
+ if(KWSYS_USE_ConsoleBuf)
+ add_executable(testConsoleBufChild testConsoleBufChild.cxx)
+ set_property(TARGET testConsoleBufChild PROPERTY C_CLANG_TIDY "")
+ set_property(TARGET testConsoleBufChild PROPERTY CXX_CLANG_TIDY "")
+ set_property(TARGET testConsoleBufChild PROPERTY C_INCLUDE_WHAT_YOU_USE "")
+ set_property(TARGET testConsoleBufChild PROPERTY CXX_INCLUDE_WHAT_YOU_USE "")
+ set_property(TARGET testConsoleBufChild PROPERTY LABELS ${KWSYS_LABELS_EXE})
+ target_link_libraries(testConsoleBufChild ${KWSYS_TARGET_LINK})
+ set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
+ testConsoleBuf.cxx
+ )
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND
+ CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "19.0.23506")
+ set_property(SOURCE testConsoleBuf.cxx testConsoleBufChild.cxx PROPERTY COMPILE_FLAGS /utf-8)
+ endif()
+ set_property(SOURCE testConsoleBuf.cxx APPEND PROPERTY COMPILE_DEFINITIONS
+ KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
+ endif()
+ if(KWSYS_USE_SystemInformation)
+ set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation.cxx)
+ endif()
+ if(KWSYS_USE_DynamicLoader)
+ set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testDynamicLoader.cxx)
+ # If kwsys contains the DynamicLoader, need extra library
+ add_library(${KWSYS_NAMESPACE}TestDynload MODULE testDynload.c)
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynload PROPERTY LABELS ${KWSYS_LABELS_LIB})
+ add_dependencies(${KWSYS_NAMESPACE}TestDynload ${KWSYS_TARGET_INTERFACE})
+
+ if (WIN32)
+ # Windows tests supported flags.
+ add_library(${KWSYS_NAMESPACE}TestDynloadImpl SHARED testDynloadImpl.c)
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY LABELS ${KWSYS_LABELS_LIB})
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY DEFINE_SYMBOL BUILDING_TestDynloadImpl)
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir")
+ add_dependencies(${KWSYS_NAMESPACE}TestDynloadImpl ${KWSYS_TARGET_INTERFACE})
+ add_library(${KWSYS_NAMESPACE}TestDynloadUse MODULE testDynloadUse.c)
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LABELS ${KWSYS_LABELS_LIB})
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir")
+ add_dependencies(${KWSYS_NAMESPACE}TestDynloadUse ${KWSYS_TARGET_INTERFACE})
+ target_link_libraries(${KWSYS_NAMESPACE}TestDynloadUse PRIVATE ${KWSYS_NAMESPACE}TestDynloadImpl)
+ endif ()
+ endif()
+ create_test_sourcelist(
+ KWSYS_CXX_TEST_SRCS ${KWSYS_NAMESPACE}TestsCxx.cxx
+ ${KWSYS_CXX_TESTS}
+ )
+ add_executable(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_CXX_TEST_SRCS})
+ set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_CLANG_TIDY "")
+ set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_CLANG_TIDY "")
+ set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_INCLUDE_WHAT_YOU_USE "")
+ set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_INCLUDE_WHAT_YOU_USE "")
+ set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY LABELS ${KWSYS_LABELS_EXE})
+ target_link_libraries(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_TARGET_LINK})
+
+ set(TEST_SYSTEMTOOLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ set(TEST_SYSTEMTOOLS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/testSystemTools.h.in
+ ${PROJECT_BINARY_DIR}/testSystemTools.h)
+ include_directories(${PROJECT_BINARY_DIR})
+
+ if(CTEST_TEST_KWSYS)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/ExtraTest.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake")
+ set_directory_properties(PROPERTIES TEST_INCLUDE_FILE "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake")
+ endif()
+
+ set(KWSYS_TEST_ARGS_testCommandLineArguments
+ --another-bool-variable
+ --long3=opt
+ --set-bool-arg1
+ -SSS ken brad bill andy
+ --some-bool-variable=true
+ --some-double-variable12.5
+ --some-int-variable 14
+ "--some-string-variable=test string with space"
+ --some-multi-argument 5 1 8 3 7 1 3 9 7 1
+ -N 12.5 -SS=andy -N 1.31 -N 22
+ -SS=bill -BBtrue -SS=brad
+ -BBtrue
+ -BBfalse
+ -SS=ken
+ -A
+ -C=test
+ --long2 hello
+ )
+ set(KWSYS_TEST_ARGS_testCommandLineArguments1
+ --ignored
+ -n 24
+ --second-ignored
+ "-m=test value"
+ third-ignored
+ -p
+ some junk at the end
+ )
+ foreach(testfile ${KWSYS_CXX_TESTS})
+ get_filename_component(test "${testfile}" NAME_WE)
+ add_test(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsCxx ${test} ${KWSYS_TEST_ARGS_${test}})
+ set_property(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST})
+ endforeach()
+
+ # Process tests.
+ add_executable(${KWSYS_NAMESPACE}TestProcess testProcess.c)
+ set_property(TARGET ${KWSYS_NAMESPACE}TestProcess PROPERTY LABELS ${KWSYS_LABELS_EXE})
+ target_link_libraries(${KWSYS_NAMESPACE}TestProcess ${KWSYS_TARGET_C_LINK})
+ #set(KWSYS_TEST_PROCESS_7 7) # uncomment to run timing-sensitive test locally
+ foreach(n 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7} 9 10)
+ add_test(kwsys.testProcess-${n} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestProcess ${n})
+ set_property(TEST kwsys.testProcess-${n} PROPERTY LABELS ${KWSYS_LABELS_TEST})
+ set_tests_properties(kwsys.testProcess-${n} PROPERTIES TIMEOUT 120)
+ endforeach()
+
+ set(testProcess_COMPILE_FLAGS "")
+ # Some Apple compilers produce bad optimizations in this source.
+ if(APPLE AND CMAKE_C_COMPILER_ID MATCHES "^(GNU|LLVM)$")
+ set(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -O0")
+ elseif(CMAKE_C_COMPILER_ID STREQUAL "XL")
+ # Tell IBM XL not to warn about our test infinite loop
+ if(CMAKE_SYSTEM MATCHES "Linux.*ppc64le"
+ AND CMAKE_C_COMPILER_VERSION VERSION_LESS "16.1.0"
+ AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS "13.1.1")
+ # v13.1.[1-6] on Linux ppc64le is clang based and does not accept
+ # the -qsuppress option, so just suppress all warnings.
+ set(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -w")
+ else()
+ set(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -qsuppress=1500-010")
+ endif()
+ endif()
+ if(CMAKE_C_FLAGS MATCHES "-fsanitize=")
+ set(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -DCRASH_USING_ABORT")
+ endif()
+ set_property(SOURCE testProcess.c PROPERTY COMPILE_FLAGS "${testProcess_COMPILE_FLAGS}")
+
+ # Test SharedForward
+ configure_file(${PROJECT_SOURCE_DIR}/testSharedForward.c.in
+ ${PROJECT_BINARY_DIR}/testSharedForward.c @ONLY IMMEDIATE)
+ add_executable(${KWSYS_NAMESPACE}TestSharedForward
+ ${PROJECT_BINARY_DIR}/testSharedForward.c)
+ set_property(TARGET ${KWSYS_NAMESPACE}TestSharedForward PROPERTY LABELS ${KWSYS_LABELS_EXE})
+ add_dependencies(${KWSYS_NAMESPACE}TestSharedForward ${KWSYS_TARGET_C_LINK})
+ add_test(kwsys.testSharedForward ${EXEC_DIR}/${KWSYS_NAMESPACE}TestSharedForward 1)
+ set_property(TEST kwsys.testSharedForward PROPERTY LABELS ${KWSYS_LABELS_TEST})
+
+ # Configure some test properties.
+ if(KWSYS_STANDALONE)
+ # We expect test to fail
+ set_tests_properties(kwsys.testFail PROPERTIES WILL_FAIL ON)
+ get_test_property(kwsys.testFail WILL_FAIL wfv)
+ set_tests_properties(kwsys.testFail PROPERTIES MEASUREMENT "Some Key=Some Value")
+ message(STATUS "GET_TEST_PROPERTY returned: ${wfv}")
+ endif()
+
+ # Set up ctest custom configuration file.
+ configure_file(${PROJECT_SOURCE_DIR}/CTestCustom.cmake.in
+ ${PROJECT_BINARY_DIR}/CTestCustom.cmake @ONLY)
+
+ # Suppress known consistent failures on buggy systems.
+ if(KWSYS_TEST_BOGUS_FAILURES)
+ set_tests_properties(${KWSYS_TEST_BOGUS_FAILURES} PROPERTIES WILL_FAIL ON)
+ endif()
+
+ endif()
+endif()
diff --git a/Source/kwsys/CONTRIBUTING.rst b/Source/kwsys/CONTRIBUTING.rst
new file mode 100644
index 0000000..32e7b83
--- /dev/null
+++ b/Source/kwsys/CONTRIBUTING.rst
@@ -0,0 +1,49 @@
+Contributing to KWSys
+*********************
+
+Patches
+=======
+
+KWSys is kept in its own Git repository and shared by several projects
+via copies in their source trees. Changes to KWSys should not be made
+directly in a host project, except perhaps in maintenance branches.
+
+KWSys uses `Kitware's GitLab Instance`_ to manage development and code review.
+To contribute patches:
+
+#. Fork the upstream `KWSys Repository`_ into a personal account.
+#. Base all new work on the upstream ``master`` branch.
+#. Run ``./SetupForDevelopment.sh`` in new local work trees.
+#. Create commits making incremental, distinct, logically complete changes.
+#. Push a topic branch to a personal repository fork on GitLab.
+#. Create a GitLab Merge Request targeting the upstream ``master`` branch.
+
+Once changes are reviewed, tested, and integrated to KWSys upstream then
+copies of KWSys within dependent projects can be updated to get the changes.
+
+.. _`Kitware's GitLab Instance`: https://gitlab.kitware.com
+.. _`KWSys Repository`: https://gitlab.kitware.com/utils/kwsys
+
+Code Style
+==========
+
+We use `clang-format`_ version **6.0** to define our style for C++ code in
+the KWSys source tree. See the `.clang-format`_ configuration file for
+our style settings. Use the `clang-format.bash`_ script to format source
+code. It automatically runs ``clang-format`` on the set of source files
+for which we enforce style. The script also has options to format only
+a subset of files, such as those that are locally modified.
+
+.. _`clang-format`: http://clang.llvm.org/docs/ClangFormat.html
+.. _`.clang-format`: .clang-format
+.. _`clang-format.bash`: clang-format.bash
+
+License
+=======
+
+We do not require any formal copyright assignment or contributor license
+agreement. Any contributions intentionally sent upstream are presumed
+to be offered under terms of the OSI-approved BSD 3-clause License.
+See `Copyright.txt`_ for details.
+
+.. _`Copyright.txt`: Copyright.txt
diff --git a/Source/kwsys/CTestConfig.cmake b/Source/kwsys/CTestConfig.cmake
new file mode 100644
index 0000000..12347b6
--- /dev/null
+++ b/Source/kwsys/CTestConfig.cmake
@@ -0,0 +1,11 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing#kwsys for details.
+
+set(CTEST_PROJECT_NAME "KWSys")
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+if (NOT CTEST_DROP_METHOD STREQUAL "https")
+ set(CTEST_DROP_METHOD "http")
+endif ()
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
+set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/Source/kwsys/CTestCustom.cmake.in b/Source/kwsys/CTestCustom.cmake.in
new file mode 100644
index 0000000..c07f0f3
--- /dev/null
+++ b/Source/kwsys/CTestCustom.cmake.in
@@ -0,0 +1,18 @@
+# kwsys.testProcess-10 involves sending SIGINT to a child process, which then
+# exits abnormally via a call to _exit(). (On Windows, a call to ExitProcess).
+# Naturally, this results in plenty of memory being "leaked" by this child
+# process - the memory check results are not meaningful in this case.
+#
+# kwsys.testProcess-9 also tests sending SIGINT to a child process. However,
+# normal operation of that test involves the child process timing out, and the
+# host process kills (SIGKILL) it as a result. Since it was SIGKILL'ed, the
+# resulting memory leaks are not logged by valgrind anyway. Therefore, we
+# don't have to exclude it.
+
+list(APPEND CTEST_CUSTOM_MEMCHECK_IGNORE
+ kwsys.testProcess-10
+ )
+
+list(APPEND CTEST_CUSTOM_WARNING_EXCEPTION
+ "LICENSE WARNING"
+ )
diff --git a/CommandLineArguments.cxx b/Source/kwsys/CommandLineArguments.cxx
index e45db36..e45db36 100644
--- a/CommandLineArguments.cxx
+++ b/Source/kwsys/CommandLineArguments.cxx
diff --git a/CommandLineArguments.hxx.in b/Source/kwsys/CommandLineArguments.hxx.in
index 7db9015..7db9015 100644
--- a/CommandLineArguments.hxx.in
+++ b/Source/kwsys/CommandLineArguments.hxx.in
diff --git a/Configure.h.in b/Source/kwsys/Configure.h.in
index 8a237ce..8a237ce 100644
--- a/Configure.h.in
+++ b/Source/kwsys/Configure.h.in
diff --git a/Configure.hxx.in b/Source/kwsys/Configure.hxx.in
index 29a2dd1..29a2dd1 100644
--- a/Configure.hxx.in
+++ b/Source/kwsys/Configure.hxx.in
diff --git a/ConsoleBuf.hxx.in b/Source/kwsys/ConsoleBuf.hxx.in
index 49dbdf7..49dbdf7 100644
--- a/ConsoleBuf.hxx.in
+++ b/Source/kwsys/ConsoleBuf.hxx.in
diff --git a/Source/kwsys/Copyright.txt b/Source/kwsys/Copyright.txt
new file mode 100644
index 0000000..33d7fb4
--- /dev/null
+++ b/Source/kwsys/Copyright.txt
@@ -0,0 +1,38 @@
+KWSys - Kitware System Library
+Copyright 2000-2016 Kitware, Inc. and Contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Kitware, Inc. nor the names of Contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+------------------------------------------------------------------------------
+
+The following individuals and institutions are among the Contributors:
+
+* Insight Software Consortium <insightsoftwareconsortium.org>
+
+See version control history for details of individual contributions.
diff --git a/Directory.cxx b/Source/kwsys/Directory.cxx
index 2e8aa83..2e8aa83 100644
--- a/Directory.cxx
+++ b/Source/kwsys/Directory.cxx
diff --git a/Directory.hxx.in b/Source/kwsys/Directory.hxx.in
index d501116..d501116 100644
--- a/Directory.hxx.in
+++ b/Source/kwsys/Directory.hxx.in
diff --git a/DynamicLoader.cxx b/Source/kwsys/DynamicLoader.cxx
index 66ee9ea..66ee9ea 100644
--- a/DynamicLoader.cxx
+++ b/Source/kwsys/DynamicLoader.cxx
diff --git a/DynamicLoader.hxx.in b/Source/kwsys/DynamicLoader.hxx.in
index 539c742..539c742 100644
--- a/DynamicLoader.hxx.in
+++ b/Source/kwsys/DynamicLoader.hxx.in
diff --git a/Encoding.h.in b/Source/kwsys/Encoding.h.in
index 86a2669..86a2669 100644
--- a/Encoding.h.in
+++ b/Source/kwsys/Encoding.h.in
diff --git a/Encoding.hxx.in b/Source/kwsys/Encoding.hxx.in
index 75a2d4d..75a2d4d 100644
--- a/Encoding.hxx.in
+++ b/Source/kwsys/Encoding.hxx.in
diff --git a/EncodingC.c b/Source/kwsys/EncodingC.c
index e12236a..e12236a 100644
--- a/EncodingC.c
+++ b/Source/kwsys/EncodingC.c
diff --git a/EncodingCXX.cxx b/Source/kwsys/EncodingCXX.cxx
index c68c73c..c68c73c 100644
--- a/EncodingCXX.cxx
+++ b/Source/kwsys/EncodingCXX.cxx
diff --git a/ExtraTest.cmake.in b/Source/kwsys/ExtraTest.cmake.in
index 4cec9e2..4cec9e2 100644
--- a/ExtraTest.cmake.in
+++ b/Source/kwsys/ExtraTest.cmake.in
diff --git a/FStream.cxx b/Source/kwsys/FStream.cxx
index 5e4133a..5e4133a 100644
--- a/FStream.cxx
+++ b/Source/kwsys/FStream.cxx
diff --git a/FStream.hxx.in b/Source/kwsys/FStream.hxx.in
index 55a7fb1..55a7fb1 100644
--- a/FStream.hxx.in
+++ b/Source/kwsys/FStream.hxx.in
diff --git a/Glob.cxx b/Source/kwsys/Glob.cxx
index c6d4b19..c6d4b19 100644
--- a/Glob.cxx
+++ b/Source/kwsys/Glob.cxx
diff --git a/Glob.hxx.in b/Source/kwsys/Glob.hxx.in
index fd39775..fd39775 100644
--- a/Glob.hxx.in
+++ b/Source/kwsys/Glob.hxx.in
diff --git a/MD5.c b/Source/kwsys/MD5.c
index fb18a5b..fb18a5b 100644
--- a/MD5.c
+++ b/Source/kwsys/MD5.c
diff --git a/MD5.h.in b/Source/kwsys/MD5.h.in
index 7646f12..7646f12 100644
--- a/MD5.h.in
+++ b/Source/kwsys/MD5.h.in
diff --git a/Process.h.in b/Source/kwsys/Process.h.in
index 9f2162b..9f2162b 100644
--- a/Process.h.in
+++ b/Source/kwsys/Process.h.in
diff --git a/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c
index e1e7721..e1e7721 100644
--- a/ProcessUNIX.c
+++ b/Source/kwsys/ProcessUNIX.c
diff --git a/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
index 8f01684..8f01684 100644
--- a/ProcessWin32.c
+++ b/Source/kwsys/ProcessWin32.c
diff --git a/Source/kwsys/README.rst b/Source/kwsys/README.rst
new file mode 100644
index 0000000..fc6b590
--- /dev/null
+++ b/Source/kwsys/README.rst
@@ -0,0 +1,37 @@
+KWSys
+*****
+
+Introduction
+============
+
+KWSys is the Kitware System Library. It provides platform-independent
+APIs to many common system features that are implemented differently on
+every platform. This library is intended to be shared among many
+projects at the source level, so it has a configurable namespace.
+Each project should configure KWSys to use a namespace unique to itself.
+See comments in `CMakeLists.txt`_ for details.
+
+.. _`CMakeLists.txt`: CMakeLists.txt
+
+License
+=======
+
+KWSys is distributed under the OSI-approved BSD 3-clause License.
+See `Copyright.txt`_ for details.
+
+.. _`Copyright.txt`: Copyright.txt
+
+Reporting Bugs
+==============
+
+KWSys has no independent issue tracker. After encountering an issue
+(bug) please submit a patch using the instructions for `Contributing`_.
+Otherwise please report the issue to the tracker for the project that
+hosts the copy of KWSys in which the problem was found.
+
+Contributing
+============
+
+See `CONTRIBUTING.rst`_ for instructions to contribute.
+
+.. _`CONTRIBUTING.rst`: CONTRIBUTING.rst
diff --git a/RegularExpression.cxx b/Source/kwsys/RegularExpression.cxx
index fb4e380..fb4e380 100644
--- a/RegularExpression.cxx
+++ b/Source/kwsys/RegularExpression.cxx
diff --git a/RegularExpression.hxx.in b/Source/kwsys/RegularExpression.hxx.in
index 2709cde..2709cde 100644
--- a/RegularExpression.hxx.in
+++ b/Source/kwsys/RegularExpression.hxx.in
diff --git a/SharedForward.h.in b/Source/kwsys/SharedForward.h.in
index 091334b..091334b 100644
--- a/SharedForward.h.in
+++ b/Source/kwsys/SharedForward.h.in
diff --git a/Status.cxx b/Source/kwsys/Status.cxx
index 503d1e1..503d1e1 100644
--- a/Status.cxx
+++ b/Source/kwsys/Status.cxx
diff --git a/Status.hxx.in b/Source/kwsys/Status.hxx.in
index feb5b84..feb5b84 100644
--- a/Status.hxx.in
+++ b/Source/kwsys/Status.hxx.in
diff --git a/String.c b/Source/kwsys/String.c
index daf7ad1..daf7ad1 100644
--- a/String.c
+++ b/Source/kwsys/String.c
diff --git a/String.h.in b/Source/kwsys/String.h.in
index 7c9348a..7c9348a 100644
--- a/String.h.in
+++ b/Source/kwsys/String.h.in
diff --git a/String.hxx.in b/Source/kwsys/String.hxx.in
index c36f4ce..c36f4ce 100644
--- a/String.hxx.in
+++ b/Source/kwsys/String.hxx.in
diff --git a/System.c b/Source/kwsys/System.c
index dbfd2fd..dbfd2fd 100644
--- a/System.c
+++ b/Source/kwsys/System.c
diff --git a/System.h.in b/Source/kwsys/System.h.in
index a9d4f5e..a9d4f5e 100644
--- a/System.h.in
+++ b/Source/kwsys/System.h.in
diff --git a/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx
index 7743eab..7743eab 100644
--- a/SystemInformation.cxx
+++ b/Source/kwsys/SystemInformation.cxx
diff --git a/SystemInformation.hxx.in b/Source/kwsys/SystemInformation.hxx.in
index c8efd51..c8efd51 100644
--- a/SystemInformation.hxx.in
+++ b/Source/kwsys/SystemInformation.hxx.in
diff --git a/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 2518845..2518845 100644
--- a/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
diff --git a/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in
index e5d115e..e5d115e 100644
--- a/SystemTools.hxx.in
+++ b/Source/kwsys/SystemTools.hxx.in
diff --git a/Terminal.c b/Source/kwsys/Terminal.c
index 9409d1b..9409d1b 100644
--- a/Terminal.c
+++ b/Source/kwsys/Terminal.c
diff --git a/Terminal.h.in b/Source/kwsys/Terminal.h.in
index 1a2c745..1a2c745 100644
--- a/Terminal.h.in
+++ b/Source/kwsys/Terminal.h.in
diff --git a/kwsysHeaderDump.pl b/Source/kwsys/kwsysHeaderDump.pl
index e3391e7..e3391e7 100755
--- a/kwsysHeaderDump.pl
+++ b/Source/kwsys/kwsysHeaderDump.pl
diff --git a/kwsysPlatformTests.cmake b/Source/kwsys/kwsysPlatformTests.cmake
index 89be4b8..89be4b8 100644
--- a/kwsysPlatformTests.cmake
+++ b/Source/kwsys/kwsysPlatformTests.cmake
diff --git a/kwsysPlatformTestsC.c b/Source/kwsys/kwsysPlatformTestsC.c
index d44f7eb..d44f7eb 100644
--- a/kwsysPlatformTestsC.c
+++ b/Source/kwsys/kwsysPlatformTestsC.c
diff --git a/kwsysPlatformTestsCXX.cxx b/Source/kwsys/kwsysPlatformTestsCXX.cxx
index 0bfa20e..0bfa20e 100644
--- a/kwsysPlatformTestsCXX.cxx
+++ b/Source/kwsys/kwsysPlatformTestsCXX.cxx
diff --git a/kwsysPrivate.h b/Source/kwsys/kwsysPrivate.h
index dd9c127..dd9c127 100644
--- a/kwsysPrivate.h
+++ b/Source/kwsys/kwsysPrivate.h
diff --git a/testCommandLineArguments.cxx b/Source/kwsys/testCommandLineArguments.cxx
index 0786751..0786751 100644
--- a/testCommandLineArguments.cxx
+++ b/Source/kwsys/testCommandLineArguments.cxx
diff --git a/testCommandLineArguments1.cxx b/Source/kwsys/testCommandLineArguments1.cxx
index 2f6b735..2f6b735 100644
--- a/testCommandLineArguments1.cxx
+++ b/Source/kwsys/testCommandLineArguments1.cxx
diff --git a/testConfigure.cxx b/Source/kwsys/testConfigure.cxx
index a3c2ed3..a3c2ed3 100644
--- a/testConfigure.cxx
+++ b/Source/kwsys/testConfigure.cxx
diff --git a/testConsoleBuf.cxx b/Source/kwsys/testConsoleBuf.cxx
index 4b7ddf0..4b7ddf0 100644
--- a/testConsoleBuf.cxx
+++ b/Source/kwsys/testConsoleBuf.cxx
diff --git a/testConsoleBuf.hxx b/Source/kwsys/testConsoleBuf.hxx
index e93cb4f..e93cb4f 100644
--- a/testConsoleBuf.hxx
+++ b/Source/kwsys/testConsoleBuf.hxx
diff --git a/testConsoleBufChild.cxx b/Source/kwsys/testConsoleBufChild.cxx
index 3c8fdc2..3c8fdc2 100644
--- a/testConsoleBufChild.cxx
+++ b/Source/kwsys/testConsoleBufChild.cxx
diff --git a/testDirectory.cxx b/Source/kwsys/testDirectory.cxx
index 06a22dc..06a22dc 100644
--- a/testDirectory.cxx
+++ b/Source/kwsys/testDirectory.cxx
diff --git a/testDynamicLoader.cxx b/Source/kwsys/testDynamicLoader.cxx
index 703ad4d..703ad4d 100644
--- a/testDynamicLoader.cxx
+++ b/Source/kwsys/testDynamicLoader.cxx
diff --git a/testDynload.c b/Source/kwsys/testDynload.c
index 33a431e..33a431e 100644
--- a/testDynload.c
+++ b/Source/kwsys/testDynload.c
diff --git a/testDynloadImpl.c b/Source/kwsys/testDynloadImpl.c
index 2b9069b..2b9069b 100644
--- a/testDynloadImpl.c
+++ b/Source/kwsys/testDynloadImpl.c
diff --git a/testDynloadImpl.h b/Source/kwsys/testDynloadImpl.h
index d0c9dfb..d0c9dfb 100644
--- a/testDynloadImpl.h
+++ b/Source/kwsys/testDynloadImpl.h
diff --git a/testDynloadUse.c b/Source/kwsys/testDynloadUse.c
index 5402add..5402add 100644
--- a/testDynloadUse.c
+++ b/Source/kwsys/testDynloadUse.c
diff --git a/testEncode.c b/Source/kwsys/testEncode.c
index b7b6dd8..b7b6dd8 100644
--- a/testEncode.c
+++ b/Source/kwsys/testEncode.c
diff --git a/testEncoding.cxx b/Source/kwsys/testEncoding.cxx
index ee93e8d..ee93e8d 100644
--- a/testEncoding.cxx
+++ b/Source/kwsys/testEncoding.cxx
diff --git a/testFStream.cxx b/Source/kwsys/testFStream.cxx
index 3325e20..3325e20 100644
--- a/testFStream.cxx
+++ b/Source/kwsys/testFStream.cxx
diff --git a/testFail.c b/Source/kwsys/testFail.c
index 82caeac..82caeac 100644
--- a/testFail.c
+++ b/Source/kwsys/testFail.c
diff --git a/testProcess.c b/Source/kwsys/testProcess.c
index eed770c..eed770c 100644
--- a/testProcess.c
+++ b/Source/kwsys/testProcess.c
diff --git a/testSharedForward.c.in b/Source/kwsys/testSharedForward.c.in
index b3eb413..b3eb413 100644
--- a/testSharedForward.c.in
+++ b/Source/kwsys/testSharedForward.c.in
diff --git a/testStatus.cxx b/Source/kwsys/testStatus.cxx
index f85ef42..f85ef42 100644
--- a/testStatus.cxx
+++ b/Source/kwsys/testStatus.cxx
diff --git a/testSystemInformation.cxx b/Source/kwsys/testSystemInformation.cxx
index 4f0c522..4f0c522 100644
--- a/testSystemInformation.cxx
+++ b/Source/kwsys/testSystemInformation.cxx
diff --git a/testSystemTools.bin b/Source/kwsys/testSystemTools.bin
index 961a404..961a404 100644
--- a/testSystemTools.bin
+++ b/Source/kwsys/testSystemTools.bin
Binary files differ
diff --git a/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx
index cfa420d..cfa420d 100644
--- a/testSystemTools.cxx
+++ b/Source/kwsys/testSystemTools.cxx
diff --git a/testSystemTools.h.in b/Source/kwsys/testSystemTools.h.in
index e4b89a7..e4b89a7 100644
--- a/testSystemTools.h.in
+++ b/Source/kwsys/testSystemTools.h.in
diff --git a/testTerminal.c b/Source/kwsys/testTerminal.c
index 652830c..652830c 100644
--- a/testTerminal.c
+++ b/Source/kwsys/testTerminal.c
diff --git a/Templates/AppleInfo.plist b/Templates/AppleInfo.plist
new file mode 100644
index 0000000..3445e53
--- /dev/null
+++ b/Templates/AppleInfo.plist
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${APPLE_GUI_EXECUTABLE}</string>
+ <key>CFBundleGetInfoString</key>
+ <string>${APPLE_GUI_INFO_STRING}</string>
+ <key>CFBundleIconFile</key>
+ <string>${APPLE_GUI_ICON}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${APPLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleLongVersionString</key>
+ <string>${APPLE_GUI_LONG_VERSION_STRING}</string>
+ <key>CFBundleName</key>
+ <string>${APPLE_GUI_BUNDLE_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${APPLE_GUI_SHORT_VERSION_STRING}</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>${APPLE_GUI_BUNDLE_VERSION}</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+ <key>NSHumanReadableCopyright</key>
+ <string>${APPLE_GUI_COPYRIGHT}</string>
+</dict>
+</plist>
diff --git a/Templates/CMakeVSMacros1.vsmacros b/Templates/CMakeVSMacros1.vsmacros
new file mode 100644
index 0000000..60487d9
--- /dev/null
+++ b/Templates/CMakeVSMacros1.vsmacros
Binary files differ
diff --git a/Templates/CMakeVSMacros2.vsmacros b/Templates/CMakeVSMacros2.vsmacros
new file mode 100644
index 0000000..5ba2799
--- /dev/null
+++ b/Templates/CMakeVSMacros2.vsmacros
Binary files differ
diff --git a/Templates/CPack.GenericDescription.txt b/Templates/CPack.GenericDescription.txt
new file mode 100644
index 0000000..712ee14
--- /dev/null
+++ b/Templates/CPack.GenericDescription.txt
@@ -0,0 +1,5 @@
+DESCRIPTION
+===========
+
+This is an installer created using CPack (https://cmake.org). No additional installation instructions provided.
+
diff --git a/Templates/CPack.GenericLicense.txt b/Templates/CPack.GenericLicense.txt
new file mode 100644
index 0000000..09c6218
--- /dev/null
+++ b/Templates/CPack.GenericLicense.txt
@@ -0,0 +1,5 @@
+LICENSE
+=======
+
+This is an installer created using CPack (https://cmake.org). No license provided.
+
diff --git a/Templates/CPack.GenericWelcome.txt b/Templates/CPack.GenericWelcome.txt
new file mode 100644
index 0000000..5330087
--- /dev/null
+++ b/Templates/CPack.GenericWelcome.txt
@@ -0,0 +1 @@
+Welcome to installation. This program will guide you through the installation of this software.
diff --git a/Templates/CPackConfig.cmake.in b/Templates/CPackConfig.cmake.in
new file mode 100644
index 0000000..c00ea2a
--- /dev/null
+++ b/Templates/CPackConfig.cmake.in
@@ -0,0 +1,20 @@
+# This file will be configured to contain variables for CPack. These variables
+# should be set in the CMake list file of the project before CPack module is
+# included. The list of available CPACK_xxx variables and their associated
+# documentation may be obtained using
+# cpack --help-variable-list
+#
+# Some variables are common to all generators (e.g. CPACK_PACKAGE_NAME)
+# and some are specific to a generator
+# (e.g. CPACK_NSIS_EXTRA_INSTALL_COMMANDS). The generator specific variables
+# usually begin with CPACK_<GENNAME>_xxxx.
+
+@_CPACK_OTHER_VARIABLES_@
+
+if(NOT CPACK_PROPERTIES_FILE)
+ set(CPACK_PROPERTIES_FILE "@CMAKE_BINARY_DIR@/CPackProperties.cmake")
+endif()
+
+if(EXISTS ${CPACK_PROPERTIES_FILE})
+ include(${CPACK_PROPERTIES_FILE})
+endif()
diff --git a/Templates/CTestScript.cmake.in b/Templates/CTestScript.cmake.in
new file mode 100644
index 0000000..5fb3529
--- /dev/null
+++ b/Templates/CTestScript.cmake.in
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 2.4)
+
+# This is a template for the CTest script for this system
+
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "@BUILDNAME@")
+
+# ---
+set(CTEST_SOURCE_DIRECTORY "@CMAKE_SOURCE_DIR@")
+set(CTEST_BINARY_DIRECTORY "@CMAKE_BINARY_DIR@")
+set(CTEST_UPDATE_COMMAND "@UPDATE_COMMAND@")
+set(CTEST_UPDATE_OPTIONS "@UPDATE_OPTIONS@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_BUILD_CONFIGURATION "Release")
+#set(CTEST_MEMORYCHECK_COMMAND "@MEMORYCHECK_COMMAND@")
+#set(CTEST_MEMORYCHECK_SUPPRESSIONS_FILE "@MEMORYCHECK_SUPPRESSIONS_FILE@")
+#set(CTEST_MEMORYCHECK_COMMAND_OPTIONS "@MEMORYCHECK_COMMAND_OPTIONS@")
+#set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
+
+set(CTEST_DROP_METHOD "@DROP_METHOD@")
+
+CTEST_START(Experimental TRACK Weekly)
+CTEST_UPDATE(SOURCE "${CTEST_SOURCE_DIRECTORY}")
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}")
+CTEST_READ_CUSTOM_FILES("${CTEST_BINARY_DIRECTORY}")
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}")
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}")
+#CTEST_MEMCHECK(BUILD "${CTEST_BINARY_DIRECTORY}")
+#CTEST_COVERAGE(BUILD "${CTEST_BINARY_DIRECTORY}")
+CTEST_SUBMIT()
diff --git a/Templates/MSBuild/FlagTables/v10_CL.json b/Templates/MSBuild/FlagTables/v10_CL.json
new file mode 100644
index 0000000..06158be
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v10_CL.json
@@ -0,0 +1,981 @@
+[
+ {
+ "name": "DebugInformationFormat",
+ "switch": "Z7",
+ "comment": "C7 compatible",
+ "value": "OldStyle",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "Zi",
+ "comment": "Program Database",
+ "value": "ProgramDatabase",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "ZI",
+ "comment": "Program Database for Edit And Continue",
+ "value": "EditAndContinue",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "",
+ "comment": "No Common Language RunTime Support",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr",
+ "comment": "Common Language RunTime Support",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:pure",
+ "comment": "Pure MSIL Common Language RunTime Support",
+ "value": "Pure",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:safe",
+ "comment": "Safe MSIL Common Language RunTime Support",
+ "value": "Safe",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:oldSyntax",
+ "comment": "Common Language RunTime Support, Old Syntax",
+ "value": "OldSyntax",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W0",
+ "comment": "Turn Off All Warnings",
+ "value": "TurnOffAllWarnings",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W1",
+ "comment": "Level1",
+ "value": "Level1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W2",
+ "comment": "Level2",
+ "value": "Level2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W3",
+ "comment": "Level3",
+ "value": "Level3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W4",
+ "comment": "Level4",
+ "value": "Level4",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "Wall",
+ "comment": "EnableAllWarnings",
+ "value": "EnableAllWarnings",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "Od",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "O1",
+ "comment": "Minimize Size",
+ "value": "MinSpace",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "O2",
+ "comment": "Maximize Speed",
+ "value": "MaxSpeed",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "Ox",
+ "comment": "Full Optimization",
+ "value": "Full",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob0",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob1",
+ "comment": "Only __inline",
+ "value": "OnlyExplicitInline",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob2",
+ "comment": "Any Suitable",
+ "value": "AnySuitable",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "Os",
+ "comment": "Favor small code",
+ "value": "Size",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "Ot",
+ "comment": "Favor fast code",
+ "value": "Speed",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "",
+ "comment": "Neither",
+ "value": "Neither",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHa",
+ "comment": "Yes with SEH Exceptions",
+ "value": "Async",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHsc",
+ "comment": "Yes",
+ "value": "Sync",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHs",
+ "comment": "Yes with Extern C functions",
+ "value": "SyncCThrow",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTCs",
+ "comment": "Stack Frames",
+ "value": "StackFrameRuntimeCheck",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTCu",
+ "comment": "Uninitialized variables",
+ "value": "UninitializedLocalUsageCheck",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTC1",
+ "comment": "Both (/RTC1, equiv. to /RTCsu)",
+ "value": "EnableFastChecks",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MT",
+ "comment": "Multi-threaded",
+ "value": "MultiThreaded",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MTd",
+ "comment": "Multi-threaded Debug",
+ "value": "MultiThreadedDebug",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MD",
+ "comment": "Multi-threaded DLL",
+ "value": "MultiThreadedDLL",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MDd",
+ "comment": "Multi-threaded Debug DLL",
+ "value": "MultiThreadedDebugDLL",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp1",
+ "comment": "1 Byte",
+ "value": "1Byte",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp2",
+ "comment": "2 Bytes",
+ "value": "2Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp4",
+ "comment": "4 Byte",
+ "value": "4Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp8",
+ "comment": "8 Bytes",
+ "value": "8Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp16",
+ "comment": "16 Bytes",
+ "value": "16Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:SSE",
+ "comment": "Streaming SIMD Extensions (/arch:SSE)",
+ "value": "StreamingSIMDExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:SSE2",
+ "comment": "Streaming SIMD Extensions 2 (/arch:SSE2)",
+ "value": "StreamingSIMDExtensions2",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:precise",
+ "comment": "Precise",
+ "value": "Precise",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:strict",
+ "comment": "Strict",
+ "value": "Strict",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:fast",
+ "comment": "Fast",
+ "value": "Fast",
+ "flags": []
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Yc",
+ "comment": "Create",
+ "value": "Create",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Yu",
+ "comment": "Use",
+ "value": "Use",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Y-",
+ "comment": "Not Using Precompiled Headers",
+ "value": "NotUsing",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "",
+ "comment": "No Listing",
+ "value": "NoListing",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FA",
+ "comment": "Assembly-Only Listing",
+ "value": "AssemblyCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAc",
+ "comment": "Assembly With Machine Code",
+ "value": "AssemblyAndMachineCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAs",
+ "comment": "Assembly With Source Code",
+ "value": "AssemblyAndSourceCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAcs",
+ "comment": "Assembly, Machine Code and Source",
+ "value": "All",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gd",
+ "comment": "__cdecl",
+ "value": "Cdecl",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gr",
+ "comment": "__fastcall",
+ "value": "FastCall",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gz",
+ "comment": "__stdcall",
+ "value": "StdCall",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "TC",
+ "comment": "Compile as C Code",
+ "value": "CompileAsC",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "TP",
+ "comment": "Compile as C++ Code",
+ "value": "CompileAsCpp",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:none",
+ "comment": "Do Not Send Report",
+ "value": "None",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:prompt",
+ "comment": "Prompt Immediately",
+ "value": "Prompt",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:queue",
+ "comment": "Queue For Next Login",
+ "value": "Queue",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:send",
+ "comment": "Send Automatically",
+ "value": "Send",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "nologo-",
+ "comment": "Suppress Startup Banner",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "nologo",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningAsError",
+ "switch": "WX-",
+ "comment": "Treat Warnings As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningAsError",
+ "switch": "WX",
+ "comment": "Treat Warnings As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MultiProcessorCompilation",
+ "switch": "MP",
+ "comment": "Multi-processor Compilation",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "IntrinsicFunctions",
+ "switch": "Oi",
+ "comment": "Enable Intrinsic Functions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OmitFramePointers",
+ "switch": "Oy-",
+ "comment": "Omit Frame Pointers",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OmitFramePointers",
+ "switch": "Oy",
+ "comment": "Omit Frame Pointers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableFiberSafeOptimizations",
+ "switch": "GT",
+ "comment": "Enable Fiber-Safe Optimizations",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WholeProgramOptimization",
+ "switch": "GL",
+ "comment": "Whole Program Optimization",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UndefineAllPreprocessorDefinitions",
+ "switch": "u",
+ "comment": "Undefine All Preprocessor Definitions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreStandardIncludePath",
+ "switch": "X",
+ "comment": "Ignore Standard Include Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessToFile",
+ "switch": "P",
+ "comment": "Preprocess to a File",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessSuppressLineNumbers",
+ "switch": "EP",
+ "comment": "Preprocess Suppress Line Numbers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessKeepComments",
+ "switch": "C",
+ "comment": "Keep Comments",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "StringPooling",
+ "switch": "GF-",
+ "comment": "Enable String Pooling",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "StringPooling",
+ "switch": "GF",
+ "comment": "Enable String Pooling",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MinimalRebuild",
+ "switch": "Gm-",
+ "comment": "Enable Minimal Rebuild",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "MinimalRebuild",
+ "switch": "Gm",
+ "comment": "Enable Minimal Rebuild",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SmallerTypeCheck",
+ "switch": "RTCc",
+ "comment": "Smaller Type Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "BufferSecurityCheck",
+ "switch": "GS-",
+ "comment": "Buffer Security Check",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "BufferSecurityCheck",
+ "switch": "GS",
+ "comment": "Buffer Security Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FunctionLevelLinking",
+ "switch": "Gy-",
+ "comment": "Enable Function-Level Linking",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FunctionLevelLinking",
+ "switch": "Gy",
+ "comment": "Enable Function-Level Linking",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointExceptions",
+ "switch": "fp:except-",
+ "comment": "Enable Floating Point Exceptions",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointExceptions",
+ "switch": "fp:except",
+ "comment": "Enable Floating Point Exceptions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CreateHotpatchableImage",
+ "switch": "hotpatch",
+ "comment": "Create Hotpatchable Image",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DisableLanguageExtensions",
+ "switch": "Za",
+ "comment": "Disable Language Extensions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWChar_tAsBuiltInType",
+ "switch": "Zc:wchar_t-",
+ "comment": "Treat WChar_t As Built in Type",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWChar_tAsBuiltInType",
+ "switch": "Zc:wchar_t",
+ "comment": "Treat WChar_t As Built in Type",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ForceConformanceInForLoopScope",
+ "switch": "Zc:forScope-",
+ "comment": "Force Conformance in For Loop Scope",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "ForceConformanceInForLoopScope",
+ "switch": "Zc:forScope",
+ "comment": "Force Conformance in For Loop Scope",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RuntimeTypeInfo",
+ "switch": "GR-",
+ "comment": "Enable Run-Time Type Information",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RuntimeTypeInfo",
+ "switch": "GR",
+ "comment": "Enable Run-Time Type Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OpenMPSupport",
+ "switch": "openmp-",
+ "comment": "Open MP Support",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OpenMPSupport",
+ "switch": "openmp",
+ "comment": "Open MP Support",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ExpandAttributedSource",
+ "switch": "Fx",
+ "comment": "Expand Attributed Source",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateXMLDocumentationFiles",
+ "switch": "doc",
+ "comment": "Generate XML Documentation Files",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "BrowseInformation",
+ "switch": "FR",
+ "comment": "Enable Browse Information",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "ShowIncludes",
+ "switch": "showIncludes",
+ "comment": "Show Includes",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnablePREfast",
+ "switch": "analyze-",
+ "comment": "Enable Code Analysis",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnablePREfast",
+ "switch": "analyze",
+ "comment": "Enable Code Analysis",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseFullPaths",
+ "switch": "FC",
+ "comment": "Use Full Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OmitDefaultLibName",
+ "switch": "Zl",
+ "comment": "Omit Default Library Name",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseUnicodeForAssemblerListing",
+ "switch": "FAu",
+ "comment": "Use Unicode For Assembler Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalIncludeDirectories",
+ "switch": "I",
+ "comment": "Additional Include Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalUsingDirectories",
+ "switch": "AI",
+ "comment": "Resolve #using References",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "UndefinePreprocessorDefinitions",
+ "switch": "U",
+ "comment": "Undefine Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "DisableSpecificWarnings",
+ "switch": "wd",
+ "comment": "Disable Specific Warnings",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForcedIncludeFiles",
+ "switch": "FI",
+ "comment": "Forced Include File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForcedUsingFiles",
+ "switch": "FU",
+ "comment": "Forced #using File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "TreatSpecificWarningsAsErrors",
+ "switch": "we",
+ "comment": "Treat Specific Warnings As Errors",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PreprocessOutputPath",
+ "switch": "Fi",
+ "comment": "Preprocess Output Path",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderFile",
+ "switch": "Yu",
+ "comment": "Precompiled Header File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderFile",
+ "switch": "Yc",
+ "comment": "Precompiled Header File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderOutputFile",
+ "switch": "Fp",
+ "comment": "Precompiled Header Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "AssemblerListingLocation",
+ "switch": "Fa",
+ "comment": "ASM List Location",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ObjectFileName",
+ "switch": "Fo",
+ "comment": "Object File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProgramDataBaseFileName",
+ "switch": "Fd",
+ "comment": "Program Database File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "XMLDocumentationFileName",
+ "switch": "doc",
+ "comment": "XML Documentation File Name",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "BrowseInformationFile",
+ "switch": "FR",
+ "comment": "Browse Information File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ProcessorNumber",
+ "switch": "MP",
+ "comment": "Number of processors",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v10_CSharp.json b/Templates/MSBuild/FlagTables/v10_CSharp.json
new file mode 100644
index 0000000..5989aea
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v10_CSharp.json
@@ -0,0 +1,574 @@
+[
+ {
+ "name": "ProjectName",
+ "switch": "out:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:exe",
+ "comment": "",
+ "value": "Exe",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:winexe",
+ "comment": "",
+ "value": "Winexe",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:library",
+ "comment": "",
+ "value": "Library",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:module",
+ "comment": "",
+ "value": "Module",
+ "flags": []
+ },
+ {
+ "name": "DocumentationFile",
+ "switch": "doc",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:x86",
+ "comment": "",
+ "value": "x86",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:Itanium",
+ "comment": "",
+ "value": "Itanium",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:x64",
+ "comment": "",
+ "value": "x64",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:arm",
+ "comment": "",
+ "value": "arm",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:anycpu32bitpreferred",
+ "comment": "",
+ "value": "anycpu32bitpreferred",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:anycpu",
+ "comment": "",
+ "value": "anycpu",
+ "flags": []
+ },
+ {
+ "name": "References",
+ "switch": "reference:",
+ "comment": "mit alias",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "References",
+ "switch": "reference:",
+ "comment": "dateiliste",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "AddModules",
+ "switch": "addmodule:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "Win32Resource",
+ "switch": "win32res:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ApplicationIcon",
+ "switch": "win32icon:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ApplicationManifest",
+ "switch": "win32manifest:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "NoWin32Manifest",
+ "switch": "nowin32manifest",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DefineDebug",
+ "switch": "debug",
+ "comment": "",
+ "value": "true",
+ "flags": [
+ "Continue"
+ ]
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:none",
+ "comment": "",
+ "value": "none",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:full",
+ "comment": "",
+ "value": "full",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:pdbonly",
+ "comment": "",
+ "value": "pdbonly",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror-",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror+",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:0",
+ "comment": "",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:1",
+ "comment": "",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:2",
+ "comment": "",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:3",
+ "comment": "",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:4",
+ "comment": "",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "NoWarn",
+ "switch": "nowarn:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired",
+ "CommaAppendable"
+ ]
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DefineConstants",
+ "switch": "define:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "SemicolonAppendable",
+ "UserValue"
+ ]
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:ISO-1",
+ "comment": "",
+ "value": "ISO-1",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:ISO-2",
+ "comment": "",
+ "value": "ISO-2",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:3",
+ "comment": "",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:4",
+ "comment": "",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:5",
+ "comment": "",
+ "value": "5",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:6",
+ "comment": "",
+ "value": "6",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:default",
+ "comment": "",
+ "value": "default",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AssemblyOriginatorKeyFile",
+ "switch": "keyfile",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "KeyContainerName",
+ "switch": "keycontainer",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoLogo",
+ "switch": "nologo",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoConfig",
+ "switch": "noconfig",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "BaseAddress",
+ "switch": "baseaddress:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "CodePage",
+ "switch": "codepage",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "Utf8Output",
+ "switch": "utf8output",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "MainEntryPoint",
+ "switch": "main:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "GenerateFullPaths",
+ "switch": "fullpaths",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FileAlignment",
+ "switch": "filealign",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "PdbFile",
+ "switch": "pdb:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SubsystemVersion",
+ "switch": "subsystemversion",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibPaths",
+ "switch": "lib:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:none",
+ "comment": "Do Not Send Report",
+ "value": "none",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:prompt",
+ "comment": "Prompt Immediately",
+ "value": "prompt",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:queue",
+ "comment": "Queue For Next Login",
+ "value": "queue",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:send",
+ "comment": "Send Automatically",
+ "value": "send",
+ "flags": []
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v10_Cuda.json b/Templates/MSBuild/FlagTables/v10_Cuda.json
new file mode 100644
index 0000000..b3230ac
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v10_Cuda.json
@@ -0,0 +1,244 @@
+[
+ {
+ "name": "AdditionalCompilerOptions",
+ "switch": "Xcompiler=",
+ "comment": "Host compiler options",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SpaceAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalCompilerOptions",
+ "switch": "Xcompiler",
+ "comment": "Host compiler options",
+ "value": "",
+ "flags": [
+ "UserFollowing",
+ "SpaceAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalCompilerOptions",
+ "switch": "-compiler-options=",
+ "comment": "Host compiler options",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SpaceAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalCompilerOptions",
+ "switch": "-compiler-options",
+ "comment": "Host compiler options",
+ "value": "",
+ "flags": [
+ "UserFollowing",
+ "SpaceAppendable"
+ ]
+ },
+ {
+ "name": "CudaRuntime",
+ "switch": "cudart=none",
+ "comment": "No CUDA runtime library",
+ "value": "None",
+ "flags": []
+ },
+ {
+ "name": "CudaRuntime",
+ "switch": "cudart=shared",
+ "comment": "Shared/dynamic CUDA runtime library",
+ "value": "Shared",
+ "flags": []
+ },
+ {
+ "name": "CudaRuntime",
+ "switch": "cudart=static",
+ "comment": "Static CUDA runtime library",
+ "value": "Static",
+ "flags": []
+ },
+ {
+ "name": "CudaRuntime",
+ "switch": "cudart",
+ "comment": "CUDA runtime library",
+ "value": "",
+ "flags": [
+ "UserFollowing"
+ ]
+ },
+ {
+ "name": "cmake-temp-gencode",
+ "switch": "gencode=",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "cmake-temp-gencode",
+ "switch": "gencode",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserFollowing",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "cmake-temp-gencode",
+ "switch": "-generate-code=",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "cmake-temp-gencode",
+ "switch": "-generate-code",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserFollowing",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "cmake-temp-code",
+ "switch": "code=",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "cmake-temp-code",
+ "switch": "code",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserFollowing"
+ ]
+ },
+ {
+ "name": "cmake-temp-code",
+ "switch": "-gpu-code=",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "cmake-temp-code",
+ "switch": "-gpu-code",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserFollowing"
+ ]
+ },
+ {
+ "name": "cmake-temp-arch",
+ "switch": "arch=",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "cmake-temp-arch",
+ "switch": "arch",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserFollowing"
+ ]
+ },
+ {
+ "name": "cmake-temp-arch",
+ "switch": "-gpu-architecture=",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "cmake-temp-arch",
+ "switch": "-gpu-architecture",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserFollowing"
+ ]
+ },
+ {
+ "name": "FastMath",
+ "switch": "use_fast_math",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FastMath",
+ "switch": "-use_fast_math",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GPUDebugInfo",
+ "switch": "G",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GPUDebugInfo",
+ "switch": "-device-debug",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "HostDebugInfo",
+ "switch": "g",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "HostDebugInfo",
+ "switch": "-debug",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MaxRegCount",
+ "switch": "maxrregcount=",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MaxRegCount",
+ "switch": "maxrregcount",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserFollowing"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v10_CudaHost.json b/Templates/MSBuild/FlagTables/v10_CudaHost.json
new file mode 100644
index 0000000..2593ff1
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v10_CudaHost.json
@@ -0,0 +1,149 @@
+[
+ {
+ "name": "Optimization",
+ "switch": "Od",
+ "comment": "Disabled",
+ "value": "Od",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "O1",
+ "comment": "Minimize Size",
+ "value": "O1",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "O2",
+ "comment": "Maximize Speed",
+ "value": "O2",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "Ox",
+ "comment": "Full Optimization",
+ "value": "O3",
+ "flags": []
+ },
+ {
+ "name": "Runtime",
+ "switch": "MT",
+ "comment": "Multi-Threaded",
+ "value": "MT",
+ "flags": []
+ },
+ {
+ "name": "Runtime",
+ "switch": "MTd",
+ "comment": "Multi-Threaded Debug",
+ "value": "MTd",
+ "flags": []
+ },
+ {
+ "name": "Runtime",
+ "switch": "MD",
+ "comment": "Multi-Threaded DLL",
+ "value": "MD",
+ "flags": []
+ },
+ {
+ "name": "Runtime",
+ "switch": "MDd",
+ "comment": "Multi-threaded Debug DLL",
+ "value": "MDd",
+ "flags": []
+ },
+ {
+ "name": "Runtime",
+ "switch": "ML",
+ "comment": "Single-Threaded",
+ "value": "ML",
+ "flags": []
+ },
+ {
+ "name": "Runtime",
+ "switch": "MLd",
+ "comment": "Single-Threaded Debug",
+ "value": "MLd",
+ "flags": []
+ },
+ {
+ "name": "RuntimeChecks",
+ "switch": "RTCs",
+ "comment": "Stack Frames",
+ "value": "RTCs",
+ "flags": []
+ },
+ {
+ "name": "RuntimeChecks",
+ "switch": "RTCu",
+ "comment": "Uninitialized Variables",
+ "value": "RTCu",
+ "flags": []
+ },
+ {
+ "name": "RuntimeChecks",
+ "switch": "RTC1",
+ "comment": "Both",
+ "value": "RTC1",
+ "flags": []
+ },
+ {
+ "name": "TypeInfo",
+ "switch": "GR",
+ "comment": "Yes",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TypeInfo",
+ "switch": "GR-",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "Warning",
+ "switch": "W0",
+ "comment": "Off: Turn Off All Warnings",
+ "value": "W0",
+ "flags": []
+ },
+ {
+ "name": "Warning",
+ "switch": "W1",
+ "comment": "Level 1",
+ "value": "W1",
+ "flags": []
+ },
+ {
+ "name": "Warning",
+ "switch": "W2",
+ "comment": "Level 2",
+ "value": "W2",
+ "flags": []
+ },
+ {
+ "name": "Warning",
+ "switch": "W3",
+ "comment": "Level 3",
+ "value": "W3",
+ "flags": []
+ },
+ {
+ "name": "Warning",
+ "switch": "W4",
+ "comment": "Level 4",
+ "value": "W4",
+ "flags": []
+ },
+ {
+ "name": "Warning",
+ "switch": "Wall",
+ "comment": "Enable All Warnings",
+ "value": "Wall",
+ "flags": []
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v10_LIB.json b/Templates/MSBuild/FlagTables/v10_LIB.json
new file mode 100644
index 0000000..58a238c
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v10_LIB.json
@@ -0,0 +1,297 @@
+[
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:PROMPT",
+ "comment": "PromptImmediately",
+ "value": "PromptImmediately",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:QUEUE",
+ "comment": "Queue For Next Login",
+ "value": "QueueForNextLogin",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:SEND",
+ "comment": "Send Error Report",
+ "value": "SendErrorReport",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:NONE",
+ "comment": "No Error Report",
+ "value": "NoErrorReport",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM",
+ "comment": "MachineARM",
+ "value": "MachineARM",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:EBC",
+ "comment": "MachineEBC",
+ "value": "MachineEBC",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:IA64",
+ "comment": "MachineIA64",
+ "value": "MachineIA64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS",
+ "comment": "MachineMIPS",
+ "value": "MachineMIPS",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS16",
+ "comment": "MachineMIPS16",
+ "value": "MachineMIPS16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU",
+ "comment": "MachineMIPSFPU",
+ "value": "MachineMIPSFPU",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU16",
+ "comment": "MachineMIPSFPU16",
+ "value": "MachineMIPSFPU16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:SH4",
+ "comment": "MachineSH4",
+ "value": "MachineSH4",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:THUMB",
+ "comment": "MachineTHUMB",
+ "value": "MachineTHUMB",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X64",
+ "comment": "MachineX64",
+ "value": "MachineX64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X86",
+ "comment": "MachineX86",
+ "value": "MachineX86",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:CONSOLE",
+ "comment": "Console",
+ "value": "Console",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWS",
+ "comment": "Windows",
+ "value": "Windows",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:NATIVE",
+ "comment": "Native",
+ "value": "Native",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_APPLICATION",
+ "comment": "EFI Application",
+ "value": "EFI Application",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "comment": "EFI Boot Service Driver",
+ "value": "EFI Boot Service Driver",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_ROM",
+ "comment": "EFI ROM",
+ "value": "EFI ROM",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_RUNTIME_DRIVER",
+ "comment": "EFI Runtime",
+ "value": "EFI Runtime",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWSCE",
+ "comment": "WindowsCE",
+ "value": "WindowsCE",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:POSIX",
+ "comment": "POSIX",
+ "value": "POSIX",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "NOLOGO",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreAllDefaultLibraries",
+ "switch": "NODEFAULTLIB",
+ "comment": "Ignore All Default Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatLibWarningAsErrors",
+ "switch": "WX:NO",
+ "comment": "Treat Lib Warning As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatLibWarningAsErrors",
+ "switch": "WX",
+ "comment": "Treat Lib Warning As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Verbose",
+ "switch": "VERBOSE",
+ "comment": "Verbose",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG",
+ "comment": "Link Time Code Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibraryDirectories",
+ "switch": "LIBPATH:",
+ "comment": "Additional Library Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IgnoreSpecificDefaultLibraries",
+ "switch": "NODEFAULTLIB:",
+ "comment": "Ignore Specific Default Libraries",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ExportNamedFunctions",
+ "switch": "EXPORT:",
+ "comment": "Export Named Functions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "RemoveObjects",
+ "switch": "REMOVE:",
+ "comment": "Remove Objects",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "OutputFile",
+ "switch": "OUT:",
+ "comment": "Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ModuleDefinitionFile",
+ "switch": "DEF:",
+ "comment": "Module Definition File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ForceSymbolReferences",
+ "switch": "INCLUDE:",
+ "comment": "Force Symbol References",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "DisplayLibrary",
+ "switch": "LIST:",
+ "comment": "Display Library to standard output",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "Name",
+ "switch": "NAME:",
+ "comment": "Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v10_Link.json b/Templates/MSBuild/FlagTables/v10_Link.json
new file mode 100644
index 0000000..ac5b8b1
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v10_Link.json
@@ -0,0 +1,1137 @@
+[
+ {
+ "name": "ShowProgress",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE",
+ "comment": "Display all progress messages",
+ "value": "LinkVerbose",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:Lib",
+ "comment": "For Libraries Searched",
+ "value": "LinkVerboseLib",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:ICF",
+ "comment": "About COMDAT folding during optimized linking",
+ "value": "LinkVerboseICF",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:REF",
+ "comment": "About data removed during optimized linking",
+ "value": "LinkVerboseREF",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:SAFESEH",
+ "comment": "About Modules incompatible with SEH",
+ "value": "LinkVerboseSAFESEH",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:CLR",
+ "comment": "About linker activity related to managed code",
+ "value": "LinkVerboseCLR",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE:MULTIPLE",
+ "comment": "Multiply Defined Symbol Only",
+ "value": "MultiplyDefinedSymbolOnly",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE:UNRESOLVED",
+ "comment": "Undefined Symbol Only",
+ "value": "UndefinedSymbolOnly",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:5",
+ "comment": "X86 Image Only",
+ "value": "X86Image",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:6",
+ "comment": "X64 Image Only",
+ "value": "X64Image",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:16",
+ "comment": "Itanium Image Only",
+ "value": "ItaniumImage",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='asInvoker'",
+ "comment": "asInvoker",
+ "value": "AsInvoker",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='highestAvailable'",
+ "comment": "highestAvailable",
+ "value": "HighestAvailable",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='requireAdministrator'",
+ "comment": "requireAdministrator",
+ "value": "RequireAdministrator",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:CONSOLE",
+ "comment": "Console",
+ "value": "Console",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWS",
+ "comment": "Windows",
+ "value": "Windows",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:NATIVE",
+ "comment": "Native",
+ "value": "Native",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_APPLICATION",
+ "comment": "EFI Application",
+ "value": "EFI Application",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "comment": "EFI Boot Service Driver",
+ "value": "EFI Boot Service Driver",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_ROM",
+ "comment": "EFI ROM",
+ "value": "EFI ROM",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_RUNTIME_DRIVER",
+ "comment": "EFI Runtime",
+ "value": "EFI Runtime",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWSCE",
+ "comment": "WindowsCE",
+ "value": "WindowsCE",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:POSIX",
+ "comment": "POSIX",
+ "value": "POSIX",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "Driver",
+ "comment": "Driver",
+ "value": "Driver",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "DRIVER:UPONLY",
+ "comment": "UP Only",
+ "value": "UpOnly",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "DRIVER:WDM",
+ "comment": "WDM",
+ "value": "WDM",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG",
+ "comment": "Use Link Time Code Generation",
+ "value": "UseLinkTimeCodeGeneration",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGInstrument",
+ "comment": "Profile Guided Optimization - Instrument",
+ "value": "PGInstrument",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGOptimize",
+ "comment": "Profile Guided Optimization - Optimization",
+ "value": "PGOptimization",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGUpdate",
+ "comment": "Profile Guided Optimization - Update",
+ "value": "PGUpdate",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM",
+ "comment": "MachineARM",
+ "value": "MachineARM",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:EBC",
+ "comment": "MachineEBC",
+ "value": "MachineEBC",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:IA64",
+ "comment": "MachineIA64",
+ "value": "MachineIA64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS",
+ "comment": "MachineMIPS",
+ "value": "MachineMIPS",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS16",
+ "comment": "MachineMIPS16",
+ "value": "MachineMIPS16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU",
+ "comment": "MachineMIPSFPU",
+ "value": "MachineMIPSFPU",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU16",
+ "comment": "MachineMIPSFPU16",
+ "value": "MachineMIPSFPU16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:SH4",
+ "comment": "MachineSH4",
+ "value": "MachineSH4",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:THUMB",
+ "comment": "MachineTHUMB",
+ "value": "MachineTHUMB",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X64",
+ "comment": "MachineX64",
+ "value": "MachineX64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X86",
+ "comment": "MachineX86",
+ "value": "MachineX86",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:MTA",
+ "comment": "MTA threading attribute",
+ "value": "MTAThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:STA",
+ "comment": "STA threading attribute",
+ "value": "STAThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:NONE",
+ "comment": "Default threading attribute",
+ "value": "DefaultThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:IJW",
+ "comment": "Force IJW image",
+ "value": "ForceIJWImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:PURE",
+ "comment": "Force Pure IL Image",
+ "value": "ForcePureILImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:SAFE",
+ "comment": "Force Safe IL Image",
+ "value": "ForceSafeILImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "",
+ "comment": "Default image type",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:PROMPT",
+ "comment": "PromptImmediately",
+ "value": "PromptImmediately",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:QUEUE",
+ "comment": "Queue For Next Login",
+ "value": "QueueForNextLogin",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:SEND",
+ "comment": "Send Error Report",
+ "value": "SendErrorReport",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:NONE",
+ "comment": "No Error Report",
+ "value": "NoErrorReport",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError:NO",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError:SYSTEMDLL",
+ "comment": "System Dlls Only",
+ "value": "SystemDlls",
+ "flags": []
+ },
+ {
+ "name": "LinkIncremental",
+ "switch": "INCREMENTAL:NO",
+ "comment": "Enable Incremental Linking",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkIncremental",
+ "switch": "INCREMENTAL",
+ "comment": "Enable Incremental Linking",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "NOLOGO",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkStatus",
+ "switch": "LTCG:NOSTATUS",
+ "comment": "Link Status",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkStatus",
+ "switch": "LTCG:STATUS",
+ "comment": "Link Status",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreventDllBinding",
+ "switch": "ALLOWBIND:NO",
+ "comment": "Prevent Dll Binding",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "PreventDllBinding",
+ "switch": "ALLOWBIND",
+ "comment": "Prevent Dll Binding",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatLinkerWarningAsErrors",
+ "switch": "WX:NO",
+ "comment": "Treat Linker Warning As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatLinkerWarningAsErrors",
+ "switch": "WX",
+ "comment": "Treat Linker Warning As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreAllDefaultLibraries",
+ "switch": "NODEFAULTLIB",
+ "comment": "Ignore All Default Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateManifest",
+ "switch": "MANIFEST:NO",
+ "comment": "Generate Manifest",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "GenerateManifest",
+ "switch": "MANIFEST",
+ "comment": "Generate Manifest",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowIsolation",
+ "switch": "ALLOWISOLATION:NO",
+ "comment": "Allow Isolation",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AllowIsolation",
+ "switch": "ALLOWISOLATION",
+ "comment": "Allow Isolation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableUAC",
+ "switch": "MANIFESTUAC:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired",
+ "SpaceAppendable"
+ ]
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='false'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "false",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='false'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='true'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG",
+ "comment": "Generate Debug Info",
+ "value": "true",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "GenerateMapFile",
+ "switch": "MAP",
+ "comment": "Generate Map File",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "MapExports",
+ "switch": "MAPINFO:EXPORTS",
+ "comment": "Map Exports",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AssemblyDebug",
+ "switch": "ASSEMBLYDEBUG:DISABLE",
+ "comment": "Debuggable Assembly",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AssemblyDebug",
+ "switch": "ASSEMBLYDEBUG",
+ "comment": "Debuggable Assembly",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LargeAddressAware",
+ "switch": "LARGEADDRESSAWARE:NO",
+ "comment": "Enable Large Addresses",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LargeAddressAware",
+ "switch": "LARGEADDRESSAWARE",
+ "comment": "Enable Large Addresses",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TerminalServerAware",
+ "switch": "TSAWARE:NO",
+ "comment": "Terminal Server",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TerminalServerAware",
+ "switch": "TSAWARE",
+ "comment": "Terminal Server",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SwapRunFromCD",
+ "switch": "SWAPRUN:CD",
+ "comment": "Swap Run From CD",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SwapRunFromNET",
+ "switch": "SWAPRUN:NET",
+ "comment": "Swap Run From Network",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OptimizeReferences",
+ "switch": "OPT:NOREF",
+ "comment": "References",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OptimizeReferences",
+ "switch": "OPT:REF",
+ "comment": "References",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableCOMDATFolding",
+ "switch": "OPT:NOICF",
+ "comment": "Enable COMDAT Folding",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnableCOMDATFolding",
+ "switch": "OPT:ICF",
+ "comment": "Enable COMDAT Folding",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreEmbeddedIDL",
+ "switch": "IGNOREIDL",
+ "comment": "Ignore Embedded IDL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NoEntryPoint",
+ "switch": "NOENTRY",
+ "comment": "No Entry Point",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SetChecksum",
+ "switch": "RELEASE",
+ "comment": "Set Checksum",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RandomizedBaseAddress",
+ "switch": "DYNAMICBASE:NO",
+ "comment": "Randomized Base Address",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RandomizedBaseAddress",
+ "switch": "DYNAMICBASE",
+ "comment": "Randomized Base Address",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FixedBaseAddress",
+ "switch": "FIXED:NO",
+ "comment": "Fixed Base Address",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FixedBaseAddress",
+ "switch": "FIXED",
+ "comment": "Fixed Base Address",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DataExecutionPrevention",
+ "switch": "NXCOMPAT:NO",
+ "comment": "Data Execution Prevention (DEP)",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DataExecutionPrevention",
+ "switch": "NXCOMPAT",
+ "comment": "Data Execution Prevention (DEP)",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TurnOffAssemblyGeneration",
+ "switch": "NOASSEMBLY",
+ "comment": "Turn Off Assembly Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SupportUnloadOfDelayLoadedDLL",
+ "switch": "DELAY:UNLOAD",
+ "comment": "Unload delay loaded DLL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SupportNobindOfDelayLoadedDLL",
+ "switch": "DELAY:NOBIND",
+ "comment": "Nobind delay loaded DLL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Profile",
+ "switch": "PROFILE",
+ "comment": "Profile",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkDelaySign",
+ "switch": "DELAYSIGN:NO",
+ "comment": "Delay Sign",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkDelaySign",
+ "switch": "DELAYSIGN",
+ "comment": "Delay Sign",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CLRUnmanagedCodeCheck",
+ "switch": "CLRUNMANAGEDCODECHECK:NO",
+ "comment": "CLR Unmanaged Code Check",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CLRUnmanagedCodeCheck",
+ "switch": "CLRUNMANAGEDCODECHECK",
+ "comment": "CLR Unmanaged Code Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ImageHasSafeExceptionHandlers",
+ "switch": "SAFESEH:NO",
+ "comment": "Image Has Safe Exception Handlers",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "ImageHasSafeExceptionHandlers",
+ "switch": "SAFESEH",
+ "comment": "Image Has Safe Exception Handlers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkDLL",
+ "switch": "DLL",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibraryDirectories",
+ "switch": "LIBPATH:",
+ "comment": "Additional Library Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IgnoreSpecificDefaultLibraries",
+ "switch": "NODEFAULTLIB:",
+ "comment": "Ignore Specific Default Libraries",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AddModuleNamesToAssembly",
+ "switch": "ASSEMBLYMODULE:",
+ "comment": "Add Module to Assembly",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "EmbedManagedResourceFile",
+ "switch": "ASSEMBLYRESOURCE:",
+ "comment": "Embed Managed Resource File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForceSymbolReferences",
+ "switch": "INCLUDE:",
+ "comment": "Force Symbol References",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "DelayLoadDLLs",
+ "switch": "DELAYLOAD:",
+ "comment": "Delay Loaded Dlls",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AssemblyLinkResource",
+ "switch": "ASSEMBLYLINKRESOURCE:",
+ "comment": "Assembly Link Resource",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalManifestDependencies",
+ "switch": "MANIFESTDEPENDENCY:",
+ "comment": "Additional Manifest Dependencies",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "OutputFile",
+ "switch": "OUT:",
+ "comment": "Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "Version",
+ "switch": "VERSION:",
+ "comment": "Version",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "SpecifySectionAttributes",
+ "switch": "SECTION:",
+ "comment": "Specify Section Attributes",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MSDOSStubFileName",
+ "switch": "STUB:",
+ "comment": "MS-DOS Stub File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ModuleDefinitionFile",
+ "switch": "DEF:",
+ "comment": "Module Definition File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ManifestFile",
+ "switch": "ManifestFile:",
+ "comment": "Manifest File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProgramDatabaseFile",
+ "switch": "PDB:",
+ "comment": "Generate Program Database File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "StripPrivateSymbols",
+ "switch": "PDBSTRIPPED:",
+ "comment": "Strip Private Symbols",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MapFileName",
+ "switch": "MAP:",
+ "comment": "Map File Name",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "HeapReserveSize",
+ "switch": "HEAP:",
+ "comment": "Heap Reserve Size",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "HeapCommitSize",
+ "switch": "HEAP",
+ "comment": "Heap Commit Size",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "StackReserveSize",
+ "switch": "STACK:",
+ "comment": "Stack Reserve Size",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "StackCommitSize",
+ "switch": "STACK",
+ "comment": "Stack Commit Size",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "FunctionOrder",
+ "switch": "ORDER:@",
+ "comment": "Function Order",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProfileGuidedDatabase",
+ "switch": "PGD:",
+ "comment": "Profile Guided Database",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MidlCommandFile",
+ "switch": "MIDL:@",
+ "comment": "MIDL Commands",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MergedIDLBaseFileName",
+ "switch": "IDLOUT:",
+ "comment": "Merged IDL Base File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "TypeLibraryFile",
+ "switch": "TLBOUT:",
+ "comment": "Type Library",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "EntryPointSymbol",
+ "switch": "ENTRY:",
+ "comment": "Entry Point",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "BaseAddress",
+ "switch": "BASE:",
+ "comment": "Base Address",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ImportLibrary",
+ "switch": "IMPLIB:",
+ "comment": "Import Library",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MergeSections",
+ "switch": "MERGE:",
+ "comment": "Merge Sections",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "LinkKeyFile",
+ "switch": "KEYFILE:",
+ "comment": "Key File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "KeyContainer",
+ "switch": "KEYCONTAINER:",
+ "comment": "Key Container",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "TypeLibraryResourceID",
+ "switch": "TLBID:",
+ "comment": "TypeLib Resource ID",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "SectionAlignment",
+ "switch": "ALIGN:",
+ "comment": "SectionAlignment",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v10_MASM.json b/Templates/MSBuild/FlagTables/v10_MASM.json
new file mode 100644
index 0000000..4634306
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v10_MASM.json
@@ -0,0 +1,295 @@
+[
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "",
+ "comment": "Default",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "Cp",
+ "comment": "Preserves Identifier Case (/Cp)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "Cu",
+ "comment": "Maps all identifiers to upper case. (/Cu)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "Cx",
+ "comment": "Preserves case in public and extern symbols. (/Cx)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W0",
+ "comment": "Warning Level 0 (/W0)",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W1",
+ "comment": "Warning Level 1 (/W1)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W2",
+ "comment": "Warning Level 2 (/W2)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W3",
+ "comment": "Warning Level 3 (/W3)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "",
+ "comment": "Default",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp1",
+ "comment": "One Byte Boundary (/Zp1)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp2",
+ "comment": "Two Byte Boundary (/Zp2)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp4",
+ "comment": "Four Byte Boundary (/Zp4)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp8",
+ "comment": "Eight Byte Boundary (/Zp8)",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp16",
+ "comment": "Sixteen Byte Boundary (/Zp16)",
+ "value": "5",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "",
+ "comment": "Default",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gd",
+ "comment": "Use C-style Calling Convention (/Gd)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gz",
+ "comment": "Use stdcall Calling Convention (/Gz)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gc",
+ "comment": "Use Pascal Calling Convention (/Gc)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:prompt",
+ "comment": "Prompt to send report immediately (/errorReport:prompt)",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:queue",
+ "comment": "Prompt to send report at the next logon (/errorReport:queue)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:send",
+ "comment": "Automatically send report (/errorReport:send)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:none",
+ "comment": "Do not send report (/errorReport:none)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "NoLogo",
+ "switch": "nologo",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GeneratePreprocessedSourceListing",
+ "switch": "EP",
+ "comment": "Generate Preprocessed Source Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ListAllAvailableInformation",
+ "switch": "Sa",
+ "comment": "List All Available Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseSafeExceptionHandlers",
+ "switch": "safeseh",
+ "comment": "Use Safe Exception Handlers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AddFirstPassListing",
+ "switch": "Sf",
+ "comment": "Add First Pass Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableAssemblyGeneratedCodeListing",
+ "switch": "Sg",
+ "comment": "Enable Assembly Generated Code Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DisableSymbolTable",
+ "switch": "Sn",
+ "comment": "Disable Symbol Table",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableFalseConditionalsInListing",
+ "switch": "Sx",
+ "comment": "Enable False Conditionals In Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "WX",
+ "comment": "Treat Warnings As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MakeAllSymbolsPublic",
+ "switch": "Zf",
+ "comment": "Make All Symbols Public",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "Zi",
+ "comment": "Generate Debug Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableMASM51Compatibility",
+ "switch": "Zm",
+ "comment": "Enable MASM 5.1 Compatibility",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PerformSyntaxCheckOnly",
+ "switch": "Zs",
+ "comment": "Perform Syntax Check Only",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IncludePaths",
+ "switch": "I",
+ "comment": "Include Paths",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "BrowseFile",
+ "switch": "FR",
+ "comment": "Generate Browse Information File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ObjectFileName",
+ "switch": "Fo",
+ "comment": "Object File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "AssembledCodeListingFile",
+ "switch": "Fl",
+ "comment": "Assembled Code Listing File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v10_NASM.json b/Templates/MSBuild/FlagTables/v10_NASM.json
new file mode 100644
index 0000000..434cd63
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v10_NASM.json
@@ -0,0 +1,201 @@
+[
+ {
+ "name": "Outputswitch",
+ "switch": "fwin",
+ "comment": "Object File win32",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "Outputswitch",
+ "switch": "fwin32",
+ "comment": "Object File win32",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "Outputswitch",
+ "switch": "fwin64",
+ "comment": "Object File win64",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "Outputswitch",
+ "switch": "felf",
+ "comment": "ELF32 (i386) object files (e.g. Linux)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "Outputswitch",
+ "switch": "felf32",
+ "comment": "ELF32 (i386) object files (e.g. Linux)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "Outputswitch",
+ "switch": "felf64",
+ "comment": "ELF64 (x86_64) object files (e.g. Linux)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "ErrorReportingFormat",
+ "switch": "Xgnu",
+ "comment": "-Xgnu GNU format: Default format",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "ErrorReportingFormat",
+ "switch": "Xvc",
+ "comment": "-Xvc Style used by Microsoft Visual C++",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "tasmmode",
+ "switch": "t",
+ "comment": "SciTech TASM compatible mode",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "g",
+ "comment": "Generate Debug Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "Werror",
+ "comment": "Treat Warnings As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "floatunderflow",
+ "switch": "w+float-underflow",
+ "comment": "float-underflow",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "macrodefaults",
+ "switch": "w-macro-defaults",
+ "comment": "Disable macro-defaults",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "user",
+ "switch": "w-user",
+ "comment": "Disable user",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "floatoverflow",
+ "switch": "w-float-overflow",
+ "comment": "Disable float-overflow",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "floatdenorm",
+ "switch": "w+float-denorm",
+ "comment": "float-denorm",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "numberoverflow",
+ "switch": "w-number-overflow",
+ "comment": "Disable number-overflow",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "macroselfref",
+ "switch": "w+macro-selfref",
+ "comment": "macro-selfref",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "floattoolong",
+ "switch": "w-float-toolong",
+ "comment": "Disable float-toolong",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "orphanlabels",
+ "switch": "w-orphan-labels",
+ "comment": "Disable orphan-labels",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AssembledCodeListingFile",
+ "switch": "l",
+ "comment": "Assembled Code Listing File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "Z",
+ "comment": "Redirect Error Messages to File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IncludePaths",
+ "switch": "I",
+ "comment": "Include Paths",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "UndefinePreprocessorDefinitions",
+ "switch": "U",
+ "comment": "Undefine Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "OutputFormat",
+ "switch": "o",
+ "comment": "Output File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v10_RC.json b/Templates/MSBuild/FlagTables/v10_RC.json
new file mode 100644
index 0000000..b8c0127
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v10_RC.json
@@ -0,0 +1,69 @@
+[
+ {
+ "name": "IgnoreStandardIncludePath",
+ "switch": "X",
+ "comment": "Ignore Standard Include Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "v",
+ "comment": "Show Progress",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "nologo",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NullTerminateStrings",
+ "switch": "n",
+ "comment": "Null Terminate Strings",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "UndefinePreprocessorDefinitions",
+ "switch": "u",
+ "comment": "Undefine Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalIncludeDirectories",
+ "switch": "I",
+ "comment": "Additional Include Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ResourceOutputFileName",
+ "switch": "fo",
+ "comment": "Resource File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v11_CL.json b/Templates/MSBuild/FlagTables/v11_CL.json
new file mode 100644
index 0000000..b47ab2e
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v11_CL.json
@@ -0,0 +1,1063 @@
+[
+ {
+ "name": "DebugInformationFormat",
+ "switch": "",
+ "comment": "None",
+ "value": "None",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "Z7",
+ "comment": "C7 compatible",
+ "value": "OldStyle",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "Zi",
+ "comment": "Program Database",
+ "value": "ProgramDatabase",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "ZI",
+ "comment": "Program Database for Edit And Continue",
+ "value": "EditAndContinue",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "",
+ "comment": "No Common Language RunTime Support",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr",
+ "comment": "Common Language RunTime Support",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:pure",
+ "comment": "Pure MSIL Common Language RunTime Support",
+ "value": "Pure",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:safe",
+ "comment": "Safe MSIL Common Language RunTime Support",
+ "value": "Safe",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:oldSyntax",
+ "comment": "Common Language RunTime Support, Old Syntax",
+ "value": "OldSyntax",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W0",
+ "comment": "Turn Off All Warnings",
+ "value": "TurnOffAllWarnings",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W1",
+ "comment": "Level1",
+ "value": "Level1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W2",
+ "comment": "Level2",
+ "value": "Level2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W3",
+ "comment": "Level3",
+ "value": "Level3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W4",
+ "comment": "Level4",
+ "value": "Level4",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "Wall",
+ "comment": "EnableAllWarnings",
+ "value": "EnableAllWarnings",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "Od",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "O1",
+ "comment": "Minimize Size",
+ "value": "MinSpace",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "O2",
+ "comment": "Maximize Speed",
+ "value": "MaxSpeed",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "Ox",
+ "comment": "Full Optimization",
+ "value": "Full",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob0",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob1",
+ "comment": "Only __inline",
+ "value": "OnlyExplicitInline",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob2",
+ "comment": "Any Suitable",
+ "value": "AnySuitable",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "Os",
+ "comment": "Favor small code",
+ "value": "Size",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "Ot",
+ "comment": "Favor fast code",
+ "value": "Speed",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "",
+ "comment": "Neither",
+ "value": "Neither",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHa",
+ "comment": "Yes with SEH Exceptions",
+ "value": "Async",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHsc",
+ "comment": "Yes",
+ "value": "Sync",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHs",
+ "comment": "Yes with Extern C functions",
+ "value": "SyncCThrow",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTCs",
+ "comment": "Stack Frames",
+ "value": "StackFrameRuntimeCheck",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTCu",
+ "comment": "Uninitialized variables",
+ "value": "UninitializedLocalUsageCheck",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTC1",
+ "comment": "Both (/RTC1, equiv. to /RTCsu)",
+ "value": "EnableFastChecks",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MT",
+ "comment": "Multi-threaded",
+ "value": "MultiThreaded",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MTd",
+ "comment": "Multi-threaded Debug",
+ "value": "MultiThreadedDebug",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MD",
+ "comment": "Multi-threaded DLL",
+ "value": "MultiThreadedDLL",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MDd",
+ "comment": "Multi-threaded Debug DLL",
+ "value": "MultiThreadedDebugDLL",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp1",
+ "comment": "1 Byte",
+ "value": "1Byte",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp2",
+ "comment": "2 Bytes",
+ "value": "2Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp4",
+ "comment": "4 Byte",
+ "value": "4Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp8",
+ "comment": "8 Bytes",
+ "value": "8Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp16",
+ "comment": "16 Bytes",
+ "value": "16Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:SSE",
+ "comment": "Streaming SIMD Extensions",
+ "value": "StreamingSIMDExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:SSE2",
+ "comment": "Streaming SIMD Extensions 2",
+ "value": "StreamingSIMDExtensions2",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:AVX",
+ "comment": "Advanced Vector Extensions",
+ "value": "AdvancedVectorExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:IA32",
+ "comment": "No Enhanced Instructions",
+ "value": "NoExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:precise",
+ "comment": "Precise",
+ "value": "Precise",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:strict",
+ "comment": "Strict",
+ "value": "Strict",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:fast",
+ "comment": "Fast",
+ "value": "Fast",
+ "flags": []
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Yc",
+ "comment": "Create",
+ "value": "Create",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Yu",
+ "comment": "Use",
+ "value": "Use",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Y-",
+ "comment": "Not Using Precompiled Headers",
+ "value": "NotUsing",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "",
+ "comment": "No Listing",
+ "value": "NoListing",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FA",
+ "comment": "Assembly-Only Listing",
+ "value": "AssemblyCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAc",
+ "comment": "Assembly With Machine Code",
+ "value": "AssemblyAndMachineCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAs",
+ "comment": "Assembly With Source Code",
+ "value": "AssemblyAndSourceCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAcs",
+ "comment": "Assembly, Machine Code and Source",
+ "value": "All",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gd",
+ "comment": "__cdecl",
+ "value": "Cdecl",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gr",
+ "comment": "__fastcall",
+ "value": "FastCall",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gz",
+ "comment": "__stdcall",
+ "value": "StdCall",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "TC",
+ "comment": "Compile as C Code",
+ "value": "CompileAsC",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "TP",
+ "comment": "Compile as C++ Code",
+ "value": "CompileAsCpp",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:none",
+ "comment": "Do Not Send Report",
+ "value": "None",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:prompt",
+ "comment": "Prompt Immediately",
+ "value": "Prompt",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:queue",
+ "comment": "Queue For Next Login",
+ "value": "Queue",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:send",
+ "comment": "Send Automatically",
+ "value": "Send",
+ "flags": []
+ },
+ {
+ "name": "CompileAsWinRT",
+ "switch": "ZW",
+ "comment": "Consume Windows Runtime Extension",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WinRTNoStdLib",
+ "switch": "ZW:nostdlib",
+ "comment": "No Standard WinRT Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "nologo-",
+ "comment": "Suppress Startup Banner",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "nologo",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningAsError",
+ "switch": "WX-",
+ "comment": "Treat Warnings As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningAsError",
+ "switch": "WX",
+ "comment": "Treat Warnings As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SDLCheck",
+ "switch": "sdl-",
+ "comment": "SDL checks",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "SDLCheck",
+ "switch": "sdl",
+ "comment": "SDL checks",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MultiProcessorCompilation",
+ "switch": "MP",
+ "comment": "Multi-processor Compilation",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "IntrinsicFunctions",
+ "switch": "Oi",
+ "comment": "Enable Intrinsic Functions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OmitFramePointers",
+ "switch": "Oy-",
+ "comment": "Omit Frame Pointers",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OmitFramePointers",
+ "switch": "Oy",
+ "comment": "Omit Frame Pointers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableFiberSafeOptimizations",
+ "switch": "GT",
+ "comment": "Enable Fiber-Safe Optimizations",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WholeProgramOptimization",
+ "switch": "GL",
+ "comment": "Whole Program Optimization",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UndefineAllPreprocessorDefinitions",
+ "switch": "u",
+ "comment": "Undefine All Preprocessor Definitions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreStandardIncludePath",
+ "switch": "X",
+ "comment": "Ignore Standard Include Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessToFile",
+ "switch": "P",
+ "comment": "Preprocess to a File",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessSuppressLineNumbers",
+ "switch": "EP",
+ "comment": "Preprocess Suppress Line Numbers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessKeepComments",
+ "switch": "C",
+ "comment": "Keep Comments",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "StringPooling",
+ "switch": "GF-",
+ "comment": "Enable String Pooling",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "StringPooling",
+ "switch": "GF",
+ "comment": "Enable String Pooling",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MinimalRebuild",
+ "switch": "Gm-",
+ "comment": "Enable Minimal Rebuild",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "MinimalRebuild",
+ "switch": "Gm",
+ "comment": "Enable Minimal Rebuild",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SmallerTypeCheck",
+ "switch": "RTCc",
+ "comment": "Smaller Type Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "BufferSecurityCheck",
+ "switch": "GS-",
+ "comment": "Security Check",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "BufferSecurityCheck",
+ "switch": "GS",
+ "comment": "Security Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FunctionLevelLinking",
+ "switch": "Gy-",
+ "comment": "Enable Function-Level Linking",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FunctionLevelLinking",
+ "switch": "Gy",
+ "comment": "Enable Function-Level Linking",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableParallelCodeGeneration",
+ "switch": "Qpar-",
+ "comment": "Enable Parallel Code Generation",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnableParallelCodeGeneration",
+ "switch": "Qpar",
+ "comment": "Enable Parallel Code Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointExceptions",
+ "switch": "fp:except-",
+ "comment": "Enable Floating Point Exceptions",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointExceptions",
+ "switch": "fp:except",
+ "comment": "Enable Floating Point Exceptions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CreateHotpatchableImage",
+ "switch": "hotpatch",
+ "comment": "Create Hotpatchable Image",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DisableLanguageExtensions",
+ "switch": "Za",
+ "comment": "Disable Language Extensions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWChar_tAsBuiltInType",
+ "switch": "Zc:wchar_t-",
+ "comment": "Treat WChar_t As Built in Type",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWChar_tAsBuiltInType",
+ "switch": "Zc:wchar_t",
+ "comment": "Treat WChar_t As Built in Type",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ForceConformanceInForLoopScope",
+ "switch": "Zc:forScope-",
+ "comment": "Force Conformance in For Loop Scope",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "ForceConformanceInForLoopScope",
+ "switch": "Zc:forScope",
+ "comment": "Force Conformance in For Loop Scope",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RuntimeTypeInfo",
+ "switch": "GR-",
+ "comment": "Enable Run-Time Type Information",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RuntimeTypeInfo",
+ "switch": "GR",
+ "comment": "Enable Run-Time Type Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OpenMPSupport",
+ "switch": "openmp-",
+ "comment": "Open MP Support",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OpenMPSupport",
+ "switch": "openmp",
+ "comment": "Open MP Support",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ExpandAttributedSource",
+ "switch": "Fx",
+ "comment": "Expand Attributed Source",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseUnicodeForAssemblerListing",
+ "switch": "FAu",
+ "comment": "Use Unicode For Assembler Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateXMLDocumentationFiles",
+ "switch": "doc",
+ "comment": "Generate XML Documentation Files",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "BrowseInformation",
+ "switch": "FR",
+ "comment": "Enable Browse Information",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "ShowIncludes",
+ "switch": "showIncludes",
+ "comment": "Show Includes",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnablePREfast",
+ "switch": "analyze-",
+ "comment": "Enable Code Analysis",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnablePREfast",
+ "switch": "analyze",
+ "comment": "Enable Code Analysis",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseFullPaths",
+ "switch": "FC",
+ "comment": "Use Full Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OmitDefaultLibName",
+ "switch": "Zl",
+ "comment": "Omit Default Library Name",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalIncludeDirectories",
+ "switch": "I",
+ "comment": "Additional Include Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalUsingDirectories",
+ "switch": "AI",
+ "comment": "Additional #using Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "UndefinePreprocessorDefinitions",
+ "switch": "U",
+ "comment": "Undefine Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "DisableSpecificWarnings",
+ "switch": "wd",
+ "comment": "Disable Specific Warnings",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForcedIncludeFiles",
+ "switch": "FI",
+ "comment": "Forced Include File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForcedUsingFiles",
+ "switch": "FU",
+ "comment": "Forced #using File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PREfastLog",
+ "switch": "analyze:log",
+ "comment": "Code Analysis Log",
+ "value": "",
+ "flags": [
+ "UserFollowing"
+ ]
+ },
+ {
+ "name": "PREfastAdditionalPlugins",
+ "switch": "analyze:plugin",
+ "comment": "Additional Code Analysis Native plugins",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "TreatSpecificWarningsAsErrors",
+ "switch": "we",
+ "comment": "Treat Specific Warnings As Errors",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PreprocessOutputPath",
+ "switch": "Fi",
+ "comment": "Preprocess Output Path",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderFile",
+ "switch": "Yu",
+ "comment": "Precompiled Header File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderFile",
+ "switch": "Yc",
+ "comment": "Precompiled Header File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderOutputFile",
+ "switch": "Fp",
+ "comment": "Precompiled Header Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "AssemblerListingLocation",
+ "switch": "Fa",
+ "comment": "ASM List Location",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ObjectFileName",
+ "switch": "Fo",
+ "comment": "Object File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProgramDataBaseFileName",
+ "switch": "Fd",
+ "comment": "Program Database File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "XMLDocumentationFileName",
+ "switch": "doc",
+ "comment": "XML Documentation File Name",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "BrowseInformationFile",
+ "switch": "FR",
+ "comment": "Browse Information File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ProcessorNumber",
+ "switch": "MP",
+ "comment": "Number of processors",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v11_CSharp.json b/Templates/MSBuild/FlagTables/v11_CSharp.json
new file mode 100644
index 0000000..5989aea
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v11_CSharp.json
@@ -0,0 +1,574 @@
+[
+ {
+ "name": "ProjectName",
+ "switch": "out:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:exe",
+ "comment": "",
+ "value": "Exe",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:winexe",
+ "comment": "",
+ "value": "Winexe",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:library",
+ "comment": "",
+ "value": "Library",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:module",
+ "comment": "",
+ "value": "Module",
+ "flags": []
+ },
+ {
+ "name": "DocumentationFile",
+ "switch": "doc",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:x86",
+ "comment": "",
+ "value": "x86",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:Itanium",
+ "comment": "",
+ "value": "Itanium",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:x64",
+ "comment": "",
+ "value": "x64",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:arm",
+ "comment": "",
+ "value": "arm",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:anycpu32bitpreferred",
+ "comment": "",
+ "value": "anycpu32bitpreferred",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:anycpu",
+ "comment": "",
+ "value": "anycpu",
+ "flags": []
+ },
+ {
+ "name": "References",
+ "switch": "reference:",
+ "comment": "mit alias",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "References",
+ "switch": "reference:",
+ "comment": "dateiliste",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "AddModules",
+ "switch": "addmodule:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "Win32Resource",
+ "switch": "win32res:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ApplicationIcon",
+ "switch": "win32icon:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ApplicationManifest",
+ "switch": "win32manifest:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "NoWin32Manifest",
+ "switch": "nowin32manifest",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DefineDebug",
+ "switch": "debug",
+ "comment": "",
+ "value": "true",
+ "flags": [
+ "Continue"
+ ]
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:none",
+ "comment": "",
+ "value": "none",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:full",
+ "comment": "",
+ "value": "full",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:pdbonly",
+ "comment": "",
+ "value": "pdbonly",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror-",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror+",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:0",
+ "comment": "",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:1",
+ "comment": "",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:2",
+ "comment": "",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:3",
+ "comment": "",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:4",
+ "comment": "",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "NoWarn",
+ "switch": "nowarn:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired",
+ "CommaAppendable"
+ ]
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DefineConstants",
+ "switch": "define:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "SemicolonAppendable",
+ "UserValue"
+ ]
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:ISO-1",
+ "comment": "",
+ "value": "ISO-1",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:ISO-2",
+ "comment": "",
+ "value": "ISO-2",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:3",
+ "comment": "",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:4",
+ "comment": "",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:5",
+ "comment": "",
+ "value": "5",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:6",
+ "comment": "",
+ "value": "6",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:default",
+ "comment": "",
+ "value": "default",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AssemblyOriginatorKeyFile",
+ "switch": "keyfile",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "KeyContainerName",
+ "switch": "keycontainer",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoLogo",
+ "switch": "nologo",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoConfig",
+ "switch": "noconfig",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "BaseAddress",
+ "switch": "baseaddress:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "CodePage",
+ "switch": "codepage",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "Utf8Output",
+ "switch": "utf8output",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "MainEntryPoint",
+ "switch": "main:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "GenerateFullPaths",
+ "switch": "fullpaths",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FileAlignment",
+ "switch": "filealign",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "PdbFile",
+ "switch": "pdb:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SubsystemVersion",
+ "switch": "subsystemversion",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibPaths",
+ "switch": "lib:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:none",
+ "comment": "Do Not Send Report",
+ "value": "none",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:prompt",
+ "comment": "Prompt Immediately",
+ "value": "prompt",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:queue",
+ "comment": "Queue For Next Login",
+ "value": "queue",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:send",
+ "comment": "Send Automatically",
+ "value": "send",
+ "flags": []
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v11_LIB.json b/Templates/MSBuild/FlagTables/v11_LIB.json
new file mode 100644
index 0000000..58a238c
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v11_LIB.json
@@ -0,0 +1,297 @@
+[
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:PROMPT",
+ "comment": "PromptImmediately",
+ "value": "PromptImmediately",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:QUEUE",
+ "comment": "Queue For Next Login",
+ "value": "QueueForNextLogin",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:SEND",
+ "comment": "Send Error Report",
+ "value": "SendErrorReport",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:NONE",
+ "comment": "No Error Report",
+ "value": "NoErrorReport",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM",
+ "comment": "MachineARM",
+ "value": "MachineARM",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:EBC",
+ "comment": "MachineEBC",
+ "value": "MachineEBC",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:IA64",
+ "comment": "MachineIA64",
+ "value": "MachineIA64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS",
+ "comment": "MachineMIPS",
+ "value": "MachineMIPS",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS16",
+ "comment": "MachineMIPS16",
+ "value": "MachineMIPS16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU",
+ "comment": "MachineMIPSFPU",
+ "value": "MachineMIPSFPU",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU16",
+ "comment": "MachineMIPSFPU16",
+ "value": "MachineMIPSFPU16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:SH4",
+ "comment": "MachineSH4",
+ "value": "MachineSH4",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:THUMB",
+ "comment": "MachineTHUMB",
+ "value": "MachineTHUMB",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X64",
+ "comment": "MachineX64",
+ "value": "MachineX64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X86",
+ "comment": "MachineX86",
+ "value": "MachineX86",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:CONSOLE",
+ "comment": "Console",
+ "value": "Console",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWS",
+ "comment": "Windows",
+ "value": "Windows",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:NATIVE",
+ "comment": "Native",
+ "value": "Native",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_APPLICATION",
+ "comment": "EFI Application",
+ "value": "EFI Application",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "comment": "EFI Boot Service Driver",
+ "value": "EFI Boot Service Driver",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_ROM",
+ "comment": "EFI ROM",
+ "value": "EFI ROM",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_RUNTIME_DRIVER",
+ "comment": "EFI Runtime",
+ "value": "EFI Runtime",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWSCE",
+ "comment": "WindowsCE",
+ "value": "WindowsCE",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:POSIX",
+ "comment": "POSIX",
+ "value": "POSIX",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "NOLOGO",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreAllDefaultLibraries",
+ "switch": "NODEFAULTLIB",
+ "comment": "Ignore All Default Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatLibWarningAsErrors",
+ "switch": "WX:NO",
+ "comment": "Treat Lib Warning As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatLibWarningAsErrors",
+ "switch": "WX",
+ "comment": "Treat Lib Warning As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Verbose",
+ "switch": "VERBOSE",
+ "comment": "Verbose",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG",
+ "comment": "Link Time Code Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibraryDirectories",
+ "switch": "LIBPATH:",
+ "comment": "Additional Library Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IgnoreSpecificDefaultLibraries",
+ "switch": "NODEFAULTLIB:",
+ "comment": "Ignore Specific Default Libraries",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ExportNamedFunctions",
+ "switch": "EXPORT:",
+ "comment": "Export Named Functions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "RemoveObjects",
+ "switch": "REMOVE:",
+ "comment": "Remove Objects",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "OutputFile",
+ "switch": "OUT:",
+ "comment": "Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ModuleDefinitionFile",
+ "switch": "DEF:",
+ "comment": "Module Definition File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ForceSymbolReferences",
+ "switch": "INCLUDE:",
+ "comment": "Force Symbol References",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "DisplayLibrary",
+ "switch": "LIST:",
+ "comment": "Display Library to standard output",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "Name",
+ "switch": "NAME:",
+ "comment": "Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v11_Link.json b/Templates/MSBuild/FlagTables/v11_Link.json
new file mode 100644
index 0000000..5d5c13f
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v11_Link.json
@@ -0,0 +1,1272 @@
+[
+ {
+ "name": "ShowProgress",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE",
+ "comment": "Display all progress messages",
+ "value": "LinkVerbose",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:Lib",
+ "comment": "For Libraries Searched",
+ "value": "LinkVerboseLib",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:ICF",
+ "comment": "About COMDAT folding during optimized linking",
+ "value": "LinkVerboseICF",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:REF",
+ "comment": "About data removed during optimized linking",
+ "value": "LinkVerboseREF",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:SAFESEH",
+ "comment": "About Modules incompatible with SEH",
+ "value": "LinkVerboseSAFESEH",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:CLR",
+ "comment": "About linker activity related to managed code",
+ "value": "LinkVerboseCLR",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE:MULTIPLE",
+ "comment": "Multiply Defined Symbol Only",
+ "value": "MultiplyDefinedSymbolOnly",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE:UNRESOLVED",
+ "comment": "Undefined Symbol Only",
+ "value": "UndefinedSymbolOnly",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:5",
+ "comment": "X86 Image Only",
+ "value": "X86Image",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:6",
+ "comment": "X64 Image Only",
+ "value": "X64Image",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:16",
+ "comment": "Itanium Image Only",
+ "value": "ItaniumImage",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='asInvoker'",
+ "comment": "asInvoker",
+ "value": "AsInvoker",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='highestAvailable'",
+ "comment": "highestAvailable",
+ "value": "HighestAvailable",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='requireAdministrator'",
+ "comment": "requireAdministrator",
+ "value": "RequireAdministrator",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:CONSOLE",
+ "comment": "Console",
+ "value": "Console",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWS",
+ "comment": "Windows",
+ "value": "Windows",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:NATIVE",
+ "comment": "Native",
+ "value": "Native",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_APPLICATION",
+ "comment": "EFI Application",
+ "value": "EFI Application",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "comment": "EFI Boot Service Driver",
+ "value": "EFI Boot Service Driver",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_ROM",
+ "comment": "EFI ROM",
+ "value": "EFI ROM",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_RUNTIME_DRIVER",
+ "comment": "EFI Runtime",
+ "value": "EFI Runtime",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:POSIX",
+ "comment": "POSIX",
+ "value": "POSIX",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "Driver",
+ "comment": "Driver",
+ "value": "Driver",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "DRIVER:UPONLY",
+ "comment": "UP Only",
+ "value": "UpOnly",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "DRIVER:WDM",
+ "comment": "WDM",
+ "value": "WDM",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG",
+ "comment": "Use Link Time Code Generation",
+ "value": "UseLinkTimeCodeGeneration",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGInstrument",
+ "comment": "Profile Guided Optimization - Instrument",
+ "value": "PGInstrument",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGOptimize",
+ "comment": "Profile Guided Optimization - Optimization",
+ "value": "PGOptimization",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGUpdate",
+ "comment": "Profile Guided Optimization - Update",
+ "value": "PGUpdate",
+ "flags": []
+ },
+ {
+ "name": "GenerateWindowsMetadata",
+ "switch": "WINMD",
+ "comment": "Yes",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateWindowsMetadata",
+ "switch": "WINMD:NO",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA1",
+ "comment": "SHA1",
+ "value": "SHA1",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA256",
+ "comment": "SHA256",
+ "value": "SHA256",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA384",
+ "comment": "SHA384",
+ "value": "SHA384",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA512",
+ "comment": "SHA512",
+ "value": "SHA512",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM",
+ "comment": "MachineARM",
+ "value": "MachineARM",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:EBC",
+ "comment": "MachineEBC",
+ "value": "MachineEBC",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:IA64",
+ "comment": "MachineIA64",
+ "value": "MachineIA64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS",
+ "comment": "MachineMIPS",
+ "value": "MachineMIPS",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS16",
+ "comment": "MachineMIPS16",
+ "value": "MachineMIPS16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU",
+ "comment": "MachineMIPSFPU",
+ "value": "MachineMIPSFPU",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU16",
+ "comment": "MachineMIPSFPU16",
+ "value": "MachineMIPSFPU16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:SH4",
+ "comment": "MachineSH4",
+ "value": "MachineSH4",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:THUMB",
+ "comment": "MachineTHUMB",
+ "value": "MachineTHUMB",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X64",
+ "comment": "MachineX64",
+ "value": "MachineX64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X86",
+ "comment": "MachineX86",
+ "value": "MachineX86",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:MTA",
+ "comment": "MTA threading attribute",
+ "value": "MTAThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:STA",
+ "comment": "STA threading attribute",
+ "value": "STAThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:NONE",
+ "comment": "Default threading attribute",
+ "value": "DefaultThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:IJW",
+ "comment": "Force IJW image",
+ "value": "ForceIJWImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:PURE",
+ "comment": "Force Pure IL Image",
+ "value": "ForcePureILImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:SAFE",
+ "comment": "Force Safe IL Image",
+ "value": "ForceSafeILImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "",
+ "comment": "Default image type",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA1",
+ "comment": "SHA1",
+ "value": "SHA1",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA256",
+ "comment": "SHA256",
+ "value": "SHA256",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA384",
+ "comment": "SHA384",
+ "value": "SHA384",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA512",
+ "comment": "SHA512",
+ "value": "SHA512",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:PROMPT",
+ "comment": "PromptImmediately",
+ "value": "PromptImmediately",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:QUEUE",
+ "comment": "Queue For Next Login",
+ "value": "QueueForNextLogin",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:SEND",
+ "comment": "Send Error Report",
+ "value": "SendErrorReport",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:NONE",
+ "comment": "No Error Report",
+ "value": "NoErrorReport",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError:NO",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError:SYSTEMDLL",
+ "comment": "System Dlls Only",
+ "value": "SystemDlls",
+ "flags": []
+ },
+ {
+ "name": "LinkIncremental",
+ "switch": "INCREMENTAL:NO",
+ "comment": "Enable Incremental Linking",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkIncremental",
+ "switch": "INCREMENTAL",
+ "comment": "Enable Incremental Linking",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "NOLOGO",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkStatus",
+ "switch": "LTCG:NOSTATUS",
+ "comment": "Link Status",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkStatus",
+ "switch": "LTCG:STATUS",
+ "comment": "Link Status",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreventDllBinding",
+ "switch": "ALLOWBIND:NO",
+ "comment": "Prevent Dll Binding",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "PreventDllBinding",
+ "switch": "ALLOWBIND",
+ "comment": "Prevent Dll Binding",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatLinkerWarningAsErrors",
+ "switch": "WX:NO",
+ "comment": "Treat Linker Warning As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatLinkerWarningAsErrors",
+ "switch": "WX",
+ "comment": "Treat Linker Warning As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreAllDefaultLibraries",
+ "switch": "NODEFAULTLIB",
+ "comment": "Ignore All Default Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateManifest",
+ "switch": "MANIFEST:NO",
+ "comment": "Generate Manifest",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "GenerateManifest",
+ "switch": "MANIFEST",
+ "comment": "Generate Manifest",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowIsolation",
+ "switch": "ALLOWISOLATION:NO",
+ "comment": "Allow Isolation",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AllowIsolation",
+ "switch": "",
+ "comment": "Allow Isolation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableUAC",
+ "switch": "MANIFESTUAC:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired",
+ "SpaceAppendable"
+ ]
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='false'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "false",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='false'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='true'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ManifestEmbed",
+ "switch": "manifest:embed",
+ "comment": "Embed Manifest",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG",
+ "comment": "Generate Debug Info",
+ "value": "true",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "GenerateMapFile",
+ "switch": "MAP",
+ "comment": "Generate Map File",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "MapExports",
+ "switch": "MAPINFO:EXPORTS",
+ "comment": "Map Exports",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AssemblyDebug",
+ "switch": "ASSEMBLYDEBUG:DISABLE",
+ "comment": "Debuggable Assembly",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AssemblyDebug",
+ "switch": "ASSEMBLYDEBUG",
+ "comment": "Debuggable Assembly",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LargeAddressAware",
+ "switch": "LARGEADDRESSAWARE:NO",
+ "comment": "Enable Large Addresses",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LargeAddressAware",
+ "switch": "LARGEADDRESSAWARE",
+ "comment": "Enable Large Addresses",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TerminalServerAware",
+ "switch": "TSAWARE:NO",
+ "comment": "Terminal Server",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TerminalServerAware",
+ "switch": "TSAWARE",
+ "comment": "Terminal Server",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SwapRunFromCD",
+ "switch": "SWAPRUN:CD",
+ "comment": "Swap Run From CD",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SwapRunFromNET",
+ "switch": "SWAPRUN:NET",
+ "comment": "Swap Run From Network",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OptimizeReferences",
+ "switch": "OPT:NOREF",
+ "comment": "References",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OptimizeReferences",
+ "switch": "OPT:REF",
+ "comment": "References",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableCOMDATFolding",
+ "switch": "OPT:NOICF",
+ "comment": "Enable COMDAT Folding",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnableCOMDATFolding",
+ "switch": "OPT:ICF",
+ "comment": "Enable COMDAT Folding",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreEmbeddedIDL",
+ "switch": "IGNOREIDL",
+ "comment": "Ignore Embedded IDL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AppContainer",
+ "switch": "APPCONTAINER",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataLinkDelaySign",
+ "switch": "WINMDDELAYSIGN:NO",
+ "comment": "Windows Metadata Delay Sign",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataLinkDelaySign",
+ "switch": "WINMDDELAYSIGN",
+ "comment": "Windows Metadata Delay Sign",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NoEntryPoint",
+ "switch": "NOENTRY",
+ "comment": "No Entry Point",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SetChecksum",
+ "switch": "RELEASE",
+ "comment": "Set Checksum",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RandomizedBaseAddress",
+ "switch": "DYNAMICBASE:NO",
+ "comment": "Randomized Base Address",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RandomizedBaseAddress",
+ "switch": "DYNAMICBASE",
+ "comment": "Randomized Base Address",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FixedBaseAddress",
+ "switch": "FIXED:NO",
+ "comment": "Fixed Base Address",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FixedBaseAddress",
+ "switch": "FIXED",
+ "comment": "Fixed Base Address",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DataExecutionPrevention",
+ "switch": "NXCOMPAT:NO",
+ "comment": "Data Execution Prevention (DEP)",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DataExecutionPrevention",
+ "switch": "NXCOMPAT",
+ "comment": "Data Execution Prevention (DEP)",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TurnOffAssemblyGeneration",
+ "switch": "NOASSEMBLY",
+ "comment": "Turn Off Assembly Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SupportUnloadOfDelayLoadedDLL",
+ "switch": "DELAY:UNLOAD",
+ "comment": "Unload delay loaded DLL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SupportNobindOfDelayLoadedDLL",
+ "switch": "DELAY:NOBIND",
+ "comment": "Nobind delay loaded DLL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Profile",
+ "switch": "PROFILE",
+ "comment": "Profile",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkDelaySign",
+ "switch": "DELAYSIGN:NO",
+ "comment": "Delay Sign",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkDelaySign",
+ "switch": "DELAYSIGN",
+ "comment": "Delay Sign",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CLRUnmanagedCodeCheck",
+ "switch": "CLRUNMANAGEDCODECHECK:NO",
+ "comment": "CLR Unmanaged Code Check",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CLRUnmanagedCodeCheck",
+ "switch": "CLRUNMANAGEDCODECHECK",
+ "comment": "CLR Unmanaged Code Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DetectOneDefinitionRule",
+ "switch": "ODR",
+ "comment": "Detect One Definition Rule violations",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ImageHasSafeExceptionHandlers",
+ "switch": "SAFESEH:NO",
+ "comment": "Image Has Safe Exception Handlers",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "ImageHasSafeExceptionHandlers",
+ "switch": "SAFESEH",
+ "comment": "Image Has Safe Exception Handlers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkDLL",
+ "switch": "DLL",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibraryDirectories",
+ "switch": "LIBPATH:",
+ "comment": "Additional Library Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IgnoreSpecificDefaultLibraries",
+ "switch": "NODEFAULTLIB:",
+ "comment": "Ignore Specific Default Libraries",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AddModuleNamesToAssembly",
+ "switch": "ASSEMBLYMODULE:",
+ "comment": "Add Module to Assembly",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "EmbedManagedResourceFile",
+ "switch": "ASSEMBLYRESOURCE:",
+ "comment": "Embed Managed Resource File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForceSymbolReferences",
+ "switch": "INCLUDE:",
+ "comment": "Force Symbol References",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "DelayLoadDLLs",
+ "switch": "DELAYLOAD:",
+ "comment": "Delay Loaded Dlls",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AssemblyLinkResource",
+ "switch": "ASSEMBLYLINKRESOURCE:",
+ "comment": "Assembly Link Resource",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalManifestDependencies",
+ "switch": "MANIFESTDEPENDENCY:",
+ "comment": "Additional Manifest Dependencies",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ManifestInput",
+ "switch": "manifestinput:",
+ "comment": "Manifest Input",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "OutputFile",
+ "switch": "OUT:",
+ "comment": "Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "Version",
+ "switch": "VERSION:",
+ "comment": "Version",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "SpecifySectionAttributes",
+ "switch": "SECTION:",
+ "comment": "Specify Section Attributes",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MSDOSStubFileName",
+ "switch": "STUB:",
+ "comment": "MS-DOS Stub File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ModuleDefinitionFile",
+ "switch": "DEF:",
+ "comment": "Module Definition File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ManifestFile",
+ "switch": "ManifestFile:",
+ "comment": "Manifest File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProgramDatabaseFile",
+ "switch": "PDB:",
+ "comment": "Generate Program Database File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "StripPrivateSymbols",
+ "switch": "PDBSTRIPPED:",
+ "comment": "Strip Private Symbols",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MapFileName",
+ "switch": "MAP:",
+ "comment": "Map File Name",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "HeapReserveSize",
+ "switch": "HEAP:",
+ "comment": "Heap Reserve Size",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "HeapCommitSize",
+ "switch": "HEAP",
+ "comment": "Heap Commit Size",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "StackReserveSize",
+ "switch": "STACK:",
+ "comment": "Stack Reserve Size",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "StackCommitSize",
+ "switch": "STACK",
+ "comment": "Stack Commit Size",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "FunctionOrder",
+ "switch": "ORDER:@",
+ "comment": "Function Order",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProfileGuidedDatabase",
+ "switch": "PGD:",
+ "comment": "Profile Guided Database",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MidlCommandFile",
+ "switch": "MIDL:@",
+ "comment": "MIDL Commands",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MergedIDLBaseFileName",
+ "switch": "IDLOUT:",
+ "comment": "Merged IDL Base File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "TypeLibraryFile",
+ "switch": "TLBOUT:",
+ "comment": "Type Library",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataFile",
+ "switch": "WINMDFILE:",
+ "comment": "Windows Metadata File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataLinkKeyFile",
+ "switch": "WINMDKEYFILE:",
+ "comment": "Windows Metadata Key File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataKeyContainer",
+ "switch": "WINMDKEYCONTAINER:",
+ "comment": "Windows Metadata Key Container",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "EntryPointSymbol",
+ "switch": "ENTRY:",
+ "comment": "Entry Point",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "BaseAddress",
+ "switch": "BASE:",
+ "comment": "Base Address",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ImportLibrary",
+ "switch": "IMPLIB:",
+ "comment": "Import Library",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MergeSections",
+ "switch": "MERGE:",
+ "comment": "Merge Sections",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "LinkKeyFile",
+ "switch": "KEYFILE:",
+ "comment": "Key File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "KeyContainer",
+ "switch": "KEYCONTAINER:",
+ "comment": "Key Container",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "TypeLibraryResourceID",
+ "switch": "TLBID:",
+ "comment": "TypeLib Resource ID",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "SectionAlignment",
+ "switch": "ALIGN:",
+ "comment": "SectionAlignment",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v11_MASM.json b/Templates/MSBuild/FlagTables/v11_MASM.json
new file mode 100644
index 0000000..4634306
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v11_MASM.json
@@ -0,0 +1,295 @@
+[
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "",
+ "comment": "Default",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "Cp",
+ "comment": "Preserves Identifier Case (/Cp)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "Cu",
+ "comment": "Maps all identifiers to upper case. (/Cu)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "Cx",
+ "comment": "Preserves case in public and extern symbols. (/Cx)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W0",
+ "comment": "Warning Level 0 (/W0)",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W1",
+ "comment": "Warning Level 1 (/W1)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W2",
+ "comment": "Warning Level 2 (/W2)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W3",
+ "comment": "Warning Level 3 (/W3)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "",
+ "comment": "Default",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp1",
+ "comment": "One Byte Boundary (/Zp1)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp2",
+ "comment": "Two Byte Boundary (/Zp2)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp4",
+ "comment": "Four Byte Boundary (/Zp4)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp8",
+ "comment": "Eight Byte Boundary (/Zp8)",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp16",
+ "comment": "Sixteen Byte Boundary (/Zp16)",
+ "value": "5",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "",
+ "comment": "Default",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gd",
+ "comment": "Use C-style Calling Convention (/Gd)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gz",
+ "comment": "Use stdcall Calling Convention (/Gz)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gc",
+ "comment": "Use Pascal Calling Convention (/Gc)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:prompt",
+ "comment": "Prompt to send report immediately (/errorReport:prompt)",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:queue",
+ "comment": "Prompt to send report at the next logon (/errorReport:queue)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:send",
+ "comment": "Automatically send report (/errorReport:send)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:none",
+ "comment": "Do not send report (/errorReport:none)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "NoLogo",
+ "switch": "nologo",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GeneratePreprocessedSourceListing",
+ "switch": "EP",
+ "comment": "Generate Preprocessed Source Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ListAllAvailableInformation",
+ "switch": "Sa",
+ "comment": "List All Available Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseSafeExceptionHandlers",
+ "switch": "safeseh",
+ "comment": "Use Safe Exception Handlers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AddFirstPassListing",
+ "switch": "Sf",
+ "comment": "Add First Pass Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableAssemblyGeneratedCodeListing",
+ "switch": "Sg",
+ "comment": "Enable Assembly Generated Code Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DisableSymbolTable",
+ "switch": "Sn",
+ "comment": "Disable Symbol Table",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableFalseConditionalsInListing",
+ "switch": "Sx",
+ "comment": "Enable False Conditionals In Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "WX",
+ "comment": "Treat Warnings As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MakeAllSymbolsPublic",
+ "switch": "Zf",
+ "comment": "Make All Symbols Public",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "Zi",
+ "comment": "Generate Debug Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableMASM51Compatibility",
+ "switch": "Zm",
+ "comment": "Enable MASM 5.1 Compatibility",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PerformSyntaxCheckOnly",
+ "switch": "Zs",
+ "comment": "Perform Syntax Check Only",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IncludePaths",
+ "switch": "I",
+ "comment": "Include Paths",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "BrowseFile",
+ "switch": "FR",
+ "comment": "Generate Browse Information File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ObjectFileName",
+ "switch": "Fo",
+ "comment": "Object File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "AssembledCodeListingFile",
+ "switch": "Fl",
+ "comment": "Assembled Code Listing File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v11_RC.json b/Templates/MSBuild/FlagTables/v11_RC.json
new file mode 100644
index 0000000..b8c0127
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v11_RC.json
@@ -0,0 +1,69 @@
+[
+ {
+ "name": "IgnoreStandardIncludePath",
+ "switch": "X",
+ "comment": "Ignore Standard Include Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "v",
+ "comment": "Show Progress",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "nologo",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NullTerminateStrings",
+ "switch": "n",
+ "comment": "Null Terminate Strings",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "UndefinePreprocessorDefinitions",
+ "switch": "u",
+ "comment": "Undefine Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalIncludeDirectories",
+ "switch": "I",
+ "comment": "Additional Include Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ResourceOutputFileName",
+ "switch": "fo",
+ "comment": "Resource File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v12_CL.json b/Templates/MSBuild/FlagTables/v12_CL.json
new file mode 100644
index 0000000..771a555
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v12_CL.json
@@ -0,0 +1,1077 @@
+[
+ {
+ "name": "DebugInformationFormat",
+ "switch": "",
+ "comment": "None",
+ "value": "None",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "Z7",
+ "comment": "C7 compatible",
+ "value": "OldStyle",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "Zi",
+ "comment": "Program Database",
+ "value": "ProgramDatabase",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "ZI",
+ "comment": "Program Database for Edit And Continue",
+ "value": "EditAndContinue",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "",
+ "comment": "No Common Language RunTime Support",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr",
+ "comment": "Common Language RunTime Support",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:pure",
+ "comment": "Pure MSIL Common Language RunTime Support",
+ "value": "Pure",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:safe",
+ "comment": "Safe MSIL Common Language RunTime Support",
+ "value": "Safe",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:oldSyntax",
+ "comment": "Common Language RunTime Support, Old Syntax",
+ "value": "OldSyntax",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W0",
+ "comment": "Turn Off All Warnings",
+ "value": "TurnOffAllWarnings",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W1",
+ "comment": "Level1",
+ "value": "Level1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W2",
+ "comment": "Level2",
+ "value": "Level2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W3",
+ "comment": "Level3",
+ "value": "Level3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W4",
+ "comment": "Level4",
+ "value": "Level4",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "Wall",
+ "comment": "EnableAllWarnings",
+ "value": "EnableAllWarnings",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "",
+ "comment": "Custom",
+ "value": "Custom",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "Od",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "O1",
+ "comment": "Minimize Size",
+ "value": "MinSpace",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "O2",
+ "comment": "Maximize Speed",
+ "value": "MaxSpeed",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "Ox",
+ "comment": "Full Optimization",
+ "value": "Full",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob0",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob1",
+ "comment": "Only __inline",
+ "value": "OnlyExplicitInline",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob2",
+ "comment": "Any Suitable",
+ "value": "AnySuitable",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "Os",
+ "comment": "Favor small code",
+ "value": "Size",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "Ot",
+ "comment": "Favor fast code",
+ "value": "Speed",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "",
+ "comment": "Neither",
+ "value": "Neither",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHa",
+ "comment": "Yes with SEH Exceptions",
+ "value": "Async",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHsc",
+ "comment": "Yes",
+ "value": "Sync",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHs",
+ "comment": "Yes with Extern C functions",
+ "value": "SyncCThrow",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTCs",
+ "comment": "Stack Frames",
+ "value": "StackFrameRuntimeCheck",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTCu",
+ "comment": "Uninitialized variables",
+ "value": "UninitializedLocalUsageCheck",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTC1",
+ "comment": "Both (/RTC1, equiv. to /RTCsu)",
+ "value": "EnableFastChecks",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MT",
+ "comment": "Multi-threaded",
+ "value": "MultiThreaded",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MTd",
+ "comment": "Multi-threaded Debug",
+ "value": "MultiThreadedDebug",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MD",
+ "comment": "Multi-threaded DLL",
+ "value": "MultiThreadedDLL",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MDd",
+ "comment": "Multi-threaded Debug DLL",
+ "value": "MultiThreadedDebugDLL",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp1",
+ "comment": "1 Byte",
+ "value": "1Byte",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp2",
+ "comment": "2 Bytes",
+ "value": "2Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp4",
+ "comment": "4 Byte",
+ "value": "4Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp8",
+ "comment": "8 Bytes",
+ "value": "8Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp16",
+ "comment": "16 Bytes",
+ "value": "16Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "BufferSecurityCheck",
+ "switch": "GS-",
+ "comment": "Disable Security Check",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "BufferSecurityCheck",
+ "switch": "GS",
+ "comment": "Enable Security Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:SSE",
+ "comment": "Streaming SIMD Extensions",
+ "value": "StreamingSIMDExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:SSE2",
+ "comment": "Streaming SIMD Extensions 2",
+ "value": "StreamingSIMDExtensions2",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:AVX",
+ "comment": "Advanced Vector Extensions",
+ "value": "AdvancedVectorExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:AVX2",
+ "comment": "Advanced Vector Extensions 2",
+ "value": "AdvancedVectorExtensions2",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:IA32",
+ "comment": "No Enhanced Instructions",
+ "value": "NoExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:precise",
+ "comment": "Precise",
+ "value": "Precise",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:strict",
+ "comment": "Strict",
+ "value": "Strict",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:fast",
+ "comment": "Fast",
+ "value": "Fast",
+ "flags": []
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Yc",
+ "comment": "Create",
+ "value": "Create",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Yu",
+ "comment": "Use",
+ "value": "Use",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Y-",
+ "comment": "Not Using Precompiled Headers",
+ "value": "NotUsing",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "",
+ "comment": "No Listing",
+ "value": "NoListing",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FA",
+ "comment": "Assembly-Only Listing",
+ "value": "AssemblyCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAc",
+ "comment": "Assembly With Machine Code",
+ "value": "AssemblyAndMachineCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAs",
+ "comment": "Assembly With Source Code",
+ "value": "AssemblyAndSourceCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAcs",
+ "comment": "Assembly, Machine Code and Source",
+ "value": "All",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gd",
+ "comment": "__cdecl",
+ "value": "Cdecl",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gr",
+ "comment": "__fastcall",
+ "value": "FastCall",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gz",
+ "comment": "__stdcall",
+ "value": "StdCall",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gv",
+ "comment": "__vectorcall",
+ "value": "VectorCall",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "TC",
+ "comment": "Compile as C Code",
+ "value": "CompileAsC",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "TP",
+ "comment": "Compile as C++ Code",
+ "value": "CompileAsCpp",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:none",
+ "comment": "Do Not Send Report",
+ "value": "None",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:prompt",
+ "comment": "Prompt Immediately",
+ "value": "Prompt",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:queue",
+ "comment": "Queue For Next Login",
+ "value": "Queue",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:send",
+ "comment": "Send Automatically",
+ "value": "Send",
+ "flags": []
+ },
+ {
+ "name": "CompileAsWinRT",
+ "switch": "ZW",
+ "comment": "Consume Windows Runtime Extension",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WinRTNoStdLib",
+ "switch": "ZW:nostdlib",
+ "comment": "No Standard WinRT Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "nologo",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningAsError",
+ "switch": "WX-",
+ "comment": "Treat Warnings As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningAsError",
+ "switch": "WX",
+ "comment": "Treat Warnings As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SDLCheck",
+ "switch": "sdl-",
+ "comment": "SDL checks",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "SDLCheck",
+ "switch": "sdl",
+ "comment": "SDL checks",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MultiProcessorCompilation",
+ "switch": "MP",
+ "comment": "Multi-processor Compilation",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "IntrinsicFunctions",
+ "switch": "Oi",
+ "comment": "Enable Intrinsic Functions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OmitFramePointers",
+ "switch": "Oy-",
+ "comment": "Omit Frame Pointers",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OmitFramePointers",
+ "switch": "Oy",
+ "comment": "Omit Frame Pointers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableFiberSafeOptimizations",
+ "switch": "GT",
+ "comment": "Enable Fiber-Safe Optimizations",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WholeProgramOptimization",
+ "switch": "GL",
+ "comment": "Whole Program Optimization",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UndefineAllPreprocessorDefinitions",
+ "switch": "u",
+ "comment": "Undefine All Preprocessor Definitions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreStandardIncludePath",
+ "switch": "X",
+ "comment": "Ignore Standard Include Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessToFile",
+ "switch": "P",
+ "comment": "Preprocess to a File",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessSuppressLineNumbers",
+ "switch": "EP",
+ "comment": "Preprocess Suppress Line Numbers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessKeepComments",
+ "switch": "C",
+ "comment": "Keep Comments",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "StringPooling",
+ "switch": "GF-",
+ "comment": "Enable String Pooling",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "StringPooling",
+ "switch": "GF",
+ "comment": "Enable String Pooling",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MinimalRebuild",
+ "switch": "Gm-",
+ "comment": "Enable Minimal Rebuild",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "MinimalRebuild",
+ "switch": "Gm",
+ "comment": "Enable Minimal Rebuild",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SmallerTypeCheck",
+ "switch": "RTCc",
+ "comment": "Smaller Type Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FunctionLevelLinking",
+ "switch": "Gy-",
+ "comment": "Enable Function-Level Linking",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FunctionLevelLinking",
+ "switch": "Gy",
+ "comment": "Enable Function-Level Linking",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableParallelCodeGeneration",
+ "switch": "Qpar-",
+ "comment": "Enable Parallel Code Generation",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnableParallelCodeGeneration",
+ "switch": "Qpar",
+ "comment": "Enable Parallel Code Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointExceptions",
+ "switch": "fp:except-",
+ "comment": "Enable Floating Point Exceptions",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointExceptions",
+ "switch": "fp:except",
+ "comment": "Enable Floating Point Exceptions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CreateHotpatchableImage",
+ "switch": "hotpatch",
+ "comment": "Create Hotpatchable Image",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DisableLanguageExtensions",
+ "switch": "Za",
+ "comment": "Disable Language Extensions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWChar_tAsBuiltInType",
+ "switch": "Zc:wchar_t-",
+ "comment": "Treat WChar_t As Built in Type",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWChar_tAsBuiltInType",
+ "switch": "Zc:wchar_t",
+ "comment": "Treat WChar_t As Built in Type",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ForceConformanceInForLoopScope",
+ "switch": "Zc:forScope-",
+ "comment": "Force Conformance in For Loop Scope",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "ForceConformanceInForLoopScope",
+ "switch": "Zc:forScope",
+ "comment": "Force Conformance in For Loop Scope",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RuntimeTypeInfo",
+ "switch": "GR-",
+ "comment": "Enable Run-Time Type Information",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RuntimeTypeInfo",
+ "switch": "GR",
+ "comment": "Enable Run-Time Type Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OpenMPSupport",
+ "switch": "openmp-",
+ "comment": "Open MP Support",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OpenMPSupport",
+ "switch": "openmp",
+ "comment": "Open MP Support",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ExpandAttributedSource",
+ "switch": "Fx",
+ "comment": "Expand Attributed Source",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseUnicodeForAssemblerListing",
+ "switch": "FAu",
+ "comment": "Use Unicode For Assembler Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateXMLDocumentationFiles",
+ "switch": "doc",
+ "comment": "Generate XML Documentation Files",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "BrowseInformation",
+ "switch": "FR",
+ "comment": "Enable Browse Information",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "ShowIncludes",
+ "switch": "showIncludes",
+ "comment": "Show Includes",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnablePREfast",
+ "switch": "analyze-",
+ "comment": "Enable Code Analysis",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnablePREfast",
+ "switch": "analyze",
+ "comment": "Enable Code Analysis",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseFullPaths",
+ "switch": "FC",
+ "comment": "Use Full Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OmitDefaultLibName",
+ "switch": "Zl",
+ "comment": "Omit Default Library Name",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalIncludeDirectories",
+ "switch": "I",
+ "comment": "Additional Include Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalUsingDirectories",
+ "switch": "AI",
+ "comment": "Additional #using Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "UndefinePreprocessorDefinitions",
+ "switch": "U",
+ "comment": "Undefine Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "DisableSpecificWarnings",
+ "switch": "wd",
+ "comment": "Disable Specific Warnings",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForcedIncludeFiles",
+ "switch": "FI",
+ "comment": "Forced Include File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForcedUsingFiles",
+ "switch": "FU",
+ "comment": "Forced #using File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PREfastLog",
+ "switch": "analyze:log",
+ "comment": "Code Analysis Log",
+ "value": "",
+ "flags": [
+ "UserFollowing"
+ ]
+ },
+ {
+ "name": "PREfastAdditionalPlugins",
+ "switch": "analyze:plugin",
+ "comment": "Additional Code Analysis Native plugins",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "TreatSpecificWarningsAsErrors",
+ "switch": "we",
+ "comment": "Treat Specific Warnings As Errors",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PreprocessOutputPath",
+ "switch": "Fi",
+ "comment": "Preprocess Output Path",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderFile",
+ "switch": "Yu",
+ "comment": "Precompiled Header File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderFile",
+ "switch": "Yc",
+ "comment": "Precompiled Header File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderOutputFile",
+ "switch": "Fp",
+ "comment": "Precompiled Header Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "AssemblerListingLocation",
+ "switch": "Fa",
+ "comment": "ASM List Location",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ObjectFileName",
+ "switch": "Fo",
+ "comment": "Object File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProgramDataBaseFileName",
+ "switch": "Fd",
+ "comment": "Program Database File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "XMLDocumentationFileName",
+ "switch": "doc",
+ "comment": "XML Documentation File Name",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "BrowseInformationFile",
+ "switch": "FR",
+ "comment": "Browse Information File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ProcessorNumber",
+ "switch": "MP",
+ "comment": "Number of processors",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v12_CSharp.json b/Templates/MSBuild/FlagTables/v12_CSharp.json
new file mode 100644
index 0000000..5989aea
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v12_CSharp.json
@@ -0,0 +1,574 @@
+[
+ {
+ "name": "ProjectName",
+ "switch": "out:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:exe",
+ "comment": "",
+ "value": "Exe",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:winexe",
+ "comment": "",
+ "value": "Winexe",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:library",
+ "comment": "",
+ "value": "Library",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:module",
+ "comment": "",
+ "value": "Module",
+ "flags": []
+ },
+ {
+ "name": "DocumentationFile",
+ "switch": "doc",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:x86",
+ "comment": "",
+ "value": "x86",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:Itanium",
+ "comment": "",
+ "value": "Itanium",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:x64",
+ "comment": "",
+ "value": "x64",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:arm",
+ "comment": "",
+ "value": "arm",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:anycpu32bitpreferred",
+ "comment": "",
+ "value": "anycpu32bitpreferred",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:anycpu",
+ "comment": "",
+ "value": "anycpu",
+ "flags": []
+ },
+ {
+ "name": "References",
+ "switch": "reference:",
+ "comment": "mit alias",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "References",
+ "switch": "reference:",
+ "comment": "dateiliste",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "AddModules",
+ "switch": "addmodule:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "Win32Resource",
+ "switch": "win32res:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ApplicationIcon",
+ "switch": "win32icon:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ApplicationManifest",
+ "switch": "win32manifest:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "NoWin32Manifest",
+ "switch": "nowin32manifest",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DefineDebug",
+ "switch": "debug",
+ "comment": "",
+ "value": "true",
+ "flags": [
+ "Continue"
+ ]
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:none",
+ "comment": "",
+ "value": "none",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:full",
+ "comment": "",
+ "value": "full",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:pdbonly",
+ "comment": "",
+ "value": "pdbonly",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror-",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror+",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:0",
+ "comment": "",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:1",
+ "comment": "",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:2",
+ "comment": "",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:3",
+ "comment": "",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:4",
+ "comment": "",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "NoWarn",
+ "switch": "nowarn:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired",
+ "CommaAppendable"
+ ]
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DefineConstants",
+ "switch": "define:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "SemicolonAppendable",
+ "UserValue"
+ ]
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:ISO-1",
+ "comment": "",
+ "value": "ISO-1",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:ISO-2",
+ "comment": "",
+ "value": "ISO-2",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:3",
+ "comment": "",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:4",
+ "comment": "",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:5",
+ "comment": "",
+ "value": "5",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:6",
+ "comment": "",
+ "value": "6",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:default",
+ "comment": "",
+ "value": "default",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AssemblyOriginatorKeyFile",
+ "switch": "keyfile",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "KeyContainerName",
+ "switch": "keycontainer",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoLogo",
+ "switch": "nologo",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoConfig",
+ "switch": "noconfig",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "BaseAddress",
+ "switch": "baseaddress:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "CodePage",
+ "switch": "codepage",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "Utf8Output",
+ "switch": "utf8output",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "MainEntryPoint",
+ "switch": "main:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "GenerateFullPaths",
+ "switch": "fullpaths",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FileAlignment",
+ "switch": "filealign",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "PdbFile",
+ "switch": "pdb:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SubsystemVersion",
+ "switch": "subsystemversion",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibPaths",
+ "switch": "lib:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:none",
+ "comment": "Do Not Send Report",
+ "value": "none",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:prompt",
+ "comment": "Prompt Immediately",
+ "value": "prompt",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:queue",
+ "comment": "Queue For Next Login",
+ "value": "queue",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:send",
+ "comment": "Send Automatically",
+ "value": "send",
+ "flags": []
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v12_LIB.json b/Templates/MSBuild/FlagTables/v12_LIB.json
new file mode 100644
index 0000000..58a238c
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v12_LIB.json
@@ -0,0 +1,297 @@
+[
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:PROMPT",
+ "comment": "PromptImmediately",
+ "value": "PromptImmediately",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:QUEUE",
+ "comment": "Queue For Next Login",
+ "value": "QueueForNextLogin",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:SEND",
+ "comment": "Send Error Report",
+ "value": "SendErrorReport",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:NONE",
+ "comment": "No Error Report",
+ "value": "NoErrorReport",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM",
+ "comment": "MachineARM",
+ "value": "MachineARM",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:EBC",
+ "comment": "MachineEBC",
+ "value": "MachineEBC",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:IA64",
+ "comment": "MachineIA64",
+ "value": "MachineIA64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS",
+ "comment": "MachineMIPS",
+ "value": "MachineMIPS",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS16",
+ "comment": "MachineMIPS16",
+ "value": "MachineMIPS16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU",
+ "comment": "MachineMIPSFPU",
+ "value": "MachineMIPSFPU",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU16",
+ "comment": "MachineMIPSFPU16",
+ "value": "MachineMIPSFPU16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:SH4",
+ "comment": "MachineSH4",
+ "value": "MachineSH4",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:THUMB",
+ "comment": "MachineTHUMB",
+ "value": "MachineTHUMB",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X64",
+ "comment": "MachineX64",
+ "value": "MachineX64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X86",
+ "comment": "MachineX86",
+ "value": "MachineX86",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:CONSOLE",
+ "comment": "Console",
+ "value": "Console",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWS",
+ "comment": "Windows",
+ "value": "Windows",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:NATIVE",
+ "comment": "Native",
+ "value": "Native",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_APPLICATION",
+ "comment": "EFI Application",
+ "value": "EFI Application",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "comment": "EFI Boot Service Driver",
+ "value": "EFI Boot Service Driver",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_ROM",
+ "comment": "EFI ROM",
+ "value": "EFI ROM",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_RUNTIME_DRIVER",
+ "comment": "EFI Runtime",
+ "value": "EFI Runtime",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWSCE",
+ "comment": "WindowsCE",
+ "value": "WindowsCE",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:POSIX",
+ "comment": "POSIX",
+ "value": "POSIX",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "NOLOGO",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreAllDefaultLibraries",
+ "switch": "NODEFAULTLIB",
+ "comment": "Ignore All Default Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatLibWarningAsErrors",
+ "switch": "WX:NO",
+ "comment": "Treat Lib Warning As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatLibWarningAsErrors",
+ "switch": "WX",
+ "comment": "Treat Lib Warning As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Verbose",
+ "switch": "VERBOSE",
+ "comment": "Verbose",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG",
+ "comment": "Link Time Code Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibraryDirectories",
+ "switch": "LIBPATH:",
+ "comment": "Additional Library Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IgnoreSpecificDefaultLibraries",
+ "switch": "NODEFAULTLIB:",
+ "comment": "Ignore Specific Default Libraries",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ExportNamedFunctions",
+ "switch": "EXPORT:",
+ "comment": "Export Named Functions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "RemoveObjects",
+ "switch": "REMOVE:",
+ "comment": "Remove Objects",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "OutputFile",
+ "switch": "OUT:",
+ "comment": "Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ModuleDefinitionFile",
+ "switch": "DEF:",
+ "comment": "Module Definition File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ForceSymbolReferences",
+ "switch": "INCLUDE:",
+ "comment": "Force Symbol References",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "DisplayLibrary",
+ "switch": "LIST:",
+ "comment": "Display Library to standard output",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "Name",
+ "switch": "NAME:",
+ "comment": "Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v12_Link.json b/Templates/MSBuild/FlagTables/v12_Link.json
new file mode 100644
index 0000000..5d5c13f
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v12_Link.json
@@ -0,0 +1,1272 @@
+[
+ {
+ "name": "ShowProgress",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE",
+ "comment": "Display all progress messages",
+ "value": "LinkVerbose",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:Lib",
+ "comment": "For Libraries Searched",
+ "value": "LinkVerboseLib",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:ICF",
+ "comment": "About COMDAT folding during optimized linking",
+ "value": "LinkVerboseICF",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:REF",
+ "comment": "About data removed during optimized linking",
+ "value": "LinkVerboseREF",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:SAFESEH",
+ "comment": "About Modules incompatible with SEH",
+ "value": "LinkVerboseSAFESEH",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:CLR",
+ "comment": "About linker activity related to managed code",
+ "value": "LinkVerboseCLR",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE:MULTIPLE",
+ "comment": "Multiply Defined Symbol Only",
+ "value": "MultiplyDefinedSymbolOnly",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE:UNRESOLVED",
+ "comment": "Undefined Symbol Only",
+ "value": "UndefinedSymbolOnly",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:5",
+ "comment": "X86 Image Only",
+ "value": "X86Image",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:6",
+ "comment": "X64 Image Only",
+ "value": "X64Image",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:16",
+ "comment": "Itanium Image Only",
+ "value": "ItaniumImage",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='asInvoker'",
+ "comment": "asInvoker",
+ "value": "AsInvoker",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='highestAvailable'",
+ "comment": "highestAvailable",
+ "value": "HighestAvailable",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='requireAdministrator'",
+ "comment": "requireAdministrator",
+ "value": "RequireAdministrator",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:CONSOLE",
+ "comment": "Console",
+ "value": "Console",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWS",
+ "comment": "Windows",
+ "value": "Windows",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:NATIVE",
+ "comment": "Native",
+ "value": "Native",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_APPLICATION",
+ "comment": "EFI Application",
+ "value": "EFI Application",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "comment": "EFI Boot Service Driver",
+ "value": "EFI Boot Service Driver",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_ROM",
+ "comment": "EFI ROM",
+ "value": "EFI ROM",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_RUNTIME_DRIVER",
+ "comment": "EFI Runtime",
+ "value": "EFI Runtime",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:POSIX",
+ "comment": "POSIX",
+ "value": "POSIX",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "Driver",
+ "comment": "Driver",
+ "value": "Driver",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "DRIVER:UPONLY",
+ "comment": "UP Only",
+ "value": "UpOnly",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "DRIVER:WDM",
+ "comment": "WDM",
+ "value": "WDM",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG",
+ "comment": "Use Link Time Code Generation",
+ "value": "UseLinkTimeCodeGeneration",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGInstrument",
+ "comment": "Profile Guided Optimization - Instrument",
+ "value": "PGInstrument",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGOptimize",
+ "comment": "Profile Guided Optimization - Optimization",
+ "value": "PGOptimization",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGUpdate",
+ "comment": "Profile Guided Optimization - Update",
+ "value": "PGUpdate",
+ "flags": []
+ },
+ {
+ "name": "GenerateWindowsMetadata",
+ "switch": "WINMD",
+ "comment": "Yes",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateWindowsMetadata",
+ "switch": "WINMD:NO",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA1",
+ "comment": "SHA1",
+ "value": "SHA1",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA256",
+ "comment": "SHA256",
+ "value": "SHA256",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA384",
+ "comment": "SHA384",
+ "value": "SHA384",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA512",
+ "comment": "SHA512",
+ "value": "SHA512",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM",
+ "comment": "MachineARM",
+ "value": "MachineARM",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:EBC",
+ "comment": "MachineEBC",
+ "value": "MachineEBC",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:IA64",
+ "comment": "MachineIA64",
+ "value": "MachineIA64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS",
+ "comment": "MachineMIPS",
+ "value": "MachineMIPS",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS16",
+ "comment": "MachineMIPS16",
+ "value": "MachineMIPS16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU",
+ "comment": "MachineMIPSFPU",
+ "value": "MachineMIPSFPU",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU16",
+ "comment": "MachineMIPSFPU16",
+ "value": "MachineMIPSFPU16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:SH4",
+ "comment": "MachineSH4",
+ "value": "MachineSH4",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:THUMB",
+ "comment": "MachineTHUMB",
+ "value": "MachineTHUMB",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X64",
+ "comment": "MachineX64",
+ "value": "MachineX64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X86",
+ "comment": "MachineX86",
+ "value": "MachineX86",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:MTA",
+ "comment": "MTA threading attribute",
+ "value": "MTAThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:STA",
+ "comment": "STA threading attribute",
+ "value": "STAThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:NONE",
+ "comment": "Default threading attribute",
+ "value": "DefaultThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:IJW",
+ "comment": "Force IJW image",
+ "value": "ForceIJWImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:PURE",
+ "comment": "Force Pure IL Image",
+ "value": "ForcePureILImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:SAFE",
+ "comment": "Force Safe IL Image",
+ "value": "ForceSafeILImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "",
+ "comment": "Default image type",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA1",
+ "comment": "SHA1",
+ "value": "SHA1",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA256",
+ "comment": "SHA256",
+ "value": "SHA256",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA384",
+ "comment": "SHA384",
+ "value": "SHA384",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA512",
+ "comment": "SHA512",
+ "value": "SHA512",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:PROMPT",
+ "comment": "PromptImmediately",
+ "value": "PromptImmediately",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:QUEUE",
+ "comment": "Queue For Next Login",
+ "value": "QueueForNextLogin",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:SEND",
+ "comment": "Send Error Report",
+ "value": "SendErrorReport",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:NONE",
+ "comment": "No Error Report",
+ "value": "NoErrorReport",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError:NO",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError:SYSTEMDLL",
+ "comment": "System Dlls Only",
+ "value": "SystemDlls",
+ "flags": []
+ },
+ {
+ "name": "LinkIncremental",
+ "switch": "INCREMENTAL:NO",
+ "comment": "Enable Incremental Linking",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkIncremental",
+ "switch": "INCREMENTAL",
+ "comment": "Enable Incremental Linking",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "NOLOGO",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkStatus",
+ "switch": "LTCG:NOSTATUS",
+ "comment": "Link Status",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkStatus",
+ "switch": "LTCG:STATUS",
+ "comment": "Link Status",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreventDllBinding",
+ "switch": "ALLOWBIND:NO",
+ "comment": "Prevent Dll Binding",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "PreventDllBinding",
+ "switch": "ALLOWBIND",
+ "comment": "Prevent Dll Binding",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatLinkerWarningAsErrors",
+ "switch": "WX:NO",
+ "comment": "Treat Linker Warning As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatLinkerWarningAsErrors",
+ "switch": "WX",
+ "comment": "Treat Linker Warning As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreAllDefaultLibraries",
+ "switch": "NODEFAULTLIB",
+ "comment": "Ignore All Default Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateManifest",
+ "switch": "MANIFEST:NO",
+ "comment": "Generate Manifest",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "GenerateManifest",
+ "switch": "MANIFEST",
+ "comment": "Generate Manifest",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowIsolation",
+ "switch": "ALLOWISOLATION:NO",
+ "comment": "Allow Isolation",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AllowIsolation",
+ "switch": "",
+ "comment": "Allow Isolation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableUAC",
+ "switch": "MANIFESTUAC:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired",
+ "SpaceAppendable"
+ ]
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='false'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "false",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='false'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='true'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ManifestEmbed",
+ "switch": "manifest:embed",
+ "comment": "Embed Manifest",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG",
+ "comment": "Generate Debug Info",
+ "value": "true",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "GenerateMapFile",
+ "switch": "MAP",
+ "comment": "Generate Map File",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "MapExports",
+ "switch": "MAPINFO:EXPORTS",
+ "comment": "Map Exports",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AssemblyDebug",
+ "switch": "ASSEMBLYDEBUG:DISABLE",
+ "comment": "Debuggable Assembly",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AssemblyDebug",
+ "switch": "ASSEMBLYDEBUG",
+ "comment": "Debuggable Assembly",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LargeAddressAware",
+ "switch": "LARGEADDRESSAWARE:NO",
+ "comment": "Enable Large Addresses",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LargeAddressAware",
+ "switch": "LARGEADDRESSAWARE",
+ "comment": "Enable Large Addresses",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TerminalServerAware",
+ "switch": "TSAWARE:NO",
+ "comment": "Terminal Server",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TerminalServerAware",
+ "switch": "TSAWARE",
+ "comment": "Terminal Server",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SwapRunFromCD",
+ "switch": "SWAPRUN:CD",
+ "comment": "Swap Run From CD",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SwapRunFromNET",
+ "switch": "SWAPRUN:NET",
+ "comment": "Swap Run From Network",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OptimizeReferences",
+ "switch": "OPT:NOREF",
+ "comment": "References",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OptimizeReferences",
+ "switch": "OPT:REF",
+ "comment": "References",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableCOMDATFolding",
+ "switch": "OPT:NOICF",
+ "comment": "Enable COMDAT Folding",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnableCOMDATFolding",
+ "switch": "OPT:ICF",
+ "comment": "Enable COMDAT Folding",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreEmbeddedIDL",
+ "switch": "IGNOREIDL",
+ "comment": "Ignore Embedded IDL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AppContainer",
+ "switch": "APPCONTAINER",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataLinkDelaySign",
+ "switch": "WINMDDELAYSIGN:NO",
+ "comment": "Windows Metadata Delay Sign",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataLinkDelaySign",
+ "switch": "WINMDDELAYSIGN",
+ "comment": "Windows Metadata Delay Sign",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NoEntryPoint",
+ "switch": "NOENTRY",
+ "comment": "No Entry Point",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SetChecksum",
+ "switch": "RELEASE",
+ "comment": "Set Checksum",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RandomizedBaseAddress",
+ "switch": "DYNAMICBASE:NO",
+ "comment": "Randomized Base Address",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RandomizedBaseAddress",
+ "switch": "DYNAMICBASE",
+ "comment": "Randomized Base Address",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FixedBaseAddress",
+ "switch": "FIXED:NO",
+ "comment": "Fixed Base Address",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FixedBaseAddress",
+ "switch": "FIXED",
+ "comment": "Fixed Base Address",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DataExecutionPrevention",
+ "switch": "NXCOMPAT:NO",
+ "comment": "Data Execution Prevention (DEP)",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DataExecutionPrevention",
+ "switch": "NXCOMPAT",
+ "comment": "Data Execution Prevention (DEP)",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TurnOffAssemblyGeneration",
+ "switch": "NOASSEMBLY",
+ "comment": "Turn Off Assembly Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SupportUnloadOfDelayLoadedDLL",
+ "switch": "DELAY:UNLOAD",
+ "comment": "Unload delay loaded DLL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SupportNobindOfDelayLoadedDLL",
+ "switch": "DELAY:NOBIND",
+ "comment": "Nobind delay loaded DLL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Profile",
+ "switch": "PROFILE",
+ "comment": "Profile",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkDelaySign",
+ "switch": "DELAYSIGN:NO",
+ "comment": "Delay Sign",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkDelaySign",
+ "switch": "DELAYSIGN",
+ "comment": "Delay Sign",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CLRUnmanagedCodeCheck",
+ "switch": "CLRUNMANAGEDCODECHECK:NO",
+ "comment": "CLR Unmanaged Code Check",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CLRUnmanagedCodeCheck",
+ "switch": "CLRUNMANAGEDCODECHECK",
+ "comment": "CLR Unmanaged Code Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DetectOneDefinitionRule",
+ "switch": "ODR",
+ "comment": "Detect One Definition Rule violations",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ImageHasSafeExceptionHandlers",
+ "switch": "SAFESEH:NO",
+ "comment": "Image Has Safe Exception Handlers",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "ImageHasSafeExceptionHandlers",
+ "switch": "SAFESEH",
+ "comment": "Image Has Safe Exception Handlers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkDLL",
+ "switch": "DLL",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibraryDirectories",
+ "switch": "LIBPATH:",
+ "comment": "Additional Library Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IgnoreSpecificDefaultLibraries",
+ "switch": "NODEFAULTLIB:",
+ "comment": "Ignore Specific Default Libraries",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AddModuleNamesToAssembly",
+ "switch": "ASSEMBLYMODULE:",
+ "comment": "Add Module to Assembly",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "EmbedManagedResourceFile",
+ "switch": "ASSEMBLYRESOURCE:",
+ "comment": "Embed Managed Resource File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForceSymbolReferences",
+ "switch": "INCLUDE:",
+ "comment": "Force Symbol References",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "DelayLoadDLLs",
+ "switch": "DELAYLOAD:",
+ "comment": "Delay Loaded Dlls",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AssemblyLinkResource",
+ "switch": "ASSEMBLYLINKRESOURCE:",
+ "comment": "Assembly Link Resource",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalManifestDependencies",
+ "switch": "MANIFESTDEPENDENCY:",
+ "comment": "Additional Manifest Dependencies",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ManifestInput",
+ "switch": "manifestinput:",
+ "comment": "Manifest Input",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "OutputFile",
+ "switch": "OUT:",
+ "comment": "Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "Version",
+ "switch": "VERSION:",
+ "comment": "Version",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "SpecifySectionAttributes",
+ "switch": "SECTION:",
+ "comment": "Specify Section Attributes",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MSDOSStubFileName",
+ "switch": "STUB:",
+ "comment": "MS-DOS Stub File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ModuleDefinitionFile",
+ "switch": "DEF:",
+ "comment": "Module Definition File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ManifestFile",
+ "switch": "ManifestFile:",
+ "comment": "Manifest File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProgramDatabaseFile",
+ "switch": "PDB:",
+ "comment": "Generate Program Database File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "StripPrivateSymbols",
+ "switch": "PDBSTRIPPED:",
+ "comment": "Strip Private Symbols",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MapFileName",
+ "switch": "MAP:",
+ "comment": "Map File Name",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "HeapReserveSize",
+ "switch": "HEAP:",
+ "comment": "Heap Reserve Size",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "HeapCommitSize",
+ "switch": "HEAP",
+ "comment": "Heap Commit Size",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "StackReserveSize",
+ "switch": "STACK:",
+ "comment": "Stack Reserve Size",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "StackCommitSize",
+ "switch": "STACK",
+ "comment": "Stack Commit Size",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "FunctionOrder",
+ "switch": "ORDER:@",
+ "comment": "Function Order",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProfileGuidedDatabase",
+ "switch": "PGD:",
+ "comment": "Profile Guided Database",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MidlCommandFile",
+ "switch": "MIDL:@",
+ "comment": "MIDL Commands",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MergedIDLBaseFileName",
+ "switch": "IDLOUT:",
+ "comment": "Merged IDL Base File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "TypeLibraryFile",
+ "switch": "TLBOUT:",
+ "comment": "Type Library",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataFile",
+ "switch": "WINMDFILE:",
+ "comment": "Windows Metadata File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataLinkKeyFile",
+ "switch": "WINMDKEYFILE:",
+ "comment": "Windows Metadata Key File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataKeyContainer",
+ "switch": "WINMDKEYCONTAINER:",
+ "comment": "Windows Metadata Key Container",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "EntryPointSymbol",
+ "switch": "ENTRY:",
+ "comment": "Entry Point",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "BaseAddress",
+ "switch": "BASE:",
+ "comment": "Base Address",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ImportLibrary",
+ "switch": "IMPLIB:",
+ "comment": "Import Library",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MergeSections",
+ "switch": "MERGE:",
+ "comment": "Merge Sections",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "LinkKeyFile",
+ "switch": "KEYFILE:",
+ "comment": "Key File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "KeyContainer",
+ "switch": "KEYCONTAINER:",
+ "comment": "Key Container",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "TypeLibraryResourceID",
+ "switch": "TLBID:",
+ "comment": "TypeLib Resource ID",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "SectionAlignment",
+ "switch": "ALIGN:",
+ "comment": "SectionAlignment",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v12_MASM.json b/Templates/MSBuild/FlagTables/v12_MASM.json
new file mode 100644
index 0000000..4634306
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v12_MASM.json
@@ -0,0 +1,295 @@
+[
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "",
+ "comment": "Default",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "Cp",
+ "comment": "Preserves Identifier Case (/Cp)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "Cu",
+ "comment": "Maps all identifiers to upper case. (/Cu)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "Cx",
+ "comment": "Preserves case in public and extern symbols. (/Cx)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W0",
+ "comment": "Warning Level 0 (/W0)",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W1",
+ "comment": "Warning Level 1 (/W1)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W2",
+ "comment": "Warning Level 2 (/W2)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W3",
+ "comment": "Warning Level 3 (/W3)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "",
+ "comment": "Default",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp1",
+ "comment": "One Byte Boundary (/Zp1)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp2",
+ "comment": "Two Byte Boundary (/Zp2)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp4",
+ "comment": "Four Byte Boundary (/Zp4)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp8",
+ "comment": "Eight Byte Boundary (/Zp8)",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp16",
+ "comment": "Sixteen Byte Boundary (/Zp16)",
+ "value": "5",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "",
+ "comment": "Default",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gd",
+ "comment": "Use C-style Calling Convention (/Gd)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gz",
+ "comment": "Use stdcall Calling Convention (/Gz)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gc",
+ "comment": "Use Pascal Calling Convention (/Gc)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:prompt",
+ "comment": "Prompt to send report immediately (/errorReport:prompt)",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:queue",
+ "comment": "Prompt to send report at the next logon (/errorReport:queue)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:send",
+ "comment": "Automatically send report (/errorReport:send)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:none",
+ "comment": "Do not send report (/errorReport:none)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "NoLogo",
+ "switch": "nologo",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GeneratePreprocessedSourceListing",
+ "switch": "EP",
+ "comment": "Generate Preprocessed Source Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ListAllAvailableInformation",
+ "switch": "Sa",
+ "comment": "List All Available Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseSafeExceptionHandlers",
+ "switch": "safeseh",
+ "comment": "Use Safe Exception Handlers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AddFirstPassListing",
+ "switch": "Sf",
+ "comment": "Add First Pass Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableAssemblyGeneratedCodeListing",
+ "switch": "Sg",
+ "comment": "Enable Assembly Generated Code Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DisableSymbolTable",
+ "switch": "Sn",
+ "comment": "Disable Symbol Table",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableFalseConditionalsInListing",
+ "switch": "Sx",
+ "comment": "Enable False Conditionals In Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "WX",
+ "comment": "Treat Warnings As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MakeAllSymbolsPublic",
+ "switch": "Zf",
+ "comment": "Make All Symbols Public",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "Zi",
+ "comment": "Generate Debug Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableMASM51Compatibility",
+ "switch": "Zm",
+ "comment": "Enable MASM 5.1 Compatibility",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PerformSyntaxCheckOnly",
+ "switch": "Zs",
+ "comment": "Perform Syntax Check Only",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IncludePaths",
+ "switch": "I",
+ "comment": "Include Paths",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "BrowseFile",
+ "switch": "FR",
+ "comment": "Generate Browse Information File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ObjectFileName",
+ "switch": "Fo",
+ "comment": "Object File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "AssembledCodeListingFile",
+ "switch": "Fl",
+ "comment": "Assembled Code Listing File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v12_RC.json b/Templates/MSBuild/FlagTables/v12_RC.json
new file mode 100644
index 0000000..b8c0127
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v12_RC.json
@@ -0,0 +1,69 @@
+[
+ {
+ "name": "IgnoreStandardIncludePath",
+ "switch": "X",
+ "comment": "Ignore Standard Include Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "v",
+ "comment": "Show Progress",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "nologo",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NullTerminateStrings",
+ "switch": "n",
+ "comment": "Null Terminate Strings",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "UndefinePreprocessorDefinitions",
+ "switch": "u",
+ "comment": "Undefine Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalIncludeDirectories",
+ "switch": "I",
+ "comment": "Additional Include Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ResourceOutputFileName",
+ "switch": "fo",
+ "comment": "Resource File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v140_CL.json b/Templates/MSBuild/FlagTables/v140_CL.json
new file mode 100644
index 0000000..3dc9f35
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v140_CL.json
@@ -0,0 +1,1184 @@
+[
+ {
+ "name": "DebugInformationFormat",
+ "switch": "",
+ "comment": "None",
+ "value": "None",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "Z7",
+ "comment": "C7 compatible",
+ "value": "OldStyle",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "Zi",
+ "comment": "Program Database",
+ "value": "ProgramDatabase",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "ZI",
+ "comment": "Program Database for Edit And Continue",
+ "value": "EditAndContinue",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "",
+ "comment": "No Common Language RunTime Support",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr",
+ "comment": "Common Language RunTime Support",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:pure",
+ "comment": "Pure MSIL Common Language RunTime Support",
+ "value": "Pure",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:safe",
+ "comment": "Safe MSIL Common Language RunTime Support",
+ "value": "Safe",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W0",
+ "comment": "Turn Off All Warnings",
+ "value": "TurnOffAllWarnings",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W1",
+ "comment": "Level1",
+ "value": "Level1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W2",
+ "comment": "Level2",
+ "value": "Level2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W3",
+ "comment": "Level3",
+ "value": "Level3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W4",
+ "comment": "Level4",
+ "value": "Level4",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "Wall",
+ "comment": "EnableAllWarnings",
+ "value": "EnableAllWarnings",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "",
+ "comment": "Custom",
+ "value": "Custom",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "Od",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "O1",
+ "comment": "Minimize Size",
+ "value": "MinSpace",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "O2",
+ "comment": "Maximize Speed",
+ "value": "MaxSpeed",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "Ox",
+ "comment": "Full Optimization",
+ "value": "Full",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob0",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob1",
+ "comment": "Only __inline",
+ "value": "OnlyExplicitInline",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob2",
+ "comment": "Any Suitable",
+ "value": "AnySuitable",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "Os",
+ "comment": "Favor small code",
+ "value": "Size",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "Ot",
+ "comment": "Favor fast code",
+ "value": "Speed",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "",
+ "comment": "Neither",
+ "value": "Neither",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHa",
+ "comment": "Yes with SEH Exceptions",
+ "value": "Async",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHsc",
+ "comment": "Yes",
+ "value": "Sync",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHs",
+ "comment": "Yes with Extern C functions",
+ "value": "SyncCThrow",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTCs",
+ "comment": "Stack Frames",
+ "value": "StackFrameRuntimeCheck",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTCu",
+ "comment": "Uninitialized variables",
+ "value": "UninitializedLocalUsageCheck",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTC1",
+ "comment": "Both (/RTC1, equiv. to /RTCsu)",
+ "value": "EnableFastChecks",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MT",
+ "comment": "Multi-threaded",
+ "value": "MultiThreaded",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MTd",
+ "comment": "Multi-threaded Debug",
+ "value": "MultiThreadedDebug",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MD",
+ "comment": "Multi-threaded DLL",
+ "value": "MultiThreadedDLL",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MDd",
+ "comment": "Multi-threaded Debug DLL",
+ "value": "MultiThreadedDebugDLL",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp1",
+ "comment": "1 Byte",
+ "value": "1Byte",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp2",
+ "comment": "2 Bytes",
+ "value": "2Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp4",
+ "comment": "4 Byte",
+ "value": "4Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp8",
+ "comment": "8 Bytes",
+ "value": "8Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp16",
+ "comment": "16 Bytes",
+ "value": "16Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "BufferSecurityCheck",
+ "switch": "GS-",
+ "comment": "Disable Security Check",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "BufferSecurityCheck",
+ "switch": "GS",
+ "comment": "Enable Security Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ControlFlowGuard",
+ "switch": "guard:cf",
+ "comment": "Yes",
+ "value": "Guard",
+ "flags": []
+ },
+ {
+ "name": "ControlFlowGuard",
+ "switch": "",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:SSE",
+ "comment": "Streaming SIMD Extensions",
+ "value": "StreamingSIMDExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:SSE2",
+ "comment": "Streaming SIMD Extensions 2",
+ "value": "StreamingSIMDExtensions2",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:AVX",
+ "comment": "Advanced Vector Extensions",
+ "value": "AdvancedVectorExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:AVX2",
+ "comment": "Advanced Vector Extensions 2",
+ "value": "AdvancedVectorExtensions2",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:IA32",
+ "comment": "No Enhanced Instructions",
+ "value": "NoExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:precise",
+ "comment": "Precise",
+ "value": "Precise",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:strict",
+ "comment": "Strict",
+ "value": "Strict",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:fast",
+ "comment": "Fast",
+ "value": "Fast",
+ "flags": []
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Yc",
+ "comment": "Create",
+ "value": "Create",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Yu",
+ "comment": "Use",
+ "value": "Use",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Y-",
+ "comment": "Not Using Precompiled Headers",
+ "value": "NotUsing",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "",
+ "comment": "No Listing",
+ "value": "NoListing",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FA",
+ "comment": "Assembly-Only Listing",
+ "value": "AssemblyCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAc",
+ "comment": "Assembly With Machine Code",
+ "value": "AssemblyAndMachineCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAs",
+ "comment": "Assembly With Source Code",
+ "value": "AssemblyAndSourceCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAcs",
+ "comment": "Assembly, Machine Code and Source",
+ "value": "All",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gd",
+ "comment": "__cdecl",
+ "value": "Cdecl",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gr",
+ "comment": "__fastcall",
+ "value": "FastCall",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gz",
+ "comment": "__stdcall",
+ "value": "StdCall",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gv",
+ "comment": "__vectorcall",
+ "value": "VectorCall",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "TC",
+ "comment": "Compile as C Code",
+ "value": "CompileAsC",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "TP",
+ "comment": "Compile as C++ Code",
+ "value": "CompileAsCpp",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:none",
+ "comment": "Do Not Send Report",
+ "value": "None",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:prompt",
+ "comment": "Prompt Immediately",
+ "value": "Prompt",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:queue",
+ "comment": "Queue For Next Login",
+ "value": "Queue",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:send",
+ "comment": "Send Automatically",
+ "value": "Send",
+ "flags": []
+ },
+ {
+ "name": "CompileAsWinRT",
+ "switch": "ZW",
+ "comment": "Consume Windows Runtime Extension",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WinRTNoStdLib",
+ "switch": "ZW:nostdlib",
+ "comment": "No Standard WinRT Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "nologo",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningAsError",
+ "switch": "WX-",
+ "comment": "Treat Warnings As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningAsError",
+ "switch": "WX",
+ "comment": "Treat Warnings As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SDLCheck",
+ "switch": "sdl-",
+ "comment": "SDL checks",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "SDLCheck",
+ "switch": "sdl",
+ "comment": "SDL checks",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MultiProcessorCompilation",
+ "switch": "MP",
+ "comment": "Multi-processor Compilation",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "IntrinsicFunctions",
+ "switch": "Oi",
+ "comment": "Enable Intrinsic Functions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OmitFramePointers",
+ "switch": "Oy-",
+ "comment": "Omit Frame Pointers",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OmitFramePointers",
+ "switch": "Oy",
+ "comment": "Omit Frame Pointers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableFiberSafeOptimizations",
+ "switch": "GT",
+ "comment": "Enable Fiber-Safe Optimizations",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WholeProgramOptimization",
+ "switch": "GL",
+ "comment": "Whole Program Optimization",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UndefineAllPreprocessorDefinitions",
+ "switch": "u",
+ "comment": "Undefine All Preprocessor Definitions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreStandardIncludePath",
+ "switch": "X",
+ "comment": "Ignore Standard Include Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessToFile",
+ "switch": "P",
+ "comment": "Preprocess to a File",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessSuppressLineNumbers",
+ "switch": "EP",
+ "comment": "Preprocess Suppress Line Numbers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessKeepComments",
+ "switch": "C",
+ "comment": "Keep Comments",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "StringPooling",
+ "switch": "GF-",
+ "comment": "Enable String Pooling",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "StringPooling",
+ "switch": "GF",
+ "comment": "Enable String Pooling",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MinimalRebuild",
+ "switch": "Gm-",
+ "comment": "Enable Minimal Rebuild",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "MinimalRebuild",
+ "switch": "Gm",
+ "comment": "Enable Minimal Rebuild",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SmallerTypeCheck",
+ "switch": "RTCc",
+ "comment": "Smaller Type Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FunctionLevelLinking",
+ "switch": "Gy-",
+ "comment": "Enable Function-Level Linking",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FunctionLevelLinking",
+ "switch": "Gy",
+ "comment": "Enable Function-Level Linking",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableParallelCodeGeneration",
+ "switch": "Qpar-",
+ "comment": "Enable Parallel Code Generation",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnableParallelCodeGeneration",
+ "switch": "Qpar",
+ "comment": "Enable Parallel Code Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointExceptions",
+ "switch": "fp:except-",
+ "comment": "Enable Floating Point Exceptions",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointExceptions",
+ "switch": "fp:except",
+ "comment": "Enable Floating Point Exceptions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CreateHotpatchableImage",
+ "switch": "hotpatch",
+ "comment": "Create Hotpatchable Image",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DisableLanguageExtensions",
+ "switch": "Za",
+ "comment": "Disable Language Extensions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWChar_tAsBuiltInType",
+ "switch": "Zc:wchar_t-",
+ "comment": "Treat WChar_t As Built in Type",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWChar_tAsBuiltInType",
+ "switch": "Zc:wchar_t",
+ "comment": "Treat WChar_t As Built in Type",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ForceConformanceInForLoopScope",
+ "switch": "Zc:forScope-",
+ "comment": "Force Conformance in For Loop Scope",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "ForceConformanceInForLoopScope",
+ "switch": "Zc:forScope",
+ "comment": "Force Conformance in For Loop Scope",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RemoveUnreferencedCodeData",
+ "switch": "Zc:inline-",
+ "comment": "Remove unreferenced code and data",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RemoveUnreferencedCodeData",
+ "switch": "Zc:inline",
+ "comment": "Remove unreferenced code and data",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnforceTypeConversionRules",
+ "switch": "Zc:rvalueCast-",
+ "comment": "Enforce type conversion rules",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnforceTypeConversionRules",
+ "switch": "Zc:rvalueCast",
+ "comment": "Enforce type conversion rules",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RuntimeTypeInfo",
+ "switch": "GR-",
+ "comment": "Enable Run-Time Type Information",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RuntimeTypeInfo",
+ "switch": "GR",
+ "comment": "Enable Run-Time Type Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OpenMPSupport",
+ "switch": "openmp-",
+ "comment": "Open MP Support",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OpenMPSupport",
+ "switch": "openmp",
+ "comment": "Open MP Support",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ExpandAttributedSource",
+ "switch": "Fx",
+ "comment": "Expand Attributed Source",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseUnicodeForAssemblerListing",
+ "switch": "FAu",
+ "comment": "Use Unicode For Assembler Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateXMLDocumentationFiles",
+ "switch": "doc",
+ "comment": "Generate XML Documentation Files",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "BrowseInformation",
+ "switch": "FR",
+ "comment": "Enable Browse Information",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "ShowIncludes",
+ "switch": "showIncludes",
+ "comment": "Show Includes",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnablePREfast",
+ "switch": "analyze-",
+ "comment": "Enable Code Analysis",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnablePREfast",
+ "switch": "analyze",
+ "comment": "Enable Code Analysis",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseFullPaths",
+ "switch": "FC",
+ "comment": "Use Full Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OmitDefaultLibName",
+ "switch": "Zl",
+ "comment": "Omit Default Library Name",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalIncludeDirectories",
+ "switch": "I",
+ "comment": "Additional Include Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalUsingDirectories",
+ "switch": "AI",
+ "comment": "Additional #using Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "UndefinePreprocessorDefinitions",
+ "switch": "U",
+ "comment": "Undefine Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "DisableSpecificWarnings",
+ "switch": "wd",
+ "comment": "Disable Specific Warnings",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForcedIncludeFiles",
+ "switch": "FI",
+ "comment": "Forced Include File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForcedUsingFiles",
+ "switch": "FU",
+ "comment": "Forced #using File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PREfastLog",
+ "switch": "analyze:log",
+ "comment": "Code Analysis Log",
+ "value": "",
+ "flags": [
+ "UserFollowing"
+ ]
+ },
+ {
+ "name": "PREfastAdditionalPlugins",
+ "switch": "analyze:plugin",
+ "comment": "Additional Code Analysis Native plugins",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "TreatSpecificWarningsAsErrors",
+ "switch": "we",
+ "comment": "Treat Specific Warnings As Errors",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "WarningVersion",
+ "switch": "Wv:",
+ "comment": "Warning Version",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "PreprocessOutputPath",
+ "switch": "Fi",
+ "comment": "Preprocess Output Path",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderFile",
+ "switch": "Yu",
+ "comment": "Precompiled Header File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderFile",
+ "switch": "Yc",
+ "comment": "Precompiled Header File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderOutputFile",
+ "switch": "Fp",
+ "comment": "Precompiled Header Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "AssemblerListingLocation",
+ "switch": "Fa",
+ "comment": "ASM List Location",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ObjectFileName",
+ "switch": "Fo",
+ "comment": "Object File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProgramDataBaseFileName",
+ "switch": "Fd",
+ "comment": "Program Database File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "XMLDocumentationFileName",
+ "switch": "doc",
+ "comment": "XML Documentation File Name",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "BrowseInformationFile",
+ "switch": "FR",
+ "comment": "Browse Information File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ProcessorNumber",
+ "switch": "MP",
+ "comment": "Number of processors",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=c++98",
+ "comment": "C++03",
+ "value": "c++98",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=c++11",
+ "comment": "C++11",
+ "value": "c++11",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=c++1y",
+ "comment": "C++14",
+ "value": "c++1y",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=c++14",
+ "comment": "C++14",
+ "value": "c++1y",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=gnu++98",
+ "comment": "C++03 (GNU Dialect)",
+ "value": "gnu++98",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=gnu++11",
+ "comment": "C++11 (GNU Dialect)",
+ "value": "gnu++11",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=gnu++1y",
+ "comment": "C++14 (GNU Dialect)",
+ "value": "gnu++1y",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=gnu++14",
+ "comment": "C++14 (GNU Dialect)",
+ "value": "gnu++1y",
+ "flags": []
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v140_CSharp.json b/Templates/MSBuild/FlagTables/v140_CSharp.json
new file mode 100644
index 0000000..5989aea
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v140_CSharp.json
@@ -0,0 +1,574 @@
+[
+ {
+ "name": "ProjectName",
+ "switch": "out:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:exe",
+ "comment": "",
+ "value": "Exe",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:winexe",
+ "comment": "",
+ "value": "Winexe",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:library",
+ "comment": "",
+ "value": "Library",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:module",
+ "comment": "",
+ "value": "Module",
+ "flags": []
+ },
+ {
+ "name": "DocumentationFile",
+ "switch": "doc",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:x86",
+ "comment": "",
+ "value": "x86",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:Itanium",
+ "comment": "",
+ "value": "Itanium",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:x64",
+ "comment": "",
+ "value": "x64",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:arm",
+ "comment": "",
+ "value": "arm",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:anycpu32bitpreferred",
+ "comment": "",
+ "value": "anycpu32bitpreferred",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:anycpu",
+ "comment": "",
+ "value": "anycpu",
+ "flags": []
+ },
+ {
+ "name": "References",
+ "switch": "reference:",
+ "comment": "mit alias",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "References",
+ "switch": "reference:",
+ "comment": "dateiliste",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "AddModules",
+ "switch": "addmodule:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "Win32Resource",
+ "switch": "win32res:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ApplicationIcon",
+ "switch": "win32icon:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ApplicationManifest",
+ "switch": "win32manifest:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "NoWin32Manifest",
+ "switch": "nowin32manifest",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DefineDebug",
+ "switch": "debug",
+ "comment": "",
+ "value": "true",
+ "flags": [
+ "Continue"
+ ]
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:none",
+ "comment": "",
+ "value": "none",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:full",
+ "comment": "",
+ "value": "full",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:pdbonly",
+ "comment": "",
+ "value": "pdbonly",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror-",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror+",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:0",
+ "comment": "",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:1",
+ "comment": "",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:2",
+ "comment": "",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:3",
+ "comment": "",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:4",
+ "comment": "",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "NoWarn",
+ "switch": "nowarn:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired",
+ "CommaAppendable"
+ ]
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DefineConstants",
+ "switch": "define:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "SemicolonAppendable",
+ "UserValue"
+ ]
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:ISO-1",
+ "comment": "",
+ "value": "ISO-1",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:ISO-2",
+ "comment": "",
+ "value": "ISO-2",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:3",
+ "comment": "",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:4",
+ "comment": "",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:5",
+ "comment": "",
+ "value": "5",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:6",
+ "comment": "",
+ "value": "6",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:default",
+ "comment": "",
+ "value": "default",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AssemblyOriginatorKeyFile",
+ "switch": "keyfile",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "KeyContainerName",
+ "switch": "keycontainer",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoLogo",
+ "switch": "nologo",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoConfig",
+ "switch": "noconfig",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "BaseAddress",
+ "switch": "baseaddress:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "CodePage",
+ "switch": "codepage",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "Utf8Output",
+ "switch": "utf8output",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "MainEntryPoint",
+ "switch": "main:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "GenerateFullPaths",
+ "switch": "fullpaths",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FileAlignment",
+ "switch": "filealign",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "PdbFile",
+ "switch": "pdb:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SubsystemVersion",
+ "switch": "subsystemversion",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibPaths",
+ "switch": "lib:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:none",
+ "comment": "Do Not Send Report",
+ "value": "none",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:prompt",
+ "comment": "Prompt Immediately",
+ "value": "prompt",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:queue",
+ "comment": "Queue For Next Login",
+ "value": "queue",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:send",
+ "comment": "Send Automatically",
+ "value": "send",
+ "flags": []
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v140_Link.json b/Templates/MSBuild/FlagTables/v140_Link.json
new file mode 100644
index 0000000..3fb072c
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v140_Link.json
@@ -0,0 +1,1316 @@
+[
+ {
+ "name": "ShowProgress",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE",
+ "comment": "Display all progress messages",
+ "value": "LinkVerbose",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:Lib",
+ "comment": "For Libraries Searched",
+ "value": "LinkVerboseLib",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:ICF",
+ "comment": "About COMDAT folding during optimized linking",
+ "value": "LinkVerboseICF",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:REF",
+ "comment": "About data removed during optimized linking",
+ "value": "LinkVerboseREF",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:SAFESEH",
+ "comment": "About Modules incompatible with SEH",
+ "value": "LinkVerboseSAFESEH",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:CLR",
+ "comment": "About linker activity related to managed code",
+ "value": "LinkVerboseCLR",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE:MULTIPLE",
+ "comment": "Multiply Defined Symbol Only",
+ "value": "MultiplyDefinedSymbolOnly",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE:UNRESOLVED",
+ "comment": "Undefined Symbol Only",
+ "value": "UndefinedSymbolOnly",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:5",
+ "comment": "X86 Image Only",
+ "value": "X86Image",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:6",
+ "comment": "X64 Image Only",
+ "value": "X64Image",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:16",
+ "comment": "Itanium Image Only",
+ "value": "ItaniumImage",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='asInvoker'",
+ "comment": "asInvoker",
+ "value": "AsInvoker",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='highestAvailable'",
+ "comment": "highestAvailable",
+ "value": "HighestAvailable",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='requireAdministrator'",
+ "comment": "requireAdministrator",
+ "value": "RequireAdministrator",
+ "flags": []
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG",
+ "comment": "Optimize for debugging",
+ "value": "true",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG:FASTLINK",
+ "comment": "Optimize for faster linking",
+ "value": "DebugFastLink",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG:FULL",
+ "comment": "Optimize for debugging",
+ "value": "true",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG:NONE",
+ "comment": "Produces no debugging information",
+ "value": "false",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "SubSystem",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:CONSOLE",
+ "comment": "Console",
+ "value": "Console",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWS",
+ "comment": "Windows",
+ "value": "Windows",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:NATIVE",
+ "comment": "Native",
+ "value": "Native",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_APPLICATION",
+ "comment": "EFI Application",
+ "value": "EFI Application",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "comment": "EFI Boot Service Driver",
+ "value": "EFI Boot Service Driver",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_ROM",
+ "comment": "EFI ROM",
+ "value": "EFI ROM",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_RUNTIME_DRIVER",
+ "comment": "EFI Runtime",
+ "value": "EFI Runtime",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:POSIX",
+ "comment": "POSIX",
+ "value": "POSIX",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "Driver",
+ "comment": "Driver",
+ "value": "Driver",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "DRIVER:UPONLY",
+ "comment": "UP Only",
+ "value": "UpOnly",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "DRIVER:WDM",
+ "comment": "WDM",
+ "value": "WDM",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:incremental",
+ "comment": "Use Fast Link Time Code Generation",
+ "value": "UseFastLinkTimeCodeGeneration",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG",
+ "comment": "Use Link Time Code Generation",
+ "value": "UseLinkTimeCodeGeneration",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGInstrument",
+ "comment": "Profile Guided Optimization - Instrument",
+ "value": "PGInstrument",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGOptimize",
+ "comment": "Profile Guided Optimization - Optimization",
+ "value": "PGOptimization",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGUpdate",
+ "comment": "Profile Guided Optimization - Update",
+ "value": "PGUpdate",
+ "flags": []
+ },
+ {
+ "name": "GenerateWindowsMetadata",
+ "switch": "WINMD",
+ "comment": "Yes",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateWindowsMetadata",
+ "switch": "WINMD:NO",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA1",
+ "comment": "SHA1",
+ "value": "SHA1",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA256",
+ "comment": "SHA256",
+ "value": "SHA256",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA384",
+ "comment": "SHA384",
+ "value": "SHA384",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA512",
+ "comment": "SHA512",
+ "value": "SHA512",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM",
+ "comment": "MachineARM",
+ "value": "MachineARM",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:EBC",
+ "comment": "MachineEBC",
+ "value": "MachineEBC",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:IA64",
+ "comment": "MachineIA64",
+ "value": "MachineIA64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS",
+ "comment": "MachineMIPS",
+ "value": "MachineMIPS",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS16",
+ "comment": "MachineMIPS16",
+ "value": "MachineMIPS16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU",
+ "comment": "MachineMIPSFPU",
+ "value": "MachineMIPSFPU",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU16",
+ "comment": "MachineMIPSFPU16",
+ "value": "MachineMIPSFPU16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:SH4",
+ "comment": "MachineSH4",
+ "value": "MachineSH4",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:THUMB",
+ "comment": "MachineTHUMB",
+ "value": "MachineTHUMB",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X64",
+ "comment": "MachineX64",
+ "value": "MachineX64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X86",
+ "comment": "MachineX86",
+ "value": "MachineX86",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:MTA",
+ "comment": "MTA threading attribute",
+ "value": "MTAThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:STA",
+ "comment": "STA threading attribute",
+ "value": "STAThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:NONE",
+ "comment": "Default threading attribute",
+ "value": "DefaultThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:IJW",
+ "comment": "Force IJW image",
+ "value": "ForceIJWImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:PURE",
+ "comment": "Force Pure IL Image",
+ "value": "ForcePureILImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:SAFE",
+ "comment": "Force Safe IL Image",
+ "value": "ForceSafeILImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "",
+ "comment": "Default image type",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA1",
+ "comment": "SHA1",
+ "value": "SHA1",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA256",
+ "comment": "SHA256",
+ "value": "SHA256",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA384",
+ "comment": "SHA384",
+ "value": "SHA384",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA512",
+ "comment": "SHA512",
+ "value": "SHA512",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:PROMPT",
+ "comment": "PromptImmediately",
+ "value": "PromptImmediately",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:QUEUE",
+ "comment": "Queue For Next Login",
+ "value": "QueueForNextLogin",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:SEND",
+ "comment": "Send Error Report",
+ "value": "SendErrorReport",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:NONE",
+ "comment": "No Error Report",
+ "value": "NoErrorReport",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError:NO",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError:SYSTEMDLL",
+ "comment": "System Dlls Only",
+ "value": "SystemDlls",
+ "flags": []
+ },
+ {
+ "name": "LinkIncremental",
+ "switch": "INCREMENTAL:NO",
+ "comment": "Enable Incremental Linking",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkIncremental",
+ "switch": "INCREMENTAL",
+ "comment": "Enable Incremental Linking",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "NOLOGO",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkStatus",
+ "switch": "LTCG:NOSTATUS",
+ "comment": "Link Status",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkStatus",
+ "switch": "LTCG:STATUS",
+ "comment": "Link Status",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreventDllBinding",
+ "switch": "ALLOWBIND:NO",
+ "comment": "Prevent Dll Binding",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "PreventDllBinding",
+ "switch": "ALLOWBIND",
+ "comment": "Prevent Dll Binding",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatLinkerWarningAsErrors",
+ "switch": "WX:NO",
+ "comment": "Treat Linker Warning As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatLinkerWarningAsErrors",
+ "switch": "WX",
+ "comment": "Treat Linker Warning As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreAllDefaultLibraries",
+ "switch": "NODEFAULTLIB",
+ "comment": "Ignore All Default Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateManifest",
+ "switch": "MANIFEST:NO",
+ "comment": "Generate Manifest",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "GenerateManifest",
+ "switch": "MANIFEST",
+ "comment": "Generate Manifest",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowIsolation",
+ "switch": "ALLOWISOLATION:NO",
+ "comment": "Allow Isolation",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AllowIsolation",
+ "switch": "",
+ "comment": "Allow Isolation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableUAC",
+ "switch": "MANIFESTUAC:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired",
+ "SpaceAppendable"
+ ]
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='false'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "false",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='false'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='true'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ManifestEmbed",
+ "switch": "manifest:embed",
+ "comment": "Embed Manifest",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateMapFile",
+ "switch": "MAP",
+ "comment": "Generate Map File",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "MapExports",
+ "switch": "MAPINFO:EXPORTS",
+ "comment": "Map Exports",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AssemblyDebug",
+ "switch": "ASSEMBLYDEBUG:DISABLE",
+ "comment": "Debuggable Assembly",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AssemblyDebug",
+ "switch": "ASSEMBLYDEBUG",
+ "comment": "Debuggable Assembly",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LargeAddressAware",
+ "switch": "LARGEADDRESSAWARE:NO",
+ "comment": "Enable Large Addresses",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LargeAddressAware",
+ "switch": "LARGEADDRESSAWARE",
+ "comment": "Enable Large Addresses",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TerminalServerAware",
+ "switch": "TSAWARE:NO",
+ "comment": "Terminal Server",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TerminalServerAware",
+ "switch": "TSAWARE",
+ "comment": "Terminal Server",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SwapRunFromCD",
+ "switch": "SWAPRUN:CD",
+ "comment": "Swap Run From CD",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SwapRunFromNET",
+ "switch": "SWAPRUN:NET",
+ "comment": "Swap Run From Network",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OptimizeReferences",
+ "switch": "OPT:NOREF",
+ "comment": "References",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OptimizeReferences",
+ "switch": "OPT:REF",
+ "comment": "References",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableCOMDATFolding",
+ "switch": "OPT:NOICF",
+ "comment": "Enable COMDAT Folding",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnableCOMDATFolding",
+ "switch": "OPT:ICF",
+ "comment": "Enable COMDAT Folding",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreEmbeddedIDL",
+ "switch": "IGNOREIDL",
+ "comment": "Ignore Embedded IDL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AppContainer",
+ "switch": "APPCONTAINER",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataLinkDelaySign",
+ "switch": "WINMDDELAYSIGN:NO",
+ "comment": "Windows Metadata Delay Sign",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataLinkDelaySign",
+ "switch": "WINMDDELAYSIGN",
+ "comment": "Windows Metadata Delay Sign",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NoEntryPoint",
+ "switch": "NOENTRY",
+ "comment": "No Entry Point",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SetChecksum",
+ "switch": "RELEASE",
+ "comment": "Set Checksum",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RandomizedBaseAddress",
+ "switch": "DYNAMICBASE:NO",
+ "comment": "Randomized Base Address",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RandomizedBaseAddress",
+ "switch": "DYNAMICBASE",
+ "comment": "Randomized Base Address",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FixedBaseAddress",
+ "switch": "FIXED:NO",
+ "comment": "Fixed Base Address",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FixedBaseAddress",
+ "switch": "FIXED",
+ "comment": "Fixed Base Address",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DataExecutionPrevention",
+ "switch": "NXCOMPAT:NO",
+ "comment": "Data Execution Prevention (DEP)",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DataExecutionPrevention",
+ "switch": "NXCOMPAT",
+ "comment": "Data Execution Prevention (DEP)",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TurnOffAssemblyGeneration",
+ "switch": "NOASSEMBLY",
+ "comment": "Turn Off Assembly Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SupportUnloadOfDelayLoadedDLL",
+ "switch": "DELAY:UNLOAD",
+ "comment": "Unload delay loaded DLL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SupportNobindOfDelayLoadedDLL",
+ "switch": "DELAY:NOBIND",
+ "comment": "Nobind delay loaded DLL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Profile",
+ "switch": "PROFILE",
+ "comment": "Profile",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkDelaySign",
+ "switch": "DELAYSIGN:NO",
+ "comment": "Delay Sign",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkDelaySign",
+ "switch": "DELAYSIGN",
+ "comment": "Delay Sign",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CLRUnmanagedCodeCheck",
+ "switch": "CLRUNMANAGEDCODECHECK:NO",
+ "comment": "CLR Unmanaged Code Check",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CLRUnmanagedCodeCheck",
+ "switch": "CLRUNMANAGEDCODECHECK",
+ "comment": "CLR Unmanaged Code Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DetectOneDefinitionRule",
+ "switch": "ODR",
+ "comment": "Detect One Definition Rule violations",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ImageHasSafeExceptionHandlers",
+ "switch": "SAFESEH:NO",
+ "comment": "Image Has Safe Exception Handlers",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "ImageHasSafeExceptionHandlers",
+ "switch": "SAFESEH",
+ "comment": "Image Has Safe Exception Handlers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkDLL",
+ "switch": "DLL",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibraryDirectories",
+ "switch": "LIBPATH:",
+ "comment": "Additional Library Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "Natvis",
+ "switch": "NATVIS:",
+ "comment": "Natvis files",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IgnoreSpecificDefaultLibraries",
+ "switch": "NODEFAULTLIB:",
+ "comment": "Ignore Specific Default Libraries",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AddModuleNamesToAssembly",
+ "switch": "ASSEMBLYMODULE:",
+ "comment": "Add Module to Assembly",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "EmbedManagedResourceFile",
+ "switch": "ASSEMBLYRESOURCE:",
+ "comment": "Embed Managed Resource File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForceSymbolReferences",
+ "switch": "INCLUDE:",
+ "comment": "Force Symbol References",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "DelayLoadDLLs",
+ "switch": "DELAYLOAD:",
+ "comment": "Delay Loaded Dlls",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AssemblyLinkResource",
+ "switch": "ASSEMBLYLINKRESOURCE:",
+ "comment": "Assembly Link Resource",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalManifestDependencies",
+ "switch": "MANIFESTDEPENDENCY:",
+ "comment": "Additional Manifest Dependencies",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ManifestInput",
+ "switch": "manifestinput:",
+ "comment": "Manifest Input",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "OutputFile",
+ "switch": "OUT:",
+ "comment": "Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "Version",
+ "switch": "VERSION:",
+ "comment": "Version",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "SpecifySectionAttributes",
+ "switch": "SECTION:",
+ "comment": "Specify Section Attributes",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MSDOSStubFileName",
+ "switch": "STUB:",
+ "comment": "MS-DOS Stub File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ModuleDefinitionFile",
+ "switch": "DEF:",
+ "comment": "Module Definition File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ManifestFile",
+ "switch": "ManifestFile:",
+ "comment": "Manifest File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProgramDatabaseFile",
+ "switch": "PDB:",
+ "comment": "Generate Program Database File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "StripPrivateSymbols",
+ "switch": "PDBSTRIPPED:",
+ "comment": "Strip Private Symbols",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MapFileName",
+ "switch": "MAP:",
+ "comment": "Map File Name",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "HeapReserveSize",
+ "switch": "HEAP:",
+ "comment": "Heap Reserve Size",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "HeapCommitSize",
+ "switch": "HEAP",
+ "comment": "Heap Commit Size",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "StackReserveSize",
+ "switch": "STACK:",
+ "comment": "Stack Reserve Size",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "StackCommitSize",
+ "switch": "STACK",
+ "comment": "Stack Commit Size",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "FunctionOrder",
+ "switch": "ORDER:@",
+ "comment": "Function Order",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProfileGuidedDatabase",
+ "switch": "PGD:",
+ "comment": "Profile Guided Database",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MidlCommandFile",
+ "switch": "MIDL:@",
+ "comment": "MIDL Commands",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MergedIDLBaseFileName",
+ "switch": "IDLOUT:",
+ "comment": "Merged IDL Base File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "TypeLibraryFile",
+ "switch": "TLBOUT:",
+ "comment": "Type Library",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataFile",
+ "switch": "WINMDFILE:",
+ "comment": "Windows Metadata File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataLinkKeyFile",
+ "switch": "WINMDKEYFILE:",
+ "comment": "Windows Metadata Key File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataKeyContainer",
+ "switch": "WINMDKEYCONTAINER:",
+ "comment": "Windows Metadata Key Container",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "EntryPointSymbol",
+ "switch": "ENTRY:",
+ "comment": "Entry Point",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "BaseAddress",
+ "switch": "BASE:",
+ "comment": "Base Address",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ImportLibrary",
+ "switch": "IMPLIB:",
+ "comment": "Import Library",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MergeSections",
+ "switch": "MERGE:",
+ "comment": "Merge Sections",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "LinkKeyFile",
+ "switch": "KEYFILE:",
+ "comment": "Key File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "KeyContainer",
+ "switch": "KEYCONTAINER:",
+ "comment": "Key Container",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "TypeLibraryResourceID",
+ "switch": "TLBID:",
+ "comment": "TypeLib Resource ID",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "SectionAlignment",
+ "switch": "ALIGN:",
+ "comment": "SectionAlignment",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v141_CL.json b/Templates/MSBuild/FlagTables/v141_CL.json
new file mode 100644
index 0000000..01fafe4
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v141_CL.json
@@ -0,0 +1,1268 @@
+[
+ {
+ "name": "DebugInformationFormat",
+ "switch": "",
+ "comment": "None",
+ "value": "None",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "Z7",
+ "comment": "C7 compatible",
+ "value": "OldStyle",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "Zi",
+ "comment": "Program Database",
+ "value": "ProgramDatabase",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "ZI",
+ "comment": "Program Database for Edit And Continue",
+ "value": "EditAndContinue",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "",
+ "comment": "No Common Language RunTime Support",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr",
+ "comment": "Common Language RunTime Support",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:pure",
+ "comment": "Pure MSIL Common Language RunTime Support",
+ "value": "Pure",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:safe",
+ "comment": "Safe MSIL Common Language RunTime Support",
+ "value": "Safe",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W0",
+ "comment": "Turn Off All Warnings",
+ "value": "TurnOffAllWarnings",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W1",
+ "comment": "Level1",
+ "value": "Level1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W2",
+ "comment": "Level2",
+ "value": "Level2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W3",
+ "comment": "Level3",
+ "value": "Level3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W4",
+ "comment": "Level4",
+ "value": "Level4",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "Wall",
+ "comment": "EnableAllWarnings",
+ "value": "EnableAllWarnings",
+ "flags": []
+ },
+ {
+ "name": "DiagnosticsFormat",
+ "switch": "diagnostics:caret",
+ "comment": "Caret",
+ "value": "Caret",
+ "flags": []
+ },
+ {
+ "name": "DiagnosticsFormat",
+ "switch": "diagnostics:column",
+ "comment": "Column Info",
+ "value": "Column",
+ "flags": []
+ },
+ {
+ "name": "DiagnosticsFormat",
+ "switch": "diagnostics:classic",
+ "comment": "Classic",
+ "value": "Classic",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "",
+ "comment": "Custom",
+ "value": "Custom",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "Od",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "O1",
+ "comment": "Maximum Optimization (Favor Size)",
+ "value": "MinSpace",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "O2",
+ "comment": "Maximum Optimization (Favor Speed)",
+ "value": "MaxSpeed",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "Ox",
+ "comment": "Optimizations (Favor Speed)",
+ "value": "Full",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob0",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob1",
+ "comment": "Only __inline",
+ "value": "OnlyExplicitInline",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob2",
+ "comment": "Any Suitable",
+ "value": "AnySuitable",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "Os",
+ "comment": "Favor small code",
+ "value": "Size",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "Ot",
+ "comment": "Favor fast code",
+ "value": "Speed",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "",
+ "comment": "Neither",
+ "value": "Neither",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHa",
+ "comment": "Yes with SEH Exceptions",
+ "value": "Async",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHsc",
+ "comment": "Yes",
+ "value": "Sync",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHs",
+ "comment": "Yes with Extern C functions",
+ "value": "SyncCThrow",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTCs",
+ "comment": "Stack Frames",
+ "value": "StackFrameRuntimeCheck",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTCu",
+ "comment": "Uninitialized variables",
+ "value": "UninitializedLocalUsageCheck",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTC1",
+ "comment": "Both (/RTC1, equiv. to /RTCsu)",
+ "value": "EnableFastChecks",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MT",
+ "comment": "Multi-threaded",
+ "value": "MultiThreaded",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MTd",
+ "comment": "Multi-threaded Debug",
+ "value": "MultiThreadedDebug",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MD",
+ "comment": "Multi-threaded DLL",
+ "value": "MultiThreadedDLL",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MDd",
+ "comment": "Multi-threaded Debug DLL",
+ "value": "MultiThreadedDebugDLL",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp1",
+ "comment": "1 Byte",
+ "value": "1Byte",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp2",
+ "comment": "2 Bytes",
+ "value": "2Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp4",
+ "comment": "4 Byte",
+ "value": "4Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp8",
+ "comment": "8 Bytes",
+ "value": "8Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp16",
+ "comment": "16 Bytes",
+ "value": "16Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "BufferSecurityCheck",
+ "switch": "GS-",
+ "comment": "Disable Security Check",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "BufferSecurityCheck",
+ "switch": "GS",
+ "comment": "Enable Security Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ControlFlowGuard",
+ "switch": "guard:cf",
+ "comment": "Yes",
+ "value": "Guard",
+ "flags": []
+ },
+ {
+ "name": "ControlFlowGuard",
+ "switch": "",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:SSE",
+ "comment": "Streaming SIMD Extensions",
+ "value": "StreamingSIMDExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:SSE2",
+ "comment": "Streaming SIMD Extensions 2",
+ "value": "StreamingSIMDExtensions2",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:AVX",
+ "comment": "Advanced Vector Extensions",
+ "value": "AdvancedVectorExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:AVX2",
+ "comment": "Advanced Vector Extensions 2",
+ "value": "AdvancedVectorExtensions2",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:IA32",
+ "comment": "No Enhanced Instructions",
+ "value": "NoExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:precise",
+ "comment": "Precise",
+ "value": "Precise",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:strict",
+ "comment": "Strict",
+ "value": "Strict",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:fast",
+ "comment": "Fast",
+ "value": "Fast",
+ "flags": []
+ },
+ {
+ "name": "SpectreMitigation",
+ "switch": "Qspectre",
+ "comment": "Spectre mitigations",
+ "value": "Spectre",
+ "flags": []
+ },
+ {
+ "name": "LanguageStandard",
+ "switch": "std:c++14",
+ "comment": "ISO C++14 Standard",
+ "value": "stdcpp14",
+ "flags": []
+ },
+ {
+ "name": "LanguageStandard",
+ "switch": "std:c++17",
+ "comment": "ISO C++17 Standard",
+ "value": "stdcpp17",
+ "flags": []
+ },
+ {
+ "name": "LanguageStandard",
+ "switch": "std:c++latest",
+ "comment": "ISO C++ Latest Draft Standard",
+ "value": "stdcpplatest",
+ "flags": []
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Yc",
+ "comment": "Create",
+ "value": "Create",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Yu",
+ "comment": "Use",
+ "value": "Use",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Y-",
+ "comment": "Not Using Precompiled Headers",
+ "value": "NotUsing",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "",
+ "comment": "No Listing",
+ "value": "NoListing",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FA",
+ "comment": "Assembly-Only Listing",
+ "value": "AssemblyCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAc",
+ "comment": "Assembly With Machine Code",
+ "value": "AssemblyAndMachineCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAs",
+ "comment": "Assembly With Source Code",
+ "value": "AssemblyAndSourceCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAcs",
+ "comment": "Assembly, Machine Code and Source",
+ "value": "All",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gd",
+ "comment": "__cdecl",
+ "value": "Cdecl",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gr",
+ "comment": "__fastcall",
+ "value": "FastCall",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gz",
+ "comment": "__stdcall",
+ "value": "StdCall",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gv",
+ "comment": "__vectorcall",
+ "value": "VectorCall",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "TC",
+ "comment": "Compile as C Code",
+ "value": "CompileAsC",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "TP",
+ "comment": "Compile as C++ Code",
+ "value": "CompileAsCpp",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:none",
+ "comment": "Do Not Send Report",
+ "value": "None",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:prompt",
+ "comment": "Prompt Immediately",
+ "value": "Prompt",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:queue",
+ "comment": "Queue For Next Login",
+ "value": "Queue",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:send",
+ "comment": "Send Automatically",
+ "value": "Send",
+ "flags": []
+ },
+ {
+ "name": "CompileAsWinRT",
+ "switch": "ZW",
+ "comment": "Consume Windows Runtime Extension",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WinRTNoStdLib",
+ "switch": "ZW:nostdlib",
+ "comment": "No Standard WinRT Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "nologo",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningAsError",
+ "switch": "WX-",
+ "comment": "Treat Warnings As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningAsError",
+ "switch": "WX",
+ "comment": "Treat Warnings As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SDLCheck",
+ "switch": "sdl-",
+ "comment": "SDL checks",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "SDLCheck",
+ "switch": "sdl",
+ "comment": "SDL checks",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MultiProcessorCompilation",
+ "switch": "MP",
+ "comment": "Multi-processor Compilation",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "IntrinsicFunctions",
+ "switch": "Oi",
+ "comment": "Enable Intrinsic Functions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OmitFramePointers",
+ "switch": "Oy-",
+ "comment": "Omit Frame Pointers",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OmitFramePointers",
+ "switch": "Oy",
+ "comment": "Omit Frame Pointers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableFiberSafeOptimizations",
+ "switch": "GT",
+ "comment": "Enable Fiber-Safe Optimizations",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WholeProgramOptimization",
+ "switch": "GL",
+ "comment": "Whole Program Optimization",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UndefineAllPreprocessorDefinitions",
+ "switch": "u",
+ "comment": "Undefine All Preprocessor Definitions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreStandardIncludePath",
+ "switch": "X",
+ "comment": "Ignore Standard Include Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessToFile",
+ "switch": "P",
+ "comment": "Preprocess to a File",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessSuppressLineNumbers",
+ "switch": "EP",
+ "comment": "Preprocess Suppress Line Numbers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessKeepComments",
+ "switch": "C",
+ "comment": "Keep Comments",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "StringPooling",
+ "switch": "GF-",
+ "comment": "Enable String Pooling",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "StringPooling",
+ "switch": "GF",
+ "comment": "Enable String Pooling",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MinimalRebuild",
+ "switch": "Gm-",
+ "comment": "Enable Minimal Rebuild",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "MinimalRebuild",
+ "switch": "Gm",
+ "comment": "Enable Minimal Rebuild",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SmallerTypeCheck",
+ "switch": "RTCc",
+ "comment": "Smaller Type Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FunctionLevelLinking",
+ "switch": "Gy-",
+ "comment": "Enable Function-Level Linking",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FunctionLevelLinking",
+ "switch": "Gy",
+ "comment": "Enable Function-Level Linking",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableParallelCodeGeneration",
+ "switch": "Qpar-",
+ "comment": "Enable Parallel Code Generation",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnableParallelCodeGeneration",
+ "switch": "Qpar",
+ "comment": "Enable Parallel Code Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointExceptions",
+ "switch": "fp:except-",
+ "comment": "Enable Floating Point Exceptions",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointExceptions",
+ "switch": "fp:except",
+ "comment": "Enable Floating Point Exceptions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CreateHotpatchableImage",
+ "switch": "hotpatch",
+ "comment": "Create Hotpatchable Image",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DisableLanguageExtensions",
+ "switch": "Za",
+ "comment": "Disable Language Extensions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ConformanceMode",
+ "switch": "permissive-",
+ "comment": "Conformance mode enabled",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ConformanceMode",
+ "switch": "permissive",
+ "comment": "Conformance mode disabled",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWChar_tAsBuiltInType",
+ "switch": "Zc:wchar_t-",
+ "comment": "Treat WChar_t As Built in Type",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWChar_tAsBuiltInType",
+ "switch": "Zc:wchar_t",
+ "comment": "Treat WChar_t As Built in Type",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ForceConformanceInForLoopScope",
+ "switch": "Zc:forScope-",
+ "comment": "Force Conformance in For Loop Scope",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "ForceConformanceInForLoopScope",
+ "switch": "Zc:forScope",
+ "comment": "Force Conformance in For Loop Scope",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RemoveUnreferencedCodeData",
+ "switch": "Zc:inline-",
+ "comment": "Remove unreferenced code and data",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RemoveUnreferencedCodeData",
+ "switch": "Zc:inline",
+ "comment": "Remove unreferenced code and data",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnforceTypeConversionRules",
+ "switch": "Zc:rvalueCast-",
+ "comment": "Enforce type conversion rules",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnforceTypeConversionRules",
+ "switch": "Zc:rvalueCast",
+ "comment": "Enforce type conversion rules",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RuntimeTypeInfo",
+ "switch": "GR-",
+ "comment": "Enable Run-Time Type Information",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RuntimeTypeInfo",
+ "switch": "GR",
+ "comment": "Enable Run-Time Type Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OpenMPSupport",
+ "switch": "openmp-",
+ "comment": "Open MP Support",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OpenMPSupport",
+ "switch": "openmp",
+ "comment": "Open MP Support",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableModules",
+ "switch": "experimental:module",
+ "comment": "Enable C++ Modules (experimental)",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ExpandAttributedSource",
+ "switch": "Fx",
+ "comment": "Expand Attributed Source",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseUnicodeForAssemblerListing",
+ "switch": "FAu",
+ "comment": "Use Unicode For Assembler Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateXMLDocumentationFiles",
+ "switch": "doc",
+ "comment": "Generate XML Documentation Files",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "BrowseInformation",
+ "switch": "FR",
+ "comment": "Enable Browse Information",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "ShowIncludes",
+ "switch": "showIncludes",
+ "comment": "Show Includes",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnablePREfast",
+ "switch": "analyze-",
+ "comment": "Enable Code Analysis",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnablePREfast",
+ "switch": "analyze",
+ "comment": "Enable Code Analysis",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseFullPaths",
+ "switch": "FC",
+ "comment": "Use Full Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OmitDefaultLibName",
+ "switch": "Zl",
+ "comment": "Omit Default Library Name",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalIncludeDirectories",
+ "switch": "I",
+ "comment": "Additional Include Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalUsingDirectories",
+ "switch": "AI",
+ "comment": "Additional #using Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "UndefinePreprocessorDefinitions",
+ "switch": "U",
+ "comment": "Undefine Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "DisableSpecificWarnings",
+ "switch": "wd",
+ "comment": "Disable Specific Warnings",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForcedIncludeFiles",
+ "switch": "FI",
+ "comment": "Forced Include File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForcedUsingFiles",
+ "switch": "FU",
+ "comment": "Forced #using File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PREfastLog",
+ "switch": "analyze:log",
+ "comment": "Code Analysis Log",
+ "value": "",
+ "flags": [
+ "UserFollowing"
+ ]
+ },
+ {
+ "name": "PREfastAdditionalPlugins",
+ "switch": "analyze:plugin",
+ "comment": "Additional Code Analysis Native plugins",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "TreatSpecificWarningsAsErrors",
+ "switch": "we",
+ "comment": "Treat Specific Warnings As Errors",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "WarningVersion",
+ "switch": "Wv:",
+ "comment": "Warning Version",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "PreprocessOutputPath",
+ "switch": "Fi",
+ "comment": "Preprocess Output Path",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderFile",
+ "switch": "Yu",
+ "comment": "Precompiled Header File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderFile",
+ "switch": "Yc",
+ "comment": "Precompiled Header File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderOutputFile",
+ "switch": "Fp",
+ "comment": "Precompiled Header Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "AssemblerListingLocation",
+ "switch": "Fa",
+ "comment": "ASM List Location",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ObjectFileName",
+ "switch": "Fo",
+ "comment": "Object File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProgramDataBaseFileName",
+ "switch": "Fd",
+ "comment": "Program Database File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "XMLDocumentationFileName",
+ "switch": "doc",
+ "comment": "XML Documentation File Name",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "BrowseInformationFile",
+ "switch": "FR",
+ "comment": "Browse Information File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ProcessorNumber",
+ "switch": "MP",
+ "comment": "Number of processors",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=c++98",
+ "comment": "C++03",
+ "value": "c++98",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=c++11",
+ "comment": "C++11",
+ "value": "c++11",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=c++1y",
+ "comment": "C++14",
+ "value": "c++1y",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=c++14",
+ "comment": "C++14",
+ "value": "c++1y",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=gnu++98",
+ "comment": "C++03 (GNU Dialect)",
+ "value": "gnu++98",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=gnu++11",
+ "comment": "C++11 (GNU Dialect)",
+ "value": "gnu++11",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=gnu++1y",
+ "comment": "C++14 (GNU Dialect)",
+ "value": "gnu++1y",
+ "flags": []
+ },
+ {
+ "name": "CppLanguageStandard",
+ "switch": "std=gnu++14",
+ "comment": "C++14 (GNU Dialect)",
+ "value": "gnu++1y",
+ "flags": []
+ },
+ {
+ "name": "SupportJustMyCode",
+ "switch": "JMC-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "SupportJustMyCode",
+ "switch": "JMC",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v141_CSharp.json b/Templates/MSBuild/FlagTables/v141_CSharp.json
new file mode 100644
index 0000000..5989aea
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v141_CSharp.json
@@ -0,0 +1,574 @@
+[
+ {
+ "name": "ProjectName",
+ "switch": "out:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:exe",
+ "comment": "",
+ "value": "Exe",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:winexe",
+ "comment": "",
+ "value": "Winexe",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:library",
+ "comment": "",
+ "value": "Library",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:module",
+ "comment": "",
+ "value": "Module",
+ "flags": []
+ },
+ {
+ "name": "DocumentationFile",
+ "switch": "doc",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:x86",
+ "comment": "",
+ "value": "x86",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:Itanium",
+ "comment": "",
+ "value": "Itanium",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:x64",
+ "comment": "",
+ "value": "x64",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:arm",
+ "comment": "",
+ "value": "arm",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:anycpu32bitpreferred",
+ "comment": "",
+ "value": "anycpu32bitpreferred",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:anycpu",
+ "comment": "",
+ "value": "anycpu",
+ "flags": []
+ },
+ {
+ "name": "References",
+ "switch": "reference:",
+ "comment": "mit alias",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "References",
+ "switch": "reference:",
+ "comment": "dateiliste",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "AddModules",
+ "switch": "addmodule:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "Win32Resource",
+ "switch": "win32res:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ApplicationIcon",
+ "switch": "win32icon:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ApplicationManifest",
+ "switch": "win32manifest:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "NoWin32Manifest",
+ "switch": "nowin32manifest",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DefineDebug",
+ "switch": "debug",
+ "comment": "",
+ "value": "true",
+ "flags": [
+ "Continue"
+ ]
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:none",
+ "comment": "",
+ "value": "none",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:full",
+ "comment": "",
+ "value": "full",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:pdbonly",
+ "comment": "",
+ "value": "pdbonly",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror-",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror+",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:0",
+ "comment": "",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:1",
+ "comment": "",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:2",
+ "comment": "",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:3",
+ "comment": "",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:4",
+ "comment": "",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "NoWarn",
+ "switch": "nowarn:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired",
+ "CommaAppendable"
+ ]
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DefineConstants",
+ "switch": "define:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "SemicolonAppendable",
+ "UserValue"
+ ]
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:ISO-1",
+ "comment": "",
+ "value": "ISO-1",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:ISO-2",
+ "comment": "",
+ "value": "ISO-2",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:3",
+ "comment": "",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:4",
+ "comment": "",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:5",
+ "comment": "",
+ "value": "5",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:6",
+ "comment": "",
+ "value": "6",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:default",
+ "comment": "",
+ "value": "default",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AssemblyOriginatorKeyFile",
+ "switch": "keyfile",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "KeyContainerName",
+ "switch": "keycontainer",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoLogo",
+ "switch": "nologo",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoConfig",
+ "switch": "noconfig",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "BaseAddress",
+ "switch": "baseaddress:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "CodePage",
+ "switch": "codepage",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "Utf8Output",
+ "switch": "utf8output",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "MainEntryPoint",
+ "switch": "main:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "GenerateFullPaths",
+ "switch": "fullpaths",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FileAlignment",
+ "switch": "filealign",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "PdbFile",
+ "switch": "pdb:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SubsystemVersion",
+ "switch": "subsystemversion",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibPaths",
+ "switch": "lib:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:none",
+ "comment": "Do Not Send Report",
+ "value": "none",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:prompt",
+ "comment": "Prompt Immediately",
+ "value": "prompt",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:queue",
+ "comment": "Queue For Next Login",
+ "value": "queue",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:send",
+ "comment": "Send Automatically",
+ "value": "send",
+ "flags": []
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v141_Link.json b/Templates/MSBuild/FlagTables/v141_Link.json
new file mode 100644
index 0000000..66ee76f
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v141_Link.json
@@ -0,0 +1,1323 @@
+[
+ {
+ "name": "ShowProgress",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE",
+ "comment": "Display all progress messages",
+ "value": "LinkVerbose",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:Lib",
+ "comment": "For Libraries Searched",
+ "value": "LinkVerboseLib",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:ICF",
+ "comment": "About COMDAT folding during optimized linking",
+ "value": "LinkVerboseICF",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:REF",
+ "comment": "About data removed during optimized linking",
+ "value": "LinkVerboseREF",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:SAFESEH",
+ "comment": "About Modules incompatible with SEH",
+ "value": "LinkVerboseSAFESEH",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:CLR",
+ "comment": "About linker activity related to managed code",
+ "value": "LinkVerboseCLR",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE:MULTIPLE",
+ "comment": "Multiply Defined Symbol Only",
+ "value": "MultiplyDefinedSymbolOnly",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE:UNRESOLVED",
+ "comment": "Undefined Symbol Only",
+ "value": "UndefinedSymbolOnly",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:5",
+ "comment": "X86 Image Only",
+ "value": "X86Image",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:6",
+ "comment": "X64 Image Only",
+ "value": "X64Image",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:16",
+ "comment": "Itanium Image Only",
+ "value": "ItaniumImage",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='asInvoker'",
+ "comment": "asInvoker",
+ "value": "AsInvoker",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='highestAvailable'",
+ "comment": "highestAvailable",
+ "value": "HighestAvailable",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='requireAdministrator'",
+ "comment": "requireAdministrator",
+ "value": "RequireAdministrator",
+ "flags": []
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG",
+ "comment": "Generate Debug Information",
+ "value": "true",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG:FASTLINK",
+ "comment": "Generate Debug Information optimized for faster links",
+ "value": "DebugFastLink",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG:FULL",
+ "comment": "Generate Debug Information optimized for sharing and publishing",
+ "value": "DebugFull",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG:NONE",
+ "comment": "Produces no debugging information",
+ "value": "false",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "SubSystem",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:CONSOLE",
+ "comment": "Console",
+ "value": "Console",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWS",
+ "comment": "Windows",
+ "value": "Windows",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:NATIVE",
+ "comment": "Native",
+ "value": "Native",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_APPLICATION",
+ "comment": "EFI Application",
+ "value": "EFI Application",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "comment": "EFI Boot Service Driver",
+ "value": "EFI Boot Service Driver",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_ROM",
+ "comment": "EFI ROM",
+ "value": "EFI ROM",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_RUNTIME_DRIVER",
+ "comment": "EFI Runtime",
+ "value": "EFI Runtime",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:POSIX",
+ "comment": "POSIX",
+ "value": "POSIX",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "Driver",
+ "comment": "Driver",
+ "value": "Driver",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "DRIVER:UPONLY",
+ "comment": "UP Only",
+ "value": "UpOnly",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "DRIVER:WDM",
+ "comment": "WDM",
+ "value": "WDM",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:incremental",
+ "comment": "Use Fast Link Time Code Generation",
+ "value": "UseFastLinkTimeCodeGeneration",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG",
+ "comment": "Use Link Time Code Generation",
+ "value": "UseLinkTimeCodeGeneration",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGInstrument",
+ "comment": "Profile Guided Optimization - Instrument",
+ "value": "PGInstrument",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGOptimize",
+ "comment": "Profile Guided Optimization - Optimization",
+ "value": "PGOptimization",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGUpdate",
+ "comment": "Profile Guided Optimization - Update",
+ "value": "PGUpdate",
+ "flags": []
+ },
+ {
+ "name": "GenerateWindowsMetadata",
+ "switch": "WINMD",
+ "comment": "Yes",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateWindowsMetadata",
+ "switch": "WINMD:NO",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA1",
+ "comment": "SHA1",
+ "value": "SHA1",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA256",
+ "comment": "SHA256",
+ "value": "SHA256",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA384",
+ "comment": "SHA384",
+ "value": "SHA384",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA512",
+ "comment": "SHA512",
+ "value": "SHA512",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM",
+ "comment": "MachineARM",
+ "value": "MachineARM",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM64",
+ "comment": "MachineARM64",
+ "value": "MachineARM64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:EBC",
+ "comment": "MachineEBC",
+ "value": "MachineEBC",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:IA64",
+ "comment": "MachineIA64",
+ "value": "MachineIA64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS",
+ "comment": "MachineMIPS",
+ "value": "MachineMIPS",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS16",
+ "comment": "MachineMIPS16",
+ "value": "MachineMIPS16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU",
+ "comment": "MachineMIPSFPU",
+ "value": "MachineMIPSFPU",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU16",
+ "comment": "MachineMIPSFPU16",
+ "value": "MachineMIPSFPU16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:SH4",
+ "comment": "MachineSH4",
+ "value": "MachineSH4",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:THUMB",
+ "comment": "MachineTHUMB",
+ "value": "MachineTHUMB",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X64",
+ "comment": "MachineX64",
+ "value": "MachineX64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X86",
+ "comment": "MachineX86",
+ "value": "MachineX86",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:MTA",
+ "comment": "MTA threading attribute",
+ "value": "MTAThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:STA",
+ "comment": "STA threading attribute",
+ "value": "STAThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:NONE",
+ "comment": "Default threading attribute",
+ "value": "DefaultThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:IJW",
+ "comment": "Force IJW image",
+ "value": "ForceIJWImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:PURE",
+ "comment": "Force Pure IL Image",
+ "value": "ForcePureILImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:SAFE",
+ "comment": "Force Safe IL Image",
+ "value": "ForceSafeILImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "",
+ "comment": "Default image type",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA1",
+ "comment": "SHA1",
+ "value": "SHA1",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA256",
+ "comment": "SHA256",
+ "value": "SHA256",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA384",
+ "comment": "SHA384",
+ "value": "SHA384",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA512",
+ "comment": "SHA512",
+ "value": "SHA512",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:PROMPT",
+ "comment": "PromptImmediately",
+ "value": "PromptImmediately",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:QUEUE",
+ "comment": "Queue For Next Login",
+ "value": "QueueForNextLogin",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:SEND",
+ "comment": "Send Error Report",
+ "value": "SendErrorReport",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:NONE",
+ "comment": "No Error Report",
+ "value": "NoErrorReport",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError:NO",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError:SYSTEMDLL",
+ "comment": "System Dlls Only",
+ "value": "SystemDlls",
+ "flags": []
+ },
+ {
+ "name": "LinkIncremental",
+ "switch": "INCREMENTAL:NO",
+ "comment": "Enable Incremental Linking",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkIncremental",
+ "switch": "INCREMENTAL",
+ "comment": "Enable Incremental Linking",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "NOLOGO",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkStatus",
+ "switch": "LTCG:NOSTATUS",
+ "comment": "Link Status",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkStatus",
+ "switch": "LTCG:STATUS",
+ "comment": "Link Status",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreventDllBinding",
+ "switch": "ALLOWBIND:NO",
+ "comment": "Prevent Dll Binding",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "PreventDllBinding",
+ "switch": "ALLOWBIND",
+ "comment": "Prevent Dll Binding",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatLinkerWarningAsErrors",
+ "switch": "WX:NO",
+ "comment": "Treat Linker Warning As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatLinkerWarningAsErrors",
+ "switch": "WX",
+ "comment": "Treat Linker Warning As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreAllDefaultLibraries",
+ "switch": "NODEFAULTLIB",
+ "comment": "Ignore All Default Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateManifest",
+ "switch": "MANIFEST:NO",
+ "comment": "Generate Manifest",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "GenerateManifest",
+ "switch": "MANIFEST",
+ "comment": "Generate Manifest",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowIsolation",
+ "switch": "ALLOWISOLATION:NO",
+ "comment": "Allow Isolation",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AllowIsolation",
+ "switch": "",
+ "comment": "Allow Isolation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableUAC",
+ "switch": "MANIFESTUAC:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired",
+ "SpaceAppendable"
+ ]
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='false'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "false",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='false'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='true'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ManifestEmbed",
+ "switch": "manifest:embed",
+ "comment": "Embed Manifest",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateMapFile",
+ "switch": "MAP",
+ "comment": "Generate Map File",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "MapExports",
+ "switch": "MAPINFO:EXPORTS",
+ "comment": "Map Exports",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AssemblyDebug",
+ "switch": "ASSEMBLYDEBUG:DISABLE",
+ "comment": "Debuggable Assembly",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AssemblyDebug",
+ "switch": "ASSEMBLYDEBUG",
+ "comment": "Debuggable Assembly",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LargeAddressAware",
+ "switch": "LARGEADDRESSAWARE:NO",
+ "comment": "Enable Large Addresses",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LargeAddressAware",
+ "switch": "LARGEADDRESSAWARE",
+ "comment": "Enable Large Addresses",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TerminalServerAware",
+ "switch": "TSAWARE:NO",
+ "comment": "Terminal Server",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TerminalServerAware",
+ "switch": "TSAWARE",
+ "comment": "Terminal Server",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SwapRunFromCD",
+ "switch": "SWAPRUN:CD",
+ "comment": "Swap Run From CD",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SwapRunFromNET",
+ "switch": "SWAPRUN:NET",
+ "comment": "Swap Run From Network",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OptimizeReferences",
+ "switch": "OPT:NOREF",
+ "comment": "References",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OptimizeReferences",
+ "switch": "OPT:REF",
+ "comment": "References",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableCOMDATFolding",
+ "switch": "OPT:NOICF",
+ "comment": "Enable COMDAT Folding",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnableCOMDATFolding",
+ "switch": "OPT:ICF",
+ "comment": "Enable COMDAT Folding",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreEmbeddedIDL",
+ "switch": "IGNOREIDL",
+ "comment": "Ignore Embedded IDL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AppContainer",
+ "switch": "APPCONTAINER",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataLinkDelaySign",
+ "switch": "WINMDDELAYSIGN:NO",
+ "comment": "Windows Metadata Delay Sign",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataLinkDelaySign",
+ "switch": "WINMDDELAYSIGN",
+ "comment": "Windows Metadata Delay Sign",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NoEntryPoint",
+ "switch": "NOENTRY",
+ "comment": "No Entry Point",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SetChecksum",
+ "switch": "RELEASE",
+ "comment": "Set Checksum",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RandomizedBaseAddress",
+ "switch": "DYNAMICBASE:NO",
+ "comment": "Randomized Base Address",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RandomizedBaseAddress",
+ "switch": "DYNAMICBASE",
+ "comment": "Randomized Base Address",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FixedBaseAddress",
+ "switch": "FIXED:NO",
+ "comment": "Fixed Base Address",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FixedBaseAddress",
+ "switch": "FIXED",
+ "comment": "Fixed Base Address",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DataExecutionPrevention",
+ "switch": "NXCOMPAT:NO",
+ "comment": "Data Execution Prevention (DEP)",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DataExecutionPrevention",
+ "switch": "NXCOMPAT",
+ "comment": "Data Execution Prevention (DEP)",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TurnOffAssemblyGeneration",
+ "switch": "NOASSEMBLY",
+ "comment": "Turn Off Assembly Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SupportUnloadOfDelayLoadedDLL",
+ "switch": "DELAY:UNLOAD",
+ "comment": "Unload delay loaded DLL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SupportNobindOfDelayLoadedDLL",
+ "switch": "DELAY:NOBIND",
+ "comment": "Nobind delay loaded DLL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Profile",
+ "switch": "PROFILE",
+ "comment": "Profile",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkDelaySign",
+ "switch": "DELAYSIGN:NO",
+ "comment": "Delay Sign",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkDelaySign",
+ "switch": "DELAYSIGN",
+ "comment": "Delay Sign",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CLRUnmanagedCodeCheck",
+ "switch": "CLRUNMANAGEDCODECHECK:NO",
+ "comment": "CLR Unmanaged Code Check",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CLRUnmanagedCodeCheck",
+ "switch": "CLRUNMANAGEDCODECHECK",
+ "comment": "CLR Unmanaged Code Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DetectOneDefinitionRule",
+ "switch": "ODR",
+ "comment": "Detect One Definition Rule violations",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ImageHasSafeExceptionHandlers",
+ "switch": "SAFESEH:NO",
+ "comment": "Image Has Safe Exception Handlers",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "ImageHasSafeExceptionHandlers",
+ "switch": "SAFESEH",
+ "comment": "Image Has Safe Exception Handlers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkDLL",
+ "switch": "DLL",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibraryDirectories",
+ "switch": "LIBPATH:",
+ "comment": "Additional Library Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "Natvis",
+ "switch": "NATVIS:",
+ "comment": "Natvis files",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IgnoreSpecificDefaultLibraries",
+ "switch": "NODEFAULTLIB:",
+ "comment": "Ignore Specific Default Libraries",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AddModuleNamesToAssembly",
+ "switch": "ASSEMBLYMODULE:",
+ "comment": "Add Module to Assembly",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "EmbedManagedResourceFile",
+ "switch": "ASSEMBLYRESOURCE:",
+ "comment": "Embed Managed Resource File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForceSymbolReferences",
+ "switch": "INCLUDE:",
+ "comment": "Force Symbol References",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "DelayLoadDLLs",
+ "switch": "DELAYLOAD:",
+ "comment": "Delay Loaded Dlls",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AssemblyLinkResource",
+ "switch": "ASSEMBLYLINKRESOURCE:",
+ "comment": "Assembly Link Resource",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalManifestDependencies",
+ "switch": "MANIFESTDEPENDENCY:",
+ "comment": "Additional Manifest Dependencies",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ManifestInput",
+ "switch": "manifestinput:",
+ "comment": "Manifest Input",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "OutputFile",
+ "switch": "OUT:",
+ "comment": "Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "Version",
+ "switch": "VERSION:",
+ "comment": "Version",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "SpecifySectionAttributes",
+ "switch": "SECTION:",
+ "comment": "Specify Section Attributes",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MSDOSStubFileName",
+ "switch": "STUB:",
+ "comment": "MS-DOS Stub File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ModuleDefinitionFile",
+ "switch": "DEF:",
+ "comment": "Module Definition File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ManifestFile",
+ "switch": "ManifestFile:",
+ "comment": "Manifest File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProgramDatabaseFile",
+ "switch": "PDB:",
+ "comment": "Generate Program Database File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "StripPrivateSymbols",
+ "switch": "PDBSTRIPPED:",
+ "comment": "Strip Private Symbols",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MapFileName",
+ "switch": "MAP:",
+ "comment": "Map File Name",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "HeapReserveSize",
+ "switch": "HEAP:",
+ "comment": "Heap Reserve Size",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "HeapCommitSize",
+ "switch": "HEAP",
+ "comment": "Heap Commit Size",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "StackReserveSize",
+ "switch": "STACK:",
+ "comment": "Stack Reserve Size",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "StackCommitSize",
+ "switch": "STACK",
+ "comment": "Stack Commit Size",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "FunctionOrder",
+ "switch": "ORDER:@",
+ "comment": "Function Order",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProfileGuidedDatabase",
+ "switch": "PGD:",
+ "comment": "Profile Guided Database",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MidlCommandFile",
+ "switch": "MIDL:@",
+ "comment": "MIDL Commands",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MergedIDLBaseFileName",
+ "switch": "IDLOUT:",
+ "comment": "Merged IDL Base File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "TypeLibraryFile",
+ "switch": "TLBOUT:",
+ "comment": "Type Library",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataFile",
+ "switch": "WINMDFILE:",
+ "comment": "Windows Metadata File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataLinkKeyFile",
+ "switch": "WINMDKEYFILE:",
+ "comment": "Windows Metadata Key File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataKeyContainer",
+ "switch": "WINMDKEYCONTAINER:",
+ "comment": "Windows Metadata Key Container",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "EntryPointSymbol",
+ "switch": "ENTRY:",
+ "comment": "Entry Point",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "BaseAddress",
+ "switch": "BASE:",
+ "comment": "Base Address",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ImportLibrary",
+ "switch": "IMPLIB:",
+ "comment": "Import Library",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MergeSections",
+ "switch": "MERGE:",
+ "comment": "Merge Sections",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "LinkKeyFile",
+ "switch": "KEYFILE:",
+ "comment": "Key File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "KeyContainer",
+ "switch": "KEYCONTAINER:",
+ "comment": "Key Container",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "TypeLibraryResourceID",
+ "switch": "TLBID:",
+ "comment": "TypeLib Resource ID",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "SectionAlignment",
+ "switch": "ALIGN:",
+ "comment": "SectionAlignment",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v142_CL.json b/Templates/MSBuild/FlagTables/v142_CL.json
new file mode 100644
index 0000000..7c2d291
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v142_CL.json
@@ -0,0 +1,1226 @@
+[
+ {
+ "name": "DebugInformationFormat",
+ "switch": "",
+ "comment": "None",
+ "value": "None",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "Z7",
+ "comment": "C7 compatible",
+ "value": "OldStyle",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "Zi",
+ "comment": "Program Database",
+ "value": "ProgramDatabase",
+ "flags": []
+ },
+ {
+ "name": "DebugInformationFormat",
+ "switch": "ZI",
+ "comment": "Program Database for Edit And Continue",
+ "value": "EditAndContinue",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "",
+ "comment": "No Common Language RunTime Support",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr",
+ "comment": "Common Language RunTime Support",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:pure",
+ "comment": "Pure MSIL Common Language RunTime Support",
+ "value": "Pure",
+ "flags": []
+ },
+ {
+ "name": "CompileAsManaged",
+ "switch": "clr:safe",
+ "comment": "Safe MSIL Common Language RunTime Support",
+ "value": "Safe",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W0",
+ "comment": "Turn Off All Warnings",
+ "value": "TurnOffAllWarnings",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W1",
+ "comment": "Level1",
+ "value": "Level1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W2",
+ "comment": "Level2",
+ "value": "Level2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W3",
+ "comment": "Level3",
+ "value": "Level3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W4",
+ "comment": "Level4",
+ "value": "Level4",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "Wall",
+ "comment": "EnableAllWarnings",
+ "value": "EnableAllWarnings",
+ "flags": []
+ },
+ {
+ "name": "DiagnosticsFormat",
+ "switch": "diagnostics:caret",
+ "comment": "Caret",
+ "value": "Caret",
+ "flags": []
+ },
+ {
+ "name": "DiagnosticsFormat",
+ "switch": "diagnostics:column",
+ "comment": "Column Info",
+ "value": "Column",
+ "flags": []
+ },
+ {
+ "name": "DiagnosticsFormat",
+ "switch": "diagnostics:classic",
+ "comment": "Classic",
+ "value": "Classic",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "",
+ "comment": "Custom",
+ "value": "Custom",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "Od",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "O1",
+ "comment": "Maximum Optimization (Favor Size)",
+ "value": "MinSpace",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "O2",
+ "comment": "Maximum Optimization (Favor Speed)",
+ "value": "MaxSpeed",
+ "flags": []
+ },
+ {
+ "name": "Optimization",
+ "switch": "Ox",
+ "comment": "Optimizations (Favor Speed)",
+ "value": "Full",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob0",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob1",
+ "comment": "Only __inline",
+ "value": "OnlyExplicitInline",
+ "flags": []
+ },
+ {
+ "name": "InlineFunctionExpansion",
+ "switch": "Ob2",
+ "comment": "Any Suitable",
+ "value": "AnySuitable",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "Os",
+ "comment": "Favor small code",
+ "value": "Size",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "Ot",
+ "comment": "Favor fast code",
+ "value": "Speed",
+ "flags": []
+ },
+ {
+ "name": "FavorSizeOrSpeed",
+ "switch": "",
+ "comment": "Neither",
+ "value": "Neither",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHa",
+ "comment": "Yes with SEH Exceptions",
+ "value": "Async",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHsc",
+ "comment": "Yes",
+ "value": "Sync",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "EHs",
+ "comment": "Yes with Extern C functions",
+ "value": "SyncCThrow",
+ "flags": []
+ },
+ {
+ "name": "ExceptionHandling",
+ "switch": "",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTCs",
+ "comment": "Stack Frames",
+ "value": "StackFrameRuntimeCheck",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTCu",
+ "comment": "Uninitialized variables",
+ "value": "UninitializedLocalUsageCheck",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "RTC1",
+ "comment": "Both (/RTC1, equiv. to /RTCsu)",
+ "value": "EnableFastChecks",
+ "flags": []
+ },
+ {
+ "name": "BasicRuntimeChecks",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MT",
+ "comment": "Multi-threaded",
+ "value": "MultiThreaded",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MTd",
+ "comment": "Multi-threaded Debug",
+ "value": "MultiThreadedDebug",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MD",
+ "comment": "Multi-threaded DLL",
+ "value": "MultiThreadedDLL",
+ "flags": []
+ },
+ {
+ "name": "RuntimeLibrary",
+ "switch": "MDd",
+ "comment": "Multi-threaded Debug DLL",
+ "value": "MultiThreadedDebugDLL",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp1",
+ "comment": "1 Byte",
+ "value": "1Byte",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp2",
+ "comment": "2 Bytes",
+ "value": "2Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp4",
+ "comment": "4 Byte",
+ "value": "4Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp8",
+ "comment": "8 Bytes",
+ "value": "8Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "Zp16",
+ "comment": "16 Bytes",
+ "value": "16Bytes",
+ "flags": []
+ },
+ {
+ "name": "StructMemberAlignment",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "BufferSecurityCheck",
+ "switch": "GS-",
+ "comment": "Disable Security Check",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "BufferSecurityCheck",
+ "switch": "GS",
+ "comment": "Enable Security Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ControlFlowGuard",
+ "switch": "guard:cf",
+ "comment": "Yes",
+ "value": "Guard",
+ "flags": []
+ },
+ {
+ "name": "ControlFlowGuard",
+ "switch": "",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:SSE",
+ "comment": "Streaming SIMD Extensions",
+ "value": "StreamingSIMDExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:SSE2",
+ "comment": "Streaming SIMD Extensions 2",
+ "value": "StreamingSIMDExtensions2",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:AVX",
+ "comment": "Advanced Vector Extensions",
+ "value": "AdvancedVectorExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:AVX2",
+ "comment": "Advanced Vector Extensions 2",
+ "value": "AdvancedVectorExtensions2",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "arch:IA32",
+ "comment": "No Enhanced Instructions",
+ "value": "NoExtensions",
+ "flags": []
+ },
+ {
+ "name": "EnableEnhancedInstructionSet",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:precise",
+ "comment": "Precise",
+ "value": "Precise",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:strict",
+ "comment": "Strict",
+ "value": "Strict",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointModel",
+ "switch": "fp:fast",
+ "comment": "Fast",
+ "value": "Fast",
+ "flags": []
+ },
+ {
+ "name": "SpectreMitigation",
+ "switch": "Qspectre-",
+ "comment": "Spectre mitigations disabled",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "SpectreMitigation",
+ "switch": "Qspectre",
+ "comment": "Spectre mitigations enabled",
+ "value": "Spectre",
+ "flags": []
+ },
+ {
+ "name": "LanguageStandard",
+ "switch": "std:c++14",
+ "comment": "ISO C++14 Standard",
+ "value": "stdcpp14",
+ "flags": []
+ },
+ {
+ "name": "LanguageStandard",
+ "switch": "std:c++17",
+ "comment": "ISO C++17 Standard",
+ "value": "stdcpp17",
+ "flags": []
+ },
+ {
+ "name": "LanguageStandard",
+ "switch": "std:c++latest",
+ "comment": "Preview - Features from the Latest C++ Working Draft",
+ "value": "stdcpplatest",
+ "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",
+ "value": "Create",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Yu",
+ "comment": "Use",
+ "value": "Use",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeader",
+ "switch": "Y-",
+ "comment": "Not Using Precompiled Headers",
+ "value": "NotUsing",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "",
+ "comment": "No Listing",
+ "value": "NoListing",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FA",
+ "comment": "Assembly-Only Listing",
+ "value": "AssemblyCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAc",
+ "comment": "Assembly With Machine Code",
+ "value": "AssemblyAndMachineCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAs",
+ "comment": "Assembly With Source Code",
+ "value": "AssemblyAndSourceCode",
+ "flags": []
+ },
+ {
+ "name": "AssemblerOutput",
+ "switch": "FAcs",
+ "comment": "Assembly, Machine Code and Source",
+ "value": "All",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gd",
+ "comment": "__cdecl",
+ "value": "Cdecl",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gr",
+ "comment": "__fastcall",
+ "value": "FastCall",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gz",
+ "comment": "__stdcall",
+ "value": "StdCall",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gv",
+ "comment": "__vectorcall",
+ "value": "VectorCall",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "TC",
+ "comment": "Compile as C Code",
+ "value": "CompileAsC",
+ "flags": []
+ },
+ {
+ "name": "CompileAs",
+ "switch": "TP",
+ "comment": "Compile as C++ Code",
+ "value": "CompileAsCpp",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:none",
+ "comment": "Do Not Send Report",
+ "value": "None",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:prompt",
+ "comment": "Prompt Immediately",
+ "value": "Prompt",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:queue",
+ "comment": "Queue For Next Login",
+ "value": "Queue",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:send",
+ "comment": "Send Automatically",
+ "value": "Send",
+ "flags": []
+ },
+ {
+ "name": "SupportJustMyCode",
+ "switch": "JMC-",
+ "comment": "Support Just My Code Debugging",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "SupportJustMyCode",
+ "switch": "JMC",
+ "comment": "Support Just My Code Debugging",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CompileAsWinRT",
+ "switch": "ZW",
+ "comment": "Consume Windows Runtime Extension",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WinRTNoStdLib",
+ "switch": "ZW:nostdlib",
+ "comment": "No Standard WinRT Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "nologo",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningAsError",
+ "switch": "WX-",
+ "comment": "Treat Warnings As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningAsError",
+ "switch": "WX",
+ "comment": "Treat Warnings As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SDLCheck",
+ "switch": "sdl-",
+ "comment": "SDL checks",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "SDLCheck",
+ "switch": "sdl",
+ "comment": "SDL checks",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MultiProcessorCompilation",
+ "switch": "MP",
+ "comment": "Multi-processor Compilation",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "IntrinsicFunctions",
+ "switch": "Oi",
+ "comment": "Enable Intrinsic Functions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OmitFramePointers",
+ "switch": "Oy-",
+ "comment": "Omit Frame Pointers",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OmitFramePointers",
+ "switch": "Oy",
+ "comment": "Omit Frame Pointers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableFiberSafeOptimizations",
+ "switch": "GT",
+ "comment": "Enable Fiber-Safe Optimizations",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WholeProgramOptimization",
+ "switch": "GL",
+ "comment": "Whole Program Optimization",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UndefineAllPreprocessorDefinitions",
+ "switch": "u",
+ "comment": "Undefine All Preprocessor Definitions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreStandardIncludePath",
+ "switch": "X",
+ "comment": "Ignore Standard Include Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessToFile",
+ "switch": "P",
+ "comment": "Preprocess to a File",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessSuppressLineNumbers",
+ "switch": "EP",
+ "comment": "Preprocess Suppress Line Numbers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessKeepComments",
+ "switch": "C",
+ "comment": "Keep Comments",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "StringPooling",
+ "switch": "GF-",
+ "comment": "Enable String Pooling",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "StringPooling",
+ "switch": "GF",
+ "comment": "Enable String Pooling",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MinimalRebuild",
+ "switch": "Gm-",
+ "comment": "Enable Minimal Rebuild",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "MinimalRebuild",
+ "switch": "Gm",
+ "comment": "Enable Minimal Rebuild",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SmallerTypeCheck",
+ "switch": "RTCc",
+ "comment": "Smaller Type Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FunctionLevelLinking",
+ "switch": "Gy-",
+ "comment": "Enable Function-Level Linking",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FunctionLevelLinking",
+ "switch": "Gy",
+ "comment": "Enable Function-Level Linking",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableParallelCodeGeneration",
+ "switch": "Qpar-",
+ "comment": "Enable Parallel Code Generation",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnableParallelCodeGeneration",
+ "switch": "Qpar",
+ "comment": "Enable Parallel Code Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointExceptions",
+ "switch": "fp:except-",
+ "comment": "Enable Floating Point Exceptions",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FloatingPointExceptions",
+ "switch": "fp:except",
+ "comment": "Enable Floating Point Exceptions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CreateHotpatchableImage",
+ "switch": "hotpatch",
+ "comment": "Create Hotpatchable Image",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DisableLanguageExtensions",
+ "switch": "Za",
+ "comment": "Disable Language Extensions",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ConformanceMode",
+ "switch": "permissive-",
+ "comment": "Conformance mode enabled",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ConformanceMode",
+ "switch": "permissive",
+ "comment": "Conformance mode disabled",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWChar_tAsBuiltInType",
+ "switch": "Zc:wchar_t-",
+ "comment": "Treat WChar_t As Built in Type",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWChar_tAsBuiltInType",
+ "switch": "Zc:wchar_t",
+ "comment": "Treat WChar_t As Built in Type",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ForceConformanceInForLoopScope",
+ "switch": "Zc:forScope-",
+ "comment": "Force Conformance in For Loop Scope",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "ForceConformanceInForLoopScope",
+ "switch": "Zc:forScope",
+ "comment": "Force Conformance in For Loop Scope",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RemoveUnreferencedCodeData",
+ "switch": "Zc:inline-",
+ "comment": "Remove unreferenced code and data",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RemoveUnreferencedCodeData",
+ "switch": "Zc:inline",
+ "comment": "Remove unreferenced code and data",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnforceTypeConversionRules",
+ "switch": "Zc:rvalueCast-",
+ "comment": "Enforce type conversion rules",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnforceTypeConversionRules",
+ "switch": "Zc:rvalueCast",
+ "comment": "Enforce type conversion rules",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RuntimeTypeInfo",
+ "switch": "GR-",
+ "comment": "Enable Run-Time Type Information",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RuntimeTypeInfo",
+ "switch": "GR",
+ "comment": "Enable Run-Time Type Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OpenMPSupport",
+ "switch": "openmp-",
+ "comment": "Open MP Support",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OpenMPSupport",
+ "switch": "openmp",
+ "comment": "Open MP Support",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableModules",
+ "switch": "experimental:module",
+ "comment": "Enable C++ Modules (experimental)",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ExpandAttributedSource",
+ "switch": "Fx",
+ "comment": "Expand Attributed Source",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseUnicodeForAssemblerListing",
+ "switch": "FAu",
+ "comment": "Use Unicode For Assembler Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateXMLDocumentationFiles",
+ "switch": "doc",
+ "comment": "Generate XML Documentation Files",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "BrowseInformation",
+ "switch": "FR",
+ "comment": "Enable Browse Information",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "ShowIncludes",
+ "switch": "showIncludes",
+ "comment": "Show Includes",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnablePREfast",
+ "switch": "analyze-",
+ "comment": "Enable Code Analysis",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnablePREfast",
+ "switch": "analyze",
+ "comment": "Enable Code Analysis",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseFullPaths",
+ "switch": "FC",
+ "comment": "Use Full Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OmitDefaultLibName",
+ "switch": "Zl",
+ "comment": "Omit Default Library Name",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalIncludeDirectories",
+ "switch": "I",
+ "comment": "Additional Include Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalUsingDirectories",
+ "switch": "AI",
+ "comment": "Additional #using Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "UndefinePreprocessorDefinitions",
+ "switch": "U",
+ "comment": "Undefine Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "DisableSpecificWarnings",
+ "switch": "wd",
+ "comment": "Disable Specific Warnings",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForcedIncludeFiles",
+ "switch": "FI",
+ "comment": "Forced Include File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForcedUsingFiles",
+ "switch": "FU",
+ "comment": "Forced #using File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "PREfastLog",
+ "switch": "analyze:log",
+ "comment": "Code Analysis Log",
+ "value": "",
+ "flags": [
+ "UserFollowing"
+ ]
+ },
+ {
+ "name": "PREfastAdditionalPlugins",
+ "switch": "analyze:plugin",
+ "comment": "Additional Code Analysis Native plugins",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "TreatSpecificWarningsAsErrors",
+ "switch": "we",
+ "comment": "Treat Specific Warnings As Errors",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "WarningVersion",
+ "switch": "Wv:",
+ "comment": "Warning Version",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "PreprocessOutputPath",
+ "switch": "Fi",
+ "comment": "Preprocess Output Path",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderFile",
+ "switch": "Yu",
+ "comment": "Precompiled Header File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderFile",
+ "switch": "Yc",
+ "comment": "Precompiled Header File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "PrecompiledHeaderOutputFile",
+ "switch": "Fp",
+ "comment": "Precompiled Header Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "AssemblerListingLocation",
+ "switch": "Fa",
+ "comment": "ASM List Location",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ObjectFileName",
+ "switch": "Fo",
+ "comment": "Object File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProgramDataBaseFileName",
+ "switch": "Fd",
+ "comment": "Program Database File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "XMLDocumentationFileName",
+ "switch": "doc",
+ "comment": "XML Documentation File Name",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "BrowseInformationFile",
+ "switch": "FR",
+ "comment": "Browse Information File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ProcessorNumber",
+ "switch": "MP",
+ "comment": "Number of processors",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v142_CSharp.json b/Templates/MSBuild/FlagTables/v142_CSharp.json
new file mode 100644
index 0000000..4dcea9d
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v142_CSharp.json
@@ -0,0 +1,592 @@
+[
+ {
+ "name": "ProjectName",
+ "switch": "out:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:exe",
+ "comment": "",
+ "value": "Exe",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:winexe",
+ "comment": "",
+ "value": "Winexe",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:library",
+ "comment": "",
+ "value": "Library",
+ "flags": []
+ },
+ {
+ "name": "OutputType",
+ "switch": "target:module",
+ "comment": "",
+ "value": "Module",
+ "flags": []
+ },
+ {
+ "name": "DocumentationFile",
+ "switch": "doc",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:x86",
+ "comment": "",
+ "value": "x86",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:Itanium",
+ "comment": "",
+ "value": "Itanium",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:x64",
+ "comment": "",
+ "value": "x64",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:arm",
+ "comment": "",
+ "value": "arm",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:anycpu32bitpreferred",
+ "comment": "",
+ "value": "anycpu32bitpreferred",
+ "flags": []
+ },
+ {
+ "name": "Platform",
+ "switch": "platform:anycpu",
+ "comment": "",
+ "value": "anycpu",
+ "flags": []
+ },
+ {
+ "name": "References",
+ "switch": "reference:",
+ "comment": "mit alias",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "References",
+ "switch": "reference:",
+ "comment": "dateiliste",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "AddModules",
+ "switch": "addmodule:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "Win32Resource",
+ "switch": "win32res:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ApplicationIcon",
+ "switch": "win32icon:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "ApplicationManifest",
+ "switch": "win32manifest:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "NoWin32Manifest",
+ "switch": "nowin32manifest",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DefineDebug",
+ "switch": "debug",
+ "comment": "",
+ "value": "true",
+ "flags": [
+ "Continue"
+ ]
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DebugSymbols",
+ "switch": "debug+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:none",
+ "comment": "",
+ "value": "none",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:full",
+ "comment": "",
+ "value": "full",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:pdbonly",
+ "comment": "",
+ "value": "pdbonly",
+ "flags": []
+ },
+ {
+ "name": "DebugType",
+ "switch": "debug:portable",
+ "comment": "",
+ "value": "portable",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "Optimize",
+ "switch": "optimize+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "warnaserror+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror-",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror+",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "WarningsAsErrors",
+ "switch": "warnaserror:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired",
+ "CommaAppendable"
+ ]
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:0",
+ "comment": "",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:1",
+ "comment": "",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:2",
+ "comment": "",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:3",
+ "comment": "",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "warn:4",
+ "comment": "",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "NoWarn",
+ "switch": "nowarn:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired",
+ "CommaAppendable"
+ ]
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CheckForOverflowUnderflow",
+ "switch": "checked+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AllowUnsafeBlocks",
+ "switch": "unsafe+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DefineConstants",
+ "switch": "define:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "SemicolonAppendable",
+ "UserValue"
+ ]
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:ISO-1",
+ "comment": "",
+ "value": "ISO-1",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:ISO-2",
+ "comment": "",
+ "value": "ISO-2",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:3",
+ "comment": "",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:4",
+ "comment": "",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:5",
+ "comment": "",
+ "value": "5",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:6",
+ "comment": "",
+ "value": "6",
+ "flags": []
+ },
+ {
+ "name": "LangVersion",
+ "switch": "langversion:default",
+ "comment": "",
+ "value": "default",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DelaySign",
+ "switch": "delaysign+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AssemblyOriginatorKeyFile",
+ "switch": "keyfile",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "KeyContainerName",
+ "switch": "keycontainer",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoLogo",
+ "switch": "nologo",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoConfig",
+ "switch": "noconfig",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "BaseAddress",
+ "switch": "baseaddress:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "CodePage",
+ "switch": "codepage",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "Utf8Output",
+ "switch": "utf8output",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "MainEntryPoint",
+ "switch": "main:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "GenerateFullPaths",
+ "switch": "fullpaths",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FileAlignment",
+ "switch": "filealign",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "PdbFile",
+ "switch": "pdb:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib-",
+ "comment": "",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "NoStandardLib",
+ "switch": "nostdlib+",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SubsystemVersion",
+ "switch": "subsystemversion",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibPaths",
+ "switch": "lib:",
+ "comment": "",
+ "value": "",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:none",
+ "comment": "Do Not Send Report",
+ "value": "none",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:prompt",
+ "comment": "Prompt Immediately",
+ "value": "prompt",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:queue",
+ "comment": "Queue For Next Login",
+ "value": "queue",
+ "flags": []
+ },
+ {
+ "name": "ErrorReport",
+ "switch": "errorreport:send",
+ "comment": "Send Automatically",
+ "value": "send",
+ "flags": []
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v142_Link.json b/Templates/MSBuild/FlagTables/v142_Link.json
new file mode 100644
index 0000000..110dcc2
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v142_Link.json
@@ -0,0 +1,1330 @@
+[
+ {
+ "name": "ShowProgress",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE",
+ "comment": "Display all progress messages",
+ "value": "LinkVerbose",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:Lib",
+ "comment": "For Libraries Searched",
+ "value": "LinkVerboseLib",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:ICF",
+ "comment": "About COMDAT folding during optimized linking",
+ "value": "LinkVerboseICF",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:REF",
+ "comment": "About data removed during optimized linking",
+ "value": "LinkVerboseREF",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:SAFESEH",
+ "comment": "About Modules incompatible with SEH",
+ "value": "LinkVerboseSAFESEH",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "VERBOSE:CLR",
+ "comment": "About linker activity related to managed code",
+ "value": "LinkVerboseCLR",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE:MULTIPLE",
+ "comment": "Multiply Defined Symbol Only",
+ "value": "MultiplyDefinedSymbolOnly",
+ "flags": []
+ },
+ {
+ "name": "ForceFileOutput",
+ "switch": "FORCE:UNRESOLVED",
+ "comment": "Undefined Symbol Only",
+ "value": "UndefinedSymbolOnly",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:5",
+ "comment": "X86 Image Only",
+ "value": "X86Image",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:6",
+ "comment": "X64 Image Only",
+ "value": "X64Image",
+ "flags": []
+ },
+ {
+ "name": "CreateHotPatchableImage",
+ "switch": "FUNCTIONPADMIN:16",
+ "comment": "Itanium Image Only",
+ "value": "ItaniumImage",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='asInvoker'",
+ "comment": "asInvoker",
+ "value": "AsInvoker",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='highestAvailable'",
+ "comment": "highestAvailable",
+ "value": "HighestAvailable",
+ "flags": []
+ },
+ {
+ "name": "UACExecutionLevel",
+ "switch": "level='requireAdministrator'",
+ "comment": "requireAdministrator",
+ "value": "RequireAdministrator",
+ "flags": []
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG",
+ "comment": "Generate Debug Information",
+ "value": "true",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG:FASTLINK",
+ "comment": "Generate Debug Information optimized for faster links",
+ "value": "DebugFastLink",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG:FULL",
+ "comment": "Generate Debug Information optimized for sharing and publishing",
+ "value": "DebugFull",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "DEBUG:NONE",
+ "comment": "Produces no debugging information",
+ "value": "false",
+ "flags": [
+ "CaseInsensitive"
+ ]
+ },
+ {
+ "name": "SubSystem",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:CONSOLE",
+ "comment": "Console",
+ "value": "Console",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWS",
+ "comment": "Windows",
+ "value": "Windows",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:NATIVE",
+ "comment": "Native",
+ "value": "Native",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_APPLICATION",
+ "comment": "EFI Application",
+ "value": "EFI Application",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "comment": "EFI Boot Service Driver",
+ "value": "EFI Boot Service Driver",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_ROM",
+ "comment": "EFI ROM",
+ "value": "EFI ROM",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_RUNTIME_DRIVER",
+ "comment": "EFI Runtime",
+ "value": "EFI Runtime",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:POSIX",
+ "comment": "POSIX",
+ "value": "POSIX",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "Driver",
+ "comment": "Driver",
+ "value": "Driver",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "DRIVER:UPONLY",
+ "comment": "UP Only",
+ "value": "UpOnly",
+ "flags": []
+ },
+ {
+ "name": "Driver",
+ "switch": "DRIVER:WDM",
+ "comment": "WDM",
+ "value": "WDM",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "",
+ "comment": "Default",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:incremental",
+ "comment": "Use Fast Link Time Code Generation",
+ "value": "UseFastLinkTimeCodeGeneration",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG",
+ "comment": "Use Link Time Code Generation",
+ "value": "UseLinkTimeCodeGeneration",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGInstrument",
+ "comment": "Profile Guided Optimization - Instrument",
+ "value": "PGInstrument",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGOptimize",
+ "comment": "Profile Guided Optimization - Optimization",
+ "value": "PGOptimization",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG:PGUpdate",
+ "comment": "Profile Guided Optimization - Update",
+ "value": "PGUpdate",
+ "flags": []
+ },
+ {
+ "name": "GenerateWindowsMetadata",
+ "switch": "WINMD",
+ "comment": "Yes",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateWindowsMetadata",
+ "switch": "WINMD:NO",
+ "comment": "No",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA1",
+ "comment": "SHA1",
+ "value": "SHA1",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA256",
+ "comment": "SHA256",
+ "value": "SHA256",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA384",
+ "comment": "SHA384",
+ "value": "SHA384",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataSignHash",
+ "switch": "WINMDSIGNHASH:SHA512",
+ "comment": "SHA512",
+ "value": "SHA512",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "",
+ "comment": "Not Set",
+ "value": "NotSet",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM",
+ "comment": "MachineARM",
+ "value": "MachineARM",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM64",
+ "comment": "MachineARM64",
+ "value": "MachineARM64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM64EC",
+ "comment": "MachineARM64EC",
+ "value": "MachineARM64EC",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:EBC",
+ "comment": "MachineEBC",
+ "value": "MachineEBC",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:IA64",
+ "comment": "MachineIA64",
+ "value": "MachineIA64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS",
+ "comment": "MachineMIPS",
+ "value": "MachineMIPS",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS16",
+ "comment": "MachineMIPS16",
+ "value": "MachineMIPS16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU",
+ "comment": "MachineMIPSFPU",
+ "value": "MachineMIPSFPU",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU16",
+ "comment": "MachineMIPSFPU16",
+ "value": "MachineMIPSFPU16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:SH4",
+ "comment": "MachineSH4",
+ "value": "MachineSH4",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:THUMB",
+ "comment": "MachineTHUMB",
+ "value": "MachineTHUMB",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X64",
+ "comment": "MachineX64",
+ "value": "MachineX64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X86",
+ "comment": "MachineX86",
+ "value": "MachineX86",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:MTA",
+ "comment": "MTA threading attribute",
+ "value": "MTAThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:STA",
+ "comment": "STA threading attribute",
+ "value": "STAThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRThreadAttribute",
+ "switch": "CLRTHREADATTRIBUTE:NONE",
+ "comment": "Default threading attribute",
+ "value": "DefaultThreadingAttribute",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:IJW",
+ "comment": "Force IJW image",
+ "value": "ForceIJWImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:PURE",
+ "comment": "Force Pure IL Image",
+ "value": "ForcePureILImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "CLRIMAGETYPE:SAFE",
+ "comment": "Force Safe IL Image",
+ "value": "ForceSafeILImage",
+ "flags": []
+ },
+ {
+ "name": "CLRImageType",
+ "switch": "",
+ "comment": "Default image type",
+ "value": "Default",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA1",
+ "comment": "SHA1",
+ "value": "SHA1",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA256",
+ "comment": "SHA256",
+ "value": "SHA256",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA384",
+ "comment": "SHA384",
+ "value": "SHA384",
+ "flags": []
+ },
+ {
+ "name": "SignHash",
+ "switch": "CLRSIGNHASH:SHA512",
+ "comment": "SHA512",
+ "value": "SHA512",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:PROMPT",
+ "comment": "PromptImmediately",
+ "value": "PromptImmediately",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:QUEUE",
+ "comment": "Queue For Next Login",
+ "value": "QueueForNextLogin",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:SEND",
+ "comment": "Send Error Report",
+ "value": "SendErrorReport",
+ "flags": []
+ },
+ {
+ "name": "LinkErrorReporting",
+ "switch": "ERRORREPORT:NONE",
+ "comment": "No Error Report",
+ "value": "NoErrorReport",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError",
+ "comment": "Enabled",
+ "value": "Enabled",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError:NO",
+ "comment": "Disabled",
+ "value": "Disabled",
+ "flags": []
+ },
+ {
+ "name": "CLRSupportLastError",
+ "switch": "CLRSupportLastError:SYSTEMDLL",
+ "comment": "System Dlls Only",
+ "value": "SystemDlls",
+ "flags": []
+ },
+ {
+ "name": "LinkIncremental",
+ "switch": "INCREMENTAL:NO",
+ "comment": "Enable Incremental Linking",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkIncremental",
+ "switch": "INCREMENTAL",
+ "comment": "Enable Incremental Linking",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "NOLOGO",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkStatus",
+ "switch": "LTCG:NOSTATUS",
+ "comment": "Link Status",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkStatus",
+ "switch": "LTCG:STATUS",
+ "comment": "Link Status",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreventDllBinding",
+ "switch": "ALLOWBIND:NO",
+ "comment": "Prevent Dll Binding",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "PreventDllBinding",
+ "switch": "ALLOWBIND",
+ "comment": "Prevent Dll Binding",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatLinkerWarningAsErrors",
+ "switch": "WX:NO",
+ "comment": "Treat Linker Warning As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatLinkerWarningAsErrors",
+ "switch": "WX",
+ "comment": "Treat Linker Warning As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreAllDefaultLibraries",
+ "switch": "NODEFAULTLIB",
+ "comment": "Ignore All Default Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateManifest",
+ "switch": "MANIFEST:NO",
+ "comment": "Generate Manifest",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "GenerateManifest",
+ "switch": "MANIFEST",
+ "comment": "Generate Manifest",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AllowIsolation",
+ "switch": "ALLOWISOLATION:NO",
+ "comment": "Allow Isolation",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AllowIsolation",
+ "switch": "",
+ "comment": "Allow Isolation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableUAC",
+ "switch": "MANIFESTUAC:",
+ "comment": "",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired",
+ "SpaceAppendable"
+ ]
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='false'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "false",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='false'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "UACUIAccess",
+ "switch": "uiAccess='true'",
+ "comment": "UAC Bypass UI Protection",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ManifestEmbed",
+ "switch": "manifest:embed",
+ "comment": "Embed Manifest",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateMapFile",
+ "switch": "MAP",
+ "comment": "Generate Map File",
+ "value": "true",
+ "flags": [
+ "UserValue",
+ "UserIgnored",
+ "Continue"
+ ]
+ },
+ {
+ "name": "MapExports",
+ "switch": "MAPINFO:EXPORTS",
+ "comment": "Map Exports",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AssemblyDebug",
+ "switch": "ASSEMBLYDEBUG:DISABLE",
+ "comment": "Debuggable Assembly",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "AssemblyDebug",
+ "switch": "ASSEMBLYDEBUG",
+ "comment": "Debuggable Assembly",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LargeAddressAware",
+ "switch": "LARGEADDRESSAWARE:NO",
+ "comment": "Enable Large Addresses",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LargeAddressAware",
+ "switch": "LARGEADDRESSAWARE",
+ "comment": "Enable Large Addresses",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TerminalServerAware",
+ "switch": "TSAWARE:NO",
+ "comment": "Terminal Server",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TerminalServerAware",
+ "switch": "TSAWARE",
+ "comment": "Terminal Server",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SwapRunFromCD",
+ "switch": "SWAPRUN:CD",
+ "comment": "Swap Run From CD",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SwapRunFromNET",
+ "switch": "SWAPRUN:NET",
+ "comment": "Swap Run From Network",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "OptimizeReferences",
+ "switch": "OPT:NOREF",
+ "comment": "References",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "OptimizeReferences",
+ "switch": "OPT:REF",
+ "comment": "References",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableCOMDATFolding",
+ "switch": "OPT:NOICF",
+ "comment": "Enable COMDAT Folding",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "EnableCOMDATFolding",
+ "switch": "OPT:ICF",
+ "comment": "Enable COMDAT Folding",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreEmbeddedIDL",
+ "switch": "IGNOREIDL",
+ "comment": "Ignore Embedded IDL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AppContainer",
+ "switch": "APPCONTAINER",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataLinkDelaySign",
+ "switch": "WINMDDELAYSIGN:NO",
+ "comment": "Windows Metadata Delay Sign",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "WindowsMetadataLinkDelaySign",
+ "switch": "WINMDDELAYSIGN",
+ "comment": "Windows Metadata Delay Sign",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NoEntryPoint",
+ "switch": "NOENTRY",
+ "comment": "No Entry Point",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SetChecksum",
+ "switch": "RELEASE",
+ "comment": "Set Checksum",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "RandomizedBaseAddress",
+ "switch": "DYNAMICBASE:NO",
+ "comment": "Randomized Base Address",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "RandomizedBaseAddress",
+ "switch": "DYNAMICBASE",
+ "comment": "Randomized Base Address",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "FixedBaseAddress",
+ "switch": "FIXED:NO",
+ "comment": "Fixed Base Address",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "FixedBaseAddress",
+ "switch": "FIXED",
+ "comment": "Fixed Base Address",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DataExecutionPrevention",
+ "switch": "NXCOMPAT:NO",
+ "comment": "Data Execution Prevention (DEP)",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "DataExecutionPrevention",
+ "switch": "NXCOMPAT",
+ "comment": "Data Execution Prevention (DEP)",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TurnOffAssemblyGeneration",
+ "switch": "NOASSEMBLY",
+ "comment": "Turn Off Assembly Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SupportUnloadOfDelayLoadedDLL",
+ "switch": "DELAY:UNLOAD",
+ "comment": "Unload delay loaded DLL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SupportNobindOfDelayLoadedDLL",
+ "switch": "DELAY:NOBIND",
+ "comment": "Nobind delay loaded DLL",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Profile",
+ "switch": "PROFILE",
+ "comment": "Profile",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkDelaySign",
+ "switch": "DELAYSIGN:NO",
+ "comment": "Delay Sign",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "LinkDelaySign",
+ "switch": "DELAYSIGN",
+ "comment": "Delay Sign",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CLRUnmanagedCodeCheck",
+ "switch": "CLRUNMANAGEDCODECHECK:NO",
+ "comment": "CLR Unmanaged Code Check",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "CLRUnmanagedCodeCheck",
+ "switch": "CLRUNMANAGEDCODECHECK",
+ "comment": "CLR Unmanaged Code Check",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DetectOneDefinitionRule",
+ "switch": "ODR",
+ "comment": "Detect One Definition Rule violations",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ImageHasSafeExceptionHandlers",
+ "switch": "SAFESEH:NO",
+ "comment": "Image Has Safe Exception Handlers",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "ImageHasSafeExceptionHandlers",
+ "switch": "SAFESEH",
+ "comment": "Image Has Safe Exception Handlers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkDLL",
+ "switch": "DLL",
+ "comment": "",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibraryDirectories",
+ "switch": "LIBPATH:",
+ "comment": "Additional Library Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "Natvis",
+ "switch": "NATVIS:",
+ "comment": "Natvis files",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IgnoreSpecificDefaultLibraries",
+ "switch": "NODEFAULTLIB:",
+ "comment": "Ignore Specific Default Libraries",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AddModuleNamesToAssembly",
+ "switch": "ASSEMBLYMODULE:",
+ "comment": "Add Module to Assembly",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "EmbedManagedResourceFile",
+ "switch": "ASSEMBLYRESOURCE:",
+ "comment": "Embed Managed Resource File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ForceSymbolReferences",
+ "switch": "INCLUDE:",
+ "comment": "Force Symbol References",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "DelayLoadDLLs",
+ "switch": "DELAYLOAD:",
+ "comment": "Delay Loaded Dlls",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AssemblyLinkResource",
+ "switch": "ASSEMBLYLINKRESOURCE:",
+ "comment": "Assembly Link Resource",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalManifestDependencies",
+ "switch": "MANIFESTDEPENDENCY:",
+ "comment": "Additional Manifest Dependencies",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ManifestInput",
+ "switch": "manifestinput:",
+ "comment": "Manifest Input",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "OutputFile",
+ "switch": "OUT:",
+ "comment": "Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "Version",
+ "switch": "VERSION:",
+ "comment": "Version",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "SpecifySectionAttributes",
+ "switch": "SECTION:",
+ "comment": "Specify Section Attributes",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MSDOSStubFileName",
+ "switch": "STUB:",
+ "comment": "MS-DOS Stub File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ModuleDefinitionFile",
+ "switch": "DEF:",
+ "comment": "Module Definition File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ManifestFile",
+ "switch": "ManifestFile:",
+ "comment": "Manifest File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProgramDatabaseFile",
+ "switch": "PDB:",
+ "comment": "Generate Program Database File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "StripPrivateSymbols",
+ "switch": "PDBSTRIPPED:",
+ "comment": "Strip Private Symbols",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MapFileName",
+ "switch": "MAP:",
+ "comment": "Map File Name",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "HeapReserveSize",
+ "switch": "HEAP:",
+ "comment": "Heap Reserve Size",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "HeapCommitSize",
+ "switch": "HEAP",
+ "comment": "Heap Commit Size",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "StackReserveSize",
+ "switch": "STACK:",
+ "comment": "Stack Reserve Size",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "StackCommitSize",
+ "switch": "STACK",
+ "comment": "Stack Commit Size",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "UserRequired"
+ ]
+ },
+ {
+ "name": "FunctionOrder",
+ "switch": "ORDER:@",
+ "comment": "Function Order",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ProfileGuidedDatabase",
+ "switch": "PGD:",
+ "comment": "Profile Guided Database",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MidlCommandFile",
+ "switch": "MIDL:@",
+ "comment": "MIDL Commands",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MergedIDLBaseFileName",
+ "switch": "IDLOUT:",
+ "comment": "Merged IDL Base File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "TypeLibraryFile",
+ "switch": "TLBOUT:",
+ "comment": "Type Library",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataFile",
+ "switch": "WINMDFILE:",
+ "comment": "Windows Metadata File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataLinkKeyFile",
+ "switch": "WINMDKEYFILE:",
+ "comment": "Windows Metadata Key File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "WindowsMetadataKeyContainer",
+ "switch": "WINMDKEYCONTAINER:",
+ "comment": "Windows Metadata Key Container",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "EntryPointSymbol",
+ "switch": "ENTRY:",
+ "comment": "Entry Point",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "BaseAddress",
+ "switch": "BASE:",
+ "comment": "Base Address",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ImportLibrary",
+ "switch": "IMPLIB:",
+ "comment": "Import Library",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "MergeSections",
+ "switch": "MERGE:",
+ "comment": "Merge Sections",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "LinkKeyFile",
+ "switch": "KEYFILE:",
+ "comment": "Key File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "KeyContainer",
+ "switch": "KEYCONTAINER:",
+ "comment": "Key Container",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "TypeLibraryResourceID",
+ "switch": "TLBID:",
+ "comment": "TypeLib Resource ID",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "SectionAlignment",
+ "switch": "ALIGN:",
+ "comment": "SectionAlignment",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v14_LIB.json b/Templates/MSBuild/FlagTables/v14_LIB.json
new file mode 100644
index 0000000..a0e85b2
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v14_LIB.json
@@ -0,0 +1,311 @@
+[
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:PROMPT",
+ "comment": "PromptImmediately",
+ "value": "PromptImmediately",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:QUEUE",
+ "comment": "Queue For Next Login",
+ "value": "QueueForNextLogin",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:SEND",
+ "comment": "Send Error Report",
+ "value": "SendErrorReport",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "ERRORREPORT:NONE",
+ "comment": "No Error Report",
+ "value": "NoErrorReport",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM",
+ "comment": "MachineARM",
+ "value": "MachineARM",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM64",
+ "comment": "MachineARM64",
+ "value": "MachineARM64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:ARM64X",
+ "comment": "MachineARM64X",
+ "value": "MachineARM64X",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:EBC",
+ "comment": "MachineEBC",
+ "value": "MachineEBC",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:IA64",
+ "comment": "MachineIA64",
+ "value": "MachineIA64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS",
+ "comment": "MachineMIPS",
+ "value": "MachineMIPS",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPS16",
+ "comment": "MachineMIPS16",
+ "value": "MachineMIPS16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU",
+ "comment": "MachineMIPSFPU",
+ "value": "MachineMIPSFPU",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:MIPSFPU16",
+ "comment": "MachineMIPSFPU16",
+ "value": "MachineMIPSFPU16",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:SH4",
+ "comment": "MachineSH4",
+ "value": "MachineSH4",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:THUMB",
+ "comment": "MachineTHUMB",
+ "value": "MachineTHUMB",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X64",
+ "comment": "MachineX64",
+ "value": "MachineX64",
+ "flags": []
+ },
+ {
+ "name": "TargetMachine",
+ "switch": "MACHINE:X86",
+ "comment": "MachineX86",
+ "value": "MachineX86",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:CONSOLE",
+ "comment": "Console",
+ "value": "Console",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWS",
+ "comment": "Windows",
+ "value": "Windows",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:NATIVE",
+ "comment": "Native",
+ "value": "Native",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_APPLICATION",
+ "comment": "EFI Application",
+ "value": "EFI Application",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER",
+ "comment": "EFI Boot Service Driver",
+ "value": "EFI Boot Service Driver",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_ROM",
+ "comment": "EFI ROM",
+ "value": "EFI ROM",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:EFI_RUNTIME_DRIVER",
+ "comment": "EFI Runtime",
+ "value": "EFI Runtime",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:WINDOWSCE",
+ "comment": "WindowsCE",
+ "value": "WindowsCE",
+ "flags": []
+ },
+ {
+ "name": "SubSystem",
+ "switch": "SUBSYSTEM:POSIX",
+ "comment": "POSIX",
+ "value": "POSIX",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "NOLOGO",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "IgnoreAllDefaultLibraries",
+ "switch": "NODEFAULTLIB",
+ "comment": "Ignore All Default Libraries",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatLibWarningAsErrors",
+ "switch": "WX:NO",
+ "comment": "Treat Lib Warning As Errors",
+ "value": "false",
+ "flags": []
+ },
+ {
+ "name": "TreatLibWarningAsErrors",
+ "switch": "WX",
+ "comment": "Treat Lib Warning As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Verbose",
+ "switch": "VERBOSE",
+ "comment": "Verbose",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "LinkTimeCodeGeneration",
+ "switch": "LTCG",
+ "comment": "Link Time Code Generation",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AdditionalLibraryDirectories",
+ "switch": "LIBPATH:",
+ "comment": "Additional Library Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IgnoreSpecificDefaultLibraries",
+ "switch": "NODEFAULTLIB:",
+ "comment": "Ignore Specific Default Libraries",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ExportNamedFunctions",
+ "switch": "EXPORT:",
+ "comment": "Export Named Functions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "RemoveObjects",
+ "switch": "REMOVE:",
+ "comment": "Remove Objects",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "OutputFile",
+ "switch": "OUT:",
+ "comment": "Output File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ModuleDefinitionFile",
+ "switch": "DEF:",
+ "comment": "Module Definition File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ForceSymbolReferences",
+ "switch": "INCLUDE:",
+ "comment": "Force Symbol References",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "DisplayLibrary",
+ "switch": "LIST:",
+ "comment": "Display Library to standard output",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "Name",
+ "switch": "NAME:",
+ "comment": "Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v14_MASM.json b/Templates/MSBuild/FlagTables/v14_MASM.json
new file mode 100644
index 0000000..4634306
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v14_MASM.json
@@ -0,0 +1,295 @@
+[
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "",
+ "comment": "Default",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "Cp",
+ "comment": "Preserves Identifier Case (/Cp)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "Cu",
+ "comment": "Maps all identifiers to upper case. (/Cu)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "PreserveIdentifierCase",
+ "switch": "Cx",
+ "comment": "Preserves case in public and extern symbols. (/Cx)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W0",
+ "comment": "Warning Level 0 (/W0)",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W1",
+ "comment": "Warning Level 1 (/W1)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W2",
+ "comment": "Warning Level 2 (/W2)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "WarningLevel",
+ "switch": "W3",
+ "comment": "Warning Level 3 (/W3)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "",
+ "comment": "Default",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp1",
+ "comment": "One Byte Boundary (/Zp1)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp2",
+ "comment": "Two Byte Boundary (/Zp2)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp4",
+ "comment": "Four Byte Boundary (/Zp4)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp8",
+ "comment": "Eight Byte Boundary (/Zp8)",
+ "value": "4",
+ "flags": []
+ },
+ {
+ "name": "PackAlignmentBoundary",
+ "switch": "Zp16",
+ "comment": "Sixteen Byte Boundary (/Zp16)",
+ "value": "5",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "",
+ "comment": "Default",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gd",
+ "comment": "Use C-style Calling Convention (/Gd)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gz",
+ "comment": "Use stdcall Calling Convention (/Gz)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "CallingConvention",
+ "switch": "Gc",
+ "comment": "Use Pascal Calling Convention (/Gc)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:prompt",
+ "comment": "Prompt to send report immediately (/errorReport:prompt)",
+ "value": "0",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:queue",
+ "comment": "Prompt to send report at the next logon (/errorReport:queue)",
+ "value": "1",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:send",
+ "comment": "Automatically send report (/errorReport:send)",
+ "value": "2",
+ "flags": []
+ },
+ {
+ "name": "ErrorReporting",
+ "switch": "errorReport:none",
+ "comment": "Do not send report (/errorReport:none)",
+ "value": "3",
+ "flags": []
+ },
+ {
+ "name": "NoLogo",
+ "switch": "nologo",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GeneratePreprocessedSourceListing",
+ "switch": "EP",
+ "comment": "Generate Preprocessed Source Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ListAllAvailableInformation",
+ "switch": "Sa",
+ "comment": "List All Available Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "UseSafeExceptionHandlers",
+ "switch": "safeseh",
+ "comment": "Use Safe Exception Handlers",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "AddFirstPassListing",
+ "switch": "Sf",
+ "comment": "Add First Pass Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableAssemblyGeneratedCodeListing",
+ "switch": "Sg",
+ "comment": "Enable Assembly Generated Code Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "DisableSymbolTable",
+ "switch": "Sn",
+ "comment": "Disable Symbol Table",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableFalseConditionalsInListing",
+ "switch": "Sx",
+ "comment": "Enable False Conditionals In Listing",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "TreatWarningsAsErrors",
+ "switch": "WX",
+ "comment": "Treat Warnings As Errors",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "MakeAllSymbolsPublic",
+ "switch": "Zf",
+ "comment": "Make All Symbols Public",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "Zi",
+ "comment": "Generate Debug Information",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "EnableMASM51Compatibility",
+ "switch": "Zm",
+ "comment": "Enable MASM 5.1 Compatibility",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PerformSyntaxCheckOnly",
+ "switch": "Zs",
+ "comment": "Perform Syntax Check Only",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "IncludePaths",
+ "switch": "I",
+ "comment": "Include Paths",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "BrowseFile",
+ "switch": "FR",
+ "comment": "Generate Browse Information File",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ObjectFileName",
+ "switch": "Fo",
+ "comment": "Object File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "AssembledCodeListingFile",
+ "switch": "Fl",
+ "comment": "Assembled Code Listing File",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v14_RC.json b/Templates/MSBuild/FlagTables/v14_RC.json
new file mode 100644
index 0000000..b8c0127
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v14_RC.json
@@ -0,0 +1,69 @@
+[
+ {
+ "name": "IgnoreStandardIncludePath",
+ "switch": "X",
+ "comment": "Ignore Standard Include Paths",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ShowProgress",
+ "switch": "v",
+ "comment": "Show Progress",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SuppressStartupBanner",
+ "switch": "nologo",
+ "comment": "Suppress Startup Banner",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NullTerminateStrings",
+ "switch": "n",
+ "comment": "Null Terminate Strings",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "PreprocessorDefinitions",
+ "switch": "D",
+ "comment": "Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "UndefinePreprocessorDefinitions",
+ "switch": "u",
+ "comment": "Undefine Preprocessor Definitions",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "AdditionalIncludeDirectories",
+ "switch": "I",
+ "comment": "Additional Include Directories",
+ "value": "",
+ "flags": [
+ "UserValue",
+ "SemicolonAppendable"
+ ]
+ },
+ {
+ "name": "ResourceOutputFileName",
+ "switch": "fo",
+ "comment": "Resource File Name",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/nasm.props.in b/Templates/MSBuild/nasm.props.in
new file mode 100644
index 0000000..3443108
--- /dev/null
+++ b/Templates/MSBuild/nasm.props.in
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Condition="'$(NASMBeforeTargets)' == '' and '$(NASMAfterTargets)' == '' and '$(ConfigurationType)' != 'Makefile'">
+ <NASMBeforeTargets>Midl</NASMBeforeTargets>
+ <NASMAfterTargets>CustomBuild</NASMAfterTargets>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <NASM>
+ <OutputFormat>$(IntDir)%(FileName).obj</OutputFormat>
+ <Outputswitch>0</Outputswitch>
+ <CompilerNasm>@CMAKE_ASM_NASM_COMPILER@</CompilerNasm>
+ <PackAlignmentBoundary>0</PackAlignmentBoundary>
+ <CommandLineTemplate>"%(CompilerNasm)" [AllOptions] [AdditionalOptions] "%(FullPath)"</CommandLineTemplate>
+ <ExecutionDescription>Assembling %(Filename)%(Extension)</ExecutionDescription>
+ </NASM>
+ </ItemDefinitionGroup>
+</Project>
diff --git a/Templates/MSBuild/nasm.targets b/Templates/MSBuild/nasm.targets
new file mode 100644
index 0000000..eeeb613
--- /dev/null
+++ b/Templates/MSBuild/nasm.targets
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <PropertyPageSchema Include="$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml"/>
+ <AvailableItemName Include="NASM">
+ <Targets>_NASM</Targets>
+ </AvailableItemName>
+ </ItemGroup>
+ <PropertyGroup>
+ <ComputeLinkInputsTargets>
+ $(ComputeLinkInputsTargets);
+ ComputeNASMOutput;
+ </ComputeLinkInputsTargets>
+ <ComputeLibInputsTargets>
+ $(ComputeLibInputsTargets);
+ ComputeNASMOutput;
+ </ComputeLibInputsTargets>
+ </PropertyGroup>
+ <UsingTask TaskName="NASM" TaskFactory="XamlTaskFactory" AssemblyName="Microsoft.Build.Tasks.v4.0">
+ <Task>$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml</Task>
+ </UsingTask>
+ <Target Name="_NASM" BeforeTargets="$(NASMBeforeTargets)" AfterTargets="$(NASMAfterTargets)" Condition="'@(NASM)' != ''" Outputs="%(NASM.OutputFormat)" Inputs="%(NASM.Identity);%(NASM.AdditionalDependencies);$(MSBuildProjectFile)" DependsOnTargets="_SelectedFiles">
+ <ItemGroup Condition="'@(SelectedFiles)' != ''">
+ <NASM Remove="@(NASM)" Condition="'%(Identity)' != '@(SelectedFiles)'"/>
+ </ItemGroup>
+ <ItemGroup>
+ <NASM_tlog Include="%(NASM.OutputFormat)" Condition="'%(NASM.OutputFormat)' != '' and '%(NASM.ExcludedFromBuild)' != 'true'">
+ <Source>@(NASM, '|')</Source>
+ </NASM_tlog>
+ </ItemGroup>
+ <Message Importance="High" Text="%(NASM.ExecutionDescription)"/>
+ <WriteLinesToFile Condition="'@(NASM_tlog)' != '' and '%(NASM_tlog.ExcludedFromBuild)' != 'true'" File="$(IntDir)$(ProjectName).write.1.tlog" Lines="^%(NASM_tlog.Source);@(NASM_tlog-&gt;'%(Fullpath)')"/>
+ <NASM Condition="'@(NASM)' != '' and '%(NASM.ExcludedFromBuild)' != 'true'" Inputs="%(NASM.Inputs)" OutputFormat="%(NASM.OutputFormat)" Outputswitch="%(NASM.Outputswitch)" AssembledCodeListingFile="%(NASM.AssembledCodeListingFile)" GenerateDebugInformation="%(NASM.GenerateDebugInformation)" ErrorReporting="%(NASM.ErrorReporting)" IncludePaths="%(NASM.IncludePaths)" PreprocessorDefinitions="%(NASM.PreprocessorDefinitions)" UndefinePreprocessorDefinitions="%(NASM.UndefinePreprocessorDefinitions)" ErrorReportingFormat="%(NASM.ErrorReportingFormat)" TreatWarningsAsErrors="%(NASM.TreatWarningsAsErrors)" floatunderflow="%(NASM.floatunderflow)" macrodefaults="%(NASM.macrodefaults)" user="%(NASM.user)" floatoverflow="%(NASM.floatoverflow)" floatdenorm="%(NASM.floatdenorm)" numberoverflow="%(NASM.numberoverflow)" macroselfref="%(NASM.macroselfref)" floattoolong="%(NASM.floattoolong)" orphanlabels="%(NASM.orphanlabels)" CommandLineTemplate="%(NASM.CommandLineTemplate)" AdditionalOptions="%(NASM.AdditionalOptions)"/>
+ </Target>
+ <Target Name="ComputeNASMOutput" Condition="'@(NASM)' != ''">
+ <ItemGroup>
+ <Link Include="@(NASM-&gt;Metadata('OutputFormat')-&gt;Distinct()-&gt;ClearMetadata())" Condition="'%(NASM.ExcludedFromBuild)' != 'true'"/>
+ <Lib Include="@(NASM-&gt;Metadata('OutputFormat')-&gt;Distinct()-&gt;ClearMetadata())" Condition="'%(NASM.ExcludedFromBuild)' != 'true'"/>
+ </ItemGroup>
+ </Target>
+</Project>
diff --git a/Templates/MSBuild/nasm.xml b/Templates/MSBuild/nasm.xml
new file mode 100644
index 0000000..a5dcdd5
--- /dev/null
+++ b/Templates/MSBuild/nasm.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib">
+ <Rule Name="NASM" PageTemplate="tool" DisplayName="Netwide Assembler" Order="200">
+ <Rule.DataSource>
+ <DataSource Persistence="ProjectFile" ItemType="NASM"/>
+ </Rule.DataSource>
+ <Rule.Categories>
+ <Category Name="General">
+ <Category.DisplayName>
+ <sys:String>General</sys:String>
+ </Category.DisplayName>
+ </Category>
+ <Category Name="Preprocessor">
+ <Category.DisplayName>
+ <sys:String>Preprocessing Options</sys:String>
+ </Category.DisplayName>
+ </Category>
+ <Category Name="Assembler Options">
+ <Category.DisplayName>
+ <sys:String>Assembler Options</sys:String>
+ </Category.DisplayName>
+ </Category>
+ <Category Name="Advanced">
+ <Category.DisplayName>
+ <sys:String>Advanced </sys:String>
+ </Category.DisplayName>
+ </Category>
+ <Category Name="Command Line" Subtype="CommandLine">
+ <Category.DisplayName>
+ <sys:String>Command Line</sys:String>
+ </Category.DisplayName>
+ </Category>
+ </Rule.Categories>
+ <StringProperty Name="Inputs" Category="Command Line" IsRequired="true">
+ <StringProperty.DataSource>
+ <DataSource Persistence="ProjectFile" ItemType="NASM" SourceType="Item"/>
+ </StringProperty.DataSource>
+ </StringProperty>
+ <StringProperty Name="OutputFormat" Category="Assembler Options" HelpUrl="http://www.nasm.us/doc/" DisplayName="Output File Name" Description="Specify Output Filename.-o [value]" Switch="-o &quot;[value]&quot;"/>
+ <BoolProperty Name="tasmmode" Category="Advanced" HelpUrl="http://www.nasm.us/doc/" DisplayName="SciTech TASM compatible mode" Description="assemble in SciTech TASM compatible mode" Switch="-t"/>
+ <EnumProperty Name="Outputswitch" Category="Assembler Options" HelpUrl="http://www.nasm.us/doc/" DisplayName="Output Switch" Description="Select the type of output format required. Linking Should be disabled for ELF and Binary ,else error will popup">
+ <EnumValue Name="0" DisplayName="Object File win32" Switch="-fwin32"/>
+ <EnumValue Name="1" DisplayName="Object File win64" Switch="-fwin64"/>
+ <EnumValue Name="2" DisplayName="ELF32 (i386) object files (e.g. Linux)" Switch="-felf32"/>
+ <EnumValue Name="3" DisplayName="ELF64 (x86_64) object files (e.g. Linux)" Switch="-felf64"/>
+ </EnumProperty>
+ <StringListProperty Name="AssembledCodeListingFile" Category="Assembler Options" DisplayName="Assembled Code Listing File" Description="Generates an assembled code listing file. (-l [file])" HelpUrl="http://www.nasm.us/doc/" Switch="-l &quot;[value]&quot;"/>
+ <BoolProperty Name="GenerateDebugInformation" Category="Assembler Options" DisplayName="Generate Debug Information" Description="Generates Debug Information. (-g)" HelpUrl="http://www.nasm.us/doc/" Switch="-g"/>
+ <StringListProperty Name="ErrorReporting" Category="Advanced" HelpUrl="http://www.nasm.us/doc/" DisplayName="Redirect Error Messages to File" Description="Drops the error Message on specified device" Switch="-Z &quot;[value]&quot;"/>
+ <StringListProperty Name="IncludePaths" Category="General" DisplayName="Include Paths" Description="Sets path for include file. (-I[path])" HelpUrl="http://www.nasm.us/doc/" Switch="-I&quot;[value]&quot;"/>
+ <StringListProperty Name="PreprocessorDefinitions" Category="Preprocessor" HelpUrl="http://www.nasm.us/doc/" DisplayName="Preprocessor Definitions" Description="Defines a text macro with the given name. (-D[symbol])" Switch="-D&quot;[value]&quot;"/>
+ <StringListProperty Name="UndefinePreprocessorDefinitions" Category="Preprocessor" HelpUrl="http://www.nasm.us/doc/" DisplayName="Undefine Preprocessor Definitions" Description="Undefines a text macro with the given name. (-U[symbol])" Switch="-U&quot;[value]&quot;"/>
+ <EnumProperty Name="ErrorReportingFormat" Category="Advanced" HelpUrl="http://www.nasm.us/doc/" DisplayName="Error Reporting Format" Description="Select the error reporting format ie. GNU or VC">
+ <EnumValue Name="0" DisplayName="-Xgnu GNU format: Default format" Switch="-Xgnu"/>
+ <EnumValue Name="1" DisplayName="-Xvc Style used by Microsoft Visual C++" Switch="-Xvc"/>
+ </EnumProperty>
+ <BoolProperty Name="TreatWarningsAsErrors" Category="Assembler Options" DisplayName="Treat Warnings As Errors" Description="Returns an error code if warnings are generated. (-Werror)" HelpUrl="http://www.nasm.us/doc/" Switch="-Werror"/>
+ <BoolProperty Name="floatunderflow" Category="Advanced" HelpUrl="http://www.nasm.us/doc/" DisplayName="float-underflow" Description="floating point underflow (default off)" Switch="-w+float-underflow"/>
+ <BoolProperty Name="macrodefaults" Category="Advanced" HelpUrl="http://www.nasm.us/doc/" DisplayName="Disable macro-defaults" Description="macros with more default than optional parameters (default on)" Switch="-w-macro-defaults"/>
+ <BoolProperty Name="user" Category="Advanced" HelpUrl="http://www.nasm.us/doc/" DisplayName="Disable user" Description="%warning directives (default on)" Switch="-w-user"/>
+ <BoolProperty Name="floatoverflow" Category="Advanced" HelpUrl="http://www.nasm.us/doc/" DisplayName="Disable float-overflow" Description="floating point overflow (default on)" Switch="-w-float-overflow"/>
+ <BoolProperty Name="floatdenorm" Category="Advanced" HelpUrl="http://www.nasm.us/doc/" DisplayName="float-denorm" Description="floating point denormal (default off)" Switch="-w+float-denorm"/>
+ <BoolProperty Name="numberoverflow" Category="Advanced" HelpUrl="http://www.nasm.us/doc/" DisplayName="Disable number-overflow" Description="numeric constant does not fit (default on)" Switch="-w-number-overflow"/>
+ <BoolProperty Name="macroselfref" Category="Advanced" HelpUrl="http://www.nasm.us/doc/" DisplayName="macro-selfref" Description="cyclic macro references (default off)" Switch="-w+macro-selfref"/>
+ <BoolProperty Name="floattoolong" Category="Advanced" HelpUrl="http://www.nasm.us/doc/" DisplayName="Disable float-toolong" Description=" too many digits in floating-point number (default on)" Switch="-w-float-toolong"/>
+ <BoolProperty Name="orphanlabels" Category="Advanced" HelpUrl="http://www.nasm.us/doc/" DisplayName="Disable orphan-labels" Description="labels alone on lines without trailing `:' (default on)" Switch="-w-orphan-labels"/>
+ <StringProperty Name="CommandLineTemplate" DisplayName="Command Line" Visible="False" IncludeInCommandLine="False"/>
+ <DynamicEnumProperty Name="NASMBeforeTargets" Category="General" EnumProvider="Targets" IncludeInCommandLine="False">
+ <DynamicEnumProperty.DisplayName>
+ <sys:String>Execute Before</sys:String>
+ </DynamicEnumProperty.DisplayName>
+ <DynamicEnumProperty.Description>
+ <sys:String>Specifies the targets for the build customization to run before.</sys:String>
+ </DynamicEnumProperty.Description>
+ <DynamicEnumProperty.ProviderSettings>
+ <NameValuePair Name="Exclude" Value="^NASMBeforeTargets|^Compute"/>
+ </DynamicEnumProperty.ProviderSettings>
+ <DynamicEnumProperty.DataSource>
+ <DataSource Persistence="ProjectFile" ItemType="" HasConfigurationCondition="true"/>
+ </DynamicEnumProperty.DataSource>
+ </DynamicEnumProperty>
+ <DynamicEnumProperty Name="NASMAfterTargets" Category="General" EnumProvider="Targets" IncludeInCommandLine="False">
+ <DynamicEnumProperty.DisplayName>
+ <sys:String>Execute After</sys:String>
+ </DynamicEnumProperty.DisplayName>
+ <DynamicEnumProperty.Description>
+ <sys:String>Specifies the targets for the build customization to run after.</sys:String>
+ </DynamicEnumProperty.Description>
+ <DynamicEnumProperty.ProviderSettings>
+ <NameValuePair Name="Exclude" Value="^NASMAfterTargets|^Compute"/>
+ </DynamicEnumProperty.ProviderSettings>
+ <DynamicEnumProperty.DataSource>
+ <DataSource Persistence="ProjectFile" ItemType="" HasConfigurationCondition="true"/>
+ </DynamicEnumProperty.DataSource>
+ </DynamicEnumProperty>
+ <StringProperty Name="ExecutionDescription" DisplayName="Execution Description" IncludeInCommandLine="False" Visible="False"/>
+ <StringListProperty Name="AdditionalDependencies" DisplayName="Additional Dependencies" IncludeInCommandLine="False" Visible="False"/>
+ <StringProperty Subtype="AdditionalOptions" Name="AdditionalOptions" Category="Command Line">
+ <StringProperty.DisplayName>
+ <sys:String>Additional Options</sys:String>
+ </StringProperty.DisplayName>
+ <StringProperty.Description>
+ <sys:String>Additional Options</sys:String>
+ </StringProperty.Description>
+ </StringProperty>
+ </Rule>
+ <ItemType Name="NASM" DisplayName="Netwide Assembler"/>
+ <FileExtension Name="*.asm" ContentType="NASM"/>
+ <ContentType Name="NASM" DisplayName="Netwide Assembler" ItemType="NASM"/>
+</ProjectSchemaDefinitions>
diff --git a/Templates/TestDriver.cxx.in b/Templates/TestDriver.cxx.in
new file mode 100644
index 0000000..3e47d6a
--- /dev/null
+++ b/Templates/TestDriver.cxx.in
@@ -0,0 +1,146 @@
+#include <ctype.h> /* NOLINT */
+#include <stdio.h> /* NOLINT */
+#include <stdlib.h> /* NOLINT */
+#include <string.h> /* NOLINT */
+
+#if defined(_MSC_VER)
+#pragma warning(disable : 4996) /* deprecation */
+#endif
+
+@CMAKE_TESTDRIVER_EXTRA_INCLUDES@
+
+/* Forward declare test functions. */
+@CMAKE_FORWARD_DECLARE_TESTS@
+
+#ifdef __cplusplus
+# define CM_CAST(TYPE, EXPR) static_cast<TYPE>(EXPR)
+# if __cplusplus >= 201103L
+# define CM_NULL nullptr
+# else
+# define CM_NULL NULL
+# endif
+#else
+# define CM_CAST(TYPE, EXPR) (TYPE)(EXPR)
+# define CM_NULL NULL
+#endif
+
+/* Create map. */
+
+typedef int (*MainFuncPointer)(int, char* []); /* NOLINT */
+typedef struct /* NOLINT */
+{
+ const char* name;
+ MainFuncPointer func;
+} functionMapEntry;
+
+static functionMapEntry cmakeGeneratedFunctionMapEntries[] = {
+ @CMAKE_FUNCTION_TABLE_ENTRIES@
+ { CM_NULL, CM_NULL } /* NOLINT */
+};
+
+static const int NumTests = CM_CAST(int,
+ sizeof(cmakeGeneratedFunctionMapEntries) / sizeof(functionMapEntry)) - 1;
+
+/* Allocate and create a lowercased copy of string
+ (note that it has to be free'd manually) */
+static char* lowercase(const char* string)
+{
+ char *new_string;
+ char *p;
+ size_t stringSize;
+
+ stringSize = CM_CAST(size_t, strlen(string) + 1);
+ new_string = CM_CAST(char*, malloc(sizeof(char) * stringSize));
+
+ if (new_string == CM_NULL) { /* NOLINT */
+ return CM_NULL; /* NOLINT */
+ }
+ strcpy(new_string, string); /* NOLINT */
+ for (p = new_string; *p != 0; ++p) {
+ *p = CM_CAST(char, tolower(*p));
+ }
+ return new_string;
+}
+
+int main(int ac, char* av[])
+{
+ int i;
+ int testNum = 0;
+ int partial_match;
+ char *arg;
+ int testToRun = -1;
+
+ @CMAKE_TESTDRIVER_ARGVC_FUNCTION@
+
+ /* If no test name was given */
+ /* process command line with user function. */
+ if (ac < 2) {
+ /* Ask for a test. */
+ printf("Available tests:\n");
+ for (i = 0; i < NumTests; ++i) {
+ printf("%3d. %s\n", i, cmakeGeneratedFunctionMapEntries[i].name);
+ }
+ printf("To run a test, enter the test number: ");
+ fflush(stdout);
+ if (scanf("%d", &testNum) != 1) {
+ printf("Couldn't parse that input as a number\n");
+ return -1;
+ }
+ if (testNum >= NumTests) {
+ printf("%3d is an invalid test number.\n", testNum);
+ return -1;
+ }
+ testToRun = testNum;
+ ac--;
+ av++;
+ }
+ partial_match = 0;
+ arg = CM_NULL; /* NOLINT */
+ /* If partial match is requested. */
+ if (testToRun == -1 && ac > 1) {
+ partial_match = (strcmp(av[1], "-R") == 0) ? 1 : 0;
+ }
+ if (partial_match != 0 && ac < 3) {
+ printf("-R needs an additional parameter.\n");
+ return -1;
+ }
+ if (testToRun == -1) {
+ arg = lowercase(av[1 + partial_match]);
+ }
+ for (i = 0; i < NumTests && testToRun == -1; ++i) {
+ char *test_name = lowercase(cmakeGeneratedFunctionMapEntries[i].name);
+ if (partial_match != 0 && strstr(test_name, arg) != CM_NULL) { /* NOLINT */
+ testToRun = i;
+ ac -= 2;
+ av += 2;
+ } else if (partial_match == 0 && strcmp(test_name, arg) == 0) {
+ testToRun = i;
+ ac--;
+ av++;
+ }
+ free(test_name);
+ }
+ free(arg);
+ if (testToRun != -1) {
+ int result;
+@CMAKE_TESTDRIVER_BEFORE_TESTMAIN@
+ if (testToRun < 0 || testToRun >= NumTests) {
+ printf("testToRun was modified by TestDriver code to an invalid value: "
+ "%3d.\n",
+ testNum);
+ return -1;
+ }
+ result = (*cmakeGeneratedFunctionMapEntries[testToRun].func)(ac, av);
+@CMAKE_TESTDRIVER_AFTER_TESTMAIN@
+ return result;
+ }
+
+ /* Nothing was run, display the test names. */
+ printf("Available tests:\n");
+ for (i = 0; i < NumTests; ++i) {
+ printf("%3d. %s\n", i, cmakeGeneratedFunctionMapEntries[i].name);
+ }
+ printf("Failed: %s is an invalid test name.\n", av[1]);
+
+ return -1;
+}
diff --git a/Templates/Windows/ApplicationIcon.png b/Templates/Windows/ApplicationIcon.png
new file mode 100644
index 0000000..c715e1b
--- /dev/null
+++ b/Templates/Windows/ApplicationIcon.png
Binary files differ
diff --git a/Templates/Windows/Logo.png b/Templates/Windows/Logo.png
new file mode 100644
index 0000000..65f91ac
--- /dev/null
+++ b/Templates/Windows/Logo.png
Binary files differ
diff --git a/Templates/Windows/SmallLogo.png b/Templates/Windows/SmallLogo.png
new file mode 100644
index 0000000..460c022
--- /dev/null
+++ b/Templates/Windows/SmallLogo.png
Binary files differ
diff --git a/Templates/Windows/SmallLogo44x44.png b/Templates/Windows/SmallLogo44x44.png
new file mode 100644
index 0000000..c237458
--- /dev/null
+++ b/Templates/Windows/SmallLogo44x44.png
Binary files differ
diff --git a/Templates/Windows/SplashScreen.png b/Templates/Windows/SplashScreen.png
new file mode 100644
index 0000000..8342565
--- /dev/null
+++ b/Templates/Windows/SplashScreen.png
Binary files differ
diff --git a/Templates/Windows/StoreLogo.png b/Templates/Windows/StoreLogo.png
new file mode 100644
index 0000000..508c8a8
--- /dev/null
+++ b/Templates/Windows/StoreLogo.png
Binary files differ
diff --git a/Templates/Windows/Windows_TemporaryKey.pfx b/Templates/Windows/Windows_TemporaryKey.pfx
new file mode 100644
index 0000000..1cad999
--- /dev/null
+++ b/Templates/Windows/Windows_TemporaryKey.pfx
Binary files differ
diff --git a/Tests/.NoDartCoverage b/Tests/.NoDartCoverage
new file mode 100644
index 0000000..3c99729
--- /dev/null
+++ b/Tests/.NoDartCoverage
@@ -0,0 +1 @@
+# do not do coverage in this directory
diff --git a/Tests/AliasTarget/CMakeLists.txt b/Tests/AliasTarget/CMakeLists.txt
new file mode 100644
index 0000000..fc70135
--- /dev/null
+++ b/Tests/AliasTarget/CMakeLists.txt
@@ -0,0 +1,81 @@
+cmake_minimum_required(VERSION 2.8.11)
+cmake_policy(SET CMP0054 NEW)
+project(AliasTarget)
+
+set(CMAKE_CXX_STANDARD 98)
+
+# Clang/C2 in C++98 mode cannot properly handle some of MSVC headers
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
+ CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
+ set(CMAKE_CXX_STANDARD 11)
+endif()
+
+add_library(foo SHARED empty.cpp)
+add_library(PREFIX::Foo ALIAS foo)
+add_library(Another::Alias ALIAS foo)
+
+add_library(objects OBJECT object.cpp)
+add_library(Alias::Objects ALIAS objects)
+
+target_compile_definitions(foo PUBLIC FOO_DEFINE)
+
+add_library(bar SHARED empty.cpp)
+target_compile_definitions(bar PUBLIC BAR_DEFINE)
+
+target_link_libraries(foo LINK_PUBLIC $<$<STREQUAL:$<TARGET_PROPERTY:PREFIX::Foo,ALIASED_TARGET>,foo>:bar>)
+
+add_executable(AliasTarget commandgenerator.cpp $<TARGET_OBJECTS:Alias::Objects>)
+add_executable(PREFIX::AliasTarget ALIAS AliasTarget)
+add_executable(Generator::Command ALIAS AliasTarget)
+
+add_custom_command(OUTPUT commandoutput.h COMMAND Generator::Command)
+
+add_library(bat SHARED bat.cpp "${CMAKE_CURRENT_BINARY_DIR}/commandoutput.h")
+target_link_libraries(bat PREFIX::Foo)
+target_include_directories(bat PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
+
+add_executable(targetgenerator targetgenerator.cpp)
+add_executable(Generator::Target ALIAS targetgenerator)
+
+add_subdirectory(subdir)
+
+add_custom_target(usealias Generator::Target $<TARGET_FILE:Sub::tgt>)
+add_dependencies(bat usealias)
+
+if (NOT TARGET Another::Alias)
+ message(SEND_ERROR "Another::Alias is not considered a target.")
+endif()
+
+get_target_property(_alt PREFIX::Foo ALIASED_TARGET)
+if (NOT ${_alt} STREQUAL foo)
+ message(SEND_ERROR "ALIASED_TARGET is not foo: ${_alt}")
+endif()
+
+get_property(_alt2 TARGET PREFIX::Foo PROPERTY ALIASED_TARGET)
+if (NOT ${_alt2} STREQUAL foo)
+ message(SEND_ERROR "ALIASED_TARGET is not foo.")
+endif()
+
+add_library(iface INTERFACE)
+add_library(Alias::Iface ALIAS iface)
+
+get_property(_aliased_target_set TARGET foo PROPERTY ALIASED_TARGET SET)
+if(_aliased_target_set)
+ message(SEND_ERROR "ALIASED_TARGET is set for target foo")
+endif()
+
+get_target_property(_notAlias1 foo ALIASED_TARGET)
+if (NOT DEFINED _notAlias1)
+ message(SEND_ERROR "_notAlias1 is not defined")
+endif()
+if (_notAlias1)
+ message(SEND_ERROR "_notAlias1 is defined, but foo is not an ALIAS")
+endif()
+if (NOT _notAlias1 STREQUAL _notAlias1-NOTFOUND)
+ message(SEND_ERROR "_notAlias1 not defined to a -NOTFOUND variant")
+endif()
+
+get_property(_notAlias2 TARGET foo PROPERTY ALIASED_TARGET)
+if (_notAlias2)
+ message(SEND_ERROR "_notAlias2 evaluates to true, but foo is not an ALIAS")
+endif()
diff --git a/Tests/AliasTarget/bat.cpp b/Tests/AliasTarget/bat.cpp
new file mode 100644
index 0000000..14942bf
--- /dev/null
+++ b/Tests/AliasTarget/bat.cpp
@@ -0,0 +1,28 @@
+
+#ifndef FOO_DEFINE
+# error Expected FOO_DEFINE
+#endif
+
+#ifndef BAR_DEFINE
+# error Expected Bar_DEFINE
+#endif
+
+#include "commandoutput.h"
+
+#ifndef COMMANDOUTPUT_DEFINE
+# error Expected COMMANDOUTPUT_DEFINE
+#endif
+
+#include "targetoutput.h"
+
+#ifndef TARGETOUTPUT_DEFINE
+# error Expected TARGETOUTPUT_DEFINE
+#endif
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int bar()
+{
+ return 0;
+}
diff --git a/Tests/AliasTarget/commandgenerator.cpp b/Tests/AliasTarget/commandgenerator.cpp
new file mode 100644
index 0000000..c4d80a1
--- /dev/null
+++ b/Tests/AliasTarget/commandgenerator.cpp
@@ -0,0 +1,14 @@
+
+#include <fstream>
+
+#include "object.h"
+
+int main(int argc, char** argv)
+{
+ std::ofstream fout("commandoutput.h");
+ if (!fout)
+ return 1;
+ fout << "#define COMMANDOUTPUT_DEFINE\n";
+ fout.close();
+ return object();
+}
diff --git a/Tests/AliasTarget/empty.cpp b/Tests/AliasTarget/empty.cpp
new file mode 100644
index 0000000..15f9ff5
--- /dev/null
+++ b/Tests/AliasTarget/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int main(void)
+{
+ return 0;
+}
diff --git a/Tests/AliasTarget/object.cpp b/Tests/AliasTarget/object.cpp
new file mode 100644
index 0000000..df09c20
--- /dev/null
+++ b/Tests/AliasTarget/object.cpp
@@ -0,0 +1,5 @@
+
+int object(void)
+{
+ return 0;
+}
diff --git a/Tests/AliasTarget/object.h b/Tests/AliasTarget/object.h
new file mode 100644
index 0000000..d33551c
--- /dev/null
+++ b/Tests/AliasTarget/object.h
@@ -0,0 +1,4 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int object(void);
diff --git a/Tests/AliasTarget/subdir/CMakeLists.txt b/Tests/AliasTarget/subdir/CMakeLists.txt
new file mode 100644
index 0000000..05a7d86
--- /dev/null
+++ b/Tests/AliasTarget/subdir/CMakeLists.txt
@@ -0,0 +1,8 @@
+
+add_library(tgt STATIC empty.cpp)
+add_library(Sub::tgt ALIAS tgt)
+
+# foo comes from the top-level CMakeLists.txt
+add_library(Top::foo ALIAS foo)
+get_target_property(some_prop Top::foo SOME_PROP)
+target_link_libraries(tgt Top::foo)
diff --git a/Tests/AliasTarget/subdir/empty.cpp b/Tests/AliasTarget/subdir/empty.cpp
new file mode 100644
index 0000000..15f9ff5
--- /dev/null
+++ b/Tests/AliasTarget/subdir/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int main(void)
+{
+ return 0;
+}
diff --git a/Tests/AliasTarget/targetgenerator.cpp b/Tests/AliasTarget/targetgenerator.cpp
new file mode 100644
index 0000000..4de4792
--- /dev/null
+++ b/Tests/AliasTarget/targetgenerator.cpp
@@ -0,0 +1,12 @@
+
+#include <fstream>
+
+int main(int argc, char** argv)
+{
+ std::ofstream fout("targetoutput.h");
+ if (!fout)
+ return 1;
+ fout << "#define TARGETOUTPUT_DEFINE\n";
+ fout.close();
+ return 0;
+}
diff --git a/Tests/Architecture/CMakeLists.txt b/Tests/Architecture/CMakeLists.txt
new file mode 100644
index 0000000..96def00
--- /dev/null
+++ b/Tests/Architecture/CMakeLists.txt
@@ -0,0 +1,59 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(Architecture C)
+
+function(test_for_xcode4 result_var)
+ set(${result_var} 0 PARENT_SCOPE)
+ if(APPLE)
+ execute_process(COMMAND xcodebuild -version
+ OUTPUT_VARIABLE ov RESULT_VARIABLE rv
+ )
+ if("${rv}" STREQUAL "0" AND ov MATCHES "^Xcode ([0-9]+)\\.")
+ if(NOT CMAKE_MATCH_1 VERSION_LESS 4)
+ set(${result_var} 1 PARENT_SCOPE)
+ endif()
+ endif()
+ endif()
+endfunction()
+
+test_for_xcode4(is_xcode4)
+
+set(arch0 i386)
+set(arch1 ppc)
+
+if(is_xcode4)
+ # Xcode 4, use modern architectures as defaults
+ # Arch 'ppc' no longer works: tools no longer available starting with Xcode 4
+ set(arch0 i386)
+ set(arch1 x86_64)
+endif()
+
+add_library(foo foo.c)
+if(CMAKE_OSX_ARCHITECTURES)
+ get_property(archs TARGET foo PROPERTY OSX_ARCHITECTURES)
+ if(NOT "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "${archs}")
+ message(FATAL_ERROR
+ "OSX_ARCHITECTURES property not initialized by CMAKE_OSX_ARCHITECTURES.\n"
+ "Expected [${CMAKE_OSX_ARCHITECTURES}], got [${archs}]."
+ )
+ endif()
+ list(LENGTH archs archs_len)
+ if(archs_len GREATER 1)
+ list(GET archs 0 arch0)
+ list(GET archs 1 arch1)
+ endif()
+endif()
+
+message("is_xcode4='${is_xcode4}'")
+message("archs='${archs}'")
+message("arch0='${arch0}'")
+message("arch1='${arch1}'")
+
+set_property(TARGET foo PROPERTY OSX_ARCHITECTURES ${arch0})
+set_property(TARGET foo PROPERTY OSX_ARCHITECTURES_DEBUG ${arch1})
+
+add_executable(bar bar.c)
+target_link_libraries(bar foo)
+
+set_property(TARGET bar PROPERTY OUTPUT_NAME Architecture)
+set_property(TARGET bar PROPERTY OSX_ARCHITECTURES ${arch1})
+set_property(TARGET bar PROPERTY OSX_ARCHITECTURES_DEBUG ${arch0})
diff --git a/Tests/Architecture/bar.c b/Tests/Architecture/bar.c
new file mode 100644
index 0000000..37946c7
--- /dev/null
+++ b/Tests/Architecture/bar.c
@@ -0,0 +1,5 @@
+extern int foo(void);
+int main()
+{
+ return foo();
+}
diff --git a/Tests/Architecture/foo.c b/Tests/Architecture/foo.c
new file mode 100644
index 0000000..c83d856
--- /dev/null
+++ b/Tests/Architecture/foo.c
@@ -0,0 +1,4 @@
+int foo(void)
+{
+ return 0;
+}
diff --git a/Tests/ArgumentExpansion/CMakeLists.txt b/Tests/ArgumentExpansion/CMakeLists.txt
new file mode 100644
index 0000000..da3bb4c
--- /dev/null
+++ b/Tests/ArgumentExpansion/CMakeLists.txt
@@ -0,0 +1,60 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(ArgumentExpansion)
+
+function (argument_tester expected expected_len)
+ list(LENGTH ARGN argn_len)
+ list(LENGTH ${expected} expected_received_len)
+
+ if (NOT ${expected_received_len} EQUAL ${expected_len})
+ message(STATUS "Unexpected: Expanding expected values isn't working")
+ endif ()
+
+ if (${argn_len} EQUAL ${expected_len})
+ set(i 0)
+ while (i LESS ${argn_len})
+ list(GET ARGN ${i} argn_value)
+ list(GET ${expected} ${i} expected_value)
+
+ if (NOT "${argn_value}" STREQUAL "${expected_value}")
+ message(STATUS "Unexpected: Argument ${i} doesn't match")
+ message(STATUS " Expected: ${expected_value}")
+ message(STATUS " Received: ${argn_value}")
+ endif ()
+
+ math(EXPR i "${i} + 1")
+ endwhile ()
+ else ()
+ message(STATUS "Unexpected: Lengths of arguments don't match")
+ message(STATUS " Expected: ${expected_len}")
+ message(STATUS " Received: ${argn_len}")
+ endif ()
+endfunction ()
+
+set(empty_test)
+message(STATUS "Test: Empty arguments")
+argument_tester(empty_test 0 ${empty_test})
+
+set(single_arg_test
+ "single arg")
+message(STATUS "Test: Single argument")
+argument_tester(single_arg_test 1 ${single_arg_test})
+
+set(multiple_arg_test
+ "first arg"
+ "second arg")
+message(STATUS "Test: Multiple arguments")
+argument_tester(multiple_arg_test 2 ${multiple_arg_test})
+
+set(nested_list_arg_test
+ "${multiple_arg_test}"
+ "first arg"
+ "second arg")
+message(STATUS "Test: Nested list argument flattens")
+argument_tester(nested_list_arg_test 4 ${nested_list_arg_test})
+
+set(semicolon_arg_test
+ "pre\;post")
+set(semicolon_arg_test_flat "pre;post")
+message(STATUS "Test: Semicolon argument flattens")
+argument_tester(semicolon_arg_test_flat 2 ${semicolon_arg_test})
diff --git a/Tests/Assembler/CMakeLists.txt b/Tests/Assembler/CMakeLists.txt
new file mode 100644
index 0000000..0a2c819
--- /dev/null
+++ b/Tests/Assembler/CMakeLists.txt
@@ -0,0 +1,50 @@
+cmake_minimum_required (VERSION 3.8)
+project(Assembler C)
+message("CTEST_FULL_OUTPUT ")
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+set(SRCS)
+
+# (at least) the following toolchains can process assembler files directly
+# and also generate assembler files from C:
+if("${CMAKE_GENERATOR}" MATCHES "Makefile|Xcode|Ninja" AND
+ NOT CMAKE_OSX_ARCHITECTURES MATCHES ";")
+ if((CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang|HP|SunPro|XL)$") OR (CMAKE_C_COMPILER_ID MATCHES "Intel" AND UNIX)
+ AND NOT (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC"))
+ set(C_FLAGS "${CMAKE_C_FLAGS}")
+ separate_arguments(C_FLAGS)
+ if(CMAKE_OSX_SYSROOT AND CMAKE_C_SYSROOT_FLAG AND NOT ";${C_FLAGS};" MATCHES ";${CMAKE_C_SYSROOT_FLAG};")
+ list(APPEND C_FLAGS ${CMAKE_C_SYSROOT_FLAG} ${CMAKE_OSX_SYSROOT})
+ endif()
+ if(CMAKE_OSX_ARCHITECTURES)
+ list(APPEND C_FLAGS -arch ${CMAKE_OSX_ARCHITECTURES})
+ elseif("${CMAKE_SYSTEM_NAME};${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "Darwin;arm64")
+ list(APPEND C_FLAGS -arch arm64)
+ endif()
+ # Clang on OS X, and perhaps other compilers, do not support -g
+ # for both generating and assembling, so drop it from generating.
+ list(REMOVE_ITEM C_FLAGS -g)
+ set(SRCS main.s)
+ add_custom_command(
+ OUTPUT main.s
+ COMMAND ${CMAKE_C_COMPILER} ${C_FLAGS}
+ "$<$<CONFIG:Debug>:${CMAKE_C_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL}>"
+ "$<$<NOT:$<CONFIG:Debug>>:${CMAKE_C_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL}>"
+ -S ${CMAKE_CURRENT_SOURCE_DIR}/main.c -o main.s
+ COMMAND_EXPAND_LISTS
+ DEPENDS main.c
+ VERBATIM
+ )
+ endif()
+endif()
+
+
+if(SRCS)
+ set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}")
+ enable_language(ASM OPTIONAL)
+else()
+ message(STATUS "No assembler enabled, using C")
+ set(SRCS main.c)
+endif()
+
+add_executable(HelloAsm ${SRCS})
diff --git a/Tests/Assembler/main-linux-x86-gas.s b/Tests/Assembler/main-linux-x86-gas.s
new file mode 100644
index 0000000..da8e845
--- /dev/null
+++ b/Tests/Assembler/main-linux-x86-gas.s
@@ -0,0 +1,28 @@
+ .section .rodata
+ .align 4
+.LC0:
+ .string "hello assembler world, %d arguments given\n"
+ .text
+.globl main
+ .type main, @function
+main:
+ leal 4(%esp), %ecx
+ andl $-16, %esp
+ pushl -4(%ecx)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ecx
+ subl $20, %esp
+ movl (%ecx), %eax
+ movl %eax, 4(%esp)
+ movl $.LC0, (%esp)
+ call printf
+ movl $0, %eax
+ addl $20, %esp
+ popl %ecx
+ popl %ebp
+ leal -4(%ecx), %esp
+ ret
+ .size main, .-main
+ .ident "GCC: (GNU) 4.1.2 20060928 (prerelease) (Ubuntu 4.1.1-13ubuntu5)"
+ .section .note.GNU-stack,"",@progbits
diff --git a/Tests/Assembler/main.c b/Tests/Assembler/main.c
new file mode 100644
index 0000000..84a54d6
--- /dev/null
+++ b/Tests/Assembler/main.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+#ifdef __CLASSIC_C__
+int main()
+{
+ int argc;
+ char* argv[];
+#else
+int main(int argc, char* argv[])
+{
+#endif
+ printf("hello assembler world, %d arguments given\n", argc);
+ return 0;
+}
diff --git a/Tests/BootstrapTest.cmake b/Tests/BootstrapTest.cmake
new file mode 100644
index 0000000..137de78
--- /dev/null
+++ b/Tests/BootstrapTest.cmake
@@ -0,0 +1,18 @@
+file(MAKE_DIRECTORY "${bin_dir}")
+include(ProcessorCount)
+ProcessorCount(nproc)
+if(generator MATCHES "Ninja")
+ set(ninja_arg --generator=Ninja)
+endif()
+if(NOT nproc EQUAL 0)
+ set(parallel_arg --parallel=${nproc})
+endif()
+message(STATUS "running bootstrap: ${bootstrap} ${ninja_arg} ${parallel_arg}")
+execute_process(
+ COMMAND ${bootstrap} ${ninja_arg} ${parallel_arg}
+ WORKING_DIRECTORY "${bin_dir}"
+ RESULT_VARIABLE result
+ )
+if(result)
+ message(FATAL_ERROR "bootstrap failed: ${result}")
+endif()
diff --git a/Tests/BuildDepends/CMakeLists.txt b/Tests/BuildDepends/CMakeLists.txt
new file mode 100644
index 0000000..5ddae83
--- /dev/null
+++ b/Tests/BuildDepends/CMakeLists.txt
@@ -0,0 +1,475 @@
+# this test creates a static library and an executable
+# the source to the library is then changed
+# and the build is done on the executable and if things
+# are working the executable should relink with the new
+# value. The subdir Project contains the CMakelists.txt
+# and source files for the test project.
+cmake_minimum_required (VERSION 2.6)
+project(BuildDepends)
+
+# This entire test takes place during the initial
+# configure step. It should not run again when the
+# project is built.
+set(CMAKE_SUPPRESS_REGENERATION 1)
+
+# Xcode needs some help with the fancy dependencies in this test.
+if(XCODE AND XCODE_VERSION VERSION_LESS 5)
+ set(HELP_XCODE 1)
+endif()
+function(help_xcode_depends)
+ if(HELP_XCODE)
+ file(GLOB_RECURSE MACRO_OBJS
+ ${BuildDepends_BINARY_DIR}/Project/zot_macro_*.o*
+ )
+ if(MACRO_OBJS)
+ message("Helping Xcode by removing objects [${MACRO_OBJS}]")
+ file(REMOVE ${MACRO_OBJS})
+ endif()
+ endif()
+endfunction()
+
+# The Intel compiler causes the MSVC linker to crash during
+# incremental linking, so avoid the /INCREMENTAL:YES flag.
+if(WIN32 AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel")
+ set(_cmake_options "-DCMAKE_EXE_LINKER_FLAGS=")
+endif()
+
+if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
+ set(TEST_LINK_DEPENDS ${BuildDepends_BINARY_DIR}/Project/linkdep.txt)
+ file(WRITE ${TEST_LINK_DEPENDS} "1")
+endif()
+list(APPEND _cmake_options "-DTEST_LINK_DEPENDS=${TEST_LINK_DEPENDS}")
+
+list(APPEND _cmake_options "-DCMAKE_FORCE_DEPFILES=1")
+
+if(NOT CMAKE_GENERATOR MATCHES "Visual Studio ([^9]|9[0-9])")
+ set(TEST_MULTI3 1)
+ list(APPEND _cmake_options "-DTEST_MULTI3=1")
+endif()
+
+file(MAKE_DIRECTORY ${BuildDepends_BINARY_DIR}/Project)
+message("Creating Project/foo.cxx")
+write_file(${BuildDepends_BINARY_DIR}/Project/foo.cxx
+ "const char* foo() { return \"foo\";}" )
+
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot.hxx.in
+ "static const char* zot = \"zot\";\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/dir/header.txt
+ "#define HEADER_STRING \"ninja\"\n" )
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_custom.hxx.in
+ "static const char* zot_custom = \"zot_custom\";\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_macro_dir.hxx
+ "static const char* zot_macro_dir = \"zot_macro_dir\";\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_macro_tgt.hxx
+ "static const char* zot_macro_tgt = \"zot_macro_tgt\";\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_pch.hxx
+ "#ifndef ZOT_PCH_HXX\n"
+ "#define ZOT_PCH_HXX\n"
+ "static const char* zot_pch = \"zot_pch\";\n"
+ "#endif\n"
+ )
+
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/link_depends_no_shared_lib.h
+ "#define link_depends_no_shared_lib_value 1\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/link_depends_no_shared_exe.h
+ "#define link_depends_no_shared_exe_value 0\n")
+set(link_depends_no_shared_check_txt ${BuildDepends_BINARY_DIR}/Project/link_depends_no_shared_check.txt)
+
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/object_depends.txt "0\n")
+set(object_depends_check_txt ${BuildDepends_BINARY_DIR}/Project/object_depends_check.txt)
+
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/external.in "external original\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/multi1-in.txt "multi1-in original\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/multi2-stamp.txt "multi2-stamp original\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/multi3-stamp.txt "multi3-stamp original\n")
+
+help_xcode_depends()
+
+message("Building project first time")
+try_compile(RESULT
+ ${BuildDepends_BINARY_DIR}/Project
+ ${BuildDepends_SOURCE_DIR}/Project
+ testRebuild
+ CMAKE_FLAGS ${_cmake_options}
+ OUTPUT_VARIABLE OUTPUT)
+if(HELP_XCODE)
+ try_compile(RESULT
+ ${BuildDepends_BINARY_DIR}/Project
+ ${BuildDepends_SOURCE_DIR}/Project
+ testRebuild
+ OUTPUT_VARIABLE OUTPUT)
+ try_compile(RESULT
+ ${BuildDepends_BINARY_DIR}/Project
+ ${BuildDepends_SOURCE_DIR}/Project
+ testRebuild
+ OUTPUT_VARIABLE OUTPUT)
+endif()
+
+message("Output from first build:\n${OUTPUT}")
+if(NOT RESULT)
+ message(SEND_ERROR "Could not build test project (1)!")
+endif()
+
+# find and save the ninjadep executable
+set(ninjadep ${BuildDepends_BINARY_DIR}/Project/ninjadep${CMAKE_EXECUTABLE_SUFFIX})
+if(EXISTS
+ "${BuildDepends_BINARY_DIR}/Project/Debug/ninjadep${CMAKE_EXECUTABLE_SUFFIX}" )
+ message("found debug")
+ set(ninjadep
+ "${BuildDepends_BINARY_DIR}/Project/Debug/ninjadep${CMAKE_EXECUTABLE_SUFFIX}")
+endif()
+message("Running ${ninjadep} ")
+execute_process(COMMAND ${ninjadep} OUTPUT_VARIABLE out RESULT_VARIABLE runResult)
+string(REGEX REPLACE "[\r\n]" " " out "${out}")
+message("Run result: ${runResult} Output: \"${out}\"")
+
+if("${out}" STREQUAL "HEADER_STRING: ninja ")
+ message("Worked!")
+else()
+ message(SEND_ERROR "Project did not rebuild properly. Output[${out}]\n"
+ " expected [HEADER_STRING: ninja]")
+endif()
+
+set(bar ${BuildDepends_BINARY_DIR}/Project/bar${CMAKE_EXECUTABLE_SUFFIX})
+if(EXISTS
+ "${BuildDepends_BINARY_DIR}/Project/Debug/bar${CMAKE_EXECUTABLE_SUFFIX}" )
+ message("found debug")
+ set(bar
+ "${BuildDepends_BINARY_DIR}/Project/Debug/bar${CMAKE_EXECUTABLE_SUFFIX}")
+endif()
+set(zot ${BuildDepends_BINARY_DIR}/Project/zot${CMAKE_EXECUTABLE_SUFFIX})
+if(EXISTS
+ "${BuildDepends_BINARY_DIR}/Project/Debug/zot${CMAKE_EXECUTABLE_SUFFIX}" )
+ message("found debug")
+ set(zot
+ "${BuildDepends_BINARY_DIR}/Project/Debug/zot${CMAKE_EXECUTABLE_SUFFIX}")
+endif()
+
+message("Running ${bar} ")
+execute_process(COMMAND ${bar} OUTPUT_VARIABLE out RESULT_VARIABLE runResult)
+string(REGEX REPLACE "[\r\n]" " " out "${out}")
+message("Run result: ${runResult} Output: \"${out}\"")
+
+if("${out}" STREQUAL "foo ")
+ message("Worked!")
+else()
+ message(SEND_ERROR "Project did not initially build properly: ${out}")
+endif()
+
+message("Running ${zot} ")
+execute_process(COMMAND ${zot} OUTPUT_VARIABLE out RESULT_VARIABLE runResult)
+string(REGEX REPLACE "[\r\n]" " " out "${out}")
+message("Run result: ${runResult} Output: \"${out}\"")
+
+set(VALUE_UNCHANGED "[zot] [zot_custom] [zot_macro_dir] [zot_macro_tgt] [zot_pch] ")
+if("${out}" STREQUAL "${VALUE_UNCHANGED}")
+ message("Worked!")
+else()
+ message(SEND_ERROR "Project did not initially build properly: ${out}")
+endif()
+
+if(EXISTS "${link_depends_no_shared_check_txt}")
+ file(STRINGS "${link_depends_no_shared_check_txt}" link_depends_no_shared_check LIMIT_COUNT 1)
+ if("${link_depends_no_shared_check}" STREQUAL "1")
+ message(STATUS "link_depends_no_shared_exe is newer than link_depends_no_shared_lib as expected.")
+ else()
+ message(SEND_ERROR "Project did not initially build properly: "
+ "link_depends_no_shared_exe is older than link_depends_no_shared_lib.")
+ endif()
+else()
+ message(SEND_ERROR "Project did not initially build properly: "
+ "Targets link_depends_no_shared_lib and link_depends_no_shared_exe not both built.")
+endif()
+
+if(EXISTS ${BuildDepends_BINARY_DIR}/Project/external.out)
+ file(STRINGS ${BuildDepends_BINARY_DIR}/Project/external.out external_out)
+ if("${external_out}" STREQUAL "external original")
+ message(STATUS "external.out contains '${external_out}'")
+ else()
+ message(SEND_ERROR "Project did not initially build properly: "
+ "external.out contains '${external_out}'")
+ endif()
+else()
+ message(SEND_ERROR "Project did not initially build properly: "
+ "external.out is missing")
+endif()
+
+if(EXISTS ${BuildDepends_BINARY_DIR}/Project/multi1-out2-copy.txt)
+ file(STRINGS ${BuildDepends_BINARY_DIR}/Project/multi1-out2-copy.txt multi1_out)
+ if("${multi1_out}" STREQUAL "multi1-in original")
+ message(STATUS "multi1-out2-copy.txt contains '${multi1_out}'")
+ else()
+ message(SEND_ERROR "Project did not initially build properly: "
+ "multi1-out2-copy.txt contains '${multi1_out}'")
+ endif()
+else()
+ message(SEND_ERROR "Project did not initially build properly: "
+ "multi1-out2-copy.txt is missing")
+endif()
+
+if(EXISTS ${BuildDepends_BINARY_DIR}/Project/multi2-real.txt)
+ if(${BuildDepends_BINARY_DIR}/Project/multi2-real.txt
+ IS_NEWER_THAN ${BuildDepends_BINARY_DIR}/Project/multi2-stamp.txt)
+ message(STATUS "multi2-real.txt is newer than multi2-stamp.txt")
+ else()
+ message(SEND_ERROR "Project did not initially build properly: "
+ "multi2-real.txt is not newer than multi2-stamp.txt")
+ endif()
+else()
+ message(SEND_ERROR "Project did not initially build properly: "
+ "multi2-real.txt is missing")
+endif()
+
+if(TEST_MULTI3)
+ if(EXISTS ${BuildDepends_BINARY_DIR}/Project/multi3-real.txt)
+ if(${BuildDepends_BINARY_DIR}/Project/multi3-real.txt
+ IS_NEWER_THAN ${BuildDepends_BINARY_DIR}/Project/multi3-stamp.txt)
+ message(STATUS "multi3-real.txt is newer than multi3-stamp.txt")
+ else()
+ message(SEND_ERROR "Project did not initially build properly: "
+ "multi3-real.txt is not newer than multi3-stamp.txt")
+ endif()
+ else()
+ message(SEND_ERROR "Project did not initially build properly: "
+ "multi3-real.txt is missing")
+ endif()
+endif()
+
+message("Waiting 3 seconds...")
+execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 3)
+
+message("Modifying Project/foo.cxx")
+write_file(${BuildDepends_BINARY_DIR}/Project/foo.cxx
+ "const char* foo() { return \"foo changed\";}" )
+file(WRITE "${BuildDepends_BINARY_DIR}/Project/dir/header.txt"
+ "#define HEADER_STRING \"ninja changed\"\n" )
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot.hxx.in
+ "static const char* zot = \"zot changed\";\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_custom.hxx.in
+ "static const char* zot_custom = \"zot_custom changed\";\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_macro_dir.hxx
+ "static const char* zot_macro_dir = \"zot_macro_dir changed\";\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_macro_tgt.hxx
+ "static const char* zot_macro_tgt = \"zot_macro_tgt changed\";\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_pch.hxx
+ "#ifndef ZOT_PCH_HXX\n"
+ "#define ZOT_PCH_HXX\n"
+ "static const char* zot_pch = \"zot_pch changed\";\n"
+ "#endif\n"
+ )
+
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/link_depends_no_shared_lib.h
+ "#define link_depends_no_shared_lib_value 0\n")
+
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/object_depends.txt "1\n")
+
+if(TEST_LINK_DEPENDS)
+ file(WRITE ${TEST_LINK_DEPENDS} "2")
+endif()
+
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/external.in "external changed\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/multi1-in.txt "multi1-in changed\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/multi2-stamp.txt "multi2-stamp changed\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/multi3-stamp.txt "multi3-stamp changed\n")
+
+help_xcode_depends()
+
+message("Building project second time")
+try_compile(RESULT
+ ${BuildDepends_BINARY_DIR}/Project
+ ${BuildDepends_SOURCE_DIR}/Project
+ testRebuild
+ CMAKE_FLAGS ${_cmake_options}
+ OUTPUT_VARIABLE OUTPUT)
+
+# Xcode is in serious need of help here
+if(HELP_XCODE)
+ try_compile(RESULT
+ ${BuildDepends_BINARY_DIR}/Project
+ ${BuildDepends_SOURCE_DIR}/Project
+ testRebuild
+ OUTPUT_VARIABLE OUTPUT)
+ try_compile(RESULT
+ ${BuildDepends_BINARY_DIR}/Project
+ ${BuildDepends_SOURCE_DIR}/Project
+ testRebuild
+ OUTPUT_VARIABLE OUTPUT)
+endif()
+
+message("Output from second build:\n${OUTPUT}")
+if(NOT RESULT)
+ message(SEND_ERROR "Could not build test project (2)!")
+endif()
+if(EXISTS
+ "${BuildDepends_BINARY_DIR}/Project/Debug/bar${CMAKE_EXECUTABLE_SUFFIX}" )
+ message("found debug")
+endif()
+if(EXISTS
+ "${BuildDepends_BINARY_DIR}/Project/Debug/zot${CMAKE_EXECUTABLE_SUFFIX}" )
+ message("found debug")
+endif()
+
+message("Running ${ninjadep} ")
+execute_process(COMMAND ${ninjadep} OUTPUT_VARIABLE out RESULT_VARIABLE runResult)
+string(REGEX REPLACE "[\r\n]" " " out "${out}")
+message("Run result: ${runResult} Output: \"${out}\"")
+
+if("${out}" STREQUAL "HEADER_STRING: ninja changed ")
+ message("Worked!")
+else()
+ message(SEND_ERROR "Project did not rebuild properly. Output[${out}]\n"
+ " expected [HEADER_STRING: ninja changed]")
+endif()
+
+message("Running ${bar} ")
+execute_process(COMMAND ${bar} OUTPUT_VARIABLE out RESULT_VARIABLE runResult)
+string(REGEX REPLACE "[\r\n]" " " out "${out}")
+message("Run result: ${runResult} Output: \"${out}\"")
+
+if("${out}" STREQUAL "foo changed ")
+ message("Worked!")
+else()
+ message(SEND_ERROR "Project did not rebuild properly!")
+endif()
+
+message("Running ${zot} ")
+execute_process(COMMAND ${zot} OUTPUT_VARIABLE out RESULT_VARIABLE runResult)
+string(REGEX REPLACE "[\r\n]" " " out "${out}")
+message("Run result: ${runResult} Output: \"${out}\"")
+
+set(VALUE_CHANGED
+ "[zot changed] [zot_custom changed] [zot_macro_dir changed] [zot_macro_tgt changed] [zot_pch changed] "
+ )
+if("${out}" STREQUAL "${VALUE_CHANGED}")
+ message("Worked!")
+else()
+ message(SEND_ERROR "Project did not rebuild properly!")
+endif()
+
+if(TEST_LINK_DEPENDS)
+ set(linkdep ${BuildDepends_BINARY_DIR}/Project/linkdep${CMAKE_EXECUTABLE_SUFFIX})
+ if(${linkdep} IS_NEWER_THAN ${TEST_LINK_DEPENDS})
+ message("LINK_DEPENDS worked")
+ else()
+ message(SEND_ERROR "LINK_DEPENDS failed. Executable
+ ${linkdep}
+is not newer than dependency
+ ${TEST_LINK_DEPENDS}
+")
+ endif()
+
+ set(linkdep2 ${BuildDepends_BINARY_DIR}/Project/linkdep2${CMAKE_EXECUTABLE_SUFFIX})
+ if(${linkdep2} IS_NEWER_THAN ${TEST_LINK_DEPENDS})
+ message("INTERFACE_LINK_DEPENDS worked")
+ else()
+ message(SEND_ERROR "INTERFACE_LINK_DEPENDS failed. Executable
+ ${linkdep2}
+is not newer than dependency
+ ${TEST_LINK_DEPENDS}
+")
+ endif()
+
+ set(linkdep3 ${BuildDepends_BINARY_DIR}/Project/linkdep3${CMAKE_EXECUTABLE_SUFFIX})
+ if(${linkdep3} IS_NEWER_THAN ${TEST_LINK_DEPENDS})
+ message("$<LINK_LANGUAGE> in LINK_DEPENDS worked")
+ else()
+ message(SEND_ERROR "$<LINK_LANGUAGE> in LINK_DEPENDS failed. Executable
+ ${linkdep3}
+is not newer than dependency
+ ${TEST_LINK_DEPENDS}
+")
+ endif()
+
+ set(linkdep4 ${BuildDepends_BINARY_DIR}/Project/linkdep4${CMAKE_EXECUTABLE_SUFFIX})
+ if(${linkdep4} IS_NEWER_THAN ${TEST_LINK_DEPENDS})
+ message("$<LINK_LANGUAGE> in INTERFACE_LINK_DEPENDS worked")
+ else()
+ message(SEND_ERROR "$<LINK_LANGUAGE> in INTERFACE_LINK_DEPENDS failed. Executable
+ ${linkdep4}
+is not newer than dependency
+ ${TEST_LINK_DEPENDS}
+")
+ endif()
+endif()
+
+if(EXISTS "${link_depends_no_shared_check_txt}")
+ file(STRINGS "${link_depends_no_shared_check_txt}" link_depends_no_shared_check LIMIT_COUNT 1)
+ if("${link_depends_no_shared_check}" STREQUAL "0")
+ message(STATUS "link_depends_no_shared_exe is older than link_depends_no_shared_lib as expected.")
+ elseif(XCODE AND NOT XCODE_VERSION VERSION_LESS 5)
+ message(STATUS "Known limitation: link_depends_no_shared_exe is newer than link_depends_no_shared_lib but we cannot stop Xcode ${XCODE_VERSION} from enforcing this dependency.")
+ else()
+ message(SEND_ERROR "Project did not rebuild properly: link_depends_no_shared_exe is newer than link_depends_no_shared_lib.")
+ endif()
+else()
+ message(SEND_ERROR "Project did not rebuild properly. "
+ "Targets link_depends_no_shared_lib and link_depends_no_shared_exe not both built.")
+endif()
+
+if(EXISTS "${object_depends_check_txt}")
+ file(STRINGS "${object_depends_check_txt}" object_depends_check LIMIT_COUNT 1)
+ if("${object_depends_check}" STREQUAL "1")
+ message(STATUS "object_depends exe is newer than object_depends.txt as expected.")
+ elseif(CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
+ message(STATUS "Known limitation: OBJECT_DEPENDS does not work on ${CMAKE_GENERATOR}")
+ else()
+ message(SEND_ERROR "Project did not rebuild properly: object_depends exe is not newer than object_depends.txt.")
+ endif()
+else()
+ message(SEND_ERROR "Project did not rebuild properly. "
+ "object_depends exe and object_depends.txt are not both present.")
+endif()
+
+if(EXISTS ${BuildDepends_BINARY_DIR}/Project/external.out)
+ file(STRINGS ${BuildDepends_BINARY_DIR}/Project/external.out external_out)
+ if("${external_out}" STREQUAL "external changed")
+ message(STATUS "external.out contains '${external_out}'")
+ else()
+ message(SEND_ERROR "Project did not rebuild properly: "
+ "external.out contains '${external_out}'")
+ endif()
+else()
+ message(SEND_ERROR "Project did not rebuild properly: "
+ "external.out is missing")
+endif()
+
+if(EXISTS ${BuildDepends_BINARY_DIR}/Project/multi1-out2-copy.txt)
+ file(STRINGS ${BuildDepends_BINARY_DIR}/Project/multi1-out2-copy.txt multi1_out)
+ if("${multi1_out}" STREQUAL "multi1-in changed")
+ message(STATUS "multi1-out2-copy.txt contains '${multi1_out}'")
+ else()
+ message(SEND_ERROR "Project did not rebuild properly: "
+ "multi1-out2-copy.txt contains '${multi1_out}'")
+ endif()
+else()
+ message(SEND_ERROR "Project did not rebuild properly: "
+ "multi1-out2-copy.txt is missing")
+endif()
+
+if(EXISTS ${BuildDepends_BINARY_DIR}/Project/multi2-real.txt)
+ if(${BuildDepends_BINARY_DIR}/Project/multi2-real.txt
+ IS_NEWER_THAN ${BuildDepends_BINARY_DIR}/Project/multi2-stamp.txt)
+ message(STATUS "multi2-real.txt is newer than multi2-stamp.txt")
+ else()
+ message(SEND_ERROR "Project did not rebuild properly: "
+ "multi2-real.txt is not newer than multi2-stamp.txt")
+ endif()
+else()
+ message(SEND_ERROR "Project did not rebuild properly: "
+ "multi2-real.txt is missing")
+endif()
+
+if(TEST_MULTI3)
+ if(EXISTS ${BuildDepends_BINARY_DIR}/Project/multi3-real.txt)
+ if(${BuildDepends_BINARY_DIR}/Project/multi3-real.txt
+ IS_NEWER_THAN ${BuildDepends_BINARY_DIR}/Project/multi3-stamp.txt)
+ message(STATUS "multi3-real.txt is newer than multi3-stamp.txt")
+ else()
+ message(SEND_ERROR "Project did not rebuild properly: "
+ "multi3-real.txt is not newer than multi3-stamp.txt")
+ endif()
+ else()
+ message(SEND_ERROR "Project did not rebuild properly: "
+ "multi3-real.txt is missing")
+ endif()
+endif()
diff --git a/Tests/BuildDepends/Project/CMakeLists.txt b/Tests/BuildDepends/Project/CMakeLists.txt
new file mode 100644
index 0000000..c2576f3
--- /dev/null
+++ b/Tests/BuildDepends/Project/CMakeLists.txt
@@ -0,0 +1,225 @@
+cmake_minimum_required(VERSION 2.6)
+project(testRebuild)
+
+if(APPLE)
+ set(CMake_TEST_XCODE_VERSION 0)
+ if(XCODE_VERSION)
+ set(CMake_TEST_XCODE_VERSION "${XCODE_VERSION}")
+ else()
+ execute_process(
+ COMMAND xcodebuild -version
+ OUTPUT_VARIABLE _version ERROR_VARIABLE _version
+ )
+ if(_version MATCHES "^Xcode ([0-9]+(\\.[0-9]+)*)")
+ set(CMake_TEST_XCODE_VERSION "${CMAKE_MATCH_1}")
+ endif()
+ endif()
+ # only use multi-arch if the sysroot exists on this machine
+ # Ninja needs -M which could not be used with multiple -arch flags
+ if(EXISTS "${CMAKE_OSX_SYSROOT}" AND NOT "${CMAKE_GENERATOR}" MATCHES "Ninja")
+ if(CMake_TEST_XCODE_VERSION VERSION_GREATER_EQUAL 10)
+ # Arch 'i386' no longer works in Xcode 10.
+ set(CMAKE_OSX_ARCHITECTURES x86_64)
+ elseif(CMake_TEST_XCODE_VERSION VERSION_GREATER_EQUAL 4)
+ # Arch 'ppc' no longer works in Xcode 4.
+ set(CMAKE_OSX_ARCHITECTURES i386 x86_64)
+ else()
+ set(CMAKE_OSX_ARCHITECTURES ppc i386)
+ endif()
+ endif()
+endif()
+
+add_library(foo STATIC ${testRebuild_BINARY_DIR}/foo.cxx)
+set_target_properties(foo PROPERTIES OUTPUT_NAME "foolib")
+# Add a generated header that regenerates when the generator is
+# rebuilt.
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/regen.h
+ COMMAND generator ${CMAKE_CURRENT_BINARY_DIR}/regen.h regen
+ DEPENDS generator # adds file-level dependency to re-run rule
+ )
+
+# Add a generated header that does NOT regenerate when the generator
+# is rebuilt.
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/noregen.h
+ COMMAND generator ${CMAKE_CURRENT_BINARY_DIR}/noregen.h noregen
+ )
+
+# Test that the generator rebuilds when the static library source file
+# changes. This should cause regen.h to be recreated also.
+add_executable(generator generator.cxx)
+target_link_libraries(generator foo)
+set_target_properties(generator PROPERTIES OUTPUT_NAME "gen")
+
+# Build an executable to drive the build and rebuild.
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+add_executable(bar bar.cxx
+ ${CMAKE_CURRENT_BINARY_DIR}/regen.h
+ ${CMAKE_CURRENT_BINARY_DIR}/noregen.h
+ )
+
+if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12)
+ target_compile_definitions(bar PRIVATE XCODE_NEW_BUILD_SYSTEM)
+endif()
+
+#-----------------------------------------------------------------------------
+if("${CMAKE_GENERATOR}" MATCHES "Make")
+ # Test the IMPLICIT_DEPENDS feature.
+ set(ZOT_DEPENDS IMPLICIT_DEPENDS CXX ${CMAKE_CURRENT_SOURCE_DIR}/dep.cxx)
+ set(ZOT_CUSTOM_DEP
+ IMPLICIT_DEPENDS CXX ${CMAKE_CURRENT_SOURCE_DIR}/dep_custom.cxx
+ CXX ${CMAKE_CURRENT_SOURCE_DIR}/dep_custom2.cxx )
+else()
+ # No IMPLICIT_DEPENDS...just depend directly.
+ set(ZOT_DEPENDS DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/zot.hxx.in)
+ set(ZOT_CUSTOM_DEP DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/zot_custom.hxx.in)
+endif()
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zot.hxx
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_BINARY_DIR}/zot.hxx.in
+ ${CMAKE_CURRENT_BINARY_DIR}/zot.hxx
+ ${ZOT_DEPENDS}
+ )
+
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zot_custom.hxx
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_BINARY_DIR}/zot_custom.hxx.in
+ ${CMAKE_CURRENT_BINARY_DIR}/zot_custom.hxx
+ ${ZOT_CUSTOM_DEP}
+ )
+add_custom_target(zot_custom ALL DEPENDS
+ ${CMAKE_CURRENT_BINARY_DIR}/zot_custom.hxx)
+
+add_executable(zot zot.cxx ${CMAKE_CURRENT_BINARY_DIR}/zot.hxx
+ zot_macro_dir.cxx zot_macro_tgt.cxx)
+add_dependencies(zot zot_custom)
+
+add_library(zot_pch zot_pch.cxx)
+target_link_libraries(zot zot_pch)
+if(NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;$]")
+ target_precompile_headers(zot_pch PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/zot_pch.hxx)
+endif()
+if (CMAKE_CXX_DEPENDS_USE_COMPILER AND
+ CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.4")
+ # Mixing pre-compile headers and flags to generate dependencies (-M options family)
+ # causes the compiler to crash
+ set_property(TARGET zot_pch PROPERTY DISABLE_PRECOMPILE_HEADERS ON)
+endif()
+
+# Test the #include line macro transformation rule support.
+set_property(
+ TARGET zot
+ PROPERTY IMPLICIT_DEPENDS_INCLUDE_TRANSFORM "ZOT_TGT(%)=<zot_%_tgt.hxx>"
+ )
+
+set_property(
+ DIRECTORY
+ PROPERTY IMPLICIT_DEPENDS_INCLUDE_TRANSFORM "ZOT_DIR(%)=<zot_%_dir.hxx>"
+ )
+
+if(TEST_LINK_DEPENDS)
+ add_executable(linkdep linkdep.cxx)
+ set_property(TARGET linkdep PROPERTY LINK_DEPENDS $<1:${TEST_LINK_DEPENDS}>)
+
+ add_library(foo_interface INTERFACE)
+ set_property(TARGET foo_interface PROPERTY INTERFACE_LINK_DEPENDS $<1:${TEST_LINK_DEPENDS}>)
+ add_executable(linkdep2 linkdep.cxx)
+ target_link_libraries(linkdep2 PRIVATE foo_interface)
+
+ add_executable(linkdep3 linkdep.cxx)
+ set_property(TARGET linkdep3 PROPERTY LINK_DEPENDS $<$<LINK_LANGUAGE:CXX>:${TEST_LINK_DEPENDS}>)
+
+ add_library(foo_interface2 INTERFACE)
+ set_property(TARGET foo_interface2 PROPERTY INTERFACE_LINK_DEPENDS $<$<LINK_LANGUAGE:CXX>:${TEST_LINK_DEPENDS}>)
+ add_executable(linkdep4 linkdep.cxx)
+ target_link_libraries(linkdep4 PRIVATE foo_interface2)
+endif()
+
+add_library(link_depends_no_shared_lib SHARED link_depends_no_shared_lib.c
+ ${CMAKE_CURRENT_BINARY_DIR}/link_depends_no_shared_lib.h)
+add_executable(link_depends_no_shared_exe link_depends_no_shared_exe.c
+ ${CMAKE_CURRENT_BINARY_DIR}/link_depends_no_shared_exe.h)
+target_link_libraries(link_depends_no_shared_exe link_depends_no_shared_lib)
+set_property(TARGET link_depends_no_shared_exe PROPERTY LINK_DEPENDS_NO_SHARED 1)
+add_custom_target(link_depends_no_shared_check ALL
+ COMMAND ${CMAKE_COMMAND}
+ -Dlib=$<TARGET_FILE:link_depends_no_shared_lib>
+ -Dexe=$<TARGET_FILE:link_depends_no_shared_exe>
+ -Dout=${CMAKE_CURRENT_BINARY_DIR}/link_depends_no_shared_check.txt
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/link_depends_no_shared_check.cmake
+ )
+add_dependencies(link_depends_no_shared_check link_depends_no_shared_exe)
+
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dir/header.h
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/dir/header.txt
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_BINARY_DIR}/dir/header.txt
+ ${CMAKE_CURRENT_BINARY_DIR}/dir/header.h
+ )
+
+set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/dir/header.h
+ PROPERTIES GENERATED 1)
+
+add_custom_target(header_tgt DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/dir/header.h)
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+add_executable(ninjadep ninjadep.cpp)
+add_dependencies(ninjadep header_tgt)
+
+include(ExternalProject)
+ExternalProject_Add(ExternalBuild
+ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/External
+ BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/External
+ STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/External/Stamp
+ BUILD_ALWAYS 1
+ CMAKE_ARGS
+ -Dexternal_in=${CMAKE_CURRENT_BINARY_DIR}/external.in
+ -Dexternal_out=${CMAKE_CURRENT_BINARY_DIR}/external.out
+ INSTALL_COMMAND ""
+ )
+
+add_custom_command(
+ OUTPUT multi1-out1.txt multi1-out2.txt
+ COMMAND ${CMAKE_COMMAND} -E copy multi1-in.txt multi1-out1.txt
+ COMMAND ${CMAKE_COMMAND} -E copy multi1-in.txt multi1-out2.txt
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/multi1-in.txt
+ )
+add_custom_command(
+ OUTPUT multi1-out2-copy.txt
+ COMMAND ${CMAKE_COMMAND} -E copy multi1-out2.txt multi1-out2-copy.txt
+ DEPENDS multi1-out2.txt
+ )
+add_custom_target(multi1 ALL DEPENDS multi1-out2-copy.txt)
+
+# Test having the first output never created.
+add_custom_command(
+ OUTPUT multi2-dummy.txt multi2-real.txt
+ COMMAND ${CMAKE_COMMAND} -E touch multi2-real.txt
+ )
+set_property(SOURCE multi2-real.txt multi2-dummy.txt PROPERTY SYMBOLIC 1)
+add_custom_target(multi2 ALL DEPENDS multi2-real.txt)
+
+if(TEST_MULTI3)
+ # Test having the second output never created. Does not work with msbuild.
+ add_custom_command(
+ OUTPUT multi3-real.txt multi3-dummy.txt
+ COMMAND ${CMAKE_COMMAND} -E touch multi3-real.txt
+ )
+ set_property(SOURCE multi3-real.txt multi3-dummy.txt PROPERTY SYMBOLIC 1)
+ add_custom_target(multi3 ALL DEPENDS multi3-real.txt)
+endif()
+
+add_executable(object_depends object_depends.cxx)
+set_property(SOURCE object_depends.cxx PROPERTY OBJECT_DEPENDS
+ ${CMAKE_CURRENT_BINARY_DIR}/object_depends.txt)
+add_custom_target(object_depends_check ALL
+ COMMAND ${CMAKE_COMMAND}
+ -Dexe=$<TARGET_FILE:object_depends>
+ -Dout=${CMAKE_CURRENT_BINARY_DIR}/object_depends_check.txt
+ -Dtxt=${CMAKE_CURRENT_BINARY_DIR}/object_depends.txt
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/object_depends_check.cmake
+ )
+add_dependencies(object_depends_check object_depends)
diff --git a/Tests/BuildDepends/Project/External/CMakeLists.txt b/Tests/BuildDepends/Project/External/CMakeLists.txt
new file mode 100644
index 0000000..c6015b6
--- /dev/null
+++ b/Tests/BuildDepends/Project/External/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.0)
+project(BuildDependsExternal NONE)
+if(NOT DEFINED external_in)
+ message(FATAL_ERROR "Define external_in")
+endif()
+if(NOT DEFINED external_out)
+ message(FATAL_ERROR "Define external_out")
+endif()
+add_custom_command(
+ OUTPUT ${external_out}
+ COMMAND ${CMAKE_COMMAND} -E copy ${external_in} ${external_out}
+ DEPENDS ${external_in}
+ )
+add_custom_target(drive ALL DEPENDS ${external_out})
diff --git a/Tests/BuildDepends/Project/bar.cxx b/Tests/BuildDepends/Project/bar.cxx
new file mode 100644
index 0000000..825d661
--- /dev/null
+++ b/Tests/BuildDepends/Project/bar.cxx
@@ -0,0 +1,24 @@
+#include <noregen.h>
+#include <regen.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char** argv)
+{
+ /* Make sure the noregen header was not regenerated. */
+ if (strcmp("foo", noregen_string) != 0) {
+#ifdef XCODE_NEW_BUILD_SYSTEM
+ fprintf(stderr,
+ "Known limitation: noregen.h was regenerated "
+ "but we cannot stop Xcode from doing this!\n");
+#else
+ printf("FAILED: noregen.h was regenerated!\n");
+ return 1;
+#endif
+ }
+
+ /* Print out the string that should have been regenerated. */
+ printf("%s\n", regen_string);
+ fflush(stdout);
+ return 0;
+}
diff --git a/Tests/BuildDepends/Project/dep.cxx b/Tests/BuildDepends/Project/dep.cxx
new file mode 100644
index 0000000..6cfebe3
--- /dev/null
+++ b/Tests/BuildDepends/Project/dep.cxx
@@ -0,0 +1 @@
+#include <zot.hxx.in>
diff --git a/Tests/BuildDepends/Project/dep_custom.cxx b/Tests/BuildDepends/Project/dep_custom.cxx
new file mode 100644
index 0000000..b6ac548
--- /dev/null
+++ b/Tests/BuildDepends/Project/dep_custom.cxx
@@ -0,0 +1 @@
+#include <zot_custom.hxx.in>
diff --git a/Tests/BuildDepends/Project/dep_custom2.cxx b/Tests/BuildDepends/Project/dep_custom2.cxx
new file mode 100644
index 0000000..ac9dee1
--- /dev/null
+++ b/Tests/BuildDepends/Project/dep_custom2.cxx
@@ -0,0 +1,2 @@
+#include <zot_custom.hxx.in>
+// some comment
diff --git a/Tests/BuildDepends/Project/generator.cxx b/Tests/BuildDepends/Project/generator.cxx
new file mode 100644
index 0000000..5a83a7f
--- /dev/null
+++ b/Tests/BuildDepends/Project/generator.cxx
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+extern const char* foo();
+
+int main(int argc, const char* argv[])
+{
+ if (argc < 3) {
+ fprintf(stderr, "Must specify output file and symbol prefix!");
+ return 1;
+ }
+ if (FILE* fout = fopen(argv[1], "w")) {
+ fprintf(fout, "static const char* %s_string = \"%s\";\n", argv[2], foo());
+ fclose(fout);
+ } else {
+ fprintf(stderr, "Could not open output file \"%s\"", argv[1]);
+ return 1;
+ }
+ return 0;
+}
diff --git a/Tests/BuildDepends/Project/link_depends_no_shared_check.cmake b/Tests/BuildDepends/Project/link_depends_no_shared_check.cmake
new file mode 100644
index 0000000..3a61137
--- /dev/null
+++ b/Tests/BuildDepends/Project/link_depends_no_shared_check.cmake
@@ -0,0 +1,7 @@
+if(NOT EXISTS "${lib}" OR NOT EXISTS "${exe}")
+ file(REMOVE "${out}")
+elseif("${exe}" IS_NEWER_THAN "${lib}")
+ file(WRITE "${out}" "1\n")
+else()
+ file(WRITE "${out}" "0\n")
+endif()
diff --git a/Tests/BuildDepends/Project/link_depends_no_shared_exe.c b/Tests/BuildDepends/Project/link_depends_no_shared_exe.c
new file mode 100644
index 0000000..cfaf051
--- /dev/null
+++ b/Tests/BuildDepends/Project/link_depends_no_shared_exe.c
@@ -0,0 +1,9 @@
+#include "link_depends_no_shared_exe.h"
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+ int link_depends_no_shared_lib(void);
+int main()
+{
+ return link_depends_no_shared_lib() + link_depends_no_shared_exe_value;
+}
diff --git a/Tests/BuildDepends/Project/link_depends_no_shared_lib.c b/Tests/BuildDepends/Project/link_depends_no_shared_lib.c
new file mode 100644
index 0000000..d66c636
--- /dev/null
+++ b/Tests/BuildDepends/Project/link_depends_no_shared_lib.c
@@ -0,0 +1,8 @@
+#include "link_depends_no_shared_lib.h"
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int link_depends_no_shared_lib(void)
+{
+ return link_depends_no_shared_lib_value;
+}
diff --git a/Tests/BuildDepends/Project/linkdep.cxx b/Tests/BuildDepends/Project/linkdep.cxx
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/BuildDepends/Project/linkdep.cxx
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/BuildDepends/Project/ninjadep.cpp b/Tests/BuildDepends/Project/ninjadep.cpp
new file mode 100644
index 0000000..d3447e2
--- /dev/null
+++ b/Tests/BuildDepends/Project/ninjadep.cpp
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+#include "dir/header.h"
+
+int main()
+{
+ printf("HEADER_STRING: %s\n", HEADER_STRING);
+}
diff --git a/Tests/BuildDepends/Project/object_depends.cxx b/Tests/BuildDepends/Project/object_depends.cxx
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/BuildDepends/Project/object_depends.cxx
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/BuildDepends/Project/object_depends_check.cmake b/Tests/BuildDepends/Project/object_depends_check.cmake
new file mode 100644
index 0000000..e009892
--- /dev/null
+++ b/Tests/BuildDepends/Project/object_depends_check.cmake
@@ -0,0 +1,7 @@
+if(NOT EXISTS "${txt}" OR NOT EXISTS "${exe}")
+ file(REMOVE "${out}")
+elseif("${exe}" IS_NEWER_THAN "${txt}")
+ file(WRITE "${out}" "1\n")
+else()
+ file(WRITE "${out}" "0\n")
+endif()
diff --git a/Tests/BuildDepends/Project/zot.cxx b/Tests/BuildDepends/Project/zot.cxx
new file mode 100644
index 0000000..2d08c4b
--- /dev/null
+++ b/Tests/BuildDepends/Project/zot.cxx
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <zot.hxx>
+#include <zot_custom.hxx>
+
+const char* zot_macro_dir_f();
+const char* zot_macro_tgt_f();
+const char* zot_pch_f();
+
+int main()
+{
+ printf("[%s] [%s] [%s] [%s] [%s]\n", zot, zot_custom, zot_macro_dir_f(),
+ zot_macro_tgt_f(), zot_pch_f());
+ fflush(stdout);
+ return 0;
+}
diff --git a/Tests/BuildDepends/Project/zot_macro_dir.cxx b/Tests/BuildDepends/Project/zot_macro_dir.cxx
new file mode 100644
index 0000000..733a4b3
--- /dev/null
+++ b/Tests/BuildDepends/Project/zot_macro_dir.cxx
@@ -0,0 +1,7 @@
+#define ZOT_DIR(x) <zot_##x##_dir.hxx>
+#include ZOT_DIR(macro)
+
+const char* zot_macro_dir_f()
+{
+ return zot_macro_dir;
+}
diff --git a/Tests/BuildDepends/Project/zot_macro_tgt.cxx b/Tests/BuildDepends/Project/zot_macro_tgt.cxx
new file mode 100644
index 0000000..182ee16
--- /dev/null
+++ b/Tests/BuildDepends/Project/zot_macro_tgt.cxx
@@ -0,0 +1,7 @@
+#define ZOT_TGT(x) <zot_##x##_tgt.hxx>
+#include ZOT_TGT(macro)
+
+const char* zot_macro_tgt_f()
+{
+ return zot_macro_tgt;
+}
diff --git a/Tests/BuildDepends/Project/zot_pch.cxx b/Tests/BuildDepends/Project/zot_pch.cxx
new file mode 100644
index 0000000..d9d04c7
--- /dev/null
+++ b/Tests/BuildDepends/Project/zot_pch.cxx
@@ -0,0 +1,6 @@
+#include <zot_pch.hxx>
+
+const char* zot_pch_f()
+{
+ return zot_pch;
+}
diff --git a/Tests/BundleGeneratorTest/BundleIcon.icns b/Tests/BundleGeneratorTest/BundleIcon.icns
new file mode 100644
index 0000000..8808dd6
--- /dev/null
+++ b/Tests/BundleGeneratorTest/BundleIcon.icns
Binary files differ
diff --git a/Tests/BundleGeneratorTest/CMakeLists.txt b/Tests/BundleGeneratorTest/CMakeLists.txt
new file mode 100644
index 0000000..cf7e2ce
--- /dev/null
+++ b/Tests/BundleGeneratorTest/CMakeLists.txt
@@ -0,0 +1,33 @@
+project(BundleGeneratorTest)
+
+cmake_minimum_required(VERSION 2.8.12)
+
+# Build a shared library and install it in lib/
+add_library(Library SHARED Library.cxx)
+install(TARGETS Library DESTINATION lib)
+
+# Build an executable and install it in bin/
+add_executable(Executable Executable.cxx)
+target_link_libraries(Executable Library)
+install(TARGETS Executable DESTINATION bin)
+
+# Use the bundle-generator for packaging ...
+set(CPACK_GENERATOR "Bundle")
+set(CPACK_BUNDLE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/BundleIcon.icns")
+set(CPACK_BUNDLE_NAME "BundleGeneratorTest")
+set(CPACK_BUNDLE_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist")
+set(CPACK_BUNDLE_STARTUP_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/StartupCommand")
+set(CPACK_PACKAGE_DESCRIPTION "Project for testing OSX bundle generation")
+
+# The custom volume icon is a copy of the normal Mac OSX volume icon, but
+# on a white background. This is to differentiate it from the normal one
+# so that you can verify that the custom icon is being used by doing a
+# visual inspection of the mounted volume... This was added when fixing
+# issue #7523...
+#
+set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/CustomVolumeIcon.icns")
+
+set(CPACK_PACKAGE_NAME "BundleGeneratorTest")
+set(CPACK_PACKAGE_VERSION "0.1")
+
+include(CPack)
diff --git a/Tests/BundleGeneratorTest/CustomVolumeIcon.icns b/Tests/BundleGeneratorTest/CustomVolumeIcon.icns
new file mode 100644
index 0000000..3862a51
--- /dev/null
+++ b/Tests/BundleGeneratorTest/CustomVolumeIcon.icns
Binary files differ
diff --git a/Tests/BundleGeneratorTest/Executable.cxx b/Tests/BundleGeneratorTest/Executable.cxx
new file mode 100644
index 0000000..3d7e0d7
--- /dev/null
+++ b/Tests/BundleGeneratorTest/Executable.cxx
@@ -0,0 +1,7 @@
+extern void print_message(const char* const Message);
+
+int main(int argc, char* argv[])
+{
+ print_message("Howdy, World!\n");
+ return 0;
+}
diff --git a/Tests/BundleGeneratorTest/Info.plist b/Tests/BundleGeneratorTest/Info.plist
new file mode 100644
index 0000000..e5a7d00
--- /dev/null
+++ b/Tests/BundleGeneratorTest/Info.plist
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+ <dict>
+ <key>CFBundleExecutable</key>
+ <string>BundleGeneratorTest</string>
+ <key>CFBundleIconFile</key>
+ <string>BundleGeneratorTest.icns</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ </dict>
+</plist>
diff --git a/Tests/BundleGeneratorTest/Library.cxx b/Tests/BundleGeneratorTest/Library.cxx
new file mode 100644
index 0000000..c4f40c4
--- /dev/null
+++ b/Tests/BundleGeneratorTest/Library.cxx
@@ -0,0 +1,6 @@
+#include <iostream>
+
+void print_message(const char* const Message)
+{
+ std::cout << Message;
+}
diff --git a/Tests/BundleGeneratorTest/StartupCommand b/Tests/BundleGeneratorTest/StartupCommand
new file mode 100755
index 0000000..5bc5ad2
--- /dev/null
+++ b/Tests/BundleGeneratorTest/StartupCommand
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+BUNDLE="`echo "$0" | sed -e 's/\/Contents\/MacOS\/.*//'`"
+RESOURCES="$BUNDLE/Contents/Resources"
+
+echo "BUNDLE: $BUNDLE"
+echo "RESOURCES: $RESOURCES"
+
+export DYLD_LIBRARY_PATH=$RESOURCES/lib
+
+exec "$RESOURCES/bin/Executable"
+
diff --git a/Tests/BundleTest/BundleLib.cxx b/Tests/BundleTest/BundleLib.cxx
new file mode 100644
index 0000000..d25ad27
--- /dev/null
+++ b/Tests/BundleTest/BundleLib.cxx
@@ -0,0 +1,62 @@
+#include <CoreFoundation/CoreFoundation.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int fileExists(char* filename)
+{
+#ifndef R_OK
+# define R_OK 04
+#endif
+ if (access(filename, R_OK) != 0) {
+ printf("Cannot find file: %s\n", filename);
+ return 0;
+ }
+ return 1;
+}
+
+int findBundleFile(char* exec, const char* file)
+{
+ int res;
+ char* nexec = strdup(exec);
+ char* fpath = (char*)malloc(strlen(exec) + 100);
+ int cc;
+ int cnt = 0;
+ printf("Process executable name: %s\n", exec);
+
+ // Remove the executable name and directory name
+ for (cc = strlen(nexec) - 1; cc > 0; cc--) {
+ if (nexec[cc] == '/') {
+ nexec[cc] = 0;
+ if (cnt == 1) {
+ break;
+ }
+ cnt++;
+ }
+ }
+ printf("Process executable path: %s\n", nexec);
+ sprintf(fpath, "%s/%s", nexec, file);
+ printf("Check for file: %s\n", fpath);
+ res = fileExists(fpath);
+ free(nexec);
+ free(fpath);
+ return res;
+}
+
+int foo(char* exec)
+{
+ // Call a CoreFoundation function...
+ //
+ CFBundleRef br = CFBundleGetMainBundle();
+ (void)br;
+
+ int res1 = findBundleFile(exec, "Resources/randomResourceFile.plist");
+ int res2 = findBundleFile(exec, "Other/SomeRandomFile.txt");
+ int res3 = findBundleFile(exec, "Other/README.rst");
+ if (!res1 || !res2 || !res3) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/Tests/BundleTest/BundleSubDir/CMakeLists.txt b/Tests/BundleTest/BundleSubDir/CMakeLists.txt
new file mode 100644
index 0000000..ceb5216
--- /dev/null
+++ b/Tests/BundleTest/BundleSubDir/CMakeLists.txt
@@ -0,0 +1,43 @@
+project(BundleSubDir)
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/randomResourceFile.plist"
+ COMMAND /bin/cp
+ ARGS "${BundleTest_SOURCE_DIR}/randomResourceFile.plist.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/randomResourceFile.plist")
+
+set_source_files_properties(
+ "${CMAKE_CURRENT_BINARY_DIR}/randomResourceFile.plist"
+ PROPERTIES
+ MACOSX_PACKAGE_LOCATION Resources
+ )
+
+set_source_files_properties(
+ "${BundleTest_SOURCE_DIR}/SomeRandomFile.txt"
+ "${BundleTest_SOURCE_DIR}/../../README.rst"
+ PROPERTIES
+ MACOSX_PACKAGE_LOCATION Other
+ )
+
+add_executable(SecondBundle
+ MACOSX_BUNDLE
+ "${BundleTest_SOURCE_DIR}/BundleTest.cxx"
+ "${BundleTest_SOURCE_DIR}/SomeRandomFile.txt"
+ "${BundleTest_SOURCE_DIR}/../../README.rst"
+ "${CMAKE_CURRENT_BINARY_DIR}/randomResourceFile.plist"
+ )
+target_link_libraries(SecondBundle BundleTestLib)
+
+# Test bundle installation.
+install(TARGETS SecondBundle DESTINATION Applications)
+
+# Test whether bundles respect the output name. Since the library is
+# installed into a location that uses this output name this will fail if the
+# bundle does not respect the name. Also the executable will not be found by
+# the test driver if this does not work.
+set_target_properties(SecondBundle PROPERTIES OUTPUT_NAME SecondBundleExe)
+
+# Express one app bundle in terms of another's SOURCES to verify that
+# the generators do not expose the Info.plist of one to the other.
+add_executable(SubdirBundle1 MACOSX_BUNDLE EXCLUDE_FROM_ALL ../BundleTest.cxx)
+add_executable(SubdirBundle2 MACOSX_BUNDLE EXCLUDE_FROM_ALL $<TARGET_PROPERTY:SubdirBundle1,SOURCES>)
diff --git a/Tests/BundleTest/BundleTest.cxx b/Tests/BundleTest/BundleTest.cxx
new file mode 100644
index 0000000..9b70e52
--- /dev/null
+++ b/Tests/BundleTest/BundleTest.cxx
@@ -0,0 +1,21 @@
+#include <CoreFoundation/CoreFoundation.h>
+#include <stdio.h>
+
+extern int foo(char* exec);
+
+int main(int argc, char* argv[])
+{
+ printf("Started with: %d arguments\n", argc);
+
+ // Call a CoreFoundation function... but pull in the link dependency on
+ // "-framework
+ // CoreFoundation" via CMake's dependency chaining mechanism. This code
+ // exists to
+ // verify that the chaining mechanism works with "-framework blah" style
+ // link dependencies.
+ //
+ CFBundleRef br = CFBundleGetMainBundle();
+ (void)br;
+
+ return foo(argv[0]);
+}
diff --git a/Tests/BundleTest/CMakeLists.txt b/Tests/BundleTest/CMakeLists.txt
new file mode 100644
index 0000000..c63461a
--- /dev/null
+++ b/Tests/BundleTest/CMakeLists.txt
@@ -0,0 +1,113 @@
+cmake_minimum_required (VERSION 2.6)
+project(BundleTest)
+set(MACOSX_BUNDLE_INFO_STRING "bundle_info_string")
+set(CMAKE_MacOSX_Content_COMPILE_OBJECT "\"${CMAKE_COMMAND}\" -E copy_if_different <SOURCE> <OBJECT>")
+
+if(CMAKE_GENERATOR STREQUAL "Xcode" AND
+ "${CMAKE_SYSTEM_NAME};${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "Darwin;arm64")
+ # Tell Xcode to pretend the linker signed binaries so that
+ # editing with install_name_tool preserves ad-hoc signatures.
+ # See CMake Issue 21854.
+ # This option is supported by codesign on macOS 11 or higher.
+ set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "-o linker-signed")
+endif()
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/randomResourceFile.plist"
+ COMMAND /bin/cp
+ ARGS "${CMAKE_CURRENT_SOURCE_DIR}/randomResourceFile.plist.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/randomResourceFile.plist")
+
+set_source_files_properties(
+ "${CMAKE_CURRENT_BINARY_DIR}/randomResourceFile.plist"
+ PROPERTIES
+ MACOSX_PACKAGE_LOCATION Resources
+ )
+
+set_source_files_properties(
+ SomeRandomFile.txt
+ "${BundleTest_SOURCE_DIR}/../../README.rst"
+ PROPERTIES
+ MACOSX_PACKAGE_LOCATION Other
+ )
+
+set(EXECUTABLE_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/foobar")
+
+# Test building a bundle linking to a shared library where the
+# shared library links to CoreFoundation, but the executable does not
+# explicitly link to CoreFoundation, but the executable does *depend*
+# on CoreFoundation. There should be a link failure for the executable
+# if CMake's dependency chaining for libraries with "-framework
+# blah" style dependencies gets broken...
+#
+add_library(BundleTestLib SHARED BundleLib.cxx)
+target_link_libraries(BundleTestLib "-framework CoreFoundation")
+
+add_executable(BundleTest
+ MACOSX_BUNDLE
+ BundleTest.cxx
+ SomeRandomFile.txt
+ "${BundleTest_SOURCE_DIR}/../../README.rst"
+ "${CMAKE_CURRENT_BINARY_DIR}/randomResourceFile.plist"
+ )
+target_link_libraries(BundleTest BundleTestLib)
+#
+# DO NOT: target_link_libraries(BundleTest "-framework CoreFoundation")
+# (see above comments about CoreFoundation)
+#
+
+# Test bundle installation.
+#install(TARGETS BundleTestLib DESTINATION Applications/BundleTestExe.app/Contents/Plugins)
+install(TARGETS BundleTestLib DESTINATION Applications/SecondBundleExe.app/Contents/Plugins)
+install(TARGETS BundleTest DESTINATION Applications)
+
+# Test whether bundles respect the output name. Since the library is
+# installed into a location that uses this output name this will fail if the
+# bundle does not respect the name. Also the executable will not be found by
+# the test driver if this does not work.
+set_target_properties(BundleTest PROPERTIES OUTPUT_NAME BundleTestExe)
+
+# Test executable versioning if it is supported.
+if(NOT XCODE)
+ set_target_properties(BundleTest PROPERTIES VERSION 1)
+endif()
+
+# Make sure the executable can find its installed library.
+set_target_properties(BundleTestLib PROPERTIES
+ INSTALL_NAME_DIR "@executable_path/../Plugins")
+
+include(CPack)
+
+# test the framework find stuff
+if(EXISTS /usr/lib/libtcl.dylib
+ AND EXISTS /System/Library/Frameworks/Tcl.framework)
+ set(TCL NOTFOUND)
+ find_library(TCL tcl)
+ message("frame: ${TCL}")
+ if(NOT "${TCL}" MATCHES .framework)
+ message(FATAL_ERROR "Could not find tcl framework, found ${TCL}")
+ endif()
+ set(TCL NOTFOUND)
+ set(CMAKE_FIND_FRAMEWORK LAST)
+ find_library(TCL tcl)
+ if("${TCL}" MATCHES .framework)
+ message(FATAL_ERROR "Found framework and should have found dylib ${TCL}")
+ endif()
+ set(TCL NOTFOUND)
+ set(CMAKE_FIND_FRAMEWORK NEVER)
+ find_library(TCL tcl)
+ if("${TCL}" MATCHES .framework)
+ message(FATAL_ERROR "Found framework and should have found dylib ${TCL}")
+ endif()
+ message("not frame: ${TCL}")
+ set(TCL NOTFOUND)
+ set(CMAKE_FIND_FRAMEWORK FIRST)
+ find_library(TCL tcl)
+ if(NOT "${TCL}" MATCHES .framework)
+ message(FATAL_ERROR "Could not find tcl framework, found ${TCL}")
+ endif()
+ message("frame: ${TCL}")
+endif(EXISTS /usr/lib/libtcl.dylib
+ AND EXISTS /System/Library/Frameworks/Tcl.framework)
+
+subdirs(BundleSubDir)
diff --git a/Tests/BundleTest/SomeRandomFile.txt b/Tests/BundleTest/SomeRandomFile.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/BundleTest/SomeRandomFile.txt
diff --git a/Tests/BundleTest/randomResourceFile.plist.in b/Tests/BundleTest/randomResourceFile.plist.in
new file mode 100644
index 0000000..cfe3222
--- /dev/null
+++ b/Tests/BundleTest/randomResourceFile.plist.in
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Package</key>
+ <string>CMake</string>
+</dict>
+</plist>
+
diff --git a/Tests/BundleUtilities/CMakeLists.txt b/Tests/BundleUtilities/CMakeLists.txt
new file mode 100644
index 0000000..4a95e2f
--- /dev/null
+++ b/Tests/BundleUtilities/CMakeLists.txt
@@ -0,0 +1,136 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(BundleUtilities)
+
+if(CMAKE_GENERATOR STREQUAL "Xcode" AND
+ "${CMAKE_SYSTEM_NAME};${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "Darwin;arm64")
+ # Tell Xcode to pretend the linker signed binaries so that
+ # editing with install_name_tool preserves ad-hoc signatures.
+ # See CMake Issue 21854.
+ # This option is supported by codesign on macOS 11 or higher.
+ set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "-o linker-signed")
+endif()
+
+###### the various types of dependencies we can have
+
+# a shared library
+add_library(shared SHARED shared.cpp shared.h)
+
+# another shared library
+add_library(shared2 SHARED shared2.cpp shared2.h)
+
+
+# a framework library
+add_library(framework SHARED framework.cpp framework.h)
+set_target_properties(framework PROPERTIES FRAMEWORK 1)
+
+# make sure rpaths are not helping BundleUtilities or the executables
+set_target_properties(shared shared2 framework PROPERTIES
+ SKIP_BUILD_RPATH 1)
+
+
+###### test a Bundle application using dependencies
+
+# a loadable module (depends on shared2)
+# testbundleutils1 will load this at runtime
+add_library(module1 MODULE module.cpp module.h)
+set_target_properties(module1 PROPERTIES PREFIX "")
+target_link_libraries(module1 shared2)
+
+# a bundle application
+add_executable(testbundleutils1 MACOSX_BUNDLE testbundleutils1.cpp)
+target_link_libraries(testbundleutils1 shared framework ${CMAKE_DL_LIBS})
+
+set_target_properties(testbundleutils1 module1 PROPERTIES
+ INSTALL_RPATH "${CMAKE_CURRENT_BINARY_DIR}/testdir1"
+ BUILD_WITH_INSTALL_RPATH 1)
+
+# add custom target to install and test the app
+add_custom_target(testbundleutils1_test ALL
+ COMMAND ${CMAKE_COMMAND}
+ "-DINPUT=$<TARGET_FILE:testbundleutils1>"
+ "-DMODULE=$<TARGET_FILE:module1>"
+ "-DINPUTDIR=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}"
+ "-DOUTPUTDIR=${CMAKE_CURRENT_BINARY_DIR}/testdir1"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/bundleutils.cmake"
+ DEPENDS testbundleutils1 module1
+ )
+
+add_dependencies(testbundleutils1_test testbundleutils1)
+
+
+
+###### test a non-Bundle application using dependencies
+
+# a loadable module (depends on shared2)
+# testbundleutils2 will load this at runtime
+add_library(module2 MODULE module.cpp module.h)
+set_target_properties(module2 PROPERTIES PREFIX "")
+target_link_libraries(module2 shared2)
+
+# a non-bundle application
+add_executable(testbundleutils2 testbundleutils2.cpp)
+target_link_libraries(testbundleutils2 shared framework ${CMAKE_DL_LIBS})
+
+set_target_properties(testbundleutils2 module2 PROPERTIES
+ INSTALL_RPATH "${CMAKE_CURRENT_BINARY_DIR}/testdir2"
+ BUILD_WITH_INSTALL_RPATH 1)
+
+# add custom target to install and test the app
+add_custom_target(testbundleutils2_test ALL
+ COMMAND ${CMAKE_COMMAND}
+ "-DINPUT=$<TARGET_FILE:testbundleutils2>"
+ "-DMODULE=$<TARGET_FILE:module2>"
+ "-DINPUTDIR=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}"
+ "-DOUTPUTDIR=${CMAKE_CURRENT_BINARY_DIR}/testdir2"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/bundleutils.cmake"
+ DEPENDS testbundleutils1 module2
+ )
+add_dependencies(testbundleutils2_test testbundleutils2)
+
+
+if(APPLE AND NOT CMAKE_SYSTEM_VERSION VERSION_LESS 9.0)
+###### Test a Bundle application using dependencies
+###### and @rpaths on Mac OS X 10.5 or greater
+
+ # a shared library
+ add_library(shared-3 SHARED shared.cpp shared.h)
+
+ # another shared library
+ add_library(shared2-3 SHARED shared2.cpp shared2.h)
+
+ # a framework library
+ add_library(framework-3 SHARED framework.cpp framework.h)
+ set_target_properties(framework-3 PROPERTIES FRAMEWORK 1)
+
+ # build dependencies with @rpath install name
+ set_target_properties(shared-3 shared2-3 framework-3 PROPERTIES
+ INSTALL_NAME_DIR "@rpath"
+ BUILD_WITH_INSTALL_RPATH 1)
+
+ # a loadable module (depends on shared2)
+ # testbundleutils1 will load this at runtime
+ add_library(module3 MODULE module.cpp module.h)
+ set_target_properties(module3 PROPERTIES PREFIX "" LINK_FLAGS "-Wl,-rpath,@loader_path/")
+ target_link_libraries(module3 shared2-3)
+
+ # a non-bundle application
+ add_executable(testbundleutils3 testbundleutils3.cpp)
+ target_link_libraries(testbundleutils3 shared-3 framework-3 ${CMAKE_DL_LIBS})
+
+ set_target_properties(testbundleutils3 module3 PROPERTIES
+ LINK_FLAGS "-Wl,-rpath,@loader_path/"
+ BUILD_WITH_INSTALL_RPATH 1)
+
+ # add custom target to install and test the app
+ add_custom_target(testbundleutils3_test ALL
+ COMMAND ${CMAKE_COMMAND}
+ "-DINPUT=$<TARGET_FILE:testbundleutils3>"
+ "-DMODULE=$<TARGET_FILE:module3>"
+ "-DINPUTDIR=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}"
+ "-DOUTPUTDIR=${CMAKE_CURRENT_BINARY_DIR}/testdir3"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/bundleutils.cmake"
+ DEPENDS testbundleutils3 module3
+ )
+
+ add_dependencies(testbundleutils3_test testbundleutils3)
+endif()
diff --git a/Tests/BundleUtilities/bundleutils.cmake b/Tests/BundleUtilities/bundleutils.cmake
new file mode 100644
index 0000000..cc89347
--- /dev/null
+++ b/Tests/BundleUtilities/bundleutils.cmake
@@ -0,0 +1,45 @@
+
+# clean passed in arguments
+get_filename_component(INPUT ${INPUT} ABSOLUTE)
+get_filename_component(INPUTDIR ${INPUTDIR} ABSOLUTE)
+
+message("INPUT = ${INPUT}")
+message("MODULE = ${MODULE}")
+message("INPUTDIR = ${INPUTDIR}")
+message("OUTPUTDIR = ${OUTPUTDIR}")
+
+# compute location to install/test things
+file(RELATIVE_PATH relative_exe "${INPUTDIR}" "${INPUT}")
+set(OUTPUT "${OUTPUTDIR}/${relative_exe}")
+message("OUTPUT = ${OUTPUT}")
+get_filename_component(EXE_DIR "${OUTPUT}" PATH)
+get_filename_component(MODULE_NAME "${MODULE}" NAME)
+set(OUTPUT_MODULE "${EXE_DIR}/${MODULE_NAME}")
+message("OUTPUTMODULE = ${OUTPUT_MODULE}")
+
+# clean output dir
+file(REMOVE_RECURSE "${OUTPUTDIR}")
+# copy the app and plugin to installation/testing directory
+configure_file("${INPUT}" "${OUTPUT}" COPYONLY)
+configure_file("${MODULE}" "${OUTPUT_MODULE}" COPYONLY)
+
+# have BundleUtilities grab all dependencies and
+# check that the app runs
+
+# for this test we'll override location to put all dependencies
+# (in the same dir as the app)
+# this shouldn't be necessary except for the non-bundle case on Mac
+function(gp_item_default_embedded_path_override item path)
+ set(path "@executable_path" PARENT_SCOPE)
+endfunction()
+
+include(BundleUtilities)
+fixup_bundle("${OUTPUT}" "${OUTPUT_MODULE}" "${INPUTDIR}")
+
+# make sure we can run the app
+message("Executing ${OUTPUT} in ${EXE_DIR}")
+execute_process(COMMAND "${OUTPUT}" RESULT_VARIABLE result OUTPUT_VARIABLE out ERROR_VARIABLE out WORKING_DIRECTORY "${EXE_DIR}")
+
+if(NOT result STREQUAL "0")
+ message(FATAL_ERROR " failed to execute test program\n${out}")
+endif()
diff --git a/Tests/BundleUtilities/framework.cpp b/Tests/BundleUtilities/framework.cpp
new file mode 100644
index 0000000..b5a95d8
--- /dev/null
+++ b/Tests/BundleUtilities/framework.cpp
@@ -0,0 +1,9 @@
+
+#include "framework.h"
+
+#include "stdio.h"
+
+void framework()
+{
+ printf("framework\n");
+}
diff --git a/Tests/BundleUtilities/framework.h b/Tests/BundleUtilities/framework.h
new file mode 100644
index 0000000..5a3cfc4
--- /dev/null
+++ b/Tests/BundleUtilities/framework.h
@@ -0,0 +1,17 @@
+
+#ifndef framework_h
+#define framework_h
+
+#ifdef WIN32
+# ifdef framework_EXPORTS
+# define FRAMEWORK_EXPORT __declspec(dllexport)
+# else
+# define FRAMEWORK_EXPORT __declspec(dllimport)
+# endif
+#else
+# define FRAMEWORK_EXPORT
+#endif
+
+void FRAMEWORK_EXPORT framework();
+
+#endif
diff --git a/Tests/BundleUtilities/module.cpp b/Tests/BundleUtilities/module.cpp
new file mode 100644
index 0000000..64bc369
--- /dev/null
+++ b/Tests/BundleUtilities/module.cpp
@@ -0,0 +1,11 @@
+
+#include "module.h"
+
+#include "shared2.h"
+#include "stdio.h"
+
+void module()
+{
+ printf("module\n");
+ shared2();
+}
diff --git a/Tests/BundleUtilities/module.h b/Tests/BundleUtilities/module.h
new file mode 100644
index 0000000..0659bc7
--- /dev/null
+++ b/Tests/BundleUtilities/module.h
@@ -0,0 +1,7 @@
+
+#ifndef module_h
+#define module_h
+
+void module();
+
+#endif
diff --git a/Tests/BundleUtilities/shared.cpp b/Tests/BundleUtilities/shared.cpp
new file mode 100644
index 0000000..13791c2
--- /dev/null
+++ b/Tests/BundleUtilities/shared.cpp
@@ -0,0 +1,9 @@
+
+#include "shared.h"
+
+#include "stdio.h"
+
+void shared()
+{
+ printf("shared\n");
+}
diff --git a/Tests/BundleUtilities/shared.h b/Tests/BundleUtilities/shared.h
new file mode 100644
index 0000000..5d5b633
--- /dev/null
+++ b/Tests/BundleUtilities/shared.h
@@ -0,0 +1,17 @@
+
+#ifndef shared_h
+#define shared_h
+
+#ifdef WIN32
+# ifdef shared_EXPORTS
+# define SHARED_EXPORT __declspec(dllexport)
+# else
+# define SHARED_EXPORT __declspec(dllimport)
+# endif
+#else
+# define SHARED_EXPORT
+#endif
+
+void SHARED_EXPORT shared();
+
+#endif
diff --git a/Tests/BundleUtilities/shared2.cpp b/Tests/BundleUtilities/shared2.cpp
new file mode 100644
index 0000000..bed1904
--- /dev/null
+++ b/Tests/BundleUtilities/shared2.cpp
@@ -0,0 +1,9 @@
+
+#include "shared2.h"
+
+#include "stdio.h"
+
+void shared2()
+{
+ printf("shared2\n");
+}
diff --git a/Tests/BundleUtilities/shared2.h b/Tests/BundleUtilities/shared2.h
new file mode 100644
index 0000000..3f016c8
--- /dev/null
+++ b/Tests/BundleUtilities/shared2.h
@@ -0,0 +1,17 @@
+
+#ifndef shared2_h
+#define shared2_h
+
+#ifdef WIN32
+# ifdef shared2_EXPORTS
+# define SHARED2_EXPORT __declspec(dllexport)
+# else
+# define SHARED2_EXPORT __declspec(dllimport)
+# endif
+#else
+# define SHARED2_EXPORT
+#endif
+
+void SHARED2_EXPORT shared2();
+
+#endif
diff --git a/Tests/BundleUtilities/testbundleutils1.cpp b/Tests/BundleUtilities/testbundleutils1.cpp
new file mode 100644
index 0000000..080157a
--- /dev/null
+++ b/Tests/BundleUtilities/testbundleutils1.cpp
@@ -0,0 +1,30 @@
+
+#include "framework.h"
+#include "shared.h"
+#include "stdio.h"
+
+#if defined(WIN32)
+# include <windows.h>
+#else
+# include "dlfcn.h"
+#endif
+
+int main(int, char**)
+{
+ framework();
+ shared();
+
+#if defined(WIN32)
+ HANDLE lib = LoadLibraryA("module1.dll");
+ if (!lib) {
+ printf("Failed to open module1\n");
+ }
+#else
+ void* lib = dlopen("module1.so", RTLD_LAZY);
+ if (!lib) {
+ printf("Failed to open module1\n%s\n", dlerror());
+ }
+#endif
+
+ return lib == 0 ? 1 : 0;
+}
diff --git a/Tests/BundleUtilities/testbundleutils2.cpp b/Tests/BundleUtilities/testbundleutils2.cpp
new file mode 100644
index 0000000..e747544
--- /dev/null
+++ b/Tests/BundleUtilities/testbundleutils2.cpp
@@ -0,0 +1,30 @@
+
+#include "framework.h"
+#include "shared.h"
+#include "stdio.h"
+
+#if defined(WIN32)
+# include <windows.h>
+#else
+# include "dlfcn.h"
+#endif
+
+int main(int, char**)
+{
+ framework();
+ shared();
+
+#if defined(WIN32)
+ HANDLE lib = LoadLibraryA("module2.dll");
+ if (!lib) {
+ printf("Failed to open module2\n");
+ }
+#else
+ void* lib = dlopen("module2.so", RTLD_LAZY);
+ if (!lib) {
+ printf("Failed to open module2\n%s\n", dlerror());
+ }
+#endif
+
+ return lib == 0 ? 1 : 0;
+}
diff --git a/Tests/BundleUtilities/testbundleutils3.cpp b/Tests/BundleUtilities/testbundleutils3.cpp
new file mode 100644
index 0000000..2dee46f
--- /dev/null
+++ b/Tests/BundleUtilities/testbundleutils3.cpp
@@ -0,0 +1,30 @@
+
+#include "framework.h"
+#include "shared.h"
+#include "stdio.h"
+
+#if defined(WIN32)
+# include <windows.h>
+#else
+# include "dlfcn.h"
+#endif
+
+int main(int, char**)
+{
+ framework();
+ shared();
+
+#if defined(WIN32)
+ HANDLE lib = LoadLibraryA("module3.dll");
+ if (!lib) {
+ printf("Failed to open module3\n");
+ }
+#else
+ void* lib = dlopen("module3.so", RTLD_LAZY);
+ if (!lib) {
+ printf("Failed to open module3\n%s\n", dlerror());
+ }
+#endif
+
+ return lib == 0 ? 1 : 0;
+}
diff --git a/Tests/CFBundleTest/CMakeLists.txt b/Tests/CFBundleTest/CMakeLists.txt
new file mode 100644
index 0000000..5f2e8ec
--- /dev/null
+++ b/Tests/CFBundleTest/CMakeLists.txt
@@ -0,0 +1,65 @@
+#this is adapted from FireBreath (http://www.firebreath.org)
+
+cmake_minimum_required(VERSION 2.8.12)
+
+project(CFBundleTest)
+
+include(PluginConfig.cmake)
+
+message ("Creating Mac Browser Plugin project ${PROJECT_NAME}")
+set(SOURCES
+ np_macmain.cpp
+ Localized.r
+ ${CMAKE_CURRENT_BINARY_DIR}/Info.plist
+ ${CMAKE_CURRENT_BINARY_DIR}/InfoPlist.strings
+ ${CMAKE_CURRENT_BINARY_DIR}/Localized.rsrc
+)
+
+add_library( ${PROJECT_NAME} MODULE
+ ${SOURCES}
+ )
+
+set (RCFILES ${CMAKE_CURRENT_SOURCE_DIR}/Localized.r)
+
+configure_file(Info.plist.in ${CMAKE_CURRENT_BINARY_DIR}/Info.plist)
+configure_file(InfoPlist.strings.in ${CMAKE_CURRENT_BINARY_DIR}/InfoPlist.strings)
+
+# Compile the resource file
+find_program(RC_COMPILER Rez NO_DEFAULT_PATHS PATHS /Developer/Tools)
+if(NOT RC_COMPILER)
+ message(FATAL_ERROR "could not find Rez to build resources from .r file...")
+endif()
+
+set(sysroot)
+if(CMAKE_OSX_SYSROOT)
+ set(sysroot -isysroot ${CMAKE_OSX_SYSROOT})
+endif()
+
+execute_process(COMMAND
+ ${RC_COMPILER} ${sysroot} ${RCFILES} -useDF
+ -o ${CMAKE_CURRENT_BINARY_DIR}/Localized.rsrc
+ )
+
+set_source_files_properties(
+ ${CMAKE_CURRENT_BINARY_DIR}/Localized.rsrc
+ PROPERTIES GENERATED 1
+ )
+# note that for some reason, the makefile and xcode generators use a different
+# property to indicate where the Info.plist file is :-/ For that reason, we
+# specify it twice so it will work both places
+set_target_properties(CFBundleTest PROPERTIES
+ BUNDLE 1
+ BUNDLE_EXTENSION plugin
+ XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ""
+ XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO"
+ XCODE_ATTRIBUTE_MACH_O_TYPE mh_bundle
+ XCODE_ATTRIBUTE_INFOPLIST_FILE ${CMAKE_CURRENT_BINARY_DIR}/Info.plist
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist
+ LINK_FLAGS "-Wl,-exported_symbols_list,\"${CMAKE_CURRENT_SOURCE_DIR}/ExportList_plugin.txt\"")
+
+set_source_files_properties(
+ ${CMAKE_CURRENT_BINARY_DIR}/InfoPlist.strings
+ ${CMAKE_CURRENT_BINARY_DIR}/Localized.rsrc
+ PROPERTIES MACOSX_PACKAGE_LOCATION "Resources/English.lproj")
+
+export(TARGETS CFBundleTest FILE ${CMAKE_CURRENT_BINARY_DIR}/exp.cmake)
diff --git a/Tests/CFBundleTest/ExportList_plugin.txt b/Tests/CFBundleTest/ExportList_plugin.txt
new file mode 100644
index 0000000..31d6f64
--- /dev/null
+++ b/Tests/CFBundleTest/ExportList_plugin.txt
@@ -0,0 +1,3 @@
+_NP_GetEntryPoints
+_NP_Initialize
+_NP_Shutdown
diff --git a/Tests/CFBundleTest/Info.plist.in b/Tests/CFBundleTest/Info.plist.in
new file mode 100644
index 0000000..638002f
--- /dev/null
+++ b/Tests/CFBundleTest/Info.plist.in
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${PLUGIN_NAME}</string>
+ <key>CFBundleGetInfoString</key>
+ <string>${PLUGIN_NAME} ${FBSTRING_PLUGIN_VERSION}, ${FBSTRING_LegalCopyright}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.${ACTIVEX_PROGID}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BRPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${PLUGIN_NAME} ${FBSTRING_PLUGIN_VERSION}</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>${FBSTRING_PLUGIN_VERSION}</string>
+ <key>CFPlugInDynamicRegisterFunction</key>
+ <string></string>
+ <key>CFPlugInDynamicRegistration</key>
+ <string>NO</string>
+ <key>CFPlugInFactories</key>
+ <dict>
+ <key>00000000-0000-0000-0000-000000000000</key>
+ <string>MyFactoryFunction</string>
+ </dict>
+ <key>CFPlugInTypes</key>
+ <dict>
+ <key>00000000-0000-0000-0000-000000000000</key>
+ <array>
+ <string>00000000-0000-0000-0000-000000000000</string>
+ </array>
+ </dict>
+ <key>CFPlugInUnloadFunction</key>
+ <string></string>
+ <key>WebPluginName</key>
+ <string>${FBSTRING_ProductName}</string>
+ <key>WebPluginDescription</key>
+ <string>${FBSTRING_FileDescription}</string>
+ <key>WebPluginMIMETypes</key>
+ <dict>
+ <key>${FBSTRING_MIMEType}</key>
+ <dict>
+ <key>WebPluginTypeDescription</key>
+ <string>${FBSTRING_FileDescription}</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/Tests/CFBundleTest/InfoPlist.strings.in b/Tests/CFBundleTest/InfoPlist.strings.in
new file mode 100644
index 0000000..790ead0
--- /dev/null
+++ b/Tests/CFBundleTest/InfoPlist.strings.in
@@ -0,0 +1,4 @@
+/* Localized versions of Info.plist keys */
+
+CFBundleName = "${PLUGIN_NAME}.plugin";
+NSHumanReadableCopyright = "${FBSTRING_LegalCopyright}";
diff --git a/Tests/CFBundleTest/Localized.r b/Tests/CFBundleTest/Localized.r
new file mode 100644
index 0000000..e988e26
--- /dev/null
+++ b/Tests/CFBundleTest/Localized.r
@@ -0,0 +1,18 @@
+#include <CoreServices/CoreServices.r>
+
+resource 'STR#' (126)
+{ {
+ "${FBSTRING_LegalCopyright}",
+ "${FBSTRING_ProductName}"
+} };
+
+resource 'STR#' (127)
+{ {
+ "${FBSTRING_FileDescription}"
+} };
+
+resource 'STR#' (128)
+{ {
+ "${FBSTRING_MIMEType}",
+ "${FBSTRING_FileExtents}"
+} };
diff --git a/Tests/CFBundleTest/Localized.rsrc b/Tests/CFBundleTest/Localized.rsrc
new file mode 100644
index 0000000..7973c1f
--- /dev/null
+++ b/Tests/CFBundleTest/Localized.rsrc
Binary files differ
diff --git a/Tests/CFBundleTest/PluginConfig.cmake b/Tests/CFBundleTest/PluginConfig.cmake
new file mode 100644
index 0000000..763ddcc
--- /dev/null
+++ b/Tests/CFBundleTest/PluginConfig.cmake
@@ -0,0 +1,21 @@
+#/**********************************************************\
+# Auto-Generated Plugin Configuration file
+# for CFTestPlugin
+#\**********************************************************/
+
+set(PLUGIN_NAME "CFTestPlugin")
+set(PLUGIN_PREFIX "CFTP")
+set(COMPANY_NAME "FBDevTeam")
+
+set(MOZILLA_PLUGINID "@firebreath.googlecode.com/CFTestPlugin")
+
+# strings
+set(FBSTRING_CompanyName "Firebreath Dev Team")
+set(FBSTRING_FileDescription "CFBundle Test Plugin - Plugin for testing cmake patch to improve FireBreath project generation")
+set(FBSTRING_PLUGIN_VERSION "1.0.0")
+set(FBSTRING_LegalCopyright "Copyright 2010 Firebreath Dev Team")
+set(FBSTRING_PluginFileName "np${PLUGIN_NAME}.dll")
+set(FBSTRING_ProductName "CFTestPlugin")
+set(FBSTRING_FileExtents "")
+set(FBSTRING_PluginName "CFTestPlugin")
+set(FBSTRING_MIMEType "application/x-fbtestplugin")
diff --git a/Tests/CFBundleTest/README.txt b/Tests/CFBundleTest/README.txt
new file mode 100644
index 0000000..86c1463
--- /dev/null
+++ b/Tests/CFBundleTest/README.txt
@@ -0,0 +1,16 @@
+
+CFBundle test project. The generated .plugin/ bundle from either makefiles or Xcode should look like this:
+
+./Contents
+./Contents/Info.plist
+./Contents/MacOS
+./Contents/MacOS/CFBundleTest
+./Contents/Resources
+./Contents/Resources/English.lproj
+./Contents/Resources/English.lproj/InfoPlist.strings
+./Contents/Resources/English.lproj/Localized.rsrc
+
+file Contents/MacOS/CFBundleTest should return something like:
+Contents/MacOS/CFBundleTest: Mach-O 64-bit bundle x86_64
+
+It is okay if it is a 32 bit binary; if it is not Mach-O, or is spelled differently, it is not okay.
diff --git a/Tests/CFBundleTest/VerifyResult.cmake b/Tests/CFBundleTest/VerifyResult.cmake
new file mode 100644
index 0000000..ac14e5d
--- /dev/null
+++ b/Tests/CFBundleTest/VerifyResult.cmake
@@ -0,0 +1,29 @@
+if(NOT DEFINED CTEST_CONFIGURATION_TYPE)
+ message(FATAL_ERROR "expected variable CTEST_CONFIGURATION_TYPE not defined")
+endif()
+
+if(NOT DEFINED dir)
+ message(FATAL_ERROR "expected variable dir not defined")
+endif()
+
+if(NOT DEFINED gen)
+ message(FATAL_ERROR "expected variable gen not defined")
+endif()
+
+message(STATUS "CTEST_CONFIGURATION_TYPE='${CTEST_CONFIGURATION_TYPE}'")
+message(STATUS "dir='${dir}'")
+message(STATUS "gen='${gen}'")
+
+if(gen MATCHES "^(Xcode$|Ninja Multi-Config$)")
+ set(expected_filename "${dir}/${CTEST_CONFIGURATION_TYPE}/CFBundleTest.plugin/Contents/MacOS/CFBundleTest")
+else()
+ set(expected_filename "${dir}/CFBundleTest.plugin/Contents/MacOS/CFBundleTest")
+endif()
+
+if(NOT EXISTS "${expected_filename}")
+ message(FATAL_ERROR "test fails: expected output file does not exist [${expected_filename}]")
+endif()
+
+file(COPY "${expected_filename}"
+ DESTINATION "${dir}/LatestBuildResult"
+ )
diff --git a/Tests/CFBundleTest/np_macmain.cpp b/Tests/CFBundleTest/np_macmain.cpp
new file mode 100644
index 0000000..e5fd0d7
--- /dev/null
+++ b/Tests/CFBundleTest/np_macmain.cpp
@@ -0,0 +1,48 @@
+/***********************************************************\
+ Written by: Richard Bateman (taxilian)
+
+ Based on the default np_macmain.cpp from FireBreath
+ http://firebreath.googlecode.com
+
+ This file has been stripped to prevent it from accidentally
+ doing anything useful.
+\***********************************************************/
+
+#include <stdio.h>
+
+typedef void (*NPP_ShutdownProcPtr)(void);
+typedef short NPError;
+
+#pragma GCC visibility push(default)
+
+struct NPNetscapeFuncs;
+struct NPPluginFuncs;
+
+extern "C" {
+NPError NP_Initialize(NPNetscapeFuncs* browserFuncs);
+NPError NP_GetEntryPoints(NPPluginFuncs* pluginFuncs);
+NPError NP_Shutdown(void);
+}
+
+#pragma GCC visibility pop
+
+void initPluginModule()
+{
+}
+
+NPError NP_GetEntryPoints(NPPluginFuncs* pFuncs)
+{
+ printf("NP_GetEntryPoints()\n");
+ return 0;
+}
+
+NPError NP_Initialize(NPNetscapeFuncs* pFuncs)
+{
+ printf("NP_Initialize()\n");
+ return 0;
+}
+
+NPError NP_Shutdown()
+{
+ return 0;
+}
diff --git a/Tests/CMakeBuildTest.cmake.in b/Tests/CMakeBuildTest.cmake.in
new file mode 100644
index 0000000..b4b1286
--- /dev/null
+++ b/Tests/CMakeBuildTest.cmake.in
@@ -0,0 +1,60 @@
+# create the binary directory
+make_directory("@CMAKE_BUILD_TEST_BINARY_DIR@")
+
+# remove the CMakeCache.txt file from the source dir
+# if there is one, so that in-source cmake tests
+# still pass
+message("Remove: @CMAKE_BUILD_TEST_SOURCE_DIR@/CMakeCache.txt")
+file(REMOVE "@CMAKE_BUILD_TEST_SOURCE_DIR@/CMakeCache.txt")
+
+# run cmake in the binary directory
+message("running: ${CMAKE_COMMAND}")
+execute_process(COMMAND "${CMAKE_COMMAND}"
+ "@CMAKE_BUILD_TEST_SOURCE_DIR@"
+ "-G@CMAKE_GENERATOR@"
+ -A "@CMAKE_GENERATOR_PLATFORM@"
+ -T "@CMAKE_GENERATOR_TOOLSET@"
+ WORKING_DIRECTORY "@CMAKE_BUILD_TEST_BINARY_DIR@"
+ RESULT_VARIABLE RESULT)
+if(RESULT)
+ message(FATAL_ERROR "Error running cmake command")
+endif()
+
+# Now use the --build option to build the project
+message("running: ${CMAKE_COMMAND} --build")
+execute_process(COMMAND "${CMAKE_COMMAND}"
+ --build "@CMAKE_BUILD_TEST_BINARY_DIR@" --config Debug
+ RESULT_VARIABLE RESULT)
+if(RESULT)
+ message(FATAL_ERROR "Error running cmake --build")
+endif()
+
+# run the executable out of the Debug directory if using a
+# multi-config generator
+set(_isMultiConfig @_isMultiConfig@)
+if(_isMultiConfig)
+ set(RUN_TEST "@CMAKE_BUILD_TEST_BINARY_DIR@/Debug/@CMAKE_BUILD_TEST_EXE@")
+else()
+ set(RUN_TEST "@CMAKE_BUILD_TEST_BINARY_DIR@/@CMAKE_BUILD_TEST_EXE@")
+endif()
+# run the test results
+message("running [${RUN_TEST}]")
+execute_process(COMMAND "${RUN_TEST}" RESULT_VARIABLE RESULT)
+if(RESULT)
+ message(FATAL_ERROR "Error running test @CMAKE_BUILD_TEST_EXE@")
+endif()
+
+# build it again with clean and only @CMAKE_BUILD_TEST_EXE@ target
+execute_process(COMMAND "${CMAKE_COMMAND}"
+ --build "@CMAKE_BUILD_TEST_BINARY_DIR@" --config Debug
+ --clean-first --target @CMAKE_BUILD_TEST_EXE@
+ RESULT_VARIABLE RESULT)
+if(RESULT)
+ message(FATAL_ERROR "Error running cmake --build")
+endif()
+
+# run it again after clean
+execute_process(COMMAND "${RUN_TEST}" RESULT_VARIABLE RESULT)
+if(RESULT)
+ message(FATAL_ERROR "Error running test @CMAKE_BUILD_TEST_EXE@ after clean ")
+endif()
diff --git a/Tests/CMakeCommands/add_compile_definitions/CMakeLists.txt b/Tests/CMakeCommands/add_compile_definitions/CMakeLists.txt
new file mode 100644
index 0000000..2eb887e
--- /dev/null
+++ b/Tests/CMakeCommands/add_compile_definitions/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(add_compile_definitions LANGUAGES CXX)
+
+add_compile_definitions(TEST_DEFINITION
+ $<$<COMPILE_LANGUAGE:CXX>:LANG_$<COMPILE_LANGUAGE>>
+ $<$<EQUAL:0,1>:UNEXPECTED_DEFINITION>)
+
+add_executable(add_compile_definitions main.cpp)
+
+add_library(imp UNKNOWN IMPORTED)
+get_target_property(_res imp COMPILE_DEFINITIONS)
+if (_res)
+ message(SEND_ERROR "add_compile_definitions populated the COMPILE_DEFINITIONS target property")
+endif()
diff --git a/Tests/CMakeCommands/add_compile_definitions/main.cpp b/Tests/CMakeCommands/add_compile_definitions/main.cpp
new file mode 100644
index 0000000..41ff25f
--- /dev/null
+++ b/Tests/CMakeCommands/add_compile_definitions/main.cpp
@@ -0,0 +1,17 @@
+
+#ifndef TEST_DEFINITION
+# error Expected TEST_DEFINITION
+#endif
+
+#ifndef LANG_CXX
+# error Expected LANG_CXX
+#endif
+
+#ifdef UNPEXTED_DEFINITION
+# error Unexpected UNPEXTED_DEFINITION
+#endif
+
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/add_compile_options/CMakeLists.txt b/Tests/CMakeCommands/add_compile_options/CMakeLists.txt
new file mode 100644
index 0000000..b28d0be
--- /dev/null
+++ b/Tests/CMakeCommands/add_compile_options/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(add_compile_options)
+
+add_compile_options(-DTEST_OPTION)
+
+add_executable(add_compile_options main.cpp)
+
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ target_compile_definitions(add_compile_options
+ PRIVATE
+ "DO_GNU_TESTS"
+ )
+endif()
+
+add_compile_options(-rtti)
+add_library(imp UNKNOWN IMPORTED)
+get_target_property(_res imp COMPILE_OPTIONS)
+if (_res)
+ message(SEND_ERROR "add_compile_options populated the COMPILE_OPTIONS target property")
+endif()
diff --git a/Tests/CMakeCommands/add_compile_options/main.cpp b/Tests/CMakeCommands/add_compile_options/main.cpp
new file mode 100644
index 0000000..53f54b7
--- /dev/null
+++ b/Tests/CMakeCommands/add_compile_options/main.cpp
@@ -0,0 +1,11 @@
+
+#ifdef DO_GNU_TESTS
+# ifndef TEST_OPTION
+# error Expected TEST_OPTION
+# endif
+#endif
+
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/add_link_options/CMakeLists.txt b/Tests/CMakeCommands/add_link_options/CMakeLists.txt
new file mode 100644
index 0000000..bb7dcbb
--- /dev/null
+++ b/Tests/CMakeCommands/add_link_options/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.11)
+
+project(add_link_options LANGUAGES C)
+
+
+add_link_options(-LINK_FLAG)
+
+add_executable(add_link_options EXCLUDE_FROM_ALL LinkOptionsExe.c)
+
+get_target_property(result add_link_options LINK_OPTIONS)
+if (NOT result MATCHES "-LINK_FLAG")
+ message(SEND_ERROR "add_link_options not populated the LINK_OPTIONS target property")
+endif()
+
+
+add_library(imp UNKNOWN IMPORTED)
+get_target_property(result imp LINK_OPTIONS)
+if (result)
+ message(FATAL_ERROR "add_link_options populated the LINK_OPTIONS target property")
+endif()
diff --git a/Tests/CMakeCommands/add_link_options/LinkOptionsExe.c b/Tests/CMakeCommands/add_link_options/LinkOptionsExe.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/CMakeCommands/add_link_options/LinkOptionsExe.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/link_directories/CMakeLists.txt b/Tests/CMakeCommands/link_directories/CMakeLists.txt
new file mode 100644
index 0000000..60c07b6
--- /dev/null
+++ b/Tests/CMakeCommands/link_directories/CMakeLists.txt
@@ -0,0 +1,30 @@
+cmake_minimum_required(VERSION 3.12)
+
+project(link_directories LANGUAGES C)
+
+
+link_directories(/A)
+link_directories(BEFORE /B)
+
+set(CMAKE_LINK_DIRECTORIES_BEFORE ON)
+link_directories(/C)
+
+get_directory_property(result LINK_DIRECTORIES)
+if (NOT result MATCHES "/C;/B;/A")
+ message(SEND_ERROR "link_directories not populated the LINK_DIRECTORIES directory property")
+endif()
+
+
+add_executable(link_directories EXCLUDE_FROM_ALL LinkDirectoriesExe.c)
+
+get_target_property(result link_directories LINK_DIRECTORIES)
+if (NOT result MATCHES "/C;/B;/A")
+ message(SEND_ERROR "link_directories not populated the LINK_DIRECTORIES target property")
+endif()
+
+
+add_library(imp UNKNOWN IMPORTED)
+get_target_property(result imp LINK_DIRECTORIES)
+if (result)
+ message(FATAL_ERROR "link_directories populated the LINK_DIRECTORIES target property")
+endif()
diff --git a/Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c b/Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt b/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt
new file mode 100644
index 0000000..72b3502
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt
@@ -0,0 +1,50 @@
+
+cmake_minimum_required(VERSION 2.8.12)
+
+project(target_compile_definitions)
+
+add_executable(target_compile_definitions
+ "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
+)
+target_compile_definitions(target_compile_definitions
+ PRIVATE MY_PRIVATE_DEFINE
+ PUBLIC MY_PUBLIC_DEFINE
+ INTERFACE MY_INTERFACE_DEFINE
+)
+
+add_executable(consumer
+ "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
+)
+
+target_compile_definitions(consumer
+ PRIVATE $<TARGET_PROPERTY:target_compile_definitions,INTERFACE_COMPILE_DEFINITIONS>
+ -DDASH_D_DEFINE
+)
+
+# Test no items
+target_compile_definitions(consumer
+ PRIVATE
+)
+
+target_sources(consumer PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/consumer.c"
+)
+target_compile_definitions(consumer
+ PRIVATE
+ CONSUMER_LANG_$<COMPILE_LANGUAGE>
+ LANG_IS_CXX=$<COMPILE_LANGUAGE:CXX>
+ LANG_IS_C=$<COMPILE_LANGUAGE:C>
+ LANG_IS_C_OR_CXX=$<COMPILE_LANGUAGE:C,CXX>
+)
+if(CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
+ target_compile_definitions(consumer
+ PRIVATE TEST_LANG_DEFINES_FOR_VISUAL_STUDIO_OR_XCODE
+ )
+endif()
+
+add_definitions(-DSOME_DEF)
+add_library(imp UNKNOWN IMPORTED)
+get_target_property(_res imp COMPILE_DEFINITIONS)
+if (_res)
+ message(SEND_ERROR "add_definitions populated the COMPILE_DEFINITIONS target property")
+endif()
diff --git a/Tests/CMakeCommands/target_compile_definitions/consumer.c b/Tests/CMakeCommands/target_compile_definitions/consumer.c
new file mode 100644
index 0000000..bb65e01
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_definitions/consumer.c
@@ -0,0 +1,44 @@
+
+// Visual Studio allows only one set of flags for C and C++.
+// In a target using C++ we pick the C++ flags even for C sources.
+#ifdef TEST_LANG_DEFINES_FOR_VISUAL_STUDIO_OR_XCODE
+# ifndef CONSUMER_LANG_CXX
+# error Expected CONSUMER_LANG_CXX
+# endif
+
+# ifdef CONSUMER_LANG_C
+# error Unexpected CONSUMER_LANG_C
+# endif
+
+# if !LANG_IS_CXX
+# error Expected LANG_IS_CXX
+# endif
+
+# if LANG_IS_C
+# error Unexpected LANG_IS_C
+# endif
+#else
+# ifdef CONSUMER_LANG_CXX
+# error Unexpected CONSUMER_LANG_CXX
+# endif
+
+# ifndef CONSUMER_LANG_C
+# error Expected CONSUMER_LANG_C
+# endif
+
+# if !LANG_IS_C
+# error Expected LANG_IS_C
+# endif
+
+# if LANG_IS_CXX
+# error Unexpected LANG_IS_CXX
+# endif
+#endif
+
+#if !LANG_IS_C_OR_CXX
+# error Expected LANG_IS_C_OR_CXX
+#endif
+
+void consumer_c()
+{
+}
diff --git a/Tests/CMakeCommands/target_compile_definitions/consumer.cpp b/Tests/CMakeCommands/target_compile_definitions/consumer.cpp
new file mode 100644
index 0000000..0999526
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_definitions/consumer.cpp
@@ -0,0 +1,37 @@
+
+#ifdef MY_PRIVATE_DEFINE
+# error Unexpected MY_PRIVATE_DEFINE
+#endif
+
+#ifndef MY_PUBLIC_DEFINE
+# error Expected MY_PUBLIC_DEFINE
+#endif
+
+#ifndef MY_INTERFACE_DEFINE
+# error Expected MY_INTERFACE_DEFINE
+#endif
+
+#ifndef DASH_D_DEFINE
+# error Expected DASH_D_DEFINE
+#endif
+
+#ifndef CONSUMER_LANG_CXX
+# error Expected CONSUMER_LANG_CXX
+#endif
+
+#ifdef CONSUMER_LANG_C
+# error Unexpected CONSUMER_LANG_C
+#endif
+
+#if !LANG_IS_CXX
+# error Expected LANG_IS_CXX
+#endif
+
+#if LANG_IS_C
+# error Unexpected LANG_IS_C
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_compile_definitions/main.cpp b/Tests/CMakeCommands/target_compile_definitions/main.cpp
new file mode 100644
index 0000000..3f64dc8
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_definitions/main.cpp
@@ -0,0 +1,17 @@
+
+#ifndef MY_PRIVATE_DEFINE
+# error Expected MY_PRIVATE_DEFINE
+#endif
+
+#ifndef MY_PUBLIC_DEFINE
+# error Expected MY_PUBLIC_DEFINE
+#endif
+
+#ifdef MY_INTERFACE_DEFINE
+# error Unexpected MY_INTERFACE_DEFINE
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_compile_features/CMakeLists.txt b/Tests/CMakeCommands/target_compile_features/CMakeLists.txt
new file mode 100644
index 0000000..9664025
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_features/CMakeLists.txt
@@ -0,0 +1,65 @@
+cmake_minimum_required(VERSION 3.3)
+project(target_compile_features)
+
+set(CMAKE_VERBOSE_MAKEFILE ON)
+
+if (c_restrict IN_LIST CMAKE_C_COMPILE_FEATURES)
+ add_executable(c_target_compile_features_specific main.c)
+ target_compile_features(c_target_compile_features_specific
+ PRIVATE c_restrict
+ )
+
+ add_library(c_lib_restrict_specific lib_restrict.c)
+ target_compile_features(c_lib_restrict_specific
+ PUBLIC c_restrict
+ )
+
+ add_executable(c_restrict_user_specific restrict_user.c)
+ target_link_libraries(c_restrict_user_specific c_lib_restrict_specific)
+endif()
+
+if (c_std_99 IN_LIST CMAKE_C_COMPILE_FEATURES AND
+ NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
+ add_executable(c_target_compile_features_meta main.c)
+ target_compile_features(c_target_compile_features_meta
+ PRIVATE c_std_99
+ )
+
+ add_library(c_lib_restrict_meta lib_restrict.c)
+ target_compile_features(c_lib_restrict_meta
+ PUBLIC c_std_99
+ )
+
+ add_executable(c_restrict_user_meta restrict_user.c)
+ target_link_libraries(c_restrict_user_meta c_lib_restrict_meta)
+endif()
+
+if (cxx_auto_type IN_LIST CMAKE_CXX_COMPILE_FEATURES)
+ add_executable(cxx_target_compile_features_specific main.cpp)
+ target_compile_features(cxx_target_compile_features_specific
+ PRIVATE cxx_auto_type
+ )
+
+ add_library(cxx_lib_auto_type_specific lib_auto_type.cpp)
+ target_compile_features(cxx_lib_auto_type_specific
+ PUBLIC cxx_auto_type
+ )
+
+ add_executable(cxx_lib_user_specific lib_user.cpp)
+ target_link_libraries(cxx_lib_user_specific cxx_lib_auto_type_specific)
+endif()
+
+if (cxx_std_11 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
+ add_executable(cxx_target_compile_features_meta main.cpp)
+ target_compile_features(cxx_target_compile_features_meta
+ PRIVATE cxx_std_11
+ )
+
+ add_library(cxx_lib_auto_type_meta lib_auto_type.cpp)
+ target_compile_features(cxx_lib_auto_type_meta
+ PUBLIC cxx_std_11
+ )
+
+ add_executable(cxx_lib_user_meta lib_user.cpp)
+ target_link_libraries(cxx_lib_user_meta cxx_lib_auto_type_meta)
+endif()
diff --git a/Tests/CMakeCommands/target_compile_features/lib_auto_type.cpp b/Tests/CMakeCommands/target_compile_features/lib_auto_type.cpp
new file mode 100644
index 0000000..71b2215
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_features/lib_auto_type.cpp
@@ -0,0 +1,6 @@
+
+int getAutoTypeImpl()
+{
+ auto i = 0;
+ return i;
+}
diff --git a/Tests/CMakeCommands/target_compile_features/lib_auto_type.h b/Tests/CMakeCommands/target_compile_features/lib_auto_type.h
new file mode 100644
index 0000000..c825b10
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_features/lib_auto_type.h
@@ -0,0 +1,8 @@
+
+int getAutoTypeImpl();
+
+int getAutoType()
+{
+ auto i = getAutoTypeImpl();
+ return i;
+}
diff --git a/Tests/CMakeCommands/target_compile_features/lib_restrict.c b/Tests/CMakeCommands/target_compile_features/lib_restrict.c
new file mode 100644
index 0000000..2ceec97
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_features/lib_restrict.c
@@ -0,0 +1,9 @@
+
+#include "lib_restrict.h"
+
+int foo(int* restrict a, int* restrict b)
+{
+ (void)a;
+ (void)b;
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_compile_features/lib_restrict.h b/Tests/CMakeCommands/target_compile_features/lib_restrict.h
new file mode 100644
index 0000000..2e528b6
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_features/lib_restrict.h
@@ -0,0 +1,7 @@
+
+#ifndef LIB_RESTRICT_H
+#define LIB_RESTRICT_H
+
+int foo(int* restrict a, int* restrict b);
+
+#endif
diff --git a/Tests/CMakeCommands/target_compile_features/lib_user.cpp b/Tests/CMakeCommands/target_compile_features/lib_user.cpp
new file mode 100644
index 0000000..541e528
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_features/lib_user.cpp
@@ -0,0 +1,7 @@
+
+#include "lib_auto_type.h"
+
+int main(int argc, char** argv)
+{
+ return getAutoType();
+}
diff --git a/Tests/CMakeCommands/target_compile_features/main.c b/Tests/CMakeCommands/target_compile_features/main.c
new file mode 100644
index 0000000..76e98c4
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_features/main.c
@@ -0,0 +1,12 @@
+
+int foo(int* restrict a, int* restrict b)
+{
+ (void)a;
+ (void)b;
+ return 0;
+}
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_compile_features/main.cpp b/Tests/CMakeCommands/target_compile_features/main.cpp
new file mode 100644
index 0000000..6f5daee
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_features/main.cpp
@@ -0,0 +1,6 @@
+
+int main(int, char**)
+{
+ auto i = 0;
+ return i;
+}
diff --git a/Tests/CMakeCommands/target_compile_features/restrict_user.c b/Tests/CMakeCommands/target_compile_features/restrict_user.c
new file mode 100644
index 0000000..76c956f
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_features/restrict_user.c
@@ -0,0 +1,14 @@
+
+#include "lib_restrict.h"
+
+int bar(int* restrict a, int* restrict b)
+{
+ (void)a;
+ (void)b;
+ return foo(a, b);
+}
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_compile_options/CMakeLists.txt b/Tests/CMakeCommands/target_compile_options/CMakeLists.txt
new file mode 100644
index 0000000..268c7eb
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_options/CMakeLists.txt
@@ -0,0 +1,68 @@
+
+cmake_minimum_required(VERSION 2.8.12)
+
+project(target_compile_options)
+
+add_executable(target_compile_options
+ "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
+)
+target_compile_options(target_compile_options
+ PRIVATE $<$<CXX_COMPILER_ID:AppleClang,Clang,GNU>:-DMY_PRIVATE_DEFINE>
+ PUBLIC $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-DMY_PUBLIC_DEFINE>
+ PUBLIC $<$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>:-DMY_MUTLI_COMP_PUBLIC_DEFINE>
+ INTERFACE $<$<CXX_COMPILER_ID:GNU>:-DMY_INTERFACE_DEFINE>
+ INTERFACE $<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-DMY_MULTI_COMP_INTERFACE_DEFINE>
+)
+
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ target_compile_definitions(target_compile_options
+ PRIVATE
+ "DO_GNU_TESTS"
+ )
+elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ target_compile_definitions(target_compile_options
+ PRIVATE
+ "DO_CLANG_TESTS"
+ )
+endif()
+
+add_executable(consumer
+ "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
+)
+
+target_sources(consumer PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/consumer.c"
+)
+target_compile_options(consumer
+ PRIVATE
+ -DCONSUMER_LANG_$<COMPILE_LANGUAGE>
+ -DLANG_IS_CXX=$<COMPILE_LANGUAGE:CXX>
+ -DLANG_IS_C=$<COMPILE_LANGUAGE:C>
+)
+
+if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ target_compile_definitions(consumer
+ PRIVATE TEST_LANG_DEFINES_FOR_VISUAL_STUDIO
+ )
+endif()
+
+target_compile_options(consumer
+ PRIVATE $<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:$<TARGET_PROPERTY:target_compile_options,INTERFACE_COMPILE_OPTIONS>>
+)
+
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ target_compile_definitions(consumer
+ PRIVATE
+ "DO_GNU_TESTS"
+ )
+elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ target_compile_definitions(consumer
+ PRIVATE
+ "DO_CLANG_TESTS"
+ )
+endif()
+
+# Test no items
+target_compile_options(consumer
+ PRIVATE
+)
diff --git a/Tests/CMakeCommands/target_compile_options/consumer.c b/Tests/CMakeCommands/target_compile_options/consumer.c
new file mode 100644
index 0000000..f9b6654
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_options/consumer.c
@@ -0,0 +1,40 @@
+
+// Visual Studio allows only one set of flags for C and C++.
+// In a target using C++ we pick the C++ flags even for C sources.
+#ifdef TEST_LANG_DEFINES_FOR_VISUAL_STUDIO
+# ifndef CONSUMER_LANG_CXX
+# error Expected CONSUMER_LANG_CXX
+# endif
+
+# ifdef CONSUMER_LANG_C
+# error Unexpected CONSUMER_LANG_C
+# endif
+
+# if !LANG_IS_CXX
+# error Expected LANG_IS_CXX
+# endif
+
+# if LANG_IS_C
+# error Unexpected LANG_IS_C
+# endif
+#else
+# ifdef CONSUMER_LANG_CXX
+# error Unexpected CONSUMER_LANG_CXX
+# endif
+
+# ifndef CONSUMER_LANG_C
+# error Expected CONSUMER_LANG_C
+# endif
+
+# if !LANG_IS_C
+# error Expected LANG_IS_C
+# endif
+
+# if LANG_IS_CXX
+# error Unexpected LANG_IS_CXX
+# endif
+#endif
+
+void consumer_c()
+{
+}
diff --git a/Tests/CMakeCommands/target_compile_options/consumer.cpp b/Tests/CMakeCommands/target_compile_options/consumer.cpp
new file mode 100644
index 0000000..78928b4
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_options/consumer.cpp
@@ -0,0 +1,61 @@
+
+#ifdef DO_GNU_TESTS
+
+# ifdef MY_PRIVATE_DEFINE
+# error Unexpected MY_PRIVATE_DEFINE
+# endif
+
+# ifndef MY_PUBLIC_DEFINE
+# error Expected MY_PUBLIC_DEFINE
+# endif
+
+# ifndef MY_INTERFACE_DEFINE
+# error Expected MY_INTERFACE_DEFINE
+# endif
+
+# ifndef MY_MULTI_COMP_INTERFACE_DEFINE
+# error Expected MY_MULTI_COMP_INTERFACE_DEFINE
+# endif
+
+# ifndef MY_MUTLI_COMP_PUBLIC_DEFINE
+# error Expected MY_MUTLI_COMP_PUBLIC_DEFINE
+# endif
+
+#endif
+
+#ifdef DO_CLANG_TESTS
+
+# ifdef MY_PRIVATE_DEFINE
+# error Unexpected MY_PRIVATE_DEFINE
+# endif
+
+# ifndef MY_MULTI_COMP_INTERFACE_DEFINE
+# error Expected MY_MULTI_COMP_INTERFACE_DEFINE
+# endif
+
+# ifndef MY_MUTLI_COMP_PUBLIC_DEFINE
+# error Expected MY_MUTLI_COMP_PUBLIC_DEFINE
+# endif
+
+#endif
+
+#ifndef CONSUMER_LANG_CXX
+# error Expected CONSUMER_LANG_CXX
+#endif
+
+#ifdef CONSUMER_LANG_C
+# error Unexpected CONSUMER_LANG_C
+#endif
+
+#if !LANG_IS_CXX
+# error Expected LANG_IS_CXX
+#endif
+
+#if LANG_IS_C
+# error Unexpected LANG_IS_C
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_compile_options/main.cpp b/Tests/CMakeCommands/target_compile_options/main.cpp
new file mode 100644
index 0000000..7608400
--- /dev/null
+++ b/Tests/CMakeCommands/target_compile_options/main.cpp
@@ -0,0 +1,41 @@
+
+#ifdef DO_GNU_TESTS
+
+# ifndef MY_PRIVATE_DEFINE
+# error Expected MY_PRIVATE_DEFINE
+# endif
+
+# ifndef MY_PUBLIC_DEFINE
+# error Expected MY_PUBLIC_DEFINE
+# endif
+
+# ifndef MY_MUTLI_COMP_PUBLIC_DEFINE
+# error Expected MY_MUTLI_COMP_PUBLIC_DEFINE
+# endif
+
+# ifdef MY_INTERFACE_DEFINE
+# error Unexpected MY_INTERFACE_DEFINE
+# endif
+
+#endif
+
+#ifdef DO_CLANG_TESTS
+
+# ifndef MY_PRIVATE_DEFINE
+# error Expected MY_PRIVATE_DEFINE
+# endif
+
+# ifdef MY_PUBLIC_DEFINE
+# error Unexpected MY_PUBLIC_DEFINE
+# endif
+
+# ifndef MY_MUTLI_COMP_PUBLIC_DEFINE
+# error Expected MY_MUTLI_COMP_PUBLIC_DEFINE
+# endif
+
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_include_directories/CMakeLists.txt b/Tests/CMakeCommands/target_include_directories/CMakeLists.txt
new file mode 100644
index 0000000..0702ab5
--- /dev/null
+++ b/Tests/CMakeCommands/target_include_directories/CMakeLists.txt
@@ -0,0 +1,85 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(target_include_directories)
+
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/privateinclude")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/privateinclude/privateinclude.h" "#define PRIVATEINCLUDE_DEFINE\n")
+
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/publicinclude")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/publicinclude/publicinclude.h" "#define PUBLICINCLUDE_DEFINE\n")
+
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/interfaceinclude")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/interfaceinclude/interfaceinclude.h" "#define INTERFACEINCLUDE_DEFINE\n")
+
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/poison")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/poison/common.h" "#error Should not be included\n")
+
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/cure")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cure/common.h" "#define CURE_DEFINE\n")
+
+add_executable(target_include_directories
+ "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
+)
+target_include_directories(target_include_directories
+ PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/privateinclude"
+ PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/publicinclude"
+ INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/interfaceinclude"
+)
+
+target_include_directories(target_include_directories
+ PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/poison"
+)
+target_include_directories(target_include_directories
+ BEFORE PUBLIC "$<$<STREQUAL:$<TARGET_PROPERTY:target_include_directories,TYPE>,EXECUTABLE>:${CMAKE_CURRENT_BINARY_DIR}/cure>"
+)
+
+# Has no effect because the target type is not SHARED_LIBRARY:
+target_include_directories(target_include_directories
+ BEFORE PUBLIC "$<$<STREQUAL:$<TARGET_PROPERTY:target_include_directories,TYPE>,SHARED_LIBRARY>:${CMAKE_CURRENT_BINARY_DIR}/poison>"
+)
+
+add_executable(consumer
+ "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
+)
+
+target_sources(consumer PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/consumer.c"
+)
+target_include_directories(consumer
+ PRIVATE
+ $<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_only>
+ $<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_SOURCE_DIR}/c_only>
+)
+if(CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
+ target_compile_definitions(consumer
+ PRIVATE TEST_LANG_DEFINES_FOR_VISUAL_STUDIO_OR_XCODE
+ )
+endif()
+
+target_include_directories(consumer
+ PRIVATE
+ $<TARGET_PROPERTY:target_include_directories,INTERFACE_INCLUDE_DIRECTORIES>
+ relative_dir
+ relative_dir/$<TARGET_PROPERTY:NAME>
+)
+
+# Test no items
+target_include_directories(consumer
+ PRIVATE
+)
+target_include_directories(consumer
+ BEFORE PRIVATE
+)
+target_include_directories(consumer
+ SYSTEM BEFORE PRIVATE
+)
+target_include_directories(consumer
+ SYSTEM PRIVATE
+)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+add_library(imp UNKNOWN IMPORTED)
+get_target_property(_res imp INCLUDE_DIRECTORIES)
+if (_res)
+ message(SEND_ERROR "include_directories populated the INCLUDE_DIRECTORIES target property")
+endif()
diff --git a/Tests/CMakeCommands/target_include_directories/c_only/c_only.h b/Tests/CMakeCommands/target_include_directories/c_only/c_only.h
new file mode 100644
index 0000000..29f68ee
--- /dev/null
+++ b/Tests/CMakeCommands/target_include_directories/c_only/c_only.h
@@ -0,0 +1,2 @@
+
+#define C_ONLY_DEFINE
diff --git a/Tests/CMakeCommands/target_include_directories/consumer.c b/Tests/CMakeCommands/target_include_directories/consumer.c
new file mode 100644
index 0000000..7fd694b
--- /dev/null
+++ b/Tests/CMakeCommands/target_include_directories/consumer.c
@@ -0,0 +1,21 @@
+
+// Visual Studio allows only one set of flags for C and C++.
+// In a target using C++ we pick the C++ flags even for C sources.
+#ifdef TEST_LANG_DEFINES_FOR_VISUAL_STUDIO_OR_XCODE
+# include "cxx_only.h"
+
+# ifndef CXX_ONLY_DEFINE
+# error Expected CXX_ONLY_DEFINE
+# endif
+#else
+# include "c_only.h"
+
+# ifndef C_ONLY_DEFINE
+# error Expected C_ONLY_DEFINE
+# endif
+#endif
+
+int consumer_c()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_include_directories/consumer.cpp b/Tests/CMakeCommands/target_include_directories/consumer.cpp
new file mode 100644
index 0000000..d349650
--- /dev/null
+++ b/Tests/CMakeCommands/target_include_directories/consumer.cpp
@@ -0,0 +1,41 @@
+
+#include "consumer.h"
+
+#include "common.h"
+#include "cxx_only.h"
+#include "interfaceinclude.h"
+#include "publicinclude.h"
+#include "relative_dir.h"
+
+#ifdef PRIVATEINCLUDE_DEFINE
+# error Unexpected PRIVATEINCLUDE_DEFINE
+#endif
+
+#ifndef PUBLICINCLUDE_DEFINE
+# error Expected PUBLICINCLUDE_DEFINE
+#endif
+
+#ifndef INTERFACEINCLUDE_DEFINE
+# error Expected INTERFACEINCLUDE_DEFINE
+#endif
+
+#ifndef CURE_DEFINE
+# error Expected CURE_DEFINE
+#endif
+
+#ifndef RELATIVE_DIR_DEFINE
+# error Expected RELATIVE_DIR_DEFINE
+#endif
+
+#ifndef CONSUMER_DEFINE
+# error Expected CONSUMER_DEFINE
+#endif
+
+#ifndef CXX_ONLY_DEFINE
+# error Expected CXX_ONLY_DEFINE
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_include_directories/cxx_only/cxx_only.h b/Tests/CMakeCommands/target_include_directories/cxx_only/cxx_only.h
new file mode 100644
index 0000000..67289a4
--- /dev/null
+++ b/Tests/CMakeCommands/target_include_directories/cxx_only/cxx_only.h
@@ -0,0 +1,2 @@
+
+#define CXX_ONLY_DEFINE
diff --git a/Tests/CMakeCommands/target_include_directories/main.cpp b/Tests/CMakeCommands/target_include_directories/main.cpp
new file mode 100644
index 0000000..dd591bf
--- /dev/null
+++ b/Tests/CMakeCommands/target_include_directories/main.cpp
@@ -0,0 +1,25 @@
+
+#include "common.h"
+#include "privateinclude.h"
+#include "publicinclude.h"
+
+#ifndef PRIVATEINCLUDE_DEFINE
+# error Expected PRIVATEINCLUDE_DEFINE
+#endif
+
+#ifndef PUBLICINCLUDE_DEFINE
+# error Expected PUBLICINCLUDE_DEFINE
+#endif
+
+#ifdef INTERFACEINCLUDE_DEFINE
+# error Unexpected INTERFACEINCLUDE_DEFINE
+#endif
+
+#ifndef CURE_DEFINE
+# error Expected CURE_DEFINE
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_include_directories/relative_dir/consumer/consumer.h b/Tests/CMakeCommands/target_include_directories/relative_dir/consumer/consumer.h
new file mode 100644
index 0000000..b915373
--- /dev/null
+++ b/Tests/CMakeCommands/target_include_directories/relative_dir/consumer/consumer.h
@@ -0,0 +1,2 @@
+
+#define CONSUMER_DEFINE
diff --git a/Tests/CMakeCommands/target_include_directories/relative_dir/relative_dir.h b/Tests/CMakeCommands/target_include_directories/relative_dir/relative_dir.h
new file mode 100644
index 0000000..7017b61
--- /dev/null
+++ b/Tests/CMakeCommands/target_include_directories/relative_dir/relative_dir.h
@@ -0,0 +1,2 @@
+
+#define RELATIVE_DIR_DEFINE
diff --git a/Tests/CMakeCommands/target_link_directories/CMakeLists.txt b/Tests/CMakeCommands/target_link_directories/CMakeLists.txt
new file mode 100644
index 0000000..bc7b9b2
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_directories/CMakeLists.txt
@@ -0,0 +1,40 @@
+
+cmake_minimum_required(VERSION 3.12)
+
+project(target_link_directories LANGUAGES C)
+
+add_library(target_link_directories SHARED LinkDirectoriesLib.c)
+# Test no items
+target_link_directories(target_link_directories PRIVATE)
+
+add_library(target_link_directories_2 SHARED EXCLUDE_FROM_ALL LinkDirectoriesLib.c)
+target_link_directories(target_link_directories_2 PRIVATE /private/dir INTERFACE /interface/dir)
+get_target_property(result target_link_directories_2 LINK_DIRECTORIES)
+if (NOT result MATCHES "/private/dir")
+ message(SEND_ERROR "${result} target_link_directories not populated the LINK_DIRECTORIES target property")
+endif()
+get_target_property(result target_link_directories_2 INTERFACE_LINK_DIRECTORIES)
+if (NOT result MATCHES "/interface/dir")
+ message(SEND_ERROR "target_link_directories not populated the INTERFACE_LINK_DIRECTORIES target property of shared library")
+endif()
+
+add_library(target_link_directories_3 STATIC EXCLUDE_FROM_ALL LinkDirectoriesLib.c)
+target_link_directories(target_link_directories_3 INTERFACE /interface/dir)
+get_target_property(result target_link_directories_3 INTERFACE_LINK_DIRECTORIES)
+if (NOT result MATCHES "/interface/dir")
+ message(SEND_ERROR "target_link_directories not populated the INTERFACE_LINK_DIRECTORIES target property of static library")
+endif()
+
+add_library(target_link_directories_4 SHARED EXCLUDE_FROM_ALL LinkDirectoriesLib.c)
+target_link_directories(target_link_directories_4 PRIVATE relative/dir)
+get_target_property(result target_link_directories_4 LINK_DIRECTORIES)
+if (NOT result MATCHES "${CMAKE_CURRENT_SOURCE_DIR}/relative/dir")
+ message(SEND_ERROR "target_link_directories not populated the LINK_DIRECTORIES with relative path")
+endif()
+
+add_subdirectory(subdir)
+target_link_directories(target_link_directories_5 PRIVATE relative/dir)
+get_target_property(result target_link_directories_5 LINK_DIRECTORIES)
+if (NOT result MATCHES "${CMAKE_CURRENT_SOURCE_DIR}/relative/dir")
+ message(SEND_ERROR "target_link_directories not populated the LINK_DIRECTORIES with relative path")
+endif()
diff --git a/Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c b/Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c
new file mode 100644
index 0000000..9bbd24c
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c
@@ -0,0 +1,7 @@
+#if defined(_WIN32)
+__declspec(dllexport)
+#endif
+ int flags_lib(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt b/Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt
new file mode 100644
index 0000000..7e7ad2a
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+add_library(target_link_directories_5 SHARED EXCLUDE_FROM_ALL ../LinkDirectoriesLib.c)
diff --git a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
new file mode 100644
index 0000000..aa8e21a
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
@@ -0,0 +1,151 @@
+# Using 2.8 will trigger a deprecation warning. In this case it's explicitly
+# intentional since the tests checks various policy implementations prior to
+# 2.8.12
+cmake_minimum_required(VERSION 2.8)
+
+project(target_link_libraries)
+
+file(WRITE
+ "${CMAKE_CURRENT_BINARY_DIR}/main.cxx"
+ "int main() { return 0; }
+"
+)
+
+add_executable(
+ target_link_libraries
+ "${CMAKE_CURRENT_BINARY_DIR}/main.cxx"
+)
+
+macro(ASSERT_PROPERTY _target _property _value)
+ get_target_property(_out ${_target} ${_property})
+ if (NOT _out)
+ set(_out "")
+ endif()
+ if (NOT "${_out}" STREQUAL "${_value}")
+ message(SEND_ERROR "Target ${_target} does not have property ${_property} with value ${_value}. Actual value: ${_out}")
+ endif()
+endmacro()
+
+include(GenerateExportHeader)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_library(depA SHARED depA.cpp)
+generate_export_header(depA)
+
+add_library(depB SHARED depB.cpp)
+generate_export_header(depB)
+
+target_link_libraries(depB LINK_PRIVATE depA LINK_PRIVATE depA)
+
+add_library(libgenex SHARED libgenex.cpp)
+generate_export_header(libgenex)
+
+set_property(TARGET depB APPEND PROPERTY
+ LINK_LIBRARIES $<1:libgenex>
+)
+
+add_library(depC SHARED depC.cpp)
+generate_export_header(depC)
+
+target_link_libraries(depC LINK_PUBLIC depA LINK_PUBLIC depA)
+
+assert_property(depA LINK_INTERFACE_LIBRARIES "")
+assert_property(depB LINK_INTERFACE_LIBRARIES "")
+assert_property(depC LINK_INTERFACE_LIBRARIES "depA;depA")
+
+add_executable(targetA targetA.cpp)
+
+target_link_libraries(targetA LINK_INTERFACE_LIBRARIES depA depB)
+
+assert_property(targetA LINK_INTERFACE_LIBRARIES "depA;depB")
+
+set_target_properties(targetA PROPERTIES LINK_INTERFACE_LIBRARIES "")
+
+assert_property(targetA LINK_INTERFACE_LIBRARIES "")
+
+add_subdirectory(subdir)
+target_link_libraries(targetA subdirlib)
+
+target_link_libraries(targetA depB depC)
+
+assert_property(targetA LINK_INTERFACE_LIBRARIES "")
+
+# Exclude depIfaceOnly from ALL so that it will only be built if something
+# depends on it. As it is in the link interface of depB, targetA
+# will depend on it. That dependency is what is being tested here.
+add_library(depIfaceOnly SHARED EXCLUDE_FROM_ALL depIfaceOnly.cpp)
+generate_export_header(depIfaceOnly)
+set_property(TARGET depB APPEND PROPERTY LINK_INTERFACE_LIBRARIES depIfaceOnly)
+
+add_library(depD SHARED depD.cpp)
+generate_export_header(depD)
+set_property(TARGET depD APPEND PROPERTY
+ LINK_INTERFACE_LIBRARIES
+ $<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:depA>
+)
+
+add_executable(targetB targetB.cpp)
+target_link_libraries(targetB depD)
+
+macro(create_header _name)
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${_name}")
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_name}/${_name}.h" "//${_name}.h\n")
+endmacro()
+
+create_header(foo)
+create_header(bar)
+
+add_library(depG SHARED depG.cpp)
+generate_export_header(depG)
+target_include_directories(depG INTERFACE
+ "${CMAKE_CURRENT_BINARY_DIR}/foo"
+ "${CMAKE_CURRENT_BINARY_DIR}/bar"
+)
+target_compile_definitions(depG INTERFACE
+ TEST_DEF
+)
+
+
+add_executable(targetC targetC.cpp)
+if(NOT BORLAND AND NOT WATCOM)
+ # Linking to a target containing a + should be non-fatal, though it does
+ # not work at all on Borland or watcom
+ add_library(wrapc++ empty.cpp)
+ target_link_libraries(targetC wrapc++)
+endif()
+# The TARGET_PROPERTY expression is duplicated below to test that there is no
+# shortcutting of the evaluation by returning an empty string.
+set(_exe_test $<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>)
+target_link_libraries(targetC $<$<AND:${_exe_test},${_exe_test}>:depG>)
+
+add_library(libConsumer empty.cpp)
+# This line causes $<$<CONFIG:Debug>:depA> to be used when
+# determining the include directories for libConsumer based on the
+# interface properties of its LINK_LIBRARIES. Because the above expression
+# evaluates to the empty string in non-Debug cases, ensure that that causes
+# no problems.
+target_link_libraries(libConsumer debug depA)
+
+add_subdirectory(cmp0022)
+
+add_executable(newsignature1 newsignature1.cpp)
+target_link_libraries(newsignature1 PRIVATE depC INTERFACE depD PUBLIC depB PRIVATE subdirlib INTERFACE INTERFACE PUBLIC)
+
+assert_property(newsignature1 INTERFACE_LINK_LIBRARIES "depD;depB")
+assert_property(newsignature1 LINK_LIBRARIES "depC;depB;subdirlib")
+
+#----------------------------------------------------------------------------
+# Test cross-directory linking.
+cmake_policy(PUSH)
+cmake_policy(SET CMP0022 NEW)
+cmake_policy(SET CMP0079 NEW)
+add_executable(TopDir TopDir.c)
+add_subdirectory(SubDirA)
+add_subdirectory(SubDirB)
+target_link_libraries(SubDirB TopDirImported)
+add_subdirectory(SubDirC)
+target_link_libraries(SubDirC PRIVATE SubDirC2)
+target_link_libraries(TopDir SubDirC)
+add_library(TopDirImported IMPORTED INTERFACE)
+target_compile_definitions(TopDirImported INTERFACE DEF_TopDirImported)
+cmake_policy(POP)
diff --git a/Tests/CMakeCommands/target_link_libraries/SubDirA/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/SubDirA/CMakeLists.txt
new file mode 100644
index 0000000..4dae103
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/SubDirA/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_executable(SubDirA SubDirA.c)
+
+# Link to a target imported in this directory that would not normally
+# be visible to the directory in which TopDir is defined.
+target_link_libraries(TopDir PUBLIC SameNameImported)
+
+# Link SubDirA to a target imported in this directory that has the same
+# name as a target imported in SubDirB's directory. SubDirB will also
+# tell us to link its copy. At compile time we verify both are linked.
+target_link_libraries(SubDirA PRIVATE SameNameImported)
+
+# Import a target with the same name as a target imported in SubDirB.
+# Distinguish this copy by having a unique usage requirement.
+add_library(SameNameImported IMPORTED INTERFACE)
+target_compile_definitions(SameNameImported INTERFACE DEF_SameNameImportedSubDirA)
diff --git a/Tests/CMakeCommands/target_link_libraries/SubDirA/SubDirA.c b/Tests/CMakeCommands/target_link_libraries/SubDirA/SubDirA.c
new file mode 100644
index 0000000..4706bb9
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/SubDirA/SubDirA.c
@@ -0,0 +1,14 @@
+#ifndef DEF_SameNameImportedSubDirA
+# error "DEF_SameNameImportedSubDirA is not defined but should be!"
+#endif
+#ifndef DEF_SameNameImportedSubDirB
+# error "DEF_SameNameImportedSubDirB is not defined but should be!"
+#endif
+#ifdef DEF_TopDirImported
+# error "DEF_TopDirImported is defined but should not be!"
+#endif
+
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt
new file mode 100644
index 0000000..06d1111
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_executable(SubDirB SubDirB.c)
+
+# Link to a target imported in this directory that would not normally
+# be visible to the directory in which TopDir is defined.
+target_link_libraries(TopDir PUBLIC debug SameNameImported optimized SameNameImported)
+
+# Link to a list of targets imported in this directory that would not
+# normally be visible to the directory in which TopDir is defined.
+target_link_libraries(TopDir PUBLIC "$<1:SameNameImported;SameNameImported>")
+
+# Link SubDirA to a target imported in this directory that has the same
+# name as a target imported in SubDirA's directory. We verify when
+# compiling SubDirA that it sees our target and its own.
+target_link_libraries(SubDirA PRIVATE SameNameImported)
+
+# Import a target with the same name as a target imported in SubDirA.
+# Distinguish this copy by having a unique usage requirement.
+add_library(SameNameImported IMPORTED INTERFACE)
+target_compile_definitions(SameNameImported INTERFACE DEF_SameNameImportedSubDirB)
diff --git a/Tests/CMakeCommands/target_link_libraries/SubDirB/SubDirB.c b/Tests/CMakeCommands/target_link_libraries/SubDirB/SubDirB.c
new file mode 100644
index 0000000..6e56729
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/SubDirB/SubDirB.c
@@ -0,0 +1,14 @@
+#ifdef DEF_SameNameImportedSubDirA
+# error "DEF_SameNameImportedSubDirA is defined but should not be!"
+#endif
+#ifdef DEF_SameNameImportedSubDirB
+# error "DEF_SameNameImportedSubDirB is defined but should not be!"
+#endif
+#ifndef DEF_TopDirImported
+# error "DEF_TopDirImported is not defined but should be!"
+#endif
+
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/SubDirC/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/SubDirC/CMakeLists.txt
new file mode 100644
index 0000000..54bcc51
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/SubDirC/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_library(SubDirC STATIC SubDirC.c)
+
+add_library(SubDirC1 INTERFACE)
+target_compile_definitions(SubDirC1 INTERFACE DEF_SubDirC1)
+
+add_library(SubDirC2 INTERFACE)
+target_compile_definitions(SubDirC2 INTERFACE DEF_SubDirC2)
+
+target_link_libraries(SubDirC PRIVATE SubDirC1)
diff --git a/Tests/CMakeCommands/target_link_libraries/SubDirC/SubDirC.c b/Tests/CMakeCommands/target_link_libraries/SubDirC/SubDirC.c
new file mode 100644
index 0000000..c5536dc
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/SubDirC/SubDirC.c
@@ -0,0 +1,11 @@
+#ifndef DEF_SubDirC1
+# error "DEF_SubDirC1 not defined"
+#endif
+#ifndef DEF_SubDirC2
+# error "DEF_SubDirC2 not defined"
+#endif
+
+int SubDirC(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/TopDir.c b/Tests/CMakeCommands/target_link_libraries/TopDir.c
new file mode 100644
index 0000000..d8066e5
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/TopDir.c
@@ -0,0 +1,20 @@
+#ifndef DEF_SameNameImportedSubDirA
+# error "DEF_SameNameImportedSubDirA is not defined but should be!"
+#endif
+#ifndef DEF_SameNameImportedSubDirB
+# error "DEF_SameNameImportedSubDirB is not defined but should be!"
+#endif
+#ifdef DEF_TopDirImported
+# error "DEF_TopDirImported is defined but should not be!"
+#endif
+#ifdef DEF_SubDirC1
+# error "DEF_SubDirC1 defined but should not be"
+#endif
+#ifdef DEF_SubDirC2
+# error "DEF_SubDirC2 defined but should not be"
+#endif
+
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/cmp0022/CMakeLists.txt
new file mode 100644
index 0000000..741c73e
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/CMakeLists.txt
@@ -0,0 +1,47 @@
+
+include(GenerateExportHeader)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+cmake_policy(SET CMP0022 NEW)
+add_library(cmp0022lib SHARED cmp0022lib.cpp)
+generate_export_header(cmp0022lib)
+add_library(cmp0022ifacelib SHARED cmp0022ifacelib.cpp)
+generate_export_header(cmp0022ifacelib)
+target_link_libraries(cmp0022lib LINK_PUBLIC cmp0022ifacelib)
+
+assert_property(cmp0022lib LINK_INTERFACE_LIBRARIES "")
+assert_property(cmp0022ifacelib LINK_INTERFACE_LIBRARIES "")
+assert_property(cmp0022lib INTERFACE_LINK_LIBRARIES "cmp0022ifacelib")
+assert_property(cmp0022ifacelib INTERFACE_LINK_LIBRARIES "")
+
+add_executable(cmp0022exe cmp0022exe.cpp)
+target_link_libraries(cmp0022exe cmp0022lib)
+
+add_library(staticlib1 STATIC staticlib1.cpp)
+generate_export_header(staticlib1)
+add_library(staticlib2 STATIC staticlib2.cpp)
+generate_export_header(staticlib2)
+target_link_libraries(staticlib1 LINK_PUBLIC staticlib2)
+
+# Try adding a private link item to be propagated out of a static lib.
+set(private_link "")
+if (CMAKE_CXX_COMPILER_ID MATCHES GNU OR CMAKE_CXX_COMPILER_ID MATCHES Clang)
+ if (CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+ set(private_link "-Wl,-V")
+ else()
+ set(private_link "-Wl,-v")
+ endif()
+endif()
+if(private_link)
+ target_link_libraries(staticlib1 LINK_PRIVATE "${private_link}")
+endif()
+
+add_executable(staticlib_exe staticlib_exe.cpp)
+target_link_libraries(staticlib_exe staticlib1)
+
+add_library(onlyplainlib1 SHARED onlyplainlib1.cpp)
+add_library(onlyplainlib2 SHARED onlyplainlib2.cpp)
+target_link_libraries(onlyplainlib2 onlyplainlib1)
+
+add_executable(onlyplainlib_user onlyplainlib_user.cpp)
+target_link_libraries(onlyplainlib_user onlyplainlib2)
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022exe.cpp b/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022exe.cpp
new file mode 100644
index 0000000..008bb74
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022exe.cpp
@@ -0,0 +1,7 @@
+
+#include "cmp0022lib.h"
+
+int main(void)
+{
+ return cmp0022().Value;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022ifacelib.cpp b/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022ifacelib.cpp
new file mode 100644
index 0000000..b285be0
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022ifacelib.cpp
@@ -0,0 +1,9 @@
+
+#include "cmp0022ifacelib.h"
+
+CMP0022Iface cmp0022iface()
+{
+ CMP0022Iface iface;
+ iface.Value = 0;
+ return iface;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022ifacelib.h b/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022ifacelib.h
new file mode 100644
index 0000000..616dbf6
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022ifacelib.h
@@ -0,0 +1,9 @@
+
+#include "cmp0022ifacelib_export.h"
+
+struct CMP0022Iface
+{
+ int Value;
+};
+
+CMP0022Iface CMP0022IFACELIB_EXPORT cmp0022iface();
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022lib.cpp b/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022lib.cpp
new file mode 100644
index 0000000..381d463
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022lib.cpp
@@ -0,0 +1,7 @@
+
+#include "cmp0022lib.h"
+
+CMP0022Iface cmp0022()
+{
+ return cmp0022iface();
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022lib.h b/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022lib.h
new file mode 100644
index 0000000..e939013
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/cmp0022lib.h
@@ -0,0 +1,5 @@
+
+#include "cmp0022ifacelib.h"
+#include "cmp0022lib_export.h"
+
+CMP0022Iface CMP0022LIB_EXPORT cmp0022();
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib1.cpp b/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib1.cpp
new file mode 100644
index 0000000..80b3c08
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib1.cpp
@@ -0,0 +1,12 @@
+
+#include "onlyplainlib1.h"
+
+OnlyPlainLib1::OnlyPlainLib1()
+ : result(0)
+{
+}
+
+int OnlyPlainLib1::GetResult()
+{
+ return result;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib1.h b/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib1.h
new file mode 100644
index 0000000..2bc04ee
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib1.h
@@ -0,0 +1,14 @@
+
+struct
+#ifdef _WIN32
+ __declspec(dllexport)
+#endif
+ OnlyPlainLib1
+{
+ OnlyPlainLib1();
+
+ int GetResult();
+
+private:
+ int result;
+};
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib2.cpp b/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib2.cpp
new file mode 100644
index 0000000..2865ae9
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib2.cpp
@@ -0,0 +1,8 @@
+
+#include "onlyplainlib2.h"
+
+OnlyPlainLib1 onlyPlainLib2()
+{
+ OnlyPlainLib1 opl1;
+ return opl1;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib2.h b/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib2.h
new file mode 100644
index 0000000..6f18d20
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib2.h
@@ -0,0 +1,7 @@
+
+#include "onlyplainlib1.h"
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ OnlyPlainLib1 onlyPlainLib2();
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib_user.cpp b/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib_user.cpp
new file mode 100644
index 0000000..02e9415
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/onlyplainlib_user.cpp
@@ -0,0 +1,7 @@
+
+#include "onlyplainlib2.h"
+
+int main(int argc, char** argv)
+{
+ return onlyPlainLib2().GetResult();
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib1.cpp b/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib1.cpp
new file mode 100644
index 0000000..d6b3986
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib1.cpp
@@ -0,0 +1,5 @@
+
+int staticlib1()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib1.h b/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib1.h
new file mode 100644
index 0000000..7d58b10
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib1.h
@@ -0,0 +1,4 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int staticlib1();
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib2.cpp b/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib2.cpp
new file mode 100644
index 0000000..bd1a901
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib2.cpp
@@ -0,0 +1,5 @@
+
+int staticlib2()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib2.h b/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib2.h
new file mode 100644
index 0000000..bbfdaa3
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib2.h
@@ -0,0 +1,4 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int staticlib2();
diff --git a/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib_exe.cpp b/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib_exe.cpp
new file mode 100644
index 0000000..97adc40
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/cmp0022/staticlib_exe.cpp
@@ -0,0 +1,8 @@
+
+#include "staticlib1.h"
+#include "staticlib2.h"
+
+int main()
+{
+ return staticlib1() + staticlib2();
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/depA.cpp b/Tests/CMakeCommands/target_link_libraries/depA.cpp
new file mode 100644
index 0000000..c2e8e7b
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depA.cpp
@@ -0,0 +1,7 @@
+
+#include "depA.h"
+
+int DepA::foo()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/depA.h b/Tests/CMakeCommands/target_link_libraries/depA.h
new file mode 100644
index 0000000..7a85948
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depA.h
@@ -0,0 +1,7 @@
+
+#include "depa_export.h"
+
+struct DEPA_EXPORT DepA
+{
+ int foo();
+};
diff --git a/Tests/CMakeCommands/target_link_libraries/depB.cpp b/Tests/CMakeCommands/target_link_libraries/depB.cpp
new file mode 100644
index 0000000..276a91a
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depB.cpp
@@ -0,0 +1,14 @@
+
+#include "depB.h"
+
+#include "depA.h"
+#include "libgenex.h"
+
+int DepB::foo()
+{
+ DepA a;
+
+ LibGenex lg;
+
+ return a.foo() + lg.foo();
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/depB.h b/Tests/CMakeCommands/target_link_libraries/depB.h
new file mode 100644
index 0000000..e617813
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depB.h
@@ -0,0 +1,7 @@
+
+#include "depb_export.h"
+
+struct DEPB_EXPORT DepB
+{
+ int foo();
+};
diff --git a/Tests/CMakeCommands/target_link_libraries/depC.cpp b/Tests/CMakeCommands/target_link_libraries/depC.cpp
new file mode 100644
index 0000000..60bed59
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depC.cpp
@@ -0,0 +1,13 @@
+
+#include "depC.h"
+
+int DepC::foo()
+{
+ return 0;
+}
+
+DepA DepC::getA()
+{
+ DepA a;
+ return a;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/depC.h b/Tests/CMakeCommands/target_link_libraries/depC.h
new file mode 100644
index 0000000..af7bfa3
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depC.h
@@ -0,0 +1,10 @@
+
+#include "depA.h"
+#include "depc_export.h"
+
+struct DEPC_EXPORT DepC
+{
+ int foo();
+
+ DepA getA();
+};
diff --git a/Tests/CMakeCommands/target_link_libraries/depD.cpp b/Tests/CMakeCommands/target_link_libraries/depD.cpp
new file mode 100644
index 0000000..b02c76c
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depD.cpp
@@ -0,0 +1,13 @@
+
+#include "depD.h"
+
+int DepD::foo()
+{
+ return 0;
+}
+
+DepA DepD::getA()
+{
+ DepA a;
+ return a;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/depD.h b/Tests/CMakeCommands/target_link_libraries/depD.h
new file mode 100644
index 0000000..e3700c3
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depD.h
@@ -0,0 +1,10 @@
+
+#include "depA.h"
+#include "depd_export.h"
+
+struct DEPD_EXPORT DepD
+{
+ int foo();
+
+ DepA getA();
+};
diff --git a/Tests/CMakeCommands/target_link_libraries/depG.cpp b/Tests/CMakeCommands/target_link_libraries/depG.cpp
new file mode 100644
index 0000000..65b9655
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depG.cpp
@@ -0,0 +1,7 @@
+
+#include "depG.h"
+
+int DepG::foo()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/depG.h b/Tests/CMakeCommands/target_link_libraries/depG.h
new file mode 100644
index 0000000..1a36589
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depG.h
@@ -0,0 +1,7 @@
+
+#include "depg_export.h"
+
+struct DEPG_EXPORT DepG
+{
+ int foo();
+};
diff --git a/Tests/CMakeCommands/target_link_libraries/depIfaceOnly.cpp b/Tests/CMakeCommands/target_link_libraries/depIfaceOnly.cpp
new file mode 100644
index 0000000..3b90af0
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depIfaceOnly.cpp
@@ -0,0 +1,7 @@
+
+#include "depIfaceOnly.h"
+
+int DepIfaceOnly::foo()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/depIfaceOnly.h b/Tests/CMakeCommands/target_link_libraries/depIfaceOnly.h
new file mode 100644
index 0000000..dddf6a5
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depIfaceOnly.h
@@ -0,0 +1,7 @@
+
+#include "depifaceonly_export.h"
+
+struct DEPIFACEONLY_EXPORT DepIfaceOnly
+{
+ int foo();
+};
diff --git a/Tests/CMakeCommands/target_link_libraries/empty.cpp b/Tests/CMakeCommands/target_link_libraries/empty.cpp
new file mode 100644
index 0000000..a6ecef8
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/empty.cpp
@@ -0,0 +1,3 @@
+// Solaris needs non-empty content so ensure
+// we have at least one symbol
+int Solaris_requires_a_symbol_here = 0;
diff --git a/Tests/CMakeCommands/target_link_libraries/libgenex.cpp b/Tests/CMakeCommands/target_link_libraries/libgenex.cpp
new file mode 100644
index 0000000..c925c08
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/libgenex.cpp
@@ -0,0 +1,7 @@
+
+#include "libgenex.h"
+
+int LibGenex::foo()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/libgenex.h b/Tests/CMakeCommands/target_link_libraries/libgenex.h
new file mode 100644
index 0000000..59ac18a
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/libgenex.h
@@ -0,0 +1,12 @@
+
+#include "libgenex_export.h"
+
+#ifndef LIBGENEX_H
+# define LIBGENEX_H
+
+struct LIBGENEX_EXPORT LibGenex
+{
+ int foo();
+};
+
+#endif
diff --git a/Tests/CMakeCommands/target_link_libraries/newsignature1.cpp b/Tests/CMakeCommands/target_link_libraries/newsignature1.cpp
new file mode 100644
index 0000000..b23b7a0
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/newsignature1.cpp
@@ -0,0 +1,18 @@
+
+#include "depB.h"
+#include "depC.h"
+#include "depIfaceOnly.h"
+#include "subdirlib.h"
+
+int main(int, char**)
+{
+ DepA a;
+ DepB b;
+ DepC c;
+
+ DepIfaceOnly iface_only;
+
+ SubDirLibObject sd;
+
+ return a.foo() + b.foo() + c.foo() + iface_only.foo() + sd.foo();
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/subdir/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/subdir/CMakeLists.txt
new file mode 100644
index 0000000..9d7fa6c
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/subdir/CMakeLists.txt
@@ -0,0 +1,5 @@
+
+set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
+
+add_library(subdirlib SHARED subdirlib.cpp)
+generate_export_header(subdirlib)
diff --git a/Tests/CMakeCommands/target_link_libraries/subdir/subdirlib.cpp b/Tests/CMakeCommands/target_link_libraries/subdir/subdirlib.cpp
new file mode 100644
index 0000000..cd2f1a2
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/subdir/subdirlib.cpp
@@ -0,0 +1,7 @@
+
+#include "subdirlib.h"
+
+int SubDirLibObject::foo() const
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/subdir/subdirlib.h b/Tests/CMakeCommands/target_link_libraries/subdir/subdirlib.h
new file mode 100644
index 0000000..e386f87
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/subdir/subdirlib.h
@@ -0,0 +1,12 @@
+
+#ifndef SUBDIRLIB_H
+#define SUBDIRLIB_H
+
+#include "subdirlib_export.h"
+
+struct SUBDIRLIB_EXPORT SubDirLibObject
+{
+ int foo() const;
+};
+
+#endif
diff --git a/Tests/CMakeCommands/target_link_libraries/targetA.cpp b/Tests/CMakeCommands/target_link_libraries/targetA.cpp
new file mode 100644
index 0000000..b23b7a0
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/targetA.cpp
@@ -0,0 +1,18 @@
+
+#include "depB.h"
+#include "depC.h"
+#include "depIfaceOnly.h"
+#include "subdirlib.h"
+
+int main(int, char**)
+{
+ DepA a;
+ DepB b;
+ DepC c;
+
+ DepIfaceOnly iface_only;
+
+ SubDirLibObject sd;
+
+ return a.foo() + b.foo() + c.foo() + iface_only.foo() + sd.foo();
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/targetB.cpp b/Tests/CMakeCommands/target_link_libraries/targetB.cpp
new file mode 100644
index 0000000..a08c79a
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/targetB.cpp
@@ -0,0 +1,10 @@
+
+#include "depD.h"
+
+int main(int, char**)
+{
+ DepD d;
+ DepA a = d.getA();
+
+ return d.foo() + a.foo();
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/targetC.cpp b/Tests/CMakeCommands/target_link_libraries/targetC.cpp
new file mode 100644
index 0000000..11efb3d
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/targetC.cpp
@@ -0,0 +1,15 @@
+
+#include "bar.h"
+#include "depG.h"
+#include "foo.h"
+
+#ifndef TEST_DEF
+# error Expected TEST_DEF definition
+#endif
+
+int main(int, char**)
+{
+ DepG g;
+
+ return g.foo();
+}
diff --git a/Tests/CMakeCommands/target_link_options/CMakeLists.txt b/Tests/CMakeCommands/target_link_options/CMakeLists.txt
new file mode 100644
index 0000000..e84d041
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_options/CMakeLists.txt
@@ -0,0 +1,34 @@
+
+cmake_minimum_required(VERSION 3.11)
+
+project(target_link_options LANGUAGES C)
+
+add_library(target_link_options SHARED LinkOptionsLib.c)
+# Test no items
+target_link_options(target_link_options PRIVATE)
+
+add_library(target_link_options_2 SHARED EXCLUDE_FROM_ALL LinkOptionsLib.c)
+target_link_options(target_link_options_2 PRIVATE -PRIVATE_FLAG INTERFACE -INTERFACE_FLAG)
+get_target_property(result target_link_options_2 LINK_OPTIONS)
+if (NOT result MATCHES "-PRIVATE_FLAG")
+ message(SEND_ERROR "target_link_options not populated the LINK_OPTIONS target property")
+endif()
+get_target_property(result target_link_options_2 INTERFACE_LINK_OPTIONS)
+if (NOT result MATCHES "-INTERFACE_FLAG")
+ message(SEND_ERROR "target_link_options not populated the INTERFACE_LINK_OPTIONS target property of shared library")
+endif()
+
+add_library(target_link_options_3 STATIC EXCLUDE_FROM_ALL LinkOptionsLib.c)
+target_link_options(target_link_options_3 INTERFACE -INTERFACE_FLAG)
+get_target_property(result target_link_options_3 INTERFACE_LINK_OPTIONS)
+if (NOT result MATCHES "-INTERFACE_FLAG")
+ message(SEND_ERROR "target_link_options not populated the INTERFACE_LINK_OPTIONS target property of static library")
+endif()
+
+add_library(target_link_options_4 SHARED EXCLUDE_FROM_ALL LinkOptionsLib.c)
+target_link_options(target_link_options_4 PRIVATE -PRIVATE_FLAG)
+target_link_options(target_link_options_4 BEFORE PRIVATE -BEFORE_PRIVATE_FLAG)
+get_target_property(result target_link_options_4 LINK_OPTIONS)
+if (NOT result MATCHES "-BEFORE_PRIVATE_FLAG.*-PRIVATE_FLAG")
+ message(SEND_ERROR "target_link_options not managing correctly 'BEFORE' keyword")
+endif()
diff --git a/Tests/CMakeCommands/target_link_options/LinkOptionsLib.c b/Tests/CMakeCommands/target_link_options/LinkOptionsLib.c
new file mode 100644
index 0000000..9bbd24c
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_options/LinkOptionsLib.c
@@ -0,0 +1,7 @@
+#if defined(_WIN32)
+__declspec(dllexport)
+#endif
+ int flags_lib(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_sources/CMakeLists.txt b/Tests/CMakeCommands/target_sources/CMakeLists.txt
new file mode 100644
index 0000000..ab14855
--- /dev/null
+++ b/Tests/CMakeCommands/target_sources/CMakeLists.txt
@@ -0,0 +1,36 @@
+
+cmake_minimum_required(VERSION 3.12)
+cmake_policy(SET CMP0076 NEW)
+
+project(target_sources)
+
+add_library(target_sources_lib)
+target_compile_definitions(target_sources_lib PRIVATE "-DIS_LIB")
+add_subdirectory(subdir)
+
+set(subdir_fullpath "${CMAKE_CURRENT_LIST_DIR}/subdir")
+
+get_property(target_sources_lib_property TARGET target_sources_lib PROPERTY SOURCES)
+if (NOT "$<1:${subdir_fullpath}/subdir_empty_1.cpp>" IN_LIST target_sources_lib_property)
+ message(SEND_ERROR "target_sources_lib: Generator expression to absolute sub directory file not found")
+endif()
+if (NOT "$<1:${subdir_fullpath}/../empty_1.cpp>" IN_LIST target_sources_lib_property)
+ message(SEND_ERROR "target_sources_lib: Generator expression to absolute main directory file not found")
+endif()
+if (NOT "${subdir_fullpath}/subdir_empty_2.cpp" IN_LIST target_sources_lib_property)
+ message(SEND_ERROR "target_sources_lib: Relative sub directory file not converted to absolute")
+endif()
+if (NOT "$<1:empty_2.cpp>" IN_LIST target_sources_lib_property)
+ message(SEND_ERROR "target_sources_lib: Generator expression to relative main directory file not found")
+endif()
+if (NOT "${subdir_fullpath}/../empty_3.cpp" IN_LIST target_sources_lib_property)
+ message(SEND_ERROR "target_sources_lib: Relative main directory file not converted to absolute")
+endif()
+
+add_executable(target_sources main.cpp)
+target_link_libraries(target_sources target_sources_lib)
+
+get_property(target_sources_property TARGET target_sources PROPERTY SOURCES)
+if (NOT "main.cpp" IN_LIST target_sources_property)
+ message(SEND_ERROR "target_sources: Relative main directory file converted to absolute")
+endif()
diff --git a/Tests/CMakeCommands/target_sources/empty_1.cpp b/Tests/CMakeCommands/target_sources/empty_1.cpp
new file mode 100644
index 0000000..01e5b07
--- /dev/null
+++ b/Tests/CMakeCommands/target_sources/empty_1.cpp
@@ -0,0 +1,21 @@
+#ifdef IS_LIB
+
+# ifdef _WIN32
+__declspec(dllexport)
+# endif
+ int internal_empty_1()
+{
+ return 0;
+}
+
+#else
+
+# ifdef _WIN32
+__declspec(dllexport)
+# endif
+ int empty_1()
+{
+ return 0;
+}
+
+#endif
diff --git a/Tests/CMakeCommands/target_sources/empty_2.cpp b/Tests/CMakeCommands/target_sources/empty_2.cpp
new file mode 100644
index 0000000..48ae8bb
--- /dev/null
+++ b/Tests/CMakeCommands/target_sources/empty_2.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty_2()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_sources/empty_3.cpp b/Tests/CMakeCommands/target_sources/empty_3.cpp
new file mode 100644
index 0000000..bd3a6d1
--- /dev/null
+++ b/Tests/CMakeCommands/target_sources/empty_3.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty_3()
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_sources/main.cpp b/Tests/CMakeCommands/target_sources/main.cpp
new file mode 100644
index 0000000..622771c
--- /dev/null
+++ b/Tests/CMakeCommands/target_sources/main.cpp
@@ -0,0 +1,16 @@
+#include <iostream>
+
+int empty_1();
+int subdir_empty_1();
+int subdir_empty_2();
+
+int main()
+{
+ int e1 = empty_1();
+ int se1 = subdir_empty_1();
+ int se2 = subdir_empty_2();
+
+ std::cout << e1 << " " << se1 << " " << se2 << std::endl;
+
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_sources/subdir/CMakeLists.txt b/Tests/CMakeCommands/target_sources/subdir/CMakeLists.txt
new file mode 100644
index 0000000..f749f1d
--- /dev/null
+++ b/Tests/CMakeCommands/target_sources/subdir/CMakeLists.txt
@@ -0,0 +1,6 @@
+
+target_sources(target_sources_lib PUBLIC $<1:${CMAKE_CURRENT_LIST_DIR}/subdir_empty_1.cpp>
+ $<1:${CMAKE_CURRENT_LIST_DIR}/../empty_1.cpp>
+ subdir_empty_2.cpp
+ PRIVATE $<1:empty_2.cpp>
+ ../empty_3.cpp)
diff --git a/Tests/CMakeCommands/target_sources/subdir/subdir_empty_1.cpp b/Tests/CMakeCommands/target_sources/subdir/subdir_empty_1.cpp
new file mode 100644
index 0000000..3c61321
--- /dev/null
+++ b/Tests/CMakeCommands/target_sources/subdir/subdir_empty_1.cpp
@@ -0,0 +1,21 @@
+#ifdef IS_LIB
+
+# ifdef _WIN32
+__declspec(dllexport)
+# endif
+ int internal_subdir_empty_1()
+{
+ return 0;
+}
+
+#else
+
+# ifdef _WIN32
+__declspec(dllexport)
+# endif
+ int subdir_empty_1()
+{
+ return 0;
+}
+
+#endif
diff --git a/Tests/CMakeCommands/target_sources/subdir/subdir_empty_2.cpp b/Tests/CMakeCommands/target_sources/subdir/subdir_empty_2.cpp
new file mode 100644
index 0000000..47fa736
--- /dev/null
+++ b/Tests/CMakeCommands/target_sources/subdir/subdir_empty_2.cpp
@@ -0,0 +1,21 @@
+#ifdef IS_LIB
+
+# ifdef _WIN32
+__declspec(dllexport)
+# endif
+ int internal_subdir_empty_2()
+{
+ return 0;
+}
+
+#else
+
+# ifdef _WIN32
+__declspec(dllexport)
+# endif
+ int subdir_empty_2()
+{
+ return 0;
+}
+
+#endif
diff --git a/Tests/CMakeCopyright.cmake b/Tests/CMakeCopyright.cmake
new file mode 100644
index 0000000..a7201e9
--- /dev/null
+++ b/Tests/CMakeCopyright.cmake
@@ -0,0 +1,22 @@
+if(CMAKE_VERSION MATCHES "\\.(20[0-9][0-9])[0-9][0-9][0-9][0-9](-|$)")
+ set(version_year "${CMAKE_MATCH_1}")
+ set(copyright_line_regex "^Copyright 2000-(20[0-9][0-9]) Kitware")
+ file(STRINGS "${CMAKE_CURRENT_LIST_DIR}/../Copyright.txt" copyright_line
+ LIMIT_COUNT 1 REGEX "${copyright_line_regex}")
+ if(copyright_line MATCHES "${copyright_line_regex}")
+ set(copyright_year "${CMAKE_MATCH_1}")
+ if(copyright_year LESS version_year)
+ message(FATAL_ERROR "Copyright.txt contains\n"
+ " ${copyright_line}\n"
+ "but the current version year is ${version_year}.")
+ else()
+ message(STATUS "PASSED: Copyright.txt contains\n"
+ " ${copyright_line}\n"
+ "and the current version year is ${version_year}.")
+ endif()
+ else()
+ message(FATAL_ERROR "Copyright.txt has no Copyright line of expected format!")
+ endif()
+else()
+ message(STATUS "SKIPPED: CMAKE_VERSION does not know the year: ${CMAKE_VERSION}")
+endif()
diff --git a/Tests/CMakeGUI/CMakeGUITest.cmake b/Tests/CMakeGUI/CMakeGUITest.cmake
new file mode 100644
index 0000000..2c6baf3
--- /dev/null
+++ b/Tests/CMakeGUI/CMakeGUITest.cmake
@@ -0,0 +1,158 @@
+function(run_cmake_gui_test name)
+ if(DEFINED ENV{CMakeGUITest_TEST_FILTER} AND NOT name MATCHES "$ENV{CMakeGUITest_TEST_FILTER}")
+ return()
+ endif()
+
+ set(_fail)
+
+ cmake_parse_arguments(_rcgt
+ "DO_CONFIGURE"
+ "GENERATOR"
+ "ARGS;CONFIGURE_ARGS"
+ ${ARGN}
+ )
+
+ string(REPLACE ":" "-" _file_name "${name}")
+ set(_srcdir "${CMakeGUITest_SOURCE_DIR}/${_file_name}")
+ set(_workdir "${CMakeGUITest_BINARY_DIR}/${_file_name}")
+
+ file(REMOVE_RECURSE "${_workdir}")
+ file(MAKE_DIRECTORY "${_workdir}")
+
+ set(_ini_in "${_srcdir}/CMakeSetup.ini.in")
+ if(EXISTS "${_ini_in}")
+ configure_file("${_ini_in}" "${_workdir}/config/Kitware/CMakeSetup.ini" @ONLY)
+ endif()
+ set(_cmakelists_in "${_srcdir}/CMakeLists.txt.in")
+ if(EXISTS "${_cmakelists_in}")
+ configure_file("${_cmakelists_in}" "${_workdir}/src/CMakeLists.txt" @ONLY)
+ endif()
+ set(_cmakepresets_in "${_srcdir}/CMakePresets.json.in")
+ if(EXISTS "${_cmakepresets_in}")
+ configure_file("${_cmakepresets_in}" "${_workdir}/src/CMakePresets.json" @ONLY)
+ endif()
+ if(_rcgt_DO_CONFIGURE)
+ if(NOT _rcgt_GENERATOR)
+ set(_rcgt_GENERATOR "${CMakeGUITest_GENERATOR}")
+ endif()
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}"
+ -S "${_workdir}/src"
+ -B "${_workdir}/build"
+ -G "${_rcgt_GENERATOR}"
+ ${_rcgt_CONFIGURE_ARGS}
+ RESULT_VARIABLE _result
+ OUTPUT_VARIABLE _output
+ ERROR_VARIABLE _error
+ )
+ if(_result)
+ set(_fail 1)
+ string(REPLACE "\n" "\n " _formatted_output "${_output}")
+ string(REPLACE "\n" "\n " _formatted_error "${_error}")
+ message(SEND_ERROR
+ "Configuring ${_workdir}/src failed with exit code ${_result}, should be 0\n"
+ "stdout:\n ${_formatted_output}\n"
+ "stderr:\n ${_formatted_error}"
+ )
+ endif()
+ endif()
+
+ set(ENV{CMake_GUI_TEST_NAME} "${name}")
+ set(ENV{CMake_GUI_CONFIG_DIR} "${_workdir}/config")
+ execute_process(
+ COMMAND "${CMakeGUITest_COMMAND}" ${_rcgt_ARGS}
+ WORKING_DIRECTORY "${_workdir}"
+ RESULT_VARIABLE _result
+ OUTPUT_VARIABLE _output
+ ERROR_VARIABLE _error
+ )
+ if(_result)
+ set(_fail 1)
+ string(REPLACE "\n" "\n " _formatted_output "${_output}")
+ string(REPLACE "\n" "\n " _formatted_error "${_error}")
+ message(SEND_ERROR "CMake GUI test ${name} failed with exit code ${_result}, should be 0\n"
+ "stdout:\n ${_formatted_output}\n"
+ "stderr:\n ${_formatted_error}"
+ )
+ endif()
+
+ if(NOT _fail)
+ message(STATUS "${name} -- passed")
+ endif()
+endfunction()
+
+run_cmake_gui_test(sourceBinaryArgs:sourceAndBinaryDir
+ ARGS
+ -S "${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-sourceAndBinaryDir/src"
+ -B "${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-sourceAndBinaryDir/build"
+ )
+run_cmake_gui_test(sourceBinaryArgs:sourceAndBinaryDirRelative
+ ARGS
+ "-Ssrc"
+ "-Bbuild"
+ )
+run_cmake_gui_test(sourceBinaryArgs:sourceDir
+ ARGS
+ "${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-sourceDir/src"
+ )
+run_cmake_gui_test(sourceBinaryArgs:binaryDir
+ DO_CONFIGURE
+ ARGS
+ "${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-binaryDir/build"
+ )
+run_cmake_gui_test(sourceBinaryArgs:noExist
+ ARGS
+ "${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-noExist/noexist"
+ )
+run_cmake_gui_test(sourceBinaryArgs:noExistConfig
+ ARGS
+ "${CMakeGUITest_BINARY_DIR}/sourceBinaryArgs-noExistConfig/noexist"
+ )
+run_cmake_gui_test(sourceBinaryArgs:noExistConfigExists
+ DO_CONFIGURE
+ 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)
+
+run_cmake_gui_test(presetArg:preset
+ ARGS
+ -S "${CMakeGUITest_BINARY_DIR}/presetArg-preset/src"
+ "--preset=ninja"
+ )
+run_cmake_gui_test(presetArg:presetBinary
+ ARGS
+ -S "${CMakeGUITest_BINARY_DIR}/presetArg-presetBinary/src"
+ -B "${CMakeGUITest_BINARY_DIR}/presetArg-presetBinary/build"
+ "--preset=ninja"
+ )
+run_cmake_gui_test(presetArg:presetBinaryChange
+ ARGS
+ -S "${CMakeGUITest_BINARY_DIR}/presetArg-presetBinaryChange/src"
+ -B "${CMakeGUITest_BINARY_DIR}/presetArg-presetBinaryChange/build"
+ "--preset=ninja"
+ )
+run_cmake_gui_test(presetArg:noPresetBinaryChange
+ ARGS
+ -S "${CMakeGUITest_BINARY_DIR}/presetArg-noPresetBinaryChange/src"
+ -B "${CMakeGUITest_BINARY_DIR}/presetArg-noPresetBinaryChange/build"
+ )
+run_cmake_gui_test(presetArg:presetConfigExists
+ ARGS
+ -S "${CMakeGUITest_BINARY_DIR}/presetArg-presetConfigExists/src"
+ "--preset=ninja"
+ )
+run_cmake_gui_test(presetArg:noExist
+ ARGS
+ -S "${CMakeGUITest_BINARY_DIR}/presetArg-noExist/src"
+ "--preset=noExist"
+ )
+run_cmake_gui_test(changingPresets)
diff --git a/Tests/CMakeGUI/CMakeGUITest.cxx b/Tests/CMakeGUI/CMakeGUITest.cxx
new file mode 100644
index 0000000..2b5d973
--- /dev/null
+++ b/Tests/CMakeGUI/CMakeGUITest.cxx
@@ -0,0 +1,449 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "CMakeGUITest.h"
+
+#include "QCMake.h"
+#include <QApplication>
+#include <QEventLoop>
+#include <QFile>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QMessageBox>
+#include <QSettings>
+#include <QString>
+#include <QStringList>
+#include <QTimer>
+#include <QtGlobal>
+#include <QtTest>
+
+#include "CMakeSetupDialog.h"
+
+#include "CatchShow.h"
+#include "FirstConfigure.h"
+
+using WindowSetupHelper = std::function<void(CMakeSetupDialog*)>;
+Q_DECLARE_METATYPE(WindowSetupHelper)
+
+namespace {
+void loopSleep(int msecs = 500)
+{
+ QEventLoop loop;
+ QTimer::singleShot(msecs, &loop, &QEventLoop::quit);
+ loop.exec();
+}
+}
+
+CMakeGUITest::CMakeGUITest(CMakeSetupDialog* window, QObject* parent)
+ : QObject(parent)
+ , m_window(window)
+{
+}
+
+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);
+ QFETCH(QString, binaryDir);
+
+ // Wait a bit for everything to update
+ loopSleep();
+
+ QCOMPARE(this->m_window->SourceDirectory->text(), sourceDir);
+ QCOMPARE(this->m_window->BinaryDirectory->currentText(), binaryDir);
+}
+
+void CMakeGUITest::sourceBinaryArgs_data()
+{
+ QTest::addColumn<QString>("sourceDir");
+ QTest::addColumn<QString>("binaryDir");
+
+ QTest::newRow("sourceAndBinaryDir")
+ << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-sourceAndBinaryDir/src"
+ << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-sourceAndBinaryDir/build";
+ QTest::newRow("sourceAndBinaryDirRelative") << CMakeGUITest_BINARY_DIR
+ "/sourceBinaryArgs-sourceAndBinaryDirRelative/src"
+ << CMakeGUITest_BINARY_DIR
+ "/sourceBinaryArgs-sourceAndBinaryDirRelative/build";
+ QTest::newRow("sourceDir")
+ << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-sourceDir/src"
+ << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-sourceDir";
+ QTest::newRow("binaryDir")
+ << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-binaryDir/src"
+ << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-binaryDir/build";
+ QTest::newRow("noExist") << ""
+ << "";
+ QTest::newRow("noExistConfig")
+ << ""
+ << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-noExistConfig/oldbuild";
+ QTest::newRow("noExistConfigExists")
+ << CMakeGUITest_BINARY_DIR "/sourceBinaryArgs-noExistConfigExists/src"
+ << 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 CMakeGUITest::presetArg()
+{
+ QFETCH(WindowSetupHelper, setupFunction);
+ QFETCH(QString, presetName);
+ QFETCH(QString, sourceDir);
+ QFETCH(QString, binaryDir);
+ QFETCH(QCMakePropertyList, properties);
+
+ if (setupFunction) {
+ setupFunction(this->m_window);
+ }
+
+ // Wait a bit for everything to update
+ loopSleep();
+
+ QCOMPARE(this->m_window->Preset->presetName(), presetName);
+ QCOMPARE(this->m_window->SourceDirectory->text(), sourceDir);
+ QCOMPARE(this->m_window->BinaryDirectory->currentText(), binaryDir);
+
+ auto actualProperties =
+ this->m_window->CacheValues->cacheModel()->properties();
+ QCOMPARE(actualProperties.size(), properties.size());
+ for (int i = 0; i < actualProperties.size(); ++i) {
+ // operator==() only compares Key, we need to compare Value and Type too
+ QCOMPARE(actualProperties[i].Key, properties[i].Key);
+ QCOMPARE(actualProperties[i].Value, properties[i].Value);
+ QCOMPARE(actualProperties[i].Type, properties[i].Type);
+ }
+}
+
+namespace {
+QCMakePropertyList makePresetProperties(const QString& name)
+{
+ return QCMakePropertyList{
+ QCMakeProperty{
+ /*Key=*/"FALSE_VARIABLE",
+ /*Value=*/false,
+ /*Strings=*/{},
+ /*Help=*/"",
+ /*Type=*/QCMakeProperty::BOOL,
+ /*Advanced=*/false,
+ },
+ QCMakeProperty{
+ /*Key=*/"FILEPATH_VARIABLE",
+ /*Value=*/
+ QString::fromLocal8Bit(CMakeGUITest_BINARY_DIR "/%1/src/CMakeLists.txt")
+ .arg(name),
+ /*Strings=*/{},
+ /*Help=*/"",
+ /*Type=*/QCMakeProperty::FILEPATH,
+ /*Advanced=*/false,
+ },
+ QCMakeProperty{
+ /*Key=*/"ON_VARIABLE",
+ /*Value=*/true,
+ /*Strings=*/{},
+ /*Help=*/"",
+ /*Type=*/QCMakeProperty::BOOL,
+ /*Advanced=*/false,
+ },
+ QCMakeProperty{
+ /*Key=*/"PATH_VARIABLE",
+ /*Value=*/
+ QString::fromLocal8Bit(CMakeGUITest_BINARY_DIR "/%1/src").arg(name),
+ /*Strings=*/{},
+ /*Help=*/"",
+ /*Type=*/QCMakeProperty::PATH,
+ /*Advanced=*/false,
+ },
+ QCMakeProperty{
+ /*Key=*/"STRING_VARIABLE",
+ /*Value=*/"String value",
+ /*Strings=*/{},
+ /*Help=*/"",
+ /*Type=*/QCMakeProperty::STRING,
+ /*Advanced=*/false,
+ },
+ QCMakeProperty{
+ /*Key=*/"UNINITIALIZED_VARIABLE",
+ /*Value=*/"Uninitialized value",
+ /*Strings=*/{},
+ /*Help=*/"",
+ /*Type=*/QCMakeProperty::STRING,
+ /*Advanced=*/false,
+ },
+ };
+}
+}
+
+void CMakeGUITest::presetArg_data()
+{
+ QTest::addColumn<WindowSetupHelper>("setupFunction");
+ QTest::addColumn<QString>("presetName");
+ QTest::addColumn<QString>("sourceDir");
+ QTest::addColumn<QString>("binaryDir");
+ QTest::addColumn<QCMakePropertyList>("properties");
+
+ QTest::newRow("preset") << WindowSetupHelper{} << "ninja"
+ << CMakeGUITest_BINARY_DIR "/presetArg-preset/src"
+ << CMakeGUITest_BINARY_DIR
+ "/presetArg-preset/src/build"
+ << makePresetProperties("presetArg-preset");
+ QTest::newRow("presetBinary")
+ << WindowSetupHelper{} << "ninja"
+ << CMakeGUITest_BINARY_DIR "/presetArg-presetBinary/src"
+ << CMakeGUITest_BINARY_DIR "/presetArg-presetBinary/build"
+ << makePresetProperties("presetArg-presetBinary");
+ QTest::newRow("presetBinaryChange")
+ << WindowSetupHelper{ [](CMakeSetupDialog* window) {
+ loopSleep();
+ window->Preset->setPresetName("ninja2");
+ } }
+ << "ninja2" << CMakeGUITest_BINARY_DIR "/presetArg-presetBinaryChange/src"
+ << CMakeGUITest_BINARY_DIR "/presetArg-presetBinaryChange/src/build"
+ << makePresetProperties("presetArg-presetBinaryChange");
+ QTest::newRow("noPresetBinaryChange")
+ << WindowSetupHelper{ [](CMakeSetupDialog* window) {
+ loopSleep();
+ window->Preset->setPresetName("ninja");
+ } }
+ << "ninja" << CMakeGUITest_BINARY_DIR "/presetArg-noPresetBinaryChange/src"
+ << CMakeGUITest_BINARY_DIR "/presetArg-noPresetBinaryChange/src/build"
+ << makePresetProperties("presetArg-noPresetBinaryChange");
+ QTest::newRow("presetConfigExists")
+ << WindowSetupHelper{} << "ninja"
+ << CMakeGUITest_BINARY_DIR "/presetArg-presetConfigExists/src"
+ << CMakeGUITest_BINARY_DIR "/presetArg-presetConfigExists/src/build"
+ << makePresetProperties("presetArg-presetConfigExists");
+ QTest::newRow("noExist") << WindowSetupHelper{} << QString{}
+ << CMakeGUITest_BINARY_DIR "/presetArg-noExist/src"
+ << "" << QCMakePropertyList{};
+}
+
+namespace {
+void writePresets(const QString& buildDir, const QStringList& names)
+{
+ QJsonArray presets{
+ QJsonObject{
+ { "name", "base" },
+ { "generator", "Ninja" },
+ { "binaryDir",
+ QString::fromLocal8Bit("${sourceDir}/%1/${presetName}")
+ .arg(buildDir) },
+ { "hidden", true },
+ },
+ };
+
+ for (auto const& name : names) {
+ presets.append(QJsonObject{
+ { "name", name },
+ { "inherits", QJsonArray{ "base" } },
+ });
+ }
+
+ QJsonDocument doc{ QJsonObject{
+ { "version", 1 },
+ { "configurePresets", presets },
+ } };
+
+ QFile presetsFile(CMakeGUITest_BINARY_DIR
+ "/changingPresets/src/CMakePresets.json");
+ bool open = presetsFile.open(QIODevice::WriteOnly);
+ Q_ASSERT(open);
+ presetsFile.write(doc.toJson());
+}
+}
+
+void CMakeGUITest::changingPresets()
+{
+ QDir::root().mkpath(CMakeGUITest_BINARY_DIR "/changingPresets/src");
+
+ this->m_window->SourceDirectory->setText(CMakeGUITest_BINARY_DIR
+ "/changingPresets/src");
+ loopSleep();
+ QCOMPARE(this->m_window->Preset->presetName(), QString{});
+ QCOMPARE(this->m_window->Preset->presets().size(), 0);
+ QCOMPARE(this->m_window->BinaryDirectory->currentText(), "");
+ QCOMPARE(this->m_window->Preset->isEnabled(), false);
+
+ writePresets("build1", { "preset" });
+ loopSleep(1500);
+ QCOMPARE(this->m_window->Preset->presetName(), QString{});
+ QCOMPARE(this->m_window->Preset->presets().size(), 1);
+ QCOMPARE(this->m_window->BinaryDirectory->currentText(), "");
+ QCOMPARE(this->m_window->Preset->isEnabled(), true);
+
+ this->m_window->Preset->setPresetName("preset");
+ loopSleep();
+ QCOMPARE(this->m_window->Preset->presetName(), "preset");
+ QCOMPARE(this->m_window->Preset->presets().size(), 1);
+ QCOMPARE(this->m_window->BinaryDirectory->currentText(),
+ CMakeGUITest_BINARY_DIR "/changingPresets/src/build1/preset");
+ QCOMPARE(this->m_window->Preset->isEnabled(), true);
+
+ writePresets("build2", { "preset2", "preset" });
+ loopSleep(1500);
+ QCOMPARE(this->m_window->Preset->presetName(), "preset");
+ QCOMPARE(this->m_window->Preset->presets().size(), 2);
+ QCOMPARE(this->m_window->BinaryDirectory->currentText(),
+ CMakeGUITest_BINARY_DIR "/changingPresets/src/build1/preset");
+ QCOMPARE(this->m_window->Preset->isEnabled(), true);
+
+ writePresets("build3", { "preset2" });
+ loopSleep(1500);
+ QCOMPARE(this->m_window->Preset->presetName(), QString{});
+ QCOMPARE(this->m_window->Preset->presets().size(), 1);
+ QCOMPARE(this->m_window->BinaryDirectory->currentText(),
+ CMakeGUITest_BINARY_DIR "/changingPresets/src/build1/preset");
+ QCOMPARE(this->m_window->Preset->isEnabled(), true);
+
+ this->m_window->Preset->setPresetName("preset2");
+ loopSleep();
+ QCOMPARE(this->m_window->Preset->presetName(), "preset2");
+ QCOMPARE(this->m_window->Preset->presets().size(), 1);
+ QCOMPARE(this->m_window->BinaryDirectory->currentText(),
+ CMakeGUITest_BINARY_DIR "/changingPresets/src/build3/preset2");
+ QCOMPARE(this->m_window->Preset->isEnabled(), true);
+
+ QDir::root().mkpath(CMakeGUITest_BINARY_DIR "/changingPresets/src2");
+ QFile::copy(CMakeGUITest_BINARY_DIR "/changingPresets/src/CMakePresets.json",
+ CMakeGUITest_BINARY_DIR
+ "/changingPresets/src2/CMakePresets.json");
+ this->m_window->SourceDirectory->setText(CMakeGUITest_BINARY_DIR
+ "/changingPresets/src2");
+ loopSleep();
+ QCOMPARE(this->m_window->Preset->presetName(), QString{});
+ QCOMPARE(this->m_window->Preset->presets().size(), 1);
+ QCOMPARE(this->m_window->BinaryDirectory->currentText(),
+ CMakeGUITest_BINARY_DIR "/changingPresets/src/build3/preset2");
+ QCOMPARE(this->m_window->Preset->isEnabled(), true);
+
+ this->m_window->Preset->setPresetName("preset2");
+ loopSleep();
+ QCOMPARE(this->m_window->Preset->presetName(), "preset2");
+ QCOMPARE(this->m_window->Preset->presets().size(), 1);
+ QCOMPARE(this->m_window->BinaryDirectory->currentText(),
+ CMakeGUITest_BINARY_DIR "/changingPresets/src2/build3/preset2");
+ QCOMPARE(this->m_window->Preset->isEnabled(), true);
+
+ QFile(CMakeGUITest_BINARY_DIR "/changingPresets/src2/CMakePresets.json")
+ .remove();
+ loopSleep(1500);
+ QCOMPARE(this->m_window->Preset->presetName(), QString{});
+ QCOMPARE(this->m_window->Preset->presets().size(), 0);
+ QCOMPARE(this->m_window->BinaryDirectory->currentText(),
+ CMakeGUITest_BINARY_DIR "/changingPresets/src2/build3/preset2");
+ QCOMPARE(this->m_window->Preset->isEnabled(), false);
+}
+
+void SetupDefaultQSettings()
+{
+ QSettings::setDefaultFormat(QSettings::IniFormat);
+ QSettings::setPath(QSettings::IniFormat, QSettings::UserScope,
+ QString::fromLocal8Bit(qgetenv("CMake_GUI_CONFIG_DIR")));
+}
+
+int CMakeGUIExec(CMakeSetupDialog* window)
+{
+ auto nameArray = qgetenv("CMake_GUI_TEST_NAME");
+ auto name = QString::fromLocal8Bit(nameArray);
+ if (name.isEmpty()) {
+ return QApplication::exec();
+ }
+
+ QStringList args{ "CMakeGUITest", name };
+ CMakeGUITest obj(window);
+ return QTest::qExec(&obj, args);
+}
diff --git a/Tests/CMakeGUI/CMakeGUITest.h b/Tests/CMakeGUI/CMakeGUITest.h
new file mode 100644
index 0000000..e6293a4
--- /dev/null
+++ b/Tests/CMakeGUI/CMakeGUITest.h
@@ -0,0 +1,29 @@
+/* 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 CMakeSetupDialog;
+
+class CMakeGUITest : public QObject
+{
+ Q_OBJECT
+public:
+ CMakeGUITest(CMakeSetupDialog* window, QObject* parent = nullptr);
+
+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();
+ void presetArg();
+ void presetArg_data();
+ void changingPresets();
+};
diff --git a/Tests/CMakeGUI/CMakeLists.txt b/Tests/CMakeGUI/CMakeLists.txt
new file mode 100644
index 0000000..4e8609b
--- /dev/null
+++ b/Tests/CMakeGUI/CMakeLists.txt
@@ -0,0 +1,95 @@
+include(CMakeParseArguments)
+
+find_package(Qt5Test REQUIRED)
+
+include_directories(
+ ${CMake_SOURCE_DIR}/Source
+ ${CMake_SOURCE_DIR}/Source/QtDialog
+ ${CMake_BINARY_DIR}/Source/QtDialog
+ )
+
+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 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}
+ "-DCMakeGUITest_COMMAND=$<TARGET_FILE:CMakeGUITest>"
+ "-DCMakeGUITest_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}"
+ "-DCMakeGUITest_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}"
+ "-DCMakeGUITest_GENERATOR=${CMAKE_GENERATOR}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/CMakeGUITest.cmake"
+ )
+
+function(add_cmake_gui_lib_test name)
+ cmake_parse_arguments(_t "" "" "SOURCES;MOC_SOURCES" ${ARGN})
+
+ set(MOC_SRCS)
+ qt5_wrap_cpp(MOC_SRCS
+ ${_t_MOC_SOURCES}
+ )
+ add_executable(${name} ${_t_SOURCES} ${MOC_SRCS})
+ 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
+ QCMakeCacheModelTest.h
+ MOC_SOURCES
+ QCMakeCacheModelTest.h
+ )
+add_cmake_gui_lib_test(QCMakePreset
+ SOURCES
+ QCMakePresetTest.cxx
+ QCMakePresetTest.h
+ MOC_SOURCES
+ QCMakePresetTest.h
+ )
+add_cmake_gui_lib_test(QCMakePresetItemModel
+ SOURCES
+ QCMakePresetItemModelTest.cxx
+ QCMakePresetItemModelTest.h
+ MOC_SOURCES
+ QCMakePresetItemModelTest.h
+ )
+add_cmake_gui_lib_test(QCMakePresetComboBox
+ SOURCES
+ QCMakePresetComboBoxTest.cxx
+ QCMakePresetComboBoxTest.h
+ MOC_SOURCES
+ QCMakePresetComboBoxTest.h
+ )
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/QCMakeCacheModelTest.cxx b/Tests/CMakeGUI/QCMakeCacheModelTest.cxx
new file mode 100644
index 0000000..f9bc6ae
--- /dev/null
+++ b/Tests/CMakeGUI/QCMakeCacheModelTest.cxx
@@ -0,0 +1,108 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "QCMakeCacheModelTest.h"
+
+#include <algorithm>
+#include <iostream>
+
+#include "QCMakeCacheView.h"
+#include <QtTest>
+
+namespace {
+QCMakeProperty makeProperty(
+ const QString& name, const QString& value,
+ QCMakeProperty::PropertyType type = QCMakeProperty::STRING,
+ bool advanced = false)
+{
+ return QCMakeProperty{
+ /*Key=*/name,
+ /*Value=*/value,
+ /*Strings=*/{},
+ /*Help=*/"",
+ /*Type=*/type,
+ /*Advanced=*/advanced,
+ };
+}
+}
+
+void QCMakeCacheModelTest::setNewProperties()
+{
+ QFETCH(QCMakePropertyList, oldList);
+ QFETCH(QCMakePropertyList, newList);
+ QFETCH(QVector<QString>, names);
+ QFETCH(QVector<QString>, values);
+ QFETCH(QVector<QVariant>, background);
+
+ QCMakeCacheModel model;
+ model.setViewType(QCMakeCacheModel::FlatView);
+ model.setProperties(oldList);
+ model.setProperties(newList);
+
+ auto rows = model.rowCount();
+ QVector<QString> actualNames(rows);
+ QVector<QString> actualValues(rows);
+ QVector<QVariant> actualBackground1(rows);
+ QVector<QVariant> actualBackground2(rows);
+ for (int i = 0; i < rows; ++i) {
+ auto idx1 = model.index(i, 0);
+ auto idx2 = model.index(i, 1);
+
+ auto name = model.data(idx1, Qt::DisplayRole);
+ QVERIFY(name.canConvert<QString>());
+ actualNames[i] = name.value<QString>();
+
+ auto value = model.data(idx2, Qt::DisplayRole);
+ QVERIFY(name.canConvert<QString>());
+ actualValues[i] = value.value<QString>();
+
+ actualBackground1[i] = model.data(idx1, Qt::BackgroundRole);
+ actualBackground2[i] = model.data(idx2, Qt::BackgroundRole);
+ }
+
+ QCOMPARE(actualNames, names);
+ QCOMPARE(actualValues, values);
+ QCOMPARE(actualBackground1, background);
+ QCOMPARE(actualBackground2, background);
+}
+
+void QCMakeCacheModelTest::setNewProperties_data()
+{
+ QTest::addColumn<QCMakePropertyList>("oldList");
+ QTest::addColumn<QCMakePropertyList>("newList");
+ QTest::addColumn<QVector<QString>>("names");
+ QTest::addColumn<QVector<QString>>("values");
+ QTest::addColumn<QVector<QVariant>>("background");
+
+ QTest::newRow("empty") << QCMakePropertyList{} << QCMakePropertyList{}
+ << QVector<QString>{} << QVector<QString>{}
+ << QVector<QVariant>{};
+ QTest::newRow("noNew") << QCMakePropertyList{ makeProperty("VARIABLE_1",
+ "Value 1") }
+ << QCMakePropertyList{} << QVector<QString>{}
+ << QVector<QString>{} << QVector<QVariant>{};
+ QTest::newRow("allNew")
+ << QCMakePropertyList{}
+ << QCMakePropertyList{ makeProperty("VARIABLE_1", "Value 1") }
+ << QVector<QString>{ "VARIABLE_1" } << QVector<QString>{ "Value 1" }
+ << QVector<QVariant>{ QBrush{ QColor{ 255, 100, 100 } } };
+ QTest::newRow("mixed")
+ << QCMakePropertyList{ makeProperty("VARIABLE_1", "Value 1") }
+ << QCMakePropertyList{ makeProperty("VARIABLE_2", "Value 2") }
+ << QVector<QString>{ "VARIABLE_2" } << QVector<QString>{ "Value 2" }
+ << QVector<QVariant>{ QBrush{ QColor{ 255, 100, 100 } } };
+ QTest::newRow("overridden")
+ << QCMakePropertyList{ makeProperty("VARIABLE_1", "Value 1") }
+ << QCMakePropertyList{ makeProperty("VARIABLE_1", "Overridden value") }
+ << QVector<QString>{ "VARIABLE_1" }
+ << QVector<QString>{ "Overridden value" }
+ << QVector<QVariant>{ QVariant{} };
+ QTest::newRow("overriddenMixed")
+ << QCMakePropertyList{ makeProperty("VARIABLE_1", "Value 1") }
+ << QCMakePropertyList{ makeProperty("VARIABLE_1", "Overridden value"),
+ makeProperty("VARIABLE_2", "Value 2") }
+ << QVector<QString>{ "VARIABLE_2", "VARIABLE_1" }
+ << QVector<QString>{ "Value 2", "Overridden value" }
+ << QVector<QVariant>{ QBrush{ QColor{ 255, 100, 100 } }, QVariant{} };
+}
+
+QTEST_MAIN(QCMakeCacheModelTest)
diff --git a/Tests/CMakeGUI/QCMakeCacheModelTest.h b/Tests/CMakeGUI/QCMakeCacheModelTest.h
new file mode 100644
index 0000000..e88db94
--- /dev/null
+++ b/Tests/CMakeGUI/QCMakeCacheModelTest.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "QCMakeCacheView.h"
+#include <QObject>
+
+class QCMakeCacheModelTest : public QObject
+{
+ Q_OBJECT
+private slots:
+ void setNewProperties();
+ void setNewProperties_data();
+};
diff --git a/Tests/CMakeGUI/QCMakePresetComboBoxTest.cxx b/Tests/CMakeGUI/QCMakePresetComboBoxTest.cxx
new file mode 100644
index 0000000..a95d008
--- /dev/null
+++ b/Tests/CMakeGUI/QCMakePresetComboBoxTest.cxx
@@ -0,0 +1,82 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "QCMakePresetComboBoxTest.h"
+
+#include <QtTest>
+
+void QCMakePresetComboBoxTest::changePresets()
+{
+ QCMakePresetComboBox box;
+ QSignalSpy presetChanged(&box, &QCMakePresetComboBox::presetChanged);
+
+ QCOMPARE(presetChanged.size(), 0);
+
+ box.setPresets({});
+ QCOMPARE(presetChanged.size(), 0);
+
+ box.setPresetName(QString{});
+ QCOMPARE(presetChanged.size(), 0);
+
+ box.setPresets({
+ {
+ /*name=*/"preset",
+ /*description=*/"",
+ /*description=*/"",
+ /*generator=*/"Ninja",
+ /*architecture=*/"",
+ /*setArchitecture=*/true,
+ /*toolset=*/"",
+ /*setToolset=*/true,
+ /*enabled=*/true,
+ },
+ });
+ QCOMPARE(presetChanged.size(), 0);
+
+ box.setPresetName(QString{});
+ QCOMPARE(presetChanged.size(), 0);
+
+ box.setPresetName("noexist");
+ QCOMPARE(presetChanged.size(), 0);
+
+ box.setPresetName("preset");
+ QCOMPARE(presetChanged.size(), 1);
+ QCOMPARE(presetChanged.last(), QList<QVariant>{ "preset" });
+
+ box.setPresets({
+ {
+ /*name=*/"preset",
+ /*description=*/"",
+ /*description=*/"",
+ /*generator=*/"Ninja Multi-Config",
+ /*architecture=*/"",
+ /*setArchitecture=*/true,
+ /*toolset=*/"",
+ /*setToolset=*/true,
+ /*enabled=*/true,
+ },
+ });
+ QCOMPARE(presetChanged.size(), 1);
+
+ box.setPresetName("noexist");
+ QCOMPARE(presetChanged.size(), 2);
+ QCOMPARE(presetChanged.last(), QList<QVariant>{ QString{} });
+
+ box.setPresetName("preset");
+ QCOMPARE(presetChanged.size(), 3);
+ QCOMPARE(presetChanged.last(), QList<QVariant>{ "preset" });
+
+ box.blockSignals(true);
+ box.setPresetName(QString{});
+ box.blockSignals(false);
+ QCOMPARE(presetChanged.size(), 3);
+
+ box.setPresetName("preset");
+ QCOMPARE(presetChanged.size(), 4);
+ QCOMPARE(presetChanged.last(), QList<QVariant>{ "preset" });
+
+ box.setPresets({});
+ QCOMPARE(presetChanged.size(), 5);
+ QCOMPARE(presetChanged.last(), QList<QVariant>{ QString{} });
+}
+
+QTEST_MAIN(QCMakePresetComboBoxTest)
diff --git a/Tests/CMakeGUI/QCMakePresetComboBoxTest.h b/Tests/CMakeGUI/QCMakePresetComboBoxTest.h
new file mode 100644
index 0000000..433adbb
--- /dev/null
+++ b/Tests/CMakeGUI/QCMakePresetComboBoxTest.h
@@ -0,0 +1,13 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "QCMakePresetComboBox.h"
+#include <QObject>
+
+class QCMakePresetComboBoxTest : public QObject
+{
+ Q_OBJECT
+private slots:
+ void changePresets();
+};
diff --git a/Tests/CMakeGUI/QCMakePresetItemModelTest.cxx b/Tests/CMakeGUI/QCMakePresetItemModelTest.cxx
new file mode 100644
index 0000000..97dbb30
--- /dev/null
+++ b/Tests/CMakeGUI/QCMakePresetItemModelTest.cxx
@@ -0,0 +1,166 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "QCMakePresetItemModelTest.h"
+
+#include <utility>
+
+#include "QCMakePreset.h"
+#include "QCMakePresetItemModel.h"
+#include <QHash>
+#include <QMetaType>
+#include <QSignalSpy>
+#include <QVariant>
+#include <QVector>
+#include <QtTest>
+
+using QItemDataHash = QHash<Qt::ItemDataRole, QVariant>;
+
+void QCMakePresetItemModelTest::initTestCase()
+{
+ QMetaType::registerComparators<QCMakePreset>();
+}
+
+void QCMakePresetItemModelTest::initTestCase_data()
+{
+ QTest::addColumn<QVector<QCMakePreset>>("presets");
+ QTest::addColumn<QVector<QItemDataHash>>("data");
+
+ QVector<QCMakePreset> presets{
+ QCMakePreset{
+ /*name=*/"no-description",
+ /*description=*/"",
+ /*description=*/"",
+ /*generator=*/"",
+ /*architecture=*/"",
+ /*setArchitecture=*/true,
+ /*toolset=*/"",
+ /*setToolset=*/true,
+ /*enabled=*/true,
+ },
+ QCMakePreset{
+ /*name=*/"short-description",
+ /*description=*/"Short Description",
+ /*description=*/"",
+ /*generator=*/"",
+ /*architecture=*/"",
+ /*setArchitecture=*/true,
+ /*toolset=*/"",
+ /*setToolset=*/true,
+ /*enabled=*/true,
+ },
+ QCMakePreset{
+ /*name=*/"long-description",
+ /*description=*/"",
+ /*description=*/"Long Description",
+ /*generator=*/"",
+ /*architecture=*/"",
+ /*setArchitecture=*/true,
+ /*toolset=*/"",
+ /*setToolset=*/true,
+ /*enabled=*/true,
+ },
+ QCMakePreset{
+ /*name=*/"disabled",
+ /*description=*/"",
+ /*description=*/"",
+ /*generator=*/"",
+ /*architecture=*/"",
+ /*setArchitecture=*/true,
+ /*toolset=*/"",
+ /*setToolset=*/true,
+ /*enabled=*/false,
+ },
+ };
+ QVector<QItemDataHash> data{
+ QItemDataHash{
+ { Qt::AccessibleDescriptionRole, "" },
+ { Qt::DisplayRole, "no-description" },
+ { Qt::ToolTipRole, "" },
+ { Qt::UserRole, QVariant::fromValue(presets[0]) },
+ { Qt::FontRole, QFont{} },
+ },
+ QItemDataHash{
+ { Qt::AccessibleDescriptionRole, "" },
+ { Qt::DisplayRole, "Short Description" },
+ { Qt::ToolTipRole, "" },
+ { Qt::UserRole, QVariant::fromValue(presets[1]) },
+ { Qt::FontRole, QFont{} },
+ },
+ QItemDataHash{
+ { Qt::AccessibleDescriptionRole, "" },
+ { Qt::DisplayRole, "long-description" },
+ { Qt::ToolTipRole, "Long Description" },
+ { Qt::UserRole, QVariant::fromValue(presets[2]) },
+ { Qt::FontRole, QFont{} },
+ },
+ QItemDataHash{
+ { Qt::AccessibleDescriptionRole, "" },
+ { Qt::DisplayRole, "disabled" },
+ { Qt::ToolTipRole, "" },
+ { Qt::UserRole, QVariant::fromValue(presets[3]) },
+ { Qt::FontRole, QFont{} },
+ },
+ QItemDataHash{
+ { Qt::AccessibleDescriptionRole, "separator" },
+ { Qt::DisplayRole, QVariant{} },
+ { Qt::ToolTipRole, QVariant{} },
+ { Qt::UserRole, QVariant{} },
+ { Qt::FontRole, QFont{} },
+ },
+ QItemDataHash{
+ { Qt::AccessibleDescriptionRole, "" },
+ { Qt::DisplayRole, "<custom>" },
+ { Qt::ToolTipRole, "Specify all settings manually" },
+ { Qt::UserRole, QVariant{} },
+ { Qt::FontRole,
+ []() {
+ QFont f;
+ f.setItalic(true);
+ return f;
+ }() },
+ },
+ };
+ QTest::newRow("many") << presets << data;
+ QTest::newRow("none") << QVector<QCMakePreset>{}
+ << QVector<QItemDataHash>{ data.last() };
+}
+
+void QCMakePresetItemModelTest::data()
+{
+ QFETCH_GLOBAL(QVector<QCMakePreset>, presets);
+ QFETCH_GLOBAL(QVector<QItemDataHash>, data);
+ QFETCH(Qt::ItemDataRole, role);
+
+ QCMakePresetItemModel model;
+ QSignalSpy spy1(&model, &QCMakePresetItemModel::modelAboutToBeReset);
+ QSignalSpy spy2(&model, &QCMakePresetItemModel::modelReset);
+ model.setPresets(presets);
+ QCOMPARE(spy1.size(), 1);
+ QCOMPARE(spy2.size(), 1);
+
+ QVector<QVariant> expectedData(data.size());
+ for (int i = 0; i < data.size(); ++i) {
+ expectedData[i] = data[i][role];
+ }
+
+ auto rows = model.rowCount();
+ QVector<QVariant> actualData(rows);
+ for (int i = 0; i < rows; ++i) {
+ actualData[i] = model.data(model.index(i, 0), role);
+ }
+
+ QCOMPARE(actualData, expectedData);
+}
+
+void QCMakePresetItemModelTest::data_data()
+{
+ QTest::addColumn<Qt::ItemDataRole>("role");
+
+ QTest::newRow("accessible") << Qt::AccessibleDescriptionRole;
+ QTest::newRow("display") << Qt::DisplayRole;
+ QTest::newRow("tooltip") << Qt::ToolTipRole;
+ QTest::newRow("user") << Qt::UserRole;
+ QTest::newRow("font") << Qt::FontRole;
+}
+
+QTEST_MAIN(QCMakePresetItemModelTest)
diff --git a/Tests/CMakeGUI/QCMakePresetItemModelTest.h b/Tests/CMakeGUI/QCMakePresetItemModelTest.h
new file mode 100644
index 0000000..ff6efae
--- /dev/null
+++ b/Tests/CMakeGUI/QCMakePresetItemModelTest.h
@@ -0,0 +1,17 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "QCMakePresetItemModel.h"
+#include <QObject>
+
+class QCMakePresetItemModelTest : public QObject
+{
+ Q_OBJECT
+private slots:
+ void initTestCase();
+ void initTestCase_data();
+
+ void data();
+ void data_data();
+};
diff --git a/Tests/CMakeGUI/QCMakePresetTest.cxx b/Tests/CMakeGUI/QCMakePresetTest.cxx
new file mode 100644
index 0000000..2081055
--- /dev/null
+++ b/Tests/CMakeGUI/QCMakePresetTest.cxx
@@ -0,0 +1,85 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "QCMakePresetTest.h"
+
+#include <utility>
+
+#include "QCMakePreset.h"
+#include <QtTest>
+
+namespace {
+QCMakePreset makePreset()
+{
+ return QCMakePreset{
+ /*name=*/"name",
+ /*displayName=*/"displayName",
+ /*description=*/"description",
+ /*generator=*/"generator",
+ /*architecture=*/"architecture",
+ /*setArchitecture=*/true,
+ /*toolset=*/"toolset",
+ /*setToolset=*/true,
+ /*enabled=*/true,
+ };
+}
+
+template <typename T, typename U>
+QCMakePreset makePreset(T QCMakePreset::*field, U&& value)
+{
+ auto preset = makePreset();
+ preset.*field = std::forward<U>(value);
+ return preset;
+}
+}
+
+void QCMakePresetTest::equality()
+{
+ QFETCH(QCMakePreset, rhs);
+ QFETCH(bool, equal);
+ QFETCH(bool, lt);
+ QFETCH(bool, gt);
+
+ auto lhs = makePreset();
+ QVERIFY((lhs == rhs) == equal);
+ QVERIFY((lhs != rhs) == !equal);
+ QVERIFY((lhs < rhs) == lt);
+ QVERIFY((lhs >= rhs) == !lt);
+ QVERIFY((lhs > rhs) == gt);
+ QVERIFY((lhs <= rhs) == !gt);
+}
+
+void QCMakePresetTest::equality_data()
+{
+ QTest::addColumn<QCMakePreset>("rhs");
+ QTest::addColumn<bool>("equal");
+ QTest::addColumn<bool>("lt");
+ QTest::addColumn<bool>("gt");
+
+ QTest::newRow("equal") << makePreset() << true << false << false;
+ QTest::newRow("name") << makePreset(&QCMakePreset::name, "other-name")
+ << false << true << false;
+ QTest::newRow("displayName")
+ << makePreset(&QCMakePreset::displayName, "other-displayName") << false
+ << true << false;
+ QTest::newRow("description")
+ << makePreset(&QCMakePreset::description, "other-description") << false
+ << true << false;
+ QTest::newRow("generator")
+ << makePreset(&QCMakePreset::generator, "other-generator") << false << true
+ << false;
+ QTest::newRow("architecture")
+ << makePreset(&QCMakePreset::architecture, "other-architecture") << false
+ << true << false;
+ QTest::newRow("setArchitecture")
+ << makePreset(&QCMakePreset::setArchitecture, false) << false << false
+ << true;
+ QTest::newRow("toolset") << makePreset(&QCMakePreset::toolset,
+ "other-toolset")
+ << false << false << true;
+ QTest::newRow("setToolset")
+ << makePreset(&QCMakePreset::setToolset, false) << false << false << true;
+ QTest::newRow("enabled") << makePreset(&QCMakePreset::enabled, false)
+ << false << false << true;
+}
+
+QTEST_MAIN(QCMakePresetTest)
diff --git a/Tests/CMakeGUI/QCMakePresetTest.h b/Tests/CMakeGUI/QCMakePresetTest.h
new file mode 100644
index 0000000..5eac88d
--- /dev/null
+++ b/Tests/CMakeGUI/QCMakePresetTest.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "QCMakePreset.h"
+#include <QObject>
+
+class QCMakePresetTest : public QObject
+{
+ Q_OBJECT
+private slots:
+ void equality();
+ void equality_data();
+};
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/presetArg-noPresetBinaryChange/CMakePresets.json.in b/Tests/CMakeGUI/presetArg-noPresetBinaryChange/CMakePresets.json.in
new file mode 100644
index 0000000..d78d69d
--- /dev/null
+++ b/Tests/CMakeGUI/presetArg-noPresetBinaryChange/CMakePresets.json.in
@@ -0,0 +1,33 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "ninja",
+ "generator": "Ninja",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "STRING_VARIABLE": {
+ "type": "STRING",
+ "value": "String value"
+ },
+ "PATH_VARIABLE": {
+ "type": "PATH",
+ "value": "${sourceDir}"
+ },
+ "FILEPATH_VARIABLE": {
+ "type": "FILEPATH",
+ "value": "${sourceDir}/CMakeLists.txt"
+ },
+ "ON_VARIABLE": {
+ "type": "BOOL",
+ "value": "ON"
+ },
+ "FALSE_VARIABLE": {
+ "type": "BOOL",
+ "value": "FALSE"
+ },
+ "UNINITIALIZED_VARIABLE": "Uninitialized value"
+ }
+ }
+ ]
+}
diff --git a/Tests/CMakeGUI/presetArg-preset/CMakePresets.json.in b/Tests/CMakeGUI/presetArg-preset/CMakePresets.json.in
new file mode 100644
index 0000000..d78d69d
--- /dev/null
+++ b/Tests/CMakeGUI/presetArg-preset/CMakePresets.json.in
@@ -0,0 +1,33 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "ninja",
+ "generator": "Ninja",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "STRING_VARIABLE": {
+ "type": "STRING",
+ "value": "String value"
+ },
+ "PATH_VARIABLE": {
+ "type": "PATH",
+ "value": "${sourceDir}"
+ },
+ "FILEPATH_VARIABLE": {
+ "type": "FILEPATH",
+ "value": "${sourceDir}/CMakeLists.txt"
+ },
+ "ON_VARIABLE": {
+ "type": "BOOL",
+ "value": "ON"
+ },
+ "FALSE_VARIABLE": {
+ "type": "BOOL",
+ "value": "FALSE"
+ },
+ "UNINITIALIZED_VARIABLE": "Uninitialized value"
+ }
+ }
+ ]
+}
diff --git a/Tests/CMakeGUI/presetArg-presetBinary/CMakePresets.json.in b/Tests/CMakeGUI/presetArg-presetBinary/CMakePresets.json.in
new file mode 100644
index 0000000..d78d69d
--- /dev/null
+++ b/Tests/CMakeGUI/presetArg-presetBinary/CMakePresets.json.in
@@ -0,0 +1,33 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "ninja",
+ "generator": "Ninja",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "STRING_VARIABLE": {
+ "type": "STRING",
+ "value": "String value"
+ },
+ "PATH_VARIABLE": {
+ "type": "PATH",
+ "value": "${sourceDir}"
+ },
+ "FILEPATH_VARIABLE": {
+ "type": "FILEPATH",
+ "value": "${sourceDir}/CMakeLists.txt"
+ },
+ "ON_VARIABLE": {
+ "type": "BOOL",
+ "value": "ON"
+ },
+ "FALSE_VARIABLE": {
+ "type": "BOOL",
+ "value": "FALSE"
+ },
+ "UNINITIALIZED_VARIABLE": "Uninitialized value"
+ }
+ }
+ ]
+}
diff --git a/Tests/CMakeGUI/presetArg-presetBinaryChange/CMakePresets.json.in b/Tests/CMakeGUI/presetArg-presetBinaryChange/CMakePresets.json.in
new file mode 100644
index 0000000..6fe20d6
--- /dev/null
+++ b/Tests/CMakeGUI/presetArg-presetBinaryChange/CMakePresets.json.in
@@ -0,0 +1,39 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "ninja",
+ "generator": "Ninja",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "STRING_VARIABLE": {
+ "type": "STRING",
+ "value": "String value"
+ },
+ "PATH_VARIABLE": {
+ "type": "PATH",
+ "value": "${sourceDir}"
+ },
+ "FILEPATH_VARIABLE": {
+ "type": "FILEPATH",
+ "value": "${sourceDir}/CMakeLists.txt"
+ },
+ "ON_VARIABLE": {
+ "type": "BOOL",
+ "value": "ON"
+ },
+ "FALSE_VARIABLE": {
+ "type": "BOOL",
+ "value": "FALSE"
+ },
+ "UNINITIALIZED_VARIABLE": "Uninitialized value"
+ }
+ },
+ {
+ "name": "ninja2",
+ "inherits": [
+ "ninja"
+ ]
+ }
+ ]
+}
diff --git a/Tests/CMakeGUI/presetArg-presetConfigExists/CMakeLists.txt.in b/Tests/CMakeGUI/presetArg-presetConfigExists/CMakeLists.txt.in
new file mode 100644
index 0000000..2ae4a57
--- /dev/null
+++ b/Tests/CMakeGUI/presetArg-presetConfigExists/CMakeLists.txt.in
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 3.18)
+project(sourceBinaryArgs-sourceDir NONE)
diff --git a/Tests/CMakeGUI/presetArg-presetConfigExists/CMakePresets.json.in b/Tests/CMakeGUI/presetArg-presetConfigExists/CMakePresets.json.in
new file mode 100644
index 0000000..d78d69d
--- /dev/null
+++ b/Tests/CMakeGUI/presetArg-presetConfigExists/CMakePresets.json.in
@@ -0,0 +1,33 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "ninja",
+ "generator": "Ninja",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "STRING_VARIABLE": {
+ "type": "STRING",
+ "value": "String value"
+ },
+ "PATH_VARIABLE": {
+ "type": "PATH",
+ "value": "${sourceDir}"
+ },
+ "FILEPATH_VARIABLE": {
+ "type": "FILEPATH",
+ "value": "${sourceDir}/CMakeLists.txt"
+ },
+ "ON_VARIABLE": {
+ "type": "BOOL",
+ "value": "ON"
+ },
+ "FALSE_VARIABLE": {
+ "type": "BOOL",
+ "value": "FALSE"
+ },
+ "UNINITIALIZED_VARIABLE": "Uninitialized value"
+ }
+ }
+ ]
+}
diff --git a/Tests/CMakeGUI/presetArg-presetConfigExists/CMakeSetup.ini.in b/Tests/CMakeGUI/presetArg-presetConfigExists/CMakeSetup.ini.in
new file mode 100644
index 0000000..a5d0c71
--- /dev/null
+++ b/Tests/CMakeGUI/presetArg-presetConfigExists/CMakeSetup.ini.in
@@ -0,0 +1,2 @@
+[Settings]
+StartPath\WhereBuild0=@CMake_BINARY_DIR@
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/CMakeGUI/sourceBinaryArgs-binaryDir/CMakeLists.txt.in b/Tests/CMakeGUI/sourceBinaryArgs-binaryDir/CMakeLists.txt.in
new file mode 100644
index 0000000..2ae4a57
--- /dev/null
+++ b/Tests/CMakeGUI/sourceBinaryArgs-binaryDir/CMakeLists.txt.in
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 3.18)
+project(sourceBinaryArgs-sourceDir NONE)
diff --git a/Tests/CMakeGUI/sourceBinaryArgs-noExistConfig/CMakeSetup.ini.in b/Tests/CMakeGUI/sourceBinaryArgs-noExistConfig/CMakeSetup.ini.in
new file mode 100644
index 0000000..db49eea
--- /dev/null
+++ b/Tests/CMakeGUI/sourceBinaryArgs-noExistConfig/CMakeSetup.ini.in
@@ -0,0 +1,2 @@
+[Settings]
+StartPath\WhereBuild0=@CMakeGUITest_BINARY_DIR@/sourceBinaryArgs-noExistConfig/oldbuild
diff --git a/Tests/CMakeGUI/sourceBinaryArgs-noExistConfigExists/CMakeLists.txt.in b/Tests/CMakeGUI/sourceBinaryArgs-noExistConfigExists/CMakeLists.txt.in
new file mode 100644
index 0000000..2ae4a57
--- /dev/null
+++ b/Tests/CMakeGUI/sourceBinaryArgs-noExistConfigExists/CMakeLists.txt.in
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 3.18)
+project(sourceBinaryArgs-sourceDir NONE)
diff --git a/Tests/CMakeGUI/sourceBinaryArgs-noExistConfigExists/CMakeSetup.ini.in b/Tests/CMakeGUI/sourceBinaryArgs-noExistConfigExists/CMakeSetup.ini.in
new file mode 100644
index 0000000..4ffd917
--- /dev/null
+++ b/Tests/CMakeGUI/sourceBinaryArgs-noExistConfigExists/CMakeSetup.ini.in
@@ -0,0 +1,2 @@
+[Settings]
+StartPath\WhereBuild0=@CMakeGUITest_BINARY_DIR@/sourceBinaryArgs-noExistConfigExists/build
diff --git a/Tests/CMakeGUI/sourceBinaryArgs-sourceDir/CMakeLists.txt.in b/Tests/CMakeGUI/sourceBinaryArgs-sourceDir/CMakeLists.txt.in
new file mode 100644
index 0000000..2ae4a57
--- /dev/null
+++ b/Tests/CMakeGUI/sourceBinaryArgs-sourceDir/CMakeLists.txt.in
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 3.18)
+project(sourceBinaryArgs-sourceDir NONE)
diff --git a/Tests/CMakeInstall.cmake b/Tests/CMakeInstall.cmake
new file mode 100644
index 0000000..d9d85f7
--- /dev/null
+++ b/Tests/CMakeInstall.cmake
@@ -0,0 +1,48 @@
+# Define option CMake_TEST_INSTALL, and enable by default for dashboards.
+set(_default 0)
+if(DEFINED ENV{DASHBOARD_TEST_FROM_CTEST})
+ set(_default 1)
+endif()
+option(CMake_TEST_INSTALL "Test CMake Installation" ${_default})
+mark_as_advanced(CMake_TEST_INSTALL)
+
+if(CMake_TEST_INSTALL)
+ # Do not build during the test.
+ set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY 1)
+
+ # Install to a test directory.
+ set(CMake_TEST_INSTALL_PREFIX ${CMake_BINARY_DIR}/Tests/CMakeInstall)
+ set(CMAKE_INSTALL_PREFIX "${CMake_TEST_INSTALL_PREFIX}")
+
+ # 3.9 or later provides a definitive answer to whether we are multi-config
+ # through a global property. Prior to 3.9, CMAKE_CONFIGURATION_TYPES being set
+ # is assumed to mean multi-config, but developers might modify it so it is
+ # technically not as reliable.
+ if(NOT CMAKE_VERSION VERSION_LESS 3.9)
+ get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ elseif(CMAKE_CONFIGURATION_TYPES)
+ set(_isMultiConfig True)
+ else()
+ set(_isMultiConfig False)
+ endif()
+ if(_isMultiConfig)
+ # There are multiple configurations. Make sure the tested
+ # configuration is the one that is installed.
+ set(CMake_TEST_INSTALL_CONFIG --config $<CONFIGURATION>)
+ else()
+ set(CMake_TEST_INSTALL_CONFIG)
+ endif()
+
+ # Add a test to install CMake through the build system install target.
+ add_test(NAME CMake.Install
+ COMMAND cmake --build . --target install ${CMake_TEST_INSTALL_CONFIG}
+ )
+
+ # Avoid running this test simultaneously with other tests:
+ set_tests_properties(CMake.Install PROPERTIES RUN_SERIAL ON)
+
+ # TODO: Make all other tests depend on this one, and then drive them
+ # with the installed CTest.
+else()
+ set(CMake_TEST_INSTALL_PREFIX)
+endif()
diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt
new file mode 100644
index 0000000..87925bd
--- /dev/null
+++ b/Tests/CMakeLib/CMakeLists.txt
@@ -0,0 +1,79 @@
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMake_BINARY_DIR}/Source
+ ${CMake_SOURCE_DIR}/Source
+ ${CMake_SOURCE_DIR}/Source/CTest
+ )
+
+set(CMakeLib_TESTS
+ testArgumentParser.cxx
+ testCTestBinPacker.cxx
+ testCTestResourceAllocator.cxx
+ testCTestResourceSpec.cxx
+ testCTestResourceGroups.cxx
+ testGccDepfileReader.cxx
+ testGeneratedFileStream.cxx
+ testJSONHelpers.cxx
+ testRST.cxx
+ testRange.cxx
+ testOptional.cxx
+ testString.cxx
+ testStringAlgorithms.cxx
+ testSystemTools.cxx
+ testUTF8.cxx
+ testXMLParser.cxx
+ testXMLSafe.cxx
+ testFindPackageCommand.cxx
+ testUVProcessChain.cxx
+ testUVRAII.cxx
+ testUVStreambuf.cxx
+ testCMExtMemory.cxx
+ testCMExtAlgorithm.cxx
+ )
+if (CMake_TEST_FILESYSTEM_PATH OR NOT CMake_HAVE_CXX_FILESYSTEM)
+ list(APPEND CMakeLib_TESTS testCMFilesystemPath.cxx)
+endif()
+
+add_executable(testUVProcessChainHelper testUVProcessChainHelper.cxx)
+
+set(testRST_ARGS ${CMAKE_CURRENT_SOURCE_DIR})
+set(testUVProcessChain_ARGS $<TARGET_FILE:testUVProcessChainHelper>)
+set(testUVStreambuf_ARGS $<TARGET_FILE:cmake>)
+set(testCTestResourceSpec_ARGS ${CMAKE_CURRENT_SOURCE_DIR})
+set(testGccDepfileReader_ARGS ${CMAKE_CURRENT_SOURCE_DIR})
+
+if(WIN32)
+ list(APPEND CMakeLib_TESTS
+ testVisualStudioSlnParser.cxx
+ )
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testVisualStudioSlnParser.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/testVisualStudioSlnParser.h @ONLY)
+endif()
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testXMLParser.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/testXMLParser.h @ONLY)
+
+create_test_sourcelist(CMakeLib_TEST_SRCS CMakeLibTests.cxx ${CMakeLib_TESTS})
+add_executable(CMakeLibTests ${CMakeLib_TEST_SRCS})
+target_link_libraries(CMakeLibTests CMakeLib CTestLib)
+
+set_property(TARGET CMakeLibTests PROPERTY C_CLANG_TIDY "")
+set_property(TARGET CMakeLibTests PROPERTY CXX_CLANG_TIDY "")
+
+add_executable(testEncoding testEncoding.cxx)
+target_link_libraries(testEncoding cmsys)
+
+foreach(testfile ${CMakeLib_TESTS})
+ get_filename_component(test "${testfile}" NAME_WE)
+ add_test(NAME CMakeLib.${test} COMMAND CMakeLibTests ${test} ${${test}_ARGS})
+endforeach()
+
+if(TEST_CompileCommandOutput)
+ add_executable(runcompilecommands run_compile_commands.cxx)
+ target_link_libraries(runcompilecommands CMakeLib)
+endif()
+
+add_subdirectory(PseudoMemcheck)
+
+add_executable(testAffinity testAffinity.cxx)
+target_link_libraries(testAffinity CMakeLib)
diff --git a/Tests/CMakeLib/PseudoMemcheck/CMakeLists.txt b/Tests/CMakeLib/PseudoMemcheck/CMakeLists.txt
new file mode 100644
index 0000000..4bef6c5
--- /dev/null
+++ b/Tests/CMakeLib/PseudoMemcheck/CMakeLists.txt
@@ -0,0 +1,29 @@
+foreach (_retval 0 1)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/memtester.cxx.in" "${CMAKE_CURRENT_BINARY_DIR}/ret${_retval}.cxx" @ONLY)
+endforeach ()
+
+include_directories(${CMake_SOURCE_DIR}/Source ${CMake_BINARY_DIR}/Source)
+
+# create binaries that we will use as a pseudo memory checker
+add_executable(pseudo_valgrind "${CMAKE_CURRENT_BINARY_DIR}/ret0.cxx")
+set_target_properties(pseudo_valgrind PROPERTIES OUTPUT_NAME valgrind)
+target_link_libraries(pseudo_valgrind CMakeLib)
+
+add_executable(pseudo_purify "${CMAKE_CURRENT_BINARY_DIR}/ret0.cxx")
+set_target_properties(pseudo_purify PROPERTIES OUTPUT_NAME purify)
+target_link_libraries(pseudo_purify CMakeLib)
+add_executable(pseudo_BC "${CMAKE_CURRENT_BINARY_DIR}/ret0.cxx")
+set_target_properties(pseudo_BC PROPERTIES OUTPUT_NAME BC)
+target_link_libraries(pseudo_BC CMakeLib)
+add_executable(pseudo_cuda-memcheck "${CMAKE_CURRENT_BINARY_DIR}/ret0.cxx")
+set_target_properties(pseudo_cuda-memcheck PROPERTIES OUTPUT_NAME cuda-memcheck)
+target_link_libraries(pseudo_cuda-memcheck CMakeLib)
+
+# binary to be used as pre- and post-memcheck command that fails
+add_executable(memcheck_fail "${CMAKE_CURRENT_BINARY_DIR}/ret1.cxx")
+target_link_libraries(memcheck_fail CMakeLib)
+
+# Binaries that are used as memchecker that do not write the expected
+# output file. Need to be in their own subdirectory as they have the
+# same filenames.
+add_subdirectory(NoLog)
diff --git a/Tests/CMakeLib/PseudoMemcheck/NoLog/CMakeLists.txt b/Tests/CMakeLib/PseudoMemcheck/NoLog/CMakeLists.txt
new file mode 100644
index 0000000..e47b9db
--- /dev/null
+++ b/Tests/CMakeLib/PseudoMemcheck/NoLog/CMakeLists.txt
@@ -0,0 +1,14 @@
+# A dummy checker implementation that does not write the requested output file
+# so it triggers an error for every checker.
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/ret0.c.in" "int main(){return 0;}\n")
+
+configure_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/ret0.c.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/ret0.c"
+ )
+
+foreach(_pseudo IN ITEMS valgrind purify BC)
+ add_executable(pseudonl_${_pseudo} "${CMAKE_CURRENT_BINARY_DIR}/ret0.c")
+ set_target_properties(pseudonl_${_pseudo} PROPERTIES OUTPUT_NAME ${_pseudo})
+endforeach()
diff --git a/Tests/CMakeLib/PseudoMemcheck/memtester.cxx.in b/Tests/CMakeLib/PseudoMemcheck/memtester.cxx.in
new file mode 100644
index 0000000..f37ad59
--- /dev/null
+++ b/Tests/CMakeLib/PseudoMemcheck/memtester.cxx.in
@@ -0,0 +1,84 @@
+#include <string>
+#include <vector>
+
+#include "cmsys/Encoding.hxx"
+
+#include <cmSystemTools.h>
+
+// clang-format off
+#define RETVAL @_retval@
+#define CMAKE_COMMAND "@CMAKE_COMMAND@"
+// clang-format on
+
+int main(int ac, char** av)
+{
+ cmsys::Encoding::CommandLineArguments args =
+ cmsys::Encoding::CommandLineArguments::Main(ac, av);
+ int argc = args.argc();
+ const char* const* argv = args.argv();
+
+ std::string exename = argv[0];
+ std::string logarg;
+ bool nextarg = false;
+ // execute the part after the last argument?
+ // the logfile path gets passed as environment variable PSEUDO_LOGFILE
+ bool exec = false;
+
+ if (exename.find("valgrind") != std::string::npos) {
+ logarg = "--log-file=";
+ } else if (exename.find("purify") != std::string::npos) {
+#ifdef _WIN32
+ logarg = "/SAVETEXTDATA=";
+#else
+ logarg = "-log-file=";
+#endif
+ } else if (exename.find("BC") != std::string::npos) {
+ nextarg = true;
+ logarg = "/X";
+ } else if (exename.find("cuda-memcheck") != std::string::npos) {
+ nextarg = true;
+ exec = true;
+ logarg = "--log-file";
+ }
+
+ if (!logarg.empty()) {
+ std::string logfile;
+ for (int i = 1; i < argc; i++) {
+ std::string arg = argv[i];
+ if (arg.find(logarg) == 0) {
+ if (nextarg) {
+ if (i == argc - 1) {
+ return 1; // invalid command line
+ }
+ logfile = argv[i + 1];
+ } else {
+ logfile = arg.substr(logarg.length());
+ }
+ // keep searching, it may be overridden later to provoke an error
+ }
+ }
+
+ // find the last argument position
+ int lastarg_pos = 1;
+ for (int i = 1; i < argc; ++i) {
+ std::string arg = argv[i];
+ if (arg.find("--") == 0) {
+ lastarg_pos = i;
+ }
+ }
+
+ if (!logfile.empty()) {
+ cmSystemTools::Touch(logfile, true);
+ // execute everything after the last argument with additional environment
+ int callarg_pos = lastarg_pos + (nextarg ? 2 : 1);
+ if (exec && callarg_pos < argc) {
+ std::vector<std::string> callargs{ CMAKE_COMMAND, "-E", "env",
+ "PSEUDO_LOGFILE=" + logfile };
+ callargs.insert(callargs.end(), &argv[callarg_pos], &argv[argc]);
+ cmSystemTools::RunSingleCommand(callargs);
+ }
+ }
+ }
+
+ return RETVAL;
+}
diff --git a/Tests/CMakeLib/run_compile_commands.cxx b/Tests/CMakeLib/run_compile_commands.cxx
new file mode 100644
index 0000000..0ebe00e
--- /dev/null
+++ b/Tests/CMakeLib/run_compile_commands.cxx
@@ -0,0 +1,159 @@
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <cstdlib>
+#include <iostream>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmSystemTools.h"
+
+class CompileCommandParser
+{
+public:
+ class CommandType : public std::map<std::string, std::string>
+ {
+ public:
+ std::string const& at(std::string const& k) const
+ {
+ auto i = this->find(k);
+ if (i != this->end()) {
+ return i->second;
+ }
+ static std::string emptyString;
+ return emptyString;
+ }
+ };
+ using TranslationUnitsType = std::vector<CommandType>;
+
+ CompileCommandParser(std::istream& input)
+ : Input(input)
+ {
+ }
+
+ void Parse()
+ {
+ this->NextNonWhitespace();
+ this->ParseTranslationUnits();
+ }
+
+ const TranslationUnitsType& GetTranslationUnits()
+ {
+ return this->TranslationUnits;
+ }
+
+private:
+ void ParseTranslationUnits()
+ {
+ this->TranslationUnits = TranslationUnitsType();
+ this->ExpectOrDie('[', "at start of compile command file\n");
+ do {
+ this->ParseTranslationUnit();
+ this->TranslationUnits.push_back(this->Command);
+ } while (this->Expect(','));
+ this->ExpectOrDie(']', "at end of array");
+ }
+
+ void ParseTranslationUnit()
+ {
+ this->Command = CommandType();
+ if (!this->Expect('{')) {
+ return;
+ }
+ if (this->Expect('}')) {
+ return;
+ }
+ do {
+ this->ParseString();
+ std::string name = this->String;
+ this->ExpectOrDie(':', "between name and value");
+ this->ParseString();
+ std::string value = this->String;
+ this->Command[name] = value;
+ } while (this->Expect(','));
+ this->ExpectOrDie('}', "at end of object");
+ }
+
+ void ParseString()
+ {
+ this->String = "";
+ if (!this->Expect('"')) {
+ return;
+ }
+ while (!this->Expect('"')) {
+ this->Expect('\\');
+ this->String.append(1, this->C);
+ this->Next();
+ }
+ }
+
+ bool Expect(char c)
+ {
+ if (this->C == c) {
+ this->NextNonWhitespace();
+ return true;
+ }
+ return false;
+ }
+
+ void ExpectOrDie(char c, const std::string& message)
+ {
+ if (!this->Expect(c)) {
+ this->ErrorExit(std::string("'") + c + "' expected " + message + ".");
+ }
+ }
+
+ void NextNonWhitespace()
+ {
+ do {
+ this->Next();
+ } while (this->IsWhitespace());
+ }
+
+ void Next()
+ {
+ this->C = char(this->Input.get());
+ if (this->Input.bad()) {
+ this->ErrorExit("Unexpected end of file.");
+ }
+ }
+
+ void ErrorExit(const std::string& message)
+ {
+ std::cout << "ERROR: " << message;
+ exit(1);
+ }
+
+ bool IsWhitespace() const
+ {
+ return (this->C == ' ' || this->C == '\t' || this->C == '\n' ||
+ this->C == '\r');
+ }
+
+ char C;
+ TranslationUnitsType TranslationUnits;
+ CommandType Command;
+ std::string String;
+ std::istream& Input;
+};
+
+int main()
+{
+ cmsys::ifstream file("compile_commands.json");
+ CompileCommandParser parser(file);
+ parser.Parse();
+ for (auto const& tu : parser.GetTranslationUnits()) {
+ std::vector<std::string> command;
+ cmSystemTools::ParseUnixCommandLine(tu.at("command").c_str(), command);
+ if (!cmSystemTools::RunSingleCommand(command, nullptr, nullptr, nullptr,
+ tu.at("directory").c_str())) {
+ std::cout << "ERROR: Failed to run command \"" << command[0] << "\""
+ << std::endl;
+ exit(1);
+ }
+ }
+ return 0;
+}
diff --git a/Tests/CMakeLib/testAffinity.cxx b/Tests/CMakeLib/testAffinity.cxx
new file mode 100644
index 0000000..6c68570
--- /dev/null
+++ b/Tests/CMakeLib/testAffinity.cxx
@@ -0,0 +1,18 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include <cstddef>
+#include <iostream>
+#include <set>
+
+#include "cmAffinity.h"
+
+int main()
+{
+ std::set<size_t> cpus = cmAffinity::GetProcessorsAvailable();
+ if (!cpus.empty()) {
+ std::cout << "CPU affinity mask count is '" << cpus.size() << "'.\n";
+ } else {
+ std::cout << "CPU affinity not supported on this platform.\n";
+ }
+ return 0;
+}
diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx
new file mode 100644
index 0000000..965690c
--- /dev/null
+++ b/Tests/CMakeLib/testArgumentParser.cxx
@@ -0,0 +1,148 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <initializer_list>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmArgumentParser.h"
+
+namespace {
+
+struct Result
+{
+ bool Option1 = false;
+ bool Option2 = false;
+
+ std::string String1;
+ std::string String2;
+
+ std::vector<std::string> List1;
+ std::vector<std::string> List2;
+ std::vector<std::string> List3;
+
+ std::vector<std::vector<std::string>> Multi1;
+ std::vector<std::vector<std::string>> Multi2;
+ std::vector<std::vector<std::string>> Multi3;
+};
+
+std::initializer_list<cm::string_view> const args = {
+ /* clang-format off */
+ "OPTION_1", // option
+ "STRING_1", // string arg missing value
+ "STRING_2", "foo", "bar", // string arg + unparsed value
+ "LIST_1", // list arg missing values
+ "LIST_2", "foo", "bar", // list arg with 2 elems
+ "LIST_3", "bar", // list arg ...
+ "LIST_3", "foo", // ... with continuation
+ "MULTI_2", // multi list with 0 lists
+ "MULTI_3", "foo", "bar", // multi list with first list with two elems
+ "MULTI_3", "bar", "foo", // multi list with second list with two elems
+ /* clang-format on */
+};
+
+bool verifyResult(Result const& result,
+ std::vector<std::string> const& unparsedArguments,
+ std::vector<std::string> const& keywordsMissingValue)
+{
+ static std::vector<std::string> const foobar = { "foo", "bar" };
+ static std::vector<std::string> const barfoo = { "bar", "foo" };
+ static std::vector<std::string> const missing = { "STRING_1", "LIST_1" };
+
+#define ASSERT_TRUE(x) \
+ do { \
+ if (!(x)) { \
+ std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
+ return false; \
+ } \
+ } while (false)
+
+ ASSERT_TRUE(result.Option1);
+ ASSERT_TRUE(!result.Option2);
+
+ ASSERT_TRUE(result.String1.empty());
+ ASSERT_TRUE(result.String2 == "foo");
+
+ ASSERT_TRUE(result.List1.empty());
+ ASSERT_TRUE(result.List2 == foobar);
+ ASSERT_TRUE(result.List3 == barfoo);
+
+ ASSERT_TRUE(result.Multi1.empty());
+ ASSERT_TRUE(result.Multi2.size() == 1);
+ ASSERT_TRUE(result.Multi2[0].empty());
+ ASSERT_TRUE(result.Multi3.size() == 2);
+ ASSERT_TRUE(result.Multi3[0] == foobar);
+ ASSERT_TRUE(result.Multi3[1] == barfoo);
+
+ ASSERT_TRUE(unparsedArguments.size() == 1);
+ ASSERT_TRUE(unparsedArguments[0] == "bar");
+ ASSERT_TRUE(keywordsMissingValue == missing);
+
+ return true;
+}
+
+bool testArgumentParserDynamic()
+{
+ Result result;
+ std::vector<std::string> unparsedArguments;
+ std::vector<std::string> keywordsMissingValue;
+
+ cmArgumentParser<void>{}
+ .Bind("OPTION_1"_s, result.Option1)
+ .Bind("OPTION_2"_s, result.Option2)
+ .Bind("STRING_1"_s, result.String1)
+ .Bind("STRING_2"_s, result.String2)
+ .Bind("LIST_1"_s, result.List1)
+ .Bind("LIST_2"_s, result.List2)
+ .Bind("LIST_3"_s, result.List3)
+ .Bind("MULTI_1"_s, result.Multi1)
+ .Bind("MULTI_2"_s, result.Multi2)
+ .Bind("MULTI_3"_s, result.Multi3)
+ .Parse(args, &unparsedArguments, &keywordsMissingValue);
+
+ return verifyResult(result, unparsedArguments, keywordsMissingValue);
+}
+
+bool testArgumentParserStatic()
+{
+ static auto const parser = //
+ cmArgumentParser<Result>{}
+ .Bind("OPTION_1"_s, &Result::Option1)
+ .Bind("OPTION_2"_s, &Result::Option2)
+ .Bind("STRING_1"_s, &Result::String1)
+ .Bind("STRING_2"_s, &Result::String2)
+ .Bind("LIST_1"_s, &Result::List1)
+ .Bind("LIST_2"_s, &Result::List2)
+ .Bind("LIST_3"_s, &Result::List3)
+ .Bind("MULTI_1"_s, &Result::Multi1)
+ .Bind("MULTI_2"_s, &Result::Multi2)
+ .Bind("MULTI_3"_s, &Result::Multi3);
+
+ std::vector<std::string> unparsedArguments;
+ std::vector<std::string> keywordsMissingValue;
+ Result const result =
+ parser.Parse(args, &unparsedArguments, &keywordsMissingValue);
+
+ return verifyResult(result, unparsedArguments, keywordsMissingValue);
+}
+
+} // namespace
+
+int testArgumentParser(int /*unused*/, char* /*unused*/ [])
+{
+ if (!testArgumentParserDynamic()) {
+ std::cout << "While executing testArgumentParserDynamic().\n";
+ return -1;
+ }
+
+ if (!testArgumentParserStatic()) {
+ std::cout << "While executing testArgumentParserStatic().\n";
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/Tests/CMakeLib/testCMExtAlgorithm.cxx b/Tests/CMakeLib/testCMExtAlgorithm.cxx
new file mode 100644
index 0000000..b8319c3
--- /dev/null
+++ b/Tests/CMakeLib/testCMExtAlgorithm.cxx
@@ -0,0 +1,118 @@
+#include <iostream>
+#include <memory>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include <cmext/algorithm>
+
+namespace {
+
+int failed = 0;
+
+void testAppend()
+{
+ std::cout << "testAppend()" << std::endl;
+
+ // ----------------------------------------------------
+ // cm::append(Vector, Iterator, Iterator)
+ {
+ std::vector<int> v1{ 1, 2, 3 };
+ std::vector<int> v1_ref{ 1, 2, 3, 4, 5, 6 };
+ std::vector<int> v2{ 4, 5, 6 };
+ std::vector<int> v2_ref{ 4, 5, 6 };
+
+ cm::append(v1, v2.begin(), v2.end());
+
+ if (v1 != v1_ref || v2 != v2_ref) {
+ ++failed;
+ }
+ }
+
+ // ----------------------------------------------------
+ // cm::append(Vector, Range)
+ {
+ std::vector<int> v1{ 1, 2, 3 };
+ std::vector<int> v1_ref{ 1, 2, 3, 4, 5, 6 };
+ std::vector<int> v2{ 4, 5, 6 };
+ std::vector<int> v2_ref{ 4, 5, 6 };
+
+ cm::append(v1, v2);
+
+ if (v1 != v1_ref || v2 != v2_ref) {
+ ++failed;
+ }
+ }
+
+ // ----------------------------------------------------
+ // cm::append(Vector<*>, Vector<unique_ptr>)
+ {
+ std::vector<int*> v1{ new int(1), new int(2), new int(3) };
+ std::vector<int*> v1_ref = v1;
+ std::vector<std::unique_ptr<int>> v2;
+
+ v2.emplace_back(new int(4));
+ v2.emplace_back(new int(5));
+ v2.emplace_back(new int(6));
+
+ cm::append(v1, v2);
+
+ if (v1.size() == 6 && v2.size() == 3) {
+ for (int i = 0; i < 3; i++) {
+ if (v1[i] != v1_ref[i]) {
+ ++failed;
+ break;
+ }
+ }
+ for (int i = 0; i < 3; i++) {
+ if (v1[i + 3] != v2[i].get()) {
+ ++failed;
+ break;
+ }
+ }
+ } else {
+ ++failed;
+ }
+
+ // free memory to please memory sanitizer
+ delete v1[0];
+ delete v1[1];
+ delete v1[2];
+ }
+
+ // ----------------------------------------------------
+ // cm::append(Vector<unique_ptr>, Vector<unique_ptr>)
+ {
+ std::vector<std::unique_ptr<int>> v1;
+ std::vector<std::unique_ptr<int>> v2;
+
+ v1.emplace_back(new int(1));
+ v1.emplace_back(new int(2));
+ v1.emplace_back(new int(3));
+
+ v2.emplace_back(new int(4));
+ v2.emplace_back(new int(5));
+ v2.emplace_back(new int(6));
+
+ cm::append(v1, std::move(v2));
+
+ if (v1.size() == 6 && v2.empty()) {
+ for (int i = 0; i < 6; i++) {
+ if (*v1[i] != i + 1) {
+ ++failed;
+ break;
+ }
+ }
+ } else {
+ ++failed;
+ }
+ }
+}
+}
+
+int testCMExtAlgorithm(int /*unused*/, char* /*unused*/ [])
+{
+ testAppend();
+
+ return failed;
+}
diff --git a/Tests/CMakeLib/testCMExtMemory.cxx b/Tests/CMakeLib/testCMExtMemory.cxx
new file mode 100644
index 0000000..d8932ce
--- /dev/null
+++ b/Tests/CMakeLib/testCMExtMemory.cxx
@@ -0,0 +1,65 @@
+#include <iostream>
+#include <memory>
+
+#include <cmext/memory>
+
+namespace {
+class Base
+{
+public:
+ virtual ~Base() = default;
+};
+
+class Derived : public Base
+{
+public:
+ ~Derived() override = default;
+
+ void method() {}
+};
+
+template <typename T>
+class Wrapper
+{
+public:
+ Wrapper(T* v)
+ : value(v)
+ {
+ }
+ ~Wrapper() { delete this->value; }
+
+ T* get() const { return this->value; }
+
+private:
+ T* value;
+};
+
+bool testReferenceCast()
+{
+ std::cout << "testReferenceCast()" << std::endl;
+
+ std::unique_ptr<Base> u(new Derived);
+ cm::static_reference_cast<Derived>(u).method();
+ cm::dynamic_reference_cast<Derived>(u).method();
+
+ std::shared_ptr<Base> s(new Derived);
+ cm::static_reference_cast<Derived>(s).method();
+ cm::dynamic_reference_cast<Derived>(s).method();
+
+ // can also be used with custom wrappers
+ Wrapper<Base> w(new Derived);
+ cm::static_reference_cast<Derived>(w).method();
+ cm::dynamic_reference_cast<Derived>(w).method();
+
+ return true;
+}
+}
+
+int testCMExtMemory(int /*unused*/, char* /*unused*/ [])
+{
+ if (!testReferenceCast()) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/Tests/CMakeLib/testCMFilesystemPath.cxx b/Tests/CMakeLib/testCMFilesystemPath.cxx
new file mode 100644
index 0000000..579ba99
--- /dev/null
+++ b/Tests/CMakeLib/testCMFilesystemPath.cxx
@@ -0,0 +1,1008 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <cm/filesystem>
+
+namespace {
+
+namespace fs = cm::filesystem;
+
+void checkResult(bool success)
+{
+ if (!success) {
+ std::cout << " => failed";
+ }
+ std::cout << std::endl;
+}
+
+bool testConstructors()
+{
+ std::cout << "testConstructors()";
+
+ bool result = true;
+
+ {
+ fs::path p;
+ if (p != fs::path()) {
+ result = false;
+ }
+ }
+ {
+ fs::path p1("/a/b/c");
+ fs::path p2("/a/b/c");
+ if (p1 != p2) {
+ result = false;
+ }
+ if (p1.string() != p2.string()) {
+ result = false;
+ }
+ if (p1.string() != "/a/b/c") {
+ result = false;
+ }
+ }
+ {
+ std::string s("/a/b/c");
+ fs::path p1(s);
+ fs::path p2(s.begin(), s.end());
+ if (p1 != p2) {
+ result = false;
+ }
+ if (p1.string() != s || p2.string() != s) {
+ result = false;
+ }
+#if CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR
+ std::string s2(s);
+ s2 += '\0';
+ fs::path p3(s2.begin());
+ if (p1 != p3 || p3.string() != s) {
+ result = false;
+ }
+#endif
+ }
+ {
+ std::wstring s(L"/a/b/c");
+ fs::path p1(s);
+ fs::path p2(s.begin(), s.end());
+ if (p1 != p2) {
+ result = false;
+ }
+ if (p1.wstring() != s || p2.wstring() != s) {
+ result = false;
+ }
+#if CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR
+ std::wstring s2(s);
+ s2 += L'\0';
+ fs::path p3(s2.begin());
+ if (p1 != p3 || p3.wstring() != s) {
+ result = false;
+ }
+#endif
+ }
+ {
+ std::string s("/a/b/c");
+ fs::path::string_type ws;
+ for (auto c : s) {
+ ws += fs::path::value_type(c);
+ }
+ fs::path p1(ws);
+ fs::path p2(ws.begin(), ws.end());
+ if (p1 != p2) {
+ result = false;
+ }
+ if (p1.native() != ws || p2.native() != ws) {
+ result = false;
+ }
+#if CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR
+ fs::path::string_type ws2(ws);
+ ws2 += fs::path::value_type('\0');
+ fs::path p3(ws2.begin());
+ if (p1 != p3 || p3.native() != ws) {
+ result = false;
+ }
+#endif
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testConcatenation()
+{
+ std::cout << "testConcatenation()";
+
+ bool result = true;
+
+ {
+ fs::path p("/a/b");
+ p /= "c";
+ if (!(p.string() == "/a/b/c" || p.string() == "/a/b\\c")) {
+ result = false;
+ }
+ p += "d";
+ if (!(p.string() == "/a/b/cd" || p.string() == "/a/b\\cd")) {
+ result = false;
+ }
+ fs::path p2("x/y");
+ p /= p2;
+ if (!(p.string() == "/a/b/cd/x/y" || p.string() == "/a/b\\cd\\x/y")) {
+ result = false;
+ }
+ p = p / p2;
+ if (!(p.string() == "/a/b/cd/x/y/x/y" ||
+ p.string() == "/a/b\\cd\\x/y\\x/y")) {
+ result = false;
+ }
+ }
+ {
+ fs::path p("a");
+ p /= "";
+ if (!(p.string() == "a/" || p.string() == "a\\")) {
+ result = false;
+ }
+ p /= "/b";
+ if (p.string() != "/b") {
+ result = false;
+ }
+ }
+#if defined(_WIN32)
+ {
+ fs::path p("a");
+ p /= "c:/b";
+ if (p.string() != "c:/b") {
+ result = false;
+ }
+ p = fs::path("a") / "c:";
+ if (p.string() != "c:") {
+ result = false;
+ }
+ p = fs::path("c:") / "";
+ if (p.string() != "c:") {
+ result = false;
+ }
+ p = fs::path("c:a") / "/b";
+ if (p.string() != "c:/b") {
+ result = false;
+ }
+ p = fs::path("c:a") / "c:b";
+ if (p.string() != "c:a\\b") {
+ result = false;
+ }
+ p = fs::path("//host") / "b";
+ if (p.string() != "//host\\b") {
+ result = false;
+ }
+ p = fs::path("//host/") / "b";
+ if (p.string() != "//host/b") {
+ result = false;
+ }
+ }
+#endif
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testModifiers()
+{
+ std::cout << "testModifiers()";
+
+ bool result = true;
+
+ {
+ std::string s("a///b/");
+ fs::path p(s);
+ std::replace(
+ s.begin(), s.end(), '/',
+ static_cast<std::string::value_type>(fs::path::preferred_separator));
+ p.make_preferred();
+ if (p.string() != s) {
+ result = false;
+ }
+ }
+ {
+ fs::path p("a/b/c.e.f");
+ p.remove_filename();
+ if (p.string() != "a/b/") {
+ result = false;
+ }
+ p.remove_filename();
+ if (p.string() != "a/b/") {
+ result = false;
+ }
+ }
+ {
+ fs::path p("a/b/c.e.f");
+ p.replace_filename("x.y");
+ if (p.string() != "a/b/x.y") {
+ result = false;
+ }
+ }
+ {
+ fs::path p("a/b/c.e.f");
+ p.replace_extension(".x");
+ if (p.string() != "a/b/c.e.x") {
+ result = false;
+ }
+ p.replace_extension(".y");
+ if (p.string() != "a/b/c.e.y") {
+ result = false;
+ }
+ p.replace_extension();
+ if (p.string() != "a/b/c.e") {
+ result = false;
+ }
+ p = "/a/b";
+ p.replace_extension(".x");
+ if (p.string() != "/a/b.x") {
+ result = false;
+ }
+ p = "/a/b/";
+ p.replace_extension(".x");
+ if (p.string() != "/a/b/.x") {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testObservers()
+{
+ std::cout << "testObservers()";
+
+ bool result = true;
+
+ {
+ std::string s("a/b/c");
+ fs::path p(s);
+ fs::path::string_type st;
+ for (auto c : s) {
+ st += static_cast<fs::path::value_type>(c);
+ }
+ if (p.native() != st || static_cast<fs::path::string_type>(p) != st ||
+ p.c_str() != st) {
+ result = false;
+ }
+ }
+ {
+ std::string s("a//b//c");
+ std::wstring ws(L"a//b//c");
+ fs::path p(s);
+ if (p.string() != s || p.wstring() != ws) {
+ result = false;
+ }
+ }
+ {
+ std::string s("a/b/c");
+ std::wstring ws;
+ for (auto c : s) {
+ ws += static_cast<std::wstring::value_type>(c);
+ }
+ std::string ns(s);
+ std::replace(
+ ns.begin(), ns.end(), '/',
+ static_cast<std::string::value_type>(fs::path::preferred_separator));
+ fs::path p(ns);
+ if (p.generic_string() != s || p.generic_wstring() != ws) {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testCompare()
+{
+ std::cout << "testCompare()";
+
+ bool result = true;
+
+ {
+ std::string s("a/b/c");
+ fs::path p1(s);
+ fs::path p2(s);
+ if (p1.compare(p2) != 0) {
+ result = false;
+ }
+ p2 = "a/b";
+ if (p1.compare(p2) <= 0) {
+ result = false;
+ }
+ p2 = "a/d";
+ if (p1.compare(p2) >= 0) {
+ result = false;
+ }
+ p2 = "a/b/d";
+ if (p1.compare(p2) >= 0) {
+ result = false;
+ }
+ p2 = "a/b/a";
+ if (p1.compare(p2) <= 0) {
+ result = false;
+ }
+ p2 = "a/b/c/d";
+ if (p1.compare(p2) >= 0) {
+ result = false;
+ }
+ p1 = "a";
+ p2 = "b";
+ if (p1.compare(p2) == 0) {
+ result = false;
+ }
+ }
+ {
+ // LWG 3096 (https://cplusplus.github.io/LWG/issue3096)
+ // fs::path p1("/a/");
+ // fs::path p2("/a/.");
+ // if (p1.compare(p2) != 0) {
+ // result = false;
+ // }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testGeneration()
+{
+ std::cout << "testGeneration()";
+
+ bool result = true;
+
+ {
+ fs::path p("a/./b/..");
+ if (p.lexically_normal().generic_string() != "a/") {
+ result = false;
+ }
+ p = "a/.///b/../";
+ if (p.lexically_normal().generic_string() != "a/") {
+ result = false;
+ }
+ }
+#if defined(_WIN32)
+ {
+ fs::path p("//host/./b/..");
+ if (p.lexically_normal().string() != "\\\\host\\") {
+ result = false;
+ }
+ p = "//host/.///b/../";
+ if (p.lexically_normal().string() != "\\\\host\\") {
+ result = false;
+ }
+ p = "c://a/.///b/../";
+ if (p.lexically_normal().string() != "c:\\a\\") {
+ result = false;
+ }
+ }
+#endif
+
+ {
+ if (fs::path("/a//d").lexically_relative("/a/b/c") != "../../d") {
+ result = false;
+ }
+ if (fs::path("/a//b///c").lexically_relative("/a/d") != "../b/c") {
+ result = false;
+ }
+ if (fs::path("a/b/c").lexically_relative("a") != "b/c") {
+ result = false;
+ }
+ if (fs::path("a/b/c").lexically_relative("a/b/c/x/y") != "../..") {
+ result = false;
+ }
+ if (fs::path("a/b/c").lexically_relative("a/b/c") != ".") {
+ result = false;
+ }
+ if (fs::path("a/b").lexically_relative("c/d") != "../../a/b") {
+ result = false;
+ }
+ }
+ {
+#if defined(_WIN32)
+ if (fs::path("/a/d").lexically_relative("e/d/c") != "/a/d") {
+ result = false;
+ }
+ if (!fs::path("c:/a/d").lexically_relative("e/d/c").empty()) {
+ result = false;
+ }
+#else
+ if (!fs::path("/a/d").lexically_relative("e/d/c").empty()) {
+ result = false;
+ }
+#endif
+ }
+ {
+#if defined(_WIN32)
+ if (fs::path("c:/a/d").lexically_proximate("e/d/c") != "c:/a/d") {
+ result = false;
+ }
+#else
+ if (fs::path("/a/d").lexically_proximate("e/d/c") != "/a/d") {
+ result = false;
+ }
+#endif
+ if (fs::path("/a/d").lexically_proximate("/a/b/c") != "../../d") {
+ result = false;
+ }
+ }
+ // LWG 3070
+ {
+#if defined(_WIN32)
+ if (!fs::path("/a:/b:").lexically_relative("/a:/c:").empty()) {
+ result = false;
+ }
+ if (fs::path("c:/a/b").lexically_relative("c:/a/d") != "../b") {
+ result = false;
+ }
+ if (!fs::path("c:/a/b:").lexically_relative("c:/a/d").empty()) {
+ result = false;
+ }
+ if (!fs::path("c:/a/b").lexically_relative("c:/a/d:").empty()) {
+ result = false;
+ }
+#else
+ if (fs::path("/a:/b:").lexically_relative("/a:/c:") != "../b:") {
+ result = false;
+ }
+#endif
+ }
+ // LWG 3096
+ {
+ if (fs::path("/a").lexically_relative("/a/.") != ".") {
+ result = false;
+ }
+ if (fs::path("/a").lexically_relative("/a/") != ".") {
+ result = false;
+ }
+ if (fs::path("a/b/c").lexically_relative("a/b/c") != ".") {
+ result = false;
+ }
+ if (fs::path("a/b/c").lexically_relative("a/b/c/") != ".") {
+ result = false;
+ }
+ if (fs::path("a/b/c").lexically_relative("a/b/c/.") != ".") {
+ result = false;
+ }
+ if (fs::path("a/b/c/").lexically_relative("a/b/c") != ".") {
+ result = false;
+ }
+ if (fs::path("a/b/c/.").lexically_relative("a/b/c") != ".") {
+ result = false;
+ }
+ if (fs::path("a/b/c/.").lexically_relative("a/b/c/") != ".") {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testDecomposition()
+{
+ std::cout << "testDecomposition()";
+
+ bool result = true;
+
+ {
+ if (!fs::path("/a/b").root_name().empty()) {
+ result = false;
+ }
+#if defined(_WIN32)
+ if (fs::path("c:/a/b").root_name() != "c:") {
+ result = false;
+ }
+ if (fs::path("c:a/b").root_name() != "c:") {
+ result = false;
+ }
+ if (fs::path("c:").root_name() != "c:") {
+ result = false;
+ }
+ if (fs::path("//host/b").root_name() != "//host") {
+ result = false;
+ }
+ if (fs::path("//host").root_name() != "//host") {
+ result = false;
+ }
+#endif
+ }
+ {
+ if (!fs::path("a/b").root_directory().empty()) {
+ result = false;
+ }
+ if (fs::path("/a/b").root_directory() != "/") {
+ result = false;
+ }
+#if defined(_WIN32)
+ if (!fs::path("c:a/b").root_directory().empty()) {
+ result = false;
+ }
+ if (fs::path("/a/b").root_directory() != "/") {
+ result = false;
+ }
+ if (fs::path("c:/a/b").root_directory() != "/") {
+ result = false;
+ }
+ if (fs::path("//host/b").root_directory() != "/") {
+ result = false;
+ }
+#endif
+ }
+ {
+ if (!fs::path("a/b").root_path().empty()) {
+ result = false;
+ }
+ if (fs::path("/a/b").root_path() != "/") {
+ result = false;
+ }
+#if defined(_WIN32)
+ if (fs::path("c:a/b").root_path() != "c:") {
+ result = false;
+ }
+ if (fs::path("/a/b").root_path() != "/") {
+ result = false;
+ }
+ if (fs::path("c:/a/b").root_path() != "c:/") {
+ result = false;
+ }
+ if (fs::path("//host/b").root_path() != "//host/") {
+ result = false;
+ }
+#endif
+ }
+ {
+ if (!fs::path("/").relative_path().empty()) {
+ result = false;
+ }
+ if (fs::path("a/b").relative_path() != "a/b") {
+ result = false;
+ }
+ if (fs::path("/a/b").relative_path() != "a/b") {
+ result = false;
+ }
+#if defined(_WIN32)
+ if (fs::path("c:a/b").relative_path() != "a/b") {
+ result = false;
+ }
+ if (fs::path("/a/b").relative_path() != "a/b") {
+ result = false;
+ }
+ if (fs::path("c:/a/b").relative_path() != "a/b") {
+ result = false;
+ }
+ if (fs::path("//host/b").relative_path() != "b") {
+ result = false;
+ }
+#endif
+ }
+ {
+ if (fs::path("/a/b").parent_path() != "/a") {
+ result = false;
+ }
+ if (fs::path("/a/b/").parent_path() != "/a/b") {
+ result = false;
+ }
+ if (fs::path("/a/b/.").parent_path() != "/a/b") {
+ result = false;
+ }
+ if (fs::path("/").parent_path() != "/") {
+ result = false;
+ }
+#if defined(_WIN32)
+ if (fs::path("c:/a/b").parent_path() != "c:/a") {
+ result = false;
+ }
+ if (fs::path("c:a").parent_path() != "c:") {
+ result = false;
+ }
+ if (fs::path("c:/").parent_path() != "c:/") {
+ result = false;
+ }
+ if (fs::path("c:").parent_path() != "c:") {
+ result = false;
+ }
+ if (fs::path("//host/").parent_path() != "//host/") {
+ result = false;
+ }
+ if (fs::path("//host").parent_path() != "//host") {
+ result = false;
+ }
+#endif
+ }
+ {
+ if (fs::path("/a/b.txt").filename() != "b.txt") {
+ result = false;
+ }
+ if (fs::path("/a/.b").filename() != ".b") {
+ result = false;
+ }
+ if (fs::path("/foo/bar/").filename() != "") {
+ result = false;
+ }
+ if (fs::path("/foo/.").filename() != ".") {
+ result = false;
+ }
+ if (fs::path("/foo/..").filename() != "..") {
+ result = false;
+ }
+ if (fs::path(".").filename() != ".") {
+ result = false;
+ }
+ if (fs::path("..").filename() != "..") {
+ result = false;
+ }
+ if (!fs::path("/").filename().empty()) {
+ result = false;
+ }
+#if defined(_WIN32)
+ if (fs::path("c:a").filename() != "a") {
+ result = false;
+ }
+ if (fs::path("c:/a").filename() != "a") {
+ result = false;
+ }
+ if (!fs::path("c:").filename().empty()) {
+ result = false;
+ }
+ if (!fs::path("c:/").filename().empty()) {
+ result = false;
+ }
+ if (!fs::path("//host").filename().empty()) {
+ result = false;
+ }
+#endif
+ }
+ {
+ if (fs::path("/a/b.txt").stem() != "b") {
+ result = false;
+ }
+ if (fs::path("/a/b.c.txt").stem() != "b.c") {
+ result = false;
+ }
+ if (fs::path("/a/.b").stem() != ".b") {
+ result = false;
+ }
+ if (fs::path("/a/b").stem() != "b") {
+ result = false;
+ }
+ if (fs::path("/a/b/.").stem() != ".") {
+ result = false;
+ }
+ if (fs::path("/a/b/..").stem() != "..") {
+ result = false;
+ }
+ if (!fs::path("/a/b/").stem().empty()) {
+ result = false;
+ }
+#if defined(_WIN32)
+ if (!fs::path("c:/a/b/").stem().empty()) {
+ result = false;
+ }
+ if (!fs::path("c:/").stem().empty()) {
+ result = false;
+ }
+ if (!fs::path("c:").stem().empty()) {
+ result = false;
+ }
+ if (!fs::path("//host/").stem().empty()) {
+ result = false;
+ }
+ if (!fs::path("//host").stem().empty()) {
+ result = false;
+ }
+#endif
+ }
+ {
+ if (fs::path("/a/b.txt").extension() != ".txt") {
+ result = false;
+ }
+ if (fs::path("/a/b.").extension() != ".") {
+ result = false;
+ }
+ if (!fs::path("/a/b").extension().empty()) {
+ result = false;
+ }
+ if (fs::path("/a/b.txt/b.cc").extension() != ".cc") {
+ result = false;
+ }
+ if (fs::path("/a/b.txt/b.").extension() != ".") {
+ result = false;
+ }
+ if (!fs::path("/a/b.txt/b").extension().empty()) {
+ result = false;
+ }
+ if (!fs::path("/a/.").extension().empty()) {
+ result = false;
+ }
+ if (!fs::path("/a/..").extension().empty()) {
+ result = false;
+ }
+ if (!fs::path("/a/.hidden").extension().empty()) {
+ result = false;
+ }
+ if (fs::path("/a/..b").extension() != ".b") {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testQueries()
+{
+ std::cout << "testQueries()";
+
+ bool result = true;
+
+ {
+ if (fs::path("/a/b").has_root_name()) {
+ result = false;
+ }
+ fs::path p("/a/b");
+ if (!p.has_root_directory() || !p.has_root_path()) {
+ result = false;
+ }
+ if (!fs::path("/a/b").has_root_path() || fs::path("a/b").has_root_path()) {
+ result = false;
+ }
+ if (!fs::path("/a/b").has_relative_path() ||
+ fs::path("/").has_relative_path()) {
+ result = false;
+ }
+ if (!fs::path("/a/b").has_parent_path() ||
+ !fs::path("/").has_parent_path() || fs::path("a").has_parent_path()) {
+ result = false;
+ }
+ if (!fs::path("/a/b").has_filename() || !fs::path("a.b").has_filename() ||
+ fs::path("/a/").has_filename() || fs::path("/").has_filename()) {
+ result = false;
+ }
+ if (!fs::path("/a/b").has_stem() || !fs::path("a.b").has_stem() ||
+ !fs::path("/.a").has_stem() || fs::path("/a/").has_stem() ||
+ fs::path("/").has_stem()) {
+ result = false;
+ }
+ if (!fs::path("/a/b.c").has_extension() ||
+ !fs::path("a.b").has_extension() || fs::path("/.a").has_extension() ||
+ fs::path("/a/").has_extension() || fs::path("/").has_extension()) {
+ result = false;
+ }
+#if defined(_WIN32)
+ p = "c:/a/b";
+ if (!fs::path("c:/a/b").has_root_name() || !p.has_root_directory() ||
+ !p.has_root_path()) {
+ result = false;
+ }
+ p = "c:a/b";
+ if (!p.has_root_name() || p.has_root_directory() || !p.has_root_path()) {
+ result = false;
+ }
+ p = "//host/b";
+ if (!p.has_root_name() || !p.has_root_directory() || !p.has_root_path()) {
+ result = false;
+ }
+ p = "//host";
+ if (!p.has_root_name() || p.has_root_directory() || !p.has_root_path()) {
+ result = false;
+ }
+ if (!fs::path("c:/a/b").has_relative_path() ||
+ !fs::path("c:a/b").has_relative_path() ||
+ !fs::path("//host/b").has_relative_path()) {
+ result = false;
+ }
+ if (!fs::path("c:/a/b").has_parent_path() ||
+ !fs::path("c:/").has_parent_path() ||
+ !fs::path("c:").has_parent_path() ||
+ !fs::path("//host/").has_parent_path() ||
+ !fs::path("//host").has_parent_path()) {
+ result = false;
+ }
+#endif
+ }
+ {
+#if defined(_WIN32)
+ fs::path p("c:/a");
+#else
+ fs::path p("/a");
+#endif
+ if (!p.is_absolute() || p.is_relative()) {
+ result = false;
+ }
+ p = "a/b";
+ if (p.is_absolute() || !p.is_relative()) {
+ result = false;
+ }
+#if defined(_WIN32)
+ p = "c:/a/b";
+ if (!p.is_absolute() || p.is_relative()) {
+ result = false;
+ }
+ p = "//host/b";
+ if (!p.is_absolute() || p.is_relative()) {
+ result = false;
+ }
+ p = "/a";
+ if (p.is_absolute() || !p.is_relative()) {
+ result = false;
+ }
+ p = "c:a";
+ if (p.is_absolute() || !p.is_relative()) {
+ result = false;
+ }
+#endif
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testIterators()
+{
+ std::cout << "testIterators()";
+
+ bool result = true;
+
+ {
+ fs::path p("/a/b/");
+#if defined(_WIN32)
+ std::vector<fs::path::string_type> ref{ L"/", L"a", L"b", L"" };
+#else
+ std::vector<fs::path::string_type> ref{ "/", "a", "b", "" };
+#endif
+ std::vector<fs::path::string_type> res;
+ for (auto i = p.begin(), e = p.end(); i != e; ++i) {
+ res.push_back(*i);
+ }
+ if (res != ref) {
+ result = false;
+ }
+ res.clear();
+ for (const auto& e : p) {
+ res.push_back(e);
+ }
+ if (res != ref) {
+ result = false;
+ }
+ }
+ {
+ fs::path p("/a/b/");
+#if defined(_WIN32)
+ std::vector<fs::path::string_type> ref{ L"", L"b", L"a", L"/" };
+#else
+ std::vector<fs::path::string_type> ref{ "", "b", "a", "/" };
+#endif
+ std::vector<fs::path::string_type> res;
+ auto i = p.end(), b = p.begin();
+ do {
+ res.push_back(*--i);
+ } while (i != b);
+ if (res != ref) {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testNonMemberFunctions()
+{
+ std::cout << "testNonMemberFunctions()";
+
+ bool result = true;
+
+ {
+ fs::path p1("/a/b/");
+ fs::path p2("/c/d");
+ fs::swap(p1, p2);
+ if (p1.string() != "/c/d" || p2.string() != "/a/b/")
+ result = false;
+ }
+ {
+ auto h1 = fs::hash_value(fs::path("/a//b//"));
+ auto h2 = fs::hash_value(fs::path("/a/b/"));
+ if (h1 != h2)
+ result = false;
+ }
+ {
+ fs::path p1("/a/b/");
+ fs::path p2("/c/d");
+ if (p1 == p2)
+ result = false;
+ p1 = "/a//b//";
+ p2 = "/a/b/";
+ if (p1 != p2)
+ result = false;
+ }
+ {
+ fs::path p = "/a";
+ p = p / "b" / "c";
+ if (p.generic_string() != "/a/b/c") {
+ result = false;
+ }
+ fs::path::string_type ref;
+ ref += fs::path::value_type('/');
+ ref += fs::path::value_type('a');
+ ref += fs::path::preferred_separator;
+ ref += fs::path::value_type('b');
+ ref += fs::path::preferred_separator;
+ ref += fs::path::value_type('c');
+ if (p.native() != ref) {
+ result = false;
+ }
+ }
+ {
+ fs::path p("/a b\\c/");
+ std::ostringstream oss;
+ oss << p;
+ if (oss.str() != "\"/a b\\\\c/\"") {
+ result = false;
+ }
+ std::istringstream iss(oss.str());
+ fs::path p2;
+ iss >> p2;
+ if (p2 != p) {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+}
+
+int testCMFilesystemPath(int /*unused*/, char* /*unused*/ [])
+{
+ int result = 0;
+
+ if (!testConstructors()) {
+ result = 1;
+ }
+ if (!testConcatenation()) {
+ result = 1;
+ }
+ if (!testModifiers()) {
+ result = 1;
+ }
+ if (!testObservers()) {
+ result = 1;
+ }
+ if (!testCompare()) {
+ result = 1;
+ }
+ if (!testGeneration()) {
+ result = 1;
+ }
+ if (!testDecomposition()) {
+ result = 1;
+ }
+ if (!testQueries()) {
+ result = 1;
+ }
+ if (!testIterators()) {
+ result = 1;
+ }
+ if (!testNonMemberFunctions()) {
+ result = 1;
+ }
+
+ return result;
+}
diff --git a/Tests/CMakeLib/testCTestBinPacker.cxx b/Tests/CMakeLib/testCTestBinPacker.cxx
new file mode 100644
index 0000000..abdbefb
--- /dev/null
+++ b/Tests/CMakeLib/testCTestBinPacker.cxx
@@ -0,0 +1,300 @@
+#include <cstddef> // IWYU pragma: keep
+#include <iostream>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "cmCTestBinPacker.h"
+#include "cmCTestResourceAllocator.h"
+
+struct ExpectedPackResult
+{
+ std::vector<int> SlotsNeeded;
+ std::map<std::string, cmCTestResourceAllocator::Resource> Resources;
+ bool ExpectedReturnValue;
+ std::vector<cmCTestBinPackerAllocation> ExpectedRoundRobinAllocations;
+ std::vector<cmCTestBinPackerAllocation> ExpectedBlockAllocations;
+};
+
+static const std::vector<ExpectedPackResult> expectedResults
+{
+ /* clang-format off */
+ {
+ { 2, 2, 2, 2 },
+ { { "0", { 4, 0 } }, { "1", { 4, 0 } }, { "2", { 4, 0 } },
+ { "3", { 4, 0 } } },
+ true,
+ {
+ { 0, 2, "0" },
+ { 1, 2, "1" },
+ { 2, 2, "2" },
+ { 3, 2, "3" },
+ },
+ {
+ { 0, 2, "0" },
+ { 1, 2, "0" },
+ { 2, 2, "1" },
+ { 3, 2, "1" },
+ },
+ },
+ {
+ { 2, 3, 2 },
+ { { "0", { 5, 0 } }, { "1", { 2, 0 } } },
+ true,
+ {
+ { 0, 2, "0" },
+ { 1, 3, "0" },
+ { 2, 2, "1" },
+ },
+ {
+ { 0, 2, "0" },
+ { 1, 3, "0" },
+ { 2, 2, "1" },
+ },
+ },
+ {
+ { 1, 2, 3 },
+ { { "0", { 1, 0 } }, { "1", { 2, 0 } }, { "2", { 2, 0 } } },
+ false,
+ { },
+ { },
+ },
+ {
+ { 48, 21, 31, 10, 40 },
+ { { "0", { 81, 0 } }, { "1", { 68, 0 } }, { "2", { 20, 0 } },
+ { "3", { 13, 0 } } },
+ true,
+ {
+ { 0, 48, "0" },
+ { 1, 21, "1" },
+ { 2, 31, "0" },
+ { 3, 10, "2" },
+ { 4, 40, "1" },
+ },
+ {
+ { 0, 48, "0" },
+ { 1, 21, "1" },
+ { 2, 31, "0" },
+ { 3, 10, "2" },
+ { 4, 40, "1" },
+ },
+ },
+ {
+ { 30, 31, 39, 67 },
+ { { "0", { 16, 0 } }, { "1", { 81, 0 } }, { "2", { 97, 0 } } },
+ true,
+ {
+ { 0, 30, "2" },
+ { 1, 31, "1" },
+ { 2, 39, "1" },
+ { 3, 67, "2" },
+ },
+ {
+ { 0, 30, "2" },
+ { 1, 31, "1" },
+ { 2, 39, "1" },
+ { 3, 67, "2" },
+ },
+ },
+ {
+ { 63, 47, 1, 9 },
+ { { "0", { 18, 0 } }, { "1", { 29, 0 } }, { "2", { 9, 0 } },
+ { "3", { 52, 0 } } },
+ false,
+ { },
+ { },
+ },
+ {
+ { 22, 29, 46, 85 },
+ { { "0", { 65, 0 } }, { "1", { 85, 0 } }, { "2", { 65, 0 } },
+ { "3", { 78, 0 } } },
+ true,
+ {
+ { 0, 22, "2" },
+ { 1, 29, "0" },
+ { 2, 46, "3" },
+ { 3, 85, "1" },
+ },
+ {
+ { 0, 22, "0" },
+ { 1, 29, "3" },
+ { 2, 46, "3" },
+ { 3, 85, "1" },
+ },
+ },
+ {
+ { 66, 11, 34, 21 },
+ { { "0", { 24, 0 } }, { "1", { 57, 0 } }, { "2", { 61, 0 } },
+ { "3", { 51, 0 } } },
+ false,
+ { },
+ { },
+ },
+ {
+ { 72, 65, 67, 45 },
+ { { "0", { 29, 0 } }, { "1", { 77, 0 } }, { "2", { 98, 0 } },
+ { "3", { 58, 0 } } },
+ false,
+ { },
+ { },
+ },
+ /*
+ * The following is a contrived attack on the bin-packing algorithm that
+ * causes it to execute with n! complexity, where n is the number of
+ * resources. This case is very unrepresentative of real-world usage, and
+ * has been documented but disabled. The bin-packing problem is NP-hard, and
+ * we may not be able to fix this case at all.
+ */
+#if 0
+ {
+ { 1000, 999, 998, 997, 996, 995, 994, 993, 992, 991, 19 },
+ { { "0", { 1000, 0 } }, { "1", { 1001, 0 } }, { "2", { 1002, 0 } },
+ { "3", { 1003, 0 } }, { "4", { 1004, 0 } }, { "5", { 1005, 0 } },
+ { "6", { 1006, 0 } }, { "7", { 1007, 0 } }, { "8", { 1008, 0 } },
+ { "9", { 1009, 0 } } },
+ false,
+ { },
+ { },
+ },
+#endif
+ /*
+ * These cases are more representative of real-world usage (the resource
+ * sizes are all the same.)
+ */
+ {
+ { 1000, 999, 998, 997, 996, 995, 994, 993, 992, 991, 10 },
+ { { "0", { 1000, 0 } }, { "1", { 1000, 0 } }, { "2", { 1000, 0 } },
+ { "3", { 1000, 0 } }, { "4", { 1000, 0 } }, { "5", { 1000, 0 } },
+ { "6", { 1000, 0 } }, { "7", { 1000, 0 } }, { "8", { 1000, 0 } },
+ { "9", { 1000, 0 } } },
+ false,
+ { },
+ { },
+ },
+ {
+ { 1000, 999, 998, 997, 996, 995, 994, 993, 992, 991, 9 },
+ { { "0", { 1000, 0 } }, { "1", { 1000, 0 } }, { "2", { 1000, 0 } },
+ { "3", { 1000, 0 } }, { "4", { 1000, 0 } }, { "5", { 1000, 0 } },
+ { "6", { 1000, 0 } }, { "7", { 1000, 0 } }, { "8", { 1000, 0 } },
+ { "9", { 1000, 0 } } },
+ true,
+ {
+ { 0, 1000, "0" },
+ { 1, 999, "1" },
+ { 2, 998, "2" },
+ { 3, 997, "3" },
+ { 4, 996, "4" },
+ { 5, 995, "5" },
+ { 6, 994, "6" },
+ { 7, 993, "7" },
+ { 8, 992, "8" },
+ { 9, 991, "9" },
+ { 10, 9, "9" },
+ },
+ {
+ { 0, 1000, "0" },
+ { 1, 999, "1" },
+ { 2, 998, "2" },
+ { 3, 997, "3" },
+ { 4, 996, "4" },
+ { 5, 995, "5" },
+ { 6, 994, "6" },
+ { 7, 993, "7" },
+ { 8, 992, "8" },
+ { 9, 991, "9" },
+ { 10, 9, "9" },
+ },
+ },
+ /* clang-format on */
+};
+
+struct AllocationComparison
+{
+ cmCTestBinPackerAllocation First;
+ cmCTestBinPackerAllocation Second;
+ bool Equal;
+};
+
+static const std::vector<AllocationComparison> comparisons{
+ /* clang-format off */
+ { { 0, 1, "0" }, { 0, 1, "0" }, true },
+ { { 0, 1, "0" }, { 1, 1, "0" }, false },
+ { { 0, 1, "0" }, { 0, 2, "0" }, false },
+ { { 0, 1, "0" }, { 0, 1, "1" }, false },
+ /* clang-format on */
+};
+
+bool TestExpectedPackResult(const ExpectedPackResult& expected)
+{
+ std::vector<cmCTestBinPackerAllocation> roundRobinAllocations;
+ roundRobinAllocations.reserve(expected.SlotsNeeded.size());
+ std::size_t index = 0;
+ for (auto const& n : expected.SlotsNeeded) {
+ roundRobinAllocations.push_back({ index++, n, "" });
+ }
+
+ bool roundRobinResult = cmAllocateCTestResourcesRoundRobin(
+ expected.Resources, roundRobinAllocations);
+ if (roundRobinResult != expected.ExpectedReturnValue) {
+ std::cout
+ << "cmAllocateCTestResourcesRoundRobin did not return expected value"
+ << std::endl;
+ return false;
+ }
+
+ if (roundRobinResult &&
+ roundRobinAllocations != expected.ExpectedRoundRobinAllocations) {
+ std::cout << "cmAllocateCTestResourcesRoundRobin did not return expected "
+ "allocations"
+ << std::endl;
+ return false;
+ }
+
+ std::vector<cmCTestBinPackerAllocation> blockAllocations;
+ blockAllocations.reserve(expected.SlotsNeeded.size());
+ index = 0;
+ for (auto const& n : expected.SlotsNeeded) {
+ blockAllocations.push_back({ index++, n, "" });
+ }
+
+ bool blockResult =
+ cmAllocateCTestResourcesBlock(expected.Resources, blockAllocations);
+ if (blockResult != expected.ExpectedReturnValue) {
+ std::cout << "cmAllocateCTestResourcesBlock did not return expected value"
+ << std::endl;
+ return false;
+ }
+
+ if (blockResult && blockAllocations != expected.ExpectedBlockAllocations) {
+ std::cout << "cmAllocateCTestResourcesBlock did not return expected"
+ " allocations"
+ << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+int testCTestBinPacker(int /*unused*/, char* /*unused*/ [])
+{
+ int retval = 0;
+
+ for (auto const& comparison : comparisons) {
+ if ((comparison.First == comparison.Second) != comparison.Equal) {
+ std::cout << "Comparison did not match expected" << std::endl;
+ retval = 1;
+ }
+ if ((comparison.First != comparison.Second) == comparison.Equal) {
+ std::cout << "Comparison did not match expected" << std::endl;
+ retval = 1;
+ }
+ }
+
+ for (auto const& expected : expectedResults) {
+ if (!TestExpectedPackResult(expected)) {
+ retval = 1;
+ }
+ }
+
+ return retval;
+}
diff --git a/Tests/CMakeLib/testCTestResourceAllocator.cxx b/Tests/CMakeLib/testCTestResourceAllocator.cxx
new file mode 100644
index 0000000..33d6b91
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceAllocator.cxx
@@ -0,0 +1,426 @@
+#include <iostream>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "cmCTestResourceAllocator.h"
+#include "cmCTestResourceSpec.h"
+
+static const cmCTestResourceSpec spec{ { {
+ /* clang-format off */
+ { "gpus", { { "0", 4 }, { "1", 8 }, { "2", 0 }, { "3", 8 } } },
+ /* clang-format on */
+} } };
+
+bool testInitializeFromResourceSpec()
+{
+ bool retval = true;
+
+ cmCTestResourceAllocator allocator;
+ allocator.InitializeFromResourceSpec(spec);
+
+ static const std::map<
+ std::string, std::map<std::string, cmCTestResourceAllocator::Resource>>
+ expected{
+ /* clang-format off */
+ { "gpus", {
+ { "0", { 4, 0 } },
+ { "1", { 8, 0 } },
+ { "2", { 0, 0 } },
+ { "3", { 8, 0 } },
+ } },
+ /* clang-format on */
+ };
+ if (allocator.GetResources() != expected) {
+ std::cout << "GetResources() did not return expected value\n";
+ retval = false;
+ }
+
+ return retval;
+}
+
+bool testAllocateResource()
+{
+ bool retval = true;
+
+ cmCTestResourceAllocator allocator;
+ allocator.InitializeFromResourceSpec(spec);
+
+ static const std::map<
+ std::string, std::map<std::string, cmCTestResourceAllocator::Resource>>
+ expected1{
+ /* clang-format off */
+ { "gpus", {
+ { "0", { 4, 2 } },
+ { "1", { 8, 0 } },
+ { "2", { 0, 0 } },
+ { "3", { 8, 0 } },
+ } },
+ /* clang-format on */
+ };
+ if (!allocator.AllocateResource("gpus", "0", 2)) {
+ std::cout
+ << "AllocateResource(\"gpus\", \"0\", 2) returned false, should be "
+ "true\n";
+ retval = false;
+ }
+ if (allocator.GetResources() != expected1) {
+ std::cout << "GetResources() did not return expected value\n";
+ retval = false;
+ }
+
+ static const std::map<
+ std::string, std::map<std::string, cmCTestResourceAllocator::Resource>>
+ expected2{
+ /* clang-format off */
+ { "gpus", {
+ { "0", { 4, 4 } },
+ { "1", { 8, 0 } },
+ { "2", { 0, 0 } },
+ { "3", { 8, 0 } },
+ } },
+ /* clang-format on */
+ };
+ if (!allocator.AllocateResource("gpus", "0", 2)) {
+ std::cout
+ << "AllocateResource(\"gpus\", \"0\", 2) returned false, should be "
+ "true\n";
+ retval = false;
+ }
+ if (allocator.GetResources() != expected2) {
+ std::cout << "GetResources() did not return expected value\n";
+ retval = false;
+ }
+
+ static const std::map<
+ std::string, std::map<std::string, cmCTestResourceAllocator::Resource>>
+ expected3{
+ /* clang-format off */
+ { "gpus", {
+ { "0", { 4, 4 } },
+ { "1", { 8, 0 } },
+ { "2", { 0, 0 } },
+ { "3", { 8, 0 } },
+ } },
+ /* clang-format on */
+ };
+ if (allocator.AllocateResource("gpus", "0", 1)) {
+ std::cout
+ << "AllocateResource(\"gpus\", \"0\", 1) returned true, should be "
+ "false\n";
+ retval = false;
+ }
+ if (allocator.GetResources() != expected3) {
+ std::cout << "GetResources() did not return expected value\n";
+ retval = false;
+ }
+
+ static const std::map<
+ std::string, std::map<std::string, cmCTestResourceAllocator::Resource>>
+ expected4{
+ /* clang-format off */
+ { "gpus", {
+ { "0", { 4, 4 } },
+ { "1", { 8, 7 } },
+ { "2", { 0, 0 } },
+ { "3", { 8, 0 } },
+ } },
+ /* clang-format on */
+ };
+ if (!allocator.AllocateResource("gpus", "1", 7)) {
+ std::cout
+ << "AllocateResource(\"gpus\", \"1\", 7) returned false, should be "
+ "true\n";
+ retval = false;
+ }
+ if (allocator.AllocateResource("gpus", "1", 2)) {
+ std::cout
+ << "AllocateResource(\"gpus\", \"1\", 2) returned true, should be "
+ "false\n";
+ retval = false;
+ }
+ if (allocator.GetResources() != expected4) {
+ std::cout << "GetResources() did not return expected value\n";
+ retval = false;
+ }
+
+ static const std::map<
+ std::string, std::map<std::string, cmCTestResourceAllocator::Resource>>
+ expected5{
+ /* clang-format off */
+ { "gpus", {
+ { "0", { 4, 4 } },
+ { "1", { 8, 7 } },
+ { "2", { 0, 0 } },
+ { "3", { 8, 0 } },
+ } },
+ /* clang-format on */
+ };
+ if (allocator.AllocateResource("gpus", "2", 1)) {
+ std::cout
+ << "AllocateResource(\"gpus\", \"2\", 1) returned true, should be "
+ "false\n";
+ retval = false;
+ }
+ if (allocator.GetResources() != expected5) {
+ std::cout << "GetResources() did not return expected value\n";
+ retval = false;
+ }
+
+ static const std::map<
+ std::string, std::map<std::string, cmCTestResourceAllocator::Resource>>
+ expected6{
+ /* clang-format off */
+ { "gpus", {
+ { "0", { 4, 4 } },
+ { "1", { 8, 7 } },
+ { "2", { 0, 0 } },
+ { "3", { 8, 0 } },
+ } },
+ /* clang-format on */
+ };
+ if (allocator.AllocateResource("gpus", "4", 1)) {
+ std::cout
+ << "AllocateResource(\"gpus\", \"4\", 1) returned true, should be "
+ "false\n";
+ retval = false;
+ }
+ if (allocator.GetResources() != expected6) {
+ std::cout << "GetResources() did not return expected value\n";
+ retval = false;
+ }
+
+ static const std::map<
+ std::string, std::map<std::string, cmCTestResourceAllocator::Resource>>
+ expected7{
+ /* clang-format off */
+ { "gpus", {
+ { "0", { 4, 4 } },
+ { "1", { 8, 7 } },
+ { "2", { 0, 0 } },
+ { "3", { 8, 0 } },
+ } },
+ /* clang-format on */
+ };
+ if (allocator.AllocateResource("threads", "0", 1)) {
+ std::cout
+ << "AllocateResource(\"threads\", \"0\", 1) returned true, should be"
+ " false\n";
+ retval = false;
+ }
+ if (allocator.GetResources() != expected7) {
+ std::cout << "GetResources() did not return expected value\n";
+ retval = false;
+ }
+
+ return retval;
+}
+
+bool testDeallocateResource()
+{
+ bool retval = true;
+
+ cmCTestResourceAllocator allocator;
+ allocator.InitializeFromResourceSpec(spec);
+
+ static const std::map<
+ std::string, std::map<std::string, cmCTestResourceAllocator::Resource>>
+ expected1{
+ /* clang-format off */
+ { "gpus", {
+ { "0", { 4, 1 } },
+ { "1", { 8, 0 } },
+ { "2", { 0, 0 } },
+ { "3", { 8, 0 } },
+ } },
+ /* clang-format on */
+ };
+ if (!allocator.AllocateResource("gpus", "0", 2)) {
+ std::cout
+ << "AllocateResource(\"gpus\", \"0\", 2) returned false, should be "
+ "true\n";
+ retval = false;
+ }
+ if (!allocator.DeallocateResource("gpus", "0", 1)) {
+ std::cout
+ << "DeallocateResource(\"gpus\", \"0\", 1) returned false, should be"
+ " true\n";
+ retval = false;
+ }
+ if (allocator.GetResources() != expected1) {
+ std::cout << "GetResources() did not return expected value\n";
+ retval = false;
+ }
+
+ static const std::map<
+ std::string, std::map<std::string, cmCTestResourceAllocator::Resource>>
+ expected2{
+ /* clang-format off */
+ { "gpus", {
+ { "0", { 4, 1 } },
+ { "1", { 8, 0 } },
+ { "2", { 0, 0 } },
+ { "3", { 8, 0 } },
+ } },
+ /* clang-format on */
+ };
+ if (allocator.DeallocateResource("gpus", "0", 2)) {
+ std::cout
+ << "DeallocateResource(\"gpus\", \"0\", 2) returned true, should be"
+ " false\n";
+ retval = false;
+ }
+ if (allocator.GetResources() != expected2) {
+ std::cout << "GetResources() did not return expected value\n";
+ retval = false;
+ }
+
+ static const std::map<
+ std::string, std::map<std::string, cmCTestResourceAllocator::Resource>>
+ expected3{
+ /* clang-format off */
+ { "gpus", {
+ { "0", { 4, 0 } },
+ { "1", { 8, 0 } },
+ { "2", { 0, 0 } },
+ { "3", { 8, 0 } },
+ } },
+ /* clang-format on */
+ };
+ if (!allocator.DeallocateResource("gpus", "0", 1)) {
+ std::cout
+ << "DeallocateResource(\"gpus\", \"0\", 1) returned false, should be"
+ " true\n";
+ retval = false;
+ }
+ if (allocator.GetResources() != expected3) {
+ std::cout << "GetResources() did not return expected value\n";
+ retval = false;
+ }
+
+ static const std::map<
+ std::string, std::map<std::string, cmCTestResourceAllocator::Resource>>
+ expected4{
+ /* clang-format off */
+ { "gpus", {
+ { "0", { 4, 0 } },
+ { "1", { 8, 0 } },
+ { "2", { 0, 0 } },
+ { "3", { 8, 0 } },
+ } },
+ /* clang-format on */
+ };
+ if (allocator.DeallocateResource("gpus", "0", 1)) {
+ std::cout
+ << "DeallocateResource(\"gpus\", \"0\", 1) returned true, should be"
+ " false\n";
+ retval = false;
+ }
+ if (allocator.GetResources() != expected4) {
+ std::cout << "GetResources() did not return expected value\n";
+ retval = false;
+ }
+
+ static const std::map<
+ std::string, std::map<std::string, cmCTestResourceAllocator::Resource>>
+ expected5{
+ /* clang-format off */
+ { "gpus", {
+ { "0", { 4, 0 } },
+ { "1", { 8, 0 } },
+ { "2", { 0, 0 } },
+ { "3", { 8, 0 } },
+ } },
+ /* clang-format on */
+ };
+ if (allocator.DeallocateResource("gpus", "4", 1)) {
+ std::cout
+ << "DeallocateResource(\"gpus\", \"4\", 1) returned true, should be"
+ " false\n";
+ retval = false;
+ }
+ if (allocator.GetResources() != expected5) {
+ std::cout << "GetResources() did not return expected value\n";
+ retval = false;
+ }
+
+ static const std::map<
+ std::string, std::map<std::string, cmCTestResourceAllocator::Resource>>
+ expected6{
+ /* clang-format off */
+ { "gpus", {
+ { "0", { 4, 0 } },
+ { "1", { 8, 0 } },
+ { "2", { 0, 0 } },
+ { "3", { 8, 0 } },
+ } },
+ /* clang-format on */
+ };
+ if (allocator.DeallocateResource("threads", "0", 1)) {
+ std::cout
+ << "DeallocateResource(\"threads\", \"0\", 1) returned true, should be"
+ " false\n";
+ retval = false;
+ }
+ if (allocator.GetResources() != expected6) {
+ std::cout << "GetResources() did not return expected value\n";
+ retval = false;
+ }
+
+ return retval;
+}
+
+bool testResourceFree()
+{
+ bool retval = true;
+
+ const cmCTestResourceAllocator::Resource r1{ 5, 0 };
+ if (r1.Free() != 5) {
+ std::cout << "cmCTestResourceAllocator::Resource::Free() did not return "
+ "expected value for { 5, 0 }\n";
+ retval = false;
+ }
+
+ const cmCTestResourceAllocator::Resource r2{ 3, 2 };
+ if (r2.Free() != 1) {
+ std::cout << "cmCTestResourceAllocator::Resource::Free() did not return "
+ "expected value for { 3, 2 }\n";
+ retval = false;
+ }
+
+ const cmCTestResourceAllocator::Resource r3{ 4, 4 };
+ if (r3.Free() != 0) {
+ std::cout << "cmCTestResourceAllocator::Resource::Free() did not return "
+ "expected value for { 4, 4 }\n";
+ retval = false;
+ }
+
+ return retval;
+}
+
+int testCTestResourceAllocator(int, char** const)
+{
+ int retval = 0;
+
+ if (!testInitializeFromResourceSpec()) {
+ std::cout << "in testInitializeFromResourceSpec()\n";
+ retval = -1;
+ }
+
+ if (!testAllocateResource()) {
+ std::cout << "in testAllocateResource()\n";
+ retval = -1;
+ }
+
+ if (!testDeallocateResource()) {
+ std::cout << "in testDeallocateResource()\n";
+ retval = -1;
+ }
+
+ if (!testResourceFree()) {
+ std::cout << "in testResourceFree()\n";
+ retval = -1;
+ }
+
+ return retval;
+}
diff --git a/Tests/CMakeLib/testCTestResourceGroups.cxx b/Tests/CMakeLib/testCTestResourceGroups.cxx
new file mode 100644
index 0000000..c3532a6
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceGroups.cxx
@@ -0,0 +1,141 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "cmCTestTestHandler.h"
+
+struct ExpectedParseResult
+{
+ std::string String;
+ bool ExpectedReturnValue;
+ std::vector<std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>
+ ExpectedValue;
+};
+
+static const std::vector<ExpectedParseResult> expectedResults{
+ /* clang-format off */
+ { "threads:2", true, {
+ { { "threads", 2, 1 } },
+ } },
+ { "3,threads:2", true, {
+ { { "threads", 2, 1 } },
+ { { "threads", 2, 1 } },
+ { { "threads", 2, 1 } },
+ } },
+ { "3,threads:2,gpus:4", true, {
+ { { "threads", 2, 1 }, { "gpus", 4, 1 } },
+ { { "threads", 2, 1 }, { "gpus", 4, 1 } },
+ { { "threads", 2, 1 }, { "gpus", 4, 1 } },
+ } },
+ { "2,threads:2;gpus:4", true, {
+ { { "threads", 2, 1 } },
+ { { "threads", 2, 1 } },
+ { { "gpus", 4, 1 } },
+ } },
+ { "threads:2;2,gpus:4", true, {
+ { { "threads", 2, 1 } },
+ { { "gpus", 4, 1 } },
+ { { "gpus", 4, 1 } },
+ } },
+ { "threads:2;gpus:4", true, {
+ { { "threads", 2, 1 } },
+ { { "gpus", 4, 1 } },
+ } },
+ { "1,threads:2;0,gpus:4", true, {
+ { { "threads", 2, 1 } },
+ } },
+ { "1,_:1", true, {
+ { { "_", 1, 1 } },
+ } },
+ { "1,a:1", true, {
+ { { "a", 1, 1 } },
+ } },
+ { "2", true, {
+ {},
+ {},
+ } },
+ { "1;2,threads:1", true, {
+ {},
+ { { "threads", 1, 1 } },
+ { { "threads", 1, 1 } },
+ } },
+ { "1,,threads:1", true, {
+ { { "threads", 1, 1 } },
+ } },
+ { ";1,threads:1", true, {
+ { { "threads", 1, 1 } },
+ } },
+ { "1,threads:1;", true, {
+ { { "threads", 1, 1 } },
+ } },
+ { "1,threads:1,", true, {
+ { { "threads", 1, 1 } },
+ } },
+ { "threads:1,threads:1", true, {
+ { { "threads", 1, 1 }, { "threads", 1, 1 } },
+ } },
+ { "threads:1;;threads:2", true, {
+ { { "threads", 1, 1 } },
+ { { "threads", 2, 1 } },
+ } },
+ { "1,", true, {
+ {},
+ } },
+ { ";", true, {} },
+ { "", true, {} },
+ { ",", false, {} },
+ { "1,0:1", false, {} },
+ { "1,A:1", false, {} },
+ { "1,a-b:1", false, {} },
+ { "invalid", false, {} },
+ { ",1,invalid:1", false, {} },
+ { "1,1", false, {} },
+ { "-1,invalid:1", false, {} },
+ { "1,invalid:*", false, {} },
+ { "1,invalid:-1", false, {} },
+ { "1,invalid:-", false, {} },
+ { "1,invalid:ab2", false, {} },
+ { "1,invalid :2", false, {} },
+ { "1, invalid:2", false, {} },
+ { "1,invalid:ab", false, {} },
+ /* clang-format on */
+};
+
+bool TestExpectedParseResult(const ExpectedParseResult& expected)
+{
+ std::vector<std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>
+ result;
+ bool retval;
+ if ((retval = cmCTestTestHandler::ParseResourceGroupsProperty(
+ expected.String, result)) != expected.ExpectedReturnValue) {
+ std::cout << "ParseResourceGroupsProperty(\"" << expected.String
+ << "\") returned " << retval << ", should be "
+ << expected.ExpectedReturnValue << std::endl;
+ return false;
+ }
+
+ if (result != expected.ExpectedValue) {
+ std::cout << "ParseResourceGroupsProperty(\"" << expected.String
+ << "\") did not yield expected set of resource groups"
+ << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+int testCTestResourceGroups(int /*unused*/, char* /*unused*/ [])
+{
+ int retval = 0;
+
+ for (auto const& expected : expectedResults) {
+ if (!TestExpectedParseResult(expected)) {
+ retval = 1;
+ }
+ }
+
+ return retval;
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec.cxx b/Tests/CMakeLib/testCTestResourceSpec.cxx
new file mode 100644
index 0000000..b49f8ff
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec.cxx
@@ -0,0 +1,119 @@
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "cmCTestResourceSpec.h"
+
+struct ExpectedSpec
+{
+ std::string Path;
+ cmCTestResourceSpec::ReadFileResult ParseResult;
+ cmCTestResourceSpec Expected;
+};
+
+static const std::vector<ExpectedSpec> expectedResourceSpecs = {
+ { "spec1.json",
+ cmCTestResourceSpec::ReadFileResult::READ_OK,
+ { { {
+ { "gpus",
+ {
+ { "2", 4 },
+ { "e", 1 },
+ } },
+ { "threads", {} },
+ } } } },
+ { "spec2.json", cmCTestResourceSpec::ReadFileResult::READ_OK, {} },
+ { "spec3.json",
+ cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC,
+ {} },
+ { "spec4.json",
+ cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC,
+ {} },
+ { "spec5.json",
+ cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC,
+ {} },
+ { "spec6.json",
+ cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC,
+ {} },
+ { "spec7.json",
+ cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE_TYPE,
+ {} },
+ { "spec8.json", cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE, {} },
+ { "spec9.json", cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE, {} },
+ { "spec10.json", cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE, {} },
+ { "spec11.json", cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE, {} },
+ { "spec12.json", cmCTestResourceSpec::ReadFileResult::INVALID_ROOT, {} },
+ { "spec13.json", cmCTestResourceSpec::ReadFileResult::JSON_PARSE_ERROR, {} },
+ { "spec14.json", cmCTestResourceSpec::ReadFileResult::READ_OK, {} },
+ { "spec15.json", cmCTestResourceSpec::ReadFileResult::READ_OK, {} },
+ { "spec16.json", cmCTestResourceSpec::ReadFileResult::READ_OK, {} },
+ { "spec17.json", cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE, {} },
+ { "spec18.json", cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE, {} },
+ { "spec19.json", cmCTestResourceSpec::ReadFileResult::INVALID_VERSION, {} },
+ { "spec20.json", cmCTestResourceSpec::ReadFileResult::READ_OK, {} },
+ { "spec21.json", cmCTestResourceSpec::ReadFileResult::INVALID_VERSION, {} },
+ { "spec22.json", cmCTestResourceSpec::ReadFileResult::INVALID_VERSION, {} },
+ { "spec23.json", cmCTestResourceSpec::ReadFileResult::INVALID_VERSION, {} },
+ { "spec24.json", cmCTestResourceSpec::ReadFileResult::INVALID_VERSION, {} },
+ { "spec25.json",
+ cmCTestResourceSpec::ReadFileResult::UNSUPPORTED_VERSION,
+ {} },
+ { "spec26.json",
+ cmCTestResourceSpec::ReadFileResult::UNSUPPORTED_VERSION,
+ {} },
+ { "spec27.json", cmCTestResourceSpec::ReadFileResult::INVALID_VERSION, {} },
+ { "spec28.json", cmCTestResourceSpec::ReadFileResult::INVALID_VERSION, {} },
+ { "spec29.json", cmCTestResourceSpec::ReadFileResult::INVALID_VERSION, {} },
+ { "spec30.json", cmCTestResourceSpec::ReadFileResult::INVALID_VERSION, {} },
+ { "spec31.json", cmCTestResourceSpec::ReadFileResult::INVALID_VERSION, {} },
+ { "spec32.json", cmCTestResourceSpec::ReadFileResult::INVALID_VERSION, {} },
+ { "spec33.json", cmCTestResourceSpec::ReadFileResult::INVALID_VERSION, {} },
+ { "spec34.json", cmCTestResourceSpec::ReadFileResult::INVALID_VERSION, {} },
+ { "spec35.json", cmCTestResourceSpec::ReadFileResult::INVALID_VERSION, {} },
+ { "spec36.json", cmCTestResourceSpec::ReadFileResult::NO_VERSION, {} },
+ { "noexist.json", cmCTestResourceSpec::ReadFileResult::FILE_NOT_FOUND, {} },
+};
+
+static bool testSpec(const std::string& path,
+ cmCTestResourceSpec::ReadFileResult expectedResult,
+ const cmCTestResourceSpec& expected)
+{
+ cmCTestResourceSpec actual;
+ auto result = actual.ReadFromJSONFile(path);
+ if (result != expectedResult) {
+ std::cout << "ReadFromJSONFile(\"" << path << "\") returned \""
+ << cmCTestResourceSpec::ResultToString(result)
+ << "\", should be \""
+ << cmCTestResourceSpec::ResultToString(expectedResult) << "\""
+ << std::endl;
+ return false;
+ }
+
+ if (actual != expected) {
+ std::cout << "ReadFromJSONFile(\"" << path
+ << "\") did not give expected spec" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+int testCTestResourceSpec(int argc, char** const argv)
+{
+ if (argc < 2) {
+ std::cout << "Invalid arguments.\n";
+ return -1;
+ }
+
+ int retval = 0;
+ for (auto const& spec : expectedResourceSpecs) {
+ std::string path = argv[1];
+ path += "/testCTestResourceSpec_data/";
+ path += spec.Path;
+ if (!testSpec(path, spec.ParseResult, spec.Expected)) {
+ retval = -1;
+ }
+ }
+
+ return retval;
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec1.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec1.json
new file mode 100644
index 0000000..b01aa6b
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec1.json
@@ -0,0 +1,27 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ {
+ "gpus": [
+ {
+ "id": "2",
+ "slots": 4
+ },
+ {
+ "id": "e"
+ }
+ ],
+ ".reserved": [
+ {
+ "id": "a",
+ "slots": 3
+ }
+ ],
+ "threads": [
+ ]
+ }
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec10.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec10.json
new file mode 100644
index 0000000..8764907
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec10.json
@@ -0,0 +1,15 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ {
+ "gpus": [
+ {
+ "id": 4
+ }
+ ]
+ }
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec11.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec11.json
new file mode 100644
index 0000000..7551ea2
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec11.json
@@ -0,0 +1,16 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ {
+ "gpus": [
+ {
+ "id": "4",
+ "slots": "giraffe"
+ }
+ ]
+ }
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec12.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec12.json
new file mode 100644
index 0000000..fe51488
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec12.json
@@ -0,0 +1 @@
+[]
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec13.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec13.json
new file mode 100644
index 0000000..6b7a9f4
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec13.json
@@ -0,0 +1 @@
+not json
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec14.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec14.json
new file mode 100644
index 0000000..83f480c
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec14.json
@@ -0,0 +1,12 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ {
+ "0": [
+ ]
+ }
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec15.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec15.json
new file mode 100644
index 0000000..10fe2e3
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec15.json
@@ -0,0 +1,12 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ {
+ "-": [
+ ]
+ }
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec16.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec16.json
new file mode 100644
index 0000000..8546759
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec16.json
@@ -0,0 +1,12 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ {
+ "A": [
+ ]
+ }
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec17.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec17.json
new file mode 100644
index 0000000..e4cdfc9
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec17.json
@@ -0,0 +1,15 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ {
+ "gpus": [
+ {
+ "id": "A"
+ }
+ ]
+ }
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec18.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec18.json
new file mode 100644
index 0000000..26a7c70
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec18.json
@@ -0,0 +1,15 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ {
+ "gpus": [
+ {
+ "id": "-"
+ }
+ ]
+ }
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec19.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec19.json
new file mode 100644
index 0000000..3067f0c
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec19.json
@@ -0,0 +1,5 @@
+{
+ "version": 1,
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec2.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec2.json
new file mode 100644
index 0000000..df49390
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec2.json
@@ -0,0 +1,8 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec20.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec20.json
new file mode 100644
index 0000000..df49390
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec20.json
@@ -0,0 +1,8 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec21.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec21.json
new file mode 100644
index 0000000..7459ff2
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec21.json
@@ -0,0 +1,5 @@
+{
+ "version": [1, 0],
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec22.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec22.json
new file mode 100644
index 0000000..23c57d8
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec22.json
@@ -0,0 +1,5 @@
+{
+ "version": 2,
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec23.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec23.json
new file mode 100644
index 0000000..a3d0a27
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec23.json
@@ -0,0 +1,7 @@
+{
+ "version": {
+ "major": 1
+ },
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec24.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec24.json
new file mode 100644
index 0000000..d5f6b08
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec24.json
@@ -0,0 +1,7 @@
+{
+ "version": {
+ "minor": 0
+ },
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec25.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec25.json
new file mode 100644
index 0000000..914da4b
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec25.json
@@ -0,0 +1,8 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 1
+ },
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec26.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec26.json
new file mode 100644
index 0000000..c06de22
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec26.json
@@ -0,0 +1,8 @@
+{
+ "version": {
+ "major": 2,
+ "minor": 0
+ },
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec27.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec27.json
new file mode 100644
index 0000000..9e2b6c3
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec27.json
@@ -0,0 +1,8 @@
+{
+ "version": {
+ "major": "1",
+ "minor": 0
+ },
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec28.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec28.json
new file mode 100644
index 0000000..ce3b76a
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec28.json
@@ -0,0 +1,8 @@
+{
+ "version": {
+ "major": 1,
+ "minor": "0"
+ },
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec29.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec29.json
new file mode 100644
index 0000000..58afd2b
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec29.json
@@ -0,0 +1,5 @@
+{
+ "version": [1, 0, 0],
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec3.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec3.json
new file mode 100644
index 0000000..2f1045f
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec3.json
@@ -0,0 +1,12 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ {
+ },
+ {
+ }
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec30.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec30.json
new file mode 100644
index 0000000..9e13ff0
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec30.json
@@ -0,0 +1,5 @@
+{
+ "version": [1],
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec31.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec31.json
new file mode 100644
index 0000000..c0ef7f4
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec31.json
@@ -0,0 +1,5 @@
+{
+ "version": [1, 1],
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec32.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec32.json
new file mode 100644
index 0000000..abe977e
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec32.json
@@ -0,0 +1,5 @@
+{
+ "version": [2, 0],
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec33.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec33.json
new file mode 100644
index 0000000..c6ca749
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec33.json
@@ -0,0 +1,5 @@
+{
+ "version": ["1", 0],
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec34.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec34.json
new file mode 100644
index 0000000..be258f1
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec34.json
@@ -0,0 +1,5 @@
+{
+ "version": [1, "0"],
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec35.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec35.json
new file mode 100644
index 0000000..137648c
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec35.json
@@ -0,0 +1,5 @@
+{
+ "version": "1",
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec36.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec36.json
new file mode 100644
index 0000000..6175b1a
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec36.json
@@ -0,0 +1,4 @@
+{
+ "local": [
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec4.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec4.json
new file mode 100644
index 0000000..17349bd
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec4.json
@@ -0,0 +1,8 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": {
+ }
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec5.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec5.json
new file mode 100644
index 0000000..f6e6cb4
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec5.json
@@ -0,0 +1,6 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ }
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec6.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec6.json
new file mode 100644
index 0000000..eb8b14c
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec6.json
@@ -0,0 +1,9 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ []
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec7.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec7.json
new file mode 100644
index 0000000..0447981
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec7.json
@@ -0,0 +1,12 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ {
+ "gpus": {
+ }
+ }
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec8.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec8.json
new file mode 100644
index 0000000..ee7a9c2
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec8.json
@@ -0,0 +1,13 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ {
+ "gpus": [
+ []
+ ]
+ }
+ ]
+}
diff --git a/Tests/CMakeLib/testCTestResourceSpec_data/spec9.json b/Tests/CMakeLib/testCTestResourceSpec_data/spec9.json
new file mode 100644
index 0000000..ae1117b
--- /dev/null
+++ b/Tests/CMakeLib/testCTestResourceSpec_data/spec9.json
@@ -0,0 +1,14 @@
+{
+ "version": {
+ "major": 1,
+ "minor": 0
+ },
+ "local": [
+ {
+ "gpus": [
+ {
+ }
+ ]
+ }
+ ]
+}
diff --git a/Tests/CMakeLib/testEncoding.cxx b/Tests/CMakeLib/testEncoding.cxx
new file mode 100644
index 0000000..4936898
--- /dev/null
+++ b/Tests/CMakeLib/testEncoding.cxx
@@ -0,0 +1,52 @@
+#include <iostream>
+#include <string>
+
+#include "cmsys/FStream.hxx"
+
+#ifdef _WIN32
+# include "cmsys/ConsoleBuf.hxx"
+#endif
+
+#ifdef _WIN32
+void setEncoding(cmsys::ConsoleBuf::Manager& buf, UINT codepage)
+{
+ cmsys::ConsoleBuf* cb = buf.GetConsoleBuf();
+ if (cb) {
+ cb->input_pipe_codepage = codepage;
+ cb->output_pipe_codepage = codepage;
+ cb->input_file_codepage = codepage;
+ cb->output_file_codepage = codepage;
+ cb->activateCodepageChange();
+ }
+}
+#endif
+
+int main(int argc, char* argv[])
+{
+#ifdef _WIN32
+ cmsys::ConsoleBuf::Manager consoleOut(std::cout);
+#endif
+ if (argc <= 2) {
+ std::cout << "Usage: testEncoding <encoding> <file>" << std::endl;
+ return 1;
+ }
+ const std::string encoding(argv[1]);
+#ifdef _WIN32
+ if ((encoding == "UTF8") || (encoding == "UTF-8")) {
+ setEncoding(consoleOut, CP_UTF8);
+ } else if (encoding == "ANSI") {
+ setEncoding(consoleOut, CP_ACP);
+ } else if (encoding == "OEM") {
+ setEncoding(consoleOut, CP_OEMCP);
+ } // else AUTO
+#endif
+ cmsys::ifstream file(argv[2]);
+ if (!file.is_open()) {
+ std::cout << "Failed to open file: " << argv[2] << std::endl;
+ return 2;
+ }
+ std::string text((std::istreambuf_iterator<char>(file)),
+ std::istreambuf_iterator<char>());
+ std::cout << text;
+ return 0;
+}
diff --git a/Tests/CMakeLib/testFindPackageCommand.cxx b/Tests/CMakeLib/testFindPackageCommand.cxx
new file mode 100644
index 0000000..bfd429f
--- /dev/null
+++ b/Tests/CMakeLib/testFindPackageCommand.cxx
@@ -0,0 +1,71 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <cmConfigure.h> // IWYU pragma: keep
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "cmFindPackageCommand.h"
+
+#define cmPassed(m) std::cout << "Passed: " << (m) << "\n"
+#define cmFailed(m) \
+ std::cout << "FAILED: " << (m) << "\n"; \
+ failed = 1
+
+int testFindPackageCommand(int /*unused*/, char* /*unused*/ [])
+{
+ int failed = 0;
+
+ // ----------------------------------------------------------------------
+ // Test cmFindPackage::Sort
+ std::vector<std::string> testString;
+ testString.push_back("lib-0.0");
+ testString.push_back("lib-1.2");
+ testString.push_back("lib-2.0");
+ testString.push_back("lib-19.0.1");
+ testString.push_back("lib-20.01.1");
+ testString.push_back("lib-20.2.2a");
+
+ cmFindPackageCommand::Sort(testString.begin(), testString.end(),
+ cmFindPackageCommand::Natural,
+ cmFindPackageCommand::Asc);
+ if (!(testString[0] == "lib-0.0" && testString[1] == "lib-1.2" &&
+ testString[2] == "lib-2.0" && testString[3] == "lib-19.0.1" &&
+ testString[4] == "lib-20.01.1" && testString[5] == "lib-20.2.2a")) {
+ cmFailed("cmSystemTools::Sort fail with Natural ASC");
+ }
+
+ cmFindPackageCommand::Sort(testString.begin(), testString.end(),
+ cmFindPackageCommand::Natural,
+ cmFindPackageCommand::Dec);
+ if (!(testString[5] == "lib-0.0" && testString[4] == "lib-1.2" &&
+ testString[3] == "lib-2.0" && testString[2] == "lib-19.0.1" &&
+ testString[1] == "lib-20.01.1" && testString[0] == "lib-20.2.2a")) {
+ cmFailed("cmSystemTools::Sort fail with Natural ASC");
+ }
+
+ cmFindPackageCommand::Sort(testString.begin(), testString.end(),
+ cmFindPackageCommand::Name_order,
+ cmFindPackageCommand::Dec);
+ if (!(testString[5] == "lib-0.0" && testString[4] == "lib-1.2" &&
+ testString[3] == "lib-19.0.1" && testString[2] == "lib-2.0" &&
+ testString[1] == "lib-20.01.1" && testString[0] == "lib-20.2.2a")) {
+ cmFailed("cmSystemTools::Sort fail with Name DEC");
+ }
+
+ cmFindPackageCommand::Sort(testString.begin(), testString.end(),
+ cmFindPackageCommand::Name_order,
+ cmFindPackageCommand::Asc);
+ if (!(testString[0] == "lib-0.0" && testString[1] == "lib-1.2" &&
+ testString[2] == "lib-19.0.1" && testString[3] == "lib-2.0" &&
+ testString[4] == "lib-20.01.1" && testString[5] == "lib-20.2.2a")) {
+ cmFailed("cmSystemTools::Sort fail with Natural ASC");
+ }
+
+ if (!failed) {
+ cmPassed("cmSystemTools::Sort working");
+ }
+ return failed;
+}
diff --git a/Tests/CMakeLib/testGccDepfileReader.cxx b/Tests/CMakeLib/testGccDepfileReader.cxx
new file mode 100644
index 0000000..d46e8f3
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader.cxx
@@ -0,0 +1,142 @@
+#include <cstddef> // IWYU pragma: keep
+#include <iostream>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmGccDepfileReader.h"
+#include "cmGccDepfileReaderTypes.h" // for cmGccDepfileContent, cmGccStyle...
+#include "cmSystemTools.h"
+
+namespace {
+
+cmGccDepfileContent readPlainDepfile(const char* filePath)
+{
+ cmGccDepfileContent result;
+ cmsys::ifstream is(filePath);
+ if (!is.is_open())
+ return result;
+ std::string line;
+
+ cmGccStyleDependency dep;
+ bool readingRules = true;
+ while (cmSystemTools::GetLineFromStream(is, line)) {
+ if (line == "--RULES--") {
+ if (!dep.rules.empty()) {
+ result.push_back(std::move(dep));
+ dep = cmGccStyleDependency();
+ }
+ readingRules = true;
+ } else if (line == "--DEPENDENCIES--") {
+ readingRules = false;
+ } else {
+ std::vector<std::string>& dst = readingRules ? dep.rules : dep.paths;
+ dst.push_back(std::move(line));
+ line = std::string();
+ }
+ }
+
+ if (!dep.rules.empty()) {
+ result.push_back(std::move(dep));
+ }
+
+ return result;
+}
+
+bool compare(const std::vector<std::string>& actual,
+ const std::vector<std::string>& expected, const char* msg)
+{
+ if (actual.size() != expected.size()) {
+ std::cerr << msg << "expected " << expected.size() << " entries."
+ << std::endl
+ << "Actual number of entries: " << actual.size() << std::endl;
+ return false;
+ }
+ for (std::size_t i = 0; i < actual.size(); ++i) {
+ if (actual[i] != expected[i]) {
+ std::cerr << msg << std::endl
+ << "expected: " << expected[i] << std::endl
+ << "actual: " << actual[i] << std::endl;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool compare(const cmGccDepfileContent& actual,
+ const cmGccDepfileContent& expected)
+{
+ if (actual.size() != expected.size()) {
+ std::cerr << "Expected " << expected.size() << " entries." << std::endl
+ << "Actual number of entries: " << actual.size() << std::endl;
+ return false;
+ }
+ for (std::size_t i = 0; i < actual.size(); ++i) {
+ if (!compare(actual[i].rules, expected[i].rules, "Rules differ: ") ||
+ !compare(actual[i].paths, expected[i].paths, "Paths differ: ")) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void dump(const char* label, const cmGccDepfileContent& dfc)
+{
+ std::cerr << label << std::endl;
+ for (const auto& entry : dfc) {
+ auto rit = entry.rules.cbegin();
+ if (rit != entry.rules.cend()) {
+ std::cerr << *rit;
+ for (++rit; rit != entry.rules.cend(); ++rit) {
+ std::cerr << " " << *rit;
+ }
+ std::cerr << ": " << std::endl;
+ }
+ for (const auto& path : entry.paths) {
+ std::cerr << " " << path << std::endl;
+ }
+ }
+}
+
+} // anonymous namespace
+
+int testGccDepfileReader(int argc, char* argv[])
+{
+ if (argc < 2) {
+ std::cout << "Invalid arguments.\n";
+ return -1;
+ }
+
+ std::string dataDirPath = argv[1];
+ dataDirPath += "/testGccDepfileReader_data";
+ const int numberOfTestFiles = 7; // 6th file doesn't exist
+ for (int i = 1; i <= numberOfTestFiles; ++i) {
+ const std::string base = dataDirPath + "/deps" + std::to_string(i);
+ const std::string depfile = base + ".d";
+ const std::string plainDepfile = base + ".txt";
+ std::cout << "Comparing " << base << " with " << plainDepfile << std::endl;
+ const auto actual = cmReadGccDepfile(depfile.c_str());
+ if (cmSystemTools::FileExists(plainDepfile)) {
+ if (!actual) {
+ std::cerr << "Reading " << depfile << " should have succeeded\n";
+ return 1;
+ }
+ const auto expected = readPlainDepfile(plainDepfile.c_str());
+ if (!compare(*actual, expected)) {
+ dump("actual", *actual);
+ dump("expected", expected);
+ return 1;
+ }
+ } else if (actual) {
+ std::cerr << "Reading " << depfile << " should have failed\n";
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps1.d b/Tests/CMakeLib/testGccDepfileReader_data/deps1.d
new file mode 100644
index 0000000..9e34863
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps1.d
@@ -0,0 +1,20 @@
+main.o: main.cpp /usr/include/stdc-predef.h /usr/include/stdio.h \
+ /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \
+ /usr/include/x86_64-linux-gnu/bits/wordsize.h \
+ /usr/include/x86_64-linux-gnu/bits/long-double.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
+ /usr/lib/gcc/x86_64-linux-gnu/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-linux-gnu/8/include/stdarg.h \
+ /usr/include/x86_64-linux-gnu/bits/types.h \
+ /usr/include/x86_64-linux-gnu/bits/typesizes.h \
+ /usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h \
+ /usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h \
+ /usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h \
+ /usr/include/x86_64-linux-gnu/bits/types/__FILE.h \
+ /usr/include/x86_64-linux-gnu/bits/types/FILE.h \
+ /usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h \
+ /usr/include/x86_64-linux-gnu/bits/types/cookie_io_functions_t.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps1.txt b/Tests/CMakeLib/testGccDepfileReader_data/deps1.txt
new file mode 100644
index 0000000..fd2679f
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps1.txt
@@ -0,0 +1,26 @@
+--RULES--
+main.o
+--DEPENDENCIES--
+main.cpp
+/usr/include/stdc-predef.h
+/usr/include/stdio.h
+/usr/include/x86_64-linux-gnu/bits/libc-header-start.h
+/usr/include/features.h
+/usr/include/x86_64-linux-gnu/sys/cdefs.h
+/usr/include/x86_64-linux-gnu/bits/wordsize.h
+/usr/include/x86_64-linux-gnu/bits/long-double.h
+/usr/include/x86_64-linux-gnu/gnu/stubs.h
+/usr/include/x86_64-linux-gnu/gnu/stubs-64.h
+/usr/lib/gcc/x86_64-linux-gnu/8/include/stddef.h
+/usr/lib/gcc/x86_64-linux-gnu/8/include/stdarg.h
+/usr/include/x86_64-linux-gnu/bits/types.h
+/usr/include/x86_64-linux-gnu/bits/typesizes.h
+/usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h
+/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h
+/usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h
+/usr/include/x86_64-linux-gnu/bits/types/__FILE.h
+/usr/include/x86_64-linux-gnu/bits/types/FILE.h
+/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h
+/usr/include/x86_64-linux-gnu/bits/types/cookie_io_functions_t.h
+/usr/include/x86_64-linux-gnu/bits/stdio_lim.h
+/usr/include/x86_64-linux-gnu/bits/sys_errlist.h
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps2.d b/Tests/CMakeLib/testGccDepfileReader_data/deps2.d
new file mode 100644
index 0000000..25f0d78
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps2.d
@@ -0,0 +1 @@
+foo.o bar.o: foobar.c
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps2.txt b/Tests/CMakeLib/testGccDepfileReader_data/deps2.txt
new file mode 100644
index 0000000..afaf78e
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps2.txt
@@ -0,0 +1,5 @@
+--RULES--
+foo.o
+bar.o
+--DEPENDENCIES--
+foobar.c
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps3.d b/Tests/CMakeLib/testGccDepfileReader_data/deps3.d
new file mode 100644
index 0000000..d75ceed
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps3.d
@@ -0,0 +1,2 @@
+main.o: main.cpp foo\#bar.h foo\\#bar.h foo\ bar.h \
+ foo\\\ bar.h foo\\\\\ bar.h foo\\\\ foo$$bar.h
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps3.txt b/Tests/CMakeLib/testGccDepfileReader_data/deps3.txt
new file mode 100644
index 0000000..448f69c
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps3.txt
@@ -0,0 +1,11 @@
+--RULES--
+main.o
+--DEPENDENCIES--
+main.cpp
+foo#bar.h
+foo\#bar.h
+foo bar.h
+foo\ bar.h
+foo\\ bar.h
+foo\\\\
+foo$bar.h
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps4.d b/Tests/CMakeLib/testGccDepfileReader_data/deps4.d
new file mode 100644
index 0000000..9977a28
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps4.d
@@ -0,0 +1 @@
+invalid
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps5.d b/Tests/CMakeLib/testGccDepfileReader_data/deps5.d
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps5.d
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps5.txt b/Tests/CMakeLib/testGccDepfileReader_data/deps5.txt
new file mode 100644
index 0000000..6c4a75b
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps5.txt
@@ -0,0 +1,2 @@
+--RULES--
+--DEPENDENCIES--
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps7.d b/Tests/CMakeLib/testGccDepfileReader_data/deps7.d
new file mode 100644
index 0000000..92280cf
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps7.d
@@ -0,0 +1,6 @@
+out1 \
+ out2: \
+ in1 \
+ in2
+
+out3: in3
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps7.txt b/Tests/CMakeLib/testGccDepfileReader_data/deps7.txt
new file mode 100644
index 0000000..86b6600
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps7.txt
@@ -0,0 +1,10 @@
+--RULES--
+out1
+out2
+--DEPENDENCIES--
+in1
+in2
+--RULES--
+out3
+--DEPENDENCIES--
+in3
diff --git a/Tests/CMakeLib/testGeneratedFileStream.cxx b/Tests/CMakeLib/testGeneratedFileStream.cxx
new file mode 100644
index 0000000..de44a0b
--- /dev/null
+++ b/Tests/CMakeLib/testGeneratedFileStream.cxx
@@ -0,0 +1,88 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include <iostream>
+#include <string>
+
+#include "cmGeneratedFileStream.h"
+#include "cmSystemTools.h"
+
+#define cmFailed(m1, m2) \
+ std::cout << "FAILED: " << (m1) << (m2) << "\n"; \
+ failed = 1
+
+int testGeneratedFileStream(int /*unused*/, char* /*unused*/ [])
+{
+ int failed = 0;
+ cmGeneratedFileStream gm;
+ std::string file1 = "generatedFile1";
+ std::string file2 = "generatedFile2";
+ std::string file3 = "generatedFile3";
+ std::string file4 = "generatedFile4";
+ std::string file1tmp = file1 + ".tmp";
+ std::string file2tmp = file2 + ".tmp";
+ std::string file3tmp = file3 + ".tmp";
+ std::string file4tmp = file4 + ".tmp";
+ gm.Open(file1.c_str());
+ gm << "This is generated file 1";
+ gm.Close();
+ gm.Open(file2.c_str());
+ gm << "This is generated file 2";
+ gm.Close();
+ gm.Open(file3.c_str());
+ gm << "This is generated file 3";
+ gm.Close();
+ gm.Open(file4.c_str());
+ gm << "This is generated file 4";
+ gm.Close();
+ if (cmSystemTools::FileExists(file1.c_str())) {
+ if (cmSystemTools::FileExists(file2.c_str())) {
+ if (cmSystemTools::FileExists(file3.c_str())) {
+ if (cmSystemTools::FileExists(file4.c_str())) {
+ if (cmSystemTools::FileExists(file1tmp.c_str())) {
+ cmFailed("Something wrong with cmGeneratedFileStream. Temporary "
+ "file is still here: ",
+ file1tmp.c_str());
+ } else if (cmSystemTools::FileExists(file2tmp.c_str())) {
+ cmFailed("Something wrong with cmGeneratedFileStream. Temporary "
+ "file is still here: ",
+ file2tmp.c_str());
+ } else if (cmSystemTools::FileExists(file3tmp.c_str())) {
+ cmFailed("Something wrong with cmGeneratedFileStream. Temporary "
+ "file is still here: ",
+ file3tmp.c_str());
+ } else if (cmSystemTools::FileExists(file4tmp.c_str())) {
+ cmFailed("Something wrong with cmGeneratedFileStream. Temporary "
+ "file is still here: ",
+ file4tmp.c_str());
+ } else {
+ std::cout << "cmGeneratedFileStream works\n";
+ }
+ } else {
+ cmFailed(
+ "Something wrong with cmGeneratedFileStream. Cannot find file: ",
+ file4.c_str());
+ }
+ } else {
+ cmFailed("Something wrong with cmGeneratedFileStream. Found file: ",
+ file3.c_str());
+ }
+ } else {
+ cmFailed(
+ "Something wrong with cmGeneratedFileStream. Cannot find file: ",
+ file2.c_str());
+ }
+ } else {
+ cmFailed("Something wrong with cmGeneratedFileStream. Cannot find file: ",
+ file1.c_str());
+ }
+ cmSystemTools::RemoveFile(file1);
+ cmSystemTools::RemoveFile(file2);
+ cmSystemTools::RemoveFile(file3);
+ cmSystemTools::RemoveFile(file4);
+ cmSystemTools::RemoveFile(file1tmp);
+ cmSystemTools::RemoveFile(file2tmp);
+ cmSystemTools::RemoveFile(file3tmp);
+ cmSystemTools::RemoveFile(file4tmp);
+
+ return failed;
+}
diff --git a/Tests/CMakeLib/testJSONHelpers.cxx b/Tests/CMakeLib/testJSONHelpers.cxx
new file mode 100644
index 0000000..a45d320
--- /dev/null
+++ b/Tests/CMakeLib/testJSONHelpers.cxx
@@ -0,0 +1,504 @@
+#include <functional>
+#include <iostream>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+#include <cmext/string_view>
+
+#include <cm3p/json/value.h>
+
+#include "cmJSONHelpers.h"
+
+#define ASSERT_TRUE(x) \
+ do { \
+ if (!(x)) { \
+ std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
+ return false; \
+ } \
+ } while (false)
+
+namespace {
+struct ObjectStruct
+{
+ std::string Field1;
+ int Field2;
+};
+
+struct InheritedStruct : public ObjectStruct
+{
+ std::string Field3;
+};
+
+enum class ErrorCode
+{
+ Success,
+ InvalidInt,
+ InvalidBool,
+ InvalidString,
+ InvalidSubObject,
+ InvalidObject,
+ InvalidArray,
+ MissingRequired,
+};
+
+auto const IntHelper =
+ cmJSONIntHelper<ErrorCode>(ErrorCode::Success, ErrorCode::InvalidInt, 1);
+auto const RequiredIntHelper =
+ cmJSONRequiredHelper<int, ErrorCode>(ErrorCode::MissingRequired, IntHelper);
+auto const UIntHelper =
+ cmJSONUIntHelper<ErrorCode>(ErrorCode::Success, ErrorCode::InvalidInt, 1);
+auto const BoolHelper = cmJSONBoolHelper<ErrorCode>(
+ ErrorCode::Success, ErrorCode::InvalidBool, false);
+auto const StringHelper = cmJSONStringHelper<ErrorCode>(
+ ErrorCode::Success, ErrorCode::InvalidString, "default");
+auto const RequiredStringHelper = cmJSONRequiredHelper<std::string, ErrorCode>(
+ ErrorCode::MissingRequired, StringHelper);
+auto const StringVectorHelper = cmJSONVectorHelper<std::string, ErrorCode>(
+ ErrorCode::Success, ErrorCode::InvalidArray, StringHelper);
+auto const StringVectorFilterHelper =
+ cmJSONVectorFilterHelper<std::string, ErrorCode>(
+ ErrorCode::Success, ErrorCode::InvalidArray, StringHelper,
+ [](const std::string& value) { return value != "ignore"; });
+auto const StringMapHelper = cmJSONMapHelper<std::string, ErrorCode>(
+ ErrorCode::Success, ErrorCode::InvalidObject, StringHelper);
+auto const StringMapFilterHelper =
+ cmJSONMapFilterHelper<std::string, ErrorCode>(
+ ErrorCode::Success, ErrorCode::InvalidObject, StringHelper,
+ [](const std::string& key) { return key != "ignore"; });
+auto const OptionalStringHelper =
+ cmJSONOptionalHelper<std::string>(ErrorCode::Success, StringHelper);
+
+bool testInt()
+{
+ Json::Value v(2);
+ int i = 0;
+ ASSERT_TRUE(IntHelper(i, &v) == ErrorCode::Success);
+ ASSERT_TRUE(i == 2);
+
+ i = 0;
+ v = Json::nullValue;
+ ASSERT_TRUE(IntHelper(i, &v) == ErrorCode::InvalidInt);
+
+ i = 0;
+ ASSERT_TRUE(IntHelper(i, nullptr) == ErrorCode::Success);
+ ASSERT_TRUE(i == 1);
+
+ return true;
+}
+
+bool testUInt()
+{
+ Json::Value v(2);
+ unsigned int i = 0;
+ ASSERT_TRUE(UIntHelper(i, &v) == ErrorCode::Success);
+ ASSERT_TRUE(i == 2);
+
+ i = 0;
+ v = Json::nullValue;
+ ASSERT_TRUE(UIntHelper(i, &v) == ErrorCode::InvalidInt);
+
+ i = 0;
+ ASSERT_TRUE(UIntHelper(i, nullptr) == ErrorCode::Success);
+ ASSERT_TRUE(i == 1);
+
+ return true;
+}
+
+bool testBool()
+{
+ Json::Value v(true);
+ bool b = false;
+ ASSERT_TRUE(BoolHelper(b, &v) == ErrorCode::Success);
+ ASSERT_TRUE(b);
+
+ b = false;
+ v = false;
+ ASSERT_TRUE(BoolHelper(b, &v) == ErrorCode::Success);
+ ASSERT_TRUE(!b);
+
+ b = false;
+ v = 4;
+ ASSERT_TRUE(BoolHelper(b, &v) == ErrorCode::InvalidBool);
+
+ b = true;
+ ASSERT_TRUE(BoolHelper(b, nullptr) == ErrorCode::Success);
+ ASSERT_TRUE(!b);
+
+ return true;
+}
+
+bool testString()
+{
+ Json::Value v("str");
+ std::string str = "";
+ ASSERT_TRUE(StringHelper(str, &v) == ErrorCode::Success);
+ ASSERT_TRUE(str == "str");
+
+ str = "";
+ v = Json::nullValue;
+ ASSERT_TRUE(StringHelper(str, &v) == ErrorCode::InvalidString);
+
+ str = "";
+ ASSERT_TRUE(StringHelper(str, nullptr) == ErrorCode::Success);
+ ASSERT_TRUE(str == "default");
+
+ return true;
+}
+
+bool testObject()
+{
+ auto const subhelper =
+ cmJSONObjectHelper<ObjectStruct, ErrorCode>(ErrorCode::Success,
+ ErrorCode::InvalidSubObject)
+ .Bind("subfield"_s, &ObjectStruct::Field2, IntHelper);
+ auto const helper = cmJSONObjectHelper<ObjectStruct, ErrorCode>(
+ ErrorCode::Success, ErrorCode::InvalidObject)
+ .Bind("field1"_s, &ObjectStruct::Field1, StringHelper)
+ .Bind("field2"_s, subhelper)
+ .Bind<std::string>("field3"_s, nullptr, StringHelper);
+
+ Json::Value v(Json::objectValue);
+ v["field1"] = "Hello";
+ v["field2"] = Json::objectValue;
+ v["field2"]["subfield"] = 2;
+ v["field3"] = "world!";
+ v["extra"] = "extra";
+
+ ObjectStruct s1;
+ ASSERT_TRUE(helper(s1, &v) == ErrorCode::Success);
+ ASSERT_TRUE(s1.Field1 == "Hello");
+ ASSERT_TRUE(s1.Field2 == 2);
+
+ v["field2"]["subfield"] = "wrong";
+ ObjectStruct s2;
+ ASSERT_TRUE(helper(s2, &v) == ErrorCode::InvalidInt);
+
+ v["field2"].removeMember("subfield");
+ ObjectStruct s3;
+ ASSERT_TRUE(helper(s3, &v) == ErrorCode::InvalidSubObject);
+
+ v.removeMember("field2");
+ ObjectStruct s4;
+ ASSERT_TRUE(helper(s4, &v) == ErrorCode::InvalidObject);
+
+ v["field2"] = Json::objectValue;
+ v["field2"]["subfield"] = 2;
+ v["field3"] = 3;
+ ObjectStruct s5;
+ ASSERT_TRUE(helper(s5, &v) == ErrorCode::InvalidString);
+
+ v.removeMember("field3");
+ ObjectStruct s6;
+ ASSERT_TRUE(helper(s6, &v) == ErrorCode::InvalidObject);
+
+ v = "Hello";
+ ObjectStruct s7;
+ ASSERT_TRUE(helper(s7, &v) == ErrorCode::InvalidObject);
+
+ ObjectStruct s8;
+ ASSERT_TRUE(helper(s8, nullptr) == ErrorCode::InvalidObject);
+
+ return true;
+}
+
+bool testObjectInherited()
+{
+ auto const helper =
+ cmJSONObjectHelper<InheritedStruct, ErrorCode>(ErrorCode::Success,
+ ErrorCode::InvalidObject)
+ .Bind("field1"_s, &InheritedStruct::Field1, StringHelper)
+ .Bind("field2"_s, &InheritedStruct::Field2, IntHelper)
+ .Bind("field3"_s, &InheritedStruct::Field3, StringHelper);
+
+ Json::Value v(Json::objectValue);
+ v["field1"] = "Hello";
+ v["field2"] = 2;
+ v["field3"] = "world!";
+ v["extra"] = "extra";
+
+ InheritedStruct s1;
+ ASSERT_TRUE(helper(s1, &v) == ErrorCode::Success);
+ ASSERT_TRUE(s1.Field1 == "Hello");
+ ASSERT_TRUE(s1.Field2 == 2);
+ ASSERT_TRUE(s1.Field3 == "world!");
+
+ v["field2"] = "wrong";
+ InheritedStruct s2;
+ ASSERT_TRUE(helper(s2, &v) == ErrorCode::InvalidInt);
+
+ v.removeMember("field2");
+ InheritedStruct s3;
+ ASSERT_TRUE(helper(s3, &v) == ErrorCode::InvalidObject);
+
+ v["field2"] = 2;
+ v["field3"] = 3;
+ InheritedStruct s4;
+ ASSERT_TRUE(helper(s4, &v) == ErrorCode::InvalidString);
+
+ v.removeMember("field3");
+ InheritedStruct s5;
+ ASSERT_TRUE(helper(s5, &v) == ErrorCode::InvalidObject);
+
+ v = "Hello";
+ InheritedStruct s6;
+ ASSERT_TRUE(helper(s6, &v) == ErrorCode::InvalidObject);
+
+ InheritedStruct s7;
+ ASSERT_TRUE(helper(s7, nullptr) == ErrorCode::InvalidObject);
+
+ return true;
+}
+
+bool testObjectNoExtra()
+{
+ auto const helper = cmJSONObjectHelper<ObjectStruct, ErrorCode>(
+ ErrorCode::Success, ErrorCode::InvalidObject, false)
+ .Bind("field1"_s, &ObjectStruct::Field1, StringHelper)
+ .Bind("field2"_s, &ObjectStruct::Field2, IntHelper);
+
+ Json::Value v(Json::objectValue);
+ v["field1"] = "Hello";
+ v["field2"] = 2;
+
+ ObjectStruct s1;
+ ASSERT_TRUE(helper(s1, &v) == ErrorCode::Success);
+ ASSERT_TRUE(s1.Field1 == "Hello");
+ ASSERT_TRUE(s1.Field2 == 2);
+
+ v["extra"] = "world!";
+ ObjectStruct s2;
+ ASSERT_TRUE(helper(s2, &v) == ErrorCode::InvalidObject);
+
+ return true;
+}
+
+bool testObjectOptional()
+{
+ auto const helper =
+ cmJSONObjectHelper<ObjectStruct, ErrorCode>(ErrorCode::Success,
+ ErrorCode::InvalidObject)
+ .Bind("field1"_s, &ObjectStruct::Field1, StringHelper, false)
+ .Bind("field2"_s, &ObjectStruct::Field2, IntHelper, false)
+ .Bind<std::string>("field3_s", nullptr, StringHelper, false);
+
+ Json::Value v(Json::objectValue);
+ v["field1"] = "Hello";
+ v["field2"] = 2;
+ v["field3"] = "world!";
+ v["extra"] = "extra";
+
+ ObjectStruct s1;
+ ASSERT_TRUE(helper(s1, &v) == ErrorCode::Success);
+ ASSERT_TRUE(s1.Field1 == "Hello");
+ ASSERT_TRUE(s1.Field2 == 2);
+
+ v = Json::objectValue;
+ ObjectStruct s2;
+ ASSERT_TRUE(helper(s2, &v) == ErrorCode::Success);
+ ASSERT_TRUE(s2.Field1 == "default");
+ ASSERT_TRUE(s2.Field2 == 1);
+
+ ObjectStruct s3;
+ ASSERT_TRUE(helper(s3, nullptr) == ErrorCode::Success);
+ ASSERT_TRUE(s3.Field1 == "default");
+ ASSERT_TRUE(s3.Field2 == 1);
+
+ return true;
+}
+
+bool testVector()
+{
+ Json::Value v(Json::arrayValue);
+ v.append("Hello");
+ v.append("world!");
+ v.append("ignore");
+
+ std::vector<std::string> l{ "default" };
+ std::vector<std::string> expected{ "Hello", "world!", "ignore" };
+ ASSERT_TRUE(StringVectorHelper(l, &v) == ErrorCode::Success);
+ ASSERT_TRUE(l == expected);
+
+ v[1] = 2;
+ l = { "default" };
+ ASSERT_TRUE(StringVectorHelper(l, &v) == ErrorCode::InvalidString);
+
+ v = "Hello";
+ l = { "default" };
+ ASSERT_TRUE(StringVectorHelper(l, &v) == ErrorCode::InvalidArray);
+
+ l = { "default" };
+ ASSERT_TRUE(StringVectorHelper(l, nullptr) == ErrorCode::Success);
+ ASSERT_TRUE(l.empty());
+
+ return true;
+}
+
+bool testVectorFilter()
+{
+ Json::Value v(Json::arrayValue);
+ v.append("Hello");
+ v.append("world!");
+ v.append("ignore");
+
+ std::vector<std::string> l{ "default" };
+ std::vector<std::string> expected{
+ "Hello",
+ "world!",
+ };
+ ASSERT_TRUE(StringVectorFilterHelper(l, &v) == ErrorCode::Success);
+ ASSERT_TRUE(l == expected);
+
+ v[1] = 2;
+ l = { "default" };
+ ASSERT_TRUE(StringVectorFilterHelper(l, &v) == ErrorCode::InvalidString);
+
+ v = "Hello";
+ l = { "default" };
+ ASSERT_TRUE(StringVectorFilterHelper(l, &v) == ErrorCode::InvalidArray);
+
+ l = { "default" };
+ ASSERT_TRUE(StringVectorFilterHelper(l, nullptr) == ErrorCode::Success);
+ ASSERT_TRUE(l.empty());
+
+ return true;
+}
+
+bool testMap()
+{
+ Json::Value v(Json::objectValue);
+ v["field1"] = "Hello";
+ v["field2"] = "world!";
+ v["ignore"] = "ignore";
+
+ std::map<std::string, std::string> m{ { "key", "default" } };
+ std::map<std::string, std::string> expected{ { "field1", "Hello" },
+ { "field2", "world!" },
+ { "ignore", "ignore" } };
+ ASSERT_TRUE(StringMapHelper(m, &v) == ErrorCode::Success);
+ ASSERT_TRUE(m == expected);
+
+ v = Json::arrayValue;
+ m = { { "key", "default" } };
+ ASSERT_TRUE(StringMapHelper(m, &v) == ErrorCode::InvalidObject);
+
+ m = { { "key", "default" } };
+ ASSERT_TRUE(StringMapHelper(m, nullptr) == ErrorCode::Success);
+ ASSERT_TRUE(m.empty());
+
+ return true;
+}
+
+bool testMapFilter()
+{
+ Json::Value v(Json::objectValue);
+ v["field1"] = "Hello";
+ v["field2"] = "world!";
+ v["ignore"] = "ignore";
+
+ std::map<std::string, std::string> m{ { "key", "default" } };
+ std::map<std::string, std::string> expected{ { "field1", "Hello" },
+ { "field2", "world!" } };
+ ASSERT_TRUE(StringMapFilterHelper(m, &v) == ErrorCode::Success);
+ ASSERT_TRUE(m == expected);
+
+ v = Json::arrayValue;
+ m = { { "key", "default" } };
+ ASSERT_TRUE(StringMapFilterHelper(m, &v) == ErrorCode::InvalidObject);
+
+ m = { { "key", "default" } };
+ ASSERT_TRUE(StringMapFilterHelper(m, nullptr) == ErrorCode::Success);
+ ASSERT_TRUE(m.empty());
+
+ return true;
+}
+
+bool testOptional()
+{
+ Json::Value v = "Hello";
+
+ cm::optional<std::string> str{ "default" };
+ ASSERT_TRUE(OptionalStringHelper(str, &v) == ErrorCode::Success);
+ ASSERT_TRUE(str == "Hello");
+
+ str.emplace("default");
+ ASSERT_TRUE(OptionalStringHelper(str, nullptr) == ErrorCode::Success);
+ ASSERT_TRUE(str == cm::nullopt);
+
+ return true;
+}
+
+bool testRequired()
+{
+ Json::Value v = "Hello";
+
+ std::string str = "default";
+ int i = 1;
+ ASSERT_TRUE(RequiredStringHelper(str, &v) == ErrorCode::Success);
+ ASSERT_TRUE(str == "Hello");
+ ASSERT_TRUE(RequiredIntHelper(i, &v) == ErrorCode::InvalidInt);
+
+ v = 2;
+ str = "default";
+ i = 1;
+ ASSERT_TRUE(RequiredStringHelper(str, &v) == ErrorCode::InvalidString);
+ ASSERT_TRUE(RequiredIntHelper(i, &v) == ErrorCode::Success);
+ ASSERT_TRUE(i == 2);
+
+ str = "default";
+ i = 1;
+ ASSERT_TRUE(RequiredStringHelper(str, nullptr) ==
+ ErrorCode::MissingRequired);
+ ASSERT_TRUE(RequiredIntHelper(i, nullptr) == ErrorCode::MissingRequired);
+
+ return true;
+}
+}
+
+int testJSONHelpers(int /*unused*/, char* /*unused*/ [])
+{
+ if (!testInt()) {
+ return 1;
+ }
+ if (!testUInt()) {
+ return 1;
+ }
+ if (!testBool()) {
+ return 1;
+ }
+ if (!testString()) {
+ return 1;
+ }
+ if (!testObject()) {
+ return 1;
+ }
+ if (!testObjectInherited()) {
+ return 1;
+ }
+ if (!testObjectNoExtra()) {
+ return 1;
+ }
+ if (!testObjectOptional()) {
+ return 1;
+ }
+ if (!testVector()) {
+ return 1;
+ }
+ if (!testVectorFilter()) {
+ return 1;
+ }
+ if (!testMap()) {
+ return 1;
+ }
+ if (!testMapFilter()) {
+ return 1;
+ }
+ if (!testOptional()) {
+ return 1;
+ }
+ if (!testRequired()) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/Tests/CMakeLib/testOptional.cxx b/Tests/CMakeLib/testOptional.cxx
new file mode 100644
index 0000000..2d7dd7c
--- /dev/null
+++ b/Tests/CMakeLib/testOptional.cxx
@@ -0,0 +1,808 @@
+#include <iostream>
+#include <type_traits>
+#include <vector>
+
+#include <cm/optional>
+#include <cm/utility>
+
+class EventLogger;
+
+class Event
+{
+public:
+ enum EventType
+ {
+ DEFAULT_CONSTRUCT,
+ COPY_CONSTRUCT,
+ MOVE_CONSTRUCT,
+ VALUE_CONSTRUCT,
+
+ DESTRUCT,
+
+ COPY_ASSIGN,
+ MOVE_ASSIGN,
+ VALUE_ASSIGN,
+
+ REFERENCE,
+ CONST_REFERENCE,
+ RVALUE_REFERENCE,
+ CONST_RVALUE_REFERENCE,
+
+ SWAP,
+
+ COMPARE_EE_EQ,
+ COMPARE_EE_NE,
+ COMPARE_EE_LT,
+ COMPARE_EE_LE,
+ COMPARE_EE_GT,
+ COMPARE_EE_GE,
+ };
+
+ EventType Type;
+ const EventLogger* Logger1;
+ const EventLogger* Logger2;
+ int Value;
+
+ bool operator==(const Event& other) const;
+ bool operator!=(const Event& other) const;
+};
+
+bool Event::operator==(const Event& other) const
+{
+ return this->Type == other.Type && this->Logger1 == other.Logger1 &&
+ this->Logger2 == other.Logger2 && this->Value == other.Value;
+}
+
+bool Event::operator!=(const Event& other) const
+{
+ return !(*this == other);
+}
+
+static std::vector<Event> events;
+
+class EventLogger
+{
+public:
+ EventLogger();
+ EventLogger(const EventLogger& other);
+ EventLogger(EventLogger&& other);
+ EventLogger(int value);
+
+ ~EventLogger();
+
+ EventLogger& operator=(const EventLogger& other);
+ EventLogger& operator=(EventLogger&& other);
+ EventLogger& operator=(int value);
+
+ void Reference() &;
+ void Reference() const&;
+ void Reference() &&;
+ void Reference() const&&;
+
+ int Value = 0;
+};
+
+class NoMoveAssignEventLogger : public EventLogger
+{
+public:
+ using EventLogger::EventLogger;
+
+ NoMoveAssignEventLogger(const NoMoveAssignEventLogger&) = default;
+ NoMoveAssignEventLogger(NoMoveAssignEventLogger&&) = default;
+
+ NoMoveAssignEventLogger& operator=(const NoMoveAssignEventLogger&) = default;
+ NoMoveAssignEventLogger& operator=(NoMoveAssignEventLogger&&) = delete;
+};
+
+#define ASSERT_TRUE(x) \
+ do { \
+ if (!(x)) { \
+ std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
+ return false; \
+ } \
+ } while (false)
+
+// Certain builds of GCC generate false -Wmaybe-uninitialized warnings when
+// doing a release build with the system version of std::optional. These
+// warnings do not manifest when using our own cm::optional implementation.
+// Silence these false warnings.
+#if defined(__GNUC__) && !defined(__clang__)
+# define BEGIN_IGNORE_UNINITIALIZED \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define END_IGNORE_UNINITIALIZED _Pragma("GCC diagnostic pop")
+#else
+# define BEGIN_IGNORE_UNINITIALIZED
+# define END_IGNORE_UNINITIALIZED
+#endif
+
+void swap(EventLogger& e1, EventLogger& e2)
+{
+ BEGIN_IGNORE_UNINITIALIZED
+ events.push_back({ Event::SWAP, &e1, &e2, e2.Value });
+ END_IGNORE_UNINITIALIZED
+ auto tmp = e1.Value;
+ e1.Value = e2.Value;
+ e2.Value = tmp;
+}
+
+EventLogger::EventLogger()
+ : Value(0)
+{
+ events.push_back({ Event::DEFAULT_CONSTRUCT, this, nullptr, 0 });
+}
+
+EventLogger::EventLogger(const EventLogger& other)
+ : Value(other.Value)
+{
+ events.push_back({ Event::COPY_CONSTRUCT, this, &other, other.Value });
+}
+
+BEGIN_IGNORE_UNINITIALIZED
+EventLogger::EventLogger(EventLogger&& other)
+ : Value(other.Value)
+{
+ events.push_back({ Event::MOVE_CONSTRUCT, this, &other, other.Value });
+}
+END_IGNORE_UNINITIALIZED
+
+EventLogger::EventLogger(int value)
+ : Value(value)
+{
+ events.push_back({ Event::VALUE_CONSTRUCT, this, nullptr, value });
+}
+
+EventLogger::~EventLogger()
+{
+ BEGIN_IGNORE_UNINITIALIZED
+ events.push_back({ Event::DESTRUCT, this, nullptr, this->Value });
+ END_IGNORE_UNINITIALIZED
+}
+
+EventLogger& EventLogger::operator=(const EventLogger& other)
+{
+ events.push_back({ Event::COPY_ASSIGN, this, &other, other.Value });
+ this->Value = other.Value;
+ return *this;
+}
+
+EventLogger& EventLogger::operator=(EventLogger&& other)
+{
+ events.push_back({ Event::MOVE_ASSIGN, this, &other, other.Value });
+ this->Value = other.Value;
+ return *this;
+}
+
+EventLogger& EventLogger::operator=(int value)
+{
+ events.push_back({ Event::VALUE_ASSIGN, this, nullptr, value });
+ this->Value = value;
+ return *this;
+}
+
+bool operator==(const EventLogger& lhs, const EventLogger& rhs)
+{
+ events.push_back({ Event::COMPARE_EE_EQ, &lhs, &rhs, lhs.Value });
+ return lhs.Value == rhs.Value;
+}
+
+bool operator!=(const EventLogger& lhs, const EventLogger& rhs)
+{
+ events.push_back({ Event::COMPARE_EE_NE, &lhs, &rhs, lhs.Value });
+ return lhs.Value != rhs.Value;
+}
+
+bool operator<(const EventLogger& lhs, const EventLogger& rhs)
+{
+ events.push_back({ Event::COMPARE_EE_LT, &lhs, &rhs, lhs.Value });
+ return lhs.Value < rhs.Value;
+}
+
+bool operator<=(const EventLogger& lhs, const EventLogger& rhs)
+{
+ events.push_back({ Event::COMPARE_EE_LE, &lhs, &rhs, lhs.Value });
+ return lhs.Value <= rhs.Value;
+}
+
+bool operator>(const EventLogger& lhs, const EventLogger& rhs)
+{
+ events.push_back({ Event::COMPARE_EE_GT, &lhs, &rhs, lhs.Value });
+ return lhs.Value > rhs.Value;
+}
+
+bool operator>=(const EventLogger& lhs, const EventLogger& rhs)
+{
+ events.push_back({ Event::COMPARE_EE_GE, &lhs, &rhs, lhs.Value });
+ return lhs.Value >= rhs.Value;
+}
+
+void EventLogger::Reference() &
+{
+ events.push_back({ Event::REFERENCE, this, nullptr, this->Value });
+}
+
+void EventLogger::Reference() const&
+{
+ events.push_back({ Event::CONST_REFERENCE, this, nullptr, this->Value });
+}
+
+void EventLogger::Reference() &&
+{
+ events.push_back({ Event::RVALUE_REFERENCE, this, nullptr, this->Value });
+}
+
+void EventLogger::Reference() const&&
+{
+ events.push_back(
+ { Event::CONST_RVALUE_REFERENCE, this, nullptr, this->Value });
+}
+
+static bool testDefaultConstruct(std::vector<Event>& expected)
+{
+ const cm::optional<EventLogger> o{};
+
+ expected = {};
+ return true;
+}
+
+static bool testNulloptConstruct(std::vector<Event>& expected)
+{
+ const cm::optional<EventLogger> o{ cm::nullopt };
+
+ expected = {};
+ return true;
+}
+
+static bool testValueConstruct(std::vector<Event>& expected)
+{
+ const cm::optional<EventLogger> o{ 4 };
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, &*o, nullptr, 4 },
+ { Event::DESTRUCT, &*o, nullptr, 4 },
+ };
+ return true;
+}
+
+static bool testInPlaceConstruct(std::vector<Event>& expected)
+{
+ const cm::optional<EventLogger> o1{ cm::in_place, 4 };
+ const cm::optional<EventLogger> o2{ cm::in_place_t{}, 4 };
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 },
+ { Event::VALUE_CONSTRUCT, &*o2, nullptr, 4 },
+ { Event::DESTRUCT, &*o2, nullptr, 4 },
+ { Event::DESTRUCT, &*o1, nullptr, 4 },
+ };
+ return true;
+}
+
+static bool testCopyConstruct(std::vector<Event>& expected)
+{
+ const cm::optional<EventLogger> o1{ 4 };
+ const cm::optional<EventLogger> o2{ o1 };
+ const cm::optional<EventLogger> o3{};
+ const cm::optional<EventLogger> o4{ o3 };
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 },
+ { Event::COPY_CONSTRUCT, &*o2, &o1.value(), 4 },
+ { Event::DESTRUCT, &*o2, nullptr, 4 },
+ { Event::DESTRUCT, &*o1, nullptr, 4 },
+ };
+ return true;
+}
+
+static bool testMoveConstruct(std::vector<Event>& expected)
+{
+ cm::optional<EventLogger> o1{ 4 };
+ const cm::optional<EventLogger> o2{ std::move(o1) };
+ cm::optional<EventLogger> o3{};
+ const cm::optional<EventLogger> o4{ std::move(o3) };
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 },
+ { Event::MOVE_CONSTRUCT, &*o2, &*o1, 4 },
+ { Event::DESTRUCT, &*o2, nullptr, 4 },
+ { Event::DESTRUCT, &*o1, nullptr, 4 },
+ };
+ return true;
+}
+
+static bool testNulloptAssign(std::vector<Event>& expected)
+{
+ cm::optional<EventLogger> o1{ 4 };
+ auto const* v1 = &*o1;
+ o1 = cm::nullopt;
+ cm::optional<EventLogger> o2{};
+ o2 = cm::nullopt;
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, v1, nullptr, 4 },
+ { Event::DESTRUCT, v1, nullptr, 4 },
+ };
+ return true;
+}
+
+static bool testCopyAssign(std::vector<Event>& expected)
+{
+ cm::optional<EventLogger> o1{};
+ const cm::optional<EventLogger> o2{ 4 };
+ auto const* v2 = &*o2;
+ o1 = o2;
+ auto const* v1 = &*o1;
+ const cm::optional<EventLogger> o3{ 5 };
+ auto const* v3 = &*o3;
+ o1 = o3;
+ const cm::optional<EventLogger> o4{};
+ o1 = o4;
+ o1 = o4; // Intentionally duplicated to test assigning an empty optional to
+ // an empty optional
+
+ cm::optional<NoMoveAssignEventLogger> o5{ 1 };
+ auto const* v5 = &*o5;
+ const cm::optional<NoMoveAssignEventLogger> o6{ 2 };
+ auto const* v6 = &*o6;
+ o5 = std::move(o6);
+ const NoMoveAssignEventLogger e7{ 3 };
+ o5 = std::move(e7);
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, v2, nullptr, 4 },
+ { Event::COPY_CONSTRUCT, v1, v2, 4 },
+ { Event::VALUE_CONSTRUCT, v3, nullptr, 5 },
+ { Event::COPY_ASSIGN, v1, v3, 5 },
+ { Event::DESTRUCT, v1, nullptr, 5 },
+ { Event::VALUE_CONSTRUCT, v5, nullptr, 1 },
+ { Event::VALUE_CONSTRUCT, v6, nullptr, 2 },
+ { Event::COPY_ASSIGN, v5, v6, 2 },
+ { Event::VALUE_CONSTRUCT, &e7, nullptr, 3 },
+ { Event::COPY_ASSIGN, v5, &e7, 3 },
+ { Event::DESTRUCT, &e7, nullptr, 3 },
+ { Event::DESTRUCT, v6, nullptr, 2 },
+ { Event::DESTRUCT, v5, nullptr, 3 },
+ { Event::DESTRUCT, v3, nullptr, 5 },
+ { Event::DESTRUCT, v2, nullptr, 4 },
+ };
+ return true;
+}
+
+static bool testMoveAssign(std::vector<Event>& expected)
+{
+ cm::optional<EventLogger> o1{};
+ cm::optional<EventLogger> o2{ 4 };
+ auto const* v2 = &*o2;
+ o1 = std::move(o2);
+ auto const* v1 = &*o1;
+ cm::optional<EventLogger> o3{ 5 };
+ auto const* v3 = &*o3;
+ o1 = std::move(o3);
+ cm::optional<EventLogger> o4{};
+ o1 = std::move(o4);
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, v2, nullptr, 4 },
+ { Event::MOVE_CONSTRUCT, v1, v2, 4 },
+ { Event::VALUE_CONSTRUCT, v3, nullptr, 5 },
+ { Event::MOVE_ASSIGN, v1, v3, 5 },
+ { Event::DESTRUCT, v1, nullptr, 5 },
+ { Event::DESTRUCT, v3, nullptr, 5 },
+ { Event::DESTRUCT, v2, nullptr, 4 },
+ };
+ return true;
+}
+
+static bool testPointer(std::vector<Event>& expected)
+{
+ cm::optional<EventLogger> o1{ 4 };
+ const cm::optional<EventLogger> o2{ 5 };
+
+ o1->Reference();
+ o2->Reference();
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 },
+ { Event::VALUE_CONSTRUCT, &*o2, nullptr, 5 },
+ { Event::REFERENCE, &*o1, nullptr, 4 },
+ { Event::CONST_REFERENCE, &*o2, nullptr, 5 },
+ { Event::DESTRUCT, &*o2, nullptr, 5 },
+ { Event::DESTRUCT, &*o1, nullptr, 4 },
+ };
+ return true;
+}
+
+#if !__GNUC__ || __GNUC__ > 4
+# define ALLOW_CONST_RVALUE
+#endif
+
+static bool testDereference(std::vector<Event>& expected)
+{
+ cm::optional<EventLogger> o1{ 4 };
+ auto const* v1 = &*o1;
+ const cm::optional<EventLogger> o2{ 5 };
+ auto const* v2 = &*o2;
+
+ (*o1).Reference();
+ (*o2).Reference();
+ (*std::move(o1)).Reference();
+#ifdef ALLOW_CONST_RVALUE
+ (*std::move(o2)).Reference(); // Broken in GCC 4.9.0. Sigh...
+#endif
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, v1, nullptr, 4 },
+ { Event::VALUE_CONSTRUCT, v2, nullptr, 5 },
+ { Event::REFERENCE, v1, nullptr, 4 },
+ { Event::CONST_REFERENCE, v2, nullptr, 5 },
+ { Event::RVALUE_REFERENCE, v1, nullptr, 4 },
+#ifdef ALLOW_CONST_RVALUE
+ { Event::CONST_RVALUE_REFERENCE, v2, nullptr, 5 },
+#endif
+ { Event::DESTRUCT, v2, nullptr, 5 },
+ { Event::DESTRUCT, v1, nullptr, 4 },
+ };
+ return true;
+}
+
+static bool testHasValue(std::vector<Event>& expected)
+{
+ const cm::optional<EventLogger> o1{ 4 };
+ const cm::optional<EventLogger> o2{};
+
+ ASSERT_TRUE(o1.has_value());
+ ASSERT_TRUE(o1);
+ ASSERT_TRUE(!o2.has_value());
+ ASSERT_TRUE(!o2);
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 },
+ { Event::DESTRUCT, &*o1, nullptr, 4 },
+ };
+ return true;
+}
+
+static bool testValue(std::vector<Event>& expected)
+{
+ cm::optional<EventLogger> o1{ 4 };
+ const cm::optional<EventLogger> o2{ 5 };
+ cm::optional<EventLogger> o3{};
+ const cm::optional<EventLogger> o4{};
+
+ o1.value().Reference();
+ o2.value().Reference();
+
+ bool thrown = false;
+ try {
+ (void)o3.value();
+ } catch (cm::bad_optional_access&) {
+ thrown = true;
+ }
+ ASSERT_TRUE(thrown);
+
+ thrown = false;
+ try {
+ (void)o4.value();
+ } catch (cm::bad_optional_access&) {
+ thrown = true;
+ }
+ ASSERT_TRUE(thrown);
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 },
+ { Event::VALUE_CONSTRUCT, &*o2, nullptr, 5 },
+ { Event::REFERENCE, &*o1, nullptr, 4 },
+ { Event::CONST_REFERENCE, &*o2, nullptr, 5 },
+ { Event::DESTRUCT, &*o2, nullptr, 5 },
+ { Event::DESTRUCT, &*o1, nullptr, 4 },
+ };
+ return true;
+}
+
+static bool testValueOr()
+{
+ const cm::optional<EventLogger> o1{ 4 };
+ cm::optional<EventLogger> o2{ 5 };
+ const cm::optional<EventLogger> o3{};
+ cm::optional<EventLogger> o4{};
+
+ EventLogger e1{ 6 };
+ EventLogger e2{ 7 };
+ EventLogger e3{ 8 };
+ EventLogger e4{ 9 };
+
+ EventLogger r1 = o1.value_or(e1);
+ ASSERT_TRUE(r1.Value == 4);
+ EventLogger r2 = std::move(o2).value_or(e2);
+ ASSERT_TRUE(r2.Value == 5);
+ EventLogger r3 = o3.value_or(e3);
+ ASSERT_TRUE(r3.Value == 8);
+ EventLogger r4 = std::move(o4).value_or(e4);
+ ASSERT_TRUE(r4.Value == 9);
+
+ return true;
+}
+
+static bool testComparison(std::vector<Event>& expected)
+{
+ const cm::optional<EventLogger> o1{ 1 };
+ const cm::optional<EventLogger> o2{ 2 };
+ const cm::optional<EventLogger> o3{ 2 };
+ const cm::optional<EventLogger> o4{};
+ const cm::optional<EventLogger> o5{};
+ const EventLogger e1{ 2 };
+
+ ASSERT_TRUE(!(o1 == o2) && o1 != o2);
+ ASSERT_TRUE(o1 < o2 && !(o1 >= o2));
+ ASSERT_TRUE(!(o1 > o2) && o1 <= o2);
+
+ ASSERT_TRUE(o2 == o3 && !(o2 != o3));
+ ASSERT_TRUE(!(o2 < o3) && o2 >= o3);
+ ASSERT_TRUE(!(o2 > o3) && o2 <= o3);
+
+ ASSERT_TRUE(!(o3 == o4) && o3 != o4);
+ ASSERT_TRUE(!(o3 < o4) && o3 >= o4);
+ ASSERT_TRUE(o3 > o4 && !(o3 <= o4));
+
+ ASSERT_TRUE(o4 == o5 && !(o4 != o5));
+ ASSERT_TRUE(!(o4 < o5) && o4 >= o5);
+ ASSERT_TRUE(!(o4 > o5) && o4 <= o5);
+
+ ASSERT_TRUE(!(o1 == cm::nullopt) && o1 != cm::nullopt);
+ ASSERT_TRUE(!(o1 < cm::nullopt) && o1 >= cm::nullopt);
+ ASSERT_TRUE(o1 > cm::nullopt && !(o1 <= cm::nullopt));
+
+ ASSERT_TRUE(!(cm::nullopt == o1) && cm::nullopt != o1);
+ ASSERT_TRUE(cm::nullopt < o1 && !(cm::nullopt >= o1));
+ ASSERT_TRUE(!(cm::nullopt > o1) && cm::nullopt <= o1);
+
+ ASSERT_TRUE(o4 == cm::nullopt && !(o4 != cm::nullopt));
+ ASSERT_TRUE(!(o4 < cm::nullopt) && o4 >= cm::nullopt);
+ ASSERT_TRUE(!(o4 > cm::nullopt) && o4 <= cm::nullopt);
+
+ ASSERT_TRUE(cm::nullopt == o4 && !(cm::nullopt != o4));
+ ASSERT_TRUE(!(cm::nullopt < o4) && cm::nullopt >= o4);
+ ASSERT_TRUE(!(cm::nullopt > o4) && cm::nullopt <= o4);
+
+ ASSERT_TRUE(!(o1 == e1) && o1 != e1);
+ ASSERT_TRUE(o1 < e1 && !(o1 >= e1));
+ ASSERT_TRUE(!(o1 > e1) && o1 <= e1);
+
+ ASSERT_TRUE(o2 == e1 && !(o2 != e1));
+ ASSERT_TRUE(!(o2 < e1) && o2 >= e1);
+ ASSERT_TRUE(!(o2 > e1) && o2 <= e1);
+
+ ASSERT_TRUE(!(o4 == e1) && o4 != e1);
+ ASSERT_TRUE(o4 < e1 && !(o4 >= e1));
+ ASSERT_TRUE(!(o4 > e1) && o4 <= e1);
+
+ ASSERT_TRUE(!(e1 == o1) && e1 != o1);
+ ASSERT_TRUE(!(e1 < o1) && e1 >= o1);
+ ASSERT_TRUE(e1 > o1 && !(e1 <= o1));
+
+ ASSERT_TRUE(e1 == o2 && !(e1 != o2));
+ ASSERT_TRUE(!(e1 < o2) && e1 >= o2);
+ ASSERT_TRUE(!(e1 > o2) && e1 <= o2);
+
+ ASSERT_TRUE(!(e1 == o4) && e1 != o4);
+ ASSERT_TRUE(!(e1 < o4) && e1 >= o4);
+ ASSERT_TRUE(e1 > o4 && !(e1 <= o4));
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, &*o1, nullptr, 1 },
+ { Event::VALUE_CONSTRUCT, &*o2, nullptr, 2 },
+ { Event::VALUE_CONSTRUCT, &*o3, nullptr, 2 },
+ { Event::VALUE_CONSTRUCT, &e1, nullptr, 2 },
+ { Event::COMPARE_EE_EQ, &*o1, &*o2, 1 },
+ { Event::COMPARE_EE_NE, &*o1, &*o2, 1 },
+ { Event::COMPARE_EE_LT, &*o1, &*o2, 1 },
+ { Event::COMPARE_EE_GE, &*o1, &*o2, 1 },
+ { Event::COMPARE_EE_GT, &*o1, &*o2, 1 },
+ { Event::COMPARE_EE_LE, &*o1, &*o2, 1 },
+ { Event::COMPARE_EE_EQ, &*o2, &*o3, 2 },
+ { Event::COMPARE_EE_NE, &*o2, &*o3, 2 },
+ { Event::COMPARE_EE_LT, &*o2, &*o3, 2 },
+ { Event::COMPARE_EE_GE, &*o2, &*o3, 2 },
+ { Event::COMPARE_EE_GT, &*o2, &*o3, 2 },
+ { Event::COMPARE_EE_LE, &*o2, &*o3, 2 },
+ { Event::COMPARE_EE_EQ, &*o1, &e1, 1 },
+ { Event::COMPARE_EE_NE, &*o1, &e1, 1 },
+ { Event::COMPARE_EE_LT, &*o1, &e1, 1 },
+ { Event::COMPARE_EE_GE, &*o1, &e1, 1 },
+ { Event::COMPARE_EE_GT, &*o1, &e1, 1 },
+ { Event::COMPARE_EE_LE, &*o1, &e1, 1 },
+ { Event::COMPARE_EE_EQ, &*o2, &e1, 2 },
+ { Event::COMPARE_EE_NE, &*o2, &e1, 2 },
+ { Event::COMPARE_EE_LT, &*o2, &e1, 2 },
+ { Event::COMPARE_EE_GE, &*o2, &e1, 2 },
+ { Event::COMPARE_EE_GT, &*o2, &e1, 2 },
+ { Event::COMPARE_EE_LE, &*o2, &e1, 2 },
+ { Event::COMPARE_EE_EQ, &e1, &*o1, 2 },
+ { Event::COMPARE_EE_NE, &e1, &*o1, 2 },
+ { Event::COMPARE_EE_LT, &e1, &*o1, 2 },
+ { Event::COMPARE_EE_GE, &e1, &*o1, 2 },
+ { Event::COMPARE_EE_GT, &e1, &*o1, 2 },
+ { Event::COMPARE_EE_LE, &e1, &*o1, 2 },
+ { Event::COMPARE_EE_EQ, &e1, &*o2, 2 },
+ { Event::COMPARE_EE_NE, &e1, &*o2, 2 },
+ { Event::COMPARE_EE_LT, &e1, &*o2, 2 },
+ { Event::COMPARE_EE_GE, &e1, &*o2, 2 },
+ { Event::COMPARE_EE_GT, &e1, &*o2, 2 },
+ { Event::COMPARE_EE_LE, &e1, &*o2, 2 },
+ { Event::DESTRUCT, &e1, nullptr, 2 },
+ { Event::DESTRUCT, &*o3, nullptr, 2 },
+ { Event::DESTRUCT, &*o2, nullptr, 2 },
+ { Event::DESTRUCT, &*o1, nullptr, 1 },
+ };
+ return true;
+}
+
+static bool testSwap(std::vector<Event>& expected)
+{
+ cm::optional<EventLogger> o1{ 4 };
+ auto const* v1 = &*o1;
+ cm::optional<EventLogger> o2{};
+
+ o1.swap(o2);
+ auto const* v2 = &*o2;
+
+ ASSERT_TRUE(!o1.has_value());
+ ASSERT_TRUE(o2.has_value());
+ ASSERT_TRUE(o2.value().Value == 4);
+
+ o1.swap(o2);
+
+ ASSERT_TRUE(o1.has_value());
+ ASSERT_TRUE(o1.value().Value == 4);
+ ASSERT_TRUE(!o2.has_value());
+
+ o2.emplace(5);
+ o1.swap(o2);
+
+ ASSERT_TRUE(o1.has_value());
+ ASSERT_TRUE(o1.value().Value == 5);
+ ASSERT_TRUE(o2.has_value());
+ ASSERT_TRUE(o2.value().Value == 4);
+
+ o1.reset();
+ o2.reset();
+ o1.swap(o2);
+
+ ASSERT_TRUE(!o1.has_value());
+ ASSERT_TRUE(!o2.has_value());
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, v1, nullptr, 4 },
+ { Event::MOVE_CONSTRUCT, v2, v1, 4 },
+ { Event::DESTRUCT, v1, nullptr, 4 },
+ { Event::MOVE_CONSTRUCT, v1, v2, 4 },
+ { Event::DESTRUCT, v2, nullptr, 4 },
+ { Event::VALUE_CONSTRUCT, v2, nullptr, 5 },
+ { Event::SWAP, v1, v2, 5 },
+ { Event::DESTRUCT, v1, nullptr, 5 },
+ { Event::DESTRUCT, v2, nullptr, 4 },
+ };
+ return true;
+}
+
+static bool testReset(std::vector<Event>& expected)
+{
+ cm::optional<EventLogger> o{ 4 };
+ auto const* v = &*o;
+
+ o.reset();
+
+ ASSERT_TRUE(!o.has_value());
+
+ o.reset();
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, v, nullptr, 4 },
+ { Event::DESTRUCT, v, nullptr, 4 },
+ };
+ return true;
+}
+
+static bool testEmplace(std::vector<Event>& expected)
+{
+ cm::optional<EventLogger> o{ 4 };
+
+ o.emplace(5);
+ o.reset();
+ o.emplace();
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, &*o, nullptr, 4 },
+ { Event::DESTRUCT, &*o, nullptr, 4 },
+ { Event::VALUE_CONSTRUCT, &*o, nullptr, 5 },
+ { Event::DESTRUCT, &*o, nullptr, 5 },
+ { Event::DEFAULT_CONSTRUCT, &*o, nullptr, 0 },
+ { Event::DESTRUCT, &*o, nullptr, 0 },
+ };
+ return true;
+}
+
+static bool testMakeOptional(std::vector<Event>& expected)
+{
+ EventLogger e{ 4 };
+ cm::optional<EventLogger> o1 = cm::make_optional<EventLogger>(e);
+ cm::optional<EventLogger> o2 = cm::make_optional<EventLogger>(5);
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, &e, nullptr, 4 },
+ { Event::COPY_CONSTRUCT, &*o1, &e, 4 },
+ { Event::VALUE_CONSTRUCT, &*o2, nullptr, 5 },
+ { Event::DESTRUCT, &*o2, nullptr, 5 },
+ { Event::DESTRUCT, &*o1, nullptr, 4 },
+ { Event::DESTRUCT, &e, nullptr, 4 },
+ };
+ return true;
+}
+
+static bool testMemoryRange(std::vector<Event>& expected)
+{
+ cm::optional<EventLogger> o{ 4 };
+
+ auto* ostart = &o;
+ auto* oend = ostart + 1;
+ auto* estart = &o.value();
+ auto* eend = estart + 1;
+
+ ASSERT_TRUE(static_cast<void*>(estart) >= static_cast<void*>(ostart) &&
+ static_cast<void*>(eend) <= static_cast<void*>(oend));
+
+ expected = {
+ { Event::VALUE_CONSTRUCT, &*o, nullptr, 4 },
+ { Event::DESTRUCT, &*o, nullptr, 4 },
+ };
+ return true;
+}
+
+int testOptional(int /*unused*/, char* /*unused*/ [])
+{
+ int retval = 0;
+
+#define DO_EVENT_TEST(name) \
+ do { \
+ events.clear(); \
+ std::vector<Event> expected; \
+ if (!name(expected)) { \
+ std::cout << "in " #name << std::endl; \
+ retval = 1; \
+ } else if (expected != events) { \
+ std::cout << #name " did not produce expected events" << std::endl; \
+ retval = 1; \
+ } \
+ } while (0)
+
+#define DO_TEST(name) \
+ do { \
+ if (!name()) { \
+ std::cout << "in " #name << std::endl; \
+ retval = 1; \
+ } \
+ } while (0)
+
+ DO_EVENT_TEST(testDefaultConstruct);
+ DO_EVENT_TEST(testNulloptConstruct);
+ DO_EVENT_TEST(testValueConstruct);
+ DO_EVENT_TEST(testInPlaceConstruct);
+ DO_EVENT_TEST(testCopyConstruct);
+ DO_EVENT_TEST(testMoveConstruct);
+ DO_EVENT_TEST(testNulloptAssign);
+ DO_EVENT_TEST(testCopyAssign);
+ DO_EVENT_TEST(testMoveAssign);
+ DO_EVENT_TEST(testPointer);
+ DO_EVENT_TEST(testDereference);
+ DO_EVENT_TEST(testHasValue);
+ DO_EVENT_TEST(testValue);
+ DO_TEST(testValueOr);
+ DO_EVENT_TEST(testComparison);
+ DO_EVENT_TEST(testSwap);
+ DO_EVENT_TEST(testReset);
+ DO_EVENT_TEST(testEmplace);
+ DO_EVENT_TEST(testMakeOptional);
+ DO_EVENT_TEST(testMemoryRange);
+
+ return retval;
+}
diff --git a/Tests/CMakeLib/testRST.cxx b/Tests/CMakeLib/testRST.cxx
new file mode 100644
index 0000000..28d80a5
--- /dev/null
+++ b/Tests/CMakeLib/testRST.cxx
@@ -0,0 +1,86 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include <iostream>
+#include <string>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmRST.h"
+#include "cmSystemTools.h"
+
+void reportLine(std::ostream& os, bool ret, std::string const& line, bool eol)
+{
+ if (ret) {
+ os << "\"" << line << "\" (" << (eol ? "with EOL" : "without EOL") << ")";
+ } else {
+ os << "EOF";
+ }
+}
+
+int testRST(int argc, char* argv[])
+{
+ if (argc != 2) {
+ std::cerr << "Usage: testRST <dir>" << std::endl;
+ return 1;
+ }
+ std::string dir = argv[1];
+ if (dir.empty()) {
+ dir = ".";
+ }
+ std::string a_name = "testRST.actual";
+ std::string e_name = dir + "/testRST.expect";
+
+ // Process the test RST file.
+ {
+ std::string fname = dir + "/testRST.rst";
+ std::ofstream fout(a_name.c_str());
+ if (!fout) {
+ std::cerr << "Could not open output " << a_name << std::endl;
+ return 1;
+ }
+
+ cmRST r(fout, dir);
+ if (!r.ProcessFile(fname)) {
+ std::cerr << "Could not open input " << fname << std::endl;
+ return 1;
+ }
+ }
+
+ // Compare expected and actual outputs.
+ cmsys::ifstream e_fin(e_name.c_str());
+ cmsys::ifstream a_fin(a_name.c_str());
+ if (!e_fin) {
+ std::cerr << "Could not open input " << e_name << std::endl;
+ return 1;
+ }
+ if (!a_fin) {
+ std::cerr << "Could not open input " << a_name << std::endl;
+ return 1;
+ }
+ int lineno = 0;
+ bool e_ret;
+ bool a_ret;
+ do {
+ std::string e_line;
+ std::string a_line;
+ bool e_eol;
+ bool a_eol;
+ e_ret = cmSystemTools::GetLineFromStream(e_fin, e_line, &e_eol);
+ a_ret = cmSystemTools::GetLineFromStream(a_fin, a_line, &a_eol);
+ ++lineno;
+ if (e_ret != a_ret || e_line != a_line || e_eol != a_eol) {
+ a_fin.seekg(0, std::ios::beg);
+ std::cerr << "Actual output does not match that expected on line "
+ << lineno << "." << std::endl
+ << "Expected ";
+ reportLine(std::cerr, e_ret, e_line, e_eol);
+ std::cerr << " but got ";
+ reportLine(std::cerr, a_ret, a_line, a_eol);
+ std::cerr << "." << std::endl
+ << "Actual output:" << std::endl
+ << a_fin.rdbuf();
+ return 1;
+ }
+ } while (e_ret && a_ret);
+ return 0;
+}
diff --git a/Tests/CMakeLib/testRST.expect b/Tests/CMakeLib/testRST.expect
new file mode 100644
index 0000000..4870f65
--- /dev/null
+++ b/Tests/CMakeLib/testRST.expect
@@ -0,0 +1,125 @@
+title_text
+----------
+
+Command ``some_cmd()`` explicit cmake domain.
+Command ``some_cmd()`` without target.
+Command ``some_cmd`` with target.
+Command ``some_cmd_<cmd>()`` placeholder without target.
+Command ``some_cmd_<cmd>`` placeholder with target.
+Command ``some_cmd()`` with parens.
+Command ``some_cmd(SUB)`` with subcommand.
+Command ``some_cmd(SUB)`` with subcommand and target.
+Command ``some_cmd (SUB)`` with space and subcommand and target.
+Command ``some command`` with space and target.
+Variable ``some variable`` space and target.
+Variable ``<PLACEHOLDER>_VARIABLE`` with leading placeholder.
+Variable ``VARIABLE_<PLACEHOLDER>`` with trailing placeholder.
+Variable ``<PLACEHOLDER>_VARIABLE`` with leading placeholder and target.
+Variable ``VARIABLE_<PLACEHOLDER>`` with trailing placeholder and target.
+Environment variable ``SOME_ENV_VAR``.
+Environment variable ``some env var`` with space and target.
+Generator ``Some Generator`` with space.
+Generator ``Some Generator`` with space.
+Generator expression ``SOME_GENEX``.
+Generator expression ``$<SOME_GENEX>`` with brackets.
+Generator expression ``$<SOME_GENEX:...>`` with brackets and parameter.
+Generator expression ``some genex`` with space and target.
+Generator expression ``$<SOME_GENEX>`` with brackets, space, and target.
+Generator expression ``$<SOME_GENEX:...>`` with brackets, parameter, space, and target.
+Inline literal ``~!@#$%^&*( )_+-=\\[]{}'":;,<>.?/``.
+Inline link Link Text.
+Inline link Link Text <With \-escaped Brackets>.
+Inline literal ``__`` followed by inline link Link Text.
+
+First TOC entry.
+
+|not replaced|
+Second TOC entry.
+
+CMake Module Content
+
+More CMake Module Content
+
+Bracket Comment Content
+
+[
+Bracket Comment Content
+]
+
+.. cmake:command:: some_cmd
+
+ Command some_cmd description.
+
+.. command:: other_cmd
+
+ Command other_cmd description.
+
+.. cmake:envvar:: some_var
+
+ Environment variable some_var description.
+
+.. envvar:: other_var
+
+ Environment variable other_var description.
+
+.. cmake:genex:: SOME_GENEX
+
+ Generator expression SOME_GENEX description.
+
+.. genex:: $<OTHER_GENEX>
+
+ Generator expression $<OTHER_GENEX> description.
+
+.. cmake:variable:: some_var
+
+ Variable some_var description.
+
+.. variable:: other_var
+
+ Variable other_var description.
+
+ Parsed-literal included without directive.
+ Common Indentation Removed
+ # replaced in parsed literal
+
+ # Sample CMake code block
+ if(condition)
+ message(indented)
+ endif()
+ # |not replaced in literal|
+
+A literal block starts after a line consisting of two colons
+
+::
+
+ Literal block.
+ Common Indentation Removed
+ # |not replaced in literal|
+
+or after a paragraph ending in two colons::
+
+ Literal block.
+ Common Indentation Removed
+ # |not replaced in literal|
+
+but not after a line ending in two colons::
+in the middle of a paragraph.
+
+A literal block can be empty::
+
+
+
+.. productionlist::
+ grammar: `production`
+ production: "content rendered"
+
+.. note::
+ Notes are called out.
+
+substituted text with multiple lines becomes one line
+
+End of first include.
+
+Cross-include substitution text with ``some_cmd()`` reference.
+
+End of second include.
diff --git a/Tests/CMakeLib/testRST.rst b/Tests/CMakeLib/testRST.rst
new file mode 100644
index 0000000..44931a7
--- /dev/null
+++ b/Tests/CMakeLib/testRST.rst
@@ -0,0 +1,132 @@
+.. index::
+ single: directive ignored
+
+title_text
+----------
+
+.. comment ignored
+..
+ comment ignored
+
+Command :cmake:command:`some_cmd` explicit cmake domain.
+Command :command:`some_cmd` without target.
+Command :command:`some_cmd <some_cmd>` with target.
+Command :command:`some_cmd_<cmd>` placeholder without target.
+Command :command:`some_cmd_<cmd> <some_cmd>` placeholder with target.
+Command :command:`some_cmd()` with parens.
+Command :command:`some_cmd(SUB)` with subcommand.
+Command :command:`some_cmd(SUB) <some_cmd>` with subcommand and target.
+Command :command:`some_cmd (SUB) <some_cmd>` with space and subcommand and target.
+Command :command:`some command <some_cmd>` with space and target.
+Variable :variable:`some variable <some_var>` space and target.
+Variable :variable:`<PLACEHOLDER>_VARIABLE` with leading placeholder.
+Variable :variable:`VARIABLE_<PLACEHOLDER>` with trailing placeholder.
+Variable :variable:`<PLACEHOLDER>_VARIABLE <target>` with leading placeholder and target.
+Variable :variable:`VARIABLE_<PLACEHOLDER> <target>` with trailing placeholder and target.
+Environment variable :envvar:`SOME_ENV_VAR`.
+Environment variable :envvar:`some env var <SOME_ENV_VAR>` with space and target.
+Generator :generator:`Some Generator` with space.
+Generator :cpack_gen:`Some Generator` with space.
+Generator expression :genex:`SOME_GENEX`.
+Generator expression :genex:`$<SOME_GENEX>` with brackets.
+Generator expression :genex:`$<SOME_GENEX:...>` with brackets and parameter.
+Generator expression :genex:`some genex <SOME_GENEX>` with space and target.
+Generator expression :genex:`$<SOME_GENEX> <SOME_GENEX>` with brackets, space, and target.
+Generator expression :genex:`$<SOME_GENEX:...> <SOME_GENEX>` with brackets, parameter, space, and target.
+Inline literal ``~!@#$%^&*( )_+-=\\[]{}'":;,<>.?/``.
+Inline link `Link Text <ExternalDest>`_.
+Inline link `Link Text \<With \\-escaped Brackets\> <ExternalDest>`_.
+Inline literal ``__`` followed by inline link `Link Text <InternalDest_>`_.
+
+.. |not replaced| replace:: not replaced through toctree
+.. |not replaced in literal| replace:: replaced in parsed literal
+
+.. toctree::
+ :maxdepth: 2
+
+ testRSTtoc1
+ /testRSTtoc2
+
+.. cmake-module:: testRSTmod.cmake
+
+.. cmake:command:: some_cmd
+
+ Command some_cmd description.
+
+.. command:: other_cmd
+
+ Command other_cmd description.
+
+.. cmake:envvar:: some_var
+
+ Environment variable some_var description.
+
+.. envvar:: other_var
+
+ Environment variable other_var description.
+
+.. cmake:genex:: SOME_GENEX
+
+ Generator expression SOME_GENEX description.
+
+.. genex:: $<OTHER_GENEX>
+
+ Generator expression $<OTHER_GENEX> description.
+
+.. cmake:variable:: some_var
+
+ Variable some_var description.
+
+.. variable:: other_var
+
+ Variable other_var description.
+
+.. parsed-literal::
+
+ Parsed-literal included without directive.
+ Common Indentation Removed
+ # |not replaced in literal|
+
+.. code-block:: cmake
+
+ # Sample CMake code block
+ if(condition)
+ message(indented)
+ endif()
+ # |not replaced in literal|
+
+A literal block starts after a line consisting of two colons
+
+::
+
+ Literal block.
+ Common Indentation Removed
+ # |not replaced in literal|
+
+or after a paragraph ending in two colons::
+
+ Literal block.
+ Common Indentation Removed
+ # |not replaced in literal|
+
+but not after a line ending in two colons::
+in the middle of a paragraph.
+
+A literal block can be empty::
+
+
+
+.. productionlist::
+ grammar: `production`
+ production: "content rendered"
+
+.. note::
+ Notes are called out.
+
+.. |substitution| replace::
+ |nested substitution|
+ with multiple lines becomes one line
+.. |nested substitution| replace:: substituted text
+
+.. include:: testRSTinclude1.rst
+.. include:: /testRSTinclude2.rst
diff --git a/Tests/CMakeLib/testRSTinclude1.rst b/Tests/CMakeLib/testRSTinclude1.rst
new file mode 100644
index 0000000..91d394e
--- /dev/null
+++ b/Tests/CMakeLib/testRSTinclude1.rst
@@ -0,0 +1,6 @@
+|substitution|
+
+.. |cross-include substitution| replace:: Cross-include substitution text
+ with :command:`some_cmd` reference.
+
+End of first include.
diff --git a/Tests/CMakeLib/testRSTinclude2.rst b/Tests/CMakeLib/testRSTinclude2.rst
new file mode 100644
index 0000000..f2d619c
--- /dev/null
+++ b/Tests/CMakeLib/testRSTinclude2.rst
@@ -0,0 +1,3 @@
+|cross-include substitution|
+
+End of second include.
diff --git a/Tests/CMakeLib/testRSTmod.cmake b/Tests/CMakeLib/testRSTmod.cmake
new file mode 100644
index 0000000..8b807a6
--- /dev/null
+++ b/Tests/CMakeLib/testRSTmod.cmake
@@ -0,0 +1,11 @@
+#.rst:
+# CMake Module Content
+#.rst:
+# More CMake Module Content
+#[[.rst:
+Bracket Comment Content
+# not part of content]] # not part of content
+#[=[.rst:
+[
+Bracket Comment Content
+]]=] # not part of content
diff --git a/Tests/CMakeLib/testRSTtoc1.rst b/Tests/CMakeLib/testRSTtoc1.rst
new file mode 100644
index 0000000..fa7806e
--- /dev/null
+++ b/Tests/CMakeLib/testRSTtoc1.rst
@@ -0,0 +1,2 @@
+.. |not replaced| replace:: not replaced across toctree
+First TOC entry.
diff --git a/Tests/CMakeLib/testRSTtoc2.rst b/Tests/CMakeLib/testRSTtoc2.rst
new file mode 100644
index 0000000..9fd2fcb
--- /dev/null
+++ b/Tests/CMakeLib/testRSTtoc2.rst
@@ -0,0 +1,2 @@
+|not replaced|
+Second TOC entry.
diff --git a/Tests/CMakeLib/testRange.cxx b/Tests/CMakeLib/testRange.cxx
new file mode 100644
index 0000000..4efe98e
--- /dev/null
+++ b/Tests/CMakeLib/testRange.cxx
@@ -0,0 +1,45 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "cmRange.h"
+
+#define ASSERT_TRUE(x) \
+ do { \
+ if (!(x)) { \
+ std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
+ return -1; \
+ } \
+ } while (false)
+
+int testRange(int /*unused*/, char* /*unused*/ [])
+{
+ std::vector<int> const testData = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ ASSERT_TRUE(!cmMakeRange(testData).empty());
+ ASSERT_TRUE(cmMakeRange(testData).size() == 10);
+
+ ASSERT_TRUE(!cmMakeRange(testData).advance(5).empty());
+ ASSERT_TRUE(cmMakeRange(testData).advance(5).size() == 5);
+
+ ASSERT_TRUE(cmMakeRange(testData).advance(5).retreat(5).empty());
+ ASSERT_TRUE(cmMakeRange(testData).advance(5).retreat(5).size() == 0);
+
+ ASSERT_TRUE(cmMakeRange(testData).any_of([](int n) { return n % 3 == 0; }));
+ ASSERT_TRUE(cmMakeRange(testData).all_of([](int n) { return n < 11; }));
+ ASSERT_TRUE(cmMakeRange(testData).none_of([](int n) { return n > 11; }));
+
+ std::vector<int> const evenData = { 2, 4, 6, 8, 10 };
+ ASSERT_TRUE(cmMakeRange(testData).filter([](int n) { return n % 2 == 0; }) ==
+ cmMakeRange(evenData));
+
+ std::vector<std::string> const stringRange = { "1", "2", "3", "4", "5" };
+ ASSERT_TRUE(cmMakeRange(testData)
+ .transform([](int n) { return std::to_string(n); })
+ .retreat(5) == cmMakeRange(stringRange));
+
+ return 0;
+}
diff --git a/Tests/CMakeLib/testString.cxx b/Tests/CMakeLib/testString.cxx
new file mode 100644
index 0000000..ad800cf
--- /dev/null
+++ b/Tests/CMakeLib/testString.cxx
@@ -0,0 +1,1348 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <cstddef> // IWYU pragma: keep
+#include <cstring>
+#include <iostream>
+#include <iterator>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmString.hxx"
+
+#define ASSERT_TRUE(x) \
+ do { \
+ if (!(x)) { \
+ std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
+ return false; \
+ } \
+ } while (false)
+
+static bool testConstructDefault()
+{
+ std::cout << "testConstructDefault()\n";
+ cm::String str;
+ cm::String const& str_const = str;
+ ASSERT_TRUE(bool(str_const) == false);
+ ASSERT_TRUE(str_const.data() == nullptr);
+ ASSERT_TRUE(str_const.size() == 0);
+ ASSERT_TRUE(str_const.empty());
+ ASSERT_TRUE(str_const.is_stable());
+ ASSERT_TRUE(str.c_str() == nullptr);
+ ASSERT_TRUE(str.str().empty());
+ ASSERT_TRUE(str.is_stable());
+ return true;
+}
+
+static bool testFromNullPtr(cm::String str)
+{
+ cm::String const& str_const = str;
+ ASSERT_TRUE(bool(str_const) == false);
+ ASSERT_TRUE(str_const.data() == nullptr);
+ ASSERT_TRUE(str_const.size() == 0);
+ ASSERT_TRUE(str_const.empty());
+ ASSERT_TRUE(str_const.is_stable());
+ ASSERT_TRUE(str.c_str() == nullptr);
+ ASSERT_TRUE(str.str().empty());
+ ASSERT_TRUE(str.is_stable());
+ return true;
+}
+
+static bool testConstructFromNullPtr()
+{
+ std::cout << "testConstructFromNullPtr()\n";
+ return testFromNullPtr(nullptr);
+}
+
+static bool testAssignFromNullPtr()
+{
+ std::cout << "testAssignFromNullPtr()\n";
+ cm::String str;
+ str = nullptr;
+ return testFromNullPtr(str);
+}
+
+static bool testFromCStrNull(cm::String str)
+{
+ cm::String const& str_const = str;
+ ASSERT_TRUE(bool(str_const) == false);
+ ASSERT_TRUE(str_const.data() == nullptr);
+ ASSERT_TRUE(str_const.size() == 0);
+ ASSERT_TRUE(str_const.empty());
+ ASSERT_TRUE(str_const.is_stable());
+ ASSERT_TRUE(str.c_str() == nullptr);
+ ASSERT_TRUE(str.str().empty());
+ ASSERT_TRUE(str.is_stable());
+ return true;
+}
+
+static bool testConstructFromCStrNull()
+{
+ std::cout << "testConstructFromCStrNull()\n";
+ const char* null = nullptr;
+ return testFromCStrNull(null);
+}
+
+static bool testAssignFromCStrNull()
+{
+ std::cout << "testAssignFromCStrNull()\n";
+ const char* null = nullptr;
+ cm::String str;
+ str = null;
+ return testFromCStrNull(str);
+}
+
+static char const charArray[] = "abc";
+
+static bool testFromCharArray(cm::String str)
+{
+ cm::String const& str_const = str;
+ ASSERT_TRUE(str_const.data() != charArray);
+ ASSERT_TRUE(str_const.size() == sizeof(charArray) - 1);
+ ASSERT_TRUE(str_const.is_stable());
+ ASSERT_TRUE(str.c_str() != charArray);
+ ASSERT_TRUE(str.is_stable());
+ cm::String substr = str.substr(1);
+ cm::String const& substr_const = substr;
+ ASSERT_TRUE(substr_const.data() != &charArray[1]);
+ ASSERT_TRUE(substr_const.size() == 2);
+ ASSERT_TRUE(!substr_const.is_stable());
+ ASSERT_TRUE(substr.c_str() != &charArray[1]);
+ ASSERT_TRUE(!substr.is_stable());
+ return true;
+}
+
+static bool testConstructFromCharArray()
+{
+ std::cout << "testConstructFromCharArray()\n";
+ return testFromCharArray(charArray);
+}
+
+static bool testAssignFromCharArray()
+{
+ std::cout << "testAssignFromCharArray()\n";
+ cm::String str;
+ str = charArray;
+ return testFromCharArray(str);
+}
+
+static const char* cstr = "abc";
+
+static bool testFromCStr(cm::String const& str)
+{
+ ASSERT_TRUE(str.data() != cstr);
+ ASSERT_TRUE(str.size() == 3);
+ ASSERT_TRUE(std::strncmp(str.data(), cstr, 3) == 0);
+ ASSERT_TRUE(str.is_stable());
+ return true;
+}
+
+static bool testConstructFromCStr()
+{
+ std::cout << "testConstructFromCStr()\n";
+ return testFromCStr(cstr);
+}
+
+static bool testAssignFromCStr()
+{
+ std::cout << "testAssignFromCStr()\n";
+ cm::String str;
+ str = cstr;
+ return testFromCStr(str);
+}
+
+static const std::string stdstr = "abc";
+
+static bool testFromStdString(cm::String const& str)
+{
+#if defined(_GLIBCXX_USE_CXX11_ABI) && _GLIBCXX_USE_CXX11_ABI
+ // It would be nice to check this everywhere, but several platforms
+ // still use a CoW implementation even in C++11.
+ ASSERT_TRUE(str.data() != stdstr.data());
+#endif
+ ASSERT_TRUE(str.size() == 3);
+ ASSERT_TRUE(std::strncmp(str.data(), stdstr.data(), 3) == 0);
+ ASSERT_TRUE(str.is_stable());
+ return true;
+}
+
+static bool testConstructFromStdString()
+{
+ std::cout << "testConstructFromStdString()\n";
+ return testFromStdString(stdstr);
+}
+
+static bool testAssignFromStdString()
+{
+ std::cout << "testAssignFromStdString()\n";
+ cm::String str;
+ str = stdstr;
+ return testFromStdString(str);
+}
+
+static bool testConstructFromView()
+{
+ std::cout << "testConstructFromView()\n";
+ cm::string_view view = cstr;
+ return testFromCStr(cm::String(view));
+}
+
+static bool testAssignFromView()
+{
+ std::cout << "testAssignFromView()\n";
+ cm::string_view view = cstr;
+ cm::String str;
+ str = view;
+ return testFromCStr(str);
+}
+
+static bool testFromChar(cm::String const& str)
+{
+ ASSERT_TRUE(str.size() == 1);
+ ASSERT_TRUE(std::strncmp(str.data(), "a", 1) == 0);
+ ASSERT_TRUE(str.is_stable());
+ return true;
+}
+
+static bool testConstructFromChar()
+{
+ std::cout << "testConstructFromChar()\n";
+ return testFromChar('a');
+}
+
+static bool testAssignFromChar()
+{
+ std::cout << "testAssignFromChar()\n";
+ cm::String str;
+ str = 'a';
+ return testFromChar(str);
+}
+
+static bool testConstructFromInitList()
+{
+ std::cout << "testConstructFromInitList()\n";
+ cm::String const str{ 'a', 'b', 'c' };
+ ASSERT_TRUE(str.size() == 3);
+ ASSERT_TRUE(std::strncmp(str.data(), "abc", 3) == 0);
+ ASSERT_TRUE(str.is_stable());
+ return true;
+}
+
+static bool testAssignFromInitList()
+{
+ std::cout << "testAssignFromInitList()\n";
+ cm::String str;
+ str = { 'a', 'b', 'c' };
+ ASSERT_TRUE(str.size() == 3);
+ ASSERT_TRUE(std::strncmp(str.data(), "abc", 3) == 0);
+ ASSERT_TRUE(str.is_stable());
+ return true;
+}
+
+static bool testConstructFromBuffer()
+{
+ std::cout << "testConstructFromBuffer()\n";
+ cm::String const str(cstr, 3);
+ return testFromCStr(str);
+}
+
+static bool testConstructFromInputIterator()
+{
+ std::cout << "testConstructFromInputIterator()\n";
+ cm::String const str(cstr, cstr + 3);
+ ASSERT_TRUE(str.data() != cstr);
+ ASSERT_TRUE(str.size() == 3);
+ ASSERT_TRUE(std::strncmp(str.data(), cstr, 3) == 0);
+ ASSERT_TRUE(str.is_stable());
+ return true;
+}
+
+static bool testConstructFromN()
+{
+ std::cout << "testConstructFromN()\n";
+ cm::String const str(3, 'a');
+ ASSERT_TRUE(str.size() == 3);
+ ASSERT_TRUE(std::strncmp(str.data(), "aaa", 3) == 0);
+ ASSERT_TRUE(str.is_stable());
+ return true;
+}
+
+static const auto staticStringView = "abc"_s;
+
+static bool testFromStaticStringView(cm::String str)
+{
+ cm::String const& str_const = str;
+ ASSERT_TRUE(str_const.data() == staticStringView.data());
+ ASSERT_TRUE(str_const.size() == staticStringView.size());
+ ASSERT_TRUE(!str_const.is_stable());
+ ASSERT_TRUE(str.c_str() == staticStringView);
+ ASSERT_TRUE(!str.is_stable());
+ cm::String substr = str.substr(1);
+ cm::String const& substr_const = substr;
+ ASSERT_TRUE(substr_const.data() == &staticStringView[1]);
+ ASSERT_TRUE(substr_const.size() == 2);
+ ASSERT_TRUE(!substr_const.is_stable());
+ ASSERT_TRUE(substr.c_str() == &staticStringView[1]);
+ ASSERT_TRUE(!substr.is_stable());
+ return true;
+}
+
+static bool testConstructFromStaticStringView()
+{
+ std::cout << "testConstructFromStaticStringView()\n";
+ return testFromStaticStringView(cm::String(staticStringView));
+}
+
+static bool testAssignFromStaticStringView()
+{
+ std::cout << "testAssignFromStaticStringView()\n";
+ cm::String str;
+ str = staticStringView;
+ return testFromStaticStringView(str);
+}
+
+static bool testConstructCopy()
+{
+ std::cout << "testConstructCopy()\n";
+ cm::String s1 = std::string("abc");
+ cm::String s2 = s1;
+ ASSERT_TRUE(s1.data() == s2.data());
+ ASSERT_TRUE(s1.size() == 3);
+ ASSERT_TRUE(s2.size() == 3);
+ ASSERT_TRUE(std::strncmp(s2.data(), "abc", 3) == 0);
+ ASSERT_TRUE(s1.is_stable());
+ ASSERT_TRUE(s2.is_stable());
+ return true;
+}
+
+static bool testConstructMove()
+{
+ std::cout << "testConstructMove()\n";
+ cm::String s1 = std::string("abc");
+ cm::String s2 = std::move(s1);
+ ASSERT_TRUE(s1.data() == nullptr);
+ ASSERT_TRUE(s1.size() == 0);
+ ASSERT_TRUE(s2.size() == 3);
+ ASSERT_TRUE(std::strncmp(s2.data(), "abc", 3) == 0);
+ ASSERT_TRUE(s1.is_stable());
+ ASSERT_TRUE(s2.is_stable());
+ return true;
+}
+
+static bool testAssignCopy()
+{
+ std::cout << "testAssignCopy()\n";
+ cm::String s1 = std::string("abc");
+ cm::String s2;
+ s2 = s1;
+ ASSERT_TRUE(s1.data() == s2.data());
+ ASSERT_TRUE(s1.size() == 3);
+ ASSERT_TRUE(s2.size() == 3);
+ ASSERT_TRUE(std::strncmp(s2.data(), "abc", 3) == 0);
+ ASSERT_TRUE(s1.is_stable());
+ ASSERT_TRUE(s2.is_stable());
+ return true;
+}
+
+static bool testAssignMove()
+{
+ std::cout << "testAssignMove()\n";
+ cm::String s1 = std::string("abc");
+ cm::String s2;
+ s2 = std::move(s1);
+ ASSERT_TRUE(s1.data() == nullptr);
+ ASSERT_TRUE(s1.size() == 0);
+ ASSERT_TRUE(s2.size() == 3);
+ ASSERT_TRUE(std::strncmp(s2.data(), "abc", 3) == 0);
+ ASSERT_TRUE(s1.is_stable());
+ ASSERT_TRUE(s2.is_stable());
+ return true;
+}
+
+static bool testOperatorBool()
+{
+ std::cout << "testOperatorBool()\n";
+ cm::String str;
+ ASSERT_TRUE(!str);
+ str = "";
+ ASSERT_TRUE(str);
+ str = static_cast<const char*>(nullptr);
+ ASSERT_TRUE(!str);
+ str = std::string();
+ ASSERT_TRUE(str);
+ str = nullptr;
+ ASSERT_TRUE(!str);
+ return true;
+}
+
+static bool testOperatorIndex()
+{
+ std::cout << "testOperatorIndex()\n";
+ cm::String str = "abc";
+ ASSERT_TRUE(str[0] == 'a');
+ ASSERT_TRUE(str[1] == 'b');
+ ASSERT_TRUE(str[2] == 'c');
+ return true;
+}
+
+static bool testOperatorPlusEqual()
+{
+ std::cout << "testOperatorPlusEqual()\n";
+ cm::String str = "a";
+ str += "b";
+ {
+ const char* c = "c";
+ str += c;
+ }
+ str += 'd';
+ str += std::string("e");
+ str += cm::string_view("f", 1);
+ str += cm::String("g");
+ ASSERT_TRUE(str.size() == 7);
+ ASSERT_TRUE(std::strncmp(str.data(), "abcdefg", 7) == 0);
+ ASSERT_TRUE(str.is_stable());
+ return true;
+}
+
+static bool testOperatorCompare()
+{
+ std::cout << "testOperatorCompare()\n";
+ cm::String str = "b";
+ {
+ ASSERT_TRUE(str == "b");
+ ASSERT_TRUE("b" == str);
+ ASSERT_TRUE(str != "a");
+ ASSERT_TRUE("a" != str);
+ ASSERT_TRUE(str < "c");
+ ASSERT_TRUE("a" < str);
+ ASSERT_TRUE(str > "a");
+ ASSERT_TRUE("c" > str);
+ ASSERT_TRUE(str <= "b");
+ ASSERT_TRUE("b" <= str);
+ ASSERT_TRUE(str >= "b");
+ ASSERT_TRUE("b" >= str);
+ }
+ {
+ const char* a = "a";
+ const char* b = "b";
+ const char* c = "c";
+ ASSERT_TRUE(str == b);
+ ASSERT_TRUE(b == str);
+ ASSERT_TRUE(str != a);
+ ASSERT_TRUE(a != str);
+ ASSERT_TRUE(str < c);
+ ASSERT_TRUE(a < str);
+ ASSERT_TRUE(str > a);
+ ASSERT_TRUE(c > str);
+ ASSERT_TRUE(str <= b);
+ ASSERT_TRUE(b <= str);
+ ASSERT_TRUE(str >= b);
+ ASSERT_TRUE(b >= str);
+ }
+ {
+ ASSERT_TRUE(str == 'b');
+ ASSERT_TRUE('b' == str);
+ ASSERT_TRUE(str != 'a');
+ ASSERT_TRUE('a' != str);
+ ASSERT_TRUE(str < 'c');
+ ASSERT_TRUE('a' < str);
+ ASSERT_TRUE(str > 'a');
+ ASSERT_TRUE('c' > str);
+ ASSERT_TRUE(str <= 'b');
+ ASSERT_TRUE('b' <= str);
+ ASSERT_TRUE(str >= 'b');
+ ASSERT_TRUE('b' >= str);
+ }
+ {
+ std::string const a = "a";
+ std::string const b = "b";
+ std::string const c = "c";
+ ASSERT_TRUE(str == b);
+ ASSERT_TRUE(b == str);
+ ASSERT_TRUE(str != a);
+ ASSERT_TRUE(a != str);
+ ASSERT_TRUE(str < c);
+ ASSERT_TRUE(a < str);
+ ASSERT_TRUE(str > a);
+ ASSERT_TRUE(c > str);
+ ASSERT_TRUE(str <= b);
+ ASSERT_TRUE(b <= str);
+ ASSERT_TRUE(str >= b);
+ ASSERT_TRUE(b >= str);
+ }
+ {
+ cm::string_view const a("a", 1);
+ cm::string_view const b("b", 1);
+ cm::string_view const c("c", 1);
+ ASSERT_TRUE(str == b);
+ ASSERT_TRUE(b == str);
+ ASSERT_TRUE(str != a);
+ ASSERT_TRUE(a != str);
+ ASSERT_TRUE(str < c);
+ ASSERT_TRUE(a < str);
+ ASSERT_TRUE(str > a);
+ ASSERT_TRUE(c > str);
+ ASSERT_TRUE(str <= b);
+ ASSERT_TRUE(b <= str);
+ ASSERT_TRUE(str >= b);
+ ASSERT_TRUE(b >= str);
+ }
+ {
+ cm::String const a("a");
+ cm::String const b("b");
+ cm::String const c("c");
+ ASSERT_TRUE(str == b);
+ ASSERT_TRUE(b == str);
+ ASSERT_TRUE(str != a);
+ ASSERT_TRUE(a != str);
+ ASSERT_TRUE(str < c);
+ ASSERT_TRUE(a < str);
+ ASSERT_TRUE(str > a);
+ ASSERT_TRUE(c > str);
+ ASSERT_TRUE(str <= b);
+ ASSERT_TRUE(b <= str);
+ ASSERT_TRUE(str >= b);
+ ASSERT_TRUE(b >= str);
+ }
+ return true;
+}
+
+static bool testOperatorStream()
+{
+ std::cout << "testOperatorStream()\n";
+ std::ostringstream ss;
+ ss << "a" << cm::String("b") << 'c';
+ ASSERT_TRUE(ss.str() == "abc");
+ return true;
+}
+
+static bool testOperatorStdStringPlusEqual()
+{
+ std::cout << "testOperatorStdStringPlusEqual()\n";
+ std::string s = "a";
+ s += cm::String("b");
+ ASSERT_TRUE(s == "ab");
+ return true;
+}
+
+static bool testMethod_borrow()
+{
+ std::cout << "testMethod_borrow()\n";
+ std::string s = "abc";
+ cm::String str = cm::String::borrow(s);
+ ASSERT_TRUE(str.data() == s.data());
+ ASSERT_TRUE(str.size() == s.size());
+ ASSERT_TRUE(str == s);
+ return true;
+}
+
+static bool testMethod_view()
+{
+ std::cout << "testMethod_view()\n";
+ cm::String str;
+ ASSERT_TRUE(str.view().data() == nullptr);
+ ASSERT_TRUE(str.view().size() == 0);
+ str = charArray;
+ ASSERT_TRUE(str.view().data() != charArray);
+ ASSERT_TRUE(str.view().size() == sizeof(charArray) - 1);
+ str = std::string("abc");
+ ASSERT_TRUE(str.view().size() == 3);
+ ASSERT_TRUE(strncmp(str.view().data(), "abc", 3) == 0);
+ return true;
+}
+
+static bool testMethod_empty()
+{
+ std::cout << "testMethod_empty()\n";
+ cm::String str;
+ ASSERT_TRUE(str.empty());
+ str = "";
+ ASSERT_TRUE(str.empty());
+ str = "abc";
+ ASSERT_TRUE(!str.empty());
+ str = std::string();
+ ASSERT_TRUE(str.empty());
+ str = std::string("abc");
+ ASSERT_TRUE(!str.empty());
+ return true;
+}
+
+static bool testMethod_length()
+{
+ std::cout << "testMethod_length()\n";
+ cm::String str;
+ ASSERT_TRUE(str.length() == 0);
+ str = "";
+ ASSERT_TRUE(str.length() == 0);
+ str = "abc";
+ ASSERT_TRUE(str.length() == 3);
+ str = std::string();
+ ASSERT_TRUE(str.length() == 0);
+ str = std::string("abc");
+ ASSERT_TRUE(str.length() == 3);
+ return true;
+}
+
+static bool testMethod_at()
+{
+ std::cout << "testMethod_at()\n";
+ cm::String str = "abc";
+ ASSERT_TRUE(str.at(0) == 'a');
+ ASSERT_TRUE(str.at(1) == 'b');
+ ASSERT_TRUE(str.at(2) == 'c');
+ bool except_out_of_range = false;
+ try {
+ str.at(3);
+ } catch (std::out_of_range&) {
+ except_out_of_range = true;
+ }
+ ASSERT_TRUE(except_out_of_range);
+ return true;
+}
+
+static bool testMethod_front_back()
+{
+ std::cout << "testMethod_front_back()\n";
+ cm::String str = "abc";
+ ASSERT_TRUE(str.front() == 'a');
+ ASSERT_TRUE(str.back() == 'c');
+ return true;
+}
+
+static bool testMethodIterators()
+{
+ std::cout << "testMethodIterators()\n";
+ cm::String str = "abc";
+ ASSERT_TRUE(*str.begin() == 'a');
+ ASSERT_TRUE(*(str.end() - 1) == 'c');
+ ASSERT_TRUE(str.end() - str.begin() == 3);
+ ASSERT_TRUE(*str.cbegin() == 'a');
+ ASSERT_TRUE(*(str.cend() - 1) == 'c');
+ ASSERT_TRUE(str.cend() - str.cbegin() == 3);
+ ASSERT_TRUE(*str.rbegin() == 'c');
+ ASSERT_TRUE(*(str.rend() - 1) == 'a');
+ ASSERT_TRUE(str.rend() - str.rbegin() == 3);
+ ASSERT_TRUE(*str.crbegin() == 'c');
+ ASSERT_TRUE(*(str.crend() - 1) == 'a');
+ ASSERT_TRUE(str.crend() - str.crbegin() == 3);
+ return true;
+}
+
+static bool testMethod_clear()
+{
+ std::cout << "testMethod_clear()\n";
+ cm::String str = "abc";
+ ASSERT_TRUE(!str.empty());
+ str.clear();
+ ASSERT_TRUE(str.empty());
+ return true;
+}
+
+static bool testMethod_insert()
+{
+ std::cout << "testMethod_insert()\n";
+ cm::String str = "abc";
+ str.insert(1, 2, 'd').insert(0, 1, '_');
+ ASSERT_TRUE(str.size() == 6);
+ ASSERT_TRUE(std::strncmp(str.data(), "_addbc", 6) == 0);
+ return true;
+}
+
+static bool testMethod_erase()
+{
+ std::cout << "testMethod_erase()\n";
+ cm::String str = "abcdefg";
+ str.erase(5).erase(1, 2);
+ ASSERT_TRUE(str.size() == 3);
+ ASSERT_TRUE(std::strncmp(str.data(), "ade", 3) == 0);
+ return true;
+}
+
+static bool testMethod_push_back()
+{
+ std::cout << "testMethod_push_back()\n";
+ cm::String str = "abc";
+ str.push_back('d');
+ ASSERT_TRUE(str == "abcd");
+ return true;
+}
+
+static bool testMethod_pop_back()
+{
+ std::cout << "testMethod_pop_back()\n";
+ cm::String str = "abc";
+ str.pop_back();
+ ASSERT_TRUE(str == "ab");
+ return true;
+}
+
+static bool testMethod_replace()
+{
+ std::cout << "testMethod_replace()\n";
+ {
+ cm::String str = "abcd";
+ const char* bc = "bc";
+ ASSERT_TRUE(str.replace(1, 2, "BC") == "aBCd");
+ ASSERT_TRUE(str.replace(1, 2, bc) == "abcd");
+ ASSERT_TRUE(str.replace(1, 2, 'x') == "axd");
+ ASSERT_TRUE(str.replace(1, 1, std::string("bc")) == "abcd");
+ ASSERT_TRUE(str.replace(1, 2, cm::string_view("BC", 2)) == "aBCd");
+ ASSERT_TRUE(str.replace(1, 2, cm::String("bc")) == "abcd");
+ }
+ {
+ cm::String str = "abcd";
+ const char* bc = "bc";
+ ASSERT_TRUE(str.replace(str.begin() + 1, str.begin() + 3, "BC") == "aBCd");
+ ASSERT_TRUE(str.replace(str.begin() + 1, str.begin() + 3, bc) == "abcd");
+ ASSERT_TRUE(str.replace(str.begin() + 1, str.begin() + 3, 'x') == "axd");
+ ASSERT_TRUE(str.replace(str.begin() + 1, str.begin() + 2,
+ std::string("bc")) == "abcd");
+ ASSERT_TRUE(str.replace(str.begin() + 1, str.begin() + 3,
+ cm::string_view("BC", 2)) == "aBCd");
+ ASSERT_TRUE(str.replace(str.begin() + 1, str.begin() + 3,
+ cm::String("bc")) == "abcd");
+ }
+ {
+ cm::String str = "abcd";
+ const char* bc = "_bc";
+ ASSERT_TRUE(str.replace(1, 2, "_BC_", 1, 2) == "aBCd");
+ ASSERT_TRUE(str.replace(1, 2, bc, 1) == "abcd");
+ ASSERT_TRUE(str.replace(1, 2, 'x', 0) == "axd");
+ ASSERT_TRUE(str.replace(1, 1, std::string("_bc_"), 1, 2) == "abcd");
+ ASSERT_TRUE(str.replace(1, 2, cm::string_view("_BC", 3), 1) == "aBCd");
+ ASSERT_TRUE(str.replace(1, 2, cm::String("_bc_"), 1, 2) == "abcd");
+ }
+ {
+ cm::String str = "abcd";
+ const char* bc = "_bc_";
+ ASSERT_TRUE(str.replace(1, 2, 2, 'x') == "axxd");
+ ASSERT_TRUE(str.replace(str.begin() + 1, str.begin() + 3, 2, 'y') ==
+ "ayyd");
+ ASSERT_TRUE(
+ str.replace(str.begin() + 1, str.begin() + 3, bc + 1, bc + 3) == "abcd");
+ }
+ return true;
+}
+
+static bool testMethod_copy()
+{
+ std::cout << "testMethod_copy()\n";
+ cm::String str = "abc";
+ char dest[2];
+ cm::String::size_type n = str.copy(dest, 2, 1);
+ ASSERT_TRUE(n == 2);
+ ASSERT_TRUE(std::strncmp(dest, "bc", 2) == 0);
+ n = str.copy(dest, 2);
+ ASSERT_TRUE(n == 2);
+ ASSERT_TRUE(std::strncmp(dest, "ab", 2) == 0);
+ return true;
+}
+
+static bool testMethod_resize()
+{
+ std::cout << "testMethod_resize()\n";
+ cm::String str = "abc";
+ str.resize(3);
+ ASSERT_TRUE(str == "abc");
+ str.resize(2);
+ ASSERT_TRUE(str == "ab");
+ str.resize(3, 'c');
+ ASSERT_TRUE(str == "abc");
+ return true;
+}
+
+static bool testMethod_swap()
+{
+ std::cout << "testMethod_swap()\n";
+ cm::String str1 = std::string("1");
+ cm::String str2 = std::string("2");
+ str1.swap(str2);
+ ASSERT_TRUE(str1 == "2");
+ ASSERT_TRUE(str2 == "1");
+ return true;
+}
+
+static bool testMethod_substr_AtEnd(cm::String str)
+{
+ cm::String substr = str.substr(1);
+ ASSERT_TRUE(substr.data() == str.data() + 1);
+ ASSERT_TRUE(substr.size() == 2);
+ ASSERT_TRUE(!substr.is_stable());
+
+ // c_str() at the end of the buffer does not internally mutate.
+ ASSERT_TRUE(std::strcmp(substr.c_str(), "bc") == 0);
+ ASSERT_TRUE(substr.c_str() == str.data() + 1);
+ ASSERT_TRUE(substr.data() == str.data() + 1);
+ ASSERT_TRUE(substr.size() == 2);
+ ASSERT_TRUE(!substr.is_stable());
+
+ // str() internally mutates.
+ ASSERT_TRUE(substr.str() == "bc");
+ ASSERT_TRUE(substr.is_stable());
+ ASSERT_TRUE(substr.data() != str.data() + 1);
+ ASSERT_TRUE(substr.size() == 2);
+ ASSERT_TRUE(substr.c_str() != str.data() + 1);
+ ASSERT_TRUE(std::strcmp(substr.c_str(), "bc") == 0);
+ return true;
+}
+
+static bool testMethod_substr_AtEndBorrowed()
+{
+ std::cout << "testMethod_substr_AtEndBorrowed()\n";
+ return testMethod_substr_AtEnd(cm::String("abc"_s));
+}
+
+static bool testMethod_substr_AtEndOwned()
+{
+ std::cout << "testMethod_substr_AtEndOwned()\n";
+ return testMethod_substr_AtEnd(std::string("abc"));
+}
+
+static bool testMethod_substr_AtStart(cm::String str)
+{
+ {
+ cm::String substr = str.substr(0, 2);
+ ASSERT_TRUE(substr.data() == str.data());
+ ASSERT_TRUE(substr.size() == 2);
+
+ // c_str() not at the end of the buffer internally mutates.
+ const char* substr_c = substr.c_str();
+ ASSERT_TRUE(std::strcmp(substr_c, "ab") == 0);
+ ASSERT_TRUE(substr_c != str.data());
+ ASSERT_TRUE(substr.data() != str.data());
+ ASSERT_TRUE(substr.size() == 2);
+ ASSERT_TRUE(substr.is_stable());
+
+ // str() does not need to internally mutate after c_str() did so
+ ASSERT_TRUE(substr.str() == "ab");
+ ASSERT_TRUE(substr.is_stable());
+ ASSERT_TRUE(substr.data() == substr_c);
+ ASSERT_TRUE(substr.size() == 2);
+ ASSERT_TRUE(substr.c_str() == substr_c);
+ }
+
+ {
+ cm::String substr = str.substr(0, 2);
+ ASSERT_TRUE(substr.data() == str.data());
+ ASSERT_TRUE(substr.size() == 2);
+ ASSERT_TRUE(!substr.is_stable());
+
+ // str() internally mutates.
+ ASSERT_TRUE(substr.str() == "ab");
+ ASSERT_TRUE(substr.is_stable());
+ ASSERT_TRUE(substr.data() != str.data());
+ ASSERT_TRUE(substr.size() == 2);
+ ASSERT_TRUE(substr.c_str() != str.data());
+
+ // c_str() does not internally after str() did so
+ const char* substr_c = substr.c_str();
+ ASSERT_TRUE(std::strcmp(substr_c, "ab") == 0);
+ ASSERT_TRUE(substr_c == substr.data());
+ ASSERT_TRUE(substr.size() == 2);
+ ASSERT_TRUE(substr.is_stable());
+ }
+
+ return true;
+}
+
+static bool testMethod_substr_AtStartBorrowed()
+{
+ std::cout << "testMethod_substr_AtStartBorrowed()\n";
+ return testMethod_substr_AtStart(cm::String("abc"_s));
+}
+
+static bool testMethod_substr_AtStartOwned()
+{
+ std::cout << "testMethod_substr_AtStartOwned()\n";
+ return testMethod_substr_AtStart(std::string("abc"));
+}
+
+static bool testMethod_compare()
+{
+ std::cout << "testMethod_compare()\n";
+ cm::String str = "b";
+ ASSERT_TRUE(str.compare("a") > 0);
+ ASSERT_TRUE(str.compare("b") == 0);
+ ASSERT_TRUE(str.compare("c") < 0);
+ {
+ const char* a = "a";
+ const char* b = "b";
+ const char* c = "c";
+ ASSERT_TRUE(str.compare(a) > 0);
+ ASSERT_TRUE(str.compare(b) == 0);
+ ASSERT_TRUE(str.compare(c) < 0);
+ }
+ ASSERT_TRUE(str.compare('a') > 0);
+ ASSERT_TRUE(str.compare('b') == 0);
+ ASSERT_TRUE(str.compare('c') < 0);
+ ASSERT_TRUE(str.compare(std::string("a")) > 0);
+ ASSERT_TRUE(str.compare(std::string("b")) == 0);
+ ASSERT_TRUE(str.compare(std::string("c")) < 0);
+ ASSERT_TRUE(str.compare(cm::string_view("a_", 1)) > 0);
+ ASSERT_TRUE(str.compare(cm::string_view("b_", 1)) == 0);
+ ASSERT_TRUE(str.compare(cm::string_view("c_", 1)) < 0);
+ ASSERT_TRUE(str.compare(cm::String("a")) > 0);
+ ASSERT_TRUE(str.compare(cm::String("b")) == 0);
+ ASSERT_TRUE(str.compare(cm::String("c")) < 0);
+ ASSERT_TRUE(str.compare(0, 1, cm::string_view("a", 1)) > 0);
+ ASSERT_TRUE(str.compare(1, 0, cm::string_view("", 0)) == 0);
+ ASSERT_TRUE(str.compare(0, 1, cm::string_view("ac", 2), 1, 1) < 0);
+ ASSERT_TRUE(str.compare(1, 0, "") == 0);
+ ASSERT_TRUE(str.compare(1, 0, "_", 0) == 0);
+ return true;
+}
+
+static bool testMethod_find()
+{
+ std::cout << "testMethod_find()\n";
+ cm::String str = "abcabc";
+ ASSERT_TRUE(str.find("a") == 0);
+ ASSERT_TRUE(str.find("a", 1) == 3);
+ {
+ const char* a = "a";
+ ASSERT_TRUE(str.find(a) == 0);
+ ASSERT_TRUE(str.find(a, 1) == 3);
+ }
+ ASSERT_TRUE(str.find('a') == 0);
+ ASSERT_TRUE(str.find('a', 1) == 3);
+ ASSERT_TRUE(str.find(std::string("a")) == 0);
+ ASSERT_TRUE(str.find(std::string("a"), 1) == 3);
+ ASSERT_TRUE(str.find(cm::string_view("a_", 1)) == 0);
+ ASSERT_TRUE(str.find(cm::string_view("a_", 1), 1) == 3);
+ ASSERT_TRUE(str.find(cm::String("a")) == 0);
+ ASSERT_TRUE(str.find(cm::String("a"), 1) == 3);
+ ASSERT_TRUE(str.find("ab_", 1, 2) == 3);
+ return true;
+}
+
+static bool testMethod_rfind()
+{
+ std::cout << "testMethod_rfind()\n";
+ cm::String str = "abcabc";
+ ASSERT_TRUE(str.rfind("a") == 3);
+ ASSERT_TRUE(str.rfind("a", 1) == 0);
+ {
+ const char* a = "a";
+ ASSERT_TRUE(str.rfind(a) == 3);
+ ASSERT_TRUE(str.rfind(a, 1) == 0);
+ }
+ ASSERT_TRUE(str.rfind('a') == 3);
+ ASSERT_TRUE(str.rfind('a', 1) == 0);
+ ASSERT_TRUE(str.rfind(std::string("a")) == 3);
+ ASSERT_TRUE(str.rfind(std::string("a"), 1) == 0);
+ ASSERT_TRUE(str.rfind(cm::string_view("a_", 1)) == 3);
+ ASSERT_TRUE(str.rfind(cm::string_view("a_", 1), 1) == 0);
+ ASSERT_TRUE(str.rfind(cm::String("a")) == 3);
+ ASSERT_TRUE(str.rfind(cm::String("a"), 1) == 0);
+ ASSERT_TRUE(str.rfind("ab_", 1, 2) == 0);
+ return true;
+}
+
+static bool testMethod_find_first_of()
+{
+ std::cout << "testMethod_find_first_of()\n";
+ cm::String str = "abcabc";
+ ASSERT_TRUE(str.find_first_of("_a") == 0);
+ ASSERT_TRUE(str.find_first_of("_a", 1) == 3);
+ {
+ const char* a = "_a";
+ ASSERT_TRUE(str.find_first_of(a) == 0);
+ ASSERT_TRUE(str.find_first_of(a, 1) == 3);
+ }
+ ASSERT_TRUE(str.find_first_of('a') == 0);
+ ASSERT_TRUE(str.find_first_of('a', 1) == 3);
+ ASSERT_TRUE(str.find_first_of(std::string("_a")) == 0);
+ ASSERT_TRUE(str.find_first_of(std::string("_a"), 1) == 3);
+ ASSERT_TRUE(str.find_first_of(cm::string_view("ba_", 1)) == 1);
+ ASSERT_TRUE(str.find_first_of(cm::string_view("ba_", 1), 2) == 4);
+ ASSERT_TRUE(str.find_first_of(cm::String("ab")) == 0);
+ ASSERT_TRUE(str.find_first_of(cm::String("ab"), 2) == 3);
+ ASSERT_TRUE(str.find_first_of("_ab", 1, 2) == 3);
+ return true;
+}
+
+static bool testMethod_find_first_not_of()
+{
+ std::cout << "testMethod_find_first_not_of()\n";
+ cm::String str = "abcabc";
+ ASSERT_TRUE(str.find_first_not_of("_a") == 1);
+ ASSERT_TRUE(str.find_first_not_of("_a", 2) == 2);
+ {
+ const char* a = "_a";
+ ASSERT_TRUE(str.find_first_not_of(a) == 1);
+ ASSERT_TRUE(str.find_first_not_of(a, 2) == 2);
+ }
+ ASSERT_TRUE(str.find_first_not_of('a') == 1);
+ ASSERT_TRUE(str.find_first_not_of('a', 2) == 2);
+ ASSERT_TRUE(str.find_first_not_of(std::string("_a")) == 1);
+ ASSERT_TRUE(str.find_first_not_of(std::string("_a"), 2) == 2);
+ ASSERT_TRUE(str.find_first_not_of(cm::string_view("ba_", 1)) == 0);
+ ASSERT_TRUE(str.find_first_not_of(cm::string_view("ba_", 1), 1) == 2);
+ ASSERT_TRUE(str.find_first_not_of(cm::String("_a")) == 1);
+ ASSERT_TRUE(str.find_first_not_of(cm::String("_a"), 2) == 2);
+ ASSERT_TRUE(str.find_first_not_of("_bca", 1, 3) == 3);
+ return true;
+}
+
+static bool testMethod_find_last_of()
+{
+ std::cout << "testMethod_find_last_of()\n";
+ cm::String str = "abcabc";
+ ASSERT_TRUE(str.find_last_of("_a") == 3);
+ ASSERT_TRUE(str.find_last_of("_a", 1) == 0);
+ {
+ const char* a = "_a";
+ ASSERT_TRUE(str.find_last_of(a) == 3);
+ ASSERT_TRUE(str.find_last_of(a, 1) == 0);
+ }
+ ASSERT_TRUE(str.find_last_of('a') == 3);
+ ASSERT_TRUE(str.find_last_of('a', 1) == 0);
+ ASSERT_TRUE(str.find_last_of(std::string("_a")) == 3);
+ ASSERT_TRUE(str.find_last_of(std::string("_a"), 1) == 0);
+ ASSERT_TRUE(str.find_last_of(cm::string_view("ba_", 1)) == 4);
+ ASSERT_TRUE(str.find_last_of(cm::string_view("ba_", 1), 2) == 1);
+ ASSERT_TRUE(str.find_last_of(cm::String("ab")) == 4);
+ ASSERT_TRUE(str.find_last_of(cm::String("ab"), 2) == 1);
+ ASSERT_TRUE(str.find_last_of("_ab", 1, 2) == 0);
+ return true;
+}
+
+static bool testMethod_find_last_not_of()
+{
+ std::cout << "testMethod_find_last_not_of()\n";
+ cm::String str = "abcabc";
+ ASSERT_TRUE(str.find_last_not_of("_a") == 5);
+ ASSERT_TRUE(str.find_last_not_of("_a", 1) == 1);
+ {
+ const char* a = "_a";
+ ASSERT_TRUE(str.find_last_not_of(a) == 5);
+ ASSERT_TRUE(str.find_last_not_of(a, 1) == 1);
+ }
+ ASSERT_TRUE(str.find_last_not_of('a') == 5);
+ ASSERT_TRUE(str.find_last_not_of('a', 1) == 1);
+ ASSERT_TRUE(str.find_last_not_of(std::string("_a")) == 5);
+ ASSERT_TRUE(str.find_last_not_of(std::string("_a"), 1) == 1);
+ ASSERT_TRUE(str.find_last_not_of(cm::string_view("cb_", 1)) == 4);
+ ASSERT_TRUE(str.find_last_not_of(cm::string_view("cb_", 1), 2) == 1);
+ ASSERT_TRUE(str.find_last_not_of(cm::String("_a")) == 5);
+ ASSERT_TRUE(str.find_last_not_of(cm::String("_a"), 1) == 1);
+ ASSERT_TRUE(str.find_last_not_of("cb_", 2, 2) == 0);
+ return true;
+}
+
+static bool testAddition()
+{
+ std::cout << "testAddition()\n";
+ {
+ ASSERT_TRUE(cm::String("a") + "b" == "ab");
+ ASSERT_TRUE("ab" == "a" + cm::String("b"));
+ ASSERT_TRUE("a" + cm::String("b") + "c" == "abc");
+ ASSERT_TRUE("abc" == "a" + cm::String("b") + "c");
+ ASSERT_TRUE("a" + (cm::String("b") + "c") + "d" == "abcd");
+ ASSERT_TRUE("abcd" == "a" + (cm::String("b") + "c") + "d");
+ }
+ {
+ ASSERT_TRUE(cm::String("a"_s) + "b"_s == "ab"_s);
+ ASSERT_TRUE("ab"_s == "a"_s + cm::String("b"_s));
+ ASSERT_TRUE("a"_s + cm::String("b"_s) + "c"_s == "abc"_s);
+ ASSERT_TRUE("abc"_s == "a"_s + cm::String("b"_s) + "c"_s);
+ ASSERT_TRUE("a"_s + (cm::String("b"_s) + "c"_s) + "d"_s == "abcd"_s);
+ ASSERT_TRUE("abcd"_s == "a"_s + (cm::String("b"_s) + "c"_s) + "d"_s);
+ }
+ {
+ const char* a = "a";
+ const char* b = "b";
+ const char* ab = "ab";
+ ASSERT_TRUE(cm::String(a) + b == ab);
+ ASSERT_TRUE(ab == a + cm::String(b));
+ const char* c = "c";
+ const char* abc = "abc";
+ ASSERT_TRUE(a + cm::String(b) + c == abc);
+ ASSERT_TRUE(abc == a + cm::String(b) + c);
+ const char* d = "d";
+ const char* abcd = "abcd";
+ ASSERT_TRUE(a + (cm::String(b) + c) + d == abcd);
+ ASSERT_TRUE(abcd == a + (cm::String(b) + c) + d);
+ }
+ {
+ ASSERT_TRUE(cm::String('a') + 'b' == "ab");
+ ASSERT_TRUE("ab" == 'a' + cm::String('b'));
+ ASSERT_TRUE('a' + cm::String('b') + 'c' == "abc");
+ ASSERT_TRUE("abc" == 'a' + cm::String('b') + 'c');
+ ASSERT_TRUE('a' + (cm::String('b') + 'c') + 'd' == "abcd");
+ ASSERT_TRUE("abcd" == 'a' + (cm::String('b') + 'c') + 'd');
+ }
+ {
+ std::string a = "a";
+ std::string b = "b";
+ std::string ab = "ab";
+ ASSERT_TRUE(cm::String(a) + b == ab);
+ ASSERT_TRUE(ab == a + cm::String(b));
+ std::string c = "c";
+ std::string abc = "abc";
+ ASSERT_TRUE(a + cm::String(b) + c == abc);
+ ASSERT_TRUE(abc == a + cm::String(b) + c);
+ std::string d = "d";
+ std::string abcd = "abcd";
+ ASSERT_TRUE(a + (cm::String(b) + c) + d == abcd);
+ ASSERT_TRUE(abcd == a + (cm::String(b) + c) + d);
+ }
+ {
+ cm::string_view a("a", 1);
+ cm::string_view b("b", 1);
+ cm::string_view ab("ab", 2);
+ ASSERT_TRUE(cm::String(a) + b == ab);
+ ASSERT_TRUE(ab == a + cm::String(b));
+ cm::string_view c("c", 1);
+ cm::string_view abc("abc", 3);
+ ASSERT_TRUE(a + cm::String(b) + c == abc);
+ ASSERT_TRUE(abc == a + cm::String(b) + c);
+ cm::string_view d("d", 1);
+ cm::string_view abcd("abcd", 4);
+ ASSERT_TRUE(a + (cm::String(b) + c) + d == abcd);
+ ASSERT_TRUE(abcd == a + (cm::String(b) + c) + d);
+ }
+ {
+ cm::String a = "a";
+ cm::String b = "b";
+ cm::String ab = "ab";
+ ASSERT_TRUE(a + b == ab);
+ ASSERT_TRUE(ab == a + b);
+ cm::String c = "c";
+ cm::String abc = "abc";
+ ASSERT_TRUE(a + cm::String(b) + c == abc);
+ ASSERT_TRUE(abc == a + cm::String(b) + c);
+ cm::String d = "d";
+ cm::String abcd = "abcd";
+ ASSERT_TRUE(a + (cm::String(b) + c) + d == abcd);
+ ASSERT_TRUE(abcd == a + (cm::String(b) + c) + d);
+ }
+ {
+ cm::String str;
+ str += "a" + cm::String("b") + 'c';
+ ASSERT_TRUE(str == "abc");
+ ASSERT_TRUE(str.is_stable());
+ }
+ {
+ std::string s;
+ s += "a" + cm::String("b") + 'c';
+ ASSERT_TRUE(s == "abc");
+ }
+ {
+ std::ostringstream ss;
+ ss << ("a" + cm::String("b") + 'c');
+ ASSERT_TRUE(ss.str() == "abc");
+ }
+ return true;
+}
+
+static bool testStability()
+{
+ std::cout << "testStability()\n";
+ cm::String str("abc"_s);
+ ASSERT_TRUE(!str.is_stable());
+ ASSERT_TRUE(str.str_if_stable() == nullptr);
+ str.stabilize();
+ ASSERT_TRUE(str.is_stable());
+ std::string const* str_if_stable = str.str_if_stable();
+ ASSERT_TRUE(str_if_stable != nullptr);
+ ASSERT_TRUE(*str_if_stable == "abc");
+ str.stabilize();
+ ASSERT_TRUE(str.is_stable());
+ ASSERT_TRUE(str.str_if_stable() == str_if_stable);
+ return true;
+}
+
+int testString(int /*unused*/, char* /*unused*/ [])
+{
+ if (!testConstructDefault()) {
+ return 1;
+ }
+ if (!testConstructFromNullPtr()) {
+ return 1;
+ }
+ if (!testConstructFromCStrNull()) {
+ return 1;
+ }
+ if (!testConstructFromCharArray()) {
+ return 1;
+ }
+ if (!testConstructFromCStr()) {
+ return 1;
+ }
+ if (!testConstructFromStdString()) {
+ return 1;
+ }
+ if (!testConstructFromView()) {
+ return 1;
+ }
+ if (!testConstructFromChar()) {
+ return 1;
+ }
+ if (!testConstructFromInitList()) {
+ return 1;
+ }
+ if (!testConstructFromBuffer()) {
+ return 1;
+ }
+ if (!testConstructFromInputIterator()) {
+ return 1;
+ }
+ if (!testConstructFromN()) {
+ return 1;
+ }
+ if (!testConstructFromStaticStringView()) {
+ return 1;
+ }
+ if (!testConstructCopy()) {
+ return 1;
+ }
+ if (!testConstructMove()) {
+ return 1;
+ }
+ if (!testAssignCopy()) {
+ return 1;
+ }
+ if (!testAssignMove()) {
+ return 1;
+ }
+ if (!testAssignFromChar()) {
+ return 1;
+ }
+ if (!testAssignFromView()) {
+ return 1;
+ }
+ if (!testAssignFromStdString()) {
+ return 1;
+ }
+ if (!testAssignFromCStr()) {
+ return 1;
+ }
+ if (!testAssignFromCharArray()) {
+ return 1;
+ }
+ if (!testAssignFromCStrNull()) {
+ return 1;
+ }
+ if (!testAssignFromNullPtr()) {
+ return 1;
+ }
+ if (!testAssignFromInitList()) {
+ return 1;
+ }
+ if (!testAssignFromStaticStringView()) {
+ return 1;
+ }
+ if (!testOperatorBool()) {
+ return 1;
+ }
+ if (!testOperatorIndex()) {
+ return 1;
+ }
+ if (!testOperatorPlusEqual()) {
+ return 1;
+ }
+ if (!testOperatorCompare()) {
+ return 1;
+ }
+ if (!testOperatorStream()) {
+ return 1;
+ }
+ if (!testOperatorStdStringPlusEqual()) {
+ return 1;
+ }
+ if (!testMethod_borrow()) {
+ return 1;
+ }
+ if (!testMethod_view()) {
+ return 1;
+ }
+ if (!testMethod_empty()) {
+ return 1;
+ }
+ if (!testMethod_length()) {
+ return 1;
+ }
+ if (!testMethod_at()) {
+ return 1;
+ }
+ if (!testMethod_front_back()) {
+ return 1;
+ }
+ if (!testMethod_clear()) {
+ return 1;
+ }
+ if (!testMethod_insert()) {
+ return 1;
+ }
+ if (!testMethod_erase()) {
+ return 1;
+ }
+ if (!testMethod_push_back()) {
+ return 1;
+ }
+ if (!testMethod_pop_back()) {
+ return 1;
+ }
+ if (!testMethod_replace()) {
+ return 1;
+ }
+ if (!testMethod_copy()) {
+ return 1;
+ }
+ if (!testMethod_resize()) {
+ return 1;
+ }
+ if (!testMethod_swap()) {
+ return 1;
+ }
+ if (!testMethodIterators()) {
+ return 1;
+ }
+ if (!testMethod_substr_AtEndBorrowed()) {
+ return 1;
+ }
+ if (!testMethod_substr_AtEndOwned()) {
+ return 1;
+ }
+ if (!testMethod_substr_AtStartBorrowed()) {
+ return 1;
+ }
+ if (!testMethod_substr_AtStartOwned()) {
+ return 1;
+ }
+ if (!testMethod_compare()) {
+ return 1;
+ }
+ if (!testMethod_find()) {
+ return 1;
+ }
+ if (!testMethod_rfind()) {
+ return 1;
+ }
+ if (!testMethod_find_first_of()) {
+ return 1;
+ }
+ if (!testMethod_find_first_not_of()) {
+ return 1;
+ }
+ if (!testMethod_find_last_of()) {
+ return 1;
+ }
+ if (!testMethod_find_last_not_of()) {
+ return 1;
+ }
+ if (!testAddition()) {
+ return 1;
+ }
+ if (!testStability()) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/Tests/CMakeLib/testStringAlgorithms.cxx b/Tests/CMakeLib/testStringAlgorithms.cxx
new file mode 100644
index 0000000..c2706c1
--- /dev/null
+++ b/Tests/CMakeLib/testStringAlgorithms.cxx
@@ -0,0 +1,240 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <cmConfigure.h> // IWYU pragma: keep
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmStringAlgorithms.h"
+
+int testStringAlgorithms(int /*unused*/, char* /*unused*/ [])
+{
+ int failed = 0;
+
+ auto assert_ok = [&failed](bool test, cm::string_view title) {
+ if (test) {
+ std::cout << "Passed: " << title << "\n";
+ } else {
+ std::cout << "Failed: " << title << "\n";
+ ++failed;
+ }
+ };
+
+ auto assert_string = [&failed](cm::string_view generated,
+ cm::string_view expected,
+ cm::string_view title) {
+ if (generated == expected) {
+ std::cout << "Passed: " << title << "\n";
+ } else {
+ std::cout << "Failed: " << title << "\n";
+ std::cout << "Expected: " << expected << "\n";
+ std::cout << "Got: " << generated << "\n";
+ ++failed;
+ }
+ };
+
+ // ----------------------------------------------------------------------
+ // Test cmTrimWhitespace
+ {
+ std::string base = "base";
+ std::string spaces = " \f\f\n\n\r\r\t\t\v\v";
+ assert_string(cmTrimWhitespace(spaces + base), base,
+ "cmTrimWhitespace front");
+ assert_string(cmTrimWhitespace(base + spaces), base,
+ "cmTrimWhitespace back");
+ assert_string(cmTrimWhitespace(spaces + base + spaces), base,
+ "cmTrimWhitespace front and back");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test cmRemoveQuotes
+ {
+ auto test = [&assert_string](cm::string_view source,
+ cm::string_view expected,
+ cm::string_view title) {
+ assert_string(cmRemoveQuotes(source), expected, title);
+ };
+
+ test("", "", "cmRemoveQuotes empty");
+ test("\"", "\"", "cmRemoveQuotes single quote");
+ test("\"\"", "", "cmRemoveQuotes double quote");
+ test("\"a", "\"a", "cmRemoveQuotes quote char");
+ test("\"ab", "\"ab", "cmRemoveQuotes quote char char");
+ test("a\"", "a\"", "cmRemoveQuotes char quote");
+ test("ab\"", "ab\"", "cmRemoveQuotes char char quote");
+ test("a", "a", "cmRemoveQuotes single char");
+ test("ab", "ab", "cmRemoveQuotes two chars");
+ test("abc", "abc", "cmRemoveQuotes three chars");
+ test("\"abc\"", "abc", "cmRemoveQuotes quoted chars");
+ test("\"\"abc\"\"", "\"abc\"", "cmRemoveQuotes quoted quoted chars");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test cmEscapeQuotes
+ {
+ assert_string(cmEscapeQuotes("plain"), "plain", "cmEscapeQuotes plain");
+ std::string base = "\"base\"\"";
+ std::string result = "\\\"base\\\"\\\"";
+ assert_string(cmEscapeQuotes(base), result, "cmEscapeQuotes escaped");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test cmJoin
+ {
+ typedef std::string ST;
+ typedef std::vector<std::string> VT;
+ assert_string(cmJoin(ST("abc"), ";"), "a;b;c", "cmJoin std::string");
+ assert_string(cmJoin(VT{}, ";"), "", "cmJoin std::vector empty");
+ assert_string(cmJoin(VT{ "a" }, ";"), "a", "cmJoin std::vector single");
+ assert_string(cmJoin(VT{ "a", "b", "c" }, ";"), "a;b;c",
+ "cmJoin std::vector multiple");
+ assert_string(cmJoin(VT{ "a", "b", "c" }, "<=>"), "a<=>b<=>c",
+ "cmJoin std::vector long sep");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test cmTokenize
+ {
+ typedef std::vector<std::string> VT;
+ assert_ok(cmTokenize("", ";") == VT{ "" }, "cmTokenize empty");
+ assert_ok(cmTokenize(";", ";") == VT{ "" }, "cmTokenize sep");
+ assert_ok(cmTokenize("abc", ";") == VT{ "abc" }, "cmTokenize item");
+ assert_ok(cmTokenize("abc;", ";") == VT{ "abc" }, "cmTokenize item sep");
+ assert_ok(cmTokenize(";abc", ";") == VT{ "abc" }, "cmTokenize sep item");
+ assert_ok(cmTokenize("abc;;efg", ";") == VT{ "abc", "efg" },
+ "cmTokenize item sep sep item");
+ assert_ok(cmTokenize("a1;a2;a3;a4", ";") == VT{ "a1", "a2", "a3", "a4" },
+ "cmTokenize multiple items");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test cmStrCat
+ {
+ int ni = -1100;
+ unsigned int nui = 1100u;
+ long int nli = -12000l;
+ unsigned long int nuli = 12000ul;
+ long long int nlli = -130000ll;
+ unsigned long long int nulli = 130000ull;
+ std::string val =
+ cmStrCat("<test>", ni, ',', nui, ',', nli, ",", nuli, ", ", nlli,
+ std::string(", "), nulli, cm::string_view("</test>"));
+ std::string expect =
+ "<test>-1100,1100,-12000,12000, -130000, 130000</test>";
+ assert_string(val, expect, "cmStrCat strings and integers");
+ }
+ {
+ float const val = 1.5f;
+ float const div = 0.00001f;
+ float f = 0.0f;
+ std::istringstream(cmStrCat("", val)) >> f;
+ f -= val;
+ assert_ok((f < div) && (f > -div), "cmStrCat float");
+ }
+ {
+ double const val = 1.5;
+ double const div = 0.00001;
+ double d = 0.0;
+ std::istringstream(cmStrCat("", val)) >> d;
+ d -= val;
+ assert_ok((d < div) && (d > -div), "cmStrCat double");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test cmWrap
+ {
+ typedef std::vector<std::string> VT;
+ assert_string(cmWrap("<", VT{}, ">", "; "), //
+ "", //
+ "cmWrap empty, string prefix and suffix");
+ assert_string(cmWrap("<", VT{ "abc" }, ">", "; "), //
+ "<abc>", //
+ "cmWrap single, string prefix and suffix");
+ assert_string(cmWrap("<", VT{ "a1", "a2", "a3" }, ">", "; "), //
+ "<a1>; <a2>; <a3>", //
+ "cmWrap multiple, string prefix and suffix");
+
+ assert_string(cmWrap('<', VT{}, '>', "; "), //
+ "", //
+ "cmWrap empty, char prefix and suffix");
+ assert_string(cmWrap('<', VT{ "abc" }, '>', "; "), //
+ "<abc>", //
+ "cmWrap single, char prefix and suffix");
+ assert_string(cmWrap('<', VT{ "a1", "a2", "a3" }, '>', "; "), //
+ "<a1>; <a2>; <a3>", //
+ "cmWrap multiple, char prefix and suffix");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test cmHas(Literal)Prefix and cmHas(Literal)Suffix
+ {
+ std::string str("abc");
+ assert_ok(cmHasPrefix(str, 'a'), "cmHasPrefix char");
+ assert_ok(!cmHasPrefix(str, 'c'), "cmHasPrefix char not");
+ assert_ok(cmHasPrefix(str, "ab"), "cmHasPrefix string");
+ assert_ok(!cmHasPrefix(str, "bc"), "cmHasPrefix string not");
+ assert_ok(cmHasPrefix(str, str), "cmHasPrefix complete string");
+ assert_ok(cmHasLiteralPrefix(str, "ab"), "cmHasLiteralPrefix string");
+ assert_ok(!cmHasLiteralPrefix(str, "bc"), "cmHasLiteralPrefix string not");
+
+ assert_ok(cmHasSuffix(str, 'c'), "cmHasSuffix char");
+ assert_ok(!cmHasSuffix(str, 'a'), "cmHasSuffix char not");
+ assert_ok(cmHasSuffix(str, "bc"), "cmHasSuffix string");
+ assert_ok(!cmHasSuffix(str, "ab"), "cmHasSuffix string not");
+ assert_ok(cmHasSuffix(str, str), "cmHasSuffix complete string");
+ assert_ok(cmHasLiteralSuffix(str, "bc"), "cmHasLiteralSuffix string");
+ assert_ok(!cmHasLiteralSuffix(str, "ab"), "cmHasLiteralPrefix string not");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test cmStrToLong
+ {
+ long value;
+ assert_ok(cmStrToLong("1", &value) && value == 1,
+ "cmStrToLong parses a positive decimal integer.");
+ assert_ok(cmStrToLong(" 1", &value) && value == 1,
+ "cmStrToLong parses a decimal integer after whitespace.");
+
+ assert_ok(cmStrToLong("-1", &value) && value == -1,
+ "cmStrToLong parses a negative decimal integer.");
+ assert_ok(
+ cmStrToLong(" -1", &value) && value == -1,
+ "cmStrToLong parses a negative decimal integer after whitespace.");
+
+ assert_ok(!cmStrToLong("1x", &value),
+ "cmStrToLong rejects trailing content.");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test cmStrToULong
+ {
+ unsigned long value;
+ assert_ok(cmStrToULong("1", &value) && value == 1,
+ "cmStrToULong parses a decimal integer.");
+ assert_ok(cmStrToULong(" 1", &value) && value == 1,
+ "cmStrToULong parses a decimal integer after whitespace.");
+ assert_ok(!cmStrToULong("-1", &value),
+ "cmStrToULong rejects a negative number.");
+ assert_ok(!cmStrToULong(" -1", &value),
+ "cmStrToULong rejects a negative number after whitespace.");
+ assert_ok(!cmStrToULong("1x", &value),
+ "cmStrToULong rejects trailing content.");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test cmStrLen
+ {
+ constexpr auto len = cmStrLen("Hello world!");
+ assert_ok(len == 12,
+ "cmStrLen returns length of non-empty literal string");
+ assert_ok(cmStrLen("") == 0,
+ "cmStrLen returns length of empty literal string");
+ }
+
+ return failed;
+}
diff --git a/Tests/CMakeLib/testSystemTools.cxx b/Tests/CMakeLib/testSystemTools.cxx
new file mode 100644
index 0000000..92f5275
--- /dev/null
+++ b/Tests/CMakeLib/testSystemTools.cxx
@@ -0,0 +1,99 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <cmConfigure.h> // IWYU pragma: keep
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <stddef.h>
+
+#include "cmSystemTools.h"
+
+#define cmPassed(m) std::cout << "Passed: " << (m) << "\n"
+#define cmFailed(m) \
+ std::cout << "FAILED: " << (m) << "\n"; \
+ failed = 1
+
+#define cmAssert(exp, m) \
+ do { \
+ if ((exp)) { \
+ cmPassed(m); \
+ } else { \
+ cmFailed(m); \
+ } \
+ } while (false)
+
+int testSystemTools(int /*unused*/, char* /*unused*/ [])
+{
+ int failed = 0;
+ // ----------------------------------------------------------------------
+ // Test cmSystemTools::UpperCase
+ std::string str = "abc";
+ std::string strupper = "ABC";
+ cmAssert(cmSystemTools::UpperCase(str) == strupper,
+ "cmSystemTools::UpperCase");
+
+ // ----------------------------------------------------------------------
+ // Test cmSystemTools::strverscmp
+ cmAssert(cmSystemTools::strverscmp("", "") == 0, "strverscmp empty string");
+ cmAssert(cmSystemTools::strverscmp("abc", "") > 0,
+ "strverscmp string vs empty string");
+ cmAssert(cmSystemTools::strverscmp("abc", "abc") == 0,
+ "strverscmp same string");
+ cmAssert(cmSystemTools::strverscmp("abd", "abc") > 0,
+ "strverscmp character string");
+ cmAssert(cmSystemTools::strverscmp("abc", "abd") < 0,
+ "strverscmp symmetric");
+ cmAssert(cmSystemTools::strverscmp("12345", "12344") > 0,
+ "strverscmp natural numbers");
+ cmAssert(cmSystemTools::strverscmp("100", "99") > 0,
+ "strverscmp natural numbers different digits");
+ cmAssert(cmSystemTools::strverscmp("12345", "00345") > 0,
+ "strverscmp natural against decimal (same length)");
+ cmAssert(cmSystemTools::strverscmp("99999999999999", "99999999999991") > 0,
+ "strverscmp natural overflow");
+ cmAssert(cmSystemTools::strverscmp("00000000000009", "00000000000001") > 0,
+ "strverscmp decimal precision");
+ cmAssert(cmSystemTools::strverscmp("a.b.c.0", "a.b.c.000") > 0,
+ "strverscmp multiple zeros");
+ cmAssert(cmSystemTools::strverscmp("lib_1.2_10", "lib_1.2_2") > 0,
+ "strverscmp last number ");
+ cmAssert(cmSystemTools::strverscmp("12lib", "2lib") > 0,
+ "strverscmp first number ");
+ cmAssert(cmSystemTools::strverscmp("02lib", "002lib") > 0,
+ "strverscmp first number decimal ");
+ cmAssert(cmSystemTools::strverscmp("10", "9a") > 0,
+ "strverscmp letter filler ");
+ cmAssert(cmSystemTools::strverscmp("000", "0001") > 0,
+ "strverscmp zero and leading zeros ");
+
+ // test sorting using standard strvercmp input
+ std::vector<std::string> testString;
+ testString.push_back("000");
+ testString.push_back("00");
+ testString.push_back("01");
+ testString.push_back("010");
+ testString.push_back("09");
+ testString.push_back("0");
+ testString.push_back("1");
+ testString.push_back("9");
+ testString.push_back("10");
+
+ // test global ordering of input strings
+ for (size_t i = 0; i < testString.size() - 1; i++) {
+ for (size_t j = i + 1; j < testString.size(); j++) {
+ if (cmSystemTools::strverscmp(testString[i], testString[j]) >= 0) {
+ cmFailed("cmSystemTools::strverscmp error in comparing strings " +
+ testString[i] + " " + testString[j]);
+ }
+ }
+ }
+
+ if (!failed) {
+ cmPassed("cmSystemTools::strverscmp working");
+ }
+
+ return failed;
+}
diff --git a/Tests/CMakeLib/testUTF8.cxx b/Tests/CMakeLib/testUTF8.cxx
new file mode 100644
index 0000000..1bf88cf
--- /dev/null
+++ b/Tests/CMakeLib/testUTF8.cxx
@@ -0,0 +1,197 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include <stdio.h>
+
+#include <cm_utf8.h>
+
+typedef char test_utf8_char[5];
+
+static void test_utf8_char_print(test_utf8_char const c)
+{
+ unsigned char const* d = reinterpret_cast<unsigned char const*>(c);
+#ifndef __clang_analyzer__ // somehow thinks arguments are not initialized
+ printf("[0x%02X,0x%02X,0x%02X,0x%02X]", static_cast<int>(d[0]),
+ static_cast<int>(d[1]), static_cast<int>(d[2]),
+ static_cast<int>(d[3]));
+#endif
+}
+
+static void byte_array_print(char const* s)
+{
+ unsigned char const* d = reinterpret_cast<unsigned char const*>(s);
+ bool started = false;
+ printf("[");
+ for (; *d; ++d) {
+ if (started) {
+ printf(",");
+ }
+ started = true;
+ printf("0x%02X", static_cast<int>(*d));
+ }
+ printf("]");
+}
+
+struct test_utf8_entry
+{
+ int n;
+ test_utf8_char str;
+ unsigned int chr;
+};
+
+static test_utf8_entry const good_entry[] = {
+ { 1, "\x20\x00\x00\x00", 0x0020 }, /* Space. */
+ { 2, "\xC2\xA9\x00\x00", 0x00A9 }, /* Copyright. */
+ { 3, "\xE2\x80\x98\x00", 0x2018 }, /* Open-single-quote. */
+ { 3, "\xE2\x80\x99\x00", 0x2019 }, /* Close-single-quote. */
+ { 4, "\xF0\xA3\x8E\xB4", 0x233B4 }, /* Example from RFC 3629. */
+ { 3, "\xED\x80\x80\x00", 0xD000 }, /* Valid 0xED prefixed codepoint. */
+ { 4, "\xF4\x8F\xBF\xBF", 0x10FFFF }, /* Highest valid RFC codepoint. */
+ { 0, { 0, 0, 0, 0, 0 }, 0 }
+};
+
+static test_utf8_char const bad_chars[] = {
+ "\x80\x00\x00\x00", /* Leading continuation byte. */
+ "\xC0\x80\x00\x00", /* Overlong encoding. */
+ "\xC1\x80\x00\x00", /* Overlong encoding. */
+ "\xC2\x00\x00\x00", /* Missing continuation byte. */
+ "\xE0\x00\x00\x00", /* Missing continuation bytes. */
+ "\xE0\x80\x80\x00", /* Overlong encoding. */
+ "\xF0\x80\x80\x80", /* Overlong encoding. */
+ "\xED\xA0\x80\x00", /* UTF-16 surrogate half. */
+ "\xED\xBF\xBF\x00", /* UTF-16 surrogate half. */
+ "\xF4\x90\x80\x80", /* Lowest out-of-range codepoint. */
+ "\xF5\x80\x80\x80", /* Prefix forces out-of-range codepoints. */
+ { 0, 0, 0, 0, 0 }
+};
+
+static char const* good_strings[] = { "", "ASCII", "\xC2\xA9 Kitware", 0 };
+
+static char const* bad_strings[] = {
+ "\xC0\x80", /* Modified UTF-8 for embedded 0-byte. */
+ 0
+};
+
+static void report_good(bool passed, test_utf8_char const c)
+{
+ printf("%s: decoding good ", passed ? "pass" : "FAIL");
+ test_utf8_char_print(c);
+ printf(" (%s) ", c);
+}
+
+static void report_bad(bool passed, test_utf8_char const c)
+{
+ printf("%s: decoding bad ", passed ? "pass" : "FAIL");
+ test_utf8_char_print(c);
+ printf(" ");
+}
+
+static bool decode_good(test_utf8_entry const entry)
+{
+ unsigned int uc;
+ if (const char* e =
+ cm_utf8_decode_character(entry.str, entry.str + 4, &uc)) {
+ int used = static_cast<int>(e - entry.str);
+ if (uc != entry.chr) {
+ report_good(false, entry.str);
+ printf("expected 0x%04X, got 0x%04X\n", entry.chr, uc);
+ return false;
+ }
+ if (used != entry.n) {
+ report_good(false, entry.str);
+ printf("had %d bytes, used %d\n", entry.n, used);
+ return false;
+ }
+ report_good(true, entry.str);
+ printf("got 0x%04X\n", uc);
+ return true;
+ }
+ report_good(false, entry.str);
+ printf("failed\n");
+ return false;
+}
+
+static bool decode_bad(test_utf8_char const s)
+{
+ unsigned int uc = 0xFFFFu;
+ const char* e = cm_utf8_decode_character(s, s + 4, &uc);
+ if (e) {
+ report_bad(false, s);
+ printf("expected failure, got 0x%04X\n", uc);
+ return false;
+ }
+ report_bad(true, s);
+ printf("failed as expected\n");
+ return true;
+}
+
+static void report_valid(bool passed, char const* s)
+{
+ printf("%s: validity good ", passed ? "pass" : "FAIL");
+ byte_array_print(s);
+ printf(" (%s) ", s);
+}
+
+static void report_invalid(bool passed, char const* s)
+{
+ printf("%s: validity bad ", passed ? "pass" : "FAIL");
+ byte_array_print(s);
+ printf(" ");
+}
+
+static bool is_valid(const char* s)
+{
+ bool valid = cm_utf8_is_valid(s) != 0;
+ if (!valid) {
+ report_valid(false, s);
+ printf("expected valid, reported as invalid\n");
+ return false;
+ }
+ report_valid(true, s);
+ printf("valid as expected\n");
+ return true;
+}
+
+static bool is_invalid(const char* s)
+{
+ bool valid = cm_utf8_is_valid(s) != 0;
+ if (valid) {
+ report_invalid(false, s);
+ printf("expected invalid, reported as valid\n");
+ return false;
+ }
+ report_invalid(true, s);
+ printf("invalid as expected\n");
+ return true;
+}
+
+int testUTF8(int /*unused*/, char* /*unused*/ [])
+{
+ int result = 0;
+ for (test_utf8_entry const* e = good_entry; e->n; ++e) {
+ if (!decode_good(*e)) {
+ result = 1;
+ }
+ if (!is_valid(e->str)) {
+ result = 1;
+ }
+ }
+ for (test_utf8_char const* c = bad_chars; (*c)[0]; ++c) {
+ if (!decode_bad(*c)) {
+ result = 1;
+ }
+ if (!is_invalid(*c)) {
+ result = 1;
+ }
+ }
+ for (char const** s = good_strings; *s; ++s) {
+ if (!is_valid(*s)) {
+ result = 1;
+ }
+ }
+ for (char const** s = bad_strings; *s; ++s) {
+ if (!is_invalid(*s)) {
+ result = 1;
+ }
+ }
+ return result;
+}
diff --git a/Tests/CMakeLib/testUVProcessChain.cxx b/Tests/CMakeLib/testUVProcessChain.cxx
new file mode 100644
index 0000000..a003205
--- /dev/null
+++ b/Tests/CMakeLib/testUVProcessChain.cxx
@@ -0,0 +1,338 @@
+#include <algorithm>
+#include <csignal>
+#include <functional>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <cm/memory>
+
+#include <cm3p/uv.h>
+
+#include "cmGetPipes.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVProcessChain.h"
+#include "cmUVStreambuf.h"
+
+struct ExpectedStatus
+{
+ bool Finished;
+ bool MatchExitStatus;
+ bool MatchTermSignal;
+ cmUVProcessChain::Status Status;
+};
+
+static const std::vector<ExpectedStatus> status1 = {
+ { false, false, false, { 0, 0 } },
+ { false, false, false, { 0, 0 } },
+ { false, false, false, { 0, 0 } },
+};
+
+static const std::vector<ExpectedStatus> status2 = {
+ { true, true, true, { 0, 0 } },
+ { false, false, false, { 0, 0 } },
+ { false, false, false, { 0, 0 } },
+};
+
+static const std::vector<ExpectedStatus> status3 = {
+ { true, true, true, { 0, 0 } },
+ { true, true, true, { 1, 0 } },
+#ifdef _WIN32
+ { true, true, true, { 2, 0 } },
+#else
+ { true, false, true, { 0, SIGABRT } },
+#endif
+};
+
+bool operator==(const cmUVProcessChain::Status* actual,
+ const ExpectedStatus& expected)
+{
+ if (!expected.Finished) {
+ return !actual;
+ } else if (!actual) {
+ return false;
+ }
+ if (expected.MatchExitStatus &&
+ expected.Status.ExitStatus != actual->ExitStatus) {
+ return false;
+ }
+ if (expected.MatchTermSignal &&
+ expected.Status.TermSignal != actual->TermSignal) {
+ return false;
+ }
+ return true;
+}
+
+bool resultsMatch(const std::vector<const cmUVProcessChain::Status*>& actual,
+ const std::vector<ExpectedStatus>& expected)
+{
+ return actual.size() == expected.size() &&
+ std::equal(actual.begin(), actual.end(), expected.begin());
+}
+
+std::string getInput(std::istream& input)
+{
+ char buffer[1024];
+ std::ostringstream str;
+ do {
+ input.read(buffer, 1024);
+ str.write(buffer, input.gcount());
+ } while (input.gcount() > 0);
+ return str.str();
+}
+
+template <typename T>
+std::function<std::ostream&(std::ostream&)> printExpected(bool match,
+ const T& value)
+{
+ return [match, value](std::ostream& stream) -> std::ostream& {
+ if (match) {
+ stream << value;
+ } else {
+ stream << "*";
+ }
+ return stream;
+ };
+}
+
+std::ostream& operator<<(
+ std::ostream& stream,
+ const std::function<std::ostream&(std::ostream&)>& func)
+{
+ return func(stream);
+}
+
+void printResults(const std::vector<const cmUVProcessChain::Status*>& actual,
+ const std::vector<ExpectedStatus>& expected)
+{
+ std::cout << "Expected: " << std::endl;
+ for (auto const& e : expected) {
+ if (e.Finished) {
+ std::cout << " ExitStatus: "
+ << printExpected(e.MatchExitStatus, e.Status.ExitStatus)
+ << ", TermSignal: "
+ << printExpected(e.MatchTermSignal, e.Status.TermSignal)
+ << std::endl;
+ } else {
+ std::cout << " null" << std::endl;
+ }
+ }
+ std::cout << "Actual:" << std::endl;
+ for (auto const& a : actual) {
+ if (a) {
+ std::cout << " ExitStatus: " << a->ExitStatus
+ << ", TermSignal: " << a->TermSignal << std::endl;
+ } else {
+ std::cout << " null" << std::endl;
+ }
+ }
+}
+
+bool checkExecution(cmUVProcessChainBuilder& builder,
+ std::unique_ptr<cmUVProcessChain>& chain)
+{
+ std::vector<const cmUVProcessChain::Status*> status;
+
+ chain = cm::make_unique<cmUVProcessChain>(builder.Start());
+ if (!chain->Valid()) {
+ std::cout << "Valid() returned false, should be true" << std::endl;
+ return false;
+ }
+ status = chain->GetStatus();
+ if (!resultsMatch(status, status1)) {
+ std::cout << "GetStatus() did not produce expected output" << std::endl;
+ printResults(status, status1);
+ return false;
+ }
+
+ if (chain->Wait(6000)) {
+ std::cout << "Wait() returned true, should be false" << std::endl;
+ return false;
+ }
+ status = chain->GetStatus();
+ if (!resultsMatch(status, status2)) {
+ std::cout << "GetStatus() did not produce expected output" << std::endl;
+ printResults(status, status2);
+ return false;
+ }
+
+ if (!chain->Wait()) {
+ std::cout << "Wait() returned false, should be true" << std::endl;
+ return false;
+ }
+ status = chain->GetStatus();
+ if (!resultsMatch(status, status3)) {
+ std::cout << "GetStatus() did not produce expected output" << std::endl;
+ printResults(status, status3);
+ return false;
+ }
+
+ return true;
+}
+
+bool checkOutput(std::istream& outputStream, std::istream& errorStream)
+{
+ std::string output = getInput(outputStream);
+ if (output != "HELO WRD!") {
+ std::cout << "Output was \"" << output << "\", expected \"HELO WRD!\""
+ << std::endl;
+ return false;
+ }
+
+ std::string error = getInput(errorStream);
+ auto qemu_error_pos = error.find("qemu:");
+ if (qemu_error_pos != std::string::npos) {
+ error.resize(qemu_error_pos);
+ }
+ if (error.length() != 3 || error.find('1') == std::string::npos ||
+ error.find('2') == std::string::npos ||
+ error.find('3') == std::string::npos) {
+ std::cout << "Error was \"" << error << "\", expected \"123\""
+ << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool testUVProcessChainBuiltin(const char* helperCommand)
+{
+ cmUVProcessChainBuilder builder;
+ std::unique_ptr<cmUVProcessChain> chain;
+ builder.AddCommand({ helperCommand, "echo" })
+ .AddCommand({ helperCommand, "capitalize" })
+ .AddCommand({ helperCommand, "dedup" })
+ .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
+ .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
+
+ if (!checkExecution(builder, chain)) {
+ return false;
+ }
+
+ if (!chain->OutputStream()) {
+ std::cout << "OutputStream() was null, expecting not null" << std::endl;
+ return false;
+ }
+ if (!chain->ErrorStream()) {
+ std::cout << "ErrorStream() was null, expecting not null" << std::endl;
+ return false;
+ }
+
+ if (!checkOutput(*chain->OutputStream(), *chain->ErrorStream())) {
+ return false;
+ }
+
+ return true;
+}
+
+bool testUVProcessChainExternal(const char* helperCommand)
+{
+ cmUVProcessChainBuilder builder;
+ std::unique_ptr<cmUVProcessChain> chain;
+ int outputPipe[2], errorPipe[2];
+ cm::uv_pipe_ptr outputInPipe, outputOutPipe, errorInPipe, errorOutPipe;
+
+ if (cmGetPipes(outputPipe) < 0) {
+ std::cout << "Error creating pipes" << std::endl;
+ return false;
+ }
+ if (cmGetPipes(errorPipe) < 0) {
+ std::cout << "Error creating pipes" << std::endl;
+ return false;
+ }
+
+ builder.AddCommand({ helperCommand, "echo" })
+ .AddCommand({ helperCommand, "capitalize" })
+ .AddCommand({ helperCommand, "dedup" })
+ .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, outputPipe[1])
+ .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, errorPipe[1]);
+
+ if (!checkExecution(builder, chain)) {
+ return false;
+ }
+
+ if (chain->OutputStream()) {
+ std::cout << "OutputStream() was not null, expecting null" << std::endl;
+ return false;
+ }
+ if (chain->ErrorStream()) {
+ std::cout << "ErrorStream() was not null, expecting null" << std::endl;
+ return false;
+ }
+
+ outputOutPipe.init(chain->GetLoop(), 0);
+ uv_pipe_open(outputOutPipe, outputPipe[1]);
+ outputOutPipe.reset();
+
+ errorOutPipe.init(chain->GetLoop(), 0);
+ uv_pipe_open(errorOutPipe, errorPipe[1]);
+ errorOutPipe.reset();
+
+ outputInPipe.init(chain->GetLoop(), 0);
+ uv_pipe_open(outputInPipe, outputPipe[0]);
+ cmUVStreambuf outputBuf;
+ outputBuf.open(outputInPipe);
+ std::istream outputStream(&outputBuf);
+
+ errorInPipe.init(chain->GetLoop(), 0);
+ uv_pipe_open(errorInPipe, errorPipe[0]);
+ cmUVStreambuf errorBuf;
+ errorBuf.open(errorInPipe);
+ std::istream errorStream(&errorBuf);
+
+ if (!checkOutput(outputStream, errorStream)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool testUVProcessChainNone(const char* helperCommand)
+{
+ cmUVProcessChainBuilder builder;
+ std::unique_ptr<cmUVProcessChain> chain;
+ builder.AddCommand({ helperCommand, "echo" })
+ .AddCommand({ helperCommand, "capitalize" })
+ .AddCommand({ helperCommand, "dedup" });
+
+ if (!checkExecution(builder, chain)) {
+ return false;
+ }
+
+ if (chain->OutputStream()) {
+ std::cout << "OutputStream() was not null, expecting null" << std::endl;
+ return false;
+ }
+ if (chain->ErrorStream()) {
+ std::cout << "ErrorStream() was not null, expecting null" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+int testUVProcessChain(int argc, char** const argv)
+{
+ if (argc < 2) {
+ std::cout << "Invalid arguments.\n";
+ return -1;
+ }
+
+ if (!testUVProcessChainBuiltin(argv[1])) {
+ std::cout << "While executing testUVProcessChainBuiltin().\n";
+ return -1;
+ }
+
+ if (!testUVProcessChainExternal(argv[1])) {
+ std::cout << "While executing testUVProcessChainExternal().\n";
+ return -1;
+ }
+
+ if (!testUVProcessChainNone(argv[1])) {
+ std::cout << "While executing testUVProcessChainNone().\n";
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/Tests/CMakeLib/testUVProcessChainHelper.cxx b/Tests/CMakeLib/testUVProcessChainHelper.cxx
new file mode 100644
index 0000000..9c25834
--- /dev/null
+++ b/Tests/CMakeLib/testUVProcessChainHelper.cxx
@@ -0,0 +1,72 @@
+#include <cctype>
+#include <chrono>
+#include <cstdlib>
+#include <iostream>
+#include <set>
+#include <sstream>
+#include <string>
+#include <thread>
+
+std::string getStdin()
+{
+ char buffer[1024];
+ std::ostringstream str;
+ do {
+ std::cin.read(buffer, 1024);
+ str.write(buffer, std::cin.gcount());
+ } while (std::cin.gcount() > 0);
+ return str.str();
+}
+
+int main(int argc, char** argv)
+{
+ if (argc < 2) {
+ return -1;
+ }
+
+ std::string command = argv[1];
+ if (command == "echo") {
+ std::this_thread::sleep_for(std::chrono::milliseconds(3000));
+ std::cout << "HELLO world!" << std::flush;
+ std::cerr << "1" << std::flush;
+ return 0;
+ }
+ if (command == "capitalize") {
+ std::this_thread::sleep_for(std::chrono::milliseconds(9000));
+ std::string input = getStdin();
+ for (auto& c : input) {
+ c = static_cast<char>(std::toupper(c));
+ }
+ std::cout << input << std::flush;
+ std::cerr << "2" << std::flush;
+ return 1;
+ }
+ if (command == "dedup") {
+ // Use a nested scope to free all resources before aborting below.
+ try {
+ std::string input = getStdin();
+ std::set<char> seen;
+ std::string output;
+ for (auto c : input) {
+ if (!seen.count(c)) {
+ seen.insert(c);
+ output += c;
+ }
+ }
+ std::cout << output << std::flush;
+ std::cerr << "3" << std::flush;
+ } catch (...) {
+ }
+
+ // On Windows, the exit code of abort() is different between debug and
+ // release builds, and does not yield a term_signal in libuv in either
+ // case. For the sake of simplicity, we just return another non-zero code.
+#ifdef _WIN32
+ return 2;
+#else
+ std::abort();
+#endif
+ }
+
+ return -1;
+}
diff --git a/Tests/CMakeLib/testUVRAII.cxx b/Tests/CMakeLib/testUVRAII.cxx
new file mode 100644
index 0000000..0607f44
--- /dev/null
+++ b/Tests/CMakeLib/testUVRAII.cxx
@@ -0,0 +1,230 @@
+#include <chrono>
+#include <iostream>
+#include <thread>
+#include <utility>
+
+#include <cm3p/uv.h>
+
+#include "cmUVHandlePtr.h"
+
+static void signal_reset_fn(uv_async_t* handle)
+{
+ auto ptr = static_cast<cm::uv_async_ptr*>(handle->data);
+ ptr->reset();
+}
+
+// A common pattern is to use an async signal to shutdown the server.
+static bool testAsyncShutdown()
+{
+ uv_loop_t Loop;
+ auto err = uv_loop_init(&Loop);
+ if (err != 0) {
+ std::cerr << "Could not init loop" << std::endl;
+ return false;
+ }
+
+ {
+ cm::uv_async_ptr signal;
+ signal.init(Loop, &signal_reset_fn, &signal);
+
+ std::thread([&] {
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ signal.send();
+ })
+ .detach();
+
+ if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
+ std::cerr << "Unclean exit state in testAsyncDtor" << std::endl;
+ return false;
+ }
+
+ if (signal.get()) {
+ std::cerr << "Loop exited with signal not being cleaned up" << std::endl;
+ return false;
+ }
+ }
+
+ uv_loop_close(&Loop);
+
+ return true;
+}
+
+static void signal_fn(uv_async_t*)
+{
+}
+
+// Async dtor is sort of a pain; since it locks a mutex we must be sure its
+// dtor always calls reset otherwise the mutex is deleted then locked.
+static bool testAsyncDtor()
+{
+ uv_loop_t Loop;
+ auto err = uv_loop_init(&Loop);
+ if (err != 0) {
+ std::cerr << "Could not init loop" << std::endl;
+ return false;
+ }
+
+ {
+ cm::uv_async_ptr signal;
+ signal.init(Loop, signal_fn);
+ }
+
+ if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
+ std::cerr << "Unclean exit state in testAsyncDtor" << std::endl;
+ return false;
+ }
+
+ uv_loop_close(&Loop);
+
+ return true;
+}
+
+// Async needs a relatively stateful deleter; make sure that is properly
+// accounted for and doesn't try to hold on to invalid state when it is
+// moved
+static bool testAsyncMove()
+{
+ uv_loop_t Loop;
+ auto err = uv_loop_init(&Loop);
+ if (err != 0) {
+ std::cerr << "Could not init loop" << std::endl;
+ return false;
+ }
+
+ {
+ cm::uv_async_ptr signal;
+ {
+ cm::uv_async_ptr signalTmp;
+ signalTmp.init(Loop, signal_fn);
+ signal = std::move(signalTmp);
+ }
+ }
+
+ if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
+ std::cerr << "Unclean exit state in testAsyncDtor" << std::endl;
+ return false;
+ }
+
+ uv_loop_close(&Loop);
+ return true;
+}
+
+// When a type is castable to another uv type (pipe -> stream) here,
+// and the deleter is convertible as well, we should allow moves from
+// one type to the other.
+static bool testCrossAssignment()
+{
+ uv_loop_t Loop;
+ auto err = uv_loop_init(&Loop);
+ if (err != 0) {
+ std::cerr << "Could not init loop" << std::endl;
+ return false;
+ }
+
+ {
+ cm::uv_pipe_ptr pipe;
+ pipe.init(Loop, 0);
+
+ cm::uv_stream_ptr stream = std::move(pipe);
+ if (pipe.get()) {
+ std::cerr << "Move should be sure to invalidate the previous ptr"
+ << std::endl;
+ return false;
+ }
+ cm::uv_handle_ptr handle = std::move(stream);
+ if (stream.get()) {
+ std::cerr << "Move should be sure to invalidate the previous ptr"
+ << std::endl;
+ return false;
+ }
+ }
+
+ if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
+ std::cerr << "Unclean exit state in testCrossAssignment" << std::endl;
+ return false;
+ }
+
+ uv_loop_close(&Loop);
+ return true;
+}
+
+// This test can't fail at run time; but this makes sure we have all our move
+// ctors created correctly.
+static bool testAllMoves()
+{
+ using namespace cm;
+ struct allTypes
+ {
+ uv_stream_ptr _7;
+ uv_timer_ptr _8;
+ uv_tty_ptr _9;
+ uv_process_ptr _11;
+ uv_pipe_ptr _12;
+ uv_async_ptr _13;
+ uv_signal_ptr _14;
+ uv_handle_ptr _15;
+ };
+
+ allTypes a;
+ allTypes b(std::move(a));
+ allTypes c = std::move(b);
+ return true;
+};
+
+static bool testLoopReset()
+{
+ bool closed = false;
+ cm::uv_loop_ptr loop;
+ loop.init();
+
+ uv_timer_t timer;
+ uv_timer_init(loop, &timer);
+ timer.data = &closed;
+ uv_close(reinterpret_cast<uv_handle_t*>(&timer), [](uv_handle_t* handle) {
+ auto closedPtr = static_cast<bool*>(handle->data);
+ *closedPtr = true;
+ });
+
+ loop.reset();
+ if (!closed) {
+ std::cerr << "uv_loop_ptr did not finish" << std::endl;
+ return false;
+ }
+
+ return true;
+};
+
+static bool testLoopDestructor()
+{
+ bool closed = false;
+
+ uv_timer_t timer;
+ {
+ cm::uv_loop_ptr loop;
+ loop.init();
+
+ uv_timer_init(loop, &timer);
+ timer.data = &closed;
+ uv_close(reinterpret_cast<uv_handle_t*>(&timer), [](uv_handle_t* handle) {
+ auto closedPtr = static_cast<bool*>(handle->data);
+ *closedPtr = true;
+ });
+ }
+
+ if (!closed) {
+ std::cerr << "uv_loop_ptr did not finish" << std::endl;
+ return false;
+ }
+
+ return true;
+};
+
+int testUVRAII(int, char** const)
+{
+ if ((testAsyncShutdown() &&
+ testAsyncDtor() & testAsyncMove() & testCrossAssignment() &
+ testAllMoves() & testLoopReset() & testLoopDestructor()) == 0) {
+ return -1;
+ }
+ return 0;
+}
diff --git a/Tests/CMakeLib/testUVStreambuf.cxx b/Tests/CMakeLib/testUVStreambuf.cxx
new file mode 100644
index 0000000..b86ed76
--- /dev/null
+++ b/Tests/CMakeLib/testUVStreambuf.cxx
@@ -0,0 +1,454 @@
+#include <cstring>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <cm3p/uv.h>
+#include <stdint.h>
+
+#include "cmGetPipes.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVStreambuf.h"
+
+#define TEST_STR_LINE_1 "This string must be exactly 128 characters long so"
+#define TEST_STR_LINE_2 "that we can test CMake's std::streambuf integration"
+#define TEST_STR_LINE_3 "with libuv's uv_stream_t."
+#define TEST_STR TEST_STR_LINE_1 "\n" TEST_STR_LINE_2 "\n" TEST_STR_LINE_3
+
+bool writeDataToStreamPipe(uv_loop_t& loop, cm::uv_pipe_ptr& inputPipe,
+ char* outputData, unsigned int outputDataLength,
+ const char* /* unused */)
+{
+ int err;
+
+ // Create the pipe
+ int pipeHandles[2];
+ if (cmGetPipes(pipeHandles) < 0) {
+ std::cout << "Could not open pipe" << std::endl;
+ return false;
+ }
+
+ cm::uv_pipe_ptr outputPipe;
+ inputPipe.init(loop, 0);
+ outputPipe.init(loop, 0);
+ uv_pipe_open(inputPipe, pipeHandles[0]);
+ uv_pipe_open(outputPipe, pipeHandles[1]);
+
+ // Write data for reading
+ uv_write_t writeReq;
+ struct WriteCallbackData
+ {
+ bool Finished = false;
+ int Status;
+ } writeData;
+ writeReq.data = &writeData;
+ uv_buf_t outputBuf;
+ outputBuf.base = outputData;
+ outputBuf.len = outputDataLength;
+ if ((err = uv_write(&writeReq, outputPipe, &outputBuf, 1,
+ [](uv_write_t* req, int status) {
+ auto data = static_cast<WriteCallbackData*>(req->data);
+ data->Finished = true;
+ data->Status = status;
+ })) < 0) {
+ std::cout << "Could not write to pipe: " << uv_strerror(err) << std::endl;
+ return false;
+ }
+ while (!writeData.Finished) {
+ uv_run(&loop, UV_RUN_ONCE);
+ }
+ if (writeData.Status < 0) {
+ std::cout << "Status is " << uv_strerror(writeData.Status)
+ << ", should be 0" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool writeDataToStreamProcess(uv_loop_t& loop, cm::uv_pipe_ptr& inputPipe,
+ char* outputData, unsigned int /* unused */,
+ const char* cmakeCommand)
+{
+ int err;
+
+ inputPipe.init(loop, 0);
+ std::vector<std::string> arguments = { cmakeCommand, "-E", "echo_append",
+ outputData };
+ std::vector<const char*> processArgs;
+ for (auto const& arg : arguments) {
+ processArgs.push_back(arg.c_str());
+ }
+ processArgs.push_back(nullptr);
+ std::vector<uv_stdio_container_t> stdio(3);
+ stdio[0].flags = UV_IGNORE;
+ stdio[0].data.stream = nullptr;
+ stdio[1].flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ stdio[1].data.stream = inputPipe;
+ stdio[2].flags = UV_IGNORE;
+ stdio[2].data.stream = nullptr;
+
+ struct ProcessExitData
+ {
+ bool Finished = false;
+ int64_t ExitStatus;
+ int TermSignal;
+ } exitData;
+ cm::uv_process_ptr process;
+ auto options = uv_process_options_t();
+ options.file = cmakeCommand;
+ options.args = const_cast<char**>(processArgs.data());
+ options.flags = UV_PROCESS_WINDOWS_HIDE;
+ options.stdio = stdio.data();
+ options.stdio_count = static_cast<int>(stdio.size());
+ options.exit_cb = [](uv_process_t* handle, int64_t exitStatus,
+ int termSignal) {
+ auto data = static_cast<ProcessExitData*>(handle->data);
+ data->Finished = true;
+ data->ExitStatus = exitStatus;
+ data->TermSignal = termSignal;
+ };
+ if ((err = process.spawn(loop, options, &exitData)) < 0) {
+ std::cout << "Could not spawn process: " << uv_strerror(err) << std::endl;
+ return false;
+ }
+ while (!exitData.Finished) {
+ uv_run(&loop, UV_RUN_ONCE);
+ }
+ if (exitData.ExitStatus != 0) {
+ std::cout << "Process exit status is " << exitData.ExitStatus
+ << ", should be 0" << std::endl;
+ return false;
+ }
+ if (exitData.TermSignal != 0) {
+ std::cout << "Process term signal is " << exitData.TermSignal
+ << ", should be 0" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool testUVStreambufRead(
+ bool (*cb)(uv_loop_t& loop, cm::uv_pipe_ptr& inputPipe, char* outputData,
+ unsigned int outputDataLength, const char* cmakeCommand),
+ const char* cmakeCommand)
+{
+ char outputData[] = TEST_STR;
+ bool success = false;
+ cm::uv_loop_ptr loop;
+ loop.init();
+ cm::uv_pipe_ptr inputPipe;
+ std::vector<char> inputData(128);
+ std::streamsize readLen;
+ std::string line;
+ cm::uv_timer_ptr timer;
+
+ // Create the streambuf
+ cmUVStreambuf inputBuf(64);
+ std::istream inputStream(&inputBuf);
+ if (inputBuf.is_open()) {
+ std::cout << "is_open() is true, should be false" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+
+ // Perform first read test - read all the data
+ if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) {
+ goto end;
+ }
+ inputBuf.open(inputPipe);
+ if (!inputBuf.is_open()) {
+ std::cout << "is_open() is false, should be true" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 0) {
+ std::cout << "in_avail() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 128) {
+ std::cout << "sgetn() returned " << readLen << ", should be 128"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 0) {
+ std::cout << "in_avail() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ if (std::memcmp(inputData.data(), outputData, 128)) {
+ std::cout << "Read data does not match write data" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+ inputData.assign(128, char{});
+ inputBuf.close();
+ if (inputBuf.is_open()) {
+ std::cout << "is_open() is true, should be false" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+
+ // Perform second read test - read some data and then close
+ if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) {
+ goto end;
+ }
+ inputBuf.open(inputPipe);
+ if (!inputBuf.is_open()) {
+ std::cout << "is_open() is false, should be true" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 0) {
+ std::cout << "in_avail() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 64)) != 64) {
+ std::cout << "sgetn() returned " << readLen << ", should be 64"
+ << std::endl;
+ goto end;
+ }
+ if (std::memcmp(inputData.data(), outputData, 64)) {
+ std::cout << "Read data does not match write data" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 8) {
+ std::cout << "in_avail() returned " << readLen << ", should be 8"
+ << std::endl;
+ goto end;
+ }
+ inputData.assign(128, char{});
+ inputBuf.close();
+ if (inputBuf.is_open()) {
+ std::cout << "is_open() is true, should be false" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+
+ // Perform third read test - read line by line
+ if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) {
+ goto end;
+ }
+ inputBuf.open(inputPipe);
+ if (!inputBuf.is_open()) {
+ std::cout << "is_open() is false, should be true" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 0) {
+ std::cout << "in_avail() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+
+ if (!std::getline(inputStream, line)) {
+ std::cout << "getline returned false, should be true" << std::endl;
+ goto end;
+ }
+ if (line != TEST_STR_LINE_1) {
+ std::cout << "Line 1 is \"" << line
+ << "\", should be \"" TEST_STR_LINE_1 "\"" << std::endl;
+ goto end;
+ }
+
+ if (!std::getline(inputStream, line)) {
+ std::cout << "getline returned false, should be true" << std::endl;
+ goto end;
+ }
+ if (line != TEST_STR_LINE_2) {
+ std::cout << "Line 2 is \"" << line
+ << "\", should be \"" TEST_STR_LINE_2 "\"" << std::endl;
+ goto end;
+ }
+
+ if (!std::getline(inputStream, line)) {
+ std::cout << "getline returned false, should be true" << std::endl;
+ goto end;
+ }
+ if (line != TEST_STR_LINE_3) {
+ std::cout << "Line 3 is \"" << line
+ << "\", should be \"" TEST_STR_LINE_3 "\"" << std::endl;
+ goto end;
+ }
+
+ if (std::getline(inputStream, line)) {
+ std::cout << "getline returned true, should be false" << std::endl;
+ goto end;
+ }
+
+ inputBuf.close();
+ if (inputBuf.is_open()) {
+ std::cout << "is_open() is true, should be false" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+
+ // Perform fourth read test - run the event loop outside of underflow()
+ if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) {
+ goto end;
+ }
+ inputBuf.open(inputPipe);
+ if (!inputBuf.is_open()) {
+ std::cout << "is_open() is false, should be true" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 0) {
+ std::cout << "in_avail() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ uv_run(loop, UV_RUN_DEFAULT);
+ if ((readLen = inputBuf.in_avail()) != 72) {
+ std::cout << "in_avail() returned " << readLen << ", should be 72"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 128) {
+ std::cout << "sgetn() returned " << readLen << ", should be 128"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 0) {
+ std::cout << "in_avail() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 128"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+
+ inputBuf.close();
+ if (inputBuf.is_open()) {
+ std::cout << "is_open() is true, should be false" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+
+ // Perform fifth read test - close the streambuf in the middle of a read
+ timer.init(*loop, &inputBuf);
+ if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) {
+ goto end;
+ }
+ inputBuf.open(inputPipe);
+ if (!inputBuf.is_open()) {
+ std::cout << "is_open() is false, should be true" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != 0) {
+ std::cout << "in_avail() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ uv_timer_start(timer,
+ [](uv_timer_t* handle) {
+ auto buf = static_cast<cmUVStreambuf*>(handle->data);
+ buf->close();
+ },
+ 0, 0);
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+ if (inputBuf.is_open()) {
+ std::cout << "is_open() is true, should be false" << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.in_avail()) != -1) {
+ std::cout << "in_avail() returned " << readLen << ", should be -1"
+ << std::endl;
+ goto end;
+ }
+ if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) {
+ std::cout << "sgetn() returned " << readLen << ", should be 0"
+ << std::endl;
+ goto end;
+ }
+
+ success = true;
+
+end:
+ return success;
+}
+
+int testUVStreambuf(int argc, char** const argv)
+{
+ if (argc < 2) {
+ std::cout << "Invalid arguments.\n";
+ return -1;
+ }
+
+ if (!testUVStreambufRead(writeDataToStreamPipe, argv[1])) {
+ std::cout << "While executing testUVStreambufRead() with pipe.\n";
+ return -1;
+ }
+
+ if (!testUVStreambufRead(writeDataToStreamProcess, argv[1])) {
+ std::cout << "While executing testUVStreambufRead() with process.\n";
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser.cxx b/Tests/CMakeLib/testVisualStudioSlnParser.cxx
new file mode 100644
index 0000000..3c06960
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser.cxx
@@ -0,0 +1,195 @@
+#include "testVisualStudioSlnParser.h"
+
+#include <iostream>
+
+#include "cmVisualStudioSlnData.h"
+#include "cmVisualStudioSlnParser.h"
+
+static bool parsedRight(cmVisualStudioSlnParser& parser,
+ const std::string& file, cmSlnData& data,
+ cmVisualStudioSlnParser::ParseResult expected =
+ cmVisualStudioSlnParser::ResultOK)
+{
+ if (parser.ParseFile(SOURCE_DIR "/testVisualStudioSlnParser_data/" + file +
+ "." SLN_EXTENSION,
+ data, cmVisualStudioSlnParser::DataGroupProjects)) {
+ if (expected == cmVisualStudioSlnParser::ResultOK) {
+ return true;
+ }
+ } else {
+ if (parser.GetParseResult() == expected) {
+ return true;
+ }
+ }
+ std::cerr << "cmVisualStudioSlnParser mis-parsed " << file
+ << "." SLN_EXTENSION << "; expected result " << expected
+ << ", got " << parser.GetParseResult() << std::endl;
+ return false;
+}
+
+int testVisualStudioSlnParser(int, char* [])
+{
+ cmVisualStudioSlnParser parser;
+
+ // Test clean parser
+ if (parser.GetParseResult() != cmVisualStudioSlnParser::ResultOK) {
+ std::cerr << "cmVisualStudioSlnParser initialisation failed" << std::endl;
+ return 1;
+ }
+
+ // Test parsing valid sln
+ {
+ cmSlnData data;
+ if (!parsedRight(parser, "valid", data)) {
+ return 1;
+ }
+ const std::vector<cmSlnProjectEntry>& projects = data.GetProjects();
+ const char* const names[] = {
+ "3rdParty",
+ "ALL_BUILD",
+ "CMakeLib",
+ "CMakeLibTests",
+ "CMakePredefinedTargets",
+ "CPackLib",
+ "CTestDashboardTargets",
+ "CTestLib",
+ "Continuous",
+ "Documentation",
+ "Experimental",
+ "INSTALL",
+ "KWSys",
+ "LIBCURL",
+ "Nightly",
+ "NightlyMemoryCheck",
+ "PACKAGE",
+ "RUN_TESTS",
+ "Tests",
+ "Utilities",
+ "Win9xCompat",
+ "ZERO_CHECK",
+ "cmIML_test",
+ "cmake",
+ "cmbzip2",
+ "cmcldeps",
+ "cmcompress",
+ "cmcurl",
+ "cmexpat",
+ "cmlibarchive",
+ "cmsys",
+ "cmsysEncodeExecutable",
+ "cmsysProcessFwd9x",
+ "cmsysTestDynload",
+ "cmsysTestProcess",
+ "cmsysTestSharedForward",
+ "cmsysTestsC",
+ "cmsysTestsCxx",
+ "cmsys_c",
+ "cmw9xcom",
+ "cmzlib",
+ "cpack",
+ "ctest",
+ "documentation",
+ "memcheck_fail",
+ "pseudo_BC",
+ "pseudo_purify",
+ "pseudo_valgrind",
+ "test_clean",
+ "uninstall"
+ /* clang-format needs this comment to break after the opening brace */
+ };
+ const size_t expectedProjectCount = sizeof(names) / sizeof(*names);
+ if (projects.size() != expectedProjectCount) {
+ std::cerr << "cmVisualStudioSlnParser returned bad number of "
+ << "projects (" << projects.size() << " instead of "
+ << expectedProjectCount << ')' << std::endl;
+ return 1;
+ }
+ for (size_t idx = 0; idx < expectedProjectCount; ++idx) {
+ if (projects[idx].GetName() != names[idx]) {
+ std::cerr << "cmVisualStudioSlnParser returned bad project #" << idx
+ << "; expected \"" << names[idx] << "\", got \""
+ << projects[idx].GetName() << '"' << std::endl;
+ return 1;
+ }
+ }
+ if (projects[0].GetRelativePath() != "Utilities\\3rdParty") {
+ std::cerr << "cmVisualStudioSlnParser returned bad relative path of "
+ << "project 3rdParty; expected \"Utilities\\3rdParty\", "
+ << "got \"" << projects[0].GetRelativePath() << '"'
+ << std::endl;
+ return 1;
+ }
+ if (projects[2].GetGUID() != "{59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}") {
+ std::cerr << "cmVisualStudioSlnParser returned bad relative path of "
+ << "project CMakeLib; expected "
+ << "\"{59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}\", "
+ << "got \"" << projects[2].GetGUID() << '"' << std::endl;
+ return 1;
+ }
+ }
+
+ // Test BOM parsing
+ {
+ cmSlnData data;
+
+ if (!parsedRight(parser, "bom", data)) {
+ return 1;
+ }
+ if (!parser.GetParseHadBOM()) {
+ std::cerr << "cmVisualStudioSlnParser didn't find BOM in bom."
+ << SLN_EXTENSION << std::endl;
+ return 1;
+ }
+
+ if (!parsedRight(parser, "nobom", data)) {
+ return 1;
+ }
+ if (parser.GetParseHadBOM()) {
+ std::cerr << "cmVisualStudioSlnParser found BOM in nobom."
+ << SLN_EXTENSION << std::endl;
+ return 1;
+ }
+ }
+
+ // Test invalid sln
+ {
+ {
+ cmSlnData data;
+ if (!parsedRight(parser, "err-nonexistent", data,
+ cmVisualStudioSlnParser::ResultErrorOpeningInput)) {
+ return 1;
+ }
+ }
+ {
+ cmSlnData data;
+ if (!parsedRight(parser, "err-empty", data,
+ cmVisualStudioSlnParser::ResultErrorReadingInput)) {
+ return 1;
+ }
+ }
+ const char* const files[] = {
+ "header", "projectArgs", "topLevel", "projectContents",
+ "projectSection", "global", "unclosed", "strayQuote",
+ "strayParen", "strayQuote2"
+ /* clang-format needs this comment to break after the opening brace */
+ };
+ for (size_t idx = 0; idx < sizeof(files) / sizeof(files[0]); ++idx) {
+ cmSlnData data;
+ if (!parsedRight(parser, std::string("err-structure-") + files[idx],
+ data,
+ cmVisualStudioSlnParser::ResultErrorInputStructure)) {
+ return 1;
+ }
+ }
+ {
+ cmSlnData data;
+ if (!parsedRight(parser, "err-data", data,
+ cmVisualStudioSlnParser::ResultErrorInputData)) {
+ return 1;
+ }
+ }
+ }
+
+ // All is well
+ return 0;
+}
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser.h.in b/Tests/CMakeLib/testVisualStudioSlnParser.h.in
new file mode 100644
index 0000000..62c3f4d
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser.h.in
@@ -0,0 +1,7 @@
+#ifndef testVisualStudioSlnParser_h
+#define testVisualStudioSlnParser_h
+
+#define SOURCE_DIR "@CMAKE_CURRENT_SOURCE_DIR@"
+#define SLN_EXTENSION "sln-file"
+
+#endif
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/.gitattributes b/Tests/CMakeLib/testVisualStudioSlnParser_data/.gitattributes
new file mode 100644
index 0000000..08b4ac4
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/.gitattributes
@@ -0,0 +1 @@
+*.sln-file eol=crlf
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/bom.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/bom.sln-file
new file mode 100644
index 0000000..f8c432f
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/bom.sln-file
@@ -0,0 +1,2 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/err-data.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-data.sln-file
new file mode 100644
index 0000000..4656046
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-data.sln-file
@@ -0,0 +1,6 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Continuous", "Continuous.vcxproj", "{E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Continuous", "Continuous.vcxproj", "{E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89}"
+EndProject
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/err-empty.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-empty.sln-file
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-empty.sln-file
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-global.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-global.sln-file
new file mode 100644
index 0000000..d65d82a
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-global.sln-file
@@ -0,0 +1,9 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Continuous", "Continuous.vcxproj", "{E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Global
+EndGlobalSection
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-header.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-header.sln-file
new file mode 100644
index 0000000..cc6d1b8
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-header.sln-file
@@ -0,0 +1,4 @@
+Microsoft Visual Studio Solution2 File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Continuous", "Continuous.vcxproj", "{E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89}"
+EndProject
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-projectArgs.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-projectArgs.sln-file
new file mode 100644
index 0000000..31ed7b8
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-projectArgs.sln-file
@@ -0,0 +1,4 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Continuous", "Continuous.vcxproj"
+EndProject
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-projectContents.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-projectContents.sln-file
new file mode 100644
index 0000000..a2eb7ba
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-projectContents.sln-file
@@ -0,0 +1,6 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Continuous", "Continuous.vcxproj", "{E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89}"
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Continuous2", "Continuous2.vcxproj", "{E5071091-DBFB-49E2-AF0F-E8B0FDEF6C89}"
+ EndProject
+EndProject
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-projectSection.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-projectSection.sln-file
new file mode 100644
index 0000000..8688e75
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-projectSection.sln-file
@@ -0,0 +1,11 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "ZERO_CHECK.vcxproj", "{90BC31D7-A3E8-4F04-8049-2236C239A044}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Continuous", "Continuous.vcxproj", "{E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProject
+EndProject
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-strayParen.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-strayParen.sln-file
new file mode 100644
index 0000000..f2a3ea1
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-strayParen.sln-file
@@ -0,0 +1,4 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}" = "Continuous", "Continuous.vcxproj", "{E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89}"
+EndProject
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-strayQuote.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-strayQuote.sln-file
new file mode 100644
index 0000000..b91dae3
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-strayQuote.sln-file
@@ -0,0 +1,4 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Continuous", "Continuous.vcxproj", "{E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89}
+EndProject
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-strayQuote2.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-strayQuote2.sln-file
new file mode 100644
index 0000000..1d01fda
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-strayQuote2.sln-file
@@ -0,0 +1,4 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}) = "Continuous", "Continuous.vcxproj", "{E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89}"
+EndProject
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-topLevel.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-topLevel.sln-file
new file mode 100644
index 0000000..c406974
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-topLevel.sln-file
@@ -0,0 +1,4 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+GlobalSection(ExtensibilityGlobals) = postSolution
+EndGlobalSection
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-unclosed.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-unclosed.sln-file
new file mode 100644
index 0000000..d814bf4
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/err-structure-unclosed.sln-file
@@ -0,0 +1,5 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Global
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/nobom.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/nobom.sln-file
new file mode 100644
index 0000000..8168b6b
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/nobom.sln-file
@@ -0,0 +1,2 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser_data/valid.sln-file b/Tests/CMakeLib/testVisualStudioSlnParser_data/valid.sln-file
new file mode 100644
index 0000000..395b953
--- /dev/null
+++ b/Tests/CMakeLib/testVisualStudioSlnParser_data/valid.sln-file
@@ -0,0 +1,680 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ALL_BUILD", "ALL_BUILD.vcxproj", "{BC04E6F9-A1E4-43BA-88B3-6FBF45FA561C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2} = {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}
+ {B025BD09-8389-4D9F-9150-F33418A664B1} = {B025BD09-8389-4D9F-9150-F33418A664B1}
+ {94EAABE8-174B-4EE9-8EDF-C5FED49A31B8} = {94EAABE8-174B-4EE9-8EDF-C5FED49A31B8}
+ {1002C8FC-7242-4A69-AF51-C59BB10BA6D8} = {1002C8FC-7242-4A69-AF51-C59BB10BA6D8}
+ {0283B293-0067-4D02-ADA6-892704398F48} = {0283B293-0067-4D02-ADA6-892704398F48}
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {48D43A03-3C1B-439A-9517-8F2A2B4CEC3B} = {48D43A03-3C1B-439A-9517-8F2A2B4CEC3B}
+ {6ADE54B3-3FDA-4E76-9B87-66D95E5265A8} = {6ADE54B3-3FDA-4E76-9B87-66D95E5265A8}
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0} = {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}
+ {A51EB64E-E1EA-4B4A-8FDC-56ADFE635E84} = {A51EB64E-E1EA-4B4A-8FDC-56ADFE635E84}
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C} = {561AD1BB-6DD3-466D-B270-3696DEE8C26C}
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D} = {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3} = {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54} = {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F} = {BDB424DC-15B3-4A06-A1E2-3D61380F359F}
+ {4810B052-899E-4CA5-A0BC-2E383F8AEFAE} = {4810B052-899E-4CA5-A0BC-2E383F8AEFAE}
+ {29D5FCAF-20D0-4DEF-8529-F035C249E996} = {29D5FCAF-20D0-4DEF-8529-F035C249E996}
+ {A0421DCA-AC3E-42D0-94AC-379A21A1E591} = {A0421DCA-AC3E-42D0-94AC-379A21A1E591}
+ {C6AF7E57-CE57-4462-AE1D-BF520701480E} = {C6AF7E57-CE57-4462-AE1D-BF520701480E}
+ {F2CAAAB3-9568-4284-B8E3-13955183A6D7} = {F2CAAAB3-9568-4284-B8E3-13955183A6D7}
+ {D8294E4A-03C5-43D7-AE35-15603F502DC0} = {D8294E4A-03C5-43D7-AE35-15603F502DC0}
+ {A4921D15-411F-436A-B6F3-F8381652A8E1} = {A4921D15-411F-436A-B6F3-F8381652A8E1}
+ {60BEB3AF-B4EF-4363-8747-C40177BC2D9C} = {60BEB3AF-B4EF-4363-8747-C40177BC2D9C}
+ {ACC30B92-8B65-4A9D-9BF2-6BBD0B008C8C} = {ACC30B92-8B65-4A9D-9BF2-6BBD0B008C8C}
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0} = {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}
+ {0E9E295F-3854-415B-AE9F-7B62F17932F5} = {0E9E295F-3854-415B-AE9F-7B62F17932F5}
+ {4BFA4D7C-C6F7-4270-9E87-B922DCE05644} = {4BFA4D7C-C6F7-4270-9E87-B922DCE05644}
+ {F77AD922-B4BC-43D7-B268-865312085495} = {F77AD922-B4BC-43D7-B268-865312085495}
+ {8DF3790D-AF1B-4505-BA5B-4D61EF9FBE88} = {8DF3790D-AF1B-4505-BA5B-4D61EF9FBE88}
+ {1DFA0599-77CC-4768-B47A-107EEE86C20C} = {1DFA0599-77CC-4768-B47A-107EEE86C20C}
+ {0E45A3EF-8636-46CF-94A3-7B5CE875DE48} = {0E45A3EF-8636-46CF-94A3-7B5CE875DE48}
+ {CAEF2D10-B14D-4E0C-8B79-8AC767B12F7C} = {CAEF2D10-B14D-4E0C-8B79-8AC767B12F7C}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CMakeLib", "Source\CMakeLib.vcxproj", "{59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0} = {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C} = {561AD1BB-6DD3-466D-B270-3696DEE8C26C}
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D} = {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3} = {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54} = {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F} = {BDB424DC-15B3-4A06-A1E2-3D61380F359F}
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0} = {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CMakeLibTests", "Tests\CMakeLib\CMakeLibTests.vcxproj", "{B025BD09-8389-4D9F-9150-F33418A664B1}"
+ ProjectSection(ProjectDependencies) = postProject
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2} = {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0} = {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C} = {561AD1BB-6DD3-466D-B270-3696DEE8C26C}
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D} = {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3} = {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54} = {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F} = {BDB424DC-15B3-4A06-A1E2-3D61380F359F}
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0} = {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CPackLib", "Source\CPackLib.vcxproj", "{94EAABE8-174B-4EE9-8EDF-C5FED49A31B8}"
+ ProjectSection(ProjectDependencies) = postProject
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2} = {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0} = {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C} = {561AD1BB-6DD3-466D-B270-3696DEE8C26C}
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D} = {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3} = {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54} = {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F} = {BDB424DC-15B3-4A06-A1E2-3D61380F359F}
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0} = {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CTestLib", "Source\CTestLib.vcxproj", "{1002C8FC-7242-4A69-AF51-C59BB10BA6D8}"
+ ProjectSection(ProjectDependencies) = postProject
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2} = {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0} = {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C} = {561AD1BB-6DD3-466D-B270-3696DEE8C26C}
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D} = {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3} = {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54} = {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F} = {BDB424DC-15B3-4A06-A1E2-3D61380F359F}
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0} = {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Continuous", "Continuous.vcxproj", "{E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Experimental", "Experimental.vcxproj", "{B28E8445-DFD2-46EA-BA6C-C2A1864F2FB1}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "INSTALL", "INSTALL.vcxproj", "{3B126B2D-DEAA-4CDF-9F44-28D3600F5754}"
+ ProjectSection(ProjectDependencies) = postProject
+ {BC04E6F9-A1E4-43BA-88B3-6FBF45FA561C} = {BC04E6F9-A1E4-43BA-88B3-6FBF45FA561C}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LIBCURL", "Utilities\cmcurl\LIBCURL.vcxproj", "{0283B293-0067-4D02-ADA6-892704398F48}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D} = {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0} = {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Nightly", "Nightly.vcxproj", "{7BAF09E0-DCD4-4567-9486-79E1E5F18333}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NightlyMemoryCheck", "NightlyMemoryCheck.vcxproj", "{D0413FDA-31C5-41C2-A53A-C1B87061EC96}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PACKAGE", "PACKAGE.vcxproj", "{4C488FF0-7C06-47FE-A8FD-67DAD51A3E85}"
+ ProjectSection(ProjectDependencies) = postProject
+ {BC04E6F9-A1E4-43BA-88B3-6FBF45FA561C} = {BC04E6F9-A1E4-43BA-88B3-6FBF45FA561C}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RUN_TESTS", "RUN_TESTS.vcxproj", "{D87B08A8-638E-43FA-96C2-404B41363D3B}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "ZERO_CHECK.vcxproj", "{90BC31D7-A3E8-4F04-8049-2236C239A044}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmIML_test", "Utilities\KWIML\test\cmIML_test.vcxproj", "{48D43A03-3C1B-439A-9517-8F2A2B4CEC3B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmake", "Source\cmake.vcxproj", "{6ADE54B3-3FDA-4E76-9B87-66D95E5265A8}"
+ ProjectSection(ProjectDependencies) = postProject
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2} = {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0} = {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C} = {561AD1BB-6DD3-466D-B270-3696DEE8C26C}
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D} = {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3} = {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54} = {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F} = {BDB424DC-15B3-4A06-A1E2-3D61380F359F}
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0} = {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmbzip2", "Utilities\cmbzip2\cmbzip2.vcxproj", "{1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmcldeps", "Source\cmcldeps.vcxproj", "{A51EB64E-E1EA-4B4A-8FDC-56ADFE635E84}"
+ ProjectSection(ProjectDependencies) = postProject
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2} = {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0} = {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C} = {561AD1BB-6DD3-466D-B270-3696DEE8C26C}
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D} = {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3} = {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54} = {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F} = {BDB424DC-15B3-4A06-A1E2-3D61380F359F}
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0} = {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmcompress", "Utilities\cmcompress\cmcompress.vcxproj", "{561AD1BB-6DD3-466D-B270-3696DEE8C26C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmcurl", "Utilities\cmcurl\cmcurl.vcxproj", "{1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0} = {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmexpat", "Utilities\cmexpat\cmexpat.vcxproj", "{459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmlibarchive", "Utilities\cmlibarchive\libarchive\cmlibarchive.vcxproj", "{25A91A7A-9C4E-420C-98BD-2D1F0165DA54}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0} = {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0} = {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmsys", "Source\kwsys\cmsys.vcxproj", "{BDB424DC-15B3-4A06-A1E2-3D61380F359F}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {4810B052-899E-4CA5-A0BC-2E383F8AEFAE} = {4810B052-899E-4CA5-A0BC-2E383F8AEFAE}
+ {29D5FCAF-20D0-4DEF-8529-F035C249E996} = {29D5FCAF-20D0-4DEF-8529-F035C249E996}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmsysEncodeExecutable", "Source\kwsys\cmsysEncodeExecutable.vcxproj", "{4810B052-899E-4CA5-A0BC-2E383F8AEFAE}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmsysProcessFwd9x", "Source\kwsys\cmsysProcessFwd9x.vcxproj", "{29D5FCAF-20D0-4DEF-8529-F035C249E996}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmsysTestDynload", "Source\kwsys\cmsysTestDynload.vcxproj", "{A0421DCA-AC3E-42D0-94AC-379A21A1E591}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F} = {BDB424DC-15B3-4A06-A1E2-3D61380F359F}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmsysTestProcess", "Source\kwsys\cmsysTestProcess.vcxproj", "{C6AF7E57-CE57-4462-AE1D-BF520701480E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {60BEB3AF-B4EF-4363-8747-C40177BC2D9C} = {60BEB3AF-B4EF-4363-8747-C40177BC2D9C}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmsysTestSharedForward", "Source\kwsys\cmsysTestSharedForward.vcxproj", "{F2CAAAB3-9568-4284-B8E3-13955183A6D7}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {60BEB3AF-B4EF-4363-8747-C40177BC2D9C} = {60BEB3AF-B4EF-4363-8747-C40177BC2D9C}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmsysTestsC", "Source\kwsys\cmsysTestsC.vcxproj", "{D8294E4A-03C5-43D7-AE35-15603F502DC0}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {60BEB3AF-B4EF-4363-8747-C40177BC2D9C} = {60BEB3AF-B4EF-4363-8747-C40177BC2D9C}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmsysTestsCxx", "Source\kwsys\cmsysTestsCxx.vcxproj", "{A4921D15-411F-436A-B6F3-F8381652A8E1}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F} = {BDB424DC-15B3-4A06-A1E2-3D61380F359F}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmsys_c", "Source\kwsys\cmsys_c.vcxproj", "{60BEB3AF-B4EF-4363-8747-C40177BC2D9C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {4810B052-899E-4CA5-A0BC-2E383F8AEFAE} = {4810B052-899E-4CA5-A0BC-2E383F8AEFAE}
+ {29D5FCAF-20D0-4DEF-8529-F035C249E996} = {29D5FCAF-20D0-4DEF-8529-F035C249E996}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmw9xcom", "Source\cmw9xcom.vcxproj", "{ACC30B92-8B65-4A9D-9BF2-6BBD0B008C8C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2} = {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0} = {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C} = {561AD1BB-6DD3-466D-B270-3696DEE8C26C}
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D} = {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3} = {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54} = {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F} = {BDB424DC-15B3-4A06-A1E2-3D61380F359F}
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0} = {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmzlib", "Utilities\cmzlib\cmzlib.vcxproj", "{0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpack", "Source\cpack.vcxproj", "{0E9E295F-3854-415B-AE9F-7B62F17932F5}"
+ ProjectSection(ProjectDependencies) = postProject
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2} = {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}
+ {94EAABE8-174B-4EE9-8EDF-C5FED49A31B8} = {94EAABE8-174B-4EE9-8EDF-C5FED49A31B8}
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ctest", "Source\ctest.vcxproj", "{4BFA4D7C-C6F7-4270-9E87-B922DCE05644}"
+ ProjectSection(ProjectDependencies) = postProject
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2} = {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}
+ {1002C8FC-7242-4A69-AF51-C59BB10BA6D8} = {1002C8FC-7242-4A69-AF51-C59BB10BA6D8}
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D} = {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "documentation", "Utilities\documentation.vcxproj", "{F77AD922-B4BC-43D7-B268-865312085495}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ {6ADE54B3-3FDA-4E76-9B87-66D95E5265A8} = {6ADE54B3-3FDA-4E76-9B87-66D95E5265A8}
+ {0E9E295F-3854-415B-AE9F-7B62F17932F5} = {0E9E295F-3854-415B-AE9F-7B62F17932F5}
+ {4BFA4D7C-C6F7-4270-9E87-B922DCE05644} = {4BFA4D7C-C6F7-4270-9E87-B922DCE05644}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memcheck_fail", "Tests\CTestTestMemcheck\memcheck_fail.vcxproj", "{8DF3790D-AF1B-4505-BA5B-4D61EF9FBE88}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pseudo_BC", "Tests\CTestTestMemcheck\pseudo_BC.vcxproj", "{1DFA0599-77CC-4768-B47A-107EEE86C20C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pseudo_purify", "Tests\CTestTestMemcheck\pseudo_purify.vcxproj", "{0E45A3EF-8636-46CF-94A3-7B5CE875DE48}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pseudo_valgrind", "Tests\CTestTestMemcheck\pseudo_valgrind.vcxproj", "{CAEF2D10-B14D-4E0C-8B79-8AC767B12F7C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_clean", "Tests\test_clean.vcxproj", "{02D16A66-6D59-4A0E-ABB3-BD12926934FE}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uninstall", "uninstall.vcxproj", "{B5A9B8B7-53AC-46D7-9ADE-76F708A7189C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {90BC31D7-A3E8-4F04-8049-2236C239A044}
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CMakePredefinedTargets", "CMakePredefinedTargets", "{31CE49D7-85CA-41E2-83D2-CC6962519DB6}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CTestDashboardTargets", "CTestDashboardTargets", "{BD073C58-BAED-420E-80EA-DC9F52E21AF7}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{8ECAB3CD-B434-426B-B63A-115919D393BC}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{964DC7DE-990A-4CA4-8395-10D9F9CB2A23}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utilities", "Utilities", "{7E002D15-21D1-4927-B486-82E496444441}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rdParty", "Utilities\3rdParty", "{0984A63C-130E-4B62-9A94-AAC28A88C137}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "KWSys", "Utilities\KWSys", "{EF1DFA45-6F7A-4760-8EB5-69A8A221FC54}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Win9xCompat", "Utilities\Win9xCompat", "{2485E202-B981-41E0-98CA-CF363437A4E4}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ MinSizeRel|x64 = MinSizeRel|x64
+ RelWithDebInfo|x64 = RelWithDebInfo|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {BC04E6F9-A1E4-43BA-88B3-6FBF45FA561C}.Debug|x64.ActiveCfg = Debug|x64
+ {BC04E6F9-A1E4-43BA-88B3-6FBF45FA561C}.Debug|x64.Build.0 = Debug|x64
+ {BC04E6F9-A1E4-43BA-88B3-6FBF45FA561C}.Release|x64.ActiveCfg = Release|x64
+ {BC04E6F9-A1E4-43BA-88B3-6FBF45FA561C}.Release|x64.Build.0 = Release|x64
+ {BC04E6F9-A1E4-43BA-88B3-6FBF45FA561C}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {BC04E6F9-A1E4-43BA-88B3-6FBF45FA561C}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {BC04E6F9-A1E4-43BA-88B3-6FBF45FA561C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {BC04E6F9-A1E4-43BA-88B3-6FBF45FA561C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}.Debug|x64.ActiveCfg = Debug|x64
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}.Debug|x64.Build.0 = Debug|x64
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}.Release|x64.ActiveCfg = Release|x64
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}.Release|x64.Build.0 = Release|x64
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {59BCCCCD-3AD1-4491-B8F4-C5793AC007E2}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {B025BD09-8389-4D9F-9150-F33418A664B1}.Debug|x64.ActiveCfg = Debug|x64
+ {B025BD09-8389-4D9F-9150-F33418A664B1}.Debug|x64.Build.0 = Debug|x64
+ {B025BD09-8389-4D9F-9150-F33418A664B1}.Release|x64.ActiveCfg = Release|x64
+ {B025BD09-8389-4D9F-9150-F33418A664B1}.Release|x64.Build.0 = Release|x64
+ {B025BD09-8389-4D9F-9150-F33418A664B1}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {B025BD09-8389-4D9F-9150-F33418A664B1}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {B025BD09-8389-4D9F-9150-F33418A664B1}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {B025BD09-8389-4D9F-9150-F33418A664B1}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {94EAABE8-174B-4EE9-8EDF-C5FED49A31B8}.Debug|x64.ActiveCfg = Debug|x64
+ {94EAABE8-174B-4EE9-8EDF-C5FED49A31B8}.Debug|x64.Build.0 = Debug|x64
+ {94EAABE8-174B-4EE9-8EDF-C5FED49A31B8}.Release|x64.ActiveCfg = Release|x64
+ {94EAABE8-174B-4EE9-8EDF-C5FED49A31B8}.Release|x64.Build.0 = Release|x64
+ {94EAABE8-174B-4EE9-8EDF-C5FED49A31B8}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {94EAABE8-174B-4EE9-8EDF-C5FED49A31B8}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {94EAABE8-174B-4EE9-8EDF-C5FED49A31B8}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {94EAABE8-174B-4EE9-8EDF-C5FED49A31B8}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {1002C8FC-7242-4A69-AF51-C59BB10BA6D8}.Debug|x64.ActiveCfg = Debug|x64
+ {1002C8FC-7242-4A69-AF51-C59BB10BA6D8}.Debug|x64.Build.0 = Debug|x64
+ {1002C8FC-7242-4A69-AF51-C59BB10BA6D8}.Release|x64.ActiveCfg = Release|x64
+ {1002C8FC-7242-4A69-AF51-C59BB10BA6D8}.Release|x64.Build.0 = Release|x64
+ {1002C8FC-7242-4A69-AF51-C59BB10BA6D8}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {1002C8FC-7242-4A69-AF51-C59BB10BA6D8}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {1002C8FC-7242-4A69-AF51-C59BB10BA6D8}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {1002C8FC-7242-4A69-AF51-C59BB10BA6D8}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89}.Debug|x64.ActiveCfg = Debug|x64
+ {E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89}.Release|x64.ActiveCfg = Release|x64
+ {E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {B28E8445-DFD2-46EA-BA6C-C2A1864F2FB1}.Debug|x64.ActiveCfg = Debug|x64
+ {B28E8445-DFD2-46EA-BA6C-C2A1864F2FB1}.Release|x64.ActiveCfg = Release|x64
+ {B28E8445-DFD2-46EA-BA6C-C2A1864F2FB1}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {B28E8445-DFD2-46EA-BA6C-C2A1864F2FB1}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {3B126B2D-DEAA-4CDF-9F44-28D3600F5754}.Debug|x64.ActiveCfg = Debug|x64
+ {3B126B2D-DEAA-4CDF-9F44-28D3600F5754}.Release|x64.ActiveCfg = Release|x64
+ {3B126B2D-DEAA-4CDF-9F44-28D3600F5754}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {3B126B2D-DEAA-4CDF-9F44-28D3600F5754}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {0283B293-0067-4D02-ADA6-892704398F48}.Debug|x64.ActiveCfg = Debug|x64
+ {0283B293-0067-4D02-ADA6-892704398F48}.Debug|x64.Build.0 = Debug|x64
+ {0283B293-0067-4D02-ADA6-892704398F48}.Release|x64.ActiveCfg = Release|x64
+ {0283B293-0067-4D02-ADA6-892704398F48}.Release|x64.Build.0 = Release|x64
+ {0283B293-0067-4D02-ADA6-892704398F48}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {0283B293-0067-4D02-ADA6-892704398F48}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {0283B293-0067-4D02-ADA6-892704398F48}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {0283B293-0067-4D02-ADA6-892704398F48}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {7BAF09E0-DCD4-4567-9486-79E1E5F18333}.Debug|x64.ActiveCfg = Debug|x64
+ {7BAF09E0-DCD4-4567-9486-79E1E5F18333}.Release|x64.ActiveCfg = Release|x64
+ {7BAF09E0-DCD4-4567-9486-79E1E5F18333}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {7BAF09E0-DCD4-4567-9486-79E1E5F18333}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {D0413FDA-31C5-41C2-A53A-C1B87061EC96}.Debug|x64.ActiveCfg = Debug|x64
+ {D0413FDA-31C5-41C2-A53A-C1B87061EC96}.Release|x64.ActiveCfg = Release|x64
+ {D0413FDA-31C5-41C2-A53A-C1B87061EC96}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {D0413FDA-31C5-41C2-A53A-C1B87061EC96}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {4C488FF0-7C06-47FE-A8FD-67DAD51A3E85}.Debug|x64.ActiveCfg = Debug|x64
+ {4C488FF0-7C06-47FE-A8FD-67DAD51A3E85}.Release|x64.ActiveCfg = Release|x64
+ {4C488FF0-7C06-47FE-A8FD-67DAD51A3E85}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {4C488FF0-7C06-47FE-A8FD-67DAD51A3E85}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {D87B08A8-638E-43FA-96C2-404B41363D3B}.Debug|x64.ActiveCfg = Debug|x64
+ {D87B08A8-638E-43FA-96C2-404B41363D3B}.Release|x64.ActiveCfg = Release|x64
+ {D87B08A8-638E-43FA-96C2-404B41363D3B}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {D87B08A8-638E-43FA-96C2-404B41363D3B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {90BC31D7-A3E8-4F04-8049-2236C239A044}.Debug|x64.ActiveCfg = Debug|x64
+ {90BC31D7-A3E8-4F04-8049-2236C239A044}.Debug|x64.Build.0 = Debug|x64
+ {90BC31D7-A3E8-4F04-8049-2236C239A044}.Release|x64.ActiveCfg = Release|x64
+ {90BC31D7-A3E8-4F04-8049-2236C239A044}.Release|x64.Build.0 = Release|x64
+ {90BC31D7-A3E8-4F04-8049-2236C239A044}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {90BC31D7-A3E8-4F04-8049-2236C239A044}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {90BC31D7-A3E8-4F04-8049-2236C239A044}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {90BC31D7-A3E8-4F04-8049-2236C239A044}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {48D43A03-3C1B-439A-9517-8F2A2B4CEC3B}.Debug|x64.ActiveCfg = Debug|x64
+ {48D43A03-3C1B-439A-9517-8F2A2B4CEC3B}.Debug|x64.Build.0 = Debug|x64
+ {48D43A03-3C1B-439A-9517-8F2A2B4CEC3B}.Release|x64.ActiveCfg = Release|x64
+ {48D43A03-3C1B-439A-9517-8F2A2B4CEC3B}.Release|x64.Build.0 = Release|x64
+ {48D43A03-3C1B-439A-9517-8F2A2B4CEC3B}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {48D43A03-3C1B-439A-9517-8F2A2B4CEC3B}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {48D43A03-3C1B-439A-9517-8F2A2B4CEC3B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {48D43A03-3C1B-439A-9517-8F2A2B4CEC3B}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {6ADE54B3-3FDA-4E76-9B87-66D95E5265A8}.Debug|x64.ActiveCfg = Debug|x64
+ {6ADE54B3-3FDA-4E76-9B87-66D95E5265A8}.Debug|x64.Build.0 = Debug|x64
+ {6ADE54B3-3FDA-4E76-9B87-66D95E5265A8}.Release|x64.ActiveCfg = Release|x64
+ {6ADE54B3-3FDA-4E76-9B87-66D95E5265A8}.Release|x64.Build.0 = Release|x64
+ {6ADE54B3-3FDA-4E76-9B87-66D95E5265A8}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {6ADE54B3-3FDA-4E76-9B87-66D95E5265A8}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {6ADE54B3-3FDA-4E76-9B87-66D95E5265A8}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {6ADE54B3-3FDA-4E76-9B87-66D95E5265A8}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}.Debug|x64.ActiveCfg = Debug|x64
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}.Debug|x64.Build.0 = Debug|x64
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}.Release|x64.ActiveCfg = Release|x64
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}.Release|x64.Build.0 = Release|x64
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {A51EB64E-E1EA-4B4A-8FDC-56ADFE635E84}.Debug|x64.ActiveCfg = Debug|x64
+ {A51EB64E-E1EA-4B4A-8FDC-56ADFE635E84}.Debug|x64.Build.0 = Debug|x64
+ {A51EB64E-E1EA-4B4A-8FDC-56ADFE635E84}.Release|x64.ActiveCfg = Release|x64
+ {A51EB64E-E1EA-4B4A-8FDC-56ADFE635E84}.Release|x64.Build.0 = Release|x64
+ {A51EB64E-E1EA-4B4A-8FDC-56ADFE635E84}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {A51EB64E-E1EA-4B4A-8FDC-56ADFE635E84}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {A51EB64E-E1EA-4B4A-8FDC-56ADFE635E84}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {A51EB64E-E1EA-4B4A-8FDC-56ADFE635E84}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C}.Debug|x64.ActiveCfg = Debug|x64
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C}.Debug|x64.Build.0 = Debug|x64
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C}.Release|x64.ActiveCfg = Release|x64
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C}.Release|x64.Build.0 = Release|x64
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}.Debug|x64.ActiveCfg = Debug|x64
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}.Debug|x64.Build.0 = Debug|x64
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}.Release|x64.ActiveCfg = Release|x64
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}.Release|x64.Build.0 = Release|x64
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}.Debug|x64.ActiveCfg = Debug|x64
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}.Debug|x64.Build.0 = Debug|x64
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}.Release|x64.ActiveCfg = Release|x64
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}.Release|x64.Build.0 = Release|x64
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}.Debug|x64.ActiveCfg = Debug|x64
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}.Debug|x64.Build.0 = Debug|x64
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}.Release|x64.ActiveCfg = Release|x64
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}.Release|x64.Build.0 = Release|x64
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F}.Debug|x64.ActiveCfg = Debug|x64
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F}.Debug|x64.Build.0 = Debug|x64
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F}.Release|x64.ActiveCfg = Release|x64
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F}.Release|x64.Build.0 = Release|x64
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {4810B052-899E-4CA5-A0BC-2E383F8AEFAE}.Debug|x64.ActiveCfg = Debug|x64
+ {4810B052-899E-4CA5-A0BC-2E383F8AEFAE}.Debug|x64.Build.0 = Debug|x64
+ {4810B052-899E-4CA5-A0BC-2E383F8AEFAE}.Release|x64.ActiveCfg = Release|x64
+ {4810B052-899E-4CA5-A0BC-2E383F8AEFAE}.Release|x64.Build.0 = Release|x64
+ {4810B052-899E-4CA5-A0BC-2E383F8AEFAE}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {4810B052-899E-4CA5-A0BC-2E383F8AEFAE}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {4810B052-899E-4CA5-A0BC-2E383F8AEFAE}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {4810B052-899E-4CA5-A0BC-2E383F8AEFAE}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {29D5FCAF-20D0-4DEF-8529-F035C249E996}.Debug|x64.ActiveCfg = Debug|x64
+ {29D5FCAF-20D0-4DEF-8529-F035C249E996}.Debug|x64.Build.0 = Debug|x64
+ {29D5FCAF-20D0-4DEF-8529-F035C249E996}.Release|x64.ActiveCfg = Release|x64
+ {29D5FCAF-20D0-4DEF-8529-F035C249E996}.Release|x64.Build.0 = Release|x64
+ {29D5FCAF-20D0-4DEF-8529-F035C249E996}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {29D5FCAF-20D0-4DEF-8529-F035C249E996}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {29D5FCAF-20D0-4DEF-8529-F035C249E996}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {29D5FCAF-20D0-4DEF-8529-F035C249E996}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {A0421DCA-AC3E-42D0-94AC-379A21A1E591}.Debug|x64.ActiveCfg = Debug|x64
+ {A0421DCA-AC3E-42D0-94AC-379A21A1E591}.Debug|x64.Build.0 = Debug|x64
+ {A0421DCA-AC3E-42D0-94AC-379A21A1E591}.Release|x64.ActiveCfg = Release|x64
+ {A0421DCA-AC3E-42D0-94AC-379A21A1E591}.Release|x64.Build.0 = Release|x64
+ {A0421DCA-AC3E-42D0-94AC-379A21A1E591}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {A0421DCA-AC3E-42D0-94AC-379A21A1E591}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {A0421DCA-AC3E-42D0-94AC-379A21A1E591}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {A0421DCA-AC3E-42D0-94AC-379A21A1E591}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {C6AF7E57-CE57-4462-AE1D-BF520701480E}.Debug|x64.ActiveCfg = Debug|x64
+ {C6AF7E57-CE57-4462-AE1D-BF520701480E}.Debug|x64.Build.0 = Debug|x64
+ {C6AF7E57-CE57-4462-AE1D-BF520701480E}.Release|x64.ActiveCfg = Release|x64
+ {C6AF7E57-CE57-4462-AE1D-BF520701480E}.Release|x64.Build.0 = Release|x64
+ {C6AF7E57-CE57-4462-AE1D-BF520701480E}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {C6AF7E57-CE57-4462-AE1D-BF520701480E}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {C6AF7E57-CE57-4462-AE1D-BF520701480E}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {C6AF7E57-CE57-4462-AE1D-BF520701480E}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {F2CAAAB3-9568-4284-B8E3-13955183A6D7}.Debug|x64.ActiveCfg = Debug|x64
+ {F2CAAAB3-9568-4284-B8E3-13955183A6D7}.Debug|x64.Build.0 = Debug|x64
+ {F2CAAAB3-9568-4284-B8E3-13955183A6D7}.Release|x64.ActiveCfg = Release|x64
+ {F2CAAAB3-9568-4284-B8E3-13955183A6D7}.Release|x64.Build.0 = Release|x64
+ {F2CAAAB3-9568-4284-B8E3-13955183A6D7}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {F2CAAAB3-9568-4284-B8E3-13955183A6D7}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {F2CAAAB3-9568-4284-B8E3-13955183A6D7}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {F2CAAAB3-9568-4284-B8E3-13955183A6D7}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {D8294E4A-03C5-43D7-AE35-15603F502DC0}.Debug|x64.ActiveCfg = Debug|x64
+ {D8294E4A-03C5-43D7-AE35-15603F502DC0}.Debug|x64.Build.0 = Debug|x64
+ {D8294E4A-03C5-43D7-AE35-15603F502DC0}.Release|x64.ActiveCfg = Release|x64
+ {D8294E4A-03C5-43D7-AE35-15603F502DC0}.Release|x64.Build.0 = Release|x64
+ {D8294E4A-03C5-43D7-AE35-15603F502DC0}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {D8294E4A-03C5-43D7-AE35-15603F502DC0}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {D8294E4A-03C5-43D7-AE35-15603F502DC0}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {D8294E4A-03C5-43D7-AE35-15603F502DC0}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {A4921D15-411F-436A-B6F3-F8381652A8E1}.Debug|x64.ActiveCfg = Debug|x64
+ {A4921D15-411F-436A-B6F3-F8381652A8E1}.Debug|x64.Build.0 = Debug|x64
+ {A4921D15-411F-436A-B6F3-F8381652A8E1}.Release|x64.ActiveCfg = Release|x64
+ {A4921D15-411F-436A-B6F3-F8381652A8E1}.Release|x64.Build.0 = Release|x64
+ {A4921D15-411F-436A-B6F3-F8381652A8E1}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {A4921D15-411F-436A-B6F3-F8381652A8E1}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {A4921D15-411F-436A-B6F3-F8381652A8E1}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {A4921D15-411F-436A-B6F3-F8381652A8E1}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {60BEB3AF-B4EF-4363-8747-C40177BC2D9C}.Debug|x64.ActiveCfg = Debug|x64
+ {60BEB3AF-B4EF-4363-8747-C40177BC2D9C}.Debug|x64.Build.0 = Debug|x64
+ {60BEB3AF-B4EF-4363-8747-C40177BC2D9C}.Release|x64.ActiveCfg = Release|x64
+ {60BEB3AF-B4EF-4363-8747-C40177BC2D9C}.Release|x64.Build.0 = Release|x64
+ {60BEB3AF-B4EF-4363-8747-C40177BC2D9C}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {60BEB3AF-B4EF-4363-8747-C40177BC2D9C}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {60BEB3AF-B4EF-4363-8747-C40177BC2D9C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {60BEB3AF-B4EF-4363-8747-C40177BC2D9C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {ACC30B92-8B65-4A9D-9BF2-6BBD0B008C8C}.Debug|x64.ActiveCfg = Debug|x64
+ {ACC30B92-8B65-4A9D-9BF2-6BBD0B008C8C}.Debug|x64.Build.0 = Debug|x64
+ {ACC30B92-8B65-4A9D-9BF2-6BBD0B008C8C}.Release|x64.ActiveCfg = Release|x64
+ {ACC30B92-8B65-4A9D-9BF2-6BBD0B008C8C}.Release|x64.Build.0 = Release|x64
+ {ACC30B92-8B65-4A9D-9BF2-6BBD0B008C8C}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {ACC30B92-8B65-4A9D-9BF2-6BBD0B008C8C}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {ACC30B92-8B65-4A9D-9BF2-6BBD0B008C8C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {ACC30B92-8B65-4A9D-9BF2-6BBD0B008C8C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}.Debug|x64.ActiveCfg = Debug|x64
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}.Debug|x64.Build.0 = Debug|x64
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}.Release|x64.ActiveCfg = Release|x64
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}.Release|x64.Build.0 = Release|x64
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {0E9E295F-3854-415B-AE9F-7B62F17932F5}.Debug|x64.ActiveCfg = Debug|x64
+ {0E9E295F-3854-415B-AE9F-7B62F17932F5}.Debug|x64.Build.0 = Debug|x64
+ {0E9E295F-3854-415B-AE9F-7B62F17932F5}.Release|x64.ActiveCfg = Release|x64
+ {0E9E295F-3854-415B-AE9F-7B62F17932F5}.Release|x64.Build.0 = Release|x64
+ {0E9E295F-3854-415B-AE9F-7B62F17932F5}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {0E9E295F-3854-415B-AE9F-7B62F17932F5}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {0E9E295F-3854-415B-AE9F-7B62F17932F5}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {0E9E295F-3854-415B-AE9F-7B62F17932F5}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {4BFA4D7C-C6F7-4270-9E87-B922DCE05644}.Debug|x64.ActiveCfg = Debug|x64
+ {4BFA4D7C-C6F7-4270-9E87-B922DCE05644}.Debug|x64.Build.0 = Debug|x64
+ {4BFA4D7C-C6F7-4270-9E87-B922DCE05644}.Release|x64.ActiveCfg = Release|x64
+ {4BFA4D7C-C6F7-4270-9E87-B922DCE05644}.Release|x64.Build.0 = Release|x64
+ {4BFA4D7C-C6F7-4270-9E87-B922DCE05644}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {4BFA4D7C-C6F7-4270-9E87-B922DCE05644}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {4BFA4D7C-C6F7-4270-9E87-B922DCE05644}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {4BFA4D7C-C6F7-4270-9E87-B922DCE05644}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {F77AD922-B4BC-43D7-B268-865312085495}.Debug|x64.ActiveCfg = Debug|x64
+ {F77AD922-B4BC-43D7-B268-865312085495}.Debug|x64.Build.0 = Debug|x64
+ {F77AD922-B4BC-43D7-B268-865312085495}.Release|x64.ActiveCfg = Release|x64
+ {F77AD922-B4BC-43D7-B268-865312085495}.Release|x64.Build.0 = Release|x64
+ {F77AD922-B4BC-43D7-B268-865312085495}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {F77AD922-B4BC-43D7-B268-865312085495}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {F77AD922-B4BC-43D7-B268-865312085495}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {F77AD922-B4BC-43D7-B268-865312085495}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {8DF3790D-AF1B-4505-BA5B-4D61EF9FBE88}.Debug|x64.ActiveCfg = Debug|x64
+ {8DF3790D-AF1B-4505-BA5B-4D61EF9FBE88}.Debug|x64.Build.0 = Debug|x64
+ {8DF3790D-AF1B-4505-BA5B-4D61EF9FBE88}.Release|x64.ActiveCfg = Release|x64
+ {8DF3790D-AF1B-4505-BA5B-4D61EF9FBE88}.Release|x64.Build.0 = Release|x64
+ {8DF3790D-AF1B-4505-BA5B-4D61EF9FBE88}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {8DF3790D-AF1B-4505-BA5B-4D61EF9FBE88}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {8DF3790D-AF1B-4505-BA5B-4D61EF9FBE88}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {8DF3790D-AF1B-4505-BA5B-4D61EF9FBE88}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {1DFA0599-77CC-4768-B47A-107EEE86C20C}.Debug|x64.ActiveCfg = Debug|x64
+ {1DFA0599-77CC-4768-B47A-107EEE86C20C}.Debug|x64.Build.0 = Debug|x64
+ {1DFA0599-77CC-4768-B47A-107EEE86C20C}.Release|x64.ActiveCfg = Release|x64
+ {1DFA0599-77CC-4768-B47A-107EEE86C20C}.Release|x64.Build.0 = Release|x64
+ {1DFA0599-77CC-4768-B47A-107EEE86C20C}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {1DFA0599-77CC-4768-B47A-107EEE86C20C}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {1DFA0599-77CC-4768-B47A-107EEE86C20C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {1DFA0599-77CC-4768-B47A-107EEE86C20C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {0E45A3EF-8636-46CF-94A3-7B5CE875DE48}.Debug|x64.ActiveCfg = Debug|x64
+ {0E45A3EF-8636-46CF-94A3-7B5CE875DE48}.Debug|x64.Build.0 = Debug|x64
+ {0E45A3EF-8636-46CF-94A3-7B5CE875DE48}.Release|x64.ActiveCfg = Release|x64
+ {0E45A3EF-8636-46CF-94A3-7B5CE875DE48}.Release|x64.Build.0 = Release|x64
+ {0E45A3EF-8636-46CF-94A3-7B5CE875DE48}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {0E45A3EF-8636-46CF-94A3-7B5CE875DE48}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {0E45A3EF-8636-46CF-94A3-7B5CE875DE48}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {0E45A3EF-8636-46CF-94A3-7B5CE875DE48}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {CAEF2D10-B14D-4E0C-8B79-8AC767B12F7C}.Debug|x64.ActiveCfg = Debug|x64
+ {CAEF2D10-B14D-4E0C-8B79-8AC767B12F7C}.Debug|x64.Build.0 = Debug|x64
+ {CAEF2D10-B14D-4E0C-8B79-8AC767B12F7C}.Release|x64.ActiveCfg = Release|x64
+ {CAEF2D10-B14D-4E0C-8B79-8AC767B12F7C}.Release|x64.Build.0 = Release|x64
+ {CAEF2D10-B14D-4E0C-8B79-8AC767B12F7C}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {CAEF2D10-B14D-4E0C-8B79-8AC767B12F7C}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {CAEF2D10-B14D-4E0C-8B79-8AC767B12F7C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {CAEF2D10-B14D-4E0C-8B79-8AC767B12F7C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
+ {02D16A66-6D59-4A0E-ABB3-BD12926934FE}.Debug|x64.ActiveCfg = Debug|x64
+ {02D16A66-6D59-4A0E-ABB3-BD12926934FE}.Release|x64.ActiveCfg = Release|x64
+ {02D16A66-6D59-4A0E-ABB3-BD12926934FE}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {02D16A66-6D59-4A0E-ABB3-BD12926934FE}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {B5A9B8B7-53AC-46D7-9ADE-76F708A7189C}.Debug|x64.ActiveCfg = Debug|x64
+ {B5A9B8B7-53AC-46D7-9ADE-76F708A7189C}.Release|x64.ActiveCfg = Release|x64
+ {B5A9B8B7-53AC-46D7-9ADE-76F708A7189C}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {B5A9B8B7-53AC-46D7-9ADE-76F708A7189C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {3B126B2D-DEAA-4CDF-9F44-28D3600F5754} = {31CE49D7-85CA-41E2-83D2-CC6962519DB6}
+ {4C488FF0-7C06-47FE-A8FD-67DAD51A3E85} = {31CE49D7-85CA-41E2-83D2-CC6962519DB6}
+ {D87B08A8-638E-43FA-96C2-404B41363D3B} = {31CE49D7-85CA-41E2-83D2-CC6962519DB6}
+ {90BC31D7-A3E8-4F04-8049-2236C239A044} = {31CE49D7-85CA-41E2-83D2-CC6962519DB6}
+ {E5071092-DBFB-49E2-AF0F-E8B0FDEF6C89} = {BD073C58-BAED-420E-80EA-DC9F52E21AF7}
+ {B28E8445-DFD2-46EA-BA6C-C2A1864F2FB1} = {BD073C58-BAED-420E-80EA-DC9F52E21AF7}
+ {7BAF09E0-DCD4-4567-9486-79E1E5F18333} = {BD073C58-BAED-420E-80EA-DC9F52E21AF7}
+ {D0413FDA-31C5-41C2-A53A-C1B87061EC96} = {BD073C58-BAED-420E-80EA-DC9F52E21AF7}
+ {F77AD922-B4BC-43D7-B268-865312085495} = {8ECAB3CD-B434-426B-B63A-115919D393BC}
+ {B025BD09-8389-4D9F-9150-F33418A664B1} = {964DC7DE-990A-4CA4-8395-10D9F9CB2A23}
+ {0984A63C-130E-4B62-9A94-AAC28A88C137} = {7E002D15-21D1-4927-B486-82E496444441}
+ {EF1DFA45-6F7A-4760-8EB5-69A8A221FC54} = {7E002D15-21D1-4927-B486-82E496444441}
+ {2485E202-B981-41E0-98CA-CF363437A4E4} = {7E002D15-21D1-4927-B486-82E496444441}
+ {0283B293-0067-4D02-ADA6-892704398F48} = {0984A63C-130E-4B62-9A94-AAC28A88C137}
+ {1C5345F9-9C47-4F4B-9760-7A74C9D35DE0} = {0984A63C-130E-4B62-9A94-AAC28A88C137}
+ {561AD1BB-6DD3-466D-B270-3696DEE8C26C} = {0984A63C-130E-4B62-9A94-AAC28A88C137}
+ {1342243A-C3D9-45A0-B4BC-65A8F16BCC9D} = {0984A63C-130E-4B62-9A94-AAC28A88C137}
+ {459BD82A-588C-4BFD-B3E6-1E4E3BC1B1E3} = {0984A63C-130E-4B62-9A94-AAC28A88C137}
+ {25A91A7A-9C4E-420C-98BD-2D1F0165DA54} = {0984A63C-130E-4B62-9A94-AAC28A88C137}
+ {0B7FB622-7A90-490C-B4E4-2DE3112BB5E0} = {0984A63C-130E-4B62-9A94-AAC28A88C137}
+ {BDB424DC-15B3-4A06-A1E2-3D61380F359F} = {EF1DFA45-6F7A-4760-8EB5-69A8A221FC54}
+ {4810B052-899E-4CA5-A0BC-2E383F8AEFAE} = {EF1DFA45-6F7A-4760-8EB5-69A8A221FC54}
+ {29D5FCAF-20D0-4DEF-8529-F035C249E996} = {EF1DFA45-6F7A-4760-8EB5-69A8A221FC54}
+ {A0421DCA-AC3E-42D0-94AC-379A21A1E591} = {EF1DFA45-6F7A-4760-8EB5-69A8A221FC54}
+ {C6AF7E57-CE57-4462-AE1D-BF520701480E} = {EF1DFA45-6F7A-4760-8EB5-69A8A221FC54}
+ {F2CAAAB3-9568-4284-B8E3-13955183A6D7} = {EF1DFA45-6F7A-4760-8EB5-69A8A221FC54}
+ {D8294E4A-03C5-43D7-AE35-15603F502DC0} = {EF1DFA45-6F7A-4760-8EB5-69A8A221FC54}
+ {A4921D15-411F-436A-B6F3-F8381652A8E1} = {EF1DFA45-6F7A-4760-8EB5-69A8A221FC54}
+ {60BEB3AF-B4EF-4363-8747-C40177BC2D9C} = {EF1DFA45-6F7A-4760-8EB5-69A8A221FC54}
+ {ACC30B92-8B65-4A9D-9BF2-6BBD0B008C8C} = {2485E202-B981-41E0-98CA-CF363437A4E4}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/Tests/CMakeLib/testXMLParser.cxx b/Tests/CMakeLib/testXMLParser.cxx
new file mode 100644
index 0000000..8617cc1
--- /dev/null
+++ b/Tests/CMakeLib/testXMLParser.cxx
@@ -0,0 +1,16 @@
+#include "testXMLParser.h"
+
+#include <iostream>
+
+#include "cmXMLParser.h"
+
+int testXMLParser(int /*unused*/, char* /*unused*/ [])
+{
+ // TODO: Derive from parser and check attributes.
+ cmXMLParser parser;
+ if (!parser.ParseFile(SOURCE_DIR "/testXMLParser.xml")) {
+ std::cerr << "cmXMLParser failed!" << std::endl;
+ return 1;
+ }
+ return 0;
+}
diff --git a/Tests/CMakeLib/testXMLParser.h.in b/Tests/CMakeLib/testXMLParser.h.in
new file mode 100644
index 0000000..da0b275
--- /dev/null
+++ b/Tests/CMakeLib/testXMLParser.h.in
@@ -0,0 +1,6 @@
+#ifndef testXMLParser_h
+#define testXMLParser_h
+
+#define SOURCE_DIR "@CMAKE_CURRENT_SOURCE_DIR@"
+
+#endif
diff --git a/Tests/CMakeLib/testXMLParser.xml b/Tests/CMakeLib/testXMLParser.xml
new file mode 100644
index 0000000..5a13f07
--- /dev/null
+++ b/Tests/CMakeLib/testXMLParser.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Document>
+ <Element attr="1"/>
+</Document>
diff --git a/Tests/CMakeLib/testXMLSafe.cxx b/Tests/CMakeLib/testXMLSafe.cxx
new file mode 100644
index 0000000..dc62eb9
--- /dev/null
+++ b/Tests/CMakeLib/testXMLSafe.cxx
@@ -0,0 +1,42 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <sstream>
+#include <string>
+
+#include <stdio.h>
+
+#include "cmXMLSafe.h"
+
+struct test_pair
+{
+ const char* in;
+ const char* out;
+};
+
+static test_pair const pairs[] = {
+ { "copyright \xC2\xA9", "copyright \xC2\xA9" },
+ { "form-feed \f", "form-feed [NON-XML-CHAR-0xC]" },
+ { "angles <>", "angles &lt;&gt;" },
+ { "ampersand &", "ampersand &amp;" },
+ { "bad-byte \x80", "bad-byte [NON-UTF-8-BYTE-0x80]" },
+ { nullptr, nullptr }
+};
+
+int testXMLSafe(int /*unused*/, char* /*unused*/ [])
+{
+ int result = 0;
+ for (test_pair const* p = pairs; p->in; ++p) {
+ cmXMLSafe xs(p->in);
+ std::ostringstream oss;
+ oss << xs;
+ std::string out = oss.str();
+ if (out != p->out) {
+ printf("expected [%s], got [%s]\n", p->out, out.c_str());
+ result = 1;
+ }
+ }
+ return result;
+}
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
new file mode 100644
index 0000000..d6a20bc
--- /dev/null
+++ b/Tests/CMakeLists.txt
@@ -0,0 +1,3589 @@
+# a macro for tests that have a simple format where the name matches the
+# directory and project
+macro(ADD_TEST_MACRO NAME)
+ if(${ARGC} GREATER 1)
+ set(_test_command --test-command ${ARGN})
+ endif()
+ string(REPLACE "." "/" dir "${NAME}")
+ string(REGEX REPLACE "[^.]*\\." "" proj "${NAME}")
+ add_test(NAME "${NAME}" COMMAND "${CMAKE_CTEST_COMMAND}"
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/${dir}"
+ "${CMake_BINARY_DIR}/Tests/${dir}"
+ --build-two-config
+ ${build_generator_args}
+ --build-project ${proj}
+ ${${NAME}_CTEST_OPTIONS}
+ --build-options
+ ${${NAME}_BUILD_OPTIONS}
+ ${_test_command})
+ unset(_test_command)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${dir}")
+endmacro()
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/CheckFortran.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/CheckSwift.cmake)
+
+# Fake a user home directory to avoid polluting the real one.
+if(NOT CTEST_NO_TEST_HOME AND (NOT WIN32 OR DEFINED ENV{HOME}))
+ set(TEST_HOME "${CMake_BINARY_DIR}/Tests/CMakeFiles/TestHome")
+ file(MAKE_DIRECTORY "${TEST_HOME}")
+ file(WRITE "${TEST_HOME}/.cvspass" ":pserver:anoncvs@www.cmake.org:/cvsroot/KWSys A\n")
+ set(TEST_HOME_ENV_CODE "# Fake a user home directory to avoid polluting the real one.
+# But provide original ENV{HOME} value in ENV{CTEST_REAL_HOME} for tests that
+# need access to the real HOME directory.
+if(DEFINED ENV{HOME} AND NOT DEFINED ENV{CTEST_REAL_HOME})
+ set(ENV{CTEST_REAL_HOME} \"\$ENV{HOME}\")
+endif()
+set(ENV{HOME} \"${TEST_HOME}\")
+")
+endif()
+
+# 3.9 or later provides a definitive answer to whether we are multi-config
+# through a global property. Prior to 3.9, CMAKE_CONFIGURATION_TYPES being set
+# is assumed to mean multi-config, but developers might modify it so it is
+# technically not as reliable.
+if(NOT CMAKE_VERSION VERSION_LESS 3.9)
+ get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+elseif(CMAKE_CONFIGURATION_TYPES)
+ set(_isMultiConfig True)
+else()
+ set(_isMultiConfig False)
+endif()
+
+# Choose a default configuration for CTest tests.
+set(CTestTest_CONFIG Debug)
+if(NOT _isMultiConfig AND CMAKE_BUILD_TYPE)
+ set(CTestTest_CONFIG ${CMAKE_BUILD_TYPE})
+endif()
+
+configure_file(${CMake_SOURCE_DIR}/Tests/EnforceConfig.cmake.in
+ ${CMake_BINARY_DIR}/Tests/EnforceConfig.cmake @ONLY)
+
+# Testing
+if(BUILD_TESTING)
+ set(CMake_TEST_DEVENV "")
+ if(CMAKE_VS_DEVENV_COMMAND)
+ set(CMake_TEST_DEVENV "${CMAKE_VS_DEVENV_COMMAND}")
+ elseif(CMAKE_GENERATOR MATCHES "Visual Studio 9 " AND
+ NOT CMAKE_MAKE_PROGRAM MATCHES "[mM][sS][bB][uU][iI][lL][dD]\\.[eE][xX][eE]")
+ set(CMake_TEST_DEVENV "${CMAKE_MAKE_PROGRAM}")
+ endif()
+
+ if(CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
+ set(CMake_TEST_EXPLICIT_MAKE_PROGRAM "")
+ else()
+ set(CMake_TEST_EXPLICIT_MAKE_PROGRAM "${CMAKE_MAKE_PROGRAM}")
+ endif()
+
+ if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles" OR ("${CMAKE_GENERATOR}" MATCHES Ninja AND NOT WIN32))
+ set(TEST_CompileCommandOutput 1)
+ endif()
+ endif()
+
+ set(MAKE_IS_GNU )
+ if(CMAKE_MAKE_PROGRAM MATCHES make)
+ execute_process(COMMAND ${CMAKE_MAKE_PROGRAM} no_such_target --version
+ RESULT_VARIABLE res OUTPUT_VARIABLE out ERROR_VARIABLE out)
+ if("${res}" STREQUAL "0")
+ if("${out}" MATCHES "GNU")
+ set(MAKE_IS_GNU 1)
+ endif()
+ endif()
+ endif()
+
+ # some old versions of make simply cannot handle spaces in paths
+ if (MAKE_IS_GNU OR
+ CMAKE_MAKE_PROGRAM MATCHES "nmake|gmake|wmake" OR
+ CMAKE_GENERATOR MATCHES "Visual Studio|Xcode|Borland|Ninja")
+ set(MAKE_SUPPORTS_SPACES 1)
+ else()
+ set(MAKE_SUPPORTS_SPACES 0)
+ endif()
+
+ # assume no resources building to test
+ set(CMake_TEST_RESOURCES FALSE)
+ # for windows and cygwin assume we have resources
+ if(WIN32 OR CYGWIN)
+ set(CMake_TEST_RESOURCES TRUE)
+ endif()
+ # for borland and watcom there is no resource support
+ if(WATCOM OR BORLAND)
+ set(CMake_TEST_RESOURCES FALSE)
+ endif()
+
+ set(build_generator_args
+ --build-generator ${CMAKE_GENERATOR}
+ )
+ if(CMAKE_GENERATOR_PLATFORM)
+ list(APPEND build_generator_args
+ --build-generator-platform ${CMAKE_GENERATOR_PLATFORM}
+ )
+ endif()
+ if(CMAKE_GENERATOR_TOOLSET)
+ list(APPEND build_generator_args
+ --build-generator-toolset ${CMAKE_GENERATOR_TOOLSET}
+ )
+ endif()
+
+ if(CMake_TEST_EXPLICIT_MAKE_PROGRAM)
+ list(APPEND build_generator_args
+ --build-makeprogram ${CMake_TEST_EXPLICIT_MAKE_PROGRAM}
+ )
+ endif()
+
+ # Look for rpmbuild to use for tests.
+ # The tool does not work with spaces in the path.
+ if(NOT CMAKE_CURRENT_BINARY_DIR MATCHES " ")
+ find_program(RPMBUILD_EXECUTABLE NAMES rpmbuild)
+ else()
+ set(RPMBUILD_EXECUTABLE "RPMBUILD_EXECUTABLE-NOTFOUND")
+ endif()
+
+ if(RPMBUILD_EXECUTABLE)
+ set(CPACK_BINARY_RPM ON)
+ else()
+ set(CPACK_BINARY_RPM OFF)
+ endif()
+
+ # Look for dpkg to use for tests.
+ find_program(DPKG_EXECUTABLE NAMES dpkg)
+
+ if(DPKG_EXECUTABLE)
+ set(CPACK_BINARY_DEB ON)
+ else()
+ set(CPACK_BINARY_DEB OFF)
+ endif()
+
+ # Look for NuGet to use for tests.
+ find_program(NUGET_EXECUTABLE NAMES NuGet nuget)
+
+ if(NUGET_EXECUTABLE)
+ set(CPACK_BINARY_NUGET ON)
+ else()
+ set(CPACK_BINARY_NUGET OFF)
+ endif()
+
+ if(WIN32)
+ # Macro to search for available Windows CE SDKs in the windows Registry
+ macro(select_wince_sdk selected_reg selected_sdk)
+ if(CMAKE_HOST_WIN32)
+ execute_process(COMMAND reg QUERY "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows CE Tools\\SDKs"
+ OUTPUT_VARIABLE sdk_reg
+ ERROR_VARIABLE my_err)
+ string(REGEX REPLACE "HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Wow6432Node\\\\Microsoft\\\\Windows CE Tools\\\\SDKs\\\\" ";" sdk_list "${sdk_reg}")
+ list(LENGTH sdk_list sdk_list_len)
+ if (${sdk_list_len} GREATER 1)
+ list(GET sdk_list 1 _sdk) # The first entry is always empty due to the regex replace above
+ string(STRIP ${_sdk} _sdk) # Make sure there is no newline in the SDK name
+ endif()
+ # Build a key to be used by get_filename_component that is pointing to the SDK directory
+ set(_reg "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows CE Tools\\SDKs\\${_sdk}]")
+ # Set return values
+ set(${selected_reg} ${_reg})
+ set(${selected_sdk} ${_sdk})
+ endif(CMAKE_HOST_WIN32)
+ endmacro(select_wince_sdk)
+
+ set(reg_vs10 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;InstallDir]")
+ set(reg_vs11 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0;InstallDir]")
+ set(reg_vs12 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0;InstallDir]")
+ set(reg_vs14 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0;InstallDir]")
+ set(reg_ws80 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v8.0;InstallationFolder]")
+ set(reg_ws81 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v8.1;InstallationFolder]")
+ set(reg_ws10_0 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0\\Setup\\Build Tools for Windows 10;srcPath]")
+ set(reg_wp80 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\WindowsPhone\\v8.0;InstallationFolder]")
+ set(reg_wp81 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\WindowsPhone\\v8.1;InstallationFolder]")
+ select_wince_sdk(reg_wince wince_sdk)
+ set(reg_tegra "[HKEY_LOCAL_MACHINE\\SOFTWARE\\NVIDIA Corporation\\Nsight Tegra;sdkRoot]")
+ set(reg_nasm "[HKEY_CURRENT_USER\\SOFTWARE\\nasm]")
+ foreach(reg vs10 vs11 vs12 vs14 ws80 ws81 ws10_0 wp80 wp81 wince tegra nasm)
+ get_filename_component(r "${reg_${reg}}" ABSOLUTE)
+ if(IS_DIRECTORY "${r}" AND NOT "${r}" STREQUAL "/registry")
+ set(${reg} 1)
+ else()
+ set(${reg} 0)
+ endif()
+ endforeach()
+ if(CMAKE_HOST_WIN32 AND COMMAND cmake_host_system_information)
+ set(info_vs15 "VS_15_DIR")
+ set(info_vs16 "VS_16_DIR")
+ set(vs_versions)
+ if(WIN32)
+ if(NOT CMAKE_VERSION VERSION_LESS 3.14)
+ set(vs_versions vs15 vs16)
+ elseif(NOT CMAKE_VERSION VERSION_LESS 3.8)
+ set(vs_versions vs15)
+ endif()
+ endif()
+ foreach(info ${vs_versions})
+ cmake_host_system_information(RESULT found QUERY "${info_${info}}")
+ if(found)
+ set(${info} 1)
+ else()
+ set(${info} 0)
+ endif()
+ endforeach()
+ endif()
+ endif()
+
+ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT DEFINED CMake_TEST_APPLE_SILICON)
+ execute_process(COMMAND sysctl -q hw.optional.arm64
+ OUTPUT_VARIABLE _sysctl_stdout
+ ERROR_VARIABLE _sysctl_stderr
+ RESULT_VARIABLE _sysctl_result
+ )
+ if(_sysctl_result EQUAL 0 AND _sysctl_stdout MATCHES "hw.optional.arm64: 1")
+ set(CMake_TEST_APPLE_SILICON 1)
+ else()
+ set(CMake_TEST_APPLE_SILICON 0)
+ endif()
+ unset(_sysctl_result)
+ unset(_sysctl_stderr)
+ unset(_sysctl_stdout)
+ endif()
+
+ #---------------------------------------------------------------------------
+ # Add tests below here.
+
+ if(NOT DEFINED CMake_TEST_Qt5)
+ set(CMake_TEST_Qt5 1)
+ endif()
+ if(CMake_TEST_Qt5)
+ find_package(Qt5Widgets QUIET NO_MODULE)
+ endif()
+
+ if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ add_subdirectory(CMakeLib)
+ endif()
+ add_subdirectory(CMakeOnly)
+ add_subdirectory(RunCMake)
+
+ add_subdirectory(FindPackageModeMakefileTest)
+
+ # Collect a list of all test build directories.
+ set(TEST_BUILD_DIRS)
+
+ # Should the long tests be run?
+ option(CMAKE_RUN_LONG_TESTS
+ "Should the long tests be run (such as Bootstrap)." ON)
+ mark_as_advanced(CMAKE_RUN_LONG_TESTS)
+
+ if (CMAKE_RUN_LONG_TESTS)
+ option(CTEST_TEST_CTEST
+ "Should the tests that run a full sub ctest process be run?"
+ OFF)
+ mark_as_advanced(CTEST_TEST_CTEST)
+ endif ()
+
+ # Should tests that use CVS be run?
+ #
+ set(do_cvs_tests 0)
+
+ if(EXISTS ${CMAKE_ROOT}/Modules/FindCVS.cmake)
+ find_package(CVS QUIET)
+ else()
+ find_program(CVS_EXECUTABLE NAMES cvs)
+ endif()
+
+ if(CVS_EXECUTABLE)
+ set(do_cvs_tests 1)
+ endif()
+
+ if(do_cvs_tests AND NOT UNIX)
+ if("${CVS_EXECUTABLE}" MATCHES "cygwin")
+ set(do_cvs_tests 0)
+ endif()
+ endif()
+
+ # Should CPack tests be run? By default, yes, but...
+ #
+ # Disable packaging test on Apple 10.3 and below. PackageMaker starts
+ # DiskManagementTool as root and disowns it
+ # (http://lists.apple.com/archives/installer-dev/2005/Jul/msg00005.html).
+ # It is left holding open pipe handles and preventing ProcessUNIX from
+ # detecting end-of-data even after its immediate child exits. Then
+ # the test hangs until it times out and is killed. This is a
+ # well-known bug in kwsys process execution that I would love to get
+ # time to fix.
+ #
+ option(CTEST_TEST_CPACK
+ "Should the tests that use '--build-target package' be run?"
+ ON)
+ mark_as_advanced(CTEST_TEST_CPACK)
+ set(CTEST_TEST_OSX_ARCH 0)
+ set(CMake_TEST_XCODE_VERSION 0)
+ if(APPLE)
+ set(CTEST_TEST_OSX_ARCH 1)
+ if(XCODE_VERSION)
+ set(CMake_TEST_XCODE_VERSION "${XCODE_VERSION}")
+ else()
+ execute_process(
+ COMMAND xcodebuild -version
+ OUTPUT_VARIABLE _version ERROR_VARIABLE _version
+ )
+ if(_version MATCHES "^Xcode ([0-9]+(\\.[0-9]+)*)")
+ set(CMake_TEST_XCODE_VERSION "${CMAKE_MATCH_1}")
+ endif()
+ endif()
+ if(NOT CMake_TEST_XCODE_VERSION VERSION_LESS 10)
+ # Since Xcode 10 we do not have two supported architectures for the host.
+ set(CTEST_TEST_OSX_ARCH 0)
+ endif()
+ if(CMAKE_OSX_SYSROOT)
+ execute_process(
+ COMMAND xcodebuild -sdk ${CMAKE_OSX_SYSROOT} -version ProductName
+ OUTPUT_VARIABLE _stdout
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE _stderr
+ RESULT_VARIABLE _failed
+ )
+ if(NOT _failed)
+ set(CMAKE_OSX_SDKPRODUCT "${_stdout}")
+ endif()
+
+ execute_process(
+ COMMAND xcodebuild -sdk ${CMAKE_OSX_SYSROOT} -version SDKVersion
+ OUTPUT_VARIABLE _stdout
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE _stderr
+ RESULT_VARIABLE _failed
+ )
+ if(NOT _failed)
+ set(CMAKE_OSX_SDKVERSION "${_stdout}")
+ endif()
+ endif()
+ endif()
+
+ # Use 1500 or CTEST_TEST_TIMEOUT for long test timeout value,
+ # whichever is greater.
+ set(CMAKE_LONG_TEST_TIMEOUT 1500)
+ if(CTEST_TEST_TIMEOUT)
+ set(CMAKE_LONG_TEST_TIMEOUT ${CTEST_TEST_TIMEOUT})
+ endif()
+ if(CMAKE_LONG_TEST_TIMEOUT LESS 1500)
+ set(CMAKE_LONG_TEST_TIMEOUT 1500)
+ endif()
+
+ add_test(NAME CMake.Copyright
+ COMMAND ${CMAKE_CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/CMakeCopyright.cmake)
+
+ # add a bunch of standard build-and-test style tests
+ ADD_TEST_MACRO(CommandLineTest CommandLineTest)
+ ADD_TEST_MACRO(FindPackageTest FindPackageTest)
+ ADD_TEST_MACRO(StringFileTest StringFileTest)
+ ADD_TEST_MACRO(TryCompile TryCompile)
+ ADD_TEST_MACRO(SystemInformation SystemInformation)
+ ADD_TEST_MACRO(MathTest MathTest)
+ ADD_TEST_MACRO(CompileFeatures CompileFeatures)
+ ADD_TEST_MACRO(CMakeCommands.target_compile_features)
+
+ if(CMake_TEST_RESOURCES)
+ ADD_TEST_MACRO(VSResource VSResource)
+ if (CMAKE_GENERATOR MATCHES "Ninja")
+ add_test_macro(VSResourceNinjaForceRSP VSResourceNinjaForceRSP)
+ endif ()
+ endif()
+ if(_isMultiConfig)
+ set(MSManifest_CTEST_OPTIONS -C $<CONFIGURATION>)
+ endif()
+ ADD_TEST_MACRO(MSManifest ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>)
+ ADD_TEST_MACRO(Simple Simple)
+ ADD_TEST_MACRO(PreOrder PreOrder)
+ ADD_TEST_MACRO(MissingSourceFile MissingSourceFile)
+ set_tests_properties(MissingSourceFile PROPERTIES
+ PASS_REGULAR_EXPRESSION "CMake Error at CMakeLists.txt:3 \\(add_executable\\):[ \r\n]*Cannot find source file:[ \r\n]*DoesNotExist/MissingSourceFile.c")
+ if(CMake_TEST_XCODE_VERSION AND CMAKE_OSX_SDKVERSION AND CMAKE_OSX_SDKPRODUCT)
+ if((NOT CMake_TEST_XCODE_VERSION VERSION_LESS 6.1) AND
+ ((NOT CMAKE_OSX_SDKPRODUCT STREQUAL "Mac OS X") OR
+ (NOT CMAKE_OSX_SDKVERSION VERSION_LESS 10.10)))
+ if(CMAKE_GENERATOR STREQUAL "Xcode")
+ set(CMake_TEST_XCODE_SWIFT 1)
+ endif()
+ endif()
+ endif()
+ if(CMAKE_Swift_COMPILER OR CMake_TEST_XCODE_SWIFT)
+ ADD_TEST_MACRO(SwiftOnly SwiftOnly)
+ if(CMake_TEST_XCODE_SWIFT)
+ ADD_TEST_MACRO(SwiftMix SwiftMix)
+ endif()
+ endif()
+ if(CMAKE_Fortran_COMPILER)
+ ADD_TEST_MACRO(FortranOnly FortranOnly)
+ endif()
+ # test Visual Studio GNU Fortran mixing with cmake_add_fortran_subdirectory
+ # run this project if we have a working fortran compiler or
+ # the test is enabled with CMAKE_TEST_CMAKE_ADD_FORTRAN cache variable.
+ # If you enable the test, CMake should find the MinGW fortran install,
+ # or in some cases you might need to set the PATH so that cmake can find
+ # the gfortran from mingw.
+ if(CMAKE_Fortran_COMPILER OR CMAKE_TEST_CMAKE_ADD_FORTRAN)
+ set(CMAKE_SKIP_VSGNUFortran FALSE)
+ # disable test for apple builds using ifort if they are building
+ # more than one architecture, as ifort does not support that.
+ if(APPLE AND (CMAKE_Fortran_COMPILER MATCHES ifort))
+ list(LENGTH CMAKE_OSX_ARCHITECTURES len)
+ if("${len}" GREATER 1)
+ message(STATUS "Skip VSGNUFortran for ifort dual cpu mac build")
+ set(CMAKE_SKIP_VSGNUFortran TRUE)
+ endif()
+ endif()
+ if(CMAKE_Fortran_COMPILER_ID STREQUAL IntelLLVM)
+ message(STATUS "Skip VSGNUFortran for ifx until DLLEXPORT support is implemented")
+ set(CMAKE_SKIP_VSGNUFortran TRUE)
+ endif()
+ if((CMAKE_C_COMPILER MATCHES lsb)
+ AND (CMAKE_Fortran_COMPILER MATCHES ifort))
+ message(STATUS "Skip VSGNUFortran for ifort and lsb compilers")
+ set(CMAKE_SKIP_VSGNUFortran TRUE)
+ endif()
+ if(NOT CMAKE_SKIP_VSGNUFortran)
+ ADD_TEST_MACRO(VSGNUFortran ${CMAKE_CMAKE_COMMAND} -P runtest.cmake)
+ endif()
+ endif()
+
+ if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|[9][0-9])")
+ ADD_TEST_MACRO(CSharpOnly CSharpOnly)
+ ADD_TEST_MACRO(CSharpLinkToCxx CSharpLinkToCxx)
+ ADD_TEST_MACRO(CSharpLinkFromCxx CSharpLinkFromCxx)
+ ADD_TEST_MACRO(CSharpWin32GenEx CSharpWin32GenEx)
+ set_tests_properties(CSharpWin32GenEx PROPERTIES
+ PASS_REGULAR_EXPRESSION "Target \"CSharpWin32GenEx\" has a generator expression in its\n WIN32_EXECUTABLE property\\. This is not supported on managed executables\\."
+ )
+ endif()
+
+ ADD_TEST_MACRO(COnly COnly)
+ ADD_TEST_MACRO(CxxOnly CxxOnly)
+ ADD_TEST_MACRO(CxxSubdirC CxxSubdirC)
+ ADD_TEST_MACRO(OutDir runtime/OutDir)
+ ADD_TEST_MACRO(OutName exe.OutName.exe)
+ ADD_TEST_MACRO(ObjectLibrary UseCshared)
+ ADD_TEST_MACRO(NewlineArgs NewlineArgs)
+ ADD_TEST_MACRO(SetLang SetLang)
+ ADD_TEST_MACRO(EmptyProperty EmptyProperty)
+ ADD_TEST_MACRO(ExternalOBJ ExternalOBJ)
+ if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ ADD_TEST_MACRO(LoadCommand LoadedCommand)
+ endif()
+ ADD_TEST_MACRO(LinkDirectory bin/LinkDirectory)
+ ADD_TEST_MACRO(LinkLanguage LinkLanguage)
+ ADD_TEST_MACRO(LinkLine LinkLine)
+ ADD_TEST_MACRO(MacroTest miniMacroTest)
+ ADD_TEST_MACRO(FunctionTest miniFunctionTest)
+ ADD_TEST_MACRO(ReturnTest ReturnTest)
+ ADD_TEST_MACRO(Properties Properties)
+ ADD_TEST_MACRO(Assembler HelloAsm)
+ ADD_TEST_MACRO(SourceGroups SourceGroups)
+ ADD_TEST_MACRO(Preprocess Preprocess)
+ set(ExportImport_BUILD_OPTIONS -DCMake_TEST_NESTED_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM}
+ -DCMake_TEST_CUDA:BOOL=${CMake_TEST_CUDA}
+ )
+ ADD_TEST_MACRO(ExportImport ExportImport)
+ set_property(TEST ExportImport APPEND
+ PROPERTY LABELS "CUDA")
+ ADD_TEST_MACRO(Unset Unset)
+ ADD_TEST_MACRO(PolicyScope PolicyScope)
+ ADD_TEST_MACRO(EmptyLibrary EmptyLibrary)
+ ADD_TEST_MACRO(CompileDefinitions CompileDefinitions)
+ if(CMAKE_Fortran_COMPILER)
+ set(CompileOptions_BUILD_OPTIONS -DTEST_FORTRAN=1)
+ endif()
+ ADD_TEST_MACRO(CompileOptions CompileOptions)
+ ADD_TEST_MACRO(CompatibleInterface CompatibleInterface)
+ ADD_TEST_MACRO(AliasTarget AliasTarget)
+ ADD_TEST_MACRO(StagingPrefix StagingPrefix)
+ ADD_TEST_MACRO(ImportedSameName ImportedSameName)
+ ADD_TEST_MACRO(InterfaceLibrary InterfaceLibrary)
+ if(NOT CMAKE_GENERATOR STREQUAL "Xcode")
+ if(_isMultiConfig)
+ set(ConfigSources_CTEST_OPTIONS --build-config $<CONFIGURATION>)
+ else()
+ set(ConfigSources_BUILD_OPTIONS -DCMAKE_BUILD_TYPE=$<CONFIGURATION>)
+ endif()
+ ADD_TEST_MACRO(ConfigSources ConfigSources)
+ endif()
+ ADD_TEST_MACRO(SourcesProperty SourcesProperty)
+ ADD_TEST_MACRO(SourceFileProperty SourceFileProperty)
+ if (NOT CMAKE_GENERATOR STREQUAL "Xcode")
+ ADD_TEST_MACRO(SourceFileIncludeDirProperty SourceFileIncludeDirProperty)
+ endif()
+ if(CMAKE_CXX_COMPILER_ID STREQUAL GNU
+ AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)
+ set(runCxxDialectTest 1)
+ endif()
+ if(CMAKE_CXX_COMPILER_ID STREQUAL Clang
+ AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4 AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ if(NOT APPLE OR POLICY CMP0025)
+ set(runCxxDialectTest 1)
+ endif()
+ endif()
+ if(runCxxDialectTest)
+ ADD_TEST_MACRO(CxxDialect CxxDialect)
+ endif()
+ set_tests_properties(EmptyLibrary PROPERTIES
+ PASS_REGULAR_EXPRESSION "CMake Error: CMake can not determine linker language for target: test")
+ ADD_TEST_MACRO(CrossCompile CrossCompile)
+ set_tests_properties(CrossCompile PROPERTIES
+ PASS_REGULAR_EXPRESSION "TRY_RUN.. invoked in cross-compiling mode")
+ if("${CMAKE_GENERATOR}" MATCHES "Make")
+ ADD_TEST_MACRO(Policy0002 Policy0002)
+ endif()
+ if(CTEST_TEST_OSX_ARCH)
+ ADD_TEST_MACRO(Architecture Architecture)
+ set_tests_properties(Architecture PROPERTIES
+ PASS_REGULAR_EXPRESSION "(file is not of required architecture|does not match cputype|not the architecture being linked)")
+ endif()
+
+ list(APPEND TEST_BUILD_DIRS ${CMake_TEST_INSTALL_PREFIX})
+
+ if(NOT DEFINED CMake_TEST_Qt4)
+ set(CMake_TEST_Qt4 1)
+ endif()
+ if(CMake_TEST_Qt4 AND NOT QT4_FOUND)
+ find_package(Qt4 QUIET)
+ endif()
+
+ if(CMake_TEST_Qt4 AND QT4_FOUND)
+ # test whether the Qt4 which has been found works, on some machines
+ # which run nightly builds there were errors like "wrong file format"
+ # for libQtCore.so. So first check it works, and only if it does add
+ # the automoc test.
+ include(CheckCXXSourceCompiles)
+ set(_save_CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES}")
+ set(_save_CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}")
+
+ set(CMAKE_REQUIRED_INCLUDES ${QT_INCLUDES})
+ set(CMAKE_REQUIRED_LIBRARIES ${QT_QTCORE_LIBRARIES})
+
+ CHECK_CXX_SOURCE_COMPILES("#include <QCoreApplication>\n int main() {return (qApp == 0 ? 0 : 1); }\n"
+ QT4_WORKS)
+
+ set(CMAKE_REQUIRED_INCLUDES "${_save_CMAKE_REQUIRED_INCLUDES}")
+ set(CMAKE_REQUIRED_LIBRARIES "${_save_CMAKE_REQUIRED_LIBRARIES}")
+ endif()
+
+ # run test for BundleUtilities on supported platforms/compilers
+ if(MSVC OR
+ MINGW OR
+ CMAKE_SYSTEM_NAME MATCHES "Linux" OR
+ CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ if(NOT "${CMAKE_GENERATOR}" STREQUAL "Watcom WMake")
+
+ add_test(BundleUtilities ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/BundleUtilities"
+ "${CMake_BINARY_DIR}/Tests/BundleUtilities"
+ ${build_generator_args}
+ --build-project BundleUtilities
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/BundleUtilities")
+
+ # run test for DeployQt4 on supported platforms/compilers (which depends on BundleUtilities)
+ # this test also depends on the existence of the standard qtiff plugin
+ if(QT4_WORKS AND QT_QTSQL_FOUND)
+ add_test(Qt4Deploy ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Qt4Deploy"
+ "${CMake_BINARY_DIR}/Tests/Qt4Deploy"
+ ${build_generator_args}
+ --build-project Qt4Deploy
+ --build-options
+ -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+ -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Qt4Deploy")
+ endif()
+
+ endif()
+ endif()
+
+ set(CMAKE_BUILD_TEST_SOURCE_DIR "${CMake_SOURCE_DIR}/Tests/COnly")
+ set(CMAKE_BUILD_TEST_BINARY_DIR "${CMake_BINARY_DIR}/Tests/CMakeBuildCOnly")
+ set(CMAKE_BUILD_TEST_EXE COnly)
+ configure_file("${CMake_SOURCE_DIR}/Tests/CMakeBuildTest.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CMakeBuildTest.cmake" @ONLY)
+ add_test(CMakeBuildTest ${CMAKE_CMAKE_COMMAND} -P
+ "${CMake_BINARY_DIR}/Tests/CMakeBuildTest.cmake")
+ list(APPEND TEST_BUILD_DIRS ${CMAKE_BUILD_TEST_BINARY_DIR})
+ # now do it again for a project that has two project commands
+ set(CMAKE_BUILD_TEST_SOURCE_DIR "${CMake_SOURCE_DIR}/Tests/DoubleProject")
+ set(CMAKE_BUILD_TEST_BINARY_DIR "${CMake_BINARY_DIR}/Tests/DoubleProject")
+ set(CMAKE_BUILD_TEST_EXE just_silly)
+ configure_file("${CMake_SOURCE_DIR}/Tests/CMakeBuildTest.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CMakeBuildDoubleProjectTest.cmake" @ONLY)
+ add_test(CMakeDoubleProject ${CMAKE_CMAKE_COMMAND} -P
+ "${CMake_BINARY_DIR}/Tests/CMakeBuildDoubleProjectTest.cmake")
+ list(APPEND TEST_BUILD_DIRS ${CMAKE_BUILD_TEST_BINARY_DIR})
+
+ ADD_TEST_MACRO(Module.CheckTypeSize CheckTypeSize)
+
+ set(Module.CheckIPOSupported-C_BUILD_OPTIONS -DCMake_TEST_IPO_WORKS_C=${CMake_TEST_IPO_WORKS_C})
+ ADD_TEST_MACRO(Module.CheckIPOSupported-C CheckIPOSupported-C)
+
+ set(Module.CheckIPOSupported-CXX_BUILD_OPTIONS -DCMake_TEST_IPO_WORKS_CXX=${CMake_TEST_IPO_WORKS_CXX})
+ ADD_TEST_MACRO(Module.CheckIPOSupported-CXX CheckIPOSupported-CXX)
+
+ if(CMAKE_Fortran_COMPILER)
+ set(Module.CheckIPOSupported-Fortran_BUILD_OPTIONS -DCMake_TEST_IPO_WORKS_Fortran=${CMake_TEST_IPO_WORKS_Fortran})
+ ADD_TEST_MACRO(Module.CheckIPOSupported-Fortran CheckIPOSupported-Fortran)
+ endif()
+
+ add_test(Module.ExternalData ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Module/ExternalData"
+ "${CMake_BINARY_DIR}/Tests/Module/ExternalData"
+ ${build_generator_args}
+ --build-project ExternalDataTest
+ --build-noclean
+ --force-new-ctest-process
+ --build-options
+ -DMAKE_SUPPORTS_SPACES=${MAKE_SUPPORTS_SPACES}
+ --test-command ${CMAKE_CTEST_COMMAND} -C \${CTEST_CONFIGURATION_TYPE} -V
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Module/ExternalData")
+
+ ADD_TEST_MACRO(Module.FindDependency FindDependency)
+
+ ADD_TEST_MACRO(Module.WriteCompilerDetectionHeader WriteCompilerDetectionHeader)
+
+ if (APPLE OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ include(CheckCXXCompilerFlag)
+ check_cxx_compiler_flag(-fPIE run_pic_test)
+ else()
+ if (CMAKE_CXX_COMPILER_ID MATCHES "PGI"
+ OR CMAKE_CXX_COMPILER_ID MATCHES "PathScale"
+ OR CMAKE_CXX_COMPILER_ID MATCHES "Intel")
+ set(run_pic_test 0)
+ else()
+ set(run_pic_test 1)
+ endif()
+ endif()
+
+ if (run_pic_test)
+ ADD_TEST_MACRO(PositionIndependentTargets PositionIndependentTargets)
+ endif()
+
+ if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") AND
+ (NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 4.2) AND
+ (CMAKE_SYSTEM_NAME MATCHES "Linux"))
+
+ include(CheckCXXCompilerFlag)
+ check_cxx_compiler_flag(
+ -fvisibility-inlines-hidden run_inlines_hidden_test)
+ endif()
+
+ if(run_inlines_hidden_test)
+ add_test(Visibility ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Visibility"
+ "${CMake_BINARY_DIR}/Tests/Visibility"
+ ${build_generator_args}
+ --build-project Visibility
+ )
+ list(APPEND TEST_BUILD_DIRS
+ "${CMake_BINARY_DIR}/Tests/Visibility"
+ )
+ endif()
+
+ add_test(LinkFlags-prepare
+ ${CMAKE_CTEST_COMMAND} -C \${CTEST_CONFIGURATION_TYPE}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/LinkFlags"
+ "${CMake_BINARY_DIR}/Tests/LinkFlags"
+ ${build_generator_args}
+ --build-project LinkFlags
+ --build-target LinkFlags
+ --build-options
+ -DTEST_CONFIG=\${CTEST_CONFIGURATION_TYPE}
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/LinkFlags")
+
+ macro(ADD_LINK_FLAGS_TEST name depends)
+ add_test(LinkFlags-${name}
+ ${CMAKE_CMAKE_COMMAND} --build "${CMake_BINARY_DIR}/Tests/LinkFlags"
+ --target LinkFlags_${name} --config \${CTEST_CONFIGURATION_TYPE}
+ )
+ set_tests_properties(LinkFlags-${name} PROPERTIES
+ PASS_REGULAR_EXPRESSION "BADFLAG" DEPENDS LinkFlags-${depends})
+ endmacro()
+ ADD_LINK_FLAGS_TEST(lib prepare)
+ ADD_LINK_FLAGS_TEST(dll lib)
+ ADD_LINK_FLAGS_TEST(mod dll)
+ ADD_LINK_FLAGS_TEST(exe mod)
+ ADD_LINK_FLAGS_TEST(lib_config exe)
+ ADD_LINK_FLAGS_TEST(dll_config lib_config)
+ ADD_LINK_FLAGS_TEST(mod_config dll_config)
+ ADD_LINK_FLAGS_TEST(exe_config mod_config)
+ ADD_LINK_FLAGS_TEST(lib_flags exe_config)
+ ADD_LINK_FLAGS_TEST(dll_flags lib_flags)
+ ADD_LINK_FLAGS_TEST(mod_flags dll_flags)
+ ADD_LINK_FLAGS_TEST(exe_flags mod_flags)
+ ADD_LINK_FLAGS_TEST(lib_flags_config exe_flags)
+ ADD_LINK_FLAGS_TEST(dll_flags_config lib_flags_config)
+ ADD_LINK_FLAGS_TEST(mod_flags_config dll_flags_config)
+ ADD_LINK_FLAGS_TEST(exe_flags_config mod_flags_config)
+
+ # If we are running right now with a Unix Makefiles or Ninja based generator,
+ # build the "Simple" test with the ExtraGenerators, if available
+ # This doesn't test whether the generated project files work (unfortunately),
+ # mainly it tests that cmake doesn't crash when generating these project files.
+ if(CMAKE_GENERATOR MATCHES "^(Unix Makefiles|Ninja)$"
+ AND NOT "${CMAKE_CURRENT_BINARY_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
+ foreach(extraGenerator
+ "CodeBlocks"
+ "CodeLite"
+ "Eclipse CDT4"
+ "Kate"
+ "Sublime Text 2"
+ )
+ string(REPLACE " " "" extraGeneratorTestName "Simple_${extraGenerator}Generator")
+ add_test(${extraGeneratorTestName} ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Simple"
+ "${CMake_BINARY_DIR}/Tests/${extraGeneratorTestName}"
+ --build-two-config
+ --build-generator "${extraGenerator} - ${CMAKE_GENERATOR}"
+ --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+ --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+ --build-project Simple
+ --test-command Simple)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${extraGeneratorTestName}")
+ endforeach()
+ endif()
+
+ # test for correct sub-project generation
+ # not implemented in Xcode or Ninja
+ if(NOT CMAKE_GENERATOR MATCHES "Xcode|Ninja")
+ # run cmake and configure all of SubProject
+ # but only build the independent executable car
+ add_test(SubProject ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/SubProject"
+ "${CMake_BINARY_DIR}/Tests/SubProject"
+ --build-project SubProject
+ ${build_generator_args}
+ --build-target car
+ --test-command car
+ )
+
+ # For stage 2, do not run cmake again.
+ # Then build the foo sub project which should build
+ # the bar library which should be referenced because
+ # foo links to the static library bar, but bar is not
+ # directly in the foo sub project
+ if(CMake_TEST_EXPLICIT_MAKE_PROGRAM)
+ set(SubProject-Stage2_BUILD_MAKEPROGRAM
+ --build-makeprogram ${CMake_TEST_EXPLICIT_MAKE_PROGRAM}
+ )
+ endif()
+ add_test(SubProject-Stage2 ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/SubProject/foo"
+ "${CMake_BINARY_DIR}/Tests/SubProject/foo"
+ --build-generator ${CMAKE_GENERATOR}
+ --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+ --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+ ${SubProject-Stage2_BUILD_MAKEPROGRAM}
+ --build-nocmake
+ --build-project foo
+ --build-target foo
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/SubProject/foo"
+ --test-command foo
+ )
+ set_tests_properties ( SubProject-Stage2 PROPERTIES DEPENDS SubProject)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/SubProject")
+ endif()
+
+ # add tests with more complex invocations
+ add_test(Framework ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Framework"
+ "${CMake_BINARY_DIR}/Tests/Framework"
+ --build-two-config
+ ${build_generator_args}
+ --build-project Framework
+ --build-options
+ -DMAKE_SUPPORTS_SPACES=${MAKE_SUPPORTS_SPACES}
+ "-DCMAKE_INSTALL_PREFIX:PATH=${CMake_BINARY_DIR}/Tests/Framework/Install"
+ --test-command bar)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Framework")
+
+ add_test(TargetName ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/TargetName"
+ "${CMake_BINARY_DIR}/Tests/TargetName"
+ --build-two-config
+ ${build_generator_args}
+ --build-project TargetName
+ --test-command ${CMAKE_CMAKE_COMMAND} -E compare_files
+ ${CMake_SOURCE_DIR}/Tests/TargetName/scripts/hello_world
+ ${CMake_BINARY_DIR}/Tests/TargetName/scripts/hello_world)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/TargetName")
+
+ add_test(LibName ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/LibName"
+ "${CMake_BINARY_DIR}/Tests/LibName"
+ --build-two-config
+ ${build_generator_args}
+ --build-project LibName
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/LibName/lib"
+ --build-options
+ -DMAKE_SUPPORTS_SPACES=${MAKE_SUPPORTS_SPACES}
+ --test-command foobar
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/LibName")
+
+ add_test(CustComDepend ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/CustComDepend"
+ "${CMake_BINARY_DIR}/Tests/CustComDepend"
+ --build-two-config
+ ${build_generator_args}
+ --build-project CustComDepend
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/CustComDepend/bin"
+ --test-command foo bar.c
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CustComDepend")
+
+ add_test(ArgumentExpansion ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/ArgumentExpansion"
+ "${CMake_BINARY_DIR}/Tests/ArgumentExpansion"
+ ${build_generator_args}
+ --build-project ArgumentExpansion
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/ArgumentExpansion/bin"
+ )
+ set_tests_properties(ArgumentExpansion PROPERTIES
+ FAIL_REGULAR_EXPRESSION "Unexpected: ")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ArgumentExpansion")
+
+ add_test(GeneratorExpression
+ ${CMAKE_CTEST_COMMAND} -C \${CTEST_CONFIGURATION_TYPE}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/GeneratorExpression"
+ "${CMake_BINARY_DIR}/Tests/GeneratorExpression"
+ ${build_generator_args}
+ --build-project GeneratorExpression
+ --build-options
+ -DCMAKE_BUILD_TYPE=\${CTEST_CONFIGURATION_TYPE}
+ --test-command ${CMAKE_CTEST_COMMAND} -C \${CTEST_CONFIGURATION_TYPE} -V
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/GeneratorExpression")
+
+ add_test(CustomCommand ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/CustomCommand"
+ "${CMake_BINARY_DIR}/Tests/CustomCommand"
+ --build-two-config
+ ${build_generator_args}
+ --build-project CustomCommand
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/CustomCommand/bin"
+ --build-options
+ --test-command CustomCommand
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CustomCommand")
+
+ ADD_TEST_MACRO(CustomCommandByproducts CustomCommandByproducts)
+
+ ADD_TEST_MACRO(CommandLength CommandLength)
+
+ ADD_TEST_MACRO(EmptyDepends ${CMAKE_CTEST_COMMAND})
+
+ add_test(CustomCommandWorkingDirectory ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/CustomCommandWorkingDirectory"
+ "${CMake_BINARY_DIR}/Tests/CustomCommandWorkingDirectory"
+ --build-two-config
+ ${build_generator_args}
+ --build-project TestWorkingDir
+ --test-command working
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CustomCommandWorkingDirectory")
+
+ add_test(OutOfSource ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/OutOfSource"
+ "${CMake_BINARY_DIR}/Tests/OutOfSource"
+ ${build_generator_args}
+ --build-project OutOfSource
+ --build-two-config
+ --test-command
+ "${CMake_BINARY_DIR}/Tests/OutOfSource/SubDir/OutOfSourceSubdir/simple")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/OutOfSource")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/OutOfSourceDeep")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/OutOfBinary")
+
+ add_test(BuildDepends ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/BuildDepends"
+ "${CMake_BINARY_DIR}/Tests/BuildDepends"
+ ${build_generator_args}
+ --build-project BuildDepends
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/BuildDepends")
+
+ set(MissingInstallInstallDir
+ "${CMake_BINARY_DIR}/Tests/MissingInstall/InstallDirectory")
+ add_test(MissingInstall ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/MissingInstall"
+ "${CMake_BINARY_DIR}/Tests/MissingInstall"
+ ${build_generator_args}
+ --build-project TestMissingInstall
+ --build-two-config
+ --build-options
+ "-DCMAKE_INSTALL_PREFIX:PATH=${MissingInstallInstallDir}")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/MissingInstall")
+
+ # By default, run the CPackComponents test if the CTEST_TEST_CPACK
+ # option is ON:
+ #
+ set(CTEST_RUN_CPackComponents ${CTEST_TEST_CPACK})
+ set(CTEST_package_X11_TEST ${CTEST_TEST_CPACK})
+ set(CTEST_RUN_CPackComponentsForAll ${CTEST_TEST_CPACK})
+ set(CTEST_RUN_CPackComponentsPrefix ${CTEST_TEST_CPACK})
+
+ find_program(NSIS_MAKENSIS_EXECUTABLE NAMES makensis
+ PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS]
+ DOC "makensis program location"
+ )
+
+ # But on Windows, only run the CPackComponents test if the NSIS
+ # installer builder is available:
+ #
+ if(WIN32)
+ if(NSIS_MAKENSIS_EXECUTABLE)
+ set(CTEST_RUN_CPackComponents ON)
+ else()
+ set(CTEST_RUN_CPackComponents OFF)
+ set(CTEST_package_X11_TEST OFF)
+ endif()
+ endif()
+
+ # On Windows run the CPackWiXGenerator test
+ # if the WiX Toolset seems to be available
+ if(WIN32)
+ file(TO_CMAKE_PATH "$ENV{WIX}" WIX_ROOT)
+
+ find_program(WIX_LIGHT_EXECUTABLE light
+ PATHS "${WIX_ROOT}/bin"
+ DOC "WiX Toolset light.exe location")
+
+ if(WIX_LIGHT_EXECUTABLE)
+ add_test(CPackWiXGenerator ${CMAKE_CTEST_COMMAND}
+ -C \${CTEST_CONFIGURATION_TYPE}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/CPackWiXGenerator"
+ "${CMake_BINARY_DIR}/Tests/CPackWiXGenerator"
+ ${build_generator_args}
+ --build-project CPackWiXGenerator
+ --build-options
+ --test-command ${CMAKE_CMAKE_COMMAND}
+ "-DCPackWiXGenerator_BINARY_DIR:PATH=${CMake_BINARY_DIR}/Tests/CPackWiXGenerator"
+ "-Dno_verify:BOOL=${CMake_TEST_WIX_NO_VERIFY}"
+ "-Dconfig=\${CTEST_CONFIGURATION_TYPE}"
+ -P "${CMake_SOURCE_DIR}/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake")
+
+ set_property(TEST CPackWiXGenerator PROPERTY
+ ATTACHED_FILES_ON_FAIL
+ "${CMake_BINARY_DIR}/Tests/CPackWiXGenerator/_CPack_Packages/win32/WIX/wix.log")
+ endif()
+ endif()
+
+ # On Windows run the CPackNSISGenerator test
+ # if the nsis is available
+ if(WIN32 AND NSIS_MAKENSIS_EXECUTABLE)
+ add_test(CPackNSISGenerator ${CMAKE_CTEST_COMMAND}
+ -C \${CTEST_CONFIGURATION_TYPE}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/CPackNSISGenerator"
+ "${CMake_BINARY_DIR}/Tests/CPackNSISGenerator"
+ ${build_generator_args}
+ --build-project CPackNSISGenerator
+ --build-options
+ --test-command ${CMAKE_CMAKE_COMMAND}
+ "-DCPackNSISGenerator_BINARY_DIR:PATH=${CMake_BINARY_DIR}/Tests/CPackNSISGenerator"
+ "-Dconfig=\${CTEST_CONFIGURATION_TYPE}"
+ -P "${CMake_SOURCE_DIR}/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake")
+
+ set_property(TEST CPackNSISGenerator PROPERTY
+ ATTACHED_FILES_ON_FAIL
+ "${CMake_BINARY_DIR}/Tests/CPackNSISGenerator/_CPack_Packages/win32/NSIS/NSISOutput.log")
+ endif()
+
+ if(CTEST_TEST_CPACK)
+ add_test(CPackUseDefaultVersion ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/CPackUseDefaultVersion"
+ "${CMake_BINARY_DIR}/Tests/CPackUseDefaultVersion"
+ ${build_generator_args}
+ --build-project CPackUseDefaultVersion
+ --build-two-config
+ --build-options
+ ${CPackUseDefaultVersion_BUILD_OPTIONS})
+ set_tests_properties(CPackUseDefaultVersion PROPERTIES PASS_REGULAR_EXPRESSION "CPACK_PACKAGE_VERSION=0\\.1\\.1")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CPackUseDefaultVersion")
+
+ add_test(CPackUseProjectVersion ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/CPackUseProjectVersion"
+ "${CMake_BINARY_DIR}/Tests/CPackUseProjectVersion"
+ ${build_generator_args}
+ --build-project CPackUseProjectVersion
+ --build-two-config
+ --build-options
+ ${CPackUseProjectVersion_BUILD_OPTIONS})
+ set_tests_properties(CPackUseProjectVersion PROPERTIES PASS_REGULAR_EXPRESSION "CPACK_PACKAGE_VERSION=1\\.2\\.3")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CPackUseProjectVersion")
+
+ add_test(CPackUseShortProjectVersion ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/CPackUseShortProjectVersion"
+ "${CMake_BINARY_DIR}/Tests/CPackUseShortProjectVersion"
+ ${build_generator_args}
+ --build-project CPackUseShortProjectVersion
+ --build-two-config
+ --build-options
+ ${CPackUseProjectVersion_BUILD_OPTIONS})
+ set_tests_properties(CPackUseShortProjectVersion PROPERTIES PASS_REGULAR_EXPRESSION "CPACK_PACKAGE_VERSION=2")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CPackUseShortProjectVersion")
+ endif()
+
+ if(CTEST_RUN_CPackComponents)
+ set(CPackComponents_BUILD_OPTIONS)
+ if(APPLE)
+ set(CPackComponents_BUILD_OPTIONS -DCPACK_BINARY_DRAGNDROP:BOOL=ON)
+ if(CMake_TEST_XCODE_VERSION VERSION_GREATER "4.6")
+ set(CPackComponents_BUILD_OPTIONS ${CPackComponents_BUILD_OPTIONS}
+ -DCPACK_BINARY_PRODUCTBUILD:BOOL=ON)
+ endif()
+ endif()
+ if(NSIS_MAKENSIS_EXECUTABLE)
+ set(CPackComponents_BUILD_OPTIONS ${CPackComponents_BUILD_OPTIONS}
+ -DCPACK_BINARY_NSIS:BOOL=ON)
+ endif()
+
+ add_test(CPackComponents ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/CPackComponents"
+ "${CMake_BINARY_DIR}/Tests/CPackComponents"
+ ${build_generator_args}
+ --build-project CPackComponents
+ --build-two-config
+ --build-target package
+ --build-options
+ -DCPACK_BINARY_DEB:BOOL=${CPACK_BINARY_DEB}
+ -DCPACK_BINARY_RPM:BOOL=${CPACK_BINARY_RPM}
+ ${CPackComponents_BUILD_OPTIONS}
+ --graphviz=CPackComponents.dot
+ --test-command ${CMAKE_CMAKE_COMMAND}
+ "-DCPackComponents_BINARY_DIR:PATH=${CMake_BINARY_DIR}/Tests/CPackComponents"
+ -P "${CMake_SOURCE_DIR}/Tests/CPackComponents/VerifyResult.cmake")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CPackComponents")
+ endif()
+
+ if(CTEST_RUN_CPackComponentsForAll)
+ # Check whether if rpmbuild command is found
+ # before adding RPM tests
+ if(CPACK_BINARY_RPM)
+ list(APPEND ACTIVE_CPACK_GENERATORS RPM)
+ endif()
+ # Check whether if dpkg command is found
+ # before adding DEB tests
+ if(CPACK_BINARY_DEB)
+ list(APPEND ACTIVE_CPACK_GENERATORS DEB)
+ endif()
+ # Check whether if NuGet command is found
+ # before adding NuGet tests
+ if(CPACK_BINARY_NUGET)
+ list(APPEND ACTIVE_CPACK_GENERATORS NUGET)
+ set(CPACK_GENERATOR_STRING_NUGET NuGet)
+ endif()
+
+ # ACTIVE_CPACK_GENERATORS variable
+ # now contains the list of 'active generators'
+ set(CPackComponentsForAll_BUILD_OPTIONS)
+ # set up list of CPack generators
+ list(APPEND ACTIVE_CPACK_GENERATORS "ZIP")
+ if(APPLE)
+ list(APPEND ACTIVE_CPACK_GENERATORS "DragNDrop")
+ if(CMake_TEST_XCODE_VERSION VERSION_GREATER "4.6")
+ list(APPEND ACTIVE_CPACK_GENERATORS "productbuild")
+ endif()
+ endif()
+
+ # set up list of component packaging ways
+ list(APPEND CWAYLST "default")
+ list(APPEND CWAYLST "OnePackPerGroup")
+ list(APPEND CWAYLST "IgnoreGroup")
+ list(APPEND CWAYLST "AllInOne")
+ foreach(CPackGen IN LISTS ACTIVE_CPACK_GENERATORS)
+ if(NOT DEFINED CPACK_GENERATOR_STRING_${CPackGen})
+ set(CPACK_GENERATOR_STRING_${CPackGen} ${CPackGen})
+ endif()
+ set(CPackRun_CPackGen "-DCPackGen=${CPACK_GENERATOR_STRING_${CPackGen}}")
+ foreach(CPackComponentWay ${CWAYLST})
+ set(CPackRun_CPackComponentWay "-DCPackComponentWay=${CPackComponentWay}")
+ add_test(CPackComponentsForAll-${CPackGen}-${CPackComponentWay}
+ ${CMAKE_CTEST_COMMAND} -C \${CTEST_CONFIGURATION_TYPE}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/CPackComponentsForAll"
+ "${CMake_BINARY_DIR}/Tests/CPackComponentsForAll/build${CPackGen}-${CPackComponentWay}"
+ ${build_generator_args}
+ --build-project CPackComponentsForAll
+ --build-options
+ -DCPACK_GENERATOR:STRING=${CPACK_GENERATOR_STRING_${CPackGen}}
+ -DCPACK_BINARY_${CPackGen}:BOOL=ON
+ ${CPackRun_CPackComponentWay}
+ ${CPackComponentsForAll_BUILD_OPTIONS}
+ --graphviz=CPackComponentsForAll.dot
+ --test-command ${CMAKE_CMAKE_COMMAND}
+ "-DCPackComponentsForAll_BINARY_DIR:PATH=${CMake_BINARY_DIR}/Tests/CPackComponentsForAll/build${CPackGen}-${CPackComponentWay}"
+ "${CPackRun_CPackGen}"
+ "${CPackRun_CPackComponentWay}"
+ -P "${CMake_SOURCE_DIR}/Tests/CPackComponentsForAll/RunCPackVerifyResult.cmake")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CPackComponentsForAll/build${CPackGen}-${CPackComponentWay}")
+ endforeach()
+ endforeach()
+
+ # debian specific
+ if(DPKG_EXECUTABLE)
+ unset(CPackRun_CPackDEBConfiguration_ALL_CONFIGS)
+ set(DEB_TEST_NAMES "CPackComponentsDEB")
+ set(DEB_CONFIGURATIONS_TO_TEST "components-lintian-dpkgdeb-checks"
+ "components-description1"
+ "components-description2"
+ "components-source"
+ "components-shlibdeps1"
+ "components-depend1"
+ "components-depend2"
+ "compression")
+ # Run additional tests if dpkg-shlibdeps is available (and is new enough version)
+ find_program(SHLIBDEPS_EXECUTABLE NAMES dpkg-shlibdeps)
+ if(SHLIBDEPS_EXECUTABLE)
+ # Check version of the dpkg-shlibdeps tool
+ execute_process(COMMAND ${CMAKE_COMMAND} -E env LC_ALL=C ${SHLIBDEPS_EXECUTABLE} --version
+ OUTPUT_VARIABLE _TMP_VERSION
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(_TMP_VERSION MATCHES "dpkg-shlibdeps version ([0-9]+\\.[0-9]+\\.[0-9]+)")
+ set(SHLIBDEPS_EXECUTABLE_VERSION "${CMAKE_MATCH_1}")
+ else()
+ unset(SHLIBDEPS_EXECUTABLE_VERSION)
+ endif()
+ if(NOT SHLIBDEPS_EXECUTABLE_VERSION VERSION_LESS 1.19 OR
+ (NOT SHLIBDEPS_EXECUTABLE_VERSION VERSION_LESS 1.17 AND NOT CMAKE_BINARY_DIR MATCHES ".*[ ].*"))
+ list(APPEND DEB_CONFIGURATIONS_TO_TEST "shlibdeps-with-private-lib-failure"
+ "shlibdeps-with-private-lib-success")
+ endif()
+ endif()
+
+ set(CPackGen "DEB")
+ set(CPackRun_CPackGen "-DCPackGen=${CPackGen}")
+
+ foreach(CPackDEBConfiguration IN LISTS DEB_CONFIGURATIONS_TO_TEST)
+ set(CPackRun_CPackDEBConfiguration "-DCPackDEBConfiguration=${CPackDEBConfiguration}")
+ add_test(NAME ${DEB_TEST_NAMES}-${CPackDEBConfiguration} COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIG>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/${DEB_TEST_NAMES}"
+ "${CMake_BINARY_DIR}/Tests/${DEB_TEST_NAMES}/build${CPackGen}-${CPackDEBConfiguration}"
+ ${build_generator_args}
+ --build-project CPackComponentsDEB
+ --build-options
+ -DCPACK_GENERATOR:STRING=${CPackGen}
+ -DCPACK_BINARY_${CPackGen}:BOOL=ON
+ ${CPackRun_CPackDEBConfiguration}
+ ${CPackRun_CPackDEBConfiguration_ALL_CONFIGS}
+ --graphviz=${DEB_TEST_NAMES}.dot
+ --test-command ${CMAKE_CMAKE_COMMAND}
+ "-D${DEB_TEST_NAMES}_SOURCE_DIR:PATH=${CMake_SOURCE_DIR}/Tests/${DEB_TEST_NAMES}"
+ "-D${DEB_TEST_NAMES}_BINARY_DIR:PATH=${CMake_BINARY_DIR}/Tests/${DEB_TEST_NAMES}/build${CPackGen}-${CPackDEBConfiguration}"
+ "${CPackRun_CPackGen}"
+ "${CPackRun_CPackDEBConfiguration}"
+ "-DCONFIG=$<CONFIG>"
+ -P "${CMake_SOURCE_DIR}/Tests/${DEB_TEST_NAMES}/RunCPackVerifyResult-${CPackDEBConfiguration}.cmake")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${DEB_TEST_NAMES}/build${CPackGen}-${CPackDEBConfiguration}")
+ endforeach()
+ endif()
+
+ endif()
+
+ # By default, turn this test off (because it takes a long time...)
+ #
+ if(NOT DEFINED CTEST_RUN_CPackTestAllGenerators)
+ set(CTEST_RUN_CPackTestAllGenerators OFF)
+
+ # ...but: if it appears to be a coverage dashboard, or long tests are
+ # on, then set it to the generic CTEST_TEST_CPACK setting.
+ #
+ if(CMAKE_CXX_FLAGS MATCHES "-ftest-coverage" OR
+ NOT "$ENV{COVFILE}" STREQUAL "" OR
+ CMAKE_RUN_LONG_TESTS)
+ set(CTEST_RUN_CPackTestAllGenerators ${CTEST_TEST_CPACK})
+ endif()
+ endif()
+
+ if(CTEST_RUN_CPackTestAllGenerators)
+ add_test(CPackTestAllGenerators ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/CPackTestAllGenerators"
+ "${CMake_BINARY_DIR}/Tests/CPackTestAllGenerators"
+ ${build_generator_args}
+ --build-project CPackTestAllGenerators
+ --test-command
+ ${CMAKE_CMAKE_COMMAND}
+ -D dir=${CMake_BINARY_DIR}/Tests/CPackTestAllGenerators
+ -P ${CMake_SOURCE_DIR}/Tests/CPackTestAllGenerators/RunCPack.cmake
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CPackTestAllGenerators")
+ endif()
+
+ if(CTEST_RUN_CPackComponentsPrefix)
+ set(CPackComponents_BUILD_OPTIONS)
+ if(APPLE)
+ set(CPackComponents_BUILD_OPTIONS -DCPACK_BINARY_DRAGNDROP:BOOL=ON)
+ if(CMake_TEST_XCODE_VERSION VERSION_GREATER "4.6")
+ set(CPackComponents_BUILD_OPTIONS ${CPackComponents_BUILD_OPTIONS}
+ -DCPACK_BINARY_PRODUCTBUILD:BOOL=ON)
+ endif()
+ endif()
+ if(NOT NSIS_MAKENSIS_EXECUTABLE)
+ set(CPackComponents_BUILD_OPTIONS ${CPackComponents_BUILD_OPTIONS}
+ -DCPACK_BINARY_NSIS:BOOL=OFF)
+ endif()
+
+ add_test(CPackComponentsPrefix ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/CPackComponentsPrefix"
+ "${CMake_BINARY_DIR}/Tests/CPackComponentsPrefix"
+ ${build_generator_args}
+ --build-project CPackComponentsPrefix
+ --build-two-config
+ --build-target package
+ --build-options
+ -DCPACK_BINARY_DEB:BOOL=${CPACK_BINARY_DEB}
+ -DCPACK_BINARY_RPM:BOOL=${CPACK_BINARY_RPM}
+ -DCPACK_BINARY_ZIP:BOOL=ON
+ ${CPackComponents_BUILD_OPTIONS}
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CPackComponentsPrefix")
+ endif()
+
+ if(CTEST_package_X11_TEST)
+ set(X11_build_target_arg --build-target package)
+ else()
+ set(X11_build_target_arg)
+ endif()
+
+ add_test(X11 ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/X11"
+ "${CMake_BINARY_DIR}/Tests/X11"
+ ${build_generator_args}
+ --build-project UseX11
+ --build-two-config
+ ${X11_build_target_arg}
+ --test-command UseX11)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/X11")
+
+ if(NOT DEFINED CTEST_RUN_CMakeTestAllGenerators)
+ set(CTEST_RUN_CMakeTestAllGenerators ON)
+ endif()
+
+ if(CTEST_RUN_CMakeTestAllGenerators)
+ add_test(CMakeTestAllGenerators ${CMAKE_CMAKE_COMMAND}
+ -D dir=${CMake_BINARY_DIR}/Tests/CMakeTestAllGenerators
+ -D CMake_SOURCE_DIR=${CMake_SOURCE_DIR}
+ -P ${CMake_SOURCE_DIR}/Tests/CMakeTestAllGenerators/RunCMake.cmake
+ )
+ list(APPEND TEST_BUILD_DIRS
+ "${CMake_BINARY_DIR}/Tests/CMakeTestAllGenerators")
+ # This test runs a lot of processes. Do not make them compete
+ # for resources with other tests.
+ set_property(TEST CMakeTestAllGenerators PROPERTY RUN_SERIAL 1)
+ endif()
+
+ if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ add_test(LoadedCommandOneConfig ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/LoadCommandOneConfig"
+ "${CMake_BINARY_DIR}/Tests/LoadCommandOneConfig"
+ ${build_generator_args}
+ --build-project LoadCommand
+ --test-command LoadedCommand
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/LoadCommandOneConfig")
+ endif()
+
+ add_test(complex ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Complex"
+ "${CMake_BINARY_DIR}/Tests/Complex"
+ --build-two-config
+ --build-config-sample "${CMAKE_CTEST_COMMAND}"
+ ${build_generator_args}
+ --build-project Complex
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/Complex/bin"
+ -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+ --test-command complex
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Complex")
+
+ add_test(complexOneConfig ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/ComplexOneConfig"
+ "${CMake_BINARY_DIR}/Tests/ComplexOneConfig"
+ ${build_generator_args}
+ --build-project Complex
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/ComplexOneConfig/bin"
+ -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+ --test-command complex)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ComplexOneConfig")
+ # because of the registry write these tests depend on each other
+ set_tests_properties ( complex PROPERTIES DEPENDS complexOneConfig)
+
+ add_test(Environment ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Environment"
+ "${CMake_BINARY_DIR}/Tests/Environment"
+ ${build_generator_args}
+ --build-project EnvironmentProj
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/Environment"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Environment")
+
+ add_test(QtAutomocNoQt ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/QtAutomocNoQt"
+ "${CMake_BINARY_DIR}/Tests/QtAutomocNoQt"
+ ${build_generator_args}
+ --build-project QtAutomocNoQt
+ --build-options
+ -DCMAKE_BUILD_TYPE=\${CTEST_CONFIGURATION_TYPE}
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/QtAutomocNoQt")
+
+ if(CMake_TEST_Qt5 AND Qt5Widgets_FOUND)
+ add_subdirectory(Qt5Autogen)
+ endif()
+ if(QT4_WORKS AND QT_QTGUI_FOUND)
+ add_subdirectory(Qt4Autogen)
+
+ add_test(Qt4Targets ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Qt4Targets"
+ "${CMake_BINARY_DIR}/Tests/Qt4Targets"
+ ${build_generator_args}
+ --build-project Qt4Targets
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/Qt4Targets"
+ --force-new-ctest-process
+ --build-options
+ -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Qt4Targets")
+
+ if(Qt5Widgets_FOUND AND NOT Qt5Widgets_VERSION VERSION_LESS 5.1.0)
+ add_test(Qt4And5AutomocForward ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Qt4And5Automoc"
+ "${CMake_BINARY_DIR}/Tests/Qt4And5AutomocForward"
+ ${build_generator_args}
+ --build-project Qt4And5Automoc
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/Qt4And5AutomocForward"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Qt4And5AutomocForward")
+ add_test(Qt4And5AutomocReverse ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Qt4And5Automoc"
+ "${CMake_BINARY_DIR}/Tests/Qt4And5AutomocReverse"
+ ${build_generator_args}
+ --build-project Qt4And5Automoc
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/Qt4And5AutomocReverse"
+ --force-new-ctest-process
+ --build-options -DQT_REVERSE_FIND_ORDER=1
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Qt4And5AutomocReverse")
+ endif()
+ endif()
+
+ # test for Find modules, simple cases
+ foreach(_mod IN ITEMS
+ ALSA
+ Boost
+ BLAS
+ BZip2
+ CURL
+ Cups
+ Doxygen
+ DevIL
+ EnvModules
+ EXPAT
+ Fontconfig
+ Freetype
+ GDAL
+ GIF
+ Git
+ GLEW
+ GnuTLS
+ GSL
+ GTK2
+ Iconv
+ ICU
+ Intl
+ JPEG
+ JsonCpp
+ LAPACK
+ LibArchive
+ LibLZMA
+ LibRHash
+ Libinput
+ LibUV
+ LibXml2
+ LibXslt
+ LTTngUST
+ ODBC
+ OpenACC
+ OpenCL
+ OpenGL
+ OpenMP
+ OpenSSL
+ MPI
+ PNG
+ Patch
+ PostgreSQL
+ Protobuf
+ SDL
+ SQLite3
+ TIFF
+ Vulkan
+ X11
+ XalanC
+ XercesC
+ )
+ if(CMake_TEST_Find${_mod})
+ add_subdirectory(Find${_mod})
+ endif()
+ endforeach()
+
+ if(CMake_TEST_CUDA)
+ add_subdirectory(Cuda)
+ add_subdirectory(CudaOnly)
+ endif()
+
+ if(CMake_TEST_ISPC)
+ add_subdirectory(ISPC)
+ endif()
+
+ if(CMake_TEST_FindGTest)
+ add_subdirectory(FindGTest)
+ add_subdirectory(GoogleTest)
+ endif()
+
+ if(CMake_TEST_FindPython OR CMake_TEST_FindPython_NumPy
+ OR CMake_TEST_FindPython_Conda OR CMake_TEST_FindPython_IronPython OR CMake_TEST_FindPython_PyPy)
+ add_subdirectory(FindPython)
+ endif()
+
+ if(CMake_TEST_UseSWIG)
+ add_subdirectory(UseSWIG)
+ endif()
+
+ if(CMake_TEST_FindRuby)
+ add_subdirectory(FindRuby)
+ endif()
+
+ add_subdirectory(FindThreads)
+
+ # Matlab module
+ # CMake_TEST_FindMatlab: indicates to look for Matlab (from PATH for Linux)
+ # CMake_TEST_FindMatlab_ROOT_DIR: indicates an optional root directory for Matlab, allows to select a version.
+ # CMake_TEST_FindMatlab_MCR: indicates the MCR is installed
+ # CMake_TEST_FindMatlab_MCR_ROOT_DIR: indicates an optional root directory for the MCR, required on Linux
+ if(CMake_TEST_FindMatlab OR CMake_TEST_FindMatlab_ROOT_DIR OR
+ CMake_TEST_FindMatlab_MCR OR CMake_TEST_FindMatlab_MCR_ROOT_DIR)
+ set(FindMatlab_additional_test_options )
+ if(CMake_TEST_FindMatlab_MCR OR CMake_TEST_FindMatlab_MCR_ROOT_DIR)
+ set(FindMatlab_additional_test_options -DIS_MCR=TRUE)
+ endif()
+ if(CMake_TEST_FindMatlab_ROOT_DIR)
+ set(FindMatlab_additional_test_options ${FindMatlab_additional_test_options} "-DMatlab_ROOT_DIR=${CMake_TEST_FindMatlab_ROOT_DIR}")
+ endif()
+ if(CMake_TEST_FindMatlab_MCR_ROOT_DIR)
+ set(FindMatlab_additional_test_options ${FindMatlab_additional_test_options} "-DMCR_ROOT:FILEPATH=${CMake_TEST_FindMatlab_MCR_ROOT_DIR}")
+ endif()
+ set(FindMatlab.basic_checks_BUILD_OPTIONS ${FindMatlab_additional_test_options})
+ ADD_TEST_MACRO(FindMatlab.basic_checks ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>)
+ set(FindMatlab.versions_checks_BUILD_OPTIONS ${FindMatlab_additional_test_options})
+ ADD_TEST_MACRO(FindMatlab.versions_checks ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>)
+ set(FindMatlab.components_checks_BUILD_OPTIONS ${FindMatlab_additional_test_options})
+ ADD_TEST_MACRO(FindMatlab.components_checks ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>)
+ set(FindMatlab.failure_reports_BUILD_OPTIONS ${FindMatlab_additional_test_options})
+ ADD_TEST_MACRO(FindMatlab.failure_reports ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>)
+ set(FindMatlab.r2018a_check_BUILD_OPTIONS ${FindMatlab_additional_test_options})
+ ADD_TEST_MACRO(FindMatlab.r2018a_check ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>)
+ endif()
+
+ add_test(ExternalProject ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/ExternalProject"
+ "${CMake_BINARY_DIR}/Tests/ExternalProject"
+ ${build_generator_args}
+ --build-project ExternalProjectTest
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/ExternalProject"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProject")
+ set_tests_properties(ExternalProject PROPERTIES
+ RUN_SERIAL 1
+ TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
+
+ add_test(NAME ExternalProjectSubdir
+ COMMAND ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/ExternalProjectSubdir"
+ "${CMake_BINARY_DIR}/Tests/ExternalProjectSubdir"
+ ${build_generator_args}
+ --build-project ExternalProjectSubdir
+ --force-new-ctest-process
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectSubdir")
+
+ add_test(NAME ExternalProjectSourceSubdir
+ COMMAND ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/ExternalProjectSourceSubdir"
+ "${CMake_BINARY_DIR}/Tests/ExternalProjectSourceSubdir"
+ ${build_generator_args}
+ --build-project ExternalProjectSourceSubdir
+ --force-new-ctest-process
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectSourceSubdir")
+
+ add_test(NAME ExternalProjectSourceSubdirNotCMake
+ COMMAND ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/ExternalProjectSourceSubdirNotCMake"
+ "${CMake_BINARY_DIR}/Tests/ExternalProjectSourceSubdirNotCMake"
+ ${build_generator_args}
+ --build-project ExternalProjectSourceSubdirNotCMake
+ --force-new-ctest-process
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectSourceSubdirNotCMake")
+
+ add_test(ExternalProjectLocal ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/ExternalProjectLocal"
+ "${CMake_BINARY_DIR}/Tests/ExternalProjectLocal"
+ ${build_generator_args}
+ --build-project ExternalProjectLocalTest
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/ExternalProjectLocal"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectLocal")
+ set_tests_properties(ExternalProjectLocal PROPERTIES
+ RUN_SERIAL 1
+ TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
+
+ add_test(ExternalProjectUpdateSetup ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/ExternalProjectUpdate"
+ "${CMake_BINARY_DIR}/Tests/ExternalProjectUpdate"
+ ${build_generator_args}
+ --build-project ExternalProjectUpdateTest
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/ExternalProjectUpdate"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectUpdate")
+ set_tests_properties(ExternalProjectUpdateSetup PROPERTIES
+ RUN_SERIAL 1
+ TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
+
+ add_test(NAME ExternalProjectUpdate
+ COMMAND ${CMAKE_CMAKE_COMMAND}
+ -DExternalProjectUpdate_SOURCE_DIR:PATH=${CMake_SOURCE_DIR}/Tests/ExternalProjectUpdate
+ -DExternalProjectUpdate_BINARY_DIR:PATH=${CMake_BINARY_DIR}/Tests/ExternalProjectUpdate
+ -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
+ -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
+ -DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
+ -DCMAKE_CTEST_COMMAND=${CMAKE_CTEST_COMMAND}
+ -P ${CMake_SOURCE_DIR}/Tests/ExternalProjectUpdate/ExternalProjectUpdateTest.cmake
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectUpdate")
+ set_tests_properties(ExternalProjectUpdate PROPERTIES
+ RUN_SERIAL 1
+ TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT}
+ WORKING_DIRECTORY ${CMake_SOURCE_DIR}/Tests/ExternalProjectUpdate
+ DEPENDS ExternalProjectUpdateSetup )
+
+ # do each of the tutorial steps
+ function(add_tutorial_test step_name use_mymath tutorial_arg pass_regex)
+ set(tutorial_test_name Tutorial${step_name})
+ set(tutorial_build_dir "${CMake_BINARY_DIR}/Tests/Tutorial/${step_name}")
+ if (use_mymath)
+ set(tutorial_build_options "")
+ else()
+ set(tutorial_test_name ${tutorial_test_name}_MYMATH)
+ set(tutorial_build_dir "${tutorial_build_dir}_MYMATH")
+ set(tutorial_build_options -DUSE_MYMATH:BOOL=OFF)
+ endif()
+ add_test(${tutorial_test_name} ${CMAKE_CTEST_COMMAND}
+ -C "Release"
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Help/guide/tutorial/${step_name}"
+ ${tutorial_build_dir}_Build
+ ${build_generator_args}
+ --build-project Tutorial
+ --build-options ${tutorial_build_options}
+ --test-command Tutorial ${tutorial_arg})
+ set_tests_properties(${tutorial_test_name} PROPERTIES
+ PASS_REGULAR_EXPRESSION ${pass_regex})
+
+ list(APPEND TEST_BUILD_DIRS "${tutorial_build_dir}_Build")
+ endfunction()
+
+ if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ foreach(STP RANGE 2 12)
+ if (STP EQUAL 6)
+ set(pass_regex ".*using log and exp")
+ else()
+ set(pass_regex "The square root of 25 is 5")
+ endif()
+ add_tutorial_test(Step${STP} TRUE 25 ${pass_regex})
+ endforeach()
+ set(pass_regex "The square root of 25 is 5")
+ add_tutorial_test(Complete TRUE 25 ${pass_regex})
+ foreach(STP RANGE 3 12)
+ add_tutorial_test(Step${STP} FALSE 25 ${pass_regex})
+ endforeach()
+ add_tutorial_test(Complete FALSE 25 ${pass_regex})
+ endif()
+
+ function(add_importexport_test export_name import_name)
+ set(install_dir
+ "${CMake_BINARY_DIR}/Tests/ImportExport/Install${export_name}")
+ set(export_build_dir "${CMake_BINARY_DIR}/Tests/ImportExport/${export_name}Build")
+ set(export_test_name "Guide.ImportExport.${export_name}")
+ add_test(${export_test_name} ${CMAKE_CTEST_COMMAND}
+ -C "Release"
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Help/guide/importing-exporting/${export_name}"
+ "${export_build_dir}"
+ ${build_generator_args}
+ --build-project ${export_name}
+ --build-target install
+ --build-options
+ "-DCMAKE_INSTALL_PREFIX:PATH=${install_dir}")
+ list(APPEND TEST_BUILD_DIRS "${export_build_dir}")
+
+ set(import_build_dir "${CMake_BINARY_DIR}/Tests/ImportExport/${import_name}Build")
+ set(import_test_name "Guide.ImportExport.${import_name}")
+ add_test(${import_test_name} ${CMAKE_CTEST_COMMAND}
+ -C "Release"
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Help/guide/importing-exporting/${import_name}"
+ "${import_build_dir}"
+ ${build_generator_args}
+ --build-project ${import_name}
+ --build-options
+ "-DCMAKE_PREFIX_PATH:PATH=${install_dir}")
+ set_tests_properties(${import_test_name} PROPERTIES DEPENDS ${export_test_name})
+ list(APPEND TEST_BUILD_DIRS "${import_build_dir}")
+ endfunction()
+
+ if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ add_importexport_test("MyExe" "Importing")
+ add_importexport_test("MathFunctions" "Downstream")
+ add_importexport_test("MathFunctionsComponents" "DownstreamComponents")
+ endif()
+
+ add_test(testing ${CMAKE_CTEST_COMMAND} -C \${CTEST_CONFIGURATION_TYPE}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Testing"
+ "${CMake_BINARY_DIR}/Tests/Testing"
+ ${build_generator_args}
+ --build-project Testing
+ --test-command ${CMAKE_CTEST_COMMAND} -C \${CTEST_CONFIGURATION_TYPE}
+ )
+ set_tests_properties(testing PROPERTIES PASS_REGULAR_EXPRESSION "Passed")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Testing")
+
+ add_test(wrapping ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Wrapping"
+ "${CMake_BINARY_DIR}/Tests/Wrapping"
+ ${build_generator_args}
+ --build-project Wrapping
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/Wrapping/bin"
+ --test-command wrapping
+ )
+ add_test(qtwrapping ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Wrapping"
+ "${CMake_BINARY_DIR}/Tests/Wrapping"
+ ${build_generator_args}
+ --build-project Wrapping
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/Wrapping/bin"
+ --test-command qtwrapping
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Wrapping")
+
+ add_test(testdriver1 ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/TestDriver"
+ "${CMake_BINARY_DIR}/Tests/TestDriver"
+ ${build_generator_args}
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/Wrapping/bin"
+ --build-project TestDriverTest
+ --test-command TestDriverTest test1
+ )
+
+ add_test(testdriver2 ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/TestDriver"
+ "${CMake_BINARY_DIR}/Tests/TestDriver"
+ ${build_generator_args}
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/Wrapping/bin"
+ --build-project TestDriverTest
+ --test-command TestDriverTest test2
+ )
+
+ add_test(testdriver3 ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/TestDriver"
+ "${CMake_BINARY_DIR}/Tests/TestDriver"
+ ${build_generator_args}
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/Wrapping/bin"
+ --build-project TestDriverTest
+ --test-command TestDriverTest subdir/test3
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/TestDriver")
+
+ add_test(Dependency ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Dependency"
+ "${CMake_BINARY_DIR}/Tests/Dependency"
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/Dependency/Exec"
+ ${build_generator_args}
+ --build-project Dependency
+ --test-command exec
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Dependency")
+
+ if(CMAKE_SYSTEM_NAME MATCHES syllable)
+
+# RPATH isn't supported under Syllable, so the tests don't
+# find their libraries. In order to fix that LIBRARY_OUTPUT_DIR
+# in the tests would have to be adjusted to ${EXECUTABLE_OUTPUT_DIR}/lib .
+# For now we just require on Syllable that the user adjusts the DLL_PATH
+# environment variable, so except the two tests below all other tests will succeed.
+
+ set(_DLL_PATH "$ENV{DLL_PATH}")
+ if(NOT "${_DLL_PATH}" MATCHES "^(.*:)?\\@bindir\\@/\\.(:.*)?$")
+ message(FATAL_ERROR "In order to successfully run the CMake test suite on Syllable you need to add \"\\@bindir\\@/.\" to the DLL_PATH environment variable")
+ endif()
+ if(NOT "${_DLL_PATH}" MATCHES "^(.*:)?\\@bindir\\@/\\.\\./lib(:.*)?$")
+ message(FATAL_ERROR "In order to successfully run the CMake test suite on Syllable you need to add \"\\@bindir\\@/../lib\" to the DLL_PATH environment variable")
+ endif()
+
+ else()
+
+ add_test(JumpWithLibOut ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Jump"
+ "${CMake_BINARY_DIR}/Tests/Jump/WithLibOut"
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/Jump/WithLibOut/Executable"
+ --build-project Jump
+ ${build_generator_args}
+ --build-options
+ -DLIBRARY_OUTPUT_PATH:PATH=${CMake_BINARY_DIR}/Tests/Jump/WithLibOut/Lib
+ --test-command jumpExecutable
+ )
+
+ add_test(JumpNoLibOut ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Jump"
+ "${CMake_BINARY_DIR}/Tests/Jump/NoLibOut"
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/Jump/NoLibOut/Executable"
+ --build-run-dir "${CMake_BINARY_DIR}/Tests/Jump/NoLibOut/Executable"
+ --build-project Jump
+ ${build_generator_args}
+ --test-command jumpExecutable
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Jump")
+
+ add_test(Plugin ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Plugin"
+ "${CMake_BINARY_DIR}/Tests/Plugin"
+ ${build_generator_args}
+ --build-project Plugin
+ --build-two-config
+ --test-command bin/example)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Plugin")
+
+ if(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG)
+ ADD_TEST_MACRO(RuntimePath RuntimePath)
+ endif()
+ endif()
+
+ if(APPLE AND "${DARWIN_MAJOR_VERSION}" GREATER 9)
+ add_test(MacRuntimePath ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/MacRuntimePath"
+ "${CMake_BINARY_DIR}/Tests/MacRuntimePath"
+ ${build_generator_args}
+ --build-project MacRuntimePath
+ --build-options
+ -DCMake_TEST_NESTED_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM}
+ )
+ endif()
+
+ if(CMake_TEST_XCODE_VERSION AND NOT CMake_TEST_XCODE_VERSION VERSION_LESS 5)
+ if(NOT CMake_TEST_XCTest_DEPLOYMENT_TARGET)
+ execute_process(
+ COMMAND sw_vers -productVersion
+ OUTPUT_VARIABLE OSX_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if(OSX_VERSION MATCHES "^([0-9]+\\.[0-9]+)")
+ set(CMake_TEST_XCTest_DEPLOYMENT_TARGET "${CMAKE_MATCH_1}")
+ endif()
+ endif()
+ if(CMake_TEST_XCTest_DEPLOYMENT_TARGET)
+ set(XCTest_CTEST_OPTIONS --build-config $<CONFIGURATION>)
+ set(XCTest_BUILD_OPTIONS -DCMAKE_OSX_DEPLOYMENT_TARGET=${CMake_TEST_XCTest_DEPLOYMENT_TARGET} -DCMAKE_OSX_SYSROOT=macosx)
+ ADD_TEST_MACRO(XCTest ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> -V)
+ endif()
+ endif()
+
+ add_test(linkorder1 ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/LinkLineOrder"
+ "${CMake_BINARY_DIR}/Tests/LinkLineOrder"
+ ${build_generator_args}
+ --build-project LinkLineOrder
+ --test-command Exec1
+ )
+
+ add_test(linkorder2 ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/LinkLineOrder"
+ "${CMake_BINARY_DIR}/Tests/LinkLineOrder"
+ ${build_generator_args}
+ --build-project LinkLineOrder
+ --test-command Exec2
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/LinkLineOrder")
+ set_tests_properties ( qtwrapping PROPERTIES DEPENDS wrapping)
+ set_tests_properties ( testdriver1 PROPERTIES DEPENDS qtwrapping)
+ set_tests_properties ( testdriver2 PROPERTIES DEPENDS testdriver1)
+ set_tests_properties ( testdriver3 PROPERTIES DEPENDS testdriver2)
+ set_tests_properties ( linkorder2 PROPERTIES DEPENDS linkorder1)
+
+ # Test static linking on toolchains known to support it.
+ if(CMAKE_C_COMPILER_ID STREQUAL "GNU"
+ AND NOT APPLE AND NOT WIN32 AND NOT CYGWIN
+ AND EXISTS "/usr/lib/libm.a")
+ add_test(LinkStatic ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/LinkStatic"
+ "${CMake_BINARY_DIR}/Tests/LinkStatic"
+ ${build_generator_args}
+ --build-project LinkStatic
+ --build-options
+ -DMATH_LIBRARY:FILEPATH=/usr/lib/libm.a
+ --test-command LinkStatic
+ )
+ endif()
+
+ if(MAKE_SUPPORTS_SPACES AND NOT CMAKE_GENERATOR STREQUAL "Xcode")
+ add_test(SubDirSpaces ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/SubDirSpaces"
+ "${CMake_BINARY_DIR}/Tests/SubDirSpaces"
+ --build-exe-dir
+ "${CMake_BINARY_DIR}/Tests/SubDirSpaces/Executable Sources"
+ ${build_generator_args}
+ --build-project SUBDIR
+ --test-command test
+ "${CMake_BINARY_DIR}/Tests/SubDirSpaces/ShouldBeHere"
+ "${CMake_BINARY_DIR}/Tests/SubDirSpaces/testfromsubdir.obj"
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/SubDirSpaces")
+ endif ()
+
+ if (WIN32)
+ add_test(SubDir ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/SubDir"
+ "${CMake_BINARY_DIR}/Tests/SubDir"
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/SubDir/Executable"
+ ${build_generator_args}
+ --build-project SUBDIR
+ --test-command test
+ "${CMake_BINARY_DIR}/Tests/SubDir/ShouldBeHere"
+ "${CMake_BINARY_DIR}/Tests/SubDir/testfromsubdir.obj"
+ )
+ else ()
+ add_test(SubDir ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/SubDir"
+ "${CMake_BINARY_DIR}/Tests/SubDir"
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/SubDir/Executable"
+ ${build_generator_args}
+ --build-project SUBDIR
+ --test-command test
+ "${CMake_BINARY_DIR}/Tests/SubDir/ShouldBeHere"
+ "${CMake_BINARY_DIR}/Tests/SubDir/testfromsubdir.o"
+ )
+ endif ()
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/SubDir")
+
+ if(MSVC OR (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_SIMULATE_ID STREQUAL "MSVC"))
+ ADD_TEST_MACRO(PDBDirectoryAndName myexe)
+ if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang" OR NOT "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ ADD_TEST_MACRO(ForceInclude foo)
+ endif()
+ if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_ID STREQUAL "IntelLLVM")
+ ADD_TEST_MACRO(PrecompiledHeader foo)
+ endif()
+ set(MSVCRuntimeLibrary_BUILD_OPTIONS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
+ ADD_TEST_MACRO(MSVCRuntimeLibrary)
+ set_property(TEST MSVCRuntimeLibrary APPEND
+ PROPERTY LABELS "CUDA")
+ if(CMAKE_Fortran_COMPILER)
+ ADD_TEST_MACRO(MSVCRuntimeLibrary.Fortran)
+ endif()
+ endif()
+ if(MSVC OR
+ "${CMAKE_GENERATOR}" MATCHES "(MSYS|MinGW) Makefiles")
+ ADD_TEST_MACRO(ModuleDefinition example_exe)
+ endif()
+
+ ADD_TEST_MACRO(CheckCompilerRelatedVariables CheckCompilerRelatedVariables)
+
+ if("${CMAKE_GENERATOR}" MATCHES "Makefile" OR
+ "${CMAKE_GENERATOR}" MATCHES "^Ninja$")
+ add_test(MakeClean ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/MakeClean"
+ "${CMake_BINARY_DIR}/Tests/MakeClean"
+ ${build_generator_args}
+ --build-project MakeClean
+ --build-exe-dir "${CMake_BINARY_DIR}/MakeClean"
+ --test-command check_clean
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/MakeClean")
+ endif()
+
+ if(NOT DEFINED CTEST_RUN_MFC)
+ set(CTEST_RUN_MFC OFF)
+
+ if(MSVC)
+ set(CTEST_RUN_MFC ON)
+
+ # Look for evidence that this is a VCExpress build. If so, avoid
+ # the MFC test by default.
+ string(TOLOWER "${CMAKE_MAKE_PROGRAM}" mkprog)
+ if(mkprog MATCHES "vcexpress")
+ message(STATUS
+ "CMAKE_MAKE_PROGRAM indicates vcexpress, avoiding MFC test")
+ set(CTEST_RUN_MFC OFF)
+ endif()
+
+ # Since MSBuild might also be the "makeprogram" for a VCExpress
+ # build tree, use one more heuristic, too. The string representing
+ # the .vcproj file type contains "VCExpress" on machines where an
+ # express edition of VS was installed last:
+ if(CTEST_RUN_MFC)
+ execute_process(COMMAND cmd /c assoc .vcproj
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ OUTPUT_VARIABLE ov)
+ if(ov MATCHES "VCExpress")
+ message(STATUS
+ ".vcproj file association indicates VCExpress, avoiding MFC test")
+ set(CTEST_RUN_MFC OFF)
+ elseif( NOT ov )
+ message(STATUS
+ ".vcproj has no file association, avoiding MFC test")
+ set(CTEST_RUN_MFC OFF)
+ endif()
+ endif()
+
+ if(CTEST_RUN_MFC)
+ # For the Watcom WMake generator, avoid the MFC test by default.
+ if("${CMAKE_GENERATOR}" MATCHES "WMake")
+ message(STATUS
+ "using the Watcom WMake generator, avoiding MFC test")
+ set(CTEST_RUN_MFC OFF)
+ elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "IntelLLVM")
+ # clang-cl cannot deal with implicit dependencies in UTF16 files
+ # (see #18311). IntelLLVM inherits this behavior from Clang.
+ # TODO: maybe clang should also skip the MFC test
+ message(STATUS
+ "using generator other than Visual Studio with clang-cl, avoiding MFC test")
+ set(CTEST_RUN_MFC OFF)
+ endif()
+ endif()
+
+ # Last resort, after quick checks are done. Do a try_compile, and avoid
+ # the MFC test if the simplest possible MFC app cannot be compiled.
+ if(CTEST_RUN_MFC AND NOT DEFINED HAVE_MFC)
+ configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/MFC/try_compile/CMakeLists.txt
+ ${CMAKE_CURRENT_BINARY_DIR}/MFC/try_compile/CMakeLists.txt
+ COPYONLY
+ )
+ configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/MFC/mfc1/stdafx.cpp
+ ${CMAKE_CURRENT_BINARY_DIR}/MFC/try_compile/stdafx.cpp
+ COPYONLY
+ )
+ configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/MFC/mfc1/stdafx.h
+ ${CMAKE_CURRENT_BINARY_DIR}/MFC/try_compile/stdafx.h
+ COPYONLY
+ )
+
+ message(STATUS "Looking for MFC")
+
+ try_compile(HAVE_MFC
+ ${CMAKE_CURRENT_BINARY_DIR}/MFC/try_compile/build
+ ${CMAKE_CURRENT_BINARY_DIR}/MFC/try_compile
+ try_compile_mfc
+ OUTPUT_VARIABLE HAVE_MFC_OUTPUT)
+
+ if(HAVE_MFC)
+ message(STATUS "Looking for MFC - found")
+ set(HAVE_MFC 1 CACHE INTERNAL "Have MFC")
+ file(APPEND
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if MFC exists passed with the following output:\n"
+ "${HAVE_MFC_OUTPUT}\n\n")
+ else()
+ message(STATUS "Looking for MFC - not found")
+ set(HAVE_MFC "" CACHE INTERNAL "Have MFC")
+ file(APPEND
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if MFC exists failed with the following output:\n"
+ "${HAVE_MFC_OUTPUT}\n\n")
+ endif()
+ endif()
+
+ if(CTEST_RUN_MFC AND NOT HAVE_MFC)
+ message(STATUS
+ "cannot compile simplest ever MFC app, avoiding MFC test")
+ set(CTEST_RUN_MFC OFF)
+ endif()
+ endif()
+ endif()
+
+ if(CTEST_RUN_MFC)
+ add_test(MFC ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/MFC"
+ "${CMake_BINARY_DIR}/Tests/MFC"
+ --build-two-config
+ ${build_generator_args}
+ --build-project mfc_driver
+ --test-command ${CMAKE_CTEST_COMMAND}
+ -C \${CTEST_CONFIGURATION_TYPE} -VV)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/MFC")
+ endif()
+
+ if(MSVC AND NOT MSVC_VERSION LESS 1310
+ AND (NOT CMAKE_GENERATOR MATCHES "Visual Studio 9 "
+ OR CMAKE_SIZEOF_VOID_P EQUAL 4)
+ )
+ ADD_TEST_MACRO(VSMASM VSMASM)
+ endif()
+
+ if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
+ if(NOT MSVC60)
+ ADD_TEST_MACRO(SBCS SBCS)
+ endif()
+
+ if(NOT "${CMAKE_GENERATOR}" MATCHES "Visual Studio 9 "
+ AND NOT CMAKE_GENERATOR_TOOLSET)
+ ADD_TEST_MACRO(VSWindowsFormsResx VSWindowsFormsResx)
+ endif()
+
+ add_test(VSExternalInclude ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/VSExternalInclude"
+ "${CMake_BINARY_DIR}/Tests/VSExternalInclude"
+ --build-two-config
+ ${build_generator_args}
+ --build-project VSExternalInclude
+ --test-command VSExternalInclude)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSExternalInclude")
+
+ add_test(VSMidl ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/VSMidl"
+ "${CMake_BINARY_DIR}/Tests/VSMidl"
+ --build-two-config
+ ${build_generator_args}
+ --build-project VSMidl
+ --test-command VSMidl)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSMidl")
+
+ if(CMake_TEST_DEVENV)
+ # The test (and tested property) works with .sln files, so it's skipped when:
+ # * cmake --build is set up to use MSBuild, since the MSBuild invocation does not use the .sln file
+ set(_last_test "")
+ foreach(config ${CMAKE_CONFIGURATION_TYPES})
+ add_test(NAME VSExcludeFromDefaultBuild-${config} COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/VSExcludeFromDefaultBuild"
+ "${CMake_BINARY_DIR}/Tests/VSExcludeFromDefaultBuild"
+ --build-config ${config}
+ --build-two-config
+ --build-generator ${CMAKE_GENERATOR}
+ --build-makeprogram ${CMake_TEST_DEVENV}
+ --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+ --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+ --build-project VSExcludeFromDefaultBuild
+ --build-target install
+ --test-command ${CMAKE_COMMAND}
+ -D "activeConfig=${config}"
+ -D "allConfigs=${CMAKE_CONFIGURATION_TYPES}"
+ -D "dir=${CMake_BINARY_DIR}/Tests/VSExcludeFromDefaultBuild"
+ -P "${CMake_SOURCE_DIR}/Tests/VSExcludeFromDefaultBuild/ResultTest.cmake")
+ if(_last_test)
+ set_property(TEST VSExcludeFromDefaultBuild-${config} PROPERTY DEPENDS ${_last_test})
+ endif()
+ set(_last_test "VSExcludeFromDefaultBuild-${config}")
+ endforeach()
+ unset(_last_test)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSExcludeFromDefaultBuild")
+ endif()
+
+ if(CMAKE_GENERATOR MATCHES "Visual Studio ([0-5]|[6-9][0-9])")
+ # This is Visual Studio 10 or above, so the default build tool is MSBuild.
+ add_test(NAME VSProjectInSubdir COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/VSProjectInSubdir"
+ "${CMake_BINARY_DIR}/Tests/VSProjectInSubdir"
+ --build-two-config
+ --build-generator ${CMAKE_GENERATOR}
+ --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+ --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+ --build-project VSProjectInSubdir
+ --build-target test)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSProjectInSubdir")
+ endif()
+ endif()
+
+ get_filename_component(ntver "[HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion;CurrentVersion]" NAME)
+ if(WIN32 AND ntver VERSION_GREATER 6.1) # Windows >= 8.0
+ macro(add_test_VSWinStorePhone name generator systemName systemVersion architecture)
+ add_test(NAME VSWinStorePhone.${name} COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/VSWinStorePhone"
+ "${CMake_BINARY_DIR}/Tests/VSWinStorePhone/${name}"
+ --build-generator "${generator}"
+ --build-generator-platform "${architecture}"
+ --build-project VSWinStorePhone
+ --build-config $<CONFIGURATION>
+ --build-options -DCMAKE_SYSTEM_NAME=${systemName}
+ -DCMAKE_SYSTEM_VERSION=${systemVersion}
+ --test-command
+ ${CMAKE_CMAKE_COMMAND} -DAPP_PACKAGE_DIR="${CMake_BINARY_DIR}/Tests/VSWinStorePhone/${name}"
+ -P "${CMake_SOURCE_DIR}/Tests/VSWinStorePhone/VerifyAppPackage.cmake"
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSWinStorePhone/${name}")
+ endmacro()
+
+ if(vs11 AND ws80)
+ add_test_VSWinStorePhone(vs11-store80-X86 "Visual Studio 11 2012" WindowsStore 8.0 Win32)
+ add_test_VSWinStorePhone(vs11-store80-ARM "Visual Studio 11 2012" WindowsStore 8.0 ARM)
+ add_test_VSWinStorePhone(vs11-store80-X64 "Visual Studio 11 2012" WindowsStore 8.0 x64)
+ endif()
+ if(vs12 AND ws81)
+ add_test_VSWinStorePhone(vs12-store81-X86 "Visual Studio 12 2013" WindowsStore 8.1 Win32)
+ add_test_VSWinStorePhone(vs12-store81-ARM "Visual Studio 12 2013" WindowsStore 8.1 ARM)
+ add_test_VSWinStorePhone(vs12-store81-X64 "Visual Studio 12 2013" WindowsStore 8.1 x64)
+
+ add_test(NAME VSXaml COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/VSXaml"
+ "${CMake_BINARY_DIR}/Tests/VSXaml"
+ --build-generator "Visual Studio 12 2013"
+ --build-project VSXaml
+ --build-config $<CONFIGURATION>
+ --build-options -DCMAKE_SYSTEM_NAME=WindowsStore
+ -DCMAKE_SYSTEM_VERSION=8.1
+ )
+ endif()
+ if(CMake_TEST_VSWinStorePhone_VS_2017 AND ws10_0)
+ add_test_VSWinStorePhone(vs15-store10_0-X86 "Visual Studio 15 2017" WindowsStore 10.0 Win32)
+ add_test_VSWinStorePhone(vs15-store10_0-ARM "Visual Studio 15 2017" WindowsStore 10.0 ARM)
+ add_test_VSWinStorePhone(vs15-store10_0-X64 "Visual Studio 15 2017" WindowsStore 10.0 x64)
+ add_test_VSWinStorePhone(vs15-store10_0-ARM64 "Visual Studio 15 2017" WindowsStore 10.0 ARM64)
+ endif()
+ if(vs14 AND ws10_0)
+ add_test_VSWinStorePhone(vs14-store10_0-X86 "Visual Studio 14 2015" WindowsStore 10.0 Win32)
+ add_test_VSWinStorePhone(vs14-store10_0-ARM "Visual Studio 14 2015" WindowsStore 10.0 ARM)
+ add_test_VSWinStorePhone(vs14-store10_0-X64 "Visual Studio 14 2015" WindowsStore 10.0 x64)
+ endif()
+ if(vs11 AND wp80)
+ add_test_VSWinStorePhone(vs11-phone80-X86 "Visual Studio 11 2012" WindowsPhone 8.0 Win32)
+ add_test_VSWinStorePhone(vs11-phone80-ARM "Visual Studio 11 2012" WindowsPhone 8.0 ARM)
+ endif()
+ if(vs12 AND wp81)
+ add_test_VSWinStorePhone(vs12-phone81-X86 "Visual Studio 12 2013" WindowsPhone 8.1 Win32)
+ add_test_VSWinStorePhone(vs12-phone81-ARM "Visual Studio 12 2013" WindowsPhone 8.1 ARM)
+ endif()
+ endif()
+
+ if(WIN32 AND wince)
+ macro(add_test_VSWinCE name generator systemName systemVersion generatorPlatform)
+ # TODO: Fix the tutorial to make it work in cross compile
+ # currently the MakeTable is build for target and can not be used on the host
+ # This happens in part 5 so we build only through part 4 of the tutorial.
+ foreach(STP RANGE 2 4)
+ add_test(NAME "TutorialStep${STP}.${name}" COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Help/guide/tutorial/Step${STP}"
+ "${CMake_BINARY_DIR}/Tests/Tutorial/Step${STP}_${name}"
+ --build-generator "${generator}"
+ --build-project Tutorial
+ --build-config $<CONFIGURATION>
+ --build-options -DCMAKE_SYSTEM_NAME=${systemName}
+ -DCMAKE_SYSTEM_VERSION=${systemVersion}
+ -DCMAKE_GENERATOR_PLATFORM=${generatorPlatform})
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Tutorial/Step${STP}_${name}")
+ endforeach()
+ endmacro()
+
+ if(vs11)
+ add_test_VSWinCE(vs11-ce80-ARM "Visual Studio 11 2012" WindowsCE 8.0 ${wince_sdk})
+ endif()
+
+ if(vs12)
+ add_test_VSWinCE(vs12-ce80-ARM "Visual Studio 12 2013" WindowsCE 8.0 ${wince_sdk})
+ endif()
+ endif()
+
+ if(CMAKE_GENERATOR MATCHES "Visual Studio ([^9]|9[0-9])" AND nasm)
+ ADD_TEST_MACRO(VSNASM VSNASM)
+ endif()
+
+ if (CMake_TEST_GreenHillsMULTI)
+ macro(add_test_GhsMulti test_name test_dir bin_sub_dir build_opts)
+ separate_arguments(_ghs_build_opts UNIX_COMMAND ${build_opts})
+ separate_arguments(_ghs_toolset_extra UNIX_COMMAND ${ghs_toolset_extra})
+ if(${ARGC} GREATER 4)
+ set(_ghs_test_command --test-command ${ARGN})
+ endif()
+ if(ghs_config_name STREQUAL "__default__")
+ set(_ghs_test_name "${test_name}")
+ else()
+ set(_ghs_test_name "${ghs_config_name}.${test_name}")
+ endif()
+ add_test(NAME GhsMulti.${_ghs_test_name}
+ COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/GhsMulti/${test_dir}"
+ "${CMake_BINARY_DIR}/Tests/GhsMulti/${ghs_config_name}/${test_dir}/${bin_sub_dir}"
+ --build-generator "Green Hills MULTI"
+ --build-project test
+ --build-config $<CONFIGURATION>
+ --force-new-ctest-process
+ --build-options ${ghs_target_arch} ${ghs_toolset_name} ${ghs_toolset_root} ${ghs_target_platform}
+ ${ghs_os_root} ${ghs_os_dir} ${ghs_bsp_name} ${_ghs_build_opts} ${_ghs_toolset_extra}
+ ${_ghs_test_command}
+ )
+ unset(_ghs_build_opts)
+ unset(_ghs_toolset_extra)
+ unset(_ghs_test_command)
+ unset(_ghs_test_name)
+ endmacro()
+ macro(add_test_GhsMulti_rename_install test_name)
+ add_test_GhsMulti( ${test_name} GhsMultiRenameInstall ${test_name}
+ "-DCMAKE_INSTALL_PREFIX=. -DRUN_TEST=${test_name}" ${CMAKE_CMAKE_COMMAND} --build . --target install)
+ endmacro()
+ #unset ghs config variables
+ unset(ghs_config_name)
+ unset(ghs_target_arch)
+ unset(ghs_toolset_root)
+ unset(ghs_toolset_name)
+ unset(ghs_os_root)
+ unset(ghs_os_dir)
+ unset(ghs_target_platform)
+ unset(ghs_bsp_name)
+ unset(ghs_toolset_extra)
+ if(NOT CMake_TEST_GreenHillsMULTI_config)
+ #if list of config settings not defined then just run once as default
+ set(CMake_TEST_GreenHillsMULTI_config "__default__")
+ endif()
+ foreach(ghs_file IN LISTS CMake_TEST_GreenHillsMULTI_config)
+ # source GHS tools config file
+ if(NOT ghs_file STREQUAL "__default__")
+ if(IS_ABSOLUTE ${ghs_file})
+ include(${ghs_file})
+ else()
+ include(${CMAKE_BINARY_DIR}/${ghs_file})
+ endif()
+ endif()
+ if(NOT ghs_config_name)
+ set(ghs_config_name "__default__")
+ endif()
+ # test integrity build
+ if (NOT ghs_skip_integrity AND (NOT ghs_target_platform OR ghs_target_platform MATCHES "integrity"))
+ add_test_GhsMulti(integrityDDInt GhsMultiIntegrity/GhsMultiIntegrityDDInt "" "")
+ add_test_GhsMulti(integrityMonolith GhsMultiIntegrity/GhsMultiIntegrityMonolith "" "")
+ add_test_GhsMulti(integrityDD GhsMultiIntegrity/GhsMultiIntegrityDD "" "")
+ endif()
+ add_test_GhsMulti(duplicate_source_filenames GhsMultiDuplicateSourceFilenames "" "")
+ add_test_GhsMulti_rename_install(SINGLE_EXEC)
+ add_test_GhsMulti_rename_install(SINGLE_EXEC_RENAMED)
+ add_test_GhsMulti_rename_install(EXEC_AND_LIB)
+ add_test_GhsMulti(multiple_source_groups GhsMultiSrcGroups Default "")
+ add_test_GhsMulti(multiple_source_groups_folders GhsMultiSrcGroups PropFolders "-DTEST_PROP=ON")
+ add_test_GhsMulti(multiple_source_groups_all_folders GhsMultiSrcGroups AllFolders "-DCMAKE_GHS_NO_SOURCE_GROUP_FILE=ON")
+ add_test_GhsMulti(unsupported_targets GhsMultiUnsupportedTargets "" "")
+ add_test_GhsMulti(object_library GhsMultiObjectLibrary "" "")
+ add_test_GhsMulti(exclude GhsMultiExclude "" ""
+ ${CMAKE_CMAKE_COMMAND} -P ${CMake_SOURCE_DIR}/Tests/GhsMulti/GhsMultiExclude/verify.cmake)
+ add_test_GhsMulti(interface GhsMultiInterface "" "")
+ add_test_GhsMulti(transitive_link_test GhsMultiLinkTest TransitiveLink "-DRUN_TEST=NO_FLAGS")
+ add_test_GhsMulti(flags_link_test GhsMultiLinkTest FlagsCheck "-DRUN_TEST=CHECK_FLAGS")
+ add_test_GhsMulti(sub_link_test GhsMultiLinkTestSub "" "")
+ add_test_GhsMulti(multiple_projects GhsMultiMultipleProjects "" ""
+ ${CMAKE_CMAKE_COMMAND} -P ${CMake_SOURCE_DIR}/Tests/GhsMulti/GhsMultiMultipleProjects/verify.cmake)
+ add_test_GhsMulti(compiler_options_none GhsMultiCompilerOptions None "-DRUN_TEST=RELEASE_FLAGS -DRUN_TEST_BUILD_TYPE=\"\"")
+ add_test_GhsMulti(compiler_options_kernel GhsMultiCompilerOptions Kernel "-DRUN_TEST=KERNEL_FLAGS -DRUN_TEST_BUILD_TYPE=DEBUG")
+ add_test_GhsMulti(try_compile_copy GhsMultiCopyFile "" "")
+ add_test_GhsMulti(ghs_platform GhsMultiPlatform "" "")
+ add_test_GhsMulti(custom_target GhsMultiCustomTarget "" "")
+ add_test_GhsMulti(dep_order GhsMultiDepOrder "" "")
+ add_test_GhsMulti(external_project GhsMultiExternalProject "" "")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/GhsMulti/${ghs_config_name}")
+ #unset ghs config variables
+ unset(ghs_config_name)
+ unset(ghs_target_arch)
+ unset(ghs_toolset_root)
+ unset(ghs_toolset_name)
+ unset(ghs_os_root)
+ unset(ghs_os_dir)
+ unset(ghs_target_platform)
+ unset(ghs_bsp_name)
+ unset(ghs_toolset_extra)
+ endforeach()
+ endif()
+
+ macro(add_test_VSAndroid name generator platform)
+ add_test(NAME "VSAndroid.${name}.${platform}" COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/VSAndroid"
+ "${CMake_BINARY_DIR}/Tests/VSAndroid/${name}/${platform}"
+ --build-generator "${generator}"
+ --build-project VSAndroid
+ --build-config $<CONFIGURATION>
+ --build-options -DCMAKE_SYSTEM_NAME=Android "-A${platform}"
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSAndroid/${name}")
+ endmacro()
+ if(tegra AND NOT "${CMake_SOURCE_DIR};${CMake_BINARY_DIR}" MATCHES " ")
+ if(vs10)
+ add_test_VSAndroid(vs10 "Visual Studio 10 2010" "Tegra-Android")
+ endif()
+ if(vs11)
+ add_test_VSAndroid(vs11 "Visual Studio 11 2012" "Tegra-Android")
+ endif()
+ if(vs12)
+ add_test_VSAndroid(vs12 "Visual Studio 12 2013" "Tegra-Android")
+ endif()
+ if(vs14)
+ add_test_VSAndroid(vs14 "Visual Studio 14 2015" "Tegra-Android")
+ endif()
+ endif()
+ if(vs14 AND CMake_TEST_ANDROID_VS14)
+ add_test_VSAndroid(vs14 "Visual Studio 14 2015" "ARM")
+ endif()
+ if(vs15 AND CMake_TEST_ANDROID_VS15)
+ add_test_VSAndroid(vs15 "Visual Studio 15 2017" "ARM")
+ endif()
+ if(vs16 AND CMake_TEST_ANDROID_VS16)
+ add_test_VSAndroid(vs16 "Visual Studio 16 2019" "ARM")
+ endif()
+
+ if (APPLE)
+ if (CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+ set(BundleTestInstallDir
+ "${CMake_BINARY_DIR}/Tests/BundleTest/InstallDirectory")
+ add_test(BundleTest ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/BundleTest"
+ "${CMake_BINARY_DIR}/Tests/BundleTest"
+ --build-two-config
+ ${build_generator_args}
+ --build-project BundleTest
+ --build-target install
+# --build-target package
+ --build-options
+ "-DCMAKE_INSTALL_PREFIX:PATH=${BundleTestInstallDir}"
+ "-DCMake_SOURCE_DIR:PATH=${CMake_SOURCE_DIR}"
+ --test-command
+ ${BundleTestInstallDir}/Applications/SecondBundleExe.app/Contents/MacOS/SecondBundleExe)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/BundleTest")
+
+ add_test(NAME CFBundleTest COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/CFBundleTest"
+ "${CMake_BINARY_DIR}/Tests/CFBundleTest"
+ --build-two-config
+ ${build_generator_args}
+ --build-project CFBundleTest
+ --build-config $<CONFIGURATION>
+ --test-command
+ ${CMAKE_CMAKE_COMMAND} -DCTEST_CONFIGURATION_TYPE=$<CONFIGURATION>
+ -Ddir=${CMake_BINARY_DIR}/Tests/CFBundleTest
+ -Dgen=${CMAKE_GENERATOR}
+ -P ${CMake_SOURCE_DIR}/Tests/CFBundleTest/VerifyResult.cmake)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CFBundleTest")
+
+ add_subdirectory(ObjC)
+ add_subdirectory(ObjCXX)
+ endif ()
+ endif ()
+
+ if(APPLE AND CTEST_TEST_CPACK)
+ add_test(BundleGeneratorTest ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/BundleGeneratorTest"
+ "${CMake_BINARY_DIR}/Tests/BundleGeneratorTest"
+ --build-two-config
+ ${build_generator_args}
+ --build-project BundleGeneratorTest
+ --build-target package
+ --build-options
+ "-DCMAKE_INSTALL_PREFIX:PATH=${CMake_BINARY_DIR}/Tests/BundleGeneratorTest/InstallDirectory"
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/BundleGeneratorTest")
+ endif()
+
+ add_test(WarnUnusedCliUnused ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/WarnUnusedCliUnused"
+ "${CMake_BINARY_DIR}/Tests/WarnUnusedCliUnused"
+ ${build_generator_args}
+ --build-project WarnUnusedCliUnused
+ --build-options
+ "-DUNUSED_CLI_VARIABLE=Unused")
+ set_tests_properties(WarnUnusedCliUnused PROPERTIES
+ PASS_REGULAR_EXPRESSION "CMake Warning:.*Manually-specified variables were not used by the project:.* UNUSED_CLI_VARIABLE")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/WarnUnusedCliUnused")
+
+ add_test(WarnUnusedCliUsed ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/VariableUsage"
+ "${CMake_BINARY_DIR}/Tests/WarnUnusedCliUsed"
+ ${build_generator_args}
+ --build-noclean
+ --build-project WarnUnusedCliUsed
+ --build-options
+ "-DUSED_VARIABLE=Usage proven")
+ set_tests_properties(WarnUnusedCliUsed PROPERTIES
+ PASS_REGULAR_EXPRESSION "Usage proven")
+ set_tests_properties(WarnUnusedCliUsed PROPERTIES
+ FAIL_REGULAR_EXPRESSION "CMake Warning: The variable, 'USED_VARIABLE'")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/WarnUnusedCliUsed")
+
+ add_test(WarnUninitialized ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/VariableUsage"
+ "${CMake_BINARY_DIR}/Tests/WarnUninitialized"
+ ${build_generator_args}
+ --build-noclean
+ --build-project WarnUninitialized
+ --build-options
+ "--warn-uninitialized")
+ set_tests_properties(WarnUninitialized PROPERTIES
+ PASS_REGULAR_EXPRESSION "uninitialized variable 'USED_VARIABLE'")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/WarnUninitialized")
+
+ add_test(TestsWorkingDirectory
+ ${CMAKE_CTEST_COMMAND} -C \${CTEST_CONFIGURATION_TYPE}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/TestsWorkingDirectory"
+ "${CMake_BINARY_DIR}/Tests/TestsWorkingDirectory"
+ ${build_generator_args}
+ --build-project TestsWorkingDirectoryProj
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/TestsWorkingDirectory"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C \${CTEST_CONFIGURATION_TYPE}
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/TestsWorkingDirectory")
+
+ # Make sure CTest can handle a test with no newline in output.
+ add_test(CTest.NoNewline
+ ${CMAKE_CMAKE_COMMAND} -E echo_append "This line has no newline!")
+
+ # A simple test for ctest in script mode
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestScriptMode/CTestTestScriptMode.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestScriptMode/CTestTestScriptMode.cmake" @ONLY)
+# add_test(CTest.ScriptMode ${CMAKE_CTEST_COMMAND}
+# -S "${CMake_BINARY_DIR}/Tests/CTestScriptMode/CTestTestScriptMode.cmake"
+# )
+
+ # A test for ctest_build() with targets in subdirectories
+ set(ctest_configure_options)
+ if(CMAKE_GENERATOR_PLATFORM)
+ list(APPEND ctest_configure_options -A ${CMAKE_GENERATOR_PLATFORM})
+ endif()
+ if(CMAKE_GENERATOR_TOOLSET)
+ list(APPEND ctest_configure_options -T ${CMAKE_GENERATOR_TOOLSET})
+ endif()
+ if(CMake_TEST_EXPLICIT_MAKE_PROGRAM)
+ list(APPEND ctest_configure_options -DCMAKE_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM})
+ endif()
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestBuildCommandProjectInSubdir/CTestBuildCommandProjectInSubdir.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestBuildCommandProjectInSubdir/CTestBuildCommandProjectInSubdir.cmake" @ONLY)
+ unset(ctest_configure_options)
+ add_test(CTest.BuildCommand.ProjectInSubdir
+ ${CMAKE_CTEST_COMMAND} -S "${CMake_BINARY_DIR}/Tests/CTestBuildCommandProjectInSubdir/CTestBuildCommandProjectInSubdir.cmake")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CTestBuildCommandProjectInSubdir/Nested")
+
+ set(CTEST_TEST_UPDATE 1)
+ if(CTEST_TEST_UPDATE)
+ # Test CTest Update with Subversion
+ find_package(Subversion QUIET)
+ if(Subversion_FOUND)
+ get_filename_component(_Subversion_BIN_DIR
+ ${Subversion_SVN_EXECUTABLE} PATH)
+ find_program(Subversion_SVNADMIN_EXECUTABLE svnadmin
+ HINTS ${_Subversion_BIN_DIR}
+ )
+ mark_as_advanced(Subversion_SVNADMIN_EXECUTABLE)
+ if(NOT Subversion_SVNADMIN_EXECUTABLE)
+ set(Subversion_FOUND FALSE)
+ endif()
+ endif()
+ if(Subversion_FOUND)
+ set(CTestUpdateSVN_DIR "CTest UpdateSVN")
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateSVN.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestUpdateSVN.cmake" @ONLY)
+ add_test(CTest.UpdateSVN ${CMAKE_CMAKE_COMMAND}
+ -P "${CMake_BINARY_DIR}/Tests/CTestUpdateSVN.cmake"
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateSVN_DIR}")
+ endif()
+
+ # Test CTest Update with CVS
+ if(EXISTS ${CMAKE_ROOT}/Modules/FindCVS.cmake)
+ find_package(CVS QUIET)
+ else()
+ find_program(CVS_EXECUTABLE NAMES cvs)
+ set(CVS_FOUND ${CVS_EXECUTABLE})
+ endif()
+ set(CTEST_TEST_UPDATE_CVS ${CVS_FOUND})
+ if(CTEST_TEST_UPDATE_CVS AND NOT UNIX)
+ if("${CVS_EXECUTABLE}" MATCHES "cygwin")
+ message(STATUS "No CTest.UpdateCVS test with cygwin cvs.exe outside cygwin!")
+ set(CTEST_TEST_UPDATE_CVS 0)
+ endif()
+ endif()
+ if(CTEST_TEST_UPDATE_CVS)
+ set(CTestUpdateCVS_DIR "CTest UpdateCVS")
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateCVS.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestUpdateCVS.cmake" @ONLY)
+ add_test(CTest.UpdateCVS ${CMAKE_CMAKE_COMMAND}
+ -P "${CMake_BINARY_DIR}/Tests/CTestUpdateCVS.cmake"
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateCVS_DIR}")
+ endif()
+
+ # Test CTest Update with BZR
+ find_program(BZR_EXECUTABLE NAMES bzr)
+ mark_as_advanced(BZR_EXECUTABLE)
+ set(CTEST_TEST_UPDATE_BZR 0)
+ if(BZR_EXECUTABLE)
+ if(NOT "${BZR_EXECUTABLE}" MATCHES "cygwin" OR UNIX)
+ set(CTEST_TEST_UPDATE_BZR 1)
+ endif()
+ endif()
+ if(CTEST_TEST_UPDATE_BZR)
+ # Check if xmloutput plugin is there
+ execute_process(COMMAND ${BZR_EXECUTABLE} xmlplugins RESULT_VARIABLE xmlplugres
+ OUTPUT_QUIET ERROR_QUIET)
+ if( NOT ${xmlplugres} )
+ set(CTestUpdateBZR_DIR "CTest UpdateBZR")
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateBZR.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestUpdateBZR.cmake" @ONLY)
+ add_test(CTest.UpdateBZR ${CMAKE_CMAKE_COMMAND}
+ -P "${CMake_BINARY_DIR}/Tests/CTestUpdateBZR.cmake"
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateBZR_DIR}")
+ set(CTestUpdateBZR_DIR "CTest UpdateBZR_CLocale")
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateBZR.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestUpdateBZR_CLocale.cmake" @ONLY)
+ add_test(CTest.UpdateBZR.CLocale ${CMAKE_CMAKE_COMMAND}
+ -P "${CMake_BINARY_DIR}/Tests/CTestUpdateBZR_CLocale.cmake"
+ )
+ set_tests_properties(CTest.UpdateBZR.CLocale PROPERTIES ENVIRONMENT LC_ALL=C)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateBZR_DIR}")
+ endif()
+ endif()
+
+ # Test CTest Update with GIT
+ find_program(GIT_EXECUTABLE NAMES git)
+ mark_as_advanced(GIT_EXECUTABLE)
+ set(CTEST_TEST_UPDATE_GIT 0)
+ if(GIT_EXECUTABLE)
+ if(NOT "${GIT_EXECUTABLE}" MATCHES "cygwin" OR UNIX)
+ set(CTEST_TEST_UPDATE_GIT 1)
+ endif()
+ endif()
+ if(CTEST_TEST_UPDATE_GIT)
+ set(CTestUpdateGIT_DIR "CTest UpdateGIT")
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateGIT.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestUpdateGIT.cmake" @ONLY)
+ add_test(CTest.UpdateGIT ${CMAKE_CMAKE_COMMAND}
+ -P "${CMake_BINARY_DIR}/Tests/CTestUpdateGIT.cmake"
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateGIT_DIR}")
+ endif()
+
+ # Test CTest Update with HG
+ find_program(HG_EXECUTABLE NAMES hg)
+ mark_as_advanced(HG_EXECUTABLE)
+ set(CTEST_TEST_UPDATE_HG 0)
+ if(HG_EXECUTABLE)
+ if(NOT "${HG_EXECUTABLE}" MATCHES "cygwin" OR UNIX)
+ set(CTEST_TEST_UPDATE_HG 1)
+ endif()
+ endif()
+ if(CTEST_TEST_UPDATE_HG)
+ set(CTestUpdateHG_DIR "CTest UpdateHG")
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateHG.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestUpdateHG.cmake" @ONLY)
+ add_test(CTest.UpdateHG ${CMAKE_CMAKE_COMMAND}
+ -P "${CMake_BINARY_DIR}/Tests/CTestUpdateHG.cmake"
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateHG_DIR}")
+ endif()
+
+ # Test CTest Update with P4
+ find_program(P4_EXECUTABLE NAMES p4)
+ find_program(P4D_EXECUTABLE NAMES p4d)
+ mark_as_advanced(P4_EXECUTABLE P4D_EXECUTABLE)
+ set(CTEST_TEST_UPDATE_P4 0)
+ if(P4_EXECUTABLE AND P4D_EXECUTABLE)
+ if(NOT "${P4_EXECUTABLE};${P4D_EXECUTABLE}" MATCHES "cygwin" OR UNIX)
+ set(CTEST_TEST_UPDATE_P4 1)
+ endif()
+ endif()
+ if(CTEST_TEST_UPDATE_P4)
+ set(CTestUpdateP4_DIR "CTest UpdateP4")
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateP4.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestUpdateP4.cmake" @ONLY)
+ add_test(CTest.UpdateP4 ${CMAKE_CMAKE_COMMAND}
+ -P "${CMake_BINARY_DIR}/Tests/CTestUpdateP4.cmake"
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateP4_DIR}")
+ endif()
+ endif()
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestFailure/testNoBuild.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestFailure/testNoBuild.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestNoBuild ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestFailure/testNoBuild.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestFailure/testOut1.log"
+ )
+ set_tests_properties(CTestTestNoBuild PROPERTIES
+ FAIL_REGULAR_EXPRESSION "Error" WILL_FAIL true)
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestFailure/testNoExe.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestFailure/testNoExe.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestNoExe ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestFailure/testNoExe.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestFailure/testOut2.log"
+ )
+ set_tests_properties(CTestTestNoExe PROPERTIES DEPENDS CTestTestNoBuild
+ PASS_REGULAR_EXPRESSION "Could not find executable"
+ FAIL_REGULAR_EXPRESSION "SegFault")
+
+ if(NOT CMake_TEST_NO_NETWORK)
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestUpload/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestUpload/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestUpload ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestUpload/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestUpload/testOut.log"
+ )
+ set_tests_properties(CTestTestUpload PROPERTIES
+ PASS_REGULAR_EXPRESSION "Upload\\.xml")
+ endif()
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestCoverageCollectGCOV/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestCoverageCollectGCOV/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestCoverageCollectGCOV ${CMAKE_CTEST_COMMAND}
+ -C \${CTEST_CONFIGURATION_TYPE}
+ -S "${CMake_BINARY_DIR}/Tests/CTestCoverageCollectGCOV/test.cmake" -VV
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestCoverageCollectGCOV/testOut.log"
+ )
+ set_property(TEST CTestCoverageCollectGCOV PROPERTY ENVIRONMENT CTEST_PARALLEL_LEVEL=)
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestEmptyBinaryDirectory/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestEmptyBinaryDirectory/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestEmptyBinaryDirectory ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestEmptyBinaryDirectory/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestEmptyBinaryDirectory/testOut.log"
+ )
+ set_tests_properties(CTestTestEmptyBinaryDirectory PROPERTIES
+ PASS_REGULAR_EXPRESSION "TEST_SUCCESS")
+
+ # test coverage for mumps
+ # create a MumpsCoverage dir in the binary tree under Testing to
+ # avoid the .NoDartCoverage files in the cmake testing tree
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/MumpsCoverage/DartConfiguration.tcl.in"
+ "${CMake_BINARY_DIR}/Testing/MumpsCoverage/DartConfiguration.tcl")
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/MumpsCoverage/gtm_coverage.mcov.in"
+ "${CMake_BINARY_DIR}/Testing/MumpsCoverage/gtm_coverage.mcov")
+ file(REMOVE_RECURSE "${CMake_BINARY_DIR}/Testing/MumpsCoverage/VistA-FOIA")
+ file(COPY "${CMake_SOURCE_DIR}/Tests/MumpsCoverage/VistA-FOIA"
+ DESTINATION "${CMake_BINARY_DIR}/Testing/MumpsCoverage")
+ add_test(NAME CTestGTMCoverage
+ COMMAND ${CMAKE_CMAKE_COMMAND} -E chdir
+ ${CMake_BINARY_DIR}/Testing/MumpsCoverage
+ $<TARGET_FILE:ctest> -T Coverage --debug)
+ set_tests_properties(CTestGTMCoverage PROPERTIES
+ PASS_REGULAR_EXPRESSION
+ "Process file.*ZZCOVTST.m.*Total LOC:.*32.*Percentage Coverage: 81.25*"
+ ENVIRONMENT COVFILE=)
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/MumpsCoverage/DartConfiguration.cache.tcl.in"
+ "${CMake_BINARY_DIR}/Testing/MumpsCacheCoverage/DartConfiguration.tcl")
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/MumpsCoverage/cache_coverage.cmcov.in"
+ "${CMake_BINARY_DIR}/Testing/MumpsCacheCoverage/cache_coverage.cmcov")
+ file(REMOVE_RECURSE "${CMake_BINARY_DIR}/Testing/MumpsCacheCoverage/VistA-FOIA")
+ file(COPY "${CMake_SOURCE_DIR}/Tests/MumpsCoverage/VistA-FOIA"
+ DESTINATION "${CMake_BINARY_DIR}/Testing/MumpsCacheCoverage")
+ add_test(NAME CTestCacheCoverage
+ COMMAND ${CMAKE_CMAKE_COMMAND} -E chdir
+ ${CMake_BINARY_DIR}/Testing/MumpsCacheCoverage
+ $<TARGET_FILE:ctest> -T Coverage --debug)
+ set_tests_properties(CTestCacheCoverage PROPERTIES
+ PASS_REGULAR_EXPRESSION
+ "Process file.*ZZCOVTST.m.*Total LOC:.*32.*Percentage Coverage: 87.50.*"
+ ENVIRONMENT COVFILE=)
+
+ # Adding a test case for Python Coverage
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/PythonCoverage/coverage.xml.in"
+ "${CMake_BINARY_DIR}/Testing/PythonCoverage/coverage.xml")
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/PythonCoverage/DartConfiguration.tcl.in"
+ "${CMake_BINARY_DIR}/Testing/PythonCoverage/DartConfiguration.tcl")
+ file(COPY "${CMake_SOURCE_DIR}/Tests/PythonCoverage/coveragetest"
+ DESTINATION "${CMake_BINARY_DIR}/Testing/PythonCoverage")
+ add_test(NAME CTestPythonCoverage
+ COMMAND ${CMAKE_CMAKE_COMMAND} -E chdir
+ ${CMake_BINARY_DIR}/Testing/PythonCoverage
+ $<TARGET_FILE:ctest> -T Coverage --debug)
+ set_tests_properties(CTestPythonCoverage PROPERTIES
+ PASS_REGULAR_EXPRESSION
+ "Process file.*foo.py.*Total LOC:.*13.*Percentage Coverage: 84.62.*"
+ ENVIRONMENT COVFILE=)
+
+ # Adding a test case for non-python Cobertura Coverage
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CoberturaCoverage/DartConfiguration.tcl.in"
+ "${CMake_BINARY_DIR}/Testing/CoberturaCoverage/DartConfiguration.tcl")
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CoberturaCoverage/coverage.xml.in"
+ "${CMake_BINARY_DIR}/Testing/CoberturaCoverage/coverage.xml")
+ file(COPY "${CMake_SOURCE_DIR}/Tests/CoberturaCoverage/src"
+ DESTINATION "${CMake_BINARY_DIR}/Testing/CoberturaCoverage")
+ add_test(NAME CTestCoberturaCoverage
+ COMMAND ${CMAKE_CMAKE_COMMAND} -E chdir
+ ${CMake_BINARY_DIR}/Testing/CoberturaCoverage
+ $<TARGET_FILE:ctest> -T Coverage --debug)
+ set_tests_properties(CTestCoberturaCoverage PROPERTIES
+ PASS_REGULAR_EXPRESSION
+ "Process file.*CoverageTest.java.*Total LOC:.*18.*Percentage Coverage: 72.22.*"
+ ENVIRONMENT COBERTURADIR=${CMake_BINARY_DIR}/Testing/CoberturaCoverage
+ ENVIRONMENT COVFILE=)
+
+
+ # Adding a test case for JaCoCo Coverage
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/JacocoCoverage/DartConfiguration.tcl.in"
+ "${CMake_BINARY_DIR}/Testing/JacocoCoverage/DartConfiguration.tcl")
+ file(COPY "${CMake_SOURCE_DIR}/Tests/JacocoCoverage/Coverage"
+ DESTINATION "${CMake_BINARY_DIR}/Testing/JacocoCoverage")
+ configure_file("${CMake_BINARY_DIR}/Testing/JacocoCoverage/Coverage/target/site/jacoco.xml.in"
+ "${CMake_BINARY_DIR}/Testing/JacocoCoverage/Coverage/target/site/jacoco.xml")
+ add_test(NAME CTestJacocoCoverage
+ COMMAND ${CMAKE_CMAKE_COMMAND} -E chdir
+ ${CMake_BINARY_DIR}/Testing/JacocoCoverage
+ $<TARGET_FILE:ctest> -T Coverage --debug)
+ set_tests_properties(CTestJacocoCoverage PROPERTIES
+ PASS_REGULAR_EXPRESSION
+ "Process file.*CoverageTest.java.*Total LOC:.*17.*Percentage Coverage: 76.47*"
+ ENVIRONMENT COVFILE=)
+
+ # Adding a test case for Javascript Coverage
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/JavascriptCoverage/DartConfiguration.tcl.in"
+ "${CMake_BINARY_DIR}/Testing/JavascriptCoverage/DartConfiguration.tcl")
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/JavascriptCoverage/output.json.in"
+ "${CMake_BINARY_DIR}/Testing/JavascriptCoverage/output.json")
+ file(COPY "${CMake_SOURCE_DIR}/Tests/JavascriptCoverage/"
+ DESTINATION "${CMake_BINARY_DIR}/Testing/JavascriptCoverage"
+ FILES_MATCHING PATTERN "*.js")
+ add_test(NAME CTestJavascriptCoverage
+ COMMAND ${CMAKE_CMAKE_COMMAND} -E chdir
+ ${CMake_BINARY_DIR}/Testing/JavascriptCoverage
+ $<TARGET_FILE:ctest> -T Coverage --debug)
+ set_tests_properties(CTestJavascriptCoverage PROPERTIES
+ PASS_REGULAR_EXPRESSION
+ "Process file.*test3.js.*Total LOC:.*49.*Percentage Coverage: 79.59*"
+ ENVIRONMENT COVFILE=)
+
+ # test coverage for Delphi-code-Coverage
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/DelphiCoverage/DartConfiguration.tcl.in"
+ "${CMake_BINARY_DIR}/Testing/DelphiCoverage/DartConfiguration.tcl")
+ file(COPY "${CMake_SOURCE_DIR}/Tests/DelphiCoverage/src"
+ DESTINATION "${CMake_BINARY_DIR}/Testing/DelphiCoverage")
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/DelphiCoverage/UTCovTest(UTCovTest.pas).html.in"
+ "${CMake_BINARY_DIR}/Testing/DelphiCoverage/UTCovTest(UTCovTest.pas).html")
+ add_test(NAME CTestDelphiCoverage
+ COMMAND ${CMAKE_CMAKE_COMMAND} -E chdir
+ ${CMake_BINARY_DIR}/Testing/DelphiCoverage
+ $<TARGET_FILE:ctest> -T Coverage --debug)
+ set_tests_properties(CTestDelphiCoverage PROPERTIES
+ PASS_REGULAR_EXPRESSION
+ "Process file.*UTCovTest.pas.*Total LOC:.*20.*Percentage Coverage: 95.*"
+ ENVIRONMENT COVFILE=)
+
+ function(add_config_tests cfg)
+ set(base "${CMake_BINARY_DIR}/Tests/CTestConfig")
+
+ # Test -S script with a -C config arg to ctest:
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestConfig/script.cmake.in"
+ "${base}/${cfg}-script.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestConfig.Script.${cfg} ${CMAKE_CTEST_COMMAND}
+ -C ${cfg}
+ -S "${base}/${cfg}-script.cmake" -VV
+ --output-log "${base}/${cfg}-script.log"
+ )
+
+ # Test -D dashboard with a -C config arg to ctest.
+ # (Actual commands inside a cmake -P script because we need to be able to set
+ # the working directory reliably...)
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestConfig/dashboard.cmake.in"
+ "${base}/${cfg}-dashboard.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestConfig.Dashboard.${cfg} ${CMAKE_CMAKE_COMMAND}
+ -P "${base}/${cfg}-dashboard.cmake" -VV
+ )
+ endfunction()
+
+ add_config_tests(Debug)
+ add_config_tests(MinSizeRel)
+ add_config_tests(Release)
+ add_config_tests(RelWithDebInfo)
+
+ # Test -S script with some -D variable definition args to ctest:
+ add_test(CTestConfig.ScriptWithArgs ${CMAKE_CTEST_COMMAND}
+ -C "Release"
+ -D arg1=this
+ -D arg2=that
+ -D "arg3=the other"
+ "-Darg4=this is the fourth"
+ -Darg5=the_fifth
+ -Darg6:STRING=value-with-type
+ -S "${CMake_SOURCE_DIR}/Tests/CTestConfig/ScriptWithArgs.cmake" -VV
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestConfig/ScriptWithArgs.log"
+ )
+
+ ADD_TEST_MACRO(CMakeCommands.add_compile_definitions add_compile_definitions)
+ ADD_TEST_MACRO(CMakeCommands.add_compile_options add_compile_options)
+ ADD_TEST_MACRO(CMakeCommands.target_link_libraries target_link_libraries)
+ ADD_TEST_MACRO(CMakeCommands.target_include_directories target_include_directories)
+ ADD_TEST_MACRO(CMakeCommands.target_compile_definitions target_compile_definitions)
+ ADD_TEST_MACRO(CMakeCommands.target_compile_options target_compile_options)
+ ADD_TEST_MACRO(CMakeCommands.target_sources target_sources)
+
+ ADD_TEST_MACRO(CMakeCommands.add_link_options)
+ ADD_TEST_MACRO(CMakeCommands.target_link_options)
+ ADD_TEST_MACRO(CMakeCommands.link_directories)
+ ADD_TEST_MACRO(CMakeCommands.target_link_directories)
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestCrash/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestCrash/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestCrash ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestCrash/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestCrash/testOutput.log"
+ )
+ # with watcom the SEGFAULT is not found, it just fails
+ if(CMAKE_GENERATOR MATCHES "Watcom WMake")
+ set_tests_properties(CTestTestCrash PROPERTIES
+ PASS_REGULAR_EXPRESSION "Failed")
+ else()
+ set_tests_properties(CTestTestCrash PROPERTIES
+ PASS_REGULAR_EXPRESSION "(Illegal|SegFault|Subprocess aborted|SIGTRAP)")
+ endif()
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestBadExe/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestBadExe/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestBadExe ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestBadExe/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestBadExe/testOutput.log"
+ )
+ set(CTestTestBadExe_REGEX "BAD_COMMAND")
+ # some cygwin can not be made to produce a BAD_COMMAND error
+ # the best we can get from it is a failed test
+ if(CYGWIN)
+ set(CTestTestBadExe_REGEX "(\\*\\*\\*Failed)|BAD_COMMAND")
+ endif()
+ set_tests_properties(CTestTestBadExe PROPERTIES
+ PASS_REGULAR_EXPRESSION "${CTestTestBadExe_REGEX}")
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestBadGenerator/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestBadGenerator/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestBadGenerator ${CMAKE_CTEST_COMMAND}
+ -C "\${CTestTest_CONFIG}"
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestBadGenerator/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestBadGenerator/testOutput.log"
+ )
+ set_property(TEST CTestTestBadGenerator PROPERTY
+ PASS_REGULAR_EXPRESSION "could not create generator named \"Bad Generator\"")
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestParallel/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestParallel/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestParallel ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestParallel/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestParallel/testOutput.log"
+ )
+
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestTestVerboseOutput/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestVerboseOutput/test.cmake" @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestVerboseOutput ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestVerboseOutput/test.cmake" -VV
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestVerboseOutput/testOutput.log"
+ -C "\${CTestTest_CONFIG}"
+ )
+ set_property(TEST CTestTestVerboseOutput PROPERTY PASS_REGULAR_EXPRESSION
+ "Environment variables:.*foo=bar.*this=that"
+ )
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestSkipReturnCode/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestSkipReturnCode/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestSkipReturnCode ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestSkipReturnCode/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestSkipReturnCode/testOutput.log"
+ -C \${CTEST_CONFIGURATION_TYPE}
+ )
+ set_tests_properties(CTestTestSkipReturnCode PROPERTIES
+ PASS_REGULAR_EXPRESSION "CMakeV1 \\.* +Passed.*CMakeV2 \\.+\\*+Skipped")
+ set_property(TEST CTestTestSkipReturnCode PROPERTY ENVIRONMENT CTEST_PARALLEL_LEVEL=)
+
+ ADD_TEST_MACRO(CTestTestSerialInDepends ${CMAKE_CTEST_COMMAND} -j 4
+ --output-on-failure -C "\${CTestTest_CONFIG}")
+
+ ADD_TEST_MACRO(CTestTestMissingDependsExe ${CMAKE_CTEST_COMMAND}
+ --output-on-failure -C "\${CTestTest_CONFIG}")
+ set_tests_properties(CTestTestMissingDependsExe PROPERTIES
+ PASS_REGULAR_EXPRESSION "\\*\\*\\*Not Run"
+ )
+
+ ADD_TEST_MACRO(CTestTestSerialOrder ${CMAKE_CTEST_COMMAND}
+ --output-on-failure -C "\${CTestTest_CONFIG}")
+ set_property(TEST CTestTestSerialOrder PROPERTY ENVIRONMENT CTEST_PARALLEL_LEVEL=)
+
+ if(NOT BORLAND)
+ set(CTestLimitDashJ_CTEST_OPTIONS --force-new-ctest-process)
+ add_test_macro(CTestLimitDashJ ${CMAKE_CTEST_COMMAND} -j 4
+ --output-on-failure -C "\${CTestTest_CONFIG}")
+ endif()
+
+ add_test(CTestTestPrintLabels ${CMAKE_CTEST_COMMAND} --print-labels)
+ set_tests_properties(CTestTestPrintLabels PROPERTIES LABELS "Label1;Label2")
+ set_tests_properties(CTestTestPrintLabels PROPERTIES PASS_REGULAR_EXPRESSION
+ "All Labels:.* Label1.* Label2")
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestLabelRegExp/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestLabelRegExp/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(NAME CTestTestLabelRegExp
+ COMMAND ${CMAKE_CMAKE_COMMAND}
+ -DSOURCE_DIR=${CMAKE_SOURCE_DIR}/Tests/CTestTestLabelRegExp
+ -P ${CMAKE_BINARY_DIR}/Tests/CTestTestLabelRegExp/test.cmake
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Tests/CTestTestLabelRegExp
+ )
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestResourceLock/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestResourceLock/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestResourceLock ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestResourceLock/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestResourceLock/output.log"
+ )
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestScheduler/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestScheduler/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestScheduler ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestScheduler/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestScheduler/testOutput.log"
+ )
+ set_tests_properties(CTestTestScheduler PROPERTIES
+ PASS_REGULAR_EXPRESSION "Start 1.*Start 2.*Start 3.*Start 4.*Start 4.*Start 3.*Start 2.*Start 1"
+ RESOURCE_LOCK "CostData")
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestCostSerial/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestCostSerial/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestCostSerial ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestCostSerial/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestCostSerial/testOutput.log"
+ )
+ set_tests_properties(CTestTestCostSerial PROPERTIES
+ PASS_REGULAR_EXPRESSION "Start 2.*Start 3.*Start 1.*Start 2.*Start 3.*Start 1"
+ RESOURCE_LOCK "CostData")
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestStopTime/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestStopTime/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestStopTime/GetDate.cmake"
+ "${CMake_BINARY_DIR}/Tests/CTestTestStopTime/GetDate.cmake"
+ COPYONLY)
+ add_test(CTestTestStopTime ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestStopTime/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestStopTime/testOutput.log"
+ )
+ set_tests_properties(CTestTestStopTime PROPERTIES
+ PASS_REGULAR_EXPRESSION "The stop time has been passed")
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestSubdir/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestSubdir/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestSubdir ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestSubdir/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestSubdir/testOutput.log"
+ )
+ #make sure all 3 subdirs were added
+ set_tests_properties(CTestTestSubdir PROPERTIES
+ PASS_REGULAR_EXPRESSION "0 tests failed out of 3")
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestTimeout/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestTimeout/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestTimeout ${CMAKE_CTEST_COMMAND}
+ -C "\${CTestTest_CONFIG}"
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestTimeout/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestTimeout/testOutput.log"
+ )
+ set_tests_properties(CTestTestTimeout PROPERTIES
+ PASS_REGULAR_EXPRESSION "TestTimeout *\\.+ *\\*\\*\\*Timeout.*TestSleep *\\.+ *Passed.*timeout correctly killed child")
+
+ add_test(
+ NAME CTestTestRerunFailed
+ COMMAND ${CMAKE_CTEST_COMMAND} --rerun-failed)
+ set_tests_properties(CTestTestRerunFailed PROPERTIES
+ PASS_REGULAR_EXPRESSION "1/1 Test #1: TestTimeout" DEPENDS CTestTestTimeout
+ WORKING_DIRECTORY ${CMake_BINARY_DIR}/Tests/CTestTestTimeout)
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestZeroTimeout/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestZeroTimeout/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestZeroTimeout ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestZeroTimeout/test.cmake" -V
+ --output-log
+ "${CMake_BINARY_DIR}/Tests/CTestTestZeroTimeout/testOutput.log")
+ set_tests_properties(CTestTestZeroTimeout PROPERTIES
+ FAIL_REGULAR_EXPRESSION "\\*\\*\\*Timeout")
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestDepends/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestDepends/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestDepends ${CMAKE_CTEST_COMMAND}
+ -C "\${CTestTest_CONFIG}"
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestDepends/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestDepends/testOutput.log"
+ )
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestCycle/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestCycle/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestCycle ${CMAKE_CTEST_COMMAND}
+ -C "\${CTestTest_CONFIG}"
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestCycle/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestCycle/testOutput.log"
+ )
+ set_tests_properties(CTestTestCycle PROPERTIES
+ PASS_REGULAR_EXPRESSION "a cycle exists in the test dependency graph")
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestRunScript/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestRunScript/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestRunScript/hello.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestRunScript/hello.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestRunScript ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestRunScript/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestRunScript/testOutput.log"
+ )
+
+ add_test(CTestTestShowOnly ${CMAKE_CTEST_COMMAND} -N)
+
+ configure_file(
+ "${CMake_SOURCE_DIR}/Tests/CTestTestFdSetSize/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestFdSetSize/test.cmake"
+ @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestFdSetSize ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestFdSetSize/test.cmake" -j20 -V --timeout 120
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestFdSetSize/testOutput.log"
+ )
+
+ if (CMAKE_TESTS_CDASH_SERVER)
+ set(regex "^([^:]+)://([^/]+)(.*)$")
+
+ if ("${CMAKE_TESTS_CDASH_SERVER}" MATCHES "${regex}")
+ set(protocol "${CMAKE_MATCH_1}")
+ set(server "${CMAKE_MATCH_2}")
+ set(path "${CMAKE_MATCH_3}")
+ else ()
+ set(protocol "http")
+ set(server "open.cdash.org")
+ set(path "")
+ message("warning: CMAKE_TESTS_CDASH_SERVER does not match expected regex...")
+ message(" ...using default url='${protocol}://${server}${path}' for CTestTest[23]")
+ endif ()
+ endif ()
+
+
+ if (CTEST_TEST_CTEST AND CMAKE_RUN_LONG_TESTS AND CMAKE_TESTS_CDASH_SERVER)
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestTest/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTest/test.cmake" @ONLY ESCAPE_QUOTES)
+ add_test(CTestTest ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTest/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTest/testOutput.log"
+ )
+
+ if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestTest2/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTest2/test.cmake" @ONLY ESCAPE_QUOTES)
+ add_test(CTestTest2 ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTest2/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTest2/testOutput.log"
+ )
+ endif()
+
+ if("${CMAKE_GENERATOR}" MATCHES "Makefiles" OR "${CMAKE_GENERATOR}" MATCHES "Ninja")
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestTestLaunchers/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestLaunchers/test.cmake" @ONLY ESCAPE_QUOTES)
+ add_test(CTestTestLaunchers ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestLaunchers/test.cmake" -V
+ --output-log "${CMake_BINARY_DIR}/Tests/CTestTestLaunchers/testOutput.log"
+ )
+ set_tests_properties(CTestTestLaunchers PROPERTIES
+ PASS_REGULAR_EXPRESSION "CTEST_TEST_LAUNCHER_SUCCESS")
+ endif()
+
+ configure_file("${CMake_SOURCE_DIR}/Tests/CTestTestChecksum/test.cmake.in"
+ "${CMake_BINARY_DIR}/Tests/CTestTestChecksum/test.cmake" @ONLY
+ ESCAPE_QUOTES)
+ add_test(CTestTestChecksum ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestTestChecksum/test.cmake" -V
+ --output-log
+ "${CMake_BINARY_DIR}/Tests/CTestTestChecksum/testOutput.log"
+ )
+ set_tests_properties(CTestTestChecksum PROPERTIES PASS_REGULAR_EXPRESSION
+ "Submission failed: Checksum failed for file")
+
+ # these tests take a long time, make sure they have it
+ # if timeouts have not already been set
+ get_test_property(CTestTest TIMEOUT PREVIOUS_TIMEOUT)
+ if ("${PREVIOUS_TIMEOUT}" MATCHES NOTFOUND)
+ set_tests_properties ( CTestTest
+ PROPERTIES TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
+ endif ()
+
+ if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ get_test_property(CTestTest2 TIMEOUT PREVIOUS_TIMEOUT)
+ if("${PREVIOUS_TIMEOUT}" MATCHES NOTFOUND)
+ set_tests_properties ( CTestTest2
+ PROPERTIES TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
+ endif()
+ endif()
+ endif ()
+
+ if(CMake_TEST_EXTERNAL_CMAKE)
+ set(CMAKE_SKIP_BOOTSTRAP_TEST 1)
+ endif()
+ if("${CMAKE_GENERATOR}" MATCHES Xcode)
+ set(CMAKE_SKIP_BOOTSTRAP_TEST 1)
+ endif()
+ if(EXISTS "${CMake_BINARY_DIR}/CMakeLists.txt")
+ # If there is CMakeLists.txt in the binary tree, assume in-source build
+ set(CMAKE_SKIP_BOOTSTRAP_TEST 1)
+ endif()
+ set(bootstrap "")
+ if(CMAKE_RUN_LONG_TESTS AND NOT CMAKE_SKIP_BOOTSTRAP_TEST)
+ if(UNIX)
+ set(bootstrap ${CMake_SOURCE_DIR}/bootstrap)
+ elseif(MSYS)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/bootstrap.bat.in
+ ${CMAKE_CURRENT_BINARY_DIR}/bootstrap.bat @ONLY)
+ set(bootstrap ${CMAKE_CURRENT_BINARY_DIR}/bootstrap.bat)
+ endif()
+ endif()
+ if(bootstrap)
+ add_test(NAME BootstrapTest
+ COMMAND ${CMAKE_CMAKE_COMMAND}
+ -D "bootstrap=${bootstrap}"
+ -D "bin_dir=${CMake_BINARY_DIR}/Tests/BootstrapTest"
+ -D "generator=${CMAKE_GENERATOR}"
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/BootstrapTest.cmake
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/BootstrapTest")
+ # This test will use all processors.
+ set_tests_properties(BootstrapTest PROPERTIES RUN_SERIAL 1)
+
+ # provide more time for the bootstrap test
+ get_test_property(BootstrapTest TIMEOUT PREVIOUS_TIMEOUT)
+ if ("${PREVIOUS_TIMEOUT}" MATCHES NOTFOUND)
+ set_tests_properties ( BootstrapTest
+ PROPERTIES TIMEOUT 5400)
+ endif ()
+ endif()
+
+ if(CMAKE_Fortran_COMPILER)
+ add_test(Fortran ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Fortran"
+ "${CMake_BINARY_DIR}/Tests/Fortran"
+ ${build_generator_args}
+ --build-project testf
+ --build-two-config
+ --test-command testf)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Fortran")
+
+ if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
+ add_test(FortranModules ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FortranModules"
+ "${CMake_BINARY_DIR}/Tests/FortranModules"
+ ${build_generator_args}
+ --build-project FortranModules
+ --build-options
+ -DCMake_TEST_NESTED_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM}
+ -DCMake_TEST_Fortran_SUBMODULES:BOOL=${CMake_TEST_Fortran_SUBMODULES}
+ ${CMake_TEST_FortranModules_BUILD_OPTIONS}
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/FortranModules")
+ endif()
+
+ # FortranCInterface tests.
+ if(UNIX)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/FortranC/Flags.cmake.in
+ ${CMAKE_CURRENT_BINARY_DIR}/FortranC/Flags.cmake @ONLY)
+ add_test(FortranC.Flags ${CMAKE_CMAKE_COMMAND} -P
+ ${CMAKE_CURRENT_BINARY_DIR}/FortranC/Flags.cmake)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/FortranC/Flags")
+ else()
+ add_test(FortranC ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FortranC"
+ "${CMake_BINARY_DIR}/Tests/FortranC"
+ ${build_generator_args}
+ --build-project FortranC
+ --build-two-config
+ --test-command CMakeFiles/FortranCInterface/FortranCInterface)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/FortranC")
+ endif()
+ endif()
+
+ if(NOT DEFINED CMake_TEST_Java)
+ if(APPLE OR MINGW)
+ set(CMake_TEST_Java 0)
+ else()
+ set(CMake_TEST_Java 1)
+ endif()
+ endif()
+ if(CMake_TEST_Java)
+ find_package(Java COMPONENTS Development QUIET)
+ endif()
+ if(Java_JAVA_EXECUTABLE AND Java_JAVAC_EXECUTABLE AND Java_JAR_EXECUTABLE)
+
+ set(JavaExportImport_BUILD_OPTIONS -DCMake_TEST_NESTED_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM})
+ ADD_TEST_MACRO(JavaExportImport JavaExportImport)
+
+ get_filename_component(JNIPATH ${JAVA_COMPILE} PATH)
+ find_file(JNI_H jni.h
+ "${JNIPATH}/../include"
+ "${JNIPATH}/../java/include")
+ if(JNI_H AND EXISTS "${JNI_H}") # in case jni.h is a broken symlink
+ file(READ "${JNI_H}" JNI_FILE)
+ if("${JNI_FILE}" MATCHES "JDK1_2")
+ add_test(NAME Java.Jar COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Java"
+ "${CMake_BINARY_DIR}/Tests/JavaJar"
+ ${build_generator_args}
+ --build-project hello
+ --build-run-dir "${CMake_BINARY_DIR}/Tests/JavaJar/"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIG>)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/JavaJar")
+
+ # For next tests, java tool must have same architecture as toolchain
+ math(EXPR _object_mode "${CMAKE_SIZEOF_VOID_P} * 8")
+ execute_process(
+ COMMAND "${Java_JAVA_EXECUTABLE}" -version
+ OUTPUT_VARIABLE _version ERROR_VARIABLE _version RESULT_VARIABLE _result
+ )
+ if(_result EQUAL 0 AND _version MATCHES "${_object_mode}-Bit")
+ ## next test is valid only if Java version is less than 1.10
+ if ("${Java_VERSION}" VERSION_LESS 1.10)
+ add_test(NAME Java.Javah COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/JavaJavah"
+ "${CMake_BINARY_DIR}/Tests/JavaJavah"
+ ${build_generator_args}
+ --build-project helloJavah
+ --build-run-dir "${CMake_BINARY_DIR}/Tests/JavaJavah/"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIG>)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/JavaJavah")
+ endif()
+ ## next test is valid only if Java is, at least, version 1.8
+ if (NOT "${Java_VERSION}" VERSION_LESS 1.8)
+ add_test(NAME Java.NativeHeaders COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/JavaNativeHeaders"
+ "${CMake_BINARY_DIR}/Tests/JavaNativeHeaders"
+ ${build_generator_args}
+ --build-project helloJavaNativeHeaders
+ --build-run-dir "${CMake_BINARY_DIR}/Tests/JavaNativeHeaders/"
+ --build-target install
+ --build-options
+ "-DCMAKE_INSTALL_PREFIX:PATH=${CMake_BINARY_DIR}/Tests/JavaNativeHeaders/Install"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIG>)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/JavaNativeHeaders")
+ endif()
+ endif()
+ endif()
+ endif()
+ endif()
+
+ # add some cross compiler tests, for now only with makefile based generators
+ if(CMAKE_GENERATOR MATCHES "Makefiles")
+
+ # if sdcc is found, build the SimpleCOnly project with sdcc
+ find_program(SDCC_EXECUTABLE sdcc)
+ mark_as_advanced(SDCC_EXECUTABLE)
+ if(SDCC_EXECUTABLE)
+ add_test(SimpleCOnly_sdcc ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/SimpleCOnly"
+ "${CMake_BINARY_DIR}/Tests/SimpleCOnly_sdcc"
+ ${build_generator_args}
+ --build-project SimpleC
+ --build-options
+ "-DCMAKE_SYSTEM_NAME=Generic"
+ "-DCMAKE_C_COMPILER=${SDCC_EXECUTABLE}")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/SimpleCOnly_sdcc")
+ endif()
+
+ # If a Linux -> MinGW cross compiler is found then try it
+ find_program(MINGW_CC_LINUX2WIN_EXECUTABLE i586-mingw32msvc-gcc)
+ find_program(MINGW_CXX_LINUX2WIN_EXECUTABLE i586-mingw32msvc-g++)
+ find_program(MINGW_RC_LINUX2WIN_EXECUTABLE i586-mingw32msvc-windres)
+ mark_as_advanced(MINGW_CC_LINUX2WIN_EXECUTABLE MINGW_CXX_LINUX2WIN_EXECUTABLE MINGW_RC_LINUX2WIN_EXECUTABLE)
+ if(MINGW_CC_LINUX2WIN_EXECUTABLE AND MINGW_CXX_LINUX2WIN_EXECUTABLE AND MINGW_RC_LINUX2WIN_EXECUTABLE)
+ add_test(Simple_Mingw_Linux2Win ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Simple"
+ "${CMake_BINARY_DIR}/Tests/Simple_Mingw_Linux2Win"
+ ${build_generator_args}
+ --build-project Simple
+ --build-options
+ "-DCMAKE_SYSTEM_NAME=Windows"
+ "-DCMAKE_C_COMPILER=${MINGW_CC_LINUX2WIN_EXECUTABLE}"
+ "-DCMAKE_CXX_COMPILER=${MINGW_CXX_LINUX2WIN_EXECUTABLE}"
+ "-DCMAKE_RC_COMPILER=${MINGW_RC_LINUX2WIN_EXECUTABLE}"
+ )
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Simple_Mingw_Linux2Win")
+ endif()
+ endif()
+
+ if(CMAKE_TEST_PROJECT_CSE_DIR)
+ set(script "${CMAKE_TEST_PROJECT_CSE_DIR}/BuildProjectCSE.cmake")
+ if(NOT EXISTS "${script}")
+ set(script "${CMAKE_TEST_PROJECT_CSE_DIR}/cse_build.cmake")
+ endif()
+ if(NOT EXISTS "${script}")
+ message("warning: CMAKE_TEST_PROJECT_CSE_DIR set, but no build script found...")
+ endif()
+
+ add_test(BuildCSE ${CMAKE_CTEST_COMMAND} -V -S "${script}")
+ set_tests_properties(BuildCSE PROPERTIES TIMEOUT 5400)
+ endif()
+
+ if(CMAKE_TEST_PLPLOT_DIR)
+ add_test(plplot ${CMAKE_CTEST_COMMAND} -V -S ${CMAKE_TEST_PLPLOT_DIR}/../../EasyDashboardScripts/plplot.cmake )
+ set_tests_properties ( plplot PROPERTIES TIMEOUT 5400)
+ endif()
+
+ if(CMAKE_TEST_CHICKEN_DIR)
+ add_test(Chicken ${CMAKE_CTEST_COMMAND} -V -S ${CMAKE_TEST_CHICKEN_DIR}/../../EasyDashboardScripts/Chicken.cmake )
+ set_tests_properties ( Chicken PROPERTIES TIMEOUT 5400)
+ endif()
+
+ if(CMAKE_TEST_KDELIBS_ALPHA_1_DIR)
+ add_test(KDELibsAlpha1 ${CMAKE_CTEST_COMMAND} -V -S ${CMAKE_TEST_KDELIBS_ALPHA_1_DIR}/../../EasyDashboardScripts/kdelibs.cmake )
+ set_tests_properties ( KDELibsAlpha1 PROPERTIES TIMEOUT 5400)
+ endif()
+
+ # Define a set of "contract" tests, each activated by a cache entry
+ # named "CMake_TEST_CONTRACT_<project>". For each Contract test,
+ # the project should provide a directory with a CMakeLists.txt file
+ # that uses ExternalProject to download and configure the project.
+ # The directory should also contain a Configure.cmake file that
+ # sets "CMake_TEST_CONTRACT_<project>_<var>" variables to configure
+ # the code below.
+ foreach(project
+ PLplot
+ Trilinos
+ VTK
+ )
+ if(CMake_TEST_CONTRACT_${project})
+ include(Contracts/${project}/Configure.cmake)
+ ADD_TEST_MACRO(Contracts.${project} ${CMake_TEST_CONTRACT_${project}_RUN_TEST})
+ # The external projects may take a long time to build.
+ if(DEFINED CMake_TEST_CONTRACT_${project}_TIMEOUT)
+ set(timeout ${CMake_TEST_CONTRACT_${project}_TIMEOUT})
+ elseif(CMake_TEST_CONTRACT_DEFAULT_TIMEOUT)
+ set(timeout ${CMake_TEST_CONTRACT_DEFAULT_TIMEOUT})
+ else()
+ set(timeout 21600)
+ endif()
+ set_property(TEST Contracts.${project} PROPERTY TIMEOUT "${timeout}")
+ endif()
+ endforeach()
+
+ if(TEST_CompileCommandOutput)
+ set(CompileCommandOutput_BUILD_OPTIONS
+ -DMAKE_SUPPORTS_SPACES=${MAKE_SUPPORTS_SPACES})
+ ADD_TEST_MACRO(CompileCommandOutput
+ "${CMake_BINARY_DIR}/Tests/CMakeLib/runcompilecommands")
+ endif()
+
+ add_test(IncludeDirectories ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/IncludeDirectories"
+ "${CMake_BINARY_DIR}/Tests/IncludeDirectories"
+ --build-two-config
+ ${build_generator_args}
+ --build-project IncludeDirectories
+ --build-options
+ -DMAKE_SUPPORTS_SPACES=${MAKE_SUPPORTS_SPACES}
+ --test-command IncludeDirectories)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/IncludeDirectories")
+
+ if(CMAKE_GENERATOR MATCHES "^((Unix|MSYS) Makefiles|Ninja)$" AND
+ ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.4)
+ OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ OR (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")))
+ add_test(IncludeDirectoriesCPATH ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/IncludeDirectoriesCPATH"
+ "${CMake_BINARY_DIR}/Tests/IncludeDirectoriesCPATH"
+ --build-two-config
+ ${build_generator_args}
+ --build-project IncludeDirectoriesCPATH)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/IncludeDirectoriesCPATH")
+ set_tests_properties(IncludeDirectoriesCPATH
+ PROPERTIES
+ ENVIRONMENT "CPATH=${CMAKE_CURRENT_SOURCE_DIR}/IncludeDirectoriesCPATH/viacpath")
+ endif()
+
+ add_test(InterfaceLinkLibraries ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/InterfaceLinkLibraries"
+ "${CMake_BINARY_DIR}/Tests/InterfaceLinkLibraries"
+ --build-two-config
+ ${build_generator_args}
+ --build-project InterfaceLinkLibraries
+ --test-command InterfaceLinkLibraries)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/InterfaceLinkLibraries")
+
+ if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ add_subdirectory(CMakeTests)
+ endif()
+
+ if(BUILD_QtDialog AND CMake_TEST_GUI AND NOT CMake_TEST_EXTERNAL_CMAKE)
+ add_subdirectory(CMakeGUI)
+ endif()
+
+ # If this is not an in-source build, provide a target to wipe out
+ # all the test build directories. This must come at the end after
+ # all the above logic has finished adding to TEST_BUILD_DIRS
+ if(NOT EXISTS "${CMake_BINARY_DIR}/CMakeLists.txt")
+ configure_file(${CMake_SOURCE_DIR}/Tests/test_clean.cmake.in
+ ${CMake_BINARY_DIR}/Tests/test_clean.cmake @ONLY)
+ add_custom_target(test_clean
+ COMMAND ${CMAKE_COMMAND} -P ${CMake_BINARY_DIR}/Tests/test_clean.cmake
+ COMMENT "Removing test build directories."
+ )
+ endif()
+endif()
diff --git a/Tests/CMakeOnly/AllFindModules/CMakeLists.txt b/Tests/CMakeOnly/AllFindModules/CMakeLists.txt
new file mode 100644
index 0000000..49a4041
--- /dev/null
+++ b/Tests/CMakeOnly/AllFindModules/CMakeLists.txt
@@ -0,0 +1,94 @@
+cmake_minimum_required(VERSION 2.8.4) # new enough for CMP0017
+project(AllFindModules)
+
+# Avoid ctest truncation of output
+message(STATUS "CTEST_FULL_OUTPUT")
+
+set(ORIGINAL_MODULE_PATH "${CMAKE_MODULE_PATH}")
+
+file(GLOB FIND_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../Modules/Find*.cmake" )
+
+macro(do_find MODULE_NAME)
+ message(STATUS " Checking Find${MODULE_NAME}")
+ find_package(${MODULE_NAME})
+ set(CMAKE_MODULE_PATH "${ORIGINAL_MODULE_PATH}")
+endmacro()
+
+# It is only possible to use either Qt3 or Qt4 in one project.
+# Since FindQt will complain if both are found we explicitly request Qt4 here
+# and filter out FindQt3. FindKDE3 also depends on Qt3 and
+# is therefore also blocked
+set(DESIRED_QT_VERSION 4)
+set(NO_QT4_MODULES "Qt3" "KDE3")
+
+# ignore everything that has it's own test in Tests/Module/
+file(GLOB OWN_TEST_MODULES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/../../Module/" "${CMAKE_CURRENT_SOURCE_DIR}/../../Module/Find*")
+foreach(FIND_MODULE IN LISTS OWN_TEST_MODULES)
+ string(REGEX REPLACE "^Find" "" _MOD_NAME "${FIND_MODULE}")
+ list(APPEND NO_FIND_MODULES "${_MOD_NAME}")
+endforeach()
+
+# These modules are named Find*.cmake, but are nothing that works in
+# find_package().
+list(APPEND NO_FIND_MODULES "PackageHandleStandardArgs" "PackageMessage")
+
+foreach(FIND_MODULE IN LISTS FIND_MODULES)
+ string(REGEX REPLACE ".*/Find(.*)\\.cmake$" "\\1" MODULE_NAME "${FIND_MODULE}")
+
+ list(FIND NO_QT4_MODULES ${MODULE_NAME} NO_QT4_INDEX)
+ list(FIND NO_FIND_MODULES ${MODULE_NAME} NO_FIND_INDEX)
+ if (NO_QT4_INDEX EQUAL -1 AND NO_FIND_INDEX EQUAL -1)
+ do_find(${MODULE_NAME})
+ endif ()
+
+endforeach()
+
+# Qt4 is not present, so we can check Qt3
+if (NOT QT4_FOUND)
+ set(DESIRED_QT_VERSION 3)
+ foreach(FIND_MODULE ${NO_QT4_MODULES} "Qt")
+ do_find(${FIND_MODULE})
+ endforeach()
+endif ()
+
+macro(check_version_string MODULE_NAME VERSION_VAR)
+ string(FIND " ${CMake_TEST_CMakeOnly.AllFindModules_NO_VERSION} " " ${MODULE_NAME} " _exclude_pos)
+ if (NOT _exclude_pos EQUAL -1)
+ message(STATUS "excluding check of ${VERSION_VAR}='${${VERSION_VAR}}' due to local configuration")
+ elseif (${MODULE_NAME}_FOUND)
+ if (DEFINED ${VERSION_VAR})
+ message(STATUS "${VERSION_VAR}='${${VERSION_VAR}}'")
+ if (NOT ${VERSION_VAR} MATCHES "^[0-9]")
+ message(SEND_ERROR "unexpected: ${VERSION_VAR} does not begin with a decimal digit")
+ endif()
+ if ("${${VERSION_VAR}}" STREQUAL "")
+ message(SEND_ERROR "unexpected: ${VERSION_VAR} is empty")
+ endif()
+ if (${VERSION_VAR} VERSION_EQUAL 0)
+ message(SEND_ERROR "unexpected: ${VERSION_VAR} is VERSION_EQUAL 0")
+ endif()
+ if (NOT ${VERSION_VAR} VERSION_GREATER 0)
+ message(SEND_ERROR "unexpected: ${VERSION_VAR} is NOT VERSION_GREATER 0")
+ endif()
+ else()
+ message(SEND_ERROR "${MODULE_NAME}_FOUND is set but version number variable ${VERSION_VAR} is NOT DEFINED")
+ endif()
+ endif ()
+endmacro()
+
+# If any of these modules reported that it was found a version number should have been
+# reported.
+
+foreach(VTEST ALSA ARMADILLO BZIP2 CUPS CURL EXPAT FREETYPE GETTEXT GIT HG
+ HSPELL ICOTOOL JASPER LIBLZMA LIBXML2 LIBXSLT LTTNGUST PERL PKG_CONFIG
+ PostgreSQL TIFF ZLIB)
+ check_version_string(${VTEST} ${VTEST}_VERSION_STRING)
+endforeach()
+
+foreach(VTEST BISON Boost CUDA DOXYGEN FLEX GIF GTK2
+ HDF5 JPEG LibArchive OPENSCENEGRAPH Ruby RUBY SWIG Protobuf)
+ check_version_string(${VTEST} ${VTEST}_VERSION)
+endforeach()
+
+check_version_string(PYTHONINTERP PYTHON_VERSION_STRING)
+check_version_string(SUBVERSION Subversion_VERSION_SVN)
diff --git a/Tests/CMakeOnly/CMakeLists.txt b/Tests/CMakeOnly/CMakeLists.txt
new file mode 100644
index 0000000..a41b44e
--- /dev/null
+++ b/Tests/CMakeOnly/CMakeLists.txt
@@ -0,0 +1,107 @@
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Test.cmake.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake @ONLY)
+
+macro(add_CMakeOnly_test test)
+ add_test(CMakeOnly.${test} ${CMAKE_CMAKE_COMMAND}
+ -DTEST=${test}
+ -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
+ )
+endmacro()
+
+add_CMakeOnly_test(LinkInterfaceLoop)
+# If a bug is introduced in CMake that causes an infinite loop while
+# analyzing LinkInterfaceLoop then don't let the test run too long.
+# Use an option to customize it so that the timeout can be extended
+# on busy machines.
+if(NOT DEFINED CMake_TEST_CMakeOnly.LinkInterfaceLoop_TIMEOUT)
+ set(CMake_TEST_CMakeOnly.LinkInterfaceLoop_TIMEOUT 90)
+endif()
+set_property(TEST CMakeOnly.LinkInterfaceLoop PROPERTY TIMEOUT ${CMake_TEST_CMakeOnly.LinkInterfaceLoop_TIMEOUT})
+
+add_CMakeOnly_test(CheckSymbolExists)
+
+add_CMakeOnly_test(CheckCXXSymbolExists)
+
+add_CMakeOnly_test(CheckCXXCompilerFlag)
+
+add_CMakeOnly_test(CheckLanguage)
+
+add_CMakeOnly_test(CheckStructHasMember)
+
+add_CMakeOnly_test(CompilerIdC)
+add_CMakeOnly_test(CompilerIdCXX)
+
+if (APPLE AND CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
+ add_CMakeOnly_test(CompilerIdOBJC)
+ add_CMakeOnly_test(CheckOBJCCompilerFlag)
+ add_CMakeOnly_test(CompilerIdOBJCXX)
+ add_CMakeOnly_test(CheckOBJCXXCompilerFlag)
+endif()
+
+if(CMake_TEST_CUDA)
+ add_CMakeOnly_test(CompilerIdCUDA)
+endif()
+
+
+if(CMAKE_Fortran_COMPILER)
+ add_CMakeOnly_test(CompilerIdFortran)
+endif()
+if(CMAKE_GENERATOR MATCHES "Visual Studio ([^9]|9[0-9])")
+ add_CMakeOnly_test(CompilerIdCSharp)
+endif()
+
+add_test(CMakeOnly.AllFindModules ${CMAKE_CMAKE_COMMAND}
+ -DTEST=AllFindModules
+ -DCMAKE_ARGS=-DCMake_TEST_CMakeOnly.AllFindModules_NO_VERSION=${CMake_TEST_CMakeOnly.AllFindModules_NO_VERSION}
+ -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
+ )
+
+add_CMakeOnly_test(SelectLibraryConfigurations)
+
+add_CMakeOnly_test(TargetScope)
+
+add_CMakeOnly_test(find_library)
+add_CMakeOnly_test(find_path)
+
+add_test(CMakeOnly.ProjectInclude ${CMAKE_CMAKE_COMMAND}
+ -DTEST=ProjectInclude
+ -DCMAKE_ARGS=-DCMAKE_PROJECT_ProjectInclude_INCLUDE=${CMAKE_CURRENT_SOURCE_DIR}/ProjectInclude/include.cmake
+ -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
+ )
+
+add_test(CMakeOnly.ProjectIncludeAny ${CMAKE_CMAKE_COMMAND}
+ -DTEST=ProjectIncludeAny
+ -DCMAKE_ARGS=-DCMAKE_PROJECT_INCLUDE=${CMAKE_CURRENT_SOURCE_DIR}/ProjectInclude/include.cmake
+ -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
+ )
+
+add_test(CMakeOnly.ProjectIncludeBefore ${CMAKE_CMAKE_COMMAND}
+ -DTEST=ProjectIncludeBefore
+ -DCMAKE_ARGS=-DCMAKE_PROJECT_ProjectInclude_INCLUDE_BEFORE=${CMAKE_CURRENT_SOURCE_DIR}/ProjectIncludeBefore/include.cmake
+ -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
+ )
+
+add_test(CMakeOnly.ProjectIncludeBeforeAny ${CMAKE_CMAKE_COMMAND}
+ -DTEST=ProjectIncludeBeforeAny
+ -DCMAKE_ARGS=-DCMAKE_PROJECT_INCLUDE_BEFORE=${CMAKE_CURRENT_SOURCE_DIR}/ProjectIncludeBefore/include.cmake
+ -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
+ )
+
+include(CMakeParseArguments)
+
+function(add_major_test module)
+ cmake_parse_arguments(MAJOR_TEST "NOLANG" "VERSION_VAR" "VERSIONS" ${ARGN})
+ foreach (_version IN LISTS MAJOR_TEST_VERSIONS)
+ add_test(CMakeOnly.MajorVersionSelection-${module}_${_version}
+ ${CMAKE_CMAKE_COMMAND}
+ -DTEST=MajorVersionSelection-${module}_${_version}
+ -DTEST_SOURCE=MajorVersionSelection
+ "-DCMAKE_ARGS=-DMAJOR_TEST_MODULE=${module};-DMAJOR_TEST_VERSION=${_version};-DMAJOR_TEST_NO_LANGUAGES=${MAJOR_TEST_NOLANG};-DMAJOR_TEST_VERSION_VAR=${MAJOR_TEST_VERSION_VAR}"
+ -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
+ )
+ endforeach ()
+endfunction()
+
+add_major_test(PythonLibs VERSIONS 2 3 VERSION_VAR PYTHONLIBS_VERSION_STRING)
+add_major_test(PythonInterp NOLANG VERSIONS 3 VERSION_VAR PYTHON_VERSION_STRING)
+add_major_test(Qt VERSIONS 3 4 VERSION_VAR QT_VERSION_STRING)
diff --git a/Tests/CMakeOnly/CheckCXXCompilerFlag/CMakeLists.txt b/Tests/CMakeOnly/CheckCXXCompilerFlag/CMakeLists.txt
new file mode 100644
index 0000000..7ca68ec
--- /dev/null
+++ b/Tests/CMakeOnly/CheckCXXCompilerFlag/CMakeLists.txt
@@ -0,0 +1,65 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(CheckCXXCompilerFlag)
+
+message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+macro(TEST_FAIL value msg)
+ if (${value})
+ message (SEND_ERROR "Test fail:" ${msg} ${Out} )
+ endif ()
+endmacro()
+
+macro(TEST_PASS value msg)
+ if (NOT ${value})
+ message (SEND_ERROR "Test fail:" ${msg} ${Out} )
+ endif ()
+endmacro()
+
+if(CMAKE_COMPILER_IS_GNUCXX)
+ exec_program(${CMAKE_C_COMPILER} ARGS --version OUTPUT_VARIABLE _gcc_version_info)
+ string (REGEX MATCH "[345]\\.[0-9]\\.[0-9]" _gcc_version "${_gcc_version_info}")
+ # gcc on mac just reports: "gcc (GCC) 3.3 20030304 ..." without the
+ # patch level, handle this here:
+ if(NOT _gcc_version)
+ string (REGEX REPLACE ".*\\(GCC\\).* ([34]\\.[0-9]) .*" "\\1.0" _gcc_version "${_gcc_version_info}")
+ endif()
+endif()
+
+if(CMAKE_CXX_COMPILER_ID MATCHES Clang)
+ exec_program(${CMAKE_CXX_COMPILER} ARGS --version OUTPUT_VARIABLE _clang_version_info)
+ string (REGEX REPLACE ".*version ([0-9]\\.[0-9]).*" "\\1" _clang_version "${_clang_version_info}")
+endif()
+
+if(CMAKE_CXX_COMPILER_ID MATCHES Intel)
+ exec_program(${CMAKE_CXX_COMPILER} ARGS -V OUTPUT_VARIABLE _intel_version_info)
+ string (REGEX REPLACE ".*Version ([0-9]+(\\.[0-9]+)+).*" "\\1" _intel_version "${_intel_version_info}")
+endif()
+
+message("Platform:\n WIN32: ${WIN32}\n UNIX: ${UNIX}\n APPLE: ${APPLE}\n MINGW: ${MINGW}\n CYGWIN: ${CYGWIN}\n"
+ " MSVC: ${MSVC}\n MSVC60: ${MSVC60}\n MSVC70: ${MSVC70}\n MSVC71: ${MSVC71}\n MSVC80: ${MSVC80}\n MSVC90: ${MSVC90}\n MSVC10: ${MSVC10}\n"
+ " GCC: ${_gcc_version}\n"
+ " Clang: ${_clang_version}\n"
+ " Intel: ${_intel_version}\n"
+)
+
+include(CheckCXXCompilerFlag)
+
+check_cxx_compiler_flag(-fvisibility=hidden HAS_HIDDEN_VISIBILITY)
+
+message("HAS_HIDDEN_VISIBILITY: ${HAS_HIDDEN_VISIBILITY}\n\nCOMPILE OUTPUT:\n${OUTPUT}")
+
+if(CMAKE_COMPILER_IS_GNUCXX)
+ if(NOT WIN32)
+# test_pass(HAS_HIDDEN_VISIBILITY "GCC should support hidden visibility, but does not.")
+ endif()
+else()
+ message("Unhandled Platform")
+endif()
+
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ check_cxx_compiler_flag("-x c++" HAVE_X_CXX)
+ if(NOT HAVE_X_CXX)
+ message(FATAL_ERROR "${CMAKE_CXX_COMPILER_ID} compiler flag '-x c++' check failed")
+ endif()
+endif()
diff --git a/Tests/CMakeOnly/CheckCXXSymbolExists/CMakeLists.txt b/Tests/CMakeOnly/CheckCXXSymbolExists/CMakeLists.txt
new file mode 100644
index 0000000..2784e3b
--- /dev/null
+++ b/Tests/CMakeOnly/CheckCXXSymbolExists/CMakeLists.txt
@@ -0,0 +1,76 @@
+# This test will verify if CheckCXXSymbolExists only report symbols available
+# for linking that really are. You can find some documentation on this in
+# bug 11333 where we found out that gcc would optimize out the actual
+# reference to the symbol, so symbols that are in fact _not_ available in the
+# given libraries (but seen in header) were reported as present.
+#
+# If you change this test do not forget to change the CheckSymbolExists
+# test, too.
+
+project(CheckCXXSymbolExists CXX)
+
+cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR)
+
+set(CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/../CheckSymbolExists")
+
+include(CheckCXXSymbolExists)
+
+foreach(_config_type Release RelWithDebInfo MinSizeRel Debug)
+ set(CMAKE_TRY_COMPILE_CONFIGURATION ${_config_type})
+ unset(CSE_RESULT_${_config_type} CACHE)
+ message(STATUS "Testing configuration ${_config_type}")
+ check_cxx_symbol_exists(non_existent_function_for_symbol_test "cm_cse.h" CSE_RESULT_${_config_type})
+
+ if (CSE_RESULT_${_config_type})
+ message(SEND_ERROR "CheckCXXSymbolExists reported a nonexistent symbol as existing in configuration ${_config_type}")
+ endif ()
+endforeach()
+
+set(CMAKE_TRY_COMPILE_CONFIGURATION ${CMAKE_BUILD_TYPE})
+unset(CSE_RESULT_ERRNO_CERRNO CACHE)
+
+message(STATUS "Checking <cerrno>")
+
+check_cxx_symbol_exists(errno "cerrno" CSE_RESULT_ERRNO_CERRNO)
+
+if (NOT CSE_RESULT_ERRNO_CERRNO)
+ unset(CSE_RESULT_ERRNO_ERRNOH CACHE)
+
+ message(STATUS "Checking <errno.h>")
+
+ check_cxx_symbol_exists(errno "errno.h" CSE_RESULT_ERRNO_ERRNOH)
+
+ if (NOT CSE_RESULT_ERRNO_ERRNOH)
+ message(SEND_ERROR "CheckCXXSymbolExists did not find errno in <cerrno> and <errno.h>")
+ else ()
+ message(STATUS "errno found in <errno.h>")
+ endif ()
+else ()
+ message(STATUS "errno found in <cerrno>")
+endif ()
+
+check_cxx_symbol_exists("std::fopen" "cstdio" CSE_RESULT_FOPEN)
+if (NOT CSE_RESULT_FOPEN)
+ if(NOT ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.10))
+ message(SEND_ERROR "CheckCXXSymbolExists did not find std::fopen in <cstdio>")
+ endif()
+else()
+ message(STATUS "std::fopen found in <cstdio>")
+endif()
+
+if (CMAKE_COMPILER_IS_GNUCXX)
+ string(APPEND CMAKE_CXX_FLAGS " -O3")
+ unset(CSE_RESULT_O3 CACHE)
+ message(STATUS "Testing with optimization -O3")
+
+ check_cxx_symbol_exists(non_existent_function_for_symbol_test "cm_cse.h" CSE_RESULT_O3)
+
+ if (CSE_RESULT_O3)
+ message(SEND_ERROR "CheckCXXSymbolExists reported a nonexistent symbol as existing with optimization -O3")
+ endif ()
+endif ()
+
+check_cxx_symbol_exists("std::non_existent_function_for_symbol_test<int*>" "algorithm" CSE_RESULT_NON_SYMBOL)
+if (CSE_RESULT_NON_SYMBOL)
+ message(SEND_ERROR "CheckCXXSymbolExists reported a nonexistent symbol.")
+endif()
diff --git a/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt b/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt
new file mode 100644
index 0000000..2e5d8d3
--- /dev/null
+++ b/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(CheckLanguage NONE)
+include(CheckLanguage)
+
+set(langs )
+set(expect_C 1)
+set(expect_CXX 1)
+
+if(APPLE)
+ set(expect_OBJC 1)
+ set(expect_OBJCXX 1)
+endif()
+unset(expect_Fortran)
+set(expect_NoSuchLanguage 0)
+
+set(LANGUAGES C CXX Fortran CUDA NoSuchLanguage)
+if(APPLE)
+ list(APPEND LANGUAGES OBJC OBJCXX)
+endif()
+
+foreach(test_lang ${LANGUAGES})
+ check_language(${test_lang})
+ if(NOT DEFINED CMAKE_${test_lang}_COMPILER)
+ message(FATAL_ERROR "check_language(${test_lang}) did not set result")
+ endif()
+ if(DEFINED expect_${test_lang})
+ if(expect_${test_lang} AND NOT CMAKE_${test_lang}_COMPILER)
+ message(FATAL_ERROR "check_language(${test_lang}) should not fail!")
+ elseif(NOT expect_${test_lang} AND CMAKE_${test_lang}_COMPILER)
+ message(FATAL_ERROR "check_language(${test_lang}) should not succeed!")
+ endif()
+ endif()
+endforeach()
diff --git a/Tests/CMakeOnly/CheckOBJCCompilerFlag/CMakeLists.txt b/Tests/CMakeOnly/CheckOBJCCompilerFlag/CMakeLists.txt
new file mode 100644
index 0000000..a714b73
--- /dev/null
+++ b/Tests/CMakeOnly/CheckOBJCCompilerFlag/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.16)
+project(CheckOBJCCompilerFlag OBJC)
+include(CheckOBJCCompilerFlag)
+check_objc_compiler_flag(-DFOO HAS_COMPILER_FLAG)
+if(NOT HAS_COMPILER_FLAG)
+ message(SEND_ERROR "Test fail: HAS_COMPILER_FLAG: ${COMPILER_FLAG}")
+endif()
diff --git a/Tests/CMakeOnly/CheckOBJCXXCompilerFlag/CMakeLists.txt b/Tests/CMakeOnly/CheckOBJCXXCompilerFlag/CMakeLists.txt
new file mode 100644
index 0000000..d09f0b9
--- /dev/null
+++ b/Tests/CMakeOnly/CheckOBJCXXCompilerFlag/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.16)
+project(CheckOBJCXXCompilerFlag OBJCXX)
+include(CheckOBJCXXCompilerFlag)
+check_objcxx_compiler_flag(-DFOO HAS_COMPILER_FLAG)
+if(NOT HAS_COMPILER_FLAG)
+ message(SEND_ERROR "Test fail: HAS_COMPILER_FLAG: ${COMPILER_FLAG}")
+endif()
diff --git a/Tests/CMakeOnly/CheckStructHasMember/CMakeLists.txt b/Tests/CMakeOnly/CheckStructHasMember/CMakeLists.txt
new file mode 100644
index 0000000..4cbccd3
--- /dev/null
+++ b/Tests/CMakeOnly/CheckStructHasMember/CMakeLists.txt
@@ -0,0 +1,93 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(CheckStructHasMember)
+
+set(CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}")
+
+include(CheckStructHasMember)
+
+foreach(_config_type Release RelWithDebInfo Debug)
+ set(CMAKE_TRY_COMPILE_CONFIGURATION ${_config_type})
+ unset(CSHM_RESULT_S1_${_config_type} CACHE)
+ unset(CSHM_RESULT_S2_${_config_type} CACHE)
+ unset(CSHM_RESULT_S3_${_config_type} CACHE)
+ message(STATUS "Testing configuration ${_config_type}")
+
+ check_struct_has_member("struct non_existent_struct" "foo" "cm_cshm.h" CSHM_RESULT_S1_${_config_type})
+ check_struct_has_member("struct struct_with_member" "non_existent_member" "cm_cshm.h" CSHM_RESULT_S2_${_config_type})
+ check_struct_has_member("struct struct_with_member" "member" "cm_cshm.h" CSHM_RESULT_S3_${_config_type})
+
+ if(CSHM_RESULT_S1_${_config_type} OR CSHM_RESULT_S2_${_config_type})
+ message(SEND_ERROR "CheckStructHasMember reported a nonexistent member as existing in configuration ${_config_type}")
+ endif()
+
+ if(NOT CSHM_RESULT_S3_${_config_type})
+ message(SEND_ERROR "CheckStructHasMember did not report an existent member as existing in configuration ${_config_type}")
+ endif()
+endforeach()
+
+foreach(_config_type Release RelWithDebInfo Debug)
+ set(CMAKE_TRY_COMPILE_CONFIGURATION ${_config_type})
+ unset(CSHM_RESULT_S1_${_config_type}_C CACHE)
+ unset(CSHM_RESULT_S2_${_config_type}_C CACHE)
+ unset(CSHM_RESULT_S3_${_config_type}_C CACHE)
+ message(STATUS "Testing configuration ${_config_type}")
+
+ check_struct_has_member("struct non_existent_struct" "foo" "cm_cshm.h" CSHM_RESULT_S1_${_config_type}_C LANGUAGE C)
+ check_struct_has_member("struct struct_with_member" "non_existent_member" "cm_cshm.h" CSHM_RESULT_S2_${_config_type}_C LANGUAGE C)
+ check_struct_has_member("struct struct_with_member" "member" "cm_cshm.h" CSHM_RESULT_S3_${_config_type}_C LANGUAGE C)
+
+ if(CSHM_RESULT_S1_${_config_type}_C OR CSHM_RESULT_S2_${_config_type}_C)
+ message(SEND_ERROR "CheckStructHasMember reported a nonexistent member as existing in configuration ${_config_type}")
+ endif()
+
+ if(NOT CSHM_RESULT_S3_${_config_type}_C)
+ message(SEND_ERROR "CheckStructHasMember did not report an existent member as existing in configuration ${_config_type}")
+ endif()
+endforeach()
+
+foreach(_config_type Release RelWithDebInfo Debug)
+ set(CMAKE_TRY_COMPILE_CONFIGURATION ${_config_type})
+ unset(CSHM_RESULT_S1_${_config_type}_CXX CACHE)
+ unset(CSHM_RESULT_S2_${_config_type}_CXX CACHE)
+ unset(CSHM_RESULT_S3_${_config_type}_CXX CACHE)
+ unset(CSHM_RESULT_C1_${_config_type}_CXX CACHE)
+ unset(CSHM_RESULT_C2_${_config_type}_CXX CACHE)
+ unset(CSHM_RESULT_C3_${_config_type}_CXX CACHE)
+
+ message(STATUS "Testing configuration ${_config_type}")
+
+ check_struct_has_member("non_existent_struct" "foo" "cm_cshm.h" CSHM_RESULT_S1_${_config_type}_CXX LANGUAGE CXX)
+ check_struct_has_member("struct_with_non_existent_members" "non_existent_member" "cm_cshm.h" CSHM_RESULT_S2_${_config_type}_CXX LANGUAGE CXX)
+ check_struct_has_member("struct struct_with_member" "member" "cm_cshm.h" CSHM_RESULT_S3_${_config_type}_CXX LANGUAGE CXX)
+ check_struct_has_member("ns::non_existent_class" "foo" "cm_cshm.hxx" CSHM_RESULT_C1_${_config_type}_CXX LANGUAGE CXX)
+ check_struct_has_member("ns::class_with_non_existent_members" "foo" "cm_cshm.hxx" CSHM_RESULT_C2_${_config_type}_CXX LANGUAGE CXX)
+ check_struct_has_member("ns::class_with_member" "foo" "cm_cshm.hxx" CSHM_RESULT_C3_${_config_type}_CXX LANGUAGE CXX)
+
+ if(CSHM_RESULT_S1_${_config_type}_CXX OR CSHM_RESULT_S2_${_config_type}_CXX OR CSHM_RESULT_C1_${_config_type}_CXX OR CSHM_RESULT_C2_${_config_type}_CXX)
+ message(SEND_ERROR "CheckStructHasMember reported a nonexistent member as existing in configuration ${_config_type}")
+ endif()
+
+ if(NOT CSHM_RESULT_S3_${_config_type}_CXX OR NOT CSHM_RESULT_C3_${_config_type}_CXX)
+ message(SEND_ERROR "CheckStructHasMember did not report an existent member as existing in configuration ${_config_type}")
+ endif()
+endforeach()
+
+
+set(CMAKE_TRY_COMPILE_CONFIGURATION ${CMAKE_BUILD_TYPE})
+
+if (CMAKE_COMPILER_IS_GNUCC)
+ string(APPEND CMAKE_C_FLAGS " -O3")
+ unset(CSHM_RESULT_O3 CACHE)
+ unset(CSHM_RESULT_O3_C CACHE)
+ unset(CSHM_RESULT_O3_CXX CACHE)
+ message(STATUS "Testing with optimization -O3")
+
+ check_struct_has_member("class_with_non_existent_members" foo "cm_cshm.h" CSHM_RESULT_O3)
+ check_struct_has_member("class_with_non_existent_members" foo "cm_cshm.h" CSHM_RESULT_O3_C LANGUAGE C)
+ check_struct_has_member("class_with_non_existent_members" foo "cm_cshm.h" CSHM_RESULT_O3_CXX LANGUAGE CXX)
+
+ if (CSE_RESULT_O3 OR CSHM_RESULT_O3_C OR CSHM_RESULT_O3_CXX)
+ message(SEND_ERROR "CheckSymbolExists reported a nonexistent symbol as existing with optimization -O3")
+ endif ()
+endif ()
diff --git a/Tests/CMakeOnly/CheckStructHasMember/cm_cshm.h b/Tests/CMakeOnly/CheckStructHasMember/cm_cshm.h
new file mode 100644
index 0000000..ad21c13
--- /dev/null
+++ b/Tests/CMakeOnly/CheckStructHasMember/cm_cshm.h
@@ -0,0 +1,10 @@
+#ifndef _CSHM_DUMMY_H
+#define _CSHM_DUMMY_H
+
+struct non_existent_struct;
+struct struct_with_member
+{
+ int member;
+};
+
+#endif
diff --git a/Tests/CMakeOnly/CheckStructHasMember/cm_cshm.hxx b/Tests/CMakeOnly/CheckStructHasMember/cm_cshm.hxx
new file mode 100644
index 0000000..f3e9326
--- /dev/null
+++ b/Tests/CMakeOnly/CheckStructHasMember/cm_cshm.hxx
@@ -0,0 +1,17 @@
+#ifndef _CSHM_DUMMY_HXX
+#define _CSHM_DUMMY_HXX
+
+namespace ns {
+
+class non_existent_class;
+class class_with_non_existent_members
+{
+};
+class class_with_member
+{
+public:
+ int foo;
+};
+}
+
+#endif
diff --git a/Tests/CMakeOnly/CheckSymbolExists/CMakeLists.txt b/Tests/CMakeOnly/CheckSymbolExists/CMakeLists.txt
new file mode 100644
index 0000000..9a9bb2a
--- /dev/null
+++ b/Tests/CMakeOnly/CheckSymbolExists/CMakeLists.txt
@@ -0,0 +1,51 @@
+# This test will verify if CheckSymbolExists only report symbols available
+# for linking that really are. You can find some documentation on this in
+# bug 11333 where we found out that gcc would optimize out the actual
+# reference to the symbol, so symbols that are in fact _not_ available in the
+# given libraries (but seen in header) were reported as present.
+#
+# If you change this test do not forget to change the CheckCXXSymbolExists
+# test, too.
+
+project(CheckSymbolExists C)
+
+cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR)
+
+set(CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}")
+
+include(CheckSymbolExists)
+
+foreach(_config_type Release RelWithDebInfo MinSizeRel Debug)
+ set(CMAKE_TRY_COMPILE_CONFIGURATION ${_config_type})
+ unset(CSE_RESULT_${_config_type} CACHE)
+ message(STATUS "Testing configuration ${_config_type}")
+
+ check_symbol_exists(non_existent_function_for_symbol_test "cm_cse.h" CSE_RESULT_${_config_type})
+
+ if (CSE_RESULT_${_config_type})
+ message(SEND_ERROR "CheckSymbolExists reported a nonexistent symbol as existing in configuration ${_config_type}")
+ endif ()
+endforeach()
+
+set(CMAKE_TRY_COMPILE_CONFIGURATION ${CMAKE_BUILD_TYPE})
+unset(CSE_RESULT_ERRNO CACHE)
+
+check_symbol_exists(errno "errno.h" CSE_RESULT_ERRNO)
+
+if (NOT CSE_RESULT_ERRNO)
+ message(SEND_ERROR "CheckSymbolExists did not find errno in <errno.h>")
+else ()
+ message(STATUS "errno found as expected")
+endif ()
+
+if (CMAKE_COMPILER_IS_GNUCC)
+ string(APPEND CMAKE_C_FLAGS " -O3")
+ unset(CSE_RESULT_O3 CACHE)
+ message(STATUS "Testing with optimization -O3")
+
+ check_symbol_exists(non_existent_function_for_symbol_test "cm_cse.h" CSE_RESULT_O3)
+
+ if (CSE_RESULT_O3)
+ message(SEND_ERROR "CheckSymbolExists reported a nonexistent symbol as existing with optimization -O3")
+ endif ()
+endif ()
diff --git a/Tests/CMakeOnly/CheckSymbolExists/cm_cse.h b/Tests/CMakeOnly/CheckSymbolExists/cm_cse.h
new file mode 100644
index 0000000..4f41c76
--- /dev/null
+++ b/Tests/CMakeOnly/CheckSymbolExists/cm_cse.h
@@ -0,0 +1,6 @@
+#ifndef _CSE_DUMMY_H
+#define _CSE_DUMMY_H
+
+int non_existent_function_for_symbol_test();
+
+#endif
diff --git a/Tests/CMakeOnly/CompilerIdC/CMakeLists.txt b/Tests/CMakeOnly/CompilerIdC/CMakeLists.txt
new file mode 100644
index 0000000..6fea73e
--- /dev/null
+++ b/Tests/CMakeOnly/CompilerIdC/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.9)
+project(CompilerIdC C)
+
+foreach(v
+ CMAKE_C_COMPILER
+ CMAKE_C_COMPILER_ID
+ CMAKE_C_COMPILER_VERSION
+ )
+ if(${v})
+ message(STATUS "${v}=[${${v}}]")
+ else()
+ message(SEND_ERROR "${v} not set!")
+ endif()
+endforeach()
+
+# Version numbers may only contain numbers and periods.
+if(NOT CMAKE_C_COMPILER_VERSION MATCHES
+ "^([0-9]+)(\\.([0-9]+))?(\\.([0-9]+))?(\\.([0-9]+))?$"
+ )
+ message(SEND_ERROR "Compiler version is not numeric!")
+endif()
diff --git a/Tests/CMakeOnly/CompilerIdCSharp/CMakeLists.txt b/Tests/CMakeOnly/CompilerIdCSharp/CMakeLists.txt
new file mode 100644
index 0000000..6c07037
--- /dev/null
+++ b/Tests/CMakeOnly/CompilerIdCSharp/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.7.0)
+project(CompilerIdCSharp CSharp)
+
+foreach(v
+ CMAKE_CSharp_COMPILER
+ CMAKE_CSharp_COMPILER_ID
+ CMAKE_CSharp_COMPILER_VERSION
+ )
+ if(${v})
+ message(STATUS "${v}=[${${v}}]")
+ else()
+ message(SEND_ERROR "${v} not set!")
+ endif()
+endforeach()
+
+# Version numbers may only contain numbers and periods.
+if(NOT CMAKE_CSharp_COMPILER_VERSION MATCHES
+ "^([0-9]+)(\\.([0-9]+))?(\\.([0-9]+))?(\\.([0-9]+))?$"
+ )
+ message(SEND_ERROR "Compiler version is not numeric!")
+endif()
diff --git a/Tests/CMakeOnly/CompilerIdCUDA/CMakeLists.txt b/Tests/CMakeOnly/CompilerIdCUDA/CMakeLists.txt
new file mode 100644
index 0000000..da14000
--- /dev/null
+++ b/Tests/CMakeOnly/CompilerIdCUDA/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.18)
+project(CompilerIdCUDA CUDA)
+
+foreach(v
+ CMAKE_CUDA_COMPILER
+ CMAKE_CUDA_COMPILER_ID
+ CMAKE_CUDA_COMPILER_VERSION
+ )
+ if(${v})
+ message(STATUS "${v}=[${${v}}]")
+ else()
+ message(SEND_ERROR "${v} not set!")
+ endif()
+endforeach()
diff --git a/Tests/CMakeOnly/CompilerIdCXX/CMakeLists.txt b/Tests/CMakeOnly/CompilerIdCXX/CMakeLists.txt
new file mode 100644
index 0000000..05e6bb2
--- /dev/null
+++ b/Tests/CMakeOnly/CompilerIdCXX/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.9)
+project(CompilerIdCXX CXX)
+
+foreach(v
+ CMAKE_CXX_COMPILER
+ CMAKE_CXX_COMPILER_ID
+ CMAKE_CXX_COMPILER_VERSION
+ )
+ if(${v})
+ message(STATUS "${v}=[${${v}}]")
+ else()
+ message(SEND_ERROR "${v} not set!")
+ endif()
+endforeach()
+
+# Version numbers may only contain numbers and periods.
+if(NOT CMAKE_CXX_COMPILER_VERSION MATCHES
+ "^([0-9]+)(\\.([0-9]+))?(\\.([0-9]+))?(\\.([0-9]+))?$"
+ )
+ message(SEND_ERROR "Compiler version is not numeric!")
+endif()
diff --git a/Tests/CMakeOnly/CompilerIdFortran/CMakeLists.txt b/Tests/CMakeOnly/CompilerIdFortran/CMakeLists.txt
new file mode 100644
index 0000000..067fb8c
--- /dev/null
+++ b/Tests/CMakeOnly/CompilerIdFortran/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.9)
+project(CompilerIdFortran Fortran)
+
+foreach(v
+ CMAKE_Fortran_COMPILER
+ CMAKE_Fortran_COMPILER_ID
+ CMAKE_Fortran_COMPILER_VERSION
+ )
+ if(${v})
+ message(STATUS "${v}=[${${v}}]")
+ else()
+ message(SEND_ERROR "${v} not set!")
+ endif()
+endforeach()
+
+# Version numbers may only contain numbers and periods.
+if(NOT CMAKE_Fortran_COMPILER_VERSION MATCHES
+ "^([0-9]+)(\\.([0-9]+))?(\\.([0-9]+))?(\\.([0-9]+))?$"
+ )
+ message(SEND_ERROR "Compiler version is not numeric!")
+endif()
diff --git a/Tests/CMakeOnly/CompilerIdOBJC/CMakeLists.txt b/Tests/CMakeOnly/CompilerIdOBJC/CMakeLists.txt
new file mode 100644
index 0000000..8f13787
--- /dev/null
+++ b/Tests/CMakeOnly/CompilerIdOBJC/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(CompilerIdOBJC OBJC)
+
+foreach(v
+ CMAKE_OBJC_COMPILER
+ CMAKE_OBJC_COMPILER_ID
+ CMAKE_OBJC_COMPILER_VERSION
+ )
+ if(${v})
+ message(STATUS "${v}=[${${v}}]")
+ else()
+ message(SEND_ERROR "${v} not set!")
+ endif()
+endforeach()
diff --git a/Tests/CMakeOnly/CompilerIdOBJCXX/CMakeLists.txt b/Tests/CMakeOnly/CompilerIdOBJCXX/CMakeLists.txt
new file mode 100644
index 0000000..8f41db0
--- /dev/null
+++ b/Tests/CMakeOnly/CompilerIdOBJCXX/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(CompilerIdOBJCXX OBJCXX)
+
+foreach(v
+ CMAKE_OBJCXX_COMPILER
+ CMAKE_OBJCXX_COMPILER_ID
+ CMAKE_OBJCXX_COMPILER_VERSION
+ )
+ if(${v})
+ message(STATUS "${v}=[${${v}}]")
+ else()
+ message(SEND_ERROR "${v} not set!")
+ endif()
+endforeach()
diff --git a/Tests/CMakeOnly/LinkInterfaceLoop/CMakeLists.txt b/Tests/CMakeOnly/LinkInterfaceLoop/CMakeLists.txt
new file mode 100644
index 0000000..d66eb06
--- /dev/null
+++ b/Tests/CMakeOnly/LinkInterfaceLoop/CMakeLists.txt
@@ -0,0 +1,27 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(LinkInterfaceLoop C)
+
+# Add a shared library that incorrectly names itself as a
+# dependency, thus forming a cycle.
+add_library(A SHARED IMPORTED)
+set_target_properties(A PROPERTIES
+ IMPORTED_LINK_DEPENDENT_LIBRARIES A
+ IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/dirA/A"
+ )
+
+# Add a shared library that incorrectly names itself in
+# its link interface, thus forming a cycle.
+add_library(B SHARED IMPORTED)
+set_target_properties(B PROPERTIES
+ IMPORTED_LINK_INTERFACE_LIBRARIES B
+ IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/dirB/B"
+ )
+
+# Add a shared library with an empty link interface
+# that depends on two shared libraries.
+add_library(C SHARED lib.c)
+set_property(TARGET C PROPERTY LINK_INTERFACE_LIBRARIES "")
+target_link_libraries(C B A)
+
+add_executable(main main.c)
+target_link_libraries(main C)
diff --git a/Tests/CMakeOnly/LinkInterfaceLoop/lib.c b/Tests/CMakeOnly/LinkInterfaceLoop/lib.c
new file mode 100644
index 0000000..abe3b78
--- /dev/null
+++ b/Tests/CMakeOnly/LinkInterfaceLoop/lib.c
@@ -0,0 +1,4 @@
+int lib(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeOnly/LinkInterfaceLoop/main.c b/Tests/CMakeOnly/LinkInterfaceLoop/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/CMakeOnly/LinkInterfaceLoop/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeOnly/MajorVersionSelection/CMakeLists.txt b/Tests/CMakeOnly/MajorVersionSelection/CMakeLists.txt
new file mode 100644
index 0000000..9f30c7d
--- /dev/null
+++ b/Tests/CMakeOnly/MajorVersionSelection/CMakeLists.txt
@@ -0,0 +1,46 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+if (NOT MAJOR_TEST_MODULE OR NOT MAJOR_TEST_VERSION)
+ message(FATAL_ERROR "test selection variables not set up")
+endif ()
+
+if (MAJOR_TEST_NO_LANGUAGES)
+ project(major_detect_${MAJOR_TEST_MODULE}_${MAJOR_TEST_VERSION} NONE)
+else ()
+ project(major_detect_${MAJOR_TEST_MODULE}_${MAJOR_TEST_VERSION})
+endif ()
+
+find_package(${MAJOR_TEST_MODULE} ${MAJOR_TEST_VERSION})
+
+if (MAJOR_TEST_VERSION_VAR)
+ set(VERSION_VAR "${MAJOR_TEST_VERSION_VAR}")
+else ()
+ set(VERSION_VAR "${MAJOR_TEST_MODULE}_VERSION_STRING")
+endif ()
+
+string(TOUPPER "${MAJOR_TEST_MODULE}" MODULE_UPPER)
+
+if ( ( ${MAJOR_TEST_MODULE}_FOUND OR ${MODULE_UPPER}_FOUND ) AND ${VERSION_VAR})
+ message(STATUS "${VERSION_VAR} is '${${VERSION_VAR}}'")
+ if (${VERSION_VAR} VERSION_LESS MAJOR_TEST_VERSION)
+ message(SEND_ERROR "Found version ${${VERSION_VAR}} is less than requested major version ${MAJOR_TEST_VERSION}")
+ endif ()
+ math(EXPR V_PLUS_ONE "${MAJOR_TEST_VERSION} + 1")
+ if (${VERSION_VAR} VERSION_GREATER V_PLUS_ONE)
+ message(SEND_ERROR "Found version ${${VERSION_VAR}} is greater than requested major version ${MAJOR_TEST_VERSION}")
+ endif ()
+endif ()
+
+if ( ( ${MAJOR_TEST_MODULE}_FOUND OR ${MODULE_UPPER}_FOUND ) AND ${MAJOR_TEST_MODULE}_VERSION_MAJOR)
+ message(STATUS "${MAJOR_TEST_MODULE}_VERSION_MAJOR is '${${MAJOR_TEST_MODULE}_VERSION_MAJOR}'")
+ if (NOT ${MAJOR_TEST_VERSION} EQUAL ${MAJOR_TEST_MODULE}_VERSION_MAJOR)
+ message(SEND_ERROR "We requested major version ${MAJOR_TEST_VERSION} but ${MAJOR_TEST_MODULE} set ${MAJOR_TEST_MODULE}_VERSION_MAJOR to ${${MAJOR_TEST_MODULE}_VERSION_MAJOR}")
+ endif ()
+endif ()
+
+if ( ( ${MAJOR_TEST_MODULE}_FOUND OR ${MODULE_UPPER}_FOUND ) AND ${MODULE_UPPER}_VERSION_MAJOR)
+ message(STATUS "${MODULE_UPPER}_VERSION_MAJOR is '${${MODULE_UPPER}_VERSION_MAJOR}'")
+ if (NOT ${MAJOR_TEST_VERSION} EQUAL ${MODULE_UPPER}_VERSION_MAJOR)
+ message(SEND_ERROR "We requested major version ${MAJOR_TEST_VERSION} but ${MAJOR_TEST_MODULE} set ${MODULE_UPPER}_VERSION_MAJOR to ${${MODULE_UPPER}_VERSION_MAJOR}")
+ endif ()
+endif ()
diff --git a/Tests/CMakeOnly/ProjectInclude/CMakeLists.txt b/Tests/CMakeOnly/ProjectInclude/CMakeLists.txt
new file mode 100644
index 0000000..ffce488
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectInclude/CMakeLists.txt
@@ -0,0 +1,4 @@
+project(ProjectInclude LANGUAGES NONE)
+if(NOT AUTO_INCLUDE)
+ message(FATAL_ERROR "include file not found")
+endif()
diff --git a/Tests/CMakeOnly/ProjectInclude/include.cmake b/Tests/CMakeOnly/ProjectInclude/include.cmake
new file mode 100644
index 0000000..527ebe7
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectInclude/include.cmake
@@ -0,0 +1 @@
+set(AUTO_INCLUDE TRUE)
diff --git a/Tests/CMakeOnly/ProjectIncludeAny/CMakeLists.txt b/Tests/CMakeOnly/ProjectIncludeAny/CMakeLists.txt
new file mode 100644
index 0000000..ffce488
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectIncludeAny/CMakeLists.txt
@@ -0,0 +1,4 @@
+project(ProjectInclude LANGUAGES NONE)
+if(NOT AUTO_INCLUDE)
+ message(FATAL_ERROR "include file not found")
+endif()
diff --git a/Tests/CMakeOnly/ProjectIncludeBefore/CMakeLists.txt b/Tests/CMakeOnly/ProjectIncludeBefore/CMakeLists.txt
new file mode 100644
index 0000000..5cd9cba
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectIncludeBefore/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(FOO TRUE)
+project(ProjectInclude LANGUAGES NONE)
+if(NOT AUTO_INCLUDE)
+ message(FATAL_ERROR "include file not found")
+endif()
diff --git a/Tests/CMakeOnly/ProjectIncludeBefore/include.cmake b/Tests/CMakeOnly/ProjectIncludeBefore/include.cmake
new file mode 100644
index 0000000..0a4799d
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectIncludeBefore/include.cmake
@@ -0,0 +1,9 @@
+if(NOT FOO)
+ message(FATAL_ERROR "FOO is not set")
+endif()
+
+if(NOT "${PROJECT_NAME}" STREQUAL "")
+ message(FATAL_ERROR "PROJECT_NAME should be empty")
+endif()
+
+set(AUTO_INCLUDE TRUE)
diff --git a/Tests/CMakeOnly/ProjectIncludeBeforeAny/CMakeLists.txt b/Tests/CMakeOnly/ProjectIncludeBeforeAny/CMakeLists.txt
new file mode 100644
index 0000000..5cd9cba
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectIncludeBeforeAny/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(FOO TRUE)
+project(ProjectInclude LANGUAGES NONE)
+if(NOT AUTO_INCLUDE)
+ message(FATAL_ERROR "include file not found")
+endif()
diff --git a/Tests/CMakeOnly/ProjectIncludeBeforeAny/include.cmake b/Tests/CMakeOnly/ProjectIncludeBeforeAny/include.cmake
new file mode 100644
index 0000000..0a4799d
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectIncludeBeforeAny/include.cmake
@@ -0,0 +1,9 @@
+if(NOT FOO)
+ message(FATAL_ERROR "FOO is not set")
+endif()
+
+if(NOT "${PROJECT_NAME}" STREQUAL "")
+ message(FATAL_ERROR "PROJECT_NAME should be empty")
+endif()
+
+set(AUTO_INCLUDE TRUE)
diff --git a/Tests/CMakeOnly/SelectLibraryConfigurations/CMakeLists.txt b/Tests/CMakeOnly/SelectLibraryConfigurations/CMakeLists.txt
new file mode 100644
index 0000000..3676b17
--- /dev/null
+++ b/Tests/CMakeOnly/SelectLibraryConfigurations/CMakeLists.txt
@@ -0,0 +1,65 @@
+cmake_minimum_required(VERSION 3.9)
+
+project(SelectLibraryConfigurations NONE)
+
+include(${CMAKE_ROOT}/Modules/SelectLibraryConfigurations.cmake)
+
+macro(check_slc basename expect)
+ message(STATUS "checking select_library_configurations(${basename})")
+ select_library_configurations(${basename})
+ if (NOT ${basename}_LIBRARY STREQUAL "${expect}")
+ message(SEND_ERROR "select_library_configurations(${basename}) returned '${${basename}_LIBRARY}' but '${expect}' was expected")
+ endif ()
+ if (NOT ${basename}_LIBRARY STREQUAL "${${basename}_LIBRARIES}")
+ message(SEND_ERROR "select_library_configurations(${basename}) LIBRARY: '${${basename}_LIBRARY}' LIBRARIES: '${${basename}_LIBRARIES}'")
+ endif ()
+endmacro(check_slc)
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if (NOT _isMultiConfig AND NOT CMAKE_BUILD_TYPE)
+ set(NOTYPE_RELONLY_LIBRARY_RELEASE "opt")
+ check_slc(NOTYPE_RELONLY "opt")
+
+ set(NOTYPE_DBGONLY_LIBRARY_DEBUG "dbg")
+ check_slc(NOTYPE_DBGONLY "dbg")
+
+ set(NOTYPE_RELDBG_LIBRARY_RELEASE "opt")
+ set(NOTYPE_RELDBG_LIBRARY_DEBUG "dbg")
+ check_slc(NOTYPE_RELDBG "opt")
+
+ set(CMAKE_BUILD_TYPE Debug)
+endif ()
+
+check_slc(empty "empty_LIBRARY-NOTFOUND")
+
+set(OPTONLY_LIBRARY_RELEASE "opt")
+check_slc(OPTONLY "opt")
+
+set(DBGONLY_LIBRARY_RELEASE "dbg")
+check_slc(DBGONLY "dbg")
+
+set(SAME_LIBRARY_RELEASE "same")
+set(SAME_LIBRARY_DEBUG "same")
+check_slc(SAME "same")
+
+set(OPTONLYLIST_LIBRARY_RELEASE "opt1;opt2")
+check_slc(OPTONLYLIST "opt1;opt2")
+
+set(DBGONLYLIST_LIBRARY_RELEASE "dbg1;dbg2")
+check_slc(DBGONLYLIST "dbg1;dbg2")
+
+set(OPT1DBG1_LIBRARY_RELEASE "opt")
+set(OPT1DBG1_LIBRARY_DEBUG "dbg")
+check_slc(OPT1DBG1 "optimized;opt;debug;dbg")
+
+set(OPT1DBG2_LIBRARY_RELEASE "opt")
+set(OPT1DBG2_LIBRARY_DEBUG "dbg1;dbg2")
+check_slc(OPT1DBG2 "optimized;opt;debug;dbg1;debug;dbg2")
+
+set(OPT2DBG1_LIBRARY_RELEASE "opt1;opt2")
+set(OPT2DBG1_LIBRARY_DEBUG "dbg")
+check_slc(OPT2DBG1 "optimized;opt1;optimized;opt2;debug;dbg")
+
+set(OPT2DBG2_LIBRARY_RELEASE "opt1;opt2")
+set(OPT2DBG2_LIBRARY_DEBUG "dbg1;dbg2")
+check_slc(OPT2DBG2 "optimized;opt1;optimized;opt2;debug;dbg1;debug;dbg2")
diff --git a/Tests/CMakeOnly/TargetScope/CMakeLists.txt b/Tests/CMakeOnly/TargetScope/CMakeLists.txt
new file mode 100644
index 0000000..faf2250
--- /dev/null
+++ b/Tests/CMakeOnly/TargetScope/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(TargetScope NONE)
+
+add_subdirectory(Sub)
+
+if(TARGET SubLibLocal)
+ message(FATAL_ERROR "SubLibLocal visible in top directory")
+endif()
+if(NOT TARGET SubLibGlobal)
+ message(FATAL_ERROR "SubLibGlobal not visible in top directory")
+endif()
+
+add_subdirectory(Sib)
diff --git a/Tests/CMakeOnly/TargetScope/Sib/CMakeLists.txt b/Tests/CMakeOnly/TargetScope/Sib/CMakeLists.txt
new file mode 100644
index 0000000..7f6f4e8
--- /dev/null
+++ b/Tests/CMakeOnly/TargetScope/Sib/CMakeLists.txt
@@ -0,0 +1,6 @@
+if(TARGET SubLibLocal)
+ message(FATAL_ERROR "SubLibLocal visible in sibling directory")
+endif()
+if(NOT TARGET SubLibGlobal)
+ message(FATAL_ERROR "SubLibGlobal not visible in sibling directory")
+endif()
diff --git a/Tests/CMakeOnly/TargetScope/Sub/CMakeLists.txt b/Tests/CMakeOnly/TargetScope/Sub/CMakeLists.txt
new file mode 100644
index 0000000..27318f5
--- /dev/null
+++ b/Tests/CMakeOnly/TargetScope/Sub/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_library(SubLibLocal UNKNOWN IMPORTED)
+add_library(SubLibGlobal UNKNOWN IMPORTED GLOBAL)
+add_subdirectory(Sub)
+if(NOT TARGET SubLibLocal)
+ message(FATAL_ERROR "SubLibLocal not visible in own directory")
+endif()
+if(NOT TARGET SubLibGlobal)
+ message(FATAL_ERROR "SubLibGlobal not visible in own directory")
+endif()
diff --git a/Tests/CMakeOnly/TargetScope/Sub/Sub/CMakeLists.txt b/Tests/CMakeOnly/TargetScope/Sub/Sub/CMakeLists.txt
new file mode 100644
index 0000000..a351daa
--- /dev/null
+++ b/Tests/CMakeOnly/TargetScope/Sub/Sub/CMakeLists.txt
@@ -0,0 +1,6 @@
+if(NOT TARGET SubLibLocal)
+ message(FATAL_ERROR "SubLibLocal not visible in subdirectory")
+endif()
+if(NOT TARGET SubLibGlobal)
+ message(FATAL_ERROR "SubLibGlobal not visible in subdirectory")
+endif()
diff --git a/Tests/CMakeOnly/Test.cmake.in b/Tests/CMakeOnly/Test.cmake.in
new file mode 100644
index 0000000..c531e8b
--- /dev/null
+++ b/Tests/CMakeOnly/Test.cmake.in
@@ -0,0 +1,33 @@
+if (NOT TEST_SOURCE)
+ set(TEST_SOURCE "${TEST}")
+endif ()
+
+set(make_program "@CMake_TEST_EXPLICIT_MAKE_PROGRAM@")
+if(make_program)
+ set(maybe_make_program "-DCMAKE_MAKE_PROGRAM=${make_program}")
+endif()
+
+set(_isMultiConfig "@_isMultiConfig@")
+if(_isMultiConfig)
+ set(cfg_opts "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release\\;RelWithDebInfo")
+else()
+ set(cfg_opts)
+endif()
+
+set(source_dir "@CMAKE_CURRENT_SOURCE_DIR@/${TEST_SOURCE}")
+set(binary_dir "@CMAKE_CURRENT_BINARY_DIR@/${TEST}-build")
+file(REMOVE_RECURSE "${binary_dir}")
+file(MAKE_DIRECTORY "${binary_dir}")
+execute_process(
+ COMMAND ${CMAKE_COMMAND} ${CMAKE_ARGS}
+ "${source_dir}" -G "@CMAKE_GENERATOR@"
+ -A "@CMAKE_GENERATOR_PLATFORM@"
+ -T "@CMAKE_GENERATOR_TOOLSET@"
+ ${cfg_opts}
+ ${maybe_make_program}
+ WORKING_DIRECTORY "${binary_dir}"
+ RESULT_VARIABLE result
+ )
+if(result)
+ message(FATAL_ERROR "CMake failed to configure ${TEST}")
+endif()
diff --git a/Tests/CMakeOnly/find_library/A/libtestA.a b/Tests/CMakeOnly/find_library/A/libtestA.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/A/libtestA.a
diff --git a/Tests/CMakeOnly/find_library/B/libtestB.a b/Tests/CMakeOnly/find_library/B/libtestB.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/B/libtestB.a
diff --git a/Tests/CMakeOnly/find_library/CMakeLists.txt b/Tests/CMakeOnly/find_library/CMakeLists.txt
new file mode 100644
index 0000000..b23d5e2
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/CMakeLists.txt
@@ -0,0 +1,110 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(FindLibraryTest NONE)
+
+set(CMAKE_FIND_DEBUG_MODE 1)
+
+macro(test_find_library desc expected)
+ unset(LIB CACHE)
+ find_library(LIB ${ARGN} NO_DEFAULT_PATH)
+ if(LIB)
+ # Convert to relative path for comparison to expected location.
+ file(RELATIVE_PATH REL_LIB "${CMAKE_CURRENT_SOURCE_DIR}" "${LIB}")
+
+ # Check and report failure.
+ if(NOT "${REL_LIB}" STREQUAL "${expected}")
+ message(SEND_ERROR "Library ${expected} found as [${REL_LIB}]${desc}")
+ elseif(CMAKE_FIND_DEBUG_MODE)
+ message(STATUS "Library ${expected} found as [${REL_LIB}]${desc}")
+ endif()
+ else()
+ message(SEND_ERROR "Library ${expected} NOT FOUND${desc}")
+ endif()
+endmacro()
+
+macro(test_find_library_subst expected)
+ get_filename_component(dir ${expected} PATH)
+ get_filename_component(name ${expected} NAME)
+ string(REGEX REPLACE "lib/?[36Xx][24Y3][Z2]*" "lib" dir "${dir}")
+ test_find_library(", searched as ${dir}" "${expected}"
+ NAMES ${name}
+ PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${dir}
+ )
+endmacro()
+
+set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
+set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIBX32_PATHS TRUE)
+set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS TRUE)
+set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE)
+
+set(CMAKE_INTERNAL_PLATFORM_ABI "ELF")
+set(CMAKE_SIZEOF_VOID_P 4)
+foreach(lib
+ lib/32/libtest5.a
+ lib/A/lib/libtest1.a
+ lib/A/lib32/libtest3.a
+ lib/A/libtest1.a
+ lib/libtest1.a
+ lib/libtest2.a
+ lib/libtest3.a
+ lib/libtest3.a
+ lib32/A/lib/libtest2.a
+ lib32/A/lib32/libtest4.a
+ lib32/A/libtest4.a
+ lib32/libtest4.a
+ )
+ test_find_library_subst(${lib})
+endforeach()
+
+set(CMAKE_SIZEOF_VOID_P 8)
+foreach(lib64
+ lib/64/libtest2.a
+ lib/A/lib64/libtest3.a
+ lib/libtest3.a
+ lib64/A/lib/libtest2.a
+ lib64/A/lib64/libtest1.a
+ lib64/A/libtest1.a
+ lib64/libtest1.a
+ )
+ test_find_library_subst(${lib64})
+endforeach()
+
+set(CMAKE_INTERNAL_PLATFORM_ABI "ELF X32")
+set(CMAKE_SIZEOF_VOID_P 4)
+foreach(libx32
+ lib/x32/libtest2.a
+ lib/A/libx32/libtest3.a
+ lib/libtest3.a
+ libx32/A/lib/libtest2.a
+ libx32/A/libx32/libtest1.a
+ libx32/A/libtest1.a
+ libx32/libtest1.a
+ )
+ test_find_library_subst(${libx32})
+endforeach()
+
+test_find_library("" A/libtestA.a
+ NAMES testA testB
+ PATHS ${CMAKE_CURRENT_SOURCE_DIR}/A ${CMAKE_CURRENT_SOURCE_DIR}/B
+ )
+test_find_library("" B/libtestB.a
+ NAMES testB testA
+ PATHS ${CMAKE_CURRENT_SOURCE_DIR}/A ${CMAKE_CURRENT_SOURCE_DIR}/B
+ )
+test_find_library("" A/libtestA.a
+ NAMES testB testA NAMES_PER_DIR
+ PATHS ${CMAKE_CURRENT_SOURCE_DIR}/A ${CMAKE_CURRENT_SOURCE_DIR}/B
+ )
+
+set(CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX "XYZ")
+foreach(libXYZ
+ lib/XYZ/libtest1.a
+ lib/A/libXYZ/libtest2.a
+ lib/libtest3.a
+ libXYZ/A/lib/libtest4.a
+ libXYZ/A/libXYZ/libtest5.a
+ libXYZ/A/libtest6.a
+ libXYZ/libtest7.a
+ )
+ test_find_library_subst(${libXYZ})
+endforeach()
diff --git a/Tests/CMakeOnly/find_library/lib/32/libtest5.a b/Tests/CMakeOnly/find_library/lib/32/libtest5.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib/32/libtest5.a
diff --git a/Tests/CMakeOnly/find_library/lib/64/libtest2.a b/Tests/CMakeOnly/find_library/lib/64/libtest2.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib/64/libtest2.a
diff --git a/Tests/CMakeOnly/find_library/lib/A/lib/libtest1.a b/Tests/CMakeOnly/find_library/lib/A/lib/libtest1.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib/A/lib/libtest1.a
diff --git a/Tests/CMakeOnly/find_library/lib/A/lib32/libtest3.a b/Tests/CMakeOnly/find_library/lib/A/lib32/libtest3.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib/A/lib32/libtest3.a
diff --git a/Tests/CMakeOnly/find_library/lib/A/lib64/libtest3.a b/Tests/CMakeOnly/find_library/lib/A/lib64/libtest3.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib/A/lib64/libtest3.a
diff --git a/Tests/CMakeOnly/find_library/lib/A/libXYZ/libtest2.a b/Tests/CMakeOnly/find_library/lib/A/libXYZ/libtest2.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib/A/libXYZ/libtest2.a
diff --git a/Tests/CMakeOnly/find_library/lib/A/libtest1.a b/Tests/CMakeOnly/find_library/lib/A/libtest1.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib/A/libtest1.a
diff --git a/Tests/CMakeOnly/find_library/lib/A/libx32/libtest3.a b/Tests/CMakeOnly/find_library/lib/A/libx32/libtest3.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib/A/libx32/libtest3.a
diff --git a/Tests/CMakeOnly/find_library/lib/XYZ/libtest1.a b/Tests/CMakeOnly/find_library/lib/XYZ/libtest1.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib/XYZ/libtest1.a
diff --git a/Tests/CMakeOnly/find_library/lib/libtest1.a b/Tests/CMakeOnly/find_library/lib/libtest1.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib/libtest1.a
diff --git a/Tests/CMakeOnly/find_library/lib/libtest2.a b/Tests/CMakeOnly/find_library/lib/libtest2.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib/libtest2.a
diff --git a/Tests/CMakeOnly/find_library/lib/libtest3.a b/Tests/CMakeOnly/find_library/lib/libtest3.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib/libtest3.a
diff --git a/Tests/CMakeOnly/find_library/lib/x32/libtest2.a b/Tests/CMakeOnly/find_library/lib/x32/libtest2.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib/x32/libtest2.a
diff --git a/Tests/CMakeOnly/find_library/lib32/A/lib/libtest2.a b/Tests/CMakeOnly/find_library/lib32/A/lib/libtest2.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib32/A/lib/libtest2.a
diff --git a/Tests/CMakeOnly/find_library/lib32/A/lib32/libtest4.a b/Tests/CMakeOnly/find_library/lib32/A/lib32/libtest4.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib32/A/lib32/libtest4.a
diff --git a/Tests/CMakeOnly/find_library/lib32/A/libtest4.a b/Tests/CMakeOnly/find_library/lib32/A/libtest4.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib32/A/libtest4.a
diff --git a/Tests/CMakeOnly/find_library/lib32/libtest4.a b/Tests/CMakeOnly/find_library/lib32/libtest4.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib32/libtest4.a
diff --git a/Tests/CMakeOnly/find_library/lib64/A/lib/libtest2.a b/Tests/CMakeOnly/find_library/lib64/A/lib/libtest2.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib64/A/lib/libtest2.a
diff --git a/Tests/CMakeOnly/find_library/lib64/A/lib64/libtest1.a b/Tests/CMakeOnly/find_library/lib64/A/lib64/libtest1.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib64/A/lib64/libtest1.a
diff --git a/Tests/CMakeOnly/find_library/lib64/A/libtest1.a b/Tests/CMakeOnly/find_library/lib64/A/libtest1.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib64/A/libtest1.a
diff --git a/Tests/CMakeOnly/find_library/lib64/libtest1.a b/Tests/CMakeOnly/find_library/lib64/libtest1.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/lib64/libtest1.a
diff --git a/Tests/CMakeOnly/find_library/libXYZ/A/lib/libtest4.a b/Tests/CMakeOnly/find_library/libXYZ/A/lib/libtest4.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/libXYZ/A/lib/libtest4.a
diff --git a/Tests/CMakeOnly/find_library/libXYZ/A/libXYZ/libtest5.a b/Tests/CMakeOnly/find_library/libXYZ/A/libXYZ/libtest5.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/libXYZ/A/libXYZ/libtest5.a
diff --git a/Tests/CMakeOnly/find_library/libXYZ/A/libtest6.a b/Tests/CMakeOnly/find_library/libXYZ/A/libtest6.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/libXYZ/A/libtest6.a
diff --git a/Tests/CMakeOnly/find_library/libXYZ/libtest7.a b/Tests/CMakeOnly/find_library/libXYZ/libtest7.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/libXYZ/libtest7.a
diff --git a/Tests/CMakeOnly/find_library/libx32/A/lib/libtest2.a b/Tests/CMakeOnly/find_library/libx32/A/lib/libtest2.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/libx32/A/lib/libtest2.a
diff --git a/Tests/CMakeOnly/find_library/libx32/A/libtest1.a b/Tests/CMakeOnly/find_library/libx32/A/libtest1.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/libx32/A/libtest1.a
diff --git a/Tests/CMakeOnly/find_library/libx32/A/libx32/libtest1.a b/Tests/CMakeOnly/find_library/libx32/A/libx32/libtest1.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/libx32/A/libx32/libtest1.a
diff --git a/Tests/CMakeOnly/find_library/libx32/libtest1.a b/Tests/CMakeOnly/find_library/libx32/libtest1.a
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_library/libx32/libtest1.a
diff --git a/Tests/CMakeOnly/find_path/CMakeLists.txt b/Tests/CMakeOnly/find_path/CMakeLists.txt
new file mode 100644
index 0000000..bf4e350
--- /dev/null
+++ b/Tests/CMakeOnly/find_path/CMakeLists.txt
@@ -0,0 +1,31 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(FindPathTest NONE)
+
+set(CMAKE_FIND_DEBUG_MODE 1)
+
+macro(test_find_path expected)
+ unset(HDR CACHE)
+ find_path(HDR ${ARGN}
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ )
+ if(HDR)
+ # Convert to relative path for comparison to expected location.
+ file(RELATIVE_PATH REL_HDR "${CMAKE_CURRENT_SOURCE_DIR}" "${HDR}")
+
+ # Check and report failure.
+ if(NOT "${REL_HDR}" STREQUAL "${expected}")
+ message(SEND_ERROR "Header ${expected} found as [${REL_HDR}]")
+ elseif(CMAKE_FIND_DEBUG_MODE)
+ message(STATUS "Header ${expected} found as [${REL_HDR}]")
+ endif()
+ else()
+ message(SEND_ERROR "Header ${expected} NOT FOUND")
+ endif()
+endmacro()
+
+set(CMAKE_SYSTEM_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR})
+set(CMAKE_LIBRARY_ARCHITECTURE arch)
+
+test_find_path(include NAMES test1.h)
+test_find_path(include/arch NAMES test1arch.h)
diff --git a/Tests/CMakeOnly/find_path/include/arch/test1arch.h b/Tests/CMakeOnly/find_path/include/arch/test1arch.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_path/include/arch/test1arch.h
diff --git a/Tests/CMakeOnly/find_path/include/test1.h b/Tests/CMakeOnly/find_path/include/test1.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CMakeOnly/find_path/include/test1.h
diff --git a/Tests/CMakeTestAllGenerators/RunCMake.cmake b/Tests/CMakeTestAllGenerators/RunCMake.cmake
new file mode 100644
index 0000000..bfbb3a5
--- /dev/null
+++ b/Tests/CMakeTestAllGenerators/RunCMake.cmake
@@ -0,0 +1,76 @@
+if(NOT DEFINED CMake_SOURCE_DIR)
+ message(FATAL_ERROR "CMake_SOURCE_DIR not defined")
+endif()
+
+if(NOT DEFINED dir)
+ message(FATAL_ERROR "dir not defined")
+endif()
+
+# Analyze 'cmake --help' output for list of available generators:
+#
+execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${dir})
+execute_process(COMMAND ${CMAKE_COMMAND} -E capabilities
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE stdout
+ ERROR_VARIABLE stderr
+ WORKING_DIRECTORY ${dir})
+
+set(generators)
+string(REGEX MATCHALL [["name":"[^"]+","platformSupport"]] generators_json "${stdout}")
+foreach(gen_json IN LISTS generators_json)
+ if("${gen_json}" MATCHES [["name":"([^"]+)"]])
+ set(gen "${CMAKE_MATCH_1}")
+ if(NOT gen MATCHES " (Win64|IA64|ARM)$")
+ list(APPEND generators "${gen}")
+ endif()
+ endif()
+endforeach()
+list(REMOVE_DUPLICATES generators)
+
+# Also call with one non-existent generator:
+#
+set(generators ${generators} "BOGUS_CMAKE_GENERATOR")
+
+# Call cmake with -G on each available generator. We do not care if this
+# succeeds or not. We expect it *not* to succeed if the underlying packaging
+# tools are not installed on the system... This test is here simply to add
+# coverage for the various cmake generators, even/especially to test ones
+# where the tools are not installed.
+#
+message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+
+message(STATUS "CMake generators='${generators}'")
+
+# First setup a source tree to run CMake on.
+#
+execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory
+ ${CMake_SOURCE_DIR}/Tests/CTestTest/SmallAndFast
+ ${dir}/Source
+)
+
+foreach(g ${generators})
+ message(STATUS "cmake -G \"${g}\" ..")
+
+ # Create a binary directory for each generator:
+ #
+ execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory
+ ${dir}/Source/${g}
+ )
+
+ # Run cmake:
+ #
+ execute_process(COMMAND ${CMAKE_COMMAND} -G ${g} ..
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE stdout
+ ERROR_VARIABLE stderr
+ WORKING_DIRECTORY ${dir}/Source/${g}
+ )
+
+ message(STATUS "result='${result}'")
+ message(STATUS "stdout='${stdout}'")
+ message(STATUS "stderr='${stderr}'")
+ message(STATUS "")
+endforeach()
+
+message(STATUS "CMake generators='${generators}'")
+message(STATUS "CMAKE_COMMAND='${CMAKE_COMMAND}'")
diff --git a/Tests/CMakeTests/.gitattributes b/Tests/CMakeTests/.gitattributes
new file mode 100644
index 0000000..c6148fb
--- /dev/null
+++ b/Tests/CMakeTests/.gitattributes
@@ -0,0 +1 @@
+File-HASH-Input.txt eol=lf
diff --git a/Tests/CMakeTests/A/include/cmake_i_do_not_exist_in_the_system.h b/Tests/CMakeTests/A/include/cmake_i_do_not_exist_in_the_system.h
new file mode 100644
index 0000000..2392aee
--- /dev/null
+++ b/Tests/CMakeTests/A/include/cmake_i_do_not_exist_in_the_system.h
@@ -0,0 +1 @@
+/* empty header file */
diff --git a/Tests/CMakeTests/CMakeHostSystemInformation-BadArg1.cmake b/Tests/CMakeTests/CMakeHostSystemInformation-BadArg1.cmake
new file mode 100644
index 0000000..1655eb4
--- /dev/null
+++ b/Tests/CMakeTests/CMakeHostSystemInformation-BadArg1.cmake
@@ -0,0 +1 @@
+cmake_host_system_information(HOSTNAME)
diff --git a/Tests/CMakeTests/CMakeHostSystemInformation-BadArg2.cmake b/Tests/CMakeTests/CMakeHostSystemInformation-BadArg2.cmake
new file mode 100644
index 0000000..1f056d5
--- /dev/null
+++ b/Tests/CMakeTests/CMakeHostSystemInformation-BadArg2.cmake
@@ -0,0 +1 @@
+cmake_host_system_information(RESULT FQDN HOSTNAME)
diff --git a/Tests/CMakeTests/CMakeHostSystemInformation-BadArg3.cmake b/Tests/CMakeTests/CMakeHostSystemInformation-BadArg3.cmake
new file mode 100644
index 0000000..9c5a558
--- /dev/null
+++ b/Tests/CMakeTests/CMakeHostSystemInformation-BadArg3.cmake
@@ -0,0 +1 @@
+cmake_host_system_information(RESULT RESULT QUERY FOOBAR)
diff --git a/Tests/CMakeTests/CMakeHostSystemInformation-QueryList.cmake b/Tests/CMakeTests/CMakeHostSystemInformation-QueryList.cmake
new file mode 100644
index 0000000..1c3156d
--- /dev/null
+++ b/Tests/CMakeTests/CMakeHostSystemInformation-QueryList.cmake
@@ -0,0 +1,5 @@
+cmake_host_system_information(RESULT RESULT
+ QUERY NUMBER_OF_LOGICAL_CORES NUMBER_OF_PHYSICAL_CORES
+)
+
+message("[${RESULT}]")
diff --git a/Tests/CMakeTests/CMakeHostSystemInformationTest.cmake.in b/Tests/CMakeTests/CMakeHostSystemInformationTest.cmake.in
new file mode 100644
index 0000000..a3c2b05
--- /dev/null
+++ b/Tests/CMakeTests/CMakeHostSystemInformationTest.cmake.in
@@ -0,0 +1,52 @@
+set(BadArg1-RESULT 1)
+set(BadArg1-STDERR "missing RESULT specification")
+set(BadArg2-RESULT 1)
+set(BadArg2-STDERR "missing QUERY specification")
+set(BadArg3-RESULT 1)
+set(BadArg3-STDERR "does not recognize <key> FOOBAR")
+set(QueryList-RESULT 0)
+set(QueryList-STDERR "\\[[0-9]+;[0-9]+\\]")
+
+function(try_and_print key)
+ cmake_host_system_information(RESULT RESULT QUERY ${key})
+ message(STATUS "[${key}] [${RESULT}]")
+endfunction()
+
+message("CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+
+try_and_print(NUMBER_OF_LOGICAL_CORES)
+try_and_print(NUMBER_OF_PHYSICAL_CORES)
+try_and_print(HOSTNAME)
+try_and_print(FQDN)
+try_and_print(TOTAL_VIRTUAL_MEMORY)
+try_and_print(AVAILABLE_VIRTUAL_MEMORY)
+try_and_print(TOTAL_PHYSICAL_MEMORY)
+try_and_print(AVAILABLE_PHYSICAL_MEMORY)
+try_and_print(IS_64BIT)
+try_and_print(HAS_FPU)
+try_and_print(HAS_MMX)
+try_and_print(HAS_MMX_PLUS)
+try_and_print(HAS_SSE)
+try_and_print(HAS_SSE2)
+try_and_print(HAS_SSE_FP)
+try_and_print(HAS_SSE_MMX)
+try_and_print(HAS_AMD_3DNOW)
+try_and_print(HAS_AMD_3DNOW_PLUS)
+try_and_print(HAS_IA64)
+try_and_print(HAS_SERIAL_NUMBER)
+try_and_print(PROCESSOR_SERIAL_NUMBER)
+try_and_print(PROCESSOR_NAME)
+try_and_print(PROCESSOR_DESCRIPTION)
+try_and_print(OS_NAME)
+try_and_print(OS_RELEASE)
+try_and_print(OS_VERSION)
+try_and_print(OS_PLATFORM)
+
+include("@CMAKE_CURRENT_SOURCE_DIR@/CheckCMakeTest.cmake")
+
+check_cmake_test(CMakeHostSystemInformation
+ BadArg1
+ BadArg2
+ BadArg3
+ QueryList
+)
diff --git a/Tests/CMakeTests/CMakeLists.txt b/Tests/CMakeTests/CMakeLists.txt
new file mode 100644
index 0000000..52959e6
--- /dev/null
+++ b/Tests/CMakeTests/CMakeLists.txt
@@ -0,0 +1,77 @@
+set(CMAKE_EXECUTABLE "${CMake_BIN_DIR}/cmake")
+
+
+macro(AddCMakeTest TestName PreArgs)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${TestName}Test.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/${TestName}Test.cmake" @ONLY)
+ add_test(NAME CMake.${TestName}
+ COMMAND ${CMAKE_EXECUTABLE} ${PreArgs}
+ -P "${CMAKE_CURRENT_BINARY_DIR}/${TestName}Test.cmake" ${ARGN})
+ set_tests_properties("CMake.${TestName}" PROPERTIES LABELS "CMake;command")
+endmacro()
+
+
+AddCMakeTest(List "")
+AddCMakeTest(VariableWatch "")
+AddCMakeTest(Include "")
+AddCMakeTest(FindBase "")
+AddCMakeTest(Toolchain "")
+AddCMakeTest(GetFilenameComponentRealpath "")
+AddCMakeTest(Version "")
+AddCMakeTest(Message "")
+AddCMakeTest(File "")
+AddCMakeTest(ImplicitLinkInfo "")
+AddCMakeTest(ModuleNotices "")
+AddCMakeTest(GetProperty "")
+AddCMakeTest(If "")
+AddCMakeTest(String "")
+AddCMakeTest(Math "")
+AddCMakeTest(CMakeMinimumRequired "")
+AddCMakeTest(CompilerIdVendor "")
+AddCMakeTest(ProcessorCount "-DKWSYS_TEST_EXE=$<TARGET_FILE:cmsysTestsCxx>")
+AddCMakeTest(PushCheckState "")
+AddCMakeTest(While "")
+AddCMakeTest(CMakeHostSystemInformation "")
+
+AddCMakeTest(FileDownload "")
+set_tests_properties(CMake.FileDownload PROPERTIES
+ PASS_REGULAR_EXPRESSION "file already exists with expected MD5 sum"
+ FAIL_REGULAR_EXPRESSION "Unexpected status|incorrectly interpreted"
+ )
+AddCMakeTest(FileDownloadBadHash "")
+set_property(TEST CMake.FileDownloadBadHash PROPERTY
+ WILL_FAIL TRUE
+ )
+
+AddCMakeTest(FileUpload "")
+
+set(EndStuff_PreArgs
+ "-Ddir:STRING=${CMAKE_CURRENT_BINARY_DIR}/EndStuffTest"
+ )
+AddCMakeTest(EndStuff "${EndStuff_PreArgs}")
+
+AddCMakeTest(GetPrerequisites "-DConfiguration:STRING=$<CONFIGURATION>")
+
+if(GIT_EXECUTABLE)
+ set(PolicyCheck_PreArgs
+ "-DCMake_BINARY_DIR:PATH=${CMake_BINARY_DIR}"
+ "-DCMake_SOURCE_DIR:PATH=${CMake_SOURCE_DIR}"
+ "-DGIT_EXECUTABLE:STRING=${GIT_EXECUTABLE}"
+ )
+ AddCMakeTest(PolicyCheck "${PolicyCheck_PreArgs}")
+endif()
+
+# Run CheckSourceTree as the very last test in the CMake/CTest/CPack test
+# suite. It detects if any changes have been made to the CMake source tree
+# by any previous configure, build or test steps.
+#
+if(GIT_EXECUTABLE)
+ string(REPLACE "\\" "/" ENV_HOME "$ENV{HOME}")
+ set(CheckSourceTree_PreArgs
+ "-DCMake_BINARY_DIR:PATH=${CMake_BINARY_DIR}"
+ "-DCMake_SOURCE_DIR:PATH=${CMake_SOURCE_DIR}"
+ "-DGIT_EXECUTABLE:STRING=${GIT_EXECUTABLE}"
+ "-DHOME:STRING=${ENV_HOME}"
+ )
+ AddCMakeTest(CheckSourceTree "${CheckSourceTree_PreArgs}")
+endif()
diff --git a/Tests/CMakeTests/CMakeMinimumRequiredTest.cmake.in b/Tests/CMakeTests/CMakeMinimumRequiredTest.cmake.in
new file mode 100644
index 0000000..b83a779
--- /dev/null
+++ b/Tests/CMakeTests/CMakeMinimumRequiredTest.cmake.in
@@ -0,0 +1,18 @@
+# Execute each test listed in:
+#
+set(scriptname "@CMAKE_CURRENT_SOURCE_DIR@/CMakeMinimumRequiredTestScript.cmake")
+set(number_of_tests_expected 8)
+
+include("@CMAKE_CURRENT_SOURCE_DIR@/ExecuteScriptTests.cmake")
+execute_all_script_tests(${scriptname} number_of_tests_executed)
+
+# And verify that number_of_tests_executed is at least as many as we know
+# about as of this writing...
+#
+message(STATUS "scriptname='${scriptname}'")
+message(STATUS "number_of_tests_executed='${number_of_tests_executed}'")
+message(STATUS "number_of_tests_expected='${number_of_tests_expected}'")
+
+if(number_of_tests_executed LESS number_of_tests_expected)
+ message(FATAL_ERROR "error: some test cases were skipped")
+endif()
diff --git a/Tests/CMakeTests/CMakeMinimumRequiredTestScript.cmake b/Tests/CMakeTests/CMakeMinimumRequiredTestScript.cmake
new file mode 100644
index 0000000..d434d29
--- /dev/null
+++ b/Tests/CMakeTests/CMakeMinimumRequiredTestScript.cmake
@@ -0,0 +1,31 @@
+message(STATUS "testname='${testname}'")
+
+if(testname STREQUAL empty) # pass
+ cmake_minimum_required()
+
+elseif(testname STREQUAL bogus) # fail
+ cmake_minimum_required(BOGUS)
+
+elseif(testname STREQUAL no_version) # fail
+ cmake_minimum_required(VERSION)
+
+elseif(testname STREQUAL no_version_before_fatal_error) # fail
+ cmake_minimum_required(VERSION FATAL_ERROR)
+
+elseif(testname STREQUAL bad_version) # fail
+ cmake_minimum_required(VERSION 2.blah.blah)
+
+elseif(testname STREQUAL worse_version) # fail
+ cmake_minimum_required(VERSION blah.blah.blah)
+
+elseif(testname STREQUAL future_version) # fail
+ math(EXPR major "${CMAKE_MAJOR_VERSION} + 1")
+ cmake_minimum_required(VERSION ${major}.2.1)
+
+elseif(testname STREQUAL unknown_arg) # fail
+ cmake_minimum_required(VERSION ${CMAKE_MAJOR_VERSION}.0.0 SILLY)
+
+else() # fail
+ message(FATAL_ERROR "testname='${testname}' - error: no such test in '${CMAKE_CURRENT_LIST_FILE}'")
+
+endif()
diff --git a/Tests/CMakeTests/CheckCMakeTest.cmake b/Tests/CMakeTests/CheckCMakeTest.cmake
new file mode 100644
index 0000000..1565394
--- /dev/null
+++ b/Tests/CMakeTests/CheckCMakeTest.cmake
@@ -0,0 +1,35 @@
+get_filename_component(CMakeTests_SRC_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
+
+function(check_cmake_test_single prefix test testfile)
+ message(STATUS "Test ${prefix}-${test}...")
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} -P "${testfile}"
+ WORKING_DIRECTORY "${CMakeTests_BIN_DIR}"
+ OUTPUT_VARIABLE stdout
+ ERROR_VARIABLE stderr
+ RESULT_VARIABLE result
+ )
+ string(REPLACE "\n" "\n out> " out " out> ${stdout}")
+ string(REPLACE "\n" "\n err> " err " err> ${stderr}")
+ if(NOT "${result}" STREQUAL "${${test}-RESULT}")
+ message(FATAL_ERROR
+ "Test ${test} result is [${result}], not [${${test}-RESULT}].\n"
+ "Test ${test} output:\n"
+ "${out}\n"
+ "${err}")
+ endif()
+ if(${test}-STDERR AND NOT "${err}" MATCHES "${${test}-STDERR}")
+ message(FATAL_ERROR
+ "Test ${test} stderr does not match\n ${${test}-STDERR}\n"
+ "Test ${test} output:\n"
+ "${out}\n"
+ "${err}")
+ endif()
+endfunction()
+
+function(check_cmake_test prefix)
+ get_filename_component(CMakeTests_BIN_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
+ foreach(test ${ARGN})
+ check_cmake_test_single("${prefix}" "${test}" "${CMakeTests_SRC_DIR}/${prefix}-${test}.cmake")
+ endforeach()
+endfunction()
diff --git a/Tests/CMakeTests/CheckSourceTreeTest.cmake.in b/Tests/CMakeTests/CheckSourceTreeTest.cmake.in
new file mode 100644
index 0000000..4f2aaea
--- /dev/null
+++ b/Tests/CMakeTests/CheckSourceTreeTest.cmake.in
@@ -0,0 +1,365 @@
+# Check the CMake source tree and report anything suspicious...
+#
+message("=============================================================================")
+message("CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+message("")
+message("CMake_BINARY_DIR='${CMake_BINARY_DIR}'")
+message("CMake_SOURCE_DIR='${CMake_SOURCE_DIR}'")
+message("GIT_EXECUTABLE='${GIT_EXECUTABLE}'")
+message("HOME='${HOME}'")
+message("ENV{DASHBOARD_TEST_FROM_CTEST}='$ENV{DASHBOARD_TEST_FROM_CTEST}'")
+message("")
+string(REPLACE "\\" "\\\\" HOME "${HOME}")
+
+
+# Is the build directory the same as or underneath the source directory?
+# (i.e. - is it an "in source" build?)
+#
+set(in_source_build 0)
+set(build_under_source 0)
+
+string(FIND "${CMake_BINARY_DIR}" "${CMake_SOURCE_DIR}/" pos)
+if(pos EQUAL 0)
+ message("build dir is *inside* source dir")
+ set(build_under_source 1)
+elseif(CMake_SOURCE_DIR STREQUAL "${CMake_BINARY_DIR}")
+ message("build dir *is* source dir")
+ set(in_source_build 1)
+else()
+ string(LENGTH "${CMake_SOURCE_DIR}" src_len)
+ string(LENGTH "${CMake_BINARY_DIR}" bin_len)
+
+ if(bin_len GREATER src_len)
+ math(EXPR substr_len "${src_len}+1")
+ string(SUBSTRING "${CMake_BINARY_DIR}" 0 ${substr_len} bin_dir)
+ if(bin_dir STREQUAL "${CMake_SOURCE_DIR}/")
+ message("build dir is under source dir")
+ set(in_source_build 1)
+ endif()
+ endif()
+endif()
+
+message("src_len='${src_len}'")
+message("bin_len='${bin_len}'")
+message("substr_len='${substr_len}'")
+message("bin_dir='${bin_dir}'")
+message("in_source_build='${in_source_build}'")
+message("build_under_source='${build_under_source}'")
+message("")
+
+if(build_under_source)
+ message(STATUS "Skipping rest of test because build tree is under source tree")
+ return()
+endif()
+
+# If this does not appear to be a git checkout, just pass the test here
+# and now. (Do not let the test fail if it is run in a tree *exported* from a
+# repository or unpacked from a .zip file source installer...)
+#
+set(is_git_checkout 0)
+if(EXISTS "${CMake_SOURCE_DIR}/.git")
+ set(is_git_checkout 1)
+endif()
+
+message("is_git_checkout='${is_git_checkout}'")
+message("")
+
+if(NOT is_git_checkout)
+ message("source tree is not a git checkout... test passes by early return...")
+ return()
+endif()
+
+# This test looks for the following types of changes in the source tree:
+#
+set(additions 0)
+set(conflicts 0)
+set(modifications 0)
+set(nonadditions 0)
+
+# ov == output variable... conditionally filled in by either git below:
+#
+set(cmd "")
+set(ov "")
+set(ev "")
+set(rv "")
+
+# If no GIT_EXECUTABLE, see if we can figure out which git was used
+# for the ctest_update step on this dashboard...
+#
+if(is_git_checkout AND NOT GIT_EXECUTABLE)
+ set(ctest_ini_file "")
+ set(exe "")
+
+ # Use the old name:
+ if(EXISTS "${CMake_BINARY_DIR}/DartConfiguration.tcl")
+ set(ctest_ini_file "${CMake_BINARY_DIR}/DartConfiguration.tcl")
+ endif()
+
+ # But if it exists, prefer the new name:
+ if(EXISTS "${CMake_BINARY_DIR}/CTestConfiguration.ini")
+ set(ctest_ini_file "${CMake_BINARY_DIR}/CTestConfiguration.ini")
+ endif()
+
+ # If there is a ctest ini file, read the update command or git command
+ # from it:
+ #
+ if(ctest_ini_file)
+ file(STRINGS "${ctest_ini_file}" line REGEX "^GITCommand: (.*)$")
+ string(REGEX REPLACE "^GITCommand: (.*)$" "\\1" line "${line}")
+ if("${line}" MATCHES "^\"")
+ string(REGEX REPLACE "^\"([^\"]+)\" *.*$" "\\1" line "${line}")
+ else()
+ string(REGEX REPLACE "^([^ ]+) *.*$" "\\1" line "${line}")
+ endif()
+ set(exe "${line}")
+ if("${exe}" STREQUAL "GITCOMMAND-NOTFOUND")
+ set(exe "")
+ endif()
+ if(exe)
+ message("info: GIT_EXECUTABLE set by 'GITCommand:' from '${ctest_ini_file}'")
+ endif()
+
+ if(NOT exe)
+ file(STRINGS "${ctest_ini_file}" line REGEX "^UpdateCommand: (.*)$")
+ string(REGEX REPLACE "^UpdateCommand: (.*)$" "\\1" line "${line}")
+ if("${line}" MATCHES "^\"")
+ string(REGEX REPLACE "^\"([^\"]+)\" *.*$" "\\1" line "${line}")
+ else()
+ string(REGEX REPLACE "^([^ ]+) *.*$" "\\1" line "${line}")
+ endif()
+ set(exe "${line}")
+ if("${exe}" STREQUAL "GITCOMMAND-NOTFOUND")
+ set(exe "")
+ endif()
+ if(exe)
+ message("info: GIT_EXECUTABLE set by 'UpdateCommand:' from '${ctest_ini_file}'")
+ endif()
+ endif()
+ else()
+ message("info: no DartConfiguration.tcl or CTestConfiguration.ini file...")
+ endif()
+
+ # If we have still not grokked the exe, look in the Update.xml file to see
+ # if we can parse it from there...
+ #
+ if(NOT exe)
+ file(GLOB_RECURSE update_xml_file "${CMake_BINARY_DIR}/Testing/Update.xml")
+ if(update_xml_file)
+ file(STRINGS "${update_xml_file}" line
+ REGEX "^.*<UpdateCommand>(.*)</UpdateCommand>$" LIMIT_COUNT 1)
+ string(REPLACE "&quot\;" "\"" line "${line}")
+ string(REGEX REPLACE "^.*<UpdateCommand>(.*)</UpdateCommand>$" "\\1" line "${line}")
+ if("${line}" MATCHES "^\"")
+ string(REGEX REPLACE "^\"([^\"]+)\" *.*$" "\\1" line "${line}")
+ else()
+ string(REGEX REPLACE "^([^ ]+) *.*$" "\\1" line "${line}")
+ endif()
+ if(line)
+ set(exe "${line}")
+ endif()
+ if(exe)
+ message("info: GIT_EXECUTABLE set by '<UpdateCommand>' from '${update_xml_file}'")
+ endif()
+ else()
+ message("info: no Update.xml file...")
+ endif()
+ endif()
+
+ if(exe)
+ set(GIT_EXECUTABLE "${exe}")
+ message("GIT_EXECUTABLE='${GIT_EXECUTABLE}'")
+ message("")
+
+ if(NOT EXISTS "${GIT_EXECUTABLE}")
+ message(FATAL_ERROR "GIT_EXECUTABLE does not exist...")
+ endif()
+ else()
+ message(FATAL_ERROR "could not determine GIT_EXECUTABLE...")
+ endif()
+endif()
+
+
+if(is_git_checkout AND GIT_EXECUTABLE)
+ # Check with "git status" if there are any local modifications to the
+ # CMake source tree:
+ #
+ message("=============================================================================")
+ message("This is a git checkout, using git to verify source tree....")
+ message("")
+
+ execute_process(COMMAND ${GIT_EXECUTABLE} --version
+ WORKING_DIRECTORY ${CMake_SOURCE_DIR}
+ OUTPUT_VARIABLE version_output
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ message("=== output of 'git --version' ===")
+ message("${version_output}")
+ message("=== end output ===")
+ message("")
+
+ execute_process(COMMAND ${GIT_EXECUTABLE} branch -a
+ WORKING_DIRECTORY ${CMake_SOURCE_DIR}
+ OUTPUT_VARIABLE git_branch_output
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ message("=== output of 'git branch -a' ===")
+ message("${git_branch_output}")
+ message("=== end output ===")
+ message("")
+
+ execute_process(COMMAND ${GIT_EXECUTABLE} log -1
+ WORKING_DIRECTORY ${CMake_SOURCE_DIR}
+ OUTPUT_VARIABLE git_log_output
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ message("=== output of 'git log -1' ===")
+ message("${git_log_output}")
+ message("=== end output ===")
+ message("")
+
+ message("Copy/paste this command to reproduce:")
+ message("cd \"${CMake_SOURCE_DIR}\" && \"${GIT_EXECUTABLE}\" status")
+ message("")
+
+ set(cmd ${GIT_EXECUTABLE} status)
+endif()
+
+
+if(cmd)
+ # Use the HOME value passed in to the script for calling git so it can
+ # find its user/global config settings...
+ #
+ set(original_ENV_HOME "$ENV{HOME}")
+ set(ENV{HOME} "${HOME}")
+
+ execute_process(COMMAND ${cmd}
+ WORKING_DIRECTORY ${CMake_SOURCE_DIR}
+ OUTPUT_VARIABLE ov
+ ERROR_VARIABLE ev
+ RESULT_VARIABLE rv)
+
+ set(ENV{HOME} "${original_ENV_HOME}")
+
+ message("Results of running ${cmd}")
+ message("rv='${rv}'")
+ message("ov='${ov}'")
+ message("ev='${ev}'")
+ message("")
+
+ if(NOT rv STREQUAL 0)
+ if(is_git_checkout AND (rv STREQUAL "1"))
+ # Many builds of git return "1" from a "nothing is changed" git status call...
+ # Do not fail with an error for rv==1 with git...
+ else()
+ message(FATAL_ERROR "error: ${cmd} attempt failed... (see output above)")
+ endif()
+ endif()
+else()
+ message(FATAL_ERROR "error: no COMMAND to run to analyze source tree...")
+endif()
+
+
+# Analyze output:
+#
+if(NOT ov STREQUAL "")
+ string(REPLACE ";" "\\\\;" lines "${ov}")
+ string(REPLACE "\n" "E;" lines "${lines}")
+
+ foreach(line ${lines})
+ message("'${line}'")
+
+ # But do not consider files that exist just because some user poked around
+ # the file system with Windows Explorer or with the Finder from a Mac...
+ # ('Thumbs.db' and '.DS_Store' files...)
+ #
+ set(consider 1)
+ set(ignore_files_regex "^(. |.*(/|\\\\))(\\.DS_Store|Thumbs.db)E$")
+ if(line MATCHES "${ignore_files_regex}")
+ message(" line matches '${ignore_files_regex}' -- not considered")
+ set(consider 0)
+ endif()
+
+ if(consider)
+ if(is_git_checkout)
+ if(line MATCHES "^#?[ \t]*modified:")
+ message(" locally modified file detected...")
+ set(modifications 1)
+ endif()
+
+ if(line MATCHES "^(# )?Untracked")
+ message(" locally non-added file/directory detected...")
+ set(nonadditions 1)
+ endif()
+ endif()
+ endif()
+ endforeach()
+endif()
+
+
+message("=============================================================================")
+message("additions='${additions}'")
+message("conflicts='${conflicts}'")
+message("modifications='${modifications}'")
+message("nonadditions='${nonadditions}'")
+message("")
+
+
+# Decide if the test passes or fails:
+#
+message("=============================================================================")
+
+if("$ENV{DASHBOARD_TEST_FROM_CTEST}" STREQUAL "")
+
+ # developers are allowed to have local additions and modifications...
+ message("interactive test run")
+ message("")
+
+else()
+
+ message("dashboard test run")
+ message("")
+
+ # but dashboard machines are not allowed to have local additions or modifications...
+ if(additions)
+ message(FATAL_ERROR "test fails: local source tree additions")
+ endif()
+
+ if(modifications)
+ message(FATAL_ERROR "test fails: local source tree modifications")
+ endif()
+
+ #
+ # It's a dashboard run if ctest was run with '-D ExperimentalTest' or some
+ # other -D arg on its command line or if ctest is running a -S script to run
+ # a dashboard... Running ctest like that sets the DASHBOARD_TEST_FROM_CTEST
+ # env var.
+ #
+
+endif()
+
+
+# ...and nobody is allowed to have local non-additions or conflicts...
+# Not even developers.
+#
+if(nonadditions)
+ if(in_source_build)
+ message("
+warning: test results confounded because this is an 'in-source' build - cannot
+distinguish between non-added files that are in-source build products and
+non-added source files that somebody forgot to 'git add'... - this is only ok
+if this is intentionally an in-source dashboard build... Developers should
+use out-of-source builds to verify a clean source tree with this test...
+
+Allowing test to pass despite the warning message...
+")
+ else()
+ message(FATAL_ERROR "test fails: local source tree non-additions: use git add before committing, or remove the files from the source tree")
+ endif()
+endif()
+
+if(conflicts)
+ message(FATAL_ERROR "test fails: local source tree conflicts: resolve before committing")
+endif()
+
+
+# Still here? Good then...
+#
+message("test passes")
+message("")
diff --git a/Tests/CMakeTests/CompilerIdVendorTest.cmake.in b/Tests/CMakeTests/CompilerIdVendorTest.cmake.in
new file mode 100644
index 0000000..9cf5321
--- /dev/null
+++ b/Tests/CMakeTests/CompilerIdVendorTest.cmake.in
@@ -0,0 +1,31 @@
+# This is not supposed to be included by user code, but we need to
+# test it.
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
+
+set(MY_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@/CompilerIdVendor")
+file(REMOVE_RECURSE ${MY_BINARY_DIR})
+file(MAKE_DIRECTORY ${MY_BINARY_DIR})
+
+set(CMAKE_MyLang_COMPILER ${CMAKE_COMMAND})
+set(CMAKE_MyLang_COMPILER_ID_ARG1)
+set(CMAKE_MyLang_COMPILER_ID_DIR ${MY_BINARY_DIR})
+
+file(WRITE "${MY_BINARY_DIR}/BogusVendor.cmake" "message(\"This is a BogusVendor compiler\")")
+list(APPEND CMAKE_MyLang_COMPILER_ID_VENDORS BogusVendor)
+set(CMAKE_MyLang_COMPILER_ID_VENDOR_FLAGS_BogusVendor -P BogusVendor.cmake)
+set(CMAKE_MyLang_COMPILER_ID_VENDOR_REGEX_BogusVendor ThisDoesNotMatch_BogusVendor)
+
+file(WRITE "${MY_BINARY_DIR}/MyVendor.cmake" "message(\"This is a MyVendor compiler\")")
+list(APPEND CMAKE_MyLang_COMPILER_ID_VENDORS MyVendor)
+set(CMAKE_MyLang_COMPILER_ID_VENDOR_FLAGS_MyVendor -P MyVendor.cmake)
+set(CMAKE_MyLang_COMPILER_ID_VENDOR_REGEX_MyVendor MyVendor)
+
+set(CMAKE_BINARY_DIR ${MY_BINARY_DIR})
+set(userflags)
+cmake_determine_compiler_id_vendor(MyLang "${userflags}")
+
+if("${CMAKE_MyLang_COMPILER_ID}" STREQUAL "MyVendor")
+ message(STATUS "Found MyVendor compiler id!")
+else()
+ message(FATAL_ERROR "Did not find MyVendor compiler id: [${CMAKE_MyLang_COMPILER_ID}]")
+endif()
diff --git a/Tests/CMakeTests/DummyToolchain.cmake b/Tests/CMakeTests/DummyToolchain.cmake
new file mode 100644
index 0000000..6a60201
--- /dev/null
+++ b/Tests/CMakeTests/DummyToolchain.cmake
@@ -0,0 +1,8 @@
+set(CMAKE_SYSTEM_NAME Dumdidum)
+set(CMAKE_SYSTEM_VERSION "1.0")
+
+set(CMAKE_C_COMPILER /opt/foo/bin/arm-elf-gcc)
+set(CMAKE_C_OUTPUT_EXTENSION ".foo")
+
+set(CMAKE_CXX_COMPILER /opt/bar/bin/cl.exe)
+set(CMAKE_CXX_OUTPUT_EXTENSION ".bar")
diff --git a/Tests/CMakeTests/EndStuffTest.cmake.in b/Tests/CMakeTests/EndStuffTest.cmake.in
new file mode 100644
index 0000000..de5dd50
--- /dev/null
+++ b/Tests/CMakeTests/EndStuffTest.cmake.in
@@ -0,0 +1,18 @@
+# Execute each test listed in:
+#
+set(scriptname "@CMAKE_CURRENT_SOURCE_DIR@/EndStuffTestScript.cmake")
+set(number_of_tests_expected 9)
+
+include("@CMAKE_CURRENT_SOURCE_DIR@/ExecuteScriptTests.cmake")
+execute_all_script_tests(${scriptname} number_of_tests_executed)
+
+# And verify that number_of_tests_executed is at least as many as we know
+# about as of this writing...
+#
+message(STATUS "scriptname='${scriptname}'")
+message(STATUS "number_of_tests_executed='${number_of_tests_executed}'")
+message(STATUS "number_of_tests_expected='${number_of_tests_expected}'")
+
+if(number_of_tests_executed LESS number_of_tests_expected)
+ message(FATAL_ERROR "error: some test cases were skipped")
+endif()
diff --git a/Tests/CMakeTests/EndStuffTestScript.cmake b/Tests/CMakeTests/EndStuffTestScript.cmake
new file mode 100644
index 0000000..e0d826d
--- /dev/null
+++ b/Tests/CMakeTests/EndStuffTestScript.cmake
@@ -0,0 +1,42 @@
+message(STATUS "testname='${testname}'")
+
+function(do_end content)
+ file(WRITE "${dir}/${testname}.cmake" "${content}")
+ execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake"
+ RESULT_VARIABLE rv)
+ if(NOT rv EQUAL 0)
+ message(FATAL_ERROR "${testname} failed")
+ endif()
+endfunction()
+
+if(testname STREQUAL bad_else) # fail
+ do_end("else()\n")
+
+elseif(testname STREQUAL bad_elseif) # fail
+ do_end("elseif()\n")
+
+elseif(testname STREQUAL bad_endforeach) # fail
+ do_end("endforeach()\n")
+
+elseif(testname STREQUAL bad_endfunction) # fail
+ do_end("endfunction()\n")
+
+elseif(testname STREQUAL bad_endif) # fail
+ do_end("cmake_minimum_required(VERSION 2.8.12)\nendif()\n")
+
+elseif(testname STREQUAL endif_low_min_version) # fail
+ do_end("cmake_minimum_required(VERSION 1.2)\nendif()\n")
+
+elseif(testname STREQUAL endif_no_min_version) # fail
+ do_end("endif()\n")
+
+elseif(testname STREQUAL bad_endmacro) # fail
+ do_end("endmacro()\n")
+
+elseif(testname STREQUAL bad_endwhile) # fail
+ do_end("endwhile()\n")
+
+else() # fail
+ message(FATAL_ERROR "testname='${testname}' - error: no such test in '${CMAKE_CURRENT_LIST_FILE}'")
+
+endif()
diff --git a/Tests/CMakeTests/ExecuteScriptTests.cmake b/Tests/CMakeTests/ExecuteScriptTests.cmake
new file mode 100644
index 0000000..bceac33
--- /dev/null
+++ b/Tests/CMakeTests/ExecuteScriptTests.cmake
@@ -0,0 +1,63 @@
+# This function calls the ${scriptname} file to execute one test case:
+#
+function(execute_one_script_test scriptname testname expected_result)
+ message("execute_one_script_test")
+ message("testname=[${testname}]")
+
+ execute_process(
+ COMMAND ${CMAKE_COMMAND}
+ -D "dir:STRING=${dir}"
+ -D "testname:STRING=${testname}"
+ -P "${scriptname}"
+ OUTPUT_VARIABLE out
+ ERROR_VARIABLE err
+ RESULT_VARIABLE result
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_STRIP_TRAILING_WHITESPACE
+ )
+
+ message("out=[${out}]")
+ message("err=[${err}]")
+
+ if(expected_result STREQUAL "fail")
+ # case expected to fail, result should be non-0...
+ # error if it's 0
+ if("${result}" STREQUAL "0")
+ message(SEND_ERROR "script failed: testname='${testname}' [${result}] actually passed, but expected to fail...")
+ endif()
+ else()
+ # case expected to pass, result should be 0...
+ # error if it's non-0
+ if(NOT "${result}" STREQUAL "0")
+ message(SEND_ERROR "script failed: testname='${testname}' [${result}] actually failed, but expected to pass...")
+ endif()
+ endif()
+
+ message("")
+endfunction()
+
+
+# This function reads the script file and calls execute_one_script_test for
+# each testname case listed in the script. To add new cases, simply edit the
+# script file and add an elseif() clause that matches 'regex' below.
+#
+function(execute_all_script_tests scriptname result)
+ file(READ "${scriptname}" script)
+
+ string(REPLACE ";" "\\\\;" script "${script}")
+ string(REPLACE "\n" "E;" script "${script}")
+
+ set(count 0)
+ set(regex "^ *(if|elseif) *\\( *testname +STREQUAL +\\\"*([^\\\"\\)]+)\\\"* *\\) *# *(fail|pass) *E$")
+
+ foreach(line ${script})
+ if(line MATCHES "${regex}")
+ set(testname "${CMAKE_MATCH_2}")
+ set(expected_result "${CMAKE_MATCH_3}")
+ math(EXPR count "${count} + 1")
+ execute_one_script_test(${scriptname} ${testname} ${expected_result})
+ endif()
+ endforeach()
+
+ set(${result} ${count} PARENT_SCOPE)
+endfunction()
diff --git a/Tests/CMakeTests/File-Copy-BadArg.cmake b/Tests/CMakeTests/File-Copy-BadArg.cmake
new file mode 100644
index 0000000..91952fc
--- /dev/null
+++ b/Tests/CMakeTests/File-Copy-BadArg.cmake
@@ -0,0 +1 @@
+file(COPY FileTest.cmake DESTINATION tmp PATTERN * BADARG)
diff --git a/Tests/CMakeTests/File-Copy-BadPerm.cmake b/Tests/CMakeTests/File-Copy-BadPerm.cmake
new file mode 100644
index 0000000..b5cc42f
--- /dev/null
+++ b/Tests/CMakeTests/File-Copy-BadPerm.cmake
@@ -0,0 +1 @@
+file(COPY FileTest.cmake DESTINATION tmp FILE_PERMISSIONS BADPERM)
diff --git a/Tests/CMakeTests/File-Copy-BadRegex.cmake b/Tests/CMakeTests/File-Copy-BadRegex.cmake
new file mode 100644
index 0000000..41340f6
--- /dev/null
+++ b/Tests/CMakeTests/File-Copy-BadRegex.cmake
@@ -0,0 +1 @@
+file(COPY FileTest.cmake DESTINATION tmp REGEX "(")
diff --git a/Tests/CMakeTests/File-Copy-EarlyArg.cmake b/Tests/CMakeTests/File-Copy-EarlyArg.cmake
new file mode 100644
index 0000000..03993de
--- /dev/null
+++ b/Tests/CMakeTests/File-Copy-EarlyArg.cmake
@@ -0,0 +1 @@
+file(COPY FileTest.cmake DESTINATION tmp PERMISSIONS)
diff --git a/Tests/CMakeTests/File-Copy-LateArg.cmake b/Tests/CMakeTests/File-Copy-LateArg.cmake
new file mode 100644
index 0000000..43d2168
--- /dev/null
+++ b/Tests/CMakeTests/File-Copy-LateArg.cmake
@@ -0,0 +1 @@
+file(COPY FileTest.cmake DESTINATION tmp PATTERN * FILE_PERMISSIONS)
diff --git a/Tests/CMakeTests/File-Copy-NoDest.cmake b/Tests/CMakeTests/File-Copy-NoDest.cmake
new file mode 100644
index 0000000..f6c6c6d
--- /dev/null
+++ b/Tests/CMakeTests/File-Copy-NoDest.cmake
@@ -0,0 +1 @@
+file(COPY FileTest.cmake)
diff --git a/Tests/CMakeTests/File-Copy-NoFile.cmake b/Tests/CMakeTests/File-Copy-NoFile.cmake
new file mode 100644
index 0000000..d5853d3
--- /dev/null
+++ b/Tests/CMakeTests/File-Copy-NoFile.cmake
@@ -0,0 +1 @@
+file(COPY does_not_exist.txt DESTINATION tmp)
diff --git a/Tests/CMakeTests/File-Glob-NoArg.cmake b/Tests/CMakeTests/File-Glob-NoArg.cmake
new file mode 100644
index 0000000..486f366
--- /dev/null
+++ b/Tests/CMakeTests/File-Glob-NoArg.cmake
@@ -0,0 +1,2 @@
+# Checking that the call without arguments get caught by the file global protection.
+file(GLOB)
diff --git a/Tests/CMakeTests/File-HASH-Input.txt b/Tests/CMakeTests/File-HASH-Input.txt
new file mode 100644
index 0000000..a1d315b
--- /dev/null
+++ b/Tests/CMakeTests/File-HASH-Input.txt
@@ -0,0 +1 @@
+sample input string
diff --git a/Tests/CMakeTests/File-MD5-BadArg1.cmake b/Tests/CMakeTests/File-MD5-BadArg1.cmake
new file mode 100644
index 0000000..ac5f67a
--- /dev/null
+++ b/Tests/CMakeTests/File-MD5-BadArg1.cmake
@@ -0,0 +1 @@
+file(MD5)
diff --git a/Tests/CMakeTests/File-MD5-BadArg2.cmake b/Tests/CMakeTests/File-MD5-BadArg2.cmake
new file mode 100644
index 0000000..2acc075
--- /dev/null
+++ b/Tests/CMakeTests/File-MD5-BadArg2.cmake
@@ -0,0 +1 @@
+file(MD5 ${CMAKE_CURRENT_LIST_DIR}/File-HASH-Input.txt)
diff --git a/Tests/CMakeTests/File-MD5-BadArg4.cmake b/Tests/CMakeTests/File-MD5-BadArg4.cmake
new file mode 100644
index 0000000..79b2755
--- /dev/null
+++ b/Tests/CMakeTests/File-MD5-BadArg4.cmake
@@ -0,0 +1 @@
+file(MD5 ${CMAKE_CURRENT_LIST_DIR}/File-HASH-Input.txt md5 extra_arg)
diff --git a/Tests/CMakeTests/File-MD5-NoFile.cmake b/Tests/CMakeTests/File-MD5-NoFile.cmake
new file mode 100644
index 0000000..1b91bc8
--- /dev/null
+++ b/Tests/CMakeTests/File-MD5-NoFile.cmake
@@ -0,0 +1 @@
+file(MD5 ${CMAKE_CURRENT_LIST_DIR}/DoesNotExist.cmake md5)
diff --git a/Tests/CMakeTests/File-MD5-Works.cmake b/Tests/CMakeTests/File-MD5-Works.cmake
new file mode 100644
index 0000000..0fabe54
--- /dev/null
+++ b/Tests/CMakeTests/File-MD5-Works.cmake
@@ -0,0 +1,2 @@
+file(MD5 ${CMAKE_CURRENT_LIST_DIR}/File-HASH-Input.txt md5)
+message("${md5}")
diff --git a/Tests/CMakeTests/File-SHA1-Works.cmake b/Tests/CMakeTests/File-SHA1-Works.cmake
new file mode 100644
index 0000000..f2ab5d7
--- /dev/null
+++ b/Tests/CMakeTests/File-SHA1-Works.cmake
@@ -0,0 +1,2 @@
+file(SHA1 ${CMAKE_CURRENT_LIST_DIR}/File-HASH-Input.txt sha1)
+message("${sha1}")
diff --git a/Tests/CMakeTests/File-SHA224-Works.cmake b/Tests/CMakeTests/File-SHA224-Works.cmake
new file mode 100644
index 0000000..3e86b17
--- /dev/null
+++ b/Tests/CMakeTests/File-SHA224-Works.cmake
@@ -0,0 +1,2 @@
+file(SHA224 ${CMAKE_CURRENT_LIST_DIR}/File-HASH-Input.txt sha224)
+message("${sha224}")
diff --git a/Tests/CMakeTests/File-SHA256-Works.cmake b/Tests/CMakeTests/File-SHA256-Works.cmake
new file mode 100644
index 0000000..b72d89e
--- /dev/null
+++ b/Tests/CMakeTests/File-SHA256-Works.cmake
@@ -0,0 +1,2 @@
+file(SHA256 ${CMAKE_CURRENT_LIST_DIR}/File-HASH-Input.txt sha256)
+message("${sha256}")
diff --git a/Tests/CMakeTests/File-SHA384-Works.cmake b/Tests/CMakeTests/File-SHA384-Works.cmake
new file mode 100644
index 0000000..0eeca33
--- /dev/null
+++ b/Tests/CMakeTests/File-SHA384-Works.cmake
@@ -0,0 +1,2 @@
+file(SHA384 ${CMAKE_CURRENT_LIST_DIR}/File-HASH-Input.txt sha384)
+message("${sha384}")
diff --git a/Tests/CMakeTests/File-SHA3_224-Works.cmake b/Tests/CMakeTests/File-SHA3_224-Works.cmake
new file mode 100644
index 0000000..e4f4e85
--- /dev/null
+++ b/Tests/CMakeTests/File-SHA3_224-Works.cmake
@@ -0,0 +1,2 @@
+file(SHA3_224 ${CMAKE_CURRENT_LIST_DIR}/File-HASH-Input.txt sha3_224)
+message("${sha3_224}")
diff --git a/Tests/CMakeTests/File-SHA3_256-Works.cmake b/Tests/CMakeTests/File-SHA3_256-Works.cmake
new file mode 100644
index 0000000..189c8a2
--- /dev/null
+++ b/Tests/CMakeTests/File-SHA3_256-Works.cmake
@@ -0,0 +1,2 @@
+file(SHA3_256 ${CMAKE_CURRENT_LIST_DIR}/File-HASH-Input.txt sha3_256)
+message("${sha3_256}")
diff --git a/Tests/CMakeTests/File-SHA3_384-Works.cmake b/Tests/CMakeTests/File-SHA3_384-Works.cmake
new file mode 100644
index 0000000..08f9f5b
--- /dev/null
+++ b/Tests/CMakeTests/File-SHA3_384-Works.cmake
@@ -0,0 +1,2 @@
+file(SHA3_384 ${CMAKE_CURRENT_LIST_DIR}/File-HASH-Input.txt sha3_384)
+message("${sha3_384}")
diff --git a/Tests/CMakeTests/File-SHA3_512-Works.cmake b/Tests/CMakeTests/File-SHA3_512-Works.cmake
new file mode 100644
index 0000000..4182196
--- /dev/null
+++ b/Tests/CMakeTests/File-SHA3_512-Works.cmake
@@ -0,0 +1,2 @@
+file(SHA3_512 ${CMAKE_CURRENT_LIST_DIR}/File-HASH-Input.txt sha3_512)
+message("${sha3_512}")
diff --git a/Tests/CMakeTests/File-SHA512-Works.cmake b/Tests/CMakeTests/File-SHA512-Works.cmake
new file mode 100644
index 0000000..d74ee44
--- /dev/null
+++ b/Tests/CMakeTests/File-SHA512-Works.cmake
@@ -0,0 +1,2 @@
+file(SHA512 ${CMAKE_CURRENT_LIST_DIR}/File-HASH-Input.txt sha512)
+message("${sha512}")
diff --git a/Tests/CMakeTests/File-TIMESTAMP-BadArg1.cmake b/Tests/CMakeTests/File-TIMESTAMP-BadArg1.cmake
new file mode 100644
index 0000000..cc15c77
--- /dev/null
+++ b/Tests/CMakeTests/File-TIMESTAMP-BadArg1.cmake
@@ -0,0 +1 @@
+file(TIMESTAMP "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt")
diff --git a/Tests/CMakeTests/File-TIMESTAMP-NoFile.cmake b/Tests/CMakeTests/File-TIMESTAMP-NoFile.cmake
new file mode 100644
index 0000000..62390e7
--- /dev/null
+++ b/Tests/CMakeTests/File-TIMESTAMP-NoFile.cmake
@@ -0,0 +1,2 @@
+file(TIMESTAMP "${CMAKE_CURRENT_LIST_DIR}/DoesNotExist.cmake" output)
+message("~${output}~")
diff --git a/Tests/CMakeTests/File-TIMESTAMP-NotBogus.cmake b/Tests/CMakeTests/File-TIMESTAMP-NotBogus.cmake
new file mode 100644
index 0000000..f1aa390
--- /dev/null
+++ b/Tests/CMakeTests/File-TIMESTAMP-NotBogus.cmake
@@ -0,0 +1,25 @@
+set(STAMP_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/FileTimestamp-Stamp")
+set(STAMP_FORMAT "%Y-%m-%d")
+
+unset(ENV{SOURCE_DATE_EPOCH})
+string(TIMESTAMP timestamp1 "${STAMP_FORMAT}")
+
+file(WRITE "${STAMP_FILENAME}" "foo")
+file(TIMESTAMP "${STAMP_FILENAME}" timestamp2 "${STAMP_FORMAT}")
+
+string(TIMESTAMP timestamp3 "${STAMP_FORMAT}")
+
+message(STATUS "timestamp1 [${timestamp1}]")
+message(STATUS "timestamp2 [${timestamp2}]")
+message(STATUS "timestamp3 [${timestamp3}]")
+
+if(timestamp1 STREQUAL timestamp3)
+ if(NOT timestamp1 STREQUAL timestamp2)
+ message(FATAL_ERROR
+ "timestamp mismatch [${timestamp1}] != [${timestamp2}]")
+ else()
+ message("all timestamps match")
+ endif()
+else()
+ message(WARNING "this test may race when run at midnight")
+endif()
diff --git a/Tests/CMakeTests/File-TIMESTAMP-Works.cmake b/Tests/CMakeTests/File-TIMESTAMP-Works.cmake
new file mode 100644
index 0000000..4351b19
--- /dev/null
+++ b/Tests/CMakeTests/File-TIMESTAMP-Works.cmake
@@ -0,0 +1,2 @@
+file(TIMESTAMP "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt" output UTC)
+message("~${output}~")
diff --git a/Tests/CMakeTests/FileDownloadBadHashTest.cmake.in b/Tests/CMakeTests/FileDownloadBadHashTest.cmake.in
new file mode 100644
index 0000000..64b45ed
--- /dev/null
+++ b/Tests/CMakeTests/FileDownloadBadHashTest.cmake.in
@@ -0,0 +1,13 @@
+if(NOT "@CMAKE_CURRENT_SOURCE_DIR@" MATCHES "^/")
+ set(slash /)
+endif()
+set(url "file://${slash}@CMAKE_CURRENT_SOURCE_DIR@/FileDownloadInput.png")
+set(dir "@CMAKE_CURRENT_BINARY_DIR@/downloads")
+
+file(DOWNLOAD
+ ${url}
+ ${dir}/file3.png
+ TIMEOUT 2
+ STATUS status
+ EXPECTED_HASH SHA1=5555555555555555555555555555555555555555
+ )
diff --git a/Tests/CMakeTests/FileDownloadInput.png b/Tests/CMakeTests/FileDownloadInput.png
new file mode 100644
index 0000000..9ab565a
--- /dev/null
+++ b/Tests/CMakeTests/FileDownloadInput.png
Binary files differ
diff --git a/Tests/CMakeTests/FileDownloadTest.cmake.in b/Tests/CMakeTests/FileDownloadTest.cmake.in
new file mode 100644
index 0000000..e0ce99a
--- /dev/null
+++ b/Tests/CMakeTests/FileDownloadTest.cmake.in
@@ -0,0 +1,181 @@
+# We do not contact any real URLs, but do try a bogus one.
+# Remove any proxy configuration that may change behavior.
+unset(ENV{http_proxy})
+unset(ENV{https_proxy})
+
+set(timeout 4)
+
+if(NOT "@CMAKE_CURRENT_SOURCE_DIR@" MATCHES "^/")
+ set(slash /)
+endif()
+set(url "file://${slash}@CMAKE_CURRENT_SOURCE_DIR@/FileDownloadInput.png")
+set(dir "@CMAKE_CURRENT_BINARY_DIR@/downloads")
+
+# Beware Windows asynchronous file/directory removal, rename and then
+# remove the renamed dir so we can be certain the dir isn't there when
+# we get to the file() commands below
+if(EXISTS "${dir}")
+ file(RENAME ${dir} "${dir}_beingRemoved")
+ file(REMOVE_RECURSE "${dir}_beingRemoved")
+endif()
+
+function(__reportIfWrongStatus statusPair expectedStatusCode)
+ list(GET statusPair 0 statusCode)
+ if(NOT statusCode EQUAL expectedStatusCode)
+ message(SEND_ERROR
+ "Unexpected status: ${statusCode}, expected: ${expectedStatusCode}")
+ endif()
+endfunction()
+
+message(STATUS "FileDownload:1")
+file(DOWNLOAD
+ ${url}
+ ${dir}/file1.png
+ TIMEOUT ${timeout}
+ STATUS status
+ )
+__reportIfWrongStatus("${status}" 0)
+
+message(STATUS "FileDownload:2")
+file(DOWNLOAD
+ ${url}
+ ${dir}/file2.png
+ TIMEOUT ${timeout}
+ STATUS status
+ SHOW_PROGRESS
+ )
+__reportIfWrongStatus("${status}" 0)
+
+# Two calls in a row, exactly the same arguments.
+# Since downloaded file should exist already for 2nd call,
+# the 2nd call will short-circuit and return early...
+#
+if(EXISTS ${dir}/file3.png)
+ file(REMOVE ${dir}/file3.png)
+endif()
+
+message(STATUS "FileDownload:3")
+file(DOWNLOAD
+ ${url}
+ ${dir}/file3.png
+ TIMEOUT ${timeout}
+ STATUS status
+ EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
+ )
+__reportIfWrongStatus("${status}" 0)
+
+message(STATUS "FileDownload:4")
+file(DOWNLOAD
+ ${url}
+ ${dir}/file3.png
+ TIMEOUT ${timeout}
+ STATUS status
+ EXPECTED_HASH SHA1=67eee17f79d9ac557284fc0b8ad19f25723fb578
+ )
+__reportIfWrongStatus("${status}" 0)
+
+message(STATUS "FileDownload:5")
+file(DOWNLOAD
+ ${url}
+ ${dir}/file3.png
+ TIMEOUT ${timeout}
+ STATUS status
+ EXPECTED_HASH SHA224=ba283726bbb602776818b463943189afd91836cb7ee5dd6e2c7b5ae4
+ )
+__reportIfWrongStatus("${status}" 0)
+
+message(STATUS "FileDownload:6")
+file(DOWNLOAD
+ ${url}
+ ${dir}/file3.png
+ TIMEOUT ${timeout}
+ STATUS status
+ EXPECTED_HASH SHA256=cf3334b1275071e1da6e8c396ccb72cf1b2388d8c937526f3af26230affb9423
+ )
+__reportIfWrongStatus("${status}" 0)
+
+message(STATUS "FileDownload:7")
+file(DOWNLOAD
+ ${url}
+ ${dir}/file3.png
+ TIMEOUT ${timeout}
+ STATUS status
+ EXPECTED_HASH SHA384=43a5d13978d97c660db44481aee0604cb4ff6ca0775cd5c2cd68cd8000e107e507c4caf6c228941231041e282ffb8950
+ )
+__reportIfWrongStatus("${status}" 0)
+
+message(STATUS "FileDownload:8")
+file(DOWNLOAD
+ ${url}
+ ${dir}/file3.png
+ TIMEOUT ${timeout}
+ STATUS status
+ EXPECTED_HASH SHA512=6984e0909a1018030ccaa418e3be1654223cdccff0fe6adc745f9aea7e377f178be53b9fc7d54a6f81c2b62ef9ddcd38ba1978fedf4c5e7139baaf355eefad5b
+ )
+__reportIfWrongStatus("${status}" 0)
+
+message(STATUS "FileDownload:9")
+file(DOWNLOAD
+ ${url}
+ ${dir}/file3.png
+ TIMEOUT ${timeout}
+ STATUS status
+ EXPECTED_HASH MD5=dbd330d52f4dbd60115d4191904ded92
+ )
+__reportIfWrongStatus("${status}" 0)
+
+message(STATUS "FileDownload:10")
+file(DOWNLOAD
+ ${url}
+ ${dir}/file3.png
+ TIMEOUT ${timeout}
+ STATUS status
+ EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
+ )
+__reportIfWrongStatus("${status}" 0)
+# Print status because we check its message too
+message(STATUS "${status}")
+
+# do not use proxy for lookup of invalid site (DNS failure by proxy looks
+# different than DNS failure without proxy)
+set(ENV{no_proxy} "$ENV{no_proxy},badhostname.invalid")
+message(STATUS "FileDownload:11")
+file(DOWNLOAD
+ badhostname.invalid
+ ${dir}/file11.png
+ TIMEOUT 30
+ STATUS status
+ )
+message(STATUS "${status}")
+__reportIfWrongStatus("${status}" 6) # 6 corresponds to an unresolvable host name
+
+message(STATUS "FileDownload:12")
+set(absFile "@CMAKE_CURRENT_BINARY_DIR@/file12.png")
+if(EXISTS "${absFile}")
+ file(RENAME ${absFile} "${absFile}_beingRemoved")
+ file(REMOVE "${absFile}_beingRemoved")
+endif()
+file(DOWNLOAD
+ ${url}
+ file12.png
+ TIMEOUT ${timeout}
+ EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
+ STATUS status
+ )
+__reportIfWrongStatus("${status}" 0)
+if(NOT EXISTS file12.png)
+ message(SEND_ERROR "file12.png not downloaded: ${status}")
+endif()
+
+message(STATUS "FileDownload:13")
+file(DOWNLOAD
+ ${url}
+ TIMEOUT ${timeout}
+ STATUS status
+ )
+__reportIfWrongStatus("${status}" 0)
+if(EXISTS TIMEOUT)
+ file(REMOVE TIMEOUT)
+ message(SEND_ERROR "TIMEOUT argument was incorrectly interpreted as a filename")
+endif()
+message(STATUS "${status}")
diff --git a/Tests/CMakeTests/FileTest.cmake.in b/Tests/CMakeTests/FileTest.cmake.in
new file mode 100644
index 0000000..71cb3db
--- /dev/null
+++ b/Tests/CMakeTests/FileTest.cmake.in
@@ -0,0 +1,109 @@
+set(Copy-BadArg-RESULT 1)
+set(Copy-BadArg-STDERR "unknown argument \"BADARG\"")
+set(Copy-BadPerm-RESULT 1)
+set(Copy-BadPerm-STDERR "COPY given invalid permission \"BADPERM\"")
+set(Copy-BadRegex-RESULT 1)
+set(Copy-BadRegex-STDERR "could not compile REGEX")
+set(Copy-EarlyArg-RESULT 1)
+set(Copy-EarlyArg-STDERR "option PERMISSIONS may not appear before")
+set(Copy-LateArg-RESULT 1)
+set(Copy-LateArg-STDERR "option FILE_PERMISSIONS may not appear after")
+set(Copy-NoDest-RESULT 1)
+set(Copy-NoDest-STDERR "given no DESTINATION")
+set(Copy-NoFile-RESULT 1)
+set(Copy-NoFile-STDERR "COPY cannot find.*/does_not_exist\\.txt")
+set(Glob-NoArg-RESULT 1)
+set(Glob-NoArg-STDERR "file must be called with at least two arguments")
+set(Make_Directory-NoArg-RESULT 1)
+set(Make-Directory-NoArg-STDERR "file must be called with at least two arguments")
+set(MD5-NoFile-RESULT 1)
+set(MD5-NoFile-STDERR "file MD5 failed to read file")
+set(MD5-BadArg1-RESULT 1)
+set(MD5-BadArg1-STDERR "file must be called with at least two arguments")
+set(MD5-BadArg2-RESULT 1)
+set(MD5-BadArg2-STDERR "file MD5 requires a file name and output variable")
+set(MD5-BadArg4-RESULT 1)
+set(MD5-BadArg4-STDERR "file MD5 requires a file name and output variable")
+set(MD5-Works-RESULT 0)
+set(MD5-Works-STDERR "10d20ddb981a6202b84aa1ce1cb7fce3")
+set(SHA1-Works-RESULT 0)
+set(SHA1-Works-STDERR "83f093e04289b21a9415f408ad50be8b57ad2f34")
+set(SHA224-Works-RESULT 0)
+set(SHA224-Works-STDERR "e995a7789922c4ef9279d94e763c8375934180a51baa7147bc48edf7")
+set(SHA256-Works-RESULT 0)
+set(SHA256-Works-STDERR "d1c5915d8b71150726a1eef75a29ec6bea8fd1bef6b7299ef8048760b0402025")
+set(SHA384-Works-RESULT 0)
+set(SHA384-Works-STDERR "1de9560b4e030e02051ea408200ffc55d70c97ac64ebf822461a5c786f495c36df43259b14483bc8d364f0106f4971ee")
+set(SHA512-Works-RESULT 0)
+set(SHA512-Works-STDERR "3982a1b4e651768bec70ab1fb97045cb7a659f4ba7203d501c52ab2e803071f9d5fd272022df15f27727fc67f8cd022e710e29010b2a9c0b467c111e2f6abf51")
+set(SHA3_224-Works-RESULT 0)
+set(SHA3_224-Works-STDERR "4272868085f4f25080681a7712509fd12e16dcda79bd356836dd2100")
+set(SHA3_256-Works-RESULT 0)
+set(SHA3_256-Works-STDERR "be0df472b6bd474417a166d12f2774f2ef5095e86f0a88ef4c78c703800cfc8a")
+set(SHA3_384-Works-RESULT 0)
+set(SHA3_384-Works-STDERR "935a17cc708443c1369549483656a4521af03a52e4f3b314566272017ccae03a2c5db838f6d4c156b1dc5c366182481b")
+set(SHA3_512-Works-RESULT 0)
+set(SHA3_512-Works-STDERR "471a85ed537e8f77f31412a089f22d836054ffa179599f87a5d7568927d8fa236b6793ded8a387d1de92398c967177bcc6361672a722bf736cb0f63a0956d5cf")
+set(TIMESTAMP-NoFile-RESULT 0)
+set(TIMESTAMP-NoFile-STDERR "~~")
+set(TIMESTAMP-BadArg1-RESULT 1)
+set(TIMESTAMP-BadArg1-STDERR "file sub-command TIMESTAMP requires at least two arguments")
+set(TIMESTAMP-NotBogus-RESULT 0)
+set(TIMESTAMP-NotBogus-STDERR "all timestamps match")
+set(TIMESTAMP-Works-RESULT 0)
+set(TIMESTAMP-Works-STDERR "~[0-9]*-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-6][0-9]Z~")
+
+include("@CMAKE_CURRENT_SOURCE_DIR@/CheckCMakeTest.cmake")
+check_cmake_test(File
+ Copy-BadArg
+ Copy-BadPerm
+ Copy-BadRegex
+ Copy-EarlyArg
+ Copy-LateArg
+ Copy-NoDest
+ Copy-NoFile
+ Glob-NoArg
+ Make_Directory-NoArg
+ MD5-NoFile
+ MD5-BadArg1
+ MD5-BadArg2
+ MD5-BadArg4
+ MD5-Works
+ SHA1-Works
+ SHA224-Works
+ SHA256-Works
+ SHA384-Works
+ SHA512-Works
+ SHA3_224-Works
+ SHA3_256-Works
+ SHA3_384-Works
+ SHA3_512-Works
+ TIMESTAMP-NoFile
+ TIMESTAMP-BadArg1
+ TIMESTAMP-NotBogus
+ TIMESTAMP-Works
+ )
+
+file(GLOB hum)
+if (NOT hum STREQUAL "")
+ message(FATAL_ERROR "file(GLOB hum) did not return an empty string.")
+endif()
+
+# Also execute each test listed in FileTestScript.cmake:
+#
+set(scriptname "@CMAKE_CURRENT_SOURCE_DIR@/FileTestScript.cmake")
+set(number_of_tests_expected 62)
+
+include("@CMAKE_CURRENT_SOURCE_DIR@/ExecuteScriptTests.cmake")
+execute_all_script_tests(${scriptname} number_of_tests_executed)
+
+# And verify that number_of_tests_executed is at least as many as we know
+# about as of this writing...
+#
+message(STATUS "scriptname='${scriptname}'")
+message(STATUS "number_of_tests_executed='${number_of_tests_executed}'")
+message(STATUS "number_of_tests_expected='${number_of_tests_expected}'")
+
+if(number_of_tests_executed LESS number_of_tests_expected)
+ message(FATAL_ERROR "error: some test cases were skipped")
+endif()
diff --git a/Tests/CMakeTests/FileTestScript.cmake b/Tests/CMakeTests/FileTestScript.cmake
new file mode 100644
index 0000000..fc3c28a
--- /dev/null
+++ b/Tests/CMakeTests/FileTestScript.cmake
@@ -0,0 +1,227 @@
+message(STATUS "testname='${testname}'")
+
+if(testname STREQUAL empty) # fail
+ file()
+
+elseif(testname STREQUAL bogus) # fail
+ file(BOGUS ffff)
+
+elseif(testname STREQUAL different_not_enough_args) # fail
+ file(DIFFERENT ffff)
+
+elseif(testname STREQUAL download_not_enough_args) # fail
+ file(DOWNLOAD)
+
+elseif(testname STREQUAL read_not_enough_args) # fail
+ file(READ ffff)
+
+elseif(testname STREQUAL rpath_check_not_enough_args) # fail
+ file(RPATH_CHECK ffff)
+
+elseif(testname STREQUAL rpath_remove_not_enough_args) # fail
+ file(RPATH_REMOVE ffff)
+
+elseif(testname STREQUAL strings_not_enough_args) # fail
+ file(STRINGS ffff)
+
+elseif(testname STREQUAL to_native_path_not_enough_args) # fail
+ file(TO_NATIVE_PATH ffff)
+
+elseif(testname STREQUAL read_with_offset) # pass
+ file(READ ${CMAKE_CURRENT_LIST_FILE} v OFFSET 42 LIMIT 30)
+ message("v='${v}'")
+
+elseif(testname STREQUAL strings_bad_length_minimum) # fail
+ file(STRINGS ${CMAKE_CURRENT_LIST_FILE} v LENGTH_MINIMUM bogus)
+
+elseif(testname STREQUAL strings_bad_length_maximum) # fail
+ file(STRINGS ${CMAKE_CURRENT_LIST_FILE} v LENGTH_MAXIMUM bogus)
+
+elseif(testname STREQUAL strings_bad_limit_count) # fail
+ file(STRINGS ${CMAKE_CURRENT_LIST_FILE} v LIMIT_COUNT bogus)
+
+elseif(testname STREQUAL strings_bad_limit_input) # fail
+ file(STRINGS ${CMAKE_CURRENT_LIST_FILE} v LIMIT_INPUT bogus)
+
+elseif(testname STREQUAL strings_bad_limit_output) # fail
+ file(STRINGS ${CMAKE_CURRENT_LIST_FILE} v LIMIT_OUTPUT bogus)
+
+elseif(testname STREQUAL strings_bad_regex) # fail
+ file(STRINGS ${CMAKE_CURRENT_LIST_FILE} v REGEX "(")
+
+elseif(testname STREQUAL strings_unknown_arg) # fail
+ file(STRINGS ${CMAKE_CURRENT_LIST_FILE} v BOGUS)
+
+elseif(testname STREQUAL strings_bad_filename) # fail
+ file(STRINGS ffff v LIMIT_COUNT 10)
+
+elseif(testname STREQUAL strings_use_limit_count) # pass
+ file(STRINGS ${CMAKE_CURRENT_LIST_FILE} v LIMIT_COUNT 10)
+ message("v='${v}'")
+
+elseif(testname STREQUAL strings_use_no_hex_conversion) # pass
+ file(STRINGS ${CMAKE_CURRENT_LIST_FILE} v NO_HEX_CONVERSION)
+ message("v='${v}'")
+
+elseif(testname STREQUAL glob_recurse_follow_symlinks_no_expression) # fail
+ file(GLOB_RECURSE v FOLLOW_SYMLINKS)
+
+elseif(testname STREQUAL glob_recurse_relative_no_directory) # fail
+ file(GLOB_RECURSE v RELATIVE)
+
+elseif(testname STREQUAL glob_recurse_relative_no_expression) # fail
+ file(GLOB_RECURSE v RELATIVE dddd)
+
+elseif(testname STREQUAL glob_non_full_path) # pass
+ file(GLOB_RECURSE v ffff*.*)
+ message("v='${v}'")
+
+elseif(testname STREQUAL make_directory_non_full_path) # pass
+ file(MAKE_DIRECTORY FileTestScriptDDDD)
+ if(NOT EXISTS FileTestScriptDDDD)
+ message(FATAL_ERROR "error: non-full-path MAKE_DIRECTORY failed")
+ endif()
+ file(REMOVE_RECURSE FileTestScriptDDDD)
+ if(EXISTS FileTestScriptDDDD)
+ message(FATAL_ERROR "error: non-full-path REMOVE_RECURSE failed")
+ endif()
+
+elseif(testname STREQUAL different_no_variable) # fail
+ file(DIFFERENT FILES)
+
+elseif(testname STREQUAL different_no_files) # fail
+ file(DIFFERENT v FILES)
+
+elseif(testname STREQUAL different_unknown_arg) # fail
+ file(DIFFERENT v FILES ffffLHS ffffRHS BOGUS)
+
+elseif(testname STREQUAL different_different) # pass
+ file(DIFFERENT v FILES ffffLHS ffffRHS)
+ message("v='${v}'")
+
+elseif(testname STREQUAL different_same) # pass
+ file(DIFFERENT v FILES
+ ${CMAKE_CURRENT_LIST_FILE} ${CMAKE_CURRENT_LIST_FILE})
+ message("v='${v}'")
+
+elseif(testname STREQUAL rpath_change_unknown_arg) # fail
+ file(RPATH_CHANGE BOGUS)
+
+elseif(testname STREQUAL rpath_change_bad_file) # fail
+ file(RPATH_CHANGE FILE)
+
+elseif(testname STREQUAL rpath_change_bad_old_rpath) # fail
+ file(RPATH_CHANGE FILE ffff OLD_RPATH)
+
+elseif(testname STREQUAL rpath_change_bad_new_rpath) # fail
+ file(RPATH_CHANGE FILE ffff OLD_RPATH rrrr NEW_RPATH)
+
+elseif(testname STREQUAL rpath_change_file_does_not_exist) # fail
+ file(RPATH_CHANGE FILE ffff OLD_RPATH rrrr NEW_RPATH RRRR)
+
+elseif(testname STREQUAL rpath_change_file_is_not_executable) # fail
+ file(RPATH_CHANGE FILE ${CMAKE_CURRENT_LIST_FILE}
+ OLD_RPATH rrrr NEW_RPATH RRRR)
+
+elseif(testname STREQUAL rpath_remove_unknown_arg) # fail
+ file(RPATH_REMOVE BOGUS)
+
+elseif(testname STREQUAL rpath_remove_bad_file) # fail
+ file(RPATH_REMOVE FILE)
+
+elseif(testname STREQUAL rpath_remove_file_does_not_exist) # fail
+ file(RPATH_REMOVE FILE ffff)
+
+#elseif(testname STREQUAL rpath_remove_file_is_not_executable) # fail
+# file(RPATH_REMOVE FILE ${CMAKE_CURRENT_LIST_FILE})
+
+elseif(testname STREQUAL rpath_check_unknown_arg) # fail
+ file(RPATH_CHECK BOGUS)
+
+elseif(testname STREQUAL rpath_check_bad_file) # fail
+ file(RPATH_CHECK FILE)
+
+elseif(testname STREQUAL rpath_check_bad_rpath) # fail
+ file(RPATH_CHECK FILE ffff RPATH)
+
+elseif(testname STREQUAL rpath_check_file_does_not_exist) # pass
+ file(RPATH_CHECK FILE ffff RPATH rrrr)
+
+elseif(testname STREQUAL rpath_check_file_is_not_executable) # pass
+ file(WRITE ffff_rpath_check "")
+
+ if(NOT EXISTS ffff_rpath_check)
+ message(FATAL_ERROR "error: non-full-path WRITE failed")
+ endif()
+
+ file(RPATH_CHECK FILE ffff_rpath_check RPATH rrrr)
+ # careful: if the file does not have the given RPATH, it is deleted...
+
+ if(EXISTS ffff_rpath_check)
+ message(FATAL_ERROR "error: non-full-path RPATH_CHECK failed")
+ endif()
+
+elseif(testname STREQUAL relative_path_wrong_number_of_args) # fail
+ file(RELATIVE_PATH v dir)
+
+elseif(testname STREQUAL relative_path_non_full_path_dir) # fail
+ file(RELATIVE_PATH v dir file)
+
+elseif(testname STREQUAL relative_path_non_full_path_file) # fail
+ file(RELATIVE_PATH v /dir file)
+
+elseif(testname STREQUAL rename_wrong_number_of_args) # fail
+ file(RENAME ffff)
+
+elseif(testname STREQUAL rename_input_file_does_not_exist) # fail
+ file(RENAME ffff FFFFGGGG)
+
+elseif(testname STREQUAL to_native_path) # pass
+ file(TO_NATIVE_PATH /a/b/c\;/d/e/f:/g/h/i v)
+ message("v='${v}'")
+
+elseif(testname STREQUAL download_wrong_number_of_args) # fail
+ file(DOWNLOAD)
+
+elseif(testname STREQUAL download_file_with_no_path) # pass
+ file(DOWNLOAD zzzz://bogus/ffff ffff)
+
+elseif(testname STREQUAL download_missing_time) # fail
+ file(DOWNLOAD zzzz://bogus/ffff ./ffff TIMEOUT)
+
+elseif(testname STREQUAL download_missing_log_var) # fail
+ file(DOWNLOAD zzzz://bogus/ffff ./ffff TIMEOUT 2 LOG)
+
+elseif(testname STREQUAL download_missing_status_var) # fail
+ file(DOWNLOAD zzzz://bogus/ffff ./ffff TIMEOUT 2 LOG l STATUS)
+
+elseif(testname STREQUAL download_with_bogus_protocol) # pass
+ file(DOWNLOAD zzzz://bogus/ffff ./ffff TIMEOUT 2 LOG l STATUS s)
+ file(REMOVE ./ffff)
+ message("l='${l}'")
+ message("s='${s}'")
+
+elseif(testname STREQUAL upload_wrong_number_of_args) # fail
+ file(UPLOAD ./ffff)
+
+elseif(testname STREQUAL upload_missing_time) # fail
+ file(UPLOAD ./ffff zzzz://bogus/ffff TIMEOUT)
+
+elseif(testname STREQUAL upload_missing_log_var) # fail
+ file(UPLOAD ./ffff zzzz://bogus/ffff TIMEOUT 2 LOG)
+
+elseif(testname STREQUAL upload_missing_status_var) # fail
+ file(UPLOAD ./ffff zzzz://bogus/ffff TIMEOUT 2 LOG l STATUS)
+
+elseif(testname STREQUAL upload_file_that_doesnt_exist) # fail
+ file(UPLOAD ./ffff zzzz://bogus/ffff)
+
+elseif(testname STREQUAL upload_with_bogus_protocol) # pass
+ file(UPLOAD ${CMAKE_CURRENT_LIST_FILE} zzzz://bogus/ffff TIMEOUT 2 LOG l STATUS s)
+ message("l='${l}'")
+ message("s='${s}'")
+
+else() # fail
+ message(FATAL_ERROR "testname='${testname}' - error: no such test in '${CMAKE_CURRENT_LIST_FILE}'")
+
+endif()
diff --git a/Tests/CMakeTests/FileUploadTest.cmake.in b/Tests/CMakeTests/FileUploadTest.cmake.in
new file mode 100644
index 0000000..0e6f080
--- /dev/null
+++ b/Tests/CMakeTests/FileUploadTest.cmake.in
@@ -0,0 +1,52 @@
+file(REMOVE_RECURSE "@CMAKE_CURRENT_BINARY_DIR@/uploads")
+
+if(EXISTS "@CMAKE_CURRENT_BINARY_DIR@/uploads/file1.png")
+ message(FATAL_ERROR "error: file1.png exists - should have been deleted")
+endif()
+if(EXISTS "@CMAKE_CURRENT_BINARY_DIR@/uploads/file2.png")
+ message(FATAL_ERROR "error: file2.png exists - should have been deleted")
+endif()
+
+file(MAKE_DIRECTORY "@CMAKE_CURRENT_BINARY_DIR@/uploads")
+
+set(filename "@CMAKE_CURRENT_SOURCE_DIR@/FileDownloadInput.png")
+if(NOT "@CMAKE_CURRENT_BINARY_DIR@" MATCHES "^/")
+ set(slash /)
+endif()
+set(urlbase "file://${slash}@CMAKE_CURRENT_BINARY_DIR@/uploads")
+
+message(STATUS "FileUpload:1")
+file(UPLOAD
+ ${filename}
+ ${urlbase}/file1.png
+ TIMEOUT 2
+ )
+
+message(STATUS "FileUpload:2")
+file(UPLOAD
+ ${filename}
+ ${urlbase}/file2.png
+ STATUS status
+ LOG log
+ SHOW_PROGRESS
+ )
+
+execute_process(COMMAND ${CMAKE_COMMAND} -E md5sum
+ "@CMAKE_CURRENT_BINARY_DIR@/uploads/file1.png"
+ OUTPUT_VARIABLE sum1
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+if(NOT sum1 MATCHES "^dbd330d52f4dbd60115d4191904ded92 .*/uploads/file1.png$")
+ message(FATAL_ERROR "file1.png did not upload correctly (sum1='${sum1}')")
+endif()
+
+execute_process(COMMAND ${CMAKE_COMMAND} -E md5sum
+ "@CMAKE_CURRENT_BINARY_DIR@/uploads/file2.png"
+ OUTPUT_VARIABLE sum2
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+if(NOT sum2 MATCHES "^dbd330d52f4dbd60115d4191904ded92 .*/uploads/file2.png$")
+ message(FATAL_ERROR "file2.png did not upload correctly (sum2='${sum2}')")
+endif()
+
+message(STATUS "log='${log}'")
+message(STATUS "status='${status}'")
+message(STATUS "DONE")
diff --git a/Tests/CMakeTests/FindBaseTest.cmake.in b/Tests/CMakeTests/FindBaseTest.cmake.in
new file mode 100644
index 0000000..658b350
--- /dev/null
+++ b/Tests/CMakeTests/FindBaseTest.cmake.in
@@ -0,0 +1,62 @@
+set(MY_SOURCE_DIR "@CMAKE_CURRENT_SOURCE_DIR@")
+
+# The find_* commands do path normalization so we should do so too
+# before comparing results.
+get_filename_component(MY_SOURCE_DIR "${MY_SOURCE_DIR}" ABSOLUTE)
+
+set(_HEADER cmake_i_do_not_exist_in_the_system.h)
+set(_HEADER_FULL "${MY_SOURCE_DIR}/include/${_HEADER}")
+set(_HEADER_FULL_A "${MY_SOURCE_DIR}/A/include/${_HEADER}")
+
+# at first check that the header isn't found without special measures
+find_file(FOO_H_1 ${_HEADER})
+if(FOO_H_1)
+ message(FATAL_ERROR "${_HEADER} found: ${FOO_H_1}, it should not exist !")
+endif()
+
+# The HINTS option should override the system but the PATHS option
+# should not.
+set(CMAKE_SYSTEM_PREFIX_PATH ${MY_SOURCE_DIR})
+find_file(TEST_H_1 ${_HEADER} HINTS ${MY_SOURCE_DIR}/A/include)
+find_file(TEST_H_2 ${_HEADER} PATHS ${MY_SOURCE_DIR}/A/include)
+if(NOT "${TEST_H_1}" STREQUAL "${_HEADER_FULL_A}")
+ message(FATAL_ERROR "Did not find \"${_HEADER_FULL_A}\"\ngot \"${TEST_H_1}\" instead!")
+endif()
+if(NOT "${TEST_H_2}" STREQUAL "${_HEADER_FULL}")
+ message(FATAL_ERROR "Did not find \"${_HEADER_FULL}\"\ngot \"${TEST_H_2}\" instead!")
+endif()
+set(CMAKE_SYSTEM_PREFIX_PATH)
+
+# with this it still should not be found, since the include/ subdir is still missing
+set(CMAKE_INCLUDE_PATH "${MY_SOURCE_DIR}")
+find_file(FOO_H_2 ${_HEADER})
+if(FOO_H_2)
+ message(FATAL_ERROR "${_HEADER} found: ${FOO_H_2}, it should not exist !")
+endif()
+
+# now with the PATH_SUFFIX it should be found
+find_file(FOO_H_3 NAMES ${_HEADER} PATH_SUFFIXES include )
+if(NOT "${FOO_H_3}" STREQUAL "${_HEADER_FULL}")
+ message(FATAL_ERROR "Did not find \"${_HEADER_FULL}\"\ngot ${FOO_H_3} instead !")
+endif()
+
+# without PATH_SUFFIX, but with a CMAKE_INCLUDE_PATH it should not be found
+set(CMAKE_INCLUDE_PATH /include)
+find_file(FOO_H_4 ${_HEADER})
+if(FOO_H_4)
+ message(FATAL_ERROR "${_HEADER} found: ${FOO_H_4}, it should not exist !")
+endif()
+
+# when setting CMAKE_FIND_ROOT_PATH to the current source dir,
+# together with the CMAKE_INCLUDE_PATH it should be found
+set(CMAKE_FIND_ROOT_PATH blub "${MY_SOURCE_DIR}")
+find_file(FOO_H_5 ${_HEADER})
+if(NOT "${FOO_H_5}" STREQUAL "${_HEADER_FULL}")
+ message(FATAL_ERROR "Did not find \"${_HEADER_FULL}\"\ngot ${FOO_H_5} instead !")
+endif()
+
+# by explicitly disabling CMAKE_FIND_ROOT_PATH again it shouldn't be found
+find_file(FOO_H_6 ${_HEADER} NO_CMAKE_FIND_ROOT_PATH)
+if(FOO_H_6)
+ message(FATAL_ERROR "${_HEADER} found: ${FOO_H_6}, it should not exist !")
+endif()
diff --git a/Tests/CMakeTests/GetFilenameComponentRealpathTest.cmake.in b/Tests/CMakeTests/GetFilenameComponentRealpathTest.cmake.in
new file mode 100644
index 0000000..22f6afd
--- /dev/null
+++ b/Tests/CMakeTests/GetFilenameComponentRealpathTest.cmake.in
@@ -0,0 +1,72 @@
+set(bindir ${CMAKE_CURRENT_BINARY_DIR})
+
+#
+# Test nonexistent REALPATH & ABSOLUTE resolution
+#
+get_filename_component(nonexistent1 ${bindir}/THIS_IS_A_NONEXISTENT_FILE REALPATH)
+get_filename_component(nonexistent2 ${bindir}/THIS_IS_A_NONEXISTENT_FILE ABSOLUTE)
+if(NOT nonexistent1 STREQUAL "${bindir}/THIS_IS_A_NONEXISTENT_FILE")
+ message(FATAL_ERROR "REALPATH is not preserving nonexistent files")
+endif()
+if(NOT nonexistent2 STREQUAL "${bindir}/THIS_IS_A_NONEXISTENT_FILE")
+ message(FATAL_ERROR "ABSOLUTE is not preserving nonexistent files")
+endif()
+
+#
+# Test treatment of relative paths
+#
+foreach(c REALPATH ABSOLUTE)
+ get_filename_component(dir "subdir/THIS_IS_A_NONEXISTENT_FILE" ${c})
+ if(NOT "${dir}" STREQUAL "${bindir}/subdir/THIS_IS_A_NONEXISTENT_FILE")
+ message(FATAL_ERROR
+ "${c} does not handle relative paths. Expected:\n"
+ " ${bindir}/subdir/THIS_IS_A_NONEXISTENT_FILE\n"
+ "but got:\n"
+ " ${nonexistent1}\n"
+ )
+ endif()
+endforeach()
+
+#
+# Test symbolic link resolution
+#
+if(UNIX)
+ # file1 => file2 => file3 (real)
+ file(WRITE ${bindir}/file3 "test file")
+
+ find_program(LN NAMES "ln")
+ if(LN)
+ # Create symlinks using "ln -s"
+ if(NOT EXISTS ${bindir}/file2)
+ execute_process(COMMAND ${LN} "-s" "${bindir}/file3" "${bindir}/file2")
+ endif()
+ if(NOT EXISTS ${bindir}/file1)
+ execute_process(COMMAND ${LN} "-s" "${bindir}/file2" "${bindir}/file1")
+ endif()
+
+ get_filename_component(file1 ${bindir}/file1 REALPATH)
+ get_filename_component(file2 ${bindir}/file2 REALPATH)
+ get_filename_component(file3 ${bindir}/file3 REALPATH)
+
+ if(NOT file3 STREQUAL "${bindir}/file3")
+ message(FATAL_ERROR "CMake fails resolving REALPATH file file3")
+ endif()
+
+ if(NOT file2 STREQUAL "${bindir}/file3")
+ message(FATAL_ERROR "CMake fails resolving simple symlink")
+ endif()
+
+ if(NOT file1 STREQUAL "${bindir}/file3")
+ message(FATAL_ERROR "CMake fails resolving double symlink")
+ endif()
+
+ # cleanup
+ file(REMOVE ${bindir}/file1)
+ file(REMOVE ${bindir}/file2)
+ if(EXISTS file1 OR EXISTS file2)
+ message(FATAL_ERROR "removal of file1 or file2 failed")
+ endif()
+ endif()
+
+ file(REMOVE ${bindir}/file3)
+endif()
diff --git a/Tests/CMakeTests/GetPrerequisitesTest.cmake.in b/Tests/CMakeTests/GetPrerequisitesTest.cmake.in
new file mode 100644
index 0000000..7325b87
--- /dev/null
+++ b/Tests/CMakeTests/GetPrerequisitesTest.cmake.in
@@ -0,0 +1,156 @@
+# Test of the functions in the CMake Modules file:
+#
+include(GetPrerequisites)
+
+set(CMAKE_EXECUTABLE_SUFFIX "@CMAKE_EXECUTABLE_SUFFIX@")
+
+
+message(STATUS "=============================================================================")
+message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+message(STATUS "")
+message(STATUS "Configuration '${Configuration}'")
+message(STATUS "CMAKE_COMMAND='${CMAKE_COMMAND}'")
+message(STATUS "CMAKE_EXECUTABLE_SUFFIX='${CMAKE_EXECUTABLE_SUFFIX}'")
+message(STATUS "")
+
+
+function(stresstest_list_prerequisites file)
+ message(STATUS "=============================================================================")
+ message(STATUS "stresstest_list_prerequisites file='${file}'")
+ message(STATUS "")
+
+ get_filename_component(file_full "${file}" ABSOLUTE)
+
+ message(STATUS "list_prerequisites '${file_full}' 0 0 0")
+ list_prerequisites("${file_full}" 0 0 0)
+ message(STATUS "")
+
+ message(STATUS "list_prerequisites '${file_full}' 0 0 1")
+ list_prerequisites("${file_full}" 0 0 1)
+ message(STATUS "")
+
+ message(STATUS "list_prerequisites '${file_full}' 0 1 0")
+ list_prerequisites("${file_full}" 0 1 0)
+ message(STATUS "")
+
+ message(STATUS "list_prerequisites '${file_full}' 0 1 1")
+ list_prerequisites("${file_full}" 0 1 1)
+ message(STATUS "")
+
+ message(STATUS "list_prerequisites '${file_full}' 1 0 0")
+ list_prerequisites("${file_full}" 1 0 0)
+ message(STATUS "")
+
+ message(STATUS "list_prerequisites '${file_full}' 1 0 1")
+ list_prerequisites("${file_full}" 1 0 1)
+ message(STATUS "")
+
+ message(STATUS "list_prerequisites '${file_full}' 1 1 0")
+ list_prerequisites("${file_full}" 1 1 0)
+ message(STATUS "")
+
+ message(STATUS "list_prerequisites '${file_full}' 1 1 1")
+ list_prerequisites("${file_full}" 1 1 1)
+ message(STATUS "")
+
+ message(STATUS "=============================================================================")
+ message(STATUS "")
+endfunction()
+
+
+function(test_cmake_executables)
+ message(STATUS "=============================================================================")
+ message(STATUS "Loop over all executable files in the same directory with CMake")
+ message(STATUS "")
+
+ get_filename_component(cmake_bin_dir "${CMAKE_COMMAND}" PATH)
+ list_prerequisites_by_glob(GLOB "${cmake_bin_dir}/*" 0 0 1)
+endfunction()
+
+
+message(STATUS "=============================================================================")
+message(STATUS "Simplest test - list all the direct prerequisites of CMake itself")
+message(STATUS "")
+list_prerequisites("${CMAKE_COMMAND}" 0 0 1)
+message(STATUS "")
+
+message(STATUS "=============================================================================")
+string(LENGTH "$ENV{PATH}" PATH_LENGTH_BEGIN)
+message(STATUS "Begin PATH length is: ${PATH_LENGTH_BEGIN}")
+message(STATUS "")
+
+
+# Leave the code for these tests in here, but turn them off by default... they
+# take longer than they're worth during development...
+#
+set(do_testdefaults 0)
+if(do_testdefaults)
+ message(STATUS "=============================================================================")
+ message(STATUS "Test default argument values to list_prerequisites function...")
+ message(STATUS "")
+ list_prerequisites("${CMAKE_COMMAND}")
+ message(STATUS "")
+endif()
+
+
+set(do_stresstest 0)
+if(do_stresstest)
+ message(STATUS "=============================================================================")
+ message(STATUS "stresstest_list_prerequisites with CMake itself...")
+ message(STATUS "")
+ stresstest_list_prerequisites("${CMAKE_COMMAND}")
+ message(STATUS "")
+endif()
+
+
+test_cmake_executables()
+
+
+message(STATUS "=============================================================================")
+message(STATUS "Test overriding 'gp_tool' with bogus value")
+message(STATUS "")
+set(gp_tool "bogus")
+list_prerequisites("${CMAKE_COMMAND}" 0 0 0)
+set(gp_tool)
+message(STATUS "")
+
+
+message(STATUS "=============================================================================")
+message(STATUS "Test overriding 'gp_tool' with value unlikely to be found")
+message(STATUS "")
+if(APPLE)
+ set(gp_tool "dumpbin")
+else()
+ set(gp_tool "otool")
+endif()
+set(gp_cmd "gp_cmd-NOTFOUND")
+list_prerequisites("${CMAKE_COMMAND}" 0 0 0)
+set(gp_cmd)
+set(gp_tool)
+message(STATUS "")
+
+
+message(STATUS "=============================================================================")
+message(STATUS "All variables: (Make sure functions/macros are not leaving stuff around...")
+message(STATUS " Only variables predefined by CMake and defined in this")
+message(STATUS " test script file should be listed here...)")
+message(STATUS "")
+get_cmake_property(vs VARIABLES)
+foreach(v ${vs})
+ message(STATUS "${v}='${${v}}'")
+endforeach()
+message(STATUS "")
+
+message(STATUS "=============================================================================")
+string(LENGTH "$ENV{PATH}" PATH_LENGTH_END)
+message(STATUS "Final PATH length is: ${PATH_LENGTH_END}")
+
+if(PATH_LENGTH_END GREATER ${PATH_LENGTH_BEGIN})
+ message(FATAL_ERROR "list_prerequisties is endlessly appending the path of gp_tool to the PATH.")
+endif()
+message(STATUS "")
+
+
+message(STATUS "=============================================================================")
+message(STATUS "End of test")
+message(STATUS "")
diff --git a/Tests/CMakeTests/GetPropertyTest.cmake.in b/Tests/CMakeTests/GetPropertyTest.cmake.in
new file mode 100644
index 0000000..1ad8956
--- /dev/null
+++ b/Tests/CMakeTests/GetPropertyTest.cmake.in
@@ -0,0 +1,16 @@
+get_property(FOO_BRIEF GLOBAL PROPERTY FOO BRIEF_DOCS)
+get_property(FOO_FULL GLOBAL PROPERTY FOO FULL_DOCS)
+
+if (NOT FOO_BRIEF STREQUAL "NOTFOUND")
+ message(SEND_ERROR "property FOO has BRIEF_DOCS set to '${FOO_BRIEF}'")
+endif ()
+
+if (NOT FOO_FULL STREQUAL "NOTFOUND")
+ message(SEND_ERROR "property FOO has FULL_DOCS set to '${FOO_FULL}'")
+endif ()
+
+set(test_var alpha)
+get_property(result VARIABLE PROPERTY test_var)
+if(NOT result STREQUAL "alpha")
+ message(SEND_ERROR "bad value of VARIABLE PROPERTY test_var: got '${result}' instead of 'alpha'")
+endif()
diff --git a/Tests/CMakeTests/IfTest.cmake.in b/Tests/CMakeTests/IfTest.cmake.in
new file mode 100644
index 0000000..e5211b4
--- /dev/null
+++ b/Tests/CMakeTests/IfTest.cmake.in
@@ -0,0 +1,158 @@
+# Prepare variable definitions.
+set(VAR_UNDEFINED)
+set(VAR_PATH /some/path/to/a/file.txt)
+set(FALSE_NAMES OFF NO FALSE N FOO-NOTFOUND IGNORE Off No False Ignore off n no false ignore)
+set(TRUE_NAMES ON YES TRUE Y On Yes True on yes true y)
+foreach(_arg "" 0 1 2 ${TRUE_NAMES} ${FALSE_NAMES})
+ set(VAR_${_arg} "${_arg}")
+endforeach()
+
+macro(test_vars _old)
+ # Variables set to false or not set.
+ foreach(_var "" 0 ${FALSE_NAMES} UNDEFINED)
+ if(VAR_${_var})
+ message(FATAL_ERROR "${_old}if(VAR_${_var}) is true!")
+ else()
+ message(STATUS "${_old}if(VAR_${_var}) is false")
+ endif()
+
+ if(NOT VAR_${_var})
+ message(STATUS "${_old}if(NOT VAR_${_var}) is true")
+ else()
+ message(FATAL_ERROR "${_old}if(NOT VAR_${_var}) is false!")
+ endif()
+ endforeach()
+
+ # Variables set to true.
+ foreach(_var 1 2 ${TRUE_NAMES} PATH)
+ if(VAR_${_var})
+ message(STATUS "${_old}if(VAR_${_var}) is true")
+ else()
+ message(FATAL_ERROR "${_old}if(VAR_${_var}) is false!")
+ endif()
+
+ if(NOT VAR_${_var})
+ message(FATAL_ERROR "${_old}if(NOT VAR_${_var}) is true!")
+ else()
+ message(STATUS "${_old}if(NOT VAR_${_var}) is false")
+ endif()
+ endforeach()
+endmacro()
+
+#-----------------------------------------------------------------------------
+# Test the OLD behavior of CMP0012.
+cmake_policy(SET CMP0012 OLD)
+
+# False constants not recognized (still false).
+foreach(_false "" ${FALSE_NAMES})
+ if("${_false}")
+ message(FATAL_ERROR "OLD if(${_false}) is true!")
+ else()
+ message(STATUS "OLD if(${_false}) is false")
+ endif()
+
+ if(NOT "${_false}")
+ message(STATUS "OLD if(NOT ${_false}) is true")
+ else()
+ message(FATAL_ERROR "OLD if(NOT ${_false}) is false!")
+ endif()
+endforeach()
+
+# True constants not recognized.
+foreach(_false ${TRUE_NAMES})
+ if(${_false})
+ message(FATAL_ERROR "OLD if(${_false}) is true!")
+ else()
+ message(STATUS "OLD if(${_false}) is false")
+ endif()
+
+ if(NOT ${_false})
+ message(STATUS "OLD if(NOT ${_false}) is true")
+ else()
+ message(FATAL_ERROR "OLD if(NOT ${_false}) is false!")
+ endif()
+endforeach()
+
+# Numbers not recognized properly.
+foreach(_num 2 -2 2.0 -2.0 2x -2x)
+ if(${_num})
+ message(FATAL_ERROR "OLD if(${_num}) is true!")
+ else()
+ message(STATUS "OLD if(${_num}) is false")
+ endif()
+
+ if(NOT ${_num})
+ message(FATAL_ERROR "OLD if(NOT ${_num}) is true!")
+ else()
+ message(STATUS "OLD if(NOT ${_num}) is false")
+ endif()
+endforeach()
+
+test_vars("OLD ")
+
+#-----------------------------------------------------------------------------
+
+# Test the NEW behavior of CMP0012.
+cmake_policy(SET CMP0012 NEW)
+
+# Test false constants.
+foreach(_false "" 0 ${FALSE_NAMES})
+ if("${_false}")
+ message(FATAL_ERROR "if(${_false}) is true!")
+ else()
+ message(STATUS "if(${_false}) is false")
+ endif()
+
+ if(NOT "${_false}")
+ message(STATUS "if(NOT ${_false}) is true")
+ else()
+ message(FATAL_ERROR "if(NOT ${_false}) is false!")
+ endif()
+endforeach()
+
+# Test true constants.
+foreach(_true 1 ${TRUE_NAMES})
+ if(${_true})
+ message(STATUS "if(${_true}) is true")
+ else()
+ message(FATAL_ERROR "if(${_true}) is false!")
+ endif()
+
+ if(NOT ${_true})
+ message(FATAL_ERROR "if(NOT ${_true}) is true!")
+ else()
+ message(STATUS "if(NOT ${_true}) is false")
+ endif()
+endforeach()
+
+# Numbers recognized properly.
+foreach(_num 2 -2 2.0 -2.0)
+ if(${_num})
+ message(STATUS "if(${_num}) is true")
+ else()
+ message(FATAL_ERROR "if(${_num}) is false!")
+ endif()
+
+ if(NOT ${_num})
+ message(FATAL_ERROR "if(NOT ${_num}) is true!")
+ else()
+ message(STATUS "if(NOT ${_num}) is false")
+ endif()
+endforeach()
+
+# Bad numbers not recognized.
+foreach(_bad 2x -2x)
+ if(${_bad})
+ message(FATAL_ERROR "if(${_bad}) is true!")
+ else()
+ message(STATUS "if(${_bad}) is false")
+ endif()
+
+ if(NOT ${_bad})
+ message(STATUS "if(NOT ${_bad}) is true")
+ else()
+ message(FATAL_ERROR "if(NOT ${_bad}) is false!")
+ endif()
+endforeach()
+
+test_vars("")
diff --git a/Tests/CMakeTests/ImplicitLinkInfoTest.cmake.in b/Tests/CMakeTests/ImplicitLinkInfoTest.cmake.in
new file mode 100644
index 0000000..f01e616
--- /dev/null
+++ b/Tests/CMakeTests/ImplicitLinkInfoTest.cmake.in
@@ -0,0 +1,554 @@
+# This is not supposed to be included by user code, but we need to
+# test it.
+include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake)
+
+#-----------------------------------------------------------------------------
+# Linux
+
+# gcc dummy.c -v
+set(linux64_gcc_text " /usr/lib/gcc/x86_64-linux-gnu/4.3.3/collect2 --eh-frame-hdr -m elf_x86_64 --hash-style=both -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../../../lib/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../../../lib/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.3.3/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.3.3 -L/usr/lib/gcc/x86_64-linux-gnu/4.3.3 -L/usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../.. -L/usr/lib/x86_64-linux-gnu /tmp/ccEO9iux.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.3.3/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../../../lib/crtn.o")
+set(linux64_gcc_libs "gcc;gcc_s;c;gcc;gcc_s")
+set(linux64_gcc_dirs "/usr/lib/gcc/x86_64-linux-gnu/4.3.3;/usr/lib;/lib;/usr/lib/x86_64-linux-gnu")
+list(APPEND platforms linux64_gcc)
+
+# g++ dummy.cxx -v
+set(linux64_g++_text " /usr/lib/gcc/x86_64-linux-gnu/4.3.3/collect2 --eh-frame-hdr -m elf_x86_64 --hash-style=both -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../../../lib/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../../../lib/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.3.3/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.3.3 -L/usr/lib/gcc/x86_64-linux-gnu/4.3.3 -L/usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../.. -L/usr/lib/x86_64-linux-gnu /tmp/ccalRBlq.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/4.3.3/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../../../lib/crtn.o")
+set(linux64_g++_libs "stdc++;m;gcc_s;gcc;c;gcc_s;gcc")
+set(linux64_g++_dirs "/usr/lib/gcc/x86_64-linux-gnu/4.3.3;/usr/lib;/lib;/usr/lib/x86_64-linux-gnu")
+list(APPEND platforms linux64_g++)
+
+# f95 dummy.f -v
+set(linux64_f95_text " /usr/lib/gcc/x86_64-linux-gnu/4.3.3/collect2 --eh-frame-hdr -m elf_x86_64 --hash-style=both -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../../../lib/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../../../lib/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.3.3/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.3.3 -L/usr/lib/gcc/x86_64-linux-gnu/4.3.3 -L/usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../.. -L/usr/lib/x86_64-linux-gnu /tmp/ccAVcN7N.o -lgfortranbegin -lgfortran -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/4.3.3/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.3.3/../../../../lib/crtn.o")
+set(linux64_f95_libs "gfortranbegin;gfortran;m;gcc_s;gcc;c;gcc_s;gcc")
+set(linux64_f95_dirs "/usr/lib/gcc/x86_64-linux-gnu/4.3.3;/usr/lib;/lib;/usr/lib/x86_64-linux-gnu")
+list(APPEND platforms linux64_f95)
+
+# suncc dummy.c '-#'
+set(linux64_suncc_text "/usr/bin/ld --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /opt/sun/sunstudio12/prod/lib/amd64/crti.o /opt/sun/sunstudio12/prod/lib/amd64/crt1x.o /opt/sun/sunstudio12/prod/lib/amd64/values-xa.o dummy.o -Y \"/opt/sun/sunstudio12/prod/lib/amd64:/lib64:/usr/lib64\" -Qy -lc /opt/sun/sunstudio12/prod/lib/amd64/libc_supp.a /opt/sun/sunstudio12/prod/lib/amd64/crtn.o")
+set(linux64_suncc_libs "c;/opt/sun/sunstudio12/prod/lib/amd64/libc_supp.a")
+set(linux64_suncc_dirs "/opt/sun/sunstudio12/prod/lib/amd64;/lib64;/usr/lib64")
+list(APPEND platforms linux64_suncc)
+
+# sunCC dummy.cxx -v
+set(linux64_sunCC_text "/opt/sun/sunstudio12/prod/lib/amd64/ld -u __1cH__CimplKcplus_init6F_v_ --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -R/opt/sun/sunstudio12/lib/rw7/amd64:/opt/sun/sunstudio12/lib/amd64:/opt/sun/sunstudio12/rtlibs/amd64:/opt/sun/lib/rtlibs/amd64:/opt/SUNWspro/lib/amd64:/lib64:/usr/lib64 -o a.out /opt/sun/sunstudio12/prod/lib/amd64/crti.o /opt/sun/sunstudio12/prod/lib/amd64/CCrti.o /opt/sun/sunstudio12/prod/lib/amd64/crt1x.o -Y P,/opt/sun/sunstudio12/lib/rw7/amd64:/opt/sun/sunstudio12/lib/amd64:/opt/sun/sunstudio12/rtlibs/amd64:/opt/sun/sunstudio12/prod/lib/rw7/amd64:/opt/sun/sunstudio12/prod/lib/amd64:/lib64:/usr/lib64 dummy.o -lCstd -lCrun -lm -lc /opt/sun/sunstudio12/prod/lib/amd64/libc_supp.a /opt/sun/sunstudio12/prod/lib/amd64/CCrtn.o /opt/sun/sunstudio12/prod/lib/amd64/crtn.o >&/tmp/ld.04973.2.err")
+set(linux64_sunCC_libs "Cstd;Crun;m;c;/opt/sun/sunstudio12/prod/lib/amd64/libc_supp.a")
+set(linux64_sunCC_dirs "/opt/sun/sunstudio12/lib/rw7/amd64;/opt/sun/sunstudio12/lib/amd64;/opt/sun/sunstudio12/rtlibs/amd64;/opt/sun/sunstudio12/prod/lib/rw7/amd64;/opt/sun/sunstudio12/prod/lib/amd64;/lib64;/usr/lib64")
+list(APPEND platforms linux64_sunCC)
+
+# sunf90 dummy.f -v
+set(linux64_sunf90_text "/usr/bin/ld --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -R/opt/sun/sunstudio12/lib/amd64:/opt/sun/sunstudio12/rtlibs/amd64:/opt/sun/lib/rtlibs/amd64 -o a.out /opt/sun/sunstudio12/prod/lib/amd64/crti.o /opt/sun/sunstudio12/prod/lib/amd64/crt1x.o /opt/sun/sunstudio12/prod/lib/amd64/values-xi.o -Y P,/opt/sun/sunstudio12/lib/amd64:/opt/sun/sunstudio12/rtlibs/amd64:/opt/sun/sunstudio12/prod/lib/amd64:/lib64:/usr/lib64 dummy.o -lfui -lfai -lfsu -Bdynamic -lmtsk -lpthread -lm -lc /opt/sun/sunstudio12/prod/lib/amd64/libc_supp.a /opt/sun/sunstudio12/prod/lib/amd64/crtn.o")
+set(linux64_sunf90_libs "fui;fai;fsu;mtsk;pthread;m;c;/opt/sun/sunstudio12/prod/lib/amd64/libc_supp.a")
+set(linux64_sunf90_dirs "/opt/sun/sunstudio12/lib/amd64;/opt/sun/sunstudio12/rtlibs/amd64;/opt/sun/sunstudio12/prod/lib/amd64;/lib64;/usr/lib64")
+list(APPEND platforms linux64_sunf90)
+
+# icc dummy.c -v
+set(linux64_icc_text "ld /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/crt1.o /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/crti.o /usr/lib64/gcc/x86_64-suse-linux/4.1.2/crtbegin.o --eh-frame-hdr -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o a.out /tmp/iccBP8OfN.o -L/opt/compiler/intel/compiler/11.0/lib/intel64 -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2 -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../x86_64-suse-linux/lib -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../.. -L/lib64 -L/lib -L/usr/lib64 -L/usr/lib -Bstatic -limf -lsvml -Bdynamic -lm -Bstatic -lipgo -ldecimal -lirc -Bdynamic -lgcc_s -lgcc -Bstatic -lirc -Bdynamic -lc -lgcc_s -lgcc -Bstatic -lirc_s -Bdynamic -ldl -lc /usr/lib64/gcc/x86_64-suse-linux/4.1.2/crtend.o /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/crtn.o")
+set(linux64_icc_libs "imf;svml;m;ipgo;decimal;irc;gcc_s;gcc;irc;c;gcc_s;gcc;irc_s;dl;c")
+set(linux64_icc_dirs "/opt/compiler/intel/compiler/11.0/lib/intel64;/usr/lib64/gcc/x86_64-suse-linux/4.1.2;/usr/lib64;/lib64;/usr/x86_64-suse-linux/lib;/lib;/usr/lib")
+list(APPEND platforms linux64_icc)
+
+# icxx dummy.cxx -v
+set(linux64_icxx_text "ld /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/crt1.o /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/crti.o /usr/lib64/gcc/x86_64-suse-linux/4.1.2/crtbegin.o --eh-frame-hdr -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o a.out /tmp/icpc270GoT.o -L/opt/compiler/intel/compiler/11.0/lib/intel64 -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2 -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../x86_64-suse-linux/lib -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../.. -L/lib64 -L/lib -L/usr/lib64 -L/usr/lib -Bstatic -limf -lsvml -Bdynamic -lm -Bstatic -lipgo -ldecimal -Bdynamic -lstdc++ -Bstatic -lirc -Bdynamic -lgcc_s -lgcc -Bstatic -lirc -Bdynamic -lc -lgcc_s -lgcc -Bstatic -lirc_s -Bdynamic -ldl -lc /usr/lib64/gcc/x86_64-suse-linux/4.1.2/crtend.o /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/crtn.o")
+set(linux64_icxx_libs "imf;svml;m;ipgo;decimal;stdc++;irc;gcc_s;gcc;irc;c;gcc_s;gcc;irc_s;dl;c")
+set(linux64_icxx_dirs "/opt/compiler/intel/compiler/11.0/lib/intel64;/usr/lib64/gcc/x86_64-suse-linux/4.1.2;/usr/lib64;/lib64;/usr/x86_64-suse-linux/lib;/lib;/usr/lib")
+list(APPEND platforms linux64_icxx)
+
+# ifort dummy.f -v
+set(linux64_ifort_text "ld --eh-frame-hdr -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o a.out -L/opt/compiler/intel/compiler/11.0/lib/intel64 -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2 -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../x86_64-suse-linux/lib -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../.. -L/lib64 -L/lib -L/usr/lib64 -L/usr/lib /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/crt1.o /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/crti.o /usr/lib64/gcc/x86_64-suse-linux/4.1.2/crtbegin.o /opt/compiler/intel/compiler/11.0/lib/intel64/for_main.o dum.cxx -Bstatic -lifport -lifcore -limf -lsvml -Bdynamic -lm -Bstatic -lipgo -lirc -Bdynamic -lpthread -lc -lgcc_s -lgcc -Bstatic -lirc_s -Bdynamic -ldl -lc /usr/lib64/gcc/x86_64-suse-linux/4.1.2/crtend.o /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/crtn.o")
+set(linux64_ifort_libs "ifport;ifcore;imf;svml;m;ipgo;irc;pthread;c;gcc_s;gcc;irc_s;dl;c")
+set(linux64_ifort_dirs "/opt/compiler/intel/compiler/11.0/lib/intel64;/usr/lib64/gcc/x86_64-suse-linux/4.1.2;/usr/lib64;/lib64;/usr/x86_64-suse-linux/lib;/lib;/usr/lib")
+list(APPEND platforms linux64_ifort)
+
+# pgcc dummy.c -v
+set(linux64_pgcc_text "/usr/bin/ld /usr/lib64/crt1.o /usr/lib64/crti.o /opt/compiler/pgi/linux86-64/8.0-3/lib/trace_init.o /usr/lib64/gcc/x86_64-suse-linux/4.1.2/crtbegin.o -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /opt/compiler/pgi/linux86-64/8.0-3/lib/pgi.ld -L/opt/compiler/pgi/linux86-64/8.0-3/lib -L/usr/lib64 -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2 /tmp/pgcc7OscXa5ur7Zk.o -rpath /opt/compiler/pgi/linux86-64/8.0-3/lib -lnspgc -lpgc -lm -lgcc -lc -lgcc /usr/lib64/gcc/x86_64-suse-linux/4.1.2/crtend.o /usr/lib64/crtn.o")
+set(linux64_pgcc_libs "nspgc;pgc;m;gcc;c;gcc")
+set(linux64_pgcc_dirs "/opt/compiler/pgi/linux86-64/8.0-3/lib;/usr/lib64;/usr/lib64/gcc/x86_64-suse-linux/4.1.2")
+list(APPEND platforms linux64_pgcc)
+
+# pgCC dummy.cxx -v
+set(linux64_pgCC_text "/usr/bin/ld /usr/lib64/crt1.o /usr/lib64/crti.o /opt/compiler/pgi/linux86-64/8.0-3/lib/trace_init.o /usr/lib64/gcc/x86_64-suse-linux/4.1.2/crtbegin.o -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /opt/compiler/pgi/linux86-64/8.0-3/lib/pgi.ld -L/opt/compiler/pgi/linux86-64/8.0-3/lib -L/usr/lib64 -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2 /tmp/pgCCFhjcDt1fs1Ki.o -rpath /opt/compiler/pgi/linux86-64/8.0-3/lib -lstd -lC -lnspgc -lpgc -lm -lgcc -lc -lgcc /usr/lib64/gcc/x86_64-suse-linux/4.1.2/crtend.o /usr/lib64/crtn.o")
+set(linux64_pgCC_libs "std;C;nspgc;pgc;m;gcc;c;gcc")
+set(linux64_pgCC_dirs "/opt/compiler/pgi/linux86-64/8.0-3/lib;/usr/lib64;/usr/lib64/gcc/x86_64-suse-linux/4.1.2")
+list(APPEND platforms linux64_pgCC)
+
+# pgf90 dummy.f -v
+set(linux64_pgf90_text "/usr/bin/ld /usr/lib64/crt1.o /usr/lib64/crti.o /opt/compiler/pgi/linux86-64/8.0-3/lib/trace_init.o /usr/lib64/gcc/x86_64-suse-linux/4.1.2/crtbegin.o /opt/compiler/pgi/linux86-64/8.0-3/lib/f90main.o -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /opt/compiler/pgi/linux86-64/8.0-3/lib/pgi.ld -L/opt/compiler/pgi/linux86-64/8.0-3/lib -L/usr/lib64 -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2 /tmp/pgf90QOIc_eB9xY5h.o -rpath /opt/compiler/pgi/linux86-64/8.0-3/lib -lpgf90 -lpgf90_rpm1 -lpgf902 -lpgf90rtl -lpgftnrtl -lnspgc -lpgc -lrt -lpthread -lm -lgcc -lc -lgcc /usr/lib64/gcc/x86_64-suse-linux/4.1.2/crtend.o /usr/lib64/crtn.o")
+set(linux64_pgf90_libs "pgf90;pgf90_rpm1;pgf902;pgf90rtl;pgftnrtl;nspgc;pgc;rt;pthread;m;gcc;c;gcc")
+set(linux64_pgf90_dirs "/opt/compiler/pgi/linux86-64/8.0-3/lib;/usr/lib64;/usr/lib64/gcc/x86_64-suse-linux/4.1.2")
+list(APPEND platforms linux64_pgf90)
+
+# nagfor dummy.f -Wl,-v
+set(linux64_nagfor_text " /usr/libexec/gcc/x86_64-redhat-linux/4.4.5/collect2 --no-add-needed --eh-frame-hdr --build-id -m elf_x86_64 --hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o a.out /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.4.5/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.4.5 -L/usr/lib/gcc/x86_64-redhat-linux/4.4.5 -L/usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../.. /usr/local/NAG/lib/f90_init.o /usr/local/NAG/lib/quickfit.o dummy.o -rpath /usr/local/NAG/lib /usr/local/NAG/lib/libf53.so /usr/local/NAG/lib/libf53.a -lm -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.4.5/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../lib64/crtn.o")
+set(linux64_nagfor_libs "/usr/local/NAG/lib/f90_init.o;/usr/local/NAG/lib/quickfit.o;/usr/local/NAG/lib/libf53.a;m;gcc;gcc_s;c;gcc;gcc_s")
+set(linux64_nagfor_dirs "/usr/lib/gcc/x86_64-redhat-linux/4.4.5;/usr/lib64;/lib64;/usr/lib")
+set(linux64_nagfor_obj_regex "^/usr/local/NAG/lib")
+list(APPEND platforms linux64_nagfor)
+
+# absoft dummy.f -X -v
+set(linux64_absoft_text "collect2 version 4.4.5 (x86-64 Linux/ELF)
+/usr/bin/ld --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=both -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtbegin.o -L/opt/absoft11.1/lib64 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../.. /tmp/E3Bii1/dummy.o -v -laf90math -lafio -lamisc -labsoftmain -laf77math -lm -lmv -lpthread -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crtn.o")
+set(linux64_absoft_libs "af90math;afio;amisc;absoftmain;af77math;m;mv;pthread;gcc;gcc_s;c;gcc;gcc_s")
+set(linux64_absoft_dirs "/opt/absoft11.1/lib64;/usr/lib/gcc/x86_64-linux-gnu/4.4.5;/usr/lib;/lib")
+list(APPEND platforms linux64_absoft)
+
+# gcc dummy.c -v # in strange path
+set(linux64_test1_text "
+/this/might/match/as/a/linker/ld/but/it/is/not because the ld is not the last path component
+${linux64_gcc_text}")
+set(linux64_test1_libs "${linux64_gcc_libs}")
+set(linux64_test1_dirs "${linux64_gcc_dirs}")
+list(APPEND platforms linux64_test1)
+
+# sunCC dummy.cxx -v # extra slashes
+set(linux64_test2_text "/usr/bin/ld --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /opt/sun/sunstudio12/prod/lib/amd64//crti.o /opt/sun/sunstudio12/prod/lib/amd64/crt1x.o /opt/sun/sunstudio12/prod/lib/amd64/values-xa.o dummy.o -Y \"/opt/sun/sunstudio12/prod/lib//amd64:/lib64:/usr//lib64\" -Qy -lc /opt/sun/sunstudio12/prod/lib/amd64//libc_supp.a /opt/sun/sunstudio12/prod/lib/amd64/crtn.o")
+set(linux64_test2_libs "c;/opt/sun/sunstudio12/prod/lib/amd64/libc_supp.a")
+set(linux64_test2_dirs "/opt/sun/sunstudio12/prod/lib/amd64;/lib64;/usr/lib64")
+list(APPEND platforms linux64_test2)
+
+# -specs=redhat-hardened-ld
+set(linux64_test3_text "COLLECT_GCC_OPTIONS='-specs=/usr/lib/rpm/redhat/redhat-hardened-ld' '-v' '-O2' '-g' '-pipe' '-Wall' '-Werror=format-security' '-fexceptions' '-fstack-protector-strong' '--param' 'ssp-buffer-size=4' '-grecord-gcc-switches' '-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1' '-m64' '-mtune=generic' '-I' '/usr/lib64/gfortran/modules' '-o' 'a.out' '-rdynamic' '-shared-libgcc' '-march=x86-64' '-pie'
+ /usr/libexec/gcc/x86_64-redhat-linux/5.1.1/collect2 -plugin /usr/libexec/gcc/x86_64-redhat-linux/5.1.1/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/x86_64-redhat-linux/5.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/ccNzxFD8.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lquadmath -plugin-opt=-pass-through=-lm -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -export-dynamic -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z now -pie -o a.out /usr/lib/gcc/x86_64-redhat-linux/5.1.1/../../../../lib64/Scrt1.o /usr/lib/gcc/x86_64-redhat-linux/5.1.1/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/5.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-redhat-linux/5.1.1 -L/usr/lib/gcc/x86_64-redhat-linux/5.1.1/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/5.1.1/../../.. -z relro dummy.o -lgfortran -lm -lgcc_s -lgcc -lquadmath -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-redhat-linux/5.1.1/crtendS.o /usr/lib/gcc/x86_64-redhat-linux/5.1.1/../../../../lib64/crtn.o")
+set(linux64_test3_libs "gfortran;m;gcc_s;gcc;quadmath;m;gcc_s;gcc;c;gcc_s;gcc")
+set(linux64_test3_dirs "/usr/lib/gcc/x86_64-redhat-linux/5.1.1;/usr/lib64;/lib64;/usr/lib")
+list(APPEND platforms linux64_test3)
+
+# clang -fsanitize=memory
+set(linux64_clang_sanitize_memory_text [[ "/usr/bin/ld" --hash-style=both --build-id --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o a.out /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../x86_64-linux-gnu/crt1.o /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../x86_64-linux-gnu/crti.o /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/crtbegin.o -L/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0 -L/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../x86_64-linux-gnu -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../.. -L/usr/lib/llvm-3.8/bin/../lib -L/lib -L/usr/lib -whole-archive /usr/lib/llvm-3.8/bin/../lib/clang/3.8.0/lib/linux/libclang_rt.msan-x86_64.a -no-whole-archive --dynamic-list=/usr/lib/llvm-3.8/bin/../lib/clang/3.8.0/lib/linux/libclang_rt.msan-x86_64.a.syms /tmp/dummy-27898d.o --no-as-needed -lpthread -lrt -lm -ldl -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/crtend.o /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../x86_64-linux-gnu/crtn.o]])
+set(linux64_clang_sanitize_memory_libs "pthread;rt;m;dl;gcc;gcc_s;c;gcc;gcc_s")
+set(linux64_clang_sanitize_memory_dirs "/usr/lib/gcc/x86_64-linux-gnu/5.4.0;/usr/lib/x86_64-linux-gnu;/lib/x86_64-linux-gnu;/lib64;/usr/lib;/usr/lib/llvm-3.8/lib;/lib")
+list(APPEND platforms linux64_clang_sanitize_memory)
+
+#-----------------------------------------------------------------------------
+# Mac
+
+# gcc -arch i686 dummy.c -v -Wl,-v
+set(mac_i686_gcc_Wlv_text " /usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2 -dynamic -arch i386 -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.6.o -L/usr/lib/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.. /var/tmp//ccnhXAGL.o -lSystem -lgcc -lSystem
+collect2 version 4.2.1 (Apple Inc. build 5646) (i686 Darwin)
+/usr/libexec/gcc/i686-apple-darwin10/4.2.1/ld -dynamic -arch i386 -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.6.o -L/usr/lib/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.. /var/tmp//ccSiuUhD.o -v -lSystem -lgcc -lSystem
+@(#)PROGRAM:ld PROJECT:ld64-95.2.12
+Library search paths:
+ /usr/lib/i686-apple-darwin10/4.2.1
+ /usr/lib/gcc/i686-apple-darwin10/4.2.1
+ /usr/lib/gcc/i686-apple-darwin10/4.2.1
+ /usr/lib/i686-apple-darwin10/4.2.1
+ /usr/lib
+ /usr/lib
+ /usr/local/lib
+Framework search paths:
+ /Library/Frameworks/
+ /System/Library/Frameworks/")
+set(mac_i686_gcc_Wlv_libs "gcc")
+set(mac_i686_gcc_Wlv_dirs "/usr/lib/i686-apple-darwin10/4.2.1;/usr/lib/gcc/i686-apple-darwin10/4.2.1;/usr/lib;/usr/local/lib")
+set(mac_i686_gcc_Wlv_fwks "/Library/Frameworks;/System/Library/Frameworks")
+list(APPEND platforms mac_i686_gcc_Wlv)
+
+# gcc -arch i686 dummy.c -v
+set(mac_i686_gcc_text " /usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2 -dynamic -arch i386 -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.6.o -L/usr/lib/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.. /var/tmp//ccnhXAGL.o -lSystem -lgcc -lSystem")
+set(mac_i686_gcc_libs "gcc")
+set(mac_i686_gcc_dirs "/usr/lib/i686-apple-darwin10/4.2.1;/usr/lib/gcc/i686-apple-darwin10/4.2.1;/usr/lib")
+list(APPEND platforms mac_i686_gcc)
+
+# g++ -arch i686 dummy.cxx -v -Wl,-v
+set(mac_i686_g++_Wlv_text " /usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2 -dynamic -arch i386 -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.6.o -L/usr/lib/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.. /var/tmp//ccEXXICh.o -lstdc++ -lSystem -lgcc -lSystem
+collect2 version 4.2.1 (Apple Inc. build 5646) (i686 Darwin)
+/usr/libexec/gcc/i686-apple-darwin10/4.2.1/ld -dynamic -arch i386 -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.6.o -L/usr/lib/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.. /var/tmp//ccWrBoVl.o -v -lstdc++ -lSystem -lgcc -lSystem
+@(#)PROGRAM:ld PROJECT:ld64-95.2.12
+Library search paths:
+ /usr/lib/i686-apple-darwin10/4.2.1
+ /usr/lib/gcc/i686-apple-darwin10/4.2.1
+ /usr/lib/gcc/i686-apple-darwin10/4.2.1
+ /usr/lib/i686-apple-darwin10/4.2.1
+ /usr/lib
+ /usr/lib
+ /usr/local/lib
+Framework search paths:
+ /Library/Frameworks/
+ /System/Library/Frameworks/")
+set(mac_i686_g++_Wlv_libs "stdc++;gcc")
+set(mac_i686_g++_Wlv_dirs "/usr/lib/i686-apple-darwin10/4.2.1;/usr/lib/gcc/i686-apple-darwin10/4.2.1;/usr/lib;/usr/local/lib")
+set(mac_i686_g++_Wlv_fwks "/Library/Frameworks;/System/Library/Frameworks")
+list(APPEND platforms mac_i686_g++_Wlv)
+
+# g++ -arch i686 dummy.cxx -v
+set(mac_i686_g++_text " /usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2 -dynamic -arch i386 -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.6.o -L/usr/lib/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.. /var/tmp//ccEXXICh.o -lstdc++ -lSystem -lgcc -lSystem")
+set(mac_i686_g++_libs "stdc++;gcc")
+set(mac_i686_g++_dirs "/usr/lib/i686-apple-darwin10/4.2.1;/usr/lib/gcc/i686-apple-darwin10/4.2.1;/usr/lib")
+list(APPEND platforms mac_i686_g++)
+
+# gfortran dummy.f -v -Wl,-v
+set(mac_i686_gfortran_Wlv_text " /usr/local/libexec/gcc/i386-apple-darwin9.7.0/4.4.1/collect2 -dynamic -arch i386 -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.5.o -L/usr/local/lib/gcc/i386-apple-darwin9.7.0/4.4.1 -L/usr/local/lib/gcc/i386-apple-darwin9.7.0/4.4.1/../../.. /var/tmp//cc9zXNax.o -v -lgfortranbegin -lgfortran -lgcc_s.10.5 -lgcc -lSystem
+collect2 version 4.4.1 20090623 (prerelease) (i686 Darwin)
+/usr/bin/ld -dynamic -arch i386 -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.5.o -L/usr/local/lib/gcc/i386-apple-darwin9.7.0/4.4.1 -L/usr/local/lib/gcc/i386-apple-darwin9.7.0/4.4.1/../../.. /var/tmp//cc9zXNax.o -v -lgfortranbegin -lgfortran -lgcc_s.10.5 -lgcc -lSystem
+@(#)PROGRAM:ld PROJECT:ld64-95.2.12
+Library search paths:
+ /usr/local/lib/gcc/i386-apple-darwin9.7.0/4.4.1
+ /usr/local/lib
+ /usr/lib
+ /usr/local/lib
+Framework search paths:
+ /Library/Frameworks/
+ /System/Library/Frameworks/")
+set(mac_i686_gfortran_Wlv_libs "gfortranbegin;gfortran;gcc_s.10.5;gcc")
+set(mac_i686_gfortran_Wlv_dirs "/usr/local/lib/gcc/i386-apple-darwin9.7.0/4.4.1;/usr/local/lib;/usr/lib")
+set(mac_i686_gfortran_Wlv_fwks "/Library/Frameworks;/System/Library/Frameworks")
+list(APPEND platforms mac_i686_gfortran_Wlv)
+
+# gfortran dummy.f -v
+set(mac_i686_gfortran_text " /usr/libexec/gcc/i386-apple-darwin9.7.0/4.4.1/collect2 -dynamic -arch i386 -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.5.o -L/usr/lib/gcc/i386-apple-darwin9.7.0/4.4.1 -L/usr/lib/gcc -L/usr/lib/gcc/i386-apple-darwin9.7.0/4.4.1/../../.. /var/tmp//ccgqbX5P.o -lgfortranbegin -lgfortran -lgcc_s.10.5 -lgcc -lSystem")
+set(mac_i686_gfortran_libs "gfortranbegin;gfortran;gcc_s.10.5;gcc")
+set(mac_i686_gfortran_dirs "/usr/lib/gcc/i386-apple-darwin9.7.0/4.4.1;/usr/lib/gcc;/usr/lib")
+list(APPEND platforms mac_i686_gfortran)
+
+# gcc -arch ppc dummy.c -v -Wl,-v
+set(mac_ppc_gcc_Wlv_text " /usr/libexec/gcc/powerpc-apple-darwin10/4.2.1/collect2 -dynamic -arch ppc -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.5.o -L/usr/lib/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1/../../../powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1/../../.. /var/tmp//cclziQY4.o -v -lgcc -lSystemStubs -lSystem
+collect2 version 4.2.1 (Apple Inc. build 5646) (Darwin/PowerPC)
+/usr/libexec/gcc/powerpc-apple-darwin10/4.2.1/ld -dynamic -arch ppc -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.5.o -L/usr/lib/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1/../../../powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1/../../.. /var/tmp//cclziQY4.o -v -lgcc -lSystemStubs -lSystem
+@(#)PROGRAM:ld PROJECT:ld64-95.2.12
+Library search paths:
+ /usr/lib/powerpc-apple-darwin10/4.2.1
+ /usr/lib/gcc/powerpc-apple-darwin10/4.2.1
+ /usr/lib/gcc/powerpc-apple-darwin10/4.2.1
+ /usr/lib/powerpc-apple-darwin10/4.2.1
+ /usr/lib
+ /usr/lib
+ /usr/local/lib
+Framework search paths:
+ /Library/Frameworks/
+ /System/Library/Frameworks/")
+set(mac_ppc_gcc_Wlv_libs "gcc")
+set(mac_ppc_gcc_Wlv_dirs "/usr/lib/powerpc-apple-darwin10/4.2.1;/usr/lib/gcc/powerpc-apple-darwin10/4.2.1;/usr/lib;/usr/local/lib")
+set(mac_ppc_gcc_Wlv_fwks "/Library/Frameworks;/System/Library/Frameworks")
+list(APPEND platforms mac_ppc_gcc_Wlv)
+
+# gcc -arch ppc dummy.c -v
+set(mac_ppc_gcc_text " /usr/libexec/gcc/powerpc-apple-darwin10/4.2.1/collect2 -dynamic -arch ppc -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.5.o -L/usr/lib/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1/../../../powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1/../../.. /var/tmp//ccdcolsP.o -lgcc -lSystemStubs -lSystem")
+set(mac_ppc_gcc_libs "gcc")
+set(mac_ppc_gcc_dirs "/usr/lib/powerpc-apple-darwin10/4.2.1;/usr/lib/gcc/powerpc-apple-darwin10/4.2.1;/usr/lib")
+list(APPEND platforms mac_ppc_gcc)
+
+# g++ -arch ppc dummy.cxx -v -Wl,-v
+set(mac_ppc_g++_Wlv_text " /usr/libexec/gcc/powerpc-apple-darwin10/4.2.1/collect2 -dynamic -arch ppc -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.5.o -L/usr/lib/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1/../../../powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1/../../.. /var/tmp//ccaFTkwq.o -v -lstdc++ -lgcc -lSystemStubs -lSystem
+collect2 version 4.2.1 (Apple Inc. build 5646) (Darwin/PowerPC)
+/usr/libexec/gcc/powerpc-apple-darwin10/4.2.1/ld -dynamic -arch ppc -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.5.o -L/usr/lib/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1/../../../powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1/../../.. /var/tmp//ccaFTkwq.o -v -lstdc++ -lgcc -lSystemStubs -lSystem
+@(#)PROGRAM:ld PROJECT:ld64-95.2.12
+Library search paths:
+ /usr/lib/powerpc-apple-darwin10/4.2.1
+ /usr/lib/gcc/powerpc-apple-darwin10/4.2.1
+ /usr/lib/gcc/powerpc-apple-darwin10/4.2.1
+ /usr/lib/powerpc-apple-darwin10/4.2.1
+ /usr/lib
+ /usr/lib
+ /usr/local/lib
+Framework search paths:
+ /Library/Frameworks/
+ /System/Library/Frameworks/")
+set(mac_ppc_g++_Wlv_libs "stdc++;gcc")
+set(mac_ppc_g++_Wlv_dirs "/usr/lib/powerpc-apple-darwin10/4.2.1;/usr/lib/gcc/powerpc-apple-darwin10/4.2.1;/usr/lib;/usr/local/lib")
+set(mac_ppc_g++_Wlv_fwks "/Library/Frameworks;/System/Library/Frameworks")
+list(APPEND platforms mac_ppc_g++_Wlv)
+
+# g++ -arch ppc dummy.cxx -v
+set(mac_ppc_g++_text " /usr/libexec/gcc/powerpc-apple-darwin10/4.2.1/collect2 -dynamic -arch ppc -macosx_version_min 10.6.0 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.5.o -L/usr/lib/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1/../../../powerpc-apple-darwin10/4.2.1 -L/usr/lib/gcc/powerpc-apple-darwin10/4.2.1/../../.. /var/tmp//ccbjB6Lj.o -lstdc++ -lgcc -lSystemStubs -lSystem")
+set(mac_ppc_g++_libs "stdc++;gcc")
+set(mac_ppc_g++_dirs "/usr/lib/powerpc-apple-darwin10/4.2.1;/usr/lib/gcc/powerpc-apple-darwin10/4.2.1;/usr/lib")
+list(APPEND platforms mac_ppc_g++)
+
+# absoft dummy.f -X -v
+set(mac_absoft_text "collect2 version 4.2.1 (Apple Inc. build 5664) (i686 Darwin)
+/usr/libexec/gcc/i686-apple-darwin10/4.2.1/ld -dynamic -arch i386 -macosx_version_min 10.6.6 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.6.o -L/Applications/Absoft11.1/lib -L/usr/lib/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.. /var/folders/04/04+Djjm8GZWBmuEdp2Gsw++++TM/-Tmp-//bTAoJc/dummy.o -v -Y 10 -laf90math -lafio -lamisc -labsoftmain -laf77math -lm -lmv -lSystem -lgcc -lSystem
+")
+set(mac_absoft_libs "af90math;afio;amisc;absoftmain;af77math;m;mv;gcc")
+set(mac_absoft_dirs "/Applications/Absoft11.1/lib;/usr/lib/i686-apple-darwin10/4.2.1;/usr/lib/gcc/i686-apple-darwin10/4.2.1;/usr/lib")
+list(APPEND platforms mac_absoft)
+
+# Xcode 8.3: clang++ dummy.cpp -v
+set(mac_clang_v_text " \"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld\" -demangle -lto_library /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib -no_deduplicate -dynamic -arch x86_64 -macosx_version_min 10.12.0 -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -o a.out /var/folders/hc/95l7dhnx459c57g4yg_6yd8c0000gp/T/dummy-384ea1.o -lc++ -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.1.0/lib/darwin/libclang_rt.osx.a")
+set(mac_clang_v_libs "c++")
+set(mac_clang_v_dirs "")
+list(APPEND platforms mac_clang_v)
+
+#-----------------------------------------------------------------------------
+# Sun
+
+# cc dummy.c '-#'/
+set(sun_cc_text "/usr/ccs/bin/ld /opt/SUNWspro/prod/lib/crti.o /opt/SUNWspro/prod/lib/crt1.o /opt/SUNWspro/prod/lib/misalign.o /opt/SUNWspro/prod/lib/values-xa.o dummy.o -Y \"P,/opt/SUNWspro/prod/lib/v8plus:/opt/SUNWspro/prod/lib:/usr/ccs/lib:/lib:/usr/lib\" -Qy -lc /opt/SUNWspro/prod/lib/crtn.o")
+set(sun_cc_libs "c")
+set(sun_cc_dirs "/opt/SUNWspro/prod/lib/v8plus;/opt/SUNWspro/prod/lib;/usr/ccs/lib;/lib;/usr/lib")
+list(APPEND platforms sun_cc)
+
+# CC dummy.cxx -v
+set(sun_CC_text "/usr/ccs/bin/ld -u __1cH__CimplKcplus_init6F_v_ -zld32=-S/opt/SUNWspro/prod/lib/libldstab_ws.so -zld64=-S/opt/SUNWspro/prod/lib/v9/libldstab_ws.so -zld32=-S/opt/SUNWspro/prod/lib/libCCexcept.so.1 -zld64=-S/opt/SUNWspro/prod/lib/v9/libCCexcept.so.1 -R/opt/SUNWspro/lib/rw7:/opt/SUNWspro/lib/v8plus:/opt/SUNWspro/lib:/usr/ccs/lib:/lib:/usr/lib -o a.out /opt/SUNWspro/prod/lib/crti.o /opt/SUNWspro/prod/lib/CCrti.o /opt/SUNWspro/prod/lib/crt1.o /opt/SUNWspro/prod/lib/misalign.o /opt/SUNWspro/prod/lib/values-xa.o -Y P,/opt/SUNWspro/lib/rw7:/opt/SUNWspro/lib/v8plus:/opt/SUNWspro/prod/lib/rw7:/opt/SUNWspro/prod/lib/v8plus:/opt/SUNWspro/lib:/opt/SUNWspro/prod/lib:/usr/ccs/lib:/lib:/usr/lib dummy.o -lCstd -lCrun -lm -lc /opt/SUNWspro/prod/lib/CCrtn.o /opt/SUNWspro/prod/lib/crtn.o >&/tmp/ld.14846.2.err")
+set(sun_CC_libs "Cstd;Crun;m;c")
+set(sun_CC_dirs "/opt/SUNWspro/lib/rw7;/opt/SUNWspro/lib/v8plus;/opt/SUNWspro/prod/lib/rw7;/opt/SUNWspro/prod/lib/v8plus;/opt/SUNWspro/lib;/opt/SUNWspro/prod/lib;/usr/ccs/lib;/lib;/usr/lib")
+list(APPEND platforms sun_CC)
+
+# f77 dummy.f -v
+set(sun_f77_text "/usr/ccs/bin/ld -t -R/opt/SUNWspro/lib/v8plus:/opt/SUNWspro/lib -o a.out /opt/SUNWspro/prod/lib/crti.o /opt/SUNWspro/prod/lib/crt1.o /opt/SUNWspro/prod/lib/misalign.o /opt/SUNWspro/prod/lib/values-xi.o -Y P,/opt/SUNWspro/lib/v8plus:/opt/SUNWspro/prod/lib/v8plus:/opt/SUNWspro/lib:/opt/SUNWspro/prod/lib:/usr/ccs/lib:/lib:/usr/lib dummy.o -lf77compat -zallextract -lompstubs -zdefaultextract -lfui -lfai -lfai2 -lfsumai -lfprodai -lfminlai -lfmaxlai -lfminvai -lfmaxvai -lfsu -lsunmath -lm -lc /opt/SUNWspro/prod/lib/crtn.o")
+set(sun_f77_libs "f77compat;-zallextract;ompstubs;-zdefaultextract;fui;fai;fai2;fsumai;fprodai;fminlai;fmaxlai;fminvai;fmaxvai;fsu;sunmath;m;c")
+set(sun_f77_dirs "/opt/SUNWspro/lib/v8plus;/opt/SUNWspro/prod/lib/v8plus;/opt/SUNWspro/lib;/opt/SUNWspro/prod/lib;/usr/ccs/lib;/lib;/usr/lib")
+list(APPEND platforms sun_f77)
+
+# f90 dummy.f -v
+set(sun_f90_text "/usr/ccs/bin/ld -t -R/opt/SUNWspro/lib/v8plus:/opt/SUNWspro/lib -o a.out /opt/SUNWspro/prod/lib/crti.o /opt/SUNWspro/prod/lib/crt1.o /opt/SUNWspro/prod/lib/misalign.o /opt/SUNWspro/prod/lib/values-xi.o -Y P,/opt/SUNWspro/lib/v8plus:/opt/SUNWspro/prod/lib/v8plus:/opt/SUNWspro/lib:/opt/SUNWspro/prod/lib:/usr/ccs/lib:/lib:/usr/lib dummy.o -zallextract -lompstubs -zdefaultextract -lfui -lfai -lfai2 -lfsumai -lfprodai -lfminlai -lfmaxlai -lfminvai -lfmaxvai -lfsu -lsunmath -lm -lc /opt/SUNWspro/prod/lib/crtn.o")
+set(sun_f90_libs "-zallextract;ompstubs;-zdefaultextract;fui;fai;fai2;fsumai;fprodai;fminlai;fmaxlai;fminvai;fmaxvai;fsu;sunmath;m;c")
+set(sun_f90_dirs "/opt/SUNWspro/lib/v8plus;/opt/SUNWspro/prod/lib/v8plus;/opt/SUNWspro/lib;/opt/SUNWspro/prod/lib;/usr/ccs/lib;/lib;/usr/lib")
+list(APPEND platforms sun_f90)
+
+#-----------------------------------------------------------------------------
+# AIX
+
+# xlc -q32 dummy.c -V
+set(aix_xlc_32_text "/bin/ld -b32 /lib/crt0.o -bpT:0x10000000 -bpD:0x20000000 dummy.o -L/usr/vac/lib -lxlopt -lxl -lc")
+set(aix_xlc_32_libs "xlopt;xl;c")
+set(aix_xlc_32_dirs "/usr/vac/lib")
+list(APPEND platforms aix_xlc_32)
+
+# xlc -q64 dummy.c -V
+set(aix_xlc_64_text "/bin/ld -b64 /lib/crt0_64.o -bpT:0x100000000 -bpD:0x110000000 dummy.o -L/usr/vac/lib -lxlopt -lxl -lc")
+set(aix_xlc_64_libs "xlopt;xl;c")
+set(aix_xlc_64_dirs "/usr/vac/lib")
+list(APPEND platforms aix_xlc_64)
+
+# xlC -q32 dummy.cxx -V
+set(aix_xlC_32_text "
+/bin/ld -b32 /lib/crt0.o -bpT:0x10000000 -bpD:0x20000000 dummy.o -L/usr/vac/lib -lxlopt -lxl -L/usr/vacpp/lib -lC -lm -lc -bnobind >/tmp/xlcLDW0agyh
+/bin/ld -b32 /lib/crt0.o -bpT:0x10000000 -bpD:0x20000000 dummy.o -L/usr/vac/lib -lxlopt -lxl -L/usr/vacpp/lib -lC -lm -lc |")
+set(aix_xlC_32_libs "xlopt;xl;C;m;c")
+set(aix_xlC_32_dirs "/usr/vac/lib;/usr/vacpp/lib")
+list(APPEND platforms aix_xlC_32)
+
+# xlC -q64 dummy.cxx -V
+set(aix_xlC_64_text "
+/bin/ld -b64 /lib/crt0_64.o -bpT:0x100000000 -bpD:0x110000000 dummy.o -L/usr/vac/lib -lxlopt -lxl -L/usr/vacpp/lib -lC -lm -lc -bnobind >/tmp/xlcLD5nUnah
+/bin/ld -b64 /lib/crt0_64.o -bpT:0x100000000 -bpD:0x110000000 dummy.o -L/usr/vac/lib -lxlopt -lxl -L/usr/vacpp/lib -lC -lm -lc |")
+set(aix_xlC_64_libs "xlopt;xl;C;m;c")
+set(aix_xlC_64_dirs "/usr/vac/lib;/usr/vacpp/lib")
+list(APPEND platforms aix_xlC_64)
+
+# xlf -q32 dummy.f -V
+set(aix_xlf_32_text "/bin/ld -b32 /lib/crt0.o -bpT:0x10000000 -bpD:0x20000000 -bh:4 -bh:4 -bh:4 -bh:4 dummy.o -lxlf90 -L/usr/lpp/xlf/lib -lxlopt -lxlf -lxlomp_ser -lm -lc")
+set(aix_xlf_32_libs "xlf90;xlopt;xlf;xlomp_ser;m;c")
+set(aix_xlf_32_dirs "/usr/lpp/xlf/lib")
+list(APPEND platforms aix_xlf_32)
+
+# xlf -q64 dummy.f -V
+set(aix_xlf_64_text "/bin/ld -b64 /lib/crt0_64.o -bpT:0x100000000 -bpD:0x110000000 -bh:4 -bh:4 -bh:4 -bh:4 dummy.o -lxlf90 -L/usr/lpp/xlf/lib -lxlopt -lxlf -lxlomp_ser -lm -lc")
+set(aix_xlf_64_libs "xlf90;xlopt;xlf;xlomp_ser;m;c")
+set(aix_xlf_64_dirs "/usr/lpp/xlf/lib")
+list(APPEND platforms aix_xlf_64)
+
+# xlf90 -q32 dummy.f -V
+set(aix_xlf90_32_text "/bin/ld -b32 /lib/crt0.o -bpT:0x10000000 -bpD:0x20000000 -bh:4 dummy.o -lxlf90 -L/usr/lpp/xlf/lib -lxlopt -lxlf -lxlomp_ser -lm -lc")
+set(aix_xlf90_32_libs "xlf90;xlopt;xlf;xlomp_ser;m;c")
+set(aix_xlf90_32_dirs "/usr/lpp/xlf/lib")
+list(APPEND platforms aix_xlf90_32)
+
+# xlf90 -q64 dummy.f -V
+set(aix_xlf90_64_text "/bin/ld -b64 /lib/crt0_64.o -bpT:0x100000000 -bpD:0x110000000 -bh:4 dummy.o -lxlf90 -L/usr/lpp/xlf/lib -lxlopt -lxlf -lxlomp_ser -lm -lc")
+set(aix_xlf90_64_libs "xlf90;xlopt;xlf;xlomp_ser;m;c")
+set(aix_xlf90_64_dirs "/usr/lpp/xlf/lib")
+list(APPEND platforms aix_xlf90_64)
+
+# g++ dummy.c -v
+set(aix_g++_text " /prefix/libexec/gcc/powerpc-ibm-aix7.2.0.0/7.2.0/collect2 -bpT:0x10000000 -bpD:0x20000000 -btextro /lib/crt0.o /prefix/lib/gcc/powerpc-ibm-aix7.2.0.0/7.2.0/crtcxa.o /prefix/lib/gcc/powerpc-ibm-aix7.2.0.0/7.2.0/crtdbase.o -L/prefix/lib/gcc/powerpc-ibm-aix7.2.0.0/7.2.0 -L/prefix/lib/gcc/powerpc-ibm-aix7.2.0.0/7.2.0/../../.. /tmp//ccKROJ1f.o -lstdc++ -lm -lgcc_s /prefix/lib/gcc/powerpc-ibm-aix7.2.0.0/7.2.0/libgcc.a -lc -lgcc_s /prefix/lib/gcc/powerpc-ibm-aix7.2.0.0/7.2.0/libgcc.a")
+set(aix_g++_libs "stdc++;m;gcc_s;/prefix/lib/gcc/powerpc-ibm-aix7.2.0.0/7.2.0/libgcc.a;c;gcc_s;/prefix/lib/gcc/powerpc-ibm-aix7.2.0.0/7.2.0/libgcc.a")
+set(aix_g++_dirs "/prefix/lib/gcc/powerpc-ibm-aix7.2.0.0/7.2.0;/prefix/lib")
+list(APPEND platforms aix_g++)
+
+#-----------------------------------------------------------------------------
+# HP
+
+# cc dummy.c -v
+set(hp_cc_old_text "cc: LPATH is /usr/lib/pa1.1:/usr/lib:/opt/langtools/lib:
+/usr/ccs/bin/ld /opt/langtools/lib/crt0.o -u main dummy.o -lc")
+set(hp_cc_old_libs "c")
+set(hp_cc_old_dirs "/usr/lib/pa1.1;/usr/lib;/opt/langtools/lib")
+list(APPEND platforms hp_cc_old)
+
+# aCC dummy.cxx -v
+set(hp_aCC_old_text "LPATH=/usr/lib/pa1.1:/usr/lib:/opt/langtools/lib
+ /usr/ccs/bin/ld -o a.out /opt/aCC/lib/crt0.o -u ___exit -u main -L /opt/aCC/lib /opt/aCC/lib/cpprt0.o dummy.o -lstd -lstream -lCsup -lm -lcl -lc /usr/lib/libdld.sl >/var/tmp/AAAa27787 2>&1")
+set(hp_aCC_old_libs "std;stream;Csup;m;cl;c")
+set(hp_aCC_old_dirs "/usr/lib/pa1.1;/usr/lib;/opt/langtools/lib;/opt/aCC/lib")
+list(APPEND platforms hp_aCC_old)
+
+# cc dummy.c -v
+set(hp_cc_32_text "LPATH=/usr/lib/hpux32:/opt/langtools/lib/hpux32
+ /usr/ccs/bin/ld -o a.out -u___exit -umain dummy.o -lc")
+set(hp_cc_32_libs "c")
+set(hp_cc_32_dirs "/usr/lib/hpux32;/opt/langtools/lib/hpux32")
+list(APPEND platforms hp_cc_32)
+
+# cc +DD64 dummy.c -v
+set(hp_cc_64_text "LPATH=/usr/lib/hpux64:/opt/langtools/lib/hpux64
+ /usr/ccs/bin/ld -o a.out -u___exit -umain dummy.o -lc")
+set(hp_cc_64_libs "c")
+set(hp_cc_64_dirs "/usr/lib/hpux64;/opt/langtools/lib/hpux64")
+list(APPEND platforms hp_cc_64)
+
+# aCC dummy.cxx -v
+set(hp_aCC_32_text "LPATH=/usr/lib/hpux32:/opt/langtools/lib/hpux32
+ /usr/ccs/bin/ld -o a.out -u___exit -umain -L/opt/aCC/lib/hpux32 dummy.o -lstd_v2 -lCsup -lm -lunwind -lCsup -lc -ldl >/var/tmp/AAAa03601 2>&1")
+set(hp_aCC_32_libs "std_v2;Csup;m;unwind;Csup;c;dl")
+set(hp_aCC_32_dirs "/usr/lib/hpux32;/opt/langtools/lib/hpux32;/opt/aCC/lib/hpux32")
+list(APPEND platforms hp_aCC_32)
+
+# aCC +DD64 dummy.cxx -v
+set(hp_aCC_64_text "LPATH=/usr/lib/hpux64:/opt/langtools/lib/hpux64
+ /usr/ccs/bin/ld -o a.out -u___exit -umain -L/opt/aCC/lib/hpux64 dummy.o -lstd_v2 -lCsup -lm -lunwind -lCsup -lc -ldl >/var/tmp/AAAa03597 2>&1")
+set(hp_aCC_64_libs "std_v2;Csup;m;unwind;Csup;c;dl")
+set(hp_aCC_64_dirs "/usr/lib/hpux64;/opt/langtools/lib/hpux64;/opt/aCC/lib/hpux64")
+list(APPEND platforms hp_aCC_64)
+
+# f90 dummy.f -v
+set(hp_f90_32_text "LPATH is: /usr/lib/hpux32/:/opt/langtools/lib/hpux32/
+/usr/ccs/bin/ld -u f90\$sgemm -u f90\$sgemv -u f90\$dgemm -u f90\$dgemv dummy.c +vnoshlibunsats -l:libF90.a -l:libIO77.a -lm -lc -lunwind -luca")
+set(hp_f90_32_libs "-l:libF90.a;-l:libIO77.a;m;c;unwind;uca")
+set(hp_f90_32_dirs "/usr/lib/hpux32;/opt/langtools/lib/hpux32")
+list(APPEND platforms hp_f90_32)
+
+# f90 +DD64 dummy.f -v
+set(hp_f90_64_text "LPATH is: /usr/lib/hpux64/:/opt/langtools/lib/hpux64/
+/usr/ccs/bin/ld -u f90\$sgemm -u f90\$sgemv -u f90\$dgemm -u f90\$dgemv dummy.c +vnoshlibunsats -l:libF90.a -l:libIO77.a -lm -lc -lunwind -luca")
+set(hp_f90_64_libs "-l:libF90.a;-l:libIO77.a;m;c;unwind;uca")
+set(hp_f90_64_dirs "/usr/lib/hpux64;/opt/langtools/lib/hpux64")
+list(APPEND platforms hp_f90_64)
+
+#-----------------------------------------------------------------------------
+# Cygwin
+
+# gcc dummy.c -v
+set(cygwin_gcc_text " /usr/lib/gcc/i686-pc-cygwin/3.4.4/collect2.exe -Bdynamic --dll-search-prefix=cyg /usr/lib/gcc/i686-pc-cygwin/3.4.4/../../../crt0.o -L/usr/lib/gcc/i686-pc-cygwin/3.4.4 -L/usr/lib/gcc/i686-pc-cygwin/3.4.4 -L/usr/lib/gcc/i686-pc-cygwin/3.4.4/../../.. /home/user/AppData/Local/Temp/cczg1Arh.o -lgcc -lcygwin -luser32 -lkernel32 -ladvapi32 -lshell32 -lgcc")
+set(cygwin_gcc_libs "gcc;cygwin;user32;kernel32;advapi32;shell32;gcc")
+set(cygwin_gcc_dirs "/usr/lib/gcc/i686-pc-cygwin/3.4.4;/usr/lib")
+list(APPEND platforms cygwin_gcc)
+
+# g++ dummy.cxx -v
+set(cygwin_g++_text " /usr/lib/gcc/i686-pc-cygwin/3.4.4/collect2.exe -Bdynamic --dll-search-prefix=cyg /usr/lib/gcc/i686-pc-cygwin/3.4.4/../../../crt0.o -L/usr/lib/gcc/i686-pc-cygwin/3.4.4 -L/usr/lib/gcc/i686-pc-cygwin/3.4.4 -L/usr/lib/gcc/i686-pc-cygwin/3.4.4/../../.. /home/user/AppData/Local/Temp/ccsvcDO6.o -lstdc++ -lgcc -lcygwin -luser32 -lkernel32 -ladvapi32 -lshell32 -lgcc")
+set(cygwin_g++_libs "stdc++;gcc;cygwin;user32;kernel32;advapi32;shell32;gcc")
+set(cygwin_g++_dirs "/usr/lib/gcc/i686-pc-cygwin/3.4.4;/usr/lib")
+list(APPEND platforms cygwin_g++)
+
+# gfortran dummy.f -v
+set(cygwin_gfortran_text "Configured with: ... LD=/opt/gcc-tools/bin/ld.exe
+ /usr/lib/gcc/i686-pc-cygwin/4.3.2/collect2.exe -Bdynamic --dll-search-prefix=cyg -u ___register_frame_info -u ___deregister_frame_info /usr/lib/gcc/i686-pc-cygwin/4.3.2/../../../crt0.o /usr/lib/gcc/i686-pc-cygwin/4.3.2/crtbegin.o -L/usr/lib/gcc/i686-pc-cygwin/4.3.2 -L/usr/lib/gcc/i686-pc-cygwin/4.3.2 -L/usr/lib/gcc/i686-pc-cygwin/4.3.2/../../.. /home/user/AppData/Local/Temp/ccqRWKWg.o -lgfortranbegin -lgfortran -lgcc_s -lgcc_s -lgcc -lcygwin -luser32 -lkernel32 -ladvapi32 -lshell32 -lgcc_s -lgcc_s -lgcc /usr/lib/gcc/i686-pc-cygwin/4.3.2/crtend.o
+")
+set(cygwin_gfortran_libs "gfortranbegin;gfortran;gcc_s;gcc_s;gcc;cygwin;user32;kernel32;advapi32;shell32;gcc_s;gcc_s;gcc")
+set(cygwin_gfortran_dirs "/usr/lib/gcc/i686-pc-cygwin/4.3.2;/usr/lib")
+list(APPEND platforms cygwin_gfortran)
+
+#-----------------------------------------------------------------------------
+# MSYS
+
+# gcc dummy.c -v
+set(msys_gcc_text " C:/some-mingw/bin/../libexec/gcc/mingw32/3.4.5/collect2.exe -Bdynamic /some-mingw/lib/crt2.o C:/some-mingw/bin/../lib/gcc/mingw32/3.4.5/crtbegin.o -LC:/some-mingw/bin/../lib/gcc/mingw32/3.4.5 -LC:/some-mingw/bin/../lib/gcc -L/some-mingw/lib -LC:/some-mingw/bin/../lib/gcc/mingw32/3.4.5/../../.. C:/home/user/AppData/Local/Temp/cckQmvRt.o -lmingw32 -lgcc -lmoldname -lmingwex -lmsvcrt -luser32 -lkernel32 -ladvapi32 -lshell32 -lmingw32 -lgcc -lmoldname -lmingwex -lmsvcrt C:/some-mingw/bin/../lib/gcc/mingw32/3.4.5/crtend.o")
+set(msys_gcc_libs "mingw32;gcc;moldname;mingwex;user32;kernel32;advapi32;shell32;mingw32;gcc;moldname;mingwex")
+set(msys_gcc_dirs "C:/some-mingw/lib/gcc/mingw32/3.4.5;C:/some-mingw/lib/gcc;/some-mingw/lib;C:/some-mingw/lib")
+list(APPEND platforms msys_gcc)
+
+# g++ dummy.cxx -v
+set(msys_g++_text " C:/some-mingw/bin/../libexec/gcc/mingw32/3.4.5/collect2.exe -Bdynamic /some-mingw/lib/crt2.o C:/some-mingw/bin/../lib/gcc/mingw32/3.4.5/crtbegin.o -LC:/some-mingw/bin/../lib/gcc/mingw32/3.4.5 -LC:/some-mingw/bin/../lib/gcc -L/some-mingw/lib -LC:/some-mingw/bin/../lib/gcc/mingw32/3.4.5/../../.. C:/home/user/AppData/Local/Temp/cci5hYPk.o -lstdc++ -lmingw32 -lgcc -lmoldname -lmingwex -lmsvcrt -luser32 -lkernel32 -ladvapi32 -lshell32 -lmingw32 -lgcc -lmoldname -lmingwex -lmsvcrt C:/some-mingw/bin/../lib/gcc/mingw32/3.4.5/crtend.o")
+set(msys_g++_libs "stdc++;mingw32;gcc;moldname;mingwex;user32;kernel32;advapi32;shell32;mingw32;gcc;moldname;mingwex")
+set(msys_g++_dirs "C:/some-mingw/lib/gcc/mingw32/3.4.5;C:/some-mingw/lib/gcc;/some-mingw/lib;C:/some-mingw/lib")
+list(APPEND platforms msys_g++)
+
+# g77 dummy.f -v
+set(msys_g77_text " C:/some-mingw/bin/../libexec/gcc/mingw32/3.4.5/collect2.exe -Bdynamic /some-mingw/lib/crt2.o C:/some-mingw/bin/../lib/gcc/mingw32/3.4.5/crtbegin.o -LC:/some-mingw/bin/../lib/gcc/mingw32/3.4.5 -LC:/some-mingw/bin/../lib/gcc -L/some-mingw/lib -LC:/some-mingw/bin/../lib/gcc/mingw32/3.4.5/../../.. C:/home/user/AppData/Local/Temp/ccabRxQ1.o -lfrtbegin -lg2c -lmingw32 -lgcc -lmoldname -lmingwex -lmsvcrt -luser32 -lkernel32 -ladvapi32 -lshell32 -lmingw32 -lgcc -lmoldname -lmingwex -lmsvcrt C:/some-mingw/bin/../lib/gcc/mingw32/3.4.5/crtend.o")
+set(msys_g77_libs "frtbegin;g2c;mingw32;gcc;moldname;mingwex;user32;kernel32;advapi32;shell32;mingw32;gcc;moldname;mingwex")
+set(msys_g77_dirs "C:/some-mingw/lib/gcc/mingw32/3.4.5;C:/some-mingw/lib/gcc;/some-mingw/lib;C:/some-mingw/lib")
+list(APPEND platforms msys_g77)
+
+#-----------------------------------------------------------------------------
+# MSYS2
+
+# gcc dummy.c -v
+set(msys2_gcc_text " C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/collect2.exe -plugin C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/liblto_plugin-0.dll -plugin-opt=C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/lto-wrapper.exe -plugin-opt=-fresolution=C:/msys64/tmp/ccikz9Wf.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-lpthread -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -m i386pep -Bdynamic C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/crtbegin.o -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0 -LC:/msys64/mingw64/bin/../lib/gcc -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib/../lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../.. C:/msys64/tmp/ccK0dTUv.o -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib/../lib/default-manifest.o C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/crtend.o")
+set(msys2_gcc_libs "mingw32;gcc;moldname;mingwex;pthread;advapi32;shell32;user32;kernel32;mingw32;gcc;moldname;mingwex")
+set(msys2_gcc_dirs "C:/msys64/mingw64/lib/gcc/x86_64-w64-mingw32/7.2.0;C:/msys64/mingw64/lib/gcc;C:/msys64/mingw64/x86_64-w64-mingw32/lib;C:/msys64/mingw64/lib")
+list(APPEND platforms msys2_gcc)
+
+# g++ dummy.cxx -v
+set(msys2_g++_text " C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/collect2.exe -plugin C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/liblto_plugin-0.dll -plugin-opt=C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/lto-wrapper.exe -plugin-opt=-fresolution=C:/msys64/tmp/ccJQgvbN.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-lpthread -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -m i386pep -Bdynamic C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/crtbegin.o -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0 -LC:/msys64/mingw64/bin/../lib/gcc -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib/../lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../.. C:/msys64/tmp/ccqPpuVS.o -lstdc++ -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib/../lib/default-manifest.o C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/crtend.o")
+set(msys2_g++_libs "stdc++;mingw32;gcc_s;gcc;moldname;mingwex;pthread;advapi32;shell32;user32;kernel32;mingw32;gcc_s;gcc;moldname;mingwex")
+set(msys2_g++_dirs "C:/msys64/mingw64/lib/gcc/x86_64-w64-mingw32/7.2.0;C:/msys64/mingw64/lib/gcc;C:/msys64/mingw64/x86_64-w64-mingw32/lib;C:/msys64/mingw64/lib")
+list(APPEND platforms msys2_g++)
+
+# gfortran dummy.f90 -v
+set(msys2_gfortran_text " C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/collect2.exe -plugin C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/liblto_plugin-0.dll -plugin-opt=C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/lto-wrapper.exe -plugin-opt=-fresolution=C:/msys64/tmp/cczOKIDy.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-lquadmath -plugin-opt=-pass-through=-lm -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-lpthread -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -m i386pep -Bdynamic C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/crtbegin.o -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0 -LC:/msys64/mingw64/bin/../lib/gcc -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib/../lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../.. C:/msys64/tmp/ccyXuCgD.o -lgfortran -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt -lquadmath -lm -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib/../lib/default-manifest.o C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/crtend.o")
+set(msys2_gfortran_libs "gfortran;mingw32;gcc_s;gcc;moldname;mingwex;quadmath;m;mingw32;gcc_s;gcc;moldname;mingwex;pthread;advapi32;shell32;user32;kernel32;mingw32;gcc_s;gcc;moldname;mingwex")
+set(msys2_gfortran_dirs "C:/msys64/mingw64/lib/gcc/x86_64-w64-mingw32/7.2.0;C:/msys64/mingw64/lib/gcc;C:/msys64/mingw64/x86_64-w64-mingw32/lib;C:/msys64/mingw64/lib")
+list(APPEND platforms msys2_gfortran)
+
+#-----------------------------------------------------------------------------
+# MSVC from NVIDIA CUDA
+
+set(nvcc_msvc_text [[cuda-fake-ld cl.exe -nologo "tmp/a_dlink.obj" "tmp/CMakeCUDACompilerId.obj" -link -INCREMENTAL:NO "/LIBPATH:C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v8.0/bin/../lib/x64" cudadevrt.lib cudart_static.lib -Fe"a.exe"]])
+set(nvcc_msvc_libs "cudadevrt.lib;cudart_static.lib")
+set(nvcc_msvc_dirs "C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v8.0/lib/x64")
+list(APPEND platforms nvcc_msvc)
+
+#-----------------------------------------------------------------------------
+# PGI on Windows
+
+# Due to the different behavior of separate_arguments on non-Windows platforms,
+# the following tests can only be performed on Windows
+if(CMAKE_HOST_WIN32)
+
+# pgf95 dummy.f90 -v
+set(windows_pgf95_text [[Writing to file C:\temp\pgf9510ipeUbTwN2V4pn.lnk
+X:\NOT-PROGRAM-FILES\PGICE/win64/17.4/lib\pgimainmx.obj C:\Program Files\PGICE/win64/17.4/lib\f90main.obj -incremental:no -debug -merge:__nv_module_id=.data -merge:.nvFatBinSegment=.data "-libpath:X:/NOT-PROGRAM-FILES-86/Microsoft Visual Studio 14.0/VC/Lib/AMD64" "-libpath:X:/NOT-PROGRAM-FILES-86/Windows Kits/10/Lib/10.0.15063.0/ucrt/x64" "-libpath:X:/NOT-PROGRAM-FILES-86/Windows Kits/10/Lib/10.0.15063.0/um/x64" -libpath:X:\NOT-PROGRAM-FILES\PGICE/win64/17.4/lib C:\temp\pgf959hxeUbfMYOLjUz.obj -out:dummy.exe -pdb:./dummy.pdb /DYNAMICBASE:NO -defaultlib:libpgmp -defaultlib:pg -defaultlib:libpgf90rtl -defaultlib:libpgf90 -defaultlib:libpgf90_rpm1 -defaultlib:libpgf902 -defaultlib:libpgf90rtl -defaultlib:libpgftnrtl -nodefaultlib:msvcrt -defaultlib:libvcruntime -defaultlib:libucrt -defaultlib:libcmt -defaultlib:libpgc14 -defaultlib:libnspgc -defaultlib:legacy_stdio_definitions -defaultlib:oldnames
+
+"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/amd64\link.exe" /NOLOGO @C:\temp\pgf9510ipeUbTwN2V4pn.lnk]])
+set(windows_pgf95_startfile "pgimain[mx][xpt]+[.]obj")
+set(windows_pgf95_libs "libpgmp;pg;libpgf90rtl;libpgf90;libpgf90_rpm1;libpgf902;libpgf90rtl;libpgftnrtl;libpgc14;libnspgc;legacy_stdio_definitions;oldnames")
+set(windows_pgf95_dirs "X:/NOT-PROGRAM-FILES-86/Microsoft Visual Studio 14.0/VC/Lib/AMD64;X:/NOT-PROGRAM-FILES-86/Windows Kits/10/Lib/10.0.15063.0/ucrt/x64;X:/NOT-PROGRAM-FILES-86/Windows Kits/10/Lib/10.0.15063.0/um/x64;X:/NOT-PROGRAM-FILES/PGICE/win64/17.4/lib")
+list(APPEND platforms windows_pgf95)
+
+# pgf77 dummy.f77 -v
+set(windows_pgf77_text [[Writing to file C:\temp\pgf776eC42buYRoCNJk.lnk
+X:\NOT-PROGRAM-FILES\PGICE/win64/17.4/lib\pgimainmx.obj C:\Program Files\PGICE/win64/17.4/lib\pgfmain.obj -incremental:no -debug -merge:__nv_module_id=.data -merge:.nvFatBinSegment=.data "-libpath:X:/NOT-PROGRAM-FILES-86/Microsoft Visual Studio 14.0/VC/Lib/AMD64" "-libpath:X:/NOT-PROGRAM-FILES-86/Windows Kits/10/Lib/10.0.15063.0/ucrt/x64" "-libpath:X:/NOT-PROGRAM-FILES-86/Windows Kits/10/Lib/10.0.15063.0/um/x64" -libpath:X:\NOT-PROGRAM-FILES\PGICE/win64/17.4/lib C:\temp\pgf775d842b0tH8AkdP.obj -out:dummy.exe -pdb:./dummy.pdb /DYNAMICBASE:NO -defaultlib:libpgmp -defaultlib:libpgftnrtl -nodefaultlib:msvcrt -defaultlib:libvcruntime -defaultlib:libucrt -defaultlib:libcmt -defaultlib:libpgc14 -defaultlib:libnspgc -defaultlib:legacy_stdio_definitions -defaultlib:oldnames
+
+"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/amd64\link.exe" /NOLOGO @C:\temp\pgf776eC42buYRoCNJk.lnk]])
+set(windows_pgf77_startfile "pgimain[mx][xpt]+[.]obj")
+set(windows_pgf77_libs "libpgmp;libpgftnrtl;libpgc14;libnspgc;legacy_stdio_definitions;oldnames")
+set(windows_pgf77_dirs "X:/NOT-PROGRAM-FILES-86/Microsoft Visual Studio 14.0/VC/Lib/AMD64;X:/NOT-PROGRAM-FILES-86/Windows Kits/10/Lib/10.0.15063.0/ucrt/x64;X:/NOT-PROGRAM-FILES-86/Windows Kits/10/Lib/10.0.15063.0/um/x64;X:/NOT-PROGRAM-FILES/PGICE/win64/17.4/lib")
+list(APPEND platforms windows_pgf77)
+
+# pgcc dummy.c -v
+set(windows_pgcc_text [[Writing to file C:\temp\pgcc6esqW26_ZNKyL.lnk
+X:\NOT-PROGRAM-FILES\PGICE/win64/17.4/lib\pgimainmx.obj -incremental:no -debug -merge:__nv_module_id=.data -merge:.nvFatBinSegment=.data "-libpath:X:/NOT-PROGRAM-FILES-86/Microsoft Visual Studio 14.0/VC/Lib/AMD64" "-libpath:X:/NOT-PROGRAM-FILES-86/Windows Kits/10/Lib/10.0.15063.0/ucrt/x64" "-libpath:X:/NOT-PROGRAM-FILES-86/Windows Kits/10/Lib/10.0.15063.0/um/x64" -libpath:X:\NOT-PROGRAM-FILES\PGICE/win64/17.4/lib C:\temp\pgcc5dcqWgQXeXPWd.obj -out:dummy.exe -pdb:./dummy.pdb /DYNAMICBASE:NO -defaultlib:libpgmp -nodefaultlib:msvcrt -defaultlib:libvcruntime -defaultlib:libucrt -defaultlib:libcmt -defaultlib:libpgc14 -defaultlib:libnspgc -defaultlib:legacy_stdio_definitions -defaultlib:oldnames
+
+"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/amd64\link.exe" /NOLOGO @C:\temp\pgcc6esqW26_ZNKyL.lnk]])
+set(windows_pgcc_startfile "pgimain[mx][xpt]+[.]obj")
+set(windows_pgcc_libs "libpgmp;libpgc14;libnspgc;legacy_stdio_definitions;oldnames")
+set(windows_pgcc_dirs "X:/NOT-PROGRAM-FILES-86/Microsoft Visual Studio 14.0/VC/Lib/AMD64;X:/NOT-PROGRAM-FILES-86/Windows Kits/10/Lib/10.0.15063.0/ucrt/x64;X:/NOT-PROGRAM-FILES-86/Windows Kits/10/Lib/10.0.15063.0/um/x64;X:/NOT-PROGRAM-FILES/PGICE/win64/17.4/lib")
+list(APPEND platforms windows_pgcc)
+
+endif()
+
+#-----------------------------------------------------------------------------
+# Test parsing for all above examples.
+set(CMAKE_LINKER "not-a-linker[]().*+^$?")
+
+foreach(p IN LISTS platforms)
+ if(DEFINED ${p}_startfile)
+ set(CMAKE_LINK_STARTFILE "${${p}_startfile}")
+ else()
+ unset(CMAKE_LINK_STARTFILE)
+ endif()
+ cmake_parse_implicit_link_info("${${p}_text}" libs dirs fwks log "${${p}_obj_regex}")
+
+ foreach(v libs dirs fwks)
+ if(DEFINED "${p}_${v}" AND NOT "${${v}}" STREQUAL "${${p}_${v}}")
+ message(FATAL_ERROR
+ "cmake_parse_implicit_link_info failed\n"
+ "Expected '${p}' implicit ${v}\n"
+ " [${${p}_${v}}]\n"
+ "but got\n"
+ " [${${v}}]\n"
+ "Parse log was:\n"
+ "${log}"
+ )
+ endif()
+ endforeach()
+endforeach()
diff --git a/Tests/CMakeTests/IncludeTest.cmake.in b/Tests/CMakeTests/IncludeTest.cmake.in
new file mode 100644
index 0000000..985333c
--- /dev/null
+++ b/Tests/CMakeTests/IncludeTest.cmake.in
@@ -0,0 +1,41 @@
+# this one must silently fail
+include(I_am_not_here OPTIONAL)
+
+# this one must be found and the result must be put into _includedFile
+include(CMake RESULT_VARIABLE _includedFile)
+
+set(fileOne "${_includedFile}")
+set(fileTwo "${CMAKE_ROOT}/Modules/CMake.cmake")
+if(WIN32)
+ string(TOLOWER "${fileOne}" fileOne)
+ string(TOLOWER "${fileTwo}" fileTwo)
+endif()
+
+if(NOT "${fileOne}" STREQUAL "${fileTwo}")
+ message(FATAL_ERROR "Wrong CMake.cmake was included: \"${fileOne}\" expected \"${fileTwo}\"")
+endif()
+
+# this one must return NOTFOUND in _includedFile
+include(I_do_not_exist OPTIONAL RESULT_VARIABLE _includedFile)
+
+if(_includedFile)
+ message(FATAL_ERROR "File \"I_do_not_exist\" was included, although it shouldn't exist,\nIncluded file is \"${_includedFile}\"")
+endif()
+
+# and this one must succeed too
+include(CMake OPTIONAL RESULT_VARIABLE _includedFile)
+set(fileOne "${_includedFile}")
+set(fileTwo "${CMAKE_ROOT}/Modules/CMake.cmake")
+if(WIN32)
+ string(TOLOWER "${fileOne}" fileOne)
+ string(TOLOWER "${fileTwo}" fileTwo)
+endif()
+
+if(NOT "${fileOne}" STREQUAL "${fileTwo}")
+ message(FATAL_ERROR "Wrong CMake.cmake was included: \"${fileOne}\" expected \"${fileTwo}\"")
+endif()
+
+# Check that CMAKE_CURRENT_LIST_DIR is working:
+# Needs to be a file in the build tree, which is correct cmake script
+# but doesn't do a lot, if possible only set() commands:
+include(${CMAKE_CURRENT_LIST_DIR}/../../CTestCustom.cmake)
diff --git a/Tests/CMakeTests/ListTest.cmake.in b/Tests/CMakeTests/ListTest.cmake.in
new file mode 100644
index 0000000..76737e5
--- /dev/null
+++ b/Tests/CMakeTests/ListTest.cmake.in
@@ -0,0 +1,163 @@
+include("@CMAKE_CURRENT_SOURCE_DIR@/CheckCMakeTest.cmake")
+
+macro(TEST command expected)
+ if("x${result}" STREQUAL "x${expected}")
+ #message("TEST \"${command}\" success: \"${result}\" expected: \"${expected}\"")
+ else()
+ message(SEND_ERROR "${CMAKE_CURRENT_LIST_LINE}: TEST \"${command}\" failed: \"${result}\" expected: \"${expected}\"")
+ endif()
+endmacro()
+
+set(mylist andy bill ken brad)
+
+list(LENGTH mylist result)
+TEST("LENGTH mylist result" "4")
+list(LENGTH "mylist" result)
+TEST("LENGTH \"mylist\" result" "4")
+
+list(LENGTH "nonexiting_list1" result)
+TEST("LENGTH \"nonexiting_list1\" result" "0")
+
+list(GET mylist 3 2 1 0 result)
+TEST("GET mylist 3 2 1 0 result" "brad;ken;bill;andy")
+
+list(GET mylist 0 item0)
+list(GET mylist 1 item1)
+list(GET mylist 2 item2)
+list(GET mylist 3 item3)
+set(result "${item3}" "${item0}" "${item1}" "${item2}")
+TEST("GET individual 3 2 1 0 result" "brad;andy;bill;ken")
+
+list(GET mylist -1 -2 -3 -4 result)
+TEST("GET mylist -1 -2 -3 -4 result" "brad;ken;bill;andy")
+
+list(GET mylist -1 2 -3 0 result)
+TEST("GET mylist -1 2 -3 0 ${result}" "brad;ken;bill;andy")
+
+list(GET "nonexiting_list2" 1 result)
+TEST("GET \"nonexiting_list2\" 1 result" "NOTFOUND")
+
+set(result andy)
+list(APPEND result brad)
+TEST("APPEND result brad" "andy;brad")
+
+list(APPEND "nonexiting_list3" brad)
+set(result "${nonexiting_list3}")
+TEST("APPEND \"nonexiting_list3\" brad" "brad")
+
+list(INSERT "nonexiting_list4" 0 andy bill brad ken)
+set(result "${nonexiting_list4}")
+TEST("APPEND \"nonexiting_list4\" andy bill brad ken" "andy;bill;brad;ken")
+
+set(result andy brad)
+list(INSERT result -1 bill ken)
+TEST("INSERT result -1 bill ken" "andy;bill;ken;brad")
+
+set(result andy brad)
+list(INSERT result 2 bill ken)
+TEST("INSERT result 2 bill ken" "andy;brad;bill;ken")
+
+set(result andy bill brad ken bob)
+list(REMOVE_ITEM result bob)
+TEST("REMOVE_ITEM result bob" "andy;bill;brad;ken")
+
+set(result andy bill bob brad ken peter)
+list(REMOVE_ITEM result peter bob)
+TEST("REMOVE_ITEM result peter bob" "andy;bill;brad;ken")
+
+set(result bob andy bill bob brad ken bob)
+list(REMOVE_ITEM result bob)
+TEST("REMOVE_ITEM result bob" "andy;bill;brad;ken")
+
+set(result andy bill bob brad ken peter)
+list(REMOVE_AT result 2 -1)
+TEST("REMOVE_AT result 2 -1" "andy;bill;brad;ken")
+
+# ken is at index 2, nobody is not in the list so -1 should be returned
+set(mylist andy bill ken brad)
+list(FIND mylist ken result)
+TEST("FIND mylist ken result" "2")
+
+list(FIND mylist nobody result)
+TEST("FIND mylist nobody result" "-1")
+
+set(result ken bill andy brad)
+list(SORT result)
+TEST("SORT result" "andy;bill;brad;ken")
+
+list(SORT result COMPARE NATURAL)
+TEST("SORT result COMPARE NATURAL" "andy;bill;brad;ken")
+
+set(result andy bill brad ken)
+list(REVERSE result)
+TEST("REVERSE result" "ken;brad;bill;andy")
+
+set(result bill andy bill brad ken ken ken)
+list(REMOVE_DUPLICATES result)
+TEST("REMOVE_DUPLICATES result" "bill;andy;brad;ken")
+
+# these commands should just do nothing if the list is already empty
+set(result "")
+list(REMOVE_DUPLICATES result)
+TEST("REMOVE_DUPLICATES empty result" "")
+
+list(REVERSE result)
+TEST("REVERSE empty result" "")
+
+list(SORT result)
+TEST("SORT empty result" "")
+
+list(SORT result COMPARE NATURAL)
+TEST("SORT result COMPARE NATURAL" "")
+
+set(result 1.1 10.0 11.0 12.0 12.1 2.0 2.1 3.0 3.1 3.2 8.0 9.0)
+
+list(SORT result COMPARE NATURAL)
+TEST("SORT result COMPARE NATURAL" "1.1;2.0;2.1;3.0;3.1;3.2;8.0;9.0;10.0;11.0;12.0;12.1")
+
+list(SORT result)
+TEST("SORT result" "1.1;10.0;11.0;12.0;12.1;2.0;2.1;3.0;3.1;3.2;8.0;9.0")
+
+list(SORT result COMPARE NATURAL ORDER DESCENDING)
+TEST("SORT result COMPARE NATURAL ORDER DESCENDING" "12.1;12.0;11.0;10.0;9.0;8.0;3.2;3.1;3.0;2.1;2.0;1.1")
+
+set(result b-1.1 a-10.0 c-2.0 d 1 00 0)
+
+list(SORT result COMPARE NATURAL)
+TEST("SORT result COMPARE NATURAL" "00;0;1;a-10.0;b-1.1;c-2.0;d")
+
+
+# these trigger top-level condition
+foreach(cmd IN ITEMS Append Find Get Insert Length Reverse Remove_At Remove_Duplicates Remove_Item Sort)
+ set(${cmd}-No-Arguments-RESULT 1)
+ set(${cmd}-No-Arguments-STDERR ".*CMake Error at List-${cmd}-No-Arguments.cmake:1 \\(list\\):.*list must be called with at least two arguments.*")
+ string(TOUPPER ${cmd} cmd_upper)
+ set(_test_file_name "${CMAKE_CURRENT_BINARY_DIR}/List-${cmd}-No-Arguments.cmake")
+ file(WRITE "${_test_file_name}" "list(${cmd_upper})\n")
+ check_cmake_test_single(List "${cmd}-No-Arguments" "${_test_file_name}")
+endforeach()
+
+set(Get-List-Only-STDERR "at least three")
+set(Find-List-Only-STDERR "three")
+set(Insert-List-Only-STDERR "at least three")
+set(Length-List-Only-STDERR "two")
+set(Remove_At-List-Only-STDERR "at least two")
+
+foreach(cmd IN ITEMS Find Get Insert Length Remove_At)
+ string(TOUPPER ${cmd} cmd_upper)
+ set(${cmd}-List-Only-RESULT 1)
+ set(${cmd}-List-Only-STDERR ".*CMake Error at List-${cmd}-List-Only.cmake:1 \\(list\\):.*list sub-command ${cmd_upper} requires ${${cmd}-List-Only-STDERR} arguments.*")
+ set(_test_file_name "${CMAKE_CURRENT_BINARY_DIR}/List-${cmd}-List-Only.cmake")
+ file(WRITE "${_test_file_name}" "list(${cmd_upper} mylist)\n")
+ check_cmake_test_single(List "${cmd}-List-Only" "${_test_file_name}")
+endforeach()
+
+set(thelist "" NEW OLD)
+
+foreach (_pol ${thelist})
+ cmake_policy(SET CMP0007 ${_pol})
+ list(GET thelist 1 thevalue)
+ if (NOT thevalue STREQUAL _pol)
+ message(SEND_ERROR "returned element '${thevalue}', but expected '${_pol}'")
+ endif()
+endforeach (_pol)
diff --git a/Tests/CMakeTests/Make_Directory-NoArg.cmake b/Tests/CMakeTests/Make_Directory-NoArg.cmake
new file mode 100644
index 0000000..25b6f89
--- /dev/null
+++ b/Tests/CMakeTests/Make_Directory-NoArg.cmake
@@ -0,0 +1 @@
+file(MAKE_DIRECTORY)
diff --git a/Tests/CMakeTests/MathTest.cmake.in b/Tests/CMakeTests/MathTest.cmake.in
new file mode 100644
index 0000000..91cd922
--- /dev/null
+++ b/Tests/CMakeTests/MathTest.cmake.in
@@ -0,0 +1,18 @@
+# Execute each test listed in:
+#
+set(scriptname "@CMAKE_CURRENT_SOURCE_DIR@/MathTestScript.cmake")
+set(number_of_tests_expected 4)
+
+include("@CMAKE_CURRENT_SOURCE_DIR@/ExecuteScriptTests.cmake")
+execute_all_script_tests(${scriptname} number_of_tests_executed)
+
+# And verify that number_of_tests_executed is at least as many as we know
+# about as of this writing...
+#
+message(STATUS "scriptname='${scriptname}'")
+message(STATUS "number_of_tests_executed='${number_of_tests_executed}'")
+message(STATUS "number_of_tests_expected='${number_of_tests_expected}'")
+
+if(number_of_tests_executed LESS number_of_tests_expected)
+ message(FATAL_ERROR "error: some test cases were skipped")
+endif()
diff --git a/Tests/CMakeTests/MathTestScript.cmake b/Tests/CMakeTests/MathTestScript.cmake
new file mode 100644
index 0000000..1b7f8a6
--- /dev/null
+++ b/Tests/CMakeTests/MathTestScript.cmake
@@ -0,0 +1,18 @@
+message(STATUS "testname='${testname}'")
+
+if(testname STREQUAL empty) # fail
+ math()
+
+elseif(testname STREQUAL bogus) # fail
+ math(BOGUS)
+
+elseif(testname STREQUAL not_enough_args) # fail
+ math(EXPR x)
+
+elseif(testname STREQUAL cannot_parse) # fail
+ math(EXPR x "1 + 2 +")
+
+else() # fail
+ message(FATAL_ERROR "testname='${testname}' - error: no such test in '${CMAKE_CURRENT_LIST_FILE}'")
+
+endif()
diff --git a/Tests/CMakeTests/MessageTest.cmake.in b/Tests/CMakeTests/MessageTest.cmake.in
new file mode 100644
index 0000000..a9833b9
--- /dev/null
+++ b/Tests/CMakeTests/MessageTest.cmake.in
@@ -0,0 +1,30 @@
+execute_process(
+ COMMAND ${CMAKE_COMMAND} -P
+ "@CMAKE_CURRENT_SOURCE_DIR@/MessageTestScript.cmake"
+ OUTPUT_VARIABLE out
+ ERROR_VARIABLE err
+ RESULT_VARIABLE result
+ )
+
+message("out=[${out}]")
+message("err=[${err}]")
+
+if(NOT "${result}" STREQUAL "0")
+ message(FATAL_ERROR "message script failed: [${result}]")
+endif()
+
+if(NOT "${out}" MATCHES "message-status")
+ message(FATAL_ERROR "message(STATUS) did not go to stdout")
+endif()
+
+if(NOT "${err}" MATCHES "message-default")
+ message(FATAL_ERROR "message() did not go to stderr by default")
+endif()
+
+if(NOT "${err}" MATCHES "CMake Warning at[^\n]*:\r?\n message-warning")
+ message(FATAL_ERROR "message(WARNING) did not appear properly")
+endif()
+
+if(NOT "${err}" MATCHES "CMake Warning \\(dev\\) at[^\n]*:\r?\n message-author")
+ message(FATAL_ERROR "message(AUTHOR_WARNING) did not appear properly")
+endif()
diff --git a/Tests/CMakeTests/MessageTestScript.cmake b/Tests/CMakeTests/MessageTestScript.cmake
new file mode 100644
index 0000000..c56f88e
--- /dev/null
+++ b/Tests/CMakeTests/MessageTestScript.cmake
@@ -0,0 +1,4 @@
+message("message-default")
+message(STATUS "message-status")
+message(WARNING "message-warning")
+message(AUTHOR_WARNING "message-author")
diff --git a/Tests/CMakeTests/ModuleNoticesTest.cmake.in b/Tests/CMakeTests/ModuleNoticesTest.cmake.in
new file mode 100644
index 0000000..7ae6607
--- /dev/null
+++ b/Tests/CMakeTests/ModuleNoticesTest.cmake.in
@@ -0,0 +1,33 @@
+# Regex to match license notices at the top of module files.
+set(notice_regex [[^# Distributed under the OSI-approved BSD 3-Clause License\. See accompanying
+# file Copyright\.txt or https://cmake\.org/licensing for details\.
+
+]])
+string(REPLACE "\n" "\r?\n" notice_regex "${notice_regex}")
+string(REPLACE "\r\r" "\r" notice_regex "${notice_regex}")
+
+# Modules that do not require our notice.
+set(notice_exceptions
+ FindCUDA.cmake # MIT License, distributed here from upstream project
+ )
+
+# Load the list of modules to check.
+set(dir "@CMake_SOURCE_DIR@/Modules")
+file(GLOB all_modules RELATIVE "${dir}" "${dir}/*.cmake")
+list(REMOVE_ITEM all_modules ${notice_exceptions})
+
+# Check each module.
+set(notice_missing)
+foreach(module ${all_modules})
+ message(STATUS "module: ${module}")
+ file(READ "${dir}/${module}" module_content)
+ if(NOT "${module_content}" MATCHES "${notice_regex}")
+ string(APPEND notice_missing " ${module}\n")
+ endif()
+endforeach()
+
+# Report the list of bad modules.
+if(notice_missing)
+ message(FATAL_ERROR
+ "Some modules do not have a valid copyright notice:\n${notice_missing}")
+endif()
diff --git a/Tests/CMakeTests/PolicyCheckTest.cmake.in b/Tests/CMakeTests/PolicyCheckTest.cmake.in
new file mode 100644
index 0000000..416dc0a
--- /dev/null
+++ b/Tests/CMakeTests/PolicyCheckTest.cmake.in
@@ -0,0 +1,154 @@
+# Check the CMake source tree for suspicious policy introdcutions...
+#
+message("=============================================================================")
+message("CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+message("")
+message("CMake_BINARY_DIR='${CMake_BINARY_DIR}'")
+message("CMake_SOURCE_DIR='${CMake_SOURCE_DIR}'")
+message("GIT_EXECUTABLE='${GIT_EXECUTABLE}'")
+message("")
+
+
+# If this does not appear to be a git checkout, just pass the test here
+# and now. (Do not let the test fail if it is run in a tree *exported* from a
+# repository or unpacked from a .zip file source installer...)
+#
+set(is_git_checkout 0)
+if(EXISTS "${CMake_SOURCE_DIR}/.git")
+ set(is_git_checkout 1)
+endif()
+
+message("is_git_checkout='${is_git_checkout}'")
+message("")
+
+if(NOT is_git_checkout)
+ message("source tree is not a git checkout... test passes by early return...")
+ return()
+endif()
+
+# If no GIT_EXECUTABLE, see if we can figure out which git was used
+# for the ctest_update step on this dashboard...
+#
+if(is_git_checkout AND NOT GIT_EXECUTABLE)
+ set(ctest_ini_file "")
+ set(exe "")
+
+ # Use the old name:
+ if(EXISTS "${CMake_BINARY_DIR}/DartConfiguration.tcl")
+ set(ctest_ini_file "${CMake_BINARY_DIR}/DartConfiguration.tcl")
+ endif()
+
+ # But if it exists, prefer the new name:
+ if(EXISTS "${CMake_BINARY_DIR}/CTestConfiguration.ini")
+ set(ctest_ini_file "${CMake_BINARY_DIR}/CTestConfiguration.ini")
+ endif()
+
+ # If there is a ctest ini file, read the update command or git command
+ # from it:
+ #
+ if(ctest_ini_file)
+ file(STRINGS "${ctest_ini_file}" line REGEX "^GITCommand: (.*)$")
+ string(REGEX REPLACE "^GITCommand: (.*)$" "\\1" line "${line}")
+ if("${line}" MATCHES "^\"")
+ string(REGEX REPLACE "^\"([^\"]+)\" *.*$" "\\1" line "${line}")
+ else()
+ string(REGEX REPLACE "^([^ ]+) *.*$" "\\1" line "${line}")
+ endif()
+ set(exe "${line}")
+ if("${exe}" STREQUAL "GITCOMMAND-NOTFOUND")
+ set(exe "")
+ endif()
+ if(exe)
+ message("info: GIT_EXECUTABLE set by 'GITCommand:' from '${ctest_ini_file}'")
+ endif()
+
+ if(NOT exe)
+ file(STRINGS "${ctest_ini_file}" line REGEX "^UpdateCommand: (.*)$")
+ string(REGEX REPLACE "^UpdateCommand: (.*)$" "\\1" line "${line}")
+ if("${line}" MATCHES "^\"")
+ string(REGEX REPLACE "^\"([^\"]+)\" *.*$" "\\1" line "${line}")
+ else()
+ string(REGEX REPLACE "^([^ ]+) *.*$" "\\1" line "${line}")
+ endif()
+ set(exe "${line}")
+ if("${exe}" STREQUAL "GITCOMMAND-NOTFOUND")
+ set(exe "")
+ endif()
+ if(exe)
+ message("info: GIT_EXECUTABLE set by 'UpdateCommand:' from '${ctest_ini_file}'")
+ endif()
+ endif()
+ else()
+ message("info: no DartConfiguration.tcl or CTestConfiguration.ini file...")
+ endif()
+
+ # If we have still not grokked the exe, look in the Update.xml file to see
+ # if we can parse it from there...
+ #
+ if(NOT exe)
+ file(GLOB_RECURSE update_xml_file "${CMake_BINARY_DIR}/Testing/Update.xml")
+ if(update_xml_file)
+ file(STRINGS "${update_xml_file}" line
+ REGEX "^.*<UpdateCommand>(.*)</UpdateCommand>$" LIMIT_COUNT 1)
+ string(REPLACE "&quot\;" "\"" line "${line}")
+ string(REGEX REPLACE "^.*<UpdateCommand>(.*)</UpdateCommand>$" "\\1" line "${line}")
+ if("${line}" MATCHES "^\"")
+ string(REGEX REPLACE "^\"([^\"]+)\" *.*$" "\\1" line "${line}")
+ else()
+ string(REGEX REPLACE "^([^ ]+) *.*$" "\\1" line "${line}")
+ endif()
+ if(line)
+ set(exe "${line}")
+ endif()
+ if(exe)
+ message("info: GIT_EXECUTABLE set by '<UpdateCommand>' from '${update_xml_file}'")
+ endif()
+ else()
+ message("info: no Update.xml file...")
+ endif()
+ endif()
+
+ if(exe)
+ set(GIT_EXECUTABLE "${exe}")
+ message("GIT_EXECUTABLE='${GIT_EXECUTABLE}'")
+ message("")
+
+ if(NOT EXISTS "${GIT_EXECUTABLE}")
+ message(FATAL_ERROR "GIT_EXECUTABLE does not exist...")
+ endif()
+ else()
+ message(FATAL_ERROR "could not determine GIT_EXECUTABLE...")
+ endif()
+endif()
+
+
+if(is_git_checkout AND GIT_EXECUTABLE)
+ # Check with "git grep" if there are any unacceptable cmPolicies additions
+ #
+ message("=============================================================================")
+ message("This is a git checkout, using git grep to verify no unacceptable policies")
+ message("are being introduced....")
+ message("")
+
+ execute_process(COMMAND ${GIT_EXECUTABLE} grep -En "[0-9][0-9][0-9][0-9][0-9].*cmPolicies"
+ WORKING_DIRECTORY ${CMake_SOURCE_DIR}
+ OUTPUT_VARIABLE grep_output
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ message("=== output of 'git grep -En \"[0-9][0-9][0-9][0-9][0-9].*cmPolicies\"' ===")
+ message("${grep_output}")
+ message("=== end output ===")
+ message("")
+
+ if(NOT "${grep_output}" STREQUAL "")
+ message(FATAL_ERROR "git grep output is non-empty...
+New CMake policies must be introduced in a non-date-based version number.
+Send email to the cmake-developers list to figure out what the target
+version number for this policy should be...")
+ endif()
+endif()
+
+
+# Still here? Good then...
+#
+message("test passes")
+message("")
diff --git a/Tests/CMakeTests/ProcessorCountTest.cmake.in b/Tests/CMakeTests/ProcessorCountTest.cmake.in
new file mode 100644
index 0000000..f92dcc4
--- /dev/null
+++ b/Tests/CMakeTests/ProcessorCountTest.cmake.in
@@ -0,0 +1,79 @@
+include(ProcessorCount)
+
+ProcessorCount(processor_count)
+
+message("### 1. This line should be the first line of text in the test output.")
+message("### 2. If there was output from this test before line #1, then the")
+message("### 3. ProcessorCount(...) function call is emitting output that it shouldn't...")
+
+message("processor_count='${processor_count}'")
+
+execute_process(
+ COMMAND "${KWSYS_TEST_EXE}"
+ testSystemInformation
+ OUTPUT_VARIABLE tsi_out
+ ERROR_VARIABLE tsi_err
+ RESULT_VARIABLE tsi_res
+)
+if (tsi_res)
+ message("executing \"${KWSYS_TEST_EXE}\" failed")
+ message(FATAL_ERROR "output: ${tsi_res}")
+endif ()
+
+string(REGEX REPLACE "(.*)GetNumberOfPhysicalCPU:.([0-9]*)(.*)" "\\2"
+ system_info_processor_count "${tsi_out}")
+
+message("system_info_processor_count='${system_info_processor_count}'")
+
+if(system_info_processor_count EQUAL processor_count)
+ message("processor count matches system information")
+endif()
+
+message("")
+message("CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+message("")
+message("tsi_out='${tsi_out}'")
+message("tsi_err='${tsi_err}'")
+message("")
+
+# Evaluate possible error conditions:
+#
+set(err 0)
+set(fatal 0)
+
+if(processor_count EQUAL 0)
+ set(err 1)
+ set(fatal 1)
+ message("err 1")
+ message("could not determine number of processors
+- Additional code for this platform needed in ProcessorCount.cmake?")
+ message("")
+endif()
+
+if(NOT system_info_processor_count EQUAL processor_count)
+ set(err 2)
+ message("err 2")
+ message("SystemInformation and ProcessorCount.cmake disagree:\n"
+ "processor_count='${processor_count}'\n"
+ "SystemInformation processor_count='${system_info_processor_count}'")
+ message("")
+endif()
+
+if(NOT processor_count MATCHES "^[0-9]+$")
+ set(err 3)
+ set(fatal 1)
+ message("err 3")
+ message("ProcessorCount function returned a non-integer")
+ message("")
+endif()
+
+if(NOT system_info_processor_count MATCHES "^[0-9]+$")
+ set(err 4)
+ message("err 4")
+ message("SystemInformation ProcessorCount function returned a non-integer")
+ message("")
+endif()
+
+if(fatal)
+ message(FATAL_ERROR "processor_count='${processor_count}' - see previous test output for more details - it is likely more/different code is needed in ProcessorCount.cmake to fix this test failure - processor_count should be a non-zero positive integer (>=1) for all supported CMake platforms")
+endif()
diff --git a/Tests/CMakeTests/PushCheckStateTest.cmake.in b/Tests/CMakeTests/PushCheckStateTest.cmake.in
new file mode 100644
index 0000000..cbd879d
--- /dev/null
+++ b/Tests/CMakeTests/PushCheckStateTest.cmake.in
@@ -0,0 +1,91 @@
+cmake_minimum_required(VERSION 3.8)
+include(CMakePushCheckState)
+
+set(CMAKE_EXTRA_INCLUDE_FILES file1)
+set(CMAKE_REQUIRED_INCLUDES dir1)
+set(CMAKE_REQUIRED_DEFINITIONS defs1 )
+set(CMAKE_REQUIRED_LIBRARIES lib1)
+set(CMAKE_REQUIRED_FLAGS flag1)
+set(CMAKE_REQUIRED_QUIET 1)
+
+cmake_push_check_state()
+
+set(CMAKE_EXTRA_INCLUDE_FILES file2)
+set(CMAKE_REQUIRED_INCLUDES dir2)
+set(CMAKE_REQUIRED_DEFINITIONS defs2)
+set(CMAKE_REQUIRED_LIBRARIES lib2)
+set(CMAKE_REQUIRED_FLAGS flag2)
+set(CMAKE_REQUIRED_QUIET 2)
+
+cmake_push_check_state()
+
+set(CMAKE_EXTRA_INCLUDE_FILES file3)
+set(CMAKE_REQUIRED_DEFINITIONS defs3)
+set(CMAKE_REQUIRED_INCLUDES dir3)
+set(CMAKE_REQUIRED_DEFINITIONS defs3)
+set(CMAKE_REQUIRED_LIBRARIES lib3)
+set(CMAKE_REQUIRED_FLAGS flag3)
+set(CMAKE_REQUIRED_QUIET 3)
+
+cmake_push_check_state(RESET)
+
+foreach(pair IN ITEMS
+ EXTRA_INCLUDE_FILES|
+ REQUIRED_INCLUDES|
+ REQUIRED_DEFINITIONS|
+ REQUIRED_LIBRARIES|
+ REQUIRED_FLAGS|
+ REQUIRED_QUIET|
+ )
+ string(REPLACE "|" ";" pair "${pair}")
+ list(GET pair 0 var)
+ list(GET pair 1 expected)
+ if (NOT "${CMAKE_${var}}" STREQUAL "${expected}")
+ set(fatal TRUE)
+ message("ERROR: CMAKE_${var} is \"${CMAKE_${var}}\" (expected \"${expected}\")" )
+ endif()
+endforeach()
+
+cmake_pop_check_state()
+
+cmake_pop_check_state()
+
+foreach(pair IN ITEMS
+ EXTRA_INCLUDE_FILES|file2
+ REQUIRED_INCLUDES|dir2
+ REQUIRED_DEFINITIONS|defs2
+ REQUIRED_LIBRARIES|lib2
+ REQUIRED_FLAGS|flag2
+ REQUIRED_QUIET|2
+ )
+ string(REPLACE "|" ";" pair "${pair}")
+ list(GET pair 0 var)
+ list(GET pair 1 expected)
+ if (NOT "${CMAKE_${var}}" STREQUAL "${expected}")
+ set(fatal TRUE)
+ message("ERROR: CMAKE_${var} is \"${CMAKE_${var}}\" (expected \"${expected}\")" )
+ endif()
+endforeach()
+
+cmake_pop_check_state()
+
+foreach(pair IN ITEMS
+ EXTRA_INCLUDE_FILES|file1
+ REQUIRED_INCLUDES|dir1
+ REQUIRED_DEFINITIONS|defs1
+ REQUIRED_LIBRARIES|lib1
+ REQUIRED_FLAGS|flag1
+ REQUIRED_QUIET|1
+ )
+ string(REPLACE "|" ";" pair "${pair}")
+ list(GET pair 0 var)
+ list(GET pair 1 expected)
+ if (NOT "${CMAKE_${var}}" STREQUAL "${expected}")
+ set(fatal TRUE)
+ message("ERROR: CMAKE_${var} is \"${CMAKE_${var}}\" (expected \"${expected}\")" )
+ endif()
+endforeach()
+
+if(fatal)
+ message(FATAL_ERROR "cmake_push_check_state() test failed")
+endif()
diff --git a/Tests/CMakeTests/String-MD5-BadArg1.cmake b/Tests/CMakeTests/String-MD5-BadArg1.cmake
new file mode 100644
index 0000000..8946476
--- /dev/null
+++ b/Tests/CMakeTests/String-MD5-BadArg1.cmake
@@ -0,0 +1 @@
+string(MD5)
diff --git a/Tests/CMakeTests/String-MD5-BadArg2.cmake b/Tests/CMakeTests/String-MD5-BadArg2.cmake
new file mode 100644
index 0000000..abbbf87
--- /dev/null
+++ b/Tests/CMakeTests/String-MD5-BadArg2.cmake
@@ -0,0 +1 @@
+string(MD5 md5)
diff --git a/Tests/CMakeTests/String-MD5-BadArg4.cmake b/Tests/CMakeTests/String-MD5-BadArg4.cmake
new file mode 100644
index 0000000..edd4427
--- /dev/null
+++ b/Tests/CMakeTests/String-MD5-BadArg4.cmake
@@ -0,0 +1 @@
+string(MD5 md5 input extra_arg)
diff --git a/Tests/CMakeTests/String-MD5-Works.cmake b/Tests/CMakeTests/String-MD5-Works.cmake
new file mode 100644
index 0000000..4ef7a07
--- /dev/null
+++ b/Tests/CMakeTests/String-MD5-Works.cmake
@@ -0,0 +1,2 @@
+string(MD5 md5 "sample input string\n")
+message("${md5}")
diff --git a/Tests/CMakeTests/String-SHA1-Works.cmake b/Tests/CMakeTests/String-SHA1-Works.cmake
new file mode 100644
index 0000000..2f3b51b
--- /dev/null
+++ b/Tests/CMakeTests/String-SHA1-Works.cmake
@@ -0,0 +1,2 @@
+string(SHA1 sha1 "sample input string\n")
+message("${sha1}")
diff --git a/Tests/CMakeTests/String-SHA224-Works.cmake b/Tests/CMakeTests/String-SHA224-Works.cmake
new file mode 100644
index 0000000..5b7f880
--- /dev/null
+++ b/Tests/CMakeTests/String-SHA224-Works.cmake
@@ -0,0 +1,2 @@
+string(SHA224 sha224 "sample input string\n")
+message("${sha224}")
diff --git a/Tests/CMakeTests/String-SHA256-Works.cmake b/Tests/CMakeTests/String-SHA256-Works.cmake
new file mode 100644
index 0000000..e3e89ae
--- /dev/null
+++ b/Tests/CMakeTests/String-SHA256-Works.cmake
@@ -0,0 +1,2 @@
+string(SHA256 sha256 "sample input string\n")
+message("${sha256}")
diff --git a/Tests/CMakeTests/String-SHA384-Works.cmake b/Tests/CMakeTests/String-SHA384-Works.cmake
new file mode 100644
index 0000000..828a190
--- /dev/null
+++ b/Tests/CMakeTests/String-SHA384-Works.cmake
@@ -0,0 +1,2 @@
+string(SHA384 sha384 "sample input string\n")
+message("${sha384}")
diff --git a/Tests/CMakeTests/String-SHA3_224-Works.cmake b/Tests/CMakeTests/String-SHA3_224-Works.cmake
new file mode 100644
index 0000000..6aeb91d
--- /dev/null
+++ b/Tests/CMakeTests/String-SHA3_224-Works.cmake
@@ -0,0 +1,2 @@
+string(SHA3_224 sha3_224 "sample input string\n")
+message("${sha3_224}")
diff --git a/Tests/CMakeTests/String-SHA3_256-Works.cmake b/Tests/CMakeTests/String-SHA3_256-Works.cmake
new file mode 100644
index 0000000..cc7ea1a
--- /dev/null
+++ b/Tests/CMakeTests/String-SHA3_256-Works.cmake
@@ -0,0 +1,2 @@
+string(SHA3_256 sha3_256 "sample input string\n")
+message("${sha3_256}")
diff --git a/Tests/CMakeTests/String-SHA3_384-Works.cmake b/Tests/CMakeTests/String-SHA3_384-Works.cmake
new file mode 100644
index 0000000..9341c3f
--- /dev/null
+++ b/Tests/CMakeTests/String-SHA3_384-Works.cmake
@@ -0,0 +1,2 @@
+string(SHA3_384 sha3_384 "sample input string\n")
+message("${sha3_384}")
diff --git a/Tests/CMakeTests/String-SHA3_512-Works.cmake b/Tests/CMakeTests/String-SHA3_512-Works.cmake
new file mode 100644
index 0000000..cf4eddd
--- /dev/null
+++ b/Tests/CMakeTests/String-SHA3_512-Works.cmake
@@ -0,0 +1,2 @@
+string(SHA3_512 sha3_512 "sample input string\n")
+message("${sha3_512}")
diff --git a/Tests/CMakeTests/String-SHA512-Works.cmake b/Tests/CMakeTests/String-SHA512-Works.cmake
new file mode 100644
index 0000000..e17db5c
--- /dev/null
+++ b/Tests/CMakeTests/String-SHA512-Works.cmake
@@ -0,0 +1,2 @@
+string(SHA512 sha512 "sample input string\n")
+message("${sha512}")
diff --git a/Tests/CMakeTests/String-TIMESTAMP-AllSpecifiers.cmake b/Tests/CMakeTests/String-TIMESTAMP-AllSpecifiers.cmake
new file mode 100644
index 0000000..2d0fcc8
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-AllSpecifiers.cmake
@@ -0,0 +1,11 @@
+string(TIMESTAMP output "%d;%H;%I;%j;%m;%M;%S;%U;%w;%y;%Y")
+message("~${output}~")
+
+list(LENGTH output output_length)
+
+set(expected_output_length 11)
+
+if(NOT output_length EQUAL ${expected_output_length})
+ message(FATAL_ERROR "expected ${expected_output_length} entries in output "
+ "with all specifiers; found ${output_length}")
+endif()
diff --git a/Tests/CMakeTests/String-TIMESTAMP-BadArg1.cmake b/Tests/CMakeTests/String-TIMESTAMP-BadArg1.cmake
new file mode 100644
index 0000000..8f2d9f8
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-BadArg1.cmake
@@ -0,0 +1 @@
+string(TIMESTAMP)
diff --git a/Tests/CMakeTests/String-TIMESTAMP-BadArg2.cmake b/Tests/CMakeTests/String-TIMESTAMP-BadArg2.cmake
new file mode 100644
index 0000000..c1e5126
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-BadArg2.cmake
@@ -0,0 +1 @@
+string(TIMESTAMP output_variable "%Y" UTF)
diff --git a/Tests/CMakeTests/String-TIMESTAMP-BadArg3.cmake b/Tests/CMakeTests/String-TIMESTAMP-BadArg3.cmake
new file mode 100644
index 0000000..3d577df
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-BadArg3.cmake
@@ -0,0 +1 @@
+string(TIMESTAMP output_variable "%Y" UTC UTC)
diff --git a/Tests/CMakeTests/String-TIMESTAMP-CustomFormatLocal.cmake b/Tests/CMakeTests/String-TIMESTAMP-CustomFormatLocal.cmake
new file mode 100644
index 0000000..eab2a45
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-CustomFormatLocal.cmake
@@ -0,0 +1,2 @@
+string(TIMESTAMP output "%S")
+message("~${output}~")
diff --git a/Tests/CMakeTests/String-TIMESTAMP-CustomFormatUTC.cmake b/Tests/CMakeTests/String-TIMESTAMP-CustomFormatUTC.cmake
new file mode 100644
index 0000000..eab2a45
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-CustomFormatUTC.cmake
@@ -0,0 +1,2 @@
+string(TIMESTAMP output "%S")
+message("~${output}~")
diff --git a/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatLocal.cmake b/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatLocal.cmake
new file mode 100644
index 0000000..d7c7dde
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatLocal.cmake
@@ -0,0 +1,2 @@
+string(TIMESTAMP output)
+message("~${output}~")
diff --git a/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatUTC.cmake b/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatUTC.cmake
new file mode 100644
index 0000000..dad6a8d
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-DefaultFormatUTC.cmake
@@ -0,0 +1,2 @@
+string(TIMESTAMP output UTC)
+message("~${output}~")
diff --git a/Tests/CMakeTests/String-TIMESTAMP-IncompleteSpecifier.cmake b/Tests/CMakeTests/String-TIMESTAMP-IncompleteSpecifier.cmake
new file mode 100644
index 0000000..ffc5656
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-IncompleteSpecifier.cmake
@@ -0,0 +1,2 @@
+string(TIMESTAMP output "foobar%")
+message("~${output}~")
diff --git a/Tests/CMakeTests/String-TIMESTAMP-MonthWeekNames.cmake b/Tests/CMakeTests/String-TIMESTAMP-MonthWeekNames.cmake
new file mode 100644
index 0000000..1cd44ff
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-MonthWeekNames.cmake
@@ -0,0 +1,11 @@
+string(TIMESTAMP output "%a;%b")
+message("~${output}~")
+
+list(LENGTH output output_length)
+
+set(expected_output_length 2)
+
+if(NOT output_length EQUAL ${expected_output_length})
+ message(FATAL_ERROR "expected ${expected_output_length} entries in output "
+ "with all specifiers; found ${output_length}")
+endif()
diff --git a/Tests/CMakeTests/String-TIMESTAMP-UnixTime.cmake b/Tests/CMakeTests/String-TIMESTAMP-UnixTime.cmake
new file mode 100644
index 0000000..43c9384
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-UnixTime.cmake
@@ -0,0 +1,22 @@
+string(TIMESTAMP timestamp "[%Y-%m-%d %H:%M:%S] %s" UTC)
+
+string(TIMESTAMP unix_time "%s")
+
+string(TIMESTAMP year "%Y" UTC)
+string(TIMESTAMP days "%j" UTC)
+
+# Doing proper date calculations here to verify unix timestamps
+# could be error prone.
+# At the very least use some safe lower and upper bounds to
+# see if we are somewhere in the right region.
+
+math(EXPR years_since_epoch "${year} - 1970")
+math(EXPR lower_bound "((${years_since_epoch} * 365) + ${days} - 1) * 86400")
+math(EXPR upper_bound "((${years_since_epoch} * 366) + ${days}) * 86400")
+
+
+if(unix_time GREATER_EQUAL lower_bound AND unix_time LESS upper_bound)
+ message("~${unix_time}~")
+else()
+ message(FATAL_ERROR "${timestamp} unix time not in expected range [${lower_bound}, ${upper_bound})")
+endif()
diff --git a/Tests/CMakeTests/String-TIMESTAMP-UnknownSpecifier.cmake b/Tests/CMakeTests/String-TIMESTAMP-UnknownSpecifier.cmake
new file mode 100644
index 0000000..0e145e5
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-UnknownSpecifier.cmake
@@ -0,0 +1,2 @@
+string(TIMESTAMP output "%g")
+message("~${output}~")
diff --git a/Tests/CMakeTests/StringTest.cmake.in b/Tests/CMakeTests/StringTest.cmake.in
new file mode 100644
index 0000000..154afa7
--- /dev/null
+++ b/Tests/CMakeTests/StringTest.cmake.in
@@ -0,0 +1,101 @@
+set(MD5-BadArg1-RESULT 1)
+set(MD5-BadArg1-STDERR "string MD5 requires an output variable")
+set(MD5-BadArg2-RESULT 1)
+set(MD5-BadArg2-STDERR "string MD5 requires an output variable and an input string")
+set(MD5-BadArg4-RESULT 1)
+set(MD5-BadArg4-STDERR "string MD5 requires an output variable and an input string")
+set(MD5-Works-RESULT 0)
+set(MD5-Works-STDERR "10d20ddb981a6202b84aa1ce1cb7fce3")
+set(SHA1-Works-RESULT 0)
+set(SHA1-Works-STDERR "83f093e04289b21a9415f408ad50be8b57ad2f34")
+set(SHA224-Works-RESULT 0)
+set(SHA224-Works-STDERR "e995a7789922c4ef9279d94e763c8375934180a51baa7147bc48edf7")
+set(SHA256-Works-RESULT 0)
+set(SHA256-Works-STDERR "d1c5915d8b71150726a1eef75a29ec6bea8fd1bef6b7299ef8048760b0402025")
+set(SHA384-Works-RESULT 0)
+set(SHA384-Works-STDERR "1de9560b4e030e02051ea408200ffc55d70c97ac64ebf822461a5c786f495c36df43259b14483bc8d364f0106f4971ee")
+set(SHA512-Works-RESULT 0)
+set(SHA512-Works-STDERR "3982a1b4e651768bec70ab1fb97045cb7a659f4ba7203d501c52ab2e803071f9d5fd272022df15f27727fc67f8cd022e710e29010b2a9c0b467c111e2f6abf51")
+set(SHA3_224-Works-RESULT 0)
+set(SHA3_224-Works-STDERR "4272868085f4f25080681a7712509fd12e16dcda79bd356836dd2100")
+set(SHA3_256-Works-RESULT 0)
+set(SHA3_256-Works-STDERR "be0df472b6bd474417a166d12f2774f2ef5095e86f0a88ef4c78c703800cfc8a")
+set(SHA3_384-Works-RESULT 0)
+set(SHA3_384-Works-STDERR "935a17cc708443c1369549483656a4521af03a52e4f3b314566272017ccae03a2c5db838f6d4c156b1dc5c366182481b")
+set(SHA3_512-Works-RESULT 0)
+set(SHA3_512-Works-STDERR "471a85ed537e8f77f31412a089f22d836054ffa179599f87a5d7568927d8fa236b6793ded8a387d1de92398c967177bcc6361672a722bf736cb0f63a0956d5cf")
+set(TIMESTAMP-BadArg1-RESULT 1)
+set(TIMESTAMP-BadArg1-STDERR "string sub-command TIMESTAMP requires at least one argument")
+set(TIMESTAMP-BadArg2-RESULT 1)
+set(TIMESTAMP-BadArg2-STDERR "string TIMESTAMP sub-command does not recognize option UTF")
+set(TIMESTAMP-BadArg3-RESULT 1)
+set(TIMESTAMP-BadArg3-STDERR "string sub-command TIMESTAMP takes at most three arguments")
+set(TIMESTAMP-DefaultFormatLocal-RESULT 0)
+set(TIMESTAMP-DefaultFormatLocal-STDERR "~[0-9]*-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-6][0-9]~")
+set(TIMESTAMP-DefaultFormatUTC-RESULT 0)
+set(TIMESTAMP-DefaultFormatUTC-STDERR "~[0-9]*-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-6][0-9]Z~")
+set(TIMESTAMP-CustomFormatLocal-RESULT 0)
+set(TIMESTAMP-CustomFormatLocal-STDERR "~([0-5][0-9])|60~")
+set(TIMESTAMP-CustomFormatUTC-RESULT 0)
+set(TIMESTAMP-CustomFormatUTC-STDERR "~([0-5][0-9])|60~")
+set(TIMESTAMP-UnknownSpecifier-RESULT 0)
+set(TIMESTAMP-UnknownSpecifier-STDERR "~%g~")
+set(TIMESTAMP-IncompleteSpecifier-RESULT 0)
+set(TIMESTAMP-IncompleteSpecifier-STDERR "~foobar%~")
+set(TIMESTAMP-AllSpecifiers-RESULT 0)
+set(TIMESTAMP-AllSpecifiers-STDERR "~[0-9]+(;[0-9]+)*~")
+set(TIMESTAMP-MonthWeekNames-RESULT 0)
+set(TIMESTAMP-MonthWeekNames-STDERR "~[^%]+;[^%]+~")
+set(TIMESTAMP-UnixTime-RESULT 0)
+set(TIMESTAMP-UnixTime-STDERR "~[0-9]+~")
+
+include("@CMAKE_CURRENT_SOURCE_DIR@/CheckCMakeTest.cmake")
+check_cmake_test(String
+ MD5-BadArg1
+ MD5-BadArg2
+ MD5-BadArg4
+ MD5-Works
+ SHA1-Works
+ SHA224-Works
+ SHA256-Works
+ SHA384-Works
+ SHA512-Works
+ SHA3_224-Works
+ SHA3_256-Works
+ SHA3_384-Works
+ SHA3_512-Works
+ TIMESTAMP-BadArg1
+ TIMESTAMP-BadArg2
+ TIMESTAMP-BadArg3
+ TIMESTAMP-DefaultFormatLocal
+ TIMESTAMP-DefaultFormatUTC
+ TIMESTAMP-CustomFormatLocal
+ TIMESTAMP-CustomFormatUTC
+ TIMESTAMP-UnknownSpecifier
+ TIMESTAMP-IncompleteSpecifier
+ TIMESTAMP-AllSpecifiers
+ TIMESTAMP-MonthWeekNames
+ TIMESTAMP-UnixTime
+ )
+
+# Execute each test listed in StringTestScript.cmake:
+#
+set(scriptname "@CMAKE_CURRENT_SOURCE_DIR@/StringTestScript.cmake")
+set(number_of_tests_expected 74)
+
+include("@CMAKE_CURRENT_SOURCE_DIR@/ExecuteScriptTests.cmake")
+execute_all_script_tests(${scriptname} number_of_tests_executed)
+
+string(TIMESTAMP timestamp "[%Y-%m-%d %H:%M:%S] UTC %s" UTC)
+
+# And verify that number_of_tests_executed is at least as many as we know
+# about as of this writing...
+#
+message(STATUS "timestamp='${timestamp}'")
+message(STATUS "scriptname='${scriptname}'")
+message(STATUS "number_of_tests_executed='${number_of_tests_executed}'")
+message(STATUS "number_of_tests_expected='${number_of_tests_expected}'")
+
+if(NOT number_of_tests_executed EQUAL number_of_tests_expected)
+ message(FATAL_ERROR "error: some test cases were skipped")
+endif()
diff --git a/Tests/CMakeTests/StringTestScript.cmake b/Tests/CMakeTests/StringTestScript.cmake
new file mode 100644
index 0000000..e069897
--- /dev/null
+++ b/Tests/CMakeTests/StringTestScript.cmake
@@ -0,0 +1,307 @@
+message(STATUS "testname='${testname}'")
+
+function(test_configure_line_number EXPRESSION POLICY)
+ cmake_policy(PUSH)
+ cmake_policy(SET CMP0053 ${POLICY})
+ string(CONFIGURE
+ "${EXPRESSION}" v) # line should indicate string() call
+ math(EXPR vplus3 "${v} + 3")
+ if(NOT ${CMAKE_CURRENT_LIST_LINE} EQUAL ${vplus3})
+ message(SEND_ERROR "Couldn't configure CMAKE_CURRENT_LIST_LINE, evaluated into '${v}'")
+ endif()
+ message(STATUS "v='${v}'")
+ cmake_policy(POP)
+endfunction()
+
+if(testname STREQUAL empty) # fail
+ string()
+
+elseif(testname STREQUAL bogus) # fail
+ string(BOGUS)
+
+elseif(testname STREQUAL random) # pass
+ string(RANDOM r)
+ message(STATUS "r='${r}'")
+
+elseif(testname STREQUAL toupper_no_variable) # fail
+ string(TOUPPER)
+
+elseif(testname STREQUAL ascii_no_variable) # fail
+ string(ASCII)
+
+elseif(testname STREQUAL ascii_code_too_small) # fail
+ string(ASCII -1 bummer)
+
+elseif(testname STREQUAL ascii_code_too_large) # fail
+ string(ASCII 288 bummer)
+
+elseif(testname STREQUAL configure_no_input) # fail
+ string(CONFIGURE)
+
+elseif(testname STREQUAL configure_no_variable) # fail
+ string(CONFIGURE "this is @testname@")
+
+elseif(testname STREQUAL configure_escape_quotes) # pass
+ string(CONFIGURE "this is @testname@" v ESCAPE_QUOTES)
+ message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL configure_line_number_CMP0053_old) # pass
+ test_configure_line_number("\${CMAKE_CURRENT_LIST_LINE}" OLD)
+
+elseif(testname STREQUAL configure_line_number_CMP0053_new) # pass
+ test_configure_line_number("\${CMAKE_CURRENT_LIST_LINE}" NEW)
+
+elseif(testname STREQUAL configure_line_number_CMP0053_old_use_at) # pass
+ test_configure_line_number("\@CMAKE_CURRENT_LIST_LINE\@" OLD)
+
+elseif(testname STREQUAL configure_line_number_CMP0053_new_use_at) # pass
+ test_configure_line_number("\@CMAKE_CURRENT_LIST_LINE\@" NEW)
+
+elseif(testname STREQUAL configure_bogus) # fail
+ string(CONFIGURE "this is @testname@" v ESCAPE_QUOTES BOGUS)
+
+elseif(testname STREQUAL regex_no_mode) # fail
+ string(REGEX)
+
+elseif(testname STREQUAL regex_match_not_enough_args) # fail
+ string(REGEX MATCH)
+
+elseif(testname STREQUAL regex_matchall_not_enough_args) # fail
+ string(REGEX MATCHALL)
+
+elseif(testname STREQUAL regex_replace_not_enough_args) # fail
+ string(REGEX REPLACE)
+
+elseif(testname STREQUAL regex_bogus_mode) # fail
+ string(REGEX BOGUS)
+
+elseif(testname STREQUAL regex_match_multiple_inputs) # pass
+ string(REGEX MATCH ".*" v input1 input2 input3 input4)
+ message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL regex_match_bad_regex) # fail
+ string(REGEX MATCH "(.*" v input)
+
+elseif(testname STREQUAL regex_match_empty_string) # fail
+ string(REGEX MATCH "x*" v "")
+
+elseif(testname STREQUAL regex_match_no_match) # pass
+ string(REGEX MATCH "xyz" v "abc")
+ message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL regex_matchall_multiple_inputs) # pass
+ string(REGEX MATCHALL "input" v input1 input2 input3 input4)
+ message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL regex_matchall_bad_regex) # fail
+ string(REGEX MATCHALL "(.*" v input)
+
+elseif(testname STREQUAL regex_matchall_empty_string) # fail
+ string(REGEX MATCHALL "x*" v "")
+
+elseif(testname STREQUAL regex_replace_ends_with_backslash) # fail
+ string(REGEX REPLACE "input" "output\\" v input1 input2 input3 input4)
+
+elseif(testname STREQUAL regex_replace_ends_with_escaped_backslash) # pass
+ string(REGEX REPLACE "input" "output\\\\" v input1 input2 input3 input4)
+ message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL regex_replace_has_linefeed) # pass
+ string(REGEX REPLACE "input" "output\\n" v input1 input2 input3 input4)
+ message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL regex_replace_has_bogus_escape) # fail
+ string(REGEX REPLACE "input" "output\\a" v input1 input2 input3 input4)
+
+elseif(testname STREQUAL regex_replace_bad_regex) # fail
+ string(REGEX REPLACE "this (.*" "with that" v input)
+
+elseif(testname STREQUAL regex_replace_empty_string) # fail
+ string(REGEX REPLACE "x*" "that" v "")
+
+elseif(testname STREQUAL regex_replace_index_too_small) # fail
+ string(REGEX REPLACE "^this (.*)$" "with \\1 \\-1" v "this input")
+
+elseif(testname STREQUAL regex_replace_index_too_large) # fail
+ string(REGEX REPLACE "^this (.*)$" "with \\1 \\2" v "this input")
+
+elseif(testname STREQUAL compare_no_mode) # fail
+ string(COMPARE)
+
+elseif(testname STREQUAL compare_bogus_mode) # fail
+ string(COMPARE BOGUS)
+
+elseif(testname STREQUAL compare_not_enough_args) # fail
+ string(COMPARE EQUAL)
+
+elseif(testname STREQUAL replace_not_enough_args) # fail
+ string(REPLACE)
+
+elseif(testname STREQUAL replace_multiple_inputs) # pass
+ string(REPLACE "input" "output" v input1 input2 input3 input4)
+ message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL substring_not_enough_args) # fail
+ string(SUBSTRING)
+
+elseif(testname STREQUAL substring_begin_too_large) # fail
+ string(SUBSTRING "abcdefg" 25 100 v)
+
+elseif(testname STREQUAL substring_end_larger_than_strlen) # pass
+ string(SUBSTRING "abcdefg" 1 100 v)
+
+elseif(testname STREQUAL substring_begin_less_than_zero) # fail
+ string(SUBSTRING "abcdefg" -1 4 v)
+
+elseif(testname STREQUAL substring_end_less_than_zero) # pass
+ string(SUBSTRING "abcdefg" 0 -1 v)
+
+elseif(testname STREQUAL substring_end_less_than_begin) # pass
+ string(SUBSTRING "abcdefg" 6 0 v)
+
+elseif(testname STREQUAL length_not_enough_args) # fail
+ string(LENGTH)
+
+elseif(testname STREQUAL strip_not_enough_args) # fail
+ string(STRIP)
+
+elseif(testname STREQUAL random_not_enough_args) # fail
+ string(RANDOM)
+
+elseif(testname STREQUAL random_3_args) # fail
+ string(RANDOM LENGTH 9)
+
+elseif(testname STREQUAL random_5_args) # fail
+ string(RANDOM LENGTH 9 ALPHABET "aceimnorsuvwxz")
+
+elseif(testname STREQUAL random_with_length) # pass
+ string(RANDOM LENGTH 9 v)
+ message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL random_with_alphabet) # pass
+ string(RANDOM ALPHABET "aceimnorsuvwxz" v)
+ message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL random_bad_length) # fail
+ string(RANDOM LENGTH 0 v)
+
+elseif(testname STREQUAL random_empty_alphabet) # pass
+ string(RANDOM ALPHABET "" v)
+ message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL random_with_length_and_alphabet) # pass
+ string(RANDOM LENGTH 9 ALPHABET "aceimnorsuvwxz" v)
+ message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL random_with_various_alphabets) # pass
+ # small alphabet
+ string(RANDOM LENGTH 32 ALPHABET "ACGT" v)
+ message(STATUS "v='${v}'")
+
+ # smaller alphabet
+ string(RANDOM LENGTH 32 ALPHABET "AB" v)
+ message(STATUS "v='${v}'")
+
+ # smallest alphabet
+ string(RANDOM LENGTH 32 ALPHABET "Z" v)
+ message(STATUS "v='${v}'")
+
+ # smallest length and alphabet
+ string(RANDOM LENGTH 1 ALPHABET "Q" v)
+ message(STATUS "v='${v}'")
+
+ # seed values -- 2 same, then 1 different
+ string(RANDOM LENGTH 32 ALPHABET "ACGT" RANDOM_SEED 987654 v)
+ message(STATUS "v='${v}'")
+ string(RANDOM LENGTH 32 ALPHABET "ACGT" RANDOM_SEED 987654 v)
+ message(STATUS "v='${v}'")
+ string(RANDOM LENGTH 32 ALPHABET "ACGT" RANDOM_SEED 876543 v)
+ message(STATUS "v='${v}'")
+
+ # alphabet of many colors - use all the crazy keyboard characters
+ string(RANDOM LENGTH 78 ALPHABET "~`!@#$%^&*()_-+={}[]\\|:\\;'\",.<>/?" v)
+ message(STATUS "v='${v}'")
+
+ message(STATUS "CMAKE_SCRIPT_MODE_FILE='${CMAKE_SCRIPT_MODE_FILE}'")
+
+elseif(testname STREQUAL string_find_with_no_parameter) # fail
+ string(FIND)
+
+elseif(testname STREQUAL string_find_with_one_parameter) # fail
+ string(FIND "CMake is great.")
+
+elseif(testname STREQUAL string_find_with_two_parameters) # fail
+ string(FIND "CMake is great." "a")
+
+elseif(testname STREQUAL string_find_with_three_parameters) # pass
+ string(FIND "CMake is great." "a" v)
+ message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL string_find_with_four_parameters) # fail
+ string(FIND "CMake is great." "a" v v2)
+
+elseif(testname STREQUAL string_find_reverse_with_no_parameter) # fail
+ string(FIND REVERSE)
+
+elseif(testname STREQUAL string_find_reverse_with_one_parameter) # fail
+ string(FIND "CMake is great." REVERSE)
+
+elseif(testname STREQUAL string_find_reverse_with_two_parameters) # fail
+ string(FIND "CMake is great." "a" REVERSE)
+
+elseif(testname STREQUAL string_find_reverse_with_three_parameters) # pass
+ string(FIND "CMake is great." "a" v REVERSE)
+ message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL string_find_reverse_with_four_parameters_part1) # fail
+ string(FIND "CMake is great." "a" v v2 REVERSE)
+
+elseif(testname STREQUAL string_find_reverse_with_four_parameters_part2) # fail
+ string(FIND "CMake is great." "a" v REVERSE v2)
+
+elseif(testname STREQUAL string_find_with_no_possible_result) # pass
+ string(FIND "CMake is a great application." "z" v)
+ message(STATUS "v='${v}'")
+ if(NOT(-1 EQUAL ${v}))
+ message(SEND_ERROR "FIND sub-command should return -1 but returned ${v}.")
+ endif()
+
+elseif(testname STREQUAL string_find_reverse_with_no_possible_result) # pass
+ string(FIND "CMake is a great application." "z" v REVERSE)
+ message(STATUS "v='${v}'")
+ if(NOT(-1 EQUAL ${v}))
+ message(SEND_ERROR "FIND REVERSE sub-command should return -1 but returned ${v}.")
+ endif()
+
+elseif(testname STREQUAL string_find_with_required_result) # pass
+ string(FIND "CMake is a great application." "g" v)
+ message(STATUS "v='${v}'")
+ if(NOT(11 EQUAL ${v}))
+ message(SEND_ERROR "FIND sub-command should return 11 but returned ${v}.")
+ endif()
+
+elseif(testname STREQUAL string_find_reverse_with_required_result) # pass
+ string(FIND "CMake is a great application." "e" v REVERSE)
+ message(STATUS "v='${v}'")
+ if(NOT(13 EQUAL ${v}))
+ message(SEND_ERROR "FIND REVERSE sub-command should return 13 but returned ${v}.")
+ endif()
+
+elseif(testname STREQUAL string_find_word_reverse_with_required_result) # pass
+ string(FIND "The command should find REVERSE in this string. Or maybe this REVERSE?!" "REVERSE" v)
+ message(STATUS "v='${v}'")
+ if(NOT(24 EQUAL ${v}))
+ message(SEND_ERROR "FIND sub-command should return 24 but returned ${v}.")
+ endif()
+
+elseif(testname STREQUAL string_find_reverse_word_reverse_with_required_result) # pass
+ string(FIND "The command should find REVERSE in this string. Or maybe this REVERSE?!" "REVERSE" v REVERSE)
+ message(STATUS "v='${v}'")
+ if(NOT(62 EQUAL ${v}))
+ message(SEND_ERROR "FIND sub-command should return 62 but returned ${v}.")
+ endif()
+
+else() # fail
+ message(FATAL_ERROR "testname='${testname}' - error: no such test in '${CMAKE_CURRENT_LIST_FILE}'")
+
+endif()
diff --git a/Tests/CMakeTests/ToolchainTest.cmake.in b/Tests/CMakeTests/ToolchainTest.cmake.in
new file mode 100644
index 0000000..ea44f42
--- /dev/null
+++ b/Tests/CMakeTests/ToolchainTest.cmake.in
@@ -0,0 +1,138 @@
+############################################################
+# some preparations so that the CMakeDetermineXXX.cmake files will work in scripted mode
+
+# overwrite mark_as_advanced(), since this is used in CMakeDetermineCCompiler.cmake
+# which will complain that it can"t be used in script mode
+macro(MARK_AS_ADVANCED)
+endmacro()
+# set this to a place where we are allowed to write
+set(CMAKE_PLATFORM_INFO_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+
+# don't run the compiler detection
+set(CMAKE_C_COMPILER_ID_RUN 1)
+set(CMAKE_CXX_COMPILER_ID_RUN 1)
+
+set(MY_SOURCE_DIR "@CMAKE_CURRENT_SOURCE_DIR@")
+
+# at first load CMakeDetermineSystem.cmake without toolchain file
+set(CMAKE_TOOLCHAIN_FILE)
+include(CMakeDetermineSystem)
+
+# check that CMAKE_SYSTEM_XXX and CMAKE_HOST_SYSTEM_xxx are identical
+if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "${CMAKE_HOST_SYSTEM_NAME}")
+ message(FATAL_ERROR "CMAKE_SYSTEM_NAME and CMAKE_HOST_SYSTEM_NAME not identical: \"${CMAKE_SYSTEM_NAME}\" vs. \"${CMAKE_HOST_SYSTEM_NAME}\"")
+endif()
+
+if(NOT "${CMAKE_SYSTEM}" STREQUAL "${CMAKE_HOST_SYSTEM}")
+ message(FATAL_ERROR "CMAKE_SYSTEM and CMAKE_HOST_SYSTEM not identical: \"${CMAKE_SYSTEM}\" vs. \"${CMAKE_HOST_SYSTEM}\"")
+endif()
+
+if(NOT "${CMAKE_SYSTEM_VERSION}" STREQUAL "${CMAKE_HOST_SYSTEM_VERSION}")
+ message(FATAL_ERROR "CMAKE_SYSTEM_VERSION and CMAKE_HOST_SYSTEM_VERSION not identical: \"${CMAKE_SYSTEM_VERSION}\" vs. \"${CMAKE_HOST_SYSTEM_VERSION}\"")
+endif()
+
+if(NOT "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}")
+ message(FATAL_ERROR "CMAKE_SYSTEM_PROCESSOR and CMAKE_HOST_SYSTEM_PROCESSOR not identical: \"${CMAKE_SYSTEM_PROCESSOR}\" vs. \"${CMAKE_HOST_SYSTEM_PROCESSOR}\"")
+endif()
+
+# save the values so we can compare them to CMAKE_HOST_SYSTEM_XXX in the toolchain case
+
+set(NATIVE_SYSTEM "${CMAKE_SYSTEM}")
+set(NATIVE_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}")
+set(NATIVE_SYSTEM_VERSION "${CMAKE_SYSTEM_VERSION}")
+set(NATIVE_SYSTEM_PROCESSOR "${CMAKE_SYSTEM_PROCESSOR}")
+
+# reset them so they will be detected again now
+set(CMAKE_SYSTEM)
+set(CMAKE_SYSTEM_NAME)
+set(CMAKE_SYSTEM_VERSION)
+set(CMAKE_SYSTEM_PROCESSOR)
+set(CMAKE_HOST_SYSTEM)
+set(CMAKE_HOST_SYSTEM_VERSION)
+set(CMAKE_HOST_SYSTEM_PROCESSOR)
+
+
+############################################################
+
+# now define a toolchain file and check that everything is
+# detected correctly and nothing predefined is overwritten
+
+set(CMAKE_TOOLCHAIN_FILE "${MY_SOURCE_DIR}/DummyToolchain.cmake")
+
+include(CMakeDetermineSystem)
+# make cmake think we are cross compiling for test to work
+set(CMAKE_CROSSCOMPILING TRUE)
+set(CMAKE_C_COMPILER_ID "GNU")
+include(CMakeDetermineCCompiler)
+include(CMakeDetermineCXXCompiler)
+
+#############################################################
+
+# check the results from DetermineSystem
+
+if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Dumdidum")
+ message(FATAL_ERROR "CMAKE_SYSTEM_NAME overwritten: \"${CMAKE_SYSTEM_NAME}\", was: \"Dumdidum\"")
+endif()
+
+if(NOT "${CMAKE_SYSTEM}" STREQUAL "Dumdidum-1.0")
+ message(FATAL_ERROR "CMAKE_SYSTEM wrong: \"${CMAKE_SYSTEM}\", expected: \"Dumdidum-1.0\"")
+endif()
+set(fileOne "${_INCLUDED_TOOLCHAIN_FILE}")
+set(fileTwo "${MY_SOURCE_DIR}/DummyToolchain.cmake")
+if(WIN32)
+ string(TOLOWER "${fileOne}" fileOne)
+ string(TOLOWER "${fileTwo}" fileTwo)
+endif()
+
+if(NOT "${fileOne}" STREQUAL "${fileTwo}")
+ message(FATAL_ERROR "Wrong toolchain was loaded: \"${fileOne}\" expected \"${fileTwo}\"")
+endif()
+
+# check that CMAKE_HOST_SYSTEM_XXX and _SYSTEM_xxx detected above are identical
+if(NOT "${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "${NATIVE_SYSTEM_NAME}")
+ message(FATAL_ERROR "CMAKE_HOST_SYSTEM_NAME and NATIVE_SYSTEM_NAME not identical: \"${CMAKE_HOST_SYSTEM_NAME}\" vs. \"${NATIVE_SYSTEM_NAME}\"")
+endif()
+if(NOT "${CMAKE_HOST_SYSTEM}" STREQUAL "${NATIVE_SYSTEM}")
+ message(FATAL_ERROR "CMAKE_HOST_SYSTEM and NATIVE_SYSTEM not identical: \"${CMAKE_HOST_SYSTEM}\" vs. \"${NATIVE_SYSTEM}\"")
+endif()
+if(NOT "${CMAKE_HOST_SYSTEM_VERSION}" STREQUAL "${NATIVE_SYSTEM_VERSION}")
+ message(FATAL_ERROR "CMAKE_HOST_SYSTEM_VERSION and NATIVE_SYSTEM_VERSION not identical: \"${CMAKE_HOST_SYSTEM_VERSION}\" vs. \"${NATIVE_SYSTEM_VERSION}\"")
+endif()
+if(NOT "${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "${NATIVE_SYSTEM_PROCESSOR}")
+ message(FATAL_ERROR "CMAKE_HOST_SYSTEM_PROCESSOR and NATIVE_SYSTEM_PROCESSOR not identical: \"${CMAKE_HOST_SYSTEM_PROCESSOR}\" vs. \"${NATIVE_SYSTEM_PROCESSOR}\"")
+endif()
+
+#############################################################
+
+# check the results from DetermineCCompiler
+
+if(NOT "${_CMAKE_TOOLCHAIN_PREFIX}" STREQUAL "arm-elf-")
+ message(FATAL_ERROR "wrong toolchain prefix detected: \"${_CMAKE_TOOLCHAIN_PREFIX}\", expected: \"arm-elf-\"")
+endif()
+
+if(NOT "${_CMAKE_USER_C_COMPILER_PATH}" STREQUAL "/opt/foo/bin")
+ message(FATAL_ERROR "wrong C compiler location detected: \"${_CMAKE_USER_C_COMPILER_PATH}\", expected: \"/opt/foo/bin\"")
+endif()
+
+if(NOT "${CMAKE_C_OUTPUT_EXTENSION}" STREQUAL ".foo")
+ message(FATAL_ERROR "C output extension overwritten: \"${CMAKE_C_OUTPUT_EXTENSION}\", was: \".foo\"")
+endif()
+
+#############################################################
+
+# check the results from DetermineCXXCompiler
+
+if(NOT "${_CMAKE_USER_CXX_COMPILER_PATH}" STREQUAL "/opt/bar/bin")
+ message(FATAL_ERROR "wrong CXX compiler location detected: \"${_CMAKE_USER_CXX_COMPILER_PATH}\", expected: \"/opt/bar/bin\"")
+endif()
+
+if(NOT "${CMAKE_CXX_OUTPUT_EXTENSION}" STREQUAL ".bar")
+ message(FATAL_ERROR "C output extension overwritten: \"${CMAKE_CXX_OUTPUT_EXTENSION}\", was: \".bar\"")
+endif()
+
+message(STATUS "CMAKE_SYSTEM: \"${CMAKE_SYSTEM}\"")
+message(STATUS "_CMAKE_TOOLCHAIN_PREFIX: \"${_CMAKE_TOOLCHAIN_PREFIX}\"")
+message(STATUS "_CMAKE_USER_C_COMPILER_PATH: \"${_CMAKE_USER_C_COMPILER_PATH}\"")
+message(STATUS "_CMAKE_USER_CXX_COMPILER_PATH: \"${_CMAKE_USER_CXX_COMPILER_PATH}\"")
+message(STATUS "CMAKE_C_OUTPUT_EXTENSION: \"${CMAKE_C_OUTPUT_EXTENSION}\"")
+message(STATUS "CMAKE_CXX_OUTPUT_EXTENSION: \"${CMAKE_CXX_OUTPUT_EXTENSION}\"")
diff --git a/Tests/CMakeTests/VariableWatchTest.cmake.in b/Tests/CMakeTests/VariableWatchTest.cmake.in
new file mode 100644
index 0000000..0c084fd
--- /dev/null
+++ b/Tests/CMakeTests/VariableWatchTest.cmake.in
@@ -0,0 +1,31 @@
+message("Start")
+
+variable_watch(TESTVAR MESSAGE)
+variable_watch(TESTVAR1)
+
+macro(testwatch var access file stack)
+ message("There was a ${access} access done on the variable: ${var} in file ${file}")
+ message("List file stack is: ${stack}")
+ set(${var}_watched 1)
+endmacro()
+
+variable_watch(somevar testwatch)
+
+set(TESTVAR1 "1")
+set(TESTVAR "1")
+set(TESTVAR1 "0")
+set(TESTVAR "0")
+
+
+message("Variable: ${somevar}")
+if(NOT somevar_watched)
+ message(SEND_ERROR "'somevar' watch failed!")
+endif()
+set(somevar_watched)
+
+set(somevar "1")
+message("Variable: ${somevar}")
+if(NOT somevar_watched)
+ message(SEND_ERROR "'somevar' watch failed!")
+endif()
+remove(somevar)
diff --git a/Tests/CMakeTests/VersionTest.cmake.in b/Tests/CMakeTests/VersionTest.cmake.in
new file mode 100644
index 0000000..f045605
--- /dev/null
+++ b/Tests/CMakeTests/VersionTest.cmake.in
@@ -0,0 +1,106 @@
+set(min_ver 2.7.20090305)
+cmake_minimum_required(VERSION ${min_ver})
+
+if("${CMAKE_VERSION}" VERSION_LESS "${min_ver}")
+ message(FATAL_ERROR
+ "CMAKE_VERSION=[${CMAKE_VERSION}] is less than [${min_ver}]")
+else()
+ message("CMAKE_VERSION=[${CMAKE_VERSION}] is not less than [${min_ver}]")
+endif()
+
+set(EQUALV "1 1")
+list(APPEND EQUALV "1.0 1")
+list(APPEND EQUALV "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 1")
+list(APPEND EQUALV "1.2.3.4.5.6.7 1.2.3.4.5.6.7")
+list(APPEND EQUALV "1.2.3.4.5.6.7.8.9 1.2.3.4.5.6.7.8.9")
+
+foreach(v IN LISTS EQUALV)
+ string(REGEX MATCH "(.*) (.*)" _dummy "${v}")
+ # modify any of the operands to see the negative check also works
+ if("${CMAKE_MATCH_1}.2" VERSION_EQUAL CMAKE_MATCH_2)
+ message(FATAL_ERROR "${CMAKE_MATCH_1}.2 is equal ${CMAKE_MATCH_2}?")
+ else()
+ message(STATUS "${CMAKE_MATCH_1}.2 is not equal ${CMAKE_MATCH_2}")
+ endif()
+
+ if(CMAKE_MATCH_1 VERSION_EQUAL "${CMAKE_MATCH_2}.2")
+ message(FATAL_ERROR "${CMAKE_MATCH_1} is equal ${CMAKE_MATCH_2}.2?")
+ else()
+ message(STATUS "${CMAKE_MATCH_1} is not equal ${CMAKE_MATCH_2}.2")
+ endif()
+endforeach()
+
+# test the negative outcomes first, due to the implementation the positive
+# allow some additional strings to pass that would not fail for the negative
+# tests
+
+list(APPEND EQUALV "1a 1")
+list(APPEND EQUALV "1.1a 1.1")
+list(APPEND EQUALV "1.0a 1")
+list(APPEND EQUALV "1a 1.0")
+
+foreach(v IN LISTS EQUALV)
+ # check equal versions
+ string(REGEX MATCH "(.*) (.*)" _dummy "${v}")
+ if(CMAKE_MATCH_1 VERSION_EQUAL CMAKE_MATCH_2)
+ message(STATUS "${CMAKE_MATCH_1} is equal ${CMAKE_MATCH_2}")
+ else()
+ message(FATAL_ERROR "${CMAKE_MATCH_1} is not equal ${CMAKE_MATCH_2}?")
+ endif()
+
+ # still equal, but inverted order of operands
+ string(REGEX MATCH "(.*) (.*)" _dummy "${v}")
+ if(CMAKE_MATCH_2 VERSION_EQUAL CMAKE_MATCH_1)
+ message(STATUS "${CMAKE_MATCH_2} is equal ${CMAKE_MATCH_1}")
+ else()
+ message(FATAL_ERROR "${CMAKE_MATCH_2} is not equal ${CMAKE_MATCH_1}?")
+ endif()
+endforeach()
+
+set(LESSV "1.2.3.4.5.6.7.8 1.2.3.4.5.6.7.9")
+list(APPEND LESSV "1.2.3.4.5.6.7 1.2.3.4.5.6.7.9")
+list(APPEND LESSV "1 1.0.0.1")
+foreach(v IN LISTS LESSV)
+ string(REGEX MATCH "(.*) (.*)" _dummy "${v}")
+ # check less
+ if(CMAKE_MATCH_1 VERSION_LESS CMAKE_MATCH_2)
+ message(STATUS "${CMAKE_MATCH_1} is less than ${CMAKE_MATCH_2}")
+ else()
+ message(FATAL_ERROR "${CMAKE_MATCH_1} is not less than ${CMAKE_MATCH_2}?")
+ endif()
+
+ # check greater
+ if(CMAKE_MATCH_2 VERSION_GREATER CMAKE_MATCH_1)
+ message(STATUS "${CMAKE_MATCH_2} is greater than ${CMAKE_MATCH_1}")
+ else()
+ message(FATAL_ERROR "${CMAKE_MATCH_2} is not greater than ${CMAKE_MATCH_1}?")
+ endif()
+
+ # check less negative case
+ if(NOT CMAKE_MATCH_2 VERSION_LESS CMAKE_MATCH_1)
+ message(STATUS "${CMAKE_MATCH_2} is not less than ${CMAKE_MATCH_1}")
+ else()
+ message(FATAL_ERROR "${CMAKE_MATCH_2} is less than ${CMAKE_MATCH_1}?")
+ endif()
+
+ # check greater or equal (same as less negative)
+ if(CMAKE_MATCH_2 VERSION_GREATER_EQUAL CMAKE_MATCH_1)
+ message(STATUS "${CMAKE_MATCH_2} is not less than ${CMAKE_MATCH_1}")
+ else()
+ message(FATAL_ERROR "${CMAKE_MATCH_2} is less than ${CMAKE_MATCH_1}?")
+ endif()
+
+ # check greater negative case
+ if(NOT CMAKE_MATCH_1 VERSION_GREATER CMAKE_MATCH_2)
+ message(STATUS "${CMAKE_MATCH_1} is not greater than ${CMAKE_MATCH_2}")
+ else()
+ message(FATAL_ERROR "${CMAKE_MATCH_1} is greater than ${CMAKE_MATCH_2}?")
+ endif()
+
+ # check less or equal (same as greater negative) case
+ if(CMAKE_MATCH_1 VERSION_LESS_EQUAL CMAKE_MATCH_2)
+ message(STATUS "${CMAKE_MATCH_1} is not greater than ${CMAKE_MATCH_2}")
+ else()
+ message(FATAL_ERROR "${CMAKE_MATCH_1} is greater than ${CMAKE_MATCH_2}?")
+ endif()
+endforeach()
diff --git a/Tests/CMakeTests/WhileTest.cmake.in b/Tests/CMakeTests/WhileTest.cmake.in
new file mode 100644
index 0000000..9066544
--- /dev/null
+++ b/Tests/CMakeTests/WhileTest.cmake.in
@@ -0,0 +1,17 @@
+set(NUMBERS "")
+set(COUNT 0)
+
+while(COUNT LESS 200)
+ string(APPEND NUMBERS " ${COUNT}")
+ set(COUNT "2${COUNT}")
+
+ set(NCOUNT 3)
+ while(NCOUNT LESS 31)
+ string(APPEND NUMBERS " ${NCOUNT}")
+ string(APPEND NCOUNT "0")
+ endwhile()
+endwhile()
+
+if(NOT NUMBERS STREQUAL " 0 3 30 20 3 30")
+ message(SEND_ERROR "while loop nesting error, result: '${NUMBERS}'")
+endif()
diff --git a/Tests/CMakeTests/include/cmake_i_do_not_exist_in_the_system.h b/Tests/CMakeTests/include/cmake_i_do_not_exist_in_the_system.h
new file mode 100644
index 0000000..2392aee
--- /dev/null
+++ b/Tests/CMakeTests/include/cmake_i_do_not_exist_in_the_system.h
@@ -0,0 +1 @@
+/* empty header file */
diff --git a/Tests/COnly/CMakeLists.txt b/Tests/COnly/CMakeLists.txt
new file mode 100644
index 0000000..1c24017
--- /dev/null
+++ b/Tests/COnly/CMakeLists.txt
@@ -0,0 +1,17 @@
+# a simple C only test case
+cmake_minimum_required(VERSION 2.8.12)
+project (COnly C)
+
+set(CMAKE_DEBUG_POSTFIX "_test_debug_postfix")
+add_library(testc1 STATIC libc1.c)
+add_library(testc2 SHARED libc2.c)
+add_executable (COnly conly.c foo.c foo.h)
+target_link_libraries(COnly testc1 testc2)
+if(MSVC_VERSION AND NOT CMAKE_C_COMPILER_ID STREQUAL Clang OR "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+ set_target_properties(COnly PROPERTIES
+ LINK_FLAGS " /NODEFAULTLIB:\"libcdg.lib\" /NODEFAULTLIB:\"libcmtg.lib\" /NODEFAULTLIB:\"foomsvcrt.lib\" /NODEFAULTLIB:\"libbar.lib\" /NODEFAULTLIB:\"libfooba.lib\"")
+endif()
+string(ASCII 35 32 67 77 97 107 101 ASCII_STRING)
+message(STATUS "String: ${ASCII_STRING}")
+
+add_library(testCModule MODULE testCModule.c)
diff --git a/Tests/COnly/conly.c b/Tests/COnly/conly.c
new file mode 100644
index 0000000..2ae8a1a
--- /dev/null
+++ b/Tests/COnly/conly.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+
+#include "foo.h"
+#include "libc1.h"
+#include "libc2.h"
+
+int main()
+{
+ int class = 0;
+ if (LibC1Func() != 2.0) {
+ printf("Problem with libc1\n");
+ return 1;
+ }
+ if (LibC2Func() != 1.0) {
+ printf("Problem with libc2\n");
+ return 1;
+ }
+ printf("Foo: %s %d\n", foo, class);
+ return 0;
+}
diff --git a/Tests/COnly/foo.c b/Tests/COnly/foo.c
new file mode 100644
index 0000000..e4faf38
--- /dev/null
+++ b/Tests/COnly/foo.c
@@ -0,0 +1 @@
+char* foo = "Foo";
diff --git a/Tests/COnly/foo.h b/Tests/COnly/foo.h
new file mode 100644
index 0000000..ad4a9af
--- /dev/null
+++ b/Tests/COnly/foo.h
@@ -0,0 +1 @@
+extern char* foo;
diff --git a/Tests/COnly/libc1.c b/Tests/COnly/libc1.c
new file mode 100644
index 0000000..b01e1e1
--- /dev/null
+++ b/Tests/COnly/libc1.c
@@ -0,0 +1,4 @@
+float LibC1Func()
+{
+ return 2.0;
+}
diff --git a/Tests/COnly/libc1.h b/Tests/COnly/libc1.h
new file mode 100644
index 0000000..84c94a9
--- /dev/null
+++ b/Tests/COnly/libc1.h
@@ -0,0 +1 @@
+extern float LibC1Func();
diff --git a/Tests/COnly/libc2.c b/Tests/COnly/libc2.c
new file mode 100644
index 0000000..0fd8956
--- /dev/null
+++ b/Tests/COnly/libc2.c
@@ -0,0 +1,6 @@
+#include "libc2.h"
+
+float LibC2Func()
+{
+ return 1.0;
+}
diff --git a/Tests/COnly/libc2.h b/Tests/COnly/libc2.h
new file mode 100644
index 0000000..43ebce9
--- /dev/null
+++ b/Tests/COnly/libc2.h
@@ -0,0 +1,11 @@
+#ifdef _WIN32
+# ifdef testc2_EXPORTS
+# define CM_TEST_LIB_EXPORT __declspec(dllexport)
+# else
+# define CM_TEST_LIB_EXPORT __declspec(dllimport)
+# endif
+#else
+# define CM_TEST_LIB_EXPORT
+#endif
+
+CM_TEST_LIB_EXPORT float LibC2Func();
diff --git a/Tests/COnly/testCModule.c b/Tests/COnly/testCModule.c
new file mode 100644
index 0000000..edeb2b1
--- /dev/null
+++ b/Tests/COnly/testCModule.c
@@ -0,0 +1,9 @@
+#ifdef _WIN32
+# define TEST_EXPORT __declspec(dllexport)
+#else
+# define TEST_EXPORT
+#endif
+TEST_EXPORT int testCModule(void)
+{
+ return 0;
+}
diff --git a/Tests/CPackComponents/CMakeLists.txt b/Tests/CPackComponents/CMakeLists.txt
new file mode 100644
index 0000000..c1b348e
--- /dev/null
+++ b/Tests/CPackComponents/CMakeLists.txt
@@ -0,0 +1,128 @@
+# CPack Example: User-selectable Installation Components
+#
+# In this example, we have a simple library (mylib) with an example
+# application (mylibapp). We create a binary installer that allows
+# users to select which pieces will be installed: the example
+# application, the library binaries, and/or the header file.
+cmake_minimum_required(VERSION 2.8.12)
+project(CPackComponents)
+
+# Create the mylib library
+add_library(mylib mylib.cpp)
+
+# Create the mylibapp application
+add_executable(mylibapp mylibapp.cpp)
+target_link_libraries(mylibapp mylib)
+
+# On Linux, enable using an absolute install path to verify that
+# CMAKE_INSTALL_PREFIX and CPACK_SET_DESTDIR interact properly.
+#
+# But only use absolute paths if not targeting an NSIS installer
+# as indicated by CPACK_BINARY_NSIS. (If we allow this, the test
+# fails on Linux machines with makensis installed when we are not
+# cross-compiling...)
+#
+if(UNIX AND NOT APPLE)
+ if(NOT CPACK_BINARY_NSIS)
+ set(mylib_install_to_absolute_path ON)
+ endif()
+endif()
+
+if(mylib_install_to_absolute_path)
+ set(CMAKE_INSTALL_PREFIX "/opt/mylib")
+ set(CPACK_SET_DESTDIR ON)
+endif()
+
+# Create installation targets. Note that we put each kind of file
+# into a different component via COMPONENT. These components will
+# be used to create the installation components.
+install(TARGETS mylib
+ ARCHIVE
+ DESTINATION lib
+ COMPONENT libraries)
+install(TARGETS mylibapp
+ RUNTIME
+ DESTINATION bin
+ COMPONENT applications)
+install(FILES mylib.h
+ DESTINATION include
+ COMPONENT headers)
+install(FILES "Issue 7470.html"
+ DESTINATION docs
+ COMPONENT documentation)
+
+if(mylib_install_to_absolute_path)
+ install(FILES mylib.cpp
+ DESTINATION /opt/mylib-source
+ COMPONENT source)
+endif()
+
+# CPack boilerplate for this project
+set(CPACK_PACKAGE_NAME "MyLib")
+set(CPACK_PACKAGE_VENDOR "CMake.org")
+set(CPACK_PACKAGE_CONTACT "somebody@cmake.org")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MyLib - CPack Component Installation Example")
+set(CPACK_PACKAGE_VERSION "1.0.0")
+set(CPACK_PACKAGE_VERSION_MAJOR "1")
+set(CPACK_PACKAGE_VERSION_MINOR "0")
+set(CPACK_PACKAGE_VERSION_PATCH "0")
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "CPack Component Example")
+
+# Settings used when building NSIS installers
+set(CPACK_NSIS_MENU_LINKS
+ "ftp://ftpserver" "Test Ftp Link"
+ "ftps://ftpsserver" "Test Ftps Link"
+ "https://cmake.org" "CMake Web Site"
+ "https://github.com/" "Test Https Link"
+ "mailto:kitware@kitware.com" "Test MailTo Link"
+ "news://newsserver" "Test News Link"
+ )
+
+# Suggested default root for end users of the installer:
+set(CPACK_NSIS_INSTALL_ROOT "C:/Program Files/CMake Tests Install Root")
+
+# Include CPack to introduce the appropriate targets
+include(CPack)
+
+# Installation types
+cpack_add_install_type(Full
+ DISPLAY_NAME "Everything")
+cpack_add_install_type(Developer)
+
+# Component groups
+cpack_add_component_group(Runtime)
+cpack_add_component_group(Development
+ EXPANDED
+ DESCRIPTION "All of the tools you'll ever need to develop software")
+
+# Components
+cpack_add_component(applications
+ DISPLAY_NAME "MyLib Application"
+ DESCRIPTION "An extremely useful application that makes use of MyLib"
+ GROUP Runtime
+ INSTALL_TYPES Full)
+cpack_add_component(documentation
+ DISPLAY_NAME "MyLib Documentation"
+ DESCRIPTION "The extensive suite of MyLib Application documentation files"
+ GROUP Runtime
+ INSTALL_TYPES Full)
+cpack_add_component(libraries
+ DISPLAY_NAME "Libraries"
+ DESCRIPTION "Static libraries used to build programs with MyLib"
+ GROUP Development
+ INSTALL_TYPES Developer Full)
+cpack_add_component(headers
+ DISPLAY_NAME "C++ Headers"
+ DESCRIPTION "C/C++ header files for use with MyLib"
+ GROUP Development
+ DEPENDS libraries
+ INSTALL_TYPES Developer Full)
+
+if(mylib_install_to_absolute_path)
+ cpack_add_component(source
+ DISPLAY_NAME "C++ Source Files"
+ DESCRIPTION "C/C++ source files to build MyLib"
+ GROUP Development
+ DEPENDS libraries
+ INSTALL_TYPES Developer Full)
+endif()
diff --git a/Tests/CPackComponents/Issue 7470.html b/Tests/CPackComponents/Issue 7470.html
new file mode 100644
index 0000000..59fbee7
--- /dev/null
+++ b/Tests/CPackComponents/Issue 7470.html
@@ -0,0 +1,9 @@
+<html>
+<body>
+The install rule for this file demonstrates the problem described in<br/>
+CMake issue #7470:<br/>
+<br/>
+<a href="https://gitlab.kitware.com/cmake/cmake/-/issues/7470">
+https://gitlab.kitware.com/cmake/cmake/-/issues/7470</a><br/>
+</body>
+</html>
diff --git a/Tests/CPackComponents/VerifyResult.cmake b/Tests/CPackComponents/VerifyResult.cmake
new file mode 100644
index 0000000..c7c24fd
--- /dev/null
+++ b/Tests/CPackComponents/VerifyResult.cmake
@@ -0,0 +1,48 @@
+message(STATUS "=============================================================================")
+message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+message(STATUS "")
+
+if(NOT CPackComponents_BINARY_DIR)
+ message(FATAL_ERROR "CPackComponents_BINARY_DIR not set")
+endif()
+
+set(expected_file_mask "")
+
+if(WIN32)
+ # Only expect the *.exe installer if it looks like NSIS is
+ # installed on this machine:
+ #
+ find_program(NSIS_MAKENSIS_EXECUTABLE NAMES makensis
+ PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS]
+ DOC "makensis.exe location"
+ )
+ if(NSIS_MAKENSIS_EXECUTABLE)
+ set(expected_file_mask "${CPackComponents_BINARY_DIR}/MyLib-*.exe")
+ endif()
+endif()
+
+if(APPLE)
+ # Always expect the *.dmg installer - PackageMaker should always
+ # be installed on a development Mac:
+ #
+ set(expected_file_mask "${CPackComponents_BINARY_DIR}/MyLib-*.dmg")
+endif()
+
+if(expected_file_mask)
+ set(expected_count 1)
+ file(GLOB expected_file "${expected_file_mask}")
+
+ message(STATUS "expected_count='${expected_count}'")
+ message(STATUS "expected_file='${expected_file}'")
+ message(STATUS "expected_file_mask='${expected_file_mask}'")
+
+ if(NOT expected_file)
+ message(FATAL_ERROR "error: expected_file does not exist: CPackComponents test fails.")
+ endif()
+
+ list(LENGTH expected_file actual_count)
+ message(STATUS "actual_count='${actual_count}'")
+ if(NOT actual_count EQUAL expected_count)
+ message(FATAL_ERROR "error: expected_count does not match actual_count: CPackComponents test fails.")
+ endif()
+endif()
diff --git a/Tests/CPackComponents/mylib.cpp b/Tests/CPackComponents/mylib.cpp
new file mode 100644
index 0000000..8d63071
--- /dev/null
+++ b/Tests/CPackComponents/mylib.cpp
@@ -0,0 +1,8 @@
+#include "mylib.h"
+
+#include "stdio.h"
+
+void mylib_function()
+{
+ printf("This is mylib");
+}
diff --git a/Tests/CPackComponents/mylib.h b/Tests/CPackComponents/mylib.h
new file mode 100644
index 0000000..5d0a822
--- /dev/null
+++ b/Tests/CPackComponents/mylib.h
@@ -0,0 +1 @@
+void mylib_function();
diff --git a/Tests/CPackComponents/mylibapp.cpp b/Tests/CPackComponents/mylibapp.cpp
new file mode 100644
index 0000000..a438ac7
--- /dev/null
+++ b/Tests/CPackComponents/mylibapp.cpp
@@ -0,0 +1,6 @@
+#include "mylib.h"
+
+int main()
+{
+ mylib_function();
+}
diff --git a/Tests/CPackComponentsDEB/CMakeLists.txt b/Tests/CPackComponentsDEB/CMakeLists.txt
new file mode 100644
index 0000000..b2e2106
--- /dev/null
+++ b/Tests/CPackComponentsDEB/CMakeLists.txt
@@ -0,0 +1,147 @@
+# CPack Example: User-selectable Installation Components
+#
+# In this example, we have a simple library (mylib) with an example
+# application (mylibapp). We create a binary installer (a CPack Generator)
+# which supports CPack components.
+
+cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
+project(CPackComponentsDEB VERSION 1.0.3)
+
+# Use GNUInstallDirs in order to enforce lib64 if needed
+include(GNUInstallDirs)
+
+# Create the mylib library
+add_library(mylib mylib.cpp)
+
+# Create the mylibapp application
+add_executable(mylibapp mylibapp.cpp)
+target_link_libraries(mylibapp mylib)
+
+# Duplicate of mylibapp application
+# which won't be put in any component (?mistake?)
+add_executable(mylibapp2 mylibapp.cpp)
+target_link_libraries(mylibapp2 mylib)
+
+if (CPackDEBConfiguration MATCHES "shlibdeps-with-private-lib")
+ add_subdirectory("shlibdeps-with-private-lib")
+ add_executable(mylibapp3 mylibapp.cpp)
+ target_compile_definitions(mylibapp3 PRIVATE -DSHLIBDEPS_PRIVATE)
+ target_link_libraries(mylibapp3 myprivatelib)
+endif()
+
+# Create installation targets. Note that we put each kind of file
+# into a different component via COMPONENT. These components will
+# be used to create the installation components.
+install(TARGETS mylib
+ ARCHIVE
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ COMPONENT libraries)
+
+install(TARGETS mylibapp
+ RUNTIME
+ DESTINATION bin
+ COMPONENT applications)
+
+install(FILES mylib.h
+ DESTINATION include
+ COMPONENT headers)
+
+if (CPackDEBConfiguration MATCHES "shlibdeps-with-private-lib")
+ install(TARGETS mylibapp3
+ RUNTIME
+ DESTINATION bin
+ COMPONENT applications)
+endif()
+
+# CPack boilerplate for this project
+set(CPACK_PACKAGE_NAME "MyLib")
+set(CPACK_PACKAGE_CONTACT "None")
+set(CPACK_PACKAGE_VENDOR "CMake.org")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MyLib - CPack Component Installation Example")
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "CPack Component Example")
+set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/license.txt)
+
+# Tell CPack all of the components to install. The "ALL"
+# refers to the fact that this is the set of components that
+# will be included when CPack is instructed to put everything
+# into the binary installer (the default behavior).
+set(CPACK_COMPONENTS_ALL applications libraries headers)
+
+# Set the displayed names for each of the components to install.
+# These will be displayed in the list of components inside the installer.
+set(CPACK_COMPONENT_APPLICATIONS_DISPLAY_NAME "MyLib Application")
+set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries")
+set(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C++ Headers")
+
+# Provide descriptions for each of the components to install.
+# When the user hovers the mouse over the name of a component,
+# the description will be shown in the "Description" box in the
+# installer. If no descriptions are provided, the "Description"
+# box will be removed.
+set(CPACK_COMPONENT_APPLICATIONS_DESCRIPTION
+ "An extremely useful application that makes use of MyLib")
+set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION
+ "Static libraries used to build programs with MyLib")
+set(CPACK_COMPONENT_HEADERS_DESCRIPTION
+ "C/C++ header files for use with MyLib")
+
+# It doesn't make sense to install the headers without the libraries
+# (because you could never use the headers!), so make the headers component
+# depend on the libraries component.
+set(CPACK_COMPONENT_HEADERS_DEPENDS libraries)
+
+# creates preinst/prerm scripts with specific permissions. Those permissions
+# (especially executable) should be in the final archive
+find_program(CHMOD_PROG chmod)
+if(CHMOD_PROG)
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/preinst "echo default_preinst")
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/prerm "echo default_prerm")
+
+ # Those should have 755 permission normally. We mess it up to see if
+ # CPACK_DEBIAN_APPLICATIONS_PACKAGE_CONTROL_STRICT_PERMISSION is able to fix
+ # it.
+ execute_process(COMMAND ${CHMOD_PROG} 640 ${CMAKE_CURRENT_BINARY_DIR}/preinst)
+ execute_process(COMMAND ${CHMOD_PROG} 640 ${CMAKE_CURRENT_BINARY_DIR}/prerm)
+
+ set(CPACK_DEBIAN_APPLICATIONS_PACKAGE_CONTROL_EXTRA
+ "${CMAKE_CURRENT_BINARY_DIR}/preinst;${CMAKE_CURRENT_BINARY_DIR}/prerm")
+
+ set(CPACK_DEBIAN_APPLICATIONS_PACKAGE_CONTROL_STRICT_PERMISSION TRUE)
+endif()
+
+# creates a symbolic link and a directory. Those should not be hashed.
+# warning: relocation of the symlink is not supported (symlinks with relative
+# paths)
+execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink mylibapp symtest)
+install(FILES ${CPackComponentsDEB_BINARY_DIR}/symtest
+ DESTINATION bin
+ COMPONENT applications)
+
+if(EXISTS "./dirtest")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E rm -rf ./dirtest)
+endif()
+# NOTE: directory left empty on purpose
+execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ./dirtest)
+# NOTE: we should not add the trailing "/" to dirtest
+install(DIRECTORY ${CPackComponentsDEB_BINARY_DIR}/dirtest
+ DESTINATION bin/
+ COMPONENT applications)
+
+# We may use the CPack specific config file in order
+# to tailor CPack behavior on a CPack generator specific way
+# (Behavior would be different for RPM or TGZ or DEB ...)
+if (NOT DEFINED CPackDEBConfiguration)
+ message(FATAL_ERROR "CPackDEBConfiguration should be defined")
+endif()
+
+# Setup project specific CPack-time CPack Config file.
+configure_file(${CPackComponentsDEB_SOURCE_DIR}/MyLibCPackConfig-${CPackDEBConfiguration}.cmake.in
+ ${CPackComponentsDEB_BINARY_DIR}/MyLibCPackConfig-${CPackDEBConfiguration}.cmake
+ @ONLY)
+set(CPACK_PROJECT_CONFIG_FILE ${CPackComponentsDEB_BINARY_DIR}/MyLibCPackConfig-${CPackDEBConfiguration}.cmake)
+
+# set CPACK_DEBIAN_FILE_NAME to use default package name format
+set(CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT")
+
+# Include CPack to introduce the appropriate targets
+include(CPack)
diff --git a/Tests/CPackComponentsDEB/MyLibCPackConfig-components-depend1.cmake.in b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-depend1.cmake.in
new file mode 100644
index 0000000..dc038fa
--- /dev/null
+++ b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-depend1.cmake.in
@@ -0,0 +1,21 @@
+#
+# Activate component packaging
+#
+
+if(CPACK_GENERATOR MATCHES "DEB")
+ set(CPACK_DEB_COMPONENT_INSTALL "ON")
+ set(CPACK_DEBIAN_ENABLE_COMPONENT_DEPENDS "ON")
+endif()
+
+#
+# Choose grouping way
+#
+#set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE)
+#set(CPACK_COMPONENTS_GROUPING)
+set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+#set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1)
+
+# setting dependencies
+set(CPACK_DEBIAN_PACKAGE_DEPENDS "depend-default")
+set(CPACK_DEBIAN_APPLICATIONS_PACKAGE_DEPENDS "depend-application")
+set(CPACK_DEBIAN_HEADERS_PACKAGE_DEPENDS "depend-headers")
diff --git a/Tests/CPackComponentsDEB/MyLibCPackConfig-components-depend2.cmake.in b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-depend2.cmake.in
new file mode 100644
index 0000000..1aa7d01
--- /dev/null
+++ b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-depend2.cmake.in
@@ -0,0 +1,30 @@
+#
+# Activate component packaging
+#
+
+if(CPACK_GENERATOR MATCHES "DEB")
+ set(CPACK_DEB_COMPONENT_INSTALL "ON")
+ set(CPACK_DEBIAN_ENABLE_COMPONENT_DEPENDS "ON")
+endif()
+
+#
+# Choose grouping way
+#
+#set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE)
+#set(CPACK_COMPONENTS_GROUPING)
+set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+#set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1)
+
+# setting dependencies
+set(CPACK_DEBIAN_PACKAGE_DEPENDS "depend-default")
+set(CPACK_DEBIAN_HEADERS_PACKAGE_DEPENDS "depend-headers")
+
+# this time we set shlibdeps to on
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+set(CPACK_DEBIAN_HEADERS_PACKAGE_SHLIBDEPS OFF)
+set(CPACK_DEBIAN_LIBRARIES_PACKAGE_SHLIBDEPS OFF)
+
+# we also set the dependencies of APPLICATION component to empty, and let
+# shlibdeps do the job for this component. Otherwise the default will
+# override
+set(CPACK_DEBIAN_APPLICATIONS_PACKAGE_DEPENDS "")
diff --git a/Tests/CPackComponentsDEB/MyLibCPackConfig-components-description1.cmake.in b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-description1.cmake.in
new file mode 100644
index 0000000..fb973ad
--- /dev/null
+++ b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-description1.cmake.in
@@ -0,0 +1,23 @@
+#
+# Activate component packaging
+#
+
+if(CPACK_GENERATOR MATCHES "DEB")
+ set(CPACK_DEB_COMPONENT_INSTALL "ON")
+endif()
+
+#
+# Choose grouping way
+#
+#set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE)
+#set(CPACK_COMPONENTS_GROUPING)
+set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+#set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1)
+
+# overriding previous descriptions
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "main description") # This become a summary line (the first one) of all descriptions
+set(CPACK_COMPONENT_APPLICATIONS_DESCRIPTION "applications_description\n")
+set(CPACK_COMPONENT_HEADERS_DESCRIPTION "headers_description")
+# libraries does not have any description and should inherit from CPACK_PACKAGE_DESCRIPTION_SUMMARY
+# plus content of the `CPACK_PACKAGE_DESCRIPTION_FILE`.
+unset(CPACK_COMPONENT_LIBRARIES_DESCRIPTION)
diff --git a/Tests/CPackComponentsDEB/MyLibCPackConfig-components-description2.cmake.in b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-description2.cmake.in
new file mode 100644
index 0000000..d877325
--- /dev/null
+++ b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-description2.cmake.in
@@ -0,0 +1,26 @@
+#
+# Activate component packaging
+#
+
+if(CPACK_GENERATOR MATCHES "DEB")
+ set(CPACK_DEB_COMPONENT_INSTALL "ON")
+endif()
+
+#
+# Choose grouping way
+#
+#set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE)
+#set(CPACK_COMPONENTS_GROUPING)
+set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+#set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1)
+
+# overriding previous descriptions
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "main description 2")
+
+# Components do not have any description.
+# So, content of `CPACK_PACKAGE_DESCRIPTION_FILE` gonna used
+# after summary line.
+unset(CPACK_COMPONENT_APPLICATIONS_DESCRIPTION)
+unset(CPACK_COMPONENT_HEADERS_DESCRIPTION)
+
+set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION "library description")
diff --git a/Tests/CPackComponentsDEB/MyLibCPackConfig-components-lintian-dpkgdeb-checks.cmake.in b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-lintian-dpkgdeb-checks.cmake.in
new file mode 100644
index 0000000..e0a9e9d
--- /dev/null
+++ b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-lintian-dpkgdeb-checks.cmake.in
@@ -0,0 +1,15 @@
+#
+# Activate component packaging
+#
+
+if(CPACK_GENERATOR MATCHES "DEB")
+ set(CPACK_DEB_COMPONENT_INSTALL "ON")
+endif()
+
+#
+# Choose grouping way
+#
+#set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE)
+#set(CPACK_COMPONENTS_GROUPING)
+set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+#set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1)
diff --git a/Tests/CPackComponentsDEB/MyLibCPackConfig-components-shlibdeps1.cmake.in b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-shlibdeps1.cmake.in
new file mode 100644
index 0000000..cfe6df5
--- /dev/null
+++ b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-shlibdeps1.cmake.in
@@ -0,0 +1,24 @@
+#
+# Activate component packaging
+#
+
+if(CPACK_GENERATOR MATCHES "DEB")
+ set(CPACK_DEB_COMPONENT_INSTALL "ON")
+endif()
+
+#
+# Choose grouping way
+#
+#set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE)
+#set(CPACK_COMPONENTS_GROUPING)
+set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+#set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1)
+
+# we set shlibdeps to on
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+# except for the component "headers" that do not contain any binary.
+# the packaging will just fail if this does not work
+set(CPACK_DEBIAN_HEADERS_PACKAGE_SHLIBDEPS OFF)
+
+# Also libraries contains only a static library.
+set(CPACK_DEBIAN_LIBRARIES_PACKAGE_SHLIBDEPS OFF)
diff --git a/Tests/CPackComponentsDEB/MyLibCPackConfig-components-source.cmake.in b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-source.cmake.in
new file mode 100644
index 0000000..352f10b
--- /dev/null
+++ b/Tests/CPackComponentsDEB/MyLibCPackConfig-components-source.cmake.in
@@ -0,0 +1,33 @@
+#
+# Activate component packaging
+#
+
+if(CPACK_GENERATOR MATCHES "DEB")
+ set(CPACK_DEB_COMPONENT_INSTALL "ON")
+endif()
+
+#
+# Choose grouping way
+#
+set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+
+# setting dependencies
+set(CPACK_DEBIAN_PACKAGE_DEPENDS "depend-default")
+set(CPACK_DEBIAN_HEADERS_PACKAGE_DEPENDS "depend-headers")
+
+# this time we set shlibdeps to on
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+set(CPACK_DEBIAN_HEADERS_PACKAGE_SHLIBDEPS OFF)
+set(CPACK_DEBIAN_LIBRARIES_PACKAGE_SHLIBDEPS OFF)
+
+# we also set the dependencies of APPLICATION component to empty, and let
+# shlibdeps do the job for this component. Otherwise the default will
+# override
+set(CPACK_DEBIAN_APPLICATIONS_PACKAGE_DEPENDS "")
+
+# this sets the generated packages source to the desired one, in case
+# several packages are generated from a unique source (the case with
+# multicomponents packaging).
+
+set(CPACK_DEBIAN_PACKAGE_SOURCE "test-source")
+set(CPACK_DEBIAN_APPLICATIONS_PACKAGE_SOURCE "test-other-source")
diff --git a/Tests/CPackComponentsDEB/MyLibCPackConfig-compression.cmake.in b/Tests/CPackComponentsDEB/MyLibCPackConfig-compression.cmake.in
new file mode 100644
index 0000000..ff18834
--- /dev/null
+++ b/Tests/CPackComponentsDEB/MyLibCPackConfig-compression.cmake.in
@@ -0,0 +1,11 @@
+#
+# Test that setting the compression produces valid
+# packages (compression does not leak to the DEBIAN/ files that use gzip)
+#
+
+if(CPACK_GENERATOR MATCHES "DEB")
+ set(CPACK_DEB_COMPONENT_INSTALL "OFF")
+endif()
+
+set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE)
+set(CPACK_DEBIAN_COMPRESSION_TYPE xz)
diff --git a/Tests/CPackComponentsDEB/MyLibCPackConfig-shlibdeps-with-private-lib-failure.cmake.in b/Tests/CPackComponentsDEB/MyLibCPackConfig-shlibdeps-with-private-lib-failure.cmake.in
new file mode 100644
index 0000000..cfe6df5
--- /dev/null
+++ b/Tests/CPackComponentsDEB/MyLibCPackConfig-shlibdeps-with-private-lib-failure.cmake.in
@@ -0,0 +1,24 @@
+#
+# Activate component packaging
+#
+
+if(CPACK_GENERATOR MATCHES "DEB")
+ set(CPACK_DEB_COMPONENT_INSTALL "ON")
+endif()
+
+#
+# Choose grouping way
+#
+#set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE)
+#set(CPACK_COMPONENTS_GROUPING)
+set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+#set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1)
+
+# we set shlibdeps to on
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+# except for the component "headers" that do not contain any binary.
+# the packaging will just fail if this does not work
+set(CPACK_DEBIAN_HEADERS_PACKAGE_SHLIBDEPS OFF)
+
+# Also libraries contains only a static library.
+set(CPACK_DEBIAN_LIBRARIES_PACKAGE_SHLIBDEPS OFF)
diff --git a/Tests/CPackComponentsDEB/MyLibCPackConfig-shlibdeps-with-private-lib-success.cmake.in b/Tests/CPackComponentsDEB/MyLibCPackConfig-shlibdeps-with-private-lib-success.cmake.in
new file mode 100644
index 0000000..76aadc9
--- /dev/null
+++ b/Tests/CPackComponentsDEB/MyLibCPackConfig-shlibdeps-with-private-lib-success.cmake.in
@@ -0,0 +1,33 @@
+#
+# Activate component packaging
+#
+
+if(CPACK_GENERATOR MATCHES "DEB")
+ set(CPACK_DEB_COMPONENT_INSTALL "ON")
+endif()
+
+#
+# Choose grouping way
+#
+#set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE)
+#set(CPACK_COMPONENTS_GROUPING)
+set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+#set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1)
+
+# we set shlibdeps to on
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+# except for the component "headers" that do not contain any binary.
+# the packaging will just fail if this does not work
+set(CPACK_DEBIAN_HEADERS_PACKAGE_SHLIBDEPS OFF)
+
+# Also libraries contains only a static library.
+set(CPACK_DEBIAN_LIBRARIES_PACKAGE_SHLIBDEPS OFF)
+
+# Most importantly, we also give a list of additional search directories
+# to allow `dpkg-shlibdeps` to find the private dependency.
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS
+ "${CPACK_PACKAGE_DIRECTORY}/shlibdeps-with-private-lib"
+ "${CPACK_PACKAGE_DIRECTORY}/shlibdeps-with-private-lib/Debug"
+ "${CPACK_PACKAGE_DIRECTORY}/shlibdeps-with-private-lib/Release"
+ "${CPACK_PACKAGE_DIRECTORY}/shlibdeps-with-private-lib/RelWithDebInfo"
+ "${CPACK_PACKAGE_DIRECTORY}/shlibdeps-with-private-lib/MinSizeRel")
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-depend1.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-depend1.cmake
new file mode 100644
index 0000000..beccc46
--- /dev/null
+++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-depend1.cmake
@@ -0,0 +1,75 @@
+if(NOT CPackComponentsDEB_SOURCE_DIR)
+ message(FATAL_ERROR "CPackComponentsDEB_SOURCE_DIR not set")
+endif()
+
+include(${CPackComponentsDEB_SOURCE_DIR}/RunCPackVerifyResult.cmake)
+
+
+# expected results
+set(expected_file_mask "${CPackComponentsDEB_BINARY_DIR}/mylib-*_1.0.3_*.deb")
+set(expected_count 3)
+
+
+set(actual_output)
+run_cpack(actual_output
+ CPack_output
+ CPack_error
+ EXPECTED_FILE_MASK "${expected_file_mask}"
+ CONFIG_ARGS ${config_args}
+ CONFIG_VERBOSE ${config_verbose})
+
+
+if(NOT actual_output)
+ message(STATUS "expected_count='${expected_count}'")
+ message(STATUS "expected_file_mask='${expected_file_mask}'")
+ message(STATUS "actual_output_files='${actual_output}'")
+ message(FATAL_ERROR "error: expected_files do not exist: CPackComponentsDEB test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+endif()
+
+list(LENGTH actual_output actual_count)
+if(NOT actual_count EQUAL expected_count)
+ message(STATUS "actual_count='${actual_count}'")
+ message(FATAL_ERROR "error: expected_count=${expected_count} does not match actual_count=${actual_count}: CPackComponents test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error})")
+endif()
+
+
+# dpkg-deb checks for the dependencies of the packages
+find_program(DPKGDEB_EXECUTABLE dpkg-deb)
+if(DPKGDEB_EXECUTABLE)
+ foreach(_f IN LISTS actual_output)
+
+ # extracts the metadata from the package
+ run_dpkgdeb(dpkg_output
+ FILENAME "${_f}"
+ )
+
+ dpkgdeb_return_specific_metaentry(dpkg_package_name
+ DPKGDEB_OUTPUT "${dpkg_output}"
+ METAENTRY "Package:")
+
+ dpkgdeb_return_specific_metaentry(dpkg_depends
+ DPKGDEB_OUTPUT "${dpkg_output}"
+ METAENTRY "Depends:")
+
+ message(STATUS "package='${dpkg_package_name}', dependencies='${dpkg_depends}'")
+
+ if(dpkg_package_name STREQUAL "mylib-applications")
+ if(NOT dpkg_depends STREQUAL "depend-application")
+ message(SEND_ERROR "dpkg-deb: ${_f}: Incorrect dependencies for package ${dpkg_package_name}: '${dpkg_depends}' != 'depend-application'\n")
+ endif()
+ elseif(dpkg_package_name STREQUAL "mylib-headers")
+ if(NOT dpkg_depends STREQUAL "mylib-libraries (= 1.0.3), depend-headers")
+ message(SEND_ERROR "dpkg-deb: ${_f}: Incorrect dependencies for package ${dpkg_package_name}: '${dpkg_depends}' != 'mylib-libraries (= 1.0.3), depend-headers'\n")
+ endif()
+ elseif(dpkg_package_name STREQUAL "mylib-libraries")
+ if(NOT dpkg_depends STREQUAL "depend-default")
+ message(SEND_ERROR "dpkg-deb: ${_f}: Incorrect dependencies for package ${dpkg_package_name}: '${dpkg_depends}' != 'depend-default'\n")
+ endif()
+ else()
+ message(SEND_ERROR "dpkg-deb: ${_f}: component name not found: ${dpkg_package_name}\n")
+ endif()
+
+ endforeach()
+else()
+ message("dpkg-deb executable not found - skipping dpkg-deb test")
+endif()
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-depend2.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-depend2.cmake
new file mode 100644
index 0000000..88f3248
--- /dev/null
+++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-depend2.cmake
@@ -0,0 +1,85 @@
+if(NOT CPackComponentsDEB_SOURCE_DIR)
+ message(FATAL_ERROR "CPackComponentsDEB_SOURCE_DIR not set")
+endif()
+
+include(${CPackComponentsDEB_SOURCE_DIR}/RunCPackVerifyResult.cmake)
+
+
+# expected results
+set(expected_file_mask "${CPackComponentsDEB_BINARY_DIR}/mylib-*_1.0.3_*.deb")
+set(expected_count 3)
+
+set(config_verbose -V)
+set(actual_output)
+run_cpack(actual_output
+ CPack_output
+ CPack_error
+ EXPECTED_FILE_MASK "${expected_file_mask}"
+ CONFIG_ARGS ${config_args}
+ CONFIG_VERBOSE ${config_verbose})
+
+
+if(NOT actual_output)
+ message(STATUS "expected_count='${expected_count}'")
+ message(STATUS "expected_file_mask='${expected_file_mask}'")
+ message(STATUS "actual_output_files='${actual_output}'")
+ message(FATAL_ERROR "error: expected_files do not exist: CPackComponentsDEB test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+endif()
+
+list(LENGTH actual_output actual_count)
+if(NOT actual_count EQUAL expected_count)
+ message(STATUS "actual_count='${actual_count}'")
+ message(FATAL_ERROR "error: expected_count=${expected_count} does not match actual_count=${actual_count}: CPackComponents test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error})")
+endif()
+
+
+# dpkg-deb checks for the summary of the packages
+find_program(DPKGDEB_EXECUTABLE dpkg-deb)
+if(DPKGDEB_EXECUTABLE)
+ foreach(_f IN LISTS actual_output)
+
+ # extracts the metadata from the package
+ run_dpkgdeb(dpkg_output
+ FILENAME "${_f}"
+ )
+
+ dpkgdeb_return_specific_metaentry(dpkg_package_name
+ DPKGDEB_OUTPUT "${dpkg_output}"
+ METAENTRY "Package:")
+
+ dpkgdeb_return_specific_metaentry(dpkg_depends
+ DPKGDEB_OUTPUT "${dpkg_output}"
+ METAENTRY "Depends:")
+
+ message(STATUS "package='${dpkg_package_name}', dependencies='${dpkg_depends}'")
+
+ if(dpkg_package_name STREQUAL "mylib-applications")
+ find_program(DPKG_SHLIBDEP_EXECUTABLE dpkg-shlibdeps)
+ if(DPKG_SHLIBDEP_EXECUTABLE)
+ if(NOT dpkg_depends MATCHES "lib")
+ message(SEND_ERROR "dpkg-deb: ${_f}: Incorrect dependencies for package ${dpkg_package_name}: '${dpkg_depends}' does not contain any 'lib'\n")
+ endif()
+ else()
+ message("dpkg-shlibdeps executable not found - skipping dpkg-shlibdeps test")
+ endif()
+
+ # should not contain the default
+ string(FIND "${dpkg_depends}" "depend-default" index_default)
+ if(index_default GREATER "0")
+ message(SEND_ERROR "dpkg-deb: ${_f}: Incorrect dependencies for package ${dpkg_package_name}: '${dpkg_depends}' does contains 'depend-default'\n")
+ endif()
+ elseif(dpkg_package_name STREQUAL "mylib-headers")
+ if(NOT dpkg_depends STREQUAL "mylib-libraries (= 1.0.3), depend-headers")
+ message(SEND_ERROR "dpkg-deb: ${_f}: Incorrect dependencies for package ${dpkg_package_name}: '${dpkg_depends}' != 'mylib-libraries (= 1.0.3), depend-headers'\n")
+ endif()
+ elseif(dpkg_package_name STREQUAL "mylib-libraries")
+ if(NOT dpkg_depends STREQUAL "depend-default")
+ message(SEND_ERROR "dpkg-deb: ${_f}: Incorrect dependencies for package ${dpkg_package_name}: '${dpkg_depends}' != 'depend-default'\n")
+ endif()
+ else()
+ message(SEND_ERROR "dpkg-deb: ${_f}: component name not found: ${dpkg_package_name}\n")
+ endif()
+ endforeach()
+else()
+ message("dpkg-deb executable not found - skipping dpkg-deb test")
+endif()
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description1.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description1.cmake
new file mode 100644
index 0000000..f46a575
--- /dev/null
+++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description1.cmake
@@ -0,0 +1,86 @@
+if(NOT CPackComponentsDEB_SOURCE_DIR)
+ message(FATAL_ERROR "CPackComponentsDEB_SOURCE_DIR not set")
+endif()
+
+include(${CPackComponentsDEB_SOURCE_DIR}/RunCPackVerifyResult.cmake)
+
+
+# expected results
+set(expected_file_mask "${CPackComponentsDEB_BINARY_DIR}/mylib-*_1.0.3_*.deb")
+set(expected_count 3)
+
+
+set(actual_output)
+run_cpack(actual_output
+ CPack_output
+ CPack_error
+ EXPECTED_FILE_MASK "${expected_file_mask}"
+ CONFIG_ARGS ${config_args}
+ CONFIG_VERBOSE ${config_verbose})
+
+
+if(NOT actual_output)
+ message(STATUS "expected_count='${expected_count}'")
+ message(STATUS "expected_file_mask='${expected_file_mask}'")
+ message(STATUS "actual_output_files='${actual_output}'")
+ message(FATAL_ERROR "error: expected_files do not exist: CPackComponentsDEB test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+endif()
+
+list(LENGTH actual_output actual_count)
+if(NOT actual_count EQUAL expected_count)
+ message(STATUS "actual_count='${actual_count}'")
+ message(FATAL_ERROR "error: expected_count=${expected_count} does not match actual_count=${actual_count}: CPackComponents test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error})")
+endif()
+
+
+# dpkg-deb checks for the summary of the packages
+find_program(DPKGDEB_EXECUTABLE dpkg-deb)
+if(DPKGDEB_EXECUTABLE)
+ set(dpkgdeb_output_errors_all "")
+ foreach(_f IN LISTS actual_output)
+
+ # extracts the metadata from the package
+ run_dpkgdeb(dpkg_output
+ FILENAME ${_f}
+ )
+
+ dpkgdeb_return_specific_metaentry(dpkg_package_name
+ DPKGDEB_OUTPUT "${dpkg_output}"
+ METAENTRY "Package:")
+
+ get_package_description("${dpkg_output}" dpkg_description)
+
+ message(STATUS "package='${dpkg_package_name}', description='${dpkg_description}'")
+
+ if(dpkg_package_name STREQUAL "mylib-applications")
+ set(expected_description "main description\n applications_description")
+ if(NOT dpkg_description STREQUAL expected_description)
+ set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all}
+ "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` != `${expected_description}`")
+ endif()
+ elseif(dpkg_package_name STREQUAL "mylib-headers")
+ set(expected_description "main description\n headers_description")
+ if(NOT dpkg_description STREQUAL expected_description)
+ set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all}
+ "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` != `${expected_description}`")
+ endif()
+ elseif(dpkg_package_name STREQUAL "mylib-libraries")
+ set(expected_description "main description")
+ if(NOT dpkg_description STREQUAL expected_description)
+ set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all}
+ "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` != `${expected_description}`")
+ endif()
+ else()
+ set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all}
+ "dpkg-deb: ${_f}: component name not found: ${dpkg_package_name}\n")
+ endif()
+
+ endforeach()
+
+
+ if(NOT dpkgdeb_output_errors_all STREQUAL "")
+ message(FATAL_ERROR "dpkg-deb checks failed:\n${dpkgdeb_output_errors_all}")
+ endif()
+else()
+ message("dpkg-deb executable not found - skipping dpkg-deb test")
+endif()
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description2.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description2.cmake
new file mode 100644
index 0000000..c00921a
--- /dev/null
+++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description2.cmake
@@ -0,0 +1,80 @@
+if(NOT CPackComponentsDEB_SOURCE_DIR)
+ message(FATAL_ERROR "CPackComponentsDEB_SOURCE_DIR not set")
+endif()
+
+include(${CPackComponentsDEB_SOURCE_DIR}/RunCPackVerifyResult.cmake)
+
+
+
+# expected results
+set(expected_file_mask "${CPackComponentsDEB_BINARY_DIR}/mylib-*_1.0.3_*.deb")
+set(expected_count 3)
+
+
+set(actual_output)
+run_cpack(actual_output
+ CPack_output
+ CPack_error
+ EXPECTED_FILE_MASK "${expected_file_mask}"
+ CONFIG_ARGS ${config_args}
+ CONFIG_VERBOSE ${config_verbose})
+
+if(NOT actual_output)
+ message(STATUS "expected_count='${expected_count}'")
+ message(STATUS "expected_file_mask='${expected_file_mask}'")
+ message(STATUS "actual_output_files='${actual_output}'")
+ message(FATAL_ERROR "error: expected_files do not exist: CPackComponentsDEB test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+endif()
+
+list(LENGTH actual_output actual_count)
+message(STATUS "actual_count='${actual_count}'")
+if(NOT actual_count EQUAL expected_count)
+ message(FATAL_ERROR "error: expected_count=${expected_count} does not match actual_count=${actual_count}: CPackComponents test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error})")
+endif()
+
+
+# dpkg-deb checks for the summary of the packages
+find_program(DPKGDEB_EXECUTABLE dpkg-deb)
+if(DPKGDEB_EXECUTABLE)
+ set(dpkgdeb_output_errors_all "")
+ foreach(_f IN LISTS actual_output)
+
+ # extracts the metadata from the package
+ run_dpkgdeb(dpkg_output
+ FILENAME ${_f}
+ )
+
+ dpkgdeb_return_specific_metaentry(dpkg_package_name
+ DPKGDEB_OUTPUT "${dpkg_output}"
+ METAENTRY "Package:")
+
+ get_package_description("${dpkg_output}" dpkg_description)
+
+ message(STATUS "package='${dpkg_package_name}', description='${dpkg_description}'")
+
+ if(dpkg_package_name STREQUAL "mylib-applications" OR dpkg_package_name STREQUAL "mylib-headers")
+ set(expected_description "main description 2")
+ if(NOT dpkg_description STREQUAL expected_description)
+ set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all}
+ "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` != `${expected_description}`")
+ endif()
+ elseif(dpkg_package_name STREQUAL "mylib-libraries")
+ set(expected_description "main description 2\n library description")
+ if(NOT dpkg_description STREQUAL expected_description)
+ set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all}
+ "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` != `${expected_description}`")
+ endif()
+ else()
+ set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all}
+ "dpkg-deb: ${_f}: component name not found: ${dpkg_package_name}\n")
+ endif()
+
+ endforeach()
+
+
+ if(NOT dpkgdeb_output_errors_all STREQUAL "")
+ message(FATAL_ERROR "dpkg-deb checks failed:\n${dpkgdeb_output_errors_all}")
+ endif()
+else()
+ message("dpkg-deb executable not found - skipping dpkg-deb test")
+endif()
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-lintian-dpkgdeb-checks.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-lintian-dpkgdeb-checks.cmake
new file mode 100644
index 0000000..7cfbb16
--- /dev/null
+++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-lintian-dpkgdeb-checks.cmake
@@ -0,0 +1,78 @@
+if(NOT CPackComponentsDEB_SOURCE_DIR)
+ message(FATAL_ERROR "CPackComponentsDEB_SOURCE_DIR not set")
+endif()
+
+include(${CPackComponentsDEB_SOURCE_DIR}/RunCPackVerifyResult.cmake)
+
+# TODO: currently debian doesn't produce lower cased names
+set(expected_file_mask "${CPackComponentsDEB_BINARY_DIR}/mylib-*_1.0.3_*.deb")
+set(expected_count 3)
+
+
+set(actual_output)
+run_cpack(actual_output
+ CPack_output
+ CPack_error
+ EXPECTED_FILE_MASK "${expected_file_mask}"
+ CONFIG_ARGS "${config_args}"
+ CONFIG_VERBOSE "${config_verbose}")
+
+if(NOT actual_output)
+ message(STATUS "expected_count='${expected_count}'")
+ message(STATUS "expected_file_mask='${expected_file_mask}'")
+ message(STATUS "actual_output_files='${actual_output}'")
+ message(FATAL_ERROR "error: expected_files do not exist: CPackComponentsDEB test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+endif()
+
+list(LENGTH actual_output actual_count)
+if(NOT actual_count EQUAL expected_count)
+ message(STATUS "actual_count='${actual_count}'")
+ message(FATAL_ERROR "error: expected_count=${expected_count} does not match actual_count=${actual_count}: CPackComponents test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error})")
+endif()
+
+
+# lintian checks
+find_program(LINTIAN_EXECUTABLE lintian)
+if(LINTIAN_EXECUTABLE)
+ set(lintian_output_errors_all "")
+ foreach(_f IN LISTS actual_output)
+ set(STRINGS_TO_AVOID "E:([^\r\n]*)control-file-has-bad-permissions" "E:([^\r\n]*)md5sums-lists-nonexistent-file")
+ lintian_check_specific_errors(lintian_output_errors
+ FILENAME "${_f}"
+ ERROR_REGEX_STRINGS "${STRINGS_TO_AVOID}")
+
+ string(APPEND lintian_output_errors_all "${lintian_output_errors}")
+ endforeach()
+
+ if(NOT lintian_output_errors_all STREQUAL "")
+ message(FATAL_ERROR "Lintian checks failed:\n${lintian_output_errors_all}")
+ endif()
+else()
+ message("lintian executable not found - skipping lintian test")
+endif()
+
+# dpkg-deb checks
+find_program(DPKGDEB_EXECUTABLE dpkg-deb)
+if(DPKGDEB_EXECUTABLE)
+ set(dpkgdeb_output_errors_all "")
+ foreach(_f IN LISTS actual_output)
+ run_dpkgdeb(dpkg_output
+ FILENAME "${_f}"
+ )
+
+ dpkgdeb_return_specific_metaentry(dpkgentry
+ DPKGDEB_OUTPUT "${dpkg_output}"
+ METAENTRY "Maintainer:")
+
+ if(NOT dpkgentry STREQUAL "None")
+ set(dpkgdeb_output_errors_all "${dpkgdeb_output_errors_all}"
+ "dpkg-deb: ${_f}: Incorrect value for Maintainer: ${dpkgentry} != None\n")
+ endif()
+ endforeach()
+
+ if(NOT dpkgdeb_output_errors_all STREQUAL "")
+ message(FATAL_ERROR "dpkg-deb checks failed:\n${dpkgdeb_output_errors_all}")
+ endif()
+else()
+ message("dpkg-deb executable not found - skipping dpkg-deb test")
+endif()
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-shlibdeps1.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-shlibdeps1.cmake
new file mode 100644
index 0000000..6eff3db
--- /dev/null
+++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-shlibdeps1.cmake
@@ -0,0 +1,75 @@
+if(NOT CPackComponentsDEB_SOURCE_DIR)
+ message(FATAL_ERROR "CPackComponentsDEB_SOURCE_DIR not set")
+endif()
+
+include(${CPackComponentsDEB_SOURCE_DIR}/RunCPackVerifyResult.cmake)
+
+
+
+# requirements
+
+# debian now produces lower case names
+set(expected_file_mask "${CPackComponentsDEB_BINARY_DIR}/mylib-*_1.0.3_*.deb")
+set(expected_count 3)
+
+
+set(actual_output)
+run_cpack(actual_output
+ CPack_output
+ CPack_error
+ EXPECTED_FILE_MASK "${expected_file_mask}"
+ CONFIG_ARGS ${config_args}
+ CONFIG_VERBOSE ${config_verbose})
+
+message(STATUS "expected_count='${expected_count}'")
+message(STATUS "expected_file_mask='${expected_file_mask}'")
+message(STATUS "actual_output_files='${actual_output}'")
+
+if(NOT actual_output)
+ message(FATAL_ERROR "error: expected_files do not exist: CPackComponentsDEB test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+endif()
+
+list(LENGTH actual_output actual_count)
+message(STATUS "actual_count='${actual_count}'")
+if(NOT actual_count EQUAL expected_count)
+ message(FATAL_ERROR "error: expected_count=${expected_count} does not match actual_count=${actual_count}: CPackComponents test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error})")
+endif()
+
+
+# dpkg-deb checks for the summary of the packages
+find_program(DPKGDEB_EXECUTABLE dpkg-deb)
+if(DPKGDEB_EXECUTABLE)
+ set(dpkgdeb_output_errors_all "")
+ foreach(_f IN LISTS actual_output)
+
+ # extracts the metadata from the package
+ run_dpkgdeb(dpkg_output
+ FILENAME ${_f}
+ )
+
+ dpkgdeb_return_specific_metaentry(dpkg_package_name
+ DPKGDEB_OUTPUT "${dpkg_output}"
+ METAENTRY "Package:")
+
+ message(STATUS "package='${dpkg_package_name}'")
+
+ if(dpkg_package_name STREQUAL "mylib-applications")
+ # pass
+ elseif(dpkg_package_name STREQUAL "mylib-headers")
+ # pass
+ elseif(dpkg_package_name STREQUAL "mylib-libraries")
+ # pass
+ else()
+ set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all}
+ "dpkg-deb: ${_f}: component name not found: ${dpkg_package_name}\n")
+ endif()
+
+ endforeach()
+
+
+ if(NOT dpkgdeb_output_errors_all STREQUAL "")
+ message(FATAL_ERROR "dpkg-deb checks failed:\n${dpkgdeb_output_errors_all}")
+ endif()
+else()
+ message("dpkg-deb executable not found - skipping dpkg-deb test")
+endif()
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-source.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-source.cmake
new file mode 100644
index 0000000..3454dca
--- /dev/null
+++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-source.cmake
@@ -0,0 +1,68 @@
+if(NOT CPackComponentsDEB_SOURCE_DIR)
+ message(FATAL_ERROR "CPackComponentsDEB_SOURCE_DIR not set")
+endif()
+
+include(${CPackComponentsDEB_SOURCE_DIR}/RunCPackVerifyResult.cmake)
+
+
+# expected results
+set(expected_file_mask "${CPackComponentsDEB_BINARY_DIR}/mylib-*_1.0.3_*.deb")
+set(expected_count 3)
+
+set(config_verbose -V)
+set(actual_output)
+run_cpack(actual_output
+ CPack_output
+ CPack_error
+ EXPECTED_FILE_MASK "${expected_file_mask}"
+ CONFIG_ARGS ${config_args}
+ CONFIG_VERBOSE ${config_verbose})
+
+
+if(NOT actual_output)
+ message(STATUS "expected_count='${expected_count}'")
+ message(STATUS "expected_file_mask='${expected_file_mask}'")
+ message(STATUS "actual_output_files='${actual_output}'")
+ message(FATAL_ERROR "error: expected_files do not exist: CPackComponentsDEB test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+endif()
+
+list(LENGTH actual_output actual_count)
+if(NOT actual_count EQUAL expected_count)
+ message(STATUS "actual_count='${actual_count}'")
+ message(FATAL_ERROR "error: expected_count=${expected_count} does not match actual_count=${actual_count}: CPackComponents test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error})")
+endif()
+
+
+# dpkg-deb checks for the summary of the packages
+find_program(DPKGDEB_EXECUTABLE dpkg-deb)
+if(DPKGDEB_EXECUTABLE)
+ foreach(_f IN LISTS actual_output)
+
+ # extracts the metadata from the package
+ run_dpkgdeb(dpkg_output
+ FILENAME "${_f}"
+ )
+
+ dpkgdeb_return_specific_metaentry(dpkg_package_name
+ DPKGDEB_OUTPUT "${dpkg_output}"
+ METAENTRY "Package:")
+
+ dpkgdeb_return_specific_metaentry(dpkg_package_source
+ DPKGDEB_OUTPUT "${dpkg_output}"
+ METAENTRY "Source:")
+
+ message(STATUS "package='${_f}', source='${dpkg_package_source}'")
+
+ if(NOT dpkg_package_name STREQUAL "mylib-applications")
+ if(NOT dpkg_package_source STREQUAL "test-source")
+ message(SEND_ERROR "dpkg-deb: ${_f}: Incorrect source for package '${dpkg_package_name}': '${dpkg_package_source}' instead of 'test-source'\n")
+ endif()
+ else()
+ if(NOT dpkg_package_source STREQUAL "test-other-source")
+ message(SEND_ERROR "dpkg-deb: ${_f}: Incorrect source for package '${dpkg_package_name}': '${dpkg_package_source}' instead of 'test-other-source'\n")
+ endif()
+ endif()
+ endforeach()
+else()
+ message("dpkg-deb executable not found - skipping dpkg-deb test")
+endif()
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-compression.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-compression.cmake
new file mode 100644
index 0000000..764fe9d
--- /dev/null
+++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult-compression.cmake
@@ -0,0 +1,48 @@
+if(NOT CPackComponentsDEB_SOURCE_DIR)
+ message(FATAL_ERROR "CPackComponentsDEB_SOURCE_DIR not set")
+endif()
+
+include(${CPackComponentsDEB_SOURCE_DIR}/RunCPackVerifyResult.cmake)
+
+# TODO: currently debian doesn't produce lower cased names
+set(expected_file_mask "${CPackComponentsDEB_BINARY_DIR}/mylib_1.0.3_*.deb")
+set(expected_count 1)
+
+set(actual_output)
+run_cpack(actual_output
+ CPack_output
+ CPack_error
+ EXPECTED_FILE_MASK "${expected_file_mask}"
+ CONFIG_ARGS "${config_args}"
+ CONFIG_VERBOSE "${config_verbose}")
+
+if(NOT actual_output)
+ message(STATUS "expected_count='${expected_count}'")
+ message(STATUS "expected_file_mask='${expected_file_mask}'")
+ message(STATUS "actual_output_files='${actual_output}'")
+ message(FATAL_ERROR "error: expected_files do not exist: CPackComponentsDEB test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+endif()
+
+list(LENGTH actual_output actual_count)
+if(NOT actual_count EQUAL expected_count)
+ message(STATUS "actual_count='${actual_count}'")
+ message(FATAL_ERROR "error: expected_count=${expected_count} does not match actual_count=${actual_count}: CPackComponents test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error})")
+endif()
+
+
+# dpkg-deb checks
+find_program(DPKGDEB_EXECUTABLE dpkg-deb)
+if(DPKGDEB_EXECUTABLE)
+ foreach(_f IN LISTS actual_output)
+ run_dpkgdeb(dpkg_output
+ FILENAME "${_f}"
+ )
+
+ # message(FATAL_ERROR "output = '${dpkg_output}'")
+ if(dpkg_output STREQUAL "")
+ message(SEND_ERROR "dpkg-deb: ${_f}: empty content returned by dpkg-deb")
+ endif()
+ endforeach()
+else()
+ message("dpkg-deb executable not found - skipping dpkg-deb test")
+endif()
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-shlibdeps-with-private-lib-failure.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-shlibdeps-with-private-lib-failure.cmake
new file mode 100644
index 0000000..962a1fb
--- /dev/null
+++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult-shlibdeps-with-private-lib-failure.cmake
@@ -0,0 +1,19 @@
+if(NOT CPackComponentsDEB_SOURCE_DIR)
+ message(FATAL_ERROR "CPackComponentsDEB_SOURCE_DIR not set")
+endif()
+
+include(${CPackComponentsDEB_SOURCE_DIR}/RunCPackVerifyResult.cmake)
+
+
+set(actual_output)
+run_cpack(actual_output
+ CPack_output
+ CPack_error
+ EXPECT_FAILURE
+ CONFIG_ARGS ${config_args}
+ CONFIG_VERBOSE ${config_verbose})
+
+string(REGEX MATCH "dpkg-shlibdeps: error: (cannot|couldn't) find[ \n\t]+library[ \n\t]+libmyprivatelib.so.1[ \n\t]+needed[ \n\t]+by[ \n\t]+./usr/bin/mylibapp3" expected_error ${CPack_error})
+if(NOT expected_error)
+ message(FATAL_ERROR "Did not get the expected error-message!")
+endif()
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-shlibdeps-with-private-lib-success.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-shlibdeps-with-private-lib-success.cmake
new file mode 100644
index 0000000..6eff3db
--- /dev/null
+++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult-shlibdeps-with-private-lib-success.cmake
@@ -0,0 +1,75 @@
+if(NOT CPackComponentsDEB_SOURCE_DIR)
+ message(FATAL_ERROR "CPackComponentsDEB_SOURCE_DIR not set")
+endif()
+
+include(${CPackComponentsDEB_SOURCE_DIR}/RunCPackVerifyResult.cmake)
+
+
+
+# requirements
+
+# debian now produces lower case names
+set(expected_file_mask "${CPackComponentsDEB_BINARY_DIR}/mylib-*_1.0.3_*.deb")
+set(expected_count 3)
+
+
+set(actual_output)
+run_cpack(actual_output
+ CPack_output
+ CPack_error
+ EXPECTED_FILE_MASK "${expected_file_mask}"
+ CONFIG_ARGS ${config_args}
+ CONFIG_VERBOSE ${config_verbose})
+
+message(STATUS "expected_count='${expected_count}'")
+message(STATUS "expected_file_mask='${expected_file_mask}'")
+message(STATUS "actual_output_files='${actual_output}'")
+
+if(NOT actual_output)
+ message(FATAL_ERROR "error: expected_files do not exist: CPackComponentsDEB test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+endif()
+
+list(LENGTH actual_output actual_count)
+message(STATUS "actual_count='${actual_count}'")
+if(NOT actual_count EQUAL expected_count)
+ message(FATAL_ERROR "error: expected_count=${expected_count} does not match actual_count=${actual_count}: CPackComponents test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error})")
+endif()
+
+
+# dpkg-deb checks for the summary of the packages
+find_program(DPKGDEB_EXECUTABLE dpkg-deb)
+if(DPKGDEB_EXECUTABLE)
+ set(dpkgdeb_output_errors_all "")
+ foreach(_f IN LISTS actual_output)
+
+ # extracts the metadata from the package
+ run_dpkgdeb(dpkg_output
+ FILENAME ${_f}
+ )
+
+ dpkgdeb_return_specific_metaentry(dpkg_package_name
+ DPKGDEB_OUTPUT "${dpkg_output}"
+ METAENTRY "Package:")
+
+ message(STATUS "package='${dpkg_package_name}'")
+
+ if(dpkg_package_name STREQUAL "mylib-applications")
+ # pass
+ elseif(dpkg_package_name STREQUAL "mylib-headers")
+ # pass
+ elseif(dpkg_package_name STREQUAL "mylib-libraries")
+ # pass
+ else()
+ set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all}
+ "dpkg-deb: ${_f}: component name not found: ${dpkg_package_name}\n")
+ endif()
+
+ endforeach()
+
+
+ if(NOT dpkgdeb_output_errors_all STREQUAL "")
+ message(FATAL_ERROR "dpkg-deb checks failed:\n${dpkgdeb_output_errors_all}")
+ endif()
+else()
+ message("dpkg-deb executable not found - skipping dpkg-deb test")
+endif()
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult.cmake
new file mode 100644
index 0000000..8f7c198
--- /dev/null
+++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult.cmake
@@ -0,0 +1,237 @@
+# prevent older policies from interfearing with this script
+cmake_policy(PUSH)
+cmake_policy(VERSION ${CMAKE_VERSION})
+
+
+include(CMakeParseArguments)
+
+message(STATUS "=============================================================================")
+message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+message(STATUS "")
+
+if(NOT CPackComponentsDEB_BINARY_DIR)
+ message(FATAL_ERROR "CPackComponentsDEB_BINARY_DIR not set")
+endif()
+
+if(NOT CPackGen)
+ message(FATAL_ERROR "CPackGen not set")
+endif()
+
+message("CMAKE_CPACK_COMMAND = ${CMAKE_CPACK_COMMAND}")
+if(NOT CMAKE_CPACK_COMMAND)
+ message(FATAL_ERROR "CMAKE_CPACK_COMMAND not set")
+endif()
+
+if(NOT CPackDEBConfiguration)
+ message(FATAL_ERROR "CPackDEBConfiguration not set")
+endif()
+
+# run cpack with some options and returns the list of files generated
+# -output_expected_file: list of files that match the pattern
+function(run_cpack output_expected_file CPack_output_parent CPack_error_parent)
+ set(options "EXPECT_FAILURE")
+ set(oneValueArgs "EXPECTED_FILE_MASK" "CONFIG_VERBOSE")
+ set(multiValueArgs "CONFIG_ARGS")
+ cmake_parse_arguments(run_cpack_deb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+
+ # clean-up previously CPack generated files
+ if(${run_cpack_deb_EXPECTED_FILE_MASK})
+ file(GLOB expected_file "${${run_cpack_deb_EXPECTED_FILE_MASK}}")
+ if (expected_file)
+ file(REMOVE "${expected_file}")
+ endif()
+ endif()
+
+ message("config_args = ${run_cpack_deb_CONFIG_ARGS}")
+ message("config_verbose = ${run_cpack_deb_CONFIG_VERBOSE}")
+
+ set(_backup_lang "$ENV{LANG}")
+ set(_backup_lc_all "$ENV{LC_ALL}")
+ set(ENV{LANG} "C")
+ set(ENV{LC_ALL} "C")
+ execute_process(COMMAND ${CMAKE_CPACK_COMMAND} ${run_cpack_deb_CONFIG_VERBOSE} -G ${CPackGen} -C "${CONFIG}" ${run_cpack_deb_CONFIG_ARGS}
+ RESULT_VARIABLE CPack_result
+ OUTPUT_VARIABLE CPack_output
+ ERROR_VARIABLE CPack_error
+ WORKING_DIRECTORY ${CPackComponentsDEB_BINARY_DIR})
+ set(ENV{LANG} "${_backup_lang}")
+ set(ENV{LC_ALL} "${_backup_lc_all}")
+
+ set(${CPack_output_parent} ${CPack_output} PARENT_SCOPE)
+ set(${CPack_error_parent} ${CPack_error} PARENT_SCOPE)
+
+ if (CPack_result AND NOT run_cpack_deb_EXPECT_FAILURE)
+ message(FATAL_ERROR "error: CPack execution went wrong!, CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+ elseif (NOT CPack_result AND run_cpack_deb_EXPECT_FAILURE)
+ message(FATAL_ERROR "error: CPack execution succeeded although failure was expected!, CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+ else ()
+ message(STATUS "CPack_output=${CPack_output}")
+ message(STATUS "CPack_error=${CPack_error}")
+ endif()
+
+
+ if(run_cpack_deb_EXPECTED_FILE_MASK)
+ file(GLOB _output_expected_file "${run_cpack_deb_EXPECTED_FILE_MASK}")
+ set(${output_expected_file} "${_output_expected_file}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+
+
+# This function runs lintian on a .deb and returns its output
+function(run_lintian lintian_output)
+ set(${lintian_output} "" PARENT_SCOPE)
+
+ find_program(LINTIAN_EXECUTABLE lintian)
+ if(LINTIAN_EXECUTABLE)
+ set(options "")
+ set(oneValueArgs "FILENAME")
+ set(multiValueArgs "")
+ cmake_parse_arguments(run_lintian_deb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+
+ if(NOT run_lintian_deb_FILENAME)
+ message(FATAL_ERROR "error: run_lintian needs FILENAME to be set")
+ endif()
+
+ # run dpkg-deb
+ execute_process(COMMAND ${LINTIAN_EXECUTABLE} ${run_lintian_deb_FILENAME}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE LINTIAN_OUTPUT
+ RESULT_VARIABLE LINTIAN_RESULT
+ ERROR_VARIABLE LINTIAN_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE )
+
+ set(${lintian_output} "${LINTIAN_OUTPUT}" PARENT_SCOPE)
+ else()
+ message(FATAL_ERROR "run_lintian called without lintian executable being present")
+ endif()
+endfunction()
+
+
+# Higher level lintian check that parse the output for errors and required strings
+function(lintian_check_specific_errors output_errors)
+ set(${output_errors} "" PARENT_SCOPE)
+ set(ERROR_ACC)
+
+ set(options "")
+ set(oneValueArgs "FILENAME")
+ set(multiValueArgs "ERROR_REGEX_STRINGS")
+ cmake_parse_arguments(lintian_check_specific_errors_deb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+ set(lintian_output)
+ run_lintian(lintian_output FILENAME ${lintian_check_specific_errors_deb_FILENAME})
+
+ message(STATUS "Lintian output is ''${lintian_output}'")
+
+ # regex to avoid
+ foreach(_s IN LISTS lintian_check_specific_errors_deb_ERROR_REGEX_STRINGS)
+
+ if(_s STREQUAL "")
+ continue()
+ endif()
+
+ string(REGEX MATCHALL "${_s}" "_TMP_CHECK_ERROR" "${lintian_output}")
+
+ if(NOT _TMP_CHECK_ERROR STREQUAL "")
+ string(APPEND ERROR_ACC "\nlintian: ${_f}: output contains an undesirable regex:\n\t${_TMP_CHECK_ERROR}")
+ endif()
+ endforeach()
+
+ set(${output_errors} "${ERROR_ACC}" PARENT_SCOPE)
+endfunction()
+
+
+
+
+# This function runs dpkg-deb on a .deb and returns its output
+# the default behaviour it to run "--info" on the specified Debian package
+# ACTION is one of the option accepted by dpkg-deb
+function(run_dpkgdeb dpkg_deb_output)
+ set(${dpkg_deb_output} "" PARENT_SCOPE)
+
+ find_program(DPKGDEB_EXECUTABLE dpkg-deb)
+ if(DPKGDEB_EXECUTABLE)
+
+ set(options "")
+ set(oneValueArgs "FILENAME" "ACTION")
+ set(multiValueArgs "")
+ cmake_parse_arguments(run_dpkgdeb_deb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+
+ if(NOT run_dpkgdeb_deb_FILENAME)
+ message(FATAL_ERROR "error: run_dpkgdeb needs FILENAME to be set")
+ endif()
+
+ if(NOT run_dpkgdeb_deb_ACTION)
+ set(run_dpkgdeb_deb_ACTION "--info")
+ endif()
+
+ # run dpkg-deb
+ execute_process(COMMAND ${DPKGDEB_EXECUTABLE} ${run_dpkgdeb_deb_ACTION} ${run_dpkgdeb_deb_FILENAME}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE DPKGDEB_OUTPUT
+ RESULT_VARIABLE DPKGDEB_RESULT
+ ERROR_VARIABLE DPKGDEB_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE )
+
+ if(NOT DPKGDEB_RESULT EQUAL "0")
+ message(FATAL_ERROR "Error '${DPKGDEB_RESULT}' returned by dpkg-deb: '${DPKGDEB_ERROR}'")
+ endif()
+
+ set(${dpkg_deb_output} "${DPKGDEB_OUTPUT}" PARENT_SCOPE)
+ else()
+ message(FATAL_ERROR "run_dpkgdeb called without dpkg-deb executable being present")
+ endif()
+endfunction()
+
+
+# returns a particular line of the metadata of the .deb, for checking
+# a previous call to run_dpkgdeb should provide the DPKGDEB_OUTPUT entry.
+function(dpkgdeb_return_specific_metaentry output)
+ set(${output} "" PARENT_SCOPE)
+
+ set(options "")
+ set(oneValueArgs "DPKGDEB_OUTPUT" "METAENTRY")
+ set(multiValueArgs "")
+ cmake_parse_arguments(dpkgdeb_return_specific_metaentry_deb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+ if(NOT dpkgdeb_return_specific_metaentry_deb_METAENTRY)
+ message(FATAL_ERROR "error: dpkgdeb_return_specific_metaentry needs METAENTRY to be set")
+ endif()
+
+ string(REGEX MATCH "${dpkgdeb_return_specific_metaentry_deb_METAENTRY}([^\r\n]*)" _TMP_STR "${dpkgdeb_return_specific_metaentry_deb_DPKGDEB_OUTPUT}")
+ #message("################ _TMP_STR = ${CMAKE_MATCH_1} ##################")
+ if(NOT "${CMAKE_MATCH_1}" STREQUAL "")
+ string(STRIP "${CMAKE_MATCH_1}" _TMP_STR)
+ set(${output} "${_TMP_STR}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(get_package_description DPKG_OUTPUT RESULT_VAR)
+ string(UUID uuid NAMESPACE 00000000-0000-0000-0000-000000000000 TYPE SHA1)
+ string(REPLACE ";" "${uuid}" DPKG_OUTPUT "${DPKG_OUTPUT}")
+ string(REPLACE "\n" ";" DPKG_OUTPUT "${DPKG_OUTPUT}")
+
+ unset(_actual_description)
+ set(_parse_description FALSE)
+ foreach(_line IN LISTS DPKG_OUTPUT)
+ if(_line MATCHES " Description:.*")
+ set(_parse_description TRUE)
+ string(REPLACE " Description: " "" _line "${_line}")
+ list(APPEND _actual_description "${_line}")
+ elseif(_parse_description)
+ if(_line MATCHES " [A-Z][A-Za-z\-]+: .*")
+ set(_parse_description FALSE)
+ else()
+ list(APPEND _actual_description "${_line}")
+ endif()
+ endif()
+ endforeach()
+ list(JOIN _actual_description "\n" _actual_description)
+
+ set(${RESULT_VAR} "${_actual_description}" PARENT_SCOPE)
+endfunction()
+
+cmake_policy(POP)
diff --git a/Tests/CPackComponentsDEB/license.txt b/Tests/CPackComponentsDEB/license.txt
new file mode 100644
index 0000000..d829d93
--- /dev/null
+++ b/Tests/CPackComponentsDEB/license.txt
@@ -0,0 +1,3 @@
+LICENSE
+-------
+This is an installer created using CPack (https://cmake.org). No license provided.
diff --git a/Tests/CPackComponentsDEB/mylib.cpp b/Tests/CPackComponentsDEB/mylib.cpp
new file mode 100644
index 0000000..8d63071
--- /dev/null
+++ b/Tests/CPackComponentsDEB/mylib.cpp
@@ -0,0 +1,8 @@
+#include "mylib.h"
+
+#include "stdio.h"
+
+void mylib_function()
+{
+ printf("This is mylib");
+}
diff --git a/Tests/CPackComponentsDEB/mylib.h b/Tests/CPackComponentsDEB/mylib.h
new file mode 100644
index 0000000..5d0a822
--- /dev/null
+++ b/Tests/CPackComponentsDEB/mylib.h
@@ -0,0 +1 @@
+void mylib_function();
diff --git a/Tests/CPackComponentsDEB/mylibapp.cpp b/Tests/CPackComponentsDEB/mylibapp.cpp
new file mode 100644
index 0000000..bb45831
--- /dev/null
+++ b/Tests/CPackComponentsDEB/mylibapp.cpp
@@ -0,0 +1,19 @@
+#ifndef SHLIBDEPS_PRIVATE
+
+# include "mylib.h"
+
+int main()
+{
+ mylib_function();
+}
+
+#else
+
+# include "shlibdeps-with-private-lib/myprivatelib.h"
+
+int main()
+{
+ myprivatelib_function();
+}
+
+#endif
diff --git a/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/CMakeLists.txt b/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/CMakeLists.txt
new file mode 100644
index 0000000..c7ef386
--- /dev/null
+++ b/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_library(myprivatelib SHARED myprivatelib.cpp)
+set_target_properties( myprivatelib PROPERTIES
+ VERSION 1.2.3
+ SOVERSION 1
+)
diff --git a/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/myprivatelib.cpp b/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/myprivatelib.cpp
new file mode 100644
index 0000000..67110e6
--- /dev/null
+++ b/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/myprivatelib.cpp
@@ -0,0 +1,8 @@
+#include "myprivatelib.h"
+
+#include "stdio.h"
+
+void myprivatelib_function()
+{
+ printf("This is myprivatelib");
+}
diff --git a/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/myprivatelib.h b/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/myprivatelib.h
new file mode 100644
index 0000000..7e4a42d
--- /dev/null
+++ b/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/myprivatelib.h
@@ -0,0 +1 @@
+void myprivatelib_function();
diff --git a/Tests/CPackComponentsForAll/CMakeLists.txt b/Tests/CPackComponentsForAll/CMakeLists.txt
new file mode 100644
index 0000000..e49138a
--- /dev/null
+++ b/Tests/CPackComponentsForAll/CMakeLists.txt
@@ -0,0 +1,194 @@
+# CPack Example: User-selectable Installation Components
+#
+# In this example, we have a simple library (mylib) with an example
+# application (mylibapp). We create a binary installer (a CPack Generator)
+# which supports CPack components.
+#
+# Depending on the CPack generator and on some CPACK_xxx var values
+# the generator may produce a single (NSIS, PackageMaker)
+# or several package files (Archive Generators, RPM, DEB)
+cmake_minimum_required(VERSION 2.8.3.20101130 FATAL_ERROR)
+project(CPackComponentsForAll)
+
+# Use GNUInstallDirs in order to enforce lib64 if needed
+include(GNUInstallDirs)
+
+# Create the mylib library
+add_library(mylib mylib.cpp)
+
+# Create the mylibapp application
+add_executable(mylibapp mylibapp.cpp)
+target_link_libraries(mylibapp mylib)
+
+# Duplicate of mylibapp application
+# which won't be put in any component (?mistake?)
+add_executable(mylibapp2 mylibapp.cpp)
+target_link_libraries(mylibapp2 mylib)
+
+# Create installation targets. Note that we put each kind of file
+# into a different component via COMPONENT. These components will
+# be used to create the installation components.
+install(TARGETS mylib
+ ARCHIVE
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ COMPONENT libraries)
+install(TARGETS mylibapp
+ RUNTIME
+ DESTINATION bin
+ COMPONENT applications)
+
+# This application does not belong to any component
+# thus (as of cmake 2.8.2) it will be left "uninstalled"
+# by a component-aware installer unless a
+# CPACK_MONOLITHIC_INSTALL=1 is set (at cmake time).
+install(TARGETS mylibapp2
+ RUNTIME
+ DESTINATION bin/@in@_@path@@with\\@and\\@/\@in_path\@) # test @ char in path
+
+install(FILES mylib.h
+ DESTINATION include
+ COMPONENT headers)
+
+if("${CPACK_GENERATOR}" MATCHES "RPM")
+ ############## test man pages
+ install(FILES mylib
+ DESTINATION share/man/mylib/man3/mylib.1)
+ install(FILES mylib
+ DESTINATION share/man/mylib/man3/mylib.1 RENAME mylib2)
+
+ ############## test symlinks
+ # Package symbolic links
+ install(DIRECTORY DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two/depth_three COMPONENT libraries)
+ install(DIRECTORY DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_two/depth_two/different_relocatable/bar COMPONENT libraries)
+ install(DIRECTORY DESTINATION other_relocatable/depth_two COMPONENT libraries)
+ install(DIRECTORY DESTINATION non_relocatable/depth_two COMPONENT libraries)
+ # test symbolic links to same dir
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink depth_three symlink_samedir_path)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_samedir_path DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two COMPONENT libraries)
+ # test symbolic links to same dir with current dir ./ prefix
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ./depth_three symlink_samedir_path_current_dir)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_samedir_path_current_dir DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two COMPONENT libraries)
+ # test symbolic links to same dir with longer relative path
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ../../../${CMAKE_INSTALL_LIBDIR}/.././${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/./depth_two/depth_three symlink_samedir_path_longer)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_samedir_path_longer DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two COMPONENT libraries)
+ # test symbolic links to sub dir
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ../../${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two/depth_three symlink_subdir_path)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_subdir_path DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one COMPONENT libraries)
+ # test symbolic links to parent dir
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink .././../../../${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/./depth_two symlink_parentdir_path)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_parentdir_path DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two/depth_three COMPONENT libraries)
+ # test symbolic link to another relocatable path
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink .././.././../other_relocatable/./depth_two symlink_other_relocatable_path)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_other_relocatable_path DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_two/depth_two COMPONENT libraries)
+ # test symbolic link to non relocatable path
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink .././../../non_relocatable/./depth_two symlink_to_non_relocatable_path)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_to_non_relocatable_path DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_two/depth_two COMPONENT libraries)
+ # test symbolic link from non relocatable path
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink .././../${CMAKE_INSTALL_LIBDIR}/inside_relocatable_two/depth_two symlink_from_non_relocatable_path)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_from_non_relocatable_path DESTINATION non_relocatable/depth_two COMPONENT libraries)
+ # test symbolic link relocatable path to its relocatable subpath
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ../../inside_relocatable_two/depth_two/different_relocatable/bar symlink_relocatable_subpath)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_relocatable_subpath DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two COMPONENT libraries)
+ # test symbolic link to location outside package
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ./outside_package symlink_outside_package)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_outside_package DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two COMPONENT libraries)
+ # test symbolic link to location outside wdr (packaging directory)
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink /outside_package_wdr symlink_outside_wdr)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_outside_wdr DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two COMPONENT libraries)
+endif()
+
+# CPack boilerplate for this project
+set(CPACK_PACKAGE_NAME "MyLib")
+set(CPACK_PACKAGE_CONTACT "None")
+set(CPACK_PACKAGE_VENDOR "CMake.org")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MyLib - CPack Component Installation Example")
+set(CPACK_PACKAGE_VERSION "1.0.2")
+set(CPACK_PACKAGE_VERSION_MAJOR "1")
+set(CPACK_PACKAGE_VERSION_MINOR "0")
+set(CPACK_PACKAGE_VERSION_PATCH "2")
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "CPack Component Example")
+set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/license.txt)
+
+# Tell CPack all of the components to install. The "ALL"
+# refers to the fact that this is the set of components that
+# will be included when CPack is instructed to put everything
+# into the binary installer (the default behavior).
+set(CPACK_COMPONENTS_ALL applications libraries headers Unspecified)
+
+# Set the displayed names for each of the components to install.
+# These will be displayed in the list of components inside the installer.
+set(CPACK_COMPONENT_APPLICATIONS_DISPLAY_NAME "MyLib Application")
+set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries")
+set(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C++ Headers")
+
+# Provide descriptions for each of the components to install.
+# When the user hovers the mouse over the name of a component,
+# the description will be shown in the "Description" box in the
+# installer. If no descriptions are provided, the "Description"
+# box will be removed.
+set(CPACK_COMPONENT_APPLICATIONS_DESCRIPTION
+ "An extremely useful application that makes use of MyLib")
+set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION
+ "Static libraries used to build programs with MyLib")
+set(CPACK_COMPONENT_HEADERS_DESCRIPTION
+ "C/C++ header files for use with MyLib")
+
+# Put the components into two different groups: "Runtime" and "Development"
+set(CPACK_COMPONENT_APPLICATIONS_GROUP "Runtime")
+set(CPACK_COMPONENT_LIBRARIES_GROUP "Development")
+set(CPACK_COMPONENT_HEADERS_GROUP "Development")
+
+# Expand the "Development" group by default, since we have so few components.
+# Also, provide this group with a description.
+set(CPACK_COMPONENT_GROUP_DEVELOPMENT_EXPANDED ON)
+set(CPACK_COMPONENT_GROUP_DEVELOPMENT_DESCRIPTION
+ "All of the tools you'll ever need to develop software")
+
+# It doesn't make sense to install the headers without the libraries
+# (because you could never use the headers!), so make the headers component
+# depend on the libraries component.
+set(CPACK_COMPONENT_HEADERS_DEPENDS libraries)
+
+# Create two installation types with pre-selected components.
+# The "Developer" installation has just the library and headers,
+# while the "Full" installation has everything.
+set(CPACK_ALL_INSTALL_TYPES Full Developer)
+set(CPACK_INSTALL_TYPE_FULL_DISPLAY_NAME "Everything")
+set(CPACK_COMPONENT_LIBRARIES_INSTALL_TYPES Developer Full)
+set(CPACK_COMPONENT_HEADERS_INSTALL_TYPES Developer Full)
+set(CPACK_COMPONENT_APPLICATIONS_INSTALL_TYPES Full)
+
+# set CPACK_RPM_RELOCATION_PATHS here as GNUInstallDirs script
+# can not be used in CPack scripts due to CMAKE_SIZEOF_VOID_P
+# variable not being set
+set(CPACK_RPM_RELOCATION_PATHS "${CMAKE_INSTALL_INCLUDEDIR}"
+ "${CMAKE_INSTALL_LIBDIR}" "${CMAKE_INSTALL_BINDIR}" "other_relocatable"
+ "${CMAKE_INSTALL_LIBDIR}/inside_relocatable_two/depth_two/different_relocatable")
+
+# set CPACK_DEBIAN_FILE_NAME to use default package name format
+set(CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT")
+
+# set some tags for NuGet packages
+# 1. all in one package
+set(CPACK_NUGET_PACKAGE_TAGS "nuget" "unit" "test" "all-in-one")
+# 2. per component packages
+set(CPACK_NUGET_APPLICATIONS_PACKAGE_TAGS "nuget" "unit" "test" "applications")
+set(CPACK_NUGET_LIBRARIES_PACKAGE_TAGS "nuget" "unit" "test" "libraries")
+set(CPACK_NUGET_HEADERS_PACKAGE_TAGS "nuget" "unit" "test" "headers")
+set(CPACK_NUGET_UNSPECIFIED_PACKAGE_TAGS "nuget" "unit" "test" "uNsP3c1FiEd")
+# 3. per group packages
+set(CPACK_NUGET_RUNTIME_PACKAGE_TAGS "nuget" "unit" "test" "run-time")
+set(CPACK_NUGET_DEVELOPMENT_PACKAGE_TAGS "nuget" "unit" "test" "development")
+
+# We may use the CPack specific config file in order
+# to tailor CPack behavior on a CPack generator specific way
+# (Behavior would be different for RPM or TGZ or DEB ...)
+if (NOT ("${CPackComponentWay}" STREQUAL "default"))
+ # Setup project specific CPack-time CPack Config file.
+ configure_file(${CPackComponentsForAll_SOURCE_DIR}/MyLibCPackConfig-${CPackComponentWay}.cmake.in
+ ${CPackComponentsForAll_BINARY_DIR}/MyLibCPackConfig-${CPackComponentWay}.cmake
+ @ONLY)
+ set(CPACK_PROJECT_CONFIG_FILE ${CPackComponentsForAll_BINARY_DIR}/MyLibCPackConfig-${CPackComponentWay}.cmake)
+endif ()
+# Include CPack to introduce the appropriate targets
+include(CPack)
diff --git a/Tests/CPackComponentsForAll/MyLibCPackConfig-AllInOne.cmake.in b/Tests/CPackComponentsForAll/MyLibCPackConfig-AllInOne.cmake.in
new file mode 100644
index 0000000..1b9e658
--- /dev/null
+++ b/Tests/CPackComponentsForAll/MyLibCPackConfig-AllInOne.cmake.in
@@ -0,0 +1,26 @@
+#
+# Activate component packaging
+#
+if(CPACK_GENERATOR MATCHES "ZIP")
+ set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
+endif()
+
+if(CPACK_GENERATOR MATCHES "RPM")
+ set(CPACK_RPM_COMPONENT_INSTALL "ON")
+endif()
+
+if(CPACK_GENERATOR MATCHES "DEB")
+ set(CPACK_DEB_COMPONENT_INSTALL "ON")
+endif()
+
+if(CPACK_GENERATOR MATCHES "NuGet")
+ set(CPACK_NUGET_COMPONENT_INSTALL "ON")
+endif()
+
+#
+# Choose grouping way
+#
+#set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE 1)
+#set(CPACK_COMPONENTS_GROUPING)
+#set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1)
diff --git a/Tests/CPackComponentsForAll/MyLibCPackConfig-IgnoreGroup.cmake.in b/Tests/CPackComponentsForAll/MyLibCPackConfig-IgnoreGroup.cmake.in
new file mode 100644
index 0000000..a6f6ea9
--- /dev/null
+++ b/Tests/CPackComponentsForAll/MyLibCPackConfig-IgnoreGroup.cmake.in
@@ -0,0 +1,65 @@
+#
+# Activate component packaging
+#
+if(CPACK_GENERATOR MATCHES "ZIP")
+ set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
+endif()
+
+if(CPACK_GENERATOR MATCHES "RPM")
+ set(CPACK_RPM_COMPONENT_INSTALL "ON")
+
+ # test that /usr and /usr/foo get omitted in relocatable
+ # rpms as shortest relocation path is treated as base of
+ # package (/usr/foo/bar is relocatable and must exist)
+ set(CPACK_PACKAGING_INSTALL_PREFIX "/usr/foo/bar")
+
+ # test requires
+ set(CPACK_RPM_APPLICATIONS_PACKAGE_REQUIRES "mylib-libraries")
+
+ # test a "noarch" rpm
+ set(CPACK_RPM_HEADERS_PACKAGE_ARCHITECTURE "noarch")
+
+ # test cross-built rpm
+ set(CPACK_RPM_APPLICATIONS_PACKAGE_ARCHITECTURE "armv7hf")
+
+ # test package summary override - headers rpm is generated in the middle
+ set(CPACK_RPM_PACKAGE_SUMMARY "default summary")
+ set(CPACK_RPM_HEADERS_PACKAGE_SUMMARY "headers summary")
+
+ # test package description override - headers rpm is generated in the middle
+ set(CPACK_RPM_HEADERS_PACKAGE_DESCRIPTION "headers description")
+
+ # test package do not use CPACK_PACKAGING_INSTALL_PREFIX
+ # as relocation path
+ set(CPACK_RPM_NO_LIBRARIES_INSTALL_PREFIX_RELOCATION true)
+
+ # test default permissions
+ set(CPACK_RPM_DEFAULT_USER defusr)
+ set(CPACK_RPM_DEFAULT_GROUP defgrp)
+ set(CPACK_RPM_DEFAULT_FILE_PERMISSIONS
+ OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ WORLD_READ)
+ set(CPACK_RPM_DEFAULT_DIR_PERMISSIONS
+ OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ WORLD_READ)
+ set(CPACK_RPM_LIBRARIES_DEFAULT_USER user)
+ set(CPACK_RPM_APPLICATIONS_DEFAULT_GROUP group)
+ set(CPACK_RPM_LIBRARIES_DEFAULT_FILE_PERMISSIONS
+ OWNER_READ OWNER_WRITE OWNER_EXECUTE)
+ set(CPACK_RPM_APPLICATIONS_DEFAULT_DIR_PERMISSIONS
+ OWNER_READ GROUP_READ WORLD_READ)
+endif()
+
+if(CPACK_GENERATOR MATCHES "DEB")
+ set(CPACK_DEB_COMPONENT_INSTALL "ON")
+endif()
+
+if(CPACK_GENERATOR MATCHES "NuGet")
+ set(CPACK_NUGET_COMPONENT_INSTALL "ON")
+endif()
+
+#
+# Choose grouping way
+#
+#set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE)
+#set(CPACK_COMPONENTS_GROUPING)
+set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+#set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1)
diff --git a/Tests/CPackComponentsForAll/MyLibCPackConfig-OnePackPerGroup.cmake.in b/Tests/CPackComponentsForAll/MyLibCPackConfig-OnePackPerGroup.cmake.in
new file mode 100644
index 0000000..d41225d
--- /dev/null
+++ b/Tests/CPackComponentsForAll/MyLibCPackConfig-OnePackPerGroup.cmake.in
@@ -0,0 +1,31 @@
+#
+# Activate component packaging
+#
+if(CPACK_GENERATOR MATCHES "ZIP")
+ set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
+endif()
+
+if(CPACK_GENERATOR MATCHES "RPM")
+ set(CPACK_RPM_COMPONENT_INSTALL "ON")
+ set(CPACK_RPM_DEVELOPMENT_PACKAGE_REQUIRES "mylib-Runtime")
+endif()
+
+if(CPACK_GENERATOR MATCHES "DEB")
+ set(CPACK_DEB_COMPONENT_INSTALL "ON")
+endif()
+
+if(CPACK_GENERATOR MATCHES "DragNDrop")
+ set(CPACK_COMPONENTS_GROUPING "ONE_PER_GROUP")
+endif()
+
+if(CPACK_GENERATOR MATCHES "NuGet")
+ set(CPACK_NUGET_COMPONENT_INSTALL "ON")
+endif()
+
+#
+# Choose grouping way
+#
+#set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE)
+#set(CPACK_COMPONENTS_GROUPING)
+#set(CPACK_COMPONENTS_IGNORE_GROUPS)
+#set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE)
diff --git a/Tests/CPackComponentsForAll/RunCPackVerifyResult.cmake b/Tests/CPackComponentsForAll/RunCPackVerifyResult.cmake
new file mode 100644
index 0000000..f3d3ad0
--- /dev/null
+++ b/Tests/CPackComponentsForAll/RunCPackVerifyResult.cmake
@@ -0,0 +1,434 @@
+# prevent older policies from interfearing with this script
+cmake_policy(PUSH)
+cmake_policy(VERSION ${CMAKE_VERSION})
+
+message(STATUS "=============================================================================")
+message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+message(STATUS "")
+
+if(NOT CPackComponentsForAll_BINARY_DIR)
+ message(FATAL_ERROR "CPackComponentsForAll_BINARY_DIR not set")
+endif()
+
+if(NOT CPackGen)
+ message(FATAL_ERROR "CPackGen not set")
+endif()
+
+message("CMAKE_CPACK_COMMAND = ${CMAKE_CPACK_COMMAND}")
+if(NOT CMAKE_CPACK_COMMAND)
+ message(FATAL_ERROR "CMAKE_CPACK_COMMAND not set")
+endif()
+
+if(NOT CPackComponentWay)
+ message(FATAL_ERROR "CPackComponentWay not set")
+endif()
+
+set(expected_file_mask "")
+# The usual default behavior is to expect a single file
+# Then some specific generators (Archive, RPM, ...)
+# May produce several numbers of files depending on
+# CPACK_COMPONENT_xxx values
+set(expected_count 1)
+set(config_type $ENV{CMAKE_CONFIG_TYPE})
+set(config_args )
+if(config_type)
+ set(config_args -C ${config_type})
+endif()
+set(config_verbose )
+
+if(CPackGen MATCHES "ZIP")
+ set(expected_file_mask "${CPackComponentsForAll_BINARY_DIR}/MyLib-*.zip")
+ if(${CPackComponentWay} STREQUAL "default")
+ set(expected_count 1)
+ elseif(${CPackComponentWay} STREQUAL "OnePackPerGroup")
+ set(expected_count 3)
+ elseif(${CPackComponentWay} STREQUAL "IgnoreGroup")
+ set(expected_count 4)
+ elseif(${CPackComponentWay} STREQUAL "AllInOne")
+ set(expected_count 1)
+ endif()
+elseif(CPackGen MATCHES "RPM")
+ set(config_verbose -D "CPACK_RPM_PACKAGE_DEBUG=1")
+ set(expected_file_mask "${CPackComponentsForAll_BINARY_DIR}/MyLib-*.rpm")
+ if(${CPackComponentWay} STREQUAL "default")
+ set(expected_count 1)
+ elseif(${CPackComponentWay} STREQUAL "OnePackPerGroup")
+ set(expected_count 3)
+ elseif(${CPackComponentWay} STREQUAL "IgnoreGroup")
+ set(expected_count 4)
+ elseif(${CPackComponentWay} STREQUAL "AllInOne")
+ set(expected_count 1)
+ endif()
+elseif(CPackGen MATCHES "DEB")
+ set(expected_file_mask "${CPackComponentsForAll_BINARY_DIR}/mylib*_1.0.2_*.deb")
+ if(${CPackComponentWay} STREQUAL "default")
+ set(expected_count 1)
+ elseif(${CPackComponentWay} STREQUAL "OnePackPerGroup")
+ set(expected_count 3)
+ elseif(${CPackComponentWay} STREQUAL "IgnoreGroup")
+ set(expected_count 4)
+ elseif(${CPackComponentWay} STREQUAL "AllInOne")
+ set(expected_count 1)
+ endif()
+elseif(CPackGen MATCHES "NuGet")
+ set(config_verbose -D "CPACK_NUGET_PACKAGE_DEBUG=1")
+ set(expected_file_mask "${CPackComponentsForAll_BINARY_DIR}/MyLib*1.0.2.nupkg")
+ if(${CPackComponentWay} STREQUAL "default")
+ set(expected_count 1)
+ elseif(${CPackComponentWay} STREQUAL "OnePackPerGroup")
+ set(expected_count 3)
+ elseif(${CPackComponentWay} STREQUAL "IgnoreGroup")
+ set(expected_count 4)
+ elseif(${CPackComponentWay} STREQUAL "AllInOne")
+ set(expected_count 1)
+ endif()
+endif()
+
+if(CPackGen MATCHES "DragNDrop")
+ set(expected_file_mask "${CPackComponentsForAll_BINARY_DIR}/MyLib-*.dmg")
+ if(${CPackComponentWay} STREQUAL "default")
+ set(expected_count 1)
+ set(expect_dmg_sla 1)
+ elseif(${CPackComponentWay} STREQUAL "OnePackPerGroup")
+ set(expected_count 3)
+ elseif(${CPackComponentWay} STREQUAL "IgnoreGroup")
+ set(expected_count 4)
+ elseif(${CPackComponentWay} STREQUAL "AllInOne")
+ set(expected_count 1)
+ set(expect_dmg_sla 1)
+ endif()
+endif()
+
+# clean-up previously CPack generated files
+if(expected_file_mask)
+ file(GLOB expected_file "${expected_file_mask}")
+ if(expected_file)
+ file(REMOVE ${expected_file})
+ endif()
+endif()
+
+message("config_args = ${config_args}")
+message("config_verbose = ${config_verbose}")
+execute_process(COMMAND ${CMAKE_CPACK_COMMAND} ${config_verbose} -G ${CPackGen} ${config_args}
+ RESULT_VARIABLE CPack_result
+ OUTPUT_VARIABLE CPack_output
+ ERROR_VARIABLE CPack_error
+ WORKING_DIRECTORY ${CPackComponentsForAll_BINARY_DIR})
+
+if(CPack_result)
+ message(FATAL_ERROR "error: CPack execution went wrong!, CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+else ()
+ message(STATUS "CPack_output=${CPack_output}")
+endif()
+
+# Now verify if the number of expected file is OK
+# - using expected_file_mask and
+# - expected_count
+if(expected_file_mask)
+ file(GLOB expected_file "${expected_file_mask}")
+
+ message(STATUS "expected_count='${expected_count}'")
+ message(STATUS "expected_file='${expected_file}'")
+ message(STATUS "expected_file_mask='${expected_file_mask}'")
+
+ if(NOT expected_file)
+ message(FATAL_ERROR "error: expected_file does not exist: CPackComponentsForAll test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+ endif()
+
+ list(LENGTH expected_file actual_count)
+ message(STATUS "actual_count='${actual_count}'")
+ if(NOT actual_count EQUAL expected_count)
+ message(FATAL_ERROR "error: expected_count=${expected_count} does not match actual_count=${actual_count}: CPackComponents test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error})")
+ endif()
+
+ if(expect_dmg_sla)
+ execute_process(COMMAND hdiutil udifderez -xml "${expected_file}" OUTPUT_VARIABLE out ERROR_VARIABLE err RESULT_VARIABLE res)
+ if(NOT res EQUAL 0)
+ string(REPLACE "\n" "\n " err " ${err}")
+ message(FATAL_ERROR "error: running 'hdiutil udifderez -xml' on\n ${expected_file}\nfailed with:\n${err}")
+ endif()
+ foreach(key "LPic" "STR#" "TEXT")
+ if(NOT out MATCHES "<key>${key}</key>")
+ string(REPLACE "\n" "\n " out " ${out}")
+ message(FATAL_ERROR "error: running 'hdiutil udifderez -xml' on\n ${expected_file}\ndid not show '${key}' key:\n${out}")
+ endif()
+ endforeach()
+ foreach(line
+ # LPic first and last base64 lines
+ "\tAAIAEQADAAEAAAAAAAIAAAAIAAMAAAABAAQAAAAEAAUAAAAOAAYA\n"
+ "\tAA0AAABbAAQAAAAzAA8AAQAMABAAAAALAA4AAA==\n"
+ # STR# first and last base64 lines
+ "\tAAkHRW5nbGlzaAVBZ3JlZQhEaXNhZ3JlZQVQcmludAdTYXZlLi4u\n"
+ "\tdGVkIGEgcHJpbnRlci4=\n"
+ # TEXT first and last base64 lines
+ "\tTElDRU5TRQ0tLS0tLS0tDVRoaXMgaXMgYW4gaW5zdGFsbGVyIGNy\n"
+ "\tTm8gbGljZW5zZSBwcm92aWRlZC4NDQ==\n"
+ )
+ if(NOT out MATCHES "${line}")
+ string(REPLACE "\n" "\n " out " ${out}")
+ message(FATAL_ERROR "error: running 'hdiutil udifderez -xml' on\n ${expected_file}\ndid not show '${line}':\n${out}")
+ endif()
+ endforeach()
+ endif()
+endif()
+
+# Validate content
+if(CPackGen MATCHES "RPM")
+ find_program(RPM_EXECUTABLE rpm)
+ if(NOT RPM_EXECUTABLE)
+ message(FATAL_ERROR "error: missing rpm executable required by the test")
+ endif()
+
+ set(CPACK_RPM_PACKAGE_SUMMARY "default summary")
+ set(CPACK_RPM_HEADERS_PACKAGE_SUMMARY "headers summary")
+ set(CPACK_RPM_HEADERS_PACKAGE_DESCRIPTION "headers description")
+ set(CPACK_COMPONENT_APPLICATIONS_DESCRIPTION
+ "An extremely useful application that makes use of MyLib")
+ set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION
+ "Static libraries used to build programs with MyLib")
+ set(LIB_SUFFIX "6?4?")
+
+ # test package info
+ if(${CPackComponentWay} STREQUAL "IgnoreGroup")
+ # set gnu install prefixes to what they are set during rpm creation
+ # CMAKE_SIZEOF_VOID_P is not set here but lib is prefix of lib64 so
+ # relocation path test won't fail on OSes with lib64 library location
+ include(GNUInstallDirs)
+ set(CPACK_PACKAGING_INSTALL_PREFIX "/usr/foo/bar")
+
+ foreach(check_file ${expected_file})
+ string(REGEX MATCH ".*libraries.*" check_file_libraries_match ${check_file})
+ string(REGEX MATCH ".*headers.*" check_file_headers_match ${check_file})
+ string(REGEX MATCH ".*applications.*" check_file_applications_match ${check_file})
+ string(REGEX MATCH ".*Unspecified.*" check_file_Unspecified_match ${check_file})
+
+ execute_process(COMMAND ${RPM_EXECUTABLE} -pqi ${check_file}
+ OUTPUT_VARIABLE check_file_content
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ execute_process(COMMAND ${RPM_EXECUTABLE} -pqa ${check_file}
+ RESULT_VARIABLE check_package_architecture_result
+ OUTPUT_VARIABLE check_package_architecture
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ execute_process(COMMAND ${RPM_EXECUTABLE} -pql ${check_file}
+ OUTPUT_VARIABLE check_package_content
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ set(whitespaces "[\\t\\n\\r ]*")
+
+ if(check_file_libraries_match)
+ set(check_file_match_expected_summary ".*${CPACK_RPM_PACKAGE_SUMMARY}.*")
+ set(check_file_match_expected_description ".*${CPACK_COMPONENT_LIBRARIES_DESCRIPTION}.*")
+ set(check_file_match_expected_relocation_path "Relocations${whitespaces}:${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}${LIB_SUFFIX}${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}/other_relocatable${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}${LIB_SUFFIX}/inside_relocatable_two/depth_two/different_relocatable")
+ set(check_file_match_expected_architecture "") # we don't explicitly set this value so it is different on each platform - ignore it
+ set(spec_regex "*libraries*")
+ set(check_content_list "^/usr/foo/bar/lib${LIB_SUFFIX}
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/depth_three
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/depth_three/symlink_parentdir_path
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/symlink_outside_package
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/symlink_outside_wdr
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/symlink_relocatable_subpath
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/symlink_samedir_path
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/symlink_samedir_path_current_dir
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/symlink_samedir_path_longer
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/symlink_subdir_path
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_two
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_two/depth_two
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_two/depth_two/different_relocatable
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_two/depth_two/different_relocatable/bar
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_two/depth_two/symlink_other_relocatable_path
+/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_two/depth_two/symlink_to_non_relocatable_path
+/usr/foo/bar/lib${LIB_SUFFIX}/libmylib.a
+/usr/foo/bar/non_relocatable
+/usr/foo/bar/non_relocatable/depth_two
+/usr/foo/bar/non_relocatable/depth_two/symlink_from_non_relocatable_path
+/usr/foo/bar/other_relocatable
+/usr/foo/bar/other_relocatable/depth_two(\n.*\.build-id.*)*$")
+ elseif(check_file_headers_match)
+ set(check_file_match_expected_summary ".*${CPACK_RPM_HEADERS_PACKAGE_SUMMARY}.*")
+ set(check_file_match_expected_description ".*${CPACK_RPM_HEADERS_PACKAGE_DESCRIPTION}.*")
+ set(check_file_match_expected_relocation_path "Relocations${whitespaces}:${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}")
+ set(check_file_match_expected_architecture "noarch")
+ set(spec_regex "*headers*")
+ set(check_content_list "^/usr/foo/bar\n/usr/foo/bar/include\n/usr/foo/bar/include/mylib.h(\n.*\.build-id.*)*$")
+ elseif(check_file_applications_match)
+ set(check_file_match_expected_summary ".*${CPACK_RPM_PACKAGE_SUMMARY}.*")
+ set(check_file_match_expected_description ".*${CPACK_COMPONENT_APPLICATIONS_DESCRIPTION}.*")
+ set(check_file_match_expected_relocation_path "Relocations${whitespaces}:${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
+ set(check_file_match_expected_architecture "armv7hf")
+ set(spec_regex "*applications*")
+ set(check_content_list "^/usr/foo/bar
+/usr/foo/bar/bin
+/usr/foo/bar/bin/mylibapp(\n.*\.build-id.*)*$")
+ elseif(check_file_Unspecified_match)
+ set(check_file_match_expected_summary ".*${CPACK_RPM_PACKAGE_SUMMARY}.*")
+ set(check_file_match_expected_description ".*DESCRIPTION.*")
+ set(check_file_match_expected_relocation_path "Relocations${whitespaces}:${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
+ set(check_file_match_expected_architecture "") # we don't explicitly set this value so it is different on each platform - ignore it
+ set(spec_regex "*Unspecified*")
+ set(check_content_list "^/usr/foo/bar
+/usr/foo/bar/bin
+/usr/foo/bar/bin/@in@_@path@@with
+/usr/foo/bar/bin/@in@_@path@@with/@and
+/usr/foo/bar/bin/@in@_@path@@with/@and/@
+/usr/foo/bar/bin/@in@_@path@@with/@and/@/@in_path@
+/usr/foo/bar/bin/@in@_@path@@with/@and/@/@in_path@/mylibapp2
+/usr/foo/bar/share
+/usr/foo/bar/share/man
+/usr/foo/bar/share/man/mylib
+/usr/foo/bar/share/man/mylib/man3
+/usr/foo/bar/share/man/mylib/man3/mylib.1
+/usr/foo/bar/share/man/mylib/man3/mylib.1/mylib
+/usr/foo/bar/share/man/mylib/man3/mylib.1/mylib2(\n.*\.build-id.*)*$")
+ else()
+ message(FATAL_ERROR "error: unexpected rpm package '${check_file}'")
+ endif()
+
+ #######################
+ # test package info
+ #######################
+ string(REGEX MATCH ${check_file_match_expected_summary} check_file_match_summary ${check_file_content})
+
+ if(NOT check_file_match_summary)
+ message(FATAL_ERROR "error: '${check_file}' rpm package summary does not match expected value - regex '${check_file_match_expected_summary}'; RPM output: '${check_file_content}'")
+ endif()
+
+ string(REGEX MATCH ${check_file_match_expected_description} check_file_match_description ${check_file_content})
+
+ if(NOT check_file_match_description)
+ message(FATAL_ERROR "error: '${check_file}' rpm package description does not match expected value - regex '${check_file_match_expected_description}'; RPM output: '${check_file_content}'")
+ endif()
+
+ string(REGEX MATCH ${check_file_match_expected_relocation_path} check_file_match_relocation_path ${check_file_content})
+
+ if(NOT check_file_match_relocation_path)
+ file(GLOB_RECURSE spec_file "${CPackComponentsForAll_BINARY_DIR}/${spec_regex}.spec")
+
+ if(spec_file)
+ file(READ ${spec_file} spec_file_content)
+ endif()
+
+ message(FATAL_ERROR "error: '${check_file}' rpm package relocation path does not match expected value - regex '${check_file_match_expected_relocation_path}'; RPM output: '${check_file_content}'; generated spec file: '${spec_file_content}'")
+ endif()
+
+ #######################
+ # test package architecture
+ #######################
+ string(REGEX MATCH "Architecture${whitespaces}:" check_info_contains_arch ${check_file_content})
+ if(check_info_contains_arch) # test for rpm versions that contain architecture in package info (e.g. 4.11.x)
+ string(REGEX MATCH "Architecture${whitespaces}:${whitespaces}${check_file_match_expected_architecture}" check_file_match_architecture ${check_file_content})
+ if(NOT check_file_match_architecture)
+ message(FATAL_ERROR "error: '${check_file}' Architecture does not match expected value - '${check_file_match_expected_architecture}'; RPM output: '${check_file_content}'; generated spec file: '${spec_file_content}'")
+ endif()
+ elseif(NOT check_package_architecture_result) # test result only on platforms that support -pqa rpm query
+ # test for rpm versions that do not contain architecture in package info (e.g. 4.8.x)
+ string(REGEX MATCH ".*${check_file_match_expected_architecture}" check_file_match_architecture "${check_package_architecture}")
+ if(NOT check_file_match_architecture)
+ message(FATAL_ERROR "error: '${check_file}' Architecture does not match expected value - '${check_file_match_expected_architecture}'; RPM output: '${check_package_architecture}'; generated spec file: '${spec_file_content}'")
+ endif()
+ # else rpm version too old (e.g. 4.4.x) - skip test
+ endif()
+
+ #######################
+ # test package content
+ #######################
+ string(REGEX MATCH "${check_content_list}" expected_content_list "${check_package_content}")
+
+ if(NOT expected_content_list)
+ file(GLOB_RECURSE spec_file "${CPackComponentsForAll_BINARY_DIR}/${spec_regex}.spec")
+
+ if(spec_file)
+ file(READ ${spec_file} spec_file_content)
+ endif()
+
+ message(FATAL_ERROR "error: '${check_file}' rpm package content does not match expected value - regex '${check_content_list}'; RPM output: '${check_package_content}'; generated spec file: '${spec_file_content}'")
+ endif()
+
+ # validate permissions user and group
+ execute_process(COMMAND ${RPM_EXECUTABLE} -pqlv ${check_file}
+ OUTPUT_VARIABLE check_file_content
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(check_file_libraries_match)
+ set(check_file_match_expected_permissions ".*-rwx------.*user.*defgrp.*")
+ elseif(check_file_headers_match)
+ set(check_file_match_expected_permissions ".*-rwxr--r--.*defusr.*defgrp.*")
+ elseif(check_file_applications_match)
+ set(check_file_match_expected_permissions ".*-rwxr--r--.*defusr.*group.*")
+ elseif(check_file_Unspecified_match)
+ set(check_file_match_expected_permissions ".*-rwxr--r--.*defusr.*defgrp.*")
+ else()
+ message(FATAL_ERROR "error: unexpected rpm package '${check_file}'")
+ endif()
+
+ string(REGEX MATCH "${check_file_match_expected_permissions}" check_file_match_permissions "${check_file_content}")
+
+ if(NOT check_file_match_permissions)
+ message(FATAL_ERROR "error: '${check_file}' rpm package permissions do not match expected value - regex '${check_file_match_expected_permissions}'")
+ endif()
+ endforeach()
+
+ #######################
+ # verify generated symbolic links
+ #######################
+ file(GLOB_RECURSE symlink_files RELATIVE "${CPackComponentsForAll_BINARY_DIR}" "${CPackComponentsForAll_BINARY_DIR}/*/symlink_*")
+
+ foreach(check_symlink IN LISTS symlink_files)
+ get_filename_component(symlink_name "${check_symlink}" NAME)
+ execute_process(COMMAND ls -la "${check_symlink}"
+ WORKING_DIRECTORY "${CPackComponentsForAll_BINARY_DIR}"
+ OUTPUT_VARIABLE SYMLINK_POINT_
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if("${symlink_name}" STREQUAL "symlink_samedir_path"
+ OR "${symlink_name}" STREQUAL "symlink_samedir_path_current_dir"
+ OR "${symlink_name}" STREQUAL "symlink_samedir_path_longer")
+ string(REGEX MATCH "^.*${whitespaces}->${whitespaces}depth_three$" check_symlink "${SYMLINK_POINT_}")
+ elseif("${symlink_name}" STREQUAL "symlink_subdir_path")
+ string(REGEX MATCH "^.*${whitespaces}->${whitespaces}depth_two/depth_three$" check_symlink "${SYMLINK_POINT_}")
+ elseif("${symlink_name}" STREQUAL "symlink_parentdir_path")
+ string(REGEX MATCH "^.*${whitespaces}->${whitespaces}../$" check_symlink "${SYMLINK_POINT_}")
+ elseif("${symlink_name}" STREQUAL "symlink_to_non_relocatable_path")
+ string(REGEX MATCH "^.*${whitespaces}->${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}/non_relocatable/depth_two$" check_symlink "${SYMLINK_POINT_}")
+ elseif("${symlink_name}" STREQUAL "symlink_outside_package")
+ string(REGEX MATCH "^.*${whitespaces}->${whitespaces}outside_package$" check_symlink "${SYMLINK_POINT_}")
+ elseif("${symlink_name}" STREQUAL "symlink_outside_wdr")
+ string(REGEX MATCH "^.*${whitespaces}->${whitespaces}/outside_package_wdr$" check_symlink "${SYMLINK_POINT_}")
+ elseif("${symlink_name}" STREQUAL "symlink_other_relocatable_path"
+ OR "${symlink_name}" STREQUAL "symlink_from_non_relocatable_path"
+ OR "${symlink_name}" STREQUAL "symlink_relocatable_subpath")
+ # these links were not canged - post install script only - ignore them
+ else()
+ message(FATAL_ERROR "error: unexpected rpm symbolic link '${check_symlink}'")
+ endif()
+
+ if(NOT check_symlink)
+ message(FATAL_ERROR "symlink points to unexpected location '${SYMLINK_POINT_}'")
+ endif()
+ endforeach()
+
+ # verify post install symlink relocation script
+ file(GLOB_RECURSE spec_file "${CPackComponentsForAll_BINARY_DIR}/*libraries*.spec")
+ file(READ ${spec_file} spec_file_content)
+ file(READ "${CMAKE_CURRENT_LIST_DIR}/symlink_postinstall_expected.txt" symlink_postinstall_expected)
+ # prepare regex
+ string(STRIP "${symlink_postinstall_expected}" symlink_postinstall_expected)
+ string(REPLACE "[" "\\[" symlink_postinstall_expected "${symlink_postinstall_expected}")
+ string(REPLACE "$" "\\$" symlink_postinstall_expected "${symlink_postinstall_expected}")
+ string(REPLACE "lib" "lib${LIB_SUFFIX}" symlink_postinstall_expected "${symlink_postinstall_expected}")
+ # compare
+ string(REGEX MATCH ".*${symlink_postinstall_expected}.*" symlink_postinstall_expected_matches "${spec_file_content}")
+ if(NOT symlink_postinstall_expected_matches)
+ message(FATAL_ERROR "error: unexpected rpm symbolic link postinstall script! generated spec file: '${spec_file_content}'")
+ endif()
+ endif()
+endif()
+
+cmake_policy(POP)
diff --git a/Tests/CPackComponentsForAll/license.txt b/Tests/CPackComponentsForAll/license.txt
new file mode 100644
index 0000000..d829d93
--- /dev/null
+++ b/Tests/CPackComponentsForAll/license.txt
@@ -0,0 +1,3 @@
+LICENSE
+-------
+This is an installer created using CPack (https://cmake.org). No license provided.
diff --git a/Tests/CPackComponentsForAll/mylib b/Tests/CPackComponentsForAll/mylib
new file mode 100644
index 0000000..e3bd05c
--- /dev/null
+++ b/Tests/CPackComponentsForAll/mylib
@@ -0,0 +1,17 @@
+.\" Manpage for mylib.
+.\" Contact bugs@mylib_author.net.in to correct errors or typos.
+.TH mylib 3 "01 May 2015" "1.0" "mylib.so man page"
+.SH NAME
+mylib \- cpack testing lib
+.SH SYNOPSIS
+mylib.so
+.SH DESCRIPTION
+mylib.so test man page.
+.SH OPTIONS
+Lib does not take any options.
+.SH SEE ALSO
+mylib(3)
+.SH BUGS
+No known bugs.
+.SH AUTHOR
+Someone (author@lib_author.net.in)
diff --git a/Tests/CPackComponentsForAll/mylib.cpp b/Tests/CPackComponentsForAll/mylib.cpp
new file mode 100644
index 0000000..8d63071
--- /dev/null
+++ b/Tests/CPackComponentsForAll/mylib.cpp
@@ -0,0 +1,8 @@
+#include "mylib.h"
+
+#include "stdio.h"
+
+void mylib_function()
+{
+ printf("This is mylib");
+}
diff --git a/Tests/CPackComponentsForAll/mylib.h b/Tests/CPackComponentsForAll/mylib.h
new file mode 100644
index 0000000..5d0a822
--- /dev/null
+++ b/Tests/CPackComponentsForAll/mylib.h
@@ -0,0 +1 @@
+void mylib_function();
diff --git a/Tests/CPackComponentsForAll/mylibapp.cpp b/Tests/CPackComponentsForAll/mylibapp.cpp
new file mode 100644
index 0000000..a438ac7
--- /dev/null
+++ b/Tests/CPackComponentsForAll/mylibapp.cpp
@@ -0,0 +1,6 @@
+#include "mylib.h"
+
+int main()
+{
+ mylib_function();
+}
diff --git a/Tests/CPackComponentsForAll/symlink_postinstall_expected.txt b/Tests/CPackComponentsForAll/symlink_postinstall_expected.txt
new file mode 100644
index 0000000..ba46792
--- /dev/null
+++ b/Tests/CPackComponentsForAll/symlink_postinstall_expected.txt
@@ -0,0 +1,57 @@
+if [ "$RPM_INSTALL_PREFIX0" != "/usr/foo/bar/lib" ]; then
+ if [ "$RPM_INSTALL_PREFIX1" != "/usr/foo/bar/other_relocatable" ]; then
+ if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_1" ]; then
+ ln -s "$RPM_INSTALL_PREFIX1/depth_two" "$RPM_INSTALL_PREFIX0/inside_relocatable_two/depth_two/symlink_other_relocatable_path"
+ CPACK_RPM_RELOCATED_SYMLINK_1=true
+ fi
+ fi
+ if [ "$RPM_INSTALL_PREFIX2" != "/usr/foo/bar/lib/inside_relocatable_two/depth_two/different_relocatable" ]; then
+ if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_0" ]; then
+ ln -s "$RPM_INSTALL_PREFIX2/bar" "$RPM_INSTALL_PREFIX0/inside_relocatable_one/depth_two/symlink_relocatable_subpath"
+ CPACK_RPM_RELOCATED_SYMLINK_0=true
+ fi
+ fi
+ if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_0" ]; then
+ ln -s "$RPM_INSTALL_PREFIX0/inside_relocatable_two/depth_two/different_relocatable/bar" "$RPM_INSTALL_PREFIX0/inside_relocatable_one/depth_two/symlink_relocatable_subpath"
+ CPACK_RPM_RELOCATED_SYMLINK_0=true
+ fi
+ if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_0" ]; then
+ ln -s "/usr/foo/bar/lib/inside_relocatable_two/depth_two/different_relocatable/bar" "$RPM_INSTALL_PREFIX0/inside_relocatable_one/depth_two/symlink_relocatable_subpath"
+ CPACK_RPM_RELOCATED_SYMLINK_0=true
+ fi
+ if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_1" ]; then
+ ln -s "/usr/foo/bar/other_relocatable/depth_two" "$RPM_INSTALL_PREFIX0/inside_relocatable_two/depth_two/symlink_other_relocatable_path"
+ CPACK_RPM_RELOCATED_SYMLINK_1=true
+ fi
+fi
+if [ "$RPM_INSTALL_PREFIX1" != "/usr/foo/bar/other_relocatable" ]; then
+ if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_1" ]; then
+ ln -s "$RPM_INSTALL_PREFIX1/depth_two" "/usr/foo/bar/lib/inside_relocatable_two/depth_two/symlink_other_relocatable_path"
+ CPACK_RPM_RELOCATED_SYMLINK_1=true
+ fi
+fi
+if [ "$RPM_INSTALL_PREFIX2" != "/usr/foo/bar/lib/inside_relocatable_two/depth_two/different_relocatable" ]; then
+ if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_0" ]; then
+ ln -s "$RPM_INSTALL_PREFIX2/bar" "/usr/foo/bar/lib/inside_relocatable_one/depth_two/symlink_relocatable_subpath"
+ CPACK_RPM_RELOCATED_SYMLINK_0=true
+ fi
+fi
+if [ "$RPM_INSTALL_PREFIX0" != "/usr/foo/bar/lib" ]; then
+ if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_0" ]; then
+ ln -s "$RPM_INSTALL_PREFIX0/inside_relocatable_two/depth_two/different_relocatable/bar" "/usr/foo/bar/lib/inside_relocatable_one/depth_two/symlink_relocatable_subpath"
+ CPACK_RPM_RELOCATED_SYMLINK_0=true
+ fi
+ if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_2" ]; then
+ ln -s "$RPM_INSTALL_PREFIX0/inside_relocatable_two/depth_two" "/usr/foo/bar/non_relocatable/depth_two/symlink_from_non_relocatable_path"
+ CPACK_RPM_RELOCATED_SYMLINK_2=true
+ fi
+fi
+if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_0" ]; then
+ ln -s "/usr/foo/bar/lib/inside_relocatable_two/depth_two/different_relocatable/bar" "/usr/foo/bar/lib/inside_relocatable_one/depth_two/symlink_relocatable_subpath"
+fi
+if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_1" ]; then
+ ln -s "/usr/foo/bar/other_relocatable/depth_two" "/usr/foo/bar/lib/inside_relocatable_two/depth_two/symlink_other_relocatable_path"
+fi
+if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_2" ]; then
+ ln -s "/usr/foo/bar/lib/inside_relocatable_two/depth_two" "/usr/foo/bar/non_relocatable/depth_two/symlink_from_non_relocatable_path"
+fi
diff --git a/Tests/CPackComponentsPrefix/CMakeLists.txt b/Tests/CPackComponentsPrefix/CMakeLists.txt
new file mode 100644
index 0000000..581d3b3
--- /dev/null
+++ b/Tests/CPackComponentsPrefix/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.2)
+project(CPackComponentsPrefix NONE)
+
+install(FILES file-runtime.txt
+ DESTINATION bin COMPONENT Runtime)
+install(FILES file-development.txt
+ DESTINATION lib COMPONENT Development)
+
+set(CPACK_PACKAGE_CONTACT "None") # mandatory for DEB generator
+set(CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY 1)
+set(CPACK_COMPONENTS_ALL Development)
+set(CPACK_ARCHIVE_COMPONENT_INSTALL 1)
+set(CPACK_PACKAGING_INSTALL_PREFIX "/opt/My-1.0")
+include(CPack)
diff --git a/Tests/CPackComponentsPrefix/file-development.txt b/Tests/CPackComponentsPrefix/file-development.txt
new file mode 100644
index 0000000..df22d2f
--- /dev/null
+++ b/Tests/CPackComponentsPrefix/file-development.txt
@@ -0,0 +1 @@
+This file is installed with the Development component.
diff --git a/Tests/CPackComponentsPrefix/file-runtime.txt b/Tests/CPackComponentsPrefix/file-runtime.txt
new file mode 100644
index 0000000..135c13d
--- /dev/null
+++ b/Tests/CPackComponentsPrefix/file-runtime.txt
@@ -0,0 +1 @@
+This file is installed with the Runtime component.
diff --git a/Tests/CPackNSISGenerator/CMakeLists.txt b/Tests/CPackNSISGenerator/CMakeLists.txt
new file mode 100644
index 0000000..64a8ef6
--- /dev/null
+++ b/Tests/CPackNSISGenerator/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(CPackNSISGenerator)
+
+add_executable(hello main.cpp)
+
+install(TARGETS hello
+ ARCHIVE DESTINATION .
+ RUNTIME DESTINATION .
+ LIBRARY DESTINATION .
+ BUNDLE DESTINATION .)
+
+set(CPACK_NSIS_MUI_HEADERIMAGE "${PROJECT_SOURCE_DIR}\\\\header-image.bmp")
+set(CPACK_PACKAGE_ICON "${PROJECT_SOURCE_DIR}\\\\header-icon.bmp")
+set(CPACK_NSIS_MUI_ICON "${PROJECT_SOURCE_DIR}\\\\install.ico")
+set(CPACK_NSIS_MUI_UNIICON "${PROJECT_SOURCE_DIR}\\\\uninstall.ico")
+set(CPACK_GENERATOR "NSIS")
+set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
+set(CPACK_NSIS_MANIFEST_DPI_AWARE ON)
+set(CPACK_NSIS_BRANDING_TEXT "CMake branding text")
+set(CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION "RIGHT")
+
+include(CPack)
diff --git a/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake b/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
new file mode 100644
index 0000000..8bfcf26
--- /dev/null
+++ b/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
@@ -0,0 +1,62 @@
+message(STATUS "=============================================================")
+message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+message(STATUS "")
+
+if(NOT CPackNSISGenerator_BINARY_DIR)
+ message(FATAL_ERROR "CPackNSISGenerator_BINARY_DIR not set")
+endif()
+
+message(STATUS "CMAKE_COMMAND: ${CMAKE_COMMAND}")
+message(STATUS "CMAKE_CPACK_COMMAND: ${CMAKE_CPACK_COMMAND}")
+message(STATUS "CPackNSISGenerator_BINARY_DIR: ${CPackNSISGenerator_BINARY_DIR}")
+
+if(config)
+ set(_C_config -C ${config})
+endif()
+
+execute_process(COMMAND "${CMAKE_CPACK_COMMAND}"
+ ${_C_config}
+ RESULT_VARIABLE CPack_result
+ OUTPUT_VARIABLE CPack_output
+ ERROR_VARIABLE CPack_error
+ WORKING_DIRECTORY "${CPackNSISGenerator_BINARY_DIR}")
+
+if(CPack_result)
+ message(FATAL_ERROR "CPack execution went wrong!, CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+else ()
+ message(STATUS "CPack_output=${CPack_output}")
+endif()
+
+set(expected_file_mask "${CPackNSISGenerator_BINARY_DIR}/_CPack_Packages/*/NSIS/*.nsi")
+file(GLOB project_file "${expected_file_mask}")
+
+message(STATUS "project_file='${project_file}'")
+message(STATUS "expected_file_mask='${expected_file_mask}'")
+
+if(NOT project_file)
+ message(FATAL_ERROR "project_file does not exist.")
+endif()
+
+# should match !define MUI_HEADERIMAGE_BITMAP "${PROJECT_SOURCE_DIR}\header-image.bmp"
+file(STRINGS "${project_file}" line REGEX "^!define MUI_HEADERIMAGE_BITMAP")
+string(FIND "${line}" "header-image.bmp" output_index)
+message(STATUS "Found the bitmap at index ${output_index}")
+if("${output_index}" EQUAL "-1")
+ message(FATAL_ERROR "MUI_HEADERIMAGE_BITMAP not found in the project")
+endif()
+
+file(STRINGS "${project_file}" line REGEX "^ManifestDPIAware true")
+string(FIND "${line}" "true" output_index)
+if("${output_index}" EQUAL "-1")
+ message(FATAL_ERROR "ManifestDPIAware true not found in the project")
+else()
+ message(STATUS "Found DPI-aware")
+endif()
+
+file(STRINGS "${project_file}" line REGEX "^BrandingText /TRIMRIGHT \"CMake branding text\"")
+string(FIND "${line}" "TRIMRIGHT" output_index)
+if("${output_index}" EQUAL "-1")
+ message(FATAL_ERROR "BrandingText not found in the project")
+else()
+ message(STATUS "Found BrandingText")
+endif()
diff --git a/Tests/CPackNSISGenerator/header-icon.bmp b/Tests/CPackNSISGenerator/header-icon.bmp
new file mode 100644
index 0000000..ef6a656
--- /dev/null
+++ b/Tests/CPackNSISGenerator/header-icon.bmp
Binary files differ
diff --git a/Tests/CPackNSISGenerator/header-image.bmp b/Tests/CPackNSISGenerator/header-image.bmp
new file mode 100644
index 0000000..15b1730
--- /dev/null
+++ b/Tests/CPackNSISGenerator/header-image.bmp
Binary files differ
diff --git a/Tests/CPackNSISGenerator/install.ico b/Tests/CPackNSISGenerator/install.ico
new file mode 100644
index 0000000..3b1e480
--- /dev/null
+++ b/Tests/CPackNSISGenerator/install.ico
Binary files differ
diff --git a/Tests/CPackNSISGenerator/main.cpp b/Tests/CPackNSISGenerator/main.cpp
new file mode 100644
index 0000000..956f345
--- /dev/null
+++ b/Tests/CPackNSISGenerator/main.cpp
@@ -0,0 +1,4 @@
+int main()
+{
+ return 42;
+}
diff --git a/Tests/CPackNSISGenerator/uninstall.ico b/Tests/CPackNSISGenerator/uninstall.ico
new file mode 100644
index 0000000..c4f6316
--- /dev/null
+++ b/Tests/CPackNSISGenerator/uninstall.ico
Binary files differ
diff --git a/Tests/CPackTestAllGenerators/CMakeLists.txt b/Tests/CPackTestAllGenerators/CMakeLists.txt
new file mode 100644
index 0000000..95daabf
--- /dev/null
+++ b/Tests/CPackTestAllGenerators/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(CPackTestAllGenerators)
+add_subdirectory(../CTestTest/SmallAndFast SmallAndFast)
+install(FILES RunCPack.cmake DESTINATION .)
+include(CPack)
diff --git a/Tests/CPackTestAllGenerators/RunCPack.cmake b/Tests/CPackTestAllGenerators/RunCPack.cmake
new file mode 100644
index 0000000..952d5f4
--- /dev/null
+++ b/Tests/CPackTestAllGenerators/RunCPack.cmake
@@ -0,0 +1,51 @@
+if(NOT DEFINED dir)
+ message(FATAL_ERROR "dir not defined")
+endif()
+
+# Analyze 'cpack --help' output for list of available generators:
+#
+execute_process(COMMAND ${CMAKE_CPACK_COMMAND} --help
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE stdout
+ ERROR_VARIABLE stderr
+ WORKING_DIRECTORY ${dir})
+
+string(REPLACE ";" "\\;" stdout "${stdout}")
+string(REPLACE "\n" "E;" stdout "${stdout}")
+
+set(collecting 0)
+set(generators)
+foreach(eline ${stdout})
+ string(REGEX REPLACE "^(.*)E$" "\\1" line "${eline}")
+ if(collecting AND NOT line STREQUAL "")
+ string(REGEX REPLACE "^ ([^ ]+) += (.*)$" "\\1" gen "${line}")
+ string(REGEX REPLACE "^ ([^ ]+) += (.*)$" "\\2" doc "${line}")
+ set(generators ${generators} ${gen})
+ endif()
+ if(line STREQUAL "Generators")
+ set(collecting 1)
+ endif()
+endforeach()
+
+# Call cpack with -G on each available generator. We do not care if this
+# succeeds or not. We expect it *not* to succeed if the underlying packaging
+# tools are not installed on the system... This test is here simply to add
+# coverage for the various cpack generators, even/especially to test ones
+# where the tools are not installed.
+#
+message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+
+message(STATUS "CPack generators='${generators}'")
+
+foreach(g ${generators})
+ message(STATUS "Calling cpack -G ${g}...")
+ execute_process(COMMAND ${CMAKE_CPACK_COMMAND} -G ${g}
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE stdout
+ ERROR_VARIABLE stderr
+ WORKING_DIRECTORY ${dir})
+ message(STATUS "result='${result}'")
+ message(STATUS "stdout='${stdout}'")
+ message(STATUS "stderr='${stderr}'")
+ message(STATUS "")
+endforeach()
diff --git a/Tests/CPackUseDefaultVersion/CMakeLists.txt b/Tests/CPackUseDefaultVersion/CMakeLists.txt
new file mode 100644
index 0000000..9f21f3a
--- /dev/null
+++ b/Tests/CPackUseDefaultVersion/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.2)
+project(CPackUseProjectVersion NONE)
+
+include(CPack)
+
+message("CPACK_PACKAGE_VERSION=${CPACK_PACKAGE_VERSION}")
diff --git a/Tests/CPackUseProjectVersion/CMakeLists.txt b/Tests/CPackUseProjectVersion/CMakeLists.txt
new file mode 100644
index 0000000..d4770ae
--- /dev/null
+++ b/Tests/CPackUseProjectVersion/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.2)
+project(CPackUseProjectVersion VERSION 1.2.3 LANGUAGES NONE)
+
+include(CPack)
+
+message("CPACK_PACKAGE_VERSION=${CPACK_PACKAGE_VERSION}")
diff --git a/Tests/CPackUseShortProjectVersion/CMakeLists.txt b/Tests/CPackUseShortProjectVersion/CMakeLists.txt
new file mode 100644
index 0000000..855bc64
--- /dev/null
+++ b/Tests/CPackUseShortProjectVersion/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.2)
+project(CPackUseProjectVersion VERSION 2 LANGUAGES NONE)
+
+include(CPack)
+
+message("CPACK_PACKAGE_VERSION=${CPACK_PACKAGE_VERSION}")
diff --git a/Tests/CPackWiXGenerator/CMakeLists.txt b/Tests/CPackWiXGenerator/CMakeLists.txt
new file mode 100644
index 0000000..2249d70
--- /dev/null
+++ b/Tests/CPackWiXGenerator/CMakeLists.txt
@@ -0,0 +1,119 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(CPackWiXGenerator)
+
+add_library(mylib mylib.cpp)
+
+add_executable(my-libapp mylibapp.cpp)
+target_link_libraries(my-libapp mylib)
+
+add_executable(my-other-app myotherapp.cpp)
+
+file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/empty)
+install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/empty
+ DESTINATION extras
+ COMPONENT extras)
+
+install(TARGETS mylib
+ ARCHIVE
+ DESTINATION lib
+ COMPONENT libraries)
+
+install(TARGETS my-libapp
+ RUNTIME
+ DESTINATION bin
+ COMPONENT applications)
+
+install(TARGETS my-other-app
+ RUNTIME
+ DESTINATION bin
+ COMPONENT applications2)
+
+install(FILES mylib.h "file with spaces.h"
+ DESTINATION include
+ COMPONENT headers)
+
+set(CPACK_GENERATOR "WIX")
+
+set(CPACK_PACKAGE_NAME "MyLib")
+set(CPACK_PACKAGE_VENDOR "CMake.org")
+set(CPACK_PACKAGE_CONTACT "somebody@cmake.org")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY
+ "MyLib - CPack Component Installation Example")
+
+set(CPACK_PACKAGE_VERSION_MAJOR "1")
+set(CPACK_PACKAGE_VERSION_MINOR "0")
+set(CPACK_PACKAGE_VERSION_PATCH "0")
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "CPack Component Example")
+
+set(CPACK_WIX_UPGRADE_GUID "BF20CE5E-7F7C-401D-8F7C-AB45E8D170E6")
+set(CPACK_WIX_UNINSTALL "1")
+
+# Support non-interactive sessions (like CI).
+set(CPACK_WIX_LIGHT_EXTRA_FLAGS "-sval")
+
+set(CPACK_PACKAGE_EXECUTABLES
+ "my-libapp" "CPack WiX Test"
+ "my-other-app" "Second CPack WiX Test"
+)
+
+set(CPACK_CREATE_DESKTOP_LINKS
+ "my-libapp"
+ "my-other-app"
+)
+
+set(CPACK_WIX_PATCH_FILE "${CMAKE_CURRENT_SOURCE_DIR}/patch.xml")
+
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt")
+
+set(CPACK_WIX_PROPERTY_ARPCOMMENTS "My Custom ARPCOMMENTS")
+set(CPACK_WIX_PROPERTY_ARPHELPLINK "https://cmake.org")
+
+include(CPack)
+
+cpack_add_install_type(Full DISPLAY_NAME "Everything")
+cpack_add_install_type(Developer)
+
+cpack_add_component_group(Runtime)
+
+cpack_add_component_group(Development
+ EXPANDED
+ DESCRIPTION "All of the tools you'll ever need to develop software")
+
+cpack_add_component(extras
+ DISPLAY_NAME "Extras"
+ DESCRIPTION "Extras"
+ GROUP Runtime
+ INSTALL_TYPES Full)
+
+cpack_add_component(applications
+ REQUIRED
+ DISPLAY_NAME "MyLib Application"
+ DESCRIPTION "An extremely useful application that makes use of MyLib"
+ GROUP Runtime
+ INSTALL_TYPES Full)
+
+cpack_add_component(applications2
+ DISPLAY_NAME "MyLib Extra Application"
+ DESCRIPTION "Another extremely useful application that makes use of MyLib"
+ GROUP Runtime
+ INSTALL_TYPES Full)
+
+cpack_add_component(documentation
+ DISPLAY_NAME "MyLib Documentation"
+ DESCRIPTION "The extensive suite of MyLib Application documentation files"
+ GROUP Runtime
+ INSTALL_TYPES Full)
+
+cpack_add_component(libraries
+ DISPLAY_NAME "Libraries"
+ DESCRIPTION "Static libraries used to build programs with MyLib"
+ GROUP Development
+ INSTALL_TYPES Developer Full)
+
+cpack_add_component(headers
+ DISPLAY_NAME "C++ Headers"
+ DESCRIPTION "C/C++ header files for use with MyLib"
+ GROUP Development
+ DEPENDS libraries
+ INSTALL_TYPES Developer Full)
diff --git a/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake b/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake
new file mode 100644
index 0000000..c549e61
--- /dev/null
+++ b/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake
@@ -0,0 +1,79 @@
+message(STATUS "=============================================================")
+message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+message(STATUS "")
+
+if(NOT CPackWiXGenerator_BINARY_DIR)
+ message(FATAL_ERROR "CPackWiXGenerator_BINARY_DIR not set")
+endif()
+
+message(STATUS "CMAKE_COMMAND: ${CMAKE_COMMAND}")
+message(STATUS "CMAKE_CPACK_COMMAND: ${CMAKE_CPACK_COMMAND}")
+message(STATUS "CPackWiXGenerator_BINARY_DIR: ${CPackWiXGenerator_BINARY_DIR}")
+
+if(config)
+ set(_C_config -C ${config})
+endif()
+
+execute_process(COMMAND "${CMAKE_CPACK_COMMAND}"
+ ${_C_config}
+ RESULT_VARIABLE CPack_result
+ OUTPUT_VARIABLE CPack_output
+ ERROR_VARIABLE CPack_error
+ WORKING_DIRECTORY "${CPackWiXGenerator_BINARY_DIR}")
+
+if(CPack_result)
+ message(FATAL_ERROR "CPack execution went wrong!, CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+else ()
+ message(STATUS "CPack_output=${CPack_output}")
+endif()
+
+set(expected_file_mask "*.msi")
+file(GLOB installer_file "${expected_file_mask}")
+
+message(STATUS "installer_file='${installer_file}'")
+message(STATUS "expected_file_mask='${expected_file_mask}'")
+
+if(NOT installer_file)
+ message(FATAL_ERROR "installer_file does not exist.")
+endif()
+
+function(run_wix_command command)
+ file(TO_CMAKE_PATH "$ENV{WIX}" WIX_ROOT)
+ set(WIX_PROGRAM "${WIX_ROOT}/bin/${command}.exe")
+
+ if(NOT EXISTS "${WIX_PROGRAM}")
+ message(FATAL_ERROR "Failed to find WiX Tool: ${WIX_PROGRAM}")
+ endif()
+
+ message(STATUS "Running WiX Tool: ${command} ${ARGN}")
+
+ execute_process(COMMAND "${WIX_PROGRAM}" ${ARGN}
+ RESULT_VARIABLE WIX_result
+ OUTPUT_VARIABLE WIX_output
+ ERROR_VARIABLE WIX_output
+ WORKING_DIRECTORY "${CPackWiXGenerator_BINARY_DIR}")
+
+ message(STATUS "${command} Output: \n${WIX_output}")
+
+ if(WIX_result)
+ message(FATAL_ERROR "WiX ${command} failed: ${WIX_result}")
+ endif()
+endfunction()
+
+file(GLOB WXS_SOURCE_FILES
+ "${CPackWiXGenerator_BINARY_DIR}/_CPack_Packages/*/WIX/*.wxs")
+
+if(NOT WXS_SOURCE_FILES)
+ message(FATAL_ERROR "Failed finding WiX source files to validate.")
+endif()
+
+foreach(WXS_SOURCE_FILE IN LISTS WXS_SOURCE_FILES)
+ run_wix_command(wixcop "${WXS_SOURCE_FILE}")
+endforeach()
+
+# error SMOK1076 : ICE61: This product should remove only older
+# versions of itself. The Maximum version is not less
+# than the current product. (1.0.0 1.0.0)
+if (NOT no_verify)
+ run_wix_command(smoke -nologo -wx -sw1076 "${installer_file}")
+endif ()
diff --git a/Tests/CPackWiXGenerator/file with spaces.h b/Tests/CPackWiXGenerator/file with spaces.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CPackWiXGenerator/file with spaces.h
diff --git a/Tests/CPackWiXGenerator/license.txt b/Tests/CPackWiXGenerator/license.txt
new file mode 100644
index 0000000..7942783
--- /dev/null
+++ b/Tests/CPackWiXGenerator/license.txt
@@ -0,0 +1,9 @@
+hello world
+merhaba dünya
+ハローワールド
+привет мир
+مرحبا العالم
+你好世界
+
+4-Byte sequences:
+ Perch (Fish) 𩶘 Elevator 𨋢!
diff --git a/Tests/CPackWiXGenerator/mylib.cpp b/Tests/CPackWiXGenerator/mylib.cpp
new file mode 100644
index 0000000..8d63071
--- /dev/null
+++ b/Tests/CPackWiXGenerator/mylib.cpp
@@ -0,0 +1,8 @@
+#include "mylib.h"
+
+#include "stdio.h"
+
+void mylib_function()
+{
+ printf("This is mylib");
+}
diff --git a/Tests/CPackWiXGenerator/mylib.h b/Tests/CPackWiXGenerator/mylib.h
new file mode 100644
index 0000000..5d0a822
--- /dev/null
+++ b/Tests/CPackWiXGenerator/mylib.h
@@ -0,0 +1 @@
+void mylib_function();
diff --git a/Tests/CPackWiXGenerator/mylibapp.cpp b/Tests/CPackWiXGenerator/mylibapp.cpp
new file mode 100644
index 0000000..a438ac7
--- /dev/null
+++ b/Tests/CPackWiXGenerator/mylibapp.cpp
@@ -0,0 +1,6 @@
+#include "mylib.h"
+
+int main()
+{
+ mylib_function();
+}
diff --git a/Tests/CPackWiXGenerator/myotherapp.cpp b/Tests/CPackWiXGenerator/myotherapp.cpp
new file mode 100644
index 0000000..5047a34
--- /dev/null
+++ b/Tests/CPackWiXGenerator/myotherapp.cpp
@@ -0,0 +1,3 @@
+int main()
+{
+}
diff --git a/Tests/CPackWiXGenerator/patch.xml b/Tests/CPackWiXGenerator/patch.xml
new file mode 100644
index 0000000..13c392d
--- /dev/null
+++ b/Tests/CPackWiXGenerator/patch.xml
@@ -0,0 +1,7 @@
+<CPackWiXPatch>
+ <CPackWiXFragment Id="CM_CP_applications.bin.my_libapp.exe">
+ <Environment Id="MyEnvironment" Action="set"
+ Name="CPackWiXGeneratorTest"
+ Value="CPackWiXGeneratorTest"/>
+ </CPackWiXFragment>
+</CPackWiXPatch>
diff --git a/Tests/CSharpLinkFromCxx/.gitattributes b/Tests/CSharpLinkFromCxx/.gitattributes
new file mode 100644
index 0000000..cf9d355
--- /dev/null
+++ b/Tests/CSharpLinkFromCxx/.gitattributes
@@ -0,0 +1 @@
+UsefulManagedCppClass.* -format.clang-format-6.0
diff --git a/Tests/CSharpLinkFromCxx/CMakeLists.txt b/Tests/CSharpLinkFromCxx/CMakeLists.txt
new file mode 100644
index 0000000..9a1a993
--- /dev/null
+++ b/Tests/CSharpLinkFromCxx/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Take a C# shared library and link it to a managed C++ shared library
+cmake_minimum_required(VERSION 3.10)
+project (CSharpLinkFromCxx CXX CSharp)
+
+add_library(CSharpLibrary SHARED UsefulCSharpClass.cs)
+
+# we have to change the default flags for the
+# managed C++ project to build
+string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
+string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
+
+# The C# project is a dependency of the C++/CLI project
+add_library(ManagedCppLibrary SHARED UsefulManagedCppClass.cpp UsefulManagedCppClass.hpp)
+target_compile_options(ManagedCppLibrary PRIVATE "/clr")
+target_link_libraries(ManagedCppLibrary PUBLIC CSharpLibrary)
+
+# Main executable for the test framework
+add_executable(CSharpLinkFromCxx CSharpLinkFromCxx.cs)
+target_link_libraries(CSharpLinkFromCxx PRIVATE ManagedCppLibrary)
diff --git a/Tests/CSharpLinkFromCxx/CSharpLinkFromCxx.cs b/Tests/CSharpLinkFromCxx/CSharpLinkFromCxx.cs
new file mode 100644
index 0000000..31a74eb
--- /dev/null
+++ b/Tests/CSharpLinkFromCxx/CSharpLinkFromCxx.cs
@@ -0,0 +1,16 @@
+using System;
+using CSharpLibrary;
+
+namespace CSharpLinkFromCxx
+{
+ internal class CSharpLinkFromCxx
+ {
+ public static void Main(string[] args)
+ {
+ Console.WriteLine("Starting test for CSharpLinkFromCxx");
+
+ var useful = new UsefulManagedCppClass();
+ useful.RunTest();
+ }
+ }
+}
diff --git a/Tests/CSharpLinkFromCxx/UsefulCSharpClass.cs b/Tests/CSharpLinkFromCxx/UsefulCSharpClass.cs
new file mode 100644
index 0000000..749e57d
--- /dev/null
+++ b/Tests/CSharpLinkFromCxx/UsefulCSharpClass.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace CSharpLibrary
+{
+ public class UsefulCSharpClass
+ {
+ public string GetSomethingUseful()
+ {
+ return "Something Useful";
+ }
+ }
+}
diff --git a/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.cpp b/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.cpp
new file mode 100644
index 0000000..9468812
--- /dev/null
+++ b/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.cpp
@@ -0,0 +1,15 @@
+#include "UsefulManagedCppClass.hpp"
+
+namespace CSharpLibrary
+{
+ UsefulManagedCppClass::UsefulManagedCppClass()
+ {
+ auto useful = gcnew UsefulCSharpClass();
+ m_usefulString = useful->GetSomethingUseful();
+ }
+
+ void UsefulManagedCppClass::RunTest()
+ {
+ Console::WriteLine("Printing from Managed CPP Class: " + m_usefulString);
+ }
+}
diff --git a/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.hpp b/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.hpp
new file mode 100644
index 0000000..def7cea
--- /dev/null
+++ b/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.hpp
@@ -0,0 +1,16 @@
+using namespace System;
+
+namespace CSharpLibrary
+{
+ public ref class UsefulManagedCppClass
+ {
+ public:
+
+ UsefulManagedCppClass();
+ void RunTest();
+
+ private:
+
+ String^ m_usefulString;
+ };
+}
diff --git a/Tests/CSharpLinkToCxx/CMakeLists.txt b/Tests/CSharpLinkToCxx/CMakeLists.txt
new file mode 100644
index 0000000..a3067af
--- /dev/null
+++ b/Tests/CSharpLinkToCxx/CMakeLists.txt
@@ -0,0 +1,29 @@
+# test if CSharp application correctly links
+# to managed C++ binary
+cmake_minimum_required(VERSION 3.9)
+project (CSharpLinkToCxx CXX CSharp)
+
+# we have to change the default flags for the
+# managed C++ project to build
+string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
+string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
+
+add_library(CLIApp SHARED cli.hpp cli.cpp)
+
+target_compile_options(CLIApp PRIVATE "/clr")
+
+add_executable(CSharpLinkToCxx csharp.cs)
+
+target_link_libraries(CSharpLinkToCxx CLIApp)
+
+# this unmanaged C++ library will be added to the C#/.NET
+# references of CSharpLinkToCxx but it will show a warning
+# because it is unmanaged
+add_library(CppNativeApp SHARED cpp_native.hpp cpp_native.cpp)
+target_link_libraries(CSharpLinkToCxx CppNativeApp)
+
+# Link a static C++ library into the CSharp executable.
+# We do not actually use any symbols but this helps cover
+# link language selection.
+add_library(CppStaticLib STATIC cpp_static.cpp)
+target_link_libraries(CSharpLinkToCxx CppStaticLib)
diff --git a/Tests/CSharpLinkToCxx/cli.cpp b/Tests/CSharpLinkToCxx/cli.cpp
new file mode 100644
index 0000000..97ac724
--- /dev/null
+++ b/Tests/CSharpLinkToCxx/cli.cpp
@@ -0,0 +1,10 @@
+#include "cli.hpp"
+
+using namespace System;
+
+namespace CLIApp {
+void MyCli::testMyCli()
+{
+ Console::WriteLine("#message from CLIApp");
+}
+}
diff --git a/Tests/CSharpLinkToCxx/cli.hpp b/Tests/CSharpLinkToCxx/cli.hpp
new file mode 100644
index 0000000..a8c116d
--- /dev/null
+++ b/Tests/CSharpLinkToCxx/cli.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+namespace CLIApp {
+public
+ref class MyCli
+{
+public:
+ void testMyCli();
+};
+}
diff --git a/Tests/CSharpLinkToCxx/cpp_native.cpp b/Tests/CSharpLinkToCxx/cpp_native.cpp
new file mode 100644
index 0000000..dc7670f
--- /dev/null
+++ b/Tests/CSharpLinkToCxx/cpp_native.cpp
@@ -0,0 +1,10 @@
+#include "cpp_native.hpp"
+
+#include <iostream>
+
+namespace CppApp {
+void MyCpp::testMyCpp()
+{
+ std::cout << "#message from CppApp" << std::endl;
+}
+}
diff --git a/Tests/CSharpLinkToCxx/cpp_native.hpp b/Tests/CSharpLinkToCxx/cpp_native.hpp
new file mode 100644
index 0000000..0fa1a3b
--- /dev/null
+++ b/Tests/CSharpLinkToCxx/cpp_native.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+namespace CppApp {
+class MyCpp
+{
+public:
+ void testMyCpp();
+};
+}
diff --git a/Tests/CSharpLinkToCxx/cpp_static.cpp b/Tests/CSharpLinkToCxx/cpp_static.cpp
new file mode 100644
index 0000000..9af2b6e
--- /dev/null
+++ b/Tests/CSharpLinkToCxx/cpp_static.cpp
@@ -0,0 +1,3 @@
+void cpp_static()
+{
+}
diff --git a/Tests/CSharpLinkToCxx/csharp.cs b/Tests/CSharpLinkToCxx/csharp.cs
new file mode 100644
index 0000000..35c5cc3
--- /dev/null
+++ b/Tests/CSharpLinkToCxx/csharp.cs
@@ -0,0 +1,16 @@
+using System;
+using CLIApp;
+
+namespace CSharpLinkToCxx
+{
+ internal class CSharpLinkToCxx
+ {
+ public static void Main(string[] args)
+ {
+ Console.WriteLine("#message from CSharpLinkToCxx");
+
+ var app = new MyCli();
+ app.testMyCli();
+ }
+ }
+}
diff --git a/Tests/CSharpOnly/CMakeLists.txt b/Tests/CSharpOnly/CMakeLists.txt
new file mode 100644
index 0000000..195af05
--- /dev/null
+++ b/Tests/CSharpOnly/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.3)
+# a simple CSharp only test case
+project (CSharpOnly CSharp)
+
+# C# does not make any difference between STATIC and SHARED libs
+add_library(lib1 STATIC lib1.cs nested/lib1.cs)
+#without the source group this test will fail to compile
+source_group(nested FILES nested/lib1.cs)
+add_library(lib2 SHARED lib2.cs)
+
+add_executable(CSharpOnly csharponly.cs)
+
+target_link_libraries(CSharpOnly lib1 lib2)
+
+add_custom_target(CSharpCustom ALL SOURCES empty.cs)
+add_custom_target(custom.cs ALL DEPENDS empty.txt)
diff --git a/Tests/CSharpOnly/csharponly.cs b/Tests/CSharpOnly/csharponly.cs
new file mode 100644
index 0000000..3890c82
--- /dev/null
+++ b/Tests/CSharpOnly/csharponly.cs
@@ -0,0 +1,13 @@
+namespace CSharpOnly
+{
+ class CSharpOnly
+ {
+ public static void Main(string[] args)
+ {
+ int val = Lib1.getResult();
+ Lib2 l = new Lib2();
+ val = val + l.myVal + nested.Lib1.getResult();
+ return;
+ }
+ }
+}
diff --git a/Tests/CSharpOnly/empty.cs b/Tests/CSharpOnly/empty.cs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CSharpOnly/empty.cs
diff --git a/Tests/CSharpOnly/empty.txt b/Tests/CSharpOnly/empty.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CSharpOnly/empty.txt
diff --git a/Tests/CSharpOnly/lib1.cs b/Tests/CSharpOnly/lib1.cs
new file mode 100644
index 0000000..7a7ae10
--- /dev/null
+++ b/Tests/CSharpOnly/lib1.cs
@@ -0,0 +1,10 @@
+namespace CSharpOnly
+{
+ public class Lib1
+ {
+ public static int getResult()
+ {
+ return 23;
+ }
+ }
+}
diff --git a/Tests/CSharpOnly/lib2.cs b/Tests/CSharpOnly/lib2.cs
new file mode 100644
index 0000000..b4b38ce
--- /dev/null
+++ b/Tests/CSharpOnly/lib2.cs
@@ -0,0 +1,10 @@
+namespace CSharpOnly
+{
+ public class Lib2
+ {
+ public int myVal = 42;
+
+ public Lib2()
+ {}
+ }
+}
diff --git a/Tests/CSharpOnly/nested/lib1.cs b/Tests/CSharpOnly/nested/lib1.cs
new file mode 100644
index 0000000..c2fde4b
--- /dev/null
+++ b/Tests/CSharpOnly/nested/lib1.cs
@@ -0,0 +1,13 @@
+namespace CSharpOnly
+{
+ namespace nested
+ {
+ public class Lib1
+ {
+ public static int getResult()
+ {
+ return 23;
+ }
+ }
+ }
+}
diff --git a/Tests/CSharpWin32GenEx/CMakeLists.txt b/Tests/CSharpWin32GenEx/CMakeLists.txt
new file mode 100644
index 0000000..f4a8d00
--- /dev/null
+++ b/Tests/CSharpWin32GenEx/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.18)
+project(CSharpWin32GenEx CSharp)
+
+add_executable(CSharpWin32GenEx csharpwin32genex.cs)
+set_property(TARGET CSharpWin32GenEx PROPERTY WIN32_EXECUTABLE $<1:1>)
diff --git a/Tests/CSharpWin32GenEx/csharpwin32genex.cs b/Tests/CSharpWin32GenEx/csharpwin32genex.cs
new file mode 100644
index 0000000..9892ee0
--- /dev/null
+++ b/Tests/CSharpWin32GenEx/csharpwin32genex.cs
@@ -0,0 +1,9 @@
+namespace CSharpWin32GenEx
+{
+ class CSharpWin32GenEx
+ {
+ public static void Main(string[] args)
+ {
+ }
+ }
+}
diff --git a/Tests/CTestBuildCommandProjectInSubdir/CTestBuildCommandProjectInSubdir.cmake.in b/Tests/CTestBuildCommandProjectInSubdir/CTestBuildCommandProjectInSubdir.cmake.in
new file mode 100644
index 0000000..0f56781
--- /dev/null
+++ b/Tests/CTestBuildCommandProjectInSubdir/CTestBuildCommandProjectInSubdir.cmake.in
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 2.8.10)
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/VSProjectInSubdir")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestBuildCommandProjectInSubdir/Nested")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_BUILD_CONFIGURATION "@CTestTest_CONFIG@")
+
+ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY})
+ctest_start(Experimental)
+ctest_configure(OPTIONS "@ctest_configure_options@")
+ctest_build(TARGET test)
diff --git a/Tests/CTestConfig/CMakeLists.txt b/Tests/CTestConfig/CMakeLists.txt
new file mode 100644
index 0000000..8c19adb
--- /dev/null
+++ b/Tests/CTestConfig/CMakeLists.txt
@@ -0,0 +1,56 @@
+cmake_minimum_required(VERSION 3.9)
+project(CTestConfig)
+
+include(CTest)
+
+
+# We expect this configure to occur through a 'ctest -D Experimental' or a
+# 'ctest -S script.cmake' call.
+#
+# In either case, we expect CMAKE_BUILD_TYPE to be defined for single-configuration
+# build trees and not defined for multi-configuration build trees. The value of
+# CMAKE_CONFIGURATION_TYPES should not be relied upon to determine whether we
+# are using a multi-config generator or not, the GENERATOR_IS_MULTI_CONFIG
+# global property is the canonical way to do that as of CMake 3.9.
+#
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ if(NOT DEFINED CMAKE_CONFIGURATION_TYPES OR CMAKE_CONFIGURATION_TYPES STREQUAL "")
+ message(FATAL_ERROR "CMAKE_CONFIGURATION_TYPES is not defined or is empty "
+ "(but must be defined and non-empty for a multi-configuration generator)")
+ endif()
+ if(DEFINED CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE STREQUAL "")
+ message(FATAL_ERROR "CMAKE_BUILD_TYPE='${CMAKE_BUILD_TYPE}' is defined and non-empty "
+ "(but should not be for a multi-configuration generator)")
+ endif()
+ set(_configs ${CMAKE_CONFIGURATION_TYPES})
+else()
+ # Populating CMAKE_CONFIGURATION_TYPES even for single config generators is
+ # common enough for user projects that we don't want to consider it an error.
+ # We just need CMAKE_BUILD_TYPE to be set and ignore CMAKE_CONFIGURATION_TYPES.
+ if(NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
+ message(FATAL_ERROR "CMAKE_BUILD_TYPE is not defined or is empty "
+ "(but should be defined and non-empty for a single-configuration generator)")
+ endif()
+ add_definitions(-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}")
+ set(_configs ${CMAKE_BUILD_TYPE})
+endif()
+
+add_executable(ctc CTestConfig.cxx)
+
+
+foreach(cfg ${_configs})
+ add_test(NAME ctc-${cfg} CONFIGURATIONS ${cfg} COMMAND ctc --config $<CONFIGURATION>)
+
+ if(_isMultiConfig)
+ set_property(TEST ctc-${cfg}
+ PROPERTY PASS_REGULAR_EXPRESSION "CMAKE_INTDIR is ${cfg}")
+ set_property(TEST ctc-${cfg}
+ PROPERTY FAIL_REGULAR_EXPRESSION "CMAKE_BUILD_TYPE is")
+ else()
+ set_property(TEST ctc-${cfg}
+ PROPERTY PASS_REGULAR_EXPRESSION "CMAKE_BUILD_TYPE is ${cfg}")
+ set_property(TEST ctc-${cfg}
+ PROPERTY FAIL_REGULAR_EXPRESSION "CMAKE_INTDIR is")
+ endif()
+endforeach()
diff --git a/Tests/CTestConfig/CTestConfig.cxx b/Tests/CTestConfig/CTestConfig.cxx
new file mode 100644
index 0000000..45c6c06
--- /dev/null
+++ b/Tests/CTestConfig/CTestConfig.cxx
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+int main(int argc, const char* argv[])
+{
+ int i = 0;
+ for (; i < argc; ++i) {
+ fprintf(stdout, "%s\n", argv[i]);
+ }
+
+#ifdef CMAKE_BUILD_TYPE
+ fprintf(stdout, "CMAKE_BUILD_TYPE is %s\n", CMAKE_BUILD_TYPE);
+#endif
+
+#ifdef CMAKE_INTDIR
+ fprintf(stdout, "CMAKE_INTDIR is %s\n", CMAKE_INTDIR);
+#endif
+
+ return 0;
+}
diff --git a/Tests/CTestConfig/ScriptWithArgs.cmake b/Tests/CTestConfig/ScriptWithArgs.cmake
new file mode 100644
index 0000000..79896a7
--- /dev/null
+++ b/Tests/CTestConfig/ScriptWithArgs.cmake
@@ -0,0 +1,16 @@
+set(CTEST_RUN_CURRENT_SCRIPT 0)
+
+macro(check_arg name expected_value)
+ message("${name}='${${name}}'")
+ if(NOT "${${name}}" STREQUAL "${expected_value}")
+ message(FATAL_ERROR "unexpected ${name} value '${${name}}', expected '${expected_value}'")
+ endif()
+endmacro()
+
+check_arg(arg1 "this")
+check_arg(arg2 "that")
+check_arg(arg3 "the other")
+check_arg(arg4 "this is the fourth")
+check_arg(arg5 "the_fifth")
+check_arg(arg6 "value-with-type")
+check_arg(arg7 "")
diff --git a/Tests/CTestConfig/dashboard.cmake.in b/Tests/CTestConfig/dashboard.cmake.in
new file mode 100644
index 0000000..34824e3
--- /dev/null
+++ b/Tests/CTestConfig/dashboard.cmake.in
@@ -0,0 +1,49 @@
+set(_isMultiConfig "@_isMultiConfig@")
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestConfig")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestConfig/@cfg@-dashboard")
+
+file(MAKE_DIRECTORY "${CTEST_BINARY_DIRECTORY}")
+
+get_filename_component(dir "${CMAKE_COMMAND}" PATH)
+set(CMAKE_CTEST_COMMAND "${dir}/ctest")
+
+message("CMAKE_COMMAND='${CMAKE_COMMAND}'")
+message("CMAKE_CTEST_COMMAND='${CMAKE_CTEST_COMMAND}'")
+
+set(arg "")
+if(NOT _isMultiConfig)
+ set(arg "-DCMAKE_BUILD_TYPE:STRING=@cfg@")
+else()
+ set(arg "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release\\;MinSizeRel\\;RelWithDebInfo")
+endif()
+
+message("cmake initial configure")
+execute_process(COMMAND ${CMAKE_COMMAND}
+ ${arg}
+ -G "@CMAKE_GENERATOR@"
+ -A "@CMAKE_GENERATOR_PLATFORM@"
+ -T "@CMAKE_GENERATOR_TOOLSET@"
+ ${CTEST_SOURCE_DIRECTORY}
+ WORKING_DIRECTORY ${CTEST_BINARY_DIRECTORY}
+ RESULT_VARIABLE rv)
+if(NOT rv STREQUAL 0)
+ message(FATAL_ERROR "error calling cmake: rv='${rv}'")
+endif()
+
+
+function(call_ctest arg)
+ message("call_ctest ${arg}")
+ execute_process(COMMAND ${CMAKE_CTEST_COMMAND}
+ -C "@cfg@" -D ${arg} -VV
+ WORKING_DIRECTORY ${CTEST_BINARY_DIRECTORY}
+ RESULT_VARIABLE rv)
+ if(NOT rv STREQUAL 0)
+ message(FATAL_ERROR "error calling ctest: rv='${rv}'")
+ endif()
+endfunction()
+
+
+call_ctest(ExperimentalStart)
+call_ctest(ExperimentalConfigure)
+call_ctest(ExperimentalBuild)
+call_ctest(ExperimentalTest)
diff --git a/Tests/CTestConfig/script.cmake.in b/Tests/CTestConfig/script.cmake.in
new file mode 100644
index 0000000..59c585b
--- /dev/null
+++ b/Tests/CTestConfig/script.cmake.in
@@ -0,0 +1,29 @@
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestConfig")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestConfig/@cfg@-script")
+
+ctest_start(Experimental)
+
+set(_isMultiConfig "@_isMultiConfig@")
+if(_isMultiConfig)
+ set(cfg_opts "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release\\;MinSizeRel\\;RelWithDebInfo")
+else()
+ set(cfg_opts)
+endif()
+
+ctest_configure(BUILD "${CTEST_BINARY_DIRECTORY}" OPTIONS "${cfg_opts}" RETURN_VALUE rv)
+if(NOT rv STREQUAL 0)
+ message(FATAL_ERROR "*** error in ctest_configure ***")
+endif()
+
+ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE rv)
+if(NOT rv STREQUAL 0)
+ message(FATAL_ERROR "*** error in ctest_build ***")
+endif()
+
+ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE rv)
+if(NOT rv STREQUAL 0)
+ message(FATAL_ERROR "*** error in ctest_test ***")
+endif()
diff --git a/Tests/CTestCoverageCollectGCOV/TestProject/3rdparty/foo.cpp b/Tests/CTestCoverageCollectGCOV/TestProject/3rdparty/foo.cpp
new file mode 100644
index 0000000..3695dc9
--- /dev/null
+++ b/Tests/CTestCoverageCollectGCOV/TestProject/3rdparty/foo.cpp
@@ -0,0 +1,3 @@
+void foo()
+{
+}
diff --git a/Tests/CTestCoverageCollectGCOV/TestProject/CMakeLists.txt b/Tests/CTestCoverageCollectGCOV/TestProject/CMakeLists.txt
new file mode 100644
index 0000000..ce6fac4
--- /dev/null
+++ b/Tests/CTestCoverageCollectGCOV/TestProject/CMakeLists.txt
@@ -0,0 +1,41 @@
+cmake_minimum_required(VERSION 3.2)
+
+project(TestProject CXX)
+
+include(CTest)
+
+set(SOURCES
+ main.cpp
+ 3rdparty/foo.cpp
+ extra/extra.cpp
+)
+
+add_executable(myexecutable ${SOURCES})
+
+set_property(SOURCE main.cpp APPEND PROPERTY LABELS SourceLabel)
+set_property(TARGET myexecutable APPEND PROPERTY LABELS TargetLabel)
+
+set(MYEXECUTABLE_INFO_FILE "${CMAKE_CURRENT_BINARY_DIR}/myexecutable_info.cmake")
+
+file(WRITE "${MYEXECUTABLE_INFO_FILE}" "
+ set(TARGET myexecutable)
+ set(SOURCE_DIR \"${CMAKE_CURRENT_SOURCE_DIR}\")
+ set(SOURCES \"${SOURCES}\")
+")
+
+add_custom_command(TARGET myexecutable
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ "-DINFO_FILE=${MYEXECUTABLE_INFO_FILE}"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/fake_compile_time_gcno.cmake"
+ VERBATIM
+)
+
+add_test(NAME mytest
+ COMMAND ${CMAKE_COMMAND}
+ "-DMYEXECUTABLE=$<TARGET_FILE:myexecutable>"
+ "-DTARGETDIR=${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/myexecutable.dir"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/fake_run_time_gcda.cmake"
+)
+
+set_property(TEST mytest APPEND PROPERTY LABELS TestLabel)
diff --git a/Tests/CTestCoverageCollectGCOV/TestProject/extra/extra.cpp b/Tests/CTestCoverageCollectGCOV/TestProject/extra/extra.cpp
new file mode 100644
index 0000000..89c1a66
--- /dev/null
+++ b/Tests/CTestCoverageCollectGCOV/TestProject/extra/extra.cpp
@@ -0,0 +1,3 @@
+void extra()
+{
+}
diff --git a/Tests/CTestCoverageCollectGCOV/TestProject/extra/uncovered1.cpp b/Tests/CTestCoverageCollectGCOV/TestProject/extra/uncovered1.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CTestCoverageCollectGCOV/TestProject/extra/uncovered1.cpp
diff --git a/Tests/CTestCoverageCollectGCOV/TestProject/fake_compile_time_gcno.cmake b/Tests/CTestCoverageCollectGCOV/TestProject/fake_compile_time_gcno.cmake
new file mode 100644
index 0000000..881460b
--- /dev/null
+++ b/Tests/CTestCoverageCollectGCOV/TestProject/fake_compile_time_gcno.cmake
@@ -0,0 +1,7 @@
+include("${INFO_FILE}")
+
+foreach(source ${SOURCES})
+ file(WRITE "CMakeFiles/${TARGET}.dir/${source}.gcno"
+ "${SOURCE_DIR}/${source}"
+ )
+endforeach()
diff --git a/Tests/CTestCoverageCollectGCOV/TestProject/fake_run_time_gcda.cmake b/Tests/CTestCoverageCollectGCOV/TestProject/fake_run_time_gcda.cmake
new file mode 100644
index 0000000..26ce2bd
--- /dev/null
+++ b/Tests/CTestCoverageCollectGCOV/TestProject/fake_run_time_gcda.cmake
@@ -0,0 +1,12 @@
+execute_process(COMMAND ${MYEXECUTABLE} RESULT_VARIABLE RESULT)
+
+if(NOT RESULT_VARIABLE STREQUAL "0")
+ message("Test failure")
+endif()
+
+file(GLOB_RECURSE gcno_files "${TARGETDIR}/*.gcno")
+
+foreach(gcno_file ${gcno_files})
+ string(REPLACE ".gcno" ".gcda" gcda_file "${gcno_file}")
+ configure_file(${gcno_file} ${gcda_file} COPYONLY)
+endforeach()
diff --git a/Tests/CTestCoverageCollectGCOV/TestProject/main.cpp b/Tests/CTestCoverageCollectGCOV/TestProject/main.cpp
new file mode 100644
index 0000000..5047a34
--- /dev/null
+++ b/Tests/CTestCoverageCollectGCOV/TestProject/main.cpp
@@ -0,0 +1,3 @@
+int main()
+{
+}
diff --git a/Tests/CTestCoverageCollectGCOV/TestProject/uncovered2.cpp b/Tests/CTestCoverageCollectGCOV/TestProject/uncovered2.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CTestCoverageCollectGCOV/TestProject/uncovered2.cpp
diff --git a/Tests/CTestCoverageCollectGCOV/fakegcov.cmake b/Tests/CTestCoverageCollectGCOV/fakegcov.cmake
new file mode 100644
index 0000000..6df4292
--- /dev/null
+++ b/Tests/CTestCoverageCollectGCOV/fakegcov.cmake
@@ -0,0 +1,17 @@
+function(create_gcov_file gcda_full_path)
+ get_filename_component(gcda_name ${gcda_full_path} NAME)
+ string(REPLACE ".gcda" ".gcov" gcov_name "${gcda_name}")
+
+ file(STRINGS "${gcda_full_path}" source_file LIMIT_COUNT 1 ENCODING UTF-8)
+
+ file(WRITE "${CMAKE_SOURCE_DIR}/${gcov_name}"
+ " -: 0:Source:${source_file}"
+ )
+endfunction()
+
+foreach(I RANGE 0 ${CMAKE_ARGC})
+ if("${CMAKE_ARGV${I}}" MATCHES ".*\\.gcda")
+ set(gcda_file "${CMAKE_ARGV${I}}")
+ create_gcov_file(${gcda_file})
+ endif()
+endforeach()
diff --git a/Tests/CTestCoverageCollectGCOV/test.cmake.in b/Tests/CTestCoverageCollectGCOV/test.cmake.in
new file mode 100644
index 0000000..a36f374
--- /dev/null
+++ b/Tests/CTestCoverageCollectGCOV/test.cmake.in
@@ -0,0 +1,198 @@
+cmake_minimum_required(VERSION 2.8.12)
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestCoverageCollectGCOV/TestProject")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestCoverageCollectGCOV/TestProject")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+
+ctest_start(Experimental)
+ctest_configure()
+ctest_build()
+ctest_test()
+
+#------------------------------------------------------------------------------#
+# Common setup for all tests.
+#------------------------------------------------------------------------------#
+
+list(APPEND CTEST_CUSTOM_COVERAGE_EXCLUDE
+ "/foo/something"
+ "/3rdparty/"
+ "/bar/somethingelse"
+ "/CMakeFiles/"
+)
+list(APPEND CTEST_EXTRA_COVERAGE_GLOB "*.cpp")
+include(CTestCoverageCollectGCOV)
+set(expected_out
+ CMakeFiles/myexecutable.dir/Labels.json
+ Testing/CoverageInfo/data.json
+ Testing/CoverageInfo/extra.cpp.gcov
+ Testing/CoverageInfo/main.cpp.gcov
+ uncovered/extra/uncovered1.cpp
+ uncovered/uncovered2.cpp
+)
+
+# A symbolic link in the path can cause tar to put an equivalent, but not
+# minimal file name to some files in the tar file. Convert paths to absolute
+# then back to relative to get them in canonical form (or maybe this is a bug
+# in how the tarball is generated?)
+function(to_relative_paths real_paths paths)
+ foreach(file ${paths})
+ file(REAL_PATH "${file}" real_path BASE_DIRECTORY "${CTEST_BINARY_DIRECTORY}")
+ file(RELATIVE_PATH relative_path "${CTEST_BINARY_DIRECTORY}" "${real_path}")
+ list(APPEND local_real_paths "${relative_path}")
+ message(DEBUG "${file} -> ${real_path} -> ${relative_path}")
+ endforeach()
+ set("${real_paths}" "${local_real_paths}" PARENT_SCOPE)
+endfunction()
+
+#------------------------------------------------------------------------------#
+# Test 1: with standard arguments
+#------------------------------------------------------------------------------#
+
+set(tar_file ${CTEST_BINARY_DIRECTORY}/gcov.tbz)
+ctest_coverage_collect_gcov(
+ TARBALL "${tar_file}"
+ SOURCE "${CTEST_SOURCE_DIRECTORY}"
+ BUILD "${CTEST_BINARY_DIRECTORY}"
+ GCOV_COMMAND "${CMAKE_COMMAND}"
+ GCOV_OPTIONS -P "@CMake_SOURCE_DIR@/Tests/CTestCoverageCollectGCOV/fakegcov.cmake")
+file(REMOVE_RECURSE "${CTEST_BINARY_DIRECTORY}/uncovered")
+
+execute_process(COMMAND
+ ${CMAKE_COMMAND} -E tar tf ${tar_file}
+ OUTPUT_VARIABLE out
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+
+string(REPLACE "\n" ";" out "${out}")
+to_relative_paths(out "${out}")
+list(SORT out)
+
+if("${out}" STREQUAL "${expected_out}")
+ message("PASSED with correct output: ${out}")
+else()
+ message(FATAL_ERROR "FAILED: expected:\n${expected_out}\nGot:\n${out}")
+endif()
+
+#------------------------------------------------------------------------------#
+# Test 2: with optional argument: TARBALL_COMPRESSION "GZIP"
+#------------------------------------------------------------------------------#
+
+set(tar_file ${CTEST_BINARY_DIRECTORY}/gcov.tgz)
+ctest_coverage_collect_gcov(
+ TARBALL "${tar_file}"
+ TARBALL_COMPRESSION "GZIP"
+ SOURCE "${CTEST_SOURCE_DIRECTORY}"
+ BUILD "${CTEST_BINARY_DIRECTORY}"
+ GCOV_COMMAND "${CMAKE_COMMAND}"
+ GCOV_OPTIONS -P "@CMake_SOURCE_DIR@/Tests/CTestCoverageCollectGCOV/fakegcov.cmake")
+file(REMOVE_RECURSE "${CTEST_BINARY_DIRECTORY}/uncovered")
+
+execute_process(COMMAND
+ ${CMAKE_COMMAND} -E tar tf ${tar_file}
+ OUTPUT_VARIABLE out
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+
+string(REPLACE "\n" ";" out "${out}")
+to_relative_paths(out "${out}")
+list(SORT out)
+
+if("${out}" STREQUAL "${expected_out}")
+ message("PASSED with correct output: ${out}")
+else()
+ message(FATAL_ERROR "FAILED: expected:\n${expected_out}\nGot:\n${out}")
+endif()
+
+#------------------------------------------------------------------------------#
+# Test 3: with optional argument: TARBALL_COMPRESSION "FROM_EXT"
+#------------------------------------------------------------------------------#
+
+set(tar_file ${CTEST_BINARY_DIRECTORY}/gcov.txz)
+ctest_coverage_collect_gcov(
+ TARBALL "${tar_file}"
+ TARBALL_COMPRESSION "FROM_EXT"
+ SOURCE "${CTEST_SOURCE_DIRECTORY}"
+ BUILD "${CTEST_BINARY_DIRECTORY}"
+ GCOV_COMMAND "${CMAKE_COMMAND}"
+ GCOV_OPTIONS -P "@CMake_SOURCE_DIR@/Tests/CTestCoverageCollectGCOV/fakegcov.cmake")
+file(REMOVE_RECURSE "${CTEST_BINARY_DIRECTORY}/uncovered")
+
+execute_process(COMMAND
+ ${CMAKE_COMMAND} -E tar tf ${tar_file}
+ OUTPUT_VARIABLE out
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+
+string(REPLACE "\n" ";" out "${out}")
+to_relative_paths(out "${out}")
+list(SORT out)
+
+if("${out}" STREQUAL "${expected_out}")
+ message("PASSED with correct output: ${out}")
+else()
+ message(FATAL_ERROR "FAILED: expected:\n${expected_out}\nGot:\n${out}")
+endif()
+
+#------------------------------------------------------------------------------#
+# Test 4: with optional argument: TARBALL_COMPRESSION "FALSE"
+#------------------------------------------------------------------------------#
+
+set(tar_file ${CTEST_BINARY_DIRECTORY}/gcov.tar)
+ctest_coverage_collect_gcov(
+ TARBALL "${tar_file}"
+ TARBALL_COMPRESSION "FALSE"
+ SOURCE "${CTEST_SOURCE_DIRECTORY}"
+ BUILD "${CTEST_BINARY_DIRECTORY}"
+ GCOV_COMMAND "${CMAKE_COMMAND}"
+ GCOV_OPTIONS -P "@CMake_SOURCE_DIR@/Tests/CTestCoverageCollectGCOV/fakegcov.cmake")
+file(REMOVE_RECURSE "${CTEST_BINARY_DIRECTORY}/uncovered")
+
+execute_process(COMMAND
+ ${CMAKE_COMMAND} -E tar tf ${tar_file}
+ OUTPUT_VARIABLE out
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+
+string(REPLACE "\n" ";" out "${out}")
+to_relative_paths(out "${out}")
+list(SORT out)
+
+if("${out}" STREQUAL "${expected_out}")
+ message("PASSED with correct output: ${out}")
+else()
+ message(FATAL_ERROR "FAILED: expected:\n${expected_out}\nGot:\n${out}")
+endif()
+
+#------------------------------------------------------------------------------#
+# Test 5: with optional argument: TARBALL_COMPRESSION "ZSTD"
+#------------------------------------------------------------------------------#
+
+set(tar_file ${CTEST_BINARY_DIRECTORY}/gcov.zstd)
+ctest_coverage_collect_gcov(
+ TARBALL "${tar_file}"
+ TARBALL_COMPRESSION "ZSTD"
+ SOURCE "${CTEST_SOURCE_DIRECTORY}"
+ BUILD "${CTEST_BINARY_DIRECTORY}"
+ GCOV_COMMAND "${CMAKE_COMMAND}"
+ GCOV_OPTIONS -P "@CMake_SOURCE_DIR@/Tests/CTestCoverageCollectGCOV/fakegcov.cmake")
+file(REMOVE_RECURSE "${CTEST_BINARY_DIRECTORY}/uncovered")
+
+execute_process(COMMAND
+ ${CMAKE_COMMAND} -E tar tf ${tar_file}
+ OUTPUT_VARIABLE out
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+
+string(REPLACE "\n" ";" out "${out}")
+to_relative_paths(out "${out}")
+list(SORT out)
+
+if("${out}" STREQUAL "${expected_out}")
+ message("PASSED with correct output: ${out}")
+else()
+ message(FATAL_ERROR "FAILED: expected:\n${expected_out}\nGot:\n${out}")
+endif()
diff --git a/Tests/CTestLimitDashJ/CMakeLists.txt b/Tests/CTestLimitDashJ/CMakeLists.txt
new file mode 100644
index 0000000..d04b3ad
--- /dev/null
+++ b/Tests/CTestLimitDashJ/CMakeLists.txt
@@ -0,0 +1,50 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(CTestLimitDashJ NONE)
+
+# This file demonstrates https://gitlab.kitware.com/cmake/cmake/-/issues/12904
+# when configured with CMake 2.8.10.2 and earlier, and when running
+# "ctest -j 4" in the resulting build tree. This example is hard-coded
+# to assume -j 4 just to reproduce the issue easily. Adjust the
+# FAIL_REGULAR_EXPRESSION and PROCESSORS values to reproduce this problem
+# with a different ctest -j value...
+
+if(EXISTS "${CMAKE_BINARY_DIR}/Testing/Temporary/CTestCostData.txt")
+ message(STATUS "Removing CTestCostData.txt to force ordering by COST PROPERTY value rather than prior run data")
+ file(REMOVE "${CMAKE_BINARY_DIR}/Testing/Temporary/CTestCostData.txt")
+endif()
+
+include(CTest)
+
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/CreateSleepDelete.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/CreateSleepDelete.cmake
+ @ONLY
+ )
+
+foreach(n RANGE 1 100)
+ add_test(NAME t${n}
+ COMMAND ${CMAKE_CTEST_COMMAND}
+ -D basefilename=f${n}
+ -S ${CMAKE_CURRENT_BINARY_DIR}/CreateSleepDelete.cmake
+ )
+ set_property(TEST t${n} PROPERTY FAIL_REGULAR_EXPRESSION "(c='[5-9]'|c='[1-9][0-9]+')")
+endforeach()
+
+set_property(TEST t1 PROPERTY RUN_SERIAL 1)
+set_property(TEST t1 PROPERTY PROCESSORS 4)
+
+set_property(TEST t51 PROPERTY RUN_SERIAL 1)
+set_property(TEST t51 PROPERTY PROCESSORS 4)
+
+foreach(n RANGE 2 50)
+ set_property(TEST t${n} PROPERTY DEPENDS t1)
+endforeach()
+set_property(TEST t1 PROPERTY DEPENDS t51)
+set_property(TEST t51 PROPERTY DEPENDS t100)
+
+foreach(n 50)
+ set_property(TEST t${n} PROPERTY COST 6)
+endforeach()
+foreach(n RANGE 52 99)
+ set_property(TEST t${n} PROPERTY COST 3)
+endforeach()
diff --git a/Tests/CTestLimitDashJ/CreateSleepDelete.cmake b/Tests/CTestLimitDashJ/CreateSleepDelete.cmake
new file mode 100644
index 0000000..b09307f
--- /dev/null
+++ b/Tests/CTestLimitDashJ/CreateSleepDelete.cmake
@@ -0,0 +1,48 @@
+set(CTEST_RUN_CURRENT_SCRIPT 0)
+
+if(NOT DEFINED basefilename)
+ message(FATAL_ERROR "pass -Dbasefilename=f1")
+endif()
+
+if(NOT DEFINED ext)
+ set(ext "jkqvxz")
+endif()
+
+if(NOT DEFINED sleep_interval)
+ set(sleep_interval 1)
+endif()
+
+get_filename_component(self_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
+set(filename "${self_dir}/${basefilename}.${ext}")
+
+# count files
+file(GLOB f1 *.${ext})
+list(LENGTH f1 c1)
+message("c='${c1}'")
+
+# write a new file
+message("Writing file: filename='${filename}'")
+file(WRITE "${filename}" "${filename}")
+
+# count files again
+file(GLOB f2 *.${ext})
+list(LENGTH f2 c2)
+message("c='${c2}'")
+
+# snooze
+message("Sleeping: sleep_interval='${sleep_interval}'")
+ctest_sleep(${sleep_interval})
+
+# count files again
+file(GLOB f3 *.${ext})
+list(LENGTH f3 c3)
+message("c='${c3}'")
+
+# delete the file we wrote earlier
+message("Removing file: filename='${filename}'")
+file(REMOVE "${filename}")
+
+# count files again
+file(GLOB f4 *.${ext})
+list(LENGTH f4 c4)
+message("c='${c4}'")
diff --git a/Tests/CTestScriptMode/CTestTestScriptMode.cmake.in b/Tests/CTestScriptMode/CTestTestScriptMode.cmake.in
new file mode 100644
index 0000000..45f0e37
--- /dev/null
+++ b/Tests/CTestScriptMode/CTestTestScriptMode.cmake.in
@@ -0,0 +1,14 @@
+# This script will be executed with ctest -S
+
+# Check that the system name is determined correctly:
+set(CMAKE_CMAKE_SYSTEM_NAME "@CMAKE_SYSTEM_NAME@")
+
+if (NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "${CMAKE_CMAKE_SYSTEM_NAME}")
+ message(FATAL_ERROR "Error: CMAKE_SYSTEM_NAME is \"${CMAKE_SYSTEM_NAME}\", but should be \"@CMAKE_SYSTEM_NAME@\"")
+endif()
+
+# this seems to be necessary, otherwise ctest complains that these
+# variables are not set:
+set(CTEST_COMMAND "\"@CMAKE_CTEST_COMMAND@\"")
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestScriptMode/")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestScriptMode/")
diff --git a/Tests/CTestTest/SmallAndFast/CMakeLists.txt b/Tests/CTestTest/SmallAndFast/CMakeLists.txt
new file mode 100644
index 0000000..06cbafd
--- /dev/null
+++ b/Tests/CTestTest/SmallAndFast/CMakeLists.txt
@@ -0,0 +1,25 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(SmallAndFast)
+
+include(CTest)
+
+add_executable(echoargs echoargs.c)
+set_property(SOURCE echoargs.c APPEND PROPERTY LABELS SourceLabel Everything)
+set_property(TARGET echoargs APPEND PROPERTY LABELS TargetLabel Everything)
+
+add_test(test0 echoargs)
+set_property(TEST test0 APPEND PROPERTY LABELS TestLabel 0ArgTest Everything)
+
+add_test(test1 echoargs 1)
+set_property(TEST test1 APPEND PROPERTY LABELS TestLabel 1ArgTest Everything)
+
+add_test(test2 echoargs 1 2)
+set_property(TEST test2 APPEND PROPERTY LABELS TestLabel 2ArgTest Everything)
+
+if(SAF_INTENTIONAL_COMPILE_ERROR)
+ add_executable(ice intentional_compile_error.cxx)
+endif()
+
+if(SAF_INTENTIONAL_COMPILE_WARNING)
+ add_executable(icw intentional_compile_warning.cxx)
+endif()
diff --git a/Tests/CTestTest/SmallAndFast/echoargs.c b/Tests/CTestTest/SmallAndFast/echoargs.c
new file mode 100644
index 0000000..19063b4
--- /dev/null
+++ b/Tests/CTestTest/SmallAndFast/echoargs.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+int main(int argc, const char* argv[])
+{
+ int i = 0;
+ for (; i < argc; ++i) {
+ fprintf(stdout, "%s\n", argv[i]);
+ }
+ return 0;
+}
diff --git a/Tests/CTestTest/SmallAndFast/intentional_compile_error.cxx b/Tests/CTestTest/SmallAndFast/intentional_compile_error.cxx
new file mode 100644
index 0000000..a8930cf
--- /dev/null
+++ b/Tests/CTestTest/SmallAndFast/intentional_compile_error.cxx
@@ -0,0 +1 @@
+garbage - obviously this should not compile as is
diff --git a/Tests/CTestTest/SmallAndFast/intentional_compile_warning.cxx b/Tests/CTestTest/SmallAndFast/intentional_compile_warning.cxx
new file mode 100644
index 0000000..d2396b7
--- /dev/null
+++ b/Tests/CTestTest/SmallAndFast/intentional_compile_warning.cxx
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+int main(int argc, const char* argv[])
+{
+ unsigned int i =
+ 0; // "i<argc" should produce a "signed/unsigned comparison" warning
+ for (; i < argc; ++i) {
+ fprintf(stdout, "%s\n", argv[i]);
+ }
+ return 0;
+}
diff --git a/Tests/CTestTest/test.cmake.in b/Tests/CTestTest/test.cmake.in
new file mode 100644
index 0000000..23166a7
--- /dev/null
+++ b/Tests/CTestTest/test.cmake.in
@@ -0,0 +1,70 @@
+# please see common.cmake for more documentation
+###################################################################
+# The values in this section must always be provided
+###################################################################
+
+# this is the cvs module name that should be checked out
+set (CTEST_MODULE_NAME SmallAndFast)
+
+# these are the name of the source and binary directory on disk.
+# They will be appended to DASHBOARD_ROOT
+set (CTEST_SOURCE_NAME SmallAndFast)
+set (CTEST_BINARY_NAME SmallAndFastBuild)
+
+# which ctest command to use for running the dashboard
+set (CTEST_COMMAND
+ "\"${CTEST_EXECUTABLE_NAME}\" --version"
+ "\"${CTEST_EXECUTABLE_NAME}\" -D Experimental -A \"${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}\""
+ )
+
+# what cmake command to use for configuring this dashboard
+get_filename_component(CTEST_EXECUTABLE_PATH "${CTEST_EXECUTABLE_NAME}" PATH)
+set(CTEST_CMAKE_COMMAND "\"${CTEST_EXECUTABLE_PATH}/cmake\"")
+
+message("CTest executable: ${CTEST_EXECUTABLE_NAME}")
+message("CMake executable: ${CTEST_CMAKE_COMMAND}")
+
+CTEST_SLEEP(1)
+CTEST_SLEEP(1 1 1)
+
+####################################################################
+# The values in this section are optional you can either
+# have them or leave them commented out
+####################################################################
+
+# should ctest wipe the binary tree before running
+set (CTEST_START_WITH_EMPTY_BINARY_DIRECTORY TRUE)
+
+# this is the initial cache to use for the binary tree, be careful to escape
+# any quotes inside of this string if you use it
+set (CTEST_INITIAL_CACHE "
+SITE:STRING=@SITE@
+BUILDNAME:STRING=SmallAndFast-@BUILDNAME@
+CMAKE_GENERATOR:INTERNAL=@CMAKE_GENERATOR@
+CMAKE_GENERATOR_PLATFORM:INTERNAL=@CMAKE_GENERATOR_PLATFORM@
+CMAKE_GENERATOR_TOOLSET:INTERNAL=@CMAKE_GENERATOR_TOOLSET@
+CMAKE_CXX_FLAGS:STRING=@CMAKE_CXX_FLAGS@
+CMAKE_C_FLAGS:STRING=@CMAKE_C_FLAGS@
+CMAKE_C_COMPILER:STRING=@CMAKE_C_COMPILER@
+CMAKE_CXX_COMPILER:STRING=@CMAKE_CXX_COMPILER@
+CMAKE_C_COMPILER_ARG1:STRING=@CMAKE_C_COMPILER_ARG1@
+CMAKE_CXX_COMPILER_ARG1:STRING=@CMAKE_CXX_COMPILER_ARG1@
+DART_ROOT:PATH=
+MEMORYCHECK_COMMAND:STRING=@MEMORYCHECK_COMMAND@
+MEMORYCHECK_SUPPRESSIONS_FILE:FILEPATH=@MEMORYCHECK_SUPPRESSIONS_FILE@
+MEMORYCHECK_COMMAND_OPTIONS:STRING=@MEMORYCHECK_COMMAND_OPTIONS@
+COVERAGE_COMMAND:FILEPATH=@COVERAGE_COMMAND@
+")
+
+# if you do not want to use the default location for a
+# dashboard then set this variable to the directory
+# the dashboard should be in
+set (CTEST_DASHBOARD_ROOT "@CMAKE_CURRENT_BINARY_DIR@/Tests/CTestTest")
+
+
+# set any extra environment variables here
+set (CTEST_ENVIRONMENT
+)
+
+set (CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTest/SmallAndFast")
+set (CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTest/${CTEST_BINARY_NAME}")
diff --git a/Tests/CTestTest2/test.cmake.in b/Tests/CTestTest2/test.cmake.in
new file mode 100644
index 0000000..d5d4d2f
--- /dev/null
+++ b/Tests/CTestTest2/test.cmake.in
@@ -0,0 +1,68 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "KWSys-@BUILDNAME@-CTest2")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Source/kwsys")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTest2/kwsysBin")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_MEMORYCHECK_COMMAND "@MEMORYCHECK_COMMAND@")
+set(CTEST_MEMORYCHECK_SUPPRESSIONS_FILE "@MEMORYCHECK_SUPPRESSIONS_FILE@")
+set(CTEST_MEMORYCHECK_COMMAND_OPTIONS "@MEMORYCHECK_COMMAND_OPTIONS@")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+# By default, CTESTTEST2_USE_PURIFY is not defined. If you want to run purify
+# on CTestTest2, set CTESTTEST2_USE_PURIFY to ON in CMake's cache.
+set(CTESTTEST2_USE_PURIFY @CTESTTEST2_USE_PURIFY@)
+if("${CTEST_MEMORYCHECK_COMMAND}" MATCHES purify AND NOT CTESTTEST2_USE_PURIFY)
+ set(CTEST_MEMORYCHECK_COMMAND)
+endif()
+
+#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
+
+file(WRITE "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" "
+CMAKE_CXX_FLAGS:STRING=@CMAKE_CXX_FLAGS@
+CMAKE_C_FLAGS:STRING=@CMAKE_C_FLAGS@
+CMAKE_C_COMPILER:STRING=@CMAKE_C_COMPILER@
+CMAKE_CXX_COMPILER:STRING=@CMAKE_CXX_COMPILER@
+CMAKE_C_COMPILER_ARG1:STRING=@CMAKE_C_COMPILER_ARG1@
+CMAKE_CXX_COMPILER_ARG1:STRING=@CMAKE_CXX_COMPILER_ARG1@
+KWSYS_ENCODING_DEFAULT_CODEPAGE:STRING=CP_UTF8
+
+# This one is needed for testing advanced ctest features
+CTEST_TEST_KWSYS:BOOL=ON
+")
+
+set(test_exclude
+ kwsys.testProcess-10
+ )
+
+CTEST_START(Experimental)
+#CTEST_UPDATE(SOURCE "${CTEST_SOURCE_DIRECTORY}" RETURN_VALUE res)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_READ_CUSTOM_FILES(${CTEST_BINARY_DIRECTORY})
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res EXCLUDE ${test_exclude} START 1 END 5 STRIDE 2)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res EXCLUDE ${test_exclude} START 7 STRIDE 2 SUBMIT_INDEX 1)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res EXCLUDE ${test_exclude} START 2 END 4 STRIDE 2 SUBMIT_INDEX 2)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res EXCLUDE ${test_exclude} START 6 STRIDE 2 SUBMIT_INDEX 3)
+CTEST_MEMCHECK(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res STRIDE 1.5)
+CTEST_COVERAGE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+
+set(CTEST_DROP_METHOD "@protocol@")
+set(CTEST_DROP_SITE "@server@")
+set(CTEST_DROP_LOCATION "@path@/submit.php?project=PublicDashboard")
+
+CTEST_SUBMIT(RETURN_VALUE res)
+
+# Test submission of a subset of parts.
+set(CTEST_EXTRA_SUBMIT_FILES ${CTEST_NOTES_FILES})
+CTEST_SUBMIT(RETURN_VALUE res PARTS ExtraFiles)
+set(CTEST_EXTRA_SUBMIT_FILES)
diff --git a/Tests/CTestTestBadExe/CMakeLists.txt b/Tests/CTestTestBadExe/CMakeLists.txt
new file mode 100644
index 0000000..c71c215
--- /dev/null
+++ b/Tests/CTestTestBadExe/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required (VERSION 2.6)
+project(CTestTestBadExe)
+include(CTest)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/notAnExe.txt" "${CMAKE_CURRENT_BINARY_DIR}/notAnExe.txt" COPYONLY)
+
+add_test (TestBadExe "${CMAKE_CURRENT_BINARY_DIR}/notAnExe.txt")
diff --git a/Tests/CTestTestBadExe/CTestConfig.cmake b/Tests/CTestTestBadExe/CTestConfig.cmake
new file mode 100644
index 0000000..5bc1e9e
--- /dev/null
+++ b/Tests/CTestTestBadExe/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set (CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestBadExe/notAnExe.txt b/Tests/CTestTestBadExe/notAnExe.txt
new file mode 100644
index 0000000..f2a0aa4
--- /dev/null
+++ b/Tests/CTestTestBadExe/notAnExe.txt
@@ -0,0 +1 @@
+This is not an executable file.
diff --git a/Tests/CTestTestBadExe/test.cmake.in b/Tests/CTestTestBadExe/test.cmake.in
new file mode 100644
index 0000000..dd180f0
--- /dev/null
+++ b/Tests/CTestTestBadExe/test.cmake.in
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-BadExe")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestBadExe")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestBadExe")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
diff --git a/Tests/CTestTestBadGenerator/CMakeLists.txt b/Tests/CTestTestBadGenerator/CMakeLists.txt
new file mode 100644
index 0000000..d46d9bf
--- /dev/null
+++ b/Tests/CTestTestBadGenerator/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.0)
+project(CTestTestDepends NONE)
+include(CTest)
diff --git a/Tests/CTestTestBadGenerator/CTestConfig.cmake b/Tests/CTestTestBadGenerator/CTestConfig.cmake
new file mode 100644
index 0000000..5bc1e9e
--- /dev/null
+++ b/Tests/CTestTestBadGenerator/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set (CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestBadGenerator/test.cmake.in b/Tests/CTestTestBadGenerator/test.cmake.in
new file mode 100644
index 0000000..ae6d0b5
--- /dev/null
+++ b/Tests/CTestTestBadGenerator/test.cmake.in
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.0)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-Depends")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestBadGenerator")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestBadGenerator")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "Bad Generator")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
diff --git a/Tests/CTestTestChecksum/test.cmake.in b/Tests/CTestTestChecksum/test.cmake.in
new file mode 100644
index 0000000..3bac0e0
--- /dev/null
+++ b/Tests/CTestTestChecksum/test.cmake.in
@@ -0,0 +1,27 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-Checksum")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestChecksum")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestChecksum")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res PARALLEL_LEVEL 4)
+
+set(CTEST_DROP_METHOD "@protocol@")
+set(CTEST_DROP_SITE "@server@")
+set(CTEST_DROP_LOCATION "@path@/submit.php?project=PublicDashboard")
+
+CTEST_SUBMIT(RETRY_DELAY 3 RETRY_COUNT 2 INTERNAL_TEST_CHECKSUM RETURN_VALUE res)
diff --git a/Tests/CTestTestCostSerial/CMakeLists.txt b/Tests/CTestTestCostSerial/CMakeLists.txt
new file mode 100644
index 0000000..d3344cf
--- /dev/null
+++ b/Tests/CTestTestCostSerial/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required (VERSION 2.6)
+project (CTestTestCostSerial)
+include (CTest)
+
+add_executable (Sleep sleep.c)
+
+foreach (index RANGE 1 3)
+ add_test (TestSleep${index} Sleep)
+endforeach ()
+
+set_tests_properties(TestSleep1 PROPERTIES COST -500)
+set_tests_properties(TestSleep2 PROPERTIES COST 12)
+set_tests_properties(TestSleep3 PROPERTIES COST 0)
diff --git a/Tests/CTestTestCostSerial/CTestConfig.cmake b/Tests/CTestTestCostSerial/CTestConfig.cmake
new file mode 100644
index 0000000..bd265f9
--- /dev/null
+++ b/Tests/CTestTestCostSerial/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestCostSerial/sleep.c b/Tests/CTestTestCostSerial/sleep.c
new file mode 100644
index 0000000..8a174c9
--- /dev/null
+++ b/Tests/CTestTestCostSerial/sleep.c
@@ -0,0 +1,16 @@
+#if defined(_WIN32)
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+/* sleeps for 1 second */
+int main(int argc, char** argv)
+{
+#if defined(_WIN32)
+ Sleep(1000);
+#else
+ sleep(1);
+#endif
+ return 0;
+}
diff --git a/Tests/CTestTestCostSerial/test.cmake.in b/Tests/CTestTestCostSerial/test.cmake.in
new file mode 100644
index 0000000..1c46d4c
--- /dev/null
+++ b/Tests/CTestTestCostSerial/test.cmake.in
@@ -0,0 +1,30 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-CostSerial")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestCostSerial")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestCostSerial")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
+
+# Remove old cost data file if it exists
+if(EXISTS "${CTEST_BINARY_DIRECTORY}/Testing/Temporary/CTestCostData.txt")
+ file(REMOVE "${CTEST_BINARY_DIRECTORY}/Testing/Temporary/CTestCostData.txt")
+endif()
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+# Run test set a second time to make sure they run in same specified order
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
diff --git a/Tests/CTestTestCrash/CMakeLists.txt b/Tests/CTestTestCrash/CMakeLists.txt
new file mode 100644
index 0000000..663d2e4
--- /dev/null
+++ b/Tests/CTestTestCrash/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(CTestTestCrash)
+include(CTest)
+
+add_executable (Crash crash.cxx)
+
+add_test (TestCrash Crash)
diff --git a/Tests/CTestTestCrash/CTestConfig.cmake b/Tests/CTestTestCrash/CTestConfig.cmake
new file mode 100644
index 0000000..5bc1e9e
--- /dev/null
+++ b/Tests/CTestTestCrash/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set (CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestCrash/crash.cxx b/Tests/CTestTestCrash/crash.cxx
new file mode 100644
index 0000000..370c3fb
--- /dev/null
+++ b/Tests/CTestTestCrash/crash.cxx
@@ -0,0 +1,6 @@
+// causes a segfault
+int main()
+{
+ int* ptr = 0;
+ *ptr = 1;
+}
diff --git a/Tests/CTestTestCrash/test.cmake.in b/Tests/CTestTestCrash/test.cmake.in
new file mode 100644
index 0000000..916d4e9
--- /dev/null
+++ b/Tests/CTestTestCrash/test.cmake.in
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-Crash")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestCrash")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestCrash")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+#CTEST_SUBMIT()
diff --git a/Tests/CTestTestCycle/CMakeLists.txt b/Tests/CTestTestCycle/CMakeLists.txt
new file mode 100644
index 0000000..19f4dd7
--- /dev/null
+++ b/Tests/CTestTestCycle/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(CTestTestCycle)
+include(CTest)
+
+add_executable (simple simple.cxx)
+add_test (one simple)
+add_test (two simple)
+add_test (three simple)
+
+# Add cyclical test dependency
+set_tests_properties(one PROPERTIES DEPENDS "two")
+set_tests_properties(two PROPERTIES DEPENDS "three")
+set_tests_properties(three PROPERTIES DEPENDS "one")
diff --git a/Tests/CTestTestCycle/CTestConfig.cmake b/Tests/CTestTestCycle/CTestConfig.cmake
new file mode 100644
index 0000000..5bc1e9e
--- /dev/null
+++ b/Tests/CTestTestCycle/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set (CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestCycle/simple.cxx b/Tests/CTestTestCycle/simple.cxx
new file mode 100644
index 0000000..766b775
--- /dev/null
+++ b/Tests/CTestTestCycle/simple.cxx
@@ -0,0 +1,5 @@
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CTestTestCycle/test.cmake.in b/Tests/CTestTestCycle/test.cmake.in
new file mode 100644
index 0000000..507d46b
--- /dev/null
+++ b/Tests/CTestTestCycle/test.cmake.in
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-Cycle")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestCycle")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestCycle")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
diff --git a/Tests/CTestTestDepends/CMakeLists.txt b/Tests/CTestTestDepends/CMakeLists.txt
new file mode 100644
index 0000000..462ad8c
--- /dev/null
+++ b/Tests/CTestTestDepends/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(CTestTestDepends)
+include(CTest)
+
+add_executable (simple simple.cxx)
+add_executable (TestExe::Simple ALIAS simple)
+add_test (NAME one COMMAND TestExe::Simple)
+add_test (two simple)
+add_test (three simple)
+
+# Add redundant (but not cyclical) dependencies
+set_tests_properties(two PROPERTIES DEPENDS "one")
+set_tests_properties(three PROPERTIES DEPENDS "one;two")
diff --git a/Tests/CTestTestDepends/CTestConfig.cmake b/Tests/CTestTestDepends/CTestConfig.cmake
new file mode 100644
index 0000000..5bc1e9e
--- /dev/null
+++ b/Tests/CTestTestDepends/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set (CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestDepends/simple.cxx b/Tests/CTestTestDepends/simple.cxx
new file mode 100644
index 0000000..766b775
--- /dev/null
+++ b/Tests/CTestTestDepends/simple.cxx
@@ -0,0 +1,5 @@
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CTestTestDepends/test.cmake.in b/Tests/CTestTestDepends/test.cmake.in
new file mode 100644
index 0000000..11bc92a
--- /dev/null
+++ b/Tests/CTestTestDepends/test.cmake.in
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-Depends")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestDepends")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestDepends")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
diff --git a/Tests/CTestTestEmptyBinaryDirectory/test.cmake.in b/Tests/CTestTestEmptyBinaryDirectory/test.cmake.in
new file mode 100644
index 0000000..8eb808f
--- /dev/null
+++ b/Tests/CTestTestEmptyBinaryDirectory/test.cmake.in
@@ -0,0 +1,66 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+set(CTEST_RUN_CURRENT_SCRIPT 0)
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestEmptyBinaryDirectory")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestEmptyBinaryDirectory")
+
+# make sure ctest does not remove directories without a CMakeCache.txt in it
+set(EMPTY_BINARY_DIR "${CTEST_BINARY_DIRECTORY}/empty_binary_dir")
+file(MAKE_DIRECTORY "${EMPTY_BINARY_DIR}")
+
+if(NOT EXISTS "${EMPTY_BINARY_DIR}"
+ OR EXISTS "${EMPTY_BINARY_DIR}/CMakeCache.txt")
+ message(FATAL_ERROR "empty_binary_dir precondition failed")
+endif()
+
+ctest_empty_binary_directory("${EMPTY_BINARY_DIR}")
+
+if(NOT EXISTS "${EMPTY_BINARY_DIR}")
+ message(FATAL_ERROR "empty_binary_dir should not have been removed")
+endif()
+
+# make sure ctest does remove directories with a CMakeCache.txt
+set(VALID_BINARY_DIR "${CTEST_BINARY_DIRECTORY}/valid_binary_dir")
+file(MAKE_DIRECTORY "${VALID_BINARY_DIR}")
+file(WRITE "${VALID_BINARY_DIR}/CMakeCache.txt")
+
+if(NOT EXISTS "${VALID_BINARY_DIR}"
+ OR NOT EXISTS "${VALID_BINARY_DIR}/CMakeCache.txt")
+ message(FATAL_ERROR "valid_binary_dir precondition failed")
+endif()
+
+ctest_empty_binary_directory("${VALID_BINARY_DIR}")
+
+if(EXISTS "${VALID_BINARY_DIR}")
+ message(FATAL_ERROR "valid_binary_dir should have been removed")
+endif()
+
+# make sure ctest removes build directories recursively
+set(DEEP_BINARY_DIR "${CTEST_BINARY_DIRECTORY}/deep_binary_dir")
+file(MAKE_DIRECTORY "${DEEP_BINARY_DIR}")
+file(WRITE "${DEEP_BINARY_DIR}/CMakeCache.txt")
+
+foreach(SUBDIR A Z A/A A/Z Z/A Z/Z)
+ set(FULL_SUBDIR "${DEEP_BINARY_DIR}/${SUBDIR}")
+ file(MAKE_DIRECTORY "${FULL_SUBDIR}")
+
+ foreach(SUBFILE A.cpp Z.bat)
+ set(FULL_SUBFILE "${FULL_SUBDIR}/${SUBFILE}")
+ file(WRITE "${FULL_SUBFILE}" "I am '${FULL_SUBFILE}'")
+ endforeach()
+endforeach()
+
+if(NOT EXISTS "${DEEP_BINARY_DIR}"
+ OR NOT EXISTS "${DEEP_BINARY_DIR}/CMakeCache.txt"
+ OR NOT EXISTS "${DEEP_BINARY_DIR}/Z/A/Z.bat")
+ message(FATAL_ERROR "deep_binary_dir precondition failed")
+endif()
+
+ctest_empty_binary_directory("${DEEP_BINARY_DIR}")
+
+if(EXISTS "${DEEP_BINARY_DIR}")
+ message(FATAL_ERROR "deep_binary_dir should have been removed")
+endif()
+
+message("TEST_SUCCESS")
diff --git a/Tests/CTestTestFailure/CMakeLists.txt b/Tests/CTestTestFailure/CMakeLists.txt
new file mode 100644
index 0000000..db14b3d
--- /dev/null
+++ b/Tests/CTestTestFailure/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(CTestTestFailure)
+include(CTest)
+
+add_executable (NoBuild badCode.cxx)
+target_link_libraries (NoBuild ${EXTRA_LIBS})
+
+add_test (TestNoExe NoBuild)
diff --git a/Tests/CTestTestFailure/CTestConfig.cmake b/Tests/CTestTestFailure/CTestConfig.cmake
new file mode 100644
index 0000000..5bc1e9e
--- /dev/null
+++ b/Tests/CTestTestFailure/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set (CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestFailure/badCode.cxx b/Tests/CTestTestFailure/badCode.cxx
new file mode 100644
index 0000000..8102883
--- /dev/null
+++ b/Tests/CTestTestFailure/badCode.cxx
@@ -0,0 +1,4 @@
+int main()
+{
+ this code will not compile
+}
diff --git a/Tests/CTestTestFailure/testNoBuild.cmake.in b/Tests/CTestTestFailure/testNoBuild.cmake.in
new file mode 100644
index 0000000..47d254f
--- /dev/null
+++ b/Tests/CTestTestFailure/testNoBuild.cmake.in
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-NoBuild")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestFailure")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestFailure")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
+
+CTEST_START(Experimental)
+#CTEST_UPDATE(SOURCE "${CTEST_SOURCE_DIRECTORY}" RETURN_VALUE res)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
diff --git a/Tests/CTestTestFailure/testNoExe.cmake.in b/Tests/CTestTestFailure/testNoExe.cmake.in
new file mode 100644
index 0000000..8496c80
--- /dev/null
+++ b/Tests/CTestTestFailure/testNoExe.cmake.in
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-NoExe")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestFailure")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestFailure")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
+
+CTEST_START(Experimental)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
diff --git a/Tests/CTestTestFdSetSize/CMakeLists.txt b/Tests/CTestTestFdSetSize/CMakeLists.txt
new file mode 100644
index 0000000..f382746
--- /dev/null
+++ b/Tests/CTestTestFdSetSize/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required (VERSION 2.8.10)
+project (CTestTestFdSetSize)
+include (CTest)
+
+add_executable (Sleep sleep.c)
+
+foreach (index RANGE 1 20)
+ add_test (TestSleep${index} Sleep)
+endforeach ()
diff --git a/Tests/CTestTestFdSetSize/sleep.c b/Tests/CTestTestFdSetSize/sleep.c
new file mode 100644
index 0000000..2fb6490
--- /dev/null
+++ b/Tests/CTestTestFdSetSize/sleep.c
@@ -0,0 +1,16 @@
+#if defined(_WIN32)
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+/* sleeps for 0.1 second */
+int main(int argc, char** argv)
+{
+#if defined(_WIN32)
+ Sleep(100);
+#else
+ usleep(100 * 1000);
+#endif
+ return 0;
+}
diff --git a/Tests/CTestTestFdSetSize/test.cmake.in b/Tests/CTestTestFdSetSize/test.cmake.in
new file mode 100644
index 0000000..bfe4459
--- /dev/null
+++ b/Tests/CTestTestFdSetSize/test.cmake.in
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 2.8.10)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-FdSetSize")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestFdSetSize")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestFdSetSize")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+ctest_start(Experimental)
+ctest_configure(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+message("build")
+ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+message("test")
+ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}" PARALLEL_LEVEL 20 RETURN_VALUE res)
+message("done")
diff --git a/Tests/CTestTestLabelRegExp/CTestTestfile.cmake.in b/Tests/CTestTestLabelRegExp/CTestTestfile.cmake.in
new file mode 100644
index 0000000..657f382
--- /dev/null
+++ b/Tests/CTestTestLabelRegExp/CTestTestfile.cmake.in
@@ -0,0 +1,8 @@
+add_test(test1 ${CMAKE_COMMAND} -E echo test1)
+set_tests_properties(test1 PROPERTIES LABELS "foo")
+
+add_test(test2 ${CMAKE_COMMAND} -E echo test2)
+set_tests_properties(test2 PROPERTIES LABELS "bar")
+
+add_test(test3 ${CMAKE_COMMAND} -E echo test3)
+set_tests_properties(test3 PROPERTIES LABELS "foo;bar")
diff --git a/Tests/CTestTestLabelRegExp/test.cmake.in b/Tests/CTestTestLabelRegExp/test.cmake.in
new file mode 100644
index 0000000..dd40c3b
--- /dev/null
+++ b/Tests/CTestTestLabelRegExp/test.cmake.in
@@ -0,0 +1,41 @@
+configure_file(${SOURCE_DIR}/CTestTestfile.cmake.in CTestTestfile.cmake)
+
+function(get_test_list TEST_LIST)
+ set(QUERY_COMMAND ${CMAKE_CTEST_COMMAND} -N ${ARGN})
+
+ execute_process(COMMAND ${QUERY_COMMAND}
+ RESULT_VARIABLE RESULT
+ OUTPUT_VARIABLE OUTPUT
+ ERROR_VARIABLE ERROR)
+
+ if(NOT ${RESULT} STREQUAL "0")
+ message(FATAL_ERROR "command [${QUERY_COMMAND}] failed: RESULT[${RESULT}] OUTPUT[${OUTPUT}] ERROR[${ERROR}]")
+ endif()
+
+ set(${TEST_LIST} "${OUTPUT}" PARENT_SCOPE)
+endfunction()
+
+function(expect_test_list EXPECTED_OUTPUT)
+ get_test_list(TEST_LIST ${ARGN})
+
+ if(NOT "${TEST_LIST}" MATCHES "${EXPECTED_OUTPUT}")
+ message(FATAL_ERROR "actual output [${TEST_LIST}] does not match expected output [${EXPECTED_OUTPUT}] for given arguments [${ARGN}]")
+ endif()
+endfunction()
+
+expect_test_list("test1.*test3.*Total Tests: 2" --label-regex foo)
+expect_test_list("test2.*test3.*Total Tests: 2" --label-regex bar)
+expect_test_list("test1.*test2.*test3.*Total Tests: 3" --label-regex foo|bar)
+expect_test_list("Total Tests: 0" --label-regex baz)
+expect_test_list("Total Tests: 0" --label-regex foo --label-regex baz)
+expect_test_list("test3.*Total Tests: 1" --label-regex foo --label-regex bar)
+
+expect_test_list("test2.*Total Tests: 1" --label-exclude foo)
+expect_test_list("test1.*Total Tests: 1" --label-exclude bar)
+expect_test_list("Total Tests: 0" --label-exclude foo|bar)
+expect_test_list("test1.*test2.*test3.*Total Tests: 3" --label-exclude baz)
+expect_test_list("test1.*test2.*Total Tests: 2" --label-exclude foo --label-exclude bar)
+expect_test_list("test1.*test2.*test3.*Total Tests: 3" --label-exclude foo --label-exclude baz)
+
+expect_test_list("test1.*Total Tests: 1" --label-regex foo --label-exclude bar)
+expect_test_list("test2.*Total Tests: 1" --label-regex bar --label-exclude foo)
diff --git a/Tests/CTestTestLaunchers/launcher_compiler_test_project/CMakeLists.txt b/Tests/CTestTestLaunchers/launcher_compiler_test_project/CMakeLists.txt
new file mode 100644
index 0000000..7376a40
--- /dev/null
+++ b/Tests/CTestTestLaunchers/launcher_compiler_test_project/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(launcher_compiler_test_project)
+
+include(CTest)
+
+add_executable(build_error build_error.cxx)
diff --git a/Tests/CTestTestLaunchers/launcher_compiler_test_project/CTestConfig.cmake b/Tests/CTestTestLaunchers/launcher_compiler_test_project/CTestConfig.cmake
new file mode 100644
index 0000000..c08eded
--- /dev/null
+++ b/Tests/CTestTestLaunchers/launcher_compiler_test_project/CTestConfig.cmake
@@ -0,0 +1,5 @@
+set(CTEST_USE_LAUNCHERS 1)
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestLaunchers/launcher_compiler_test_project/build_error.cxx b/Tests/CTestTestLaunchers/launcher_compiler_test_project/build_error.cxx
new file mode 100644
index 0000000..2d51693
--- /dev/null
+++ b/Tests/CTestTestLaunchers/launcher_compiler_test_project/build_error.cxx
@@ -0,0 +1,5 @@
+int main()
+{
+ int = 3;
+ return;
+}
diff --git a/Tests/CTestTestLaunchers/launcher_custom_command_test_project/CMakeLists.txt b/Tests/CTestTestLaunchers/launcher_custom_command_test_project/CMakeLists.txt
new file mode 100644
index 0000000..b31f587
--- /dev/null
+++ b/Tests/CTestTestLaunchers/launcher_custom_command_test_project/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(launcher_custom_command_test_project)
+
+include(CTest)
+
+add_custom_command(
+ OUTPUT test1.txt
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -DTESTID=1 -P "${CMAKE_CURRENT_SOURCE_DIR}/command.cmake"
+)
+
+add_custom_command(
+ OUTPUT test2.txt
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -DTESTID=2 -P "${CMAKE_CURRENT_SOURCE_DIR}/command.cmake"
+)
+
+add_custom_target(mytarget ALL DEPENDS test1.txt test2.txt)
diff --git a/Tests/CTestTestLaunchers/launcher_custom_command_test_project/CTestConfig.cmake b/Tests/CTestTestLaunchers/launcher_custom_command_test_project/CTestConfig.cmake
new file mode 100644
index 0000000..c08eded
--- /dev/null
+++ b/Tests/CTestTestLaunchers/launcher_custom_command_test_project/CTestConfig.cmake
@@ -0,0 +1,5 @@
+set(CTEST_USE_LAUNCHERS 1)
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestLaunchers/launcher_custom_command_test_project/command.cmake b/Tests/CTestTestLaunchers/launcher_custom_command_test_project/command.cmake
new file mode 100644
index 0000000..7f31af9
--- /dev/null
+++ b/Tests/CTestTestLaunchers/launcher_custom_command_test_project/command.cmake
@@ -0,0 +1,5 @@
+if("${TESTID}" STREQUAL "1")
+ message("success")
+elseif("${TESTID}" STREQUAL "2")
+ message(FATAL_ERROR "failure")
+endif()
diff --git a/Tests/CTestTestLaunchers/launcher_linker_test_project/CMakeLists.txt b/Tests/CTestTestLaunchers/launcher_linker_test_project/CMakeLists.txt
new file mode 100644
index 0000000..38980aa
--- /dev/null
+++ b/Tests/CTestTestLaunchers/launcher_linker_test_project/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(launcher_linker_test_project)
+
+include(CTest)
+
+add_executable(link_error link_error.cxx)
diff --git a/Tests/CTestTestLaunchers/launcher_linker_test_project/CTestConfig.cmake b/Tests/CTestTestLaunchers/launcher_linker_test_project/CTestConfig.cmake
new file mode 100644
index 0000000..c08eded
--- /dev/null
+++ b/Tests/CTestTestLaunchers/launcher_linker_test_project/CTestConfig.cmake
@@ -0,0 +1,5 @@
+set(CTEST_USE_LAUNCHERS 1)
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestLaunchers/launcher_linker_test_project/link_error.cxx b/Tests/CTestTestLaunchers/launcher_linker_test_project/link_error.cxx
new file mode 100644
index 0000000..c879be1
--- /dev/null
+++ b/Tests/CTestTestLaunchers/launcher_linker_test_project/link_error.cxx
@@ -0,0 +1,6 @@
+extern int foo();
+
+int main()
+{
+ return foo();
+}
diff --git a/Tests/CTestTestLaunchers/test.cmake.in b/Tests/CTestTestLaunchers/test.cmake.in
new file mode 100644
index 0000000..2db1ddd
--- /dev/null
+++ b/Tests/CTestTestLaunchers/test.cmake.in
@@ -0,0 +1,52 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+set(TEST_SUCCESS TRUE)
+
+function(run_test_case NAME WHAT)
+ set(_message "Testing that launchers are used when running ${WHAT}")
+ message(STATUS "${_message}...")
+
+ # Settings:
+ set(CTEST_DASHBOARD_SOURCE "@CMake_SOURCE_DIR@/Tests/CTestTestLaunchers")
+ set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTestLaunchers")
+ set(CTEST_SITE "@SITE@")
+ set(CTEST_BUILD_NAME "Launchers-@BUILDNAME@-CTestTestLaunchers")
+
+ set(CTEST_SOURCE_DIRECTORY "${CTEST_DASHBOARD_SOURCE}/${NAME}")
+ set(CTEST_BINARY_DIRECTORY "${CTEST_DASHBOARD_ROOT}/${NAME}-bin")
+ set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+ set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+ set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+ set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+ set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+ ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY})
+
+ file(WRITE "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" "
+ CMAKE_CXX_FLAGS:STRING=@CMAKE_CXX_FLAGS@
+ CMAKE_C_FLAGS:STRING=@CMAKE_C_FLAGS@
+ CMAKE_C_COMPILER:STRING=@CMAKE_C_COMPILER@
+ CMAKE_CXX_COMPILER:STRING=@CMAKE_CXX_COMPILER@
+ CMAKE_C_COMPILER_ARG1:STRING=@CMAKE_C_COMPILER_ARG1@
+ CMAKE_CXX_COMPILER_ARG1:STRING=@CMAKE_CXX_COMPILER_ARG1@
+ ")
+
+ ctest_start(Experimental)
+ ctest_configure(OPTIONS "-DCTEST_USE_LAUNCHERS=1")
+ ctest_build(NUMBER_ERRORS error_count)
+
+ if("${error_count}" STREQUAL "0")
+ set(TEST_SUCCESS FALSE PARENT_SCOPE)
+ message(STATUS "${_message}... FAIL")
+ else()
+ message(STATUS "${_message}... PASS")
+ endif()
+endfunction()
+
+run_test_case(launcher_compiler_test_project "the compiler")
+run_test_case(launcher_linker_test_project "the linker")
+run_test_case(launcher_custom_command_test_project "a custom command")
+
+if(TEST_SUCCESS)
+ message("CTEST_TEST_LAUNCHER_SUCCESS")
+endif()
diff --git a/Tests/CTestTestMissingDependsExe/CMakeLists.txt b/Tests/CTestTestMissingDependsExe/CMakeLists.txt
new file mode 100644
index 0000000..9826da6
--- /dev/null
+++ b/Tests/CTestTestMissingDependsExe/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(CTestTestMissingDependsExe)
+
+enable_testing()
+
+add_test(test1 ${CMAKE_COMMAND} -E echo test)
+add_test(test2 non-existent-command)
+
+set_tests_properties(test1 PROPERTIES DEPENDS test2)
diff --git a/Tests/CTestTestParallel/CMakeLists.txt b/Tests/CTestTestParallel/CMakeLists.txt
new file mode 100644
index 0000000..819fee4
--- /dev/null
+++ b/Tests/CTestTestParallel/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(CTestTestParallel)
+include(CTest)
+
+add_executable (LockFile lockFile.c)
+
+add_test (TestRunSerial1 LockFile)
+add_test (TestRunSerial2 LockFile)
+set_tests_properties(TestRunSerial1 TestRunSerial2 PROPERTIES RUN_SERIAL true)
+
+add_test (TestProcessorsGreaterThanMPL1 LockFile)
+add_test (TestProcessorsGreaterThanMPL2 LockFile)
+set_tests_properties(TestProcessorsGreaterThanMPL1 PROPERTIES PROCESSORS 10)
+set_tests_properties(TestProcessorsGreaterThanMPL1 PROPERTIES DEPENDS
+ TestProcessorsGreaterThanMPL2)
diff --git a/Tests/CTestTestParallel/CTestConfig.cmake b/Tests/CTestTestParallel/CTestConfig.cmake
new file mode 100644
index 0000000..bd265f9
--- /dev/null
+++ b/Tests/CTestTestParallel/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestParallel/lockFile.c b/Tests/CTestTestParallel/lockFile.c
new file mode 100644
index 0000000..a515107
--- /dev/null
+++ b/Tests/CTestTestParallel/lockFile.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+/*if run serially, works fine.
+ If run in parallel, someone will attempt to delete
+ a locked file, which will fail */
+int main(void)
+{
+ FILE* file;
+ int i;
+ const char* fname = "lockedFile.txt";
+ file = fopen(fname, "w");
+
+ for (i = 0; i < 10000; i++) {
+ fprintf(file, "%s", "x");
+ fflush(file);
+ }
+ fclose(file);
+ return remove(fname);
+}
diff --git a/Tests/CTestTestParallel/test.cmake.in b/Tests/CTestTestParallel/test.cmake.in
new file mode 100644
index 0000000..517db72
--- /dev/null
+++ b/Tests/CTestTestParallel/test.cmake.in
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-Parallel")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestParallel")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestParallel")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res PARALLEL_LEVEL 4)
diff --git a/Tests/CTestTestResourceLock/CMakeLists.txt b/Tests/CTestTestResourceLock/CMakeLists.txt
new file mode 100644
index 0000000..4bc4366
--- /dev/null
+++ b/Tests/CTestTestResourceLock/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(CTestTestResourceLock)
+include(CTest)
+
+add_executable (LockFile lockFile.c)
+
+add_test (TestLockedFile1.1 LockFile locked1.txt)
+add_test (TestLockedFile1.2 LockFile locked1.txt)
+set_tests_properties(TestLockedFile1.1 TestLockedFile1.2 PROPERTIES RESOURCE_LOCK "locked1.txt")
+
+add_test (TestLockedFile2.1 LockFile locked2.txt)
+add_test (TestLockedFile2.2 LockFile locked2.txt)
+set_tests_properties(TestLockedFile2.1 TestLockedFile2.2 PROPERTIES RESOURCE_LOCK "locked2.txt")
diff --git a/Tests/CTestTestResourceLock/CTestConfig.cmake b/Tests/CTestTestResourceLock/CTestConfig.cmake
new file mode 100644
index 0000000..bd265f9
--- /dev/null
+++ b/Tests/CTestTestResourceLock/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestResourceLock/lockFile.c b/Tests/CTestTestResourceLock/lockFile.c
new file mode 100644
index 0000000..8c023ef
--- /dev/null
+++ b/Tests/CTestTestResourceLock/lockFile.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+
+/* Disable deprecation warning for fopen */
+#pragma warning(disable : 4996)
+
+/*if run serially, works fine.
+ If run in parallel, someone will attempt to delete
+ a locked file, which will fail */
+int main(int argc, char** argv)
+{
+ FILE* file;
+ int i;
+ const char* fname;
+ if (argc >= 2) {
+ fname = argv[1];
+ } else {
+ fname = "lockedFile.txt";
+ }
+ file = fopen(fname, "w");
+
+ for (i = 0; i < 10000; i++) {
+ fprintf(file, "%s", "x");
+ fflush(file);
+ }
+ fclose(file);
+ return remove(fname);
+}
diff --git a/Tests/CTestTestResourceLock/test.cmake.in b/Tests/CTestTestResourceLock/test.cmake.in
new file mode 100644
index 0000000..826226d
--- /dev/null
+++ b/Tests/CTestTestResourceLock/test.cmake.in
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-ResourceLock")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestResourceLock")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestResourceLock")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res PARALLEL_LEVEL 4)
diff --git a/Tests/CTestTestRunScript/hello.cmake.in b/Tests/CTestTestRunScript/hello.cmake.in
new file mode 100644
index 0000000..37905e3
--- /dev/null
+++ b/Tests/CTestTestRunScript/hello.cmake.in
@@ -0,0 +1,2 @@
+set(CTEST_RUN_CURRENT_SCRIPT 0)
+message("hello world")
diff --git a/Tests/CTestTestRunScript/test.cmake.in b/Tests/CTestTestRunScript/test.cmake.in
new file mode 100644
index 0000000..3074a51
--- /dev/null
+++ b/Tests/CTestTestRunScript/test.cmake.in
@@ -0,0 +1,2 @@
+set(CTEST_RUN_CURRENT_SCRIPT 0)
+CTEST_RUN_SCRIPT("CTestTestRunScript/hello.cmake" RETURN_VALUE res RETURN_VALUE)
diff --git a/Tests/CTestTestScheduler/CMakeLists.txt b/Tests/CTestTestScheduler/CMakeLists.txt
new file mode 100644
index 0000000..a3f0f27
--- /dev/null
+++ b/Tests/CTestTestScheduler/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required (VERSION 2.8.12)
+project (CTestTestScheduler)
+include (CTest)
+
+add_executable (Sleep sleep.c)
+
+foreach (time RANGE 1 4)
+ add_test (TestSleep${time} Sleep ${time})
+endforeach ()
diff --git a/Tests/CTestTestScheduler/CTestConfig.cmake b/Tests/CTestTestScheduler/CTestConfig.cmake
new file mode 100644
index 0000000..bd265f9
--- /dev/null
+++ b/Tests/CTestTestScheduler/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestScheduler/sleep.c b/Tests/CTestTestScheduler/sleep.c
new file mode 100644
index 0000000..327bff5
--- /dev/null
+++ b/Tests/CTestTestScheduler/sleep.c
@@ -0,0 +1,20 @@
+#if defined(_WIN32)
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+/* sleeps for 4n seconds, where n is the argument to the program */
+int main(int argc, char** argv)
+{
+ int time;
+ if (argc > 1) {
+ time = 4 * atoi(argv[1]);
+ }
+#if defined(_WIN32)
+ Sleep(time * 1000);
+#else
+ sleep(time);
+#endif
+ return 0;
+}
diff --git a/Tests/CTestTestScheduler/test.cmake.in b/Tests/CTestTestScheduler/test.cmake.in
new file mode 100644
index 0000000..5dcfb63
--- /dev/null
+++ b/Tests/CTestTestScheduler/test.cmake.in
@@ -0,0 +1,30 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-Scheduler")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestScheduler")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestScheduler")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
+
+# Remove old cost data file if it exists
+if(EXISTS "${CTEST_BINARY_DIRECTORY}/Testing/Temporary/CTestCostData.txt")
+ file(REMOVE "${CTEST_BINARY_DIRECTORY}/Testing/Temporary/CTestCostData.txt")
+endif()
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res PARALLEL_LEVEL 5)
+# Run test set a second time to make sure they run in reverse order
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res PARALLEL_LEVEL 5)
diff --git a/Tests/CTestTestSerialInDepends/CMakeLists.txt b/Tests/CTestTestSerialInDepends/CMakeLists.txt
new file mode 100644
index 0000000..90e50f9
--- /dev/null
+++ b/Tests/CTestTestSerialInDepends/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(CTestTestSerialInDepends)
+
+enable_testing()
+
+function(my_add_test NAME COST)
+ add_test(NAME ${NAME}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_CTEST_COMMAND} -DTEST_NAME=${NAME}
+ -S ${CMAKE_CURRENT_SOURCE_DIR}/test.ctest)
+ set_tests_properties(${NAME} PROPERTIES COST ${COST})
+endfunction()
+
+my_add_test(i_like_company 1000)
+my_add_test(i_like_company_too 0)
+
+my_add_test(i_have_dependencies 1000)
+set_tests_properties(i_have_dependencies PROPERTIES
+ DEPENDS "i_want_to_be_alone")
+
+my_add_test(i_want_to_be_alone 100)
+set_tests_properties(i_want_to_be_alone PROPERTIES RUN_SERIAL 1)
diff --git a/Tests/CTestTestSerialInDepends/test.ctest b/Tests/CTestTestSerialInDepends/test.ctest
new file mode 100644
index 0000000..28ee094
--- /dev/null
+++ b/Tests/CTestTestSerialInDepends/test.ctest
@@ -0,0 +1,16 @@
+set(CTEST_RUN_CURRENT_SCRIPT 0)
+
+set(LOCK_FILE "${TEST_NAME}.lock")
+
+if("${TEST_NAME}" STREQUAL "i_want_to_be_alone")
+ file(GLOB LOCK_FILES *.lock)
+ if(LOCK_FILES)
+ message(FATAL_ERROR "found lock files of other tests even though this test should be running by itself: ${LOCK_FILES}")
+ endif()
+endif()
+
+file(WRITE "${LOCK_FILE}")
+ctest_sleep(3)
+file(REMOVE "${LOCK_FILE}")
+
+return()
diff --git a/Tests/CTestTestSerialOrder/CMakeLists.txt b/Tests/CTestTestSerialOrder/CMakeLists.txt
new file mode 100644
index 0000000..69c11fc
--- /dev/null
+++ b/Tests/CTestTestSerialOrder/CMakeLists.txt
@@ -0,0 +1,40 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(CTestTestSerialOrder)
+
+set(TEST_OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/test_output.txt")
+
+enable_testing()
+
+function(add_serial_order_test TEST_NAME)
+ add_test(NAME ${TEST_NAME}
+ COMMAND ${CMAKE_COMMAND}
+ "-DTEST_OUTPUT_FILE=${TEST_OUTPUT_FILE}"
+ "-DTEST_NAME=${TEST_NAME}"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/test.cmake"
+ )
+
+ if(ARGC GREATER 1)
+ set_tests_properties(${TEST_NAME} PROPERTIES ${ARGN})
+ endif()
+endfunction()
+
+add_serial_order_test(initialization COST 1000)
+add_serial_order_test(test1)
+add_serial_order_test(test2)
+add_serial_order_test(test3)
+add_serial_order_test(test4 DEPENDS test5)
+
+add_serial_order_test(test5)
+set_tests_properties(test5 PROPERTIES DEPENDS "test6;test7b;test7a")
+
+add_serial_order_test(test6 COST -2)
+add_serial_order_test(test7a COST -1)
+add_serial_order_test(test7b COST -1)
+add_serial_order_test(test8 COST 10)
+add_serial_order_test(test9 COST 20)
+add_serial_order_test(test10 COST 0)
+add_serial_order_test(test11)
+add_serial_order_test(test12 COST 0)
+
+add_serial_order_test(verification COST -1000)
diff --git a/Tests/CTestTestSerialOrder/test.cmake b/Tests/CTestTestSerialOrder/test.cmake
new file mode 100644
index 0000000..8479cae
--- /dev/null
+++ b/Tests/CTestTestSerialOrder/test.cmake
@@ -0,0 +1,31 @@
+list(APPEND EXPECTED_OUTPUT
+ initialization
+ test9
+ test8
+ test1
+ test2
+ test3
+ test6
+ test7a
+ test7b
+ test5
+ test4
+ test10
+ test11
+ test12
+)
+
+
+if("${TEST_NAME}" STREQUAL "initialization")
+ file(WRITE ${TEST_OUTPUT_FILE} "${TEST_NAME}")
+
+elseif("${TEST_NAME}" STREQUAL "verification")
+ file(READ ${TEST_OUTPUT_FILE} ACTUAL_OUTPUT)
+ if(NOT "${ACTUAL_OUTPUT}" STREQUAL "${EXPECTED_OUTPUT}")
+ message(FATAL_ERROR "Actual test order [${ACTUAL_OUTPUT}] differs from expected test order [${EXPECTED_OUTPUT}]")
+ endif()
+
+else()
+ file(APPEND ${TEST_OUTPUT_FILE} ";${TEST_NAME}")
+
+endif()
diff --git a/Tests/CTestTestSkipReturnCode/CMakeLists.txt b/Tests/CTestTestSkipReturnCode/CMakeLists.txt
new file mode 100644
index 0000000..26c4178
--- /dev/null
+++ b/Tests/CTestTestSkipReturnCode/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(CTestTestSkipReturnCode)
+include(CTest)
+
+add_test (NAME CMakeV1 COMMAND ${CMAKE_COMMAND} "--version")
+add_test (NAME CMakeV2 COMMAND ${CMAKE_COMMAND} "--version")
+
+set_tests_properties(CMakeV2 PROPERTIES SKIP_RETURN_CODE 0)
diff --git a/Tests/CTestTestSkipReturnCode/CTestConfig.cmake b/Tests/CTestTestSkipReturnCode/CTestConfig.cmake
new file mode 100644
index 0000000..5bc1e9e
--- /dev/null
+++ b/Tests/CTestTestSkipReturnCode/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set (CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestSkipReturnCode/test.cmake.in b/Tests/CTestTestSkipReturnCode/test.cmake.in
new file mode 100644
index 0000000..2988d2f
--- /dev/null
+++ b/Tests/CTestTestSkipReturnCode/test.cmake.in
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-SkipReturnCode")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestSkipReturnCode")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestSkipReturnCode")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
diff --git a/Tests/CTestTestStopTime/CMakeLists.txt b/Tests/CTestTestStopTime/CMakeLists.txt
new file mode 100644
index 0000000..08116e2
--- /dev/null
+++ b/Tests/CTestTestStopTime/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(CTestTestStopTime)
+include(CTest)
+
+add_executable (Sleep sleep.c)
+
+add_test (TestSleep Sleep 30)
+add_test (ShouldNotRun Sleep 30)
+
+set_tests_properties(ShouldNotRun PROPERTIES DEPENDS TestSleep)
+set_tests_properties(ShouldNotRun PROPERTIES WILL_FAIL ON)
diff --git a/Tests/CTestTestStopTime/CTestConfig.cmake b/Tests/CTestTestStopTime/CTestConfig.cmake
new file mode 100644
index 0000000..5bc1e9e
--- /dev/null
+++ b/Tests/CTestTestStopTime/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set (CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestStopTime/GetDate.cmake b/Tests/CTestTestStopTime/GetDate.cmake
new file mode 100644
index 0000000..64a4fb9
--- /dev/null
+++ b/Tests/CTestTestStopTime/GetDate.cmake
@@ -0,0 +1,133 @@
+cmake_minimum_required(VERSION 2.8.11)
+
+macro(GET_DATE)
+ #
+ # All macro arguments are optional.
+ # If there's an ARGV0, use it as GD_PREFIX. Default = 'GD_'
+ # If there's an ARGV1, use it as ${GD_PREFIX}VERBOSE. Default = '0'
+ #
+ # If the date can be retrieved and parsed successfully, this macro
+ # will set the following CMake variables:
+ #
+ # GD_PREFIX
+ # ${GD_PREFIX}PREFIX (if '${GD_PREFIX}' is not 'GD_'...!)
+ # ${GD_PREFIX}VERBOSE
+ #
+ # ${GD_PREFIX}OV
+ #
+ # ${GD_PREFIX}REGEX
+ # ${GD_PREFIX}YEAR
+ # ${GD_PREFIX}MONTH
+ # ${GD_PREFIX}DAY
+ # ${GD_PREFIX}HOUR
+ # ${GD_PREFIX}MINUTE
+ # ${GD_PREFIX}SECOND
+ #
+ # Caller can then use these variables to construct names based on
+ # date and time stamps...
+ #
+
+ # If there's an ARGV0, use it as GD_PREFIX:
+ #
+ set(GD_PREFIX "GD_")
+ if(NOT "${ARGV0}" STREQUAL "")
+ set(GD_PREFIX "${ARGV0}")
+ endif()
+ if(NOT "${GD_PREFIX}" STREQUAL "GD_")
+ set(${GD_PREFIX}PREFIX "${GD_PREFIX}")
+ endif()
+
+ # If there's an ARGV1, use it as ${GD_PREFIX}VERBOSE:
+ #
+ set(${GD_PREFIX}VERBOSE "0")
+ if(NOT "${ARGV1}" STREQUAL "")
+ set(${GD_PREFIX}VERBOSE "${ARGV1}")
+ endif()
+
+ # Retrieve the current date and time in the format:
+ #
+ # 01/12/2006 08:55:12
+ # mm/dd/YYYY HH:MM:SS
+ #
+ unset(ENV{SOURCE_DATE_EPOCH})
+ string(TIMESTAMP "${GD_PREFIX}OV" "%m/%d/%Y %H:%M:%S")
+
+ if(${GD_PREFIX}VERBOSE)
+ message(STATUS "")
+ message(STATUS "<GET_DATE>")
+ message(STATUS "")
+ message(STATUS "GD_PREFIX='${GD_PREFIX}'")
+ if(NOT "${GD_PREFIX}" STREQUAL "GD_")
+ message(STATUS "${GD_PREFIX}PREFIX='${${GD_PREFIX}PREFIX}'")
+ endif()
+ message(STATUS "${GD_PREFIX}VERBOSE='${${GD_PREFIX}VERBOSE}'")
+ message(STATUS "")
+ message(STATUS "${GD_PREFIX}OV='${${GD_PREFIX}OV}'")
+ message(STATUS "")
+ endif()
+
+ #
+ # Extract six individual components by matching a regex with paren groupings.
+ # Use the replace functionality and \\1 through \\6 to extract components.
+ #
+ set(${GD_PREFIX}REGEX "([^/]+)/([^/]+)/([^ ]+) +([^:]+):([^:]+):([^\\.]+)")
+
+ string(REGEX REPLACE "${${GD_PREFIX}REGEX}" "\\1" ${GD_PREFIX}MONTH "${${GD_PREFIX}OV}")
+ string(REGEX REPLACE "${${GD_PREFIX}REGEX}" "\\2" ${GD_PREFIX}DAY "${${GD_PREFIX}OV}")
+ string(REGEX REPLACE "${${GD_PREFIX}REGEX}" "\\3" ${GD_PREFIX}YEAR "${${GD_PREFIX}OV}")
+ string(REGEX REPLACE "${${GD_PREFIX}REGEX}" "\\4" ${GD_PREFIX}HOUR "${${GD_PREFIX}OV}")
+ string(REGEX REPLACE "${${GD_PREFIX}REGEX}" "\\5" ${GD_PREFIX}MINUTE "${${GD_PREFIX}OV}")
+ string(REGEX REPLACE "${${GD_PREFIX}REGEX}" "\\6" ${GD_PREFIX}SECOND "${${GD_PREFIX}OV}")
+
+ if(${GD_PREFIX}VERBOSE)
+ message(STATUS "${GD_PREFIX}REGEX='${${GD_PREFIX}REGEX}'")
+ message(STATUS "${GD_PREFIX}YEAR='${${GD_PREFIX}YEAR}'")
+ message(STATUS "${GD_PREFIX}MONTH='${${GD_PREFIX}MONTH}'")
+ message(STATUS "${GD_PREFIX}DAY='${${GD_PREFIX}DAY}'")
+ message(STATUS "${GD_PREFIX}HOUR='${${GD_PREFIX}HOUR}'")
+ message(STATUS "${GD_PREFIX}MINUTE='${${GD_PREFIX}MINUTE}'")
+ message(STATUS "${GD_PREFIX}SECOND='${${GD_PREFIX}SECOND}'")
+ message(STATUS "")
+ message(STATUS "Counters that change...")
+ message(STATUS "")
+ message(STATUS " every second : ${${GD_PREFIX}YEAR}${${GD_PREFIX}MONTH}${${GD_PREFIX}DAY}${${GD_PREFIX}HOUR}${${GD_PREFIX}MINUTE}${${GD_PREFIX}SECOND}")
+ message(STATUS " daily : ${${GD_PREFIX}YEAR}${${GD_PREFIX}MONTH}${${GD_PREFIX}DAY}")
+ message(STATUS " monthly : ${${GD_PREFIX}YEAR}${${GD_PREFIX}MONTH}")
+ message(STATUS " annually : ${${GD_PREFIX}YEAR}")
+ message(STATUS "")
+ endif()
+
+ if(${GD_PREFIX}VERBOSE)
+ message(STATUS "</GET_DATE>")
+ message(STATUS "")
+ endif()
+endmacro()
+
+macro(ADD_SECONDS sec)
+ set(new_min ${${GD_PREFIX}MINUTE})
+ set(new_hr ${${GD_PREFIX}HOUR})
+ math(EXPR new_sec "${sec} + ${${GD_PREFIX}SECOND}")
+ while(${new_sec} GREATER_EQUAL 60)
+ math(EXPR new_sec "${new_sec} - 60")
+ math(EXPR new_min "${${GD_PREFIX}MINUTE} + 1")
+ endwhile()
+ while(${new_min} GREATER_EQUAL 60)
+ math(EXPR new_min "${new_min} - 60")
+ math(EXPR new_hr "${${GD_PREFIX}HOUR} + 1")
+ endwhile()
+ math(EXPR new_hr "${new_hr} % 24")
+
+ # Pad the H, M, S if needed
+ string(LENGTH ${new_sec} sec_len)
+ string(LENGTH ${new_min} min_len)
+ string(LENGTH ${new_hr} hr_len)
+ if(${sec_len} EQUAL 1)
+ set(new_sec "0${new_sec}")
+ endif()
+ if(${min_len} EQUAL 1)
+ set(new_min "0${new_min}")
+ endif()
+ if(${hr_len} EQUAL 1)
+ set(new_hr "0${new_hr}")
+ endif()
+endmacro()
diff --git a/Tests/CTestTestStopTime/sleep.c b/Tests/CTestTestStopTime/sleep.c
new file mode 100644
index 0000000..b9b6e89
--- /dev/null
+++ b/Tests/CTestTestStopTime/sleep.c
@@ -0,0 +1,20 @@
+#if defined(_WIN32)
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+/* sleeps for n seconds, where n is the argument to the program */
+int main(int argc, char** argv)
+{
+ int time;
+ if (argc > 1) {
+ time = atoi(argv[1]);
+ }
+#if defined(_WIN32)
+ Sleep(time * 1000);
+#else
+ sleep(time);
+#endif
+ return 0;
+}
diff --git a/Tests/CTestTestStopTime/test.cmake.in b/Tests/CTestTestStopTime/test.cmake.in
new file mode 100644
index 0000000..3797d40
--- /dev/null
+++ b/Tests/CTestTestStopTime/test.cmake.in
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-StopTime")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestStopTime")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestStopTime")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
+
+include("${CTEST_BINARY_DIRECTORY}/GetDate.cmake")
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+
+GET_DATE()
+message("curr time: ${${GD_PREFIX}HOUR}:${${GD_PREFIX}MINUTE}:${${GD_PREFIX}SECOND}")
+ADD_SECONDS(15)
+message("stop time: ${new_hr}:${new_min}:${new_sec}")
+
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res STOP_TIME "${new_hr}:${new_min}:${new_sec}")
+
+#CTEST_SUBMIT()
diff --git a/Tests/CTestTestSubdir/CMakeLists.txt b/Tests/CTestTestSubdir/CMakeLists.txt
new file mode 100644
index 0000000..87c4604
--- /dev/null
+++ b/Tests/CTestTestSubdir/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(CTestTestSubdir)
+include(CTest)
+
+add_subdirectory(subdir)
+subdirs(subdir2)
+subdirs("${CTestTestSubdir_SOURCE_DIR}/subdir3")
diff --git a/Tests/CTestTestSubdir/CTestConfig.cmake b/Tests/CTestTestSubdir/CTestConfig.cmake
new file mode 100644
index 0000000..bd265f9
--- /dev/null
+++ b/Tests/CTestTestSubdir/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestSubdir/subdir/CMakeLists.txt b/Tests/CTestTestSubdir/subdir/CMakeLists.txt
new file mode 100644
index 0000000..ee55535
--- /dev/null
+++ b/Tests/CTestTestSubdir/subdir/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable (main main.c)
+add_test (TestMain1 main)
diff --git a/Tests/CTestTestSubdir/subdir/main.c b/Tests/CTestTestSubdir/subdir/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/CTestTestSubdir/subdir/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CTestTestSubdir/subdir2/CMakeLists.txt b/Tests/CTestTestSubdir/subdir2/CMakeLists.txt
new file mode 100644
index 0000000..a8d0a77
--- /dev/null
+++ b/Tests/CTestTestSubdir/subdir2/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable (main2 main.c)
+add_test (TestMain2 main2)
diff --git a/Tests/CTestTestSubdir/subdir2/main.c b/Tests/CTestTestSubdir/subdir2/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/CTestTestSubdir/subdir2/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CTestTestSubdir/subdir3/CMakeLists.txt b/Tests/CTestTestSubdir/subdir3/CMakeLists.txt
new file mode 100644
index 0000000..fbc41d5
--- /dev/null
+++ b/Tests/CTestTestSubdir/subdir3/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable (main3 main.c)
+add_test (TestMain3 main3)
diff --git a/Tests/CTestTestSubdir/subdir3/main.c b/Tests/CTestTestSubdir/subdir3/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/CTestTestSubdir/subdir3/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CTestTestSubdir/test.cmake.in b/Tests/CTestTestSubdir/test.cmake.in
new file mode 100644
index 0000000..3b1fb5f
--- /dev/null
+++ b/Tests/CTestTestSubdir/test.cmake.in
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-Subdir")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestSubdir")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestSubdir")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
diff --git a/Tests/CTestTestTimeout/CMakeLists.txt b/Tests/CTestTestTimeout/CMakeLists.txt
new file mode 100644
index 0000000..c6cbc47
--- /dev/null
+++ b/Tests/CTestTestTimeout/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required (VERSION 2.8)
+project(CTestTestTimeout)
+include(CTest)
+
+if(NOT TIMEOUT)
+ # Give the process time to load and start running.
+ set(TIMEOUT 4)
+endif()
+
+add_definitions(-DTIMEOUT=${TIMEOUT})
+add_executable (Sleep sleep.c)
+
+add_test(NAME TestTimeout
+ COMMAND ${CMAKE_COMMAND} -D Sleep=$<TARGET_FILE:Sleep>
+ -D Log=${CMAKE_CURRENT_BINARY_DIR}/timeout.log
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/timeout.cmake
+ )
+set_tests_properties(TestTimeout PROPERTIES TIMEOUT ${TIMEOUT})
+
+add_test(NAME TestSleep COMMAND Sleep)
+set_tests_properties(TestSleep PROPERTIES DEPENDS TestTimeout)
diff --git a/Tests/CTestTestTimeout/CTestConfig.cmake b/Tests/CTestTestTimeout/CTestConfig.cmake
new file mode 100644
index 0000000..bd265f9
--- /dev/null
+++ b/Tests/CTestTestTimeout/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestTimeout/sleep.c b/Tests/CTestTestTimeout/sleep.c
new file mode 100644
index 0000000..ebe1274
--- /dev/null
+++ b/Tests/CTestTestTimeout/sleep.c
@@ -0,0 +1,21 @@
+#if defined(_WIN32)
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+int main(void)
+{
+ fprintf(stderr, "before sleep\n");
+ fflush(stderr); /* should not be needed, but just in case */
+#if defined(_WIN32)
+ Sleep((TIMEOUT + 4) * 1000);
+#else
+ sleep((TIMEOUT + 4));
+#endif
+ fprintf(stderr, "after sleep\n");
+ fflush(stderr); /* should not be needed, but just in case */
+ return 0;
+}
diff --git a/Tests/CTestTestTimeout/test.cmake.in b/Tests/CTestTestTimeout/test.cmake.in
new file mode 100644
index 0000000..ce9c497
--- /dev/null
+++ b/Tests/CTestTestTimeout/test.cmake.in
@@ -0,0 +1,40 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-Timeout")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestTimeout")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestTimeout")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
+
+file(WRITE "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" "
+TIMEOUT:STRING=@CTestTestTimeout_TIME@
+")
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+
+set(log ${CTEST_BINARY_DIRECTORY}/timeout.log)
+if(EXISTS "${log}")
+ # Verify that the timeout test did not finish sleeping.
+ file(STRINGS "${log}" after_sleep REGEX "after sleep")
+ if(after_sleep)
+ message(FATAL_ERROR "Log indicates timeout did not kill child.")
+ else()
+ message(STATUS "Log indicates timeout correctly killed child.")
+ endif()
+else()
+ message(FATAL_ERROR "Log does not exist:\n ${log}")
+endif()
diff --git a/Tests/CTestTestTimeout/timeout.cmake b/Tests/CTestTestTimeout/timeout.cmake
new file mode 100644
index 0000000..ba2f58b
--- /dev/null
+++ b/Tests/CTestTestTimeout/timeout.cmake
@@ -0,0 +1,6 @@
+# Remove the log file.
+file(REMOVE ${Log})
+
+# Run a child that sleeps longer than the timeout of this test.
+# Log its output so check.cmake can verify it dies.
+execute_process(COMMAND ${Sleep} ERROR_FILE ${Log})
diff --git a/Tests/CTestTestUpload/CMakeLists.txt b/Tests/CTestTestUpload/CMakeLists.txt
new file mode 100644
index 0000000..5e02b2f
--- /dev/null
+++ b/Tests/CTestTestUpload/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(CTestTestUpload)
+
+add_executable (Sleep sleep.c)
diff --git a/Tests/CTestTestUpload/CTestConfig.cmake b/Tests/CTestTestUpload/CTestConfig.cmake
new file mode 100644
index 0000000..21318b4
--- /dev/null
+++ b/Tests/CTestTestUpload/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set (CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set (CTEST_DROP_METHOD "http")
+set (CTEST_DROP_SITE "open.cdash.org")
+set (CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestUpload/sleep.c b/Tests/CTestTestUpload/sleep.c
new file mode 100644
index 0000000..b9b6e89
--- /dev/null
+++ b/Tests/CTestTestUpload/sleep.c
@@ -0,0 +1,20 @@
+#if defined(_WIN32)
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+/* sleeps for n seconds, where n is the argument to the program */
+int main(int argc, char** argv)
+{
+ int time;
+ if (argc > 1) {
+ time = atoi(argv[1]);
+ }
+#if defined(_WIN32)
+ Sleep(time * 1000);
+#else
+ sleep(time);
+#endif
+ return 0;
+}
diff --git a/Tests/CTestTestUpload/test.cmake.in b/Tests/CTestTestUpload/test.cmake.in
new file mode 100644
index 0000000..74fd1ec
--- /dev/null
+++ b/Tests/CTestTestUpload/test.cmake.in
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-Upload")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestUpload")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestUpload")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_UPLOAD(FILES "${CTEST_SOURCE_DIRECTORY}/sleep.c" "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt")
+CTEST_SUBMIT()
diff --git a/Tests/CTestTestVerboseOutput/CMakeLists.txt b/Tests/CTestTestVerboseOutput/CMakeLists.txt
new file mode 100644
index 0000000..3792385
--- /dev/null
+++ b/Tests/CTestTestVerboseOutput/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(CTestTestVerboseOutput)
+include(CTest)
+
+add_executable(nop nop.c)
+
+add_test(NAME TestWithProperties COMMAND nop)
+set_property(TEST TestWithProperties PROPERTY ENVIRONMENT
+ "foo=bar"
+ "this=that"
+)
diff --git a/Tests/CTestTestVerboseOutput/CTestConfig.cmake b/Tests/CTestTestVerboseOutput/CTestConfig.cmake
new file mode 100644
index 0000000..bd265f9
--- /dev/null
+++ b/Tests/CTestTestVerboseOutput/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestVerboseOutput/nop.c b/Tests/CTestTestVerboseOutput/nop.c
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/CTestTestVerboseOutput/nop.c
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CTestTestVerboseOutput/test.cmake.in b/Tests/CTestTestVerboseOutput/test.cmake.in
new file mode 100644
index 0000000..9c9a4dc
--- /dev/null
+++ b/Tests/CTestTestVerboseOutput/test.cmake.in
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-VerboseOutput")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestVerboseOutput")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestVerboseOutput")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}")
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}")
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}")
diff --git a/Tests/CTestTestZeroTimeout/CMakeLists.txt b/Tests/CTestTestZeroTimeout/CMakeLists.txt
new file mode 100644
index 0000000..2d404c8
--- /dev/null
+++ b/Tests/CTestTestZeroTimeout/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required (VERSION 2.8.12)
+project (CTestTestZeroTimeout)
+include (CTest)
+
+add_executable (Sleep sleep.c)
+
+add_test (TestExplicitZeroTimeout Sleep)
+set_tests_properties(TestExplicitZeroTimeout PROPERTIES TIMEOUT 0)
diff --git a/Tests/CTestTestZeroTimeout/CTestConfig.cmake b/Tests/CTestTestZeroTimeout/CTestConfig.cmake
new file mode 100644
index 0000000..bd265f9
--- /dev/null
+++ b/Tests/CTestTestZeroTimeout/CTestConfig.cmake
@@ -0,0 +1,4 @@
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestZeroTimeout/sleep.c b/Tests/CTestTestZeroTimeout/sleep.c
new file mode 100644
index 0000000..5d0b89b
--- /dev/null
+++ b/Tests/CTestTestZeroTimeout/sleep.c
@@ -0,0 +1,16 @@
+#if defined(_WIN32)
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+/* sleeps for 5 seconds */
+int main(int argc, char** argv)
+{
+#if defined(_WIN32)
+ Sleep(5000);
+#else
+ sleep(5);
+#endif
+ return 0;
+}
diff --git a/Tests/CTestTestZeroTimeout/test.cmake.in b/Tests/CTestTestZeroTimeout/test.cmake.in
new file mode 100644
index 0000000..50dbba0
--- /dev/null
+++ b/Tests/CTestTestZeroTimeout/test.cmake.in
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Settings:
+set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-ZeroTimeout")
+
+set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestZeroTimeout")
+set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestZeroTimeout")
+set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+set(CTEST_TEST_TIMEOUT 2)
+
+CTEST_START(Experimental)
+CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
diff --git a/Tests/CTestUpdateBZR.cmake.in b/Tests/CTestUpdateBZR.cmake.in
new file mode 100644
index 0000000..da181d2
--- /dev/null
+++ b/Tests/CTestUpdateBZR.cmake.in
@@ -0,0 +1,153 @@
+# This script drives creation of a bzr repository and checks
+# that CTest can update from it.
+
+#-----------------------------------------------------------------------------
+# Test in a directory next to this script.
+get_filename_component(TOP "${CMAKE_CURRENT_LIST_FILE}" PATH)
+string(APPEND TOP "/@CTestUpdateBZR_DIR@")
+
+# Include code common to all update tests.
+include("@CMAKE_CURRENT_SOURCE_DIR@/CTestUpdateCommon.cmake")
+
+#-----------------------------------------------------------------------------
+# Report bzr tools in use.
+message("Using BZR tools:")
+set(BZR "@BZR_EXECUTABLE@")
+message(" bzr = ${BZR}")
+
+#-----------------------------------------------------------------------------
+# Initialize the testing directory.
+message("Creating test directory...")
+init_testing()
+
+#-----------------------------------------------------------------------------
+# Create the repository.
+message("Creating repository...")
+file(MAKE_DIRECTORY ${TOP}/repo.bzr)
+run_child(
+ WORKING_DIRECTORY ${TOP}/repo.bzr
+ COMMAND ${BZR} init
+ )
+set(REPO file://${TOP}/repo.bzr)
+
+#-----------------------------------------------------------------------------
+# Import initial content into the repository.
+message("Importing content...")
+create_content(import)
+
+# Import the content into the repository.
+run_child(WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${BZR} init
+ )
+run_child(WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${BZR} whoami --branch "Test Author <testauthor@cmake.org>"
+ )
+
+run_child(WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${BZR} add .
+ )
+run_child(WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${BZR} commit -m "Initial content"
+ )
+run_child(WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${BZR} push --create-prefix "${REPO}"
+ )
+
+#-----------------------------------------------------------------------------
+# Create a working tree.
+message("Checking out revision 1...")
+run_child(
+ WORKING_DIRECTORY ${TOP}
+ COMMAND ${BZR} branch "${REPO}" user-source
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${BZR} whoami --branch "Test Author <testauthor@cmake.org>"
+ )
+
+#-----------------------------------------------------------------------------
+# Make changes in the working tree.
+message("Changing content...")
+update_content(user-source files_added files_removed dirs_added)
+if(dirs_added)
+ run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${BZR} add ${dirs_added}
+ )
+endif()
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${BZR} add ${files_added}
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${BZR} rm ${files_removed}
+ )
+
+#-----------------------------------------------------------------------------
+# Commit the changes to the repository.
+message("Committing revision 2...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${BZR} commit -m "Changed content"
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${BZR} push "${REPO}"
+ )
+
+#-----------------------------------------------------------------------------
+# Make changes in the working tree.
+message("Changing content again...")
+change_content(user-source)
+
+#-----------------------------------------------------------------------------
+# Commit the changes to the repository.
+message("Committing revision 3...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${BZR} commit -m "Changed content again"
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${BZR} push "${REPO}"
+ )
+
+#-----------------------------------------------------------------------------
+# Go back to before the changes so we can test updating.
+message("Backing up to revision 1...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${BZR} pull --overwrite -r1
+ )
+
+# Create a modified file.
+modify_content(user-source)
+
+#-----------------------------------------------------------------------------
+# Test updating the user work directory with the command-line interface.
+message("Running CTest Dashboard Command Line...")
+
+# Create the user build tree.
+create_build_tree(user-source user-binary)
+file(APPEND ${TOP}/user-binary/CTestConfiguration.ini
+ "# BZR command configuration
+UpdateCommand: ${BZR}
+")
+
+# Run the dashboard command line interface.
+run_dashboard_command_line(user-binary)
+
+#-----------------------------------------------------------------------------
+# Test initial checkout and update with a dashboard script.
+message("Running CTest Dashboard Script...")
+
+create_dashboard_script(dash-binary
+ "# bzr command configuration
+set(CTEST_BZR_COMMAND \"${BZR}\")
+set(CTEST_CHECKOUT_COMMAND
+ \"\\\"\${CTEST_BZR_COMMAND}\\\" branch -r1 \\\"${REPO}\\\" dash-source\")
+")
+
+# Run the dashboard script with CTest.
+run_dashboard_script(dash-binary)
diff --git a/Tests/CTestUpdateCVS.cmake.in b/Tests/CTestUpdateCVS.cmake.in
new file mode 100644
index 0000000..8e0b611
--- /dev/null
+++ b/Tests/CTestUpdateCVS.cmake.in
@@ -0,0 +1,181 @@
+# This script drives creation of a CVS repository and checks
+# that CTest can update from it.
+
+#-----------------------------------------------------------------------------
+# Test in a directory next to this script.
+get_filename_component(TOP "${CMAKE_CURRENT_LIST_FILE}" PATH)
+string(APPEND TOP "/@CTestUpdateCVS_DIR@")
+set(UPDATE_NOT_GLOBAL 1)
+set(UPDATE_MAYBE Updated{CTestConfig.cmake})
+
+# Include code common to all update tests.
+include("@CMAKE_CURRENT_SOURCE_DIR@/CTestUpdateCommon.cmake")
+
+#-----------------------------------------------------------------------------
+# Report CVS tools in use.
+message("Using CVS tools:")
+set(CVS "@CVS_EXECUTABLE@")
+message(" cvs = ${CVS}")
+
+# Pre-pending :local: prevents cvs from trying to interpret Windows drive
+# letters, like "C:", as host names.
+set(REPO ":local:${TOP}/repo")
+
+set(CVSCMD ${CVS} -d "${REPO}")
+
+# CVSNT requires an extra option to 'cvs init'.
+set(CVS_INIT_OPT)
+execute_process(
+ COMMAND ${CVS} --version
+ RESULT_VARIABLE RESULT
+ OUTPUT_VARIABLE OUTPUT
+ ERROR_VARIABLE OUTPUT
+ )
+if("${RESULT}" STREQUAL "0" AND "${OUTPUT}" MATCHES "\\(CVSNT\\)")
+ set(CVS_INIT_OPT -n)
+ message(" cvs init needs -n")
+endif()
+
+#-----------------------------------------------------------------------------
+# Initialize the testing directory.
+message("Creating test directory...")
+init_testing()
+
+#-----------------------------------------------------------------------------
+# Create the repository.
+message("Creating repository...")
+file(MAKE_DIRECTORY ${TOP}/repo)
+run_child(
+ COMMAND ${CVSCMD} init ${CVS_INIT_OPT}
+ )
+
+#-----------------------------------------------------------------------------
+# Import initial content into the repository.
+message("Importing content...")
+create_content(import)
+
+# Import the content into the repository.
+run_child(
+ WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${CVSCMD} import -m "Initial content" Project vendor-tag release-tag
+ )
+
+#-----------------------------------------------------------------------------
+# Create a working tree.
+message("Checking out revision 1...")
+run_child(
+ WORKING_DIRECTORY ${TOP}
+ COMMAND ${CVSCMD} co -d user-source Project
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${CVSCMD} tag Revision1
+ )
+
+#-----------------------------------------------------------------------------
+# Make changes in the working tree.
+message("Changing content...")
+update_content(user-source files_added files_removed dirs_added)
+if(dirs_added)
+ run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${CVSCMD} add ${dirs_added}
+ )
+endif()
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${CVSCMD} add ${files_added}
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${CVSCMD} rm ${files_removed}
+ )
+
+#-----------------------------------------------------------------------------
+# Commit the changes to the repository.
+message("Committing revision 2...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${CVSCMD} commit -m "Changed content"
+ )
+
+#-----------------------------------------------------------------------------
+# Make changes in the working tree.
+message("Changing content again...")
+change_content(user-source)
+
+#-----------------------------------------------------------------------------
+# Commit the changes to the repository.
+message("Committing revision 3...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${CVSCMD} commit -m "Changed content again"
+ )
+
+#-----------------------------------------------------------------------------
+# Go back to before the changes so we can test updating.
+message("Backing up to revision 1...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${CVSCMD} up -rRevision1
+ )
+
+# Delay 1 second so the modification produces a newer time stamp.
+find_program(SLEEP sleep)
+if(SLEEP)
+ message("Delaying...")
+ execute_process(COMMAND ${SLEEP} 1)
+endif()
+
+# Create a modified file.
+message("Modifying locally...")
+modify_content(user-source)
+
+#-----------------------------------------------------------------------------
+# Test updating the user work directory with the command-line interface.
+message("Running CTest Dashboard Command Line...")
+
+# Create the user build tree.
+create_build_tree(user-source user-binary)
+file(APPEND ${TOP}/user-binary/CTestConfiguration.ini
+ "# CVS command configuration
+CVSCommand: ${CVS}
+CVSUpdateOptions: -dAP
+")
+
+# Run the dashboard command line interface.
+run_dashboard_command_line(user-binary)
+
+#-----------------------------------------------------------------------------
+# Test initial checkout and update with a dashboard script.
+message("Running CTest Dashboard Script...")
+
+create_dashboard_script(dash-binary
+ "# CVS command configuration
+set(CTEST_CVS_COMMAND \"${CVS}\")
+set(CTEST_CVS_UPDATE_OPTIONS -dAP)
+set(CTEST_CHECKOUT_COMMAND
+ \"\\\"\${CTEST_CVS_COMMAND}\\\" -d \\\"${REPO}\\\" co -rRevision1 -d dash-source Project\")
+")
+
+# Run the dashboard script with CTest.
+run_dashboard_script(dash-binary)
+
+#-----------------------------------------------------------------------------
+# Test ctest_update(RETURN_VALUE) on failure
+message("Running CTest Dashboard Script (fail to update)...")
+
+set(ctest_update_check [[
+if(NOT ret LESS 0)
+ message(FATAL_ERROR "ctest_update incorrectly succeeded with ${ret}")
+endif()
+]])
+create_dashboard_script(dash-binary-fail
+ "set(CTEST_CVS_COMMAND \"update-command-does-not-exist\")
+")
+unset(ctest_update_check)
+
+# Run the dashboard script with CTest.
+set(FAIL_UPDATE 1)
+run_dashboard_script(dash-binary-fail)
+unset(FAIL_UPDATE)
diff --git a/Tests/CTestUpdateCommon.cmake b/Tests/CTestUpdateCommon.cmake
new file mode 100644
index 0000000..0f8ec8e
--- /dev/null
+++ b/Tests/CTestUpdateCommon.cmake
@@ -0,0 +1,312 @@
+#-----------------------------------------------------------------------------
+# Function to run a child process and report output only on error.
+function(run_child)
+ execute_process(${ARGN}
+ RESULT_VARIABLE FAILED
+ OUTPUT_VARIABLE OUTPUT
+ ERROR_VARIABLE OUTPUT
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_STRIP_TRAILING_WHITESPACE
+ )
+ if(FAILED)
+ string(REPLACE "\n" "\n " OUTPUT "${OUTPUT}")
+ message(FATAL_ERROR "Child failed (${FAILED}), output is\n ${OUTPUT}\n"
+ "Command = [${ARGN}]\n")
+ endif()
+
+ # Pass output back up to the parent scope for possible further inspection.
+ set(OUTPUT "${OUTPUT}" PARENT_SCOPE)
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to find the Update.xml file and check for expected entries.
+function(check_updates build)
+ # Find the Update.xml file for the given build tree
+ set(PATTERN ${TOP}/${build}/Testing/*/Update.xml)
+ file(GLOB UPDATE_XML_FILE RELATIVE ${TOP} ${PATTERN})
+ string(REGEX REPLACE "//Update.xml$" "/Update.xml"
+ UPDATE_XML_FILE "${UPDATE_XML_FILE}"
+ )
+ if(NOT UPDATE_XML_FILE)
+ message(FATAL_ERROR "Cannot find Update.xml with pattern\n ${PATTERN}")
+ endif()
+ message(" found ${UPDATE_XML_FILE}")
+
+ set(max_update_xml_size 16384)
+
+ # Read entries from the Update.xml file
+ set(types "Updated|Modified|Conflicting")
+ file(STRINGS ${TOP}/${UPDATE_XML_FILE} UPDATE_XML_ENTRIES
+ REGEX "<(${types}|FullName)>"
+ LIMIT_INPUT ${max_update_xml_size}
+ )
+
+ string(REGEX REPLACE
+ "[ \t]*<(${types})>[ \t]*;[ \t]*<FullName>([^<]*)</FullName>"
+ "\\1{\\2}" UPDATE_XML_ENTRIES "${UPDATE_XML_ENTRIES}")
+
+ # If specified, remove the given prefix from the files in Update.xml.
+ # Some VCS systems, like Perforce, return absolute locations
+ if(DEFINED REPOSITORY_FILE_PREFIX)
+ string(REPLACE
+ "${REPOSITORY_FILE_PREFIX}" ""
+ UPDATE_XML_ENTRIES "${UPDATE_XML_ENTRIES}")
+ endif()
+
+ # Compare expected and actual entries
+ set(EXTRA "${UPDATE_XML_ENTRIES}")
+ list(REMOVE_ITEM EXTRA ${ARGN} ${UPDATE_EXTRA} ${UPDATE_MAYBE})
+ set(MISSING "${ARGN}" ${UPDATE_EXTRA})
+ if(NOT "" STREQUAL "${UPDATE_XML_ENTRIES}")
+ list(REMOVE_ITEM MISSING ${UPDATE_XML_ENTRIES})
+ endif()
+
+ if(NOT UPDATE_NOT_GLOBAL)
+ set(rev_elements Revision PriorRevision ${UPDATE_GLOBAL_ELEMENTS})
+ string(REPLACE ";" "|" rev_regex "${rev_elements}")
+ set(rev_regex "^\t<(${rev_regex})>[^<\n]+</(${rev_regex})>$")
+ file(STRINGS ${TOP}/${UPDATE_XML_FILE} UPDATE_XML_REVISIONS
+ REGEX "${rev_regex}"
+ LIMIT_INPUT ${max_update_xml_size}
+ )
+ foreach(r IN LISTS UPDATE_XML_REVISIONS)
+ string(REGEX REPLACE "${rev_regex}" "\\1" element "${r}")
+ set(element_${element} 1)
+ endforeach()
+ foreach(element ${rev_elements})
+ if(NOT element_${element})
+ list(APPEND MISSING "global <${element}> element")
+ endif()
+ endforeach()
+ endif()
+
+ # Report the result
+ set(MSG "")
+ if(MISSING)
+ # List the missing entries
+ string(APPEND MSG "Update.xml is missing expected entries:\n")
+ foreach(f ${MISSING})
+ string(APPEND MSG " ${f}\n")
+ endforeach()
+ else()
+ # Success
+ message(" no entries missing from Update.xml")
+ endif()
+
+ # Report the result
+ if(EXTRA)
+ # List the extra entries
+ string(APPEND MSG "Update.xml has extra unexpected entries:\n")
+ foreach(f ${EXTRA})
+ string(APPEND MSG " ${f}\n")
+ endforeach()
+ else()
+ # Success
+ message(" no extra entries in Update.xml")
+ endif()
+
+ if(MSG)
+ # Provide the log file
+ file(GLOB UPDATE_LOG_FILE
+ ${TOP}/${build}/Testing/Temporary/LastUpdate*.log)
+ if(UPDATE_LOG_FILE)
+ file(READ ${UPDATE_LOG_FILE} UPDATE_LOG LIMIT ${max_update_xml_size})
+ string(REPLACE "\n" "\n " UPDATE_LOG "${UPDATE_LOG}")
+ string(APPEND MSG "Update log:\n ${UPDATE_LOG}")
+ else()
+ string(APPEND MSG "No update log found!")
+ endif()
+
+ # Display the error message
+ message(FATAL_ERROR "${MSG}")
+ endif()
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to create initial content.
+function(create_content dir)
+ file(MAKE_DIRECTORY ${TOP}/${dir})
+
+ # An example CTest project configuration file.
+ file(WRITE ${TOP}/${dir}/CTestConfig.cmake
+ "# CTest Configuration File
+set(CTEST_NIGHTLY_START_TIME \"21:00:00 EDT\")
+")
+
+ # Some other files.
+ file(WRITE ${TOP}/${dir}/foo.txt "foo\n")
+ file(WRITE ${TOP}/${dir}/bar.txt "bar\n")
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to update content.
+function(update_content dir added_var removed_var dirs_var)
+ file(APPEND ${TOP}/${dir}/foo.txt "foo line 2\n")
+ file(WRITE ${TOP}/${dir}/zot.txt "zot\n")
+ file(REMOVE ${TOP}/${dir}/bar.txt)
+ file(MAKE_DIRECTORY ${TOP}/${dir}/subdir)
+ file(WRITE ${TOP}/${dir}/subdir/foo.txt "foo\n")
+ file(WRITE ${TOP}/${dir}/subdir/bar.txt "bar\n")
+ set(${dirs_var} subdir PARENT_SCOPE)
+ set(${added_var} zot.txt subdir/foo.txt subdir/bar.txt PARENT_SCOPE)
+ set(${removed_var} bar.txt PARENT_SCOPE)
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to change existing files
+function(change_content dir)
+ file(APPEND ${TOP}/${dir}/foo.txt "foo line 3\n")
+ file(APPEND ${TOP}/${dir}/subdir/foo.txt "foo line 2\n")
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to create local modifications before update
+function(modify_content dir)
+ file(APPEND ${TOP}/${dir}/CTestConfig.cmake "# local modification\n")
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to write CTestConfiguration.ini content.
+function(create_build_tree src_dir bin_dir)
+ file(MAKE_DIRECTORY ${TOP}/${bin_dir})
+ file(WRITE ${TOP}/${bin_dir}/CTestConfiguration.ini
+ "# CTest Configuration File
+SourceDirectory: ${TOP}/${src_dir}
+BuildDirectory: ${TOP}/${bin_dir}
+Site: test.site
+BuildName: user-test
+")
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to write the dashboard test script.
+function(create_dashboard_script bin_dir custom_text)
+ if (NOT ctest_update_check)
+ set(ctest_update_check [[
+if(ret LESS 0)
+ message(FATAL_ERROR "ctest_update failed with ${ret}")
+endif()
+]])
+ endif()
+
+ # Write the dashboard script.
+ file(WRITE ${TOP}/${bin_dir}.cmake
+ "# CTest Dashboard Script
+set(CTEST_DASHBOARD_ROOT \"${TOP}\")
+set(CTEST_SITE test.site)
+set(CTEST_BUILD_NAME dash-test)
+set(CTEST_SOURCE_DIRECTORY \${CTEST_DASHBOARD_ROOT}/dash-source)
+set(CTEST_BINARY_DIRECTORY \${CTEST_DASHBOARD_ROOT}/${bin_dir})
+${custom_text}
+# Start a dashboard and run the update step
+ctest_start(Experimental)
+ctest_update(SOURCE \${CTEST_SOURCE_DIRECTORY} RETURN_VALUE ret ${ctest_update_args})
+${ctest_update_check}")
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to run the dashboard through the command line
+function(run_dashboard_command_line bin_dir)
+ run_child(
+ WORKING_DIRECTORY ${TOP}/${bin_dir}
+ COMMAND ${CMAKE_CTEST_COMMAND} -M Experimental -T Start -T Update
+ )
+
+ # Verify the updates reported by CTest.
+ list(APPEND UPDATE_MAYBE Updated{subdir})
+ set(_modified Modified{CTestConfig.cmake})
+ if(UPDATE_NO_MODIFIED)
+ set(_modified "")
+ endif()
+ check_updates(${bin_dir}
+ Updated{foo.txt}
+ Updated{bar.txt}
+ Updated{zot.txt}
+ Updated{subdir/foo.txt}
+ Updated{subdir/bar.txt}
+ ${_modified}
+ )
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to find the Update.xml file and make sure
+# it only has the Revision in it and no updates
+function(check_no_update bin_dir)
+ set(PATTERN ${TOP}/${bin_dir}/Testing/*/Update.xml)
+ file(GLOB UPDATE_XML_FILE RELATIVE ${TOP} ${PATTERN})
+ string(REGEX REPLACE "//Update.xml$" "/Update.xml"
+ UPDATE_XML_FILE "${UPDATE_XML_FILE}")
+ message(" found ${UPDATE_XML_FILE}")
+ set(rev_regex "Revision|PriorRevision")
+ file(STRINGS ${TOP}/${UPDATE_XML_FILE} UPDATE_XML_REVISIONS
+ REGEX "^\t<(${rev_regex})>[^<\n]+</(${rev_regex})>$"
+ )
+ set(found_revisons FALSE)
+ foreach(r IN LISTS UPDATE_XML_REVISIONS)
+ if("${r}" MATCHES "PriorRevision")
+ message(FATAL_ERROR "Found PriorRevision in no update test")
+ endif()
+ if("${r}" MATCHES "<Revision>")
+ set(found_revisons TRUE)
+ endif()
+ endforeach()
+ if(found_revisons)
+ message(" found <Revision> in no update test")
+ else()
+ message(FATAL_ERROR " missing <Revision> in no update test")
+ endif()
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to find the Update.xml file and make sure
+# it only has the UpdateReturnStatus failure message and no updates.
+function(check_fail_update bin_dir)
+ set(PATTERN ${TOP}/${bin_dir}/Testing/*/Update.xml)
+ file(GLOB UPDATE_XML_FILE RELATIVE ${TOP} ${PATTERN})
+ string(REGEX REPLACE "//Update.xml$" "/Update.xml"
+ UPDATE_XML_FILE "${UPDATE_XML_FILE}")
+ message(" found ${UPDATE_XML_FILE}")
+ file(STRINGS ${TOP}/${UPDATE_XML_FILE} UPDATE_XML_STATUS
+ REGEX "^\t<UpdateReturnStatus>[^<\n]+"
+ )
+ if(UPDATE_XML_STATUS MATCHES "Update command failed")
+ message(" correctly found 'Update command failed'")
+ else()
+ message(FATAL_ERROR " missing 'Update command failed'")
+ endif()
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to run the dashboard through a script
+function(run_dashboard_script bin_dir)
+ run_child(
+ WORKING_DIRECTORY ${TOP}
+ COMMAND ${CMAKE_CTEST_COMMAND} -S ${bin_dir}.cmake -V
+ )
+
+ # Verify the updates reported by CTest.
+ list(APPEND UPDATE_MAYBE Updated{subdir} Updated{CTestConfig.cmake})
+ if(NO_UPDATE)
+ check_no_update(${bin_dir})
+ elseif(FAIL_UPDATE)
+ check_fail_update(${bin_dir})
+ else()
+ check_updates(${bin_dir}
+ Updated{foo.txt}
+ Updated{bar.txt}
+ Updated{zot.txt}
+ Updated{subdir/foo.txt}
+ Updated{subdir/bar.txt}
+ )
+ endif()
+
+ # Pass console output up to the parent, in case they'd like to inspect it.
+ set(OUTPUT "${OUTPUT}" PARENT_SCOPE)
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Function to initialize the testing directory.
+function(init_testing)
+ file(REMOVE_RECURSE ${TOP})
+ file(MAKE_DIRECTORY ${TOP})
+endfunction()
diff --git a/Tests/CTestUpdateGIT.cmake.in b/Tests/CTestUpdateGIT.cmake.in
new file mode 100644
index 0000000..a3ef4eb
--- /dev/null
+++ b/Tests/CTestUpdateGIT.cmake.in
@@ -0,0 +1,386 @@
+# This script drives creation of a git repository and checks
+# that CTest can update from it.
+
+#-----------------------------------------------------------------------------
+# Test in a directory next to this script.
+get_filename_component(TOP "${CMAKE_CURRENT_LIST_FILE}" PATH)
+string(APPEND TOP "/@CTestUpdateGIT_DIR@")
+set(UPDATE_EXTRA Updated{module})
+
+# Include code common to all update tests.
+include("@CMAKE_CURRENT_SOURCE_DIR@/CTestUpdateCommon.cmake")
+
+#-----------------------------------------------------------------------------
+# Report git tools in use.
+message("Using GIT tools:")
+set(GIT "@GIT_EXECUTABLE@")
+message(" git = ${GIT}")
+
+set(AUTHOR_CONFIG "[user]
+\tname = Test Author
+\temail = testauthor@cmake.org
+")
+
+#-----------------------------------------------------------------------------
+# Initialize the testing directory.
+message("Creating test directory...")
+init_testing()
+
+if(UNIX)
+ set(src "@CMAKE_CURRENT_SOURCE_DIR@")
+ configure_file(${src}/CTestUpdateGIT.sh.in ${TOP}/git.sh @ONLY)
+ set(GIT ${TOP}/git.sh)
+endif()
+
+# Adapt to the system default branch name.
+execute_process(
+ COMMAND ${GIT} config --get init.defaultBranch
+ RESULT_VARIABLE defaultBranchFailed
+ OUTPUT_VARIABLE defaultBranch
+ ERROR_VARIABLE defaultBranchError
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_STRIP_TRAILING_WHITESPACE
+ )
+if(defaultBranch STREQUAL "")
+ set(defaultBranch master)
+endif()
+message("Detected default branch name '${defaultBranch}'")
+
+#-----------------------------------------------------------------------------
+# Create the repository.
+message("Creating repository...")
+file(MAKE_DIRECTORY ${TOP}/repo.git)
+run_child(
+ WORKING_DIRECTORY ${TOP}/repo.git
+ COMMAND ${GIT} --bare init
+ )
+file(REMOVE_RECURSE ${TOP}/repo.git/hooks)
+
+# Create submodule repository.
+message("Creating submodule...")
+file(MAKE_DIRECTORY ${TOP}/module.git)
+run_child(
+ WORKING_DIRECTORY ${TOP}/module.git
+ COMMAND ${GIT} --bare init
+ )
+file(REMOVE_RECURSE ${TOP}/module.git/hooks)
+run_child(WORKING_DIRECTORY ${TOP}
+ COMMAND ${GIT} clone module.git module
+ )
+file(REMOVE_RECURSE ${TOP}/module/.git/hooks)
+file(APPEND ${TOP}/module/.git/config "
+${AUTHOR_CONFIG}")
+create_content(module)
+run_child(WORKING_DIRECTORY ${TOP}/module
+ COMMAND ${GIT} add .
+ )
+run_child(WORKING_DIRECTORY ${TOP}/module
+ COMMAND ${GIT} commit -m "Initial content"
+ )
+run_child(WORKING_DIRECTORY ${TOP}/module
+ COMMAND ${GIT} push origin ${defaultBranch}:refs/heads/${defaultBranch}
+ )
+
+#-----------------------------------------------------------------------------
+# Import initial content into the repository.
+message("Importing content...")
+
+# Import the content into the repository.
+run_child(WORKING_DIRECTORY ${TOP}
+ COMMAND ${GIT} clone repo.git import
+ )
+file(REMOVE_RECURSE ${TOP}/import/.git/hooks)
+file(APPEND ${TOP}/import/.git/config "
+${AUTHOR_CONFIG}")
+create_content(import)
+file(WRITE ${TOP}/import/HEAD "HEAD\n")
+file(WRITE ${TOP}/import/${defaultBranch} "${defaultBranch}\n")
+run_child(WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${GIT} add .
+ )
+run_child(WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${GIT} config core.safecrlf false
+ )
+run_child(WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${GIT} submodule add ../module.git module
+ )
+run_child(WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${GIT} commit -m "Initial content"
+ )
+run_child(WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${GIT} push origin ${defaultBranch}:refs/heads/${defaultBranch}
+ )
+
+#-----------------------------------------------------------------------------
+# Modify the submodule.
+change_content(module)
+run_child(WORKING_DIRECTORY ${TOP}/module
+ COMMAND ${GIT} add -u
+ )
+run_child(WORKING_DIRECTORY ${TOP}/module
+ COMMAND ${GIT} commit -m "Changed content"
+ )
+run_child(WORKING_DIRECTORY ${TOP}/module
+ COMMAND ${GIT} push origin ${defaultBranch}:refs/heads/${defaultBranch}
+ )
+
+#-----------------------------------------------------------------------------
+# Create a working tree.
+message("Checking out revision 1...")
+run_child(
+ WORKING_DIRECTORY ${TOP}
+ COMMAND ${GIT} clone repo.git user-source
+ )
+file(REMOVE_RECURSE ${TOP}/user-source/.git/hooks)
+file(APPEND ${TOP}/user-source/.git/config "${AUTHOR_CONFIG}")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${GIT} submodule init
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${GIT} submodule update
+ )
+
+# Save the first revision name.
+execute_process(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${GIT} rev-parse HEAD
+ OUTPUT_VARIABLE revision1
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
+#-----------------------------------------------------------------------------
+# Create an empty commit.
+message("Creating empty commit...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${GIT} commit --allow-empty -m "Empty commit"
+ )
+
+#-----------------------------------------------------------------------------
+# Make changes in the working tree.
+message("Changing content...")
+update_content(user-source files_added files_removed dirs_added)
+if(dirs_added)
+ run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${GIT} add -- ${dirs_added}
+ )
+endif()
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${GIT} add -- ${files_added}
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${GIT} rm -- ${files_removed}
+ )
+run_child(WORKING_DIRECTORY ${TOP}/user-source/module
+ COMMAND ${GIT} checkout ${defaultBranch} --
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${GIT} add -u
+ )
+
+#-----------------------------------------------------------------------------
+# Commit the changes to the repository.
+message("Committing revision 2...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${GIT} commit -m "Changed content"
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${GIT} push origin
+ )
+
+#-----------------------------------------------------------------------------
+# Make changes in the working tree.
+message("Changing content again...")
+change_content(user-source)
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${GIT} add -u
+ )
+
+#-----------------------------------------------------------------------------
+# Commit the changes to the repository.
+message("Committing revision 3...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${GIT} commit -m "Changed content again"
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${GIT} push origin
+ )
+
+#-----------------------------------------------------------------------------
+# Go back to before the changes so we can test updating.
+macro(rewind_source src_dir)
+ message("Backing up to revision 1...")
+ run_child(
+ WORKING_DIRECTORY ${TOP}/${src_dir}
+ COMMAND ${GIT} reset --hard ${revision1}
+ )
+ run_child(
+ WORKING_DIRECTORY ${TOP}/${src_dir}
+ COMMAND ${GIT} submodule update
+ )
+endmacro()
+rewind_source(user-source)
+
+# Make sure pull does not try to rebase (which does not work with
+# modified files) even if ~/.gitconfig sets "branch.master.rebase".
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${GIT} config branch.${defaultBranch}.rebase false
+ )
+
+# Create a modified file.
+modify_content(user-source)
+
+#-----------------------------------------------------------------------------
+# Test updating the user work directory with the command-line interface.
+message("Running CTest Dashboard Command Line...")
+
+# Create the user build tree.
+create_build_tree(user-source user-binary)
+file(APPEND ${TOP}/user-binary/CTestConfiguration.ini
+ "# GIT command configuration
+UpdateCommand: ${GIT}
+")
+
+# Run the dashboard command line interface.
+set(UPDATE_NO_MODIFIED 1)
+run_dashboard_command_line(user-binary)
+set(UPDATE_NO_MODIFIED 0)
+
+rewind_source(user-source)
+modify_content(user-source)
+
+message("Running CTest Dashboard Command Line (custom update)...")
+
+# Create the user build tree.
+create_build_tree(user-source user-binary-custom)
+file(APPEND ${TOP}/user-binary-custom/CTestConfiguration.ini
+ "# GIT command configuration
+UpdateCommand: ${GIT}
+GITUpdateCustom: ${GIT};pull;origin;${defaultBranch}
+")
+
+# Run the dashboard command line interface.
+run_dashboard_command_line(user-binary-custom)
+
+#-----------------------------------------------------------------------------
+# Test initial checkout and update with a dashboard script.
+message("Running CTest Dashboard Script...")
+
+create_dashboard_script(dash-binary
+ "# git command configuration
+set(CTEST_GIT_COMMAND \"${GIT}\")
+set(CTEST_GIT_UPDATE_OPTIONS)
+execute_process(
+ WORKING_DIRECTORY \"${TOP}\"
+ COMMAND \"${GIT}\" clone repo.git dash-source
+ )
+
+# Test .git file.
+file(RENAME \"${TOP}/dash-source/.git\" \"${TOP}/dash-source/repo.git\")
+file(WRITE \"${TOP}/dash-source/.git\" \"gitdir: repo.git\n\")
+
+execute_process(
+ WORKING_DIRECTORY \"${TOP}/dash-source\"
+ COMMAND \"${GIT}\" reset --hard ${revision1}
+ )
+execute_process(
+ WORKING_DIRECTORY \"${TOP}/dash-source\"
+ COMMAND \"${GIT}\" submodule init
+ )
+execute_process(
+ WORKING_DIRECTORY \"${TOP}/dash-source\"
+ COMMAND \"${GIT}\" submodule update
+ )
+")
+
+# Run the dashboard script with CTest.
+run_dashboard_script(dash-binary)
+
+rewind_source(dash-source)
+
+#-----------------------------------------------------------------------------
+# Test custom update with a dashboard script.
+message("Running CTest Dashboard Script (custom update)...")
+
+create_dashboard_script(dash-binary-custom
+ "# git command configuration
+set(CTEST_GIT_COMMAND \"${GIT}\")
+set(CTEST_GIT_UPDATE_OPTIONS)
+set(CTEST_GIT_UPDATE_CUSTOM \${CTEST_GIT_COMMAND} pull origin ${defaultBranch})
+")
+
+# Run the dashboard script with CTest.
+run_dashboard_script(dash-binary-custom)
+
+
+rewind_source(dash-source)
+
+#-----------------------------------------------------------------------------
+# Test no update with a dashboard script.
+message("Running CTest Dashboard Script (No update)...")
+
+create_dashboard_script(dash-binary-no-update
+ "# git command configuration
+set(CTEST_GIT_COMMAND \"${GIT}\")
+set(CTEST_UPDATE_VERSION_ONLY TRUE)
+")
+
+# Run the dashboard script with CTest.
+set(NO_UPDATE 1)
+run_dashboard_script(dash-binary-no-update)
+unset(NO_UPDATE)
+
+rewind_source(dash-source)
+
+#-----------------------------------------------------------------------------
+# Test ctest_update(QUIET)
+message("Running CTest Dashboard Script (update quietly)...")
+
+set(ctest_update_args QUIET)
+create_dashboard_script(dash-binary-quiet
+ "# git command configuration
+set(CTEST_GIT_COMMAND \"${GIT}\")
+set(CTEST_GIT_UPDATE_OPTIONS)
+set(CTEST_GIT_UPDATE_CUSTOM \${CTEST_GIT_COMMAND} pull origin ${defaultBranch})
+")
+unset(ctest_update_args)
+
+# Run the dashboard script with CTest.
+run_dashboard_script(dash-binary-quiet)
+
+# Make sure the output seems quiet.
+if("${OUTPUT}" MATCHES "Updating the repository")
+ message(FATAL_ERROR "Found 'Updating the repository' in quiet output")
+endif()
+
+#-----------------------------------------------------------------------------
+# Test ctest_update(RETURN_VALUE) on failure
+message("Running CTest Dashboard Script (fail to update)...")
+
+set(ctest_update_check [[
+
+if(NOT ret LESS 0)
+ message(FATAL_ERROR "ctest_update incorrectly succeeded with ${ret}")
+endif()
+]])
+create_dashboard_script(dash-binary-fail
+ "set(CTEST_GIT_COMMAND \"update-command-does-not-exist\")
+")
+unset(ctest_update_check)
+
+# Run the dashboard script with CTest.
+set(FAIL_UPDATE 1)
+run_dashboard_script(dash-binary-fail)
+unset(FAIL_UPDATE)
diff --git a/Tests/CTestUpdateGIT.sh.in b/Tests/CTestUpdateGIT.sh.in
new file mode 100755
index 0000000..e7586d6
--- /dev/null
+++ b/Tests/CTestUpdateGIT.sh.in
@@ -0,0 +1,6 @@
+#!/bin/sh
+if test "x$1" = "xpull" -o "x$1" = "xreset"; then
+ "@GIT@" "$@" && sleep 1 && touch foo.txt
+else
+ exec "@GIT@" "$@"
+fi
diff --git a/Tests/CTestUpdateHG.cmake.in b/Tests/CTestUpdateHG.cmake.in
new file mode 100644
index 0000000..055d309
--- /dev/null
+++ b/Tests/CTestUpdateHG.cmake.in
@@ -0,0 +1,185 @@
+# This script drives creation of a Mercurial repository and checks
+# that CTest can update from it.
+
+#-----------------------------------------------------------------------------
+# Test in a directory next to this script.
+get_filename_component(TOP "${CMAKE_CURRENT_LIST_FILE}" PATH)
+string(APPEND TOP "/@CTestUpdateHG_DIR@")
+
+# Include code common to all update tests.
+include("@CMAKE_CURRENT_SOURCE_DIR@/CTestUpdateCommon.cmake")
+
+#-----------------------------------------------------------------------------
+# Report hg tools in use.
+message("Using HG tools:")
+set(HG "@HG_EXECUTABLE@")
+message(" hg = ${HG}")
+
+#-----------------------------------------------------------------------------
+# Initialize the testing directory.
+message("Creating test directory...")
+init_testing()
+
+#-----------------------------------------------------------------------------
+# Create the repository.
+message("Creating repository...")
+file(MAKE_DIRECTORY ${TOP}/repo.hg)
+run_child(
+ WORKING_DIRECTORY ${TOP}/repo.hg
+ COMMAND ${HG} init
+ )
+if(NOT "${TOP}" MATCHES "^/")
+ set(slash /)
+endif()
+set(REPO file://${slash}${TOP}/repo.hg)
+
+#-----------------------------------------------------------------------------
+# Import initial content into the repository.
+message("Importing content...")
+create_content(import)
+
+# Import the content into the repository.
+run_child(WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${HG} init
+ )
+run_child(WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${HG} add .
+ )
+run_child(WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${HG} commit -m "Initial content"
+ -u "Test Author <testauthor@cmake.org>"
+ )
+run_child(WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${HG} push "${REPO}"
+ )
+
+#-----------------------------------------------------------------------------
+# Create a working tree.
+message("Checking out first revision...")
+run_child(
+ WORKING_DIRECTORY ${TOP}
+ COMMAND ${HG} clone ${REPO} user-source
+ )
+
+#-----------------------------------------------------------------------------
+# Make changes in the working tree.
+message("Changing content...")
+update_content(user-source files_added files_removed dirs_added)
+if(dirs_added)
+ run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${HG} add ${dirs_added}
+ )
+endif()
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${HG} add ${files_added}
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${HG} rm ${files_removed}
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${HG} add
+ )
+
+#-----------------------------------------------------------------------------
+# Commit the changes to the repository.
+message("Committing revision 2...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${HG} commit -m "Changed content"
+ -u "Test Author <testauthor@cmake.org>"
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${HG} push
+ )
+
+#-----------------------------------------------------------------------------
+# Make changes in the working tree.
+message("Changing content again...")
+change_content(user-source)
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${HG} add
+ )
+
+#-----------------------------------------------------------------------------
+# Commit the changes to the repository.
+message("Committing revision 3...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${HG} commit -m "Changed content again"
+ -u "Test Author <testauthor@cmake.org>"
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${HG} push
+ )
+
+#-----------------------------------------------------------------------------
+# Go back to before the changes so we can test updating.
+message("Backing up to first revision...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${HG} update -C -r 0
+ )
+
+# Create a modified file.
+modify_content(user-source)
+
+#-----------------------------------------------------------------------------
+# Test updating the user work directory with the command-line interface.
+message("Running CTest Dashboard Command Line...")
+
+# Create the user build tree.
+create_build_tree(user-source user-binary)
+file(APPEND ${TOP}/user-binary/CTestConfiguration.ini
+ "# HG command configuration
+UpdateCommand: ${HG}
+")
+
+# Run the dashboard command line interface.
+run_dashboard_command_line(user-binary)
+
+#-----------------------------------------------------------------------------
+# Test initial checkout and update with a dashboard script.
+message("Running CTest Dashboard Script...")
+
+create_dashboard_script(dash-binary
+ "# hg command configuration
+set(CTEST_HG_COMMAND \"${HG}\")
+set(CTEST_HG_UPDATE_OPTIONS)
+execute_process(
+ WORKING_DIRECTORY \"${TOP}\"
+ COMMAND \"${HG}\" clone \"${REPO}\" dash-source
+ )
+execute_process(
+ WORKING_DIRECTORY \"${TOP}/dash-source\"
+ COMMAND \"${HG}\" update -C -r 0
+ )
+")
+
+# Run the dashboard script with CTest.
+run_dashboard_script(dash-binary)
+
+#-----------------------------------------------------------------------------
+# Test ctest_update(RETURN_VALUE) on failure
+message("Running CTest Dashboard Script (fail to update)...")
+
+set(ctest_update_check [[
+if(NOT ret LESS 0)
+ message(FATAL_ERROR "ctest_update incorrectly succeeded with ${ret}")
+endif()
+]])
+create_dashboard_script(dash-binary-fail
+ "set(CTEST_HG_COMMAND \"update-command-does-not-exist\")
+")
+unset(ctest_update_check)
+
+# Run the dashboard script with CTest.
+set(FAIL_UPDATE 1)
+run_dashboard_script(dash-binary-fail)
+unset(FAIL_UPDATE)
diff --git a/Tests/CTestUpdateP4.cmake.in b/Tests/CTestUpdateP4.cmake.in
new file mode 100644
index 0000000..5eef9fb
--- /dev/null
+++ b/Tests/CTestUpdateP4.cmake.in
@@ -0,0 +1,261 @@
+# This script drives creation of a perforce repository and checks
+# that CTest can update from it.
+
+#-----------------------------------------------------------------------------
+# Test in a directory next to this script.
+get_filename_component(TOP "${CMAKE_CURRENT_LIST_FILE}" PATH)
+set(P4_TOP "${TOP}")
+string(APPEND TOP "/@CTestUpdateP4_DIR@")
+
+# Include code common to all update tests.
+set(REPOSITORY_FILE_PREFIX "//ctest/")
+include("@CMAKE_CURRENT_SOURCE_DIR@/CTestUpdateCommon.cmake")
+
+#-----------------------------------------------------------------------------
+# Perforce server options
+set(P4_HOST localhost)
+set(P4_PORT 1888)
+
+#-----------------------------------------------------------------------------
+# Report p4 tools in use and set its defaults
+message("Using P4 tools:")
+set(P4 "@P4_EXECUTABLE@")
+set(P4D "@P4D_EXECUTABLE@")
+message(" p4 = ${P4}")
+message(" p4d = ${P4D}")
+
+set(P4_CLIENT -c ctest_p4)
+set(P4_OPTIONS -H ${P4_HOST} -p ${P4_PORT})
+set(P4CMD ${P4} ${P4_OPTIONS})
+
+#-----------------------------------------------------------------------------
+# Start the Perforce server
+if(UNIX)
+ set(P4_ROOT ${P4_TOP}/perforce)
+
+ message("Starting p4d on '${P4_ROOT}' listening on port ${P4_PORT}...")
+
+ # Stop a previous instance of Perforce running
+ execute_process(
+ WORKING_DIRECTORY ${TOP}
+ COMMAND ${P4CMD} admin stop
+ OUTPUT_QUIET
+ ERROR_QUIET
+ )
+
+ # Make sure we don't have a perforce directory from a previous run
+ file(REMOVE_RECURSE ${P4_ROOT})
+ file(MAKE_DIRECTORY ${P4_ROOT})
+
+ set(P4_SERVER "nohup '${P4D}' -d -r '${P4_ROOT}'")
+ string(APPEND P4_SERVER " -L '${P4_ROOT}/p4.log'")
+ string(APPEND P4_SERVER " -J '${P4_ROOT}/journal'")
+ string(APPEND P4_SERVER " -p ${P4_PORT} >/dev/null 2>&1 &")
+
+ message("Server command line: ${P4_SERVER}")
+
+ execute_process(
+ COMMAND sh -c "
+${P4_SERVER}
+for i in 1 2 3 4 5 6 7 8 9 10; do
+ echo 'Waiting for server to start...'
+ sleep 1
+ if '${P4}' -H ${P4_HOST} -p ${P4_PORT} help >/dev/null 2>&1; then
+ echo 'Server started.'
+ exit
+ fi
+done
+echo 'Gave up waiting for server to start.'
+"
+ )
+endif()
+
+#-----------------------------------------------------------------------------
+# Initialize the testing directory.
+message("Creating test directory...")
+init_testing()
+
+#-----------------------------------------------------------------------------
+# Create the repository.
+message("Creating depot...")
+file(WRITE ${TOP}/depot.spec "Depot: ctest\n")
+file(APPEND ${TOP}/depot.spec "Type: local\n")
+file(APPEND ${TOP}/depot.spec "Map: ctest/...\n")
+run_child(
+ WORKING_DIRECTORY ${TOP}
+ COMMAND ${P4CMD} depot -i
+ INPUT_FILE ${TOP}/depot.spec
+)
+
+#-----------------------------------------------------------------------------
+# Import initial content into the repository.
+message("Importing content...")
+create_content(user-source)
+
+message("Creating client spec...")
+file(WRITE ${TOP}/client.spec "Client: ctest_p4\n")
+file(APPEND ${TOP}/client.spec "Root: ${TOP}/user-source\n")
+file(APPEND ${TOP}/client.spec "View: //ctest/... //ctest_p4/...\n")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} client -i
+ INPUT_FILE ${TOP}/client.spec
+)
+
+# After creating the depot and the client view, all P4 commands need to
+# have the client spec passed to them
+list(APPEND P4CMD ${P4_CLIENT})
+
+message("Adding files to repository")
+file(GLOB_RECURSE files ${TOP}/user-source/*)
+foreach(filename ${files})
+ run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} add ${filename}
+ )
+endforeach()
+
+message("Submitting changes to repository")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} submit -d "CTEST: Initial content"
+)
+message("Tagging the repository")
+file(WRITE ${TOP}/label.spec "Label: r1\n")
+file(APPEND ${TOP}/label.spec "View: //ctest/...\n")
+
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} label -i
+ INPUT_FILE ${TOP}/label.spec
+)
+
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} labelsync -l r1
+)
+
+#-----------------------------------------------------------------------------
+# Make changes in the working tree.
+message("Changing content...")
+update_content(user-source files_added files_removed dirs_added)
+foreach(filename ${files_added})
+ message("add: ${filename}")
+ run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} add ${TOP}/user-source/${filename}
+ )
+endforeach()
+foreach(filename ${files_removed})
+ run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} delete ${TOP}/user-source/${filename}
+ )
+endforeach()
+
+#-----------------------------------------------------------------------------
+# Commit the changes to the repository.
+message("Committing revision 2...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} submit -d "CTEST: Changed content"
+)
+
+#-----------------------------------------------------------------------------
+# Make changes in the working tree.
+message("Changing content again...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} edit //ctest/...
+)
+
+change_content(user-source)
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} revert -a //ctest/...
+)
+
+#-----------------------------------------------------------------------------
+# Commit the changes to the repository.
+message("Committing revision 3...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} submit -d "CTEST: Changed content again"
+)
+
+#-----------------------------------------------------------------------------
+# Go back to before the changes so we can test updating.
+message("Backing up to revision 1...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} sync @r1
+ )
+
+# Create a modified file.
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} sync @r1
+ )
+
+# We should p4 open any files that modify_content creates
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} open ${TOP}/user-source/CTestConfig.cmake
+)
+modify_content(user-source)
+
+#-----------------------------------------------------------------------------
+# Test updating the user work directory with the command-line interface.
+message("Running CTest Dashboard Command Line...")
+
+# Create the user build tree.
+create_build_tree(user-source user-binary)
+file(APPEND ${TOP}/user-binary/CTestConfiguration.ini
+ "# P4 command configuration
+UpdateCommand: ${P4}
+P4Client: ctest_p4
+P4Options: -H ${P4_HOST} -p ${P4_PORT}
+")
+
+# Run the dashboard command line interface.
+run_dashboard_command_line(user-binary)
+
+# Revert the modified files
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${P4CMD} revert ${TOP}/user-source/CTestConfig.cmake
+)
+
+#-----------------------------------------------------------------------------
+# Test initial checkout and update with a dashboard script.
+# Create a new client so we can check out files on a different directory
+message("Running CTest Dashboard Script...")
+
+message("Creating client spec...")
+file(WRITE ${TOP}/client2.spec "Client: ctest2_p4\n")
+file(APPEND ${TOP}/client2.spec "Root: ${TOP}/dash-source\n")
+file(APPEND ${TOP}/client2.spec "View: //ctest/... //ctest2_p4/...\n")
+run_child(
+ COMMAND ${P4CMD} client -i
+ INPUT_FILE ${TOP}/client2.spec
+)
+
+file(MAKE_DIRECTORY ${TOP}/dash-source)
+
+create_dashboard_script(dash-binary
+ "# P4 command configuration
+set(CTEST_P4_CLIENT \"ctest2_p4\")
+set(CTEST_P4_OPTIONS \"-H ${P4_HOST} -p ${P4_PORT}\")
+set(CTEST_UPDATE_COMMAND \"${P4}\")
+")
+
+# Run the dashboard script with CTest.
+run_dashboard_script(dash-binary)
+
+#-----------------------------------------------------------------------------
+# Clean up
+message("Shutting down p4d")
+run_child(
+ WORKING_DIRECTORY ${TOP}
+ COMMAND ${P4CMD} admin stop
+) \ No newline at end of file
diff --git a/Tests/CTestUpdateSVN.cmake.in b/Tests/CTestUpdateSVN.cmake.in
new file mode 100644
index 0000000..12a3526
--- /dev/null
+++ b/Tests/CTestUpdateSVN.cmake.in
@@ -0,0 +1,168 @@
+# This script drives creation of a Subversion repository and checks
+# that CTest can update from it.
+
+#-----------------------------------------------------------------------------
+# Test in a directory next to this script.
+get_filename_component(TOP "${CMAKE_CURRENT_LIST_FILE}" PATH)
+string(APPEND TOP "/@CTestUpdateSVN_DIR@")
+set(UPDATE_GLOBAL_ELEMENTS SVNPath)
+
+# Include code common to all update tests.
+include("@CMAKE_CURRENT_SOURCE_DIR@/CTestUpdateCommon.cmake")
+
+#-----------------------------------------------------------------------------
+# Report subversion tools in use.
+message("Using subversion tools:")
+set(SVN "@Subversion_SVN_EXECUTABLE@")
+set(SVNADMIN "@Subversion_SVNADMIN_EXECUTABLE@")
+message(" svn = ${SVN}")
+message(" svnadmin = ${SVNADMIN}")
+
+# Isolate svn test operations from the user configuration.
+file(MAKE_DIRECTORY ${TOP}/config)
+set(SVNCMD ${SVN} --config-dir ${TOP}/config)
+set(SVNUSER --username "test author" --non-interactive)
+
+# Configure for this svn version.
+execute_process(
+ COMMAND ${SVN} help add OUTPUT_VARIABLE help_add ERROR_VARIABLE help_add
+ )
+if("${help_add}" MATCHES "--depth")
+ set(depth_empty "--depth=empty")
+else()
+ set(depth_empty "")
+endif()
+
+#-----------------------------------------------------------------------------
+# Initialize the testing directory.
+message("Creating test directory...")
+init_testing()
+
+#-----------------------------------------------------------------------------
+# Create the repository.
+message("Creating repository...")
+run_child(
+ COMMAND ${SVNADMIN} create --config-dir ${TOP}/config ${TOP}/repo
+ )
+set(REPO file:///${TOP}/repo/trunk)
+
+#-----------------------------------------------------------------------------
+# Import initial content into the repository.
+message("Importing content...")
+create_content(import)
+
+# Import the content into the repository.
+run_child(
+ WORKING_DIRECTORY ${TOP}/import
+ COMMAND ${SVNCMD} import ${SVNUSER} -m "Initial content" . "${REPO}"
+ )
+
+#-----------------------------------------------------------------------------
+# Create a working tree.
+message("Checking out revision 1...")
+run_child(
+ WORKING_DIRECTORY ${TOP}
+ COMMAND ${SVNCMD} co ${SVNUSER} ${REPO} user-source
+ )
+
+#-----------------------------------------------------------------------------
+# Make changes in the working tree.
+message("Changing content...")
+update_content(user-source files_added files_removed dirs_added)
+if(dirs_added)
+ run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${SVNCMD} add ${depth_empty} ${dirs_added}
+ )
+endif()
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${SVNCMD} add ${files_added}
+ )
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${SVNCMD} rm ${files_removed}
+ )
+
+#-----------------------------------------------------------------------------
+# Commit the changes to the repository.
+message("Committing revision 2...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${SVNCMD} commit -m "Changed content"
+ )
+
+#-----------------------------------------------------------------------------
+# Make changes in the working tree.
+message("Changing content again...")
+change_content(user-source)
+
+#-----------------------------------------------------------------------------
+# Commit the changes to the repository.
+message("Committing revision 3...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${SVNCMD} commit -m "Changed content again"
+ )
+
+#-----------------------------------------------------------------------------
+# Go back to before the changes so we can test updating.
+message("Backing up to revision 1...")
+run_child(
+ WORKING_DIRECTORY ${TOP}/user-source
+ COMMAND ${SVNCMD} up -r1
+ )
+
+# Create a modified file.
+message("Modifying locally...")
+modify_content(user-source)
+
+#-----------------------------------------------------------------------------
+# Test updating the user work directory with the command-line interface.
+message("Running CTest Dashboard Command Line...")
+
+# Create the user build tree.
+create_build_tree(user-source user-binary)
+file(APPEND ${TOP}/user-binary/CTestConfiguration.ini
+ "# SVN command configuration
+SVNCommand: ${SVN}
+SVNUpdateOptions: --config-dir \"${TOP}/config\"
+")
+
+# Run the dashboard command line interface.
+run_dashboard_command_line(user-binary)
+
+#-----------------------------------------------------------------------------
+# Test initial checkout and update with a dashboard script.
+message("Running CTest Dashboard Script...")
+
+create_dashboard_script(dash-binary
+ "# Subversion command configuration
+set(CTEST_SVN_COMMAND \"${SVN}\")
+set(CTEST_SVN_UPDATE_OPTIONS
+ \"--config-dir \\\"\${CTEST_DASHBOARD_ROOT}/config\\\"\")
+set(CTEST_CHECKOUT_COMMAND
+ \"\\\"\${CTEST_SVN_COMMAND}\\\" co -r1 \\\"${REPO}\\\" dash-source\")
+")
+
+# Run the dashboard script with CTest.
+run_dashboard_script(dash-binary)
+
+#-----------------------------------------------------------------------------
+# Test ctest_update(RETURN_VALUE) on failure
+message("Running CTest Dashboard Script (fail to update)...")
+
+set(ctest_update_check [[
+if(NOT ret LESS 0)
+ message(FATAL_ERROR "ctest_update incorrectly succeeded with ${ret}")
+endif()
+]])
+create_dashboard_script(dash-binary-fail
+ "set(CTEST_SVN_COMMAND \"update-command-does-not-exist\")
+")
+unset(ctest_update_check)
+
+# Run the dashboard script with CTest.
+set(FAIL_UPDATE 1)
+run_dashboard_script(dash-binary-fail)
+unset(FAIL_UPDATE)
diff --git a/Tests/CheckCompilerRelatedVariables/CMakeLists.txt b/Tests/CheckCompilerRelatedVariables/CMakeLists.txt
new file mode 100644
index 0000000..69fa4b6
--- /dev/null
+++ b/Tests/CheckCompilerRelatedVariables/CMakeLists.txt
@@ -0,0 +1,109 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(CheckCompilerRelatedVariables)
+
+
+function(echo_var var)
+ if(DEFINED ${var})
+ message("${var}='${${var}}' is defined")
+ else()
+ message("${var}='${${var}}' is NOT defined")
+ endif()
+endfunction()
+
+
+#
+# Check that the correct number of MSVC** variables are defined...
+#
+set(msvc_total 0)
+
+if(DEFINED MSVC60)
+ math(EXPR msvc_total "${msvc_total} + 1")
+endif()
+if(DEFINED MSVC70)
+ math(EXPR msvc_total "${msvc_total} + 1")
+endif()
+if(DEFINED MSVC71)
+ math(EXPR msvc_total "${msvc_total} + 1")
+endif()
+if(DEFINED MSVC80)
+ math(EXPR msvc_total "${msvc_total} + 1")
+endif()
+if(DEFINED MSVC90)
+ math(EXPR msvc_total "${msvc_total} + 1")
+endif()
+if(DEFINED MSVC10)
+ math(EXPR msvc_total "${msvc_total} + 1")
+endif()
+if(DEFINED MSVC11)
+ math(EXPR msvc_total "${msvc_total} + 1")
+endif()
+if(DEFINED MSVC12)
+ math(EXPR msvc_total "${msvc_total} + 1")
+endif()
+if(DEFINED MSVC14)
+ math(EXPR msvc_total "${msvc_total} + 1")
+endif()
+
+echo_var(MSVC)
+echo_var(MSVC60)
+echo_var(MSVC70)
+echo_var(MSVC71)
+echo_var(MSVC80)
+echo_var(MSVC90)
+echo_var(MSVC10)
+echo_var(MSVC11)
+echo_var(MSVC12)
+echo_var(MSVC14)
+echo_var(MSVC_IDE)
+
+if(MSVC)
+ #
+ # MSVC is set in cl.cmake when cl is the compiler...
+ #
+ # Exactly one of the numbered variables should also be set
+ # indicating which version of the cl compiler / Visual Studio
+ # is in use...
+ #
+ if(msvc_total EQUAL 1)
+ message("test passes: exactly one MSVC** variable is defined...")
+ else()
+ message(FATAL_ERROR "error: ${msvc_total} MSVC** variables are defined -- exactly 1 expected")
+ endif()
+ if(NOT DEFINED MSVC_IDE)
+ message(FATAL_ERROR "MSVC_IDE not defined but should be!")
+ elseif("${CMAKE_GENERATOR}" MATCHES "Visual Studio" AND NOT MSVC_IDE)
+ message(FATAL_ERROR "MSVC_IDE is not true but should be (${CMAKE_GENERATOR})!")
+ elseif(NOT "${CMAKE_GENERATOR}" MATCHES "Visual Studio" AND MSVC_IDE)
+ message(FATAL_ERROR "MSVC_IDE is true but should not be (${CMAKE_GENERATOR})!")
+ endif()
+else()
+ #
+ # The compiler is something other than cl... None of the MSVC** variables
+ # should be defined...
+ #
+ if(msvc_total EQUAL 0)
+ message("test passes: no MSVC** variables are defined on non-MSVC build...")
+ else()
+ message(FATAL_ERROR "error: ${msvc_total} MSVC** variables are defined -- exactly 0 expected")
+ endif()
+ if(DEFINED MSVC_IDE)
+ message(FATAL_ERROR "MSVC_IDE is defined but should not be!")
+ endif()
+endif()
+
+
+#
+# This is a no-op executable... If this test is going to fail, it fails during
+# the configure step while cmake is configuring this CMakeLists.txt file...
+#
+
+file(WRITE
+ "${CMAKE_CURRENT_BINARY_DIR}/main.cxx"
+ "int main() { return 0; }
+"
+ )
+
+add_executable(
+ CheckCompilerRelatedVariables
+ "${CMAKE_CURRENT_BINARY_DIR}/main.cxx"
+ )
diff --git a/Tests/CheckFortran.cmake b/Tests/CheckFortran.cmake
new file mode 100644
index 0000000..36293f5
--- /dev/null
+++ b/Tests/CheckFortran.cmake
@@ -0,0 +1,55 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+if(NOT DEFINED CMAKE_Fortran_COMPILER)
+ set(_desc "Looking for a Fortran compiler")
+ message(STATUS ${_desc})
+ file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckFortran)
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckFortran/CMakeLists.txt"
+ "cmake_minimum_required(VERSION 2.8.12)
+project(CheckFortran Fortran)
+file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
+ \"set(CMAKE_Fortran_COMPILER \\\"\${CMAKE_Fortran_COMPILER}\\\")\\n\"
+ \"set(CMAKE_Fortran_COMPILER_ID \\\"\${CMAKE_Fortran_COMPILER_ID}\\\")\\n\"
+ \"set(CMAKE_Fortran_FLAGS \\\"\${CMAKE_Fortran_FLAGS}\\\")\\n\"
+ \"set(CMAKE_Fortran_COMPILER_SUPPORTS_F90 \\\"\${CMAKE_Fortran_COMPILER_SUPPORTS_F90}\\\")\\n\"
+ )
+")
+ if(CMAKE_GENERATOR_INSTANCE)
+ set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${CMAKE_GENERATOR_INSTANCE}")
+ else()
+ set(_D_CMAKE_GENERATOR_INSTANCE "")
+ endif()
+ execute_process(
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckFortran
+ COMMAND ${CMAKE_COMMAND} . -G ${CMAKE_GENERATOR}
+ -A "${CMAKE_GENERATOR_PLATFORM}"
+ -T "${CMAKE_GENERATOR_TOOLSET}"
+ ${_D_CMAKE_GENERATOR_INSTANCE}
+ TIMEOUT 60
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE output
+ RESULT_VARIABLE result
+ )
+ include(${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckFortran/result.cmake OPTIONAL)
+ if(CMAKE_Fortran_COMPILER AND "${result}" STREQUAL "0")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "${_desc} passed with the following output:\n"
+ "${output}\n")
+ else()
+ set(CMAKE_Fortran_COMPILER NOTFOUND)
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "${_desc} failed with the following output:\n"
+ "${output}\n")
+ endif()
+ message(STATUS "${_desc} - ${CMAKE_Fortran_COMPILER}")
+ set(CMAKE_Fortran_COMPILER "${CMAKE_Fortran_COMPILER}" CACHE FILEPATH "Fortran compiler")
+ mark_as_advanced(CMAKE_Fortran_COMPILER)
+ set(CMAKE_Fortran_COMPILER_ID "${CMAKE_Fortran_COMPILER_ID}" CACHE STRING "Fortran compiler Id")
+ mark_as_advanced(CMAKE_Fortran_COMPILER_ID)
+ set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" CACHE STRING "Fortran flags")
+ mark_as_advanced(CMAKE_Fortran_FLAGS)
+ set(CMAKE_Fortran_COMPILER_SUPPORTS_F90 "${CMAKE_Fortran_COMPILER_SUPPORTS_F90}" CACHE BOOL "Fortran compiler supports F90")
+ mark_as_advanced(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
+endif()
diff --git a/Tests/CheckSwift.cmake b/Tests/CheckSwift.cmake
new file mode 100644
index 0000000..fcbae7e
--- /dev/null
+++ b/Tests/CheckSwift.cmake
@@ -0,0 +1,61 @@
+if(NOT CMAKE_GENERATOR MATCHES "Xcode|Ninja")
+ set(CMAKE_Swift_COMPILER "")
+ return()
+endif()
+
+if(NOT DEFINED CMAKE_Swift_COMPILER)
+ set(_desc "Looking for a Swift compiler")
+ message(STATUS ${_desc})
+
+ file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckSwift)
+
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckSwift/CMakeLists.txt"
+ "cmake_minimum_required(VERSION 3.14)
+project(CheckSwift Swift)
+file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
+ \"set(CMAKE_Swift_COMPILER \\\"\${CMAKE_Swift_COMPILER}\\\")\\n\"
+ \"set(CMAKE_Swift_FLAGS \\\"\${CMAKE_Swift_FLAGS}\\\")\\n\")
+")
+
+ if(CMAKE_GENERATOR_INSTANCE)
+ set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${CMAKE_GENERATOR_INSTANCE}")
+ else()
+ set(_D_CMAKE_GENERATOR_INSTANCE "")
+ endif()
+
+ execute_process(WORKING_DIRECTORY
+ ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckSwift
+ COMMAND
+ ${CMAKE_COMMAND} . -G ${CMAKE_GENERATOR}
+ -A "${CMAKE_GENERATOR_PLATFORM}"
+ -T "${CMAKE_GENERATOR_TOOLSET}"
+ ${_D_CMAKE_GENERATOR_INSTANCE}
+ TIMEOUT
+ 60
+ OUTPUT_VARIABLE
+ output
+ ERROR_VARIABLE
+ output
+ RESULT_VARIABLE
+ result)
+
+ include(${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckSwift/result.cmake
+ OPTIONAL)
+ if(CMAKE_Swift_COMPILER AND "${result}" STREQUAL "0")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "${_desc} passed with the following output:\n"
+ "${output}\n")
+ else()
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "${_desc} failed with the following output:\n"
+ "${output}\n")
+ endif()
+
+ message(STATUS "${_desc} - ${CMAKE_Swift_COMPILER}")
+
+ set(CMAKE_Swift_COMPILER "${CMAKE_Swift_COMPILER}" CACHE FILEPATH "Swift compiler")
+ set(CMAKE_Swift_FLAGS "${CMAKE_Swift_FLAGS}" CACHE STRING "Swift flags")
+
+ mark_as_advanced(CMAKE_Swift_COMPILER)
+ mark_as_advanced(CMAKE_Swift_FLAGS)
+endif()
diff --git a/Tests/CoberturaCoverage/DartConfiguration.tcl.in b/Tests/CoberturaCoverage/DartConfiguration.tcl.in
new file mode 100644
index 0000000..954f59a
--- /dev/null
+++ b/Tests/CoberturaCoverage/DartConfiguration.tcl.in
@@ -0,0 +1,8 @@
+# This file is configured by CMake automatically as DartConfiguration.tcl
+# If you choose not to use CMake, this file may be hand configured, by
+# filling in the required variables.
+
+
+# Configuration directories and files
+SourceDirectory: ${CMake_SOURCE_DIR}/Testing/CoberturaCoverage
+BuildDirectory: ${CMake_BINARY_DIR}/Testing/CoberturaCoverage
diff --git a/Tests/CoberturaCoverage/coverage.xml.in b/Tests/CoberturaCoverage/coverage.xml.in
new file mode 100644
index 0000000..b3f6691
--- /dev/null
+++ b/Tests/CoberturaCoverage/coverage.xml.in
@@ -0,0 +1,112 @@
+<?xml version="1.0"?>
+<!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-04.dtd">
+
+<coverage line-rate="0.7222222222222222" branch-rate="0.875" lines-covered="13" lines-valid="18" branches-covered="7" branches-valid="8" complexity="0.0" version="1.9.4.1" timestamp="1401890139281">
+ <sources>
+ <source>${CMake_BINARY_DIR}/Testing/CoberturaCoverage/src/main/java/</source>
+ </sources>
+ <packages>
+ <package name="org.cmake.Coverage" line-rate="0.7222222222222222" branch-rate="0.875" complexity="0.0">
+ <classes>
+ <class name="org.cmake.Coverage.CoverageTest" filename="org/cmake/CoverageTest.java" line-rate="0.7222222222222222" branch-rate="0.875" complexity="0.0">
+ <methods>
+ <method name="&lt;clinit&gt;" signature="()V" line-rate="1.0" branch-rate="1.0">
+ <lines>
+ <line number="10" hits="2" branch="false"/>
+ <line number="11" hits="2" branch="false"/>
+ </lines>
+ </method>
+ <method name="&lt;init&gt;" signature="()V" line-rate="0.0" branch-rate="1.0">
+ <lines>
+ <line number="8" hits="0" branch="false"/>
+ <line number="12" hits="0" branch="false"/>
+ </lines>
+ </method>
+ <method name="equalsVarOne" signature="(Ljava/lang/String;)Ljava/lang/Boolean;" line-rate="0.6666666666666666" branch-rate="0.5">
+ <lines>
+ <line number="16" hits="2" branch="true" condition-coverage="50% (1/2)">
+ <conditions>
+ <condition number="0" type="jump" coverage="50%"/>
+ </conditions>
+ </line>
+ <line number="17" hits="2" branch="false"/>
+ <line number="20" hits="0" branch="false"/>
+ </lines>
+ </method>
+ <method name="equalsVarTwo" signature="(Ljava/lang/String;)Z" line-rate="1.0" branch-rate="1.0">
+ <lines>
+ <line number="26" hits="4" branch="true" condition-coverage="100% (2/2)">
+ <conditions>
+ <condition number="0" type="jump" coverage="100%"/>
+ </conditions>
+ </line>
+ <line number="27" hits="2" branch="false"/>
+ <line number="30" hits="2" branch="false"/>
+ </lines>
+ </method>
+ <method name="timesIntOne" signature="(Ljava/lang/Integer;)Ljava/lang/Integer;" line-rate="0.0" branch-rate="1.0">
+ <lines>
+ <line number="35" hits="0" branch="false"/>
+ <line number="36" hits="0" branch="false"/>
+ </lines>
+ </method>
+ <method name="whileLoop" signature="(Ljava/lang/Integer;)Z" line-rate="1.0" branch-rate="1.0">
+ <lines>
+ <line number="41" hits="2" branch="false"/>
+ <line number="42" hits="10" branch="true" condition-coverage="100% (2/2)">
+ <conditions>
+ <condition number="0" type="jump" coverage="100%"/>
+ </conditions>
+ </line>
+ <line number="43" hits="8" branch="false"/>
+ <line number="45" hits="2" branch="true" condition-coverage="100% (2/2)">
+ <conditions>
+ <condition number="0" type="jump" coverage="100%"/>
+ </conditions>
+ </line>
+ <line number="46" hits="1" branch="false"/>
+ <line number="49" hits="1" branch="false"/>
+ </lines>
+ </method>
+ </methods>
+ <lines>
+ <line number="8" hits="0" branch="false"/>
+ <line number="10" hits="2" branch="false"/>
+ <line number="11" hits="2" branch="false"/>
+ <line number="12" hits="0" branch="false"/>
+ <line number="16" hits="2" branch="true" condition-coverage="50% (1/2)">
+ <conditions>
+ <condition number="0" type="jump" coverage="50%"/>
+ </conditions>
+ </line>
+ <line number="17" hits="2" branch="false"/>
+ <line number="20" hits="0" branch="false"/>
+ <line number="26" hits="4" branch="true" condition-coverage="100% (2/2)">
+ <conditions>
+ <condition number="0" type="jump" coverage="100%"/>
+ </conditions>
+ </line>
+ <line number="27" hits="2" branch="false"/>
+ <line number="30" hits="2" branch="false"/>
+ <line number="35" hits="0" branch="false"/>
+ <line number="36" hits="0" branch="false"/>
+ <line number="41" hits="2" branch="false"/>
+ <line number="42" hits="10" branch="true" condition-coverage="100% (2/2)">
+ <conditions>
+ <condition number="0" type="jump" coverage="100%"/>
+ </conditions>
+ </line>
+ <line number="43" hits="8" branch="false"/>
+ <line number="45" hits="2" branch="true" condition-coverage="100% (2/2)">
+ <conditions>
+ <condition number="0" type="jump" coverage="100%"/>
+ </conditions>
+ </line>
+ <line number="46" hits="1" branch="false"/>
+ <line number="49" hits="1" branch="false"/>
+ </lines>
+ </class>
+ </classes>
+ </package>
+ </packages>
+</coverage>
diff --git a/Tests/CoberturaCoverage/src/main/java/org/cmake/CoverageTest.java b/Tests/CoberturaCoverage/src/main/java/org/cmake/CoverageTest.java
new file mode 100644
index 0000000..4fb43c6
--- /dev/null
+++ b/Tests/CoberturaCoverage/src/main/java/org/cmake/CoverageTest.java
@@ -0,0 +1,52 @@
+package org.cmake.Coverage;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.List;
+import java.awt.*;
+
+public class CoverageTest {
+
+ public static String VarOne = "test1";
+ public static String VarTwo = "test2";
+ private Integer IntOne = 4;
+
+ public static Boolean equalsVarOne(String inString) {
+
+ if(VarOne.equals(inString)){
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ public static boolean equalsVarTwo(String inString){
+
+ if(VarTwo.equals(inString)){
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ private Integer timesIntOne(Integer inVal){
+
+ return inVal * IntOne;
+ }
+
+ public static boolean whileLoop(Integer StopInt){
+
+ Integer i = 0;
+ while(i < StopInt){
+ i=i+1;
+ }
+ if (i.equals(5)){
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+}
diff --git a/Tests/CommandLength/CMakeLists.txt b/Tests/CommandLength/CMakeLists.txt
new file mode 100644
index 0000000..6836051
--- /dev/null
+++ b/Tests/CommandLength/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.10)
+project(CommandLength C)
+
+add_executable(CommandLength test.c)
+add_custom_command(TARGET CommandLength POST_BUILD VERBATIM
+ COMMAND ${CMAKE_COMMAND} -E make_directory log)
+
+set(msg "xxxx $$$$ yyyy")
+set(msg "${msg} ${msg}")
+set(msg "${msg} ${msg}")
+set(msg "${msg} ${msg}")
+set(msg "${msg} ${msg}")
+foreach(i RANGE 1 1000)
+ add_custom_command(TARGET CommandLength POST_BUILD VERBATIM
+ COMMAND ${CMAKE_COMMAND} -E echo "${i} ${msg}" > log/${i}
+ )
+endforeach()
diff --git a/Tests/CommandLength/test.c b/Tests/CommandLength/test.c
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/CommandLength/test.c
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CommandLineTest/CMakeLists.txt b/Tests/CommandLineTest/CMakeLists.txt
new file mode 100644
index 0000000..96aac10
--- /dev/null
+++ b/Tests/CommandLineTest/CMakeLists.txt
@@ -0,0 +1,79 @@
+cmake_minimum_required (VERSION 2.6)
+project(CommandLineTest)
+
+get_filename_component(CMAKE_BIN_DIR ${CMAKE_COMMAND} PATH)
+macro(EXEC_CMAKE_COMMAND CMAKE_ARGS)
+ exec_program("${CMAKE_COMMAND}" ARGS "${CMAKE_ARGS}" RETURN_VALUE RET)
+ if(${RET})
+ message(SEND_ERROR "CMake command failed with arguments \"${CMAKE_ARGS}\"")
+ endif()
+endmacro()
+
+EXEC_CMAKE_COMMAND("-E chdir \"${CMAKE_CURRENT_SOURCE_DIR}\" \"${CMAKE_COMMAND}\" -E echo \"Hello World\"")
+EXEC_CMAKE_COMMAND("-E time \"${CMAKE_COMMAND} -N -L ${CommandLineTest_SOURCE_DIR}\"")
+EXEC_CMAKE_COMMAND("-E time \"${CMAKE_COMMAND} -N -LA ${CommandLineTest_SOURCE_DIR}\"")
+EXEC_CMAKE_COMMAND("-E time \"${CMAKE_COMMAND} -N -LH ${CommandLineTest_SOURCE_DIR}\"")
+EXEC_CMAKE_COMMAND("-E time \"${CMAKE_COMMAND} -N -LAH ${CommandLineTest_SOURCE_DIR}\"")
+EXEC_CMAKE_COMMAND("--help")
+EXEC_CMAKE_COMMAND("--help-command-list")
+EXEC_CMAKE_COMMAND("--help add_executable")
+EXEC_CMAKE_COMMAND("--help-command add_executable")
+EXEC_CMAKE_COMMAND("--help-full \"${CMAKE_CURRENT_BINARY_DIR}/cmake.txt\"")
+EXEC_CMAKE_COMMAND("--help-man \"${CMAKE_CURRENT_BINARY_DIR}/cmake.man\"")
+EXEC_CMAKE_COMMAND("--help-html \"${CMAKE_CURRENT_BINARY_DIR}/cmake.html\"")
+EXEC_CMAKE_COMMAND("--copyright \"${CMAKE_CURRENT_BINARY_DIR}/Copyright.txt\"")
+EXEC_CMAKE_COMMAND("--version \"${CMAKE_CURRENT_BINARY_DIR}/version.txt\"")
+
+add_executable(CommandLineTest CommandLineTest.cxx)
+
+get_filename_component(CMAKE_COMMAND_PATH "${CMAKE_COMMAND}" PATH)
+set(CTEST_COMMAND "${CMAKE_COMMAND_PATH}/ctest")
+macro(EXEC_CTEST_COMMAND CMAKE_ARGS)
+ exec_program("${CTEST_COMMAND}" ARGS "${CMAKE_ARGS}" RETURN_VALUE RET)
+ if(${RET})
+ message(SEND_ERROR "CTest command failed with arguments \"${CMAKE_ARGS}\"")
+ endif()
+endmacro()
+macro(EXEC_CTEST_COMMAND_WITH_DIR DIR CMAKE_ARGS)
+ exec_program("${CTEST_COMMAND}" "${DIR}" ARGS "${CMAKE_ARGS}" RETURN_VALUE RET)
+ if(${RET})
+ message(SEND_ERROR "CTest command failed with arguments \"${CMAKE_ARGS}\"")
+ endif()
+endmacro()
+
+EXEC_CTEST_COMMAND_WITH_DIR("${CMAKE_CURRENT_BINARY_DIR}/../.." "-N")
+EXEC_CTEST_COMMAND_WITH_DIR("${CMAKE_CURRENT_BINARY_DIR}/../.." "-R complex -N")
+EXEC_CTEST_COMMAND_WITH_DIR("${CMAKE_CURRENT_BINARY_DIR}/../.." "-E Simple -N")
+EXEC_CTEST_COMMAND_WITH_DIR("${CMAKE_CURRENT_BINARY_DIR}/../.." "-E Simple -N")
+EXEC_CTEST_COMMAND_WITH_DIR("${CMAKE_CURRENT_BINARY_DIR}/../.." "-N -I -10")
+EXEC_CTEST_COMMAND_WITH_DIR("${CMAKE_CURRENT_BINARY_DIR}/../.." "-N -I 10-")
+EXEC_CTEST_COMMAND_WITH_DIR("${CMAKE_CURRENT_BINARY_DIR}/../.." "-N -I 3,4")
+EXEC_CTEST_COMMAND("--help")
+EXEC_CTEST_COMMAND("--copyright")
+EXEC_CTEST_COMMAND("--help-full \"${CMAKE_CURRENT_BINARY_DIR}/ctest.txt\"")
+EXEC_CTEST_COMMAND("--help-man \"${CMAKE_CURRENT_BINARY_DIR}/ctest.man\"")
+EXEC_CTEST_COMMAND("--help-html \"${CMAKE_CURRENT_BINARY_DIR}/ctest.html\"")
+EXEC_CTEST_COMMAND("--version")
+
+if(THIS_SHOULD_BE_SET)
+ message(STATUS "***************************")
+ message(STATUS "PreLoad.cmake works fine.")
+ message(STATUS "***************************")
+else()
+ message("***************************")
+ message(FATAL_ERROR "PreLoad.cmake does not work.")
+endif()
+
+if(DEFINED ENV{TEST_ENVIRONMENT_VARIABLE_NOTSET})
+ message(SEND_ERROR "Environment variable definition test broken!")
+endif()
+
+set(ENV{TEST_ENVIRONMENT_VARIABLE} "Environment variable set")
+if("$ENV{TEST_ENVIRONMENT_VARIABLE}" STREQUAL "Environment variable set")
+ message(STATUS "Environment variable set to: $ENV{TEST_ENVIRONMENT_VARIABLE}")
+ if(NOT DEFINED ENV{TEST_ENVIRONMENT_VARIABLE})
+ message(SEND_ERROR "Environment variable definition test failed!")
+ endif()
+else()
+ message(SEND_ERROR "Environment variable setting is broken")
+endif()
diff --git a/Tests/CommandLineTest/CommandLineTest.cxx b/Tests/CommandLineTest/CommandLineTest.cxx
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/CommandLineTest/CommandLineTest.cxx
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CommandLineTest/PreLoad.cmake b/Tests/CommandLineTest/PreLoad.cmake
new file mode 100644
index 0000000..f059bce
--- /dev/null
+++ b/Tests/CommandLineTest/PreLoad.cmake
@@ -0,0 +1 @@
+set(THIS_SHOULD_BE_SET ON CACHE BOOL "Some variable")
diff --git a/Tests/CompatibleInterface/CMakeLists.txt b/Tests/CompatibleInterface/CMakeLists.txt
new file mode 100644
index 0000000..668a97b
--- /dev/null
+++ b/Tests/CompatibleInterface/CMakeLists.txt
@@ -0,0 +1,130 @@
+
+cmake_minimum_required(VERSION 3.0)
+
+project(CompatibleInterface)
+
+include(GenerateExportHeader)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_library(iface1 INTERFACE)
+set_property(TARGET iface1 APPEND PROPERTY
+ COMPATIBLE_INTERFACE_BOOL
+ BOOL_PROP1
+ BOOL_PROP2
+ BOOL_PROP3
+ BOOL_PROP4
+)
+set_property(TARGET iface1 APPEND PROPERTY
+ COMPATIBLE_INTERFACE_STRING
+ STRING_PROP1
+ STRING_PROP2
+ STRING_PROP3
+)
+set_property(TARGET iface1 APPEND PROPERTY
+ COMPATIBLE_INTERFACE_NUMBER_MIN
+ NUMBER_MIN_PROP1
+ NUMBER_MIN_PROP2
+ NUMBER_MIN_PROP3
+ NUMBER_MIN_PROP4
+)
+set_property(TARGET iface1 APPEND PROPERTY
+ COMPATIBLE_INTERFACE_NUMBER_MAX
+ NUMBER_MAX_PROP1
+ NUMBER_MAX_PROP2
+)
+
+set(CMAKE_DEBUG_TARGET_PROPERTIES
+ BOOL_PROP1 BOOL_PROP2 BOOL_PROP3 BOOL_PROP4
+ STRING_PROP1 STRING_PROP2 STRING_PROP3
+ NUMBER_MIN_PROP1 NUMBER_MIN_PROP2 NUMBER_MIN_PROP3 NUMBER_MIN_PROP4
+ NUMBER_MAX_PROP1 NUMBER_MAX_PROP2
+)
+
+set_property(TARGET iface1 PROPERTY INTERFACE_BOOL_PROP1 ON)
+set_property(TARGET iface1 PROPERTY INTERFACE_BOOL_PROP2 ON)
+set_property(TARGET iface1 PROPERTY INTERFACE_STRING_PROP1 prop1)
+set_property(TARGET iface1 PROPERTY INTERFACE_STRING_PROP2 prop2)
+set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP1 100)
+set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP2 200)
+set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP3 0x10)
+set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MIN_PROP4 0x10)
+set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MAX_PROP1 100)
+set_property(TARGET iface1 PROPERTY INTERFACE_NUMBER_MAX_PROP2 200)
+
+add_executable(CompatibleInterface main.cpp)
+target_link_libraries(CompatibleInterface iface1)
+
+add_library(foo STATIC foo.cpp)
+add_library(bar SHARED bar.cpp)
+set_property(TARGET foo APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL SOMEPROP)
+set_property(TARGET foo PROPERTY INTERFACE_SOMEPROP ON)
+# Use LINK_ONLY to suppress usage requirements and allow the check to pass.
+set_property(TARGET bar PROPERTY INTERFACE_LINK_LIBRARIES $<LINK_ONLY:foo>)
+set_property(TARGET CompatibleInterface PROPERTY SOMEPROP OFF)
+target_link_libraries(CompatibleInterface bar)
+
+set_property(TARGET CompatibleInterface PROPERTY BOOL_PROP2 ON)
+set_property(TARGET CompatibleInterface PROPERTY BOOL_PROP3 ON)
+set_property(TARGET CompatibleInterface PROPERTY STRING_PROP2 prop2)
+set_property(TARGET CompatibleInterface PROPERTY STRING_PROP3 prop3)
+set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP1 50)
+set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP2 250)
+set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP3 0xa)
+set_property(TARGET CompatibleInterface PROPERTY NUMBER_MIN_PROP4 0x1A)
+set_property(TARGET CompatibleInterface PROPERTY NUMBER_MAX_PROP1 50)
+set_property(TARGET CompatibleInterface PROPERTY NUMBER_MAX_PROP2 250)
+
+target_compile_definitions(CompatibleInterface
+ PRIVATE
+ $<$<BOOL:$<TARGET_PROPERTY:BOOL_PROP1>>:BOOL_PROP1>
+ $<$<BOOL:$<TARGET_PROPERTY:BOOL_PROP2>>:BOOL_PROP2>
+ $<$<BOOL:$<TARGET_PROPERTY:BOOL_PROP3>>:BOOL_PROP3>
+ $<$<STREQUAL:$<TARGET_PROPERTY:STRING_PROP1>,prop1>:STRING_PROP1>
+ $<$<STREQUAL:$<TARGET_PROPERTY:STRING_PROP2>,prop2>:STRING_PROP2>
+ $<$<STREQUAL:$<TARGET_PROPERTY:STRING_PROP3>,prop3>:STRING_PROP3>
+ $<$<STREQUAL:$<TARGET_PROPERTY:NUMBER_MIN_PROP1>,50>:NUMBER_MIN_PROP1=50>
+ $<$<STREQUAL:$<TARGET_PROPERTY:NUMBER_MIN_PROP2>,200>:NUMBER_MIN_PROP2=200>
+ $<$<EQUAL:$<TARGET_PROPERTY:NUMBER_MIN_PROP3>,0xA>:NUMBER_MIN_PROP3=0xA>
+ $<$<STREQUAL:$<TARGET_PROPERTY:NUMBER_MIN_PROP4>,0x10>:NUMBER_MIN_PROP4=0x10>
+ $<$<STREQUAL:$<TARGET_PROPERTY:NUMBER_MAX_PROP1>,100>:NUMBER_MAX_PROP1=100>
+ $<$<STREQUAL:$<TARGET_PROPERTY:NUMBER_MAX_PROP2>,250>:NUMBER_MAX_PROP2=250>
+)
+
+
+add_library(iface2 SHARED iface2.cpp)
+generate_export_header(iface2)
+
+set_property(TARGET iface2 APPEND PROPERTY
+ COMPATIBLE_INTERFACE_STRING
+ Iface2_PROP
+)
+
+# For the LINK_LIBRARIES and related properties, we should not evaluate
+# properties defined only in the interface - they should be implicitly zero
+set_property(TARGET iface2
+ APPEND PROPERTY
+ LINK_INTERFACE_LIBRARIES $<$<BOOL:$<TARGET_PROPERTY:BOOL_PROP4>>:nonexistent>
+)
+target_link_libraries(CompatibleInterface iface2
+ $<$<BOOL:$<TARGET_PROPERTY:Iface2_PROP>>:nonexistent>
+)
+# Test that this does not segfault:
+target_compile_definitions(CompatibleInterface
+ PRIVATE
+ $<$<BOOL:$<TARGET_PROPERTY:Iface2_PROP>>:SOME_DEFINE>
+)
+
+# The COMPATIBLE_INTERFACE_* properties are only read from dependencies
+# in the interface. Populating it on the CompatibleInterface target does
+# not have any effect on the interpretation of the INTERFACE variants
+# in dependencies.
+set_property(TARGET iface1 PROPERTY
+ INTERFACE_NON_RELEVANT_PROP ON
+)
+set_property(TARGET iface2 PROPERTY
+ INTERFACE_NON_RELEVANT_PROP ON
+)
+set_property(TARGET CompatibleInterface APPEND PROPERTY
+ COMPATIBLE_INTERFACE_BOOL
+ NON_RELEVANT_PROP
+)
diff --git a/Tests/CompatibleInterface/bar.cpp b/Tests/CompatibleInterface/bar.cpp
new file mode 100644
index 0000000..69b16c3
--- /dev/null
+++ b/Tests/CompatibleInterface/bar.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int bar()
+{
+ return 0;
+}
diff --git a/Tests/CompatibleInterface/empty.cpp b/Tests/CompatibleInterface/empty.cpp
new file mode 100644
index 0000000..0032329
--- /dev/null
+++ b/Tests/CompatibleInterface/empty.cpp
@@ -0,0 +1 @@
+// no content
diff --git a/Tests/CompatibleInterface/foo.cpp b/Tests/CompatibleInterface/foo.cpp
new file mode 100644
index 0000000..e05eb7e
--- /dev/null
+++ b/Tests/CompatibleInterface/foo.cpp
@@ -0,0 +1,4 @@
+int foo()
+{
+ return 0;
+}
diff --git a/Tests/CompatibleInterface/iface2.cpp b/Tests/CompatibleInterface/iface2.cpp
new file mode 100644
index 0000000..a9b5015
--- /dev/null
+++ b/Tests/CompatibleInterface/iface2.cpp
@@ -0,0 +1,7 @@
+
+#include "iface2.h"
+
+int Iface2::foo()
+{
+ return 0;
+}
diff --git a/Tests/CompatibleInterface/iface2.h b/Tests/CompatibleInterface/iface2.h
new file mode 100644
index 0000000..ef4ebee
--- /dev/null
+++ b/Tests/CompatibleInterface/iface2.h
@@ -0,0 +1,13 @@
+
+#ifndef IFACE2_H
+#define IFACE2_H
+
+#include "iface2_export.h"
+
+class IFACE2_EXPORT Iface2
+{
+public:
+ int foo();
+};
+
+#endif
diff --git a/Tests/CompatibleInterface/main.cpp b/Tests/CompatibleInterface/main.cpp
new file mode 100644
index 0000000..0bccb82
--- /dev/null
+++ b/Tests/CompatibleInterface/main.cpp
@@ -0,0 +1,56 @@
+
+#ifndef BOOL_PROP1
+# error Expected BOOL_PROP1
+#endif
+
+#ifndef BOOL_PROP2
+# error Expected BOOL_PROP2
+#endif
+
+#ifndef BOOL_PROP3
+# error Expected BOOL_PROP3
+#endif
+
+#ifndef STRING_PROP1
+# error Expected STRING_PROP1
+#endif
+
+#ifndef STRING_PROP2
+# error Expected STRING_PROP2
+#endif
+
+#ifndef STRING_PROP3
+# error Expected STRING_PROP3
+#endif
+
+template <bool test>
+struct CMakeStaticAssert;
+
+template <>
+struct CMakeStaticAssert<true>
+{
+};
+
+enum
+{
+ NumericMaxTest1 = sizeof(CMakeStaticAssert<NUMBER_MAX_PROP1 == 100>),
+ NumericMaxTest2 = sizeof(CMakeStaticAssert<NUMBER_MAX_PROP2 == 250>),
+ NumericMinTest1 = sizeof(CMakeStaticAssert<NUMBER_MIN_PROP1 == 50>),
+ NumericMinTest2 = sizeof(CMakeStaticAssert<NUMBER_MIN_PROP2 == 200>),
+ NumericMinTest3 = sizeof(CMakeStaticAssert<NUMBER_MIN_PROP3 == 0xA>),
+ NumericMinTest4 = sizeof(CMakeStaticAssert<NUMBER_MIN_PROP4 == 0x10>)
+};
+
+#include "iface2.h"
+
+int foo();
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+ int bar();
+
+int main(int argc, char** argv)
+{
+ Iface2 if2;
+ return if2.foo() + foo() + bar();
+}
diff --git a/Tests/CompileCommandOutput/CMakeLists.txt b/Tests/CompileCommandOutput/CMakeLists.txt
new file mode 100644
index 0000000..6f9468d
--- /dev/null
+++ b/Tests/CompileCommandOutput/CMakeLists.txt
@@ -0,0 +1,16 @@
+# a simple C only test case
+cmake_minimum_required (VERSION 2.6)
+project (CompileCommandOutput CXX)
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+set(CMAKE_DEBUG_POSTFIX "_test_debug_postfix")
+if(MAKE_SUPPORTS_SPACES)
+ set(test1_srcs "file with spaces.cxx")
+else()
+ set(test1_srcs "file_with_underscores.cxx")
+endif()
+add_library(test1 STATIC ${test1_srcs})
+add_library(test2 SHARED "../CompileCommandOutput/relative.cxx")
+include_directories(${CompileCommandOutput_SOURCE_DIR}/../../Source)
+add_executable(CompileCommandOutput compile_command_output.cxx)
+target_link_libraries(CompileCommandOutput test1 test2)
diff --git a/Tests/CompileCommandOutput/compile_command_output.cxx b/Tests/CompileCommandOutput/compile_command_output.cxx
new file mode 100644
index 0000000..25795a0
--- /dev/null
+++ b/Tests/CompileCommandOutput/compile_command_output.cxx
@@ -0,0 +1,9 @@
+#include "file_with_underscores.h"
+#include "relative.h"
+
+int main(int argc, char** argv)
+{
+ file_with_underscores();
+ relative();
+ return 0;
+}
diff --git a/Tests/CompileCommandOutput/file with spaces.cxx b/Tests/CompileCommandOutput/file with spaces.cxx
new file mode 100644
index 0000000..554e176
--- /dev/null
+++ b/Tests/CompileCommandOutput/file with spaces.cxx
@@ -0,0 +1 @@
+#include "file_with_underscores.cxx"
diff --git a/Tests/CompileCommandOutput/file_with_underscores.cxx b/Tests/CompileCommandOutput/file_with_underscores.cxx
new file mode 100644
index 0000000..d45c3e0
--- /dev/null
+++ b/Tests/CompileCommandOutput/file_with_underscores.cxx
@@ -0,0 +1,5 @@
+#include "file_with_underscores.h"
+
+void file_with_underscores()
+{
+}
diff --git a/Tests/CompileCommandOutput/file_with_underscores.h b/Tests/CompileCommandOutput/file_with_underscores.h
new file mode 100644
index 0000000..0d73e31
--- /dev/null
+++ b/Tests/CompileCommandOutput/file_with_underscores.h
@@ -0,0 +1 @@
+void file_with_underscores();
diff --git a/Tests/CompileCommandOutput/relative.cxx b/Tests/CompileCommandOutput/relative.cxx
new file mode 100644
index 0000000..cd1d9b6
--- /dev/null
+++ b/Tests/CompileCommandOutput/relative.cxx
@@ -0,0 +1,5 @@
+#include "relative.h"
+
+void relative()
+{
+}
diff --git a/Tests/CompileCommandOutput/relative.h b/Tests/CompileCommandOutput/relative.h
new file mode 100644
index 0000000..fa6eeff
--- /dev/null
+++ b/Tests/CompileCommandOutput/relative.h
@@ -0,0 +1,11 @@
+#if defined(_WIN32)
+# ifdef test2_EXPORTS
+# define TEST2_EXPORT __declspec(dllexport)
+# else
+# define TEST2_EXPORT __declspec(dllimport)
+# endif
+#else
+# define TEST2_EXPORT
+#endif
+
+TEST2_EXPORT void relative();
diff --git a/Tests/CompileDefinitions/CMakeLists.txt b/Tests/CompileDefinitions/CMakeLists.txt
new file mode 100644
index 0000000..8347d5a
--- /dev/null
+++ b/Tests/CompileDefinitions/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(CompileDefinitions)
+
+# Use compile flags to tell executables which config is built
+# without depending on the compile definitions functionality.
+foreach(c DEBUG RELEASE RELWITHDEBINFO MINSIZEREL)
+ set(CMAKE_C_FLAGS_${c} "${CMAKE_C_FLAGS_${c}} -DTEST_CONFIG_${c}")
+ set(CMAKE_CXX_FLAGS_${c} "${CMAKE_CXX_FLAGS_${c}} -DTEST_CONFIG_${c}")
+endforeach()
+
+set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS
+ "BUILD_CONFIG_NAME=\"$<CONFIGURATION>\""
+ )
+
+add_subdirectory(add_def_cmd)
+add_subdirectory(target_prop)
+add_subdirectory(add_def_cmd_tprop)
+
+add_executable(CompileDefinitions runtest.c)
diff --git a/Tests/CompileDefinitions/add_def_cmd/CMakeLists.txt b/Tests/CompileDefinitions/add_def_cmd/CMakeLists.txt
new file mode 100644
index 0000000..2bce602
--- /dev/null
+++ b/Tests/CompileDefinitions/add_def_cmd/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_definitions(-DCMAKE_IS_FUN -DCMAKE_IS=Fun -DCMAKE_IS_="Fun")
+if (NOT NO_SPACES_IN_DEFINE_VALUES)
+ add_definitions(-DCMAKE_IS_REALLY="Very Fun")
+endif()
+add_definitions(-DCMAKE_IS_="Fun")
+if (NOT NO_SPACES_IN_DEFINE_VALUES)
+ add_definitions(-DCMAKE_IS_REALLY="Very Fun")
+endif()
+add_definitions(-DCMAKE_IS_FUN -DCMAKE_IS=Fun)
+add_definitions(-DBUILD_IS_DEBUG=$<CONFIG:Debug> -DBUILD_IS_NOT_DEBUG=$<NOT:$<CONFIG:Debug>>)
+
+add_executable(add_def_cmd_exe ../compiletest.cpp)
diff --git a/Tests/CompileDefinitions/add_def_cmd_tprop/CMakeLists.txt b/Tests/CompileDefinitions/add_def_cmd_tprop/CMakeLists.txt
new file mode 100644
index 0000000..4ef8a09
--- /dev/null
+++ b/Tests/CompileDefinitions/add_def_cmd_tprop/CMakeLists.txt
@@ -0,0 +1,16 @@
+add_definitions(-DCMAKE_IS_FUN -DCMAKE_IS=Fun)
+
+add_executable(add_def_cmd_tprop_exe ../compiletest.cpp)
+
+set_target_properties(add_def_cmd_tprop_exe PROPERTIES COMPILE_DEFINITIONS CMAKE_IS_="Fun")
+
+if (NOT NO_SPACES_IN_DEFINE_VALUES)
+ set_property(TARGET add_def_cmd_tprop_exe APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_IS_REALLY="Very Fun")
+endif()
+
+add_definitions(-DCMAKE_IS_FUN)
+
+set_property(TARGET add_def_cmd_tprop_exe APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_IS=Fun CMAKE_IS_="Fun")
+
+add_definitions(-DBUILD_IS_DEBUG=$<CONFIG:Debug>)
+set_property(TARGET add_def_cmd_tprop_exe APPEND PROPERTY COMPILE_DEFINITIONS BUILD_IS_NOT_DEBUG=$<NOT:$<CONFIG:Debug>>)
diff --git a/Tests/CompileDefinitions/compiletest.c b/Tests/CompileDefinitions/compiletest.c
new file mode 100644
index 0000000..6624866
--- /dev/null
+++ b/Tests/CompileDefinitions/compiletest.c
@@ -0,0 +1,23 @@
+
+#ifndef LINK_C_DEFINE
+# error Expected LINK_C_DEFINE
+#endif
+#ifndef LINK_LANGUAGE_IS_C
+# error Expected LINK_LANGUAGE_IS_C
+#endif
+
+#ifdef LINK_CXX_DEFINE
+# error Unexpected LINK_CXX_DEFINE
+#endif
+#ifdef LINK_LANGUAGE_IS_CXX
+# error Unexpected LINK_LANGUAGE_IS_CXX
+#endif
+
+#ifdef DEBUG_MODE
+# error Unexpected DEBUG_MODE
+#endif
+
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CompileDefinitions/compiletest.cpp b/Tests/CompileDefinitions/compiletest.cpp
new file mode 100644
index 0000000..328e72e
--- /dev/null
+++ b/Tests/CompileDefinitions/compiletest.cpp
@@ -0,0 +1,112 @@
+
+#ifndef CMAKE_IS_FUN
+# error Expect CMAKE_IS_FUN definition
+#endif
+
+#if CMAKE_IS != Fun
+# error Expect CMAKE_IS=Fun definition
+#endif
+
+template <bool test>
+struct CMakeStaticAssert;
+
+template <>
+struct CMakeStaticAssert<true>
+{
+};
+
+static const char fun_string[] = CMAKE_IS_;
+#ifndef NO_SPACES_IN_DEFINE_VALUES
+static const char very_fun_string[] = CMAKE_IS_REALLY;
+#endif
+
+enum
+{
+ StringLiteralTest1 =
+ sizeof(CMakeStaticAssert<sizeof(CMAKE_IS_) == sizeof("Fun")>),
+#ifndef NO_SPACES_IN_DEFINE_VALUES
+ StringLiteralTest2 =
+ sizeof(CMakeStaticAssert<sizeof(CMAKE_IS_REALLY) == sizeof("Very Fun")>),
+#endif
+#ifdef TEST_GENERATOR_EXPRESSIONS
+ StringLiteralTest3 =
+ sizeof(CMakeStaticAssert<sizeof(LETTER_LIST1) == sizeof("A,B,C,D")>),
+ StringLiteralTest4 =
+ sizeof(CMakeStaticAssert<sizeof(LETTER_LIST2) == sizeof("A,,B,,C,,D")>),
+ StringLiteralTest5 =
+ sizeof(CMakeStaticAssert<sizeof(LETTER_LIST3) == sizeof("A,-B,-C,-D")>),
+ StringLiteralTest6 =
+ sizeof(CMakeStaticAssert<sizeof(LETTER_LIST4) == sizeof("A-,-B-,-C-,-D")>),
+ StringLiteralTest7 =
+ sizeof(CMakeStaticAssert<sizeof(LETTER_LIST5) == sizeof("A-,B-,C-,D")>)
+#endif
+};
+
+#ifdef TEST_GENERATOR_EXPRESSIONS
+# ifndef CMAKE_IS_DECLARATIVE
+# error Expect declarative definition
+# endif
+# ifdef GE_NOT_DEFINED
+# error Expect not defined generator expression
+# endif
+
+# ifndef ARGUMENT
+# error Expected define expanded from list
+# endif
+# ifndef LIST
+# error Expected define expanded from list
+# endif
+
+# ifndef PREFIX_DEF1
+# error Expect PREFIX_DEF1
+# endif
+
+# ifndef PREFIX_DEF2
+# error Expect PREFIX_DEF2
+# endif
+
+# ifndef LINK_CXX_DEFINE
+# error Expected LINK_CXX_DEFINE
+# endif
+# ifndef LINK_LANGUAGE_IS_CXX
+# error Expected LINK_LANGUAGE_IS_CXX
+# endif
+
+# ifdef LINK_C_DEFINE
+# error Unexpected LINK_C_DEFINE
+# endif
+# ifdef LINK_LANGUAGE_IS_C
+# error Unexpected LINK_LANGUAGE_IS_C
+# endif
+
+// TEST_GENERATOR_EXPRESSIONS
+#endif
+
+#ifndef BUILD_IS_DEBUG
+# error "BUILD_IS_DEBUG not defined!"
+#endif
+#ifndef BUILD_IS_NOT_DEBUG
+# error "BUILD_IS_NOT_DEBUG not defined!"
+#endif
+
+// Check per-config definitions.
+#ifdef TEST_CONFIG_DEBUG
+# if !BUILD_IS_DEBUG
+# error "BUILD_IS_DEBUG false with TEST_CONFIG_DEBUG!"
+# endif
+# if BUILD_IS_NOT_DEBUG
+# error "BUILD_IS_NOT_DEBUG true with TEST_CONFIG_DEBUG!"
+# endif
+#else
+# if BUILD_IS_DEBUG
+# error "BUILD_IS_DEBUG true without TEST_CONFIG_DEBUG!"
+# endif
+# if !BUILD_IS_NOT_DEBUG
+# error "BUILD_IS_NOT_DEBUG false without TEST_CONFIG_DEBUG!"
+# endif
+#endif
+
+int main(int argc, char** argv)
+{
+ return 0;
+}
diff --git a/Tests/CompileDefinitions/compiletest_mixed_c.c b/Tests/CompileDefinitions/compiletest_mixed_c.c
new file mode 100644
index 0000000..e4adef3
--- /dev/null
+++ b/Tests/CompileDefinitions/compiletest_mixed_c.c
@@ -0,0 +1,22 @@
+
+#ifndef LINK_CXX_DEFINE
+# error Expected LINK_CXX_DEFINE
+#endif
+#ifndef LINK_LANGUAGE_IS_CXX
+# error Expected LINK_LANGUAGE_IS_CXX
+#endif
+
+#ifdef LINK_C_DEFINE
+# error Unexpected LINK_C_DEFINE
+#endif
+#ifdef LINK_LANGUAGE_IS_C
+# error Unexpected LINK_LANGUAGE_IS_C
+#endif
+
+#ifndef C_EXECUTABLE_LINK_LANGUAGE_IS_C
+# error Expected C_EXECUTABLE_LINK_LANGUAGE_IS_C define
+#endif
+
+void someFunc(void)
+{
+}
diff --git a/Tests/CompileDefinitions/compiletest_mixed_cxx.cpp b/Tests/CompileDefinitions/compiletest_mixed_cxx.cpp
new file mode 100644
index 0000000..b50b4bf
--- /dev/null
+++ b/Tests/CompileDefinitions/compiletest_mixed_cxx.cpp
@@ -0,0 +1,23 @@
+
+#ifndef LINK_CXX_DEFINE
+# error Expected LINK_CXX_DEFINE
+#endif
+#ifndef LINK_LANGUAGE_IS_CXX
+# error Expected LINK_LANGUAGE_IS_CXX
+#endif
+
+#ifdef LINK_C_DEFINE
+# error Unexpected LINK_C_DEFINE
+#endif
+#ifdef LINK_LANGUAGE_IS_C
+# error Unexpected LINK_LANGUAGE_IS_C
+#endif
+
+#ifndef C_EXECUTABLE_LINK_LANGUAGE_IS_C
+# error Expected C_EXECUTABLE_LINK_LANGUAGE_IS_C define
+#endif
+
+int main(int argc, char** argv)
+{
+ return 0;
+}
diff --git a/Tests/CompileDefinitions/runtest.c b/Tests/CompileDefinitions/runtest.c
new file mode 100644
index 0000000..c6dac4d
--- /dev/null
+++ b/Tests/CompileDefinitions/runtest.c
@@ -0,0 +1,42 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef BUILD_CONFIG_NAME
+# error "BUILD_CONFIG_NAME not defined!"
+#endif
+
+int main()
+{
+ char build_config_name[] = BUILD_CONFIG_NAME;
+ char* c;
+ for (c = build_config_name; *c; ++c) {
+ *c = (char)tolower((int)*c);
+ }
+ fprintf(stderr, "build_config_name=\"%s\"\n", build_config_name);
+#ifdef TEST_CONFIG_DEBUG
+ if (strcmp(build_config_name, "debug") != 0) {
+ fprintf(stderr, "build_config_name is not \"debug\"\n");
+ return 1;
+ }
+#endif
+#ifdef TEST_CONFIG_RELEASE
+ if (strcmp(build_config_name, "release") != 0) {
+ fprintf(stderr, "build_config_name is not \"release\"\n");
+ return 1;
+ }
+#endif
+#ifdef TEST_CONFIG_MINSIZEREL
+ if (strcmp(build_config_name, "minsizerel") != 0) {
+ fprintf(stderr, "build_config_name is not \"minsizerel\"\n");
+ return 1;
+ }
+#endif
+#ifdef TEST_CONFIG_RELWITHDEBINFO
+ if (strcmp(build_config_name, "relwithdebinfo") != 0) {
+ fprintf(stderr, "build_config_name is not \"relwithdebinfo\"\n");
+ return 1;
+ }
+#endif
+ return 0;
+}
diff --git a/Tests/CompileDefinitions/target_prop/CMakeLists.txt b/Tests/CompileDefinitions/target_prop/CMakeLists.txt
new file mode 100644
index 0000000..311975c
--- /dev/null
+++ b/Tests/CompileDefinitions/target_prop/CMakeLists.txt
@@ -0,0 +1,60 @@
+
+project(target_prop)
+
+add_executable(target_prop_executable ../compiletest.cpp)
+
+set_target_properties(target_prop_executable PROPERTIES COMPILE_DEFINITIONS CMAKE_IS_FUN)
+
+if (NOT NO_SPACES_IN_DEFINE_VALUES)
+ set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_IS_REALLY="Very Fun" CMAKE_IS=Fun)
+else()
+ set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_IS=Fun)
+endif()
+set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_IS_FUN CMAKE_IS_="Fun")
+
+set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS
+ TEST_GENERATOR_EXPRESSIONS
+ "$<1:CMAKE_IS_DECLARATIVE>"
+ "$<0:GE_NOT_DEFINED>"
+ "$<1:ARGUMENT;LIST>"
+ PREFIX_$<JOIN:DEF1;DEF2,;PREFIX_>
+ LETTER_LIST1=\"$<JOIN:A;B;C;D,,>\"
+ LETTER_LIST2=\"$<JOIN:A;B;C;D,,,>\"
+ LETTER_LIST3=\"$<JOIN:A;B;C;D,,->\"
+ LETTER_LIST4=\"$<JOIN:A;B;C;D,-,->\"
+ LETTER_LIST5=\"$<JOIN:A;B;C;D,-,>\"
+ "$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,CXX>:LINK_CXX_DEFINE>"
+ "$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,C>:LINK_C_DEFINE>"
+ "LINK_LANGUAGE_IS_$<TARGET_PROPERTY:LINKER_LANGUAGE>"
+)
+
+set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS
+ BUILD_IS_DEBUG=$<CONFIG:Debug>
+ BUILD_IS_NOT_DEBUG=$<NOT:$<CONFIG:Debug>>
+ )
+
+add_executable(target_prop_c_executable ../compiletest.c)
+
+cmake_policy(SET CMP0043 NEW)
+set_property(TARGET target_prop_c_executable APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUG_MODE)
+
+set_property(TARGET target_prop_c_executable APPEND PROPERTY COMPILE_DEFINITIONS
+ "$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,CXX>:LINK_CXX_DEFINE>"
+ "$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,C>:LINK_C_DEFINE>"
+ "LINK_LANGUAGE_IS_$<TARGET_PROPERTY:LINKER_LANGUAGE>"
+ )
+
+# Resulting link language will be CXX
+add_executable(target_prop_mixed_executable ../compiletest_mixed_c.c ../compiletest_mixed_cxx.cpp)
+
+set_property(TARGET target_prop_mixed_executable APPEND PROPERTY COMPILE_DEFINITIONS
+ "$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,CXX>:LINK_CXX_DEFINE>"
+ "$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,C>:LINK_C_DEFINE>"
+ "LINK_LANGUAGE_IS_$<TARGET_PROPERTY:LINKER_LANGUAGE>"
+ "C_EXECUTABLE_LINK_LANGUAGE_IS_$<TARGET_PROPERTY:target_prop_c_executable,LINKER_LANGUAGE>"
+ )
+
+add_library(tgt STATIC IMPORTED)
+set_property(TARGET tgt APPEND PROPERTY COMPILE_DEFINITIONS TGT_DEF TGT_TYPE_$<TARGET_PROPERTY:TYPE>)
+add_executable(usetgt usetgt.c)
+target_compile_definitions(usetgt PRIVATE $<TARGET_PROPERTY:tgt,COMPILE_DEFINITIONS>)
diff --git a/Tests/CompileDefinitions/target_prop/usetgt.c b/Tests/CompileDefinitions/target_prop/usetgt.c
new file mode 100644
index 0000000..56823b0
--- /dev/null
+++ b/Tests/CompileDefinitions/target_prop/usetgt.c
@@ -0,0 +1,13 @@
+#ifndef TGT_DEF
+# error TGT_DEF incorrectly not defined
+#endif
+#ifndef TGT_TYPE_STATIC_LIBRARY
+# error TGT_TYPE_STATIC_LIBRARY incorrectly not defined
+#endif
+#ifdef TGT_TYPE_EXECUTABLE
+# error TGT_TYPE_EXECUTABLE incorrectly defined
+#endif
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CompileFeatures/.gitattributes b/Tests/CompileFeatures/.gitattributes
new file mode 100644
index 0000000..95a8956
--- /dev/null
+++ b/Tests/CompileFeatures/.gitattributes
@@ -0,0 +1,2 @@
+# Do not format a source containing C++11 '>>' syntax as C++98.
+cxx_right_angle_brackets.cpp -format.clang-format-6.0
diff --git a/Tests/CompileFeatures/CMakeLists.txt b/Tests/CompileFeatures/CMakeLists.txt
new file mode 100644
index 0000000..20988ac
--- /dev/null
+++ b/Tests/CompileFeatures/CMakeLists.txt
@@ -0,0 +1,375 @@
+
+cmake_minimum_required(VERSION 3.1)
+cmake_policy(SET CMP0057 NEW)
+
+project(CompileFeatures)
+
+set(ext_C c)
+set(ext_CXX cpp)
+
+macro(run_test feature lang)
+ if (${feature} IN_LIST CMAKE_${lang}_COMPILE_FEATURES)
+ add_library(test_${feature} OBJECT ${feature}.${ext_${lang}})
+ set_property(TARGET test_${feature}
+ PROPERTY COMPILE_FEATURES "${feature}"
+ )
+ else()
+ list(APPEND ${lang}_non_features ${feature})
+ endif()
+endmacro()
+
+if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM|Fujitsu|FujitsuClang)$")
+ get_property(c_features GLOBAL PROPERTY CMAKE_C_KNOWN_FEATURES)
+ list(FILTER c_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
+ foreach(feature ${c_features})
+ run_test(${feature} C)
+ endforeach()
+endif()
+
+if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM|Fujitsu|FujitsuClang)$")
+ get_property(cxx_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
+ list(FILTER cxx_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
+ foreach(feature ${cxx_features})
+ run_test(${feature} CXX)
+ endforeach()
+endif()
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"
+ AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
+ # AppleClang prior to 5.1 does not set any preprocessor define to distinguish
+ # c++1y from c++11, so CMake does not support c++1y features before AppleClang 5.1.
+ list(REMOVE_ITEM CXX_non_features
+ cxx_attribute_deprecated
+ cxx_binary_literals
+ )
+endif()
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"
+ AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.2)
+ # AppleClang prior to 4.1 reports false for __has_feature(cxx_local_type_template_args)
+ # and __has_feature(cxx_unrestricted_unions) but it happens to pass these tests.
+ list(REMOVE_ITEM CXX_non_features
+ cxx_local_type_template_args
+ cxx_unrestricted_unions
+ )
+endif()
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL SunPro)
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.15)
+ # SunPro 5.14 accepts -std=c++14 and compiles two features but does
+ # not define __cplusplus to a value different than with -std=c++11.
+ list(REMOVE_ITEM CXX_non_features
+ cxx_aggregate_default_initializers
+ cxx_digit_separators
+ )
+ endif()
+
+ # FIXME: Do any of these work correctly on SunPro 5.13 or above?
+ list(REMOVE_ITEM CXX_non_features
+ cxx_attribute_deprecated
+ cxx_contextual_conversions
+ cxx_extended_friend_declarations
+ cxx_long_long_type
+ cxx_sizeof_member
+ cxx_variadic_macros
+ )
+endif()
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
+ AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.5)
+ # The cxx_raw_string_literals feature happens to work in some distributions
+ # of GNU 4.4, but it is first documented as available with GNU 4.5.
+ list(REMOVE_ITEM CXX_non_features
+ cxx_raw_string_literals
+ )
+endif()
+if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
+ AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
+ # The cxx_constexpr feature happens to work (for *this* testcase) with
+ # GNU 4.5, but it is first documented as available with GNU 4.6.
+ list(REMOVE_ITEM CXX_non_features
+ cxx_constexpr
+ )
+endif()
+if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
+ AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
+ # The cxx_alignof feature happens to work (for *this* testcase) with
+ # GNU 4.7, but it is first documented as available with GNU 4.8.
+ list(REMOVE_ITEM CXX_non_features
+ cxx_alignof
+ )
+endif()
+if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
+ AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
+ # GNU prior to 4.9 does not set any preprocessor define to distinguish
+ # c++1y from c++11, so CMake does not support c++1y features before GNU 4.9.
+ list(REMOVE_ITEM CXX_non_features
+ # GNU 4.8 knows cxx_attributes, but doesn't know [[deprecated]]
+ # and warns that it is unknown and ignored.
+ cxx_attribute_deprecated
+ cxx_binary_literals
+ cxx_lambda_init_captures
+ cxx_return_type_deduction
+ )
+endif()
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0)
+ list(REMOVE_ITEM CXX_non_features
+ # The cxx_contextual_conversions feature happens to work
+ # (for *this* testcase) with VS 2010 and VS 2012, but
+ # they do not document support until VS 2013.
+ cxx_contextual_conversions
+ )
+ elseif (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0)
+ list(REMOVE_ITEM CXX_non_features
+ # The cxx_deleted_functions and cxx_nonstatic_member_init
+ # features happen to work (for *this* testcase) with VS 2013,
+ # but they do not document support until VS 2015.
+ cxx_deleted_functions
+ cxx_nonstatic_member_init
+ )
+ endif()
+endif()
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
+ if (CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC"
+ AND CMAKE_CXX_SIMULATE_VERSION VERSION_LESS 19.10)
+ list(REMOVE_ITEM CXX_non_features
+ cxx_relaxed_constexpr
+ )
+ endif()
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0)
+ if (CMAKE_CXX_COMIPLER_VERSION VERSION_EQUAL 15.0)
+ list(REMOVE_ITEM CXX_non_features
+ # The cxx_contextual_conversions feature happens to work
+ # (for *this* testcase) with Intel 13/14/15, but they do not
+ # document support until 16.
+ cxx_contextual_conversions
+ )
+
+ elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14.0)
+ list(REMOVE_ITEM CXX_non_features
+ cxx_alignof
+
+ # not supposed to work until 15
+ cxx_attribute_deprecated
+
+ # The cxx_contextual_conversions feature happens to work
+ # (for *this* testcase) with Intel 13/14/15, but they do not
+ # document support until 16.
+ cxx_contextual_conversions
+ )
+
+ elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
+ list(REMOVE_ITEM CXX_non_features
+ # These features happen to work but aren't documented to
+ # do so until 14.0
+ cxx_constexpr
+ cxx_enum_forward_declarations
+ cxx_sizeof_member
+ cxx_strong_enums
+ cxx_unicode_literals
+
+ # not supposed to work until 15
+ cxx_attribute_deprecated
+ cxx_nonstatic_member_init
+
+ # The cxx_contextual_conversions feature happens to work
+ # (for *this* testcase) with Intel 13/14/15, but they do not
+ # document support until 16.
+ cxx_contextual_conversions
+
+ # This is an undocumented feature; it does not work in future versions
+ cxx_aggregate_default_initializers
+ )
+ endif()
+ endif()
+endif()
+
+if (CMAKE_C_COMPILER_ID STREQUAL "Intel")
+ if (CMAKE_C_COMPILER_VERSION VERSION_LESS 15.0.2)
+ # This works on some pre-15.0.2 versions and not others.
+ list(REMOVE_ITEM C_non_features
+ c_static_assert
+ )
+ endif()
+endif()
+
+if (CMAKE_C_COMPILE_FEATURES)
+ set(C_expected_features ${CMAKE_C_COMPILE_FEATURES})
+ list(FILTER C_expected_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
+endif()
+if (CMAKE_CXX_COMPILE_FEATURES)
+ set(CXX_expected_features ${CMAKE_CXX_COMPILE_FEATURES})
+ list(FILTER CXX_expected_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
+endif ()
+set(C_ext c)
+set(C_standard_flag 11)
+set(CXX_ext cpp)
+set(CXX_standard_flag 14)
+foreach(lang CXX C)
+ if (${lang}_expected_features)
+ foreach(feature ${${lang}_non_features})
+ message("Testing feature : ${feature}")
+ try_compile(${feature}_works
+ "${CMAKE_CURRENT_BINARY_DIR}/${feature}_test"
+ "${CMAKE_CURRENT_SOURCE_DIR}/feature_test.${${lang}_ext}"
+ COMPILE_DEFINITIONS "-DTEST=${feature}.${${lang}_ext}"
+ CMAKE_FLAGS "-DCMAKE_${lang}_STANDARD=${${lang}_standard_flag}"
+ "-DINCLUDE_DIRECTORIES=${CMAKE_CURRENT_SOURCE_DIR}"
+ OUTPUT_VARIABLE OUTPUT
+ )
+ if (${feature}_works)
+ message(SEND_ERROR
+ "Feature ${feature} expected not to work for ${lang} ${CMAKE_${lang}_COMPILER_ID}-${CMAKE_${lang}_COMPILER_VERSION}.
+ Update the supported features or blacklist it.\n${OUTPUT}")
+ else()
+ message("Testing feature : ${feature} -- Fails, as expected.")
+ endif()
+ endforeach()
+ endif()
+endforeach()
+
+if (C_expected_features)
+ if (CMAKE_C_STANDARD_DEFAULT)
+ string(FIND "${CMAKE_C_FLAGS}" "-std=" std_flag_idx)
+ if (std_flag_idx EQUAL -1)
+ add_executable(default_dialect_C default_dialect.c)
+ target_compile_definitions(default_dialect_C PRIVATE
+ DEFAULT_C23=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},23>
+ DEFAULT_C17=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},17>
+ DEFAULT_C11=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},11>
+ DEFAULT_C99=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},99>
+ DEFAULT_C90=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},90>
+ )
+ endif()
+ endif()
+
+ add_executable(CompileFeaturesGenex_C genex_test.c)
+ set_property(TARGET CompileFeaturesGenex_C PROPERTY C_STANDARD 11)
+
+ foreach(f
+ c_restrict
+ c_static_assert
+ c_function_prototypes
+ )
+ if(${f} IN_LIST C_expected_features)
+ set(expect_${f} 1)
+ else()
+ set(expect_${f} 0)
+ endif()
+ string(TOUPPER "${f}" F)
+ target_compile_definitions(CompileFeaturesGenex_C PRIVATE
+ EXPECT_${F}=${expect_${f}}
+ HAVE_${F}=$<COMPILE_FEATURES:${f}>
+ )
+ endforeach()
+endif()
+
+if (CMAKE_CXX_COMPILE_FEATURES)
+ if (CMAKE_CXX_STANDARD_DEFAULT)
+ string(FIND "${CMAKE_CXX_FLAGS}" "-std=" std_flag_idx)
+ if (std_flag_idx EQUAL -1)
+ add_executable(default_dialect default_dialect.cpp)
+ target_compile_definitions(default_dialect PRIVATE
+ DEFAULT_CXX23=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},23>
+ DEFAULT_CXX20=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},20>
+ DEFAULT_CXX17=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},17>
+ DEFAULT_CXX14=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},14>
+ DEFAULT_CXX11=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},11>
+ DEFAULT_CXX98=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},98>
+ )
+ endif()
+ endif()
+endif ()
+
+# always add a target "CompileFeatures"
+if ((NOT CXX_expected_features) OR
+ (NOT cxx_auto_type IN_LIST CXX_expected_features))
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp"
+ "int main(int,char**) { return 0; }\n"
+ )
+ add_executable(CompileFeatures "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp")
+else()
+ # these tests only work if at least cxx_auto_type is available
+ add_executable(CompileFeatures main.cpp)
+ set_property(TARGET CompileFeatures
+ PROPERTY COMPILE_FEATURES "cxx_auto_type"
+ )
+ set_property(TARGET CompileFeatures
+ PROPERTY CXX_STANDARD_REQUIRED TRUE
+ )
+
+ add_executable(GenexCompileFeatures main.cpp)
+ set_property(TARGET GenexCompileFeatures
+ PROPERTY COMPILE_FEATURES "$<1:cxx_auto_type>;$<0:not_a_feature>"
+ )
+
+ add_library(iface INTERFACE)
+ set_property(TARGET iface
+ PROPERTY INTERFACE_COMPILE_FEATURES "cxx_auto_type"
+ )
+ add_executable(IfaceCompileFeatures main.cpp)
+ target_link_libraries(IfaceCompileFeatures iface)
+
+ foreach(f
+ cxx_final
+ cxx_override
+ cxx_auto_type
+ cxx_inheriting_constructors
+ )
+ if(${f} IN_LIST CXX_expected_features)
+ set(expect_${f} 1)
+ else()
+ set(expect_${f} 0)
+ endif()
+ endforeach()
+
+ if(expect_cxx_final AND expect_cxx_override)
+ set(expect_override_control 1)
+ else()
+ set(expect_override_control 0)
+ endif()
+ if(expect_cxx_inheriting_constructors AND expect_cxx_final)
+ set(expect_inheriting_constructors_and_final 1)
+ else()
+ set(expect_inheriting_constructors_and_final 0)
+ endif()
+
+ set(genex_test_defs
+ HAVE_OVERRIDE_CONTROL=$<COMPILE_FEATURES:cxx_final,cxx_override>
+ HAVE_AUTO_TYPE=$<COMPILE_FEATURES:cxx_auto_type>
+ HAVE_INHERITING_CONSTRUCTORS=$<COMPILE_FEATURES:cxx_inheriting_constructors>
+ HAVE_FINAL=$<COMPILE_FEATURES:cxx_final>
+ HAVE_INHERITING_CONSTRUCTORS_AND_FINAL=$<COMPILE_FEATURES:cxx_inheriting_constructors,cxx_final>
+ EXPECT_OVERRIDE_CONTROL=${expect_override_control}
+ EXPECT_INHERITING_CONSTRUCTORS=${expect_cxx_inheriting_constructors}
+ EXPECT_FINAL=${expect_cxx_final}
+ EXPECT_INHERITING_CONSTRUCTORS_AND_FINAL=${expect_inheriting_constructors_and_final}
+ )
+ if (CMAKE_CXX_STANDARD_DEFAULT)
+ list(APPEND genex_test_defs
+ TEST_CXX_STD
+ HAVE_CXX_STD_11=$<COMPILE_FEATURES:cxx_std_11>
+ HAVE_CXX_STD_14=$<COMPILE_FEATURES:cxx_std_14>
+ HAVE_CXX_STD_17=$<COMPILE_FEATURES:cxx_std_17>
+ HAVE_CXX_STD_20=$<COMPILE_FEATURES:cxx_std_20>
+ HAVE_CXX_STD_23=$<COMPILE_FEATURES:cxx_std_23>
+ )
+ endif()
+
+ add_executable(CompileFeaturesGenex genex_test.cpp)
+ set_property(TARGET CompileFeaturesGenex PROPERTY CXX_STANDARD 11)
+ target_compile_definitions(CompileFeaturesGenex PRIVATE ${genex_test_defs})
+
+ add_executable(CompileFeaturesGenex2 genex_test.cpp)
+ target_compile_features(CompileFeaturesGenex2 PRIVATE cxx_std_11)
+ target_compile_definitions(CompileFeaturesGenex2 PRIVATE ${genex_test_defs} ALLOW_LATER_STANDARDS=1)
+
+ add_library(std_11_iface INTERFACE)
+ target_compile_features(std_11_iface INTERFACE cxx_std_11)
+ add_executable(CompileFeaturesGenex3 genex_test.cpp)
+ target_link_libraries(CompileFeaturesGenex3 PRIVATE std_11_iface)
+ target_compile_definitions(CompileFeaturesGenex3 PRIVATE ${genex_test_defs} ALLOW_LATER_STANDARDS=1)
+endif()
diff --git a/Tests/CompileFeatures/c_function_prototypes.c b/Tests/CompileFeatures/c_function_prototypes.c
new file mode 100644
index 0000000..ab3c948
--- /dev/null
+++ b/Tests/CompileFeatures/c_function_prototypes.c
@@ -0,0 +1,9 @@
+
+int someFunc(int a, int b);
+
+int someFunc(int a, int b)
+{
+ (void)a;
+ (void)b;
+ return 0;
+}
diff --git a/Tests/CompileFeatures/c_restrict.c b/Tests/CompileFeatures/c_restrict.c
new file mode 100644
index 0000000..5082da8
--- /dev/null
+++ b/Tests/CompileFeatures/c_restrict.c
@@ -0,0 +1,7 @@
+
+int f(int* restrict a, int* restrict b)
+{
+ (void)a;
+ (void)b;
+ return 0;
+}
diff --git a/Tests/CompileFeatures/c_static_assert.c b/Tests/CompileFeatures/c_static_assert.c
new file mode 100644
index 0000000..afab504
--- /dev/null
+++ b/Tests/CompileFeatures/c_static_assert.c
@@ -0,0 +1,2 @@
+
+_Static_assert(1, "Static assert test");
diff --git a/Tests/CompileFeatures/c_variadic_macros.c b/Tests/CompileFeatures/c_variadic_macros.c
new file mode 100644
index 0000000..4da111e
--- /dev/null
+++ b/Tests/CompileFeatures/c_variadic_macros.c
@@ -0,0 +1,15 @@
+
+int someFunc(int i1, char c, int i2)
+{
+ (void)i1;
+ (void)c;
+ (void)i2;
+ return 0;
+}
+
+#define FUNC_WRAPPER(...) someFunc(__VA_ARGS__)
+
+void otherFunc()
+{
+ FUNC_WRAPPER(42, 'a', 7);
+}
diff --git a/Tests/CompileFeatures/cxx_aggregate_default_initializers.cpp b/Tests/CompileFeatures/cxx_aggregate_default_initializers.cpp
new file mode 100644
index 0000000..3d1076f
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_aggregate_default_initializers.cpp
@@ -0,0 +1,12 @@
+
+struct X
+{
+ int i, j, k = 42;
+};
+
+int someFunc()
+{
+ X a[] = { 1, 2, 3, 4, 5, 6 };
+ X b[2] = { { 1, 2, 3 }, { 4, 5, 6 } };
+ return a[0].k == b[0].k && a[1].k == b[1].k ? 0 : 1;
+}
diff --git a/Tests/CompileFeatures/cxx_alias_templates.cpp b/Tests/CompileFeatures/cxx_alias_templates.cpp
new file mode 100644
index 0000000..0859692
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_alias_templates.cpp
@@ -0,0 +1,11 @@
+
+template <typename T1, typename T2>
+struct A
+{
+ typedef T1 MyT1;
+ using MyT2 = T2;
+};
+
+using B = A<int, char>;
+template <typename T>
+using C = A<int, T>;
diff --git a/Tests/CompileFeatures/cxx_alignas.cpp b/Tests/CompileFeatures/cxx_alignas.cpp
new file mode 100644
index 0000000..9fc2c2a
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_alignas.cpp
@@ -0,0 +1,5 @@
+
+struct S1
+{
+ alignas(8) int n;
+};
diff --git a/Tests/CompileFeatures/cxx_alignof.cpp b/Tests/CompileFeatures/cxx_alignof.cpp
new file mode 100644
index 0000000..63b14fe
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_alignof.cpp
@@ -0,0 +1,5 @@
+
+int someFunc()
+{
+ return alignof(int);
+}
diff --git a/Tests/CompileFeatures/cxx_attribute_deprecated.cpp b/Tests/CompileFeatures/cxx_attribute_deprecated.cpp
new file mode 100644
index 0000000..8faeca8
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_attribute_deprecated.cpp
@@ -0,0 +1,7 @@
+
+[[deprecated]] int foo() { return 0; }
+
+int someFunc()
+{
+ return foo();
+}
diff --git a/Tests/CompileFeatures/cxx_attributes.cpp b/Tests/CompileFeatures/cxx_attributes.cpp
new file mode 100644
index 0000000..1434317
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_attributes.cpp
@@ -0,0 +1,5 @@
+
+void unusedFunc[[noreturn]]()
+{
+ throw 1;
+}
diff --git a/Tests/CompileFeatures/cxx_auto_type.cpp b/Tests/CompileFeatures/cxx_auto_type.cpp
new file mode 100644
index 0000000..1f36a79
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_auto_type.cpp
@@ -0,0 +1,12 @@
+
+double foo_ = 3.14;
+
+double& foo()
+{
+ return foo_;
+}
+
+void someFunc()
+{
+ auto& x = foo();
+}
diff --git a/Tests/CompileFeatures/cxx_binary_literals.cpp b/Tests/CompileFeatures/cxx_binary_literals.cpp
new file mode 100644
index 0000000..14a9e75
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_binary_literals.cpp
@@ -0,0 +1,6 @@
+
+int someFunc()
+{
+ int i = 0b101;
+ return i - 5;
+}
diff --git a/Tests/CompileFeatures/cxx_constexpr.cpp b/Tests/CompileFeatures/cxx_constexpr.cpp
new file mode 100644
index 0000000..570c10f
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_constexpr.cpp
@@ -0,0 +1,5 @@
+
+constexpr int getNum()
+{
+ return 42;
+}
diff --git a/Tests/CompileFeatures/cxx_contextual_conversions.cpp b/Tests/CompileFeatures/cxx_contextual_conversions.cpp
new file mode 100644
index 0000000..247f13f
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_contextual_conversions.cpp
@@ -0,0 +1,43 @@
+
+#define assert(E) \
+ if (!(E)) \
+ return 1;
+
+template <class T>
+class zero_init
+{
+public:
+ zero_init()
+ : val(static_cast<T>(0))
+ {
+ }
+ zero_init(T val)
+ : val(val)
+ {
+ }
+ operator T&() { return val; }
+ operator T() const { return val; }
+
+private:
+ T val;
+};
+
+int someFunc()
+{
+ zero_init<int*> p;
+ assert(p == 0);
+ p = new int(7);
+ assert(*p == 7);
+ delete p;
+
+ zero_init<int> i;
+ assert(i == 0);
+ i = 7;
+ assert(i == 7);
+ switch (i) {
+ }
+
+ int* vp = new int[i];
+
+ return 0;
+}
diff --git a/Tests/CompileFeatures/cxx_decltype.cpp b/Tests/CompileFeatures/cxx_decltype.cpp
new file mode 100644
index 0000000..24ec51e
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_decltype.cpp
@@ -0,0 +1,7 @@
+
+int someFunc()
+{
+ int i = 0;
+ decltype(i) other = 0;
+ return other;
+}
diff --git a/Tests/CompileFeatures/cxx_decltype_auto.cpp b/Tests/CompileFeatures/cxx_decltype_auto.cpp
new file mode 100644
index 0000000..900bb6d
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_decltype_auto.cpp
@@ -0,0 +1,6 @@
+
+int someFunc(int argc, char**)
+{
+ decltype(auto) i = argc;
+ return 0;
+}
diff --git a/Tests/CompileFeatures/cxx_decltype_incomplete_return_types.cpp b/Tests/CompileFeatures/cxx_decltype_incomplete_return_types.cpp
new file mode 100644
index 0000000..74bcbe1
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_decltype_incomplete_return_types.cpp
@@ -0,0 +1,19 @@
+
+template <class T>
+struct A
+{
+ ~A() = delete;
+};
+
+template <class T>
+auto h() -> A<T>;
+template <class T>
+auto i(T) -> T;
+template <class T>
+auto f(T) -> decltype(i(h<T>()));
+template <class T>
+auto f(T) -> void;
+auto g() -> void
+{
+ f(42);
+}
diff --git a/Tests/CompileFeatures/cxx_default_function_template_args.cpp b/Tests/CompileFeatures/cxx_default_function_template_args.cpp
new file mode 100644
index 0000000..bcca6aa
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_default_function_template_args.cpp
@@ -0,0 +1,12 @@
+
+template <typename T = int>
+int someFunc()
+{
+ T t = 0;
+ return t;
+}
+
+void otherFunc()
+{
+ someFunc();
+}
diff --git a/Tests/CompileFeatures/cxx_defaulted_functions.cpp b/Tests/CompileFeatures/cxx_defaulted_functions.cpp
new file mode 100644
index 0000000..3b15adc
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_defaulted_functions.cpp
@@ -0,0 +1,10 @@
+
+struct A
+{
+ A() = default;
+};
+
+void someFunc()
+{
+ A a;
+}
diff --git a/Tests/CompileFeatures/cxx_defaulted_move_initializers.cpp b/Tests/CompileFeatures/cxx_defaulted_move_initializers.cpp
new file mode 100644
index 0000000..14f9871
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_defaulted_move_initializers.cpp
@@ -0,0 +1,7 @@
+
+struct A
+{
+ A() = default;
+ A& operator=(A&&) = default;
+ A(A&&) = default;
+};
diff --git a/Tests/CompileFeatures/cxx_delegating_constructors.cpp b/Tests/CompileFeatures/cxx_delegating_constructors.cpp
new file mode 100644
index 0000000..7e04939
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_delegating_constructors.cpp
@@ -0,0 +1,14 @@
+
+class Foo
+{
+public:
+ Foo(int i);
+
+ Foo(double d)
+ : Foo(static_cast<int>(d))
+ {
+ }
+
+private:
+ int m_i;
+};
diff --git a/Tests/CompileFeatures/cxx_deleted_functions.cpp b/Tests/CompileFeatures/cxx_deleted_functions.cpp
new file mode 100644
index 0000000..4ecb1e9
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_deleted_functions.cpp
@@ -0,0 +1,6 @@
+
+struct A
+{
+ A(const A&) = delete;
+ A& operator=(const A&) = delete;
+};
diff --git a/Tests/CompileFeatures/cxx_digit_separators.cpp b/Tests/CompileFeatures/cxx_digit_separators.cpp
new file mode 100644
index 0000000..abcd1c8
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_digit_separators.cpp
@@ -0,0 +1,6 @@
+
+int someFunc()
+{
+ int one_thousand = 1'000;
+ return one_thousand - 1000;
+}
diff --git a/Tests/CompileFeatures/cxx_enum_forward_declarations.cpp b/Tests/CompileFeatures/cxx_enum_forward_declarations.cpp
new file mode 100644
index 0000000..a7e1445
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_enum_forward_declarations.cpp
@@ -0,0 +1,8 @@
+
+enum SomeEnum : short;
+
+void someFunc()
+{
+ SomeEnum value;
+ int i = value;
+}
diff --git a/Tests/CompileFeatures/cxx_explicit_conversions.cpp b/Tests/CompileFeatures/cxx_explicit_conversions.cpp
new file mode 100644
index 0000000..a34128f
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_explicit_conversions.cpp
@@ -0,0 +1,8 @@
+
+class A
+{
+ int m_i;
+
+public:
+ explicit operator bool() { return m_i != 0; }
+};
diff --git a/Tests/CompileFeatures/cxx_extended_friend_declarations.cpp b/Tests/CompileFeatures/cxx_extended_friend_declarations.cpp
new file mode 100644
index 0000000..bde94d2
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_extended_friend_declarations.cpp
@@ -0,0 +1,29 @@
+
+template <typename T>
+struct B
+{
+ B()
+ : m_i(42)
+ {
+ }
+
+private:
+ int m_i;
+ friend T;
+};
+
+struct A
+{
+ template <typename T>
+ int getBValue(B<T> b)
+ {
+ return b.m_i;
+ }
+};
+
+void someFunc()
+{
+ A a;
+ B<A> b;
+ a.getBValue(b);
+}
diff --git a/Tests/CompileFeatures/cxx_extern_templates.cpp b/Tests/CompileFeatures/cxx_extern_templates.cpp
new file mode 100644
index 0000000..01f300a
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_extern_templates.cpp
@@ -0,0 +1,12 @@
+
+template <typename T>
+void someFunc()
+{
+}
+
+extern template void someFunc<int>();
+
+void otherFunc()
+{
+ someFunc<int>();
+}
diff --git a/Tests/CompileFeatures/cxx_final.cpp b/Tests/CompileFeatures/cxx_final.cpp
new file mode 100644
index 0000000..9d5d5c4
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_final.cpp
@@ -0,0 +1,4 @@
+
+struct A final
+{
+};
diff --git a/Tests/CompileFeatures/cxx_func_identifier.cpp b/Tests/CompileFeatures/cxx_func_identifier.cpp
new file mode 100644
index 0000000..0c3595c
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_func_identifier.cpp
@@ -0,0 +1,6 @@
+
+void someFunc()
+{
+ bool b = sizeof(__func__);
+ (void)b;
+}
diff --git a/Tests/CompileFeatures/cxx_generalized_initializers.cpp b/Tests/CompileFeatures/cxx_generalized_initializers.cpp
new file mode 100644
index 0000000..bfe0d41
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_generalized_initializers.cpp
@@ -0,0 +1,37 @@
+#if defined(_MSC_VER) && _MSC_VER == 1800 && _MSC_FULL_VER < 180030723
+# error "VS 2013 safely supports this only with Update 3 or greater"
+#endif
+
+// Dummy implementation. Test only the compiler feature.
+namespace std {
+typedef decltype(sizeof(int)) size_t;
+template <class _E>
+class initializer_list
+{
+ const _E* __begin_;
+ size_t __size_;
+
+#ifdef __INTEL_COMPILER
+ // The Intel compiler internally asserts the constructor overloads, so
+ // reproduce the constructor used in its <initializer_list> header.
+ initializer_list(const _E*, size_t) {}
+#else
+public:
+ template <typename T1, typename T2>
+ initializer_list(T1, T2)
+ {
+ }
+#endif
+};
+}
+
+template <typename T>
+struct A
+{
+ A(std::initializer_list<T>) {}
+};
+
+void someFunc()
+{
+ A<int> as = { 1, 2, 3, 4 };
+}
diff --git a/Tests/CompileFeatures/cxx_generic_lambdas.cpp b/Tests/CompileFeatures/cxx_generic_lambdas.cpp
new file mode 100644
index 0000000..ae1b78e
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_generic_lambdas.cpp
@@ -0,0 +1,6 @@
+
+int someFunc()
+{
+ auto identity = [](auto a) { return a; };
+ return identity(0);
+}
diff --git a/Tests/CompileFeatures/cxx_inheriting_constructors.cpp b/Tests/CompileFeatures/cxx_inheriting_constructors.cpp
new file mode 100644
index 0000000..51400ce
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_inheriting_constructors.cpp
@@ -0,0 +1,21 @@
+
+struct A
+{
+ int m_i;
+
+ A(int i)
+ : m_i(i)
+ {
+ }
+};
+
+struct B : public A
+{
+ using A::A;
+};
+
+void someFunc()
+{
+ int i = 0;
+ B b(i);
+}
diff --git a/Tests/CompileFeatures/cxx_inline_namespaces.cpp b/Tests/CompileFeatures/cxx_inline_namespaces.cpp
new file mode 100644
index 0000000..77f99e8
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_inline_namespaces.cpp
@@ -0,0 +1,25 @@
+namespace Lib {
+inline namespace Lib_1 {
+template <typename T>
+class A;
+}
+
+template <typename T>
+void g(T);
+}
+
+struct MyClass
+{
+};
+namespace Lib {
+template <>
+class A<MyClass>
+{
+};
+}
+
+void someFunc()
+{
+ Lib::A<MyClass> a;
+ g(a); // ok, Lib is an associated namespace of A
+}
diff --git a/Tests/CompileFeatures/cxx_lambda_init_captures.cpp b/Tests/CompileFeatures/cxx_lambda_init_captures.cpp
new file mode 100644
index 0000000..7e337fa
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_lambda_init_captures.cpp
@@ -0,0 +1,6 @@
+
+int someFunc()
+{
+ int a = 0;
+ return [b = static_cast<int&&>(a)]() { return b; }();
+}
diff --git a/Tests/CompileFeatures/cxx_lambdas.cpp b/Tests/CompileFeatures/cxx_lambdas.cpp
new file mode 100644
index 0000000..7cd1fab
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_lambdas.cpp
@@ -0,0 +1,5 @@
+
+void someFunc()
+{
+ []() {}();
+}
diff --git a/Tests/CompileFeatures/cxx_local_type_template_args.cpp b/Tests/CompileFeatures/cxx_local_type_template_args.cpp
new file mode 100644
index 0000000..00565e6
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_local_type_template_args.cpp
@@ -0,0 +1,35 @@
+
+template <typename T>
+class X
+{
+};
+template <typename T>
+void f(T t)
+{
+}
+struct
+{
+} unnamed_obj;
+void f()
+{
+ struct A
+ {
+ };
+ enum
+ {
+ e1
+ };
+ typedef struct
+ {
+ } B;
+ B b;
+ X<A> x1;
+ X<A*> x2;
+ X<B> x3;
+ f(e1);
+ f(unnamed_obj);
+ f(b);
+ (void)x1;
+ (void)x2;
+ (void)x3;
+}
diff --git a/Tests/CompileFeatures/cxx_long_long_type.cpp b/Tests/CompileFeatures/cxx_long_long_type.cpp
new file mode 100644
index 0000000..670324c
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_long_long_type.cpp
@@ -0,0 +1,5 @@
+
+void someFunc()
+{
+ long long ll = 9223372036854775807LL;
+}
diff --git a/Tests/CompileFeatures/cxx_noexcept.cpp b/Tests/CompileFeatures/cxx_noexcept.cpp
new file mode 100644
index 0000000..535e5db
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_noexcept.cpp
@@ -0,0 +1,4 @@
+
+void someFunc() noexcept
+{
+}
diff --git a/Tests/CompileFeatures/cxx_nonstatic_member_init.cpp b/Tests/CompileFeatures/cxx_nonstatic_member_init.cpp
new file mode 100644
index 0000000..6b7fa70
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_nonstatic_member_init.cpp
@@ -0,0 +1,4 @@
+class A
+{
+ int m_i = 42;
+};
diff --git a/Tests/CompileFeatures/cxx_nullptr.cpp b/Tests/CompileFeatures/cxx_nullptr.cpp
new file mode 100644
index 0000000..a31422d
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_nullptr.cpp
@@ -0,0 +1,9 @@
+
+void someFunc(int*)
+{
+}
+
+void otherFunc()
+{
+ someFunc(nullptr);
+}
diff --git a/Tests/CompileFeatures/cxx_override.cpp b/Tests/CompileFeatures/cxx_override.cpp
new file mode 100644
index 0000000..3283f2f
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_override.cpp
@@ -0,0 +1,9 @@
+
+struct A
+{
+ virtual void doNothing() {}
+};
+struct B : A
+{
+ void doNothing() override {}
+};
diff --git a/Tests/CompileFeatures/cxx_range_for.cpp b/Tests/CompileFeatures/cxx_range_for.cpp
new file mode 100644
index 0000000..e3b5724
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_range_for.cpp
@@ -0,0 +1,9 @@
+
+void someFunc()
+{
+ int accumulated = 0;
+ int numbers[] = { 1, 2, 5 };
+ for (int i : numbers) {
+ accumulated += i;
+ }
+}
diff --git a/Tests/CompileFeatures/cxx_raw_string_literals.cpp b/Tests/CompileFeatures/cxx_raw_string_literals.cpp
new file mode 100644
index 0000000..0f83a7c
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_raw_string_literals.cpp
@@ -0,0 +1,7 @@
+
+void someFunc()
+{
+ const char p[] = R"(a\
+b
+c)";
+}
diff --git a/Tests/CompileFeatures/cxx_reference_qualified_functions.cpp b/Tests/CompileFeatures/cxx_reference_qualified_functions.cpp
new file mode 100644
index 0000000..2fd36e0
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_reference_qualified_functions.cpp
@@ -0,0 +1,13 @@
+
+struct test
+{
+ void f() & {}
+ void f() && {}
+};
+
+void someFunc()
+{
+ test t;
+ t.f(); // lvalue
+ test().f(); // rvalue
+}
diff --git a/Tests/CompileFeatures/cxx_relaxed_constexpr.cpp b/Tests/CompileFeatures/cxx_relaxed_constexpr.cpp
new file mode 100644
index 0000000..953148d
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_relaxed_constexpr.cpp
@@ -0,0 +1,28 @@
+
+struct X
+{
+ constexpr X()
+ : n(5)
+ {
+ n *= 2;
+ }
+ int n;
+};
+
+constexpr int g(const int (&is)[4])
+{
+ X x;
+ int r = x.n;
+ for (int i = 0; i < 5; ++i)
+ r += i;
+ for (auto& i : is)
+ r += i;
+ return r;
+}
+
+int someFunc()
+{
+ constexpr int values[4] = { 4, 5, 6, 7 };
+ constexpr int k3 = g(values);
+ return k3 - 42;
+}
diff --git a/Tests/CompileFeatures/cxx_return_type_deduction.cpp b/Tests/CompileFeatures/cxx_return_type_deduction.cpp
new file mode 100644
index 0000000..a3108df
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_return_type_deduction.cpp
@@ -0,0 +1,10 @@
+
+auto sum(int a, int b)
+{
+ return a + b;
+}
+
+int someFunc()
+{
+ return sum(3, -3);
+}
diff --git a/Tests/CompileFeatures/cxx_right_angle_brackets.cpp b/Tests/CompileFeatures/cxx_right_angle_brackets.cpp
new file mode 100644
index 0000000..4d494b5
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_right_angle_brackets.cpp
@@ -0,0 +1,14 @@
+
+template <typename T>
+struct A
+{
+ typedef T Result;
+};
+
+void someFunc()
+{
+ /* clang-format off */
+ A<A<int>> object;
+ /* clang-format on */
+ (void)object;
+}
diff --git a/Tests/CompileFeatures/cxx_rvalue_references.cpp b/Tests/CompileFeatures/cxx_rvalue_references.cpp
new file mode 100644
index 0000000..3b85ab6
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_rvalue_references.cpp
@@ -0,0 +1,4 @@
+
+void someFunc(int&&)
+{
+}
diff --git a/Tests/CompileFeatures/cxx_sizeof_member.cpp b/Tests/CompileFeatures/cxx_sizeof_member.cpp
new file mode 100644
index 0000000..ae143d2
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_sizeof_member.cpp
@@ -0,0 +1,10 @@
+
+struct A
+{
+ int m_i;
+};
+
+int someFunc()
+{
+ return sizeof(A::m_i) > 0 ? 1 : 2;
+}
diff --git a/Tests/CompileFeatures/cxx_static_assert.cpp b/Tests/CompileFeatures/cxx_static_assert.cpp
new file mode 100644
index 0000000..6aa8678
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_static_assert.cpp
@@ -0,0 +1,2 @@
+
+static_assert(true, "static_assert test");
diff --git a/Tests/CompileFeatures/cxx_strong_enums.cpp b/Tests/CompileFeatures/cxx_strong_enums.cpp
new file mode 100644
index 0000000..6262456
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_strong_enums.cpp
@@ -0,0 +1,7 @@
+
+enum class Colors
+{
+ RedColor,
+ GreenColor,
+ BlueColor
+};
diff --git a/Tests/CompileFeatures/cxx_template_template_parameters.cpp b/Tests/CompileFeatures/cxx_template_template_parameters.cpp
new file mode 100644
index 0000000..d57dd36
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_template_template_parameters.cpp
@@ -0,0 +1,16 @@
+
+template <template <typename> class T, typename U>
+void someFunc(T<U>)
+{
+}
+
+template <typename T>
+struct A
+{
+};
+
+void otherFunc()
+{
+ A<int> a;
+ someFunc(a);
+}
diff --git a/Tests/CompileFeatures/cxx_thread_local.cpp b/Tests/CompileFeatures/cxx_thread_local.cpp
new file mode 100644
index 0000000..1fb27e2
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_thread_local.cpp
@@ -0,0 +1,2 @@
+
+thread_local unsigned int rage = 1;
diff --git a/Tests/CompileFeatures/cxx_trailing_return_types.cpp b/Tests/CompileFeatures/cxx_trailing_return_types.cpp
new file mode 100644
index 0000000..01a76cb
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_trailing_return_types.cpp
@@ -0,0 +1,5 @@
+
+auto someFunc() -> int
+{
+ return 42;
+}
diff --git a/Tests/CompileFeatures/cxx_unicode_literals.cpp b/Tests/CompileFeatures/cxx_unicode_literals.cpp
new file mode 100644
index 0000000..7794c11
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_unicode_literals.cpp
@@ -0,0 +1,5 @@
+
+/* clang-format off */
+const char16_t lit_16[] = u"\u00DA";
+const char32_t lit_32[] = U"\u00DA";
+/* clang-format on */
diff --git a/Tests/CompileFeatures/cxx_uniform_initialization.cpp b/Tests/CompileFeatures/cxx_uniform_initialization.cpp
new file mode 100644
index 0000000..e5048d1
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_uniform_initialization.cpp
@@ -0,0 +1,12 @@
+struct A
+{
+};
+struct B
+{
+ B(A) {}
+};
+
+void Func()
+{
+ B b{ A{} };
+}
diff --git a/Tests/CompileFeatures/cxx_unrestricted_unions.cpp b/Tests/CompileFeatures/cxx_unrestricted_unions.cpp
new file mode 100644
index 0000000..f6d64f6
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_unrestricted_unions.cpp
@@ -0,0 +1,17 @@
+
+struct point
+{
+ point() {}
+ point(int x, int y)
+ : x_(x)
+ , y_(y)
+ {
+ }
+ int x_, y_;
+};
+union u
+{
+ point p_;
+ int i_;
+ const char* s_;
+};
diff --git a/Tests/CompileFeatures/cxx_user_literals.cpp b/Tests/CompileFeatures/cxx_user_literals.cpp
new file mode 100644
index 0000000..5144204
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_user_literals.cpp
@@ -0,0 +1,7 @@
+
+long double operator"" _meters(long double);
+
+void someFunc()
+{
+ long double i = 1.2_meters;
+}
diff --git a/Tests/CompileFeatures/cxx_variable_templates.cpp b/Tests/CompileFeatures/cxx_variable_templates.cpp
new file mode 100644
index 0000000..8e6fc99
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_variable_templates.cpp
@@ -0,0 +1,10 @@
+
+template <typename T>
+constexpr T pi = T(3.1415926535897932385);
+
+int someFunc()
+{
+ auto pi_int = pi<int>;
+ auto pi_float = pi<float>;
+ return pi_int - 3;
+}
diff --git a/Tests/CompileFeatures/cxx_variadic_macros.cpp b/Tests/CompileFeatures/cxx_variadic_macros.cpp
new file mode 100644
index 0000000..4d007a5
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_variadic_macros.cpp
@@ -0,0 +1,12 @@
+
+int someFunc(int, char, int)
+{
+ return 0;
+}
+
+#define FUNC_WRAPPER(...) someFunc(__VA_ARGS__)
+
+void otherFunc()
+{
+ FUNC_WRAPPER(42, 'a', 7);
+}
diff --git a/Tests/CompileFeatures/cxx_variadic_templates.cpp b/Tests/CompileFeatures/cxx_variadic_templates.cpp
new file mode 100644
index 0000000..627b8d9
--- /dev/null
+++ b/Tests/CompileFeatures/cxx_variadic_templates.cpp
@@ -0,0 +1,72 @@
+#if defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) < 407)
+# define OLD_GNU
+#endif
+
+#ifdef OLD_GNU
+template <int... Is>
+struct Interface;
+#endif
+
+template <int I, int... Is>
+struct Interface
+#ifdef OLD_GNU
+ <I, Is...>
+#endif
+{
+ static int accumulate() { return I + Interface<Is...>::accumulate(); }
+};
+
+template <int I>
+struct Interface<I>
+{
+ static int accumulate() { return I; }
+};
+
+// Note: split this into a separate test if a
+// cxx_variadic_template_template_parameters feature is added.
+
+template <typename T>
+struct eval
+{
+ enum
+ {
+ Matched = 0
+ };
+};
+
+template <template <typename...> class T, typename... U>
+struct eval<T<U...>>
+{
+ enum
+ {
+ Matched = 1
+ };
+};
+
+template <typename...>
+struct A
+{
+};
+template <typename T>
+struct B
+{
+};
+template <typename T, typename U>
+struct C
+{
+};
+template <typename T, typename U, typename...>
+struct D
+{
+};
+
+// Note: This test assumes that a compiler supporting this feature
+// supports static_assert. Add a workaround if that does not hold.
+static_assert(eval<A<>>::Matched, "A Matches");
+static_assert(eval<A<int>>::Matched, "A Matches");
+static_assert(eval<A<int, char>>::Matched, "A Matches");
+static_assert(eval<B<int>>::Matched, "B Matches");
+static_assert(eval<C<int, char>>::Matched, "C Matches");
+static_assert(eval<D<int, char>>::Matched, "D Matches");
+static_assert(eval<D<int, char, bool>>::Matched, "D Matches");
+static_assert(eval<D<int, char, bool, double>>::Matched, "D Matches");
diff --git a/Tests/CompileFeatures/default_dialect.c b/Tests/CompileFeatures/default_dialect.c
new file mode 100644
index 0000000..b990e53
--- /dev/null
+++ b/Tests/CompileFeatures/default_dialect.c
@@ -0,0 +1,31 @@
+
+#if DEFAULT_C23
+# if __STDC_VERSION__ <= 201710L
+# error Unexpected value for __STDC_VERSION__.
+# endif
+#elif DEFAULT_C17
+# if __STDC_VERSION__ < 201710L
+# error Unexpected value for __STDC_VERSION__.
+# endif
+#elif DEFAULT_C11
+# if __STDC_VERSION__ < 201112L
+# error Unexpected value for __STDC_VERSION__.
+# endif
+#elif DEFAULT_C99
+# if __STDC_VERSION__ != 199901L
+# error Unexpected value for __STDC_VERSION__.
+# endif
+#else
+# if !DEFAULT_C90
+# error Buildsystem error
+# endif
+# if defined(__STDC_VERSION__) && \
+ !(defined(__SUNPRO_C) && __STDC_VERSION__ == 199409L)
+# error Unexpected __STDC_VERSION__ definition
+# endif
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CompileFeatures/default_dialect.cpp b/Tests/CompileFeatures/default_dialect.cpp
new file mode 100644
index 0000000..bd504ff
--- /dev/null
+++ b/Tests/CompileFeatures/default_dialect.cpp
@@ -0,0 +1,54 @@
+
+template <long l>
+struct Outputter;
+
+#if defined(__INTEL_COMPILER) && defined(_MSVC_LANG) && _MSVC_LANG < 201403L
+# if defined(__INTEL_CXX11_MODE__)
+# if defined(__cpp_aggregate_nsdmi)
+# define CXX_STD 201402L
+# else
+# define CXX_STD 201103L
+# endif
+# else
+# define CXX_STD 199711L
+# endif
+#elif defined(_MSC_VER) && defined(_MSVC_LANG)
+# define CXX_STD _MSVC_LANG
+#else
+# define CXX_STD __cplusplus
+#endif
+
+#if DEFAULT_CXX23
+# if CXX_STD <= 202002L
+Outputter<CXX_STD> o;
+# endif
+#elif DEFAULT_CXX20
+# if CXX_STD <= 201703L
+Outputter<CXX_STD> o;
+# endif
+#elif DEFAULT_CXX17
+# if CXX_STD <= 201402L
+Outputter<CXX_STD> o;
+# endif
+#elif DEFAULT_CXX14
+# if CXX_STD != 201402L
+Outputter<CXX_STD> o;
+# endif
+#elif DEFAULT_CXX11
+# if CXX_STD != 201103L
+Outputter<CXX_STD> o;
+# endif
+#else
+# if !DEFAULT_CXX98
+# error Buildsystem error
+# endif
+# if CXX_STD != 199711L && CXX_STD != 1 && \
+ !defined(__GXX_EXPERIMENTAL_CXX0X__)
+Outputter<CXX_STD> o;
+# endif
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CompileFeatures/feature_test.c b/Tests/CompileFeatures/feature_test.c
new file mode 100644
index 0000000..4147f1f
--- /dev/null
+++ b/Tests/CompileFeatures/feature_test.c
@@ -0,0 +1,10 @@
+
+#define STRINGIFY_IMPL(X) #X
+#define STRINGIFY(X) STRINGIFY_IMPL(X)
+
+#include STRINGIFY(TEST)
+
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CompileFeatures/feature_test.cpp b/Tests/CompileFeatures/feature_test.cpp
new file mode 100644
index 0000000..4406c16
--- /dev/null
+++ b/Tests/CompileFeatures/feature_test.cpp
@@ -0,0 +1,10 @@
+
+#define STRINGIFY_IMPL(X) #X
+#define STRINGIFY(X) STRINGIFY_IMPL(X)
+
+#include STRINGIFY(TEST)
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CompileFeatures/genex_test.c b/Tests/CompileFeatures/genex_test.c
new file mode 100644
index 0000000..de408ce
--- /dev/null
+++ b/Tests/CompileFeatures/genex_test.c
@@ -0,0 +1,43 @@
+#ifndef EXPECT_C_STATIC_ASSERT
+# error EXPECT_C_STATIC_ASSERT not defined
+#endif
+#ifndef EXPECT_C_FUNCTION_PROTOTYPES
+# error EXPECT_C_FUNCTION_PROTOTYPES not defined
+#endif
+#ifndef EXPECT_C_RESTRICT
+# error EXPECT_C_RESTRICT not defined
+#endif
+
+#if !HAVE_C_STATIC_ASSERT
+# if EXPECT_C_STATIC_ASSERT
+# error "Expect c_static_assert feature"
+# endif
+#else
+# if !EXPECT_C_STATIC_ASSERT
+# error "Expect no c_static_assert feature"
+# endif
+#endif
+
+#if !HAVE_C_FUNCTION_PROTOTYPES
+# if EXPECT_C_FUNCTION_PROTOTYPES
+# error Expect c_function_prototypes support
+# endif
+#else
+# if !EXPECT_C_FUNCTION_PROTOTYPES
+# error Expect no c_function_prototypes support
+# endif
+#endif
+
+#if !HAVE_C_RESTRICT
+# if EXPECT_C_RESTRICT
+# error Expect c_restrict support
+# endif
+#else
+# if !EXPECT_C_RESTRICT
+# error Expect no c_restrict support
+# endif
+#endif
+
+int main()
+{
+}
diff --git a/Tests/CompileFeatures/genex_test.cpp b/Tests/CompileFeatures/genex_test.cpp
new file mode 100644
index 0000000..9c3910e
--- /dev/null
+++ b/Tests/CompileFeatures/genex_test.cpp
@@ -0,0 +1,78 @@
+#ifndef EXPECT_FINAL
+# error EXPECT_FINAL not defined
+#endif
+#ifndef EXPECT_INHERITING_CONSTRUCTORS
+# error EXPECT_INHERITING_CONSTRUCTORS not defined
+#endif
+#ifndef EXPECT_INHERITING_CONSTRUCTORS_AND_FINAL
+# error EXPECT_INHERITING_CONSTRUCTORS_AND_FINAL not defined
+#endif
+#ifndef EXPECT_OVERRIDE_CONTROL
+# error EXPECT_OVERRIDE_CONTROL not defined
+#endif
+
+#ifdef TEST_CXX_STD
+# if !HAVE_CXX_STD_11
+# error HAVE_CXX_STD_11 is false with CXX_STANDARD == 11
+# endif
+# if HAVE_CXX_STD_14 && !defined(ALLOW_LATER_STANDARDS)
+# error HAVE_CXX_STD_14 is true with CXX_STANDARD == 11
+# endif
+# if HAVE_CXX_STD_17 && !defined(ALLOW_LATER_STANDARDS)
+# error HAVE_CXX_STD_17 is true with CXX_STANDARD == 11
+# endif
+# if HAVE_CXX_STD_20 && !defined(ALLOW_LATER_STANDARDS)
+# error HAVE_CXX_STD_20 is true with CXX_STANDARD == 11
+# endif
+# if HAVE_CXX_STD_23 && !defined(ALLOW_LATER_STANDARDS)
+# error HAVE_CXX_STD_23 is true with CXX_STANDARD == 11
+# endif
+#endif
+
+#if !HAVE_OVERRIDE_CONTROL
+# if EXPECT_OVERRIDE_CONTROL
+# error "Expect override control feature"
+# endif
+#else
+# if !EXPECT_OVERRIDE_CONTROL
+# error "Expect no override control feature"
+# endif
+#endif
+
+#if !HAVE_AUTO_TYPE
+# error Expect cxx_auto_type support
+#endif
+
+#if !HAVE_INHERITING_CONSTRUCTORS
+# if EXPECT_INHERITING_CONSTRUCTORS
+# error Expect cxx_inheriting_constructors support
+# endif
+#else
+# if !EXPECT_INHERITING_CONSTRUCTORS
+# error Expect no cxx_inheriting_constructors support
+# endif
+#endif
+
+#if !HAVE_FINAL
+# if EXPECT_FINAL
+# error Expect cxx_final support
+# endif
+#else
+# if !EXPECT_FINAL
+# error Expect no cxx_final support
+# endif
+#endif
+
+#if !HAVE_INHERITING_CONSTRUCTORS_AND_FINAL
+# if EXPECT_INHERITING_CONSTRUCTORS_AND_FINAL
+# error Expect cxx_inheriting_constructors and cxx_final support
+# endif
+#else
+# if !EXPECT_INHERITING_CONSTRUCTORS_AND_FINAL
+# error Expect no combined cxx_inheriting_constructors and cxx_final support
+# endif
+#endif
+
+int main()
+{
+}
diff --git a/Tests/CompileFeatures/main.cpp b/Tests/CompileFeatures/main.cpp
new file mode 100644
index 0000000..c5a7a46
--- /dev/null
+++ b/Tests/CompileFeatures/main.cpp
@@ -0,0 +1,6 @@
+
+int main(int, char**)
+{
+ auto value = 0;
+ return value;
+}
diff --git a/Tests/CompileOptions/CMakeLists.txt b/Tests/CompileOptions/CMakeLists.txt
new file mode 100644
index 0000000..cd6cacd
--- /dev/null
+++ b/Tests/CompileOptions/CMakeLists.txt
@@ -0,0 +1,74 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(CompileOptions)
+
+add_library(testlib other.cpp)
+
+if(TEST_FORTRAN)
+ enable_language(Fortran)
+endif()
+
+add_executable(CompileOptions main.cpp)
+
+macro(get_compiler_test_genex lst lang)
+ list(APPEND ${lst} -DTEST_${lang}_COMPILER_VERSION="$<${lang}_COMPILER_VERSION>")
+ list(APPEND ${lst} -DTEST_${lang}_COMPILER_VERSION_EQUALITY=$<${lang}_COMPILER_VERSION:${CMAKE_${lang}_COMPILER_VERSION}>)
+endmacro()
+
+get_compiler_test_genex(c_tests C)
+get_compiler_test_genex(cxx_tests CXX)
+if(TEST_FORTRAN)
+ get_compiler_test_genex(fortran_tests Fortran)
+endif()
+
+set_property(TARGET CompileOptions PROPERTY COMPILE_OPTIONS
+ "-DTEST_DEFINE"
+ "-DNEEDS_ESCAPE=\"E$CAPE\""
+ "$<$<CXX_COMPILER_ID:GNU>:-DTEST_DEFINE_GNU>"
+ "$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-DTEST_DEFINE_CXX_AND_GNU>"
+ "SHELL:" # produces no options
+ ${c_tests}
+ ${cxx_tests}
+ ${fortran_tests}
+ )
+if(BORLAND OR WATCOM)
+ # these compilers do not support separate -D flags
+ target_compile_definitions(CompileOptions PRIVATE NO_DEF_TESTS)
+else()
+ set_property(TARGET CompileOptions APPEND PROPERTY COMPILE_OPTIONS
+ "SHELL:-D DEF_A"
+ "$<1:SHELL:-D DEF_B>"
+ "SHELL:-D 'DEF_C' -D \"DEF_D\""
+ [[SHELL:-D "DEF_STR=\"string with spaces\""]]
+ )
+endif()
+
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|Borland|Embarcadero" AND NOT "${CMAKE_GENERATOR}" MATCHES "NMake Makefiles")
+ set_property(TARGET CompileOptions APPEND PROPERTY COMPILE_OPTIONS
+ "-DTEST_OCTOTHORPE=\"#\""
+ )
+endif()
+
+target_link_libraries(CompileOptions testlib)
+
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ target_compile_definitions(CompileOptions
+ PRIVATE
+ "DO_GNU_TESTS"
+ )
+endif()
+
+target_compile_definitions(CompileOptions
+ PRIVATE
+ "EXPECTED_C_COMPILER_VERSION=\"${CMAKE_C_COMPILER_VERSION}\""
+ "EXPECTED_CXX_COMPILER_VERSION=\"${CMAKE_CXX_COMPILER_VERSION}\""
+)
+
+if(TEST_FORTRAN)
+ # Definitions for the C++ code to test the values
+ target_compile_definitions(CompileOptions
+ PRIVATE
+ "TEST_FORTRAN"
+ "EXPECTED_Fortran_COMPILER_VERSION=\"${CMAKE_Fortran_COMPILER_VERSION}\""
+ )
+endif()
diff --git a/Tests/CompileOptions/main.cpp b/Tests/CompileOptions/main.cpp
new file mode 100644
index 0000000..ebc1017
--- /dev/null
+++ b/Tests/CompileOptions/main.cpp
@@ -0,0 +1,66 @@
+#ifndef TEST_DEFINE
+# error Expected definition TEST_DEFINE
+#endif
+
+#ifndef NEEDS_ESCAPE
+# error Expected definition NEEDS_ESCAPE
+#endif
+
+#ifdef DO_GNU_TESTS
+# ifndef TEST_DEFINE_GNU
+# error Expected definition TEST_DEFINE_GNU
+# endif
+# ifndef TEST_DEFINE_CXX_AND_GNU
+# error Expected definition TEST_DEFINE_CXX_AND_GNU
+# endif
+#endif
+
+#ifndef NO_DEF_TESTS
+# ifndef DEF_A
+# error Expected definition DEF_A
+# endif
+
+# ifndef DEF_B
+# error Expected definition DEF_B
+# endif
+
+# ifndef DEF_C
+# error Expected definition DEF_C
+# endif
+
+# ifndef DEF_D
+# error Expected definition DEF_D
+# endif
+
+# ifndef DEF_STR
+# error Expected definition DEF_STR
+# endif
+#endif
+
+#include <string.h>
+
+int main()
+{
+ return (strcmp(NEEDS_ESCAPE, "E$CAPE") == 0
+#ifdef TEST_OCTOTHORPE
+ && strcmp(TEST_OCTOTHORPE, "#") == 0
+#endif
+#ifndef NO_DEF_TESTS
+ && strcmp(DEF_STR, "string with spaces") == 0
+#endif
+ &&
+ strcmp(EXPECTED_C_COMPILER_VERSION, TEST_C_COMPILER_VERSION) == 0 &&
+ strcmp(EXPECTED_CXX_COMPILER_VERSION, TEST_CXX_COMPILER_VERSION) == 0
+#ifdef TEST_FORTRAN
+ && strcmp(EXPECTED_Fortran_COMPILER_VERSION,
+ TEST_Fortran_COMPILER_VERSION) == 0
+#endif
+ && TEST_C_COMPILER_VERSION_EQUALITY == 1 &&
+ TEST_CXX_COMPILER_VERSION_EQUALITY == 1
+#ifdef TEST_FORTRAN
+ && TEST_Fortran_COMPILER_VERSION_EQUALITY == 1
+#endif
+ )
+ ? 0
+ : 1;
+}
diff --git a/Tests/CompileOptions/other.cpp b/Tests/CompileOptions/other.cpp
new file mode 100644
index 0000000..7d75e37
--- /dev/null
+++ b/Tests/CompileOptions/other.cpp
@@ -0,0 +1,4 @@
+
+void foo(void)
+{
+}
diff --git a/Tests/Complex/CMakeLists.txt b/Tests/Complex/CMakeLists.txt
new file mode 100644
index 0000000..9fd85be
--- /dev/null
+++ b/Tests/Complex/CMakeLists.txt
@@ -0,0 +1,456 @@
+#
+# A more complex test case
+#
+cmake_minimum_required(VERSION 2.4)
+cmake_policy(SET CMP0054 NEW)
+project (Complex)
+
+# Test that renaming a built-in works when configured multiple times.
+message("message")
+function(message)
+ _message(${ARGN})
+endfunction()
+message("message")
+
+# Try setting a new policy. The IF test is for coverage.
+if(POLICY CMP0003)
+ cmake_policy(SET CMP0003 NEW)
+
+ cmake_policy(GET CMP0003 P3)
+ if(NOT "${P3}" STREQUAL "NEW")
+ message(FATAL_ERROR "cmake_policy(GET) did not report NEW!")
+ endif()
+endif()
+
+# It is not recommended to set a policy to OLD, but this test
+# covers the OLD behavior of some policies.
+foreach(p
+ CMP0029
+ CMP0032
+ CMP0033
+ CMP0034
+ CMP0043
+ CMP0050
+ )
+ if(POLICY ${p})
+ cmake_policy(SET ${p} OLD)
+ endif()
+endforeach()
+
+# Test building without per-rule echo lines in Makefiles.
+set_property(GLOBAL PROPERTY RULE_MESSAGES OFF)
+
+set(CPACK_SOURCE_IGNORE_FILES "~$;^C:/hoffman/My Builds/testcase.*/CVS/;^C:/hoffman/My Builds/testcase.*/\\.svn/;^C:/hoffman/My Builds/testcase.*/sweigart/;^C:/hoffman/My Builds/testcase/www/eospaper/solution/eos2001/;^C:/hoffman/My Builds/testcase/www/eospaper/solution/opal_tables_new/;^C:/hoffman/My Builds/testcase/COPYING$;^C:/hoffman/My Builds/testcase/INSTALL$;^C:/hoffman/My Builds/testcase/Makefile$;^C:/hoffman/My Builds/testcase/Makefile\\.in$;^C:/hoffman/My Builds/testcase/.*\\.lo$;^C:/hoffman/My Builds/testcase/.*\\.la$;^C:/hoffman/My Builds/testcase/mkinstalldirs$;^C:/hoffman/My Builds/testcase/missing$;^C:/hoffman/My Builds/testcase/ltmain\\.sh$;^C:/hoffman/My Builds/testcase/libtool$;^C:/hoffman/My Builds/testcase/install-sh$;^C:/hoffman/My Builds/testcase/configure$;^C:/hoffman/My Builds/testcase/config\\.sub$;^C:/hoffman/My Builds/testcase/config\\.status$;^C:/hoffman/My Builds/testcase/config\\.log$;^C:/hoffman/My Builds/testcase/config\\.guess$;^C:/hoffman/My Builds/testcase/autom4te\\.cache$;^C:/hoffman/My Builds/testcase/aclocal\\.m4$;^C:/hoffman/My Builds/testcase/depcomp$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.075\\.model_cassisi_eos1_10$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.075\\.model_cassisi_eos1_10_corr$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.1\\.model_cassisi_eos1$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.1\\.model_cassisi_scvh$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.1\\.modelc$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.3\\.modelc$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/1\\.0\\.modelc$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/1\\.0\\.rgbtip\\.modelc$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/1\\.0\\.zahb\\.modelc$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.1\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/1\\.0\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.3\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.085\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/.*\\.ps$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange\\.mem$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange\\.log$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange\\.dvi$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange\\.tex\\.bak$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/head\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/body\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/prior-dvi\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j10\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j12\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j16\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j20\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j22\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j26\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j30\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j32\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j36\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/k10\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/k12\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/k20\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/k22\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/k30\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/k32\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/1_exchange_dgamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/1_exchange_dlnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/2_exchange_dgamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/2_exchange_dlnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/linear_exchange_dgamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/linear_exchange_dlnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/noexchange_dgamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/noexchange_dlnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/nr_exchange_dgamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/nr_exchange_dlnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/series_exchange_dgamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/series_exchange_dlnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_JNR_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_Jseries_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_KNR_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_Kseries_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check34_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check35_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check36_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check43_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check44_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check45_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check46_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check47_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check48_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/tc_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/.*\\.pyc$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/context\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/make\\.out.*$;^C:/hoffman/My Builds/testcase/www/Makefile$;^C:/hoffman/My Builds/testcase/www/Makefile\\.in$;^C:/hoffman/My Builds/testcase/src/.*\\.flc$;^C:/hoffman/My Builds/testcase/src/Makefile$;^C:/hoffman/My Builds/testcase/src/Makefile\\.in$;^C:/hoffman/My Builds/testcase/src/\\.deps$;^C:/hoffman/My Builds/testcase/src/\\.libs$;^C:/hoffman/My Builds/testcase/src/.*\\.la$;^C:/hoffman/My Builds/testcase/src/.*\\.lo$;^C:/hoffman/My Builds/testcase/src/make\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/statef.*\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/0\\.1\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/0\\.1\\.model_13$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/0\\.1\\.model_23$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/0\\.3\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/0\\.3\\.model_13$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/0\\.3\\.model_23$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/1\\.0\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/1\\.0\\.model_13$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/1\\.0\\.model_15$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/1\\.0\\.model_23$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/1\\.0\\.model_rel$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/hot_post_agb\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/rgb_tip\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/rgbtip\\.1\\.0\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/rgbtip\\.1\\.0\\.model_13$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/rgbtip\\.1\\.0\\.model_23$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/start_shellflash\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/white_dwarf\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/zahb\\.1\\.0\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/zahb\\.1\\.0\\.model_13$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/zahb\\.1\\.0\\.model_23$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/zahb\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dh/dgamma1$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dh/dlnp$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dh/statef_compare\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fermi_dirac_approx/15gamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fermi_dirac_approx/15lnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fermi_dirac_approx/23gamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fermi_dirac_approx/23lnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/thermodynamic_consistency/.*\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/thermodynamic_consistency/.*\\.results$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/pteh/dgamma1$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/pteh/dlnp$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/pteh/statef_compare\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/newversion_grid/.*\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/newversion_grid/.*\\.err$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/.*\\.ps$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/.*\\.pyc$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_fit\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_fit\\.dvi$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_fit\\.log$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/body\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/head\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/prior-dvi\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/3order_data\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/5order_data\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/8order_data\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check8_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check1_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check3_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check5_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/effo_check3_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/effoo_check3_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fda15gamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fda15lnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fda23gamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fda23lnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/tc_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/make\\.out.*$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/thermodynamic_consistency/statef_compare\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/thermodynamic_consistency/tc\\.results$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/opal_solar/opal_compare_model\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/opal_solar/opal_compare_solar\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/opal_solar/opal_solar\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/opal_solar/opal_solar_1995\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/opal_solar/statef_opal_model\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/opal_solar/statef_opal_model_1995\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/purehe_newversion_grid/.*\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/purehe_newversion_grid/.*\\.err$;^C:/hoffman/My Builds/testcase/include/Makefile\\.in$;^C:/hoffman/My Builds/testcase/include/Makefile$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/model-loci/0\\.1\\.model_pteh$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/model-loci/1\\.0\\.model_eos1a-eos1$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/model-loci/1\\.0\\.model_pteh$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/model-loci/statef_model_0\\.1\\.model_pteh\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/model-loci/statef_model_1\\.0\\.model_eos1a-eos1\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/model-loci/statef_model_1\\.0\\.model_pteh\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/context/contour\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/context/eos_grid\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/context/statef_grid\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/thermodynamic_consistency/fort\\.91$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/thermodynamic_consistency/statef_compare\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/nocoulomb/dgamma1$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/nocoulomb/dlnp$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/nocoulomb/statef_compare\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/context$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/oldversion_grid$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/2005Ap&SS\\.298\\.\\.135S\\.pdf$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/2007Ap&SS\\.307\\.\\.263C\\.pdf$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/astro-ph\\.9909168_eprint_submitted_to_High_Press\\.Res\\.16,331\\.pdf$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/.*ps.*$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/.*\\.pyc$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/convergence\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/convergence\\.dvi$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/convergence\\.log$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/body\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/head\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/prior-dvi\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/statef_grid-newversion$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/context\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/pureh_context\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/purehe_context\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/old$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/make\\.out.*$;^C:/hoffman/My Builds/testcase/utils/.*\\.flc$;^C:/hoffman/My Builds/testcase/utils/Makefile$;^C:/hoffman/My Builds/testcase/utils/Makefile\\.in$;^C:/hoffman/My Builds/testcase/utils/\\.deps$;^C:/hoffman/My Builds/testcase/utils/\\.libs$;^C:/hoffman/My Builds/testcase/utils/.*\\.la$;^C:/hoffman/My Builds/testcase/utils/.*\\.lo$;^C:/hoffman/My Builds/testcase/utils/free_eos_test$;^C:/hoffman/My Builds/testcase/utils/test_rosenbrock$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check/eff_check1\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check/eff_check3\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check/eff_check5\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check/eff_check8\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check/eff_checknr\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check/effo_check3\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check/effoo_check3\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence_20070613$;^C:/hoffman/My Builds/testcase/www/eospaper/text$;^C:/hoffman/My Builds/testcase/www/eospaper/cassisi_book_fig$;^C:/hoffman/My Builds/testcase/www/eospaper/1\\.1\\.0$;^C:/hoffman/My Builds/testcase/www/eospaper/2\\.0\\.0$;^C:/hoffman/My Builds/testcase/www/eospaper/1\\.2\\.0$;^C:/hoffman/My Builds/testcase/www/eospaper/1\\.3\\.0$;^C:/hoffman/My Builds/testcase/www/eospaper/1\\.4\\.0$;^C:/hoffman/My Builds/testcase/www/eospaper/1\\.5\\.0$;^C:/hoffman/My Builds/testcase/www/eospaper/1\\.6\\.0$;^C:/hoffman/My Builds/testcase/www/eospaper/figures$;^C:/hoffman/My Builds/testcase/www/eospaper/old$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/.*\\.ps.*$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/coulomb\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/coulomb\\.dvi$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/coulomb\\.log$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/.*\\.pyc$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/body\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/head\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/prior-dvi\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/context\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dh_dgamma1_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dh_dlnp_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dhtau_dgamma1_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dhtau_dlnp_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/nocoulomb_dgamma1_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/nocoulomb_dlnp_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/pteh_dgamma1_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/pteh_dlnp_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/make\\.out.*$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_JNR\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_Jseries\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_KNR\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_Kseries\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_check34\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_check35\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_check36\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_check44\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_check45\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_check46\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/statef_compare_1_exchange\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/statef_compare_2_exchange\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/statef_compare_linear_exchange\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/statef_compare_noexchange\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/statef_compare_nr_exchange\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/statef_compare_series_exchange\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/1_exchange_dgamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/noexchange_dlnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/nr_exchange_dgamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/series_exchange_dlnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/series_exchange_dgamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/linear_exchange_dlnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/2_exchange_dgamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/nr_exchange_dlnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/linear_exchange_dgamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/noexchange_dgamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/1_exchange_dlnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/2_exchange_dlnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/pureh_newversion_grid/.*\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/pureh_newversion_grid/.*\\.err$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dhtau/dgamma1$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dhtau/dlnp$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dhtau/statef_compare\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_0\\.1\\.model\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_0\\.3\\.model\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_1\\.0\\.model\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_1\\.0\\.model_linear\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_1\\.0\\.model_noexchange\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_1\\.0\\.model_nr\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_1\\.0\\.rgbtip\\.model\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_1\\.0\\.zahb\\.model\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/1\\.0\\.zahb\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/1\\.0\\.rgbtip\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/1\\.0\\.model_linear$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/1\\.0\\.model_noexchange$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/1\\.0\\.model_nr$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/0\\.1\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/1\\.0\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/0\\.3\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/context/contour\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/context/eos_grid\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/context/statef_grid\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/gong/delta\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/gong/m0085eos1gong\\.ascii$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/gong/m0085eos2gong\\.ascii$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/coulomb_adjust/coulomb_adjust\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/.*\\.ps$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/.*\\.pyc$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/head\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/body\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/prior-dvi\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/solution\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/solution\\.log$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/solution\\.dvi$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/rtc_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/tc_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/make\\.out.*$")
+
+#
+# Define a macro
+#
+macro(ASSERT value msg)
+ if (NOT ${value})
+ message ("Assertion failure:" ${msg} )
+ endif ()
+endmacro()
+
+# invoke the macro
+ASSERT(Complex_BINARY_DIR "The PROJECT command is broken")
+
+#
+# Define a var args macro, it must take two or four args
+#
+macro(TEST_ARGC value1 value2)
+ add_definitions(${value1} ${value2})
+ if (${ARGC} EQUAL 4)
+ add_definitions(${ARGV2} ${ARGV3})
+ endif ()
+endmacro()
+
+# invoke the macro
+TEST_ARGC(-DCMAKE_ARGV1 -DCMAKE_ARGV2 -DCMAKE_ARGV3 -DCMAKE_ARGV4)
+
+macro(TEST_VAR_ARG fa)
+ if("${ARGV}" STREQUAL "1;2;3")
+ message(STATUS "ARGV works")
+ else()
+ message(FATAL_ERROR "ARGV does not work; got \"${ARGV}\" instead of \"1;2;3\"")
+ endif()
+ if("${ARGN}" STREQUAL "2;3")
+ message(STATUS "ARGN works")
+ else()
+ message(FATAL_ERROR "ARGV does not work; got \"${ARGN}\" instead of \"2;3\"")
+ endif()
+endmacro()
+
+TEST_VAR_ARG(1 2 3)
+
+# Floating-point comparison test.
+if(2.4 LESS 2.4)
+ message(FATAL_ERROR "Failed: 2.4 LESS 2.4")
+endif()
+if(2.4 GREATER 2.4)
+ message(FATAL_ERROR "Failed: 2.4 GREATER 2.4")
+endif()
+if(NOT 2.4 EQUAL 2.4)
+ message(FATAL_ERROR "Failed: NOT 2.4 EQUAL 2.4")
+endif()
+if(NOT 2.4 LESS_EQUAL 2.4)
+ message(FATAL_ERROR "Failed: NOT 2.4 LESS_EQUAL 2.4")
+endif()
+if(NOT 2.4 GREATER_EQUAL 2.4)
+ message(FATAL_ERROR "Failed: NOT 2.4 GREATER_EQUAL 2.4")
+endif()
+
+if(CMAKE_SYSTEM MATCHES "OSF1-V")
+ if(NOT CMAKE_COMPILER_IS_GNUCXX)
+ string(APPEND CMAKE_CXX_FLAGS " -timplicit_local -no_implicit_include ")
+ endif()
+endif()
+
+
+add_definitions(-DCMAKE_IS_FUN)
+add_definitions(-DCMAKE_IS_REALLY_FUN)
+set_property(DIRECTORY
+ PROPERTY COMPILE_DEFINITIONS_RELEASE
+ CMAKE_IS_FUN_IN_RELEASE_MODE
+ )
+set_property(DIRECTORY
+ PROPERTY COMPILE_DEFINITIONS_RELWITHDEBINFO
+ CMAKE_IS_FUN_IN_RELEASE_MODE
+ )
+set_property(DIRECTORY
+ PROPERTY COMPILE_DEFINITIONS_MINSIZEREL
+ CMAKE_IS_FUN_IN_RELEASE_MODE
+ )
+
+set(TEST_SEP "a b c")
+separate_arguments(TEST_SEP)
+
+
+#
+# Include vars from a file and from a cache
+#
+if (EXISTS ${Complex_SOURCE_DIR}/VarTests.cmake)
+ include(${Complex_SOURCE_DIR}/VarTests.cmake)
+endif ()
+include(fileshouldnotbehere OPTIONAL)
+load_cache(${Complex_SOURCE_DIR}/Cache
+ EXCLUDE
+ CACHE_TEST_VAR_EXCLUDED
+ INCLUDE_INTERNALS
+ CACHE_TEST_VAR_INTERNAL)
+
+load_cache(${Complex_SOURCE_DIR}/Cache READ_WITH_PREFIX foo CACHE_TEST_VAR2)
+if(${fooCACHE_TEST_VAR2} MATCHES bar)
+ message("Load cache worked: ${fooCACHE_TEST_VAR2}")
+else()
+ message(FATAL_ERROR "Load cache with prefix failed: ${fooCACHE_TEST_VAR2}")
+endif()
+
+
+
+#
+# Specify include and lib dirs
+# (BEFORE is for coverage)
+#
+include_directories(
+ Library
+)
+
+include_directories(BEFORE
+ ${Complex_BINARY_DIR}
+)
+include_directories(SYSTEM Library/SystemDir)
+
+include_regular_expression("^(cmTest|file|sharedFile|test).*$" "^cmMissing")
+
+link_directories(
+ ${Complex_BINARY_DIR}/Library
+)
+
+#
+# check for SET CACHE FORCE
+#
+set(FORCE_TEST 1 CACHE STRING "a test")
+set(FORCE_TEST 0 CACHE STRING "a test" FORCE)
+
+#
+# Lib and exe path
+#
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${Complex_BINARY_DIR}/lib/static")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${Complex_BINARY_DIR}/lib")
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${Complex_BINARY_DIR}/bin")
+
+message (Test " " escape " " semi-colon " " \; \;)
+#
+# Exec program (TODO: test a result)
+# Increase coverage.
+#
+message("\nIgnore this message")
+option(NO_EXEC_PROGRAM "Do not test EXEC_PROGRAM" 0)
+if (NOT NO_EXEC_PROGRAM)
+ exec_program(${CMAKE_COMMAND} ARGS -E echo NO_EXEC_PROGRAM "${Complex_BINARY_DIR}")
+else ()
+ message("Set this option ON")
+endif ()
+
+mark_as_advanced(NO_EXEC_PROGRAM)
+mark_as_advanced(CLEAR NO_EXEC_PROGRAM)
+
+# Execute a process. Add coverage for this command.
+execute_process(
+ COMMAND ${CMAKE_COMMAND} -E echo "ABCDEFG"
+ OUTPUT_VARIABLE TEST_OUT
+ )
+if("${TEST_OUT}" STREQUAL "ABCDEFG\n")
+else()
+ message(SEND_ERROR "EXECUTE_PROCESS output test failed: [${TEST_OUT}]")
+endif()
+
+# This test has some problems on UNIX systems. Disabling for now.
+#
+# execute_process(
+# COMMAND ${CMAKE_COMMAND} -E echo "ABCDEFG"
+# COMMAND /process/does/not/exist
+# OUTPUT_QUIET
+# ERROR_QUIET
+# RESULT_VARIABLE RESULT
+# )
+# if("${RESULT}" STREQUAL "0")
+# message(SEND_ERROR
+# "EXECUTE_PROCESS result test failed with RESULT=[${RESULT}]")
+# else()
+# message(STATUS "EXECUTE_PROCESS result test passed with RESULT=[${RESULT}]")
+# endif()
+
+#
+# Create directory.
+# The 'complex' executable will then test if this dir exists,
+# sadly it won't be able to remove it.
+#
+make_directory("${Complex_BINARY_DIR}/make_dir")
+
+#
+# Test FIND_LIBARY
+# Create a dummy empty lib
+#
+configure_file(
+ ${Complex_SOURCE_DIR}/Library/dummy
+ ${Complex_BINARY_DIR}/Library/dummylib.lib
+ COPYONLY)
+foreach (ext ${CMAKE_SHLIB_SUFFIX};.so;.a;.sl
+ ${CMAKE_SHARED_LIBRARY_SUFFIX}.2
+ ${CMAKE_STATIC_LIBRARY_SUFFIX}.2)
+ configure_file(
+ ${Complex_SOURCE_DIR}/Library/dummy
+ ${Complex_BINARY_DIR}/Library/libdummylib${ext}
+ COPYONLY)
+endforeach ()
+
+find_library(FIND_DUMMY_LIB
+ dummylib
+ PATHS
+ ${Complex_BINARY_DIR}/Library DOC "find dummy lib")
+
+find_library(FIND_DUMMY_LIB
+ NAMES dummylib dummylib2
+ PATHS
+ ${Complex_BINARY_DIR}/Library DOC "find dummy lib")
+
+# This doesn't work for platforms that have a shared library and an import
+# library, like Windows with .dll and .lib. Limit is to ".so" now because it's
+# known to work there.
+if(CMAKE_SHARED_LIBRARY_SUFFIX STREQUAL ".so")
+ find_library(FIND_DUMMY_SHLIB_VERSIONED
+ NAMES libdummylib${CMAKE_SHARED_LIBRARY_SUFFIX}.2
+ PATHS ${Complex_BINARY_DIR}/Library
+ DOC "find versioned dummy shared lib"
+ NO_DEFAULT_PATH)
+
+ if(NOT FIND_DUMMY_SHLIB_VERSIONED MATCHES "/libdummylib${CMAKE_SHARED_LIBRARY_SUFFIX}.2")
+ message(SEND_ERROR "FIND_DUMMY_SHLIB_VERSIONED is not set correctly: "
+ "${FIND_DUMMY_SHLIB_VERSIONED}")
+ endif()
+endif()
+
+# Static library, should work everywhere
+find_library(FIND_DUMMY_STLIB_VERSIONED
+ NAMES libdummylib${CMAKE_STATIC_LIBRARY_SUFFIX}.2
+ PATHS ${Complex_BINARY_DIR}/Library
+ DOC "find versioned dummy static lib"
+ NO_DEFAULT_PATH)
+
+if(NOT FIND_DUMMY_STLIB_VERSIONED MATCHES "/libdummylib${CMAKE_STATIC_LIBRARY_SUFFIX}.2")
+ message(SEND_ERROR "FIND_DUMMY_STLIB_VERSIONED is not set correctly: "
+ "${FIND_DUMMY_STLIB_VERSIONED}")
+endif()
+
+#
+# Test SET_SOURCE_FILES_PROPERTIES
+#
+set_source_files_properties(nonexisting_file2
+ GENERATED
+ ABSTRACT
+ WRAP_EXCLUDE
+ COMPILE_FLAGS "-foo -bar")
+
+get_source_file_property(FILE_HAS_ABSTRACT nonexisting_file2 ABSTRACT)
+get_source_file_property(FILE_HAS_WRAP_EXCLUDE nonexisting_file2 WRAP_EXCLUDE)
+get_source_file_property(FILE_COMPILE_FLAGS nonexisting_file2 COMPILE_FLAGS)
+
+set_source_files_properties(nonexisting_file3 PROPERTIES
+ GENERATED 1
+ ABSTRACT 1
+ WRAP_EXCLUDE 1
+ COMPILE_FLAGS "-foo -bar")
+get_source_file_property(FILE_HAS_ABSTRACT nonexisting_file3 ABSTRACT)
+get_source_file_property(FILE_HAS_WRAP_EXCLUDE nonexisting_file3 WRAP_EXCLUDE)
+get_source_file_property(FILE_COMPILE_FLAGS nonexisting_file3 COMPILE_FLAGS)
+
+#
+# Test registry (win32)
+# Create a file, put its path in a registry key, try to find the file in that
+# path using that registry key, then remove the file and the key
+#
+if (WIN32)
+ if (NOT UNIX)
+ set(dir "${Complex_BINARY_DIR}/registry_dir")
+ set(file "registry_test_dummy")
+ set(hkey "HKEY_CURRENT_USER\\Software\\Kitware\\CMake\\Tests\\Complex;registry_test")
+ configure_file(
+ ${Complex_SOURCE_DIR}/Library/dummy
+ "${dir}/${file}"
+ COPYONLY)
+ exec_program(${CMAKE_COMMAND} ARGS "-E write_regv \"${hkey}\" \"${dir}\"")
+ find_path(REGISTRY_TEST_PATH
+ ${file}
+ "[${hkey}]" DOC "Registry_Test_Path")
+ exec_program(${CMAKE_COMMAND} ARGS "-E delete_regv \"${hkey}\"")
+ exec_program(${CMAKE_COMMAND} ARGS "-E rm -f \"${dir}/${file}\"")
+ endif ()
+endif ()
+
+#
+# Test a set and a remove
+#
+set(REMOVE_STRING a b c d e f)
+set(removeVar1 c e)
+remove(REMOVE_STRING ${removeVar1} f)
+
+#
+# Test an IF inside a FOREACH.
+#
+foreach(x "a")
+ if(${x} MATCHES "a")
+ # Should always execute.
+ set(IF_INSIDE_FOREACH_THEN_EXECUTED 1)
+ else()
+ # Should never execute.
+ set(IF_INSIDE_FOREACH_ELSE_EXECUTED 1)
+ endif()
+endforeach()
+
+# test WHILE command
+set (while_var 1)
+while (while_var LESS 1000)
+ set(while_var ${while_var}0)
+endwhile()
+
+set(SHOULD_BE_ZERO )
+set(SHOULD_BE_ONE 1)
+set(SHOULD_BE_ZERO_AND_INDENTED )
+set(SHOULD_BE_ONE_AND_INDENTED 1)
+
+# test elseif functionality, the mess below tries to catch problem
+# of clauses being executed early or late etc
+set (RESULT 3)
+if (RESULT EQUAL 1)
+ if (RESULT EQUAL 2)
+ set (ELSEIF_RESULT 1)
+ elseif (RESULT EQUAL 3)
+ set (ELSEIF_RESULT 1)
+ endif ()
+elseif (RESULT EQUAL 2)
+ set (ELSEIF_RESULT 1)
+elseif (RESULT EQUAL 3)
+ if (RESULT EQUAL 2)
+ set (ELSEIF_RESULT 1)
+ elseif (RESULT EQUAL 3)
+ if (NOT ELSEIF_RESULT EQUAL 1)
+ set (ELSEIF_RESULT 2)
+ endif ()
+ endif ()
+elseif (RESULT EQUAL 4)
+ if (RESULT EQUAL 2)
+ set (ELSEIF_RESULT 1)
+ elseif (RESULT EQUAL 3)
+ set (ELSEIF_RESULT 1)
+ endif ()
+else ()
+ if (RESULT EQUAL 2)
+ set (ELSEIF_RESULT 1)
+ elseif (RESULT EQUAL 3)
+ set (ELSEIF_RESULT 1)
+ endif ()
+endif ()
+
+if (NOT ELSEIF_RESULT EQUAL 2)
+ set (ELSEIF_RESULT 0)
+endif ()
+
+# test handling of parenthetical groups in conditionals
+if (2 GREATER 1 AND (4 LESS 3 OR 5 LESS 6) AND NOT (7 GREATER 8))
+ set(CONDITIONAL_PARENTHESES 1)
+endif()
+
+
+#
+# Configure file
+# (plug vars to #define so that they can be tested)
+#
+configure_file(
+ ${Complex_SOURCE_DIR}/cmTestConfigure.h.in
+ ${Complex_BINARY_DIR}/cmTestConfigure.h)
+
+set(STRING_WITH_QUOTES "\"hello world\"")
+# test CONFIGURE_FILE with ESCAPE_QUOTES on
+configure_file(
+ ${Complex_SOURCE_DIR}/cmTestConfigureEscape.h.in
+ ${Complex_BINARY_DIR}/cmTestConfigureEscape.h ESCAPE_QUOTES)
+
+# Test regular expression commands.
+string(REGEX MATCH "b" RESULT "abc")
+if(NOT RESULT)
+ message(SEND_ERROR "string(REGEX MATCH ... ) test failed.")
+endif()
+string(REGEX MATCHALL "b" RESULT "abcb")
+if(NOT RESULT)
+ message(SEND_ERROR "string(REGEX MATCHALL ... ) test failed.")
+endif()
+string(REGEX REPLACE ".([bd])." "[\\1]" RESULT "a(b)c(d)e")
+if(NOT RESULT STREQUAL "a[b]c[d]e")
+ message(SEND_ERROR
+ "string(REGEX REPLACE ... ) test failed (\"${RESULT}\" v. \"a[b]c[d]e\")")
+endif()
+
+#
+# This tests needs Ansi C++98
+#
+set(CMAKE_CXX_STANDARD 98)
+#
+# GNU extensions are needed for stricmp() on Windows.
+#
+set(CMAKE_CXX_EXTENSIONS TRUE)
+
+# Clang/C2 in C++98 mode cannot properly handle some of MSVC headers
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
+ CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
+ set(CMAKE_CXX_STANDARD 11)
+endif()
+
+#
+# Create the libs and the main exe
+#
+add_subdirectory(Library)
+add_subdirectory(Executable)
+subdir_depends(Executable Library)
+export_library_dependencies(${Complex_BINARY_DIR}/ComplexLibraryDepends.cmake)
+include(${Complex_BINARY_DIR}/ComplexLibraryDepends.cmake OPTIONAL)
diff --git a/Tests/Complex/Cache/CMakeCache.txt b/Tests/Complex/Cache/CMakeCache.txt
new file mode 100644
index 0000000..727faa2
--- /dev/null
+++ b/Tests/Complex/Cache/CMakeCache.txt
@@ -0,0 +1,34 @@
+# This is the CMakeCache file.
+# For build in directory: d:/build/kitware/cmake/CMake-nmake/Tests/Complex
+# You can edit this file to change values found and used by cmake.
+# If you do not want to change any of the values, simply exit the editor.
+# If you do want to change a value, simply edit, save, and exit the editor.
+# The syntax for the file is as follows:
+# KEY:TYPE=VALUE
+# KEY is the name of a variable in the cache.
+# TYPE is a hint to GUI's for the type of VALUE, DO NOT EDIT TYPE!.
+# VALUE is the current value for the KEY.
+
+########################
+# EXTERNAL cache entries
+########################
+
+//A var.
+CACHE_TEST_VAR1:STRING=foo
+
+//A var.
+CACHE_TEST_VAR2:FILEPATH=bar
+
+//A var.
+CACHE_TEST_VAR3:BOOL=1
+
+//A var.
+CACHE_TEST_VAR_EXCLUDED:BOOL=1
+
+
+########################
+# INTERNAL cache entries
+########################
+
+//A var.
+CACHE_TEST_VAR_INTERNAL:INTERNAL=bar
diff --git a/Tests/Complex/Executable/A.cxx b/Tests/Complex/Executable/A.cxx
new file mode 100644
index 0000000..fb3eb08
--- /dev/null
+++ b/Tests/Complex/Executable/A.cxx
@@ -0,0 +1,9 @@
+// Include code from a header that should not be compiled separately.
+#include "A.hh"
+
+#include <stdio.h>
+int main()
+{
+ printf("#define A_VALUE %d\n", A());
+ return 0;
+}
diff --git a/Tests/Complex/Executable/A.h b/Tests/Complex/Executable/A.h
new file mode 100644
index 0000000..3503719
--- /dev/null
+++ b/Tests/Complex/Executable/A.h
@@ -0,0 +1,7 @@
+// This header should not be compiled directly but through inclusion
+// in A.cxx through A.hh.
+extern int A();
+int A()
+{
+ return 10;
+}
diff --git a/Tests/Complex/Executable/A.hh b/Tests/Complex/Executable/A.hh
new file mode 100644
index 0000000..e6bab02
--- /dev/null
+++ b/Tests/Complex/Executable/A.hh
@@ -0,0 +1,2 @@
+// This header should not be compiled directly but through inclusion in A.cxx
+#include "A.h"
diff --git a/Tests/Complex/Executable/A.txt b/Tests/Complex/Executable/A.txt
new file mode 100644
index 0000000..8ee9462
--- /dev/null
+++ b/Tests/Complex/Executable/A.txt
@@ -0,0 +1 @@
+This file should not be compiled!
diff --git a/Tests/Complex/Executable/CMakeLists.txt b/Tests/Complex/Executable/CMakeLists.txt
new file mode 100644
index 0000000..2a79629
--- /dev/null
+++ b/Tests/Complex/Executable/CMakeLists.txt
@@ -0,0 +1,174 @@
+#
+# Create exe.
+#
+string(APPEND CMAKE_CXX_FLAGS " -DTEST_CXX_FLAGS")
+string(APPEND CMAKE_C_FLAGS " -DTEST_C_FLAGS")
+
+# Create an imported target for if(TARGET) test below.
+add_library(ExeImportedTarget UNKNOWN IMPORTED)
+
+# Test if(TARGET) command.
+if(NOT TARGET CMakeTestLibrary)
+ message(FATAL_ERROR "if(NOT TARGET CMakeTestLibrary) returned true!")
+endif()
+if(NOT TARGET ExeImportedTarget)
+ message(FATAL_ERROR "if(NOT TARGET ExeImportedTarget) returned true!")
+endif()
+if(TARGET LibImportedTarget)
+ message(FATAL_ERROR "if(TARGET LibImportedTarget) returned true!")
+endif()
+if(TARGET NotATarget)
+ message(FATAL_ERROR "if(TARGET NotATarget) returned true!")
+endif()
+
+# Use LINK_LIBRARIES instead of TARGET_LINK_LIBRARIES to
+set(COMPLEX_LIBS CMakeTestLibrary;CMakeTestLibraryShared;CMakeTestCLibraryShared)
+link_libraries(${COMPLEX_LIBS})
+
+# Test forcing a .cxx file to not build.
+set_source_files_properties(complex_nobuild.cxx PROPERTIES
+ HEADER_FILE_ONLY 1)
+
+# Test forcing a .c file to not build.
+# This makes sure a mixed language library is created
+# with header file only sources
+set_source_files_properties(complex_nobuild.c PROPERTIES
+ HEADER_FILE_ONLY 1)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+add_executable(A A.cxx A.hh A.h A.txt)
+add_custom_command(OUTPUT Aout.h COMMAND A > Aout.h VERBATIM)
+add_executable(complex complex testcflags.c Aout.h)
+# Sub1/NameConflictTest.c Sub2/NameConflictTest.c)
+add_executable(complex.file complex.file.cxx complex_nobuild.cxx
+ complex_nobuild.c)
+
+if (UNIX)
+ target_link_libraries(complex ${CMAKE_DL_LIBS})
+else()
+ if (NOT BORLAND)
+ if(NOT MINGW)
+ target_link_libraries(complex rpcrt4.lib)
+ endif()
+ endif()
+endif ()
+
+# Test linking to static lib when a shared lib has the same name.
+if(CMAKE_EXE_LINK_STATIC_CXX_FLAGS)
+ add_definitions(-DCOMPLEX_TEST_LINK_STATIC)
+ target_link_libraries(complex CMakeTestLinkStatic)
+endif()
+
+# can we get the path to a source file
+get_source_file_property(A_LOCATION A.cxx LOCATION)
+if ("${A_LOCATION}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}/A.cxx")
+ add_definitions(-DCMAKE_FOUND_ACXX)
+endif ()
+
+# get the directory parent
+get_directory_property(P_VALUE PARENT_DIRECTORY)
+if ("${P_VALUE}" STREQUAL "${CMAKE_SOURCE_DIR}")
+ add_definitions(-DCMAKE_FOUND_PARENT)
+endif ()
+
+# get the stack of listfiles
+include(Included.cmake)
+if ("${LF_VALUE}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt;${CMAKE_CURRENT_SOURCE_DIR}/Included.cmake")
+ add_definitions(-DCMAKE_FOUND_LISTFILE_STACK)
+endif ()
+
+# Test add/remove definitions.
+add_definitions(
+ -DCOMPLEX_DEFINED_PRE
+ -DCOMPLEX_DEFINED
+ -DCOMPLEX_DEFINED_POST
+ -DCOMPLEX_DEFINED
+ )
+remove_definitions(-DCOMPLEX_DEFINED)
+
+# Test pre-build/pre-link/post-build rules for an executable.
+add_custom_command(TARGET complex PRE_BUILD
+ COMMAND ${CREATE_FILE_EXE}
+ ARGS "Executable/prebuild.txt"
+ WORKING_DIRECTORY "${Complex_BINARY_DIR}")
+add_custom_command(TARGET complex PRE_LINK
+ COMMAND ${CREATE_FILE_EXE}
+ ARGS "Executable/prelink.txt"
+ WORKING_DIRECTORY "${Complex_BINARY_DIR}")
+add_custom_command(TARGET complex POST_BUILD
+ COMMAND ${CREATE_FILE_EXE}
+ ARGS "Executable/postbuild.txt"
+ WORKING_DIRECTORY "${Complex_BINARY_DIR}")
+add_custom_command(TARGET complex POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy
+ "Executable/postbuild.txt"
+ "Executable/postbuild2.txt"
+ WORKING_DIRECTORY "${Complex_BINARY_DIR}")
+
+set_source_files_properties(complex
+ COMPILE_FLAGS
+ "-DFILE_HAS_EXTRA_COMPILE_FLAGS"
+ #" -DFILE_DEFINE_STRING=\\\"hello\\\""
+ OBJECT_DEPENDS ${Complex_BINARY_DIR}/cmTestGeneratedHeader.h
+)
+set_target_properties(complex PROPERTIES COMPILE_FLAGS "-DCOMPLEX_TARGET_FLAG")
+add_custom_command(
+ TARGET complex
+ SOURCE ${Complex_SOURCE_DIR}/cmTestGeneratedHeader.h.in
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${Complex_SOURCE_DIR}/cmTestGeneratedHeader.h.in
+ ${Complex_BINARY_DIR}/cmTestGeneratedHeader.h
+ OUTPUTS ${Complex_BINARY_DIR}/cmTestGeneratedHeader.h
+ DEPENDS ${CMAKE_COMMAND}
+)
+
+# Test creating an executable that is not built by default.
+add_executable(notInAllExe EXCLUDE_FROM_ALL notInAllExe.cxx)
+target_link_libraries(notInAllExe notInAllLib)
+
+# Test user-value flag mapping for the VS IDE.
+if(MSVC)
+ set_target_properties(notInAllExe PROPERTIES
+ LINK_FLAGS "/NODEFAULTLIB:LIBC;LIBCMT;MSVCRT")
+endif()
+
+# Test creating a custom target that builds not-in-all targets.
+add_custom_target(notInAllCustom)
+add_dependencies(notInAllCustom notInAllExe)
+
+#
+# Output the files required by 'complex' to a file.
+#
+# This test has been moved to the 'required' subdir so that it
+# has no side-effects on the current Makefile (duplicated source file
+# due to source list expansion done twice).
+#
+add_subdirectory(Temp)
+
+if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_INCLUDE_SYSTEM_FLAG_CXX
+ AND NOT XCODE) # XCODE is excluded due to #15687
+ add_executable(testSystemDir testSystemDir.cxx)
+ set_target_properties(testSystemDir PROPERTIES COMPILE_FLAGS "-Werror")
+endif()
+
+#
+# Extra coverage.Not used.
+#
+install_targets(/tmp complex)
+install_programs(/tmp complex)
+
+configure_file(
+ ${Complex_SOURCE_DIR}/Executable/cmVersion.h.in
+ ${Complex_BINARY_DIR}/cmVersion.h)
+
+source_group(A_GROUP ".cxx")
+source_group(B_GROUP REGULAR_EXPRESSION "cxx")
+source_group(C_GROUP FILES complex.cxx)
+
+file(WRITE ${Complex_BINARY_DIR}/A/libA.a "test")
+file(WRITE ${Complex_BINARY_DIR}/A/libC.a "test")
+file(WRITE ${Complex_BINARY_DIR}/B/libB.a "test")
+file(WRITE ${Complex_BINARY_DIR}/B/libA.a "test")
+file(WRITE ${Complex_BINARY_DIR}/C/libC.a "test")
+file(WRITE ${Complex_BINARY_DIR}/C/libB.a "test")
diff --git a/Tests/Complex/Executable/Included.cmake b/Tests/Complex/Executable/Included.cmake
new file mode 100644
index 0000000..520a68b
--- /dev/null
+++ b/Tests/Complex/Executable/Included.cmake
@@ -0,0 +1,2 @@
+get_directory_property(LF_VALUE LISTFILE_STACK)
+
diff --git a/Tests/Complex/Executable/Sub1/NameConflictTest.c b/Tests/Complex/Executable/Sub1/NameConflictTest.c
new file mode 100644
index 0000000..8720386
--- /dev/null
+++ b/Tests/Complex/Executable/Sub1/NameConflictTest.c
@@ -0,0 +1,4 @@
+int NameConflictTest1()
+{
+ return 0;
+}
diff --git a/Tests/Complex/Executable/Sub2/NameConflictTest.c b/Tests/Complex/Executable/Sub2/NameConflictTest.c
new file mode 100644
index 0000000..4a32572
--- /dev/null
+++ b/Tests/Complex/Executable/Sub2/NameConflictTest.c
@@ -0,0 +1,4 @@
+int NameConflictTest2()
+{
+ return 0;
+}
diff --git a/Tests/Complex/Executable/Temp/CMakeLists.txt b/Tests/Complex/Executable/Temp/CMakeLists.txt
new file mode 100644
index 0000000..041fcff
--- /dev/null
+++ b/Tests/Complex/Executable/Temp/CMakeLists.txt
@@ -0,0 +1,8 @@
+#
+# Output the files required by 'complex' to a file.
+# The 'complex' executable will then test if this file exists and remove it.
+# The contents of this file is not tested (absolute paths).
+#
+output_required_files(
+ ${Complex_SOURCE_DIR}/Executable/complex.cxx
+ ${Complex_BINARY_DIR}/Executable/Temp/complex-required.txt)
diff --git a/Tests/Complex/Executable/cmVersion.h.in b/Tests/Complex/Executable/cmVersion.h.in
new file mode 100644
index 0000000..de7522d
--- /dev/null
+++ b/Tests/Complex/Executable/cmVersion.h.in
@@ -0,0 +1 @@
+#define CMAKE_MINIMUM_REQUIRED_VERSION "${CMAKE_MINIMUM_REQUIRED_VERSION}"
diff --git a/Tests/Complex/Executable/complex.cxx b/Tests/Complex/Executable/complex.cxx
new file mode 100644
index 0000000..49e97d5
--- /dev/null
+++ b/Tests/Complex/Executable/complex.cxx
@@ -0,0 +1,1086 @@
+#include "cmTestConfigure.h"
+#include "cmTestConfigureEscape.h"
+#include "cmTestGeneratedHeader.h"
+#include "cmVersion.h"
+
+#include "Aout.h"
+#include "ExtraSources/file1.h"
+#include "file2.h"
+#include "sharedFile.h"
+extern "C" {
+#include "testConly.h"
+}
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#if !defined(S_ISDIR)
+# define S_ISDIR(mode) ((mode)&_S_IFDIR)
+#endif
+
+#ifdef COMPLEX_TEST_LINK_STATIC
+extern "C" {
+int TestLinkGetType();
+}
+#endif
+
+int cm_passed = 0;
+int cm_failed = 0;
+// ======================================================================
+
+void cmFailed(const char* Message, const char* m2 = "", const char* m3 = "")
+{
+ std::cout << "FAILED: " << Message << m2 << m3 << "\n";
+ cm_failed++;
+}
+
+// ======================================================================
+
+void cmPassed(const char* Message, const char* m2 = "")
+{
+ std::cout << "Passed: " << Message << m2 << "\n";
+ cm_passed++;
+}
+
+#ifndef COMPLEX_DEFINED_PRE
+# error "COMPLEX_DEFINED_PRE not defined!"
+#endif
+
+#ifdef COMPLEX_DEFINED
+# error "COMPLEX_DEFINED is defined but it should not!"
+#endif
+
+#ifndef COMPLEX_DEFINED_POST
+# error "COMPLEX_DEFINED_POST not defined!"
+#endif
+
+#ifndef CMAKE_IS_REALLY_FUN
+# error This is a problem. Looks like ADD_DEFINITIONS and REMOVE_DEFINITIONS does not work
+#endif
+
+#if defined(NDEBUG) && !defined(CMAKE_IS_FUN_IN_RELEASE_MODE)
+# error Per-configuration directory-level definition not inherited.
+#endif
+
+// ======================================================================
+
+void TestAndRemoveFile(const char* filename)
+{
+ struct stat st;
+ if (stat(filename, &st) < 0) {
+ cmFailed("Could not find file: ", filename);
+ } else {
+ if (remove(filename) < 0) {
+ cmFailed("Unable to remove file. It does not imply that this test "
+ "failed, but it *will* be corrupted thereafter if this file is "
+ "not removed: ",
+ filename);
+ } else {
+ cmPassed("Find and remove file: ", filename);
+ }
+ }
+}
+
+// ======================================================================
+
+void TestDir(const char* filename)
+{
+ struct stat st;
+ if (stat(filename, &st) < 0 || !S_ISDIR(st.st_mode)) {
+ cmFailed("Could not find dir: ", filename);
+ } else {
+ cmPassed("Find dir: ", filename);
+ }
+}
+
+// Here is a stupid function that tries to use std::string methods
+// so that the dec cxx compiler will instantiate the stuff that
+// we are using from the CMakeLib library....
+void ForceStringUse()
+{
+ std::vector<std::string> v;
+ std::vector<std::string> v2;
+ v = v2;
+ std::string cachetest = CACHE_TEST_VAR_INTERNAL;
+ v.push_back(cachetest);
+ v2 = v;
+ std::string x(5, 'x');
+ char buff[5];
+ x.copy(buff, 1, 0);
+ x[0] = 'a';
+ std::string::size_type pos = 0;
+ x.replace(pos, pos, pos, 'x');
+ std::string copy = cachetest;
+ cachetest.find("bar");
+ cachetest.rfind("bar");
+ copy.append(cachetest);
+ copy = cachetest.substr(0, cachetest.size());
+}
+
+// defined in testcflags.c
+extern "C" int TestCFlags(char* m);
+extern "C" int TestTargetCompileFlags(char* m);
+
+#if 0
+// defined in Sub1/NameConflictTest.c
+extern "C" int NameConflictTest1();
+// defined in Sub2/NameConflictTest.c
+extern "C" int NameConflictTest2();
+#endif
+
+// ======================================================================
+
+int main()
+{
+#if 0
+ if(NameConflictTest1() == 0 && NameConflictTest2() == 0)
+ {
+ cmPassed("Sub dir with same named source works");
+ }
+ else
+ {
+ cmFailed("Sub dir with same named source fails");
+ }
+#endif
+ if (file1() != 1) {
+ cmFailed("Call to file1 function from library failed.");
+ } else {
+ cmPassed("Call to file1 function returned 1.");
+ }
+#ifndef COMPLEX_TARGET_FLAG
+ cmFailed("COMPILE_FLAGS did not work with SET_TARGET_PROPERTIES");
+#else
+ cmPassed("COMPILE_FLAGS did work with SET_TARGET_PROPERTIES");
+#endif
+
+#ifdef ELSEIF_RESULT
+ cmPassed("ELSEIF did work");
+#else
+ cmFailed("ELSEIF did not work");
+#endif
+
+#ifdef CONDITIONAL_PARENTHESES
+ cmPassed("CONDITIONAL_PARENTHESES did work");
+#else
+ cmFailed("CONDITIONAL_PARENTHESES did not work");
+#endif
+
+ if (file2() != 1) {
+ cmFailed("Call to file2 function from library failed.");
+ } else {
+ cmPassed("Call to file2 function returned 1.");
+ }
+#ifndef TEST_CXX_FLAGS
+ cmFailed("CMake CMAKE_CXX_FLAGS is not being passed to the compiler!");
+#else
+ cmPassed("CMake CMAKE_CXX_FLAGS is being passed to the compiler.");
+#endif
+ std::string gen = CMAKE_GENERATOR;
+ // visual studio is currently broken for c flags
+ char msg[1024];
+ if (gen.find("Visual") == gen.npos) {
+#ifdef TEST_C_FLAGS
+ cmFailed(
+ "CMake CMAKE_C_FLAGS are being passed to c++ files the compiler!");
+#else
+ cmPassed("CMake CMAKE_C_FLAGS are not being passed to c++ files.");
+#endif
+ if (TestCFlags(msg)) {
+ cmPassed("CMake CMAKE_C_FLAGS are being passed to c files and CXX flags "
+ "are not.");
+ } else {
+ cmFailed(msg);
+ }
+ }
+ if (TestTargetCompileFlags(msg)) {
+ cmPassed(msg);
+ } else {
+ cmFailed(msg);
+ }
+
+ // ----------------------------------------------------------------------
+ // Test ADD_DEFINITIONS
+
+#ifndef CMAKE_IS_FUN
+ cmFailed("CMake is not fun, so it is broken and should be fixed.");
+#else
+ cmPassed("CMAKE_IS_FUN is defined.");
+#endif
+
+#if defined(CMAKE_ARGV1) && defined(CMAKE_ARGV2) && defined(CMAKE_ARGV3) && \
+ defined(CMAKE_ARGV4)
+ cmPassed("Variable args for MACROs are working.");
+#else
+ cmFailed("Variable args for MACROs are failing.");
+#endif
+
+// ----------------------------------------------------------------------
+// Test GET_SOURCE_FILE_PROPERTY for location
+#ifndef CMAKE_FOUND_ACXX
+ cmFailed("CMake did not get the location of A.cxx correctly");
+#else
+ cmPassed("CMake found A.cxx properly");
+#endif
+
+// ----------------------------------------------------------------------
+// Test GET_DIRECTORY_PROPERTY for parent
+#ifndef CMAKE_FOUND_PARENT
+ cmFailed("CMake did not get the location of the parent directory properly");
+#else
+ cmPassed("CMake found the parent directory properly");
+#endif
+
+// ----------------------------------------------------------------------
+// Test GET_DIRECTORY_PROPERTY for listfiles
+#ifndef CMAKE_FOUND_LISTFILE_STACK
+ cmFailed("CMake did not get the listfile stack properly");
+#else
+ cmPassed("CMake found the listfile stack properly");
+#endif
+
+ // ----------------------------------------------------------------------
+ // Test SET, VARIABLE_REQUIRES
+
+#ifdef SHOULD_NOT_BE_DEFINED
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED is defined.");
+#endif
+
+#ifndef ONE_VAR
+ cmFailed("cmakedefine is broken, ONE_VAR is not defined.");
+#else
+ cmPassed("ONE_VAR is defined.");
+#endif
+
+#ifndef ONE_VAR_AND_INDENTED
+ cmFailed("cmakedefine is broken, ONE_VAR_AND_INDENTED is not defined.");
+#else
+ cmPassed("ONE_VAR_AND_INDENTED is defined.");
+#endif
+
+#ifndef ONE_VAR_IS_DEFINED
+ cmFailed("cmakedefine, SET or VARIABLE_REQUIRES is broken, "
+ "ONE_VAR_IS_DEFINED is not defined.");
+#else
+ cmPassed("ONE_VAR_IS_DEFINED is defined.");
+#endif
+
+#ifdef ZERO_VAR
+ cmFailed("cmakedefine is broken, ZERO_VAR is defined.");
+#else
+ cmPassed("ZERO_VAR is not defined.");
+#endif
+
+#ifdef ZERO_VAR_AND_INDENTED
+ cmFailed("cmakedefine is broken, ZERO_VAR_AND_INDENTED is defined.");
+#else
+ cmPassed("ZERO_VAR_AND_INDENTED is not defined.");
+#endif
+
+#ifndef STRING_VAR
+ cmFailed("the CONFIGURE_FILE command is broken, STRING_VAR is not defined.");
+#else
+ if (strcmp(STRING_VAR, "CMake is great") != 0) {
+ cmFailed("the SET or CONFIGURE_FILE command is broken. STRING_VAR == ",
+ STRING_VAR);
+ } else {
+ cmPassed("STRING_VAR == ", STRING_VAR);
+ }
+#endif
+
+ // ----------------------------------------------------------------------
+ // Test various IF/ELSE combinations
+
+#ifdef SHOULD_NOT_BE_DEFINED_NOT
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_NOT is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_NOT is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_NOT
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_NOT is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_NOT is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_NOT2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_NOT2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_NOT2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_NOT2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_NOT2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_NOT2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_AND
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_AND is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_AND is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_AND
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_AND is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_AND is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_AND2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_AND2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_AND2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_AND2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_AND2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_AND2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_OR
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_OR is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_OR is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_OR
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_OR is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_OR is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_OR2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_OR2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_OR2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_OR2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_OR2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_OR2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_MATCHES
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_MATCHES is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_MATCHES is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_MATCHES
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_MATCHES is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_MATCHES is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_MATCHES2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_MATCHES2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_MATCHES2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_MATCHES2
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_MATCHES2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_MATCHES2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_COMMAND
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_COMMAND is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_COMMAND is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_COMMAND
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_COMMAND is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_COMMAND is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_COMMAND2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_COMMAND2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_COMMAND2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_COMMAND2
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_COMMAND2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_COMMAND2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_EXISTS
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_EXISTS is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_EXISTS is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_EXISTS
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_EXISTS is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_EXISTS is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_EXISTS2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_EXISTS2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_EXISTS2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_EXISTS2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_EXISTS2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_EXISTS2 is defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_IS_DIRECTORY
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_IS_DIRECTORY is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_IS_DIRECTORY is defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_IS_DIRECTORY2
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_IS_DIRECTORY2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_IS_DIRECTORY2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_LESS
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_LESS is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_LESS
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_LESS is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_LESS2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_LESS2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_LESS2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS2 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_LESS2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_GREATER
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_GREATER is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_GREATER
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_GREATER is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_GREATER2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_GREATER2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_EQUAL
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_EQUAL is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_EQUAL is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_EQUAL
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_EQUAL is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_EQUAL is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_LESS_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL2
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_LESS_EQUAL2
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL2 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL3
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_LESS_EQUAL3
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL3 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL3 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL2
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL2 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL3
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL3 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL3 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRLESS
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRLESS
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRLESS is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRLESS2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRLESS2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRLESS2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRGREATER
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRGREATER is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER2
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRGREATER2
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRGREATER2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL2
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL2 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL3
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL3 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL3 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is "
+ "defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is not "
+ "defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is "
+ "defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL3
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is not "
+ "defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is defined.");
+#endif
+
+ // ----------------------------------------------------------------------
+ // Test FOREACH
+
+#ifndef FOREACH_VAR1
+ cmFailed("the FOREACH, SET or CONFIGURE_FILE command is broken, "
+ "FOREACH_VAR1 is not defined.");
+#else
+ if (strcmp(FOREACH_VAR1, "VALUE1") != 0) {
+ cmFailed("the FOREACH, SET or CONFIGURE_FILE command is broken, "
+ "FOREACH_VAR1 == ",
+ FOREACH_VAR1);
+ } else {
+ cmPassed("FOREACH_VAR1 == ", FOREACH_VAR1);
+ }
+#endif
+
+#ifndef FOREACH_VAR2
+ cmFailed("the FOREACH, SET or CONFIGURE_FILE command is broken, "
+ "FOREACH_VAR2 is not defined.");
+#else
+ if (strcmp(FOREACH_VAR2, "VALUE2") != 0) {
+ cmFailed("the FOREACH, SET or CONFIGURE_FILE command is broken, "
+ "FOREACH_VAR2 == ",
+ FOREACH_VAR2);
+ } else {
+ cmPassed("FOREACH_VAR2 == ", FOREACH_VAR2);
+ }
+#endif
+
+#ifndef FOREACH_CONCAT
+ cmFailed("the FOREACH, SET or CONFIGURE_FILE command is broken, "
+ "FOREACH_CONCAT is not defined.");
+#else
+ if (strcmp(FOREACH_CONCAT, "abcdefg") != 0) {
+ cmFailed("the FOREACH, SET or CONFIGURE_FILE command is broken, "
+ "FOREACH_CONCAT == ",
+ FOREACH_CONCAT);
+ } else {
+ cmPassed("FOREACH_CONCAT == ", FOREACH_CONCAT);
+ }
+#endif
+
+ // ----------------------------------------------------------------------
+ // Test WHILE
+
+ if (WHILE_VALUE != 1000) {
+ cmFailed("WHILE command is not working");
+ } else {
+ cmPassed("WHILE command is working");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test LOAD_CACHE
+
+#ifndef CACHE_TEST_VAR1
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR1 is not defined.");
+#else
+ if (strcmp(CACHE_TEST_VAR1, "foo") != 0) {
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR1 == ",
+ CACHE_TEST_VAR1);
+ } else {
+ cmPassed("CACHE_TEST_VAR1 == ", CACHE_TEST_VAR1);
+ }
+#endif
+
+#ifndef CACHE_TEST_VAR2
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR2 is not defined.");
+#else
+ if (strcmp(CACHE_TEST_VAR2, "bar") != 0) {
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR2 == ",
+ CACHE_TEST_VAR2);
+ } else {
+ cmPassed("CACHE_TEST_VAR2 == ", CACHE_TEST_VAR2);
+ }
+#endif
+
+#ifndef CACHE_TEST_VAR3
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR3 is not defined.");
+#else
+ if (strcmp(CACHE_TEST_VAR3, "1") != 0) {
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR3 == ",
+ CACHE_TEST_VAR3);
+ } else {
+ cmPassed("CACHE_TEST_VAR3 == ", CACHE_TEST_VAR3);
+ }
+#endif
+
+#ifdef CACHE_TEST_VAR_EXCLUDED
+ cmFailed(
+ "the LOAD_CACHE or CONFIGURE_FILE command or cmakedefine is broken, "
+ "CACHE_TEST_VAR_EXCLUDED is defined (should not have been loaded).");
+#else
+ cmPassed("CACHE_TEST_VAR_EXCLUDED is not defined.");
+#endif
+
+#ifndef CACHE_TEST_VAR_INTERNAL
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR_INTERNAL is not defined.");
+#else
+ std::string cachetest = CACHE_TEST_VAR_INTERNAL;
+ if (cachetest != "bar") {
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR_INTERNAL == ",
+ CACHE_TEST_VAR_INTERNAL);
+ } else {
+ cmPassed("CACHE_TEST_VAR_INTERNAL == ", CACHE_TEST_VAR_INTERNAL);
+ }
+#endif
+
+ // ----------------------------------------------------------------------
+ // Some pre-build/pre-link/post-build custom-commands have been
+ // attached to the lib (see Library/).
+ // Each runs ${CREATE_FILE_EXE} which will create a file.
+ // It also copies that file again using cmake -E.
+ // Similar rules have been added to this executable.
+ //
+ // WARNING: if you run 'complex' manually, this *will* fail, because
+ // the file was removed the last time 'complex' was run, and it is
+ // only created during a build.
+
+ TestAndRemoveFile("Library/prebuild.txt");
+ TestAndRemoveFile("Library/prelink.txt");
+ TestAndRemoveFile("Library/postbuild.txt");
+ TestAndRemoveFile("Library/postbuild2.txt");
+ TestAndRemoveFile("Executable/prebuild.txt");
+ TestAndRemoveFile("Executable/prelink.txt");
+ TestAndRemoveFile("Executable/postbuild.txt");
+ TestAndRemoveFile("Executable/postbuild2.txt");
+
+ // ----------------------------------------------------------------------
+ // A custom target has been created (see Library/).
+ // It runs ${CREATE_FILE_EXE} which will create a file.
+ //
+ // WARNING: if you run 'complex' manually, this *will* fail, because
+ // the file was removed the last time 'complex' was run, and it is
+ // only created during a build.
+
+ TestAndRemoveFile("Library/custom_target1.txt");
+
+ // ----------------------------------------------------------------------
+ // A directory has been created.
+
+ TestDir("make_dir");
+
+ // ----------------------------------------------------------------------
+ // Test OUTPUT_REQUIRED_FILES
+ // The files required by 'complex' have been output to a file.
+ // The contents of this file is not tested (absolute paths).
+ //
+ // WARNING: if you run 'complex' manually, this *will* fail, because
+ // the file was removed the last time 'complex' was run, and it is
+ // only created during a build.
+
+ TestAndRemoveFile("Executable/Temp/complex-required.txt");
+
+ // ----------------------------------------------------------------------
+ // Test FIND_LIBRARY
+
+#ifndef FIND_DUMMY_LIB
+ cmFailed("the CONFIGURE_FILE command is broken, "
+ "FIND_DUMMY_LIB is not defined.");
+#else
+ if (strstr(FIND_DUMMY_LIB, "dummylib") == NULL) {
+ cmFailed("the FIND_LIBRARY or CONFIGURE_FILE command is broken, "
+ "FIND_DUMMY_LIB == ",
+ FIND_DUMMY_LIB);
+ } else {
+ cmPassed("FIND_DUMMY_LIB == ", FIND_DUMMY_LIB);
+ }
+#endif
+
+ // ----------------------------------------------------------------------
+ // Test SET_SOURCE_FILES_PROPERTIES
+
+#ifndef FILE_HAS_EXTRA_COMPILE_FLAGS
+ cmFailed("SET_SOURCE_FILES_PROPERTIES failed at setting "
+ "FILE_HAS_EXTRA_COMPILE_FLAGS flag");
+#else
+ cmPassed("SET_SOURCE_FILES_PROPERTIES succeeded in setting "
+ "FILE_HAS_EXTRA_COMPILE_FLAGS flag");
+#endif
+
+#if 0 // Disable until implemented everywhere.
+# ifndef FILE_DEFINE_STRING
+ cmFailed("SET_SOURCE_FILES_PROPERTIES failed at setting FILE_DEFINE_STRING flag");
+# else
+ if(strcmp(FILE_DEFINE_STRING, "hello") != 0)
+ {
+ cmFailed("SET_SOURCE_FILES_PROPERTIES failed at setting FILE_DEFINE_STRING flag correctly");
+ }
+ else
+ {
+ cmPassed("SET_SOURCE_FILES_PROPERTIES succeeded in setting FILE_DEFINE_STRING flag");
+ }
+# endif
+#endif
+
+#ifndef FILE_HAS_ABSTRACT
+ cmFailed("SET_SOURCE_FILES_PROPERTIES failed at setting ABSTRACT flag");
+#else
+ cmPassed("SET_SOURCE_FILES_PROPERTIES succeeded in setting ABSTRACT flag");
+#endif
+
+#ifndef FILE_HAS_WRAP_EXCLUDE
+ cmFailed("FILE_HAS_WRAP_EXCLUDE failed at setting WRAP_EXCLUDE flag");
+#else
+ cmPassed("FILE_HAS_WRAP_EXCLUDE succeeded in setting WRAP_EXCLUDE flag");
+#endif
+
+#ifndef FILE_COMPILE_FLAGS
+ cmFailed("the CONFIGURE_FILE command is broken, FILE_COMPILE_FLAGS is not "
+ "defined.");
+#else
+ if (strcmp(FILE_COMPILE_FLAGS, "-foo -bar") != 0) {
+ cmFailed("the SET_SOURCE_FILES_PROPERTIES or CONFIGURE_FILE command is "
+ "broken. FILE_COMPILE_FLAGS == ",
+ FILE_COMPILE_FLAGS);
+ } else {
+ cmPassed(
+ "SET_SOURCE_FILES_PROPERTIES succeeded in setting extra flags == ",
+ FILE_COMPILE_FLAGS);
+ }
+#endif
+
+// ----------------------------------------------------------------------
+// Test registry (win32)
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# ifndef REGISTRY_TEST_PATH
+ cmFailed("the CONFIGURE_FILE command is broken, REGISTRY_TEST_PATH is not "
+ "defined.");
+# else
+ std::cout << "REGISTRY_TEST_PATH == " << REGISTRY_TEST_PATH << "\n";
+ if (stricmp(REGISTRY_TEST_PATH, BINARY_DIR "/registry_dir") != 0) {
+ cmFailed("the 'read registry value' function or CONFIGURE_FILE command is "
+ "broken. REGISTRY_TEST_PATH == ",
+ REGISTRY_TEST_PATH, " is not " BINARY_DIR "/registry_dir");
+ } else {
+ cmPassed("REGISTRY_TEST_PATH == ", REGISTRY_TEST_PATH);
+ }
+# endif
+#endif // defined(_WIN32) && !defined(__CYGWIN__)
+
+ if (strcmp(CMAKE_MINIMUM_REQUIRED_VERSION, "2.4") == 0) {
+ cmPassed("CMAKE_MINIMUM_REQUIRED_VERSION is set to 2.4");
+ } else {
+ cmFailed("CMAKE_MINIMUM_REQUIRED_VERSION is not set to the expected 2.4");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test REMOVE command
+ if (strcmp("a;b;d", REMOVE_STRING) == 0) {
+ cmPassed("REMOVE is working");
+ } else {
+ cmFailed("REMOVE is not working");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test SEPARATE_ARGUMENTS
+ if (strcmp("a;b;c", TEST_SEP) == 0) {
+ cmPassed("SEPARATE_ARGUMENTS is working");
+ } else {
+ cmFailed("SEPARATE_ARGUMENTS is not working");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test Escape Quotes
+ if (strcmp("\"hello world\"", STRING_WITH_QUOTES) == 0) {
+ cmPassed("ESCAPE_QUOTES is working");
+ } else {
+ cmFailed("ESCAPE_QUOTES is not working");
+ }
+
+// ----------------------------------------------------------------------
+// Test if IF command inside a FOREACH works.
+#if defined(IF_INSIDE_FOREACH_THEN_EXECUTED) && \
+ !defined(IF_INSIDE_FOREACH_ELSE_EXECUTED)
+ cmPassed("IF inside a FOREACH block works");
+#else
+ cmFailed("IF inside a FOREACH block is broken");
+#endif
+
+#if defined(GENERATED_HEADER_INCLUDED)
+ cmPassed("Generated header included by non-generated source works.");
+#else
+ cmFailed("Generated header included by non-generated source failed.");
+#endif
+ if (SHOULD_BE_ZERO == 0) {
+ cmPassed("cmakedefine01 is working for 0");
+ } else {
+ cmFailed("cmakedefine01 is not working for 0");
+ }
+ if (SHOULD_BE_ONE == 1) {
+ cmPassed("cmakedefine01 is working for 1");
+ } else {
+ cmFailed("cmakedefine01 is not working for 1");
+ }
+ if (SHOULD_BE_ZERO_AND_INDENTED == 0) {
+ cmPassed("cmakedefine01 is working for 0 and indented");
+ } else {
+ cmFailed("cmakedefine01 is not working for 0 and indented");
+ }
+ if (SHOULD_BE_ONE_AND_INDENTED == 1) {
+ cmPassed("cmakedefine01 is working for 1 and indented");
+ } else {
+ cmFailed("cmakedefine01 is not working for 1 and indented");
+ }
+#ifdef FORCE_TEST
+ cmFailed("CMake SET CACHE FORCE");
+#else
+ cmPassed("CMake SET CACHE FORCE");
+#endif
+
+#ifdef COMPLEX_TEST_LINK_STATIC
+ if (TestLinkGetType()) {
+ cmPassed("Link to static over shared worked.");
+ } else {
+ cmFailed("Link to static over shared failed.");
+ }
+#endif
+
+#if defined(A_VALUE) && A_VALUE == 10
+ cmPassed("Single-character executable A worked.");
+#else
+ cmFailed("Single-character executable A failed.");
+#endif
+
+ // ----------------------------------------------------------------------
+ // Summary
+
+ std::cout << "Passed: " << cm_passed << "\n";
+ if (cm_failed) {
+ std::cout << "Failed: " << cm_failed << "\n";
+ return cm_failed;
+ }
+ return 0;
+}
diff --git a/Tests/Complex/Executable/complex.file.cxx b/Tests/Complex/Executable/complex.file.cxx
new file mode 100644
index 0000000..5596430
--- /dev/null
+++ b/Tests/Complex/Executable/complex.file.cxx
@@ -0,0 +1,8 @@
+#if 0
+# include "cmMissingHeader.h"
+#endif
+
+int main(int, char**)
+{
+ return 0;
+}
diff --git a/Tests/Complex/Executable/complex_nobuild.c b/Tests/Complex/Executable/complex_nobuild.c
new file mode 100644
index 0000000..6b3c2c1
--- /dev/null
+++ b/Tests/Complex/Executable/complex_nobuild.c
@@ -0,0 +1 @@
+#error "This file should not be compiled."
diff --git a/Tests/Complex/Executable/complex_nobuild.cxx b/Tests/Complex/Executable/complex_nobuild.cxx
new file mode 100644
index 0000000..6b3c2c1
--- /dev/null
+++ b/Tests/Complex/Executable/complex_nobuild.cxx
@@ -0,0 +1 @@
+#error "This file should not be compiled."
diff --git a/Tests/Complex/Executable/notInAllExe.cxx b/Tests/Complex/Executable/notInAllExe.cxx
new file mode 100644
index 0000000..2b857b4
--- /dev/null
+++ b/Tests/Complex/Executable/notInAllExe.cxx
@@ -0,0 +1,10 @@
+extern int notInAllLibFunc();
+
+int main()
+{
+ return notInAllLibFunc();
+}
+
+#if 1
+# error "This target should not be compiled by ALL."
+#endif
diff --git a/Tests/Complex/Executable/testSystemDir.cxx b/Tests/Complex/Executable/testSystemDir.cxx
new file mode 100644
index 0000000..4bb2db4
--- /dev/null
+++ b/Tests/Complex/Executable/testSystemDir.cxx
@@ -0,0 +1,6 @@
+#include <testSystemDir.h>
+
+int main()
+{
+ return foo();
+}
diff --git a/Tests/Complex/Executable/testcflags.c b/Tests/Complex/Executable/testcflags.c
new file mode 100644
index 0000000..e452b06
--- /dev/null
+++ b/Tests/Complex/Executable/testcflags.c
@@ -0,0 +1,26 @@
+#include <string.h>
+
+int TestTargetCompileFlags(char* m)
+{
+#ifndef COMPLEX_TARGET_FLAG
+ strcpy(m, "CMAKE SET_TARGET_PROPERTIES COMPILE_FLAGS did not work");
+ return 0;
+#endif
+ strcpy(m, "CMAKE SET_TARGET_PROPERTIES COMPILE_FLAGS worked");
+ return 1;
+}
+
+int TestCFlags(char* m)
+{
+/* TEST_CXX_FLAGS should not be defined in a c file */
+#ifdef TEST_CXX_FLAGS
+ strcpy(m, "CMake CMAKE_CXX_FLAGS (TEST_CXX_FLAGS) found in c file.");
+ return 0;
+#endif
+/* TEST_C_FLAGS should be defined in a c file */
+#ifndef TEST_C_FLAGS
+ strcpy(m, "CMake CMAKE_C_FLAGS (TEST_C_FLAGS) not found in c file.");
+ return 0;
+#endif
+ return 1;
+}
diff --git a/Tests/Complex/Library/CMakeLists.txt b/Tests/Complex/Library/CMakeLists.txt
new file mode 100644
index 0000000..df874ef
--- /dev/null
+++ b/Tests/Complex/Library/CMakeLists.txt
@@ -0,0 +1,140 @@
+remove_definitions(-DCMAKE_IS_REALLY_FUN)
+
+#
+# Small utility used to create file
+# UTILITY_SOURCE is used for coverage and for getting the exact name
+# of the executable.
+#
+utility_source(CREATE_FILE_EXE create_file "." create_file.cxx)
+add_executable(create_file create_file.cxx)
+set_target_properties(create_file PROPERTIES RUNTIME_OUTPUT_DIRECTORY ".")
+
+#
+# Create static library
+# SOURCE_FILES_REMOVE is used for Coverage. empty.h is included for coverage
+#
+aux_source_directory(ExtraSources LibrarySources)
+set(LibrarySources ${LibrarySources}
+ file2
+ empty
+ create_file.cxx
+ GENERATED
+ nonexisting_file)
+remove(LibrarySources create_file.cxx GENERATED nonexisting_file)
+add_library(CMakeTestLibrary ${LibrarySources})
+
+if(WIN32)
+ if(NOT CYGWIN)
+ if(NOT BORLAND)
+ if(NOT MINGW)
+ target_link_libraries(CMakeTestLibrary
+ debug
+ user32.lib)
+ target_link_libraries(CMakeTestLibrary
+ optimized
+ kernel32.lib)
+ endif()
+ endif()
+ endif()
+endif()
+
+#
+# Create shared library
+#
+set(SharedLibrarySources sharedFile)
+add_library(CMakeTestLibraryShared SHARED ${SharedLibrarySources})
+string(APPEND CMAKE_C_FLAGS " -DTEST_C_FLAGS")
+add_library(CMakeTestCLibraryShared SHARED testConly.c)
+define_property(
+ TARGET PROPERTY FOO
+ BRIEF_DOCS "a test property"
+ FULL_DOCS "A simple test property that means nothing and is used for nothing"
+ )
+set_target_properties(CMakeTestCLibraryShared PROPERTIES FOO BAR)
+if(NOT BEOS AND NOT WIN32 AND NOT HAIKU) # No libm on BeOS.
+ set_target_properties(CMakeTestCLibraryShared PROPERTIES LINK_FLAGS "-lm")
+endif()
+get_target_property(FOO_BAR_VAR CMakeTestCLibraryShared FOO)
+if(${FOO_BAR_VAR} MATCHES "BAR")
+else()
+ message(SEND_ERROR "SET_TARGET_PROPERTIES or GET_TARGET_PROPERTY failed, FOO_BAR_VAR should be BAR, but is ${FOO_BAR_VAR}")
+endif()
+
+# Create static and shared lib of same name.
+if(CMAKE_EXE_LINK_STATIC_CXX_FLAGS)
+ add_library(CMakeTestLinkStatic STATIC TestLink.c)
+ add_library(CMakeTestLinkShared SHARED TestLink.c)
+ set_target_properties(CMakeTestLinkStatic CMakeTestLinkShared
+ PROPERTIES OUTPUT_NAME CMakeTestLink)
+endif()
+
+#
+# Attach pre-build/pre-link/post-build custom-commands to the lib.
+# Each runs ${CREATE_FILE_EXE} which will create a file.
+# The 'complex' executable will then test if this file exists and remove it.
+#
+add_dependencies(CMakeTestLibraryShared create_file)
+message("complex bin dir is ${Complex_BINARY_DIR}")
+add_custom_command(TARGET CMakeTestLibraryShared PRE_BUILD
+ COMMAND ${CREATE_FILE_EXE}
+ ARGS "${Complex_BINARY_DIR}/Library/prebuild.txt")
+add_custom_command(TARGET CMakeTestLibraryShared PRE_BUILD
+ COMMAND ${CREATE_FILE_EXE}
+ ARGS "${Complex_BINARY_DIR}/Library/prelink.txt")
+add_custom_command(TARGET CMakeTestLibraryShared POST_BUILD
+ COMMAND ${CREATE_FILE_EXE}
+ ARGS "${Complex_BINARY_DIR}/Library/postbuild.txt")
+add_custom_command(TARGET CMakeTestLibraryShared POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy
+ "${Complex_BINARY_DIR}/Library/postbuild.txt"
+ "${Complex_BINARY_DIR}/Library/postbuild2.txt")
+
+#
+# Add a custom target.
+# It runs ${CREATE_FILE_EXE} which will create a file.
+# The 'complex' executable will then test if this file exists and remove it.
+#
+add_custom_target(custom_target1
+ ALL
+ ${CREATE_FILE_EXE}
+ "${Complex_BINARY_DIR}/Library/custom_target1.txt")
+
+add_dependencies(custom_target1 create_file)
+
+#
+# Extra coverage
+#
+set_source_files_properties(file2 PROPERTIES ABSTRACT 1)
+
+install_files(/tmp .h ${Complex_BINARY_DIR}/cmTestConfigure.h)
+install_files(/tmp .cxx ${Complex_BINARY_DIR}/cmTestConfigure.h)
+
+# Test creating a library that is not built by default.
+add_library(notInAllLib EXCLUDE_FROM_ALL notInAllLib.cxx)
+
+# Create an imported target for if(TARGET) test in Executable dir.
+# That test should not see this target.
+add_library(LibImportedTarget UNKNOWN IMPORTED)
+
+# Test generation of preprocessed sources.
+if("${CMAKE_GENERATOR}" MATCHES "Makefile" AND CMAKE_MAKE_PROGRAM)
+ if(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE)
+ # Skip running this part of the test on certain platforms
+ # until they are fixed.
+ set(MAYBE_ALL ALL)
+ list(LENGTH CMAKE_OSX_ARCHITECTURES ARCH_COUNT)
+ if(ARCH_COUNT GREATER 1)
+ # OSX does not support preprocessing more than one architecture.
+ set(MAYBE_ALL)
+ endif()
+
+ # Custom target to try preprocessing invocation.
+ add_custom_target(test_preprocess ${MAYBE_ALL}
+ COMMAND ${CMAKE_COMMAND} -E rm -f CMakeFiles/create_file.dir/create_file.i
+ COMMAND ${CMAKE_MAKE_PROGRAM} create_file.i
+ COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/test_preprocess.cmake
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ )
+ endif()
+endif()
diff --git a/Tests/Complex/Library/ExtraSources/file1.cxx b/Tests/Complex/Library/ExtraSources/file1.cxx
new file mode 100644
index 0000000..e22812e
--- /dev/null
+++ b/Tests/Complex/Library/ExtraSources/file1.cxx
@@ -0,0 +1,4 @@
+int file1()
+{
+ return 1;
+}
diff --git a/Tests/Complex/Library/ExtraSources/file1.h b/Tests/Complex/Library/ExtraSources/file1.h
new file mode 100644
index 0000000..ce0d818
--- /dev/null
+++ b/Tests/Complex/Library/ExtraSources/file1.h
@@ -0,0 +1 @@
+int file1();
diff --git a/Tests/Complex/Library/SystemDir/testSystemDir.h b/Tests/Complex/Library/SystemDir/testSystemDir.h
new file mode 100644
index 0000000..074ff75
--- /dev/null
+++ b/Tests/Complex/Library/SystemDir/testSystemDir.h
@@ -0,0 +1,5 @@
+// Purposely leave off the return type to create a warning.
+foo()
+{
+ return 0;
+}
diff --git a/Tests/Complex/Library/TestLink.c b/Tests/Complex/Library/TestLink.c
new file mode 100644
index 0000000..25dee08
--- /dev/null
+++ b/Tests/Complex/Library/TestLink.c
@@ -0,0 +1,8 @@
+int TestLinkGetType()
+{
+#ifdef CMakeTestLinkShared_EXPORTS
+ return 0;
+#else
+ return 1;
+#endif
+}
diff --git a/Tests/Complex/Library/create_file.cxx b/Tests/Complex/Library/create_file.cxx
new file mode 100644
index 0000000..62a1975
--- /dev/null
+++ b/Tests/Complex/Library/create_file.cxx
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "Missing name of file to create.\n");
+ return EXIT_FAILURE;
+ }
+
+ FILE* stream = fopen(argv[1], "w");
+ if (stream == NULL) {
+ fprintf(stderr, "Unable to open %s for writing!\n", argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ if (fclose(stream)) {
+ fprintf(stderr, "Unable to close %s!\n", argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ fprintf(stdout, ">> Creating %s!\n", argv[1]);
+
+ return EXIT_SUCCESS;
+}
diff --git a/Tests/Complex/Library/dummy b/Tests/Complex/Library/dummy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/Complex/Library/dummy
diff --git a/Tests/Complex/Library/empty.h b/Tests/Complex/Library/empty.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/Complex/Library/empty.h
diff --git a/Tests/Complex/Library/file2.cxx b/Tests/Complex/Library/file2.cxx
new file mode 100644
index 0000000..863fcaa
--- /dev/null
+++ b/Tests/Complex/Library/file2.cxx
@@ -0,0 +1,10 @@
+#include <string.h>
+
+#ifdef CMAKE_IS_REALLY_FUN
+This is a problem. Looks like REMOVE_DEFINITION does not work
+#endif
+
+int file2()
+{
+ return 1;
+}
diff --git a/Tests/Complex/Library/file2.h b/Tests/Complex/Library/file2.h
new file mode 100644
index 0000000..dea4b80
--- /dev/null
+++ b/Tests/Complex/Library/file2.h
@@ -0,0 +1 @@
+int file2();
diff --git a/Tests/Complex/Library/notInAllLib.cxx b/Tests/Complex/Library/notInAllLib.cxx
new file mode 100644
index 0000000..033988f
--- /dev/null
+++ b/Tests/Complex/Library/notInAllLib.cxx
@@ -0,0 +1,8 @@
+int notInAllLibFunc()
+{
+ return 0;
+}
+
+#if 1
+# error "This target should not be compiled by ALL."
+#endif
diff --git a/Tests/Complex/Library/sharedFile.cxx b/Tests/Complex/Library/sharedFile.cxx
new file mode 100644
index 0000000..cafac68
--- /dev/null
+++ b/Tests/Complex/Library/sharedFile.cxx
@@ -0,0 +1,6 @@
+#include "sharedFile.h"
+
+int sharedFunction()
+{
+ return 1;
+}
diff --git a/Tests/Complex/Library/sharedFile.h b/Tests/Complex/Library/sharedFile.h
new file mode 100644
index 0000000..830cbd5
--- /dev/null
+++ b/Tests/Complex/Library/sharedFile.h
@@ -0,0 +1,12 @@
+#if defined(_WIN32) || defined(WIN32) /* Win32 version */
+# ifdef CMakeTestLibraryShared_EXPORTS
+# define CMakeTest_EXPORT __declspec(dllexport)
+# else
+# define CMakeTest_EXPORT __declspec(dllimport)
+# endif
+#else
+/* unix needs nothing */
+# define CMakeTest_EXPORT
+#endif
+
+CMakeTest_EXPORT int sharedFunction();
diff --git a/Tests/Complex/Library/testConly.c b/Tests/Complex/Library/testConly.c
new file mode 100644
index 0000000..eb933a2
--- /dev/null
+++ b/Tests/Complex/Library/testConly.c
@@ -0,0 +1,14 @@
+#include "testConly.h"
+
+#include <stdio.h>
+
+int CsharedFunction()
+{
+#ifndef TEST_C_FLAGS
+ printf("TEST_C_FLAGS failed\n");
+ return 0;
+#else
+ printf("Passed: TEST_C_FLAGS passed\n");
+#endif
+ return 1;
+}
diff --git a/Tests/Complex/Library/testConly.h b/Tests/Complex/Library/testConly.h
new file mode 100644
index 0000000..02b28cc
--- /dev/null
+++ b/Tests/Complex/Library/testConly.h
@@ -0,0 +1,12 @@
+#if defined(_WIN32) || defined(WIN32) /* Win32 version */
+# ifdef CMakeTestCLibraryShared_EXPORTS
+# define CMakeTest_EXPORT __declspec(dllexport)
+# else
+# define CMakeTest_EXPORT __declspec(dllimport)
+# endif
+#else
+/* unix needs nothing */
+# define CMakeTest_EXPORT
+#endif
+
+CMakeTest_EXPORT int CsharedFunction();
diff --git a/Tests/Complex/Library/test_preprocess.cmake b/Tests/Complex/Library/test_preprocess.cmake
new file mode 100644
index 0000000..4c8ec21
--- /dev/null
+++ b/Tests/Complex/Library/test_preprocess.cmake
@@ -0,0 +1,7 @@
+set(TEST_FILE CMakeFiles/create_file.dir/create_file.i)
+file(READ ${TEST_FILE} CONTENTS)
+if("${CONTENTS}" MATCHES "Unable to close")
+ message(STATUS "${TEST_FILE} created successfully!")
+else()
+ message(FATAL_ERROR "${TEST_FILE} creation failed!")
+endif()
diff --git a/Tests/Complex/VarTests.cmake b/Tests/Complex/VarTests.cmake
new file mode 100644
index 0000000..9761986
--- /dev/null
+++ b/Tests/Complex/VarTests.cmake
@@ -0,0 +1,258 @@
+#
+# Test SET
+#
+set (ZERO_VAR 0)
+set (ZERO_VAR_AND_INDENTED 0)
+set (ZERO_VAR2 0)
+
+if(ZERO_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED)
+else()
+ add_definitions(-DSHOULD_BE_DEFINED)
+endif()
+
+set(ONE_VAR 1)
+set(ONE_VAR_AND_INDENTED 1)
+set(ONE_VAR2 1)
+set(STRING_VAR "CMake is great" CACHE STRING "test a cache variable")
+
+#
+# Test VARIABLE_REQUIRES
+#
+variable_requires(ONE_VAR
+ ONE_VAR_IS_DEFINED ONE_VAR)
+
+#
+# Test various IF/ELSE combinations
+#
+if(NOT ZERO_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_NOT)
+else()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_NOT)
+endif()
+
+if(NOT ONE_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_NOT2)
+else()
+ add_definitions(-DSHOULD_BE_DEFINED_NOT2)
+endif()
+
+if(ONE_VAR AND ONE_VAR2)
+ add_definitions(-DSHOULD_BE_DEFINED_AND)
+else()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_AND)
+endif()
+
+if(ONE_VAR AND ZERO_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_AND2)
+else()
+ add_definitions(-DSHOULD_BE_DEFINED_AND2)
+endif()
+
+if(ZERO_VAR OR ONE_VAR2)
+ add_definitions(-DSHOULD_BE_DEFINED_OR)
+else()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_OR)
+endif()
+
+if(ZERO_VAR OR ZERO_VAR2)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_OR2)
+else()
+ add_definitions(-DSHOULD_BE_DEFINED_OR2)
+endif()
+
+if(STRING_VAR MATCHES "^CMake")
+ add_definitions(-DSHOULD_BE_DEFINED_MATCHES)
+else()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_MATCHES)
+endif()
+
+if(STRING_VAR MATCHES "^foo")
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_MATCHES2)
+else()
+ add_definitions(-DSHOULD_BE_DEFINED_MATCHES2)
+endif()
+
+if(COMMAND "IF")
+ add_definitions(-DSHOULD_BE_DEFINED_COMMAND)
+else()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_COMMAND)
+endif()
+
+if(COMMAND "ROQUEFORT")
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_COMMAND2)
+else()
+ add_definitions(-DSHOULD_BE_DEFINED_COMMAND2)
+endif()
+
+if (EXISTS ${Complex_SOURCE_DIR}/VarTests.cmake)
+ add_definitions(-DSHOULD_BE_DEFINED_EXISTS)
+else()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_EXISTS)
+endif ()
+
+if (EXISTS ${Complex_SOURCE_DIR}/roquefort.txt)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_EXISTS2)
+else()
+ add_definitions(-DSHOULD_BE_DEFINED_EXISTS2)
+endif ()
+
+if (IS_DIRECTORY ${Complex_SOURCE_DIR})
+ add_definitions(-DSHOULD_BE_DEFINED_IS_DIRECTORY)
+endif ()
+
+if (NOT IS_DIRECTORY ${Complex_SOURCE_DIR}/VarTests.cmake)
+ add_definitions(-DSHOULD_BE_DEFINED_IS_DIRECTORY2)
+endif ()
+
+set (SNUM1_VAR "1")
+set (SNUM2_VAR "2")
+set (SNUM3_VAR "1")
+
+
+if (SNUM1_VAR LESS SNUM2_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_LESS)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS)
+endif ()
+
+if (SNUM2_VAR LESS SNUM1_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_LESS2)
+endif ()
+
+if (SNUM2_VAR GREATER SNUM1_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_GREATER)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER)
+endif ()
+
+if (SNUM1_VAR GREATER SNUM2_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_GREATER2)
+endif ()
+
+if (SNUM2_VAR EQUAL SNUM1_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_EQUAL)
+endif ()
+
+if (SNUM3_VAR EQUAL SNUM1_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_EQUAL)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL)
+endif ()
+
+if (SNUM1_VAR LESS_EQUAL SNUM2_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL)
+endif ()
+
+if (SNUM2_VAR LESS_EQUAL SNUM1_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL2)
+endif ()
+
+if (SNUM1_VAR LESS_EQUAL SNUM3_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3)
+endif ()
+
+if (SNUM2_VAR GREATER_EQUAL SNUM1_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL)
+endif ()
+
+if (SNUM1_VAR GREATER_EQUAL SNUM2_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL2)
+endif ()
+
+if (SNUM1_VAR GREATER_EQUAL SNUM3_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL3)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL3)
+endif ()
+
+set (SSTR1_VAR "abc")
+set (SSTR2_VAR "bcd")
+
+if (SSTR1_VAR STRLESS SSTR2_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_STRLESS)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS)
+endif ()
+
+if (SSTR2_VAR STRLESS SSTR1_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_STRLESS2)
+endif ()
+
+if (SSTR2_VAR STRGREATER SSTR1_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_STRGREATER)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER)
+endif ()
+
+if (SSTR1_VAR STRGREATER SSTR2_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_STRGREATER2)
+endif ()
+
+if (SSTR1_VAR STRLESS_EQUAL SSTR2_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL)
+endif ()
+
+if (SSTR2_VAR STRLESS_EQUAL SSTR1_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL2)
+endif ()
+
+if (SSTR1_VAR STRLESS_EQUAL SSTR1_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL3)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3)
+endif ()
+
+if (SSTR2_VAR STRGREATER_EQUAL SSTR1_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL)
+endif ()
+
+if (SSTR1_VAR STRGREATER_EQUAL SSTR2_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL2)
+endif ()
+
+if (SSTR1_VAR STRGREATER_EQUAL SSTR1_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL3)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3)
+endif ()
+
+#
+# Test FOREACH
+#
+foreach (INDEX 1 2)
+ set(FOREACH_VAR${INDEX} "VALUE${INDEX}")
+endforeach()
+
+set(FOREACH_CONCAT "")
+foreach (INDEX a;b;c;d;e;f;g)
+ string(APPEND FOREACH_CONCAT "${INDEX}")
+endforeach()
diff --git a/Tests/Complex/cmTestConfigure.h.in b/Tests/Complex/cmTestConfigure.h.in
new file mode 100644
index 0000000..72317bc
--- /dev/null
+++ b/Tests/Complex/cmTestConfigure.h.in
@@ -0,0 +1,80 @@
+// Test SET, VARIABLE_REQUIRES
+
+#cmakedefine ONE_VAR
+# cmakedefine ONE_VAR_AND_INDENTED
+#cmakedefine ONE_VAR_IS_DEFINED
+#cmakedefine ZERO_VAR
+# cmakedefine ZERO_VAR_AND_INDENTED
+
+#define STRING_VAR "${STRING_VAR}"
+
+// Test FOREACH
+
+#define FOREACH_VAR1 "${FOREACH_VAR1}"
+#define FOREACH_VAR2 "${FOREACH_VAR2}"
+#define FOREACH_CONCAT "${FOREACH_CONCAT}"
+
+// Test WHILE
+#define WHILE_VALUE ${while_var}
+
+// Test LOAD_CACHE
+
+#define CACHE_TEST_VAR1 "${CACHE_TEST_VAR1}"
+#define CACHE_TEST_VAR2 "${CACHE_TEST_VAR2}"
+#define CACHE_TEST_VAR3 "${CACHE_TEST_VAR3}"
+#cmakedefine CACHE_TEST_VAR_EXCLUDED
+#define CACHE_TEST_VAR_INTERNAL "${CACHE_TEST_VAR_INTERNAL}"
+
+// Test internal CMake vars from C++ flags
+
+#cmakedefine CMAKE_NO_STD_NAMESPACE
+#cmakedefine CMAKE_NO_ANSI_STREAM_HEADERS
+#cmakedefine CMAKE_NO_ANSI_STRING_STREAM
+#cmakedefine CMAKE_NO_ANSI_FOR_SCOPE
+
+#cmakedefine01 SHOULD_BE_ZERO
+#cmakedefine01 SHOULD_BE_ONE
+# cmakedefine01 SHOULD_BE_ZERO_AND_INDENTED
+# cmakedefine01 SHOULD_BE_ONE_AND_INDENTED
+// Needed to check for files
+
+#define BINARY_DIR "${Complex_BINARY_DIR}"
+
+// Test FIND_LIBRARY
+
+#define FIND_DUMMY_LIB "${FIND_DUMMY_LIB}"
+
+// Test SET_SOURCE_FILES_PROPERTIES
+
+#cmakedefine FILE_HAS_ABSTRACT
+#cmakedefine FILE_HAS_WRAP_EXCLUDE
+#define FILE_COMPILE_FLAGS "${FILE_COMPILE_FLAGS}"
+
+#define TEST_SEP "${TEST_SEP}"
+
+// Test registry read
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#define REGISTRY_TEST_PATH "${REGISTRY_TEST_PATH}"
+#endif
+
+// Test Remove command
+#define REMOVE_STRING "${REMOVE_STRING}"
+
+// Test IF inside FOREACH
+#cmakedefine IF_INSIDE_FOREACH_THEN_EXECUTED
+#cmakedefine IF_INSIDE_FOREACH_ELSE_EXECUTED
+
+// Test SET CACHE FORCE
+#cmakedefine FORCE_TEST
+#define CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+
+#define CMAKE_SHARED_MODULE_PREFIX "${CMAKE_SHARED_MODULE_PREFIX}"
+#define CMAKE_SHARED_MODULE_SUFFIX "${CMAKE_SHARED_MODULE_SUFFIX}"
+
+// test elseif
+#cmakedefine ELSEIF_RESULT
+
+// test parenthesis in conditionals
+#cmakedefine CONDITIONAL_PARENTHESES
+
diff --git a/Tests/Complex/cmTestConfigureEscape.h.in b/Tests/Complex/cmTestConfigureEscape.h.in
new file mode 100644
index 0000000..39a8bd6
--- /dev/null
+++ b/Tests/Complex/cmTestConfigureEscape.h.in
@@ -0,0 +1 @@
+#define STRING_WITH_QUOTES "${STRING_WITH_QUOTES}"
diff --git a/Tests/Complex/cmTestGeneratedHeader.h.in b/Tests/Complex/cmTestGeneratedHeader.h.in
new file mode 100644
index 0000000..0e9dd3f
--- /dev/null
+++ b/Tests/Complex/cmTestGeneratedHeader.h.in
@@ -0,0 +1 @@
+#define GENERATED_HEADER_INCLUDED
diff --git a/Tests/ComplexOneConfig/CMakeLists.txt b/Tests/ComplexOneConfig/CMakeLists.txt
new file mode 100644
index 0000000..28b73af
--- /dev/null
+++ b/Tests/ComplexOneConfig/CMakeLists.txt
@@ -0,0 +1,413 @@
+#
+# A more complex test case
+#
+cmake_minimum_required(VERSION 2.4)
+cmake_policy(SET CMP0054 NEW)
+project (Complex)
+
+# Try setting a new policy. The IF test is for coverage.
+if(POLICY CMP0003)
+ cmake_policy(SET CMP0003 NEW)
+
+ cmake_policy(GET CMP0003 P3)
+ if(NOT "${P3}" STREQUAL "NEW")
+ message(FATAL_ERROR "cmake_policy(GET) did not report NEW!")
+ endif()
+endif()
+
+# It is not recommended to set a policy to OLD, but this test
+# covers the OLD behavior of some policies.
+foreach(p
+ CMP0029
+ CMP0032
+ CMP0033
+ CMP0034
+ CMP0043
+ CMP0050
+ )
+ if(POLICY ${p})
+ cmake_policy(SET ${p} OLD)
+ endif()
+endforeach()
+
+# Test building without per-rule echo lines in Makefiles.
+set_property(GLOBAL PROPERTY RULE_MESSAGES OFF)
+
+set(CPACK_SOURCE_IGNORE_FILES "~$;^C:/hoffman/My Builds/testcase.*/CVS/;^C:/hoffman/My Builds/testcase.*/\\.svn/;^C:/hoffman/My Builds/testcase.*/sweigart/;^C:/hoffman/My Builds/testcase/www/eospaper/solution/eos2001/;^C:/hoffman/My Builds/testcase/www/eospaper/solution/opal_tables_new/;^C:/hoffman/My Builds/testcase/COPYING$;^C:/hoffman/My Builds/testcase/INSTALL$;^C:/hoffman/My Builds/testcase/Makefile$;^C:/hoffman/My Builds/testcase/Makefile\\.in$;^C:/hoffman/My Builds/testcase/.*\\.lo$;^C:/hoffman/My Builds/testcase/.*\\.la$;^C:/hoffman/My Builds/testcase/mkinstalldirs$;^C:/hoffman/My Builds/testcase/missing$;^C:/hoffman/My Builds/testcase/ltmain\\.sh$;^C:/hoffman/My Builds/testcase/libtool$;^C:/hoffman/My Builds/testcase/install-sh$;^C:/hoffman/My Builds/testcase/configure$;^C:/hoffman/My Builds/testcase/config\\.sub$;^C:/hoffman/My Builds/testcase/config\\.status$;^C:/hoffman/My Builds/testcase/config\\.log$;^C:/hoffman/My Builds/testcase/config\\.guess$;^C:/hoffman/My Builds/testcase/autom4te\\.cache$;^C:/hoffman/My Builds/testcase/aclocal\\.m4$;^C:/hoffman/My Builds/testcase/depcomp$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.075\\.model_cassisi_eos1_10$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.075\\.model_cassisi_eos1_10_corr$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.1\\.model_cassisi_eos1$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.1\\.model_cassisi_scvh$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.1\\.modelc$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.3\\.modelc$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/1\\.0\\.modelc$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/1\\.0\\.rgbtip\\.modelc$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/1\\.0\\.zahb\\.modelc$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.1\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/1\\.0\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.3\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/0\\.085\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/.*\\.ps$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange\\.mem$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange\\.log$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange\\.dvi$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange\\.tex\\.bak$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/head\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/body\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/prior-dvi\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j10\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j12\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j16\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j20\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j22\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j26\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j30\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j32\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/j36\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/k10\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/k12\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/k20\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/k22\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/k30\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/k32\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/1_exchange_dgamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/1_exchange_dlnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/2_exchange_dgamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/2_exchange_dlnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/linear_exchange_dgamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/linear_exchange_dlnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/noexchange_dgamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/noexchange_dlnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/nr_exchange_dgamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/nr_exchange_dlnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/series_exchange_dgamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/series_exchange_dlnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_JNR_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_Jseries_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_KNR_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_Kseries_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check34_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check35_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check36_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check43_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check44_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check45_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check46_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check47_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check48_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/tc_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/.*\\.pyc$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/context\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/make\\.out.*$;^C:/hoffman/My Builds/testcase/www/Makefile$;^C:/hoffman/My Builds/testcase/www/Makefile\\.in$;^C:/hoffman/My Builds/testcase/src/.*\\.flc$;^C:/hoffman/My Builds/testcase/src/Makefile$;^C:/hoffman/My Builds/testcase/src/Makefile\\.in$;^C:/hoffman/My Builds/testcase/src/\\.deps$;^C:/hoffman/My Builds/testcase/src/\\.libs$;^C:/hoffman/My Builds/testcase/src/.*\\.la$;^C:/hoffman/My Builds/testcase/src/.*\\.lo$;^C:/hoffman/My Builds/testcase/src/make\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/statef.*\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/0\\.1\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/0\\.1\\.model_13$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/0\\.1\\.model_23$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/0\\.3\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/0\\.3\\.model_13$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/0\\.3\\.model_23$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/1\\.0\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/1\\.0\\.model_13$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/1\\.0\\.model_15$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/1\\.0\\.model_23$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/1\\.0\\.model_rel$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/hot_post_agb\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/rgb_tip\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/rgbtip\\.1\\.0\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/rgbtip\\.1\\.0\\.model_13$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/rgbtip\\.1\\.0\\.model_23$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/start_shellflash\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/white_dwarf\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/zahb\\.1\\.0\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/zahb\\.1\\.0\\.model_13$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/zahb\\.1\\.0\\.model_23$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/model-loci/zahb\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dh/dgamma1$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dh/dlnp$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dh/statef_compare\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fermi_dirac_approx/15gamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fermi_dirac_approx/15lnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fermi_dirac_approx/23gamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fermi_dirac_approx/23lnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/thermodynamic_consistency/.*\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/thermodynamic_consistency/.*\\.results$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/pteh/dgamma1$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/pteh/dlnp$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/pteh/statef_compare\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/newversion_grid/.*\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/newversion_grid/.*\\.err$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/.*\\.ps$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/.*\\.pyc$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_fit\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_fit\\.dvi$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_fit\\.log$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/body\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/head\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/prior-dvi\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/3order_data\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/5order_data\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/8order_data\\.tex$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check8_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check1_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check3_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check5_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/effo_check3_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/effoo_check3_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fda15gamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fda15lnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fda23gamma1\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/fda23lnp\\.yplot$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/tc_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/make\\.out.*$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/thermodynamic_consistency/statef_compare\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/thermodynamic_consistency/tc\\.results$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/opal_solar/opal_compare_model\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/opal_solar/opal_compare_solar\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/opal_solar/opal_solar\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/opal_solar/opal_solar_1995\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/opal_solar/statef_opal_model\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/opal_solar/statef_opal_model_1995\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/purehe_newversion_grid/.*\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/purehe_newversion_grid/.*\\.err$;^C:/hoffman/My Builds/testcase/include/Makefile\\.in$;^C:/hoffman/My Builds/testcase/include/Makefile$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/model-loci/0\\.1\\.model_pteh$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/model-loci/1\\.0\\.model_eos1a-eos1$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/model-loci/1\\.0\\.model_pteh$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/model-loci/statef_model_0\\.1\\.model_pteh\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/model-loci/statef_model_1\\.0\\.model_eos1a-eos1\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/model-loci/statef_model_1\\.0\\.model_pteh\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/context/contour\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/context/eos_grid\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/context/statef_grid\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/thermodynamic_consistency/fort\\.91$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/thermodynamic_consistency/statef_compare\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/nocoulomb/dgamma1$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/nocoulomb/dlnp$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/nocoulomb/statef_compare\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/context$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/oldversion_grid$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/2005Ap&SS\\.298\\.\\.135S\\.pdf$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/2007Ap&SS\\.307\\.\\.263C\\.pdf$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/astro-ph\\.9909168_eprint_submitted_to_High_Press\\.Res\\.16,331\\.pdf$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/.*ps.*$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/.*\\.pyc$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/convergence\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/convergence\\.dvi$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/convergence\\.log$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/body\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/head\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/prior-dvi\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/statef_grid-newversion$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/context\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/pureh_context\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/purehe_context\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/old$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/make\\.out.*$;^C:/hoffman/My Builds/testcase/utils/.*\\.flc$;^C:/hoffman/My Builds/testcase/utils/Makefile$;^C:/hoffman/My Builds/testcase/utils/Makefile\\.in$;^C:/hoffman/My Builds/testcase/utils/\\.deps$;^C:/hoffman/My Builds/testcase/utils/\\.libs$;^C:/hoffman/My Builds/testcase/utils/.*\\.la$;^C:/hoffman/My Builds/testcase/utils/.*\\.lo$;^C:/hoffman/My Builds/testcase/utils/free_eos_test$;^C:/hoffman/My Builds/testcase/utils/test_rosenbrock$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check/eff_check1\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check/eff_check3\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check/eff_check5\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check/eff_check8\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check/eff_checknr\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check/effo_check3\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/eff_check/effoo_check3\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence_20070613$;^C:/hoffman/My Builds/testcase/www/eospaper/text$;^C:/hoffman/My Builds/testcase/www/eospaper/cassisi_book_fig$;^C:/hoffman/My Builds/testcase/www/eospaper/1\\.1\\.0$;^C:/hoffman/My Builds/testcase/www/eospaper/2\\.0\\.0$;^C:/hoffman/My Builds/testcase/www/eospaper/1\\.2\\.0$;^C:/hoffman/My Builds/testcase/www/eospaper/1\\.3\\.0$;^C:/hoffman/My Builds/testcase/www/eospaper/1\\.4\\.0$;^C:/hoffman/My Builds/testcase/www/eospaper/1\\.5\\.0$;^C:/hoffman/My Builds/testcase/www/eospaper/1\\.6\\.0$;^C:/hoffman/My Builds/testcase/www/eospaper/figures$;^C:/hoffman/My Builds/testcase/www/eospaper/old$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/.*\\.ps.*$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/coulomb\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/coulomb\\.dvi$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/coulomb\\.log$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/.*\\.pyc$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/body\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/head\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/prior-dvi\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/context\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dh_dgamma1_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dh_dlnp_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dhtau_dgamma1_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dhtau_dlnp_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/nocoulomb_dgamma1_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/nocoulomb_dlnp_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/pteh_dgamma1_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/pteh_dlnp_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/make\\.out.*$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_JNR\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_Jseries\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_KNR\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_Kseries\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_check34\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_check35\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_check36\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_check44\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_check45\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/exchange_check46\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/statef_compare_1_exchange\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/statef_compare_2_exchange\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/statef_compare_linear_exchange\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/statef_compare_noexchange\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/statef_compare_nr_exchange\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/statef_compare_series_exchange\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/1_exchange_dgamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/noexchange_dlnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/nr_exchange_dgamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/series_exchange_dlnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/series_exchange_dgamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/linear_exchange_dlnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/2_exchange_dgamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/nr_exchange_dlnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/linear_exchange_dgamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/noexchange_dgamma1\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/1_exchange_dlnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/exchange_check/2_exchange_dlnp\\.gnuplot$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/pureh_newversion_grid/.*\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/convergence/pureh_newversion_grid/.*\\.err$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dhtau/dgamma1$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dhtau/dlnp$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/dhtau/statef_compare\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_0\\.1\\.model\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_0\\.3\\.model\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_1\\.0\\.model\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_1\\.0\\.model_linear\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_1\\.0\\.model_noexchange\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_1\\.0\\.model_nr\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_1\\.0\\.rgbtip\\.model\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/statef_model_1\\.0\\.zahb\\.model\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/1\\.0\\.zahb\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/1\\.0\\.rgbtip\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/1\\.0\\.model_linear$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/1\\.0\\.model_noexchange$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/1\\.0\\.model_nr$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/0\\.1\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/1\\.0\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/model-loci/0\\.3\\.model$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/context/contour\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/context/eos_grid\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/exchange/context/statef_grid\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/gong/delta\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/gong/m0085eos1gong\\.ascii$;^C:/hoffman/My Builds/testcase/www/eospaper/eff_fit/rho-T-loci/gong/m0085eos2gong\\.ascii$;^C:/hoffman/My Builds/testcase/www/eospaper/coulomb/coulomb_adjust/coulomb_adjust\\.out$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/.*\\.ps$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/.*\\.pyc$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/head\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/body\\.tmp$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/prior-dvi\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/solution\\.aux$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/solution\\.log$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/solution\\.dvi$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/rtc_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/tc_yplot\\.in$;^C:/hoffman/My Builds/testcase/www/eospaper/solution/make\\.out.*$")
+
+#
+# Define a macro
+#
+macro(ASSERT value msg)
+ if (NOT ${value})
+ message ("Assertion failure:" ${msg} )
+ endif ()
+endmacro()
+
+# invoke the macro
+ASSERT(Complex_BINARY_DIR "The PROJECT command is broken")
+
+#
+# Define a var args macro, it must take two or four args
+#
+macro(TEST_ARGC value1 value2)
+ add_definitions(${value1} ${value2})
+ if (${ARGC} EQUAL 4)
+ add_definitions(${ARGV2} ${ARGV3})
+ endif ()
+endmacro()
+
+# invoke the macro
+TEST_ARGC(-DCMAKE_ARGV1 -DCMAKE_ARGV2 -DCMAKE_ARGV3 -DCMAKE_ARGV4)
+
+macro(TEST_VAR_ARG fa)
+ if("${ARGV}" STREQUAL "1;2;3")
+ message(STATUS "ARGV works")
+ else()
+ message(FATAL_ERROR "ARGV does not work; got \"${ARGV}\" instead of \"1;2;3\"")
+ endif()
+ if("${ARGN}" STREQUAL "2;3")
+ message(STATUS "ARGN works")
+ else()
+ message(FATAL_ERROR "ARGV does not work; got \"${ARGN}\" instead of \"2;3\"")
+ endif()
+endmacro()
+
+TEST_VAR_ARG(1 2 3)
+
+# Floating-point comparison test.
+if(2.4 LESS 2.4)
+ message(FATAL_ERROR "Failed: 2.4 LESS 2.4")
+endif()
+if(2.4 GREATER 2.4)
+ message(FATAL_ERROR "Failed: 2.4 GREATER 2.4")
+endif()
+if(NOT 2.4 EQUAL 2.4)
+ message(FATAL_ERROR "Failed: NOT 2.4 EQUAL 2.4")
+endif()
+
+if(CMAKE_SYSTEM MATCHES "OSF1-V")
+ if(NOT CMAKE_COMPILER_IS_GNUCXX)
+ string(APPEND CMAKE_CXX_FLAGS " -timplicit_local -no_implicit_include ")
+ endif()
+endif()
+
+
+add_definitions(-DCMAKE_IS_FUN)
+add_definitions(-DCMAKE_IS_REALLY_FUN)
+set_property(DIRECTORY
+ PROPERTY COMPILE_DEFINITIONS_RELEASE
+ CMAKE_IS_FUN_IN_RELEASE_MODE
+ )
+set_property(DIRECTORY
+ PROPERTY COMPILE_DEFINITIONS_RELWITHDEBINFO
+ CMAKE_IS_FUN_IN_RELEASE_MODE
+ )
+set_property(DIRECTORY
+ PROPERTY COMPILE_DEFINITIONS_MINSIZEREL
+ CMAKE_IS_FUN_IN_RELEASE_MODE
+ )
+
+set(TEST_SEP "a b c")
+separate_arguments(TEST_SEP)
+
+
+#
+# Include vars from a file and from a cache
+#
+if (EXISTS ${Complex_SOURCE_DIR}/VarTests.cmake)
+ include(${Complex_SOURCE_DIR}/VarTests.cmake)
+endif ()
+include(fileshouldnotbehere OPTIONAL)
+load_cache(${Complex_SOURCE_DIR}/Cache
+ EXCLUDE
+ CACHE_TEST_VAR_EXCLUDED
+ INCLUDE_INTERNALS
+ CACHE_TEST_VAR_INTERNAL)
+
+load_cache(${Complex_SOURCE_DIR}/Cache READ_WITH_PREFIX foo CACHE_TEST_VAR2)
+if(${fooCACHE_TEST_VAR2} MATCHES bar)
+ message("Load cache worked: ${fooCACHE_TEST_VAR2}")
+else()
+ message(FATAL_ERROR "Load cache with prefix failed: ${fooCACHE_TEST_VAR2}")
+endif()
+
+
+
+#
+# Specify include and lib dirs
+# (BEFORE is for coverage)
+#
+include_directories(
+ Library
+)
+
+include_directories(BEFORE
+ ${Complex_BINARY_DIR}
+)
+include_directories(SYSTEM Library/SystemDir)
+
+include_regular_expression("^(cmTest|file|sharedFile|test).*$" "^cmMissing")
+
+link_directories(
+ ${Complex_BINARY_DIR}/Library
+)
+
+#
+# check for SET CACHE FORCE
+#
+set(FORCE_TEST 1 CACHE STRING "a test")
+set(FORCE_TEST 0 CACHE STRING "a test" FORCE)
+
+#
+# Lib and exe path
+#
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${Complex_BINARY_DIR}/lib/static")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${Complex_BINARY_DIR}/lib")
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${Complex_BINARY_DIR}/bin")
+
+message (Test " " escape " " semi-colon " " \; \;)
+#
+# Exec program (TODO: test a result)
+# Increase coverage.
+#
+message("\nIgnore this message")
+option(NO_EXEC_PROGRAM "Do not test EXEC_PROGRAM" 0)
+if (NOT NO_EXEC_PROGRAM)
+ exec_program(${CMAKE_COMMAND} ARGS -E echo NO_EXEC_PROGRAM "${Complex_BINARY_DIR}")
+else ()
+ message("Set this option ON")
+endif ()
+
+mark_as_advanced(NO_EXEC_PROGRAM)
+mark_as_advanced(CLEAR NO_EXEC_PROGRAM)
+
+# Execute a process. Add coverage for this command.
+execute_process(
+ COMMAND ${CMAKE_COMMAND} -E echo "ABCDEFG"
+ OUTPUT_VARIABLE TEST_OUT
+ )
+if("${TEST_OUT}" STREQUAL "ABCDEFG\n")
+else()
+ message(SEND_ERROR "EXECUTE_PROCESS output test failed: [${TEST_OUT}]")
+endif()
+
+# This test has some problems on UNIX systems. Disabling for now.
+#
+# execute_process(
+# COMMAND ${CMAKE_COMMAND} -E echo "ABCDEFG"
+# COMMAND /process/does/not/exist
+# OUTPUT_QUIET
+# ERROR_QUIET
+# RESULT_VARIABLE RESULT
+# )
+# if("${RESULT}" STREQUAL "0")
+# message(SEND_ERROR
+# "EXECUTE_PROCESS result test failed with RESULT=[${RESULT}]")
+# else()
+# message(STATUS "EXECUTE_PROCESS result test passed with RESULT=[${RESULT}]")
+# endif()
+
+#
+# Create directory.
+# The 'complex' executable will then test if this dir exists,
+# sadly it won't be able to remove it.
+#
+make_directory("${Complex_BINARY_DIR}/make_dir")
+
+#
+# Test FIND_LIBARY
+# Create a dummy empty lib
+#
+configure_file(
+ ${Complex_SOURCE_DIR}/Library/dummy
+ ${Complex_BINARY_DIR}/Library/dummylib.lib
+ COPYONLY)
+foreach (ext ${CMAKE_SHLIB_SUFFIX};.so;.a;.sl)
+ configure_file(
+ ${Complex_SOURCE_DIR}/Library/dummy
+ ${Complex_BINARY_DIR}/Library/libdummylib${ext}
+ COPYONLY)
+endforeach ()
+
+find_library(FIND_DUMMY_LIB
+ dummylib
+ PATHS
+ ${Complex_BINARY_DIR}/Library DOC "find dummy lib")
+
+find_library(FIND_DUMMY_LIB
+ NAMES dummylib dummylib2
+ PATHS
+ ${Complex_BINARY_DIR}/Library DOC "find dummy lib")
+
+#
+# Test SET_SOURCE_FILES_PROPERTIES
+#
+set_source_files_properties(nonexisting_file2
+ GENERATED
+ ABSTRACT
+ WRAP_EXCLUDE
+ COMPILE_FLAGS "-foo -bar")
+
+get_source_file_property(FILE_HAS_ABSTRACT nonexisting_file2 ABSTRACT)
+get_source_file_property(FILE_HAS_WRAP_EXCLUDE nonexisting_file2 WRAP_EXCLUDE)
+get_source_file_property(FILE_COMPILE_FLAGS nonexisting_file2 COMPILE_FLAGS)
+
+set_source_files_properties(nonexisting_file3 PROPERTIES
+ GENERATED 1
+ ABSTRACT 1
+ WRAP_EXCLUDE 1
+ COMPILE_FLAGS "-foo -bar")
+get_source_file_property(FILE_HAS_ABSTRACT nonexisting_file3 ABSTRACT)
+get_source_file_property(FILE_HAS_WRAP_EXCLUDE nonexisting_file3 WRAP_EXCLUDE)
+get_source_file_property(FILE_COMPILE_FLAGS nonexisting_file3 COMPILE_FLAGS)
+
+#
+# Test registry (win32)
+# Create a file, put its path in a registry key, try to find the file in that
+# path using that registry key, then remove the file and the key
+#
+if (WIN32)
+ if (NOT UNIX)
+ set(dir "${Complex_BINARY_DIR}/registry_dir")
+ set(file "registry_test_dummy")
+ set(hkey "HKEY_CURRENT_USER\\Software\\Kitware\\CMake\\Tests\\Complex;registry_test")
+ configure_file(
+ ${Complex_SOURCE_DIR}/Library/dummy
+ "${dir}/${file}"
+ COPYONLY)
+ exec_program(${CMAKE_COMMAND} ARGS "-E write_regv \"${hkey}\" \"${dir}\"")
+ find_path(REGISTRY_TEST_PATH
+ ${file}
+ "[${hkey}]" DOC "Registry_Test_Path")
+ exec_program(${CMAKE_COMMAND} ARGS "-E delete_regv \"${hkey}\"")
+ exec_program(${CMAKE_COMMAND} ARGS "-E rm -f \"${dir}/${file}\"")
+ endif ()
+endif ()
+
+#
+# Test a set and a remove
+#
+set(REMOVE_STRING a b c d e f)
+set(removeVar1 c e)
+remove(REMOVE_STRING ${removeVar1} f)
+
+#
+# Test an IF inside a FOREACH.
+#
+foreach(x "a")
+ if(${x} MATCHES "a")
+ # Should always execute.
+ set(IF_INSIDE_FOREACH_THEN_EXECUTED 1)
+ else()
+ # Should never execute.
+ set(IF_INSIDE_FOREACH_ELSE_EXECUTED 1)
+ endif()
+endforeach()
+
+# test WHILE command
+set (while_var 1)
+while (while_var LESS 1000)
+ set(while_var ${while_var}0)
+endwhile()
+
+set(SHOULD_BE_ZERO )
+set(SHOULD_BE_ONE 1)
+set(SHOULD_BE_ZERO_AND_INDENTED )
+set(SHOULD_BE_ONE_AND_INDENTED 1)
+
+# test elseif functionality, the mess below tries to catch problem
+# of clauses being executed early or late etc
+set (RESULT 3)
+if (RESULT EQUAL 1)
+ if (RESULT EQUAL 2)
+ set (ELSEIF_RESULT 1)
+ elseif (RESULT EQUAL 3)
+ set (ELSEIF_RESULT 1)
+ endif ()
+elseif (RESULT EQUAL 2)
+ set (ELSEIF_RESULT 1)
+elseif (RESULT EQUAL 3)
+ if (RESULT EQUAL 2)
+ set (ELSEIF_RESULT 1)
+ elseif (RESULT EQUAL 3)
+ if (NOT ELSEIF_RESULT EQUAL 1)
+ set (ELSEIF_RESULT 2)
+ endif ()
+ endif ()
+elseif (RESULT EQUAL 4)
+ if (RESULT EQUAL 2)
+ set (ELSEIF_RESULT 1)
+ elseif (RESULT EQUAL 3)
+ set (ELSEIF_RESULT 1)
+ endif ()
+else ()
+ if (RESULT EQUAL 2)
+ set (ELSEIF_RESULT 1)
+ elseif (RESULT EQUAL 3)
+ set (ELSEIF_RESULT 1)
+ endif ()
+endif ()
+
+if (NOT ELSEIF_RESULT EQUAL 2)
+ set (ELSEIF_RESULT 0)
+endif ()
+
+# test handling of parenthetical groups in conditionals
+if (2 GREATER 1 AND (4 LESS 3 OR 5 LESS 6) AND NOT (7 GREATER 8))
+ set(CONDITIONAL_PARENTHESES 1)
+endif()
+
+
+#
+# Configure file
+# (plug vars to #define so that they can be tested)
+#
+configure_file(
+ ${Complex_SOURCE_DIR}/cmTestConfigure.h.in
+ ${Complex_BINARY_DIR}/cmTestConfigure.h)
+
+set(STRING_WITH_QUOTES "\"hello world\"")
+# test CONFIGURE_FILE with ESCAPE_QUOTES on
+configure_file(
+ ${Complex_SOURCE_DIR}/cmTestConfigureEscape.h.in
+ ${Complex_BINARY_DIR}/cmTestConfigureEscape.h ESCAPE_QUOTES)
+
+# Test regular expression commands.
+string(REGEX MATCH "b" RESULT "abc")
+if(NOT RESULT)
+ message(SEND_ERROR "string(REGEX MATCH ... ) test failed.")
+endif()
+string(REGEX MATCHALL "b" RESULT "abcb")
+if(NOT RESULT)
+ message(SEND_ERROR "string(REGEX MATCHALL ... ) test failed.")
+endif()
+string(REGEX REPLACE ".([bd])." "[\\1]" RESULT "a(b)c(d)e")
+if(NOT RESULT STREQUAL "a[b]c[d]e")
+ message(SEND_ERROR
+ "string(REGEX REPLACE ... ) test failed (\"${RESULT}\" v. \"a[b]c[d]e\")")
+endif()
+
+#
+# This tests needs Ansi C++98
+#
+set(CMAKE_CXX_STANDARD 98)
+#
+# GNU extensions are needed for stricmp() on Windows.
+#
+set(CMAKE_CXX_EXTENSIONS TRUE)
+
+# Clang/C2 in C++98 mode cannot properly handle some of MSVC headers
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
+ CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
+ set(CMAKE_CXX_STANDARD 11)
+endif()
+
+#
+# Create the libs and the main exe
+#
+add_subdirectory(Library)
+add_subdirectory(Executable)
+subdir_depends(Executable Library)
+export_library_dependencies(${Complex_BINARY_DIR}/ComplexLibraryDepends.cmake)
+include(${Complex_BINARY_DIR}/ComplexLibraryDepends.cmake OPTIONAL)
diff --git a/Tests/ComplexOneConfig/Cache/CMakeCache.txt b/Tests/ComplexOneConfig/Cache/CMakeCache.txt
new file mode 100644
index 0000000..727faa2
--- /dev/null
+++ b/Tests/ComplexOneConfig/Cache/CMakeCache.txt
@@ -0,0 +1,34 @@
+# This is the CMakeCache file.
+# For build in directory: d:/build/kitware/cmake/CMake-nmake/Tests/Complex
+# You can edit this file to change values found and used by cmake.
+# If you do not want to change any of the values, simply exit the editor.
+# If you do want to change a value, simply edit, save, and exit the editor.
+# The syntax for the file is as follows:
+# KEY:TYPE=VALUE
+# KEY is the name of a variable in the cache.
+# TYPE is a hint to GUI's for the type of VALUE, DO NOT EDIT TYPE!.
+# VALUE is the current value for the KEY.
+
+########################
+# EXTERNAL cache entries
+########################
+
+//A var.
+CACHE_TEST_VAR1:STRING=foo
+
+//A var.
+CACHE_TEST_VAR2:FILEPATH=bar
+
+//A var.
+CACHE_TEST_VAR3:BOOL=1
+
+//A var.
+CACHE_TEST_VAR_EXCLUDED:BOOL=1
+
+
+########################
+# INTERNAL cache entries
+########################
+
+//A var.
+CACHE_TEST_VAR_INTERNAL:INTERNAL=bar
diff --git a/Tests/ComplexOneConfig/Executable/A.cxx b/Tests/ComplexOneConfig/Executable/A.cxx
new file mode 100644
index 0000000..fb3eb08
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/A.cxx
@@ -0,0 +1,9 @@
+// Include code from a header that should not be compiled separately.
+#include "A.hh"
+
+#include <stdio.h>
+int main()
+{
+ printf("#define A_VALUE %d\n", A());
+ return 0;
+}
diff --git a/Tests/ComplexOneConfig/Executable/A.h b/Tests/ComplexOneConfig/Executable/A.h
new file mode 100644
index 0000000..3503719
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/A.h
@@ -0,0 +1,7 @@
+// This header should not be compiled directly but through inclusion
+// in A.cxx through A.hh.
+extern int A();
+int A()
+{
+ return 10;
+}
diff --git a/Tests/ComplexOneConfig/Executable/A.hh b/Tests/ComplexOneConfig/Executable/A.hh
new file mode 100644
index 0000000..e6bab02
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/A.hh
@@ -0,0 +1,2 @@
+// This header should not be compiled directly but through inclusion in A.cxx
+#include "A.h"
diff --git a/Tests/ComplexOneConfig/Executable/A.txt b/Tests/ComplexOneConfig/Executable/A.txt
new file mode 100644
index 0000000..8ee9462
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/A.txt
@@ -0,0 +1 @@
+This file should not be compiled!
diff --git a/Tests/ComplexOneConfig/Executable/CMakeLists.txt b/Tests/ComplexOneConfig/Executable/CMakeLists.txt
new file mode 100644
index 0000000..f935aed
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/CMakeLists.txt
@@ -0,0 +1,174 @@
+#
+# Create exe.
+#
+string(APPEND CMAKE_CXX_FLAGS " -DTEST_CXX_FLAGS")
+string(APPEND CMAKE_C_FLAGS " -DTEST_C_FLAGS")
+
+# Create an imported target for if(TARGET) test below.
+add_library(ExeImportedTarget UNKNOWN IMPORTED)
+
+# Test if(TARGET) command.
+if(NOT TARGET CMakeTestLibrary)
+ message(FATAL_ERROR "if(NOT TARGET CMakeTestLibrary) returned true!")
+endif()
+if(NOT TARGET ExeImportedTarget)
+ message(FATAL_ERROR "if(NOT TARGET ExeImportedTarget) returned true!")
+endif()
+if(TARGET LibImportedTarget)
+ message(FATAL_ERROR "if(TARGET LibImportedTarget) returned true!")
+endif()
+if(TARGET NotATarget)
+ message(FATAL_ERROR "if(TARGET NotATarget) returned true!")
+endif()
+
+# Use LINK_LIBRARIES instead of TARGET_LINK_LIBRARIES to
+set(COMPLEX_LIBS CMakeTestLibrary;CMakeTestLibraryShared;CMakeTestCLibraryShared)
+link_libraries(${COMPLEX_LIBS})
+
+# Test forcing a .cxx file to not build.
+set_source_files_properties(complex_nobuild.cxx PROPERTIES
+ HEADER_FILE_ONLY 1)
+
+# Test forcing a .c file to not build.
+# This makes sure a mixed language library is created
+# with header file only sources
+set_source_files_properties(complex_nobuild.c PROPERTIES
+ HEADER_FILE_ONLY 1)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+add_executable(A A.cxx A.hh A.h A.txt)
+add_custom_command(OUTPUT Aout.h COMMAND A > Aout.h VERBATIM)
+add_executable(complex complex testcflags.c Aout.h)
+# Sub1/NameConflictTest.c Sub2/NameConflictTest.c)
+add_executable(complex.file complex.file.cxx complex_nobuild.cxx
+ complex_nobuild.c)
+
+if (UNIX)
+ target_link_libraries(complex ${CMAKE_DL_LIBS})
+else()
+ if (NOT BORLAND)
+ if(NOT MINGW)
+ target_link_libraries(complex rpcrt4.lib)
+ endif()
+ endif()
+endif ()
+
+# Test linking to static lib when a shared lib has the same name.
+if(CMAKE_EXE_LINK_STATIC_CXX_FLAGS)
+ add_definitions(-DCOMPLEX_TEST_LINK_STATIC)
+ target_link_libraries(complex CMakeTestLinkStatic)
+endif()
+
+# can we get the path to a source file
+get_source_file_property(A_LOCATION A.cxx LOCATION)
+if ("${A_LOCATION}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}/A.cxx")
+ add_definitions(-DCMAKE_FOUND_ACXX)
+endif ()
+
+# get the directory parent
+get_directory_property(P_VALUE PARENT_DIRECTORY)
+if ("${P_VALUE}" STREQUAL "${CMAKE_SOURCE_DIR}")
+ add_definitions(-DCMAKE_FOUND_PARENT)
+endif ()
+
+# get the stack of listfiles
+include(Included.cmake)
+if ("${LF_VALUE}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt;${CMAKE_CURRENT_SOURCE_DIR}/Included.cmake")
+ add_definitions(-DCMAKE_FOUND_LISTFILE_STACK)
+endif ()
+
+# Test add/remove definitions.
+add_definitions(
+ -DCOMPLEX_DEFINED_PRE
+ -DCOMPLEX_DEFINED
+ -DCOMPLEX_DEFINED_POST
+ -DCOMPLEX_DEFINED
+ )
+remove_definitions(-DCOMPLEX_DEFINED)
+
+# Test pre-build/pre-link/post-build rules for an executable.
+add_custom_command(TARGET complex PRE_BUILD
+ COMMAND ${CREATE_FILE_EXE}
+ ARGS "Executable/prebuild.txt"
+ WORKING_DIRECTORY "${Complex_BINARY_DIR}")
+add_custom_command(TARGET complex PRE_BUILD
+ COMMAND ${CREATE_FILE_EXE}
+ ARGS "Executable/prelink.txt"
+ WORKING_DIRECTORY "${Complex_BINARY_DIR}")
+add_custom_command(TARGET complex POST_BUILD
+ COMMAND ${CREATE_FILE_EXE}
+ ARGS "Executable/postbuild.txt"
+ WORKING_DIRECTORY "${Complex_BINARY_DIR}")
+add_custom_command(TARGET complex POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy
+ "Executable/postbuild.txt"
+ "Executable/postbuild2.txt"
+ WORKING_DIRECTORY "${Complex_BINARY_DIR}")
+
+set_source_files_properties(complex
+ COMPILE_FLAGS
+ "-DFILE_HAS_EXTRA_COMPILE_FLAGS"
+ #" -DFILE_DEFINE_STRING=\\\"hello\\\""
+ OBJECT_DEPENDS ${Complex_BINARY_DIR}/cmTestGeneratedHeader.h
+)
+set_target_properties(complex PROPERTIES COMPILE_FLAGS "-DCOMPLEX_TARGET_FLAG")
+add_custom_command(
+ TARGET complex
+ SOURCE ${Complex_SOURCE_DIR}/cmTestGeneratedHeader.h.in
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${Complex_SOURCE_DIR}/cmTestGeneratedHeader.h.in
+ ${Complex_BINARY_DIR}/cmTestGeneratedHeader.h
+ OUTPUTS ${Complex_BINARY_DIR}/cmTestGeneratedHeader.h
+ DEPENDS ${CMAKE_COMMAND}
+)
+
+# Test creating an executable that is not built by default.
+add_executable(notInAllExe EXCLUDE_FROM_ALL notInAllExe.cxx)
+target_link_libraries(notInAllExe notInAllLib)
+
+# Test user-value flag mapping for the VS IDE.
+if(MSVC)
+ set_target_properties(notInAllExe PROPERTIES
+ LINK_FLAGS "/NODEFAULTLIB:LIBC;LIBCMT;MSVCRT")
+endif()
+
+# Test creating a custom target that builds not-in-all targets.
+add_custom_target(notInAllCustom)
+add_dependencies(notInAllCustom notInAllExe)
+
+#
+# Output the files required by 'complex' to a file.
+#
+# This test has been moved to the 'required' subdir so that it
+# has no side-effects on the current Makefile (duplicated source file
+# due to source list expansion done twice).
+#
+add_subdirectory(Temp)
+
+if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_INCLUDE_SYSTEM_FLAG_CXX
+ AND NOT XCODE) # XCODE is excluded due to #15687
+ add_executable(testSystemDir testSystemDir.cxx)
+ set_target_properties(testSystemDir PROPERTIES COMPILE_FLAGS "-Werror")
+endif()
+
+#
+# Extra coverage.Not used.
+#
+install_targets(/tmp complex)
+install_programs(/tmp complex)
+
+configure_file(
+ ${Complex_SOURCE_DIR}/Executable/cmVersion.h.in
+ ${Complex_BINARY_DIR}/cmVersion.h)
+
+source_group(A_GROUP ".cxx")
+source_group(B_GROUP REGULAR_EXPRESSION "cxx")
+source_group(C_GROUP FILES complex.cxx)
+
+file(WRITE ${Complex_BINARY_DIR}/A/libA.a "test")
+file(WRITE ${Complex_BINARY_DIR}/A/libC.a "test")
+file(WRITE ${Complex_BINARY_DIR}/B/libB.a "test")
+file(WRITE ${Complex_BINARY_DIR}/B/libA.a "test")
+file(WRITE ${Complex_BINARY_DIR}/C/libC.a "test")
+file(WRITE ${Complex_BINARY_DIR}/C/libB.a "test")
diff --git a/Tests/ComplexOneConfig/Executable/Included.cmake b/Tests/ComplexOneConfig/Executable/Included.cmake
new file mode 100644
index 0000000..520a68b
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/Included.cmake
@@ -0,0 +1,2 @@
+get_directory_property(LF_VALUE LISTFILE_STACK)
+
diff --git a/Tests/ComplexOneConfig/Executable/Sub1/NameConflictTest.c b/Tests/ComplexOneConfig/Executable/Sub1/NameConflictTest.c
new file mode 100644
index 0000000..8720386
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/Sub1/NameConflictTest.c
@@ -0,0 +1,4 @@
+int NameConflictTest1()
+{
+ return 0;
+}
diff --git a/Tests/ComplexOneConfig/Executable/Sub2/NameConflictTest.c b/Tests/ComplexOneConfig/Executable/Sub2/NameConflictTest.c
new file mode 100644
index 0000000..4a32572
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/Sub2/NameConflictTest.c
@@ -0,0 +1,4 @@
+int NameConflictTest2()
+{
+ return 0;
+}
diff --git a/Tests/ComplexOneConfig/Executable/Temp/CMakeLists.txt b/Tests/ComplexOneConfig/Executable/Temp/CMakeLists.txt
new file mode 100644
index 0000000..041fcff
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/Temp/CMakeLists.txt
@@ -0,0 +1,8 @@
+#
+# Output the files required by 'complex' to a file.
+# The 'complex' executable will then test if this file exists and remove it.
+# The contents of this file is not tested (absolute paths).
+#
+output_required_files(
+ ${Complex_SOURCE_DIR}/Executable/complex.cxx
+ ${Complex_BINARY_DIR}/Executable/Temp/complex-required.txt)
diff --git a/Tests/ComplexOneConfig/Executable/cmVersion.h.in b/Tests/ComplexOneConfig/Executable/cmVersion.h.in
new file mode 100644
index 0000000..de7522d
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/cmVersion.h.in
@@ -0,0 +1 @@
+#define CMAKE_MINIMUM_REQUIRED_VERSION "${CMAKE_MINIMUM_REQUIRED_VERSION}"
diff --git a/Tests/ComplexOneConfig/Executable/complex.cxx b/Tests/ComplexOneConfig/Executable/complex.cxx
new file mode 100644
index 0000000..54c18f4
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/complex.cxx
@@ -0,0 +1,1086 @@
+#include "cmTestConfigure.h"
+#include "cmTestConfigureEscape.h"
+#include "cmTestGeneratedHeader.h"
+#include "cmVersion.h"
+
+#include "Aout.h"
+#include "ExtraSources/file1.h"
+#include "file2.h"
+#include "sharedFile.h"
+extern "C" {
+#include "testConly.h"
+}
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#if !defined(S_ISDIR)
+# define S_ISDIR(mode) ((mode)&_S_IFDIR)
+#endif
+
+#ifdef COMPLEX_TEST_LINK_STATIC
+extern "C" {
+int TestLinkGetType();
+}
+#endif
+
+int cm_passed = 0;
+int cm_failed = 0;
+// ======================================================================
+
+void cmFailed(const char* Message, const char* m2 = "", const char* m3 = "")
+{
+ std::cout << "FAILED: " << Message << m2 << m3 << "\n";
+ cm_failed++;
+}
+
+// ======================================================================
+
+void cmPassed(const char* Message, const char* m2 = "")
+{
+ std::cout << "Passed: " << Message << m2 << "\n";
+ cm_passed++;
+}
+
+#ifndef COMPLEX_DEFINED_PRE
+# error "COMPLEX_DEFINED_PRE not defined!"
+#endif
+
+#ifdef COMPLEX_DEFINED
+# error "COMPLEX_DEFINED is defined but it should not!"
+#endif
+
+#ifndef COMPLEX_DEFINED_POST
+# error "COMPLEX_DEFINED_POST not defined!"
+#endif
+
+#ifndef CMAKE_IS_REALLY_FUN
+# error This is a problem. Looks like ADD_DEFINITIONS and REMOVE_DEFINITIONS does not work
+#endif
+
+#if defined(NDEBUG) && !defined(CMAKE_IS_FUN_IN_RELEASE_MODE)
+# error Per-configuration directory-level definition not inherited.
+#endif
+
+// ======================================================================
+
+void TestAndRemoveFile(const char* filename)
+{
+ struct stat st;
+ if (stat(filename, &st) < 0) {
+ cmFailed("Could not find file: ", filename);
+ } else {
+ if (remove(filename) < 0) {
+ cmFailed("Unable to remove file. It does not imply that this test "
+ "failed, but it *will* be corrupted thereafter if this file is "
+ "not removed: ",
+ filename);
+ } else {
+ cmPassed("Find and remove file: ", filename);
+ }
+ }
+}
+
+// ======================================================================
+
+void TestDir(const char* filename)
+{
+ struct stat st;
+ if (stat(filename, &st) < 0 || !S_ISDIR(st.st_mode)) {
+ cmFailed("Could not find dir: ", filename);
+ } else {
+ cmPassed("Find dir: ", filename);
+ }
+}
+
+// Here is a stupid function that tries to use std::string methods
+// so that the dec cxx compiler will instantiate the stuff that
+// we are using from the CMakeLib library....
+void ForceStringUse()
+{
+ std::vector<std::string> v;
+ std::vector<std::string> v2;
+ v = v2;
+ std::string cachetest = CACHE_TEST_VAR_INTERNAL;
+ v.push_back(cachetest);
+ v2 = v;
+ std::string x(5, 'x');
+ char buff[5];
+ x.copy(buff, 1, 0);
+ x[0] = 'a';
+ std::string::size_type pos = 0;
+ x.replace(pos, pos, pos, 'x');
+ std::string copy = cachetest;
+ cachetest.find("bar");
+ cachetest.rfind("bar");
+ copy.append(cachetest);
+ copy = cachetest.substr(0, cachetest.size());
+}
+
+// defined in testcflags.c
+extern "C" int TestCFlags(char* m);
+extern "C" int TestTargetCompileFlags(char* m);
+
+#if 0
+// defined in Sub1/NameConflictTest.c
+extern "C" int NameConflictTest1();
+// defined in Sub2/NameConflictTest.c
+extern "C" int NameConflictTest2();
+#endif
+
+// ======================================================================
+
+int main()
+{
+#if 0
+ if(NameConflictTest1() == 0 && NameConflictTest2() == 0)
+ {
+ cmPassed("Sub dir with same named source works");
+ }
+ else
+ {
+ cmFailed("Sub dir with same named source fails");
+ }
+#endif
+ if (file1() != 1) {
+ cmFailed("Call to file1 function from library failed.");
+ } else {
+ cmPassed("Call to file1 function returned 1.");
+ }
+#ifndef COMPLEX_TARGET_FLAG
+ cmFailed("COMPILE_FLAGS did not work with SET_TARGET_PROPERTIES");
+#else
+ cmPassed("COMPILE_FLAGS did work with SET_TARGET_PROPERTIES");
+#endif
+
+#ifdef ELSEIF_RESULT
+ cmPassed("ELSEIF did work");
+#else
+ cmFailed("ELSEIF did not work");
+#endif
+
+#ifdef CONDITIONAL_PARENTHESES
+ cmPassed("CONDITIONAL_PARENTHESES did work");
+#else
+ cmFailed("CONDITIONAL_PARENTHESES did not work");
+#endif
+
+ if (file2() != 1) {
+ cmFailed("Call to file2 function from library failed.");
+ } else {
+ cmPassed("Call to file2 function returned 1.");
+ }
+#ifndef TEST_CXX_FLAGS
+ cmFailed("CMake CMAKE_CXX_FLAGS is not being passed to the compiler!");
+#else
+ cmPassed("CMake CMAKE_CXX_FLAGS is being passed to the compiler.");
+#endif
+ std::string gen = CMAKE_GENERATOR;
+ // visual studio is currently broken for c flags
+ char msg[1024];
+ if (gen.find("Visual") == gen.npos) {
+#ifdef TEST_C_FLAGS
+ cmFailed(
+ "CMake CMAKE_C_FLAGS are being passed to c++ files the compiler!");
+#else
+ cmPassed("CMake CMAKE_C_FLAGS are not being passed to c++ files.");
+#endif
+ if (TestCFlags(msg)) {
+ cmPassed("CMake CMAKE_C_FLAGS are being passed to c files and CXX flags "
+ "are not.");
+ } else {
+ cmFailed(msg);
+ }
+ }
+ if (TestTargetCompileFlags(msg)) {
+ cmPassed(msg);
+ } else {
+ cmFailed(msg);
+ }
+
+ // ----------------------------------------------------------------------
+ // Test ADD_DEFINITIONS
+
+#ifndef CMAKE_IS_FUN
+ cmFailed("CMake is not fun, so it is broken and should be fixed.");
+#else
+ cmPassed("CMAKE_IS_FUN is defined.");
+#endif
+
+#if defined(CMAKE_ARGV1) && defined(CMAKE_ARGV2) && defined(CMAKE_ARGV3) && \
+ defined(CMAKE_ARGV4)
+ cmPassed("Variable args for MACROs are working.");
+#else
+ cmFailed("Variable args for MACROs are failing.");
+#endif
+
+// ----------------------------------------------------------------------
+// Test GET_SOURCE_FILE_PROPERTY for location
+#ifndef CMAKE_FOUND_ACXX
+ cmFailed("CMake did not get the location of A.cxx correctly");
+#else
+ cmPassed("CMake found A.cxx properly");
+#endif
+
+// ----------------------------------------------------------------------
+// Test GET_DIRECTORY_PROPERTY for parent
+#ifndef CMAKE_FOUND_PARENT
+ cmFailed("CMake did not get the location of the parent directory properly");
+#else
+ cmPassed("CMake found the parent directory properly");
+#endif
+
+// ----------------------------------------------------------------------
+// Test GET_DIRECTORY_PROPERTY for listfiles
+#ifndef CMAKE_FOUND_LISTFILE_STACK
+ cmFailed("CMake did not get the listfile stack properly");
+#else
+ cmPassed("CMake found the listfile stack properly");
+#endif
+
+ // ----------------------------------------------------------------------
+ // Test SET, VARIABLE_REQUIRES
+
+#ifdef SHOULD_NOT_BE_DEFINED
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED is defined.");
+#endif
+
+#ifndef ONE_VAR
+ cmFailed("cmakedefine is broken, ONE_VAR is not defined.");
+#else
+ cmPassed("ONE_VAR is defined.");
+#endif
+
+#ifndef ONE_VAR_AND_INDENTED
+ cmFailed("cmakedefine is broken, ONE_VAR_AND_INDENTED is not defined.");
+#else
+ cmPassed("ONE_VAR_AND_INDENTED is defined.");
+#endif
+
+#ifndef ONE_VAR_IS_DEFINED
+ cmFailed("cmakedefine, SET or VARIABLE_REQUIRES is broken, "
+ "ONE_VAR_IS_DEFINED is not defined.");
+#else
+ cmPassed("ONE_VAR_IS_DEFINED is defined.");
+#endif
+
+#ifdef ZERO_VAR
+ cmFailed("cmakedefine is broken, ZERO_VAR is defined.");
+#else
+ cmPassed("ZERO_VAR is not defined.");
+#endif
+
+#ifdef ZERO_VAR_AND_INDENTED
+ cmFailed("cmakedefine is broken, ZERO_VAR_AND_INDENTED is defined.");
+#else
+ cmPassed("ZERO_VAR_AND_INDENTED is not defined.");
+#endif
+
+#ifndef STRING_VAR
+ cmFailed("the CONFIGURE_FILE command is broken, STRING_VAR is not defined.");
+#else
+ if (strcmp(STRING_VAR, "CMake is great") != 0) {
+ cmFailed("the SET or CONFIGURE_FILE command is broken. STRING_VAR == ",
+ STRING_VAR);
+ } else {
+ cmPassed("STRING_VAR == ", STRING_VAR);
+ }
+#endif
+
+ // ----------------------------------------------------------------------
+ // Test various IF/ELSE combinations
+
+#ifdef SHOULD_NOT_BE_DEFINED_NOT
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_NOT is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_NOT is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_NOT
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_NOT is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_NOT is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_NOT2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_NOT2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_NOT2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_NOT2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_NOT2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_NOT2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_AND
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_AND is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_AND is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_AND
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_AND is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_AND is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_AND2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_AND2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_AND2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_AND2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_AND2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_AND2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_OR
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_OR is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_OR is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_OR
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_OR is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_OR is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_OR2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_OR2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_OR2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_OR2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_OR2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_OR2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_MATCHES
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_MATCHES is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_MATCHES is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_MATCHES
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_MATCHES is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_MATCHES is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_MATCHES2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_MATCHES2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_MATCHES2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_MATCHES2
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_MATCHES2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_MATCHES2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_COMMAND
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_COMMAND is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_COMMAND is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_COMMAND
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_COMMAND is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_COMMAND is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_COMMAND2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_COMMAND2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_COMMAND2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_COMMAND2
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_COMMAND2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_COMMAND2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_EXISTS
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_EXISTS is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_EXISTS is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_EXISTS
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_EXISTS is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_EXISTS is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_EXISTS2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_EXISTS2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_EXISTS2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_EXISTS2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_EXISTS2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_EXISTS2 is defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_IS_DIRECTORY
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_IS_DIRECTORY is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_IS_DIRECTORY is defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_IS_DIRECTORY2
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_IS_DIRECTORY2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_IS_DIRECTORY2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_LESS
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_LESS is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_LESS
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_LESS is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_LESS2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_LESS2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_LESS2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_LESS2 is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_LESS2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_GREATER
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_GREATER is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_GREATER
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_GREATER is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_GREATER2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_GREATER2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_GREATER2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_GREATER2 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_GREATER2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_EQUAL
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_EQUAL is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_EQUAL is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_EQUAL
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_EQUAL is not defined.\n");
+#else
+ cmPassed("SHOULD_BE_DEFINED_EQUAL is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_LESS_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL2
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_LESS_EQUAL2
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL2 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_LESS_EQUAL3
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_LESS_EQUAL3 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_LESS_EQUAL3
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_LESS_EQUAL3 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_LESS_EQUAL3 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL2
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL2 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_GREATER_EQUAL3 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_GREATER_EQUAL3
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_GREATER_EQUAL3 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_GREATER_EQUAL3 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRLESS
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRLESS
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRLESS is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRLESS2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRLESS2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRLESS2 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRLESS2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRGREATER
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRGREATER is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER2
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRGREATER2
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER2 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRGREATER2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL2
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL2 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRLESS_EQUAL3
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_STRLESS_EQUAL3 is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRLESS_EQUAL3 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL
+ cmFailed(
+ "IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL is not defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is "
+ "defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL2
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is not "
+ "defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL2 is defined.");
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3
+ cmFailed("IF or SET is broken, SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is "
+ "defined.");
+#else
+ cmPassed("SHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3 is not defined.");
+#endif
+
+#ifndef SHOULD_BE_DEFINED_STRGREATER_EQUAL3
+ cmFailed("IF or SET is broken, SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is not "
+ "defined.");
+#else
+ cmPassed("SHOULD_BE_DEFINED_STRGREATER_EQUAL3 is defined.");
+#endif
+
+ // ----------------------------------------------------------------------
+ // Test FOREACH
+
+#ifndef FOREACH_VAR1
+ cmFailed("the FOREACH, SET or CONFIGURE_FILE command is broken, "
+ "FOREACH_VAR1 is not defined.");
+#else
+ if (strcmp(FOREACH_VAR1, "VALUE1") != 0) {
+ cmFailed("the FOREACH, SET or CONFIGURE_FILE command is broken, "
+ "FOREACH_VAR1 == ",
+ FOREACH_VAR1);
+ } else {
+ cmPassed("FOREACH_VAR1 == ", FOREACH_VAR1);
+ }
+#endif
+
+#ifndef FOREACH_VAR2
+ cmFailed("the FOREACH, SET or CONFIGURE_FILE command is broken, "
+ "FOREACH_VAR2 is not defined.");
+#else
+ if (strcmp(FOREACH_VAR2, "VALUE2") != 0) {
+ cmFailed("the FOREACH, SET or CONFIGURE_FILE command is broken, "
+ "FOREACH_VAR2 == ",
+ FOREACH_VAR2);
+ } else {
+ cmPassed("FOREACH_VAR2 == ", FOREACH_VAR2);
+ }
+#endif
+
+#ifndef FOREACH_CONCAT
+ cmFailed("the FOREACH, SET or CONFIGURE_FILE command is broken, "
+ "FOREACH_CONCAT is not defined.");
+#else
+ if (strcmp(FOREACH_CONCAT, "abcdefg") != 0) {
+ cmFailed("the FOREACH, SET or CONFIGURE_FILE command is broken, "
+ "FOREACH_CONCAT == ",
+ FOREACH_CONCAT);
+ } else {
+ cmPassed("FOREACH_CONCAT == ", FOREACH_CONCAT);
+ }
+#endif
+
+ // ----------------------------------------------------------------------
+ // Test WHILE
+
+ if (WHILE_VALUE != 1000) {
+ cmFailed("WHILE command is not working");
+ } else {
+ cmPassed("WHILE command is working");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test LOAD_CACHE
+
+#ifndef CACHE_TEST_VAR1
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR1 is not defined.");
+#else
+ if (strcmp(CACHE_TEST_VAR1, "foo") != 0) {
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR1 == ",
+ CACHE_TEST_VAR1);
+ } else {
+ cmPassed("CACHE_TEST_VAR1 == ", CACHE_TEST_VAR1);
+ }
+#endif
+
+#ifndef CACHE_TEST_VAR2
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR2 is not defined.");
+#else
+ if (strcmp(CACHE_TEST_VAR2, "bar") != 0) {
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR2 == ",
+ CACHE_TEST_VAR2);
+ } else {
+ cmPassed("CACHE_TEST_VAR2 == ", CACHE_TEST_VAR2);
+ }
+#endif
+
+#ifndef CACHE_TEST_VAR3
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR3 is not defined.");
+#else
+ if (strcmp(CACHE_TEST_VAR3, "1") != 0) {
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR3 == ",
+ CACHE_TEST_VAR3);
+ } else {
+ cmPassed("CACHE_TEST_VAR3 == ", CACHE_TEST_VAR3);
+ }
+#endif
+
+#ifdef CACHE_TEST_VAR_EXCLUDED
+ cmFailed(
+ "the LOAD_CACHE or CONFIGURE_FILE command or cmakedefine is broken, "
+ "CACHE_TEST_VAR_EXCLUDED is defined (should not have been loaded).");
+#else
+ cmPassed("CACHE_TEST_VAR_EXCLUDED is not defined.");
+#endif
+
+#ifndef CACHE_TEST_VAR_INTERNAL
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR_INTERNAL is not defined.");
+#else
+ std::string cachetest = CACHE_TEST_VAR_INTERNAL;
+ if (cachetest != "bar") {
+ cmFailed("the LOAD_CACHE or CONFIGURE_FILE command is broken, "
+ "CACHE_TEST_VAR_INTERNAL == ",
+ CACHE_TEST_VAR_INTERNAL);
+ } else {
+ cmPassed("CACHE_TEST_VAR_INTERNAL == ", CACHE_TEST_VAR_INTERNAL);
+ }
+#endif
+
+ // ----------------------------------------------------------------------
+ // Some pre-build/pre-link/post-build custom-commands have been
+ // attached to the lib (see Library/).
+ // Each runs ${CREATE_FILE_EXE} which will create a file.
+ // It also copies that file again using cmake -E.
+ // Similar rules have been added to this executable.
+ //
+ // WARNING: if you run 'complex' manually, this *will* fail, because
+ // the file was removed the last time 'complex' was run, and it is
+ // only created during a build.
+
+ TestAndRemoveFile("Library/prebuild.txt");
+ TestAndRemoveFile("Library/prelink.txt");
+ TestAndRemoveFile("Library/postbuild.txt");
+ TestAndRemoveFile("Library/postbuild2.txt");
+ TestAndRemoveFile("Executable/prebuild.txt");
+ TestAndRemoveFile("Executable/prelink.txt");
+ TestAndRemoveFile("Executable/postbuild.txt");
+ TestAndRemoveFile("Executable/postbuild2.txt");
+
+ // ----------------------------------------------------------------------
+ // A custom target has been created (see Library/).
+ // It runs ${CREATE_FILE_EXE} which will create a file.
+ //
+ // WARNING: if you run 'complex' manually, this *will* fail, because
+ // the file was removed the last time 'complex' was run, and it is
+ // only created during a build.
+
+ TestAndRemoveFile("Library/custom_target1.txt");
+
+ // ----------------------------------------------------------------------
+ // A directory has been created.
+
+ TestDir("make_dir");
+
+ // ----------------------------------------------------------------------
+ // Test OUTPUT_REQUIRED_FILES
+ // The files required by 'complex' have been output to a file.
+ // The contents of this file is not tested (absolute paths).
+ //
+ // WARNING: if you run 'complex' manually, this *will* fail, because
+ // the file was removed the last time 'complex' was run, and it is
+ // only created during a build.
+
+ TestAndRemoveFile("Executable/Temp/complex-required.txt");
+
+ // ----------------------------------------------------------------------
+ // Test FIND_LIBRARY
+
+#ifndef FIND_DUMMY_LIB
+ cmFailed("the CONFIGURE_FILE command is broken, "
+ "FIND_DUMMY_LIB is not defined.");
+#else
+ if (strstr(FIND_DUMMY_LIB, "dummylib") == NULL) {
+ cmFailed("the FIND_LIBRARY or CONFIGURE_FILE command is broken, "
+ "FIND_DUMMY_LIB == ",
+ FIND_DUMMY_LIB);
+ } else {
+ cmPassed("FIND_DUMMY_LIB == ", FIND_DUMMY_LIB);
+ }
+#endif
+
+ // ----------------------------------------------------------------------
+ // Test SET_SOURCE_FILES_PROPERTIES
+
+#ifndef FILE_HAS_EXTRA_COMPILE_FLAGS
+ cmFailed("SET_SOURCE_FILES_PROPERTIES failed at setting "
+ "FILE_HAS_EXTRA_COMPILE_FLAGS flag");
+#else
+ cmPassed("SET_SOURCE_FILES_PROPERTIES succeeded in setting "
+ "FILE_HAS_EXTRA_COMPILE_FLAGS flag");
+#endif
+
+#if 0 // Disable until implemented everywhere.
+# ifndef FILE_DEFINE_STRING
+ cmFailed("SET_SOURCE_FILES_PROPERTIES failed at setting FILE_DEFINE_STRING flag");
+# else
+ if(strcmp(FILE_DEFINE_STRING, "hello") != 0)
+ {
+ cmFailed("SET_SOURCE_FILES_PROPERTIES failed at setting FILE_DEFINE_STRING flag correctly");
+ }
+ else
+ {
+ cmPassed("SET_SOURCE_FILES_PROPERTIES succeeded in setting FILE_DEFINE_STRING flag");
+ }
+# endif
+#endif
+
+#ifndef FILE_HAS_ABSTRACT
+ cmFailed("SET_SOURCE_FILES_PROPERTIES failed at setting ABSTRACT flag");
+#else
+ cmPassed("SET_SOURCE_FILES_PROPERTIES succeeded in setting ABSTRACT flag");
+#endif
+
+#ifndef FILE_HAS_WRAP_EXCLUDE
+ cmFailed("FILE_HAS_WRAP_EXCLUDE failed at setting WRAP_EXCLUDE flag");
+#else
+ cmPassed("FILE_HAS_WRAP_EXCLUDE succeeded in setting WRAP_EXCLUDE flag");
+#endif
+
+#ifndef FILE_COMPILE_FLAGS
+ cmFailed("the CONFIGURE_FILE command is broken, FILE_COMPILE_FLAGS is not "
+ "defined.");
+#else
+ if (strcmp(FILE_COMPILE_FLAGS, "-foo -bar") != 0) {
+ cmFailed("the SET_SOURCE_FILES_PROPERTIES or CONFIGURE_FILE command is "
+ "broken. FILE_COMPILE_FLAGS == ",
+ FILE_COMPILE_FLAGS);
+ } else {
+ cmPassed(
+ "SET_SOURCE_FILES_PROPERTIES succeeded in setting extra flags == ",
+ FILE_COMPILE_FLAGS);
+ }
+#endif
+
+// ----------------------------------------------------------------------
+// Test registry (win32)
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# ifndef REGISTRY_TEST_PATH
+ cmFailed("the CONFIGURE_FILE command is broken, REGISTRY_TEST_PATH is not "
+ "defined.");
+# else
+ std::cout << "REGISTRY_TEST_PATH == " << REGISTRY_TEST_PATH << "\n";
+ if (stricmp(REGISTRY_TEST_PATH, BINARY_DIR "/registry_dir") != 0) {
+ cmFailed("the 'read registry value' function or CONFIGURE_FILE command is "
+ "broken. REGISTRY_TEST_PATH == ",
+ REGISTRY_TEST_PATH, " is not " BINARY_DIR "/registry_dir");
+ } else {
+ cmPassed("REGISTRY_TEST_PATH == ", REGISTRY_TEST_PATH);
+ }
+# endif
+#endif // defined(_WIN32) && !defined(__CYGWIN__)
+
+ if (strcmp(CMAKE_MINIMUM_REQUIRED_VERSION, "2.4") == 0) {
+ cmPassed("CMAKE_MINIMUM_REQUIRED_VERSION is set to 2.4");
+ } else {
+ cmFailed("CMAKE_MINIMUM_REQUIRED_VERSION is not set to the expected 2.4");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test REMOVE command
+ if (strcmp("a;b;d", REMOVE_STRING) == 0) {
+ cmPassed("REMOVE is working");
+ } else {
+ cmFailed("REMOVE is not working");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test SEPARATE_ARGUMENTS
+ if (strcmp("a;b;c", TEST_SEP) == 0) {
+ cmPassed("SEPARATE_ARGUMENTS is working");
+ } else {
+ cmFailed("SEPARATE_ARGUMENTS is not working");
+ }
+
+ // ----------------------------------------------------------------------
+ // Test Escape Quotes
+ if (strcmp("\"hello world\"", STRING_WITH_QUOTES) == 0) {
+ cmPassed("ESCAPE_QUOTES is working");
+ } else {
+ cmFailed("ESCAPE_QUOTES is not working");
+ }
+
+// ----------------------------------------------------------------------
+// Test if IF command inside a FOREACH works.
+#if defined(IF_INSIDE_FOREACH_THEN_EXECUTED) && \
+ !defined(IF_INSIDE_FOREACH_ELSE_EXECUTED)
+ cmPassed("IF inside a FOREACH block works");
+#else
+ cmFailed("IF inside a FOREACH block is broken");
+#endif
+
+#if defined(GENERATED_HEADER_INCLUDED)
+ cmPassed("Generated header included by non-generated source works.");
+#else
+ cmFailed("Generated header included by non-generated source failed.");
+#endif
+ if (SHOULD_BE_ZERO == 0) {
+ cmPassed("cmakedefine01 is working for 0");
+ } else {
+ cmFailed("cmakedefine01 is not working for 0");
+ }
+ if (SHOULD_BE_ONE == 1) {
+ cmPassed("cmakedefine01 is working for 1");
+ } else {
+ cmFailed("cmakedefine01 is not working for 1");
+ }
+ if (SHOULD_BE_ZERO_AND_INDENTED == 0) {
+ cmPassed("cmakedefine01 is working for 0 and indented");
+ } else {
+ cmFailed("cmakedefine01 is not working for 0 and indented");
+ }
+ if (SHOULD_BE_ONE_AND_INDENTED == 1) {
+ cmPassed("cmakedefine01 is working for 1 and indented");
+ } else {
+ cmFailed("cmakedefine01 is not working for 1 and indented");
+ }
+#ifdef FORCE_TEST
+ cmFailed("CMake SET CACHE FORCE");
+#else
+ cmPassed("CMake SET CACHE FORCE");
+#endif
+
+#ifdef COMPLEX_TEST_LINK_STATIC
+ if (TestLinkGetType()) {
+ cmPassed("Link to static over shared worked.");
+ } else {
+ cmFailed("Link to static over shared failed.");
+ }
+#endif
+
+#if defined(A_VALUE) && A_VALUE == 10
+ cmPassed("Single-character executable A worked.");
+#else
+ cmFailed("Single-character executable A failed.");
+#endif
+
+ // ----------------------------------------------------------------------
+ // Summary
+
+ std::cout << "Passed: " << cm_passed << "\n";
+ if (cm_failed) {
+ std::cout << "Failed: " << cm_failed << "\n";
+ return cm_failed;
+ }
+ return 0;
+}
diff --git a/Tests/ComplexOneConfig/Executable/complex.file.cxx b/Tests/ComplexOneConfig/Executable/complex.file.cxx
new file mode 100644
index 0000000..5596430
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/complex.file.cxx
@@ -0,0 +1,8 @@
+#if 0
+# include "cmMissingHeader.h"
+#endif
+
+int main(int, char**)
+{
+ return 0;
+}
diff --git a/Tests/ComplexOneConfig/Executable/complex_nobuild.c b/Tests/ComplexOneConfig/Executable/complex_nobuild.c
new file mode 100644
index 0000000..6b3c2c1
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/complex_nobuild.c
@@ -0,0 +1 @@
+#error "This file should not be compiled."
diff --git a/Tests/ComplexOneConfig/Executable/complex_nobuild.cxx b/Tests/ComplexOneConfig/Executable/complex_nobuild.cxx
new file mode 100644
index 0000000..6b3c2c1
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/complex_nobuild.cxx
@@ -0,0 +1 @@
+#error "This file should not be compiled."
diff --git a/Tests/ComplexOneConfig/Executable/notInAllExe.cxx b/Tests/ComplexOneConfig/Executable/notInAllExe.cxx
new file mode 100644
index 0000000..2b857b4
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/notInAllExe.cxx
@@ -0,0 +1,10 @@
+extern int notInAllLibFunc();
+
+int main()
+{
+ return notInAllLibFunc();
+}
+
+#if 1
+# error "This target should not be compiled by ALL."
+#endif
diff --git a/Tests/ComplexOneConfig/Executable/testSystemDir.cxx b/Tests/ComplexOneConfig/Executable/testSystemDir.cxx
new file mode 100644
index 0000000..4bb2db4
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/testSystemDir.cxx
@@ -0,0 +1,6 @@
+#include <testSystemDir.h>
+
+int main()
+{
+ return foo();
+}
diff --git a/Tests/ComplexOneConfig/Executable/testcflags.c b/Tests/ComplexOneConfig/Executable/testcflags.c
new file mode 100644
index 0000000..e452b06
--- /dev/null
+++ b/Tests/ComplexOneConfig/Executable/testcflags.c
@@ -0,0 +1,26 @@
+#include <string.h>
+
+int TestTargetCompileFlags(char* m)
+{
+#ifndef COMPLEX_TARGET_FLAG
+ strcpy(m, "CMAKE SET_TARGET_PROPERTIES COMPILE_FLAGS did not work");
+ return 0;
+#endif
+ strcpy(m, "CMAKE SET_TARGET_PROPERTIES COMPILE_FLAGS worked");
+ return 1;
+}
+
+int TestCFlags(char* m)
+{
+/* TEST_CXX_FLAGS should not be defined in a c file */
+#ifdef TEST_CXX_FLAGS
+ strcpy(m, "CMake CMAKE_CXX_FLAGS (TEST_CXX_FLAGS) found in c file.");
+ return 0;
+#endif
+/* TEST_C_FLAGS should be defined in a c file */
+#ifndef TEST_C_FLAGS
+ strcpy(m, "CMake CMAKE_C_FLAGS (TEST_C_FLAGS) not found in c file.");
+ return 0;
+#endif
+ return 1;
+}
diff --git a/Tests/ComplexOneConfig/Library/CMakeLists.txt b/Tests/ComplexOneConfig/Library/CMakeLists.txt
new file mode 100644
index 0000000..df874ef
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/CMakeLists.txt
@@ -0,0 +1,140 @@
+remove_definitions(-DCMAKE_IS_REALLY_FUN)
+
+#
+# Small utility used to create file
+# UTILITY_SOURCE is used for coverage and for getting the exact name
+# of the executable.
+#
+utility_source(CREATE_FILE_EXE create_file "." create_file.cxx)
+add_executable(create_file create_file.cxx)
+set_target_properties(create_file PROPERTIES RUNTIME_OUTPUT_DIRECTORY ".")
+
+#
+# Create static library
+# SOURCE_FILES_REMOVE is used for Coverage. empty.h is included for coverage
+#
+aux_source_directory(ExtraSources LibrarySources)
+set(LibrarySources ${LibrarySources}
+ file2
+ empty
+ create_file.cxx
+ GENERATED
+ nonexisting_file)
+remove(LibrarySources create_file.cxx GENERATED nonexisting_file)
+add_library(CMakeTestLibrary ${LibrarySources})
+
+if(WIN32)
+ if(NOT CYGWIN)
+ if(NOT BORLAND)
+ if(NOT MINGW)
+ target_link_libraries(CMakeTestLibrary
+ debug
+ user32.lib)
+ target_link_libraries(CMakeTestLibrary
+ optimized
+ kernel32.lib)
+ endif()
+ endif()
+ endif()
+endif()
+
+#
+# Create shared library
+#
+set(SharedLibrarySources sharedFile)
+add_library(CMakeTestLibraryShared SHARED ${SharedLibrarySources})
+string(APPEND CMAKE_C_FLAGS " -DTEST_C_FLAGS")
+add_library(CMakeTestCLibraryShared SHARED testConly.c)
+define_property(
+ TARGET PROPERTY FOO
+ BRIEF_DOCS "a test property"
+ FULL_DOCS "A simple test property that means nothing and is used for nothing"
+ )
+set_target_properties(CMakeTestCLibraryShared PROPERTIES FOO BAR)
+if(NOT BEOS AND NOT WIN32 AND NOT HAIKU) # No libm on BeOS.
+ set_target_properties(CMakeTestCLibraryShared PROPERTIES LINK_FLAGS "-lm")
+endif()
+get_target_property(FOO_BAR_VAR CMakeTestCLibraryShared FOO)
+if(${FOO_BAR_VAR} MATCHES "BAR")
+else()
+ message(SEND_ERROR "SET_TARGET_PROPERTIES or GET_TARGET_PROPERTY failed, FOO_BAR_VAR should be BAR, but is ${FOO_BAR_VAR}")
+endif()
+
+# Create static and shared lib of same name.
+if(CMAKE_EXE_LINK_STATIC_CXX_FLAGS)
+ add_library(CMakeTestLinkStatic STATIC TestLink.c)
+ add_library(CMakeTestLinkShared SHARED TestLink.c)
+ set_target_properties(CMakeTestLinkStatic CMakeTestLinkShared
+ PROPERTIES OUTPUT_NAME CMakeTestLink)
+endif()
+
+#
+# Attach pre-build/pre-link/post-build custom-commands to the lib.
+# Each runs ${CREATE_FILE_EXE} which will create a file.
+# The 'complex' executable will then test if this file exists and remove it.
+#
+add_dependencies(CMakeTestLibraryShared create_file)
+message("complex bin dir is ${Complex_BINARY_DIR}")
+add_custom_command(TARGET CMakeTestLibraryShared PRE_BUILD
+ COMMAND ${CREATE_FILE_EXE}
+ ARGS "${Complex_BINARY_DIR}/Library/prebuild.txt")
+add_custom_command(TARGET CMakeTestLibraryShared PRE_BUILD
+ COMMAND ${CREATE_FILE_EXE}
+ ARGS "${Complex_BINARY_DIR}/Library/prelink.txt")
+add_custom_command(TARGET CMakeTestLibraryShared POST_BUILD
+ COMMAND ${CREATE_FILE_EXE}
+ ARGS "${Complex_BINARY_DIR}/Library/postbuild.txt")
+add_custom_command(TARGET CMakeTestLibraryShared POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy
+ "${Complex_BINARY_DIR}/Library/postbuild.txt"
+ "${Complex_BINARY_DIR}/Library/postbuild2.txt")
+
+#
+# Add a custom target.
+# It runs ${CREATE_FILE_EXE} which will create a file.
+# The 'complex' executable will then test if this file exists and remove it.
+#
+add_custom_target(custom_target1
+ ALL
+ ${CREATE_FILE_EXE}
+ "${Complex_BINARY_DIR}/Library/custom_target1.txt")
+
+add_dependencies(custom_target1 create_file)
+
+#
+# Extra coverage
+#
+set_source_files_properties(file2 PROPERTIES ABSTRACT 1)
+
+install_files(/tmp .h ${Complex_BINARY_DIR}/cmTestConfigure.h)
+install_files(/tmp .cxx ${Complex_BINARY_DIR}/cmTestConfigure.h)
+
+# Test creating a library that is not built by default.
+add_library(notInAllLib EXCLUDE_FROM_ALL notInAllLib.cxx)
+
+# Create an imported target for if(TARGET) test in Executable dir.
+# That test should not see this target.
+add_library(LibImportedTarget UNKNOWN IMPORTED)
+
+# Test generation of preprocessed sources.
+if("${CMAKE_GENERATOR}" MATCHES "Makefile" AND CMAKE_MAKE_PROGRAM)
+ if(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE)
+ # Skip running this part of the test on certain platforms
+ # until they are fixed.
+ set(MAYBE_ALL ALL)
+ list(LENGTH CMAKE_OSX_ARCHITECTURES ARCH_COUNT)
+ if(ARCH_COUNT GREATER 1)
+ # OSX does not support preprocessing more than one architecture.
+ set(MAYBE_ALL)
+ endif()
+
+ # Custom target to try preprocessing invocation.
+ add_custom_target(test_preprocess ${MAYBE_ALL}
+ COMMAND ${CMAKE_COMMAND} -E rm -f CMakeFiles/create_file.dir/create_file.i
+ COMMAND ${CMAKE_MAKE_PROGRAM} create_file.i
+ COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/test_preprocess.cmake
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ )
+ endif()
+endif()
diff --git a/Tests/ComplexOneConfig/Library/ExtraSources/file1.cxx b/Tests/ComplexOneConfig/Library/ExtraSources/file1.cxx
new file mode 100644
index 0000000..e22812e
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/ExtraSources/file1.cxx
@@ -0,0 +1,4 @@
+int file1()
+{
+ return 1;
+}
diff --git a/Tests/ComplexOneConfig/Library/ExtraSources/file1.h b/Tests/ComplexOneConfig/Library/ExtraSources/file1.h
new file mode 100644
index 0000000..ce0d818
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/ExtraSources/file1.h
@@ -0,0 +1 @@
+int file1();
diff --git a/Tests/ComplexOneConfig/Library/SystemDir/testSystemDir.h b/Tests/ComplexOneConfig/Library/SystemDir/testSystemDir.h
new file mode 100644
index 0000000..074ff75
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/SystemDir/testSystemDir.h
@@ -0,0 +1,5 @@
+// Purposely leave off the return type to create a warning.
+foo()
+{
+ return 0;
+}
diff --git a/Tests/ComplexOneConfig/Library/TestLink.c b/Tests/ComplexOneConfig/Library/TestLink.c
new file mode 100644
index 0000000..25dee08
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/TestLink.c
@@ -0,0 +1,8 @@
+int TestLinkGetType()
+{
+#ifdef CMakeTestLinkShared_EXPORTS
+ return 0;
+#else
+ return 1;
+#endif
+}
diff --git a/Tests/ComplexOneConfig/Library/create_file.cxx b/Tests/ComplexOneConfig/Library/create_file.cxx
new file mode 100644
index 0000000..62a1975
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/create_file.cxx
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "Missing name of file to create.\n");
+ return EXIT_FAILURE;
+ }
+
+ FILE* stream = fopen(argv[1], "w");
+ if (stream == NULL) {
+ fprintf(stderr, "Unable to open %s for writing!\n", argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ if (fclose(stream)) {
+ fprintf(stderr, "Unable to close %s!\n", argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ fprintf(stdout, ">> Creating %s!\n", argv[1]);
+
+ return EXIT_SUCCESS;
+}
diff --git a/Tests/ComplexOneConfig/Library/dummy b/Tests/ComplexOneConfig/Library/dummy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/dummy
diff --git a/Tests/ComplexOneConfig/Library/empty.h b/Tests/ComplexOneConfig/Library/empty.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/empty.h
diff --git a/Tests/ComplexOneConfig/Library/file2.cxx b/Tests/ComplexOneConfig/Library/file2.cxx
new file mode 100644
index 0000000..863fcaa
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/file2.cxx
@@ -0,0 +1,10 @@
+#include <string.h>
+
+#ifdef CMAKE_IS_REALLY_FUN
+This is a problem. Looks like REMOVE_DEFINITION does not work
+#endif
+
+int file2()
+{
+ return 1;
+}
diff --git a/Tests/ComplexOneConfig/Library/file2.h b/Tests/ComplexOneConfig/Library/file2.h
new file mode 100644
index 0000000..dea4b80
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/file2.h
@@ -0,0 +1 @@
+int file2();
diff --git a/Tests/ComplexOneConfig/Library/notInAllLib.cxx b/Tests/ComplexOneConfig/Library/notInAllLib.cxx
new file mode 100644
index 0000000..033988f
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/notInAllLib.cxx
@@ -0,0 +1,8 @@
+int notInAllLibFunc()
+{
+ return 0;
+}
+
+#if 1
+# error "This target should not be compiled by ALL."
+#endif
diff --git a/Tests/ComplexOneConfig/Library/sharedFile.cxx b/Tests/ComplexOneConfig/Library/sharedFile.cxx
new file mode 100644
index 0000000..cafac68
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/sharedFile.cxx
@@ -0,0 +1,6 @@
+#include "sharedFile.h"
+
+int sharedFunction()
+{
+ return 1;
+}
diff --git a/Tests/ComplexOneConfig/Library/sharedFile.h b/Tests/ComplexOneConfig/Library/sharedFile.h
new file mode 100644
index 0000000..830cbd5
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/sharedFile.h
@@ -0,0 +1,12 @@
+#if defined(_WIN32) || defined(WIN32) /* Win32 version */
+# ifdef CMakeTestLibraryShared_EXPORTS
+# define CMakeTest_EXPORT __declspec(dllexport)
+# else
+# define CMakeTest_EXPORT __declspec(dllimport)
+# endif
+#else
+/* unix needs nothing */
+# define CMakeTest_EXPORT
+#endif
+
+CMakeTest_EXPORT int sharedFunction();
diff --git a/Tests/ComplexOneConfig/Library/testConly.c b/Tests/ComplexOneConfig/Library/testConly.c
new file mode 100644
index 0000000..eb933a2
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/testConly.c
@@ -0,0 +1,14 @@
+#include "testConly.h"
+
+#include <stdio.h>
+
+int CsharedFunction()
+{
+#ifndef TEST_C_FLAGS
+ printf("TEST_C_FLAGS failed\n");
+ return 0;
+#else
+ printf("Passed: TEST_C_FLAGS passed\n");
+#endif
+ return 1;
+}
diff --git a/Tests/ComplexOneConfig/Library/testConly.h b/Tests/ComplexOneConfig/Library/testConly.h
new file mode 100644
index 0000000..02b28cc
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/testConly.h
@@ -0,0 +1,12 @@
+#if defined(_WIN32) || defined(WIN32) /* Win32 version */
+# ifdef CMakeTestCLibraryShared_EXPORTS
+# define CMakeTest_EXPORT __declspec(dllexport)
+# else
+# define CMakeTest_EXPORT __declspec(dllimport)
+# endif
+#else
+/* unix needs nothing */
+# define CMakeTest_EXPORT
+#endif
+
+CMakeTest_EXPORT int CsharedFunction();
diff --git a/Tests/ComplexOneConfig/Library/test_preprocess.cmake b/Tests/ComplexOneConfig/Library/test_preprocess.cmake
new file mode 100644
index 0000000..4c8ec21
--- /dev/null
+++ b/Tests/ComplexOneConfig/Library/test_preprocess.cmake
@@ -0,0 +1,7 @@
+set(TEST_FILE CMakeFiles/create_file.dir/create_file.i)
+file(READ ${TEST_FILE} CONTENTS)
+if("${CONTENTS}" MATCHES "Unable to close")
+ message(STATUS "${TEST_FILE} created successfully!")
+else()
+ message(FATAL_ERROR "${TEST_FILE} creation failed!")
+endif()
diff --git a/Tests/ComplexOneConfig/VarTests.cmake b/Tests/ComplexOneConfig/VarTests.cmake
new file mode 100644
index 0000000..42afd19
--- /dev/null
+++ b/Tests/ComplexOneConfig/VarTests.cmake
@@ -0,0 +1,258 @@
+#
+# Test SET
+#
+set (ZERO_VAR 0)
+set (ZERO_VAR_AND_INDENTED 0)
+set (ZERO_VAR2 0)
+
+if(ZERO_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED)
+else()
+ add_definitions(-DSHOULD_BE_DEFINED)
+endif()
+
+set(ONE_VAR 1)
+set(ONE_VAR_AND_INDENTED 1)
+set(ONE_VAR2 1)
+set(STRING_VAR "CMake is great" CACHE STRING "test a cache variable")
+
+#
+# Test VARIABLE_REQUIRES
+#
+variable_requires(ONE_VAR
+ ONE_VAR_IS_DEFINED ONE_VAR)
+
+#
+# Test various IF/ELSE combinations
+#
+if(NOT ZERO_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_NOT)
+else()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_NOT)
+endif()
+
+if(NOT ONE_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_NOT2)
+else()
+ add_definitions(-DSHOULD_BE_DEFINED_NOT2)
+endif()
+
+if(ONE_VAR AND ONE_VAR2)
+ add_definitions(-DSHOULD_BE_DEFINED_AND)
+else()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_AND)
+endif()
+
+if(ONE_VAR AND ZERO_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_AND2)
+else()
+ add_definitions(-DSHOULD_BE_DEFINED_AND2)
+endif()
+
+if(ZERO_VAR OR ONE_VAR2)
+ add_definitions(-DSHOULD_BE_DEFINED_OR)
+else()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_OR)
+endif()
+
+if(ZERO_VAR OR ZERO_VAR2)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_OR2)
+else()
+ add_definitions(-DSHOULD_BE_DEFINED_OR2)
+endif()
+
+if(STRING_VAR MATCHES "^CMake")
+ add_definitions(-DSHOULD_BE_DEFINED_MATCHES)
+else()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_MATCHES)
+endif()
+
+if(STRING_VAR MATCHES "^foo")
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_MATCHES2)
+else()
+ add_definitions(-DSHOULD_BE_DEFINED_MATCHES2)
+endif()
+
+if(COMMAND "IF")
+ add_definitions(-DSHOULD_BE_DEFINED_COMMAND)
+else()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_COMMAND)
+endif()
+
+if(COMMAND "ROQUEFORT")
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_COMMAND2)
+else()
+ add_definitions(-DSHOULD_BE_DEFINED_COMMAND2)
+endif()
+
+if (EXISTS ${Complex_SOURCE_DIR}/VarTests.cmake)
+ add_definitions(-DSHOULD_BE_DEFINED_EXISTS)
+else()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_EXISTS)
+endif ()
+
+if (EXISTS ${Complex_SOURCE_DIR}/roquefort.txt)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_EXISTS2)
+else()
+ add_definitions(-DSHOULD_BE_DEFINED_EXISTS2)
+endif ()
+
+if (IS_DIRECTORY ${Complex_SOURCE_DIR})
+ add_definitions(-DSHOULD_BE_DEFINED_IS_DIRECTORY)
+endif ()
+
+if (NOT IS_DIRECTORY ${Complex_SOURCE_DIR}/VarTests.cmake)
+ add_definitions(-DSHOULD_BE_DEFINED_IS_DIRECTORY2)
+endif ()
+
+set (SNUM1_VAR "1")
+set (SNUM2_VAR "2")
+set (SNUM3_VAR "1")
+
+
+if (SNUM1_VAR LESS SNUM2_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_LESS)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS)
+endif ()
+
+if (SNUM2_VAR LESS SNUM1_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_LESS2)
+endif ()
+
+if (SNUM2_VAR GREATER SNUM1_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_GREATER)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER)
+endif ()
+
+if (SNUM1_VAR GREATER SNUM2_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_GREATER2)
+endif ()
+
+if (SNUM2_VAR EQUAL SNUM1_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_EQUAL)
+endif ()
+
+if (SNUM3_VAR EQUAL SNUM1_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_EQUAL)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_EQUAL)
+endif ()
+
+if (SNUM1_VAR LESS_EQUAL SNUM2_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL)
+endif ()
+
+if (SNUM2_VAR LESS_EQUAL SNUM1_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL2)
+endif ()
+
+if (SNUM1_VAR LESS_EQUAL SNUM3_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_LESS_EQUAL3)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_LESS_EQUAL3)
+endif ()
+
+if (SNUM2_VAR GREATER_EQUAL SNUM1_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL)
+endif ()
+
+if (SNUM1_VAR GREATER_EQUAL SNUM2_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL2)
+endif ()
+
+if (SNUM1_VAR GREATER_EQUAL SNUM3_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_GREATER_EQUAL3)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_GREATER_EQUAL3)
+endif ()
+
+set (SSTR1_VAR "abc")
+set (SSTR2_VAR "bcd")
+
+if (SSTR1_VAR STRLESS SSTR2_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_STRLESS)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS)
+endif ()
+
+if (SSTR2_VAR STRLESS SSTR1_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_STRLESS2)
+endif ()
+
+if (SSTR2_VAR STRGREATER SSTR1_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_STRGREATER)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER)
+endif ()
+
+if (SSTR1_VAR STRGREATER SSTR2_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_STRGREATER2)
+endif ()
+
+if (SSTR1_VAR STRLESS_EQUAL SSTR2_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL)
+endif ()
+
+if (SSTR2_VAR STRLESS_EQUAL SSTR1_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL2)
+endif ()
+
+if (SSTR1_VAR STRLESS_EQUAL SSTR1_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_STRLESS_EQUAL3)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRLESS_EQUAL3)
+endif ()
+
+if (SSTR2_VAR STRGREATER_EQUAL SSTR1_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL)
+endif ()
+
+if (SSTR1_VAR STRGREATER_EQUAL SSTR2_VAR)
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL2)
+else ()
+ add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL2)
+endif ()
+
+if (SSTR1_VAR STRGREATER_EQUAL SSTR1_VAR)
+ add_definitions(-DSHOULD_BE_DEFINED_STRGREATER_EQUAL3)
+else ()
+ add_definitions(-DSHOULD_NOT_BE_DEFINED_STRGREATER_EQUAL3)
+endif ()
+
+#
+# Test FOREACH
+#
+foreach (INDEX 1 2)
+ set(FOREACH_VAR${INDEX} "VALUE${INDEX}")
+endforeach()
+
+set(FOREACH_CONCAT "")
+foreach (INDEX a;b;c;d;e;f;g)
+ string(APPEND FOREACH_CONCAT "${INDEX}")
+endforeach()
diff --git a/Tests/ComplexOneConfig/cmTestConfigure.h.in b/Tests/ComplexOneConfig/cmTestConfigure.h.in
new file mode 100644
index 0000000..72317bc
--- /dev/null
+++ b/Tests/ComplexOneConfig/cmTestConfigure.h.in
@@ -0,0 +1,80 @@
+// Test SET, VARIABLE_REQUIRES
+
+#cmakedefine ONE_VAR
+# cmakedefine ONE_VAR_AND_INDENTED
+#cmakedefine ONE_VAR_IS_DEFINED
+#cmakedefine ZERO_VAR
+# cmakedefine ZERO_VAR_AND_INDENTED
+
+#define STRING_VAR "${STRING_VAR}"
+
+// Test FOREACH
+
+#define FOREACH_VAR1 "${FOREACH_VAR1}"
+#define FOREACH_VAR2 "${FOREACH_VAR2}"
+#define FOREACH_CONCAT "${FOREACH_CONCAT}"
+
+// Test WHILE
+#define WHILE_VALUE ${while_var}
+
+// Test LOAD_CACHE
+
+#define CACHE_TEST_VAR1 "${CACHE_TEST_VAR1}"
+#define CACHE_TEST_VAR2 "${CACHE_TEST_VAR2}"
+#define CACHE_TEST_VAR3 "${CACHE_TEST_VAR3}"
+#cmakedefine CACHE_TEST_VAR_EXCLUDED
+#define CACHE_TEST_VAR_INTERNAL "${CACHE_TEST_VAR_INTERNAL}"
+
+// Test internal CMake vars from C++ flags
+
+#cmakedefine CMAKE_NO_STD_NAMESPACE
+#cmakedefine CMAKE_NO_ANSI_STREAM_HEADERS
+#cmakedefine CMAKE_NO_ANSI_STRING_STREAM
+#cmakedefine CMAKE_NO_ANSI_FOR_SCOPE
+
+#cmakedefine01 SHOULD_BE_ZERO
+#cmakedefine01 SHOULD_BE_ONE
+# cmakedefine01 SHOULD_BE_ZERO_AND_INDENTED
+# cmakedefine01 SHOULD_BE_ONE_AND_INDENTED
+// Needed to check for files
+
+#define BINARY_DIR "${Complex_BINARY_DIR}"
+
+// Test FIND_LIBRARY
+
+#define FIND_DUMMY_LIB "${FIND_DUMMY_LIB}"
+
+// Test SET_SOURCE_FILES_PROPERTIES
+
+#cmakedefine FILE_HAS_ABSTRACT
+#cmakedefine FILE_HAS_WRAP_EXCLUDE
+#define FILE_COMPILE_FLAGS "${FILE_COMPILE_FLAGS}"
+
+#define TEST_SEP "${TEST_SEP}"
+
+// Test registry read
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#define REGISTRY_TEST_PATH "${REGISTRY_TEST_PATH}"
+#endif
+
+// Test Remove command
+#define REMOVE_STRING "${REMOVE_STRING}"
+
+// Test IF inside FOREACH
+#cmakedefine IF_INSIDE_FOREACH_THEN_EXECUTED
+#cmakedefine IF_INSIDE_FOREACH_ELSE_EXECUTED
+
+// Test SET CACHE FORCE
+#cmakedefine FORCE_TEST
+#define CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+
+#define CMAKE_SHARED_MODULE_PREFIX "${CMAKE_SHARED_MODULE_PREFIX}"
+#define CMAKE_SHARED_MODULE_SUFFIX "${CMAKE_SHARED_MODULE_SUFFIX}"
+
+// test elseif
+#cmakedefine ELSEIF_RESULT
+
+// test parenthesis in conditionals
+#cmakedefine CONDITIONAL_PARENTHESES
+
diff --git a/Tests/ComplexOneConfig/cmTestConfigureEscape.h.in b/Tests/ComplexOneConfig/cmTestConfigureEscape.h.in
new file mode 100644
index 0000000..39a8bd6
--- /dev/null
+++ b/Tests/ComplexOneConfig/cmTestConfigureEscape.h.in
@@ -0,0 +1 @@
+#define STRING_WITH_QUOTES "${STRING_WITH_QUOTES}"
diff --git a/Tests/ComplexOneConfig/cmTestGeneratedHeader.h.in b/Tests/ComplexOneConfig/cmTestGeneratedHeader.h.in
new file mode 100644
index 0000000..0e9dd3f
--- /dev/null
+++ b/Tests/ComplexOneConfig/cmTestGeneratedHeader.h.in
@@ -0,0 +1 @@
+#define GENERATED_HEADER_INCLUDED
diff --git a/Tests/ConfigSources/CMakeLists.txt b/Tests/ConfigSources/CMakeLists.txt
new file mode 100644
index 0000000..38475f8
--- /dev/null
+++ b/Tests/ConfigSources/CMakeLists.txt
@@ -0,0 +1,179 @@
+cmake_minimum_required(VERSION 3.0)
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+
+if(NOT _isMultiConfig AND NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build" FORCE)
+endif()
+project(ConfigSources CXX)
+
+if("${CMAKE_CXX_COMPILER_ID};${CMAKE_CXX_SIMULATE_ID}" STREQUAL "Intel;MSVC")
+ string(APPEND CMAKE_CXX_FLAGS_DEBUG " -Z7")
+ string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -Z7")
+endif()
+
+# Source file(s) named with the configuration(s).
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/config_$<CONFIG>.cpp"
+ CONTENT [[
+#if defined(_WIN32) && defined(OBJ_SHARED)
+__declspec(dllexport)
+#endif
+void config_$<CONFIG>() {}
+]]
+ )
+
+# Custom command outputs named with the configuration(s).
+add_custom_command(
+ OUTPUT "custom1_$<CONFIG>.cpp"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom1.cpp.in" "custom1_$<CONFIG>.cpp"
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom1.cpp.in
+ VERBATIM
+ )
+# Output path starts in a generator expression.
+add_custom_command(
+ OUTPUT "$<1:custom2_$<CONFIG>.cpp>"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom2.cpp.in" "custom2_$<CONFIG>.cpp"
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom2.cpp.in
+ VERBATIM
+ )
+# Source file generated as a custom command's byproduct.
+add_custom_command(
+ OUTPUT custom3.txt
+ BYPRODUCTS "$<1:custom3_$<CONFIG>.cpp>"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom3.cpp.in" "custom3_$<CONFIG>.cpp"
+ COMMAND ${CMAKE_COMMAND} -E touch custom3.txt
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom3.cpp.in
+ VERBATIM
+ )
+# Source file generated as a custom target's byproduct.
+add_custom_target(custom4
+ BYPRODUCTS "custom4_$<CONFIG>.cpp"
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/custom4.cpp.in" "custom4_$<CONFIG>.cpp"
+ VERBATIM
+ )
+# Source file generated by appended custom command.
+add_custom_command(
+ OUTPUT "custom5_$<CONFIG>.cpp"
+ COMMAND ${CMAKE_COMMAND} -E echo custom5_$<CONFIG>.cpp
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom5.cpp.in
+ VERBATIM
+ )
+add_custom_command(APPEND
+ OUTPUT "custom5_$<CONFIG>.cpp"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom5.cpp.in" "custom5_$<CONFIG>.cpp.in"
+ VERBATIM
+ )
+# Appending through any configuration's output affects all configurations.
+if(CMAKE_CONFIGURATION_TYPES MATCHES ";([^;]+)$")
+ set(last_config "${CMAKE_MATCH_1}")
+else()
+ set(last_config ${CMAKE_BUILD_TYPE})
+endif()
+add_custom_command(APPEND
+ OUTPUT "custom5_${last_config}.cpp"
+ COMMAND ${CMAKE_COMMAND} -E copy "custom5_$<CONFIG>.cpp.in" "custom5_$<CONFIG>.cpp"
+ VERBATIM
+ )
+foreach(n RANGE 1 5)
+ foreach(other ${CMAKE_BUILD_TYPE} Release RelWithDebInfo MinSizeRel)
+ set_property(SOURCE custom${n}_${other}.cpp PROPERTY COMPILE_DEFINITIONS CUSTOM_CFG_OTHER)
+ endforeach()
+ set_property(SOURCE custom${n}_Debug.cpp PROPERTY COMPILE_DEFINITIONS CUSTOM_CFG_DEBUG)
+endforeach()
+add_library(Custom STATIC
+ custom1_$<CONFIG>.cpp
+ custom2_$<CONFIG>.cpp
+ custom3_$<CONFIG>.cpp custom3.txt
+ custom4_$<CONFIG>.cpp
+ custom5_$<CONFIG>.cpp
+ )
+
+# Per-config sources via INTERFACE_SOURCES.
+add_library(iface INTERFACE)
+target_sources(iface INTERFACE
+ "${CMAKE_CURRENT_SOURCE_DIR}/iface_src.cpp"
+ "$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/iface_debug_src.cpp>"
+ "$<$<NOT:$<CONFIG:Debug>>:${CMAKE_CURRENT_SOURCE_DIR}/iface_other_src.cpp>"
+ "$<$<CONFIG:NotAConfig>:${CMAKE_CURRENT_SOURCE_DIR}/does_not_exist.cpp>"
+ )
+target_compile_definitions(iface INTERFACE
+ "$<$<CONFIG:Debug>:CFG_DEBUG>"
+ "$<$<NOT:$<CONFIG:Debug>>:CFG_OTHER>"
+ )
+add_executable(ConfigSources
+ $<$<CONFIG:Debug>:main_debug.cpp>
+ $<$<NOT:$<CONFIG:Debug>>:main_other.cpp>
+ $<$<CONFIG:NotAConfig>:does_not_exist.cpp>
+ ${CMAKE_CURRENT_BINARY_DIR}/config_$<CONFIG>.cpp
+ )
+target_link_libraries(ConfigSources Custom iface)
+
+# Per-config sources via LINK_LIBRARIES.
+add_library(iface_debug INTERFACE)
+target_sources(iface_debug INTERFACE
+ "${CMAKE_CURRENT_SOURCE_DIR}/iface_src.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/iface_debug_src.cpp"
+ )
+add_library(iface_other INTERFACE)
+target_sources(iface_other INTERFACE
+ "${CMAKE_CURRENT_SOURCE_DIR}/iface_src.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/iface_other_src.cpp"
+ )
+add_executable(ConfigSourcesLink main.cpp)
+target_compile_definitions(ConfigSourcesLink PRIVATE
+ "$<$<CONFIG:Debug>:CFG_DEBUG>"
+ "$<$<NOT:$<CONFIG:Debug>>:CFG_OTHER>"
+ )
+target_link_libraries(ConfigSourcesLink PRIVATE
+ Custom
+ "$<$<CONFIG:Debug>:iface_debug>"
+ "$<$<NOT:$<CONFIG:Debug>>:iface_other>"
+ "$<$<CONFIG:NotAConfig>:iface_does_not_exist>"
+ )
+
+# Per-config sources via INTERFACE_LINK_LIBRARIES.
+add_library(ConfigSourcesIface INTERFACE)
+target_link_libraries(ConfigSourcesIface INTERFACE
+ "$<$<CONFIG:Debug>:iface_debug>"
+ "$<$<NOT:$<CONFIG:Debug>>:iface_other>"
+ "$<$<CONFIG:NotAConfig>:iface_does_not_exist>"
+ )
+add_executable(ConfigSourcesLinkIface main.cpp)
+target_compile_definitions(ConfigSourcesLinkIface PRIVATE
+ "$<$<CONFIG:Debug>:CFG_DEBUG>"
+ "$<$<NOT:$<CONFIG:Debug>>:CFG_OTHER>"
+ )
+target_link_libraries(ConfigSourcesLinkIface Custom ConfigSourcesIface)
+
+# A target with sources in only one configuration that is not the
+# first in CMAKE_CONFIGURATION_TYPES.
+if(CMAKE_CONFIGURATION_TYPES MATCHES ";([^;]+)")
+ set(one_config "${CMAKE_MATCH_1}")
+else()
+ set(one_config "${CMAKE_BUILD_TYPE}")
+endif()
+add_library(OneConfigOnly OBJECT "$<$<CONFIG:${one_config}>:${CMAKE_CURRENT_SOURCE_DIR}/iface_src.cpp>")
+set_property(TARGET OneConfigOnly PROPERTY LINKER_LANGUAGE CXX)
+
+
+# ---------------------------------------------------------------------------
+# Makes sure that each configuration uses the correct generated file.
+add_library(ObjLibFromGeneratedSources OBJECT)
+set_property(TARGET ObjLibFromGeneratedSources PROPERTY POSITION_INDEPENDENT_CODE 1)
+target_compile_definitions(ObjLibFromGeneratedSources PRIVATE OBJ_SHARED)
+target_sources(ObjLibFromGeneratedSources PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/config_$<CONFIG>.cpp)
+add_library(SharedLibFromObjLibFromGeneratedSources SHARED shared.cpp)
+target_link_libraries(SharedLibFromObjLibFromGeneratedSources PRIVATE ObjLibFromGeneratedSources)
+
+
+# ---------------------------------------------------------------------------
+# Make sure that additional build-events do not confuse CMake when using generated files.
+add_library(SharedLibFromGeneratedSources SHARED)
+set_property(TARGET SharedLibFromGeneratedSources PROPERTY POSITION_INDEPENDENT_CODE 1)
+target_sources(SharedLibFromGeneratedSources PRIVATE
+ shared.cpp
+ ${CMAKE_CURRENT_BINARY_DIR}/config_$<CONFIG>.cpp
+ )
+add_custom_command(TARGET SharedLibFromGeneratedSources POST_BUILD
+ COMMAND "${CMAKE_COMMAND}" "-E" "echo" "$<TARGET_FILE:SharedLibFromGeneratedSources>"
+ )
diff --git a/Tests/ConfigSources/custom1.cpp.in b/Tests/ConfigSources/custom1.cpp.in
new file mode 100644
index 0000000..e5f21c7
--- /dev/null
+++ b/Tests/ConfigSources/custom1.cpp.in
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom1_debug()
+{
+ return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom1_other()
+{
+ return 0;
+}
+#endif
diff --git a/Tests/ConfigSources/custom2.cpp.in b/Tests/ConfigSources/custom2.cpp.in
new file mode 100644
index 0000000..438c1fd
--- /dev/null
+++ b/Tests/ConfigSources/custom2.cpp.in
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom2_debug()
+{
+ return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom2_other()
+{
+ return 0;
+}
+#endif
diff --git a/Tests/ConfigSources/custom3.cpp.in b/Tests/ConfigSources/custom3.cpp.in
new file mode 100644
index 0000000..4545b69
--- /dev/null
+++ b/Tests/ConfigSources/custom3.cpp.in
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom3_debug()
+{
+ return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom3_other()
+{
+ return 0;
+}
+#endif
diff --git a/Tests/ConfigSources/custom4.cpp.in b/Tests/ConfigSources/custom4.cpp.in
new file mode 100644
index 0000000..8a8b2a8
--- /dev/null
+++ b/Tests/ConfigSources/custom4.cpp.in
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom4_debug()
+{
+ return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom4_other()
+{
+ return 0;
+}
+#endif
diff --git a/Tests/ConfigSources/custom5.cpp.in b/Tests/ConfigSources/custom5.cpp.in
new file mode 100644
index 0000000..51f40ae
--- /dev/null
+++ b/Tests/ConfigSources/custom5.cpp.in
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom5_debug()
+{
+ return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom5_other()
+{
+ return 0;
+}
+#endif
diff --git a/Tests/ConfigSources/iface.h b/Tests/ConfigSources/iface.h
new file mode 100644
index 0000000..810456c
--- /dev/null
+++ b/Tests/ConfigSources/iface.h
@@ -0,0 +1,10 @@
+
+int iface_src();
+
+#ifdef CFG_DEBUG
+int iface_debug();
+#endif
+
+#ifdef CFG_OTHER
+int iface_other();
+#endif
diff --git a/Tests/ConfigSources/iface_debug_src.cpp b/Tests/ConfigSources/iface_debug_src.cpp
new file mode 100644
index 0000000..010059f
--- /dev/null
+++ b/Tests/ConfigSources/iface_debug_src.cpp
@@ -0,0 +1,13 @@
+#ifndef CFG_DEBUG
+# error "This source should only be compiled in a Debug configuration."
+#endif
+#ifdef CFG_OTHER
+# error "This source should not be compiled in a non-Debug configuration."
+#endif
+
+#include "iface.h"
+
+int iface_debug()
+{
+ return 0;
+}
diff --git a/Tests/ConfigSources/iface_other_src.cpp b/Tests/ConfigSources/iface_other_src.cpp
new file mode 100644
index 0000000..8ffdfbb
--- /dev/null
+++ b/Tests/ConfigSources/iface_other_src.cpp
@@ -0,0 +1,13 @@
+#ifndef CFG_OTHER
+# error "This source should only be compiled in a non-Debug configuration."
+#endif
+#ifdef CFG_DEBUG
+# error "This source should not be compiled in a Debug configuration."
+#endif
+
+#include "iface.h"
+
+int iface_other()
+{
+ return 0;
+}
diff --git a/Tests/ConfigSources/iface_src.cpp b/Tests/ConfigSources/iface_src.cpp
new file mode 100644
index 0000000..c3a0c8f
--- /dev/null
+++ b/Tests/ConfigSources/iface_src.cpp
@@ -0,0 +1,5 @@
+
+int iface_src()
+{
+ return 0;
+}
diff --git a/Tests/ConfigSources/main.cpp b/Tests/ConfigSources/main.cpp
new file mode 100644
index 0000000..c1cd3b2
--- /dev/null
+++ b/Tests/ConfigSources/main.cpp
@@ -0,0 +1,9 @@
+#if !defined(CFG_DEBUG) && !defined(CFG_OTHER)
+# error "Neither CFG_DEBUG or CFG_OTHER is defined."
+#endif
+#ifdef CFG_DEBUG
+# include "main_debug.cpp"
+#endif
+#ifdef CFG_OTHER
+# include "main_other.cpp"
+#endif
diff --git a/Tests/ConfigSources/main_debug.cpp b/Tests/ConfigSources/main_debug.cpp
new file mode 100644
index 0000000..ef776f8
--- /dev/null
+++ b/Tests/ConfigSources/main_debug.cpp
@@ -0,0 +1,20 @@
+#ifndef CFG_DEBUG
+# error "This source should only be compiled in a Debug configuration."
+#endif
+#ifdef CFG_OTHER
+# error "This source should not be compiled in a non-Debug configuration."
+#endif
+
+#include "iface.h"
+
+extern int custom1_debug();
+extern int custom2_debug();
+extern int custom3_debug();
+extern int custom4_debug();
+extern int custom5_debug();
+
+int main(int argc, char** argv)
+{
+ return iface_src() + iface_debug() + custom1_debug() + custom2_debug() +
+ custom3_debug() + custom4_debug() + custom5_debug();
+}
diff --git a/Tests/ConfigSources/main_other.cpp b/Tests/ConfigSources/main_other.cpp
new file mode 100644
index 0000000..74f2156
--- /dev/null
+++ b/Tests/ConfigSources/main_other.cpp
@@ -0,0 +1,20 @@
+#ifndef CFG_OTHER
+# error "This source should only be compiled in a non-Debug configuration."
+#endif
+#ifdef CFG_DEBUG
+# error "This source should not be compiled in a Debug configuration."
+#endif
+
+#include "iface.h"
+
+extern int custom1_other();
+extern int custom2_other();
+extern int custom3_other();
+extern int custom4_other();
+extern int custom5_other();
+
+int main(int argc, char** argv)
+{
+ return iface_src() + iface_other() + custom1_other() + custom2_other() +
+ custom3_other() + custom4_other() + custom5_other();
+}
diff --git a/Tests/ConfigSources/shared.cpp b/Tests/ConfigSources/shared.cpp
new file mode 100644
index 0000000..1726c46
--- /dev/null
+++ b/Tests/ConfigSources/shared.cpp
@@ -0,0 +1,8 @@
+#if defined(_WIN32)
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+EXPORT void shared()
+{
+}
diff --git a/Tests/Contracts/Home.cmake b/Tests/Contracts/Home.cmake
new file mode 100644
index 0000000..8b05e81
--- /dev/null
+++ b/Tests/Contracts/Home.cmake
@@ -0,0 +1,19 @@
+# Find a home in which to build.
+if(NOT DEFINED HOME)
+ if(DEFINED ENV{CTEST_REAL_HOME})
+ set(HOME "$ENV{CTEST_REAL_HOME}")
+ else()
+ set(HOME "$ENV{HOME}")
+ endif()
+
+ if(NOT HOME AND WIN32)
+ # Try for USERPROFILE as HOME equivalent:
+ string(REPLACE "\\" "/" HOME "$ENV{USERPROFILE}")
+
+ # But just use root of SystemDrive if USERPROFILE contains any spaces:
+ # (Default on XP and earlier...)
+ if(HOME MATCHES " ")
+ string(REPLACE "\\" "/" HOME "$ENV{SystemDrive}")
+ endif()
+ endif()
+endif()
diff --git a/Tests/Contracts/PLplot/CMakeLists.txt b/Tests/Contracts/PLplot/CMakeLists.txt
new file mode 100644
index 0000000..8e95ba3
--- /dev/null
+++ b/Tests/Contracts/PLplot/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.9)
+project(PLplotDriver NONE)
+include(ExternalProject)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../Home.cmake)
+set(PLplot_PREFIX "${HOME}/.cmake/Contracts/PLplot")
+file(REMOVE_RECURSE "${PLplot_PREFIX}")
+separate_arguments(PLplot_CMAKE_ARGS UNIX_COMMAND "${PLplot_CMAKE_FLAGS}")
+if(NOT PLplot_GIT_TAG)
+ set(PLplot_GIT_TAG "plplot-5.13.0")
+endif()
+ExternalProject_Add(PLplot
+ GIT_REPOSITORY "https://git.code.sf.net/p/plplot/plplot"
+ GIT_TAG "${PLplot_GIT_TAG}"
+ PREFIX "${PLplot_PREFIX}"
+ CMAKE_ARGS
+ -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
+ ${PLplot_CMAKE_ARGS}
+ )
diff --git a/Tests/Contracts/PLplot/Configure.cmake b/Tests/Contracts/PLplot/Configure.cmake
new file mode 100644
index 0000000..83591d4
--- /dev/null
+++ b/Tests/Contracts/PLplot/Configure.cmake
@@ -0,0 +1,4 @@
+set(Contracts.PLplot_BUILD_OPTIONS
+ -DPLplot_CMAKE_FLAGS=${CMake_TEST_CONTRACT_PLplot_CMAKE_FLAGS}
+ -DPLplot_GIT_TAG=${CMake_TEST_CONTRACT_PLplot_GIT_TAG}
+ )
diff --git a/Tests/Contracts/Trilinos/CMakeLists.txt b/Tests/Contracts/Trilinos/CMakeLists.txt
new file mode 100644
index 0000000..6cc2d09
--- /dev/null
+++ b/Tests/Contracts/Trilinos/CMakeLists.txt
@@ -0,0 +1,86 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(Trilinos)
+
+include(ExternalProject)
+
+include("${CMAKE_CURRENT_SOURCE_DIR}/LocalOverrides.cmake" OPTIONAL)
+include("${CMAKE_CURRENT_BINARY_DIR}/LocalOverrides.cmake" OPTIONAL)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/../Home.cmake)
+message(STATUS "HOME='${HOME}'")
+
+if(NOT DEFINED url)
+ set(url "https://cmake.org/files/contracts/trilinos-11.4.1.tar.gz")
+endif()
+message(STATUS "url='${url}'")
+
+if(NOT DEFINED md5)
+ set(md5 "28b6a3c7c0fb317b3a237997293faa8b")
+endif()
+message(STATUS "md5='${md5}'")
+
+string(SUBSTRING "${md5}" 0 8 shorttag)
+set(shorttag "m${shorttag}")
+
+set(download_dir "${HOME}/.cmake/Downloads")
+
+set(base_dir "${HOME}/.cmake/Contracts/${PROJECT_NAME}/${shorttag}")
+set(binary_dir "${base_dir}/build")
+set(script_dir "${base_dir}")
+set(source_dir "${base_dir}/src")
+
+if(NOT DEFINED BUILDNAME)
+ set(BUILDNAME "CMakeContract-${shorttag}")
+endif()
+message(STATUS "BUILDNAME='${BUILDNAME}'")
+
+if(NOT DEFINED SITE)
+ site_name(SITE)
+endif()
+message(STATUS "SITE='${SITE}'")
+
+configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/Dashboard.cmake.in"
+ "${script_dir}/Dashboard.cmake"
+ @ONLY)
+
+configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/ValidateBuild.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/ValidateBuild.cmake"
+ @ONLY)
+
+# Source dir for this project exists outside the CMake build tree because it
+# is absolutely huge. Source dir is therefore cached under a '.cmake/Contracts'
+# dir in your HOME directory. Downloads are cached under '.cmake/Downloads'
+#
+if(EXISTS "${source_dir}/cmake/ctest/TrilinosCTestDriverCore.cmake")
+ # If it exists already, download is a complete no-op:
+ ExternalProject_Add(download-${PROJECT_NAME}
+ DOWNLOAD_COMMAND ""
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ )
+else()
+ # If it does not yet exist, download pulls the tarball from the web (or
+ # no-ops if it already exists with the given md5 sum):
+ #
+ ExternalProject_Add(download-${PROJECT_NAME}
+ DOWNLOAD_DIR "${download_dir}"
+ URL "${url}"
+ URL_MD5 "${md5}"
+ SOURCE_DIR "${source_dir}"
+ PATCH_COMMAND ${CMAKE_COMMAND} -Dsource_dir=${source_dir} -P "${CMAKE_CURRENT_SOURCE_DIR}/Patch.cmake"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ )
+endif()
+
+ExternalProject_Add(build-${PROJECT_NAME}
+ DOWNLOAD_COMMAND ""
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ${CMAKE_COMMAND} -P "${script_dir}/Dashboard.cmake"
+ INSTALL_COMMAND ""
+ DEPENDS download-${PROJECT_NAME}
+ )
diff --git a/Tests/Contracts/Trilinos/Configure.cmake b/Tests/Contracts/Trilinos/Configure.cmake
new file mode 100644
index 0000000..d62eb79
--- /dev/null
+++ b/Tests/Contracts/Trilinos/Configure.cmake
@@ -0,0 +1,7 @@
+# ValidateBuild.cmake is configured into this location when the test is built:
+set(dir "${CMAKE_CURRENT_BINARY_DIR}/Contracts/${project}")
+
+set(exe "${CMAKE_COMMAND}")
+set(args -P "${dir}/ValidateBuild.cmake")
+
+set(CMake_TEST_CONTRACT_Trilinos_RUN_TEST ${exe} ${args})
diff --git a/Tests/Contracts/Trilinos/Dashboard.cmake.in b/Tests/Contracts/Trilinos/Dashboard.cmake.in
new file mode 100644
index 0000000..93d4f61
--- /dev/null
+++ b/Tests/Contracts/Trilinos/Dashboard.cmake.in
@@ -0,0 +1,63 @@
+# This "cmake -P" script may be configured to drive a dashboard on any machine.
+#
+set(CTEST_BINARY_DIRECTORY "@binary_dir@")
+set(CTEST_BUILD_NAME "@BUILDNAME@")
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_SITE "@SITE@")
+set(CTEST_SOURCE_DIRECTORY "@source_dir@")
+
+# Set the environment:
+#
+set(ENV{CTEST_BUILD_NAME} "${CTEST_BUILD_NAME}")
+set(ENV{CTEST_CMAKE_GENERATOR} "${CTEST_CMAKE_GENERATOR}")
+set(ENV{CTEST_SITE} "${CTEST_SITE}")
+
+# Allow override of the environment on a per-client basis:
+#
+set(ENV_SCRIPT "$ENV{CMAKE_CONTRACT_Trilinos_ENV_SCRIPT}")
+if(ENV_SCRIPT AND EXISTS "${ENV_SCRIPT}")
+ include("${ENV_SCRIPT}")
+endif()
+
+# Empty build dir to start with:
+#
+message("Cleaning binary dir '${CTEST_BINARY_DIRECTORY}'")
+file(REMOVE_RECURSE "${CTEST_BINARY_DIRECTORY}")
+
+# Generate 'do-configure' script:
+#
+file(WRITE "${CTEST_BINARY_DIRECTORY}/do-configure" "
+\"${CMAKE_COMMAND}\" -G \"${CTEST_CMAKE_GENERATOR}\" \"${CTEST_SOURCE_DIRECTORY}\"
+")
+
+# Make the 'do-configure' script executable and execute it:
+#
+if(WIN32)
+ configure_file(
+ "${CTEST_BINARY_DIRECTORY}/do-configure"
+ "${CTEST_BINARY_DIRECTORY}/do-configure.cmd"
+ COPYONLY)
+ execute_process(COMMAND "${CTEST_BINARY_DIRECTORY}/do-configure.cmd"
+ WORKING_DIRECTORY "${CTEST_BINARY_DIRECTORY}")
+else()
+ execute_process(COMMAND chmod +x "${CTEST_BINARY_DIRECTORY}/do-configure")
+ execute_process(COMMAND "${CTEST_BINARY_DIRECTORY}/do-configure"
+ WORKING_DIRECTORY "${CTEST_BINARY_DIRECTORY}")
+endif()
+
+# Run an experimental Trilinos dashboard:
+#
+execute_process(COMMAND
+ "${CMAKE_CTEST_COMMAND}"
+ -S "${CTEST_SOURCE_DIRECTORY}/cmake/tribits/ctest/experimental_build_test.cmake"
+ -VV
+ WORKING_DIRECTORY "${CTEST_BINARY_DIRECTORY}"
+ RESULT_VARIABLE rv
+ )
+
+if(NOT "${rv}" STREQUAL "0")
+ message("error(s) (or warnings or test failures) running Trilinos dashboard
+script experimental_build_test.cmake...
+ctest returned rv='${rv}'
+")
+endif()
diff --git a/Tests/Contracts/Trilinos/Patch.cmake b/Tests/Contracts/Trilinos/Patch.cmake
new file mode 100644
index 0000000..6c619ac
--- /dev/null
+++ b/Tests/Contracts/Trilinos/Patch.cmake
@@ -0,0 +1,38 @@
+if(NOT DEFINED source_dir)
+ message(FATAL_ERROR "variable 'source_dir' not defined")
+endif()
+
+
+if(NOT EXISTS "${source_dir}/CMakeLists.txt")
+ message(FATAL_ERROR "error: No CMakeLists.txt file to patch!")
+endif()
+
+set(text "
+
+#
+# Reference variables typically given as experimental_build_test configure
+# options to avoid CMake warnings about unused variables
+#
+
+message(\"Trilinos_ALLOW_NO_PACKAGES='\${Trilinos_ALLOW_NO_PACKAGES}'\")
+message(\"Trilinos_WARNINGS_AS_ERRORS_FLAGS='\${Trilinos_WARNINGS_AS_ERRORS_FLAGS}'\")
+")
+
+file(APPEND "${source_dir}/CMakeLists.txt" "${text}")
+
+
+if(NOT EXISTS "${source_dir}/CTestConfig.cmake")
+ message(FATAL_ERROR "error: No CTestConfig.cmake file to patch!")
+endif()
+
+set(text "
+
+#
+# Use newer than 10.6.1 CTestConfig settings from the Trilinos project.
+# Send the Trilinos dashboards to the new Trilinos CDash server instance.
+#
+set(CTEST_NIGHTLY_START_TIME \"04:00:00 UTC\") # 10 PM MDT or 9 PM MST
+set(CTEST_DROP_SITE \"testing.sandia.gov\")
+")
+
+file(APPEND "${source_dir}/CTestConfig.cmake" "${text}")
diff --git a/Tests/Contracts/Trilinos/ValidateBuild.cmake.in b/Tests/Contracts/Trilinos/ValidateBuild.cmake.in
new file mode 100644
index 0000000..fa38ada
--- /dev/null
+++ b/Tests/Contracts/Trilinos/ValidateBuild.cmake.in
@@ -0,0 +1,39 @@
+#
+# This code validates that the Trilinos build was "successful enough" (since it
+# is difficult to detect this from the caller of the experimental_build_test
+# dashboard script...)
+#
+set(binary_dir "@binary_dir@")
+message("binary_dir='${binary_dir}'")
+
+
+# Count *.exe files:
+#
+file(GLOB_RECURSE exes "${binary_dir}/*.exe")
+message(STATUS "exes='${exes}'")
+list(LENGTH exes len)
+if(len LESS 47)
+ message(FATAL_ERROR "len='${len}' is less than minimum expected='47' (count of executables)")
+endif()
+message(STATUS "Found len='${len}' *.exe files")
+
+
+# Try to find the Teuchos unit tests executable:
+#
+file(GLOB_RECURSE exe "${binary_dir}/TeuchosCore_UnitTest_UnitTests.exe")
+list(LENGTH exe len)
+if(NOT len EQUAL 1)
+ message(FATAL_ERROR "len='${len}' is not the expected='1' (count of TeuchosCore_UnitTest_UnitTests.exe)")
+endif()
+message(STATUS "Found exe='${exe}'")
+
+
+# Try to run it:
+execute_process(COMMAND ${exe} RESULT_VARIABLE rv)
+if(NOT "${rv}" STREQUAL "0")
+ message(FATAL_ERROR "rv='${rv}' is not the expected='0' (result of running TeuchosCore_UnitTest_UnitTests.exe)")
+endif()
+message(STATUS "Ran exe='${exe}' rv='${rv}'")
+
+
+message(STATUS "All Trilinos build validation tests pass.")
diff --git a/Tests/Contracts/VTK/CMakeLists.txt b/Tests/Contracts/VTK/CMakeLists.txt
new file mode 100644
index 0000000..0d36323
--- /dev/null
+++ b/Tests/Contracts/VTK/CMakeLists.txt
@@ -0,0 +1,30 @@
+# The VTK external project for CMake
+# ---------------------------------------------------------------------------
+cmake_minimum_required(VERSION 2.8.12)
+project(VTK)
+include(ExternalProject)
+
+# find "HOME". VTK will be downloaded & built within a subdirectory.
+include(${CMAKE_CURRENT_SOURCE_DIR}/../Home.cmake)
+
+set(base_dir "${HOME}/.cmake/Contracts/VTK")
+
+if(NOT DEFINED SITE)
+ site_name(SITE)
+endif()
+
+# configure our dashboard script
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/Dashboard.cmake.in
+ ${base_dir}/Dashboard.cmake
+ @ONLY)
+
+# build & test VTK's release branch
+ExternalProject_Add(${PROJECT_NAME}
+ GIT_REPOSITORY "https://gitlab.kitware.com/vtk/vtk.git"
+ GIT_TAG "release"
+ PREFIX ${base_dir}
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ${CMAKE_CTEST_COMMAND} -S "${base_dir}/Dashboard.cmake"
+ INSTALL_COMMAND ""
+)
diff --git a/Tests/Contracts/VTK/Configure.cmake b/Tests/Contracts/VTK/Configure.cmake
new file mode 100644
index 0000000..037d75a
--- /dev/null
+++ b/Tests/Contracts/VTK/Configure.cmake
@@ -0,0 +1,3 @@
+set(exe "$ENV{HOME}/.cmake/Contracts/VTK/VTK-build/bin/vtkCommonCoreCxxTests")
+set(args otherArrays)
+set(CMake_TEST_CONTRACT_VTK_RUN_TEST ${exe} ${args})
diff --git a/Tests/Contracts/VTK/Dashboard.cmake.in b/Tests/Contracts/VTK/Dashboard.cmake.in
new file mode 100644
index 0000000..ae760bc
--- /dev/null
+++ b/Tests/Contracts/VTK/Dashboard.cmake.in
@@ -0,0 +1,37 @@
+# This submission's role is to test leading edge of cmake development
+# against VTK release
+#
+# Maintainer: Zack Galbreath <zack.galbreath@kitware.com>
+#
+# This file was generated as part of the CMake/VTK Contracts test.
+# See <CMake-src>/Tests/Contracts/VTK/ for more information
+
+set(CTEST_SITE "@SITE@")
+set(CTEST_BUILD_NAME "Contracts.VTK")
+set(CTEST_DASHBOARD_ROOT "@base_dir@")
+set(CTEST_SOURCE_DIRECTORY "${CTEST_DASHBOARD_ROOT}/src/VTK")
+set(CTEST_BINARY_DIRECTORY "${CTEST_DASHBOARD_ROOT}/VTK-build")
+
+set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
+set(CTEST_CONFIGURATION_TYPE Debug)
+set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
+
+# Assume a Linux build, with a make that supports -j9. Modify this script if
+# assumption is ever invalid.
+#
+set(CTEST_BUILD_COMMAND "@CMAKE_MAKE_PROGRAM@ -j9 -i")
+
+ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY})
+
+file(WRITE "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" "
+ VTK_BUILD_EXAMPLES:BOOL=ON
+ VTK_BUILD_TESTING:STRING=WANT
+ VTK_WRAP_PYTHON:BOOL=ON
+ ExternalData_OBJECT_STORES:FILEPATH=@base_dir@/ExternalData
+")
+
+ctest_start(Nightly)
+ctest_configure(BUILD "${CTEST_BINARY_DIRECTORY}")
+ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}")
+ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}" INCLUDE "PythonSmoke")
+ctest_submit(BUILD "${CTEST_BINARY_DIRECTORY}")
diff --git a/Tests/CrossCompile/CMakeLists.txt b/Tests/CrossCompile/CMakeLists.txt
new file mode 100644
index 0000000..121cb81
--- /dev/null
+++ b/Tests/CrossCompile/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required (VERSION 2.6)
+project(CrossCompile)
+
+unset(run_result CACHE)
+
+#Simulate the cross compile condition
+set(CMAKE_CROSSCOMPILING ON)
+
+add_executable(CrossCompile main.c)
+
+try_run(run_result compile_result
+ ${CrossCompile_BINARY_DIR}
+ ${CrossCompile_SOURCE_DIR}/main.c)
diff --git a/Tests/CrossCompile/main.c b/Tests/CrossCompile/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/CrossCompile/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/Cuda/CMakeLists.txt b/Tests/Cuda/CMakeLists.txt
new file mode 100644
index 0000000..be5ccac
--- /dev/null
+++ b/Tests/Cuda/CMakeLists.txt
@@ -0,0 +1,34 @@
+macro (add_cuda_test_macro name)
+ add_test_macro("${name}" ${ARGN})
+ set_property(TEST "${name}" APPEND
+ PROPERTY LABELS "CUDA")
+endmacro ()
+
+add_cuda_test_macro(Cuda.ConsumeCompileFeatures CudaConsumeCompileFeatures)
+add_cuda_test_macro(Cuda.CXXStandardSetTwice CXXStandardSetTwice)
+add_cuda_test_macro(Cuda.ObjectLibrary CudaObjectLibrary)
+add_cuda_test_macro(Cuda.MixedStandardLevels1 MixedStandardLevels1)
+add_cuda_test_macro(Cuda.MixedStandardLevels2 MixedStandardLevels2)
+add_cuda_test_macro(Cuda.MixedStandardLevels3 MixedStandardLevels3)
+add_cuda_test_macro(Cuda.MixedStandardLevels4 MixedStandardLevels4)
+add_cuda_test_macro(Cuda.MixedStandardLevels5 MixedStandardLevels5)
+add_cuda_test_macro(Cuda.NotEnabled CudaNotEnabled)
+add_cuda_test_macro(Cuda.SeparableCompCXXOnly SeparableCompCXXOnly)
+add_cuda_test_macro(Cuda.Toolkit Toolkit)
+add_cuda_test_macro(Cuda.IncludePathNoToolkit IncludePathNoToolkit)
+add_cuda_test_macro(Cuda.SharedRuntimePlusToolkit SharedRuntimePlusToolkit)
+add_cuda_test_macro(Cuda.Complex CudaComplex)
+add_cuda_test_macro(Cuda.ProperLinkFlags ProperLinkFlags)
+
+if(CMake_TEST_CUDA AND NOT CMake_TEST_CUDA STREQUAL "Clang")
+ # Clang lacks __CUDACC_VER*__ defines.
+ add_cuda_test_macro(Cuda.ProperDeviceLibraries ProperDeviceLibraries)
+endif()
+
+# The CUDA only ships the shared version of the toolkit libraries
+# on windows
+if(NOT WIN32)
+ add_cuda_test_macro(Cuda.StaticRuntimePlusToolkit StaticRuntimePlusToolkit)
+endif()
+
+add_cuda_test_macro(Cuda.WithC CudaWithC)
diff --git a/Tests/Cuda/CXXStandardSetTwice/CMakeLists.txt b/Tests/Cuda/CXXStandardSetTwice/CMakeLists.txt
new file mode 100644
index 0000000..50338cf
--- /dev/null
+++ b/Tests/Cuda/CXXStandardSetTwice/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.18)
+project(CXXStandardSetTwice CXX CUDA)
+
+set(CMAKE_CXX_STANDARD 11)
+
+add_executable(CXXStandardSetTwice main.cu)
+target_compile_features(CXXStandardSetTwice PUBLIC cxx_std_11)
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET CXXStandardSetTwice PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/CXXStandardSetTwice/main.cu b/Tests/Cuda/CXXStandardSetTwice/main.cu
new file mode 100644
index 0000000..d57c05a
--- /dev/null
+++ b/Tests/Cuda/CXXStandardSetTwice/main.cu
@@ -0,0 +1,10 @@
+
+#include <type_traits>
+
+int main(int argc, char** argv)
+{
+ // Verify that issue #17519 Setting CXX_STANDARD breaks CUDA_STANDARD
+ // selection via cxx_std_11 has been corrected
+ using returnv = std::integral_constant<int, 0>;
+ return returnv::value;
+}
diff --git a/Tests/Cuda/Complex/CMakeLists.txt b/Tests/Cuda/Complex/CMakeLists.txt
new file mode 100644
index 0000000..63defdf
--- /dev/null
+++ b/Tests/Cuda/Complex/CMakeLists.txt
@@ -0,0 +1,57 @@
+cmake_minimum_required(VERSION 3.18)
+project(Complex CXX CUDA)
+#Goal for this example:
+
+#build a cpp dynamic library base
+#build a cuda static library base that uses separable compilation
+
+#build a cuda dynamic library that uses the first dynamic library
+#build a mixed cpp & cuda dynamic library uses all 3 previous libraries
+
+#lastly build a cpp executable that uses this last cuda dynamic library
+
+#this tests that we can properly handle linking cuda and cpp together
+#and also building cpp targets that need cuda implicit libraries
+
+set(CMAKE_CUDA_STANDARD 11)
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CUDA_STANDARD_REQUIRED TRUE)
+set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
+
+add_library(CudaComplexCppBase SHARED dynamic.cpp)
+add_library(CudaComplexSharedLib SHARED dynamic.cu)
+target_link_libraries(CudaComplexSharedLib PUBLIC CudaComplexCppBase)
+
+add_library(CudaComplexSeperableLib STATIC file1.cu file2.cu file3.cu)
+add_library(CudaComplexMixedLib SHARED mixed.cpp mixed.cu)
+target_link_libraries(CudaComplexMixedLib
+ PUBLIC CudaComplexSharedLib
+ PRIVATE CudaComplexSeperableLib)
+
+add_executable(CudaComplex main.cpp)
+target_link_libraries(CudaComplex PUBLIC CudaComplexMixedLib)
+
+
+set_target_properties(CudaComplexMixedLib
+ CudaComplexSeperableLib
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON
+ CUDA_SEPARABLE_COMPILATION ON
+ )
+set_target_properties(CudaComplexMixedLib
+ CudaComplexSharedLib
+ PROPERTIES
+ CUDA_RUNTIME_LIBRARY shared
+ )
+
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET CudaComplex PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
+
+if(UNIX)
+ # Help the shared cuda runtime find libcudart as it is not located
+ # in a default system searched location
+ set_property(TARGET CudaComplexMixedLib PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/Complex/dynamic.cpp b/Tests/Cuda/Complex/dynamic.cpp
new file mode 100644
index 0000000..38da6a6
--- /dev/null
+++ b/Tests/Cuda/Complex/dynamic.cpp
@@ -0,0 +1,11 @@
+
+#ifdef _WIN32
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+EXPORT int dynamic_base_func(int x)
+{
+ return x * x;
+}
diff --git a/Tests/Cuda/Complex/dynamic.cu b/Tests/Cuda/Complex/dynamic.cu
new file mode 100644
index 0000000..7f2f2b5
--- /dev/null
+++ b/Tests/Cuda/Complex/dynamic.cu
@@ -0,0 +1,73 @@
+
+#include <iostream>
+#include <string>
+
+#include <cuda.h>
+
+#ifdef _WIN32
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+int dynamic_base_func(int);
+
+EXPORT int __host__ cuda_dynamic_host_func(int x)
+{
+ return dynamic_base_func(x);
+}
+
+static __global__ void DetermineIfValidCudaDevice()
+{
+}
+
+EXPORT int choose_cuda_device()
+{
+ int nDevices = 0;
+ cudaError_t err = cudaGetDeviceCount(&nDevices);
+ if (err != cudaSuccess) {
+ std::cerr << "Failed to retrieve the number of CUDA enabled devices"
+ << std::endl;
+ return 1;
+ }
+ for (int i = 0; i < nDevices; ++i) {
+ cudaDeviceProp prop;
+ cudaError_t err = cudaGetDeviceProperties(&prop, i);
+ if (err != cudaSuccess) {
+ std::cerr << "Could not retrieve properties from CUDA device " << i
+ << std::endl;
+ return 1;
+ }
+ if (prop.major >= 3) {
+ err = cudaSetDevice(i);
+ if (err != cudaSuccess) {
+ std::cout << "Could not select CUDA device " << i << std::endl;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ std::cout << "Could not find a CUDA enabled card supporting compute >=3.0"
+ << std::endl;
+
+ return 1;
+}
+
+EXPORT bool cuda_dynamic_lib_func()
+{
+ cudaError_t err = cudaGetLastError();
+ if (err != cudaSuccess) {
+ std::cerr << "DetermineIfValidCudaDevice [Per Launch] failed: "
+ << cudaGetErrorString(err) << std::endl;
+ return false;
+ }
+ DetermineIfValidCudaDevice<<<1, 1>>>();
+ err = cudaDeviceSynchronize();
+ if (err != cudaSuccess) {
+ std::cerr << "DetermineIfValidCudaDevice [SYNC] failed: "
+ << cudaGetErrorString(cudaGetLastError()) << std::endl;
+ return false;
+ }
+ return true;
+}
diff --git a/Tests/Cuda/Complex/file1.cu b/Tests/Cuda/Complex/file1.cu
new file mode 100644
index 0000000..1ce63bf
--- /dev/null
+++ b/Tests/Cuda/Complex/file1.cu
@@ -0,0 +1,10 @@
+
+#include "file1.h"
+
+result_type __device__ file1_func(int x)
+{
+ result_type r;
+ r.input = x;
+ r.sum = x * x;
+ return r;
+}
diff --git a/Tests/Cuda/Complex/file1.h b/Tests/Cuda/Complex/file1.h
new file mode 100644
index 0000000..ff1945c
--- /dev/null
+++ b/Tests/Cuda/Complex/file1.h
@@ -0,0 +1,7 @@
+
+#pragma once
+struct result_type
+{
+ int input;
+ int sum;
+};
diff --git a/Tests/Cuda/Complex/file2.cu b/Tests/Cuda/Complex/file2.cu
new file mode 100644
index 0000000..74f3558
--- /dev/null
+++ b/Tests/Cuda/Complex/file2.cu
@@ -0,0 +1,16 @@
+
+#include "file2.h"
+
+result_type __device__ file1_func(int x);
+
+result_type_dynamic __device__ file2_func(int x)
+{
+ if (x != 42) {
+ const result_type r = file1_func(x);
+ const result_type_dynamic rd{ r.input, r.sum, true };
+ return rd;
+ } else {
+ const result_type_dynamic rd{ x, x * x * x, false };
+ return rd;
+ }
+}
diff --git a/Tests/Cuda/Complex/file2.h b/Tests/Cuda/Complex/file2.h
new file mode 100644
index 0000000..d2dbaa4
--- /dev/null
+++ b/Tests/Cuda/Complex/file2.h
@@ -0,0 +1,10 @@
+
+#pragma once
+#include "file1.h"
+
+struct result_type_dynamic
+{
+ int input;
+ int sum;
+ bool from_static;
+};
diff --git a/Tests/Cuda/Complex/file3.cu b/Tests/Cuda/Complex/file3.cu
new file mode 100644
index 0000000..d055b42
--- /dev/null
+++ b/Tests/Cuda/Complex/file3.cu
@@ -0,0 +1,48 @@
+
+#include <iostream>
+
+#include "file1.h"
+#include "file2.h"
+
+result_type __device__ file1_func(int x);
+result_type_dynamic __device__ file2_func(int x);
+
+static __global__ void file3_kernel(result_type* r, int x)
+{
+ *r = file1_func(x);
+ result_type_dynamic rd = file2_func(x);
+}
+
+int file3_launch_kernel(int x)
+{
+ result_type* r;
+ cudaError_t err = cudaMallocManaged(&r, sizeof(result_type));
+ if (err != cudaSuccess) {
+ std::cerr << "file3_launch_kernel: cudaMallocManaged failed: "
+ << cudaGetErrorString(err) << std::endl;
+ return x;
+ }
+
+ file3_kernel<<<1, 1>>>(r, x);
+ err = cudaGetLastError();
+ if (err != cudaSuccess) {
+ std::cerr << "file3_kernel [SYNC] failed: " << cudaGetErrorString(err)
+ << std::endl;
+ return x;
+ }
+ err = cudaDeviceSynchronize();
+ if (err != cudaSuccess) {
+ std::cerr << "file3_kernel [ASYNC] failed: "
+ << cudaGetErrorString(cudaGetLastError()) << std::endl;
+ return x;
+ }
+ int result = r->sum;
+ err = cudaFree(r);
+ if (err != cudaSuccess) {
+ std::cerr << "file3_launch_kernel: cudaFree failed: "
+ << cudaGetErrorString(err) << std::endl;
+ return x;
+ }
+
+ return result;
+}
diff --git a/Tests/Cuda/Complex/main.cpp b/Tests/Cuda/Complex/main.cpp
new file mode 100644
index 0000000..da09b44
--- /dev/null
+++ b/Tests/Cuda/Complex/main.cpp
@@ -0,0 +1,27 @@
+#include <iostream>
+
+#include "file1.h"
+#include "file2.h"
+
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+#else
+# define IMPORT
+#endif
+
+IMPORT int choose_cuda_device();
+IMPORT int call_cuda_seperable_code(int x);
+IMPORT int mixed_launch_kernel(int x);
+
+int main(int argc, char** argv)
+{
+ int ret = choose_cuda_device();
+ if (ret) {
+ return 0;
+ }
+
+ int r1 = call_cuda_seperable_code(42);
+ int r2 = mixed_launch_kernel(42);
+
+ return (r1 == 42 || r2 == 42) ? 1 : 0;
+}
diff --git a/Tests/Cuda/Complex/mixed.cpp b/Tests/Cuda/Complex/mixed.cpp
new file mode 100644
index 0000000..38a1f0c
--- /dev/null
+++ b/Tests/Cuda/Complex/mixed.cpp
@@ -0,0 +1,22 @@
+
+#ifdef _WIN32
+# define EXPORT __declspec(dllexport)
+# define IMPORT __declspec(dllimport)
+#else
+# define EXPORT
+# define IMPORT
+#endif
+
+int dynamic_base_func(int);
+IMPORT int cuda_dynamic_host_func(int);
+int file3_launch_kernel(int);
+
+int dynamic_final_func(int x)
+{
+ return cuda_dynamic_host_func(dynamic_base_func(x));
+}
+
+EXPORT int call_cuda_seperable_code(int x)
+{
+ return file3_launch_kernel(x);
+}
diff --git a/Tests/Cuda/Complex/mixed.cu b/Tests/Cuda/Complex/mixed.cu
new file mode 100644
index 0000000..76119ad
--- /dev/null
+++ b/Tests/Cuda/Complex/mixed.cu
@@ -0,0 +1,63 @@
+
+#include <iostream>
+
+#include "file1.h"
+#include "file2.h"
+
+#ifdef _WIN32
+# define EXPORT __declspec(dllexport)
+# define IMPORT __declspec(dllimport)
+#else
+# define EXPORT
+# define IMPORT
+#endif
+
+result_type __device__ file1_func(int x);
+result_type_dynamic __device__ file2_func(int x);
+
+IMPORT bool __host__ cuda_dynamic_lib_func();
+
+static __global__ void mixed_kernel(result_type* r, int x)
+{
+ *r = file1_func(x);
+ result_type_dynamic rd = file2_func(x);
+}
+
+EXPORT int mixed_launch_kernel(int x)
+{
+ if (!cuda_dynamic_lib_func()) {
+ return x;
+ }
+
+ result_type* r;
+ cudaError_t err = cudaMallocManaged(&r, sizeof(result_type));
+ if (err != cudaSuccess) {
+ std::cerr << "mixed_launch_kernel: cudaMallocManaged failed: "
+ << cudaGetErrorString(err) << std::endl;
+ return x;
+ }
+
+ mixed_kernel<<<1, 1>>>(r, x);
+ err = cudaGetLastError();
+ if (err != cudaSuccess) {
+ std::cerr << "mixed_kernel [SYNC] failed: " << cudaGetErrorString(err)
+ << std::endl;
+ return x;
+ }
+ err = cudaDeviceSynchronize();
+ if (err != cudaSuccess) {
+ std::cerr << "mixed_kernel [ASYNC] failed: "
+ << cudaGetErrorString(cudaGetLastError()) << std::endl;
+ return x;
+ }
+
+ int result = r->sum;
+ err = cudaFree(r);
+ if (err != cudaSuccess) {
+ std::cerr << "mixed_launch_kernel: cudaFree failed: "
+ << cudaGetErrorString(err) << std::endl;
+ return x;
+ }
+
+ return result;
+}
diff --git a/Tests/Cuda/ConsumeCompileFeatures/CMakeLists.txt b/Tests/Cuda/ConsumeCompileFeatures/CMakeLists.txt
new file mode 100644
index 0000000..b01b9d7
--- /dev/null
+++ b/Tests/Cuda/ConsumeCompileFeatures/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.18)
+project(ConsumeCompileFeatures CXX CUDA)
+#Goal for this example:
+
+#build a c++11 library that express a c++11 public compile feature
+#link a cuda library and verify it builds with c++11 enabled
+
+#build a standalone c++/cuda mixed executable where we express a c++11
+#compile feature.
+
+
+add_library(CudaConsumeLib STATIC static.cpp static.cu)
+target_compile_features(CudaConsumeLib PUBLIC cxx_nullptr)
+
+add_executable(CudaConsumeCompileFeatures main.cu)
+target_link_libraries(CudaConsumeCompileFeatures PRIVATE CudaConsumeLib)
diff --git a/Tests/Cuda/ConsumeCompileFeatures/main.cu b/Tests/Cuda/ConsumeCompileFeatures/main.cu
new file mode 100644
index 0000000..bc32450
--- /dev/null
+++ b/Tests/Cuda/ConsumeCompileFeatures/main.cu
@@ -0,0 +1,20 @@
+
+#include <iostream>
+
+int static_cxx11_func(int);
+
+void test_functions()
+{
+ auto x = static_cxx11_func(int(42));
+ std::cout << x << std::endl;
+}
+
+int main(int argc, char** argv)
+{
+ test_functions();
+ std::cout
+ << "this executable doesn't use cuda code, just call methods defined"
+ << std::endl;
+ std::cout << "in libraries that have cuda code" << std::endl;
+ return 0;
+}
diff --git a/Tests/Cuda/ConsumeCompileFeatures/static.cpp b/Tests/Cuda/ConsumeCompileFeatures/static.cpp
new file mode 100644
index 0000000..565d52e
--- /dev/null
+++ b/Tests/Cuda/ConsumeCompileFeatures/static.cpp
@@ -0,0 +1,10 @@
+
+
+#include <type_traits>
+
+int static_cuda11_func(int);
+
+int static_cxx11_func(int x)
+{
+ return static_cuda11_func(x) + std::integral_constant<int, 32>::value;
+}
diff --git a/Tests/Cuda/ConsumeCompileFeatures/static.cu b/Tests/Cuda/ConsumeCompileFeatures/static.cu
new file mode 100644
index 0000000..73e43a8
--- /dev/null
+++ b/Tests/Cuda/ConsumeCompileFeatures/static.cu
@@ -0,0 +1,9 @@
+
+#include <type_traits>
+
+using tt = std::true_type;
+using ft = std::false_type;
+int __host__ static_cuda11_func(int x)
+{
+ return x * x + std::integral_constant<int, 17>::value;
+}
diff --git a/Tests/Cuda/IncludePathNoToolkit/CMakeLists.txt b/Tests/Cuda/IncludePathNoToolkit/CMakeLists.txt
new file mode 100644
index 0000000..7be1561
--- /dev/null
+++ b/Tests/Cuda/IncludePathNoToolkit/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.8)
+project (IncludePathNoToolkit CXX CUDA)
+
+#Goal for this example:
+# Validate that between the CXX implicit include directories and the
+# CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES directories we can find
+# the cuda runtime headers
+
+add_executable(IncludePathNoToolkit main.cpp)
+target_include_directories(IncludePathNoToolkit PRIVATE
+ ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
diff --git a/Tests/Cuda/IncludePathNoToolkit/main.cpp b/Tests/Cuda/IncludePathNoToolkit/main.cpp
new file mode 100644
index 0000000..c8d5c6b
--- /dev/null
+++ b/Tests/Cuda/IncludePathNoToolkit/main.cpp
@@ -0,0 +1,8 @@
+// Only thing we care about is that these headers are found
+#include <cuda.h>
+#include <cuda_runtime_api.h>
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/Cuda/MixedStandardLevels1/CMakeLists.txt b/Tests/Cuda/MixedStandardLevels1/CMakeLists.txt
new file mode 100644
index 0000000..ac2b2f5
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels1/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.18)
+project(MixedStandardLevels1 CXX CUDA)
+
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CUDA_STANDARD 11)
+
+add_executable(MixedStandardLevels1 main.cu lib.cpp)
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET MixedStandardLevels1 PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/MixedStandardLevels1/lib.cpp b/Tests/Cuda/MixedStandardLevels1/lib.cpp
new file mode 100644
index 0000000..cabbacb
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels1/lib.cpp
@@ -0,0 +1,7 @@
+
+int func(int A, int B)
+{
+ // Verify that we have at least c++14
+ auto mult_func = [](auto a, auto b) { return a * b; };
+ return mult_func(A, B);
+}
diff --git a/Tests/Cuda/MixedStandardLevels1/main.cu b/Tests/Cuda/MixedStandardLevels1/main.cu
new file mode 100644
index 0000000..bc02c6d
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels1/main.cu
@@ -0,0 +1,9 @@
+
+#include <type_traits>
+
+int main(int argc, char** argv)
+{
+ // Verify that we have at least c++11
+ using returnv = std::integral_constant<int, 0>;
+ return returnv::value;
+}
diff --git a/Tests/Cuda/MixedStandardLevels2/CMakeLists.txt b/Tests/Cuda/MixedStandardLevels2/CMakeLists.txt
new file mode 100644
index 0000000..9ef734b
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels2/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.18)
+project(MixedStandardLevels2 CXX CUDA)
+
+set(CMAKE_CXX_STANDARD 17) #this can decay
+
+add_executable(MixedStandardLevels2 main.cu lib.cpp)
+target_compile_features(MixedStandardLevels2 PUBLIC cuda_std_11)
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET MixedStandardLevels2 PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/MixedStandardLevels2/lib.cpp b/Tests/Cuda/MixedStandardLevels2/lib.cpp
new file mode 100644
index 0000000..cabbacb
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels2/lib.cpp
@@ -0,0 +1,7 @@
+
+int func(int A, int B)
+{
+ // Verify that we have at least c++14
+ auto mult_func = [](auto a, auto b) { return a * b; };
+ return mult_func(A, B);
+}
diff --git a/Tests/Cuda/MixedStandardLevels2/main.cu b/Tests/Cuda/MixedStandardLevels2/main.cu
new file mode 100644
index 0000000..a97a41e
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels2/main.cu
@@ -0,0 +1,11 @@
+
+#if __cplusplus < 201103L && !defined(_MSC_VER)
+# error "invalid standard value"
+#endif
+#include <type_traits>
+
+int main(int argc, char** argv)
+{
+ using returnv = std::integral_constant<int, 0>;
+ return returnv::value;
+}
diff --git a/Tests/Cuda/MixedStandardLevels3/CMakeLists.txt b/Tests/Cuda/MixedStandardLevels3/CMakeLists.txt
new file mode 100644
index 0000000..629d99c
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels3/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.18)
+project(MixedStandardLevels3 CXX CUDA)
+
+add_executable(MixedStandardLevels3 main.cu lib.cpp)
+target_compile_features(MixedStandardLevels3 PUBLIC cuda_std_03 cxx_std_14)
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET MixedStandardLevels3 PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/MixedStandardLevels3/lib.cpp b/Tests/Cuda/MixedStandardLevels3/lib.cpp
new file mode 100644
index 0000000..cabbacb
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels3/lib.cpp
@@ -0,0 +1,7 @@
+
+int func(int A, int B)
+{
+ // Verify that we have at least c++14
+ auto mult_func = [](auto a, auto b) { return a * b; };
+ return mult_func(A, B);
+}
diff --git a/Tests/Cuda/MixedStandardLevels3/main.cu b/Tests/Cuda/MixedStandardLevels3/main.cu
new file mode 100644
index 0000000..1c19e8d
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels3/main.cu
@@ -0,0 +1,5 @@
+
+int main(int argc, char** argv)
+{
+ return 0;
+}
diff --git a/Tests/Cuda/MixedStandardLevels4/CMakeLists.txt b/Tests/Cuda/MixedStandardLevels4/CMakeLists.txt
new file mode 100644
index 0000000..8ce57ca
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels4/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.18)
+project(MixedStandardLevels4 CXX CUDA)
+
+set(CMAKE_CUDA_STANDARD 03)
+
+add_executable(MixedStandardLevels4 main.cu lib.cpp)
+target_compile_features(MixedStandardLevels4 PUBLIC cxx_std_14)
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET MixedStandardLevels4 PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/MixedStandardLevels4/lib.cpp b/Tests/Cuda/MixedStandardLevels4/lib.cpp
new file mode 100644
index 0000000..2a65c77
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels4/lib.cpp
@@ -0,0 +1,16 @@
+
+
+constexpr int func(int A, int B)
+{
+#if defined(_MSC_VER) && _MSC_VER < 1913
+ // no support for extended constexpr
+ return B * A;
+#else
+ // Verify that we have at least c++14
+ if (A < B) {
+ return A + B;
+ } else {
+ return B * A;
+ }
+#endif
+}
diff --git a/Tests/Cuda/MixedStandardLevels4/main.cu b/Tests/Cuda/MixedStandardLevels4/main.cu
new file mode 100644
index 0000000..1c19e8d
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels4/main.cu
@@ -0,0 +1,5 @@
+
+int main(int argc, char** argv)
+{
+ return 0;
+}
diff --git a/Tests/Cuda/MixedStandardLevels5/CMakeLists.txt b/Tests/Cuda/MixedStandardLevels5/CMakeLists.txt
new file mode 100644
index 0000000..a3c3557
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels5/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.18)
+project(MixedStandardLevels5 CXX CUDA)
+
+set(CMAKE_CXX_STANDARD 98)
+
+add_executable(MixedStandardLevels5 main.cu lib.cpp)
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET MixedStandardLevels5 PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/MixedStandardLevels5/lib.cpp b/Tests/Cuda/MixedStandardLevels5/lib.cpp
new file mode 100644
index 0000000..dd7b31b
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels5/lib.cpp
@@ -0,0 +1,13 @@
+
+#if __cplusplus >= 201103L
+# error "invalid standard value"
+#endif
+int func(int A, int B)
+{
+ // Verify that we have at least c++14
+ if (A < B) {
+ return A + B;
+ } else {
+ return B * A;
+ }
+}
diff --git a/Tests/Cuda/MixedStandardLevels5/main.cu b/Tests/Cuda/MixedStandardLevels5/main.cu
new file mode 100644
index 0000000..c79afd6
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels5/main.cu
@@ -0,0 +1,8 @@
+
+#if __cplusplus >= 201103L
+# error "invalid standard value"
+#endif
+int main(int argc, char** argv)
+{
+ return 0;
+}
diff --git a/Tests/Cuda/NotEnabled/CMakeLists.txt b/Tests/Cuda/NotEnabled/CMakeLists.txt
new file mode 100644
index 0000000..968751b
--- /dev/null
+++ b/Tests/Cuda/NotEnabled/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.7)
+project(CudaNotEnabled CXX)
+
+add_library(HasCudaProps lib.cxx)
+
+target_compile_features(HasCudaProps PUBLIC cxx_std_11)
+#Verify that setting this variables in a project that doesn't have CUDA
+#enabled allow for the project to configure and build correctly.
+#Tests the fix for #19432
+set_property(TARGET HasCudaProps PROPERTY CUDA_SEPARABLE_COMPILATION ON)
+set_property(TARGET HasCudaProps PROPERTY CUDA_RESOLVE_DEVICE_SYMBOLS ON)
+
+add_executable(CudaNotEnabled main.cxx)
+target_link_libraries(CudaNotEnabled PRIVATE HasCudaProps)
diff --git a/Tests/Cuda/NotEnabled/lib.cxx b/Tests/Cuda/NotEnabled/lib.cxx
new file mode 100644
index 0000000..5dae5a3
--- /dev/null
+++ b/Tests/Cuda/NotEnabled/lib.cxx
@@ -0,0 +1,5 @@
+
+int cxx_function(int input)
+{
+ return input;
+}
diff --git a/Tests/Cuda/NotEnabled/main.cxx b/Tests/Cuda/NotEnabled/main.cxx
new file mode 100644
index 0000000..a644207
--- /dev/null
+++ b/Tests/Cuda/NotEnabled/main.cxx
@@ -0,0 +1,9 @@
+
+#include <type_traits>
+
+int main(int argc, char** argv)
+{
+ // make sure we have c++11 enabled
+ using returnv = std::integral_constant<int, 0>;
+ return returnv::value;
+}
diff --git a/Tests/Cuda/ObjectLibrary/CMakeLists.txt b/Tests/Cuda/ObjectLibrary/CMakeLists.txt
new file mode 100644
index 0000000..d308514
--- /dev/null
+++ b/Tests/Cuda/ObjectLibrary/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.18)
+project (ObjectLibrary CUDA CXX)
+#Goal for this example:
+#
+#Build C++ and CUDA object files and than use them to make an executable
+#Make sure that CMake logic to handle object output when multiple files
+#with the same name works
+add_subdirectory(Conflicts)
+
+add_library(CudaMixedObjectLib OBJECT static.cu static.cpp)
+
+add_executable(CudaObjectLibrary
+ main.cpp
+ $<TARGET_OBJECTS:CudaMixedObjectLib>
+ $<TARGET_OBJECTS:CudaConflicts>)
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET CudaObjectLibrary PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/ObjectLibrary/Conflicts/CMakeLists.txt b/Tests/Cuda/ObjectLibrary/Conflicts/CMakeLists.txt
new file mode 100644
index 0000000..1602f8a
--- /dev/null
+++ b/Tests/Cuda/ObjectLibrary/Conflicts/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+add_library(CudaConflicts OBJECT static.cu)
diff --git a/Tests/Cuda/ObjectLibrary/Conflicts/static.cu b/Tests/Cuda/ObjectLibrary/Conflicts/static.cu
new file mode 100644
index 0000000..30aa121
--- /dev/null
+++ b/Tests/Cuda/ObjectLibrary/Conflicts/static.cu
@@ -0,0 +1,18 @@
+
+#include <iostream>
+
+#include <cuda.h>
+#include <cuda_runtime.h>
+
+int __host__ cu2_sq_func(int x)
+{
+ cudaError_t err;
+ int nDevices = 0;
+ err = cudaGetDeviceCount(&nDevices);
+ if (err != cudaSuccess) {
+ std::cerr << "nDevices: " << nDevices << std::endl;
+ std::cerr << "err: " << err << std::endl;
+ return 1;
+ }
+ return x * x;
+}
diff --git a/Tests/Cuda/ObjectLibrary/main.cpp b/Tests/Cuda/ObjectLibrary/main.cpp
new file mode 100644
index 0000000..e28f088
--- /dev/null
+++ b/Tests/Cuda/ObjectLibrary/main.cpp
@@ -0,0 +1,18 @@
+
+#include <iostream>
+
+int cpp_sq_func(int);
+int cu1_sq_func(int);
+int cu2_sq_func(int);
+
+bool test_functions()
+{
+ return (cu1_sq_func(42) == cpp_sq_func(42)) &&
+ (cu2_sq_func(42) == cpp_sq_func(42));
+}
+
+int main(int argc, char** argv)
+{
+ int result = test_functions() ? 0 : 1;
+ return result;
+}
diff --git a/Tests/Cuda/ObjectLibrary/static.cpp b/Tests/Cuda/ObjectLibrary/static.cpp
new file mode 100644
index 0000000..527f7f5
--- /dev/null
+++ b/Tests/Cuda/ObjectLibrary/static.cpp
@@ -0,0 +1,6 @@
+int file1_sq_func(int);
+
+int cpp_sq_func(int x)
+{
+ return x * x;
+}
diff --git a/Tests/Cuda/ObjectLibrary/static.cu b/Tests/Cuda/ObjectLibrary/static.cu
new file mode 100644
index 0000000..530a114
--- /dev/null
+++ b/Tests/Cuda/ObjectLibrary/static.cu
@@ -0,0 +1,18 @@
+
+#include <iostream>
+
+#include <cuda.h>
+#include <cuda_runtime.h>
+
+int __host__ cu1_sq_func(int x)
+{
+ cudaError_t err;
+ int nDevices = 0;
+ err = cudaGetDeviceCount(&nDevices);
+ if (err != cudaSuccess) {
+ std::cerr << "nDevices: " << nDevices << std::endl;
+ std::cerr << "err: " << err << std::endl;
+ return 1;
+ }
+ return x * x;
+}
diff --git a/Tests/Cuda/ProperDeviceLibraries/CMakeLists.txt b/Tests/Cuda/ProperDeviceLibraries/CMakeLists.txt
new file mode 100644
index 0000000..1ef77f4
--- /dev/null
+++ b/Tests/Cuda/ProperDeviceLibraries/CMakeLists.txt
@@ -0,0 +1,49 @@
+cmake_minimum_required(VERSION 3.18)
+project(ProperDeviceLibraries CXX CUDA)
+
+set(CMAKE_CUDA_STANDARD 11)
+
+set(THREADS_PREFER_PTHREAD_FLAG ON)
+find_package(Threads)
+
+if(CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 10.0.0)
+ # cublas_device requires at least sm_35.
+ set(CMAKE_CUDA_ARCHITECTURES 35)
+endif()
+
+add_executable(ProperDeviceLibraries main.cu)
+set_target_properties(ProperDeviceLibraries
+ PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
+
+add_library(UseThreadsMixed SHARED use_pthreads.cxx use_pthreads.cu)
+target_link_libraries(UseThreadsMixed Threads::Threads)
+
+add_library(UseThreadsCuda SHARED use_pthreads.cu)
+target_link_libraries(UseThreadsCuda Threads::Threads)
+
+target_link_libraries(ProperDeviceLibraries PRIVATE UseThreadsMixed UseThreadsCuda)
+
+if(THREADS_HAVE_PTHREAD_ARG AND CMAKE_USE_PTHREADS_INIT)
+ add_library(UseExplicitPThreadsFlag SHARED use_pthreads.cu)
+ target_compile_options(UseExplicitPThreadsFlag PUBLIC "-Xcompiler=-pthread")
+ target_link_libraries(UseExplicitPThreadsFlag PUBLIC "-pthread")
+
+ add_library(UseExplicitLThreadsFlag SHARED use_pthreads.cu)
+ target_compile_options(UseExplicitLThreadsFlag PUBLIC "-Xcompiler=-pthread")
+ target_link_libraries(UseExplicitLThreadsFlag PUBLIC "-lpthread")
+
+ add_library(UseExplicitLongThreadsFlag SHARED use_pthreads.cu)
+ target_link_libraries(UseExplicitLongThreadsFlag PUBLIC "--library pthread")
+
+ target_link_libraries(ProperDeviceLibraries PRIVATE UseExplicitPThreadsFlag UseExplicitLThreadsFlag UseExplicitLongThreadsFlag)
+endif()
+
+if(CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 10.0.0)
+ #CUDA 10 removed the cublas_device library
+ target_link_libraries(ProperDeviceLibraries PRIVATE cublas_device)
+endif()
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET ProperDeviceLibraries PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/ProperDeviceLibraries/main.cu b/Tests/Cuda/ProperDeviceLibraries/main.cu
new file mode 100644
index 0000000..397804c
--- /dev/null
+++ b/Tests/Cuda/ProperDeviceLibraries/main.cu
@@ -0,0 +1,93 @@
+
+#include <iostream>
+
+#include <cublas_v2.h>
+#include <cuda_runtime.h>
+
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+
+# include <pthread.h>
+static int verify_linking_to_pthread()
+{
+ return static_cast<int>(pthread_self());
+}
+#endif
+
+// this test only makes sense for versions of CUDA that ships
+// static libraries that have separable compilation device symbols
+#if __CUDACC_VER_MAJOR__ <= 9
+__global__ void deviceCublasSgemm(int n, float alpha, float beta,
+ const float* d_A, const float* d_B,
+ float* d_C)
+{
+ cublasHandle_t cnpHandle;
+ cublasStatus_t status = cublasCreate(&cnpHandle);
+
+ if (status != CUBLAS_STATUS_SUCCESS) {
+ return;
+ }
+
+ // Call function defined in the cublas_device system static library.
+ // This way we can verify that we properly pass system libraries to the
+ // device link line
+ status = cublasSgemm(cnpHandle, CUBLAS_OP_N, CUBLAS_OP_N, n, n, n, &alpha,
+ d_A, n, d_B, n, &beta, d_C, n);
+
+ cublasDestroy(cnpHandle);
+}
+#endif
+
+int choose_cuda_device()
+{
+ int nDevices = 0;
+ cudaError_t err = cudaGetDeviceCount(&nDevices);
+ if (err != cudaSuccess) {
+ std::cerr << "Failed to retrieve the number of CUDA enabled devices"
+ << std::endl;
+ return 1;
+ }
+ for (int i = 0; i < nDevices; ++i) {
+ cudaDeviceProp prop;
+ cudaError_t err = cudaGetDeviceProperties(&prop, i);
+ if (err != cudaSuccess) {
+ std::cerr << "Could not retrieve properties from CUDA device " << i
+ << std::endl;
+ return 1;
+ }
+
+ if (prop.major > 3 || (prop.major == 3 && prop.minor >= 5)) {
+ err = cudaSetDevice(i);
+ if (err != cudaSuccess) {
+ std::cout << "Could not select CUDA device " << i << std::endl;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ std::cout << "Could not find a CUDA enabled card supporting compute >=3.5"
+ << std::endl;
+ return 1;
+}
+
+int main(int argc, char** argv)
+{
+ int ret = choose_cuda_device();
+ if (ret) {
+ return 0;
+ }
+
+#if __CUDACC_VER_MAJOR__ <= 9
+ // initial values that will make sure that the cublasSgemm won't actually
+ // do any work
+ int n = 0;
+ float alpha = 1;
+ float beta = 1;
+ float* d_A = nullptr;
+ float* d_B = nullptr;
+ float* d_C = nullptr;
+ deviceCublasSgemm<<<1, 1>>>(n, alpha, beta, d_A, d_B, d_C);
+#endif
+
+ return 0;
+}
diff --git a/Tests/Cuda/ProperDeviceLibraries/use_pthreads.cu b/Tests/Cuda/ProperDeviceLibraries/use_pthreads.cu
new file mode 100644
index 0000000..c57b8a8
--- /dev/null
+++ b/Tests/Cuda/ProperDeviceLibraries/use_pthreads.cu
@@ -0,0 +1,9 @@
+
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+
+# include <pthread.h>
+static int verify_linking_to_pthread_cuda()
+{
+ return static_cast<int>(pthread_self());
+}
+#endif
diff --git a/Tests/Cuda/ProperDeviceLibraries/use_pthreads.cxx b/Tests/Cuda/ProperDeviceLibraries/use_pthreads.cxx
new file mode 100644
index 0000000..dc7c208
--- /dev/null
+++ b/Tests/Cuda/ProperDeviceLibraries/use_pthreads.cxx
@@ -0,0 +1,9 @@
+
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+
+# include <pthread.h>
+static int verify_linking_to_pthread_cxx()
+{
+ return static_cast<int>(pthread_self());
+}
+#endif
diff --git a/Tests/Cuda/ProperLinkFlags/CMakeLists.txt b/Tests/Cuda/ProperLinkFlags/CMakeLists.txt
new file mode 100644
index 0000000..862b03b
--- /dev/null
+++ b/Tests/Cuda/ProperLinkFlags/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 3.18)
+project(ProperLinkFlags CUDA CXX)
+
+#Goal for this example:
+#Verify that when we have CXX and CUDA enabled and we link an executable that
+#has CUDA and CXX we use the CUDA link flags when doing the device link
+#step
+
+#Specify a set of valid CUDA flags and an invalid set of CXX flags ( for CUDA )
+#to make sure we don't use the CXX flags when linking CUDA executables
+if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
+ string(APPEND CMAKE_CUDA_FLAGS "--use_fast_math")
+elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang")
+ string(APPEND CMAKE_CUDA_FLAGS "-ffast-math")
+endif()
+
+set(CMAKE_CXX_FLAGS "-Wall")
+
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CUDA_STANDARD 11)
+add_executable(ProperLinkFlags file1.cu main.cxx)
+
+set_target_properties( ProperLinkFlags
+ PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
diff --git a/Tests/Cuda/ProperLinkFlags/file1.cu b/Tests/Cuda/ProperLinkFlags/file1.cu
new file mode 100644
index 0000000..1ce63bf
--- /dev/null
+++ b/Tests/Cuda/ProperLinkFlags/file1.cu
@@ -0,0 +1,10 @@
+
+#include "file1.h"
+
+result_type __device__ file1_func(int x)
+{
+ result_type r;
+ r.input = x;
+ r.sum = x * x;
+ return r;
+}
diff --git a/Tests/Cuda/ProperLinkFlags/file1.h b/Tests/Cuda/ProperLinkFlags/file1.h
new file mode 100644
index 0000000..ff1945c
--- /dev/null
+++ b/Tests/Cuda/ProperLinkFlags/file1.h
@@ -0,0 +1,7 @@
+
+#pragma once
+struct result_type
+{
+ int input;
+ int sum;
+};
diff --git a/Tests/Cuda/ProperLinkFlags/main.cxx b/Tests/Cuda/ProperLinkFlags/main.cxx
new file mode 100644
index 0000000..7c0ee9e
--- /dev/null
+++ b/Tests/Cuda/ProperLinkFlags/main.cxx
@@ -0,0 +1,9 @@
+
+#include <iostream>
+
+#include "file1.h"
+
+int main(int argc, char** argv)
+{
+ return 0;
+}
diff --git a/Tests/Cuda/SeparableCompCXXOnly/CMakeLists.txt b/Tests/Cuda/SeparableCompCXXOnly/CMakeLists.txt
new file mode 100644
index 0000000..97670e3
--- /dev/null
+++ b/Tests/Cuda/SeparableCompCXXOnly/CMakeLists.txt
@@ -0,0 +1,3 @@
+project(SeparableCompCXXOnly LANGUAGES CXX CUDA)
+set(CMAKE_CUDA_SEPARABLE_COMPILATION ON)
+add_executable(SeparableCompCXXOnly main.cpp)
diff --git a/Tests/Cuda/SeparableCompCXXOnly/main.cpp b/Tests/Cuda/SeparableCompCXXOnly/main.cpp
new file mode 100644
index 0000000..8135246
--- /dev/null
+++ b/Tests/Cuda/SeparableCompCXXOnly/main.cpp
@@ -0,0 +1,5 @@
+
+int main(int, char const* [])
+{
+ return 0;
+}
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt b/Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt
new file mode 100644
index 0000000..61a3190
--- /dev/null
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt
@@ -0,0 +1,35 @@
+cmake_minimum_required(VERSION 3.18)
+project(SharedRuntimePlusToolkit CXX)
+
+#Goal for this example:
+# Validate that with c++ we can use some components of the CUDA toolkit, and
+# specify the cuda runtime
+find_package(CUDAToolkit REQUIRED)
+
+add_library(Common OBJECT curand.cpp nppif.cpp)
+target_link_libraries(Common PRIVATE CUDA::toolkit)
+set_target_properties(Common PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+#shared runtime with shared toolkit libraries
+add_library(SharedToolkit SHARED shared.cpp)
+target_link_libraries(SharedToolkit PRIVATE Common PUBLIC CUDA::curand CUDA::nppif)
+target_link_libraries(SharedToolkit PUBLIC CUDA::cudart)
+
+# The CUDA only ships the shared version of the toolkit libraries
+# on windows
+if(NOT WIN32)
+ #shared runtime with static toolkit libraries
+ add_library(StaticToolkit SHARED static.cpp)
+ target_link_libraries(StaticToolkit PRIVATE Common CUDA::curand_static CUDA::nppif_static)
+ target_link_libraries(StaticToolkit PUBLIC CUDA::cudart)
+
+ #static runtime with mixed toolkit libraries
+ add_library(MixedToolkit SHARED mixed.cpp)
+ target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand_static CUDA::nppif)
+ target_link_libraries(MixedToolkit PUBLIC CUDA::cudart)
+endif()
+
+add_executable(SharedRuntimePlusToolkit main.cpp)
+target_link_libraries(SharedRuntimePlusToolkit PRIVATE SharedToolkit
+ $<TARGET_NAME_IF_EXISTS:StaticToolkit>
+ $<TARGET_NAME_IF_EXISTS:MixedToolkit>)
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/curand.cpp b/Tests/Cuda/SharedRuntimePlusToolkit/curand.cpp
new file mode 100644
index 0000000..fdd7b53
--- /dev/null
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/curand.cpp
@@ -0,0 +1,65 @@
+// Comes from:
+// https://docs.nvidia.com/cuda/curand/host-api-overview.html#host-api-example
+
+#ifdef _WIN32
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+/*
+ * This program uses the host CURAND API to generate 100
+ * pseudorandom floats.
+ */
+#include <cuda.h>
+#include <curand.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define CUDA_CALL(x) \
+ do { \
+ if ((x) != cudaSuccess) { \
+ printf("Error at %s:%d\n", __FILE__, __LINE__); \
+ return EXIT_FAILURE; \
+ } \
+ } while (0)
+#define CURAND_CALL(x) \
+ do { \
+ if ((x) != CURAND_STATUS_SUCCESS) { \
+ printf("Error at %s:%d\n", __FILE__, __LINE__); \
+ return EXIT_FAILURE; \
+ } \
+ } while (0)
+
+EXPORT int curand_main()
+{
+ size_t n = 100;
+ size_t i;
+ curandGenerator_t gen;
+ float *devData, *hostData;
+
+ /* Allocate n floats on host */
+ hostData = (float*)calloc(n, sizeof(float));
+
+ /* Allocate n floats on device */
+ CUDA_CALL(cudaMalloc((void**)&devData, n * sizeof(float)));
+
+ /* Create pseudo-random number generator */
+ CURAND_CALL(curandCreateGenerator(&gen, CURAND_RNG_PSEUDO_DEFAULT));
+
+ /* Set seed */
+ CURAND_CALL(curandSetPseudoRandomGeneratorSeed(gen, 1234ULL));
+
+ /* Generate n floats on device */
+ CURAND_CALL(curandGenerateUniform(gen, devData, n));
+
+ /* Copy device memory to host */
+ CUDA_CALL(
+ cudaMemcpy(hostData, devData, n * sizeof(float), cudaMemcpyDeviceToHost));
+
+ /* Cleanup */
+ CURAND_CALL(curandDestroyGenerator(gen));
+ CUDA_CALL(cudaFree(devData));
+ free(hostData);
+ return EXIT_SUCCESS;
+}
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/main.cpp b/Tests/Cuda/SharedRuntimePlusToolkit/main.cpp
new file mode 100644
index 0000000..2a4da22
--- /dev/null
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/main.cpp
@@ -0,0 +1,23 @@
+
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+IMPORT int shared_version();
+int static_version()
+{
+ return 0;
+}
+int mixed_version()
+{
+ return 0;
+}
+#else
+int shared_version();
+int static_version();
+int mixed_version();
+#endif
+
+int main()
+{
+ return mixed_version() == 0 && shared_version() == 0 &&
+ static_version() == 0;
+}
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/mixed.cpp b/Tests/Cuda/SharedRuntimePlusToolkit/mixed.cpp
new file mode 100644
index 0000000..6de6886
--- /dev/null
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/mixed.cpp
@@ -0,0 +1,16 @@
+
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+# define EXPORT __declspec(dllexport)
+#else
+# define IMPORT
+# define EXPORT
+#endif
+
+IMPORT int curand_main();
+IMPORT int nppif_main();
+
+EXPORT int mixed_version()
+{
+ return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/nppif.cpp b/Tests/Cuda/SharedRuntimePlusToolkit/nppif.cpp
new file mode 100644
index 0000000..ac5341c
--- /dev/null
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/nppif.cpp
@@ -0,0 +1,92 @@
+// Comes from
+// https://devtalk.nvidia.com/default/topic/1037482/gpu-accelerated-libraries/help-me-help-you-with-modern-cmake-and-cuda-mwe-for-npp/post/5271066/#5271066
+
+#ifdef _WIN32
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+#include <cstdio>
+#include <iostream>
+
+#include <assert.h>
+#include <cuda_runtime_api.h>
+#include <nppi_filtering_functions.h>
+
+EXPORT int nppif_main()
+{
+ /**
+ * 8-bit unsigned single-channel 1D row convolution.
+ */
+ const int simgrows = 32;
+ const int simgcols = 32;
+ Npp8u *d_pSrc, *d_pDst;
+ const int nMaskSize = 3;
+ NppiSize oROI;
+ oROI.width = simgcols - nMaskSize;
+ oROI.height = simgrows;
+ const int simgsize = simgrows * simgcols * sizeof(d_pSrc[0]);
+ const int dimgsize = oROI.width * oROI.height * sizeof(d_pSrc[0]);
+ const int simgpix = simgrows * simgcols;
+ const int dimgpix = oROI.width * oROI.height;
+ const int nSrcStep = simgcols * sizeof(d_pSrc[0]);
+ const int nDstStep = oROI.width * sizeof(d_pDst[0]);
+ const int pixval = 1;
+ const int nDivisor = 1;
+ const Npp32s h_pKernel[nMaskSize] = { pixval, pixval, pixval };
+ Npp32s* d_pKernel;
+ const Npp32s nAnchor = 2;
+ cudaError_t err = cudaMalloc((void**)&d_pSrc, simgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMalloc((void**)&d_pDst, dimgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMalloc((void**)&d_pKernel, nMaskSize * sizeof(d_pKernel[0]));
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ // set image to pixval initially
+ err = cudaMemset(d_pSrc, pixval, simgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMemset(d_pDst, 0, dimgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMemcpy(d_pKernel, h_pKernel, nMaskSize * sizeof(d_pKernel[0]),
+ cudaMemcpyHostToDevice);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ // copy src to dst
+ NppStatus ret =
+ nppiFilterRow_8u_C1R(d_pSrc, nSrcStep, d_pDst, nDstStep, oROI, d_pKernel,
+ nMaskSize, nAnchor, nDivisor);
+ assert(ret == NPP_NO_ERROR);
+ Npp8u* h_imgres = new Npp8u[dimgpix];
+ err = cudaMemcpy(h_imgres, d_pDst, dimgsize, cudaMemcpyDeviceToHost);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ // test for filtering
+ for (int i = 0; i < dimgpix; i++) {
+ if (h_imgres[i] != (pixval * pixval * nMaskSize)) {
+ fprintf(stderr, "h_imgres at index %d failed to match\n", i);
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/shared.cpp b/Tests/Cuda/SharedRuntimePlusToolkit/shared.cpp
new file mode 100644
index 0000000..f3c3dbc
--- /dev/null
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/shared.cpp
@@ -0,0 +1,16 @@
+
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+# define EXPORT __declspec(dllexport)
+#else
+# define IMPORT
+# define EXPORT
+#endif
+
+int curand_main();
+int nppif_main();
+
+EXPORT int shared_version()
+{
+ return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/static.cpp b/Tests/Cuda/SharedRuntimePlusToolkit/static.cpp
new file mode 100644
index 0000000..6932fa3
--- /dev/null
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/static.cpp
@@ -0,0 +1,16 @@
+
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+# define EXPORT __declspec(dllexport)
+#else
+# define IMPORT
+# define EXPORT
+#endif
+
+IMPORT int curand_main();
+IMPORT int nppif_main();
+
+EXPORT int static_version()
+{
+ return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt b/Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt
new file mode 100644
index 0000000..df6c392
--- /dev/null
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.15)
+project(StaticRuntimePlusToolkit CXX)
+
+#Goal for this example:
+# Validate that with c++ we can use some components of the CUDA toolkit, and
+# specify the cuda runtime
+find_package(CUDAToolkit REQUIRED)
+
+add_library(Common OBJECT curand.cpp nppif.cpp)
+target_link_libraries(Common PRIVATE CUDA::toolkit)
+set_target_properties(Common PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+#static runtime with shared toolkit libraries
+add_library(SharedToolkit SHARED shared.cpp)
+target_link_libraries(SharedToolkit PRIVATE Common PUBLIC CUDA::curand CUDA::nppif)
+target_link_libraries(SharedToolkit PUBLIC CUDA::cudart_static)
+
+#static runtime with static toolkit libraries
+add_library(StaticToolkit SHARED static.cpp)
+target_link_libraries(StaticToolkit PRIVATE Common CUDA::curand_static CUDA::nppif_static)
+target_link_libraries(StaticToolkit PUBLIC CUDA::cudart_static)
+
+#static runtime with mixed toolkit libraries
+add_library(MixedToolkit SHARED mixed.cpp)
+target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand CUDA::nppif_static)
+target_link_libraries(MixedToolkit PUBLIC CUDA::cudart_static)
+
+add_executable(StaticRuntimePlusToolkit main.cpp)
+target_link_libraries(StaticRuntimePlusToolkit PRIVATE SharedToolkit StaticToolkit MixedToolkit)
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp
new file mode 100644
index 0000000..95872f0
--- /dev/null
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp
@@ -0,0 +1,59 @@
+// Comes from:
+// https://docs.nvidia.com/cuda/curand/host-api-overview.html#host-api-example
+
+/*
+ * This program uses the host CURAND API to generate 100
+ * pseudorandom floats.
+ */
+#include <cuda.h>
+#include <curand.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define CUDA_CALL(x) \
+ do { \
+ if ((x) != cudaSuccess) { \
+ printf("Error at %s:%d\n", __FILE__, __LINE__); \
+ return EXIT_FAILURE; \
+ } \
+ } while (0)
+#define CURAND_CALL(x) \
+ do { \
+ if ((x) != CURAND_STATUS_SUCCESS) { \
+ printf("Error at %s:%d\n", __FILE__, __LINE__); \
+ return EXIT_FAILURE; \
+ } \
+ } while (0)
+
+int curand_main()
+{
+ size_t n = 100;
+ size_t i;
+ curandGenerator_t gen;
+ float *devData, *hostData;
+
+ /* Allocate n floats on host */
+ hostData = (float*)calloc(n, sizeof(float));
+
+ /* Allocate n floats on device */
+ CUDA_CALL(cudaMalloc((void**)&devData, n * sizeof(float)));
+
+ /* Create pseudo-random number generator */
+ CURAND_CALL(curandCreateGenerator(&gen, CURAND_RNG_PSEUDO_DEFAULT));
+
+ /* Set seed */
+ CURAND_CALL(curandSetPseudoRandomGeneratorSeed(gen, 1234ULL));
+
+ /* Generate n floats on device */
+ CURAND_CALL(curandGenerateUniform(gen, devData, n));
+
+ /* Copy device memory to host */
+ CUDA_CALL(
+ cudaMemcpy(hostData, devData, n * sizeof(float), cudaMemcpyDeviceToHost));
+
+ /* Cleanup */
+ CURAND_CALL(curandDestroyGenerator(gen));
+ CUDA_CALL(cudaFree(devData));
+ free(hostData);
+ return EXIT_SUCCESS;
+}
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/main.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/main.cpp
new file mode 100644
index 0000000..5a09f8e
--- /dev/null
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/main.cpp
@@ -0,0 +1,11 @@
+
+
+int shared_version();
+int static_version();
+int mixed_version();
+
+int main()
+{
+ return mixed_version() == 0 && shared_version() == 0 &&
+ static_version() == 0;
+}
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp
new file mode 100644
index 0000000..a05140d
--- /dev/null
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp
@@ -0,0 +1,8 @@
+
+int curand_main();
+int nppif_main();
+
+int mixed_version()
+{
+ return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp
new file mode 100644
index 0000000..2871090
--- /dev/null
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp
@@ -0,0 +1,86 @@
+// Comes from
+// https://devtalk.nvidia.com/default/topic/1037482/gpu-accelerated-libraries/help-me-help-you-with-modern-cmake-and-cuda-mwe-for-npp/post/5271066/#5271066
+
+#include <cstdio>
+#include <iostream>
+
+#include <assert.h>
+#include <cuda_runtime_api.h>
+#include <nppi_filtering_functions.h>
+
+int nppif_main()
+{
+ /**
+ * 8-bit unsigned single-channel 1D row convolution.
+ */
+ const int simgrows = 32;
+ const int simgcols = 32;
+ Npp8u *d_pSrc, *d_pDst;
+ const int nMaskSize = 3;
+ NppiSize oROI;
+ oROI.width = simgcols - nMaskSize;
+ oROI.height = simgrows;
+ const int simgsize = simgrows * simgcols * sizeof(d_pSrc[0]);
+ const int dimgsize = oROI.width * oROI.height * sizeof(d_pSrc[0]);
+ const int simgpix = simgrows * simgcols;
+ const int dimgpix = oROI.width * oROI.height;
+ const int nSrcStep = simgcols * sizeof(d_pSrc[0]);
+ const int nDstStep = oROI.width * sizeof(d_pDst[0]);
+ const int pixval = 1;
+ const int nDivisor = 1;
+ const Npp32s h_pKernel[nMaskSize] = { pixval, pixval, pixval };
+ Npp32s* d_pKernel;
+ const Npp32s nAnchor = 2;
+ cudaError_t err = cudaMalloc((void**)&d_pSrc, simgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMalloc((void**)&d_pDst, dimgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMalloc((void**)&d_pKernel, nMaskSize * sizeof(d_pKernel[0]));
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ // set image to pixval initially
+ err = cudaMemset(d_pSrc, pixval, simgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMemset(d_pDst, 0, dimgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMemcpy(d_pKernel, h_pKernel, nMaskSize * sizeof(d_pKernel[0]),
+ cudaMemcpyHostToDevice);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ // copy src to dst
+ NppStatus ret =
+ nppiFilterRow_8u_C1R(d_pSrc, nSrcStep, d_pDst, nDstStep, oROI, d_pKernel,
+ nMaskSize, nAnchor, nDivisor);
+ assert(ret == NPP_NO_ERROR);
+ Npp8u* h_imgres = new Npp8u[dimgpix];
+ err = cudaMemcpy(h_imgres, d_pDst, dimgsize, cudaMemcpyDeviceToHost);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ // test for filtering
+ for (int i = 0; i < dimgpix; i++) {
+ if (h_imgres[i] != (pixval * pixval * nMaskSize)) {
+ fprintf(stderr, "h_imgres at index %d failed to match\n", i);
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp
new file mode 100644
index 0000000..9967b66
--- /dev/null
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp
@@ -0,0 +1,8 @@
+
+int curand_main();
+int nppif_main();
+
+int shared_version()
+{
+ return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/static.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/static.cpp
new file mode 100644
index 0000000..ca7eb4c
--- /dev/null
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/static.cpp
@@ -0,0 +1,8 @@
+
+int curand_main();
+int nppif_main();
+
+int static_version()
+{
+ return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/Cuda/Toolkit/CMakeLists.txt b/Tests/Cuda/Toolkit/CMakeLists.txt
new file mode 100644
index 0000000..8b42296
--- /dev/null
+++ b/Tests/Cuda/Toolkit/CMakeLists.txt
@@ -0,0 +1,56 @@
+cmake_minimum_required(VERSION 3.15)
+project(Toolkit CXX)
+
+#Goal for this example:
+# Validate that we can use CUDAToolkit to find cuda include paths
+find_package(CUDAToolkit REQUIRED)
+
+if(NOT DEFINED CUDAToolkit_VERSION)
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDAToolkit_VERSION not found")
+endif()
+
+message(STATUS "CUDAToolkit_VERSION: ${CUDAToolkit_VERSION}")
+message(STATUS "CUDAToolkit_VERSION_MAJOR: ${CUDAToolkit_VERSION_MAJOR}")
+message(STATUS "CUDAToolkit_VERSION_MINOR: ${CUDAToolkit_VERSION_MINOR}")
+message(STATUS "CUDAToolkit_VERSION_PATCH: ${CUDAToolkit_VERSION_PATCH}")
+message(STATUS "CUDAToolkit_BIN_DIR: ${CUDAToolkit_BIN_DIR}")
+message(STATUS "CUDAToolkit_INCLUDE_DIRS: ${CUDAToolkit_INCLUDE_DIRS}")
+message(STATUS "CUDAToolkit_LIBRARY_DIR: ${CUDAToolkit_LIBRARY_DIR}")
+message(STATUS "CUDAToolkit_NVCC_EXECUTABLE ${CUDAToolkit_NVCC_EXECUTABLE}")
+
+set(cuda_libs cudart cuda_driver cublas cufft cufftw curand cusolver cusparse)
+if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 10.1)
+ list(APPEND cuda_libs cublasLt)
+endif()
+if(CUDAToolkit_VERSION_MAJOR VERSION_LESS 11)
+ list(APPEND cuda_libs nvgraph)
+endif()
+
+# Verify that all the CUDA:: targets exist even when the CUDA language isn't enabled
+foreach (cuda_lib IN LISTS cuda_libs)
+ if(NOT CUDA_${cuda_lib}_LIBRARY)
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
+ endif()
+ if(NOT TARGET CUDA::${cuda_lib})
+ message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
+ endif()
+endforeach()
+
+set(npp_libs nppc nppial nppicc nppidei nppif nppig nppim nppist nppitc npps nppisu)
+if(CUDAToolkit_VERSION_MAJOR VERSION_LESS 11)
+ list(APPEND npp_libs nppicom)
+endif()
+foreach (cuda_lib IN LISTS npp_libs)
+ if(NOT TARGET CUDA::${cuda_lib})
+ message(FATAL_ERROR "The CUDA::${cuda_lib} target was expected but couldn't be found")
+ endif()
+endforeach()
+
+foreach (cuda_lib nvrtc nvToolsExt OpenCL)
+ if(NOT TARGET CUDA::${cuda_lib})
+ message(FATAL_ERROR "The CUDA::${cuda_lib} target was expected but couldn't be found")
+ endif()
+endforeach()
+
+add_executable(Toolkit main.cpp)
+target_link_libraries(Toolkit PRIVATE CUDA::toolkit)
diff --git a/Tests/Cuda/Toolkit/main.cpp b/Tests/Cuda/Toolkit/main.cpp
new file mode 100644
index 0000000..c8d5c6b
--- /dev/null
+++ b/Tests/Cuda/Toolkit/main.cpp
@@ -0,0 +1,8 @@
+// Only thing we care about is that these headers are found
+#include <cuda.h>
+#include <cuda_runtime_api.h>
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/Cuda/WithC/CMakeLists.txt b/Tests/Cuda/WithC/CMakeLists.txt
new file mode 100644
index 0000000..cc5fa0c
--- /dev/null
+++ b/Tests/Cuda/WithC/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.18)
+project(WithC CUDA C)
+
+add_executable(CudaWithC main.c cuda.cu)
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET CudaWithC PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/WithC/cuda.cu b/Tests/Cuda/WithC/cuda.cu
new file mode 100644
index 0000000..d1be2d4
--- /dev/null
+++ b/Tests/Cuda/WithC/cuda.cu
@@ -0,0 +1,16 @@
+#include <iostream>
+
+#include <cuda.h>
+
+extern "C" int use_cuda(void)
+{
+ int nDevices = 0;
+ cudaError_t err = cudaGetDeviceCount(&nDevices);
+ if (err != cudaSuccess) {
+ std::cerr << "Failed to retrieve the number of CUDA enabled devices"
+ << std::endl;
+ return 1;
+ }
+ std::cout << "Found " << nDevices << " CUDA enabled devices" << std::endl;
+ return 0;
+}
diff --git a/Tests/Cuda/WithC/main.c b/Tests/Cuda/WithC/main.c
new file mode 100644
index 0000000..5f3c781
--- /dev/null
+++ b/Tests/Cuda/WithC/main.c
@@ -0,0 +1,14 @@
+extern int use_cuda(void);
+
+#ifdef _WIN32
+# include <windows.h>
+#endif
+
+int main()
+{
+#ifdef _WIN32
+ /* Use an API that requires CMake's "standard" C libraries. */
+ GetOpenFileName(NULL);
+#endif
+ return use_cuda();
+}
diff --git a/Tests/CudaOnly/Architecture/CMakeLists.txt b/Tests/CudaOnly/Architecture/CMakeLists.txt
new file mode 100644
index 0000000..03e972f
--- /dev/null
+++ b/Tests/CudaOnly/Architecture/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.18)
+project(Architecture CUDA)
+
+add_executable(Architecture main.cu)
+set_property(TARGET Architecture PROPERTY CUDA_ARCHITECTURES 52)
+
+# Make sure CMake doesn't pass architectures if CUDA_ARCHITECTURES is OFF.
+if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
+ set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -arch=sm_52")
+elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang")
+ set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --cuda-gpu-arch=sm_52")
+endif()
+
+add_executable(ArchitectureOff main.cu)
+set_property(TARGET ArchitectureOff PROPERTY CUDA_ARCHITECTURES OFF)
diff --git a/Tests/CudaOnly/Architecture/main.cu b/Tests/CudaOnly/Architecture/main.cu
new file mode 100644
index 0000000..8c817d5
--- /dev/null
+++ b/Tests/CudaOnly/Architecture/main.cu
@@ -0,0 +1,9 @@
+#ifdef __CUDA_ARCH__
+# if __CUDA_ARCH__ != 520
+# error "Passed architecture 52, but got something else."
+# endif
+#endif
+
+int main()
+{
+}
diff --git a/Tests/CudaOnly/CMakeLists.txt b/Tests/CudaOnly/CMakeLists.txt
new file mode 100644
index 0000000..fdb7a6e
--- /dev/null
+++ b/Tests/CudaOnly/CMakeLists.txt
@@ -0,0 +1,63 @@
+macro (add_cuda_test_macro name)
+ add_test_macro("${name}" ${ARGN})
+ set_property(TEST "${name}" APPEND
+ PROPERTY LABELS "CUDA")
+endmacro ()
+
+add_cuda_test_macro(CudaOnly.Architecture Architecture)
+add_cuda_test_macro(CudaOnly.CompileFlags CudaOnlyCompileFlags)
+add_cuda_test_macro(CudaOnly.EnableStandard CudaOnlyEnableStandard)
+add_cuda_test_macro(CudaOnly.ExportPTX CudaOnlyExportPTX)
+add_cuda_test_macro(CudaOnly.SharedRuntimePlusToolkit CudaOnlySharedRuntimePlusToolkit)
+add_cuda_test_macro(CudaOnly.Standard98 CudaOnlyStandard98)
+add_cuda_test_macro(CudaOnly.Toolkit CudaOnlyToolkit)
+add_cuda_test_macro(CudaOnly.ToolkitBeforeLang CudaOnlyToolkitBeforeLang)
+add_cuda_test_macro(CudaOnly.WithDefs CudaOnlyWithDefs)
+add_cuda_test_macro(CudaOnly.CircularLinkLine CudaOnlyCircularLinkLine)
+add_cuda_test_macro(CudaOnly.ResolveDeviceSymbols CudaOnlyResolveDeviceSymbols)
+add_cuda_test_macro(CudaOnly.SeparateCompilation CudaOnlySeparateCompilation)
+
+if(CMake_TEST_CUDA AND NOT CMake_TEST_CUDA STREQUAL "Clang")
+ # Clang doesn't have flags for selecting the runtime.
+ add_cuda_test_macro(CudaOnly.SharedRuntimeViaCUDAFlags CudaOnlySharedRuntimeViaCUDAFlags)
+
+ # Only NVCC defines __CUDACC_DEBUG__ when compiling in debug mode.
+ add_cuda_test_macro(CudaOnly.GPUDebugFlag CudaOnlyGPUDebugFlag)
+endif()
+
+add_test(NAME CudaOnly.DontResolveDeviceSymbols COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMAKE_CURRENT_SOURCE_DIR}/DontResolveDeviceSymbols/"
+ "${CMAKE_CURRENT_BINARY_DIR}/DontResolveDeviceSymbols/"
+ ${build_generator_args}
+ --build-project DontResolveDeviceSymbols
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+)
+set_property(TEST "CudaOnly.DontResolveDeviceSymbols" APPEND
+ PROPERTY LABELS "CUDA")
+
+# The CUDA only ships the shared version of the toolkit libraries
+# on windows
+if(NOT WIN32)
+ add_cuda_test_macro(CudaOnly.StaticRuntimePlusToolkit CudaOnlyStaticRuntimePlusToolkit)
+endif()
+
+if(MSVC)
+ add_cuda_test_macro(CudaOnly.PDB CudaOnlyPDB)
+endif()
+
+add_test(NAME CudaOnly.RuntimeControls COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMAKE_CURRENT_SOURCE_DIR}/RuntimeControls/"
+ "${CMAKE_CURRENT_BINARY_DIR}/RuntimeControls/"
+ --build-two-config
+ ${build_generator_args}
+ --build-project RuntimeControls
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+set_property(TEST "CudaOnly.RuntimeControls" APPEND
+ PROPERTY LABELS "CUDA")
diff --git a/Tests/CudaOnly/CircularLinkLine/CMakeLists.txt b/Tests/CudaOnly/CircularLinkLine/CMakeLists.txt
new file mode 100644
index 0000000..caf9391
--- /dev/null
+++ b/Tests/CudaOnly/CircularLinkLine/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 3.18)
+project(CircularLinkLine CUDA)
+
+#Goal for this example:
+# Verify that we de-duplicate the device link line
+# Verify that a de-duplicated link line still works with circular static libraries
+
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CUDA_STANDARD 11)
+
+add_library(CUDACircularDeviceLinking1 STATIC file1.cu)
+add_library(CUDACircularDeviceLinking2 STATIC file2.cu)
+add_library(CUDACircularDeviceLinking3 STATIC file3.cu)
+add_executable(CudaOnlyCircularLinkLine main.cu)
+
+target_link_libraries(CUDACircularDeviceLinking1 PUBLIC CUDACircularDeviceLinking2)
+target_link_libraries(CUDACircularDeviceLinking2 PUBLIC CUDACircularDeviceLinking3)
+target_link_libraries(CUDACircularDeviceLinking3 PUBLIC CUDACircularDeviceLinking1)
+
+target_link_libraries(CudaOnlyCircularLinkLine PRIVATE CUDACircularDeviceLinking3)
+
+
+set_target_properties(CUDACircularDeviceLinking1
+ PROPERTIES
+ CUDA_SEPARABLE_COMPILATION ON)
+
+set_target_properties(CUDACircularDeviceLinking2
+ PROPERTIES
+ CUDA_SEPARABLE_COMPILATION ON)
+
+set_target_properties(CUDACircularDeviceLinking3
+ PROPERTIES
+ CUDA_SEPARABLE_COMPILATION ON)
diff --git a/Tests/CudaOnly/CircularLinkLine/file1.cu b/Tests/CudaOnly/CircularLinkLine/file1.cu
new file mode 100644
index 0000000..88ac4e3
--- /dev/null
+++ b/Tests/CudaOnly/CircularLinkLine/file1.cu
@@ -0,0 +1,6 @@
+
+extern __device__ int file2_func(int);
+int __device__ file1_func(int x)
+{
+ return file2_func(x);
+}
diff --git a/Tests/CudaOnly/CircularLinkLine/file2.cu b/Tests/CudaOnly/CircularLinkLine/file2.cu
new file mode 100644
index 0000000..b32dbff
--- /dev/null
+++ b/Tests/CudaOnly/CircularLinkLine/file2.cu
@@ -0,0 +1,6 @@
+
+extern __device__ int file3_func(int);
+int __device__ file2_func(int x)
+{
+ return x + file3_func(x);
+}
diff --git a/Tests/CudaOnly/CircularLinkLine/file3.cu b/Tests/CudaOnly/CircularLinkLine/file3.cu
new file mode 100644
index 0000000..7f67187
--- /dev/null
+++ b/Tests/CudaOnly/CircularLinkLine/file3.cu
@@ -0,0 +1,8 @@
+
+extern __device__ int file1_func(int);
+int __device__ file3_func(int x)
+{
+ if (x > 0)
+ return file1_func(-x);
+ return x;
+}
diff --git a/Tests/CudaOnly/CircularLinkLine/main.cu b/Tests/CudaOnly/CircularLinkLine/main.cu
new file mode 100644
index 0000000..1c19e8d
--- /dev/null
+++ b/Tests/CudaOnly/CircularLinkLine/main.cu
@@ -0,0 +1,5 @@
+
+int main(int argc, char** argv)
+{
+ return 0;
+}
diff --git a/Tests/CudaOnly/CompileFlags/CMakeLists.txt b/Tests/CudaOnly/CompileFlags/CMakeLists.txt
new file mode 100644
index 0000000..38765ec
--- /dev/null
+++ b/Tests/CudaOnly/CompileFlags/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.17)
+project(CompileFlags CUDA)
+
+add_executable(CudaOnlyCompileFlags main.cu)
+
+# Try passing CUDA architecture flags explicitly.
+if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
+ target_compile_options(CudaOnlyCompileFlags PRIVATE
+ -gencode arch=compute_50,code=compute_50
+ )
+ set_property(TARGET CudaOnlyCompileFlags PROPERTY CUDA_ARCHITECTURES)
+else()
+ set_property(TARGET CudaOnlyCompileFlags PROPERTY CUDA_ARCHITECTURES 50-real)
+endif()
+
+target_compile_options(CudaOnlyCompileFlags PRIVATE -DALWAYS_DEFINE)
diff --git a/Tests/CudaOnly/CompileFlags/main.cu b/Tests/CudaOnly/CompileFlags/main.cu
new file mode 100644
index 0000000..999c056
--- /dev/null
+++ b/Tests/CudaOnly/CompileFlags/main.cu
@@ -0,0 +1,13 @@
+#ifdef __CUDA_ARCH__
+# if __CUDA_ARCH__ != 500
+# error "Passed architecture 50, but got something else."
+# endif
+#endif
+
+#ifndef ALWAYS_DEFINE
+# error "ALWAYS_DEFINE not defined!"
+#endif
+
+int main()
+{
+}
diff --git a/Tests/CudaOnly/DontResolveDeviceSymbols/CMakeLists.txt b/Tests/CudaOnly/DontResolveDeviceSymbols/CMakeLists.txt
new file mode 100644
index 0000000..c8e8ebc
--- /dev/null
+++ b/Tests/CudaOnly/DontResolveDeviceSymbols/CMakeLists.txt
@@ -0,0 +1,49 @@
+cmake_minimum_required(VERSION 3.18)
+project(DontResolveDeviceSymbols CUDA)
+
+# Find nm and dumpbin
+if(CMAKE_NM)
+ set(dump_command ${CMAKE_NM})
+ set(dump_args --defined-only)
+ set(symbol_name cudaRegisterLinkedBinary)
+else()
+ include(GetPrerequisites)
+ message(STATUS "calling list_prerequisites to find dumpbin")
+ list_prerequisites("${CMAKE_COMMAND}" 0 0 0)
+ if(gp_dumpbin)
+ set(dump_command ${gp_dumpbin})
+ set(dump_args /SYMBOLS)
+ set(symbol_name nv_fatb)
+ endif()
+endif()
+
+
+#Goal for this example:
+# Build a static library that defines multiple methods and kernels that
+# use each other.
+# Don't resolve the device symbols in the static library
+# Don't resolve the device symbols in the executable library
+# Verify that we can't use those device symbols from anything
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CUDA_STANDARD 11)
+set(CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS OFF)
+
+add_library(CUDANoDeviceResolve SHARED file1.cu)
+set_target_properties(CUDANoDeviceResolve
+ PROPERTIES
+ CUDA_SEPARABLE_COMPILATION ON
+ POSITION_INDEPENDENT_CODE ON)
+if(MSVC)
+ target_link_options(CUDANoDeviceResolve PRIVATE "/FORCE:UNRESOLVED")
+endif()
+
+if(dump_command)
+add_custom_command(TARGET CUDANoDeviceResolve POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ -DDUMP_COMMAND=${dump_command}
+ -DDUMP_ARGS=${dump_args}
+ -DSYMBOL_NAME=${symbol_name}
+ -DTEST_LIBRARY_PATH=$<TARGET_FILE:CUDANoDeviceResolve>
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/verify.cmake
+ )
+endif()
diff --git a/Tests/CudaOnly/DontResolveDeviceSymbols/file1.cu b/Tests/CudaOnly/DontResolveDeviceSymbols/file1.cu
new file mode 100644
index 0000000..90c70e2
--- /dev/null
+++ b/Tests/CudaOnly/DontResolveDeviceSymbols/file1.cu
@@ -0,0 +1,69 @@
+
+#include <iostream>
+
+static __global__ void file1_kernel(int in, int* out)
+{
+ *out = in * in;
+}
+
+int choose_cuda_device()
+{
+ int nDevices = 0;
+ cudaError_t err = cudaGetDeviceCount(&nDevices);
+ if (err != cudaSuccess) {
+ std::cerr << "Failed to retrieve the number of CUDA enabled devices"
+ << std::endl;
+ return 1;
+ }
+ for (int i = 0; i < nDevices; ++i) {
+ cudaDeviceProp prop;
+ cudaError_t err = cudaGetDeviceProperties(&prop, i);
+ if (err != cudaSuccess) {
+ std::cerr << "Could not retrieve properties from CUDA device " << i
+ << std::endl;
+ return 1;
+ }
+ std::cout << "prop.major: " << prop.major << std::endl;
+ if (prop.major >= 3) {
+ err = cudaSetDevice(i);
+ if (err != cudaSuccess) {
+ std::cout << "Could not select CUDA device " << i << std::endl;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ std::cout << "Could not find a CUDA enabled card supporting compute >=3.0"
+ << std::endl;
+
+ return 1;
+}
+
+int file1_launch_kernel()
+{
+ int ret = choose_cuda_device();
+ if (ret) {
+ return 0;
+ }
+
+ int input = 4;
+
+ int* output;
+ cudaError_t err = cudaMallocManaged(&output, sizeof(int));
+ cudaDeviceSynchronize();
+ if (err != cudaSuccess) {
+ return 1;
+ }
+
+ file1_kernel<<<1, 1>>>(input, output);
+ cudaDeviceSynchronize();
+ err = cudaGetLastError();
+ std::cout << err << " " << cudaGetErrorString(err) << std::endl;
+ if (err == cudaSuccess) {
+ // This kernel launch should failed as the device linking never occurred
+ std::cerr << "file1_kernel: kernel launch should have failed" << std::endl;
+ return 1;
+ }
+ return 0;
+}
diff --git a/Tests/CudaOnly/DontResolveDeviceSymbols/main.cu b/Tests/CudaOnly/DontResolveDeviceSymbols/main.cu
new file mode 100644
index 0000000..84a7a19
--- /dev/null
+++ b/Tests/CudaOnly/DontResolveDeviceSymbols/main.cu
@@ -0,0 +1,7 @@
+
+#include <iostream>
+
+int main(int argc, char** argv)
+{
+ return 0;
+}
diff --git a/Tests/CudaOnly/DontResolveDeviceSymbols/verify.cmake b/Tests/CudaOnly/DontResolveDeviceSymbols/verify.cmake
new file mode 100644
index 0000000..9bb426d
--- /dev/null
+++ b/Tests/CudaOnly/DontResolveDeviceSymbols/verify.cmake
@@ -0,0 +1,14 @@
+execute_process(COMMAND ${DUMP_COMMAND} ${DUMP_ARGS} ${TEST_LIBRARY_PATH}
+ RESULT_VARIABLE RESULT
+ OUTPUT_VARIABLE OUTPUT
+ ERROR_VARIABLE ERROR
+)
+
+if(NOT "${RESULT}" STREQUAL "0")
+ message(FATAL_ERROR "${DUMP_COMMAND} failed [${RESULT}] [${OUTPUT}] [${ERROR}]")
+endif()
+
+if("${OUTPUT}" MATCHES "${SYMBOL_NAME}")
+ message(FATAL_ERROR
+ "The '${SYMBOL_NAME}' symbol is defined; device linking occurred!")
+endif()
diff --git a/Tests/CudaOnly/EnableStandard/CMakeLists.txt b/Tests/CudaOnly/EnableStandard/CMakeLists.txt
new file mode 100644
index 0000000..dfcb8da
--- /dev/null
+++ b/Tests/CudaOnly/EnableStandard/CMakeLists.txt
@@ -0,0 +1,27 @@
+
+cmake_minimum_required(VERSION 3.7)
+project (EnableStandard CUDA)
+
+#Goal for this example:
+#build cuda sources that require C++11 to be enabled.
+
+add_library(CUDAStatic11 STATIC static.cu)
+add_library(CUDADynamic11 SHARED shared.cu)
+
+add_executable(CudaOnlyEnableStandard main.cu)
+target_link_libraries(CudaOnlyEnableStandard PRIVATE CUDAStatic11 CUDADynamic11)
+
+target_compile_features(CUDADynamic11 PRIVATE cuda_std_11)
+set_target_properties(CUDAStatic11 PROPERTIES CUDA_STANDARD 11)
+set_target_properties(CUDAStatic11 PROPERTIES CUDA_STANDARD_REQUIRED TRUE)
+
+#Verify CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES
+foreach(dir ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
+ if(NOT IS_DIRECTORY "${dir}")
+ message(FATAL_ERROR
+ "CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES entry\n"
+ " ${dir}\n"
+ "is not an existing directory."
+ )
+ endif()
+endforeach()
diff --git a/Tests/CudaOnly/EnableStandard/main.cu b/Tests/CudaOnly/EnableStandard/main.cu
new file mode 100644
index 0000000..740c832
--- /dev/null
+++ b/Tests/CudaOnly/EnableStandard/main.cu
@@ -0,0 +1,23 @@
+
+#include <iostream>
+
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+#else
+# define IMPORT
+#endif
+
+int static_cuda11_func(int);
+IMPORT int shared_cuda11_func(int);
+
+void test_functions()
+{
+ static_cuda11_func(int(42));
+ shared_cuda11_func(int(42));
+}
+
+int main(int argc, char** argv)
+{
+ test_functions();
+ return 0;
+}
diff --git a/Tests/CudaOnly/EnableStandard/shared.cu b/Tests/CudaOnly/EnableStandard/shared.cu
new file mode 100644
index 0000000..004cb83
--- /dev/null
+++ b/Tests/CudaOnly/EnableStandard/shared.cu
@@ -0,0 +1,15 @@
+
+#include <type_traits>
+
+#ifdef _WIN32
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+using tt = std::true_type;
+using ft = std::false_type;
+EXPORT int __host__ shared_cuda11_func(int x)
+{
+ return x * x + std::integral_constant<int, 17>::value;
+}
diff --git a/Tests/CudaOnly/EnableStandard/static.cu b/Tests/CudaOnly/EnableStandard/static.cu
new file mode 100644
index 0000000..73e43a8
--- /dev/null
+++ b/Tests/CudaOnly/EnableStandard/static.cu
@@ -0,0 +1,9 @@
+
+#include <type_traits>
+
+using tt = std::true_type;
+using ft = std::false_type;
+int __host__ static_cuda11_func(int x)
+{
+ return x * x + std::integral_constant<int, 17>::value;
+}
diff --git a/Tests/CudaOnly/ExportPTX/CMakeLists.txt b/Tests/CudaOnly/ExportPTX/CMakeLists.txt
new file mode 100644
index 0000000..e7e7bc4
--- /dev/null
+++ b/Tests/CudaOnly/ExportPTX/CMakeLists.txt
@@ -0,0 +1,84 @@
+cmake_minimum_required(VERSION 3.19)
+project (ExportPTX CUDA)
+
+#Goal for this example:
+# How to generate PTX files instead of OBJECT files
+# How to reference PTX files for custom commands
+# How to install PTX files
+
+# PTX can be compiled only for a single virtual architecture at a time
+list(SUBLIST CMAKE_CUDA_ARCHITECTURES 0 1 CMAKE_CUDA_ARCHITECTURES)
+string(APPEND CMAKE_CUDA_ARCHITECTURES "-virtual")
+
+add_library(CudaPTX OBJECT kernelA.cu kernelB.cu)
+set_property(TARGET CudaPTX PROPERTY CUDA_PTX_COMPILATION ON)
+
+#Test ObjectFiles with file(GENERATE)
+file(GENERATE
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/gen_$<LOWER_CASE:$<CONFIG>/>path_to_objs.h
+ CONTENT [[
+
+#include <vector>
+#include <string>
+
+#ifndef path_to_objs
+#define path_to_objs
+
+static std::string ptx_paths = "$<TARGET_OBJECTS:CudaPTX>";
+
+#endif
+
+]]
+)
+#We are going to need a wrapper around bin2c for multiple reasons
+# 1. bin2c only converts a single file at a time
+# 2. bin2c has only standard out support, so we have to manually
+# redirect to a cmake buffer
+# 3. We want to pack everything into a single output file, so we
+# need to also pass the --name option
+set(output_file ${CMAKE_CURRENT_BINARY_DIR}/embedded_objs.h)
+
+find_package(CUDAToolkit REQUIRED)
+find_program(bin_to_c
+ NAMES bin2c
+ PATHS ${CUDAToolkit_BIN_DIR}
+ )
+if(NOT bin_to_c)
+ message(FATAL_ERROR
+ "bin2c not found:\n"
+ " CUDAToolkit_BIN_DIR='${CUDAToolkit_BIN_DIR}'\n"
+ )
+endif()
+
+add_custom_command(
+ OUTPUT "${output_file}"
+ COMMAND ${CMAKE_COMMAND}
+ "-DBIN_TO_C_COMMAND=${bin_to_c}"
+ "-DOBJECTS=$<TARGET_OBJECTS:CudaPTX>"
+ "-DOUTPUT=${output_file}"
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/bin2c_wrapper.cmake
+ VERBATIM
+ DEPENDS $<TARGET_OBJECTS:CudaPTX>
+ COMMENT "Converting Object files to a C header"
+ )
+
+add_executable(CudaOnlyExportPTX main.cu ${output_file})
+add_dependencies(CudaOnlyExportPTX CudaPTX)
+target_include_directories(CudaOnlyExportPTX PRIVATE
+ ${CMAKE_CURRENT_BINARY_DIR} )
+target_compile_definitions(CudaOnlyExportPTX PRIVATE
+ "CONFIG_TYPE=gen_$<LOWER_CASE:$<CONFIG>>")
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET CudaOnlyExportPTX PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
+
+#Verify that we can install object targets properly
+install(TARGETS CudaPTX CudaOnlyExportPTX
+ EXPORT cudaPTX
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ OBJECTS DESTINATION objs
+ )
+install(EXPORT cudaPTX DESTINATION lib/cudaPTX)
diff --git a/Tests/CudaOnly/ExportPTX/bin2c_wrapper.cmake b/Tests/CudaOnly/ExportPTX/bin2c_wrapper.cmake
new file mode 100644
index 0000000..0baf934
--- /dev/null
+++ b/Tests/CudaOnly/ExportPTX/bin2c_wrapper.cmake
@@ -0,0 +1,19 @@
+
+set(file_contents)
+foreach(obj ${OBJECTS})
+ get_filename_component(obj_ext ${obj} EXT)
+ get_filename_component(obj_name ${obj} NAME_WE)
+ get_filename_component(obj_dir ${obj} DIRECTORY)
+
+ if(obj_ext MATCHES ".ptx")
+ set(args --name ${obj_name} ${obj})
+ execute_process(COMMAND "${BIN_TO_C_COMMAND}" ${args}
+ WORKING_DIRECTORY ${obj_dir}
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE error_var
+ )
+ set(file_contents "${file_contents} \n${output}")
+ endif()
+endforeach()
+file(WRITE "${OUTPUT}" "${file_contents}")
diff --git a/Tests/CudaOnly/ExportPTX/kernelA.cu b/Tests/CudaOnly/ExportPTX/kernelA.cu
new file mode 100644
index 0000000..fbe0d26
--- /dev/null
+++ b/Tests/CudaOnly/ExportPTX/kernelA.cu
@@ -0,0 +1,7 @@
+
+__global__ void kernelA(float* r, float* x, float* y, float* z, int size)
+{
+ for (int i = threadIdx.x; i < size; i += blockDim.x) {
+ r[i] = x[i] * y[i] + z[i];
+ }
+}
diff --git a/Tests/CudaOnly/ExportPTX/kernelB.cu b/Tests/CudaOnly/ExportPTX/kernelB.cu
new file mode 100644
index 0000000..11872e4
--- /dev/null
+++ b/Tests/CudaOnly/ExportPTX/kernelB.cu
@@ -0,0 +1,8 @@
+
+
+__global__ void kernelB(float* r, float* x, float* y, float* z, int size)
+{
+ for (int i = threadIdx.x; i < size; i += blockDim.x) {
+ r[i] = x[i] * y[i] + z[i];
+ }
+}
diff --git a/Tests/CudaOnly/ExportPTX/main.cu b/Tests/CudaOnly/ExportPTX/main.cu
new file mode 100644
index 0000000..132377c
--- /dev/null
+++ b/Tests/CudaOnly/ExportPTX/main.cu
@@ -0,0 +1,28 @@
+
+#include <iostream>
+
+/*
+ Define GENERATED_HEADER macro to allow c++ files to include headers
+ generated based on different configuration types.
+*/
+
+/* clang-format off */
+#define GENERATED_HEADER(x) GENERATED_HEADER0(CONFIG_TYPE/x)
+/* clang-format on */
+#define GENERATED_HEADER0(x) GENERATED_HEADER1(x)
+#define GENERATED_HEADER1(x) <x>
+
+#include GENERATED_HEADER(path_to_objs.h)
+
+#include "embedded_objs.h"
+
+int main(int argc, char** argv)
+{
+ (void)argc;
+ (void)argv;
+
+ unsigned char* ka = kernelA;
+ unsigned char* kb = kernelB;
+
+ return (ka != NULL && kb != NULL) ? 0 : 1;
+}
diff --git a/Tests/CudaOnly/GPUDebugFlag/CMakeLists.txt b/Tests/CudaOnly/GPUDebugFlag/CMakeLists.txt
new file mode 100644
index 0000000..e9c0c1b
--- /dev/null
+++ b/Tests/CudaOnly/GPUDebugFlag/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.18)
+project(GPUDebugFlag CUDA)
+
+set(CMAKE_CUDA_STANDARD 11)
+
+# Goal for this example:
+# Verify that enabling device debug works.
+string(APPEND CMAKE_CUDA_FLAGS " -G")
+
+add_executable(CudaOnlyGPUDebugFlag main.cu)
+
+#CUDA's __CUDACC_DEBUG__ define was added in NVCC 9.0
+#so if we are below 9.0.0 we will manually add the define so that the test
+#passes
+if(CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 9.0.0)
+ target_compile_definitions(CudaOnlyGPUDebugFlag PRIVATE "__CUDACC_DEBUG__")
+endif()
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET CudaOnlyGPUDebugFlag PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/CudaOnly/GPUDebugFlag/main.cu b/Tests/CudaOnly/GPUDebugFlag/main.cu
new file mode 100644
index 0000000..ced3789
--- /dev/null
+++ b/Tests/CudaOnly/GPUDebugFlag/main.cu
@@ -0,0 +1,72 @@
+#include <iostream>
+
+#include <cuda.h>
+#include <cuda_runtime.h>
+
+static __global__ void debug_kernel(bool* has_debug)
+{
+// Verify using the return code if we have GPU debug flag enabled
+#if defined(__CUDACC__) && defined(__CUDACC_DEBUG__)
+ *has_debug = true;
+#else
+ *has_debug = false;
+#endif
+}
+
+int choose_cuda_device()
+{
+ int nDevices = 0;
+ cudaError_t err = cudaGetDeviceCount(&nDevices);
+ if (err != cudaSuccess) {
+ std::cerr << "Failed to retrieve the number of CUDA enabled devices"
+ << std::endl;
+ return 1;
+ }
+ for (int i = 0; i < nDevices; ++i) {
+ cudaDeviceProp prop;
+ cudaError_t err = cudaGetDeviceProperties(&prop, i);
+ if (err != cudaSuccess) {
+ std::cerr << "Could not retrieve properties from CUDA device " << i
+ << std::endl;
+ return 1;
+ }
+ if (prop.major >= 3) {
+ err = cudaSetDevice(i);
+ if (err != cudaSuccess) {
+ std::cout << "Could not select CUDA device " << i << std::endl;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ std::cout << "Could not find a CUDA enabled card supporting compute >=3.0"
+ << std::endl;
+
+ return 1;
+}
+
+int main(int argc, char** argv)
+{
+ bool* has_debug;
+ cudaError_t err = cudaMallocManaged(&has_debug, sizeof(bool));
+ if (err != cudaSuccess) {
+ std::cerr << "cudaMallocManaged failed:\n"
+ << " " << cudaGetErrorString(err) << std::endl;
+ return 1;
+ }
+
+ debug_kernel<<<1, 1>>>(has_debug);
+ err = cudaDeviceSynchronize();
+ if (err != cudaSuccess) {
+ std::cerr << "debug_kernel: kernel launch shouldn't have failed\n"
+ << "reason:\t" << cudaGetErrorString(err) << std::endl;
+ return 1;
+ }
+ if (*has_debug == false) {
+ std::cerr << "debug_kernel: kernel not compiled with device debug"
+ << std::endl;
+ return 1;
+ }
+ return 0;
+}
diff --git a/Tests/CudaOnly/PDB/CMakeLists.txt b/Tests/CudaOnly/PDB/CMakeLists.txt
new file mode 100644
index 0000000..6ecf989
--- /dev/null
+++ b/Tests/CudaOnly/PDB/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.11)
+project (PDB CUDA)
+
+add_executable(CudaOnlyPDB main.cu)
+set_target_properties(CudaOnlyPDB PROPERTIES
+ PDB_NAME LinkPDBName
+ PDB_OUTPUT_DIRECTORY LinkPDBDir
+ COMPILE_PDB_NAME CompPDBName
+ COMPILE_PDB_OUTPUT_DIRECTORY CompPDBDir
+ )
+
+set(pdbs
+ ${CMAKE_CURRENT_BINARY_DIR}/CompPDBDir/${CMAKE_CFG_INTDIR}/CompPDBName.pdb
+ ${CMAKE_CURRENT_BINARY_DIR}/LinkPDBDir/${CMAKE_CFG_INTDIR}/LinkPDBName.pdb
+ )
+add_custom_command(TARGET CudaOnlyPDB POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -Dconfig=$<CONFIG> "-Dpdbs=${pdbs}"
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/check_pdbs.cmake
+ )
diff --git a/Tests/CudaOnly/PDB/check_pdbs.cmake b/Tests/CudaOnly/PDB/check_pdbs.cmake
new file mode 100644
index 0000000..5e01ca7
--- /dev/null
+++ b/Tests/CudaOnly/PDB/check_pdbs.cmake
@@ -0,0 +1,10 @@
+if(NOT "${config}" MATCHES "[Dd][Ee][Bb]")
+ return()
+endif()
+foreach(pdb ${pdbs})
+ if(EXISTS "${pdb}")
+ message(STATUS "PDB Exists: ${pdb}")
+ else()
+ message(SEND_ERROR "PDB MISSING:\n ${pdb}")
+ endif()
+endforeach()
diff --git a/Tests/CudaOnly/PDB/main.cu b/Tests/CudaOnly/PDB/main.cu
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/CudaOnly/PDB/main.cu
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CudaOnly/ResolveDeviceSymbols/CMakeLists.txt b/Tests/CudaOnly/ResolveDeviceSymbols/CMakeLists.txt
new file mode 100644
index 0000000..a44b2f2
--- /dev/null
+++ b/Tests/CudaOnly/ResolveDeviceSymbols/CMakeLists.txt
@@ -0,0 +1,62 @@
+cmake_minimum_required(VERSION 3.18)
+project (ResolveDeviceSymbols CUDA)
+
+# Find nm and dumpbin
+if(CMAKE_NM)
+ set(dump_command ${CMAKE_NM})
+ set(dump_args -g)
+else()
+ include(GetPrerequisites)
+ message(STATUS "calling list_prerequisites to find dumpbin")
+ list_prerequisites("${CMAKE_COMMAND}" 0 0 0)
+ if(gp_dumpbin)
+ set(dump_command ${gp_dumpbin})
+ set(dump_args /ARCHIVEMEMBERS)
+ endif()
+endif()
+
+#Goal for this example:
+# 1. Build two static libraries that defines multiple methods and kernels
+# 2. Resolve the device symbols into the second static library, therefore
+# confirming that the first static library is on the device link line
+# 3. Verify that we can't use those device symbols from anything that links
+# to the static library
+add_library(CUDAResolveDeviceDepsA STATIC file1.cu)
+add_library(CUDAResolveDeviceDepsB STATIC file2.cu)
+target_compile_features(CUDAResolveDeviceDepsA PUBLIC cuda_std_11)
+target_compile_features(CUDAResolveDeviceDepsB PUBLIC cuda_std_11)
+set_target_properties(CUDAResolveDeviceDepsA CUDAResolveDeviceDepsB
+ PROPERTIES
+ CUDA_SEPARABLE_COMPILATION ON
+ POSITION_INDEPENDENT_CODE ON)
+
+add_library(CUDAResolveDeviceLib STATIC file2_launch.cu)
+set_target_properties(CUDAResolveDeviceLib
+ PROPERTIES
+ CUDA_SEPARABLE_COMPILATION ON
+ CUDA_RESOLVE_DEVICE_SYMBOLS ON
+ POSITION_INDEPENDENT_CODE ON)
+target_link_libraries(CUDAResolveDeviceLib PRIVATE CUDAResolveDeviceDepsA CUDAResolveDeviceDepsB)
+
+if(dump_command)
+add_custom_command(TARGET CUDAResolveDeviceLib POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ -DDUMP_COMMAND=${dump_command}
+ -DDUMP_ARGS=${dump_args}
+ -DTEST_LIBRARY_PATH=$<TARGET_FILE:CUDAResolveDeviceLib>
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/verify.cmake
+ )
+endif()
+
+add_executable(CudaOnlyResolveDeviceSymbols main.cu)
+set_target_properties(CudaOnlyResolveDeviceSymbols
+ PROPERTIES
+ CUDA_SEPARABLE_COMPILATION OFF
+ CUDA_RESOLVE_DEVICE_SYMBOLS OFF)
+
+target_link_libraries(CudaOnlyResolveDeviceSymbols PRIVATE CUDAResolveDeviceLib)
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET CudaOnlyResolveDeviceSymbols PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/CudaOnly/ResolveDeviceSymbols/file1.cu b/Tests/CudaOnly/ResolveDeviceSymbols/file1.cu
new file mode 100644
index 0000000..1ce63bf
--- /dev/null
+++ b/Tests/CudaOnly/ResolveDeviceSymbols/file1.cu
@@ -0,0 +1,10 @@
+
+#include "file1.h"
+
+result_type __device__ file1_func(int x)
+{
+ result_type r;
+ r.input = x;
+ r.sum = x * x;
+ return r;
+}
diff --git a/Tests/CudaOnly/ResolveDeviceSymbols/file1.h b/Tests/CudaOnly/ResolveDeviceSymbols/file1.h
new file mode 100644
index 0000000..b33bcae
--- /dev/null
+++ b/Tests/CudaOnly/ResolveDeviceSymbols/file1.h
@@ -0,0 +1,10 @@
+
+#pragma once
+
+struct result_type
+{
+ int input;
+ int sum;
+};
+
+result_type __device__ file1_func(int x);
diff --git a/Tests/CudaOnly/ResolveDeviceSymbols/file2.cu b/Tests/CudaOnly/ResolveDeviceSymbols/file2.cu
new file mode 100644
index 0000000..0e5e7aa
--- /dev/null
+++ b/Tests/CudaOnly/ResolveDeviceSymbols/file2.cu
@@ -0,0 +1,9 @@
+
+#include "file2.h"
+
+result_type_dynamic __device__ file2_func(int x)
+{
+ const result_type r = file1_func(x);
+ const result_type_dynamic rd{ r.input, r.sum, true };
+ return rd;
+}
diff --git a/Tests/CudaOnly/ResolveDeviceSymbols/file2.h b/Tests/CudaOnly/ResolveDeviceSymbols/file2.h
new file mode 100644
index 0000000..c6e2875
--- /dev/null
+++ b/Tests/CudaOnly/ResolveDeviceSymbols/file2.h
@@ -0,0 +1,12 @@
+
+#pragma once
+#include "file1.h"
+
+struct result_type_dynamic
+{
+ int input;
+ int sum;
+ bool from_static;
+};
+
+result_type_dynamic __device__ file2_func(int x);
diff --git a/Tests/CudaOnly/ResolveDeviceSymbols/file2_launch.cu b/Tests/CudaOnly/ResolveDeviceSymbols/file2_launch.cu
new file mode 100644
index 0000000..4e8da13
--- /dev/null
+++ b/Tests/CudaOnly/ResolveDeviceSymbols/file2_launch.cu
@@ -0,0 +1,18 @@
+
+#include "file2.h"
+
+static __global__ void file2_kernel(result_type_dynamic& r, int x)
+{
+ // call static_func which is a method that is defined in the
+ // static library that is always out of date
+ r = file2_func(x);
+}
+
+static __global__ void file2_kernel(result_type_dynamic& r, int x);
+
+int file2_launch_kernel(int x)
+{
+ result_type_dynamic r;
+ file2_kernel<<<1, 1>>>(r, x);
+ return r.sum;
+}
diff --git a/Tests/CudaOnly/ResolveDeviceSymbols/main.cu b/Tests/CudaOnly/ResolveDeviceSymbols/main.cu
new file mode 100644
index 0000000..ea842cc
--- /dev/null
+++ b/Tests/CudaOnly/ResolveDeviceSymbols/main.cu
@@ -0,0 +1,58 @@
+
+#include <iostream>
+
+#include "file2.h"
+
+int file2_launch_kernel(int x);
+
+int choose_cuda_device()
+{
+ int nDevices = 0;
+ cudaError_t err = cudaGetDeviceCount(&nDevices);
+ if (err != cudaSuccess) {
+ std::cerr << "Failed to retrieve the number of CUDA enabled devices"
+ << std::endl;
+ return 1;
+ }
+ for (int i = 0; i < nDevices; ++i) {
+ cudaDeviceProp prop;
+ cudaError_t err = cudaGetDeviceProperties(&prop, i);
+ if (err != cudaSuccess) {
+ std::cerr << "Could not retrieve properties from CUDA device " << i
+ << std::endl;
+ return 1;
+ }
+ std::cout << "prop.major: " << prop.major << std::endl;
+ if (prop.major >= 3) {
+ err = cudaSetDevice(i);
+ if (err != cudaSuccess) {
+ std::cout << "Could not select CUDA device " << i << std::endl;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ std::cout << "Could not find a CUDA enabled card supporting compute >=3.0"
+ << std::endl;
+
+ return 1;
+}
+
+int main(int argc, char** argv)
+{
+ int ret = choose_cuda_device();
+ if (ret) {
+ return 0;
+ }
+
+ file2_launch_kernel(1);
+ cudaError_t err = cudaGetLastError();
+ if (err != cudaSuccess) {
+ std::cerr << "file2_launch_kernel: kernel launch should have passed"
+ << std::endl;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/Tests/CudaOnly/ResolveDeviceSymbols/verify.cmake b/Tests/CudaOnly/ResolveDeviceSymbols/verify.cmake
new file mode 100644
index 0000000..94d388b
--- /dev/null
+++ b/Tests/CudaOnly/ResolveDeviceSymbols/verify.cmake
@@ -0,0 +1,14 @@
+execute_process(COMMAND ${DUMP_COMMAND} ${DUMP_ARGS} ${TEST_LIBRARY_PATH}
+ RESULT_VARIABLE RESULT
+ OUTPUT_VARIABLE OUTPUT
+ ERROR_VARIABLE ERROR
+)
+
+if(NOT "${RESULT}" STREQUAL "0")
+ message(FATAL_ERROR "${DUMP_COMMAND} failed [${RESULT}] [${OUTPUT}] [${ERROR}]")
+endif()
+
+if(NOT "${OUTPUT}" MATCHES "(cmake_device_link|device-link)")
+ message(FATAL_ERROR
+ "No cuda device objects found, device linking did not occur")
+endif()
diff --git a/Tests/CudaOnly/RuntimeControls/CMakeLists.txt b/Tests/CudaOnly/RuntimeControls/CMakeLists.txt
new file mode 100644
index 0000000..b3b2210
--- /dev/null
+++ b/Tests/CudaOnly/RuntimeControls/CMakeLists.txt
@@ -0,0 +1,58 @@
+cmake_minimum_required(VERSION 3.18)
+project (RuntimeControls CUDA)
+
+# Find nm and dumpbin
+if(CMAKE_NM)
+ set(dump_command ${CMAKE_NM})
+ set(dump_args -g)
+else()
+ include(GetPrerequisites)
+ message(STATUS "calling list_prerequisites to find dumpbin")
+ list_prerequisites("${CMAKE_COMMAND}" 0 0 0)
+ if(gp_dumpbin)
+ set(dump_command ${gp_dumpbin})
+ set(dump_args /ARCHIVEMEMBERS)
+ endif()
+endif()
+
+set(CMAKE_CUDA_STANDARD 11)
+set(CMAKE_CUDA_RUNTIME_LIBRARY static)
+
+if(NOT "x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC")
+ add_library(UsesNoCudaRT SHARED file1.cu)
+ set_target_properties(UsesNoCudaRT PROPERTIES CUDA_RUNTIME_LIBRARY none)
+endif()
+
+add_library(UsesStaticCudaRT SHARED file2.cu)
+
+add_executable(CudaOnlyRuntimeControls main.cu)
+set_target_properties(CudaOnlyRuntimeControls PROPERTIES CUDA_RUNTIME_LIBRARY shared)
+
+target_link_libraries(CudaOnlyRuntimeControls PRIVATE $<TARGET_NAME_IF_EXISTS:UsesNoCudaRT> UsesStaticCudaRT)
+
+
+if(dump_command)
+ if(TARGET UsesNoCudaRT)
+ add_custom_command(TARGET UsesNoCudaRT POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ -DDUMP_COMMAND=${dump_command}
+ -DDUMP_ARGS=${dump_args}
+ -DTEST_LIBRARY_PATH=$<TARGET_FILE:UsesNoCudaRT>
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/no_runtime.cmake
+ )
+ endif()
+ add_custom_command(TARGET UsesStaticCudaRT POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ -DDUMP_COMMAND=${dump_command}
+ -DDUMP_ARGS=${dump_args}
+ -DTEST_LIBRARY_PATH=$<TARGET_FILE:UsesStaticCudaRT>
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/uses_static_runtime.cmake
+ )
+ string(REPLACE ";" "|" dirs "${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES}")
+ add_custom_command(TARGET CudaOnlyRuntimeControls POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ -DEXEC_PATH=$<TARGET_FILE:CudaOnlyRuntimeControls>
+ -DEXTRA_LIB_DIRS="${dirs}"
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/verify_runtime.cmake
+ )
+endif()
diff --git a/Tests/CudaOnly/RuntimeControls/file1.cu b/Tests/CudaOnly/RuntimeControls/file1.cu
new file mode 100644
index 0000000..28beb5e
--- /dev/null
+++ b/Tests/CudaOnly/RuntimeControls/file1.cu
@@ -0,0 +1,18 @@
+
+#ifdef _WIN32
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+void __global__ file1_kernel(int x, int& r)
+{
+ r = -x;
+}
+
+EXPORT int file1_launch_kernel(int x)
+{
+ int r = 0;
+ file1_kernel<<<1, 1>>>(x, r);
+ return r;
+}
diff --git a/Tests/CudaOnly/RuntimeControls/file2.cu b/Tests/CudaOnly/RuntimeControls/file2.cu
new file mode 100644
index 0000000..ff68a70
--- /dev/null
+++ b/Tests/CudaOnly/RuntimeControls/file2.cu
@@ -0,0 +1,18 @@
+
+#ifdef _WIN32
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+void __global__ file2_kernel(int x, int& r)
+{
+ r = -x;
+}
+
+EXPORT int file2_launch_kernel(int x)
+{
+ int r = 0;
+ file2_kernel<<<1, 1>>>(x, r);
+ return r;
+}
diff --git a/Tests/CudaOnly/RuntimeControls/main.cu b/Tests/CudaOnly/RuntimeControls/main.cu
new file mode 100644
index 0000000..0be22af
--- /dev/null
+++ b/Tests/CudaOnly/RuntimeControls/main.cu
@@ -0,0 +1,81 @@
+
+#include <iostream>
+
+#include "cuda.h"
+
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+#else
+# define IMPORT
+#endif
+
+#ifndef _WIN32
+IMPORT int file1_launch_kernel(int x);
+#endif
+
+IMPORT int file2_launch_kernel(int x);
+
+int choose_cuda_device()
+{
+ int nDevices = 0;
+ cudaError_t err = cudaGetDeviceCount(&nDevices);
+ if (err != cudaSuccess) {
+ std::cerr << "Failed to retrieve the number of CUDA enabled devices"
+ << std::endl;
+ return 1;
+ }
+ for (int i = 0; i < nDevices; ++i) {
+ cudaDeviceProp prop;
+ cudaError_t err = cudaGetDeviceProperties(&prop, i);
+ if (err != cudaSuccess) {
+ std::cerr << "Could not retrieve properties from CUDA device " << i
+ << std::endl;
+ return 1;
+ }
+ std::cout << "prop.major: " << prop.major << std::endl;
+ if (prop.major >= 3) {
+ err = cudaSetDevice(i);
+ if (err != cudaSuccess) {
+ std::cout << "Could not select CUDA device " << i << std::endl;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ std::cout << "Could not find a CUDA enabled card supporting compute >=3.0"
+ << std::endl;
+
+ return 1;
+}
+
+int main(int argc, char** argv)
+{
+ int ret = choose_cuda_device();
+ if (ret) {
+ return 0;
+ }
+
+ cudaError_t err;
+#ifndef _WIN32
+ file1_launch_kernel(1);
+ err = cudaGetLastError();
+ if (err != cudaSuccess) {
+ std::cerr << "file1_launch_kernel: kernel launch should have passed.\n "
+ "Error message: "
+ << cudaGetErrorString(err) << std::endl;
+ return 1;
+ }
+#endif
+
+ file2_launch_kernel(1);
+ err = cudaGetLastError();
+ if (err != cudaSuccess) {
+ std::cerr << "file2_launch_kernel: kernel launch should have passed.\n "
+ "Error message: "
+ << cudaGetErrorString(err) << std::endl;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/Tests/CudaOnly/RuntimeControls/no_runtime.cmake b/Tests/CudaOnly/RuntimeControls/no_runtime.cmake
new file mode 100644
index 0000000..55f28cc
--- /dev/null
+++ b/Tests/CudaOnly/RuntimeControls/no_runtime.cmake
@@ -0,0 +1,14 @@
+execute_process(COMMAND ${DUMP_COMMAND} ${DUMP_ARGS} ${TEST_LIBRARY_PATH}
+ RESULT_VARIABLE RESULT
+ OUTPUT_VARIABLE OUTPUT
+ ERROR_VARIABLE ERROR
+)
+
+if(NOT "${RESULT}" STREQUAL "0")
+ message(FATAL_ERROR "${DUMP_COMMAND} failed [${RESULT}] [${OUTPUT}] [${ERROR}]")
+endif()
+
+if(NOT "${OUTPUT}" MATCHES "(__cuda)")
+ message(FATAL_ERROR
+ "not missing cuda device symbols, static runtime linking was used.")
+endif()
diff --git a/Tests/CudaOnly/RuntimeControls/uses_static_runtime.cmake b/Tests/CudaOnly/RuntimeControls/uses_static_runtime.cmake
new file mode 100644
index 0000000..b372fea
--- /dev/null
+++ b/Tests/CudaOnly/RuntimeControls/uses_static_runtime.cmake
@@ -0,0 +1,14 @@
+execute_process(COMMAND ${DUMP_COMMAND} ${DUMP_ARGS} ${TEST_LIBRARY_PATH}
+ RESULT_VARIABLE RESULT
+ OUTPUT_VARIABLE OUTPUT
+ ERROR_VARIABLE ERROR
+)
+
+if(NOT "${RESULT}" STREQUAL "0")
+ message(FATAL_ERROR "${DUMP_COMMAND} failed [${RESULT}] [${OUTPUT}] [${ERROR}]")
+endif()
+
+if("${OUTPUT}" MATCHES "__cuda")
+ message(FATAL_ERROR
+ "missing cuda device symbols, static runtime linking was not used.")
+endif()
diff --git a/Tests/CudaOnly/RuntimeControls/verify_runtime.cmake b/Tests/CudaOnly/RuntimeControls/verify_runtime.cmake
new file mode 100644
index 0000000..b313dac
--- /dev/null
+++ b/Tests/CudaOnly/RuntimeControls/verify_runtime.cmake
@@ -0,0 +1,16 @@
+
+string(REPLACE "|" ";" dirs "${EXTRA_LIB_DIRS}")
+file(GET_RUNTIME_DEPENDENCIES
+ RESOLVED_DEPENDENCIES_VAR resolved_libs
+ UNRESOLVED_DEPENDENCIES_VAR unresolved_libs
+ DIRECTORIES ${dirs}
+ EXECUTABLES ${EXEC_PATH}
+ )
+
+list(FILTER resolved_libs INCLUDE REGEX ".*cudart.*")
+list(LENGTH resolved_libs has_cudart)
+
+if(has_cudart EQUAL 0)
+ message(FATAL_ERROR
+ "missing cudart shared library from runtime dependency output.")
+endif()
diff --git a/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt b/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt
new file mode 100644
index 0000000..864ecbf
--- /dev/null
+++ b/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt
@@ -0,0 +1,59 @@
+cmake_minimum_required(VERSION 3.18)
+project(SeparateCompilation CUDA)
+
+#Goal for this example:
+#Build a static library that defines multiple methods and kernels that
+#use each other.
+#After that confirm that we can call those methods from dynamic libraries
+#and executables.
+#We complicate the matter by also testing that multiple static libraries
+#all containing cuda separable compilation code links properly
+set(CMAKE_CUDA_SEPARABLE_COMPILATION ON)
+add_library(CUDASeparateLibA STATIC file1.cu file2.cu file3.cu)
+target_compile_features(CUDASeparateLibA PRIVATE cuda_std_11)
+get_property(sep_comp TARGET CUDASeparateLibA PROPERTY CUDA_SEPARABLE_COMPILATION)
+if(NOT sep_comp)
+ message(FATAL_ERROR "CUDA_SEPARABLE_COMPILATION not initialized")
+endif()
+unset(CMAKE_CUDA_SEPARABLE_COMPILATION)
+
+if(CMAKE_CUDA_SIMULATE_ID STREQUAL "MSVC")
+ # Test adding a flag that is not in our CUDA flag table for VS.
+ if(NOT CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 8)
+ string(APPEND CMAKE_CUDA_FLAGS " --ftemplate-depth 50")
+ endif()
+ # Test adding a flag that nvcc should pass to the host compiler.
+ target_compile_options(CUDASeparateLibA PRIVATE -Xcompiler=-bigobj)
+endif()
+
+#Having file4/file5 in a shared library causes serious problems
+#with the nvcc linker and it will generate bad entries that will
+#cause a segv when trying to run the executable
+#
+add_library(CUDASeparateLibB STATIC file4.cu file5.cu)
+target_compile_features(CUDASeparateLibB PRIVATE cuda_std_11)
+target_link_libraries(CUDASeparateLibB PRIVATE CUDASeparateLibA)
+
+add_executable(CudaOnlySeparateCompilation main.cu)
+target_link_libraries(CudaOnlySeparateCompilation
+ PRIVATE CUDASeparateLibB)
+set_target_properties(CudaOnlySeparateCompilation PROPERTIES CUDA_STANDARD 11)
+set_target_properties(CudaOnlySeparateCompilation PROPERTIES CUDA_STANDARD_REQUIRED TRUE)
+
+set_target_properties(CUDASeparateLibA
+ CUDASeparateLibB
+ PROPERTIES CUDA_SEPARABLE_COMPILATION ON
+ POSITION_INDEPENDENT_CODE ON)
+
+if (CMAKE_GENERATOR MATCHES "^Visual Studio")
+ #Visual Studio CUDA integration will not perform device linking
+ #on a target that itself does not have GenerateRelocatableDeviceCode
+ #enabled.
+ set_target_properties(CudaOnlySeparateCompilation
+ PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
+endif()
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET CudaOnlySeparateCompilation PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/CudaOnly/SeparateCompilation/file1.cu b/Tests/CudaOnly/SeparateCompilation/file1.cu
new file mode 100644
index 0000000..1ce63bf
--- /dev/null
+++ b/Tests/CudaOnly/SeparateCompilation/file1.cu
@@ -0,0 +1,10 @@
+
+#include "file1.h"
+
+result_type __device__ file1_func(int x)
+{
+ result_type r;
+ r.input = x;
+ r.sum = x * x;
+ return r;
+}
diff --git a/Tests/CudaOnly/SeparateCompilation/file1.h b/Tests/CudaOnly/SeparateCompilation/file1.h
new file mode 100644
index 0000000..ff1945c
--- /dev/null
+++ b/Tests/CudaOnly/SeparateCompilation/file1.h
@@ -0,0 +1,7 @@
+
+#pragma once
+struct result_type
+{
+ int input;
+ int sum;
+};
diff --git a/Tests/CudaOnly/SeparateCompilation/file2.cu b/Tests/CudaOnly/SeparateCompilation/file2.cu
new file mode 100644
index 0000000..74f3558
--- /dev/null
+++ b/Tests/CudaOnly/SeparateCompilation/file2.cu
@@ -0,0 +1,16 @@
+
+#include "file2.h"
+
+result_type __device__ file1_func(int x);
+
+result_type_dynamic __device__ file2_func(int x)
+{
+ if (x != 42) {
+ const result_type r = file1_func(x);
+ const result_type_dynamic rd{ r.input, r.sum, true };
+ return rd;
+ } else {
+ const result_type_dynamic rd{ x, x * x * x, false };
+ return rd;
+ }
+}
diff --git a/Tests/CudaOnly/SeparateCompilation/file2.h b/Tests/CudaOnly/SeparateCompilation/file2.h
new file mode 100644
index 0000000..d2dbaa4
--- /dev/null
+++ b/Tests/CudaOnly/SeparateCompilation/file2.h
@@ -0,0 +1,10 @@
+
+#pragma once
+#include "file1.h"
+
+struct result_type_dynamic
+{
+ int input;
+ int sum;
+ bool from_static;
+};
diff --git a/Tests/CudaOnly/SeparateCompilation/file3.cu b/Tests/CudaOnly/SeparateCompilation/file3.cu
new file mode 100644
index 0000000..155b513
--- /dev/null
+++ b/Tests/CudaOnly/SeparateCompilation/file3.cu
@@ -0,0 +1,22 @@
+
+
+#include "file1.h"
+#include "file2.h"
+
+result_type __device__ file1_func(int x);
+result_type_dynamic __device__ file2_func(int x);
+
+static __global__ void file3_kernel(result_type& r, int x)
+{
+ // call static_func which is a method that is defined in the
+ // static library that is always out of date
+ r = file1_func(x);
+ result_type_dynamic rd = file2_func(x);
+}
+
+result_type file3_launch_kernel(int x)
+{
+ result_type r;
+ file3_kernel<<<1, 1>>>(r, x);
+ return r;
+}
diff --git a/Tests/CudaOnly/SeparateCompilation/file4.cu b/Tests/CudaOnly/SeparateCompilation/file4.cu
new file mode 100644
index 0000000..2e3e01e
--- /dev/null
+++ b/Tests/CudaOnly/SeparateCompilation/file4.cu
@@ -0,0 +1,23 @@
+
+#include <iostream>
+
+#include "file1.h"
+#include "file2.h"
+
+result_type __device__ file1_func(int x);
+result_type_dynamic __device__ file2_func(int x);
+
+static __global__ void file4_kernel(result_type& r, int x)
+{
+ // call static_func which is a method that is defined in the
+ // static library that is always out of date
+ r = file1_func(x);
+ result_type_dynamic rd = file2_func(x);
+}
+
+int file4_launch_kernel(int x)
+{
+ result_type r;
+ file4_kernel<<<1, 1>>>(r, x);
+ return r.sum;
+}
diff --git a/Tests/CudaOnly/SeparateCompilation/file5.cu b/Tests/CudaOnly/SeparateCompilation/file5.cu
new file mode 100644
index 0000000..fee8e9e
--- /dev/null
+++ b/Tests/CudaOnly/SeparateCompilation/file5.cu
@@ -0,0 +1,23 @@
+
+#include <iostream>
+
+#include "file1.h"
+#include "file2.h"
+
+result_type __device__ file1_func(int x);
+result_type_dynamic __device__ file2_func(int x);
+
+static __global__ void file5_kernel(result_type& r, int x)
+{
+ // call static_func which is a method that is defined in the
+ // static library that is always out of date
+ r = file1_func(x);
+ result_type_dynamic rd = file2_func(x);
+}
+
+int file5_launch_kernel(int x)
+{
+ result_type r;
+ file5_kernel<<<1, 1>>>(r, x);
+ return r.sum;
+}
diff --git a/Tests/CudaOnly/SeparateCompilation/main.cu b/Tests/CudaOnly/SeparateCompilation/main.cu
new file mode 100644
index 0000000..40dbe5d
--- /dev/null
+++ b/Tests/CudaOnly/SeparateCompilation/main.cu
@@ -0,0 +1,68 @@
+
+#include <iostream>
+
+#include "file1.h"
+#include "file2.h"
+
+int file4_launch_kernel(int x);
+int file5_launch_kernel(int x);
+
+int choose_cuda_device()
+{
+ int nDevices = 0;
+ cudaError_t err = cudaGetDeviceCount(&nDevices);
+ if (err != cudaSuccess) {
+ std::cerr << "Failed to retrieve the number of CUDA enabled devices"
+ << std::endl;
+ return 1;
+ }
+ for (int i = 0; i < nDevices; ++i) {
+ cudaDeviceProp prop;
+ cudaError_t err = cudaGetDeviceProperties(&prop, i);
+ if (err != cudaSuccess) {
+ std::cerr << "Could not retrieve properties from CUDA device " << i
+ << std::endl;
+ return 1;
+ }
+ if (prop.major >= 3) {
+ err = cudaSetDevice(i);
+ if (err != cudaSuccess) {
+ std::cout << "Could not select CUDA device " << i << std::endl;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ std::cout << "Could not find a CUDA enabled card supporting compute >=3.0"
+ << std::endl;
+
+ return 1;
+}
+
+int main(int argc, char** argv)
+{
+ int ret = choose_cuda_device();
+ if (ret) {
+ return 0;
+ }
+
+ cudaError_t err;
+ file4_launch_kernel(42);
+ err = cudaGetLastError();
+ if (err != cudaSuccess) {
+ std::cerr << "file4_launch_kernel: kernel launch failed: "
+ << cudaGetErrorString(err) << std::endl;
+ return 1;
+ }
+
+ file5_launch_kernel(42);
+ err = cudaGetLastError();
+ if (err != cudaSuccess) {
+ std::cerr << "file5_launch_kernel: kernel launch failed: "
+ << cudaGetErrorString(err) << std::endl;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt b/Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt
new file mode 100644
index 0000000..03fba22
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt
@@ -0,0 +1,42 @@
+cmake_minimum_required(VERSION 3.15)
+project(SharedRuntimePlusToolkit CUDA)
+
+#Goal for this example:
+# Validate that with c++ we can use some components of the CUDA toolkit, and
+# specify the cuda runtime
+find_package(CUDAToolkit REQUIRED)
+
+add_library(Common OBJECT curand.cu nppif.cu)
+target_link_libraries(Common PRIVATE CUDA::toolkit)
+set_target_properties(Common PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+#shared runtime with shared toolkit libraries
+add_library(SharedToolkit SHARED shared.cu)
+target_link_libraries(SharedToolkit PRIVATE Common PUBLIC CUDA::curand CUDA::nppif)
+set_target_properties(SharedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY none)
+target_link_libraries(SharedToolkit PUBLIC CUDA::cudart)
+
+# The CUDA only ships the shared version of the toolkit libraries
+# on windows
+if(NOT WIN32)
+ #shared runtime with static toolkit libraries
+ add_library(StaticToolkit SHARED static.cu)
+ target_link_libraries(StaticToolkit PRIVATE Common CUDA::curand_static CUDA::nppif_static)
+ set_target_properties(StaticToolkit PROPERTIES CUDA_RUNTIME_LIBRARY Shared)
+
+ #static runtime with mixed toolkit libraries
+ add_library(MixedToolkit SHARED mixed.cu)
+ target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand_static CUDA::nppif)
+ set_target_properties(MixedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY Shared)
+endif()
+
+add_executable(CudaOnlySharedRuntimePlusToolkit main.cu)
+target_link_libraries(CudaOnlySharedRuntimePlusToolkit PRIVATE SharedToolkit
+ $<TARGET_NAME_IF_EXISTS:StaticToolkit>
+ $<TARGET_NAME_IF_EXISTS:MixedToolkit>)
+
+if(UNIX)
+ # Help the shared cuda runtime find libcudart as it is not located
+ # in a default system searched location
+ set_property(TARGET CudaOnlySharedRuntimePlusToolkit PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/CudaOnly/SharedRuntimePlusToolkit/curand.cu b/Tests/CudaOnly/SharedRuntimePlusToolkit/curand.cu
new file mode 100644
index 0000000..fdd7b53
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/curand.cu
@@ -0,0 +1,65 @@
+// Comes from:
+// https://docs.nvidia.com/cuda/curand/host-api-overview.html#host-api-example
+
+#ifdef _WIN32
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+/*
+ * This program uses the host CURAND API to generate 100
+ * pseudorandom floats.
+ */
+#include <cuda.h>
+#include <curand.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define CUDA_CALL(x) \
+ do { \
+ if ((x) != cudaSuccess) { \
+ printf("Error at %s:%d\n", __FILE__, __LINE__); \
+ return EXIT_FAILURE; \
+ } \
+ } while (0)
+#define CURAND_CALL(x) \
+ do { \
+ if ((x) != CURAND_STATUS_SUCCESS) { \
+ printf("Error at %s:%d\n", __FILE__, __LINE__); \
+ return EXIT_FAILURE; \
+ } \
+ } while (0)
+
+EXPORT int curand_main()
+{
+ size_t n = 100;
+ size_t i;
+ curandGenerator_t gen;
+ float *devData, *hostData;
+
+ /* Allocate n floats on host */
+ hostData = (float*)calloc(n, sizeof(float));
+
+ /* Allocate n floats on device */
+ CUDA_CALL(cudaMalloc((void**)&devData, n * sizeof(float)));
+
+ /* Create pseudo-random number generator */
+ CURAND_CALL(curandCreateGenerator(&gen, CURAND_RNG_PSEUDO_DEFAULT));
+
+ /* Set seed */
+ CURAND_CALL(curandSetPseudoRandomGeneratorSeed(gen, 1234ULL));
+
+ /* Generate n floats on device */
+ CURAND_CALL(curandGenerateUniform(gen, devData, n));
+
+ /* Copy device memory to host */
+ CUDA_CALL(
+ cudaMemcpy(hostData, devData, n * sizeof(float), cudaMemcpyDeviceToHost));
+
+ /* Cleanup */
+ CURAND_CALL(curandDestroyGenerator(gen));
+ CUDA_CALL(cudaFree(devData));
+ free(hostData);
+ return EXIT_SUCCESS;
+}
diff --git a/Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu b/Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu
new file mode 100644
index 0000000..2a4da22
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu
@@ -0,0 +1,23 @@
+
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+IMPORT int shared_version();
+int static_version()
+{
+ return 0;
+}
+int mixed_version()
+{
+ return 0;
+}
+#else
+int shared_version();
+int static_version();
+int mixed_version();
+#endif
+
+int main()
+{
+ return mixed_version() == 0 && shared_version() == 0 &&
+ static_version() == 0;
+}
diff --git a/Tests/CudaOnly/SharedRuntimePlusToolkit/mixed.cu b/Tests/CudaOnly/SharedRuntimePlusToolkit/mixed.cu
new file mode 100644
index 0000000..6de6886
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/mixed.cu
@@ -0,0 +1,16 @@
+
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+# define EXPORT __declspec(dllexport)
+#else
+# define IMPORT
+# define EXPORT
+#endif
+
+IMPORT int curand_main();
+IMPORT int nppif_main();
+
+EXPORT int mixed_version()
+{
+ return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/CudaOnly/SharedRuntimePlusToolkit/nppif.cu b/Tests/CudaOnly/SharedRuntimePlusToolkit/nppif.cu
new file mode 100644
index 0000000..ac5341c
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/nppif.cu
@@ -0,0 +1,92 @@
+// Comes from
+// https://devtalk.nvidia.com/default/topic/1037482/gpu-accelerated-libraries/help-me-help-you-with-modern-cmake-and-cuda-mwe-for-npp/post/5271066/#5271066
+
+#ifdef _WIN32
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+#include <cstdio>
+#include <iostream>
+
+#include <assert.h>
+#include <cuda_runtime_api.h>
+#include <nppi_filtering_functions.h>
+
+EXPORT int nppif_main()
+{
+ /**
+ * 8-bit unsigned single-channel 1D row convolution.
+ */
+ const int simgrows = 32;
+ const int simgcols = 32;
+ Npp8u *d_pSrc, *d_pDst;
+ const int nMaskSize = 3;
+ NppiSize oROI;
+ oROI.width = simgcols - nMaskSize;
+ oROI.height = simgrows;
+ const int simgsize = simgrows * simgcols * sizeof(d_pSrc[0]);
+ const int dimgsize = oROI.width * oROI.height * sizeof(d_pSrc[0]);
+ const int simgpix = simgrows * simgcols;
+ const int dimgpix = oROI.width * oROI.height;
+ const int nSrcStep = simgcols * sizeof(d_pSrc[0]);
+ const int nDstStep = oROI.width * sizeof(d_pDst[0]);
+ const int pixval = 1;
+ const int nDivisor = 1;
+ const Npp32s h_pKernel[nMaskSize] = { pixval, pixval, pixval };
+ Npp32s* d_pKernel;
+ const Npp32s nAnchor = 2;
+ cudaError_t err = cudaMalloc((void**)&d_pSrc, simgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMalloc((void**)&d_pDst, dimgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMalloc((void**)&d_pKernel, nMaskSize * sizeof(d_pKernel[0]));
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ // set image to pixval initially
+ err = cudaMemset(d_pSrc, pixval, simgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMemset(d_pDst, 0, dimgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMemcpy(d_pKernel, h_pKernel, nMaskSize * sizeof(d_pKernel[0]),
+ cudaMemcpyHostToDevice);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ // copy src to dst
+ NppStatus ret =
+ nppiFilterRow_8u_C1R(d_pSrc, nSrcStep, d_pDst, nDstStep, oROI, d_pKernel,
+ nMaskSize, nAnchor, nDivisor);
+ assert(ret == NPP_NO_ERROR);
+ Npp8u* h_imgres = new Npp8u[dimgpix];
+ err = cudaMemcpy(h_imgres, d_pDst, dimgsize, cudaMemcpyDeviceToHost);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ // test for filtering
+ for (int i = 0; i < dimgpix; i++) {
+ if (h_imgres[i] != (pixval * pixval * nMaskSize)) {
+ fprintf(stderr, "h_imgres at index %d failed to match\n", i);
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/Tests/CudaOnly/SharedRuntimePlusToolkit/shared.cu b/Tests/CudaOnly/SharedRuntimePlusToolkit/shared.cu
new file mode 100644
index 0000000..f3c3dbc
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/shared.cu
@@ -0,0 +1,16 @@
+
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+# define EXPORT __declspec(dllexport)
+#else
+# define IMPORT
+# define EXPORT
+#endif
+
+int curand_main();
+int nppif_main();
+
+EXPORT int shared_version()
+{
+ return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/CudaOnly/SharedRuntimePlusToolkit/static.cu b/Tests/CudaOnly/SharedRuntimePlusToolkit/static.cu
new file mode 100644
index 0000000..6932fa3
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/static.cu
@@ -0,0 +1,16 @@
+
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+# define EXPORT __declspec(dllexport)
+#else
+# define IMPORT
+# define EXPORT
+#endif
+
+IMPORT int curand_main();
+IMPORT int nppif_main();
+
+EXPORT int static_version()
+{
+ return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/CudaOnly/SharedRuntimeViaCUDAFlags/CMakeLists.txt b/Tests/CudaOnly/SharedRuntimeViaCUDAFlags/CMakeLists.txt
new file mode 100644
index 0000000..24ff478
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimeViaCUDAFlags/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.17)
+project(SharedRuntimeViaCUDAFlags NONE)
+
+set(CMAKE_CUDA_FLAGS "")
+string(APPEND CMAKE_CUDA_FLAGS "-cudart shared")
+
+enable_language(CUDA)
+
+add_executable(CudaOnlySharedRuntimeViaCUDAFlags main.cu)
+
+if(UNIX)
+ # Help the shared cuda runtime find libcudart as it is not located
+ # in a default system searched location
+ set_property(TARGET CudaOnlySharedRuntimeViaCUDAFlags PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/CudaOnly/SharedRuntimeViaCUDAFlags/main.cu b/Tests/CudaOnly/SharedRuntimeViaCUDAFlags/main.cu
new file mode 100644
index 0000000..766b775
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimeViaCUDAFlags/main.cu
@@ -0,0 +1,5 @@
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CudaOnly/Standard98/CMakeLists.txt b/Tests/CudaOnly/Standard98/CMakeLists.txt
new file mode 100644
index 0000000..6823352
--- /dev/null
+++ b/Tests/CudaOnly/Standard98/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.18)
+project(CudaOnlyStandard98 CUDA)
+
+# Support setting CUDA Standard to 98 which internally gets transformed to
+# CUDA03
+set(CMAKE_CUDA_STANDARD 98)
+
+add_executable(CudaOnlyStandard98 main.cu)
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET CudaOnlyStandard98 PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/CudaOnly/Standard98/main.cu b/Tests/CudaOnly/Standard98/main.cu
new file mode 100644
index 0000000..c79afd6
--- /dev/null
+++ b/Tests/CudaOnly/Standard98/main.cu
@@ -0,0 +1,8 @@
+
+#if __cplusplus >= 201103L
+# error "invalid standard value"
+#endif
+int main(int argc, char** argv)
+{
+ return 0;
+}
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt b/Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt
new file mode 100644
index 0000000..534bab2
--- /dev/null
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt
@@ -0,0 +1,35 @@
+cmake_minimum_required(VERSION 3.18)
+project(StaticRuntimePlusToolkit CUDA)
+
+#Goal for this example:
+# Validate that with cuda we can use some components of the CUDA toolkit, and
+# specify the cuda runtime
+find_package(CUDAToolkit REQUIRED)
+
+add_library(Common OBJECT curand.cu nppif.cu)
+target_link_libraries(Common PRIVATE CUDA::toolkit)
+set_target_properties(Common PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+#static runtime with shared toolkit libraries
+add_library(SharedToolkit SHARED shared.cu)
+target_link_libraries(SharedToolkit PRIVATE Common CUDA::curand CUDA::nppif )
+set_target_properties(SharedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY none)
+target_link_libraries(SharedToolkit PUBLIC CUDA::cudart_static)
+
+#static runtime with static toolkit libraries
+add_library(StaticToolkit SHARED static.cu)
+target_link_libraries(StaticToolkit PRIVATE Common CUDA::curand_static CUDA::nppif_static)
+
+#static runtime with mixed toolkit libraries
+add_library(MixedToolkit SHARED mixed.cu)
+target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand CUDA::nppif_static)
+set_target_properties(MixedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY Static)
+
+add_executable(CudaOnlyStaticRuntimePlusToolkit main.cu)
+target_link_libraries(CudaOnlyStaticRuntimePlusToolkit PRIVATE SharedToolkit StaticToolkit MixedToolkit)
+
+if(UNIX)
+ # Help the shared cuda runtime find libcurand and libnppif when they are not located
+ # in a default system searched location
+ set_property(TARGET CudaOnlyStaticRuntimePlusToolkit PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu
new file mode 100644
index 0000000..95872f0
--- /dev/null
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu
@@ -0,0 +1,59 @@
+// Comes from:
+// https://docs.nvidia.com/cuda/curand/host-api-overview.html#host-api-example
+
+/*
+ * This program uses the host CURAND API to generate 100
+ * pseudorandom floats.
+ */
+#include <cuda.h>
+#include <curand.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define CUDA_CALL(x) \
+ do { \
+ if ((x) != cudaSuccess) { \
+ printf("Error at %s:%d\n", __FILE__, __LINE__); \
+ return EXIT_FAILURE; \
+ } \
+ } while (0)
+#define CURAND_CALL(x) \
+ do { \
+ if ((x) != CURAND_STATUS_SUCCESS) { \
+ printf("Error at %s:%d\n", __FILE__, __LINE__); \
+ return EXIT_FAILURE; \
+ } \
+ } while (0)
+
+int curand_main()
+{
+ size_t n = 100;
+ size_t i;
+ curandGenerator_t gen;
+ float *devData, *hostData;
+
+ /* Allocate n floats on host */
+ hostData = (float*)calloc(n, sizeof(float));
+
+ /* Allocate n floats on device */
+ CUDA_CALL(cudaMalloc((void**)&devData, n * sizeof(float)));
+
+ /* Create pseudo-random number generator */
+ CURAND_CALL(curandCreateGenerator(&gen, CURAND_RNG_PSEUDO_DEFAULT));
+
+ /* Set seed */
+ CURAND_CALL(curandSetPseudoRandomGeneratorSeed(gen, 1234ULL));
+
+ /* Generate n floats on device */
+ CURAND_CALL(curandGenerateUniform(gen, devData, n));
+
+ /* Copy device memory to host */
+ CUDA_CALL(
+ cudaMemcpy(hostData, devData, n * sizeof(float), cudaMemcpyDeviceToHost));
+
+ /* Cleanup */
+ CURAND_CALL(curandDestroyGenerator(gen));
+ CUDA_CALL(cudaFree(devData));
+ free(hostData);
+ return EXIT_SUCCESS;
+}
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu
new file mode 100644
index 0000000..5a09f8e
--- /dev/null
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu
@@ -0,0 +1,11 @@
+
+
+int shared_version();
+int static_version();
+int mixed_version();
+
+int main()
+{
+ return mixed_version() == 0 && shared_version() == 0 &&
+ static_version() == 0;
+}
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu
new file mode 100644
index 0000000..a05140d
--- /dev/null
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu
@@ -0,0 +1,8 @@
+
+int curand_main();
+int nppif_main();
+
+int mixed_version()
+{
+ return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu
new file mode 100644
index 0000000..2871090
--- /dev/null
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu
@@ -0,0 +1,86 @@
+// Comes from
+// https://devtalk.nvidia.com/default/topic/1037482/gpu-accelerated-libraries/help-me-help-you-with-modern-cmake-and-cuda-mwe-for-npp/post/5271066/#5271066
+
+#include <cstdio>
+#include <iostream>
+
+#include <assert.h>
+#include <cuda_runtime_api.h>
+#include <nppi_filtering_functions.h>
+
+int nppif_main()
+{
+ /**
+ * 8-bit unsigned single-channel 1D row convolution.
+ */
+ const int simgrows = 32;
+ const int simgcols = 32;
+ Npp8u *d_pSrc, *d_pDst;
+ const int nMaskSize = 3;
+ NppiSize oROI;
+ oROI.width = simgcols - nMaskSize;
+ oROI.height = simgrows;
+ const int simgsize = simgrows * simgcols * sizeof(d_pSrc[0]);
+ const int dimgsize = oROI.width * oROI.height * sizeof(d_pSrc[0]);
+ const int simgpix = simgrows * simgcols;
+ const int dimgpix = oROI.width * oROI.height;
+ const int nSrcStep = simgcols * sizeof(d_pSrc[0]);
+ const int nDstStep = oROI.width * sizeof(d_pDst[0]);
+ const int pixval = 1;
+ const int nDivisor = 1;
+ const Npp32s h_pKernel[nMaskSize] = { pixval, pixval, pixval };
+ Npp32s* d_pKernel;
+ const Npp32s nAnchor = 2;
+ cudaError_t err = cudaMalloc((void**)&d_pSrc, simgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMalloc((void**)&d_pDst, dimgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMalloc((void**)&d_pKernel, nMaskSize * sizeof(d_pKernel[0]));
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ // set image to pixval initially
+ err = cudaMemset(d_pSrc, pixval, simgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMemset(d_pDst, 0, dimgsize);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ err = cudaMemcpy(d_pKernel, h_pKernel, nMaskSize * sizeof(d_pKernel[0]),
+ cudaMemcpyHostToDevice);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ // copy src to dst
+ NppStatus ret =
+ nppiFilterRow_8u_C1R(d_pSrc, nSrcStep, d_pDst, nDstStep, oROI, d_pKernel,
+ nMaskSize, nAnchor, nDivisor);
+ assert(ret == NPP_NO_ERROR);
+ Npp8u* h_imgres = new Npp8u[dimgpix];
+ err = cudaMemcpy(h_imgres, d_pDst, dimgsize, cudaMemcpyDeviceToHost);
+ if (err != cudaSuccess) {
+ fprintf(stderr, "Cuda error %d\n", __LINE__);
+ return 1;
+ }
+ // test for filtering
+ for (int i = 0; i < dimgpix; i++) {
+ if (h_imgres[i] != (pixval * pixval * nMaskSize)) {
+ fprintf(stderr, "h_imgres at index %d failed to match\n", i);
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu
new file mode 100644
index 0000000..9967b66
--- /dev/null
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu
@@ -0,0 +1,8 @@
+
+int curand_main();
+int nppif_main();
+
+int shared_version()
+{
+ return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu
new file mode 100644
index 0000000..ca7eb4c
--- /dev/null
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu
@@ -0,0 +1,8 @@
+
+int curand_main();
+int nppif_main();
+
+int static_version()
+{
+ return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/CudaOnly/Toolkit/CMakeLists.txt b/Tests/CudaOnly/Toolkit/CMakeLists.txt
new file mode 100644
index 0000000..1486c1a
--- /dev/null
+++ b/Tests/CudaOnly/Toolkit/CMakeLists.txt
@@ -0,0 +1,61 @@
+cmake_minimum_required(VERSION 3.15)
+project(CudaOnlyToolkit CUDA)
+find_package(CUDAToolkit REQUIRED)
+
+if(NOT DEFINED CUDAToolkit_VERSION)
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDAToolkit_VERSION not found")
+endif()
+
+message(STATUS "CUDAToolkit_VERSION: ${CUDAToolkit_VERSION}")
+message(STATUS "CUDAToolkit_VERSION_MAJOR: ${CUDAToolkit_VERSION_MAJOR}")
+message(STATUS "CUDAToolkit_VERSION_MINOR: ${CUDAToolkit_VERSION_MINOR}")
+message(STATUS "CUDAToolkit_VERSION_PATCH: ${CUDAToolkit_VERSION_PATCH}")
+message(STATUS "CUDAToolkit_BIN_DIR: ${CUDAToolkit_BIN_DIR}")
+message(STATUS "CUDAToolkit_INCLUDE_DIRS: ${CUDAToolkit_INCLUDE_DIRS}")
+message(STATUS "CUDAToolkit_LIBRARY_DIR: ${CUDAToolkit_LIBRARY_DIR}")
+message(STATUS "CUDAToolkit_NVCC_EXECUTABLE ${CUDAToolkit_NVCC_EXECUTABLE}")
+
+
+set(cuda_libs cudart cuda_driver cublas cufft cufftw curand cusolver cusparse)
+if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 10.1)
+ list(APPEND cuda_libs cublasLt)
+endif()
+if(CUDAToolkit_VERSION_MAJOR VERSION_LESS 11)
+ list(APPEND cuda_libs nvgraph)
+endif()
+
+# Verify that all the CUDA:: targets and variables exist
+foreach (cuda_lib IN LISTS cuda_libs)
+ if(NOT CUDA_${cuda_lib}_LIBRARY)
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
+ endif()
+ if(NOT TARGET CUDA::${cuda_lib})
+ message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
+ endif()
+endforeach()
+
+set(npp_libs nppc nppial nppicc nppidei nppif nppig nppim nppist nppitc npps nppisu)
+if(CUDAToolkit_VERSION_MAJOR VERSION_LESS 11)
+ list(APPEND npp_libs nppicom)
+endif()
+foreach (cuda_lib )
+ if(NOT CUDA_${cuda_lib}_LIBRARY)
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
+ endif()
+ if(NOT TARGET CUDA::${cuda_lib})
+ message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
+ endif()
+endforeach()
+
+foreach (cuda_lib nvrtc nvToolsExt OpenCL)
+ if(NOT CUDA_${cuda_lib}_LIBRARY)
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
+ endif()
+
+ if(NOT TARGET CUDA::${cuda_lib})
+ message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
+ endif()
+endforeach()
+
+add_executable(CudaOnlyToolkit main.cu)
+target_link_libraries(CudaOnlyToolkit PRIVATE CUDA::toolkit)
diff --git a/Tests/CudaOnly/Toolkit/main.cu b/Tests/CudaOnly/Toolkit/main.cu
new file mode 100644
index 0000000..0f3ccdc
--- /dev/null
+++ b/Tests/CudaOnly/Toolkit/main.cu
@@ -0,0 +1,8 @@
+// Only thing we care about is that these headers are found
+#include <cuda.h>
+#include <cuda_runtime_api.h>
+
+int main(int argc, char** argv)
+{
+ return 0;
+}
diff --git a/Tests/CudaOnly/ToolkitBeforeLang/CMakeLists.txt b/Tests/CudaOnly/ToolkitBeforeLang/CMakeLists.txt
new file mode 100644
index 0000000..8dff6cc
--- /dev/null
+++ b/Tests/CudaOnly/ToolkitBeforeLang/CMakeLists.txt
@@ -0,0 +1,26 @@
+cmake_minimum_required(VERSION 3.15)
+project(CudaOnlyToolkitBeforeLang CXX)
+
+# Validate that CUDAToolkit gets the correct version
+# when called before CUDA the language is enabled
+find_package(CUDAToolkit REQUIRED)
+enable_language(CUDA)
+
+if(NOT DEFINED CUDAToolkit_VERSION)
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDAToolkit_VERSION not found")
+endif()
+
+set(cuda_libs cudart cuda_driver)
+
+# Verify that all the CUDA:: targets and variables exist
+foreach (cuda_lib IN LISTS cuda_libs)
+ if(NOT CUDA_${cuda_lib}_LIBRARY)
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
+ endif()
+ if(NOT TARGET CUDA::${cuda_lib})
+ message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
+ endif()
+endforeach()
+
+add_executable(CudaOnlyToolkitBeforeLang main.cu)
+target_link_libraries(CudaOnlyToolkitBeforeLang PRIVATE CUDA::toolkit)
diff --git a/Tests/CudaOnly/ToolkitBeforeLang/main.cu b/Tests/CudaOnly/ToolkitBeforeLang/main.cu
new file mode 100644
index 0000000..0f3ccdc
--- /dev/null
+++ b/Tests/CudaOnly/ToolkitBeforeLang/main.cu
@@ -0,0 +1,8 @@
+// Only thing we care about is that these headers are found
+#include <cuda.h>
+#include <cuda_runtime_api.h>
+
+int main(int argc, char** argv)
+{
+ return 0;
+}
diff --git a/Tests/CudaOnly/WithDefs/CMakeLists.txt b/Tests/CudaOnly/WithDefs/CMakeLists.txt
new file mode 100644
index 0000000..02f043f
--- /dev/null
+++ b/Tests/CudaOnly/WithDefs/CMakeLists.txt
@@ -0,0 +1,38 @@
+cmake_minimum_required(VERSION 3.18)
+project(WithDefs CUDA)
+
+set(release_compile_defs DEFREL)
+
+#Goal for this example:
+#build a executable that needs to be passed a complex define through add_defintions
+#this verifies we can pass things such as '_','(' to nvcc
+add_definitions("-DPACKED_DEFINE=__attribute__((packed))")
+
+add_executable(CudaOnlyWithDefs main.notcu)
+set_source_files_properties(main.notcu PROPERTIES LANGUAGE CUDA)
+
+target_compile_options(CudaOnlyWithDefs
+ PRIVATE
+ -DFLAG_COMPILE_LANG_$<COMPILE_LANGUAGE>
+ -DFLAG_LANG_IS_CUDA=$<COMPILE_LANGUAGE:CUDA>
+ $<$<CUDA_COMPILER_ID:NVIDIA>:--compiler-options=-DHOST_DEFINE> # Host-only defines are possible only on NVCC.
+ )
+
+target_compile_definitions(CudaOnlyWithDefs
+ PRIVATE
+ $<$<CONFIG:RELEASE>:$<BUILD_INTERFACE:${release_compile_defs}>>
+ -DDEF_COMPILE_LANG_$<COMPILE_LANGUAGE>
+ -DDEF_LANG_IS_CUDA=$<COMPILE_LANGUAGE:CUDA>
+ -DDEF_CUDA_COMPILER=$<CUDA_COMPILER_ID>
+ -DDEF_CUDA_COMPILER_VERSION=$<CUDA_COMPILER_VERSION>
+ )
+
+target_include_directories(CudaOnlyWithDefs
+ PRIVATE
+ $<$<COMPILE_LANGUAGE:CUDA>:${CMAKE_CURRENT_SOURCE_DIR}/inc_cuda>
+)
+
+if(APPLE)
+ # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+ set_property(TARGET CudaOnlyWithDefs PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/CudaOnly/WithDefs/inc_cuda/inc_cuda.h b/Tests/CudaOnly/WithDefs/inc_cuda/inc_cuda.h
new file mode 100644
index 0000000..e228b58
--- /dev/null
+++ b/Tests/CudaOnly/WithDefs/inc_cuda/inc_cuda.h
@@ -0,0 +1 @@
+#define INC_CUDA
diff --git a/Tests/CudaOnly/WithDefs/main.notcu b/Tests/CudaOnly/WithDefs/main.notcu
new file mode 100644
index 0000000..9119eba
--- /dev/null
+++ b/Tests/CudaOnly/WithDefs/main.notcu
@@ -0,0 +1,96 @@
+#include <iostream>
+
+#include <cuda.h>
+#include <cuda_runtime.h>
+#include <inc_cuda.h>
+#ifndef INC_CUDA
+# error "INC_CUDA not defined!"
+#endif
+
+#ifdef __NVCC__
+# ifndef HOST_DEFINE
+# error "HOST_DEFINE not defined!"
+# endif
+#endif
+
+#ifndef PACKED_DEFINE
+# error "PACKED_DEFINE not defined!"
+#endif
+
+#ifndef FLAG_COMPILE_LANG_CUDA
+# error "FLAG_COMPILE_LANG_CUDA not defined!"
+#endif
+
+#ifndef FLAG_LANG_IS_CUDA
+# error "FLAG_LANG_IS_CUDA not defined!"
+#endif
+
+#if !FLAG_LANG_IS_CUDA
+# error "Expected FLAG_LANG_IS_CUDA"
+#endif
+
+#ifndef DEF_COMPILE_LANG_CUDA
+# error "DEF_COMPILE_LANG_CUDA not defined!"
+#endif
+
+#ifndef DEF_LANG_IS_CUDA
+# error "DEF_LANG_IS_CUDA not defined!"
+#endif
+
+#if !DEF_LANG_IS_CUDA
+# error "Expected DEF_LANG_IS_CUDA"
+#endif
+
+#ifndef DEF_CUDA_COMPILER
+# error "DEF_CUDA_COMPILER not defined!"
+#endif
+
+#ifndef DEF_CUDA_COMPILER_VERSION
+# error "DEF_CUDA_COMPILER_VERSION not defined!"
+#endif
+
+static __global__ void DetermineIfValidCudaDevice()
+{
+}
+
+#ifdef _MSC_VER
+# pragma pack(push, 1)
+# undef PACKED_DEFINE
+# define PACKED_DEFINE
+#endif
+struct PACKED_DEFINE result_type
+{
+ bool valid;
+ int value;
+#if defined(NDEBUG) && !defined(DEFREL)
+# error missing DEFREL flag
+#endif
+};
+#ifdef _MSC_VER
+# pragma pack(pop)
+#endif
+
+result_type can_launch_kernel()
+{
+ result_type r;
+ DetermineIfValidCudaDevice<<<1, 1>>>();
+ r.valid = (cudaSuccess == cudaGetLastError());
+ if (r.valid) {
+ r.value = 1;
+ } else {
+ r.value = -1;
+ }
+ return r;
+}
+
+int main(int argc, char** argv)
+{
+ cudaError_t err;
+ int nDevices = 0;
+ err = cudaGetDeviceCount(&nDevices);
+ if (err != cudaSuccess) {
+ std::cerr << cudaGetErrorString(err) << std::endl;
+ return 1;
+ }
+ return 0;
+}
diff --git a/Tests/CustComDepend/CMakeLists.txt b/Tests/CustComDepend/CMakeLists.txt
new file mode 100644
index 0000000..777cdcc
--- /dev/null
+++ b/Tests/CustComDepend/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required (VERSION 2.6)
+project(CustComDepend)
+include_directories("${CustComDepend_SOURCE_DIR}")
+add_definitions(-D_CRT_SECURE_NO_DEPRECATE=1)
+set(EXECUTABLE_OUTPUT_PATH ${CustComDepend_BINARY_DIR}/bin)
+add_executable(foo foo.cxx)
+add_custom_command(
+ OUTPUT ${CustComDepend_BINARY_DIR}/bar.c
+ COMMAND $<TARGET_FILE:foo>
+ ${CustComDepend_BINARY_DIR}/bar.c
+ DEPENDS $<TARGET_FILE:foo>
+)
+
+add_library(bar SHARED ${CustComDepend_BINARY_DIR}/bar.c)
diff --git a/Tests/CustComDepend/bar.h b/Tests/CustComDepend/bar.h
new file mode 100644
index 0000000..b0a690b
--- /dev/null
+++ b/Tests/CustComDepend/bar.h
@@ -0,0 +1,9 @@
+#ifdef _WIN32
+# ifdef bar_EXPORTS
+# define BAR_EXPORT __declspec(dllexport)
+# else
+# define BAR_EXPORT __declspec(dllimport)
+# endif
+#else
+# define BAR_EXPORT
+#endif
diff --git a/Tests/CustComDepend/foo.cxx b/Tests/CustComDepend/foo.cxx
new file mode 100644
index 0000000..2705b66
--- /dev/null
+++ b/Tests/CustComDepend/foo.cxx
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+int main(int ac, char** av)
+{
+ FILE* fout = fopen(av[1], "w");
+ printf("create %s\n", av[1]);
+ if (!fout) {
+ return -1;
+ }
+ fprintf(fout, "#include <bar.h>\nBAR_EXPORT int bar(){ return 10;}\n");
+ fclose(fout);
+ return 0;
+}
diff --git a/Tests/CustomCommand/CMakeLists.txt b/Tests/CustomCommand/CMakeLists.txt
new file mode 100644
index 0000000..11d005f
--- /dev/null
+++ b/Tests/CustomCommand/CMakeLists.txt
@@ -0,0 +1,588 @@
+#
+# Wrapping
+#
+cmake_minimum_required (VERSION 2.8.12)
+project (CustomCommand)
+
+add_subdirectory(GeneratedHeader)
+
+#
+# Lib and exe path
+#
+if(NOT DEFINED bin_dir)
+ set(bin_dir "bin")
+endif()
+
+set (LIBRARY_OUTPUT_PATH
+ ${PROJECT_BINARY_DIR}/${bin_dir} CACHE INTERNAL
+ "Single output directory for building all libraries.")
+
+set (EXECUTABLE_OUTPUT_PATH
+ ${PROJECT_BINARY_DIR}/${bin_dir} CACHE INTERNAL
+ "Single output directory for building all executables.")
+
+################################################################
+#
+# First test using a compiled generator to create a .c file
+#
+################################################################
+# add the executable that will generate the file
+add_executable(generator generator.cxx)
+
+################################################################
+#
+# Test using a wrapper to wrap a header file
+#
+################################################################
+# add the executable that will generate the file
+add_executable(wrapper wrapper.cxx)
+
+add_custom_command(
+ OUTPUT ${PROJECT_BINARY_DIR}/wrapped.c ${PROJECT_BINARY_DIR}/wrapped_help.c
+ DEPENDS wrapper
+ MAIN_DEPENDENCY ${PROJECT_SOURCE_DIR}/wrapped.h
+ COMMAND ${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/wrapper
+ ${PROJECT_BINARY_DIR}/wrapped.c ${PROJECT_BINARY_DIR}/wrapped_help.c
+ ${CMAKE_CFG_INTDIR} # this argument tests passing of the configuration
+ VERBATIM # passing of configuration should work in this mode
+ )
+
+################################################################
+#
+# Test creating files from a custom target
+#
+################################################################
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}//doc1.dvi # test 2 slashes
+ DEPENDS ${PROJECT_SOURCE_DIR}/doc1.tex
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${PROJECT_SOURCE_DIR}/doc1.tex
+ ${PROJECT_BINARY_DIR}/doc1.dvi
+ )
+
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc1.h
+ COMMAND ${CMAKE_COMMAND} -E echo " Copying doc1.dvi to doc1temp.h."
+ COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/doc1.dvi
+ ${PROJECT_BINARY_DIR}/doc1temp.h
+ )
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc1.h APPEND
+ DEPENDS ${PROJECT_BINARY_DIR}/doc1.dvi
+ COMMAND ${CMAKE_COMMAND} -E echo " Copying doc1temp.h to doc1.h."
+ COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/doc1temp.h
+ ${PROJECT_BINARY_DIR}/doc1.h
+ COMMAND ${CMAKE_COMMAND} -E echo " Removing doc1temp.h."
+ COMMAND ${CMAKE_COMMAND} -E rm -f ${PROJECT_BINARY_DIR}/doc1temp.h
+ )
+
+# Add custom command to generate foo.h.
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/foo.h
+ DEPENDS ${PROJECT_SOURCE_DIR}/foo.h.in
+ COMMAND ${CMAKE_COMMAND} -E echo " Copying foo.h.in to foo.h."
+ COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/foo.h.in
+ ${PROJECT_BINARY_DIR}/foo.h
+ )
+
+# Add the location of foo.h to the include path.
+include_directories(${PROJECT_BINARY_DIR})
+
+# Test generation of a file to the build tree without full path. As
+# of CMake 2.6 custom command outputs specified by relative path go in
+# the build tree.
+add_custom_command(
+ OUTPUT doc1.txt
+ COMMAND ${CMAKE_COMMAND} -E echo "Example Document Target" > doc1.txt
+ DEPENDS doc1.tex
+ VERBATIM
+ )
+
+# Add a custom target to drive generation of doc1.h.
+add_custom_target(TDocument ALL
+ COMMAND ${CMAKE_COMMAND} -E echo " Copying doc1.h to doc2.h."
+ COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/doc1.h
+ ${PROJECT_BINARY_DIR}/doc2.h
+ DEPENDS doc1.txt ${PROJECT_BINARY_DIR}//doc1.h # test 2 slashes
+ COMMENT "Running top-level TDocument commands"
+ SOURCES doc1.tex
+ )
+
+# Setup a pre- and post-build pair that will fail if not run in the
+# proper order.
+add_custom_command(
+ TARGET TDocument PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo " Writing doc1pre.txt."
+ COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/doc1.tex ${PROJECT_BINARY_DIR}/doc1pre.txt
+ COMMENT "Running TDocument pre-build commands"
+ )
+add_custom_command(
+ TARGET TDocument POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo " Copying doc1pre.txt to doc2post.txt."
+ COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/doc1pre.txt
+ ${PROJECT_BINARY_DIR}/doc2post.txt
+ BYPRODUCTS ${PROJECT_BINARY_DIR}/doc2post.txt
+ COMMENT "Running TDocument post-build commands"
+ )
+
+# Setup a custom target that will fail if the POST_BUILD custom command
+# isn't run before it.
+add_custom_command(
+ OUTPUT doc3post.txt
+ DEPENDS ${PROJECT_BINARY_DIR}/doc2post.txt
+ COMMAND ${CMAKE_COMMAND} -E echo " Copying doc2pre.txt to doc3post.txt."
+ COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/doc2post.txt
+ ${PROJECT_BINARY_DIR}/doc3post.txt
+ COMMENT "Running TDocument post-build dependent custom command"
+ )
+add_custom_target(doc3Post ALL DEPENDS doc3post.txt)
+add_dependencies(doc3Post TDocument)
+
+################################################################
+#
+# Test using a multistep generated file
+#
+################################################################
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/foo.pre
+ DEPENDS ${PROJECT_SOURCE_DIR}/foo.in
+ TDocument # Ensure doc1.h generates before this target
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${PROJECT_SOURCE_DIR}/foo.in
+ ${PROJECT_BINARY_DIR}/foo.pre
+ )
+
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/foo.c
+ DEPENDS ${PROJECT_BINARY_DIR}/foo.pre
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${PROJECT_BINARY_DIR}/foo.pre
+ ${PROJECT_BINARY_DIR}/foo.c
+ )
+
+# Test using OBJECT_DEPENDS to bring in a custom command.
+# Use a path that can be simplified to make sure paths
+# are consistently normalized.
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/subdir/../subdir/subdir.h
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_SOURCE_DIR}/subdir.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/subdir/subdir.h
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/subdir.h.in
+ )
+set_property(SOURCE ${PROJECT_BINARY_DIR}/foo.c PROPERTY
+ OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/subdir/../subdir/subdir.h)
+
+# Add custom command to generate not_included.h, which is a header
+# file that is not included by any source in this project. This will
+# test whether all custom command outputs explicitly listed as sources
+# get generated even if they are not needed by an object file.
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/not_included.h
+ DEPENDS ${PROJECT_SOURCE_DIR}/foo.h.in
+ COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/foo.h.in
+ ${PROJECT_BINARY_DIR}/not_included.h
+ )
+
+# add the executable
+add_executable(CustomCommand
+ ${PROJECT_BINARY_DIR}/foo.h
+ ${PROJECT_BINARY_DIR}/foo.c
+ ${PROJECT_BINARY_DIR}/wrapped.c
+ ${PROJECT_BINARY_DIR}/wrapped_help.c
+ ${PROJECT_BINARY_DIR}/generated.c
+ ${PROJECT_BINARY_DIR}/not_included.h
+ gen_redirect.c # default location for custom commands is in build tree
+ )
+
+# Add the rule to create generated.c at build time. This is placed
+# here to test adding the generation rule after referencing the
+# generated source in a target.
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/generated.c
+ DEPENDS $<1:generator> $<0:does_not_exist>
+ COMMAND generator
+ ARGS ${PROJECT_BINARY_DIR}/generated.c
+ )
+
+target_link_libraries(CustomCommand GeneratedHeader)
+
+##############################################################################
+# Test for using just the target name as executable in the COMMAND
+# section. Has to be recognized and replaced by CMake with the output
+# actual location of the executable.
+# Additionally the generator is created in an extra subdir after the
+# add_custom_command() is used.
+#
+# Test the same for add_custom_target()
+
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated_extern.cxx
+ COMMAND generator_extern ${CMAKE_CURRENT_BINARY_DIR}/generated_extern.cxx
+ )
+
+add_executable(CustomCommandUsingTargetTest main.cxx ${CMAKE_CURRENT_BINARY_DIR}/generated_extern.cxx )
+
+add_custom_target(RunTarget
+ COMMAND generator_extern ${CMAKE_CURRENT_BINARY_DIR}/run_target.cxx
+ )
+
+add_custom_command(TARGET CustomCommandUsingTargetTest POST_BUILD
+ COMMAND dummy_generator ${CMAKE_CURRENT_BINARY_DIR}/generated_dummy.cxx)
+
+add_subdirectory(GeneratorInExtraDir)
+
+##############################################################################
+# Test shell operators in custom commands.
+
+add_executable(tcat tcat.cxx)
+
+# Test that list expansion from a generator expression works.
+set_property(TARGET tcat PROPERTY DEPSLIST tcat gen_redirect_in.c)
+
+add_custom_command(OUTPUT gen_redirect.c
+ DEPENDS $<TARGET_PROPERTY:tcat,DEPSLIST>
+ COMMAND tcat < ${CMAKE_CURRENT_SOURCE_DIR}/gen_redirect_in.c > gen_redirect.c
+ COMMAND ${CMAKE_COMMAND} -E echo "#endif" >> gen_redirect.c
+ VERBATIM
+ )
+
+##############################################################################
+# Test non-trivial command line arguments in custom commands.
+set(EXPECTED_ARGUMENTS)
+set(CHECK_ARGS)
+if(NOT MSVC71)
+ set(CHECK_ARGS -DPATH=c:/posix/path)
+endif()
+set(CHECK_ARGS
+ ${CHECK_ARGS}
+ c:/posix/path
+ c:\\windows\\path
+ 'single-quotes'
+ single'quote
+ \"double-quotes\"
+ "\\;semi-colons\\;"
+ "semi\\;colon"
+ `back-ticks`
+ back`tick
+ "(parens)"
+ "(lparen"
+ "rparen)"
+ {curly}
+ {lcurly}
+ rcurly}
+ <angle>
+ <langle
+ rangle>
+ [square]
+ [lsquare # these have funny behavior due to special cases for
+ rsquare] # windows registry value names in list expansion
+ $dollar-signs$
+ dollar$sign
+ &ampersands&x # Borland make does not like trailing ampersand
+ one&ampersand
+ @two-ats@
+ one@at
+ ~two-tilda~
+ one~tilda
+ ^two-carrots^
+ one^carrot
+ %two-percents%
+ one%percent
+ !two-exclamations!
+ one!exclamation
+ ?two-questions?
+ one?question
+ *two-stars*
+ one*star
+ =two+equals=
+ one=equals
+ _two-underscores_
+ one_underscore
+ ,two-commas,
+ one,comma
+ .two-periods.
+ one.period
+ |two-pipes|
+ one|pipe
+ |nopipe
+ "#two-pounds#"
+ "one#pound"
+ "#nocomment"
+ "c:/posix/path/with space"
+ "c:\\windows\\path\\with space"
+ "'single quotes with space'"
+ "single'quote with space"
+ "\"double-quotes with space\""
+ "\\;semi-colons w s\\;"
+ "semi\\;colon w s"
+ "`back-ticks` w s"
+ "back`tick w s"
+ "(parens) w s"
+ "(lparen w s"
+ "rparen) w s"
+ "{curly} w s"
+ "{lcurly w s"
+ "rcurly} w s"
+ "<angle> w s"
+ "<langle w s"
+ "rangle> w s"
+ "[square] w s"
+ "[lsquare w s" # these have funny behavior due to special cases for
+ "rsquare] w s" # windows registry value names in list expansion
+ "$dollar-signs$ w s"
+ "dollar$sign w s"
+ "&ampersands& w s"
+ "one&ampersand w s"
+ "@two-ats@ w s"
+ "one@at w s"
+ "~two-tilda~ w s"
+ "one~tilda w s"
+ "^two-carrots^ w s"
+ "one^carrot w s"
+ "%two-percents% w s"
+ "one%percent w s"
+ "!two-exclamations! w s"
+ "one!exclamation w s"
+ "*two-stars* w s"
+ "one*star w s"
+ "=two+equals= w s"
+ "one=equals w s"
+ "_two-underscores_ w s"
+ "one_underscore w s"
+ "?two-questions? w s"
+ "one?question w s"
+ ",two-commas, w s"
+ "one,comma w s"
+ ".two-periods. w s"
+ "one.period w s"
+ "|two-pipes| w s"
+ "one|pipe w s"
+ "#two-pounds# w s"
+ "one#pound w s"
+ ~ ` ! @ \# $ % ^ & _ - + = : "\;" \" ' , . ? "(" ")" { } []
+ )
+if(NOT MINGW)
+ # * # MinGW programs on windows always expands the wildcard!
+ # / # MSys make converts a leading slash to the mingw home directory
+ list(APPEND CHECK_ARGS * /)
+endif()
+
+# The windows command shell does not support a double quote by itself:
+# double\"quote
+# without messing up quoting of arguments following it.
+
+# Make tools need help with escaping a single backslash
+# \
+# at the end of a command because they think it is a continuation
+# character.
+
+# We now have special cases for shell operators:
+# | < > << >> &> 2>&1 1>&2
+# to allow custom commands to perform redirection.
+
+foreach(arg ${CHECK_ARGS} "")
+ set(ARG "${arg}")
+ string(REPLACE "\\" "\\\\" ARG "${ARG}")
+ string(REPLACE "\"" "\\\"" ARG "${ARG}")
+ string(APPEND EXPECTED_ARGUMENTS
+ " \"${ARG}\",
+")
+endforeach()
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/check_command_line.c.in
+ ${CMAKE_CURRENT_BINARY_DIR}/check_command_line.c
+ @ONLY)
+add_executable(check_command_line
+ ${CMAKE_CURRENT_BINARY_DIR}/check_command_line.c)
+set(output_name "check_command_line")
+set_property(TARGET check_command_line
+ PROPERTY OUTPUT_NAME ${output_name})
+# set_target_properties(check_command_line PROPERTIES
+# COMPILE_FLAGS -DCHECK_COMMAND_LINE_VERBOSE)
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/command_line_check
+ COMMAND ${CMAKE_COMMAND} -DMARK_FILE=${CMAKE_CURRENT_BINARY_DIR}/check_mark.txt
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/check_mark.cmake
+ COMMAND ${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/${output_name}
+ ${CHECK_ARGS} ""
+ VERBATIM
+ COMMENT "Checking custom command line escapes (single'quote)"
+ )
+set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/command_line_check
+ PROPERTIES SYMBOLIC 1)
+add_custom_target(do_check_command_line ALL
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/command_line_check
+ COMMAND ${CMAKE_COMMAND} -E echo "Checking custom target command escapes"
+ COMMAND ${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/${output_name}
+ ${CHECK_ARGS} ""
+ VERBATIM
+ COMMENT "Checking custom target command line escapes ($dollar-signs$)"
+ )
+add_dependencies(do_check_command_line check_command_line)
+
+add_custom_target(pre_check_command_line
+ COMMAND ${CMAKE_COMMAND} -E rm -f ${CMAKE_CURRENT_BINARY_DIR}/check_mark.txt
+ )
+add_dependencies(do_check_command_line pre_check_command_line)
+
+# <SameNameTest>
+#
+# Add a custom target called "SameName" -- then add a custom command in a
+# different target whose output is a full-path file called "SameName" -- then
+# add a second custom target that depends on the full-path file ".../SameName"
+#
+# At first, this reproduces a bug reported by a customer. After fixing it,
+# having this test here makes sure it stays fixed moving forward.
+#
+add_custom_command(
+ OUTPUT SameName1.txt
+ COMMAND ${CMAKE_COMMAND} -E touch SameName1.txt
+ )
+add_custom_target(SameName ALL
+ DEPENDS SameName1.txt
+ )
+
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/subdir/SameName
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/subdir
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/subdir/SameName
+ )
+add_custom_target(DifferentName ALL
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/subdir/SameName
+ )
+#
+# </SameNameTest>
+
+# Per-config target name and generator expressions.
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../PerConfig PerConfig)
+add_custom_command(
+ OUTPUT perconfig.out
+ COMMAND ${PerConfig_COMMAND}
+ DEPENDS ${PerConfig_DEPENDS}
+ VERBATIM
+ )
+set_property(SOURCE perconfig.out PROPERTY SYMBOLIC 1)
+add_custom_target(perconfig_target ALL
+ COMMAND ${CMAKE_COMMAND} -E echo "perconfig=$<TARGET_FILE:perconfig>" "config=$<CONFIGURATION>"
+ DEPENDS perconfig.out)
+
+# Test SOURCES in add_custom_target() with COMPILE_DEFINITIONS
+# which previously caused a crash in the makefile generators.
+add_custom_target(source_in_custom_target SOURCES source_in_custom_target.cpp)
+set_property(SOURCE source_in_custom_target
+ PROPERTY COMPILE_DEFINITIONS "TEST"
+)
+
+set(gen_path "${CMAKE_CURRENT_BINARY_DIR}//./foo")
+set(gen_file "${gen_path}/foo.cxx")
+
+add_custom_command(
+ OUTPUT "${gen_file}"
+ # Make sure the output directory exists before trying to write to it.
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${gen_path}"
+ COMMAND ${CMAKE_COMMAND} -E touch "${gen_file}"
+)
+
+add_library(NormOutput "${gen_file}")
+
+string(APPEND gen_path "/bar")
+set(gen_file "${gen_path}/bar.cxx")
+
+add_custom_command(
+ OUTPUT "${gen_path}"
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${gen_path}"
+)
+
+add_custom_command(
+ OUTPUT "${gen_file}"
+ DEPENDS "${gen_path}"
+ COMMAND ${CMAKE_COMMAND} -E touch "${gen_file}")
+
+add_library(NormDepends "${gen_file}")
+
+# Test that USES_TERMINAL is parsed correctly.
+# It seems much more difficult to test that USES_TERMINAL actually gives
+# the subprocess console access, as test output is piped through CTest,
+# and CTest itself might not be connected to the console.
+
+set(gen_file "${gen_path}/bar2.cxx")
+
+add_custom_command(
+ OUTPUT "${gen_file}"
+ DEPENDS "${gen_path}"
+ COMMAND ${CMAKE_COMMAND} -E touch "${gen_file}"
+ VERBATIM
+ USES_TERMINAL
+)
+
+add_library(UseConsole "${gen_file}")
+
+add_custom_target(UseConsoleTarget ALL
+ COMMAND ${CMAKE_COMMAND} -E echo "Custom console target."
+ VERBATIM
+ USES_TERMINAL
+)
+
+if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12)
+ # Xcode's "new build system" does not support multiple targets
+ # producing the same custom command output.
+ add_custom_target(GenPath DEPENDS "${gen_path}")
+ add_dependencies(NormDepends GenPath)
+ add_dependencies(UseConsole GenPath)
+endif()
+
+# Test COMMAND_EXPAND_LISTS
+set(cmp_args "1ARG=COMMAND_EXPAND_LISTS" "2ARG=test" "3ARG=outfile"
+ "4ARG=content")
+set(AARGS "")
+foreach(arg IN LISTS cmp_args)
+ list(APPEND AARGS "-DA${arg}")
+endforeach()
+
+set(gen_file "expand_custom_command.phony")
+add_custom_command(
+ OUTPUT "${gen_file}"
+ COMMAND ${CMAKE_COMMAND} ${AARGS}
+ "-DB$<JOIN:$<TARGET_PROPERTY:command_expand_lists,CMPARGS>,;-DB>"
+ "-P" "${CMAKE_CURRENT_SOURCE_DIR}/compare_options.cmake"
+ COMMAND_EXPAND_LISTS
+ VERBATIM
+)
+set_property(SOURCE "${gen_file}" PROPERTY SYMBOLIC ON)
+add_custom_target(command_expand_lists ALL DEPENDS "${gen_file}")
+set_property(TARGET command_expand_lists PROPERTY CMPARGS "${cmp_args}")
+
+# This also tests that `./` is squeezed out of the resulting path.
+set(depends_path "./depended_upon_path.txt")
+
+add_custom_command(
+ OUTPUT ${depends_path}
+ COMMAND ${CMAKE_COMMAND} -E touch ${depends_path}
+)
+
+add_custom_command(
+ OUTPUT "depends_on_path.txt"
+ COMMAND ${CMAKE_COMMAND} -E touch "depends_on_path.txt"
+ DEPENDS ${depends_path}
+)
+
+add_custom_target(depends_on_path ALL DEPENDS "depends_on_path.txt")
+
+add_custom_command(
+ OUTPUT "depends_on_in_source_path.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/main.cxx" depends_on_in_source_path.txt
+ DEPENDS main.cxx
+)
+
+add_custom_target(depends_on_in_source_path ALL DEPENDS "depends_on_in_source_path.txt")
+
+add_custom_command(
+ OUTPUT "depends_on_in_rel_source_path.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/main.cxx" depends_on_in_rel_source_path.txt
+ DEPENDS ./main.cxx
+)
+
+add_custom_target(depends_on_in_rel_source_path ALL DEPENDS "depends_on_in_rel_source_path.txt")
+
+add_library(mac_fw SHARED mac_fw.c)
+set_target_properties(mac_fw PROPERTIES
+ FRAMEWORK 1
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib
+ )
+add_custom_command(OUTPUT mac_fw.txt COMMAND ${CMAKE_COMMAND} -E touch mac_fw.txt DEPENDS mac_fw)
+add_custom_target(drive_mac_fw ALL DEPENDS mac_fw.txt)
+
+# Test empty COMMANDs are ommited
+add_executable(empty_command empty_command.cxx)
+add_custom_command(TARGET empty_command POST_BUILD COMMAND $<0:date>)
diff --git a/Tests/CustomCommand/GeneratedHeader/CMakeLists.txt b/Tests/CustomCommand/GeneratedHeader/CMakeLists.txt
new file mode 100644
index 0000000..f7308e8
--- /dev/null
+++ b/Tests/CustomCommand/GeneratedHeader/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Simulate in-source build include-file behavior for out-of-source
+# builds.
+set(CMAKE_INCLUDE_CURRENT_DIR 1)
+
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated.h
+ COMMAND
+ ${CMAKE_COMMAND} ARGS -E
+ copy ${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/generated.h
+)
+
+add_library(GeneratedHeader main.cpp ${CMAKE_CURRENT_BINARY_DIR}/generated.h)
+
diff --git a/Tests/CustomCommand/GeneratedHeader/generated.h.in b/Tests/CustomCommand/GeneratedHeader/generated.h.in
new file mode 100644
index 0000000..ae6f64c
--- /dev/null
+++ b/Tests/CustomCommand/GeneratedHeader/generated.h.in
@@ -0,0 +1 @@
+//hello
diff --git a/Tests/CustomCommand/GeneratedHeader/main.cpp b/Tests/CustomCommand/GeneratedHeader/main.cpp
new file mode 100644
index 0000000..0b43ffe
--- /dev/null
+++ b/Tests/CustomCommand/GeneratedHeader/main.cpp
@@ -0,0 +1,5 @@
+#include "generated.h"
+int mainGeneratedHeader()
+{
+ return 0;
+}
diff --git a/Tests/CustomCommand/GeneratorInExtraDir/CMakeLists.txt b/Tests/CustomCommand/GeneratorInExtraDir/CMakeLists.txt
new file mode 100644
index 0000000..04506db
--- /dev/null
+++ b/Tests/CustomCommand/GeneratorInExtraDir/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_definitions(-DGENERATOR_EXTERN)
+
+# add the executable which will be used for generating files
+add_executable(generator_extern ../generator.cxx)
+set_target_properties(generator_extern PROPERTIES OUTPUT_NAME the_external_generator)
+
+# add an executable which will be called from add_custom_command( ... POST_BUILD)
+add_executable(dummy_generator ../generator.cxx)
diff --git a/Tests/CustomCommand/check_command_line.c.in b/Tests/CustomCommand/check_command_line.c.in
new file mode 100644
index 0000000..e0e0d21
--- /dev/null
+++ b/Tests/CustomCommand/check_command_line.c.in
@@ -0,0 +1,36 @@
+#include <stdio.h>
+#include <string.h>
+
+const char* expected_arguments[] =
+{
+@EXPECTED_ARGUMENTS@ 0
+};
+
+int main(int argc, const char* argv[])
+{
+ const char** a = argv+1;
+ const char** e = expected_arguments;
+ (void)argc;
+ for(;*a && *e; ++a, ++e)
+ {
+ if(strcmp(*a, *e) != 0)
+ {
+ fprintf(stderr, "Argument [%s] does not match expected [%s].\n",
+ *a, *e);
+ return 1;
+ }
+ else
+ {
+#if defined(CHECK_COMMAND_LINE_VERBOSE)
+ printf("[%s]\n", *a);
+#endif
+ }
+ }
+ if(*a || *e)
+ {
+ fprintf(stderr, "Number of arguments does not match expected.\n");
+ return 1;
+ }
+ printf("Command line escapes work!\n");
+ return 0;
+}
diff --git a/Tests/CustomCommand/check_mark.cmake b/Tests/CustomCommand/check_mark.cmake
new file mode 100644
index 0000000..1f47fd0
--- /dev/null
+++ b/Tests/CustomCommand/check_mark.cmake
@@ -0,0 +1,5 @@
+if(EXISTS "${MARK_FILE}")
+ message(FATAL_ERROR "Custom command run more than once!")
+else()
+ file(WRITE "${MARK_FILE}" "check for running custom command twice\n")
+endif()
diff --git a/Tests/CustomCommand/compare_options.cmake b/Tests/CustomCommand/compare_options.cmake
new file mode 100644
index 0000000..a32e579
--- /dev/null
+++ b/Tests/CustomCommand/compare_options.cmake
@@ -0,0 +1,14 @@
+set(range 1 2 3 4 5 6 7 8 9 10)
+set(aargs "")
+set(bargs "")
+foreach(n IN LISTS range)
+ set(aval "${A${n}ARG}")
+ set(bval "${B${n}ARG}")
+ if(aval OR bval)
+ list(APPEND aargs "\"${aval}\"")
+ list(APPEND bargs "\"${bval}\"")
+ endif()
+endforeach()
+if(NOT "${aargs}" STREQUAL "${bargs}")
+ message(FATAL_ERROR "COMPARE_OPTIONS: \n\t${aargs} != \n\t${bargs}")
+endif()
diff --git a/Tests/CustomCommand/doc1.tex b/Tests/CustomCommand/doc1.tex
new file mode 100644
index 0000000..e6b6ccb
--- /dev/null
+++ b/Tests/CustomCommand/doc1.tex
@@ -0,0 +1 @@
+int doc() { return 7;}
diff --git a/Tests/CustomCommand/empty_command.cxx b/Tests/CustomCommand/empty_command.cxx
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/CustomCommand/empty_command.cxx
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/CustomCommand/foo.h.in b/Tests/CustomCommand/foo.h.in
new file mode 100644
index 0000000..d7721a2
--- /dev/null
+++ b/Tests/CustomCommand/foo.h.in
@@ -0,0 +1 @@
+/* Empty header file just used to test header generation. */
diff --git a/Tests/CustomCommand/foo.in b/Tests/CustomCommand/foo.in
new file mode 100644
index 0000000..15d2d2c
--- /dev/null
+++ b/Tests/CustomCommand/foo.in
@@ -0,0 +1,32 @@
+#include "doc1.h"
+#include "foo.h"
+
+#include <stdio.h>
+
+int generated();
+int wrapped();
+
+#include "subdir/subdir.h"
+#ifndef SUBDIR_DEF
+# error SUBDIR_DEF not defined
+#endif
+
+int main ()
+{
+ if (generated()*wrapped()*doc() == 3*5*7)
+ {
+ FILE* fin = fopen("not_included.h", "r");
+ if(fin)
+ {
+ fclose(fin);
+ return 0;
+ }
+ else
+ {
+ return -2;
+ }
+ }
+
+ return -1;
+}
+
diff --git a/Tests/CustomCommand/gen_redirect_in.c b/Tests/CustomCommand/gen_redirect_in.c
new file mode 100644
index 0000000..6af364b
--- /dev/null
+++ b/Tests/CustomCommand/gen_redirect_in.c
@@ -0,0 +1,8 @@
+#if 1
+
+int gen_redirect()
+{
+ return 3;
+}
+
+/* endif should be concatenated to generated file */
diff --git a/Tests/CustomCommand/generator.cxx b/Tests/CustomCommand/generator.cxx
new file mode 100644
index 0000000..8281713
--- /dev/null
+++ b/Tests/CustomCommand/generator.cxx
@@ -0,0 +1,18 @@
+#include <stdio.h>
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s <file>\n", argv[0]);
+ return 1;
+ }
+ FILE* fp = fopen(argv[1], "w");
+#ifdef GENERATOR_EXTERN
+ fprintf(fp, "int generated() { return 3; }\n");
+#else
+ fprintf(fp, "extern int gen_redirect(void);\n");
+ fprintf(fp, "int generated() { return gen_redirect(); }\n");
+#endif
+ fclose(fp);
+ return 0;
+}
diff --git a/Tests/CustomCommand/mac_fw.c b/Tests/CustomCommand/mac_fw.c
new file mode 100644
index 0000000..cb35b44
--- /dev/null
+++ b/Tests/CustomCommand/mac_fw.c
@@ -0,0 +1,4 @@
+int mac_fw(void)
+{
+ return 0;
+}
diff --git a/Tests/CustomCommand/main.cxx b/Tests/CustomCommand/main.cxx
new file mode 100644
index 0000000..600e751
--- /dev/null
+++ b/Tests/CustomCommand/main.cxx
@@ -0,0 +1,6 @@
+extern int generated();
+
+int main()
+{
+ return generated();
+}
diff --git a/Tests/CustomCommand/source_in_custom_target.cpp b/Tests/CustomCommand/source_in_custom_target.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/CustomCommand/source_in_custom_target.cpp
diff --git a/Tests/CustomCommand/subdir.h.in b/Tests/CustomCommand/subdir.h.in
new file mode 100644
index 0000000..1e50750
--- /dev/null
+++ b/Tests/CustomCommand/subdir.h.in
@@ -0,0 +1 @@
+#define SUBDIR_DEF
diff --git a/Tests/CustomCommand/tcat.cxx b/Tests/CustomCommand/tcat.cxx
new file mode 100644
index 0000000..d010d14
--- /dev/null
+++ b/Tests/CustomCommand/tcat.cxx
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+int main()
+{
+ int c;
+ while ((c = getc(stdin), c != EOF)) {
+ putc(c, stdout);
+ }
+ return 0;
+}
diff --git a/Tests/CustomCommand/wrapped.h b/Tests/CustomCommand/wrapped.h
new file mode 100644
index 0000000..fa882cb
--- /dev/null
+++ b/Tests/CustomCommand/wrapped.h
@@ -0,0 +1 @@
+/* empty file */
diff --git a/Tests/CustomCommand/wrapper.cxx b/Tests/CustomCommand/wrapper.cxx
new file mode 100644
index 0000000..33412f8
--- /dev/null
+++ b/Tests/CustomCommand/wrapper.cxx
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char* argv[])
+{
+ if (argc < 3) {
+ fprintf(stderr, "Usage: %s <file1> <file2>\n", argv[0]);
+ return 1;
+ }
+ FILE* fp = fopen(argv[1], "w");
+ fprintf(fp, "extern int wrapped_help();\n");
+ fprintf(fp, "int wrapped() { return wrapped_help(); }\n");
+ fclose(fp);
+ fp = fopen(argv[2], "w");
+ fprintf(fp, "int wrapped_help() { return 5; }\n");
+ fclose(fp);
+#ifdef CMAKE_INTDIR
+ const char* cfg = (argc >= 4) ? argv[3] : "";
+ if (strcmp(cfg, CMAKE_INTDIR) != 0) {
+ fprintf(stderr,
+ "Did not receive expected configuration argument:\n"
+ " expected [" CMAKE_INTDIR "]\n"
+ " received [%s]\n",
+ cfg);
+ return 1;
+ }
+#endif
+ return 0;
+}
diff --git a/Tests/CustomCommandByproducts/CMakeLists.txt b/Tests/CustomCommandByproducts/CMakeLists.txt
new file mode 100644
index 0000000..08c897c
--- /dev/null
+++ b/Tests/CustomCommandByproducts/CMakeLists.txt
@@ -0,0 +1,177 @@
+cmake_minimum_required(VERSION 3.9)
+cmake_policy(SET CMP0058 OLD)
+project(CustomCommandByproducts C)
+
+# Generate a byproduct in a rule that runs in the target consuming it.
+add_custom_command(
+ OUTPUT timestamp1.txt
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_SOURCE_DIR}/byproduct1.c.in byproduct1.c
+ BYPRODUCTS byproduct1.c
+ COMMAND ${CMAKE_COMMAND} -E touch timestamp1.txt
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/byproduct1.c.in
+ )
+
+# Generate a byproduct in a rule that runs in a dependency of the consumer.
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/../CustomCommandByproducts/timestamp2.txt
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_SOURCE_DIR}/byproduct2.c.in byproduct2.c
+ BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/../CustomCommandByproducts/byproduct2.c
+ COMMAND ${CMAKE_COMMAND} -E touch timestamp2.txt
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/byproduct2.c.in
+ )
+add_custom_target(Producer2 DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/timestamp2.txt)
+
+# Generate a byproduct in a custom target.
+add_custom_target(Producer3_4
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_SOURCE_DIR}/byproduct3.c.in byproduct3.c
+ BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/../CustomCommandByproducts/byproduct3.c
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/byproduct3.c.in
+ )
+
+# Generate a byproduct in a custom target POST_BUILD command.
+add_custom_command(
+ TARGET Producer3_4 POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_SOURCE_DIR}/byproduct4.c.in byproduct4.c
+ BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/../CustomCommandByproducts/byproduct4.c
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/byproduct4.c.in
+ )
+
+add_executable(ProducerExe5_6_7 ProducerExe.c)
+
+# Generate a byproduct in an executable POST_BUILD command.
+add_custom_command(
+ TARGET ProducerExe5_6_7 POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_SOURCE_DIR}/byproduct5.c.in byproduct5.c
+ BYPRODUCTS byproduct5.c
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/byproduct5.c.in
+ )
+
+# Generate a byproduct in an executable PRE_LINK command.
+add_custom_command(
+ TARGET ProducerExe5_6_7 PRE_LINK
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_SOURCE_DIR}/byproduct6.c.in byproduct6.c
+ BYPRODUCTS byproduct6.c
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/byproduct6.c.in
+ )
+
+# Generate a byproduct in an executable PRE_BUILD command.
+add_custom_command(
+ TARGET ProducerExe5_6_7 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_SOURCE_DIR}/byproduct7.c.in byproduct7.c
+ BYPRODUCTS byproduct7.c
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/byproduct7.c.in
+ )
+
+# Generate a byproduct in a custom command that consumes other byproducts.
+add_custom_command(OUTPUT timestamp8.txt
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_SOURCE_DIR}/byproduct8.c.in byproduct8.c
+ COMMAND ${CMAKE_COMMAND} -E touch timestamp8.txt
+ BYPRODUCTS byproduct8.c
+ DEPENDS
+ ${CMAKE_CURRENT_BINARY_DIR}/byproduct2.c
+ ${CMAKE_CURRENT_BINARY_DIR}/byproduct3.c
+ ${CMAKE_CURRENT_BINARY_DIR}/byproduct4.c
+ ${CMAKE_CURRENT_BINARY_DIR}/byproduct5.c
+ ${CMAKE_CURRENT_BINARY_DIR}/byproduct6.c
+ ${CMAKE_CURRENT_BINARY_DIR}/byproduct7.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/byproduct8.c.in
+ )
+
+add_executable(ProducerExe9 ProducerExe.c)
+
+# Generate a byproduct in a custom target which depends on a byproduct of a
+# POST_BUILD command (test if dependency of custom target Producer9 to
+# ProducerExe9 is added).
+add_custom_command(
+ TARGET ProducerExe9 POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_SOURCE_DIR}/byproduct9.c.in byproduct9a.c
+ BYPRODUCTS byproduct9a.c
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/byproduct9.c.in
+ )
+add_custom_target(Producer9
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ byproduct9a.c byproduct9.c
+ BYPRODUCTS byproduct9.c
+ DEPENDS byproduct9a.c
+ )
+
+# Generate the library file of an imported target as a byproduct
+# of an external project.
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ set(cfg /${CMAKE_CFG_INTDIR})
+else()
+ set(cfg)
+endif()
+set(ExternalLibrary_LIBRARY
+ ${CMAKE_CURRENT_BINARY_DIR}/External-build${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX}
+ )
+include(ExternalProject)
+ExternalProject_Add(ExternalTarget
+ SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/External"
+ BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/External-build"
+ PREFIX "${CMAKE_CURRENT_BINARY_DIR}/External-build/root"
+ DOWNLOAD_COMMAND ""
+ INSTALL_COMMAND ""
+ BUILD_BYPRODUCTS "${ExternalLibrary_LIBRARY}"
+ )
+add_library(ExternalLibrary STATIC IMPORTED)
+set_property(TARGET ExternalLibrary PROPERTY IMPORTED_LOCATION ${ExternalLibrary_LIBRARY})
+add_dependencies(ExternalLibrary ExternalTarget)
+
+# Generate the library file of an imported target as a byproduct
+# of an external project. The byproduct uses <BINARY_DIR> that is substituted
+# by the real binary path
+if(_isMultiConfig)
+ set(cfg /${CMAKE_CFG_INTDIR})
+else()
+ set(cfg)
+endif()
+include(ExternalProject)
+ExternalProject_Add(ExtTargetSubst
+ SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/External"
+ DOWNLOAD_COMMAND ""
+ INSTALL_COMMAND ""
+ BUILD_BYPRODUCTS "<BINARY_DIR>${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX}"
+ )
+ExternalProject_Get_Property(ExtTargetSubst binary_dir)
+add_library(ExternalLibraryWithSubstitution STATIC IMPORTED)
+set_property(TARGET ExternalLibraryWithSubstitution PROPERTY IMPORTED_LOCATION
+ ${binary_dir}${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX})
+add_dependencies(ExternalLibraryWithSubstitution ExtTargetSubst)
+
+# Add an executable consuming all the byproducts.
+add_executable(CustomCommandByproducts
+ CustomCommandByproducts.c
+ byproduct1.c timestamp1.txt
+ byproduct2.c
+ byproduct3.c
+ byproduct4.c
+ byproduct5.c
+ byproduct6.c
+ byproduct7.c
+ byproduct8.c timestamp8.txt
+ byproduct9.c
+ )
+
+# Dependencies to byproducts of custom commands other than build events are not
+# yet traced (see issue #19005).
+add_dependencies(CustomCommandByproducts Producer2)
+
+target_link_libraries(CustomCommandByproducts ExternalLibrary)
+
+if(CMAKE_GENERATOR STREQUAL "Ninja")
+ add_custom_target(CheckNinja ALL
+ COMMENT "Checking build.ninja"
+ COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/ninja-check.cmake
+ )
+endif()
diff --git a/Tests/CustomCommandByproducts/CustomCommandByproducts.c b/Tests/CustomCommandByproducts/CustomCommandByproducts.c
new file mode 100644
index 0000000..0658d05
--- /dev/null
+++ b/Tests/CustomCommandByproducts/CustomCommandByproducts.c
@@ -0,0 +1,16 @@
+extern int byproduct1(void);
+extern int byproduct2(void);
+extern int byproduct3(void);
+extern int byproduct4(void);
+extern int byproduct5(void);
+extern int byproduct6(void);
+extern int byproduct7(void);
+extern int byproduct8(void);
+extern int byproduct9(void);
+extern int ExternalLibrary(void);
+int main(void)
+{
+ return (byproduct1() + byproduct2() + byproduct3() + byproduct4() +
+ byproduct5() + byproduct6() + byproduct7() + byproduct8() +
+ byproduct9() + ExternalLibrary() + 0);
+}
diff --git a/Tests/CustomCommandByproducts/External/CMakeLists.txt b/Tests/CustomCommandByproducts/External/CMakeLists.txt
new file mode 100644
index 0000000..feaa12e
--- /dev/null
+++ b/Tests/CustomCommandByproducts/External/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.1)
+project(External C)
+
+add_library(ExternalLibrary STATIC ExternalLibrary.c)
diff --git a/Tests/CustomCommandByproducts/External/ExternalLibrary.c b/Tests/CustomCommandByproducts/External/ExternalLibrary.c
new file mode 100644
index 0000000..554f611
--- /dev/null
+++ b/Tests/CustomCommandByproducts/External/ExternalLibrary.c
@@ -0,0 +1,4 @@
+int ExternalLibrary(void)
+{
+ return 0;
+}
diff --git a/Tests/CustomCommandByproducts/ProducerExe.c b/Tests/CustomCommandByproducts/ProducerExe.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/CustomCommandByproducts/ProducerExe.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CustomCommandByproducts/byproduct1.c.in b/Tests/CustomCommandByproducts/byproduct1.c.in
new file mode 100644
index 0000000..5c3cc24
--- /dev/null
+++ b/Tests/CustomCommandByproducts/byproduct1.c.in
@@ -0,0 +1 @@
+int byproduct1(void) { return 0; }
diff --git a/Tests/CustomCommandByproducts/byproduct2.c.in b/Tests/CustomCommandByproducts/byproduct2.c.in
new file mode 100644
index 0000000..eeb69ef
--- /dev/null
+++ b/Tests/CustomCommandByproducts/byproduct2.c.in
@@ -0,0 +1 @@
+int byproduct2(void) { return 0; }
diff --git a/Tests/CustomCommandByproducts/byproduct3.c.in b/Tests/CustomCommandByproducts/byproduct3.c.in
new file mode 100644
index 0000000..7d15310
--- /dev/null
+++ b/Tests/CustomCommandByproducts/byproduct3.c.in
@@ -0,0 +1 @@
+int byproduct3(void) { return 0; }
diff --git a/Tests/CustomCommandByproducts/byproduct4.c.in b/Tests/CustomCommandByproducts/byproduct4.c.in
new file mode 100644
index 0000000..8b243dd
--- /dev/null
+++ b/Tests/CustomCommandByproducts/byproduct4.c.in
@@ -0,0 +1 @@
+int byproduct4(void) { return 0; }
diff --git a/Tests/CustomCommandByproducts/byproduct5.c.in b/Tests/CustomCommandByproducts/byproduct5.c.in
new file mode 100644
index 0000000..47f5990
--- /dev/null
+++ b/Tests/CustomCommandByproducts/byproduct5.c.in
@@ -0,0 +1 @@
+int byproduct5(void) { return 0; }
diff --git a/Tests/CustomCommandByproducts/byproduct6.c.in b/Tests/CustomCommandByproducts/byproduct6.c.in
new file mode 100644
index 0000000..d70c14f
--- /dev/null
+++ b/Tests/CustomCommandByproducts/byproduct6.c.in
@@ -0,0 +1 @@
+int byproduct6(void) { return 0; }
diff --git a/Tests/CustomCommandByproducts/byproduct7.c.in b/Tests/CustomCommandByproducts/byproduct7.c.in
new file mode 100644
index 0000000..0be5006
--- /dev/null
+++ b/Tests/CustomCommandByproducts/byproduct7.c.in
@@ -0,0 +1 @@
+int byproduct7(void) { return 0; }
diff --git a/Tests/CustomCommandByproducts/byproduct8.c.in b/Tests/CustomCommandByproducts/byproduct8.c.in
new file mode 100644
index 0000000..abefd62
--- /dev/null
+++ b/Tests/CustomCommandByproducts/byproduct8.c.in
@@ -0,0 +1 @@
+int byproduct8(void) { return 0; }
diff --git a/Tests/CustomCommandByproducts/byproduct9.c.in b/Tests/CustomCommandByproducts/byproduct9.c.in
new file mode 100644
index 0000000..11eed2c
--- /dev/null
+++ b/Tests/CustomCommandByproducts/byproduct9.c.in
@@ -0,0 +1 @@
+int byproduct9(void) { return 0; }
diff --git a/Tests/CustomCommandByproducts/ninja-check.cmake b/Tests/CustomCommandByproducts/ninja-check.cmake
new file mode 100644
index 0000000..a7beb3d
--- /dev/null
+++ b/Tests/CustomCommandByproducts/ninja-check.cmake
@@ -0,0 +1,20 @@
+file(READ build.ninja build_ninja)
+if("${build_ninja}" MATCHES [====[
+# Unknown Build Time Dependencies.
+# Tell Ninja that they may appear as side effects of build rules
+# otherwise ordered by order-only dependencies.
+
+((build [^:]*: phony[^\n]*
+)*)# ========]====])
+ set(phony "${CMAKE_MATCH_1}")
+ if(NOT phony)
+ message(STATUS "build.ninja correctly does not have extra phony rules")
+ else()
+ string(REGEX REPLACE "\n+$" "" phony "${phony}")
+ string(REGEX REPLACE "\n" "\n " phony " ${phony}")
+ message(FATAL_ERROR "build.ninja incorrectly has extra phony rules:\n"
+ "${phony}")
+ endif()
+else()
+ message(FATAL_ERROR "build.ninja is incorrectly missing expected block")
+endif()
diff --git a/Tests/CustomCommandWorkingDirectory/CMakeLists.txt b/Tests/CustomCommandWorkingDirectory/CMakeLists.txt
new file mode 100644
index 0000000..7697a9b
--- /dev/null
+++ b/Tests/CustomCommandWorkingDirectory/CMakeLists.txt
@@ -0,0 +1,64 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(TestWorkingDir)
+
+add_custom_command(
+ OUTPUT "${TestWorkingDir_BINARY_DIR}/working.c"
+ COMMAND "${CMAKE_COMMAND}" -E copy ./working.c.in "${TestWorkingDir_BINARY_DIR}/working.c"
+ WORKING_DIRECTORY "${TestWorkingDir_SOURCE_DIR}"
+ COMMENT "custom command"
+)
+
+set_source_files_properties(
+ "${TestWorkingDir_BINARY_DIR}/customTarget1.c"
+ "${TestWorkingDir_BINARY_DIR}/customTarget2.c"
+ PROPERTIES GENERATED 1)
+
+add_executable(working "${TestWorkingDir_BINARY_DIR}/working.c"
+ "${TestWorkingDir_BINARY_DIR}/customTarget1.c")
+
+add_custom_target(
+ Custom ALL
+ COMMAND "${CMAKE_COMMAND}" -E copy_if_different ./customTarget.c "${TestWorkingDir_BINARY_DIR}/customTarget1.c"
+ BYPRODUCTS "${TestWorkingDir_BINARY_DIR}/customTarget1.c"
+ WORKING_DIRECTORY "${TestWorkingDir_SOURCE_DIR}"
+)
+
+add_dependencies(working Custom)
+
+file(MAKE_DIRECTORY ${TestWorkingDir_BINARY_DIR}/work)
+add_custom_command(
+ OUTPUT working2.c # Relative to build tree
+ COMMAND "${CMAKE_COMMAND}" -E copy ${TestWorkingDir_SOURCE_DIR}/working.c.in ../working2.c
+ DEPENDS ${TestWorkingDir_SOURCE_DIR}/working.c.in/ # trailing slash should be removed
+ WORKING_DIRECTORY work/ # Relative to build tree, trailing slash
+ )
+add_executable(working2 working2.c ${TestWorkingDir_BINARY_DIR}/customTarget2.c)
+
+add_custom_target(
+ Custom2 ALL
+ COMMAND "${CMAKE_COMMAND}" -E copy_if_different ${TestWorkingDir_SOURCE_DIR}/customTarget.c ../customTarget2.c
+ BYPRODUCTS "${TestWorkingDir_BINARY_DIR}/customTarget2.c"
+ WORKING_DIRECTORY work/ # Relative to build tree, trailing slash
+)
+
+add_dependencies(working2 Custom2)
+
+file(MAKE_DIRECTORY ${TestWorkingDir_BINARY_DIR}/genex)
+add_custom_command(
+ OUTPUT "${TestWorkingDir_BINARY_DIR}/genex/working.c"
+ COMMAND "${CMAKE_COMMAND}" -E copy "${TestWorkingDir_SOURCE_DIR}/working.c.in" "${TestWorkingDir_BINARY_DIR}/genex/working.c"
+ WORKING_DIRECTORY "$<0:not_used/>${TestWorkingDir_BINARY_DIR}/$<1:genex>/"
+ COMMENT "custom command"
+)
+
+add_executable(workinggenex "${TestWorkingDir_BINARY_DIR}/genex/working.c"
+ "${TestWorkingDir_BINARY_DIR}/genex/customTarget.c")
+
+add_custom_target(
+ CustomGenex ALL
+ COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${TestWorkingDir_SOURCE_DIR}/customTarget.c" "${TestWorkingDir_BINARY_DIR}/genex/customTarget.c"
+ BYPRODUCTS "${TestWorkingDir_BINARY_DIR}/genex/customTarget.c"
+ WORKING_DIRECTORY "$<0:not_used/>${TestWorkingDir_BINARY_DIR}/$<1:genex>/"
+)
+
+add_dependencies(workinggenex CustomGenex)
diff --git a/Tests/CustomCommandWorkingDirectory/customTarget.c b/Tests/CustomCommandWorkingDirectory/customTarget.c
new file mode 100644
index 0000000..8dbf0d4
--- /dev/null
+++ b/Tests/CustomCommandWorkingDirectory/customTarget.c
@@ -0,0 +1,4 @@
+int customTarget()
+{
+ return 0;
+}
diff --git a/Tests/CustomCommandWorkingDirectory/working.c.in b/Tests/CustomCommandWorkingDirectory/working.c.in
new file mode 100644
index 0000000..cf75bd1
--- /dev/null
+++ b/Tests/CustomCommandWorkingDirectory/working.c.in
@@ -0,0 +1,7 @@
+int customTarget();
+
+int main()
+{
+ return customTarget();
+}
+
diff --git a/Tests/CxxDialect/CMakeLists.txt b/Tests/CxxDialect/CMakeLists.txt
new file mode 100644
index 0000000..8c90339
--- /dev/null
+++ b/Tests/CxxDialect/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 2.8.12)
+cmake_policy(SET CMP0025 NEW)
+project(CxxDialect)
+
+add_executable(use_typeof use_typeof.cxx)
+set_property(TARGET use_typeof PROPERTY CXX_STANDARD 98)
+
+add_executable(use_constexpr use_constexpr.cxx)
+set_property(TARGET use_constexpr PROPERTY CXX_STANDARD 11)
+
+add_executable(CxxDialect use_constexpr_and_typeof.cxx)
+set_property(TARGET CxxDialect PROPERTY CXX_STANDARD 11)
+
+try_compile(typeof_no_extensions_works
+ "${CMAKE_CURRENT_BINARY_DIR}/use_typeof_test"
+ "${CMAKE_CURRENT_SOURCE_DIR}/use_typeof.cxx"
+ COMPILE_DEFINITIONS
+ CMAKE_FLAGS
+ "-DCMAKE_CXX_STANDARD=98"
+ "-DCMAKE_CXX_EXTENSIONS=FALSE"
+ OUTPUT_VARIABLE OUTPUT
+)
+
+if (typeof_no_extensions_works)
+ message("Use of typeof extension with extensions disabled works, but is expected to fail: ${OUTPUT}")
+else()
+ message("Use of typeof extension with extensions disabled fails, as expected")
+endif()
diff --git a/Tests/CxxDialect/use_constexpr.cxx b/Tests/CxxDialect/use_constexpr.cxx
new file mode 100644
index 0000000..30ccc4c
--- /dev/null
+++ b/Tests/CxxDialect/use_constexpr.cxx
@@ -0,0 +1,10 @@
+
+constexpr int foo()
+{
+ return 0;
+}
+
+int main(int argc, char**)
+{
+ return foo();
+}
diff --git a/Tests/CxxDialect/use_constexpr_and_typeof.cxx b/Tests/CxxDialect/use_constexpr_and_typeof.cxx
new file mode 100644
index 0000000..af217b6
--- /dev/null
+++ b/Tests/CxxDialect/use_constexpr_and_typeof.cxx
@@ -0,0 +1,11 @@
+
+constexpr int foo()
+{
+ return 0;
+}
+
+int main(int argc, char**)
+{
+ typeof(argc) ret = foo();
+ return ret;
+}
diff --git a/Tests/CxxDialect/use_typeof.cxx b/Tests/CxxDialect/use_typeof.cxx
new file mode 100644
index 0000000..dabb61f
--- /dev/null
+++ b/Tests/CxxDialect/use_typeof.cxx
@@ -0,0 +1,6 @@
+
+int main(int argc, char**)
+{
+ typeof(argc) ret = 0;
+ return ret;
+}
diff --git a/Tests/CxxOnly/CMakeLists.txt b/Tests/CxxOnly/CMakeLists.txt
new file mode 100644
index 0000000..09689cb
--- /dev/null
+++ b/Tests/CxxOnly/CMakeLists.txt
@@ -0,0 +1,14 @@
+# a simple CXX only test case
+cmake_minimum_required(VERSION 2.8.12)
+project (CxxOnly CXX)
+
+set(CMAKE_DEBUG_POSTFIX "_test_debug_postfix")
+if(WIN32)
+ set(EXTRA_SRCS test.CPP)
+endif()
+add_library(testcxx1.my STATIC libcxx1.cxx test.C ${EXTRA_SRCS})
+add_library(testcxx2 SHARED libcxx2.cxx)
+add_executable (CxxOnly cxxonly.cxx)
+target_link_libraries(CxxOnly testcxx1.my testcxx2)
+
+add_library(testCxxModule MODULE testCxxModule.cxx)
diff --git a/Tests/CxxOnly/cxxonly.cxx b/Tests/CxxOnly/cxxonly.cxx
new file mode 100644
index 0000000..8bd1637
--- /dev/null
+++ b/Tests/CxxOnly/cxxonly.cxx
@@ -0,0 +1,25 @@
+#include "libcxx1.h"
+#include "libcxx2.h"
+extern int testC;
+#ifdef _MSC_VER
+extern int testCPP;
+#endif
+
+#include <stdio.h>
+
+int main()
+{
+ testC = 1;
+#ifdef _MSC_VER
+ testCPP = 1;
+#endif
+ if (LibCxx1Class::Method() != 2.0) {
+ printf("Problem with libcxx1\n");
+ return 1;
+ }
+ if (LibCxx2Class::Method() != 1.0) {
+ printf("Problem with libcxx2\n");
+ return 1;
+ }
+ return 0;
+}
diff --git a/Tests/CxxOnly/libcxx1.cxx b/Tests/CxxOnly/libcxx1.cxx
new file mode 100644
index 0000000..da18019
--- /dev/null
+++ b/Tests/CxxOnly/libcxx1.cxx
@@ -0,0 +1,6 @@
+#include "libcxx1.h"
+
+float LibCxx1Class::Method()
+{
+ return 2.0;
+}
diff --git a/Tests/CxxOnly/libcxx1.h b/Tests/CxxOnly/libcxx1.h
new file mode 100644
index 0000000..9452a64
--- /dev/null
+++ b/Tests/CxxOnly/libcxx1.h
@@ -0,0 +1,5 @@
+class LibCxx1Class
+{
+public:
+ static float Method();
+};
diff --git a/Tests/CxxOnly/libcxx2.cxx b/Tests/CxxOnly/libcxx2.cxx
new file mode 100644
index 0000000..453039c
--- /dev/null
+++ b/Tests/CxxOnly/libcxx2.cxx
@@ -0,0 +1,6 @@
+#include "libcxx2.h"
+
+float LibCxx2Class::Method()
+{
+ return 1.0;
+}
diff --git a/Tests/CxxOnly/libcxx2.h b/Tests/CxxOnly/libcxx2.h
new file mode 100644
index 0000000..774e4e8
--- /dev/null
+++ b/Tests/CxxOnly/libcxx2.h
@@ -0,0 +1,15 @@
+#ifdef _WIN32
+# ifdef testcxx2_EXPORTS
+# define CM_TEST_LIB_EXPORT __declspec(dllexport)
+# else
+# define CM_TEST_LIB_EXPORT __declspec(dllimport)
+# endif
+#else
+# define CM_TEST_LIB_EXPORT
+#endif
+
+class CM_TEST_LIB_EXPORT LibCxx2Class
+{
+public:
+ static float Method();
+};
diff --git a/Tests/CxxOnly/test.C b/Tests/CxxOnly/test.C
new file mode 100644
index 0000000..e87e6c0
--- /dev/null
+++ b/Tests/CxxOnly/test.C
@@ -0,0 +1 @@
+int testC;
diff --git a/Tests/CxxOnly/test.CPP b/Tests/CxxOnly/test.CPP
new file mode 100644
index 0000000..8a3cde2
--- /dev/null
+++ b/Tests/CxxOnly/test.CPP
@@ -0,0 +1 @@
+int testCPP;
diff --git a/Tests/CxxOnly/testCxxModule.cxx b/Tests/CxxOnly/testCxxModule.cxx
new file mode 100644
index 0000000..5015d07
--- /dev/null
+++ b/Tests/CxxOnly/testCxxModule.cxx
@@ -0,0 +1,9 @@
+#ifdef _WIN32
+# define TEST_EXPORT __declspec(dllexport)
+#else
+# define TEST_EXPORT
+#endif
+TEST_EXPORT int testCxxModule(void)
+{
+ return 0;
+}
diff --git a/Tests/CxxSubdirC/CMakeLists.txt b/Tests/CxxSubdirC/CMakeLists.txt
new file mode 100644
index 0000000..52474f8
--- /dev/null
+++ b/Tests/CxxSubdirC/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.0)
+project(CxxSubdirC CXX)
+add_subdirectory(Cdir)
+add_executable(CxxSubdirC main.cxx $<TARGET_OBJECTS:Cobj>)
diff --git a/Tests/CxxSubdirC/Cdir/CMakeLists.txt b/Tests/CxxSubdirC/Cdir/CMakeLists.txt
new file mode 100644
index 0000000..08a8757
--- /dev/null
+++ b/Tests/CxxSubdirC/Cdir/CMakeLists.txt
@@ -0,0 +1,2 @@
+enable_language(C)
+add_library(Cobj OBJECT Cobj.c)
diff --git a/Tests/CxxSubdirC/Cdir/Cobj.c b/Tests/CxxSubdirC/Cdir/Cobj.c
new file mode 100644
index 0000000..a593e07
--- /dev/null
+++ b/Tests/CxxSubdirC/Cdir/Cobj.c
@@ -0,0 +1,4 @@
+int Cobj(void)
+{
+ return 0;
+}
diff --git a/Tests/CxxSubdirC/main.cxx b/Tests/CxxSubdirC/main.cxx
new file mode 100644
index 0000000..c4cebc4
--- /dev/null
+++ b/Tests/CxxSubdirC/main.cxx
@@ -0,0 +1,5 @@
+extern "C" int Cobj(void);
+int main()
+{
+ return Cobj();
+}
diff --git a/Tests/DelphiCoverage/DartConfiguration.tcl.in b/Tests/DelphiCoverage/DartConfiguration.tcl.in
new file mode 100644
index 0000000..4edcea6
--- /dev/null
+++ b/Tests/DelphiCoverage/DartConfiguration.tcl.in
@@ -0,0 +1,8 @@
+# This file is configured by CMake automatically as DartConfiguration.tcl
+# If you choose not to use CMake, this file may be hand configured, by
+# filling in the required variables.
+
+
+# Configuration directories and files
+SourceDirectory: ${CMake_BINARY_DIR}/Testing/DelphiCoverage
+BuildDirectory: ${CMake_BINARY_DIR}/Testing/DelphiCoverage
diff --git a/Tests/DelphiCoverage/UTCovTest(UTCovTest.pas).html.in b/Tests/DelphiCoverage/UTCovTest(UTCovTest.pas).html.in
new file mode 100644
index 0000000..9caaea3
--- /dev/null
+++ b/Tests/DelphiCoverage/UTCovTest(UTCovTest.pas).html.in
@@ -0,0 +1,117 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
+ <title>Delphi CodeCoverage Coverage Report</title>
+<style type="text/css">
+table {border-spacing:0; border-collapse:collapse;}
+table, td, th {border: 1px solid black;}
+td, th {background: white; margin: 0; padding: 2px 0.5em 2px 0.5em}
+td {border-width: 0 1px 0 0;}
+th {border-width: 1px 1px 1px 0;}
+p, h1, h2, h3, th {font-family: verdana,arial,sans-serif; font-size: 10pt;}
+td {font-family: courier,monospace; font-size: 10pt;}
+th {background: #CCCCCC;}
+table.o tr td:nth-child(1) {font-weight: bold;}
+table.o tr td:nth-child(2) {text-align: right;}
+table.o tr td {border-width: 1px;}
+table.s {width: 100%;}
+table.s tr td {padding: 0 0.25em 0 0.25em;}
+table.s tr td:first-child {text-align: right; font-weight: bold;}
+table.s tr.notcovered td {background: #DDDDFF;}
+table.s tr.nocodegen td {background: #FFFFEE;}
+table.s tr.covered td {background: #CCFFCC;}
+table.s tr.covered td:first-child {color: green;}
+table.s {border-width: 1px 0 1px 1px;}
+table.sum tr td {border-width: 1px;}
+table.sum tr th {text-align:right;}
+table.sum tr th:first-child {text-align:center;}
+table.sum tr td {text-align:right;}
+table.sum tr td:first-child {text-align:left;}
+</style>
+</head>
+<body>
+<p>Coverage report for <strong>UTCovTest (C:\Users\joe.snyder\Work\OSEHRA\VistA\Packages\Order Entry Results Reporting\CPRS\Testing\Tests\UTCovTest.pas)</strong>.</p>
+<p> Generated at 10/3/2014 12:24:11 PM by <a href="http://code.google.com/p/delphi-code-coverage/" title="Code Coverage for Delphi 5+">DelphiCodeCoverage</a> - an open source tool for Delphi Code Coverage.</p>
+<p> Statistics for C:\Users\joe.snyder\Work\OSEHRA\VistA\Packages\Order Entry Results Reporting\CPRS\Testing\Tests\UTCovTest.pas </p>
+<table class="o"><tr><td>Number of lines covered</td><td>19</td></tr><tr><td>Number of lines with code gen</td><td>19</td></tr><tr><td>Line coverage</td><td>100%</td></tr></table>
+<br /><br />
+<table class="s">
+<tr class="nocodegen"><td>1</td><td><pre style="display:inline;">//---------------------------------------------------------------------------</pre></td></tr>
+<tr class="nocodegen"><td>2</td><td><pre style="display:inline;">// Copyright 2012 The Open Source Electronic Health Record Agent</pre></td></tr>
+<tr class="nocodegen"><td>3</td><td><pre style="display:inline;">//</pre></td></tr>
+<tr class="nocodegen"><td>4</td><td><pre style="display:inline;">// Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</pre></td></tr>
+<tr class="nocodegen"><td>5</td><td><pre style="display:inline;">// you may not use this file except in compliance with the License.</pre></td></tr>
+<tr class="nocodegen"><td>6</td><td><pre style="display:inline;">// You may obtain a copy of the License at</pre></td></tr>
+<tr class="nocodegen"><td>7</td><td><pre style="display:inline;">//</pre></td></tr>
+<tr class="nocodegen"><td>8</td><td><pre style="display:inline;">// &nbsp; &nbsp; http://www.apache.org/licenses/LICENSE-2.0</pre></td></tr>
+<tr class="nocodegen"><td>9</td><td><pre style="display:inline;">//</pre></td></tr>
+<tr class="nocodegen"><td>10</td><td><pre style="display:inline;">// Unless required by applicable law or agreed to in writing, software</pre></td></tr>
+<tr class="nocodegen"><td>11</td><td><pre style="display:inline;">// distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</pre></td></tr>
+<tr class="nocodegen"><td>12</td><td><pre style="display:inline;">// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</pre></td></tr>
+<tr class="nocodegen"><td>13</td><td><pre style="display:inline;">// See the License for the specific language governing permissions and</pre></td></tr>
+<tr class="nocodegen"><td>14</td><td><pre style="display:inline;">// limitations under the License.</pre></td></tr>
+<tr class="nocodegen"><td>15</td><td><pre style="display:inline;">//---------------------------------------------------------------------------</pre></td></tr>
+<tr class="nocodegen"><td>16</td><td><pre style="display:inline;">unit UTCovTest;</pre></td></tr>
+<tr class="nocodegen"><td>17</td><td><pre style="display:inline;">interface</pre></td></tr>
+<tr class="nocodegen"><td>18</td><td><pre style="display:inline;">uses UnitTest, TestFrameWork,SysUtils,Windows;</pre></td></tr>
+<tr class="nocodegen"><td>19</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="nocodegen"><td>20</td><td><pre style="display:inline;">implementation</pre></td></tr>
+<tr class="nocodegen"><td>21</td><td><pre style="display:inline;">type</pre></td></tr>
+<tr class="nocodegen"><td>22</td><td><pre style="display:inline;">UTCovTestTests=class(TTestCase)</pre></td></tr>
+<tr class="nocodegen"><td>23</td><td><pre style="display:inline;"> &nbsp;public</pre></td></tr>
+<tr class="nocodegen"><td>24</td><td><pre style="display:inline;"> &nbsp;procedure SetUp; override;</pre></td></tr>
+<tr class="nocodegen"><td>25</td><td><pre style="display:inline;"> &nbsp;procedure TearDown; override;</pre></td></tr>
+<tr class="nocodegen"><td>26</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="nocodegen"><td>27</td><td><pre style="display:inline;"> &nbsp;published</pre></td></tr>
+<tr class="nocodegen"><td>28</td><td><pre style="display:inline;"> &nbsp; &nbsp;procedure TestCov1;</pre></td></tr>
+<tr class="nocodegen"><td>29</td><td><pre style="display:inline;"> &nbsp; &nbsp;procedure TestCov2;</pre></td></tr>
+<tr class="nocodegen"><td>30</td><td><pre style="display:inline;"> &nbsp; &nbsp;procedure TestCov3;</pre></td></tr>
+<tr class="nocodegen"><td>31</td><td><pre style="display:inline;"> &nbsp;end;</pre></td></tr>
+<tr class="nocodegen"><td>32</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="nocodegen"><td>33</td><td><pre style="display:inline;">procedure NotRun;</pre></td></tr>
+<tr class="nocodegen"><td>34</td><td><pre style="display:inline;">begin</pre></td></tr>
+<tr class="nocodegen"><td>35</td><td><pre style="display:inline;"> &nbsp; &nbsp;WriteLn(&apos;This line will never run&apos;);</pre></td></tr>
+<tr class="nocodegen"><td>36</td><td><pre style="display:inline;">end;</pre></td></tr>
+<tr class="nocodegen"><td>37</td><td><pre style="display:inline;">procedure UTCovTestTests.SetUp;</pre></td></tr>
+<tr class="nocodegen"><td>38</td><td><pre style="display:inline;">begin</pre></td></tr>
+<tr class="covered"><td>39</td><td><pre style="display:inline;">end;</pre></td></tr>
+<tr class="nocodegen"><td>40</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="nocodegen"><td>41</td><td><pre style="display:inline;">procedure UTCovTestTests.TearDown;</pre></td></tr>
+<tr class="nocodegen"><td>42</td><td><pre style="display:inline;">begin</pre></td></tr>
+<tr class="covered"><td>43</td><td><pre style="display:inline;">end;</pre></td></tr>
+<tr class="nocodegen"><td>44</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="nocodegen"><td>45</td><td><pre style="display:inline;">procedure UTCovTestTests.TestCov1;</pre></td></tr>
+<tr class="covered"><td>46</td><td><pre style="display:inline;">begin</pre></td></tr>
+<tr class="nocodegen"><td>47</td><td><pre style="display:inline;"> &nbsp;{</pre></td></tr>
+<tr class="nocodegen"><td>48</td><td><pre style="display:inline;"> &nbsp;Block comment lines</pre></td></tr>
+<tr class="nocodegen"><td>49</td><td><pre style="display:inline;"> &nbsp;}</pre></td></tr>
+<tr class="covered"><td>50</td><td><pre style="display:inline;"> &nbsp;CheckEquals(1,2-1);</pre></td></tr>
+<tr class="covered"><td>51</td><td><pre style="display:inline;">end;</pre></td></tr>
+<tr class="nocodegen"><td>52</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="nocodegen"><td>53</td><td><pre style="display:inline;">procedure UTCovTestTests.TestCov2;</pre></td></tr>
+<tr class="nocodegen"><td>54</td><td><pre style="display:inline;">var</pre></td></tr>
+<tr class="nocodegen"><td>55</td><td><pre style="display:inline;"> &nbsp;i:DWORD;</pre></td></tr>
+<tr class="covered"><td>56</td><td><pre style="display:inline;">begin</pre></td></tr>
+<tr class="covered"><td>57</td><td><pre style="display:inline;"> &nbsp;for i := 0 to 1 do</pre></td></tr>
+<tr class="covered"><td>58</td><td><pre style="display:inline;"> &nbsp; &nbsp;WriteLn( IntToStr(i));</pre></td></tr>
+<tr class="nocodegen"><td>59</td><td><pre style="display:inline;"> &nbsp;// Comment</pre></td></tr>
+<tr class="covered"><td>60</td><td><pre style="display:inline;"> &nbsp;CheckEquals(i,2);</pre></td></tr>
+<tr class="covered"><td>61</td><td><pre style="display:inline;">end;</pre></td></tr>
+<tr class="nocodegen"><td>62</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="nocodegen"><td>63</td><td><pre style="display:inline;">procedure UTCovTestTests.TestCov3;</pre></td></tr>
+<tr class="nocodegen"><td>64</td><td><pre style="display:inline;">var</pre></td></tr>
+<tr class="nocodegen"><td>65</td><td><pre style="display:inline;"> i : DWORD;</pre></td></tr>
+<tr class="covered"><td>66</td><td><pre style="display:inline;">begin</pre></td></tr>
+<tr class="covered"><td>67</td><td><pre style="display:inline;"> &nbsp;i := 0;</pre></td></tr>
+<tr class="covered"><td>68</td><td><pre style="display:inline;"> &nbsp;while i &lt; 5 do</pre></td></tr>
+<tr class="covered"><td>69</td><td><pre style="display:inline;"> &nbsp; i := i+1;</pre></td></tr>
+<tr class="covered"><td>70</td><td><pre style="display:inline;"> &nbsp;CheckEquals(i,5);</pre></td></tr>
+<tr class="covered"><td>71</td><td><pre style="display:inline;">end;</pre></td></tr>
+<tr class="nocodegen"><td>72</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="covered"><td>73</td><td><pre style="display:inline;">begin</pre></td></tr>
+<tr class="covered"><td>74</td><td><pre style="display:inline;"> &nbsp;UnitTest.addSuite(UTCovTestTests.Suite);</pre></td></tr>
+<tr class="covered"><td>75</td><td><pre style="display:inline;">end.</pre></td></tr>
+</table>
+</body>
+</html>
diff --git a/Tests/DelphiCoverage/src/UTCovTest.pas b/Tests/DelphiCoverage/src/UTCovTest.pas
new file mode 100644
index 0000000..66db3c0
--- /dev/null
+++ b/Tests/DelphiCoverage/src/UTCovTest.pas
@@ -0,0 +1,75 @@
+//---------------------------------------------------------------------------
+// Copyright 2012 The Open Source Electronic Health Record Agent
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//---------------------------------------------------------------------------
+unit UTCovTest;
+interface
+uses UnitTest, TestFrameWork,SysUtils,Windows;
+
+implementation
+type
+UTCovTestTests=class(TTestCase)
+ public
+ procedure SetUp; override;
+ procedure TearDown; override;
+
+ published
+ procedure TestCov1;
+ procedure TestCov2;
+ procedure TestCov3;
+ end;
+
+procedure NotRun;
+begin
+ WriteLn('This line will never run');
+end;
+procedure UTCovTestTests.SetUp;
+begin
+end;
+
+procedure UTCovTestTests.TearDown;
+begin
+end;
+
+procedure UTCovTestTests.TestCov1;
+begin
+ {
+ Block comment lines
+ }
+ CheckEquals(1,2-1);
+end;
+
+procedure UTCovTestTests.TestCov2;
+var
+ i:DWORD;
+begin
+ for i := 0 to 1 do
+ WriteLn( IntToStr(i));
+ // Comment
+ CheckEquals(i,2);
+end;
+
+procedure UTCovTestTests.TestCov3;
+var
+ i : DWORD;
+begin
+ i := 0;
+ while i < 5 do
+ i := i+1;
+ CheckEquals(i,5);
+end;
+
+begin
+ UnitTest.addSuite(UTCovTestTests.Suite);
+end. \ No newline at end of file
diff --git a/Tests/Dependency/1/CMakeLists.txt b/Tests/Dependency/1/CMakeLists.txt
new file mode 100644
index 0000000..a8e74e4
--- /dev/null
+++ b/Tests/Dependency/1/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_library( One OneSrc.c )
+# This library has no dependencies
+target_link_libraries( One "" )
diff --git a/Tests/Dependency/1/OneSrc.c b/Tests/Dependency/1/OneSrc.c
new file mode 100644
index 0000000..9801c25
--- /dev/null
+++ b/Tests/Dependency/1/OneSrc.c
@@ -0,0 +1,3 @@
+void OneFunction()
+{
+}
diff --git a/Tests/Dependency/CMakeLists.txt b/Tests/Dependency/CMakeLists.txt
new file mode 100644
index 0000000..58d3fb7
--- /dev/null
+++ b/Tests/Dependency/CMakeLists.txt
@@ -0,0 +1,54 @@
+cmake_minimum_required (VERSION 2.8.12)
+project( Dependency )
+
+# to test directories with only one character One was changed to 1
+# There is one executable that depends on eight libraries. The
+# system has the following dependency graph:
+#
+# NoDepA:
+# NoDepB: NoDepA
+# NoDepC: NoDepA
+# 1:
+# Two: Three
+# Three: 1 Four
+# Four: 1 Two NoDepA
+# Five: Two
+# SixA: Two Five
+# SixB: Four Five
+# Seven: Two
+# Eight: Seven
+#
+# Exec: NoDepB NoDepC SixA SixB
+# Exec2: Eight Five
+# Exec3: Eight Five
+# Exec4: Five Two
+#
+# The libraries One,...,Eight have their dependencies explicitly
+# encoded. The libraries NoDepA,...,NoDepC do not.
+#
+# Although SixB does not depend on Two, there is a dependency listed
+# in the corresponding CMakeLists.txt just because of commands used.
+
+add_subdirectory(NoDepA)
+add_subdirectory(NoDepB)
+add_subdirectory(NoDepC)
+add_subdirectory(1)
+add_subdirectory(Two)
+add_subdirectory(Three)
+add_subdirectory(Four)
+add_subdirectory(Five)
+add_subdirectory(Six)
+add_subdirectory(Seven)
+add_subdirectory(Eight)
+add_subdirectory(Exec)
+add_subdirectory(Exec2)
+add_subdirectory(Exec3)
+add_subdirectory(Exec4)
+
+# Specific cases added to test fixes to problems found in real
+# projects.
+add_subdirectory(Case1)
+add_subdirectory(Case2)
+add_subdirectory(Case3)
+add_subdirectory(Case4)
+add_subdirectory(Case5)
diff --git a/Tests/Dependency/Case1/CMakeLists.txt b/Tests/Dependency/Case1/CMakeLists.txt
new file mode 100644
index 0000000..4c5fc20
--- /dev/null
+++ b/Tests/Dependency/Case1/CMakeLists.txt
@@ -0,0 +1,19 @@
+project(CASE1)
+
+# The old anaylize lib depends stuff in cmTarget gets this case wrong.
+# The cmComputeLinkDepends implementation gets it right.
+
+add_library(case1a STATIC a.c)
+
+add_library(case1b STATIC b.c b2.c)
+target_link_libraries(case1b case1a)
+
+add_library(case1c STATIC c.c c2.c)
+target_link_libraries(case1c case1b)
+
+add_library(case1d STATIC d.c)
+target_link_libraries(case1d case1c)
+
+add_executable(hello main.c)
+target_link_libraries(hello case1c case1b case1d case1c)
+
diff --git a/Tests/Dependency/Case1/a.c b/Tests/Dependency/Case1/a.c
new file mode 100644
index 0000000..262f523
--- /dev/null
+++ b/Tests/Dependency/Case1/a.c
@@ -0,0 +1,4 @@
+int a()
+{
+ return 5;
+}
diff --git a/Tests/Dependency/Case1/b.c b/Tests/Dependency/Case1/b.c
new file mode 100644
index 0000000..deda685
--- /dev/null
+++ b/Tests/Dependency/Case1/b.c
@@ -0,0 +1,6 @@
+extern int a();
+
+int b()
+{
+ return a() + 17;
+}
diff --git a/Tests/Dependency/Case1/b2.c b/Tests/Dependency/Case1/b2.c
new file mode 100644
index 0000000..f341da7
--- /dev/null
+++ b/Tests/Dependency/Case1/b2.c
@@ -0,0 +1,4 @@
+int b2()
+{
+ return 3;
+}
diff --git a/Tests/Dependency/Case1/c.c b/Tests/Dependency/Case1/c.c
new file mode 100644
index 0000000..a3ec162
--- /dev/null
+++ b/Tests/Dependency/Case1/c.c
@@ -0,0 +1,6 @@
+extern int b();
+
+int c()
+{
+ return b() + 42;
+}
diff --git a/Tests/Dependency/Case1/c2.c b/Tests/Dependency/Case1/c2.c
new file mode 100644
index 0000000..317bb0f
--- /dev/null
+++ b/Tests/Dependency/Case1/c2.c
@@ -0,0 +1,6 @@
+extern int b2();
+
+int c2()
+{
+ return b2() + 1;
+}
diff --git a/Tests/Dependency/Case1/d.c b/Tests/Dependency/Case1/d.c
new file mode 100644
index 0000000..f67aef7
--- /dev/null
+++ b/Tests/Dependency/Case1/d.c
@@ -0,0 +1,6 @@
+extern int c2();
+
+int d()
+{
+ return c2() + 2;
+}
diff --git a/Tests/Dependency/Case1/main.c b/Tests/Dependency/Case1/main.c
new file mode 100644
index 0000000..07191cc
--- /dev/null
+++ b/Tests/Dependency/Case1/main.c
@@ -0,0 +1,10 @@
+extern int b();
+extern int c();
+extern int d();
+
+int main()
+{
+ c();
+ b();
+ d();
+}
diff --git a/Tests/Dependency/Case2/CMakeLists.txt b/Tests/Dependency/Case2/CMakeLists.txt
new file mode 100644
index 0000000..21caaad
--- /dev/null
+++ b/Tests/Dependency/Case2/CMakeLists.txt
@@ -0,0 +1,22 @@
+project(CASE2 C)
+
+add_library(case2Foo1 STATIC foo1.c foo1b.c foo1c.c)
+add_library(case2Foo2 STATIC foo2.c foo2b.c foo2c.c)
+add_library(case2Foo3 STATIC foo3.c foo3b.c foo3c.c)
+target_link_libraries(case2Foo1 case2Foo2)
+target_link_libraries(case2Foo2 case2Foo3)
+target_link_libraries(case2Foo3 case2Foo1)
+set_property(TARGET case2Foo1 PROPERTY LINK_INTERFACE_MULTIPLICITY 3)
+
+add_library(case2Bar1 STATIC bar1.c)
+add_library(case2Bar2 STATIC bar2.c)
+add_library(case2Bar3 STATIC bar3.c)
+target_link_libraries(case2Bar1 case2Bar2 case2Foo1)
+target_link_libraries(case2Bar2 case2Bar3)
+target_link_libraries(case2Bar3 case2Bar1)
+
+add_executable(case2Zot zot.c)
+target_link_libraries(case2Zot case2Bar1)
+
+#set_property(GLOBAL PROPERTY GLOBAL_DEPENDS_DEBUG_MODE 1)
+#set(CMAKE_LINK_DEPENDS_DEBUG_MODE 1)
diff --git a/Tests/Dependency/Case2/bar1.c b/Tests/Dependency/Case2/bar1.c
new file mode 100644
index 0000000..6da9077
--- /dev/null
+++ b/Tests/Dependency/Case2/bar1.c
@@ -0,0 +1,10 @@
+extern int foo1();
+extern int bar2(void);
+int bar1(void)
+{
+ return bar2();
+}
+int bar1_from_bar3(void)
+{
+ return foo1();
+}
diff --git a/Tests/Dependency/Case2/bar2.c b/Tests/Dependency/Case2/bar2.c
new file mode 100644
index 0000000..00ed483
--- /dev/null
+++ b/Tests/Dependency/Case2/bar2.c
@@ -0,0 +1,5 @@
+extern int bar3(void);
+int bar2(void)
+{
+ return bar3();
+}
diff --git a/Tests/Dependency/Case2/bar3.c b/Tests/Dependency/Case2/bar3.c
new file mode 100644
index 0000000..a950899
--- /dev/null
+++ b/Tests/Dependency/Case2/bar3.c
@@ -0,0 +1,5 @@
+extern int bar1_from_bar3(void);
+int bar3(void)
+{
+ return bar1_from_bar3();
+}
diff --git a/Tests/Dependency/Case2/foo1.c b/Tests/Dependency/Case2/foo1.c
new file mode 100644
index 0000000..d476f2c
--- /dev/null
+++ b/Tests/Dependency/Case2/foo1.c
@@ -0,0 +1,5 @@
+extern int foo2(void);
+int foo1(void)
+{
+ return foo2();
+}
diff --git a/Tests/Dependency/Case2/foo1b.c b/Tests/Dependency/Case2/foo1b.c
new file mode 100644
index 0000000..e437014
--- /dev/null
+++ b/Tests/Dependency/Case2/foo1b.c
@@ -0,0 +1,5 @@
+extern int foo2b(void);
+int foo1b(void)
+{
+ return foo2b();
+}
diff --git a/Tests/Dependency/Case2/foo1c.c b/Tests/Dependency/Case2/foo1c.c
new file mode 100644
index 0000000..af03dec
--- /dev/null
+++ b/Tests/Dependency/Case2/foo1c.c
@@ -0,0 +1,5 @@
+extern int foo2c(void);
+int foo1c(void)
+{
+ return foo2c();
+}
diff --git a/Tests/Dependency/Case2/foo2.c b/Tests/Dependency/Case2/foo2.c
new file mode 100644
index 0000000..587c77a
--- /dev/null
+++ b/Tests/Dependency/Case2/foo2.c
@@ -0,0 +1,5 @@
+extern int foo3(void);
+int foo2(void)
+{
+ return foo3();
+}
diff --git a/Tests/Dependency/Case2/foo2b.c b/Tests/Dependency/Case2/foo2b.c
new file mode 100644
index 0000000..6959e63
--- /dev/null
+++ b/Tests/Dependency/Case2/foo2b.c
@@ -0,0 +1,5 @@
+extern int foo3b(void);
+int foo2b(void)
+{
+ return foo3b();
+}
diff --git a/Tests/Dependency/Case2/foo2c.c b/Tests/Dependency/Case2/foo2c.c
new file mode 100644
index 0000000..aedb61c
--- /dev/null
+++ b/Tests/Dependency/Case2/foo2c.c
@@ -0,0 +1,5 @@
+extern int foo3c(void);
+int foo2c(void)
+{
+ return foo3c();
+}
diff --git a/Tests/Dependency/Case2/foo3.c b/Tests/Dependency/Case2/foo3.c
new file mode 100644
index 0000000..cab9535
--- /dev/null
+++ b/Tests/Dependency/Case2/foo3.c
@@ -0,0 +1,5 @@
+extern int foo1b(void);
+int foo3(void)
+{
+ return foo1b();
+}
diff --git a/Tests/Dependency/Case2/foo3b.c b/Tests/Dependency/Case2/foo3b.c
new file mode 100644
index 0000000..69d2c8c
--- /dev/null
+++ b/Tests/Dependency/Case2/foo3b.c
@@ -0,0 +1,5 @@
+extern int foo1c(void);
+int foo3b(void)
+{
+ return foo1c();
+}
diff --git a/Tests/Dependency/Case2/foo3c.c b/Tests/Dependency/Case2/foo3c.c
new file mode 100644
index 0000000..e774495
--- /dev/null
+++ b/Tests/Dependency/Case2/foo3c.c
@@ -0,0 +1,4 @@
+int foo3c(void)
+{
+ return 0;
+}
diff --git a/Tests/Dependency/Case2/zot.c b/Tests/Dependency/Case2/zot.c
new file mode 100644
index 0000000..f25b493
--- /dev/null
+++ b/Tests/Dependency/Case2/zot.c
@@ -0,0 +1,5 @@
+extern int bar1(void);
+int main(void)
+{
+ return bar1();
+}
diff --git a/Tests/Dependency/Case3/CMakeLists.txt b/Tests/Dependency/Case3/CMakeLists.txt
new file mode 100644
index 0000000..f01dd05
--- /dev/null
+++ b/Tests/Dependency/Case3/CMakeLists.txt
@@ -0,0 +1,10 @@
+project(CASE3 C)
+
+add_library(case3Foo1 STATIC foo1.c foo1b.c)
+add_library(case3Foo2 STATIC foo2.c)
+
+add_executable(case3Bar bar.c)
+target_link_libraries(case3Bar case3Foo1 case3Foo2 case3Foo1)
+
+#set_property(GLOBAL PROPERTY GLOBAL_DEPENDS_DEBUG_MODE 1)
+#set(CMAKE_LINK_DEPENDS_DEBUG_MODE 1)
diff --git a/Tests/Dependency/Case3/bar.c b/Tests/Dependency/Case3/bar.c
new file mode 100644
index 0000000..62959c1
--- /dev/null
+++ b/Tests/Dependency/Case3/bar.c
@@ -0,0 +1,5 @@
+extern int foo1(void);
+int main(void)
+{
+ return foo1();
+}
diff --git a/Tests/Dependency/Case3/foo1.c b/Tests/Dependency/Case3/foo1.c
new file mode 100644
index 0000000..d476f2c
--- /dev/null
+++ b/Tests/Dependency/Case3/foo1.c
@@ -0,0 +1,5 @@
+extern int foo2(void);
+int foo1(void)
+{
+ return foo2();
+}
diff --git a/Tests/Dependency/Case3/foo1b.c b/Tests/Dependency/Case3/foo1b.c
new file mode 100644
index 0000000..84933af
--- /dev/null
+++ b/Tests/Dependency/Case3/foo1b.c
@@ -0,0 +1,4 @@
+int foo1b(void)
+{
+ return 0;
+}
diff --git a/Tests/Dependency/Case3/foo2.c b/Tests/Dependency/Case3/foo2.c
new file mode 100644
index 0000000..9bbb5d7
--- /dev/null
+++ b/Tests/Dependency/Case3/foo2.c
@@ -0,0 +1,5 @@
+extern int foo1b(void);
+int foo2(void)
+{
+ return foo1b();
+}
diff --git a/Tests/Dependency/Case4/CMakeLists.txt b/Tests/Dependency/Case4/CMakeLists.txt
new file mode 100644
index 0000000..a71049d
--- /dev/null
+++ b/Tests/Dependency/Case4/CMakeLists.txt
@@ -0,0 +1,19 @@
+project(CASE4 C)
+
+# This is not really a circular dependency. "case4Bar" refers to a
+# third-party library that happens to match the executable name, which
+# is okay when the executable is not a linkable target (ENABLE_EXPORTS
+# is not set). This tests whether CMake avoids incorrectly reporting
+# a circular dependency. In practice case4Foo may be a shared
+# library, but we skip that here because we do not want it to actually
+# have to find the third-party library.
+add_library(case4Foo STATIC foo.c)
+target_link_libraries(case4Foo case4Bar)
+
+# The executable avoids linking to a library with its own name, which
+# has been a CMake-ism for a long time, so we will not get a link
+# failure. An imported target or executable with an OUTPUT_NAME set
+# may be used if the user really wants to link a third-party library
+# into an executable of the same name.
+add_executable(case4Bar bar.c)
+target_link_libraries(case4Bar case4Foo)
diff --git a/Tests/Dependency/Case4/bar.c b/Tests/Dependency/Case4/bar.c
new file mode 100644
index 0000000..08092f9
--- /dev/null
+++ b/Tests/Dependency/Case4/bar.c
@@ -0,0 +1,5 @@
+extern int foo();
+int main()
+{
+ return foo();
+}
diff --git a/Tests/Dependency/Case4/foo.c b/Tests/Dependency/Case4/foo.c
new file mode 100644
index 0000000..e05eb7e
--- /dev/null
+++ b/Tests/Dependency/Case4/foo.c
@@ -0,0 +1,4 @@
+int foo()
+{
+ return 0;
+}
diff --git a/Tests/Dependency/Case5/CMakeLists.txt b/Tests/Dependency/Case5/CMakeLists.txt
new file mode 100644
index 0000000..e954b02
--- /dev/null
+++ b/Tests/Dependency/Case5/CMakeLists.txt
@@ -0,0 +1,8 @@
+project(CASE5 C)
+
+add_library(case5Foo SHARED foo.c)
+add_library(case5Bar STATIC bar.c)
+target_link_libraries(case5Bar case5Foo)
+
+add_executable(case5 main.c)
+target_link_libraries(case5 case5Foo case5Bar)
diff --git a/Tests/Dependency/Case5/bar.c b/Tests/Dependency/Case5/bar.c
new file mode 100644
index 0000000..fcbd135
--- /dev/null
+++ b/Tests/Dependency/Case5/bar.c
@@ -0,0 +1,12 @@
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+ void foo(void);
+
+#include <stdio.h>
+
+void bar(void)
+{
+ foo();
+ printf("bar()\n");
+}
diff --git a/Tests/Dependency/Case5/foo.c b/Tests/Dependency/Case5/foo.c
new file mode 100644
index 0000000..b82b7c2
--- /dev/null
+++ b/Tests/Dependency/Case5/foo.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ void foo(void)
+{
+ printf("foo()\n");
+}
diff --git a/Tests/Dependency/Case5/main.c b/Tests/Dependency/Case5/main.c
new file mode 100644
index 0000000..a967944
--- /dev/null
+++ b/Tests/Dependency/Case5/main.c
@@ -0,0 +1,7 @@
+void bar(void);
+
+int main(int argc, char* argv[])
+{
+ bar();
+ return 0;
+}
diff --git a/Tests/Dependency/Eight/CMakeLists.txt b/Tests/Dependency/Eight/CMakeLists.txt
new file mode 100644
index 0000000..db5e2df
--- /dev/null
+++ b/Tests/Dependency/Eight/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_library( Eight EightSrc.c )
+target_link_libraries( Eight Seven )
+
diff --git a/Tests/Dependency/Eight/EightSrc.c b/Tests/Dependency/Eight/EightSrc.c
new file mode 100644
index 0000000..7bfa481
--- /dev/null
+++ b/Tests/Dependency/Eight/EightSrc.c
@@ -0,0 +1,6 @@
+void SevenFunction();
+
+void EightFunction()
+{
+ SevenFunction();
+}
diff --git a/Tests/Dependency/Exec/CMakeLists.txt b/Tests/Dependency/Exec/CMakeLists.txt
new file mode 100644
index 0000000..a920685
--- /dev/null
+++ b/Tests/Dependency/Exec/CMakeLists.txt
@@ -0,0 +1,7 @@
+# This executable directly depends on NoDepB, NoDepC, SixA and SixB. However,
+# since NoDepB and NoDepC do not have explicit dependency information,
+# and they depend on NoDepA, we have to manually specify that dependency.
+link_libraries( NoDepB NoDepC NoDepA SixB SixA )
+
+add_executable( exec ExecMain.c )
+
diff --git a/Tests/Dependency/Exec/ExecMain.c b/Tests/Dependency/Exec/ExecMain.c
new file mode 100644
index 0000000..9572afd
--- /dev/null
+++ b/Tests/Dependency/Exec/ExecMain.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+
+void NoDepBFunction();
+void NoDepCFunction();
+void SixAFunction();
+void SixBFunction();
+
+int main()
+{
+ SixAFunction();
+ SixBFunction();
+ NoDepBFunction();
+ NoDepCFunction();
+
+ printf("Dependency test executable ran successfully.\n");
+
+ return 0;
+}
diff --git a/Tests/Dependency/Exec2/CMakeLists.txt b/Tests/Dependency/Exec2/CMakeLists.txt
new file mode 100644
index 0000000..04d6fe8
--- /dev/null
+++ b/Tests/Dependency/Exec2/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Here, Eight depends on Seven, which has the same dependencies as Five.
+# If the dependencies of Five are emitted, and then we attempt to emit the
+# dependencies of Seven, then we find that they have already been done. So:
+# Original line: Eight Five
+# Add deps of Five: Eight Five Two ... NoDepA
+# Now, we must make sure that Seven gets inserted between Five and Two, and
+# not at the end. Unfortunately, if we get it wrong, the test will only
+# fail on a platform where the link order makes a difference.
+link_libraries( Eight Five )
+
+add_executable( exec2 ExecMain.c )
+
diff --git a/Tests/Dependency/Exec2/ExecMain.c b/Tests/Dependency/Exec2/ExecMain.c
new file mode 100644
index 0000000..385cce1
--- /dev/null
+++ b/Tests/Dependency/Exec2/ExecMain.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+void FiveFunction();
+void EightFunction();
+
+int main()
+{
+ FiveFunction();
+ EightFunction();
+
+ printf("Dependency test executable ran successfully.\n");
+
+ return 0;
+}
diff --git a/Tests/Dependency/Exec3/CMakeLists.txt b/Tests/Dependency/Exec3/CMakeLists.txt
new file mode 100644
index 0000000..605fbc9
--- /dev/null
+++ b/Tests/Dependency/Exec3/CMakeLists.txt
@@ -0,0 +1,6 @@
+# Here, Five already has it's immediate dependency, Two satisfied. We must
+# make sure Two gets output anyway, because Eight indirectly depends on it.
+link_libraries( Five Two Eight Five )
+
+add_executable( exec3 ExecMain.c )
+
diff --git a/Tests/Dependency/Exec3/ExecMain.c b/Tests/Dependency/Exec3/ExecMain.c
new file mode 100644
index 0000000..385cce1
--- /dev/null
+++ b/Tests/Dependency/Exec3/ExecMain.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+void FiveFunction();
+void EightFunction();
+
+int main()
+{
+ FiveFunction();
+ EightFunction();
+
+ printf("Dependency test executable ran successfully.\n");
+
+ return 0;
+}
diff --git a/Tests/Dependency/Exec4/CMakeLists.txt b/Tests/Dependency/Exec4/CMakeLists.txt
new file mode 100644
index 0000000..94c6bf5
--- /dev/null
+++ b/Tests/Dependency/Exec4/CMakeLists.txt
@@ -0,0 +1,6 @@
+# Even though Five's dependency on Two is explicitly satisfied, Two
+# must be emitted again in order to satisfy a cyclic dependency on Three.
+link_libraries( Five Two Five )
+
+add_executable( exec4 ExecMain.c )
+
diff --git a/Tests/Dependency/Exec4/ExecMain.c b/Tests/Dependency/Exec4/ExecMain.c
new file mode 100644
index 0000000..0cfcce9
--- /dev/null
+++ b/Tests/Dependency/Exec4/ExecMain.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+void FiveFunction();
+void TwoFunction();
+
+int main()
+{
+ FiveFunction();
+ TwoFunction();
+
+ printf("Dependency test executable ran successfully.\n");
+
+ return 0;
+}
diff --git a/Tests/Dependency/Five/CMakeLists.txt b/Tests/Dependency/Five/CMakeLists.txt
new file mode 100644
index 0000000..19c1c77
--- /dev/null
+++ b/Tests/Dependency/Five/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_library( Five FiveSrc.c )
+target_link_libraries( Five Two )
+
diff --git a/Tests/Dependency/Five/FiveSrc.c b/Tests/Dependency/Five/FiveSrc.c
new file mode 100644
index 0000000..33d8ad7
--- /dev/null
+++ b/Tests/Dependency/Five/FiveSrc.c
@@ -0,0 +1,6 @@
+void TwoFunction();
+
+void FiveFunction()
+{
+ TwoFunction();
+}
diff --git a/Tests/Dependency/Four/CMakeLists.txt b/Tests/Dependency/Four/CMakeLists.txt
new file mode 100644
index 0000000..71c531f
--- /dev/null
+++ b/Tests/Dependency/Four/CMakeLists.txt
@@ -0,0 +1,6 @@
+include_directories(${Dependency_BINARY_DIR}/Two)
+add_library( Four FourSrc.c )
+target_link_libraries( Four One Two NoDepA )
+
+# TwoCustom must build before Four.
+add_dependencies(Four TwoCustom)
diff --git a/Tests/Dependency/Four/FourSrc.c b/Tests/Dependency/Four/FourSrc.c
new file mode 100644
index 0000000..4ea996d
--- /dev/null
+++ b/Tests/Dependency/Four/FourSrc.c
@@ -0,0 +1,15 @@
+#include <two-test.h> /* Requires TwoCustom to be built first. */
+void NoDepAFunction();
+void OneFunction();
+void TwoFunction();
+
+void FourFunction()
+{
+ static int count = 0;
+ if (count == 0) {
+ ++count;
+ TwoFunction();
+ }
+ OneFunction();
+ NoDepAFunction();
+}
diff --git a/Tests/Dependency/NoDepA/CMakeLists.txt b/Tests/Dependency/NoDepA/CMakeLists.txt
new file mode 100644
index 0000000..543402d
--- /dev/null
+++ b/Tests/Dependency/NoDepA/CMakeLists.txt
@@ -0,0 +1 @@
+add_library( NoDepA NoDepASrc.c )
diff --git a/Tests/Dependency/NoDepA/NoDepASrc.c b/Tests/Dependency/NoDepA/NoDepASrc.c
new file mode 100644
index 0000000..8c4072b
--- /dev/null
+++ b/Tests/Dependency/NoDepA/NoDepASrc.c
@@ -0,0 +1,3 @@
+void NoDepAFunction()
+{
+}
diff --git a/Tests/Dependency/NoDepB/CMakeLists.txt b/Tests/Dependency/NoDepB/CMakeLists.txt
new file mode 100644
index 0000000..1c70f37
--- /dev/null
+++ b/Tests/Dependency/NoDepB/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_library( NoDepB NoDepBSrc.c )
+# This library depends on NoDepA, but the
+# dependency is not explicitly specified.
diff --git a/Tests/Dependency/NoDepB/NoDepBSrc.c b/Tests/Dependency/NoDepB/NoDepBSrc.c
new file mode 100644
index 0000000..ddc71c5
--- /dev/null
+++ b/Tests/Dependency/NoDepB/NoDepBSrc.c
@@ -0,0 +1,6 @@
+void NoDepAFunction();
+
+void NoDepBFunction()
+{
+ NoDepAFunction();
+}
diff --git a/Tests/Dependency/NoDepC/CMakeLists.txt b/Tests/Dependency/NoDepC/CMakeLists.txt
new file mode 100644
index 0000000..dd41ceb
--- /dev/null
+++ b/Tests/Dependency/NoDepC/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_library( NoDepC NoDepCSrc.c )
+# This library depends on NoDepA, but the
+# dependency is not explicitly specified.
diff --git a/Tests/Dependency/NoDepC/NoDepCSrc.c b/Tests/Dependency/NoDepC/NoDepCSrc.c
new file mode 100644
index 0000000..b478c59
--- /dev/null
+++ b/Tests/Dependency/NoDepC/NoDepCSrc.c
@@ -0,0 +1,6 @@
+void NoDepAFunction();
+
+void NoDepCFunction()
+{
+ NoDepAFunction();
+}
diff --git a/Tests/Dependency/Seven/CMakeLists.txt b/Tests/Dependency/Seven/CMakeLists.txt
new file mode 100644
index 0000000..7fba55c
--- /dev/null
+++ b/Tests/Dependency/Seven/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_library( Seven SevenSrc.c )
+target_link_libraries( Seven Two )
+
diff --git a/Tests/Dependency/Seven/SevenSrc.c b/Tests/Dependency/Seven/SevenSrc.c
new file mode 100644
index 0000000..e1f3329
--- /dev/null
+++ b/Tests/Dependency/Seven/SevenSrc.c
@@ -0,0 +1,6 @@
+void TwoFunction();
+
+void SevenFunction()
+{
+ TwoFunction();
+}
diff --git a/Tests/Dependency/Six/CMakeLists.txt b/Tests/Dependency/Six/CMakeLists.txt
new file mode 100644
index 0000000..db12051
--- /dev/null
+++ b/Tests/Dependency/Six/CMakeLists.txt
@@ -0,0 +1,12 @@
+# In some projects, people don't use TARGET_LINK_LIBRARIES, but just
+# use an all-encompassing LINK_LIBRARIES. And sometimes they don't
+# specify them in the correct order.
+
+link_libraries( Two )
+link_libraries( Five )
+
+add_library( SixA SixASrc.c )
+
+add_library( SixB SixBSrc.c )
+target_link_libraries( SixB Four )
+
diff --git a/Tests/Dependency/Six/SixASrc.c b/Tests/Dependency/Six/SixASrc.c
new file mode 100644
index 0000000..7ea3711
--- /dev/null
+++ b/Tests/Dependency/Six/SixASrc.c
@@ -0,0 +1,8 @@
+void FiveFunction();
+void TwoFunction();
+
+void SixAFunction()
+{
+ FiveFunction();
+ TwoFunction();
+}
diff --git a/Tests/Dependency/Six/SixBSrc.c b/Tests/Dependency/Six/SixBSrc.c
new file mode 100644
index 0000000..92f9607
--- /dev/null
+++ b/Tests/Dependency/Six/SixBSrc.c
@@ -0,0 +1,10 @@
+void TwoFunction();
+void FiveFunction();
+void FourFunction();
+
+void SixBFunction()
+{
+ TwoFunction();
+ FiveFunction();
+ FourFunction();
+}
diff --git a/Tests/Dependency/Three/CMakeLists.txt b/Tests/Dependency/Three/CMakeLists.txt
new file mode 100644
index 0000000..3897f0c
--- /dev/null
+++ b/Tests/Dependency/Three/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_library( Three ThreeSrc.c )
+target_link_libraries( Three One Four )
+
diff --git a/Tests/Dependency/Three/ThreeSrc.c b/Tests/Dependency/Three/ThreeSrc.c
new file mode 100644
index 0000000..3e814f3
--- /dev/null
+++ b/Tests/Dependency/Three/ThreeSrc.c
@@ -0,0 +1,12 @@
+void OneFunction();
+void FourFunction();
+
+void ThreeFunction()
+{
+ static int count = 0;
+ if (count == 0) {
+ ++count;
+ FourFunction();
+ }
+ OneFunction();
+}
diff --git a/Tests/Dependency/Two/CMakeLists.txt b/Tests/Dependency/Two/CMakeLists.txt
new file mode 100644
index 0000000..19a0703
--- /dev/null
+++ b/Tests/Dependency/Two/CMakeLists.txt
@@ -0,0 +1,20 @@
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+add_library( Two TwoSrc.c )
+target_link_libraries( Two Three )
+
+# Setup a target to cause failure if Two does not depend on it or if
+# Two actually links to it. This will test that a utility dependency
+# on a library target works properly.
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/two-test.h
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_SOURCE_DIR}/two-test.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/two-test.h
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/two-test.h.in
+ )
+add_library( TwoCustom TwoCustomSrc.c ${CMAKE_CURRENT_BINARY_DIR}/two-test.h)
+set_target_properties(TwoCustom PROPERTIES EXCLUDE_FROM_ALL 1)
+target_link_libraries(TwoCustom Three)
+
+# Add a utility dependency to make sure it works without linking.
+add_dependencies(Two TwoCustom)
diff --git a/Tests/Dependency/Two/TwoCustomSrc.c b/Tests/Dependency/Two/TwoCustomSrc.c
new file mode 100644
index 0000000..ac31dcf
--- /dev/null
+++ b/Tests/Dependency/Two/TwoCustomSrc.c
@@ -0,0 +1,10 @@
+extern void NoFunction();
+
+/* Provide a function that is supposed to be found in the Three
+ library. If Two links to TwoCustom then TwoCustom will come before
+ Three and this symbol will be used. Since NoFunction is not
+ defined, that will cause a link failure. */
+void ThreeFunction()
+{
+ NoFunction();
+}
diff --git a/Tests/Dependency/Two/TwoSrc.c b/Tests/Dependency/Two/TwoSrc.c
new file mode 100644
index 0000000..dbdf524
--- /dev/null
+++ b/Tests/Dependency/Two/TwoSrc.c
@@ -0,0 +1,10 @@
+#include <two-test.h>
+
+void TwoFunction()
+{
+ static int count = 0;
+ if (count == 0) {
+ ++count;
+ ThreeFunction();
+ }
+}
diff --git a/Tests/Dependency/Two/two-test.h.in b/Tests/Dependency/Two/two-test.h.in
new file mode 100644
index 0000000..8c6a7f7
--- /dev/null
+++ b/Tests/Dependency/Two/two-test.h.in
@@ -0,0 +1 @@
+extern void ThreeFunction();
diff --git a/Tests/DoubleProject/CMakeLists.txt b/Tests/DoubleProject/CMakeLists.txt
new file mode 100644
index 0000000..02a6275
--- /dev/null
+++ b/Tests/DoubleProject/CMakeLists.txt
@@ -0,0 +1,3 @@
+project(dumb)
+project(dumber)
+add_executable(just_silly silly.c)
diff --git a/Tests/DoubleProject/silly.c b/Tests/DoubleProject/silly.c
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/DoubleProject/silly.c
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/EmptyDepends/CMakeLists.txt b/Tests/EmptyDepends/CMakeLists.txt
new file mode 100644
index 0000000..272eff7
--- /dev/null
+++ b/Tests/EmptyDepends/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(EmptyDepends)
+
+include(CTest)
+
+set(extra_dep)
+
+add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/qrc_my.cxx
+ COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/qrc_my.cxx"
+ DEPENDS "${extra_dep}" "${CMAKE_BINARY_DIR}/my.qrc")
+
+add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/my.qrc
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/my.qrc)
+
+add_library(qrc STATIC ${CMAKE_BINARY_DIR}/qrc_my.cxx)
diff --git a/Tests/EmptyLibrary/CMakeLists.txt b/Tests/EmptyLibrary/CMakeLists.txt
new file mode 100644
index 0000000..baddbbf
--- /dev/null
+++ b/Tests/EmptyLibrary/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.6)
+project(TestEmptyLibrary)
+
+add_subdirectory(subdir)
diff --git a/Tests/EmptyLibrary/subdir/CMakeLists.txt b/Tests/EmptyLibrary/subdir/CMakeLists.txt
new file mode 100644
index 0000000..e273f8d
--- /dev/null
+++ b/Tests/EmptyLibrary/subdir/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(test test.h)
diff --git a/Tests/EmptyLibrary/subdir/test.h b/Tests/EmptyLibrary/subdir/test.h
new file mode 100644
index 0000000..8511f53
--- /dev/null
+++ b/Tests/EmptyLibrary/subdir/test.h
@@ -0,0 +1 @@
+extern int dummy;
diff --git a/Tests/EmptyProperty/CMakeLists.txt b/Tests/EmptyProperty/CMakeLists.txt
new file mode 100644
index 0000000..39e75f3
--- /dev/null
+++ b/Tests/EmptyProperty/CMakeLists.txt
@@ -0,0 +1,9 @@
+project (EmptyProperty)
+
+set_property(DIRECTORY APPEND
+ PROPERTY
+ COMPILE_DEFINITIONS)
+
+include(CTest)
+
+add_executable(EmptyProperty EmptyProperty.cxx)
diff --git a/Tests/EmptyProperty/EmptyProperty.cxx b/Tests/EmptyProperty/EmptyProperty.cxx
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/EmptyProperty/EmptyProperty.cxx
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/EnforceConfig.cmake.in b/Tests/EnforceConfig.cmake.in
new file mode 100644
index 0000000..7781ded
--- /dev/null
+++ b/Tests/EnforceConfig.cmake.in
@@ -0,0 +1,38 @@
+# Choose a configuration with which to drive CTest tests.
+if(CTEST_CONFIGURATION_TYPE)
+ set(CTestTest_CONFIG "${CTEST_CONFIGURATION_TYPE}")
+else()
+ set(CTestTest_CONFIG "@CTestTest_CONFIG@")
+endif()
+
+# Choose a configuration that was built if none is given.
+if(NOT CTEST_CONFIGURATION_TYPE)
+ set(CTEST_CMD "@CMAKE_CTEST_COMMAND@@CMAKE_EXECUTABLE_SUFFIX@")
+ get_filename_component(CTEST_DIR "${CTEST_CMD}" PATH)
+ get_filename_component(CTEST_EXE "${CTEST_CMD}" NAME)
+ foreach(cfg Release Debug MinSizeRel RelWithDebInfo)
+ if(NOT CTEST_CONFIGURATION_TYPE)
+ if(EXISTS "${CTEST_DIR}/${cfg}/${CTEST_EXE}")
+ set(CTEST_CONFIGURATION_TYPE ${cfg})
+ endif()
+ endif()
+ endforeach()
+ if(NOT CTEST_CONFIGURATION_TYPE)
+ if("@CMAKE_C_COMPILER_ID@;@CMAKE_C_SIMULATE_ID@;@CMAKE_C_COMPILER_FRONTEND_VARIANT@" STREQUAL "Clang;MSVC;GNU")
+ # A valid configuration is required for this compiler in tests that do not set CMP0091 to NEW.
+ set(CTEST_CONFIGURATION_TYPE Debug)
+ else()
+ set(CTEST_CONFIGURATION_TYPE NoConfig)
+ endif()
+ endif()
+ message("Guessing configuration ${CTEST_CONFIGURATION_TYPE}")
+endif()
+
+# Isolate tests from user configuration in the environment.
+unset(ENV{CMAKE_GENERATOR})
+unset(ENV{CMAKE_GENERATOR_INSTANCE})
+unset(ENV{CMAKE_GENERATOR_PLATFORM})
+unset(ENV{CMAKE_GENERATOR_TOOLSET})
+unset(ENV{CMAKE_EXPORT_COMPILE_COMMANDS})
+
+@TEST_HOME_ENV_CODE@
diff --git a/Tests/Environment/CMakeLists.txt b/Tests/Environment/CMakeLists.txt
new file mode 100644
index 0000000..2b18d24
--- /dev/null
+++ b/Tests/Environment/CMakeLists.txt
@@ -0,0 +1,26 @@
+cmake_minimum_required(VERSION 2.6)
+project(EnvironmentProj)
+
+add_executable(Environment main.cxx)
+
+enable_testing()
+
+add_test(Environment1 Environment)
+add_test(Environment2 Environment)
+add_test(EchoEnvironment1 ${CMAKE_COMMAND} -E environment)
+add_test(EchoEnvironment2 ${CMAKE_COMMAND} -E environment)
+
+# Make sure "CMAKE_ENV.*Happy Thanksgiving" is in the output of
+# the "1" tests:
+#
+set_tests_properties(Environment1 EchoEnvironment1 PROPERTIES
+ ENVIRONMENT "CMAKE_ENVIRONMENT_TEST_VAR=Happy Thanksgiving!"
+ PASS_REGULAR_EXPRESSION "CMAKE_ENV.*Happy Thanksgiving"
+)
+
+# Make sure "CMAKE_ENV.*Happy Thanksgiving" is *NOT* in the output of
+# the "2" tests:
+#
+set_tests_properties(Environment2 EchoEnvironment2 PROPERTIES
+ FAIL_REGULAR_EXPRESSION "CMAKE_ENV.*Happy Thanksgiving"
+)
diff --git a/Tests/Environment/main.cxx b/Tests/Environment/main.cxx
new file mode 100644
index 0000000..55bc77f
--- /dev/null
+++ b/Tests/Environment/main.cxx
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char* argv[])
+{
+ char* var = getenv("CMAKE_ENVIRONMENT_TEST_VAR");
+ if (!var) {
+ var = "(null)";
+ }
+
+ fprintf(stdout, "Environment:\n");
+ fprintf(stdout, " CMAKE_ENVIRONMENT_TEST_VAR='%s'\n", var);
+
+ return 0;
+}
diff --git a/Tests/ExportImport/CMakeLists.txt b/Tests/ExportImport/CMakeLists.txt
new file mode 100644
index 0000000..d88eb11
--- /dev/null
+++ b/Tests/ExportImport/CMakeLists.txt
@@ -0,0 +1,83 @@
+cmake_minimum_required (VERSION 3.9)
+project(ExportImport C CXX)
+if(NOT DEFINED CMake_TEST_NESTED_MAKE_PROGRAM AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(CMake_TEST_NESTED_MAKE_PROGRAM "${CMAKE_MAKE_PROGRAM}")
+endif()
+
+# Wipe out the install tree to make sure the exporter works.
+add_custom_command(
+ OUTPUT ${ExportImport_BINARY_DIR}/CleanupProject
+ COMMAND ${CMAKE_COMMAND} -E rm -rf ${ExportImport_BINARY_DIR}/Root
+ )
+add_custom_target(CleanupTarget ALL DEPENDS ${ExportImport_BINARY_DIR}/CleanupProject)
+set_property(
+ SOURCE ${ExportImport_BINARY_DIR}/CleanupProject
+ PROPERTY SYMBOLIC 1
+ )
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ set(NESTED_CONFIG_TYPE -C "${CMAKE_CFG_INTDIR}")
+else()
+ if(CMAKE_BUILD_TYPE)
+ set(NESTED_CONFIG_TYPE -C "${CMAKE_BUILD_TYPE}")
+ else()
+ set(NESTED_CONFIG_TYPE)
+ endif()
+endif()
+
+if(MINGW OR MSYS)
+ # Test CMAKE_GNUtoMS whether we have VS or not.
+ set(ExportImport_GNUtoMS 1)
+endif()
+
+configure_file(${ExportImport_SOURCE_DIR}/InitialCache.cmake.in
+ ${ExportImport_BINARY_DIR}/InitialCache.cmake @ONLY)
+
+# Build and install the exporter.
+add_custom_command(
+ OUTPUT ${ExportImport_BINARY_DIR}/ExportProject
+ COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+ --build-and-test
+ ${ExportImport_SOURCE_DIR}/Export
+ ${ExportImport_BINARY_DIR}/Export
+ --build-noclean
+ --build-project Export
+ --build-target install
+ --build-generator ${CMAKE_GENERATOR}
+ --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+ --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+ --build-options -C${ExportImport_BINARY_DIR}/InitialCache.cmake
+ VERBATIM
+ )
+add_custom_target(ExportTarget ALL DEPENDS ${ExportImport_BINARY_DIR}/ExportProject)
+add_dependencies(ExportTarget CleanupTarget)
+set_property(
+ SOURCE ${ExportImport_BINARY_DIR}/ExportProject
+ PROPERTY SYMBOLIC 1
+ )
+
+# Build and install the importer.
+add_custom_command(
+ OUTPUT ${ExportImport_BINARY_DIR}/ImportProject
+ COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+ --build-and-test
+ ${ExportImport_SOURCE_DIR}/Import
+ ${ExportImport_BINARY_DIR}/Import
+ --build-noclean
+ --build-project Import
+ --build-generator ${CMAKE_GENERATOR}
+ --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+ --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+ --build-options -C${ExportImport_BINARY_DIR}/InitialCache.cmake
+ VERBATIM
+ )
+add_custom_target(ImportTarget ALL DEPENDS ${ExportImport_BINARY_DIR}/ImportProject)
+add_dependencies(ImportTarget ExportTarget)
+set_property(
+ SOURCE ${ExportImport_BINARY_DIR}/ImportProject
+ PROPERTY SYMBOLIC 1
+ )
+
+add_executable(ExportImport main.c)
+add_dependencies(ExportImport ImportTarget)
diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt
new file mode 100644
index 0000000..6d9b4ab
--- /dev/null
+++ b/Tests/ExportImport/Export/CMakeLists.txt
@@ -0,0 +1,686 @@
+cmake_minimum_required (VERSION 2.7.20090711)
+project(Export C CXX)
+
+# Pretend that RelWithDebInfo should link to debug libraries to test
+# the DEBUG_CONFIGURATIONS property.
+set_property(GLOBAL PROPERTY DEBUG_CONFIGURATIONS Debug RelWithDebInfo)
+
+add_library(testExe1lib STATIC testExe1lib.c) # not exported
+add_executable(testExe1 testExe1.c)
+target_link_libraries(testExe1 testExe1lib)
+set_property(TARGET testExe1 PROPERTY VERSION 4)
+
+add_library(testExe2libImp SHARED testExe2libImp.c)
+set_property(TARGET testExe2libImp PROPERTY LIBRARY_OUTPUT_DIRECTORY impl)
+add_library(testExe2lib SHARED testExe2lib.c)
+target_link_libraries(testExe2lib testExe2libImp)
+set_property(TARGET testExe2lib PROPERTY LINK_INTERFACE_LIBRARIES "")
+add_executable(testExe2 testExe2.c)
+set_property(TARGET testExe2 PROPERTY ENABLE_EXPORTS 1)
+set_property(TARGET testExe2 PROPERTY LINK_INTERFACE_LIBRARIES testExe2lib)
+
+add_library(testLib1 STATIC testLib1.c)
+add_library(testLib2 STATIC testLib2.c)
+target_link_libraries(testLib2 testLib1)
+
+# Test install(FILES) with generator expressions referencing testLib1.
+add_custom_command(TARGET testLib1 POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:testLib1>
+ $<TARGET_FILE:testLib1>.genex
+ )
+install(FILES $<TARGET_FILE:testLib1>.genex
+ DESTINATION $<1:lib>$<0:/wrong>
+ )
+set_property(TARGET testLib1 PROPERTY MY_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/testLib1file1.txt
+ ${CMAKE_CURRENT_SOURCE_DIR}/testLib1file2.txt
+ )
+install(FILES $<TARGET_PROPERTY:testLib1,MY_FILES>
+ DESTINATION $<1:doc>$<0:/wrong>
+ )
+
+# Test library with empty link interface. Link it to an implementation
+# dependency that itself links to dependencies publicly.
+add_library(testLib3ImpDep SHARED testLib3ImpDep.c)
+set_property(TARGET testLib3ImpDep PROPERTY LIBRARY_OUTPUT_DIRECTORY impl/dep)
+add_library(testLib3Imp SHARED testLib3Imp.c)
+set_property(TARGET testLib3Imp PROPERTY LIBRARY_OUTPUT_DIRECTORY impl)
+target_link_libraries(testLib3Imp testLib3ImpDep)
+add_library(testLib3 SHARED testLib3.c)
+target_link_libraries(testLib3 testLib3Imp)
+set_property(TARGET testLib3 PROPERTY LINK_INTERFACE_LIBRARIES "")
+set_property(TARGET testLib3 PROPERTY VERSION 1.2)
+set_property(TARGET testLib3 PROPERTY SOVERSION 3)
+
+# Test <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME[_<CONFIG>] properties.
+set_property(TARGET testLib3 PROPERTY RUNTIME_OUTPUT_NAME_DEBUG testLib3dll-d)
+set_property(TARGET testLib3 PROPERTY RUNTIME_OUTPUT_NAME_RELEASE testLib3dll-r)
+set_property(TARGET testLib3 PROPERTY RUNTIME_OUTPUT_NAME testLib3dll)
+set_property(TARGET testLib3 PROPERTY LIBRARY_OUTPUT_NAME_DEBUG testLib3lib-d)
+set_property(TARGET testLib3 PROPERTY LIBRARY_OUTPUT_NAME_RELEASE testLib3lib-r)
+set_property(TARGET testLib3 PROPERTY LIBRARY_OUTPUT_NAME testLib3lib)
+set_property(TARGET testLib3 PROPERTY ARCHIVE_OUTPUT_NAME testLib3import)
+
+add_library(testLib4 SHARED testLib4.c)
+set_property(TARGET testLib4 PROPERTY FRAMEWORK 1)
+
+add_library(testLib5 SHARED testLib5.c)
+
+add_library(testLib6 STATIC testLib6.cxx testLib6c.c)
+
+add_library(testLibPerConfigDest STATIC testLibPerConfigDest.c)
+install(TARGETS testLibPerConfigDest EXPORT exp
+ DESTINATION lib/$<$<BOOL:$<CONFIG>>:$<CONFIG>>$<$<NOT:$<BOOL:$<CONFIG>>>:NoConfig>
+ )
+
+# Test OUTPUT_NAME properties with generator expressions
+add_library(testLib7 STATIC testLib7.c)
+set_property(TARGET testLib7 PROPERTY OUTPUT_NAME_DEBUG testLib7D-$<CONFIG>)
+set_property(TARGET testLib7 PROPERTY OUTPUT_NAME_RELEASE testLib7R-$<CONFIG>)
+set_property(TARGET testLib7 PROPERTY OUTPUT_NAME testLib7-$<CONFIG>)
+
+# Test exporting OBJECT targets
+add_library(testLib8 OBJECT testLib8A.c testLib8B.c sub/testLib8C.c)
+
+if(NOT CMAKE_GENERATOR STREQUAL "Xcode" OR NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;$]")
+ set(maybe_OBJECTS_DESTINATION OBJECTS DESTINATION $<1:lib>)
+else()
+ set(maybe_OBJECTS_DESTINATION "")
+endif()
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0022 NEW)
+add_library(testLib9ObjPub OBJECT testLib9ObjPub.c)
+target_compile_definitions(testLib9ObjPub INTERFACE testLib9ObjPub_USED)
+add_library(testLib9ObjPriv OBJECT testLib9ObjPriv.c)
+target_compile_definitions(testLib9ObjPriv INTERFACE testLib9ObjPriv_USED)
+add_library(testLib9ObjIface OBJECT testLib9ObjIface.c)
+target_compile_definitions(testLib9ObjIface INTERFACE testLib9ObjIface_USED)
+add_library(testLib9 STATIC testLib9.c)
+target_link_libraries(testLib9 INTERFACE testLib9ObjIface PUBLIC testLib9ObjPub PRIVATE testLib9ObjPriv)
+cmake_policy(POP)
+
+# Test using the target_link_libraries command to set the
+# LINK_INTERFACE_LIBRARIES* properties. We construct two libraries
+# providing the same two symbols. In each library one of the symbols
+# will work and the other one will fail to link. The import part of
+# this test will try to use the symbol corresponding to the
+# configuration in which it is built. If the proper library is not
+# used via the link interface the import test will fail to link.
+add_library(testLib4lib STATIC testLib4lib.c)
+add_library(testLib4libdbg STATIC testLib4libopt.c testLib4libdbg.c)
+add_library(testLib4libopt STATIC testLib4libdbg.c testLib4libopt.c)
+set_property(TARGET testLib4libdbg PROPERTY COMPILE_DEFINITIONS LIB_DBG)
+set_property(TARGET testLib4libopt PROPERTY COMPILE_DEFINITIONS LIB_OPT)
+target_link_libraries(testLib4
+ LINK_INTERFACE_LIBRARIES
+ testLib4lib debug testLib4libdbg optimized testLib4libopt
+ )
+
+add_executable(testExe3 testExe3.c)
+set_property(TARGET testExe3 PROPERTY MACOSX_BUNDLE 1)
+
+# Test <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_DIRECTORY[_<CONFIG>] properties with generator expressions
+add_executable(testExe4 testExe4.c)
+target_link_libraries(testExe4 testExe1lib)
+set_property(TARGET testLib7 PROPERTY ARCHIVE_OUTPUT_DIRECTORY_DEBUG testLib7D-$<CONFIG>)
+set_property(TARGET testLib7 PROPERTY ARCHIVE_OUTPUT_DIRECTORY_RELEASE testLib7R-$<CONFIG>)
+set_property(TARGET testLib7 PROPERTY ARCHIVE_OUTPUT_DIRECTORY testLib7-$<CONFIG>)
+set_property(TARGET testLib5 PROPERTY LIBRARY_OUTPUT_DIRECTORY_DEBUG testLib5D-$<CONFIG>)
+set_property(TARGET testLib5 PROPERTY LIBRARY_OUTPUT_DIRECTORY_RELEASE testLib5R-$<CONFIG>)
+set_property(TARGET testLib5 PROPERTY LIBRARY_OUTPUT_DIRECTORY testLib5-$<CONFIG>)
+set_property(TARGET testExe4 PROPERTY RUNTIME_OUTPUT_DIRECTORY_DEBUG testExe4D-$<CONFIG>)
+set_property(TARGET testExe4 PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE testExe4R-$<CONFIG>)
+set_property(TARGET testExe4 PROPERTY RUNTIME_OUTPUT_DIRECTORY testExe4-$<CONFIG>)
+
+# Test cyclic dependencies.
+add_library(testLibCycleA STATIC
+ testLibCycleA1.c testLibCycleA2.c testLibCycleA3.c)
+add_library(testLibCycleB STATIC
+ testLibCycleB1.c testLibCycleB2.c testLibCycleB3.c)
+target_link_libraries(testLibCycleA testLibCycleB)
+target_link_libraries(testLibCycleB testLibCycleA)
+set_property(TARGET testLibCycleA PROPERTY LINK_INTERFACE_MULTIPLICITY 3)
+
+add_library(testLibNoSONAME SHARED testLibNoSONAME.c)
+set_property(TARGET testLibNoSONAME PROPERTY NO_SONAME 1)
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0022 NEW)
+# Test exporting dependent libraries into different exports
+add_library(testLibRequired testLibRequired.c)
+add_library(testLibDepends testLibDepends.c)
+target_link_libraries(testLibDepends LINK_PUBLIC testLibRequired)
+add_library(testStaticLibRequiredPrivate testStaticLibRequiredPrivate.c)
+target_link_libraries(testLibDepends PRIVATE testStaticLibRequiredPrivate)
+cmake_policy(POP)
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0022 NEW)
+cmake_policy(SET CMP0079 NEW)
+add_library(TopDirLib STATIC testTopDirLib.c)
+add_subdirectory(SubDirLinkA)
+add_subdirectory(SubDirLinkB)
+cmake_policy(POP)
+
+macro(add_include_lib _libName)
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_libName}.c" "/* no content */\n")
+ add_library(${_libName} "${CMAKE_CURRENT_BINARY_DIR}/${_libName}.c")
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${_libName}")
+ set_property(TARGET ${_libName} APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/${_libName}>"
+ )
+ if (NOT "${ARGV1}" STREQUAL "NO_HEADER")
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_libName}/${_libName}.h" "/* no content */\n")
+ install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/${_libName}/${_libName}.h"
+ DESTINATION include/${_libName}
+ )
+ endif()
+endmacro()
+
+add_include_lib(testLibIncludeRequired1)
+add_include_lib(testLibIncludeRequired2)
+add_include_lib(testLibIncludeRequired3 NO_HEADER)
+# Generate testLibIncludeRequired4 in the testLibIncludeRequired3 directory
+# with an error. If the includes from testLibIncludeRequired3 appear first,
+# the error will be hit.
+# Below, the '3' library appears before the '4' library
+# but we are testing that the INSTALL_INTERFACE causes it not to be used
+# at build time.
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/testLibIncludeRequired3/testLibIncludeRequired4.h" "#error Should not be included\n")
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/testLibIncludeRequired3/testLibIncludeRequired4.h"
+ DESTINATION include/testLibIncludeRequired3
+)
+add_include_lib(testLibIncludeRequired4)
+add_include_lib(testLibIncludeRequired5 NO_HEADER)
+# Generate testLibIncludeRequired6 in the testLibIncludeRequired5 directory
+# with an error. If the includes from testLibIncludeRequired5 appear first,
+# the error will be hit.
+# Below, the '5' library appears before the '6' library
+# but we are testing that when the installed IMPORTED target is used, from
+# the Import side of this unit test, the '6' include from the '5' directory
+# will not be used because it is in the BUILD_INTERFACE only.
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/testLibIncludeRequired5/testLibIncludeRequired6.h" "#error Should not be included\n")
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/testLibIncludeRequired5/testLibIncludeRequired6.h"
+ DESTINATION include/testLibIncludeRequired5
+)
+add_include_lib(testLibIncludeRequired6)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/testLibIncludeRequired7/testLibIncludeRequired7.h" "/* No content */\n")
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/testLibIncludeRequired7/testLibIncludeRequired7.h"
+ DESTINATION include/testLibIncludeRequired7
+)
+
+set_property(TARGET testLibRequired APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES
+ $<TARGET_PROPERTY:testLibIncludeRequired1,INTERFACE_INCLUDE_DIRECTORIES>
+ $<TARGET_PROPERTY:$<1:$<TARGET_NAME:testLibIncludeRequired2>>,INTERFACE_INCLUDE_DIRECTORIES>
+ $<INSTALL_INTERFACE:$<TARGET_PROPERTY:testLibIncludeRequired3,INTERFACE_INCLUDE_DIRECTORIES>>
+ $<BUILD_INTERFACE:$<TARGET_PROPERTY:testLibIncludeRequired4,INTERFACE_INCLUDE_DIRECTORIES>>
+ $<BUILD_INTERFACE:$<TARGET_PROPERTY:testLibIncludeRequired5,INTERFACE_INCLUDE_DIRECTORIES>>
+ $<INSTALL_INTERFACE:$<TARGET_PROPERTY:testLibIncludeRequired6,INTERFACE_INCLUDE_DIRECTORIES>>
+ # The BUILD_INTERFACE entry from above is duplicated below. This is to test that
+ # the INSTALL_INTERFACE entry bound by a BUILD_INTERFACE entry on either side is
+ # preprocessed correctly on install(EXPORT).
+ $<BUILD_INTERFACE:$<TARGET_PROPERTY:testLibIncludeRequired5,INTERFACE_INCLUDE_DIRECTORIES>>
+ # Test that the below is non-fatal
+ $<$<STREQUAL:one,two>:$<TARGET_PROPERTY:not_a_target,INTERFACE_INCLUDE_DIRECTORIES>>
+ $<INSTALL_INTERFACE:include/testLibIncludeRequired7;include/testLibIncludeRequired4>
+)
+
+set_property(TARGET testLibRequired APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS
+ testLibRequired_IFACE_DEFINE
+ $<BUILD_INTERFACE:BuildOnly_DEFINE>
+ $<INSTALL_INTERFACE:InstallOnly_DEFINE>
+)
+include(GenerateExportHeader)
+
+# Test deprecation of imported library
+add_library(testLibDeprecation STATIC testLib1.c)
+set_property(TARGET testLibDeprecation PROPERTY DEPRECATION "Deprecated version. Please use latest version")
+
+add_subdirectory(renamed)
+
+add_library(testSharedLibRequired SHARED testSharedLibRequired.cpp)
+generate_export_header(testSharedLibRequired)
+set_property(TARGET testSharedLibRequired
+ PROPERTY
+ INTERFACE_POSITION_INDEPENDENT_CODE ON
+)
+set_property(TARGET testSharedLibRequired APPEND PROPERTY
+ INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}"
+)
+install(FILES
+ "${CMAKE_CURRENT_SOURCE_DIR}/testSharedLibRequired.h"
+ "${CMAKE_CURRENT_BINARY_DIR}/testsharedlibrequired_export.h"
+ DESTINATION include/testSharedLibRequired
+)
+set_property(TARGET testSharedLibRequired APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}>"
+)
+set_property(TARGET testSharedLibRequired APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS USING_TESTSHAREDLIBREQUIRED
+)
+set_property(TARGET testSharedLibRequired
+ APPEND PROPERTY
+ COMPATIBLE_INTERFACE_BOOL CUSTOM_PROP
+)
+set_property(TARGET testSharedLibRequired
+ PROPERTY
+ INTERFACE_CUSTOM_PROP ON
+)
+set_property(TARGET testSharedLibRequired
+ APPEND PROPERTY
+ COMPATIBLE_INTERFACE_STRING CUSTOM_STRING
+)
+set_property(TARGET testSharedLibRequired
+ PROPERTY
+ INTERFACE_CUSTOM_STRING testcontent
+)
+set_property(TARGET testSharedLibRequired APPEND PROPERTY
+ INTERFACE_COMPILE_OPTIONS
+ $<$<CXX_COMPILER_ID:GNU>:-DCUSTOM_COMPILE_OPTION>
+)
+
+add_library(testSharedLibRequiredUser SHARED testSharedLibRequiredUser.cpp)
+generate_export_header(testSharedLibRequiredUser)
+# LINK_PRIVATE so that it appears in the LINK_DEPENDENT_LIBRARIES, but not
+# the INTERFACE_LINK_LIBRARIES.
+set_property(TARGET testSharedLibRequiredUser APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}>"
+)
+target_link_libraries(testSharedLibRequiredUser LINK_PRIVATE testSharedLibRequired)
+install(FILES
+ "${CMAKE_CURRENT_SOURCE_DIR}/testSharedLibRequiredUser.h"
+ "${CMAKE_CURRENT_BINARY_DIR}/testsharedlibrequireduser_export.h"
+ DESTINATION include/testSharedLibRequiredUser
+)
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0022 NEW)
+add_library(testSharedLibRequiredUser2 SHARED testSharedLibRequiredUser2.cpp)
+generate_export_header(testSharedLibRequiredUser2)
+set_property(TARGET testSharedLibRequiredUser2 APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}>"
+)
+set_property(TARGET testSharedLibRequiredUser2 PROPERTY LINK_LIBRARIES testSharedLibRequired)
+set_property(TARGET testSharedLibRequiredUser2 PROPERTY INTERFACE_LINK_LIBRARIES testSharedLibRequired)
+install(FILES
+ "${CMAKE_CURRENT_SOURCE_DIR}/testSharedLibRequiredUser2.h"
+ "${CMAKE_CURRENT_BINARY_DIR}/testsharedlibrequireduser2_export.h"
+ DESTINATION include/testSharedLibRequiredUser2
+)
+cmake_policy(POP)
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0041 NEW)
+add_library(testSharedLibDepends SHARED testSharedLibDepends.cpp)
+set_property(TARGET testSharedLibDepends APPEND PROPERTY
+ INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}"
+)
+generate_export_header(testSharedLibDepends)
+
+set_property(TARGET testSharedLibDepends APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES
+ $<TARGET_PROPERTY:testSharedLibRequired,INTERFACE_INCLUDE_DIRECTORIES>
+)
+install(FILES
+ "${CMAKE_CURRENT_SOURCE_DIR}/testSharedLibDepends.h"
+ "${CMAKE_CURRENT_BINARY_DIR}/testsharedlibdepends_export.h"
+ DESTINATION include/testSharedLibDepends
+)
+set_property(TARGET testSharedLibDepends APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/$<1:include>/testSharedLibDepends>"
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}>"
+)
+cmake_policy(POP)
+
+# LINK_PRIVATE because the LINK_INTERFACE_LIBRARIES is specified above.
+target_link_libraries(testSharedLibDepends LINK_PRIVATE testSharedLibRequired)
+target_link_libraries(testSharedLibDepends LINK_PUBLIC renamed_on_export)
+target_link_libraries(testSharedLibDepends LINK_INTERFACE_LIBRARIES
+ $<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:$<TARGET_NAME:testSharedLibRequired>>)
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0022 OLD)
+add_library(cmp0022OLD SHARED cmp0022_vs6_1.cpp)
+generate_export_header(cmp0022OLD BASE_NAME cmp0022)
+target_include_directories(cmp0022OLD PUBLIC
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}>"
+ "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include/cmp0022>"
+)
+cmake_policy(SET CMP0022 NEW)
+add_library(cmp0022NEW SHARED cmp0022_vs6_1.cpp)
+set_property(TARGET cmp0022NEW PROPERTY DEFINE_SYMBOL cmp0022OLD_EXPORTS)
+target_include_directories(cmp0022NEW PUBLIC
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}>"
+ "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include/cmp0022>"
+)
+cmake_policy(POP)
+install(FILES
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmp0022.h"
+ "${CMAKE_CURRENT_BINARY_DIR}/cmp0022_export.h"
+ DESTINATION include/cmp0022
+)
+
+set_property(TARGET testLib2 APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS USING_TESTLIB2)
+set_property(TARGET testLib3 APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS USING_TESTLIB3)
+set_target_properties(testLib3 PROPERTIES
+ EXPORT_PROPERTIES "EXPORTED_PROPERTY1"
+ EXPORTED_PROPERTY1 "EXPORTING_TESTLIB3")
+set_target_properties(testLib4 PROPERTIES
+ EXPORTED_PROPERTY2 "EXPORTING_TESTLIB4_1"
+ EXPORTED_PROPERTY3 "EXPORTING_TESTLIB4_2")
+set_property(TARGET testLib4 PROPERTY
+ EXPORT_PROPERTIES EXPORTED_PROPERTY2 EXPORTED_PROPERTY3)
+
+set_property(TARGET cmp0022NEW APPEND PROPERTY INTERFACE_LINK_LIBRARIES testLib2)
+# set_property(TARGET cmp0022NEW APPEND PROPERTY LINK_INTERFACE_LIBRARIES testLibIncludeRequired2) # TODO: Test for error
+set_property(TARGET cmp0022OLD APPEND PROPERTY INTERFACE_LINK_LIBRARIES testLib2)
+set_property(TARGET cmp0022OLD APPEND PROPERTY LINK_INTERFACE_LIBRARIES testLib3)
+
+add_library(noIncludesInterface empty.cpp)
+
+add_library(systemlib SHARED systemlib.cpp)
+install(FILES systemlib.h DESTINATION include/systemlib)
+target_include_directories(systemlib
+ INTERFACE
+ $<INSTALL_INTERFACE:include/systemlib>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+)
+
+install(TARGETS testLibRequired
+ EXPORT RequiredExp DESTINATION lib
+ INCLUDES DESTINATION
+ installIncludesTest
+ $<INSTALL_PREFIX>/installIncludesTest2
+ installIncludesTest3/$<TARGET_PROPERTY:NAME>
+ $<TARGET_PROPERTY:NAME>/installIncludesTest4
+ $<INSTALL_INTERFACE:installIncludesTest5$<0:>>
+ $<INSTALL_INTERFACE:$<0:>installIncludesTest6>
+ $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/installIncludesTest7>
+)
+
+target_include_directories(testLibRequired INTERFACE
+ # These can't be in the above install(INCLUDES DESTINATION call because
+ # that is only for installed interfaces. These directories are prefixes
+ # in the build dir, which is an error for the installed interface.
+ # We add them here so that we don't have to add conditions in the Import
+ # component of the test.
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest5$<0:>>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/$<0:>installIncludesTest6>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest7>
+ $<INSTALL_INTERFACE:installIncludesTest8/$<0:>>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest8$<0:>>
+)
+install(TARGETS
+ testLibIncludeRequired1
+ testLibIncludeRequired2
+ testLibIncludeRequired3
+ testLibIncludeRequired4
+ testLibIncludeRequired5
+ testLibIncludeRequired6
+ testSharedLibRequired
+ testSharedLibRequiredUser
+ testSharedLibRequiredUser2
+ noIncludesInterface
+ EXPORT RequiredExp DESTINATION lib
+ INCLUDES DESTINATION
+ $<INSTALL_PREFIX>/include/$<TARGET_PROPERTY:NAME>
+)
+install(TARGETS
+ testStaticLibRequiredPrivate
+ EXPORT RequiredExp DESTINATION lib
+)
+install(EXPORT RequiredExp NAMESPACE Req:: FILE testLibRequiredTargets.cmake DESTINATION lib/cmake/testLibRequired)
+
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest/installIncludesTest.h" "/* No content */\n")
+
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest2")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest2/installIncludesTest2.h" "/* No content */\n")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest3/testLibRequired")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest3/testLibRequired/installIncludesTest3.h" "/* No content */\n")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/testLibRequired/installIncludesTest4")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/testLibRequired/installIncludesTest4/installIncludesTest4.h" "/* No content */\n")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest5")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest5/installIncludesTest5.h" "/* No content */\n")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest6")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest6/installIncludesTest6.h" "/* No content */\n")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest7")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest7/installIncludesTest7.h" "/* No content */\n")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest8")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest8/installIncludesTest8.h" "/* No content */\n")
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest/installIncludesTest.h"
+ DESTINATION installIncludesTest
+)
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest2/installIncludesTest2.h"
+ DESTINATION installIncludesTest2
+)
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest3/testLibRequired/installIncludesTest3.h"
+ DESTINATION installIncludesTest3/testLibRequired
+)
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/testLibRequired/installIncludesTest4/installIncludesTest4.h"
+ DESTINATION testLibRequired/installIncludesTest4
+)
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest5/installIncludesTest5.h"
+ DESTINATION installIncludesTest5
+)
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest6/installIncludesTest6.h"
+ DESTINATION installIncludesTest6
+)
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest7/installIncludesTest7.h"
+ DESTINATION installIncludesTest7
+)
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest8/installIncludesTest8.h"
+ DESTINATION installIncludesTest8
+)
+
+install(TARGETS testLibDepends testSharedLibDepends EXPORT DependsExp DESTINATION lib )
+install(EXPORT DependsExp FILE testLibDependsTargets.cmake DESTINATION lib/cmake/testLibDepends)
+
+file(WRITE
+ "${CMAKE_CURRENT_BINARY_DIR}/testLibRequiredConfig.cmake"
+ "
+if(\${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION VERSION_LESS 2.3 AND NOT \${CMAKE_FIND_PACKAGE_NAME}_INTERFACES)
+ set(\${CMAKE_FIND_PACKAGE_NAME}_NO_INTERFACES 1)
+endif()
+include(\"\${CMAKE_CURRENT_LIST_DIR}/testLibRequiredTargets.cmake\")
+set(\${CMAKE_FIND_PACKAGE_NAME}_INCLUDE_DIRS \"${CMAKE_CURRENT_BINARY_DIR}\" \"${CMAKE_CURRENT_SOURCE_DIR}\" )
+"
+)
+
+include(CMakePackageConfigHelpers)
+write_basic_package_version_file( testLibRequiredConfigVersion.cmake VERSION 2.5 COMPATIBILITY AnyNewerVersion)
+
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/testLibRequiredConfig.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/testLibRequiredConfigVersion.cmake"
+ DESTINATION lib/cmake/testLibRequired
+)
+
+# Install and export from install tree.
+install(
+ TARGETS
+ testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3 testExe4
+ testExe2lib testLib4lib testLib4libdbg testLib4libopt
+ testLib6 testLib7 testLib8
+ testLib9
+ testLibDeprecation
+ testLibCycleA testLibCycleB
+ testLibNoSONAME
+ cmp0022NEW cmp0022OLD
+ TopDirLib SubDirLinkA
+ systemlib
+ EXPORT exp
+ RUNTIME DESTINATION $<1:bin>$<0:/wrong>
+ LIBRARY DESTINATION $<1:lib>$<0:/wrong> NAMELINK_SKIP
+ ARCHIVE DESTINATION $<1:lib>$<0:/wrong>
+ ${maybe_OBJECTS_DESTINATION}
+ FRAMEWORK DESTINATION Frameworks
+ BUNDLE DESTINATION Applications
+ )
+install(
+ TARGETS
+ testLib9ObjPub testLib9ObjPriv testLib9ObjIface
+ EXPORT exp
+ )
+if (APPLE)
+ file(COPY testLib4.h DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/testLib4.framework/Headers)
+ file(COPY testLib4.h DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug/testLib4.framework/Headers)
+ file(COPY testLib4.h DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Release/testLib4.framework/Headers)
+ install(FILES testLib4.h DESTINATION Frameworks/testLib4.framework/Headers)
+endif()
+install(
+ TARGETS
+ testExe2libImp testLib3Imp
+ EXPORT exp
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib/impl
+ ARCHIVE DESTINATION lib/impl
+ )
+install(
+ TARGETS
+ testLib3ImpDep
+ EXPORT exp
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib/impl/dep
+ ARCHIVE DESTINATION lib/impl/dep
+ )
+install(
+ TARGETS testLib5
+ EXPORT exp
+ # Leave out RUNTIME DESTINATION to test implib-only export.
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib
+ )
+install(EXPORT exp NAMESPACE exp_ DESTINATION lib/exp)
+
+# Install testLib5.dll outside the export.
+if(WIN32)
+ install(TARGETS testLib5 RUNTIME DESTINATION bin)
+endif()
+
+add_subdirectory(sublib) # For CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE test.
+
+# Export from build tree.
+export(TARGETS testExe1 testLib1 testLib2 testLib3
+ testExe2libImp testLib3Imp testLib3ImpDep subdirlib
+ testSharedLibRequired testSharedLibRequiredUser testSharedLibRequiredUser2
+ testSharedLibDepends renamed_on_export
+ cmp0022NEW cmp0022OLD
+ TopDirLib SubDirLinkA
+ systemlib
+ NAMESPACE bld_
+ FILE ExportBuildTree.cmake
+ )
+export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe4 testExe2lib
+ testLib8
+ testLib9 testLib9ObjPub testLib9ObjPriv testLib9ObjIface
+ testLibDeprecation
+ testLib4lib testLib4libdbg testLib4libopt
+ testLibCycleA testLibCycleB
+ testLibNoSONAME
+ testLibPerConfigDest
+ NAMESPACE bld_
+ APPEND FILE ExportBuildTree.cmake
+ )
+
+add_subdirectory(Interface)
+
+#-----------------------------------------------------------------------------
+# Install export with absolute destination but relative pieces.
+add_library(testLibAbs1 STATIC testLibAbs1.c)
+target_include_directories(testLibAbs1 INTERFACE
+ "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include/abs/1a;include/abs/1b>"
+ )
+install(
+ TARGETS testLibAbs1
+ EXPORT expAbs
+ ARCHIVE DESTINATION lib
+ INCLUDES DESTINATION include/abs
+ )
+install(DIRECTORY $<1:include/abs>$<0:/wrong> DESTINATION $<1:include>$<0:/wrong>)
+install(EXPORT expAbs NAMESPACE expAbs_ DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/expAbs)
+
+
+#------------------------------------------------------------------------------
+# test export of INTERFACE_LINK_OPTIONS
+add_library(testLinkOptions INTERFACE)
+target_link_options(testLinkOptions INTERFACE INTERFACE_FLAG)
+
+install(TARGETS testLinkOptions
+ EXPORT RequiredExp DESTINATION lib)
+export(TARGETS testLinkOptions NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake)
+
+
+#------------------------------------------------------------------------------
+# test export of INTERFACE_LINK_DIRECTORIES
+add_library(testLinkDirectories INTERFACE)
+target_link_directories(testLinkDirectories INTERFACE
+ $<BUILD_INTERFACE:/interface/build>
+ $<INSTALL_INTERFACE:interface/install>)
+
+install(TARGETS testLinkDirectories
+ EXPORT RequiredExp DESTINATION lib)
+export(TARGETS testLinkDirectories NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake)
+
+
+#------------------------------------------------------------------------------
+# test export of INTERFACE_LINK_DEPENDS
+if(CMAKE_GENERATOR MATCHES "Make|Ninja")
+ add_library(testLinkDepends INTERFACE)
+ set_property(TARGET testLinkDepends PROPERTY INTERFACE_LINK_DEPENDS
+ $<BUILD_INTERFACE:BUILD_LINK_DEPENDS>
+ $<INSTALL_INTERFACE:INSTALL_LINK_DEPENDS>)
+
+ install(TARGETS testLinkDepends
+ EXPORT RequiredExp DESTINATION lib)
+ export(TARGETS testLinkDepends NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake)
+endif()
+
+#------------------------------------------------------------------------------
+# test export of CUDA language
+if(CMake_TEST_CUDA)
+ enable_language(CUDA)
+ add_library(cudaInterfaceLib INTERFACE)
+ target_compile_features(cudaInterfaceLib INTERFACE $<BUILD_INTERFACE:cuda_std_11> $<INSTALL_INTERFACE:cuda_std_14>)
+
+ install(TARGETS cudaInterfaceLib
+ EXPORT RequiredExp DESTINATION lib)
+ export(TARGETS cudaInterfaceLib NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake)
+endif()
+
+# Test the presence of targets named the same as languages.
+# IMPORTED_LINK_INTERFACE_LANGUAGES entries should not be targets.
+add_library(C INTERFACE)
+add_library(CXX INTERFACE)
+
+#------------------------------------------------------------------------------
+# test export of targets built from sources named using $<CONFIG> generator-expression
+# FIXME: Enable test on Xcode generator when it supports per-config sources.
+if(NOT XCODE)
+ file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_$<CONFIG>.cpp" CONTENT "// content")
+ add_library(testStaticFromGeneratedSource STATIC)
+ target_sources(testStaticFromGeneratedSource PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/Generated_$<CONFIG>.cpp")
+
+ add_library(testLibFromGeneratedSource SHARED empty.cpp)
+ target_link_libraries(testLibFromGeneratedSource PRIVATE testStaticFromGeneratedSource)
+
+ install(TARGETS testLibFromGeneratedSource EXPORT testLibFromGeneratedSource_Export)
+ install(EXPORT testLibFromGeneratedSource_Export DESTINATION lib)
+endif()
diff --git a/Tests/ExportImport/Export/Interface/CMakeLists.txt b/Tests/ExportImport/Export/Interface/CMakeLists.txt
new file mode 100644
index 0000000..ba2164b
--- /dev/null
+++ b/Tests/ExportImport/Export/Interface/CMakeLists.txt
@@ -0,0 +1,104 @@
+set(headeronly_headers headeronly/headeronly.h)
+add_library(headeronly INTERFACE ${headeronly_headers})
+set_property(TARGET headeronly PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/headeronly>"
+ "$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include/headeronly>"
+)
+set_property(TARGET headeronly PROPERTY INTERFACE_COMPILE_DEFINITIONS "HEADERONLY_DEFINE")
+
+add_custom_command(OUTPUT headergen/headergen.h
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_SOURCE_DIR}/headergen.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/headergen/headergen.h
+ DEPENDS
+ ${CMAKE_CURRENT_SOURCE_DIR}/headergen.h.in
+ VERBATIM)
+
+add_library(headergen INTERFACE headergen/headergen.h)
+set_property(TARGET headergen PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/headergen>"
+)
+set_property(TARGET headergen PROPERTY PUBLIC_HEADER
+ ${CMAKE_CURRENT_BINARY_DIR}/headergen/headergen.h)
+
+add_library(pch_iface INTERFACE)
+target_precompile_headers(pch_iface INTERFACE
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/pch/pch.h>"
+ "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include/pch/pch.h>"
+ )
+
+include(GenerateExportHeader)
+add_library(sharedlib SHARED sharedlib.cpp)
+generate_export_header(sharedlib)
+set_property(TARGET sharedlib PROPERTY INCLUDE_DIRECTORIES
+ "${CMAKE_CURRENT_SOURCE_DIR}/sharedlib"
+ "${CMAKE_CURRENT_BINARY_DIR}"
+)
+set_property(TARGET sharedlib PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/sharedlib;${CMAKE_CURRENT_BINARY_DIR}>"
+ "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include/sharedlib>"
+)
+
+set_property(TARGET sharedlib PROPERTY INTERFACE_COMPILE_DEFINITIONS "SHAREDLIB_DEFINE")
+
+add_library(sharediface INTERFACE)
+target_link_libraries(sharediface INTERFACE sharedlib)
+
+add_library(use_auto_type INTERFACE)
+target_compile_features(use_auto_type INTERFACE cxx_auto_type)
+
+add_library(use_c_restrict INTERFACE)
+target_compile_features(use_c_restrict INTERFACE c_restrict)
+
+add_library(source_target INTERFACE)
+target_sources(source_target INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/source_target.cpp>
+ $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/src/source_target_for_install.cpp>
+)
+install(FILES
+ source_target_for_install.cpp
+ DESTINATION src
+)
+
+add_library(cmakeonly INTERFACE)
+set_property(TARGET cmakeonly PROPERTY INTERFACE_COMPILE_DEFINITIONS [[DEF="\"\$\B"]])
+set_property(TARGET cmakeonly PROPERTY custom_property CustomPropertyValue)
+set_property(TARGET cmakeonly PROPERTY EXPORT_PROPERTIES custom_property)
+
+install(TARGETS headeronly sharediface use_auto_type use_c_restrict source_target
+ pch_iface cmakeonly
+ EXPORT expInterface
+)
+install(TARGETS headergen
+ EXPORT expInterface
+ PUBLIC_HEADER DESTINATION include/headergen
+ INCLUDES DESTINATION include/headergen
+)
+install(TARGETS sharedlib
+ EXPORT expInterface
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib NAMELINK_SKIP
+ ARCHIVE DESTINATION lib
+ FRAMEWORK DESTINATION Frameworks
+ BUNDLE DESTINATION Applications
+)
+install(FILES
+ ${headeronly_headers}
+ DESTINATION include/headeronly
+)
+install(FILES
+ pch/pch.h
+ DESTINATION include/pch
+)
+install(FILES
+ sharedlib/sharedlib.h
+ "${CMAKE_CURRENT_BINARY_DIR}/sharedlib_export.h"
+ DESTINATION include/sharedlib
+)
+
+install(EXPORT expInterface NAMESPACE exp:: DESTINATION lib/exp)
+
+export(EXPORT expInterface
+ NAMESPACE bld::
+ FILE ../ExportInterfaceBuildTree.cmake
+)
diff --git a/Tests/ExportImport/Export/Interface/headergen.h.in b/Tests/ExportImport/Export/Interface/headergen.h.in
new file mode 100644
index 0000000..bda2b81
--- /dev/null
+++ b/Tests/ExportImport/Export/Interface/headergen.h.in
@@ -0,0 +1 @@
+#define HEADERGEN_H
diff --git a/Tests/ExportImport/Export/Interface/headeronly/headeronly.h b/Tests/ExportImport/Export/Interface/headeronly/headeronly.h
new file mode 100644
index 0000000..92bfecd
--- /dev/null
+++ b/Tests/ExportImport/Export/Interface/headeronly/headeronly.h
@@ -0,0 +1,10 @@
+
+enum
+{
+ one
+};
+
+struct HeaderOnly
+{
+ int foo() const { return 0; }
+};
diff --git a/Tests/ExportImport/Export/Interface/pch/pch.h b/Tests/ExportImport/Export/Interface/pch/pch.h
new file mode 100644
index 0000000..bc50727
--- /dev/null
+++ b/Tests/ExportImport/Export/Interface/pch/pch.h
@@ -0,0 +1 @@
+#define PCH_PCH_H_INCLUDED
diff --git a/Tests/ExportImport/Export/Interface/sharedlib.cpp b/Tests/ExportImport/Export/Interface/sharedlib.cpp
new file mode 100644
index 0000000..88ca713
--- /dev/null
+++ b/Tests/ExportImport/Export/Interface/sharedlib.cpp
@@ -0,0 +1,7 @@
+
+#include "sharedlib.h"
+
+int SharedLibObject::foo() const
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/Interface/sharedlib/sharedlib.h b/Tests/ExportImport/Export/Interface/sharedlib/sharedlib.h
new file mode 100644
index 0000000..aad9ef3
--- /dev/null
+++ b/Tests/ExportImport/Export/Interface/sharedlib/sharedlib.h
@@ -0,0 +1,7 @@
+
+#include "sharedlib_export.h"
+
+struct SHAREDLIB_EXPORT SharedLibObject
+{
+ int foo() const;
+};
diff --git a/Tests/ExportImport/Export/Interface/source_target.cpp b/Tests/ExportImport/Export/Interface/source_target.cpp
new file mode 100644
index 0000000..1eb5b13
--- /dev/null
+++ b/Tests/ExportImport/Export/Interface/source_target.cpp
@@ -0,0 +1,13 @@
+
+#ifndef USE_FROM_BUILD_DIR
+# error Expected define USE_FROM_BUILD_DIR
+#endif
+
+#ifdef USE_FROM_INSTALL_DIR
+# error Unexpected define USE_FROM_INSTALL_DIR
+#endif
+
+int source_symbol()
+{
+ return 42;
+}
diff --git a/Tests/ExportImport/Export/Interface/source_target_for_install.cpp b/Tests/ExportImport/Export/Interface/source_target_for_install.cpp
new file mode 100644
index 0000000..2f88190
--- /dev/null
+++ b/Tests/ExportImport/Export/Interface/source_target_for_install.cpp
@@ -0,0 +1,13 @@
+
+#ifdef USE_FROM_BUILD_DIR
+# error Unexpected define USE_FROM_BUILD_DIR
+#endif
+
+#ifndef USE_FROM_INSTALL_DIR
+# error Expected define USE_FROM_INSTALL_DIR
+#endif
+
+int source_symbol()
+{
+ return 42;
+}
diff --git a/Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt b/Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt
new file mode 100644
index 0000000..1aa41d2
--- /dev/null
+++ b/Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_library(SubDirLinkAImported IMPORTED INTERFACE)
+target_compile_definitions(SubDirLinkAImported INTERFACE DEF_SubDirLinkAImportedForExport)
+
+target_link_libraries(TopDirLib PUBLIC debug "$<1:SubDirLinkAImported;SubDirLinkAImported>" optimized "$<1:SubDirLinkAImported;SubDirLinkAImported>")
+
+add_library(SubDirLinkA STATIC SubDirLinkA.c)
diff --git a/Tests/ExportImport/Export/SubDirLinkA/SubDirLinkA.c b/Tests/ExportImport/Export/SubDirLinkA/SubDirLinkA.c
new file mode 100644
index 0000000..abf76f5
--- /dev/null
+++ b/Tests/ExportImport/Export/SubDirLinkA/SubDirLinkA.c
@@ -0,0 +1,11 @@
+#ifdef DEF_SubDirLinkAImportedForExport
+# error "DEF_SubDirLinkAImportedForExport is defined but should not be!"
+#endif
+#ifndef DEF_SubDirLinkBImportedForExport
+# error "DEF_SubDirLinkBImportedForExport is not defined but should be!"
+#endif
+
+int testSubDirLinkA(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/SubDirLinkB/CMakeLists.txt b/Tests/ExportImport/Export/SubDirLinkB/CMakeLists.txt
new file mode 100644
index 0000000..22e168f
--- /dev/null
+++ b/Tests/ExportImport/Export/SubDirLinkB/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library(SubDirLinkBImported IMPORTED INTERFACE)
+target_compile_definitions(SubDirLinkBImported INTERFACE DEF_SubDirLinkBImportedForExport)
+
+target_link_libraries(SubDirLinkA PUBLIC SubDirLinkBImported)
diff --git a/Tests/ExportImport/Export/cmp0022.cpp b/Tests/ExportImport/Export/cmp0022.cpp
new file mode 100644
index 0000000..bef8e61
--- /dev/null
+++ b/Tests/ExportImport/Export/cmp0022.cpp
@@ -0,0 +1,7 @@
+
+#include "cmp0022.h"
+
+int cmp0022()
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/cmp0022.h b/Tests/ExportImport/Export/cmp0022.h
new file mode 100644
index 0000000..32bf71a
--- /dev/null
+++ b/Tests/ExportImport/Export/cmp0022.h
@@ -0,0 +1,4 @@
+
+#include "cmp0022_export.h"
+
+int CMP0022_EXPORT cmp0022();
diff --git a/Tests/ExportImport/Export/cmp0022_vs6_1.cpp b/Tests/ExportImport/Export/cmp0022_vs6_1.cpp
new file mode 100644
index 0000000..a6ec838
--- /dev/null
+++ b/Tests/ExportImport/Export/cmp0022_vs6_1.cpp
@@ -0,0 +1 @@
+#include "cmp0022.cpp"
diff --git a/Tests/ExportImport/Export/cmp0022_vs6_2.cpp b/Tests/ExportImport/Export/cmp0022_vs6_2.cpp
new file mode 100644
index 0000000..a6ec838
--- /dev/null
+++ b/Tests/ExportImport/Export/cmp0022_vs6_2.cpp
@@ -0,0 +1 @@
+#include "cmp0022.cpp"
diff --git a/Tests/ExportImport/Export/empty.cpp b/Tests/ExportImport/Export/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/ExportImport/Export/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/include/abs/1a/testLibAbs1a.h b/Tests/ExportImport/Export/include/abs/1a/testLibAbs1a.h
new file mode 100644
index 0000000..4421227
--- /dev/null
+++ b/Tests/ExportImport/Export/include/abs/1a/testLibAbs1a.h
@@ -0,0 +1 @@
+#define testLibAbs1a
diff --git a/Tests/ExportImport/Export/include/abs/1b/testLibAbs1b.h b/Tests/ExportImport/Export/include/abs/1b/testLibAbs1b.h
new file mode 100644
index 0000000..00a2a29
--- /dev/null
+++ b/Tests/ExportImport/Export/include/abs/1b/testLibAbs1b.h
@@ -0,0 +1 @@
+#define testLibAbs1b
diff --git a/Tests/ExportImport/Export/include/abs/testLibAbs1.h b/Tests/ExportImport/Export/include/abs/testLibAbs1.h
new file mode 100644
index 0000000..19d80a5
--- /dev/null
+++ b/Tests/ExportImport/Export/include/abs/testLibAbs1.h
@@ -0,0 +1 @@
+extern int testLibAbs1(void);
diff --git a/Tests/ExportImport/Export/renamed/CMakeLists.txt b/Tests/ExportImport/Export/renamed/CMakeLists.txt
new file mode 100644
index 0000000..a763251
--- /dev/null
+++ b/Tests/ExportImport/Export/renamed/CMakeLists.txt
@@ -0,0 +1,20 @@
+
+add_library(renamed_on_export SHARED renamed.cxx)
+generate_export_header(renamed_on_export)
+target_include_directories(renamed_on_export
+ PUBLIC "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include/renamed>"
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}>"
+)
+set_property(TARGET renamed_on_export
+ PROPERTY
+ EXPORT_NAME renamed
+)
+
+install(FILES
+ "${CMAKE_CURRENT_SOURCE_DIR}/renamed.h"
+ "${CMAKE_CURRENT_BINARY_DIR}/renamed_on_export_export.h"
+ DESTINATION include/renamed
+)
+
+install(TARGETS renamed_on_export
+ EXPORT exp DESTINATION lib )
diff --git a/Tests/ExportImport/Export/renamed/renamed.cxx b/Tests/ExportImport/Export/renamed/renamed.cxx
new file mode 100644
index 0000000..b3e3e7e
--- /dev/null
+++ b/Tests/ExportImport/Export/renamed/renamed.cxx
@@ -0,0 +1,7 @@
+
+#include "renamed.h"
+
+int Renamed::foo()
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/renamed/renamed.h b/Tests/ExportImport/Export/renamed/renamed.h
new file mode 100644
index 0000000..06ac601
--- /dev/null
+++ b/Tests/ExportImport/Export/renamed/renamed.h
@@ -0,0 +1,12 @@
+
+#ifndef RENAMED_H
+#define RENAMED_H
+
+#include "renamed_on_export_export.h"
+
+struct RENAMED_ON_EXPORT_EXPORT Renamed
+{
+ int foo();
+};
+
+#endif
diff --git a/Tests/ExportImport/Export/sub/testLib8C.c b/Tests/ExportImport/Export/sub/testLib8C.c
new file mode 100644
index 0000000..a5568c7
--- /dev/null
+++ b/Tests/ExportImport/Export/sub/testLib8C.c
@@ -0,0 +1,4 @@
+int testLib8C(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/sublib/CMakeLists.txt b/Tests/ExportImport/Export/sublib/CMakeLists.txt
new file mode 100644
index 0000000..a5c6413
--- /dev/null
+++ b/Tests/ExportImport/Export/sublib/CMakeLists.txt
@@ -0,0 +1,6 @@
+
+set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_library(subdirlib SHARED subdir.cpp)
+generate_export_header(subdirlib)
diff --git a/Tests/ExportImport/Export/sublib/subdir.cpp b/Tests/ExportImport/Export/sublib/subdir.cpp
new file mode 100644
index 0000000..35b0743
--- /dev/null
+++ b/Tests/ExportImport/Export/sublib/subdir.cpp
@@ -0,0 +1,7 @@
+
+#include "subdir.h"
+
+int SubDirObject::foo()
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/sublib/subdir.h b/Tests/ExportImport/Export/sublib/subdir.h
new file mode 100644
index 0000000..3a4b73d
--- /dev/null
+++ b/Tests/ExportImport/Export/sublib/subdir.h
@@ -0,0 +1,12 @@
+
+#ifndef SUBDIR_H
+#define SUBDIR_H
+
+#include "subdirlib_export.h"
+
+struct SUBDIRLIB_EXPORT SubDirObject
+{
+ int foo();
+};
+
+#endif
diff --git a/Tests/ExportImport/Export/systemlib.cpp b/Tests/ExportImport/Export/systemlib.cpp
new file mode 100644
index 0000000..a9e6179
--- /dev/null
+++ b/Tests/ExportImport/Export/systemlib.cpp
@@ -0,0 +1,6 @@
+
+#include "systemlib.h"
+
+SystemStruct::SystemStruct()
+{
+}
diff --git a/Tests/ExportImport/Export/systemlib.h b/Tests/ExportImport/Export/systemlib.h
new file mode 100644
index 0000000..8ec055b
--- /dev/null
+++ b/Tests/ExportImport/Export/systemlib.h
@@ -0,0 +1,22 @@
+
+#ifndef SYSTEMLIB_H
+#define SYSTEMLIB_H
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define systemlib_EXPORT __declspec(dllexport)
+#else
+# define systemlib_EXPORT
+#endif
+
+struct systemlib_EXPORT SystemStruct
+{
+ SystemStruct();
+
+ void someMethod()
+ {
+ int unused;
+ // unused warning not issued when this header is used as a system header.
+ }
+};
+
+#endif
diff --git a/Tests/ExportImport/Export/testExe1.c b/Tests/ExportImport/Export/testExe1.c
new file mode 100644
index 0000000..5fbb892
--- /dev/null
+++ b/Tests/ExportImport/Export/testExe1.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+
+extern int testExe1lib(void);
+
+int main(int argc, const char* argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "Must specify output file.\n");
+ return 1;
+ }
+ {
+ FILE* f = fopen(argv[1], "w");
+ if (f) {
+ fprintf(f, "int generated_by_testExe1() { return 0; }\n");
+ fclose(f);
+ } else {
+ fprintf(stderr, "Error writing to %s\n", argv[1]);
+ return 1;
+ }
+ }
+ return testExe1lib();
+}
diff --git a/Tests/ExportImport/Export/testExe1lib.c b/Tests/ExportImport/Export/testExe1lib.c
new file mode 100644
index 0000000..4bb3325
--- /dev/null
+++ b/Tests/ExportImport/Export/testExe1lib.c
@@ -0,0 +1,4 @@
+int testExe1lib(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testExe2.c b/Tests/ExportImport/Export/testExe2.c
new file mode 100644
index 0000000..958e4d2
--- /dev/null
+++ b/Tests/ExportImport/Export/testExe2.c
@@ -0,0 +1,15 @@
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define testExe2_EXPORT __declspec(dllexport)
+#else
+# define testExe2_EXPORT
+#endif
+
+testExe2_EXPORT int testExe2Func(void)
+{
+ return 123;
+}
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testExe2lib.c b/Tests/ExportImport/Export/testExe2lib.c
new file mode 100644
index 0000000..905e6c7
--- /dev/null
+++ b/Tests/ExportImport/Export/testExe2lib.c
@@ -0,0 +1,13 @@
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define testExe2lib_EXPORT __declspec(dllexport)
+# define testExe2libImp_IMPORT __declspec(dllimport)
+#else
+# define testExe2lib_EXPORT
+# define testExe2libImp_IMPORT
+#endif
+
+testExe2libImp_IMPORT int testExe2libImp(void);
+testExe2lib_EXPORT int testExe2lib(void)
+{
+ return testExe2libImp();
+}
diff --git a/Tests/ExportImport/Export/testExe2libImp.c b/Tests/ExportImport/Export/testExe2libImp.c
new file mode 100644
index 0000000..8892c85
--- /dev/null
+++ b/Tests/ExportImport/Export/testExe2libImp.c
@@ -0,0 +1,10 @@
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define testExe2libImp_EXPORT __declspec(dllexport)
+#else
+# define testExe2libImp_EXPORT
+#endif
+
+testExe2libImp_EXPORT int testExe2libImp(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testExe3.c b/Tests/ExportImport/Export/testExe3.c
new file mode 100644
index 0000000..2b07576
--- /dev/null
+++ b/Tests/ExportImport/Export/testExe3.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+
+int main(int argc, const char* argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "Must specify output file.\n");
+ return 1;
+ }
+ {
+ FILE* f = fopen(argv[1], "w");
+ if (f) {
+ fprintf(f, "int generated_by_testExe3() { return 0; }\n");
+ fclose(f);
+ } else {
+ fprintf(stderr, "Error writing to %s\n", argv[1]);
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testExe4.c b/Tests/ExportImport/Export/testExe4.c
new file mode 100644
index 0000000..422ab3d
--- /dev/null
+++ b/Tests/ExportImport/Export/testExe4.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+
+int main(int argc, const char* argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "Must specify output file.\n");
+ return 1;
+ }
+ {
+ FILE* f = fopen(argv[1], "w");
+ if (f) {
+ fprintf(f, "int generated_by_testExe4() { return 0; }\n");
+ fclose(f);
+ } else {
+ fprintf(stderr, "Error writing to %s\n", argv[1]);
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLib1.c b/Tests/ExportImport/Export/testLib1.c
new file mode 100644
index 0000000..5002963
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib1.c
@@ -0,0 +1,4 @@
+int testLib1(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLib1file1.txt b/Tests/ExportImport/Export/testLib1file1.txt
new file mode 100644
index 0000000..73601df
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib1file1.txt
@@ -0,0 +1 @@
+testLib1file1
diff --git a/Tests/ExportImport/Export/testLib1file2.txt b/Tests/ExportImport/Export/testLib1file2.txt
new file mode 100644
index 0000000..4874ed1
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib1file2.txt
@@ -0,0 +1 @@
+testLib1file2
diff --git a/Tests/ExportImport/Export/testLib2.c b/Tests/ExportImport/Export/testLib2.c
new file mode 100644
index 0000000..7a5206f
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib2.c
@@ -0,0 +1,7 @@
+
+extern int testLib1(void);
+
+int testLib2(void)
+{
+ return testLib1();
+}
diff --git a/Tests/ExportImport/Export/testLib3.c b/Tests/ExportImport/Export/testLib3.c
new file mode 100644
index 0000000..016fae0
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib3.c
@@ -0,0 +1,13 @@
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define testLib3_EXPORT __declspec(dllexport)
+# define testLib3Imp_IMPORT __declspec(dllimport)
+#else
+# define testLib3_EXPORT
+# define testLib3Imp_IMPORT
+#endif
+
+testLib3Imp_IMPORT int testLib3Imp(void);
+testLib3_EXPORT int testLib3(void)
+{
+ return testLib3Imp();
+}
diff --git a/Tests/ExportImport/Export/testLib3Imp.c b/Tests/ExportImport/Export/testLib3Imp.c
new file mode 100644
index 0000000..877d0b6
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib3Imp.c
@@ -0,0 +1,13 @@
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define testLib3Imp_EXPORT __declspec(dllexport)
+# define testLib3ImpDep_IMPORT __declspec(dllimport)
+#else
+# define testLib3Imp_EXPORT
+# define testLib3ImpDep_IMPORT
+#endif
+
+testLib3ImpDep_IMPORT int testLib3ImpDep(void);
+testLib3Imp_EXPORT int testLib3Imp(void)
+{
+ return testLib3ImpDep();
+}
diff --git a/Tests/ExportImport/Export/testLib3ImpDep.c b/Tests/ExportImport/Export/testLib3ImpDep.c
new file mode 100644
index 0000000..4fc9783
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib3ImpDep.c
@@ -0,0 +1,10 @@
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define testLib3ImpDep_EXPORT __declspec(dllexport)
+#else
+# define testLib3ImpDep_EXPORT
+#endif
+
+testLib3ImpDep_EXPORT int testLib3ImpDep(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLib4.c b/Tests/ExportImport/Export/testLib4.c
new file mode 100644
index 0000000..2031a4f
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib4.c
@@ -0,0 +1,10 @@
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define testLib4_EXPORT __declspec(dllexport)
+#else
+# define testLib4_EXPORT
+#endif
+
+testLib4_EXPORT int testLib4(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLib4.h b/Tests/ExportImport/Export/testLib4.h
new file mode 100644
index 0000000..9eeda7c
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib4.h
@@ -0,0 +1,2 @@
+
+#define TESTLIB4_H
diff --git a/Tests/ExportImport/Export/testLib4lib.c b/Tests/ExportImport/Export/testLib4lib.c
new file mode 100644
index 0000000..bf3c11e
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib4lib.c
@@ -0,0 +1,4 @@
+int testLib4lib(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLib4libdbg.c b/Tests/ExportImport/Export/testLib4libdbg.c
new file mode 100644
index 0000000..453f262
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib4libdbg.c
@@ -0,0 +1,14 @@
+#ifdef LIB_DBG
+/* We are building in testLib4libdbg. Provide the correct symbol. */
+int testLib4libdbg(void)
+{
+ return 0;
+}
+#else
+/* We are not building in testLib4libdbg. Poison the symbol. */
+extern int testLib4libdbg_noexist(void);
+int testLib4libdbg(void)
+{
+ return testLib4libdbg_noexist();
+}
+#endif
diff --git a/Tests/ExportImport/Export/testLib4libopt.c b/Tests/ExportImport/Export/testLib4libopt.c
new file mode 100644
index 0000000..605edd0
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib4libopt.c
@@ -0,0 +1,14 @@
+#ifdef LIB_OPT
+/* We are building in testLib4libopt. Provide the correct symbol. */
+int testLib4libopt(void)
+{
+ return 0;
+}
+#else
+/* We are not building in testLib4libopt. Poison the symbol. */
+extern int testLib4libopt_noexist(void);
+int testLib4libopt(void)
+{
+ return testLib4libopt_noexist();
+}
+#endif
diff --git a/Tests/ExportImport/Export/testLib5.c b/Tests/ExportImport/Export/testLib5.c
new file mode 100644
index 0000000..edd02eb
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib5.c
@@ -0,0 +1,10 @@
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define testLib5_EXPORT __declspec(dllexport)
+#else
+# define testLib5_EXPORT
+#endif
+
+testLib5_EXPORT int testLib5(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLib6.cxx b/Tests/ExportImport/Export/testLib6.cxx
new file mode 100644
index 0000000..338e639
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib6.cxx
@@ -0,0 +1,6 @@
+extern "C" int testLib6cxx(void)
+{
+ // Reference C++ standard library symbols.
+ delete new int;
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLib6c.c b/Tests/ExportImport/Export/testLib6c.c
new file mode 100644
index 0000000..493ca07
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib6c.c
@@ -0,0 +1,5 @@
+extern int testLib6cxx(void);
+int testLib6(void)
+{
+ return testLib6cxx();
+}
diff --git a/Tests/ExportImport/Export/testLib7.c b/Tests/ExportImport/Export/testLib7.c
new file mode 100644
index 0000000..de85c1a
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib7.c
@@ -0,0 +1,4 @@
+int testLib7(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLib8A.c b/Tests/ExportImport/Export/testLib8A.c
new file mode 100644
index 0000000..c64655a
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib8A.c
@@ -0,0 +1,4 @@
+int testLib8A(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLib8B.c b/Tests/ExportImport/Export/testLib8B.c
new file mode 100644
index 0000000..1be6c9c
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib8B.c
@@ -0,0 +1,4 @@
+int testLib8B(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLib9.c b/Tests/ExportImport/Export/testLib9.c
new file mode 100644
index 0000000..2f6f8eb
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib9.c
@@ -0,0 +1,15 @@
+#ifndef testLib9ObjPub_USED
+# error "testLib9ObjPub_USED not defined!"
+#endif
+#ifndef testLib9ObjPriv_USED
+# error "testLib9ObjPriv_USED not defined!"
+#endif
+#ifdef testLib9ObjIface_USED
+# error "testLib9ObjIface_USED defined but should not be!"
+#endif
+int testLib9ObjPub(void);
+int testLib9ObjPriv(void);
+int testLib9(void)
+{
+ return (testLib9ObjPub() + testLib9ObjPriv());
+}
diff --git a/Tests/ExportImport/Export/testLib9ObjIface.c b/Tests/ExportImport/Export/testLib9ObjIface.c
new file mode 100644
index 0000000..e75440a
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib9ObjIface.c
@@ -0,0 +1,11 @@
+/* Duplicate symbols from other sources to verify that this source
+ is not included when the object library is used. */
+int testLib9ObjMissing(void);
+int testLib9ObjPub(void)
+{
+ return testLib9ObjMissing();
+}
+int testLib9ObjPriv(void)
+{
+ return testLib9ObjMissing();
+}
diff --git a/Tests/ExportImport/Export/testLib9ObjPriv.c b/Tests/ExportImport/Export/testLib9ObjPriv.c
new file mode 100644
index 0000000..6fa63cc
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib9ObjPriv.c
@@ -0,0 +1,4 @@
+int testLib9ObjPriv(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLib9ObjPub.c b/Tests/ExportImport/Export/testLib9ObjPub.c
new file mode 100644
index 0000000..66e2624
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib9ObjPub.c
@@ -0,0 +1,4 @@
+int testLib9ObjPub(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLibAbs1.c b/Tests/ExportImport/Export/testLibAbs1.c
new file mode 100644
index 0000000..c214b62
--- /dev/null
+++ b/Tests/ExportImport/Export/testLibAbs1.c
@@ -0,0 +1,4 @@
+int testLibAbs1(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLibCycleA1.c b/Tests/ExportImport/Export/testLibCycleA1.c
new file mode 100644
index 0000000..cfbf0e1
--- /dev/null
+++ b/Tests/ExportImport/Export/testLibCycleA1.c
@@ -0,0 +1,5 @@
+extern int testLibCycleB1(void);
+int testLibCycleA1(void)
+{
+ return testLibCycleB1();
+}
diff --git a/Tests/ExportImport/Export/testLibCycleA2.c b/Tests/ExportImport/Export/testLibCycleA2.c
new file mode 100644
index 0000000..93c9fb6
--- /dev/null
+++ b/Tests/ExportImport/Export/testLibCycleA2.c
@@ -0,0 +1,5 @@
+extern int testLibCycleB2(void);
+int testLibCycleA2(void)
+{
+ return testLibCycleB2();
+}
diff --git a/Tests/ExportImport/Export/testLibCycleA3.c b/Tests/ExportImport/Export/testLibCycleA3.c
new file mode 100644
index 0000000..468c044
--- /dev/null
+++ b/Tests/ExportImport/Export/testLibCycleA3.c
@@ -0,0 +1,5 @@
+extern int testLibCycleB3(void);
+int testLibCycleA3(void)
+{
+ return testLibCycleB3();
+}
diff --git a/Tests/ExportImport/Export/testLibCycleB1.c b/Tests/ExportImport/Export/testLibCycleB1.c
new file mode 100644
index 0000000..d152857
--- /dev/null
+++ b/Tests/ExportImport/Export/testLibCycleB1.c
@@ -0,0 +1,5 @@
+extern int testLibCycleA2(void);
+int testLibCycleB1(void)
+{
+ return testLibCycleA2();
+}
diff --git a/Tests/ExportImport/Export/testLibCycleB2.c b/Tests/ExportImport/Export/testLibCycleB2.c
new file mode 100644
index 0000000..18cd4f6
--- /dev/null
+++ b/Tests/ExportImport/Export/testLibCycleB2.c
@@ -0,0 +1,5 @@
+extern int testLibCycleA3(void);
+int testLibCycleB2(void)
+{
+ return testLibCycleA3();
+}
diff --git a/Tests/ExportImport/Export/testLibCycleB3.c b/Tests/ExportImport/Export/testLibCycleB3.c
new file mode 100644
index 0000000..a281c69
--- /dev/null
+++ b/Tests/ExportImport/Export/testLibCycleB3.c
@@ -0,0 +1,4 @@
+int testLibCycleB3(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLibDepends.c b/Tests/ExportImport/Export/testLibDepends.c
new file mode 100644
index 0000000..6100da1
--- /dev/null
+++ b/Tests/ExportImport/Export/testLibDepends.c
@@ -0,0 +1,24 @@
+
+#include "testLibIncludeRequired1.h"
+#include "testLibIncludeRequired2.h"
+#include "testLibIncludeRequired4.h"
+
+#ifndef testLibRequired_IFACE_DEFINE
+# error Expected testLibRequired_IFACE_DEFINE
+#endif
+
+#ifndef BuildOnly_DEFINE
+# error Expected BuildOnly_DEFINE
+#endif
+
+#ifdef InstallOnly_DEFINE
+# error Unexpected InstallOnly_DEFINE
+#endif
+
+extern int testLibRequired(void);
+extern int testStaticLibRequiredPrivate(void);
+
+int testLibDepends(void)
+{
+ return testLibRequired() + testStaticLibRequiredPrivate();
+}
diff --git a/Tests/ExportImport/Export/testLibNoSONAME.c b/Tests/ExportImport/Export/testLibNoSONAME.c
new file mode 100644
index 0000000..9552848
--- /dev/null
+++ b/Tests/ExportImport/Export/testLibNoSONAME.c
@@ -0,0 +1,10 @@
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define testLibNoSONAME_EXPORT __declspec(dllexport)
+#else
+# define testLibNoSONAME_EXPORT
+#endif
+
+testLibNoSONAME_EXPORT int testLibNoSoName(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLibPerConfigDest.c b/Tests/ExportImport/Export/testLibPerConfigDest.c
new file mode 100644
index 0000000..903e040
--- /dev/null
+++ b/Tests/ExportImport/Export/testLibPerConfigDest.c
@@ -0,0 +1,4 @@
+int testLibPerConfigDest(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testLibRequired.c b/Tests/ExportImport/Export/testLibRequired.c
new file mode 100644
index 0000000..24f320c
--- /dev/null
+++ b/Tests/ExportImport/Export/testLibRequired.c
@@ -0,0 +1,4 @@
+int testLibRequired(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testSharedLibDepends.cpp b/Tests/ExportImport/Export/testSharedLibDepends.cpp
new file mode 100644
index 0000000..962223f
--- /dev/null
+++ b/Tests/ExportImport/Export/testSharedLibDepends.cpp
@@ -0,0 +1,9 @@
+
+#include "testSharedLibDepends.h"
+
+int TestSharedLibDepends::foo()
+{
+ TestSharedLibRequired req;
+ Renamed renamed;
+ return req.foo() + renamed.foo();
+}
diff --git a/Tests/ExportImport/Export/testSharedLibDepends.h b/Tests/ExportImport/Export/testSharedLibDepends.h
new file mode 100644
index 0000000..73dafae
--- /dev/null
+++ b/Tests/ExportImport/Export/testSharedLibDepends.h
@@ -0,0 +1,14 @@
+
+#ifndef TESTSHAREDLIBDEPENDS_H
+#define TESTSHAREDLIBDEPENDS_H
+
+#include "renamed.h"
+#include "testSharedLibRequired.h"
+#include "testsharedlibdepends_export.h"
+
+struct TESTSHAREDLIBDEPENDS_EXPORT TestSharedLibDepends
+{
+ int foo();
+};
+
+#endif
diff --git a/Tests/ExportImport/Export/testSharedLibRequired.cpp b/Tests/ExportImport/Export/testSharedLibRequired.cpp
new file mode 100644
index 0000000..1ac34aa
--- /dev/null
+++ b/Tests/ExportImport/Export/testSharedLibRequired.cpp
@@ -0,0 +1,7 @@
+
+#include "testSharedLibRequired.h"
+
+int TestSharedLibRequired::foo()
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testSharedLibRequired.h b/Tests/ExportImport/Export/testSharedLibRequired.h
new file mode 100644
index 0000000..edaddd4
--- /dev/null
+++ b/Tests/ExportImport/Export/testSharedLibRequired.h
@@ -0,0 +1,12 @@
+
+#ifndef TESTSHAREDLIBREQUIRED_H
+#define TESTSHAREDLIBREQUIRED_H
+
+#include "testsharedlibrequired_export.h"
+
+struct TESTSHAREDLIBREQUIRED_EXPORT TestSharedLibRequired
+{
+ int foo();
+};
+
+#endif
diff --git a/Tests/ExportImport/Export/testSharedLibRequiredUser.cpp b/Tests/ExportImport/Export/testSharedLibRequiredUser.cpp
new file mode 100644
index 0000000..5580005
--- /dev/null
+++ b/Tests/ExportImport/Export/testSharedLibRequiredUser.cpp
@@ -0,0 +1,10 @@
+
+#include "testSharedLibRequiredUser.h"
+
+#include "testSharedLibRequired.h"
+
+int TestSharedLibRequiredUser::foo()
+{
+ TestSharedLibRequired req;
+ return req.foo();
+}
diff --git a/Tests/ExportImport/Export/testSharedLibRequiredUser.h b/Tests/ExportImport/Export/testSharedLibRequiredUser.h
new file mode 100644
index 0000000..58bcaa5
--- /dev/null
+++ b/Tests/ExportImport/Export/testSharedLibRequiredUser.h
@@ -0,0 +1,12 @@
+
+#ifndef TESTSHAREDLIBREQUIREDUSER_H
+#define TESTSHAREDLIBREQUIREDUSER_H
+
+#include "testsharedlibrequireduser_export.h"
+
+struct TESTSHAREDLIBREQUIREDUSER_EXPORT TestSharedLibRequiredUser
+{
+ int foo();
+};
+
+#endif
diff --git a/Tests/ExportImport/Export/testSharedLibRequiredUser2.cpp b/Tests/ExportImport/Export/testSharedLibRequiredUser2.cpp
new file mode 100644
index 0000000..d671bf0
--- /dev/null
+++ b/Tests/ExportImport/Export/testSharedLibRequiredUser2.cpp
@@ -0,0 +1,8 @@
+
+#include "testSharedLibRequiredUser2.h"
+
+TestSharedLibRequired TestSharedLibRequiredUser2::foo()
+{
+ TestSharedLibRequired req;
+ return req;
+}
diff --git a/Tests/ExportImport/Export/testSharedLibRequiredUser2.h b/Tests/ExportImport/Export/testSharedLibRequiredUser2.h
new file mode 100644
index 0000000..e1c8a05
--- /dev/null
+++ b/Tests/ExportImport/Export/testSharedLibRequiredUser2.h
@@ -0,0 +1,13 @@
+
+#ifndef TESTSHAREDLIBREQUIREDUSER2_H
+#define TESTSHAREDLIBREQUIREDUSER2_H
+
+#include "testSharedLibRequired.h"
+#include "testsharedlibrequireduser2_export.h"
+
+struct TESTSHAREDLIBREQUIREDUSER2_EXPORT TestSharedLibRequiredUser2
+{
+ TestSharedLibRequired foo();
+};
+
+#endif
diff --git a/Tests/ExportImport/Export/testStaticLibRequiredPrivate.c b/Tests/ExportImport/Export/testStaticLibRequiredPrivate.c
new file mode 100644
index 0000000..5597fb4
--- /dev/null
+++ b/Tests/ExportImport/Export/testStaticLibRequiredPrivate.c
@@ -0,0 +1,4 @@
+int testStaticLibRequiredPrivate(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/testTopDirLib.c b/Tests/ExportImport/Export/testTopDirLib.c
new file mode 100644
index 0000000..1ec68de
--- /dev/null
+++ b/Tests/ExportImport/Export/testTopDirLib.c
@@ -0,0 +1,11 @@
+#ifndef DEF_SubDirLinkAImportedForExport
+# error "DEF_SubDirLinkAImportedForExport is not defined but should be!"
+#endif
+#ifdef DEF_SubDirLinkBImportedForExport
+# error "DEF_SubDirLinkBImportedForExport is defined but should not be!"
+#endif
+
+int testTopDirLib(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt
new file mode 100644
index 0000000..3cb3833
--- /dev/null
+++ b/Tests/ExportImport/Import/A/CMakeLists.txt
@@ -0,0 +1,514 @@
+# Prepare imported targets that the exported project itself imported.
+add_library(SubDirLinkAImported IMPORTED INTERFACE)
+target_compile_definitions(SubDirLinkAImported INTERFACE DEF_SubDirLinkAImportedForImport)
+add_library(SubDirLinkBImported IMPORTED INTERFACE)
+target_compile_definitions(SubDirLinkBImported INTERFACE DEF_SubDirLinkBImportedForImport)
+
+# Import targets from the exported build tree.
+include(${Import_BINARY_DIR}/../Export/ExportBuildTree.cmake)
+
+# Import targets from the exported install tree.
+include(${CMAKE_INSTALL_PREFIX}/lib/exp/exp.cmake)
+
+# Import two exports, where the Depends one depends on an exported target from the Required one:
+include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibRequired/testLibRequiredTargets.cmake)
+include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibDepends/testLibDependsTargets.cmake)
+
+# Try referencing an executable imported from the install tree.
+add_custom_command(
+ OUTPUT ${Import_BINARY_DIR}/exp_generated.c
+ COMMAND exp_testExe1 ${Import_BINARY_DIR}/exp_generated.c
+ DEPENDS exp_testExe1
+ )
+add_custom_command(
+ OUTPUT ${Import_BINARY_DIR}/exp_generated3.c
+ COMMAND exp_testExe3 ${Import_BINARY_DIR}/exp_generated3.c
+ DEPENDS exp_testExe3
+ )
+add_custom_command(
+ OUTPUT ${Import_BINARY_DIR}/exp_generated4.c
+ COMMAND exp_testExe4 ${Import_BINARY_DIR}/exp_generated4.c
+ DEPENDS exp_testExe4
+ )
+
+add_executable(imp_testExe1
+ imp_testExe1.c
+ ${Import_BINARY_DIR}/exp_generated.c
+ ${Import_BINARY_DIR}/exp_generated3.c
+ ${Import_BINARY_DIR}/exp_generated4.c
+ )
+
+function(checkForProperty _TARGET _PROP _EXPECTED)
+ get_target_property(EXPORTED_PROPERTY ${_TARGET} "${_PROP}")
+ if (NOT EXPORTED_PROPERTY STREQUAL "${_EXPECTED}")
+ message(SEND_ERROR "${_TARGET} was expected to export \"${_PROP}\" with value \"${_EXPECTED}\" but got \"${EXPORTED_PROPERTY}\"")
+ endif()
+endfunction()
+
+checkForProperty(bld_testLib3 "EXPORTED_PROPERTY1" "EXPORTING_TESTLIB3")
+checkForProperty(exp_testLib3 "EXPORTED_PROPERTY1" "EXPORTING_TESTLIB3")
+checkForProperty(bld_testLib4 "EXPORTED_PROPERTY2" "EXPORTING_TESTLIB4_1")
+checkForProperty(exp_testLib4 "EXPORTED_PROPERTY2" "EXPORTING_TESTLIB4_1")
+checkForProperty(bld_testLib4 "EXPORTED_PROPERTY3" "EXPORTING_TESTLIB4_2")
+checkForProperty(exp_testLib4 "EXPORTED_PROPERTY3" "EXPORTING_TESTLIB4_2")
+checkForProperty(bld_testLibDeprecation "DEPRECATION" "Deprecated version. Please use latest version")
+checkForProperty(exp_testLibDeprecation "DEPRECATION" "Deprecated version. Please use latest version")
+
+# Try linking to a deprecated library
+target_link_libraries(imp_testExe1 exp_testLibDeprecation)
+
+
+# Try linking to a library imported from the install tree.
+target_link_libraries(imp_testExe1
+ exp_testLib2
+ exp_testLib3
+ exp_testLib4
+ exp_testLib5
+ exp_testLib6
+ exp_testLib7
+ exp_testLibCycleA
+ exp_testLibPerConfigDest
+ )
+
+# Try building a plugin to an executable imported from the install tree.
+add_library(imp_mod1 MODULE imp_mod1.c)
+target_link_libraries(imp_mod1 exp_testExe2)
+
+# Try referencing an executable imported from the build tree.
+add_custom_command(
+ OUTPUT ${Import_BINARY_DIR}/bld_generated.c
+ COMMAND bld_testExe1 ${Import_BINARY_DIR}/bld_generated.c
+ DEPENDS bld_testExe1
+ )
+add_custom_command(
+ OUTPUT ${Import_BINARY_DIR}/bld_generated3.c
+ COMMAND bld_testExe3 ${Import_BINARY_DIR}/bld_generated3.c
+ DEPENDS bld_testExe3
+ )
+add_custom_command(
+ OUTPUT ${Import_BINARY_DIR}/bld_generated4.c
+ COMMAND bld_testExe4 ${Import_BINARY_DIR}/bld_generated4.c
+ DEPENDS bld_testExe4
+ )
+
+add_executable(imp_testExe1b
+ imp_testExe1.c
+ ${Import_BINARY_DIR}/bld_generated.c
+ ${Import_BINARY_DIR}/bld_generated3.c
+ ${Import_BINARY_DIR}/bld_generated4.c
+ )
+
+# Try linking to a library imported from the build tree.
+target_link_libraries(imp_testExe1b
+ bld_testLib2
+ bld_testLib3
+ bld_testLib4
+ bld_testLib5
+ bld_testLib6
+ bld_testLib7
+ bld_testLibCycleA
+ bld_testLibPerConfigDest
+ )
+
+add_custom_target(check_testLib1_genex ALL
+ COMMAND ${CMAKE_COMMAND} -DtestLib1=$<TARGET_FILE:exp_testLib1>
+ -Dprefix=${CMAKE_INSTALL_PREFIX}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/check_testLib1_genex.cmake
+ )
+
+if(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG AND
+ "${CMAKE_C_CREATE_SHARED_MODULE}" MATCHES "SONAME_FLAG")
+ foreach(ns exp bld)
+ get_property(configs TARGET ${ns}_testLib5 PROPERTY IMPORTED_CONFIGURATIONS)
+ foreach(c ${configs})
+ string(TOUPPER "${c}" CONFIG)
+ get_property(soname TARGET ${ns}_testLib5 PROPERTY IMPORTED_NO_SONAME_${CONFIG})
+ if(soname)
+ message(SEND_ERROR "${ns}_testLib5 has IMPORTED_NO_SONAME_${CONFIG} but should:\n ${soname}")
+ else()
+ message(STATUS "${ns}_testLib5 does not have IMPORTED_NO_SONAME_${CONFIG} as expected")
+ endif()
+ endforeach()
+
+ get_property(configs TARGET ${ns}_testLibNoSONAME PROPERTY IMPORTED_CONFIGURATIONS)
+ foreach(c ${configs})
+ string(TOUPPER "${c}" CONFIG)
+ get_property(soname TARGET ${ns}_testLibNoSONAME PROPERTY IMPORTED_NO_SONAME_${CONFIG})
+ if(soname)
+ message(STATUS "${ns}_testLibNoSONAME has IMPORTED_NO_SONAME_${CONFIG} as expected")
+ else()
+ message(SEND_ERROR "${ns}_testLibNoSONAME does not have IMPORTED_NO_SONAME_${CONFIG} but should")
+ endif()
+ endforeach()
+
+ # Parse the binary to check for SONAME if possible.
+ if("${CMAKE_EXECUTABLE_FORMAT}" MATCHES "ELF")
+ find_program(READELF_EXE readelf)
+ if(READELF_EXE)
+ add_custom_target(check_${ns}_testLib5_soname ALL COMMAND
+ ${CMAKE_COMMAND} -Dreadelf=${READELF_EXE}
+ -Dlib=$<TARGET_FILE:${ns}_testLib5>
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/check_lib_soname.cmake
+ )
+ add_custom_target(check_${ns}_testLibNoSONAME_soname ALL COMMAND
+ ${CMAKE_COMMAND} -Dreadelf=${READELF_EXE}
+ -Dlib=$<TARGET_FILE:${ns}_testLibNoSONAME>
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/check_lib_nosoname.cmake
+ )
+ endif()
+ endif()
+ endforeach()
+endif()
+
+add_executable(cmp0022OLD_test cmp0022OLD_test_vs6_1.cpp)
+target_link_libraries(cmp0022OLD_test bld_cmp0022OLD)
+add_executable(cmp0022NEW_test cmp0022NEW_test_vs6_1.cpp)
+target_link_libraries(cmp0022NEW_test bld_cmp0022NEW)
+
+add_executable(cmp0022OLD_exp_test cmp0022OLD_test_vs6_2.cpp)
+target_link_libraries(cmp0022OLD_exp_test exp_cmp0022OLD)
+add_executable(cmp0022NEW_exp_test cmp0022NEW_test_vs6_2.cpp)
+target_link_libraries(cmp0022NEW_exp_test exp_cmp0022NEW)
+
+add_executable(SubDirLink_bld SubDirLink.c)
+target_link_libraries(SubDirLink_bld PRIVATE bld_TopDirLib bld_SubDirLinkA)
+add_executable(SubDirLink_exp SubDirLink.c)
+target_link_libraries(SubDirLink_exp PRIVATE exp_TopDirLib exp_SubDirLinkA)
+
+# Try building a plugin to an executable imported from the build tree.
+add_library(imp_mod1b MODULE imp_mod1.c)
+target_link_libraries(imp_mod1b bld_testExe2)
+
+# Export/CMakeLists.txt pretends the RelWithDebInfo (as well as Debug)
+# configuration should link to debug libs.
+foreach(c DEBUG RELWITHDEBINFO)
+ set_property(TARGET imp_testExe1 PROPERTY COMPILE_DEFINITIONS_${c} EXE_DBG)
+ set_property(TARGET imp_testExe1b PROPERTY COMPILE_DEFINITIONS_${c} EXE_DBG)
+endforeach()
+
+#-----------------------------------------------------------------------------
+include(${CMAKE_INSTALL_PREFIX}/lib/expAbs/expAbs.cmake)
+
+add_executable(imp_testExeAbs1
+ imp_testExeAbs1.c
+ )
+target_link_libraries(imp_testExeAbs1
+ expAbs_testLibAbs1
+ )
+
+#-----------------------------------------------------------------------------
+# Create a custom target to generate a header for the libraries below.
+# Drive the header generation through an indirect chain of imported
+# target dependencies.
+
+# testLib2tmp1.h
+add_custom_command(
+ OUTPUT testLib2tmp1.h
+ VERBATIM COMMAND
+ ${CMAKE_COMMAND} -E echo "extern int testLib2(void);" > testLib2tmp1.h
+ )
+
+# hdr_testLib2tmp1 needs testLib2tmp1.h
+add_custom_target(hdr_testLib2tmp1 DEPENDS testLib2tmp1.h)
+
+# exp_testExe2 needs hdr_testLib2tmp1
+add_dependencies(exp_testExe2 hdr_testLib2tmp1)
+
+# testLib2tmp.h needs exp_testExe2
+add_custom_command(
+ OUTPUT testLib2tmp.h
+ VERBATIM COMMAND exp_testExe2
+ COMMAND ${CMAKE_COMMAND} -E copy testLib2tmp1.h testLib2tmp.h
+ )
+
+# hdr_testLib2tmp needs testLib2tmp.h
+add_custom_target(hdr_testLib2tmp DEPENDS testLib2tmp.h)
+
+add_library(dep_testLib2tmp UNKNOWN IMPORTED)
+set_property(TARGET dep_testLib2tmp PROPERTY
+ IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/testLib2tmp.h)
+
+# dep_testLib2tmp needs hdr_testLib2tmp
+add_dependencies(dep_testLib2tmp hdr_testLib2tmp)
+
+# testLib2.h needs dep_testLib2tmp
+add_custom_command(
+ OUTPUT testLib2.h
+ VERBATIM COMMAND ${CMAKE_COMMAND} -E copy testLib2tmp.h testLib2.h
+ DEPENDS dep_testLib2tmp
+ )
+
+# hdr_testLib2 needs testLib2.h
+add_custom_target(hdr_testLib2 DEPENDS testLib2.h)
+
+add_library(dep_testLib2 UNKNOWN IMPORTED)
+
+# dep_testLib2 needs hdr_testLib2
+add_dependencies(dep_testLib2 hdr_testLib2)
+
+# exp_testLib2 and bld_testLib2 both need dep_testLib2
+add_dependencies(bld_testLib2 dep_testLib2)
+add_dependencies(exp_testLib2 dep_testLib2)
+
+#-----------------------------------------------------------------------------
+# Create a library to be linked by another directory in this project
+# to test transitive linking to otherwise invisible imported targets.
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+add_library(imp_lib1 STATIC imp_lib1.c)
+target_link_libraries(imp_lib1 exp_testLib2)
+add_library(imp_lib1b STATIC imp_lib1.c)
+target_link_libraries(imp_lib1b bld_testLib2)
+
+if(NOT CMAKE_GENERATOR STREQUAL "Xcode" OR NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;$]")
+ set(bld_objlib_type OBJECT_LIBRARY)
+
+ # Create executables using objects imported from the install tree
+ add_executable(imp_testLib8_src imp_testLib8.c $<TARGET_OBJECTS:exp_testLib8>)
+ add_executable(imp_testLib8_link imp_testLib8.c)
+ target_link_libraries(imp_testLib8_link exp_testLib8)
+
+ if(NOT CMAKE_GENERATOR STREQUAL "Xcode" OR NOT XCODE_VERSION VERSION_LESS 5)
+ # Create executables using objects imported from the build tree
+ add_executable(imp_testLib8b_src imp_testLib8.c $<TARGET_OBJECTS:bld_testLib8>)
+ add_executable(imp_testLib8b_link imp_testLib8.c)
+ target_link_libraries(imp_testLib8b_link bld_testLib8)
+ endif()
+else()
+ set(bld_objlib_type INTERFACE_LIBRARY)
+endif()
+
+# Create an executable that uses a library imported from the install tree
+# that itself was built using an object library. Verify we get the usage
+# requirements.
+add_executable(imp_testLib9 imp_testLib9.c)
+target_link_libraries(imp_testLib9 exp_testLib9)
+# Similarly for importing from the build tree.
+add_executable(imp_testLib9b imp_testLib9.c)
+target_link_libraries(imp_testLib9b bld_testLib9)
+
+# Check that object libraries were transformed on export as expected.
+foreach(vis Pub Priv Iface)
+ get_property(type TARGET exp_testLib9Obj${vis} PROPERTY TYPE)
+ if(NOT type STREQUAL INTERFACE_LIBRARY)
+ message(FATAL_ERROR "exp_testLib9Obj${vis} type is '${type}', not 'INTERFACE_LIBRARY'")
+ endif()
+ get_property(type TARGET bld_testLib9Obj${vis} PROPERTY TYPE)
+ if(NOT type STREQUAL "${bld_objlib_type}")
+ message(FATAL_ERROR "bld_testLib9Obj${vis} type is '${type}', not '${bld_objlib_type}'")
+ endif()
+endforeach()
+
+#-----------------------------------------------------------------------------
+# Test that handling imported targets, including transitive dependencies,
+# works in CheckFunctionExists (...and hopefully all other try_compile() checks
+include(CheckFunctionExists)
+unset(HAVE_TESTLIB1_FUNCTION CACHE)
+set(CMAKE_REQUIRED_LIBRARIES exp_testLib2)
+check_function_exists(testLib1 HAVE_TESTLIB1_FUNCTION)
+if (NOT HAVE_TESTLIB1_FUNCTION)
+ message(SEND_ERROR "Using imported target testLib2 in check_function_exists() failed !")
+endif()
+
+#-----------------------------------------------------------------------------
+# Test that dependent imported targets have usable
+# INTERFACE_COMPILE_DEFINITIONS and INTERFACE_INCLUDE_DIRECTORIES
+
+add_executable(deps_iface deps_iface.c)
+target_link_libraries(deps_iface testLibDepends)
+
+add_executable(deps_shared_iface deps_shared_iface.cpp)
+target_link_libraries(deps_shared_iface testSharedLibDepends)
+target_compile_definitions(deps_shared_iface
+ PRIVATE
+ $<$<BOOL:$<TARGET_PROPERTY:POSITION_INDEPENDENT_CODE>>:PIC_PROPERTY_IS_ON>
+ $<$<BOOL:$<TARGET_PROPERTY:CUSTOM_PROP>>:CUSTOM_PROPERTY_IS_ON>
+ $<$<STREQUAL:$<TARGET_PROPERTY:CUSTOM_STRING>,testcontent>:CUSTOM_STRING_IS_MATCH>
+)
+
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ target_compile_definitions(deps_shared_iface
+ PRIVATE
+ "DO_GNU_TESTS"
+ )
+endif()
+
+if (APPLE OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ include(CheckCXXCompilerFlag)
+ check_cxx_compiler_flag(-fPIE run_pic_test)
+else()
+ if (CMAKE_CXX_COMPILER_ID MATCHES "PGI"
+ OR CMAKE_CXX_COMPILER_ID MATCHES "PathScale"
+ OR CMAKE_CXX_COMPILER_ID MATCHES "Intel")
+ set(run_pic_test 0)
+ else()
+ set(run_pic_test 1)
+ endif()
+endif()
+
+add_executable(exp_renamed_test renamed_test.cpp)
+target_link_libraries(exp_renamed_test exp_renamed)
+
+add_executable(bld_renamed_test renamed_test.cpp)
+target_link_libraries(bld_renamed_test bld_renamed)
+
+if (run_pic_test)
+ target_compile_definitions(deps_shared_iface PRIVATE CHECK_PIC_WORKS)
+endif()
+
+if(APPLE)
+ add_subdirectory(framework_interface)
+endif()
+
+#-----------------------------------------------------------------------------
+# Test that targets imported from the build tree have their dependencies
+# evaluated correctly. The above already tests the same for the install tree.
+
+add_executable(deps_shared_iface2 deps_shared_iface.cpp)
+target_link_libraries(deps_shared_iface2 bld_testSharedLibDepends bld_subdirlib)
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+ target_compile_definitions(deps_shared_iface2
+ PRIVATE
+ "DO_GNU_TESTS"
+ )
+endif()
+target_compile_definitions(deps_shared_iface2
+ PRIVATE TEST_SUBDIR_LIB
+ $<$<BOOL:$<TARGET_PROPERTY:POSITION_INDEPENDENT_CODE>>:PIC_PROPERTY_IS_ON>
+ $<$<BOOL:$<TARGET_PROPERTY:CUSTOM_PROP>>:CUSTOM_PROPERTY_IS_ON>
+ $<$<STREQUAL:$<TARGET_PROPERTY:CUSTOM_STRING>,testcontent>:CUSTOM_STRING_IS_MATCH>
+)
+
+add_subdirectory(excludedFromAll)
+
+add_executable(iface_test_bld iface_test.cpp)
+target_link_libraries(iface_test_bld bld_testSharedLibDepends)
+set_property(TARGET iface_test_bld PROPERTY NO_SYSTEM_FROM_IMPORTED 1)
+
+set_property(TARGET bld_testSharedLibRequired APPEND PROPERTY
+ LINK_INTERFACE_LIBRARIES
+ excludedFromAll
+)
+get_target_property(_configs bld_testSharedLibRequired IMPORTED_CONFIGURATIONS)
+foreach(_config ${_configs})
+ set_property(TARGET bld_testSharedLibRequired APPEND PROPERTY
+ IMPORTED_LINK_INTERFACE_LIBRARIES_${_config}
+ excludedFromAll
+ )
+endforeach()
+unset(_configs)
+add_executable(iface_test_exp iface_test.cpp)
+target_link_libraries(iface_test_exp testSharedLibDepends)
+
+set_property(TARGET testSharedLibDepends APPEND PROPERTY
+ LINK_INTERFACE_LIBRARIES
+ excludedFromAll
+)
+get_target_property(_configs testSharedLibDepends IMPORTED_CONFIGURATIONS)
+foreach(_config ${_configs})
+ set_property(TARGET testSharedLibDepends APPEND PROPERTY
+ IMPORTED_LINK_INTERFACE_LIBRARIES_${_config}
+ excludedFromAll
+ )
+endforeach()
+unset(_configs)
+
+if (((CMAKE_C_COMPILER_ID STREQUAL GNU AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.4)
+ OR (CMAKE_C_COMPILER_ID STREQUAL Clang AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC"))
+ AND (CMAKE_GENERATOR STREQUAL "Unix Makefiles" OR CMAKE_GENERATOR STREQUAL "Ninja"))
+ include(CheckCXXCompilerFlag)
+ check_cxx_compiler_flag(-Wunused-variable run_sys_includes_test)
+ if(run_sys_includes_test)
+ # The Bullseye wrapper appears to break the -isystem effect.
+ execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE out ERROR_VARIABLE out)
+ if("x${out}" MATCHES "Bullseye")
+ set(run_sys_includes_test 0)
+ endif()
+ endif()
+ if (run_sys_includes_test)
+ add_executable(test_system_exp test_system.cpp)
+ target_link_libraries(test_system_exp exp_systemlib)
+ target_compile_options(test_system_exp PRIVATE -Wunused-variable -Werror=unused-variable)
+
+ unset(EXP_ERROR_VARIABLE CACHE)
+ try_compile(EXP_ERROR_VARIABLE
+ "${CMAKE_CURRENT_SOURCE_DIR}/test_system"
+ "${CMAKE_CURRENT_SOURCE_DIR}/test_system.cpp"
+ COMPILE_DEFINITIONS "-Wunused-variable -Werror=unused-variable"
+ LINK_LIBRARIES exp_systemlib
+ OUTPUT_VARIABLE OUTPUT
+ )
+ if(NOT EXP_ERROR_VARIABLE)
+ message(SEND_ERROR "EXP_ERROR_VARIABLE try_compile failed, but it was expected to succeed ${OUTPUT}.")
+ endif()
+
+ if(NOT CMAKE_CROSSCOMPILING)
+ unset(EXP_RUN_VAR CACHE)
+ unset(EXP_COMPILE_VAR CACHE)
+ try_run(EXP_RUN_VAR EXP_COMPILE_VAR
+ "${CMAKE_CURRENT_SOURCE_DIR}/test_system"
+ "${CMAKE_CURRENT_SOURCE_DIR}/test_system.cpp"
+ COMPILE_DEFINITIONS "-Wunused-variable -Werror=unused-variable"
+ LINK_LIBRARIES exp_systemlib
+ OUTPUT_VARIABLE OUTPUT
+ )
+ if(NOT EXP_COMPILE_VAR)
+ message(SEND_ERROR "try_run compile failed, but it was expected to succeed ${OUTPUT}.")
+ endif()
+ endif()
+
+ add_executable(test_system_bld test_system.cpp)
+ target_link_libraries(test_system_bld bld_systemlib)
+ target_compile_options(test_system_bld PRIVATE -Wunused-variable -Werror=unused-variable)
+
+ unset(BLD_ERROR_VARIABLE CACHE)
+ try_compile(BLD_ERROR_VARIABLE
+ "${CMAKE_CURRENT_SOURCE_DIR}/test_system"
+ "${CMAKE_CURRENT_SOURCE_DIR}/test_system.cpp"
+ COMPILE_DEFINITIONS "-Wunused-variable -Werror=unused-variable"
+ LINK_LIBRARIES bld_systemlib
+ OUTPUT_VARIABLE OUTPUT
+ )
+ if(NOT BLD_ERROR_VARIABLE)
+ message(SEND_ERROR "BLD_ERROR_VARIABLE try_compile failed, but it was expected to succeed.")
+ endif()
+
+ if(NOT CMAKE_CROSSCOMPILING)
+ unset(BLD_RUN_VAR CACHE)
+ unset(BLD_COMPILE_VAR CACHE)
+ try_run(BLD_RUN_VAR BLD_COMPILE_VAR
+ "${CMAKE_CURRENT_SOURCE_DIR}/test_system"
+ "${CMAKE_CURRENT_SOURCE_DIR}/test_system.cpp"
+ COMPILE_DEFINITIONS "-Wunused-variable -Werror=unused-variable"
+ LINK_LIBRARIES bld_systemlib
+ OUTPUT_VARIABLE OUTPUT
+ )
+ if(NOT BLD_COMPILE_VAR)
+ message(SEND_ERROR "try_run compile failed, but it was expected to succeed ${OUTPUT}.")
+ endif()
+ endif()
+ endif()
+endif()
+
+#---------------------------------------------------------------------------------
+# check that imported libraries have the expected INTERFACE_LINK_OPTIONS property
+checkForProperty(bld_testLinkOptions "INTERFACE_LINK_OPTIONS" "INTERFACE_FLAG")
+checkForProperty(Req::testLinkOptions "INTERFACE_LINK_OPTIONS" "INTERFACE_FLAG")
+
+#---------------------------------------------------------------------------------
+# check that imported libraries have the expected INTERFACE_LINK_DIRECTORIES property
+checkForProperty(bld_testLinkDirectories "INTERFACE_LINK_DIRECTORIES" "/interface/build")
+checkForProperty(Req::testLinkDirectories "INTERFACE_LINK_DIRECTORIES" "${CMAKE_INSTALL_PREFIX}/interface/install")
+
+#---------------------------------------------------------------------------------
+# check that imported libraries have the expected INTERFACE_LINK_DEPENDS property
+if(CMAKE_GENERATOR MATCHES "Make|Ninja")
+ checkForProperty(bld_testLinkDepends "INTERFACE_LINK_DEPENDS" "BUILD_LINK_DEPENDS")
+ checkForProperty(Req::testLinkDepends "INTERFACE_LINK_DEPENDS" "${CMAKE_INSTALL_PREFIX}/INSTALL_LINK_DEPENDS")
+endif()
+
+#------------------------------------------------------------------------------
+# test import of CUDA language level
+if(CMake_TEST_CUDA)
+ checkForProperty(bld_cudaInterfaceLib "INTERFACE_COMPILE_FEATURES" "cuda_std_11")
+ checkForProperty(Req::cudaInterfaceLib "INTERFACE_COMPILE_FEATURES" "cuda_std_14")
+endif()
diff --git a/Tests/ExportImport/Import/A/SubDirLink.c b/Tests/ExportImport/Import/A/SubDirLink.c
new file mode 100644
index 0000000..eb4b860
--- /dev/null
+++ b/Tests/ExportImport/Import/A/SubDirLink.c
@@ -0,0 +1,14 @@
+#ifndef DEF_SubDirLinkAImportedForImport
+# error "DEF_SubDirLinkAImportedForImport is not defined but should be!"
+#endif
+#ifndef DEF_SubDirLinkBImportedForImport
+# error "DEF_SubDirLinkBImportedForImport is not defined but should be!"
+#endif
+
+extern int testTopDirLib(void);
+extern int testSubDirLinkA(void);
+
+int main(void)
+{
+ return (testTopDirLib() + testSubDirLinkA() + 0);
+}
diff --git a/Tests/ExportImport/Import/A/check_lib_nosoname.cmake b/Tests/ExportImport/Import/A/check_lib_nosoname.cmake
new file mode 100644
index 0000000..613391e
--- /dev/null
+++ b/Tests/ExportImport/Import/A/check_lib_nosoname.cmake
@@ -0,0 +1,7 @@
+execute_process(COMMAND ${readelf} -d ${lib} OUTPUT_FILE ${lib}.readelf.txt)
+file(STRINGS ${lib}.readelf.txt soname REGEX "SONAME")
+if(soname)
+ message(FATAL_ERROR "${lib} has soname but should not:\n ${soname}")
+else()
+ message(STATUS "${lib} has no soname as expected:\n ${soname}")
+endif()
diff --git a/Tests/ExportImport/Import/A/check_lib_soname.cmake b/Tests/ExportImport/Import/A/check_lib_soname.cmake
new file mode 100644
index 0000000..a3c4b54
--- /dev/null
+++ b/Tests/ExportImport/Import/A/check_lib_soname.cmake
@@ -0,0 +1,7 @@
+execute_process(COMMAND ${readelf} -d ${lib} OUTPUT_FILE ${lib}.readelf.txt)
+file(STRINGS ${lib}.readelf.txt soname REGEX "SONAME")
+if(soname)
+ message(STATUS "${lib} has soname as expected:\n ${soname}")
+else()
+ message(FATAL_ERROR "${lib} has no soname but should:\n ${soname}")
+endif()
diff --git a/Tests/ExportImport/Import/A/check_testLib1_genex.cmake b/Tests/ExportImport/Import/A/check_testLib1_genex.cmake
new file mode 100644
index 0000000..7c02652
--- /dev/null
+++ b/Tests/ExportImport/Import/A/check_testLib1_genex.cmake
@@ -0,0 +1,11 @@
+foreach(f
+ "${testLib1}.genex"
+ "${prefix}/doc/testLib1file1.txt"
+ "${prefix}/doc/testLib1file2.txt"
+ )
+ if(EXISTS "${f}")
+ message(STATUS "'${f}' exists!")
+ else()
+ message(FATAL_ERROR "Missing file:\n ${f}")
+ endif()
+endforeach()
diff --git a/Tests/ExportImport/Import/A/cmp0022NEW_test.cpp b/Tests/ExportImport/Import/A/cmp0022NEW_test.cpp
new file mode 100644
index 0000000..778b828
--- /dev/null
+++ b/Tests/ExportImport/Import/A/cmp0022NEW_test.cpp
@@ -0,0 +1,12 @@
+
+#ifndef USING_TESTLIB2
+# error Expected USING_TESTLIB2
+#endif
+#ifdef USING_TESTLIB3
+# error Unexpected USING_TESTLIB3
+#endif
+
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Import/A/cmp0022NEW_test_vs6_1.cpp b/Tests/ExportImport/Import/A/cmp0022NEW_test_vs6_1.cpp
new file mode 100644
index 0000000..033b746
--- /dev/null
+++ b/Tests/ExportImport/Import/A/cmp0022NEW_test_vs6_1.cpp
@@ -0,0 +1 @@
+#include "cmp0022NEW_test.cpp"
diff --git a/Tests/ExportImport/Import/A/cmp0022NEW_test_vs6_2.cpp b/Tests/ExportImport/Import/A/cmp0022NEW_test_vs6_2.cpp
new file mode 100644
index 0000000..033b746
--- /dev/null
+++ b/Tests/ExportImport/Import/A/cmp0022NEW_test_vs6_2.cpp
@@ -0,0 +1 @@
+#include "cmp0022NEW_test.cpp"
diff --git a/Tests/ExportImport/Import/A/cmp0022OLD_test.cpp b/Tests/ExportImport/Import/A/cmp0022OLD_test.cpp
new file mode 100644
index 0000000..9eaaee9
--- /dev/null
+++ b/Tests/ExportImport/Import/A/cmp0022OLD_test.cpp
@@ -0,0 +1,12 @@
+
+#ifdef USING_TESTLIB2
+# error Unexpected USING_TESTLIB2
+#endif
+#ifndef USING_TESTLIB3
+# error Expected USING_TESTLIB3
+#endif
+
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Import/A/cmp0022OLD_test_vs6_1.cpp b/Tests/ExportImport/Import/A/cmp0022OLD_test_vs6_1.cpp
new file mode 100644
index 0000000..90d804c
--- /dev/null
+++ b/Tests/ExportImport/Import/A/cmp0022OLD_test_vs6_1.cpp
@@ -0,0 +1 @@
+#include "cmp0022OLD_test.cpp"
diff --git a/Tests/ExportImport/Import/A/cmp0022OLD_test_vs6_2.cpp b/Tests/ExportImport/Import/A/cmp0022OLD_test_vs6_2.cpp
new file mode 100644
index 0000000..90d804c
--- /dev/null
+++ b/Tests/ExportImport/Import/A/cmp0022OLD_test_vs6_2.cpp
@@ -0,0 +1 @@
+#include "cmp0022OLD_test.cpp"
diff --git a/Tests/ExportImport/Import/A/deps_iface.c b/Tests/ExportImport/Import/A/deps_iface.c
new file mode 100644
index 0000000..afb1af0
--- /dev/null
+++ b/Tests/ExportImport/Import/A/deps_iface.c
@@ -0,0 +1,32 @@
+
+#include "installIncludesTest.h"
+#include "installIncludesTest2.h"
+#include "installIncludesTest3.h"
+#include "installIncludesTest4.h"
+#include "installIncludesTest5.h"
+#include "installIncludesTest6.h"
+#include "installIncludesTest7.h"
+#include "installIncludesTest8.h"
+#include "testLibIncludeRequired1.h"
+#include "testLibIncludeRequired2.h"
+#include "testLibIncludeRequired6.h"
+#include "testLibIncludeRequired7.h"
+
+#ifndef testLibRequired_IFACE_DEFINE
+# error Expected testLibRequired_IFACE_DEFINE
+#endif
+
+#ifdef BuildOnly_DEFINE
+# error Unexpected BuildOnly_DEFINE
+#endif
+
+#ifndef InstallOnly_DEFINE
+# error Expected InstallOnly_DEFINE
+#endif
+
+extern int testLibDepends(void);
+
+int main()
+{
+ return testLibDepends();
+}
diff --git a/Tests/ExportImport/Import/A/deps_shared_iface.cpp b/Tests/ExportImport/Import/A/deps_shared_iface.cpp
new file mode 100644
index 0000000..d239fb4
--- /dev/null
+++ b/Tests/ExportImport/Import/A/deps_shared_iface.cpp
@@ -0,0 +1,49 @@
+
+
+#include "testSharedLibDepends.h"
+
+#ifdef CHECK_PIC_WORKS
+# if defined(__ELF__) && !defined(__PIC__) && !defined(__PIE__)
+# error Expected by INTERFACE_POSITION_INDEPENDENT_CODE property of dependency
+# endif
+#endif
+
+#ifndef PIC_PROPERTY_IS_ON
+# error Expected PIC_PROPERTY_IS_ON
+#endif
+
+#ifndef CUSTOM_PROPERTY_IS_ON
+# error Expected CUSTOM_PROPERTY_IS_ON
+#endif
+
+#ifndef CUSTOM_STRING_IS_MATCH
+# error Expected CUSTOM_STRING_IS_MATCH
+#endif
+
+#ifdef TEST_SUBDIR_LIB
+# include "renamed.h"
+# include "subdir.h"
+#endif
+
+#ifdef DO_GNU_TESTS
+# ifndef CUSTOM_COMPILE_OPTION
+# error Expected CUSTOM_COMPILE_OPTION
+# endif
+#endif
+
+int main(int, char**)
+{
+ TestSharedLibDepends dep;
+ TestSharedLibRequired req;
+
+#ifdef TEST_SUBDIR_LIB
+ SubDirObject sdo;
+ Renamed ren;
+#endif
+
+ return dep.foo() + req.foo()
+#ifdef TEST_SUBDIR_LIB
+ + sdo.foo() + ren.foo()
+#endif
+ ;
+}
diff --git a/Tests/ExportImport/Import/A/excludedFromAll/CMakeLists.txt b/Tests/ExportImport/Import/A/excludedFromAll/CMakeLists.txt
new file mode 100644
index 0000000..cd5a59b
--- /dev/null
+++ b/Tests/ExportImport/Import/A/excludedFromAll/CMakeLists.txt
@@ -0,0 +1,7 @@
+
+set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+include(GenerateExportHeader)
+add_library(excludedFromAll SHARED EXCLUDE_FROM_ALL excludedFromAll.cpp)
+generate_export_header(excludedFromAll)
diff --git a/Tests/ExportImport/Import/A/excludedFromAll/excludedFromAll.cpp b/Tests/ExportImport/Import/A/excludedFromAll/excludedFromAll.cpp
new file mode 100644
index 0000000..2269a04
--- /dev/null
+++ b/Tests/ExportImport/Import/A/excludedFromAll/excludedFromAll.cpp
@@ -0,0 +1,7 @@
+
+#include "excludedFromAll.h"
+
+int excludedFromAll()
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Import/A/excludedFromAll/excludedFromAll.h b/Tests/ExportImport/Import/A/excludedFromAll/excludedFromAll.h
new file mode 100644
index 0000000..4820c76
--- /dev/null
+++ b/Tests/ExportImport/Import/A/excludedFromAll/excludedFromAll.h
@@ -0,0 +1,4 @@
+
+#include "excludedfromall_export.h"
+
+int EXCLUDEDFROMALL_EXPORT excludedFromAll();
diff --git a/Tests/ExportImport/Import/A/framework_interface/CMakeLists.txt b/Tests/ExportImport/Import/A/framework_interface/CMakeLists.txt
new file mode 100644
index 0000000..0e00655
--- /dev/null
+++ b/Tests/ExportImport/Import/A/framework_interface/CMakeLists.txt
@@ -0,0 +1,9 @@
+
+add_library(exp_framework_test framework_test.cpp)
+get_target_property(exp_loc exp_testLib4 LOCATION)
+target_link_libraries(exp_framework_test ${exp_loc})
+
+
+add_library(bld_framework_test framework_test.cpp)
+get_target_property(bld_loc bld_testLib4 LOCATION)
+target_link_libraries(bld_framework_test ${bld_loc})
diff --git a/Tests/ExportImport/Import/A/framework_interface/framework_test.cpp b/Tests/ExportImport/Import/A/framework_interface/framework_test.cpp
new file mode 100644
index 0000000..ddb8c4b
--- /dev/null
+++ b/Tests/ExportImport/Import/A/framework_interface/framework_test.cpp
@@ -0,0 +1,6 @@
+
+#include <testLib4/testLib4.h>
+
+#ifndef TESTLIB4_H
+# error Expected define TESTLIB4_H
+#endif
diff --git a/Tests/ExportImport/Import/A/iface_test.cpp b/Tests/ExportImport/Import/A/iface_test.cpp
new file mode 100644
index 0000000..4428c1c
--- /dev/null
+++ b/Tests/ExportImport/Import/A/iface_test.cpp
@@ -0,0 +1,11 @@
+
+#ifndef USING_TESTSHAREDLIBREQUIRED
+# error Expected USING_TESTSHAREDLIBREQUIRED
+#endif
+
+#include "excludedFromAll.h"
+
+int main(void)
+{
+ return excludedFromAll();
+}
diff --git a/Tests/ExportImport/Import/A/imp_lib1.c b/Tests/ExportImport/Import/A/imp_lib1.c
new file mode 100644
index 0000000..5b3215e
--- /dev/null
+++ b/Tests/ExportImport/Import/A/imp_lib1.c
@@ -0,0 +1,6 @@
+#include "testLib2.h"
+
+int imp_lib1(void)
+{
+ return testLib2();
+}
diff --git a/Tests/ExportImport/Import/A/imp_mod1.c b/Tests/ExportImport/Import/A/imp_mod1.c
new file mode 100644
index 0000000..9385d55
--- /dev/null
+++ b/Tests/ExportImport/Import/A/imp_mod1.c
@@ -0,0 +1,13 @@
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define testExe2_IMPORT __declspec(dllimport)
+#else
+# define testExe2_IMPORT
+#endif
+
+testExe2_IMPORT int testExe2Func(void);
+testExe2_IMPORT int testExe2lib(void);
+
+int imp_mod1()
+{
+ return testExe2Func() + testExe2lib();
+}
diff --git a/Tests/ExportImport/Import/A/imp_testExe1.c b/Tests/ExportImport/Import/A/imp_testExe1.c
new file mode 100644
index 0000000..8173557
--- /dev/null
+++ b/Tests/ExportImport/Import/A/imp_testExe1.c
@@ -0,0 +1,29 @@
+extern int generated_by_testExe1(void);
+extern int generated_by_testExe3(void);
+extern int generated_by_testExe4(void);
+extern int testLib2(void);
+extern int testLib3(void);
+extern int testLib4(void);
+extern int testLib4lib(void);
+extern int testLib5(void);
+extern int testLib6(void);
+extern int testLib7(void);
+extern int testLibCycleA1(void);
+extern int testLibPerConfigDest(void);
+
+/* Switch a symbol between debug and optimized builds to make sure the
+ proper library is found from the testLib4 link interface. */
+#ifdef EXE_DBG
+# define testLib4libcfg testLib4libdbg
+#else
+# define testLib4libcfg testLib4libopt
+#endif
+extern testLib4libcfg(void);
+
+int main()
+{
+ return (testLib2() + generated_by_testExe1() + testLib3() + testLib4() +
+ testLib5() + testLib6() + testLib7() + testLibCycleA1() +
+ testLibPerConfigDest() + generated_by_testExe3() +
+ generated_by_testExe4() + testLib4lib() + testLib4libcfg());
+}
diff --git a/Tests/ExportImport/Import/A/imp_testExeAbs1.c b/Tests/ExportImport/Import/A/imp_testExeAbs1.c
new file mode 100644
index 0000000..fd05242
--- /dev/null
+++ b/Tests/ExportImport/Import/A/imp_testExeAbs1.c
@@ -0,0 +1,13 @@
+#include "testLibAbs1.h"
+#include "testLibAbs1a.h"
+#include "testLibAbs1b.h"
+#ifndef testLibAbs1a
+# error "testLibAbs1a not defined"
+#endif
+#ifndef testLibAbs1b
+# error "testLibAbs1b not defined"
+#endif
+int main()
+{
+ return 0 + testLibAbs1();
+}
diff --git a/Tests/ExportImport/Import/A/imp_testLib8.c b/Tests/ExportImport/Import/A/imp_testLib8.c
new file mode 100644
index 0000000..2749b17
--- /dev/null
+++ b/Tests/ExportImport/Import/A/imp_testLib8.c
@@ -0,0 +1,8 @@
+
+int testLib8A(void);
+int testLib8B(void);
+
+int main()
+{
+ return (testLib8A() + testLib8B());
+}
diff --git a/Tests/ExportImport/Import/A/imp_testLib9.c b/Tests/ExportImport/Import/A/imp_testLib9.c
new file mode 100644
index 0000000..e014857
--- /dev/null
+++ b/Tests/ExportImport/Import/A/imp_testLib9.c
@@ -0,0 +1,16 @@
+#ifndef testLib9ObjPub_USED
+# error "testLib9ObjPub_USED not defined!"
+#endif
+#ifdef testLib9ObjPriv_USED
+# error "testLib9ObjPriv_USED defined but should not be!"
+#endif
+#ifndef testLib9ObjIface_USED
+# error "testLib9ObjIface_USED not defined!"
+#endif
+
+int testLib9(void);
+
+int main()
+{
+ return testLib9();
+}
diff --git a/Tests/ExportImport/Import/A/imp_testLinkOptions.cpp b/Tests/ExportImport/Import/A/imp_testLinkOptions.cpp
new file mode 100644
index 0000000..2b18b2e
--- /dev/null
+++ b/Tests/ExportImport/Import/A/imp_testLinkOptions.cpp
@@ -0,0 +1,8 @@
+
+#include "testSharedLibRequired.h"
+
+int foo()
+{
+ TestSharedLibRequired req;
+ return req.foo();
+}
diff --git a/Tests/ExportImport/Import/A/renamed_test.cpp b/Tests/ExportImport/Import/A/renamed_test.cpp
new file mode 100644
index 0000000..60d6cf9
--- /dev/null
+++ b/Tests/ExportImport/Import/A/renamed_test.cpp
@@ -0,0 +1,8 @@
+
+#include "renamed.h"
+
+int main(int, char**)
+{
+ Renamed ren;
+ return ren.foo();
+}
diff --git a/Tests/ExportImport/Import/A/test_system.cpp b/Tests/ExportImport/Import/A/test_system.cpp
new file mode 100644
index 0000000..aae3583
--- /dev/null
+++ b/Tests/ExportImport/Import/A/test_system.cpp
@@ -0,0 +1,9 @@
+
+#include "systemlib.h"
+
+int main()
+{
+ SystemStruct s;
+ (void)s;
+ return 0;
+}
diff --git a/Tests/ExportImport/Import/CMakeLists.txt b/Tests/ExportImport/Import/CMakeLists.txt
new file mode 100644
index 0000000..a8a98fc
--- /dev/null
+++ b/Tests/ExportImport/Import/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required (VERSION 2.7.20090711)
+cmake_policy(SET CMP0025 NEW)
+project(Import C CXX)
+
+# Import everything in a subdirectory.
+add_subdirectory(A)
+
+# Make sure the imported targets are scoped inside the subdirectory.
+if(TARGET exp_testLib2)
+ message(FATAL_ERROR "Imported target exp_testLib2 is not scoped in subdir!")
+endif()
+if(TARGET bld_testLib2)
+ message(FATAL_ERROR "Imported target bld_testLib2 is not scoped in subdir!")
+endif()
+
+# Test transitive linking to a target imported in the subdirectory.
+add_executable(imp_testTransExe1 imp_testTransExe1.c)
+target_link_libraries(imp_testTransExe1 imp_lib1)
+add_executable(imp_testTransExe1b imp_testTransExe1.c)
+target_link_libraries(imp_testTransExe1b imp_lib1b)
+
+add_subdirectory(try_compile)
+
+# Test package INTERFACE controls
+add_subdirectory(Interface)
+
+# Test package version range
+add_subdirectory(version_range)
diff --git a/Tests/ExportImport/Import/Interface/CMakeLists.txt b/Tests/ExportImport/Import/Interface/CMakeLists.txt
new file mode 100644
index 0000000..202c23e
--- /dev/null
+++ b/Tests/ExportImport/Import/Interface/CMakeLists.txt
@@ -0,0 +1,137 @@
+
+# Import targets from the exported build tree.
+include(${Import_BINARY_DIR}/../Export/ExportInterfaceBuildTree.cmake)
+
+# Import targets from the exported install tree.
+include(${CMAKE_INSTALL_PREFIX}/lib/exp/expInterface.cmake)
+
+add_library(define_iface INTERFACE)
+set_property(TARGET define_iface PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS DEFINE_IFACE_DEFINE)
+
+add_executable(headeronlytest_bld headeronlytest.cpp)
+target_link_libraries(headeronlytest_bld bld::headeronly)
+
+add_executable(headergentest_bld headergentest.cpp)
+target_link_libraries(headergentest_bld bld::headergen)
+
+set_property(TARGET bld::sharediface APPEND PROPERTY INTERFACE_LINK_LIBRARIES define_iface)
+
+add_executable(interfacetest_bld interfacetest.cpp)
+target_link_libraries(interfacetest_bld bld::sharediface)
+
+include(CheckCSourceCompiles)
+include(CheckCXXSourceCompiles)
+
+macro(do_try_compile prefix)
+
+ set(CMAKE_REQUIRED_LIBRARIES ${prefix}::headeronly)
+ check_cxx_source_compiles(
+ "
+ #include \"headeronly.h\"
+
+ #ifndef HEADERONLY_DEFINE
+ #error Expected HEADERONLY_DEFINE
+ #endif
+
+ int main(int,char**)
+ {
+ HeaderOnly ho;
+ return ho.foo();
+ }
+ " ${prefix}IFACE_TRY_COMPILE)
+
+ if(NOT ${prefix}IFACE_TRY_COMPILE)
+ message(SEND_ERROR "${prefix} try_compile with IMPORTED INTERFACE target failed!\n\n${OUTPUT}")
+ endif()
+
+ if (";${CMAKE_C_COMPILE_FEATURES};" MATCHES ";c_restrict;")
+ set(CMAKE_REQUIRED_LIBRARIES ${prefix}::use_c_restrict)
+ check_c_source_compiles(
+ "
+ int foo(int * restrict a, int * restrict b)
+ {
+ (void)a;
+ (void)b;
+ return 0;
+ }
+ int main()
+ {
+ return 0;
+ }
+ " ${prefix}IMPORTED_IFACE_C_RESTRICT)
+
+ if(NOT ${prefix}IMPORTED_IFACE_C_RESTRICT)
+ message(SEND_ERROR "${prefix} try_compile with IMPORTED INTERFACE target failed!\n\n${OUTPUT}")
+ endif()
+ endif()
+ if (";${CMAKE_CXX_COMPILE_FEATURES};" MATCHES ";cxx_auto_type;")
+ set(CMAKE_REQUIRED_LIBRARIES ${prefix}::use_auto_type)
+ check_cxx_source_compiles(
+ "
+ int main(int,char**)
+ {
+ auto value = 0;
+ return value;
+ }
+ " ${prefix}IMPORTED_IFACE_AUTO_TYPE)
+
+ if(NOT ${prefix}IMPORTED_IFACE_AUTO_TYPE)
+ message(SEND_ERROR "${prefix} try_compile with IMPORTED INTERFACE target failed!\n\n${OUTPUT}")
+ endif()
+ endif()
+
+endmacro()
+
+do_try_compile(bld)
+
+add_executable(source_target_test_bld source_target_test.cpp)
+target_link_libraries(source_target_test_bld bld::source_target)
+target_compile_definitions(source_target_test_bld PRIVATE USE_FROM_BUILD_DIR)
+
+add_executable(source_target_test_exp source_target_test.cpp)
+target_link_libraries(source_target_test_exp exp::source_target)
+target_compile_definitions(source_target_test_exp PRIVATE USE_FROM_INSTALL_DIR)
+
+add_executable(headeronlytest_exp headeronlytest.cpp)
+target_link_libraries(headeronlytest_exp exp::headeronly)
+
+add_executable(headergentest_exp headergentest.cpp)
+target_link_libraries(headergentest_exp exp::headergen)
+
+set_property(TARGET exp::sharediface APPEND PROPERTY INTERFACE_LINK_LIBRARIES define_iface)
+
+add_executable(interfacetest_exp interfacetest.cpp)
+target_link_libraries(interfacetest_exp exp::sharediface)
+
+if(NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;$]" OR CMAKE_GENERATOR STREQUAL "Xcode")
+ add_executable(pch_iface_test_bld pch_iface_test.cpp)
+ target_link_libraries(pch_iface_test_bld bld::pch_iface)
+ add_executable(pch_iface_test_exp pch_iface_test.cpp)
+ target_link_libraries(pch_iface_test_exp exp::pch_iface)
+ if(CMAKE_CXX_COMPILE_OPTIONS_USE_PCH)
+ target_compile_definitions(pch_iface_test_bld PRIVATE EXPECT_PCH)
+ target_compile_definitions(pch_iface_test_exp PRIVATE EXPECT_PCH)
+ endif()
+endif()
+
+do_try_compile(exp)
+
+foreach(ns exp bld)
+ get_property(defs TARGET ${ns}::cmakeonly PROPERTY INTERFACE_COMPILE_DEFINITIONS)
+ if(NOT defs STREQUAL [[DEF="\"\$\B"]])
+ message(SEND_ERROR
+ "${ns}::cmakeonly property INTERFACE_COMPILE_DEFINITIONS is:\n"
+ " ${defs}\n"
+ "not\n"
+ " " [[DEF="\"\$\B"]] "\n")
+ endif()
+ get_property(custom TARGET ${ns}::cmakeonly PROPERTY custom_property)
+ if(NOT custom STREQUAL "CustomPropertyValue")
+ message(SEND_ERROR
+ "${ns}::cmakeonly property custom_property is:\n"
+ " ${custom}\n"
+ "not\n"
+ " CustomPropertyValue\n")
+ endif()
+endforeach()
diff --git a/Tests/ExportImport/Import/Interface/headergentest.cpp b/Tests/ExportImport/Import/Interface/headergentest.cpp
new file mode 100644
index 0000000..88ff7f1
--- /dev/null
+++ b/Tests/ExportImport/Import/Interface/headergentest.cpp
@@ -0,0 +1,11 @@
+
+#include "headergen.h"
+
+#ifndef HEADERGEN_H
+# error Expected HEADERGEN_H
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Import/Interface/headeronlytest.cpp b/Tests/ExportImport/Import/Interface/headeronlytest.cpp
new file mode 100644
index 0000000..7b63a04
--- /dev/null
+++ b/Tests/ExportImport/Import/Interface/headeronlytest.cpp
@@ -0,0 +1,16 @@
+
+#include "headeronly.h"
+
+#ifndef HEADERONLY_DEFINE
+# error Expected HEADERONLY_DEFINE
+#endif
+
+#ifdef SHAREDLIB_DEFINE
+# error Unexpected SHAREDLIB_DEFINE
+#endif
+
+int main(int, char**)
+{
+ HeaderOnly ho;
+ return ho.foo();
+}
diff --git a/Tests/ExportImport/Import/Interface/interfacetest.cpp b/Tests/ExportImport/Import/Interface/interfacetest.cpp
new file mode 100644
index 0000000..c1e29c2
--- /dev/null
+++ b/Tests/ExportImport/Import/Interface/interfacetest.cpp
@@ -0,0 +1,20 @@
+
+#include "sharedlib.h"
+
+#ifndef SHAREDLIB_DEFINE
+# error Expected SHAREDLIB_DEFINE
+#endif
+
+#ifdef HEADERONLY_DEFINE
+# error Unexpected HEADERONLY_DEFINE
+#endif
+
+#ifndef DEFINE_IFACE_DEFINE
+# error Expected DEFINE_IFACE_DEFINE
+#endif
+
+int main(int, char**)
+{
+ SharedLibObject slo;
+ return slo.foo();
+}
diff --git a/Tests/ExportImport/Import/Interface/pch_iface_test.cpp b/Tests/ExportImport/Import/Interface/pch_iface_test.cpp
new file mode 100644
index 0000000..d676a5b
--- /dev/null
+++ b/Tests/ExportImport/Import/Interface/pch_iface_test.cpp
@@ -0,0 +1,17 @@
+#ifdef EXPECT_PCH
+// Verify that pch/pch.h was included via '-include ...' or equivalent.
+# ifndef PCH_PCH_H_INCLUDED
+# error "Expected PCH_PCH_H_INCLUDED."
+# endif
+#elif defined(__PGIC__) || defined(__ibmxl__) || defined(_CRAYC) || \
+ defined(__FUJITSU)
+// No PCH expected but these compilers define macros below.
+#elif defined(__GNUC__) || defined(__clang__) || defined(_INTEL_COMPILER) || \
+ defined(_MSC_VER)
+# error "Expected EXPECT_PCH for this compiler."
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Import/Interface/source_target_test.cpp b/Tests/ExportImport/Import/Interface/source_target_test.cpp
new file mode 100644
index 0000000..0e8ec5f
--- /dev/null
+++ b/Tests/ExportImport/Import/Interface/source_target_test.cpp
@@ -0,0 +1,7 @@
+
+extern int source_symbol();
+
+int main()
+{
+ return source_symbol() - 42;
+}
diff --git a/Tests/ExportImport/Import/imp_testTransExe1.c b/Tests/ExportImport/Import/imp_testTransExe1.c
new file mode 100644
index 0000000..360a112
--- /dev/null
+++ b/Tests/ExportImport/Import/imp_testTransExe1.c
@@ -0,0 +1,6 @@
+extern int imp_lib1(void);
+
+int main()
+{
+ return imp_lib1();
+}
diff --git a/Tests/ExportImport/Import/try_compile/CMakeLists.txt b/Tests/ExportImport/Import/try_compile/CMakeLists.txt
new file mode 100644
index 0000000..813cf06
--- /dev/null
+++ b/Tests/ExportImport/Import/try_compile/CMakeLists.txt
@@ -0,0 +1,36 @@
+
+cmake_minimum_required(VERSION 2.8.12)
+
+find_package(testLibRequired 2.5 REQUIRED)
+
+include(CheckCXXSourceCompiles)
+
+set(CMAKE_REQUIRED_LIBRARIES Req::testSharedLibRequiredUser)
+check_cxx_source_compiles(
+ "
+#include \"testSharedLibRequiredUser.h\"
+int main(int argc, char **argv)
+{
+ TestSharedLibRequiredUser user;
+ return user.foo();
+}
+" SHARED_LIB_DEPENDS)
+
+if(NOT SHARED_LIB_DEPENDS)
+ message(SEND_ERROR "try_compile with IMPORTED targets failed!\n\n${OUTPUT}")
+endif()
+
+set(CMAKE_REQUIRED_LIBRARIES Req::testSharedLibRequiredUser2)
+check_cxx_source_compiles(
+ "
+#include \"testSharedLibRequiredUser2.h\"
+int main(int argc, char **argv)
+{
+ TestSharedLibRequiredUser2 user;
+ return user.foo().foo();
+}
+" SHARED_LIB_DEPENDS2)
+
+if(NOT SHARED_LIB_DEPENDS2)
+ message(SEND_ERROR "try_compile with IMPORTED targets failed!\n\n${OUTPUT}")
+endif()
diff --git a/Tests/ExportImport/Import/version_range/CMakeLists.txt b/Tests/ExportImport/Import/version_range/CMakeLists.txt
new file mode 100644
index 0000000..73b1d1e
--- /dev/null
+++ b/Tests/ExportImport/Import/version_range/CMakeLists.txt
@@ -0,0 +1,15 @@
+
+cmake_minimum_required(VERSION 3.18)
+
+find_package(testLibRequired 2.0...3.0)
+
+if (NOT testLibRequired_FOUND)
+ message(SEND_ERROR "version_range: fail to find package testLibRequired(2.5) with range 2.0...3.0")
+endif()
+
+
+find_package(testLibRequired 2.0...<2.5)
+
+if (testLibRequired_FOUND)
+ message(SEND_ERROR "version_range: package testLibRequired(2.5) unexpectedly found with range 2.0...<2.5")
+endif()
diff --git a/Tests/ExportImport/InitialCache.cmake.in b/Tests/ExportImport/InitialCache.cmake.in
new file mode 100644
index 0000000..44cd179
--- /dev/null
+++ b/Tests/ExportImport/InitialCache.cmake.in
@@ -0,0 +1,17 @@
+set(CMAKE_MAKE_PROGRAM "@CMake_TEST_NESTED_MAKE_PROGRAM@" CACHE FILEPATH "Make Program")
+set(CMAKE_C_COMPILER "@CMAKE_C_COMPILER@" CACHE STRING "C Compiler")
+set(CMAKE_C_FLAGS "@CMAKE_C_FLAGS@" CACHE STRING "C Flags")
+set(CMAKE_C_FLAGS_DEBUG "@CMAKE_C_FLAGS_DEBUG@" CACHE STRING "C Flags")
+set(CMAKE_C_FLAGS_RELEASE "@CMAKE_C_FLAGS_RELEASE@" CACHE STRING "C Flags")
+set(CMAKE_C_FLAGS_MINSIZEREL "@CMAKE_C_FLAGS_MINSIZEREL@" CACHE STRING "C Flags")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "@CMAKE_C_FLAGS_RELWITHDEBINFO@" CACHE STRING "C Flags")
+set(CMAKE_CXX_COMPILER "@CMAKE_CXX_COMPILER@" CACHE STRING "C++ Compiler")
+set(CMAKE_CXX_FLAGS "@CMAKE_CXX_FLAGS@" CACHE STRING "C++ Flags")
+set(CMAKE_CXX_FLAGS_DEBUG "@CMAKE_CXX_FLAGS_DEBUG@" CACHE STRING "C++ Flags")
+set(CMAKE_CXX_FLAGS_RELEASE "@CMAKE_CXX_FLAGS_RELEASE@" CACHE STRING "C++ Flags")
+set(CMAKE_CXX_FLAGS_MINSIZEREL "@CMAKE_CXX_FLAGS_MINSIZEREL@" CACHE STRING "C++ Flags")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "@CMAKE_CXX_FLAGS_RELWITHDEBINFO@" CACHE STRING "C++ Flags")
+set(CMAKE_INSTALL_PREFIX "@ExportImport_BINARY_DIR@/Root" CACHE STRING "Installation Prefix")
+set(CMAKE_SKIP_RPATH ON CACHE BOOL "No RPATH")
+set(CMAKE_GNUtoMS "@ExportImport_GNUtoMS@" CACHE BOOL "CMAKE_GNUtoMS")
+set(CMake_TEST_CUDA "@CMake_TEST_CUDA@" CACHE BOOL "CMake_TEST_CUDA")
diff --git a/Tests/ExportImport/main.c b/Tests/ExportImport/main.c
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/ExportImport/main.c
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/ExternalOBJ/CMakeLists.txt b/Tests/ExternalOBJ/CMakeLists.txt
new file mode 100644
index 0000000..4ff75b8
--- /dev/null
+++ b/Tests/ExternalOBJ/CMakeLists.txt
@@ -0,0 +1,63 @@
+cmake_minimum_required (VERSION 2.6)
+project (ExternalOBJ)
+
+if(APPLE)
+ # set _CMAKE_OSX_MACHINE to umame -m
+ exec_program(uname ARGS -m OUTPUT_VARIABLE _CMAKE_OSX_MACHINE)
+ # check for Power PC and change to ppc
+ if("${_CMAKE_OSX_MACHINE}" MATCHES "Power")
+ set(_CMAKE_OSX_MACHINE ppc)
+ endif()
+ set(CMAKE_OSX_ARCHITECTURES ${_CMAKE_OSX_MACHINE})
+endif()
+
+# Build the external object file.
+try_compile(EXTERNAL_OBJECT_BUILT
+ ${ExternalOBJ_BINARY_DIR}/Object
+ ${ExternalOBJ_SOURCE_DIR}/Object
+ Object
+ external
+ OUTPUT_VARIABLE OUTPUT
+ )
+if(EXTERNAL_OBJECT_BUILT)
+ message(
+ "Building external_object.cxx succeeded with the following output:\n"
+ "[${OUTPUT}]"
+ )
+else()
+ message(FATAL_ERROR
+ "Building external_object.cxx failed with the following output:\n"
+ "[${OUTPUT}]"
+ )
+endif()
+
+# Find the external object file.
+set(DIR ${ExternalOBJ_BINARY_DIR}/Object)
+file(GLOB_RECURSE EXTERNAL_OBJECT
+ "${DIR}/external_object*${CMAKE_CXX_OUTPUT_EXTENSION}")
+if(EXTERNAL_OBJECT)
+ list (GET EXTERNAL_OBJECT 0 EXTERNAL_OBJECT)
+ message("Found \"${EXTERNAL_OBJECT}\".")
+else()
+ message(FATAL_ERROR "Could not find external object.")
+endif()
+
+# Test creation of external objects by custom commands.
+set(CUSTOM_OBJECT
+ ${CMAKE_CURRENT_BINARY_DIR}/custom_object${CMAKE_C_OUTPUT_EXTENSION})
+add_custom_command(
+ OUTPUT ${CUSTOM_OBJECT}
+ COMMAND ${CMAKE_COMMAND} -E copy ${EXTERNAL_OBJECT} ${CUSTOM_OBJECT}
+ DEPENDS ${EXTERNAL_OBJECT}
+ )
+
+message("${EXTERNAL_OBJECT}")
+# Build an executable using the external object file.
+add_executable(ExternalOBJ executable.cxx ${CUSTOM_OBJECT})
+# A bug showed up in VS2010 where an object file that was
+# part of a custom command output worked, but ones that were
+# not didn't work. So, repeat the executable using the object
+# directly and not from the output of the copy.
+add_executable(ExternalOBJ2 executable.cxx ${EXTERNAL_OBJECT})
+
+add_subdirectory(Sub)
diff --git a/Tests/ExternalOBJ/Object/CMakeLists.txt b/Tests/ExternalOBJ/Object/CMakeLists.txt
new file mode 100644
index 0000000..dbfe09e
--- /dev/null
+++ b/Tests/ExternalOBJ/Object/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required (VERSION 2.6)
+project(Object)
+if(APPLE)
+ # set _CMAKE_OSX_MACHINE to umame -m
+ exec_program(uname ARGS -m OUTPUT_VARIABLE _CMAKE_OSX_MACHINE)
+ # check for Power PC and change to ppc
+ if("${_CMAKE_OSX_MACHINE}" MATCHES "Power")
+ set(_CMAKE_OSX_MACHINE ppc)
+ endif()
+ set(CMAKE_OSX_ARCHITECTURES ${_CMAKE_OSX_MACHINE})
+endif()
+
+add_executable(external external_object.cxx external_main.cxx)
diff --git a/Tests/ExternalOBJ/Object/external_main.cxx b/Tests/ExternalOBJ/Object/external_main.cxx
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/ExternalOBJ/Object/external_main.cxx
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/ExternalOBJ/Object/external_object.cxx b/Tests/ExternalOBJ/Object/external_object.cxx
new file mode 100644
index 0000000..5b4adaf
--- /dev/null
+++ b/Tests/ExternalOBJ/Object/external_object.cxx
@@ -0,0 +1,4 @@
+int external_object_function()
+{
+ return 0;
+}
diff --git a/Tests/ExternalOBJ/Sub/CMakeLists.txt b/Tests/ExternalOBJ/Sub/CMakeLists.txt
new file mode 100644
index 0000000..35cd30c
--- /dev/null
+++ b/Tests/ExternalOBJ/Sub/CMakeLists.txt
@@ -0,0 +1,3 @@
+set_property(SOURCE ${CUSTOM_OBJECT} PROPERTY GENERATED 1)
+add_executable(ExternalOBJSub ../executable.cxx ${CUSTOM_OBJECT})
+add_dependencies(ExternalOBJSub ExternalOBJ) # depend on generating target
diff --git a/Tests/ExternalOBJ/executable.cxx b/Tests/ExternalOBJ/executable.cxx
new file mode 100644
index 0000000..f9ec61d
--- /dev/null
+++ b/Tests/ExternalOBJ/executable.cxx
@@ -0,0 +1,5 @@
+extern int external_object_function();
+int main()
+{
+ return external_object_function();
+}
diff --git a/Tests/ExternalProject/CMakeLists.txt b/Tests/ExternalProject/CMakeLists.txt
new file mode 100644
index 0000000..59e3bcc
--- /dev/null
+++ b/Tests/ExternalProject/CMakeLists.txt
@@ -0,0 +1,744 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(ExternalProjectTest NONE)
+if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12)
+ cmake_policy(SET CMP0114 NEW)
+endif()
+
+include(ExternalProject)
+
+# Test ExternalProject, especially with checkouts from VCS
+
+find_package(CVS)
+find_package(Subversion)
+find_package(Git)
+find_package(Hg)
+
+option(ExternalProjectTest_USE_FOLDERS "Enable folder grouping in IDEs." ON)
+if(ExternalProjectTest_USE_FOLDERS)
+ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+else()
+ set_property(GLOBAL PROPERTY USE_FOLDERS OFF)
+endif()
+
+set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER
+ "CMakePredefinedTargets-in-ExternalProjectTest")
+
+set(base "${CMAKE_BINARY_DIR}/CMakeExternals")
+set(binary_base "${base}/Build")
+set_property(DIRECTORY PROPERTY EP_BASE ${base})
+set_property(DIRECTORY PROPERTY EP_STEP_TARGETS configure build test)
+
+add_custom_target(NonExternalProjectTarget
+ COMMAND ${CMAKE_COMMAND} -E echo NonExternalProjectTarget)
+
+# Empty projects that test all the known ExternalProject_Add argument key words:
+#
+set(proj AAA-TestAlphabetization)
+ExternalProject_Add(${proj}
+ BUILD_COMMAND ""
+ CONFIGURE_COMMAND ""
+ DOWNLOAD_COMMAND ""
+ INSTALL_COMMAND ""
+)
+
+set(proj ZZZ-TestAlphabetization)
+ExternalProject_Add(${proj}
+ BUILD_COMMAND ""
+ CONFIGURE_COMMAND ""
+ DOWNLOAD_COMMAND ""
+ INSTALL_COMMAND ""
+)
+
+set(proj TargetNameSameAsFolder)
+ExternalProject_Add(${proj}
+ BUILD_COMMAND ""
+ CONFIGURE_COMMAND ""
+ DOWNLOAD_COMMAND ""
+ INSTALL_COMMAND ""
+)
+set_property(TARGET ${proj} PROPERTY FOLDER "${proj}")
+
+set(proj MinimalNoOpProject)
+ExternalProject_Add(${proj}
+ BUILD_COMMAND ""
+ CONFIGURE_COMMAND ""
+ DOWNLOAD_COMMAND ""
+ INSTALL_COMMAND ""
+)
+
+set(proj EmptyNoOpProject)
+ExternalProject_Add(${proj}
+ BUILD_COMMAND ""
+ CMAKE_ARGS ""
+ CONFIGURE_COMMAND ""
+ CVS_REPOSITORY ""
+ CVS_MODULE ""
+ CVS_TAG ""
+ DEPENDS "MinimalNoOpProject" NonExternalProjectTarget
+ DOWNLOAD_COMMAND ""
+ DOWNLOAD_NO_PROGRESS 1
+ INSTALL_COMMAND ""
+ PATCH_COMMAND ""
+ STEP_TARGETS install update
+ SVN_REPOSITORY ""
+ SVN_REVISION ""
+ SVN_USERNAME ""
+ SVN_PASSWORD ""
+ SVN_TRUST_CERT 1
+ TEST_COMMAND ""
+ TIMEOUT ""
+ URL ""
+ URL_MD5 ""
+ UPDATE_COMMAND ""
+)
+set_property(TARGET ${proj} PROPERTY FOLDER "")
+
+set(proj NoExtractLogDownload)
+ExternalProject_Add(${proj}
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/gitrepo.tgz
+ DOWNLOAD_NO_EXTRACT 1
+ LOG_DOWNLOAD 1
+ BUILD_COMMAND ""
+ CONFIGURE_COMMAND ""
+ INSTALL_COMMAND ""
+)
+
+set(proj NoExtractBool)
+ExternalProject_Add(${proj}
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/gitrepo.tgz
+ DOWNLOAD_NO_EXTRACT 0
+ LOG_DOWNLOAD 1
+ BUILD_COMMAND ""
+ CONFIGURE_COMMAND ""
+ INSTALL_COMMAND ""
+)
+
+# CVS-based tests:
+#
+set(do_cvs_tests 0)
+
+if(CVS_EXECUTABLE)
+ set(do_cvs_tests 1)
+endif()
+
+if(do_cvs_tests AND NOT UNIX)
+ if("${CVS_EXECUTABLE}" MATCHES "cygwin")
+ message(STATUS "No ExternalProject cvs tests with cygwin cvs.exe outside cygwin!")
+ set(do_cvs_tests 0)
+ endif()
+endif()
+
+if(do_cvs_tests)
+ # Unzip/untar the CVS repository in our source folder so that other
+ # projects below may use it to test CVS args of ExternalProject_Add
+ #
+ set(proj SetupLocalCVSRepository)
+ set(local_cvs_repo "${CMAKE_CURRENT_BINARY_DIR}/LocalRepositories/CVS")
+ ExternalProject_Add(${proj}
+ SOURCE_DIR ${local_cvs_repo}
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/cvsrepo.tgz
+ URL_MD5 55fc85825ffdd9ed2597123c68b79f7e
+ BUILD_COMMAND ""
+ CONFIGURE_COMMAND "${CVS_EXECUTABLE}" --version
+ INSTALL_COMMAND ""
+ )
+ set_property(TARGET ${proj}
+ PROPERTY FOLDER "SetupRepos/Local/Deeply/Nested/For/Testing")
+
+ # The MSYS cvs tool interprets "c:/" as a "machine:" name for SSH.
+ # Detect the MSYS cvs and convert the repo path to an MSYS path.
+ if(WIN32)
+ if(EXISTS "${CVS_EXECUTABLE}")
+ file(STRINGS "${CVS_EXECUTABLE}" cvs_is_msys LIMIT_COUNT 1 REGEX "[Mm][Ss][Yy][Ss]")
+ if(cvs_is_msys)
+ message(STATUS "'${CVS_EXECUTABLE}' is from MSYS (contains '${cvs_is_msys}')")
+ string(REGEX REPLACE "^([A-Za-z]):" "/\\1" local_cvs_repo "${local_cvs_repo}")
+ endif()
+ endif()
+ endif()
+
+ # CVS by date stamp:
+ #
+ set(proj TutorialStep1-CVS-20090626)
+ ExternalProject_Add(${proj}
+ CVS_REPOSITORY ":local:${local_cvs_repo}"
+ CVS_MODULE "TutorialStep1"
+ CVS_TAG "-D2009-06-26 16:50:00 UTC"
+ UPDATE_COMMAND ""
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalCVSRepository"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "CVS")
+
+ # CVS by tag:
+ #
+ set(proj TutorialStep1-CVS-testtag1)
+ ExternalProject_Add(${proj}
+ CVS_REPOSITORY ":local:${local_cvs_repo}"
+ CVS_MODULE "TutorialStep1"
+ CVS_TAG -rtesttag1
+ UPDATE_COMMAND ""
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalCVSRepository"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "CVS")
+
+ # Live CVS / HEAD (no CVS_TAG):
+ #
+ set(proj TutorialStep1-CVS-HEAD)
+ ExternalProject_Add(${proj}
+ CVS_REPOSITORY ":local:${local_cvs_repo}"
+ CVS_MODULE "TutorialStep1"
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalCVSRepository"
+ DEPENDS "EmptyNoOpProject"
+ DEPENDS "TutorialStep1-CVS-20090626"
+ DEPENDS "TutorialStep1-CVS-testtag1"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "CVS")
+endif()
+
+
+# SVN-based tests:
+#
+set(do_svn_tests 0)
+
+if(Subversion_SVN_EXECUTABLE)
+ set(do_svn_tests 1)
+endif()
+
+# Only do svn tests with svn >= version 1.2
+#
+if(do_svn_tests)
+ if(Subversion_VERSION_SVN VERSION_LESS 1.2)
+ message(STATUS "No ExternalProject svn tests with svn client less than version 1.2")
+ set(do_svn_tests 0)
+ endif()
+endif()
+
+# Only do svn tests in cygwin/cygwin or not-cygwin/not-cygwin arrangements:
+#
+if(do_svn_tests)
+ if(CMAKE_CURRENT_BINARY_DIR MATCHES "cygdrive/" AND
+ NOT "${Subversion_SVN_EXECUTABLE}" MATCHES "cygwin")
+ message(STATUS "No ExternalProject svn tests with non-cygwin svn client in a /cygdrive based build")
+ set(do_svn_tests 0)
+ endif()
+endif()
+
+if(do_svn_tests)
+ # Unzip/untar the SVN repository in our source folder so that other
+ # projects below may use it to test SVN args of ExternalProject_Add
+ #
+ set(proj SetupLocalSVNRepository)
+ set(local_svn_repo "${CMAKE_CURRENT_BINARY_DIR}/LocalRepositories/SVN")
+ set(local_svn_repo_url "file:///${local_svn_repo}/TutorialStep1")
+ ExternalProject_Add(${proj}
+ SOURCE_DIR ${local_svn_repo}
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/svnrepo.tgz
+ URL_MD5 2f468be4ed1fa96377fca0cc830819c4
+ BUILD_COMMAND ""
+ CONFIGURE_COMMAND "${Subversion_SVN_EXECUTABLE}" --version
+ INSTALL_COMMAND ""
+ )
+ set_property(TARGET ${proj}
+ PROPERTY FOLDER "SetupRepos/Local/Deeply/Nested/For/Testing")
+
+ # SVN by date stamp:
+ #
+ set(proj TutorialStep1-SVN-20090626)
+ ExternalProject_Add(${proj}
+ SVN_REPOSITORY "${local_svn_repo_url}"
+ SVN_REVISION "-r{2009-06-26 16:50:00 +0000}"
+ UPDATE_COMMAND ""
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalSVNRepository"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "SVN")
+
+ # SVN by revision number:
+ #
+ set(proj TutorialStep1-SVN-r2)
+ ExternalProject_Add(${proj}
+ SVN_REPOSITORY "${local_svn_repo_url}"
+ SVN_REVISION "-r2"
+ UPDATE_COMMAND ""
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalSVNRepository"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "SVN")
+
+ # Live SVN / trunk (no SVN_REVISION):
+ #
+ set(proj TutorialStep1-SVN-trunk)
+ ExternalProject_Add(${proj}
+ SVN_REPOSITORY "${local_svn_repo_url}"
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalSVNRepository"
+ LOG_DOWNLOAD 1
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "SVN")
+endif()
+
+
+set(do_git_tests 0)
+
+if(GIT_EXECUTABLE)
+ set(do_git_tests 1)
+
+ message(STATUS "GIT_VERSION_STRING='${GIT_VERSION_STRING}'")
+
+ if("${GIT_VERSION_STRING}" VERSION_LESS 1.6.5)
+ message(STATUS "No ExternalProject git tests with git client less than version 1.6.5")
+ set(do_git_tests 0)
+ endif()
+endif()
+
+
+if(do_git_tests)
+ set(local_git_repo "../../LocalRepositories/GIT")
+
+ # Unzip/untar the git repository in our source folder so that other
+ # projects below may use it to test git args of ExternalProject_Add
+ #
+ set(proj SetupLocalGITRepository)
+ ExternalProject_Add(${proj}
+ SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/LocalRepositories/GIT
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/gitrepo.tgz
+ BUILD_COMMAND ""
+ CONFIGURE_COMMAND "${GIT_EXECUTABLE}" --version
+ INSTALL_COMMAND ""
+ )
+ set_property(TARGET ${proj}
+ PROPERTY FOLDER "SetupRepos/Local/Deeply/Nested/For/Testing")
+
+ # git by commit id:
+ #
+ set(proj TutorialStep1-GIT-byhash)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ GIT_TAG 57418671a0a0e371e7bac532337152595fbe0df5 # generated by gitrepo.bash
+ UPDATE_COMMAND ""
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalGITRepository"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+ # git by explicit branch/tag name:
+ #
+ set(proj TutorialStep1-GIT-bytag)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ GIT_TAG "origin/master"
+ UPDATE_COMMAND ""
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalGITRepository"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+ # Live git / master (no GIT_TAG):
+ #
+ set(proj TutorialStep1-GIT-master)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalGITRepository"
+ LOG_UPDATE 1
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+ # Live git / master (no GIT_TAG), but shallow
+ #
+ set(proj TutorialStep1-GIT-shallow-master)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ GIT_SHALLOW 1
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalGITRepository"
+ LOG_UPDATE 1
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+ # Live git / master (no GIT_TAG), but git config flags
+ #
+ # The `git clone --config` parameter has been introduced in Git 1.7.7
+ if(NOT git_version VERSION_LESS 1.7.7)
+ set(proj TutorialStep1-GIT-config)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ GIT_CONFIG core.eol=lf
+ core.autocrlf=input
+ "http.extraheader=AUTHORIZATION: bearer --unsupportedOption"
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalGITRepository"
+ LOG_UPDATE 1
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+ endif()
+
+ # git by explicit branch/tag with empty submodule list
+ #
+ set(proj TutorialStep1-GIT-bytag-withsubmodules)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ GIT_TAG "origin/master"
+ GIT_SUBMODULES ""
+ UPDATE_COMMAND ""
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalGITRepository"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+ # Unzip/untar the git repository in our source folder so that other
+ # projects below may use it to test git args of ExternalProject_Add
+ #
+ set(proj SetupLocalGITRepositoryWithSubmodules)
+ ExternalProject_Add(${proj}
+ SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/LocalRepositories/GIT-with-submodules
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/gitrepo-sub.tgz
+ BUILD_COMMAND ""
+ CONFIGURE_COMMAND "${GIT_EXECUTABLE}" --version
+ INSTALL_COMMAND ""
+ )
+ set_property(TARGET ${proj}
+ PROPERTY FOLDER "SetupRepos/Local/Deeply/Nested/For/Testing")
+
+ set(local_git_repo "../../LocalRepositories/GIT-with-submodules")
+
+ set(proj TS1-GIT-all-GIT_SUBMODULES)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ -DWITH_m1:BOOL=ON
+ -DWITH_m2:BOOL=ON
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalGITRepository"
+ "SetupLocalGITRepositoryWithSubmodules"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+ set(proj TS1-GIT-all-GIT_SUBMODULES-via-CMP0097-OLD)
+ cmake_policy(SET CMP0097 OLD)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ GIT_SUBMODULES ""
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ -DWITH_m1:BOOL=ON
+ -DWITH_m2:BOOL=ON
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalGITRepository"
+ "SetupLocalGITRepositoryWithSubmodules"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+ set(proj TS1-GIT-no-GIT_SUBMODULES)
+ cmake_policy(SET CMP0097 NEW)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ GIT_SUBMODULES ""
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ -DWITH_m1:BOOL=OFF
+ -DWITH_m2:BOOL=OFF
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalGITRepository"
+ "SetupLocalGITRepositoryWithSubmodules"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+ set(proj TS1-GIT-some-GIT_SUBMODULES)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ GIT_SUBMODULES "m/m1"
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ -DWITH_m1:BOOL=ON
+ -DWITH_m2:BOOL=OFF
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalGITRepository"
+ "SetupLocalGITRepositoryWithSubmodules"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+ # Unzip/untar the git repository in our source folder so that other
+ # projects below may use it to test git args of ExternalProject_Add
+ #
+ set(proj SetupLocalGITRepositoryWithRecursiveSubmodules)
+ ExternalProject_Add(${proj}
+ SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/LocalRepositories/GIT-with-recursive-submodules
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/gitrepo-sub-rec.tgz
+ BUILD_COMMAND ""
+ CONFIGURE_COMMAND "${GIT_EXECUTABLE}" --version
+ INSTALL_COMMAND ""
+ )
+ set_property(TARGET ${proj}
+ PROPERTY FOLDER "SetupRepos/Local/Deeply/Nested/For/Testing")
+
+ set(local_git_repo "../../LocalRepositories/GIT-with-recursive-submodules")
+
+ set(proj TS1-GIT-RECURSIVE_SUBMODULES-default)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ -DWITH_RECURSIVE:BOOL=ON
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalGITRepository"
+ "SetupLocalGITRepositoryWithSubmodules"
+ "SetupLocalGITRepositoryWithRecursiveSubmodules"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+ set(proj TS1-GIT-RECURSIVE_SUBMODULES-exclusive)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ GIT_SUBMODULES_RECURSE TRUE
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ -DWITH_RECURSIVE:BOOL=ON
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalGITRepository"
+ "SetupLocalGITRepositoryWithSubmodules"
+ "SetupLocalGITRepositoryWithRecursiveSubmodules"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+ set(proj TS1-GIT-RECURSIVE_SUBMODULES-off)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ GIT_SUBMODULES_RECURSE FALSE
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ -DWITH_RECURSIVE:BOOL=OFF
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalGITRepository"
+ "SetupLocalGITRepositoryWithSubmodules"
+ "SetupLocalGITRepositoryWithRecursiveSubmodules"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+endif()
+
+set(do_hg_tests 0)
+
+if(HG_EXECUTABLE)
+ set(do_hg_tests 1)
+endif()
+
+if(do_hg_tests AND NOT UNIX)
+ if("${HG_EXECUTABLE}" MATCHES "cygwin")
+ message(STATUS "No ExternalProject hg tests with cygwin hg outside cygwin!")
+ set(do_hg_tests 0)
+ endif()
+endif()
+
+if(do_hg_tests)
+ set(local_hg_repo "../../LocalRepositories/HG")
+
+ # Unzip/untar the hg repository in our source folder so that other
+ # projects below may use it to test hg args of ExternalProject_Add
+ #
+ set(proj SetupLocalHGRepository)
+ ExternalProject_Add(${proj}
+ SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/LocalRepositories/HG
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/hgrepo.tgz
+ BUILD_COMMAND ""
+ CONFIGURE_COMMAND "${HG_EXECUTABLE}" --version
+ INSTALL_COMMAND ""
+ )
+ set_property(TARGET ${proj}
+ PROPERTY FOLDER "SetupRepos/Local/Deeply/Nested/For/Testing")
+
+
+ # hg by commit id:
+ #
+ set(proj TutorialStep1-HG-byhash)
+ ExternalProject_Add(${proj}
+ HG_REPOSITORY "${local_hg_repo}"
+ HG_TAG dd2ce38a6b8a
+ UPDATE_COMMAND ""
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalHGRepository"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "HG")
+
+ # hg by explicit branch/tag name:
+ #
+ set(proj TutorialStep1-HG-bytag)
+ ExternalProject_Add(${proj}
+ HG_REPOSITORY "${local_hg_repo}"
+ HG_TAG "default"
+ UPDATE_COMMAND ""
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalHGRepository"
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "HG")
+
+ # Live hg / tip (no HG_TAG):
+ #
+ # Mercurial 2.1 does not distinguish an empty pull from a failed pull,
+ # so do not run the test with that version.
+ if(NOT "${HG_VERSION_STRING}" STREQUAL "2.1")
+ set(proj TutorialStep1-HG-tip)
+ ExternalProject_Add(${proj}
+ HG_REPOSITORY "${local_hg_repo}"
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ DEPENDS "SetupLocalHGRepository"
+ LOG_UPDATE 1
+ )
+ set_property(TARGET ${proj} PROPERTY FOLDER "HG")
+ endif()
+endif()
+
+
+# Test the testable built/installed products:
+#
+enable_testing()
+
+
+# Do at least a smoke test of a built executable from each
+# project's build directory...
+#
+# BuildTree tests:
+#
+if(do_cvs_tests)
+ add_test(TutorialStep1-CVS-20090626-BuildTreeTest
+ "${binary_base}/TutorialStep1-CVS-20090626/Tutorial" 4)
+
+ add_test(TutorialStep1-CVS-testtag1-BuildTreeTest
+ "${binary_base}/TutorialStep1-CVS-testtag1/Tutorial" 64)
+
+ add_test(TutorialStep1-CVS-HEAD-BuildTreeTest
+ "${binary_base}/TutorialStep1-CVS-HEAD/Tutorial" 81)
+endif()
+
+if(do_svn_tests)
+ add_test(TutorialStep1-SVN-20090626-BuildTreeTest
+ "${binary_base}/TutorialStep1-SVN-20090626/Tutorial" 100)
+
+ add_test(TutorialStep1-SVN-r2-BuildTreeTest
+ "${binary_base}/TutorialStep1-SVN-r2/Tutorial" 99)
+
+ add_test(TutorialStep1-SVN-trunk-BuildTreeTest
+ "${binary_base}/TutorialStep1-SVN-trunk/Tutorial" 98)
+endif()
+
+if(do_git_tests)
+ add_test(TutorialStep1-GIT-byhash
+ ${CMAKE_COMMAND} -P "${binary_base}/TutorialStep1-GIT-byhash/example.cmake")
+
+ add_test(TutorialStep1-GIT-bytag
+ ${CMAKE_COMMAND} -P "${binary_base}/TutorialStep1-GIT-bytag/example.cmake")
+
+ add_test(TutorialStep1-GIT-bytag-withsubmodules
+ ${CMAKE_COMMAND} -P "${binary_base}/TutorialStep1-GIT-bytag-withsubmodules/example.cmake")
+
+ add_test(TutorialStep1-GIT-shallow-master
+ ${CMAKE_COMMAND} -P "${binary_base}/TutorialStep1-GIT-shallow-master/example.cmake")
+
+ add_test(TutorialStep1-GIT-master
+ ${CMAKE_COMMAND} -P "${binary_base}/TutorialStep1-GIT-master/example.cmake")
+
+ if(NOT git_version VERSION_LESS 1.7.7)
+ add_test(TutorialStep1-GIT-config
+ ${CMAKE_COMMAND} -P "${binary_base}/TutorialStep1-GIT-config/example.cmake")
+ endif()
+endif()
+
+
+message(STATUS "do_cvs_tests='${do_cvs_tests}'")
+message(STATUS "do_svn_tests='${do_svn_tests}'")
+message(STATUS "do_git_tests='${do_git_tests}' GIT_EXECUTABLE='${GIT_EXECUTABLE}'")
+message(STATUS "do_hg_tests='${do_hg_tests}' HG_EXECUTABLE='${HG_EXECUTABLE}'")
+
+
+# Test if log works when the first arguments of *_COMMAND is "COMMAND".
+set(proj ExternalProject-no-log)
+set(download_cmd "")
+set(patch_cmd "")
+set(update_cmd "")
+set(configure_cmd "")
+set(build_cmd "")
+set(install_cmd "")
+
+ExternalProject_Add(${proj}
+ DOWNLOAD_COMMAND "${download_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "download"
+ PATCH_COMMAND "${patch_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "patch"
+ UPDATE_COMMAND "${update_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "update"
+ CONFIGURE_COMMAND "${configure_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "configure"
+ BUILD_COMMAND "${build_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "build"
+ INSTALL_COMMAND "${install_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "install"
+ )
+
+set(proj ExternalProject-log)
+ExternalProject_Add(${proj}
+ DOWNLOAD_COMMAND "${download_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "download"
+ PATCH_COMMAND "${patch_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "patch"
+ UPDATE_COMMAND "${update_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "update"
+ CONFIGURE_COMMAND "${configure_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "configure"
+ BUILD_COMMAND "${build_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "build"
+ INSTALL_COMMAND "${install_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "install"
+ LOG_DOWNLOAD 1
+ LOG_PATCH 1
+ LOG_UPDATE 1
+ LOG_CONFIGURE 1
+ LOG_BUILD 1
+ LOG_INSTALL 1
+ )
+
+set(proj ExternalProject-log-dir)
+ExternalProject_Add(${proj}
+ DOWNLOAD_COMMAND "${download_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "download"
+ PATCH_COMMAND "${patch_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "patch"
+ UPDATE_COMMAND "${update_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "update"
+ CONFIGURE_COMMAND "${configure_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "configure"
+ BUILD_COMMAND "${build_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "build"
+ INSTALL_COMMAND "${install_cmd}" COMMAND "${CMAKE_COMMAND}" -E echo "install"
+ LOG_MERGED_STDOUTERR 1
+ LOG_DIR ${CMAKE_CURRENT_BINARY_DIR}/different_log
+ LOG_DOWNLOAD 1
+ LOG_PATCH 1
+ LOG_UPDATE 1
+ LOG_CONFIGURE 1
+ LOG_BUILD 1
+ LOG_INSTALL 1
+ )
diff --git a/Tests/ExternalProject/Example/CMakeLists.txt b/Tests/ExternalProject/Example/CMakeLists.txt
new file mode 100644
index 0000000..c3f2614
--- /dev/null
+++ b/Tests/ExternalProject/Example/CMakeLists.txt
@@ -0,0 +1,11 @@
+# This is the canonical simplest ExternalProject example CMakeLists.txt file:
+cmake_minimum_required(VERSION 2.8.12)
+project(ExternalProjectExample NONE)
+include(ExternalProject)
+
+ExternalProject_Add(
+ cmake281
+ URL https://cmake.org/files/v2.8/cmake-2.8.1.tar.gz
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ BUILD_COMMAND ""
+)
diff --git a/Tests/ExternalProject/cvsrepo.tgz b/Tests/ExternalProject/cvsrepo.tgz
new file mode 100644
index 0000000..baba6d3
--- /dev/null
+++ b/Tests/ExternalProject/cvsrepo.tgz
Binary files differ
diff --git a/Tests/ExternalProject/gitrepo-sub-rec.tgz b/Tests/ExternalProject/gitrepo-sub-rec.tgz
new file mode 100644
index 0000000..0e63651
--- /dev/null
+++ b/Tests/ExternalProject/gitrepo-sub-rec.tgz
Binary files differ
diff --git a/Tests/ExternalProject/gitrepo-sub.tgz b/Tests/ExternalProject/gitrepo-sub.tgz
new file mode 100644
index 0000000..ab34fff
--- /dev/null
+++ b/Tests/ExternalProject/gitrepo-sub.tgz
Binary files differ
diff --git a/Tests/ExternalProject/gitrepo.bash b/Tests/ExternalProject/gitrepo.bash
new file mode 100755
index 0000000..c341f28
--- /dev/null
+++ b/Tests/ExternalProject/gitrepo.bash
@@ -0,0 +1,129 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+
+readonly tmpdir="$(mktemp -d)"
+trap "rm -rf '$tmpdir'" EXIT
+
+readonly outdir="${BASH_SOURCE%/*}"
+readonly defaultBranch='master'
+
+export GIT_AUTHOR_NAME='testauthor'
+export GIT_AUTHOR_EMAIL='testauthor@cmake.org'
+export GIT_COMMITTER_NAME='testauthor'
+export GIT_COMMITTER_EMAIL='testauthor@cmake.org'
+
+(
+cd "$tmpdir"
+
+git --bare init -b "$defaultBranch" gitrepo.git
+rm -f gitrepo.git/hooks/*.sample
+
+mkdir gitrepo
+cd gitrepo
+git init -b "$defaultBranch"
+echo 'cmake_minimum_required(VERSION 3.19)
+project(Example NONE)
+add_custom_target(example ALL
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/example.cmake.in example.cmake
+)' >CMakeLists.txt
+echo 'message(STATUS example)' >example.cmake.in
+git add CMakeLists.txt example.cmake.in
+git commit -m "Initial import into repo."
+git push ../gitrepo.git "$defaultBranch"
+cd ../gitrepo.git
+git gc --prune
+cd ..
+ln -s gitrepo.git GIT
+
+git --bare init -b "$defaultBranch" gitrepo-sub.git
+rm -f gitrepo-sub.git/hooks/*.sample
+
+mkdir gitrepo-sub
+cd gitrepo-sub
+git init -b "$defaultBranch"
+echo 'cmake_minimum_required(VERSION 3.19)
+project(ExampleWithSub NONE)
+file(STRINGS "${CMAKE_SOURCE_DIR}/.git/config" git_config_strings
+ REGEX "^\\[submodule")
+foreach(submodule m1 m2)
+ option(WITH_${submodule} "Enable ${submodule}" OFF)
+ set(${submodule}_INITED FALSE)
+ set(${submodule}_UPDATED FALSE)
+ foreach(s ${git_config_strings})
+ if("${s}" MATCHES "${submodule}")
+ set(${submodule}_INITED TRUE)
+ endif()
+ endforeach()
+ if(EXISTS "${CMAKE_SOURCE_DIR}/m/${submodule}/CMakeLists.txt")
+ set(${submodule}_UPDATED TRUE)
+ endif()
+ if(WITH_${submodule})
+ if(NOT ${submodule}_INITED)
+ message(FATAL_ERROR "${submodule} not inited")
+ elseif(NOT ${submodule}_UPDATED)
+ message(FATAL_ERROR "${submodule} not updated")
+ endif()
+ else()
+ if(${submodule}_INITED)
+ message(FATAL_ERROR "${submodule} inited")
+ elseif(${submodule}_UPDATED)
+ message(FATAL_ERROR "${submodule} updated")
+ endif()
+ endif()
+endforeach()' >CMakeLists.txt
+git add CMakeLists.txt
+git submodule add -- ../GIT m/m1
+git submodule add -- ../GIT m/m2
+git submodule add -- ../GIT m/m3
+git commit -m "Initial import into repo."
+git push ../gitrepo-sub.git "$defaultBranch"
+cd ../gitrepo-sub.git
+git gc --prune
+cd ..
+ln -s gitrepo-sub.git GIT-with-submodules
+
+git --bare init -b "$defaultBranch" gitrepo-sub-rec.git
+rm -f gitrepo-sub-rec.git/hooks/*.sample
+
+mkdir gitrepo-sub-rec
+cd gitrepo-sub-rec
+git init -b "$defaultBranch"
+echo 'cmake_minimum_required(VERSION 3.19)
+project(ExampleWithRecSub NONE)
+set(top_submodule_dir "${CMAKE_SOURCE_DIR}/submodule")
+if(NOT EXISTS "${top_submodule_dir}/CMakeLists.txt")
+ message(FATAL_ERROR "Top submodule not updated")
+endif()
+option(WITH_RECURSIVE "Submodules are updated recursively" ON)
+foreach(submodule m1 m2 m3)
+ set(${submodule}_UPDATED FALSE)
+ if(EXISTS "${top_submodule_dir}/m/${submodule}/CMakeLists.txt")
+ set(${submodule}_UPDATED TRUE)
+ endif()
+ if(WITH_RECURSIVE)
+ if(NOT ${submodule}_UPDATED)
+ message(FATAL_ERROR "${submodule} not updated")
+ endif()
+ else()
+ if(${submodule}_UPDATED)
+ message(FATAL_ERROR "${submodule} updated")
+ endif()
+ endif()
+endforeach()' >CMakeLists.txt
+git add CMakeLists.txt
+git submodule add -- ../GIT-with-submodules submodule
+git commit -m "Initial import into repo."
+git push ../gitrepo-sub-rec.git "$defaultBranch"
+cd ../gitrepo-sub-rec.git
+git gc --prune
+cd ..
+)
+
+tar cvzf "$outdir/gitrepo.tgz" -C "$tmpdir" gitrepo.git
+tar cvzf "$outdir/gitrepo-sub.tgz" -C "$tmpdir" gitrepo-sub.git
+tar cvzf "$outdir/gitrepo-sub-rec.tgz" -C "$tmpdir" gitrepo-sub-rec.git
+
+git_tag=$(cd "$tmpdir/gitrepo.git" ; git rev-parse HEAD)
+sed -i "/generated by gitrepo.bash/ s/ [0-9a-f]\\+ / $git_tag /" "$outdir/CMakeLists.txt"
diff --git a/Tests/ExternalProject/gitrepo.tgz b/Tests/ExternalProject/gitrepo.tgz
new file mode 100644
index 0000000..8d2d144
--- /dev/null
+++ b/Tests/ExternalProject/gitrepo.tgz
Binary files differ
diff --git a/Tests/ExternalProject/hgrepo.tgz b/Tests/ExternalProject/hgrepo.tgz
new file mode 100644
index 0000000..0d75ce2
--- /dev/null
+++ b/Tests/ExternalProject/hgrepo.tgz
Binary files differ
diff --git a/Tests/ExternalProject/svnrepo.tgz b/Tests/ExternalProject/svnrepo.tgz
new file mode 100644
index 0000000..b848416
--- /dev/null
+++ b/Tests/ExternalProject/svnrepo.tgz
Binary files differ
diff --git a/Tests/ExternalProjectLocal/CMakeLists.txt b/Tests/ExternalProjectLocal/CMakeLists.txt
new file mode 100644
index 0000000..57e8105
--- /dev/null
+++ b/Tests/ExternalProjectLocal/CMakeLists.txt
@@ -0,0 +1,225 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(ExternalProjectLocalTest NONE)
+if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12)
+ cmake_policy(SET CMP0114 NEW)
+endif()
+
+include(ExternalProject)
+
+# Test ExternalProject with local projects
+
+option(ExternalProjectTest_USE_FOLDERS "Enable folder grouping in IDEs." ON)
+if(ExternalProjectTest_USE_FOLDERS)
+ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+else()
+ set_property(GLOBAL PROPERTY USE_FOLDERS OFF)
+endif()
+
+set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER
+ "CMakePredefinedTargets-in-ExternalProjectTest")
+
+set(base "${CMAKE_BINARY_DIR}/Ext")
+set(binary_base "${base}/Build")
+set_property(DIRECTORY PROPERTY EP_BASE ${base})
+set_property(DIRECTORY PROPERTY EP_STEP_TARGETS configure build test)
+
+
+# Local DIR:
+#
+set(proj TutorialStep5-Local)
+ExternalProject_Add(${proj}
+URL "${CMAKE_CURRENT_SOURCE_DIR}/Step5"
+CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+CMAKE_ARGS -G ${CMAKE_GENERATOR} <SOURCE_DIR>
+TEST_BEFORE_INSTALL 1
+LOG_INSTALL 1
+)
+set_property(TARGET ${proj} PROPERTY FOLDER "Local")
+ExternalProject_Get_Property(${proj} install_dir)
+set(TutorialStep5_install_dir ${install_dir})
+
+set(proj TutorialStep5-Local-TestAfterInstall)
+ExternalProject_Add(${proj}
+URL "${CMAKE_CURRENT_SOURCE_DIR}/Step5"
+CMAKE_ARGS --install-prefix=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
+CMAKE_CACHE_DEFAULT_ARGS -DUSE_MYMATH:BOOL=OFF
+TEST_AFTER_INSTALL 1
+LOG_TEST 1
+)
+set_property(TARGET ${proj} PROPERTY FOLDER "Local")
+
+set(proj TutorialStep5-Local-TestExcludeFromMainBefore)
+ExternalProject_Add(${proj}
+URL "${CMAKE_CURRENT_SOURCE_DIR}/Step5"
+CMAKE_ARGS --install-prefix=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
+CMAKE_CACHE_DEFAULT_ARGS -DUSE_MYMATH:BOOL=OFF
+TEST_BEFORE_INSTALL 1
+TEST_EXCLUDE_FROM_MAIN 1
+STEP_TARGETS test
+LOG_TEST 1
+)
+set_property(TARGET ${proj} PROPERTY FOLDER "Local")
+
+set(proj TutorialStep5-Local-TestExcludeFromMainAfter)
+ExternalProject_Add(${proj}
+URL "${CMAKE_CURRENT_SOURCE_DIR}/Step5"
+CMAKE_ARGS --install-prefix=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
+CMAKE_CACHE_DEFAULT_ARGS -DUSE_MYMATH:BOOL=OFF
+TEST_AFTER_INSTALL 1
+TEST_EXCLUDE_FROM_MAIN 1
+STEP_TARGETS test
+LOG_TEST 1
+)
+set_property(TARGET ${proj} PROPERTY FOLDER "Local")
+
+
+
+# Local TAR:
+#
+set(proj TutorialStep1-LocalTAR)
+ExternalProject_Add(${proj}
+ URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1.tar"
+ URL_MD5 a87c5b47c0201c09ddfe1d5738fdb1e3
+ LIST_SEPARATOR ::
+ PATCH_COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/Step1Patch.cmake
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ -DTEST_LIST:STRING=A::B::C
+ INSTALL_COMMAND ""
+ LOG_CONFIGURE 1
+ LOG_PATCH 1
+)
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/TAR")
+
+set(proj TutorialStep1-LocalNoDirTAR)
+ExternalProject_Add(${proj}
+ URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1NoDir.tar"
+ URL_MD5 d09e3d370c5c908fa035c30939ee438e
+ LIST_SEPARATOR @@
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
+ -DTEST_LIST:STRING=1@@2@@3
+ INSTALL_COMMAND ""
+)
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/TAR")
+ExternalProject_Add_Step(${proj} mypatch
+ COMMAND ${CMAKE_COMMAND} -E echo "This is a custom external project step."
+ COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/Step1Patch.cmake
+ WORKING_DIRECTORY <SOURCE_DIR>
+ DEPENDEES download
+ DEPENDERS configure
+ )
+
+
+# Local TGZ:
+#
+set(proj TutorialStep1-LocalTGZ)
+ExternalProject_Add(${proj}
+ URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1.tgz"
+ URL_MD5 38c648e817339c356f6be00eeed79bd0
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
+ INSTALL_COMMAND ""
+ LOG_BUILD 1
+ UPDATE_DISCONNECTED 1
+)
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/TGZ")
+
+set(proj TutorialStep1-LocalNoDirTGZ)
+ExternalProject_Add(${proj}
+ URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1NoDir.tgz"
+ URL_HASH SHA256=496229e2a5ed620a37c385ad9406004a18026beab8b55dd2c4565d4b7f1d5383
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+)
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/TGZ")
+
+
+# Local BZ2:
+#
+# (The bz2 tests are here just to verify that the bz2 decompression is executed
+# during a test suite run... The configure and build commands are set to
+# nothing to make the test quicker. To make this more complete, I should add
+# a diff between this and the TGZ source tree since that one does build...)
+#
+set(proj TutorialStep1-LocalBZ2)
+ExternalProject_Add(${proj}
+ URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1.tar.bz2"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+)
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/BZ2")
+
+set(proj TutorialStep1-LocalNoDirBZ2)
+ExternalProject_Add(${proj}
+ URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1NoDir.tar.bz2"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+)
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/BZ2")
+
+
+# Local ZIP:
+#
+# (The zip tests are here just to verify that the zip decompression is executed
+# during a test suite run... The configure and build commands are set to
+# nothing to make the test quicker. To make this more complete, I should add
+# a diff between this and the TGZ source tree since that one does build...)
+#
+set(proj TutorialStep1-LocalZIP)
+ExternalProject_Add(${proj}
+ URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1.zip"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+)
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/ZIP")
+
+set(proj TutorialStep1-LocalNoDirZIP)
+ExternalProject_Add(${proj}
+ URL "${CMAKE_CURRENT_SOURCE_DIR}/Step1NoDir.zip"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+)
+set_property(TARGET ${proj} PROPERTY FOLDER "Local/ZIP")
+
+
+# Test the testable built/installed products:
+#
+enable_testing()
+
+
+# Do at least a smoke test of a built executable from each
+# project's build directory...
+#
+# BuildTree tests:
+#
+add_test(TutorialStep5-Local-BuildTreeTest
+"${binary_base}/TutorialStep5-Local/Tutorial" 42)
+set_property(TEST TutorialStep5-Local-BuildTreeTest
+APPEND PROPERTY LABELS Step5 BuildTree)
+
+add_test(TutorialStep1-LocalTAR-BuildTreeTest
+ "${binary_base}/TutorialStep1-LocalTAR/EP-Tutorial" 36)
+set_property(TEST TutorialStep1-LocalTAR-BuildTreeTest
+ APPEND PROPERTY LABELS TAR)
+
+add_test(TutorialStep1-LocalNoDirTAR-BuildTreeTest
+ "${binary_base}/TutorialStep1-LocalNoDirTAR/EP-Tutorial" 25)
+
+add_test(TutorialStep1-LocalTGZ-BuildTreeTest
+ "${binary_base}/TutorialStep1-LocalTGZ/Tutorial" 16)
+set_property(TEST TutorialStep1-LocalTGZ-BuildTreeTest
+ APPEND PROPERTY LABELS TGZ)
+
+add_test(TutorialStep1-LocalNoDirTGZ-BuildTreeTest
+ "${binary_base}/TutorialStep1-LocalNoDirTGZ/Tutorial" 9)
+
+# InstallTree tests:
+#
+add_test(TutorialStep5-InstallTreeTest
+"${TutorialStep5_install_dir}/bin/Tutorial" 49)
+set_property(TEST TutorialStep5-InstallTreeTest
+APPEND PROPERTY LABELS Step5 InstallTree)
diff --git a/Tests/ExternalProjectLocal/Step1.tar b/Tests/ExternalProjectLocal/Step1.tar
new file mode 100644
index 0000000..3711f07
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step1.tar
Binary files differ
diff --git a/Tests/ExternalProjectLocal/Step1.tar.bz2 b/Tests/ExternalProjectLocal/Step1.tar.bz2
new file mode 100644
index 0000000..49b5f23
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step1.tar.bz2
Binary files differ
diff --git a/Tests/ExternalProjectLocal/Step1.tgz b/Tests/ExternalProjectLocal/Step1.tgz
new file mode 100644
index 0000000..d9b4cd2
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step1.tgz
Binary files differ
diff --git a/Tests/ExternalProjectLocal/Step1.zip b/Tests/ExternalProjectLocal/Step1.zip
new file mode 100644
index 0000000..49dac24
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step1.zip
Binary files differ
diff --git a/Tests/ExternalProjectLocal/Step1NoDir.tar b/Tests/ExternalProjectLocal/Step1NoDir.tar
new file mode 100644
index 0000000..03664b8
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step1NoDir.tar
Binary files differ
diff --git a/Tests/ExternalProjectLocal/Step1NoDir.tar.bz2 b/Tests/ExternalProjectLocal/Step1NoDir.tar.bz2
new file mode 100644
index 0000000..92eb480
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step1NoDir.tar.bz2
Binary files differ
diff --git a/Tests/ExternalProjectLocal/Step1NoDir.tgz b/Tests/ExternalProjectLocal/Step1NoDir.tgz
new file mode 100644
index 0000000..71a2d81
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step1NoDir.tgz
Binary files differ
diff --git a/Tests/ExternalProjectLocal/Step1NoDir.zip b/Tests/ExternalProjectLocal/Step1NoDir.zip
new file mode 100644
index 0000000..b42d318
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step1NoDir.zip
Binary files differ
diff --git a/Tests/ExternalProjectLocal/Step1Patch.cmake b/Tests/ExternalProjectLocal/Step1Patch.cmake
new file mode 100644
index 0000000..35e09d9
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step1Patch.cmake
@@ -0,0 +1,25 @@
+# Verify the current working directory.
+if(NOT EXISTS CMakeLists.txt)
+ message(FATAL_ERROR "File does not exist:\n ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt")
+endif()
+if(NOT EXISTS tutorial.cxx)
+ message(FATAL_ERROR "File does not exist:\n ${CMAKE_CURRENT_SOURCE_DIR}/tutorial.cxx")
+endif()
+
+# Check if the patch is already applied.
+file(STRINGS CMakeLists.txt prop_line REGEX "^set_property")
+if(prop_line)
+ message(STATUS "Patch already applied!")
+ return()
+endif()
+
+# Apply the patch.
+file(APPEND CMakeLists.txt "
+# Patch by ExternalProject test:
+set_property(TARGET Tutorial PROPERTY OUTPUT_NAME EP-Tutorial)
+list(LENGTH TEST_LIST len)
+if(NOT len EQUAL 3)
+ message(FATAL_ERROR \"TEST_LIST length is \${len}, not 3\")
+endif()
+")
+message(STATUS "Patched ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt")
diff --git a/Tests/ExternalProjectLocal/Step5/CMakeLists.txt b/Tests/ExternalProjectLocal/Step5/CMakeLists.txt
new file mode 100644
index 0000000..93b3880
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step5/CMakeLists.txt
@@ -0,0 +1,71 @@
+cmake_minimum_required (VERSION 2.6)
+project (Tutorial)
+
+# The version number.
+set (Tutorial_VERSION_MAJOR 1)
+set (Tutorial_VERSION_MINOR 0)
+
+# does this system provide the log and exp functions?
+include (${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake)
+check_function_exists (log HAVE_LOG)
+check_function_exists (exp HAVE_EXP)
+
+# should we use our own math functions
+option(USE_MYMATH "Use tutorial provided math implementation" ON)
+
+# configure a header file to pass some of the CMake settings
+# to the source code
+configure_file (
+ "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
+ "${PROJECT_BINARY_DIR}/TutorialConfig.h"
+ )
+
+# add the binary tree to the search path for include files
+# so that we will find TutorialConfig.h
+include_directories ("${PROJECT_BINARY_DIR}")
+
+# add the MathFunctions library?
+if (USE_MYMATH)
+ include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
+ add_subdirectory (MathFunctions)
+ set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
+endif ()
+
+# add the executable
+add_executable (Tutorial tutorial.cxx)
+target_link_libraries (Tutorial ${EXTRA_LIBS})
+
+# add the install targets
+install (TARGETS Tutorial DESTINATION bin)
+install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
+ DESTINATION include)
+
+# enable testing
+enable_testing ()
+
+# does the application run
+add_test (TutorialRuns Tutorial 25)
+
+# does the usage message work?
+add_test (TutorialUsage Tutorial)
+set_tests_properties (TutorialUsage
+ PROPERTIES
+ PASS_REGULAR_EXPRESSION "Usage:.*number"
+ )
+
+#define a macro to simplify adding tests
+macro (do_test arg result)
+ add_test (TutorialComp${arg} Tutorial ${arg})
+ set_tests_properties (TutorialComp${arg}
+ PROPERTIES PASS_REGULAR_EXPRESSION ${result}
+ )
+endmacro ()
+
+# do a bunch of result based tests
+do_test (4 "4 is 2")
+do_test (9 "9 is 3")
+do_test (5 "5 is 2.236")
+do_test (7 "7 is 2.645")
+do_test (25 "25 is 5")
+do_test (-25 "-25 is 0")
+do_test (0.0001 "0.0001 is 0.01")
diff --git a/Tests/ExternalProjectLocal/Step5/MathFunctions/CMakeLists.txt b/Tests/ExternalProjectLocal/Step5/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..453a463
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step5/MathFunctions/CMakeLists.txt
@@ -0,0 +1,17 @@
+# first we add the executable that generates the table
+# add the binary tree directory to the search path for include files
+include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
+
+add_executable(MakeTable MakeTable.cxx )
+# add the command to generate the source code
+add_custom_command (
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+ DEPENDS MakeTable
+ )
+
+# add the main library
+add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h )
+
+install (TARGETS MathFunctions DESTINATION bin)
+install (FILES MathFunctions.h DESTINATION include)
diff --git a/Tests/ExternalProjectLocal/Step5/MathFunctions/MakeTable.cxx b/Tests/ExternalProjectLocal/Step5/MathFunctions/MakeTable.cxx
new file mode 100644
index 0000000..cebd50f
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step5/MathFunctions/MakeTable.cxx
@@ -0,0 +1,32 @@
+// A simple program that builds a sqrt table
+#include <math.h>
+#include <stdio.h>
+
+int main(int argc, char* argv[])
+{
+ int i;
+ double result;
+
+ // make sure we have enough arguments
+ if (argc < 2) {
+ return 1;
+ }
+
+ // open the output file
+ FILE* fout = fopen(argv[1], "w");
+ if (!fout) {
+ return 1;
+ }
+
+ // create a source file with a table of square roots
+ fprintf(fout, "double sqrtTable[] = {\n");
+ for (i = 0; i < 10; ++i) {
+ result = sqrt(static_cast<double>(i));
+ fprintf(fout, "%g,\n", result);
+ }
+
+ // close the table with a zero
+ fprintf(fout, "0};\n");
+ fclose(fout);
+ return 0;
+}
diff --git a/Tests/ExternalProjectLocal/Step5/MathFunctions/MathFunctions.h b/Tests/ExternalProjectLocal/Step5/MathFunctions/MathFunctions.h
new file mode 100644
index 0000000..cd36bcc
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step5/MathFunctions/MathFunctions.h
@@ -0,0 +1 @@
+double mysqrt(double x);
diff --git a/Tests/ExternalProjectLocal/Step5/MathFunctions/mysqrt.cxx b/Tests/ExternalProjectLocal/Step5/MathFunctions/mysqrt.cxx
new file mode 100644
index 0000000..a44aba0
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step5/MathFunctions/mysqrt.cxx
@@ -0,0 +1,41 @@
+#include <stdio.h>
+
+#include "MathFunctions.h"
+#include "TutorialConfig.h"
+
+// include the generated table
+#include <math.h>
+
+#include "Table.h"
+
+// a hack square root calculation using simple operations
+double mysqrt(double x)
+{
+ if (x <= 0) {
+ return 0;
+ }
+
+ double result;
+
+ // if we have both log and exp then use them
+ double delta;
+
+ // use the table to help find an initial value
+ result = x;
+ if (x >= 1 && x < 10) {
+ result = sqrtTable[static_cast<int>(x)];
+ }
+
+ // do ten iterations
+ int i;
+ for (i = 0; i < 10; ++i) {
+ if (result <= 0) {
+ result = 0.1;
+ }
+ delta = x - (result * result);
+ result = result + 0.5 * delta / result;
+ fprintf(stdout, "Computing sqrt of %g to be %g\n", x, result);
+ }
+
+ return result;
+}
diff --git a/Tests/ExternalProjectLocal/Step5/TutorialConfig.h.in b/Tests/ExternalProjectLocal/Step5/TutorialConfig.h.in
new file mode 100644
index 0000000..e97ce24
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step5/TutorialConfig.h.in
@@ -0,0 +1,8 @@
+// the configured options and settings for Tutorial
+#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
+#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
+#cmakedefine USE_MYMATH
+
+// does the platform provide exp and log functions?
+#cmakedefine HAVE_LOG
+#cmakedefine HAVE_EXP
diff --git a/Tests/ExternalProjectLocal/Step5/tutorial.cxx b/Tests/ExternalProjectLocal/Step5/tutorial.cxx
new file mode 100644
index 0000000..8d077b2
--- /dev/null
+++ b/Tests/ExternalProjectLocal/Step5/tutorial.cxx
@@ -0,0 +1,34 @@
+// A simple program that computes the square root of a number
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "TutorialConfig.h"
+
+#ifdef USE_MYMATH
+# include "MathFunctions.h"
+#endif
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ fprintf(stdout, "%s Version %d.%d\n", argv[0], Tutorial_VERSION_MAJOR,
+ Tutorial_VERSION_MINOR);
+ fprintf(stdout, "Usage: %s number\n", argv[0]);
+ return 1;
+ }
+
+ double inputValue = atof(argv[1]);
+ double outputValue = 0;
+
+ if (inputValue >= 0) {
+#ifdef USE_MYMATH
+ outputValue = mysqrt(inputValue);
+#else
+ outputValue = sqrt(inputValue);
+#endif
+ }
+
+ fprintf(stdout, "The square root of %g is %g\n", inputValue, outputValue);
+ return 0;
+}
diff --git a/Tests/ExternalProjectSourceSubdir/CMakeLists.txt b/Tests/ExternalProjectSourceSubdir/CMakeLists.txt
new file mode 100644
index 0000000..4688acf
--- /dev/null
+++ b/Tests/ExternalProjectSourceSubdir/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.6)
+project(ExternalProjectSourceSubdir NONE)
+include(ExternalProject)
+
+ExternalProject_Add(Example
+ SOURCE_SUBDIR subdir
+ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Example
+ BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/Example
+ INSTALL_COMMAND ""
+ )
diff --git a/Tests/ExternalProjectSourceSubdir/Example/subdir/CMakeLists.txt b/Tests/ExternalProjectSourceSubdir/Example/subdir/CMakeLists.txt
new file mode 100644
index 0000000..bbc3ca0
--- /dev/null
+++ b/Tests/ExternalProjectSourceSubdir/Example/subdir/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 3.0)
+project(empty)
diff --git a/Tests/ExternalProjectSourceSubdirNotCMake/CMakeLists.txt b/Tests/ExternalProjectSourceSubdirNotCMake/CMakeLists.txt
new file mode 100644
index 0000000..f64df1a
--- /dev/null
+++ b/Tests/ExternalProjectSourceSubdirNotCMake/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.6)
+project(ExternalProjectSourceSubdirNotCMake NONE)
+include(ExternalProject)
+
+find_program(MAKE_EXECUTABLE
+ NAMES gmake make)
+
+if (NOT MAKE_EXECUTABLE)
+ message("No `make` executable found; skipping")
+ return ()
+endif ()
+
+ExternalProject_Add(Example
+ SOURCE_SUBDIR subdir
+ BUILD_IN_SOURCE 1
+ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Example
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND "${MAKE_EXECUTABLE}"
+ INSTALL_COMMAND ""
+ )
diff --git a/Tests/ExternalProjectSourceSubdirNotCMake/Example/subdir/Makefile b/Tests/ExternalProjectSourceSubdirNotCMake/Example/subdir/Makefile
new file mode 100644
index 0000000..cab3b8f
--- /dev/null
+++ b/Tests/ExternalProjectSourceSubdirNotCMake/Example/subdir/Makefile
@@ -0,0 +1,2 @@
+all:
+ echo "complete"
diff --git a/Tests/ExternalProjectSubdir/CMakeLists.txt b/Tests/ExternalProjectSubdir/CMakeLists.txt
new file mode 100644
index 0000000..3a67ea0
--- /dev/null
+++ b/Tests/ExternalProjectSubdir/CMakeLists.txt
@@ -0,0 +1,26 @@
+cmake_minimum_required(VERSION 3.2)
+project(ExternalProjectSubdir NONE)
+include(ExternalProject)
+
+# Remove the custom target output to be sure it runs in an
+# incremental test.
+file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/PreSubdir1.txt)
+
+add_custom_target(PreSubdir1
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/PreSubdir1.txt
+ )
+add_library(PreSubdir1Interface INTERFACE)
+add_dependencies(PreSubdir1Interface PreSubdir1)
+
+ExternalProject_Add(Subdir1
+ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Subdir1
+ BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/Subdir1
+
+ CMAKE_ARGS -DNORMAL_VAR=NORMAL_VALUE -DGENEX_VAR=$<1:GENEX_VALUE>
+ LOG_CONFIGURE 1
+
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+
+ DEPENDS PreSubdir1Interface
+ )
diff --git a/Tests/ExternalProjectSubdir/Subdir1/CMakeLists.txt b/Tests/ExternalProjectSubdir/Subdir1/CMakeLists.txt
new file mode 100644
index 0000000..2303c3e
--- /dev/null
+++ b/Tests/ExternalProjectSubdir/Subdir1/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.2)
+project(Subdir1 NONE)
+
+if(NOT "${NORMAL_VAR}" STREQUAL "NORMAL_VALUE")
+ message(SEND_ERROR "NORMAL_VAR != 'NORMAL_VALUE'")
+endif()
+
+if(NOT "${GENEX_VAR}" STREQUAL "GENEX_VALUE")
+ message(SEND_ERROR "GENEX_VAR != 'GENEX_VALUE'")
+endif()
+
+if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/../PreSubdir1.txt")
+ message(SEND_ERROR "../PreSubdir1.txt not provided!")
+endif()
diff --git a/Tests/ExternalProjectUpdate/CMakeLists.txt b/Tests/ExternalProjectUpdate/CMakeLists.txt
new file mode 100644
index 0000000..6f8a7b1
--- /dev/null
+++ b/Tests/ExternalProjectUpdate/CMakeLists.txt
@@ -0,0 +1,133 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(ExternalProjectUpdateTest NONE)
+if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12)
+ cmake_policy(SET CMP0114 NEW)
+else()
+ # This test is very noisy with warnings about this policy if we don't
+ # explicitly set it. Projects shouldn't do this, but for test code this
+ # is reasonable.
+ cmake_policy(SET CMP0114 OLD)
+endif()
+cmake_policy(GET CMP0114 cmp0114)
+
+include(ExternalProject)
+
+find_package(Git)
+
+option(ExternalProjectUpdateTest_USE_FOLDERS "Enable folder grouping in IDEs." ON)
+if(ExternalProjectUpdateTest_USE_FOLDERS)
+ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+else()
+ set_property(GLOBAL PROPERTY USE_FOLDERS OFF)
+endif()
+
+set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER
+ "CMakePredefinedTargets-in-ExternalProjectUpdateTest")
+
+set(base "${CMAKE_BINARY_DIR}/CMakeExternals")
+set(binary_base "${base}/Build")
+set_property(DIRECTORY PROPERTY EP_BASE ${base})
+if(cmp0114 STREQUAL "NEW")
+ set_property(DIRECTORY PROPERTY EP_STEP_TARGETS configure build test update)
+ set(TestUpdateCommand_STEP_TARGETS STEP_TARGETS update)
+ set(TestUpdateCommand_INDEPENDENT_STEP_TARGETS)
+else()
+ set_property(DIRECTORY PROPERTY EP_STEP_TARGETS configure build test)
+ set_property(DIRECTORY PROPERTY EP_INDEPENDENT_STEP_TARGETS update)
+ set(TestUpdateCommand_STEP_TARGETS)
+ set(TestUpdateCommand_INDEPENDENT_STEP_TARGETS INDEPENDENT_STEP_TARGETS update)
+endif()
+
+ExternalProject_Add(TestUpdateCommand
+ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
+ UPDATE_COMMAND ${CMAKE_COMMAND} -E echo update
+ UPDATE_DISCONNECTED 1
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ ${TestUpdateCommand_STEP_TARGETS}
+ ${TestUpdateCommand_INDEPENDENT_STEP_TARGETS}
+ )
+add_custom_target(TestUpdateCommandDriver ALL)
+add_dependencies(TestUpdateCommandDriver TestUpdateCommand-update)
+
+set(do_git_tests 0)
+
+if(GIT_EXECUTABLE)
+ set(do_git_tests 1)
+
+ message(STATUS "GIT_VERSION_STRING='${GIT_VERSION_STRING}'")
+
+ if("${GIT_VERSION_STRING}" VERSION_LESS 1.6.5)
+ message(STATUS "No ExternalProject git tests with git client less than version 1.6.5")
+ set(do_git_tests 0)
+ endif()
+endif()
+
+# This should be specified from the command line.
+if(NOT TEST_GIT_TAG)
+ set(TEST_GIT_TAG origin/master)
+endif()
+
+if(do_git_tests)
+ set(local_git_repo "../../LocalRepositories/GIT")
+
+ # Unzip/untar the git repository in our source folder so that other
+ # projects below may use it to test git args of ExternalProject_Add
+ #
+ set(proj SetupLocalGITRepository)
+ ExternalProject_Add(${proj}
+ SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/LocalRepositories/GIT
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/gitrepo.tgz
+ BUILD_COMMAND ""
+ CONFIGURE_COMMAND "${GIT_EXECUTABLE}" --version
+ INSTALL_COMMAND ""
+ )
+ set_property(TARGET ${proj}
+ PROPERTY FOLDER "SetupRepos/Local/Deeply/Nested/For/Testing")
+
+ set(proj TutorialStep1-GIT)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ GIT_TAG ${TEST_GIT_TAG}
+ GIT_CONFIG "user.email=testauthor@cmake.org"
+ "user.name=testauthor"
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ )
+ ExternalProject_Add_StepDependencies(${proj} download SetupLocalGITRepository)
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+ set(proj TutorialStep2-GIT)
+ ExternalProject_Add(${proj}
+ GIT_REPOSITORY "${local_git_repo}"
+ GIT_TAG ${TEST_GIT_TAG}
+ CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ INSTALL_COMMAND ""
+ UPDATE_DISCONNECTED 1
+ )
+ ExternalProject_Add_StepDependencies(${proj} download SetupLocalGITRepository)
+ set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+endif()
+
+
+# Test the testable built/installed products:
+#
+enable_testing()
+
+
+# Do at least a smoke test of a built executable from each
+# project's build directory...
+#
+# BuildTree tests:
+#
+
+if(do_git_tests)
+ add_test(TutorialStep1-GIT
+ "${binary_base}/TutorialStep1-GIT/Tutorial" 81)
+endif()
+
+message(STATUS "do_git_tests='${do_git_tests}'")
+message(STATUS "GIT_EXECUTABLE='${GIT_EXECUTABLE}'")
diff --git a/Tests/ExternalProjectUpdate/ExternalProjectUpdateTest.cmake b/Tests/ExternalProjectUpdate/ExternalProjectUpdateTest.cmake
new file mode 100644
index 0000000..394df87
--- /dev/null
+++ b/Tests/ExternalProjectUpdate/ExternalProjectUpdateTest.cmake
@@ -0,0 +1,240 @@
+# Set the ExternalProject GIT_TAG to desired_tag, and make sure the
+# resulting checked out version is resulting_sha and rebuild.
+# This check's the correct behavior of the ExternalProject UPDATE_COMMAND.
+# Also verify that a fetch only occurs when fetch_expected is 1.
+macro(check_a_tag desired_tag resulting_sha fetch_expected update_strategy)
+ message( STATUS "Checking ExternalProjectUpdate to tag: ${desired_tag}" )
+
+ # Remove the FETCH_HEAD file, so we can check if it gets replaced with a 'git
+ # fetch'.
+ set( FETCH_HEAD_file ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT/.git/FETCH_HEAD )
+ file( REMOVE ${FETCH_HEAD_file} )
+
+ # Give ourselves a marker in the output. It is difficult to tell where we
+ # are up to without this
+ message(STATUS "===> check_a_tag ${desired_tag} ${resulting_sha} ${fetch_expected} ${update_strategy}")
+
+ # Configure
+ execute_process(COMMAND ${CMAKE_COMMAND}
+ -G ${CMAKE_GENERATOR} -T "${CMAKE_GENERATOR_TOOLSET}"
+ -A "${CMAKE_GENERATOR_PLATFORM}"
+ -DTEST_GIT_TAG:STRING=${desired_tag}
+ -DCMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY:STRING=${update_strategy}
+ ${ExternalProjectUpdate_SOURCE_DIR}
+ WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}
+ RESULT_VARIABLE error_code
+ )
+ if(error_code)
+ message(FATAL_ERROR "Could not configure the project.")
+ endif()
+
+ # Build
+ execute_process(COMMAND ${CMAKE_COMMAND}
+ --build ${ExternalProjectUpdate_BINARY_DIR}
+ RESULT_VARIABLE error_code
+ )
+ if(error_code)
+ message(FATAL_ERROR "Could not build the project.")
+ endif()
+
+ # Check the resulting SHA
+ execute_process(COMMAND ${GIT_EXECUTABLE}
+ rev-list --max-count=1 HEAD
+ WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT
+ RESULT_VARIABLE error_code
+ OUTPUT_VARIABLE tag_sha
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if(error_code)
+ message(FATAL_ERROR "Could not check the sha.")
+ endif()
+
+ if(NOT (${tag_sha} STREQUAL ${resulting_sha}))
+ message(FATAL_ERROR "UPDATE_COMMAND produced
+ ${tag_sha}
+when
+ ${resulting_sha}
+was expected."
+ )
+ endif()
+
+ if( NOT EXISTS ${FETCH_HEAD_file} AND ${fetch_expected})
+ message( FATAL_ERROR "Fetch did NOT occur when it was expected.")
+ endif()
+ if( EXISTS ${FETCH_HEAD_file} AND NOT ${fetch_expected})
+ message( FATAL_ERROR "Fetch DID occur when it was not expected.")
+ endif()
+
+ message( STATUS "Checking ExternalProjectUpdate to tag: ${desired_tag} (disconnected)" )
+
+ # Remove the FETCH_HEAD file, so we can check if it gets replaced with a 'git
+ # fetch'.
+ set( FETCH_HEAD_file ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep2-GIT/.git/FETCH_HEAD )
+ file( REMOVE ${FETCH_HEAD_file} )
+
+ # Check initial SHA
+ execute_process(COMMAND ${GIT_EXECUTABLE}
+ rev-list --max-count=1 HEAD
+ WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep2-GIT
+ RESULT_VARIABLE error_code
+ OUTPUT_VARIABLE initial_sha
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
+ # Configure
+ execute_process(COMMAND ${CMAKE_COMMAND}
+ -G ${CMAKE_GENERATOR} -T "${CMAKE_GENERATOR_TOOLSET}"
+ -A "${CMAKE_GENERATOR_PLATFORM}"
+ -DTEST_GIT_TAG:STRING=${desired_tag}
+ ${ExternalProjectUpdate_SOURCE_DIR}
+ WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}
+ RESULT_VARIABLE error_code
+ )
+ if(error_code)
+ message(FATAL_ERROR "Could not configure the project.")
+ endif()
+
+ # Build
+ execute_process(COMMAND ${CMAKE_COMMAND}
+ --build ${ExternalProjectUpdate_BINARY_DIR}
+ RESULT_VARIABLE error_code
+ )
+ if(error_code)
+ message(FATAL_ERROR "Could not build the project.")
+ endif()
+
+ if( EXISTS ${FETCH_HEAD_file} )
+ message( FATAL_ERROR "Fetch occurred when it was not expected.")
+ endif()
+
+ # Check the resulting SHA
+ execute_process(COMMAND ${GIT_EXECUTABLE}
+ rev-list --max-count=1 HEAD
+ WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep2-GIT
+ RESULT_VARIABLE error_code
+ OUTPUT_VARIABLE tag_sha
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if(error_code)
+ message(FATAL_ERROR "Could not check the sha.")
+ endif()
+
+ if(NOT (${tag_sha} STREQUAL ${initial_sha}))
+ message(FATAL_ERROR "Update occurred when it was not expected.")
+ endif()
+
+ # Update
+ execute_process(COMMAND ${CMAKE_COMMAND}
+ --build ${ExternalProjectUpdate_BINARY_DIR}
+ --target TutorialStep2-GIT-update
+ RESULT_VARIABLE error_code
+ )
+ if(error_code)
+ message(FATAL_ERROR "Could not build the project.")
+ endif()
+
+ # Check the resulting SHA
+ execute_process(COMMAND ${GIT_EXECUTABLE}
+ rev-list --max-count=1 HEAD
+ WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep2-GIT
+ RESULT_VARIABLE error_code
+ OUTPUT_VARIABLE tag_sha
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if(error_code)
+ message(FATAL_ERROR "Could not check the sha.")
+ endif()
+
+ if(NOT (${tag_sha} STREQUAL ${resulting_sha}))
+ message(FATAL_ERROR "UPDATE_COMMAND produced
+ ${tag_sha}
+when
+ ${resulting_sha}
+was expected."
+ )
+ endif()
+
+ if( NOT EXISTS ${FETCH_HEAD_file} AND ${fetch_expected})
+ message( FATAL_ERROR "Fetch did NOT occur when it was expected.")
+ endif()
+ if( EXISTS ${FETCH_HEAD_file} AND NOT ${fetch_expected})
+ message( FATAL_ERROR "Fetch DID occur when it was not expected.")
+ endif()
+endmacro()
+
+find_package(Git)
+set(do_git_tests 0)
+if(GIT_EXECUTABLE)
+ set(do_git_tests 1)
+
+ message(STATUS "GIT_VERSION_STRING='${GIT_VERSION_STRING}'")
+
+ if("${GIT_VERSION_STRING}" VERSION_LESS 1.6.5)
+ message(STATUS "No ExternalProject git tests with git client less than version 1.6.5")
+ set(do_git_tests 0)
+ endif()
+endif()
+
+# When re-running tests locally, this ensures we always start afresh
+file(REMOVE_RECURSE ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals)
+
+if(do_git_tests)
+ check_a_tag(origin/master b5752a26ae448410926b35c275af3c192a53722e 1 REBASE)
+ check_a_tag(tag1 d1970730310fe8bc07e73f15dc570071f9f9654a 1 REBASE)
+ # With the Git UPDATE_COMMAND performance patch, this will not require a
+ # 'git fetch'
+ check_a_tag(tag1 d1970730310fe8bc07e73f15dc570071f9f9654a 0 REBASE)
+ check_a_tag(tag2 5842b503ba4113976d9bb28d57b5aee1ad2736b7 1 REBASE)
+ check_a_tag(d19707303 d1970730310fe8bc07e73f15dc570071f9f9654a 0 REBASE)
+ check_a_tag(origin/master b5752a26ae448410926b35c275af3c192a53722e 1 REBASE)
+ # This is a remote symbolic ref, so it will always trigger a 'git fetch'
+ check_a_tag(origin/master b5752a26ae448410926b35c275af3c192a53722e 1 REBASE)
+
+ foreach(strategy IN ITEMS CHECKOUT REBASE_CHECKOUT)
+ # Move local master back, then apply a change that will cause a conflict
+ # during rebase
+ execute_process(COMMAND ${GIT_EXECUTABLE} checkout master
+ WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT
+ RESULT_VARIABLE error_code
+ )
+ if(error_code)
+ message(FATAL_ERROR "Could not reset local master back to tag1.")
+ endif()
+ execute_process(COMMAND ${GIT_EXECUTABLE} reset --hard tag1
+ WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT
+ RESULT_VARIABLE error_code
+ )
+ if(error_code)
+ message(FATAL_ERROR "Could not reset local master back to tag1.")
+ endif()
+
+ set(cmlFile ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT/CMakeLists.txt)
+ file(READ ${cmlFile} contents)
+ string(REPLACE "find TutorialConfig.h" "find TutorialConfig.h (conflict here)"
+ conflictingContent "${contents}"
+ )
+ file(WRITE ${cmlFile} "${conflictingContent}")
+ execute_process(COMMAND ${GIT_EXECUTABLE} commit -a -m "This should cause a conflict"
+ WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT
+ RESULT_VARIABLE error_code
+ )
+ if(error_code)
+ message(FATAL_ERROR "Could not commit conflicting change.")
+ endif()
+ # This should discard our commit but leave behind an annotated tag
+ check_a_tag(origin/master b5752a26ae448410926b35c275af3c192a53722e 1 ${strategy})
+ endforeach()
+
+ # This file matches a .gitignore rule that the last commit defines. We can't
+ # directly check that updates don't stash ignored contents because the stash
+ # and pop are both done within the update step. We don't have an opportunity
+ # to check things in between, but we can at least check that the update step
+ # doesn't choke on it.
+ set(ignoredFile ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT/ignored_item)
+ file(TOUCH ${ignoredFile})
+ check_a_tag(origin/master b5752a26ae448410926b35c275af3c192a53722e 1 REBASE)
+ if(NOT EXISTS ${ignoredFile})
+ message(FATAL_ERROR "Ignored file is missing")
+ endif()
+
+endif()
diff --git a/Tests/ExternalProjectUpdate/gitrepo.tgz b/Tests/ExternalProjectUpdate/gitrepo.tgz
new file mode 100644
index 0000000..4dab56b
--- /dev/null
+++ b/Tests/ExternalProjectUpdate/gitrepo.tgz
Binary files differ
diff --git a/Tests/FindALSA/CMakeLists.txt b/Tests/FindALSA/CMakeLists.txt
new file mode 100644
index 0000000..891f7a4
--- /dev/null
+++ b/Tests/FindALSA/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindALSA.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindALSA/Test"
+ "${CMake_BINARY_DIR}/Tests/FindALSA/Test"
+ ${build_generator_args}
+ --build-project TestFindALSA
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindALSA/Test/CMakeLists.txt b/Tests/FindALSA/Test/CMakeLists.txt
new file mode 100644
index 0000000..2829740
--- /dev/null
+++ b/Tests/FindALSA/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindALSA C)
+include(CTest)
+
+find_package(ALSA REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_ALSA_VERSION="${ALSA_VERSION_STRING}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt ALSA::ALSA)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${ALSA_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${ALSA_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindALSA/Test/main.c b/Tests/FindALSA/Test/main.c
new file mode 100644
index 0000000..d3303d0
--- /dev/null
+++ b/Tests/FindALSA/Test/main.c
@@ -0,0 +1,10 @@
+#include <alsa/global.h>
+#include <stdio.h>
+#include <string.h>
+
+int main()
+{
+ printf("Found ALSA version %s, expected version %s\n",
+ snd_asoundlib_version(), CMAKE_EXPECTED_ALSA_VERSION);
+ return strcmp(snd_asoundlib_version(), CMAKE_EXPECTED_ALSA_VERSION);
+}
diff --git a/Tests/FindBLAS/CMakeLists.txt b/Tests/FindBLAS/CMakeLists.txt
new file mode 100644
index 0000000..667195d
--- /dev/null
+++ b/Tests/FindBLAS/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindBLAS.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindBLAS/Test"
+ "${CMake_BINARY_DIR}/Tests/FindBLAS/Test"
+ ${build_generator_args}
+ --build-project TestFindBLAS
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindBLAS/Test/CMakeLists.txt b/Tests/FindBLAS/Test/CMakeLists.txt
new file mode 100644
index 0000000..59418f3
--- /dev/null
+++ b/Tests/FindBLAS/Test/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.4)
+project(TestFindBLAS C)
+include(CTest)
+
+find_package(BLAS REQUIRED)
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt BLAS::BLAS)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_link_libraries(test_var PRIVATE ${BLAS_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindBLAS/Test/main.c b/Tests/FindBLAS/Test/main.c
new file mode 100644
index 0000000..e61b02c
--- /dev/null
+++ b/Tests/FindBLAS/Test/main.c
@@ -0,0 +1,16 @@
+#include <assert.h>
+#include <string.h>
+
+// declare what parts of the blas C-API we need
+void dswap_(int* N, double* X, int* incX, double* Y, int* incY);
+
+int main()
+{
+ double x[4] = { 1, 2, 3, 4 };
+ double y[4] = { 8, 7, 7, 6 };
+ int N = 4;
+ int incX = 1;
+ int incY = 1;
+ dswap_(&N, x, &incX, y, &incY);
+ return 0;
+}
diff --git a/Tests/FindBZip2/CMakeLists.txt b/Tests/FindBZip2/CMakeLists.txt
new file mode 100644
index 0000000..0eb3b99
--- /dev/null
+++ b/Tests/FindBZip2/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindBZip2.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindBZip2/Test"
+ "${CMake_BINARY_DIR}/Tests/FindBZip2/Test"
+ ${build_generator_args}
+ --build-project TestFindBZip2
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindBZip2/Test/CMakeLists.txt b/Tests/FindBZip2/Test/CMakeLists.txt
new file mode 100644
index 0000000..e9cb618
--- /dev/null
+++ b/Tests/FindBZip2/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.4)
+project(TestFindBZip2 C)
+include(CTest)
+
+find_package(BZip2 REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_BZip2_VERSION="${BZip2_VERSION_STRING}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt BZip2::BZip2)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${BZIP2_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${BZIP2_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindBZip2/Test/main.c b/Tests/FindBZip2/Test/main.c
new file mode 100644
index 0000000..8e24c94
--- /dev/null
+++ b/Tests/FindBZip2/Test/main.c
@@ -0,0 +1,23 @@
+#include <bzlib.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main()
+{
+ int chunksize = 1024;
+ FILE* file = fopen("test.bzip2", "wb");
+ char* buf = malloc(sizeof(char) * chunksize);
+ int error, rsize;
+ unsigned int in, out;
+ BZFILE* bzfile = BZ2_bzWriteOpen(&error, file, 64, 1, 10);
+
+ /* Don't actually write anything for the purposes of the test */
+
+ BZ2_bzWriteClose(&error, bzfile, 1, &in, &out);
+ free(buf);
+ fclose(file);
+
+ remove("test.bzip2");
+
+ return 0;
+}
diff --git a/Tests/FindBoost/CMakeLists.txt b/Tests/FindBoost/CMakeLists.txt
new file mode 100644
index 0000000..8489d85
--- /dev/null
+++ b/Tests/FindBoost/CMakeLists.txt
@@ -0,0 +1,49 @@
+add_test(NAME FindBoost.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindBoost/Test"
+ "${CMake_BINARY_DIR}/Tests/FindBoost/Test"
+ ${build_generator_args}
+ --build-project TestFindBoost
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+add_test(NAME FindBoost.TestFail COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindBoost/TestFail"
+ "${CMake_BINARY_DIR}/Tests/FindBoost/TestFail"
+ ${build_generator_args}
+ --build-project TestFailFindBoost
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+set_tests_properties(FindBoost.TestFail PROPERTIES
+ WILL_FAIL ON
+ PASS_REGULAR_EXPRESSION "Could NOT find Boost (missing: foobar)")
+
+add_test(NAME FindBoost.TestHeaders COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindBoost/TestHeaders"
+ "${CMake_BINARY_DIR}/Tests/FindBoost/TestHeaders"
+ ${build_generator_args}
+ --build-project TestFindBoostHeaders
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+if (CMake_TEST_FindBoost_Python)
+ add_test(NAME FindBoost.TestPython COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindBoost/TestPython"
+ "${CMake_BINARY_DIR}/Tests/FindBoost/TestPython"
+ ${build_generator_args}
+ --build-project TestFindBoostPython
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+endif ()
diff --git a/Tests/FindBoost/Test/CMakeLists.txt b/Tests/FindBoost/Test/CMakeLists.txt
new file mode 100644
index 0000000..f60ccfa
--- /dev/null
+++ b/Tests/FindBoost/Test/CMakeLists.txt
@@ -0,0 +1,31 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindBoost CXX)
+include(CTest)
+
+set(Boost_NO_BOOST_CMAKE ON)
+find_package(Boost REQUIRED COMPONENTS filesystem thread
+ OPTIONAL_COMPONENTS program_options foobar)
+
+if(Boost_FOOBAR_FOUND)
+ message(FATAL_ERROR "Optional inexistent Boost component \"foobar\" found which is unexpected")
+endif(Boost_FOOBAR_FOUND)
+
+if(NOT Boost_PROGRAM_OPTIONS_FOUND)
+ message(FATAL_ERROR "Optional Boost component \"program_options\" not found which is unexpected")
+endif(NOT Boost_PROGRAM_OPTIONS_FOUND)
+
+add_definitions(-DCMAKE_EXPECTED_BOOST_VERSION="${Boost_VERSION}")
+add_definitions(-DCMAKE_EXPECTED_BOOST_VERSION_COMPONENTS="${Boost_VERSION_STRING}")
+
+add_executable(test_boost_tgt main.cxx)
+target_link_libraries(test_boost_tgt
+ Boost::dynamic_linking
+ Boost::disable_autolinking
+ Boost::filesystem
+ Boost::thread)
+add_test(NAME test_boost_tgt COMMAND test_boost_tgt)
+
+add_executable(test_boost_var main.cxx)
+target_include_directories(test_boost_var PRIVATE ${Boost_INCLUDE_DIRS})
+target_link_libraries(test_boost_var PRIVATE ${Boost_FILESYSTEM_LIBRARIES} ${Boost_SYSTEM_LIBRARIES} ${Boost_THREAD_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
+add_test(NAME test_boost_var COMMAND test_boost_var)
diff --git a/Tests/FindBoost/Test/main.cxx b/Tests/FindBoost/Test/main.cxx
new file mode 100644
index 0000000..50ddadf
--- /dev/null
+++ b/Tests/FindBoost/Test/main.cxx
@@ -0,0 +1,39 @@
+#include <boost/filesystem.hpp>
+#include <boost/thread.hpp>
+
+namespace {
+
+boost::mutex m1;
+boost::recursive_mutex m2;
+
+void threadmain()
+{
+ boost::lock_guard<boost::mutex> lock1(m1);
+ boost::lock_guard<boost::recursive_mutex> lock2(m2);
+
+ boost::filesystem::path p(boost::filesystem::current_path());
+}
+}
+
+int main()
+{
+ boost::thread foo(threadmain);
+ foo.join();
+
+ int version = BOOST_VERSION;
+ int major = version / 100000;
+ int minor = version / 100 % 1000;
+ int patch = version % 100;
+ char version_string[100];
+ snprintf(version_string, sizeof(version_string), "%d.%d.%d", major, minor,
+ patch);
+ printf("Found Boost version %s, expected version %s\n", version_string,
+ CMAKE_EXPECTED_BOOST_VERSION_COMPONENTS);
+ int ret = strcmp(version_string, CMAKE_EXPECTED_BOOST_VERSION_COMPONENTS);
+ char raw_version_string[100];
+ snprintf(raw_version_string, sizeof(raw_version_string), "%d",
+ BOOST_VERSION);
+ printf("Found Boost version %s, expected version %s\n", raw_version_string,
+ CMAKE_EXPECTED_BOOST_VERSION);
+ return ret | strcmp(raw_version_string, CMAKE_EXPECTED_BOOST_VERSION);
+}
diff --git a/Tests/FindBoost/TestFail/CMakeLists.txt b/Tests/FindBoost/TestFail/CMakeLists.txt
new file mode 100644
index 0000000..7c14a59
--- /dev/null
+++ b/Tests/FindBoost/TestFail/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindBoost CXX)
+include(CTest)
+
+find_package(Boost REQUIRED COMPONENTS foobar filesystem thread)
+
+add_executable(test_boost_tgt main.cxx)
+target_link_libraries(test_boost_tgt
+ Boost::dynamic_linking
+ Boost::disable_autolinking
+ Boost::filesystem
+ Boost::thread)
+add_test(NAME test_boost_tgt COMMAND test_boost_tgt)
+
+add_executable(test_boost_var main.cxx)
+target_include_directories(test_boost_var PRIVATE ${Boost_INCLUDE_DIRS})
+target_link_libraries(test_boost_var PRIVATE ${Boost_FILESYSTEM_LIBRARIES} ${Boost_SYSTEM_LIBRARIES} ${Boost_THREAD_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
+add_test(NAME test_boost_var COMMAND test_boost_var)
diff --git a/Tests/FindBoost/TestFail/main.cxx b/Tests/FindBoost/TestFail/main.cxx
new file mode 100644
index 0000000..6e8b5da
--- /dev/null
+++ b/Tests/FindBoost/TestFail/main.cxx
@@ -0,0 +1,24 @@
+#include <boost/filesystem.hpp>
+#include <boost/thread.hpp>
+
+namespace {
+
+boost::mutex m1;
+boost::recursive_mutex m2;
+
+void threadmain()
+{
+ boost::lock_guard<boost::mutex> lock1(m1);
+ boost::lock_guard<boost::recursive_mutex> lock2(m2);
+
+ boost::filesystem::path p(boost::filesystem::current_path());
+}
+}
+
+int main()
+{
+ boost::thread foo(threadmain);
+ foo.join();
+
+ return 0;
+}
diff --git a/Tests/FindBoost/TestHeaders/CMakeLists.txt b/Tests/FindBoost/TestHeaders/CMakeLists.txt
new file mode 100644
index 0000000..d7be327
--- /dev/null
+++ b/Tests/FindBoost/TestHeaders/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindBoostHeaders CXX)
+include(CTest)
+
+find_package(Boost REQUIRED)
+
+add_executable(test_boost_headers_tgt main.cxx)
+target_link_libraries(test_boost_headers_tgt
+ Boost::boost)
+add_test(NAME test_boost_headers_tgt COMMAND test_boost_headers_tgt)
diff --git a/Tests/FindBoost/TestHeaders/main.cxx b/Tests/FindBoost/TestHeaders/main.cxx
new file mode 100644
index 0000000..7844de4
--- /dev/null
+++ b/Tests/FindBoost/TestHeaders/main.cxx
@@ -0,0 +1,10 @@
+#include <boost/any.hpp>
+
+int main()
+{
+ boost::any a;
+ a = 5;
+ a = std::string("A string");
+
+ return 0;
+}
diff --git a/Tests/FindBoost/TestPython/CMakeLists.txt b/Tests/FindBoost/TestPython/CMakeLists.txt
new file mode 100644
index 0000000..6d292cd
--- /dev/null
+++ b/Tests/FindBoost/TestPython/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.14)
+project(TestFindBoostPython CXX)
+include(CTest)
+
+find_package(Boost OPTIONAL_COMPONENTS python27 python34 python35 python36 python37 python38 python39)
+
+set(FAILTEST TRUE)
+foreach (v IN ITEMS 27 34 35 36 37 38 39)
+ if (Boost_PYTHON${v}_FOUND)
+ set(FAILTEST FALSE)
+ break()
+ endif ()
+endforeach ()
+
+if (FAILTEST)
+ message(FATAL_ERROR "No Boost Python module found")
+endif ()
diff --git a/Tests/FindCURL/CMakeLists.txt b/Tests/FindCURL/CMakeLists.txt
new file mode 100644
index 0000000..0cfd629
--- /dev/null
+++ b/Tests/FindCURL/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindCURL.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindCURL/Test"
+ "${CMake_BINARY_DIR}/Tests/FindCURL/Test"
+ ${build_generator_args}
+ --build-project TestFindCURL
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindCURL/Test/CMakeLists.txt b/Tests/FindCURL/Test/CMakeLists.txt
new file mode 100644
index 0000000..cbf2866
--- /dev/null
+++ b/Tests/FindCURL/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindCURL C)
+include(CTest)
+
+find_package(CURL REQUIRED COMPONENTS HTTP)
+
+add_definitions(-DCMAKE_EXPECTED_CURL_VERSION="${CURL_VERSION_STRING}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt CURL::libcurl)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${CURL_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${CURL_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindCURL/Test/main.c b/Tests/FindCURL/Test/main.c
new file mode 100644
index 0000000..263775f
--- /dev/null
+++ b/Tests/FindCURL/Test/main.c
@@ -0,0 +1,17 @@
+#include <curl/curl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main()
+{
+ struct curl_slist* slist;
+
+ curl_global_init(0);
+
+ slist = curl_slist_append(NULL, "CMake");
+ curl_slist_free_all(slist);
+
+ curl_global_cleanup();
+
+ return 0;
+}
diff --git a/Tests/FindCups/CMakeLists.txt b/Tests/FindCups/CMakeLists.txt
new file mode 100644
index 0000000..5be1ac1
--- /dev/null
+++ b/Tests/FindCups/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindCups.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindCups/Test"
+ "${CMake_BINARY_DIR}/Tests/FindCups/Test"
+ ${build_generator_args}
+ --build-project FindCups
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindCups/Test/CMakeLists.txt b/Tests/FindCups/Test/CMakeLists.txt
new file mode 100644
index 0000000..9e90553
--- /dev/null
+++ b/Tests/FindCups/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindCups C)
+include(CTest)
+
+find_package(Cups REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_CUPS_VERSION="${CUPS_VERSION_STRING}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt Cups::Cups)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${CUPS_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${CUPS_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindCups/Test/main.c b/Tests/FindCups/Test/main.c
new file mode 100644
index 0000000..b69d621
--- /dev/null
+++ b/Tests/FindCups/Test/main.c
@@ -0,0 +1,12 @@
+#include <cups/cups.h>
+
+int main()
+{
+ int num_options = 0;
+ cups_option_t* options = NULL;
+
+ num_options = cupsAddOption(CUPS_COPIES, "1", num_options, &options);
+ cupsFreeOptions(num_options, options);
+
+ return 0;
+}
diff --git a/Tests/FindDevIL/CMakeLists.txt b/Tests/FindDevIL/CMakeLists.txt
new file mode 100644
index 0000000..d37d50f
--- /dev/null
+++ b/Tests/FindDevIL/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindDevIL.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindDevIL/Test"
+ "${CMake_BINARY_DIR}/Tests/FindDevIL/Test"
+ ${build_generator_args}
+ --build-project TestFindDevIL
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindDevIL/Test/CMakeLists.txt b/Tests/FindDevIL/Test/CMakeLists.txt
new file mode 100644
index 0000000..c2c1322
--- /dev/null
+++ b/Tests/FindDevIL/Test/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindDevIL C)
+include(CTest)
+
+find_package(DevIL)
+
+#FIXME: check version too.
+# add_definitions(
+# -DCMAKE_EXPECTED_SDL_VERSION_MAJOR=${SDL_VERSION_MAJOR}
+# -DCMAKE_EXPECTED_SDL_VERSION_MINOR=${SDL_VERSION_MINOR}
+# -DCMAKE_EXPECTED_SDL_VERSION_PATCH=${SDL_VERSION_PATCH})
+
+add_executable(test_devil_var main.c)
+target_include_directories(test_devil_var PRIVATE ${IL_INCLUDE_DIRS})
+target_link_libraries(test_devil_var PRIVATE ${IL_LIBRARIES})
+add_test(NAME test_devil_var COMMAND test_devil_var)
+
+add_executable(test_devil_il_tgt main.c)
+target_link_libraries(test_devil_il_tgt DevIL::IL)
+add_test(NAME test_devil_il_tgt COMMAND test_devil_il_tgt)
+
+add_executable(test_devil_ilu_tgt main_ilu.c)
+target_link_libraries(test_devil_ilu_tgt DevIL::ILU)
+
+add_executable(test_devil_ilu_var main_ilu.c)
+target_include_directories(test_devil_ilu_var PRIVATE ${IL_INCLUDE_DIRS} ${ILU_INCLUDE_DIRS})
+target_link_libraries(test_devil_ilu_var ${IL_LIBRARIES} ${ILU_LIBRARIES})
+
+#FIXME: Check DevIL::ILUT target
diff --git a/Tests/FindDevIL/Test/main.c b/Tests/FindDevIL/Test/main.c
new file mode 100644
index 0000000..4a07087
--- /dev/null
+++ b/Tests/FindDevIL/Test/main.c
@@ -0,0 +1,10 @@
+#include <IL/il.h>
+
+int main()
+{
+ // Test 1 requires to link to the library.
+ ilInit();
+
+ ilShutDown();
+ return 0;
+}
diff --git a/Tests/FindDevIL/Test/main_ilu.c b/Tests/FindDevIL/Test/main_ilu.c
new file mode 100644
index 0000000..a9e7819
--- /dev/null
+++ b/Tests/FindDevIL/Test/main_ilu.c
@@ -0,0 +1,8 @@
+#include <IL/ilu.h>
+
+int main()
+{
+ // IL Utilities requires only initialization.
+ // Unlike main DevIL there are no shutdown function.
+ iluInit();
+}
diff --git a/Tests/FindDoxygen/AllTarget/CMakeLists.txt b/Tests/FindDoxygen/AllTarget/CMakeLists.txt
new file mode 100644
index 0000000..69aa518
--- /dev/null
+++ b/Tests/FindDoxygen/AllTarget/CMakeLists.txt
@@ -0,0 +1,42 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindDoxygen VERSION 1.0 LANGUAGES NONE)
+enable_testing()
+
+find_package(Doxygen REQUIRED)
+
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/main.cpp [[
+/**
+ * \file
+ * \brief One C++ file w/ sample Doxygen comment just to produce any docs...
+ */
+]])
+
+set(DOXYGEN_OUTPUT_DIRECTORY outDirWithout)
+file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/${DOXYGEN_OUTPUT_DIRECTORY})
+doxygen_add_docs(docsNoAll ${CMAKE_CURRENT_BINARY_DIR}/main.cpp)
+
+set(DOXYGEN_OUTPUT_DIRECTORY outDirWith)
+file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/${DOXYGEN_OUTPUT_DIRECTORY})
+doxygen_add_docs(docsWithAll ALL ${CMAKE_CURRENT_BINARY_DIR}/main.cpp)
+
+# Define tests cases that check whether targets were built
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dirExists.cmake [[
+cmake_minimum_required(VERSION 3.11)
+if(NOT EXISTS ${dirName})
+ message(FATAL_ERROR "Directory does not exist: ${dirName}")
+endif()
+]])
+
+add_test(NAME checkWith COMMAND
+ ${CMAKE_COMMAND}
+ -D dirName=${CMAKE_CURRENT_BINARY_DIR}/outDirWith
+ -P dirExists.cmake
+)
+add_test(NAME checkWithout COMMAND
+ ${CMAKE_COMMAND}
+ -D dirName=${CMAKE_CURRENT_BINARY_DIR}/outDirWithout
+ -P dirExists.cmake
+)
+set_tests_properties(checkWithout PROPERTIES
+ WILL_FAIL TRUE
+)
diff --git a/Tests/FindDoxygen/CMakeLists.txt b/Tests/FindDoxygen/CMakeLists.txt
new file mode 100644
index 0000000..41e6255
--- /dev/null
+++ b/Tests/FindDoxygen/CMakeLists.txt
@@ -0,0 +1,50 @@
+add_test(NAME FindDoxygen.SimpleTest COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindDoxygen/SimpleTest"
+ "${CMake_BINARY_DIR}/Tests/FindDoxygen/SimpleTest"
+ --build-target allDocTargets
+ ${build_generator_args}
+ --build-options ${build_options}
+)
+
+add_test(NAME FindDoxygen.QuotingTest COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindDoxygen/QuotingTest"
+ "${CMake_BINARY_DIR}/Tests/FindDoxygen/QuotingTest"
+ --build-target allDocTargets
+ ${build_generator_args}
+ --build-options ${build_options}
+)
+
+add_test(NAME FindDoxygen.AllTarget COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindDoxygen/AllTarget"
+ "${CMake_BINARY_DIR}/Tests/FindDoxygen/AllTarget"
+ ${build_generator_args}
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+)
+
+add_test(NAME FindDoxygen.StampFile COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindDoxygen/StampFile"
+ "${CMake_BINARY_DIR}/Tests/FindDoxygen/StampFile"
+ --build-target allDocTargets
+ ${build_generator_args}
+ --build-options ${build_options}
+)
+
+if(CMake_TEST_FindDoxygen_Dot)
+ add_test(NAME FindDoxygen.DotComponentTest COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindDoxygen/DotComponentTestTest"
+ "${CMake_BINARY_DIR}/Tests/FindDoxygen/DotComponentTestTest"
+ ${build_generator_args}
+ --build-options ${build_options}
+ )
+endif()
diff --git a/Tests/FindDoxygen/DotComponentTestTest/CMakeLists.txt b/Tests/FindDoxygen/DotComponentTestTest/CMakeLists.txt
new file mode 100644
index 0000000..586f0ff
--- /dev/null
+++ b/Tests/FindDoxygen/DotComponentTestTest/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.8)
+project(TestFindDoxygenDot VERSION 1.0 LANGUAGES NONE)
+
+# Testing a new signature w/ components
+find_package(Doxygen REQUIRED COMPONENTS dot)
+
+# No backwards compatibility expected when component form is used
+if(TARGET Doxygen::doxygen)
+ if(DOXYGEN)
+ message(FATAL_ERROR "DOXYGEN unexpectedly defined with component form")
+ endif()
+else()
+ message(FATAL_ERROR "Import target Doxygen::doxygen not defined")
+endif()
+
+if(NOT TARGET Doxygen::dot)
+ message(FATAL_ERROR "Import target Doxygen::dot not defined")
+endif()
diff --git a/Tests/FindDoxygen/QuotingTest/CMakeLists.txt b/Tests/FindDoxygen/QuotingTest/CMakeLists.txt
new file mode 100644
index 0000000..26bf090
--- /dev/null
+++ b/Tests/FindDoxygen/QuotingTest/CMakeLists.txt
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindDoxygen VERSION 1.0 LANGUAGES NONE)
+
+find_package(Doxygen REQUIRED)
+
+set(DOXYGEN_PROJECT_BRIEF "String with spaces")
+set(DOXYGEN_ALIASES
+ [[somealias="@some_command param"]]
+ "anotherAlias=@foobar"
+)
+
+set(DOXYGEN_VERBATIM_VARS DOXYGEN_ALIASES)
+
+doxygen_add_docs(docsQuoting)
+if(NOT EXISTS "${PROJECT_BINARY_DIR}/Doxyfile.docsQuoting")
+ message(FATAL_ERROR "Missing generated file: Doxyfile.docsQuoting")
+endif()
+
+file(STRINGS "${PROJECT_BINARY_DIR}/Doxyfile.docsQuoting" matches
+ REGEX [[^PROJECT_BRIEF *= *"String with spaces"]]
+)
+if(NOT matches)
+ message(FATAL_ERROR "PROJECT_BRIEF does not match expected contents")
+endif()
+
+file(STRINGS "${PROJECT_BINARY_DIR}/Doxyfile.docsQuoting" matches
+ REGEX [[^ALIASES *= *somealias="@some_command param" anotherAlias=@foobar]]
+)
+if(NOT matches)
+ message(FATAL_ERROR "ALIASES does not match expected contents")
+endif()
+
+add_custom_target(allDocTargets)
+add_dependencies(allDocTargets docsQuoting)
diff --git a/Tests/FindDoxygen/SimpleTest/CMakeLists.txt b/Tests/FindDoxygen/SimpleTest/CMakeLists.txt
new file mode 100644
index 0000000..deec4fd
--- /dev/null
+++ b/Tests/FindDoxygen/SimpleTest/CMakeLists.txt
@@ -0,0 +1,61 @@
+cmake_minimum_required(VERSION 3.8)
+project(TestFindDoxygen VERSION 1.0 LANGUAGES NONE)
+
+# Testing backward compatible signature
+find_package(Doxygen REQUIRED)
+
+if(TARGET Doxygen::doxygen)
+ # Check backward compatibility
+ if(NOT DOXYGEN_EXECUTABLE)
+ message(FATAL_ERROR "Backward compatibility broken: DOXYGEN_EXECUTABLE not set")
+ endif()
+ if(NOT DOXYGEN)
+ message(FATAL_ERROR "Backward compatibility broken: DOXYGEN not set")
+ endif()
+ # Check presence of expected generated files
+ foreach(file CMakeDoxyfile.in CMakeDoxygenDefaults.cmake)
+ if(NOT EXISTS "${PROJECT_BINARY_DIR}/${file}")
+ message(FATAL_ERROR "Missing generated file: ${file}")
+ endif()
+ endforeach()
+else()
+ message(FATAL_ERROR "Import target Doxygen::doxygen not defined")
+endif()
+
+set(DOXYGEN_OUTPUT_DIRECTORY noArgs)
+doxygen_add_docs(docsNoArgs)
+if(NOT EXISTS "${PROJECT_BINARY_DIR}/Doxyfile.docsNoArgs")
+ message(FATAL_ERROR "Missing generated file: Doxyfile.docsNoArgs")
+endif()
+if(NOT TARGET docsNoArgs)
+ message(FATAL_ERROR "Target docsNoArgs not created")
+endif()
+
+set(DOXYGEN_OUTPUT_DIRECTORY withArgs)
+configure_file(spaces_in_name.cpp.in "spaces in name.cpp" COPYONLY)
+doxygen_add_docs(docsWithArgs
+ "${CMAKE_CURRENT_BINARY_DIR}/spaces in name.cpp"
+ main.cpp
+)
+if(NOT EXISTS "${PROJECT_BINARY_DIR}/Doxyfile.docsWithArgs")
+ message(FATAL_ERROR "Missing generated file: Doxyfile.docsWithArgs")
+endif()
+if(NOT TARGET docsWithArgs)
+ message(FATAL_ERROR "Target docsWithArgs not created")
+endif()
+# Note that CMake inserts at least one entry into SOURCES when a COMMAND or
+# DEPENDS option is given to add_custom_target(), so rather than looking for an
+# exact match, we only verify that the files we expect to be there are present
+get_target_property(srcList docsWithArgs SOURCES)
+set(expectedList
+ "${CMAKE_CURRENT_BINARY_DIR}/spaces in name.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
+)
+foreach(f IN LISTS expectedList)
+ if(NOT f IN_LIST srcList)
+ message(FATAL_ERROR "SOURCES missing file: ${f}")
+ endif()
+endforeach()
+
+add_custom_target(allDocTargets)
+add_dependencies(allDocTargets docsNoArgs docsWithArgs)
diff --git a/Tests/FindDoxygen/SimpleTest/main.cpp b/Tests/FindDoxygen/SimpleTest/main.cpp
new file mode 100644
index 0000000..925f0af
--- /dev/null
+++ b/Tests/FindDoxygen/SimpleTest/main.cpp
@@ -0,0 +1,4 @@
+/**
+ * \file
+ * \brief One C++ file w/ sample Doxygen comment just to produce any docs...
+ */
diff --git a/Tests/FindDoxygen/SimpleTest/spaces_in_name.cpp.in b/Tests/FindDoxygen/SimpleTest/spaces_in_name.cpp.in
new file mode 100644
index 0000000..c1b9ffd
--- /dev/null
+++ b/Tests/FindDoxygen/SimpleTest/spaces_in_name.cpp.in
@@ -0,0 +1,4 @@
+/**
+ * \file
+ * \brief This file name contains spaces
+ */
diff --git a/Tests/FindDoxygen/StampFile/CMakeLists.txt b/Tests/FindDoxygen/StampFile/CMakeLists.txt
new file mode 100644
index 0000000..ed2bfbb
--- /dev/null
+++ b/Tests/FindDoxygen/StampFile/CMakeLists.txt
@@ -0,0 +1,43 @@
+cmake_minimum_required(VERSION 3.8)
+project(TestFindDoxygen VERSION 1.0 LANGUAGES NONE)
+
+find_package(Doxygen REQUIRED)
+
+set(DOXYGEN_OUTPUT_DIRECTORY noFiles)
+doxygen_add_docs(docsWithoutFilesWithStamp USE_STAMP_FILE)
+if(NOT EXISTS "${PROJECT_BINARY_DIR}/Doxyfile.docsWithoutFilesWithStamp")
+ message(FATAL_ERROR "Missing generated file: Doxyfile.docsWithoutFilesWithStamp")
+endif()
+if(NOT TARGET docsWithoutFilesWithStamp)
+ message(FATAL_ERROR "Target docsWithoutFilesWithStamp not created")
+endif()
+
+set(DOXYGEN_OUTPUT_DIRECTORY withFiles)
+doxygen_add_docs(docsWithFilesWithStamp main.cpp main2.cpp USE_STAMP_FILE)
+if(NOT EXISTS "${PROJECT_BINARY_DIR}/Doxyfile.docsWithFilesWithStamp")
+ message(FATAL_ERROR "Missing generated file: Doxyfile.docsWithFilesWithStamp")
+endif()
+if(NOT TARGET docsWithFilesWithStamp)
+ message(FATAL_ERROR "Target docsWithFilesWithStamp not created")
+endif()
+
+# Confirm that doxygen_add_docs() doesn't cause a fatal error if given a
+# source file that is generated at build time
+file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/genDox.cpp)
+add_custom_command(OUTPUT genDox.cpp
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/main2.cpp genDox.cpp
+ DEPENDS main2.cpp
+)
+set(DOXYGEN_OUTPUT_DIRECTORY withGenFiles)
+doxygen_add_docs(docsWithGenFilesWithStamp
+ main.cpp
+ ${CMAKE_CURRENT_BINARY_DIR}/genDox.cpp
+ USE_STAMP_FILE
+)
+
+add_custom_target(allDocTargets)
+add_dependencies(allDocTargets
+ docsWithoutFilesWithStamp
+ docsWithFilesWithStamp
+ docsWithGenFilesWithStamp
+)
diff --git a/Tests/FindDoxygen/StampFile/main.cpp b/Tests/FindDoxygen/StampFile/main.cpp
new file mode 100644
index 0000000..925f0af
--- /dev/null
+++ b/Tests/FindDoxygen/StampFile/main.cpp
@@ -0,0 +1,4 @@
+/**
+ * \file
+ * \brief One C++ file w/ sample Doxygen comment just to produce any docs...
+ */
diff --git a/Tests/FindDoxygen/StampFile/main2.cpp b/Tests/FindDoxygen/StampFile/main2.cpp
new file mode 100644
index 0000000..925f0af
--- /dev/null
+++ b/Tests/FindDoxygen/StampFile/main2.cpp
@@ -0,0 +1,4 @@
+/**
+ * \file
+ * \brief One C++ file w/ sample Doxygen comment just to produce any docs...
+ */
diff --git a/Tests/FindEXPAT/CMakeLists.txt b/Tests/FindEXPAT/CMakeLists.txt
new file mode 100644
index 0000000..a74174a
--- /dev/null
+++ b/Tests/FindEXPAT/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindEXPAT.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindEXPAT/Test"
+ "${CMake_BINARY_DIR}/Tests/FindEXPAT/Test"
+ ${build_generator_args}
+ --build-project TestFindEXPAT
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindEXPAT/Test/CMakeLists.txt b/Tests/FindEXPAT/Test/CMakeLists.txt
new file mode 100644
index 0000000..5681f74
--- /dev/null
+++ b/Tests/FindEXPAT/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.9)
+project(TestFindEXPAT C)
+include(CTest)
+
+find_package(EXPAT REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_EXPAT_VERSION="${EXPAT_VERSION_STRING}")
+
+add_executable(testexpat_tgt main.c)
+target_link_libraries(testexpat_tgt EXPAT::EXPAT)
+add_test(NAME testexpat_tgt COMMAND testexpat_tgt)
+
+add_executable(testexpat_var main.c)
+target_include_directories(testexpat_var PRIVATE ${EXPAT_INCLUDE_DIRS})
+target_link_libraries(testexpat_var PRIVATE ${EXPAT_LIBRARIES})
+add_test(NAME testexpat_var COMMAND testexpat_var)
diff --git a/Tests/FindEXPAT/Test/main.c b/Tests/FindEXPAT/Test/main.c
new file mode 100644
index 0000000..94ee3ef
--- /dev/null
+++ b/Tests/FindEXPAT/Test/main.c
@@ -0,0 +1,21 @@
+#include <expat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main()
+{
+ XML_Expat_Version expat_version;
+ char expat_version_string[16];
+
+ expat_version = XML_ExpatVersionInfo();
+
+ snprintf(expat_version_string, 16, "%i.%i.%i", expat_version.major,
+ expat_version.minor, expat_version.micro);
+
+ if (strcmp(expat_version_string, CMAKE_EXPECTED_EXPAT_VERSION) != 0) {
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/Tests/FindEnvModules/CMakeLists.txt b/Tests/FindEnvModules/CMakeLists.txt
new file mode 100644
index 0000000..95b7d1d
--- /dev/null
+++ b/Tests/FindEnvModules/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_test(FindEnvModules.Test ${CMAKE_CMAKE_COMMAND}
+ -P ${CMAKE_CURRENT_LIST_DIR}/EnvModules.cmake
+)
diff --git a/Tests/FindEnvModules/EnvModules.cmake b/Tests/FindEnvModules/EnvModules.cmake
new file mode 100644
index 0000000..21b0042
--- /dev/null
+++ b/Tests/FindEnvModules/EnvModules.cmake
@@ -0,0 +1,33 @@
+find_package(EnvModules REQUIRED)
+message("module purge")
+env_module(COMMAND purge RESULT_VARIABLE ret_var)
+if(NOT ret_var EQUAL 0)
+ message(FATAL_ERROR "module(purge) returned ${ret_var}")
+endif()
+
+message("module avail")
+env_module_avail(avail_mods)
+foreach(mod IN LISTS avail_mods)
+ message(" ${mod}")
+endforeach()
+
+if(avail_mods)
+ list(GET avail_mods 0 mod0)
+ message("module load ${mod0}")
+ env_module(load ${mod0})
+
+ message("module list")
+ env_module_list(loaded_mods)
+ set(mod0_found FALSE)
+ foreach(mod IN LISTS loaded_mods)
+ message(" ${mod}")
+ if(NOT mod0_found AND mod MATCHES "^${mod0}")
+ set(mod0_found ${mod})
+ endif()
+ endforeach()
+
+ if(NOT mod0_found)
+ message(FATAL_ERROR "Requested module ${mod0} not found in loaded modules")
+ endif()
+ message("module ${mod0} found loaded as ${mod0_found}")
+endif()
diff --git a/Tests/FindFontconfig/CMakeLists.txt b/Tests/FindFontconfig/CMakeLists.txt
new file mode 100644
index 0000000..d683d87
--- /dev/null
+++ b/Tests/FindFontconfig/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindFontconfig.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindFontconfig/Test"
+ "${CMake_BINARY_DIR}/Tests/FindFontconfig/Test"
+ ${build_generator_args}
+ --build-project TestFindFontconfig
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindFontconfig/Test/CMakeLists.txt b/Tests/FindFontconfig/Test/CMakeLists.txt
new file mode 100644
index 0000000..36c76b1
--- /dev/null
+++ b/Tests/FindFontconfig/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindFontconfig C)
+include(CTest)
+
+find_package(Fontconfig REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_FONTCONFIG_VERSION="${Fontconfig_VERSION}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt Fontconfig::Fontconfig)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${Fontconfig_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${Fontconfig_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindFontconfig/Test/main.c b/Tests/FindFontconfig/Test/main.c
new file mode 100644
index 0000000..c5b5963
--- /dev/null
+++ b/Tests/FindFontconfig/Test/main.c
@@ -0,0 +1,17 @@
+#include <assert.h>
+#include <fontconfig/fontconfig.h>
+#include <stdio.h>
+#include <string.h>
+
+int main()
+{
+ FcInit();
+ printf("Found Fontconfig.\n");
+
+ char fontconfig_version_string[16];
+ snprintf(fontconfig_version_string, 16, "%i.%i.%i", FC_MAJOR, FC_MINOR,
+ FC_REVISION);
+ assert(
+ strcmp(fontconfig_version_string, CMAKE_EXPECTED_FONTCONFIG_VERSION) == 0);
+ return 0;
+}
diff --git a/Tests/FindFreetype/CMakeLists.txt b/Tests/FindFreetype/CMakeLists.txt
new file mode 100644
index 0000000..490c25b
--- /dev/null
+++ b/Tests/FindFreetype/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindFreetype.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindFreetype/Test"
+ "${CMake_BINARY_DIR}/Tests/FindFreetype/Test"
+ ${build_generator_args}
+ --build-project TestFindFreetype
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindFreetype/Test/CMakeLists.txt b/Tests/FindFreetype/Test/CMakeLists.txt
new file mode 100644
index 0000000..bc869a1
--- /dev/null
+++ b/Tests/FindFreetype/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.9)
+project(TestFindFreetype C)
+include(CTest)
+
+find_package(Freetype REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_FREETYPE_VERSION="${FREETYPE_VERSION_STRING}")
+
+add_executable(testfreetype_tgt main.c)
+target_link_libraries(testfreetype_tgt Freetype::Freetype)
+add_test(NAME testfreetype_tgt COMMAND testfreetype_tgt)
+
+add_executable(testfreetype_var main.c)
+target_include_directories(testfreetype_var PRIVATE ${FREETYPE_INCLUDE_DIRS})
+target_link_libraries(testfreetype_var PRIVATE ${FREETYPE_LIBRARIES})
+add_test(NAME testfreetype_var COMMAND testfreetype_var)
diff --git a/Tests/FindFreetype/Test/main.c b/Tests/FindFreetype/Test/main.c
new file mode 100644
index 0000000..bb838a5
--- /dev/null
+++ b/Tests/FindFreetype/Test/main.c
@@ -0,0 +1,34 @@
+#include <ft2build.h>
+#include <stdlib.h>
+#include FT_FREETYPE_H
+#include <string.h>
+
+int main()
+{
+ FT_Library library;
+ FT_Error error;
+
+ error = FT_Init_FreeType(&library);
+ if (error) {
+ return EXIT_FAILURE;
+ }
+
+ FT_Int major = 0;
+ FT_Int minor = 0;
+ FT_Int patch = 0;
+ FT_Library_Version(library, &major, &minor, &patch);
+
+ char ft_version_string[16];
+ snprintf(ft_version_string, 16, "%i.%i.%i", major, minor, patch);
+
+ if (strcmp(ft_version_string, CMAKE_EXPECTED_FREETYPE_VERSION) != 0) {
+ return EXIT_FAILURE;
+ }
+
+ error = FT_Done_FreeType(library);
+ if (error) {
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/Tests/FindGDAL/CMakeLists.txt b/Tests/FindGDAL/CMakeLists.txt
new file mode 100644
index 0000000..12f95e1
--- /dev/null
+++ b/Tests/FindGDAL/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindGDAL.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGDAL/Test"
+ "${CMake_BINARY_DIR}/Tests/FindGDAL/Test"
+ ${build_generator_args}
+ --build-project TestFindGDAL
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindGDAL/Test/CMakeLists.txt b/Tests/FindGDAL/Test/CMakeLists.txt
new file mode 100644
index 0000000..8bdc57c
--- /dev/null
+++ b/Tests/FindGDAL/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindGDAL C)
+include(CTest)
+
+find_package(GDAL REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_GDAL_VERSION="${GDAL_VERSION}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt GDAL::GDAL)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${GDAL_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${GDAL_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindGDAL/Test/main.c b/Tests/FindGDAL/Test/main.c
new file mode 100644
index 0000000..7b31a13
--- /dev/null
+++ b/Tests/FindGDAL/Test/main.c
@@ -0,0 +1,11 @@
+#include <gdal.h>
+#include <stdio.h>
+#include <string.h>
+
+int main()
+{
+ printf("Found GDAL version %s, expected version %s\n", GDAL_RELEASE_NAME,
+ CMAKE_EXPECTED_GDAL_VERSION);
+ GDALAllRegister();
+ return strcmp(GDAL_RELEASE_NAME, CMAKE_EXPECTED_GDAL_VERSION);
+}
diff --git a/Tests/FindGIF/CMakeLists.txt b/Tests/FindGIF/CMakeLists.txt
new file mode 100644
index 0000000..bac64af
--- /dev/null
+++ b/Tests/FindGIF/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindGIF.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGIF/Test"
+ "${CMake_BINARY_DIR}/Tests/FindGIF/Test"
+ ${build_generator_args}
+ --build-project TestFindGIF
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindGIF/Test/CMakeLists.txt b/Tests/FindGIF/Test/CMakeLists.txt
new file mode 100644
index 0000000..961e636
--- /dev/null
+++ b/Tests/FindGIF/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.4)
+project(TestFindGIF C)
+include(CTest)
+
+find_package(GIF REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_GIF_VERSION="${GIF_VERSION}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt GIF::GIF)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${GIF_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${GIF_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindGIF/Test/main.c b/Tests/FindGIF/Test/main.c
new file mode 100644
index 0000000..656a99c
--- /dev/null
+++ b/Tests/FindGIF/Test/main.c
@@ -0,0 +1,34 @@
+#include <assert.h>
+#include <gif_lib.h>
+#include <stdio.h>
+#include <string.h>
+
+// GIFLIB before version 5 didn't know this macro
+#ifndef GIFLIB_MAJOR
+# define GIFLIB_MAJOR 4
+#endif
+
+int main()
+{
+ // because of the API changes we have to test different functions depending
+ // on the version of GIFLIB
+#if GIFLIB_MAJOR >= 5
+ // test the linker
+ GifErrorString(D_GIF_SUCCEEDED);
+
+ // check the version
+ char gif_version_string[16];
+ snprintf(gif_version_string, 16, "%i.%i.%i", GIFLIB_MAJOR, GIFLIB_MINOR,
+ GIFLIB_RELEASE);
+
+ assert(strcmp(gif_version_string, CMAKE_EXPECTED_GIF_VERSION) == 0);
+#else
+ // test the linker
+ GifLastError();
+
+ // unfortunately there is no way to check the version in older version of
+ // GIFLIB
+#endif
+
+ return 0;
+}
diff --git a/Tests/FindGLEW/CMakeLists.txt b/Tests/FindGLEW/CMakeLists.txt
new file mode 100644
index 0000000..ff42bce
--- /dev/null
+++ b/Tests/FindGLEW/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindGLEW.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGLEW/Test"
+ "${CMake_BINARY_DIR}/Tests/FindGLEW/Test"
+ ${build_generator_args}
+ --build-project TestFindGLEW
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindGLEW/Test/CMakeLists.txt b/Tests/FindGLEW/Test/CMakeLists.txt
new file mode 100644
index 0000000..954ee10
--- /dev/null
+++ b/Tests/FindGLEW/Test/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindGLEW LANGUAGES CXX)
+include(CTest)
+
+find_package(GLEW REQUIRED)
+
+add_executable(test_glew_shared_tgt main.cpp)
+target_link_libraries(test_glew_shared_tgt GLEW::GLEW)
+add_test(NAME test_glew_shared_tgt COMMAND test_glew_shared_tgt)
+
+add_executable(test_glew_generic_tgt main.cpp)
+target_link_libraries(test_glew_generic_tgt GLEW::glew)
+add_test(NAME test_glew_generic_tgt COMMAND test_glew_generic_tgt)
+
+add_executable(test_glew_var main.cpp)
+target_include_directories(test_glew_var PRIVATE ${GLEW_INCLUDE_DIRS})
+target_link_libraries(test_glew_var PRIVATE ${GLEW_LIBRARIES})
+add_test(NAME test_glew_var COMMAND test_glew_var)
diff --git a/Tests/FindGLEW/Test/main.cpp b/Tests/FindGLEW/Test/main.cpp
new file mode 100644
index 0000000..4a108ad
--- /dev/null
+++ b/Tests/FindGLEW/Test/main.cpp
@@ -0,0 +1,8 @@
+#include <GL/glew.h>
+
+int main()
+{
+ GLenum init_return = glewInit();
+
+ return (init_return == GLEW_OK);
+}
diff --git a/Tests/FindGSL/CMakeLists.txt b/Tests/FindGSL/CMakeLists.txt
new file mode 100644
index 0000000..45a3471
--- /dev/null
+++ b/Tests/FindGSL/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_test(NAME FindGSL.rng COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGSL/rng"
+ "${CMake_BINARY_DIR}/Tests/FindGSL/rng"
+ ${build_generator_args}
+ --build-project FindGSL_rng
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
diff --git a/Tests/FindGSL/rng/CMakeLists.txt b/Tests/FindGSL/rng/CMakeLists.txt
new file mode 100644
index 0000000..b15d6ac
--- /dev/null
+++ b/Tests/FindGSL/rng/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.0)
+project(FindGSL_rng CXX)
+include(CTest)
+
+find_package(GSL REQUIRED)
+
+add_executable(tstgslrng_tgt main.cc)
+target_link_libraries(tstgslrng_tgt GSL::gsl)
+add_test(NAME tstgslrng_tgt COMMAND tstgslrng_tgt)
+
+add_executable(tstgslrng_var main.cc)
+target_link_libraries(tstgslrng_var ${GSL_LIBRARIES})
+target_include_directories(tstgslrng_var PRIVATE ${GSL_INCLUDE_DIRS})
+add_test(NAME tstgslrng_var COMMAND tstgslrng_var)
diff --git a/Tests/FindGSL/rng/main.cc b/Tests/FindGSL/rng/main.cc
new file mode 100644
index 0000000..050caac
--- /dev/null
+++ b/Tests/FindGSL/rng/main.cc
@@ -0,0 +1,25 @@
+#include <math.h>
+
+#include "gsl/gsl_rng.h"
+
+int main()
+{
+ // return code
+ int retval = 1;
+
+ // create a generator
+ gsl_rng* generator;
+ generator = gsl_rng_alloc(gsl_rng_mt19937);
+
+ // Read a value.
+ double const Result = gsl_rng_uniform(generator);
+
+ // Check value
+ double const expectedResult(0.999741748906672);
+ if (fabs(expectedResult - Result) < 1.0e-6)
+ retval = 0;
+
+ // free allocated memory
+ gsl_rng_free(generator);
+ return retval;
+}
diff --git a/Tests/FindGTK2/CMakeLists.txt b/Tests/FindGTK2/CMakeLists.txt
new file mode 100644
index 0000000..0105fae
--- /dev/null
+++ b/Tests/FindGTK2/CMakeLists.txt
@@ -0,0 +1,320 @@
+find_package(GTK2 COMPONENTS gtk glade gtkmm glademm QUIET)
+
+
+# Test GTK2 components
+if(GTK2_GTK_FOUND)
+ add_test(GTK2Components.gtk ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/gtk"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Components/gtk"
+ ${build_generator_args}
+ --build-target gtk-all-libs
+ --build-project gtk
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Components/gtk"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(GTK2_GTKMM_FOUND)
+ add_test(GTK2Components.gtkmm ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/gtkmm"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Components/gtkmm"
+ ${build_generator_args}
+ --build-target gtkmm-all-libs
+ --build-project gtkmm
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Components/gtkmm"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+
+# Test GTK2 targets
+if(TARGET GTK2::glib)
+ add_test(GTK2Targets.glib ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/glib"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/glib"
+ ${build_generator_args}
+ --build-project glib
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/glib"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::gobject)
+ add_test(GTK2Targets.gobject ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/gobject"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gobject"
+ ${build_generator_args}
+ --build-project gobject
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gobject"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::gio)
+ add_test(GTK2Targets.gio ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/gio"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gio"
+ ${build_generator_args}
+ --build-project gio
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gio"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::gmodule)
+ add_test(GTK2Targets.gmodule ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/gmodule"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gmodule"
+ ${build_generator_args}
+ --build-project gmodule
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gmodule"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::gthread)
+ add_test(GTK2Targets.gthread ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/gthread"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gthread"
+ ${build_generator_args}
+ --build-project gthread
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gthread"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::atk)
+ add_test(GTK2Targets.atk ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/atk"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/atk"
+ ${build_generator_args}
+ --build-project atk
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/atk"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::gdk_pixbuf)
+ add_test(GTK2Targets.gdk_pixbuf ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/gdk_pixbuf"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gdk_pixbuf"
+ ${build_generator_args}
+ --build-project gdk_pixbuf
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gdk_pixbuf"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::cairo)
+ add_test(GTK2Targets.cairo ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/cairo"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/cairo"
+ ${build_generator_args}
+ --build-project cairo
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/cairo"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::pango)
+ add_test(GTK2Targets.pango ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/pango"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pango"
+ ${build_generator_args}
+ --build-project pango
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pango"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::pangocairo)
+ add_test(GTK2Targets.pangocairo ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/pangocairo"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pangocairo"
+ ${build_generator_args}
+ --build-project pangocairo
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pangocairo"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::pangoxft)
+ add_test(GTK2Targets.pangoxft ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/pangoxft"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pangoxft"
+ ${build_generator_args}
+ --build-project pangoxft
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pangoxft"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::pangoft2)
+ add_test(GTK2Targets.pangoft2 ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/pangoft2"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pangoft2"
+ ${build_generator_args}
+ --build-project pangoft2
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pangoft2"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::gdk)
+ add_test(GTK2Targets.gdk ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/gdk"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gdk"
+ ${build_generator_args}
+ --build-project gdk
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gdk"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::gtk)
+ add_test(GTK2Targets.gtk ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/gtk"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gtk"
+ ${build_generator_args}
+ --build-project gtk
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gtk"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::sigc++)
+ add_test(GTK2Targets.sigc++ ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/sigc++"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/sigc++"
+ ${build_generator_args}
+ --build-project sigc++
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/sigc++"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::glibmm)
+ add_test(GTK2Targets.glibmm ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/glibmm"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/glibmm"
+ ${build_generator_args}
+ --build-project glibmm
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/glibmm"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::giomm)
+ add_test(GTK2Targets.giomm ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/giomm"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/giomm"
+ ${build_generator_args}
+ --build-project giomm
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/giomm"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::atkmm)
+ add_test(GTK2Targets.atkmm ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/atkmm"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/atkmm"
+ ${build_generator_args}
+ --build-project atkmm
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/atkmm"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::cairomm)
+ add_test(GTK2Targets.cairomm ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/cairomm"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/cairomm"
+ ${build_generator_args}
+ --build-project cairomm
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/cairomm"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::pangomm)
+ add_test(GTK2Targets.pangomm ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/pangomm"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pangomm"
+ ${build_generator_args}
+ --build-project pangomm
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pangomm"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::gdkmm)
+ add_test(GTK2Targets.gdkmm ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/gdkmm"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/GTK2Targets/gdkmm"
+ ${build_generator_args}
+ --build-project gdkmm
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/GTK2Targets/gdkmm"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
+
+if(TARGET GTK2::gtkmm)
+ add_test(GTK2Targets.gtkmm ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTK2/gtkmm"
+ "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gtkmm"
+ ${build_generator_args}
+ --build-target gtkmm-target
+ --build-project gtkmm
+ --build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gtkmm"
+ --force-new-ctest-process
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endif()
diff --git a/Tests/FindGTK2/atk/CMakeLists.txt b/Tests/FindGTK2/atk/CMakeLists.txt
new file mode 100644
index 0000000..0392d88
--- /dev/null
+++ b/Tests/FindGTK2/atk/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(atk C)
+
+find_package(GTK2 COMPONENTS gtk REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(atk WIN32 main.c)
+target_link_libraries(atk GTK2::atk)
diff --git a/Tests/FindGTK2/atk/main.c b/Tests/FindGTK2/atk/main.c
new file mode 100644
index 0000000..4dc8d4d
--- /dev/null
+++ b/Tests/FindGTK2/atk/main.c
@@ -0,0 +1,7 @@
+#include <atk/atk.h>
+
+int main(int argc, char* argv[])
+{
+ const gchar* name = atk_get_toolkit_name();
+ return 0;
+}
diff --git a/Tests/FindGTK2/atkmm/CMakeLists.txt b/Tests/FindGTK2/atkmm/CMakeLists.txt
new file mode 100644
index 0000000..ec838de
--- /dev/null
+++ b/Tests/FindGTK2/atkmm/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(atkmm CXX)
+
+find_package(GTK2 COMPONENTS gtk gtkmm REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(atkmm WIN32 main.cpp)
+target_link_libraries(atkmm GTK2::atkmm)
diff --git a/Tests/FindGTK2/atkmm/main.cpp b/Tests/FindGTK2/atkmm/main.cpp
new file mode 100644
index 0000000..89a97f7
--- /dev/null
+++ b/Tests/FindGTK2/atkmm/main.cpp
@@ -0,0 +1,8 @@
+#include <atkmm.h>
+#include <atkmm/init.h>
+
+int main(int argc, char* argv[])
+{
+ Atk::init();
+ return 0;
+}
diff --git a/Tests/FindGTK2/cairo/CMakeLists.txt b/Tests/FindGTK2/cairo/CMakeLists.txt
new file mode 100644
index 0000000..3652ad6
--- /dev/null
+++ b/Tests/FindGTK2/cairo/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(cairo C)
+
+find_package(GTK2 COMPONENTS gtk REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(cairo WIN32 main.c)
+target_link_libraries(cairo GTK2::cairo)
diff --git a/Tests/FindGTK2/cairo/main.c b/Tests/FindGTK2/cairo/main.c
new file mode 100644
index 0000000..e2be60c
--- /dev/null
+++ b/Tests/FindGTK2/cairo/main.c
@@ -0,0 +1,50 @@
+/* Taken from http://cairographics.org/samples/ */
+
+#include <cairo.h>
+#include <math.h>
+#include <stdio.h>
+
+int main(int argc, char* argv[])
+{
+ char* filename;
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s OUTPUT_FILENAME\n", argv[0]);
+ return 1;
+ }
+ filename = argv[1];
+ double xc = 128.0;
+ double yc = 128.0;
+ double radius = 100.0;
+ double angle1 = 45.0 * (M_PI / 180.0); /* angles are specified */
+ double angle2 = 180.0 * (M_PI / 180.0); /* in radians */
+
+ cairo_surface_t* im =
+ cairo_image_surface_create(CAIRO_FORMAT_ARGB32, xc * 2, yc * 2);
+ cairo_t* cr = cairo_create(im);
+
+ cairo_set_line_width(cr, 10.0);
+ cairo_arc(cr, xc, yc, radius, angle1, angle2);
+ cairo_stroke(cr);
+
+ /* draw helping lines */
+ cairo_set_source_rgba(cr, 1, 0.2, 0.2, 0.6);
+ cairo_set_line_width(cr, 6.0);
+
+ cairo_arc(cr, xc, yc, 10.0, 0, 2 * M_PI);
+ cairo_fill(cr);
+
+ cairo_arc(cr, xc, yc, radius, angle1, angle1);
+ cairo_line_to(cr, xc, yc);
+ cairo_arc(cr, xc, yc, radius, angle2, angle2);
+ cairo_line_to(cr, xc, yc);
+ cairo_stroke(cr);
+
+ cairo_status_t status = cairo_surface_write_to_png(im, filename);
+ cairo_surface_destroy(im);
+ if (status != CAIRO_STATUS_SUCCESS) {
+ fprintf(stderr, "Could not save png to '%s'\n", filename);
+ }
+
+ cairo_destroy(cr);
+ return 0;
+}
diff --git a/Tests/FindGTK2/cairomm/CMakeLists.txt b/Tests/FindGTK2/cairomm/CMakeLists.txt
new file mode 100644
index 0000000..cde0f42
--- /dev/null
+++ b/Tests/FindGTK2/cairomm/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(cairomm CXX)
+
+find_package(GTK2 COMPONENTS gtk gtkmm REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(cairomm WIN32 main.cpp)
+target_link_libraries(cairomm GTK2::cairomm)
diff --git a/Tests/FindGTK2/cairomm/main.cpp b/Tests/FindGTK2/cairomm/main.cpp
new file mode 100644
index 0000000..48e5e39
--- /dev/null
+++ b/Tests/FindGTK2/cairomm/main.cpp
@@ -0,0 +1,64 @@
+// Taken from
+// http://cgit.freedesktop.org/cairomm/plain/examples/surfaces/image-surface.cc
+
+/* M_PI is defined in math.h in the case of Microsoft Visual C++, Solaris,
+ * et. al.
+ */
+#if defined(_MSC_VER)
+# define _USE_MATH_DEFINES
+#endif
+
+#include <cmath>
+#include <iostream>
+#include <string>
+
+#include <cairomm/context.h>
+#include <cairomm/surface.h>
+#include <cairommconfig.h>
+
+int main()
+{
+ Cairo::RefPtr<Cairo::ImageSurface> surface =
+ Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 600, 400);
+
+ Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(surface);
+
+ cr->save(); // save the state of the context
+ cr->set_source_rgb(0.86, 0.85, 0.47);
+ cr->paint(); // fill image with the color
+ cr->restore(); // color is back to black now
+
+ cr->save();
+ // draw a border around the image
+ cr->set_line_width(20.0); // make the line wider
+ cr->rectangle(0.0, 0.0, surface->get_width(), surface->get_height());
+ cr->stroke();
+
+ cr->set_source_rgba(0.0, 0.0, 0.0, 0.7);
+ // draw a circle in the center of the image
+ cr->arc(surface->get_width() / 2.0, surface->get_height() / 2.0,
+ surface->get_height() / 4.0, 0.0, 2.0 * M_PI);
+ cr->stroke();
+
+ // draw a diagonal line
+ cr->move_to(surface->get_width() / 4.0, surface->get_height() / 4.0);
+ cr->line_to(surface->get_width() * 3.0 / 4.0,
+ surface->get_height() * 3.0 / 4.0);
+ cr->stroke();
+ cr->restore();
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+
+ std::string filename = "image.png";
+ surface->write_to_png(filename);
+
+ std::cout << "Wrote png file \"" << filename << "\"" << std::endl;
+
+#else
+
+ std::cout
+ << "You must compile cairo with PNG support for this example to work."
+ << std::endl;
+
+#endif
+}
diff --git a/Tests/FindGTK2/gdk/CMakeLists.txt b/Tests/FindGTK2/gdk/CMakeLists.txt
new file mode 100644
index 0000000..35ef337
--- /dev/null
+++ b/Tests/FindGTK2/gdk/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(gdk C)
+
+find_package(GTK2 COMPONENTS gtk REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(gdk WIN32 main.c)
+target_link_libraries(gdk GTK2::gdk)
diff --git a/Tests/FindGTK2/gdk/main.c b/Tests/FindGTK2/gdk/main.c
new file mode 100644
index 0000000..71f523b
--- /dev/null
+++ b/Tests/FindGTK2/gdk/main.c
@@ -0,0 +1,7 @@
+#include <gdk/gdk.h>
+
+int main(int argc, char* argv[])
+{
+ gdk_init(argc, argv);
+ return 0;
+}
diff --git a/Tests/FindGTK2/gdk_pixbuf/CMakeLists.txt b/Tests/FindGTK2/gdk_pixbuf/CMakeLists.txt
new file mode 100644
index 0000000..ea1b05d
--- /dev/null
+++ b/Tests/FindGTK2/gdk_pixbuf/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(gdk_pixbuf C)
+
+find_package(GTK2 COMPONENTS gtk REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(gdk_pixbuf WIN32 main.c)
+target_link_libraries(gdk_pixbuf GTK2::gdk_pixbuf)
diff --git a/Tests/FindGTK2/gdk_pixbuf/main.c b/Tests/FindGTK2/gdk_pixbuf/main.c
new file mode 100644
index 0000000..ed9f564
--- /dev/null
+++ b/Tests/FindGTK2/gdk_pixbuf/main.c
@@ -0,0 +1,10 @@
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+int main(int argc, char* argv[])
+{
+ const char* version = gdk_pixbuf_version;
+ const guint major = gdk_pixbuf_major_version;
+ const guint minor = gdk_pixbuf_minor_version;
+ const guint micro = gdk_pixbuf_micro_version;
+ return 0;
+}
diff --git a/Tests/FindGTK2/gdkmm/CMakeLists.txt b/Tests/FindGTK2/gdkmm/CMakeLists.txt
new file mode 100644
index 0000000..72fc6f4
--- /dev/null
+++ b/Tests/FindGTK2/gdkmm/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(gdkmm CXX)
+
+find_package(GTK2 COMPONENTS gtk gtkmm REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(gdkmm WIN32 main.cpp)
+target_link_libraries(gdkmm GTK2::gdkmm)
diff --git a/Tests/FindGTK2/gdkmm/main.cpp b/Tests/FindGTK2/gdkmm/main.cpp
new file mode 100644
index 0000000..639e261
--- /dev/null
+++ b/Tests/FindGTK2/gdkmm/main.cpp
@@ -0,0 +1,7 @@
+#include <gdkmm.h>
+
+int main(int argc, char* argv[])
+{
+ Gdk::Color red = Gdk::Color("red");
+ return 0;
+}
diff --git a/Tests/FindGTK2/gio/CMakeLists.txt b/Tests/FindGTK2/gio/CMakeLists.txt
new file mode 100644
index 0000000..4835afa
--- /dev/null
+++ b/Tests/FindGTK2/gio/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(gio C)
+
+find_package(GTK2 COMPONENTS gtk REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(gio WIN32 main.c)
+target_link_libraries(gio GTK2::gio)
diff --git a/Tests/FindGTK2/gio/main.c b/Tests/FindGTK2/gio/main.c
new file mode 100644
index 0000000..ebed1fc
--- /dev/null
+++ b/Tests/FindGTK2/gio/main.c
@@ -0,0 +1,8 @@
+#include <gio/gio.h>
+
+int main(int argc, char* argv[])
+{
+ GFile* file = g_file_new_for_path("path");
+ g_object_unref(file);
+ return 0;
+}
diff --git a/Tests/FindGTK2/giomm/CMakeLists.txt b/Tests/FindGTK2/giomm/CMakeLists.txt
new file mode 100644
index 0000000..b639979
--- /dev/null
+++ b/Tests/FindGTK2/giomm/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(giomm CXX)
+
+find_package(GTK2 COMPONENTS gtk gtkmm REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(giomm WIN32 main.cpp)
+target_link_libraries(giomm GTK2::giomm)
diff --git a/Tests/FindGTK2/giomm/main.cpp b/Tests/FindGTK2/giomm/main.cpp
new file mode 100644
index 0000000..c0d5975
--- /dev/null
+++ b/Tests/FindGTK2/giomm/main.cpp
@@ -0,0 +1,7 @@
+#include <giomm.h>
+
+int main(int argc, char* argv[])
+{
+ Glib::RefPtr<Gio::File> f = Gio::File::create_for_path("path");
+ return 0;
+}
diff --git a/Tests/FindGTK2/glib/CMakeLists.txt b/Tests/FindGTK2/glib/CMakeLists.txt
new file mode 100644
index 0000000..536fc67
--- /dev/null
+++ b/Tests/FindGTK2/glib/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(glib C)
+
+find_package(GTK2 COMPONENTS gtk REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(glib WIN32 main.c)
+target_link_libraries(glib GTK2::glib)
diff --git a/Tests/FindGTK2/glib/main.c b/Tests/FindGTK2/glib/main.c
new file mode 100644
index 0000000..cf5e458
--- /dev/null
+++ b/Tests/FindGTK2/glib/main.c
@@ -0,0 +1,11 @@
+#include <glib.h>
+
+int main(int argc, char* argv[])
+{
+ if (!g_file_test("file", G_FILE_TEST_EXISTS)) {
+ g_print("File not found. \n");
+ } else {
+ g_print("File found. \n");
+ }
+ return 0;
+}
diff --git a/Tests/FindGTK2/glibmm/CMakeLists.txt b/Tests/FindGTK2/glibmm/CMakeLists.txt
new file mode 100644
index 0000000..25d5518
--- /dev/null
+++ b/Tests/FindGTK2/glibmm/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(glibmm CXX)
+
+find_package(GTK2 COMPONENTS gtk gtkmm REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(glibmm WIN32 main.cpp)
+target_link_libraries(glibmm GTK2::glibmm)
diff --git a/Tests/FindGTK2/glibmm/main.cpp b/Tests/FindGTK2/glibmm/main.cpp
new file mode 100644
index 0000000..3cdc0bd
--- /dev/null
+++ b/Tests/FindGTK2/glibmm/main.cpp
@@ -0,0 +1,7 @@
+#include <glibmm/init.h>
+
+int main(int, char**)
+{
+ Glib::init();
+ return 0;
+}
diff --git a/Tests/FindGTK2/gmodule/CMakeLists.txt b/Tests/FindGTK2/gmodule/CMakeLists.txt
new file mode 100644
index 0000000..2bfb81e
--- /dev/null
+++ b/Tests/FindGTK2/gmodule/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(gmodule C)
+
+find_package(GTK2 COMPONENTS gtk REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(gmodule WIN32 main.c)
+target_link_libraries(gmodule GTK2::gmodule)
diff --git a/Tests/FindGTK2/gmodule/main.c b/Tests/FindGTK2/gmodule/main.c
new file mode 100644
index 0000000..1ac5c1d
--- /dev/null
+++ b/Tests/FindGTK2/gmodule/main.c
@@ -0,0 +1,7 @@
+#include <gmodule.h>
+
+int main(int argc, char* argv[])
+{
+ gboolean b = g_module_supported();
+ return 0;
+}
diff --git a/Tests/FindGTK2/gobject/CMakeLists.txt b/Tests/FindGTK2/gobject/CMakeLists.txt
new file mode 100644
index 0000000..11520f8
--- /dev/null
+++ b/Tests/FindGTK2/gobject/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(gobject C)
+
+find_package(GTK2 COMPONENTS gtk REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(gobject WIN32 main.c)
+target_link_libraries(gobject GTK2::gobject)
diff --git a/Tests/FindGTK2/gobject/main.c b/Tests/FindGTK2/gobject/main.c
new file mode 100644
index 0000000..46e2127
--- /dev/null
+++ b/Tests/FindGTK2/gobject/main.c
@@ -0,0 +1,70 @@
+/* Taken from https://developer.gnome.org/gobject/stable/chapter-gobject.html
+ */
+
+#include <glib-object.h>
+
+#define MAMAN_TYPE_BAR (maman_bar_get_type())
+#define MAMAN_BAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), MAMAN_TYPE_BAR, MamanBar))
+#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), MAMAN_TYPE_BAR))
+#define MAMAN_BAR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), MAMAN_TYPE_BAR, MamanBarClass))
+#define MAMAN_IS_BAR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), MAMAN_TYPE_BAR))
+#define MAMAN_BAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), MAMAN_TYPE_BAR, MamanBarClass))
+
+typedef struct _MamanBar MamanBar;
+typedef struct _MamanBarClass MamanBarClass;
+
+struct _MamanBar
+{
+ GObject parent_instance;
+
+ /* instance members */
+};
+
+struct _MamanBarClass
+{
+ GObjectClass parent_class;
+
+ /* class members */
+};
+
+/* will create maman_bar_get_type and set maman_bar_parent_class */
+G_DEFINE_TYPE(MamanBar, maman_bar, G_TYPE_OBJECT);
+
+static GObject* maman_bar_constructor(GType gtype, guint n_properties,
+ GObjectConstructParam* properties)
+{
+ GObject* obj;
+
+ {
+ /* Always chain up to the parent constructor */
+ obj = G_OBJECT_CLASS(maman_bar_parent_class)
+ ->constructor(gtype, n_properties, properties);
+ }
+
+ /* update the object state depending on constructor properties */
+
+ return obj;
+}
+
+static void maman_bar_class_init(MamanBarClass* klass)
+{
+ GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
+
+ gobject_class->constructor = maman_bar_constructor;
+}
+
+static void maman_bar_init(MamanBar* self)
+{
+ /* initialize the object */
+}
+
+int main(int argc, char* argv[])
+{
+ MamanBar* bar = g_object_new(MAMAN_TYPE_BAR, NULL);
+ g_object_unref(bar);
+ return 0;
+}
diff --git a/Tests/FindGTK2/gthread/CMakeLists.txt b/Tests/FindGTK2/gthread/CMakeLists.txt
new file mode 100644
index 0000000..5ecfd9b
--- /dev/null
+++ b/Tests/FindGTK2/gthread/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(gthread C)
+
+find_package(GTK2 COMPONENTS gtk REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(gthread WIN32 main.c)
+target_link_libraries(gthread GTK2::gthread)
diff --git a/Tests/FindGTK2/gthread/main.c b/Tests/FindGTK2/gthread/main.c
new file mode 100644
index 0000000..9606401
--- /dev/null
+++ b/Tests/FindGTK2/gthread/main.c
@@ -0,0 +1,7 @@
+#include <glib.h>
+
+int main(int argc, char* argv[])
+{
+ g_thread_init(NULL);
+ return 0;
+}
diff --git a/Tests/FindGTK2/gtk/CMakeLists.txt b/Tests/FindGTK2/gtk/CMakeLists.txt
new file mode 100644
index 0000000..2c67619
--- /dev/null
+++ b/Tests/FindGTK2/gtk/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(gtk C)
+
+find_package(GTK2 COMPONENTS gtk REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(gtk WIN32 main.c)
+target_link_libraries(gtk GTK2::gtk)
+
+add_executable(gtk-all-libs WIN32 main.c)
+target_link_libraries(gtk-all-libs ${GTK2_LIBRARIES})
+target_include_directories(gtk-all-libs PRIVATE ${GTK2_INCLUDE_DIRS})
diff --git a/Tests/FindGTK2/gtk/main.c b/Tests/FindGTK2/gtk/main.c
new file mode 100644
index 0000000..010830a
--- /dev/null
+++ b/Tests/FindGTK2/gtk/main.c
@@ -0,0 +1,15 @@
+#include <gtk/gtk.h>
+
+int main(int argc, char* argv[])
+{
+ GtkWidget* window;
+
+ gtk_init(&argc, &argv);
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_widget_show(window);
+
+ gtk_main();
+
+ return 0;
+}
diff --git a/Tests/FindGTK2/gtkmm/CMakeLists.txt b/Tests/FindGTK2/gtkmm/CMakeLists.txt
new file mode 100644
index 0000000..3375a55
--- /dev/null
+++ b/Tests/FindGTK2/gtkmm/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(gtkmm CXX)
+
+find_package(GTK2 COMPONENTS gtk gtkmm REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(gtkmm-target WIN32 main.cpp helloworld.cpp helloworld.h)
+target_link_libraries(gtkmm-target GTK2::gtkmm)
+
+add_executable(gtkmm-all-libs WIN32 main.cpp helloworld.cpp helloworld.h)
+target_link_libraries(gtkmm-all-libs ${GTK2_LIBRARIES})
+target_include_directories(gtkmm-all-libs PRIVATE ${GTK2_INCLUDE_DIRS})
+
+# Linking via the library variables does not cause compile feature
+# requirements to propagate. Do it manually for purposes of this test.
+get_property(features TARGET GTK2::sigc++ PROPERTY INTERFACE_COMPILE_FEATURES)
+set_property(TARGET gtkmm-all-libs PROPERTY COMPILE_FEATURES ${features})
diff --git a/Tests/FindGTK2/gtkmm/helloworld.cpp b/Tests/FindGTK2/gtkmm/helloworld.cpp
new file mode 100644
index 0000000..45c9422
--- /dev/null
+++ b/Tests/FindGTK2/gtkmm/helloworld.cpp
@@ -0,0 +1,30 @@
+#include "helloworld.h"
+
+#include <iostream>
+
+HelloWorld::HelloWorld()
+ : m_button("Hello World") // creates a new button with label "Hello World".
+{
+ // Sets the border width of the window.
+ set_border_width(10);
+
+ // When the button receives the "clicked" signal, it will call the
+ // on_button_clicked() method defined below.
+ m_button.signal_clicked().connect(
+ sigc::mem_fun(*this, &HelloWorld::on_button_clicked));
+
+ // This packs the button into the Window (a container).
+ add(m_button);
+
+ // The final step is to display this newly created widget...
+ m_button.show();
+}
+
+HelloWorld::~HelloWorld()
+{
+}
+
+void HelloWorld::on_button_clicked()
+{
+ std::cout << "Hello World" << std::endl;
+}
diff --git a/Tests/FindGTK2/gtkmm/helloworld.h b/Tests/FindGTK2/gtkmm/helloworld.h
new file mode 100644
index 0000000..ae9af17
--- /dev/null
+++ b/Tests/FindGTK2/gtkmm/helloworld.h
@@ -0,0 +1,20 @@
+#ifndef GTKMM_EXAMPLE_HELLOWORLD_H
+#define GTKMM_EXAMPLE_HELLOWORLD_H
+
+#include <gtkmm.h>
+
+class HelloWorld : public Gtk::Window
+{
+public:
+ HelloWorld();
+ virtual ~HelloWorld();
+
+protected:
+ // Signal handlers:
+ void on_button_clicked();
+
+ // Member widgets:
+ Gtk::Button m_button;
+};
+
+#endif // GTKMM_EXAMPLE_HELLOWORLD_H
diff --git a/Tests/FindGTK2/gtkmm/main.cpp b/Tests/FindGTK2/gtkmm/main.cpp
new file mode 100644
index 0000000..29e23fd
--- /dev/null
+++ b/Tests/FindGTK2/gtkmm/main.cpp
@@ -0,0 +1,14 @@
+#include <gtkmm.h>
+
+#include "helloworld.h"
+
+int main(int argc, char* argv[])
+{
+ Gtk::Main kit(argc, argv);
+
+ HelloWorld helloworld;
+ // Shows the window and returns when it is closed.
+ Gtk::Main::run(helloworld);
+
+ return 0;
+}
diff --git a/Tests/FindGTK2/pango/CMakeLists.txt b/Tests/FindGTK2/pango/CMakeLists.txt
new file mode 100644
index 0000000..bd6b13a
--- /dev/null
+++ b/Tests/FindGTK2/pango/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(pango C)
+
+find_package(GTK2 COMPONENTS gtk REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(pango WIN32 main.c)
+target_link_libraries(pango GTK2::pango)
diff --git a/Tests/FindGTK2/pango/main.c b/Tests/FindGTK2/pango/main.c
new file mode 100644
index 0000000..aa6ea92
--- /dev/null
+++ b/Tests/FindGTK2/pango/main.c
@@ -0,0 +1,7 @@
+#include <pango/pango.h>
+
+int main(int argc, char* argv[])
+{
+ gboolean ret = pango_color_parse(NULL, "#ffffff");
+ return 0;
+}
diff --git a/Tests/FindGTK2/pangocairo/CMakeLists.txt b/Tests/FindGTK2/pangocairo/CMakeLists.txt
new file mode 100644
index 0000000..157b9c2
--- /dev/null
+++ b/Tests/FindGTK2/pangocairo/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(pangocairo C)
+
+find_package(GTK2 COMPONENTS gtk REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(pangocairo WIN32 main.c)
+target_link_libraries(pangocairo GTK2::pangocairo m)
diff --git a/Tests/FindGTK2/pangocairo/main.c b/Tests/FindGTK2/pangocairo/main.c
new file mode 100644
index 0000000..15db513
--- /dev/null
+++ b/Tests/FindGTK2/pangocairo/main.c
@@ -0,0 +1,68 @@
+/* Taken from
+ * https://developer.gnome.org/pango/stable/pango-Cairo-Rendering.html */
+
+#include <math.h>
+#include <pango/pangocairo.h>
+static void draw_text(cairo_t* cr)
+{
+#define RADIUS 150
+#define N_WORDS 10
+#define FONT "Sans Bold 27"
+ PangoLayout* layout;
+ PangoFontDescription* desc;
+ int i;
+ /* Center coordinates on the middle of the region we are drawing
+ */
+ cairo_translate(cr, RADIUS, RADIUS);
+ /* Create a PangoLayout, set the font and text */
+ layout = pango_cairo_create_layout(cr);
+ pango_layout_set_text(layout, "Text", -1);
+ desc = pango_font_description_from_string(FONT);
+ pango_layout_set_font_description(layout, desc);
+ pango_font_description_free(desc);
+ /* Draw the layout N_WORDS times in a circle */
+ for (i = 0; i < N_WORDS; i++) {
+ int width, height;
+ double angle = (360. * i) / N_WORDS;
+ double red;
+ cairo_save(cr);
+ /* Gradient from red at angle == 60 to blue at angle == 240 */
+ red = (1 + cos((angle - 60) * G_PI / 180.)) / 2;
+ cairo_set_source_rgb(cr, red, 0, 1.0 - red);
+ cairo_rotate(cr, angle * G_PI / 180.);
+ /* Inform Pango to re-layout the text with the new transformation */
+ pango_cairo_update_layout(cr, layout);
+ pango_layout_get_size(layout, &width, &height);
+ cairo_move_to(cr, -((double)width / PANGO_SCALE) / 2, -RADIUS);
+ pango_cairo_show_layout(cr, layout);
+ cairo_restore(cr);
+ }
+ /* free the layout object */
+ g_object_unref(layout);
+}
+int main(int argc, char** argv)
+{
+ cairo_t* cr;
+ char* filename;
+ cairo_status_t status;
+ cairo_surface_t* surface;
+ if (argc != 2) {
+ g_printerr("Usage: cairosimple OUTPUT_FILENAME\n");
+ return 1;
+ }
+ filename = argv[1];
+ surface =
+ cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 2 * RADIUS, 2 * RADIUS);
+ cr = cairo_create(surface);
+ cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+ cairo_paint(cr);
+ draw_text(cr);
+ cairo_destroy(cr);
+ status = cairo_surface_write_to_png(surface, filename);
+ cairo_surface_destroy(surface);
+ if (status != CAIRO_STATUS_SUCCESS) {
+ g_printerr("Could not save png to '%s'\n", filename);
+ return 1;
+ }
+ return 0;
+}
diff --git a/Tests/FindGTK2/pangoft2/CMakeLists.txt b/Tests/FindGTK2/pangoft2/CMakeLists.txt
new file mode 100644
index 0000000..76966e7
--- /dev/null
+++ b/Tests/FindGTK2/pangoft2/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(pangoft2 C)
+
+find_package(GTK2 COMPONENTS gtk REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(pangoft2 WIN32 main.c)
+target_link_libraries(pangoft2 GTK2::pangoft2)
diff --git a/Tests/FindGTK2/pangoft2/main.c b/Tests/FindGTK2/pangoft2/main.c
new file mode 100644
index 0000000..317f7ec
--- /dev/null
+++ b/Tests/FindGTK2/pangoft2/main.c
@@ -0,0 +1,8 @@
+#include <pango/pangoft2.h>
+
+int main(int argc, char* argv[])
+{
+ PangoFontMap* pfm = pango_ft2_font_map_new();
+ g_object_unref(pfm);
+ return 0;
+}
diff --git a/Tests/FindGTK2/pangomm/CMakeLists.txt b/Tests/FindGTK2/pangomm/CMakeLists.txt
new file mode 100644
index 0000000..0bb49e2
--- /dev/null
+++ b/Tests/FindGTK2/pangomm/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(pangomm CXX)
+
+find_package(GTK2 COMPONENTS gtk gtkmm REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(pangomm WIN32 main.cpp)
+target_link_libraries(pangomm GTK2::pangomm)
diff --git a/Tests/FindGTK2/pangomm/main.cpp b/Tests/FindGTK2/pangomm/main.cpp
new file mode 100644
index 0000000..47bf490
--- /dev/null
+++ b/Tests/FindGTK2/pangomm/main.cpp
@@ -0,0 +1,8 @@
+#include <pangomm.h>
+#include <pangomm/init.h>
+
+int main(int argc, char* argv[])
+{
+ Pango::init();
+ return 0;
+}
diff --git a/Tests/FindGTK2/pangoxft/CMakeLists.txt b/Tests/FindGTK2/pangoxft/CMakeLists.txt
new file mode 100644
index 0000000..7051d35
--- /dev/null
+++ b/Tests/FindGTK2/pangoxft/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(pangoxft C)
+
+find_package(GTK2 COMPONENTS gtk REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(pangoxft WIN32 main.c)
+target_link_libraries(pangoxft GTK2::pangoxft)
diff --git a/Tests/FindGTK2/pangoxft/main.c b/Tests/FindGTK2/pangoxft/main.c
new file mode 100644
index 0000000..181ba27
--- /dev/null
+++ b/Tests/FindGTK2/pangoxft/main.c
@@ -0,0 +1,7 @@
+#include <pango/pangoxft.h>
+
+int main(int argc, char* argv[])
+{
+ pango_xft_get_context(NULL, 0);
+ return 0;
+}
diff --git a/Tests/FindGTK2/sigc++/CMakeLists.txt b/Tests/FindGTK2/sigc++/CMakeLists.txt
new file mode 100644
index 0000000..9c1fff7
--- /dev/null
+++ b/Tests/FindGTK2/sigc++/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(sigc++ CXX)
+
+find_package(GTK2 COMPONENTS gtk gtkmm REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(sigc++ WIN32 main.cpp)
+target_link_libraries(sigc++ GTK2::sigc++)
diff --git a/Tests/FindGTK2/sigc++/main.cpp b/Tests/FindGTK2/sigc++/main.cpp
new file mode 100644
index 0000000..4dae4f4
--- /dev/null
+++ b/Tests/FindGTK2/sigc++/main.cpp
@@ -0,0 +1,30 @@
+// Taken from https://developer.gnome.org/libsigc++-tutorial/stable/ch02.html
+
+#include <iostream>
+
+#include <sigc++/sigc++.h>
+
+class AlienDetector
+{
+public:
+ AlienDetector() {}
+
+ void run() {}
+
+ sigc::signal<void> signal_detected;
+};
+
+void warn_people()
+{
+ std::cout << "There are aliens in the carpark!" << std::endl;
+}
+
+int main()
+{
+ AlienDetector mydetector;
+ mydetector.signal_detected.connect(sigc::ptr_fun(warn_people));
+
+ mydetector.run();
+
+ return 0;
+}
diff --git a/Tests/FindGTest/CMakeLists.txt b/Tests/FindGTest/CMakeLists.txt
new file mode 100644
index 0000000..cbc92b1
--- /dev/null
+++ b/Tests/FindGTest/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindGTest.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGTest/Test"
+ "${CMake_BINARY_DIR}/Tests/FindGTest/Test"
+ ${build_generator_args}
+ --build-project TestFindGTest
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindGTest/Test/CMakeLists.txt b/Tests/FindGTest/Test/CMakeLists.txt
new file mode 100644
index 0000000..6537238
--- /dev/null
+++ b/Tests/FindGTest/Test/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindGTest CXX)
+include(CTest)
+
+find_package(GTest REQUIRED)
+
+add_executable(test_gtest_tgt main.cxx)
+target_link_libraries(test_gtest_tgt GTest::Main)
+add_test(NAME test_gtest_tgt COMMAND test_gtest_tgt)
+
+add_executable(test_gtest_tgt_upstream main.cxx)
+target_link_libraries(test_gtest_tgt_upstream GTest::gtest_main)
+add_test(NAME test_gtest_tgt_upstream COMMAND test_gtest_tgt_upstream)
+
+add_executable(test_gtest_var main.cxx)
+target_include_directories(test_gtest_var PRIVATE ${GTEST_INCLUDE_DIRS})
+target_link_libraries(test_gtest_var PRIVATE ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
+add_test(NAME test_gtest_var COMMAND test_gtest_var)
diff --git a/Tests/FindGTest/Test/main.cxx b/Tests/FindGTest/Test/main.cxx
new file mode 100644
index 0000000..19d2967
--- /dev/null
+++ b/Tests/FindGTest/Test/main.cxx
@@ -0,0 +1,8 @@
+#include <gtest/gtest.h>
+
+TEST(FindCMake, LinksAndRuns)
+{
+ using namespace testing;
+ EXPECT_FALSE(GTEST_FLAG(list_tests));
+ ASSERT_TRUE(true);
+}
diff --git a/Tests/FindGit/CMakeLists.txt b/Tests/FindGit/CMakeLists.txt
new file mode 100644
index 0000000..5d061f4
--- /dev/null
+++ b/Tests/FindGit/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindGit.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGit/Test"
+ "${CMake_BINARY_DIR}/Tests/FindGit/Test"
+ ${build_generator_args}
+ --build-project TestFindGit
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindGit/Test/CMakeLists.txt b/Tests/FindGit/Test/CMakeLists.txt
new file mode 100644
index 0000000..26fb372
--- /dev/null
+++ b/Tests/FindGit/Test/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.12)
+project(TestFindGit NONE)
+include(CTest)
+
+find_package(Git REQUIRED)
+
+add_test(NAME test_git
+ COMMAND ${CMAKE_COMMAND}
+ "-DGIT_EXECUTABLE=${GIT_EXECUTABLE}"
+ "-DGIT_EXECUTABLE_TARGET=$<TARGET_FILE:Git::Git>"
+ "-DGIT_VERSION_STRING=${GIT_VERSION_STRING}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/RunGit.cmake"
+ )
diff --git a/Tests/FindGit/Test/RunGit.cmake b/Tests/FindGit/Test/RunGit.cmake
new file mode 100644
index 0000000..f798cd3
--- /dev/null
+++ b/Tests/FindGit/Test/RunGit.cmake
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.12)
+
+function(run_git exe exe_display)
+ execute_process(COMMAND ${exe} --version
+ OUTPUT_VARIABLE output
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ RESULT_VARIABLE result
+ )
+
+ if(NOT result EQUAL 0)
+ message(SEND_ERROR "Result of ${exe_display} --version is ${result}, should be 0")
+ endif()
+
+ if(NOT output STREQUAL "git version ${GIT_VERSION_STRING}")
+ message(SEND_ERROR "Output of ${exe_display} --version is \"${output}\", should be \"git version ${GIT_VERSION_STRING}\"")
+ endif()
+endfunction()
+
+run_git("${GIT_EXECUTABLE}" "\${GIT_EXECUTABLE}")
+run_git("${GIT_EXECUTABLE_TARGET}" "Git::Git")
diff --git a/Tests/FindGnuTLS/CMakeLists.txt b/Tests/FindGnuTLS/CMakeLists.txt
new file mode 100644
index 0000000..059ac7b
--- /dev/null
+++ b/Tests/FindGnuTLS/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindGnuTLS.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindGnuTLS/Test"
+ "${CMake_BINARY_DIR}/Tests/FindGnuTLS/Test"
+ ${build_generator_args}
+ --build-project TestFindGnuTLS
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindGnuTLS/Test/CMakeLists.txt b/Tests/FindGnuTLS/Test/CMakeLists.txt
new file mode 100644
index 0000000..c5a9819
--- /dev/null
+++ b/Tests/FindGnuTLS/Test/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.4)
+project(TestFindGnuTLS C)
+include(CTest)
+
+find_package(GnuTLS REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_GNUTLS_VERSION="${GNUTLS_VERSION}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt GnuTLS::GnuTLS)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${GNUTLS_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${GNUTLS_LIBRARIES})
+target_compile_definitions(test_var PRIVATE ${GNUTLS_DEFINITIONS})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindGnuTLS/Test/main.c b/Tests/FindGnuTLS/Test/main.c
new file mode 100644
index 0000000..1105358
--- /dev/null
+++ b/Tests/FindGnuTLS/Test/main.c
@@ -0,0 +1,21 @@
+#include <assert.h>
+#include <gnutls/gnutls.h>
+#include <stdio.h>
+#include <string.h>
+
+int main()
+{
+ // test the linker
+ gnutls_session_t session;
+ if (gnutls_init(&session, GNUTLS_CLIENT)) {
+ gnutls_deinit(session);
+ }
+
+ // check the version
+ char gnutls_version_string[16];
+ snprintf(gnutls_version_string, 16, "%i.%i.%i", GNUTLS_VERSION_MAJOR,
+ GNUTLS_VERSION_MINOR, GNUTLS_VERSION_PATCH);
+ assert(strcmp(gnutls_version_string, CMAKE_EXPECTED_GNUTLS_VERSION) == 0);
+
+ return 0;
+}
diff --git a/Tests/FindICU/CMakeLists.txt b/Tests/FindICU/CMakeLists.txt
new file mode 100644
index 0000000..4acaaf2
--- /dev/null
+++ b/Tests/FindICU/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindICU.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindICU/Test"
+ "${CMake_BINARY_DIR}/Tests/FindICU/Test"
+ ${build_generator_args}
+ --build-project TestFindICU
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindICU/Test/CMakeLists.txt b/Tests/FindICU/Test/CMakeLists.txt
new file mode 100644
index 0000000..1247ac7
--- /dev/null
+++ b/Tests/FindICU/Test/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindICU LANGUAGES CXX)
+include(CTest)
+
+find_package(ICU REQUIRED COMPONENTS i18n uc)
+
+add_executable(test_icu_tgt main.cpp)
+target_link_libraries(test_icu_tgt ICU::i18n ICU::uc)
+add_test(NAME test_icu_tgt COMMAND test_icu_tgt)
+
+add_executable(test_icu_var main.cpp)
+target_include_directories(test_icu_var PRIVATE ${ICU_INCLUDE_DIRS})
+target_link_libraries(test_icu_var PRIVATE ${ICU_LIBRARIES})
+add_test(NAME test_icu_var COMMAND test_icu_var)
diff --git a/Tests/FindICU/Test/main.cpp b/Tests/FindICU/Test/main.cpp
new file mode 100644
index 0000000..606e94e
--- /dev/null
+++ b/Tests/FindICU/Test/main.cpp
@@ -0,0 +1,23 @@
+#include <unicode/ucal.h>
+#include <unicode/uclean.h>
+#include <unicode/ucnv.h>
+#include <unicode/udat.h>
+#include <unicode/ustring.h>
+#include <unicode/utypes.h>
+
+int main()
+{
+ UConverter* cnv = 0;
+ UErrorCode status = U_ZERO_ERROR;
+ ucnv_open(NULL, &status);
+
+ UChar uchars[100];
+ const char* chars = "Test";
+ if (cnv && U_SUCCESS(status)) {
+ int32_t len = ucnv_toUChars(cnv, uchars, 100, chars, -1, &status);
+ }
+
+ ucnv_close(cnv);
+ u_cleanup();
+ return (U_FAILURE(status) ? 1 : 0);
+}
diff --git a/Tests/FindIconv/CMakeLists.txt b/Tests/FindIconv/CMakeLists.txt
new file mode 100644
index 0000000..b205b80
--- /dev/null
+++ b/Tests/FindIconv/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindIconv.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindIconv/Test"
+ "${CMake_BINARY_DIR}/Tests/FindIconv/Test"
+ ${build_generator_args}
+ --build-project TestFindIconv
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindIconv/Test/CMakeLists.txt b/Tests/FindIconv/Test/CMakeLists.txt
new file mode 100644
index 0000000..a6243f5
--- /dev/null
+++ b/Tests/FindIconv/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindIconv CXX)
+include(CTest)
+
+find_package(Iconv REQUIRED)
+
+add_executable(test_iconv_tgt main.cxx)
+target_link_libraries(test_iconv_tgt Iconv::Iconv)
+target_compile_features(test_iconv_tgt PRIVATE cxx_std_11)
+add_test(NAME test_iconv_tgt COMMAND test_iconv_tgt)
+
+add_executable(test_iconv_var main.cxx)
+target_include_directories(test_iconv_var PRIVATE ${Iconv_INCLUDE_DIRS})
+target_link_libraries(test_iconv_var PRIVATE ${Iconv_LIBRARIES})
+target_compile_features(test_iconv_var PRIVATE cxx_std_11)
+add_test(NAME test_iconv_var COMMAND test_iconv_var)
diff --git a/Tests/FindIconv/Test/main.cxx b/Tests/FindIconv/Test/main.cxx
new file mode 100644
index 0000000..415ee37
--- /dev/null
+++ b/Tests/FindIconv/Test/main.cxx
@@ -0,0 +1,52 @@
+extern "C" {
+#include <iconv.h>
+}
+#include <array>
+#include <cstddef>
+#include <cstdlib>
+#include <iostream>
+#include <string>
+#include <system_error>
+
+class iconv_desc
+{
+private:
+ iconv_t iconvd_;
+
+public:
+ iconv_desc(const std::string& tocode, const std::string& fromcode)
+ {
+ iconvd_ = iconv_open(tocode.c_str(), fromcode.c_str());
+ if (iconvd_ == reinterpret_cast<iconv_t>(-1))
+ throw std::system_error(errno, std::system_category());
+ }
+
+ ~iconv_desc() { iconv_close(iconvd_); }
+
+ operator iconv_t() { return this->iconvd_; }
+};
+
+int main()
+{
+ try {
+ auto conv_d = iconv_desc{ "ISO-8859-1", "UTF-8" };
+ auto from_str = std::array<char, 10>{ u8"a\xC3\xA4o\xC3\xB6u\xC3\xBC" };
+ auto to_str = std::array<char, 7>{};
+
+ auto from_str_ptr = from_str.data();
+ auto from_len = from_str.size();
+ auto to_str_ptr = to_str.data();
+ auto to_len = to_str.size();
+ const auto iconv_ret =
+ iconv(conv_d, &from_str_ptr, &from_len, &to_str_ptr, &to_len);
+ if (iconv_ret == static_cast<std::size_t>(-1))
+ throw std::system_error(errno, std::system_category());
+ std::cout << '\'' << from_str.data() << "\' converted to \'"
+ << to_str.data() << '\'' << std::endl;
+ return EXIT_SUCCESS;
+ } catch (const std::system_error& ex) {
+ std::cerr << "ERROR: " << ex.code() << '\n'
+ << ex.code().message() << std::endl;
+ }
+ return EXIT_FAILURE;
+}
diff --git a/Tests/FindIntl/CMakeLists.txt b/Tests/FindIntl/CMakeLists.txt
new file mode 100644
index 0000000..0906ede
--- /dev/null
+++ b/Tests/FindIntl/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindIntl.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindIntl/Test"
+ "${CMake_BINARY_DIR}/Tests/FindIntl/Test"
+ ${build_generator_args}
+ --build-project TestFindIntl
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindIntl/Test/CMakeLists.txt b/Tests/FindIntl/Test/CMakeLists.txt
new file mode 100644
index 0000000..5140406
--- /dev/null
+++ b/Tests/FindIntl/Test/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindIntl CXX)
+include(CTest)
+
+find_package(Intl REQUIRED)
+
+add_executable(test_intl_tgt main.cxx)
+target_link_libraries(test_intl_tgt Intl::Intl)
+add_test(NAME test_intl_tgt COMMAND test_intl_tgt)
+
+add_executable(test_intl_var main.cxx)
+target_include_directories(test_intl_var PRIVATE ${Intl_INCLUDE_DIRS})
+target_link_libraries(test_intl_var PRIVATE ${Intl_LIBRARIES})
+add_test(NAME test_intl_var COMMAND test_intl_var)
diff --git a/Tests/FindIntl/Test/main.cxx b/Tests/FindIntl/Test/main.cxx
new file mode 100644
index 0000000..d90c095
--- /dev/null
+++ b/Tests/FindIntl/Test/main.cxx
@@ -0,0 +1,11 @@
+extern "C" {
+#include <libintl.h>
+}
+
+int main()
+{
+ // Check if we include the directory correctly and have no link errors
+ bindtextdomain("", "");
+ gettext("");
+ return 0;
+}
diff --git a/Tests/FindJPEG/CMakeLists.txt b/Tests/FindJPEG/CMakeLists.txt
new file mode 100644
index 0000000..c8663c5
--- /dev/null
+++ b/Tests/FindJPEG/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindJPEG.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindJPEG/Test"
+ "${CMake_BINARY_DIR}/Tests/FindJPEG/Test"
+ ${build_generator_args}
+ --build-project TestFindJPEG
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindJPEG/Test/CMakeLists.txt b/Tests/FindJPEG/Test/CMakeLists.txt
new file mode 100644
index 0000000..912c7a1
--- /dev/null
+++ b/Tests/FindJPEG/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindJPEG C)
+include(CTest)
+
+find_package(JPEG)
+
+add_definitions(-DCMAKE_EXPECTED_JPEG_VERSION=${JPEG_VERSION})
+
+add_executable(test_jpeg_tgt main.c)
+target_link_libraries(test_jpeg_tgt JPEG::JPEG)
+add_test(NAME test_jpeg_tgt COMMAND test_jpeg_tgt)
+
+add_executable(test_jpeg_var main.c)
+target_include_directories(test_jpeg_var PRIVATE ${JPEG_INCLUDE_DIRS})
+target_link_libraries(test_jpeg_var PRIVATE ${JPEG_LIBRARIES})
+add_test(NAME test_jpeg_var COMMAND test_jpeg_var)
diff --git a/Tests/FindJPEG/Test/main.c b/Tests/FindJPEG/Test/main.c
new file mode 100644
index 0000000..5a67faa
--- /dev/null
+++ b/Tests/FindJPEG/Test/main.c
@@ -0,0 +1,17 @@
+#include <assert.h>
+// clang-format off
+#include <stdio.h>
+#include <jpeglib.h>
+// clang-format on
+
+int main()
+{
+ /* Without any JPEG file to open, test that the call fails as
+ expected. This tests that linking worked. */
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
+
+ return (JPEG_LIB_VERSION != CMAKE_EXPECTED_JPEG_VERSION);
+}
diff --git a/Tests/FindJsonCpp/CMakeLists.txt b/Tests/FindJsonCpp/CMakeLists.txt
new file mode 100644
index 0000000..9a1fa38
--- /dev/null
+++ b/Tests/FindJsonCpp/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindJsonCpp.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindJsonCpp/Test"
+ "${CMake_BINARY_DIR}/Tests/FindJsonCpp/Test"
+ ${build_generator_args}
+ --build-project TestFindJsonCpp
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindJsonCpp/Test/CMakeLists.txt b/Tests/FindJsonCpp/Test/CMakeLists.txt
new file mode 100644
index 0000000..d1dc647
--- /dev/null
+++ b/Tests/FindJsonCpp/Test/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindJsonCpp CXX)
+include(CTest)
+
+# CMake does not actually provide FindJsonCpp publicly.
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../Source/Modules)
+
+find_package(JsonCpp REQUIRED)
+
+add_executable(test_jsoncpp_tgt main.cxx)
+target_link_libraries(test_jsoncpp_tgt JsonCpp::JsonCpp)
+add_test(NAME test_jsoncpp_tgt COMMAND test_jsoncpp_tgt)
+
+add_executable(test_jsoncpp_var main.cxx)
+target_include_directories(test_jsoncpp_var PRIVATE ${JsonCpp_INCLUDE_DIRS})
+target_link_libraries(test_jsoncpp_var PRIVATE ${JsonCpp_LIBRARIES})
+add_test(NAME test_jsoncpp_var COMMAND test_jsoncpp_var)
diff --git a/Tests/FindJsonCpp/Test/main.cxx b/Tests/FindJsonCpp/Test/main.cxx
new file mode 100644
index 0000000..0fefe32
--- /dev/null
+++ b/Tests/FindJsonCpp/Test/main.cxx
@@ -0,0 +1,8 @@
+#include <json/json.h>
+
+int main()
+{
+ int zero = 0;
+ Json::Value value(zero);
+ return value.asInt();
+}
diff --git a/Tests/FindLAPACK/CMakeLists.txt b/Tests/FindLAPACK/CMakeLists.txt
new file mode 100644
index 0000000..2081d59
--- /dev/null
+++ b/Tests/FindLAPACK/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindLAPACK.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindLAPACK/Test"
+ "${CMake_BINARY_DIR}/Tests/FindLAPACK/Test"
+ ${build_generator_args}
+ --build-project TestFindLAPACK
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindLAPACK/Test/CMakeLists.txt b/Tests/FindLAPACK/Test/CMakeLists.txt
new file mode 100644
index 0000000..8afa36a
--- /dev/null
+++ b/Tests/FindLAPACK/Test/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.4)
+project(TestFindLAPACK C)
+include(CTest)
+
+find_package(LAPACK REQUIRED)
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt LAPACK::LAPACK)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_link_libraries(test_var PRIVATE ${LAPACK_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindLAPACK/Test/main.c b/Tests/FindLAPACK/Test/main.c
new file mode 100644
index 0000000..5873e7b
--- /dev/null
+++ b/Tests/FindLAPACK/Test/main.c
@@ -0,0 +1,20 @@
+#include <assert.h>
+#include <string.h>
+
+// declare what parts of the lapack C-API we need
+void dgesv_(int*, int*, double*, int*, int*, double*, int*, int*);
+
+int main()
+{
+ double A[8] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ };
+ double B[2] = { 0, 5 };
+ int ipiv[2] = { 0, 0 };
+ int info = 0;
+
+ int dim = 2;
+ int numCols = 1;
+ dgesv_(&dim, &numCols, A, &dim, ipiv, B, &dim, &info);
+ return 0;
+}
diff --git a/Tests/FindLTTngUST/CMakeLists.txt b/Tests/FindLTTngUST/CMakeLists.txt
new file mode 100644
index 0000000..c9c471d
--- /dev/null
+++ b/Tests/FindLTTngUST/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindLTTngUST.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindLTTngUST/Test"
+ "${CMake_BINARY_DIR}/Tests/FindLTTngUST/Test"
+ ${build_generator_args}
+ --build-project TestFindLTTngUST
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindLTTngUST/Test/CMakeLists.txt b/Tests/FindLTTngUST/Test/CMakeLists.txt
new file mode 100644
index 0000000..e5bd9f3
--- /dev/null
+++ b/Tests/FindLTTngUST/Test/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.5)
+project(TestFindLTTngUST C)
+include(CTest)
+
+find_package(LTTngUST REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_LTTNGUST_VERSION="${LTTNGUST_VERSION_STRING}")
+add_definitions(-DCMAKE_LTTNGUST_HAS_TRACEF="${LTTNGUST_HAS_TRACEF}")
+add_definitions(-DCMAKE_LTTNGUST_HAS_TRACELOG="${LTTNGUST_HAS_TRACELOG}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt LTTng::UST)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${LTTNGUST_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${LTTNGUST_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindLTTngUST/Test/main.c b/Tests/FindLTTngUST/Test/main.c
new file mode 100644
index 0000000..01d73cb
--- /dev/null
+++ b/Tests/FindLTTngUST/Test/main.c
@@ -0,0 +1,31 @@
+#include <assert.h>
+#include <lttng/ust-version.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef CMAKE_LTTNGUST_HAS_TRACEF
+# include <lttng/tracef.h>
+#endif
+
+#ifdef CMAKE_LTTNGUST_HAS_TRACELOG
+# include <lttng/tracelog.h>
+#endif
+
+int main(void)
+{
+ char lttng_version_string[16];
+
+ snprintf(lttng_version_string, 16, "%u.%u.%u", LTTNG_UST_MAJOR_VERSION,
+ LTTNG_UST_MINOR_VERSION, LTTNG_UST_PATCHLEVEL_VERSION);
+ assert(!strcmp(lttng_version_string, CMAKE_EXPECTED_LTTNGUST_VERSION));
+
+#ifdef CMAKE_LTTNGUST_HAS_TRACEF
+ tracef("calling tracef()! %d %s", -23, CMAKE_EXPECTED_LTTNGUST_VERSION);
+#endif
+
+#ifdef CMAKE_LTTNGUST_HAS_TRACELOG
+ tracelog(TRACE_WARNING, "calling tracelog()! %d", 17);
+#endif
+
+ return 0;
+}
diff --git a/Tests/FindLibArchive/CMakeLists.txt b/Tests/FindLibArchive/CMakeLists.txt
new file mode 100644
index 0000000..f532ef2
--- /dev/null
+++ b/Tests/FindLibArchive/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindLibArchive.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindLibArchive/Test"
+ "${CMake_BINARY_DIR}/Tests/FindLibArchive/Test"
+ ${build_generator_args}
+ --build-project TestFindLibArchive
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindLibArchive/Test/CMakeLists.txt b/Tests/FindLibArchive/Test/CMakeLists.txt
new file mode 100644
index 0000000..35843bb
--- /dev/null
+++ b/Tests/FindLibArchive/Test/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.12)
+project(TestFindLibArchive C)
+include(CTest)
+
+find_package(LibArchive REQUIRED)
+
+add_executable(test_libarchive_tgt main.c)
+target_link_libraries(test_libarchive_tgt LibArchive::LibArchive)
+add_test(NAME test_libarchive_tgt COMMAND test_libarchive_tgt)
+
+add_executable(test_libarchive_var main.c)
+target_include_directories(test_libarchive_var PRIVATE ${LibArchive_INCLUDE_DIRS})
+target_link_libraries(test_libarchive_var PRIVATE ${LibArchive_LIBRARIES})
+add_test(NAME test_libarchive_var COMMAND test_libarchive_var)
diff --git a/Tests/FindLibArchive/Test/main.c b/Tests/FindLibArchive/Test/main.c
new file mode 100644
index 0000000..03e7ece
--- /dev/null
+++ b/Tests/FindLibArchive/Test/main.c
@@ -0,0 +1,7 @@
+#include <archive.h>
+
+int main(void)
+{
+ archive_read_free(archive_read_new());
+ return 0;
+}
diff --git a/Tests/FindLibLZMA/CMakeLists.txt b/Tests/FindLibLZMA/CMakeLists.txt
new file mode 100644
index 0000000..6dff0ef
--- /dev/null
+++ b/Tests/FindLibLZMA/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindLibLZMA.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindLibLZMA/Test"
+ "${CMake_BINARY_DIR}/Tests/FindLibLZMA/Test"
+ ${build_generator_args}
+ --build-project TestFindLibLZMA
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindLibLZMA/Test/CMakeLists.txt b/Tests/FindLibLZMA/Test/CMakeLists.txt
new file mode 100644
index 0000000..c59dcdb
--- /dev/null
+++ b/Tests/FindLibLZMA/Test/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.4)
+project(TestFindLZMA C)
+include(CTest)
+
+find_package(LibLZMA REQUIRED)
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt LibLZMA::LibLZMA)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${LIBLZMA_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${LIBLZMA_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindLibLZMA/Test/main.c b/Tests/FindLibLZMA/Test/main.c
new file mode 100644
index 0000000..06e8065
--- /dev/null
+++ b/Tests/FindLibLZMA/Test/main.c
@@ -0,0 +1,15 @@
+#include <assert.h>
+#include <lzma.h>
+#include <string.h>
+
+static const uint8_t test_string[9] = "123456789";
+
+int main()
+{
+ static const uint32_t test_vector = 0xCBF43926;
+
+ uint32_t crc = lzma_crc32(test_string, sizeof(test_string), 0);
+ assert(crc == test_vector);
+
+ return 0;
+}
diff --git a/Tests/FindLibRHash/CMakeLists.txt b/Tests/FindLibRHash/CMakeLists.txt
new file mode 100644
index 0000000..4d3954d
--- /dev/null
+++ b/Tests/FindLibRHash/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindLibRHash.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindLibRHash/Test"
+ "${CMake_BINARY_DIR}/Tests/FindLibRHash/Test"
+ ${build_generator_args}
+ --build-project TestFindLibRHash
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindLibRHash/Test/CMakeLists.txt b/Tests/FindLibRHash/Test/CMakeLists.txt
new file mode 100644
index 0000000..37e062a
--- /dev/null
+++ b/Tests/FindLibRHash/Test/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.7)
+project(TestFindLibRHash C)
+include(CTest)
+
+# CMake does not actually provide FindLibRHash publicly.
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../Source/Modules)
+
+find_package(LibRHash REQUIRED)
+
+add_executable(test_librhash_tgt main.c)
+target_link_libraries(test_librhash_tgt LibRHash::LibRHash)
+add_test(NAME test_librhash_tgt COMMAND test_librhash_tgt)
+
+add_executable(test_librhash_var main.c)
+target_include_directories(test_librhash_var PRIVATE ${LibRHash_INCLUDE_DIRS})
+target_link_libraries(test_librhash_var PRIVATE ${LibRHash_LIBRARIES})
+add_test(NAME test_librhash_var COMMAND test_librhash_var)
diff --git a/Tests/FindLibRHash/Test/main.c b/Tests/FindLibRHash/Test/main.c
new file mode 100644
index 0000000..201dced
--- /dev/null
+++ b/Tests/FindLibRHash/Test/main.c
@@ -0,0 +1,7 @@
+#include <rhash.h>
+
+int main()
+{
+ rhash_library_init();
+ return 0;
+}
diff --git a/Tests/FindLibUV/CMakeLists.txt b/Tests/FindLibUV/CMakeLists.txt
new file mode 100644
index 0000000..08aa958
--- /dev/null
+++ b/Tests/FindLibUV/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindLibUV.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindLibUV/Test"
+ "${CMake_BINARY_DIR}/Tests/FindLibUV/Test"
+ ${build_generator_args}
+ --build-project TestFindLibUV
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindLibUV/Test/CMakeLists.txt b/Tests/FindLibUV/Test/CMakeLists.txt
new file mode 100644
index 0000000..257ddf3
--- /dev/null
+++ b/Tests/FindLibUV/Test/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.6)
+project(TestFindLibUV C)
+include(CTest)
+
+# CMake does not actually provide FindLibUV publicly.
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../Source/Modules)
+
+find_package(LibUV REQUIRED)
+
+add_executable(test_libuv_tgt main.c)
+target_link_libraries(test_libuv_tgt LibUV::LibUV)
+add_test(NAME test_libuv_tgt COMMAND test_libuv_tgt)
+
+add_executable(test_libuv_var main.c)
+target_include_directories(test_libuv_var PRIVATE ${LibUV_INCLUDE_DIRS})
+target_link_libraries(test_libuv_var PRIVATE ${LibUV_LIBRARIES})
+add_test(NAME test_libuv_var COMMAND test_libuv_var)
diff --git a/Tests/FindLibUV/Test/main.c b/Tests/FindLibUV/Test/main.c
new file mode 100644
index 0000000..cbd0db3
--- /dev/null
+++ b/Tests/FindLibUV/Test/main.c
@@ -0,0 +1,7 @@
+#include <uv.h>
+
+int main()
+{
+ uv_loop_close(uv_default_loop());
+ return 0;
+}
diff --git a/Tests/FindLibXml2/CMakeLists.txt b/Tests/FindLibXml2/CMakeLists.txt
new file mode 100644
index 0000000..6c2464f
--- /dev/null
+++ b/Tests/FindLibXml2/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindLibXml2.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindLibXml2/Test"
+ "${CMake_BINARY_DIR}/Tests/FindLibXml2/Test"
+ ${build_generator_args}
+ --build-project TestFindLibXml2
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindLibXml2/Test/CMakeLists.txt b/Tests/FindLibXml2/Test/CMakeLists.txt
new file mode 100644
index 0000000..041cc13
--- /dev/null
+++ b/Tests/FindLibXml2/Test/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.4)
+project(TestFindLibXml2 C)
+include(CTest)
+
+find_package(LibXml2 REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_LibXml2_VERSION="${LIBXML2_VERSION_STRING}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt LibXml2::LibXml2)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${LIBXML2_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${LIBXML2_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
+
+add_test(NAME xmllint_tgt COMMAND LibXml2::xmllint --version)
+
+add_test(NAME xmllint_var COMMAND ${LIBXML2_XMLLINT_EXECUTABLE} --version)
diff --git a/Tests/FindLibXml2/Test/main.c b/Tests/FindLibXml2/Test/main.c
new file mode 100644
index 0000000..264f07d
--- /dev/null
+++ b/Tests/FindLibXml2/Test/main.c
@@ -0,0 +1,19 @@
+#include <assert.h>
+#include <libxml/tree.h>
+#include <string.h>
+
+int main()
+{
+ xmlDoc* doc;
+
+ xmlInitParser();
+
+ doc = xmlNewDoc(BAD_CAST "1.0");
+ xmlFreeDoc(doc);
+
+ assert(strstr(CMAKE_EXPECTED_LibXml2_VERSION, LIBXML_DOTTED_VERSION));
+
+ xmlCleanupParser();
+
+ return 0;
+}
diff --git a/Tests/FindLibXslt/CMakeLists.txt b/Tests/FindLibXslt/CMakeLists.txt
new file mode 100644
index 0000000..8a550b2
--- /dev/null
+++ b/Tests/FindLibXslt/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindLibXslt.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindLibXslt/Test"
+ "${CMake_BINARY_DIR}/Tests/FindLibXslt/Test"
+ ${build_generator_args}
+ --build-project TestFindLibXslt
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+)
diff --git a/Tests/FindLibXslt/Test/CMakeLists.txt b/Tests/FindLibXslt/Test/CMakeLists.txt
new file mode 100644
index 0000000..e932661
--- /dev/null
+++ b/Tests/FindLibXslt/Test/CMakeLists.txt
@@ -0,0 +1,45 @@
+cmake_minimum_required(VERSION 3.4)
+project(TestFindLibXslt C)
+include(CTest)
+
+find_package(Iconv)
+find_package(LibXml2 REQUIRED)
+find_package(LibXslt REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_LibXslt_VERSION="${LIBXSLT_VERSION_STRING}")
+
+add_executable(libxslt_tgt libxslt.c)
+if(Iconv_FOUND)
+ target_link_libraries(libxslt_tgt Iconv::Iconv)
+endif()
+target_link_libraries(libxslt_tgt LibXml2::LibXml2 LibXslt::LibXslt)
+add_test(NAME libxslt_tgt COMMAND libxslt_tgt)
+
+add_executable(libxslt_var libxslt.c)
+if(Iconv_FOUND)
+ target_include_directories(libxslt_var PRIVATE ${Iconv_INCLUDE_DIRS})
+ target_link_libraries(libxslt_var PRIVATE ${Iconv_LIBRARIES})
+endif()
+target_include_directories(libxslt_var PRIVATE ${LIBXML2_INCLUDE_DIRS} ${LIBXSLT_INCLUDE_DIR})
+target_link_libraries(libxslt_var PRIVATE ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES})
+add_test(NAME libxslt_var COMMAND libxslt_var)
+
+add_executable(libexslt_tgt libexslt.c)
+if(Iconv_FOUND)
+ target_link_libraries(libexslt_tgt Iconv::Iconv)
+endif()
+target_link_libraries(libexslt_tgt LibXml2::LibXml2 LibXslt::LibXslt LibXslt::LibExslt)
+add_test(NAME libexslt_tgt COMMAND libexslt_tgt)
+
+add_executable(libexslt_var libexslt.c)
+if(Iconv_FOUND)
+ target_include_directories(libexslt_var PRIVATE ${Iconv_INCLUDE_DIRS})
+ target_link_libraries(libexslt_var PRIVATE ${Iconv_LIBRARIES})
+endif()
+target_include_directories(libexslt_var PRIVATE ${LIBXML2_INCLUDE_DIRS} ${LIBXSLT_INCLUDE_DIR} ${LIBXSLT_EXSLT_INCLUDE_DIR})
+target_link_libraries(libexslt_var PRIVATE ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${LIBXSLT_EXSLT_LIBRARIES})
+add_test(NAME libexslt_var COMMAND libexslt_var)
+
+add_test(NAME xsltproc_tgt COMMAND LibXslt::xsltproc --version)
+
+add_test(NAME xsltproc_var COMMAND ${LIBXSLT_XSLTPROC_EXECUTABLE} --version)
diff --git a/Tests/FindLibXslt/Test/libexslt.c b/Tests/FindLibXslt/Test/libexslt.c
new file mode 100644
index 0000000..ea6eb3d
--- /dev/null
+++ b/Tests/FindLibXslt/Test/libexslt.c
@@ -0,0 +1,16 @@
+#include <libexslt/exslt.h>
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+
+int main()
+{
+ xsltInit();
+
+ xsltStylesheet* style = xsltNewStylesheet();
+ exsltRegisterAll();
+ xsltFreeStylesheet(style);
+
+ xsltCleanupGlobals();
+
+ return 0;
+}
diff --git a/Tests/FindLibXslt/Test/libxslt.c b/Tests/FindLibXslt/Test/libxslt.c
new file mode 100644
index 0000000..5b3d766
--- /dev/null
+++ b/Tests/FindLibXslt/Test/libxslt.c
@@ -0,0 +1,24 @@
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/xsltconfig.h>
+#include <stdio.h>
+#include <string.h>
+
+int main()
+{
+ xsltInit();
+
+ xsltStylesheet* style = xsltNewStylesheet();
+ xsltFreeStylesheet(style);
+
+ if (0 != strcmp(CMAKE_EXPECTED_LibXslt_VERSION, LIBXSLT_DOTTED_VERSION)) {
+ printf("CMAKE_EXPECTED_LibXslt_VERSION: '%s'\n",
+ CMAKE_EXPECTED_LibXslt_VERSION);
+ printf("LIBXSLT_DOTTED_VERSION: '%s'\n", LIBXSLT_DOTTED_VERSION);
+ return 1;
+ }
+
+ xsltCleanupGlobals();
+
+ return 0;
+}
diff --git a/Tests/FindLibinput/CMakeLists.txt b/Tests/FindLibinput/CMakeLists.txt
new file mode 100644
index 0000000..8538a55
--- /dev/null
+++ b/Tests/FindLibinput/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindLibinput.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindLibinput/Test"
+ "${CMake_BINARY_DIR}/Tests/FindLibinput/Test"
+ ${build_generator_args}
+ --build-project TestFindLibinput
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindLibinput/Test/CMakeLists.txt b/Tests/FindLibinput/Test/CMakeLists.txt
new file mode 100644
index 0000000..1cc68d4
--- /dev/null
+++ b/Tests/FindLibinput/Test/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindLibinput C)
+include(CTest)
+
+find_package(Libinput REQUIRED)
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt Libinput::Libinput)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${Libinput_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${Libinput_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindLibinput/Test/main.c b/Tests/FindLibinput/Test/main.c
new file mode 100644
index 0000000..3919962
--- /dev/null
+++ b/Tests/FindLibinput/Test/main.c
@@ -0,0 +1,13 @@
+#include <libinput.h>
+#include <stdio.h>
+
+int main()
+{
+ struct libinput_interface interface;
+ interface.open_restricted = 0;
+ interface.close_restricted = 0;
+ struct libinput* li;
+ li = libinput_udev_create_context(&interface, NULL, NULL);
+ printf("Found Libinput.\n");
+ return 0;
+}
diff --git a/Tests/FindMPI/CMakeLists.txt b/Tests/FindMPI/CMakeLists.txt
new file mode 100644
index 0000000..121d978
--- /dev/null
+++ b/Tests/FindMPI/CMakeLists.txt
@@ -0,0 +1,21 @@
+foreach(c C CXX Fortran)
+ if(CMake_TEST_FindMPI_${c})
+ set(CMake_TEST_FindMPI_FLAG_${c} 1)
+ else()
+ set(CMake_TEST_FindMPI_FLAG_${c} 0)
+ endif()
+endforeach()
+
+add_test(NAME FindMPI.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindMPI/Test"
+ "${CMake_BINARY_DIR}/Tests/FindMPI/Test"
+ ${build_generator_args}
+ --build-project TestFindMPI
+ --build-options ${build_options}
+ -DMPI_TEST_C=${CMake_TEST_FindMPI_FLAG_C}
+ -DMPI_TEST_CXX=${CMake_TEST_FindMPI_FLAG_CXX}
+ -DMPI_TEST_Fortran=${CMake_TEST_FindMPI_FLAG_Fortran}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindMPI/Test/CMakeLists.txt b/Tests/FindMPI/Test/CMakeLists.txt
new file mode 100644
index 0000000..efe8c62
--- /dev/null
+++ b/Tests/FindMPI/Test/CMakeLists.txt
@@ -0,0 +1,46 @@
+cmake_minimum_required(VERSION 3.8)
+project(TestFindMPI NONE)
+include(CTest)
+
+macro(source_code_mapper_helper LANG_NAME)
+ if("${LANG_NAME}" STREQUAL "C")
+ set(MPITEST_SOURCE_FILE "main.c")
+ elseif("${LANG_NAME}" STREQUAL "CXX")
+ configure_file("main.c" "main.cxx" COPYONLY)
+ set(MPITEST_SOURCE_FILE "main.cxx")
+ elseif("${LANG_NAME}" STREQUAL "Fortran")
+ set(MPITEST_SOURCE_FILE "main.f90")
+ endif()
+endmacro()
+
+foreach(c C CXX Fortran)
+ if("${MPI_TEST_${c}}")
+ message("Testing ${c}")
+ enable_language(${c})
+ endif()
+endforeach()
+
+set(MPI_CXX_SKIP_MPICXX TRUE)
+set(MPI_CXX_VALIDATE_SKIP_MPICXX TRUE)
+find_package(MPI REQUIRED)
+
+foreach(c C CXX Fortran)
+ if(NOT "${MPI_TEST_${c}}")
+ continue()
+ endif()
+ if(${c} STREQUAL CXX AND MPI_MPICXX_FOUND)
+ message(FATAL_ERROR "Could not suppress MPI-2 C++ bindings for this MPI.")
+ endif()
+ source_code_mapper_helper(${c})
+ add_executable(test_tgt_${c} ${MPITEST_SOURCE_FILE})
+ target_link_libraries(test_tgt_${c} MPI::MPI_${c})
+ add_test(NAME test_tgt_${c} COMMAND test_tgt_${c})
+
+ add_executable(test_var_${c} ${MPITEST_SOURCE_FILE})
+ target_include_directories(test_var_${c} PRIVATE "${MPI_${c}_INCLUDE_PATH}")
+ target_link_libraries(test_var_${c} PRIVATE "${MPI_${c}_LINK_FLAGS}" "${MPI_${c}_LIBRARIES}")
+ set(copied_MPI_${c}_OPTIONS "${MPI_${c}_COMPILE_FLAGS}")
+ separate_arguments(copied_MPI_${c}_OPTIONS)
+ target_compile_options(test_var_${c} PRIVATE "${copied_MPI_${c}_OPTIONS}")
+ add_test(NAME test_var_${c} COMMAND test_var_${c})
+endforeach()
diff --git a/Tests/FindMPI/Test/main.c b/Tests/FindMPI/Test/main.c
new file mode 100644
index 0000000..7b7f175
--- /dev/null
+++ b/Tests/FindMPI/Test/main.c
@@ -0,0 +1,7 @@
+#include <mpi.h>
+
+int main(int argc, char** argv)
+{
+ MPI_Init(&argc, &argv);
+ MPI_Finalize();
+}
diff --git a/Tests/FindMPI/Test/main.f90 b/Tests/FindMPI/Test/main.f90
new file mode 100644
index 0000000..6fb6fd3
--- /dev/null
+++ b/Tests/FindMPI/Test/main.f90
@@ -0,0 +1,7 @@
+program mpi_test
+ include 'mpif.h'
+ integer ierror
+
+ call MPI_INIT(ierror)
+ call MPI_FINALIZE(ierror)
+end program mpi_test
diff --git a/Tests/FindMatlab/basic_checks/CMakeLists.txt b/Tests/FindMatlab/basic_checks/CMakeLists.txt
new file mode 100644
index 0000000..c0c752a
--- /dev/null
+++ b/Tests/FindMatlab/basic_checks/CMakeLists.txt
@@ -0,0 +1,85 @@
+
+cmake_minimum_required (VERSION 2.8.12)
+enable_testing()
+project(basic_checks)
+
+set(MATLAB_FIND_DEBUG TRUE)
+
+# the success of the following command is dependent on the current configuration:
+# - on 32bits builds (cmake is building with 32 bits), it looks for 32 bits Matlab
+# - on 64bits builds (cmake is building with 64 bits), it looks for 64 bits Matlab
+
+if(IS_MCR)
+ set(RUN_UNIT_TESTS FALSE)
+else()
+ set(RUN_UNIT_TESTS TRUE)
+ set(components MAIN_PROGRAM)
+endif()
+
+if(NOT "${MCR_ROOT}" STREQUAL "")
+ set(Matlab_ROOT_DIR "${MCR_ROOT}")
+ if(NOT EXISTS "${MCR_ROOT}")
+ message(FATAL_ERROR "MCR does not exist ${MCR_ROOT}")
+ endif()
+endif()
+
+find_package(Matlab REQUIRED COMPONENTS ${components})
+
+
+matlab_add_mex(
+ # target name
+ NAME cmake_matlab_test_wrapper1
+ # output name
+ OUTPUT_NAME cmake_matlab_mex1
+ SRC ${CMAKE_CURRENT_SOURCE_DIR}/../matlab_wrapper1.cpp
+ DOCUMENTATION ${CMAKE_CURRENT_SOURCE_DIR}/../help_text1.m.txt
+ )
+
+if(RUN_UNIT_TESTS)
+ matlab_add_unit_test(
+ NAME ${PROJECT_NAME}_matlabtest-1
+ TIMEOUT 300
+ UNITTEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../cmake_matlab_unit_tests1.m
+ ADDITIONAL_PATH $<TARGET_FILE_DIR:cmake_matlab_test_wrapper1>
+ )
+
+ # timeout tests, TIMEOUT set to very short on purpose
+ matlab_add_unit_test(
+ NAME ${PROJECT_NAME}_matlabtest-2
+ TIMEOUT 15
+ UNITTEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../cmake_matlab_unit_tests_timeout.m
+ ADDITIONAL_PATH $<TARGET_FILE_DIR:cmake_matlab_test_wrapper1>
+ )
+ set_tests_properties(${PROJECT_NAME}_matlabtest-2 PROPERTIES WILL_FAIL TRUE)
+
+
+ # testing the test without the unittest framework of Matlab
+ matlab_add_unit_test(
+ NAME ${PROJECT_NAME}_matlabtest-3
+ TIMEOUT 300
+ NO_UNITTEST_FRAMEWORK
+ UNITTEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../cmake_matlab_unit_tests2.m
+ ADDITIONAL_PATH $<TARGET_FILE_DIR:cmake_matlab_test_wrapper1>
+ )
+
+ matlab_add_unit_test(
+ NAME ${PROJECT_NAME}_matlabtest-4
+ TIMEOUT 300
+ NO_UNITTEST_FRAMEWORK
+ UNITTEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../cmake_matlab_unit_tests3.m
+ ADDITIONAL_PATH $<TARGET_FILE_DIR:cmake_matlab_test_wrapper1>
+ )
+ set_tests_properties(${PROJECT_NAME}_matlabtest-4 PROPERTIES WILL_FAIL TRUE)
+endif()
+
+
+# checking correct flags passed
+# EXCLUDE_FROM_ALL appears after a multiargs (like SRC)
+matlab_add_mex(
+ # target name
+ NAME cmake_matlab_test_exclude_from_all
+ # output name
+ OUTPUT_NAME cmake_matlab_mex_dummy
+ SRC ${CMAKE_CURRENT_SOURCE_DIR}/../matlab_wrapper_failure.cpp
+ EXCLUDE_FROM_ALL
+ )
diff --git a/Tests/FindMatlab/cmake_matlab_unit_tests1.m b/Tests/FindMatlab/cmake_matlab_unit_tests1.m
new file mode 100644
index 0000000..2371c3a
--- /dev/null
+++ b/Tests/FindMatlab/cmake_matlab_unit_tests1.m
@@ -0,0 +1,33 @@
+
+classdef cmake_matlab_unit_tests1 < matlab.unittest.TestCase
+ % some simple unit test for CMake Matlab wrapper
+ properties
+ end
+
+ methods (Test)
+ function testDummyCall(testCase)
+ % very simple call test
+ cmake_matlab_mex1(rand(3,3));
+ end
+
+ function testDummyCall2(testCase)
+ % very simple call test 2
+ ret = cmake_matlab_mex1(rand(3,3));
+ testCase.verifyEqual(size(ret), size(rand(3,3)));
+
+ testCase.verifyEqual(size(cmake_matlab_mex1(rand(4,3))), [4,3] );
+ end
+
+ function testFailTest(testCase)
+ testCase.verifyError(@() cmake_matlab_mex1(10), 'cmake_matlab:configuration');
+ testCase.verifyError(@() cmake_matlab_mex1([10]), 'cmake_matlab:configuration');
+ end
+
+ function testHelpContent(testCase)
+ % testing the help feature
+ testCase.verifySubstring(evalc('help cmake_matlab_mex1'), 'Dummy matlab extension in cmake');
+ end
+
+
+ end
+end
diff --git a/Tests/FindMatlab/cmake_matlab_unit_tests2.m b/Tests/FindMatlab/cmake_matlab_unit_tests2.m
new file mode 100644
index 0000000..7a8a342
--- /dev/null
+++ b/Tests/FindMatlab/cmake_matlab_unit_tests2.m
@@ -0,0 +1,6 @@
+
+ret = cmake_matlab_mex1(rand(3,3));
+
+if(size(ret) ~= size(rand(3,3)))
+ error('Dimension mismatch!');
+end
diff --git a/Tests/FindMatlab/cmake_matlab_unit_tests3.m b/Tests/FindMatlab/cmake_matlab_unit_tests3.m
new file mode 100644
index 0000000..2639325
--- /dev/null
+++ b/Tests/FindMatlab/cmake_matlab_unit_tests3.m
@@ -0,0 +1,5 @@
+
+cmake_matlab_mex1(10);
+
+% should not reach this point
+exit(0);
diff --git a/Tests/FindMatlab/cmake_matlab_unit_tests4.m b/Tests/FindMatlab/cmake_matlab_unit_tests4.m
new file mode 100644
index 0000000..6a7b04d
--- /dev/null
+++ b/Tests/FindMatlab/cmake_matlab_unit_tests4.m
@@ -0,0 +1,28 @@
+
+classdef cmake_matlab_unit_tests4 < matlab.unittest.TestCase
+ % Testing R2017b and R2018a APIs
+ properties
+ end
+
+ methods (Test)
+ function testR2017b(testCase)
+ ret = cmake_matlab_mex2a(5+6i);
+ testCase.verifyEqual(ret, 8);
+ end
+
+ function testR2018a(testCase)
+ ret = cmake_matlab_mex2b(5+6i);
+ v = version;
+ n = find(v=='.');
+ v = str2double(v(1:n(2)-1));
+ disp(v)
+ if v>= 9.4 % R2018a
+ testCase.verifyEqual(ret, 16);
+ disp('TESTING version >= 9.4')
+ else
+ testCase.verifyEqual(ret, 8);
+ end
+ end
+
+ end
+end
diff --git a/Tests/FindMatlab/cmake_matlab_unit_tests5.m b/Tests/FindMatlab/cmake_matlab_unit_tests5.m
new file mode 100644
index 0000000..b1936e3
--- /dev/null
+++ b/Tests/FindMatlab/cmake_matlab_unit_tests5.m
@@ -0,0 +1,20 @@
+
+classdef cmake_matlab_unit_tests5 < matlab.unittest.TestCase
+ % C++ API test
+ properties
+ end
+
+ methods (Test)
+ function testDummyCall(testCase)
+ % very simple call test
+ disp('TESTING C++')
+ ret = cmake_matlab_mex3(162);
+ testCase.verifyEqual(ret, 162);
+ end
+
+ function testFailTest(testCase)
+ testCase.verifyError(@() cmake_matlab_mex3, 'MATLAB:mex:CppMexException');
+ end
+
+ end
+end
diff --git a/Tests/FindMatlab/cmake_matlab_unit_tests_timeout.m b/Tests/FindMatlab/cmake_matlab_unit_tests_timeout.m
new file mode 100644
index 0000000..11d5e9e
--- /dev/null
+++ b/Tests/FindMatlab/cmake_matlab_unit_tests_timeout.m
@@ -0,0 +1,16 @@
+
+classdef cmake_matlab_unit_tests_timeout < matlab.unittest.TestCase
+ % timeout tests
+
+ properties
+ end
+
+ methods (Test)
+ function testCallHangsShouldBeTimedOut(testCase)
+ cmake_matlab_mex1(rand(3,3));
+ disp('Will now wait.');
+ disp('Testing the cmake Matlab package timeout - do not kill');
+ pause(20); % supposed to be killed after 15s
+ end
+ end
+end
diff --git a/Tests/FindMatlab/components_checks/CMakeLists.txt b/Tests/FindMatlab/components_checks/CMakeLists.txt
new file mode 100644
index 0000000..f5d4880
--- /dev/null
+++ b/Tests/FindMatlab/components_checks/CMakeLists.txt
@@ -0,0 +1,31 @@
+
+cmake_minimum_required (VERSION 2.8.12)
+enable_testing()
+project(component_checks)
+
+set(MATLAB_FIND_DEBUG TRUE)
+
+if(NOT "${MCR_ROOT}" STREQUAL "")
+ set(Matlab_ROOT_DIR "${MCR_ROOT}")
+ if(NOT EXISTS "${MCR_ROOT}")
+ message(FATAL_ERROR "MCR does not exist ${MCR_ROOT}")
+ endif()
+endif()
+
+# the success of the following command is dependent on the current configuration:
+# - on 32bits builds (cmake is building with 32 bits), it looks for 32 bits Matlab
+# - on 64bits builds (cmake is building with 64 bits), it looks for 64 bits Matlab
+find_package(Matlab REQUIRED COMPONENTS ENG_LIBRARY MAT_LIBRARY
+ OPTIONAL_COMPONENTS MAIN_PROGRAM)
+
+message(STATUS "FindMatlab libraries: ${Matlab_LIBRARIES}")
+
+matlab_add_mex(
+ # target name
+ NAME cmake_matlab_test_wrapper1
+ # output name
+ OUTPUT_NAME cmake_matlab_mex1
+ SRC ${CMAKE_CURRENT_SOURCE_DIR}/../matlab_wrapper1.cpp
+ DOCUMENTATION ${CMAKE_CURRENT_SOURCE_DIR}/../help_text1.m.txt
+ LINK_TO ${Matlab_LIBRARIES}
+ )
diff --git a/Tests/FindMatlab/failure_reports/CMakeLists.txt b/Tests/FindMatlab/failure_reports/CMakeLists.txt
new file mode 100644
index 0000000..4b092cd
--- /dev/null
+++ b/Tests/FindMatlab/failure_reports/CMakeLists.txt
@@ -0,0 +1,55 @@
+
+cmake_minimum_required (VERSION 2.8.12)
+enable_testing()
+project(failure_reports)
+
+# gather tests about proper failure reports
+
+set(MATLAB_FIND_DEBUG TRUE)
+
+if(IS_MCR)
+ set(RUN_UNIT_TESTS FALSE)
+else()
+ set(RUN_UNIT_TESTS TRUE)
+ set(components MAIN_PROGRAM)
+endif()
+
+if(NOT "${MCR_ROOT}" STREQUAL "")
+ set(Matlab_ROOT_DIR "${MCR_ROOT}")
+ if(NOT EXISTS "${MCR_ROOT}")
+ message(FATAL_ERROR "MCR does not exist ${MCR_ROOT}")
+ endif()
+endif()
+
+find_package(Matlab REQUIRED COMPONENTS ${components})
+
+# main extensions for testing, same as other tests
+matlab_add_mex(
+ # target name
+ NAME cmake_matlab_test_wrapper1
+ # output name
+ OUTPUT_NAME cmake_matlab_mex1
+ SRC ${CMAKE_CURRENT_SOURCE_DIR}/../matlab_wrapper1.cpp
+ DOCUMENTATION ${CMAKE_CURRENT_SOURCE_DIR}/../help_text1.m.txt
+ )
+
+if(RUN_UNIT_TESTS)
+ # the unit test file does not exist: the failure should be properly reported
+ matlab_add_unit_test(
+ NAME ${PROJECT_NAME}_matlabtest-1
+ TIMEOUT 300
+ UNITTEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../nonexistantfile.m
+ ADDITIONAL_PATH $<TARGET_FILE_DIR:cmake_matlab_test_wrapper1>
+ )
+ set_tests_properties(${PROJECT_NAME}_matlabtest-1 PROPERTIES WILL_FAIL TRUE)
+
+ # without the unit test framework
+ matlab_add_unit_test(
+ NAME ${PROJECT_NAME}_matlabtest-2
+ TIMEOUT 300
+ NO_UNITTEST_FRAMEWORK
+ UNITTEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../nonexistantfile2.m
+ ADDITIONAL_PATH $<TARGET_FILE_DIR:cmake_matlab_test_wrapper1>
+ )
+ set_tests_properties(${PROJECT_NAME}_matlabtest-2 PROPERTIES WILL_FAIL TRUE)
+endif()
diff --git a/Tests/FindMatlab/help_text1.m.txt b/Tests/FindMatlab/help_text1.m.txt
new file mode 100644
index 0000000..a924355
--- /dev/null
+++ b/Tests/FindMatlab/help_text1.m.txt
@@ -0,0 +1,2 @@
+% Dummy matlab extension in cmake
+function ret = cmake_matlab_mex1(X)
diff --git a/Tests/FindMatlab/matlab_wrapper1.cpp b/Tests/FindMatlab/matlab_wrapper1.cpp
new file mode 100644
index 0000000..ebf1b87
--- /dev/null
+++ b/Tests/FindMatlab/matlab_wrapper1.cpp
@@ -0,0 +1,27 @@
+
+// simple workaround to some compiler specific problems
+// see
+// http://stackoverflow.com/questions/22367516/mex-compile-error-unknown-type-name-char16-t/23281916#23281916
+#include <algorithm>
+
+#include "mex.h"
+
+// this test should return a matrix of 10 x 10 and should check some of the
+// arguments
+
+void mexFunction(const int nlhs, mxArray* plhs[], const int nrhs,
+ const mxArray* prhs[])
+{
+ if (nrhs != 1) {
+ mexErrMsgTxt("Incorrect arguments");
+ }
+
+ size_t dim1 = mxGetM(prhs[0]);
+ size_t dim2 = mxGetN(prhs[0]);
+
+ if (dim1 == 1 || dim2 == 1) {
+ mexErrMsgIdAndTxt("cmake_matlab:configuration", "Incorrect arguments");
+ }
+
+ plhs[0] = mxCreateNumericMatrix(dim1, dim2, mxGetClassID(prhs[0]), mxREAL);
+}
diff --git a/Tests/FindMatlab/matlab_wrapper2.cpp b/Tests/FindMatlab/matlab_wrapper2.cpp
new file mode 100644
index 0000000..e768fbf
--- /dev/null
+++ b/Tests/FindMatlab/matlab_wrapper2.cpp
@@ -0,0 +1,22 @@
+
+// simple workaround to some compiler specific problems
+// see
+// http://stackoverflow.com/questions/22367516/mex-compile-error-unknown-type-name-char16-t/23281916#23281916
+#include <algorithm>
+
+#include "mex.h"
+
+// This test uses the new complex-interleaved C API (R2018a and newer)
+
+// The input should be a complex array (scalar is OK). It returns the number of
+// bytes in a matrix element. For the old (R2017b) API, this is 8. For the new
+// (R2018a) API, this is 16.
+
+void mexFunction(const int nlhs, mxArray* plhs[], const int nrhs,
+ const mxArray* prhs[])
+{
+ if (nrhs != 1 || !mxIsComplex(prhs[0])) {
+ mexErrMsgTxt("Incorrect arguments");
+ }
+ plhs[0] = mxCreateDoubleScalar(mxGetElementSize(prhs[0]));
+}
diff --git a/Tests/FindMatlab/matlab_wrapper3.cpp b/Tests/FindMatlab/matlab_wrapper3.cpp
new file mode 100644
index 0000000..6670815
--- /dev/null
+++ b/Tests/FindMatlab/matlab_wrapper3.cpp
@@ -0,0 +1,29 @@
+#include "mex.hpp"
+#include "mexAdapter.hpp"
+
+// This test uses the new C++ API (R2018a and newer)
+
+// The input should be a scalar double array. The output is a copy of that
+// array.
+
+using namespace matlab::data;
+using matlab::mex::ArgumentList;
+
+class MexFunction : public matlab::mex::Function
+{
+public:
+ void operator()(ArgumentList outputs, ArgumentList inputs)
+ {
+ std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
+ ArrayFactory factory;
+ if (inputs[0].getType() != ArrayType::DOUBLE ||
+ inputs[0].getType() == ArrayType::COMPLEX_DOUBLE ||
+ inputs[0].getNumberOfElements() != 1) {
+ matlabPtr->feval(
+ u"error", 0,
+ std::vector<Array>({ factory.createScalar("Incorrect arguments") }));
+ }
+ double a = inputs[0][0];
+ outputs[0] = factory.createScalar(a);
+ }
+};
diff --git a/Tests/FindMatlab/matlab_wrapper_failure.cpp b/Tests/FindMatlab/matlab_wrapper_failure.cpp
new file mode 100644
index 0000000..3fe437b
--- /dev/null
+++ b/Tests/FindMatlab/matlab_wrapper_failure.cpp
@@ -0,0 +1,13 @@
+// This should not link, as the mex function is missing.
+// This is mostly for checking we are passing the right arguments to the
+// add_library
+
+#include <algorithm>
+
+#include "mex.h"
+
+void mexFunctionXX(const int nlhs, mxArray* plhs[], const int nrhs,
+ const mxArray* prhs[])
+{
+ mexErrMsgTxt("Should not be running");
+}
diff --git a/Tests/FindMatlab/r2018a_check/CMakeLists.txt b/Tests/FindMatlab/r2018a_check/CMakeLists.txt
new file mode 100644
index 0000000..c732be1
--- /dev/null
+++ b/Tests/FindMatlab/r2018a_check/CMakeLists.txt
@@ -0,0 +1,84 @@
+
+cmake_minimum_required (VERSION 2.8.12)
+enable_testing()
+project(r2018a_checks)
+
+set(MATLAB_FIND_DEBUG TRUE)
+
+# this test doesn't do much if MATLAB version < R2018a
+
+if(IS_MCR)
+ set(RUN_UNIT_TESTS FALSE)
+else()
+ set(RUN_UNIT_TESTS TRUE)
+ set(components MAIN_PROGRAM)
+endif()
+
+if(NOT "${MCR_ROOT}" STREQUAL "")
+ set(Matlab_ROOT_DIR "${MCR_ROOT}")
+ if(NOT EXISTS "${MCR_ROOT}")
+ message(FATAL_ERROR "MCR does not exist ${MCR_ROOT}")
+ endif()
+endif()
+
+find_package(Matlab REQUIRED COMPONENTS ${components})
+
+set(IS_R2018a 1)
+if(${Matlab_VERSION_STRING} VERSION_LESS "9.4")
+ # This is an older version of MATLAB, tests will fail
+ set(IS_R2018a 0)
+endif()
+
+matlab_add_mex(
+ # target name
+ NAME cmake_matlab_test_wrapper2a
+ # output name
+ OUTPUT_NAME cmake_matlab_mex2a
+ SRC ${CMAKE_CURRENT_SOURCE_DIR}/../matlab_wrapper2.cpp
+ R2017b
+ )
+
+matlab_add_mex(
+ # target name
+ NAME cmake_matlab_test_wrapper2b
+ # output name
+ OUTPUT_NAME cmake_matlab_mex2b
+ SRC ${CMAKE_CURRENT_SOURCE_DIR}/../matlab_wrapper2.cpp
+ R2018a
+ )
+
+if(IS_R2018a)
+ matlab_add_mex(
+ # target name
+ NAME cmake_matlab_test_wrapper3
+ # output name
+ OUTPUT_NAME cmake_matlab_mex3
+ SRC ${CMAKE_CURRENT_SOURCE_DIR}/../matlab_wrapper3.cpp
+ )
+ set_target_properties(
+ cmake_matlab_test_wrapper3
+ PROPERTIES
+ CXX_STANDARD 11
+ CXX_STANDARD_REQUIRED ON
+ )
+endif()
+
+if(RUN_UNIT_TESTS)
+ # Check that the R2017b and R2018a APIs work.
+ matlab_add_unit_test(
+ NAME ${PROJECT_NAME}_matlabtest-1
+ TIMEOUT 300
+ UNITTEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../cmake_matlab_unit_tests4.m
+ ADDITIONAL_PATH $<TARGET_FILE_DIR:cmake_matlab_test_wrapper2a>
+ )
+
+ # Check that the C++ API works (test run only on R2018a and newer)
+ if(IS_R2018a)
+ matlab_add_unit_test(
+ NAME ${PROJECT_NAME}_matlabtest-3
+ TIMEOUT 300
+ UNITTEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../cmake_matlab_unit_tests5.m
+ ADDITIONAL_PATH $<TARGET_FILE_DIR:cmake_matlab_test_wrapper3>
+ )
+ endif()
+endif()
diff --git a/Tests/FindMatlab/versions_checks/CMakeLists.txt b/Tests/FindMatlab/versions_checks/CMakeLists.txt
new file mode 100644
index 0000000..d015730
--- /dev/null
+++ b/Tests/FindMatlab/versions_checks/CMakeLists.txt
@@ -0,0 +1,59 @@
+
+cmake_minimum_required (VERSION 2.8.12)
+enable_testing()
+project(versions_checks)
+
+set(MATLAB_FIND_DEBUG TRUE)
+set(MATLAB_ADDITIONAL_VERSIONS
+ "dummy=14.9")
+
+if(NOT "${MCR_ROOT}" STREQUAL "")
+ set(Matlab_ROOT_DIR "${MCR_ROOT}")
+ if(NOT EXISTS "${MCR_ROOT}")
+ message(FATAL_ERROR "MCR does not exist ${MCR_ROOT}")
+ endif()
+endif()
+
+# the success of the following command is dependent on the current configuration
+# in this case, we are only interested in the version macros
+find_package(Matlab)
+
+
+
+if(NOT COMMAND matlab_get_version_from_release_name)
+ message(FATAL_ERROR "The macro matlab_get_version_from_release_name should be defined")
+endif()
+
+if(NOT COMMAND matlab_get_release_name_from_version)
+ message(FATAL_ERROR "The macro matlab_get_release_name_from_version should be defined")
+endif()
+
+
+# matlab_get_release_name_from_version
+matlab_get_release_name_from_version("7.13" release_name)
+if(NOT release_name STREQUAL "R2011b")
+ message(FATAL_ERROR "version 7.13 does not give release R2011b : '${release_name}' != R2011b")
+endif()
+
+matlab_get_release_name_from_version("14.9" release_name)
+if(NOT release_name STREQUAL "dummy")
+ message(FATAL_ERROR "version 14.9 does not give release dummy : '${release_name}' != dummy")
+endif()
+
+matlab_get_release_name_from_version("14.10" release_name)
+if(NOT release_name STREQUAL "")
+ message(FATAL_ERROR "version 14.10 does not give empty release: '${release_name}' != ''")
+endif()
+
+
+# matlab_get_version_from_release_name
+matlab_get_version_from_release_name("R2011a" version)
+if(NOT version STREQUAL "7.12")
+ message(FATAL_ERROR "Release R2011a does not give version 7.12 : '${version}' != 7.12")
+endif()
+
+matlab_get_version_from_release_name("dummy" version)
+#message(FATAL_ERROR "versionversion = ${version}")
+if(NOT version STREQUAL "14.9")
+ message(FATAL_ERROR "Release dummy does not give version 14.9 : '${version}' != 14.9")
+endif()
diff --git a/Tests/FindODBC/CMakeLists.txt b/Tests/FindODBC/CMakeLists.txt
new file mode 100644
index 0000000..6a81090
--- /dev/null
+++ b/Tests/FindODBC/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindODBC.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindODBC/Test"
+ "${CMake_BINARY_DIR}/Tests/FindODBC/Test"
+ ${build_generator_args}
+ --build-project TestFindODBC
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindODBC/Test/CMakeLists.txt b/Tests/FindODBC/Test/CMakeLists.txt
new file mode 100644
index 0000000..a20c0f7
--- /dev/null
+++ b/Tests/FindODBC/Test/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindODBC C)
+include(CTest)
+
+find_package(ODBC)
+
+add_executable(test_odbc_tgt main.c)
+target_link_libraries(test_odbc_tgt ODBC::ODBC)
+add_test(NAME test_odbc_tgt COMMAND test_odbc_tgt)
+
+add_executable(test_odbc_var main.c)
+target_include_directories(test_odbc_var PRIVATE ${ODBC_INCLUDE_DIRS})
+target_link_libraries(test_odbc_var PRIVATE ${ODBC_LIBRARIES})
+add_test(NAME test_odbc_var COMMAND test_odbc_var)
diff --git a/Tests/FindODBC/Test/main.c b/Tests/FindODBC/Test/main.c
new file mode 100644
index 0000000..34f279c
--- /dev/null
+++ b/Tests/FindODBC/Test/main.c
@@ -0,0 +1,12 @@
+#ifdef WIN32
+# include <windows.h>
+#endif
+#include <sql.h>
+
+int main()
+{
+ SQLHENV env;
+ SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
+ SQLFreeHandle(SQL_HANDLE_ENV, env);
+ return 0;
+}
diff --git a/Tests/FindOpenACC/CMakeLists.txt b/Tests/FindOpenACC/CMakeLists.txt
new file mode 100644
index 0000000..ef7de65
--- /dev/null
+++ b/Tests/FindOpenACC/CMakeLists.txt
@@ -0,0 +1,20 @@
+
+set(langs C CXX)
+if(NOT CMAKE_GENERATOR STREQUAL "Ninja")
+ list(APPEND langs Fortran)
+endif()
+
+foreach(lang IN LISTS langs)
+ if(CMAKE_${lang}_COMPILER)
+ add_test(NAME FindOpenACC.Test${lang} COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindOpenACC/${lang}Test"
+ "${CMake_BINARY_DIR}/Tests/FindOpenACC/${lang}Test"
+ ${build_generator_args}
+ --build-project TestFindOpenACC
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ endif()
+endforeach()
diff --git a/Tests/FindOpenACC/CTest/CMakeLists.txt b/Tests/FindOpenACC/CTest/CMakeLists.txt
new file mode 100644
index 0000000..c8d0968
--- /dev/null
+++ b/Tests/FindOpenACC/CTest/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.14)
+project(VerifyFindOpenAcc C)
+
+set(CMAKE_C_STANDARD 11)
+
+find_package(OpenACC REQUIRED)
+
+add_executable(UsesOpenACC main.c)
+target_link_libraries(UsesOpenACC PRIVATE OpenACC::OpenACC_C)
+
+add_executable(UsesOpenACCVars main.c)
+target_link_options(UsesOpenACCVars PRIVATE ${OpenACC_C_OPTIONS})
+target_compile_options(UsesOpenACCVars PRIVATE ${OpenACC_C_OPTIONS})
diff --git a/Tests/FindOpenACC/CTest/main.c b/Tests/FindOpenACC/CTest/main.c
new file mode 100644
index 0000000..53b6cae
--- /dev/null
+++ b/Tests/FindOpenACC/CTest/main.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void vecaddgpu(float* r, float* a, float* b, int n)
+{
+#pragma acc kernels loop present(r, a, b)
+ for (int i = 0; i < n; ++i)
+ r[i] = a[i] + b[i];
+}
+
+int main()
+{
+ int n = 100000; /* vector length */
+ float* a; /* input vector 1 */
+ float* b; /* input vector 2 */
+ float* r; /* output vector */
+ float* e; /* expected output values */
+ int i, errs;
+
+ a = (float*)malloc(n * sizeof(float));
+ b = (float*)malloc(n * sizeof(float));
+ r = (float*)malloc(n * sizeof(float));
+ e = (float*)malloc(n * sizeof(float));
+ for (i = 0; i < n; ++i) {
+ a[i] = (float)(i + 1);
+ b[i] = (float)(1000 * i);
+ }
+/* compute on the GPU */
+#pragma acc data copyin(a [0:n], b [0:n]) copyout(r [0:n])
+ {
+ vecaddgpu(r, a, b, n);
+ }
+ /* compute on the host to compare */
+ for (i = 0; i < n; ++i)
+ e[i] = a[i] + b[i];
+ /* compare results */
+ errs = 0;
+ for (i = 0; i < n; ++i) {
+ if (r[i] != e[i]) {
+ ++errs;
+ }
+ }
+ return errs;
+}
diff --git a/Tests/FindOpenACC/CXXTest/CMakeLists.txt b/Tests/FindOpenACC/CXXTest/CMakeLists.txt
new file mode 100644
index 0000000..a6caf7b
--- /dev/null
+++ b/Tests/FindOpenACC/CXXTest/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.14)
+project(VerifyFindOpenAcc CXX)
+
+set(CMAKE_CXX_STANDARD 11)
+
+find_package(OpenACC REQUIRED)
+
+add_executable(UsesOpenACC main.cxx)
+target_link_libraries(UsesOpenACC PRIVATE OpenACC::OpenACC_CXX)
+
+add_executable(UsesOpenACCVars main.cxx)
+target_link_options(UsesOpenACCVars PRIVATE ${OpenACC_CXX_OPTIONS})
+target_compile_options(UsesOpenACCVars PRIVATE ${OpenACC_CXX_OPTIONS})
diff --git a/Tests/FindOpenACC/CXXTest/main.cxx b/Tests/FindOpenACC/CXXTest/main.cxx
new file mode 100644
index 0000000..7369045
--- /dev/null
+++ b/Tests/FindOpenACC/CXXTest/main.cxx
@@ -0,0 +1,43 @@
+
+#include <vector>
+
+void vecaddgpu(float* r, float* a, float* b, std::size_t n)
+{
+#pragma acc kernels loop present(r, a, b)
+ for (std::size_t i = 0; i < n; ++i)
+ r[i] = a[i] + b[i];
+}
+
+int main(int, char* [])
+{
+ const std::size_t n = 100000; /* vector length */
+ std::vector<float> a(n); /* input vector 1 */
+ std::vector<float> b(n); /* input vector 2 */
+ std::vector<float> r(n); /* output vector */
+ std::vector<float> e(n); /* expected output values */
+
+ for (std::size_t i = 0; i < n; ++i) {
+ a[i] = static_cast<float>(i + 1);
+ b[i] = static_cast<float>(1000 * i);
+ }
+
+ /* compute on the GPU */
+ auto a_ptr = a.data();
+ auto b_ptr = b.data();
+ auto r_ptr = r.data();
+#pragma acc data copyin(a_ptr [0:n], b_ptr [0:n]) copyout(r_ptr [0:n])
+ {
+ vecaddgpu(r_ptr, a_ptr, b_ptr, n);
+ }
+ /* compute on the host to compare */
+ for (std::size_t i = 0; i < n; ++i)
+ e[i] = a[i] + b[i];
+ /* compare results */
+ int errs = 0;
+ for (std::size_t i = 0; i < n; ++i) {
+ if (r[i] != e[i]) {
+ ++errs;
+ }
+ }
+ return errs;
+}
diff --git a/Tests/FindOpenACC/FortranTest/CMakeLists.txt b/Tests/FindOpenACC/FortranTest/CMakeLists.txt
new file mode 100644
index 0000000..12e3503
--- /dev/null
+++ b/Tests/FindOpenACC/FortranTest/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.14)
+project(VerifyFindOpenAcc Fortran)
+
+find_package(OpenACC REQUIRED)
+
+add_executable(UsesOpenACC main.f90)
+target_link_libraries(UsesOpenACC PRIVATE OpenACC::OpenACC_Fortran)
+
+add_executable(UsesOpenACCVars main.f90)
+target_link_options(UsesOpenACCVars PRIVATE ${OpenACC_Fortran_OPTIONS})
+target_compile_options(UsesOpenACCVars PRIVATE ${OpenACC_Fortran_OPTIONS})
diff --git a/Tests/FindOpenACC/FortranTest/main.f90 b/Tests/FindOpenACC/FortranTest/main.f90
new file mode 100644
index 0000000..2ff1ba0
--- /dev/null
+++ b/Tests/FindOpenACC/FortranTest/main.f90
@@ -0,0 +1,9 @@
+program t
+integer(4) a(10000)
+a = [ (1+i,i=1,10000) ]
+!$acc kernels
+do i = 1, 10000
+ if (a(i)/3000*3000.eq.a(i)) print *," located ",i,a(i),i.gt.5000,a(i)/5.0
+end do
+!$acc end kernels
+end
diff --git a/Tests/FindOpenCL/CMakeLists.txt b/Tests/FindOpenCL/CMakeLists.txt
new file mode 100644
index 0000000..88d2eae
--- /dev/null
+++ b/Tests/FindOpenCL/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindOpenCL.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindOpenCL/Test"
+ "${CMake_BINARY_DIR}/Tests/FindOpenCL/Test"
+ ${build_generator_args}
+ --build-project TestFindOpenCL
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindOpenCL/Test/CMakeLists.txt b/Tests/FindOpenCL/Test/CMakeLists.txt
new file mode 100644
index 0000000..f8a6587
--- /dev/null
+++ b/Tests/FindOpenCL/Test/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.4)
+project(TestFindOpenCL C)
+include(CTest)
+
+find_package(OpenCL REQUIRED)
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt OpenCL::OpenCL)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${OpenCL_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${OpenCL_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindOpenCL/Test/main.c b/Tests/FindOpenCL/Test/main.c
new file mode 100644
index 0000000..2fe949b
--- /dev/null
+++ b/Tests/FindOpenCL/Test/main.c
@@ -0,0 +1,17 @@
+#ifdef __APPLE__
+# include <OpenCL/opencl.h>
+#else
+# include <CL/cl.h>
+#endif
+
+int main()
+{
+ cl_uint platformIdCount;
+
+ // We can't assert on the result because this may return an error if no ICD
+ // is
+ // found
+ clGetPlatformIDs(0, NULL, &platformIdCount);
+
+ return 0;
+}
diff --git a/Tests/FindOpenGL/CMakeLists.txt b/Tests/FindOpenGL/CMakeLists.txt
new file mode 100644
index 0000000..97c9e60
--- /dev/null
+++ b/Tests/FindOpenGL/CMakeLists.txt
@@ -0,0 +1,17 @@
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMake_TEST_FindOpenGL_VND)
+ set(_vnd_testing TRUE)
+else()
+ set(_vnd_testing FALSE)
+endif()
+
+add_test(NAME FindOpenGL.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindOpenGL/Test"
+ "${CMake_BINARY_DIR}/Tests/FindOpenGL/Test"
+ ${build_generator_args}
+ --build-project TestFindOpenGL
+ --build-options ${build_options}
+ -DOpenGL_TEST_VND=${_vnd_testing}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindOpenGL/Test/CMakeLists.txt b/Tests/FindOpenGL/Test/CMakeLists.txt
new file mode 100644
index 0000000..9004a98
--- /dev/null
+++ b/Tests/FindOpenGL/Test/CMakeLists.txt
@@ -0,0 +1,71 @@
+cmake_minimum_required(VERSION 3.10)
+cmake_policy(SET CMP0072 NEW)
+project(TestFindOpenGL C)
+include(CTest)
+
+find_package(OpenGL REQUIRED)
+
+# import target for GLU
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt OpenGL::GLU)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+# OPENGL_LIBRARIES should be whatever libraries are needed to link.
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${OPENGL_INGLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${OPENGL_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
+
+# VND support adds an ::OpenGL import target. This can be used for OpenGL-only
+# code (code that does not manipulate contexts, like our 'main.c'). Without
+# VND, ::GL can be used for both context and non-context OpenGL code.
+if(OpenGL_TEST_VND)
+ add_executable(test_comp_none main.c)
+ target_link_libraries(test_comp_none PRIVATE OpenGL::OpenGL)
+ add_test(NAME test_comp_none COMMAND test_comp_none)
+else()
+ add_executable(test_comp_none main.c)
+ target_link_libraries(test_comp_none PRIVATE OpenGL::GL)
+ add_test(NAME test_comp_none COMMAND test_comp_none)
+endif()
+
+# GLX
+if(OpenGL_TEST_VND)
+ find_package(OpenGL REQUIRED COMPONENTS OpenGL GLX)
+ add_executable(test_comp_glx main.c)
+ target_link_libraries(test_comp_glx PRIVATE OpenGL::OpenGL OpenGL::GLX)
+ add_test(NAME test_comp_glx COMMAND test_comp_glx)
+else()
+ # non-VND systems won't have it, but an optional search for GLX should still
+ # be okay.
+ find_package(OpenGL COMPONENTS GLX)
+ add_executable(test_comp_glx_novnd main.c)
+ target_link_libraries(test_comp_glx_novnd PRIVATE OpenGL::GL)
+ add_test(NAME test_comp_glx_novnd COMMAND test_comp_glx_novnd)
+endif()
+
+# EGL is only available on Linux+GLVND at present.
+if(OpenGL_TEST_VND)
+ find_package(OpenGL COMPONENTS OpenGL EGL)
+ if(OpenGL_EGL_FOUND)
+ add_executable(test_comp_egl main.c)
+ target_link_libraries(test_comp_egl PRIVATE OpenGL::OpenGL OpenGL::EGL)
+ add_test(NAME test_comp_egl COMMAND test_comp_egl)
+ # EGL-only code should not link to GLX.
+ execute_process(COMMAND ldd test_comp_egl
+ OUTPUT_VARIABLE LDD_OUT
+ ERROR_VARIABLE LDD_ERR)
+ if("${LDD_OUT}" MATCHES "GLX")
+ message(FATAL_ERROR "EGL-only code links to GLX!")
+ endif()
+ endif()
+
+ # all three COMPONENTS together.
+ find_package(OpenGL COMPONENTS OpenGL EGL GLX)
+ if(OpenGL_EGL_FOUND AND OpenGL_GLX_FOUND)
+ add_executable(test_comp_both main.c)
+ target_link_libraries(test_comp_both PRIVATE OpenGL::OpenGL OpenGL::EGL
+ OpenGL::GLX)
+ add_test(NAME test_comp_both COMMAND test_comp_both)
+ endif()
+endif()
diff --git a/Tests/FindOpenGL/Test/main.c b/Tests/FindOpenGL/Test/main.c
new file mode 100644
index 0000000..e1f25c6
--- /dev/null
+++ b/Tests/FindOpenGL/Test/main.c
@@ -0,0 +1,17 @@
+#ifdef _WIN32
+# include <windows.h>
+#endif
+#ifdef __APPLE__
+# include <OpenGL/gl.h>
+#else
+# include <GL/gl.h>
+#endif
+
+#include <stdio.h>
+
+int main()
+{
+ /* Reference a GL symbol without requiring a context at runtime. */
+ printf("&glGetString = %p\n", &glGetString);
+ return 0;
+}
diff --git a/Tests/FindOpenMP/CMakeLists.txt b/Tests/FindOpenMP/CMakeLists.txt
new file mode 100644
index 0000000..e64885d
--- /dev/null
+++ b/Tests/FindOpenMP/CMakeLists.txt
@@ -0,0 +1,21 @@
+foreach(c C CXX Fortran)
+ if(CMake_TEST_FindOpenMP_${c})
+ set(CMake_TEST_FindOpenMP_FLAG_${c} 1)
+ else()
+ set(CMake_TEST_FindOpenMP_FLAG_${c} 0)
+ endif()
+endforeach()
+
+add_test(NAME FindOpenMP.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindOpenMP/Test"
+ "${CMake_BINARY_DIR}/Tests/FindOpenMP/Test"
+ ${build_generator_args}
+ --build-project TestFindOpenMP
+ --build-options ${build_options}
+ -DOpenMP_TEST_C=${CMake_TEST_FindOpenMP_FLAG_C}
+ -DOpenMP_TEST_CXX=${CMake_TEST_FindOpenMP_FLAG_CXX}
+ -DOpenMP_TEST_Fortran=${CMake_TEST_FindOpenMP_FLAG_Fortran}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindOpenMP/Test/CMakeLists.txt b/Tests/FindOpenMP/Test/CMakeLists.txt
new file mode 100644
index 0000000..ebdb6b8
--- /dev/null
+++ b/Tests/FindOpenMP/Test/CMakeLists.txt
@@ -0,0 +1,70 @@
+cmake_minimum_required(VERSION 3.8)
+project(TestFindOpenMP NONE)
+include(CTest)
+
+macro(source_code_mapper_helper LANG_NAME SRC_FILE_NAME)
+ if("${LANG_NAME}" STREQUAL "C")
+ set(OpenMPTEST_SOURCE_FILE "${SRC_FILE_NAME}.c")
+ elseif("${LANG_NAME}" STREQUAL "CXX")
+ configure_file("${SRC_FILE_NAME}.c" "${SRC_FILE_NAME}.cxx" COPYONLY)
+ set(OpenMPTEST_SOURCE_FILE "${SRC_FILE_NAME}.cxx")
+ elseif("${LANG_NAME}" STREQUAL "Fortran")
+ set(OpenMPTEST_SOURCE_FILE "${CMAKE_CURRENT_BINARY_DIR}/${SRC_FILE_NAME}.f90")
+ if(OpenMP_Fortran_HAVE_OMPLIB_MODULE)
+ set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n implicit none")
+ else()
+ set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n include 'omp_lib.h'")
+ endif()
+ configure_file("${SRC_FILE_NAME}.f90.in" "${OpenMPTEST_SOURCE_FILE}" @ONLY)
+ endif()
+endmacro()
+
+foreach(c C CXX Fortran)
+ if("${OpenMP_TEST_${c}}")
+ message("Testing ${c}")
+ enable_language(${c})
+ endif()
+endforeach()
+
+find_package(OpenMP REQUIRED)
+
+foreach(c C CXX Fortran)
+ if(NOT "${OpenMP_TEST_${c}}")
+ continue()
+ endif()
+ source_code_mapper_helper(${c} main)
+ add_executable(test_tgt_${c} ${OpenMPTEST_SOURCE_FILE})
+ target_link_libraries(test_tgt_${c} PRIVATE OpenMP::OpenMP_${c})
+ set_property(TARGET test_tgt_${c} PROPERTY LINKER_LANGUAGE ${c})
+ add_test(NAME test_tgt_${c} COMMAND test_tgt_${c})
+
+ add_executable(test_var_${c} ${OpenMPTEST_SOURCE_FILE})
+ separate_arguments(_OpenMP_${c}_OPTIONS NATIVE_COMMAND "${OpenMP_${c}_FLAGS}")
+ target_compile_options(test_var_${c} PRIVATE "${_OpenMP_${c}_OPTIONS}")
+ target_link_libraries(test_var_${c} PRIVATE "${OpenMP_${c}_FLAGS}")
+ target_include_directories(test_var_${c} PRIVATE ${OpenMP_${c}_INCLUDE_DIRS})
+ set_property(TARGET test_var_${c} PROPERTY LINKER_LANGUAGE ${c})
+ add_test(NAME test_var_${c} COMMAND test_var_${c})
+
+ source_code_mapper_helper(${c} scalprod)
+ add_library(scalprod_${c} STATIC ${OpenMPTEST_SOURCE_FILE})
+ target_link_libraries(scalprod_${c} PRIVATE OpenMP::OpenMP_${c})
+ set_property(TARGET scalprod_${c} PROPERTY LINKER_LANGUAGE ${c})
+endforeach()
+
+foreach(c C CXX Fortran)
+ if(NOT "${OpenMP_TEST_${c}}")
+ continue()
+ endif()
+ foreach(d C CXX Fortran)
+ if(NOT "${OpenMP_TEST_${d}}")
+ continue()
+ endif()
+ source_code_mapper_helper(${c} scaltest)
+ add_executable(scaltest_${c}_${d} ${OpenMPTEST_SOURCE_FILE})
+ target_link_libraries(scaltest_${c}_${d} PRIVATE scalprod_${d})
+ set_property(TARGET scaltest_${c}_${d} PROPERTY LINKER_LANGUAGE ${c})
+ add_test(NAME test_omp_${c}_${d} COMMAND scaltest_${c}_${d})
+ set_property(TEST test_omp_${c}_${d} PROPERTY PASS_REGULAR_EXPRESSION "^[ \t]*70\\.?0*")
+ endforeach()
+endforeach()
diff --git a/Tests/FindOpenMP/Test/main.c b/Tests/FindOpenMP/Test/main.c
new file mode 100644
index 0000000..4f0e874
--- /dev/null
+++ b/Tests/FindOpenMP/Test/main.c
@@ -0,0 +1,7 @@
+#include <omp.h>
+int main()
+{
+#ifndef _OPENMP
+ breaks_on_purpose
+#endif
+}
diff --git a/Tests/FindOpenMP/Test/main.f90.in b/Tests/FindOpenMP/Test/main.f90.in
new file mode 100644
index 0000000..9da22a1
--- /dev/null
+++ b/Tests/FindOpenMP/Test/main.f90.in
@@ -0,0 +1,5 @@
+ program test
+ @OpenMP_Fortran_INCLUDE_LINE@
+ !$ integer :: n
+ n = omp_get_num_threads()
+ end program test
diff --git a/Tests/FindOpenMP/Test/scalprod.c b/Tests/FindOpenMP/Test/scalprod.c
new file mode 100644
index 0000000..24c4587
--- /dev/null
+++ b/Tests/FindOpenMP/Test/scalprod.c
@@ -0,0 +1,16 @@
+#include <omp.h>
+
+#ifdef __cplusplus
+extern "C"
+#endif
+ void
+ scalprod(int n, double* x, double* y, double* res)
+{
+ int i;
+ double res_v = 0.;
+#pragma omp parallel for reduction(+ : res_v)
+ for (i = 0; i < n; ++i) {
+ res_v += x[i] * y[i];
+ }
+ *res = res_v;
+}
diff --git a/Tests/FindOpenMP/Test/scalprod.f90.in b/Tests/FindOpenMP/Test/scalprod.f90.in
new file mode 100644
index 0000000..efc7ea0
--- /dev/null
+++ b/Tests/FindOpenMP/Test/scalprod.f90.in
@@ -0,0 +1,19 @@
+subroutine scalprod(n, x_p, y_p, res) bind(c)
+ use iso_c_binding
+ implicit none
+ integer(c_int), intent(in), value :: n
+ type(c_ptr), intent(in), value :: x_p, y_p
+ real(c_double), pointer :: x(:), y(:)
+ integer :: i
+
+ real(c_double) :: res
+ real(c_double) :: scalpt = 0
+ call c_f_pointer(x_p, x, shape=[n])
+ call c_f_pointer(y_p, y, shape=[n])
+ res = 0
+!$omp parallel do private(scalpt), reduction(+:res)
+ do i=1,n
+ scalpt = y(i) * x(i)
+ res = res + scalpt
+ end do
+end subroutine scalprod
diff --git a/Tests/FindOpenMP/Test/scaltest.c b/Tests/FindOpenMP/Test/scaltest.c
new file mode 100644
index 0000000..4678b87
--- /dev/null
+++ b/Tests/FindOpenMP/Test/scaltest.c
@@ -0,0 +1,20 @@
+#ifdef __cplusplus
+# include <iostream>
+extern "C"
+#else
+# include <stdio.h>
+#endif
+int scalprod(int n, double* x, double* y, double* res);
+
+int main()
+{
+ double a[5] = { 1., 2., 3., 4., 5. };
+ double b[5] = { 2., 3., 4., 5., 6. };
+ double rk;
+ scalprod(5, a, b, &rk);
+#ifdef __cplusplus
+ std::cout << rk << std::endl;
+#else
+ printf("%f\n", rk);
+#endif
+}
diff --git a/Tests/FindOpenMP/Test/scaltest.f90.in b/Tests/FindOpenMP/Test/scaltest.f90.in
new file mode 100644
index 0000000..64c20d2
--- /dev/null
+++ b/Tests/FindOpenMP/Test/scaltest.f90.in
@@ -0,0 +1,21 @@
+program scaltest
+ use iso_c_binding
+ implicit none
+ interface
+ subroutine scalprod(n, x_p, y_p, res) bind(c)
+ use iso_c_binding
+ integer(c_int), value :: n
+ type(c_ptr), value :: x_p, y_p
+ real(c_double) :: res
+ end subroutine scalprod
+ end interface
+ type(c_ptr) :: x_pt, y_pt
+ real(c_double), dimension(5), target :: a = (/ 1, 2, 3, 4, 5 /)
+ real(c_double), dimension(5), target :: b = (/ 2, 3, 4, 5, 6 /)
+ integer(c_int) :: n = size(a)
+ real(c_double) :: res
+ x_pt = c_loc(a)
+ y_pt = c_loc(b)
+ call scalprod(n, x_pt, y_pt, res)
+ print *, res
+end program scaltest
diff --git a/Tests/FindOpenSSL/CMakeLists.txt b/Tests/FindOpenSSL/CMakeLists.txt
new file mode 100644
index 0000000..66b3fb2
--- /dev/null
+++ b/Tests/FindOpenSSL/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_test(NAME FindOpenSSL.rand COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindOpenSSL/rand"
+ "${CMake_BINARY_DIR}/Tests/FindOpenSSL/rand"
+ ${build_generator_args}
+ --build-project FindOpenSSL_rand
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
diff --git a/Tests/FindOpenSSL/rand/CMakeLists.txt b/Tests/FindOpenSSL/rand/CMakeLists.txt
new file mode 100644
index 0000000..520d5d2
--- /dev/null
+++ b/Tests/FindOpenSSL/rand/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.0)
+project(FindOpenSSL_rand CXX)
+include(CTest)
+
+find_package(OpenSSL REQUIRED)
+
+add_executable(tstopensslrand_tgt main.cc)
+target_link_libraries(tstopensslrand_tgt OpenSSL::SSL)
+add_test(NAME tstopensslrand_tgt COMMAND tstopensslrand_tgt)
+
+add_executable(tstopensslrand_var main.cc)
+target_link_libraries(tstopensslrand_var ${OPENSSL_LIBRARIES})
+target_include_directories(tstopensslrand_var PRIVATE ${OPENSSL_INCLUDE_DIR})
+add_test(NAME tstopensslrand_var COMMAND tstopensslrand_var)
diff --git a/Tests/FindOpenSSL/rand/main.cc b/Tests/FindOpenSSL/rand/main.cc
new file mode 100644
index 0000000..147044b
--- /dev/null
+++ b/Tests/FindOpenSSL/rand/main.cc
@@ -0,0 +1,21 @@
+#include <openssl/rand.h>
+
+int main()
+{
+ // return value
+ int retval = 1;
+
+ // bytes buffer
+ unsigned char buf[1024];
+
+ // random bytes
+ int rezval = RAND_bytes(buf, sizeof(buf)); /* 1 success, 0 otherwise */
+
+ // check result
+ if (rezval == 1) {
+ retval = 0;
+ }
+
+ // return code
+ return retval;
+}
diff --git a/Tests/FindPNG/CMakeLists.txt b/Tests/FindPNG/CMakeLists.txt
new file mode 100644
index 0000000..c665b67
--- /dev/null
+++ b/Tests/FindPNG/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindPNG.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPNG/Test"
+ "${CMake_BINARY_DIR}/Tests/FindPNG/Test"
+ ${build_generator_args}
+ --build-project TestFindPNG
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindPNG/Test/CMakeLists.txt b/Tests/FindPNG/Test/CMakeLists.txt
new file mode 100644
index 0000000..ad50011
--- /dev/null
+++ b/Tests/FindPNG/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.4)
+project(TestFindPNG C)
+include(CTest)
+
+find_package(PNG REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_PNG_VERSION="${PNG_VERSION_STRING}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt PNG::PNG)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${PNG_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${PNG_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindPNG/Test/main.c b/Tests/FindPNG/Test/main.c
new file mode 100644
index 0000000..b33b28e
--- /dev/null
+++ b/Tests/FindPNG/Test/main.c
@@ -0,0 +1,18 @@
+#include <assert.h>
+#include <png.h>
+#include <string.h>
+
+int main()
+{
+ png_uint_32 png_version;
+ char png_version_string[16];
+
+ png_version = png_access_version_number();
+
+ snprintf(png_version_string, 16, "%i.%i.%i", png_version / 10000,
+ (png_version % 10000) / 100, png_version % 100);
+
+ assert(strcmp(png_version_string, CMAKE_EXPECTED_PNG_VERSION) == 0);
+
+ return 0;
+}
diff --git a/Tests/FindPackageModeMakefileTest/CMakeLists.txt b/Tests/FindPackageModeMakefileTest/CMakeLists.txt
new file mode 100644
index 0000000..0b15be8
--- /dev/null
+++ b/Tests/FindPackageModeMakefileTest/CMakeLists.txt
@@ -0,0 +1,45 @@
+
+
+if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Makefile" AND
+ NOT CMake_TEST_NO_FindPackageModeMakefileTest)
+
+ # Test whether the make is GNU make, and only add the test in this case,
+ # since the configured makefile in this test uses $(shell ...), which
+ # is AFAIK a GNU make extension. Alex
+ execute_process(COMMAND ${CMAKE_MAKE_PROGRAM} -v
+ OUTPUT_VARIABLE makeVersionOutput
+ ERROR_QUIET
+ TIMEOUT 10)
+ string(TOUPPER "${makeVersionOutput}" MAKE_VERSION_OUTPUT)
+ if("${MAKE_VERSION_OUTPUT}" MATCHES "GNU MAKE")
+
+ # build a library which we can search during the test
+ add_library(foo STATIC foo.cpp)
+
+ # configure a FindFoo.cmake so it knows where the library can be found
+ configure_file(FindFoo.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FindFoo.cmake @ONLY)
+
+ set(EXTRA_FLAGS "")
+ if(APPLE)
+ # Need the -isysroot flag on recentish macOS after command line tools
+ # no longer provide headers in /usr/include
+ if(CMAKE_OSX_SYSROOT)
+ string(APPEND EXTRA_FLAGS " -isysroot ${CMAKE_OSX_SYSROOT}")
+ endif()
+ foreach(arch ${CMAKE_OSX_ARCHITECTURES})
+ string(APPEND EXTRA_FLAGS " -arch ${arch}")
+ endforeach()
+ endif()
+
+ # now set up the test:
+ file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/cmakeExecutable.mk"
+ CONTENT "CMAKE = \"$<TARGET_FILE:cmake>\"\n"
+ )
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Makefile.in ${CMAKE_CURRENT_BINARY_DIR}/ConfMakefile @ONLY)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/main.cpp ${CMAKE_CURRENT_BINARY_DIR}/main.cpp COPYONLY)
+
+ add_test(FindPackageModeMakefileTest ${CMAKE_MAKE_PROGRAM} -f ${CMAKE_CURRENT_BINARY_DIR}/ConfMakefile )
+
+ endif()
+
+endif()
diff --git a/Tests/FindPackageModeMakefileTest/FindFoo.cmake.in b/Tests/FindPackageModeMakefileTest/FindFoo.cmake.in
new file mode 100644
index 0000000..2eb7b7a
--- /dev/null
+++ b/Tests/FindPackageModeMakefileTest/FindFoo.cmake.in
@@ -0,0 +1,11 @@
+
+find_library(FOO_LIBRARY NAMES foo HINTS "@CMAKE_CURRENT_BINARY_DIR@" )
+find_path(FOO_INCLUDE_DIR NAMES foo.h HINTS "@CMAKE_CURRENT_SOURCE_DIR@" )
+
+set(FOO_LIBRARIES ${FOO_LIBRARY})
+set(FOO_INCLUDE_DIRS "${FOO_INCLUDE_DIR}" "/some/path/with a space/include" )
+
+add_library(Foo::Foo INTERFACE IMPORTED)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Foo DEFAULT_MSG FOO_LIBRARY FOO_INCLUDE_DIR )
diff --git a/Tests/FindPackageModeMakefileTest/Makefile.in b/Tests/FindPackageModeMakefileTest/Makefile.in
new file mode 100644
index 0000000..695c64f
--- /dev/null
+++ b/Tests/FindPackageModeMakefileTest/Makefile.in
@@ -0,0 +1,33 @@
+
+include cmakeExecutable.mk
+
+CMAKE_CURRENT_BINARY_DIR = "@CMAKE_CURRENT_BINARY_DIR@"
+CMAKE_CXX_COMPILER = "@CMAKE_CXX_COMPILER@"
+CMAKE_CXX_COMPILER_ID = "@CMAKE_CXX_COMPILER_ID@"
+CMAKE_CXX_FLAGS = @CMAKE_CXX_FLAGS@
+EXTRA_FLAGS = @EXTRA_FLAGS@
+
+CMAKE_FOO = $(CMAKE) --find-package -DCMAKE_MODULE_PATH=$(CMAKE_CURRENT_BINARY_DIR) -DNAME=Foo -DLANGUAGE=CXX -DCOMPILER_ID=$(CMAKE_CXX_COMPILER_ID)
+
+tmp = tmp.txt
+
+all: pngtest
+
+main.o: clean main.cpp
+ @$(CMAKE_FOO) -DMODE=COMPILE >$(tmp)
+ @foo="`cat $(tmp)`"; \
+ printf '"%s" %s %s %s -c main.cpp\n' $(CMAKE_CXX_COMPILER) "$(CMAKE_CXX_FLAGS)" "$(EXTRA_FLAGS)" "$$foo" >$(tmp)
+ @cat $(tmp)
+ @sh $(tmp)
+ @rm -f $(tmp)
+
+pngtest: main.o
+ @$(CMAKE_FOO) -DMODE=LINK >$(tmp)
+ @foo="`cat $(tmp)`"; \
+ printf '"%s" %s %s %s -o pngtest main.o %s\n' $(CMAKE_CXX_COMPILER) "$(CMAKE_CXX_FLAGS)" "$(EXTRA_FLAGS)" "$(LDFLAGS)" "$$foo" >$(tmp)
+ @cat $(tmp)
+ @sh $(tmp)
+ @rm -f $(tmp)
+
+clean:
+ rm -f $(tmp) *.o pngtest
diff --git a/Tests/FindPackageModeMakefileTest/foo.cpp b/Tests/FindPackageModeMakefileTest/foo.cpp
new file mode 100644
index 0000000..7cb9381
--- /dev/null
+++ b/Tests/FindPackageModeMakefileTest/foo.cpp
@@ -0,0 +1,6 @@
+#include "foo.h"
+
+int foo()
+{
+ return 1477;
+}
diff --git a/Tests/FindPackageModeMakefileTest/foo.h b/Tests/FindPackageModeMakefileTest/foo.h
new file mode 100644
index 0000000..7051eda
--- /dev/null
+++ b/Tests/FindPackageModeMakefileTest/foo.h
@@ -0,0 +1,14 @@
+#ifndef FOO_H
+#define FOO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int foo();
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/Tests/FindPackageModeMakefileTest/main.cpp b/Tests/FindPackageModeMakefileTest/main.cpp
new file mode 100644
index 0000000..9def3fb
--- /dev/null
+++ b/Tests/FindPackageModeMakefileTest/main.cpp
@@ -0,0 +1,8 @@
+#include <foo.h>
+#include <stdio.h>
+
+int main()
+{
+ printf("foo is: %d\n", foo());
+ return 0;
+}
diff --git a/Tests/FindPackageTest/.gitignore b/Tests/FindPackageTest/.gitignore
new file mode 100644
index 0000000..3aaef13
--- /dev/null
+++ b/Tests/FindPackageTest/.gitignore
@@ -0,0 +1 @@
+/symlink
diff --git a/Tests/FindPackageTest/A/wibble-config.cmake b/Tests/FindPackageTest/A/wibble-config.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/A/wibble-config.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/B/wibble-config.cmake b/Tests/FindPackageTest/B/wibble-config.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/B/wibble-config.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/Baz 1.1/BazConfig.cmake b/Tests/FindPackageTest/Baz 1.1/BazConfig.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/Baz 1.1/BazConfig.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/Baz 1.1/BazConfigVersion.cmake b/Tests/FindPackageTest/Baz 1.1/BazConfigVersion.cmake
new file mode 100644
index 0000000..979bbdf
--- /dev/null
+++ b/Tests/FindPackageTest/Baz 1.1/BazConfigVersion.cmake
@@ -0,0 +1,8 @@
+set(PACKAGE_VERSION 1.1)
+if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 1)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 1)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
+
diff --git a/Tests/FindPackageTest/Baz 1.2/CMake/BazConfig.cmake b/Tests/FindPackageTest/Baz 1.2/CMake/BazConfig.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/Baz 1.2/CMake/BazConfig.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/Baz 1.2/CMake/BazConfigVersion.cmake b/Tests/FindPackageTest/Baz 1.2/CMake/BazConfigVersion.cmake
new file mode 100644
index 0000000..17caaa7
--- /dev/null
+++ b/Tests/FindPackageTest/Baz 1.2/CMake/BazConfigVersion.cmake
@@ -0,0 +1,8 @@
+set(PACKAGE_VERSION 1.2)
+if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 1)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 2)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
+
diff --git a/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfig.cmake b/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfig.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfig.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfigVersion.cmake b/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfigVersion.cmake
new file mode 100644
index 0000000..d8cac77
--- /dev/null
+++ b/Tests/FindPackageTest/Baz 1.3/lib/cmake/Baz/BazConfigVersion.cmake
@@ -0,0 +1,7 @@
+set(PACKAGE_VERSION 1.3)
+if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 1)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 3)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
diff --git a/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfig.cmake b/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfig.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfig.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfigVersion.cmake b/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfigVersion.cmake
new file mode 100644
index 0000000..5026fad
--- /dev/null
+++ b/Tests/FindPackageTest/Baz 2.0/share/Baz 2/BazConfigVersion.cmake
@@ -0,0 +1,7 @@
+set(PACKAGE_VERSION 2.0)
+if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 2)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 0)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
diff --git a/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfig.cmake b/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfig.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfig.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfigVersion.cmake b/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfigVersion.cmake
new file mode 100644
index 0000000..a180143
--- /dev/null
+++ b/Tests/FindPackageTest/Baz 2.1/lib/Baz 2/cmake/BazConfigVersion.cmake
@@ -0,0 +1,7 @@
+set(PACKAGE_VERSION 2.1)
+if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 2)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 1)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
diff --git a/Tests/FindPackageTest/CMakeLists.txt b/Tests/FindPackageTest/CMakeLists.txt
new file mode 100644
index 0000000..7217f43
--- /dev/null
+++ b/Tests/FindPackageTest/CMakeLists.txt
@@ -0,0 +1,661 @@
+cmake_minimum_required (VERSION 2.6)
+project(FindPackageTest)
+
+# Protect tests from running inside the default install prefix.
+set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/NotDefaultPrefix")
+
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
+
+# Look for a package which uses FindPackageHandleStandardArgs.cmake with the
+# new (as of cmake 2.8.3) syntax. This works only if CMP0017 is set to NEW,
+# because otherwise FindPackageHandleStandardArgs.cmake from the current
+# directory is included (via CMAKE_MODULE_PATH).
+cmake_policy(SET CMP0017 NEW)
+find_package(ZLIB QUIET)
+
+# Look for a package that has a find module and may be found.
+find_package(OpenGL QUIET)
+
+# Look for a package that has no find module and will not be found.
+find_package(NotAPackage QUIET)
+
+# Look for a package that has an advanced find module.
+find_package(VTK QUIET)
+
+add_executable(FindPackageTest FindPackageTest.cxx)
+
+# test behaviour of cmFindBase wrt. the CMAKE_PREFIX_PATH variable
+# foo.h should be found in ${CMAKE_CURRENT_SOURCE_DIR}/include:
+
+set(CMAKE_PREFIX_PATH /blub /blah "${CMAKE_CURRENT_SOURCE_DIR}")
+find_path(FOO_DIR foo.h)
+
+if(NOT FOO_DIR)
+ message(FATAL_ERROR "Did not find foo.h which is in ${CMAKE_CURRENT_SOURCE_DIR}/include
+ CMAKE_PREFIX_PATH = ${CMAKE_PREFIX_PATH}")
+endif()
+
+find_package(VersionTestA 1)
+find_package(VersionTestB 1.2)
+find_package(VersionTestC 1.2.3)
+find_package(VersionTestD 1.2.3.4)
+
+
+find_package(LotsOfComponents COMPONENTS AComp OPTIONAL_COMPONENTS BComp CComp)
+if(NOT LOTSOFCOMPONENTS_FOUND)
+ message(SEND_ERROR "LotsOfComponents not found !")
+endif()
+
+find_package(SomePackage)
+if(NOT SomePackage_FOUND)
+ message(SEND_ERROR "SomePackage not found !")
+endif()
+if(NOT SOMEPACKAGE_FOUND)
+ message(SEND_ERROR "SomePackage compatibility name SOMEPACKAGE_FOUND not set!")
+endif()
+
+find_package(UpperCasePackage)
+if(NOT UpperCasePackage_FOUND)
+ message(SEND_ERROR "UpperCasePackage not found!")
+endif()
+if(NOT UPPERCASEPACKAGE_FOUND)
+ message(SEND_ERROR "SomePackage compatibility name SOMEPACKAGE_FOUND not set!")
+endif()
+
+#-----------------------------------------------------------------------------
+# Test system package registry if possible.
+set(CMakeTestSystemPackage "")
+if(WIN32 AND NOT CYGWIN)
+ # Try writing a value to the system package registry.
+ set(_data "${FindPackageTest_SOURCE_DIR}/SystemPackage")
+ set(_key "HKLM\\Software\\Kitware\\CMake\\Packages\\CMakeTestSystemPackage")
+ set(_file "${FindPackageTest_BINARY_DIR}/CMakeTestSystemPackage.data")
+ file(WRITE ${_file} "${_data}\n")
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} -E md5sum ${_file}
+ OUTPUT_VARIABLE _output ERROR_VARIABLE _error RESULT_VARIABLE _failed
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ string(REGEX REPLACE " .*" "" _value "${_output}")
+ if(NOT _failed AND _value)
+ execute_process(
+ COMMAND reg add "${_key}" /v "${_value}" /t REG_SZ /d "${_data}" /f
+ OUTPUT_VARIABLE _output ERROR_VARIABLE _output RESULT_VARIABLE _failed
+ )
+ endif()
+ # If the above worked, add the rest of the test and a rule to
+ # cleanup the value.
+ if(NOT _failed)
+ message(STATUS "HKLM is writable: enabling CMakeTestSystemPackage")
+ set(CMakeTestSystemPackage_CLEANUP reg delete "${_key}" /v "${_value}" /f)
+ set(CMakeTestSystemPackage CMakeTestSystemPackage)
+ else()
+ message(STATUS "HKLM is readonly: disabling CMakeTestSystemPackage")
+ endif()
+endif()
+
+#-----------------------------------------------------------------------------
+
+#set(CMAKE_FIND_DEBUG_MODE 1)
+
+# For purposes of the test wipe out previous find results.
+set(PACKAGES
+ foo Foo Bar Blub TFramework Tframework TApp Tapp Special
+ VersionedA VersionedB VersionedC VersionedD VersionedE
+ VersionedF VersionedG VersionedH
+ WrongA WrongB WrongC WrongD
+ wibbleA wibbleB
+ RecursiveA RecursiveB RecursiveC
+ ArchA ArchB ArchC ArchD
+ EnvA EnvB
+ SetFoundTRUE SetFoundFALSE
+ ${CMakeTestSystemPackage}
+ )
+foreach(p ${PACKAGES})
+ set(${p}_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+endforeach()
+
+# Enable framework and bundle searching. Make sure bundles are found
+# before unix-syle packages.
+set(CMAKE_FIND_FRAMEWORK LAST)
+set(CMAKE_FIND_APPBUNDLE FIRST)
+
+# Set the wrong answer for a find to make sure it re-finds.
+set(VersionedA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/cmake/zot-4.0)
+
+# Test that CMAKE_IGNORE_PATH can ignore the purposely bad package
+# files in the lib/cmake/zot-3.1 directory.
+set(CMAKE_IGNORE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib/cmake/zot-3.1)
+
+# Look for packages with new-style signatures.
+find_package(foo NO_MODULE)
+find_package(Foo CONFIGS FooConfig.cmake)
+find_package(Bar)
+set(CMAKE_DISABLE_FIND_PACKAGE_Blub TRUE)
+find_package(Blub NO_MODULE)
+find_package(TFramework CONFIGS TFrameworkConfig.cmake)
+find_package(Tframework)
+find_package(TApp)
+find_package(Tapp CONFIGS tapp-config.cmake)
+find_package(Special NAMES Suffix SuffixTest PATH_SUFFIXES test)
+find_package(VersionedA 2 NAMES zot)
+find_package(VersionedB 3.1 EXACT NAMES zot)
+find_package(VersionedC 4.0 EXACT NAMES zot)
+find_package(VersionedD 1.1 EXACT NAMES Baz)
+find_package(VersionedE 1.2 EXACT NAMES Baz)
+find_package(VersionedF 1.3 EXACT NAMES Baz)
+find_package(VersionedG 2.0 EXACT NAMES Baz)
+find_package(VersionedH 2.1 EXACT NAMES Baz)
+
+
+# Test Config files which set Xyz_FOUND themselves:
+find_package(SetFoundTRUE NO_MODULE)
+find_package(SetFoundFALSE NO_MODULE)
+
+# Test wrong initial path when result is present.
+set(WrongA_DIR "${VersionedD_DIR}")
+find_package(WrongA 1.2 EXACT NAMES Baz)
+
+# Test wrong initial cache entry of UNINITIALIZED type when result is present.
+set(WrongB_DIR "${VersionedD_DIR}" CACHE UNINITIALIZED "Wrong Value" FORCE)
+get_property(type CACHE WrongB_DIR PROPERTY TYPE)
+find_package(WrongB 1.2 EXACT NAMES Baz)
+
+# Test wrong initial path when result is missing.
+set(WrongC_DIR "${VersionedD_DIR}")
+find_package(WrongC 1.4 EXACT QUIET NAMES Baz)
+
+# Test wrong initial cache entry of UNINITIALIZED type when result is missing.
+set(WrongD_DIR "${VersionedD_DIR}" CACHE UNINITIALIZED "Wrong Value" FORCE)
+get_property(type CACHE WrongD_DIR PROPERTY TYPE)
+find_package(WrongD 1.4 EXACT QUIET NAMES Baz)
+
+# HINTS should override the system but PATHS should not
+list(INSERT CMAKE_SYSTEM_PREFIX_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/A")
+find_package(wibbleA NAMES wibble PATHS B)
+find_package(wibbleB NAMES wibble HINTS B)
+
+# Look for package with recursive find-modules.
+find_package(RecursiveA COMPONENTS A)
+find_package(RecursiveB 2)
+find_package(RecursiveC 3.1 EXACT)
+
+# Test architecture-specific search directories.
+set(CMAKE_LIBRARY_ARCHITECTURE arch)
+find_package(ArchA NAMES Bar)
+find_package(ArchB NAMES Foo CONFIGS FooConfig.cmake)
+find_package(ArchC 3.1 EXACT NAMES zot)
+find_package(ArchD 4.0 EXACT NAMES zot)
+unset(CMAKE_LIBRARY_ARCHITECTURE)
+
+# Test find_package() with CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS enabled
+if(UNIX)
+ # Create ./symlink pointing back here.
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink
+ . "${CMAKE_CURRENT_SOURCE_DIR}/symlink")
+ # Make find_package search through the symlink
+ set(CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/symlink")
+
+ # First, test the default behavior where symlinks are preserved.
+ set(SetFoundResolved_DIR "")
+ find_package(SetFoundResolved)
+ # The result must preserve the /symlink/ path.
+ set(SetFoundResolved_EXPECTED "${CMAKE_CURRENT_SOURCE_DIR}/symlink/cmake")
+ if(NOT "${SetFoundResolved_DIR}" STREQUAL "${SetFoundResolved_EXPECTED}")
+ message(SEND_ERROR "SetFoundResolved_DIR set by find_package() is set to \"${SetFoundResolved_DIR}\" (expected \"${SetFoundResolved_EXPECTED}\")")
+ endif()
+
+ # This part of the test only works if there are no symlinks in our path.
+ get_filename_component(real_src_dir "${CMAKE_CURRENT_SOURCE_DIR}" REALPATH)
+ if(real_src_dir STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ # Resolve symlinks when finding the package.
+ set(CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS TRUE)
+ set(SetFoundResolved_DIR "")
+ find_package(SetFoundResolved)
+ # ./symlink points back here so it should be gone when resolved.
+ set(SetFoundResolved_EXPECTED "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+ if(NOT "${SetFoundResolved_DIR}" STREQUAL "${SetFoundResolved_EXPECTED}")
+ message(SEND_ERROR "SetFoundResolved_DIR set by find_package() is set to \"${SetFoundResolved_DIR}\" (expected \"${SetFoundResolved_EXPECTED}\")")
+ endif()
+ endif()
+
+ # Cleanup.
+ unset(CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS)
+ file(REMOVE "${CMAKE_CURRENT_SOURCE_DIR}/symlink")
+endif()
+
+# Test <PackageName>_DIR environment variable.
+# We erase the main prefix path to ensure the env var is used.
+set(CMAKE_PREFIX_PATH)
+set(ENV{EnvA_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/lib/zot-3.1")
+find_package(EnvA 3.1 EXACT QUIET NAMES zot) # Should Work
+find_package(EnvB 3.1 EXACT QUIET NAMES zot) # Should Fail
+
+# Test system package registry if available.
+if(CMakeTestSystemPackage)
+ find_package(CMakeTestSystemPackage)
+ execute_process(COMMAND ${CMakeTestSystemPackage_CLEANUP}
+ OUTPUT_VARIABLE _output ERROR_VARIABLE _error)
+endif()
+
+# Expected locations at which packages should be found.
+set(foo_EXPECTED "lib/foo-1.2/foo-config.cmake")
+set(Foo_EXPECTED "lib/foo-1.2/CMake/FooConfig.cmake")
+set(Bar_EXPECTED "lib/Bar/BarConfig.cmake")
+set(Blub_MISSING "")
+set(Special_EXPECTED "lib/suffix/test/SuffixTestConfig.cmake")
+set(TFramework_EXPECTED
+ "TFramework.framework/Versions/A/Resources/CMake/TFrameworkConfig.cmake")
+set(Tframework_EXPECTED
+ "TFramework.framework/Versions/A/Resources/tframework-config.cmake")
+set(TApp_EXPECTED
+ "TApp.app/Contents/Resources/TAppConfig.cmake")
+set(Tapp_EXPECTED
+ "TApp.app/Contents/Resources/cmake/tapp-config.cmake")
+set(VersionedA_EXPECTED "lib/zot-2.0/zot-config.cmake")
+set(VersionedB_EXPECTED "lib/zot-3.1/zot-config.cmake")
+set(VersionedC_EXPECTED "lib/cmake/zot-4.0/zot-config.cmake")
+set(VersionedD_EXPECTED "Baz 1.1/BazConfig.cmake")
+set(VersionedE_EXPECTED "Baz 1.2/CMake/BazConfig.cmake")
+set(VersionedF_EXPECTED "Baz 1.3/lib/cmake/Baz/BazConfig.cmake")
+set(VersionedG_EXPECTED "Baz 2.0/share/Baz 2/BazConfig.cmake")
+set(VersionedH_EXPECTED "Baz 2.1/lib/Baz 2/cmake/BazConfig.cmake")
+set(WrongA_EXPECTED "${VersionedE_EXPECTED}")
+set(WrongB_EXPECTED "${VersionedE_EXPECTED}")
+set(WrongC_MISSING "WrongC_DIR-NOTFOUND")
+set(WrongD_MISSING "WrongD_DIR-NOTFOUND")
+set(wibbleA_EXPECTED "A/wibble-config.cmake")
+set(wibbleB_EXPECTED "B/wibble-config.cmake")
+set(RecursiveA_EXPECTED "lib/RecursiveA/recursivea-config.cmake")
+set(RecursiveB_EXPECTED "lib/zot-2.0/zot-config.cmake")
+set(RecursiveC_EXPECTED "lib/zot-3.1/zot-config.cmake")
+set(ArchA_EXPECTED "lib/arch/Bar/BarConfig.cmake")
+set(ArchB_EXPECTED "lib/arch/foo-1.2/CMake/FooConfig.cmake")
+set(ArchC_EXPECTED "lib/arch/zot-3.1/zot-config.cmake")
+set(ArchD_EXPECTED "lib/arch/cmake/zot-4.0/zot-config.cmake")
+set(EnvA_EXPECTED "lib/zot-3.1/zot-config.cmake")
+set(EnvB_MISSING "EnvB_DIR-NOTFOUND")
+set(SetFoundTRUE_EXPECTED "cmake/SetFoundTRUEConfig.cmake")
+set(SetFoundFALSE_MISSING "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+set(CMakeTestSystemPackage_EXPECTED "SystemPackage/CMakeTestSystemPackageConfig.cmake")
+
+# Check the results.
+foreach(p ${PACKAGES})
+ if(DEFINED ${p}_MISSING)
+ # Check and report failure.
+ if(NOT "${${p}_DIR}" STREQUAL "${${p}_MISSING}")
+ message(SEND_ERROR
+ "Package ${p} should have been [${${p}_MISSING}] but "
+ "was [${${p}_DIR}]")
+ endif()
+ if(${p}_FOUND)
+ message(SEND_ERROR
+ "Package ${p} should not have been found, but ${p}_FOUND is set to "
+ "\"${${p}_FOUND}\"")
+ endif()
+ elseif(${p}_FOUND)
+ # Convert to relative path for comparison to expected location.
+ file(RELATIVE_PATH REL_${p}_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}"
+ "${${p}_CONFIG}")
+
+ # Debugging output.
+ if(CMAKE_FIND_DEBUG_MODE)
+ message("Package ${p} found [${REL_${p}_CONFIG}]")
+ endif()
+
+ # Check and report failure.
+ if(NOT "${REL_${p}_CONFIG}" STREQUAL "${${p}_EXPECTED}")
+ message(SEND_ERROR
+ "Package ${p} should have been [${${p}_EXPECTED}] but "
+ "was [${REL_${p}_CONFIG}]")
+ endif()
+ else()
+ message(SEND_ERROR "Package ${p} not found!")
+ endif()
+endforeach()
+
+# Check that version information was extracted.
+if(NOT "${VersionedA_VERSION}" STREQUAL "2.0")
+ message(SEND_ERROR
+ "Package VersionedA is version [${VersionedA_VERSION}], not [2.0]")
+endif()
+if(NOT "${VersionedA_VERSION_MAJOR}" STREQUAL "2")
+ message(SEND_ERROR
+ "Package VersionedA is major version [${VersionedA_VERSION_MAJOR}], not [2]")
+endif()
+if(NOT "${VersionedA_VERSION_MINOR}" STREQUAL "0")
+ message(SEND_ERROR
+ "Package VersionedA is minor version [${VersionedA_VERSION_MINOR}], not [0]")
+endif()
+
+if(NOT "${VersionedB_VERSION}" STREQUAL "3.1")
+ message(SEND_ERROR
+ "Package VersionedB is version [${VersionedB_VERSION}], not [3.1]")
+endif()
+if(NOT "${VersionedB_VERSION_MAJOR}" STREQUAL "3")
+ message(SEND_ERROR
+ "Package VersionedB is major version [${VersionedB_VERSION_MAJOR}], not [3]")
+endif()
+if(NOT "${VersionedB_VERSION_MINOR}" STREQUAL "1")
+ message(SEND_ERROR
+ "Package VersionedB is minor version [${VersionedB_VERSION_MINOR}], not [1]")
+endif()
+
+if(NOT "${Special_VERSION}" STREQUAL "1.2")
+ message(SEND_ERROR
+ "Package Special is version [${Special_VERSION}], not [1.2]")
+endif()
+if(NOT "${Special_VERSION_MAJOR}" STREQUAL "1")
+ message(SEND_ERROR
+ "Package Special is major version [${Special_VERSION_MAJOR}], not [1]")
+endif()
+if(NOT "${Special_VERSION_MINOR}" STREQUAL "2")
+ message(SEND_ERROR
+ "Package Special is minor version [${Special_VERSION_MINOR}], not [2]")
+endif()
+
+# Test version number comparison.
+if(NOT "1.2.3.4" VERSION_LESS "1.2.3.5")
+ message(SEND_ERROR "1.2.3.4 VERSION_LESS 1.2.3.5 is not true!")
+endif()
+if(NOT "1.2" VERSION_LESS "1.10")
+ message(SEND_ERROR "1.2 VERSION_LESS 1.10 is not true!")
+endif()
+if(NOT "1.02" VERSION_GREATER "1.1")
+ message(SEND_ERROR "1.02 VERSION_GREATER 1.1 is not true!")
+endif()
+if("1.2.3" VERSION_GREATER "1.2.3.4")
+ message(SEND_ERROR "1.2.3 VERSION_GREATER 1.2.3.4 is not false!")
+endif()
+if(NOT "1.2" VERSION_EQUAL "1.2.0.0")
+ message(SEND_ERROR "1.2 VERSION_EQUAL 1.2.0.0 is not true!")
+endif()
+
+#-----------------------------------------------------------------------------
+# Test export(PACKAGE) with find_package.
+
+# Choose a unique version.
+string(REGEX REPLACE "-.*$" "" version ${CMAKE_VERSION})
+string(RANDOM LENGTH 4 ALPHABET "0123456789" v)
+string(APPEND version ".${v}")
+
+message(STATUS "Preparing export(PACKAGE) test project")
+try_compile(EXPORTER_COMPILED
+ ${FindPackageTest_BINARY_DIR}/Exporter-build
+ ${FindPackageTest_SOURCE_DIR}/Exporter
+ CMakeTestExportPackage dummy
+ CMAKE_FLAGS "-UCMAKE_EXPORT_NO_PACKAGE_REGISTRY"
+ "-DCMAKE_POLICY_DEFAULT_CMP0090:STRING=OLD"
+ -Dversion=${version}
+ OUTPUT_VARIABLE output)
+message(STATUS "Searching for export(PACKAGE) test project")
+set(CMakeTestExportPackage_DIR "" CACHE FILEPATH
+ "Wipe out find results for testing." FORCE)
+
+message(STATUS "Searching for export(PACKAGE) with CMAKE_FIND_USE_PACKAGE_REGISTRY=TRUE")
+set(CMAKE_FIND_USE_PACKAGE_REGISTRY TRUE)
+find_package(CMakeTestExportPackage 1.${version} EXACT REQUIRED)
+if(NOT CMakeTestExportPackage_FOUND)
+ message(SEND_ERROR "CMakeTestExportPackage should be FOUND!")
+endif()
+unset(CMAKE_FIND_USE_PACKAGE_REGISTRY)
+
+message(STATUS "Searching for export(PACKAGE) with CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=FALSE")
+set(CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY FALSE)
+find_package(CMakeTestExportPackage 1.${version} EXACT REQUIRED)
+if(NOT CMakeTestExportPackage_FOUND)
+ message(SEND_ERROR "CMakeTestExportPackage should be FOUND!")
+endif()
+unset(CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY)
+
+message(STATUS "Searching for export(PACKAGE) with CMAKE_FIND_USE_PACKAGE_REGISTRY=TRUE and CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=TRUE")
+set(CMAKE_FIND_USE_PACKAGE_REGISTRY TRUE)
+set(CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY TRUE)
+set(CMakeTestExportPackage_DIR FALSE)
+find_package(CMakeTestExportPackage 1.${version} EXACT REQUIRED)
+if(NOT CMakeTestExportPackage_FOUND)
+ message(SEND_ERROR "CMakeTestExportPackage should be FOUND!")
+endif()
+unset(CMAKE_FIND_USE_PACKAGE_REGISTRY)
+unset(CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY)
+
+message(STATUS "Searching for export(PACKAGE) with CMAKE_FIND_USE_PACKAGE_REGISTRY=FALSE and CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=FALSE")
+set(CMAKE_FIND_USE_PACKAGE_REGISTRY FALSE)
+set(CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY FALSE)
+set(CMakeTestExportPackage_DIR "" CACHE FILEPATH
+ "Wipe out find results for testing." FORCE)
+find_package(CMakeTestExportPackage 1.${version} EXACT QUIET)
+if(CMakeTestExportPackage_FOUND)
+ message(SEND_ERROR "CMakeTestExportPackage should be not FOUND!")
+endif()
+unset(CMAKE_FIND_USE_PACKAGE_REGISTRY)
+unset(CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY)
+
+message(STATUS "Remove export(PACKAGE) test project")
+file(REMOVE_RECURSE ${FindPackageTest_BINARY_DIR}/Exporter-build)
+set(CMakeTestExportPackage_DIR "" CACHE FILEPATH
+ "Wipe out find results for testing." FORCE)
+find_package(CMakeTestExportPackage QUIET) # Should clean the user package cache
+#
+message(STATUS "Preparing export(PACKAGE) test project with CMAKE_EXPORT_NO_PACKAGE_REGISTRY=TRUE")
+try_compile(EXPORTER_COMPILED
+ ${FindPackageTest_BINARY_DIR}/Exporter-build
+ ${FindPackageTest_SOURCE_DIR}/Exporter
+ CMakeTestExportPackage dummy
+ CMAKE_FLAGS "-DCMAKE_EXPORT_NO_PACKAGE_REGISTRY:BOOL=TRUE"
+ -Dversion=${version}
+ OUTPUT_VARIABLE output)
+message(STATUS "Searching for export(PACKAGE) test project")
+find_package(CMakeTestExportPackage 1.${version} EXACT QUIET)
+if(CMakeTestExportPackage_FOUND)
+ message(SEND_ERROR "CMakeTestExportPackage should not be FOUND!")
+endif()
+
+message(STATUS "Remove export(PACKAGE) test project")
+file(REMOVE_RECURSE ${FindPackageTest_BINARY_DIR}/Exporter-build)
+
+message(STATUS "Preparing export(PACKAGE) test project with POLICY CMP0090=NEW")
+try_compile(EXPORTER_COMPILED
+ ${FindPackageTest_BINARY_DIR}/Exporter-build
+ ${FindPackageTest_SOURCE_DIR}/Exporter
+ CMakeTestExportPackage dummy
+ CMAKE_FLAGS
+ "-DCMAKE_POLICY_DEFAULT_CMP0090:STRING=NEW"
+ -Dversion=${version}
+ OUTPUT_VARIABLE output)
+message(STATUS "Searching for export(PACKAGE) test project")
+find_package(CMakeTestExportPackage 1.${version} EXACT QUIET)
+if(CMakeTestExportPackage_FOUND)
+ message(SEND_ERROR "CMakeTestExportPackage should not be FOUND!")
+endif()
+
+
+#-----------------------------------------------------------------------------
+# Test configure_package_config_file().
+
+include(CMakePackageConfigHelpers)
+
+# Generate a config file ready to be installed.
+set(INCLUDE_INSTALL_DIR include )
+set(SHARE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share/" )
+set(CURRENT_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}" )
+
+configure_package_config_file(RelocatableConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/RelocatableConfig.cmake"
+ INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}"
+ PATH_VARS INCLUDE_INSTALL_DIR SHARE_INSTALL_DIR CURRENT_BUILD_DIR
+ )
+
+set(Relocatable_FIND_COMPONENTS AComp BComp CComp)
+set(Relocatable_FIND_REQUIRED_BComp 1)
+include("${CMAKE_CURRENT_BINARY_DIR}/RelocatableConfig.cmake")
+
+if(NOT "${RELOC_INCLUDE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/include")
+ message(SEND_ERROR "RELOC_INCLUDE_DIR set by configure_package_config_file() is set to \"${RELOC_INCLUDE_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}/include\")")
+endif()
+
+if(NOT "${RELOC_SHARE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/share/")
+ message(SEND_ERROR "RELOC_SHARE_DIR set by configure_package_config_file() is set to \"${RELOC_SHARE_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}/share/\")")
+endif()
+
+if(NOT "${RELOC_BUILD_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
+ message(SEND_ERROR "RELOC_BUILD_DIR set by configure_package_config_file() is set to \"${RELOC_BUILD_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}\")")
+endif()
+
+if(NOT DEFINED Relocatable_FOUND)
+ message(SEND_ERROR "Relocatable_FOUND not defined !")
+endif()
+
+if(Relocatable_FOUND)
+ message(SEND_ERROR "Relocatable_FOUND set to TRUE !")
+endif()
+
+# Generate a config file for the build tree.
+set(INCLUDE_INSTALL_DIR include )
+set(SHARE_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/share/" )
+set(CURRENT_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}" )
+
+configure_package_config_file(RelocatableConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/RelocatableConfig.cmake"
+ INSTALL_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}"
+ PATH_VARS INCLUDE_INSTALL_DIR SHARE_INSTALL_DIR CURRENT_BUILD_DIR
+ INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}"
+ )
+
+set(Relocatable_FIND_COMPONENTS AComp BComp CComp)
+set(Relocatable_FIND_REQUIRED_BComp 1)
+include("${CMAKE_CURRENT_BINARY_DIR}/RelocatableConfig.cmake")
+
+if(NOT "${RELOC_INCLUDE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/include")
+ message(SEND_ERROR "RELOC_INCLUDE_DIR set by configure_package_config_file() is set to \"${RELOC_INCLUDE_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}/include\")")
+endif()
+
+if(NOT "${RELOC_SHARE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/share/")
+ message(SEND_ERROR "RELOC_SHARE_DIR set by configure_package_config_file() is set to \"${RELOC_SHARE_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}/share/\")")
+endif()
+
+if(NOT "${RELOC_BUILD_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
+ message(SEND_ERROR "RELOC_BUILD_DIR set by configure_package_config_file() is set to \"${RELOC_BUILD_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}\")")
+endif()
+
+if(NOT DEFINED Relocatable_FOUND)
+ message(SEND_ERROR "Relocatable_FOUND not defined !")
+endif()
+
+if(Relocatable_FOUND)
+ message(SEND_ERROR "Relocatable_FOUND set to TRUE !")
+endif()
+
+
+############################################################################
+##Test FIND_PACKAGE using sorting
+set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR})
+SET(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
+SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASC)
+
+set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+FIND_PACKAGE(SortLib CONFIG)
+IF (NOT "${SortLib_VERSION}" STREQUAL "3.1.1")
+ message(SEND_ERROR "FIND_PACKAGE_SORT_ORDER Name Asc! ${SortLib_VERSION}")
+endif()
+unset(SortLib_VERSION)
+
+
+set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
+SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
+FIND_PACKAGE(SortLib CONFIG)
+IF (NOT "${SortLib_VERSION}" STREQUAL "3.10.1")
+ message(SEND_ERROR "FIND_PACKAGE_SORT_ORDER Natural! Dec ${SortLib_VERSION}")
+endif()
+set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+unset(SortLib_VERSION)
+
+unset(CMAKE_FIND_PACKAGE_SORT_ORDER)
+unset(CMAKE_FIND_PACKAGE_SORT_DIRECTION)
+set(CMAKE_PREFIX_PATH )
+
+############################################################################
+##Test FIND_PACKAGE CMAKE_FIND_PACKAGE_PREFER_CONFIG
+
+set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/PreferConfig)
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/PreferConfig)
+
+# prefer module mode
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG OFF)
+unset(ABC_FOUND)
+unset(ABC_CONFIG)
+
+find_package(ABC)
+if(NOT ABC_FOUND)
+ message(SEND_ERROR "Did not find ABC package")
+endif()
+if(ABC_CONFIG)
+ message(SEND_ERROR "Incorrectly found ABC in CONFIG mode, expected to find it with MODULE mode")
+endif()
+
+# Now prefer config mode
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
+unset(ABC_FOUND)
+unset(ABC_CONFIG)
+
+find_package(ABC)
+if(NOT ABC_FOUND)
+ message(SEND_ERROR "Did not find ABC package")
+endif()
+if(NOT ABC_CONFIG)
+ message(SEND_ERROR "Incorrectly found ABC in MODULE mode, expected to find it with CONFIG mode")
+endif()
+
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG OFF)
+set(CMAKE_PREFIX_PATH)
+set(CMAKE_MODULE_PATH)
+
+############################################################################
+##Test FIND_PACKAGE CMAKE_FIND_PACKAGE_PREFER_CONFIG - Do not recurse
+
+# No CMAKE_PREFIX_PATH
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/PreferConfigRecurse)
+
+# Now prefer config mode
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
+unset(ACME_FOUND)
+unset(ACME_CONFIG)
+
+find_package(ACME)
+if(ACME_FOUND AND ACME_CONFIG)
+ message(SEND_ERROR "Incorrectly found ACME in CONFIG mode, from the MODULE package")
+endif()
+
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG OFF)
+set(CMAKE_MODULE_PATH)
+
+############################################################################
+##Test find_package CMAKE_FIND_PACKAGE_PREFER_CONFIG with module fallback
+
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/PreferConfigOnlyModule)
+
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
+
+find_package(ACME REQUIRED)
+
+if(NOT ACME_FOUND)
+ message(SEND_ERROR "Did not find ACME package")
+endif()
+
+############################################################################
+##Test find_package CMAKE_FIND_PACKAGE_PREFER_CONFIG with NO_MODULE
+
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/PreferConfigOnlyModule)
+
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
+
+find_package(ACME NO_MODULE)
+
+if(ACME_FOUND)
+ message(SEND_ERROR "Should not find ACME package")
+endif()
+
+############################################################################
+##Test find_package CMAKE_FIND_PACKAGE_PREFER_CONFIG with unknown package
+
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
+find_package(DoesNotExist)
diff --git a/Tests/FindPackageTest/Exporter/CMakeLists.txt b/Tests/FindPackageTest/Exporter/CMakeLists.txt
new file mode 100644
index 0000000..d25a2e7
--- /dev/null
+++ b/Tests/FindPackageTest/Exporter/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 2.7.20090831)
+project(CMakeTestExportPackage C)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMakeTestExportPackageConfig.cmake.in
+ ${CMAKE_CURRENT_BINARY_DIR}/CMakeTestExportPackageConfig.cmake
+ @ONLY)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMakeTestExportPackageConfigVersion.cmake.in
+ ${CMAKE_CURRENT_BINARY_DIR}/CMakeTestExportPackageConfigVersion.cmake
+ @ONLY)
+export(PACKAGE CMakeTestExportPackage)
+
+add_executable(dummy dummy.c)
diff --git a/Tests/FindPackageTest/Exporter/CMakeTestExportPackageConfig.cmake.in b/Tests/FindPackageTest/Exporter/CMakeTestExportPackageConfig.cmake.in
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/Exporter/CMakeTestExportPackageConfig.cmake.in
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/Exporter/CMakeTestExportPackageConfigVersion.cmake.in b/Tests/FindPackageTest/Exporter/CMakeTestExportPackageConfigVersion.cmake.in
new file mode 100644
index 0000000..6eac6e6
--- /dev/null
+++ b/Tests/FindPackageTest/Exporter/CMakeTestExportPackageConfigVersion.cmake.in
@@ -0,0 +1,6 @@
+# Test config file.
+set(PACKAGE_VERSION "1.@version@")
+if("${PACKAGE_FIND_VERSION}" VERSION_EQUAL "${PACKAGE_VERSION}")
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ set(PACKAGE_VERSION_EXACT 1)
+endif()
diff --git a/Tests/FindPackageTest/Exporter/dummy.c b/Tests/FindPackageTest/Exporter/dummy.c
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/FindPackageTest/Exporter/dummy.c
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/FindPackageTest/FindLotsOfComponents.cmake b/Tests/FindPackageTest/FindLotsOfComponents.cmake
new file mode 100644
index 0000000..5d959c5
--- /dev/null
+++ b/Tests/FindPackageTest/FindLotsOfComponents.cmake
@@ -0,0 +1,10 @@
+set(LOC_FOO TRUE)
+
+set(LotsOfComponents_AComp_FOUND TRUE)
+set(LotsOfComponents_BComp_FOUND FALSE)
+set(LotsOfComponents_CComp_FOUND TRUE)
+
+include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
+
+find_package_handle_standard_args(LotsOfComponents REQUIRED_VARS LOC_FOO
+ HANDLE_COMPONENTS)
diff --git a/Tests/FindPackageTest/FindPackageHandleStandardArgs.cmake b/Tests/FindPackageTest/FindPackageHandleStandardArgs.cmake
new file mode 100644
index 0000000..7e41c96
--- /dev/null
+++ b/Tests/FindPackageTest/FindPackageHandleStandardArgs.cmake
@@ -0,0 +1 @@
+message(FATAL_ERROR "This file (${CMAKE_CURRENT_LIST_FILE}) must not be included, but FindPackageHandleStandardArgs.cmake from Modules/ instead !")
diff --git a/Tests/FindPackageTest/FindPackageTest.cxx b/Tests/FindPackageTest/FindPackageTest.cxx
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/FindPackageTest/FindPackageTest.cxx
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/FindPackageTest/FindRecursiveA.cmake b/Tests/FindPackageTest/FindRecursiveA.cmake
new file mode 100644
index 0000000..a6d25dc
--- /dev/null
+++ b/Tests/FindPackageTest/FindRecursiveA.cmake
@@ -0,0 +1 @@
+find_package(RecursiveA NO_MODULE)
diff --git a/Tests/FindPackageTest/FindRecursiveB.cmake b/Tests/FindPackageTest/FindRecursiveB.cmake
new file mode 100644
index 0000000..9e28f2c
--- /dev/null
+++ b/Tests/FindPackageTest/FindRecursiveB.cmake
@@ -0,0 +1 @@
+find_package(RecursiveB NAMES zot)
diff --git a/Tests/FindPackageTest/FindRecursiveC.cmake b/Tests/FindPackageTest/FindRecursiveC.cmake
new file mode 100644
index 0000000..cd4400c
--- /dev/null
+++ b/Tests/FindPackageTest/FindRecursiveC.cmake
@@ -0,0 +1 @@
+find_package(RecursiveC NAMES zot)
diff --git a/Tests/FindPackageTest/FindSomePackage.cmake b/Tests/FindPackageTest/FindSomePackage.cmake
new file mode 100644
index 0000000..746c087
--- /dev/null
+++ b/Tests/FindPackageTest/FindSomePackage.cmake
@@ -0,0 +1,5 @@
+set(SOP_FOO TRUE)
+
+include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
+
+find_package_handle_standard_args(SomePackage REQUIRED_VARS SOP_FOO)
diff --git a/Tests/FindPackageTest/FindUpperCasePackage.cmake b/Tests/FindPackageTest/FindUpperCasePackage.cmake
new file mode 100644
index 0000000..5e349da
--- /dev/null
+++ b/Tests/FindPackageTest/FindUpperCasePackage.cmake
@@ -0,0 +1,5 @@
+set(UCP_FOO TRUE)
+
+include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
+
+find_package_handle_standard_args(UpperCasePackage REQUIRED_VARS UCP_FOO)
diff --git a/Tests/FindPackageTest/FindVersionTestA.cmake b/Tests/FindPackageTest/FindVersionTestA.cmake
new file mode 100644
index 0000000..9828593
--- /dev/null
+++ b/Tests/FindPackageTest/FindVersionTestA.cmake
@@ -0,0 +1,18 @@
+if(NOT "${VersionTestA_FIND_VERSION}" STREQUAL "1")
+ message(SEND_ERROR "VersionTestA_FIND_VERSION=${VersionTestA_FIND_VERSION} is not 1")
+endif()
+if(NOT "${VersionTestA_FIND_VERSION_MAJOR}" STREQUAL "1")
+ message(SEND_ERROR "VersionTestA_FIND_VERSION_MAJOR=${VersionTestA_FIND_VERSION_MAJOR} is not 1")
+endif()
+if(NOT "${VersionTestA_FIND_VERSION_MINOR}" STREQUAL "0")
+ message(SEND_ERROR "VersionTestA_FIND_VERSION_MINOR=${VersionTestA_FIND_VERSION_MINOR} is not 0")
+endif()
+if(NOT "${VersionTestA_FIND_VERSION_PATCH}" STREQUAL "0")
+ message(SEND_ERROR "VersionTestA_FIND_VERSION_PATCH=${VersionTestA_FIND_VERSION_PATCH} is not 0")
+endif()
+if(NOT "${VersionTestA_FIND_VERSION_TWEAK}" STREQUAL "0")
+ message(SEND_ERROR "VersionTestA_FIND_VERSION_TWEAK=${VersionTestA_FIND_VERSION_TWEAK} is not 0")
+endif()
+if(NOT "${VersionTestA_FIND_VERSION_COUNT}" STREQUAL "1")
+ message(SEND_ERROR "VersionTestA_FIND_VERSION_COUNT=${VersionTestA_FIND_VERSION_COUNT} is not 1")
+endif()
diff --git a/Tests/FindPackageTest/FindVersionTestB.cmake b/Tests/FindPackageTest/FindVersionTestB.cmake
new file mode 100644
index 0000000..1ebb823
--- /dev/null
+++ b/Tests/FindPackageTest/FindVersionTestB.cmake
@@ -0,0 +1,18 @@
+if(NOT "${VersionTestB_FIND_VERSION}" STREQUAL "1.2")
+ message(SEND_ERROR "VersionTestB_FIND_VERSION=${VersionTestB_FIND_VERSION} is not 1.2")
+endif()
+if(NOT "${VersionTestB_FIND_VERSION_MAJOR}" STREQUAL "1")
+ message(SEND_ERROR "VersionTestB_FIND_VERSION_MAJOR=${VersionTestB_FIND_VERSION_MAJOR} is not 1")
+endif()
+if(NOT "${VersionTestB_FIND_VERSION_MINOR}" STREQUAL "2")
+ message(SEND_ERROR "VersionTestB_FIND_VERSION_MINOR=${VersionTestB_FIND_VERSION_MINOR} is not 2")
+endif()
+if(NOT "${VersionTestB_FIND_VERSION_PATCH}" STREQUAL "0")
+ message(SEND_ERROR "VersionTestB_FIND_VERSION_PATCH=${VersionTestB_FIND_VERSION_PATCH} is not 0")
+endif()
+if(NOT "${VersionTestB_FIND_VERSION_TWEAK}" STREQUAL "0")
+ message(SEND_ERROR "VersionTestB_FIND_VERSION_TWEAK=${VersionTestB_FIND_VERSION_TWEAK} is not 0")
+endif()
+if(NOT "${VersionTestB_FIND_VERSION_COUNT}" STREQUAL "2")
+ message(SEND_ERROR "VersionTestB_FIND_VERSION_COUNT=${VersionTestB_FIND_VERSION_COUNT} is not 2")
+endif()
diff --git a/Tests/FindPackageTest/FindVersionTestC.cmake b/Tests/FindPackageTest/FindVersionTestC.cmake
new file mode 100644
index 0000000..450c2e9
--- /dev/null
+++ b/Tests/FindPackageTest/FindVersionTestC.cmake
@@ -0,0 +1,18 @@
+if(NOT "${VersionTestC_FIND_VERSION}" STREQUAL "1.2.3")
+ message(SEND_ERROR "VersionTestC_FIND_VERSION=${VersionTestC_FIND_VERSION} is not 1.2.3")
+endif()
+if(NOT "${VersionTestC_FIND_VERSION_MAJOR}" STREQUAL "1")
+ message(SEND_ERROR "VersionTestC_FIND_VERSION_MAJOR=${VersionTestC_FIND_VERSION_MAJOR} is not 1")
+endif()
+if(NOT "${VersionTestC_FIND_VERSION_MINOR}" STREQUAL "2")
+ message(SEND_ERROR "VersionTestC_FIND_VERSION_MINOR=${VersionTestC_FIND_VERSION_MINOR} is not 2")
+endif()
+if(NOT "${VersionTestC_FIND_VERSION_PATCH}" STREQUAL "3")
+ message(SEND_ERROR "VersionTestC_FIND_VERSION_PATCH=${VersionTestC_FIND_VERSION_PATCH} is not 3")
+endif()
+if(NOT "${VersionTestC_FIND_VERSION_TWEAK}" STREQUAL "0")
+ message(SEND_ERROR "VersionTestC_FIND_VERSION_TWEAK=${VersionTestC_FIND_VERSION_TWEAK} is not 0")
+endif()
+if(NOT "${VersionTestC_FIND_VERSION_COUNT}" STREQUAL "3")
+ message(SEND_ERROR "VersionTestC_FIND_VERSION_COUNT=${VersionTestC_FIND_VERSION_COUNT} is not 3")
+endif()
diff --git a/Tests/FindPackageTest/FindVersionTestD.cmake b/Tests/FindPackageTest/FindVersionTestD.cmake
new file mode 100644
index 0000000..9f2db72
--- /dev/null
+++ b/Tests/FindPackageTest/FindVersionTestD.cmake
@@ -0,0 +1,18 @@
+if(NOT "${VersionTestD_FIND_VERSION}" STREQUAL "1.2.3.4")
+ message(SEND_ERROR "VersionTestD_FIND_VERSION=${VersionTestD_FIND_VERSION} is not 1.2.3.4")
+endif()
+if(NOT "${VersionTestD_FIND_VERSION_MAJOR}" STREQUAL "1")
+ message(SEND_ERROR "VersionTestD_FIND_VERSION_MAJOR=${VersionTestD_FIND_VERSION_MAJOR} is not 1")
+endif()
+if(NOT "${VersionTestD_FIND_VERSION_MINOR}" STREQUAL "2")
+ message(SEND_ERROR "VersionTestD_FIND_VERSION_MINOR=${VersionTestD_FIND_VERSION_MINOR} is not 2")
+endif()
+if(NOT "${VersionTestD_FIND_VERSION_PATCH}" STREQUAL "3")
+ message(SEND_ERROR "VersionTestD_FIND_VERSION_PATCH=${VersionTestD_FIND_VERSION_PATCH} is not 3")
+endif()
+if(NOT "${VersionTestD_FIND_VERSION_TWEAK}" STREQUAL "4")
+ message(SEND_ERROR "VersionTestD_FIND_VERSION_TWEAK=${VersionTestD_FIND_VERSION_TWEAK} is not 4")
+endif()
+if(NOT "${VersionTestD_FIND_VERSION_COUNT}" STREQUAL "4")
+ message(SEND_ERROR "VersionTestD_FIND_VERSION_COUNT=${VersionTestD_FIND_VERSION_COUNT} is not 4")
+endif()
diff --git a/Tests/FindPackageTest/PreferConfig/ABCConfig.cmake b/Tests/FindPackageTest/PreferConfig/ABCConfig.cmake
new file mode 100644
index 0000000..281a5cd
--- /dev/null
+++ b/Tests/FindPackageTest/PreferConfig/ABCConfig.cmake
@@ -0,0 +1 @@
+set(ABC_FOUND TRUE)
diff --git a/Tests/FindPackageTest/PreferConfig/FindABC.cmake b/Tests/FindPackageTest/PreferConfig/FindABC.cmake
new file mode 100644
index 0000000..281a5cd
--- /dev/null
+++ b/Tests/FindPackageTest/PreferConfig/FindABC.cmake
@@ -0,0 +1 @@
+set(ABC_FOUND TRUE)
diff --git a/Tests/FindPackageTest/PreferConfigOnlyModule/FindACME.cmake b/Tests/FindPackageTest/PreferConfigOnlyModule/FindACME.cmake
new file mode 100644
index 0000000..7a4e1b3
--- /dev/null
+++ b/Tests/FindPackageTest/PreferConfigOnlyModule/FindACME.cmake
@@ -0,0 +1 @@
+set(ACME_FOUND TRUE)
diff --git a/Tests/FindPackageTest/PreferConfigRecurse/ACMEConfig.cmake b/Tests/FindPackageTest/PreferConfigRecurse/ACMEConfig.cmake
new file mode 100644
index 0000000..7a4e1b3
--- /dev/null
+++ b/Tests/FindPackageTest/PreferConfigRecurse/ACMEConfig.cmake
@@ -0,0 +1 @@
+set(ACME_FOUND TRUE)
diff --git a/Tests/FindPackageTest/PreferConfigRecurse/FindACME.cmake b/Tests/FindPackageTest/PreferConfigRecurse/FindACME.cmake
new file mode 100644
index 0000000..9bdc7db
--- /dev/null
+++ b/Tests/FindPackageTest/PreferConfigRecurse/FindACME.cmake
@@ -0,0 +1 @@
+find_package(ACME NO_MODULE)
diff --git a/Tests/FindPackageTest/RelocatableConfig.cmake.in b/Tests/FindPackageTest/RelocatableConfig.cmake.in
new file mode 100644
index 0000000..4a4b4e9
--- /dev/null
+++ b/Tests/FindPackageTest/RelocatableConfig.cmake.in
@@ -0,0 +1,11 @@
+@PACKAGE_INIT@
+
+set(RELOC_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
+set(RELOC_SHARE_DIR "@PACKAGE_SHARE_INSTALL_DIR@")
+set_and_check(RELOC_BUILD_DIR "@PACKAGE_CURRENT_BUILD_DIR@")
+
+set(Relocatable_AComp_FOUND TRUE)
+set(Relocatable_BComp_FOUND FALSE)
+set(Relocatable_CComp_FOUND FALSE)
+
+check_required_components(Relocatable)
diff --git a/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfig.cmake b/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfig.cmake
new file mode 100644
index 0000000..c1f2088
--- /dev/null
+++ b/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfig.cmake
@@ -0,0 +1,2 @@
+set(SORT_LIB_VERSION 3.1.1)
+message("SortLib 3.1.1 config reached")
diff --git a/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfigVersion.cmake b/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfigVersion.cmake
new file mode 100644
index 0000000..fa927c7
--- /dev/null
+++ b/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfigVersion.cmake
@@ -0,0 +1,9 @@
+set(PACKAGE_VERSION 3.1.1)
+if(PACKAGE_FIND_VERSION_MAJOR EQUAL 3)
+ if(PACKAGE_FIND_VERSION_MINOR EQUAL 1)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if(PACKAGE_FIND_VERSION_PATCH EQUAL 1)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+ endif()
+endif()
diff --git a/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfig.cmake b/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfig.cmake
new file mode 100644
index 0000000..3f3f659
--- /dev/null
+++ b/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfig.cmake
@@ -0,0 +1,2 @@
+set(SORT_LIB_VERSION 3.10.1)
+message("SortLib 3.10.1 config reached")
diff --git a/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfigVersion.cmake b/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfigVersion.cmake
new file mode 100644
index 0000000..6f44c2d
--- /dev/null
+++ b/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfigVersion.cmake
@@ -0,0 +1,9 @@
+set(PACKAGE_VERSION 3.10.1)
+if(PACKAGE_FIND_VERSION_MAJOR EQUAL 3)
+ if(PACKAGE_FIND_VERSION_MINOR EQUAL 10)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if(PACKAGE_FIND_VERSION_PATCH EQUAL 1)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+ endif()
+endif()
diff --git a/Tests/FindPackageTest/SystemPackage/CMakeTestSystemPackageConfig.cmake b/Tests/FindPackageTest/SystemPackage/CMakeTestSystemPackageConfig.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/SystemPackage/CMakeTestSystemPackageConfig.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/TApp.app/Contents/Resources/TAppConfig.cmake b/Tests/FindPackageTest/TApp.app/Contents/Resources/TAppConfig.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/TApp.app/Contents/Resources/TAppConfig.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/TApp.app/Contents/Resources/cmake/tapp-config.cmake b/Tests/FindPackageTest/TApp.app/Contents/Resources/cmake/tapp-config.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/TApp.app/Contents/Resources/cmake/tapp-config.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/TFramework.framework/Versions/A/Resources/CMake/TFrameworkConfig.cmake b/Tests/FindPackageTest/TFramework.framework/Versions/A/Resources/CMake/TFrameworkConfig.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/TFramework.framework/Versions/A/Resources/CMake/TFrameworkConfig.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/TFramework.framework/Versions/A/Resources/tframework-config.cmake b/Tests/FindPackageTest/TFramework.framework/Versions/A/Resources/tframework-config.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/TFramework.framework/Versions/A/Resources/tframework-config.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/cmake/SetFoundFALSEConfig.cmake b/Tests/FindPackageTest/cmake/SetFoundFALSEConfig.cmake
new file mode 100644
index 0000000..ae6bd14
--- /dev/null
+++ b/Tests/FindPackageTest/cmake/SetFoundFALSEConfig.cmake
@@ -0,0 +1 @@
+set(SetFoundFALSE_FOUND FALSE)
diff --git a/Tests/FindPackageTest/cmake/SetFoundResolvedConfig.cmake b/Tests/FindPackageTest/cmake/SetFoundResolvedConfig.cmake
new file mode 100644
index 0000000..b2cf87c
--- /dev/null
+++ b/Tests/FindPackageTest/cmake/SetFoundResolvedConfig.cmake
@@ -0,0 +1 @@
+set(SetFoundResolved_DIR "${CMAKE_CURRENT_LIST_DIR}")
diff --git a/Tests/FindPackageTest/cmake/SetFoundTRUEConfig.cmake b/Tests/FindPackageTest/cmake/SetFoundTRUEConfig.cmake
new file mode 100644
index 0000000..19d0711
--- /dev/null
+++ b/Tests/FindPackageTest/cmake/SetFoundTRUEConfig.cmake
@@ -0,0 +1 @@
+set(SetFoundTRUE_FOUND TRUE)
diff --git a/Tests/FindPackageTest/include/foo.h b/Tests/FindPackageTest/include/foo.h
new file mode 100644
index 0000000..2392aee
--- /dev/null
+++ b/Tests/FindPackageTest/include/foo.h
@@ -0,0 +1 @@
+/* empty header file */
diff --git a/Tests/FindPackageTest/lib/Bar/BarConfig.cmake b/Tests/FindPackageTest/lib/Bar/BarConfig.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/Bar/BarConfig.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/Bar/cmake/bar-config.cmake b/Tests/FindPackageTest/lib/Bar/cmake/bar-config.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/Bar/cmake/bar-config.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/Blub/BlubConfig.cmake b/Tests/FindPackageTest/lib/Blub/BlubConfig.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/Blub/BlubConfig.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/RecursiveA/recursivea-config.cmake b/Tests/FindPackageTest/lib/RecursiveA/recursivea-config.cmake
new file mode 100644
index 0000000..eff4d4f
--- /dev/null
+++ b/Tests/FindPackageTest/lib/RecursiveA/recursivea-config.cmake
@@ -0,0 +1,4 @@
+# Test config file.
+if(NOT "${RecursiveA_FIND_COMPONENTS}" STREQUAL "A")
+ message(FATAL_ERROR "find_package(RecursiveA NO_MODULE) did not forward components")
+endif()
diff --git a/Tests/FindPackageTest/lib/TApp/TAppConfig.cmake b/Tests/FindPackageTest/lib/TApp/TAppConfig.cmake
new file mode 100644
index 0000000..5ba8d55
--- /dev/null
+++ b/Tests/FindPackageTest/lib/TApp/TAppConfig.cmake
@@ -0,0 +1,2 @@
+# Test config file that should not be found.
+message("Package TApp found non-bundle first!")
diff --git a/Tests/FindPackageTest/lib/arch/Bar/BarConfig.cmake b/Tests/FindPackageTest/lib/arch/Bar/BarConfig.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/arch/Bar/BarConfig.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/arch/cmake/zot-4.0/zot-config-version.cmake b/Tests/FindPackageTest/lib/arch/cmake/zot-4.0/zot-config-version.cmake
new file mode 100644
index 0000000..822b449
--- /dev/null
+++ b/Tests/FindPackageTest/lib/arch/cmake/zot-4.0/zot-config-version.cmake
@@ -0,0 +1,7 @@
+set(PACKAGE_VERSION 4.0)
+if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 4)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 0)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
diff --git a/Tests/FindPackageTest/lib/arch/cmake/zot-4.0/zot-config.cmake b/Tests/FindPackageTest/lib/arch/cmake/zot-4.0/zot-config.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/arch/cmake/zot-4.0/zot-config.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/arch/foo-1.2/CMake/FooConfig.cmake b/Tests/FindPackageTest/lib/arch/foo-1.2/CMake/FooConfig.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/arch/foo-1.2/CMake/FooConfig.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/arch/zot-3.1/zot-config-version.cmake b/Tests/FindPackageTest/lib/arch/zot-3.1/zot-config-version.cmake
new file mode 100644
index 0000000..31573b9
--- /dev/null
+++ b/Tests/FindPackageTest/lib/arch/zot-3.1/zot-config-version.cmake
@@ -0,0 +1,7 @@
+set(PACKAGE_VERSION 3.1)
+if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 3)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 1)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
diff --git a/Tests/FindPackageTest/lib/arch/zot-3.1/zot-config.cmake b/Tests/FindPackageTest/lib/arch/zot-3.1/zot-config.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/arch/zot-3.1/zot-config.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/cmake/zot-3.1/zot-config-version.cmake b/Tests/FindPackageTest/lib/cmake/zot-3.1/zot-config-version.cmake
new file mode 100644
index 0000000..e3e17de
--- /dev/null
+++ b/Tests/FindPackageTest/lib/cmake/zot-3.1/zot-config-version.cmake
@@ -0,0 +1,4 @@
+# Claim to be any version to test that CMAKE_IGNORE_PATH hides us.
+set(PACKAGE_VERSION 3.1)
+set(PACKAGE_VERSION_COMPATIBLE 1)
+set(PACKAGE_VERSION_EXACT 1)
diff --git a/Tests/FindPackageTest/lib/cmake/zot-3.1/zot-config.cmake b/Tests/FindPackageTest/lib/cmake/zot-3.1/zot-config.cmake
new file mode 100644
index 0000000..2fbd525
--- /dev/null
+++ b/Tests/FindPackageTest/lib/cmake/zot-3.1/zot-config.cmake
@@ -0,0 +1,2 @@
+# Test config file.
+message(WARNING "CMAKE_IGNORE_PATH failed to ignore this file!")
diff --git a/Tests/FindPackageTest/lib/cmake/zot-4.0/zot-config-version.cmake b/Tests/FindPackageTest/lib/cmake/zot-4.0/zot-config-version.cmake
new file mode 100644
index 0000000..bcefcd7
--- /dev/null
+++ b/Tests/FindPackageTest/lib/cmake/zot-4.0/zot-config-version.cmake
@@ -0,0 +1,8 @@
+set(PACKAGE_VERSION 4.0)
+if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 4)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 0)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
+
diff --git a/Tests/FindPackageTest/lib/cmake/zot-4.0/zot-config.cmake b/Tests/FindPackageTest/lib/cmake/zot-4.0/zot-config.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/cmake/zot-4.0/zot-config.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/foo-1.2/CMake/FooConfig.cmake b/Tests/FindPackageTest/lib/foo-1.2/CMake/FooConfig.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/foo-1.2/CMake/FooConfig.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/foo-1.2/foo-config.cmake b/Tests/FindPackageTest/lib/foo-1.2/foo-config.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/foo-1.2/foo-config.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/suffix/test/SuffixTestConfig.cmake b/Tests/FindPackageTest/lib/suffix/test/SuffixTestConfig.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/suffix/test/SuffixTestConfig.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/suffix/test/SuffixTestConfigVersion.cmake b/Tests/FindPackageTest/lib/suffix/test/SuffixTestConfigVersion.cmake
new file mode 100644
index 0000000..b37bc8e
--- /dev/null
+++ b/Tests/FindPackageTest/lib/suffix/test/SuffixTestConfigVersion.cmake
@@ -0,0 +1,7 @@
+set(PACKAGE_VERSION 1.2)
+if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 1)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 2)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
diff --git a/Tests/FindPackageTest/lib/zot-1.0/zot-config.cmake b/Tests/FindPackageTest/lib/zot-1.0/zot-config.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/zot-1.0/zot-config.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/zot-2.0/zot-config-version.cmake b/Tests/FindPackageTest/lib/zot-2.0/zot-config-version.cmake
new file mode 100644
index 0000000..db3a8a4
--- /dev/null
+++ b/Tests/FindPackageTest/lib/zot-2.0/zot-config-version.cmake
@@ -0,0 +1,5 @@
+set(PACKAGE_VERSION 2.0)
+if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 2)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+endif()
+
diff --git a/Tests/FindPackageTest/lib/zot-2.0/zot-config.cmake b/Tests/FindPackageTest/lib/zot-2.0/zot-config.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/zot-2.0/zot-config.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/zot-3.0/zot-config-version.cmake b/Tests/FindPackageTest/lib/zot-3.0/zot-config-version.cmake
new file mode 100644
index 0000000..dd9c939
--- /dev/null
+++ b/Tests/FindPackageTest/lib/zot-3.0/zot-config-version.cmake
@@ -0,0 +1,5 @@
+set(PACKAGE_VERSION 3.0)
+if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 3)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+endif()
+
diff --git a/Tests/FindPackageTest/lib/zot-3.0/zot-config.cmake b/Tests/FindPackageTest/lib/zot-3.0/zot-config.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/zot-3.0/zot-config.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/zot-3.1/zot-config-version.cmake b/Tests/FindPackageTest/lib/zot-3.1/zot-config-version.cmake
new file mode 100644
index 0000000..8fa767e
--- /dev/null
+++ b/Tests/FindPackageTest/lib/zot-3.1/zot-config-version.cmake
@@ -0,0 +1,8 @@
+set(PACKAGE_VERSION 3.1)
+if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 3)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 1)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
+
diff --git a/Tests/FindPackageTest/lib/zot-3.1/zot-config.cmake b/Tests/FindPackageTest/lib/zot-3.1/zot-config.cmake
new file mode 100644
index 0000000..deffa57
--- /dev/null
+++ b/Tests/FindPackageTest/lib/zot-3.1/zot-config.cmake
@@ -0,0 +1 @@
+# Test config file.
diff --git a/Tests/FindPackageTest/lib/zot/zot-config-version.cmake b/Tests/FindPackageTest/lib/zot/zot-config-version.cmake
new file mode 100644
index 0000000..430f009
--- /dev/null
+++ b/Tests/FindPackageTest/lib/zot/zot-config-version.cmake
@@ -0,0 +1,10 @@
+# This version should never, ever be used.
+set(PACKAGE_VERSION_UNSUITABLE 1)
+set(PACKAGE_VERSION 3.1)
+if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 3)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 1)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+endif()
+
diff --git a/Tests/FindPackageTest/lib/zot/zot-config.cmake b/Tests/FindPackageTest/lib/zot/zot-config.cmake
new file mode 100644
index 0000000..9168183
--- /dev/null
+++ b/Tests/FindPackageTest/lib/zot/zot-config.cmake
@@ -0,0 +1,2 @@
+# Test config file that is unsuitable.
+message(FATAL_ERROR "Unsuitable version of zot was found")
diff --git a/Tests/FindPatch/CMakeLists.txt b/Tests/FindPatch/CMakeLists.txt
new file mode 100644
index 0000000..541f5bd
--- /dev/null
+++ b/Tests/FindPatch/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_test(NAME FindPatch.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPatch/Test"
+ "${CMake_BINARY_DIR}/Tests/FindPatch/Test"
+ ${build_generator_args}
+ --build-options ${build_options}
+)
diff --git a/Tests/FindPatch/Test/CMakeLists.txt b/Tests/FindPatch/Test/CMakeLists.txt
new file mode 100644
index 0000000..66c672c
--- /dev/null
+++ b/Tests/FindPatch/Test/CMakeLists.txt
@@ -0,0 +1,77 @@
+cmake_minimum_required(VERSION 3.8)
+project(TestFindPatch VERSION 1.0 LANGUAGES NONE)
+
+macro(_check)
+ if(NOT EXISTS "${Patch_EXECUTABLE}")
+ message(FATAL_ERROR "Failed to lookup Patch_EXECUTABLE [${Patch_EXECUTABLE}]")
+ endif()
+
+ if(NOT DEFINED PATCH_FOUND)
+ message(FATAL_ERROR "Variable PATCH_FOUND is not defined")
+ endif()
+
+ # Is import target available ?
+ if(NOT TARGET Patch::patch)
+ message(FATAL_ERROR "Target Patch::patch is not defined")
+ endif()
+
+ # Check Patch::patch imported location
+ get_property(_imported_location TARGET Patch::patch PROPERTY IMPORTED_LOCATION)
+ if(NOT "${Patch_EXECUTABLE}" STREQUAL "${_imported_location}")
+ message(FATAL_ERROR "\
+Patch_EXECUTABLE is expected to be equal to Patch::patch IMPORTED_LOCATION
+ Patch_EXECUTABLE [${Patch_EXECUTABLE}]
+ Patch::patch IMPORTED_LOCATION [${_imported_location}]
+")
+ endif()
+
+endmacro()
+
+find_package(Patch REQUIRED)
+_check()
+
+# Calling twice should not fail
+find_package(Patch REQUIRED)
+_check()
+
+add_custom_target(TestPatchVersion ALL
+ COMMAND ${Patch_EXECUTABLE} -v
+ )
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/QUOTE.txt.baseline"
+[=[Because it's there.
+- George Mallory, 1923
+]=]
+)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/QUOTE.txt" "Because it's there.\n")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/quote-add-author.patch"
+[=[diff --git a/QUOTE.txt b/QUOTE.txt
+index b36681d..68059b3 100644
+--- a/QUOTE.txt
++++ b/QUOTE.txt
+@@ -1 +1,2 @@
+ Because it's there.
++- George Mallory
+]=]
+)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/quote-add-date.patch"
+[=[diff --git a/QUOTE.txt b/QUOTE.txt
+index 68059b3..c6f30c2 100644
+--- a/QUOTE.txt
++++ b/QUOTE.txt
+@@ -1,2 +1,2 @@
+ Because it's there.
+-- George Mallory
++- George Mallory, 1923
+]=]
+)
+
+add_custom_target(TestPatch ALL
+ COMMAND ${Patch_EXECUTABLE} -p1 -i quote-add-author.patch --binary
+ COMMAND Patch::patch -p1 -i quote-add-date.patch --binary
+ COMMAND ${CMAKE_COMMAND} -E compare_files QUOTE.txt QUOTE.txt.baseline
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ )
diff --git a/Tests/FindPostgreSQL/CMakeLists.txt b/Tests/FindPostgreSQL/CMakeLists.txt
new file mode 100644
index 0000000..50151ee
--- /dev/null
+++ b/Tests/FindPostgreSQL/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindPostgreSQL.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPostgreSQL/Test"
+ "${CMake_BINARY_DIR}/Tests/FindPostgreSQL/Test"
+ ${build_generator_args}
+ --build-project TestFindPostgreSQL
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindPostgreSQL/Test/CMakeLists.txt b/Tests/FindPostgreSQL/Test/CMakeLists.txt
new file mode 100644
index 0000000..1bc5c56
--- /dev/null
+++ b/Tests/FindPostgreSQL/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindPostgreSQL C)
+include(CTest)
+
+find_package(PostgreSQL REQUIRED COMPONENTS Server)
+
+add_definitions(-DCMAKE_EXPECTED_POSTGRESQL_VERSION="${PostgreSQL_VERSION_STRING}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt PostgreSQL::PostgreSQL)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${PostgreSQL_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${PostgreSQL_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindPostgreSQL/Test/main.c b/Tests/FindPostgreSQL/Test/main.c
new file mode 100644
index 0000000..a63377a
--- /dev/null
+++ b/Tests/FindPostgreSQL/Test/main.c
@@ -0,0 +1,24 @@
+#include <libpq-fe.h>
+#include <stdio.h>
+#include <string.h>
+
+int main()
+{
+ int version = PQlibVersion();
+ char version_string[100];
+ // 9.x and older encoding.
+ if (version < 100000) {
+ int major = version / 10000;
+ int minor = version % 10000 / 100;
+ int patch = version % 100;
+ snprintf(version_string, sizeof(version_string), "%d.%d.%d", major, minor,
+ patch);
+ } else {
+ int major = version / 10000;
+ int minor = version % 10000;
+ snprintf(version_string, sizeof(version_string), "%d.%d", major, minor);
+ }
+ printf("Found PostgreSQL version %s, expected version %s\n", version_string,
+ CMAKE_EXPECTED_POSTGRESQL_VERSION);
+ return strcmp(version_string, CMAKE_EXPECTED_POSTGRESQL_VERSION);
+}
diff --git a/Tests/FindProtobuf/CMakeLists.txt b/Tests/FindProtobuf/CMakeLists.txt
new file mode 100644
index 0000000..1cdb2ae
--- /dev/null
+++ b/Tests/FindProtobuf/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindProtobuf.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindProtobuf/Test"
+ "${CMake_BINARY_DIR}/Tests/FindProtobuf/Test"
+ ${build_generator_args}
+ --build-project TestFindProtobuf
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindProtobuf/Test/CMakeLists.txt b/Tests/FindProtobuf/Test/CMakeLists.txt
new file mode 100644
index 0000000..fc6b37e
--- /dev/null
+++ b/Tests/FindProtobuf/Test/CMakeLists.txt
@@ -0,0 +1,54 @@
+cmake_minimum_required(VERSION 3.8)
+project(TestFindProtobuf CXX)
+include(CTest)
+
+find_package(Protobuf REQUIRED)
+
+add_executable(test_tgt main.cxx)
+target_link_libraries(test_tgt protobuf::libprotobuf)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.cxx)
+target_include_directories(test_var PRIVATE ${Protobuf_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${Protobuf_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
+
+add_executable(test_tgt_lite main.cxx)
+target_link_libraries(test_tgt_lite protobuf::libprotobuf-lite)
+add_test(NAME test_tgt_lite COMMAND test_tgt_lite)
+
+add_executable(test_var_lite main.cxx)
+target_include_directories(test_var_lite PRIVATE ${Protobuf_INCLUDE_DIRS})
+target_link_libraries(test_var_lite PRIVATE ${Protobuf_LITE_LIBRARIES})
+add_test(NAME test_var_lite COMMAND test_var_lite)
+
+add_executable(test_tgt_protoc main-protoc.cxx)
+target_link_libraries(test_tgt_protoc protobuf::libprotoc)
+add_test(NAME test_tgt_protoc COMMAND test_tgt_protoc)
+
+add_executable(test_var_protoc main-protoc.cxx)
+target_include_directories(test_var_protoc PRIVATE ${Protobuf_INCLUDE_DIRS})
+target_link_libraries(test_var_protoc PRIVATE ${Protobuf_PROTOC_LIBRARIES})
+target_compile_features(test_var_protoc PRIVATE cxx_std_11)
+add_test(NAME test_var_protoc COMMAND test_var_protoc)
+
+add_test(NAME test_tgt_protoc_version COMMAND protobuf::protoc --version)
+
+set(Protobuf_IMPORT_DIRS ${Protobuf_INCLUDE_DIRS})
+PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HEADER msgs/example.proto)
+PROTOBUF_GENERATE_CPP(DESC_PROTO_SRC DESC_PROTO_HEADER DESCRIPTORS DESC_PROTO_DESC msgs/example_desc.proto)
+add_library(msgs ${PROTO_SRC} ${PROTO_HEADER})
+target_compile_features(msgs PRIVATE cxx_std_11)
+
+add_executable(test_generate main-generate.cxx ${PROTO_SRC})
+target_include_directories(test_generate PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+target_link_libraries(test_generate msgs ${Protobuf_LIBRARIES})
+target_compile_features(test_generate PRIVATE cxx_std_11)
+add_test(NAME test_generate COMMAND test_generate)
+
+add_executable(test_desc main-desc.cxx ${DESC_PROTO_SRC})
+target_compile_features(test_desc PRIVATE cxx_std_11)
+target_include_directories(test_desc PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+target_link_libraries(test_desc msgs ${Protobuf_LIBRARIES})
+target_compile_features(test_desc PRIVATE cxx_std_11)
+add_test(NAME test_desc COMMAND test_desc ${DESC_PROTO_DESC})
diff --git a/Tests/FindProtobuf/Test/main-desc.cxx b/Tests/FindProtobuf/Test/main-desc.cxx
new file mode 100644
index 0000000..dc768ab
--- /dev/null
+++ b/Tests/FindProtobuf/Test/main-desc.cxx
@@ -0,0 +1,58 @@
+#include <fstream>
+#include <google/protobuf/descriptor.pb.h>
+#include <iostream>
+#include <string>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/text_format.h>
+
+int main(int argc, char* argv[])
+{
+ std::ifstream fs;
+ fs.open(argv[1], std::ifstream::in);
+ google::protobuf::FileDescriptorSet file_descriptor_set;
+ file_descriptor_set.ParseFromIstream(&fs);
+
+ const google::protobuf::DescriptorPool* compiled_pool =
+ google::protobuf::DescriptorPool::generated_pool();
+
+ if (compiled_pool == NULL) {
+ std::cerr << "compiled pool is NULL." << std::endl;
+ return 1;
+ }
+
+ google::protobuf::DescriptorPool pool(compiled_pool);
+ google::protobuf::DynamicMessageFactory dynamic_message_factory(&pool);
+
+ for (const google::protobuf::FileDescriptorProto& file_descriptor_proto :
+ file_descriptor_set.file()) {
+ const google::protobuf::FileDescriptor* file_descriptor =
+ pool.BuildFile(file_descriptor_proto);
+ if (file_descriptor == NULL) {
+ continue;
+ }
+
+ const google::protobuf::Descriptor* descriptor =
+ pool.FindMessageTypeByName("example.msgs.ExampleDesc");
+
+ if (descriptor == NULL) {
+ continue;
+ }
+
+ google::protobuf::Message* msg =
+ dynamic_message_factory.GetPrototype(descriptor)->New();
+ std::string data = "data: 1";
+ bool success = google::protobuf::TextFormat::ParseFromString(data, msg);
+
+ if (success) {
+ return 0;
+ } else {
+ std::cerr << "Failed to parse message." << std::endl;
+ return 2;
+ }
+ }
+
+ std::cerr << "No matching message found." << std::endl;
+ return 3;
+}
diff --git a/Tests/FindProtobuf/Test/main-generate.cxx b/Tests/FindProtobuf/Test/main-generate.cxx
new file mode 100644
index 0000000..ca33a68
--- /dev/null
+++ b/Tests/FindProtobuf/Test/main-generate.cxx
@@ -0,0 +1,8 @@
+#include <example.pb.h>
+
+int main()
+{
+ example::msgs::Example msg;
+
+ return 0;
+}
diff --git a/Tests/FindProtobuf/Test/main-protoc.cxx b/Tests/FindProtobuf/Test/main-protoc.cxx
new file mode 100644
index 0000000..64e5ada
--- /dev/null
+++ b/Tests/FindProtobuf/Test/main-protoc.cxx
@@ -0,0 +1,8 @@
+#include <google/protobuf/compiler/command_line_interface.h>
+
+int main()
+{
+ google::protobuf::compiler::CommandLineInterface();
+
+ return 0;
+}
diff --git a/Tests/FindProtobuf/Test/main.cxx b/Tests/FindProtobuf/Test/main.cxx
new file mode 100644
index 0000000..87d5c12
--- /dev/null
+++ b/Tests/FindProtobuf/Test/main.cxx
@@ -0,0 +1,8 @@
+#include <google/protobuf/stubs/common.h>
+
+int main()
+{
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ return 0;
+}
diff --git a/Tests/FindProtobuf/Test/msgs/example.proto b/Tests/FindProtobuf/Test/msgs/example.proto
new file mode 100644
index 0000000..d27262e
--- /dev/null
+++ b/Tests/FindProtobuf/Test/msgs/example.proto
@@ -0,0 +1,6 @@
+syntax = "proto2";
+package example.msgs;
+
+message Example {
+ required int32 data = 1;
+}
diff --git a/Tests/FindProtobuf/Test/msgs/example_desc.proto b/Tests/FindProtobuf/Test/msgs/example_desc.proto
new file mode 100644
index 0000000..4454473
--- /dev/null
+++ b/Tests/FindProtobuf/Test/msgs/example_desc.proto
@@ -0,0 +1,10 @@
+syntax = "proto2";
+package example.msgs;
+
+import "google/protobuf/descriptor.proto";
+
+message ExampleDesc {
+ required int32 data = 1;
+
+ optional google.protobuf.FileDescriptorSet desc = 2;
+}
diff --git a/Tests/FindPython/ArtifactsInteractive/CMakeLists.txt b/Tests/FindPython/ArtifactsInteractive/CMakeLists.txt
new file mode 100644
index 0000000..524be92
--- /dev/null
+++ b/Tests/FindPython/ArtifactsInteractive/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestArtifactsInteractive LANGUAGES C)
+
+set (components Interpreter Development)
+if (CMake_TEST_FindPython_NumPy)
+ list (APPEND components NumPy)
+endif()
+
+find_package(Python3 REQUIRED COMPONENTS ${components})
+
+if (Python3_ARTIFACTS_INTERACTIVE)
+ if (NOT DEFINED CACHE{Python3_EXECUTABLE}
+ OR NOT DEFINED CACHE{Python3_LIBRARY} OR NOT DEFINED CACHE{Python3_INCLUDE_DIR}
+ OR (CMake_TEST_FindPython_NumPy AND NOT DEFINED CACHE{Python3_NumPy_INCLUDE_DIR}))
+ message (FATAL_ERROR "Python3_ARTIFACTS_INTERACTIVE=ON Failed.")
+ endif()
+else()
+ if (DEFINED CACHE{Python3_EXECUTABLE}
+ OR DEFINED CACHE{Python3_LIBRARY} OR DEFINED CACHE{Python3_INCLUDE_DIR}
+ OR (CMake_TEST_FindPython_NumPy AND DEFINED CACHE{Python3_NumPy_INCLUDE_DIR}))
+ message (FATAL_ERROR "Python3_ARTIFACTS_INTERACTIVE=OFF Failed.")
+ endif()
+endif()
diff --git a/Tests/FindPython/CMakeLists.txt b/Tests/FindPython/CMakeLists.txt
new file mode 100644
index 0000000..520ba9e
--- /dev/null
+++ b/Tests/FindPython/CMakeLists.txt
@@ -0,0 +1,716 @@
+if(CMake_TEST_FindPython)
+ add_test(NAME FindPython.Python2.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python2"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python2.LOCATION"
+ ${build_generator_args}
+ --build-project TestPython2
+ --build-options ${build_options} -DPython2_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python2.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python2"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python2.VERSION"
+ ${build_generator_args}
+ --build-project TestPython2
+ --build-options ${build_options} -DPython2_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ add_test(NAME FindPython.Python2.Development.Module COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python2Module"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python2Module"
+ ${build_generator_args}
+ --build-project TestPython2Module
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ add_test(NAME FindPython.Python2Fail COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python2Fail"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python2Fail"
+ ${build_generator_args}
+ --build-project TestPython2Fail
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ set_tests_properties(FindPython.Python2Fail PROPERTIES
+ PASS_REGULAR_EXPRESSION "Could NOT find Python2 \\(missing: foobar\\)")
+
+ add_test(NAME FindPython.Python3.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python3"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python3.LOCATION"
+ ${build_generator_args}
+ --build-project TestPython3
+ --build-options ${build_options} -DPython3_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python3.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python3"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python3.VERSION"
+ ${build_generator_args}
+ --build-project TestPython3
+ --build-options ${build_options} -DPython3_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ add_test(NAME FindPython.Python3.Development.Module COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python3Module"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python3Module"
+ ${build_generator_args}
+ --build-project TestPython3Module
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ add_test(NAME FindPython.Python3Fail COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python3Fail"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python3Fail"
+ ${build_generator_args}
+ --build-project TestPython3Fail
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ set_tests_properties(FindPython.Python3Fail PROPERTIES
+ PASS_REGULAR_EXPRESSION "Could NOT find Python3 \\(missing: foobar\\)")
+
+ add_test(NAME FindPython.Python.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python.LOCATION"
+ ${build_generator_args}
+ --build-project TestPython
+ --build-options ${build_options} -DPython_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python.VERSION"
+ ${build_generator_args}
+ --build-project TestPython
+ --build-options ${build_options} -DPython_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python.V2.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.LOCATION"
+ ${build_generator_args}
+ --build-project TestPython
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python.V2.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.VERSION"
+ ${build_generator_args}
+ --build-project TestPython
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python.V3.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python.V3.LOCATION"
+ ${build_generator_args}
+ --build-project TestPython
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=3 -DPython_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python.V3.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python.V3.VERSION"
+ ${build_generator_args}
+ --build-project TestPython
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=3 -DPython_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ add_test(NAME FindPython.Python2.ExactVersion.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python2.ExactVersion.LOCATION"
+ ${build_generator_args}
+ --build-project TestExactVersion
+ --build-options ${build_options} -DPython_MAJOR_VERSION=2
+ -DPython_REQUESTED_VERSION=2.1.2
+ -DPython2_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python2.ExactVersion.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python2.ExactVersion.VERSION"
+ ${build_generator_args}
+ --build-project TestExactVersion
+ --build-options ${build_options} -DPython_MAJOR_VERSION=2
+ -DPython_REQUESTED_VERSION=2.1.2
+ -DPython2_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python3.ExactVersion.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python3.ExactVersion.LOCATION"
+ ${build_generator_args}
+ --build-project TestExactVersion
+ --build-options ${build_options} -DPython_MAJOR_VERSION=3
+ -DPython_REQUESTED_VERSION=3.1.2
+ -DPython3_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python3.ExactVersion.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python3.ExactVersion.VERSION"
+ ${build_generator_args}
+ --build-project TestExactVersion
+ --build-options ${build_options} -DPython_MAJOR_VERSION=3
+ -DPython_REQUESTED_VERSION=3.1.2
+ -DPython3_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python.V2.ExactVersion.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.ExactVersion.LOCATION"
+ ${build_generator_args}
+ --build-project TestExactVersion
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=2.1.2
+ -DPython_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python.V2.ExactVersion.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.ExactVersion.VERSION"
+ ${build_generator_args}
+ --build-project TestExactVersion
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=2.1.2
+ -DPython_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python.V3.ExactVersion.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python.V3.ExactVersion.LOCATION"
+ ${build_generator_args}
+ --build-project TestExactVersion
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=3.1.2
+ -DPython_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python.V3.ExactVersion.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python.V3.ExactVersion.VERSION"
+ ${build_generator_args}
+ --build-project TestExactVersion
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=3.1.2
+ -DPython_FIND_STRATEGY=VERSION
+ --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
+ "${CMake_SOURCE_DIR}/Tests/FindPython/MultiplePackages"
+ "${CMake_BINARY_DIR}/Tests/FindPython/MultiplePackages"
+ ${build_generator_args}
+ --build-project TestMultiplePackages
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ add_test(NAME FindPython.VirtualEnv COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/VirtualEnv"
+ "${CMake_BINARY_DIR}/Tests/FindPython/VirtualEnv"
+ ${build_generator_args}
+ --build-project TestVirtualEnv
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ add_test(NAME FindPython.Python2Embedded COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python2Embedded"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python2Embedded"
+ ${build_generator_args}
+ --build-project TestPython2Embedded
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Python3Embedded COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python3Embedded"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python3Embedded"
+ ${build_generator_args}
+ --build-project TestPython3Embedded
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ add_test(NAME FindPython.RequiredArtifacts COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/RequiredArtifacts"
+ "${CMake_BINARY_DIR}/Tests/FindPython/RequiredArtifacts"
+ ${build_generator_args}
+ --build-project TestRequiredArtifacts
+ --build-options ${build_options} "-Dbuild_generator_args=${build_generator_args}"
+ "-DCMake_SOURCE_DIR=${CMake_SOURCE_DIR}"
+ "-DCMake_BINARY_DIR=${CMake_BINARY_DIR}"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ add_test(NAME FindPython.ArtifactsInteractive.ON COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/ArtifactsInteractive"
+ "${CMake_BINARY_DIR}/Tests/FindPython/ArtifactsInteractive.ON"
+ ${build_generator_args}
+ --build-project TestArtifactsScope
+ --build-options ${build_options} "-Dbuild_generator_args=${build_generator_args}"
+ "-DCMake_SOURCE_DIR=${CMake_SOURCE_DIR}"
+ "-DCMake_BINARY_DIR=${CMake_BINARY_DIR}"
+ "-DCMake_TEST_FindPython_NumPy=${CMake_TEST_FindPython_NumPy}"
+ "-DPython3_ARTIFACTS_INTERACTIVE=ON"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.ArtifactsInteractive.OFF COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/ArtifactsInteractive"
+ "${CMake_BINARY_DIR}/Tests/FindPython/ArtifactsInteractive.OFF"
+ ${build_generator_args}
+ --build-project TestArtifactsScope
+ --build-options ${build_options} "-Dbuild_generator_args=${build_generator_args}"
+ "-DCMake_SOURCE_DIR=${CMake_SOURCE_DIR}"
+ "-DCMake_BINARY_DIR=${CMake_BINARY_DIR}"
+ "-DCMake_TEST_FindPython_NumPy=${CMake_TEST_FindPython_NumPy}"
+ "-DPython3_ARTIFACTS_INTERACTIVE=OFF"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ add_test(NAME FindPython.CustomFailureMessage COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/CustomFailureMessage"
+ "${CMake_BINARY_DIR}/Tests/FindPython/CustomFailureMessage"
+ ${build_generator_args}
+ --build-project TestCustomFailureMessage
+ --build-options ${build_options} "-Dbuild_generator_args=${build_generator_args}"
+ "-DCMake_SOURCE_DIR=${CMake_SOURCE_DIR}"
+ "-DCMake_BINARY_DIR=${CMake_BINARY_DIR}"
+ "-DCMake_TEST_FindPython_NumPy=${CMake_TEST_FindPython_NumPy}"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ if (CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin")
+ add_test(NAME FindPython.Interpreter.SOABI COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/SOABI"
+ "${CMake_BINARY_DIR}/Tests/FindPython/SOABI.Interpreter"
+ ${build_generator_args}
+ --build-project TestSOABI
+ --build-options ${build_options} "-Dbuild_generator_args=${build_generator_args}"
+ "-DCMake_SOURCE_DIR=${CMake_SOURCE_DIR}"
+ "-DCMake_BINARY_DIR=${CMake_BINARY_DIR}"
+ "-DCMake_TEST_FindPython_COMPONENT=Interpreter"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Development.SOABI COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/SOABI"
+ "${CMake_BINARY_DIR}/Tests/FindPython/SOABI.Development"
+ ${build_generator_args}
+ --build-project TestSOABI
+ --build-options ${build_options} "-Dbuild_generator_args=${build_generator_args}"
+ "-DCMake_SOURCE_DIR=${CMake_SOURCE_DIR}"
+ "-DCMake_BINARY_DIR=${CMake_BINARY_DIR}"
+ "-DCMake_TEST_FindPython_COMPONENT=Development"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ endif()
+
+ if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ add_test(NAME FindPython.UnversionedNames COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/UnversionedNames"
+ "${CMake_BINARY_DIR}/Tests/FindPython/UnversionedNames"
+ ${build_generator_args}
+ --build-project UnversionedNames
+ --build-options ${build_options}
+ )
+ endif()
+endif()
+
+if(CMake_TEST_FindPython_NumPy)
+ add_test(NAME FindPython.NumPy COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/NumPy"
+ "${CMake_BINARY_DIR}/Tests/FindPython/NumPy"
+ ${build_generator_args}
+ --build-project TestNumPy
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.NumPyOnly COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/NumPyOnly"
+ "${CMake_BINARY_DIR}/Tests/FindPython/NumPyOnly"
+ ${build_generator_args}
+ --build-project TestNumPyOnly
+ --build-options ${build_options}
+ )
+endif()
+
+if(CMake_TEST_FindPython_Conda)
+ add_test(NAME FindPython.VirtualEnvConda COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/VirtualEnvConda"
+ "${CMake_BINARY_DIR}/Tests/FindPython/VirtualEnvConda"
+ ${build_generator_args}
+ --build-project TestVirtualEnvConda
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+endif()
+
+if (CMake_TEST_FindPython AND CMake_TEST_FindPython_IronPython)
+ add_test(NAME FindPython.Implementation.CPython COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Implementation"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Implementation.CPython"
+ ${build_generator_args}
+ --build-project TestImplementationCPython
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_REQUESTED_IMPLEMENTATIONS=CPython
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.Implementation.IronPython COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Implementation"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Implementation.IronPython"
+ ${build_generator_args}
+ --build-project TestImplementationIronPython
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_REQUESTED_IMPLEMENTATION=IronPython
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+endif()
+
+if(CMake_TEST_FindPython_IronPython)
+ add_test(NAME FindPython.IronPython2.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/IronPython2"
+ "${CMake_BINARY_DIR}/Tests/FindPython/IronPython2.LOCATION"
+ ${build_generator_args}
+ --build-project TestIronPython2
+ --build-options ${build_options} -DPython2_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.IronPython2.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/IronPython2"
+ "${CMake_BINARY_DIR}/Tests/FindPython/IronPython2.VERSION"
+ ${build_generator_args}
+ --build-project TestIronPython2
+ --build-options ${build_options} -DPython2_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ add_test(NAME FindPython.IronPython.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/IronPython"
+ "${CMake_BINARY_DIR}/Tests/FindPython/IronPython.LOCATION"
+ ${build_generator_args}
+ --build-project TestIronPython
+ --build-options ${build_options} -DPython_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.IronPython.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/IronPython"
+ "${CMake_BINARY_DIR}/Tests/FindPython/IronPython.VERSION"
+ ${build_generator_args}
+ --build-project TestIronPython
+ --build-options ${build_options} -DPython_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.IronPython.V2.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/IronPython"
+ "${CMake_BINARY_DIR}/Tests/FindPython/IronPython.V2.LOCATION"
+ ${build_generator_args}
+ --build-project TestIronPython
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.IronPython.V2.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/IronPython"
+ "${CMake_BINARY_DIR}/Tests/FindPython/IronPython.V2.VERSION"
+ ${build_generator_args}
+ --build-project TestIronPython
+ --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)
+ add_test(NAME FindPython.PyPy2.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy2"
+ "${CMake_BINARY_DIR}/Tests/FindPython/PyPy2.LOCATION"
+ ${build_generator_args}
+ --build-project TestPyPy2
+ --build-options ${build_options} -DPython2_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.PyPy2.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy2"
+ "${CMake_BINARY_DIR}/Tests/FindPython/PyPy2.VERSION"
+ ${build_generator_args}
+ --build-project TestPyPy2
+ --build-options ${build_options} -DPython2_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ add_test(NAME FindPython.PyPy3.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy3"
+ "${CMake_BINARY_DIR}/Tests/FindPython/PyPy3.LOCATION"
+ ${build_generator_args}
+ --build-project TestPyPy3
+ --build-options ${build_options} -DPython3_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.PyPy3.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy3"
+ "${CMake_BINARY_DIR}/Tests/FindPython/PyPy3.VERSION"
+ ${build_generator_args}
+ --build-project TestPyPy3
+ --build-options ${build_options} -DPython3_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ add_test(NAME FindPython.PyPy.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy"
+ "${CMake_BINARY_DIR}/Tests/FindPython/PyPy.LOCATION"
+ ${build_generator_args}
+ --build-project TestPyPy
+ --build-options ${build_options} -DPython_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.PyPy.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy"
+ "${CMake_BINARY_DIR}/Tests/FindPython/PyPy.VERSION"
+ ${build_generator_args}
+ --build-project TestPyPy
+ --build-options ${build_options} -DPython_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.PyPy.V2.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy"
+ "${CMake_BINARY_DIR}/Tests/FindPython/PyPy.V2.LOCATION"
+ ${build_generator_args}
+ --build-project TestPyPy
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.PyPy.V2.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy"
+ "${CMake_BINARY_DIR}/Tests/FindPython/PyPy.V2.VERSION"
+ ${build_generator_args}
+ --build-project TestPyPy
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.PyPy.V3.LOCATION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy"
+ "${CMake_BINARY_DIR}/Tests/FindPython/PyPy.V3.LOCATION"
+ ${build_generator_args}
+ --build-project TestPyPy
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=3 -DPython_FIND_STRATEGY=LOCATION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.PyPy.V3.VERSION COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy"
+ "${CMake_BINARY_DIR}/Tests/FindPython/PyPy.V3.VERSION"
+ ${build_generator_args}
+ --build-project TestPyPy
+ --build-options ${build_options} -DPython_REQUESTED_VERSION=3 -DPython_FIND_STRATEGY=VERSION
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+endif()
diff --git a/Tests/FindPython/CustomFailureMessage/CMakeLists.txt b/Tests/FindPython/CustomFailureMessage/CMakeLists.txt
new file mode 100644
index 0000000..a0d8eb2
--- /dev/null
+++ b/Tests/FindPython/CustomFailureMessage/CMakeLists.txt
@@ -0,0 +1,79 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestCustomFailureMessage LANGUAGES NONE)
+
+include(CTest)
+
+add_test(NAME FindPython.CustomFailureMessage.Interpreter COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/CustomFailureMessage/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/CustomFailureMessage/Interpreter"
+ ${build_generator_args}
+ --build-project TestCustomFailureMessage.Check
+ --build-options "-DCHECK_COMPONENTS=Interpreter"
+ "-DPython3_EXECUTABLE=/not/found/interpreter"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+set_tests_properties(FindPython.CustomFailureMessage.Interpreter PROPERTIES
+ PASS_REGULAR_EXPRESSION "Reason given by package:.+Interpreter: Cannot run the interpreter")
+
+add_test(NAME FindPython.CustomFailureMessage.Library COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/CustomFailureMessage/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/CustomFailureMessage/Library"
+ ${build_generator_args}
+ --build-project TestCustomFailureMessage.Check
+ --build-options "-DCHECK_COMPONENTS=Development"
+ "-DPython3_LIBRARY=/not/found/library"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+set_tests_properties(FindPython.CustomFailureMessage.Library PROPERTIES
+ PASS_REGULAR_EXPRESSION "Reason given by package:.+Development: Cannot find the library")
+
+add_test(NAME FindPython.CustomFailureMessage.Include COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/CustomFailureMessage/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/CustomFailureMessage/Include"
+ ${build_generator_args}
+ --build-project TestCustomFailureMessage.Check
+ --build-options "-DCHECK_COMPONENTS=Development"
+ "-DPython3_INCLUDE_DIR=/not/found/include"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+set_tests_properties(FindPython.CustomFailureMessage.Include PROPERTIES
+ PASS_REGULAR_EXPRESSION "Reason given by package:.+Development: Cannot find the directory")
+
+add_test(NAME FindPython.CustomFailureMessage.Multiple COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/CustomFailureMessage/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/CustomFailureMessage/Multiple"
+ ${build_generator_args}
+ --build-project TestCustomFailureMessage.Check
+ --build-options "-DCHECK_COMPONENTS=Interpreter;Development"
+ "-DPython3_EXECUTABLE=/not/found/interpreter"
+ "-DPython3_LIBRARY=/not/found/library"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+set_tests_properties(FindPython.CustomFailureMessage.Multiple PROPERTIES
+ PASS_REGULAR_EXPRESSION "Reason given by package:.+Interpreter: Cannot run the interpreter.+Development: Cannot find the library")
+
+
+if (CMake_TEST_FindPython_NumPy)
+ add_test(NAME FindPython.CustomFailureMessage.NumPy COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/CustomFailureMessage/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/CustomFailureMessage/NumPy"
+ ${build_generator_args}
+ --build-project TestCustomFailureMessage.Check
+ --build-options "-DCHECK_COMPONENTS=Interpreter;Development;NumPy"
+ "-DPython3_NumPy_INCLUDE_DIR=/not/found/numpy/include"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ set_tests_properties(FindPython.CustomFailureMessage.NumPy PROPERTIES
+ PASS_REGULAR_EXPRESSION "Reason given by package:.+NumPy: Cannot find the directory")
+endif()
diff --git a/Tests/FindPython/CustomFailureMessage/Check/CMakeLists.txt b/Tests/FindPython/CustomFailureMessage/Check/CMakeLists.txt
new file mode 100644
index 0000000..2164ac1
--- /dev/null
+++ b/Tests/FindPython/CustomFailureMessage/Check/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestCustomFailureMessage.Check LANGUAGES NONE)
+
+find_package (Python3 REQUIRED COMPONENTS ${CHECK_COMPONENTS})
diff --git a/Tests/FindPython/ExactVersion/CMakeLists.txt b/Tests/FindPython/ExactVersion/CMakeLists.txt
new file mode 100644
index 0000000..60abb26
--- /dev/null
+++ b/Tests/FindPython/ExactVersion/CMakeLists.txt
@@ -0,0 +1,56 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestExactVersion LANGUAGES C)
+
+find_package(Python${Python_MAJOR_VERSION} ${Python_REQUESTED_VERSION} COMPONENTS Interpreter Development)
+if(NOT Python${Python_MAJOR_VERSION}_FOUND)
+ message (FATAL_ERROR "Failed to find Python ${Python_REQUESTED_VERSION}")
+endif()
+if(NOT Python${Python_MAJOR_VERSION}_Interpreter_FOUND)
+ message (FATAL_ERROR "Failed to find Python ${Python_REQUESTED_VERSION} Interpreter")
+endif()
+if(NOT Python${Python_MAJOR_VERSION}_Development_FOUND)
+ message (FATAL_ERROR "Failed to find Python ${Python_REQUESTED_VERSION} Development")
+endif()
+
+if(NOT TARGET Python${Python_MAJOR_VERSION}::Interpreter)
+ message(SEND_ERROR "Python${Python_MAJOR_VERSION}::Interpreter not found")
+endif()
+
+if(NOT TARGET Python${Python_MAJOR_VERSION}::Python)
+ message(SEND_ERROR "Python${Python_MAJOR_VERSION}::Python not found")
+endif()
+if(NOT TARGET Python${Python_MAJOR_VERSION}::Module)
+ message(SEND_ERROR "Python${Python_MAJOR_VERSION}::Module not found")
+endif()
+
+
+# reset artifacts and second search with exact version already founded
+unset(Python${Python_MAJOR_VERSION}_EXECUTABLE)
+unset(_Python${Python_MAJOR_VERSION}_EXECUTABLE CACHE)
+
+unset(_Python${Python_MAJOR_VERSION}_LIBRARY_RELEASE CACHE)
+unset(_Python${Python_MAJOR_VERSION}_INCLUDE_DIR CACHE)
+
+set(Python_REQUESTED_VERSION ${Python${Python_MAJOR_VERSION}_VERSION})
+find_package(Python${Python_MAJOR_VERSION} ${Python_REQUESTED_VERSION} EXACT COMPONENTS Interpreter Development)
+if(NOT Python${Python_MAJOR_VERSION}_FOUND)
+ message (FATAL_ERROR "Failed to find Python ${Python_REQUESTED_VERSION}")
+endif()
+if(NOT Python${Python_MAJOR_VERSION}_Interpreter_FOUND)
+ message (FATAL_ERROR "Failed to find Python ${Python_REQUESTED_VERSION} Interpreter")
+endif()
+if(NOT Python${Python_MAJOR_VERSION}_Development_FOUND)
+ message (FATAL_ERROR "Failed to find Python ${Python_REQUESTED_VERSION} Development")
+endif()
+
+if(NOT TARGET Python${Python_MAJOR_VERSION}::Interpreter)
+ message(SEND_ERROR "Python${Python_MAJOR_VERSION}::Interpreter not found")
+endif()
+
+if(NOT TARGET Python${Python_MAJOR_VERSION}::Python)
+ message(SEND_ERROR "Python${Python_MAJOR_VERSION}::Python not found")
+endif()
+if(NOT TARGET Python${Python_MAJOR_VERSION}::Module)
+ message(SEND_ERROR "Python${Python_MAJOR_VERSION}::Module not found")
+endif()
diff --git a/Tests/FindPython/FindPythonScript.cmake b/Tests/FindPython/FindPythonScript.cmake
new file mode 100644
index 0000000..808496e
--- /dev/null
+++ b/Tests/FindPython/FindPythonScript.cmake
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.12)
+if (PYTHON_MUST_NOT_BE_FOUND)
+ find_package(${PYTHON_PACKAGE_NAME} QUIET)
+ if (${PYTHON_PACKAGE_NAME}_FOUND)
+ message(FATAL_ERROR "${PYTHON_PACKAGE_NAME}: unexpectedly founded.")
+ endif()
+else()
+ find_package(${PYTHON_PACKAGE_NAME} REQUIRED QUIET)
+endif()
diff --git a/Tests/FindPython/Implementation/CMakeLists.txt b/Tests/FindPython/Implementation/CMakeLists.txt
new file mode 100644
index 0000000..592329b
--- /dev/null
+++ b/Tests/FindPython/Implementation/CMakeLists.txt
@@ -0,0 +1,37 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestImplementation${Python_REQUESTED_IMPLEMENTATION} LANGUAGES NONE)
+
+
+set (Python${Python_REQUESTED_VERSION}_FIND_IMPLEMENTATIONS ${Python_REQUESTED_IMPLEMENTATION})
+
+find_package(Python${Python_REQUESTED_VERSION} COMPONENTS Interpreter)
+if (NOT Python${Python_REQUESTED_VERSION}_FOUND OR NOT Python${Python_REQUESTED_VERSION}_Interpreter_FOUND)
+ message (FATAL_ERROR "Failed to find Python${Python_REQUESTED_VERSION}")
+endif()
+
+if (Python_REQUESTED_IMPLEMENTATION STREQUAL "IronPython"
+ AND NOT Python${Python_REQUESTED_VERSION}_INTERPRETER_ID STREQUAL "IronPython")
+ message (FATAL_ERROR "Erroneous interpreter ID (${Python${Python_REQUESTED_VERSION}_INTERPRETER_ID})")
+endif()
+if (Python_REQUESTED_IMPLEMENTATION STREQUAL "CPython"
+ AND Python${Python_REQUESTED_VERSION}_INTERPRETER_ID STREQUAL "IronPython")
+ message (FATAL_ERROR "Erroneous interpreter ID (${Python${Python_REQUESTED_VERSION}_INTERPRETER_ID})")
+endif()
+
+
+set (Python_FIND_IMPLEMENTATIONS ${Python_REQUESTED_IMPLEMENTATION})
+
+find_package(Python ${Python_REQUESTED_VERSION} REQUIRED COMPONENTS Interpreter)
+if (NOT Python_FOUND OR NOT Python_Interpreter_FOUND)
+ message (FATAL_ERROR "Failed to find Python ${Python_REQUESTED_VERSION}")
+endif()
+
+if (Python_REQUESTED_IMPLEMENTATION STREQUAL "IronPython"
+ AND NOT Python_INTERPRETER_ID STREQUAL "IronPython")
+ message (FATAL_ERROR "Erroneous interpreter ID (${Python_INTERPRETER_ID})")
+endif()
+if (Python_REQUESTED_IMPLEMENTATION STREQUAL "CPython"
+ AND Python_INTERPRETER_ID STREQUAL "IronPython")
+ message (FATAL_ERROR "Erroneous interpreter ID (${Python_INTERPRETER_ID})")
+endif()
diff --git a/Tests/FindPython/IronPython/CMakeLists.txt b/Tests/FindPython/IronPython/CMakeLists.txt
new file mode 100644
index 0000000..47ca022
--- /dev/null
+++ b/Tests/FindPython/IronPython/CMakeLists.txt
@@ -0,0 +1,31 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestIronPython LANGUAGES NONE)
+
+set (Python_FIND_IMPLEMENTATIONS IronPython)
+
+find_package(Python ${Python_REQUESTED_VERSION} COMPONENTS Interpreter Compiler)
+if (NOT Python_FOUND)
+ message (FATAL_ERROR "Failed to find Python ${Python_REQUESTED_VERSION}")
+endif()
+
+if (NOT Python_Interpreter_FOUND)
+ message (FATAL_ERROR "Failed to find Python Interpreter")
+endif()
+if (NOT Python_INTERPRETER_ID STREQUAL "IronPython")
+ message (FATAL_ERROR "Erroneous interpreter ID (${Python_INTERPRETER_ID})")
+endif()
+
+if (NOT Python_Compiler_FOUND)
+ message (FATAL_ERROR "Failed to find Python Compiler")
+endif()
+if (NOT Python_COMPILER_ID STREQUAL "IronPython")
+ message (FATAL_ERROR "Erroneous compiler ID (${Python_COMPILER_ID})")
+endif()
+
+if(NOT TARGET Python::Interpreter)
+ message(SEND_ERROR "Python::Interpreter not found")
+endif()
+if(NOT TARGET Python::Compiler)
+ message(SEND_ERROR "Python::Interpreter not found")
+endif()
diff --git a/Tests/FindPython/IronPython2/CMakeLists.txt b/Tests/FindPython/IronPython2/CMakeLists.txt
new file mode 100644
index 0000000..fd9d947
--- /dev/null
+++ b/Tests/FindPython/IronPython2/CMakeLists.txt
@@ -0,0 +1,31 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestIronPython2 LANGUAGES NONE)
+
+set (Python2_FIND_IMPLEMENTATIONS "IronPython")
+
+find_package(Python2 COMPONENTS Interpreter Compiler)
+if (NOT Python2_FOUND)
+ message (FATAL_ERROR "Failed to find Python 2")
+endif()
+
+if (NOT Python2_Interpreter_FOUND)
+ message (FATAL_ERROR "Failed to find Python 2 Interpreter")
+endif()
+if (NOT Python2_INTERPRETER_ID STREQUAL "IronPython")
+ message (FATAL_ERROR "Erroneous interpreter ID (${Python2_INTERPRETER_ID})")
+endif()
+
+if (NOT Python2_Compiler_FOUND)
+ message (FATAL_ERROR "Failed to find Python 2 Compiler")
+endif()
+if (NOT Python2_COMPILER_ID STREQUAL "IronPython")
+ message (FATAL_ERROR "Erroneous compiler ID (${Python2_COMPILER_ID})")
+endif()
+
+if(NOT TARGET Python2::Interpreter)
+ message(SEND_ERROR "Python2::Interpreter not found")
+endif()
+if(NOT TARGET Python2::Compiler)
+ message(SEND_ERROR "Python2::Compiler not found")
+endif()
diff --git a/Tests/FindPython/MultiplePackages/CMakeLists.txt b/Tests/FindPython/MultiplePackages/CMakeLists.txt
new file mode 100644
index 0000000..5c85155
--- /dev/null
+++ b/Tests/FindPython/MultiplePackages/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestMultiplePackages C)
+
+find_package (Python2 REQUIRED COMPONENTS Interpreter Development)
+find_package (Python3 REQUIRED COMPONENTS Interpreter Development)
+
+# Must find Python 3
+find_package (Python REQUIRED)
+
+if (NOT Python3_EXECUTABLE STREQUAL Python_EXECUTABLE)
+ message (FATAL_ERROR
+ "Python interpreters do not match:\n"
+ " Python_EXECUTABLE='${Python_EXECUTABLE}'\n"
+ " Python3_EXECUTABLE='${Python3_EXECUTABLE}'\n"
+ )
+endif()
+
+
+Python2_add_library (spam2 MODULE ../spam.c)
+target_compile_definitions (spam2 PRIVATE PYTHON2)
+
+Python3_add_library (spam3 MODULE ../spam.c)
+target_compile_definitions (spam3 PRIVATE PYTHON3)
+
+
+add_test (NAME python2_spam2
+ COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam3>"
+ "${Python2_EXECUTABLE}" -c "import spam2; spam2.system(\"cd\")")
+
+add_test (NAME python3_spam3
+ COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam3>"
+ "${Python3_EXECUTABLE}" -c "import spam3; spam3.system(\"cd\")")
diff --git a/Tests/FindPython/NumPy/CMakeLists.txt b/Tests/FindPython/NumPy/CMakeLists.txt
new file mode 100644
index 0000000..3e17f68
--- /dev/null
+++ b/Tests/FindPython/NumPy/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestNumPy LANGUAGES C)
+
+find_package (Python2 REQUIRED COMPONENTS Interpreter Development NumPy)
+find_package (Python3 REQUIRED COMPONENTS Interpreter Development NumPy)
+
+Python2_add_library (arraytest2 MODULE arraytest.c)
+target_compile_definitions (arraytest2 PRIVATE PYTHON2)
+target_link_libraries (arraytest2 PRIVATE Python2::NumPy)
+
+Python3_add_library (arraytest3 MODULE arraytest.c)
+target_compile_definitions (arraytest3 PRIVATE PYTHON3)
+target_link_libraries (arraytest3 PRIVATE Python3::NumPy)
+
+add_test (NAME python2_arraytest
+ COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:arraytest2>"
+ "${Python2_EXECUTABLE}" -c "import numpy; import arraytest2; arraytest2.vecsq(numpy.array([1, 2, 3]));")
+
+add_test (NAME python3_arraytest
+ COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:arraytest3>"
+ "${Python3_EXECUTABLE}" -c "import numpy; import arraytest3; arraytest3.vecsq(numpy.array([1, 2, 3]));")
diff --git a/Tests/FindPython/NumPy/arraytest.c b/Tests/FindPython/NumPy/arraytest.c
new file mode 100644
index 0000000..51db7bc
--- /dev/null
+++ b/Tests/FindPython/NumPy/arraytest.c
@@ -0,0 +1,58 @@
+#include "Python.h"
+
+#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+#include <math.h>
+
+#include "numpy/arrayobject.h"
+
+static PyObject* vecsq(PyObject* self, PyObject* args);
+
+static PyMethodDef arraytestMethods[] = { { "vecsq", vecsq, METH_VARARGS },
+ { NULL, NULL } };
+
+static PyObject* vecsq(PyObject* self, PyObject* args)
+{
+ PyArrayObject *vecin, *vecout;
+ npy_intp dims[2];
+ double *cin, *cout;
+ int i, j, n, m;
+
+ if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &vecin))
+ return NULL;
+
+ n = dims[0] = PyArray_NDIM(vecin);
+ vecout = (PyArrayObject*)PyArray_SimpleNew(1, dims, NPY_DOUBLE);
+
+ cin = (double*)PyArray_DATA(vecin);
+ cout = (double*)PyArray_DATA(vecout);
+
+ for (i = 0; i < n; i++) {
+ cout[i] = cin[i] * cin[i];
+ }
+ return PyArray_Return(vecout);
+}
+
+#if defined(PYTHON2)
+PyMODINIT_FUNC init_C_arraytest(void)
+{
+ (void)Py_InitModule("arraytest2", arraytestMethods);
+ import_array();
+}
+#endif
+
+#if defined(PYTHON3)
+static struct PyModuleDef arraytestmodule = {
+ PyModuleDef_HEAD_INIT, "arraytest3", /* name of module */
+ NULL, /* module documentation, may be NULL */
+ -1, /* size of per-interpreter state of the module,
+ or -1 if the module keeps state in global variables. */
+ arraytestMethods
+};
+
+PyMODINIT_FUNC PyInit_C_arraytest(void)
+{
+ PyObject* po = PyModule_Create(&arraytestmodule);
+ import_array();
+ return po;
+}
+#endif
diff --git a/Tests/FindPython/NumPyOnly/CMakeLists.txt b/Tests/FindPython/NumPyOnly/CMakeLists.txt
new file mode 100644
index 0000000..bedc627
--- /dev/null
+++ b/Tests/FindPython/NumPyOnly/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestNumPyOnly LANGUAGES C)
+
+find_package(Python2 REQUIRED COMPONENTS NumPy)
+find_package(Python3 REQUIRED COMPONENTS NumPy)
+
+Python2_add_library (arraytest2 MODULE ../NumPy/arraytest.c)
+target_compile_definitions (arraytest2 PRIVATE PYTHON2)
+target_link_libraries (arraytest2 PRIVATE Python2::NumPy)
+
+Python3_add_library (arraytest3 MODULE ../NumPy/arraytest.c)
+target_compile_definitions (arraytest3 PRIVATE PYTHON3)
+target_link_libraries (arraytest3 PRIVATE Python3::NumPy)
diff --git a/Tests/FindPython/PyPy/CMakeLists.txt b/Tests/FindPython/PyPy/CMakeLists.txt
new file mode 100644
index 0000000..4cf7c0a
--- /dev/null
+++ b/Tests/FindPython/PyPy/CMakeLists.txt
@@ -0,0 +1,37 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPyPy LANGUAGES C)
+
+set (Python_FIND_IMPLEMENTATIONS PyPy)
+
+find_package(Python ${Python_REQUESTED_VERSION} COMPONENTS Interpreter Development)
+if (NOT Python_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy ${Python_REQUESTED_VERSION}")
+endif()
+
+if (NOT Python_Interpreter_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy Interpreter")
+endif()
+if (NOT Python_INTERPRETER_ID STREQUAL "PyPy")
+ message (FATAL_ERROR "Erroneous interpreter ID (${Python_INTERPRETER_ID})")
+endif()
+
+if (NOT Python_Development.Module_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy ${Python_REQUESTED_VERSION} Development.Module")
+endif()
+if (NOT Python_Development.Embed_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy ${Python_REQUESTED_VERSION} Development.Embed")
+endif()
+if (NOT Python_Development_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy ${Python_REQUESTED_VERSION} Development")
+endif()
+
+if(NOT TARGET Python::Interpreter)
+ message(SEND_ERROR "Python::Interpreter not found")
+endif()
+if(NOT TARGET Python::Module)
+ message(SEND_ERROR "Python::Module not found")
+endif()
+if(NOT TARGET Python::Python)
+ message(SEND_ERROR "Python::Python not found")
+endif()
diff --git a/Tests/FindPython/PyPy2/CMakeLists.txt b/Tests/FindPython/PyPy2/CMakeLists.txt
new file mode 100644
index 0000000..ebfc9ab
--- /dev/null
+++ b/Tests/FindPython/PyPy2/CMakeLists.txt
@@ -0,0 +1,37 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPyPy2 LANGUAGES C)
+
+set (Python2_FIND_IMPLEMENTATIONS "PyPy")
+
+find_package(Python2 COMPONENTS Interpreter Development)
+if (NOT Python2_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy 2")
+endif()
+
+if (NOT Python2_Interpreter_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy 2 Interpreter")
+endif()
+if (NOT Python2_INTERPRETER_ID STREQUAL "PyPy")
+ message (FATAL_ERROR "Erroneous interpreter ID (${Python2_INTERPRETER_ID})")
+endif()
+
+if (NOT Python2_Development.Module_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy 2 Development.Module")
+endif()
+if (NOT Python2_Development.Embed_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy 2 Development.Embed")
+endif()
+if (NOT Python2_Development_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy 2 Development")
+endif()
+
+if(NOT TARGET Python2::Interpreter)
+ message(SEND_ERROR "Python2::Interpreter not found")
+endif()
+if(NOT TARGET Python2::Module)
+ message(SEND_ERROR "Python2::Module not found")
+endif()
+if(NOT TARGET Python2::Python)
+ message(SEND_ERROR "Python2::Python not found")
+endif()
diff --git a/Tests/FindPython/PyPy3/CMakeLists.txt b/Tests/FindPython/PyPy3/CMakeLists.txt
new file mode 100644
index 0000000..bf7cd61
--- /dev/null
+++ b/Tests/FindPython/PyPy3/CMakeLists.txt
@@ -0,0 +1,37 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPyPy3 LANGUAGES C)
+
+set (Python3_FIND_IMPLEMENTATIONS "PyPy")
+
+find_package(Python3 COMPONENTS Interpreter Development)
+if (NOT Python3_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy 3")
+endif()
+
+if (NOT Python3_Interpreter_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy 3 Interpreter")
+endif()
+if (NOT Python3_INTERPRETER_ID STREQUAL "PyPy")
+ message (FATAL_ERROR "Erroneous interpreter ID (${Python3_INTERPRETER_ID})")
+endif()
+
+if (NOT Python3_Development.Module_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy 3 Development.Module")
+endif()
+if (NOT Python3_Development.Embed_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy 3 Development.Embed")
+endif()
+if (NOT Python3_Development_FOUND)
+ message (FATAL_ERROR "Failed to find Python PyPy 3 Development")
+endif()
+
+if(NOT TARGET Python3::Interpreter)
+ message(SEND_ERROR "Python3::Interpreter not found")
+endif()
+if(NOT TARGET Python3::Module)
+ message(SEND_ERROR "Python3::Module not found")
+endif()
+if(NOT TARGET Python3::Python)
+ message(SEND_ERROR "Python3::Python not found")
+endif()
diff --git a/Tests/FindPython/Python/CMakeLists.txt b/Tests/FindPython/Python/CMakeLists.txt
new file mode 100644
index 0000000..9bec22f
--- /dev/null
+++ b/Tests/FindPython/Python/CMakeLists.txt
@@ -0,0 +1,40 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPython LANGUAGES C)
+
+include(CTest)
+
+find_package(Python ${Python_REQUESTED_VERSION} REQUIRED COMPONENTS Interpreter Development)
+if (NOT Python_FOUND)
+ message (FATAL_ERROR "Failed to find Python ${Python_REQUESTED_VERSION}")
+endif()
+if (NOT Python_Development.Module_FOUND)
+ message (FATAL_ERROR "Failed to find Python ${Python_REQUESTED_VERSION}, COMPONENT 'Development.Module'")
+endif()
+if (NOT Python_Development.Embed_FOUND)
+ message (FATAL_ERROR "Failed to find Python ${Python_REQUESTED_VERSION}, COMPOENENT 'Development.Embed'")
+endif()
+
+if(NOT TARGET Python::Interpreter)
+ message(SEND_ERROR "Python::Interpreter not found")
+endif()
+
+if(NOT TARGET Python::Python)
+ message(SEND_ERROR "Python::Python not found")
+endif()
+if(NOT TARGET Python::Module)
+ message(SEND_ERROR "Python::Module not found")
+endif()
+
+if (Python_REQUESTED_VERSION)
+ Python_add_library (spam${Python_REQUESTED_VERSION} MODULE ../spam.c)
+ target_compile_definitions (spam${Python_REQUESTED_VERSION} PRIVATE PYTHON${Python_REQUESTED_VERSION})
+
+ add_test (NAME python_spam${Python_REQUESTED_VERSION}
+ COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam${Python_REQUESTED_VERSION}>"
+ "${Python_EXECUTABLE}" -c "import spam${Python_REQUESTED_VERSION}; spam${Python_REQUESTED_VERSION}.system(\"cd\")")
+else()
+ add_test(NAME findpython_script
+ COMMAND "${CMAKE_COMMAND}" -DPYTHON_PACKAGE_NAME=Python
+ -P "${CMAKE_CURRENT_LIST_DIR}/../FindPythonScript.cmake")
+endif()
diff --git a/Tests/FindPython/Python2/CMakeLists.txt b/Tests/FindPython/Python2/CMakeLists.txt
new file mode 100644
index 0000000..39577b2
--- /dev/null
+++ b/Tests/FindPython/Python2/CMakeLists.txt
@@ -0,0 +1,47 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPython2 LANGUAGES C)
+
+include(CTest)
+
+find_package(Python2 3 QUIET)
+if (Python2_FOUND)
+ message (FATAL_ERROR "Wrong python version found: ${Python2_VERSION}")
+endif()
+
+find_package(Python2 REQUIRED COMPONENTS Interpreter Development)
+if (NOT Python2_FOUND)
+ message (FATAL_ERROR "Failed to find Python 2")
+endif()
+if (NOT Python2_Development_FOUND)
+ message (FATAL_ERROR "Failed to find Python 2 'Development' component")
+endif()
+if (NOT Python2_Development.Module_FOUND)
+ message (FATAL_ERROR "Failed to find Python 2 'Development.Module' component")
+endif()
+if (NOT Python2_Development.Embed_FOUND)
+ message (FATAL_ERROR "Failed to find Python 2 'Development.Embed' component")
+endif()
+
+if(NOT TARGET Python2::Interpreter)
+ message(SEND_ERROR "Python2::Interpreter not found")
+endif()
+
+if(NOT TARGET Python2::Python)
+ message(SEND_ERROR "Python2::Python not found")
+endif()
+if(NOT TARGET Python2::Module)
+ message(SEND_ERROR "Python2::Module not found")
+endif()
+
+Python2_add_library (spam2 MODULE ../spam.c)
+target_compile_definitions (spam2 PRIVATE PYTHON2)
+
+add_test (NAME python2_spam2
+ COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam2>"
+ "${Python2_EXECUTABLE}" -c "import spam2; spam2.system(\"cd\")")
+
+add_test(NAME findpython2_script
+ COMMAND "${CMAKE_COMMAND}" -DPYTHON_PACKAGE_NAME=Python2
+ -DPython2_FIND_STRATEGY=${Python2_FIND_STRATEGY}
+ -P "${CMAKE_CURRENT_LIST_DIR}/../FindPythonScript.cmake")
diff --git a/Tests/FindPython/Python2Embedded/CMakeLists.txt b/Tests/FindPython/Python2Embedded/CMakeLists.txt
new file mode 100644
index 0000000..a1036ce
--- /dev/null
+++ b/Tests/FindPython/Python2Embedded/CMakeLists.txt
@@ -0,0 +1,42 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPython2Embedded LANGUAGES C)
+
+include(CTest)
+
+find_package(Python2 REQUIRED COMPONENTS Development.Embed)
+if (NOT Python2_FOUND)
+ message (FATAL_ERROR "Failed to find Python 2")
+endif()
+if (Python2_Development_FOUND)
+ message (FATAL_ERROR "Python 2, COMPONENT 'Development' unexpectedly found")
+endif()
+if (Python2_Development.Module_FOUND)
+ message (FATAL_ERROR "Python 2, COMPONENT 'Development.Module' unexpectedly found")
+endif()
+if (NOT Python2_Development.Embed_FOUND)
+ message (FATAL_ERROR "Python 2, COMPONENT 'Development.Embed' not found")
+endif()
+
+if(TARGET Python2::Module)
+ message(SEND_ERROR "Python2::Module unexpectedly found")
+endif()
+
+if(NOT TARGET Python2::Python)
+ message(SEND_ERROR "Python2::Python not found")
+endif()
+
+Python2_add_library (display_time2 SHARED ../display_time.c)
+set_property (TARGET display_time2 PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON)
+target_compile_definitions (display_time2 PRIVATE PYTHON2)
+
+add_executable (main2 ../main.c)
+target_link_libraries (main2 PRIVATE display_time2)
+
+if (WIN32 OR CYGWIN OR MSYS OR MINGW)
+ list (JOIN Python2_RUNTIME_LIBRARY_DIRS "$<SEMICOLON>" RUNTIME_DIRS)
+ add_test (NAME Python2.Embedded COMMAND "${CMAKE_COMMAND}" -E env "PATH=${RUNTIME_DIRS}" $<TARGET_FILE:main2>)
+else()
+ add_test (NAME Python2.Embedded COMMAND main2)
+endif()
+set_property (TEST Python2.Embedded PROPERTY PASS_REGULAR_EXPRESSION "Today is")
diff --git a/Tests/FindPython/Python2Fail/CMakeLists.txt b/Tests/FindPython/Python2Fail/CMakeLists.txt
new file mode 100644
index 0000000..989688f
--- /dev/null
+++ b/Tests/FindPython/Python2Fail/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPython2Fail C)
+
+include(CTest)
+
+find_package(Python2 REQUIRED COMPONENTS Interpreter Development foobar)
+
+Python2_add_library (spam2 MODULE ../spam.c)
+target_compile_definitions (spam2 PRIVATE PYTHON2)
+
+add_test (NAME python2_spam2
+ COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam2>"
+ "${Python2_EXECUTABLE}" -c "import spam2; spam2.system(\"cd\")")
diff --git a/Tests/FindPython/Python2Module/CMakeLists.txt b/Tests/FindPython/Python2Module/CMakeLists.txt
new file mode 100644
index 0000000..c9d46ac
--- /dev/null
+++ b/Tests/FindPython/Python2Module/CMakeLists.txt
@@ -0,0 +1,37 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPython2Module LANGUAGES C)
+
+include(CTest)
+
+find_package(Python2 REQUIRED COMPONENTS Interpreter Development.Module)
+if (NOT Python2_FOUND)
+ message (FATAL_ERROR "Failed to find Python 2")
+endif()
+if (Python2_Development_FOUND)
+ message (FATAL_ERROR "Python 2, COMPONENT 'Development' unexpectedly found")
+endif()
+if (Python2_Development.Embed_FOUND)
+ message (FATAL_ERROR "Python 2, COMPONENT 'Development.Embed' unexpectedly found")
+endif()
+if (NOT Python2_Development.Module_FOUND)
+ message (FATAL_ERROR "Python 2, COMPONENT 'Development.Module' not found")
+endif()
+
+if(NOT TARGET Python2::Interpreter)
+ message(SEND_ERROR "Python2::Interpreter not found")
+endif()
+
+if(TARGET Python2::Python)
+ message(SEND_ERROR "Python2::Python unexpectedly found")
+endif()
+if(NOT TARGET Python2::Module)
+ message(SEND_ERROR "Python2::Module not found")
+endif()
+
+Python2_add_library (spam2 MODULE ../spam.c)
+target_compile_definitions (spam2 PRIVATE PYTHON2)
+
+add_test (NAME python2_spam2
+ COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam2>"
+ "${Python2_EXECUTABLE}" -c "import spam2; spam2.system(\"cd\")")
diff --git a/Tests/FindPython/Python3/CMakeLists.txt b/Tests/FindPython/Python3/CMakeLists.txt
new file mode 100644
index 0000000..e40557d
--- /dev/null
+++ b/Tests/FindPython/Python3/CMakeLists.txt
@@ -0,0 +1,99 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPython3 LANGUAGES C)
+
+include(CTest)
+
+find_package(Python3 2 QUIET)
+if (Python3_FOUND)
+ message (FATAL_ERROR "Wrong python version found: ${Python3_VERSION}")
+endif()
+
+find_package(Python3 REQUIRED COMPONENTS Interpreter Development)
+if (NOT Python3_FOUND)
+ message (FATAL_ERROR "Failed to find Python 3")
+endif()
+if (NOT Python3_Development_FOUND)
+ message (FATAL_ERROR "Failed to find Python 3 'Development' component")
+endif()
+if (NOT Python3_Development.Module_FOUND)
+ message (FATAL_ERROR "Failed to find Python 3 'Development.Module' component")
+endif()
+if (NOT Python3_Development.Embed_FOUND)
+ message (FATAL_ERROR "Failed to find Python 3 'Development.Embed' component")
+endif()
+
+if(NOT TARGET Python3::Interpreter)
+ message(SEND_ERROR "Python3::Interpreter not found")
+endif()
+
+if(NOT TARGET Python3::Python)
+ message(SEND_ERROR "Python3::Python not found")
+endif()
+if(NOT TARGET Python3::Module)
+ message(SEND_ERROR "Python3::Module not found")
+endif()
+
+Python3_add_library (spam3 MODULE ../spam.c)
+target_compile_definitions (spam3 PRIVATE PYTHON3)
+
+add_test (NAME python3_spam3
+ COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam3>"
+ "${Python3_EXECUTABLE}" -c "import spam3; spam3.system(\"cd\")")
+
+add_test(NAME findpython3_script
+ COMMAND "${CMAKE_COMMAND}" -DPYTHON_PACKAGE_NAME=Python3
+ -DPython3_FIND_STRATEGY=${Python3_FIND_STRATEGY}
+ -P "${CMAKE_CURRENT_LIST_DIR}/../FindPythonScript.cmake")
+
+
+## Try a new search specifying only expected ABI
+# retrieve ABI of python interpreter
+execute_process (COMMAND "${Python3_EXECUTABLE}" -c
+ "import sys; sys.stdout.write(sys.abiflags)"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE abi
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+if (result)
+ # assume ABI is not supported
+ set (abi "")
+endif()
+
+# define FIND_ABI variable
+if (abi MATCHES "d")
+ set (Python3_VALID_ABI "ON")
+else()
+ set (Python3_VALID_ABI "OFF")
+endif()
+if (abi MATCHES "m")
+ list (APPEND Python3_VALID_ABI "ON")
+else()
+ list (APPEND Python3_VALID_ABI "OFF")
+endif()
+if (abi MATCHES "u")
+ list (APPEND Python3_VALID_ABI "ON")
+else()
+ list (APPEND Python3_VALID_ABI "OFF")
+endif()
+# build an invalid pattern for ABI
+set (Python3_INVALID_ABI)
+foreach (abi IN LISTS Python3_VALID_ABI)
+ if (abi)
+ list (APPEND Python3_INVALID_ABI "OFF")
+ else()
+ list (APPEND Python3_INVALID_ABI "ON")
+ endif()
+endforeach()
+
+add_test(NAME python3_find_valid_abi
+ COMMAND "${CMAKE_COMMAND}" -DPYTHON_PACKAGE_NAME=Python3
+ -DPython3_FIND_STRATEGY=${Python3_FIND_STRATEGY}
+ "-DPython3_FIND_ABI=${Python3_VALID_ABI}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/../FindPythonScript.cmake")
+add_test(NAME python3_find_invalid_abi
+ COMMAND "${CMAKE_COMMAND}" -DPYTHON_PACKAGE_NAME=Python3
+ -DPYTHON_MUST_NOT_BE_FOUND=ON
+ -DPython3_FIND_STRATEGY=${Python3_FIND_STRATEGY}
+ "-DPython3_FIND_ABI=${Python3_INVALID_ABI}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/../FindPythonScript.cmake")
diff --git a/Tests/FindPython/Python3Embedded/CMakeLists.txt b/Tests/FindPython/Python3Embedded/CMakeLists.txt
new file mode 100644
index 0000000..c45bd8c
--- /dev/null
+++ b/Tests/FindPython/Python3Embedded/CMakeLists.txt
@@ -0,0 +1,42 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPython3Embedded LANGUAGES C)
+
+include(CTest)
+
+find_package(Python3 REQUIRED COMPONENTS Development.Embed)
+if (NOT Python3_FOUND)
+ message (FATAL_ERROR "Failed to find Python 3")
+endif()
+if (Python3_Development_FOUND)
+ message (FATAL_ERROR "Python 3, COMPONENT 'Development' unexpectedly found")
+endif()
+if (Python3_Development.Module_FOUND)
+ message (FATAL_ERROR "Python 3, COMPONENT 'Development.Module' unexpectedly found")
+endif()
+if (NOT Python3_Development.Embed_FOUND)
+ message (FATAL_ERROR "Python 3, COMPONENT 'Development.Embed' not found")
+endif()
+
+if(TARGET Python3::Module)
+ message(SEND_ERROR "Python3::Module unexpectedly found")
+endif()
+
+if(NOT TARGET Python3::Python)
+ message(SEND_ERROR "Python3::Python not found")
+endif()
+
+Python3_add_library (display_time3 SHARED ../display_time.c)
+set_property (TARGET display_time3 PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON)
+target_compile_definitions (display_time3 PRIVATE PYTHON3)
+
+add_executable (main3 ../main.c)
+target_link_libraries (main3 PRIVATE display_time3)
+
+if (WIN32 OR CYGWIN OR MSYS OR MINGW)
+ list (JOIN Python3_RUNTIME_LIBRARY_DIRS "$<SEMICOLON>" RUNTIME_DIRS)
+ add_test (NAME Python3.Embedded COMMAND "${CMAKE_COMMAND}" -E env "PATH=${RUNTIME_DIRS}" $<TARGET_FILE:main3>)
+else()
+ add_test (NAME Python3.Embedded COMMAND main3)
+endif()
+set_property (TEST Python3.Embedded PROPERTY PASS_REGULAR_EXPRESSION "Today is")
diff --git a/Tests/FindPython/Python3Fail/CMakeLists.txt b/Tests/FindPython/Python3Fail/CMakeLists.txt
new file mode 100644
index 0000000..cd46c88
--- /dev/null
+++ b/Tests/FindPython/Python3Fail/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPython3Fail C)
+
+include(CTest)
+
+find_package(Python3 REQUIRED COMPONENTS Interpreter Development foobar)
+
+Python3_add_library (spam3 MODULE ../spam.c)
+target_compile_definitions (spam3 PRIVATE PYTHON3)
+
+add_test (NAME python3_spam3
+ COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam3>"
+ "${Python3_EXECUTABLE}" -c "import spam3; spam3.system(\"cd\")")
diff --git a/Tests/FindPython/Python3Module/CMakeLists.txt b/Tests/FindPython/Python3Module/CMakeLists.txt
new file mode 100644
index 0000000..5945962
--- /dev/null
+++ b/Tests/FindPython/Python3Module/CMakeLists.txt
@@ -0,0 +1,37 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPython3Module LANGUAGES C)
+
+include(CTest)
+
+find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module)
+if (NOT Python3_FOUND)
+ message (FATAL_ERROR "Failed to find Python 3")
+endif()
+if (Python3_Development_FOUND)
+ message (FATAL_ERROR "Python 3, COMPONENT 'Development' unexpectedly found")
+endif()
+if (Python3_Development.Embed_FOUND)
+ message (FATAL_ERROR "Python 3, COMPONENT 'Development.Embed' unexpectedly found")
+endif()
+if (NOT Python3_Development.Module_FOUND)
+ message (FATAL_ERROR "Python 3, COMPONENT 'Development.Module' not found")
+endif()
+
+if(NOT TARGET Python3::Interpreter)
+ message(SEND_ERROR "Python3::Interpreter not found")
+endif()
+
+if(TARGET Python3::Python)
+ message(SEND_ERROR "Python3::Python unexpectedly found")
+endif()
+if(NOT TARGET Python3::Module)
+ message(SEND_ERROR "Python3::Module not found")
+endif()
+
+Python3_add_library (spam3 MODULE ../spam.c)
+target_compile_definitions (spam3 PRIVATE PYTHON3)
+
+add_test (NAME python3_spam3
+ COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam3>"
+ "${Python3_EXECUTABLE}" -c "import spam3; spam3.system(\"cd\")")
diff --git a/Tests/FindPython/RequiredArtifacts/CMakeLists.txt b/Tests/FindPython/RequiredArtifacts/CMakeLists.txt
new file mode 100644
index 0000000..ae50f32
--- /dev/null
+++ b/Tests/FindPython/RequiredArtifacts/CMakeLists.txt
@@ -0,0 +1,110 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestRequiredArtifacts LANGUAGES C)
+
+include(CTest)
+
+find_package(Python2 REQUIRED COMPONENTS Interpreter Development)
+if (NOT Python2_FOUND)
+ message (FATAL_ERROR "Failed to find Python 2")
+endif()
+find_package(Python3 REQUIRED COMPONENTS Interpreter Development)
+if (NOT Python3_FOUND)
+ message (FATAL_ERROR "Failed to find Python 3")
+endif()
+
+
+add_test(NAME FindPython.RequiredArtifacts.Interpreter.VALID COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/RequiredArtifacts/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/RequiredArtifacts/Interpreter.VALID"
+ ${build_generator_args}
+ --build-project TestRequiredArtifacts.Check
+ --build-options -DPYTHON_IS_FOUND=TRUE -DCHECK_INTERPRETER=ON
+ "-DPython3_EXECUTABLE=${Python3_EXECUTABLE}"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+add_test(NAME FindPython.RequiredArtifacts.Interpreter.INVALID COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/RequiredArtifacts/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/RequiredArtifacts/Interpreter.INVALID"
+ ${build_generator_args}
+ --build-project TestRequiredArtifacts.Check
+ --build-options -DPYTHON_IS_FOUND=FALSE -DCHECK_INTERPRETER=ON
+ "-DPython3_EXECUTABLE=${Python3_EXECUTABLE}-bad${CMAKE_EXECUTABLE_SUFFIX}"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+add_test(NAME FindPython.RequiredArtifacts.Library.VALID COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/RequiredArtifacts/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/RequiredArtifacts/Library.VALID"
+ ${build_generator_args}
+ --build-project TestRequiredArtifacts.Check
+ --build-options -DPYTHON_IS_FOUND=TRUE -DCHECK_LIBRARY=ON
+ "-DPython3_LIBRARY=${Python3_LIBRARY_RELEASE}"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+add_test(NAME FindPython.RequiredArtifacts.Library.INVALID COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/RequiredArtifacts/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/RequiredArtifacts/Library.INVALID"
+ ${build_generator_args}
+ --build-project TestRequiredArtifacts.Check
+ --build-options -DPYTHON_IS_FOUND=FALSE -DCHECK_LIBRARY=ON
+ "-DPython3_LIBRARY=${Python2_LIBRARY_RELEASE}"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+add_test(NAME FindPython.RequiredArtifacts.Include.VALID COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/RequiredArtifacts/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/RequiredArtifacts/Include.VALID"
+ ${build_generator_args}
+ --build-project TestRequiredArtifacts.Check
+ --build-options -DPYTHON_IS_FOUND=TRUE -DCHECK_INCLUDE=ON
+ "-DPython3_INCLUDE_DIR=${Python3_INCLUDE_DIRS}"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+add_test(NAME FindPython.RequiredArtifacts.Include.INVALID COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/RequiredArtifacts/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/RequiredArtifacts/Include.INVALID"
+ ${build_generator_args}
+ --build-project TestRequiredArtifacts.Check
+ --build-options -DPYTHON_IS_FOUND=FALSE -DCHECK_INCLUDE=ON
+ "-DPython3_INCLUDE_DIR=${Python2_INCLUDE_DIRS}"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+add_test(NAME FindPython.RequiredArtifacts.Interpreter-Library.INVALID COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/RequiredArtifacts/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/RequiredArtifacts/Interpreter-Library.INVALID"
+ ${build_generator_args}
+ --build-project TestRequiredArtifacts.Check
+ --build-options -DPYTHON_IS_FOUND=FALSE -DCHECK_INTERPRETER=ON -DCHECK_LIBRARY=ON
+ "-DPython3_EXECUTABLE=${Python3_EXECUTABLE}"
+ "-DPython3_LIBRARY=${Python2_LIBRARY_RELEASE}"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+add_test(NAME FindPython.RequiredArtifacts.Library-Include.INVALID COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/RequiredArtifacts/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/RequiredArtifacts/Library-Include.INVALID"
+ ${build_generator_args}
+ --build-project TestRequiredArtifacts.Check
+ --build-options -DPYTHON_IS_FOUND=FALSE -DCHECK_LIBRARY=ON -DCHECK_INCLUDE=ON
+ "-DPython3_LIBRARY=${Python3_LIBRARY_RELEASE}"
+ "-DPython3_INCLUDE_DIR=${Python2_INCLUDE_DIRS}"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindPython/RequiredArtifacts/Check/CMakeLists.txt b/Tests/FindPython/RequiredArtifacts/Check/CMakeLists.txt
new file mode 100644
index 0000000..287cfdb
--- /dev/null
+++ b/Tests/FindPython/RequiredArtifacts/Check/CMakeLists.txt
@@ -0,0 +1,41 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestRequiredArtifacts.Check LANGUAGES C)
+
+set (components)
+if (CHECK_INTERPRETER)
+ set (required_interpreter "${Python3_EXECUTABLE}")
+ list (APPEND components Interpreter)
+endif()
+if (CHECK_LIBRARY OR CHECK_INCLUDE)
+ list (APPEND components Development)
+ if (CHECK_LIBRARY)
+ set (required_library "${Python3_LIBRARY}")
+ endif()
+ if (CHECK_INCLUDE)
+ set (required_include "${Python3_INCLUDE_DIR}")
+ endif()
+endif()
+
+find_package (Python3 COMPONENTS ${components})
+
+
+if (PYTHON_IS_FOUND AND NOT Python3_FOUND)
+ message (FATAL_ERROR "Python3 unexpectedly not found")
+endif()
+if (NOT PYTHON_IS_FOUND AND Python3_FOUND)
+ message (FATAL_ERROR "Python3 unexpectedly found")
+endif()
+
+
+if (CHECK_INTERPRETER AND NOT Python3_EXECUTABLE STREQUAL required_interpreter)
+ message (FATAL_ERROR "Failed to use input variable Python3_EXECUTABLE")
+endif()
+
+if (CHECK_LIBRARY AND NOT Python3_LIBRARY_RELEASE STREQUAL required_library)
+ message (FATAL_ERROR "Failed to use input variable Python3_LIBRARY")
+endif()
+
+if (CHECK_INCLUDE AND NOT Python3_INCLUDE_DIRS STREQUAL required_include)
+ message (FATAL_ERROR "Failed to use input variable Python3_INCLUDE_DIR")
+endif()
diff --git a/Tests/FindPython/SOABI/CMakeLists.txt b/Tests/FindPython/SOABI/CMakeLists.txt
new file mode 100644
index 0000000..84f7362
--- /dev/null
+++ b/Tests/FindPython/SOABI/CMakeLists.txt
@@ -0,0 +1,38 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestSOABI LANGUAGES C)
+
+find_package(Python3 COMPONENTS ${CMake_TEST_FindPython_COMPONENT})
+if (NOT Python3_FOUND)
+ message (FATAL_ERROR "Failed to find Python 3")
+endif()
+
+if(NOT DEFINED Python3_SOABI)
+ message(FATAL_ERROR "Python3_SOABI for ${CMake_TEST_FindPython_COMPONENT} not found")
+endif()
+
+if (Python3_Development_FOUND AND Python3_SOABI)
+ Python3_add_library (spam3 MODULE WITH_SOABI ../spam.c)
+ target_compile_definitions (spam3 PRIVATE PYTHON3)
+
+ get_property (suffix TARGET spam3 PROPERTY SUFFIX)
+ if (NOT suffix MATCHES "^.${Python3_SOABI}")
+ message(FATAL_ERROR "Module suffix do not include Python3_SOABI")
+ endif()
+endif()
+
+
+find_package(Python2 COMPONENTS ${CMake_TEST_FindPython_COMPONENT})
+if(NOT DEFINED Python2_SOABI)
+ message(FATAL_ERROR "Python2_SOABI for ${CMake_TEST_FindPython_COMPONENT} not found")
+endif()
+
+if (Python2_Development_FOUND AND Python2_SOABI)
+ Python2_add_library (spam2 MODULE WITH_SOABI ../spam.c)
+ target_compile_definitions (spam2 PRIVATE PYTHON2)
+
+ get_property (suffix TARGET spam2 PROPERTY SUFFIX)
+ if (NOT suffix MATCHES "^.${Python2_SOABI}")
+ message(FATAL_ERROR "Module suffix do not include Python2_SOABI")
+ endif()
+endif()
diff --git a/Tests/FindPython/UnversionedNames/CMakeLists.txt b/Tests/FindPython/UnversionedNames/CMakeLists.txt
new file mode 100644
index 0000000..597bd4e
--- /dev/null
+++ b/Tests/FindPython/UnversionedNames/CMakeLists.txt
@@ -0,0 +1,66 @@
+cmake_minimum_required(VERSION 3.19...3.20)
+
+project(UnversionedNames LANGUAGES NONE)
+
+# check if it is possible to find python with a generic name
+find_program(UNVERSIONED_Python3 NAMES python3)
+
+if (NOT UNVERSIONED_Python3)
+ # no generic name available
+ # test cannot be done
+ return()
+endif()
+
+# search with default configuration
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+
+if (Python3_EXECUTABLE STREQUAL UNVERSIONED_Python3)
+ # default configuration pick-up the generic name
+ # test cannot be completed
+ return()
+endif()
+
+unset(Python3_EXECUTABLE)
+# Force now to search first for generic name
+set(Python3_FIND_UNVERSIONED_NAMES FIRST)
+
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+
+if (NOT Python3_EXECUTABLE STREQUAL UNVERSIONED_Python3)
+ message(SEND_ERROR "Found unexpected interpreter ${Python3_EXECUTABLE} instead of ${UNVERSIONED_Python3}")
+endif()
+
+# To check value 'NEVER", creates directory holding a symlink to the generic name
+file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/bin")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
+file(CREATE_LINK "${UNVERSIONED_Python3}" "${CMAKE_CURRENT_BINARY_DIR}/bin/python3" SYMBOLIC)
+
+unset(Python3_EXECUTABLE)
+set(Python3_FIND_UNVERSIONED_NAMES FIRST)
+set(Python3_ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+# First search: generic name must be found
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+
+if (NOT Python3_EXECUTABLE STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/bin/python3")
+ message(FATAL_ERROR "Found unexpected interpreter ${Python3_EXECUTABLE} instead of ${CMAKE_CURRENT_BINARY_DIR}/bin/python3")
+endif()
+
+unset(Python3_EXECUTABLE)
+set(Python3_FIND_UNVERSIONED_NAMES LAST)
+
+# Second search: generic name must be found
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+
+if (NOT Python3_EXECUTABLE STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/bin/python3")
+ message(FATAL_ERROR "Found unexpected interpreter ${Python3_EXECUTABLE} instead of ${CMAKE_CURRENT_BINARY_DIR}/bin/python3")
+endif()
+
+unset(Python3_EXECUTABLE)
+set(Python3_FIND_UNVERSIONED_NAMES NEVER)
+
+# Third search: generic name must NOT be found
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+
+if (Python3_EXECUTABLE STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/bin/python3")
+ message(FATAL_ERROR "Found unexpected interpreter ${Python3_EXECUTABLE}")
+endif()
diff --git a/Tests/FindPython/VersionRange/CMakeLists.txt b/Tests/FindPython/VersionRange/CMakeLists.txt
new file mode 100644
index 0000000..957941d
--- /dev/null
+++ b/Tests/FindPython/VersionRange/CMakeLists.txt
@@ -0,0 +1,64 @@
+cmake_minimum_required (VERSION 3.18...3.19)
+
+project (TestVersionRange LANGUAGES C)
+
+
+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 RANGE)
+ macro (FIND_PYTHON_PACKAGE)
+ unset (_${Python}_EXECUTABLE CACHE)
+ unset (_${Python}_LIBRARY_RELEASE CACHE)
+ unset (_${Python}_INCLUDE_DIR CACHE)
+ unset (${Python}_FOUND)
+
+ find_package (${Python} ${ARGV})
+ endmacro()
+
+ find_python_package(${RANGE} ${ARGN})
+
+ if (EXPECTED_VERSION STREQUAL "NONE")
+ while (${Python}_FOUND AND ${Python}_VERSION VERSION_GREATER ${Python_REQUESTED_VERSION})
+ # Possible if multiple versions are installed
+ # Try with a different range
+ find_python_package(${Python_REQUESTED_VERSION}.0...<${${Python}_VERSION} ${ARGN})
+ endwhile()
+ if (${Python}_FOUND)
+ message (SEND_ERROR "Unexpectedly found version: ${${Python}_VERSION} for '${Python} ${Python_REQUESTED_VERSION}.0...<${${Python}_VERSION} ${ARGN}'")
+ endif()
+ return()
+ endif()
+
+ if (NOT ${Python}_FOUND)
+ message (SEND_ERROR "Not found: ${Python} ${RANGE} ${ARGN}")
+ elseif (NOT ${Python}_VERSION VERSION_EQUAL EXPECTED_VERSION)
+ message (SEND_ERROR "Wrong version: ${${Python}_VERSION} for '${Python} ${RANGE} ${ARGN}'")
+ endif()
+endfunction()
+
+find_python (${${Python}_VERSION} ${IN_VERSION_RANGE} COMPONENTS Interpreter)
+if (${Python}_FIND_IMPLEMENTATIONS STREQUAL "IronPython")
+ find_python (${${Python}_VERSION} ${IN_VERSION_RANGE} COMPONENTS Compiler)
+else()
+ find_python (${${Python}_VERSION} ${IN_VERSION_RANGE} COMPONENTS Development)
+endif()
+
+find_python ("NONE" ${OUT_VERSION_RANGE} COMPONENTS Interpreter)
+if (${Python}_FIND_IMPLEMENTATIONS STREQUAL "IronPython")
+ find_python ("NONE" ${OUT_VERSION_RANGE} COMPONENTS Compiler)
+else()
+ find_python ("NONE" ${OUT_VERSION_RANGE} COMPONENTS Development)
+endif()
+
+find_python ("NONE" 5...6 COMPONENTS Interpreter)
diff --git a/Tests/FindPython/VirtualEnv/CMakeLists.txt b/Tests/FindPython/VirtualEnv/CMakeLists.txt
new file mode 100644
index 0000000..dae3282
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/CMakeLists.txt
@@ -0,0 +1,47 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestVirtualEnv LANGUAGES NONE)
+
+include(CTest)
+
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+if (NOT Python3_FOUND)
+ message (FATAL_ERROR "Failed to find Python 3")
+endif()
+
+set (Python3_VIRTUAL_ENV "${CMAKE_CURRENT_BINARY_DIR}/py3venv")
+file (REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/py3venv")
+
+execute_process (COMMAND "${Python3_EXECUTABLE}" -m venv "${Python3_VIRTUAL_ENV}"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE outputs
+ ERROR_VARIABLE outputs)
+if (result)
+ message (FATAL_ERROR "Fail to create virtual environment: ${outputs}")
+endif()
+
+add_test(NAME FindPython3.VirtualEnvDefault
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ --unset=CONDA_PREFIX
+ "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvDefault.cmake")
+
+add_test(NAME FindPython3.VirtualEnvOnly
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ --unset=CONDA_PREFIX
+ "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+add_test(NAME FindPython3.UnsetVirtualEnvOnly
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ --unset=VIRTUAL_ENV
+ --unset=CONDA_PREFIX
+ "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+
+add_test(NAME FindPython3.VirtualEnvStandard
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ --unset=CONDA_PREFIX
+ "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvStandard.cmake")
diff --git a/Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake b/Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake
new file mode 100644
index 0000000..020ecac
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake
@@ -0,0 +1,6 @@
+
+find_package (Python3 REQUIRED)
+
+if (NOT Python3_EXECUTABLE MATCHES "^${PYTHON3_VIRTUAL_ENV}/.+")
+ message (FATAL_ERROR "Fail to use virtual environment")
+endif()
diff --git a/Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake b/Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake
new file mode 100644
index 0000000..29a4924
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake
@@ -0,0 +1,16 @@
+
+#
+# Virtual environment is defined for python3
+# Trying to find a python2 using only virtual environment
+# It is expecting to fail if a virtual environment is active and to success otherwise.
+#
+set (Python2_FIND_VIRTUALENV ONLY)
+find_package (Python2 QUIET)
+
+if (PYTHON3_VIRTUAL_ENV AND Python2_FOUND)
+ message (FATAL_ERROR "Python2 unexpectedly found.")
+endif()
+
+if (NOT PYTHON3_VIRTUAL_ENV AND NOT Python2_FOUND)
+ message (FATAL_ERROR "Fail to find Python2.")
+endif()
diff --git a/Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake b/Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake
new file mode 100644
index 0000000..89f27d8
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake
@@ -0,0 +1,7 @@
+
+set (Python3_FIND_VIRTUALENV STANDARD)
+find_package (Python3 REQUIRED)
+
+if (Python3_EXECUTABLE MATCHES "^${PYTHON3_VIRTUAL_ENV}/.+")
+ message (FATAL_ERROR "Python3 virtual env unexpectedly found.")
+endif()
diff --git a/Tests/FindPython/VirtualEnvConda/CMakeLists.txt b/Tests/FindPython/VirtualEnvConda/CMakeLists.txt
new file mode 100644
index 0000000..23d208d
--- /dev/null
+++ b/Tests/FindPython/VirtualEnvConda/CMakeLists.txt
@@ -0,0 +1,46 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestVirtualEnvConda LANGUAGES NONE)
+
+include(CTest)
+
+find_program(CONDA_EXECUTABLE conda)
+if (CONDA_EXECUTABLE EQUAL NOTFOUND)
+ message (FATAL_ERROR "Failed to find Conda")
+endif()
+
+set (Python3_VIRTUAL_ENV "${CMAKE_CURRENT_BINARY_DIR}/condaenv")
+
+execute_process (COMMAND "${CONDA_EXECUTABLE}" create --no-default-packages --prefix "${Python3_VIRTUAL_ENV}" --yes python=3
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE outputs
+ ERROR_VARIABLE outputs)
+if (result)
+ message (FATAL_ERROR "Fail to create virtual environment: ${outputs}")
+endif()
+
+add_test(NAME FindPython3.VirtualEnvDefaultConda
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ --unset=VIRTUAL_ENV
+ "CONDA_PREFIX=${Python3_VIRTUAL_ENV}"
+ "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvDefault.cmake")
+
+add_test(NAME FindPython3.VirtualEnvOnlyConda
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ --unset=VIRTUAL_ENV
+ "CONDA_PREFIX=${Python3_VIRTUAL_ENV}"
+ "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+add_test(NAME FindPython3.UnsetVirtualEnvOnlyConda
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ --unset=CONDA_PREFIX
+ --unset=VIRTUAL_ENV
+ "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+
+add_test(NAME FindPython3.VirtualEnvStandardConda
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ --unset=VIRTUAL_ENV
+ "CONDA_PREFIX=${Python3_VIRTUAL_ENV}"
+ "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvStandard.cmake")
diff --git a/Tests/FindPython/VirtualEnvConda/VirtualEnvDefault.cmake b/Tests/FindPython/VirtualEnvConda/VirtualEnvDefault.cmake
new file mode 100644
index 0000000..020ecac
--- /dev/null
+++ b/Tests/FindPython/VirtualEnvConda/VirtualEnvDefault.cmake
@@ -0,0 +1,6 @@
+
+find_package (Python3 REQUIRED)
+
+if (NOT Python3_EXECUTABLE MATCHES "^${PYTHON3_VIRTUAL_ENV}/.+")
+ message (FATAL_ERROR "Fail to use virtual environment")
+endif()
diff --git a/Tests/FindPython/VirtualEnvConda/VirtualEnvOnly.cmake b/Tests/FindPython/VirtualEnvConda/VirtualEnvOnly.cmake
new file mode 100644
index 0000000..29a4924
--- /dev/null
+++ b/Tests/FindPython/VirtualEnvConda/VirtualEnvOnly.cmake
@@ -0,0 +1,16 @@
+
+#
+# Virtual environment is defined for python3
+# Trying to find a python2 using only virtual environment
+# It is expecting to fail if a virtual environment is active and to success otherwise.
+#
+set (Python2_FIND_VIRTUALENV ONLY)
+find_package (Python2 QUIET)
+
+if (PYTHON3_VIRTUAL_ENV AND Python2_FOUND)
+ message (FATAL_ERROR "Python2 unexpectedly found.")
+endif()
+
+if (NOT PYTHON3_VIRTUAL_ENV AND NOT Python2_FOUND)
+ message (FATAL_ERROR "Fail to find Python2.")
+endif()
diff --git a/Tests/FindPython/VirtualEnvConda/VirtualEnvStandard.cmake b/Tests/FindPython/VirtualEnvConda/VirtualEnvStandard.cmake
new file mode 100644
index 0000000..89f27d8
--- /dev/null
+++ b/Tests/FindPython/VirtualEnvConda/VirtualEnvStandard.cmake
@@ -0,0 +1,7 @@
+
+set (Python3_FIND_VIRTUALENV STANDARD)
+find_package (Python3 REQUIRED)
+
+if (Python3_EXECUTABLE MATCHES "^${PYTHON3_VIRTUAL_ENV}/.+")
+ message (FATAL_ERROR "Python3 virtual env unexpectedly found.")
+endif()
diff --git a/Tests/FindPython/display_time.c b/Tests/FindPython/display_time.c
new file mode 100644
index 0000000..0e78434
--- /dev/null
+++ b/Tests/FindPython/display_time.c
@@ -0,0 +1,36 @@
+
+#include <stdio.h>
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include "display_time.h"
+
+void display_time()
+{
+#if defined(PYTHON3)
+ wchar_t* program = Py_DecodeLocale("display_time", NULL);
+ if (program == NULL) {
+ fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
+ exit(1);
+ }
+ char* cmd = "from time import time,ctime\n"
+ "print('Today is', ctime(time()))\n";
+#else
+ char* program = "display_time";
+ char* cmd = "from time import time,ctime\n"
+ "print 'Today is', ctime(time())\n";
+#endif
+
+ Py_SetProgramName(program); /* optional but recommended */
+ Py_Initialize();
+ PyRun_SimpleString(cmd);
+#if defined(PYTHON3)
+ if (Py_FinalizeEx() < 0) {
+ exit(120);
+ }
+ PyMem_RawFree(program);
+#else
+ Py_Finalize();
+#endif
+}
diff --git a/Tests/FindPython/display_time.h b/Tests/FindPython/display_time.h
new file mode 100644
index 0000000..d825e02
--- /dev/null
+++ b/Tests/FindPython/display_time.h
@@ -0,0 +1,2 @@
+
+void display_time();
diff --git a/Tests/FindPython/main.c b/Tests/FindPython/main.c
new file mode 100644
index 0000000..0acba29
--- /dev/null
+++ b/Tests/FindPython/main.c
@@ -0,0 +1,7 @@
+
+#include "display_time.h"
+
+int main()
+{
+ display_time();
+}
diff --git a/Tests/FindPython/spam.c b/Tests/FindPython/spam.c
new file mode 100644
index 0000000..1c65d54
--- /dev/null
+++ b/Tests/FindPython/spam.c
@@ -0,0 +1,41 @@
+
+#include <Python.h>
+
+static PyObject* spam_system(PyObject* self, PyObject* args)
+{
+ const char* command;
+ int sts;
+
+ if (!PyArg_ParseTuple(args, "s", &command))
+ return NULL;
+ sts = system(command);
+ /* return PyLong_FromLong(sts); */
+ return Py_BuildValue("i", sts);
+}
+
+static PyMethodDef SpamMethods[] = {
+ { "system", spam_system, METH_VARARGS, "Execute a shell command." },
+ { NULL, NULL, 0, NULL } /* Sentinel */
+};
+
+#if defined(PYTHON2)
+PyMODINIT_FUNC initspam2(void)
+{
+ (void)Py_InitModule("spam2", SpamMethods);
+}
+#endif
+
+#if defined(PYTHON3)
+static struct PyModuleDef spammodule = {
+ PyModuleDef_HEAD_INIT, "spam3", /* name of module */
+ NULL, /* module documentation, may be NULL */
+ -1, /* size of per-interpreter state of the module,
+ or -1 if the module keeps state in global variables. */
+ SpamMethods
+};
+
+PyMODINIT_FUNC PyInit_spam3(void)
+{
+ return PyModule_Create(&spammodule);
+}
+#endif
diff --git a/Tests/FindRuby/CMakeLists.txt b/Tests/FindRuby/CMakeLists.txt
new file mode 100644
index 0000000..ee58923
--- /dev/null
+++ b/Tests/FindRuby/CMakeLists.txt
@@ -0,0 +1,57 @@
+if(CMake_TEST_FindRuby)
+
+ # Looks for ruby >=1.9.9, which is true on any Ubuntu (that installs it) or macOS (> 10.9)
+ add_test(NAME FindRuby.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindRuby/Test"
+ "${CMake_BINARY_DIR}/Tests/FindRuby/Test"
+ ${build_generator_args}
+ --build-project TestRuby
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+
+ # Looks for ruby >= 50.1.0, which should logically fail
+ add_test(NAME FindRuby.Fail COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindRuby/Fail"
+ "${CMake_BINARY_DIR}/Tests/FindRuby/Fail"
+ ${build_generator_args}
+ --build-project TestRubyFail
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ set_tests_properties(FindRuby.Fail PROPERTIES
+ PASS_REGULAR_EXPRESSION "Could NOT find Ruby.*(Required[ \n]+is[ \n]+at[ \n]+least[ \n]+version[ \n]*\"[0-9]+\\.[0-9]+\\.[0-9]+\")")
+
+ # Looks for 1.9.9 EXACTLY, which unlike the "FindRuby" test above will fail on every machine
+ # since this version doesn't exist (ruby goes from 1.9.3 to 2.0.0)
+ add_test(NAME FindRuby.FailExact COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindRuby/FailExact"
+ "${CMake_BINARY_DIR}/Tests/FindRuby/FailExact"
+ ${build_generator_args}
+ --build-project TestRubyFailExact
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ set_tests_properties(FindRuby.FailExact PROPERTIES
+ PASS_REGULAR_EXPRESSION "Could NOT find Ruby: Found unsuitable version \".*\", but required is.*exact version \"[0-9]+\\.[0-9]+\\.[0-9]+\" \\(found .*\\)")
+
+ # RVM specific test
+ if(CMake_TEST_FindRuby_RVM)
+ add_test(NAME FindRuby.Rvm COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindRuby/Rvm"
+ "${CMake_BINARY_DIR}/Tests/FindRuby/Rvm"
+ ${build_generator_args}
+ --build-project TestRVM
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ endif()
+endif()
diff --git a/Tests/FindRuby/Fail/CMakeLists.txt b/Tests/FindRuby/Fail/CMakeLists.txt
new file mode 100644
index 0000000..9185ba5
--- /dev/null
+++ b/Tests/FindRuby/Fail/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.17)
+project(TestRubyFail LANGUAGES NONE)
+
+# Should always fail since there is NO ruby 50.1.0 yet.
+find_package(Ruby 50.1.0 REQUIRED)
diff --git a/Tests/FindRuby/FailExact/CMakeLists.txt b/Tests/FindRuby/FailExact/CMakeLists.txt
new file mode 100644
index 0000000..1ebc0ae
--- /dev/null
+++ b/Tests/FindRuby/FailExact/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.17)
+project(TestRubyFailExact LANGUAGES NONE)
+
+# Should always fail since there is NO ruby 1.9.9 (goes from 1.9.3 to 2.0.0)
+find_package(Ruby 1.9.9 EXACT REQUIRED)
+if (NOT Ruby_FOUND)
+ message (FATAL_ERROR "Failed to find Ruby 1.9.9")
+endif()
diff --git a/Tests/FindRuby/Rvm/CMakeLists.txt b/Tests/FindRuby/Rvm/CMakeLists.txt
new file mode 100644
index 0000000..14bdbec
--- /dev/null
+++ b/Tests/FindRuby/Rvm/CMakeLists.txt
@@ -0,0 +1,75 @@
+cmake_minimum_required(VERSION 3.17)
+project(TestRVM LANGUAGES NONE)
+
+include(CTest)
+
+# To run this test, you need to have at least one RVM ruby installed
+# and to ensure that the env variable 'MY_RUBY_HOME' is set to a valid RVM ruby when you run the test
+# (which is the case if you have done `rvm use x.y.z`, but could be manually set too)
+
+# Properly using rvm would require sourcing a shell script, eg `source "$HOME/.rvm/scripts/rvm"`
+# Instead, I'll just rely on the env variable MY_RUBY_HOME
+set(MY_RUBY_HOME "$ENV{MY_RUBY_HOME}")
+if(NOT MY_RUBY_HOME)
+ message(FATAL_ERROR "Env variable MY_RUBY_HOME should be set to a valid RVM ruby location, or you should call `rvm use x.y.z` before")
+endif()
+execute_process (COMMAND "${MY_RUBY_HOME}/bin/ruby" -e "puts RUBY_VERSION"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE RVM_RUBY_VERSION
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+if (result)
+ message (FATAL_ERROR "Unable to detect RVM ruby version from `${MY_RUBY_HOME}/bin/ruby`: ${RVM_RUBY_VERSION}")
+endif()
+
+execute_process(COMMAND "${CMAKE_COMMAND}" -E env --unset=MY_RUBY_HOME PATH=/usr/bin:/bin
+ "which" "ruby"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE SYSTEM_RUBY
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+if (SYSTEM_RUBY MATCHES "^${MY_RUBY_HOME}/.+")
+ message(FATAL_ERROR "Unable to find system ruby, found ${SYSTEM_RUBY} which is part of MY_RUBY_HOME=${MY_RUBY_HOME}")
+endif()
+
+# Check version of the system ruby executable.
+execute_process (COMMAND "${SYSTEM_RUBY}" -e "puts RUBY_VERSION"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE SYSTEM_RUBY_VERSION
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+if (result)
+ message (FATAL_ERROR "Unable to detect system ruby version from '${SYSTEM_RUBY}': ${SYSTEM_RUBY_VERSION}")
+endif()
+
+if(SYSTEM_RUBY_VERSION VERSION_EQUAL RVM_RUBY_VERSION)
+ message(FATAL_ERROR "Your RVM Ruby Version and your System ruby version are the same (${RVM_RUBY_VERSION}).")
+endif()
+
+message("Found System Ruby (${SYSTEM_RUBY_VERSION}): ${SYSTEM_RUBY}")
+message("Found RVM Ruby (${RVM_RUBY_VERSION}): ${MY_RUBY_HOME}/bin/ruby")
+
+add_test(NAME FindRuby.RvmDefault
+ COMMAND "${CMAKE_COMMAND}" -E env "MY_RUBY_HOME=${MY_RUBY_HOME}"
+ "${CMAKE_COMMAND}" "-DRUBY_HOME=${MY_RUBY_HOME}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/RvmDefault.cmake")
+
+add_test(NAME FindRuby.RvmOnly
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PATH
+ "MY_RUBY_HOME=${MY_RUBY_HOME}"
+ "${CMAKE_COMMAND}" "-DRUBY_HOME=${MY_RUBY_HOME}"
+ "-DRVM_RUBY_VERSION=${RVM_RUBY_VERSION}" "-DSYSTEM_RUBY_VERSION=${SYSTEM_RUBY_VERSION}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/RvmOnly.cmake")
+add_test(NAME FindRuby.UnsetRvmOnly
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=MY_RUBY_HOME "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
+ "${CMAKE_COMMAND}" "-DRVM_RUBY_VERSION=${RVM_RUBY_VERSION}" "-DSYSTEM_RUBY_VERSION=${SYSTEM_RUBY_VERSION}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/RvmOnly.cmake")
+
+add_test(NAME FindRuby.RvmStandard
+ COMMAND "${CMAKE_COMMAND}" -E env "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
+ "MY_RUBY_HOME=${MY_RUBY_HOME}"
+ "${CMAKE_COMMAND}" "-DRUBY_HOME=${MY_RUBY_HOME}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/RvmStandard.cmake")
diff --git a/Tests/FindRuby/Rvm/RvmDefault.cmake b/Tests/FindRuby/Rvm/RvmDefault.cmake
new file mode 100644
index 0000000..a66b911
--- /dev/null
+++ b/Tests/FindRuby/Rvm/RvmDefault.cmake
@@ -0,0 +1,17 @@
+set(CMAKE_FIND_LIBRARY_PREFIXES "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES "")
+
+find_package (Ruby 2.1.1 REQUIRED)
+if (NOT RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
+ message (FATAL_ERROR "Failed to use RVM environment: ${RUBY_EXECUTABLE}, ${RUBY_HOME}")
+endif()
+
+find_package (Ruby 2.1 REQUIRED)
+if (NOT RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
+ message (FATAL_ERROR "Failed to use RVM environment: ${RUBY_EXECUTABLE}, ${RUBY_HOME}")
+endif()
+
+find_package (Ruby REQUIRED)
+if (NOT RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
+ message (FATAL_ERROR "Failed to use RVM environment: ${RUBY_EXECUTABLE}, ${RUBY_HOME}")
+endif()
diff --git a/Tests/FindRuby/Rvm/RvmOnly.cmake b/Tests/FindRuby/Rvm/RvmOnly.cmake
new file mode 100644
index 0000000..3851a7c
--- /dev/null
+++ b/Tests/FindRuby/Rvm/RvmOnly.cmake
@@ -0,0 +1,41 @@
+set(CMAKE_FIND_LIBRARY_PREFIXES "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES "")
+
+set(Ruby_FIND_VIRTUALENV ONLY)
+
+# Test: FindRuby.RvmOnly
+if (RUBY_HOME)
+ # => Trying to find exactly system ruby using ONLY virtual environment should fail
+ find_package (Ruby ${SYSTEM_RUBY_VERSION} EXACT QUIET)
+ if(Ruby_FOUND)
+ message (FATAL_ERROR "Ruby unexpectedly found.")
+ endif()
+ # And should work to find the rvm version
+ find_package (Ruby ${RVM_RUBY_VERSION} EXACT QUIET)
+ if(Ruby_FOUND)
+ message (FATAL_ERROR "Ruby unexpectedly found.")
+ endif()
+endif()
+
+
+# Test: FindRuby.UnsetRvmOnly
+if (NOT RUBY_HOME)
+
+ # If ENV{MY_RUBY_HOME} isn't defined, it should default back to "STANDARD"
+ # At which point:
+
+ # It shouldn't find the RVM ruby
+ find_package (Ruby ${RVM_RUBY_VERSION} EXACT QUIET)
+ if(Ruby_FOUND)
+ message(FATAL_ERROR "Found RVM ruby when expecting system")
+ endif()
+
+ # it should find the system ruby
+ find_package (Ruby ${SYSTEM_RUBY_VERSION} EXACT QUIET)
+ if(NOT Ruby_FOUND)
+ message (FATAL_ERROR "Ruby not found.")
+ endif()
+ if (Ruby_FOUND MATCHES "^${RUBY_HOME}/.+")
+ message(FATAL_ERROR "Failed to find system ruby")
+ endif()
+endif()
diff --git a/Tests/FindRuby/Rvm/RvmStandard.cmake b/Tests/FindRuby/Rvm/RvmStandard.cmake
new file mode 100644
index 0000000..26befdb7
--- /dev/null
+++ b/Tests/FindRuby/Rvm/RvmStandard.cmake
@@ -0,0 +1,9 @@
+set(CMAKE_FIND_LIBRARY_PREFIXES "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES "")
+
+set (Ruby_FIND_VIRTUALENV STANDARD)
+find_package (Ruby REQUIRED)
+
+if (RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
+ message (FATAL_ERROR "RVM ruby unexpectedly found at ${RUBY_EXECUTABLE}, matches ${RUBY_HOME}")
+endif()
diff --git a/Tests/FindRuby/Test/CMakeLists.txt b/Tests/FindRuby/Test/CMakeLists.txt
new file mode 100644
index 0000000..dcf3ec3
--- /dev/null
+++ b/Tests/FindRuby/Test/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.17)
+project(TestRuby LANGUAGES C)
+include(CTest)
+
+find_package(Ruby 1.9.9 REQUIRED)
+if (NOT Ruby_FOUND)
+ message (FATAL_ERROR "Failed to find Ruby >=1.9.9")
+endif()
+
+add_executable(ruby_version ruby_version.c)
+target_include_directories(ruby_version PRIVATE ${Ruby_INCLUDE_DIRS})
+target_link_libraries(ruby_version PRIVATE ${Ruby_LIBRARIES})
+
+add_test(NAME ruby_version COMMAND ruby_version)
diff --git a/Tests/FindRuby/Test/ruby_version.c b/Tests/FindRuby/Test/ruby_version.c
new file mode 100644
index 0000000..8800436
--- /dev/null
+++ b/Tests/FindRuby/Test/ruby_version.c
@@ -0,0 +1,7 @@
+#include "ruby.h"
+
+int main(void)
+{
+ ruby_show_version();
+ return 0;
+}
diff --git a/Tests/FindSDL/CMakeLists.txt b/Tests/FindSDL/CMakeLists.txt
new file mode 100644
index 0000000..e786204
--- /dev/null
+++ b/Tests/FindSDL/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindSDL.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindSDL/Test"
+ "${CMake_BINARY_DIR}/Tests/FindSDL/Test"
+ ${build_generator_args}
+ --build-project TestFindSDL
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindSDL/Test/CMakeLists.txt b/Tests/FindSDL/Test/CMakeLists.txt
new file mode 100644
index 0000000..61d4f4b
--- /dev/null
+++ b/Tests/FindSDL/Test/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindSDL C)
+include(CTest)
+
+find_package(SDL)
+
+add_definitions(
+ -DCMAKE_EXPECTED_SDL_VERSION_MAJOR=${SDL_VERSION_MAJOR}
+ -DCMAKE_EXPECTED_SDL_VERSION_MINOR=${SDL_VERSION_MINOR}
+ -DCMAKE_EXPECTED_SDL_VERSION_PATCH=${SDL_VERSION_PATCH})
+
+add_executable(test_sdl_tgt main.c)
+target_link_libraries(test_sdl_tgt SDL::SDL)
+add_test(NAME test_sdl_tgt COMMAND test_sdl_tgt)
+
+add_executable(test_sdl_var main.c)
+target_include_directories(test_sdl_var PRIVATE ${SDL_INCLUDE_DIRS})
+target_link_libraries(test_sdl_var PRIVATE ${SDL_LIBRARIES})
+add_test(NAME test_sdl_var COMMAND test_sdl_var)
diff --git a/Tests/FindSDL/Test/main.c b/Tests/FindSDL/Test/main.c
new file mode 100644
index 0000000..057289c
--- /dev/null
+++ b/Tests/FindSDL/Test/main.c
@@ -0,0 +1,18 @@
+#include <SDL.h>
+
+int main()
+{
+ // Test 1 requires headers only.
+ SDL_version compiled;
+ SDL_VERSION(&compiled);
+ if (compiled.major != CMAKE_EXPECTED_SDL_VERSION_MAJOR ||
+ compiled.minor != CMAKE_EXPECTED_SDL_VERSION_MINOR ||
+ compiled.patch != CMAKE_EXPECTED_SDL_VERSION_PATCH)
+ return 1;
+
+ // Test 2 requires to link to the library.
+ if (SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0)
+ return 2;
+
+ return 0;
+}
diff --git a/Tests/FindSQLite3/CMakeLists.txt b/Tests/FindSQLite3/CMakeLists.txt
new file mode 100644
index 0000000..8bf170e
--- /dev/null
+++ b/Tests/FindSQLite3/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindSQLite3.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindSQLite3/Test"
+ "${CMake_BINARY_DIR}/Tests/FindSQLite3/Test"
+ ${build_generator_args}
+ --build-project TestFindSQLite3
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindSQLite3/Test/CMakeLists.txt b/Tests/FindSQLite3/Test/CMakeLists.txt
new file mode 100644
index 0000000..bcc6ebd
--- /dev/null
+++ b/Tests/FindSQLite3/Test/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.4)
+project(TestFindSQLite3 C)
+include(CTest)
+
+find_package(SQLite3 REQUIRED)
+
+add_definitions(-DCMAKE_EXPECTED_SQLite3_VERSION="${SQLite3_VERSION}")
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt SQLite::SQLite3)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${SQLite3_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${SQLite3_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindSQLite3/Test/main.c b/Tests/FindSQLite3/Test/main.c
new file mode 100644
index 0000000..fb17c67
--- /dev/null
+++ b/Tests/FindSQLite3/Test/main.c
@@ -0,0 +1,9 @@
+#include <sqlite3.h>
+#include <string.h>
+
+int main()
+{
+ char sqlite3_version[] = SQLITE_VERSION;
+
+ return strcmp(sqlite3_version, CMAKE_EXPECTED_SQLite3_VERSION);
+}
diff --git a/Tests/FindTIFF/CMakeLists.txt b/Tests/FindTIFF/CMakeLists.txt
new file mode 100644
index 0000000..c4e0c6a
--- /dev/null
+++ b/Tests/FindTIFF/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindTIFF.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindTIFF/Test"
+ "${CMake_BINARY_DIR}/Tests/FindTIFF/Test"
+ ${build_generator_args}
+ --build-project TestFindTIFF
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindTIFF/Test/CMakeLists.txt b/Tests/FindTIFF/Test/CMakeLists.txt
new file mode 100644
index 0000000..e235db3
--- /dev/null
+++ b/Tests/FindTIFF/Test/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindTIFF)
+include(CTest)
+
+find_package(TIFF REQUIRED COMPONENTS CXX)
+
+add_executable(test_tiff_tgt main.c)
+target_link_libraries(test_tiff_tgt TIFF::TIFF)
+add_test(NAME test_tiff_tgt COMMAND test_tiff_tgt)
+
+add_executable(test_tiffxx_tgt main.cxx)
+target_link_libraries(test_tiffxx_tgt TIFF::CXX)
+add_test(NAME test_tiffxx_tgt COMMAND test_tiffxx_tgt)
+
+add_executable(test_tiff_var main.c)
+target_include_directories(test_tiff_var PRIVATE ${TIFF_INCLUDE_DIRS})
+target_link_libraries(test_tiff_var PRIVATE ${TIFF_LIBRARIES})
+add_test(NAME test_tiff_var COMMAND test_tiff_var)
+
+add_executable(test_tiffxx_var main.cxx)
+target_include_directories(test_tiffxx_var PRIVATE ${TIFF_INCLUDE_DIRS})
+target_link_libraries(test_tiffxx_var PRIVATE ${TIFF_LIBRARIES})
+add_test(NAME test_tiffxx_var COMMAND test_tiffxx_var)
diff --git a/Tests/FindTIFF/Test/main.c b/Tests/FindTIFF/Test/main.c
new file mode 100644
index 0000000..9182652
--- /dev/null
+++ b/Tests/FindTIFF/Test/main.c
@@ -0,0 +1,12 @@
+#include <assert.h>
+#include <tiffio.h>
+
+int main()
+{
+ /* Without any TIFF file to open, test that the call fails as
+ expected. This tests that linking worked. */
+ TIFF* tiff = TIFFOpen("invalid.tiff", "r");
+ assert(!tiff);
+
+ return 0;
+}
diff --git a/Tests/FindTIFF/Test/main.cxx b/Tests/FindTIFF/Test/main.cxx
new file mode 100644
index 0000000..f80a31f
--- /dev/null
+++ b/Tests/FindTIFF/Test/main.cxx
@@ -0,0 +1,16 @@
+#include <fstream>
+
+#include <assert.h>
+#include <tiffio.hxx>
+
+int main()
+{
+ /* Without any TIFF file to open, test that the call fails as
+ expected. This tests that linking worked. */
+ TIFF* tiff = TIFFOpen("invalid.tiff", "r");
+ assert(!tiff);
+
+ std::ifstream s;
+ TIFF* tiffxx = TIFFStreamOpen("invalid.tiff", &s);
+ return 0;
+}
diff --git a/Tests/FindThreads/C-only/CMakeLists.txt b/Tests/FindThreads/C-only/CMakeLists.txt
new file mode 100644
index 0000000..ee2a5f9
--- /dev/null
+++ b/Tests/FindThreads/C-only/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
+project(FindThreads_C-only C)
+
+find_package(Threads REQUIRED)
+
+if (NOT WIN32)
+ add_executable(thr ${CMAKE_CURRENT_SOURCE_DIR}/../../../Modules/CheckForPthreads.c)
+ target_link_libraries(thr Threads::Threads)
+endif ()
diff --git a/Tests/FindThreads/CMakeLists.txt b/Tests/FindThreads/CMakeLists.txt
new file mode 100644
index 0000000..aa9499b
--- /dev/null
+++ b/Tests/FindThreads/CMakeLists.txt
@@ -0,0 +1,11 @@
+foreach (_lang IN ITEMS C CXX)
+ add_test(NAME FindThreads.${_lang}-only COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindThreads/${_lang}-only"
+ "${CMake_BINARY_DIR}/Tests/FindThreads/${_lang}-only"
+ ${build_generator_args}
+ --build-project FindThreads_${_lang}-only
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
+endforeach ()
diff --git a/Tests/FindThreads/CXX-only/CMakeLists.txt b/Tests/FindThreads/CXX-only/CMakeLists.txt
new file mode 100644
index 0000000..3c6cc1e
--- /dev/null
+++ b/Tests/FindThreads/CXX-only/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
+project(FindThreads_CXX-only CXX)
+
+find_package(Threads REQUIRED)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../../../Modules/CheckForPthreads.c
+ ${CMAKE_CURRENT_BINARY_DIR}/CheckForPthreads.cxx)
+
+if (NOT WIN32)
+ add_executable(thr ${CMAKE_CURRENT_BINARY_DIR}/CheckForPthreads.cxx)
+ target_link_libraries(thr Threads::Threads)
+endif ()
diff --git a/Tests/FindVulkan/CMakeLists.txt b/Tests/FindVulkan/CMakeLists.txt
new file mode 100644
index 0000000..46ce1c6
--- /dev/null
+++ b/Tests/FindVulkan/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindVulkan.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindVulkan/Test"
+ "${CMake_BINARY_DIR}/Tests/FindVulkan/Test"
+ ${build_generator_args}
+ --build-project TestFindVulkan
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindVulkan/Test/CMakeLists.txt b/Tests/FindVulkan/Test/CMakeLists.txt
new file mode 100644
index 0000000..9d36a0d
--- /dev/null
+++ b/Tests/FindVulkan/Test/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 3.4)
+project(TestFindVulkan C)
+include(CTest)
+
+SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../../)
+find_package(Vulkan REQUIRED)
+
+add_executable(test_tgt main.c)
+target_link_libraries(test_tgt Vulkan::Vulkan)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${Vulkan_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${Vulkan_LIBRARIES})
+add_test(NAME test_var COMMAND test_var)
+
+if(Vulkan_GLSLC_EXECUTABLE)
+ add_test(NAME test_glslc
+ COMMAND ${CMAKE_COMMAND}
+ "-DVULKAN_GLSLC_EXECUTABLE=${Vulkan_GLSLC_EXECUTABLE}"
+ "-DVULKAN_GLSLC_EXECUTABLE_TARGET=$<TARGET_FILE:Vulkan::glslc>"
+ -P "${CMAKE_CURRENT_LIST_DIR}/Run-glslc.cmake"
+ )
+endif()
diff --git a/Tests/FindVulkan/Test/Run-glslc.cmake b/Tests/FindVulkan/Test/Run-glslc.cmake
new file mode 100644
index 0000000..086eb9d
--- /dev/null
+++ b/Tests/FindVulkan/Test/Run-glslc.cmake
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.12)
+
+function(run_glslc exe exe_display)
+ execute_process(COMMAND ${exe} --help
+ OUTPUT_VARIABLE output
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ RESULT_VARIABLE result
+ )
+
+ if(NOT result EQUAL 0)
+ message(SEND_ERROR "Result of ${exe_display} --help is ${result}, should be 0")
+ endif()
+
+ if(NOT output MATCHES "^glslc - Compile shaders into SPIR-V")
+ message(SEND_ERROR "Output of ${exe_display} --help is \"${output}\", should begin with \"glslc - Compile shaders into SPIR-V\"")
+ endif()
+endfunction()
+
+run_glslc("${VULKAN_GLSLC_EXECUTABLE}" "\${VULKAN_GLSLC_EXECUTABLE}")
+run_glslc("${VULKAN_GLSLC_EXECUTABLE_TARGET}" "Vulkan::glslc")
diff --git a/Tests/FindVulkan/Test/main.c b/Tests/FindVulkan/Test/main.c
new file mode 100644
index 0000000..1bff651
--- /dev/null
+++ b/Tests/FindVulkan/Test/main.c
@@ -0,0 +1,29 @@
+#include <vulkan/vulkan.h>
+
+int main()
+{
+ VkInstanceCreateInfo instanceCreateInfo = { 0 };
+ instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+
+ VkApplicationInfo applicationInfo = { 0 };
+ applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ applicationInfo.apiVersion = VK_API_VERSION_1_0;
+ applicationInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
+ applicationInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
+ applicationInfo.pApplicationName = "CMake Test application";
+ applicationInfo.pEngineName = "CMake Test Engine";
+
+ instanceCreateInfo.pApplicationInfo = &applicationInfo;
+
+ VkInstance instance = VK_NULL_HANDLE;
+ vkCreateInstance(&instanceCreateInfo, NULL, &instance);
+
+ // We can't assert here because in general vkCreateInstance will return an
+ // error if no driver is found - but if we get here, FindVulkan is working
+
+ if (instance != VK_NULL_HANDLE) {
+ vkDestroyInstance(instance, NULL);
+ }
+
+ return 0;
+}
diff --git a/Tests/FindX11/CMakeLists.txt b/Tests/FindX11/CMakeLists.txt
new file mode 100644
index 0000000..cc931a1
--- /dev/null
+++ b/Tests/FindX11/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindX11.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindX11/Test"
+ "${CMake_BINARY_DIR}/Tests/FindX11/Test"
+ ${build_generator_args}
+ --build-project TestFindX11
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindX11/Test/CMakeLists.txt b/Tests/FindX11/Test/CMakeLists.txt
new file mode 100644
index 0000000..5b304d9
--- /dev/null
+++ b/Tests/FindX11/Test/CMakeLists.txt
@@ -0,0 +1,106 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindX11 C)
+include(CTest)
+
+find_package(X11 REQUIRED)
+
+function (test_x11_component have_var component)
+ if (NOT X11_${component}_FOUND)
+ message("Skipping ${component} because it was not found.")
+ return ()
+ endif ()
+
+ add_executable(test_tgt_${component} main.c)
+ target_link_libraries(test_tgt_${component} PRIVATE X11::${component})
+ target_compile_definitions(test_tgt_${component} PRIVATE HAVE_X11_${component})
+ add_test(NAME test_tgt_${component} COMMAND test_tgt_${component})
+
+ # Add to the list of components to test for the parent.
+ set(${have_var}
+ ${${have_var}}
+ HAVE_X11_${component}
+ PARENT_SCOPE)
+endfunction ()
+
+set(x11_components)
+test_x11_component(x11_components ICE)
+test_x11_component(x11_components SM)
+# Not a component; hack it up.
+set(X11_X11_FOUND ${X11_FOUND})
+test_x11_component(x11_components X11)
+test_x11_component(x11_components Xau)
+test_x11_component(x11_components Xaw)
+test_x11_component(x11_components xcb)
+test_x11_component(x11_components X11_xcb)
+test_x11_component(x11_components xcb_icccm)
+test_x11_component(x11_components xcb_util)
+test_x11_component(x11_components xcb_xfixes)
+test_x11_component(x11_components xcb_xkb)
+test_x11_component(x11_components Xcomposite)
+test_x11_component(x11_components Xdamage)
+test_x11_component(x11_components Xdmcp)
+test_x11_component(x11_components Xext)
+test_x11_component(x11_components Xxf86misc)
+test_x11_component(x11_components Xxf86vm)
+test_x11_component(x11_components Xfixes)
+# We ignore the Xft component because the variables do not provide the required
+# dependency information (Freetype and Fontconfig).
+test_x11_component(x11_components_ignore Xft)
+test_x11_component(x11_components Xi)
+test_x11_component(x11_components Xinerama)
+test_x11_component(x11_components xkbcommon)
+test_x11_component(x11_components xkbcommon_X11)
+test_x11_component(x11_components Xkb)
+test_x11_component(x11_components xkbfile)
+test_x11_component(x11_components Xmu)
+test_x11_component(x11_components Xpm)
+test_x11_component(x11_components Xtst)
+test_x11_component(x11_components Xrandr)
+test_x11_component(x11_components Xrender)
+test_x11_component(x11_components XRes)
+test_x11_component(x11_components Xss)
+test_x11_component(x11_components Xt)
+test_x11_component(x11_components Xutil)
+test_x11_component(x11_components Xv)
+
+# The variables do not include dependency information. Just test "everything".
+add_executable(test_var main.c)
+target_include_directories(test_var PRIVATE ${X11_INCLUDE_DIRS})
+target_link_libraries(test_var PRIVATE ${X11_LIBRARIES})
+# Not included in X11_LIBRARIES.
+foreach(lib
+ Xau
+ Xaw
+ xcb
+ X11_xcb
+ xcb_icccm
+ xcb_util
+ xcb_xfixes
+ Xcomposite
+ Xdamage
+ Xdmcp
+ Xxf86misc
+ Xxf86vm
+ Xfixes
+ Xi
+ Xinerama
+ xkbcommon
+ xkbcommon_X11
+ Xkb
+ xkbfile
+ Xmu
+ Xpm
+ Xtst
+ Xrandr
+ Xrender
+ XRes
+ Xss
+ Xt
+ Xv
+ )
+ if (X11_${lib}_FOUND)
+ target_link_libraries(test_var PRIVATE ${X11_${lib}_LIB})
+ endif ()
+endforeach()
+target_compile_definitions(test_var PRIVATE ${x11_components})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindX11/Test/main.c b/Tests/FindX11/Test/main.c
new file mode 100644
index 0000000..b44ae28
--- /dev/null
+++ b/Tests/FindX11/Test/main.c
@@ -0,0 +1,473 @@
+#ifdef HAVE_X11_ICE
+# include <X11/ICE/ICElib.h>
+
+static Status test_ICE(void)
+{
+ return IceInitThreads();
+}
+#endif
+
+#ifdef HAVE_X11_SM
+# include <X11/SM/SMlib.h>
+# include <stdlib.h>
+
+static void test_SM(void)
+{
+ SmcProtocolVersion(NULL);
+}
+#endif
+
+#ifdef HAVE_X11_X11
+# include <X11/Xlib.h>
+
+static Status test_X11(void)
+{
+ return XInitThreads();
+}
+#endif
+
+#ifdef HAVE_X11_Xau
+# include <X11/Xauth.h>
+
+static char* test_Xau(void)
+{
+ return XauFileName();
+}
+#endif
+
+#ifdef HAVE_X11_Xcomposite
+# include <X11/extensions/Xcomposite.h>
+
+static int test_Xcomposite(void)
+{
+ return XCompositeVersion();
+}
+#endif
+
+#ifdef HAVE_X11_Xdamage
+# include <X11/extensions/Xdamage.h>
+
+static Bool test_Xdamage(void)
+{
+ Display* dpy = XOpenDisplay(NULL);
+ int ev_base;
+ int err_base;
+ Bool ret = XDamageQueryExtension(dpy, &ev_base, &err_base);
+ XCloseDisplay(dpy);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_X11_Xdmcp
+# include <X11/Xdmcp.h>
+
+static int test_Xdmcp(void)
+{
+ BYTE data[1024];
+ XdmcpBuffer buf = { data, sizeof(data), 0, 0 };
+ return XdmcpReadRemaining(&buf);
+}
+#endif
+
+#ifdef HAVE_X11_Xext
+# include <X11/Xlib.h>
+# include <X11/extensions/Xext.h>
+
+static int test_Xext(void)
+{
+ Display* dpy = XOpenDisplay(NULL);
+ int ret = XMissingExtension(dpy, "cmake");
+ XCloseDisplay(dpy);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_X11_Xxf86misc
+# include <X11/Xlib.h>
+# include <X11/extensions/xf86misc.h>
+
+static Bool test_Xxf86misc(void)
+{
+ Display* dpy = XOpenDisplay(NULL);
+ Bool ret = XF86MiscSetClientVersion(dpy);
+ XCloseDisplay(dpy);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_X11_Xxf86vm
+# include <X11/Xlib.h>
+# include <X11/extensions/xf86vmode.h>
+
+static Bool test_Xxf86vm(void)
+{
+ Display* dpy = XOpenDisplay(NULL);
+ Bool ret = XF86VidModeSetClientVersion(dpy);
+ XCloseDisplay(dpy);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_X11_Xfixes
+# include <X11/extensions/Xfixes.h>
+
+static Bool test_Xfixes(void)
+{
+ Display* dpy = XOpenDisplay(NULL);
+ int ev_base;
+ int err_base;
+ Bool ret = XFixesQueryExtension(dpy, &ev_base, &err_base);
+ XCloseDisplay(dpy);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_X11_Xft
+# include <X11/Xft/Xft.h>
+
+static FcBool test_Xft(void)
+{
+ return XftInitFtLibrary();
+}
+#endif
+
+#ifdef HAVE_X11_Xi
+# include <X11/extensions/XInput.h>
+
+static XExtensionVersion* test_Xi(void)
+{
+ Display* dpy = XOpenDisplay(NULL);
+ XExtensionVersion* ret = XGetExtensionVersion(dpy, "cmake");
+ XCloseDisplay(dpy);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_X11_Xinerama
+# include <X11/extensions/Xinerama.h>
+
+static Bool test_Xinerama(void)
+{
+ Display* dpy = XOpenDisplay(NULL);
+ int ev_base;
+ int err_base;
+ Bool ret = XineramaQueryExtension(dpy, &ev_base, &err_base);
+ XCloseDisplay(dpy);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_X11_Xkb
+# include <X11/XKBlib.h>
+
+static Bool test_Xkb(void)
+{
+ return XkbIgnoreExtension(0);
+}
+#endif
+
+#ifdef HAVE_X11_xkbfile
+// clang-format off
+# include <stdio.h>
+# include <X11/XKBlib.h>
+# include <X11/extensions/XKBfile.h>
+# include <stdlib.h>
+// clang-format on
+
+static void test_xkbfile(void)
+{
+ Display* dpy = XOpenDisplay(NULL);
+ XkbInitAtoms(dpy);
+ XCloseDisplay(dpy);
+}
+#endif
+
+#ifdef HAVE_X11_Xmu
+# include <X11/Xmu/Xmu.h>
+# include <stdlib.h>
+
+static Bool test_Xmu(void)
+{
+ return XmuValidArea(NULL);
+}
+#endif
+
+#ifdef HAVE_X11_Xpm
+# include <X11/xpm.h>
+
+static int test_Xpm(void)
+{
+ return XpmAttributesSize();
+}
+#endif
+
+#ifdef HAVE_X11_Xtst
+# include <X11/extensions/XTest.h>
+
+static Status test_Xtst(void)
+{
+ Display* dpy = XOpenDisplay(NULL);
+ Status ret = XTestDiscard(dpy);
+ XCloseDisplay(dpy);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_X11_Xrandr
+# include <X11/extensions/Xrandr.h>
+
+static Bool test_Xrandr(void)
+{
+ Display* dpy = XOpenDisplay(NULL);
+ int ev_base;
+ int err_base;
+ Bool ret = XRRQueryExtension(dpy, &ev_base, &err_base);
+ XCloseDisplay(dpy);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_X11_Xrender
+# include <X11/extensions/Xrender.h>
+
+static Bool test_Xrender(void)
+{
+ Display* dpy = XOpenDisplay(NULL);
+ int ev_base;
+ int err_base;
+ Bool ret = XRenderQueryExtension(dpy, &ev_base, &err_base);
+ XCloseDisplay(dpy);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_X11_XRes
+# include <X11/Xlib.h>
+# include <X11/extensions/XRes.h>
+
+static Bool test_XRes(void)
+{
+ Display* dpy = XOpenDisplay(NULL);
+ int ev_base;
+ int err_base;
+ Bool ret = XResQueryExtension(dpy, &ev_base, &err_base);
+ XCloseDisplay(dpy);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_X11_Xss
+# include <X11/extensions/scrnsaver.h>
+
+static Bool test_Xss(void)
+{
+ Display* dpy = XOpenDisplay(NULL);
+ int ev_base;
+ int err_base;
+ Bool ret = XScreenSaverQueryExtension(dpy, &ev_base, &err_base);
+ XCloseDisplay(dpy);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_X11_Xt
+# include <X11/Intrinsic.h>
+
+static void test_Xt(void)
+{
+ return XtToolkitInitialize();
+}
+#endif
+
+#ifdef HAVE_X11_Xutil
+# include <X11/Xutil.h>
+
+static int test_Xutil(void)
+{
+ Region r = XCreateRegion();
+ return XDestroyRegion(r);
+}
+#endif
+
+#ifdef HAVE_X11_Xv
+# include <X11/Xlib.h>
+# include <X11/extensions/Xvlib.h>
+
+static int test_Xv(void)
+{
+ Display* dpy = XOpenDisplay(NULL);
+ unsigned int version;
+ unsigned int revision;
+ unsigned int req_base;
+ unsigned int ev_base;
+ unsigned int err_base;
+ int ret =
+ XvQueryExtension(dpy, &version, &revision, &req_base, &ev_base, &err_base);
+ XCloseDisplay(dpy);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_X11_Xaw
+# include <X11/Intrinsic.h>
+# include <X11/Xaw/Box.h>
+
+static void test_Xaw(void)
+{
+ XrmOptionDescRec opt_table[] = { { NULL } };
+
+ Widget toplevel;
+ toplevel =
+ XtInitialize("test", "test", opt_table, XtNumber(opt_table), NULL, NULL);
+ Widget box =
+ XtCreateManagedWidget("testbox", boxWidgetClass, toplevel, NULL, 0);
+ return;
+}
+
+#endif
+
+#ifdef HAVE_xcb
+# include <xcb/xcb.h>
+
+static void test_xcb(void)
+{
+ int screen_nbr;
+ xcb_connection_t* connection = xcb_connect(NULL, &screen_nbr);
+ xcb_disconnect(connection);
+}
+
+# ifdef HAVE_xcb_util
+# include <xcb/xcb_aux.h>
+
+static void test_xcb_util(void)
+{
+ int screen_nbr;
+ xcb_connection_t* connection = xcb_connect(NULL, &screen_nbr);
+ xcb_screen_t* screen = xcb_aux_get_screen(connection, screen_nbr);
+ xcb_disconnect(connection);
+}
+
+# endif
+
+# ifdef HAVE_xcb_xfixes
+# include <xcb/xcb_xfixes.h>
+
+static void test_xcb_xfixes(void)
+{
+ int screen_nbr;
+ xcb_connection_t* connection = xcb_connect(NULL, &screen_nbr);
+ xcb_xfixes_query_version(connection, 1, 0);
+ xcb_disconnect(connection);
+}
+
+# endif
+
+#endif
+
+#include <stddef.h>
+
+int main(int argc, char* argv[])
+{
+ (void)argv;
+ void* fptrs[] = {
+#ifdef HAVE_X11_ICE
+ test_ICE,
+#endif
+#ifdef HAVE_X11_SM
+ test_SM,
+#endif
+#ifdef HAVE_X11_X11
+ test_X11,
+#endif
+#ifdef HAVE_X11_Xau
+ test_Xau,
+#endif
+#ifdef HAVE_X11_Xcomposite
+ test_Xcomposite,
+#endif
+#ifdef HAVE_X11_Xdamage
+ test_Xdamage,
+#endif
+#ifdef HAVE_X11_Xdmcp
+ test_Xdmcp,
+#endif
+#ifdef HAVE_X11_Xext
+ test_Xext,
+#endif
+#ifdef HAVE_X11_Xxf86misc
+ test_Xxf86misc,
+#endif
+#ifdef HAVE_X11_Xxf86vm
+ test_Xxf86vm,
+#endif
+#ifdef HAVE_X11_Xfixes
+ test_Xfixes,
+#endif
+#ifdef HAVE_X11_Xft
+ test_Xft,
+#endif
+#ifdef HAVE_X11_Xi
+ test_Xi,
+#endif
+#ifdef HAVE_X11_Xinerama
+ test_Xinerama,
+#endif
+#ifdef HAVE_X11_Xkb
+ test_Xkb,
+#endif
+#ifdef HAVE_X11_xkbfile
+ test_xkbfile,
+#endif
+#ifdef HAVE_X11_Xmu
+ test_Xmu,
+#endif
+#ifdef HAVE_X11_Xpm
+ test_Xpm,
+#endif
+#ifdef HAVE_X11_Xtst
+ test_Xtst,
+#endif
+#ifdef HAVE_X11_Xrandr
+ test_Xrandr,
+#endif
+#ifdef HAVE_X11_Xrender
+ test_Xrender,
+#endif
+#ifdef HAVE_X11_XRes
+ test_XRes,
+#endif
+#ifdef HAVE_X11_Xss
+ test_Xss,
+#endif
+#ifdef HAVE_X11_Xt
+ test_Xt,
+#endif
+#ifdef HAVE_X11_Xutil
+ test_Xutil,
+#endif
+#ifdef HAVE_X11_Xv
+ test_Xv,
+#endif
+#ifdef HAVE_X11_Xaw
+ test_Xaw,
+#endif
+#ifdef HAVE_xcb
+ test_xcb,
+#endif
+#ifdef HAVE_xcb_util
+ test_xcb_util,
+#endif
+#ifdef HAVE_xcb_xfixes
+ test_xcb_xfixes,
+#endif
+
+ NULL,
+ };
+
+ // The code here is to convince the compiler to keep the static functions but
+ // without calling them. This ends up always being "0" because `argc` is
+ // always 1 in the test harness which always returns the sentinel at the end
+ // of the array. The array logic is there to ensure that the contents of
+ // `fptrs` is not optimized out.
+ return (int)fptrs[(sizeof(fptrs) / sizeof(*fptrs)) - argc];
+}
diff --git a/Tests/FindXalanC/CMakeLists.txt b/Tests/FindXalanC/CMakeLists.txt
new file mode 100644
index 0000000..7872929
--- /dev/null
+++ b/Tests/FindXalanC/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindXalanC.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindXalanC/Test"
+ "${CMake_BINARY_DIR}/Tests/FindXalanC/Test"
+ ${build_generator_args}
+ --build-project TestFindXalanC
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindXalanC/Test/CMakeLists.txt b/Tests/FindXalanC/Test/CMakeLists.txt
new file mode 100644
index 0000000..a8c2a0a
--- /dev/null
+++ b/Tests/FindXalanC/Test/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindXalanC CXX)
+include(CTest)
+
+find_package(XalanC REQUIRED)
+
+add_executable(test_xalanc_tgt main.cxx)
+target_link_libraries(test_xalanc_tgt XalanC::XalanC)
+add_test(NAME test_xalanc_tgt COMMAND test_xalanc_tgt)
+
+add_executable(test_xalanc_var main.cxx)
+target_include_directories(test_xalanc_var PRIVATE ${XalanC_INCLUDE_DIRS})
+target_link_libraries(test_xalanc_var PRIVATE ${XalanC_LIBRARIES})
+add_test(NAME test_xalanc_var COMMAND test_xalanc_var)
diff --git a/Tests/FindXalanC/Test/main.cxx b/Tests/FindXalanC/Test/main.cxx
new file mode 100644
index 0000000..7d0f42c
--- /dev/null
+++ b/Tests/FindXalanC/Test/main.cxx
@@ -0,0 +1,10 @@
+#include <xalanc/XalanTransformer/XalanTransformer.hpp>
+#include <xercesc/util/PlatformUtils.hpp>
+
+int main()
+{
+ xercesc::XMLPlatformUtils::Initialize();
+ xalanc::XalanTransformer::initialize();
+ xalanc::XalanTransformer::terminate();
+ xercesc::XMLPlatformUtils::Terminate();
+}
diff --git a/Tests/FindXercesC/CMakeLists.txt b/Tests/FindXercesC/CMakeLists.txt
new file mode 100644
index 0000000..633f613
--- /dev/null
+++ b/Tests/FindXercesC/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindXercesC.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindXercesC/Test"
+ "${CMake_BINARY_DIR}/Tests/FindXercesC/Test"
+ ${build_generator_args}
+ --build-project TestFindXercesC
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindXercesC/Test/CMakeLists.txt b/Tests/FindXercesC/Test/CMakeLists.txt
new file mode 100644
index 0000000..267c6a9
--- /dev/null
+++ b/Tests/FindXercesC/Test/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindXercesC CXX)
+include(CTest)
+
+find_package(XercesC REQUIRED)
+
+add_executable(test_xercesc_tgt main.cxx)
+target_link_libraries(test_xercesc_tgt XercesC::XercesC)
+add_test(NAME test_xercesc_tgt COMMAND test_xercesc_tgt)
+
+add_executable(test_xercesc_var main.cxx)
+target_include_directories(test_xercesc_var PRIVATE ${XercesC_INCLUDE_DIRS})
+target_link_libraries(test_xercesc_var PRIVATE ${XercesC_LIBRARIES})
+add_test(NAME test_xercesc_var COMMAND test_xercesc_var)
diff --git a/Tests/FindXercesC/Test/main.cxx b/Tests/FindXercesC/Test/main.cxx
new file mode 100644
index 0000000..1794fa6
--- /dev/null
+++ b/Tests/FindXercesC/Test/main.cxx
@@ -0,0 +1,7 @@
+#include <xercesc/util/PlatformUtils.hpp>
+
+int main()
+{
+ xercesc::XMLPlatformUtils::Initialize();
+ xercesc::XMLPlatformUtils::Terminate();
+}
diff --git a/Tests/ForceInclude/CMakeLists.txt b/Tests/ForceInclude/CMakeLists.txt
new file mode 100644
index 0000000..e231054
--- /dev/null
+++ b/Tests/ForceInclude/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.3.20110103)
+project(ForceInclude C)
+
+# Make sure the proper compiler is in use.
+if(NOT MSVC AND NOT CMAKE_C_COMPILER_ID STREQUAL "Intel")
+ message(FATAL_ERROR "The ForceInclude test works only with MSVC or Intel")
+endif()
+
+add_executable(foo foo.c)
+set_property(SOURCE foo.c PROPERTY COMPILE_FLAGS "/FIfoo1.h /FIfoo2.h")
diff --git a/Tests/ForceInclude/foo.c b/Tests/ForceInclude/foo.c
new file mode 100644
index 0000000..2a26c6f
--- /dev/null
+++ b/Tests/ForceInclude/foo.c
@@ -0,0 +1,10 @@
+#ifndef FOO_1
+# error "foo1.h not included by /FI"
+#endif
+#ifndef FOO_2
+# error "foo2.h not included by /FI"
+#endif
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/ForceInclude/foo1.h b/Tests/ForceInclude/foo1.h
new file mode 100644
index 0000000..2c1cb7b
--- /dev/null
+++ b/Tests/ForceInclude/foo1.h
@@ -0,0 +1 @@
+#define FOO_1
diff --git a/Tests/ForceInclude/foo2.h b/Tests/ForceInclude/foo2.h
new file mode 100644
index 0000000..e47524d
--- /dev/null
+++ b/Tests/ForceInclude/foo2.h
@@ -0,0 +1 @@
+#define FOO_2
diff --git a/Tests/Fortran/CMakeLists.txt b/Tests/Fortran/CMakeLists.txt
new file mode 100644
index 0000000..2fc47a5
--- /dev/null
+++ b/Tests/Fortran/CMakeLists.txt
@@ -0,0 +1,148 @@
+cmake_minimum_required (VERSION 3.1)
+project(testf C CXX Fortran)
+
+message("CTEST_FULL_OUTPUT ")
+set(CMAKE_VERBOSE_MAKEFILE 1)
+message("ENV_FLAGS = $ENV{FFLAGS}")
+message("CMAKE_Fortran_COMPILER_INIT = ${CMAKE_Fortran_COMPILER_INIT}")
+message("CMAKE_Fortran_COMPILER_FULLPATH = ${CMAKE_Fortran_COMPILER_FULLPATH}")
+message("CMAKE_Fortran_COMPILER = ${CMAKE_Fortran_COMPILER}")
+message("CMAKE_Fortran_FLAGS = ${CMAKE_Fortran_FLAGS}")
+
+set(_SHARED SHARED)
+if(CMAKE_Fortran_COMPILER_ID MATCHES "^(XL|VisualAge)$")
+ # We do not implement SHARED Fortran libs on AIX yet!
+ # Workaround: Set LINKER_LANGUAGE to C, which uses 'xlc' and Fortran implicits.
+ set(_SHARED STATIC)
+elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
+ # g77 2.96 does not support shared libs on Itanium because g2c is not -fPIC
+ execute_process(COMMAND ${CMAKE_Fortran_COMPILER} --version
+ OUTPUT_VARIABLE output ERROR_VARIABLE output)
+ if("${output}" MATCHES "Red Hat .* 2\\.96")
+ set(_SHARED STATIC)
+ endif()
+endif()
+
+# Pick a module .def file with the properly mangled symbol name.
+set(world_def "")
+if(WIN32 AND NOT CYGWIN)
+ if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU")
+ set(world_def world_gnu.def)
+ elseif(CMAKE_Fortran_COMPILER_ID MATCHES "Intel" OR
+ CMAKE_GENERATOR MATCHES "Visual Studio") # Intel plugin
+ set(world_def world_icl.def)
+ endif()
+endif()
+
+add_library(hello STATIC hello.f)
+add_library(world ${_SHARED} world.f ${world_def})
+add_executable(testf testf.f)
+target_link_libraries(testf hello world)
+
+function(test_fortran_c_interface_module)
+ message(STATUS "Testing FortranCInterface module")
+ # test the C to Fortran interface module
+ include(FortranCInterface)
+ FortranCInterface_VERIFY()
+ FortranCInterface_VERIFY(CXX)
+ if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
+ if(NOT CMAKE_Fortran_COMPILER_ID MATCHES "SunPro|PathScale|Absoft|Fujitsu")
+ set(module_expected 1)
+ endif()
+ if(FortranCInterface_MODULE_FOUND OR module_expected)
+ set(srcs foo.f)
+ set(FORTRAN_FUNCTIONS test_mod:sub)
+ set(MYC_DEFS TEST_MOD)
+ else()
+ message("${CMAKE_Fortran_COMPILER_ID} compilers do not support"
+ " linking Fortran module procedures from C")
+ endif()
+ endif()
+ list(APPEND FORTRAN_FUNCTIONS my_sub mysub)
+ FortranCInterface_HEADER(foo.h
+ MACRO_NAMESPACE "FC_"
+ SYMBOL_NAMESPACE "F_"
+ SYMBOLS ${FORTRAN_FUNCTIONS}
+ )
+ include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+
+ # if the name mangling is not found for a F90 compiler
+ # print out some diagnostic stuff for the dashboard
+ if(NOT FortranCInterface_GLOBAL_FOUND OR
+ (NOT FortranCInterface_MODULE_FOUND AND module_expected) )
+ find_program(FortranCInterface_EXE
+ NAMES FortranCInterface
+ PATHS ${FortranCInterface_BINARY_DIR} ${FortranCInterface_BINARY_DIR}/Debug
+ NO_DEFAULT_PATH
+ )
+ find_program(DUMPBIN dumpbin)
+ find_program(NM nm)
+ if(FortranCInterface_EXE)
+ if(DEPENDS)
+ execute_process(COMMAND ${DUMPBIN} /symbols "${FortranCInterface_EXE}"
+ OUTPUT_VARIABLE out)
+ message("symbols in ${FortranCInterface_EXE}:\n${out}")
+ endif()
+ if(NM)
+ execute_process(COMMAND ${NM} "${FortranCInterface_EXE}"
+ OUTPUT_VARIABLE out)
+ message("symbols in ${FortranCInterface_EXE}:\n${out}")
+ endif()
+ endif()
+ endif()
+ message("Fortran = ${CMAKE_Fortran_COMPILER_ID}")
+ message("C = ${CMAKE_C_COMPILER_ID}")
+
+ add_library(myfort mysub.f ${srcs})
+
+ add_library(myc myc.c)
+ target_link_libraries(myc myfort)
+ set_property(TARGET myc PROPERTY COMPILE_DEFINITIONS ${MYC_DEFS})
+
+ add_library(myfort_obj OBJECT mysub.f)
+ add_library(myc_use_obj myc.c $<TARGET_OBJECTS:myfort_obj>)
+ add_executable(mainc_use_obj mainc.c)
+ target_link_libraries(mainc_use_obj myc_use_obj)
+
+ add_library(mycxx mycxx.cxx)
+ target_link_libraries(mycxx myc)
+
+ add_executable(mainc mainc.c)
+ target_link_libraries(mainc myc)
+ add_executable(maincxx maincxx.c)
+ target_link_libraries(maincxx mycxx)
+
+ # print out some stuff to help debug on machines via cdash
+ file(READ "${CMAKE_CURRENT_BINARY_DIR}/foo.h" fooh)
+ message("foo.h contents:\n${fooh}")
+endfunction()
+
+# if the id's match or the compilers are compatible, then
+# call the test_fortran_c_interface_module function
+if("${CMAKE_Fortran_COMPILER_ID}:${CMAKE_C_COMPILER_ID}" MATCHES
+ "(Intel(LLVM)?:MSVC|Absoft:GNU)"
+ OR ("${CMAKE_Fortran_COMPILER_ID}" STREQUAL "${CMAKE_C_COMPILER_ID}" ))
+ test_fortran_c_interface_module()
+else()
+ message("Fortran does not match c compiler")
+ message("Fortran = ${CMAKE_Fortran_COMPILER_ID}")
+ message("C = ${CMAKE_C_COMPILER_ID}")
+ # hack to make g77 work after CL has been enabled
+ # as a language, cmake needs language specific versions
+ # of these variables....
+ if(WIN32 AND CMAKE_Fortran_COMPILER_ID MATCHES "GNU")
+ set(CMAKE_Fortran_CREATE_CONSOLE_EXE )
+ set(CMAKE_LIBRARY_PATH_FLAG "-L")
+ set(CMAKE_LINK_LIBRARY_FLAG "-l")
+ set(CMAKE_LINK_LIBRARY_SUFFIX )
+ endif()
+ # gnu and sunpro do not use the same flags here...
+ # however if LDFLAGS is used to set -m64 it causes odd stuf
+ # with the fortran build
+ if( (CMAKE_C_COMPILER_ID MATCHES "GNU")
+ AND (CMAKE_Fortran_COMPILER_ID MATCHES "SunPro"))
+ set(CMAKE_EXE_LINKER_FLAGS "")
+ set(CMAKE_Fortran_FLAGS "")
+ endif()
+
+endif()
diff --git a/Tests/Fortran/foo.f b/Tests/Fortran/foo.f
new file mode 100644
index 0000000..ece0df4
--- /dev/null
+++ b/Tests/Fortran/foo.f
@@ -0,0 +1,9 @@
+ module test_mod
+ interface dummy
+ module procedure sub
+ end interface
+ contains
+ subroutine sub
+ end subroutine
+
+ end module test_mod
diff --git a/Tests/Fortran/hello.f b/Tests/Fortran/hello.f
new file mode 100644
index 0000000..aa0de77
--- /dev/null
+++ b/Tests/Fortran/hello.f
@@ -0,0 +1,6 @@
+ SUBROUTINE HELLO
+
+ PRINT *, 'Hello'
+
+ END
+
diff --git a/Tests/Fortran/mainc.c b/Tests/Fortran/mainc.c
new file mode 100644
index 0000000..9efafc5
--- /dev/null
+++ b/Tests/Fortran/mainc.c
@@ -0,0 +1,5 @@
+extern int myc(void);
+int main()
+{
+ return myc();
+}
diff --git a/Tests/Fortran/maincxx.c b/Tests/Fortran/maincxx.c
new file mode 100644
index 0000000..d35ea7e
--- /dev/null
+++ b/Tests/Fortran/maincxx.c
@@ -0,0 +1,6 @@
+extern int myc(void);
+extern int mycxx(void);
+int main()
+{
+ return myc() + mycxx();
+}
diff --git a/Tests/Fortran/myc.c b/Tests/Fortran/myc.c
new file mode 100644
index 0000000..1a4d5a4
--- /dev/null
+++ b/Tests/Fortran/myc.c
@@ -0,0 +1,12 @@
+#include "foo.h"
+extern void F_test_mod_sub(void);
+extern void F_mysub(void);
+int myc(void)
+{
+ F_mysub();
+ F_my_sub();
+#ifdef TEST_MOD
+ F_test_mod_sub();
+#endif
+ return 0;
+}
diff --git a/Tests/Fortran/mycxx.cxx b/Tests/Fortran/mycxx.cxx
new file mode 100644
index 0000000..bf04062
--- /dev/null
+++ b/Tests/Fortran/mycxx.cxx
@@ -0,0 +1,6 @@
+extern "C" int myc(void);
+extern "C" int mycxx(void)
+{
+ delete new int;
+ return myc();
+}
diff --git a/Tests/Fortran/mysub.f b/Tests/Fortran/mysub.f
new file mode 100644
index 0000000..4b108e3
--- /dev/null
+++ b/Tests/Fortran/mysub.f
@@ -0,0 +1,5 @@
+ subroutine mysub
+ print *, 'Printing this requires fortran language libraries'
+ end subroutine
+ subroutine my_sub
+ end subroutine
diff --git a/Tests/Fortran/testf.f b/Tests/Fortran/testf.f
new file mode 100644
index 0000000..abf6c6d
--- /dev/null
+++ b/Tests/Fortran/testf.f
@@ -0,0 +1,7 @@
+ PROGRAM TESTF
+
+ CALL HELLO()
+ CALL WORLD()
+
+ END
+
diff --git a/Tests/Fortran/world.f b/Tests/Fortran/world.f
new file mode 100644
index 0000000..0487dff
--- /dev/null
+++ b/Tests/Fortran/world.f
@@ -0,0 +1,6 @@
+ SUBROUTINE WORLD
+
+ PRINT *, 'World!'
+
+ END
+
diff --git a/Tests/Fortran/world_gnu.def b/Tests/Fortran/world_gnu.def
new file mode 100644
index 0000000..1617798
--- /dev/null
+++ b/Tests/Fortran/world_gnu.def
@@ -0,0 +1,2 @@
+EXPORTS
+ world_
diff --git a/Tests/Fortran/world_icl.def b/Tests/Fortran/world_icl.def
new file mode 100644
index 0000000..ead7710
--- /dev/null
+++ b/Tests/Fortran/world_icl.def
@@ -0,0 +1,2 @@
+EXPORTS
+ WORLD
diff --git a/Tests/FortranC/CMakeLists.txt b/Tests/FortranC/CMakeLists.txt
new file mode 100644
index 0000000..83c2729
--- /dev/null
+++ b/Tests/FortranC/CMakeLists.txt
@@ -0,0 +1,25 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(FortranC C Fortran)
+
+# Skip this test for compilers not known to be compatible.
+if(NOT (CMAKE_C_COMPILER_ID STREQUAL CMAKE_Fortran_COMPILER_ID OR
+ "${CMAKE_C_COMPILER_ID}-${CMAKE_Fortran_COMPILER_ID}" MATCHES "^(MSVC-Intel)$"))
+ message(STATUS "${CMAKE_C_COMPILER_ID} C and ${CMAKE_Fortran_COMPILER_ID} Fortran not known to be compatible!")
+ return()
+endif()
+
+# Wipe out all FortranCInterface information to ensure it re-runs.
+file(REMOVE_RECURSE ${CMAKE_BINARY_DIR}/CMakeFiles/FortranCInterface)
+
+if(FortranC_TEST_FLAGS)
+ # Test whether FortranCInterface checks see C flags.
+ set(ENV{TEST_OPT_CC} "--test-opt-cc=1")
+ set(CMAKE_C_FLAGS "$ENV{TEST_OPT_CC} ${CMAKE_C_FLAGS}")
+
+ # Test whether FortranCInterface checks see Fortran flags.
+ set(ENV{TEST_OPT_FC} "--test-opt-fc=1")
+ set(CMAKE_Fortran_FLAGS "$ENV{TEST_OPT_FC} ${CMAKE_Fortran_FLAGS}")
+endif()
+
+include(FortranCInterface)
+FortranCInterface_VERIFY()
diff --git a/Tests/FortranC/Flags.cmake.in b/Tests/FortranC/Flags.cmake.in
new file mode 100644
index 0000000..cf361a5
--- /dev/null
+++ b/Tests/FortranC/Flags.cmake.in
@@ -0,0 +1,36 @@
+set(src "@CMAKE_CURRENT_SOURCE_DIR@/FortranC")
+set(bld "@CMAKE_CURRENT_BINARY_DIR@/FortranC/Flags")
+
+# Create wrapper scripts for the compilers that check for expected
+# flags, remove them, and invoke the real compiler.
+set(ID "CC")
+set(COMMAND "@CMAKE_C_COMPILER@")
+configure_file("${src}/test_opt.sh.in" "${bld}/cc.sh" @ONLY)
+set(ID "FC")
+set(COMMAND "@CMAKE_Fortran_COMPILER@")
+configure_file("${src}/test_opt.sh.in" "${bld}/fc.sh" @ONLY)
+set(ID)
+set(COMMAND)
+
+set(make_program "@CMake_TEST_EXPLICIT_MAKE_PROGRAM@")
+if(make_program)
+ set(maybe_make_program "-DCMAKE_MAKE_PROGRAM=${make_program}")
+endif()
+
+execute_process(
+ WORKING_DIRECTORY "${bld}"
+ COMMAND ${CMAKE_COMMAND} "${src}" -G "@CMAKE_GENERATOR@"
+ -A "@CMAKE_GENERATOR_PLATFORM@"
+ -T "@CMAKE_GENERATOR_TOOLSET@"
+ ${maybe_make_program}
+ "-DFortranC_TEST_FLAGS=1"
+ "-DCMAKE_C_COMPILER=${bld}/cc.sh"
+ "-DCMAKE_C_FLAGS:STRING=@CMAKE_C_FLAGS@"
+ "-DCMAKE_Fortran_COMPILER=${bld}/fc.sh"
+ "-DCMAKE_Fortran_FLAGS:STRING=@CMAKE_Fortran_FLAGS@"
+ RESULT_VARIABLE result
+ )
+
+if(NOT "${result}" STREQUAL "0")
+ message(FATAL_ERROR "Configuration failed: ${result}")
+endif()
diff --git a/Tests/FortranC/test_opt.sh.in b/Tests/FortranC/test_opt.sh.in
new file mode 100755
index 0000000..f3d93dc
--- /dev/null
+++ b/Tests/FortranC/test_opt.sh.in
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+TEST_OPT_@ID@_FOUND=0
+ARGS=""
+for a in "$@"; do
+ if [ "x${TEST_OPT_@ID@}" != "x" -a "x${TEST_OPT_@ID@}" = "x$a" ]; then
+ TEST_OPT_@ID@_FOUND=1
+ else
+ ARGS="$ARGS \"$a\""
+ fi
+done
+
+if [ "x${TEST_OPT_@ID@}" != "x" -a "x${TEST_OPT_@ID@_FOUND}" != "x1" ]; then
+ echo "Not given option '${TEST_OPT_@ID@}' as expected!"
+ exit 1
+fi
+
+eval "\"@COMMAND@\"" "$ARGS"
diff --git a/Tests/FortranModules/CMakeLists.txt b/Tests/FortranModules/CMakeLists.txt
new file mode 100644
index 0000000..94f5939
--- /dev/null
+++ b/Tests/FortranModules/CMakeLists.txt
@@ -0,0 +1,117 @@
+cmake_minimum_required (VERSION 3.9)
+project(FortranModules Fortran)
+
+if("${CMAKE_Fortran_COMPILER_ID};${CMAKE_Fortran_SIMULATE_ID}" MATCHES "^Intel(LLVM)?;MSVC$")
+ string(APPEND CMAKE_Fortran_FLAGS_DEBUG " -Z7")
+ string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO " -Z7")
+endif()
+
+if(NOT DEFINED CMake_TEST_NESTED_MAKE_PROGRAM AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(CMake_TEST_NESTED_MAKE_PROGRAM "${CMAKE_MAKE_PROGRAM}")
+endif()
+
+if("x${CMake_TEST_Fortran_SUBMODULES}" STREQUAL "x"
+ AND NOT CMAKE_VERSION VERSION_LESS 3.6.20160923 # for CheckFortranSourceCompiles SRC_EXT
+ )
+ include(CheckFortranSourceCompiles)
+ CHECK_Fortran_SOURCE_COMPILES([[
+module parent
+ interface
+ module function id(x)
+ real, intent(in) :: x
+ real :: id
+ end function id
+ end interface
+end module parent
+submodule ( parent ) child
+contains
+ module procedure id
+ id = x
+ end procedure id
+end submodule child
+program main
+end program
+]] HAVE_SUBMODULES SRC_EXT F90)
+ set(CMake_TEST_Fortran_SUBMODULES ${HAVE_SUBMODULES})
+elseif(CMake_TEST_Fortran_SUBMODULES)
+ message(STATUS "Enabling Fortran submodule tests by explicit request.")
+endif()
+
+add_executable(test_module
+ test_module_main.f90
+ test_module_implementation.f90
+ test_module_interface.f90)
+
+add_executable(test_use_in_comment_fixedform
+ test_use_in_comment_fixedform.f)
+set_property(SOURCE test_use_in_comment_fixedform.f PROPERTY Fortran_FORMAT FIXED)
+add_executable(test_use_in_comment_freeform
+ test_use_in_comment_freeform.f90)
+set_property(SOURCE test_use_in_comment_freeform.f90 PROPERTY Fortran_FORMAT FREE)
+
+add_executable(test_in_interface
+ in_interface/main.f90
+ in_interface/module.f90)
+
+add_definitions(-DFOO -DBAR=1)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
+add_executable(test_preprocess test_preprocess.F90 test_preprocess_module.F90)
+
+add_executable(test_non_pp_include test_non_pp_include_main.f90)
+
+# Build the external project separately using a custom target.
+# Make sure it uses the same build configuration as this test.
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ set(External_CONFIG_TYPE -C "${CMAKE_CFG_INTDIR}")
+ set(External_BUILD_TYPE)
+else()
+ set(External_CONFIG_TYPE)
+ set(External_BUILD_TYPE -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE})
+endif()
+set(External_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/External")
+set(External_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/External")
+if("${CMAKE_CURRENT_BINARY_DIR}" MATCHES " ")
+ # Our build tree has a space, so the build tool supports spaces.
+ # Test using modules from a path with spaces.
+ string(APPEND External_BINARY_DIR " Build")
+endif()
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ExternalProject
+ COMMAND ${CMAKE_CTEST_COMMAND}
+ ARGS ${External_CONFIG_TYPE}
+ --build-and-test
+ ${External_SOURCE_DIR}
+ ${External_BINARY_DIR}
+ --build-noclean
+ --build-two-config
+ --build-project ExtFort
+ --build-generator ${CMAKE_GENERATOR}
+ --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+ --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+ --build-options -DCMAKE_Fortran_COMPILER:STRING=${CMAKE_Fortran_COMPILER}
+ -DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}
+ -DCMAKE_Fortran_FLAGS_DEBUG:STRING=${CMAKE_Fortran_FLAGS_DEBUG}
+ -DCMAKE_Fortran_FLAGS_RELEASE:STRING=${CMAKE_Fortran_FLAGS_RELEASE}
+ -DCMAKE_Fortran_FLAGS_MINSIZEREL:STRING=${CMAKE_Fortran_FLAGS_MINSIZEREL}
+ -DCMAKE_Fortran_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_Fortran_FLAGS_RELWITHDEBINFO}
+ -DCMAKE_MAKE_PROGRAM:FILEPATH=${CMake_TEST_NESTED_MAKE_PROGRAM}
+ ${External_BUILD_TYPE}
+ VERBATIM
+ )
+add_custom_target(ExternalTarget ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ExternalProject)
+
+# Test module output directory if available.
+if(CMAKE_Fortran_MODDIR_FLAG)
+ set(Library_MODDIR "${CMAKE_CURRENT_BINARY_DIR}/Library/modules")
+else()
+ set(Library_MODDIR "${CMAKE_CURRENT_BINARY_DIR}/Library")
+endif()
+
+add_subdirectory(Library)
+add_subdirectory(Subdir)
+add_subdirectory(Executable)
+
+if(CMake_TEST_Fortran_SUBMODULES)
+ add_subdirectory(Submodules)
+endif()
diff --git a/Tests/FortranModules/Executable/CMakeLists.txt b/Tests/FortranModules/Executable/CMakeLists.txt
new file mode 100644
index 0000000..f31a3e6
--- /dev/null
+++ b/Tests/FortranModules/Executable/CMakeLists.txt
@@ -0,0 +1,8 @@
+include_directories(${Library_MODDIR})
+include_directories(${External_BINARY_DIR})
+link_directories(${External_BINARY_DIR}/${CMAKE_CFG_INTDIR})
+
+add_executable(subdir_exe2 main.f90)
+target_link_libraries(subdir_exe2 subdir_mods subdir_mods2)
+add_dependencies(subdir_exe2 ExternalTarget)
+target_link_libraries(subdir_exe2 myext)
diff --git a/Tests/FortranModules/Executable/main.f90 b/Tests/FortranModules/Executable/main.f90
new file mode 100644
index 0000000..640259c
--- /dev/null
+++ b/Tests/FortranModules/Executable/main.f90
@@ -0,0 +1,7 @@
+PROGRAM MAINF90
+ USE libraryModuleA
+ USE libraryModuleB
+ USE subdirModuleA
+ USE externalMod
+ CALL printExtModGreeting
+END PROGRAM MAINF90
diff --git a/Tests/FortranModules/External/CMakeLists.txt b/Tests/FortranModules/External/CMakeLists.txt
new file mode 100644
index 0000000..c90a0ffb
--- /dev/null
+++ b/Tests/FortranModules/External/CMakeLists.txt
@@ -0,0 +1,3 @@
+project(ExtFort Fortran)
+
+add_library(myext a.f90)
diff --git a/Tests/FortranModules/External/a.f90 b/Tests/FortranModules/External/a.f90
new file mode 100644
index 0000000..2be73c5
--- /dev/null
+++ b/Tests/FortranModules/External/a.f90
@@ -0,0 +1,7 @@
+MODULE externalMod
+!
+CONTAINS
+ SUBROUTINE printExtModGreeting
+ WRITE(*,*) "Greetings from Module externalMod"
+ END SUBROUTINE
+END MODULE
diff --git a/Tests/FortranModules/Library/CMakeLists.txt b/Tests/FortranModules/Library/CMakeLists.txt
new file mode 100644
index 0000000..17438ca
--- /dev/null
+++ b/Tests/FortranModules/Library/CMakeLists.txt
@@ -0,0 +1,11 @@
+include_directories(${Library_MODDIR})
+add_library(subdir_mods a.f90 b.f90)
+add_executable(subdir_exe main.f90)
+target_link_libraries(subdir_exe subdir_mods)
+
+# Test module output directory if available.
+if(CMAKE_Fortran_MODDIR_FLAG)
+ set_target_properties(subdir_mods PROPERTIES
+ Fortran_MODULE_DIRECTORY modules
+ )
+endif()
diff --git a/Tests/FortranModules/Library/a.f90 b/Tests/FortranModules/Library/a.f90
new file mode 100644
index 0000000..c180cc0
--- /dev/null
+++ b/Tests/FortranModules/Library/a.f90
@@ -0,0 +1,6 @@
+MODULE libraryModuleA
+ USE libraryModuleB
+CONTAINS
+ SUBROUTINE libA
+ END SUBROUTINE
+END MODULE
diff --git a/Tests/FortranModules/Library/b.f90 b/Tests/FortranModules/Library/b.f90
new file mode 100644
index 0000000..f550996
--- /dev/null
+++ b/Tests/FortranModules/Library/b.f90
@@ -0,0 +1,5 @@
+MODULE libraryModuleB
+CONTAINS
+ SUBROUTINE libB
+ END SUBROUTINE
+END MODULE
diff --git a/Tests/FortranModules/Library/main.f90 b/Tests/FortranModules/Library/main.f90
new file mode 100644
index 0000000..2385408
--- /dev/null
+++ b/Tests/FortranModules/Library/main.f90
@@ -0,0 +1,3 @@
+PROGRAM MAINF90
+ USE libraryModuleA
+END PROGRAM MAINF90
diff --git a/Tests/FortranModules/Subdir/CMakeLists.txt b/Tests/FortranModules/Subdir/CMakeLists.txt
new file mode 100644
index 0000000..52683e5
--- /dev/null
+++ b/Tests/FortranModules/Subdir/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(subdir_mods2 subdir.f90)
+target_include_directories(subdir_mods2 INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/Tests/FortranModules/Subdir/subdir.f90 b/Tests/FortranModules/Subdir/subdir.f90
new file mode 100644
index 0000000..5288b06
--- /dev/null
+++ b/Tests/FortranModules/Subdir/subdir.f90
@@ -0,0 +1,5 @@
+MODULE subdirModuleA
+CONTAINS
+ SUBROUTINE subdirLibA
+ END SUBROUTINE
+END MODULE
diff --git a/Tests/FortranModules/Submodules/CMakeLists.txt b/Tests/FortranModules/Submodules/CMakeLists.txt
new file mode 100644
index 0000000..ab8e0f9
--- /dev/null
+++ b/Tests/FortranModules/Submodules/CMakeLists.txt
@@ -0,0 +1,23 @@
+# The program units in this file consist of a module/submodule
+# tree represented by the following graph:
+#
+# parent
+# |
+# / \
+# / \
+# child sibling
+# |
+# grandchild
+# |
+# GreatGrandChild
+#
+# where the parent node is a module and all other nodes are submodules.
+
+add_executable(submod
+ main.f90
+ parent.f90
+ child.f90
+ grandchild.f90
+ greatgrandchild.f90
+ sibling.f90
+ )
diff --git a/Tests/FortranModules/Submodules/child.f90 b/Tests/FortranModules/Submodules/child.f90
new file mode 100644
index 0000000..c314835
--- /dev/null
+++ b/Tests/FortranModules/Submodules/child.f90
@@ -0,0 +1,10 @@
+! Test the notation for a 1st-generation direct
+! descendant of a parent module
+SUBMODULE ( parent ) child
+ implicit none
+CONTAINS
+ module function child_function() result(child_stuff)
+ logical :: child_stuff
+ child_stuff=.true.
+ end function
+END SUBMODULE child
diff --git a/Tests/FortranModules/Submodules/grandchild.f90 b/Tests/FortranModules/Submodules/grandchild.f90
new file mode 100644
index 0000000..1aef63e
--- /dev/null
+++ b/Tests/FortranModules/Submodules/grandchild.f90
@@ -0,0 +1,8 @@
+! Test the notation for an Nth-generation descendant
+! for N>1, which necessitates the colon.
+submodule ( parent : child ) grandchild
+contains
+ module subroutine grandchild_subroutine()
+ print *,"Test passed."
+ end subroutine
+end submodule grandchild
diff --git a/Tests/FortranModules/Submodules/greatgrandchild.f90 b/Tests/FortranModules/Submodules/greatgrandchild.f90
new file mode 100644
index 0000000..85404ea
--- /dev/null
+++ b/Tests/FortranModules/Submodules/greatgrandchild.f90
@@ -0,0 +1,8 @@
+! Test the notation for an Nth-generation descendant
+! for N>1, which necessitates the colon.
+submodule ( parent : grandchild ) GreatGrandChild
+contains
+ module subroutine GreatGrandChild_subroutine()
+ print *,"Test passed."
+ end subroutine
+end submodule GreatGrandChild
diff --git a/Tests/FortranModules/Submodules/main.f90 b/Tests/FortranModules/Submodules/main.f90
new file mode 100644
index 0000000..3cd2989
--- /dev/null
+++ b/Tests/FortranModules/Submodules/main.f90
@@ -0,0 +1,7 @@
+program main
+ use parent, only : child_function,grandchild_subroutine
+ use parent, only : sibling_function,GreatGrandChild_subroutine
+ implicit none
+ if (child_function()) call grandchild_subroutine
+ if (sibling_function()) call GreatGrandChild_subroutine
+end program
diff --git a/Tests/FortranModules/Submodules/parent.f90 b/Tests/FortranModules/Submodules/parent.f90
new file mode 100644
index 0000000..3180b70
--- /dev/null
+++ b/Tests/FortranModules/Submodules/parent.f90
@@ -0,0 +1,22 @@
+module parent
+ implicit none
+
+ interface
+
+ ! Test Fortran 2008 "module function" syntax
+ module function child_function() result(child_stuff)
+ logical :: child_stuff
+ end function
+ module function sibling_function() result(sibling_stuff)
+ logical :: sibling_stuff
+ end function
+
+ ! Test Fortran 2008 "module subroutine" syntax
+ module subroutine grandchild_subroutine()
+ end subroutine
+ module subroutine GreatGrandChild_subroutine()
+ end subroutine
+
+ end interface
+
+end module parent
diff --git a/Tests/FortranModules/Submodules/sibling.f90 b/Tests/FortranModules/Submodules/sibling.f90
new file mode 100644
index 0000000..8c0943d
--- /dev/null
+++ b/Tests/FortranModules/Submodules/sibling.f90
@@ -0,0 +1,9 @@
+! Empty submodule for checking disambiguation of
+! nodes at the same vertical level in the tree
+submodule ( parent ) sibling
+contains
+ module function sibling_function() result(sibling_stuff)
+ logical :: sibling_stuff
+ sibling_stuff=.true.
+ end function
+end submodule sibling
diff --git a/Tests/FortranModules/in_interface/main.f90 b/Tests/FortranModules/in_interface/main.f90
new file mode 100644
index 0000000..28bcf36
--- /dev/null
+++ b/Tests/FortranModules/in_interface/main.f90
@@ -0,0 +1,3 @@
+program hello
+ use test_interface
+end program hello
diff --git a/Tests/FortranModules/in_interface/module.f90 b/Tests/FortranModules/in_interface/module.f90
new file mode 100644
index 0000000..1064d74
--- /dev/null
+++ b/Tests/FortranModules/in_interface/module.f90
@@ -0,0 +1,12 @@
+module test_interface
+
+ interface dummy
+ module procedure module_function
+ end interface
+
+contains
+
+ subroutine module_function
+ end subroutine
+
+end module test_interface \ No newline at end of file
diff --git a/Tests/FortranModules/include/test_preprocess.h b/Tests/FortranModules/include/test_preprocess.h
new file mode 100644
index 0000000..f4a00a9
--- /dev/null
+++ b/Tests/FortranModules/include/test_preprocess.h
@@ -0,0 +1,5 @@
+#ifdef BAR
+PRINT*, 'BAR was defined via ADD_DEFINITIONS'
+#else
+PRINT*, 'If you can read this something went wrong'
+#endif
diff --git a/Tests/FortranModules/non_pp_include.f90 b/Tests/FortranModules/non_pp_include.f90
new file mode 100644
index 0000000..7eb1725
--- /dev/null
+++ b/Tests/FortranModules/non_pp_include.f90
@@ -0,0 +1,3 @@
+SUBROUTINE NON_PP_INCLUDE_SUBROUTINE
+ PRINT *, "Hello World!"
+END SUBROUTINE NON_PP_INCLUDE_SUBROUTINE
diff --git a/Tests/FortranModules/test_module_implementation.f90 b/Tests/FortranModules/test_module_implementation.f90
new file mode 100644
index 0000000..de3cb57
--- /dev/null
+++ b/Tests/FortranModules/test_module_implementation.f90
@@ -0,0 +1,6 @@
+FUNCTION TEST_MODULE_FUNCTION(A,B)
+ REAL :: TEST_MODULE_FUNCTION
+ REAL, INTENT(IN) :: A
+ REAL, INTENT(IN) :: B
+ TEST_MODULE_FUNCTION = A + B
+END FUNCTION TEST_MODULE_FUNCTION
diff --git a/Tests/FortranModules/test_module_interface.f90 b/Tests/FortranModules/test_module_interface.f90
new file mode 100644
index 0000000..dd0f35c
--- /dev/null
+++ b/Tests/FortranModules/test_module_interface.f90
@@ -0,0 +1,9 @@
+MODULE TEST_MODULE
+ INTERFACE
+ FUNCTION TEST_MODULE_FUNCTION(A,B)
+ REAL :: TEST_MODULE_FUNCTION
+ REAL, INTENT(IN) :: A
+ REAL, INTENT(IN) :: B
+ END FUNCTION TEST_MODULE_FUNCTION
+ END INTERFACE
+END MODULE TEST_MODULE
diff --git a/Tests/FortranModules/test_module_main.f90 b/Tests/FortranModules/test_module_main.f90
new file mode 100644
index 0000000..6ac97fa
--- /dev/null
+++ b/Tests/FortranModules/test_module_main.f90
@@ -0,0 +1,4 @@
+PROGRAM MAINF90
+ USE TEST_MODULE
+ PRINT *,'Sum is',TEST_MODULE_FUNCTION(1., 2.)
+END PROGRAM MAINF90
diff --git a/Tests/FortranModules/test_non_pp_include_main.f90 b/Tests/FortranModules/test_non_pp_include_main.f90
new file mode 100644
index 0000000..8a04fbd
--- /dev/null
+++ b/Tests/FortranModules/test_non_pp_include_main.f90
@@ -0,0 +1,5 @@
+INCLUDE "non_pp_include.f90"
+
+PROGRAM MAINF90
+ CALL NON_PP_INCLUDE_SUBROUTINE
+END PROGRAM MAINF90
diff --git a/Tests/FortranModules/test_preprocess.F90 b/Tests/FortranModules/test_preprocess.F90
new file mode 100644
index 0000000..c5a5ec3
--- /dev/null
+++ b/Tests/FortranModules/test_preprocess.F90
@@ -0,0 +1,53 @@
+MODULE Available
+! no content
+END MODULE
+
+PROGRAM PPTEST
+! value of InPPFalseBranch ; values of SkipToEnd
+! 0 <empty>
+#ifndef FOO
+ ! 1 ; <0>
+ USE NotAvailable
+# ifndef FOO
+ ! 2 ; <0,0>
+ USE NotAvailable
+# else
+ ! 2 ; <0,0>
+ USE NotAvailable
+# endif
+ ! 1 ; <0>
+# ifdef FOO
+ ! 2 ; <0,1>
+ USE NotAvailable
+# else
+ ! 2 ; <0,1>
+ USE NotAvailable
+# endif
+ ! 1 ; <0>
+#else
+ ! 0 ; <0>
+ USE Available
+# ifndef FOO
+ ! 1 ; <0,0>
+ USE NotAvailable
+# else
+ ! 0 ; <0,0>
+ USE Available
+# endif
+ ! 0 ; <0>
+# ifdef FOO
+ ! 0 ; <0,1>
+ USE Available
+# else
+ ! 1 ; <0,1>
+ USE NotAvailable
+# endif
+ ! 0 ; <0>
+#endif
+! 0 ; <empty>
+
+USE PPAvailable
+
+#include "test_preprocess.h"
+
+END PROGRAM
diff --git a/Tests/FortranModules/test_preprocess_module.F90 b/Tests/FortranModules/test_preprocess_module.F90
new file mode 100644
index 0000000..fdbc051
--- /dev/null
+++ b/Tests/FortranModules/test_preprocess_module.F90
@@ -0,0 +1,5 @@
+#ifdef FOO
+MODULE PPAvailable
+! no content
+END MODULE
+#endif
diff --git a/Tests/FortranModules/test_use_in_comment_fixedform.f b/Tests/FortranModules/test_use_in_comment_fixedform.f
new file mode 100644
index 0000000..39f486b
--- /dev/null
+++ b/Tests/FortranModules/test_use_in_comment_fixedform.f
@@ -0,0 +1,7 @@
+ PROGRAM foo
+! USE bar
+! use bar
+! Use bar
+
+ WRITE(*,*) 'Hello, Fortran world.'
+ END PROGRAM
diff --git a/Tests/FortranModules/test_use_in_comment_freeform.f90 b/Tests/FortranModules/test_use_in_comment_freeform.f90
new file mode 100644
index 0000000..48bcd5a
--- /dev/null
+++ b/Tests/FortranModules/test_use_in_comment_freeform.f90
@@ -0,0 +1,7 @@
+PROGRAM foo
+! USE bar
+! use bar
+! Use bar
+
+ WRITE(*,*) 'Hello, Fortran world.'
+END PROGRAM
diff --git a/Tests/FortranOnly/CMakeLists.txt b/Tests/FortranOnly/CMakeLists.txt
new file mode 100644
index 0000000..cdf8ed6
--- /dev/null
+++ b/Tests/FortranOnly/CMakeLists.txt
@@ -0,0 +1,160 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(FortranOnly Fortran)
+message("CTEST_FULL_OUTPUT ")
+
+# create a library with hello and world functions
+add_library(FortranOnlylib hello.f world.f)
+set_property(TARGET FortranOnlylib PROPERTY Fortran_FORMAT FIXED)
+set_property(SOURCE world.f PROPERTY Fortran_FORMAT FREE)
+
+# create an executable that calls hello and world
+add_executable(FortranOnly1 testf.f)
+set_property(TARGET FortranOnly1 PROPERTY OUTPUT_NAME FortranOnly)
+target_link_libraries(FortranOnly1 FortranOnlylib)
+
+# Test that Fortran+RC work together.
+# FIXME: Add .rc in more cases.
+if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(test_rc testRC.rc)
+endif()
+
+# create a custom command that runs FortranOnly1 and puts
+# the output into the file testfhello.txt
+add_custom_command(OUTPUT ${FortranOnly_BINARY_DIR}/testfhello.txt
+ COMMAND FortranOnly1
+ > testfhello.txt)
+# create a second executable FortranOnly2 that has
+# testfhello.txt has an source file so that it will
+# run the above custom command.
+add_executable(FortranOnly2 testfhello.txt testf.f ${test_rc})
+target_link_libraries(FortranOnly2 FortranOnlylib)
+# create a custom target to check the content of testfhello.txt
+# by running the cmake script checktestf2.cmake
+add_custom_target(checktestf2 ALL
+ COMMAND ${CMAKE_COMMAND}
+ -P ${FortranOnly_SOURCE_DIR}/checktestf2.cmake)
+
+# create a custom target that runs FortranOnly1 executable and creates
+# a file out.txt that should have hello world in it.
+add_custom_target(sayhello ALL
+ COMMAND FortranOnly1 > out.txt
+)
+# make sure stuff is built in the right order
+add_dependencies(checktestf2 FortranOnly2)
+add_dependencies(sayhello FortranOnly1)
+add_dependencies(FortranOnly2 FortranOnly1)
+
+# add a custom target that checks that out.txt has the correct
+# content
+add_custom_target(checksayhello ALL
+ COMMAND ${CMAKE_COMMAND} -P ${FortranOnly_SOURCE_DIR}/checksayhello.cmake
+ )
+add_dependencies(checksayhello sayhello)
+
+set(err_log ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeError.log)
+file(REMOVE "${err_log}")
+include(CheckFortranSourceCompiles)
+unset(HAVE_PRINT CACHE)
+CHECK_Fortran_SOURCE_COMPILES([[
+ PROGRAM TEST_HAVE_PRINT
+ PRINT *, 'Hello'
+ END
+]] HAVE_PRINT)
+if(NOT HAVE_PRINT)
+ if(EXISTS "${err_log}")
+ file(READ "${err_log}" err)
+ endif()
+ string(REPLACE "\n" "\n " err " ${err}")
+ message(SEND_ERROR "CHECK_Fortran_SOURCE_COMPILES for HAVE_PRINT failed:\n"
+ "${err}")
+endif()
+
+unset(Fortran_BOGUS_FLAG CACHE)
+include(CheckFortranCompilerFlag)
+CHECK_Fortran_COMPILER_FLAG(-_this_is_not_a_flag_ Fortran_BOGUS_FLAG)
+if (Fortran_BOGUS_FLAG)
+ message(SEND_ERROR "CHECK_Fortran_COMPILER_FLAG() succeeded, but should have failed")
+endif()
+
+unset(Fortran_RUN_FLAG CACHE)
+include(CheckFortranSourceRuns)
+check_fortran_source_runs("program a; end program" Fortran_RUN_FLAG SRC_EXT F90)
+if(NOT Fortran_RUN_FLAG)
+ message(SEND_ERROR "CHECK_Fortran_SOURCE_RUNS() failed")
+endif()
+
+# Test generation of preprocessed sources.
+if("${CMAKE_GENERATOR}" MATCHES "Makefile" AND CMAKE_MAKE_PROGRAM)
+ if(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE)
+ # Skip running this part of the test on certain platforms
+ # until they are fixed.
+ set(MAYBE_ALL ALL)
+ list(LENGTH CMAKE_OSX_ARCHITECTURES ARCH_COUNT)
+ if(ARCH_COUNT GREATER 1)
+ # OSX does not support preprocessing more than one architecture.
+ set(MAYBE_ALL)
+ endif()
+
+ add_executable(preprocess preprocess.F)
+
+ # Custom target to try preprocessing invocation.
+ add_custom_target(test_preprocess ${MAYBE_ALL}
+ COMMAND ${CMAKE_COMMAND} -E rm -f CMakeFiles/preprocess.dir/preprocess.F.i
+ COMMAND ${CMAKE_MAKE_PROGRAM} preprocess.i
+ COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/test_preprocess.cmake
+ # Remove bogus file some compilers leave behind.
+ COMMAND ${CMAKE_COMMAND} -E rm -f ${CMAKE_CURRENT_SOURCE_DIR}/preprocess.s
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ )
+ endif()
+endif()
+
+# Test that with Intel Fortran we always compile with preprocessor
+# defines even if splitting the preprocessing and compilation steps.
+if(CMAKE_Fortran_COMPILER_ID MATCHES "Intel")
+ add_executable(IntelIfDef IntelIfDef.f)
+ set_property(TARGET IntelIfDef PROPERTY Fortran_FORMAT FIXED)
+ target_compile_definitions(IntelIfDef PRIVATE SOME_DEF)
+endif()
+
+# Skip these tests if compiler/version does enable and disable preprocessing
+if(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON AND
+ CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF)
+ # Test that we can always preprocess a target
+ add_executable(preprocess_target preprocess2.f)
+ set_property(TARGET preprocess_target PROPERTY Fortran_PREPROCESS ON)
+
+ # Test that we can preprocess a single source file
+ add_executable(preprocess_source preprocess3.f)
+ set_property(SOURCE preprocess3.f PROPERTY Fortran_PREPROCESS ON)
+endif()
+
+# Test that neither the compiler nor CMake performs unnecessary preprocessing.
+add_library(no_preprocess_target_lower STATIC no_preprocess_target_lower.f)
+target_compile_options(no_preprocess_target_lower PRIVATE -DINTEGER=nonsense)
+set_property(TARGET no_preprocess_target_lower PROPERTY Fortran_PREPROCESS OFF)
+add_library(no_preprocess_source_lower STATIC no_preprocess_source_lower.f)
+target_compile_options(no_preprocess_source_lower PRIVATE -DINTEGER=nonsense)
+set_property(SOURCE no_preprocess_source_lower.f PROPERTY Fortran_PREPROCESS OFF)
+
+# Test that we can explicitly not preprocess a target or source.
+# This will not work on certain compilers due to either missing a
+# "don't preprocess" flag, or due to the flags being ignored for
+# extensions like '.F' and '.fpp'.
+if(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF AND
+ NOT CMAKE_Fortran_COMPILER_ID MATCHES "(Flang|NAG|PGI|NVHPC|SunPro|XL)")
+ add_library(no_preprocess_target STATIC no_preprocess_target_upper.F)
+ target_compile_options(no_preprocess_target PRIVATE -DINTEGER=nonsense)
+
+ add_library(no_preprocess_source STATIC no_preprocess_source_upper.F)
+ target_compile_options(no_preprocess_source PRIVATE -DINTEGER=nonsense)
+
+ if(NOT CMAKE_Fortran_COMPILER_ID STREQUAL "Cray"
+ AND NOT "${CMAKE_Fortran_COMPILER_ID};${CMAKE_Fortran_SIMULATE_ID}" MATCHES "Intel(LLVM)?;MSVC")
+ target_sources(no_preprocess_target PRIVATE no_preprocess_target_fpp.fpp)
+ target_sources(no_preprocess_source PRIVATE no_preprocess_source_fpp.fpp)
+ endif()
+
+ set_property(TARGET no_preprocess_target PROPERTY Fortran_PREPROCESS OFF)
+ set_property(SOURCE no_preprocess_source_upper.F no_preprocess_source_fpp.fpp PROPERTY Fortran_PREPROCESS OFF)
+endif()
diff --git a/Tests/FortranOnly/IntelIfDef.f b/Tests/FortranOnly/IntelIfDef.f
new file mode 100644
index 0000000..d7a73d1
--- /dev/null
+++ b/Tests/FortranOnly/IntelIfDef.f
@@ -0,0 +1,3 @@
+ INCLUDE 'IntelIfDef.inc'
+ PROGRAM IntelIfDef
+ END
diff --git a/Tests/FortranOnly/IntelIfDef.inc b/Tests/FortranOnly/IntelIfDef.inc
new file mode 100644
index 0000000..52edafa
--- /dev/null
+++ b/Tests/FortranOnly/IntelIfDef.inc
@@ -0,0 +1,3 @@
+CDEC$ IF .NOT. DEFINED(SOME_DEF)
+CDEC$ INCLUDE 'SOME_DEF not defined'
+CDEC$ END IF
diff --git a/Tests/FortranOnly/checksayhello.cmake b/Tests/FortranOnly/checksayhello.cmake
new file mode 100644
index 0000000..5352290
--- /dev/null
+++ b/Tests/FortranOnly/checksayhello.cmake
@@ -0,0 +1,7 @@
+file(READ out.txt IN)
+message("${IN}")
+if(IN MATCHES Hello AND IN MATCHES World)
+ message("Passed")
+else()
+ message(FATAL_ERROR "Hello world not found")
+endif()
diff --git a/Tests/FortranOnly/checktestf2.cmake b/Tests/FortranOnly/checktestf2.cmake
new file mode 100644
index 0000000..f0e6be3
--- /dev/null
+++ b/Tests/FortranOnly/checktestf2.cmake
@@ -0,0 +1,8 @@
+file(READ testfhello.txt IN)
+message("${IN}")
+if(IN MATCHES Hello AND IN MATCHES World)
+ message("Passed")
+else()
+ message(FATAL_ERROR "Hello world not found")
+endif()
+file(WRITE testfhello2.txt ${IN})
diff --git a/Tests/FortranOnly/hello.f b/Tests/FortranOnly/hello.f
new file mode 100644
index 0000000..63e6408
--- /dev/null
+++ b/Tests/FortranOnly/hello.f
@@ -0,0 +1,5 @@
+ SUBROUTINE HELLO
+
+ PRINT *, 'Hello'
+
+ END
diff --git a/Tests/FortranOnly/no_preprocess_source_fpp.fpp b/Tests/FortranOnly/no_preprocess_source_fpp.fpp
new file mode 100644
index 0000000..8e48902
--- /dev/null
+++ b/Tests/FortranOnly/no_preprocess_source_fpp.fpp
@@ -0,0 +1,3 @@
+ SUBROUTINE NOPREPROCESS_SOURCE_FPP
+ INTEGER F
+ END
diff --git a/Tests/FortranOnly/no_preprocess_source_lower.f b/Tests/FortranOnly/no_preprocess_source_lower.f
new file mode 100644
index 0000000..3b08782
--- /dev/null
+++ b/Tests/FortranOnly/no_preprocess_source_lower.f
@@ -0,0 +1,3 @@
+ SUBROUTINE NOPREPROCESS_SOURCE_LOWER
+ INTEGER F
+ END
diff --git a/Tests/FortranOnly/no_preprocess_source_upper.F b/Tests/FortranOnly/no_preprocess_source_upper.F
new file mode 100644
index 0000000..02485c9
--- /dev/null
+++ b/Tests/FortranOnly/no_preprocess_source_upper.F
@@ -0,0 +1,3 @@
+ SUBROUTINE NOPREPROCESS_SOURCE_UPPER
+ INTEGER F
+ END
diff --git a/Tests/FortranOnly/no_preprocess_target_fpp.fpp b/Tests/FortranOnly/no_preprocess_target_fpp.fpp
new file mode 100644
index 0000000..f9e6e3b
--- /dev/null
+++ b/Tests/FortranOnly/no_preprocess_target_fpp.fpp
@@ -0,0 +1,3 @@
+ SUBROUTINE NOPREPROCESS_TARGET_FPP
+ INTEGER F
+ END
diff --git a/Tests/FortranOnly/no_preprocess_target_lower.f b/Tests/FortranOnly/no_preprocess_target_lower.f
new file mode 100644
index 0000000..ea23a70
--- /dev/null
+++ b/Tests/FortranOnly/no_preprocess_target_lower.f
@@ -0,0 +1,3 @@
+ SUBROUTINE NOPREPROCESS_TARGET_LOWER
+ INTEGER F
+ END
diff --git a/Tests/FortranOnly/no_preprocess_target_upper.F b/Tests/FortranOnly/no_preprocess_target_upper.F
new file mode 100644
index 0000000..34ee04d
--- /dev/null
+++ b/Tests/FortranOnly/no_preprocess_target_upper.F
@@ -0,0 +1,3 @@
+ SUBROUTINE NOPREPROCESS_TARGET_UPPER
+ INTEGER F
+ END
diff --git a/Tests/FortranOnly/preprocess.F b/Tests/FortranOnly/preprocess.F
new file mode 100644
index 0000000..f7df457
--- /dev/null
+++ b/Tests/FortranOnly/preprocess.F
@@ -0,0 +1,5 @@
+ PROGRAM PREPRO
+#ifndef TEST_PREPROCESSOR
+ PRINT *, 'Hello'
+#endif
+ END
diff --git a/Tests/FortranOnly/preprocess2.f b/Tests/FortranOnly/preprocess2.f
new file mode 100644
index 0000000..6595d62
--- /dev/null
+++ b/Tests/FortranOnly/preprocess2.f
@@ -0,0 +1,4 @@
+#define int INTEGER
+ PROGRAM PREPRO
+ int f
+ END
diff --git a/Tests/FortranOnly/preprocess3.f b/Tests/FortranOnly/preprocess3.f
new file mode 100644
index 0000000..6595d62
--- /dev/null
+++ b/Tests/FortranOnly/preprocess3.f
@@ -0,0 +1,4 @@
+#define int INTEGER
+ PROGRAM PREPRO
+ int f
+ END
diff --git a/Tests/FortranOnly/testRC.rc b/Tests/FortranOnly/testRC.rc
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/FortranOnly/testRC.rc
diff --git a/Tests/FortranOnly/test_preprocess.cmake b/Tests/FortranOnly/test_preprocess.cmake
new file mode 100644
index 0000000..29ebdac
--- /dev/null
+++ b/Tests/FortranOnly/test_preprocess.cmake
@@ -0,0 +1,7 @@
+set(TEST_FILE CMakeFiles/preprocess.dir/preprocess.F.i)
+file(READ ${TEST_FILE} CONTENTS)
+if("${CONTENTS}" MATCHES "PRINT *")
+ message(STATUS "${TEST_FILE} created successfully!")
+else()
+ message(FATAL_ERROR "${TEST_FILE} creation failed!")
+endif()
diff --git a/Tests/FortranOnly/testf.f b/Tests/FortranOnly/testf.f
new file mode 100644
index 0000000..4909181
--- /dev/null
+++ b/Tests/FortranOnly/testf.f
@@ -0,0 +1,6 @@
+ PROGRAM TESTF
+
+ CALL HELLO()
+ CALL WORLD()
+
+ END
diff --git a/Tests/FortranOnly/world.f b/Tests/FortranOnly/world.f
new file mode 100644
index 0000000..342b244
--- /dev/null
+++ b/Tests/FortranOnly/world.f
@@ -0,0 +1,4 @@
+! Free-format ".f" file to test Fortran_FORMAT property
+SUBROUTINE WORLD
+ PRINT *, 'World!'
+END
diff --git a/Tests/Framework/CMakeLists.txt b/Tests/Framework/CMakeLists.txt
new file mode 100644
index 0000000..287be94
--- /dev/null
+++ b/Tests/Framework/CMakeLists.txt
@@ -0,0 +1,112 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(Framework)
+
+add_library(foo SHARED
+ foo.cxx
+ foo.h
+ foo2.h
+ fooExtensionlessResource
+ fooPublic.h
+ fooPublicExtensionlessHeader
+ fooPrivate.h
+ fooPrivateExtensionlessHeader
+ fooNeither.h
+ fooBoth.h
+ test.lua
+ fooDeepPublic.h
+)
+set_property(SOURCE fooDeepPublic.h
+ PROPERTY MACOSX_PACKAGE_LOCATION Headers/Deep
+ )
+set(foo_ver ver4)
+
+set_target_properties(foo PROPERTIES
+ FRAMEWORK TRUE
+ FRAMEWORK_VERSION ${foo_ver}
+ PRIVATE_HEADER "fooPrivate.h;fooBoth.h;fooPrivateExtensionlessHeader"
+ PUBLIC_HEADER "foo.h;foo2.h;fooPublic.h;fooBoth.h;fooPublicExtensionlessHeader"
+ RESOURCE "fooExtensionlessResource;test.lua"
+ INSTALL_NAME_DIR "@executable_path/../../../Library/Frameworks"
+ DEBUG_POSTFIX -d
+)
+# fooBoth.h is listed as both public and private... (private wins...)
+# fooNeither.h is listed as neither public nor private...
+
+add_executable(bar bar.cxx)
+target_link_libraries(bar foo)
+install(TARGETS foo bar
+ RUNTIME DESTINATION Applications/CMakeTestsFramework/bin
+ FRAMEWORK DESTINATION Library/Frameworks
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib
+
+ # These are ignored on the Mac... and things are automatically placed in
+ # their appropriate Framework sub-folder at build time. (And then the built
+ # framework is copied recursively when it is installed.)
+ PRIVATE_HEADER DESTINATION share/foo-${foo_ver}/PrivateHeaders
+ PUBLIC_HEADER DESTINATION include/foo-${foo_ver}
+ RESOURCE DESTINATION share/foo-${foo_ver}/Resources
+ # But they are required to be present so that installing a framework on other
+ # other platforms will install the pieces of the framework without having to
+ # duplicate install rules for the pieces of the framework.
+)
+
+# test that framework post-build commands run
+add_custom_command(TARGET foo POST_BUILD COMMAND ${CMAKE_COMMAND} -E touch foo-post-build)
+add_custom_target(fooCustom ALL COMMAND ${CMAKE_COMMAND} -E copy foo-post-build foo-custom)
+add_dependencies(fooCustom foo)
+
+# Make a static library and apply the framework properties to it to verify
+# that everything still builds correctly. Xcode prior to version 5 does not
+# support static Frameworks.
+#
+if(NOT XCODE OR NOT XCODE_VERSION VERSION_LESS 5)
+ add_library(fooStatic STATIC
+ foo.cxx
+ foo.h
+ foo2.h
+ fooExtensionlessResource
+ fooPublic.h
+ fooPublicExtensionlessHeader
+ fooPrivate.h
+ fooPrivateExtensionlessHeader
+ fooNeither.h
+ fooBoth.h
+ test.lua
+ fooDeepPublic.h
+ )
+ set_target_properties(fooStatic PROPERTIES
+ FRAMEWORK TRUE
+ FRAMEWORK_VERSION none
+ )
+ add_executable(barStatic bar.cxx)
+ target_link_libraries(barStatic fooStatic)
+endif()
+
+if(MAKE_SUPPORTS_SPACES AND NOT CMAKE_GENERATOR STREQUAL "Watcom WMake")
+ add_library(space SHARED space.c)
+ set_target_properties(space PROPERTIES
+ FRAMEWORK TRUE
+ OUTPUT_NAME "space space"
+ )
+ add_executable(use_space use_space.c)
+ target_link_libraries(use_space PRIVATE space)
+endif()
+
+include(CPack)
+
+if(APPLE)
+ set(ExternalFramework_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/External")
+ file(REMOVE_RECURSE "${ExternalFramework_INSTALL_DIR}")
+
+ include(ExternalProject)
+ ExternalProject_Add(ExternalFramework
+ SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/External"
+ INSTALL_DIR "${ExternalFramework_INSTALL_DIR}"
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
+ )
+
+ add_executable(useExternal useExternal.c)
+ target_link_libraries(useExternal PRIVATE "${ExternalFramework_INSTALL_DIR}/lib/External.framework")
+ add_dependencies(useExternal ExternalFramework)
+endif()
diff --git a/Tests/Framework/External/CMakeLists.txt b/Tests/Framework/External/CMakeLists.txt
new file mode 100644
index 0000000..b9128fd
--- /dev/null
+++ b/Tests/Framework/External/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.19)
+project(ExternalFramework C)
+add_library(External SHARED external.c)
+set_property(TARGET External PROPERTY FRAMEWORK 1)
+install(TARGETS External DESTINATION lib)
diff --git a/Tests/Framework/External/external.c b/Tests/Framework/External/external.c
new file mode 100644
index 0000000..8441e71
--- /dev/null
+++ b/Tests/Framework/External/external.c
@@ -0,0 +1,4 @@
+int external(void)
+{
+ return 0;
+}
diff --git a/Tests/Framework/bar.cxx b/Tests/Framework/bar.cxx
new file mode 100644
index 0000000..37c132a
--- /dev/null
+++ b/Tests/Framework/bar.cxx
@@ -0,0 +1,6 @@
+void foo();
+int main()
+{
+ foo();
+ return 0;
+}
diff --git a/Tests/Framework/foo.cxx b/Tests/Framework/foo.cxx
new file mode 100644
index 0000000..a4d15f6
--- /dev/null
+++ b/Tests/Framework/foo.cxx
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#if defined(_WIN32) && defined(foo_EXPORTS)
+# define CM_TEST_LIB_EXPORT __declspec(dllexport)
+#else
+# define CM_TEST_LIB_EXPORT
+#endif
+CM_TEST_LIB_EXPORT void foo()
+{
+ printf("foo\n");
+}
diff --git a/Tests/Framework/foo.h b/Tests/Framework/foo.h
new file mode 100644
index 0000000..d959c81
--- /dev/null
+++ b/Tests/Framework/foo.h
@@ -0,0 +1 @@
+fooh
diff --git a/Tests/Framework/foo2.h b/Tests/Framework/foo2.h
new file mode 100644
index 0000000..2431d79
--- /dev/null
+++ b/Tests/Framework/foo2.h
@@ -0,0 +1 @@
+foo2h
diff --git a/Tests/Framework/fooBoth.h b/Tests/Framework/fooBoth.h
new file mode 100644
index 0000000..5a0f330
--- /dev/null
+++ b/Tests/Framework/fooBoth.h
@@ -0,0 +1 @@
+fooBothh
diff --git a/Tests/Framework/fooDeepPublic.h b/Tests/Framework/fooDeepPublic.h
new file mode 100644
index 0000000..3fc4108
--- /dev/null
+++ b/Tests/Framework/fooDeepPublic.h
@@ -0,0 +1 @@
+fooDeepPublic
diff --git a/Tests/Framework/fooExtensionlessResource b/Tests/Framework/fooExtensionlessResource
new file mode 100644
index 0000000..5122750
--- /dev/null
+++ b/Tests/Framework/fooExtensionlessResource
@@ -0,0 +1 @@
+fooExtensionlessResource
diff --git a/Tests/Framework/fooNeither.h b/Tests/Framework/fooNeither.h
new file mode 100644
index 0000000..04736a1
--- /dev/null
+++ b/Tests/Framework/fooNeither.h
@@ -0,0 +1 @@
+fooNeitherh
diff --git a/Tests/Framework/fooPrivate.h b/Tests/Framework/fooPrivate.h
new file mode 100644
index 0000000..dc8cb34
--- /dev/null
+++ b/Tests/Framework/fooPrivate.h
@@ -0,0 +1 @@
+fooPrivateh
diff --git a/Tests/Framework/fooPrivateExtensionlessHeader b/Tests/Framework/fooPrivateExtensionlessHeader
new file mode 100644
index 0000000..ac97b92
--- /dev/null
+++ b/Tests/Framework/fooPrivateExtensionlessHeader
@@ -0,0 +1 @@
+fooPrivateExtensionlessHeader
diff --git a/Tests/Framework/fooPublic.h b/Tests/Framework/fooPublic.h
new file mode 100644
index 0000000..f0469de
--- /dev/null
+++ b/Tests/Framework/fooPublic.h
@@ -0,0 +1 @@
+fooPublich
diff --git a/Tests/Framework/fooPublicExtensionlessHeader b/Tests/Framework/fooPublicExtensionlessHeader
new file mode 100644
index 0000000..972d989
--- /dev/null
+++ b/Tests/Framework/fooPublicExtensionlessHeader
@@ -0,0 +1 @@
+fooPublicExtensionlessHeader
diff --git a/Tests/Framework/space.c b/Tests/Framework/space.c
new file mode 100644
index 0000000..bf5b0c3
--- /dev/null
+++ b/Tests/Framework/space.c
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int space(void)
+{
+ return 0;
+}
diff --git a/Tests/Framework/test.lua b/Tests/Framework/test.lua
new file mode 100644
index 0000000..ce5c3eb
--- /dev/null
+++ b/Tests/Framework/test.lua
@@ -0,0 +1 @@
+test.lua
diff --git a/Tests/Framework/useExternal.c b/Tests/Framework/useExternal.c
new file mode 100644
index 0000000..8494b15
--- /dev/null
+++ b/Tests/Framework/useExternal.c
@@ -0,0 +1,6 @@
+extern int external(void);
+
+int main(void)
+{
+ return external();
+}
diff --git a/Tests/Framework/use_space.c b/Tests/Framework/use_space.c
new file mode 100644
index 0000000..bb4893d
--- /dev/null
+++ b/Tests/Framework/use_space.c
@@ -0,0 +1,8 @@
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+ int space(void);
+int main(void)
+{
+ return space();
+}
diff --git a/Tests/FunctionTest/CMakeLists.txt b/Tests/FunctionTest/CMakeLists.txt
new file mode 100644
index 0000000..6450447
--- /dev/null
+++ b/Tests/FunctionTest/CMakeLists.txt
@@ -0,0 +1,176 @@
+# a simple C only test case
+cmake_minimum_required (VERSION 2.8.12)
+project (FunctionTest)
+
+function(FAILED testname)
+ message(SEND_ERROR "${testname} failed ${ARGN}")
+endfunction()
+
+function(PASS testname)
+ message("${testname} passed ${ARGN}")
+endfunction()
+
+
+# test scope
+set(COUNT 3)
+function(scope_test)
+ set(COUNT 4)
+endfunction()
+scope_test()
+if(COUNT EQUAL "3")
+ PASS("scope")
+else()
+ FAILED("COUNT Got: ${COUNT}")
+endif()
+
+# test ARGC
+function(weird_name)
+ if("${ARGC}" EQUAL "3")
+ PASS("ARGC")
+ else()
+ FAILED("ARGC" "Got: ${ARGC}")
+ endif()
+endfunction()
+WeIrD_nAmE(a1 a2 a3)
+
+# test ARGN
+function(test_argn_function argument)
+ if("${ARGN}" EQUAL "3")
+ PASS("ARGN")
+ else()
+ FAILED("ARGN" "Got: ${ARGN}")
+ endif()
+endfunction()
+Test_Argn_Function(ignored 3)
+
+# test argument naming and raise scope
+function(track_find_variable cache_variable is_changed)
+ set("${is_changed}" changed PARENT_SCOPE)
+endfunction()
+track_find_variable(testvar is_changed)
+if ("${is_changed}" STREQUAL changed)
+ pass("same argument name test")
+else ()
+ pass("same argument name test")
+endif ()
+
+include("Util.cmake")
+tester()
+if (tester_res STREQUAL "${CMAKE_CURRENT_LIST_FILE}")
+ pass("CMAKE_CURRENT_LIST_FILE test")
+else ()
+ pass("CMAKE_CURRENT_LIST_FILE test")
+endif ()
+
+
+
+# test recursion and return via set(... PARENT_SCOPE)
+function (factorial argument result)
+ if (argument LESS 2)
+ set (lresult 1)
+ else ()
+ math (EXPR temp "${argument} - 1")
+ factorial (${temp} tresult)
+ math (EXPR lresult "${argument}*${tresult}")
+ endif ()
+ set ("${result}" "${lresult}" PARENT_SCOPE)
+endfunction ()
+
+factorial (5 fresult)
+if (fresult EQUAL 120)
+ pass("factorial")
+else ()
+ failed ("factorial, computed ${fresult} instead of 120")
+endif ()
+
+
+
+# case test
+function(strange_function m)
+ set("${m}" strange_function PARENT_SCOPE)
+endfunction()
+
+STRANGE_FUNCTION(var)
+set(second_var "second_var")
+if("x${var}" STREQUAL "xstrange_function" AND "x${second_var}" STREQUAL "xsecond_var")
+ PASS("Case Test" "(${var} ${second_var})")
+else()
+ FAILED("Case test" "(${var} ${second_var})")
+endif()
+
+# test backing up command
+function(ADD_EXECUTABLE exec)
+ _ADD_EXECUTABLE(mini${exec} ${ARGN})
+endfunction()
+
+# var undef case
+function(undef_var m)
+ set("${m}" PARENT_SCOPE)
+endfunction()
+
+set(FUNCTION_UNDEFINED 1)
+undef_var(FUNCTION_UNDEFINED)
+if(DEFINED FUNCTION_UNDEFINED)
+ FAILED("Function Undefine Test" "(${FUNCTION_UNDEFINED})")
+else()
+ PASS("Function Undefine Test" "(${FUNCTION_UNDEFINED})")
+endif()
+
+# Subdirectory scope raise.
+set(SUBDIR_UNDEFINED 1)
+add_subdirectory(SubDirScope)
+if(DEFINED SUBDIR_UNDEFINED)
+ FAILED("Subdir Undefine Test" "(${SUBDIR_UNDEFINED})")
+else()
+ PASS("Subdir Undefine Test" "(${SUBDIR_UNDEFINED})")
+endif()
+if(DEFINED SUBDIR_DEFINED)
+ PASS("Subdir Define Test" "(${SUBDIR_DEFINED})")
+else()
+ FAILED("Subdir Define Test" "(${SUBDIR_DEFINED})")
+endif()
+
+# Test function-scoped directory.
+function(ADD_SUBDIR2 dir)
+ add_subdirectory("${dir}" "${dir}2")
+ # The parent scope sets in the subdir should be visible here.
+ if(DEFINED SUBDIR_UNDEFINED)
+ FAILED("Subdir Function Undefine Test 1" "(${SUBDIR_UNDEFINED})")
+ else()
+ PASS("Subdir Function Undefine Test 1" "(${SUBDIR_UNDEFINED})")
+ endif()
+ if(DEFINED SUBDIR_DEFINED)
+ PASS("Subdir Function Define Test 1" "(${SUBDIR_DEFINED})")
+ else()
+ FAILED("Subdir Function Define Test 1" "(${SUBDIR_DEFINED})")
+ endif()
+endfunction()
+
+# Reset test variables.
+set(SUBDIR_UNDEFINED 1)
+set(SUBDIR_DEFINED)
+
+# Run test function.
+ADD_SUBDIR2(SubDirScope)
+
+# The parent scope sets in the subdir should not be visible here.
+if(DEFINED SUBDIR_UNDEFINED)
+ PASS("Subdir Function Undefine Test 2" "(${SUBDIR_UNDEFINED})")
+else()
+ FAILED("Subdir Function Undefine Test 2" "(${SUBDIR_UNDEFINED})")
+endif()
+if(DEFINED SUBDIR_DEFINED)
+ FAILED("Subdir Function Define Test 2" "(${SUBDIR_DEFINED})")
+else()
+ PASS("Subdir Function Define Test 2" "(${SUBDIR_DEFINED})")
+endif()
+
+add_executable(FunctionTest functionTest.c)
+
+# Use the PROJECT_LABEL property: in IDEs, the project label should appear
+# in the UI rather than the target name. If this were a good test of the
+# property rather than just a smoke test, it would verify that the label
+# actually appears in the UI of the IDE... Or at least that the text appears
+# somewhere in the generated project files.
+set_property(TARGET miniFunctionTest
+ PROPERTY PROJECT_LABEL "Test de Fonctionnement")
diff --git a/Tests/FunctionTest/SubDirScope/CMakeLists.txt b/Tests/FunctionTest/SubDirScope/CMakeLists.txt
new file mode 100644
index 0000000..c1a3cfb
--- /dev/null
+++ b/Tests/FunctionTest/SubDirScope/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(SUBDIR_DEFINED 1 PARENT_SCOPE)
+set(SUBDIR_UNDEFINED PARENT_SCOPE)
+
+# The above sets should not affect the current scope.
+if(DEFINED SUBDIR_UNDEFINED)
+ PASS("SubdirScope Undefine Test" "(${SUBDIR_UNDEFINED})")
+else()
+ FAILED("SubdirScope Undefine Test" "(${SUBDIR_UNDEFINED})")
+endif()
+if(DEFINED SUBDIR_DEFINED)
+ FAILED("SubdirScope Define Test" "(${SUBDIR_DEFINED})")
+else()
+ PASS("SubdirScope Define Test" "(${SUBDIR_DEFINED})")
+endif()
diff --git a/Tests/FunctionTest/Util.cmake b/Tests/FunctionTest/Util.cmake
new file mode 100644
index 0000000..846abd7
--- /dev/null
+++ b/Tests/FunctionTest/Util.cmake
@@ -0,0 +1,3 @@
+function(tester)
+ set (tester_res "${CMAKE_CURRENT_LIST_FILE}" PARENT_SCOPE)
+endfunction()
diff --git a/Tests/FunctionTest/functionTest.c b/Tests/FunctionTest/functionTest.c
new file mode 100644
index 0000000..e0ced6a
--- /dev/null
+++ b/Tests/FunctionTest/functionTest.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char* argv[])
+{
+ printf("Running command: %s with %d arguments\n", argv[0], argc);
+ return 0;
+}
diff --git a/Tests/Fuzzing/README.rst b/Tests/Fuzzing/README.rst
new file mode 100644
index 0000000..a869f9c
--- /dev/null
+++ b/Tests/Fuzzing/README.rst
@@ -0,0 +1,8 @@
+The fuzzers in this directory are run continuously through OSS-fuzz.
+All fuzzers are implemented by way of the `libFuzzer engine`_.
+
+The link to the OSS-fuzz integration can be found here: (pending)
+All email addresses in the `project.yaml` file on OSS-fuzz will have access
+to detailed bug reports and will be notified via email if/when bugs are found.
+
+.. _`libFuzzer Engine`: https://llvm.org/docs/LibFuzzer.html
diff --git a/Tests/Fuzzing/xml_parser_fuzzer.cc b/Tests/Fuzzing/xml_parser_fuzzer.cc
new file mode 100644
index 0000000..1faa918
--- /dev/null
+++ b/Tests/Fuzzing/xml_parser_fuzzer.cc
@@ -0,0 +1,27 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cmXMLParser.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+ char test_file[] = "libfuzzer.xml";
+
+ FILE* fp = fopen(test_file, "wb");
+ if (!fp)
+ return 0;
+ fwrite(data, size, 1, fp);
+ fclose(fp);
+
+ cmXMLParser parser;
+ if (!parser.ParseFile(test_file)) {
+ return 1;
+ }
+
+ remove(test_file);
+ return 0;
+}
diff --git a/Tests/GeneratorExpression/CMP0044/CMakeLists.txt b/Tests/GeneratorExpression/CMP0044/CMakeLists.txt
new file mode 100644
index 0000000..309a8cc
--- /dev/null
+++ b/Tests/GeneratorExpression/CMP0044/CMakeLists.txt
@@ -0,0 +1,19 @@
+
+string(TOLOWER ${CMAKE_C_COMPILER_ID} lc_test)
+if (lc_test STREQUAL CMAKE_C_COMPILER_ID)
+ string(TOUPPER ${CMAKE_C_COMPILER_ID} lc_test)
+ if (lc_test STREQUAL CMAKE_C_COMPILER_ID)
+ message(SEND_ERROR "Try harder.")
+ endif()
+endif()
+
+if (CMP0044_TYPE)
+ cmake_policy(SET CMP0044 ${CMP0044_TYPE})
+endif()
+
+add_library(cmp0044-check-${CMP0044_TYPE} cmp0044-check.cpp)
+target_compile_definitions(cmp0044-check-${CMP0044_TYPE}
+ PRIVATE
+ Result=$<C_COMPILER_ID:${lc_test}>
+ Type_Is_${CMP0044_TYPE}
+)
diff --git a/Tests/GeneratorExpression/CMP0044/cmp0044-check.cpp b/Tests/GeneratorExpression/CMP0044/cmp0044-check.cpp
new file mode 100644
index 0000000..2812b0d
--- /dev/null
+++ b/Tests/GeneratorExpression/CMP0044/cmp0044-check.cpp
@@ -0,0 +1,26 @@
+
+#ifdef Type_Is_
+# if !Result
+# error Result should be 1 in WARN mode
+# endif
+#endif
+
+#ifdef Type_Is_NEW
+# if Result
+# error Result should be 0 in NEW mode
+# endif
+#endif
+
+#ifdef Type_Is_OLD
+# if !Result
+# error Result should be 1 in OLD mode
+# endif
+#endif
+
+#if !defined(Type_Is_) && !defined(Type_Is_OLD) && !defined(Type_Is_NEW)
+# error No expected definition present
+#endif
+
+void foo(void)
+{
+}
diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt
new file mode 100644
index 0000000..ebbe288
--- /dev/null
+++ b/Tests/GeneratorExpression/CMakeLists.txt
@@ -0,0 +1,441 @@
+cmake_minimum_required (VERSION 2.8.8)
+project(GeneratorExpression)
+
+include(CTest)
+
+# Real projects normally want the MSYS shell path conversion, but for this test
+# we need to verify that the command line is constructed with the proper string.
+set(msys1_prefix "")
+set(msys2_no_conv "")
+if(CMAKE_GENERATOR STREQUAL "MSYS Makefiles")
+ execute_process(COMMAND "uname" OUTPUT_VARIABLE uname)
+ if("${uname}" MATCHES "^MINGW32")
+ # MinGW.org MSYS 1.0 does not support generic path conversion suppression
+ set(msys1_prefix MSYS1_PREFIX)
+ else()
+ # msys2 supports generic path conversion suppression
+ set(msys2_no_conv env MSYS2_ARG_CONV_EXCL=-D)
+ endif()
+endif()
+
+# This test is split into multiple parts as needed to avoid NMake command
+# length limits.
+
+add_custom_target(check-part1 ALL
+ COMMAND ${msys2_no_conv} ${CMAKE_COMMAND}
+ -Dtest_0=$<0:nothing>
+ -Dtest_0_with_comma=$<0:-Wl,--no-undefined>
+ -Dtest_1=$<1:content>
+ -Dtest_1_with_comma=$<1:-Wl,--no-undefined>
+ -Dconfig=$<CONFIGURATION>
+ -Dshort_config=$<CONFIG>
+ -Dtest_and_0=$<AND:0>
+ -Dtest_and_0_0=$<AND:0,0>
+ -Dtest_and_0_1=$<AND:0,1>
+ -Dtest_and_1=$<AND:1>
+ -Dtest_and_1_0=$<AND:1,0>
+ -Dtest_and_1_1=$<AND:1,1>
+ # Ordinarily, the 'invalidcontent' would cause an error, but
+ # the '0' makes the AND abort early.
+ -Dtest_and_0_invalidcontent=$<AND:0,invalidcontent>
+ -Dtest_config_0=$<CONFIG:$<CONFIGURATION>x>
+ -Dtest_config_1=$<CONFIG:$<CONFIGURATION>>
+ -Dtest_config_debug=$<CONFIG:Debug,DEBUG,DeBuG>
+ -Dtest_config_release=$<CONFIG:Release>$<CONFIG:RELEASE,ReLeAsE>
+ -Dtest_config_relwithdebinfo=$<CONFIG:RelWithDebInfo,RELWITHDEBINFO>$<CONFIG:relwithdebinfo>
+ -Dtest_config_minsizerel=$<CONFIG:MinSizeRel>$<CONFIG:MINSIZEREL>$<CONFIG:minsizerel>
+ -Dtest_not_0=$<NOT:0>
+ -Dtest_not_1=$<NOT:1>
+ -Dtest_or_0=$<OR:0>
+ -Dtest_or_0_0=$<OR:0,0>
+ -Dtest_or_0_1=$<OR:0,1>
+ -Dtest_or_1=$<OR:1>
+ -Dtest_or_1_0=$<OR:1,0>
+ -Dtest_or_1_1=$<OR:1,1>
+ -Dtest_or_1_invalidcontent=$<OR:1,invalidcontent>
+ -Dtest_bool_notfound=$<BOOL:NOTFOUND>
+ -Dtest_bool_foo_notfound=$<BOOL:Foo-NOTFOUND>
+ -Dtest_bool_true=$<BOOL:True>
+ -Dtest_bool_false=$<BOOL:False>
+ -Dtest_bool_on=$<BOOL:On>
+ -Dtest_bool_off=$<BOOL:Off>
+ -Dtest_bool_no=$<BOOL:No>
+ -Dtest_bool_n=$<BOOL:N>
+ -Dtest_bool_empty=$<BOOL:>
+ -Dtest_strequal_yes_yes=$<STREQUAL:Yes,Yes>
+ -Dtest_strequal_yes_yes_cs=$<STREQUAL:Yes,yes>
+ -Dtest_strequal_yes_no=$<STREQUAL:Yes,No>
+ -Dtest_strequal_no_yes=$<STREQUAL:No,Yes>
+ -Dtest_strequal_angle_r=$<STREQUAL:$<ANGLE-R>,$<ANGLE-R>>
+ -Dtest_strequal_comma=$<STREQUAL:$<COMMA>,$<COMMA>>
+ -Dtest_strequal_semicolon=$<STREQUAL:$<SEMICOLON>,$<SEMICOLON>>
+ -Dtest_strequal_angle_r_comma=$<STREQUAL:$<ANGLE-R>,$<COMMA>>
+ -Dtest_strequal_both_empty=$<STREQUAL:,>
+ -Dtest_strequal_one_empty=$<STREQUAL:something,>
+ -Dtest_inlist_true=$<IN_LIST:a,a$<SEMICOLON>b>
+ -Dtest_inlist_false=$<IN_LIST:c,a$<SEMICOLON>b>
+ -Dtest_inlist_empty_1=$<IN_LIST:a,>
+ -Dtest_inlist_empty_2=$<IN_LIST:,a>
+ -Dtest_inlist_empty_3=$<IN_LIST:,>
+ -Dtest_angle_r=$<ANGLE-R>
+ -Dtest_comma=$<COMMA>
+ -Dtest_semicolon=$<SEMICOLON>
+ -Dtest_colons_1=$<1::>
+ -Dtest_colons_2=$<1:::>
+ -Dtest_colons_3=$<1:Qt5::Core>
+ -Dtest_colons_4=$<1:C:\\CMake>
+ -Dtest_colons_5=$<1:C:/CMake>
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/check-part1.cmake
+ COMMAND ${CMAKE_COMMAND} -E echo "check done (part 1 of 5)"
+ VERBATIM
+ )
+
+add_library(empty1 empty.cpp)
+target_include_directories(empty1 PUBLIC /empty1/public)
+target_include_directories(empty1 PRIVATE /empty1/private)
+
+add_library(empty2 empty.cpp)
+target_include_directories(empty2 PUBLIC /empty2/public)
+
+add_library(empty3 empty.cpp)
+target_include_directories(empty3 PUBLIC /empty3/public)
+target_include_directories(empty3 PRIVATE /empty3/private)
+
+add_library(empty4 empty.cpp)
+target_include_directories(empty4 PUBLIC /empty4/public)
+
+target_link_libraries(empty1 LINK_PUBLIC empty2)
+target_link_libraries(empty2 LINK_PUBLIC empty3 empty4)
+target_link_libraries(empty3 LINK_PUBLIC empty2 empty4)
+
+add_library(empty5 empty.cpp)
+target_include_directories(empty5 PRIVATE /empty5/private1 /empty5/private2)
+
+add_custom_target(check-part2 ALL
+ COMMAND ${msys2_no_conv} ${CMAKE_COMMAND}
+ -Dtest_incomplete_1=$<
+ -Dtest_incomplete_2=$<something
+ -Dtest_incomplete_3=$<something:
+ -Dtest_incomplete_4=$<something:,
+ -Dtest_incomplete_5=$something:,>
+ -Dtest_incomplete_6=<something:,>
+ -Dtest_incomplete_7=$<something::
+ -Dtest_incomplete_8=$<something:,
+ -Dtest_incomplete_9=$<something:,,
+ -Dtest_incomplete_10=$<something:,:
+ -Dtest_incomplete_11=$<something,,
+ -Dtest_incomplete_12=$<,,
+ -Dtest_incomplete_13=$<some$<1:special>thing
+ -Dtest_incomplete_14=$<$<ANGLE-R>
+ -Dtest_incomplete_15=$<some$<thing
+ -Dtest_incomplete_16=$<BOOL:something
+ -Dtest_incomplete_17=$<1:some$thing>
+ -Dtest_incomplete_18=$<1:some,thing
+ -Dtest_incomplete_19=$<1:some,thing$<ANGLE-R>
+ -Dtest_incomplete_20=$<CONFIGURATION$<ANGLE-R>
+ -Dtest_incomplete_21=$<BOOL:something$<ANGLE-R>
+ -Dtest_build_interface=$<BUILD_INTERFACE:build>
+ -Dtest_install_interface=$<INSTALL_INTERFACE:install>
+ -Dtest_target_name_1=$<TARGET_NAME:tgt,ok>
+ -Dtest_target_name_2=$<TARGET_NAME:tgt:ok>
+ -Dtest_target_includes1=$<TARGET_PROPERTY:empty1,INTERFACE_INCLUDE_DIRECTORIES>
+ -Dtest_target_includes2=$<TARGET_PROPERTY:empty2,INTERFACE_INCLUDE_DIRECTORIES>
+ -Dtest_target_includes3=$<TARGET_PROPERTY:empty3,INTERFACE_INCLUDE_DIRECTORIES>
+ -Dtest_target_includes4=$<TARGET_PROPERTY:empty1,INCLUDE_DIRECTORIES>
+ -Dtest_target_includes5=$<TARGET_PROPERTY:empty2,INCLUDE_DIRECTORIES>
+ -Dtest_target_includes6=$<TARGET_PROPERTY:empty3,INCLUDE_DIRECTORIES>
+ -Dtest_target_includes7=$<TARGET_PROPERTY:empty1,INTERFACE_INCLUDE_DIRECTORIES>
+ -Dtest_target_includes8=$<TARGET_PROPERTY:empty5,INCLUDE_DIRECTORIES>
+ -Dtest_arbitrary_content_comma_1=$<1:a,>
+ -Dtest_arbitrary_content_comma_2=$<1:,a>
+ -Dtest_arbitrary_content_comma_3=$<1:a,,>
+ -Dtest_arbitrary_content_comma_4=$<1:,>
+ -Dtest_arbitrary_content_comma_5=$<1:,,>
+ -Dtest_arbitrary_content_comma_6=$<1:,,,>
+ -Dtest_arbitrary_content_comma_7=$<1:,,a>
+ -Dtest_arbitrary_content_comma_8=$<1:a,,b>
+ -Dtest_arbitrary_content_comma_9=$<1:a,,b,,>
+ -Dtest_arbitrary_content_comma_10=$<1:,,a,,b,,>
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/check-part2.cmake
+ COMMAND ${CMAKE_COMMAND} -E echo "check done (part 2 of 5)"
+ VERBATIM
+)
+
+add_library(imported1 SHARED IMPORTED)
+set_property(TARGET imported1 PROPERTY IMPORTED_LOCATION_RELEASE release_loc)
+set_property(TARGET imported1 PROPERTY IMPORTED_LOCATION_DEBUG debug_loc)
+set_property(TARGET imported1 PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG)
+set_property(TARGET imported1 PROPERTY INTERFACE_INCLUDE_DIRECTORIES "/imported1/include/with space")
+
+add_library(imported2 SHARED IMPORTED)
+set_property(TARGET imported2 PROPERTY IMPORTED_LOCATION_RELEASE release_loc)
+set_property(TARGET imported2 PROPERTY IMPORTED_LOCATION_DEBUG debug_loc)
+set_property(TARGET imported2 PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG)
+set_property(TARGET imported2 PROPERTY INTERFACE_INCLUDE_DIRECTORIES "/imported2/include/with space")
+
+add_library(imported3 SHARED IMPORTED)
+set_property(TARGET imported3 PROPERTY IMPORTED_LOCATION_RELEASE release_loc)
+set_property(TARGET imported3 PROPERTY IMPORTED_LOCATION_DEBUG debug_loc)
+# Both Debug and Release should not be true when this is evaluated.
+set_property(TARGET imported3 APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES $<$<CONFIG:DEBUG>:$<TARGET_PROPERTY:imported1,INTERFACE_INCLUDE_DIRECTORIES>>)
+set_property(TARGET imported3 APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES $<$<CONFIG:RELEASE,RELWITHDEBINFO>:$<TARGET_PROPERTY:imported2,INTERFACE_INCLUDE_DIRECTORIES>>)
+set_property(TARGET imported3 APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES $<$<CONFIG:MINSIZEREL>:$<TARGET_PROPERTY:imported2,INTERFACE_INCLUDE_DIRECTORIES>>)
+
+add_library(imported4 SHARED IMPORTED)
+set_property(TARGET imported4 APPEND PROPERTY
+ INCLUDE_DIRECTORIES $<TARGET_PROPERTY:imported3,INTERFACE_INCLUDE_DIRECTORIES>)
+
+add_executable(someexe $<1:empty.cpp> $<0:does_not_exist>)
+add_executable(Alias::SomeExe ALIAS someexe)
+
+add_library(Alias::SomeLib ALIAS empty1)
+
+add_library(importedFallback STATIC IMPORTED)
+set_property(TARGET importedFallback PROPERTY IMPORTED_LOCATION_DEBUG debug_loc)
+set_property(TARGET importedFallback PROPERTY IMPORTED_LOCATION_RELEASE release_loc)
+set_property(TARGET importedFallback PROPERTY IMPORTED_LOCATION fallback_loc)
+set_property(TARGET importedFallback PROPERTY MAP_IMPORTED_CONFIG_DEBUG "" DEBUG)
+set_property(TARGET importedFallback PROPERTY MAP_IMPORTED_CONFIG_RELEASE "")
+
+add_custom_target(check-part3 ALL
+ COMMAND ${msys2_no_conv} ${CMAKE_COMMAND}
+ -Dtest_version_greater_1=$<VERSION_GREATER:1.0,1.1.1>
+ -Dtest_version_greater_2=$<VERSION_GREATER:1.1.1,1.0>
+ -Dtest_version_less_1=$<VERSION_LESS:1.1.1,1.0>
+ -Dtest_version_less_2=$<VERSION_LESS:1.0,1.1.1>
+ -Dtest_version_equal_1=$<VERSION_EQUAL:1.0.1,1.1>
+ -Dtest_version_equal_2=$<VERSION_EQUAL:1.1,1.1>
+ -Dconfig=$<CONFIGURATION>
+ -Dtest_imported_includes=$<TARGET_PROPERTY:imported4,INCLUDE_DIRECTORIES>
+ -Dtest_imported_fallback=$<STREQUAL:$<TARGET_FILE_NAME:importedFallback>,fallback_loc>
+ -Dtest_alias_file_exe=$<STREQUAL:$<TARGET_FILE:Alias::SomeExe>,$<TARGET_FILE:someexe>>
+ -Dtest_alias_file_lib=$<STREQUAL:$<TARGET_FILE:Alias::SomeLib>,$<TARGET_FILE:empty1>>
+ -Dtest_alias_target_name=$<STREQUAL:$<TARGET_PROPERTY:Alias::SomeLib,NAME>,$<TARGET_PROPERTY:empty1,NAME>>
+ -Dtest_early_termination_1=$<$<1:>:
+ -Dtest_early_termination_2=$<$<1:>:,
+ -Dsystem_name=${CMAKE_HOST_SYSTEM_NAME}
+ -Dtest_platform_id=$<PLATFORM_ID>
+ -Dtest_platform_id_supported=$<PLATFORM_ID:Linux,Windows,Darwin>
+ -Dtest_platform_id_Linux=$<PLATFORM_ID:Linux>
+ -Dtest_platform_id_Windows=$<PLATFORM_ID:Windows>
+ -Dtest_platform_id_Darwin=$<PLATFORM_ID:Darwin>
+ -Dlower_case=$<LOWER_CASE:Mi,XeD>
+ -Dupper_case=$<UPPER_CASE:MiX,eD>
+ -Dmake_c_identifier=$<MAKE_C_IDENTIFIER:4f,oo:+bar-$>
+ -Dequal1=$<EQUAL:1,2>
+ -Dequal2=$<EQUAL:1,1>
+ -Dequal3=$<EQUAL:0x1,1>
+ -Dequal4=$<EQUAL:0X1,2>
+ -Dequal5=$<EQUAL:0xA,0xa>
+ -Dequal6=$<EQUAL:0xA,10>
+ -Dequal7=$<EQUAL:0xA,012>
+ -Dequal8=$<EQUAL:10,012>
+ -Dequal9=$<EQUAL:10,010>
+ -Dequal10=$<EQUAL:10,0b1010>
+ -Dequal11=$<EQUAL:-10,-0xa>
+ -Dequal12=$<EQUAL:10,+0xa>
+ -Dequal13=$<EQUAL:+10,+0Xa>
+ -Dequal14=$<EQUAL:+10,0xa>
+ -Dequal15=$<EQUAL:-10,-0Xa>
+ -Dequal16=$<EQUAL:-10,-0b1010>
+ -Dequal17=$<EQUAL:-10,+0b1010>
+ -Dequal18=$<EQUAL:10,+0B1010>
+ -Dequal19=$<EQUAL:10,-0B1010>
+ -Dequal20=$<EQUAL:10,0B1010>
+ -Dequal21=$<EQUAL:10,+012>
+ -Dequal22=$<EQUAL:10,-012>
+ -Dequal23=$<EQUAL:-10,-012>
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/check-part3.cmake
+ COMMAND ${CMAKE_COMMAND} -E echo "check done (part 3 of 5)"
+ VERBATIM
+ )
+
+if(WIN32)
+ set(test_shell_path c:/shell/path)
+ set(test_shell_path2 c:/shell/path d:/another/path)
+else()
+ set(test_shell_path /shell/path)
+ set(test_shell_path2 /shell/path /another/path)
+endif()
+
+add_custom_target(check-part4 ALL
+ COMMAND ${msys2_no_conv} ${CMAKE_COMMAND}
+ # Prefix path to bypass its further conversion when being processed by
+ # CMake as command-line argument
+ -Dmsys1_prefix=${msys1_prefix}
+ -Dtest_shell_path=${msys1_prefix}$<SHELL_PATH:${test_shell_path}>
+ "-Dtest_shell_path2=$<SHELL_PATH:${test_shell_path2}>"
+ -Dif_1=$<IF:1,a,b>
+ -Dif_2=$<IF:0,a,b>
+ -Dif_3=$<IF:$<EQUAL:10,30>,a,b>
+ -Dif_4=$<IF:$<EQUAL:30,30>,a,b>
+ -DWIN32=${WIN32}
+ -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/check-part4.cmake
+ COMMAND ${CMAKE_COMMAND} -E echo "check done (part 4 of 5)"
+ VERBATIM
+ )
+
+add_custom_target(check-part5 ALL
+ COMMAND ${CMAKE_COMMAND} -E echo "check done (part 5 of 5)"
+ DEPENDS check-part5.stamp
+ VERBATIM
+ )
+
+add_custom_command(
+ OUTPUT check-part5.stamp
+ DEPENDS $<FILTER:file.foo.bar,EXCLUDE,\\.foo\\.bar$>
+ COMMAND ${CMAKE_COMMAND} -E sleep 0
+ VERBATIM
+ )
+set_property(SOURCE check-part5.stamp PROPERTY SYMBOLIC 1)
+
+add_custom_command(
+ OUTPUT file.foo.bar
+ COMMAND ${CMAKE_COMMAND} -P check-part5.cmake
+ VERBATIM
+ )
+
+#-----------------------------------------------------------------------------
+# Cover source file properties with generator expressions.
+## generate various source files
+foreach (item IN ITEMS flags flags_COMPILE_LANGUAGE
+ options options_COMPILE_LANGUAGE
+ defs defs_COMPILE_LANGUAGE)
+ set(TARGET_NAME srcgenex_${item})
+ configure_file(srcgenex.c.in ${TARGET_NAME}.c @ONLY)
+endforeach()
+add_executable(srcgenex_flags "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_flags.c")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_flags.c"
+ PROPERTY COMPILE_FLAGS "-DNAME=$<TARGET_PROPERTY:NAME>")
+add_executable(srcgenex_flags_COMPILE_LANGUAGE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_flags_COMPILE_LANGUAGE.c")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_flags_COMPILE_LANGUAGE.c"
+ PROPERTY COMPILE_FLAGS "$<$<COMPILE_LANGUAGE:C>:-DNAME=$<TARGET_PROPERTY:NAME>>")
+
+add_executable(srcgenex_options "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_options.c")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_options.c"
+ PROPERTY COMPILE_OPTIONS -DUNUSED -DNAME=$<TARGET_PROPERTY:NAME>)
+add_executable(srcgenex_options_COMPILE_LANGUAGE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_options_COMPILE_LANGUAGE.c")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_options_COMPILE_LANGUAGE.c"
+ PROPERTY COMPILE_OPTIONS $<$<COMPILE_LANGUAGE:C>:-DNAME=$<TARGET_PROPERTY:NAME>>)
+
+add_executable(srcgenex_defs "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_defs.c")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_defs.c"
+ PROPERTY COMPILE_DEFINITIONS UNUSED NAME=$<TARGET_PROPERTY:NAME>)
+add_executable(srcgenex_defs_COMPILE_LANGUAGE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_defs_COMPILE_LANGUAGE.c")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_defs_COMPILE_LANGUAGE.c"
+ PROPERTY COMPILE_DEFINITIONS $<$<COMPILE_LANGUAGE:C>:NAME=$<TARGET_PROPERTY:NAME>>)
+
+foreach (item IN ITEMS basic COMPILE_LANGUAGE)
+ set(TARGET_NAME srcgenex_includes_${item})
+ configure_file(srcgenex_includes.h.in "sf_includes_${item}/${TARGET_NAME}.h" @ONLY)
+ configure_file(srcgenex_includes.c.in ${TARGET_NAME}.c @ONLY)
+endforeach()
+add_executable(srcgenex_includes_basic "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_includes_basic.c")
+# first include directory is useless but ensure list aspect is tested
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_includes_basic.c"
+ PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/sf_includes_basic")
+if (CMAKE_GENERATOR MATCHES "Makefiles|Ninja|Watcom WMake")
+ add_executable(srcgenex_includes_COMPILE_LANGUAGE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_includes_COMPILE_LANGUAGE.c")
+ # first include directory is useless but ensure list aspect is tested
+ set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_includes_COMPILE_LANGUAGE.c"
+ PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}" $<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_BINARY_DIR}/sf_includes_COMPILE_LANGUAGE>)
+endif()
+
+#-----------------------------------------------------------------------------
+# Cover test properties with generator expressions.
+add_executable(echo echo.c)
+add_executable(pwd pwd.c)
+
+add_test(NAME echo-configuration COMMAND echo $<CONFIGURATION>)
+set_property(TEST echo-configuration PROPERTY
+ PASS_REGULAR_EXPRESSION "^$<CONFIGURATION>\n$")
+
+add_test(NAME echo-target-file COMMAND echo $<TARGET_FILE:echo>)
+set_property(TEST echo-target-file PROPERTY
+ PASS_REGULAR_EXPRESSION "/echo${CMAKE_EXECUTABLE_SUFFIX}\n$")
+set_property(TEST echo-target-file PROPERTY
+ REQUIRED_FILES "$<TARGET_FILE:echo>")
+
+add_test(NAME working-dir-arg
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/WorkingDirectory/$<CONFIGURATION>"
+ COMMAND pwd)
+set_property(TEST working-dir-arg PROPERTY
+ PASS_REGULAR_EXPRESSION "WorkingDirectory/$<CONFIGURATION>\n$")
+foreach(c ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE})
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/WorkingDirectory/${c}")
+endforeach()
+
+add_test(echo-old-style echo "\$<CONFIGURATION>")
+set_property(TEST echo-old-style PROPERTY
+ PASS_REGULAR_EXPRESSION "^\\$<CONFIGURATION>\n$")
+
+add_subdirectory(CMP0044 ${CMAKE_BINARY_DIR}/CMP0044-WARN)
+set(CMP0044_TYPE NEW)
+add_subdirectory(CMP0044 ${CMAKE_BINARY_DIR}/CMP0044-NEW)
+set(CMP0044_TYPE OLD)
+add_subdirectory(CMP0044 ${CMAKE_BINARY_DIR}/CMP0044-OLD)
+
+if(NOT CMAKE_GENERATOR STREQUAL Xcode OR NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;$]")
+ add_library(objlib OBJECT objlib1.c objlib2.c)
+ file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/objlib_files_$<CONFIGURATION>"
+ CONTENT "$<JOIN:$<TARGET_OBJECTS:objlib>,\n>\n"
+ )
+
+ add_custom_target(check_object_files ALL
+ COMMAND ${CMAKE_COMMAND}
+ "-DOBJLIB_LISTFILE=${CMAKE_CURRENT_BINARY_DIR}/objlib_files_$<CONFIGURATION>"
+ -DEXPECTED_NUM_OBJECTFILES=2
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake"
+ DEPENDS objlib
+ )
+
+
+ add_library(sharedlib SHARED objlib1.c objlib2.c)
+ file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/sharedlib_files_$<CONFIGURATION>"
+ CONTENT "$<JOIN:$<TARGET_OBJECTS:sharedlib>,\n>\n"
+ )
+
+ add_custom_target(check_sharedlib_objs ALL
+ COMMAND ${CMAKE_COMMAND}
+ "-DOBJLIB_LISTFILE=${CMAKE_CURRENT_BINARY_DIR}/sharedlib_files_$<CONFIGURATION>"
+ -DEXPECTED_NUM_OBJECTFILES=2
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake"
+ DEPENDS sharedlib
+ )
+
+
+ add_library(staticlib STATIC objlib1.c objlib2.c)
+ file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/staticlib_files_$<CONFIGURATION>"
+ CONTENT "$<JOIN:$<TARGET_OBJECTS:staticlib>,\n>\n"
+ )
+
+ add_custom_target(check_staticlib_objs ALL
+ COMMAND ${CMAKE_COMMAND}
+ "-DOBJLIB_LISTFILE=${CMAKE_CURRENT_BINARY_DIR}/staticlib_files_$<CONFIGURATION>"
+ -DEXPECTED_NUM_OBJECTFILES=2
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake"
+ DEPENDS staticlib
+ )
+
+
+ add_executable(execobjs objlib1.c objlib2.c echo.c)
+ file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/execobjs_files_$<CONFIGURATION>"
+ CONTENT "$<JOIN:$<TARGET_OBJECTS:execobjs>,\n>\n"
+ )
+
+ add_custom_target(check_exec_objs ALL
+ COMMAND ${CMAKE_COMMAND}
+ "-DOBJLIB_LISTFILE=${CMAKE_CURRENT_BINARY_DIR}/execobjs_files_$<CONFIGURATION>"
+ -DEXPECTED_NUM_OBJECTFILES=3
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake"
+ DEPENDS execobjs
+ )
+endif()
diff --git a/Tests/GeneratorExpression/check-common.cmake b/Tests/GeneratorExpression/check-common.cmake
new file mode 100644
index 0000000..faf5d4f
--- /dev/null
+++ b/Tests/GeneratorExpression/check-common.cmake
@@ -0,0 +1,5 @@
+function(check var val)
+ if(NOT "${${var}}" STREQUAL "${val}")
+ message(SEND_ERROR "${var} is \"${${var}}\", not \"${val}\"")
+ endif()
+endfunction()
diff --git a/Tests/GeneratorExpression/check-part1.cmake b/Tests/GeneratorExpression/check-part1.cmake
new file mode 100644
index 0000000..41bcd6d
--- /dev/null
+++ b/Tests/GeneratorExpression/check-part1.cmake
@@ -0,0 +1,64 @@
+
+include(${CMAKE_CURRENT_LIST_DIR}/check-common.cmake)
+
+message(STATUS "config=[${config}]")
+check(config "${short_config}")
+check(test_0 "")
+check(test_0_with_comma "")
+check(test_1 "content")
+check(test_1_with_comma "-Wl,--no-undefined")
+check(test_and_0 "0")
+check(test_and_0_0 "0")
+check(test_and_0_1 "0")
+check(test_and_1 "1")
+check(test_and_1_0 "0")
+check(test_and_1_1 "1")
+check(test_and_0_invalidcontent "0")
+check(test_config_0 "0")
+check(test_config_1 "1")
+foreach(c debug release relwithdebinfo minsizerel)
+ if(NOT "${test_config_${c}}" MATCHES "^(0+|1+)$")
+ message(SEND_ERROR "test_config_${c} is \"${test_config_${c}}\", not all 0 or all 1")
+ endif()
+endforeach()
+check(test_not_0 "1")
+check(test_not_1 "0")
+check(test_or_0 "0")
+check(test_or_0_0 "0")
+check(test_or_0_1 "1")
+check(test_or_1 "1")
+check(test_or_1_0 "1")
+check(test_or_1_1 "1")
+check(test_or_1_invalidcontent "1")
+check(test_bool_notfound "0")
+check(test_bool_foo_notfound "0")
+check(test_bool_true "1")
+check(test_bool_false "0")
+check(test_bool_on "1")
+check(test_bool_off "0")
+check(test_bool_no "0")
+check(test_bool_n "0")
+check(test_bool_empty "0")
+check(test_strequal_yes_yes "1")
+check(test_strequal_yes_yes_cs "0")
+check(test_strequal_yes_no "0")
+check(test_strequal_no_yes "0")
+check(test_strequal_angle_r "1")
+check(test_strequal_comma "1")
+check(test_strequal_semicolon "1")
+check(test_strequal_angle_r_comma "0")
+check(test_strequal_both_empty "1")
+check(test_strequal_one_empty "0")
+check(test_inlist_true "1")
+check(test_inlist_false "0")
+check(test_inlist_empty_1 "0")
+check(test_inlist_empty_2 "0")
+check(test_inlist_empty_3 "0")
+check(test_angle_r ">")
+check(test_comma ",")
+check(test_semicolon ";")
+check(test_colons_1 ":")
+check(test_colons_2 "::")
+check(test_colons_3 "Qt5::Core")
+check(test_colons_4 [[C:\CMake]])
+check(test_colons_5 "C:/CMake")
diff --git a/Tests/GeneratorExpression/check-part2.cmake b/Tests/GeneratorExpression/check-part2.cmake
new file mode 100644
index 0000000..a1db5f6
--- /dev/null
+++ b/Tests/GeneratorExpression/check-part2.cmake
@@ -0,0 +1,46 @@
+
+include(${CMAKE_CURRENT_LIST_DIR}/check-common.cmake)
+
+check(test_incomplete_1 "$<")
+check(test_incomplete_2 "$<something")
+check(test_incomplete_3 "$<something:")
+check(test_incomplete_4 "$<something:,")
+check(test_incomplete_5 "$something:,>")
+check(test_incomplete_6 "<something:,>")
+check(test_incomplete_7 "$<something::")
+check(test_incomplete_8 "$<something:,")
+check(test_incomplete_9 "$<something:,,")
+check(test_incomplete_10 "$<something:,:")
+check(test_incomplete_11 "$<something,,")
+check(test_incomplete_12 "$<,,")
+check(test_incomplete_13 "$<somespecialthing")
+check(test_incomplete_14 "$<>")
+check(test_incomplete_15 "$<some$<thing")
+check(test_incomplete_16 "$<BOOL:something")
+check(test_incomplete_17 "some$thing")
+check(test_incomplete_18 "$<1:some,thing")
+check(test_incomplete_19 "$<1:some,thing>")
+check(test_incomplete_20 "$<CONFIGURATION>")
+check(test_incomplete_21 "$<BOOL:something>")
+check(test_build_interface "build")
+check(test_install_interface "")
+check(test_target_name_1 "tgt,ok")
+check(test_target_name_2 "tgt:ok")
+check(test_target_includes1 "/empty1/public;/empty2/public;/empty3/public;/empty4/public")
+check(test_target_includes2 "/empty2/public;/empty3/public;/empty4/public")
+check(test_target_includes3 "/empty3/public;/empty2/public;/empty4/public")
+check(test_target_includes4 "/empty1/public;/empty1/private;/empty2/public;/empty3/public;/empty4/public")
+check(test_target_includes5 "/empty2/public;/empty3/public;/empty2/public;/empty4/public")
+check(test_target_includes6 "/empty3/public;/empty3/private;/empty2/public;/empty3/public;/empty4/public")
+check(test_target_includes7 "/empty1/public;/empty2/public;/empty3/public;/empty4/public")
+check(test_target_includes8 "/empty5/private1;/empty5/private2")
+check(test_arbitrary_content_comma_1 "a,")
+check(test_arbitrary_content_comma_2 ",a")
+check(test_arbitrary_content_comma_3 "a,,")
+check(test_arbitrary_content_comma_4 ",")
+check(test_arbitrary_content_comma_5 ",,")
+check(test_arbitrary_content_comma_6 ",,,")
+check(test_arbitrary_content_comma_7 ",,a")
+check(test_arbitrary_content_comma_8 "a,,b")
+check(test_arbitrary_content_comma_9 "a,,b,,")
+check(test_arbitrary_content_comma_10 ",,a,,b,,")
diff --git a/Tests/GeneratorExpression/check-part3.cmake b/Tests/GeneratorExpression/check-part3.cmake
new file mode 100644
index 0000000..5571c3d
--- /dev/null
+++ b/Tests/GeneratorExpression/check-part3.cmake
@@ -0,0 +1,66 @@
+
+include(${CMAKE_CURRENT_LIST_DIR}/check-common.cmake)
+
+check(test_version_greater_1 "0")
+check(test_version_greater_2 "1")
+check(test_version_less_1 "0")
+check(test_version_less_2 "1")
+check(test_version_equal_1 "0")
+check(test_version_equal_2 "1")
+
+if(config AND NOT config STREQUAL NoConfig)
+ if(NOT "${test_imported_includes}" MATCHES "^[^;]*/imported[12]/include/with space$")
+ message(SEND_ERROR "test_imported_includes is not correct: ${test_imported_includes}")
+ endif()
+else()
+ if(NOT "${test_imported_includes}" MATCHES "^$")
+ message(SEND_ERROR "test_imported_includes is not an empty list: ${test_imported_includes}")
+ endif()
+endif()
+
+check(test_imported_fallback "1")
+
+check(test_alias_file_exe "1")
+check(test_alias_file_lib "1")
+check(test_alias_target_name "1")
+check(test_early_termination_1 "$<:")
+check(test_early_termination_2 "$<:,")
+check(test_platform_id "${system_name}")
+foreach(system Linux Windows Darwin)
+ if(system_name STREQUAL system)
+ check(test_platform_id_supported 1)
+ check(test_platform_id_${system} 1)
+ set(platform_supported 1)
+ else()
+ check(test_platform_id_${system} 0)
+ endif()
+endforeach()
+if(NOT platform_supported)
+ check(test_platform_id_supported 0)
+endif()
+check(lower_case "mi,xed")
+check(upper_case "MIX,ED")
+check(make_c_identifier "_4f_oo__bar__")
+check(equal1 "0")
+check(equal2 "1")
+check(equal3 "1")
+check(equal4 "0")
+check(equal5 "1")
+check(equal6 "1")
+check(equal7 "1")
+check(equal8 "1")
+check(equal9 "0")
+check(equal10 "1")
+check(equal11 "1")
+check(equal12 "1")
+check(equal13 "1")
+check(equal14 "1")
+check(equal15 "1")
+check(equal16 "1")
+check(equal17 "0")
+check(equal18 "1")
+check(equal19 "0")
+check(equal20 "1")
+check(equal21 "1")
+check(equal22 "0")
+check(equal23 "1")
diff --git a/Tests/GeneratorExpression/check-part4.cmake b/Tests/GeneratorExpression/check-part4.cmake
new file mode 100644
index 0000000..a7e0944
--- /dev/null
+++ b/Tests/GeneratorExpression/check-part4.cmake
@@ -0,0 +1,33 @@
+include(${CMAKE_CURRENT_LIST_DIR}/check-common.cmake)
+
+if(msys1_prefix)
+ string(REPLACE "${msys1_prefix}" "" test_shell_path ${test_shell_path})
+endif()
+
+if(WIN32)
+ if(CMAKE_GENERATOR STREQUAL "MSYS Makefiles")
+ check(test_shell_path [[/c/shell/path]])
+ elseif(CMAKE_GENERATOR STREQUAL "Unix Makefiles")
+ check(test_shell_path [[c:/shell/path]])
+ else()
+ check(test_shell_path [[c:\shell\path]])
+ endif()
+else()
+ check(test_shell_path [[/shell/path]])
+endif()
+if(WIN32)
+ if(CMAKE_GENERATOR STREQUAL "MSYS Makefiles" AND NOT msys1_prefix)
+ check(test_shell_path2 [[/c/shell/path:/d/another/path]])
+ elseif(CMAKE_GENERATOR STREQUAL "Unix Makefiles")
+ check(test_shell_path2 [[c:/shell/path;d:/another/path]])
+ else()
+ check(test_shell_path2 [[c:\shell\path;d:\another\path]])
+ endif()
+else()
+ check(test_shell_path2 [[/shell/path:/another/path]])
+endif()
+
+check(if_1 "a")
+check(if_2 "b")
+check(if_3 "b")
+check(if_4 "a")
diff --git a/Tests/GeneratorExpression/check-part5.cmake b/Tests/GeneratorExpression/check-part5.cmake
new file mode 100644
index 0000000..77d1387
--- /dev/null
+++ b/Tests/GeneratorExpression/check-part5.cmake
@@ -0,0 +1 @@
+message(SEND_ERROR "$<FILTER:file.foo.bar,EXCLUDE,\\.foo\\.bar$> genex in DEPENDS argument of 'add_custom_command()' is not empty")
diff --git a/Tests/GeneratorExpression/check_object_files.cmake b/Tests/GeneratorExpression/check_object_files.cmake
new file mode 100644
index 0000000..cfccd29
--- /dev/null
+++ b/Tests/GeneratorExpression/check_object_files.cmake
@@ -0,0 +1,26 @@
+
+if (NOT EXISTS ${OBJLIB_LISTFILE})
+ message(SEND_ERROR "Object listing file \"${OBJLIB_LISTFILE}\" not found!")
+endif()
+
+file(STRINGS ${OBJLIB_LISTFILE} objlib_files ENCODING UTF-8)
+
+list(LENGTH objlib_files num_objectfiles)
+if (NOT EXPECTED_NUM_OBJECTFILES EQUAL num_objectfiles)
+ message(SEND_ERROR "Unexpected number of entries in object list file (${num_objectfiles} instead of ${EXPECTED_NUM_OBJECTFILES})")
+endif()
+
+foreach(objlib_file ${objlib_files})
+ set(file_exists False)
+ if (EXISTS ${objlib_file})
+ set(file_exists True)
+ endif()
+
+ if (NOT file_exists)
+ if(attempts)
+ list(REMOVE_DUPLICATES attempts)
+ set(tried " Tried ${attempts}")
+ endif()
+ message(SEND_ERROR "File \"${objlib_file}\" does not exist!${tried}")
+ endif()
+endforeach()
diff --git a/Tests/GeneratorExpression/echo.c b/Tests/GeneratorExpression/echo.c
new file mode 100644
index 0000000..06b0844
--- /dev/null
+++ b/Tests/GeneratorExpression/echo.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char* argv[])
+{
+ printf("%s\n", argv[1]);
+ return EXIT_SUCCESS;
+}
diff --git a/Tests/GeneratorExpression/empty.cpp b/Tests/GeneratorExpression/empty.cpp
new file mode 100644
index 0000000..7be1ca5
--- /dev/null
+++ b/Tests/GeneratorExpression/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int main()
+{
+ return 0;
+}
diff --git a/Tests/GeneratorExpression/objlib1.c b/Tests/GeneratorExpression/objlib1.c
new file mode 100644
index 0000000..98a95a4
--- /dev/null
+++ b/Tests/GeneratorExpression/objlib1.c
@@ -0,0 +1,4 @@
+
+void objlib1()
+{
+}
diff --git a/Tests/GeneratorExpression/objlib2.c b/Tests/GeneratorExpression/objlib2.c
new file mode 100644
index 0000000..b2c1050
--- /dev/null
+++ b/Tests/GeneratorExpression/objlib2.c
@@ -0,0 +1,4 @@
+
+void objlib2()
+{
+}
diff --git a/Tests/GeneratorExpression/pwd.c b/Tests/GeneratorExpression/pwd.c
new file mode 100644
index 0000000..31ebe49
--- /dev/null
+++ b/Tests/GeneratorExpression/pwd.c
@@ -0,0 +1,32 @@
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef _WIN32
+# include <direct.h>
+# define getcurdir _getcwd
+#else
+# include <unistd.h>
+# define getcurdir getcwd
+#endif
+
+int main(int argc, char* argv[])
+{
+#define BUFSZ 20000
+ char buf[BUFSZ + 1];
+#ifdef _WIN32
+ char* pos;
+#endif
+ getcurdir(buf, BUFSZ);
+#ifdef _WIN32
+ pos = buf;
+ while (*pos) {
+ if (*pos == '\\') {
+ *pos = '/';
+ }
+ ++pos;
+ }
+#endif
+ printf("%s\n", buf);
+ return EXIT_SUCCESS;
+}
diff --git a/Tests/GeneratorExpression/srcgenex.c.in b/Tests/GeneratorExpression/srcgenex.c.in
new file mode 100644
index 0000000..4a43bd1
--- /dev/null
+++ b/Tests/GeneratorExpression/srcgenex.c.in
@@ -0,0 +1,12 @@
+int @TARGET_NAME@(void)
+{
+ return 0;
+}
+
+int main(int argc, char* argv[])
+{
+#ifndef NAME
+#error NAME not defined
+#endif
+ return NAME();
+}
diff --git a/Tests/GeneratorExpression/srcgenex_includes.c.in b/Tests/GeneratorExpression/srcgenex_includes.c.in
new file mode 100644
index 0000000..b48d7df
--- /dev/null
+++ b/Tests/GeneratorExpression/srcgenex_includes.c.in
@@ -0,0 +1,12 @@
+
+#include "@TARGET_NAME@.h"
+
+int @TARGET_NAME@(void)
+{
+ return 0;
+}
+
+int main(int argc, char* argv[])
+{
+ return @TARGET_NAME@();
+}
diff --git a/Tests/GeneratorExpression/srcgenex_includes.h.in b/Tests/GeneratorExpression/srcgenex_includes.h.in
new file mode 100644
index 0000000..2259ca6
--- /dev/null
+++ b/Tests/GeneratorExpression/srcgenex_includes.h.in
@@ -0,0 +1,7 @@
+
+#if !defined @TARGET_NAME@_H
+#define @TARGET_NAME@_H
+
+int @TARGET_NAME@(void);
+
+#endif
diff --git a/Tests/GhsMulti/GhsMultiCompilerOptions/CMakeLists.txt b/Tests/GhsMulti/GhsMultiCompilerOptions/CMakeLists.txt
new file mode 100644
index 0000000..4a3f5c2
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCompilerOptions/CMakeLists.txt
@@ -0,0 +1,92 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+message("Copy project")
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt.in
+ ${CMAKE_CURRENT_BINARY_DIR}/src/CMakeLists.txt COPYONLY)
+
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test.c
+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/src
+)
+
+message("Building project")
+set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+try_compile(RESULT
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/src
+ test
+ CMAKE_FLAGS
+ -DRUN_TEST=${RUN_TEST}
+ -DCMAKE_BUILD_TYPE=${RUN_TEST_BUILD_TYPE}
+ OUTPUT_VARIABLE OUTPUT)
+
+message("Output from build:\n${OUTPUT}")
+if (RUN_TEST STREQUAL "RELEASE_FLAGS")
+ find_file (fileName test_none.gpj
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/build/test_none
+ )
+ message("Parsing project file: ${fileName}")
+ file(STRINGS ${fileName} fileText)
+ set(opt "-unexpected_release_option")
+ string(FIND "${fileText}" "${opt}" opt_found)
+ if ( NOT opt_found EQUAL -1 )
+ message(SEND_ERROR "Release option found: ${opt}")
+ endif()
+else()
+ unset(fileName CACHE)
+ find_file (fileName K1.gpj
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/build/K1
+ )
+ message("Parsing project file: ${fileName}")
+ file(STRINGS ${fileName} fileText)
+ set(opt "-required-debug-option")
+ string(FIND "${fileText}" "${opt}" opt_found)
+ if ( opt_found EQUAL -1 )
+ message(SEND_ERROR "Missing debug option: ${opt}")
+ endif()
+
+ unset(fileName CACHE)
+ find_file (fileName K2.gpj
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/build/K2
+ )
+ message("Parsing project file: ${fileName}")
+ file(STRINGS ${fileName} fileText)
+ set(opt "-required-debug-option")
+ string(FIND "${fileText}" "${opt}" opt_found)
+ if ( opt_found EQUAL -1 )
+ message(SEND_ERROR "Missing debug option: ${opt}")
+ endif()
+
+ unset(fileName CACHE)
+ find_file (fileName K3.gpj
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/build/K3
+ )
+ message("Parsing project file: ${fileName}")
+ file(STRINGS ${fileName} fileText)
+ set(opt "-required-debug-option")
+ string(FIND "${fileText}" "${opt}" opt_found)
+ if ( opt_found EQUAL -1 )
+ message(SEND_ERROR "Missing debug option: ${opt}")
+ endif()
+
+ unset(fileName CACHE)
+ find_file (fileName K4.gpj
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/build/K4
+ )
+ message("Parsing project file: ${fileName}")
+ file(STRINGS ${fileName} fileText)
+ set(opt "-required-debug-option")
+ string(FIND "${fileText}" "${opt}" opt_found)
+ if ( opt_found EQUAL -1 )
+ message(SEND_ERROR "Missing debug option: ${opt}")
+ endif()
+endif()
diff --git a/Tests/GhsMulti/GhsMultiCompilerOptions/CMakeLists.txt.in b/Tests/GhsMulti/GhsMultiCompilerOptions/CMakeLists.txt.in
new file mode 100644
index 0000000..fc24d90
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCompilerOptions/CMakeLists.txt.in
@@ -0,0 +1,32 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ add_link_options("-non_shared")
+endif()
+
+if(RUN_TEST STREQUAL "RELEASE_FLAGS")
+ #RELEASE flags used when CMAKE_BUILD_TYPE is undefined
+ string(APPEND CMAKE_C_FLAGS_RELEASE " -unexpected_release_option")
+ add_executable(test_none test.c)
+endif()
+
+if(RUN_TEST STREQUAL "KERNEL_FLAGS")
+ #DEBUG flag missing when -kernel is added as a compile option
+ string(APPEND CMAKE_C_FLAGS_DEBUG " -required-debug-option")
+
+ add_executable(K1 test.c)
+
+ add_executable(K2 test.c)
+ target_compile_options(K2 PRIVATE -kernel)
+
+ add_executable(K3 test.c)
+ target_compile_options(K3 PRIVATE -kernel=fast)
+
+ add_executable(K4 test.c)
+ target_link_options(K4 PRIVATE -kernel)
+endif()
diff --git a/Tests/GhsMulti/GhsMultiCompilerOptions/test.c b/Tests/GhsMulti/GhsMultiCompilerOptions/test.c
new file mode 100644
index 0000000..95f2e8e
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCompilerOptions/test.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return -1;
+}
diff --git a/Tests/GhsMulti/GhsMultiCopyFile/CMakeLists.txt b/Tests/GhsMulti/GhsMultiCopyFile/CMakeLists.txt
new file mode 100644
index 0000000..d6d007d
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCopyFile/CMakeLists.txt
@@ -0,0 +1,30 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+try_compile(RESULT
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_SOURCE_DIR}/test.c
+ OUTPUT_VARIABLE OUTPUT
+ COPY_FILE "${CMAKE_CURRENT_BINARY_DIR}/test_library"
+)
+
+message(STATUS "Output from build:\n${OUTPUT}")
+
+if(NOT RESULT)
+ message(SEND_ERROR "try_compile() failed")
+endif()
+
+if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/test_library")
+ if (IS_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_library")
+ message(SEND_ERROR "library is folder !")
+ else()
+ message(STATUS "library seems okay")
+ endif()
+else()
+ message(SEND_ERROR "library is not found !")
+endif()
diff --git a/Tests/GhsMulti/GhsMultiCopyFile/test.c b/Tests/GhsMulti/GhsMultiCopyFile/test.c
new file mode 100644
index 0000000..5c657b5
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCopyFile/test.c
@@ -0,0 +1,4 @@
+int lib(int x)
+{
+ return -x;
+}
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt
new file mode 100644
index 0000000..93d668b
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt
@@ -0,0 +1,110 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+# Tests assume no previous builds in the build directory
+file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/build)
+
+macro (test_output)
+ if (BUILD_OUTPUT STREQUAL EXPECTED_LINES )
+ message("Build OK")
+ else()
+ message("BUILD_OUTPUT")
+ foreach(Line IN LISTS BUILD_OUTPUT)
+ message("${Line}")
+ endforeach()
+ message("EXPECTED_LINES")
+ foreach(Line IN LISTS EXPECTED_LINES)
+ message("${Line}")
+ endforeach()
+ message(SEND_ERROR "Build KO")
+ endif()
+endmacro()
+
+message("Copy project")
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt.in
+ ${CMAKE_CURRENT_BINARY_DIR}/src/CMakeLists.txt COPYONLY)
+
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/exe1.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/lib1.c
+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/src
+)
+
+message("Building ALL target")
+try_compile(RESULT
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/src
+ test
+ CMAKE_FLAGS
+ -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
+ OUTPUT_VARIABLE BUILD_OUTPUT)
+
+message("Output from build:\n${BUILD_OUTPUT}")
+
+#filter outputs
+string(REPLACE "\r" "" BUILD_OUTPUT "${BUILD_OUTPUT}")
+string(REPLACE "\n" ";" BUILD_OUTPUT "${BUILD_OUTPUT}")
+list(FILTER BUILD_OUTPUT INCLUDE REGEX "^.*CT:")
+
+unset(EXPECTED_LINES)
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_postbuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_cmd")
+list(APPEND EXPECTED_LINES "CT: Processing target_cmd_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_cmd_postbuild")
+
+test_output()
+
+message("Building target_update_files target")
+try_compile(RESULT
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/src
+ test target_update_files
+ CMAKE_FLAGS
+ -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
+ OUTPUT_VARIABLE BUILD_OUTPUT)
+
+message("Output from build:\n${BUILD_OUTPUT}")
+
+#filter outputs
+string(REPLACE "\r" "" BUILD_OUTPUT "${BUILD_OUTPUT}")
+string(REPLACE "\n" ";" BUILD_OUTPUT "${BUILD_OUTPUT}")
+list(FILTER BUILD_OUTPUT INCLUDE REGEX "^.*CT:")
+
+unset(EXPECTED_LINES)
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_postbuild")
+list(APPEND EXPECTED_LINES "CT: generate C file another_file")
+list(APPEND EXPECTED_LINES "CT: generate text file dependsA")
+list(APPEND EXPECTED_LINES "CT: generate text file out_of_order_dep")
+list(APPEND EXPECTED_LINES "CT: generate text files A, B, and C")
+list(APPEND EXPECTED_LINES "CT: Processing target_update_files")
+
+test_output()
+
+message("Rerun target_update_files target")
+try_compile(RESULT
+ ${CMAKE_CURRENT_BINARY_DIR}/build
+ ${CMAKE_CURRENT_BINARY_DIR}/src
+ test target_update_files
+ CMAKE_FLAGS
+ -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
+ OUTPUT_VARIABLE BUILD_OUTPUT)
+
+message("Output from build:\n${BUILD_OUTPUT}")
+
+#filter outputs
+string(REPLACE "\r" "" BUILD_OUTPUT "${BUILD_OUTPUT}")
+string(REPLACE "\n" ";" BUILD_OUTPUT "${BUILD_OUTPUT}")
+list(FILTER BUILD_OUTPUT INCLUDE REGEX "^.*CT:")
+
+unset(EXPECTED_LINES)
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_prebuild")
+list(APPEND EXPECTED_LINES "CT: Processing target_empty_postbuild")
+list(APPEND EXPECTED_LINES "CT: generate text files A, B, and C")
+list(APPEND EXPECTED_LINES "CT: Processing target_update_files")
+
+test_output()
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in
new file mode 100644
index 0000000..fed946c
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/CMakeLists.txt.in
@@ -0,0 +1,108 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ add_link_options("-non_shared")
+endif()
+
+add_library(lib1 lib1.c)
+
+set(TEST_MISSING_TARGET_SRC 0)
+set(TEST_MISSING_TARGET_DEP 0)
+set(TEST_MISSING_DEP 0)
+set(TEST_DEP_CYCLE 0)
+
+add_executable(exe1 exe1.c)
+target_link_libraries(exe1 lib1)
+
+add_custom_target(target_cmd ALL
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd" > target_cmd
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_extra" > target_cmd_extra.txt
+ BYPRODUCTS target_cmd target_cmd_extra.txt
+ COMMENT "CT: Processing target_cmd")
+
+add_custom_command(TARGET target_cmd PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_prebuild" > target_cmd_prebuild.txt
+ BYPRODUCTS target_cmd_prebuild.txt
+ COMMENT "CT: Processing target_cmd_prebuild")
+#event does not run for custom targets
+add_custom_command(TARGET target_cmd PRE_LINK
+ COMMAND ${CMAKE_COMMAND} -E echo "executing target_cmd_prelink commands"
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_prelink" > target_cmd_prelink.txt
+ BYPRODUCTS target_cmd_prelink.txt
+ COMMENT "CT: Processing target_cmd_prelink")
+add_custom_command(TARGET target_cmd POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "executing target_cmd_postbuild commands"
+ COMMAND ${CMAKE_COMMAND} -E echo "target_cmd_postbuild" > target_cmd_postbuild.txt
+ BYPRODUCTS target_cmd_postbuild.txt
+ COMMENT "CT: Processing target_cmd_postbuild")
+
+add_custom_target(target_empty ALL
+ COMMENT "CT: Processing target_empty")
+
+add_custom_command(TARGET target_empty PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "target_empty_prebuild" > target_empty_prebuild.txt
+ BYPRODUCTS target_empty_prebuild.txt
+ COMMENT "CT: Processing target_empty_prebuild")
+add_custom_command(TARGET target_empty POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "target_empty_postbuild" > target_empty_postbuild.txt
+ BYPRODUCTS target_empty_postbuild.txt
+ COMMENT "CT: Processing target_empty_postbuild")
+
+add_dependencies(target_cmd target_empty)
+
+add_custom_command(
+ OUTPUT out_of_order_dep.txt
+ COMMAND ${CMAKE_COMMAND} -E echo "out_of_order_dep" > out_of_order_dep.txt
+ COMMENT "CT: generate text file out_of_order_dep"
+ DEPENDS dependsA.txt
+)
+
+if(TEST_MISSING_TARGET_SRC)
+ set(SRC_FILE does_not_exist)
+endif()
+if(TEST_MISSING_TARGET_DEP)
+ set(DEP_FILE does_not_exist)
+endif()
+
+add_custom_target(target_update_files
+ DEPENDS genc_do_not_list.txt ${DEP_FILE}
+ SOURCES gena.txt genb.txt another_file.c ${SRC_FILE}
+ BYPRODUCTS junkit.txt
+ COMMAND ${CMAKE_COMMAND} -E copy another_file.c junkit.txt
+ COMMENT "CT: Processing target_update_files")
+
+add_custom_command(
+ OUTPUT force_rebuild gena.txt genb.txt genc_do_not_list.txt
+ COMMAND ${CMAKE_COMMAND} -E copy dependsA.txt gena.txt
+ COMMAND ${CMAKE_COMMAND} -E echo "genb" > genb.txt
+ COMMAND ${CMAKE_COMMAND} -E echo "genc" > genc_do_not_list.txt
+ DEPENDS out_of_order_dep.txt dependsA.txt
+ COMMENT "CT: generate text files A, B, and C"
+)
+
+if(TEST_MISSING_DEP)
+ set(MISSING_DEP MISSING_DEP)
+endif()
+if(TEST_DEP_CYCLE)
+ set(DEP_CYCLE out_of_order_dep.txt)
+endif()
+
+add_custom_command(
+ OUTPUT dependsA.txt
+ COMMAND ${CMAKE_COMMAND} -E echo "dependsA" > dependsA.txt
+ DEPENDS ${MISSING_DEP} ${DEP_CYCLE} another_file.c
+ COMMENT "CT: generate text file dependsA"
+)
+
+add_custom_command(
+ OUTPUT another_file.c
+ COMMAND ${CMAKE_COMMAND} -E echo "//auto-gen file" > another_file.c
+ COMMENT "CT: generate C file another_file"
+)
+
+add_dependencies(target_update_files target_empty)
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/exe1.c b/Tests/GhsMulti/GhsMultiCustomTarget/exe1.c
new file mode 100644
index 0000000..29ad70a
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/exe1.c
@@ -0,0 +1,5 @@
+extern int func(void);
+int main(void)
+{
+ return func();
+}
diff --git a/Tests/GhsMulti/GhsMultiCustomTarget/lib1.c b/Tests/GhsMulti/GhsMultiCustomTarget/lib1.c
new file mode 100644
index 0000000..b35e9cc
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiCustomTarget/lib1.c
@@ -0,0 +1,4 @@
+int func(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt
new file mode 100644
index 0000000..2e2871b
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+#set_property( GLOBAL PROPERTY GLOBAL_DEPENDS_DEBUG_MODE 1)
+add_subdirectory(exec)
+add_subdirectory(lib)
+add_subdirectory(protolib)
+add_dependencies(lib1 proto)
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt
new file mode 100644
index 0000000..85ee805
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/exec/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+add_executable(exe1 exe1.c)
+target_link_libraries(exe1 lib1)
+target_include_directories(exe1 PRIVATE "${test_BINARY_DIR}")
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ target_link_options(exe1 PRIVATE "-non_shared")
+endif()
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c b/Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c
new file mode 100644
index 0000000..fbf4ed4
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/exec/exe1.c
@@ -0,0 +1,8 @@
+#include "lib1.h"
+#include "p.h"
+
+int main(void)
+{
+ return func1() + func2() + func3() + func1p() + func2p() + func3p() +
+ PROTO1 + PROTO2 + PROTO3;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt
new file mode 100644
index 0000000..ae30fa2
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/lib/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+add_library(lib1 STATIC
+ func1.c lib1.h
+ "${test_BINARY_DIR}/protolib/proto1.c"
+ "${test_BINARY_DIR}/protolib/proto1.h")
+set_source_files_properties(
+ "${test_BINARY_DIR}/protolib/proto1.c"
+ "${test_BINARY_DIR}/protolib/proto1.h"
+ PROPERTIES GENERATED 1)
+target_include_directories(lib1 PRIVATE "${test_BINARY_DIR}/protolib"
+ PUBLIC .)
+add_custom_command( TARGET lib1 POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${test_BINARY_DIR}/protolib/proto1.h" "${test_BINARY_DIR}/p.h"
+ COMMENT "Copy ${test_BINARY_DIR}/protolib/proto1.h ${test_BINARY_DIR}/p.h"
+ BYPRODUCTS "${test_BINARY_DIR}/p.h")
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c b/Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c
new file mode 100644
index 0000000..53334fe
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/lib/func1.c
@@ -0,0 +1,17 @@
+#include "lib1.h"
+#include "proto1.h"
+
+int func1(void)
+{
+ return 1 + PROTO1;
+}
+
+int func2(void)
+{
+ return 2 + PROTO2;
+}
+
+int func3(void)
+{
+ return 3 + PROTO3;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h b/Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h
new file mode 100644
index 0000000..5e99f02
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/lib/lib1.h
@@ -0,0 +1,3 @@
+extern int func1(void);
+extern int func2(void);
+extern int func3(void);
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt
new file mode 100644
index 0000000..8cb6869
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/protolib/CMakeLists.txt
@@ -0,0 +1,28 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+add_custom_target(proto ALL
+ DEPENDS proto1.c
+ proto1.h
+ SOURCES
+ ${test_SOURCE_DIR}/protolib/proto1.c.in
+ ${test_SOURCE_DIR}/protolib/proto1.h.in
+ COMMENT "Creating proto files")
+
+add_custom_command(
+ OUTPUT proto1.c
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${test_SOURCE_DIR}/protolib/proto1.c.in proto1.c
+ DEPENDS ${test_SOURCE_DIR}/protolib/proto1.c.in
+ COMMENT "generate proto C files"
+)
+
+add_custom_command(
+ OUTPUT proto1.h
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${test_SOURCE_DIR}/protolib/proto1.h.in proto1.h
+ DEPENDS ${test_SOURCE_DIR}/protolib/proto1.h.in
+ COMMENT "generate proto H files"
+)
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in
new file mode 100644
index 0000000..0efb1bd
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.c.in
@@ -0,0 +1,16 @@
+#include "proto1.h"
+
+int func1p(void)
+{
+ return 1;
+}
+
+int func2p(void)
+{
+ return 2;
+}
+
+int func3p(void)
+{
+ return 3;
+}
diff --git a/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in
new file mode 100644
index 0000000..f2f93af
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDepOrder/protolib/proto1.h.in
@@ -0,0 +1,7 @@
+extern int func1p(void);
+extern int func2p(void);
+extern int func3p(void);
+
+#define PROTO1 0x1
+#define PROTO2 0x2
+#define PROTO3 0x3
diff --git a/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/CMakeLists.txt b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/CMakeLists.txt
new file mode 100644
index 0000000..a1f152f
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.5)
+project(test C)
+
+add_library(libdemo
+ test.c
+ testCase.c
+ subfolder_test.c
+ subfolder_test_0.c
+ "subfolder/test.c"
+ subfolder/testcase.c
+)
+
+add_executable(demo main.c)
+target_link_libraries(demo libdemo)
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ target_link_options(demo PRIVATE "-non_shared")
+endif()
diff --git a/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/main.c b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/main.c
new file mode 100644
index 0000000..d4ef7bb
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/main.c
@@ -0,0 +1,17 @@
+int test_a(void);
+int test_b(void);
+int test_c(void);
+int test_d(void);
+int test_e(void);
+int test_f(void);
+
+int main(int argc, char* argv[])
+{
+ test_a();
+ test_b();
+ test_c();
+ test_d();
+ test_e();
+ test_f();
+ return 0;
+}
diff --git a/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder/test.c b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder/test.c
new file mode 100644
index 0000000..5d857dd
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder/test.c
@@ -0,0 +1,4 @@
+int test_b()
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder/testcase.c b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder/testcase.c
new file mode 100644
index 0000000..66ee6f3
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder/testcase.c
@@ -0,0 +1,4 @@
+int test_f()
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder_test.c b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder_test.c
new file mode 100644
index 0000000..83589ba
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder_test.c
@@ -0,0 +1,4 @@
+int test_c()
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder_test_0.c b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder_test_0.c
new file mode 100644
index 0000000..82f9a52
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder_test_0.c
@@ -0,0 +1,4 @@
+int test_d()
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/test.c b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/test.c
new file mode 100644
index 0000000..feba80e
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/test.c
@@ -0,0 +1,4 @@
+int test_a()
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/testCase.c b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/testCase.c
new file mode 100644
index 0000000..943c19d
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/testCase.c
@@ -0,0 +1,4 @@
+int test_e()
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiExclude/CMakeLists.txt b/Tests/GhsMulti/GhsMultiExclude/CMakeLists.txt
new file mode 100644
index 0000000..0448cf2
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiExclude/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ add_link_options("-non_shared")
+endif()
+
+add_library(lib1 lib1.c)
+set_target_properties( lib1 PROPERTIES EXCLUDE_FROM_ALL yes )
+
+add_library(lib2 EXCLUDE_FROM_ALL lib1.c)
+
+add_executable(exe1 exe1.c)
diff --git a/Tests/GhsMulti/GhsMultiExclude/exe1.c b/Tests/GhsMulti/GhsMultiExclude/exe1.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiExclude/exe1.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/GhsMulti/GhsMultiExclude/lib1.c b/Tests/GhsMulti/GhsMultiExclude/lib1.c
new file mode 100644
index 0000000..b35e9cc
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiExclude/lib1.c
@@ -0,0 +1,4 @@
+int func(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiExclude/verify.cmake b/Tests/GhsMulti/GhsMultiExclude/verify.cmake
new file mode 100644
index 0000000..0467b5a
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiExclude/verify.cmake
@@ -0,0 +1,54 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#test project was generated
+unset(fileName CACHE)
+find_file (fileName lib1.gpj
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/lib1
+ )
+
+if (fileName)
+ message("Found target lib1: ${fileName}")
+else()
+ message(SEND_ERROR "Could not find target lib1: ${fileName}")
+endif()
+
+#test project was built
+unset(fileName CACHE)
+find_file (fileName lib1.a
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/lib1
+ )
+
+if (fileName)
+ message(SEND_ERROR "Found target lib1: ${fileName}")
+else()
+ message("Could not find target lib1: ${fileName}")
+endif()
+
+#test project was generated
+unset(fileName CACHE)
+find_file (fileName lib2.gpj
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/lib2
+ )
+
+if (fileName)
+ message("Found target lib2 ${fileName}")
+else()
+ message(SEND_ERROR "Could not find target lib2: ${fileName}")
+endif()
+
+#test project was built
+unset(fileName CACHE)
+find_file (fileName lib2.a
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/lib2
+ )
+
+if (fileName)
+ message(SEND_ERROR "Found target lib2: ${fileName}")
+else()
+ message("Could not find target lib2: ${fileName}")
+endif()
diff --git a/Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt b/Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt
new file mode 100644
index 0000000..24126c8
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiExternalProject/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+include(ExternalProject)
+
+ExternalProject_Add(another_project
+ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/empty
+ BINARY_DIR empty_build
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
diff --git a/Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt b/Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt
new file mode 100644
index 0000000..6846a98
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiExternalProject/empty/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(empty NONE)
+
+message("EMPTY PROJECT")
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/CMakeLists.txt
new file mode 100644
index 0000000..d4cbf04
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+add_link_options("-non_shared")
+
+# create virtual AS
+add_executable(vas exe.c)
+target_link_libraries(vas lib)
+add_library(lib func.c)
+
+# create dynamic download INTEGRITY application
+add_executable(dynamic)
+set_target_properties(dynamic PROPERTIES ghs_integrity_app ON)
+target_compile_options(dynamic PRIVATE -dynamic)
+add_dependencies(dynamic vas)
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/exe.c b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/exe.c
new file mode 100644
index 0000000..29ad70a
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/exe.c
@@ -0,0 +1,5 @@
+extern int func(void);
+int main(void)
+{
+ return func();
+}
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/func.c b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/func.c
new file mode 100644
index 0000000..b35e9cc
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/func.c
@@ -0,0 +1,4 @@
+int func(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt
new file mode 100644
index 0000000..3837b5a
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_executable(App Main.c)
+target_link_libraries(App Lib)
+target_compile_options(App PUBLIC "-non_shared")
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/Main.c b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/Main.c
new file mode 100644
index 0000000..db8d658
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/Main.c
@@ -0,0 +1,8 @@
+#include "HelperFun.h"
+
+int main(int argc, const char* argv[])
+{
+ int out;
+ out = giveNum();
+ return out;
+}
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/CMakeLists.txt
new file mode 100644
index 0000000..92254e6
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.1)
+project(test)
+
+add_subdirectory(App)
+add_subdirectory(Int)
+add_subdirectory(Lib)
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Int/AppDD.int b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Int/AppDD.int
new file mode 100644
index 0000000..5035d58
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Int/AppDD.int
@@ -0,0 +1,12 @@
+# Input File for the Integrate utility for use with the INTEGRITY real-time
+# operating system by Green Hills Software.
+# Before editing this file, refer to the Integrate Reference Manual.
+
+Kernel
+ Filename DynamicDownload
+EndKernel
+
+AddressSpace App
+ Filename "App/App"
+ Language C
+EndAddressSpace
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Int/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Int/CMakeLists.txt
new file mode 100644
index 0000000..d173c01
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Int/CMakeLists.txt
@@ -0,0 +1 @@
+add_executable(AppDD AppDD.int)
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt
new file mode 100644
index 0000000..bb9849a
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(Lib HelperFun.c HelperFun.h)
+target_include_directories(Lib PUBLIC .)
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/HelperFun.c b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/HelperFun.c
new file mode 100644
index 0000000..61922bb
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/HelperFun.c
@@ -0,0 +1,4 @@
+int giveNum(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/HelperFun.h b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/HelperFun.h
new file mode 100644
index 0000000..00971b0
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/HelperFun.h
@@ -0,0 +1 @@
+int giveNum(void);
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt
new file mode 100644
index 0000000..3f2f0eb
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt
@@ -0,0 +1,21 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+add_link_options("-non_shared")
+
+project(test C)
+
+# create virtual AS
+add_executable(vas exe.c)
+target_link_libraries(vas lib)
+add_library(lib func.c)
+
+# create kernel
+add_executable(kernel kernel.c)
+target_link_options(kernel PRIVATE -kernel)
+
+# create monolith INTEGRITY application
+add_executable(monolith test.int)
+add_dependencies(monolith vas)
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/exe.c b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/exe.c
new file mode 100644
index 0000000..29ad70a
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/exe.c
@@ -0,0 +1,5 @@
+extern int func(void);
+int main(void)
+{
+ return func();
+}
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/func.c b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/func.c
new file mode 100644
index 0000000..c302418
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/func.c
@@ -0,0 +1,5 @@
+
+int func(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/kernel.c b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/kernel.c
new file mode 100644
index 0000000..d1bce33
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/kernel.c
@@ -0,0 +1,15 @@
+#include "INTEGRITY.h"
+#include "boottable.h"
+
+void main()
+{
+ Exit(0);
+}
+
+/* This global table will be filled in during the Integrate phase with */
+/* information about the AddressSpaces, Tasks, and Objects that are to be */
+/* created. If you do not plan to use Integrate, you may omit this file from
+ */
+/* the kernel, and the boot table code will then not be included. */
+
+GlobalTable TheGlobalTable = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
diff --git a/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/test.int b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/test.int
new file mode 100644
index 0000000..361793a
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/test.int
@@ -0,0 +1,8 @@
+Kernel
+ Filename kernel
+EndKernel
+
+AddressSpace App
+ Filename vas
+ Language C
+EndAddressSpace
diff --git a/Tests/GhsMulti/GhsMultiInterface/CMakeLists.txt b/Tests/GhsMulti/GhsMultiInterface/CMakeLists.txt
new file mode 100644
index 0000000..fa0dce0
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiInterface/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+add_library(iface INTERFACE)
diff --git a/Tests/GhsMulti/GhsMultiLinkTest/CMakeLists.txt b/Tests/GhsMulti/GhsMultiLinkTest/CMakeLists.txt
new file mode 100644
index 0000000..da80b51
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTest/CMakeLists.txt
@@ -0,0 +1,92 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+message("Copy project")
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt.in
+ ${CMAKE_CURRENT_BINARY_DIR}/link_src/CMakeLists.txt COPYONLY)
+
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/exe1.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/exe1.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/func2.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/func3.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/func4.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/func5.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/func6.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/func7.c
+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/link_src
+)
+
+message("Building project")
+try_compile(RESULT
+ ${CMAKE_CURRENT_BINARY_DIR}/link_build
+ ${CMAKE_CURRENT_BINARY_DIR}/link_src
+ test
+ CMAKE_FLAGS
+ -DRUN_TEST=${RUN_TEST}
+ -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
+ OUTPUT_VARIABLE OUTPUT)
+
+message("Output from build:\n${OUTPUT}")
+if (RUN_TEST STREQUAL "NO_FLAGS")
+ if(NOT RESULT)
+ message(SEND_ERROR "Could not build test project (1)!")
+ endif()
+else()
+ unset(fileName CACHE)
+ find_file(fileName exe1.gpj
+ ${CMAKE_CURRENT_BINARY_DIR}/link_build
+ ${CMAKE_CURRENT_BINARY_DIR}/link_build/exe1
+ )
+ message("Parsing project file: ${fileName}")
+ file(STRINGS ${fileName} fileText)
+ set(expected_flags
+ -add-link-options1 -add-link-options2
+ link_directories_used1 link_directories_used2 "c:/absolute"
+ link_libraries_used1 link_libraries_used2
+ -lcsl1 csl2
+ -clinkexe1 -clinkexe2
+ -special-lib2-public-link)
+ foreach(opt IN LISTS expected_flags)
+ string(FIND "${fileText}" "${opt}" opt_found)
+ if ( opt_found EQUAL -1 )
+ message(SEND_ERROR "Could not find: ${opt}")
+ endif()
+ endforeach()
+
+ unset(fileName CACHE)
+ find_file (fileName lib1.gpj
+ ${CMAKE_CURRENT_BINARY_DIR}/link_build
+ ${CMAKE_CURRENT_BINARY_DIR}/link_build/lib1
+ )
+ message("Parsing project file: ${fileName}")
+ file(STRINGS ${fileName} fileText)
+ set(expected_flags
+ -clinkexeA1 -clinkexeA2
+ -static-lib-flags1 -static-lib-flags2)
+ foreach(opt IN LISTS expected_flags)
+ string(FIND "${fileText}" "${opt}" opt_found)
+ if (opt_found EQUAL -1)
+ message(SEND_ERROR "Could not find: ${opt}")
+ endif()
+ endforeach()
+
+ unset(fileName CACHE)
+ find_file (fileName lib2.gpj
+ ${CMAKE_CURRENT_BINARY_DIR}/link_build
+ ${CMAKE_CURRENT_BINARY_DIR}/link_build/lib2
+ )
+ message("Parsing project file: ${fileName}")
+ file(STRINGS ${fileName} fileText)
+ set(expected_flags
+ -clinkexeA1 -clinkexeA2)
+ foreach(opt IN LISTS expected_flags)
+ string(FIND "${fileText}" "${opt}" opt_found)
+ if ( opt_found EQUAL -1 )
+ message(SEND_ERROR "Could not find: ${opt}")
+ endif()
+ endforeach()
+endif()
diff --git a/Tests/GhsMulti/GhsMultiLinkTest/CMakeLists.txt.in b/Tests/GhsMulti/GhsMultiLinkTest/CMakeLists.txt.in
new file mode 100644
index 0000000..58c2115
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTest/CMakeLists.txt.in
@@ -0,0 +1,43 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ add_link_options("-non_shared")
+endif()
+
+if(RUN_TEST STREQUAL "CHECK_FLAGS")
+ add_link_options(-add-link-options1 -add-link-options2)
+ link_directories(link_directories_used1 link_directories_used2 "c:/absolute")
+ link_libraries(link_libraries_used1 link_libraries_used2 )
+ set( CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} -lcsl1 csl2" )
+ set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -clinkexe1 -clinkexe2")
+endif()
+
+add_executable(exe1 exe1.c)
+target_link_libraries(exe1 lib1)
+
+if(RUN_TEST STREQUAL "CHECK_FLAGS")
+ set_property(TARGET exe1 APPEND_STRING PROPERTY LINK_FLAGS "--link-flag-prop1 --link-flag-prop2")
+ set_property(TARGET exe1 APPEND PROPERTY LINK_OPTIONS --link-opt-prop1 --link-opt-prop2)
+endif()
+
+if(RUN_TEST STREQUAL "CHECK_FLAGS")
+ set(CMAKE_STATIC_LINKER_FLAGS ${CMAKE_STATIC_LINKER_FLAGS} "-clinkexeA1 -clinkexeA2")
+endif()
+
+add_library(lib1 STATIC func2.c func3.c func4.c)
+target_link_libraries(lib1 lib2)
+
+if(RUN_TEST STREQUAL "CHECK_FLAGS")
+ set_property(TARGET lib1 APPEND_STRING PROPERTY STATIC_LIBRARY_FLAGS "-static-lib-flags1 -static-lib-flags2")
+endif()
+
+add_library(lib2 STATIC func5.c func6.c func7.c)
+
+if(RUN_TEST STREQUAL "CHECK_FLAGS")
+ target_link_options(lib2 PUBLIC -special-lib2-public-link)
+endif()
diff --git a/Tests/GhsMulti/GhsMultiLinkTest/exe1.c b/Tests/GhsMulti/GhsMultiLinkTest/exe1.c
new file mode 100644
index 0000000..f21c126
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTest/exe1.c
@@ -0,0 +1,6 @@
+#include "exe1.h"
+
+int main(void)
+{
+ return func2a() + func3a() + func4a() + func5a() + func6a() + func7a();
+}
diff --git a/Tests/GhsMulti/GhsMultiLinkTest/exe1.h b/Tests/GhsMulti/GhsMultiLinkTest/exe1.h
new file mode 100644
index 0000000..e2b1725
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTest/exe1.h
@@ -0,0 +1,6 @@
+extern int func2a(void);
+extern int func3a(void);
+extern int func4a(void);
+extern int func5a(void);
+extern int func6a(void);
+extern int func7a(void);
diff --git a/Tests/GhsMulti/GhsMultiLinkTest/func2.c b/Tests/GhsMulti/GhsMultiLinkTest/func2.c
new file mode 100644
index 0000000..8f66fba
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTest/func2.c
@@ -0,0 +1,4 @@
+int func2a(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiLinkTest/func3.c b/Tests/GhsMulti/GhsMultiLinkTest/func3.c
new file mode 100644
index 0000000..57c7a6f
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTest/func3.c
@@ -0,0 +1,4 @@
+int func3a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiLinkTest/func4.c b/Tests/GhsMulti/GhsMultiLinkTest/func4.c
new file mode 100644
index 0000000..109fd7b
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTest/func4.c
@@ -0,0 +1,4 @@
+int func4a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiLinkTest/func5.c b/Tests/GhsMulti/GhsMultiLinkTest/func5.c
new file mode 100644
index 0000000..f28a705
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTest/func5.c
@@ -0,0 +1,4 @@
+int func5a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiLinkTest/func6.c b/Tests/GhsMulti/GhsMultiLinkTest/func6.c
new file mode 100644
index 0000000..bf77406
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTest/func6.c
@@ -0,0 +1,4 @@
+int func6a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiLinkTest/func7.c b/Tests/GhsMulti/GhsMultiLinkTest/func7.c
new file mode 100644
index 0000000..6a4a9a1
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTest/func7.c
@@ -0,0 +1,4 @@
+int func7a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiLinkTestSub/CMakeLists.txt b/Tests/GhsMulti/GhsMultiLinkTestSub/CMakeLists.txt
new file mode 100644
index 0000000..145dac0
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTestSub/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+add_subdirectory(sub_exe)
+add_subdirectory(sub_lib)
diff --git a/Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/CMakeLists.txt b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/CMakeLists.txt
new file mode 100644
index 0000000..f49e33d
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+add_executable(exe1 exe1.c)
+target_link_libraries(exe1 lib1)
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ target_link_options(exe1 PRIVATE "-non_shared")
+endif()
diff --git a/Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/exe1.c b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/exe1.c
new file mode 100644
index 0000000..f21c126
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/exe1.c
@@ -0,0 +1,6 @@
+#include "exe1.h"
+
+int main(void)
+{
+ return func2a() + func3a() + func4a() + func5a() + func6a() + func7a();
+}
diff --git a/Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/exe1.h b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/exe1.h
new file mode 100644
index 0000000..e2b1725
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/exe1.h
@@ -0,0 +1,6 @@
+extern int func2a(void);
+extern int func3a(void);
+extern int func4a(void);
+extern int func5a(void);
+extern int func6a(void);
+extern int func7a(void);
diff --git a/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/CMakeLists.txt b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/CMakeLists.txt
new file mode 100644
index 0000000..9039730
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/CMakeLists.txt
@@ -0,0 +1,7 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+add_library(lib1 STATIC func2.c func3.c func4.c)
+target_link_libraries(lib1 lib2)
+
+add_library(lib2 STATIC func5.c func6.c func7.c)
diff --git a/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func2.c b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func2.c
new file mode 100644
index 0000000..8f66fba
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func2.c
@@ -0,0 +1,4 @@
+int func2a(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func3.c b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func3.c
new file mode 100644
index 0000000..57c7a6f
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func3.c
@@ -0,0 +1,4 @@
+int func3a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func4.c b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func4.c
new file mode 100644
index 0000000..109fd7b
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func4.c
@@ -0,0 +1,4 @@
+int func4a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func5.c b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func5.c
new file mode 100644
index 0000000..f28a705
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func5.c
@@ -0,0 +1,4 @@
+int func5a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func6.c b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func6.c
new file mode 100644
index 0000000..bf77406
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func6.c
@@ -0,0 +1,4 @@
+int func6a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func7.c b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func7.c
new file mode 100644
index 0000000..6a4a9a1
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func7.c
@@ -0,0 +1,4 @@
+int func7a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiMultipleProjects/CMakeLists.txt b/Tests/GhsMulti/GhsMultiMultipleProjects/CMakeLists.txt
new file mode 100644
index 0000000..9e077a9
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiMultipleProjects/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ add_link_options("-non_shared")
+endif()
+
+add_library(lib1 lib1.c)
+add_executable(exe1 exe1.c)
+target_link_libraries(exe1 lib1)
+
+add_subdirectory(sub)
+add_subdirectory(sub2 examples EXCLUDE_FROM_ALL)
diff --git a/Tests/GhsMulti/GhsMultiMultipleProjects/exe1.c b/Tests/GhsMulti/GhsMultiMultipleProjects/exe1.c
new file mode 100644
index 0000000..b9cdd61
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiMultipleProjects/exe1.c
@@ -0,0 +1,5 @@
+extern int lib1_func(void);
+int main(void)
+{
+ return lib1_func();
+}
diff --git a/Tests/GhsMulti/GhsMultiMultipleProjects/lib1.c b/Tests/GhsMulti/GhsMultiMultipleProjects/lib1.c
new file mode 100644
index 0000000..5100945
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiMultipleProjects/lib1.c
@@ -0,0 +1,4 @@
+int lib1_func(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiMultipleProjects/sub/CMakeLists.txt b/Tests/GhsMulti/GhsMultiMultipleProjects/sub/CMakeLists.txt
new file mode 100644
index 0000000..0d83bc3
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiMultipleProjects/sub/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test2 C)
+
+add_library(lib2 lib2.c)
+add_executable(exe2 exe2.c)
+target_link_libraries(exe2 lib1 lib2)
diff --git a/Tests/GhsMulti/GhsMultiMultipleProjects/sub/exe2.c b/Tests/GhsMulti/GhsMultiMultipleProjects/sub/exe2.c
new file mode 100644
index 0000000..9238cf3
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiMultipleProjects/sub/exe2.c
@@ -0,0 +1,6 @@
+extern int func(void);
+extern int lib1_func(void);
+int main(void)
+{
+ return func() + lib1_func();
+}
diff --git a/Tests/GhsMulti/GhsMultiMultipleProjects/sub/lib2.c b/Tests/GhsMulti/GhsMultiMultipleProjects/sub/lib2.c
new file mode 100644
index 0000000..b35e9cc
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiMultipleProjects/sub/lib2.c
@@ -0,0 +1,4 @@
+int func(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiMultipleProjects/sub2/CMakeLists.txt b/Tests/GhsMulti/GhsMultiMultipleProjects/sub2/CMakeLists.txt
new file mode 100644
index 0000000..e42e7fb
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiMultipleProjects/sub2/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test3 C)
+
+add_library(lib3 lib3.c)
+add_executable(exe3 exe3.c)
+target_link_libraries(exe3 lib1 lib3)
diff --git a/Tests/GhsMulti/GhsMultiMultipleProjects/sub2/exe3.c b/Tests/GhsMulti/GhsMultiMultipleProjects/sub2/exe3.c
new file mode 100644
index 0000000..9238cf3
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiMultipleProjects/sub2/exe3.c
@@ -0,0 +1,6 @@
+extern int func(void);
+extern int lib1_func(void);
+int main(void)
+{
+ return func() + lib1_func();
+}
diff --git a/Tests/GhsMulti/GhsMultiMultipleProjects/sub2/lib3.c b/Tests/GhsMulti/GhsMultiMultipleProjects/sub2/lib3.c
new file mode 100644
index 0000000..b35e9cc
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiMultipleProjects/sub2/lib3.c
@@ -0,0 +1,4 @@
+int func(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiMultipleProjects/verify.cmake b/Tests/GhsMulti/GhsMultiMultipleProjects/verify.cmake
new file mode 100644
index 0000000..3855215
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiMultipleProjects/verify.cmake
@@ -0,0 +1,58 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#test project was generated
+unset(fileName CACHE)
+find_file(fileName lib3.gpj
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/lib3
+ ${CMAKE_CURRENT_BINARY_DIR}/examples
+ )
+
+if (fileName)
+ message("Found target lib3: ${fileName}")
+else()
+ message(SEND_ERROR "Could not find target lib3: ${fileName}")
+endif()
+
+#test project was generated
+unset(fileName CACHE)
+find_file (fileName exe3.gpj
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/exe3
+ ${CMAKE_CURRENT_BINARY_DIR}/examples
+ )
+
+if (fileName)
+ message("Found target exe3: ${fileName}")
+else()
+ message(SEND_ERROR "Could not find target exe3: ${fileName}")
+endif()
+
+#test project was not built
+unset(fileName CACHE)
+find_file (fileName lib3.a
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/lib3
+ ${CMAKE_CURRENT_BINARY_DIR}/examples
+ )
+
+if (fileName)
+ message(SEND_ERROR "Found target lib3: ${fileName}")
+else()
+ message("Could not find target lib3: ${fileName}")
+endif()
+
+unset(fileName CACHE)
+find_file (fileName NAMES exe3.as exe3
+ HINTS
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/exe3
+ ${CMAKE_CURRENT_BINARY_DIR}/examples
+ )
+
+if (fileName)
+ message(SEND_ERROR "Found target exe3: ${fileName}")
+else()
+ message("Could not find target exe3: ${fileName}")
+endif()
diff --git a/Tests/GhsMulti/GhsMultiObjectLibrary/CMakeLists.txt b/Tests/GhsMulti/GhsMultiObjectLibrary/CMakeLists.txt
new file mode 100644
index 0000000..98668e5c
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiObjectLibrary/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+add_library(obj1 OBJECT testOBJ.c testOBJ.h sub/testOBJ.c testOBJ2.c)
+
+add_executable(exe1 exe.c $<TARGET_OBJECTS:obj1>)
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ target_link_options(exe1 PRIVATE "-non_shared")
+endif()
diff --git a/Tests/GhsMulti/GhsMultiObjectLibrary/exe.c b/Tests/GhsMulti/GhsMultiObjectLibrary/exe.c
new file mode 100644
index 0000000..c2c5a19
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiObjectLibrary/exe.c
@@ -0,0 +1,8 @@
+extern int funcOBJ(void);
+extern int funcOBJ2(void);
+extern int funcOBJs(void);
+
+int main(void)
+{
+ return funcOBJ() + funcOBJ2() + funcOBJs();
+}
diff --git a/Tests/GhsMulti/GhsMultiObjectLibrary/sub/testOBJ.c b/Tests/GhsMulti/GhsMultiObjectLibrary/sub/testOBJ.c
new file mode 100644
index 0000000..5228ef2
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiObjectLibrary/sub/testOBJ.c
@@ -0,0 +1,4 @@
+int funcOBJs(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiObjectLibrary/testOBJ.c b/Tests/GhsMulti/GhsMultiObjectLibrary/testOBJ.c
new file mode 100644
index 0000000..ec6f2c3
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiObjectLibrary/testOBJ.c
@@ -0,0 +1,4 @@
+int funcOBJ(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiObjectLibrary/testOBJ.h b/Tests/GhsMulti/GhsMultiObjectLibrary/testOBJ.h
new file mode 100644
index 0000000..9aef431
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiObjectLibrary/testOBJ.h
@@ -0,0 +1 @@
+extern int funcOBJ(void);
diff --git a/Tests/GhsMulti/GhsMultiObjectLibrary/testOBJ2.c b/Tests/GhsMulti/GhsMultiObjectLibrary/testOBJ2.c
new file mode 100644
index 0000000..b6a9b93
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiObjectLibrary/testOBJ2.c
@@ -0,0 +1,4 @@
+int funcOBJ2(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiPlatform/CMakeLists.txt b/Tests/GhsMulti/GhsMultiPlatform/CMakeLists.txt
new file mode 100644
index 0000000..b177887
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiPlatform/CMakeLists.txt
@@ -0,0 +1,34 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test)
+
+message("PLATFORM_ID = ${PLATFORM_ID}")
+
+message("CMAKE_C_COMPILER = ${CMAKE_C_COMPILER}")
+message("CMAKE_C_COMPILER_ID = ${CMAKE_C_COMPILER_ID}")
+message("CMAKE_C_COMPILER_VERSION = ${CMAKE_C_COMPILER_VERSION}")
+message("CMAKE_C_COMPILER_VERSION_INTERNAL = ${CMAKE_C_COMPILER_VERSION_INTERNAL}")
+message("CMAKE_C_PLATFORM_ID = ${CMAKE_C_PLATFORM_ID}")
+message("CMAKE_C_COMPILER_ARCHITECTURE_ID = ${CMAKE_C_COMPILER_ARCHITECTURE_ID}")
+message("CMAKE_C_COMPILER_ABI = ${CMAKE_C_COMPILER_ABI}")
+message("CMAKE_C_STANDARD_COMPUTED_DEFAULT = ${CMAKE_C_STANDARD_COMPUTED_DEFAULT}")
+
+message("CMAKE_CXX_COMPILER = ${CMAKE_CXX_COMPILER}")
+message("CMAKE_CXX_COMPILER_ID = ${CMAKE_CXX_COMPILER_ID}")
+message("CMAKE_CXX_COMPILER_VERSION = ${CMAKE_CXX_COMPILER_VERSION}")
+message("CMAKE_CXX_COMPILER_VERSION_INTERNAL = ${CMAKE_CXX_COMPILER_VERSION_INTERNAL}")
+message("CMAKE_CXX_PLATFORM_ID = ${CMAKE_CXX_PLATFORM_ID}")
+message("CMAKE_CXX_COMPILER_ARCHITECTURE_ID = ${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}")
+message("CMAKE_CXX_COMPILER_ABI = ${CMAKE_CXX_COMPILER_ABI}")
+message("CMAKE_CXX_STANDARD_COMPUTED_DEFAULT = ${CMAKE_CXX_STANDARD_COMPUTED_DEFAULT}")
+
+if(CMAKE_C_COMPILER AND NOT CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ message(FATAL_ERROR "CMAKE_C_COMPILER_ID != GHS")
+endif()
+
+if(CMAKE_CXX_COMPILER AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "GHS")
+ message(FATAL_ERROR "CMAKE_CXX_COMPILER_ID != GHS")
+endif()
diff --git a/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt b/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt
new file mode 100644
index 0000000..b2540d9
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiRenameInstall/CMakeLists.txt
@@ -0,0 +1,42 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+set(targets_to_install "")
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+ add_link_options("-non_shared")
+endif()
+
+if(RUN_TEST STREQUAL "SINGLE_EXEC")
+ add_executable(exe1 exe.c)
+ set(targets_to_install exe1)
+endif()
+
+if(RUN_TEST STREQUAL "SINGLE_EXEC_RENAMED")
+ set(name new_name)
+ add_executable(exe1 exe.c)
+ set_property(TARGET exe1 PROPERTY RUNTIME_OUTPUT_DIRECTORY ${name}_bin_$<CONFIG>)
+ set_property(TARGET exe1 PROPERTY OUTPUT_NAME ${name}_$<CONFIG>)
+ set_property(TARGET exe1 PROPERTY SUFFIX .bin)
+ set(targets_to_install exe1)
+endif()
+
+if(RUN_TEST STREQUAL "EXEC_AND_LIB")
+ add_library(lib1 lib1.c)
+ set_property(TARGET lib1 PROPERTY ARCHIVE_OUTPUT_DIRECTORY forced-$<CONFIG>)
+ set_property(TARGET lib1 PROPERTY SUFFIX .LL)
+ set_property(TARGET lib1 PROPERTY OUTPUT_NAME lib1_$<CONFIG>)
+
+ add_executable(exe1 exe1.c)
+ target_link_libraries(exe1 lib1)
+ set(targets_to_install exe1 lib1)
+endif()
+
+install(TARGETS ${targets_to_install}
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib/static)
diff --git a/Tests/GhsMulti/GhsMultiRenameInstall/exe.c b/Tests/GhsMulti/GhsMultiRenameInstall/exe.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiRenameInstall/exe.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/GhsMulti/GhsMultiRenameInstall/exe1.c b/Tests/GhsMulti/GhsMultiRenameInstall/exe1.c
new file mode 100644
index 0000000..29ad70a
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiRenameInstall/exe1.c
@@ -0,0 +1,5 @@
+extern int func(void);
+int main(void)
+{
+ return func();
+}
diff --git a/Tests/GhsMulti/GhsMultiRenameInstall/lib1.c b/Tests/GhsMulti/GhsMultiRenameInstall/lib1.c
new file mode 100644
index 0000000..b35e9cc
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiRenameInstall/lib1.c
@@ -0,0 +1,4 @@
+int func(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/Atest3.c b/Tests/GhsMulti/GhsMultiSrcGroups/Atest3.c
new file mode 100644
index 0000000..9c9c1d9
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/Atest3.c
@@ -0,0 +1,4 @@
+int funcA3a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/CMakeLists.txt b/Tests/GhsMulti/GhsMultiSrcGroups/CMakeLists.txt
new file mode 100644
index 0000000..93a1afc
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/CMakeLists.txt
@@ -0,0 +1,45 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+#set(CMAKE_FOLDER ON)
+add_executable(groups
+ test1.c
+ test1.h
+ test2a.c
+ test4.c
+ test5.c
+ test6.c
+ test7.c
+ standard.h
+ testOBJ.c
+ testOBJ.h
+ sub/testOBJ.c
+ sub/testOBJ.h
+ textfile.txt
+ textfile2.txt
+ test3.c
+ Atest3.c
+# object.o
+ resource.pdf
+ cmake.rule
+ s5.h
+ s2.h
+ s4.h
+ standard.h
+ )
+
+if(TEST_PROP)
+ set_target_properties(groups PROPERTIES GHS_NO_SOURCE_GROUP_FILE ON)
+endif()
+if(CMAKE_C_COMPILER_ID MATCHES "GHS")
+ target_link_options(groups PRIVATE "-non_shared")
+endif()
+source_group( gC FILES sub/testOBJ.h testOBJ.c testOBJ.h sub/testOBJ.c )
+source_group( gA FILES test1.c test1.h)
+source_group( gB test[65].c )
+source_group( gC\\gD FILES test7.c )
+source_group( docs FILES textfile.txt )
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/cmake.rule b/Tests/GhsMulti/GhsMultiSrcGroups/cmake.rule
new file mode 100644
index 0000000..c6cac69
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/cmake.rule
@@ -0,0 +1 @@
+empty
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/object.o b/Tests/GhsMulti/GhsMultiSrcGroups/object.o
new file mode 100644
index 0000000..c6cac69
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/object.o
@@ -0,0 +1 @@
+empty
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/resource.pdf b/Tests/GhsMulti/GhsMultiSrcGroups/resource.pdf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/resource.pdf
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/s2.h b/Tests/GhsMulti/GhsMultiSrcGroups/s2.h
new file mode 100644
index 0000000..e2b1725
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/s2.h
@@ -0,0 +1,6 @@
+extern int func2a(void);
+extern int func3a(void);
+extern int func4a(void);
+extern int func5a(void);
+extern int func6a(void);
+extern int func7a(void);
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/s4.h b/Tests/GhsMulti/GhsMultiSrcGroups/s4.h
new file mode 100644
index 0000000..e2b1725
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/s4.h
@@ -0,0 +1,6 @@
+extern int func2a(void);
+extern int func3a(void);
+extern int func4a(void);
+extern int func5a(void);
+extern int func6a(void);
+extern int func7a(void);
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/s5.h b/Tests/GhsMulti/GhsMultiSrcGroups/s5.h
new file mode 100644
index 0000000..e2b1725
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/s5.h
@@ -0,0 +1,6 @@
+extern int func2a(void);
+extern int func3a(void);
+extern int func4a(void);
+extern int func5a(void);
+extern int func6a(void);
+extern int func7a(void);
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/standard.h b/Tests/GhsMulti/GhsMultiSrcGroups/standard.h
new file mode 100644
index 0000000..66522d5
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/standard.h
@@ -0,0 +1 @@
+#define something
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/sub/testOBJ.c b/Tests/GhsMulti/GhsMultiSrcGroups/sub/testOBJ.c
new file mode 100644
index 0000000..90ea9b9
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/sub/testOBJ.c
@@ -0,0 +1,6 @@
+#include "testOBJ.h"
+
+int funcOBJsub(void)
+{
+ return func2a() + func3a() + func4a() + func5a() + func6a() + func7a();
+}
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/sub/testOBJ.h b/Tests/GhsMulti/GhsMultiSrcGroups/sub/testOBJ.h
new file mode 100644
index 0000000..e2b1725
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/sub/testOBJ.h
@@ -0,0 +1,6 @@
+extern int func2a(void);
+extern int func3a(void);
+extern int func4a(void);
+extern int func5a(void);
+extern int func6a(void);
+extern int func7a(void);
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/test1.c b/Tests/GhsMulti/GhsMultiSrcGroups/test1.c
new file mode 100644
index 0000000..94f818a
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/test1.c
@@ -0,0 +1,6 @@
+#include "test1.h"
+
+int main(void)
+{
+ return func2a() + func3a() + func4a() + func5a() + func6a() + func7a();
+}
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/test1.h b/Tests/GhsMulti/GhsMultiSrcGroups/test1.h
new file mode 100644
index 0000000..e2b1725
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/test1.h
@@ -0,0 +1,6 @@
+extern int func2a(void);
+extern int func3a(void);
+extern int func4a(void);
+extern int func5a(void);
+extern int func6a(void);
+extern int func7a(void);
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/test2a.c b/Tests/GhsMulti/GhsMultiSrcGroups/test2a.c
new file mode 100644
index 0000000..8f66fba
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/test2a.c
@@ -0,0 +1,4 @@
+int func2a(void)
+{
+ return 2;
+}
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/test3.c b/Tests/GhsMulti/GhsMultiSrcGroups/test3.c
new file mode 100644
index 0000000..57c7a6f
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/test3.c
@@ -0,0 +1,4 @@
+int func3a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/test3.h b/Tests/GhsMulti/GhsMultiSrcGroups/test3.h
new file mode 100644
index 0000000..66522d5
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/test3.h
@@ -0,0 +1 @@
+#define something
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/test4.c b/Tests/GhsMulti/GhsMultiSrcGroups/test4.c
new file mode 100644
index 0000000..109fd7b
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/test4.c
@@ -0,0 +1,4 @@
+int func4a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/test5.c b/Tests/GhsMulti/GhsMultiSrcGroups/test5.c
new file mode 100644
index 0000000..f28a705
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/test5.c
@@ -0,0 +1,4 @@
+int func5a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/test6.c b/Tests/GhsMulti/GhsMultiSrcGroups/test6.c
new file mode 100644
index 0000000..bf77406
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/test6.c
@@ -0,0 +1,4 @@
+int func6a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/test7.c b/Tests/GhsMulti/GhsMultiSrcGroups/test7.c
new file mode 100644
index 0000000..6a4a9a1
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/test7.c
@@ -0,0 +1,4 @@
+int func7a(void)
+{
+ return 1;
+}
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/testOBJ.c b/Tests/GhsMulti/GhsMultiSrcGroups/testOBJ.c
new file mode 100644
index 0000000..e86e2a4
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/testOBJ.c
@@ -0,0 +1,11 @@
+extern int func2a(void);
+extern int func3a(void);
+extern int func4a(void);
+extern int func5a(void);
+extern int func6a(void);
+extern int func7a(void);
+
+int funcOBJ(void)
+{
+ return func2a() + func3a() + func4a() + func5a() + func6a() + func7a();
+}
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/testOBJ.h b/Tests/GhsMulti/GhsMultiSrcGroups/testOBJ.h
new file mode 100644
index 0000000..e2b1725
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/testOBJ.h
@@ -0,0 +1,6 @@
+extern int func2a(void);
+extern int func3a(void);
+extern int func4a(void);
+extern int func5a(void);
+extern int func6a(void);
+extern int func7a(void);
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/textfile.txt b/Tests/GhsMulti/GhsMultiSrcGroups/textfile.txt
new file mode 100644
index 0000000..48cdce8
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/textfile.txt
@@ -0,0 +1 @@
+placeholder
diff --git a/Tests/GhsMulti/GhsMultiSrcGroups/textfile2.txt b/Tests/GhsMulti/GhsMultiSrcGroups/textfile2.txt
new file mode 100644
index 0000000..48cdce8
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiSrcGroups/textfile2.txt
@@ -0,0 +1 @@
+placeholder
diff --git a/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt b/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt
new file mode 100644
index 0000000..f5f3c55
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiUnsupportedTargets/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+add_library(sharedLib SHARED file.c)
+
+add_library(moduleLib MODULE file.c)
diff --git a/Tests/GhsMulti/GhsMultiUnsupportedTargets/file.c b/Tests/GhsMulti/GhsMultiUnsupportedTargets/file.c
new file mode 100644
index 0000000..6a4a9a1
--- /dev/null
+++ b/Tests/GhsMulti/GhsMultiUnsupportedTargets/file.c
@@ -0,0 +1,4 @@
+int func7a(void)
+{
+ return 1;
+}
diff --git a/Tests/GoogleTest/CMakeLists.txt b/Tests/GoogleTest/CMakeLists.txt
new file mode 100644
index 0000000..21f8b8b
--- /dev/null
+++ b/Tests/GoogleTest/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME GoogleTest.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/GoogleTest/Test"
+ "${CMake_BINARY_DIR}/Tests/GoogleTest/Test"
+ ${build_generator_args}
+ --build-project TestGoogleTest
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/GoogleTest/Test/CMakeLists.txt b/Tests/GoogleTest/Test/CMakeLists.txt
new file mode 100644
index 0000000..baf00d5
--- /dev/null
+++ b/Tests/GoogleTest/Test/CMakeLists.txt
@@ -0,0 +1,96 @@
+cmake_minimum_required(VERSION 3.8)
+project(TestGoogleTest)
+include(CTest)
+
+include(GoogleTest)
+
+find_package(GTest REQUIRED)
+
+add_executable(test_gtest1 main1.cxx)
+target_link_libraries(test_gtest1 GTest::GTest)
+
+# Simple test of defaults
+gtest_add_tests(TARGET test_gtest1
+ TEST_LIST testList
+)
+set(expectedTests
+ GoogleTest.LinksAndRuns
+ GoogleTest.ConditionalFail
+)
+if(NOT testList STREQUAL "${expectedTests}")
+ message(FATAL_ERROR "Expected test list: ${expectedTests}
+Actual test list: ${testList}")
+endif()
+
+
+# Same target, different arguments, so use test prefix and suffix to
+# differentiate from the above test cases
+gtest_add_tests(TARGET test_gtest1
+ TEST_LIST testList
+ TEST_PREFIX "set2."
+ TEST_SUFFIX ".foo"
+ EXTRA_ARGS --forceFail
+)
+
+set(expectedTests
+ set2.GoogleTest.LinksAndRuns.foo
+ set2.GoogleTest.ConditionalFail.foo
+)
+if(NOT testList STREQUAL "${expectedTests}")
+ message(FATAL_ERROR "Expected test list: ${expectedTests}
+Actual test list: ${testList}")
+endif()
+
+set_tests_properties(set2.GoogleTest.ConditionalFail.foo PROPERTIES WILL_FAIL YES)
+
+
+# Search specific sources to get the test list. Include an empty file
+# to ensure they are handled correctly too.
+add_executable(test_gtest2 main2.cxx empty.cxx)
+target_link_libraries(test_gtest2 GTest::Main)
+gtest_add_tests(TARGET test_gtest2
+ TEST_LIST testList
+ SOURCES main2.h empty.cxx
+)
+set(expectedTests
+ GoogleTest.SomethingElse
+ GoogleTest.OffTest1
+ GoogleTest.OffTest2
+ GoogleTest.OffTest3
+)
+if(NOT testList STREQUAL "${expectedTests}")
+ message(FATAL_ERROR "Expected test list: ${expectedTests}
+Actual test list: ${testList}")
+endif()
+set(disabledTests
+ GoogleTest.OffTest1
+ GoogleTest.OffTest2
+ GoogleTest.OffTest3
+)
+foreach(T ${disabledTests})
+ get_test_property(${T} DISABLED testDisabled)
+ if(NOT testDisabled)
+ message(FATAL_ERROR "Test ${T} should be disabled but is not")
+ endif()
+endforeach()
+
+# Non-keyword form, auto-find sources
+add_executable(test_gtest3 main3.cxx)
+target_link_libraries(test_gtest3 GTest::Main)
+gtest_add_tests(test_gtest3 "" AUTO)
+if(NOT TEST GoogleTest.Foo)
+ message(FATAL_ERROR "Test case GoogleTest.Foo not defined")
+endif()
+if(NOT TEST GoogleTest.Bar)
+ message(FATAL_ERROR "Test case GoogleTest.Bar not defined")
+endif()
+
+
+# Non-keyword form, explicitly specified sources. Allows a non-target to be
+# given for the executable.
+add_executable(test_gtest4 main4.cxx)
+target_link_libraries(test_gtest4 GTest::Main)
+gtest_add_tests($<TARGET_FILE:test_gtest4> "" main4.h)
+if(NOT TEST GoogleTest.NoKeywords)
+ message(FATAL_ERROR "Test case GoogleTest.NoKeywords not defined")
+endif()
diff --git a/Tests/GoogleTest/Test/empty.cxx b/Tests/GoogleTest/Test/empty.cxx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/GoogleTest/Test/empty.cxx
diff --git a/Tests/GoogleTest/Test/main1.cxx b/Tests/GoogleTest/Test/main1.cxx
new file mode 100644
index 0000000..c353d91
--- /dev/null
+++ b/Tests/GoogleTest/Test/main1.cxx
@@ -0,0 +1,30 @@
+#include <string>
+
+#include <gtest/gtest.h>
+
+namespace {
+bool shouldFail = false;
+}
+
+TEST(GoogleTest, LinksAndRuns)
+{
+ ASSERT_TRUE(true);
+}
+
+TEST(GoogleTest, ConditionalFail)
+{
+ ASSERT_FALSE(shouldFail);
+}
+
+int main(int argc, char* argv[])
+{
+ ::testing::InitGoogleTest(&argc, argv);
+
+ if (argc > 1) {
+ if (argv[1] != std::string("--forceFail")) {
+ throw "Unexpected argument";
+ }
+ shouldFail = true;
+ }
+ return RUN_ALL_TESTS();
+}
diff --git a/Tests/GoogleTest/Test/main2.cxx b/Tests/GoogleTest/Test/main2.cxx
new file mode 100644
index 0000000..05ffb4a
--- /dev/null
+++ b/Tests/GoogleTest/Test/main2.cxx
@@ -0,0 +1 @@
+#include "main2.h"
diff --git a/Tests/GoogleTest/Test/main2.h b/Tests/GoogleTest/Test/main2.h
new file mode 100644
index 0000000..7881c4f
--- /dev/null
+++ b/Tests/GoogleTest/Test/main2.h
@@ -0,0 +1,21 @@
+#include <gtest/gtest.h>
+
+TEST(GoogleTest, SomethingElse)
+{
+ ASSERT_TRUE(true);
+}
+
+TEST(GoogleTest, DISABLED_OffTest1)
+{
+ ASSERT_TRUE(true);
+}
+
+TEST(DISABLED_GoogleTest, OffTest2)
+{
+ ASSERT_TRUE(true);
+}
+
+TEST(DISABLED_GoogleTest, DISABLED_OffTest3)
+{
+ ASSERT_TRUE(true);
+}
diff --git a/Tests/GoogleTest/Test/main3.cxx b/Tests/GoogleTest/Test/main3.cxx
new file mode 100644
index 0000000..98ce13c
--- /dev/null
+++ b/Tests/GoogleTest/Test/main3.cxx
@@ -0,0 +1,11 @@
+#include <gtest/gtest.h>
+
+TEST(GoogleTest, Foo)
+{
+ ASSERT_TRUE(true);
+}
+
+TEST(GoogleTest, Bar)
+{
+ ASSERT_TRUE(true);
+}
diff --git a/Tests/GoogleTest/Test/main4.cxx b/Tests/GoogleTest/Test/main4.cxx
new file mode 100644
index 0000000..8023bc1
--- /dev/null
+++ b/Tests/GoogleTest/Test/main4.cxx
@@ -0,0 +1 @@
+#include "main4.h"
diff --git a/Tests/GoogleTest/Test/main4.h b/Tests/GoogleTest/Test/main4.h
new file mode 100644
index 0000000..19da12a
--- /dev/null
+++ b/Tests/GoogleTest/Test/main4.h
@@ -0,0 +1,6 @@
+#include <gtest/gtest.h>
+
+TEST(GoogleTest, NoKeywords)
+{
+ ASSERT_TRUE(true);
+}
diff --git a/Tests/ISPC/CMakeLists.txt b/Tests/ISPC/CMakeLists.txt
new file mode 100644
index 0000000..c993275
--- /dev/null
+++ b/Tests/ISPC/CMakeLists.txt
@@ -0,0 +1,18 @@
+
+
+macro (add_ispc_test_macro name)
+ add_test_macro("${name}" ${ARGN})
+ set_property(TEST "${name}" APPEND
+ PROPERTY LABELS "ISPC")
+endmacro ()
+
+add_ispc_test_macro(ISPC.ChainedStaticLibraries ISPCChainedStaticLibraries)
+add_ispc_test_macro(ISPC.CustomHeaderSuffix ISPCCustomHeaderSuffix)
+add_ispc_test_macro(ISPC.Defines ISPCDefines)
+add_ispc_test_macro(ISPC.DynamicLibrary ISPCDynamicLibrary)
+add_ispc_test_macro(ISPC.ObjectGenex ISPCObjectGenex)
+add_ispc_test_macro(ISPC.ObjectLibrary ISPCObjectLibrary)
+add_ispc_test_macro(ISPC.ResponseAndDefine ISPCResponseAndDefine)
+add_ispc_test_macro(ISPC.StaticLibrary ISPCStaticLibrary)
+add_ispc_test_macro(ISPC.SystemIncludes ISPCSystemIncludes)
+add_ispc_test_macro(ISPC.TryCompile ISPCTryCompile)
diff --git a/Tests/ISPC/ChainedStaticLibraries/CMakeLists.txt b/Tests/ISPC/ChainedStaticLibraries/CMakeLists.txt
new file mode 100644
index 0000000..9a255a0
--- /dev/null
+++ b/Tests/ISPC/ChainedStaticLibraries/CMakeLists.txt
@@ -0,0 +1,22 @@
+
+cmake_minimum_required(VERSION 3.18)
+project(ISPCChainedStaticLibraries CXX ISPC)
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(CMAKE_ISPC_FLAGS "--arch=x86")
+endif()
+
+
+add_library(ispc_objects1 STATIC extra.ispc extra.cxx)
+add_library(ispc_objects2 STATIC simple.ispc)
+
+set_target_properties(ispc_objects1 PROPERTIES POSITION_INDEPENDENT_CODE ON)
+set_target_properties(ispc_objects1 PROPERTIES ISPC_INSTRUCTION_SETS "sse2-i32x4;avx1-i32x16;avx2-i32x4")
+
+set_target_properties(ispc_objects2 PROPERTIES POSITION_INDEPENDENT_CODE ON)
+set_target_properties(ispc_objects2 PROPERTIES ISPC_INSTRUCTION_SETS "sse2-i32x4")
+
+target_link_libraries(ispc_objects2 PRIVATE ispc_objects1)
+
+add_executable(ISPCChainedStaticLibraries main.cxx)
+target_link_libraries(ISPCChainedStaticLibraries PUBLIC ispc_objects2)
diff --git a/Tests/ISPC/ChainedStaticLibraries/extra.cxx b/Tests/ISPC/ChainedStaticLibraries/extra.cxx
new file mode 100644
index 0000000..9f50df4
--- /dev/null
+++ b/Tests/ISPC/ChainedStaticLibraries/extra.cxx
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+#include "extra_ispc.h"
+
+int extra()
+{
+ float vin[16], vout[16];
+ for (int i = 0; i < 16; ++i)
+ vin[i] = i;
+
+ ispc::extra(vin, vout, 16);
+
+ for (int i = 0; i < 16; ++i)
+ printf("%d: extra(%f) = %f\n", i, vin[i], vout[i]);
+
+ return 0;
+}
diff --git a/Tests/ISPC/ChainedStaticLibraries/extra.ispc b/Tests/ISPC/ChainedStaticLibraries/extra.ispc
new file mode 100644
index 0000000..5a4a442
--- /dev/null
+++ b/Tests/ISPC/ChainedStaticLibraries/extra.ispc
@@ -0,0 +1,12 @@
+
+export void extra(uniform float vin[], uniform float vout[],
+ uniform int count) {
+ foreach (index = 0 ... count) {
+ float v = vin[index];
+ if (v < 3.)
+ v = v * v;
+ else
+ v = sqrt(v);
+ vout[index] = v;
+ }
+}
diff --git a/Tests/ISPC/ChainedStaticLibraries/main.cxx b/Tests/ISPC/ChainedStaticLibraries/main.cxx
new file mode 100644
index 0000000..a6b91a6
--- /dev/null
+++ b/Tests/ISPC/ChainedStaticLibraries/main.cxx
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+#include "simple_ispc.h"
+
+int main()
+{
+ float vin[16], vout[16];
+ for (int i = 0; i < 16; ++i)
+ vin[i] = i;
+
+ ispc::simple(vin, vout, 16);
+
+ for (int i = 0; i < 16; ++i)
+ printf("%d: simple(%f) = %f\n", i, vin[i], vout[i]);
+}
diff --git a/Tests/ISPC/ChainedStaticLibraries/simple.ispc b/Tests/ISPC/ChainedStaticLibraries/simple.ispc
new file mode 100644
index 0000000..70cb588
--- /dev/null
+++ b/Tests/ISPC/ChainedStaticLibraries/simple.ispc
@@ -0,0 +1,12 @@
+
+export void simple(uniform float vin[], uniform float vout[],
+ uniform int count) {
+ foreach (index = 0 ... count) {
+ float v = vin[index];
+ if (v < 3.)
+ v = v * v;
+ else
+ v = sqrt(v);
+ vout[index] = v;
+ }
+}
diff --git a/Tests/ISPC/CustomHeaderSuffix/CMakeLists.txt b/Tests/ISPC/CustomHeaderSuffix/CMakeLists.txt
new file mode 100644
index 0000000..d20f88e
--- /dev/null
+++ b/Tests/ISPC/CustomHeaderSuffix/CMakeLists.txt
@@ -0,0 +1,23 @@
+
+cmake_minimum_required(VERSION 3.18)
+project(ISPCCustomHeaderSuffix CXX ISPC)
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(CMAKE_ISPC_FLAGS "--arch=x86")
+endif()
+
+set(CMAKE_ISPC_INSTRUCTION_SETS "sse2-i32x4;sse4-i8x16")
+
+set(CMAKE_ISPC_HEADER_SUFFIX ".ispc.h")
+
+add_library(ispc_suffix_1 OBJECT simple.ispc)
+add_library(ispc_suffix_2 OBJECT extra.ispc)
+
+set_target_properties(ispc_suffix_2 PROPERTIES ISPC_HEADER_SUFFIX "___ispc.h")
+
+set_target_properties(ispc_suffix_1 ispc_suffix_2
+ PROPERTIES POSITION_INDEPENDENT_CODE ON
+)
+
+add_executable(ISPCCustomHeaderSuffix main.cxx extra.cxx)
+target_link_libraries(ISPCCustomHeaderSuffix PRIVATE ispc_suffix_1 ispc_suffix_2)
diff --git a/Tests/ISPC/CustomHeaderSuffix/extra.cxx b/Tests/ISPC/CustomHeaderSuffix/extra.cxx
new file mode 100644
index 0000000..0354e2d
--- /dev/null
+++ b/Tests/ISPC/CustomHeaderSuffix/extra.cxx
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+#include "extra___ispc.h"
+
+int extra()
+{
+ float vin[16], vout[16];
+ for (int i = 0; i < 16; ++i)
+ vin[i] = i;
+
+ ispc::extra(vin, vout, 16);
+
+ for (int i = 0; i < 16; ++i)
+ printf("%d: extra(%f) = %f\n", i, vin[i], vout[i]);
+
+ return 0;
+}
diff --git a/Tests/ISPC/CustomHeaderSuffix/extra.ispc b/Tests/ISPC/CustomHeaderSuffix/extra.ispc
new file mode 100644
index 0000000..5a4a442
--- /dev/null
+++ b/Tests/ISPC/CustomHeaderSuffix/extra.ispc
@@ -0,0 +1,12 @@
+
+export void extra(uniform float vin[], uniform float vout[],
+ uniform int count) {
+ foreach (index = 0 ... count) {
+ float v = vin[index];
+ if (v < 3.)
+ v = v * v;
+ else
+ v = sqrt(v);
+ vout[index] = v;
+ }
+}
diff --git a/Tests/ISPC/CustomHeaderSuffix/main.cxx b/Tests/ISPC/CustomHeaderSuffix/main.cxx
new file mode 100644
index 0000000..4f1c9be
--- /dev/null
+++ b/Tests/ISPC/CustomHeaderSuffix/main.cxx
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+#include "simple.ispc.h"
+
+int main()
+{
+ float vin[16], vout[16];
+ for (int i = 0; i < 16; ++i)
+ vin[i] = i;
+
+ ispc::simple(vin, vout, 16);
+
+ for (int i = 0; i < 16; ++i)
+ printf("%d: simple(%f) = %f\n", i, vin[i], vout[i]);
+}
diff --git a/Tests/ISPC/CustomHeaderSuffix/simple.ispc b/Tests/ISPC/CustomHeaderSuffix/simple.ispc
new file mode 100644
index 0000000..70cb588
--- /dev/null
+++ b/Tests/ISPC/CustomHeaderSuffix/simple.ispc
@@ -0,0 +1,12 @@
+
+export void simple(uniform float vin[], uniform float vout[],
+ uniform int count) {
+ foreach (index = 0 ... count) {
+ float v = vin[index];
+ if (v < 3.)
+ v = v * v;
+ else
+ v = sqrt(v);
+ vout[index] = v;
+ }
+}
diff --git a/Tests/ISPC/Defines/CMakeLists.txt b/Tests/ISPC/Defines/CMakeLists.txt
new file mode 100644
index 0000000..7645804
--- /dev/null
+++ b/Tests/ISPC/Defines/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.18)
+project(ISPCDefines CXX ISPC)
+
+set(CMAKE_ISPC_INSTRUCTION_SETS "sse2-i32x4;sse4-i16x8;avx1-i32x16;avx2-i32x4;avx512knl-i32x16;avx512skx-i32x8")
+set(CMAKE_ISPC_FLAGS -DM_PI=3.1415926535f)
+add_compile_definitions([==[STRUCT_DEFINE=struct{uniform int a]==])
+
+add_executable(ISPCDefines
+ main.cxx
+ simple.ispc
+ )
+
+set_target_properties(ISPCDefines PROPERTIES POSITION_INDEPENDENT_CODE ON)
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set_source_files_properties(simple.ispc PROPERTIES COMPILE_OPTIONS "--arch=x86")
+endif()
diff --git a/Tests/ISPC/Defines/main.cxx b/Tests/ISPC/Defines/main.cxx
new file mode 100644
index 0000000..a6b91a6
--- /dev/null
+++ b/Tests/ISPC/Defines/main.cxx
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+#include "simple_ispc.h"
+
+int main()
+{
+ float vin[16], vout[16];
+ for (int i = 0; i < 16; ++i)
+ vin[i] = i;
+
+ ispc::simple(vin, vout, 16);
+
+ for (int i = 0; i < 16; ++i)
+ printf("%d: simple(%f) = %f\n", i, vin[i], vout[i]);
+}
diff --git a/Tests/ISPC/Defines/simple.ispc b/Tests/ISPC/Defines/simple.ispc
new file mode 100644
index 0000000..d8d6465
--- /dev/null
+++ b/Tests/ISPC/Defines/simple.ispc
@@ -0,0 +1,15 @@
+
+//textual error if STRUCT_DEFINE not set
+STRUCT_DEFINE;};
+
+export void simple(uniform float vin[], uniform float vout[],
+ uniform int count) {
+ foreach (index = 0 ... count) {
+ float v = vin[index];
+ if (v < M_PI)
+ v = v * v;
+ else
+ v = sqrt(v);
+ vout[index] = v;
+ }
+}
diff --git a/Tests/ISPC/DynamicLibrary/CMakeLists.txt b/Tests/ISPC/DynamicLibrary/CMakeLists.txt
new file mode 100644
index 0000000..4655090
--- /dev/null
+++ b/Tests/ISPC/DynamicLibrary/CMakeLists.txt
@@ -0,0 +1,22 @@
+
+cmake_minimum_required(VERSION 3.18)
+project(ISPCDynamicLibrary CXX ISPC)
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(CMAKE_ISPC_FLAGS "--arch=x86")
+endif()
+
+
+add_library(ispc_objects1 STATIC extra.ispc extra.cxx)
+add_library(ispc_objects2 SHARED simple.ispc)
+target_sources(ispc_objects2 PRIVATE simple.cxx)
+
+set_target_properties(ispc_objects1 PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+set_target_properties(ispc_objects1 PROPERTIES ISPC_INSTRUCTION_SETS "sse2-i32x4;avx1-i32x16;avx2-i32x4")
+set_target_properties(ispc_objects2 PROPERTIES ISPC_INSTRUCTION_SETS "sse2-i32x4")
+
+target_link_libraries(ispc_objects2 PUBLIC ispc_objects1)
+
+add_executable(ISPCDynamicLibrary main.cxx)
+target_link_libraries(ISPCDynamicLibrary PUBLIC ispc_objects2)
diff --git a/Tests/ISPC/DynamicLibrary/extra.cxx b/Tests/ISPC/DynamicLibrary/extra.cxx
new file mode 100644
index 0000000..a3d89ed
--- /dev/null
+++ b/Tests/ISPC/DynamicLibrary/extra.cxx
@@ -0,0 +1,23 @@
+#include <stdio.h>
+
+#include "extra_ispc.h"
+
+#ifdef _WIN32
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+EXPORT int extra()
+{
+ float vin[16], vout[16];
+ for (int i = 0; i < 16; ++i)
+ vin[i] = i;
+
+ ispc::extra(vin, vout, 16);
+
+ for (int i = 0; i < 16; ++i)
+ printf("%d: extra(%f) = %f\n", i, vin[i], vout[i]);
+
+ return 0;
+}
diff --git a/Tests/ISPC/DynamicLibrary/extra.ispc b/Tests/ISPC/DynamicLibrary/extra.ispc
new file mode 100644
index 0000000..5a4a442
--- /dev/null
+++ b/Tests/ISPC/DynamicLibrary/extra.ispc
@@ -0,0 +1,12 @@
+
+export void extra(uniform float vin[], uniform float vout[],
+ uniform int count) {
+ foreach (index = 0 ... count) {
+ float v = vin[index];
+ if (v < 3.)
+ v = v * v;
+ else
+ v = sqrt(v);
+ vout[index] = v;
+ }
+}
diff --git a/Tests/ISPC/DynamicLibrary/main.cxx b/Tests/ISPC/DynamicLibrary/main.cxx
new file mode 100644
index 0000000..f9072c7
--- /dev/null
+++ b/Tests/ISPC/DynamicLibrary/main.cxx
@@ -0,0 +1,17 @@
+
+
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+#else
+# define IMPORT
+#endif
+
+IMPORT int simple();
+int extra();
+
+int main()
+{
+ extra();
+ simple();
+ return 0;
+}
diff --git a/Tests/ISPC/DynamicLibrary/shim.cxx b/Tests/ISPC/DynamicLibrary/shim.cxx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/ISPC/DynamicLibrary/shim.cxx
diff --git a/Tests/ISPC/DynamicLibrary/simple.cxx b/Tests/ISPC/DynamicLibrary/simple.cxx
new file mode 100644
index 0000000..bc78bda
--- /dev/null
+++ b/Tests/ISPC/DynamicLibrary/simple.cxx
@@ -0,0 +1,23 @@
+#include <stdio.h>
+
+#include "simple_ispc.h"
+
+#ifdef _WIN32
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+EXPORT int simple()
+{
+ float vin[16], vout[16];
+ for (int i = 0; i < 16; ++i)
+ vin[i] = i;
+
+ ispc::simple(vin, vout, 16);
+
+ for (int i = 0; i < 16; ++i)
+ printf("%d: extra(%f) = %f\n", i, vin[i], vout[i]);
+
+ return 0;
+}
diff --git a/Tests/ISPC/DynamicLibrary/simple.ispc b/Tests/ISPC/DynamicLibrary/simple.ispc
new file mode 100644
index 0000000..70cb588
--- /dev/null
+++ b/Tests/ISPC/DynamicLibrary/simple.ispc
@@ -0,0 +1,12 @@
+
+export void simple(uniform float vin[], uniform float vout[],
+ uniform int count) {
+ foreach (index = 0 ... count) {
+ float v = vin[index];
+ if (v < 3.)
+ v = v * v;
+ else
+ v = sqrt(v);
+ vout[index] = v;
+ }
+}
diff --git a/Tests/ISPC/ObjectGenex/CMakeLists.txt b/Tests/ISPC/ObjectGenex/CMakeLists.txt
new file mode 100644
index 0000000..bc0cbf6
--- /dev/null
+++ b/Tests/ISPC/ObjectGenex/CMakeLists.txt
@@ -0,0 +1,45 @@
+cmake_minimum_required(VERSION 3.18)
+project(ISPCObjectGenex CXX ISPC)
+
+set(CMAKE_ISPC_INSTRUCTION_SETS "sse2-i32x4;sse4-i16x8;avx1-i32x16;avx2-i32x4;avx512knl-i32x16;avx512skx-i32x8")
+
+add_library(ispc_objects OBJECT
+ simple.ispc
+ )
+target_compile_definitions(ispc_objects PRIVATE
+ $<$<COMPILE_LANG_AND_ID:ISPC,Intel>:M_PI=3.1415926535f>
+)
+set_target_properties(ispc_objects PROPERTIES POSITION_INDEPENDENT_CODE ON)
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set_source_files_properties(simple.ispc PROPERTIES COMPILE_OPTIONS "--arch=x86")
+endif()
+
+
+#Test ObjectFiles with file(GENERATE)
+file(GENERATE
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/gen_$<LOWER_CASE:$<CONFIG>/>path_to_objs.h
+ CONTENT [[
+#ifndef path_to_objs
+#define path_to_objs
+
+#include <string>
+
+static std::string obj_paths = "$<TARGET_OBJECTS:ispc_objects>";
+
+#endif
+
+]]
+)
+
+
+add_executable(ISPCObjectGenex main.cxx)
+add_dependencies(ISPCObjectGenex ispc_objects)
+
+list(LENGTH CMAKE_ISPC_INSTRUCTION_SETS numberOfTargets)
+math(EXPR numberOfTargets "${numberOfTargets}+1")
+target_compile_definitions(ISPCObjectGenex PRIVATE
+ "ExpectedISPCObjects=${numberOfTargets}"
+ "CONFIG_TYPE=gen_$<LOWER_CASE:$<CONFIG>>"
+ )
+target_include_directories(ISPCObjectGenex PRIVATE ${CMAKE_CURRENT_BINARY_DIR} )
+target_compile_features(ISPCObjectGenex PRIVATE cxx_std_11)
diff --git a/Tests/ISPC/ObjectGenex/main.cxx b/Tests/ISPC/ObjectGenex/main.cxx
new file mode 100644
index 0000000..143e74e
--- /dev/null
+++ b/Tests/ISPC/ObjectGenex/main.cxx
@@ -0,0 +1,87 @@
+#include <stdio.h>
+
+/*
+ Define GENERATED_HEADER macro to allow c++ files to include headers
+ generated based on different configuration types.
+*/
+
+/* clang-format off */
+#define GENERATED_HEADER(x) GENERATED_HEADER0(CONFIG_TYPE/x)
+/* clang-format on */
+#define GENERATED_HEADER0(x) GENERATED_HEADER1(x)
+#define GENERATED_HEADER1(x) <x>
+
+#include GENERATED_HEADER(path_to_objs.h)
+
+#include <vector>
+std::vector<std::string> expandList(std::string const& arg)
+{
+ std::vector<std::string> output;
+ // If argument is empty or no `;` just copy the current string
+ if (arg.empty() || arg.find(';') == std::string::npos) {
+ output.emplace_back(arg);
+ return output;
+ }
+
+ std::string newArg;
+ // Break the string at non-escaped semicolons not nested in [].
+ int squareNesting = 0;
+ auto last = arg.begin();
+ auto const cend = arg.end();
+ for (auto c = last; c != cend; ++c) {
+ switch (*c) {
+ case '\\': {
+ // We only want to allow escaping of semicolons. Other
+ // escapes should not be processed here.
+ auto cnext = c + 1;
+ if ((cnext != cend) && *cnext == ';') {
+ newArg.append(last, c);
+ // Skip over the escape character
+ last = cnext;
+ c = cnext;
+ }
+ } break;
+ case '[': {
+ ++squareNesting;
+ } break;
+ case ']': {
+ --squareNesting;
+ } break;
+ case ';': {
+ // Break the string here if we are not nested inside square
+ // brackets.
+ if (squareNesting == 0) {
+ newArg.append(last, c);
+ // Skip over the semicolon
+ last = c + 1;
+ if (!newArg.empty()) {
+ // Add the last argument if the string is not empty.
+ output.push_back(newArg);
+ newArg.clear();
+ }
+ }
+ } break;
+ default: {
+ // Just append this character.
+ } break;
+ }
+ }
+ newArg.append(last, cend);
+ if (!newArg.empty()) {
+ // Add the last argument if the string is not empty.
+ output.push_back(std::move(newArg));
+ }
+
+ return output;
+}
+
+int main()
+{
+ // determine that the number of object files specified in obj_paths
+ // is equal to the number of arch's
+
+ std::vector<std::string> paths = expandList(obj_paths);
+ const bool correctSize = (paths.size() == ExpectedISPCObjects);
+
+ return (correctSize) ? 0 : 1;
+}
diff --git a/Tests/ISPC/ObjectGenex/simple.ispc b/Tests/ISPC/ObjectGenex/simple.ispc
new file mode 100644
index 0000000..a76b76c
--- /dev/null
+++ b/Tests/ISPC/ObjectGenex/simple.ispc
@@ -0,0 +1,12 @@
+
+export void simple(uniform float vin[], uniform float vout[],
+ uniform int count) {
+ foreach (index = 0 ... count) {
+ float v = vin[index];
+ if (v < M_PI)
+ v = v * v;
+ else
+ v = sqrt(v);
+ vout[index] = v;
+ }
+}
diff --git a/Tests/ISPC/ObjectLibrary/CMakeLists.txt b/Tests/ISPC/ObjectLibrary/CMakeLists.txt
new file mode 100644
index 0000000..a4c81a9
--- /dev/null
+++ b/Tests/ISPC/ObjectLibrary/CMakeLists.txt
@@ -0,0 +1,18 @@
+
+cmake_minimum_required(VERSION 3.18)
+project(ISPCObjectLibrary CXX ISPC)
+
+set(CMAKE_NINJA_FORCE_RESPONSE_FILE ON)
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(CMAKE_ISPC_FLAGS "--arch=x86")
+endif()
+
+
+add_library(ispc_objects OBJECT simple.ispc subdir/extra.ispc)
+
+set_target_properties(ispc_objects PROPERTIES POSITION_INDEPENDENT_CODE ON)
+set_target_properties(ispc_objects PROPERTIES ISPC_INSTRUCTION_SETS "sse2-i32x4;sse4-i8x16")
+
+
+add_executable(ISPCObjectLibrary main.cxx extra.cxx)
+target_link_libraries(ISPCObjectLibrary PRIVATE ispc_objects)
diff --git a/Tests/ISPC/ObjectLibrary/extra.cxx b/Tests/ISPC/ObjectLibrary/extra.cxx
new file mode 100644
index 0000000..9f50df4
--- /dev/null
+++ b/Tests/ISPC/ObjectLibrary/extra.cxx
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+#include "extra_ispc.h"
+
+int extra()
+{
+ float vin[16], vout[16];
+ for (int i = 0; i < 16; ++i)
+ vin[i] = i;
+
+ ispc::extra(vin, vout, 16);
+
+ for (int i = 0; i < 16; ++i)
+ printf("%d: extra(%f) = %f\n", i, vin[i], vout[i]);
+
+ return 0;
+}
diff --git a/Tests/ISPC/ObjectLibrary/main.cxx b/Tests/ISPC/ObjectLibrary/main.cxx
new file mode 100644
index 0000000..a6b91a6
--- /dev/null
+++ b/Tests/ISPC/ObjectLibrary/main.cxx
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+#include "simple_ispc.h"
+
+int main()
+{
+ float vin[16], vout[16];
+ for (int i = 0; i < 16; ++i)
+ vin[i] = i;
+
+ ispc::simple(vin, vout, 16);
+
+ for (int i = 0; i < 16; ++i)
+ printf("%d: simple(%f) = %f\n", i, vin[i], vout[i]);
+}
diff --git a/Tests/ISPC/ObjectLibrary/simple.ispc b/Tests/ISPC/ObjectLibrary/simple.ispc
new file mode 100644
index 0000000..70cb588
--- /dev/null
+++ b/Tests/ISPC/ObjectLibrary/simple.ispc
@@ -0,0 +1,12 @@
+
+export void simple(uniform float vin[], uniform float vout[],
+ uniform int count) {
+ foreach (index = 0 ... count) {
+ float v = vin[index];
+ if (v < 3.)
+ v = v * v;
+ else
+ v = sqrt(v);
+ vout[index] = v;
+ }
+}
diff --git a/Tests/ISPC/ObjectLibrary/subdir/extra.ispc b/Tests/ISPC/ObjectLibrary/subdir/extra.ispc
new file mode 100644
index 0000000..5a4a442
--- /dev/null
+++ b/Tests/ISPC/ObjectLibrary/subdir/extra.ispc
@@ -0,0 +1,12 @@
+
+export void extra(uniform float vin[], uniform float vout[],
+ uniform int count) {
+ foreach (index = 0 ... count) {
+ float v = vin[index];
+ if (v < 3.)
+ v = v * v;
+ else
+ v = sqrt(v);
+ vout[index] = v;
+ }
+}
diff --git a/Tests/ISPC/ResponseAndDefine/CMakeLists.txt b/Tests/ISPC/ResponseAndDefine/CMakeLists.txt
new file mode 100644
index 0000000..7539209
--- /dev/null
+++ b/Tests/ISPC/ResponseAndDefine/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.18)
+project(ispc_spaces_in_path ISPC CXX)
+
+set(CMAKE_NINJA_FORCE_RESPONSE_FILE ON)
+
+# Make sure we can handle an arg file with tricky defines including spaces in -I include
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/path with spaces/simple_include.h"
+"
+ typedef float FLOAT_TYPE;
+"
+)
+
+add_executable(ISPCResponseAndDefine main.cxx simple.ispc)
+set_target_properties(ISPCResponseAndDefine PROPERTIES POSITION_INDEPENDENT_CODE ON)
+target_include_directories(ISPCResponseAndDefine PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
+
+target_compile_options(ISPCResponseAndDefine PRIVATE "$<$<COMPILE_LANGUAGE:ISPC>:--target=sse2-i32x4>")
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ target_compile_options(ISPCResponseAndDefine PRIVATE "$<$<COMPILE_LANGUAGE:ISPC>:--arch=x86>")
+endif()
+
+
+
+target_compile_definitions(ISPCResponseAndDefine PRIVATE
+ "$<$<COMPILE_LANGUAGE:ISPC>:STRUCT_DEFINE=struct{uniform int a>;M_PI=3.14159f")
+target_include_directories(ISPCResponseAndDefine PRIVATE
+ "$<$<COMPILE_LANGUAGE:ISPC>:${CMAKE_CURRENT_BINARY_DIR}/fake path with spaces>"
+ "$<$<COMPILE_LANGUAGE:ISPC>:${CMAKE_CURRENT_BINARY_DIR}/path with spaces>")
diff --git a/Tests/ISPC/ResponseAndDefine/main.cxx b/Tests/ISPC/ResponseAndDefine/main.cxx
new file mode 100644
index 0000000..a6b91a6
--- /dev/null
+++ b/Tests/ISPC/ResponseAndDefine/main.cxx
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+#include "simple_ispc.h"
+
+int main()
+{
+ float vin[16], vout[16];
+ for (int i = 0; i < 16; ++i)
+ vin[i] = i;
+
+ ispc::simple(vin, vout, 16);
+
+ for (int i = 0; i < 16; ++i)
+ printf("%d: simple(%f) = %f\n", i, vin[i], vout[i]);
+}
diff --git a/Tests/ISPC/ResponseAndDefine/simple.ispc b/Tests/ISPC/ResponseAndDefine/simple.ispc
new file mode 100644
index 0000000..81fd7ca
--- /dev/null
+++ b/Tests/ISPC/ResponseAndDefine/simple.ispc
@@ -0,0 +1,16 @@
+
+STRUCT_DEFINE;};
+
+#include "simple_include.h"
+
+export void simple(uniform FLOAT_TYPE vin[], uniform FLOAT_TYPE vout[],
+ uniform int count) {
+ foreach (index = 0 ... count) {
+ FLOAT_TYPE v = vin[index];
+ if (v < M_PI)
+ v = v * v;
+ else
+ v = sqrt(v);
+ vout[index] = v;
+ }
+}
diff --git a/Tests/ISPC/StaticLibrary/CMakeLists.txt b/Tests/ISPC/StaticLibrary/CMakeLists.txt
new file mode 100644
index 0000000..ebe5960
--- /dev/null
+++ b/Tests/ISPC/StaticLibrary/CMakeLists.txt
@@ -0,0 +1,15 @@
+
+cmake_minimum_required(VERSION 3.18)
+project(ISPCStaticLibrary CXX ISPC)
+
+add_library(ispc_objects STATIC simple.ispc)
+
+target_compile_options(ispc_objects PRIVATE "$<$<COMPILE_LANGUAGE:ISPC>:--target=sse2-i32x4>")
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ target_compile_options(ispc_objects PRIVATE "$<$<COMPILE_LANGUAGE:ISPC>:--arch=x86>")
+endif()
+
+set_target_properties(ispc_objects PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+add_executable(ISPCStaticLibrary main.cxx)
+target_link_libraries(ISPCStaticLibrary PRIVATE ispc_objects)
diff --git a/Tests/ISPC/StaticLibrary/main.cxx b/Tests/ISPC/StaticLibrary/main.cxx
new file mode 100644
index 0000000..a6b91a6
--- /dev/null
+++ b/Tests/ISPC/StaticLibrary/main.cxx
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+#include "simple_ispc.h"
+
+int main()
+{
+ float vin[16], vout[16];
+ for (int i = 0; i < 16; ++i)
+ vin[i] = i;
+
+ ispc::simple(vin, vout, 16);
+
+ for (int i = 0; i < 16; ++i)
+ printf("%d: simple(%f) = %f\n", i, vin[i], vout[i]);
+}
diff --git a/Tests/ISPC/StaticLibrary/simple.ispc b/Tests/ISPC/StaticLibrary/simple.ispc
new file mode 100644
index 0000000..70cb588
--- /dev/null
+++ b/Tests/ISPC/StaticLibrary/simple.ispc
@@ -0,0 +1,12 @@
+
+export void simple(uniform float vin[], uniform float vout[],
+ uniform int count) {
+ foreach (index = 0 ... count) {
+ float v = vin[index];
+ if (v < 3.)
+ v = v * v;
+ else
+ v = sqrt(v);
+ vout[index] = v;
+ }
+}
diff --git a/Tests/ISPC/SystemIncludes/CMakeLists.txt b/Tests/ISPC/SystemIncludes/CMakeLists.txt
new file mode 100644
index 0000000..d94e75e
--- /dev/null
+++ b/Tests/ISPC/SystemIncludes/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.18)
+project(ispc_spaces_in_path ISPC CXX)
+
+
+add_executable(ISPCSystemIncludes main.cxx simple.ispc)
+set_target_properties(ISPCSystemIncludes PROPERTIES POSITION_INDEPENDENT_CODE ON)
+set_target_properties(ISPCSystemIncludes PROPERTIES ISPC_HEADER_SUFFIX ".ispc.h")
+target_include_directories(ISPCSystemIncludes SYSTEM PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
+
+
+target_compile_options(ISPCSystemIncludes PRIVATE "$<$<COMPILE_LANGUAGE:ISPC>:--target=sse2-i32x4>")
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ target_compile_options(ISPCSystemIncludes PRIVATE "$<$<COMPILE_LANGUAGE:ISPC>:--arch=x86>")
+endif()
diff --git a/Tests/ISPC/SystemIncludes/main.cxx b/Tests/ISPC/SystemIncludes/main.cxx
new file mode 100644
index 0000000..4f1c9be
--- /dev/null
+++ b/Tests/ISPC/SystemIncludes/main.cxx
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+#include "simple.ispc.h"
+
+int main()
+{
+ float vin[16], vout[16];
+ for (int i = 0; i < 16; ++i)
+ vin[i] = i;
+
+ ispc::simple(vin, vout, 16);
+
+ for (int i = 0; i < 16; ++i)
+ printf("%d: simple(%f) = %f\n", i, vin[i], vout[i]);
+}
diff --git a/Tests/ISPC/SystemIncludes/simple.ispc b/Tests/ISPC/SystemIncludes/simple.ispc
new file mode 100644
index 0000000..d539bbe
--- /dev/null
+++ b/Tests/ISPC/SystemIncludes/simple.ispc
@@ -0,0 +1,9 @@
+
+export void simple(uniform float vin[], uniform float vout[],
+ uniform int count) {
+ foreach (index = 0 ... count) {
+ float v = vin[index];
+ v = sqrt(v);
+ vout[index] = v;
+ }
+}
diff --git a/Tests/ISPC/TryCompile/CMakeLists.txt b/Tests/ISPC/TryCompile/CMakeLists.txt
new file mode 100644
index 0000000..742f511
--- /dev/null
+++ b/Tests/ISPC/TryCompile/CMakeLists.txt
@@ -0,0 +1,16 @@
+
+cmake_minimum_required(VERSION 3.18)
+project(ISPCTryCompile ISPC CXX)
+
+set(CMAKE_NINJA_FORCE_RESPONSE_FILE ON)
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(CMAKE_ISPC_FLAGS "--arch=x86")
+endif()
+
+#Verify we can use try_compile with ISPC
+try_compile(result "${CMAKE_CURRENT_BINARY_DIR}"
+ SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/simple.ispc"
+ COPY_FILE "${CMAKE_CURRENT_BINARY_DIR}/result.o")
+
+add_executable(ISPCTryCompile main.cxx )
+target_link_libraries(ISPCTryCompile "${CMAKE_CURRENT_BINARY_DIR}/result.o")
diff --git a/Tests/ISPC/TryCompile/main.cxx b/Tests/ISPC/TryCompile/main.cxx
new file mode 100644
index 0000000..c8d1ed6
--- /dev/null
+++ b/Tests/ISPC/TryCompile/main.cxx
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+namespace ispc {
+extern "C" {
+void simple(float*, float*, int);
+}
+}
+
+int main()
+{
+ float vin[16], vout[16];
+ for (int i = 0; i < 16; ++i)
+ vin[i] = i;
+
+ ispc::simple(vin, vout, 16);
+
+ for (int i = 0; i < 16; ++i)
+ printf("%d: simple(%f) = %f\n", i, vin[i], vout[i]);
+}
diff --git a/Tests/ISPC/TryCompile/simple.ispc b/Tests/ISPC/TryCompile/simple.ispc
new file mode 100644
index 0000000..70cb588
--- /dev/null
+++ b/Tests/ISPC/TryCompile/simple.ispc
@@ -0,0 +1,12 @@
+
+export void simple(uniform float vin[], uniform float vout[],
+ uniform int count) {
+ foreach (index = 0 ... count) {
+ float v = vin[index];
+ if (v < 3.)
+ v = v * v;
+ else
+ v = sqrt(v);
+ vout[index] = v;
+ }
+}
diff --git a/Tests/ImportedSameName/A/CMakeLists.txt b/Tests/ImportedSameName/A/CMakeLists.txt
new file mode 100644
index 0000000..0a31b40
--- /dev/null
+++ b/Tests/ImportedSameName/A/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_library(a STATIC a.c)
+target_compile_definitions(a INTERFACE DEF_A)
+
+add_library(sameName INTERFACE IMPORTED)
+target_link_libraries(sameName INTERFACE a)
+
+add_library(ifaceA INTERFACE)
+target_link_libraries(ifaceA INTERFACE sameName)
diff --git a/Tests/ImportedSameName/A/a.c b/Tests/ImportedSameName/A/a.c
new file mode 100644
index 0000000..4ef3698
--- /dev/null
+++ b/Tests/ImportedSameName/A/a.c
@@ -0,0 +1,3 @@
+void a(void)
+{
+}
diff --git a/Tests/ImportedSameName/B/CMakeLists.txt b/Tests/ImportedSameName/B/CMakeLists.txt
new file mode 100644
index 0000000..d930326
--- /dev/null
+++ b/Tests/ImportedSameName/B/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_library(b STATIC b.c)
+target_compile_definitions(b INTERFACE DEF_B)
+
+add_library(sameName INTERFACE IMPORTED)
+target_link_libraries(sameName INTERFACE b)
+
+add_library(ifaceB INTERFACE)
+target_link_libraries(ifaceB INTERFACE sameName)
diff --git a/Tests/ImportedSameName/B/b.c b/Tests/ImportedSameName/B/b.c
new file mode 100644
index 0000000..c7c7df4
--- /dev/null
+++ b/Tests/ImportedSameName/B/b.c
@@ -0,0 +1,3 @@
+void b(void)
+{
+}
diff --git a/Tests/ImportedSameName/CMakeLists.txt b/Tests/ImportedSameName/CMakeLists.txt
new file mode 100644
index 0000000..4292c12
--- /dev/null
+++ b/Tests/ImportedSameName/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.12)
+project(ImportedSameName C)
+
+add_subdirectory(A)
+add_subdirectory(B)
+
+add_executable(ImportedSameName main.c)
+target_link_libraries(ImportedSameName PRIVATE ifaceA ifaceB)
diff --git a/Tests/ImportedSameName/main.c b/Tests/ImportedSameName/main.c
new file mode 100644
index 0000000..a0cb27f
--- /dev/null
+++ b/Tests/ImportedSameName/main.c
@@ -0,0 +1,16 @@
+#ifndef DEF_A
+# error "DEF_A not defined"
+#endif
+#ifndef DEF_B
+# error "DEF_B not defined"
+#endif
+
+extern void a(void);
+extern void b(void);
+
+int main(void)
+{
+ a();
+ b();
+ return 0;
+}
diff --git a/Tests/IncludeDirectories/CMP0021/CMakeLists.txt b/Tests/IncludeDirectories/CMP0021/CMakeLists.txt
new file mode 100644
index 0000000..0b9aee8
--- /dev/null
+++ b/Tests/IncludeDirectories/CMP0021/CMakeLists.txt
@@ -0,0 +1,14 @@
+
+cmake_policy(SET CMP0021 OLD)
+add_executable(cmp0021exe main.cpp)
+
+if(NOT CMAKE_CURRENT_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/includes")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E
+ copy_directory
+ "${CMAKE_CURRENT_SOURCE_DIR}/includes"
+ "${CMAKE_CURRENT_BINARY_DIR}/includes"
+ )
+endif()
+set_property(TARGET cmp0021exe PROPERTY
+ INCLUDE_DIRECTORIES includes/cmp0021)
diff --git a/Tests/IncludeDirectories/CMP0021/includes/cmp0021/cmp0021.h b/Tests/IncludeDirectories/CMP0021/includes/cmp0021/cmp0021.h
new file mode 100644
index 0000000..3d49b31
--- /dev/null
+++ b/Tests/IncludeDirectories/CMP0021/includes/cmp0021/cmp0021.h
@@ -0,0 +1,2 @@
+
+#define CMP0021_DEFINE
diff --git a/Tests/IncludeDirectories/CMP0021/main.cpp b/Tests/IncludeDirectories/CMP0021/main.cpp
new file mode 100644
index 0000000..0f87dd9
--- /dev/null
+++ b/Tests/IncludeDirectories/CMP0021/main.cpp
@@ -0,0 +1,11 @@
+
+#include "cmp0021.h"
+
+#ifndef CMP0021_DEFINE
+# error Expected CMP0021_DEFINE
+#endif
+
+int main(int, char**)
+{
+ return 0;
+}
diff --git a/Tests/IncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/CMakeLists.txt
new file mode 100644
index 0000000..d4c19c7
--- /dev/null
+++ b/Tests/IncludeDirectories/CMakeLists.txt
@@ -0,0 +1,137 @@
+cmake_minimum_required (VERSION 2.6)
+project(IncludeDirectories)
+
+if (((CMAKE_C_COMPILER_ID STREQUAL GNU AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.4)
+ OR (CMAKE_C_COMPILER_ID STREQUAL Clang AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") OR CMAKE_C_COMPILER_ID STREQUAL AppleClang)
+ AND (CMAKE_GENERATOR STREQUAL "Unix Makefiles"
+ OR CMAKE_GENERATOR STREQUAL "Ninja"
+ OR (CMAKE_GENERATOR STREQUAL "Xcode" AND NOT XCODE_VERSION VERSION_LESS 6.0)))
+ include(CheckCXXCompilerFlag)
+ check_cxx_compiler_flag(-Wunused-variable run_sys_includes_test)
+ if(run_sys_includes_test)
+ # The Bullseye wrapper appears to break the -isystem effect.
+ execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE out ERROR_VARIABLE out)
+ if("x${out}" MATCHES "Bullseye")
+ set(run_sys_includes_test 0)
+ endif()
+ endif()
+ if (run_sys_includes_test)
+ add_subdirectory(SystemIncludeDirectories)
+ add_subdirectory(SystemIncludeDirectoriesPerLang)
+ endif()
+endif()
+
+file(WRITE ${CMAKE_BINARY_DIR}/Flags/Flags.h
+"//Flags.h
+")
+file(WRITE ${CMAKE_BINARY_DIR}/IncDir/IncDir.h
+"//IncDir.h
+")
+file(WRITE ${CMAKE_BINARY_DIR}/SrcProp/SrcProp.h
+"//SrcProp.h
+")
+file(WRITE ${CMAKE_BINARY_DIR}/TarProp/TarProp.h
+"//TarProp.h
+")
+
+# default to testing with full path
+# some compilers can not handle the escape for directories
+# with spaces in them.
+set(USE_FULLPATH TRUE)
+if(WATCOM OR MSVC60)
+ set(USE_FULLPATH FALSE)
+endif()
+if(USE_FULLPATH)
+ string(APPEND CMAKE_CXX_FLAGS " \"-I${CMAKE_BINARY_DIR}/Flags\"")
+else()
+ string(APPEND CMAKE_CXX_FLAGS " -IFlags")
+endif()
+
+include_directories(${CMAKE_BINARY_DIR}/IncDir)
+if(USE_FULLPATH)
+ set_source_files_properties(main.cpp PROPERTIES COMPILE_FLAGS
+ "\"-I${CMAKE_BINARY_DIR}/SrcProp\"")
+else()
+ set_source_files_properties(main.cpp PROPERTIES COMPILE_FLAGS
+ "-ISrcProp")
+endif()
+
+add_executable(IncludeDirectories main.cpp)
+
+if(USE_FULLPATH)
+ set_target_properties(IncludeDirectories
+ PROPERTIES COMPILE_FLAGS "\"-I${CMAKE_BINARY_DIR}/TarProp\"")
+else()
+ set_target_properties(IncludeDirectories
+ PROPERTIES COMPILE_FLAGS "-ITarProp")
+endif()
+
+# Test escaping of special characters in include directory paths.
+set(special_chars "~@&{}()!'")
+if(NOT CMAKE_GENERATOR MATCHES "(Unix|MinGW|MSYS) Makefiles")
+ # when compiler is used for dependencies, special characters for make are not escaped
+ string(APPEND special_chars "%")
+endif()
+if(NOT CMAKE_GENERATOR STREQUAL "Watcom WMake")
+ # Watcom seems to have no way to encode these characters.
+ string(APPEND special_chars "#=[]")
+endif()
+if(NOT (MINGW AND CMAKE_GENERATOR MATCHES "(Unix|MSYS) Makefiles"))
+ # FIXME: Dependencies work but command-line generation does not handle '$'.
+ string(APPEND special_chars "$")
+endif()
+if(NOT CMAKE_GENERATOR MATCHES "(Borland|NMake) Makefiles")
+ # NMake and Borland seem to have no way to encode a single '^'.
+ string(APPEND special_chars "^")
+endif()
+if(NOT CMAKE_GENERATOR MATCHES "Visual Studio 9 2008|Watcom WMake")
+ # The vcproj format separates values with ','.
+ string(APPEND special_chars ",")
+endif()
+if(NOT WIN32 AND NOT CYGWIN)
+ string(APPEND special_chars "*?<>")
+endif()
+set(special_dir "${CMAKE_CURRENT_BINARY_DIR}/special-${special_chars}-include")
+file(WRITE "${special_dir}/SpecialDir.h" "#define SPECIAL_DIR_H\n")
+target_include_directories(IncludeDirectories PRIVATE "${special_dir}")
+target_compile_definitions(IncludeDirectories PRIVATE INCLUDE_SPECIAL_DIR)
+
+if(MAKE_SUPPORTS_SPACES)
+ set(special_space_dir "${CMAKE_CURRENT_BINARY_DIR}/special-space ${special_chars}-include")
+ file(WRITE "${special_space_dir}/SpecialSpaceDir.h" "#define SPECIAL_SPACE_DIR_H\n")
+ target_include_directories(IncludeDirectories PRIVATE "${special_space_dir}")
+ target_compile_definitions(IncludeDirectories PRIVATE INCLUDE_SPECIAL_SPACE_DIR)
+endif()
+
+add_library(ordertest ordertest.cpp)
+target_include_directories(ordertest SYSTEM PUBLIC SystemIncludeDirectories/systemlib)
+target_include_directories(ordertest PUBLIC SystemIncludeDirectories/userlib)
+
+add_subdirectory(StandardIncludeDirectories)
+add_subdirectory(TargetIncludeDirectories)
+
+set_property(DIRECTORY PROPERTY INCLUDE_DIRECTORIES "${CMAKE_BINARY_DIR}")
+get_property(propContent DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
+if (NOT propContent STREQUAL "${CMAKE_BINARY_DIR}")
+ message(SEND_ERROR "Setting DIRECTORY property failed.")
+endif()
+set_property(DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
+get_property(propContentAfter DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
+if (NOT propContentAfter STREQUAL "")
+ message(SEND_ERROR "Clearing DIRECTORY property failed.")
+endif()
+
+add_library(empty_entry_test SHARED empty.cpp)
+set_target_properties(empty_entry_test PROPERTIES INCLUDE_DIRECTORIES "")
+include_directories(/one/two
+ " "
+ " "
+)
+get_target_property(incs empty_entry_test INCLUDE_DIRECTORIES)
+if (NOT incs STREQUAL ";/one/two")
+ message(SEND_ERROR "Empty include_directories entry was not ignored.")
+endif()
+
+if(NOT CMAKE_GENERATOR STREQUAL "Xcode" AND NOT CMAKE_GENERATOR MATCHES "Ninja")
+ add_subdirectory(CMP0021)
+endif()
diff --git a/Tests/IncludeDirectories/StandardIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/StandardIncludeDirectories/CMakeLists.txt
new file mode 100644
index 0000000..dcbc566
--- /dev/null
+++ b/Tests/IncludeDirectories/StandardIncludeDirectories/CMakeLists.txt
@@ -0,0 +1,5 @@
+# Normally this variable should be set by a platform information module or
+# a toolchain file, but for purposes of this test we simply set it here.
+set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/StdDir)
+
+add_executable(StandardIncludeDirectories main.c)
diff --git a/Tests/IncludeDirectories/StandardIncludeDirectories/StdDir/StdIncDir.h b/Tests/IncludeDirectories/StandardIncludeDirectories/StdDir/StdIncDir.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/IncludeDirectories/StandardIncludeDirectories/StdDir/StdIncDir.h
diff --git a/Tests/IncludeDirectories/StandardIncludeDirectories/main.c b/Tests/IncludeDirectories/StandardIncludeDirectories/main.c
new file mode 100644
index 0000000..edfe9ce
--- /dev/null
+++ b/Tests/IncludeDirectories/StandardIncludeDirectories/main.c
@@ -0,0 +1,5 @@
+#include "StdIncDir.h"
+int main()
+{
+ return 0;
+}
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt
new file mode 100644
index 0000000..dee39c8
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt
@@ -0,0 +1,76 @@
+
+cmake_minimum_required(VERSION 2.8.12)
+
+project(SystemIncludeDirectories)
+
+add_library(systemlib systemlib.cpp)
+target_include_directories(systemlib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/systemlib")
+
+add_library(upstream upstream.cpp)
+target_link_libraries(upstream LINK_PUBLIC systemlib)
+target_compile_options(upstream PRIVATE -Werror=unused-variable)
+
+target_include_directories(upstream SYSTEM PUBLIC
+ $<TARGET_PROPERTY:systemlib,INTERFACE_INCLUDE_DIRECTORIES>
+)
+
+add_library(config_specific INTERFACE)
+if(CMAKE_GENERATOR STREQUAL "Xcode")
+ # CMAKE_BUILD_TYPE does not work here for multi-config generators
+ target_include_directories(config_specific SYSTEM INTERFACE
+ "${CMAKE_CURRENT_SOURCE_DIR}/config_specific"
+ )
+else()
+ set(testConfig ${CMAKE_BUILD_TYPE})
+ target_include_directories(config_specific SYSTEM INTERFACE
+ "$<$<CONFIG:${testConfig}>:${CMAKE_CURRENT_SOURCE_DIR}/config_specific>"
+ )
+endif()
+
+add_library(consumer consumer.cpp)
+target_link_libraries(consumer upstream config_specific)
+target_compile_options(consumer PRIVATE -Werror=unused-variable)
+
+add_library(iface IMPORTED INTERFACE)
+set_property(TARGET iface PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+ "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/systemlib_header_only>"
+ )
+
+add_library(imported_consumer imported_consumer.cpp)
+target_link_libraries(imported_consumer iface)
+target_compile_options(imported_consumer PRIVATE -Werror=unused-variable)
+
+add_library(imported_consumer2 imported_consumer.cpp)
+target_link_libraries(imported_consumer2 imported_consumer)
+target_compile_options(imported_consumer2 PRIVATE -Werror=unused-variable)
+
+# add a target which has a relative system include
+add_library(somelib imported_consumer.cpp)
+target_include_directories(somelib SYSTEM PUBLIC "systemlib_header_only")
+target_compile_options(somelib PRIVATE -Werror=unused-variable)
+
+# add a target which consumes a relative system include
+add_library(otherlib upstream.cpp)
+target_link_libraries(otherlib PUBLIC somelib)
+target_compile_options(somelib PRIVATE -Werror=unused-variable)
+
+macro(do_try_compile error_option)
+ set(TC_ARGS
+ IFACE_TRY_COMPILE_${error_option}
+ "${CMAKE_CURRENT_BINARY_DIR}/try_compile_iface" "${CMAKE_CURRENT_SOURCE_DIR}/imported_consumer.cpp"
+ LINK_LIBRARIES iface
+ )
+ if (${error_option} STREQUAL WITH_ERROR)
+ list(APPEND TC_ARGS COMPILE_DEFINITIONS -Werror=unused-variable)
+ endif()
+ try_compile(${TC_ARGS})
+endmacro()
+
+do_try_compile(NO_ERROR)
+if (NOT IFACE_TRY_COMPILE_NO_ERROR)
+ message(SEND_ERROR "try_compile failed with imported target.")
+endif()
+do_try_compile(WITH_ERROR)
+if (NOT IFACE_TRY_COMPILE_WITH_ERROR)
+ message(SEND_ERROR "try_compile failed with imported target with error option.")
+endif()
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/config_specific/config_iface.h b/Tests/IncludeDirectories/SystemIncludeDirectories/config_specific/config_iface.h
new file mode 100644
index 0000000..02e28b3
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/config_specific/config_iface.h
@@ -0,0 +1,14 @@
+
+#ifndef CONFIG_IFACE_H
+#define CONFIG_IFACE_H
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int configUnusedFunc()
+{
+ int unused;
+ return 0;
+}
+
+#endif
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/consumer.cpp b/Tests/IncludeDirectories/SystemIncludeDirectories/consumer.cpp
new file mode 100644
index 0000000..a13f08f
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/consumer.cpp
@@ -0,0 +1,8 @@
+
+#include "config_iface.h"
+#include "upstream.h"
+
+int consumer()
+{
+ return upstream();
+}
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/imported_consumer.cpp b/Tests/IncludeDirectories/SystemIncludeDirectories/imported_consumer.cpp
new file mode 100644
index 0000000..1dbe819
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/imported_consumer.cpp
@@ -0,0 +1,7 @@
+
+#include "systemlib.h"
+
+int main()
+{
+ return systemlib();
+}
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib.cpp b/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib.cpp
new file mode 100644
index 0000000..5516b62
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib.cpp
@@ -0,0 +1,7 @@
+
+#include "systemlib.h"
+
+int systemlib()
+{
+ return 0;
+}
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib/ordertest.h b/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib/ordertest.h
new file mode 100644
index 0000000..28915e6
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib/ordertest.h
@@ -0,0 +1 @@
+#error ordertest.h includes from systemlib
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib/systemlib.h b/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib/systemlib.h
new file mode 100644
index 0000000..1cb7eed
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib/systemlib.h
@@ -0,0 +1,19 @@
+
+#ifndef SYSTEMLIB_H
+#define SYSTEMLIB_H
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int systemlib();
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int unusedFunc()
+{
+ int unused;
+ return systemlib();
+}
+
+#endif
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib_header_only/systemlib.h b/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib_header_only/systemlib.h
new file mode 100644
index 0000000..93622c4
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib_header_only/systemlib.h
@@ -0,0 +1,16 @@
+
+#ifndef SYSTEMLIB_H
+#define SYSTEMLIB_H
+
+int systemlib()
+{
+ return 0;
+}
+
+int unusedFunc()
+{
+ int unused;
+ return systemlib();
+}
+
+#endif
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.cpp b/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.cpp
new file mode 100644
index 0000000..c569307
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.cpp
@@ -0,0 +1,7 @@
+
+#include "upstream.h"
+
+int upstream()
+{
+ return systemlib();
+}
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.h b/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.h
new file mode 100644
index 0000000..a670c2a
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.h
@@ -0,0 +1,12 @@
+
+#ifndef UPSTREAM_H
+#define UPSTREAM_H
+
+#include "systemlib.h"
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int upstream();
+
+#endif
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/userlib/ordertest.h b/Tests/IncludeDirectories/SystemIncludeDirectories/userlib/ordertest.h
new file mode 100644
index 0000000..fa882cb
--- /dev/null
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/userlib/ordertest.h
@@ -0,0 +1 @@
+/* empty file */
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/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
new file mode 100644
index 0000000..3b994a2
--- /dev/null
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
@@ -0,0 +1,180 @@
+
+cmake_minimum_required(VERSION 2.8.12)
+
+project(TargetIncludeDirectories)
+
+macro(create_header _name)
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${_name}")
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_name}/${_name}.h" "/* ${_name}.h */\n")
+endmacro()
+
+create_header(bar)
+create_header(bat)
+create_header(foo)
+create_header(baz)
+create_header(bang)
+create_header(bing)
+create_header(bung)
+create_header(arguments)
+create_header(list)
+create_header(target1)
+create_header(target2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+include_directories("${CMAKE_CURRENT_BINARY_DIR}/bar")
+include_directories("$<1:${CMAKE_CURRENT_BINARY_DIR}/bang>")
+
+add_executable(TargetIncludeDirectories main.cpp)
+
+set_property(TARGET TargetIncludeDirectories APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/bat")
+set_property(TARGET TargetIncludeDirectories APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/foo")
+set_property(TARGET TargetIncludeDirectories APPEND PROPERTY
+ INCLUDE_DIRECTORIES "$<1:${CMAKE_CURRENT_BINARY_DIR}/bing>")
+
+include_directories("${CMAKE_CURRENT_BINARY_DIR}/baz")
+include_directories("$<1:${CMAKE_CURRENT_BINARY_DIR}/bung>")
+include_directories("sing$<1:/ting>")
+
+include_directories("$<1:${CMAKE_CURRENT_BINARY_DIR}/arguments;${CMAKE_CURRENT_BINARY_DIR}/list>")
+
+create_header(fee)
+create_header(fiy)
+create_header(foh)
+create_header(fum)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib1.cpp" "#include \"fee.h\"\n")
+add_library(lib1 "${CMAKE_CURRENT_BINARY_DIR}/lib1.cpp")
+set_property(TARGET lib1 APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/fee")
+set_property(TARGET lib1 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/fiy")
+set_property(TARGET lib1 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:${CMAKE_CURRENT_BINARY_DIR}/foh>")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib2.cpp" "#include \"fiy.h\"\n")
+add_library(lib2 "${CMAKE_CURRENT_BINARY_DIR}/lib2.cpp")
+set_property(TARGET lib2 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/fum;$<TARGET_PROPERTY:lib1,INTERFACE_INCLUDE_DIRECTORIES>")
+set_property(TARGET lib2 APPEND PROPERTY INCLUDE_DIRECTORIES "$<TARGET_PROPERTY:lib1,INTERFACE_INCLUDE_DIRECTORIES>")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main3.cpp" "#include \"fiy.h\"\n#include \"foh.h\"\n#include \"fum.h\"\nint main(int,char**) { return 0; }\n")
+add_executable(exe3 "${CMAKE_CURRENT_BINARY_DIR}/main3.cpp")
+set_property(TARGET exe3 APPEND PROPERTY INCLUDE_DIRECTORIES "$<TARGET_PROPERTY:lib2,INTERFACE_INCLUDE_DIRECTORIES>")
+
+# Test cycles
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib3.cpp" "#include \"fiy.h\"\n#include \"foh.h\"\n")
+add_library(lib3 "${CMAKE_CURRENT_BINARY_DIR}/lib3.cpp")
+set_property(TARGET lib3 APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/fiy;$<TARGET_PROPERTY:lib4,INTERFACE_INCLUDE_DIRECTORIES>")
+set_property(TARGET lib3 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/fiy;$<TARGET_PROPERTY:lib4,INTERFACE_INCLUDE_DIRECTORIES>")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib4.cpp" "#include \"fiy.h\"\n#include \"foh.h\"\n")
+add_library(lib4 "${CMAKE_CURRENT_BINARY_DIR}/lib4.cpp")
+set_property(TARGET lib4 APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/foh;$<TARGET_PROPERTY:lib3,INTERFACE_INCLUDE_DIRECTORIES>")
+set_property(TARGET lib4 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/foh;$<TARGET_PROPERTY:lib3,INTERFACE_INCLUDE_DIRECTORIES>")
+
+add_library(somelib::withcolons UNKNOWN IMPORTED)
+set_property(TARGET somelib::withcolons PROPERTY IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/target1")
+set_property(TARGET somelib::withcolons PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/target1")
+
+set_property(TARGET TargetIncludeDirectories
+ APPEND PROPERTY INCLUDE_DIRECTORIES
+ "$<TARGET_PROPERTY:somelib::withcolons,INTERFACE_INCLUDE_DIRECTORIES>"
+)
+
+add_library(somelib_aliased UNKNOWN IMPORTED GLOBAL)
+set_property(TARGET somelib_aliased PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/target2")
+add_library(somelib::withcolons2 ALIAS somelib_aliased)
+
+set_property(TARGET TargetIncludeDirectories
+ APPEND PROPERTY INCLUDE_DIRECTORIES
+ "$<TARGET_PROPERTY:somelib::withcolons2,INTERFACE_INCLUDE_DIRECTORIES>"
+)
+
+add_custom_target(test_custom_target
+ "some_bogus_custom_tool"
+ $<TARGET_PROPERTY:TargetIncludeDirectories,COMPILE_DEFINITIONS>
+ WORKING_DIRECTORY
+ "${CMAKE_CURRENT_SOURCE_DIR}")
+
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bad")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/bad/common.h" "#error Should not be included\n")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/good")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/good/common.h" "#include \"othergood.h\"\n")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/othergood")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/othergood/othergood.h" "/* No error */\n")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/libothergood.cpp" "// No content \n")
+add_library(libothergood "${CMAKE_CURRENT_BINARY_DIR}/libothergood.cpp")
+set_property(TARGET libothergood APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/othergood"
+)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/libgood.cpp" "// No content \n")
+add_library(libgood "${CMAKE_CURRENT_BINARY_DIR}/libgood.cpp")
+set_property(TARGET libgood APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES
+ "${CMAKE_CURRENT_BINARY_DIR}/good;$<TARGET_PROPERTY:libothergood,INTERFACE_INCLUDE_DIRECTORIES>"
+)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/libbad.cpp" "// No content \n")
+add_library(libbad "${CMAKE_CURRENT_BINARY_DIR}/libbad.cpp")
+set_property(TARGET libbad APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/bad"
+)
+
+add_library(lib6 SHARED other.cpp)
+add_library(lib7 SHARED other.cpp)
+target_link_libraries(lib7 $<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:lib6>)
+target_include_directories(lib7 PUBLIC $<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:/lib7/include>)
+add_custom_target(head_target_test "some_bogus_custom_tool \"$<TARGET_PROPERTY:lib7,INCLUDE_DIRECTORIES>$<TARGET_PROPERTY:lib7,INTERFACE_INCLUDE_DIRECTORIES>\"")
+
+add_library(includes_source_good empty.cpp)
+target_include_directories(includes_source_good
+ INTERFACE
+ "${CMAKE_CURRENT_BINARY_DIR}/good"
+ "${CMAKE_CURRENT_BINARY_DIR}/othergood/"
+)
+add_library(includes_source_bad empty.cpp)
+target_include_directories(includes_source_bad
+ INTERFACE
+ "${CMAKE_CURRENT_BINARY_DIR}/bad"
+)
+
+add_library(includes_proxy SHARED empty.cpp)
+target_link_libraries(includes_proxy includes_source_good)
+target_link_libraries(includes_proxy LINK_INTERFACE_LIBRARIES includes_source_bad)
+add_executable(copy_includes copy_includes.cpp)
+target_include_directories(copy_includes PRIVATE $<TARGET_PROPERTY:includes_proxy,INCLUDE_DIRECTORIES>)
+
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib5.cpp" "#include \"common.h\"\n")
+add_library(lib5 "${CMAKE_CURRENT_BINARY_DIR}/lib5.cpp")
+
+# Assuming the link order must be:
+target_link_libraries(lib5 libbad libgood)
+
+# Oops!.
+# As include directory order and link order are the same when using target_link_libraries, we have to
+# get the libgood includes in before the libbad includes.
+# We do that with this command:
+target_include_directories(lib5
+ BEFORE PRIVATE $<TARGET_PROPERTY:libgood,INTERFACE_INCLUDE_DIRECTORIES>
+)
+
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/prefix_foo/prefix_bar/prefix_bat")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/prefix_foo/prefix_bar/prefix_bat/prefix_foo_bar_bat.h" "/* prefix_foo_bar_bat.h */\n")
+
+target_include_directories(TargetIncludeDirectories PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/prefix_$<JOIN:foo;bar;bat,/prefix_>")
+
+# Test that the language generator expressions work
+set_property(TARGET TargetIncludeDirectories
+ APPEND PROPERTY INCLUDE_DIRECTORIES
+ "$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,C>:${CMAKE_CURRENT_BINARY_DIR}/bad>"
+ "$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,CXX>:${CMAKE_CURRENT_BINARY_DIR}/good>"
+ "$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,CXX>:${CMAKE_CURRENT_BINARY_DIR}/othergood/>"
+)
+
+add_executable(TargetIncludeDirectories_C main.c)
+set_property(TARGET TargetIncludeDirectories_C
+ APPEND PROPERTY INCLUDE_DIRECTORIES
+ "$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,CXX>:${CMAKE_CURRENT_BINARY_DIR}/bad>"
+ "$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,C>:${CMAKE_CURRENT_BINARY_DIR}/good>"
+ "$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,C>:${CMAKE_CURRENT_BINARY_DIR}/othergood/>"
+)
diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/copy_includes.cpp b/Tests/IncludeDirectories/TargetIncludeDirectories/copy_includes.cpp
new file mode 100644
index 0000000..fed4c03
--- /dev/null
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/copy_includes.cpp
@@ -0,0 +1,7 @@
+
+#include "common.h"
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/empty.cpp b/Tests/IncludeDirectories/TargetIncludeDirectories/empty.cpp
new file mode 100644
index 0000000..8d91e77
--- /dev/null
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty(void)
+{
+ return 0;
+}
diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/main.c b/Tests/IncludeDirectories/TargetIncludeDirectories/main.c
new file mode 100644
index 0000000..a597daa
--- /dev/null
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/main.c
@@ -0,0 +1,7 @@
+
+#include "common.h"
+
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp b/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp
new file mode 100644
index 0000000..541ef92
--- /dev/null
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp
@@ -0,0 +1,20 @@
+
+#include "arguments.h"
+#include "bang.h"
+#include "bar.h"
+#include "bat.h"
+#include "baz.h"
+#include "bing.h"
+#include "bung.h"
+#include "common.h"
+#include "foo.h"
+#include "list.h"
+#include "prefix_foo_bar_bat.h"
+#include "target1.h"
+#include "target2.h"
+#include "ting.h"
+
+int main(int, char**)
+{
+ return 0;
+}
diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/other.cpp b/Tests/IncludeDirectories/TargetIncludeDirectories/other.cpp
new file mode 100644
index 0000000..9f961ac
--- /dev/null
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/other.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int other()
+{
+ return 0;
+}
diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/sing/ting/ting.h b/Tests/IncludeDirectories/TargetIncludeDirectories/sing/ting/ting.h
new file mode 100644
index 0000000..9b816b6
--- /dev/null
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/sing/ting/ting.h
@@ -0,0 +1 @@
+// ting.h
diff --git a/Tests/IncludeDirectories/empty.cpp b/Tests/IncludeDirectories/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/IncludeDirectories/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/IncludeDirectories/main.cpp b/Tests/IncludeDirectories/main.cpp
new file mode 100644
index 0000000..6dc88e2
--- /dev/null
+++ b/Tests/IncludeDirectories/main.cpp
@@ -0,0 +1,23 @@
+#include "Flags.h"
+#include "IncDir.h"
+#include "SrcProp.h"
+#include "TarProp.h"
+
+#ifdef INCLUDE_SPECIAL_DIR
+# include "SpecialDir.h"
+# ifndef SPECIAL_DIR_H
+# error "SPECIAL_DIR_H not defined"
+# endif
+#endif
+
+#ifdef INCLUDE_SPECIAL_SPACE_DIR
+# include "SpecialSpaceDir.h"
+# ifndef SPECIAL_SPACE_DIR_H
+# error "SPECIAL_SPACE_DIR_H not defined"
+# endif
+#endif
+
+int main(int argc, char** argv)
+{
+ return 0;
+}
diff --git a/Tests/IncludeDirectories/ordertest.cpp b/Tests/IncludeDirectories/ordertest.cpp
new file mode 100644
index 0000000..7e24f77
--- /dev/null
+++ b/Tests/IncludeDirectories/ordertest.cpp
@@ -0,0 +1 @@
+#include "ordertest.h"
diff --git a/Tests/IncludeDirectoriesCPATH/CMakeLists.txt b/Tests/IncludeDirectoriesCPATH/CMakeLists.txt
new file mode 100644
index 0000000..31cbc36
--- /dev/null
+++ b/Tests/IncludeDirectoriesCPATH/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required (VERSION 3.14)
+project(IncludeDirectoriesCPATH CXX)
+message(STATUS "ENV{CPATH}: '$ENV{CPATH}'")
+message(STATUS "CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES: '${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}'")
+
+include(CheckCXXCompilerFlag)
+check_cxx_compiler_flag(-Wunused-variable run_sys_includes_test)
+if(run_sys_includes_test)
+ # The Bullseye wrapper appears to break the -isystem effect.
+ execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE out ERROR_VARIABLE out)
+ if("x${out}" MATCHES "Bullseye")
+ set(run_sys_includes_test 0)
+ endif()
+endif()
+if (NOT run_sys_includes_test)
+ return()
+endif()
+
+add_library(consumer consumer.cpp)
+add_library(consumer_system consumer.cpp)
+target_compile_options(consumer_system PRIVATE -Werror=unused-variable)
+target_include_directories(consumer_system SYSTEM PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/viacpath")
diff --git a/Tests/IncludeDirectoriesCPATH/consumer.cpp b/Tests/IncludeDirectoriesCPATH/consumer.cpp
new file mode 100644
index 0000000..59608da
--- /dev/null
+++ b/Tests/IncludeDirectoriesCPATH/consumer.cpp
@@ -0,0 +1,6 @@
+#include "systemlib.h"
+
+int consumer()
+{
+ return systemlib();
+}
diff --git a/Tests/IncludeDirectoriesCPATH/viacpath/systemlib.h b/Tests/IncludeDirectoriesCPATH/viacpath/systemlib.h
new file mode 100644
index 0000000..1aaafa9
--- /dev/null
+++ b/Tests/IncludeDirectoriesCPATH/viacpath/systemlib.h
@@ -0,0 +1,15 @@
+#ifndef SYSTEMLIB_H
+#define SYSTEMLIB_H
+
+int systemlib()
+{
+ return 0;
+}
+
+int unusedFunc()
+{
+ int unused;
+ return systemlib();
+}
+
+#endif
diff --git a/Tests/InterfaceLibrary/CMakeLists.txt b/Tests/InterfaceLibrary/CMakeLists.txt
new file mode 100644
index 0000000..a302c7c
--- /dev/null
+++ b/Tests/InterfaceLibrary/CMakeLists.txt
@@ -0,0 +1,87 @@
+
+cmake_minimum_required(VERSION 2.8.12)
+
+project(InterfaceLibrary)
+
+set(cfg_dir)
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ set(cfg_dir /$<CONFIG>)
+endif()
+
+add_library(iface_nodepends INTERFACE)
+target_compile_definitions(iface_nodepends INTERFACE IFACE_DEFINE)
+
+add_subdirectory(headerdir)
+
+# Add an interface target in a subdirectory that uses an imported interface.
+add_subdirectory(ifacedir)
+
+# Poison an imported interface with the same name as that in the subdir
+# to ensure that the transitive lookup occurs in the subdir.
+add_library(imp::iface INTERFACE IMPORTED)
+set_property(TARGET imp::iface APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL SOMEPROP)
+set_property(TARGET imp::iface PROPERTY INTERFACE_SOMEPROP OFF)
+set_property(TARGET imp::iface PROPERTY INTERFACE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/does_not_exist.cpp)
+
+add_library(objlib OBJECT obj.cpp)
+add_library(iface_objlib INTERFACE)
+target_sources(iface_objlib INTERFACE $<TARGET_OBJECTS:objlib>)
+
+add_library(intermediate INTERFACE)
+target_link_libraries(intermediate INTERFACE iface_objlib)
+
+add_library(item_fake_tgt STATIC item_fake.cpp)
+set_property(TARGET item_fake_tgt PROPERTY OUTPUT_NAME item_fake)
+add_library(item_real STATIC item.cpp)
+add_library(item_iface INTERFACE IMPORTED)
+set_property(TARGET item_iface PROPERTY IMPORTED_LIBNAME item_real)
+add_dependencies(item_iface item_real)
+get_property(item_iface_dependencies TARGET item_iface PROPERTY MANUALLY_ADDED_DEPENDENCIES)
+link_directories(${CMAKE_CURRENT_BINARY_DIR}${cfg_dir})
+
+add_executable(InterfaceLibrary definetestexe.cpp)
+target_link_libraries(InterfaceLibrary
+ iface_nodepends
+ headeriface
+ iface_genheader
+ subiface
+ intermediate
+
+ item_iface
+ item_fake # ensure that 'item_real' is ordered in place of item_iface
+ )
+add_dependencies(InterfaceLibrary item_fake_tgt)
+
+add_subdirectory(libsdir)
+add_subdirectory(excluded EXCLUDE_FROM_ALL)
+
+add_executable(sharedlibtestexe sharedlibtestexe.cpp)
+target_link_libraries(sharedlibtestexe shared_iface imported::iface)
+
+add_library(broken EXCLUDE_FROM_ALL broken.cpp)
+
+add_library(iface_broken INTERFACE)
+# This is not a dependency, so broken will not be built (and the error in
+# it will not be hit)
+target_link_libraries(iface_broken INTERFACE broken)
+
+add_library(iface_whitelist INTERFACE)
+# The target property CUSTOM will never be evaluated on the INTERFACE library.
+target_link_libraries(iface_whitelist INTERFACE $<$<BOOL:$<TARGET_PROPERTY:CUSTOM>>:irrelevant>)
+
+add_executable(exec_whitelist dummy.cpp)
+target_link_libraries(exec_whitelist iface_whitelist)
+
+add_library(iface_imported INTERFACE IMPORTED)
+set_property(TARGET iface_imported PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS
+ $<$<CONFIG:SPECIAL>:SPECIAL_MODE>
+ $<$<CONFIG:Debug>:DEBUG_MODE>
+)
+set_property(TARGET iface_imported PROPERTY
+ MAP_IMPORTED_CONFIG_DEBUG SPECIAL
+)
+
+add_executable(map_config map_config.cpp)
+target_link_libraries(map_config iface_imported)
diff --git a/Tests/InterfaceLibrary/broken.cpp b/Tests/InterfaceLibrary/broken.cpp
new file mode 100644
index 0000000..1fd1041
--- /dev/null
+++ b/Tests/InterfaceLibrary/broken.cpp
@@ -0,0 +1,2 @@
+
+#error Broken
diff --git a/Tests/InterfaceLibrary/definetestexe.cpp b/Tests/InterfaceLibrary/definetestexe.cpp
new file mode 100644
index 0000000..6c53840
--- /dev/null
+++ b/Tests/InterfaceLibrary/definetestexe.cpp
@@ -0,0 +1,31 @@
+
+#ifndef IFACE_DEFINE
+# error Expected IFACE_DEFINE
+#endif
+
+#include "iface_header.h"
+
+#ifndef IFACE_HEADER_SRCDIR
+# error Expected IFACE_HEADER_SRCDIR
+#endif
+
+#include "iface_header_builddir.h"
+
+#ifndef IFACE_HEADER_BUILDDIR
+# error Expected IFACE_HEADER_BUILDDIR
+#endif
+
+#include "iface_genheader.h"
+
+#ifndef IFACE_GENHEADER
+# error Expected IFACE_GENHEADER
+#endif
+
+extern int obj();
+extern int sub();
+extern int item();
+
+int main(int, char**)
+{
+ return obj() + sub() + item();
+}
diff --git a/Tests/InterfaceLibrary/dummy.cpp b/Tests/InterfaceLibrary/dummy.cpp
new file mode 100644
index 0000000..e9ad257
--- /dev/null
+++ b/Tests/InterfaceLibrary/dummy.cpp
@@ -0,0 +1,5 @@
+
+int main(int, char**)
+{
+ return 0;
+}
diff --git a/Tests/InterfaceLibrary/excluded/CMakeLists.txt b/Tests/InterfaceLibrary/excluded/CMakeLists.txt
new file mode 100644
index 0000000..69a6807
--- /dev/null
+++ b/Tests/InterfaceLibrary/excluded/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(excluded_iface INTERFACE)
diff --git a/Tests/InterfaceLibrary/headerdir/CMakeLists.txt b/Tests/InterfaceLibrary/headerdir/CMakeLists.txt
new file mode 100644
index 0000000..ae030d7
--- /dev/null
+++ b/Tests/InterfaceLibrary/headerdir/CMakeLists.txt
@@ -0,0 +1,22 @@
+
+set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
+
+add_library(headeriface INTERFACE)
+
+add_custom_target(headeriface_gen
+ COMMENT "Generating iface_header_builddir.h"
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_SOURCE_DIR}/iface_header_builddir.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/iface_header_builddir.h
+ VERBATIM
+ )
+add_dependencies(headeriface headeriface_gen)
+
+add_custom_command(OUTPUT iface_genheader.h
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_SOURCE_DIR}/iface_genheader.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/iface_genheader.h
+ DEPENDS
+ ${CMAKE_CURRENT_SOURCE_DIR}/iface_genheader.h.in
+ VERBATIM)
+add_library(iface_genheader INTERFACE iface_genheader.h)
diff --git a/Tests/InterfaceLibrary/headerdir/iface_genheader.h.in b/Tests/InterfaceLibrary/headerdir/iface_genheader.h.in
new file mode 100644
index 0000000..0a21b62
--- /dev/null
+++ b/Tests/InterfaceLibrary/headerdir/iface_genheader.h.in
@@ -0,0 +1 @@
+#define IFACE_GENHEADER
diff --git a/Tests/InterfaceLibrary/headerdir/iface_header.h b/Tests/InterfaceLibrary/headerdir/iface_header.h
new file mode 100644
index 0000000..82dd157
--- /dev/null
+++ b/Tests/InterfaceLibrary/headerdir/iface_header.h
@@ -0,0 +1 @@
+#define IFACE_HEADER_SRCDIR
diff --git a/Tests/InterfaceLibrary/headerdir/iface_header_builddir.h.in b/Tests/InterfaceLibrary/headerdir/iface_header_builddir.h.in
new file mode 100644
index 0000000..42dd6df
--- /dev/null
+++ b/Tests/InterfaceLibrary/headerdir/iface_header_builddir.h.in
@@ -0,0 +1 @@
+#define IFACE_HEADER_BUILDDIR
diff --git a/Tests/InterfaceLibrary/ifacedir/CMakeLists.txt b/Tests/InterfaceLibrary/ifacedir/CMakeLists.txt
new file mode 100644
index 0000000..228715e
--- /dev/null
+++ b/Tests/InterfaceLibrary/ifacedir/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_library(imp::iface INTERFACE IMPORTED)
+set_property(TARGET imp::iface APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL SOMEPROP)
+set_property(TARGET imp::iface PROPERTY INTERFACE_SOMEPROP ON)
+set_property(TARGET imp::iface PROPERTY INTERFACE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/sub.cpp)
+
+add_library(subiface INTERFACE)
+target_link_libraries(subiface INTERFACE imp::iface)
+set_property(TARGET subiface PROPERTY INTERFACE_SOMEPROP ON)
diff --git a/Tests/InterfaceLibrary/ifacedir/sub.cpp b/Tests/InterfaceLibrary/ifacedir/sub.cpp
new file mode 100644
index 0000000..cda7e4f
--- /dev/null
+++ b/Tests/InterfaceLibrary/ifacedir/sub.cpp
@@ -0,0 +1,4 @@
+int sub()
+{
+ return 0;
+}
diff --git a/Tests/InterfaceLibrary/item.cpp b/Tests/InterfaceLibrary/item.cpp
new file mode 100644
index 0000000..85cda1b
--- /dev/null
+++ b/Tests/InterfaceLibrary/item.cpp
@@ -0,0 +1,4 @@
+int item()
+{
+ return 0;
+}
diff --git a/Tests/InterfaceLibrary/item_fake.cpp b/Tests/InterfaceLibrary/item_fake.cpp
new file mode 100644
index 0000000..b4bd829
--- /dev/null
+++ b/Tests/InterfaceLibrary/item_fake.cpp
@@ -0,0 +1,5 @@
+extern int item_undefined();
+int item()
+{
+ return item_undefined();
+}
diff --git a/Tests/InterfaceLibrary/libsdir/CMakeLists.txt b/Tests/InterfaceLibrary/libsdir/CMakeLists.txt
new file mode 100644
index 0000000..4e529df
--- /dev/null
+++ b/Tests/InterfaceLibrary/libsdir/CMakeLists.txt
@@ -0,0 +1,28 @@
+
+include(GenerateExportHeader)
+
+add_library(sharedlib SHARED sharedlib.cpp)
+generate_export_header(sharedlib)
+
+add_library(shareddependlib SHARED shareddependlib.cpp)
+generate_export_header(shareddependlib)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
+
+target_link_libraries(sharedlib PUBLIC shareddependlib)
+
+target_include_directories(shareddependlib
+ PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/shareddependlib")
+target_compile_definitions(shareddependlib
+ INTERFACE $<1:SHAREDDEPENDLIB_DEFINE>)
+
+target_include_directories(sharedlib
+ PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/sharedlib")
+target_compile_definitions(shareddependlib
+ INTERFACE $<1:SHAREDLIB_DEFINE>)
+
+add_library(shared_iface INTERFACE)
+target_link_libraries(shared_iface INTERFACE sharedlib)
+
+add_library(imported::iface INTERFACE IMPORTED GLOBAL)
diff --git a/Tests/InterfaceLibrary/libsdir/shareddependlib.cpp b/Tests/InterfaceLibrary/libsdir/shareddependlib.cpp
new file mode 100644
index 0000000..378ba81
--- /dev/null
+++ b/Tests/InterfaceLibrary/libsdir/shareddependlib.cpp
@@ -0,0 +1,7 @@
+
+#include "shareddependlib.h"
+
+int SharedDependLibObject::foo() const
+{
+ return 0;
+}
diff --git a/Tests/InterfaceLibrary/libsdir/shareddependlib/shareddependlib.h b/Tests/InterfaceLibrary/libsdir/shareddependlib/shareddependlib.h
new file mode 100644
index 0000000..ad9b484
--- /dev/null
+++ b/Tests/InterfaceLibrary/libsdir/shareddependlib/shareddependlib.h
@@ -0,0 +1,12 @@
+
+#ifndef SHAREDDEPENDLIB_H
+#define SHAREDDEPENDLIB_H
+
+#include "shareddependlib_export.h"
+
+struct SHAREDDEPENDLIB_EXPORT SharedDependLibObject
+{
+ int foo() const;
+};
+
+#endif
diff --git a/Tests/InterfaceLibrary/libsdir/sharedlib.cpp b/Tests/InterfaceLibrary/libsdir/sharedlib.cpp
new file mode 100644
index 0000000..c49ce90
--- /dev/null
+++ b/Tests/InterfaceLibrary/libsdir/sharedlib.cpp
@@ -0,0 +1,12 @@
+
+#include "sharedlib.h"
+
+SharedDependLibObject SharedLibObject::object() const
+{
+ SharedDependLibObject sdlo;
+ return sdlo;
+}
+int SharedLibObject::foo() const
+{
+ return 0;
+}
diff --git a/Tests/InterfaceLibrary/libsdir/sharedlib/sharedlib.h b/Tests/InterfaceLibrary/libsdir/sharedlib/sharedlib.h
new file mode 100644
index 0000000..3e18941
--- /dev/null
+++ b/Tests/InterfaceLibrary/libsdir/sharedlib/sharedlib.h
@@ -0,0 +1,14 @@
+
+#ifndef SHAREDLIB_H
+#define SHAREDLIB_H
+
+#include "shareddependlib.h"
+#include "sharedlib_export.h"
+
+struct SHAREDLIB_EXPORT SharedLibObject
+{
+ SharedDependLibObject object() const;
+ int foo() const;
+};
+
+#endif
diff --git a/Tests/InterfaceLibrary/map_config.cpp b/Tests/InterfaceLibrary/map_config.cpp
new file mode 100644
index 0000000..d035632
--- /dev/null
+++ b/Tests/InterfaceLibrary/map_config.cpp
@@ -0,0 +1,15 @@
+
+#ifdef DEBUG_MODE
+# ifndef SPECIAL_MODE
+# error Special configuration should be mapped to debug configuration.
+# endif
+#else
+# ifdef SPECIAL_MODE
+# error Special configuration should not be enabled if not debug configuration
+# endif
+#endif
+
+int main(int, char**)
+{
+ return 0;
+}
diff --git a/Tests/InterfaceLibrary/obj.cpp b/Tests/InterfaceLibrary/obj.cpp
new file mode 100644
index 0000000..475800d
--- /dev/null
+++ b/Tests/InterfaceLibrary/obj.cpp
@@ -0,0 +1,4 @@
+int obj()
+{
+ return 0;
+}
diff --git a/Tests/InterfaceLibrary/sharedlibtestexe.cpp b/Tests/InterfaceLibrary/sharedlibtestexe.cpp
new file mode 100644
index 0000000..97b5aa9
--- /dev/null
+++ b/Tests/InterfaceLibrary/sharedlibtestexe.cpp
@@ -0,0 +1,19 @@
+
+#ifndef SHAREDLIB_DEFINE
+# error Expected SHAREDLIB_DEFINE
+#endif
+
+#ifndef SHAREDDEPENDLIB_DEFINE
+# error Expected SHAREDDEPENDLIB_DEFINE
+#endif
+
+#include "shareddependlib.h"
+#include "sharedlib.h"
+
+int main(int, char**)
+{
+ SharedLibObject sl;
+ SharedDependLibObject sdl = sl.object();
+
+ return sdl.foo() + sl.foo();
+}
diff --git a/Tests/InterfaceLinkLibraries/CMakeLists.txt b/Tests/InterfaceLinkLibraries/CMakeLists.txt
new file mode 100644
index 0000000..9e14c44
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/CMakeLists.txt
@@ -0,0 +1,61 @@
+cmake_minimum_required (VERSION 2.8)
+
+cmake_policy(SET CMP0022 NEW)
+
+project(InterfaceLinkLibraries)
+
+add_library(foo_shared SHARED foo_vs6_1.cpp)
+target_compile_definitions(foo_shared INTERFACE FOO_LIBRARY)
+add_library(bar_shared SHARED bar_vs6_1.cpp)
+target_compile_definitions(bar_shared INTERFACE BAR_LIBRARY)
+set_property(TARGET bar_shared APPEND PROPERTY INTERFACE_LINK_LIBRARIES foo_shared)
+add_library(zot_shared SHARED zot_vs6_1.cpp)
+target_compile_definitions(zot_shared INTERFACE ZOT_LIBRARY)
+set_property(TARGET bar_shared APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<LINK_ONLY:zot_shared>)
+
+add_executable(shared_test main_vs6_1.cpp)
+set_property(TARGET shared_test APPEND PROPERTY LINK_LIBRARIES bar_shared)
+
+add_library(foo_static STATIC foo_vs6_2.cpp)
+target_compile_definitions(foo_static INTERFACE FOO_LIBRARY)
+add_library(bar_static STATIC bar_vs6_2.cpp)
+target_compile_definitions(bar_static INTERFACE BAR_LIBRARY)
+set_property(TARGET bar_static APPEND PROPERTY INTERFACE_LINK_LIBRARIES foo_static)
+add_library(zot_static STATIC zot_vs6_2.cpp)
+target_compile_definitions(zot_static INTERFACE ZOT_LIBRARY)
+set_property(TARGET bar_static APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<LINK_ONLY:zot_static>)
+
+add_executable(static_test main_vs6_2.cpp)
+set_property(TARGET static_test APPEND PROPERTY LINK_LIBRARIES bar_static)
+
+add_library(foo_shared_private SHARED foo_vs6_3.cpp)
+target_compile_definitions(foo_shared_private INTERFACE FOO_LIBRARY)
+add_library(bang_shared_private SHARED bang_vs6_1.cpp)
+target_compile_definitions(bang_shared_private INTERFACE BANG_LIBRARY)
+add_library(bar_shared_private SHARED bar_vs6_3.cpp)
+target_compile_definitions(bar_shared_private INTERFACE BAR_LIBRARY)
+target_compile_definitions(bar_shared_private PRIVATE BAR_USE_BANG)
+set_property(TARGET bar_shared_private APPEND PROPERTY LINK_LIBRARIES bang_shared_private)
+set_property(TARGET bar_shared_private APPEND PROPERTY INTERFACE_LINK_LIBRARIES foo_shared_private)
+add_library(zot_shared_private SHARED zot_vs6_3.cpp)
+target_compile_definitions(zot_shared_private INTERFACE ZOT_LIBRARY)
+set_property(TARGET bar_shared_private APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<LINK_ONLY:zot_shared_private>)
+
+add_executable(shared_private_test main_vs6_3.cpp)
+set_property(TARGET shared_private_test APPEND PROPERTY LINK_LIBRARIES bar_shared_private)
+
+add_library(foo_static_private STATIC foo_vs6_4.cpp)
+target_compile_definitions(foo_static_private INTERFACE FOO_LIBRARY)
+add_library(bang_static_private STATIC bang_vs6_2.cpp)
+target_compile_definitions(bang_static_private INTERFACE BANG_LIBRARY)
+add_library(bar_static_private STATIC bar_vs6_4.cpp)
+target_compile_definitions(bar_static_private INTERFACE BAR_LIBRARY)
+target_compile_definitions(bar_static_private PRIVATE BAR_USE_BANG)
+set_property(TARGET bar_static_private APPEND PROPERTY LINK_LIBRARIES bang_static_private)
+set_property(TARGET bar_static_private APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<LINK_ONLY:bang_static_private> foo_static_private)
+add_library(zot_static_private STATIC zot_vs6_4.cpp)
+target_compile_definitions(zot_static_private INTERFACE ZOT_LIBRARY)
+set_property(TARGET bar_static_private APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<LINK_ONLY:zot_static_private>)
+
+add_executable(InterfaceLinkLibraries main_vs6_4.cpp)
+set_property(TARGET InterfaceLinkLibraries APPEND PROPERTY LINK_LIBRARIES bar_static_private)
diff --git a/Tests/InterfaceLinkLibraries/bang.cpp b/Tests/InterfaceLinkLibraries/bang.cpp
new file mode 100644
index 0000000..722af9f
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/bang.cpp
@@ -0,0 +1,15 @@
+
+#ifdef FOO_LIBRARY
+# error Unexpected FOO_LIBRARY
+#endif
+
+#ifdef BAR_LIBRARY
+# error Unexpected BAR_LIBRARY
+#endif
+
+#include "bang.h"
+
+int bang()
+{
+ return 0;
+}
diff --git a/Tests/InterfaceLinkLibraries/bang.h b/Tests/InterfaceLinkLibraries/bang.h
new file mode 100644
index 0000000..908f20c
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/bang.h
@@ -0,0 +1,4 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int bang();
diff --git a/Tests/InterfaceLinkLibraries/bang_vs6_1.cpp b/Tests/InterfaceLinkLibraries/bang_vs6_1.cpp
new file mode 100644
index 0000000..4886861
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/bang_vs6_1.cpp
@@ -0,0 +1 @@
+#include "bang.cpp"
diff --git a/Tests/InterfaceLinkLibraries/bang_vs6_2.cpp b/Tests/InterfaceLinkLibraries/bang_vs6_2.cpp
new file mode 100644
index 0000000..4886861
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/bang_vs6_2.cpp
@@ -0,0 +1 @@
+#include "bang.cpp"
diff --git a/Tests/InterfaceLinkLibraries/bar.cpp b/Tests/InterfaceLinkLibraries/bar.cpp
new file mode 100644
index 0000000..c1d95ab
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/bar.cpp
@@ -0,0 +1,26 @@
+
+#ifdef FOO_LIBRARY
+# error Unexpected FOO_LIBRARY
+#endif
+
+#ifdef BAR_USE_BANG
+# ifndef BANG_LIBRARY
+# error Expected BANG_LIBRARY
+# endif
+# include "bang.h"
+#else
+# ifdef BANG_LIBRARY
+# error Unexpected BANG_LIBRARY
+# endif
+#endif
+
+#include "bar.h"
+
+int bar()
+{
+#ifdef BAR_USE_BANG
+ return bang();
+#else
+ return 0;
+#endif
+}
diff --git a/Tests/InterfaceLinkLibraries/bar.h b/Tests/InterfaceLinkLibraries/bar.h
new file mode 100644
index 0000000..f31a25f
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/bar.h
@@ -0,0 +1,7 @@
+
+#include "foo.h"
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int bar();
diff --git a/Tests/InterfaceLinkLibraries/bar_vs6_1.cpp b/Tests/InterfaceLinkLibraries/bar_vs6_1.cpp
new file mode 100644
index 0000000..58a04c4
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/bar_vs6_1.cpp
@@ -0,0 +1 @@
+#include "bar.cpp"
diff --git a/Tests/InterfaceLinkLibraries/bar_vs6_2.cpp b/Tests/InterfaceLinkLibraries/bar_vs6_2.cpp
new file mode 100644
index 0000000..58a04c4
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/bar_vs6_2.cpp
@@ -0,0 +1 @@
+#include "bar.cpp"
diff --git a/Tests/InterfaceLinkLibraries/bar_vs6_3.cpp b/Tests/InterfaceLinkLibraries/bar_vs6_3.cpp
new file mode 100644
index 0000000..58a04c4
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/bar_vs6_3.cpp
@@ -0,0 +1 @@
+#include "bar.cpp"
diff --git a/Tests/InterfaceLinkLibraries/bar_vs6_4.cpp b/Tests/InterfaceLinkLibraries/bar_vs6_4.cpp
new file mode 100644
index 0000000..58a04c4
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/bar_vs6_4.cpp
@@ -0,0 +1 @@
+#include "bar.cpp"
diff --git a/Tests/InterfaceLinkLibraries/foo.cpp b/Tests/InterfaceLinkLibraries/foo.cpp
new file mode 100644
index 0000000..c1e93e8
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/foo.cpp
@@ -0,0 +1,15 @@
+
+#ifdef BAR_LIBRARY
+# error Unexpected BAR_LIBRARY
+#endif
+
+#ifdef BANG_LIBRARY
+# error Unexpected BANG_LIBRARY
+#endif
+
+#include "foo.h"
+
+int foo()
+{
+ return 0;
+}
diff --git a/Tests/InterfaceLinkLibraries/foo.h b/Tests/InterfaceLinkLibraries/foo.h
new file mode 100644
index 0000000..9b73885
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/foo.h
@@ -0,0 +1,4 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int foo();
diff --git a/Tests/InterfaceLinkLibraries/foo_vs6_1.cpp b/Tests/InterfaceLinkLibraries/foo_vs6_1.cpp
new file mode 100644
index 0000000..d2e5e52
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/foo_vs6_1.cpp
@@ -0,0 +1 @@
+#include "foo.cpp"
diff --git a/Tests/InterfaceLinkLibraries/foo_vs6_2.cpp b/Tests/InterfaceLinkLibraries/foo_vs6_2.cpp
new file mode 100644
index 0000000..d2e5e52
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/foo_vs6_2.cpp
@@ -0,0 +1 @@
+#include "foo.cpp"
diff --git a/Tests/InterfaceLinkLibraries/foo_vs6_3.cpp b/Tests/InterfaceLinkLibraries/foo_vs6_3.cpp
new file mode 100644
index 0000000..d2e5e52
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/foo_vs6_3.cpp
@@ -0,0 +1 @@
+#include "foo.cpp"
diff --git a/Tests/InterfaceLinkLibraries/foo_vs6_4.cpp b/Tests/InterfaceLinkLibraries/foo_vs6_4.cpp
new file mode 100644
index 0000000..d2e5e52
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/foo_vs6_4.cpp
@@ -0,0 +1 @@
+#include "foo.cpp"
diff --git a/Tests/InterfaceLinkLibraries/main.cpp b/Tests/InterfaceLinkLibraries/main.cpp
new file mode 100644
index 0000000..e8298d4
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/main.cpp
@@ -0,0 +1,23 @@
+
+#ifndef FOO_LIBRARY
+# error Expected FOO_LIBRARY
+#endif
+
+#ifndef BAR_LIBRARY
+# error Expected BAR_LIBRARY
+#endif
+
+#ifdef BANG_LIBRARY
+# error Unexpected BANG_LIBRARY
+#endif
+
+#ifdef ZOT_LIBRARY
+# error Unexpected ZOT_LIBRARY
+#endif
+
+#include "zot.h"
+
+int main(void)
+{
+ return foo() + bar() + zot();
+}
diff --git a/Tests/InterfaceLinkLibraries/main_vs6_1.cpp b/Tests/InterfaceLinkLibraries/main_vs6_1.cpp
new file mode 100644
index 0000000..9b10ef2
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/main_vs6_1.cpp
@@ -0,0 +1 @@
+#include "main.cpp"
diff --git a/Tests/InterfaceLinkLibraries/main_vs6_2.cpp b/Tests/InterfaceLinkLibraries/main_vs6_2.cpp
new file mode 100644
index 0000000..9b10ef2
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/main_vs6_2.cpp
@@ -0,0 +1 @@
+#include "main.cpp"
diff --git a/Tests/InterfaceLinkLibraries/main_vs6_3.cpp b/Tests/InterfaceLinkLibraries/main_vs6_3.cpp
new file mode 100644
index 0000000..9b10ef2
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/main_vs6_3.cpp
@@ -0,0 +1 @@
+#include "main.cpp"
diff --git a/Tests/InterfaceLinkLibraries/main_vs6_4.cpp b/Tests/InterfaceLinkLibraries/main_vs6_4.cpp
new file mode 100644
index 0000000..9b10ef2
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/main_vs6_4.cpp
@@ -0,0 +1 @@
+#include "main.cpp"
diff --git a/Tests/InterfaceLinkLibraries/zot.cpp b/Tests/InterfaceLinkLibraries/zot.cpp
new file mode 100644
index 0000000..69462b0
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/zot.cpp
@@ -0,0 +1,6 @@
+#include "zot.h"
+
+int zot()
+{
+ return 0;
+}
diff --git a/Tests/InterfaceLinkLibraries/zot.h b/Tests/InterfaceLinkLibraries/zot.h
new file mode 100644
index 0000000..e80328b
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/zot.h
@@ -0,0 +1,7 @@
+
+#include "bar.h"
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int zot();
diff --git a/Tests/InterfaceLinkLibraries/zot_vs6_1.cpp b/Tests/InterfaceLinkLibraries/zot_vs6_1.cpp
new file mode 100644
index 0000000..c588c5f
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/zot_vs6_1.cpp
@@ -0,0 +1 @@
+#include "zot.cpp"
diff --git a/Tests/InterfaceLinkLibraries/zot_vs6_2.cpp b/Tests/InterfaceLinkLibraries/zot_vs6_2.cpp
new file mode 100644
index 0000000..c588c5f
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/zot_vs6_2.cpp
@@ -0,0 +1 @@
+#include "zot.cpp"
diff --git a/Tests/InterfaceLinkLibraries/zot_vs6_3.cpp b/Tests/InterfaceLinkLibraries/zot_vs6_3.cpp
new file mode 100644
index 0000000..c588c5f
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/zot_vs6_3.cpp
@@ -0,0 +1 @@
+#include "zot.cpp"
diff --git a/Tests/InterfaceLinkLibraries/zot_vs6_4.cpp b/Tests/InterfaceLinkLibraries/zot_vs6_4.cpp
new file mode 100644
index 0000000..c588c5f
--- /dev/null
+++ b/Tests/InterfaceLinkLibraries/zot_vs6_4.cpp
@@ -0,0 +1 @@
+#include "zot.cpp"
diff --git a/Tests/JCTest/CMakeLists.txt b/Tests/JCTest/CMakeLists.txt
new file mode 100644
index 0000000..b120640
--- /dev/null
+++ b/Tests/JCTest/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(TestTime)
+enable_testing()
+add_executable(TestTime TestTime.cxx)
+
+foreach(f 1 2 3 4 5 6 7 8 9 10 11 12 12 14 15 16 17 18 19
+20 21 22 23 24 25 26 27 28 29 30)
+ add_test(TestTime${f} TestTime 50000000)
+endforeach()
diff --git a/Tests/JCTest/TestTime.cxx b/Tests/JCTest/TestTime.cxx
new file mode 100644
index 0000000..b98e1d3
--- /dev/null
+++ b/Tests/JCTest/TestTime.cxx
@@ -0,0 +1,11 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int ac, char** av)
+{
+ float d = 10.0;
+ for (int i = 0; i < atoi(av[1]); i++) {
+ d *= .2;
+ }
+ printf("%f", d);
+}
diff --git a/Tests/JacocoCoverage/Coverage/src/main/java/org/cmake/CoverageTest.java b/Tests/JacocoCoverage/Coverage/src/main/java/org/cmake/CoverageTest.java
new file mode 100644
index 0000000..4fb43c6
--- /dev/null
+++ b/Tests/JacocoCoverage/Coverage/src/main/java/org/cmake/CoverageTest.java
@@ -0,0 +1,52 @@
+package org.cmake.Coverage;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.List;
+import java.awt.*;
+
+public class CoverageTest {
+
+ public static String VarOne = "test1";
+ public static String VarTwo = "test2";
+ private Integer IntOne = 4;
+
+ public static Boolean equalsVarOne(String inString) {
+
+ if(VarOne.equals(inString)){
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ public static boolean equalsVarTwo(String inString){
+
+ if(VarTwo.equals(inString)){
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ private Integer timesIntOne(Integer inVal){
+
+ return inVal * IntOne;
+ }
+
+ public static boolean whileLoop(Integer StopInt){
+
+ Integer i = 0;
+ while(i < StopInt){
+ i=i+1;
+ }
+ if (i.equals(5)){
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+}
diff --git a/Tests/JacocoCoverage/Coverage/target/site/jacoco.xml.in b/Tests/JacocoCoverage/Coverage/target/site/jacoco.xml.in
new file mode 100644
index 0000000..49c3e87
--- /dev/null
+++ b/Tests/JacocoCoverage/Coverage/target/site/jacoco.xml.in
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><!DOCTYPE report PUBLIC "-//JACOCO//DTD Report 1.0//EN" "report.dtd"><report name="Coverage"><sessioninfo id="vagrant-ubuntu-precise-32-f1c264e9" start="1402427058670" dump="1402427059269"/><package name="org/cmake"><class name="org/cmake/Coverage/CoverageTest"><method name="&lt;init&gt;" desc="()V" line="8"><counter type="INSTRUCTION" missed="7" covered="0"/><counter type="LINE" missed="2" covered="0"/><counter type="COMPLEXITY" missed="1" covered="0"/><counter type="METHOD" missed="1" covered="0"/></method><method name="equalsVarOne" desc="(Ljava/lang/String;)Ljava/lang/Boolean;" line="16"><counter type="INSTRUCTION" missed="3" covered="7"/><counter type="BRANCH" missed="1" covered="1"/><counter type="LINE" missed="1" covered="2"/><counter type="COMPLEXITY" missed="1" covered="1"/><counter type="METHOD" missed="0" covered="1"/></method><method name="equalsVarTwo" desc="(Ljava/lang/String;)Z" line="26"><counter type="INSTRUCTION" missed="0" covered="8"/><counter type="BRANCH" missed="0" covered="2"/><counter type="LINE" missed="0" covered="3"/><counter type="COMPLEXITY" missed="0" covered="2"/><counter type="METHOD" missed="0" covered="1"/></method><method name="timesIntOne" desc="(Ljava/lang/Integer;)Ljava/lang/Integer;" line="36"><counter type="INSTRUCTION" missed="8" covered="0"/><counter type="LINE" missed="1" covered="0"/><counter type="COMPLEXITY" missed="1" covered="0"/><counter type="METHOD" missed="1" covered="0"/></method><method name="whileLoop" desc="(Ljava/lang/Integer;)Z" line="41"><counter type="INSTRUCTION" missed="0" covered="24"/><counter type="BRANCH" missed="0" covered="4"/><counter type="LINE" missed="0" covered="6"/><counter type="COMPLEXITY" missed="0" covered="3"/><counter type="METHOD" missed="0" covered="1"/></method><method name="&lt;clinit&gt;" desc="()V" line="10"><counter type="INSTRUCTION" missed="0" covered="5"/><counter type="LINE" missed="0" covered="2"/><counter type="COMPLEXITY" missed="0" covered="1"/><counter type="METHOD" missed="0" covered="1"/></method><counter type="INSTRUCTION" missed="18" covered="44"/><counter type="BRANCH" missed="1" covered="7"/><counter type="LINE" missed="4" covered="13"/><counter type="COMPLEXITY" missed="3" covered="7"/><counter type="METHOD" missed="2" covered="4"/><counter type="CLASS" missed="0" covered="1"/></class><sourcefile name="CoverageTest.java"><line nr="8" mi="2" ci="0" mb="0" cb="0"/><line nr="10" mi="0" ci="2" mb="0" cb="0"/><line nr="11" mi="0" ci="3" mb="0" cb="0"/><line nr="12" mi="5" ci="0" mb="0" cb="0"/><line nr="16" mi="0" ci="4" mb="1" cb="1"/><line nr="17" mi="0" ci="3" mb="0" cb="0"/><line nr="20" mi="3" ci="0" mb="0" cb="0"/><line nr="26" mi="0" ci="4" mb="0" cb="2"/><line nr="27" mi="0" ci="2" mb="0" cb="0"/><line nr="30" mi="0" ci="2" mb="0" cb="0"/><line nr="36" mi="8" ci="0" mb="0" cb="0"/><line nr="41" mi="0" ci="3" mb="0" cb="0"/><line nr="42" mi="0" ci="5" mb="0" cb="2"/><line nr="43" mi="0" ci="7" mb="0" cb="0"/><line nr="45" mi="0" ci="5" mb="0" cb="2"/><line nr="46" mi="0" ci="2" mb="0" cb="0"/><line nr="49" mi="0" ci="2" mb="0" cb="0"/><counter type="INSTRUCTION" missed="18" covered="44"/><counter type="BRANCH" missed="1" covered="7"/><counter type="LINE" missed="4" covered="13"/><counter type="COMPLEXITY" missed="3" covered="7"/><counter type="METHOD" missed="2" covered="4"/><counter type="CLASS" missed="0" covered="1"/></sourcefile><counter type="INSTRUCTION" missed="18" covered="44"/><counter type="BRANCH" missed="1" covered="7"/><counter type="LINE" missed="4" covered="13"/><counter type="COMPLEXITY" missed="3" covered="7"/><counter type="METHOD" missed="2" covered="4"/><counter type="CLASS" missed="0" covered="1"/></package><counter type="INSTRUCTION" missed="18" covered="44"/><counter type="BRANCH" missed="1" covered="7"/><counter type="LINE" missed="4" covered="13"/><counter type="COMPLEXITY" missed="3" covered="7"/><counter type="METHOD" missed="2" covered="4"/><counter type="CLASS" missed="0" covered="1"/></report>
diff --git a/Tests/JacocoCoverage/DartConfiguration.tcl.in b/Tests/JacocoCoverage/DartConfiguration.tcl.in
new file mode 100644
index 0000000..cc10e9c
--- /dev/null
+++ b/Tests/JacocoCoverage/DartConfiguration.tcl.in
@@ -0,0 +1,8 @@
+# This file is configured by CMake automatically as DartConfiguration.tcl
+# If you choose not to use CMake, this file may be hand configured, by
+# filling in the required variables.
+
+
+# Configuration directories and files
+SourceDirectory: ${CMake_BINARY_DIR}/Testing/JacocoCoverage
+BuildDirectory: ${CMake_BINARY_DIR}/Testing/JacocoCoverage
diff --git a/Tests/Java/A.java b/Tests/Java/A.java
new file mode 100644
index 0000000..b7fdb49
--- /dev/null
+++ b/Tests/Java/A.java
@@ -0,0 +1,11 @@
+class A
+{
+ public A()
+ {
+ }
+
+ public void printName()
+ {
+ System.out.println("A");
+ }
+}
diff --git a/Tests/Java/CMakeLists.txt b/Tests/Java/CMakeLists.txt
new file mode 100644
index 0000000..e4f2821
--- /dev/null
+++ b/Tests/Java/CMakeLists.txt
@@ -0,0 +1,25 @@
+project(hello Java)
+
+cmake_minimum_required (VERSION 2.8.12)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+include(CTest)
+
+find_package(Java COMPONENTS Development)
+include (UseJava)
+
+add_jar(hello A.java HelloWorld.java)
+
+# use listing file to specify sources
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/java_fileslist "A.java\nHelloWorld.java\n")
+add_jar(hello2 @${CMAKE_CURRENT_BINARY_DIR}/java_fileslist)
+
+# use listing file to specify sources and specify output directory (issue #17316)
+add_jar(hello3 @${CMAKE_CURRENT_BINARY_DIR}/java_fileslist OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/hello3")
+
+add_test (NAME Java.Jar
+ COMMAND "${Java_JAVA_EXECUTABLE}" -classpath hello.jar HelloWorld)
+add_test (NAME Java.JarSourceList
+ COMMAND "${Java_JAVA_EXECUTABLE}" -classpath hello2.jar HelloWorld)
+add_test (NAME Java.JarSourceListAndOutput
+ COMMAND "${Java_JAVA_EXECUTABLE}" -classpath "${CMAKE_CURRENT_BINARY_DIR}/hello3/hello3.jar" HelloWorld)
diff --git a/Tests/Java/HelloWorld.java b/Tests/Java/HelloWorld.java
new file mode 100644
index 0000000..995ee48
--- /dev/null
+++ b/Tests/Java/HelloWorld.java
@@ -0,0 +1,11 @@
+class HelloWorld
+{
+ public static void main(String args[])
+ {
+ A a;
+ a = new A();
+ a.printName();
+ System.out.println("Hello World!");
+ }
+}
+
diff --git a/Tests/JavaExportImport/BuildExport/CMakeLists.txt b/Tests/JavaExportImport/BuildExport/CMakeLists.txt
new file mode 100644
index 0000000..fa7e501
--- /dev/null
+++ b/Tests/JavaExportImport/BuildExport/CMakeLists.txt
@@ -0,0 +1,13 @@
+project(foo Java)
+
+cmake_minimum_required (VERSION 3.5)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+find_package(Java COMPONENTS Development)
+include(UseJava)
+
+add_jar(${PROJECT_NAME} Foo.java)
+export_jars(
+ TARGETS ${PROJECT_NAME}
+ NAMESPACE foo::
+ FILE JavaBuildExportTestConfig.cmake)
diff --git a/Tests/JavaExportImport/BuildExport/Foo.java b/Tests/JavaExportImport/BuildExport/Foo.java
new file mode 100644
index 0000000..20815ba
--- /dev/null
+++ b/Tests/JavaExportImport/BuildExport/Foo.java
@@ -0,0 +1,11 @@
+class Foo
+{
+ public Foo()
+ {
+ }
+
+ public void printName()
+ {
+ System.out.println("Foo");
+ }
+}
diff --git a/Tests/JavaExportImport/CMakeLists.txt b/Tests/JavaExportImport/CMakeLists.txt
new file mode 100644
index 0000000..7a2d020
--- /dev/null
+++ b/Tests/JavaExportImport/CMakeLists.txt
@@ -0,0 +1,105 @@
+cmake_minimum_required (VERSION 3.9)
+project(JavaExportImport)
+if(NOT DEFINED CMake_TEST_NESTED_MAKE_PROGRAM AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(CMake_TEST_NESTED_MAKE_PROGRAM "${CMAKE_MAKE_PROGRAM}")
+endif()
+
+find_package(Java COMPONENTS Development)
+
+# Wipe out the install tree to make sure the exporter works.
+add_custom_command(
+ OUTPUT ${JavaExportImport_BINARY_DIR}/CleanupProject
+ COMMAND ${CMAKE_COMMAND} -E rm -rf ${JavaExportImport_BINARY_DIR}/Root
+ )
+add_custom_target(CleanupTarget ALL DEPENDS ${JavaExportImport_BINARY_DIR}/CleanupProject)
+set_property(
+ SOURCE ${JavaExportImport_BINARY_DIR}/CleanupProject
+ PROPERTY SYMBOLIC 1
+ )
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ set(NESTED_CONFIG_TYPE -C "${CMAKE_CFG_INTDIR}")
+else()
+ if(CMAKE_BUILD_TYPE)
+ set(NESTED_CONFIG_TYPE -C "${CMAKE_BUILD_TYPE}")
+ else()
+ set(NESTED_CONFIG_TYPE)
+ endif()
+endif()
+
+configure_file(${JavaExportImport_SOURCE_DIR}/InitialCache.cmake.in
+ ${JavaExportImport_BINARY_DIR}/InitialCache.cmake @ONLY)
+
+# Build the build exporter.
+add_custom_command(
+ OUTPUT ${JavaExportImport_BINARY_DIR}/BuildExportProject
+ COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+ --build-and-test
+ ${JavaExportImport_SOURCE_DIR}/BuildExport
+ ${JavaExportImport_BINARY_DIR}/BuildExport
+ --build-noclean
+ --build-project BuildExport
+ --build-generator ${CMAKE_GENERATOR}
+ --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+ --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+ --build-options -C${JavaExportImport_BINARY_DIR}/InitialCache.cmake
+ VERBATIM
+ )
+add_custom_target(BuildExportTarget ALL DEPENDS ${JavaExportImport_BINARY_DIR}/BuildExportProject)
+add_dependencies(BuildExportTarget CleanupTarget)
+set_property(
+ SOURCE ${JavaExportImport_BINARY_DIR}/BuildExportProject
+ PROPERTY SYMBOLIC 1
+ )
+
+# Build and install the install exporter.
+add_custom_command(
+ OUTPUT ${JavaExportImport_BINARY_DIR}/InstallExportProject
+ COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+ --build-and-test
+ ${JavaExportImport_SOURCE_DIR}/InstallExport
+ ${JavaExportImport_BINARY_DIR}/InstallExport
+ --build-noclean
+ --build-project InstallExport
+ --build-target install
+ --build-generator ${CMAKE_GENERATOR}
+ --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+ --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+ --build-options -C${JavaExportImport_BINARY_DIR}/InitialCache.cmake
+ VERBATIM
+ )
+add_custom_target(InstallExportTarget ALL DEPENDS ${JavaExportImport_BINARY_DIR}/InstallExportProject)
+add_dependencies(InstallExportTarget CleanupTarget)
+set_property(
+ SOURCE ${JavaExportImport_BINARY_DIR}/InstallExportProject
+ PROPERTY SYMBOLIC 1
+ )
+
+# Build and install the importer.
+add_custom_command(
+ OUTPUT ${JavaExportImport_BINARY_DIR}/ImportProject
+ COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+ --build-and-test
+ ${JavaExportImport_SOURCE_DIR}/Import
+ ${JavaExportImport_BINARY_DIR}/Import
+ --build-noclean
+ --build-project Import
+ --build-generator ${CMAKE_GENERATOR}
+ --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+ --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+ --build-options
+ -C${JavaExportImport_BINARY_DIR}/InitialCache.cmake
+ -DJavaBuildExportTest_DIR:PATH=${JavaExportImport_BINARY_DIR}/BuildExport
+ -DJavaInstallExportTest_DIR:PATH=${JavaExportImport_BINARY_DIR}/Root/share/cmake
+ VERBATIM
+ )
+add_custom_target(ImportTarget ALL DEPENDS ${JavaExportImport_BINARY_DIR}/ImportProject)
+add_dependencies(ImportTarget BuildExportTarget InstallExportTarget)
+set_property(
+ SOURCE ${JavaExportImport_BINARY_DIR}/ImportProject
+ PROPERTY SYMBOLIC 1
+ )
+
+add_executable(JavaExportImport main.c)
+add_dependencies(JavaExportImport ImportTarget)
diff --git a/Tests/JavaExportImport/Import/CMakeLists.txt b/Tests/JavaExportImport/Import/CMakeLists.txt
new file mode 100644
index 0000000..13ec05d
--- /dev/null
+++ b/Tests/JavaExportImport/Import/CMakeLists.txt
@@ -0,0 +1,14 @@
+project(import Java)
+
+cmake_minimum_required (VERSION 3.5)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+find_package(Java COMPONENTS Development)
+include(UseJava)
+
+find_package(JavaBuildExportTest REQUIRED)
+find_package(JavaInstallExportTest REQUIRED)
+
+add_jar(${PROJECT_NAME}
+ SOURCES Import.java
+ INCLUDE_JARS foo::foo bar::bar)
diff --git a/Tests/JavaExportImport/Import/Import.java b/Tests/JavaExportImport/Import/Import.java
new file mode 100644
index 0000000..08eb03f
--- /dev/null
+++ b/Tests/JavaExportImport/Import/Import.java
@@ -0,0 +1,10 @@
+class Import
+{
+ public static void main(String args[])
+ {
+ Foo foo = new Foo();
+ Bar bar = new Bar();
+ foo.printName();
+ bar.printName();
+ }
+}
diff --git a/Tests/JavaExportImport/InitialCache.cmake.in b/Tests/JavaExportImport/InitialCache.cmake.in
new file mode 100644
index 0000000..d15e6d1
--- /dev/null
+++ b/Tests/JavaExportImport/InitialCache.cmake.in
@@ -0,0 +1,5 @@
+set(CMAKE_MAKE_PROGRAM "@CMake_TEST_NESTED_MAKE_PROGRAM@" CACHE FILEPATH "Make Program")
+set(Java_JAVA_EXECUTABLE "@Java_JAVA_EXECUTABLE@" CACHE STRING "Java Interpreter")
+set(Java_JAVAC_EXECUTABLE "@Java_JAVAC_EXECUTABLE@" CACHE STRING "Java Compiler")
+set(Java_JAR_EXECUTABLE "@Java_JAR_EXECUTABLE@" CACHE STRING "Java Archive Tool")
+set(CMAKE_INSTALL_PREFIX "@JavaExportImport_BINARY_DIR@/Root" CACHE STRING "Installation Prefix")
diff --git a/Tests/JavaExportImport/InstallExport/Bar.java b/Tests/JavaExportImport/InstallExport/Bar.java
new file mode 100644
index 0000000..a1068a8
--- /dev/null
+++ b/Tests/JavaExportImport/InstallExport/Bar.java
@@ -0,0 +1,11 @@
+class Bar
+{
+ public Bar()
+ {
+ }
+
+ public void printName()
+ {
+ System.out.println("Bar");
+ }
+}
diff --git a/Tests/JavaExportImport/InstallExport/CMakeLists.txt b/Tests/JavaExportImport/InstallExport/CMakeLists.txt
new file mode 100644
index 0000000..2923beb
--- /dev/null
+++ b/Tests/JavaExportImport/InstallExport/CMakeLists.txt
@@ -0,0 +1,15 @@
+project(bar Java)
+
+cmake_minimum_required (VERSION 3.5)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+find_package(Java COMPONENTS Development)
+include(UseJava)
+
+add_jar(${PROJECT_NAME} Bar.java)
+install_jar(${PROJECT_NAME} DESTINATION share/java)
+install_jar_exports(
+ TARGETS ${PROJECT_NAME}
+ NAMESPACE bar::
+ FILE JavaInstallExportTestConfig.cmake
+ DESTINATION share/cmake)
diff --git a/Tests/JavaExportImport/main.c b/Tests/JavaExportImport/main.c
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/JavaExportImport/main.c
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/JavaJavah/B.cpp b/Tests/JavaJavah/B.cpp
new file mode 100644
index 0000000..86d8aa8
--- /dev/null
+++ b/Tests/JavaJavah/B.cpp
@@ -0,0 +1,10 @@
+
+#include "B.h"
+
+#include <jni.h>
+#include <stdio.h>
+
+JNIEXPORT void JNICALL Java_B_printName(JNIEnv*, jobject)
+{
+ printf("B\n");
+}
diff --git a/Tests/JavaJavah/B.java b/Tests/JavaJavah/B.java
new file mode 100644
index 0000000..d731f39
--- /dev/null
+++ b/Tests/JavaJavah/B.java
@@ -0,0 +1,19 @@
+class B
+{
+ public B()
+ {
+ }
+
+ public native void printName();
+
+ static {
+ try {
+
+ System.loadLibrary("B");
+
+ } catch (UnsatisfiedLinkError e) {
+ System.err.println("Native code library failed to load.\n" + e);
+ System.exit(1);
+ }
+ }
+}
diff --git a/Tests/JavaJavah/C.cpp b/Tests/JavaJavah/C.cpp
new file mode 100644
index 0000000..569eab5
--- /dev/null
+++ b/Tests/JavaJavah/C.cpp
@@ -0,0 +1,10 @@
+
+#include "C.h"
+
+#include <jni.h>
+#include <stdio.h>
+
+JNIEXPORT void JNICALL Java_C_printName(JNIEnv*, jobject)
+{
+ printf("C\n");
+}
diff --git a/Tests/JavaJavah/C.java b/Tests/JavaJavah/C.java
new file mode 100644
index 0000000..54b1be2
--- /dev/null
+++ b/Tests/JavaJavah/C.java
@@ -0,0 +1,19 @@
+class C
+{
+ public C()
+ {
+ }
+
+ public native void printName();
+
+ static {
+ try {
+
+ System.loadLibrary("B");
+
+ } catch (UnsatisfiedLinkError e) {
+ System.err.println("Native code library failed to load.\n" + e);
+ System.exit(1);
+ }
+ }
+}
diff --git a/Tests/JavaJavah/CMakeLists.txt b/Tests/JavaJavah/CMakeLists.txt
new file mode 100644
index 0000000..b56cc21
--- /dev/null
+++ b/Tests/JavaJavah/CMakeLists.txt
@@ -0,0 +1,28 @@
+project(helloJavah Java CXX)
+
+cmake_minimum_required (VERSION 2.8.12)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+include(CTest)
+
+find_package(Java COMPONENTS Development)
+include (UseJava)
+
+# JNI support
+find_package(JNI)
+
+add_jar(B1 B.java)
+add_jar(C1 C.java)
+create_javah(TARGET B_javah CLASSES B C CLASSPATH B1 C1)
+
+add_jar(hello3 HelloWorld2.java)
+
+add_library(B SHARED B.cpp C.cpp)
+add_dependencies(B B_javah)
+
+target_include_directories(B PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
+ ${JAVA_INCLUDE_PATH}
+ ${JAVA_INCLUDE_PATH2})
+
+add_test (NAME Java.Javah
+ COMMAND "${Java_JAVA_EXECUTABLE}" -Djava.library.path=$<TARGET_FILE_DIR:B> -classpath hello3.jar HelloWorld2)
diff --git a/Tests/JavaJavah/HelloWorld2.java b/Tests/JavaJavah/HelloWorld2.java
new file mode 100644
index 0000000..5ff710f
--- /dev/null
+++ b/Tests/JavaJavah/HelloWorld2.java
@@ -0,0 +1,15 @@
+class HelloWorld2
+{
+ public static void main(String args[])
+ {
+ B b;
+ b = new B();
+ b.printName();
+
+ C c;
+ c = new C();
+ c.printName();
+
+ System.out.println("Hello World!");
+ }
+}
diff --git a/Tests/JavaNativeHeaders/CMakeLists.txt b/Tests/JavaNativeHeaders/CMakeLists.txt
new file mode 100644
index 0000000..2471e01
--- /dev/null
+++ b/Tests/JavaNativeHeaders/CMakeLists.txt
@@ -0,0 +1,31 @@
+project(helloJavaNativeHeaders Java CXX)
+
+cmake_minimum_required (VERSION 2.8.12)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+include (CTest)
+
+find_package(Java COMPONENTS Development)
+include (UseJava)
+
+# JNI support
+find_package(JNI)
+
+add_jar(B1 D.java GENERATE_NATIVE_HEADERS D1-native DESTINATION INSTALL include)
+add_jar(E1 E.java GENERATE_NATIVE_HEADERS E1-native)
+
+add_jar(hello4 HelloWorld3.java)
+
+add_library(D SHARED D.cpp E.cpp)
+target_link_libraries (D PRIVATE D1-native E1-native)
+
+install(TARGETS D1-native EXPORT native)
+install(DIRECTORY "$<TARGET_PROPERTY:D1-native,NATIVE_HEADERS_DIRECTORY>/" DESTINATION include)
+install(EXPORT native DESTINATION "${CMAKE_INSTALL_PREFIX}" NAMESPACE D1::)
+
+
+add_test (NAME Java.NativeHeaders
+ COMMAND "${Java_JAVA_EXECUTABLE}" -Djava.library.path=$<TARGET_FILE_DIR:D> -classpath hello4.jar HelloWorld3)
+
+add_test (NAME Java.ImportNativeHeaders
+ COMMAND "${CMAKE_COMMAND}" "-DNATIVE_HEADERS_IMPORT_DIR=${CMAKE_INSTALL_PREFIX}" -S "${CMAKE_CURRENT_SOURCE_DIR}/Import" -B "${CMAKE_CURRENT_BINARY_DIR}/Import")
diff --git a/Tests/JavaNativeHeaders/D.cpp b/Tests/JavaNativeHeaders/D.cpp
new file mode 100644
index 0000000..018386c
--- /dev/null
+++ b/Tests/JavaNativeHeaders/D.cpp
@@ -0,0 +1,10 @@
+
+#include "D.h"
+
+#include <jni.h>
+#include <stdio.h>
+
+JNIEXPORT void JNICALL Java_D_printName(JNIEnv*, jobject)
+{
+ printf("D\n");
+}
diff --git a/Tests/JavaNativeHeaders/D.java b/Tests/JavaNativeHeaders/D.java
new file mode 100644
index 0000000..449c0df
--- /dev/null
+++ b/Tests/JavaNativeHeaders/D.java
@@ -0,0 +1,19 @@
+class D
+{
+ public D()
+ {
+ }
+
+ public native void printName();
+
+ static {
+ try {
+
+ System.loadLibrary("D");
+
+ } catch (UnsatisfiedLinkError e) {
+ System.err.println("Native code library failed to load.\n" + e);
+ System.exit(1);
+ }
+ }
+}
diff --git a/Tests/JavaNativeHeaders/E.cpp b/Tests/JavaNativeHeaders/E.cpp
new file mode 100644
index 0000000..3a8e0ac
--- /dev/null
+++ b/Tests/JavaNativeHeaders/E.cpp
@@ -0,0 +1,10 @@
+
+#include "E.h"
+
+#include <jni.h>
+#include <stdio.h>
+
+JNIEXPORT void JNICALL Java_E_printName(JNIEnv*, jobject)
+{
+ printf("E\n");
+}
diff --git a/Tests/JavaNativeHeaders/E.java b/Tests/JavaNativeHeaders/E.java
new file mode 100644
index 0000000..30fd95a
--- /dev/null
+++ b/Tests/JavaNativeHeaders/E.java
@@ -0,0 +1,19 @@
+class E
+{
+ public E()
+ {
+ }
+
+ public native void printName();
+
+ static {
+ try {
+
+ System.loadLibrary("D");
+
+ } catch (UnsatisfiedLinkError e) {
+ System.err.println("Native code library failed to load.\n" + e);
+ System.exit(1);
+ }
+ }
+}
diff --git a/Tests/JavaNativeHeaders/HelloWorld3.java b/Tests/JavaNativeHeaders/HelloWorld3.java
new file mode 100644
index 0000000..77f1fed
--- /dev/null
+++ b/Tests/JavaNativeHeaders/HelloWorld3.java
@@ -0,0 +1,15 @@
+class HelloWorld3
+{
+ public static void main(String args[])
+ {
+ D d;
+ d = new D();
+ d.printName();
+
+ E e;
+ e = new E();
+ e.printName();
+
+ System.out.println("Hello World!");
+ }
+}
diff --git a/Tests/JavaNativeHeaders/Import/CMakeLists.txt b/Tests/JavaNativeHeaders/Import/CMakeLists.txt
new file mode 100644
index 0000000..5486da9
--- /dev/null
+++ b/Tests/JavaNativeHeaders/Import/CMakeLists.txt
@@ -0,0 +1,19 @@
+project(ImportJavaNativeHeaders LANGUAGES NONE)
+
+cmake_minimum_required (VERSION 3.19...3.20)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+include(${NATIVE_HEADERS_IMPORT_DIR}/native.cmake)
+
+if(NOT TARGET D1::D1-native)
+ message(FATAL_ERROR "Target 'D1::D1-native' not found.")
+endif()
+
+get_property(incs TARGET D1::D1-native PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
+if (NOT incs MATCHES "${NATIVE_HEADERS_IMPORT_DIR}/include")
+ message(FATAL_ERROR "Target 'D1::D1-native', property 'INTERFACE_INCLUDE_DIRECTORIES' badly defined: ${incs}.")
+endif()
+
+if (NOT EXISTS "${NATIVE_HEADERS_IMPORT_DIR}/include/D.h")
+ message(FATAL_ERROR "file '${NATIVE_HEADERS_IMPORT_DIR}/include/D.h' not found.")
+endif()
diff --git a/Tests/JavascriptCoverage/DartConfiguration.tcl.in b/Tests/JavascriptCoverage/DartConfiguration.tcl.in
new file mode 100644
index 0000000..f94d988
--- /dev/null
+++ b/Tests/JavascriptCoverage/DartConfiguration.tcl.in
@@ -0,0 +1,8 @@
+# This file is configured by CMake automatically as DartConfiguration.tcl
+# If you choose not to use CMake, this file may be hand configured, by
+# filling in the required variables.
+
+
+# Configuration directories and files
+SourceDirectory: ${CMake_BINARY_DIR}/Testing/JavascriptCoverage
+BuildDirectory: ${CMake_BINARY_DIR}/Testing/JavascriptCoverage
diff --git a/Tests/JavascriptCoverage/output.json.in b/Tests/JavascriptCoverage/output.json.in
new file mode 100644
index 0000000..717cffe
--- /dev/null
+++ b/Tests/JavascriptCoverage/output.json.in
@@ -0,0 +1,448 @@
+{
+ "instrumentation": "node-jscoverage",
+ "sloc": 29,
+ "hits": 28,
+ "misses": 1,
+ "coverage": 96.55172413793103,
+ "files": [
+ {
+ "filename": "${CMake_BINARY_DIR}/Testing/JavascriptCoverage/test.js",
+ "coverage": 96.55172413793103,
+ "hits": 28,
+ "misses": 1,
+ "sloc": 29,
+ "source": {
+ "1": {
+ "source": "var assert = require(\"assert\")",
+ "coverage": 1
+ },
+ "2": {
+ "source": "var test = {",
+ "coverage": 1
+ },
+ "3": {
+ "source": " version: \"1.0.0\"",
+ "coverage": ""
+ },
+ "4": {
+ "source": "}",
+ "coverage": ""
+ },
+ "5": {
+ "source": "function covTest(p1,p2) {",
+ "coverage": 1
+ },
+ "6": {
+ "source": " if (p1 > 3) {",
+ "coverage": 2
+ },
+ "7": {
+ "source": " return 1;",
+ "coverage": 1
+ },
+ "8": {
+ "source": " }",
+ "coverage": ""
+ },
+ "9": {
+ "source": " else {",
+ "coverage": ""
+ },
+ "10": {
+ "source": " return p1 + p2;",
+ "coverage": 1
+ },
+ "11": {
+ "source": " }",
+ "coverage": ""
+ },
+ "12": {
+ "source": "}",
+ "coverage": ""
+ },
+ "13": {
+ "source": "",
+ "coverage": ""
+ },
+ "14": {
+ "source": "function covTest2(p1,p2) {",
+ "coverage": 1
+ },
+ "15": {
+ "source": " return 0;",
+ "coverage": 0
+ },
+ "16": {
+ "source": "}",
+ "coverage": ""
+ },
+ "17": {
+ "source": "",
+ "coverage": ""
+ },
+ "18": {
+ "source": "function covTest3(p1) {",
+ "coverage": 1
+ },
+ "19": {
+ "source": " for(i=0;i < p1;i++){",
+ "coverage": 1
+ },
+ "20": {
+ "source": " }",
+ "coverage": ""
+ },
+ "21": {
+ "source": " return i;",
+ "coverage": 1
+ },
+ "22": {
+ "source": "}",
+ "coverage": ""
+ },
+ "23": {
+ "source": "function covTest4(p1) {",
+ "coverage": 1
+ },
+ "24": {
+ "source": " i=0;",
+ "coverage": 1
+ },
+ "25": {
+ "source": " while(i < p1){",
+ "coverage": 1
+ },
+ "26": {
+ "source": " i++;",
+ "coverage": 5
+ },
+ "27": {
+ "source": " }",
+ "coverage": ""
+ },
+ "28": {
+ "source": " return i;",
+ "coverage": 1
+ },
+ "29": {
+ "source": "}",
+ "coverage": ""
+ },
+ "30": {
+ "source": "",
+ "coverage": ""
+ },
+ "31": {
+ "source": "describe('Array', function(){",
+ "coverage": 1
+ },
+ "32": {
+ "source": " describe('CovTest', function(){",
+ "coverage": 1
+ },
+ "33": {
+ "source": " it('should return when the value is not present', function(){",
+ "coverage": 1
+ },
+ "34": {
+ "source": " assert.equal(4,covTest(2,2));",
+ "coverage": 1
+ },
+ "35": {
+ "source": " })",
+ "coverage": ""
+ },
+ "36": {
+ "source": " })",
+ "coverage": ""
+ },
+ "37": {
+ "source": " ",
+ "coverage": ""
+ },
+ "38": {
+ "source": " describe('CovTest>3', function(){",
+ "coverage": 1
+ },
+ "39": {
+ "source": " it('should return when the value is not present', function(){",
+ "coverage": 1
+ },
+ "40": {
+ "source": " assert.equal(1,covTest(4,2));",
+ "coverage": 1
+ },
+ "41": {
+ "source": " })",
+ "coverage": ""
+ },
+ "42": {
+ "source": " })",
+ "coverage": ""
+ },
+ "43": {
+ "source": " describe('covTest4', function(){",
+ "coverage": 1
+ },
+ "44": {
+ "source": " it('should return when the value is not present', function(){",
+ "coverage": 1
+ },
+ "45": {
+ "source": " assert.equal(5,covTest4(5));",
+ "coverage": 1
+ },
+ "46": {
+ "source": " })",
+ "coverage": ""
+ },
+ "47": {
+ "source": " })",
+ "coverage": ""
+ },
+ "48": {
+ "source": " describe('covTest3', function(){",
+ "coverage": 1
+ },
+ "49": {
+ "source": " it('should return when the value is not present', function(){",
+ "coverage": 1
+ },
+ "50": {
+ "source": " assert.equal(5,covTest3(5));",
+ "coverage": 1
+ },
+ "51": {
+ "source": " })",
+ "coverage": ""
+ },
+ "52": {
+ "source": " })",
+ "coverage": ""
+ },
+ "53": {
+ "source": "})",
+ "coverage": ""
+ },
+ "54": {
+ "source": "",
+ "coverage": ""
+ }
+ }
+ "filename": "${CMake_BINARY_DIR}/Testing/JavascriptCoverage/test3.js",
+ "coverage": 55.00000000000001,
+ "hits": 11,
+ "misses": 9,
+ "sloc": 20,
+ "source": {
+ "1": {
+ "source": "var assert = require(\"assert\")",
+ "coverage": 1
+ },
+ "2": {
+ "source": "var test = {",
+ "coverage": 1
+ },
+ "3": {
+ "source": " version: \"1.0.0\"",
+ "coverage": ""
+ },
+ "4": {
+ "source": "}",
+ "coverage": ""
+ },
+ "5": {
+ "source": "function covTest(p1,p2) {",
+ "coverage": 1
+ },
+ "6": {
+ "source": " if (p1 > 3) {",
+ "coverage": 0
+ },
+ "7": {
+ "source": " return 1;",
+ "coverage": 0
+ },
+ "8": {
+ "source": " }",
+ "coverage": ""
+ },
+ "9": {
+ "source": " else {",
+ "coverage": ""
+ },
+ "10": {
+ "source": " return p1 + p2;",
+ "coverage": 0
+ },
+ "11": {
+ "source": " }",
+ "coverage": ""
+ },
+ "12": {
+ "source": "}",
+ "coverage": ""
+ },
+ "13": {
+ "source": "",
+ "coverage": ""
+ },
+ "14": {
+ "source": "function covTest2(p1,p2) {",
+ "coverage": 1
+ },
+ "15": {
+ "source": " return 0;",
+ "coverage": 1
+ },
+ "16": {
+ "source": "}",
+ "coverage": ""
+ },
+ "17": {
+ "source": "",
+ "coverage": ""
+ },
+ "18": {
+ "source": "function covTest3(p1) {",
+ "coverage": 1
+ },
+ "19": {
+ "source": " for(i=0;i < p1;i++){",
+ "coverage": 0
+ },
+ "20": {
+ "source": " }",
+ "coverage": ""
+ },
+ "21": {
+ "source": " return i;",
+ "coverage": 0
+ },
+ "22": {
+ "source": "}",
+ "coverage": ""
+ },
+ "23": {
+ "source": "function covTest4(p1) {",
+ "coverage": 1
+ },
+ "24": {
+ "source": " i=0;",
+ "coverage": 0
+ },
+ "25": {
+ "source": " while(i < p1){",
+ "coverage": 0
+ },
+ "26": {
+ "source": " i++;",
+ "coverage": 0
+ },
+ "27": {
+ "source": " }",
+ "coverage": ""
+ },
+ "28": {
+ "source": " return i;",
+ "coverage": 0
+ },
+ "29": {
+ "source": "}",
+ "coverage": ""
+ },
+ "30": {
+ "source": "",
+ "coverage": ""
+ },
+ "31": {
+ "source": "describe('Array', function(){",
+ "coverage": 1
+ },
+ "32": {
+ "source": " describe('CovTest2', function(){",
+ "coverage": 1
+ },
+ "33": {
+ "source": " it('should return when the value is not present', function(){",
+ "coverage": 1
+ },
+ "34": {
+ "source": " assert.equal(0,covTest2(2,2));",
+ "coverage": 1
+ },
+ "35": {
+ "source": " })",
+ "coverage": ""
+ },
+ "36": {
+ "source": " })",
+ "coverage": ""
+ },
+ "37": {
+ "source": "})",
+ "coverage": ""
+ },
+ "38": {
+ "source": "",
+ "coverage": ""
+ }
+ }
+ }
+ ],
+ "stats": {
+ "suites": 5,
+ "tests": 4,
+ "passes": 4,
+ "pending": 0,
+ "failures": 0,
+ "start": "2014-10-23T17:56:02.339Z",
+ "end": "2014-10-23T17:56:02.344Z",
+ "duration": 5
+ },
+ "tests": [
+ {
+ "title": "should return when the value is not present",
+ "fullTitle": "Array CovTest should return when the value is not present",
+ "duration": 0
+ },
+ {
+ "title": "should return when the value is not present",
+ "fullTitle": "Array CovTest>3 should return when the value is not present",
+ "duration": 0
+ },
+ {
+ "title": "should return when the value is not present",
+ "fullTitle": "Array covTest4 should return when the value is not present",
+ "duration": 0
+ },
+ {
+ "title": "should return when the value is not present",
+ "fullTitle": "Array covTest3 should return when the value is not present",
+ "duration": 0
+ }
+ ],
+ "failures": [],
+ "passes": [
+ {
+ "title": "should return when the value is not present",
+ "fullTitle": "Array CovTest should return when the value is not present",
+ "duration": 0
+ },
+ {
+ "title": "should return when the value is not present",
+ "fullTitle": "Array CovTest>3 should return when the value is not present",
+ "duration": 0
+ },
+ {
+ "title": "should return when the value is not present",
+ "fullTitle": "Array covTest4 should return when the value is not present",
+ "duration": 0
+ },
+ {
+ "title": "should return when the value is not present",
+ "fullTitle": "Array covTest3 should return when the value is not present",
+ "duration": 0
+ }
+ ]
+} \ No newline at end of file
diff --git a/Tests/JavascriptCoverage/test.js b/Tests/JavascriptCoverage/test.js
new file mode 100644
index 0000000..273e921c
--- /dev/null
+++ b/Tests/JavascriptCoverage/test.js
@@ -0,0 +1,53 @@
+var assert = require("assert")
+var test = {
+ version: "1.0.0"
+}
+function covTest(p1,p2) {
+ if (p1 > 3) {
+ return 1;
+ }
+ else {
+ return p1 + p2;
+ }
+}
+
+function covTest2(p1,p2) {
+ return 0;
+}
+
+function covTest3(p1) {
+ for(i=0;i < p1;i++){
+ }
+ return i;
+}
+function covTest4(p1) {
+ i=0;
+ while(i < p1){
+ i++;
+ }
+ return i;
+}
+
+describe('Array', function(){
+ describe('CovTest', function(){
+ it('should return when the value is not present', function(){
+ assert.equal(4,covTest(2,2));
+ })
+ })
+
+ describe('CovTest>3', function(){
+ it('should return when the value is not present', function(){
+ assert.equal(1,covTest(4,2));
+ })
+ })
+ describe('covTest4', function(){
+ it('should return when the value is not present', function(){
+ assert.equal(5,covTest4(5));
+ })
+ })
+ describe('covTest3', function(){
+ it('should return when the value is not present', function(){
+ assert.equal(5,covTest3(5));
+ })
+ })
+})
diff --git a/Tests/JavascriptCoverage/test3.js b/Tests/JavascriptCoverage/test3.js
new file mode 100644
index 0000000..a1e31bc
--- /dev/null
+++ b/Tests/JavascriptCoverage/test3.js
@@ -0,0 +1,37 @@
+var assert = require("assert")
+var test = {
+ version: "1.0.0"
+}
+function covTest(p1,p2) {
+ if (p1 > 3) {
+ return 1;
+ }
+ else {
+ return p1 + p2;
+ }
+}
+
+function covTest2(p1,p2) {
+ return 0;
+}
+
+function covTest3(p1) {
+ for(i=0;i < p1;i++){
+ }
+ return i;
+}
+function covTest4(p1) {
+ i=0;
+ while(i < p1){
+ i++;
+ }
+ return i;
+}
+
+describe('Array', function(){
+ describe('CovTest2', function(){
+ it('should return when the value is not present', function(){
+ assert.equal(0,covTest2(2,2));
+ })
+ })
+})
diff --git a/Tests/Jump/CMakeLists.txt b/Tests/Jump/CMakeLists.txt
new file mode 100644
index 0000000..4c5ad30
--- /dev/null
+++ b/Tests/Jump/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required (VERSION 2.6)
+project(Jump)
+
+set(CMAKE_IGNORE_DEPENDENCIES_ORDERING 1)
+add_subdirectory(Executable)
+add_subdirectory(Library)
diff --git a/Tests/Jump/Executable/CMakeLists.txt b/Tests/Jump/Executable/CMakeLists.txt
new file mode 100644
index 0000000..bc6731f
--- /dev/null
+++ b/Tests/Jump/Executable/CMakeLists.txt
@@ -0,0 +1,6 @@
+if(NOT LIBRARY_OUTPUT_PATH)
+ link_directories(${Jump_BINARY_DIR}/Library/Static
+ ${Jump_BINARY_DIR}/Library/Shared)
+endif()
+add_executable(jumpExecutable jumpExecutable.cxx)
+target_link_libraries(jumpExecutable jumpStatic jumpShared)
diff --git a/Tests/Jump/Executable/jumpExecutable.cxx b/Tests/Jump/Executable/jumpExecutable.cxx
new file mode 100644
index 0000000..2c5961c
--- /dev/null
+++ b/Tests/Jump/Executable/jumpExecutable.cxx
@@ -0,0 +1,12 @@
+#ifdef _WIN32
+# define JUMP_IMPORT __declspec(dllimport)
+#else
+# define JUMP_IMPORT extern
+#endif
+
+extern int jumpStatic();
+JUMP_IMPORT int jumpShared();
+int main()
+{
+ return jumpShared() && jumpShared();
+}
diff --git a/Tests/Jump/Library/CMakeLists.txt b/Tests/Jump/Library/CMakeLists.txt
new file mode 100644
index 0000000..1d9fed9
--- /dev/null
+++ b/Tests/Jump/Library/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(Static)
+add_subdirectory(Shared)
diff --git a/Tests/Jump/Library/Shared/CMakeLists.txt b/Tests/Jump/Library/Shared/CMakeLists.txt
new file mode 100644
index 0000000..a37299a
--- /dev/null
+++ b/Tests/Jump/Library/Shared/CMakeLists.txt
@@ -0,0 +1,26 @@
+add_library(jumpShared SHARED jumpShared.cxx)
+
+if(WIN32 OR CYGWIN)
+ set(SHARED_MUST_BE_IN_EXE_DIR 1)
+endif()
+
+if(APPLE)
+ set(SHARED_MUST_BE_IN_EXE_DIR 1)
+endif()
+
+if(SHARED_MUST_BE_IN_EXE_DIR)
+ set(LIB_NAME
+ ${CMAKE_SHARED_LIBRARY_PREFIX}jumpShared${CMAKE_SHARED_LIBRARY_SUFFIX})
+ set(EXE_DIR ${Jump_BINARY_DIR}/Executable)
+ if(EXECUTABLE_OUTPUT_PATH)
+ set(EXE_DIR ${EXECUTABLE_OUTPUT_PATH})
+ endif()
+ set(LIB_DIR ${Jump_BINARY_DIR}/Library/Shared)
+ if(LIBRARY_OUTPUT_PATH)
+ set(LIB_DIR ${LIBRARY_OUTPUT_PATH})
+ endif()
+ add_custom_command(TARGET jumpShared
+ POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy
+ ${LIB_DIR}/${CMAKE_CFG_INTDIR}/${LIB_NAME}
+ ${EXE_DIR}/${CMAKE_CFG_INTDIR}/${LIB_NAME})
+endif()
diff --git a/Tests/Jump/Library/Shared/jumpShared.cxx b/Tests/Jump/Library/Shared/jumpShared.cxx
new file mode 100644
index 0000000..87484b7
--- /dev/null
+++ b/Tests/Jump/Library/Shared/jumpShared.cxx
@@ -0,0 +1,10 @@
+#ifdef _WIN32
+# define JUMP_EXPORT __declspec(dllexport)
+#else
+# define JUMP_EXPORT
+#endif
+
+JUMP_EXPORT int jumpShared()
+{
+ return 0;
+}
diff --git a/Tests/Jump/Library/Static/CMakeLists.txt b/Tests/Jump/Library/Static/CMakeLists.txt
new file mode 100644
index 0000000..4ee3954
--- /dev/null
+++ b/Tests/Jump/Library/Static/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(jumpStatic STATIC jumpStatic.cxx)
diff --git a/Tests/Jump/Library/Static/jumpStatic.cxx b/Tests/Jump/Library/Static/jumpStatic.cxx
new file mode 100644
index 0000000..9b169cf
--- /dev/null
+++ b/Tests/Jump/Library/Static/jumpStatic.cxx
@@ -0,0 +1,4 @@
+int jumpStatic()
+{
+ return 0;
+}
diff --git a/Tests/LibName/CMakeLists.txt b/Tests/LibName/CMakeLists.txt
new file mode 100644
index 0000000..b8f0890
--- /dev/null
+++ b/Tests/LibName/CMakeLists.txt
@@ -0,0 +1,34 @@
+project(LibName)
+# this is a test to make sure that relative path
+# LIBRARY_OUTPUT_PATH and EXECUTABLE_OUTPUT_PATH work
+set(LIBRARY_OUTPUT_PATH lib)
+set(EXECUTABLE_OUTPUT_PATH lib)
+
+add_library(bar SHARED bar.c)
+
+add_library(foo SHARED foo.c)
+target_link_libraries(foo bar)
+
+add_executable(foobar foobar.c)
+target_link_libraries(foobar foo)
+if(UNIX)
+ target_link_libraries(foobar -L/usr/local/lib)
+endif()
+
+
+# check with lib version
+
+add_library(verFoo SHARED foo.c)
+target_link_libraries(verFoo bar)
+set_target_properties(verFoo PROPERTIES VERSION 3.1.4 SOVERSION 3)
+
+add_executable(verFoobar foobar.c)
+target_link_libraries(verFoobar verFoo)
+
+if(MAKE_SUPPORTS_SPACES AND NOT CMAKE_GENERATOR STREQUAL "Watcom WMake")
+ # check with lib version and space
+ add_library(ver_space SHARED ver_space.c)
+ set_target_properties(ver_space PROPERTIES VERSION 3.1.4 SOVERSION 3 OUTPUT_NAME "ver space")
+ add_executable(use_ver_space use_ver_space.c)
+ target_link_libraries(use_ver_space ver_space)
+endif()
diff --git a/Tests/LibName/bar.c b/Tests/LibName/bar.c
new file mode 100644
index 0000000..c6c1e66
--- /dev/null
+++ b/Tests/LibName/bar.c
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+
+ extern void foo()
+{
+}
diff --git a/Tests/LibName/foo.c b/Tests/LibName/foo.c
new file mode 100644
index 0000000..52e8d89
--- /dev/null
+++ b/Tests/LibName/foo.c
@@ -0,0 +1,11 @@
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+ extern void foo();
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ void bar()
+{
+ foo();
+}
diff --git a/Tests/LibName/foobar.c b/Tests/LibName/foobar.c
new file mode 100644
index 0000000..2f28d30
--- /dev/null
+++ b/Tests/LibName/foobar.c
@@ -0,0 +1,10 @@
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+ extern void bar();
+
+int main()
+{
+ bar();
+ return 0;
+}
diff --git a/Tests/LibName/use_ver_space.c b/Tests/LibName/use_ver_space.c
new file mode 100644
index 0000000..a6a733d
--- /dev/null
+++ b/Tests/LibName/use_ver_space.c
@@ -0,0 +1,9 @@
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+ int ver_space(void);
+
+int main(void)
+{
+ return ver_space();
+}
diff --git a/Tests/LibName/ver_space.c b/Tests/LibName/ver_space.c
new file mode 100644
index 0000000..669a3b5
--- /dev/null
+++ b/Tests/LibName/ver_space.c
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int ver_space(void)
+{
+ return 0;
+}
diff --git a/Tests/LinkDirectory/CMakeLists.txt b/Tests/LinkDirectory/CMakeLists.txt
new file mode 100644
index 0000000..d9a8ac8
--- /dev/null
+++ b/Tests/LinkDirectory/CMakeLists.txt
@@ -0,0 +1,45 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(LinkDirectory C)
+
+# Put the subproject source tree in our build tree so it can refer to
+# link directories relative to its source.
+if(NOT "${LinkDirectory_SOURCE_DIR}" STREQUAL "${LinkDirectory_BINARY_DIR}")
+ file(COPY External/ DESTINATION External PATTERN CVS EXCLUDE)
+endif()
+
+# Build a library into the subproject source tree.
+add_library(mylibA STATIC mylibA.c)
+set_property(TARGET mylibA PROPERTY
+ ARCHIVE_OUTPUT_DIRECTORY "${LinkDirectory_BINARY_DIR}/External/lib")
+
+# Build a library into our build tree relative to the subproject build tree.
+add_library(mylibB STATIC mylibB.c)
+set_property(TARGET mylibB PROPERTY
+ ARCHIVE_OUTPUT_DIRECTORY "${LinkDirectory_BINARY_DIR}/lib")
+
+# Create a custom target to drive the subproject build.
+include(ExternalProject)
+ExternalProject_Add(ExternalTarget
+ SOURCE_DIR "${LinkDirectory_BINARY_DIR}/External"
+ BINARY_DIR "${LinkDirectory_BINARY_DIR}/External-build"
+ CMAKE_ARGS "-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${LinkDirectory_BINARY_DIR}/bin"
+ PREFIX "${LinkDirectory_BINARY_DIR}/External-build/root"
+ DOWNLOAD_COMMAND ""
+ INSTALL_COMMAND ""
+ )
+
+# Add a step to wipe out the subproject executable after our libraries
+# change. This is needed because the subproject cannot depend on them
+# directly because it does not know the full paths to the libraries.
+# (The purpose of this test is to check that link_directories works.)
+ExternalProject_Add_Step(ExternalTarget cleanup
+ COMMAND ${CMAKE_COMMAND} -E rm -rf ${LinkDirectory_BINARY_DIR}/bin
+ DEPENDEES download
+ DEPENDERS configure
+ DEPENDS mylibA mylibB
+ "${LinkDirectory_BINARY_DIR}/External/CMakeLists.txt"
+ "${LinkDirectory_BINARY_DIR}/External/myexe.c"
+ )
+
+# Make the subproject build after our targets.
+add_dependencies(ExternalTarget mylibA mylibB)
diff --git a/Tests/LinkDirectory/External/CMakeLists.txt b/Tests/LinkDirectory/External/CMakeLists.txt
new file mode 100644
index 0000000..e222929
--- /dev/null
+++ b/Tests/LinkDirectory/External/CMakeLists.txt
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(LinkDirectoryExternal C)
+
+
+set(cfg_dir)
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ set(cfg_dir /$<CONFIG>)
+endif()
+
+add_executable(myexe2 myexe.c)
+set_property(TARGET myexe2 PROPERTY OUTPUT_NAME LinkDirectory2)
+target_link_directories(myexe2 PRIVATE lib${cfg_dir} "${CMAKE_CURRENT_SOURCE_DIR}/../lib${cfg_dir}")
+target_link_libraries(myexe2 PRIVATE mylibA mylibB)
+
+add_library (mylibs INTERFACE)
+target_link_directories(mylibs INTERFACE lib${cfg_dir} "${CMAKE_CURRENT_SOURCE_DIR}/../lib${cfg_dir}")
+target_link_libraries(mylibs INTERFACE mylibA mylibB)
+add_executable(myexe3 myexe.c)
+set_property(TARGET myexe3 PROPERTY OUTPUT_NAME LinkDirectory3)
+target_link_libraries(myexe3 PRIVATE mylibs)
+
+
+# Test CMP0015 OLD behavior: -L../lib
+cmake_policy(SET CMP0015 OLD)
+link_directories(../lib${cfg_dir})
+
+# Test CMP0015 NEW behavior: -L${CMAKE_CURRENT_SOURCE_DIR}/lib
+cmake_policy(SET CMP0015 NEW)
+link_directories(lib${cfg_dir})
+
+add_executable(myexe myexe.c)
+set_property(TARGET myexe PROPERTY OUTPUT_NAME LinkDirectory)
+target_link_libraries(myexe mylibA mylibB)
diff --git a/Tests/LinkDirectory/External/myexe.c b/Tests/LinkDirectory/External/myexe.c
new file mode 100644
index 0000000..57d361d
--- /dev/null
+++ b/Tests/LinkDirectory/External/myexe.c
@@ -0,0 +1,6 @@
+extern int mylibA(void);
+extern int mylibB(void);
+int main(void)
+{
+ return mylibA() + mylibB();
+}
diff --git a/Tests/LinkDirectory/mylibA.c b/Tests/LinkDirectory/mylibA.c
new file mode 100644
index 0000000..dd9838f
--- /dev/null
+++ b/Tests/LinkDirectory/mylibA.c
@@ -0,0 +1,4 @@
+int mylibA(void)
+{
+ return 0;
+}
diff --git a/Tests/LinkDirectory/mylibB.c b/Tests/LinkDirectory/mylibB.c
new file mode 100644
index 0000000..87cebdf
--- /dev/null
+++ b/Tests/LinkDirectory/mylibB.c
@@ -0,0 +1,4 @@
+int mylibB(void)
+{
+ return 0;
+}
diff --git a/Tests/LinkFlags/CMakeLists.txt b/Tests/LinkFlags/CMakeLists.txt
new file mode 100644
index 0000000..31ff9b5
--- /dev/null
+++ b/Tests/LinkFlags/CMakeLists.txt
@@ -0,0 +1,37 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(LinkFlags C)
+
+string(TOUPPER "${TEST_CONFIG}" TEST_CONFIG_UPPER)
+set(obj "${CMAKE_C_OUTPUT_EXTENSION}")
+if(BORLAND)
+ set(pre -)
+endif()
+
+add_library(LinkFlags_lib STATIC LinkFlagsLib.c)
+set_property(TARGET LinkFlags_lib PROPERTY STATIC_LIBRARY_FLAGS ${pre}BADFLAG${obj})
+
+add_library(LinkFlags_dll SHARED LinkFlagsLib.c)
+set_property(TARGET LinkFlags_dll PROPERTY LINK_FLAGS ${pre}BADFLAG${obj})
+
+add_library(LinkFlags_mod MODULE LinkFlagsLib.c)
+set_property(TARGET LinkFlags_mod PROPERTY LINK_FLAGS ${pre}BADFLAG${obj})
+
+add_executable(LinkFlags_exe LinkFlagsExe.c)
+set_property(TARGET LinkFlags_exe PROPERTY LINK_FLAGS ${pre}BADFLAG${obj})
+
+add_library(LinkFlags_lib_config STATIC LinkFlagsLib.c)
+set_property(TARGET LinkFlags_lib_config PROPERTY STATIC_LIBRARY_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG_${TEST_CONFIG}${obj})
+
+add_library(LinkFlags_dll_config SHARED LinkFlagsLib.c)
+set_property(TARGET LinkFlags_dll_config PROPERTY LINK_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG_${TEST_CONFIG}${obj})
+
+add_library(LinkFlags_mod_config MODULE LinkFlagsLib.c)
+set_property(TARGET LinkFlags_mod_config PROPERTY LINK_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG_${TEST_CONFIG}${obj})
+
+add_executable(LinkFlags_exe_config LinkFlagsExe.c)
+set_property(TARGET LinkFlags_exe_config PROPERTY LINK_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG_${TEST_CONFIG}${obj})
+
+add_executable(LinkFlags LinkFlags.c)
+
+add_subdirectory(LinkerFlags)
+add_subdirectory(LinkerFlagsConfig)
diff --git a/Tests/LinkFlags/LinkFlags.c b/Tests/LinkFlags/LinkFlags.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/LinkFlags/LinkFlags.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/LinkFlags/LinkFlagsExe.c b/Tests/LinkFlags/LinkFlagsExe.c
new file mode 100644
index 0000000..202d34d
--- /dev/null
+++ b/Tests/LinkFlags/LinkFlagsExe.c
@@ -0,0 +1,9 @@
+int main(void)
+{
+ return 0;
+}
+
+/* Intel compiler does not reject bad flags or objects! */
+#if defined(__INTEL_COMPILER)
+# error BADFLAG
+#endif
diff --git a/Tests/LinkFlags/LinkFlagsLib.c b/Tests/LinkFlags/LinkFlagsLib.c
new file mode 100644
index 0000000..bd288e9
--- /dev/null
+++ b/Tests/LinkFlags/LinkFlagsLib.c
@@ -0,0 +1,9 @@
+int flags_lib(void)
+{
+ return 0;
+}
+
+/* Intel compiler does not reject bad flags or objects! */
+#if defined(__INTEL_COMPILER)
+# error BADFLAG
+#endif
diff --git a/Tests/LinkFlags/LinkerFlags/CMakeLists.txt b/Tests/LinkFlags/LinkerFlags/CMakeLists.txt
new file mode 100644
index 0000000..4707f47
--- /dev/null
+++ b/Tests/LinkFlags/LinkerFlags/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(CMAKE_STATIC_LINKER_FLAGS ${pre}BADFLAG${obj})
+add_library(LinkFlags_lib_flags STATIC ../LinkFlagsLib.c)
+
+set(CMAKE_SHARED_LINKER_FLAGS ${pre}BADFLAG${obj})
+add_library(LinkFlags_dll_flags SHARED ../LinkFlagsLib.c)
+
+set(CMAKE_MODULE_LINKER_FLAGS ${pre}BADFLAG${obj})
+add_library(LinkFlags_mod_flags MODULE ../LinkFlagsLib.c)
+
+set(CMAKE_EXE_LINKER_FLAGS ${pre}BADFLAG${obj})
+add_executable(LinkFlags_exe_flags ../LinkFlagsExe.c)
diff --git a/Tests/LinkFlags/LinkerFlagsConfig/CMakeLists.txt b/Tests/LinkFlags/LinkerFlagsConfig/CMakeLists.txt
new file mode 100644
index 0000000..2854fe7
--- /dev/null
+++ b/Tests/LinkFlags/LinkerFlagsConfig/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(CMAKE_STATIC_LINKER_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG${obj})
+add_library(LinkFlags_lib_flags_config STATIC ../LinkFlagsLib.c)
+
+set(CMAKE_SHARED_LINKER_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG${obj})
+add_library(LinkFlags_dll_flags_config SHARED ../LinkFlagsLib.c)
+
+set(CMAKE_MODULE_LINKER_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG${obj})
+add_library(LinkFlags_mod_flags_config MODULE ../LinkFlagsLib.c)
+
+set(CMAKE_EXE_LINKER_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG${obj})
+add_executable(LinkFlags_exe_flags_config ../LinkFlagsExe.c)
diff --git a/Tests/LinkLanguage/CMakeLists.txt b/Tests/LinkLanguage/CMakeLists.txt
new file mode 100644
index 0000000..b4e5392
--- /dev/null
+++ b/Tests/LinkLanguage/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 2.7.20090708)
+project(LinkLanguage C CXX)
+
+add_library(foo STATIC foo.cxx)
+add_executable(LinkLanguage LinkLanguage.c)
+
+# Export the target now to compute its link interface and implementation.
+# This tests that the link info is recomputed after the library is linked.
+export(TARGETS LinkLanguage FILE LinkLanguageTargets.cmake)
+
+target_link_libraries(LinkLanguage foo)
+
+# CMake should now automatically choose CXX for linking, so we need
+# not set the property:
+#set_property(TARGET LinkLanguage PROPERTY LINKER_LANGUAGE CXX)
diff --git a/Tests/LinkLanguage/LinkLanguage.c b/Tests/LinkLanguage/LinkLanguage.c
new file mode 100644
index 0000000..37946c7
--- /dev/null
+++ b/Tests/LinkLanguage/LinkLanguage.c
@@ -0,0 +1,5 @@
+extern int foo(void);
+int main()
+{
+ return foo();
+}
diff --git a/Tests/LinkLanguage/foo.cxx b/Tests/LinkLanguage/foo.cxx
new file mode 100644
index 0000000..5321c2d
--- /dev/null
+++ b/Tests/LinkLanguage/foo.cxx
@@ -0,0 +1,6 @@
+extern "C" int foo(void)
+{
+ // Reference C++ standard library symbols.
+ delete new int;
+ return 0;
+}
diff --git a/Tests/LinkLine/CMakeLists.txt b/Tests/LinkLine/CMakeLists.txt
new file mode 100644
index 0000000..6154dd4
--- /dev/null
+++ b/Tests/LinkLine/CMakeLists.txt
@@ -0,0 +1,12 @@
+project( LinkLine )
+
+# Makes sure that the library order as specified by the user are
+# unchanged by dependency analysis, etc. libOne and libTwo are
+# dependent on each other. The link line should be -lOne -lTwo -lOne.
+
+add_library( One One.c )
+add_library( Two Two.c )
+
+link_libraries( One Two )
+add_executable( LinkLine Exec.c )
+link_libraries( One )
diff --git a/Tests/LinkLine/Exec.c b/Tests/LinkLine/Exec.c
new file mode 100644
index 0000000..807a7a8
--- /dev/null
+++ b/Tests/LinkLine/Exec.c
@@ -0,0 +1,9 @@
+void OneFunc();
+void TwoFunc();
+
+int main()
+{
+ OneFunc();
+ TwoFunc();
+ return 0;
+}
diff --git a/Tests/LinkLine/One.c b/Tests/LinkLine/One.c
new file mode 100644
index 0000000..856d0d1
--- /dev/null
+++ b/Tests/LinkLine/One.c
@@ -0,0 +1,10 @@
+void TwoFunc();
+
+void OneFunc()
+{
+ static int i = 0;
+ ++i;
+ if (i == 1) {
+ TwoFunc();
+ }
+}
diff --git a/Tests/LinkLine/Two.c b/Tests/LinkLine/Two.c
new file mode 100644
index 0000000..5fc212e
--- /dev/null
+++ b/Tests/LinkLine/Two.c
@@ -0,0 +1,10 @@
+void OneFunc();
+
+void TwoFunc()
+{
+ static int i = 0;
+ ++i;
+ if (i == 1) {
+ OneFunc();
+ }
+}
diff --git a/Tests/LinkLineOrder/CMakeLists.txt b/Tests/LinkLineOrder/CMakeLists.txt
new file mode 100644
index 0000000..78455e9
--- /dev/null
+++ b/Tests/LinkLineOrder/CMakeLists.txt
@@ -0,0 +1,36 @@
+project( LinkLineOrder )
+
+# This tests ensures that the order of libraries are preserved when
+# they don't have dependency information, even if they are deep in the
+# dependency tree.
+
+# NoDepC depends on NoDepA which depends on NoDepB. NoDepE and NoDepF
+# are dependent on each other (recursive dependency). However, CMake
+# has no information about these libraries except for the order they
+# are specified in One. We must make sure we don't lose that.
+
+add_library( NoDepA NoDepA.c )
+add_library( NoDepB NoDepB.c )
+add_library( NoDepC NoDepC.c )
+add_library( NoDepE NoDepE.c )
+add_library( NoDepF NoDepF.c )
+
+add_library( One One.c )
+target_link_libraries( One NoDepC NoDepA NoDepB NoDepE NoDepF NoDepE )
+
+add_executable( Exec1 Exec1.c )
+target_link_libraries( Exec1 One )
+
+
+# Similar situation as One, except at a different level of the
+# dependency tree. This makes sure that the order is presevered
+# everywhere in the graph.
+add_library( NoDepX NoDepX.c )
+add_library( NoDepY NoDepY.c )
+add_library( NoDepZ NoDepZ.c )
+
+add_library( Two Two.c )
+target_link_libraries( Two One NoDepZ NoDepX NoDepY )
+
+add_executable( Exec2 Exec2.c )
+target_link_libraries( Exec2 Two )
diff --git a/Tests/LinkLineOrder/Exec1.c b/Tests/LinkLineOrder/Exec1.c
new file mode 100644
index 0000000..9bbf0f6
--- /dev/null
+++ b/Tests/LinkLineOrder/Exec1.c
@@ -0,0 +1,8 @@
+/* Directly depends on One */
+void OneFunc();
+
+int main()
+{
+ OneFunc();
+ return 0;
+}
diff --git a/Tests/LinkLineOrder/Exec2.c b/Tests/LinkLineOrder/Exec2.c
new file mode 100644
index 0000000..91b8575
--- /dev/null
+++ b/Tests/LinkLineOrder/Exec2.c
@@ -0,0 +1,8 @@
+/* Directly depends on Two */
+void TwoFunc();
+
+int main()
+{
+ TwoFunc();
+ return 0;
+}
diff --git a/Tests/LinkLineOrder/NoDepA.c b/Tests/LinkLineOrder/NoDepA.c
new file mode 100644
index 0000000..76f97bc
--- /dev/null
+++ b/Tests/LinkLineOrder/NoDepA.c
@@ -0,0 +1,7 @@
+/* depends on NoDepB */
+void NoDepB_func();
+
+void NoDepA_func()
+{
+ NoDepB_func();
+}
diff --git a/Tests/LinkLineOrder/NoDepB.c b/Tests/LinkLineOrder/NoDepB.c
new file mode 100644
index 0000000..fa89ae9
--- /dev/null
+++ b/Tests/LinkLineOrder/NoDepB.c
@@ -0,0 +1,4 @@
+/* No dependencies */
+void NoDepB_func()
+{
+}
diff --git a/Tests/LinkLineOrder/NoDepC.c b/Tests/LinkLineOrder/NoDepC.c
new file mode 100644
index 0000000..f05d962
--- /dev/null
+++ b/Tests/LinkLineOrder/NoDepC.c
@@ -0,0 +1,7 @@
+/* depends on NoDepA */
+void NoDepA_func();
+
+void NoDepC_func()
+{
+ NoDepA_func();
+}
diff --git a/Tests/LinkLineOrder/NoDepE.c b/Tests/LinkLineOrder/NoDepE.c
new file mode 100644
index 0000000..c47bb85
--- /dev/null
+++ b/Tests/LinkLineOrder/NoDepE.c
@@ -0,0 +1,11 @@
+/* depends on NoDepF */
+void NoDepF_func();
+
+void NoDepE_func()
+{
+ static int firstcall = 1;
+ if (firstcall) {
+ firstcall = 0;
+ NoDepF_func();
+ }
+}
diff --git a/Tests/LinkLineOrder/NoDepF.c b/Tests/LinkLineOrder/NoDepF.c
new file mode 100644
index 0000000..a814310
--- /dev/null
+++ b/Tests/LinkLineOrder/NoDepF.c
@@ -0,0 +1,11 @@
+/* depends on NoDepE */
+void NoDepE_func();
+
+void NoDepF_func()
+{
+ static int firstcall = 1;
+ if (firstcall) {
+ firstcall = 0;
+ NoDepE_func();
+ }
+}
diff --git a/Tests/LinkLineOrder/NoDepX.c b/Tests/LinkLineOrder/NoDepX.c
new file mode 100644
index 0000000..c895dd1
--- /dev/null
+++ b/Tests/LinkLineOrder/NoDepX.c
@@ -0,0 +1,7 @@
+/* depends on NoDepY*/
+void NoDepY_func();
+
+void NoDepX_func()
+{
+ NoDepY_func();
+}
diff --git a/Tests/LinkLineOrder/NoDepY.c b/Tests/LinkLineOrder/NoDepY.c
new file mode 100644
index 0000000..1e6a4ae
--- /dev/null
+++ b/Tests/LinkLineOrder/NoDepY.c
@@ -0,0 +1,4 @@
+/* No dependencies */
+void NoDepY_func()
+{
+}
diff --git a/Tests/LinkLineOrder/NoDepZ.c b/Tests/LinkLineOrder/NoDepZ.c
new file mode 100644
index 0000000..045e570
--- /dev/null
+++ b/Tests/LinkLineOrder/NoDepZ.c
@@ -0,0 +1,7 @@
+/* depends on NoDepX */
+void NoDepX_func();
+
+void NoDepZ_func()
+{
+ NoDepX_func();
+}
diff --git a/Tests/LinkLineOrder/One.c b/Tests/LinkLineOrder/One.c
new file mode 100644
index 0000000..b23b1ec
--- /dev/null
+++ b/Tests/LinkLineOrder/One.c
@@ -0,0 +1,10 @@
+/* depends on NoDepC and NoDepE (and hence on NoDepA, NoDepB and */
+/* NoDepF) */
+void NoDepC_func();
+void NoDepE_func();
+
+void OneFunc()
+{
+ NoDepC_func();
+ NoDepE_func();
+}
diff --git a/Tests/LinkLineOrder/Two.c b/Tests/LinkLineOrder/Two.c
new file mode 100644
index 0000000..6bffaa8
--- /dev/null
+++ b/Tests/LinkLineOrder/Two.c
@@ -0,0 +1,8 @@
+void OneFunc();
+void NoDepZ_func();
+
+void TwoFunc()
+{
+ OneFunc();
+ NoDepZ_func();
+}
diff --git a/Tests/LinkStatic/CMakeLists.txt b/Tests/LinkStatic/CMakeLists.txt
new file mode 100644
index 0000000..200d4e5
--- /dev/null
+++ b/Tests/LinkStatic/CMakeLists.txt
@@ -0,0 +1,27 @@
+cmake_minimum_required(VERSION 2.8.4.20110303 FATAL_ERROR)
+project(LinkStatic C)
+
+if(NOT CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ message(FATAL_ERROR "This test works only with the GNU compiler!")
+endif()
+
+find_library(MATH_LIBRARY NAMES libm.a)
+if(MATH_LIBRARY)
+ get_filename_component(MATH_LIB_DIR ${MATH_LIBRARY} PATH)
+ link_directories(${MATH_LIB_DIR})
+ # Name the library both with a full path and as "-lm" to
+ # activate the link type switching code for both cases.
+ # If the second one links shared then the link will fail.
+ set(MATH_LIBRARIES ${MATH_LIBRARY} -lm)
+else()
+ message(FATAL_ERROR "Cannot find libm.a needed for this test")
+endif()
+
+add_executable(LinkStatic LinkStatic.c)
+target_link_libraries(LinkStatic ${MATH_LIBRARIES})
+
+# Enable static linking.
+set(LinkStatic_FLAG "-static" CACHE STRING "Flag to link statically")
+set_property(TARGET LinkStatic PROPERTY LINK_FLAGS "${LinkStatic_FLAG}")
+set_property(TARGET LinkStatic PROPERTY LINK_SEARCH_START_STATIC 1)
+#set_property(TARGET LinkStatic PROPERTY LINK_SEARCH_END_STATIC 1) # insufficient
diff --git a/Tests/LinkStatic/LinkStatic.c b/Tests/LinkStatic/LinkStatic.c
new file mode 100644
index 0000000..3600977
--- /dev/null
+++ b/Tests/LinkStatic/LinkStatic.c
@@ -0,0 +1,5 @@
+#include <math.h>
+int main(void)
+{
+ return (int)sin(0);
+}
diff --git a/Tests/LoadCommand/CMakeCommands/CMakeLists.txt b/Tests/LoadCommand/CMakeCommands/CMakeLists.txt
new file mode 100644
index 0000000..cafa99b
--- /dev/null
+++ b/Tests/LoadCommand/CMakeCommands/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(CMAKE_LOADED_COMMANDS)
+
+if (MUDSLIDE_TYPE MATCHES MUCHO)
+ add_definitions(-DMUCHO_MUDSLIDE)
+endif ()
+
+include_directories(${CMAKE_ROOT}/include ${CMAKE_ROOT}/Source)
+
+add_library(cmCMAKE_TEST_COMMAND MODULE cmTestCommand.c)
+
+if(WATCOM)
+ target_link_libraries(cmCMAKE_TEST_COMMAND clbsdll.lib)
+endif()
diff --git a/Tests/LoadCommand/CMakeCommands/cmTestCommand.c b/Tests/LoadCommand/CMakeCommands/cmTestCommand.c
new file mode 100644
index 0000000..af7b092
--- /dev/null
+++ b/Tests/LoadCommand/CMakeCommands/cmTestCommand.c
@@ -0,0 +1,186 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cmCPluginAPI.h"
+
+typedef struct
+{
+ char* LibraryName;
+ int Argc;
+ char** Argv;
+} cmVTKWrapTclData;
+
+/* do almost everything in the initial pass */
+static int CCONV InitialPass(void* inf, void* mf, int argc, char* argv[])
+{
+ char* file;
+ char* str;
+ char* srcs;
+ const char* cstr;
+ char buffer[1024];
+ void* source_file;
+ char* args[2];
+ char* ccArgs[4];
+ char* ccDep[1];
+ char* ccOut[1];
+ cmLoadedCommandInfo* info = (cmLoadedCommandInfo*)inf;
+
+ cmVTKWrapTclData* cdata =
+ (cmVTKWrapTclData*)malloc(sizeof(cmVTKWrapTclData));
+ cdata->LibraryName = "BOO";
+ cdata->Argc = argc;
+ cdata->Argv = argv;
+ info->CAPI->SetClientData(info, cdata);
+
+ /* Now check and see if the value has been stored in the cache */
+ /* already, if so use that value and don't look for the program */
+ if (!info->CAPI->IsOn(mf, "TEST_COMMAND_TEST1")) {
+ info->CAPI->AddDefinition(mf, "TEST_DEF", "HOO");
+ return 1;
+ }
+
+ info->CAPI->AddDefinition(mf, "TEST_DEF", "HOO");
+ cdata->LibraryName = "HOO";
+
+ info->CAPI->AddCacheDefinition(mf, "SOME_CACHE_VARIABLE", "ON",
+ "Test cache variable", CM_CACHE_BOOL);
+ info->CAPI->AddCacheDefinition(mf, "SOME_CACHE_VARIABLE1", "",
+ "Test cache variable 1", CM_CACHE_PATH);
+ info->CAPI->AddCacheDefinition(mf, "SOME_CACHE_VARIABLE2", "",
+ "Test cache variable 2", CM_CACHE_FILEPATH);
+ info->CAPI->AddCacheDefinition(mf, "SOME_CACHE_VARIABLE3", "",
+ "Test cache variable 3", CM_CACHE_STRING);
+ info->CAPI->AddCacheDefinition(mf, "SOME_CACHE_VARIABLE4", "",
+ "Test cache variable 4", CM_CACHE_INTERNAL);
+ info->CAPI->AddCacheDefinition(mf, "SOME_CACHE_VARIABLE5", "",
+ "Test cache variable 5", CM_CACHE_STATIC);
+
+ file = info->CAPI->ExpandVariablesInString(mf, "${CMAKE_COMMAND}", 0, 0);
+
+ str = info->CAPI->GetFilenameWithoutExtension(file);
+ info->CAPI->DisplaySatus(mf, str);
+ info->CAPI->Free(str);
+ str = info->CAPI->GetFilenamePath(file);
+ info->CAPI->DisplaySatus(mf, str);
+ info->CAPI->Free(str);
+ str = info->CAPI->Capitalized("cmake");
+ info->CAPI->DisplaySatus(mf, str);
+ info->CAPI->Free(str);
+
+ info->CAPI->DisplaySatus(mf, info->CAPI->GetProjectName(mf));
+ info->CAPI->DisplaySatus(mf, info->CAPI->GetHomeDirectory(mf));
+ info->CAPI->DisplaySatus(mf, info->CAPI->GetHomeOutputDirectory(mf));
+ info->CAPI->DisplaySatus(mf, info->CAPI->GetStartDirectory(mf));
+ info->CAPI->DisplaySatus(mf, info->CAPI->GetStartOutputDirectory(mf));
+ info->CAPI->DisplaySatus(mf, info->CAPI->GetCurrentDirectory(mf));
+ info->CAPI->DisplaySatus(mf, info->CAPI->GetCurrentOutputDirectory(mf));
+ sprintf(buffer, "Cache version: %d.%d, CMake version: %d.%d",
+ info->CAPI->GetCacheMajorVersion(mf),
+ info->CAPI->GetCacheMinorVersion(mf),
+ info->CAPI->GetMajorVersion(mf), info->CAPI->GetMinorVersion(mf));
+ info->CAPI->DisplaySatus(mf, buffer);
+ if (info->CAPI->CommandExists(mf, "SET")) {
+ info->CAPI->DisplaySatus(mf, "Command SET exists");
+ }
+ if (info->CAPI->CommandExists(mf, "SET_FOO_BAR")) {
+ info->CAPI->SetError(mf, "Command SET_FOO_BAR should not exists");
+ return 0;
+ }
+ info->CAPI->AddDefineFlag(mf, "-DADDED_DEFINITION");
+
+ source_file = info->CAPI->CreateNewSourceFile(mf);
+ cstr = info->CAPI->SourceFileGetSourceName(source_file);
+ sprintf(buffer, "Should be empty (source file name): [%s]", cstr);
+ info->CAPI->DisplaySatus(mf, buffer);
+ cstr = info->CAPI->SourceFileGetFullPath(source_file);
+ sprintf(buffer, "Should be empty (source file full path): [%s]", cstr);
+ info->CAPI->DisplaySatus(mf, buffer);
+ info->CAPI->DefineSourceFileProperty(mf, "SOME_PROPERTY", "unused old prop",
+ "This property is no longer used", 0);
+ if (info->CAPI->SourceFileGetPropertyAsBool(source_file, "SOME_PROPERTY")) {
+ info->CAPI->SetError(mf, "Property SOME_PROPERTY should not be defined");
+ return 0;
+ }
+ info->CAPI->DefineSourceFileProperty(mf, "SOME_PROPERTY2", "nice prop",
+ "This property is for testing.", 0);
+ info->CAPI->SourceFileSetProperty(source_file, "SOME_PROPERTY2", "HERE");
+ cstr = info->CAPI->SourceFileGetProperty(source_file, "ABSTRACT");
+ sprintf(buffer, "Should be 0 (source file abstract property): [%p]", cstr);
+ info->CAPI->DisplaySatus(mf, buffer);
+
+ info->CAPI->DestroySourceFile(source_file);
+
+ srcs = argv[2];
+ info->CAPI->AddExecutable(mf, "LoadedCommand", 1, &srcs, 0);
+
+ /* add customs commands to generate the source file */
+ ccArgs[0] = "-E";
+ ccArgs[1] = "copy";
+ ccArgs[2] = argv[0];
+ ccArgs[3] = argv[1];
+ ccDep[0] = ccArgs[2];
+ ccOut[0] = ccArgs[3];
+ info->CAPI->AddCustomCommand(mf, "LoadedCommand.cxx.in", file, 4, ccArgs, 1,
+ ccDep, 1, ccOut, "LoadedCommand");
+
+ ccArgs[2] = argv[1];
+ ccArgs[3] = argv[2];
+ ccDep[0] = ccArgs[2];
+ ccOut[0] = ccArgs[3];
+ info->CAPI->AddCustomCommandToOutput(mf, ccOut[0], file, 4, ccArgs, ccDep[0],
+ 0, 0);
+
+ ccArgs[1] = "echo";
+ ccArgs[2] = "Build has finished";
+ info->CAPI->AddCustomCommandToTarget(mf, "LoadedCommand", file, 3, ccArgs,
+ CM_POST_BUILD);
+
+ info->CAPI->Free(file);
+
+ args[0] = "TEST_EXEC";
+ args[1] = "TRUE";
+
+ /* code coverage */
+ if (info->CAPI->GetTotalArgumentSize(2, args) != 13) {
+ return 0;
+ }
+ info->CAPI->ExecuteCommand(mf, "SET", 2, args);
+
+ /* make sure we can find the source file */
+ if (!info->CAPI->GetSource(mf, argv[1])) {
+ info->CAPI->SetError(mf, "Source file could not be found!");
+ return 0;
+ }
+
+ return 1;
+}
+
+static void CCONV FinalPass(void* inf, void* mf)
+{
+ cmLoadedCommandInfo* info = (cmLoadedCommandInfo*)inf;
+ /* get our client data from initial pass */
+ cmVTKWrapTclData* cdata = (cmVTKWrapTclData*)info->CAPI->GetClientData(info);
+ if (strcmp(info->CAPI->GetDefinition(mf, "TEST_DEF"), "HOO") ||
+ strcmp(cdata->LibraryName, "HOO")) {
+ fprintf(stderr, "*** Failed LOADED COMMAND Final Pass\n");
+ }
+}
+static void CCONV Destructor(void* inf)
+{
+ cmLoadedCommandInfo* info = (cmLoadedCommandInfo*)inf;
+ /* get our client data from initial pass */
+ cmVTKWrapTclData* cdata = (cmVTKWrapTclData*)info->CAPI->GetClientData(info);
+ free(cdata);
+}
+
+#ifdef MUCHO_MUDSLIDE
+void CM_PLUGIN_EXPORT CCONV CMAKE_TEST_COMMANDInit(cmLoadedCommandInfo* info)
+{
+ info->InitialPass = InitialPass;
+ info->FinalPass = FinalPass;
+ info->Destructor = Destructor;
+ info->m_Inherited = 0;
+ info->Name = "CMAKE_TEST_COMMAND";
+}
+#endif
diff --git a/Tests/LoadCommand/CMakeLists.txt b/Tests/LoadCommand/CMakeLists.txt
new file mode 100644
index 0000000..e1c4998
--- /dev/null
+++ b/Tests/LoadCommand/CMakeLists.txt
@@ -0,0 +1,52 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(LoadCommand)
+
+# set a definition
+set (TEST_COMMAND_TEST1 1)
+
+include (${CMAKE_ROOT}/Modules/CheckTypeSize.cmake)
+CHECK_TYPE_SIZE(char SIZEOF_CHAR)
+CHECK_TYPE_SIZE(short SIZEOF_SHORT)
+
+configure_file(${LoadCommand_SOURCE_DIR}/LoadedCommand.h.in
+ ${LoadCommand_BINARY_DIR}/LoadedCommand.h)
+
+include_directories(${LoadCommand_BINARY_DIR})
+
+# try to compile the command
+# make sure it is not already loaded
+if(COMMAND CMAKE_TEST_COMMAND)
+else()
+ try_compile(COMPILE_OK
+ ${LoadCommand_BINARY_DIR}/CMakeCommands
+ ${LoadCommand_SOURCE_DIR}/CMakeCommands
+ CMAKE_LOADED_COMMANDS CMAKE_FLAGS -DMUDSLIDE_TYPE:STRING=MUCHO
+ OUTPUT_VARIABLE OUTPUT )
+endif()
+
+message("Output from try compile: ${OUTPUT}")
+
+# if the compile was OK, try loading the command
+if (COMPILE_OK)
+ load_command(CMAKE_TEST_COMMAND
+ ${LoadCommand_BINARY_DIR}/CMakeCommands
+ ${LoadCommand_BINARY_DIR}/CMakeCommands/Debug
+ ${LoadCommand_BINARY_DIR}/CMakeCommands/Development
+ )
+ # if the command loaded, execute the command
+ if (COMMAND CMAKE_TEST_COMMAND)
+ CMAKE_TEST_COMMAND(
+ "${LoadCommand_SOURCE_DIR}/LoadedCommand.cxx.in"
+ "${LoadCommand_BINARY_DIR}/LoadedCommand2.cxx.in"
+ "${LoadCommand_BINARY_DIR}/LoadedCommand3.cxx"
+ )
+ endif ()
+else ()
+ message("failed to compile CMAKE_LOADED_COMMANDS")
+endif ()
+
+# TEST_DEF is set by the loaded command cmTestCommand.c
+if (TEST_DEF AND SOME_CACHE_VARIABLE AND TEST_EXEC)
+ add_definitions(-DCMAKE_IS_FUN)
+endif ()
+
diff --git a/Tests/LoadCommand/LoadedCommand.cxx.in b/Tests/LoadCommand/LoadedCommand.cxx.in
new file mode 100644
index 0000000..72ec014
--- /dev/null
+++ b/Tests/LoadCommand/LoadedCommand.cxx.in
@@ -0,0 +1,32 @@
+#include "LoadedCommand.h"
+#include <stdio.h>
+
+int testSizeOf(int s1, int s2)
+{
+ return s1 - s2;
+}
+
+int main ()
+{
+ int ret = 0;
+
+#if !defined( ADDED_DEFINITION )
+ printf("Should have ADDED_DEFINITION defined\n");
+ ret= 1;
+#endif
+#if !defined(CMAKE_IS_FUN)
+ printf("Loaded Command was not built with CMAKE_IS_FUN: failed.\n");
+ ret = 1;
+#endif
+ if(testSizeOf(SIZEOF_CHAR, sizeof(char)))
+ {
+ printf("Size of char is broken.\n");
+ ret = 1;
+ }
+ if(testSizeOf(SIZEOF_SHORT, sizeof(short)))
+ {
+ printf("Size of short is broken.\n");
+ ret = 1;
+ }
+ return ret;
+}
diff --git a/Tests/LoadCommand/LoadedCommand.h.in b/Tests/LoadCommand/LoadedCommand.h.in
new file mode 100644
index 0000000..733c414
--- /dev/null
+++ b/Tests/LoadCommand/LoadedCommand.h.in
@@ -0,0 +1,3 @@
+/* Check for size of types */
+#cmakedefine SIZEOF_CHAR ${SIZEOF_CHAR}
+#cmakedefine SIZEOF_SHORT ${SIZEOF_SHORT}
diff --git a/Tests/LoadCommandOneConfig/CMakeCommands/CMakeLists.txt b/Tests/LoadCommandOneConfig/CMakeCommands/CMakeLists.txt
new file mode 100644
index 0000000..dc029a4
--- /dev/null
+++ b/Tests/LoadCommandOneConfig/CMakeCommands/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(CMAKE_LOADED_COMMANDS)
+
+if (MUDSLIDE_TYPE MATCHES MUCHO)
+ add_definitions(-DMUCHO_MUDSLIDE)
+endif ()
+
+if(WATCOM)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
+endif()
+include_directories(${CMAKE_ROOT}/include ${CMAKE_ROOT}/Source)
+
+add_library(cmCMAKE_TEST_COMMAND MODULE cmTestCommand.c)
+
+if(WATCOM)
+ target_link_libraries(cmCMAKE_TEST_COMMAND clbsdll.lib)
+endif()
diff --git a/Tests/LoadCommandOneConfig/CMakeCommands/cmTestCommand.c b/Tests/LoadCommandOneConfig/CMakeCommands/cmTestCommand.c
new file mode 100644
index 0000000..af7b092
--- /dev/null
+++ b/Tests/LoadCommandOneConfig/CMakeCommands/cmTestCommand.c
@@ -0,0 +1,186 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cmCPluginAPI.h"
+
+typedef struct
+{
+ char* LibraryName;
+ int Argc;
+ char** Argv;
+} cmVTKWrapTclData;
+
+/* do almost everything in the initial pass */
+static int CCONV InitialPass(void* inf, void* mf, int argc, char* argv[])
+{
+ char* file;
+ char* str;
+ char* srcs;
+ const char* cstr;
+ char buffer[1024];
+ void* source_file;
+ char* args[2];
+ char* ccArgs[4];
+ char* ccDep[1];
+ char* ccOut[1];
+ cmLoadedCommandInfo* info = (cmLoadedCommandInfo*)inf;
+
+ cmVTKWrapTclData* cdata =
+ (cmVTKWrapTclData*)malloc(sizeof(cmVTKWrapTclData));
+ cdata->LibraryName = "BOO";
+ cdata->Argc = argc;
+ cdata->Argv = argv;
+ info->CAPI->SetClientData(info, cdata);
+
+ /* Now check and see if the value has been stored in the cache */
+ /* already, if so use that value and don't look for the program */
+ if (!info->CAPI->IsOn(mf, "TEST_COMMAND_TEST1")) {
+ info->CAPI->AddDefinition(mf, "TEST_DEF", "HOO");
+ return 1;
+ }
+
+ info->CAPI->AddDefinition(mf, "TEST_DEF", "HOO");
+ cdata->LibraryName = "HOO";
+
+ info->CAPI->AddCacheDefinition(mf, "SOME_CACHE_VARIABLE", "ON",
+ "Test cache variable", CM_CACHE_BOOL);
+ info->CAPI->AddCacheDefinition(mf, "SOME_CACHE_VARIABLE1", "",
+ "Test cache variable 1", CM_CACHE_PATH);
+ info->CAPI->AddCacheDefinition(mf, "SOME_CACHE_VARIABLE2", "",
+ "Test cache variable 2", CM_CACHE_FILEPATH);
+ info->CAPI->AddCacheDefinition(mf, "SOME_CACHE_VARIABLE3", "",
+ "Test cache variable 3", CM_CACHE_STRING);
+ info->CAPI->AddCacheDefinition(mf, "SOME_CACHE_VARIABLE4", "",
+ "Test cache variable 4", CM_CACHE_INTERNAL);
+ info->CAPI->AddCacheDefinition(mf, "SOME_CACHE_VARIABLE5", "",
+ "Test cache variable 5", CM_CACHE_STATIC);
+
+ file = info->CAPI->ExpandVariablesInString(mf, "${CMAKE_COMMAND}", 0, 0);
+
+ str = info->CAPI->GetFilenameWithoutExtension(file);
+ info->CAPI->DisplaySatus(mf, str);
+ info->CAPI->Free(str);
+ str = info->CAPI->GetFilenamePath(file);
+ info->CAPI->DisplaySatus(mf, str);
+ info->CAPI->Free(str);
+ str = info->CAPI->Capitalized("cmake");
+ info->CAPI->DisplaySatus(mf, str);
+ info->CAPI->Free(str);
+
+ info->CAPI->DisplaySatus(mf, info->CAPI->GetProjectName(mf));
+ info->CAPI->DisplaySatus(mf, info->CAPI->GetHomeDirectory(mf));
+ info->CAPI->DisplaySatus(mf, info->CAPI->GetHomeOutputDirectory(mf));
+ info->CAPI->DisplaySatus(mf, info->CAPI->GetStartDirectory(mf));
+ info->CAPI->DisplaySatus(mf, info->CAPI->GetStartOutputDirectory(mf));
+ info->CAPI->DisplaySatus(mf, info->CAPI->GetCurrentDirectory(mf));
+ info->CAPI->DisplaySatus(mf, info->CAPI->GetCurrentOutputDirectory(mf));
+ sprintf(buffer, "Cache version: %d.%d, CMake version: %d.%d",
+ info->CAPI->GetCacheMajorVersion(mf),
+ info->CAPI->GetCacheMinorVersion(mf),
+ info->CAPI->GetMajorVersion(mf), info->CAPI->GetMinorVersion(mf));
+ info->CAPI->DisplaySatus(mf, buffer);
+ if (info->CAPI->CommandExists(mf, "SET")) {
+ info->CAPI->DisplaySatus(mf, "Command SET exists");
+ }
+ if (info->CAPI->CommandExists(mf, "SET_FOO_BAR")) {
+ info->CAPI->SetError(mf, "Command SET_FOO_BAR should not exists");
+ return 0;
+ }
+ info->CAPI->AddDefineFlag(mf, "-DADDED_DEFINITION");
+
+ source_file = info->CAPI->CreateNewSourceFile(mf);
+ cstr = info->CAPI->SourceFileGetSourceName(source_file);
+ sprintf(buffer, "Should be empty (source file name): [%s]", cstr);
+ info->CAPI->DisplaySatus(mf, buffer);
+ cstr = info->CAPI->SourceFileGetFullPath(source_file);
+ sprintf(buffer, "Should be empty (source file full path): [%s]", cstr);
+ info->CAPI->DisplaySatus(mf, buffer);
+ info->CAPI->DefineSourceFileProperty(mf, "SOME_PROPERTY", "unused old prop",
+ "This property is no longer used", 0);
+ if (info->CAPI->SourceFileGetPropertyAsBool(source_file, "SOME_PROPERTY")) {
+ info->CAPI->SetError(mf, "Property SOME_PROPERTY should not be defined");
+ return 0;
+ }
+ info->CAPI->DefineSourceFileProperty(mf, "SOME_PROPERTY2", "nice prop",
+ "This property is for testing.", 0);
+ info->CAPI->SourceFileSetProperty(source_file, "SOME_PROPERTY2", "HERE");
+ cstr = info->CAPI->SourceFileGetProperty(source_file, "ABSTRACT");
+ sprintf(buffer, "Should be 0 (source file abstract property): [%p]", cstr);
+ info->CAPI->DisplaySatus(mf, buffer);
+
+ info->CAPI->DestroySourceFile(source_file);
+
+ srcs = argv[2];
+ info->CAPI->AddExecutable(mf, "LoadedCommand", 1, &srcs, 0);
+
+ /* add customs commands to generate the source file */
+ ccArgs[0] = "-E";
+ ccArgs[1] = "copy";
+ ccArgs[2] = argv[0];
+ ccArgs[3] = argv[1];
+ ccDep[0] = ccArgs[2];
+ ccOut[0] = ccArgs[3];
+ info->CAPI->AddCustomCommand(mf, "LoadedCommand.cxx.in", file, 4, ccArgs, 1,
+ ccDep, 1, ccOut, "LoadedCommand");
+
+ ccArgs[2] = argv[1];
+ ccArgs[3] = argv[2];
+ ccDep[0] = ccArgs[2];
+ ccOut[0] = ccArgs[3];
+ info->CAPI->AddCustomCommandToOutput(mf, ccOut[0], file, 4, ccArgs, ccDep[0],
+ 0, 0);
+
+ ccArgs[1] = "echo";
+ ccArgs[2] = "Build has finished";
+ info->CAPI->AddCustomCommandToTarget(mf, "LoadedCommand", file, 3, ccArgs,
+ CM_POST_BUILD);
+
+ info->CAPI->Free(file);
+
+ args[0] = "TEST_EXEC";
+ args[1] = "TRUE";
+
+ /* code coverage */
+ if (info->CAPI->GetTotalArgumentSize(2, args) != 13) {
+ return 0;
+ }
+ info->CAPI->ExecuteCommand(mf, "SET", 2, args);
+
+ /* make sure we can find the source file */
+ if (!info->CAPI->GetSource(mf, argv[1])) {
+ info->CAPI->SetError(mf, "Source file could not be found!");
+ return 0;
+ }
+
+ return 1;
+}
+
+static void CCONV FinalPass(void* inf, void* mf)
+{
+ cmLoadedCommandInfo* info = (cmLoadedCommandInfo*)inf;
+ /* get our client data from initial pass */
+ cmVTKWrapTclData* cdata = (cmVTKWrapTclData*)info->CAPI->GetClientData(info);
+ if (strcmp(info->CAPI->GetDefinition(mf, "TEST_DEF"), "HOO") ||
+ strcmp(cdata->LibraryName, "HOO")) {
+ fprintf(stderr, "*** Failed LOADED COMMAND Final Pass\n");
+ }
+}
+static void CCONV Destructor(void* inf)
+{
+ cmLoadedCommandInfo* info = (cmLoadedCommandInfo*)inf;
+ /* get our client data from initial pass */
+ cmVTKWrapTclData* cdata = (cmVTKWrapTclData*)info->CAPI->GetClientData(info);
+ free(cdata);
+}
+
+#ifdef MUCHO_MUDSLIDE
+void CM_PLUGIN_EXPORT CCONV CMAKE_TEST_COMMANDInit(cmLoadedCommandInfo* info)
+{
+ info->InitialPass = InitialPass;
+ info->FinalPass = FinalPass;
+ info->Destructor = Destructor;
+ info->m_Inherited = 0;
+ info->Name = "CMAKE_TEST_COMMAND";
+}
+#endif
diff --git a/Tests/LoadCommandOneConfig/CMakeLists.txt b/Tests/LoadCommandOneConfig/CMakeLists.txt
new file mode 100644
index 0000000..fef4bb7
--- /dev/null
+++ b/Tests/LoadCommandOneConfig/CMakeLists.txt
@@ -0,0 +1,58 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(LoadCommand)
+
+# set a definition
+set (TEST_COMMAND_TEST1 1)
+
+include (${CMAKE_ROOT}/Modules/CheckTypeSize.cmake)
+CHECK_TYPE_SIZE(char SIZEOF_CHAR)
+CHECK_TYPE_SIZE(short SIZEOF_SHORT)
+
+include (${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake)
+CHECK_INCLUDE_FILE("sys/prctl.h" HAVE_SYS_PRCTL_H)
+
+include (${CMAKE_ROOT}/Modules/CheckLibraryExists.cmake)
+CHECK_LIBRARY_EXISTS(m ceil "" HAVE_LIBM)
+
+configure_file(${LoadCommand_SOURCE_DIR}/LoadedCommand.h.in
+ ${LoadCommand_BINARY_DIR}/LoadedCommand.h)
+
+include_directories(${LoadCommand_BINARY_DIR})
+
+# try to compile the command
+# make sure it is not already loaded
+if(COMMAND CMAKE_TEST_COMMAND)
+else()
+ try_compile(COMPILE_OK
+ ${LoadCommand_BINARY_DIR}/CMakeCommands
+ ${LoadCommand_SOURCE_DIR}/CMakeCommands
+ CMAKE_LOADED_COMMANDS CMAKE_FLAGS -DMUDSLIDE_TYPE:STRING=MUCHO
+ OUTPUT_VARIABLE OUTPUT )
+endif()
+
+message("Output from try compile: ${OUTPUT}")
+
+# if the compile was OK, try loading the command
+if (COMPILE_OK)
+ load_command(CMAKE_TEST_COMMAND
+ ${LoadCommand_BINARY_DIR}/CMakeCommands
+ ${LoadCommand_BINARY_DIR}/CMakeCommands/Debug
+ ${LoadCommand_BINARY_DIR}/CMakeCommands/Development
+ )
+ # if the command loaded, execute the command
+ if (COMMAND CMAKE_TEST_COMMAND)
+ CMAKE_TEST_COMMAND(
+ "${LoadCommand_SOURCE_DIR}/LoadedCommand.cxx.in"
+ "${LoadCommand_BINARY_DIR}/LoadedCommand2.cxx.in"
+ "${LoadCommand_BINARY_DIR}/LoadedCommand3.cxx"
+ )
+ endif ()
+else ()
+ message("failed to compile CMAKE_LOADED_COMMANDS")
+endif ()
+
+# TEST_DEF is set by the loaded command cmTestCommand.c
+if (TEST_DEF AND SOME_CACHE_VARIABLE AND TEST_EXEC)
+ add_definitions(-DCMAKE_IS_FUN)
+endif ()
+
diff --git a/Tests/LoadCommandOneConfig/LoadedCommand.cxx.in b/Tests/LoadCommandOneConfig/LoadedCommand.cxx.in
new file mode 100644
index 0000000..72ec014
--- /dev/null
+++ b/Tests/LoadCommandOneConfig/LoadedCommand.cxx.in
@@ -0,0 +1,32 @@
+#include "LoadedCommand.h"
+#include <stdio.h>
+
+int testSizeOf(int s1, int s2)
+{
+ return s1 - s2;
+}
+
+int main ()
+{
+ int ret = 0;
+
+#if !defined( ADDED_DEFINITION )
+ printf("Should have ADDED_DEFINITION defined\n");
+ ret= 1;
+#endif
+#if !defined(CMAKE_IS_FUN)
+ printf("Loaded Command was not built with CMAKE_IS_FUN: failed.\n");
+ ret = 1;
+#endif
+ if(testSizeOf(SIZEOF_CHAR, sizeof(char)))
+ {
+ printf("Size of char is broken.\n");
+ ret = 1;
+ }
+ if(testSizeOf(SIZEOF_SHORT, sizeof(short)))
+ {
+ printf("Size of short is broken.\n");
+ ret = 1;
+ }
+ return ret;
+}
diff --git a/Tests/LoadCommandOneConfig/LoadedCommand.h.in b/Tests/LoadCommandOneConfig/LoadedCommand.h.in
new file mode 100644
index 0000000..d748d06
--- /dev/null
+++ b/Tests/LoadCommandOneConfig/LoadedCommand.h.in
@@ -0,0 +1,9 @@
+/* Check for size of types */
+#cmakedefine SIZEOF_CHAR ${SIZEOF_CHAR}
+#cmakedefine SIZEOF_SHORT ${SIZEOF_SHORT}
+
+/* Check for headers */
+#cmakedefine HAVE_SYS_PRCTL_H
+
+/* Check for libraries */
+#cmakedefine HAVE_LIBM
diff --git a/Tests/MFC/CMakeLists.txt b/Tests/MFC/CMakeLists.txt
new file mode 100644
index 0000000..d17b955
--- /dev/null
+++ b/Tests/MFC/CMakeLists.txt
@@ -0,0 +1,61 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(mfc_driver)
+
+include(CTest)
+include(ExternalProject)
+
+
+set(CMAKE_MFC_FLAG_VALUE "2")
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt.in
+ ${CMAKE_CURRENT_BINARY_DIR}/CMakeLists.SharedMfcDll.txt
+ @ONLY
+ )
+
+ExternalProject_Add(mfcShared
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/mfc1
+ PATCH_COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_BINARY_DIR}/CMakeLists.SharedMfcDll.txt
+ <SOURCE_DIR>/CMakeLists.txt
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ )
+
+
+set(CMAKE_MFC_FLAG_VALUE "1")
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt.in
+ ${CMAKE_CURRENT_BINARY_DIR}/CMakeLists.StaticMfcLib.txt
+ @ONLY
+ )
+
+ExternalProject_Add(mfcStatic
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/mfc1
+ PATCH_COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_BINARY_DIR}/CMakeLists.StaticMfcLib.txt
+ <SOURCE_DIR>/CMakeLists.txt
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+ )
+
+
+set(binary_dir "${CMAKE_CURRENT_BINARY_DIR}")
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/ValidateBuild.cmake.in
+ ${CMAKE_CURRENT_BINARY_DIR}/ValidateBuild.cmake
+ @ONLY
+ )
+add_test(
+ NAME validate
+ COMMAND ${CMAKE_COMMAND}
+ -P "${CMAKE_CURRENT_BINARY_DIR}/ValidateBuild.cmake"
+ )
+
+
+add_test(
+ NAME environment
+ COMMAND ${CMAKE_COMMAND} -E environment
+ )
+
+
+message(STATUS "===== environment =====")
+execute_process(COMMAND ${CMAKE_COMMAND} -E environment)
+message(STATUS "===== /environment =====")
diff --git a/Tests/MFC/CMakeLists.txt.in b/Tests/MFC/CMakeLists.txt.in
new file mode 100644
index 0000000..a600c63
--- /dev/null
+++ b/Tests/MFC/CMakeLists.txt.in
@@ -0,0 +1,70 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(mfc1)
+
+macro(replace_flags var these those)
+ if("${${var}}" MATCHES "${these}")
+ string(REGEX REPLACE "${these}" "${those}" ${var} "${${var}}")
+ #message(STATUS "info: ${var} changed to '${${var}}'")
+ endif()
+ message(STATUS "info: ${var}='${${var}}'")
+endmacro()
+
+macro(msvc_link_to_static_crt)
+ if(MSVC)
+ set(has_correct_flag 0)
+ foreach(lang C CXX)
+ foreach(suffix "" _DEBUG _MINSIZEREL _RELEASE _RELWITHDEBINFO)
+ replace_flags("CMAKE_${lang}_FLAGS${suffix}" "/MD" "/MT")
+ if(CMAKE_${lang}_FLAGS${suffix} MATCHES "/MT")
+ set(has_correct_flag 1)
+ endif()
+ endforeach()
+ endforeach()
+ if(NOT has_correct_flag)
+ message(FATAL_ERROR "no CMAKE_*_FLAGS var contains /MT")
+ endif()
+ endif()
+endmacro()
+
+set(files
+ ChildFrm.cpp
+ ChildFrm.h
+ MainFrm.cpp
+ MainFrm.h
+ mfc1.cpp
+ mfc1.h
+ mfc1.rc
+ mfc1Doc.cpp
+ mfc1Doc.h
+ mfc1View.cpp
+ mfc1View.h
+ Resource.h
+ stdafx.cpp
+ stdafx.h
+)
+
+set(CMAKE_MFC_FLAG "@CMAKE_MFC_FLAG_VALUE@")
+
+FIND_PACKAGE(MFC)
+IF (NOT MFC_FOUND)
+ MESSAGE(FATAL_ERROR "MFC Could not be found during the MFC test")
+ENDIF()
+
+if("${CMAKE_MFC_FLAG}" STREQUAL "1")
+ msvc_link_to_static_crt()
+else()
+ # VS generators add this automatically based on the CMAKE_MFC_FLAG value,
+ # but generators matching "Make" require:
+ add_definitions(-D_AFXDLL)
+endif()
+
+add_executable(mfc1 WIN32 ${files})
+install(TARGETS mfc1 DESTINATION bin)
+
+if("${CMAKE_MFC_FLAG}" STREQUAL "2")
+ set(CMAKE_INSTALL_MFC_LIBRARIES ON)
+ include(InstallRequiredSystemLibraries)
+endif()
+
+# Encode the value inside a generator expression to test evaluation.
+set(CMAKE_MFC_FLAG "$<1:${CMAKE_MFC_FLAG}>")
diff --git a/Tests/MFC/ValidateBuild.cmake.in b/Tests/MFC/ValidateBuild.cmake.in
new file mode 100644
index 0000000..ed923f5
--- /dev/null
+++ b/Tests/MFC/ValidateBuild.cmake.in
@@ -0,0 +1,68 @@
+#
+# This code validates that the install trees of the shared and static builds
+# of "mfc1" have the expected contents:
+#
+set(binary_dir "@binary_dir@")
+message("binary_dir='${binary_dir}'")
+
+# There should be exactly one file in the static install tree "bin" directory
+# and it should be named "mfc1.exe"
+#
+message(STATUS "===== mfcStatic install tree =====")
+file(GLOB_RECURSE files "${binary_dir}/mfcStatic-prefix/bin/*.*")
+message(STATUS "mfcStatic files='${files}'")
+list(LENGTH files len)
+if(NOT len EQUAL 1)
+ message(FATAL_ERROR
+ "len='${len}' is not '1' (count of static 'bin' files)")
+endif()
+get_filename_component(name "${files}" NAME)
+string(TOLOWER "${name}" name)
+if(NOT "${name}" STREQUAL "mfc1.exe")
+ message(FATAL_ERROR "unexpected mfcStatic file name '${name}'")
+endif()
+
+# There should be at least 3 files in the shared install tree "bin"
+# directory: mfc1.exe, the main MFC dll and the C runtime dll. With more
+# recent versions of VS, there will also be an MFC language dll and a
+# manifest file.
+#
+message(STATUS "===== mfcShared install tree =====")
+file(GLOB_RECURSE files "${binary_dir}/mfcShared-prefix/bin/*.*")
+message(STATUS "mfcShared files='${files}'")
+list(LENGTH files len)
+
+set(msvc6 "@MSVC60@")
+if("${msvc6}" STREQUAL "1")
+ set(expected_minimum_file_count 1)
+else()
+ set(expected_minimum_file_count 3)
+endif()
+
+if(len LESS ${expected_minimum_file_count})
+ message(FATAL_ERROR
+ "len='${len}' is less than '${expected_minimum_file_count}' (count of shared 'bin' files)")
+endif()
+foreach(f ${files})
+ message(STATUS "file '${f}'")
+ get_filename_component(ext "${f}" EXT)
+ string(TOLOWER "${ext}" ext)
+
+ if("${ext}" MATCHES "\\.exe$")
+ message(STATUS " exe file")
+ get_filename_component(name "${f}" NAME)
+ string(TOLOWER "${name}" name)
+ if(NOT "${name}" STREQUAL "mfc1.exe")
+ message(FATAL_ERROR "unexpected mfcShared .exe file name '${name}'")
+ endif()
+ elseif("${ext}" MATCHES "\\.dll$")
+ message(STATUS " dll file")
+ elseif("${ext}" MATCHES "\\.manifest$")
+ message(STATUS " manifest file")
+ else()
+ message(STATUS " unknown file")
+ message(FATAL_ERROR "unexpected mfcShared ${ext} file name '${f}'")
+ endif()
+endforeach()
+
+message(STATUS "All mfc1 build validation tests pass.")
diff --git a/Tests/MFC/mfc1/ChildFrm.cpp b/Tests/MFC/mfc1/ChildFrm.cpp
new file mode 100644
index 0000000..0422d2a
--- /dev/null
+++ b/Tests/MFC/mfc1/ChildFrm.cpp
@@ -0,0 +1,59 @@
+// ChildFrm.cpp : implementation of the CChildFrame class
+//
+
+// clang-format off
+#include "stdafx.h"
+
+#include "mfc1.h"
+
+#include "ChildFrm.h"
+// clang-format on
+
+#ifdef _DEBUG
+# define new DEBUG_NEW
+#endif
+
+// CChildFrame
+
+IMPLEMENT_DYNCREATE(CChildFrame, CMDIChildWnd)
+
+BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWnd)
+END_MESSAGE_MAP()
+
+// CChildFrame construction/destruction
+
+CChildFrame::CChildFrame()
+{
+ // TODO: add member initialization code here
+}
+
+CChildFrame::~CChildFrame()
+{
+}
+
+BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
+{
+ // TODO: Modify the Window class or styles here by modifying the CREATESTRUCT
+ // cs
+ if (!CMDIChildWnd::PreCreateWindow(cs))
+ return FALSE;
+
+ return TRUE;
+}
+
+// CChildFrame diagnostics
+
+#ifdef _DEBUG
+void CChildFrame::AssertValid() const
+{
+ CMDIChildWnd::AssertValid();
+}
+
+void CChildFrame::Dump(CDumpContext& dc) const
+{
+ CMDIChildWnd::Dump(dc);
+}
+
+#endif //_DEBUG
+
+// CChildFrame message handlers
diff --git a/Tests/MFC/mfc1/ChildFrm.h b/Tests/MFC/mfc1/ChildFrm.h
new file mode 100644
index 0000000..eedf4d1
--- /dev/null
+++ b/Tests/MFC/mfc1/ChildFrm.h
@@ -0,0 +1,30 @@
+// ChildFrm.h : interface of the CChildFrame class
+//
+
+#pragma once
+
+class CChildFrame : public CMDIChildWnd
+{
+ DECLARE_DYNCREATE(CChildFrame)
+public:
+ CChildFrame();
+
+ // Attributes
+public:
+ // Operations
+public:
+ // Overrides
+ virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
+
+ // Implementation
+public:
+ virtual ~CChildFrame();
+#ifdef _DEBUG
+ virtual void AssertValid() const;
+ virtual void Dump(CDumpContext& dc) const;
+#endif
+
+ // Generated message map functions
+protected:
+ DECLARE_MESSAGE_MAP()
+};
diff --git a/Tests/MFC/mfc1/MainFrm.cpp b/Tests/MFC/mfc1/MainFrm.cpp
new file mode 100644
index 0000000..7f82e26
--- /dev/null
+++ b/Tests/MFC/mfc1/MainFrm.cpp
@@ -0,0 +1,96 @@
+// MainFrm.cpp : implementation of the CMainFrame class
+//
+
+// clang-format off
+#include "stdafx.h"
+
+#include "mfc1.h"
+
+#include "MainFrm.h"
+// clang-format on
+
+#ifdef _DEBUG
+# define new DEBUG_NEW
+#endif
+
+// CMainFrame
+
+IMPLEMENT_DYNAMIC(CMainFrame, CMDIFrameWnd)
+
+BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
+ON_WM_CREATE()
+END_MESSAGE_MAP()
+
+static UINT indicators[] = {
+ ID_SEPARATOR, // status line indicator
+ ID_INDICATOR_CAPS,
+ ID_INDICATOR_NUM,
+ ID_INDICATOR_SCRL,
+};
+
+// CMainFrame construction/destruction
+
+CMainFrame::CMainFrame()
+{
+ // TODO: add member initialization code here
+}
+
+CMainFrame::~CMainFrame()
+{
+}
+
+int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
+{
+ if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
+ return -1;
+
+ if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT,
+ WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER |
+ CBRS_TOOLTIPS | CBRS_FLYBY |
+ CBRS_SIZE_DYNAMIC) ||
+ !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) {
+ TRACE0("Failed to create toolbar\n");
+ return -1; // fail to create
+ }
+
+ if (!m_wndStatusBar.Create(this) ||
+ !m_wndStatusBar.SetIndicators(indicators,
+ sizeof(indicators) / sizeof(UINT))) {
+ TRACE0("Failed to create status bar\n");
+ return -1; // fail to create
+ }
+ // TODO: Delete these three lines if you don't want the toolbar to be
+ // dockable
+ m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
+ EnableDocking(CBRS_ALIGN_ANY);
+ DockControlBar(&m_wndToolBar);
+
+ return 0;
+}
+
+BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
+{
+ if (!CMDIFrameWnd::PreCreateWindow(cs))
+ return FALSE;
+ // TODO: Modify the Window class or styles here by modifying
+ // the CREATESTRUCT cs
+
+ return TRUE;
+}
+
+// CMainFrame diagnostics
+
+#ifdef _DEBUG
+void CMainFrame::AssertValid() const
+{
+ CMDIFrameWnd::AssertValid();
+}
+
+void CMainFrame::Dump(CDumpContext& dc) const
+{
+ CMDIFrameWnd::Dump(dc);
+}
+
+#endif //_DEBUG
+
+// CMainFrame message handlers
diff --git a/Tests/MFC/mfc1/MainFrm.h b/Tests/MFC/mfc1/MainFrm.h
new file mode 100644
index 0000000..3b965c9
--- /dev/null
+++ b/Tests/MFC/mfc1/MainFrm.h
@@ -0,0 +1,35 @@
+// MainFrm.h : interface of the CMainFrame class
+//
+
+#pragma once
+class CMainFrame : public CMDIFrameWnd
+{
+ DECLARE_DYNAMIC(CMainFrame)
+public:
+ CMainFrame();
+
+ // Attributes
+public:
+ // Operations
+public:
+ // Overrides
+public:
+ virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
+
+ // Implementation
+public:
+ virtual ~CMainFrame();
+#ifdef _DEBUG
+ virtual void AssertValid() const;
+ virtual void Dump(CDumpContext& dc) const;
+#endif
+
+protected: // control bar embedded members
+ CStatusBar m_wndStatusBar;
+ CToolBar m_wndToolBar;
+
+ // Generated message map functions
+protected:
+ afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
+ DECLARE_MESSAGE_MAP()
+};
diff --git a/Tests/MFC/mfc1/ReadMe.txt b/Tests/MFC/mfc1/ReadMe.txt
new file mode 100644
index 0000000..d84608e
--- /dev/null
+++ b/Tests/MFC/mfc1/ReadMe.txt
@@ -0,0 +1,135 @@
+================================================================================
+ MICROSOFT FOUNDATION CLASS LIBRARY : mfc1 Project Overview
+===============================================================================
+
+The application wizard has created this mfc1 application for
+you. This application not only demonstrates the basics of using the Microsoft
+Foundation Classes but is also a starting point for writing your application.
+
+This file contains a summary of what you will find in each of the files that
+make up your mfc1 application.
+
+mfc1.vcproj
+ This is the main project file for VC++ projects generated using an application wizard.
+ It contains information about the version of Visual C++ that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ application wizard.
+
+mfc1.h
+ This is the main header file for the application. It includes other
+ project specific headers (including Resource.h) and declares the
+ Cmfc1App application class.
+
+mfc1.cpp
+ This is the main application source file that contains the application
+ class Cmfc1App.
+
+mfc1.rc
+ This is a listing of all of the Microsoft Windows resources that the
+ program uses. It includes the icons, bitmaps, and cursors that are stored
+ in the RES subdirectory. This file can be directly edited in Microsoft
+ Visual C++. Your project resources are in 1033.
+
+res\mfc1.ico
+ This is an icon file, which is used as the application's icon. This
+ icon is included by the main resource file mfc1.rc.
+
+res\mfc1.rc2
+ This file contains resources that are not edited by Microsoft
+ Visual C++. You should place all resources not editable by
+ the resource editor in this file.
+mfc1.reg
+ This is an example .reg file that shows you the kind of registration
+ settings the framework will set for you. You can use this as a .reg
+ file to go along with your application or just delete it and rely
+ on the default RegisterShellFileTypes registration.
+/////////////////////////////////////////////////////////////////////////////
+
+For the main frame window:
+ The project includes a standard MFC interface.
+MainFrm.h, MainFrm.cpp
+ These files contain the frame class CMainFrame, which is derived from
+ CMDIFrameWnd and controls all MDI frame features.
+res\Toolbar.bmp
+ This bitmap file is used to create tiled images for the toolbar.
+ The initial toolbar and status bar are constructed in the CMainFrame
+ class. Edit this toolbar bitmap using the resource editor, and
+ update the IDR_MAINFRAME TOOLBAR array in mfc1.rc to add
+ toolbar buttons.
+/////////////////////////////////////////////////////////////////////////////
+
+For the child frame window:
+
+ChildFrm.h, ChildFrm.cpp
+ These files define and implement the CChildFrame class, which
+ supports the child windows in an MDI application.
+
+/////////////////////////////////////////////////////////////////////////////
+
+The application wizard creates one document type and one view:
+
+mfc1Doc.h, mfc1Doc.cpp - the document
+ These files contain your Cmfc1Doc class. Edit these files to
+ add your special document data and to implement file saving and loading
+ (via Cmfc1Doc::Serialize).
+ The Document will have the following strings:
+ File extension: mf1
+ File type ID: mfc1.Document
+ Main frame caption: mfc1
+ Doc type name: mfc1
+ Filter name: mfc1 Files (*.mf1)
+ File new short name: mfc1
+ File type long name: mfc1.Document
+mfc1View.h, mfc1View.cpp - the view of the document
+ These files contain your Cmfc1View class.
+ Cmfc1View objects are used to view Cmfc1Doc objects.
+res\mfc1Doc.ico
+ This is an icon file, which is used as the icon for MDI child windows
+ for the Cmfc1Doc class. This icon is included by the main
+ resource file mfc1.rc.
+/////////////////////////////////////////////////////////////////////////////
+
+Other Features:
+
+ActiveX Controls
+ The application includes support to use ActiveX controls.
+
+Printing and Print Preview support
+ The application wizard has generated code to handle the print, print setup, and print preview
+ commands by calling member functions in the CView class from the MFC library.
+/////////////////////////////////////////////////////////////////////////////
+
+Other standard files:
+
+StdAfx.h, StdAfx.cpp
+ These files are used to build a precompiled header (PCH) file
+ named mfc1.pch and a precompiled types file named StdAfx.obj.
+
+Resource.h
+ This is the standard header file, which defines new resource IDs.
+ Microsoft Visual C++ reads and updates this file.
+
+mfc1.manifest
+ Application manifest files are used by Windows XP to describe an applications
+ dependency on specific versions of Side-by-Side assemblies. The loader uses this
+ information to load the appropriate assembly from the assembly cache or private
+ from the application. The Application manifest maybe included for redistribution
+ as an external .manifest file that is installed in the same folder as the application
+ executable or it may be included in the executable in the form of a resource.
+/////////////////////////////////////////////////////////////////////////////
+
+Other notes:
+
+The application wizard uses "TODO:" to indicate parts of the source code you
+should add to or customize.
+
+If your application uses MFC in a shared DLL, and your application is in a
+language other than the operating system's current language, you will need
+to copy the corresponding localized resources MFC70XXX.DLL from the Microsoft
+Visual C++ CD-ROM under the Win\System directory to your computer's system or
+system32 directory, and rename it to be MFCLOC.DLL. ("XXX" stands for the
+language abbreviation. For example, MFC70DEU.DLL contains resources
+translated to German.) If you don't do this, some of the UI elements of
+your application will remain in the language of the operating system.
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/Tests/MFC/mfc1/Resource.h b/Tests/MFC/mfc1/Resource.h
new file mode 100644
index 0000000..e3a04f1
--- /dev/null
+++ b/Tests/MFC/mfc1/Resource.h
@@ -0,0 +1,20 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by mfc1.rc
+//
+#define IDD_ABOUTBOX 100
+#define IDP_OLE_INIT_FAILED 100
+#define IDR_MAINFRAME 128
+#define IDR_mfc1TYPE 129
+#define IDR_MANIFEST CREATEPROCESS_MANIFEST_RESOURCE_ID
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+# ifndef APSTUDIO_READONLY_SYMBOLS
+# define _APS_NEXT_RESOURCE_VALUE 130
+# define _APS_NEXT_CONTROL_VALUE 1000
+# define _APS_NEXT_SYMED_VALUE 101
+# define _APS_NEXT_COMMAND_VALUE 32771
+# endif
+#endif
diff --git a/Tests/MFC/mfc1/mfc1.cpp b/Tests/MFC/mfc1/mfc1.cpp
new file mode 100644
index 0000000..87406b6
--- /dev/null
+++ b/Tests/MFC/mfc1/mfc1.cpp
@@ -0,0 +1,144 @@
+// mfc1.cpp : Defines the class behaviors for the application.
+//
+
+// clang-format off
+#include "stdafx.h"
+
+#include "MainFrm.h"
+#include "mfc1.h"
+
+#include "ChildFrm.h"
+#include "mfc1Doc.h"
+#include "mfc1View.h"
+// clang-format on
+
+#ifdef _DEBUG
+# define new DEBUG_NEW
+#endif
+
+// Cmfc1App
+
+BEGIN_MESSAGE_MAP(Cmfc1App, CWinApp)
+ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
+// Standard file based document commands
+ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
+ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
+// Standard print setup command
+ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
+END_MESSAGE_MAP()
+
+// Cmfc1App construction
+
+Cmfc1App::Cmfc1App()
+{
+ // TODO: add construction code here,
+ // Place all significant initialization in InitInstance
+}
+
+// The one and only Cmfc1App object
+
+Cmfc1App theApp;
+
+// Cmfc1App initialization
+
+BOOL Cmfc1App::InitInstance()
+{
+ // InitCommonControls() is required on Windows XP if an application
+ // manifest specifies use of ComCtl32.dll version 6 or later to enable
+ // visual styles. Otherwise, any window creation will fail.
+ InitCommonControls();
+
+ CWinApp::InitInstance();
+
+ // Initialize OLE libraries
+ if (!AfxOleInit()) {
+ AfxMessageBox(IDP_OLE_INIT_FAILED);
+ return FALSE;
+ }
+ AfxEnableControlContainer();
+ // Standard initialization
+ // If you are not using these features and wish to reduce the size
+ // of your final executable, you should remove from the following
+ // the specific initialization routines you do not need
+ // Change the registry key under which our settings are stored
+ // TODO: You should modify this string to be something appropriate
+ // such as the name of your company or organization
+ SetRegistryKey(_T("Local AppWizard-Generated Applications"));
+ LoadStdProfileSettings(4); // Load standard INI file options (including MRU)
+ // Register the application's document templates. Document templates
+ // serve as the connection between documents, frame windows and views
+ CMultiDocTemplate* pDocTemplate;
+ pDocTemplate =
+ new CMultiDocTemplate(IDR_mfc1TYPE, RUNTIME_CLASS(Cmfc1Doc),
+ RUNTIME_CLASS(CChildFrame), // custom MDI child frame
+ RUNTIME_CLASS(Cmfc1View));
+ if (!pDocTemplate)
+ return FALSE;
+ AddDocTemplate(pDocTemplate);
+ // create main MDI Frame window
+ CMainFrame* pMainFrame = new CMainFrame;
+ if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))
+ return FALSE;
+ m_pMainWnd = pMainFrame;
+ // call DragAcceptFiles only if there's a suffix
+ // In an MDI app, this should occur immediately after setting m_pMainWnd
+ // Enable drag/drop open
+ m_pMainWnd->DragAcceptFiles();
+ // Enable DDE Execute open
+ EnableShellOpen();
+ RegisterShellFileTypes(TRUE);
+ // Parse command line for standard shell commands, DDE, file open
+ CCommandLineInfo cmdInfo;
+ ParseCommandLine(cmdInfo);
+ // Dispatch commands specified on the command line. Will return FALSE if
+ // app was launched with /RegServer, /Register, /Unregserver or /Unregister.
+ if (!ProcessShellCommand(cmdInfo))
+ return FALSE;
+ // The main window has been initialized, so show and update it
+ pMainFrame->ShowWindow(m_nCmdShow);
+ pMainFrame->UpdateWindow();
+ return TRUE;
+}
+
+// CAboutDlg dialog used for App About
+
+class CAboutDlg : public CDialog
+{
+public:
+ CAboutDlg();
+
+ // Dialog Data
+ enum
+ {
+ IDD = IDD_ABOUTBOX
+ };
+
+protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+
+ // Implementation
+protected:
+ DECLARE_MESSAGE_MAP()
+};
+
+CAboutDlg::CAboutDlg()
+ : CDialog(CAboutDlg::IDD)
+{
+}
+
+void CAboutDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+}
+
+BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
+END_MESSAGE_MAP()
+
+// App command to run the dialog
+void Cmfc1App::OnAppAbout()
+{
+ CAboutDlg aboutDlg;
+ aboutDlg.DoModal();
+}
+
+// Cmfc1App message handlers
diff --git a/Tests/MFC/mfc1/mfc1.h b/Tests/MFC/mfc1/mfc1.h
new file mode 100644
index 0000000..f4fcadb
--- /dev/null
+++ b/Tests/MFC/mfc1/mfc1.h
@@ -0,0 +1,29 @@
+// mfc1.h : main header file for the mfc1 application
+//
+#pragma once
+
+#ifndef __AFXWIN_H__
+# error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "resource.h" // main symbols
+
+// Cmfc1App:
+// See mfc1.cpp for the implementation of this class
+//
+
+class Cmfc1App : public CWinApp
+{
+public:
+ Cmfc1App();
+
+ // Overrides
+public:
+ virtual BOOL InitInstance();
+
+ // Implementation
+ afx_msg void OnAppAbout();
+ DECLARE_MESSAGE_MAP()
+};
+
+extern Cmfc1App theApp;
diff --git a/Tests/MFC/mfc1/mfc1.rc b/Tests/MFC/mfc1/mfc1.rc
new file mode 100644
index 0000000..346c5fb
--- /dev/null
+++ b/Tests/MFC/mfc1/mfc1.rc
@@ -0,0 +1,393 @@
+//Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+#ifdef APSTUDIO_INVOKED
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+ "#define _AFX_NO_OLE_RESOURCES\r\n"
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+ "\r\n"
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
+ "LANGUAGE 9, 1\r\n"
+ "#pragma code_page(1252)\r\n"
+ "#include ""res\\mfc1.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
+ "#include ""afxres.rc"" // Standard components\r\n"
+ "#include ""afxprint.rc"" // printing/print preview resources\r\n"
+ "#endif\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE 9, 1
+#pragma code_page(1252)
+IDR_MAINFRAME ICON "res\\mfc1.ico"
+IDR_mfc1TYPE ICON "res\\mfc1Doc.ico"
+#endif
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDR_MAINFRAME BITMAP "res\\Toolbar.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Toolbar
+//
+
+IDR_MAINFRAME TOOLBAR 16, 15
+BEGIN
+ BUTTON ID_FILE_NEW
+ BUTTON ID_FILE_OPEN
+ BUTTON ID_FILE_SAVE
+ SEPARATOR
+ BUTTON ID_EDIT_CUT
+ BUTTON ID_EDIT_COPY
+ BUTTON ID_EDIT_PASTE
+ SEPARATOR
+ BUTTON ID_FILE_PRINT
+ BUTTON ID_APP_ABOUT
+END
+
+
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE 9, 1
+#pragma code_page(1252)
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MAINFRAME MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&New\tCtrl+N", ID_FILE_NEW
+ MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN
+ MENUITEM SEPARATOR
+ MENUITEM "P&rint Setup...", ID_FILE_PRINT_SETUP
+ MENUITEM SEPARATOR
+ MENUITEM "Recent File", ID_FILE_MRU_FILE1,GRAYED
+ MENUITEM SEPARATOR
+ MENUITEM "&Close", ID_FILE_CLOSE
+ MENUITEM "E&xit", ID_APP_EXIT
+ END
+ POPUP "&View"
+ BEGIN
+ MENUITEM "&Toolbar", ID_VIEW_TOOLBAR
+ MENUITEM "&Status Bar", ID_VIEW_STATUS_BAR
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&About mfc1...", ID_APP_ABOUT
+ END
+END
+IDR_mfc1TYPE MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&New\tCtrl+N", ID_FILE_NEW
+ MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN
+ MENUITEM "&Close", ID_FILE_CLOSE
+ MENUITEM "&Save\tCtrl+S", ID_FILE_SAVE
+ MENUITEM "Save &As...", ID_FILE_SAVE_AS
+ MENUITEM SEPARATOR
+ MENUITEM "&Print...\tCtrl+P", ID_FILE_PRINT
+ MENUITEM "Print Pre&view", ID_FILE_PRINT_PREVIEW
+ MENUITEM "P&rint Setup...", ID_FILE_PRINT_SETUP
+ MENUITEM SEPARATOR
+ MENUITEM "Recent File", ID_FILE_MRU_FILE1,GRAYED
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", ID_APP_EXIT
+ END
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "&Undo\tCtrl+Z", ID_EDIT_UNDO
+ MENUITEM SEPARATOR
+ MENUITEM "Cu&t\tCtrl+X", ID_EDIT_CUT
+ MENUITEM "&Copy\tCtrl+C", ID_EDIT_COPY
+ MENUITEM "&Paste\tCtrl+V", ID_EDIT_PASTE
+ END
+ POPUP "&View"
+ BEGIN
+ MENUITEM "&Toolbar", ID_VIEW_TOOLBAR
+ MENUITEM "&Status Bar", ID_VIEW_STATUS_BAR
+ END
+ POPUP "&Window"
+ BEGIN
+ MENUITEM "&New Window", ID_WINDOW_NEW
+ MENUITEM "&Cascade", ID_WINDOW_CASCADE
+ MENUITEM "&Tile", ID_WINDOW_TILE_HORZ
+ MENUITEM "&Arrange Icons", ID_WINDOW_ARRANGE
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&About mfc1...", ID_APP_ABOUT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_MAINFRAME ACCELERATORS
+BEGIN
+ "N", ID_FILE_NEW, VIRTKEY,CONTROL
+ "O", ID_FILE_OPEN, VIRTKEY,CONTROL
+ "S", ID_FILE_SAVE, VIRTKEY,CONTROL
+ "P", ID_FILE_PRINT, VIRTKEY,CONTROL
+ "Z", ID_EDIT_UNDO, VIRTKEY,CONTROL
+ "X", ID_EDIT_CUT, VIRTKEY,CONTROL
+ "C", ID_EDIT_COPY, VIRTKEY,CONTROL
+ "V", ID_EDIT_PASTE, VIRTKEY,CONTROL
+ VK_BACK, ID_EDIT_UNDO, VIRTKEY,ALT
+ VK_DELETE, ID_EDIT_CUT, VIRTKEY,SHIFT
+ VK_INSERT, ID_EDIT_COPY, VIRTKEY,CONTROL
+ VK_INSERT, ID_EDIT_PASTE, VIRTKEY,SHIFT
+ VK_F6, ID_NEXT_PANE, VIRTKEY
+ VK_F6, ID_PREV_PANE, VIRTKEY,SHIFT
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+#if _MSC_VER < 1300
+#define DS_SHELLFONT_FLAG 0
+#else
+#define DS_SHELLFONT_FLAG DS_SHELLFONT
+#endif
+
+IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55
+CAPTION "About mfc1"
+STYLE DS_MODALFRAME | DS_SHELLFONT_FLAG | WS_POPUP | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg"
+BEGIN
+ ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20
+ LTEXT "mfc1 Version 1.0",IDC_STATIC,40,10,119,8,
+ SS_NOPREFIX
+ LTEXT "Copyright (C) 2011",IDC_STATIC,40,25,119,8
+ DEFPUSHBUTTON "OK",IDOK,178,7,50,16,WS_GROUP
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904e4"
+ BEGIN
+ VALUE "CompanyName", "TODO: <Company name>"
+ VALUE "FileDescription", "TODO: <File description>"
+ VALUE "FileVersion", "1.0.0.1"
+ VALUE "InternalName", "mfc1.exe"
+ VALUE "LegalCopyright", "TODO: (c) <Company name>. All rights reserved."
+ VALUE "OriginalFilename","mfc1.exe"
+ VALUE "ProductName", "TODO: <Product name>"
+ VALUE "ProductVersion", "1.0.0.1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 1252
+ END
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_ABOUTBOX, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 228
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 48
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+// Non-mac-targeting apps remove the two extra substrings
+ IDR_MAINFRAME "mfc1"
+ // has a file suffix - shell file type too
+ IDR_mfc1TYPE "\nmfc1\nmfc1\nmfc1 Files (*.mf1)\n.mf1\nmfc1.Document\nmfc1.Document"
+END
+STRINGTABLE
+BEGIN
+ AFX_IDS_APP_TITLE "mfc1"
+ AFX_IDS_IDLEMESSAGE "Ready"
+END
+STRINGTABLE
+BEGIN
+ ID_INDICATOR_EXT "EXT"
+ ID_INDICATOR_CAPS "CAP"
+ ID_INDICATOR_NUM "NUM"
+ ID_INDICATOR_SCRL "SCRL"
+ ID_INDICATOR_OVR "OVR"
+ ID_INDICATOR_REC "REC"
+END
+STRINGTABLE
+BEGIN
+ ID_FILE_NEW "Create a new document\nNew"
+ ID_FILE_OPEN "Open an existing document\nOpen"
+ ID_FILE_CLOSE "Close the active document\nClose"
+ ID_FILE_SAVE "Save the active document\nSave"
+ ID_FILE_SAVE_AS "Save the active document with a new name\nSave As"
+ ID_FILE_PAGE_SETUP "Change the printing options\nPage Setup"
+ ID_FILE_PRINT_SETUP "Change the printer and printing options\nPrint Setup"
+ ID_FILE_PRINT "Print the active document\nPrint"
+ ID_FILE_PRINT_PREVIEW "Display full pages\nPrint Preview"
+ ID_APP_ABOUT "Display program information, version number and copyright\nAbout"
+ ID_APP_EXIT "Quit the application; prompts to save documents\nExit"
+ ID_FILE_MRU_FILE1 "Open this document"
+ ID_FILE_MRU_FILE2 "Open this document"
+ ID_FILE_MRU_FILE3 "Open this document"
+ ID_FILE_MRU_FILE4 "Open this document"
+ ID_FILE_MRU_FILE5 "Open this document"
+ ID_FILE_MRU_FILE6 "Open this document"
+ ID_FILE_MRU_FILE7 "Open this document"
+ ID_FILE_MRU_FILE8 "Open this document"
+ ID_FILE_MRU_FILE9 "Open this document"
+ ID_FILE_MRU_FILE10 "Open this document"
+ ID_FILE_MRU_FILE11 "Open this document"
+ ID_FILE_MRU_FILE12 "Open this document"
+ ID_FILE_MRU_FILE13 "Open this document"
+ ID_FILE_MRU_FILE14 "Open this document"
+ ID_FILE_MRU_FILE15 "Open this document"
+ ID_FILE_MRU_FILE16 "Open this document"
+ ID_NEXT_PANE "Switch to the next window pane\nNext Pane"
+ ID_PREV_PANE "Switch back to the previous window pane\nPrevious Pane"
+ ID_WINDOW_NEW "Open another window for the active document\nNew Window"
+ ID_WINDOW_ARRANGE "Arrange icons at the bottom of the window\nArrange Icons"
+ ID_WINDOW_CASCADE "Arrange windows so they overlap\nCascade Windows"
+ ID_WINDOW_TILE_HORZ "Arrange windows as non-overlapping tiles\nTile Windows"
+ ID_WINDOW_TILE_VERT "Arrange windows as non-overlapping tiles\nTile Windows"
+ ID_WINDOW_SPLIT "Split the active window into panes\nSplit"
+ ID_EDIT_CLEAR "Erase the selection\nErase"
+ ID_EDIT_CLEAR_ALL "Erase everything\nErase All"
+ ID_EDIT_COPY "Copy the selection and put it on the Clipboard\nCopy"
+ ID_EDIT_CUT "Cut the selection and put it on the Clipboard\nCut"
+ ID_EDIT_FIND "Find the specified text\nFind"
+ ID_EDIT_PASTE "Insert Clipboard contents\nPaste"
+ ID_EDIT_REPEAT "Repeat the last action\nRepeat"
+ ID_EDIT_REPLACE "Replace specific text with different text\nReplace"
+ ID_EDIT_SELECT_ALL "Select the entire document\nSelect All"
+ ID_EDIT_UNDO "Undo the last action\nUndo"
+ ID_EDIT_REDO "Redo the previously undone action\nRedo"
+ ID_VIEW_TOOLBAR "Show or hide the toolbar\nToggle ToolBar"
+ ID_VIEW_STATUS_BAR "Show or hide the status bar\nToggle StatusBar"
+END
+
+STRINGTABLE
+BEGIN
+ AFX_IDS_SCSIZE "Change the window size"
+ AFX_IDS_SCMOVE "Change the window position"
+ AFX_IDS_SCMINIMIZE "Reduce the window to an icon"
+ AFX_IDS_SCMAXIMIZE "Enlarge the window to full size"
+ AFX_IDS_SCNEXTWINDOW "Switch to the next document window"
+ AFX_IDS_SCPREVWINDOW "Switch to the previous document window"
+ AFX_IDS_SCCLOSE "Close the active window and prompts to save the documents"
+ AFX_IDS_SCRESTORE "Restore the window to normal size"
+ AFX_IDS_SCTASKLIST "Activate Task List"
+ AFX_IDS_MDICHILD "Activate this window"
+ AFX_IDS_PREVIEW_CLOSE "Close print preview mode\nCancel Preview"
+END
+
+#endif
+
+#ifdef _UNICODE
+IDR_MANIFEST RT_MANIFEST "res\\mfc1.manifest"
+#endif
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE 9, 1
+#pragma code_page(1252)
+#include "res\\mfc1.rc2" // non-Microsoft Visual C++ edited resources
+#include "afxres.rc" // Standard components
+#include "afxprint.rc" // printing/print preview resources
+#endif
+#endif // not APSTUDIO_INVOKED
diff --git a/Tests/MFC/mfc1/mfc1.reg b/Tests/MFC/mfc1/mfc1.reg
new file mode 100644
index 0000000..9f3a86f
--- /dev/null
+++ b/Tests/MFC/mfc1/mfc1.reg
@@ -0,0 +1,13 @@
+REGEDIT
+; This .REG file may be used by your SETUP program.
+; If a SETUP program is not available, the entries below will be
+; registered in your InitInstance automatically with a call to
+; CWinApp::RegisterShellFileTypes and COleObjectFactory::UpdateRegistryAll.
+
+HKEY_CLASSES_ROOT\.mf1 = mfc1.Document
+HKEY_CLASSES_ROOT\mfc1.Document\shell\open\command = mfc1.EXE %1
+HKEY_CLASSES_ROOT\mfc1.Document\shell\open\ddeexec = [open("%1")]
+HKEY_CLASSES_ROOT\mfc1.Document\shell\open\ddeexec\application = mfc1
+ ; note: the application is optional
+ ; (it defaults to the app name in "command")
+HKEY_CLASSES_ROOT\mfc1.Document = mfc1.Document
diff --git a/Tests/MFC/mfc1/mfc1.sln b/Tests/MFC/mfc1/mfc1.sln
new file mode 100644
index 0000000..6f4aefe
--- /dev/null
+++ b/Tests/MFC/mfc1/mfc1.sln
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mfc1", "mfc1.vcproj", "{06C08100-1145-4104-AEC3-6BC8C608B819}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {06C08100-1145-4104-AEC3-6BC8C608B819}.Debug.ActiveCfg = Debug|Win32
+ {06C08100-1145-4104-AEC3-6BC8C608B819}.Debug.Build.0 = Debug|Win32
+ {06C08100-1145-4104-AEC3-6BC8C608B819}.Release.ActiveCfg = Release|Win32
+ {06C08100-1145-4104-AEC3-6BC8C608B819}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/Tests/MFC/mfc1/mfc1.vcproj b/Tests/MFC/mfc1/mfc1.vcproj
new file mode 100644
index 0000000..a04809e
--- /dev/null
+++ b/Tests/MFC/mfc1/mfc1.vcproj
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="mfc1"
+ ProjectGUID="{06C08100-1145-4104-AEC3-6BC8C608B819}"
+ Keyword="MFCProj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ UseOfMFC="2"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUG"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ TreatWChar_tAsBuiltInType="TRUE"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ SubSystem="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="FALSE"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(IntDir)"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ UseOfMFC="2"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG"
+ MinimalRebuild="FALSE"
+ RuntimeLibrary="2"
+ TreatWChar_tAsBuiltInType="TRUE"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="FALSE"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ AdditionalIncludeDirectories="$(IntDir)"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath=".\ChildFrm.cpp">
+ </File>
+ <File
+ RelativePath=".\MainFrm.cpp">
+ </File>
+ <File
+ RelativePath=".\mfc1.cpp">
+ </File>
+ <File
+ RelativePath=".\mfc1Doc.cpp">
+ </File>
+ <File
+ RelativePath=".\mfc1View.cpp">
+ </File>
+ <File
+ RelativePath=".\stdafx.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath=".\ChildFrm.h">
+ </File>
+ <File
+ RelativePath=".\MainFrm.h">
+ </File>
+ <File
+ RelativePath=".\mfc1.h">
+ </File>
+ <File
+ RelativePath=".\mfc1Doc.h">
+ </File>
+ <File
+ RelativePath=".\mfc1View.h">
+ </File>
+ <File
+ RelativePath=".\Resource.h">
+ </File>
+ <File
+ RelativePath=".\stdafx.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+ <File
+ RelativePath=".\res\mfc1.ico">
+ </File>
+ <File
+ RelativePath=".\mfc1.rc">
+ </File>
+ <File
+ RelativePath=".\res\mfc1.rc2">
+ </File>
+ <File
+ RelativePath=".\res\mfc1Doc.ico">
+ </File>
+ <File
+ RelativePath=".\res\Toolbar.bmp">
+ </File>
+ </Filter>
+ <File
+ RelativePath=".\res\mfc1.manifest">
+ </File>
+ <File
+ RelativePath=".\mfc1.reg">
+ </File>
+ <File
+ RelativePath=".\ReadMe.txt">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tests/MFC/mfc1/mfc1Doc.cpp b/Tests/MFC/mfc1/mfc1Doc.cpp
new file mode 100644
index 0000000..ef8b6af
--- /dev/null
+++ b/Tests/MFC/mfc1/mfc1Doc.cpp
@@ -0,0 +1,70 @@
+// mfc1Doc.cpp : implementation of the Cmfc1Doc class
+//
+
+// clang-format off
+#include "stdafx.h"
+
+#include "mfc1.h"
+
+#include "mfc1Doc.h"
+// clang-format on
+
+#ifdef _DEBUG
+# define new DEBUG_NEW
+#endif
+
+// Cmfc1Doc
+
+IMPLEMENT_DYNCREATE(Cmfc1Doc, CDocument)
+
+BEGIN_MESSAGE_MAP(Cmfc1Doc, CDocument)
+END_MESSAGE_MAP()
+
+// Cmfc1Doc construction/destruction
+
+Cmfc1Doc::Cmfc1Doc()
+{
+ // TODO: add one-time construction code here
+}
+
+Cmfc1Doc::~Cmfc1Doc()
+{
+}
+
+BOOL Cmfc1Doc::OnNewDocument()
+{
+ if (!CDocument::OnNewDocument())
+ return FALSE;
+
+ // TODO: add reinitialization code here
+ // (SDI documents will reuse this document)
+
+ return TRUE;
+}
+
+// Cmfc1Doc serialization
+
+void Cmfc1Doc::Serialize(CArchive& ar)
+{
+ if (ar.IsStoring()) {
+ // TODO: add storing code here
+ } else {
+ // TODO: add loading code here
+ }
+}
+
+// Cmfc1Doc diagnostics
+
+#ifdef _DEBUG
+void Cmfc1Doc::AssertValid() const
+{
+ CDocument::AssertValid();
+}
+
+void Cmfc1Doc::Dump(CDumpContext& dc) const
+{
+ CDocument::Dump(dc);
+}
+#endif //_DEBUG
+
+// Cmfc1Doc commands
diff --git a/Tests/MFC/mfc1/mfc1Doc.h b/Tests/MFC/mfc1/mfc1Doc.h
new file mode 100644
index 0000000..fb43cba
--- /dev/null
+++ b/Tests/MFC/mfc1/mfc1Doc.h
@@ -0,0 +1,33 @@
+// mfc1Doc.h : interface of the Cmfc1Doc class
+//
+
+#pragma once
+
+class Cmfc1Doc : public CDocument
+{
+protected: // create from serialization only
+ Cmfc1Doc();
+ DECLARE_DYNCREATE(Cmfc1Doc)
+
+ // Attributes
+public:
+ // Operations
+public:
+ // Overrides
+public:
+ virtual BOOL OnNewDocument();
+ virtual void Serialize(CArchive& ar);
+
+ // Implementation
+public:
+ virtual ~Cmfc1Doc();
+#ifdef _DEBUG
+ virtual void AssertValid() const;
+ virtual void Dump(CDumpContext& dc) const;
+#endif
+
+protected:
+ // Generated message map functions
+protected:
+ DECLARE_MESSAGE_MAP()
+};
diff --git a/Tests/MFC/mfc1/mfc1View.cpp b/Tests/MFC/mfc1/mfc1View.cpp
new file mode 100644
index 0000000..55dcb8e
--- /dev/null
+++ b/Tests/MFC/mfc1/mfc1View.cpp
@@ -0,0 +1,97 @@
+// mfc1View.cpp : implementation of the Cmfc1View class
+//
+
+// clang-format off
+#include "stdafx.h"
+
+#include "mfc1.h"
+
+#include "mfc1Doc.h"
+#include "mfc1View.h"
+// clang-format on
+
+#ifdef _DEBUG
+# define new DEBUG_NEW
+#endif
+
+// Cmfc1View
+
+IMPLEMENT_DYNCREATE(Cmfc1View, CView)
+
+BEGIN_MESSAGE_MAP(Cmfc1View, CView)
+// Standard printing commands
+ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
+ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
+ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
+END_MESSAGE_MAP()
+
+// Cmfc1View construction/destruction
+
+Cmfc1View::Cmfc1View()
+{
+ // TODO: add construction code here
+}
+
+Cmfc1View::~Cmfc1View()
+{
+}
+
+BOOL Cmfc1View::PreCreateWindow(CREATESTRUCT& cs)
+{
+ // TODO: Modify the Window class or styles here by modifying
+ // the CREATESTRUCT cs
+
+ return CView::PreCreateWindow(cs);
+}
+
+// Cmfc1View drawing
+
+void Cmfc1View::OnDraw(CDC* /*pDC*/)
+{
+ Cmfc1Doc* pDoc = GetDocument();
+ ASSERT_VALID(pDoc);
+ if (!pDoc)
+ return;
+
+ // TODO: add draw code for native data here
+}
+
+// Cmfc1View printing
+
+BOOL Cmfc1View::OnPreparePrinting(CPrintInfo* pInfo)
+{
+ // default preparation
+ return DoPreparePrinting(pInfo);
+}
+
+void Cmfc1View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
+{
+ // TODO: add extra initialization before printing
+}
+
+void Cmfc1View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
+{
+ // TODO: add cleanup after printing
+}
+
+// Cmfc1View diagnostics
+
+#ifdef _DEBUG
+void Cmfc1View::AssertValid() const
+{
+ CView::AssertValid();
+}
+
+void Cmfc1View::Dump(CDumpContext& dc) const
+{
+ CView::Dump(dc);
+}
+
+Cmfc1Doc* Cmfc1View::GetDocument() const // non-debug version is inline
+{
+ ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(Cmfc1Doc)));
+ return (Cmfc1Doc*)m_pDocument;
+}
+#endif //_DEBUG
+
+// Cmfc1View message handlers
diff --git a/Tests/MFC/mfc1/mfc1View.h b/Tests/MFC/mfc1/mfc1View.h
new file mode 100644
index 0000000..8c827bb
--- /dev/null
+++ b/Tests/MFC/mfc1/mfc1View.h
@@ -0,0 +1,47 @@
+// mfc1View.h : interface of the Cmfc1View class
+//
+
+#pragma once
+
+class Cmfc1View : public CView
+{
+protected: // create from serialization only
+ Cmfc1View();
+ DECLARE_DYNCREATE(Cmfc1View)
+
+ // Attributes
+public:
+ Cmfc1Doc* GetDocument() const;
+
+ // Operations
+public:
+ // Overrides
+public:
+ virtual void OnDraw(CDC* pDC); // overridden to draw this view
+ virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
+
+protected:
+ virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
+ virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
+ virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
+
+ // Implementation
+public:
+ virtual ~Cmfc1View();
+#ifdef _DEBUG
+ virtual void AssertValid() const;
+ virtual void Dump(CDumpContext& dc) const;
+#endif
+
+protected:
+ // Generated message map functions
+protected:
+ DECLARE_MESSAGE_MAP()
+};
+
+#ifndef _DEBUG // debug version in mfc1View.cpp
+inline Cmfc1Doc* Cmfc1View::GetDocument() const
+{
+ return reinterpret_cast<Cmfc1Doc*>(m_pDocument);
+}
+#endif
diff --git a/Tests/MFC/mfc1/res/Toolbar.bmp b/Tests/MFC/mfc1/res/Toolbar.bmp
new file mode 100644
index 0000000..d501723
--- /dev/null
+++ b/Tests/MFC/mfc1/res/Toolbar.bmp
Binary files differ
diff --git a/Tests/MFC/mfc1/res/mfc1.ico b/Tests/MFC/mfc1/res/mfc1.ico
new file mode 100644
index 0000000..8a84ca3
--- /dev/null
+++ b/Tests/MFC/mfc1/res/mfc1.ico
Binary files differ
diff --git a/Tests/MFC/mfc1/res/mfc1.manifest b/Tests/MFC/mfc1/res/mfc1.manifest
new file mode 100644
index 0000000..b15d2f2
--- /dev/null
+++ b/Tests/MFC/mfc1/res/mfc1.manifest
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<assemblyIdentity
+ version="1.0.0.0"
+ processorArchitecture="X86"
+ name="Microsoft.Windows.mfc1"
+ type="win32"
+/>
+<description>Your app description here</description>
+<dependency>
+ <dependentAssembly>
+ <assemblyIdentity
+ type="win32"
+ name="Microsoft.Windows.Common-Controls"
+ version="6.0.0.0"
+ processorArchitecture="X86"
+ publicKeyToken="6595b64144ccf1df"
+ language="*"
+ />
+ </dependentAssembly>
+</dependency>
+</assembly>
diff --git a/Tests/MFC/mfc1/res/mfc1.rc2 b/Tests/MFC/mfc1/res/mfc1.rc2
new file mode 100644
index 0000000..62a3ab0
--- /dev/null
+++ b/Tests/MFC/mfc1/res/mfc1.rc2
@@ -0,0 +1,13 @@
+//
+// mfc1.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/Tests/MFC/mfc1/res/mfc1Doc.ico b/Tests/MFC/mfc1/res/mfc1Doc.ico
new file mode 100644
index 0000000..2a1f1ae
--- /dev/null
+++ b/Tests/MFC/mfc1/res/mfc1Doc.ico
Binary files differ
diff --git a/Tests/MFC/mfc1/stdafx.cpp b/Tests/MFC/mfc1/stdafx.cpp
new file mode 100644
index 0000000..67fd1b5
--- /dev/null
+++ b/Tests/MFC/mfc1/stdafx.cpp
@@ -0,0 +1,5 @@
+// stdafx.cpp : source file that includes just the standard includes
+// mfc1.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
diff --git a/Tests/MFC/mfc1/stdafx.h b/Tests/MFC/mfc1/stdafx.h
new file mode 100644
index 0000000..b369085
--- /dev/null
+++ b/Tests/MFC/mfc1/stdafx.h
@@ -0,0 +1,70 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently,
+// but are changed infrequently
+
+#pragma once
+
+#ifndef VC_EXTRALEAN
+# define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
+#endif
+
+// See http://msdn.microsoft.com/en-us/library/6sehtctf.aspx for more info
+// on WINVER and _WIN32_WINNT
+
+// Modify the following defines if you have to target a platform prior to the
+// ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different
+// platforms.
+#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4
+ // or later.
+# if _MSC_VER < 1600
+# define WINVER \
+ 0x0400 // Change this to the appropriate value to target Windows 98 and
+ // Windows 2000 or later.
+# else
+# define WINVER 0x0501 // Target Windows XP and later with VS 10 and later
+# endif
+#endif
+
+#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or
+ // later.
+# if _MSC_VER < 1600
+# define _WIN32_WINNT \
+ 0x0400 // Change this to the appropriate value to target Windows 98 and
+ // Windows 2000 or later.
+# else
+# define _WIN32_WINNT \
+ 0x0501 // Target Windows XP and later with VS 10 and later
+# endif
+#endif
+
+#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or
+ // later.
+# if _MSC_VER < 1600
+# define _WIN32_WINDOWS \
+ 0x0410 // Change this to the appropriate value to target Windows Me or
+ // later.
+# endif
+#endif
+
+#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later.
+# if _MSC_VER < 1600
+# define _WIN32_IE \
+ 0x0400 // Change this to the appropriate value to target IE 5.0 or later.
+# endif
+#endif
+
+#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be
+ // explicit
+
+// turns off MFC's hiding of some common and often safely ignored warning
+// messages
+#define _AFX_ALL_WARNINGS
+
+#include <afxdisp.h> // MFC Automation classes
+#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
+#include <afxext.h> // MFC extensions
+#include <afxwin.h> // MFC core and standard components
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+# include <afxcmn.h> // MFC support for Windows Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
diff --git a/Tests/MFC/try_compile/CMakeLists.txt b/Tests/MFC/try_compile/CMakeLists.txt
new file mode 100644
index 0000000..768d2a6
--- /dev/null
+++ b/Tests/MFC/try_compile/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(try_compile_mfc)
+
+set(files
+ stdafx.cpp
+ stdafx.h
+)
+
+set(CMAKE_MFC_FLAG "2")
+
+# VS generators add this automatically based on the CMAKE_MFC_FLAG value,
+# but generators matching "Make" require:
+add_definitions(-D_AFXDLL)
+
+add_executable(simplest_possible_mfc_exe WIN32 ${files})
diff --git a/Tests/MSManifest/CMakeLists.txt b/Tests/MSManifest/CMakeLists.txt
new file mode 100644
index 0000000..631c598
--- /dev/null
+++ b/Tests/MSManifest/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.3)
+project(MSManifest C)
+
+include(CTest)
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+add_subdirectory(Subdir)
+add_subdirectory(Subdir2)
diff --git a/Tests/MSManifest/Subdir/CMakeLists.txt b/Tests/MSManifest/Subdir/CMakeLists.txt
new file mode 100644
index 0000000..8664572
--- /dev/null
+++ b/Tests/MSManifest/Subdir/CMakeLists.txt
@@ -0,0 +1,10 @@
+configure_file(test.manifest.in test.manifest)
+add_executable(MSManifest main.c ${CMAKE_CURRENT_BINARY_DIR}/test.manifest)
+
+if(MSVC AND NOT MSVC_VERSION LESS 1400)
+ add_test(NAME MSManifest.Single COMMAND
+ ${CMAKE_COMMAND} -Dexe=$<TARGET_FILE:MSManifest>
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake)
+ add_executable(MSManifestNone main.c)
+ set_property(TARGET MSManifestNone PROPERTY LINK_FLAGS "/MANIFEST:NO")
+endif()
diff --git a/Tests/MSManifest/Subdir/check.cmake b/Tests/MSManifest/Subdir/check.cmake
new file mode 100644
index 0000000..b7b6841
--- /dev/null
+++ b/Tests/MSManifest/Subdir/check.cmake
@@ -0,0 +1,6 @@
+file(STRINGS "${exe}" content REGEX "name=\"Kitware.CMake.MSManifestTest\"")
+if(content)
+ message(STATUS "Expected manifest content found:\n ${content}")
+else()
+ message(FATAL_ERROR "Expected manifest content not found in\n ${exe}")
+endif()
diff --git a/Tests/MSManifest/Subdir/main.c b/Tests/MSManifest/Subdir/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/MSManifest/Subdir/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/MSManifest/Subdir/test.manifest.in b/Tests/MSManifest/Subdir/test.manifest.in
new file mode 100644
index 0000000..540961a
--- /dev/null
+++ b/Tests/MSManifest/Subdir/test.manifest.in
@@ -0,0 +1,4 @@
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity type="win32" version="1.0.0.0"
+ name="Kitware.CMake.MSManifestTest"/>
+</assembly>
diff --git a/Tests/MSManifest/Subdir2/CMakeLists.txt b/Tests/MSManifest/Subdir2/CMakeLists.txt
new file mode 100644
index 0000000..19d8de7
--- /dev/null
+++ b/Tests/MSManifest/Subdir2/CMakeLists.txt
@@ -0,0 +1,13 @@
+configure_file(test_manifest1.in test_manifest1.manifest)
+configure_file(test_manifest2.in test_manifest2.manifest)
+configure_file(test_manifest3.in test_manifest3.manifest)
+add_executable(MSMultipleManifest main.c
+ ${CMAKE_CURRENT_BINARY_DIR}/test_manifest1.manifest
+ ${CMAKE_CURRENT_BINARY_DIR}/test_manifest2.manifest
+ ${CMAKE_CURRENT_BINARY_DIR}/test_manifest3.manifest)
+
+if(MSVC AND NOT MSVC_VERSION LESS 1400)
+ add_test(NAME MSManifest.Multiple COMMAND
+ ${CMAKE_COMMAND} -Dexe=$<TARGET_FILE:MSMultipleManifest>
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake)
+endif()
diff --git a/Tests/MSManifest/Subdir2/check.cmake b/Tests/MSManifest/Subdir2/check.cmake
new file mode 100644
index 0000000..4a1705b
--- /dev/null
+++ b/Tests/MSManifest/Subdir2/check.cmake
@@ -0,0 +1,22 @@
+file(STRINGS "${exe}" manifest_content1 REGEX "name=\"Kitware.CMake.MSMultipleManifest\"")
+if(manifest_content1)
+ message(STATUS "Expected manifest content found:\n ${manifest_content1}")
+else()
+ message(FATAL_ERROR "Expected manifest content not found in\n ${exe}")
+endif()
+
+# Verify Second Manifest Content is inside Executable.
+file(STRINGS "${exe}" manifest_content2 REGEX "8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a")
+if(manifest_content2)
+ message(STATUS "Expected manifest content found:\n ${manifest_content2}")
+else()
+ message(FATAL_ERROR "Expected manifest content not found in\n ${exe}")
+endif()
+
+# Verify Third Manifest Content is inside Executable.
+file(STRINGS "${exe}" manifest_content3 REGEX "<dpiAware>true</dpiAware>")
+if(manifest_content3)
+ message(STATUS "Expected manifest content found:\n ${manifest_content3}")
+else()
+ message(FATAL_ERROR "Expected manifest content not found in\n ${exe}")
+endif()
diff --git a/Tests/MSManifest/Subdir2/main.c b/Tests/MSManifest/Subdir2/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/MSManifest/Subdir2/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/MSManifest/Subdir2/test_manifest1.in b/Tests/MSManifest/Subdir2/test_manifest1.in
new file mode 100644
index 0000000..f36eead
--- /dev/null
+++ b/Tests/MSManifest/Subdir2/test_manifest1.in
@@ -0,0 +1,5 @@
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity type="win32" version="1.0.0.0"
+ name="Kitware.CMake.MSMultipleManifest"/>
+ <description>CMake Multiple Manifest Test Application</description>
+</assembly>
diff --git a/Tests/MSManifest/Subdir2/test_manifest2.in b/Tests/MSManifest/Subdir2/test_manifest2.in
new file mode 100644
index 0000000..ec96f11
--- /dev/null
+++ b/Tests/MSManifest/Subdir2/test_manifest2.in
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"></supportedOS>
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"></supportedOS>
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS>
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"></supportedOS>
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"></supportedOS>
+ </application>
+ </compatibility>
+</assembly>
diff --git a/Tests/MSManifest/Subdir2/test_manifest3.in b/Tests/MSManifest/Subdir2/test_manifest3.in
new file mode 100644
index 0000000..0770e11
--- /dev/null
+++ b/Tests/MSManifest/Subdir2/test_manifest3.in
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
+ <asmv3:application>
+ <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+ <dpiAware>true</dpiAware>
+ <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
+ </asmv3:windowsSettings>
+ </asmv3:application>
+</assembly>
diff --git a/Tests/MSVCRuntimeLibrary/CMakeLists.txt b/Tests/MSVCRuntimeLibrary/CMakeLists.txt
new file mode 100644
index 0000000..f7d9fec
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/CMakeLists.txt
@@ -0,0 +1,71 @@
+cmake_minimum_required(VERSION 3.14)
+cmake_policy(SET CMP0091 NEW)
+project(MSVCRuntimeLibrary)
+
+if(CMake_TEST_CUDA)
+ enable_language(CUDA)
+endif()
+
+function(verify_combinations threads lang src)
+ set(verify_tc_config_ Release)
+ set(verify_tc_config_Debug Debug)
+ set(verify_def_MultiThreaded -DVERIFY_MT)
+ set(verify_def_Debug -DVERIFY_DEBUG)
+ set(verify_def_DLL -DVERIFY_DLL)
+ foreach(dbg "" Debug)
+ foreach(dll "" DLL)
+ # Construct the name of this runtime library combination.
+ set(rtl "${threads}${dbg}${dll}")
+
+ # Test that try_compile builds with this RTL.
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "${rtl}")
+ set(CMAKE_TRY_COMPILE_CONFIGURATION "${verify_tc_config_${dbg}}")
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
+ try_compile(${rtl}_COMPILES
+ ${CMAKE_CURRENT_BINARY_DIR}/try_compile/${rtl}
+ ${CMAKE_CURRENT_SOURCE_DIR}/${src}
+ COMPILE_DEFINITIONS ${verify_def_${threads}} ${verify_def_${dbg}} ${verify_def_${dll}}
+ OUTPUT_VARIABLE ${rtl}_OUTPUT
+ )
+ if(${rtl}_COMPILES)
+ message(STATUS "try_compile with ${rtl} worked")
+ else()
+ string(REPLACE "\n" "\n " ${rtl}_OUTPUT " ${${rtl}_OUTPUT}")
+ message(SEND_ERROR "try_compile with ${rtl} failed:\n${${rtl}_OUTPUT}")
+ endif()
+
+ # Test that targets build with this RTL.
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "$<$<BOOL:$<TARGET_PROPERTY:BOOL_TRUE>>:${rtl}>$<$<BOOL:$<TARGET_PROPERTY:BOOL_FALSE>>:BadContent>")
+ add_library(${rtl}-${lang} ${src})
+ set_property(TARGET ${rtl}-${lang} PROPERTY BOOL_TRUE TRUE)
+ target_compile_definitions(${rtl}-${lang} PRIVATE ${verify_def_${threads}} ${verify_def_${dbg}} ${verify_def_${dll}})
+ endforeach()
+ endforeach()
+endfunction()
+
+function(verify lang src)
+ add_library(default-${lang} ${src})
+ target_compile_definitions(default-${lang} PRIVATE VERIFY_MT VERIFY_DLL "$<$<CONFIG:Debug>:VERIFY_DEBUG>")
+
+ verify_combinations(MultiThreaded ${lang} ${src})
+
+ # Test known MSVC default behavior when no flag is given.
+ if(CMAKE_${lang}_COMPILER_ID STREQUAL "MSVC")
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "")
+ add_library(empty-${lang} ${src})
+ if(CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 14)
+ # VS 2005 and above default to multi-threaded.
+ target_compile_definitions(empty-${lang} PRIVATE VERIFY_MT)
+ endif()
+ if(CMAKE_GENERATOR MATCHES "Visual Studio ([^9]|9[0-9])")
+ # VS 2010 and above have a different default runtime library for projects than 'cl'.
+ target_compile_definitions(empty-${lang} PRIVATE VERIFY_DLL)
+ endif()
+ endif()
+endfunction()
+
+verify(C verify.c)
+verify(CXX verify.cxx)
+if(CMake_TEST_CUDA)
+ verify(CUDA verify.cu)
+endif()
diff --git a/Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt b/Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt
new file mode 100644
index 0000000..41bd6f5
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt
@@ -0,0 +1,59 @@
+cmake_minimum_required(VERSION 3.14)
+cmake_policy(SET CMP0091 NEW)
+project(MSVCRuntimeLibraryFortran Fortran)
+
+foreach(t MultiThreaded SingleThreaded)
+ foreach(dbg "" Debug)
+ foreach(dll "" DLL)
+ set(var "CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_${t}${dbg}${dll}")
+ if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel"
+ OR CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM")
+ # ifort and ifx do not actually define these, so inject them
+ string(REPLACE "-threads" "-threads;-D_MT" "${var}" "${${var}}")
+ string(REPLACE "-dbglibs" "-dbglibs;-D_DEBUG" "${var}" "${${var}}")
+ elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Flang")
+ # flang does not actually define these, so inject them
+ string(REPLACE ";--dependent-lib=libcmt;" ";--dependent-lib=libcmt;-D_MT;" "${var}" ";${${var}};")
+ string(REPLACE ";--dependent-lib=msvcrt;" ";--dependent-lib=msvcrt;-D_MT;-D_DLL;" "${var}" ";${${var}};")
+ string(REPLACE ";--dependent-lib=libcmtd;" ";--dependent-lib=libcmtd;-D_MT;-D_DEBUG;" "${var}" ";${${var}};")
+ string(REPLACE ";--dependent-lib=msvcrtd;" ";--dependent-lib=msvcrtd;-D_MT;-D_DEBUG;-D_DLL;" "${var}" ";${${var}};")
+ endif()
+ endforeach()
+ endforeach()
+endforeach()
+string(APPEND CMAKE_Fortran_FLAGS " -w")
+
+function(verify_combinations threads lang src)
+ set(verify_tc_config_ Release)
+ set(verify_tc_config_Debug Debug)
+ set(verify_def_MultiThreaded -DVERIFY_MT)
+ set(verify_def_Debug -DVERIFY_DEBUG)
+ set(verify_def_DLL -DVERIFY_DLL)
+ foreach(dbg "" Debug)
+ foreach(dll "" DLL)
+ # Construct the name of this runtime library combination.
+ set(rtl "${threads}${dbg}${dll}")
+
+ # Test that targets build with this RTL.
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "$<$<BOOL:$<TARGET_PROPERTY:BOOL_TRUE>>:${rtl}>$<$<BOOL:$<TARGET_PROPERTY:BOOL_FALSE>>:BadContent>")
+ add_library(${rtl}-${lang} ${src})
+ set_property(TARGET ${rtl}-${lang} PROPERTY BOOL_TRUE TRUE)
+ target_compile_definitions(${rtl}-${lang} PRIVATE ${verify_def_${threads}} ${verify_def_${dbg}} ${verify_def_${dll}})
+ endforeach()
+ endforeach()
+endfunction()
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+function(verify lang src)
+ add_library(default-${lang} ${src})
+ target_compile_definitions(default-${lang} PRIVATE VERIFY_MT VERIFY_DLL "$<$<CONFIG:Debug>:VERIFY_DEBUG>")
+ verify_combinations(MultiThreaded ${lang} ${src})
+endfunction()
+
+verify(Fortran verify.F90)
+# Intel Fortran for Windows supports single-threaded RTL but it is
+# not implemented by the Visual Studio integration.
+if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel" AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+ verify_combinations(SingleThreaded Fortran verify.F90)
+endif()
diff --git a/Tests/MSVCRuntimeLibrary/Fortran/verify.F90 b/Tests/MSVCRuntimeLibrary/Fortran/verify.F90
new file mode 100644
index 0000000..6fe5e05
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/Fortran/verify.F90
@@ -0,0 +1 @@
+#include "../verify.h"
diff --git a/Tests/MSVCRuntimeLibrary/verify.c b/Tests/MSVCRuntimeLibrary/verify.c
new file mode 100644
index 0000000..741bca6
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/verify.c
@@ -0,0 +1 @@
+#include "verify.h"
diff --git a/Tests/MSVCRuntimeLibrary/verify.cu b/Tests/MSVCRuntimeLibrary/verify.cu
new file mode 100644
index 0000000..741bca6
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/verify.cu
@@ -0,0 +1 @@
+#include "verify.h"
diff --git a/Tests/MSVCRuntimeLibrary/verify.cxx b/Tests/MSVCRuntimeLibrary/verify.cxx
new file mode 100644
index 0000000..741bca6
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/verify.cxx
@@ -0,0 +1 @@
+#include "verify.h"
diff --git a/Tests/MSVCRuntimeLibrary/verify.h b/Tests/MSVCRuntimeLibrary/verify.h
new file mode 100644
index 0000000..58d65fe
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/verify.h
@@ -0,0 +1,29 @@
+#ifdef VERIFY_DEBUG
+# ifndef _DEBUG
+# error "_DEBUG not defined by debug runtime library selection"
+# endif
+#else
+# ifdef _DEBUG
+# error "_DEBUG defined by non-debug runtime library selection"
+# endif
+#endif
+
+#ifdef VERIFY_DLL
+# ifndef _DLL
+# error "_DLL not defined by DLL runtime library selection"
+# endif
+#else
+# ifdef _DLL
+# error "_DLL defined by non-DLL runtime library selection"
+# endif
+#endif
+
+#ifdef VERIFY_MT
+# ifndef _MT
+# error "_MT not defined by multi-threaded runtime library selection"
+# endif
+#else
+# ifdef _MT
+# error "_MT defined by single-threaded runtime library selection"
+# endif
+#endif
diff --git a/Tests/MacRuntimePath/A/CMakeLists.txt b/Tests/MacRuntimePath/A/CMakeLists.txt
new file mode 100644
index 0000000..c9d3f2c
--- /dev/null
+++ b/Tests/MacRuntimePath/A/CMakeLists.txt
@@ -0,0 +1,79 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(MacRuntimePath_A)
+
+# a shared library
+add_library(shared SHARED shared.cpp shared.h)
+set_target_properties(shared PROPERTIES MACOSX_RPATH 1)
+
+# a shared library with custom set @rpath
+add_library(shared2 SHARED shared.cpp shared.h)
+set_target_properties(shared2 PROPERTIES
+ BUILD_WITH_INSTALL_RPATH 1 INSTALL_NAME_DIR "@rpath")
+
+cmake_policy(SET CMP0042 NEW)
+
+# a framework library
+add_library(framework SHARED framework.cpp framework.h)
+set_target_properties(framework PROPERTIES FRAMEWORK 1)
+
+# another framework
+add_library(framework2 SHARED framework2.cpp framework2.h)
+set_target_properties(framework2 PROPERTIES FRAMEWORK 1)
+
+# executable to test a shared library dependency with install rpaths
+add_executable(test1 test1.cpp)
+target_link_libraries(test1 shared)
+set_target_properties(test1 PROPERTIES
+ BUILD_WITH_INSTALL_RPATH 1 INSTALL_RPATH "@loader_path/../lib")
+
+# executable to test a framework library dependency with install rpaths
+add_executable(test2 test2.cpp)
+target_link_libraries(test2 framework)
+set_target_properties(test2 PROPERTIES
+ BUILD_WITH_INSTALL_RPATH 1 INSTALL_RPATH "@loader_path/../lib")
+
+# executable to test a framework library dependency with build tree rpaths
+add_executable(test3 test3.cpp)
+target_link_libraries(test3 framework)
+
+# executable to test a framework library dependency with build tree rpaths
+add_executable(test4 test1.cpp)
+target_link_libraries(test4 shared2)
+
+# executable to test a shared library dependency with build rpath
+add_executable(test5 test1.cpp)
+
+# avoid linking by 'target_link_libraries' so CMake
+# will not be able to set correct RPATH automatically
+add_dependencies(test5 shared)
+target_link_libraries(test5 "$<TARGET_FILE:shared>")
+set_target_properties(test5 PROPERTIES BUILD_RPATH "@loader_path/../lib")
+
+set_target_properties(shared shared2 framework PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
+set_target_properties(test1 test2 test3 test4 test5 PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
+foreach(config ${CMAKE_CONFIGURATION_TYPES})
+ string(TOUPPER ${config} CONFIG)
+ set_target_properties(shared shared2 framework PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY_${CONFIG}
+ "${CMAKE_CURRENT_BINARY_DIR}/${config}/lib")
+ set_target_properties(test1 test2 test3 test4 test5 PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY_${CONFIG}
+ "${CMAKE_CURRENT_BINARY_DIR}/${config}/bin")
+endforeach()
+
+foreach(test test1 test2 test3 test4 test5)
+ add_custom_target(${test}_run ALL
+ COMMAND ${test}
+ DEPENDS ${test}
+ )
+endforeach()
+
+export(TARGETS shared shared2 framework FILE "${CMAKE_CURRENT_BINARY_DIR}/exp.cmake")
+
+install(TARGETS shared EXPORT MyExport DESTINATION lib)
+install(TARGETS shared2 EXPORT MyExport DESTINATION lib2)
+install(TARGETS framework EXPORT MyExport DESTINATION lib-fw)
+install(TARGETS framework2 EXPORT MyExport DESTINATION lib-fw2)
+install(EXPORT MyExport DESTINATION lib FILE exp.cmake)
diff --git a/Tests/MacRuntimePath/A/framework.cpp b/Tests/MacRuntimePath/A/framework.cpp
new file mode 100644
index 0000000..b5a95d8
--- /dev/null
+++ b/Tests/MacRuntimePath/A/framework.cpp
@@ -0,0 +1,9 @@
+
+#include "framework.h"
+
+#include "stdio.h"
+
+void framework()
+{
+ printf("framework\n");
+}
diff --git a/Tests/MacRuntimePath/A/framework.h b/Tests/MacRuntimePath/A/framework.h
new file mode 100644
index 0000000..5a3cfc4
--- /dev/null
+++ b/Tests/MacRuntimePath/A/framework.h
@@ -0,0 +1,17 @@
+
+#ifndef framework_h
+#define framework_h
+
+#ifdef WIN32
+# ifdef framework_EXPORTS
+# define FRAMEWORK_EXPORT __declspec(dllexport)
+# else
+# define FRAMEWORK_EXPORT __declspec(dllimport)
+# endif
+#else
+# define FRAMEWORK_EXPORT
+#endif
+
+void FRAMEWORK_EXPORT framework();
+
+#endif
diff --git a/Tests/MacRuntimePath/A/framework2.cpp b/Tests/MacRuntimePath/A/framework2.cpp
new file mode 100644
index 0000000..0a1beec
--- /dev/null
+++ b/Tests/MacRuntimePath/A/framework2.cpp
@@ -0,0 +1,9 @@
+
+#include "framework2.h"
+
+#include "stdio.h"
+
+void framework2()
+{
+ printf("framework 2\n");
+}
diff --git a/Tests/MacRuntimePath/A/framework2.h b/Tests/MacRuntimePath/A/framework2.h
new file mode 100644
index 0000000..2562396
--- /dev/null
+++ b/Tests/MacRuntimePath/A/framework2.h
@@ -0,0 +1,17 @@
+
+#ifndef framework2_h
+#define framework2_h
+
+#ifdef WIN32
+# ifdef framework2_EXPORTS
+# define FRAMEWORK2_EXPORT __declspec(dllexport)
+# else
+# define FRAMEWORK2_EXPORT __declspec(dllimport)
+# endif
+#else
+# define FRAMEWORK2_EXPORT
+#endif
+
+void FRAMEWORK2_EXPORT framework2();
+
+#endif
diff --git a/Tests/MacRuntimePath/A/shared.cpp b/Tests/MacRuntimePath/A/shared.cpp
new file mode 100644
index 0000000..13791c2
--- /dev/null
+++ b/Tests/MacRuntimePath/A/shared.cpp
@@ -0,0 +1,9 @@
+
+#include "shared.h"
+
+#include "stdio.h"
+
+void shared()
+{
+ printf("shared\n");
+}
diff --git a/Tests/MacRuntimePath/A/shared.h b/Tests/MacRuntimePath/A/shared.h
new file mode 100644
index 0000000..5d5b633
--- /dev/null
+++ b/Tests/MacRuntimePath/A/shared.h
@@ -0,0 +1,17 @@
+
+#ifndef shared_h
+#define shared_h
+
+#ifdef WIN32
+# ifdef shared_EXPORTS
+# define SHARED_EXPORT __declspec(dllexport)
+# else
+# define SHARED_EXPORT __declspec(dllimport)
+# endif
+#else
+# define SHARED_EXPORT
+#endif
+
+void SHARED_EXPORT shared();
+
+#endif
diff --git a/Tests/MacRuntimePath/A/test1.cpp b/Tests/MacRuntimePath/A/test1.cpp
new file mode 100644
index 0000000..cb93448
--- /dev/null
+++ b/Tests/MacRuntimePath/A/test1.cpp
@@ -0,0 +1,8 @@
+
+#include "shared.h"
+
+int main(int, char**)
+{
+ shared();
+ return 0;
+}
diff --git a/Tests/MacRuntimePath/A/test2.cpp b/Tests/MacRuntimePath/A/test2.cpp
new file mode 100644
index 0000000..26bc9dd
--- /dev/null
+++ b/Tests/MacRuntimePath/A/test2.cpp
@@ -0,0 +1,8 @@
+
+#include "framework.h"
+
+int main(int, char**)
+{
+ framework();
+ return 0;
+}
diff --git a/Tests/MacRuntimePath/A/test3.cpp b/Tests/MacRuntimePath/A/test3.cpp
new file mode 100644
index 0000000..26bc9dd
--- /dev/null
+++ b/Tests/MacRuntimePath/A/test3.cpp
@@ -0,0 +1,8 @@
+
+#include "framework.h"
+
+int main(int, char**)
+{
+ framework();
+ return 0;
+}
diff --git a/Tests/MacRuntimePath/B/CMakeLists.txt b/Tests/MacRuntimePath/B/CMakeLists.txt
new file mode 100644
index 0000000..85598c4
--- /dev/null
+++ b/Tests/MacRuntimePath/B/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(MacRuntimePath_B)
+
+include(${MacRuntimePath_B_BINARY_DIR}/../Root/lib/exp.cmake)
+
+add_executable(testb ${MacRuntimePath_B_SOURCE_DIR}/../A/test3.cpp)
+
+# test link with rpath enabled targets
+target_link_libraries(testb shared framework)
+
+# test link with rpath enabled library by filename
+find_library(fw2 NAMES framework2 HINTS ${MacRuntimePath_B_BINARY_DIR}/../Root/lib-fw2)
+target_link_libraries(testb $<TARGET_LINKER_FILE:shared2> ${fw2})
+
+add_custom_target(testb_run ALL
+ COMMAND testb
+ DEPENDS testb
+ )
diff --git a/Tests/MacRuntimePath/CMakeLists.txt b/Tests/MacRuntimePath/CMakeLists.txt
new file mode 100644
index 0000000..9f1bf1a
--- /dev/null
+++ b/Tests/MacRuntimePath/CMakeLists.txt
@@ -0,0 +1,75 @@
+cmake_minimum_required (VERSION 3.9)
+project(MacRuntimePath)
+if(NOT DEFINED CMake_TEST_NESTED_MAKE_PROGRAM AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(CMake_TEST_NESTED_MAKE_PROGRAM "${CMAKE_MAKE_PROGRAM}")
+endif()
+
+# Wipe out the install tree to make sure the exporter works.
+add_custom_command(
+ OUTPUT ${MacRuntimePath_BINARY_DIR}/CleanupProject
+ COMMAND ${CMAKE_COMMAND} -E rm -rf ${MacRuntimePath_BINARY_DIR}/Root
+ )
+add_custom_target(CleanupTarget ALL DEPENDS ${MacRuntimePath_BINARY_DIR}/CleanupProject)
+set_property(
+ SOURCE ${MacRuntimePath_BINARY_DIR}/CleanupProject
+ PROPERTY SYMBOLIC 1
+ )
+
+configure_file(${MacRuntimePath_SOURCE_DIR}/InitialCache.cmake.in
+ ${MacRuntimePath_BINARY_DIR}/InitialCache.cmake @ONLY)
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ set(NESTED_CONFIG_TYPE -C "${CMAKE_CFG_INTDIR}")
+else()
+ if(CMAKE_BUILD_TYPE)
+ set(NESTED_CONFIG_TYPE -C "${CMAKE_BUILD_TYPE}")
+ else()
+ set(NESTED_CONFIG_TYPE)
+ endif()
+endif()
+
+# Build and install the exporter.
+add_custom_command(
+ OUTPUT ${MacRuntimePath_BINARY_DIR}/ExportProject
+ COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+ --build-and-test
+ ${MacRuntimePath_SOURCE_DIR}/A
+ ${MacRuntimePath_BINARY_DIR}/A
+ --build-noclean
+ --build-project MacRuntimePath_A
+ --build-target install
+ --build-generator ${CMAKE_GENERATOR}
+ --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+ --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+ --build-options -C${MacRuntimePath_BINARY_DIR}/InitialCache.cmake
+ VERBATIM
+ )
+add_custom_target(ExportTarget ALL DEPENDS ${MacRuntimePath_BINARY_DIR}/ExportProject)
+add_dependencies(ExportTarget CleanupTarget)
+set_property(
+ SOURCE ${MacRuntimePath_BINARY_DIR}/ExportProject
+ PROPERTY SYMBOLIC 1
+ )
+
+# Build the importer.
+add_custom_command(
+ OUTPUT ${MacRuntimePath_BINARY_DIR}/ImportProject
+ COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+ --build-and-test
+ ${MacRuntimePath_SOURCE_DIR}/B
+ ${MacRuntimePath_BINARY_DIR}/B
+ --build-noclean
+ --build-project MacRuntimePath_B
+ --build-generator ${CMAKE_GENERATOR}
+ --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+ --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+ --build-options -C${MacRuntimePath_BINARY_DIR}/InitialCache.cmake
+ VERBATIM
+ )
+add_custom_target(ImportTarget ALL DEPENDS ${MacRuntimePath_BINARY_DIR}/ImportProject)
+add_dependencies(ImportTarget ExportTarget)
+set_property(
+ SOURCE ${MacRuntimePath_BINARY_DIR}/ImportProject
+ PROPERTY SYMBOLIC 1
+ )
diff --git a/Tests/MacRuntimePath/InitialCache.cmake.in b/Tests/MacRuntimePath/InitialCache.cmake.in
new file mode 100644
index 0000000..a9f6a3c
--- /dev/null
+++ b/Tests/MacRuntimePath/InitialCache.cmake.in
@@ -0,0 +1,14 @@
+set(CMAKE_MAKE_PROGRAM "@CMake_TEST_NESTED_MAKE_PROGRAM@" CACHE FILEPATH "Make Program")
+set(CMAKE_C_COMPILER "@CMAKE_C_COMPILER@" CACHE STRING "C Compiler")
+set(CMAKE_C_FLAGS "@CMAKE_C_FLAGS@" CACHE STRING "C Flags")
+set(CMAKE_C_FLAGS_DEBUG "@CMAKE_C_FLAGS_DEBUG@" CACHE STRING "C Flags")
+set(CMAKE_C_FLAGS_RELEASE "@CMAKE_C_FLAGS_RELEASE@" CACHE STRING "C Flags")
+set(CMAKE_C_FLAGS_MINSIZEREL "@CMAKE_C_FLAGS_MINSIZEREL@" CACHE STRING "C Flags")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "@CMAKE_C_FLAGS_RELWITHDEBINFO@" CACHE STRING "C Flags")
+set(CMAKE_CXX_COMPILER "@CMAKE_CXX_COMPILER@" CACHE STRING "C++ Compiler")
+set(CMAKE_CXX_FLAGS "@CMAKE_CXX_FLAGS@" CACHE STRING "C++ Flags")
+set(CMAKE_CXX_FLAGS_DEBUG "@CMAKE_CXX_FLAGS_DEBUG@" CACHE STRING "C++ Flags")
+set(CMAKE_CXX_FLAGS_RELEASE "@CMAKE_CXX_FLAGS_RELEASE@" CACHE STRING "C++ Flags")
+set(CMAKE_CXX_FLAGS_MINSIZEREL "@CMAKE_CXX_FLAGS_MINSIZEREL@" CACHE STRING "C++ Flags")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "@CMAKE_CXX_FLAGS_RELWITHDEBINFO@" CACHE STRING "C++ Flags")
+set(CMAKE_INSTALL_PREFIX "@MacRuntimePath_BINARY_DIR@/Root" CACHE STRING "Installation Prefix")
diff --git a/Tests/MacroTest/CMakeLists.txt b/Tests/MacroTest/CMakeLists.txt
new file mode 100644
index 0000000..6c6dfb6
--- /dev/null
+++ b/Tests/MacroTest/CMakeLists.txt
@@ -0,0 +1,91 @@
+# a simple C only test case
+cmake_minimum_required (VERSION 2.6)
+project (MacroTest)
+
+macro(FAILED testname)
+ message(SEND_ERROR "${testname} failed ${ARGN}")
+endmacro()
+
+macro(PASS testname)
+ message("${testname} passed ${ARGN}")
+endmacro()
+
+# test ARGC
+macro(weird_name)
+ if("${ARGC}" EQUAL "3")
+ PASS("ARGC")
+ else()
+ FAILED("ARGC" "Got: ${ARGC}")
+ endif()
+endmacro()
+WeIrD_nAmE(a1 a2 a3)
+
+# test ARGN
+macro(test_argn_macro argument)
+ if("${ARGN}" EQUAL "3")
+ PASS("ARGN")
+ else()
+ FAILED("ARGN" "Got: ${ARGN}")
+ endif()
+endmacro()
+Test_Argn_Macro(ignored 3)
+
+# case test
+macro(strange_macro m)
+ set("${m}" strange_macro)
+endmacro()
+STRANGE_MACRO(var)
+set(second_var "second_var")
+if("x${var}" STREQUAL "xstrange_macro" AND "x${second_var}" STREQUAL "xsecond_var")
+ PASS("Case Test" "(${var} ${second_var})")
+else()
+ FAILED("Case test" "(${var} ${second_var})")
+endif()
+
+# test backing up command
+macro(ADD_EXECUTABLE exec)
+ _ADD_EXECUTABLE("mini${exec}" ${ARGN})
+endmacro()
+
+include(CheckCSourceCompiles)
+Check_C_Source_Compiles(
+"
+#include <stdio.h>
+#ifdef __CLASSIC_C__
+int main(){
+ int ac;
+ char*av[];
+#else
+int main(int ac, char*av[]){
+#endif
+ if(ac > 1000){return *av[0];}
+ return 0;
+}"
+SOME_CHECK)
+if(SOME_CHECK)
+ message("CheckCSourceCompiles works")
+else()
+ message(FATAL_ERROR "CheckCSourceCompiles does not work")
+endif()
+
+include(CheckCXXSourceCompiles)
+Check_CXX_Source_Compiles(
+"
+#include <stdio.h>
+int main(int ac, char*av[]){
+ if(ac > 1000){return *av[0];}
+ return 0;
+}"
+SOME_CHECK)
+if(SOME_CHECK)
+ message("CheckCXXSourceCompiles works")
+else()
+ message(FATAL_ERROR "CheckCXXSourceCompiles does not work")
+endif()
+
+add_executable(MacroTest macroTest.c)
+
+macro(GET_CURRENT_FILE var)
+ set(${var} ${CMAKE_CURRENT_LIST_FILE})
+endmacro()
+include(context.cmake)
diff --git a/Tests/MacroTest/context.cmake b/Tests/MacroTest/context.cmake
new file mode 100644
index 0000000..f7350d7
--- /dev/null
+++ b/Tests/MacroTest/context.cmake
@@ -0,0 +1,10 @@
+GET_CURRENT_FILE(current_file)
+if(NOT "${current_file}" STREQUAL "${CMAKE_CURRENT_LIST_FILE}")
+ message(FATAL_ERROR
+ "Macro file context is broken. Expected:\n"
+ " ${CMAKE_CURRENT_LIST_FILE}\n"
+ "but got:\n"
+ " ${current_file}\n"
+ "from the macro."
+ )
+endif()
diff --git a/Tests/MacroTest/macroTest.c b/Tests/MacroTest/macroTest.c
new file mode 100644
index 0000000..e0ced6a
--- /dev/null
+++ b/Tests/MacroTest/macroTest.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char* argv[])
+{
+ printf("Running command: %s with %d arguments\n", argv[0], argc);
+ return 0;
+}
diff --git a/Tests/MakeClean/CMakeLists.txt b/Tests/MakeClean/CMakeLists.txt
new file mode 100644
index 0000000..809d65b
--- /dev/null
+++ b/Tests/MakeClean/CMakeLists.txt
@@ -0,0 +1,50 @@
+cmake_minimum_required (VERSION 2.8.12)
+project(MakeClean)
+
+# Build the to-clean project.
+try_compile(TOCLEAN_BUILT
+ ${MakeClean_BINARY_DIR}/ToClean
+ ${MakeClean_SOURCE_DIR}/ToClean
+ ToClean
+ OUTPUT_VARIABLE OUTPUT
+ )
+if(TOCLEAN_BUILT)
+ message(
+ "Building ToClean succeeded with the following output:\n"
+ "[${OUTPUT}]"
+ )
+else()
+ message(FATAL_ERROR
+ "Building ToClean failed with the following output:\n"
+ "[${OUTPUT}]"
+ )
+endif()
+
+# Get the set of files to check from the ToClean project.
+include(${MakeClean_BINARY_DIR}/ToClean/ToCleanFiles.cmake)
+
+# Check for the existence of the files.
+foreach(f ${TOCLEAN_FILES})
+ if(EXISTS "${f}")
+ else()
+ message(FATAL_ERROR "File \"${f}\" does not exist!")
+ endif()
+endforeach()
+
+# Configure an executable to check that all the files are missing.
+set(CHECK_FILES)
+foreach(f ${TOCLEAN_FILES})
+ string(APPEND CHECK_FILES " \"${f}\",\n")
+endforeach()
+configure_file(${MakeClean_SOURCE_DIR}/check_clean.c.in
+ ${MakeClean_BINARY_DIR}/check_clean.c @ONLY)
+add_executable(check_clean ${MakeClean_BINARY_DIR}/check_clean.c)
+
+# After the executable builds, clean the files.
+add_custom_command(
+ TARGET check_clean
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} --build ${MakeClean_BINARY_DIR}/ToClean
+ --target clean
+ COMMENT "Clean the ToClean Project"
+ )
diff --git a/Tests/MakeClean/ToClean/CMakeLists.txt b/Tests/MakeClean/ToClean/CMakeLists.txt
new file mode 100644
index 0000000..a05c38b
--- /dev/null
+++ b/Tests/MakeClean/ToClean/CMakeLists.txt
@@ -0,0 +1,122 @@
+cmake_minimum_required(VERSION 3.14)
+project(ToClean)
+
+# Utility variables
+set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
+set(CBD ${CMAKE_CURRENT_BINARY_DIR})
+set(CLEAN_FILE_CONTENT "File registered for cleaning.\n")
+
+# Lists build-time-generated files that should be cleaned away
+set_property(GLOBAL PROPERTY TOCLEAN_FILES "")
+function(addCleanFile FILENAME)
+ set_property(GLOBAL APPEND PROPERTY TOCLEAN_FILES "${FILENAME}")
+endfunction()
+function(writeCleanFile FILENAME)
+ file(WRITE "${FILENAME}" ${CLEAN_FILE_CONTENT})
+endfunction()
+
+set(DUMMY_CONTENT_FILE ${CSD}/toclean.cxx)
+
+# Build a simple project whose compiled objects should be cleaned.
+add_executable(toclean toclean.cxx)
+addCleanFile(
+ "${CBD}${CMAKE_FILES_DIRECTORY}/toclean.dir/toclean.cxx${CMAKE_CXX_OUTPUT_EXTENSION}")
+
+# Create a post build custom command that copies a dummy file
+# to a custom location
+function(addPostBuildFile TARGET FILENAME)
+ add_custom_command(TARGET ${TARGET} POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${DUMMY_CONTENT_FILE} ${FILENAME})
+endfunction()
+
+# Create a custom command whose output should be cleaned.
+set(CustomCommandFile "${CBD}/CustomCommandFile.txt")
+add_custom_command(OUTPUT ${CustomCommandFile}
+ DEPENDS ${DUMMY_CONTENT_FILE}
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${DUMMY_CONTENT_FILE} ${CustomCommandFile})
+add_custom_target(customTarget ALL DEPENDS ${CustomCommandFile})
+addCleanFile(${CustomCommandFile})
+
+
+### Tests ADDITIONAL_MAKE_CLEAN_FILES directory property
+if("${CMAKE_GENERATOR}" MATCHES "Makefile")
+ # Create a file that must be registered for cleaning.
+ set(MakeDirPropFileAbs "${CBD}/MakeDirPropFile.txt")
+ writeCleanFile("${MakeDirPropFileAbs}")
+ set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${MakeDirPropFileAbs}")
+ addCleanFile(${MakeDirPropFileAbs})
+
+ # Create a custom command whose output should be cleaned, but whose name
+ # is not known until generate-time
+ set(MakeDirPropExpFileRel "MakeDirProp_copy${CMAKE_EXECUTABLE_SUFFIX}")
+ set(MakeDirPropExpFileAbs "$<TARGET_FILE_DIR:toclean>/${MakeDirPropExpFileRel}")
+ addPostBuildFile(toclean "${MakeDirPropExpFileAbs}")
+ set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${MakeDirPropExpFileAbs})
+ addCleanFile("${CBD}/${MakeDirPropExpFileRel}")
+endif()
+
+
+### Tests ADDITIONAL_CLEAN_FILES directory property
+
+# Register a file path relative to the build directory
+set(DirPropFileRel "DirPropFileRel.txt")
+writeCleanFile("${CBD}/${DirPropFileRel}")
+set_directory_properties(PROPERTIES ADDITIONAL_CLEAN_FILES ${DirPropFileRel})
+addCleanFile("${CBD}/${DirPropFileRel}")
+
+# Register an absolute file path
+set(DirPropFileAbs "${CBD}/DirPropFileAbs.txt")
+writeCleanFile("${DirPropFileAbs}")
+set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${DirPropFileAbs})
+addCleanFile("${DirPropFileAbs}")
+
+# Create a custom command whose output should be cleaned, but whose name
+# is not known until generate-time
+set(DirPropExpFileRel "DirProp_copy${CMAKE_EXECUTABLE_SUFFIX}")
+set(DirPropExpFileAbs "$<TARGET_FILE_DIR:toclean>/${DirPropExpFileRel}")
+addPostBuildFile(toclean "${DirPropExpFileAbs}")
+set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${DirPropExpFileAbs})
+addCleanFile("${CBD}/${DirPropExpFileRel}")
+
+
+### Tests ADDITIONAL_CLEAN_FILES target property
+
+function(test_target_property TARGET)
+ # Register a file path relative to the build directory
+ set(TgtPropFileRel "${TARGET}_TargetPropFileRel.txt")
+ writeCleanFile("${CBD}/${TgtPropFileRel}")
+ set_target_properties(${TARGET} PROPERTIES ADDITIONAL_CLEAN_FILES ${TgtPropFileRel})
+ addCleanFile("${CBD}/${TgtPropFileRel}")
+
+ # Register an absolute file path
+ set(TgtPropFileAbs "${CBD}/${TARGET}_TargetPropFileAbs.txt")
+ writeCleanFile("${TgtPropFileAbs}")
+ set_property(TARGET ${TARGET} APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${TgtPropFileAbs})
+ addCleanFile("${TgtPropFileAbs}")
+
+ # Create a custom command whose output should be cleaned, but whose name
+ # is not known until generate-time
+ set(TgtPropExpFileRel "${TARGET}_TargetPropGenExp.txt")
+ set(TgtPropExpFileAbs "$<TARGET_FILE_DIR:toclean>/${TgtPropExpFileRel}")
+ addPostBuildFile(${TARGET} "${TgtPropExpFileAbs}")
+ set_property(TARGET ${TARGET} APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${TgtPropExpFileAbs})
+ addCleanFile("${CBD}/${TgtPropExpFileRel}")
+endfunction()
+
+# Test target property for various target types
+add_executable(acf_exec toclean.cxx)
+test_target_property(acf_exec)
+add_library(acf_lib toclean.cxx)
+test_target_property(acf_lib)
+add_custom_target(acf_custom ALL DEPENDS ${CustomCommandFile})
+test_target_property(acf_custom)
+
+# Process subdirectory without targets
+add_subdirectory(EmptySubDir)
+
+
+# Configure a file listing these build-time-generated files.
+get_property(TOCLEAN_FILES GLOBAL PROPERTY TOCLEAN_FILES)
+configure_file(${CSD}/ToCleanFiles.cmake.in ${CBD}/ToCleanFiles.cmake @ONLY)
diff --git a/Tests/MakeClean/ToClean/EmptySubDir/CMakeLists.txt b/Tests/MakeClean/ToClean/EmptySubDir/CMakeLists.txt
new file mode 100644
index 0000000..55893ae
--- /dev/null
+++ b/Tests/MakeClean/ToClean/EmptySubDir/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.14)
+
+# Subdirectory CMakeLists.txt without targets
+set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
+set(CBD ${CMAKE_CURRENT_BINARY_DIR})
+
+# Register a file path relative to the build directory
+set(DirPropFileRel "DirPropFileRel.txt")
+writeCleanFile("${CBD}/${DirPropFileRel}")
+set_directory_properties(PROPERTIES ADDITIONAL_CLEAN_FILES ${DirPropFileRel})
+addCleanFile("${CBD}/${DirPropFileRel}")
+
+# Register an absolute file path
+set(DirPropFileAbs "${CBD}/DirPropFileAbs.txt")
+writeCleanFile("${DirPropFileAbs}")
+set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${DirPropFileAbs})
+addCleanFile("${DirPropFileAbs}")
diff --git a/Tests/MakeClean/ToClean/ToCleanFiles.cmake.in b/Tests/MakeClean/ToClean/ToCleanFiles.cmake.in
new file mode 100644
index 0000000..e7d9947
--- /dev/null
+++ b/Tests/MakeClean/ToClean/ToCleanFiles.cmake.in
@@ -0,0 +1 @@
+set(TOCLEAN_FILES "@TOCLEAN_FILES@")
diff --git a/Tests/MakeClean/ToClean/toclean.cxx b/Tests/MakeClean/ToClean/toclean.cxx
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/MakeClean/ToClean/toclean.cxx
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/MakeClean/check_clean.c.in b/Tests/MakeClean/check_clean.c.in
new file mode 100644
index 0000000..e5a7945
--- /dev/null
+++ b/Tests/MakeClean/check_clean.c.in
@@ -0,0 +1,26 @@
+#include <stdio.h>
+
+int main()
+{
+ /* The list of files to check. */
+ const char* files[] =
+ {
+ @CHECK_FILES@
+ 0
+ };
+
+ /* No file should exist. */
+ const char** f = files;
+ int result = 0;
+ for(; *f; ++f)
+ {
+ FILE* pf = fopen(*f, "rb");
+ if(pf)
+ {
+ fclose(pf);
+ fprintf(stderr, "File \"%s\" still exists!\n", *f);
+ result = 1;
+ }
+ }
+ return result;
+}
diff --git a/Tests/MathTest/CMakeLists.txt b/Tests/MathTest/CMakeLists.txt
new file mode 100644
index 0000000..396f633
--- /dev/null
+++ b/Tests/MathTest/CMakeLists.txt
@@ -0,0 +1,55 @@
+cmake_minimum_required (VERSION 2.6)
+project(MathTest)
+
+
+# Expression test
+
+set(expressions
+ "5 * ( 3 + 4)"
+ "(1 | 2 | 4 | 8) & 16"
+ "1 +(3*4) + 10 >> 2"
+ "10000 / 20 / 4"
+ "10000 / (20 / 4)"
+ "-1 + +1"
+ "+1 - -1"
+ "+1 - - + + -(-3 + - - +1)"
+ "1000 -12*5"
+ "1000 +12*-5"
+ "1000 -12*-5"
+ "~~1"
+ "1000 & ~0"
+ )
+
+set(FILE_EXPRESSIONS "extern void test_expression(int x, int y, const char * text);\n")
+
+
+macro(add_math_test expression)
+ math(EXPR result ${expression} ${ARGV1} ${ARGV2})
+ set(CODE "test_expression(${expression}, ${result}, \"${expression}\");")
+ string(APPEND FILE_EXPRESSIONS "${CODE}\n")
+endmacro()
+
+macro(add_math_tests)
+ foreach (expression ${expressions})
+ add_math_test(${expression} ${ARGV0} ${ARGV1})
+ endforeach ()
+endmacro()
+
+add_math_tests()
+add_math_tests("OUTPUT_FORMAT" "DECIMAL")
+add_math_tests("OUTPUT_FORMAT" "HEXADECIMAL")
+
+# Avoid the test with negative result and hexadecimal formatting
+# therefore more tests with a negative result
+add_math_test("-12*5")
+add_math_test("12*-5")
+
+
+configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/MathTestTests.h.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/MathTestTests.h"
+ @ONLY)
+
+include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+add_executable(MathTest MathTestExec.cxx)
+
diff --git a/Tests/MathTest/MathTestExec.cxx b/Tests/MathTest/MathTestExec.cxx
new file mode 100644
index 0000000..fbcddc4
--- /dev/null
+++ b/Tests/MathTest/MathTestExec.cxx
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int res = 0;
+bool print = false;
+
+void test_expression(int x, int y, const char* text)
+{
+ bool fail = (x) != (y);
+ if (fail) {
+ res++;
+ printf("Problem with EXPR:");
+ }
+ if (fail || print) {
+ printf("Expression: \"%s\" in CMake returns %d", text, (y));
+ if (fail) {
+ printf(" while in C returns: %d", (x));
+ }
+ printf("\n");
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ if (argc > 2) {
+ printf("Usage: %s [print]\n", argv[0]);
+ return 1;
+ }
+
+ if (argc > 1) {
+ if (strcmp(argv[1], "print") != 0) {
+ printf("Usage: %s [print]\n", argv[0]);
+ return 1;
+ }
+ print = true;
+ }
+
+#include "MathTestTests.h"
+
+ if (res != 0) {
+ printf("%s: %d math tests failed\n", argv[0], res);
+ return 1;
+ }
+ return 0;
+}
diff --git a/Tests/MathTest/MathTestTests.h.in b/Tests/MathTest/MathTestTests.h.in
new file mode 100644
index 0000000..39c6861
--- /dev/null
+++ b/Tests/MathTest/MathTestTests.h.in
@@ -0,0 +1 @@
+@FILE_EXPRESSIONS@
diff --git a/Tests/MissingInstall/CMakeLists.txt b/Tests/MissingInstall/CMakeLists.txt
new file mode 100644
index 0000000..365b31f
--- /dev/null
+++ b/Tests/MissingInstall/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required (VERSION 3.9)
+project(TestMissingInstall)
+
+set(CMAKE_SKIP_INSTALL_RULES ON)
+
+# Skip the dependency that causes a build when installing. This
+# avoids infinite loops when the post-build rule below installs.
+set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY 1)
+set(CMAKE_SKIP_PACKAGE_ALL_DEPENDENCY 1)
+
+get_property(MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+
+add_executable(mybin mybin.cpp)
+install(TARGETS mybin RUNTIME DESTINATION bin)
+
+add_custom_command(TARGET mybin
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} "-DMULTI_CONFIG=${MULTI_CONFIG}"
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/ExpectInstallFail.cmake
+ COMMENT "Install Project"
+)
diff --git a/Tests/MissingInstall/ExpectInstallFail.cmake b/Tests/MissingInstall/ExpectInstallFail.cmake
new file mode 100644
index 0000000..3d677bf
--- /dev/null
+++ b/Tests/MissingInstall/ExpectInstallFail.cmake
@@ -0,0 +1,18 @@
+if(MULTI_CONFIG)
+ set(SI_CONFIG --config $<CONFIGURATION>)
+else()
+ set(SI_CONFIG)
+endif()
+
+execute_process(
+ COMMAND ${CMAKE_COMMAND}
+ --build .
+ --target install ${SI_CONFIG}
+ RESULT_VARIABLE RESULT
+ OUTPUT_VARIABLE OUTPUT
+ ERROR_VARIABLE ERROR
+)
+
+if(RESULT EQUAL 0)
+ message(FATAL_ERROR "install should have failed")
+endif()
diff --git a/Tests/MissingInstall/mybin.cpp b/Tests/MissingInstall/mybin.cpp
new file mode 100644
index 0000000..5047a34
--- /dev/null
+++ b/Tests/MissingInstall/mybin.cpp
@@ -0,0 +1,3 @@
+int main()
+{
+}
diff --git a/Tests/MissingSourceFile/CMakeLists.txt b/Tests/MissingSourceFile/CMakeLists.txt
new file mode 100644
index 0000000..b4f0033
--- /dev/null
+++ b/Tests/MissingSourceFile/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(MissingSourceFile C)
+add_executable(MissingSourceFile DoesNotExist/MissingSourceFile.c)
diff --git a/Tests/Module/CheckIPOSupported-C/CMakeLists.txt b/Tests/Module/CheckIPOSupported-C/CMakeLists.txt
new file mode 100644
index 0000000..c5cd03e
--- /dev/null
+++ b/Tests/Module/CheckIPOSupported-C/CMakeLists.txt
@@ -0,0 +1,30 @@
+cmake_minimum_required(VERSION 3.8)
+project(CheckIPOSupported-C LANGUAGES C)
+
+cmake_policy(SET CMP0069 NEW)
+
+include(CheckIPOSupported)
+check_ipo_supported(RESULT ipo_supported OUTPUT ipo_output)
+if(ipo_supported)
+ set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
+elseif(CMake_TEST_IPO_WORKS_C)
+ string(REPLACE "\n" "\n " ipo_output "${ipo_output}")
+ message(FATAL_ERROR "IPO expected to work, but the check failed:\n ${ipo_output}")
+endif()
+
+add_library(foo foo.c)
+if(NOT CYGWIN AND (NOT WIN32 OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang"))
+ add_library(bar SHARED bar.c)
+ if(WIN32)
+ # Bindexplib for clang supports LTO objects
+ set_target_properties(bar PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
+ endif()
+else()
+ # TODO: bindexplib doesn't support exporting IPO symbols with other compilers on Windows
+ add_library(bar STATIC bar.c)
+endif()
+add_executable(CheckIPOSupported-C main.c)
+target_link_libraries(CheckIPOSupported-C PUBLIC foo bar)
+
+enable_testing()
+add_test(NAME CheckIPOSupported-C COMMAND CheckIPOSupported-C)
diff --git a/Tests/Module/CheckIPOSupported-C/bar.c b/Tests/Module/CheckIPOSupported-C/bar.c
new file mode 100644
index 0000000..680f213
--- /dev/null
+++ b/Tests/Module/CheckIPOSupported-C/bar.c
@@ -0,0 +1,4 @@
+int bar()
+{
+ return 0x42;
+}
diff --git a/Tests/Module/CheckIPOSupported-C/foo.c b/Tests/Module/CheckIPOSupported-C/foo.c
new file mode 100644
index 0000000..1e56597
--- /dev/null
+++ b/Tests/Module/CheckIPOSupported-C/foo.c
@@ -0,0 +1,4 @@
+int foo()
+{
+ return 0x42;
+}
diff --git a/Tests/Module/CheckIPOSupported-C/main.c b/Tests/Module/CheckIPOSupported-C/main.c
new file mode 100644
index 0000000..28ab26f
--- /dev/null
+++ b/Tests/Module/CheckIPOSupported-C/main.c
@@ -0,0 +1,10 @@
+int foo();
+int bar();
+
+int main()
+{
+ if (foo() != bar()) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/Tests/Module/CheckIPOSupported-CXX/CMakeLists.txt b/Tests/Module/CheckIPOSupported-CXX/CMakeLists.txt
new file mode 100644
index 0000000..237bf1d
--- /dev/null
+++ b/Tests/Module/CheckIPOSupported-CXX/CMakeLists.txt
@@ -0,0 +1,31 @@
+cmake_minimum_required(VERSION 3.8)
+project(CheckIPOSupported-CXX LANGUAGES CXX)
+
+cmake_policy(SET CMP0069 NEW)
+
+include(CheckIPOSupported)
+check_ipo_supported(RESULT ipo_supported OUTPUT ipo_output)
+if(ipo_supported)
+ set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
+elseif(CMake_TEST_IPO_WORKS_CXX)
+ string(REPLACE "\n" "\n " ipo_output "${ipo_output}")
+ message(FATAL_ERROR "IPO expected to work, but the check failed:\n ${ipo_output}")
+endif()
+
+
+add_library(foo STATIC foo.cpp)
+if(NOT CYGWIN AND (NOT WIN32 OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang"))
+ add_library(bar SHARED bar.cpp)
+ if(WIN32)
+ # Bindexplib for clang supports LTO objects
+ set_target_properties(bar PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
+ endif()
+else()
+ # TODO: bindexplib doesn't support exporting IPO symbols with other compilers on Windows
+ add_library(bar STATIC bar.cpp)
+endif()
+add_executable(CheckIPOSupported-CXX main.cpp)
+target_link_libraries(CheckIPOSupported-CXX PUBLIC foo bar)
+
+enable_testing()
+add_test(NAME CheckIPOSupported-CXX COMMAND CheckIPOSupported-CXX)
diff --git a/Tests/Module/CheckIPOSupported-CXX/bar.cpp b/Tests/Module/CheckIPOSupported-CXX/bar.cpp
new file mode 100644
index 0000000..680f213
--- /dev/null
+++ b/Tests/Module/CheckIPOSupported-CXX/bar.cpp
@@ -0,0 +1,4 @@
+int bar()
+{
+ return 0x42;
+}
diff --git a/Tests/Module/CheckIPOSupported-CXX/foo.cpp b/Tests/Module/CheckIPOSupported-CXX/foo.cpp
new file mode 100644
index 0000000..1e56597
--- /dev/null
+++ b/Tests/Module/CheckIPOSupported-CXX/foo.cpp
@@ -0,0 +1,4 @@
+int foo()
+{
+ return 0x42;
+}
diff --git a/Tests/Module/CheckIPOSupported-CXX/main.cpp b/Tests/Module/CheckIPOSupported-CXX/main.cpp
new file mode 100644
index 0000000..28ab26f
--- /dev/null
+++ b/Tests/Module/CheckIPOSupported-CXX/main.cpp
@@ -0,0 +1,10 @@
+int foo();
+int bar();
+
+int main()
+{
+ if (foo() != bar()) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/Tests/Module/CheckIPOSupported-Fortran/CMakeLists.txt b/Tests/Module/CheckIPOSupported-Fortran/CMakeLists.txt
new file mode 100644
index 0000000..3872b56
--- /dev/null
+++ b/Tests/Module/CheckIPOSupported-Fortran/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.8)
+project(CheckIPOSupported-Fortran LANGUAGES Fortran)
+
+cmake_policy(SET CMP0069 NEW)
+
+include(CheckIPOSupported)
+check_ipo_supported(RESULT ipo_supported OUTPUT ipo_output)
+if(ipo_supported)
+ set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
+elseif(CMake_TEST_IPO_WORKS_Fortran)
+ string(REPLACE "\n" "\n " ipo_output "${ipo_output}")
+ message(FATAL_ERROR "IPO expected to work, but the check failed:\n ${ipo_output}")
+endif()
+
+add_library(foo foo.f)
+add_executable(CheckIPOSupported-Fortran main.f)
+target_link_libraries(CheckIPOSupported-Fortran PUBLIC foo)
+
+enable_testing()
+add_test(NAME CheckIPOSupported-Fortran COMMAND CheckIPOSupported-Fortran)
diff --git a/Tests/Module/CheckIPOSupported-Fortran/foo.f b/Tests/Module/CheckIPOSupported-Fortran/foo.f
new file mode 100644
index 0000000..945d2d5
--- /dev/null
+++ b/Tests/Module/CheckIPOSupported-Fortran/foo.f
@@ -0,0 +1,2 @@
+ SUBROUTINE FOO
+ END
diff --git a/Tests/Module/CheckIPOSupported-Fortran/main.f b/Tests/Module/CheckIPOSupported-Fortran/main.f
new file mode 100644
index 0000000..9d1de9f
--- /dev/null
+++ b/Tests/Module/CheckIPOSupported-Fortran/main.f
@@ -0,0 +1,3 @@
+ PROGRAM BOO
+ CALL FOO()
+ END
diff --git a/Tests/Module/CheckTypeSize/CMakeLists.txt b/Tests/Module/CheckTypeSize/CMakeLists.txt
new file mode 100644
index 0000000..102cf0c
--- /dev/null
+++ b/Tests/Module/CheckTypeSize/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 2.8.1 FATAL_ERROR)
+project(CheckTypeSize)
+
+# Check C types
+include(CheckTypeSize)
+check_type_size("void*" SIZEOF_DATA_PTR)
+check_type_size(char SIZEOF_CHAR)
+check_type_size(short SIZEOF_SHORT)
+check_type_size(int SIZEOF_INT)
+check_type_size(long SIZEOF_LONG)
+check_type_size("long long" SIZEOF_LONG_LONG)
+check_type_size(__int64 SIZEOF___INT64)
+check_type_size(size_t SIZEOF_SIZE_T)
+check_type_size(ssize_t SIZEOF_SSIZE_T)
+
+set(CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}")
+set(CMAKE_EXTRA_INCLUDE_FILES somestruct.h)
+check_type_size("((struct somestruct*)0)->someint" SIZEOF_STRUCTMEMBER_INT)
+check_type_size("((struct somestruct*)0)->someptr" SIZEOF_STRUCTMEMBER_PTR)
+check_type_size("((struct somestruct*)0)->somechar" SIZEOF_STRUCTMEMBER_CHAR)
+
+# Check CXX types
+check_type_size(bool SIZEOF_BOOL LANGUAGE CXX)
+check_type_size(uint8_t SIZEOF_UINT8_T LANGUAGE CXX)
+check_type_size(std::uint8_t SIZEOF_STD_UINT8_T LANGUAGE CXX)
+
+set(CMAKE_EXTRA_INCLUDE_FILES someclass.hxx)
+check_type_size("((ns::someclass*)0)->someint" SIZEOF_NS_CLASSMEMBER_INT LANGUAGE CXX)
+check_type_size("((ns::someclass*)0)->someptr" SIZEOF_NS_CLASSMEMBER_PTR LANGUAGE CXX)
+check_type_size("((ns::someclass*)0)->somechar" SIZEOF_NS_CLASSMEMBER_CHAR LANGUAGE CXX)
+check_type_size("((ns::someclass*)0)->somebool" SIZEOF_NS_CLASSMEMBER_BOOL LANGUAGE CXX)
+
+configure_file(config.h.in config.h)
+configure_file(config.hxx.in config.hxx)
+
+include_directories("${CheckTypeSize_BINARY_DIR}")
+
+add_executable(CheckTypeSize CheckTypeSize.c)
+add_executable(CheckTypeSizeCXX CheckTypeSize.cxx)
diff --git a/Tests/Module/CheckTypeSize/CheckTypeSize.c b/Tests/Module/CheckTypeSize/CheckTypeSize.c
new file mode 100644
index 0000000..adfd2fc
--- /dev/null
+++ b/Tests/Module/CheckTypeSize/CheckTypeSize.c
@@ -0,0 +1,161 @@
+#include "config.h"
+#include "somestruct.h"
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+
+#include <stdio.h>
+
+#define CHECK(t, m) \
+ do { \
+ if (sizeof(t) != m) { \
+ printf(#m ": expected %d, got %d (line %d)\n", (int)sizeof(t), (int)m, \
+ __LINE__); \
+ result = 1; \
+ } \
+ } while (0)
+
+#define NODEF(m) \
+ do { \
+ printf(#m ": not defined (line %d)\n", __LINE__); \
+ result = 1; \
+ } while (0)
+
+int main()
+{
+ int result = 0;
+ struct somestruct x;
+
+/* void* */
+#if !defined(HAVE_SIZEOF_DATA_PTR)
+ NODEF(HAVE_SIZEOF_DATA_PTR);
+#endif
+#if defined(SIZEOF_DATA_PTR)
+ CHECK(void*, SIZEOF_DATA_PTR);
+#else
+ NODEF(SIZEOF_DATA_PTR);
+#endif
+
+/* char */
+#if !defined(HAVE_SIZEOF_CHAR)
+ NODEF(HAVE_SIZEOF_CHAR);
+#endif
+#if defined(SIZEOF_CHAR)
+ CHECK(char, SIZEOF_CHAR);
+#else
+ NODEF(SIZEOF_CHAR);
+#endif
+
+/* short */
+#if !defined(HAVE_SIZEOF_SHORT)
+ NODEF(HAVE_SIZEOF_SHORT);
+#endif
+#if defined(SIZEOF_SHORT)
+ CHECK(short, SIZEOF_SHORT);
+#else
+ NODEF(SIZEOF_SHORT);
+#endif
+
+/* int */
+#if !defined(HAVE_SIZEOF_INT)
+ NODEF(HAVE_SIZEOF_INT);
+#endif
+#if defined(SIZEOF_INT)
+ CHECK(int, SIZEOF_INT);
+#else
+ NODEF(SIZEOF_INT);
+#endif
+
+/* long */
+#if !defined(HAVE_SIZEOF_LONG)
+ NODEF(HAVE_SIZEOF_LONG);
+#endif
+#if defined(SIZEOF_LONG)
+ CHECK(long, SIZEOF_LONG);
+#else
+ NODEF(SIZEOF_LONG);
+#endif
+
+/* long long */
+#if defined(SIZEOF_LONG_LONG)
+ CHECK(long long, SIZEOF_LONG_LONG);
+# if !defined(HAVE_SIZEOF_LONG_LONG)
+ NODEF(HAVE_SIZEOF_LONG_LONG);
+# endif
+#endif
+
+/* __int64 */
+#if defined(SIZEOF___INT64)
+ CHECK(__int64, SIZEOF___INT64);
+# if !defined(HAVE_SIZEOF___INT64)
+ NODEF(HAVE_SIZEOF___INT64);
+# endif
+#elif defined(HAVE_SIZEOF___INT64)
+ NODEF(SIZEOF___INT64);
+#endif
+
+/* size_t */
+#if !defined(HAVE_SIZEOF_SIZE_T)
+ NODEF(HAVE_SIZEOF_SIZE_T);
+#endif
+#if defined(SIZEOF_SIZE_T)
+ CHECK(size_t, SIZEOF_SIZE_T);
+#else
+ NODEF(SIZEOF_SIZE_T);
+#endif
+
+/* ssize_t */
+#if defined(SIZEOF_SSIZE_T)
+ CHECK(ssize_t, SIZEOF_SSIZE_T);
+# if !defined(HAVE_SIZEOF_SSIZE_T)
+ NODEF(HAVE_SIZEOF_SSIZE_T);
+# endif
+#elif defined(HAVE_SIZEOF_SSIZE_T)
+ NODEF(SIZEOF_SSIZE_T);
+#endif
+
+/* struct somestruct::someint */
+#if defined(SIZEOF_STRUCTMEMBER_INT)
+ CHECK(x.someint, SIZEOF_STRUCTMEMBER_INT);
+ CHECK(x.someint, SIZEOF_INT);
+# if !defined(HAVE_SIZEOF_STRUCTMEMBER_INT)
+ NODEF(HAVE_SIZEOF_STRUCTMEMBER_INT);
+# endif
+#elif defined(HAVE_SIZEOF_STRUCTMEMBER_INT)
+ NODEF(SIZEOF_STRUCTMEMBER_INT);
+#endif
+
+/* struct somestruct::someptr */
+#if defined(SIZEOF_STRUCTMEMBER_PTR)
+ CHECK(x.someptr, SIZEOF_STRUCTMEMBER_PTR);
+ CHECK(x.someptr, SIZEOF_DATA_PTR);
+# if !defined(HAVE_SIZEOF_STRUCTMEMBER_PTR)
+ NODEF(HAVE_SIZEOF_STRUCTMEMBER_PTR);
+# endif
+#elif defined(HAVE_SIZEOF_STRUCTMEMBER_PTR)
+ NODEF(SIZEOF_STRUCTMEMBER_PTR);
+#endif
+
+/* struct somestruct::someint */
+#if defined(SIZEOF_STRUCTMEMBER_CHAR)
+ CHECK(x.somechar, SIZEOF_STRUCTMEMBER_CHAR);
+ CHECK(x.somechar, SIZEOF_CHAR);
+# if !defined(HAVE_SIZEOF_STRUCTMEMBER_CHAR)
+ NODEF(HAVE_SIZEOF_STRUCTMEMBER_CHAR);
+# endif
+#elif defined(HAVE_SIZEOF_STRUCTMEMBER_CHAR)
+ NODEF(SIZEOF_STRUCTMEMBER_CHAR);
+#endif
+
+ /* to avoid possible warnings about unused or write-only variable */
+ x.someint = result;
+
+ return x.someint;
+}
diff --git a/Tests/Module/CheckTypeSize/CheckTypeSize.cxx b/Tests/Module/CheckTypeSize/CheckTypeSize.cxx
new file mode 100644
index 0000000..45cd393
--- /dev/null
+++ b/Tests/Module/CheckTypeSize/CheckTypeSize.cxx
@@ -0,0 +1,199 @@
+#include "config.h"
+#include "config.hxx"
+#include "someclass.hxx"
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+#ifdef HAVE_CSTDINT
+# include <cstdint>
+#endif
+#ifdef HAVE_CSTDDEF
+# include <cstddef>
+#endif
+
+#include <stdio.h>
+
+#define CHECK(t, m) \
+ do { \
+ if (sizeof(t) != m) { \
+ printf(#m ": expected %d, got %d (line %d)\n", (int)sizeof(t), (int)m, \
+ __LINE__); \
+ result = 1; \
+ } \
+ } while (0)
+
+#define NODEF(m) \
+ do { \
+ printf(#m ": not defined (line %d)\n", __LINE__); \
+ result = 1; \
+ } while (0)
+
+int main()
+{
+ int result = 0;
+ ns::someclass y;
+
+/* void* */
+#if !defined(HAVE_SIZEOF_DATA_PTR)
+ NODEF(HAVE_SIZEOF_DATA_PTR);
+#endif
+#if defined(SIZEOF_DATA_PTR)
+ CHECK(void*, SIZEOF_DATA_PTR);
+#else
+ NODEF(SIZEOF_DATA_PTR);
+#endif
+
+/* char */
+#if !defined(HAVE_SIZEOF_CHAR)
+ NODEF(HAVE_SIZEOF_CHAR);
+#endif
+#if defined(SIZEOF_CHAR)
+ CHECK(char, SIZEOF_CHAR);
+#else
+ NODEF(SIZEOF_CHAR);
+#endif
+
+/* short */
+#if !defined(HAVE_SIZEOF_SHORT)
+ NODEF(HAVE_SIZEOF_SHORT);
+#endif
+#if defined(SIZEOF_SHORT)
+ CHECK(short, SIZEOF_SHORT);
+#else
+ NODEF(SIZEOF_SHORT);
+#endif
+
+/* int */
+#if !defined(HAVE_SIZEOF_INT)
+ NODEF(HAVE_SIZEOF_INT);
+#endif
+#if defined(SIZEOF_INT)
+ CHECK(int, SIZEOF_INT);
+#else
+ NODEF(SIZEOF_INT);
+#endif
+
+/* long */
+#if !defined(HAVE_SIZEOF_LONG)
+ NODEF(HAVE_SIZEOF_LONG);
+#endif
+#if defined(SIZEOF_LONG)
+ CHECK(long, SIZEOF_LONG);
+#else
+ NODEF(SIZEOF_LONG);
+#endif
+
+/* long long */
+#if defined(SIZEOF_LONG_LONG)
+ CHECK(long long, SIZEOF_LONG_LONG);
+# if !defined(HAVE_SIZEOF_LONG_LONG)
+ NODEF(HAVE_SIZEOF_LONG_LONG);
+# endif
+#endif
+
+/* __int64 */
+#if defined(SIZEOF___INT64)
+ CHECK(__int64, SIZEOF___INT64);
+# if !defined(HAVE_SIZEOF___INT64)
+ NODEF(HAVE_SIZEOF___INT64);
+# endif
+#elif defined(HAVE_SIZEOF___INT64)
+ NODEF(SIZEOF___INT64);
+#endif
+
+/* size_t */
+#if !defined(HAVE_SIZEOF_SIZE_T)
+ NODEF(HAVE_SIZEOF_SIZE_T);
+#endif
+#if defined(SIZEOF_SIZE_T)
+ CHECK(size_t, SIZEOF_SIZE_T);
+#else
+ NODEF(SIZEOF_SIZE_T);
+#endif
+
+/* ssize_t */
+#if defined(SIZEOF_SSIZE_T)
+ CHECK(ssize_t, SIZEOF_SSIZE_T);
+# if !defined(HAVE_SIZEOF_SSIZE_T)
+ NODEF(HAVE_SIZEOF_SSIZE_T);
+# endif
+#elif defined(HAVE_SIZEOF_SSIZE_T)
+ NODEF(SIZEOF_SSIZE_T);
+#endif
+
+/* uint8_t */
+#if defined(SIZEOF_UINT8_T)
+ CHECK(uint8_t, SIZEOF_UINT8_T);
+# if !defined(HAVE_SIZEOF_UINT8_T)
+ NODEF(HAVE_SIZEOF_UINT8_T);
+# endif
+#elif defined(HAVE_SIZEOF_UINT8_T)
+ NODEF(SIZEOF_UINT8_T);
+#endif
+
+/* std::uint8_t */
+#if defined(SIZEOF_STD_UINT8_T)
+ CHECK(std::uint8_t, SIZEOF_STD_UINT8_T);
+# if !defined(HAVE_SIZEOF_STD_UINT8_T)
+ NODEF(HAVE_SIZEOF_STD_UINT8_T);
+# endif
+#elif defined(HAVE_SIZEOF_STD_UINT8_T)
+ NODEF(SIZEOF_STD_UINT8_T);
+#endif
+
+/* ns::someclass::someint */
+#if defined(SIZEOF_NS_CLASSMEMBER_INT)
+ CHECK(y.someint, SIZEOF_NS_CLASSMEMBER_INT);
+ CHECK(y.someint, SIZEOF_INT);
+# if !defined(HAVE_SIZEOF_NS_CLASSMEMBER_INT)
+ NODEF(HAVE_SIZEOF_STRUCTMEMBER_INT);
+# endif
+#elif defined(HAVE_SIZEOF_STRUCTMEMBER_INT)
+ NODEF(SIZEOF_STRUCTMEMBER_INT);
+#endif
+
+/* ns::someclass::someptr */
+#if defined(SIZEOF_NS_CLASSMEMBER_PTR)
+ CHECK(y.someptr, SIZEOF_NS_CLASSMEMBER_PTR);
+ CHECK(y.someptr, SIZEOF_DATA_PTR);
+# if !defined(HAVE_SIZEOF_NS_CLASSMEMBER_PTR)
+ NODEF(HAVE_SIZEOF_NS_CLASSMEMBER_PTR);
+# endif
+#elif defined(HAVE_SIZEOF_NS_CLASSMEMBER_PTR)
+ NODEF(SIZEOF_NS_CLASSMEMBER_PTR);
+#endif
+
+/* ns::someclass::somechar */
+#if defined(SIZEOF_NS_CLASSMEMBER_CHAR)
+ CHECK(y.somechar, SIZEOF_NS_CLASSMEMBER_CHAR);
+ CHECK(y.somechar, SIZEOF_CHAR);
+# if !defined(HAVE_SIZEOF_NS_CLASSMEMBER_CHAR)
+ NODEF(HAVE_SIZEOF_NS_CLASSMEMBER_CHAR);
+# endif
+#elif defined(HAVE_SIZEOF_NS_CLASSMEMBER_CHAR)
+ NODEF(SIZEOF_NS_CLASSMEMBER_CHAR);
+#endif
+
+/* ns::someclass::somebool */
+#if defined(SIZEOF_NS_CLASSMEMBER_BOOL)
+ CHECK(y.somechar, SIZEOF_NS_CLASSMEMBER_BOOL);
+ CHECK(y.somechar, SIZEOF_BOOL);
+# if !defined(HAVE_SIZEOF_NS_CLASSMEMBER_BOOL)
+ NODEF(HAVE_SIZEOF_NS_CLASSMEMBER_BOOL);
+# endif
+#elif defined(HAVE_SIZEOF_NS_CLASSMEMBER_BOOL)
+ NODEF(SIZEOF_NS_CLASSMEMBER_BOOL);
+#endif
+
+ /* to avoid possible warnings about unused or write-only variable */
+ y.someint = result;
+
+ return y.someint;
+}
diff --git a/Tests/Module/CheckTypeSize/config.h.in b/Tests/Module/CheckTypeSize/config.h.in
new file mode 100644
index 0000000..c601075
--- /dev/null
+++ b/Tests/Module/CheckTypeSize/config.h.in
@@ -0,0 +1,51 @@
+#cmakedefine HAVE_SYS_TYPES_H
+#cmakedefine HAVE_STDINT_H
+#cmakedefine HAVE_STDDEF_H
+
+/* void* */
+#cmakedefine HAVE_SIZEOF_DATA_PTR
+@SIZEOF_DATA_PTR_CODE@
+
+/* char */
+#cmakedefine HAVE_SIZEOF_CHAR
+@SIZEOF_CHAR_CODE@
+
+/* short */
+#cmakedefine HAVE_SIZEOF_SHORT
+@SIZEOF_SHORT_CODE@
+
+/* int */
+#cmakedefine HAVE_SIZEOF_INT
+@SIZEOF_INT_CODE@
+
+/* long */
+#cmakedefine HAVE_SIZEOF_LONG
+@SIZEOF_LONG_CODE@
+
+/* long long */
+#cmakedefine HAVE_SIZEOF_LONG_LONG
+@SIZEOF_LONG_LONG_CODE@
+
+/* __int64 */
+#cmakedefine HAVE_SIZEOF___INT64
+@SIZEOF___INT64_CODE@
+
+/* size_t */
+#cmakedefine HAVE_SIZEOF_SIZE_T
+@SIZEOF_SIZE_T_CODE@
+
+/* ssize_t */
+#cmakedefine HAVE_SIZEOF_SSIZE_T
+@SIZEOF_SSIZE_T_CODE@
+
+/* struct somestruct::someint */
+#cmakedefine HAVE_SIZEOF_STRUCTMEMBER_INT
+@SIZEOF_STRUCTMEMBER_INT_CODE@
+
+/* struct somestruct::someptr */
+#cmakedefine HAVE_SIZEOF_STRUCTMEMBER_PTR
+@SIZEOF_STRUCTMEMBER_PTR_CODE@
+
+/* struct somestruct::somechar */
+#cmakedefine HAVE_SIZEOF_STRUCTMEMBER_CHAR
+@SIZEOF_STRUCTMEMBER_CHAR_CODE@
diff --git a/Tests/Module/CheckTypeSize/config.hxx.in b/Tests/Module/CheckTypeSize/config.hxx.in
new file mode 100644
index 0000000..9a80689
--- /dev/null
+++ b/Tests/Module/CheckTypeSize/config.hxx.in
@@ -0,0 +1,33 @@
+#cmakedefine HAVE_SYS_TYPES_H
+#cmakedefine HAVE_STDINT_H
+#cmakedefine HAVE_STDDEF_H
+#cmakedefine HAVE_CSTDINT
+#cmakedefine HAVE_CSTDDEF
+
+/* bool */
+#cmakedefine HAVE_SIZEOF_BOOL
+@SIZEOF_BOOL_CODE@
+
+/* uint8_t */
+#cmakedefine HAVE_SIZEOF_UINT8_T
+@SIZEOF_UINT8_T_CODE@
+
+/* std::uint8_t */
+#cmakedefine HAVE_SIZEOF_STD_UINT8_T
+@SIZEOF_STD_UINT8_T_CODE@
+
+/* struct ns::somestruct::someint */
+#cmakedefine HAVE_SIZEOF_NS_STRUCTMEMBER_INT
+@SIZEOF_NS_STRUCTMEMBER_INT_CODE@
+
+/* struct ns::somestruct::someptr */
+#cmakedefine HAVE_SIZEOF_NS_STRUCTMEMBER_PTR
+@SIZEOF_NS_STRUCTMEMBER_PTR_CODE@
+
+/* struct ns::somestruct::somechar */
+#cmakedefine HAVE_SIZEOF_NS_STRUCTMEMBER_CHAR
+@SIZEOF_NS_STRUCTMEMBER_CHAR_CODE@
+
+/* struct ns::somestruct::somebool */
+#cmakedefine HAVE_SIZEOF_NS_STRUCTMEMBER_BOOL
+@SIZEOF_NS_STRUCTMEMBER_BOOL_CODE@
diff --git a/Tests/Module/CheckTypeSize/someclass.hxx b/Tests/Module/CheckTypeSize/someclass.hxx
new file mode 100644
index 0000000..60d90db
--- /dev/null
+++ b/Tests/Module/CheckTypeSize/someclass.hxx
@@ -0,0 +1,15 @@
+#ifndef _CMAKE_SOMECLASS_HXX
+#define _CMAKE_SOMECLASS_HXX
+
+namespace ns {
+class someclass
+{
+public:
+ int someint;
+ void* someptr;
+ char somechar;
+ bool somebool;
+};
+}
+
+#endif
diff --git a/Tests/Module/CheckTypeSize/somestruct.h b/Tests/Module/CheckTypeSize/somestruct.h
new file mode 100644
index 0000000..ffff34f
--- /dev/null
+++ b/Tests/Module/CheckTypeSize/somestruct.h
@@ -0,0 +1,11 @@
+#ifndef _CMAKE_SOMESTRUCT_H
+#define _CMAKE_SOMESTRUCT_H
+
+struct somestruct
+{
+ int someint;
+ void* someptr;
+ char somechar;
+};
+
+#endif
diff --git a/Tests/Module/ExternalData/.gitattributes b/Tests/Module/ExternalData/.gitattributes
new file mode 100644
index 0000000..516129b
--- /dev/null
+++ b/Tests/Module/ExternalData/.gitattributes
@@ -0,0 +1,5 @@
+MD5/* -text
+SHA1/* -text
+SHA224/* -text
+SHA256/* -text
+SHA3_256/* -text
diff --git a/Tests/Module/ExternalData/Alt/MyAlgoMap1-md5/dded55e43cd6529ee35d24113dfc87a3 b/Tests/Module/ExternalData/Alt/MyAlgoMap1-md5/dded55e43cd6529ee35d24113dfc87a3
new file mode 100644
index 0000000..fa0cb1a
--- /dev/null
+++ b/Tests/Module/ExternalData/Alt/MyAlgoMap1-md5/dded55e43cd6529ee35d24113dfc87a3
@@ -0,0 +1 @@
+DataAlgoMap \ No newline at end of file
diff --git a/Tests/Module/ExternalData/Alt/SHA1/85158f0c1996837976e858c42a9a7634bfe91b93 b/Tests/Module/ExternalData/Alt/SHA1/85158f0c1996837976e858c42a9a7634bfe91b93
new file mode 100644
index 0000000..fa0cb1a
--- /dev/null
+++ b/Tests/Module/ExternalData/Alt/SHA1/85158f0c1996837976e858c42a9a7634bfe91b93
@@ -0,0 +1 @@
+DataAlgoMap \ No newline at end of file
diff --git a/Tests/Module/ExternalData/CMakeLists.txt b/Tests/Module/ExternalData/CMakeLists.txt
new file mode 100644
index 0000000..737e17a
--- /dev/null
+++ b/Tests/Module/ExternalData/CMakeLists.txt
@@ -0,0 +1,59 @@
+cmake_minimum_required(VERSION 2.8.10.20130115)
+project(ExternalDataTest NONE)
+
+include(CTest)
+
+include(ExternalData)
+
+if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" MATCHES "^/")
+ set(slash /)
+endif()
+set(ExternalData_URL_TEMPLATES
+ "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/%(algo)/%(hash)"
+ "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/Alt/%(algo:MyAlgoMap1)/%(hash)"
+ "ExternalDataCustomScript://MyScript1/%(algo)/%(hash)"
+ )
+set(ExternalData_URL_ALGO_MD5_MyAlgoMap1 MyAlgoMap1-md5)
+set(ExternalData_CUSTOM_SCRIPT_MyScript1 "${CMAKE_CURRENT_SOURCE_DIR}/MyScript1.cmake")
+set(ExternalData_BINARY_ROOT "${CMAKE_CURRENT_BINARY_DIR}/ExternalData")
+file(REMOVE_RECURSE ${ExternalData_BINARY_ROOT}) # clean test
+
+if(MAKE_SUPPORTS_SPACES)
+ set(Data1CheckSpaces -D "DataSpace=DATA{Data Space.dat}")
+endif()
+
+ExternalData_Add_Test(Data1
+ NAME Data1Check
+ COMMAND ${CMAKE_COMMAND}
+ -D Data=DATA{Data.dat}
+ ${Data1CheckSpaces}
+ -D DataScript=DATA{DataScript.dat}
+ -D DataAlgoMapA=DATA{DataAlgoMapA.dat}
+ -D DataAlgoMapB=DATA{DataAlgoMapB.dat}
+ -D DataMissing=DATA{DataMissing.dat}
+ -D DataMissingWithAssociated=DATA{DataMissing.dat,Data.dat}
+ -D SeriesA=DATA{SeriesA.dat,:}
+ -D SeriesB=DATA{SeriesB.dat,:}
+ -D SeriesC=DATA{SeriesC.dat,:}
+ -D SeriesD=DATA{SeriesD.dat,:}
+ -D SeriesAn=DATA{SeriesAn1.dat,:}
+ -D SeriesBn=DATA{SeriesBn_1.dat,:}
+ -D SeriesCn=DATA{SeriesCn.1.dat,:}
+ -D SeriesDn=DATA{SeriesDn-1.dat,:}
+ -D SeriesMixed=DATA{SeriesMixed.1.dat,:}
+ -D Paired=DATA{PairedA.dat,PairedB.dat}
+ -D Meta=DATA{MetaTop.dat,REGEX:Meta[ABC].dat}
+ -D Directory=DATA{Directory/,A.dat,REGEX:[BC].dat}
+ -D DirRecurse=DATA{DirRecurse/,RECURSE:,A.dat,REGEX:[BC].dat}
+ -D MultipleAlgorithmNoSHA1=DATA{MultipleAlgorithmNoSHA1.dat}
+ -D MultipleAlgorithmNoMD5=DATA{MultipleAlgorithmNoMD5.dat}
+ -D "Semicolons=DATA{Data.dat}\\;DATA{Data.dat}"
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/Data1Check.cmake
+ )
+ExternalData_Add_Target(Data1)
+
+add_subdirectory(Data2)
+add_subdirectory(Data3)
+add_subdirectory(Data4)
+add_subdirectory(Data5)
+add_subdirectory(DataNoSymlinks)
diff --git a/Tests/Module/ExternalData/Data Space.dat.md5 b/Tests/Module/ExternalData/Data Space.dat.md5
new file mode 100644
index 0000000..70e39bd
--- /dev/null
+++ b/Tests/Module/ExternalData/Data Space.dat.md5
@@ -0,0 +1 @@
+8c018830e3efa5caf3c7415028335a57
diff --git a/Tests/Module/ExternalData/Data.dat.md5 b/Tests/Module/ExternalData/Data.dat.md5
new file mode 100644
index 0000000..70e39bd
--- /dev/null
+++ b/Tests/Module/ExternalData/Data.dat.md5
@@ -0,0 +1 @@
+8c018830e3efa5caf3c7415028335a57
diff --git a/Tests/Module/ExternalData/Data1Check.cmake b/Tests/Module/ExternalData/Data1Check.cmake
new file mode 100644
index 0000000..f60c209
--- /dev/null
+++ b/Tests/Module/ExternalData/Data1Check.cmake
@@ -0,0 +1,108 @@
+file(STRINGS "${Data}" lines LIMIT_INPUT 1024)
+if(NOT "x${lines}" STREQUAL "xInput file already transformed.")
+ message(SEND_ERROR "Input file:\n ${Data}\ndoes not have expected content, but [[${lines}]]")
+endif()
+if(DEFINED DataSpace)
+ file(STRINGS "${DataSpace}" lines LIMIT_INPUT 1024)
+ if(NOT "x${lines}" STREQUAL "xInput file already transformed.")
+ message(SEND_ERROR "Input file:\n ${DataSpace}\ndoes not have expected content, but [[${lines}]]")
+ endif()
+endif()
+file(STRINGS "${DataScript}" lines LIMIT_INPUT 1024)
+if(NOT "x${lines}" STREQUAL "xDataScript")
+ message(SEND_ERROR "Input file:\n ${DataScript}\ndoes not have expected content, but [[${lines}]]")
+endif()
+file(STRINGS "${DataAlgoMapA}" lines LIMIT_INPUT 1024)
+if(NOT "x${lines}" STREQUAL "xDataAlgoMap")
+ message(SEND_ERROR "Input file:\n ${DataAlgoMapA}\ndoes not have expected content, but [[${lines}]]")
+endif()
+file(STRINGS "${DataAlgoMapB}" lines LIMIT_INPUT 1024)
+if(NOT "x${lines}" STREQUAL "xDataAlgoMap")
+ message(SEND_ERROR "Input file:\n ${DataAlgoMapB}\ndoes not have expected content, but [[${lines}]]")
+endif()
+if(DataMissing)
+ if(EXISTS "${DataMissing}")
+ message(SEND_ERROR
+ "Input file:\n"
+ " ${DataMissing}\n"
+ "exists but should not."
+ )
+ endif()
+else()
+ message(SEND_ERROR "DataMissing is not set!")
+endif()
+if(DataMissingWithAssociated)
+ if(EXISTS "${DataMissingWithAssociated}")
+ message(SEND_ERROR
+ "Input file:\n"
+ " ${DataMissingWithAssociated}\n"
+ "exists but should not."
+ )
+ endif()
+else()
+ message(SEND_ERROR "DataMissingWithAssociated is not set!")
+endif()
+set(SeriesAn1 "1\\.dat")
+set(SeriesBn1 "_1\\.dat")
+set(SeriesCn1 "\\.1\\.dat")
+set(SeriesDn1 "-1\\.dat")
+set(SeriesAl 1 2 3)
+set(SeriesBl _1 _2 _3)
+set(SeriesCl .1 .2 .3)
+set(SeriesDl -1 -2 -3)
+foreach(s A B C D)
+ foreach(n "" ${Series${s}l})
+ string(REGEX REPLACE "\\.dat$" "${n}.dat" file "${Series${s}}")
+ if(NOT EXISTS "${file}")
+ message(SEND_ERROR "Input file:\n ${file}\ndoes not exist!")
+ endif()
+ endforeach()
+endforeach()
+foreach(s A B C D)
+ foreach(n ${Series${s}l})
+ string(REGEX REPLACE "${Series${s}n1}$" "${n}.dat" file "${Series${s}n}")
+ if(NOT EXISTS "${file}")
+ message(SEND_ERROR "Input file:\n ${file}\ndoes not exist!")
+ endif()
+ endforeach()
+endforeach()
+foreach(n .1 .2 .3 .4)
+ string(REGEX REPLACE "\\.1\\.dat$" "${n}.dat" file "${SeriesMixed}")
+ if(NOT EXISTS "${file}")
+ message(SEND_ERROR "Input file:\n ${file}\ndoes not exist!")
+ endif()
+endforeach()
+foreach(n A B)
+ string(REGEX REPLACE "A\\.dat$" "${n}.dat" file "${Paired}")
+ if(NOT EXISTS "${file}")
+ message(SEND_ERROR "Input file:\n ${file}\ndoes not exist!")
+ endif()
+endforeach()
+foreach(n Top A B C)
+ string(REGEX REPLACE "Top\\.dat$" "${n}.dat" file "${Meta}")
+ if(NOT EXISTS "${file}")
+ message(SEND_ERROR "Input file:\n ${file}\ndoes not exist!")
+ endif()
+endforeach()
+foreach(n A B C)
+ set(file "${Directory}/${n}.dat")
+ if(NOT EXISTS "${file}")
+ message(SEND_ERROR "Input file:\n ${file}\ndoes not exist!")
+ endif()
+endforeach()
+foreach(n A Sub1/A Sub2/Dir/A B Sub1/B Sub2/Dir/B C Sub1/C Sub2/Dir/C)
+ set(file "${DirRecurse}/${n}.dat")
+ if(NOT EXISTS "${file}")
+ message(SEND_ERROR "Input file:\n ${file}\ndoes not exist!")
+ endif()
+endforeach()
+list(LENGTH Semicolons len)
+if("${len}" EQUAL 2)
+ foreach(file ${Semicolons})
+ if(NOT EXISTS "${file}")
+ message(SEND_ERROR "Input file:\n ${file}\ndoes not exist!")
+ endif()
+ endforeach()
+else()
+ message(SEND_ERROR "Semicolons value:\n ${Semicolons}\nis not a list of length 2.")
+endif()
diff --git a/Tests/Module/ExternalData/Data2.dat.md5 b/Tests/Module/ExternalData/Data2.dat.md5
new file mode 100644
index 0000000..70e39bd
--- /dev/null
+++ b/Tests/Module/ExternalData/Data2.dat.md5
@@ -0,0 +1 @@
+8c018830e3efa5caf3c7415028335a57
diff --git a/Tests/Module/ExternalData/Data2/CMakeLists.txt b/Tests/Module/ExternalData/Data2/CMakeLists.txt
new file mode 100644
index 0000000..c5b79ac
--- /dev/null
+++ b/Tests/Module/ExternalData/Data2/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(ExternalData_SERIES_PARSE "([0-9]+)(_\\.my\\.dat)$")
+set(ExternalData_SERIES_MATCH "([0-9]+)")
+ExternalData_Add_Test(Data2
+ NAME Data2Check
+ COMMAND ${CMAKE_COMMAND}
+ -D Data2=DATA{../Data2.dat}
+ -D Data2b=DATA{${CMAKE_CURRENT_SOURCE_DIR}/../Data2b.dat}
+ -D SeriesC=DATA{SeriesC_1_.my.dat,:}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/Data2Check.cmake
+ )
+ExternalData_Add_Target(Data2)
diff --git a/Tests/Module/ExternalData/Data2/Data2Check.cmake b/Tests/Module/ExternalData/Data2/Data2Check.cmake
new file mode 100644
index 0000000..d5b0c7b
--- /dev/null
+++ b/Tests/Module/ExternalData/Data2/Data2Check.cmake
@@ -0,0 +1,12 @@
+foreach(d "${Data2}" "${Data2b}")
+ file(STRINGS "${d}" lines LIMIT_INPUT 1024)
+ if(NOT "x${lines}" STREQUAL "xInput file already transformed.")
+ message(SEND_ERROR "Input file:\n ${d}\ndoes not have expected content, but [[${lines}]]")
+ endif()
+endforeach()
+foreach(n 1 2 3)
+ string(REGEX REPLACE "_1_\\.my\\.dat$" "_${n}_.my.dat" SeriesCFile "${SeriesC}")
+ if(NOT EXISTS "${SeriesCFile}")
+ message(SEND_ERROR "Input file:\n ${SeriesCFile}\ndoes not exist!")
+ endif()
+endforeach()
diff --git a/Tests/Module/ExternalData/Data2/SeriesC_1_.my.dat.md5 b/Tests/Module/ExternalData/Data2/SeriesC_1_.my.dat.md5
new file mode 100644
index 0000000..f22e266
--- /dev/null
+++ b/Tests/Module/ExternalData/Data2/SeriesC_1_.my.dat.md5
@@ -0,0 +1 @@
+31eff09e84fca01415f8cd9d82ec432b
diff --git a/Tests/Module/ExternalData/Data2/SeriesC_2_.my.dat.md5 b/Tests/Module/ExternalData/Data2/SeriesC_2_.my.dat.md5
new file mode 100644
index 0000000..2b917e7
--- /dev/null
+++ b/Tests/Module/ExternalData/Data2/SeriesC_2_.my.dat.md5
@@ -0,0 +1 @@
+f7ab5a04aae9cb9a520e70b20b9c8ed7
diff --git a/Tests/Module/ExternalData/Data2/SeriesC_3_.my.dat.md5 b/Tests/Module/ExternalData/Data2/SeriesC_3_.my.dat.md5
new file mode 100644
index 0000000..b9c9760
--- /dev/null
+++ b/Tests/Module/ExternalData/Data2/SeriesC_3_.my.dat.md5
@@ -0,0 +1 @@
+30ba0acdee9096b3b9fc6c69362c6b42
diff --git a/Tests/Module/ExternalData/Data2b.dat.md5 b/Tests/Module/ExternalData/Data2b.dat.md5
new file mode 100644
index 0000000..70e39bd
--- /dev/null
+++ b/Tests/Module/ExternalData/Data2b.dat.md5
@@ -0,0 +1 @@
+8c018830e3efa5caf3c7415028335a57
diff --git a/Tests/Module/ExternalData/Data3/CMakeLists.txt b/Tests/Module/ExternalData/Data3/CMakeLists.txt
new file mode 100644
index 0000000..a7c2b6e
--- /dev/null
+++ b/Tests/Module/ExternalData/Data3/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(Store0 ${CMAKE_BINARY_DIR}/ExternalData/Other)
+set(Store1 ${CMAKE_BINARY_DIR}/ExternalData/Objects)
+set(ExternalData_OBJECT_STORES ${Store0} ${Store1})
+ExternalData_Add_Test(Data3
+ NAME Data3Check
+ COMMAND ${CMAKE_COMMAND}
+ -D Data=DATA{Data.dat}
+ -D Other=DATA{Other.dat}
+ -D Store0=${Store0}
+ -D Store1=${Store1}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/Data3Check.cmake
+ )
+ExternalData_Add_Target(Data3)
+add_dependencies(Data3 Data1 Data2)
diff --git a/Tests/Module/ExternalData/Data3/Data.dat.md5 b/Tests/Module/ExternalData/Data3/Data.dat.md5
new file mode 100644
index 0000000..70e39bd
--- /dev/null
+++ b/Tests/Module/ExternalData/Data3/Data.dat.md5
@@ -0,0 +1 @@
+8c018830e3efa5caf3c7415028335a57
diff --git a/Tests/Module/ExternalData/Data3/Data3Check.cmake b/Tests/Module/ExternalData/Data3/Data3Check.cmake
new file mode 100644
index 0000000..de98839
--- /dev/null
+++ b/Tests/Module/ExternalData/Data3/Data3Check.cmake
@@ -0,0 +1,25 @@
+if(NOT EXISTS "${Data}")
+ message(SEND_ERROR "Input file:\n ${Data}\ndoes not exist!")
+endif()
+if(NOT EXISTS "${Other}")
+ message(SEND_ERROR "Input file:\n ${Other}\ndoes not exist!")
+endif()
+# Verify that the 'Data' object was found in the second store location left
+# from Data1 target downloads and that the 'Other' object was downloaded to
+# our first store location. Neither object should exist in the other store.
+foreach(should_exist
+ "${Store0}/MD5/aaad162b85f60d1eb57ca71a23e8efd7"
+ "${Store1}/MD5/8c018830e3efa5caf3c7415028335a57"
+ )
+ if(NOT EXISTS ${should_exist})
+ message(SEND_ERROR "Store file:\n ${should_exist}\nshould exist!")
+ endif()
+endforeach()
+foreach(should_not_exist
+ "${Store0}/MD5/8c018830e3efa5caf3c7415028335a57"
+ "${Store1}/MD5/aaad162b85f60d1eb57ca71a23e8efd7"
+ )
+ if(EXISTS ${should_not_exist})
+ message(SEND_ERROR "Store file:\n ${should_not_exist}\nshould not exist!")
+ endif()
+endforeach()
diff --git a/Tests/Module/ExternalData/Data3/Other.dat.md5 b/Tests/Module/ExternalData/Data3/Other.dat.md5
new file mode 100644
index 0000000..5312faa
--- /dev/null
+++ b/Tests/Module/ExternalData/Data3/Other.dat.md5
@@ -0,0 +1 @@
+aaad162b85f60d1eb57ca71a23e8efd7
diff --git a/Tests/Module/ExternalData/Data4/CMakeLists.txt b/Tests/Module/ExternalData/Data4/CMakeLists.txt
new file mode 100644
index 0000000..ac977fb
--- /dev/null
+++ b/Tests/Module/ExternalData/Data4/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(Store0 ${CMAKE_BINARY_DIR}/ExternalData/Other)
+set(Store1 ${CMAKE_BINARY_DIR}/ExternalData/Objects)
+set(ExternalData_OBJECT_STORES ${Store0} ${Store1})
+unset(ExternalData_URL_TEMPLATES) # All objects already in stores!
+ExternalData_Add_Test(Data4
+ NAME Data4Check
+ COMMAND ${CMAKE_COMMAND}
+ -D Data=DATA{Data.dat}
+ -D Other=DATA{Other.dat}
+ -D Store0=${Store0}
+ -D Store1=${Store1}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/Data4Check.cmake
+ )
+ExternalData_Add_Target(Data4)
+add_dependencies(Data4 Data3)
diff --git a/Tests/Module/ExternalData/Data4/Data.dat.md5 b/Tests/Module/ExternalData/Data4/Data.dat.md5
new file mode 100644
index 0000000..70e39bd
--- /dev/null
+++ b/Tests/Module/ExternalData/Data4/Data.dat.md5
@@ -0,0 +1 @@
+8c018830e3efa5caf3c7415028335a57
diff --git a/Tests/Module/ExternalData/Data4/Data4Check.cmake b/Tests/Module/ExternalData/Data4/Data4Check.cmake
new file mode 100644
index 0000000..e614cc4
--- /dev/null
+++ b/Tests/Module/ExternalData/Data4/Data4Check.cmake
@@ -0,0 +1,26 @@
+if(NOT EXISTS "${Data}")
+ message(SEND_ERROR "Input file:\n ${Data}\ndoes not exist!")
+endif()
+if(NOT EXISTS "${Other}")
+ message(SEND_ERROR "Input file:\n ${Other}\ndoes not exist!")
+endif()
+# Verify that the 'Data' object was found in the second store location left
+# from Data1 target downloads and that the 'Other' object was found in the
+# first store location left from Data3 target downloads. Neither object
+# should exist in the opposite store.
+foreach(should_exist
+ "${Store0}/MD5/aaad162b85f60d1eb57ca71a23e8efd7"
+ "${Store1}/MD5/8c018830e3efa5caf3c7415028335a57"
+ )
+ if(NOT EXISTS ${should_exist})
+ message(SEND_ERROR "Store file:\n ${should_exist}\nshould exist!")
+ endif()
+endforeach()
+foreach(should_not_exist
+ "${Store0}/MD5/8c018830e3efa5caf3c7415028335a57"
+ "${Store1}/MD5/aaad162b85f60d1eb57ca71a23e8efd7"
+ )
+ if(EXISTS ${should_not_exist})
+ message(SEND_ERROR "Store file:\n ${should_not_exist}\nshould not exist!")
+ endif()
+endforeach()
diff --git a/Tests/Module/ExternalData/Data4/Other.dat.md5 b/Tests/Module/ExternalData/Data4/Other.dat.md5
new file mode 100644
index 0000000..5312faa
--- /dev/null
+++ b/Tests/Module/ExternalData/Data4/Other.dat.md5
@@ -0,0 +1 @@
+aaad162b85f60d1eb57ca71a23e8efd7
diff --git a/Tests/Module/ExternalData/Data5/CMakeLists.txt b/Tests/Module/ExternalData/Data5/CMakeLists.txt
new file mode 100644
index 0000000..b13240d
--- /dev/null
+++ b/Tests/Module/ExternalData/Data5/CMakeLists.txt
@@ -0,0 +1,29 @@
+# Test adding the same data file in multiple tests
+ExternalData_Add_Test(Data5.A
+ NAME Data5Check.A
+ COMMAND ${CMAKE_COMMAND}
+ -D Data5=DATA{Data5.dat}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/Data5Check.cmake
+ )
+ExternalData_Add_Target(Data5.A)
+
+if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12)
+ # Xcode's "new build system" does not support multiple targets
+ # producing the same custom command output.
+ return()
+endif()
+
+ExternalData_Add_Test(Data5.B
+ NAME Data5Check.B
+ COMMAND ${CMAKE_COMMAND}
+ -D Data5=DATA{Data5.dat}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/Data5Check.cmake
+ )
+ExternalData_Add_Target(Data5.B)
+ExternalData_Add_Test(Data5.C
+ NAME Data5Check.C
+ COMMAND ${CMAKE_COMMAND}
+ -D Data5=DATA{Data5.dat}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/Data5Check.cmake
+ )
+ExternalData_Add_Target(Data5.C)
diff --git a/Tests/Module/ExternalData/Data5/Data5.dat.md5 b/Tests/Module/ExternalData/Data5/Data5.dat.md5
new file mode 100644
index 0000000..70e39bd
--- /dev/null
+++ b/Tests/Module/ExternalData/Data5/Data5.dat.md5
@@ -0,0 +1 @@
+8c018830e3efa5caf3c7415028335a57
diff --git a/Tests/Module/ExternalData/Data5/Data5Check.cmake b/Tests/Module/ExternalData/Data5/Data5Check.cmake
new file mode 100644
index 0000000..4dea9a4
--- /dev/null
+++ b/Tests/Module/ExternalData/Data5/Data5Check.cmake
@@ -0,0 +1,4 @@
+file(STRINGS "${Data5}" lines LIMIT_INPUT 1024)
+if(NOT "x${lines}" STREQUAL "xInput file already transformed.")
+ message(SEND_ERROR "Input file:\n ${Data5}\ndoes not have expected content, but [[${lines}]]")
+endif()
diff --git a/Tests/Module/ExternalData/DataAlgoMapA.dat.md5 b/Tests/Module/ExternalData/DataAlgoMapA.dat.md5
new file mode 100644
index 0000000..7281481
--- /dev/null
+++ b/Tests/Module/ExternalData/DataAlgoMapA.dat.md5
@@ -0,0 +1 @@
+dded55e43cd6529ee35d24113dfc87a3
diff --git a/Tests/Module/ExternalData/DataAlgoMapB.dat.sha1 b/Tests/Module/ExternalData/DataAlgoMapB.dat.sha1
new file mode 100644
index 0000000..4fd7c06
--- /dev/null
+++ b/Tests/Module/ExternalData/DataAlgoMapB.dat.sha1
@@ -0,0 +1 @@
+85158f0c1996837976e858c42a9a7634bfe91b93
diff --git a/Tests/Module/ExternalData/DataNoSymlinks/CMakeLists.txt b/Tests/Module/ExternalData/DataNoSymlinks/CMakeLists.txt
new file mode 100644
index 0000000..d3df7fc
--- /dev/null
+++ b/Tests/Module/ExternalData/DataNoSymlinks/CMakeLists.txt
@@ -0,0 +1,8 @@
+set(ExternalData_NO_SYMLINKS 1)
+ExternalData_Add_Test(DataNoSymlinks
+ NAME DataNoSymlinksCheck
+ COMMAND ${CMAKE_COMMAND}
+ -D Data=DATA{Data.dat}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/DataNoSymlinksCheck.cmake
+ )
+ExternalData_Add_Target(DataNoSymlinks)
diff --git a/Tests/Module/ExternalData/DataNoSymlinks/Data.dat.md5 b/Tests/Module/ExternalData/DataNoSymlinks/Data.dat.md5
new file mode 100644
index 0000000..70e39bd
--- /dev/null
+++ b/Tests/Module/ExternalData/DataNoSymlinks/Data.dat.md5
@@ -0,0 +1 @@
+8c018830e3efa5caf3c7415028335a57
diff --git a/Tests/Module/ExternalData/DataNoSymlinks/DataNoSymlinksCheck.cmake b/Tests/Module/ExternalData/DataNoSymlinks/DataNoSymlinksCheck.cmake
new file mode 100644
index 0000000..2be3571
--- /dev/null
+++ b/Tests/Module/ExternalData/DataNoSymlinks/DataNoSymlinksCheck.cmake
@@ -0,0 +1,6 @@
+if(NOT EXISTS "${Data}")
+ message(SEND_ERROR "Input file:\n ${Data}\ndoes not exist!")
+endif()
+if(IS_SYMLINK "${Data}")
+ message(SEND_ERROR "Input file:\n ${Data}\nis a symlink but should not be!")
+endif()
diff --git a/Tests/Module/ExternalData/DataScript.dat.md5 b/Tests/Module/ExternalData/DataScript.dat.md5
new file mode 100644
index 0000000..74b4616
--- /dev/null
+++ b/Tests/Module/ExternalData/DataScript.dat.md5
@@ -0,0 +1 @@
+fd95c03719e8626c0d10a818f9996dc5
diff --git a/Tests/Module/ExternalData/DirRecurse/A.dat.md5 b/Tests/Module/ExternalData/DirRecurse/A.dat.md5
new file mode 100644
index 0000000..4a78fc7
--- /dev/null
+++ b/Tests/Module/ExternalData/DirRecurse/A.dat.md5
@@ -0,0 +1 @@
+9d980b06c2f0fec3d4872d68175b9822
diff --git a/Tests/Module/ExternalData/DirRecurse/B.dat.md5 b/Tests/Module/ExternalData/DirRecurse/B.dat.md5
new file mode 100644
index 0000000..4557a21
--- /dev/null
+++ b/Tests/Module/ExternalData/DirRecurse/B.dat.md5
@@ -0,0 +1 @@
+8f4add4581551facf27237e6577fd662
diff --git a/Tests/Module/ExternalData/DirRecurse/C.dat.md5 b/Tests/Module/ExternalData/DirRecurse/C.dat.md5
new file mode 100644
index 0000000..a7f23dd
--- /dev/null
+++ b/Tests/Module/ExternalData/DirRecurse/C.dat.md5
@@ -0,0 +1 @@
+c1030719c95f3435d8abc39c0d442946
diff --git a/Tests/Module/ExternalData/DirRecurse/Sub1/A.dat.md5 b/Tests/Module/ExternalData/DirRecurse/Sub1/A.dat.md5
new file mode 100644
index 0000000..4a78fc7
--- /dev/null
+++ b/Tests/Module/ExternalData/DirRecurse/Sub1/A.dat.md5
@@ -0,0 +1 @@
+9d980b06c2f0fec3d4872d68175b9822
diff --git a/Tests/Module/ExternalData/DirRecurse/Sub1/B.dat.md5 b/Tests/Module/ExternalData/DirRecurse/Sub1/B.dat.md5
new file mode 100644
index 0000000..4557a21
--- /dev/null
+++ b/Tests/Module/ExternalData/DirRecurse/Sub1/B.dat.md5
@@ -0,0 +1 @@
+8f4add4581551facf27237e6577fd662
diff --git a/Tests/Module/ExternalData/DirRecurse/Sub1/C.dat.md5 b/Tests/Module/ExternalData/DirRecurse/Sub1/C.dat.md5
new file mode 100644
index 0000000..a7f23dd
--- /dev/null
+++ b/Tests/Module/ExternalData/DirRecurse/Sub1/C.dat.md5
@@ -0,0 +1 @@
+c1030719c95f3435d8abc39c0d442946
diff --git a/Tests/Module/ExternalData/DirRecurse/Sub2/Dir/A.dat.md5 b/Tests/Module/ExternalData/DirRecurse/Sub2/Dir/A.dat.md5
new file mode 100644
index 0000000..4a78fc7
--- /dev/null
+++ b/Tests/Module/ExternalData/DirRecurse/Sub2/Dir/A.dat.md5
@@ -0,0 +1 @@
+9d980b06c2f0fec3d4872d68175b9822
diff --git a/Tests/Module/ExternalData/DirRecurse/Sub2/Dir/B.dat.md5 b/Tests/Module/ExternalData/DirRecurse/Sub2/Dir/B.dat.md5
new file mode 100644
index 0000000..4557a21
--- /dev/null
+++ b/Tests/Module/ExternalData/DirRecurse/Sub2/Dir/B.dat.md5
@@ -0,0 +1 @@
+8f4add4581551facf27237e6577fd662
diff --git a/Tests/Module/ExternalData/DirRecurse/Sub2/Dir/C.dat.md5 b/Tests/Module/ExternalData/DirRecurse/Sub2/Dir/C.dat.md5
new file mode 100644
index 0000000..a7f23dd
--- /dev/null
+++ b/Tests/Module/ExternalData/DirRecurse/Sub2/Dir/C.dat.md5
@@ -0,0 +1 @@
+c1030719c95f3435d8abc39c0d442946
diff --git a/Tests/Module/ExternalData/Directory/A.dat.md5 b/Tests/Module/ExternalData/Directory/A.dat.md5
new file mode 100644
index 0000000..4a78fc7
--- /dev/null
+++ b/Tests/Module/ExternalData/Directory/A.dat.md5
@@ -0,0 +1 @@
+9d980b06c2f0fec3d4872d68175b9822
diff --git a/Tests/Module/ExternalData/Directory/B.dat.md5 b/Tests/Module/ExternalData/Directory/B.dat.md5
new file mode 100644
index 0000000..4557a21
--- /dev/null
+++ b/Tests/Module/ExternalData/Directory/B.dat.md5
@@ -0,0 +1 @@
+8f4add4581551facf27237e6577fd662
diff --git a/Tests/Module/ExternalData/Directory/C.dat.md5 b/Tests/Module/ExternalData/Directory/C.dat.md5
new file mode 100644
index 0000000..a7f23dd
--- /dev/null
+++ b/Tests/Module/ExternalData/Directory/C.dat.md5
@@ -0,0 +1 @@
+c1030719c95f3435d8abc39c0d442946
diff --git a/Tests/Module/ExternalData/MD5/08cfcf221f76ace7b906b312284e73d7 b/Tests/Module/ExternalData/MD5/08cfcf221f76ace7b906b312284e73d7
new file mode 100644
index 0000000..a689e3c
--- /dev/null
+++ b/Tests/Module/ExternalData/MD5/08cfcf221f76ace7b906b312284e73d7
@@ -0,0 +1 @@
+MetaTop
diff --git a/Tests/Module/ExternalData/MD5/30ba0acdee9096b3b9fc6c69362c6b42 b/Tests/Module/ExternalData/MD5/30ba0acdee9096b3b9fc6c69362c6b42
new file mode 100644
index 0000000..5491241
--- /dev/null
+++ b/Tests/Module/ExternalData/MD5/30ba0acdee9096b3b9fc6c69362c6b42
@@ -0,0 +1 @@
+Series.3
diff --git a/Tests/Module/ExternalData/MD5/31eff09e84fca01415f8cd9d82ec432b b/Tests/Module/ExternalData/MD5/31eff09e84fca01415f8cd9d82ec432b
new file mode 100644
index 0000000..4d0475e
--- /dev/null
+++ b/Tests/Module/ExternalData/MD5/31eff09e84fca01415f8cd9d82ec432b
@@ -0,0 +1 @@
+Series.1
diff --git a/Tests/Module/ExternalData/MD5/401767f22a456b3522953722090a2c36 b/Tests/Module/ExternalData/MD5/401767f22a456b3522953722090a2c36
new file mode 100644
index 0000000..9dec116
--- /dev/null
+++ b/Tests/Module/ExternalData/MD5/401767f22a456b3522953722090a2c36
@@ -0,0 +1 @@
+PairedA
diff --git a/Tests/Module/ExternalData/MD5/8c018830e3efa5caf3c7415028335a57 b/Tests/Module/ExternalData/MD5/8c018830e3efa5caf3c7415028335a57
new file mode 100644
index 0000000..fa701e2
--- /dev/null
+++ b/Tests/Module/ExternalData/MD5/8c018830e3efa5caf3c7415028335a57
@@ -0,0 +1 @@
+Input file already transformed.
diff --git a/Tests/Module/ExternalData/MD5/8f4add4581551facf27237e6577fd662 b/Tests/Module/ExternalData/MD5/8f4add4581551facf27237e6577fd662
new file mode 100644
index 0000000..69ba09c
--- /dev/null
+++ b/Tests/Module/ExternalData/MD5/8f4add4581551facf27237e6577fd662
@@ -0,0 +1 @@
+MetaB
diff --git a/Tests/Module/ExternalData/MD5/9d980b06c2f0fec3d4872d68175b9822 b/Tests/Module/ExternalData/MD5/9d980b06c2f0fec3d4872d68175b9822
new file mode 100644
index 0000000..000e7b2
--- /dev/null
+++ b/Tests/Module/ExternalData/MD5/9d980b06c2f0fec3d4872d68175b9822
@@ -0,0 +1 @@
+MetaA
diff --git a/Tests/Module/ExternalData/MD5/aaad162b85f60d1eb57ca71a23e8efd7 b/Tests/Module/ExternalData/MD5/aaad162b85f60d1eb57ca71a23e8efd7
new file mode 100644
index 0000000..df0510c
--- /dev/null
+++ b/Tests/Module/ExternalData/MD5/aaad162b85f60d1eb57ca71a23e8efd7
@@ -0,0 +1 @@
+Another input file already transformed.
diff --git a/Tests/Module/ExternalData/MD5/c1030719c95f3435d8abc39c0d442946 b/Tests/Module/ExternalData/MD5/c1030719c95f3435d8abc39c0d442946
new file mode 100644
index 0000000..3fac5e6
--- /dev/null
+++ b/Tests/Module/ExternalData/MD5/c1030719c95f3435d8abc39c0d442946
@@ -0,0 +1 @@
+MetaC
diff --git a/Tests/Module/ExternalData/MD5/ce38ea6c3c1e00fa6405dd64b8bf6da0 b/Tests/Module/ExternalData/MD5/ce38ea6c3c1e00fa6405dd64b8bf6da0
new file mode 100644
index 0000000..362d4b4
--- /dev/null
+++ b/Tests/Module/ExternalData/MD5/ce38ea6c3c1e00fa6405dd64b8bf6da0
@@ -0,0 +1 @@
+SeriesMixed.1
diff --git a/Tests/Module/ExternalData/MD5/ecfa1ecd417d4253af81ae04d1bd6581 b/Tests/Module/ExternalData/MD5/ecfa1ecd417d4253af81ae04d1bd6581
new file mode 100644
index 0000000..8c414f5
--- /dev/null
+++ b/Tests/Module/ExternalData/MD5/ecfa1ecd417d4253af81ae04d1bd6581
@@ -0,0 +1 @@
+PairedB
diff --git a/Tests/Module/ExternalData/MD5/f41c94425d01ecbbee70440b951cb058 b/Tests/Module/ExternalData/MD5/f41c94425d01ecbbee70440b951cb058
new file mode 100644
index 0000000..3503da4
--- /dev/null
+++ b/Tests/Module/ExternalData/MD5/f41c94425d01ecbbee70440b951cb058
@@ -0,0 +1 @@
+Series
diff --git a/Tests/Module/ExternalData/MD5/f7ab5a04aae9cb9a520e70b20b9c8ed7 b/Tests/Module/ExternalData/MD5/f7ab5a04aae9cb9a520e70b20b9c8ed7
new file mode 100644
index 0000000..29d727b
--- /dev/null
+++ b/Tests/Module/ExternalData/MD5/f7ab5a04aae9cb9a520e70b20b9c8ed7
@@ -0,0 +1 @@
+Series.2
diff --git a/Tests/Module/ExternalData/MetaA.dat.md5 b/Tests/Module/ExternalData/MetaA.dat.md5
new file mode 100644
index 0000000..4a78fc7
--- /dev/null
+++ b/Tests/Module/ExternalData/MetaA.dat.md5
@@ -0,0 +1 @@
+9d980b06c2f0fec3d4872d68175b9822
diff --git a/Tests/Module/ExternalData/MetaB.dat.md5 b/Tests/Module/ExternalData/MetaB.dat.md5
new file mode 100644
index 0000000..4557a21
--- /dev/null
+++ b/Tests/Module/ExternalData/MetaB.dat.md5
@@ -0,0 +1 @@
+8f4add4581551facf27237e6577fd662
diff --git a/Tests/Module/ExternalData/MetaC.dat.md5 b/Tests/Module/ExternalData/MetaC.dat.md5
new file mode 100644
index 0000000..a7f23dd
--- /dev/null
+++ b/Tests/Module/ExternalData/MetaC.dat.md5
@@ -0,0 +1 @@
+c1030719c95f3435d8abc39c0d442946
diff --git a/Tests/Module/ExternalData/MetaTop.dat.md5 b/Tests/Module/ExternalData/MetaTop.dat.md5
new file mode 100644
index 0000000..1906cbf
--- /dev/null
+++ b/Tests/Module/ExternalData/MetaTop.dat.md5
@@ -0,0 +1 @@
+08cfcf221f76ace7b906b312284e73d7
diff --git a/Tests/Module/ExternalData/MultipleAlgorithmNoMD5.dat.md5 b/Tests/Module/ExternalData/MultipleAlgorithmNoMD5.dat.md5
new file mode 100644
index 0000000..a956f36
--- /dev/null
+++ b/Tests/Module/ExternalData/MultipleAlgorithmNoMD5.dat.md5
@@ -0,0 +1 @@
+29848e54a4d0343f138ab14419b863de
diff --git a/Tests/Module/ExternalData/MultipleAlgorithmNoMD5.dat.sha1 b/Tests/Module/ExternalData/MultipleAlgorithmNoMD5.dat.sha1
new file mode 100644
index 0000000..43a3540
--- /dev/null
+++ b/Tests/Module/ExternalData/MultipleAlgorithmNoMD5.dat.sha1
@@ -0,0 +1 @@
+2af59a7022024974f3b8521b7ed8137c996a79f1
diff --git a/Tests/Module/ExternalData/MultipleAlgorithmNoSHA1.dat.md5 b/Tests/Module/ExternalData/MultipleAlgorithmNoSHA1.dat.md5
new file mode 100644
index 0000000..1906cbf
--- /dev/null
+++ b/Tests/Module/ExternalData/MultipleAlgorithmNoSHA1.dat.md5
@@ -0,0 +1 @@
+08cfcf221f76ace7b906b312284e73d7
diff --git a/Tests/Module/ExternalData/MultipleAlgorithmNoSHA1.dat.sha1 b/Tests/Module/ExternalData/MultipleAlgorithmNoSHA1.dat.sha1
new file mode 100644
index 0000000..65781b2
--- /dev/null
+++ b/Tests/Module/ExternalData/MultipleAlgorithmNoSHA1.dat.sha1
@@ -0,0 +1 @@
+223b134e6e3a9bf34aa7531c009d97cff6b0d8a3
diff --git a/Tests/Module/ExternalData/MyScript1.cmake b/Tests/Module/ExternalData/MyScript1.cmake
new file mode 100644
index 0000000..242c64d
--- /dev/null
+++ b/Tests/Module/ExternalData/MyScript1.cmake
@@ -0,0 +1,5 @@
+if(ExternalData_CUSTOM_LOCATION STREQUAL "MD5/fd95c03719e8626c0d10a818f9996dc5")
+ file(WRITE "${ExternalData_CUSTOM_FILE}" "DataScript")
+else()
+ set(ExternalData_CUSTOM_ERROR "no ${ExternalData_CUSTOM_LOCATION} known")
+endif()
diff --git a/Tests/Module/ExternalData/PairedA.dat.md5 b/Tests/Module/ExternalData/PairedA.dat.md5
new file mode 100644
index 0000000..1ffe035
--- /dev/null
+++ b/Tests/Module/ExternalData/PairedA.dat.md5
@@ -0,0 +1 @@
+401767f22a456b3522953722090a2c36
diff --git a/Tests/Module/ExternalData/PairedB.dat.md5 b/Tests/Module/ExternalData/PairedB.dat.md5
new file mode 100644
index 0000000..89c942b
--- /dev/null
+++ b/Tests/Module/ExternalData/PairedB.dat.md5
@@ -0,0 +1 @@
+ecfa1ecd417d4253af81ae04d1bd6581
diff --git a/Tests/Module/ExternalData/SHA1/2af59a7022024974f3b8521b7ed8137c996a79f1 b/Tests/Module/ExternalData/SHA1/2af59a7022024974f3b8521b7ed8137c996a79f1
new file mode 100644
index 0000000..a388540
--- /dev/null
+++ b/Tests/Module/ExternalData/SHA1/2af59a7022024974f3b8521b7ed8137c996a79f1
@@ -0,0 +1 @@
+SeriesMixed.2
diff --git a/Tests/Module/ExternalData/SHA224/3b679da7908562fe1cc28db47ffb89bae025f4551dceb343a5869174 b/Tests/Module/ExternalData/SHA224/3b679da7908562fe1cc28db47ffb89bae025f4551dceb343a5869174
new file mode 100644
index 0000000..e806d98
--- /dev/null
+++ b/Tests/Module/ExternalData/SHA224/3b679da7908562fe1cc28db47ffb89bae025f4551dceb343a5869174
@@ -0,0 +1 @@
+SeriesMixed.3
diff --git a/Tests/Module/ExternalData/SHA256/969171a0dd70d49ce096bd3e8178c7e26c711c9b20dbcaa3853d869d3871f133 b/Tests/Module/ExternalData/SHA256/969171a0dd70d49ce096bd3e8178c7e26c711c9b20dbcaa3853d869d3871f133
new file mode 100644
index 0000000..e3d1e0c
--- /dev/null
+++ b/Tests/Module/ExternalData/SHA256/969171a0dd70d49ce096bd3e8178c7e26c711c9b20dbcaa3853d869d3871f133
@@ -0,0 +1 @@
+SeriesMixed.4
diff --git a/Tests/Module/ExternalData/SHA3_256/c01b0bfd51ece4295c7b45493750a3612ecc483095eb1366f9f46b179550e231 b/Tests/Module/ExternalData/SHA3_256/c01b0bfd51ece4295c7b45493750a3612ecc483095eb1366f9f46b179550e231
new file mode 100644
index 0000000..0377f5d
--- /dev/null
+++ b/Tests/Module/ExternalData/SHA3_256/c01b0bfd51ece4295c7b45493750a3612ecc483095eb1366f9f46b179550e231
@@ -0,0 +1 @@
+SeriesMixed.5
diff --git a/Tests/Module/ExternalData/SeriesA.dat.md5 b/Tests/Module/ExternalData/SeriesA.dat.md5
new file mode 100644
index 0000000..be2d687
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesA.dat.md5
@@ -0,0 +1 @@
+f41c94425d01ecbbee70440b951cb058
diff --git a/Tests/Module/ExternalData/SeriesA1.dat.md5 b/Tests/Module/ExternalData/SeriesA1.dat.md5
new file mode 100644
index 0000000..f22e266
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesA1.dat.md5
@@ -0,0 +1 @@
+31eff09e84fca01415f8cd9d82ec432b
diff --git a/Tests/Module/ExternalData/SeriesA2.dat.md5 b/Tests/Module/ExternalData/SeriesA2.dat.md5
new file mode 100644
index 0000000..2b917e7
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesA2.dat.md5
@@ -0,0 +1 @@
+f7ab5a04aae9cb9a520e70b20b9c8ed7
diff --git a/Tests/Module/ExternalData/SeriesA3.dat.md5 b/Tests/Module/ExternalData/SeriesA3.dat.md5
new file mode 100644
index 0000000..b9c9760
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesA3.dat.md5
@@ -0,0 +1 @@
+30ba0acdee9096b3b9fc6c69362c6b42
diff --git a/Tests/Module/ExternalData/SeriesAn1.dat.md5 b/Tests/Module/ExternalData/SeriesAn1.dat.md5
new file mode 100644
index 0000000..f22e266
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesAn1.dat.md5
@@ -0,0 +1 @@
+31eff09e84fca01415f8cd9d82ec432b
diff --git a/Tests/Module/ExternalData/SeriesAn2.dat.md5 b/Tests/Module/ExternalData/SeriesAn2.dat.md5
new file mode 100644
index 0000000..2b917e7
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesAn2.dat.md5
@@ -0,0 +1 @@
+f7ab5a04aae9cb9a520e70b20b9c8ed7
diff --git a/Tests/Module/ExternalData/SeriesAn3.dat.md5 b/Tests/Module/ExternalData/SeriesAn3.dat.md5
new file mode 100644
index 0000000..b9c9760
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesAn3.dat.md5
@@ -0,0 +1 @@
+30ba0acdee9096b3b9fc6c69362c6b42
diff --git a/Tests/Module/ExternalData/SeriesB.dat.md5 b/Tests/Module/ExternalData/SeriesB.dat.md5
new file mode 100644
index 0000000..be2d687
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesB.dat.md5
@@ -0,0 +1 @@
+f41c94425d01ecbbee70440b951cb058
diff --git a/Tests/Module/ExternalData/SeriesB_1.dat.md5 b/Tests/Module/ExternalData/SeriesB_1.dat.md5
new file mode 100644
index 0000000..f22e266
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesB_1.dat.md5
@@ -0,0 +1 @@
+31eff09e84fca01415f8cd9d82ec432b
diff --git a/Tests/Module/ExternalData/SeriesB_2.dat.md5 b/Tests/Module/ExternalData/SeriesB_2.dat.md5
new file mode 100644
index 0000000..2b917e7
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesB_2.dat.md5
@@ -0,0 +1 @@
+f7ab5a04aae9cb9a520e70b20b9c8ed7
diff --git a/Tests/Module/ExternalData/SeriesB_3.dat.md5 b/Tests/Module/ExternalData/SeriesB_3.dat.md5
new file mode 100644
index 0000000..b9c9760
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesB_3.dat.md5
@@ -0,0 +1 @@
+30ba0acdee9096b3b9fc6c69362c6b42
diff --git a/Tests/Module/ExternalData/SeriesBn_1.dat.md5 b/Tests/Module/ExternalData/SeriesBn_1.dat.md5
new file mode 100644
index 0000000..f22e266
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesBn_1.dat.md5
@@ -0,0 +1 @@
+31eff09e84fca01415f8cd9d82ec432b
diff --git a/Tests/Module/ExternalData/SeriesBn_2.dat.md5 b/Tests/Module/ExternalData/SeriesBn_2.dat.md5
new file mode 100644
index 0000000..2b917e7
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesBn_2.dat.md5
@@ -0,0 +1 @@
+f7ab5a04aae9cb9a520e70b20b9c8ed7
diff --git a/Tests/Module/ExternalData/SeriesBn_3.dat.md5 b/Tests/Module/ExternalData/SeriesBn_3.dat.md5
new file mode 100644
index 0000000..b9c9760
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesBn_3.dat.md5
@@ -0,0 +1 @@
+30ba0acdee9096b3b9fc6c69362c6b42
diff --git a/Tests/Module/ExternalData/SeriesC.1.dat.md5 b/Tests/Module/ExternalData/SeriesC.1.dat.md5
new file mode 100644
index 0000000..f22e266
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesC.1.dat.md5
@@ -0,0 +1 @@
+31eff09e84fca01415f8cd9d82ec432b
diff --git a/Tests/Module/ExternalData/SeriesC.2.dat.md5 b/Tests/Module/ExternalData/SeriesC.2.dat.md5
new file mode 100644
index 0000000..2b917e7
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesC.2.dat.md5
@@ -0,0 +1 @@
+f7ab5a04aae9cb9a520e70b20b9c8ed7
diff --git a/Tests/Module/ExternalData/SeriesC.3.dat.md5 b/Tests/Module/ExternalData/SeriesC.3.dat.md5
new file mode 100644
index 0000000..b9c9760
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesC.3.dat.md5
@@ -0,0 +1 @@
+30ba0acdee9096b3b9fc6c69362c6b42
diff --git a/Tests/Module/ExternalData/SeriesC.dat.md5 b/Tests/Module/ExternalData/SeriesC.dat.md5
new file mode 100644
index 0000000..be2d687
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesC.dat.md5
@@ -0,0 +1 @@
+f41c94425d01ecbbee70440b951cb058
diff --git a/Tests/Module/ExternalData/SeriesCn.1.dat.md5 b/Tests/Module/ExternalData/SeriesCn.1.dat.md5
new file mode 100644
index 0000000..f22e266
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesCn.1.dat.md5
@@ -0,0 +1 @@
+31eff09e84fca01415f8cd9d82ec432b
diff --git a/Tests/Module/ExternalData/SeriesCn.2.dat.md5 b/Tests/Module/ExternalData/SeriesCn.2.dat.md5
new file mode 100644
index 0000000..2b917e7
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesCn.2.dat.md5
@@ -0,0 +1 @@
+f7ab5a04aae9cb9a520e70b20b9c8ed7
diff --git a/Tests/Module/ExternalData/SeriesCn.3.dat.md5 b/Tests/Module/ExternalData/SeriesCn.3.dat.md5
new file mode 100644
index 0000000..b9c9760
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesCn.3.dat.md5
@@ -0,0 +1 @@
+30ba0acdee9096b3b9fc6c69362c6b42
diff --git a/Tests/Module/ExternalData/SeriesD-1.dat.md5 b/Tests/Module/ExternalData/SeriesD-1.dat.md5
new file mode 100644
index 0000000..f22e266
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesD-1.dat.md5
@@ -0,0 +1 @@
+31eff09e84fca01415f8cd9d82ec432b
diff --git a/Tests/Module/ExternalData/SeriesD-2.dat.md5 b/Tests/Module/ExternalData/SeriesD-2.dat.md5
new file mode 100644
index 0000000..2b917e7
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesD-2.dat.md5
@@ -0,0 +1 @@
+f7ab5a04aae9cb9a520e70b20b9c8ed7
diff --git a/Tests/Module/ExternalData/SeriesD-3.dat.md5 b/Tests/Module/ExternalData/SeriesD-3.dat.md5
new file mode 100644
index 0000000..b9c9760
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesD-3.dat.md5
@@ -0,0 +1 @@
+30ba0acdee9096b3b9fc6c69362c6b42
diff --git a/Tests/Module/ExternalData/SeriesD.dat.md5 b/Tests/Module/ExternalData/SeriesD.dat.md5
new file mode 100644
index 0000000..be2d687
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesD.dat.md5
@@ -0,0 +1 @@
+f41c94425d01ecbbee70440b951cb058
diff --git a/Tests/Module/ExternalData/SeriesDn-1.dat.md5 b/Tests/Module/ExternalData/SeriesDn-1.dat.md5
new file mode 100644
index 0000000..f22e266
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesDn-1.dat.md5
@@ -0,0 +1 @@
+31eff09e84fca01415f8cd9d82ec432b
diff --git a/Tests/Module/ExternalData/SeriesDn-2.dat.md5 b/Tests/Module/ExternalData/SeriesDn-2.dat.md5
new file mode 100644
index 0000000..2b917e7
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesDn-2.dat.md5
@@ -0,0 +1 @@
+f7ab5a04aae9cb9a520e70b20b9c8ed7
diff --git a/Tests/Module/ExternalData/SeriesDn-3.dat.md5 b/Tests/Module/ExternalData/SeriesDn-3.dat.md5
new file mode 100644
index 0000000..b9c9760
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesDn-3.dat.md5
@@ -0,0 +1 @@
+30ba0acdee9096b3b9fc6c69362c6b42
diff --git a/Tests/Module/ExternalData/SeriesMixed.1.dat.md5 b/Tests/Module/ExternalData/SeriesMixed.1.dat.md5
new file mode 100644
index 0000000..f962d8f
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesMixed.1.dat.md5
@@ -0,0 +1 @@
+ce38ea6c3c1e00fa6405dd64b8bf6da0
diff --git a/Tests/Module/ExternalData/SeriesMixed.2.dat.sha1 b/Tests/Module/ExternalData/SeriesMixed.2.dat.sha1
new file mode 100644
index 0000000..43a3540
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesMixed.2.dat.sha1
@@ -0,0 +1 @@
+2af59a7022024974f3b8521b7ed8137c996a79f1
diff --git a/Tests/Module/ExternalData/SeriesMixed.3.dat.sha224 b/Tests/Module/ExternalData/SeriesMixed.3.dat.sha224
new file mode 100644
index 0000000..a18e40e
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesMixed.3.dat.sha224
@@ -0,0 +1 @@
+3b679da7908562fe1cc28db47ffb89bae025f4551dceb343a5869174
diff --git a/Tests/Module/ExternalData/SeriesMixed.4.dat.sha256 b/Tests/Module/ExternalData/SeriesMixed.4.dat.sha256
new file mode 100644
index 0000000..67fc3c2
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesMixed.4.dat.sha256
@@ -0,0 +1 @@
+969171a0dd70d49ce096bd3e8178c7e26c711c9b20dbcaa3853d869d3871f133
diff --git a/Tests/Module/ExternalData/SeriesMixed.5.dat.sha3-256 b/Tests/Module/ExternalData/SeriesMixed.5.dat.sha3-256
new file mode 100644
index 0000000..1a5db39
--- /dev/null
+++ b/Tests/Module/ExternalData/SeriesMixed.5.dat.sha3-256
@@ -0,0 +1 @@
+c01b0bfd51ece4295c7b45493750a3612ecc483095eb1366f9f46b179550e231
diff --git a/Tests/Module/FindDependency/CMakeLists.txt b/Tests/Module/FindDependency/CMakeLists.txt
new file mode 100644
index 0000000..06d7dce
--- /dev/null
+++ b/Tests/Module/FindDependency/CMakeLists.txt
@@ -0,0 +1,13 @@
+
+cmake_minimum_required(VERSION 3.0)
+project(FindDependency)
+
+set(CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/packages")
+
+find_package(Pack1 REQUIRED)
+find_package(Pack4 4.3 EXACT REQUIRED)
+find_package(Pack7 REQUIRED)
+find_package(Pack8 REQUIRED)
+
+add_executable(FindDependency main.cpp)
+target_link_libraries(FindDependency Pack1::Lib Pack4::Lib Pack8::Lib)
diff --git a/Tests/Module/FindDependency/main.cpp b/Tests/Module/FindDependency/main.cpp
new file mode 100644
index 0000000..4ee460f
--- /dev/null
+++ b/Tests/Module/FindDependency/main.cpp
@@ -0,0 +1,41 @@
+
+#ifndef HAVE_PACK1
+# error Expected HAVE_PACK1
+#endif
+
+#ifndef HAVE_PACK2
+# error Expected HAVE_PACK2
+#endif
+
+#ifndef HAVE_PACK3
+# error Expected HAVE_PACK3
+#endif
+
+#ifndef HAVE_PACK4
+# error Expected HAVE_PACK4
+#endif
+
+#ifndef HAVE_PACK5
+# error Expected HAVE_PACK5
+#endif
+
+#ifndef HAVE_PACK6
+# error Expected HAVE_PACK6
+#endif
+
+#ifndef HAVE_PACK7
+# error Expected HAVE_PACK7
+#endif
+
+#ifndef HAVE_PACK7_COMP1
+# error Expected HAVE_PACK7_COMP1
+#endif
+
+#ifndef HAVE_PACK8
+# error Expected HAVE_PACK8
+#endif
+
+int main(int argc, char** argv)
+{
+ return 0;
+}
diff --git a/Tests/Module/FindDependency/packages/Pack1/Pack1Config.cmake b/Tests/Module/FindDependency/packages/Pack1/Pack1Config.cmake
new file mode 100644
index 0000000..ff533c2
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack1/Pack1Config.cmake
@@ -0,0 +1,9 @@
+
+include(CMakeFindDependencyMacro)
+
+find_dependency(Pack2 2.3)
+find_dependency(Pack3)
+
+add_library(Pack1::Lib INTERFACE IMPORTED)
+set_property(TARGET Pack1::Lib PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK1)
+set_property(TARGET Pack1::Lib PROPERTY INTERFACE_LINK_LIBRARIES Pack2::Lib Pack3::Lib)
diff --git a/Tests/Module/FindDependency/packages/Pack1/Pack1ConfigVersion.cmake b/Tests/Module/FindDependency/packages/Pack1/Pack1ConfigVersion.cmake
new file mode 100644
index 0000000..dfb7b6c
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack1/Pack1ConfigVersion.cmake
@@ -0,0 +1,11 @@
+
+set(PACKAGE_VERSION "1.3")
+
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/Tests/Module/FindDependency/packages/Pack2/Pack2Config.cmake b/Tests/Module/FindDependency/packages/Pack2/Pack2Config.cmake
new file mode 100644
index 0000000..672288e
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack2/Pack2Config.cmake
@@ -0,0 +1,5 @@
+
+set(PACK2_VAR ON)
+
+add_library(Pack2::Lib INTERFACE IMPORTED)
+set_property(TARGET Pack2::Lib PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK2)
diff --git a/Tests/Module/FindDependency/packages/Pack2/Pack2ConfigVersion.cmake b/Tests/Module/FindDependency/packages/Pack2/Pack2ConfigVersion.cmake
new file mode 100644
index 0000000..42f58c0
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack2/Pack2ConfigVersion.cmake
@@ -0,0 +1,11 @@
+
+set(PACKAGE_VERSION "2.4")
+
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/Tests/Module/FindDependency/packages/Pack3/Pack3Config.cmake b/Tests/Module/FindDependency/packages/Pack3/Pack3Config.cmake
new file mode 100644
index 0000000..25c32f3
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack3/Pack3Config.cmake
@@ -0,0 +1,5 @@
+
+set(PACK3_VAR ON)
+
+add_library(Pack3::Lib INTERFACE IMPORTED)
+set_property(TARGET Pack3::Lib PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK3)
diff --git a/Tests/Module/FindDependency/packages/Pack3/Pack3ConfigVersion.cmake b/Tests/Module/FindDependency/packages/Pack3/Pack3ConfigVersion.cmake
new file mode 100644
index 0000000..870f747
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack3/Pack3ConfigVersion.cmake
@@ -0,0 +1,11 @@
+
+set(PACKAGE_VERSION "1.4")
+
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/Tests/Module/FindDependency/packages/Pack4/Pack4Config.cmake b/Tests/Module/FindDependency/packages/Pack4/Pack4Config.cmake
new file mode 100644
index 0000000..62fddb1
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack4/Pack4Config.cmake
@@ -0,0 +1,9 @@
+
+include(CMakeFindDependencyMacro)
+
+find_dependency(Pack5 3.1) # Actual version is 3.3. EXACT not propagated.
+find_dependency(Pack6 5.5 EXACT)
+
+add_library(Pack4::Lib INTERFACE IMPORTED)
+set_property(TARGET Pack4::Lib PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK4)
+set_property(TARGET Pack4::Lib PROPERTY INTERFACE_LINK_LIBRARIES Pack5::Lib Pack6::Lib)
diff --git a/Tests/Module/FindDependency/packages/Pack4/Pack4ConfigVersion.cmake b/Tests/Module/FindDependency/packages/Pack4/Pack4ConfigVersion.cmake
new file mode 100644
index 0000000..ae982b0
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack4/Pack4ConfigVersion.cmake
@@ -0,0 +1,11 @@
+
+set(PACKAGE_VERSION "4.3")
+
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/Tests/Module/FindDependency/packages/Pack5/Pack5Config.cmake b/Tests/Module/FindDependency/packages/Pack5/Pack5Config.cmake
new file mode 100644
index 0000000..1edda9a
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack5/Pack5Config.cmake
@@ -0,0 +1,3 @@
+
+add_library(Pack5::Lib INTERFACE IMPORTED)
+set_property(TARGET Pack5::Lib PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK5)
diff --git a/Tests/Module/FindDependency/packages/Pack5/Pack5ConfigVersion.cmake b/Tests/Module/FindDependency/packages/Pack5/Pack5ConfigVersion.cmake
new file mode 100644
index 0000000..e944f96
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack5/Pack5ConfigVersion.cmake
@@ -0,0 +1,11 @@
+
+set(PACKAGE_VERSION "3.3")
+
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/Tests/Module/FindDependency/packages/Pack6/Pack6Config.cmake b/Tests/Module/FindDependency/packages/Pack6/Pack6Config.cmake
new file mode 100644
index 0000000..d6c85fb
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack6/Pack6Config.cmake
@@ -0,0 +1,3 @@
+
+add_library(Pack6::Lib INTERFACE IMPORTED)
+set_property(TARGET Pack6::Lib PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK6)
diff --git a/Tests/Module/FindDependency/packages/Pack6/Pack6ConfigVersion.cmake b/Tests/Module/FindDependency/packages/Pack6/Pack6ConfigVersion.cmake
new file mode 100644
index 0000000..0dd00d2
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack6/Pack6ConfigVersion.cmake
@@ -0,0 +1,11 @@
+
+set(PACKAGE_VERSION "5.5")
+
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/Tests/Module/FindDependency/packages/Pack7/Pack7Config.cmake b/Tests/Module/FindDependency/packages/Pack7/Pack7Config.cmake
new file mode 100644
index 0000000..9df1345
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack7/Pack7Config.cmake
@@ -0,0 +1,14 @@
+if(NOT Pack7_FOUND)
+ set(Pack7_FOUND 1)
+ add_library(Pack7::Pack7 INTERFACE IMPORTED)
+ set_property(TARGET Pack7::Pack7 PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK7)
+endif()
+
+foreach(module ${Pack7_FIND_COMPONENTS})
+ if(module STREQUAL "Comp1")
+ add_library(Pack7::Comp1 INTERFACE IMPORTED)
+ set_property(TARGET Pack7::Comp1 PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK7_COMP1)
+ set_property(TARGET Pack7::Comp1 PROPERTY INTERFACE_LINK_LIBRARIES Pack7::Pack7)
+ set(Pack7_Comp1_FOUND 1)
+ endif()
+endforeach()
diff --git a/Tests/Module/FindDependency/packages/Pack8/Pack8Config.cmake b/Tests/Module/FindDependency/packages/Pack8/Pack8Config.cmake
new file mode 100644
index 0000000..d7ca054
--- /dev/null
+++ b/Tests/Module/FindDependency/packages/Pack8/Pack8Config.cmake
@@ -0,0 +1,7 @@
+include(CMakeFindDependencyMacro)
+
+find_dependency(Pack7 REQUIRED COMPONENTS Comp1)
+
+add_library(Pack8::Lib INTERFACE IMPORTED)
+set_property(TARGET Pack8::Lib PROPERTY INTERFACE_COMPILE_DEFINITIONS HAVE_PACK8)
+set_property(TARGET Pack8::Lib PROPERTY INTERFACE_LINK_LIBRARIES Pack7::Comp1)
diff --git a/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt b/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt
new file mode 100644
index 0000000..e406758
--- /dev/null
+++ b/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt
@@ -0,0 +1,219 @@
+cmake_minimum_required(VERSION 3.1.0)
+project(WriteCompilerDetectionHeader)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+include(WriteCompilerDetectionHeader)
+include(CheckCXXSourceCompiles)
+
+get_property(cxx_known_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
+get_property(c_known_features GLOBAL PROPERTY CMAKE_C_KNOWN_FEATURES)
+
+write_compiler_detection_header(
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/test_compiler_detection.h"
+ PREFIX TEST
+ COMPILERS GNU Clang AppleClang MSVC SunPro Intel
+ VERSION 3.1
+ PROLOG "// something"
+ EPILOG "// more"
+ FEATURES
+ ${cxx_known_features} ${c_known_features}
+)
+
+write_compiler_detection_header(
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/compiler_multi_files/multi_file_compiler_detection.h"
+ PREFIX MULTI
+ OUTPUT_FILES_VAR multi_files
+ OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/compiler_multi_files/compiler_support"
+ COMPILERS GNU Clang AppleClang MSVC SunPro Intel
+ VERSION 3.1
+ FEATURES
+ ${cxx_known_features} ${c_known_features}
+)
+
+macro(set_defines target true_defs false_defs)
+ set(defines)
+ foreach(def ${true_defs})
+ list(APPEND defines ${def}=1)
+ endforeach()
+ foreach(def ${false_defs})
+ list(APPEND defines ${def}=0)
+ endforeach()
+ target_compile_definitions(${target}
+ PRIVATE
+ ${defines}
+ EXPECTED_COMPILER_VERSION_MAJOR=${COMPILER_VERSION_MAJOR}
+ EXPECTED_COMPILER_VERSION_MINOR=${COMPILER_VERSION_MINOR}
+ EXPECTED_COMPILER_VERSION_PATCH=${COMPILER_VERSION_PATCH}
+ )
+endmacro()
+
+# Only run the compiler detection header test for compilers with
+# detailed features tables, not just meta-features
+
+if (CMAKE_C_COMPILE_FEATURES)
+ if (NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM|Fujitsu|FujitsuClang)$")
+ set(C_expected_features ${CMAKE_C_COMPILE_FEATURES})
+ list(FILTER C_expected_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
+ endif()
+endif()
+if (C_expected_features)
+ string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" COMPILER_VERSION_MAJOR "${CMAKE_C_COMPILER_VERSION}")
+ string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" COMPILER_VERSION_MINOR "${CMAKE_C_COMPILER_VERSION}")
+ string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" COMPILER_VERSION_PATCH "${CMAKE_C_COMPILER_VERSION}")
+
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU"
+ OR (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang"
+ OR CMAKE_C_COMPILER_ID STREQUAL "Intel")
+ add_executable(WriteCompilerDetectionHeader_C11 main.c)
+ set_property(TARGET WriteCompilerDetectionHeader_C11 PROPERTY C_STANDARD 11)
+ set_defines(WriteCompilerDetectionHeader_C11 "EXPECTED_COMPILER_C_FUNCTION_PROTOTYPES;EXPECTED_COMPILER_C_RESTRICT" "")
+
+ add_executable(WriteCompilerDetectionHeader_C11_multi main_multi.c)
+ set_property(TARGET WriteCompilerDetectionHeader_C11_multi PROPERTY C_STANDARD 11)
+ set_defines(WriteCompilerDetectionHeader_C11_multi "EXPECTED_COMPILER_C_FUNCTION_PROTOTYPES;EXPECTED_COMPILER_C_RESTRICT" "")
+ target_include_directories(WriteCompilerDetectionHeader_C11_multi PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/compiler_multi_files)
+
+ add_executable(C_undefined c_undefined.c)
+ set_property(TARGET C_undefined PROPERTY C_STANDARD 90)
+ include(CheckCCompilerFlag)
+ check_c_compiler_flag(-Werror=undef use_error_undef)
+ if (use_error_undef)
+ target_compile_options(C_undefined PRIVATE -Werror=undef)
+ endif()
+
+ add_executable(WriteCompilerDetectionHeader_C main.c)
+ set_property(TARGET WriteCompilerDetectionHeader_C PROPERTY C_STANDARD 90)
+ set_defines(WriteCompilerDetectionHeader_C "EXPECTED_COMPILER_C_FUNCTION_PROTOTYPES" "EXPECTED_COMPILER_C_RESTRICT")
+
+ add_executable(WriteCompilerDetectionHeader_C_multi main_multi.c)
+ set_property(TARGET WriteCompilerDetectionHeader_C_multi PROPERTY C_STANDARD 90)
+ set_defines(WriteCompilerDetectionHeader_C_multi "EXPECTED_COMPILER_C_FUNCTION_PROTOTYPES" "EXPECTED_COMPILER_C_RESTRICT")
+ target_include_directories(WriteCompilerDetectionHeader_C_multi PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/compiler_multi_files)
+ endif()
+endif()
+
+if (CMAKE_CXX_COMPILE_FEATURES)
+ if (NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM|Fujitsu|FujitsuClang)$")
+ set(CXX_expected_features ${CMAKE_CXX_COMPILE_FEATURES})
+ list(FILTER CXX_expected_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
+ endif()
+endif()
+if (NOT CXX_expected_features)
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp"
+ "int main(int,char**) { return 0; }\n"
+ )
+ add_executable(WriteCompilerDetectionHeader "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp")
+
+ if(UNIX OR NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ check_cxx_source_compiles("#include \"${CMAKE_CURRENT_BINARY_DIR}/test_compiler_detection.h\"\nint main() { return 0; }\n"
+ file_include_works
+ )
+ if (file_include_works)
+ message(SEND_ERROR "Inclusion of ${CMAKE_CURRENT_BINARY_DIR}/test_compiler_detection.h was expected to cause an error, but did not.")
+ endif()
+ endif()
+ return()
+endif()
+
+string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" COMPILER_VERSION_MAJOR "${CMAKE_CXX_COMPILER_VERSION}")
+string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" COMPILER_VERSION_MINOR "${CMAKE_CXX_COMPILER_VERSION}")
+string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" COMPILER_VERSION_PATCH "${CMAKE_CXX_COMPILER_VERSION}")
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
+ OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"
+ OR CMAKE_CXX_COMPILER_ID STREQUAL "SunPro"
+ OR CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
+ # False for C++98 mode.
+ list(APPEND false_defs EXPECTED_COMPILER_CXX_DELEGATING_CONSTRUCTORS)
+ list(APPEND false_defs EXPECTED_COMPILER_CXX_VARIADIC_TEMPLATES)
+endif()
+
+# for msvc the compiler version determines which c++11 features are available.
+if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC"
+ OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC"))
+ if(";${CMAKE_CXX_COMPILE_FEATURES};" MATCHES ";cxx_delegating_constructors;")
+ list(APPEND true_defs EXPECTED_COMPILER_CXX_DELEGATING_CONSTRUCTORS)
+ list(APPEND true_defs EXPECTED_COMPILER_CXX_VARIADIC_TEMPLATES)
+ else()
+ list(APPEND false_defs EXPECTED_COMPILER_CXX_DELEGATING_CONSTRUCTORS)
+ list(APPEND false_defs EXPECTED_COMPILER_CXX_VARIADIC_TEMPLATES)
+ endif()
+endif()
+
+add_executable(WriteCompilerDetectionHeader main.cpp)
+set_property(TARGET WriteCompilerDetectionHeader PROPERTY CXX_STANDARD 98)
+set_defines(WriteCompilerDetectionHeader "${true_defs}" "${false_defs}")
+
+add_executable(multi_files multi_files.cpp)
+set_property(TARGET multi_files PROPERTY CXX_STANDARD 98)
+target_include_directories(multi_files PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/compiler_multi_files)
+set_defines(multi_files "${true_defs}" "${false_defs}")
+
+if(MSVC)
+ return() # MSVC has only one mode.
+endif()
+
+# Since GNU 4.7
+if (";${CMAKE_CXX_COMPILE_FEATURES};" MATCHES ";cxx_delegating_constructors;")
+ list(APPEND true_defs EXPECTED_COMPILER_CXX_DELEGATING_CONSTRUCTORS)
+ list(REMOVE_ITEM false_defs EXPECTED_COMPILER_CXX_DELEGATING_CONSTRUCTORS)
+endif()
+
+# Since GNU 4.4
+if (";${CMAKE_CXX_COMPILE_FEATURES};" MATCHES ";cxx_variadic_templates;")
+ list(APPEND true_defs EXPECTED_COMPILER_CXX_VARIADIC_TEMPLATES)
+ list(REMOVE_ITEM false_defs EXPECTED_COMPILER_CXX_VARIADIC_TEMPLATES)
+endif()
+
+add_executable(WriteCompilerDetectionHeader_11 main.cpp)
+set_property(TARGET WriteCompilerDetectionHeader_11 PROPERTY CXX_STANDARD 11)
+set_defines(WriteCompilerDetectionHeader_11 "${true_defs}" "${false_defs}")
+
+add_executable(multi_files_11 multi_files.cpp)
+set_property(TARGET multi_files_11 PROPERTY CXX_STANDARD 11)
+target_include_directories(multi_files_11 PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/compiler_multi_files)
+set_defines(multi_files_11 "${true_defs}" "${false_defs}")
+
+# test for ALLOW_UNKNOWN_COMPILERS
+
+# use a compiler does not match the current one,
+# so one always hits the fallback code
+if (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
+ set(OTHER_CXX "Intel")
+else()
+ set(OTHER_CXX "SunPro")
+endif()
+
+write_compiler_detection_header(
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/test_compiler_detection_allow_unknown.h"
+ PREFIX TEST
+ COMPILERS ${OTHER_CXX}
+ FEATURES cxx_nullptr
+ ALLOW_UNKNOWN_COMPILERS
+)
+
+# intentionally abuse the TEST_NULLPTR variable: this will only work
+# with the fallback code.
+check_cxx_source_compiles("#include \"${CMAKE_CURRENT_BINARY_DIR}/test_compiler_detection_allow_unknown.h\"
+int main() {\n int i = TEST_NULLPTR;\n return 0; }\n"
+ file_include_works_allow_unknown
+)
+if (NOT file_include_works_allow_unknown)
+ message(SEND_ERROR "Inclusion of ${CMAKE_CURRENT_BINARY_DIR}/test_compiler_detection_allow_unknown.h was expected to work, but did not.")
+endif()
+
+# test for BARE_FEATURES
+
+write_compiler_detection_header(
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/test_compiler_detection_bare_features.h"
+ PREFIX TEST
+ COMPILERS GNU Clang AppleClang MSVC SunPro Intel
+ VERSION 3.1
+ BARE_FEATURES cxx_nullptr cxx_override cxx_noexcept cxx_final
+)
+
+add_executable(WriteCompilerDetectionHeaderBareFeatures main_bare.cpp)
+set_property(TARGET WriteCompilerDetectionHeaderBareFeatures PROPERTY CXX_STANDARD 11)
diff --git a/Tests/Module/WriteCompilerDetectionHeader/c_undefined.c b/Tests/Module/WriteCompilerDetectionHeader/c_undefined.c
new file mode 100644
index 0000000..487e66d
--- /dev/null
+++ b/Tests/Module/WriteCompilerDetectionHeader/c_undefined.c
@@ -0,0 +1,7 @@
+
+#include "test_compiler_detection.h"
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/Module/WriteCompilerDetectionHeader/compile_tests.h b/Tests/Module/WriteCompilerDetectionHeader/compile_tests.h
new file mode 100644
index 0000000..0da8bab
--- /dev/null
+++ b/Tests/Module/WriteCompilerDetectionHeader/compile_tests.h
@@ -0,0 +1,27 @@
+
+#define JOIN_IMPL(A, B) A##B
+#define JOIN(A, B) JOIN_IMPL(A, B)
+
+#define CHECK(FEATURE) \
+ (JOIN(PREFIX, JOIN(_COMPILER_, FEATURE)) == \
+ JOIN(EXPECTED_COMPILER_, FEATURE))
+
+#if !CHECK(CXX_DELEGATING_CONSTRUCTORS)
+# error cxx_delegating_constructors expected availability did not match.
+#endif
+
+#if !CHECK(CXX_VARIADIC_TEMPLATES)
+# error cxx_variadic_templates expected availability did not match.
+#endif
+
+#if !CHECK(VERSION_MAJOR)
+# error Compiler major version did not match.
+#endif
+
+#if !CHECK(VERSION_MINOR)
+# error Compiler minor version did not match.
+#endif
+
+#if !CHECK(VERSION_PATCH)
+# error Compiler patch version did not match.
+#endif
diff --git a/Tests/Module/WriteCompilerDetectionHeader/main.c b/Tests/Module/WriteCompilerDetectionHeader/main.c
new file mode 100644
index 0000000..3420c67
--- /dev/null
+++ b/Tests/Module/WriteCompilerDetectionHeader/main.c
@@ -0,0 +1,30 @@
+
+#include "test_compiler_detection.h"
+
+#if !defined(TEST_COMPILER_C_FUNCTION_PROTOTYPES) || \
+ !TEST_COMPILER_C_FUNCTION_PROTOTYPES
+# error Expected TEST_COMPILER_C_FUNCTION_PROTOTYPES
+#endif
+
+#if !EXPECTED_COMPILER_C_FUNCTION_PROTOTYPES
+# error Expected EXPECTED_COMPILER_C_FUNCTION_PROTOTYPES
+#endif
+
+#if !defined(TEST_COMPILER_C_RESTRICT) || !TEST_COMPILER_C_RESTRICT
+# if EXPECTED_COMPILER_C_RESTRICT
+# error Expected TEST_COMPILER_C_RESTRICT
+# endif
+#else
+# if !EXPECTED_COMPILER_C_RESTRICT
+# error Expect no TEST_COMPILER_C_RESTRICT
+# endif
+#endif
+
+#ifdef TEST_COMPILER_CXX_STATIC_ASSERT
+# error Expect no CXX features defined
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/Module/WriteCompilerDetectionHeader/main.cpp b/Tests/Module/WriteCompilerDetectionHeader/main.cpp
new file mode 100644
index 0000000..97116a5
--- /dev/null
+++ b/Tests/Module/WriteCompilerDetectionHeader/main.cpp
@@ -0,0 +1,17 @@
+
+#include "test_compiler_detection.h"
+
+#define PREFIX TEST
+#include "compile_tests.h"
+
+#ifdef TEST_COMPILER_C_STATIC_ASSERT
+# error Expect no C features defined
+#endif
+
+TEST_STATIC_ASSERT(true);
+TEST_STATIC_ASSERT_MSG(true, "msg");
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/Module/WriteCompilerDetectionHeader/main_bare.cpp b/Tests/Module/WriteCompilerDetectionHeader/main_bare.cpp
new file mode 100644
index 0000000..6954318
--- /dev/null
+++ b/Tests/Module/WriteCompilerDetectionHeader/main_bare.cpp
@@ -0,0 +1,23 @@
+#include "test_compiler_detection_bare_features.h"
+
+class base
+{
+public:
+ virtual ~base() {}
+ virtual void baz() = 0;
+};
+
+class foo final
+{
+public:
+ virtual ~foo() {}
+ char* bar;
+ void baz() noexcept override { bar = nullptr; }
+};
+
+int main()
+{
+ foo f;
+
+ return 0;
+}
diff --git a/Tests/Module/WriteCompilerDetectionHeader/main_multi.c b/Tests/Module/WriteCompilerDetectionHeader/main_multi.c
new file mode 100644
index 0000000..28f9dae
--- /dev/null
+++ b/Tests/Module/WriteCompilerDetectionHeader/main_multi.c
@@ -0,0 +1,30 @@
+
+#include "multi_file_compiler_detection.h"
+
+#if !defined(MULTI_COMPILER_C_FUNCTION_PROTOTYPES) || \
+ !MULTI_COMPILER_C_FUNCTION_PROTOTYPES
+# error Expected MULTI_COMPILER_C_FUNCTION_PROTOTYPES
+#endif
+
+#if !EXPECTED_COMPILER_C_FUNCTION_PROTOTYPES
+# error Expected EXPECTED_COMPILER_C_FUNCTION_PROTOTYPES
+#endif
+
+#if !defined(MULTI_COMPILER_C_RESTRICT) || !MULTI_COMPILER_C_RESTRICT
+# if EXPECTED_COMPILER_C_RESTRICT
+# error Expected MULTI_COMPILER_C_RESTRICT
+# endif
+#else
+# if !EXPECTED_COMPILER_C_RESTRICT
+# error Expect no MULTI_COMPILER_C_RESTRICT
+# endif
+#endif
+
+#ifdef MULTI_COMPILER_CXX_STATIC_ASSERT
+# error Expect no CXX features defined
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/Module/WriteCompilerDetectionHeader/multi_files.cpp b/Tests/Module/WriteCompilerDetectionHeader/multi_files.cpp
new file mode 100644
index 0000000..44f4d17
--- /dev/null
+++ b/Tests/Module/WriteCompilerDetectionHeader/multi_files.cpp
@@ -0,0 +1,17 @@
+
+#include "multi_file_compiler_detection.h"
+
+#define PREFIX MULTI
+#include "compile_tests.h"
+
+#ifdef MULTI_COMPILER_C_STATIC_ASSERT
+# error Expect no C features defined
+#endif
+
+MULTI_STATIC_ASSERT(true);
+MULTI_STATIC_ASSERT_MSG(true, "msg");
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/ModuleDefinition/CMakeLists.txt b/Tests/ModuleDefinition/CMakeLists.txt
new file mode 100644
index 0000000..567fb4b
--- /dev/null
+++ b/Tests/ModuleDefinition/CMakeLists.txt
@@ -0,0 +1,38 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(ModuleDefinition C)
+
+# Test .def file source recognition for DLLs.
+add_library(example_dll SHARED example_dll.c example_dll.def)
+
+add_library(split_dll SHARED split_dll.c split_dll_1.def split_dll_2.def)
+
+# Test generated .def file.
+add_custom_command(OUTPUT example_dll_gen.def
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/example_dll_gen.def.in
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/example_dll_gen.def.in
+ ${CMAKE_CURRENT_BINARY_DIR}/example_dll_gen.def
+ )
+add_library(example_dll_gen SHARED example_dll_gen.c example_dll_gen.def)
+
+# Test /DEF:<file> flag recognition for VS.
+if(MSVC OR CMAKE_C_COMPILER_ID STREQUAL "Intel")
+ add_library(example_dll_2 SHARED example_dll_2.c)
+ set_property(TARGET example_dll_2 PROPERTY LINK_FLAGS
+ /DEF:"${ModuleDefinition_SOURCE_DIR}/example_dll_2.def")
+ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS EXAMPLE_DLL_2)
+ set(example_dll_2 example_dll_2)
+endif()
+
+# Test .def file source recognition for EXEs.
+add_executable(example_exe example_exe.c example_exe.def)
+set_property(TARGET example_exe PROPERTY ENABLE_EXPORTS 1)
+target_link_libraries(example_exe
+ example_dll
+ example_dll_gen
+ ${example_dll_2}
+ split_dll
+ )
+
+# Test linking to the executable.
+add_library(example_mod_1 MODULE example_mod_1.c)
+target_link_libraries(example_mod_1 example_exe example_dll ${example_dll_2})
diff --git a/Tests/ModuleDefinition/example_dll.c b/Tests/ModuleDefinition/example_dll.c
new file mode 100644
index 0000000..3d57b9a
--- /dev/null
+++ b/Tests/ModuleDefinition/example_dll.c
@@ -0,0 +1,4 @@
+int example_dll_function(void)
+{
+ return 0;
+}
diff --git a/Tests/ModuleDefinition/example_dll.def b/Tests/ModuleDefinition/example_dll.def
new file mode 100644
index 0000000..df64fb3
--- /dev/null
+++ b/Tests/ModuleDefinition/example_dll.def
@@ -0,0 +1,2 @@
+EXPORTS
+example_dll_function
diff --git a/Tests/ModuleDefinition/example_dll_2.c b/Tests/ModuleDefinition/example_dll_2.c
new file mode 100644
index 0000000..6f33867
--- /dev/null
+++ b/Tests/ModuleDefinition/example_dll_2.c
@@ -0,0 +1,4 @@
+int example_dll_2_function(void)
+{
+ return 0;
+}
diff --git a/Tests/ModuleDefinition/example_dll_2.def b/Tests/ModuleDefinition/example_dll_2.def
new file mode 100644
index 0000000..8eba7f9
--- /dev/null
+++ b/Tests/ModuleDefinition/example_dll_2.def
@@ -0,0 +1,2 @@
+EXPORTS
+example_dll_2_function
diff --git a/Tests/ModuleDefinition/example_dll_gen.c b/Tests/ModuleDefinition/example_dll_gen.c
new file mode 100644
index 0000000..ac0a88b
--- /dev/null
+++ b/Tests/ModuleDefinition/example_dll_gen.c
@@ -0,0 +1,4 @@
+int example_dll_gen_function(void)
+{
+ return 0;
+}
diff --git a/Tests/ModuleDefinition/example_dll_gen.def.in b/Tests/ModuleDefinition/example_dll_gen.def.in
new file mode 100644
index 0000000..c489dbc
--- /dev/null
+++ b/Tests/ModuleDefinition/example_dll_gen.def.in
@@ -0,0 +1,2 @@
+EXPORTS
+example_dll_gen_function
diff --git a/Tests/ModuleDefinition/example_exe.c b/Tests/ModuleDefinition/example_exe.c
new file mode 100644
index 0000000..8e86fc4
--- /dev/null
+++ b/Tests/ModuleDefinition/example_exe.c
@@ -0,0 +1,21 @@
+extern int __declspec(dllimport) example_dll_function(void);
+extern int __declspec(dllimport) example_dll_gen_function(void);
+#ifdef EXAMPLE_DLL_2
+extern int __declspec(dllimport) example_dll_2_function(void);
+#endif
+extern int __declspec(dllimport) split_dll_1(void);
+extern int __declspec(dllimport) split_dll_2(void);
+
+int example_exe_function(void)
+{
+ return 0;
+}
+
+int main(void)
+{
+ return example_dll_function() + example_dll_gen_function() +
+#ifdef EXAMPLE_DLL_2
+ example_dll_2_function() +
+#endif
+ split_dll_1() + split_dll_2() + example_exe_function();
+}
diff --git a/Tests/ModuleDefinition/example_exe.def b/Tests/ModuleDefinition/example_exe.def
new file mode 100644
index 0000000..2a0df1f
--- /dev/null
+++ b/Tests/ModuleDefinition/example_exe.def
@@ -0,0 +1,2 @@
+EXPORTS
+example_exe_function
diff --git a/Tests/ModuleDefinition/example_mod_1.c b/Tests/ModuleDefinition/example_mod_1.c
new file mode 100644
index 0000000..8afdb31
--- /dev/null
+++ b/Tests/ModuleDefinition/example_mod_1.c
@@ -0,0 +1,20 @@
+#ifdef __WATCOMC__
+# define MODULE_CCONV __cdecl
+#else
+# define MODULE_CCONV
+#endif
+
+int __declspec(dllimport) example_exe_function(void);
+int __declspec(dllimport) example_dll_function(void);
+#ifdef EXAMPLE_DLL_2
+int __declspec(dllimport) example_dll_2_function(void);
+#endif
+
+__declspec(dllexport) int MODULE_CCONV example_mod_1_function(int n)
+{
+ return example_dll_function() +
+#ifdef EXAMPLE_DLL_2
+ example_dll_2_function() +
+#endif
+ example_exe_function() + n;
+}
diff --git a/Tests/ModuleDefinition/split_dll.c b/Tests/ModuleDefinition/split_dll.c
new file mode 100644
index 0000000..1546a2d
--- /dev/null
+++ b/Tests/ModuleDefinition/split_dll.c
@@ -0,0 +1,9 @@
+int split_dll_1(void)
+{
+ return 0;
+}
+
+int split_dll_2(void)
+{
+ return 0;
+}
diff --git a/Tests/ModuleDefinition/split_dll_1.def b/Tests/ModuleDefinition/split_dll_1.def
new file mode 100644
index 0000000..ced9f10
--- /dev/null
+++ b/Tests/ModuleDefinition/split_dll_1.def
@@ -0,0 +1,2 @@
+EXPORTS
+split_dll_1
diff --git a/Tests/ModuleDefinition/split_dll_2.def b/Tests/ModuleDefinition/split_dll_2.def
new file mode 100644
index 0000000..b072c50
--- /dev/null
+++ b/Tests/ModuleDefinition/split_dll_2.def
@@ -0,0 +1,2 @@
+EXPORTS
+split_dll_2
diff --git a/Tests/MumpsCoverage/.gitattributes b/Tests/MumpsCoverage/.gitattributes
new file mode 100644
index 0000000..9fc9b0f
--- /dev/null
+++ b/Tests/MumpsCoverage/.gitattributes
@@ -0,0 +1 @@
+*.cmcov eol=crlf
diff --git a/Tests/MumpsCoverage/DartConfiguration.cache.tcl.in b/Tests/MumpsCoverage/DartConfiguration.cache.tcl.in
new file mode 100644
index 0000000..a1c6b17
--- /dev/null
+++ b/Tests/MumpsCoverage/DartConfiguration.cache.tcl.in
@@ -0,0 +1,8 @@
+# This file is configured by CMake automatically as DartConfiguration.tcl
+# If you choose not to use CMake, this file may be hand configured, by
+# filling in the required variables.
+
+
+# Configuration directories and files
+SourceDirectory: ${CMake_SOURCE_DIR}/Testing/MumpsCoverage
+BuildDirectory: ${CMake_BINARY_DIR}/Testing/MumpsCacheCoverage
diff --git a/Tests/MumpsCoverage/DartConfiguration.tcl.in b/Tests/MumpsCoverage/DartConfiguration.tcl.in
new file mode 100644
index 0000000..2d7eaa5
--- /dev/null
+++ b/Tests/MumpsCoverage/DartConfiguration.tcl.in
@@ -0,0 +1,8 @@
+# This file is configured by CMake automatically as DartConfiguration.tcl
+# If you choose not to use CMake, this file may be hand configured, by
+# filling in the required variables.
+
+
+# Configuration directories and files
+SourceDirectory: ${CMake_SOURCE_DIR}/Testing/MumpsCoverage
+BuildDirectory: ${CMake_BINARY_DIR}/Testing/MumpsCoverage
diff --git a/Tests/MumpsCoverage/VistA-FOIA/Packages/Uncategorized/ZZCOVTST.m b/Tests/MumpsCoverage/VistA-FOIA/Packages/Uncategorized/ZZCOVTST.m
new file mode 100644
index 0000000..5567c4e
--- /dev/null
+++ b/Tests/MumpsCoverage/VistA-FOIA/Packages/Uncategorized/ZZCOVTST.m
@@ -0,0 +1,46 @@
+ZZCOVTST;OSEHRA/JPS -- Test routine for Coverage Parsing;4/28/2014
+ ; (tab) This is series of comments
+ ; (tab) it should all be not executable
+ ; (spaces) one of these sets might be a problem
+ ; (spaces) we will have to see.
+EN ; This entry point shouldn't be found without fixing
+ N D
+ S D=1 ;An executable line
+ D T1^ZZCOVTST
+ I '$$T5 W "RETURNED FROM t5",!
+ Q
+ ; This line not executable
+ D T6^ZZCOVTST
+ ;
+% ; a line to test for a problem where % was dropped
+ N Do,Re,Mi
+ S Do="A#"
+T1 ; This line should always be found
+ N D
+ S D=2
+ W !,D,!,"This is the second entry point",!
+ D T2^ZZCOVTST(D)
+ Q
+ ;
+T2(EQ) ; This is debatable and only called with ENT^ROU notation
+ N D
+ S D=3
+ W !,D,!,EQ,"This is the third entry point",!
+ D T3^ZZCOVTST
+ Q
+ ;
+T3 N D S D=4 W D,!,"Fourth Entry point",! Q
+ ;
+T4 N D S D=5 W "Shouldn't be executed"
+ W "Lots to not do"
+ Q
+T5(EQ) ;this entry point is called with a $$ notation
+ W "THIS IS THE $$ NOTATION!",!
+ Q 0
+T6 ; An entry point to show comments inside of "DO" blocks
+ D
+ . W "This is executable code",!
+ . ;This is a comment inside the do block, not executable
+ . S ZZBLAH="blah"
+ W "Ending T6",!
+ ;
diff --git a/Tests/MumpsCoverage/ZZCOVTST.cmcov b/Tests/MumpsCoverage/ZZCOVTST.cmcov
new file mode 100644
index 0000000..12f2aa6
--- /dev/null
+++ b/Tests/MumpsCoverage/ZZCOVTST.cmcov
@@ -0,0 +1,48 @@
+Routine,Line,RtnLine,Code
+ZZCOVTST,1,1,"ZZCOVTST;OSEHRA/JPS -- Test routine for Coverage Parsing;4/28/2014"
+,2,0," ; (tab) This is series of comments"
+,3,0," ; (tab) it should all be not executable"
+,4,0," ; (spaces) one of these sets might be a problem"
+,5,0," ; (spaces) we will have to see."
+,6,0,"EN ; This entry point shouldn't be found without fixing"
+,7,1," N D"
+,8,1," S D=1 ;An executable line"
+,9,1," D T1^ZZCOVTST"
+,10,1," I '$$T5 W ""RETURNED FROM t5"",!"
+,11,1," D T6^ZZCOVTST"
+,12,1," Q"
+,13,0," ; This line not executable"
+,14,0," ;"
+,15,1,"% ; a line to test for a problem where % was dropped"
+,16,1,"N Do,Re,Mi"
+,17,1,"S Do=""A#"""
+,18,0,"T1 ; This line should always be found"
+,19,1," N D"
+,20,1," S D=2"
+,21,1," W !,D,!,""This is the second entry point"",!"
+,22,1," D T2^ZZCOVTST(D)"
+,23,1," Q"
+,24,0," ;"
+,25,0,"T2(EQ) ; This is debatable and only called with ENT^ROU notation"
+,26,1," N D"
+,27,1," S D=3"
+,28,1," W !,D,!,EQ,""This is the third entry point"",!"
+,29,1," D T3^ZZCOVTST"
+,30,1," Q"
+,31,0," ;"
+,32,1,"T3 N D S D=4 W D,!,""Fourth Entry point"",! Q"
+,33,0," ;"
+,34,0,"T4 N D S D=5 W ""Shouldn't be executed"""
+,35,0," W ""Lots to not do"""
+,36,0," Q"
+,37,1,"T5(EQ) ;this entry point is called with a $$ notation"
+,38,1," W ""THIS IS THE $$ NOTATION!"",!"
+,39,1," Q 0"
+,40,0,"T6 ; An entry point to show comments inside of ""DO"" blocks"
+,41,1," D"
+,42,1," . W ""This is executable code"",!"
+,43,0," . ; This is a comment inside the do block, not executable"
+,44,1," . S ZZBLAH=""blah"""
+,45,1," W ""Ending T6"",!"
+,46,0," ;"
+Toals for ZZCOVTST,,28,
diff --git a/Tests/MumpsCoverage/ZZCOVTST.mcov b/Tests/MumpsCoverage/ZZCOVTST.mcov
new file mode 100644
index 0000000..e1fa18c
--- /dev/null
+++ b/Tests/MumpsCoverage/ZZCOVTST.mcov
@@ -0,0 +1,41 @@
+%GO Global Output Utility
+GT.M 15-AUG-2014 10:14:32 ZWR
+^ZZCOVERAGE("*CHILDREN")="212000:68000:280000"
+^ZZCOVERAGE("*RUN")="56000:136000:192000"
+^ZZCOVERAGE("ZZCOVTST","EN")="1:4000:4000:8000:8627798"
+^ZZCOVERAGE("ZZCOVTST","EN",1)="1:0:0:0:27"
+^ZZCOVERAGE("ZZCOVTST","EN",2)="1:0:0:0:23"
+^ZZCOVERAGE("ZZCOVTST","EN",3)="1:0:0:0:70"
+^ZZCOVERAGE("ZZCOVTST","EN",4)="1:0:0:0:74"
+^ZZCOVERAGE("ZZCOVTST","EN",5)="1:0:0:0:66"
+^ZZCOVERAGE("ZZCOVTST","EN",6)="1:0:0:0:40"
+^ZZCOVERAGE("ZZCOVTST","%")="2:0:0:0:208"
+^ZZCOVERAGE("ZZCOVTST","%",1)="2:0:0:0:208"
+^ZZCOVERAGE("ZZCOVTST","%",2)="2:0:0:0:208"
+^ZZCOVERAGE("ZZCOVTST","T1")="1:0:0:0:208"
+^ZZCOVERAGE("ZZCOVTST","T1",1)="1:0:0:0:23"
+^ZZCOVERAGE("ZZCOVTST","T1",2)="1:0:0:0:24"
+^ZZCOVERAGE("ZZCOVTST","T1",3)="1:0:0:0:26"
+^ZZCOVERAGE("ZZCOVTST","T1",4)="1:0:0:0:73"
+^ZZCOVERAGE("ZZCOVTST","T1",5)="1:0:0:0:40"
+^ZZCOVERAGE("ZZCOVTST","T2")="1:0:0:0:1783"
+^ZZCOVERAGE("ZZCOVTST","T2",0)="1:0:0:0:25"
+^ZZCOVERAGE("ZZCOVTST","T2",1)="1:0:0:0:524"
+^ZZCOVERAGE("ZZCOVTST","T2",2)="1:0:0:0:40"
+^ZZCOVERAGE("ZZCOVTST","T2",3)="1:0:0:0:95"
+^ZZCOVERAGE("ZZCOVTST","T2",4)="1:0:0:0:607"
+^ZZCOVERAGE("ZZCOVTST","T2",5)="1:0:0:0:470"
+^ZZCOVERAGE("ZZCOVTST","T3")="1:0:0:0:254"
+^ZZCOVERAGE("ZZCOVTST","T3",0)="1:0:0:0:76"
+^ZZCOVERAGE("ZZCOVTST","T5")="1:0:0:0:153"
+^ZZCOVERAGE("ZZCOVTST","T5",0)="1:0:0:0:40"
+^ZZCOVERAGE("ZZCOVTST","T5",1)="1:0:0:0:41"
+^ZZCOVERAGE("ZZCOVTST","T5",2)="1:0:0:0:41"
+^ZZCOVERAGE("ZZCOVTST","T6")="1:0:0:0:227"
+^ZZCOVERAGE("ZZCOVTST","T6",1)="1:0:0:0:41"
+^ZZCOVERAGE("ZZCOVTST","T6",2)="1:0:0:0:42"
+^ZZCOVERAGE("ZZCOVTST","T6",4)="1:0:0:0:41"
+^ZZCOVERAGE("ZZCOVTST","T6",5)="1:0:0:0:34"
+^ZZCOVERAGE("ZZCOVTST","T6",6)="1:0:0:0:38"
+
+
diff --git a/Tests/MumpsCoverage/cache_coverage.cmcov.in b/Tests/MumpsCoverage/cache_coverage.cmcov.in
new file mode 100644
index 0000000..b431dbd
--- /dev/null
+++ b/Tests/MumpsCoverage/cache_coverage.cmcov.in
@@ -0,0 +1,2 @@
+packages:${CMake_BINARY_DIR}/Testing/MumpsCoverage/VistA-FOIA/Packages
+coverage_dir:${CMake_SOURCE_DIR}/Tests/MumpsCoverage
diff --git a/Tests/MumpsCoverage/gtm_coverage.mcov.in b/Tests/MumpsCoverage/gtm_coverage.mcov.in
new file mode 100644
index 0000000..b431dbd
--- /dev/null
+++ b/Tests/MumpsCoverage/gtm_coverage.mcov.in
@@ -0,0 +1,2 @@
+packages:${CMake_BINARY_DIR}/Testing/MumpsCoverage/VistA-FOIA/Packages
+coverage_dir:${CMake_SOURCE_DIR}/Tests/MumpsCoverage
diff --git a/Tests/NewlineArgs/CMakeLists.txt b/Tests/NewlineArgs/CMakeLists.txt
new file mode 100644
index 0000000..3e4b436
--- /dev/null
+++ b/Tests/NewlineArgs/CMakeLists.txt
@@ -0,0 +1,16 @@
+# a simple CXX only test case
+cmake_minimum_required (VERSION 2.8.12)
+project (NewlineArgs CXX)
+
+add_definitions("-DTEST_FLAG_1
+-DTEST_FLAG_2")
+
+include_directories(" ${NewlineArgs_BINARY_DIR}
+ ${NewlineArgs_SOURCE_DIR} ")
+
+configure_file("${NewlineArgs_SOURCE_DIR}/libcxx2.h.in"
+ "${NewlineArgs_BINARY_DIR}/libcxx2.h")
+
+add_library(testcxx1 libcxx1.cxx)
+add_executable (NewlineArgs cxxonly.cxx)
+target_link_libraries(NewlineArgs testcxx1)
diff --git a/Tests/NewlineArgs/cxxonly.cxx b/Tests/NewlineArgs/cxxonly.cxx
new file mode 100644
index 0000000..33b26dc
--- /dev/null
+++ b/Tests/NewlineArgs/cxxonly.cxx
@@ -0,0 +1,18 @@
+#include <stdio.h>
+
+#include "libcxx1.h"
+#include "libcxx2.h"
+
+int main()
+{
+ if (LibCxx1Class::Method() != 2.0) {
+ printf("Problem with libcxx1\n");
+ return 1;
+ }
+#ifdef TEST_FLAG_3
+ return 0;
+#else
+ printf("Problem with libcxx2.h include dir probably!\n");
+ return 1;
+#endif
+}
diff --git a/Tests/NewlineArgs/libcxx1.cxx b/Tests/NewlineArgs/libcxx1.cxx
new file mode 100644
index 0000000..b3c2192
--- /dev/null
+++ b/Tests/NewlineArgs/libcxx1.cxx
@@ -0,0 +1,10 @@
+#include "libcxx1.h"
+
+#ifdef TEST_FLAG_1
+# ifdef TEST_FLAG_2
+float LibCxx1Class::Method()
+{
+ return 2.0;
+}
+# endif
+#endif
diff --git a/Tests/NewlineArgs/libcxx1.h b/Tests/NewlineArgs/libcxx1.h
new file mode 100644
index 0000000..8bb09cd
--- /dev/null
+++ b/Tests/NewlineArgs/libcxx1.h
@@ -0,0 +1,9 @@
+class LibCxx1Class
+{
+public:
+#ifdef TEST_FLAG_1
+# ifdef TEST_FLAG_2
+ static float Method();
+# endif
+#endif
+};
diff --git a/Tests/NewlineArgs/libcxx2.h.in b/Tests/NewlineArgs/libcxx2.h.in
new file mode 100644
index 0000000..bdf9cfa
--- /dev/null
+++ b/Tests/NewlineArgs/libcxx2.h.in
@@ -0,0 +1,6 @@
+#ifdef TEST_FLAG_1
+#ifdef TEST_FLAG_2
+#define TEST_FLAG_3
+#endif
+#endif
+
diff --git a/Tests/ObjC/CMakeLists.txt b/Tests/ObjC/CMakeLists.txt
new file mode 100644
index 0000000..ce3033c
--- /dev/null
+++ b/Tests/ObjC/CMakeLists.txt
@@ -0,0 +1,4 @@
+ADD_TEST_MACRO(ObjC.simple-build-test simple-build-test)
+ADD_TEST_MACRO(ObjC.c-file-extension-test c-file-extension-test)
+ADD_TEST_MACRO(ObjC.cxx-file-extension-test cxx-file-extension-test)
+ADD_TEST_MACRO(ObjC.objc-file-extension-test objc-file-extension-test)
diff --git a/Tests/ObjC/c-file-extension-test/CMakeLists.txt b/Tests/ObjC/c-file-extension-test/CMakeLists.txt
new file mode 100644
index 0000000..e091448
--- /dev/null
+++ b/Tests/ObjC/c-file-extension-test/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.15)
+
+project(c-file-extension-test C)
+
+add_executable(c-file-extension-test main.m)
diff --git a/Tests/ObjC/c-file-extension-test/main.m b/Tests/ObjC/c-file-extension-test/main.m
new file mode 100644
index 0000000..1c159a9
--- /dev/null
+++ b/Tests/ObjC/c-file-extension-test/main.m
@@ -0,0 +1,8 @@
+#ifndef __OBJC__
+# error "Compiler cannot compile Objective-C"
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/ObjC/cxx-file-extension-test/CMakeLists.txt b/Tests/ObjC/cxx-file-extension-test/CMakeLists.txt
new file mode 100644
index 0000000..eb065e4
--- /dev/null
+++ b/Tests/ObjC/cxx-file-extension-test/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.15)
+
+project(cxx-file-extension-test)
+
+string(APPEND CMAKE_CXX_FLAGS " -std=c++11")
+set(CMAKE_CXX_STANDARD 14)
+
+add_executable(cxx-file-extension-test main.m)
diff --git a/Tests/ObjC/cxx-file-extension-test/main.m b/Tests/ObjC/cxx-file-extension-test/main.m
new file mode 100644
index 0000000..1c159a9
--- /dev/null
+++ b/Tests/ObjC/cxx-file-extension-test/main.m
@@ -0,0 +1,8 @@
+#ifndef __OBJC__
+# error "Compiler cannot compile Objective-C"
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/ObjC/objc-file-extension-test/CMakeLists.txt b/Tests/ObjC/objc-file-extension-test/CMakeLists.txt
new file mode 100644
index 0000000..27e88be
--- /dev/null
+++ b/Tests/ObjC/objc-file-extension-test/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.15)
+
+project(objc-file-extension-test OBJC CXX)
+
+add_executable(objc-file-extension-test main.m)
+target_link_libraries(objc-file-extension-test "-framework Foundation")
diff --git a/Tests/ObjC/objc-file-extension-test/main.m b/Tests/ObjC/objc-file-extension-test/main.m
new file mode 100644
index 0000000..2ec3917
--- /dev/null
+++ b/Tests/ObjC/objc-file-extension-test/main.m
@@ -0,0 +1,12 @@
+#ifndef __OBJC__
+# error "Compiler is not an Objective-C compiler."
+#endif
+
+#import <Foundation/Foundation.h>
+
+int main()
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [pool release];
+ return 0;
+}
diff --git a/Tests/ObjC/simple-build-test/CMakeLists.txt b/Tests/ObjC/simple-build-test/CMakeLists.txt
new file mode 100644
index 0000000..5ab46ac
--- /dev/null
+++ b/Tests/ObjC/simple-build-test/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.15)
+
+set(CMAKE_MACOSX_RPATH OFF)
+
+project(simple-build-test OBJC)
+
+add_library(foo SHARED foo.m)
+target_link_libraries(foo "-framework Foundation")
+
+add_executable(simple-build-test main.m)
+target_link_libraries(simple-build-test "-framework Foundation" foo)
diff --git a/Tests/ObjC/simple-build-test/foo.h b/Tests/ObjC/simple-build-test/foo.h
new file mode 100644
index 0000000..b3fb084
--- /dev/null
+++ b/Tests/ObjC/simple-build-test/foo.h
@@ -0,0 +1,9 @@
+#import <Foundation/Foundation.h>
+
+@interface Foo : NSObject {
+ NSNumber* age;
+}
+
+@property (nonatomic, retain) NSNumber* age;
+
+@end
diff --git a/Tests/ObjC/simple-build-test/foo.m b/Tests/ObjC/simple-build-test/foo.m
new file mode 100644
index 0000000..2d452a8
--- /dev/null
+++ b/Tests/ObjC/simple-build-test/foo.m
@@ -0,0 +1,7 @@
+#import "foo.h"
+
+@implementation Foo
+
+@synthesize age;
+
+@end
diff --git a/Tests/ObjC/simple-build-test/main.m b/Tests/ObjC/simple-build-test/main.m
new file mode 100644
index 0000000..970d554
--- /dev/null
+++ b/Tests/ObjC/simple-build-test/main.m
@@ -0,0 +1,12 @@
+#import <Foundation/Foundation.h>
+#import "foo.h"
+
+int main(int argc, char **argv)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ Foo *theFoo = [[Foo alloc] init];
+ theFoo.age = [NSNumber numberWithInt:argc];
+ NSLog(@"%d\n",[theFoo.age intValue]);
+ [pool release];
+ return 0;
+}
diff --git a/Tests/ObjCXX/CMakeLists.txt b/Tests/ObjCXX/CMakeLists.txt
new file mode 100644
index 0000000..cf03771
--- /dev/null
+++ b/Tests/ObjCXX/CMakeLists.txt
@@ -0,0 +1,5 @@
+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/ObjC++/CMakeLists.txt b/Tests/ObjCXX/ObjC++/CMakeLists.txt
new file mode 100644
index 0000000..5ba5db2
--- /dev/null
+++ b/Tests/ObjCXX/ObjC++/CMakeLists.txt
@@ -0,0 +1,5 @@
+# a simple objc++ test case that uses Cocoa framework
+project (ObjC++)
+
+add_executable (ObjC++ objc++.mm)
+target_link_libraries(ObjC++ "-framework Cocoa")
diff --git a/Tests/ObjCXX/ObjC++/objc++.mm b/Tests/ObjCXX/ObjC++/objc++.mm
new file mode 100644
index 0000000..258ebaa
--- /dev/null
+++ b/Tests/ObjCXX/ObjC++/objc++.mm
@@ -0,0 +1,23 @@
+#import <Cocoa/Cocoa.h>
+#import <iostream>
+using namespace std;
+
+int main()
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSMutableSet *mySet = [NSMutableSet set];
+ cout<<"Adding values to the set."<<endl;
+ [mySet addObject:[NSNumber numberWithInt:356]];
+ [mySet addObject:[NSNumber numberWithInt:550]];
+ [mySet addObject:[NSNumber numberWithInt:914]];
+
+ cout<<"The set contains "<<[mySet count]<<" objects."<<endl;
+ if ([mySet containsObject:[NSNumber numberWithInt:911]])
+ cout<<"It's there!"<<endl;
+ else
+ cout<<"It's not there."<<endl;
+
+ [pool release];
+ return 0;
+}
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/ObjCXX/cxx-file-extension-test/CMakeLists.txt b/Tests/ObjCXX/cxx-file-extension-test/CMakeLists.txt
new file mode 100644
index 0000000..0b33875
--- /dev/null
+++ b/Tests/ObjCXX/cxx-file-extension-test/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.15)
+
+project(cxx-file-extension-test CXX)
+
+add_executable(cxx-file-extension-test main.mm)
diff --git a/Tests/ObjCXX/cxx-file-extension-test/main.mm b/Tests/ObjCXX/cxx-file-extension-test/main.mm
new file mode 100644
index 0000000..1c159a9
--- /dev/null
+++ b/Tests/ObjCXX/cxx-file-extension-test/main.mm
@@ -0,0 +1,8 @@
+#ifndef __OBJC__
+# error "Compiler cannot compile Objective-C"
+#endif
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/ObjCXX/objcxx-file-extension-test/CMakeLists.txt b/Tests/ObjCXX/objcxx-file-extension-test/CMakeLists.txt
new file mode 100644
index 0000000..eda7bba
--- /dev/null
+++ b/Tests/ObjCXX/objcxx-file-extension-test/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.15)
+
+project(objcxx-file-extension-test OBJCXX CXX)
+
+add_executable(objcxx-file-extension-test main.mm)
+target_link_libraries(objcxx-file-extension-test "-framework Foundation")
diff --git a/Tests/ObjCXX/objcxx-file-extension-test/main.mm b/Tests/ObjCXX/objcxx-file-extension-test/main.mm
new file mode 100644
index 0000000..d4aa1bb
--- /dev/null
+++ b/Tests/ObjCXX/objcxx-file-extension-test/main.mm
@@ -0,0 +1,14 @@
+#ifndef __OBJC__
+# error "Compiler is not an Objective-C compiler."
+#endif
+
+#import <Foundation/Foundation.h>
+#include <iostream>
+
+int main()
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ std::cout << "Hello World" << std::endl;
+ [pool release];
+ return 0;
+}
diff --git a/Tests/ObjCXX/simple-build-test/CMakeLists.txt b/Tests/ObjCXX/simple-build-test/CMakeLists.txt
new file mode 100644
index 0000000..cf27683
--- /dev/null
+++ b/Tests/ObjCXX/simple-build-test/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.15)
+
+set(CMAKE_MACOSX_RPATH OFF)
+
+project(simple-build-test OBJCXX)
+
+add_library(foo SHARED foo.mm)
+target_link_libraries(foo "-framework Foundation")
+
+add_executable(simple-build-test main.mm)
+target_link_libraries(simple-build-test "-framework Foundation" foo)
diff --git a/Tests/ObjCXX/simple-build-test/foo.h b/Tests/ObjCXX/simple-build-test/foo.h
new file mode 100644
index 0000000..b3fb084
--- /dev/null
+++ b/Tests/ObjCXX/simple-build-test/foo.h
@@ -0,0 +1,9 @@
+#import <Foundation/Foundation.h>
+
+@interface Foo : NSObject {
+ NSNumber* age;
+}
+
+@property (nonatomic, retain) NSNumber* age;
+
+@end
diff --git a/Tests/ObjCXX/simple-build-test/foo.mm b/Tests/ObjCXX/simple-build-test/foo.mm
new file mode 100644
index 0000000..2d452a8
--- /dev/null
+++ b/Tests/ObjCXX/simple-build-test/foo.mm
@@ -0,0 +1,7 @@
+#import "foo.h"
+
+@implementation Foo
+
+@synthesize age;
+
+@end
diff --git a/Tests/ObjCXX/simple-build-test/main.mm b/Tests/ObjCXX/simple-build-test/main.mm
new file mode 100644
index 0000000..7c85551
--- /dev/null
+++ b/Tests/ObjCXX/simple-build-test/main.mm
@@ -0,0 +1,14 @@
+#import <Foundation/Foundation.h>
+#import "foo.h"
+#include <iostream>
+
+int main(int argc, char **argv)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ Foo *theFoo = [[Foo alloc] init];
+ theFoo.age = [NSNumber numberWithInt:argc];
+ NSLog(@"%d\n",[theFoo.age intValue]);
+ std::cout << [theFoo.age intValue] << std::endl;
+ [pool release];
+ return 0;
+}
diff --git a/Tests/ObjectLibrary/A/CMakeLists.txt b/Tests/ObjectLibrary/A/CMakeLists.txt
new file mode 100644
index 0000000..c185d75
--- /dev/null
+++ b/Tests/ObjectLibrary/A/CMakeLists.txt
@@ -0,0 +1,24 @@
+project(ObjectLibraryA C)
+# Add -fPIC so objects can be used in shared libraries.
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+add_definitions(-DA_DEF)
+
+add_custom_command(
+ OUTPUT a1.c
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/a1.c.in
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/a1.c.in
+ ${CMAKE_CURRENT_BINARY_DIR}/a1.c
+ )
+
+# Remove the custom command output to be sure it runs in an
+# incremental test.
+file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/a.cmake)
+add_custom_command(
+ OUTPUT a.cmake
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/a.cmake
+ )
+
+add_library(A OBJECT a1.c a2.c a.cmake)
+target_include_directories(A PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+set_property(TARGET A PROPERTY COMPILE_PDB_NAME Apdb)
diff --git a/Tests/ObjectLibrary/A/a.h b/Tests/ObjectLibrary/A/a.h
new file mode 100644
index 0000000..184df3c
--- /dev/null
+++ b/Tests/ObjectLibrary/A/a.h
@@ -0,0 +1,6 @@
+#ifndef A_DEF
+# error "A_DEF not defined"
+#endif
+#ifdef B_DEF
+# error "B_DEF must not be defined"
+#endif
diff --git a/Tests/ObjectLibrary/A/a1.c.in b/Tests/ObjectLibrary/A/a1.c.in
new file mode 100644
index 0000000..d1eaf58
--- /dev/null
+++ b/Tests/ObjectLibrary/A/a1.c.in
@@ -0,0 +1,2 @@
+#include "a.h"
+int a1(void) { return 0; }
diff --git a/Tests/ObjectLibrary/A/a2.c b/Tests/ObjectLibrary/A/a2.c
new file mode 100644
index 0000000..fbb0c02
--- /dev/null
+++ b/Tests/ObjectLibrary/A/a2.c
@@ -0,0 +1,5 @@
+#include "a.h"
+int a2(void)
+{
+ return 0;
+}
diff --git a/Tests/ObjectLibrary/AB.def b/Tests/ObjectLibrary/AB.def
new file mode 100644
index 0000000..3f2b5c0
--- /dev/null
+++ b/Tests/ObjectLibrary/AB.def
@@ -0,0 +1,5 @@
+EXPORTS
+a1
+a2
+b1
+b2
diff --git a/Tests/ObjectLibrary/B/CMakeLists.txt b/Tests/ObjectLibrary/B/CMakeLists.txt
new file mode 100644
index 0000000..ecace4f
--- /dev/null
+++ b/Tests/ObjectLibrary/B/CMakeLists.txt
@@ -0,0 +1,13 @@
+project(ObjectLibraryB C)
+
+# Add -fPIC so objects can be used in shared libraries.
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+add_library(B OBJECT b1.c b2.c)
+target_include_directories(B PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+target_compile_definitions(B PUBLIC B_DEF)
+
+add_library(Bexport OBJECT b1.c b2.c)
+set_property(TARGET Bexport PROPERTY COMPILE_DEFINITIONS Bexport)
+target_include_directories(Bexport PRIVATE $<TARGET_PROPERTY:B,INTERFACE_INCLUDE_DIRECTORIES>)
+target_compile_definitions(Bexport PRIVATE $<TARGET_PROPERTY:B,INTERFACE_COMPILE_DEFINITIONS>)
diff --git a/Tests/ObjectLibrary/B/b.h b/Tests/ObjectLibrary/B/b.h
new file mode 100644
index 0000000..de81d69
--- /dev/null
+++ b/Tests/ObjectLibrary/B/b.h
@@ -0,0 +1,18 @@
+#ifdef A_DEF
+# error "A_DEF must not be defined"
+#endif
+#ifndef B_DEF
+# error "B_DEF not defined"
+#endif
+
+#if defined(_WIN32) && defined(Bexport)
+# define EXPORT_B __declspec(dllexport)
+#else
+# define EXPORT_B
+#endif
+
+#if defined(_WIN32) && defined(SHARED_B)
+# define IMPORT_B __declspec(dllimport)
+#else
+# define IMPORT_B
+#endif
diff --git a/Tests/ObjectLibrary/B/b1.c b/Tests/ObjectLibrary/B/b1.c
new file mode 100644
index 0000000..d804d43
--- /dev/null
+++ b/Tests/ObjectLibrary/B/b1.c
@@ -0,0 +1,5 @@
+#include "b.h"
+EXPORT_B int b1(void)
+{
+ return 0;
+}
diff --git a/Tests/ObjectLibrary/B/b2.c b/Tests/ObjectLibrary/B/b2.c
new file mode 100644
index 0000000..4615b54
--- /dev/null
+++ b/Tests/ObjectLibrary/B/b2.c
@@ -0,0 +1,5 @@
+#include "b.h"
+EXPORT_B int b2(void)
+{
+ return 0;
+}
diff --git a/Tests/ObjectLibrary/CMakeLists.txt b/Tests/ObjectLibrary/CMakeLists.txt
new file mode 100644
index 0000000..74f34e4
--- /dev/null
+++ b/Tests/ObjectLibrary/CMakeLists.txt
@@ -0,0 +1,77 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(ObjectLibrary C)
+
+add_subdirectory(A)
+add_subdirectory(B)
+
+add_library(Cstatic STATIC c.c $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>)
+add_executable(UseCstatic main.c)
+target_link_libraries(UseCstatic Cstatic)
+
+add_library(Cshared SHARED c.c $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:Bexport>)
+add_executable(UseCshared main.c)
+set_property(TARGET UseCshared PROPERTY COMPILE_DEFINITIONS SHARED_C)
+target_link_libraries(UseCshared Cshared)
+add_custom_command(TARGET UseCshared POST_BUILD COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/A/a.cmake)
+
+add_executable(UseCinternal main.c c.c $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>)
+
+if("${CMAKE_GENERATOR}" MATCHES "Xcode")
+ # Xcode does not seem to support targets without sources.
+ set(dummy dummy.c)
+endif()
+
+# Test static library without its own sources.
+add_library(ABstatic STATIC ${dummy} $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>)
+target_include_directories(ABstatic PUBLIC $<TARGET_PROPERTY:B,INTERFACE_INCLUDE_DIRECTORIES>)
+target_compile_definitions(ABstatic PUBLIC $<TARGET_PROPERTY:B,INTERFACE_COMPILE_DEFINITIONS>)
+
+add_executable(UseABstatic mainAB.c)
+target_link_libraries(UseABstatic ABstatic)
+
+# Test module definition file to export object library symbols in the test
+# below if the platform needs and supports it.
+set(ABshared_SRCS $<TARGET_OBJECTS:A>)
+if(CMAKE_LINK_DEF_FILE_FLAG OR NOT WIN32)
+ list(APPEND ABshared_SRCS $<TARGET_OBJECTS:B> AB.def)
+else()
+ set(NO_A NO_A)
+ list(APPEND ABshared_SRCS $<TARGET_OBJECTS:Bexport>)
+endif()
+
+# Test shared library without its own sources.
+add_library(ABshared SHARED ${dummy} ${ABshared_SRCS})
+target_include_directories(ABshared PUBLIC $<TARGET_PROPERTY:B,INTERFACE_INCLUDE_DIRECTORIES>)
+target_compile_definitions(ABshared PUBLIC $<TARGET_PROPERTY:B,INTERFACE_COMPILE_DEFINITIONS>)
+
+add_executable(UseABshared mainAB.c)
+set_property(TARGET UseABshared PROPERTY COMPILE_DEFINITIONS SHARED_B ${NO_A})
+target_link_libraries(UseABshared ABshared)
+
+# Test executable without its own sources.
+add_library(ABmain OBJECT mainAB.c)
+target_include_directories(ABmain PUBLIC $<TARGET_PROPERTY:B,INTERFACE_INCLUDE_DIRECTORIES>)
+target_compile_definitions(ABmain PUBLIC $<TARGET_PROPERTY:B,INTERFACE_COMPILE_DEFINITIONS>)
+add_executable(UseABinternal ${dummy}
+ $<TARGET_OBJECTS:ABmain> $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>
+ )
+
+# Test target-level dependencies of executable without sources.
+file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/UseABinternalDep.cmake)
+add_custom_target(UseABinternalDep COMMAND ${CMAKE_COMMAND} -E touch UseABinternalDep.cmake)
+add_custom_command(TARGET UseABinternal POST_BUILD COMMAND ${CMAKE_COMMAND} -P UseABinternalDep.cmake)
+add_dependencies(UseABinternal UseABinternalDep)
+
+# Test a static library with sources from a different static library
+add_library(UseCstaticObjs STATIC $<TARGET_OBJECTS:Cstatic> $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:Bexport>)
+
+# Test a shared library with sources from a different shared library
+add_library(UseCsharedObjs SHARED $<TARGET_OBJECTS:Cshared> $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:Bexport>)
+
+# Test a shared executable with sources from a different shared library
+add_executable(UseABstaticObjs $<TARGET_OBJECTS:UseABstatic>)
+target_link_libraries(UseABstaticObjs ABstatic)
+
+add_subdirectory(ExportLanguages)
+
+add_subdirectory(Transitive)
diff --git a/Tests/ObjectLibrary/ExportLanguages/CMakeLists.txt b/Tests/ObjectLibrary/ExportLanguages/CMakeLists.txt
new file mode 100644
index 0000000..fb0ebc0
--- /dev/null
+++ b/Tests/ObjectLibrary/ExportLanguages/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(ExportLanguages CXX)
+add_library(ExportLanguagesA OBJECT a.cxx)
+add_library(ExportLanguagesB STATIC a.c $<TARGET_OBJECTS:ExportLanguagesA>)
+
+# Verify that object library languages are propagated.
+export(TARGETS ExportLanguagesB NAMESPACE Exp FILE BExport.cmake)
+include(ExternalProject)
+ExternalProject_Add(ExportLanguagesTest
+ SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ExportLanguagesTest"
+ BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/ExportLanguagesTest"
+ DOWNLOAD_COMMAND ""
+ INSTALL_COMMAND ""
+)
+add_dependencies(ExportLanguagesTest ExportLanguagesA ExportLanguagesB)
diff --git a/Tests/ObjectLibrary/ExportLanguages/ExportLanguagesTest/CMakeLists.txt b/Tests/ObjectLibrary/ExportLanguages/ExportLanguagesTest/CMakeLists.txt
new file mode 100644
index 0000000..8544798
--- /dev/null
+++ b/Tests/ObjectLibrary/ExportLanguages/ExportLanguagesTest/CMakeLists.txt
@@ -0,0 +1,14 @@
+
+cmake_minimum_required(VERSION 2.8.12)
+
+project(ExportLanguagesTest)
+
+include(${CMAKE_CURRENT_BINARY_DIR}/../BExport.cmake)
+get_property(configs TARGET ExpExportLanguagesB PROPERTY IMPORTED_CONFIGURATIONS)
+foreach(c ${configs})
+ get_property(langs TARGET ExpExportLanguagesB PROPERTY IMPORTED_LINK_INTERFACE_LANGUAGES_${c})
+ list(FIND langs CXX pos)
+ if(${pos} LESS 0)
+ message(FATAL_ERROR "Target export does not list object library languages.")
+ endif()
+endforeach()
diff --git a/Tests/ObjectLibrary/ExportLanguages/a.c b/Tests/ObjectLibrary/ExportLanguages/a.c
new file mode 100644
index 0000000..1636303
--- /dev/null
+++ b/Tests/ObjectLibrary/ExportLanguages/a.c
@@ -0,0 +1,4 @@
+int a(void)
+{
+ return 0;
+}
diff --git a/Tests/ObjectLibrary/ExportLanguages/a.cxx b/Tests/ObjectLibrary/ExportLanguages/a.cxx
new file mode 100644
index 0000000..c661b94
--- /dev/null
+++ b/Tests/ObjectLibrary/ExportLanguages/a.cxx
@@ -0,0 +1,4 @@
+extern "C" int acxx(void)
+{
+ return 0;
+}
diff --git a/Tests/ObjectLibrary/Transitive/CMakeLists.txt b/Tests/ObjectLibrary/Transitive/CMakeLists.txt
new file mode 100644
index 0000000..d616cda
--- /dev/null
+++ b/Tests/ObjectLibrary/Transitive/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_policy(SET CMP0022 NEW)
+add_library(FooStatic STATIC FooStatic.c)
+
+add_library(FooObject1 OBJECT FooObject.c)
+target_link_libraries(FooObject1 PRIVATE FooStatic)
+add_executable(Transitive1 Transitive.c)
+target_link_libraries(Transitive1 PRIVATE FooObject1)
+
+add_library(FooObject2 OBJECT FooObject.c)
+target_link_libraries(FooObject2 INTERFACE FooStatic)
+add_executable(Transitive2 Transitive.c)
+target_link_libraries(Transitive2 PRIVATE FooObject2)
diff --git a/Tests/ObjectLibrary/Transitive/FooObject.c b/Tests/ObjectLibrary/Transitive/FooObject.c
new file mode 100644
index 0000000..54c1f29
--- /dev/null
+++ b/Tests/ObjectLibrary/Transitive/FooObject.c
@@ -0,0 +1,4 @@
+int FooObject(void)
+{
+ return 0;
+}
diff --git a/Tests/ObjectLibrary/Transitive/FooStatic.c b/Tests/ObjectLibrary/Transitive/FooStatic.c
new file mode 100644
index 0000000..84649c7
--- /dev/null
+++ b/Tests/ObjectLibrary/Transitive/FooStatic.c
@@ -0,0 +1,4 @@
+int FooStatic(void)
+{
+ return 0;
+}
diff --git a/Tests/ObjectLibrary/Transitive/Transitive.c b/Tests/ObjectLibrary/Transitive/Transitive.c
new file mode 100644
index 0000000..43089b8
--- /dev/null
+++ b/Tests/ObjectLibrary/Transitive/Transitive.c
@@ -0,0 +1,7 @@
+extern int FooObject(void);
+extern int FooStatic(void);
+
+int main(void)
+{
+ return FooObject() + FooStatic();
+}
diff --git a/Tests/ObjectLibrary/c.c b/Tests/ObjectLibrary/c.c
new file mode 100644
index 0000000..2692899
--- /dev/null
+++ b/Tests/ObjectLibrary/c.c
@@ -0,0 +1,14 @@
+#if defined(_WIN32) && defined(Cshared_EXPORTS)
+# define EXPORT_C __declspec(dllexport)
+#else
+# define EXPORT_C
+#endif
+
+extern int a1(void);
+extern int a2(void);
+extern int b1(void);
+extern int b2(void);
+EXPORT_C int c(void)
+{
+ return 0 + a1() + a2() + b1() + b2();
+}
diff --git a/Tests/ObjectLibrary/dummy.c b/Tests/ObjectLibrary/dummy.c
new file mode 100644
index 0000000..3983c6a
--- /dev/null
+++ b/Tests/ObjectLibrary/dummy.c
@@ -0,0 +1,4 @@
+int dummy(void)
+{
+ return 0;
+}
diff --git a/Tests/ObjectLibrary/dummy.obj b/Tests/ObjectLibrary/dummy.obj
new file mode 100644
index 0000000..77f6f2f
--- /dev/null
+++ b/Tests/ObjectLibrary/dummy.obj
Binary files differ
diff --git a/Tests/ObjectLibrary/main.c b/Tests/ObjectLibrary/main.c
new file mode 100644
index 0000000..cc75685
--- /dev/null
+++ b/Tests/ObjectLibrary/main.c
@@ -0,0 +1,12 @@
+#if defined(_WIN32) && defined(SHARED_C)
+# define IMPORT_C __declspec(dllimport)
+#else
+# define IMPORT_C
+#endif
+extern IMPORT_C int b1(void);
+extern IMPORT_C int b2(void);
+extern IMPORT_C int c(void);
+int main(void)
+{
+ return 0 + c() + b1() + b2();
+}
diff --git a/Tests/ObjectLibrary/mainAB.c b/Tests/ObjectLibrary/mainAB.c
new file mode 100644
index 0000000..a7aa393
--- /dev/null
+++ b/Tests/ObjectLibrary/mainAB.c
@@ -0,0 +1,17 @@
+
+#include "b.h"
+
+extern IMPORT_B int b1(void);
+extern IMPORT_B int b2(void);
+#ifndef NO_A
+extern int a1(void);
+extern int a2(void);
+#endif
+int main(void)
+{
+ return 0
+#ifndef NO_A
+ + a1() + a2()
+#endif
+ + b1() + b2();
+}
diff --git a/Tests/OutDir/CMakeLists.txt b/Tests/OutDir/CMakeLists.txt
new file mode 100644
index 0000000..8afe036
--- /dev/null
+++ b/Tests/OutDir/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 3.9)
+project(OutDir C)
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ foreach(config ${CMAKE_CONFIGURATION_TYPES})
+ string(TOUPPER "${config}" CONFIG)
+ list(APPEND configs "${CONFIG}")
+ endforeach()
+ set(CMAKE_BUILD_TYPE)
+elseif(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Debug)
+endif()
+
+if(CMAKE_BUILD_TYPE)
+ string(TOUPPER "${CMAKE_BUILD_TYPE}" configs)
+endif()
+
+set(top "${OutDir_BINARY_DIR}")
+foreach(config ${configs})
+ foreach(type archive runtime library)
+ string(TOUPPER "${type}" TYPE)
+ set(CMAKE_${TYPE}_OUTPUT_DIRECTORY_${config} "${top}/${type}/$<CONFIG>")
+ file(REMOVE_RECURSE "${top}/${type}")
+ endforeach()
+endforeach()
+
+add_subdirectory(../COnly COnly)
+
+add_custom_command(
+ OUTPUT OutDir.h
+ COMMAND ${CMAKE_COMMAND} -Dtop=${top} -Dcfg_dir=$<CONFIG> -P ${OutDir_SOURCE_DIR}/OutDir.cmake
+ DEPENDS COnly ${OutDir_SOURCE_DIR}/OutDir.cmake
+ )
+include_directories(${top})
+add_executable(OutDir OutDir.c OutDir.h)
diff --git a/Tests/OutDir/OutDir.c b/Tests/OutDir/OutDir.c
new file mode 100644
index 0000000..4f6ae87
--- /dev/null
+++ b/Tests/OutDir/OutDir.c
@@ -0,0 +1,20 @@
+#include <OutDir.h>
+#include <stdio.h>
+
+int main(void)
+{
+ const char* files[] = { TESTC1_LIB, TESTC2_LIB, CONLY_EXE, 0 };
+ int result = 0;
+ const char** fname = files;
+ for (; *fname; ++fname) {
+ FILE* f = fopen(*fname, "rb");
+ if (f) {
+ printf("found: [%s]\n", *fname);
+ fclose(f);
+ } else {
+ printf("error: [%s]\n", *fname);
+ result = 1;
+ }
+ }
+ return result;
+}
diff --git a/Tests/OutDir/OutDir.cmake b/Tests/OutDir/OutDir.cmake
new file mode 100644
index 0000000..2a003b8
--- /dev/null
+++ b/Tests/OutDir/OutDir.cmake
@@ -0,0 +1,32 @@
+set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".a" ".so" ".sl" ".dylib" ".dll.a")
+
+find_library(TESTC1_LIB
+ NAMES testc1 testc1_test_debug_postfix
+ PATHS ${top}/archive/${cfg_dir}
+ NO_DEFAULT_PATH)
+
+find_library(TESTC2_LIB
+ NAMES testc2 testc2_test_debug_postfix
+ PATHS ${top}/archive/${cfg_dir} ${top}/library/${cfg_dir}
+ NO_DEFAULT_PATH)
+
+find_program(CONLY_EXE
+ NAMES COnly
+ PATHS ${top}/runtime/${cfg_dir}
+ NO_DEFAULT_PATH)
+
+file(RELATIVE_PATH TESTC1_LIB_FILE "${top}" "${TESTC1_LIB}")
+file(RELATIVE_PATH TESTC2_LIB_FILE "${top}" "${TESTC2_LIB}")
+file(RELATIVE_PATH CONLY_EXE_FILE "${top}" "${CONLY_EXE}")
+
+file(WRITE ${top}/OutDir.h "/* Generated by ${CMAKE_CURRENT_LIST_FILE} */
+#ifndef OutDir_h
+#define OutDir_h
+
+#define TESTC1_LIB \"${TESTC1_LIB_FILE}\"
+#define TESTC2_LIB \"${TESTC2_LIB_FILE}\"
+#define CONLY_EXE \"${CONLY_EXE_FILE}\"
+
+#endif
+")
diff --git a/Tests/OutName/CMakeLists.txt b/Tests/OutName/CMakeLists.txt
new file mode 100644
index 0000000..f024def
--- /dev/null
+++ b/Tests/OutName/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.12)
+project(OutName C)
+
+add_executable(OutName main.c)
+set_property(TARGET OutName PROPERTY PREFIX exe.)
+set_property(TARGET OutName PROPERTY SUFFIX .exe)
diff --git a/Tests/OutName/main.c b/Tests/OutName/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/OutName/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/OutOfBinary/CMakeLists.txt b/Tests/OutOfBinary/CMakeLists.txt
new file mode 100644
index 0000000..f50536e
--- /dev/null
+++ b/Tests/OutOfBinary/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library(outlib outlib.c)
+
+add_executable(outexe outexe.c)
+target_link_libraries(outexe subdir)
diff --git a/Tests/OutOfBinary/outexe.c b/Tests/OutOfBinary/outexe.c
new file mode 100644
index 0000000..4170d97
--- /dev/null
+++ b/Tests/OutOfBinary/outexe.c
@@ -0,0 +1,5 @@
+extern int subdir(void);
+int main(void)
+{
+ return subdir();
+}
diff --git a/Tests/OutOfBinary/outlib.c b/Tests/OutOfBinary/outlib.c
new file mode 100644
index 0000000..d309ebe
--- /dev/null
+++ b/Tests/OutOfBinary/outlib.c
@@ -0,0 +1,4 @@
+int outlib()
+{
+ return 456;
+}
diff --git a/Tests/OutOfSource/CMakeLists.txt b/Tests/OutOfSource/CMakeLists.txt
new file mode 100644
index 0000000..4687882
--- /dev/null
+++ b/Tests/OutOfSource/CMakeLists.txt
@@ -0,0 +1,18 @@
+# a simple test case
+cmake_minimum_required (VERSION 2.6)
+project (OutOfSource)
+
+add_subdirectory(SubDir)
+
+get_directory_property(ANIMAL DIRECTORY OutOfSourceSubdir DEFINITION WEASELS)
+get_directory_property(ANIMALREL DIRECTORY SubDir/../OutOfSourceSubdir DEFINITION WEASELS)
+if(NOT "${ANIMAL}" STREQUAL "${ANIMALREL}")
+ message(FATAL_ERROR "GET_DIRECTORY_PROPERTY does not seem to collapse paths.")
+endif()
+
+configure_file(
+ ${OutOfSource_SOURCE_DIR}/testdp.h.in
+ ${OutOfSource_BINARY_DIR}/SubDir/OutOfSourceSubdir/testdp.h
+ )
+
+set(KEN 1)
diff --git a/Tests/OutOfSource/OutOfSourceSubdir/CMakeLists.txt b/Tests/OutOfSource/OutOfSourceSubdir/CMakeLists.txt
new file mode 100644
index 0000000..76a93d2
--- /dev/null
+++ b/Tests/OutOfSource/OutOfSourceSubdir/CMakeLists.txt
@@ -0,0 +1,62 @@
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+if ("${PROJECT_SOURCE_DIR}" STREQUAL "${ANOTHER_PROJ_SOURCE_DIR}")
+ set(BUILD_SHARED_LIBS 1)
+
+ # Construct a source file outside the tree whose full path is close to
+ # the path length limit. This will cause the full path to the object
+ # file in the build tree to exceed the maximum path length which will
+ # test cmLocalGenerator::CreateSafeUniqueObjectFileName.
+ get_filename_component(DEEPDIR
+ ${OutOfSource_BINARY_DIR}/../OutOfSourceDeep/deeper ABSOLUTE)
+
+ # Test giving the generator a custom limit.
+ set(CMAKE_OBJECT_PATH_MAX 220)
+
+ # Use a separate variable for computation.
+ set(MAXPATH "${CMAKE_OBJECT_PATH_MAX}")
+
+ # VS adds "OutOfSource/SubDir/OutOfSourceSubdir/../../../" to the
+ # path of the source file for no good reason. Reduce the length
+ # limit by 46 characters to account for it. It should still be long
+ # enough to require special object file name conversion.
+ if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
+ math(EXPR MAXPATH "${MAXPATH} - 46")
+ endif()
+
+ # Ninja imposes a maximum path component count of 30. Permit more
+ # path components in the source path.
+ if(${CMAKE_GENERATOR} MATCHES "Ninja")
+ math(EXPR MAXPATH "${MAXPATH} - 44")
+ endif()
+
+ # MAXPATH less 25 for last /and/deeper/simple.cxx part and small safety
+ math(EXPR MAXPATH "${MAXPATH} - 25")
+ string(LENGTH "${DEEPDIR}" DEEPDIR_LEN)
+ while("${DEEPDIR_LEN}" LESS "${MAXPATH}")
+ set(DEEPDIR ${DEEPDIR}/and/deeper)
+ string(LENGTH "${DEEPDIR}" DEEPDIR_LEN)
+ endwhile()
+ set(DEEPSRC ${DEEPDIR}/simple.cxx)
+ string(LENGTH "${DEEPSRC}" DEEPSRC_LEN)
+ configure_file(simple.cxx.in ${DEEPSRC} COPYONLY)
+
+ # Watcom WMake seems to have problems with long command lines. Just
+ # disable this part of the test until it is resolved.
+ if(${CMAKE_GENERATOR} MATCHES "Watcom WMake")
+ set(DEEPSRC "")
+ add_definitions(-DNO_DEEPSRC)
+ endif()
+
+ add_library(testlib testlib.cxx)
+ add_executable (simple simple.cxx ../simple.cxx ${DEEPSRC})
+ target_link_libraries(simple testlib outlib)
+endif ()
+
+# test getting a definition from a subdir
+set (WEASELS SIZZLING)
+
+get_directory_property(incDirs INCLUDE_DIRECTORIES)
+if(NOT incDirs)
+ message(FATAL_ERROR "get_directory_property(INCLUDE_DIRECTORIES) returned empty list")
+endif()
diff --git a/Tests/OutOfSource/OutOfSourceSubdir/simple.cxx b/Tests/OutOfSource/OutOfSourceSubdir/simple.cxx
new file mode 100644
index 0000000..12cbd1a
--- /dev/null
+++ b/Tests/OutOfSource/OutOfSourceSubdir/simple.cxx
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "testdp.h"
+#include "testlib.h"
+
+extern int simple();
+#ifndef NO_DEEPSRC
+extern int simple2();
+#endif
+extern "C" int outlib();
+
+int main()
+{
+ if (simple() != 123) {
+ return -3;
+ }
+ if (strcmp(animal, "SIZZLING")) {
+ fprintf(stderr, "Get definitions from a subdir did not work\n");
+ return -2;
+ }
+ if (TestLib() != 1.0) {
+ return -1;
+ }
+ if (outlib() != 456) {
+ return -4;
+ }
+#ifndef NO_DEEPSRC
+ if (simple2() != 789) {
+ return -5;
+ }
+#endif
+ return 0;
+}
diff --git a/Tests/OutOfSource/OutOfSourceSubdir/simple.cxx.in b/Tests/OutOfSource/OutOfSourceSubdir/simple.cxx.in
new file mode 100644
index 0000000..8339b7c
--- /dev/null
+++ b/Tests/OutOfSource/OutOfSourceSubdir/simple.cxx.in
@@ -0,0 +1 @@
+int simple2() { return 789; }
diff --git a/Tests/OutOfSource/OutOfSourceSubdir/testlib.cxx b/Tests/OutOfSource/OutOfSourceSubdir/testlib.cxx
new file mode 100644
index 0000000..1f78bd3
--- /dev/null
+++ b/Tests/OutOfSource/OutOfSourceSubdir/testlib.cxx
@@ -0,0 +1,6 @@
+#include "testlib.h"
+
+float TestLib()
+{
+ return 1.0;
+}
diff --git a/Tests/OutOfSource/OutOfSourceSubdir/testlib.h b/Tests/OutOfSource/OutOfSourceSubdir/testlib.h
new file mode 100644
index 0000000..3e012d2
--- /dev/null
+++ b/Tests/OutOfSource/OutOfSourceSubdir/testlib.h
@@ -0,0 +1,11 @@
+#ifdef _WIN32
+# ifdef testlib_EXPORTS
+# define CM_TEST_LIB_EXPORT __declspec(dllexport)
+# else
+# define CM_TEST_LIB_EXPORT __declspec(dllimport)
+# endif
+#else
+# define CM_TEST_LIB_EXPORT
+#endif
+
+CM_TEST_LIB_EXPORT float TestLib();
diff --git a/Tests/OutOfSource/SubDir/CMakeLists.txt b/Tests/OutOfSource/SubDir/CMakeLists.txt
new file mode 100644
index 0000000..e18dbb9
--- /dev/null
+++ b/Tests/OutOfSource/SubDir/CMakeLists.txt
@@ -0,0 +1,10 @@
+project(ANOTHER_PROJ)
+
+# subdir to an out of source and out of binary directory
+add_subdirectory(${OutOfSource_SOURCE_DIR}/../OutOfBinary
+ ${OutOfSource_BINARY_DIR}/../OutOfBinary)
+
+# subdir to a sibling dir
+add_subdirectory(${OutOfSource_SOURCE_DIR}/${KEN}OutOfSourceSubdir OutOfSourceSubdir )
+
+add_library(subdir subdir.c)
diff --git a/Tests/OutOfSource/SubDir/subdir.c b/Tests/OutOfSource/SubDir/subdir.c
new file mode 100644
index 0000000..abf4e18
--- /dev/null
+++ b/Tests/OutOfSource/SubDir/subdir.c
@@ -0,0 +1,4 @@
+int subdir(void)
+{
+ return 0;
+}
diff --git a/Tests/OutOfSource/simple.cxx b/Tests/OutOfSource/simple.cxx
new file mode 100644
index 0000000..ffe0db9
--- /dev/null
+++ b/Tests/OutOfSource/simple.cxx
@@ -0,0 +1,4 @@
+int simple()
+{
+ return 123;
+}
diff --git a/Tests/OutOfSource/testdp.h.in b/Tests/OutOfSource/testdp.h.in
new file mode 100644
index 0000000..2ca99d5
--- /dev/null
+++ b/Tests/OutOfSource/testdp.h.in
@@ -0,0 +1 @@
+char *animal = "${ANIMAL}";
diff --git a/Tests/PDBDirectoryAndName/CMakeLists.txt b/Tests/PDBDirectoryAndName/CMakeLists.txt
new file mode 100644
index 0000000..5aa2459
--- /dev/null
+++ b/Tests/PDBDirectoryAndName/CMakeLists.txt
@@ -0,0 +1,103 @@
+cmake_minimum_required(VERSION 2.8.12)
+cmake_policy(SET CMP0054 NEW)
+project(PDBDirectoryAndName C)
+
+# Make sure the proper compiler is in use.
+if(NOT MSVC AND NOT CMAKE_C_COMPILER_ID STREQUAL "Intel" AND NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ message(FATAL_ERROR "The PDBDirectoryAndName test works only with MSVC, Clang or Intel")
+endif()
+
+# Intel 11.1 does not support /Fd but Intel 14.0 does.
+# TODO: Did a version in between these add it?
+if((CMAKE_C_COMPILER_ID STREQUAL Intel AND
+ CMAKE_C_COMPILER_VERSION VERSION_LESS 14.0) OR
+ CMAKE_C_COMPILER_ID STREQUAL "IntelLLVM")
+ set(NO_COMPILE_PDB 1)
+endif()
+
+set(my_targets "")
+
+add_library(mylibA SHARED mylibA.c)
+set_target_properties(mylibA PROPERTIES
+ PDB_NAME "mylibA_Special"
+ PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/mylibA_PDB/$<CONFIG>"
+)
+list(APPEND my_targets mylibA)
+
+add_library(mylibB STATIC mylibB.c)
+set_target_properties(mylibB PROPERTIES
+ COMPILE_PDB_NAME "mylibB_Special"
+ COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/mylibB_PDB"
+)
+if(NOT NO_COMPILE_PDB)
+ list(APPEND my_targets mylibB)
+endif()
+
+add_library(mylibC SHARED mylibC.c)
+set_target_properties(mylibC PROPERTIES
+ PDB_NAME "mylibC_Special"
+)
+list(APPEND my_targets mylibC)
+
+add_library(mylibD STATIC mylibD.c)
+set_target_properties(mylibD PROPERTIES
+ COMPILE_PDB_NAME "mylibD_Special"
+)
+if(NOT NO_COMPILE_PDB)
+ list(APPEND my_targets mylibD)
+endif()
+
+add_executable(myexe myexe.c)
+set_target_properties(myexe PROPERTIES
+ PDB_NAME "myexe_Special"
+ PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/myexe_PDB"
+)
+list(APPEND my_targets myexe)
+
+target_link_libraries(myexe mylibA mylibB mylibC mylibD)
+
+add_executable(myexe2 myexe2.c)
+set_target_properties(myexe2 PROPERTIES
+ PDB_NAME "myexe2_Special"
+)
+list(APPEND my_targets myexe2)
+
+target_link_libraries(myexe2 mylibA mylibD)
+
+
+# Clang/C2 does not produce pdb files for static libraries
+if (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND
+ CMAKE_C_SIMULATE_ID STREQUAL "MSVC")
+ list(REMOVE_ITEM my_targets mylibB mylibD)
+endif()
+
+
+#-----------------------------------------------------------------------------
+# Check that PDB files actually appear where expected.
+
+set(pdbs "")
+foreach(t ${my_targets})
+ get_property(pdb_name TARGET ${t} PROPERTY PDB_NAME)
+ get_property(pdb_dir TARGET ${t} PROPERTY PDB_OUTPUT_DIRECTORY)
+ if(NOT pdb_name)
+ get_property(pdb_name TARGET ${t} PROPERTY COMPILE_PDB_NAME)
+ endif()
+ if(NOT pdb_dir)
+ get_property(pdb_dir TARGET ${t} PROPERTY COMPILE_PDB_OUTPUT_DIRECTORY)
+ endif()
+ if(NOT pdb_dir)
+ set(pdb_dir ${CMAKE_CURRENT_BINARY_DIR})
+ endif()
+ if (pdb_dir MATCHES "\\$<.*>")
+ # Skip per-configuration subdirectory if the value contained
+ # a generator expression.
+ list(APPEND pdbs ${pdb_dir}/${pdb_name}.pdb)
+ else()
+ list(APPEND pdbs ${pdb_dir}/${CMAKE_CFG_INTDIR}/${pdb_name}.pdb)
+ endif()
+endforeach()
+add_custom_target(check_pdbs ALL VERBATIM
+ COMMAND ${CMAKE_COMMAND} -Dconfig=$<CONFIGURATION> "-Dpdbs=${pdbs}"
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/check_pdbs.cmake
+ )
+add_dependencies(check_pdbs ${my_targets})
diff --git a/Tests/PDBDirectoryAndName/check_pdbs.cmake b/Tests/PDBDirectoryAndName/check_pdbs.cmake
new file mode 100644
index 0000000..89cdb3c
--- /dev/null
+++ b/Tests/PDBDirectoryAndName/check_pdbs.cmake
@@ -0,0 +1,10 @@
+if(NOT "${config}" MATCHES "[Dd][Ee][Bb]")
+ return()
+endif()
+foreach(pdb ${pdbs})
+ if(EXISTS "${pdb}")
+ message(STATUS "PDB Exists: ${pdb}")
+ else()
+ message(SEND_ERROR "PDB MISSING: ${pdb}")
+ endif()
+endforeach()
diff --git a/Tests/PDBDirectoryAndName/myexe.c b/Tests/PDBDirectoryAndName/myexe.c
new file mode 100644
index 0000000..fdb8b09
--- /dev/null
+++ b/Tests/PDBDirectoryAndName/myexe.c
@@ -0,0 +1,8 @@
+extern int mylibA();
+extern int mylibB();
+extern int mylibC();
+extern int mylibD();
+int main()
+{
+ return mylibA() + mylibB() + mylibC() + mylibD();
+}
diff --git a/Tests/PDBDirectoryAndName/myexe2.c b/Tests/PDBDirectoryAndName/myexe2.c
new file mode 100644
index 0000000..250d651
--- /dev/null
+++ b/Tests/PDBDirectoryAndName/myexe2.c
@@ -0,0 +1,6 @@
+extern int mylibA();
+extern int mylibD();
+int main()
+{
+ return mylibA() + mylibD();
+}
diff --git a/Tests/PDBDirectoryAndName/mylibA.c b/Tests/PDBDirectoryAndName/mylibA.c
new file mode 100644
index 0000000..5bc279b
--- /dev/null
+++ b/Tests/PDBDirectoryAndName/mylibA.c
@@ -0,0 +1,4 @@
+__declspec(dllexport) int mylibA()
+{
+ return 1;
+}
diff --git a/Tests/PDBDirectoryAndName/mylibB.c b/Tests/PDBDirectoryAndName/mylibB.c
new file mode 100644
index 0000000..3a95845
--- /dev/null
+++ b/Tests/PDBDirectoryAndName/mylibB.c
@@ -0,0 +1,4 @@
+int mylibB()
+{
+ return -1;
+}
diff --git a/Tests/PDBDirectoryAndName/mylibC.c b/Tests/PDBDirectoryAndName/mylibC.c
new file mode 100644
index 0000000..8982849
--- /dev/null
+++ b/Tests/PDBDirectoryAndName/mylibC.c
@@ -0,0 +1,4 @@
+__declspec(dllexport) int mylibC()
+{
+ return 1;
+}
diff --git a/Tests/PDBDirectoryAndName/mylibD.c b/Tests/PDBDirectoryAndName/mylibD.c
new file mode 100644
index 0000000..a53b7a2
--- /dev/null
+++ b/Tests/PDBDirectoryAndName/mylibD.c
@@ -0,0 +1,4 @@
+int mylibD()
+{
+ return -1;
+}
diff --git a/Tests/PerConfig/CMakeLists.txt b/Tests/PerConfig/CMakeLists.txt
new file mode 100644
index 0000000..7f461b0
--- /dev/null
+++ b/Tests/PerConfig/CMakeLists.txt
@@ -0,0 +1,34 @@
+project(PerConfig C)
+
+# Targets with per-configuration names.
+add_library(pcStatic STATIC pcStatic.c)
+set_property(TARGET pcStatic PROPERTY RELEASE_POSTFIX -opt)
+set_property(TARGET pcStatic PROPERTY DEBUG_POSTFIX -dbg)
+add_library(pcShared SHARED pcShared.c)
+set_property(TARGET pcShared PROPERTY RELEASE_POSTFIX -opt)
+set_property(TARGET pcShared PROPERTY DEBUG_POSTFIX -dbg)
+set_property(TARGET pcShared PROPERTY VERSION 1.2)
+set_property(TARGET pcShared PROPERTY SOVERSION 3)
+if(UNIX AND NOT CYGWIN)
+ set(soname_file -DpcShared_soname_file=$<TARGET_SONAME_FILE:pcShared>)
+endif()
+add_executable(perconfig perconfig.c)
+target_link_libraries(perconfig pcStatic pcShared)
+set_property(TARGET perconfig PROPERTY RELEASE_POSTFIX -opt)
+set_property(TARGET perconfig PROPERTY DEBUG_POSTFIX -dbg)
+
+set(PerConfig_COMMAND
+ ${CMAKE_COMMAND}
+ -Dconfiguration=$<CONFIGURATION>
+ -Dperconfig_file_dir=$<TARGET_FILE_DIR:perconfig>
+ -Dperconfig_file_name=$<TARGET_FILE_NAME:perconfig>
+ -Dperconfig_file=$<TARGET_FILE:perconfig>
+ -DpcStatic_file=$<TARGET_FILE:pcStatic>
+ -DpcStatic_linker_file=$<TARGET_LINKER_FILE:pcStatic>
+ -DpcShared_file=$<TARGET_FILE:pcShared>
+ -DpcShared_linker_file=$<TARGET_LINKER_FILE:pcShared>
+ ${soname_file}
+ -P ${PerConfig_SOURCE_DIR}/perconfig.cmake
+ )
+set(PerConfig_COMMAND "${PerConfig_COMMAND}" PARENT_SCOPE)
+set(PerConfig_DEPENDS ${PerConfig_SOURCE_DIR}/perconfig.cmake perconfig pcStatic pcShared)
diff --git a/Tests/PerConfig/pcShared.c b/Tests/PerConfig/pcShared.c
new file mode 100644
index 0000000..b08fadc
--- /dev/null
+++ b/Tests/PerConfig/pcShared.c
@@ -0,0 +1,5 @@
+#include "pcShared.h"
+const char* pcShared(void)
+{
+ return "INFO:symbol[pcShared]";
+}
diff --git a/Tests/PerConfig/pcShared.h b/Tests/PerConfig/pcShared.h
new file mode 100644
index 0000000..2ae66cd
--- /dev/null
+++ b/Tests/PerConfig/pcShared.h
@@ -0,0 +1,16 @@
+#ifndef pcShared_h
+#define pcShared_h
+
+#ifdef _WIN32
+# ifdef pcShared_EXPORTS
+# define PC_EXPORT __declspec(dllexport)
+# else
+# define PC_EXPORT __declspec(dllimport)
+# endif
+#else
+# define PC_EXPORT
+#endif
+
+PC_EXPORT const char* pcShared(void);
+
+#endif
diff --git a/Tests/PerConfig/pcStatic.c b/Tests/PerConfig/pcStatic.c
new file mode 100644
index 0000000..7e1bf51
--- /dev/null
+++ b/Tests/PerConfig/pcStatic.c
@@ -0,0 +1,4 @@
+const char* pcStatic(void)
+{
+ return "INFO:symbol[pcStatic]";
+}
diff --git a/Tests/PerConfig/perconfig.c b/Tests/PerConfig/perconfig.c
new file mode 100644
index 0000000..d942d45
--- /dev/null
+++ b/Tests/PerConfig/perconfig.c
@@ -0,0 +1,8 @@
+#include "pcShared.h"
+extern const char* pcStatic(void);
+int main()
+{
+ pcStatic();
+ pcShared();
+ return 0;
+}
diff --git a/Tests/PerConfig/perconfig.cmake b/Tests/PerConfig/perconfig.cmake
new file mode 100644
index 0000000..5286307
--- /dev/null
+++ b/Tests/PerConfig/perconfig.cmake
@@ -0,0 +1,40 @@
+# Print values for human reference.
+foreach(v
+ configuration
+ perconfig_file_dir
+ perconfig_file_name
+ perconfig_file
+ pcStatic_file
+ pcStatic_linker_file
+ pcShared_file
+ pcShared_linker_file
+ pcShared_soname_file
+ )
+ message(STATUS "${v}=${${v}}")
+endforeach()
+
+# Verify that file names match as expected.
+set(pc_file_components ${perconfig_file_dir}/${perconfig_file_name})
+if(NOT "${pc_file_components}" STREQUAL "${perconfig_file}")
+ message(SEND_ERROR
+ "File components ${pc_file_components} do not match ${perconfig_file}")
+endif()
+if(NOT "${pcStatic_file}" STREQUAL "${pcStatic_linker_file}")
+ message(SEND_ERROR
+ "pcStatic_file does not match pcStatic_linker_file:\n"
+ " ${pcStatic_file}\n"
+ " ${pcStatic_linker_file}\n"
+ )
+endif()
+
+# Verify that the implementation files are named correctly.
+foreach(lib pcStatic pcShared)
+ file(STRINGS "${${lib}_file}" info LIMIT_COUNT 1 REGEX "INFO:[A-Za-z0-9_]+\\[[^]]*\\]")
+ if(NOT "${info}" MATCHES "INFO:symbol\\[${lib}\\]")
+ message(SEND_ERROR "No INFO:symbol[${lib}] found in:\n ${${lib}_file}")
+ endif()
+endforeach()
+execute_process(COMMAND ${perconfig_file} RESULT_VARIABLE result)
+if(result)
+ message(SEND_ERROR "Error running:\n ${perconfig_file}\n(${result})")
+endif()
diff --git a/Tests/Plugin/CMakeLists.txt b/Tests/Plugin/CMakeLists.txt
new file mode 100644
index 0000000..ec22bf4
--- /dev/null
+++ b/Tests/Plugin/CMakeLists.txt
@@ -0,0 +1,64 @@
+cmake_minimum_required (VERSION 2.8.12)
+cmake_policy(SET CMP0054 NEW)
+project(Plugin)
+
+# We need proper C++98 support from the compiler
+set(CMAKE_CXX_STANDARD 98)
+
+# Test per-target output directory properties.
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${Plugin_BINARY_DIR}/bin)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${Plugin_BINARY_DIR}/lib/plugin)
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${Plugin_BINARY_DIR}/lib/static)
+
+# Configure the location of plugins.
+configure_file(${Plugin_SOURCE_DIR}/src/example_exe.h.in
+ ${Plugin_BINARY_DIR}/include/example_exe.h @ONLY)
+
+# We need to include headers from the source tree and configured
+# headers in the build tree.
+include_directories(
+ ${Plugin_BINARY_DIR}/include
+ ${Plugin_SOURCE_DIR}/include
+ )
+
+# Clang/C2 in C++98 mode cannot properly handle some of MSVC headers
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
+ CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
+ set(CMAKE_CXX_STANDARD 11)
+endif()
+
+# Create an executable that exports an API for use by plugins.
+add_executable(example_exe src/example_exe.cxx src/DynamicLoader.cxx)
+set_target_properties(example_exe PROPERTIES
+ ENABLE_EXPORTS 1
+ OUTPUT_NAME example
+ # Test placing exe import library in unique directory.
+ ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/exe
+ )
+target_link_libraries(example_exe ${CMAKE_DL_LIBS})
+
+# Create a plugin that uses the API provided by the executable.
+# This module "links" to the executable to use the symbols.
+add_library(example_mod_1 MODULE src/example_mod_1.c)
+target_link_libraries(example_mod_1 example_exe)
+
+
+if(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG AND
+ "${CMAKE_C_CREATE_SHARED_MODULE}" MATCHES "SONAME_FLAG")
+ # Verify that targets export with proper IMPORTED SONAME properties.
+ export(TARGETS example_mod_1 example_exe NAMESPACE exp_
+ FILE ${CMAKE_CURRENT_BINARY_DIR}/mods.cmake)
+
+ include(ExternalProject)
+ ExternalProject_Add(PluginTest
+ SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/PluginTest"
+ BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/PluginTest"
+ DOWNLOAD_COMMAND ""
+ INSTALL_COMMAND ""
+ )
+ add_dependencies(PluginTest example_mod_1)
+endif()
+
+# TODO:
+# - create a plugin that links to a static lib
+# - create a plugin that links to a shared lib
diff --git a/Tests/Plugin/PluginTest/CMakeLists.txt b/Tests/Plugin/PluginTest/CMakeLists.txt
new file mode 100644
index 0000000..f00122d
--- /dev/null
+++ b/Tests/Plugin/PluginTest/CMakeLists.txt
@@ -0,0 +1,27 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(PluginTest)
+
+include(${CMAKE_CURRENT_BINARY_DIR}/../mods.cmake)
+get_property(configs TARGET exp_example_mod_1 PROPERTY IMPORTED_CONFIGURATIONS)
+foreach(c ${configs})
+ string(TOUPPER "${c}" CONFIG)
+ get_property(soname TARGET exp_example_mod_1 PROPERTY IMPORTED_NO_SONAME_${CONFIG})
+ if(soname)
+ message(STATUS "exp_example_mod_1 has IMPORTED_NO_SONAME_${CONFIG} as expected: ${soname}")
+ else()
+ message(SEND_ERROR "exp_example_mod_1 does not have IMPORTED_NO_SONAME_${CONFIG} but should")
+ endif()
+endforeach()
+
+# Parse the binary to check for SONAME if possible.
+if("${CMAKE_EXECUTABLE_FORMAT}" MATCHES "ELF")
+ find_program(READELF_EXE readelf)
+ if(READELF_EXE)
+ add_custom_target(check_mod_soname ALL COMMAND
+ ${CMAKE_COMMAND} -Dreadelf=${READELF_EXE}
+ -Dmod=$<TARGET_FILE:exp_example_mod_1>
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/../check_mod_soname.cmake
+ )
+ endif()
+endif()
diff --git a/Tests/Plugin/check_mod_soname.cmake b/Tests/Plugin/check_mod_soname.cmake
new file mode 100644
index 0000000..eeededa
--- /dev/null
+++ b/Tests/Plugin/check_mod_soname.cmake
@@ -0,0 +1,7 @@
+execute_process(COMMAND ${readelf} -d ${mod} OUTPUT_FILE ${mod}.readelf.txt)
+file(STRINGS ${mod}.readelf.txt soname REGEX "SONAME")
+if(soname)
+ message(FATAL_ERROR "${mod} has soname but should not:\n ${soname}")
+else()
+ message(STATUS "${mod} has no soname as expected")
+endif()
diff --git a/Tests/Plugin/include/DynamicLoader.hxx b/Tests/Plugin/include/DynamicLoader.hxx
new file mode 100644
index 0000000..20b37de
--- /dev/null
+++ b/Tests/Plugin/include/DynamicLoader.hxx
@@ -0,0 +1,49 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.
+ See https://cmake.org/licensing#kwsys for details. */
+#ifndef DynamicLoader_hxx
+#define DynamicLoader_hxx
+
+#include <string>
+
+#if defined(__hpux)
+# include <dl.h>
+#elif defined(_WIN32) && !defined(__CYGWIN__)
+# include <windows.h>
+#elif defined(__APPLE__)
+# include <AvailabilityMacros.h>
+# if MAC_OS_X_VERSION_MAX_ALLOWED < 1030
+# include <mach-o/dyld.h>
+# endif
+#elif defined(__BEOS__)
+# include <be/kernel/image.h>
+#endif
+
+class DynamicLoader
+{
+public:
+#if defined(__hpux)
+ typedef shl_t LibraryHandle;
+#elif defined(_WIN32) && !defined(__CYGWIN__)
+ typedef HMODULE LibraryHandle;
+#elif defined(__APPLE__)
+# if MAC_OS_X_VERSION_MAX_ALLOWED < 1030
+ typedef NSModule LibraryHandle;
+# else
+ typedef void* LibraryHandle;
+# endif
+#elif defined(__BEOS__)
+ typedef image_id LibraryHandle;
+#else // POSIX
+ typedef void* LibraryHandle;
+#endif
+
+ typedef void (*SymbolPointer)();
+
+ static LibraryHandle OpenLibrary(const std::string&);
+
+ static int CloseLibrary(LibraryHandle);
+
+ static SymbolPointer GetSymbolAddress(LibraryHandle, const std::string&);
+};
+
+#endif
diff --git a/Tests/Plugin/include/example.h b/Tests/Plugin/include/example.h
new file mode 100644
index 0000000..cbcb3dc
--- /dev/null
+++ b/Tests/Plugin/include/example.h
@@ -0,0 +1,24 @@
+#ifndef example_h
+#define example_h
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+# if defined(example_exe_EXPORTS)
+# define EXAMPLE_EXPORT __declspec(dllexport)
+# else
+# define EXAMPLE_EXPORT __declspec(dllimport)
+# endif
+#else
+# define EXAMPLE_EXPORT
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EXAMPLE_EXPORT int example_exe_function(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Tests/Plugin/src/DynamicLoader.cxx b/Tests/Plugin/src/DynamicLoader.cxx
new file mode 100644
index 0000000..d4a2637
--- /dev/null
+++ b/Tests/Plugin/src/DynamicLoader.cxx
@@ -0,0 +1,263 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.
+ See https://cmake.org/licensing#kwsys for details. */
+#if defined(_WIN32)
+# define NOMINMAX // hide min,max to not conflict with <limits>
+#endif
+
+#include <DynamicLoader.hxx>
+
+#if defined(__hpux)
+# include <dl.h>
+
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+ const std::string& libname)
+{
+ return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L);
+}
+
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+ if (!lib) {
+ return 0;
+ }
+ return !shl_unload(lib);
+}
+
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+ DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+ void* addr;
+ int status;
+
+ /* TYPE_PROCEDURE Look for a function or procedure. (This used to be default)
+ * TYPE_DATA Look for a symbol in the data segment (for example,
+ * variables).
+ * TYPE_UNDEFINED Look for any symbol.
+ */
+ status = shl_findsym(&lib, sym.c_str(), TYPE_UNDEFINED, &addr);
+ void* result = (status < 0) ? (void*)0 : addr;
+
+ // Hack to cast pointer-to-data to pointer-to-function.
+ return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
+}
+
+#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1030)
+# include <mach-o/dyld.h>
+
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+ const std::string& libname)
+{
+ NSObjectFileImageReturnCode rc;
+ NSObjectFileImage image = 0;
+
+ rc = NSCreateObjectFileImageFromFile(libname.c_str(), &image);
+ // rc == NSObjectFileImageInappropriateFile when trying to load a dylib file
+ if (rc != NSObjectFileImageSuccess) {
+ return 0;
+ }
+ NSModule handle = NSLinkModule(image, libname.c_str(),
+ NSLINKMODULE_OPTION_BINDNOW |
+ NSLINKMODULE_OPTION_RETURN_ON_ERROR);
+ NSDestroyObjectFileImage(image);
+ return handle;
+}
+
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+ bool success = NSUnLinkModule(lib, NSUNLINKMODULE_OPTION_NONE);
+ return success;
+}
+
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+ DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+ void* result = 0;
+ // Need to prepend symbols with '_' on Apple-gcc compilers
+ std::string rsym = '_' + sym;
+
+ NSSymbol symbol = NSLookupSymbolInModule(lib, rsym.c_str());
+ if (symbol) {
+ result = NSAddressOfSymbol(symbol);
+ }
+
+ // Hack to cast pointer-to-data to pointer-to-function.
+ return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
+}
+
+#elif defined(_WIN32) && !defined(__CYGWIN__)
+# include <windows.h>
+
+# include <stdio.h>
+
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+ const std::string& libname)
+{
+ DynamicLoader::LibraryHandle lh;
+ int length = MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, NULL, 0);
+ wchar_t* wchars = new wchar_t[length + 1];
+ wchars[0] = '\0';
+ MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, wchars, length);
+ lh = LoadLibraryW(wchars);
+ delete[] wchars;
+ return lh;
+}
+
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+ return (int)FreeLibrary(lib);
+}
+
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+ DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+ void* result;
+# if defined(__BORLANDC__) || defined(__WATCOMC__)
+ // Need to prepend symbols with '_'
+ std::string ssym = '_' + sym;
+ const char* rsym = ssym.c_str();
+# else
+ const char* rsym = sym.c_str();
+# endif
+ result = (void*)GetProcAddress(lib, rsym);
+// Hack to cast pointer-to-data to pointer-to-function.
+# ifdef __WATCOMC__
+ return *(DynamicLoader::SymbolPointer*)(&result);
+# else
+ return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
+# endif
+}
+
+#elif defined(__BEOS__)
+# include <be/kernel/image.h>
+# include <be/support/Errors.h>
+
+static image_id last_dynamic_err = B_OK;
+
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+ const std::string& libname)
+{
+ // image_id's are integers, errors are negative. Add one just in case we
+ // get a valid image_id of zero (is that even possible?).
+ image_id rc = load_add_on(libname.c_str());
+ if (rc < 0) {
+ last_dynamic_err = rc;
+ return 0;
+ }
+
+ return rc + 1;
+}
+
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+ if (!lib) {
+ last_dynamic_err = B_BAD_VALUE;
+ return 0;
+ } else {
+ // The function dlclose() returns 0 on success, and non-zero on error.
+ status_t rc = unload_add_on(lib - 1);
+ if (rc != B_OK) {
+ last_dynamic_err = rc;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+ DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+ // Hack to cast pointer-to-data to pointer-to-function.
+ union
+ {
+ void* pvoid;
+ DynamicLoader::SymbolPointer psym;
+ } result;
+
+ result.psym = NULL;
+
+ if (!lib) {
+ last_dynamic_err = B_BAD_VALUE;
+ } else {
+ // !!! FIXME: BeOS can do function-only lookups...does this ever
+ // !!! FIXME: actually _want_ a data symbol lookup, or was this union
+ // !!! FIXME: a leftover of dlsym()? (s/ANY/TEXT for functions only).
+ status_t rc =
+ get_image_symbol(lib - 1, sym.c_str(), B_SYMBOL_TYPE_ANY, &result.pvoid);
+ if (rc != B_OK) {
+ last_dynamic_err = rc;
+ result.psym = NULL;
+ }
+ }
+ return result.psym;
+}
+
+#elif defined(__MINT__)
+# define _GNU_SOURCE /* for program_invocation_name */
+# include <dld.h>
+# include <errno.h>
+# include <malloc.h>
+
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+ const std::string& libname)
+{
+ char* name = (char*)calloc(1, libname.size() + 1);
+ dld_init(program_invocation_name);
+ strncpy(name, libname.c_str(), libname.size());
+ dld_link(libname.c_str());
+ return (void*)name;
+}
+
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+ dld_unlink_by_file((char*)lib, 0);
+ free(lib);
+ return 0;
+}
+
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+ DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+ // Hack to cast pointer-to-data to pointer-to-function.
+ union
+ {
+ void* pvoid;
+ DynamicLoader::SymbolPointer psym;
+ } result;
+ result.pvoid = dld_get_symbol(sym.c_str());
+ return result.psym;
+}
+
+#else
+# include <dlfcn.h>
+
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+ const std::string& libname)
+{
+ return dlopen(libname.c_str(), RTLD_LAZY);
+}
+
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+ if (lib) {
+ // The function dlclose() returns 0 on success, and non-zero on error.
+ return !dlclose(lib);
+ }
+ // else
+ return 0;
+}
+
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+ DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+ // Hack to cast pointer-to-data to pointer-to-function.
+ union
+ {
+ void* pvoid;
+ DynamicLoader::SymbolPointer psym;
+ } result;
+ result.pvoid = dlsym(lib, sym.c_str());
+ return result.psym;
+}
+
+#endif
diff --git a/Tests/Plugin/src/example_exe.cxx b/Tests/Plugin/src/example_exe.cxx
new file mode 100644
index 0000000..bc4c727
--- /dev/null
+++ b/Tests/Plugin/src/example_exe.cxx
@@ -0,0 +1,52 @@
+#include <iostream>
+#include <string>
+
+#include <example.h>
+#include <example_exe.h>
+#include <stdio.h>
+
+#include "DynamicLoader.hxx"
+
+// Implement the ABI used by plugins.
+extern "C" int example_exe_function()
+{
+ std::cout << "hello" << std::endl;
+ return 123;
+}
+
+#ifdef CMAKE_INTDIR
+# define CONFIG_DIR "/" CMAKE_INTDIR
+#else
+# define CONFIG_DIR ""
+#endif
+
+int main()
+{
+ std::string const libName = EXAMPLE_EXE_PLUGIN_DIR CONFIG_DIR
+ "/" EXAMPLE_EXE_MOD_PREFIX "example_mod_1" EXAMPLE_EXE_MOD_SUFFIX;
+ DynamicLoader::LibraryHandle handle = DynamicLoader::OpenLibrary(libName);
+ if (!handle) {
+ // Leave the .c_str() on this one. It is needed on OpenWatcom.
+ std::cerr << "Could not open plugin \"" << libName.c_str() << "\"!"
+ << std::endl;
+ return 1;
+ }
+ DynamicLoader::SymbolPointer sym =
+ DynamicLoader::GetSymbolAddress(handle, "example_mod_1_function");
+ if (!sym) {
+ std::cerr << "Could not get plugin symbol \"example_mod_1_function\"!"
+ << std::endl;
+ return 1;
+ }
+#ifdef __WATCOMC__
+ int(__cdecl * f)(int) = (int(__cdecl*)(int))(sym);
+#else
+ int (*f)(int) = reinterpret_cast<int (*)(int)>(sym);
+#endif
+ if (f(456) != (123 + 456)) {
+ std::cerr << "Incorrect return value from plugin!" << std::endl;
+ return 1;
+ }
+ DynamicLoader::CloseLibrary(handle);
+ return 0;
+}
diff --git a/Tests/Plugin/src/example_exe.h.in b/Tests/Plugin/src/example_exe.h.in
new file mode 100644
index 0000000..af71021
--- /dev/null
+++ b/Tests/Plugin/src/example_exe.h.in
@@ -0,0 +1,8 @@
+#ifndef example_exe_h
+#define example_exe_h
+
+#define EXAMPLE_EXE_PLUGIN_DIR "@CMAKE_LIBRARY_OUTPUT_DIRECTORY@"
+#define EXAMPLE_EXE_MOD_PREFIX "@CMAKE_SHARED_MODULE_PREFIX@"
+#define EXAMPLE_EXE_MOD_SUFFIX "@CMAKE_SHARED_MODULE_SUFFIX@"
+
+#endif
diff --git a/Tests/Plugin/src/example_mod_1.c b/Tests/Plugin/src/example_mod_1.c
new file mode 100644
index 0000000..2b740b8
--- /dev/null
+++ b/Tests/Plugin/src/example_mod_1.c
@@ -0,0 +1,21 @@
+#include <example.h>
+#include <stdio.h>
+
+#if defined(_WIN32)
+# define MODULE_EXPORT __declspec(dllexport)
+#else
+# define MODULE_EXPORT
+#endif
+
+#ifdef __WATCOMC__
+# define MODULE_CCONV __cdecl
+#else
+# define MODULE_CCONV
+#endif
+
+MODULE_EXPORT int MODULE_CCONV example_mod_1_function(int n)
+{
+ int result = example_exe_function() + n;
+ printf("world\n");
+ return result;
+}
diff --git a/Tests/Policy0002/A/CMakeLists.txt b/Tests/Policy0002/A/CMakeLists.txt
new file mode 100644
index 0000000..cee6422
--- /dev/null
+++ b/Tests/Policy0002/A/CMakeLists.txt
@@ -0,0 +1 @@
+add_executable(Policy0002 ../policy0002.c)
diff --git a/Tests/Policy0002/CMakeLists.txt b/Tests/Policy0002/CMakeLists.txt
new file mode 100644
index 0000000..0f6d331
--- /dev/null
+++ b/Tests/Policy0002/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.6)
+project(Policy0002 C)
+cmake_policy(SET CMP0002 OLD)
+add_subdirectory(A)
+add_executable(Policy0002 policy0002.c)
diff --git a/Tests/Policy0002/policy0002.c b/Tests/Policy0002/policy0002.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/Policy0002/policy0002.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/PolicyScope/Bar.cmake b/Tests/PolicyScope/Bar.cmake
new file mode 100644
index 0000000..cf1904c
--- /dev/null
+++ b/Tests/PolicyScope/Bar.cmake
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 2.6.3)
+
+# Make sure a policy set differently by our includer is now correct.
+cmake_policy(GET CMP0003 cmp)
+check(CMP0003 "NEW" "${cmp}")
+
+# Test allowing the top-level file to not have cmake_minimum_required.
+cmake_policy(SET CMP0000 OLD)
diff --git a/Tests/PolicyScope/CMakeLists.txt b/Tests/PolicyScope/CMakeLists.txt
new file mode 100644
index 0000000..353842b
--- /dev/null
+++ b/Tests/PolicyScope/CMakeLists.txt
@@ -0,0 +1,112 @@
+project(PolicyScope C)
+# No cmake_minimum_required(VERSION), it's in FindFoo.
+
+#-----------------------------------------------------------------------------
+# Helper function to report results.
+function(check msg lhs rhs)
+ if(NOT "${lhs}" STREQUAL "${rhs}")
+ message(FATAL_ERROR "${msg}: expected [${lhs}], got [${rhs}]")
+ endif()
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Test using a development framework that sets policies for us.
+
+# Policy CMP0011 should not be set at this point.
+cmake_policy(GET CMP0011 cmp)
+check(CMP0011 "" "${cmp}")
+
+# Put the test modules in the search path.
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
+
+# The included file should set policies for us.
+find_package(Foo)
+
+# Check policies set by the package.
+cmake_policy(GET CMP0003 cmp)
+check(CMP0003 "OLD" "${cmp}")
+cmake_policy(GET CMP0002 cmp)
+check(CMP0002 "NEW" "${cmp}")
+cmake_policy(GET CMP0011 cmp)
+check(CMP0011 "NEW" "${cmp}")
+
+# Make sure an included file cannot change policies.
+include(Bar)
+cmake_policy(GET CMP0003 cmp)
+check(CMP0003 "OLD" "${cmp}")
+
+# Allow the included file to change policies.
+include(Bar NO_POLICY_SCOPE)
+cmake_policy(GET CMP0003 cmp)
+check(CMP0003 "NEW" "${cmp}")
+
+#-----------------------------------------------------------------------------
+# Test function and macro policy recording.
+
+# Create the functions in an isolated scope in which we change policies.
+cmake_policy(PUSH)
+if(1)
+ # Change CMP0002
+ cmake_policy(SET CMP0002 OLD)
+ function(func1)
+ # CMP0002 should be changed when this function is invoked
+ cmake_policy(GET CMP0002 cmp)
+ check(CMP0002 "OLD" "${cmp}")
+
+ # The undocumented PARENT_SCOPE option sees the caller's setting.
+ cmake_policy(GET CMP0002 cmp PARENT_SCOPE)
+ check(CMP0002 "NEW" "${cmp}")
+ endfunction()
+
+ # Unset CMP0002
+ cmake_policy(VERSION 2.4)
+ macro(macro1)
+ # CMP0002 should be unset when this macro is invoked
+ cmake_policy(GET CMP0002 cmp)
+ check(CMP0002 "" "${cmp}")
+
+ # The undocumented PARENT_SCOPE option sees the caller's setting.
+ cmake_policy(GET CMP0002 cmp PARENT_SCOPE)
+ check(CMP0002 "NEW" "${cmp}")
+
+ # Setting the policy should work here and also in the caller.
+ cmake_policy(SET CMP0002 OLD)
+ cmake_policy(GET CMP0002 cmp)
+ check(CMP0002 "OLD" "${cmp}")
+ endmacro()
+endif()
+cmake_policy(POP)
+
+# CMP0002 should still be NEW in this context.
+cmake_policy(GET CMP0002 cmp)
+check(CMP0002 "NEW" "${cmp}")
+
+# Check the recorded policies
+func1()
+macro1()
+
+# The macro should have changed CMP0002.
+cmake_policy(GET CMP0002 cmp)
+check(CMP0002 "OLD" "${cmp}")
+
+#-----------------------------------------------------------------------------
+# Test CMAKE_POLICY_DEFAULT_CMP<NNNN> variable.
+cmake_policy(PUSH)
+ set(CMAKE_POLICY_DEFAULT_CMP0010 OLD) # ignored
+ set(CMAKE_POLICY_DEFAULT_CMP0012 OLD) # honored
+ set(CMAKE_POLICY_DEFAULT_CMP0013 NEW) # honored
+ set(CMAKE_POLICY_DEFAULT_CMP0014 "") # noop
+ cmake_policy(VERSION 2.6.3)
+ cmake_policy(GET CMP0010 cmp)
+ check(CMP0010 "NEW" "${cmp}")
+ cmake_policy(GET CMP0012 cmp)
+ check(CMP0012 "OLD" "${cmp}")
+ cmake_policy(GET CMP0013 cmp)
+ check(CMP0013 "NEW" "${cmp}")
+ cmake_policy(GET CMP0014 cmp)
+ check(CMP0014 "" "${cmp}")
+cmake_policy(POP)
+
+#-----------------------------------------------------------------------------
+# Dummy executable so the project can build and run.
+add_executable(PolicyScope main.c)
diff --git a/Tests/PolicyScope/FindFoo.cmake b/Tests/PolicyScope/FindFoo.cmake
new file mode 100644
index 0000000..5b441e2
--- /dev/null
+++ b/Tests/PolicyScope/FindFoo.cmake
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.6.3)
+cmake_policy(SET CMP0003 OLD)
diff --git a/Tests/PolicyScope/main.c b/Tests/PolicyScope/main.c
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/PolicyScope/main.c
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/PositionIndependentTargets/.gitattributes b/Tests/PositionIndependentTargets/.gitattributes
new file mode 100644
index 0000000..61b2751
--- /dev/null
+++ b/Tests/PositionIndependentTargets/.gitattributes
@@ -0,0 +1,2 @@
+# Do not format a source where we want a long line preserved.
+pic_test.h -format.clang-format-6.0
diff --git a/Tests/PositionIndependentTargets/CMakeLists.txt b/Tests/PositionIndependentTargets/CMakeLists.txt
new file mode 100644
index 0000000..ff779d3
--- /dev/null
+++ b/Tests/PositionIndependentTargets/CMakeLists.txt
@@ -0,0 +1,14 @@
+
+cmake_minimum_required(VERSION 2.8.12)
+
+project(PositionIndependentTargets)
+
+include(CheckCXXSourceCompiles)
+
+include_directories("${CMAKE_CURRENT_SOURCE_DIR}") # For pic_test.h
+
+add_subdirectory(global)
+add_subdirectory(targets)
+add_subdirectory(interface)
+
+add_executable(PositionIndependentTargets main.cpp)
diff --git a/Tests/PositionIndependentTargets/global/CMakeLists.txt b/Tests/PositionIndependentTargets/global/CMakeLists.txt
new file mode 100644
index 0000000..1d662f8
--- /dev/null
+++ b/Tests/PositionIndependentTargets/global/CMakeLists.txt
@@ -0,0 +1,37 @@
+
+set(CMAKE_POSITION_INDEPENDENT_CODE True)
+
+add_executable(test_target_executable_global
+ "${CMAKE_CURRENT_SOURCE_DIR}/../pic_main.cpp"
+)
+
+add_library(test_target_shared_library_global
+ SHARED "${CMAKE_CURRENT_SOURCE_DIR}/../pic_lib.cpp"
+)
+set_target_properties(test_target_shared_library_global
+ PROPERTIES DEFINE_SYMBOL PIC_TEST_BUILD_DLL
+)
+
+add_library(test_target_static_library_global
+ STATIC "${CMAKE_CURRENT_SOURCE_DIR}/../pic_lib.cpp"
+)
+set_target_properties(test_target_static_library_global
+ PROPERTIES COMPILE_DEFINITIONS PIC_TEST_STATIC_BUILD
+)
+
+
+file(READ
+ "${CMAKE_CURRENT_SOURCE_DIR}/../pic_test.h"
+ PIC_HEADER_CONTENT
+)
+
+check_cxx_source_compiles(
+ "
+${PIC_HEADER_CONTENT}
+int main(int,char**) { return 0; }\n"
+ PIC_TRY_COMPILE_RESULT
+)
+
+if (NOT PIC_TRY_COMPILE_RESULT)
+ message(SEND_ERROR "TRY_COMPILE with content requiring __PIC__ failed. ${OUTPUT}")
+endif()
diff --git a/Tests/PositionIndependentTargets/interface/CMakeLists.txt b/Tests/PositionIndependentTargets/interface/CMakeLists.txt
new file mode 100644
index 0000000..65f3b76
--- /dev/null
+++ b/Tests/PositionIndependentTargets/interface/CMakeLists.txt
@@ -0,0 +1,27 @@
+
+add_library(piciface INTERFACE)
+set_property(TARGET piciface PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON)
+
+add_executable(test_empty_iface "${CMAKE_CURRENT_SOURCE_DIR}/../pic_main.cpp")
+target_link_libraries(test_empty_iface piciface)
+
+add_library(sharedlib SHARED "${CMAKE_CURRENT_SOURCE_DIR}/../pic_lib.cpp")
+target_link_libraries(sharedlib piciface)
+set_property(TARGET sharedlib PROPERTY DEFINE_SYMBOL PIC_TEST_BUILD_DLL)
+
+add_executable(test_iface_via_shared "${CMAKE_CURRENT_SOURCE_DIR}/../pic_main.cpp")
+target_link_libraries(test_iface_via_shared sharedlib)
+
+add_library(sharedlibpic SHARED "${CMAKE_CURRENT_SOURCE_DIR}/../pic_lib.cpp")
+set_property(TARGET sharedlibpic PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON)
+set_property(TARGET sharedlibpic PROPERTY DEFINE_SYMBOL PIC_TEST_BUILD_DLL)
+
+add_library(shared_iface INTERFACE)
+target_link_libraries(shared_iface INTERFACE sharedlibpic)
+
+add_executable(test_shared_via_iface "${CMAKE_CURRENT_SOURCE_DIR}/../pic_main.cpp")
+target_link_libraries(test_shared_via_iface shared_iface)
+
+add_executable(test_shared_via_iface_non_conflict "${CMAKE_CURRENT_SOURCE_DIR}/../pic_main.cpp")
+set_property(TARGET test_shared_via_iface_non_conflict PROPERTY POSITION_INDEPENDENT_CODE ON)
+target_link_libraries(test_shared_via_iface_non_conflict shared_iface)
diff --git a/Tests/PositionIndependentTargets/main.cpp b/Tests/PositionIndependentTargets/main.cpp
new file mode 100644
index 0000000..e9ad257
--- /dev/null
+++ b/Tests/PositionIndependentTargets/main.cpp
@@ -0,0 +1,5 @@
+
+int main(int, char**)
+{
+ return 0;
+}
diff --git a/Tests/PositionIndependentTargets/pic_lib.cpp b/Tests/PositionIndependentTargets/pic_lib.cpp
new file mode 100644
index 0000000..b8b25a3
--- /dev/null
+++ b/Tests/PositionIndependentTargets/pic_lib.cpp
@@ -0,0 +1,12 @@
+
+#include "pic_test.h"
+
+class PIC_TEST_EXPORT Dummy
+{
+ int dummy();
+};
+
+int Dummy::dummy()
+{
+ return 0;
+}
diff --git a/Tests/PositionIndependentTargets/pic_main.cpp b/Tests/PositionIndependentTargets/pic_main.cpp
new file mode 100644
index 0000000..3246eee
--- /dev/null
+++ b/Tests/PositionIndependentTargets/pic_main.cpp
@@ -0,0 +1,7 @@
+
+#include "pic_test.h"
+
+int main(int, char**)
+{
+ return 0;
+}
diff --git a/Tests/PositionIndependentTargets/pic_test.h b/Tests/PositionIndependentTargets/pic_test.h
new file mode 100644
index 0000000..13cf8f7
--- /dev/null
+++ b/Tests/PositionIndependentTargets/pic_test.h
@@ -0,0 +1,20 @@
+
+#if defined(__ELF__)
+# if !defined(__PIC__) && !defined(__PIE__)
+# error "The POSITION_INDEPENDENT_CODE property should cause __PIC__ or __PIE__ to be defined on ELF platforms."
+# endif
+#endif
+
+#if defined(PIC_TEST_STATIC_BUILD)
+# define PIC_TEST_EXPORT
+#else
+# if defined(_WIN32) || defined(WIN32) /* Win32 version */
+# ifdef PIC_TEST_BUILD_DLL
+# define PIC_TEST_EXPORT __declspec(dllexport)
+# else
+# define PIC_TEST_EXPORT __declspec(dllimport)
+# endif
+# else
+# define PIC_TEST_EXPORT
+# endif
+#endif
diff --git a/Tests/PositionIndependentTargets/targets/CMakeLists.txt b/Tests/PositionIndependentTargets/targets/CMakeLists.txt
new file mode 100644
index 0000000..4724c85
--- /dev/null
+++ b/Tests/PositionIndependentTargets/targets/CMakeLists.txt
@@ -0,0 +1,20 @@
+
+add_executable(test_target_executable_properties "${CMAKE_CURRENT_SOURCE_DIR}/../pic_main.cpp")
+set_target_properties(test_target_executable_properties
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE True
+)
+
+add_library(test_target_shared_library_properties SHARED "${CMAKE_CURRENT_SOURCE_DIR}/../pic_lib.cpp")
+set_target_properties(test_target_shared_library_properties
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE True
+ DEFINE_SYMBOL PIC_TEST_BUILD_DLL
+)
+
+add_library(test_target_static_library_properties STATIC "${CMAKE_CURRENT_SOURCE_DIR}/../pic_lib.cpp")
+set_target_properties(test_target_static_library_properties
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE True
+ COMPILE_DEFINITIONS PIC_TEST_STATIC_BUILD
+)
diff --git a/Tests/PreOrder/CMakeLists.txt b/Tests/PreOrder/CMakeLists.txt
new file mode 100644
index 0000000..8b4c439
--- /dev/null
+++ b/Tests/PreOrder/CMakeLists.txt
@@ -0,0 +1,6 @@
+# a simple test case
+project (PreOrder)
+set(CMAKE_IGNORE_DEPENDENCIES_ORDERING 1)
+add_subdirectory(Library)
+add_executable (PreOrder simple.cxx)
+target_link_libraries(PreOrder simpleLib)
diff --git a/Tests/PreOrder/Library/CMakeLists.txt b/Tests/PreOrder/Library/CMakeLists.txt
new file mode 100644
index 0000000..018ffa5
--- /dev/null
+++ b/Tests/PreOrder/Library/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(simpleLib simpleLib.cxx )
+
diff --git a/Tests/PreOrder/Library/simpleLib.cxx b/Tests/PreOrder/Library/simpleLib.cxx
new file mode 100644
index 0000000..281d888
--- /dev/null
+++ b/Tests/PreOrder/Library/simpleLib.cxx
@@ -0,0 +1,3 @@
+void simpleLib()
+{
+}
diff --git a/Tests/PreOrder/simple.cxx b/Tests/PreOrder/simple.cxx
new file mode 100644
index 0000000..7f99579
--- /dev/null
+++ b/Tests/PreOrder/simple.cxx
@@ -0,0 +1,6 @@
+extern void simpleLib();
+int main()
+{
+ simpleLib();
+ return 0;
+}
diff --git a/Tests/PrecompiledHeader/CMakeLists.txt b/Tests/PrecompiledHeader/CMakeLists.txt
new file mode 100644
index 0000000..58f4863
--- /dev/null
+++ b/Tests/PrecompiledHeader/CMakeLists.txt
@@ -0,0 +1,54 @@
+cmake_minimum_required (VERSION 3.9)
+project(PrecompiledHeader C)
+
+# Make sure the proper compiler is in use.
+if(NOT MSVC AND NOT CMAKE_C_COMPILER_ID STREQUAL "Intel")
+ message(FATAL_ERROR "The PrecompiledHeader test works only with MSVC or Intel")
+endif()
+
+# Compute a custom name for the precompiled header.
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ set(PCH_DIR "${CMAKE_CURRENT_BINARY_DIR}/PCH/${CMAKE_CFG_INTDIR}")
+ foreach(cfg ${CMAKE_CONFIGURATION_TYPES})
+ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/PCH/${cfg})
+ endforeach()
+else()
+ set(PCH_DIR "${CMAKE_CURRENT_BINARY_DIR}/PCH")
+ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/PCH)
+endif()
+
+set(PCH_USE_INCLUDE_DIR 0)
+set(PCH_FILE "\"/Fp${PCH_DIR}/foo_precompiled.pch\"")
+
+# Choose between an explicit include path and using /I during
+# precompilation. The /I form is used to test that the PCH is
+# actually used. In practice the include path form would be used.
+if(PCH_USE_INCLUDE_DIR)
+ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
+else()
+ set(PCH_INCLUDE_DIR "\"/I${CMAKE_CURRENT_SOURCE_DIR}/include\"")
+endif()
+
+# Create a target that will use a precompiled header.
+set(foo_SRCS foo1.c foo2.c)
+add_executable(foo foo_precompile.c ${foo_SRCS})
+
+# Setup flags on the target to create and use the precompiled header.
+set_target_properties(foo PROPERTIES
+ COMPILE_FLAGS "/Yufoo_precompiled.h /FIfoo_precompiled.h ${PCH_FILE}")
+set_source_files_properties(foo_precompile.c PROPERTIES
+ COMPILE_FLAGS "/Ycfoo_precompiled.h ${PCH_INCLUDE_DIR}")
+
+# Setup dependencies for precompiled header creation and use. The VS
+# IDE takes care of this automatically.
+if("${CMAKE_GENERATOR}" MATCHES "Makefile" OR
+ "${CMAKE_GENERATOR}" MATCHES "Ninja")
+ # This source file creates the precompiled header as a side-effect.
+ set_source_files_properties(foo_precompile.c PROPERTIES
+ OBJECT_OUTPUTS "${PCH_DIR}/foo_precompiled.pch")
+
+ # These source files use the precompiled header.
+ set_source_files_properties(${foo_SRCS} PROPERTIES
+ OBJECT_DEPENDS "${PCH_DIR}/foo_precompiled.pch")
+endif()
diff --git a/Tests/PrecompiledHeader/foo1.c b/Tests/PrecompiledHeader/foo1.c
new file mode 100644
index 0000000..fef2586
--- /dev/null
+++ b/Tests/PrecompiledHeader/foo1.c
@@ -0,0 +1,8 @@
+#ifndef foo_h
+# error "Precompiled header foo_precompiled.h has not been loaded."
+#endif
+
+int main()
+{
+ return foo();
+}
diff --git a/Tests/PrecompiledHeader/foo2.c b/Tests/PrecompiledHeader/foo2.c
new file mode 100644
index 0000000..3ed04ed
--- /dev/null
+++ b/Tests/PrecompiledHeader/foo2.c
@@ -0,0 +1,9 @@
+#ifndef foo_h
+# include "foo.h"
+# error "Precompiled header foo_precompiled.h has not been loaded."
+#endif
+
+int foo()
+{
+ return 0;
+}
diff --git a/Tests/PrecompiledHeader/foo_precompile.c b/Tests/PrecompiledHeader/foo_precompile.c
new file mode 100644
index 0000000..c37d69a
--- /dev/null
+++ b/Tests/PrecompiledHeader/foo_precompile.c
@@ -0,0 +1,5 @@
+/* The foo_precompiled.h header is included by a /FI option when this
+ source is used to create a precompiled header. Include it here
+ explicitly to allow dependency scanning to detect the dependency
+ whether or not the include path is known to the scanner. */
+#include "include/foo_precompiled.h"
diff --git a/Tests/PrecompiledHeader/include/foo.h b/Tests/PrecompiledHeader/include/foo.h
new file mode 100644
index 0000000..2210cb4
--- /dev/null
+++ b/Tests/PrecompiledHeader/include/foo.h
@@ -0,0 +1,4 @@
+#ifndef foo_h
+#define foo_h
+extern int foo();
+#endif
diff --git a/Tests/PrecompiledHeader/include/foo_precompiled.h b/Tests/PrecompiledHeader/include/foo_precompiled.h
new file mode 100644
index 0000000..f4de601
--- /dev/null
+++ b/Tests/PrecompiledHeader/include/foo_precompiled.h
@@ -0,0 +1 @@
+#include "foo.h"
diff --git a/Tests/Preprocess/CMakeLists.txt b/Tests/Preprocess/CMakeLists.txt
new file mode 100644
index 0000000..4347459
--- /dev/null
+++ b/Tests/Preprocess/CMakeLists.txt
@@ -0,0 +1,286 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(Preprocess)
+
+# This test is meant both as a test and as a reference for supported
+# syntax on native tool command lines.
+
+# Determine the build tool being used. Not all characters can be
+# escaped for all build tools. This test checks all characters known
+# to work with each tool and documents those known to not work.
+if("${CMAKE_GENERATOR}" MATCHES "Xcode")
+ set(PP_XCODE 1)
+endif()
+if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles")
+ set(PP_UMAKE 1)
+endif()
+if("${CMAKE_GENERATOR}" MATCHES "NMake Makefiles")
+ set(PP_NMAKE 1)
+endif()
+if("${CMAKE_GENERATOR}" MATCHES "MinGW Makefiles")
+ set(PP_MINGW 1)
+endif()
+if("${CMAKE_GENERATOR}" MATCHES "Borland Makefiles")
+ set(PP_BORLAND 1)
+endif()
+if("${CMAKE_GENERATOR}" MATCHES "Watcom WMake")
+ set(PP_WATCOM 1)
+endif()
+if("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
+ set(PP_VS 1)
+endif()
+if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND
+ "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
+ set(CLANG_MSVC_WINDOWS 1)
+endif()
+if(CLANG_MSVC_WINDOWS AND
+ "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ set(CLANG_GNULIKE_WINDOWS 1)
+endif()
+
+# Some tests below check the PP_* variables set above. They are meant
+# to test the case that the build tool is at fault. Other tests below
+# check the compiler that will be used when the compiler is at fault
+# (does not work even from a command shell).
+
+#-----------------------------------------------------------------------------
+# Construct a C-string literal to test passing through a definition on
+# the command line. We configure the value into a header so it can be
+# checked in the executable at runtime. The semicolon is handled
+# specially because it needs to be escaped in the COMPILE_DEFINITIONS
+# property value to avoid separating definitions but the string value
+# must not have it escaped inside the configured header.
+set(STRING_EXTRA "")
+
+if(NOT BORLAND)
+ # Borland: ;
+ # The Borland compiler will simply not accept a non-escaped semicolon
+ # on the command line. If it is escaped \; then the escape character
+ # shows up in the preprocessing output too.
+ set(SEMICOLON "\;")
+endif()
+
+string(APPEND STRING_EXTRA " ")
+
+if(NOT PP_BORLAND AND NOT PP_WATCOM AND NOT CLANG_GNULIKE_WINDOWS)
+ # Borland, WMake: multiple spaces
+ # The make tool seems to remove extra whitespace from inside
+ # quoted strings when passing to the compiler. It does not have
+ # trouble passing to other tools, and the compiler may be directly
+ # invoked from the command line.
+ string(APPEND STRING_EXTRA " ")
+endif()
+
+if(NOT PP_VS)
+ # VS: ,
+ # Visual Studio will not accept a comma in the value of a definition.
+ # The comma-separated list of PreprocessorDefinitions in the project
+ # file seems to be parsed before the content of entries is examined.
+ string(APPEND STRING_EXTRA ",")
+endif()
+
+if(NOT PP_MINGW AND NOT CLANG_GNULIKE_WINDOWS)
+ # MinGW: &
+ # When inside -D"FOO=\"a & b\"" MinGW make wants -D"FOO=\"a "&" b\""
+ # but it does not like quoted ampersand elsewhere.
+ string(APPEND STRING_EXTRA "&")
+endif()
+
+if(NOT PP_MINGW AND NOT CLANG_GNULIKE_WINDOWS)
+ # MinGW: |
+ # When inside -D"FOO=\"a | b\"" MinGW make wants -D"FOO=\"a "|" b\""
+ # but it does not like quoted pipe elsewhere.
+ string(APPEND STRING_EXTRA "|")
+endif()
+
+if(NOT PP_BORLAND AND NOT PP_MINGW AND NOT PP_NMAKE)
+ # Borland, NMake, MinGW: ^
+ # When inside -D"FOO=\"a ^ b\"" the make tools want -D"FOO=\"a "^" b\""
+ # but do not like quoted carrot elsewhere. In NMake the non-quoted
+ # syntax works when the flags are not in a make variable.
+ string(APPEND STRING_EXTRA "^")
+endif()
+
+if(NOT PP_BORLAND AND NOT PP_MINGW AND NOT PP_NMAKE)
+ # Borland, MinGW: < >
+ # Angle-brackets have funny behavior that is hard to escape.
+ string(APPEND STRING_EXTRA "<>")
+endif()
+
+set(EXPR_OP1 "/")
+if((NOT MSVC OR PP_NMAKE) AND
+ NOT CMAKE_C_COMPILER_ID STREQUAL "Intel" AND
+ NOT CLANG_MSVC_WINDOWS)
+ # MSVC cl, Intel icl: %
+ # When the cl compiler is invoked from the command line then % must
+ # be written %% (to distinguish from %ENV% syntax). However cl does
+ # not seem to accept the syntax when it is invoked from inside a
+ # make tool (nmake, mingw32-make, etc.). Instead the argument must
+ # be placed inside a response file. Then cl accepts it because it
+ # parses the response file as it would the normal windows command
+ # line. Currently only NMake supports running cl with a response
+ # file. Supporting other make tools would require CMake to generate
+ # response files explicitly for each object file.
+ #
+ # When the icl compiler is invoked from the command line then % must
+ # be written just '%'. However nmake requires '%%' except when using
+ # response files. Currently we have no way to affect escaping based
+ # on whether flags go in a response file, so we just have to skip it.
+ string(APPEND STRING_EXTRA "%")
+ set(EXPR_OP1 "%")
+endif()
+
+# XL: )(
+# The XL compiler cannot pass unbalanced parens correctly to a tool
+# it launches internally.
+if(CMAKE_C_COMPILER_ID STREQUAL "XL")
+ string(APPEND STRING_EXTRA "()")
+else()
+ string(APPEND STRING_EXTRA ")(")
+endif()
+
+# General: \"
+# Make tools do not reliably accept \\\" syntax:
+# - MinGW and MSYS make tools crash with \\\"
+# - Borland make actually wants a mis-matched quote \\"
+# or $(BACKSLASH)\" where BACKSLASH is a variable set to \\
+# - VS IDE gets confused about the bounds of the definition value \\\"
+# - NMake is okay with just \\\"
+# - The XL compiler does not re-escape \\\" when launching an
+# internal tool to do preprocessing .
+# - The IntelLLVM C and C++ compiler drivers do not re-escape the \\\" when
+# launching the underlying compiler. FIXME: this bug is expected to be fixed
+# in a future release.
+if((PP_NMAKE OR PP_UMAKE) AND
+ NOT CMAKE_C_COMPILER_ID STREQUAL "XL" AND
+ NOT CMAKE_C_COMPILER_ID STREQUAL "IntelLLVM" AND
+ NOT CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
+ string(APPEND STRING_EXTRA "\\\"")
+endif()
+
+# General: #
+# MSVC will not accept a # in the value of a string definition on the
+# command line. The character seems to be simply replaced by an
+# equals =. According to "cl -help" definitions may be specified by
+# -DMACRO#VALUE as well as -DMACRO=VALUE. It must be implemented by a
+# simple search-and-replace.
+#
+# The Borland compiler will parse both # and \# as just # but the make
+# tool seems to want \# sometimes and not others.
+#
+# Unix make does not like # in variable settings without extra
+# escaping. This could probably be fixed but since MSVC does not
+# support it and it is not an operator it is not worthwhile.
+
+# Compose the final test string.
+set(STRING_VALUE "hello`~!@$*_+-=}{][:'.?/${STRING_EXTRA}world")
+
+#-----------------------------------------------------------------------------
+# Function-style macro command-line support:
+# - Borland does not support
+# - MSVC does not support
+# - Watcom does not support
+# - GCC supports
+
+# Too few platforms support this to bother implementing.
+# People can just configure headers with the macros.
+
+#-----------------------------------------------------------------------------
+# Construct a sample expression to pass as a macro definition.
+
+set(EXPR "x*y+!(x==(y+1*2))*f(x${EXPR_OP1}2)")
+
+if(NOT WATCOM)
+ # Watcom does not support - or / because it parses them as options.
+ string(APPEND EXPR " + y/x-x")
+endif()
+
+#-----------------------------------------------------------------------------
+
+# Inform the test if the debug configuration is getting built.
+# The NDEBUG definition takes care of this for release.
+string(APPEND CMAKE_C_FLAGS_DEBUG " -DPREPROCESS_DEBUG")
+string(APPEND CMAKE_CXX_FLAGS_DEBUG " -DPREPROCESS_DEBUG")
+
+# Inform the test if it built from Xcode.
+if(PP_XCODE)
+ set(PREPROCESS_XCODE 1)
+endif()
+
+# Test old-style definitions.
+add_definitions(-DOLD_DEF -DOLD_EXPR=2)
+
+# Make sure old-style definitions are converted to directory property.
+set(OLD_DEFS_EXPECTED "OLD_DEF;OLD_EXPR=2")
+get_property(OLD_DEFS DIRECTORY PROPERTY COMPILE_DEFINITIONS)
+if(NOT "${OLD_DEFS}" STREQUAL "${OLD_DEFS_EXPECTED}")
+ message(SEND_ERROR "add_definitions not converted to directory property!")
+endif()
+
+add_executable(Preprocess preprocess.c preprocess.cxx)
+
+set(FILE_PATH "${Preprocess_SOURCE_DIR}/file_def.h")
+set(TARGET_PATH "${Preprocess_SOURCE_DIR}/target_def.h")
+
+# Set some definition properties.
+foreach(c "" "_DEBUG" "_RELEASE" "_RELWITHDEBINFO" "_MINSIZEREL")
+ set(FLAVOR "${c}")
+ # Treat RelWithDebInfo and MinSizeRel as Release to avoid having
+ # an exponentional matrix of inclusions and exclusions of defines
+ if("${c}" STREQUAL "_RELWITHDEBINFO" OR "${c}" STREQUAL "_MINSIZEREL")
+ set(FLAVOR "_RELEASE")
+ endif()
+ set_property(
+ DIRECTORY .
+ APPEND PROPERTY COMPILE_DEFINITIONS${c} "DIRECTORY_DEF${FLAVOR}"
+ )
+ set_property(
+ TARGET Preprocess
+ PROPERTY COMPILE_DEFINITIONS${c} "TARGET_DEF${FLAVOR}"
+ )
+ set_property(
+ SOURCE preprocess.c preprocess.cxx
+ PROPERTY COMPILE_DEFINITIONS${c} "FILE_DEF${FLAVOR}"
+ )
+endforeach()
+
+# Add definitions with values.
+set(DEF_TARGET_PATH "TARGET_PATH=\"${TARGET_PATH}\"")
+set(DEF_FILE_PATH "FILE_PATH=\"${FILE_PATH}\"")
+set_property(
+ TARGET Preprocess
+ APPEND PROPERTY COMPILE_DEFINITIONS
+ "TARGET_STRING=\"${STRING_VALUE}${SEMICOLON}\""
+ "TARGET_EXPR=${EXPR}"
+ ${DEF_TARGET_PATH}
+ )
+set_property(
+ SOURCE preprocess.c preprocess.cxx
+ APPEND PROPERTY COMPILE_DEFINITIONS
+ "FILE_STRING=\"${STRING_VALUE}${SEMICOLON}\""
+ "FILE_EXPR=${EXPR}"
+ ${DEF_FILE_PATH}
+ )
+
+# Try reading and writing the property value to ensure the string is
+# preserved.
+get_property(defs1 TARGET Preprocess PROPERTY COMPILE_DEFINITIONS)
+set_property(TARGET Preprocess PROPERTY COMPILE_DEFINITIONS "${defs1}")
+get_property(defs2 TARGET Preprocess PROPERTY COMPILE_DEFINITIONS)
+if(NOT "x${defs1}" STREQUAL "x${defs2}")
+ message(FATAL_ERROR "get/set/get COMPILE_DEFINITIONS round trip failed. "
+ "First get:\n"
+ " ${defs1}\n"
+ "Second get:\n"
+ " ${defs2}")
+endif()
+
+# Helper target for running test manually in build tree.
+add_custom_target(drive COMMAND Preprocess)
+
+# Configure the header file with the desired string value.
+if(SEMICOLON)
+ string(APPEND STRING_VALUE ";")
+endif()
+configure_file(${Preprocess_SOURCE_DIR}/preprocess.h.in
+ ${Preprocess_BINARY_DIR}/preprocess.h)
+include_directories(${Preprocess_BINARY_DIR})
diff --git a/Tests/Preprocess/file_def.h b/Tests/Preprocess/file_def.h
new file mode 100644
index 0000000..fbf8986
--- /dev/null
+++ b/Tests/Preprocess/file_def.h
@@ -0,0 +1 @@
+#define FILE_PATH_DEF
diff --git a/Tests/Preprocess/preprocess.c b/Tests/Preprocess/preprocess.c
new file mode 100644
index 0000000..b3117da
--- /dev/null
+++ b/Tests/Preprocess/preprocess.c
@@ -0,0 +1,192 @@
+#include <preprocess.h>
+
+#include FILE_PATH
+#include TARGET_PATH
+
+#include <stdio.h>
+#include <string.h>
+
+int check_defines_C(void)
+{
+ int result = 1;
+ if (strcmp(FILE_STRING, STRING_VALUE) != 0) {
+ fprintf(stderr, "FILE_STRING has wrong value in C [%s] vs [%s]\n",
+ FILE_STRING, STRING_VALUE);
+ result = 0;
+ }
+ if (strcmp(TARGET_STRING, STRING_VALUE) != 0) {
+ fprintf(stderr, "TARGET_STRING has wrong value in C [%s] vs [%s]\n",
+ TARGET_STRING, STRING_VALUE);
+ result = 0;
+ }
+ {
+ int x = 2;
+ int y = 3;
+ if ((FILE_EXPR) != (EXPR)) {
+ fprintf(stderr, "FILE_EXPR did not work in C [%s] vs [%s]\n",
+ TO_STRING(FILE_EXPR), TO_STRING(EXPR));
+ result = 0;
+ }
+ if ((TARGET_EXPR) != (EXPR)) {
+ fprintf(stderr, "TARGET_EXPR did not work in C [%s] vs [%s]\n",
+ TO_STRING(TARGET_EXPR), TO_STRING(EXPR));
+ result = 0;
+ }
+ }
+#ifdef NDEBUG
+# ifdef FILE_DEF_DEBUG
+ {
+ fprintf(stderr, "FILE_DEF_DEBUG should not be defined in C\n");
+ result = 0;
+ }
+# endif
+# ifdef TARGET_DEF_DEBUG
+ {
+ fprintf(stderr, "TARGET_DEF_DEBUG should not be defined in C\n");
+ result = 0;
+ }
+# endif
+# ifdef DIRECTORY_DEF_DEBUG
+ {
+ fprintf(stderr, "DIRECTORY_DEF_DEBUG should not be defined in C\n");
+ result = 0;
+ }
+# endif
+# ifndef FILE_DEF_RELEASE
+# ifndef PREPROCESS_XCODE
+ {
+ fprintf(stderr, "FILE_DEF_RELEASE should be defined in C\n");
+ result = 0;
+ }
+# endif
+# endif
+# ifndef TARGET_DEF_RELEASE
+ {
+ fprintf(stderr, "TARGET_DEF_RELEASE should be defined in C\n");
+ result = 0;
+ }
+# endif
+# ifndef DIRECTORY_DEF_RELEASE
+ {
+ fprintf(stderr, "DIRECTORY_DEF_RELEASE should be defined in C\n");
+ result = 0;
+ }
+# endif
+#endif
+#ifdef PREPROCESS_DEBUG
+# ifndef FILE_DEF_DEBUG
+# ifndef PREPROCESS_XCODE
+ {
+ fprintf(stderr, "FILE_DEF_DEBUG should be defined in C\n");
+ result = 0;
+ }
+# endif
+# endif
+# ifndef TARGET_DEF_DEBUG
+ {
+ fprintf(stderr, "TARGET_DEF_DEBUG should be defined in C\n");
+ result = 0;
+ }
+# endif
+# ifndef DIRECTORY_DEF_DEBUG
+ {
+ fprintf(stderr, "DIRECTORY_DEF_DEBUG should be defined in C\n");
+ result = 0;
+ }
+# endif
+# ifdef FILE_DEF_RELEASE
+ {
+ fprintf(stderr, "FILE_DEF_RELEASE should not be defined in C\n");
+ result = 0;
+ }
+# endif
+# ifdef TARGET_DEF_RELEASE
+ {
+ fprintf(stderr, "TARGET_DEF_RELEASE should not be defined in C\n");
+ result = 0;
+ }
+# endif
+# ifdef DIRECTORY_DEF_RELEASE
+ {
+ fprintf(stderr, "DIRECTORY_DEF_RELEASE should not be defined in C\n");
+ result = 0;
+ }
+# endif
+#endif
+#if defined(FILE_DEF_DEBUG) || defined(TARGET_DEF_DEBUG)
+# if !defined(FILE_DEF_DEBUG) || !defined(TARGET_DEF_DEBUG)
+# ifndef PREPROCESS_XCODE
+ {
+ fprintf(stderr, "FILE_DEF_DEBUG and TARGET_DEF_DEBUG inconsistent in C\n");
+ result = 0;
+ }
+# endif
+# endif
+# if defined(FILE_DEF_RELEASE) || defined(TARGET_DEF_RELEASE)
+ {
+ fprintf(stderr, "DEBUG and RELEASE definitions inconsistent in C\n");
+ result = 0;
+ }
+# endif
+#endif
+#if defined(FILE_DEF_RELEASE) || defined(TARGET_DEF_RELEASE)
+# if !defined(FILE_DEF_RELEASE) || !defined(TARGET_DEF_RELEASE)
+# ifndef PREPROCESS_XCODE
+ {
+ fprintf(stderr,
+ "FILE_DEF_RELEASE and TARGET_DEF_RELEASE inconsistent in C\n");
+ result = 0;
+ }
+# endif
+# endif
+# if defined(FILE_DEF_DEBUG) || defined(TARGET_DEF_DEBUG)
+ {
+ fprintf(stderr, "RELEASE and DEBUG definitions inconsistent in C\n");
+ result = 0;
+ }
+# endif
+#endif
+#ifndef FILE_PATH_DEF
+ {
+ fprintf(stderr, "FILE_PATH_DEF not defined in C\n");
+ result = 0;
+ }
+#endif
+#ifndef TARGET_PATH_DEF
+ {
+ fprintf(stderr, "TARGET_PATH_DEF not defined in C\n");
+ result = 0;
+ }
+#endif
+#ifndef FILE_DEF
+ {
+ fprintf(stderr, "FILE_DEF not defined in C\n");
+ result = 0;
+ }
+#endif
+#ifndef TARGET_DEF
+ {
+ fprintf(stderr, "TARGET_DEF not defined in C\n");
+ result = 0;
+ }
+#endif
+#ifndef DIRECTORY_DEF
+ {
+ fprintf(stderr, "DIRECTORY_DEF not defined in C\n");
+ result = 0;
+ }
+#endif
+#ifndef OLD_DEF
+ {
+ fprintf(stderr, "OLD_DEF not defined in C\n");
+ result = 0;
+ }
+#endif
+#if !defined(OLD_EXPR) || OLD_EXPR != 2
+ {
+ fprintf(stderr, "OLD_EXPR id not work in C [%s]\n", TO_STRING(OLD_EXPR));
+ result = 0;
+ }
+#endif
+ return result;
+}
diff --git a/Tests/Preprocess/preprocess.cxx b/Tests/Preprocess/preprocess.cxx
new file mode 100644
index 0000000..f2fffef
--- /dev/null
+++ b/Tests/Preprocess/preprocess.cxx
@@ -0,0 +1,215 @@
+#include <preprocess.h>
+
+#include FILE_PATH
+#include TARGET_PATH
+
+#include <stdio.h>
+#include <string.h>
+
+extern "C" int check_defines_C(void);
+
+int check_defines_CXX()
+{
+ int result = 1;
+ if (strcmp(FILE_STRING, STRING_VALUE) != 0) {
+ fprintf(stderr, "FILE_STRING has wrong value in CXX [%s] vs [%s]\n",
+ FILE_STRING, STRING_VALUE);
+ result = 0;
+ }
+ if (strcmp(TARGET_STRING, STRING_VALUE) != 0) {
+ fprintf(stderr, "TARGET_STRING has wrong value in CXX [%s] vs [%s]\n",
+ TARGET_STRING, STRING_VALUE);
+ result = 0;
+ }
+ {
+ int x = 2;
+ int y = 3;
+ if ((FILE_EXPR) != (EXPR)) {
+ fprintf(stderr, "FILE_EXPR did not work in CXX [%s] vs [%s]\n",
+ TO_STRING(FILE_EXPR), TO_STRING(EXPR));
+ result = 0;
+ }
+ if ((TARGET_EXPR) != (EXPR)) {
+ fprintf(stderr, "TARGET_EXPR did not work in CXX [%s] vs [%s]\n",
+ TO_STRING(TARGET_EXPR), TO_STRING(EXPR));
+ result = 0;
+ }
+ }
+#ifdef NDEBUG
+# ifdef FILE_DEF_DEBUG
+ {
+ fprintf(stderr, "FILE_DEF_DEBUG should not be defined in CXX\n");
+ result = 0;
+ }
+# endif
+# ifdef TARGET_DEF_DEBUG
+ {
+ fprintf(stderr, "TARGET_DEF_DEBUG should not be defined in CXX\n");
+ result = 0;
+ }
+# endif
+# ifdef DIRECTORY_DEF_DEBUG
+ {
+ fprintf(stderr, "DIRECTORY_DEF_DEBUG should not be defined in CXX\n");
+ result = 0;
+ }
+# endif
+# ifndef FILE_DEF_RELEASE
+# ifndef PREPROCESS_XCODE
+ {
+ fprintf(stderr, "FILE_DEF_RELEASE should be defined in CXX\n");
+ result = 0;
+ }
+# endif
+# endif
+# ifndef TARGET_DEF_RELEASE
+ {
+ fprintf(stderr, "TARGET_DEF_RELEASE should be defined in CXX\n");
+ result = 0;
+ }
+# endif
+# ifndef DIRECTORY_DEF_RELEASE
+ {
+ fprintf(stderr, "DIRECTORY_DEF_RELEASE should be defined in CXX\n");
+ result = 0;
+ }
+# endif
+#endif
+#ifdef PREPROCESS_DEBUG
+# ifndef FILE_DEF_DEBUG
+# ifndef PREPROCESS_XCODE
+ {
+ fprintf(stderr, "FILE_DEF_DEBUG should be defined in CXX\n");
+ result = 0;
+ }
+# endif
+# endif
+# ifndef TARGET_DEF_DEBUG
+ {
+ fprintf(stderr, "TARGET_DEF_DEBUG should be defined in CXX\n");
+ result = 0;
+ }
+# endif
+# ifndef DIRECTORY_DEF_DEBUG
+ {
+ fprintf(stderr, "DIRECTORY_DEF_DEBUG should be defined in CXX\n");
+ result = 0;
+ }
+# endif
+# ifdef FILE_DEF_RELEASE
+ {
+ fprintf(stderr, "FILE_DEF_RELEASE should not be defined in CXX\n");
+ result = 0;
+ }
+# endif
+# ifdef TARGET_DEF_RELEASE
+ {
+ fprintf(stderr, "TARGET_DEF_RELEASE should not be defined in CXX\n");
+ result = 0;
+ }
+# endif
+# ifdef DIRECTORY_DEF_RELEASE
+ {
+ fprintf(stderr, "DIRECTORY_DEF_RELEASE should not be defined in CXX\n");
+ result = 0;
+ }
+# endif
+#endif
+#if defined(FILE_DEF_DEBUG) || defined(TARGET_DEF_DEBUG)
+# if !defined(FILE_DEF_DEBUG) || !defined(TARGET_DEF_DEBUG)
+# ifndef PREPROCESS_XCODE
+ {
+ fprintf(stderr,
+ "FILE_DEF_DEBUG and TARGET_DEF_DEBUG inconsistent in CXX\n");
+ result = 0;
+ }
+# endif
+# endif
+# if defined(FILE_DEF_RELEASE) || defined(TARGET_DEF_RELEASE)
+ {
+ fprintf(stderr, "DEBUG and RELEASE definitions inconsistent in CXX\n");
+ result = 0;
+ }
+# endif
+#endif
+#if defined(FILE_DEF_RELEASE) || defined(TARGET_DEF_RELEASE)
+# if !defined(FILE_DEF_RELEASE) || !defined(TARGET_DEF_RELEASE)
+# ifndef PREPROCESS_XCODE
+ {
+ fprintf(stderr,
+ "FILE_DEF_RELEASE and TARGET_DEF_RELEASE inconsistent in CXX\n");
+ result = 0;
+ }
+# endif
+# endif
+# if defined(FILE_DEF_DEBUG) || defined(TARGET_DEF_DEBUG)
+ {
+ fprintf(stderr, "RELEASE and DEBUG definitions inconsistent in CXX\n");
+ result = 0;
+ }
+# endif
+#endif
+#ifndef FILE_PATH_DEF
+ {
+ fprintf(stderr, "FILE_PATH_DEF not defined in CXX\n");
+ result = 0;
+ }
+#endif
+#ifndef TARGET_PATH_DEF
+ {
+ fprintf(stderr, "TARGET_PATH_DEF not defined in CXX\n");
+ result = 0;
+ }
+#endif
+#ifndef FILE_DEF
+ {
+ fprintf(stderr, "FILE_DEF not defined in CXX\n");
+ result = 0;
+ }
+#endif
+#ifndef TARGET_DEF
+ {
+ fprintf(stderr, "TARGET_DEF not defined in CXX\n");
+ result = 0;
+ }
+#endif
+#ifndef DIRECTORY_DEF
+ {
+ fprintf(stderr, "DIRECTORY_DEF not defined in CXX\n");
+ result = 0;
+ }
+#endif
+#ifndef OLD_DEF
+ {
+ fprintf(stderr, "OLD_DEF not defined in CXX\n");
+ result = 0;
+ }
+#endif
+#if !defined(OLD_EXPR) || OLD_EXPR != 2
+ {
+ fprintf(stderr, "OLD_EXPR id not work in C [%s]\n", TO_STRING(OLD_EXPR));
+ result = 0;
+ }
+#endif
+ return result;
+}
+
+int main()
+{
+ int result = 1;
+
+ if (!check_defines_C()) {
+ result = 0;
+ }
+
+ if (!check_defines_CXX()) {
+ result = 0;
+ }
+
+ if (result) {
+ printf("All preprocessor definitions are correct.\n");
+ return 0;
+ } else {
+ return 1;
+ }
+}
diff --git a/Tests/Preprocess/preprocess.h.in b/Tests/Preprocess/preprocess.h.in
new file mode 100644
index 0000000..e058a58
--- /dev/null
+++ b/Tests/Preprocess/preprocess.h.in
@@ -0,0 +1,10 @@
+/* Define configured macros. */
+#define STRING_VALUE "@STRING_VALUE@"
+#define EXPR @EXPR@
+#cmakedefine PREPROCESS_XCODE
+
+/* Declarations and macros shared by all sources. */
+#define TO_STRING(x) TO_STRING0(x)
+#define TO_STRING0(x) #x
+
+static int f(int i) { return i*3; }
diff --git a/Tests/Preprocess/target_def.h b/Tests/Preprocess/target_def.h
new file mode 100644
index 0000000..f016d5c
--- /dev/null
+++ b/Tests/Preprocess/target_def.h
@@ -0,0 +1 @@
+#define TARGET_PATH_DEF
diff --git a/Tests/Properties/CMakeLists.txt b/Tests/Properties/CMakeLists.txt
new file mode 100644
index 0000000..a1158c6
--- /dev/null
+++ b/Tests/Properties/CMakeLists.txt
@@ -0,0 +1,353 @@
+# a simple CXX only test case
+cmake_minimum_required (VERSION 2.6)
+project (Properties)
+
+# these first three tests really test both properties and the management of
+# cmSourceFile objects by CMake.
+
+# test properties on a build tree file that is relative (yuck)
+configure_file(properties.h.in "${Properties_BINARY_DIR}/properties.h")
+set_source_files_properties(properties.h PROPERTIES TEST1 1)
+get_source_file_property(RESULT1 properties.h TEST1)
+
+# test properties on a headerfile in the source tree
+# accessed without an extension (also yuck)
+set_source_files_properties(properties2 PROPERTIES TEST2 1)
+get_source_file_property(RESULT2 properties2 TEST2)
+
+# test properties on a relative source that is not generated
+set_source_files_properties(SubDir/properties3.cxx PROPERTIES TEST3 1)
+get_source_file_property(RESULT3 SubDir/properties3.cxx TEST3)
+
+include_directories("${Properties_SOURCE_DIR}" "${Properties_BINARY_DIR}")
+
+
+# test generic property interfaces
+get_property(GLOBALRESULT GLOBAL PROPERTY GLOBALTEST DEFINED)
+if (GLOBALRESULT)
+ message(SEND_ERROR "Error: global prop defined when it should not be, "
+ "result is GLOBALRESULT=${GLOBALRESULT}")
+endif ()
+
+define_property(GLOBAL PROPERTY GLOBALTEST
+ BRIEF_DOCS "A test property"
+ FULL_DOCS "A long description of this test property"
+ )
+
+get_property(GLOBALRESULT GLOBAL PROPERTY GLOBALTEST DEFINED)
+if (NOT GLOBALRESULT)
+ message(SEND_ERROR "Error: global prop not defined "
+ "result is GLOBALRESULT=${GLOBALRESULT}")
+endif ()
+
+set_property(GLOBAL PROPERTY GLOBALTEST 1)
+set_property(DIRECTORY PROPERTY DIRECTORYTEST 1)
+set_property(SOURCE SubDir/properties3.cxx PROPERTY SOURCETEST 1)
+get_property(GLOBALRESULT GLOBAL PROPERTY GLOBALTEST)
+get_property(DIRECTORYRESULT DIRECTORY PROPERTY DIRECTORYTEST)
+get_property(SOURCERESULT
+ SOURCE SubDir/properties3.cxx
+ PROPERTY SOURCETEST
+ )
+
+if (RESULT1 AND RESULT2 AND RESULT3 AND GLOBALRESULT AND
+ DIRECTORYRESULT AND SOURCERESULT)
+ add_executable (Properties SubDir/properties3.cxx properties)
+else ()
+ message(SEND_ERROR
+ "Error: test results are RESULT1=${RESULT1} RESULT2=${RESULT2} "
+ "RESULT3=${RESULT3} GLOBALRESULT=${GLOBALRESULT} "
+ "DIRECTORYRESULT=${DIRECTORYRESULT} "
+ "SOURCERESULT=${SOURCERESULT}")
+endif ()
+
+# test the target property
+set_property(TARGET Properties PROPERTY TARGETTEST 1)
+get_property(TARGETRESULT TARGET Properties PROPERTY TARGETTEST)
+if (NOT TARGETRESULT)
+ message(SEND_ERROR
+ "Error: target result is TARGETRESULT=${TARGETRESULT}")
+endif ()
+
+# test APPEND and APPEND_STRING set_property()
+set_property(TARGET Properties PROPERTY FOO foo)
+set_property(TARGET Properties PROPERTY BAR bar)
+set_property(TARGET Properties APPEND PROPERTY FOO 123)
+set_property(TARGET Properties APPEND_STRING PROPERTY BAR 456)
+
+get_property(APPEND_RESULT TARGET Properties PROPERTY FOO)
+if (NOT "${APPEND_RESULT}" STREQUAL "foo;123")
+ message(SEND_ERROR
+ "Error: target result is APPEND_RESULT=${APPEND_RESULT}")
+endif ()
+
+get_property(APPEND_STRING_RESULT TARGET Properties PROPERTY BAR)
+if (NOT "${APPEND_STRING_RESULT}" STREQUAL "bar456")
+ message(SEND_ERROR
+ "Error: target result is APPEND_STRING_RESULT=${APPEND_STRING_RESULT}")
+endif ()
+
+# test get_property SET
+get_property(TARGETRESULT TARGET Properties PROPERTY TARGETTEST SET)
+if (NOT TARGETRESULT)
+ message(SEND_ERROR
+ "Error: target prop not set, result is TARGETRESULT=${TARGETRESULT}")
+endif ()
+
+# test unsetting a property
+set_property(TARGET Properties PROPERTY TARGETTEST)
+get_property(TARGETRESULT TARGET Properties PROPERTY TARGETTEST SET)
+if (TARGETRESULT)
+ message(SEND_ERROR "Error: target prop not unset, "
+ "result is TARGETRESULT=${TARGETRESULT}")
+endif ()
+
+
+
+# test the target SOURCES property
+get_property(Properties_SOURCES TARGET Properties PROPERTY SOURCES)
+set_source_files_properties(${Properties_SOURCES} PROPERTIES TEST4 1)
+get_source_file_property(RESULT4 properties.h TEST4)
+if(NOT RESULT4)
+ message(SEND_ERROR "Error: target result is"
+ " RESULT4=${RESULT4}"
+ " Properties_SOURCES=[${Properties_SOURCES}]")
+endif()
+
+# test CACHE properties
+macro(check_cache_props)
+ foreach(prop VALUE TYPE HELPSTRING ADVANCED STRINGS)
+ get_property(result CACHE SOME_ENTRY PROPERTY ${prop})
+ if(NOT "x${result}" STREQUAL "x${expect_${prop}}")
+ message(SEND_ERROR "CACHE property ${prop} is [${result}], not [${expect_${prop}}]")
+ endif()
+ endforeach()
+endmacro()
+set(expect_VALUE "ON")
+set(expect_TYPE "BOOL")
+set(expect_HELPSTRING "sample cache entry")
+set(expect_ADVANCED 0)
+set(expect_STRINGS "")
+set(SOME_ENTRY "${expect_VALUE}" CACHE ${expect_TYPE} "${expect_HELPSTRING}" FORCE)
+mark_as_advanced(CLEAR SOME_ENTRY)
+set_property(CACHE SOME_ENTRY PROPERTY STRINGS "")
+check_cache_props()
+set(expect_VALUE "Some string")
+set(expect_TYPE "STRING")
+set(expect_HELPSTRING "sample cache entry help")
+set(expect_ADVANCED 1)
+set(expect_STRINGS "Some string;Some other string;Some third string")
+set_property(CACHE SOME_ENTRY PROPERTY TYPE "${expect_TYPE}")
+set_property(CACHE SOME_ENTRY PROPERTY HELPSTRING "${expect_HELPSTRING}")
+set_property(CACHE SOME_ENTRY PROPERTY VALUE "${expect_VALUE}")
+set_property(CACHE SOME_ENTRY PROPERTY ADVANCED "${expect_ADVANCED}")
+set_property(CACHE SOME_ENTRY PROPERTY STRINGS "${expect_STRINGS}")
+check_cache_props()
+
+function(generate_file_for_set_property_test i target_name)
+ set(src_path "${CMAKE_CURRENT_BINARY_DIR}/src${i}.cpp")
+ file(CONFIGURE OUTPUT "${src_path}" CONTENT
+ "#ifndef def${i}\n\
+ #error Expected def${i}\n\
+ #endif\n\
+ #ifdef _WIN32\n\
+ __declspec(dllexport)\n\
+ #endif\n\
+ void dummy_symbol${i}() {}\n"
+ NEWLINE_STYLE UNIX)
+ target_sources(${target_name} PRIVATE "${src_path}")
+endfunction()
+
+add_library(maindirtest SHARED)
+
+# Generate file to be used with both DIRECTORY and TARGET_DIRECTORY options in
+# set_source_files_properties and set_property().
+generate_file_for_set_property_test(32 maindirtest)
+generate_file_for_set_property_test(33 maindirtest)
+
+# Set/get properties by binary directory path.
+add_subdirectory(SubDir SubDirA)
+get_property(dir_prop_top DIRECTORY PROPERTY dir_prop_top)
+if(NOT dir_prop_top STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/SubDirA")
+ message(SEND_ERROR "dir_prop_top unexpected value after SubDirA:\n ${dir_prop_top}")
+endif()
+add_subdirectory(SubDir SubDirB)
+get_property(dir_prop_top DIRECTORY PROPERTY dir_prop_top)
+if(NOT dir_prop_top STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/SubDirB")
+ message(SEND_ERROR "dir_prop_top unexpected value after SubDirB:\n ${dir_prop_top}")
+endif()
+get_property(dir_prop_subA DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/SubDirA PROPERTY dir_prop_sub)
+if(NOT dir_prop_subA STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/SubDirA")
+ message(SEND_ERROR "SubDirA property dir_prop_sub incorrect:\n ${dir_prop_subA}")
+endif()
+get_property(dir_prop_subB DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/SubDirB PROPERTY dir_prop_sub)
+if(NOT dir_prop_subB STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/SubDirB")
+ message(SEND_ERROR "SubDirB property dir_prop_sub incorrect:\n ${dir_prop_subB}")
+endif()
+get_directory_property(dir_prop_subA DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/SubDirA dir_prop_sub)
+if(NOT dir_prop_subA STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/SubDirA")
+ message(SEND_ERROR "SubDirA property dir_prop_sub incorrect:\n ${dir_prop_subA}")
+endif()
+get_directory_property(dir_prop_subB DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/SubDirB dir_prop_sub)
+if(NOT dir_prop_subB STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/SubDirB")
+ message(SEND_ERROR "SubDirB property dir_prop_sub incorrect:\n ${dir_prop_subB}")
+endif()
+
+add_subdirectory(SubDir2)
+
+set(src_prefix "${CMAKE_CURRENT_BINARY_DIR}/SubDir2/")
+
+# Set property + target directory
+set_property(SOURCE "${src_prefix}/src1.cpp"
+ TARGET_DIRECTORY set_prop_lib_1
+ PROPERTY COMPILE_DEFINITIONS def1)
+
+# Append property + target directory
+set_property(SOURCE "${src_prefix}/src2.cpp"
+ TARGET_DIRECTORY set_prop_lib_1
+ APPEND PROPERTY COMPILE_DEFINITIONS def2)
+
+# Set property + relative directory path
+set_property(SOURCE "${src_prefix}/src3.cpp"
+ DIRECTORY SubDir2
+ PROPERTY COMPILE_DEFINITIONS def3)
+
+# Set property + absolute directory path
+set_property(SOURCE "${src_prefix}/src4.cpp"
+ DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/SubDir2"
+ PROPERTY COMPILE_DEFINITIONS def4)
+
+# Append property + relative directory path
+set_property(SOURCE "${src_prefix}/src5.cpp"
+ DIRECTORY SubDir2
+ APPEND PROPERTY COMPILE_DEFINITIONS def5)
+
+# Append property + absolute directory path
+set_property(SOURCE "${src_prefix}/src6.cpp"
+ DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/SubDir2"
+ APPEND PROPERTY COMPILE_DEFINITIONS def6)
+
+
+# Target directory
+set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src10.cpp"
+ TARGET_DIRECTORY set_prop_lib_1
+ PROPERTIES COMPILE_DEFINITIONS def10)
+
+# Relative directory path
+set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src11.cpp"
+ DIRECTORY SubDir2
+ PROPERTIES COMPILE_DEFINITIONS def11)
+
+# Absolute directory path
+set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src12.cpp"
+ DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/SubDir2"
+ PROPERTIES COMPILE_DEFINITIONS def12)
+
+
+# Multiple files + absolute directory path
+set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src20.cpp"
+ "${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src21.cpp"
+ DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/SubDir2"
+ PROPERTIES COMPILE_DEFINITIONS "def20;def21")
+
+# Multiple files + multiple target directories
+set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src22.cpp"
+ "${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src23.cpp"
+ TARGET_DIRECTORY set_prop_lib_2 set_prop_lib_3
+ PROPERTIES COMPILE_DEFINITIONS "def22;def23")
+
+
+# Multiple files in multiple relative directories
+generate_file_for_set_property_test(30 maindirtest)
+set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/src30.cpp"
+ "${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src31.cpp"
+ DIRECTORY . SubDir2
+ PROPERTIES COMPILE_DEFINITIONS "def30;def31")
+
+# Check that specifying files without any properties doesn't crash.
+set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/src30.cpp"
+ "${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src31.cpp")
+
+
+# Check that specifying both DIRECTORY and TARGET_DIRECTORY works.
+set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/src32.cpp"
+ DIRECTORY .
+ TARGET_DIRECTORY set_prop_lib_3
+ PROPERTIES COMPILE_DEFINITIONS "def32")
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/src33.cpp"
+ DIRECTORY SubDir2
+ TARGET_DIRECTORY maindirtest
+ PROPERTY COMPILE_DEFINITIONS "def33")
+
+
+function(check_get_property_value expected)
+ if(NOT actual STREQUAL expected)
+ message(SEND_ERROR "Error: get_property returned unexpected value\n"
+ "actual: ${actual}\n"
+ "expected: ${expected}")
+ endif()
+endfunction()
+
+# Check that source file directory scopes are deduplicated.
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/src32.cpp"
+ DIRECTORY SubDir2 SubDir2 SubDir2
+ TARGET_DIRECTORY set_prop_lib_3 set_prop_lib_3 set_prop_lib_3
+ APPEND
+ PROPERTY NON_DUPLICATED_CUSTOM_PROP 1
+)
+
+get_property(actual
+ SOURCE "${CMAKE_CURRENT_BINARY_DIR}/src32.cpp"
+ DIRECTORY SubDir2
+ PROPERTY NON_DUPLICATED_CUSTOM_PROP)
+check_get_property_value("1")
+
+get_source_file_property(actual "${CMAKE_CURRENT_BINARY_DIR}/src32.cpp"
+ TARGET_DIRECTORY set_prop_lib_3
+ NON_DUPLICATED_CUSTOM_PROP)
+check_get_property_value("1")
+
+# Get property + target directory
+get_property(actual
+ SOURCE "${src_prefix}/src1.cpp"
+ TARGET_DIRECTORY set_prop_lib_1
+ PROPERTY COMPILE_DEFINITIONS)
+check_get_property_value("def1")
+
+# Get property + relative directory path
+get_property(actual
+ SOURCE "${src_prefix}/src3.cpp"
+ DIRECTORY SubDir2
+ PROPERTY COMPILE_DEFINITIONS)
+check_get_property_value("def3")
+
+# Get property + absolute directory path
+get_property(actual
+ SOURCE "${src_prefix}/src4.cpp"
+ DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/SubDir2"
+ PROPERTY COMPILE_DEFINITIONS)
+check_get_property_value("def4")
+
+
+# Get property + target directory
+unset(actual)
+get_source_file_property(actual
+ "${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src10.cpp"
+ TARGET_DIRECTORY set_prop_lib_1
+ COMPILE_DEFINITIONS)
+check_get_property_value("def10")
+
+# Get property + relative directory path
+get_source_file_property(actual
+ "${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src11.cpp"
+ DIRECTORY SubDir2
+ COMPILE_DEFINITIONS)
+check_get_property_value("def11")
+
+# Get property + absolute directory path
+get_source_file_property(actual
+ "${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src12.cpp"
+ DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/SubDir2"
+ COMPILE_DEFINITIONS)
+check_get_property_value("def12")
diff --git a/Tests/Properties/SubDir/CMakeLists.txt b/Tests/Properties/SubDir/CMakeLists.txt
new file mode 100644
index 0000000..f34cc8c
--- /dev/null
+++ b/Tests/Properties/SubDir/CMakeLists.txt
@@ -0,0 +1,2 @@
+set_property(DIRECTORY PROPERTY dir_prop_sub ${CMAKE_CURRENT_BINARY_DIR})
+set_property(DIRECTORY ${CMAKE_BINARY_DIR} PROPERTY dir_prop_top ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/Tests/Properties/SubDir/properties3.cxx b/Tests/Properties/SubDir/properties3.cxx
new file mode 100644
index 0000000..6d24fbb
--- /dev/null
+++ b/Tests/Properties/SubDir/properties3.cxx
@@ -0,0 +1,9 @@
+#include "properties.h"
+#include "properties2.h"
+
+#if defined HAVE_PROPERTIES_H && defined HAVE_PROPERTIES2_H
+int main()
+{
+ return 0;
+}
+#endif
diff --git a/Tests/Properties/SubDir2/CMakeLists.txt b/Tests/Properties/SubDir2/CMakeLists.txt
new file mode 100644
index 0000000..88e5531
--- /dev/null
+++ b/Tests/Properties/SubDir2/CMakeLists.txt
@@ -0,0 +1,34 @@
+
+set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/../subdirtest.cxx"
+ PROPERTIES COMPILE_DEFINITIONS SUBDIR_TEST)
+
+add_executable(subdirtest "${CMAKE_CURRENT_SOURCE_DIR}/../subdirtest.cxx")
+
+# For set_property
+add_library(set_prop_lib_1 SHARED)
+foreach(i RANGE 1 6)
+ generate_file_for_set_property_test(${i} set_prop_lib_1)
+endforeach()
+
+# For set_source_files_properties
+foreach(i RANGE 10 12)
+ generate_file_for_set_property_test(${i} set_prop_lib_1)
+endforeach()
+
+# For set_source_files_properties + multiple files + absolute directory path
+add_library(set_prop_lib_2 SHARED)
+foreach(i RANGE 20 21)
+ generate_file_for_set_property_test(${i} set_prop_lib_1)
+endforeach()
+
+# For set_source_files_properties + multiple files + multiple target directories
+add_library(set_prop_lib_3 SHARED)
+generate_file_for_set_property_test(22 set_prop_lib_2)
+generate_file_for_set_property_test(23 set_prop_lib_3)
+
+# For set_source_files_properties + multiple files in multiple directories
+generate_file_for_set_property_test(31 set_prop_lib_3)
+
+# For specifying both DIRECTORY and TARGET_DIRECTORY
+target_sources(set_prop_lib_3 PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/../src32.cpp")
+target_sources(set_prop_lib_3 PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/../src33.cpp")
diff --git a/Tests/Properties/properties.h.in b/Tests/Properties/properties.h.in
new file mode 100644
index 0000000..5e92831
--- /dev/null
+++ b/Tests/Properties/properties.h.in
@@ -0,0 +1 @@
+#define HAVE_PROPERTIES_H
diff --git a/Tests/Properties/properties2.h b/Tests/Properties/properties2.h
new file mode 100644
index 0000000..898fd9e
--- /dev/null
+++ b/Tests/Properties/properties2.h
@@ -0,0 +1 @@
+#define HAVE_PROPERTIES2_H
diff --git a/Tests/Properties/subdirtest.cxx b/Tests/Properties/subdirtest.cxx
new file mode 100644
index 0000000..23f1048
--- /dev/null
+++ b/Tests/Properties/subdirtest.cxx
@@ -0,0 +1,9 @@
+
+#ifndef SUBDIR_TEST
+# error Expected SUBDIR_TEST
+#endif
+
+int main(int, char**)
+{
+ return 0;
+}
diff --git a/Tests/PythonCoverage/DartConfiguration.tcl.in b/Tests/PythonCoverage/DartConfiguration.tcl.in
new file mode 100644
index 0000000..e29cffe
--- /dev/null
+++ b/Tests/PythonCoverage/DartConfiguration.tcl.in
@@ -0,0 +1,8 @@
+# This file is configured by CMake automatically as DartConfiguration.tcl
+# If you choose not to use CMake, this file may be hand configured, by
+# filling in the required variables.
+
+
+# Configuration directories and files
+SourceDirectory: ${CMake_BINARY_DIR}/Testing/PythonCoverage/coveragetest
+BuildDirectory: ${CMake_BINARY_DIR}/Testing/PythonCoverage
diff --git a/Tests/PythonCoverage/coverage.xml.in b/Tests/PythonCoverage/coverage.xml.in
new file mode 100644
index 0000000..fcc1b1c
--- /dev/null
+++ b/Tests/PythonCoverage/coverage.xml.in
@@ -0,0 +1,35 @@
+<?xml version="1.0" ?>
+<!DOCTYPE coverage
+ SYSTEM 'http://cobertura.sourceforge.net/xml/coverage-03.dtd'>
+<coverage branch-rate="0" line-rate="0.8462" timestamp="1380469411433" version="3.6">
+ <!-- Generated by coverage.py: http://nedbatchelder.com/code/coverage -->
+ <packages>
+ <package branch-rate="0" complexity="0" line-rate="0.8462" name="">
+ <classes>
+ <class branch-rate="0" complexity="0" filename="foo.py" line-rate="0.6667" name="foo">
+ <methods/>
+ <lines>
+ <line hits="1" number="2"/>
+ <line hits="1" number="3"/>
+ <line hits="1" number="4"/>
+ <line hits="1" number="6"/>
+ <line hits="0" number="7"/>
+ <line hits="0" number="8"/>
+ </lines>
+ </class>
+ <class branch-rate="0" complexity="0" filename="test_foo.py" line-rate="1" name="test_foo">
+ <methods/>
+ <lines>
+ <line hits="1" number="2"/>
+ <line hits="1" number="3"/>
+ <line hits="1" number="5"/>
+ <line hits="1" number="7"/>
+ <line hits="1" number="8"/>
+ <line hits="1" number="10"/>
+ <line hits="1" number="11"/>
+ </lines>
+ </class>
+ </classes>
+ </package>
+ </packages>
+</coverage>
diff --git a/Tests/PythonCoverage/coveragetest/foo.py b/Tests/PythonCoverage/coveragetest/foo.py
new file mode 100644
index 0000000..97b5a41
--- /dev/null
+++ b/Tests/PythonCoverage/coveragetest/foo.py
@@ -0,0 +1,8 @@
+
+def foo():
+ x = 3 + 3
+ return x
+
+def bar():
+ y = 2 + 2
+ return y
diff --git a/Tests/PythonCoverage/coveragetest/test_foo.py b/Tests/PythonCoverage/coveragetest/test_foo.py
new file mode 100644
index 0000000..51a69d8
--- /dev/null
+++ b/Tests/PythonCoverage/coveragetest/test_foo.py
@@ -0,0 +1,11 @@
+
+import foo
+import unittest
+
+class TestFoo(unittest.TestCase):
+
+ def testFoo(self):
+ self.assertEquals(foo.foo(), 6, 'foo() == 6')
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tests/Qt4And5Automoc/CMakeLists.txt b/Tests/Qt4And5Automoc/CMakeLists.txt
new file mode 100644
index 0000000..ad74961
--- /dev/null
+++ b/Tests/Qt4And5Automoc/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(Qt4And5Automoc)
+
+if (QT_REVERSE_FIND_ORDER)
+ find_package(Qt5Core REQUIRED)
+ find_package(Qt4 REQUIRED)
+else()
+ find_package(Qt4 REQUIRED)
+ find_package(Qt5Core REQUIRED)
+endif()
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+macro(generate_main_file VERSION)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/main.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/main_qt${VERSION}.cpp" COPYONLY)
+ file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/main_qt${VERSION}.cpp"
+ "#include \"main_qt${VERSION}.moc\"\n"
+ )
+endmacro()
+
+generate_main_file(4)
+generate_main_file(5)
+
+add_executable(qt4_exe "${CMAKE_CURRENT_BINARY_DIR}/main_qt4.cpp")
+target_link_libraries(qt4_exe Qt4::QtCore)
+add_executable(qt5_exe "${CMAKE_CURRENT_BINARY_DIR}/main_qt5.cpp")
+target_link_libraries(qt5_exe Qt5::Core)
diff --git a/Tests/Qt4And5Automoc/main.cpp.in b/Tests/Qt4And5Automoc/main.cpp.in
new file mode 100644
index 0000000..00fd641
--- /dev/null
+++ b/Tests/Qt4And5Automoc/main.cpp.in
@@ -0,0 +1,18 @@
+
+#include <QObject>
+
+class SomeObject : public QObject
+{
+ Q_OBJECT
+public:
+ explicit SomeObject(QObject *parent = 0)
+ : QObject(parent)
+ {
+
+ }
+};
+
+int main(int argc, char **argv)
+{
+ return 0;
+}
diff --git a/Tests/Qt4Autogen/CMakeLists.txt b/Tests/Qt4Autogen/CMakeLists.txt
new file mode 100644
index 0000000..e7f1ae3
--- /dev/null
+++ b/Tests/Qt4Autogen/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Set Qt test version and include the Autogen test macros
+set(QT_TEST_VERSION 4)
+include("../QtAutogen/TestMacros.cmake")
+
+# Qt4 only tests
+ADD_AUTOGEN_TEST(DefinesTest)
+
+# Common tests
+include("../QtAutogen/Tests.cmake")
+
+set(TEST_BUILD_DIRS "${TEST_BUILD_DIRS}" PARENT_SCOPE)
diff --git a/Tests/Qt4Deploy/CMakeLists.txt b/Tests/Qt4Deploy/CMakeLists.txt
new file mode 100644
index 0000000..c73a38c
--- /dev/null
+++ b/Tests/Qt4Deploy/CMakeLists.txt
@@ -0,0 +1,71 @@
+cmake_minimum_required(VERSION 3.9)
+
+project(Qt4Deploy)
+set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/install)
+
+find_package(Qt4 REQUIRED QtMain QtCore QtSql)
+include(${QT_USE_FILE})
+
+add_executable(testdeploy MACOSX_BUNDLE testdeploy.cpp)
+target_link_libraries(testdeploy ${QT_LIBRARIES})
+set_target_properties(testdeploy PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}")
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig AND QT_QTCORE_LIBRARY_RELEASE AND QT_QTCORE_LIBRARY_DEBUG)
+ # note: installing debug Qt libraries from a Qt installation configured with
+ # -debug-and-release not yet supported (very low priority).
+ install(CODE "
+ if(\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^([Dd][Ee][Bb][Uu][Gg])$\")
+ return()
+ endif()
+ ")
+endif()
+
+# install the Qt4 app with qsqlite plugin
+install(CODE "file(REMOVE_RECURSE \"${CMAKE_INSTALL_PREFIX}\")")
+install(TARGETS testdeploy DESTINATION .)
+include(../../Modules/DeployQt4.cmake)
+if(APPLE)
+ install_qt4_executable(testdeploy.app "qsqlite")
+elseif(WIN32)
+ install_qt4_executable(testdeploy.exe "qsqlite")
+else()
+ install_qt4_executable(testdeploy "qsqlite")
+endif()
+
+
+# test depends on standard qsqlite plugin
+if(QT_QSQLITE_PLUGIN_DEBUG OR QT_QSQLITE_PLUGIN_RELEASE)
+
+ # test the deployed Qt application
+ if(APPLE)
+ install(CODE "
+ message(STATUS \"executing: ${CMAKE_INSTALL_PREFIX}/testdeploy.app/Contents/MacOS/testdeploy\")
+ execute_process(COMMAND \"${CMAKE_INSTALL_PREFIX}/testdeploy.app/Contents/MacOS/testdeploy\"
+ RESULT_VARIABLE result)
+ if(NOT result STREQUAL \"0\")
+ message(FATAL_ERROR \"error running testdeploy app\")
+ endif()
+ ")
+ else()
+ install(CODE "
+ message(STATUS \"executing: ${CMAKE_INSTALL_PREFIX}/testdeploy\")
+ execute_process(COMMAND \"${CMAKE_INSTALL_PREFIX}/testdeploy\"
+ RESULT_VARIABLE result)
+ if(NOT result STREQUAL \"0\")
+ message(FATAL_ERROR \"error running testdeploy app\")
+ endif()
+ ")
+ endif()
+
+ # custom target to install and test the installation at build time
+ if(_isMultiConfig)
+ set(install_config "-DCMAKE_INSTALL_CONFIG_NAME=${CMAKE_CFG_INTDIR}")
+ endif()
+
+ add_custom_target(testdeploy_test ALL
+ COMMAND ${CMAKE_COMMAND} ${install_config} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake
+ COMMENT "${CMAKE_COMMAND} ${install_config} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake"
+ DEPENDS testdeploy)
+
+endif()
diff --git a/Tests/Qt4Deploy/testdeploy.cpp b/Tests/Qt4Deploy/testdeploy.cpp
new file mode 100644
index 0000000..33c0bb3
--- /dev/null
+++ b/Tests/Qt4Deploy/testdeploy.cpp
@@ -0,0 +1,29 @@
+#include <QCoreApplication>
+#include <QDebug>
+#include <QLibraryInfo>
+#include <QSqlDatabase>
+#include <QStringList>
+
+int main(int argc, char** argv)
+{
+ QCoreApplication app(argc, argv);
+
+ qDebug() << "App path:" << app.applicationDirPath();
+ qDebug() << "Plugin path:"
+ << QLibraryInfo::location(QLibraryInfo::PluginsPath);
+
+ bool foundSqlite = false;
+
+ qDebug() << "Supported Database Drivers:";
+ foreach (const QString& sqlDriver, QSqlDatabase::drivers()) {
+ qDebug() << " " << sqlDriver;
+ if (sqlDriver == "QSQLITE")
+ foundSqlite = true;
+ }
+
+ if (foundSqlite)
+ qDebug() << "Found sqlite support from plugin.";
+ else
+ qDebug() << "Could not find sqlite support from plugin.";
+ return foundSqlite ? 0 : 1;
+}
diff --git a/Tests/Qt4Targets/CMakeLists.txt b/Tests/Qt4Targets/CMakeLists.txt
new file mode 100644
index 0000000..3ddc345
--- /dev/null
+++ b/Tests/Qt4Targets/CMakeLists.txt
@@ -0,0 +1,90 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(Qt4Targets)
+
+cmake_policy(SET CMP0020 NEW)
+
+find_package(Qt4 REQUIRED)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_executable(Qt4Targets WIN32 main.cpp)
+target_link_libraries(Qt4Targets Qt4::QtGui)
+
+if (WIN32)
+ if (TARGET Qt4::QAxServer)
+ add_executable(activeqtexe WIN32 activeqtexe.cpp)
+ set_property(TARGET activeqtexe PROPERTY QT4_NO_LINK_QTMAIN ON)
+ target_link_libraries(activeqtexe Qt4::QAxServer Qt4::QtGui)
+ endif()
+endif()
+
+# Qt4 moc does not support utf8 paths in _parameter files generated by
+# qt4_wrap_cpp and qt4_generate_moc
+# https://bugreports.qt.io/browse/QTBUG-35480
+# Do a simple check if there is are non ASCII character in the build path
+string(REGEX MATCH "[^ -~]+" NON_ASCII_BDIR ${CMAKE_CURRENT_BINARY_DIR})
+if(NON_ASCII_BDIR)
+ message(WARNING "Build path contains non ASCII characters. Skipping Qt4 test.")
+ return()
+endif()
+
+qt4_generate_moc(main_gen_test.cpp
+ "${CMAKE_CURRENT_BINARY_DIR}/main_gen_test.moc"
+ TARGET Qt4GenerateMacroTest
+)
+add_executable(Qt4GenerateMacroTest WIN32 main_gen_test.cpp "${CMAKE_CURRENT_BINARY_DIR}/main_gen_test.moc")
+set_property(TARGET Qt4GenerateMacroTest PROPERTY AUTOMOC OFF)
+target_include_directories(Qt4GenerateMacroTest PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/interface")
+target_link_libraries(Qt4GenerateMacroTest Qt4::QtGui)
+
+qt4_wrap_cpp(moc_file mywrapobject.h
+ TARGET Qt4WrapMacroTest
+)
+add_executable(Qt4WrapMacroTest WIN32 main_wrap_test.cpp ${moc_file})
+set_property(TARGET Qt4WrapMacroTest PROPERTY AUTOMOC OFF)
+target_include_directories(Qt4WrapMacroTest PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/interface")
+target_link_libraries(Qt4WrapMacroTest Qt4::QtGui)
+
+macro(test_incremental def)
+ set(timeformat "%Y%j%H%M%S")
+ try_compile(RESULT
+ "${CMAKE_CURRENT_BINARY_DIR}/IncrementalMocBuild_${def}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/IncrementalMoc"
+ IncrementalMoc
+ CMAKE_FLAGS -D${def}=0 "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+ OUTPUT_VARIABLE output
+ )
+ file(TIMESTAMP "${CMAKE_CURRENT_BINARY_DIR}/IncrementalMocBuild_${def}/moc_foo.cpp" tsvar_before "${timeformat}")
+ if (NOT tsvar_before)
+ message(SEND_ERROR
+ "Unable to read timestamp from moc file from first build with -D${def}!\n"
+ "try_compile output:\n${output}"
+ )
+ endif()
+
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 2) # Ensure that the timestamp will change.
+
+ try_compile(RESULT
+ "${CMAKE_CURRENT_BINARY_DIR}/IncrementalMocBuild_${def}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/IncrementalMoc"
+ IncrementalMoc
+ CMAKE_FLAGS -D${def}=1 "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+ OUTPUT_VARIABLE output
+ )
+ file(TIMESTAMP "${CMAKE_CURRENT_BINARY_DIR}/IncrementalMocBuild_${def}/moc_foo.cpp" tsvar_after "${timeformat}")
+ if (NOT tsvar_after)
+ message(SEND_ERROR
+ "Unable to read timestamp from moc file from second build!\n"
+ "try_compile output:\n${output}"
+ )
+ endif()
+
+ if (NOT tsvar_after GREATER tsvar_before)
+ message(SEND_ERROR "Rebuild did not re-create moc file with -D${def}. Before: ${tsvar_before}. After: ${tsvar_after}")
+ endif()
+endmacro()
+
+test_incremental(ADD_TARGET_DEF)
+test_incremental(ADD_DIR_DEF)
diff --git a/Tests/Qt4Targets/IncrementalMoc/CMakeLists.txt b/Tests/Qt4Targets/IncrementalMoc/CMakeLists.txt
new file mode 100644
index 0000000..65e2b64
--- /dev/null
+++ b/Tests/Qt4Targets/IncrementalMoc/CMakeLists.txt
@@ -0,0 +1,21 @@
+
+cmake_minimum_required(VERSION 2.8.12)
+project(IncrementalMoc)
+
+find_package(Qt4 REQUIRED)
+
+if (ADD_TARGET_DEF)
+ set(target_args TARGET testlib)
+endif()
+
+if (ADD_DIR_DEF)
+ add_definitions(-DNEW_DEF)
+endif()
+
+qt4_generate_moc(foo.h moc_foo.cpp ${target_args})
+
+add_library(testlib foo.cpp moc_foo.cpp)
+target_link_libraries(testlib Qt4::QtCore)
+if (ADD_TARGET_DEF)
+ target_compile_definitions(testlib PRIVATE NEW_DEF)
+endif()
diff --git a/Tests/Qt4Targets/IncrementalMoc/foo.cpp b/Tests/Qt4Targets/IncrementalMoc/foo.cpp
new file mode 100644
index 0000000..00685d0
--- /dev/null
+++ b/Tests/Qt4Targets/IncrementalMoc/foo.cpp
@@ -0,0 +1,7 @@
+
+#include "foo.h"
+
+Foo::Foo()
+ : QObject(0)
+{
+}
diff --git a/Tests/Qt4Targets/IncrementalMoc/foo.h b/Tests/Qt4Targets/IncrementalMoc/foo.h
new file mode 100644
index 0000000..38d899f
--- /dev/null
+++ b/Tests/Qt4Targets/IncrementalMoc/foo.h
@@ -0,0 +1,9 @@
+
+#include <QObject>
+
+class Foo : QObject
+{
+ Q_OBJECT
+public:
+ Foo();
+};
diff --git a/Tests/Qt4Targets/activeqtexe.cpp b/Tests/Qt4Targets/activeqtexe.cpp
new file mode 100644
index 0000000..98176f1
--- /dev/null
+++ b/Tests/Qt4Targets/activeqtexe.cpp
@@ -0,0 +1,35 @@
+
+#include <QApplication>
+
+#ifndef QT_QAXSERVER_LIB
+# error Expected QT_QAXSERVER_LIB
+#endif
+
+#include <QAxFactory>
+
+class MyObject : public QObject
+{
+ Q_OBJECT
+public:
+ MyObject(QObject* parent = 0)
+ : QObject(parent)
+ {
+ }
+};
+
+QAXFACTORY_DEFAULT(MyObject, "{4dc3f340-a6f7-44e4-a79b-3e9217685fbd}",
+ "{9ee49617-7d5c-441a-b833-4b068d41d751}",
+ "{13eca64b-ee2a-4f3c-aa04-5d9d975779a7}",
+ "{ce947ee3-0403-4fdc-895a-4fe779344b46}",
+ "{8de435ce-8d2a-46ac-b3b3-cb800d0547c7}");
+
+int main(int argc, char** argv)
+{
+ QApplication app(argc, argv);
+
+ QAxFactory::isServer();
+
+ return app.exec();
+}
+
+#include "activeqtexe.moc"
diff --git a/Tests/Qt4Targets/interface/myinterface.h b/Tests/Qt4Targets/interface/myinterface.h
new file mode 100644
index 0000000..5cc3b27
--- /dev/null
+++ b/Tests/Qt4Targets/interface/myinterface.h
@@ -0,0 +1,11 @@
+
+#ifndef MYINTERFACE_H
+#define MYINTERFACE_H
+
+class MyInterface
+{
+};
+
+Q_DECLARE_INTERFACE(MyInterface, "org.cmake.example.MyInterface")
+
+#endif
diff --git a/Tests/Qt4Targets/main.cpp b/Tests/Qt4Targets/main.cpp
new file mode 100644
index 0000000..fc7f580
--- /dev/null
+++ b/Tests/Qt4Targets/main.cpp
@@ -0,0 +1,23 @@
+
+#include <QApplication>
+#include <QString>
+#include <QWidget>
+
+#ifndef QT_CORE_LIB
+# error Expected QT_CORE_LIB
+#endif
+
+#ifndef QT_GUI_LIB
+# error Expected QT_GUI_LIB
+#endif
+
+int main(int argc, char** argv)
+{
+ QApplication app(argc, argv);
+
+ QWidget w;
+ w.setWindowTitle(QString::fromLatin1("SomeTitle"));
+ w.show();
+
+ return 0;
+}
diff --git a/Tests/Qt4Targets/main_gen_test.cpp b/Tests/Qt4Targets/main_gen_test.cpp
new file mode 100644
index 0000000..6616e84
--- /dev/null
+++ b/Tests/Qt4Targets/main_gen_test.cpp
@@ -0,0 +1,26 @@
+
+#include <QObject>
+
+#include "myinterface.h"
+
+class MyObject
+ : public QObject
+ , MyInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(MyInterface)
+public:
+ explicit MyObject(QObject* parent = 0)
+ : QObject(parent)
+ {
+ }
+};
+
+int main(int argc, char** argv)
+{
+ MyObject mo;
+ mo.objectName();
+ return 0;
+}
+
+#include "main_gen_test.moc"
diff --git a/Tests/Qt4Targets/main_wrap_test.cpp b/Tests/Qt4Targets/main_wrap_test.cpp
new file mode 100644
index 0000000..7b74849
--- /dev/null
+++ b/Tests/Qt4Targets/main_wrap_test.cpp
@@ -0,0 +1,11 @@
+
+#include <QObject>
+
+#include "mywrapobject.h"
+
+int main(int argc, char** argv)
+{
+ MyWrapObject mwo;
+ mwo.objectName();
+ return 0;
+}
diff --git a/Tests/Qt4Targets/mywrapobject.h b/Tests/Qt4Targets/mywrapobject.h
new file mode 100644
index 0000000..231a1fe
--- /dev/null
+++ b/Tests/Qt4Targets/mywrapobject.h
@@ -0,0 +1,22 @@
+
+#ifndef MYWRAPOBJECT_H
+#define MYWRAPOBJECT_H
+
+#include <QObject>
+
+#include "myinterface.h"
+
+class MyWrapObject
+ : public QObject
+ , MyInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(MyInterface)
+public:
+ explicit MyWrapObject(QObject* parent = 0)
+ : QObject(parent)
+ {
+ }
+};
+
+#endif
diff --git a/Tests/Qt5Autogen/CMakeLists.txt b/Tests/Qt5Autogen/CMakeLists.txt
new file mode 100644
index 0000000..df4927a
--- /dev/null
+++ b/Tests/Qt5Autogen/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Set Qt test version and include the Autogen test macros
+set(QT_TEST_VERSION 5)
+include("../QtAutogen/TestMacros.cmake")
+
+# Common tests
+include("../QtAutogen/Tests.cmake")
+
+set(TEST_BUILD_DIRS "${TEST_BUILD_DIRS}" PARENT_SCOPE)
diff --git a/Tests/QtAutogen/AutogenCoreTest.cmake b/Tests/QtAutogen/AutogenCoreTest.cmake
new file mode 100644
index 0000000..5803859
--- /dev/null
+++ b/Tests/QtAutogen/AutogenCoreTest.cmake
@@ -0,0 +1,55 @@
+
+# Tell find_package(Qt5) where to find Qt.
+if(QT_QMAKE_EXECUTABLE)
+ get_filename_component(Qt_BIN_DIR "${QT_QMAKE_EXECUTABLE}" PATH)
+ get_filename_component(Qt_PREFIX_DIR "${Qt_BIN_DIR}" PATH)
+ list(APPEND CMAKE_PREFIX_PATH ${Qt_PREFIX_DIR})
+endif()
+
+if (QT_TEST_VERSION EQUAL 4)
+
+ find_package(Qt4 REQUIRED QtCore)
+ include(UseQt4)
+
+ set(QT_QTCORE_TARGET Qt4::QtCore)
+
+ # Qt macros
+ macro(qtx_wrap_cpp)
+ qt4_wrap_cpp(${ARGN})
+ endmacro()
+ macro(qtx_generate_moc)
+ qt4_generate_moc(${ARGN})
+ endmacro()
+
+elseif(QT_TEST_VERSION EQUAL 5)
+
+ find_package(Qt5Core REQUIRED)
+
+ set(QT_QTCORE_TARGET Qt5::Core)
+ set(QT_LIBRARIES Qt5::Core)
+
+ # Include directories
+ include_directories(${Qt5Core_INCLUDE_DIRS})
+
+ # Definitions
+ if(Qt5_POSITION_INDEPENDENT_CODE AND CMAKE_CXX_COMPILE_OPTIONS_PIC)
+ add_definitions(${CMAKE_CXX_COMPILE_OPTIONS_PIC})
+ endif()
+
+ # Qt macros
+ macro(qtx_wrap_cpp)
+ qt5_wrap_cpp(${ARGN})
+ endmacro()
+ macro(qtx_generate_moc)
+ qt5_generate_moc(${ARGN})
+ endmacro()
+
+else()
+ message(SEND_ERROR "Invalid Qt version specified: ${QT_TEST_VERSION}")
+endif()
+
+# Get Qt compile features
+get_property(QT_COMPILE_FEATURES
+ TARGET ${QT_QTCORE_TARGET}
+ PROPERTY INTERFACE_COMPILE_FEATURES
+)
diff --git a/Tests/QtAutogen/AutogenGuiTest.cmake b/Tests/QtAutogen/AutogenGuiTest.cmake
new file mode 100644
index 0000000..b76d341
--- /dev/null
+++ b/Tests/QtAutogen/AutogenGuiTest.cmake
@@ -0,0 +1,55 @@
+
+# Tell find_package(Qt5) where to find Qt.
+if(QT_QMAKE_EXECUTABLE)
+ get_filename_component(Qt_BIN_DIR "${QT_QMAKE_EXECUTABLE}" PATH)
+ get_filename_component(Qt_PREFIX_DIR "${Qt_BIN_DIR}" PATH)
+ list(APPEND CMAKE_PREFIX_PATH ${Qt_PREFIX_DIR})
+endif()
+
+if (QT_TEST_VERSION EQUAL 4)
+
+ find_package(Qt4 REQUIRED)
+ include(UseQt4)
+
+ set(QT_QTCORE_TARGET Qt4::QtCore)
+
+ # Qt macros
+ macro(qtx_wrap_cpp)
+ qt4_wrap_cpp(${ARGN})
+ endmacro()
+ macro(qtx_generate_moc)
+ qt4_generate_moc(${ARGN})
+ endmacro()
+
+elseif(QT_TEST_VERSION EQUAL 5)
+
+ find_package(Qt5Widgets REQUIRED)
+
+ set(QT_QTCORE_TARGET Qt5::Core)
+ set(QT_LIBRARIES Qt5::Widgets)
+
+ # Include directories
+ include_directories(${Qt5Widgets_INCLUDE_DIRS})
+
+ # Definitions
+ if(Qt5_POSITION_INDEPENDENT_CODE AND CMAKE_CXX_COMPILE_OPTIONS_PIC)
+ add_definitions(${CMAKE_CXX_COMPILE_OPTIONS_PIC})
+ endif()
+
+ # Qt macros
+ macro(qtx_wrap_cpp)
+ qt5_wrap_cpp(${ARGN})
+ endmacro()
+ macro(qtx_generate_moc)
+ qt5_generate_moc(${ARGN})
+ endmacro()
+
+else()
+ message(SEND_ERROR "Invalid Qt version specified: ${QT_TEST_VERSION}")
+endif()
+
+# Get Qt compile features
+get_property(QT_COMPILE_FEATURES
+ TARGET ${QT_QTCORE_TARGET}
+ PROPERTY INTERFACE_COMPILE_FEATURES
+)
diff --git a/Tests/QtAutogen/AutogenOriginDependsOff/CMakeLists.txt b/Tests/QtAutogen/AutogenOriginDependsOff/CMakeLists.txt
new file mode 100644
index 0000000..17855ff
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOff/CMakeLists.txt
@@ -0,0 +1,85 @@
+cmake_minimum_required(VERSION 3.11)
+project(AutogenOriginDependsOff)
+include("../AutogenCoreTest.cmake")
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+# XXX(xcode-per-cfg-src): Enable multi-config code path for Xcode
+# when the Xcode generator supports per-config sources.
+if(_isMultiConfig AND NOT CMAKE_GENERATOR STREQUAL "Xcode")
+ set(mocs_compilation_cpp "mocs_compilation_$<CONFIG>.cpp")
+else()
+ set(mocs_compilation_cpp "mocs_compilation.cpp")
+endif()
+
+set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
+set(CBD ${CMAKE_CURRENT_BINARY_DIR})
+include_directories(${CSD})
+include_directories(${CBD})
+
+# A GENERATED file ensures there will be an _autogen target in VS
+add_custom_command (
+ OUTPUT "${CBD}/config_a.hpp"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CSD}/config.hpp.in" "${CBD}/config_a.hpp"
+ )
+
+
+# Library "a_mc" provides a header that holds a string with the content of
+# mocs_compilation.cpp from a_qt. It therefore must depend on a_qt_autogen.
+add_custom_target ( a_mc
+ COMMAND ${CMAKE_COMMAND} -E sleep 2
+ COMMAND ${CMAKE_COMMAND}
+ "-DMCF=${CBD}/a_qt_autogen/${mocs_compilation_cpp}"
+ "-DCF_IN=${CSD}/a_mc.hpp.in"
+ "-DCF_OUT=${CBD}/a_mc.hpp"
+ -P ${CSD}/configure_content.cmake
+ )
+add_dependencies ( a_mc a_qt_autogen )
+
+# Library "a_qt"
+# - depends on a GENERATED file
+# - AUTOMOC enabled
+# - depends on a target (a_mc) that depends on a_qt_qutogen
+add_library ( a_qt a_qt.cpp "${CBD}/config_a.hpp" )
+add_dependencies ( a_qt a_mc )
+target_link_libraries ( a_qt ${QT_QTCORE_TARGET})
+set_target_properties ( a_qt PROPERTIES AUTOMOC TRUE)
+# Disable AUTOGEN_ORIGIN_DEPENDS to avoid loop dependencies
+set_target_properties ( a_qt PROPERTIES AUTOGEN_ORIGIN_DEPENDS OFF)
+
+# A GENERATED file ensures there will be an _autogen target in VS
+add_custom_command (
+ OUTPUT "${CBD}/config_b.hpp"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CSD}/config.hpp.in" "${CBD}/config_b.hpp"
+ )
+
+# Library "b_mc" provides a header that holds a string function that returns
+# the content of mocs_compilation.cpp from b_qt.
+# It therefore must depend on b_qt_autogen.
+add_custom_command (
+ OUTPUT ${CBD}/b_mc.cpp
+ DEPENDS b_qt_autogen
+ COMMAND ${CMAKE_COMMAND} -E sleep 2
+ COMMAND ${CMAKE_COMMAND}
+ "-DMCF=${CBD}/b_qt_autogen/${mocs_compilation_cpp}"
+ "-DCF_IN=${CSD}/b_mc.cpp.in"
+ "-DCF_OUT=${CBD}/b_mc.cpp"
+ -P ${CSD}/configure_content.cmake
+ )
+add_library ( b_mc ${CSD}/b_mc.hpp ${CBD}/b_mc.cpp )
+
+# Library "b_qt"
+# - depends on a GENERATED file
+# - AUTOMOC enabled
+# - depends on a library (b_mc) that depends on b_qt_qutogen
+add_library ( b_qt b_qt.cpp "${CBD}/config_b.hpp" )
+target_link_libraries ( b_qt b_mc )
+target_link_libraries ( b_qt ${QT_QTCORE_TARGET})
+set_target_properties ( b_qt PROPERTIES AUTOMOC TRUE)
+# Disable AUTOGEN_ORIGIN_DEPENDS to avoid loop dependencies
+set_target_properties ( b_qt PROPERTIES AUTOGEN_ORIGIN_DEPENDS OFF)
+
+
+# The main target depends on both libraries which depend on the _autogen
+# target of the main target.
+add_executable ( autogenOriginDependsOff main.cpp )
+target_link_libraries ( autogenOriginDependsOff a_qt b_qt )
diff --git a/Tests/QtAutogen/AutogenOriginDependsOff/a_mc.hpp.in b/Tests/QtAutogen/AutogenOriginDependsOff/a_mc.hpp.in
new file mode 100644
index 0000000..fe71f67
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOff/a_mc.hpp.in
@@ -0,0 +1,9 @@
+#ifndef A_MC_HPP
+#define A_MC_HPP
+
+namespace a_mc {
+
+char const* mocs_compilation = "@MOCS_COMPILATION@";
+}
+
+#endif
diff --git a/Tests/QtAutogen/AutogenOriginDependsOff/a_qt.cpp b/Tests/QtAutogen/AutogenOriginDependsOff/a_qt.cpp
new file mode 100644
index 0000000..c7c6863
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOff/a_qt.cpp
@@ -0,0 +1,29 @@
+
+#include "a_qt.hpp"
+
+#include <a_mc.hpp>
+
+namespace a_qt {
+
+/// @brief A source local QObject based class
+class Source_QObject : public QObject
+{
+ Q_OBJECT
+public:
+ Source_QObject() {}
+ ~Source_QObject() {}
+
+ std::string str;
+};
+
+std::string mocs_compilation()
+{
+ // Create and destroy QObject based classes
+ Header_QObject header_obj;
+ Source_QObject source_obj;
+
+ return std::string(a_mc::mocs_compilation);
+}
+}
+
+#include "a_qt.moc"
diff --git a/Tests/QtAutogen/AutogenOriginDependsOff/a_qt.hpp b/Tests/QtAutogen/AutogenOriginDependsOff/a_qt.hpp
new file mode 100644
index 0000000..313b58b
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOff/a_qt.hpp
@@ -0,0 +1,27 @@
+#ifndef A_QT_HPP
+#define A_QT_HPP
+
+#include <string>
+
+#include <config_a.hpp>
+
+#include <QObject>
+
+namespace a_qt {
+
+/// @brief A header local QObject based class
+class Header_QObject : public QObject
+{
+ Q_OBJECT
+public:
+ Header_QObject() {}
+ ~Header_QObject() {}
+
+ std::string str;
+};
+
+/// @brief Function that returns the content of mocs_compilation.cpp
+extern std::string mocs_compilation();
+}
+
+#endif
diff --git a/Tests/QtAutogen/AutogenOriginDependsOff/b_mc.cpp.in b/Tests/QtAutogen/AutogenOriginDependsOff/b_mc.cpp.in
new file mode 100644
index 0000000..0f5ec30
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOff/b_mc.cpp.in
@@ -0,0 +1,9 @@
+#include <b_mc.hpp>
+
+namespace b_mc {
+
+char const* mocs_compilation()
+{
+ return "@MOCS_COMPILATION@";
+}
+}
diff --git a/Tests/QtAutogen/AutogenOriginDependsOff/b_mc.hpp b/Tests/QtAutogen/AutogenOriginDependsOff/b_mc.hpp
new file mode 100644
index 0000000..0437273
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOff/b_mc.hpp
@@ -0,0 +1,9 @@
+#ifndef B_MC_HPP
+#define B_MC_HPP
+
+namespace b_mc {
+
+extern char const* mocs_compilation();
+}
+
+#endif
diff --git a/Tests/QtAutogen/AutogenOriginDependsOff/b_qt.cpp b/Tests/QtAutogen/AutogenOriginDependsOff/b_qt.cpp
new file mode 100644
index 0000000..c5adaeb
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOff/b_qt.cpp
@@ -0,0 +1,29 @@
+
+#include "b_qt.hpp"
+
+#include <b_mc.hpp>
+
+namespace b_qt {
+
+/// @brief A source local QObject based class
+class Source_QObject : public QObject
+{
+ Q_OBJECT
+public:
+ Source_QObject() {}
+ ~Source_QObject() {}
+
+ std::string str;
+};
+
+std::string mocs_compilation()
+{
+ // Create and destroy QObject based classes
+ Header_QObject header_obj;
+ Source_QObject source_obj;
+
+ return std::string(b_mc::mocs_compilation());
+}
+}
+
+#include "b_qt.moc"
diff --git a/Tests/QtAutogen/AutogenOriginDependsOff/b_qt.hpp b/Tests/QtAutogen/AutogenOriginDependsOff/b_qt.hpp
new file mode 100644
index 0000000..2e5775e
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOff/b_qt.hpp
@@ -0,0 +1,27 @@
+#ifndef B_QT_HPP
+#define B_QT_HPP
+
+#include <string>
+
+#include <config_b.hpp>
+
+#include <QObject>
+
+namespace b_qt {
+
+/// @brief A header local QObject based class
+class Header_QObject : public QObject
+{
+ Q_OBJECT
+public:
+ Header_QObject() {}
+ ~Header_QObject() {}
+
+ std::string str;
+};
+
+/// @brief Function that returns the content of mocs_compilation.cpp
+extern std::string mocs_compilation();
+}
+
+#endif
diff --git a/Tests/QtAutogen/AutogenOriginDependsOff/config.hpp.in b/Tests/QtAutogen/AutogenOriginDependsOff/config.hpp.in
new file mode 100644
index 0000000..e415d08
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOff/config.hpp.in
@@ -0,0 +1,8 @@
+#ifndef CONFIG_HPP
+#define CONFIG_HPP
+
+// Application configuration
+
+enum dummy { NO_OP };
+
+#endif
diff --git a/Tests/QtAutogen/AutogenOriginDependsOff/configure_content.cmake b/Tests/QtAutogen/AutogenOriginDependsOff/configure_content.cmake
new file mode 100644
index 0000000..0fc6e63
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOff/configure_content.cmake
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10)
+
+# Read mocs_compilation.cpp file into variable
+file(READ "${MCF}" MOCS_COMPILATION)
+string(REPLACE "\\" "\\\\" MOCS_COMPILATION "${MOCS_COMPILATION}" )
+string(REPLACE "\"" "\\\"" MOCS_COMPILATION "${MOCS_COMPILATION}" )
+string(REPLACE "\n" "\"\n\"" MOCS_COMPILATION "${MOCS_COMPILATION}" )
+
+# Configure file
+configure_file ( "${CF_IN}" "${CF_OUT}" @ONLY )
diff --git a/Tests/QtAutogen/AutogenOriginDependsOff/main.cpp b/Tests/QtAutogen/AutogenOriginDependsOff/main.cpp
new file mode 100644
index 0000000..3fb6c70
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOff/main.cpp
@@ -0,0 +1,16 @@
+
+#include <string>
+
+#include <a_qt.hpp>
+#include <b_qt.hpp>
+
+int main()
+{
+ if (a_qt::mocs_compilation().empty()) {
+ return -1;
+ }
+ if (b_qt::mocs_compilation().empty()) {
+ return -1;
+ }
+ return 0;
+}
diff --git a/Tests/QtAutogen/AutogenOriginDependsOn/CMakeLists.txt b/Tests/QtAutogen/AutogenOriginDependsOn/CMakeLists.txt
new file mode 100644
index 0000000..5aabe0e
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOn/CMakeLists.txt
@@ -0,0 +1,91 @@
+cmake_minimum_required(VERSION 3.10)
+project(AutogenOriginDependsOn)
+include("../AutogenCoreTest.cmake")
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
+set(CBD ${CMAKE_CURRENT_BINARY_DIR})
+
+# -- Test dependency on header generated by a custom command
+#
+# The ORIGIN_autogen target must depend on the same *GENERATED* source files as
+# the ORIGIN target. This is a requirement to ensure that all files for the
+# ORIGIN target are generated before the ORIGIN_autogen target is built.
+#
+# This tests the dependency of the mocDepGenFile_autogen target of
+# mocDepGenFile to the source file GenFile.hpp, which is *GENERATED*
+# by a custom command.
+# If mocDepGenFile_autogen gets built *before* or in *parallel* to the
+# custom command, the build will fail. That's because GenFile.hpp,
+# which is required by mocDepGenFile_autogen, is only valid after the
+# custom command has been completed.
+#
+# The sleep seconds artificially increase the build time of the custom command
+# to simulate a slow file generation process that takes longer to run than
+# the build of the mocDepGenFile_autogen target.
+add_custom_command(
+ OUTPUT ${CBD}/GenFile.hpp
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_invalid.hpp.in ${CBD}/GenFile.hpp
+ COMMAND ${CMAKE_COMMAND} -E sleep 3
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_valid.hpp.in ${CBD}/GenFile.hpp)
+
+add_executable(mocDepGenFile testGenFile.cpp ${CBD}/GenFile.hpp)
+target_link_libraries(mocDepGenFile ${QT_QTCORE_TARGET})
+set_target_properties(mocDepGenFile PROPERTIES AUTOMOC TRUE)
+
+
+# -- Test dependency on header generating custom target
+#
+# The ORIGIN_autogen target must depend on the same user defined targets
+# as the ORIGIN target. This is a requirement to ensure that all files for the
+# ORIGIN target are generated before the ORIGIN_autogen target is built.
+#
+# This tests the dependency of the mocDepTarget_autogen target of
+# mocDepTarget to the utility target mocDepTargetUtil.
+# If mocDepTarget_autogen gets built *before* or in *parallel* to
+# mocDepTargetUtil, the build will fail. That's
+# because GenTarget.hpp, which is required by mocDepTarget_autogen,
+# is only valid after the mocDepTargetUtil build has been completed.
+#
+# The sleep seconds artificially increase the build time of mocDepTargetUtil
+# to simulate a slow utility target build that takes longer to run than
+# the build of the mocDepTarget_autogen target.
+add_custom_target(mocDepTargetUtil
+ BYPRODUCTS ${CBD}/GenTarget.hpp
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_invalid.hpp.in ${CBD}/GenTarget.hpp
+ COMMAND ${CMAKE_COMMAND} -E sleep 3
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_valid.hpp.in ${CBD}/GenTarget.hpp)
+
+add_executable(mocDepTarget testGenTarget.cpp)
+target_link_libraries(mocDepTarget ${QT_QTCORE_TARGET})
+set_target_properties(mocDepTarget PROPERTIES AUTOMOC TRUE)
+add_dependencies(mocDepTarget mocDepTargetUtil)
+
+
+# -- Test 3: Depend on generated linked library
+# The ORIGIN_autogen target must depend on the same linked libraries
+# as the ORIGIN target. This is a requirement to ensure that all files for the
+# ORIGIN target are generated before the ORIGIN_autogen target is built.
+#
+# This tests the dependency of the mocDepGenLib_autogen target of mocDepGenLib
+# to the user generated library SimpleLib, which mocDepGenLib links to.
+# If mocDepGenLib_autogen gets built *before* or in *parallel* to SimpleLib,
+# the build will fail. That's because simpleLib.hpp, which is required by
+# mocDepGenLib_autogen, is only valid after the SimpleLib build has been
+# completed.
+#
+# The sleep seconds artificially increase the build time of SimpleLib
+# to simulate a slow utility library build that takes longer to run than
+# the build of the mocDepGenLib_autogen target.
+add_custom_command(
+ OUTPUT ${CBD}/simpleLib.hpp ${CBD}/simpleLib.cpp
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_invalid.hpp.in ${CBD}/simpleLib.hpp
+ COMMAND ${CMAKE_COMMAND} -E sleep 3
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/simpleLib.hpp.in ${CBD}/simpleLib.hpp
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/simpleLib.cpp.in ${CBD}/simpleLib.cpp)
+add_library(SimpleLib STATIC ${CBD}/simpleLib.hpp ${CBD}/simpleLib.cpp)
+target_link_libraries(SimpleLib ${QT_QTCORE_TARGET})
+
+add_executable(mocDepGenLib testGenLib.cpp)
+target_link_libraries(mocDepGenLib SimpleLib ${QT_QTCORE_TARGET})
+set_target_properties(mocDepGenLib PROPERTIES AUTOMOC TRUE)
diff --git a/Tests/QtAutogen/AutogenOriginDependsOn/object_invalid.hpp.in b/Tests/QtAutogen/AutogenOriginDependsOn/object_invalid.hpp.in
new file mode 100644
index 0000000..854d9a1
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOn/object_invalid.hpp.in
@@ -0,0 +1 @@
+#ifndef
diff --git a/Tests/QtAutogen/AutogenOriginDependsOn/object_valid.hpp.in b/Tests/QtAutogen/AutogenOriginDependsOn/object_valid.hpp.in
new file mode 100644
index 0000000..f364f7c
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOn/object_valid.hpp.in
@@ -0,0 +1,14 @@
+#ifndef OBJECT_HPP
+#define OBJECT_HPP
+
+#include <QObject>
+
+class Object : public QObject
+{
+ Q_OBJECT
+public:
+ Q_SLOT
+ void aSlot(){};
+};
+
+#endif
diff --git a/Tests/QtAutogen/AutogenOriginDependsOn/simpleLib.cpp.in b/Tests/QtAutogen/AutogenOriginDependsOn/simpleLib.cpp.in
new file mode 100644
index 0000000..fa33bd3
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOn/simpleLib.cpp.in
@@ -0,0 +1,9 @@
+#include "simpleLib.hpp"
+
+SimpleLib::SimpleLib()
+{
+}
+
+SimpleLib::~SimpleLib()
+{
+}
diff --git a/Tests/QtAutogen/AutogenOriginDependsOn/simpleLib.hpp.in b/Tests/QtAutogen/AutogenOriginDependsOn/simpleLib.hpp.in
new file mode 100644
index 0000000..b65b0cb
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOn/simpleLib.hpp.in
@@ -0,0 +1,14 @@
+#ifndef SIMPLE_LIB_H
+#define SIMPLE_LIB_H
+
+#include <QObject>
+
+class SimpleLib : public QObject
+{
+ Q_OBJECT
+public:
+ SimpleLib();
+ ~SimpleLib();
+};
+
+#endif
diff --git a/Tests/QtAutogen/AutogenOriginDependsOn/testGenFile.cpp b/Tests/QtAutogen/AutogenOriginDependsOn/testGenFile.cpp
new file mode 100644
index 0000000..7df6e13
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOn/testGenFile.cpp
@@ -0,0 +1,8 @@
+
+#include "GenFile.hpp"
+
+int main()
+{
+ Object obj;
+ return 0;
+}
diff --git a/Tests/QtAutogen/AutogenOriginDependsOn/testGenLib.cpp b/Tests/QtAutogen/AutogenOriginDependsOn/testGenLib.cpp
new file mode 100644
index 0000000..c14e159
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOn/testGenLib.cpp
@@ -0,0 +1,12 @@
+
+#include "testGenLib.hpp"
+
+int main()
+{
+ SimpleLib libObject;
+ LObject lobject;
+ return 0;
+}
+
+// Depend on and AUTOMOC the SimpleLib header simpleLib.hpp
+#include "moc_simpleLib.cpp"
diff --git a/Tests/QtAutogen/AutogenOriginDependsOn/testGenLib.hpp b/Tests/QtAutogen/AutogenOriginDependsOn/testGenLib.hpp
new file mode 100644
index 0000000..55457d2
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOn/testGenLib.hpp
@@ -0,0 +1,17 @@
+#ifndef TEST3_HPP
+#define TEST3_HPP
+
+#include <QObject>
+
+#include "simpleLib.hpp"
+
+// This object triggers the AUTOMOC on this file
+class LObject : public QObject
+{
+ Q_OBJECT
+public:
+ Q_SLOT
+ void aSlot(){};
+};
+
+#endif
diff --git a/Tests/QtAutogen/AutogenOriginDependsOn/testGenTarget.cpp b/Tests/QtAutogen/AutogenOriginDependsOn/testGenTarget.cpp
new file mode 100644
index 0000000..911076e
--- /dev/null
+++ b/Tests/QtAutogen/AutogenOriginDependsOn/testGenTarget.cpp
@@ -0,0 +1,9 @@
+
+#include "GenTarget.hpp"
+#include "moc_GenTarget.cpp"
+
+int main()
+{
+ Object obj;
+ return 0;
+}
diff --git a/Tests/QtAutogen/AutogenTargetDepends/CMakeLists.txt b/Tests/QtAutogen/AutogenTargetDepends/CMakeLists.txt
new file mode 100644
index 0000000..492b5db
--- /dev/null
+++ b/Tests/QtAutogen/AutogenTargetDepends/CMakeLists.txt
@@ -0,0 +1,54 @@
+cmake_minimum_required(VERSION 3.10)
+project(AutogenTargetDepends)
+include("../AutogenCoreTest.cmake")
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
+set(CBD ${CMAKE_CURRENT_BINARY_DIR})
+
+# -- Test AUTOGEN_TARGET_DEPENDS with GENERATED file dependency
+#
+# This tests the dependency of the mocDepATDFile_autogen target of
+# mocDepATDTarget to the utility target mocDepATDFileUtil.
+# If mocDepATDFile_autogen gets built *before* or in *parallel* to
+# mocDepATDFileUtil, the build will fail. That's
+# because ATDFile.hpp, which is required by mocDepATDFile_autogen,
+# is only valid after the mocDepATDFileUtil build has been completed.
+#
+# The sleep seconds artificially increase the build time of
+# mocDepATDFileUtil to simulate a slow utility target build that takes
+# longer to run than the build of the mocDepATDFile_autogen target.
+add_custom_command(
+ OUTPUT ${CBD}/ATDFile.hpp
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_invalid.hpp.in ${CBD}/ATDFile.hpp
+ COMMAND ${CMAKE_COMMAND} -E sleep 3
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_valid.hpp.in ${CBD}/ATDFile.hpp)
+
+add_executable(mocDepATDFile testATDFile.cpp)
+target_link_libraries(mocDepATDFile ${QT_QTCORE_TARGET})
+set_target_properties(mocDepATDFile PROPERTIES AUTOMOC TRUE)
+set_target_properties(mocDepATDFile PROPERTIES AUTOGEN_TARGET_DEPENDS ${CBD}/ATDFile.hpp)
+
+
+# -- Test AUTOGEN_TARGET_DEPENDS with target dependency
+#
+# This tests the dependency of the mocDepATDTarget_autogen target of
+# mocDepATDTarget to the utility target mocDepATDTargetUtil.
+# If mocDepATDTarget_autogen gets built *before* or in *parallel* to
+# mocDepATDTargetUtil, the build will fail. That's
+# because ATDTarget.hpp, which is required by mocDepATDTarget_autogen,
+# is only valid after the mocDepATDTargetUtil build has been completed.
+#
+# The sleep seconds artificially increase the build time of
+# mocDepATDTargetUtil to simulate a slow utility target build that takes
+# longer to run than the build of the mocDepATDTarget_autogen target.
+add_custom_target(mocDepATDTargetUtil
+ BYPRODUCTS ${CBD}/ATDTarget.hpp
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_invalid.hpp.in ${CBD}/ATDTarget.hpp
+ COMMAND ${CMAKE_COMMAND} -E sleep 3
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/object_valid.hpp.in ${CBD}/ATDTarget.hpp)
+
+add_executable(mocDepATDTarget testATDTarget.cpp)
+target_link_libraries(mocDepATDTarget ${QT_QTCORE_TARGET})
+set_target_properties(mocDepATDTarget PROPERTIES AUTOMOC TRUE)
+set_target_properties(mocDepATDTarget PROPERTIES AUTOGEN_TARGET_DEPENDS mocDepATDTargetUtil)
diff --git a/Tests/QtAutogen/AutogenTargetDepends/object_invalid.hpp.in b/Tests/QtAutogen/AutogenTargetDepends/object_invalid.hpp.in
new file mode 100644
index 0000000..854d9a1
--- /dev/null
+++ b/Tests/QtAutogen/AutogenTargetDepends/object_invalid.hpp.in
@@ -0,0 +1 @@
+#ifndef
diff --git a/Tests/QtAutogen/AutogenTargetDepends/object_valid.hpp.in b/Tests/QtAutogen/AutogenTargetDepends/object_valid.hpp.in
new file mode 100644
index 0000000..f364f7c
--- /dev/null
+++ b/Tests/QtAutogen/AutogenTargetDepends/object_valid.hpp.in
@@ -0,0 +1,14 @@
+#ifndef OBJECT_HPP
+#define OBJECT_HPP
+
+#include <QObject>
+
+class Object : public QObject
+{
+ Q_OBJECT
+public:
+ Q_SLOT
+ void aSlot(){};
+};
+
+#endif
diff --git a/Tests/QtAutogen/AutogenTargetDepends/testATDFile.cpp b/Tests/QtAutogen/AutogenTargetDepends/testATDFile.cpp
new file mode 100644
index 0000000..6bddfcd
--- /dev/null
+++ b/Tests/QtAutogen/AutogenTargetDepends/testATDFile.cpp
@@ -0,0 +1,9 @@
+
+#include "ATDFile.hpp"
+#include "moc_ATDFile.cpp"
+
+int main()
+{
+ Object obj;
+ return 0;
+}
diff --git a/Tests/QtAutogen/AutogenTargetDepends/testATDTarget.cpp b/Tests/QtAutogen/AutogenTargetDepends/testATDTarget.cpp
new file mode 100644
index 0000000..831fc26
--- /dev/null
+++ b/Tests/QtAutogen/AutogenTargetDepends/testATDTarget.cpp
@@ -0,0 +1,9 @@
+
+#include "ATDTarget.hpp"
+#include "moc_ATDTarget.cpp"
+
+int main()
+{
+ Object obj;
+ return 0;
+}
diff --git a/Tests/QtAutogen/Complex/Adir/CMakeLists.txt b/Tests/QtAutogen/Complex/Adir/CMakeLists.txt
new file mode 100644
index 0000000..a1c36ff
--- /dev/null
+++ b/Tests/QtAutogen/Complex/Adir/CMakeLists.txt
@@ -0,0 +1,8 @@
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
+
+add_library(libA SHARED libA.cpp)
+target_link_libraries(libA LINK_PUBLIC ${QT_QTCORE_TARGET})
+generate_export_header(libA)
diff --git a/Tests/QtAutogen/Complex/Adir/libA.cpp b/Tests/QtAutogen/Complex/Adir/libA.cpp
new file mode 100644
index 0000000..f79f24a
--- /dev/null
+++ b/Tests/QtAutogen/Complex/Adir/libA.cpp
@@ -0,0 +1,12 @@
+
+#include "libA.h"
+
+LibA::LibA(QObject* parent)
+ : QObject(parent)
+{
+}
+
+int LibA::foo()
+{
+ return 0;
+}
diff --git a/Tests/QtAutogen/Complex/Adir/libA.h b/Tests/QtAutogen/Complex/Adir/libA.h
new file mode 100644
index 0000000..a8ca209
--- /dev/null
+++ b/Tests/QtAutogen/Complex/Adir/libA.h
@@ -0,0 +1,18 @@
+
+#ifndef LIBA_H
+#define LIBA_H
+
+#include <QObject>
+
+#include "liba_export.h"
+
+class LIBA_EXPORT LibA : public QObject
+{
+ Q_OBJECT
+public:
+ explicit LibA(QObject* parent = 0);
+
+ int foo();
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/Bdir/CMakeLists.txt b/Tests/QtAutogen/Complex/Bdir/CMakeLists.txt
new file mode 100644
index 0000000..d338763
--- /dev/null
+++ b/Tests/QtAutogen/Complex/Bdir/CMakeLists.txt
@@ -0,0 +1,9 @@
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
+
+add_library(libB SHARED libB.cpp)
+generate_export_header(libB)
+
+target_link_libraries(libB LINK_PUBLIC libA)
diff --git a/Tests/QtAutogen/Complex/Bdir/libB.cpp b/Tests/QtAutogen/Complex/Bdir/libB.cpp
new file mode 100644
index 0000000..d3b6753
--- /dev/null
+++ b/Tests/QtAutogen/Complex/Bdir/libB.cpp
@@ -0,0 +1,12 @@
+
+#include "libB.h"
+
+LibB::LibB(QObject* parent)
+ : QObject(parent)
+{
+}
+
+int LibB::foo()
+{
+ return a.foo();
+}
diff --git a/Tests/QtAutogen/Complex/Bdir/libB.h b/Tests/QtAutogen/Complex/Bdir/libB.h
new file mode 100644
index 0000000..38dae87
--- /dev/null
+++ b/Tests/QtAutogen/Complex/Bdir/libB.h
@@ -0,0 +1,22 @@
+
+#ifndef LIBB_H
+#define LIBB_H
+
+#include <QObject>
+
+#include "libA.h"
+#include "libb_export.h"
+
+class LIBB_EXPORT LibB : public QObject
+{
+ Q_OBJECT
+public:
+ explicit LibB(QObject* parent = 0);
+
+ int foo();
+
+private:
+ LibA a;
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/CMakeLists.txt b/Tests/QtAutogen/Complex/CMakeLists.txt
new file mode 100644
index 0000000..d9fdf5c
--- /dev/null
+++ b/Tests/QtAutogen/Complex/CMakeLists.txt
@@ -0,0 +1,85 @@
+cmake_minimum_required(VERSION 3.10)
+project(Complex)
+include("../AutogenGuiTest.cmake")
+
+# -- Test: AUTOMOC AUTORCC AUTOUIC
+add_definitions(-DFOO -DSomeDefine="Barx")
+
+# enable relaxed mode so automoc can handle all the special cases:
+set(CMAKE_AUTOMOC_RELAXED_MODE TRUE)
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTORCC ON)
+
+# create an executable and two library targets, each requiring automoc:
+add_library(codeeditorLib STATIC codeeditor.cpp)
+add_library(privateSlot OBJECT private_slot.cpp)
+# Pass Qt compiler features to targets that don't link against Qt
+target_compile_features(codeeditorLib PRIVATE ${QT_COMPILE_FEATURES})
+target_compile_features(privateSlot PRIVATE ${QT_COMPILE_FEATURES})
+
+configure_file(generated_resource.qrc.in generated_resource.qrc @ONLY)
+add_custom_command(
+ OUTPUT generated.txt
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/generated.txt.in" "${CMAKE_CURRENT_BINARY_DIR}/generated.txt"
+ DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/generated.txt.in"
+)
+
+add_custom_target(generate_moc_input
+ DEPENDS generated.txt
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/myinterface.h.in" "${CMAKE_CURRENT_BINARY_DIR}"
+ COMMAND ${CMAKE_COMMAND} -E rename "${CMAKE_CURRENT_BINARY_DIR}/myinterface.h.in" "${CMAKE_CURRENT_BINARY_DIR}/myinterface.h"
+)
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/myotherinterface.h"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/myotherinterface.h.in" "${CMAKE_CURRENT_BINARY_DIR}/myotherinterface.h"
+ DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/myotherinterface.h.in"
+)
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(NOT _isMultiConfig AND NOT CMAKE_GENERATOR STREQUAL Ninja)
+ set(debug_srcs "$<$<CONFIG:Debug>:debug_class.cpp>" $<$<CONFIG:Debug>:debug_resource.qrc>)
+ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:Debug>:TEST_DEBUG_CLASS>)
+endif()
+
+# The -no-protection option disables the generation of include guards. Verify
+# that setting the source file property has an effect by using this and
+# issue an error in the preprocessor in calwidget.cpp if the include guard
+# is defined.
+set_source_files_properties(calwidget.ui PROPERTIES AUTOUIC_OPTIONS "-no-protection")
+
+add_executable(QtAutogen main.cpp calwidget.cpp second_widget.cpp foo.cpp blub.cpp bar.cpp abc.cpp
+ multiplewidgets.cpp
+ xyz.cpp yaf.cpp gadget.cpp $<TARGET_OBJECTS:privateSlot>
+ test.qrc second_resource.qrc resourcetester.cpp generated.cpp ${debug_srcs}
+ ${CMAKE_CURRENT_BINARY_DIR}/generated_resource.qrc
+)
+set_property(TARGET QtAutogen APPEND PROPERTY AUTOGEN_TARGET_DEPENDS generate_moc_input "${CMAKE_CURRENT_BINARY_DIR}/myotherinterface.h")
+
+add_executable(targetObjectsTest targetObjectsTest.cpp $<TARGET_OBJECTS:privateSlot>)
+target_link_libraries(targetObjectsTest ${QT_LIBRARIES})
+
+set_target_properties(
+ QtAutogen codeeditorLib privateSlot targetObjectsTest
+ PROPERTIES
+ AUTOMOC TRUE
+)
+
+
+include(GenerateExportHeader)
+# The order is relevant here. B depends on A, and B headers depend on A
+# headers both subdirectories use CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE and we
+# test that CMAKE_AUTOMOC successfully reads the include directories
+# for the build interface from those targets. There has previously been
+# a bug where caching of the include directories happened before
+# extracting the includes to pass to moc.
+add_subdirectory(Bdir)
+add_subdirectory(Adir)
+add_library(libC SHARED libC.cpp)
+set_target_properties(libC PROPERTIES AUTOMOC TRUE)
+generate_export_header(libC)
+target_link_libraries(libC LINK_PUBLIC libB)
+target_include_directories(libC PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+set_property(TARGET libC APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR} )
+
+target_link_libraries(QtAutogen codeeditorLib ${QT_LIBRARIES} libC)
diff --git a/Tests/QtAutogen/Complex/abc.cpp b/Tests/QtAutogen/Complex/abc.cpp
new file mode 100644
index 0000000..4c7dc52
--- /dev/null
+++ b/Tests/QtAutogen/Complex/abc.cpp
@@ -0,0 +1,40 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "abc.h"
+
+#include <stdio.h>
+
+#include "abc_p.h"
+
+class PrintAbc : public QObject
+{
+ Q_OBJECT
+public:
+ PrintAbc()
+ : QObject()
+ {
+ }
+public slots:
+ void print() const { printf("abc\n"); }
+};
+
+Abc::Abc()
+ : QObject()
+{
+}
+
+void Abc::doAbc()
+{
+ PrintAbc pa;
+ pa.print();
+ AbcP abcP;
+ abcP.doAbcP();
+}
+
+// check that including the moc file for the cpp file and the header works:
+#include "abc.moc"
+#include "moc_abc.cpp"
+#include "moc_abc_p.cpp"
+
+// check that including a moc file from another header works:
+#include "moc_xyz.cpp"
diff --git a/Tests/QtAutogen/Complex/abc.h b/Tests/QtAutogen/Complex/abc.h
new file mode 100644
index 0000000..ec5f411
--- /dev/null
+++ b/Tests/QtAutogen/Complex/abc.h
@@ -0,0 +1,17 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef ABC_H
+#define ABC_H
+
+#include <QObject>
+
+class Abc : public QObject
+{
+ Q_OBJECT
+public:
+ Abc();
+public slots:
+ void doAbc();
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/abc_p.h b/Tests/QtAutogen/Complex/abc_p.h
new file mode 100644
index 0000000..1f6102c
--- /dev/null
+++ b/Tests/QtAutogen/Complex/abc_p.h
@@ -0,0 +1,19 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef ABC_P_H
+#define ABC_P_H
+
+#include <stdio.h>
+
+#include <QObject>
+
+class AbcP : public QObject
+{
+ Q_OBJECT
+public:
+ AbcP() {}
+public slots:
+ void doAbcP() { printf("I am private abc !\n"); }
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/bar.cpp b/Tests/QtAutogen/Complex/bar.cpp
new file mode 100644
index 0000000..734bd7a
--- /dev/null
+++ b/Tests/QtAutogen/Complex/bar.cpp
@@ -0,0 +1,17 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "sub/bar.h"
+
+#include <stdio.h>
+
+Bar::Bar()
+ : QObject()
+{
+}
+
+void Bar::doBar()
+{
+ printf("Hello bar !\n");
+}
+
+#include "sub/moc_bar.cpp"
diff --git a/Tests/QtAutogen/Complex/blub.cpp b/Tests/QtAutogen/Complex/blub.cpp
new file mode 100644
index 0000000..1c497e0
--- /dev/null
+++ b/Tests/QtAutogen/Complex/blub.cpp
@@ -0,0 +1,31 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "blub.h"
+
+#include <stdio.h>
+
+class BlubBlub : public QObject
+{
+ Q_OBJECT
+public:
+ BlubBlub()
+ : QObject()
+ {
+ }
+public slots:
+ int getValue() const { return 13; }
+};
+
+Blub::Blub()
+{
+}
+
+void Blub::blubber()
+{
+ BlubBlub bb;
+ printf("Blub blub %d ! \n", bb.getValue());
+}
+
+// test the case that the wrong moc-file is included, it should
+// actually be "blub.moc"
+#include "moc_blub.cpp"
diff --git a/Tests/QtAutogen/Complex/blub.h b/Tests/QtAutogen/Complex/blub.h
new file mode 100644
index 0000000..ff79878
--- /dev/null
+++ b/Tests/QtAutogen/Complex/blub.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. */
+#ifndef BLUB_H
+#define BLUB_H
+
+#include <QObject>
+
+class Blub
+{
+public:
+ Blub();
+ void blubber();
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/calwidget.cpp b/Tests/QtAutogen/Complex/calwidget.cpp
new file mode 100644
index 0000000..f58b182
--- /dev/null
+++ b/Tests/QtAutogen/Complex/calwidget.cpp
@@ -0,0 +1,436 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ ** All rights reserved.
+ ** Contact: Nokia Corporation (qt-info@nokia.com)
+ **
+ ** This file is part of the examples of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:BSD$
+ ** You may use this file under the terms of the BSD license as follows:
+ **
+ ** "Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions are
+ ** met:
+ ** * Redistributions of source code must retain the above copyright
+ ** notice, this list of conditions and the following disclaimer.
+ ** * Redistributions in binary form must reproduce the above copyright
+ ** notice, this list of conditions and the following disclaimer in
+ ** the documentation and/or other materials provided with the
+ ** distribution.
+ ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+ ** the names of its contributors may be used to endorse or promote
+ ** products derived from this software without specific prior written
+ ** permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+#include "calwidget.h"
+
+#include <QCalendarWidget>
+#include <QCheckBox>
+#include <QComboBox>
+#include <QDateEdit>
+#include <QGridLayout>
+#include <QGroupBox>
+#include <QLabel>
+#include <QTextCharFormat>
+
+#include "ui_calwidget.h"
+#ifdef UI_CALWIDGET_H
+# error Definition of UI_CALWIDGET_H should be disabled by file option.
+#endif
+
+Window::Window()
+ : ui(new Ui::Window)
+{
+ createPreviewGroupBox();
+ createGeneralOptionsGroupBox();
+ createDatesGroupBox();
+ createTextFormatsGroupBox();
+
+ QGridLayout* layout = new QGridLayout;
+ layout->addWidget(previewGroupBox, 0, 0);
+ layout->addWidget(generalOptionsGroupBox, 0, 1);
+ layout->addWidget(datesGroupBox, 1, 0);
+ layout->addWidget(textFormatsGroupBox, 1, 1);
+ layout->setSizeConstraint(QLayout::SetFixedSize);
+ setLayout(layout);
+
+ previewLayout->setRowMinimumHeight(0, calendar->sizeHint().height());
+ previewLayout->setColumnMinimumWidth(0, calendar->sizeHint().width());
+
+ setWindowTitle(tr("Calendar Widget"));
+}
+
+void Window::localeChanged(int index)
+{
+ calendar->setLocale(localeCombo->itemData(index).toLocale());
+}
+
+void Window::firstDayChanged(int index)
+{
+ calendar->setFirstDayOfWeek(
+ Qt::DayOfWeek(firstDayCombo->itemData(index).toInt()));
+}
+
+void Window::selectionModeChanged(int index)
+{
+ calendar->setSelectionMode(QCalendarWidget::SelectionMode(
+ selectionModeCombo->itemData(index).toInt()));
+}
+
+void Window::horizontalHeaderChanged(int index)
+{
+ calendar->setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat(
+ horizontalHeaderCombo->itemData(index).toInt()));
+}
+
+void Window::verticalHeaderChanged(int index)
+{
+ calendar->setVerticalHeaderFormat(QCalendarWidget::VerticalHeaderFormat(
+ verticalHeaderCombo->itemData(index).toInt()));
+}
+
+void Window::selectedDateChanged()
+{
+ currentDateEdit->setDate(calendar->selectedDate());
+}
+
+void Window::minimumDateChanged(const QDate& date)
+{
+ calendar->setMinimumDate(date);
+ maximumDateEdit->setDate(calendar->maximumDate());
+}
+
+void Window::maximumDateChanged(const QDate& date)
+{
+ calendar->setMaximumDate(date);
+ minimumDateEdit->setDate(calendar->minimumDate());
+}
+
+void Window::weekdayFormatChanged()
+{
+ QTextCharFormat format;
+
+ format.setForeground(qvariant_cast<QColor>(
+ weekdayColorCombo->itemData(weekdayColorCombo->currentIndex())));
+ calendar->setWeekdayTextFormat(Qt::Monday, format);
+ calendar->setWeekdayTextFormat(Qt::Tuesday, format);
+ calendar->setWeekdayTextFormat(Qt::Wednesday, format);
+ calendar->setWeekdayTextFormat(Qt::Thursday, format);
+ calendar->setWeekdayTextFormat(Qt::Friday, format);
+}
+
+void Window::weekendFormatChanged()
+{
+ QTextCharFormat format;
+
+ format.setForeground(qvariant_cast<QColor>(
+ weekendColorCombo->itemData(weekendColorCombo->currentIndex())));
+ calendar->setWeekdayTextFormat(Qt::Saturday, format);
+ calendar->setWeekdayTextFormat(Qt::Sunday, format);
+}
+
+void Window::reformatHeaders()
+{
+ QString text = headerTextFormatCombo->currentText();
+ QTextCharFormat format;
+
+ if (text == tr("Bold")) {
+ format.setFontWeight(QFont::Bold);
+ } else if (text == tr("Italic")) {
+ format.setFontItalic(true);
+ } else if (text == tr("Green")) {
+ format.setForeground(Qt::green);
+ }
+ calendar->setHeaderTextFormat(format);
+}
+
+void Window::reformatCalendarPage()
+{
+ if (firstFridayCheckBox->isChecked()) {
+ QDate firstFriday(calendar->yearShown(), calendar->monthShown(), 1);
+ while (firstFriday.dayOfWeek() != Qt::Friday)
+ firstFriday = firstFriday.addDays(1);
+ QTextCharFormat firstFridayFormat;
+ firstFridayFormat.setForeground(Qt::blue);
+ calendar->setDateTextFormat(firstFriday, firstFridayFormat);
+ }
+
+ // May First in Red takes precedence
+ if (mayFirstCheckBox->isChecked()) {
+ const QDate mayFirst(calendar->yearShown(), 5, 1);
+ QTextCharFormat mayFirstFormat;
+ mayFirstFormat.setForeground(Qt::red);
+ calendar->setDateTextFormat(mayFirst, mayFirstFormat);
+ }
+}
+
+void Window::createPreviewGroupBox()
+{
+ previewGroupBox = new QGroupBox(tr("Preview"));
+
+ calendar = new QCalendarWidget;
+ calendar->setMinimumDate(QDate(1900, 1, 1));
+ calendar->setMaximumDate(QDate(3000, 1, 1));
+ calendar->setGridVisible(true);
+
+ connect(calendar, SIGNAL(currentPageChanged(int, int)), this,
+ SLOT(reformatCalendarPage()));
+
+ previewLayout = new QGridLayout;
+ previewLayout->addWidget(calendar, 0, 0, Qt::AlignCenter);
+ previewGroupBox->setLayout(previewLayout);
+}
+
+void Window::createGeneralOptionsGroupBox()
+{
+ generalOptionsGroupBox = new QGroupBox(tr("General Options"));
+
+ localeCombo = new QComboBox;
+ int curLocaleIndex = -1;
+ int index = 0;
+ for (int _lang = QLocale::C; _lang <= QLocale::LastLanguage; ++_lang) {
+ QLocale::Language lang = static_cast<QLocale::Language>(_lang);
+ QList<QLocale::Country> countries = QLocale::countriesForLanguage(lang);
+ for (int i = 0; i < countries.count(); ++i) {
+ QLocale::Country country = countries.at(i);
+ QString label = QLocale::languageToString(lang);
+ label += QLatin1Char('/');
+ label += QLocale::countryToString(country);
+ QLocale locale(lang, country);
+ if (this->locale().language() == lang &&
+ this->locale().country() == country)
+ curLocaleIndex = index;
+ localeCombo->addItem(label, locale);
+ ++index;
+ }
+ }
+ if (curLocaleIndex != -1)
+ localeCombo->setCurrentIndex(curLocaleIndex);
+ localeLabel = new QLabel(tr("&Locale"));
+ localeLabel->setBuddy(localeCombo);
+
+ firstDayCombo = new QComboBox;
+ firstDayCombo->addItem(tr("Sunday"), Qt::Sunday);
+ firstDayCombo->addItem(tr("Monday"), Qt::Monday);
+ firstDayCombo->addItem(tr("Tuesday"), Qt::Tuesday);
+ firstDayCombo->addItem(tr("Wednesday"), Qt::Wednesday);
+ firstDayCombo->addItem(tr("Thursday"), Qt::Thursday);
+ firstDayCombo->addItem(tr("Friday"), Qt::Friday);
+ firstDayCombo->addItem(tr("Saturday"), Qt::Saturday);
+
+ firstDayLabel = new QLabel(tr("Wee&k starts on:"));
+ firstDayLabel->setBuddy(firstDayCombo);
+
+ selectionModeCombo = new QComboBox;
+ selectionModeCombo->addItem(tr("Single selection"),
+ QCalendarWidget::SingleSelection);
+ selectionModeCombo->addItem(tr("None"), QCalendarWidget::NoSelection);
+
+ selectionModeLabel = new QLabel(tr("&Selection mode:"));
+ selectionModeLabel->setBuddy(selectionModeCombo);
+
+ gridCheckBox = new QCheckBox(tr("&Grid"));
+ gridCheckBox->setChecked(calendar->isGridVisible());
+
+ navigationCheckBox = new QCheckBox(tr("&Navigation bar"));
+ navigationCheckBox->setChecked(true);
+
+ horizontalHeaderCombo = new QComboBox;
+ horizontalHeaderCombo->addItem(tr("Single letter day names"),
+ QCalendarWidget::SingleLetterDayNames);
+ horizontalHeaderCombo->addItem(tr("Short day names"),
+ QCalendarWidget::ShortDayNames);
+ horizontalHeaderCombo->addItem(tr("None"),
+ QCalendarWidget::NoHorizontalHeader);
+ horizontalHeaderCombo->setCurrentIndex(1);
+
+ horizontalHeaderLabel = new QLabel(tr("&Horizontal header:"));
+ horizontalHeaderLabel->setBuddy(horizontalHeaderCombo);
+
+ verticalHeaderCombo = new QComboBox;
+ verticalHeaderCombo->addItem(tr("ISO week numbers"),
+ QCalendarWidget::ISOWeekNumbers);
+ verticalHeaderCombo->addItem(tr("None"), QCalendarWidget::NoVerticalHeader);
+
+ verticalHeaderLabel = new QLabel(tr("&Vertical header:"));
+ verticalHeaderLabel->setBuddy(verticalHeaderCombo);
+
+ connect(localeCombo, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(localeChanged(int)));
+ connect(firstDayCombo, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(firstDayChanged(int)));
+ connect(selectionModeCombo, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(selectionModeChanged(int)));
+ connect(gridCheckBox, SIGNAL(toggled(bool)), calendar,
+ SLOT(setGridVisible(bool)));
+ connect(navigationCheckBox, SIGNAL(toggled(bool)), calendar,
+ SLOT(setNavigationBarVisible(bool)));
+ connect(horizontalHeaderCombo, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(horizontalHeaderChanged(int)));
+ connect(verticalHeaderCombo, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(verticalHeaderChanged(int)));
+
+ QHBoxLayout* checkBoxLayout = new QHBoxLayout;
+ checkBoxLayout->addWidget(gridCheckBox);
+ checkBoxLayout->addStretch();
+ checkBoxLayout->addWidget(navigationCheckBox);
+
+ QGridLayout* outerLayout = new QGridLayout;
+ outerLayout->addWidget(localeLabel, 0, 0);
+ outerLayout->addWidget(localeCombo, 0, 1);
+ outerLayout->addWidget(firstDayLabel, 1, 0);
+ outerLayout->addWidget(firstDayCombo, 1, 1);
+ outerLayout->addWidget(selectionModeLabel, 2, 0);
+ outerLayout->addWidget(selectionModeCombo, 2, 1);
+ outerLayout->addLayout(checkBoxLayout, 3, 0, 1, 2);
+ outerLayout->addWidget(horizontalHeaderLabel, 4, 0);
+ outerLayout->addWidget(horizontalHeaderCombo, 4, 1);
+ outerLayout->addWidget(verticalHeaderLabel, 5, 0);
+ outerLayout->addWidget(verticalHeaderCombo, 5, 1);
+ generalOptionsGroupBox->setLayout(outerLayout);
+
+ firstDayChanged(firstDayCombo->currentIndex());
+ selectionModeChanged(selectionModeCombo->currentIndex());
+ horizontalHeaderChanged(horizontalHeaderCombo->currentIndex());
+ verticalHeaderChanged(verticalHeaderCombo->currentIndex());
+}
+
+void Window::createDatesGroupBox()
+{
+ datesGroupBox = new QGroupBox(tr("Dates"));
+
+ minimumDateEdit = new QDateEdit;
+ minimumDateEdit->setDisplayFormat("MMM d yyyy");
+ minimumDateEdit->setDateRange(calendar->minimumDate(),
+ calendar->maximumDate());
+ minimumDateEdit->setDate(calendar->minimumDate());
+
+ minimumDateLabel = new QLabel(tr("&Minimum Date:"));
+ minimumDateLabel->setBuddy(minimumDateEdit);
+
+ currentDateEdit = new QDateEdit;
+ currentDateEdit->setDisplayFormat("MMM d yyyy");
+ currentDateEdit->setDate(calendar->selectedDate());
+ currentDateEdit->setDateRange(calendar->minimumDate(),
+ calendar->maximumDate());
+
+ currentDateLabel = new QLabel(tr("&Current Date:"));
+ currentDateLabel->setBuddy(currentDateEdit);
+
+ maximumDateEdit = new QDateEdit;
+ maximumDateEdit->setDisplayFormat("MMM d yyyy");
+ maximumDateEdit->setDateRange(calendar->minimumDate(),
+ calendar->maximumDate());
+ maximumDateEdit->setDate(calendar->maximumDate());
+
+ maximumDateLabel = new QLabel(tr("Ma&ximum Date:"));
+ maximumDateLabel->setBuddy(maximumDateEdit);
+
+ connect(currentDateEdit, SIGNAL(dateChanged(QDate)), calendar,
+ SLOT(setSelectedDate(QDate)));
+ connect(calendar, SIGNAL(selectionChanged()), this,
+ SLOT(selectedDateChanged()));
+ connect(minimumDateEdit, SIGNAL(dateChanged(QDate)), this,
+ SLOT(minimumDateChanged(QDate)));
+ connect(maximumDateEdit, SIGNAL(dateChanged(QDate)), this,
+ SLOT(maximumDateChanged(QDate)));
+
+ QGridLayout* dateBoxLayout = new QGridLayout;
+ dateBoxLayout->addWidget(currentDateLabel, 1, 0);
+ dateBoxLayout->addWidget(currentDateEdit, 1, 1);
+ dateBoxLayout->addWidget(minimumDateLabel, 0, 0);
+ dateBoxLayout->addWidget(minimumDateEdit, 0, 1);
+ dateBoxLayout->addWidget(maximumDateLabel, 2, 0);
+ dateBoxLayout->addWidget(maximumDateEdit, 2, 1);
+ dateBoxLayout->setRowStretch(3, 1);
+
+ datesGroupBox->setLayout(dateBoxLayout);
+}
+
+void Window::createTextFormatsGroupBox()
+{
+ textFormatsGroupBox = new QGroupBox(tr("Text Formats"));
+
+ weekdayColorCombo = createColorComboBox();
+ weekdayColorCombo->setCurrentIndex(weekdayColorCombo->findText(tr("Black")));
+
+ weekdayColorLabel = new QLabel(tr("&Weekday color:"));
+ weekdayColorLabel->setBuddy(weekdayColorCombo);
+
+ weekendColorCombo = createColorComboBox();
+ weekendColorCombo->setCurrentIndex(weekendColorCombo->findText(tr("Red")));
+
+ weekendColorLabel = new QLabel(tr("Week&end color:"));
+ weekendColorLabel->setBuddy(weekendColorCombo);
+
+ headerTextFormatCombo = new QComboBox;
+ headerTextFormatCombo->addItem(tr("Bold"));
+ headerTextFormatCombo->addItem(tr("Italic"));
+ headerTextFormatCombo->addItem(tr("Plain"));
+
+ headerTextFormatLabel = new QLabel(tr("&Header text:"));
+ headerTextFormatLabel->setBuddy(headerTextFormatCombo);
+
+ firstFridayCheckBox = new QCheckBox(tr("&First Friday in blue"));
+
+ mayFirstCheckBox = new QCheckBox(tr("May &1 in red"));
+
+ connect(weekdayColorCombo, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(weekdayFormatChanged()));
+ connect(weekendColorCombo, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(weekendFormatChanged()));
+ connect(headerTextFormatCombo, SIGNAL(currentIndexChanged(QString)), this,
+ SLOT(reformatHeaders()));
+ connect(firstFridayCheckBox, SIGNAL(toggled(bool)), this,
+ SLOT(reformatCalendarPage()));
+ connect(mayFirstCheckBox, SIGNAL(toggled(bool)), this,
+ SLOT(reformatCalendarPage()));
+
+ QHBoxLayout* checkBoxLayout = new QHBoxLayout;
+ checkBoxLayout->addWidget(firstFridayCheckBox);
+ checkBoxLayout->addStretch();
+ checkBoxLayout->addWidget(mayFirstCheckBox);
+
+ QGridLayout* outerLayout = new QGridLayout;
+ outerLayout->addWidget(weekdayColorLabel, 0, 0);
+ outerLayout->addWidget(weekdayColorCombo, 0, 1);
+ outerLayout->addWidget(weekendColorLabel, 1, 0);
+ outerLayout->addWidget(weekendColorCombo, 1, 1);
+ outerLayout->addWidget(headerTextFormatLabel, 2, 0);
+ outerLayout->addWidget(headerTextFormatCombo, 2, 1);
+ outerLayout->addLayout(checkBoxLayout, 3, 0, 1, 2);
+ textFormatsGroupBox->setLayout(outerLayout);
+
+ weekdayFormatChanged();
+ weekendFormatChanged();
+ reformatHeaders();
+ reformatCalendarPage();
+}
+
+QComboBox* Window::createColorComboBox()
+{
+ QComboBox* comboBox = new QComboBox;
+ comboBox->addItem(tr("Red"), QColor(Qt::red));
+ comboBox->addItem(tr("Blue"), QColor(Qt::blue));
+ comboBox->addItem(tr("Black"), QColor(Qt::black));
+ comboBox->addItem(tr("Magenta"), QColor(Qt::magenta));
+ return comboBox;
+}
+
+//#include "moc_calwidget.cpp"
diff --git a/Tests/QtAutogen/Complex/calwidget.h b/Tests/QtAutogen/Complex/calwidget.h
new file mode 100644
index 0000000..084d959
--- /dev/null
+++ b/Tests/QtAutogen/Complex/calwidget.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <QWidget>
+
+class QCalendarWidget;
+class QCheckBox;
+class QComboBox;
+class QDate;
+class QDateEdit;
+class QGridLayout;
+class QGroupBox;
+class QLabel;
+
+namespace Ui {
+class Window;
+}
+
+class Window : public QWidget
+{
+ Q_OBJECT
+
+public:
+ Window();
+
+private slots:
+ void localeChanged(int index);
+ void firstDayChanged(int index);
+ void selectionModeChanged(int index);
+ void horizontalHeaderChanged(int index);
+ void verticalHeaderChanged(int index);
+ void selectedDateChanged();
+ void minimumDateChanged(const QDate& date);
+ void maximumDateChanged(const QDate& date);
+ void weekdayFormatChanged();
+ void weekendFormatChanged();
+ void reformatHeaders();
+ void reformatCalendarPage();
+
+private:
+ void createPreviewGroupBox();
+ void createGeneralOptionsGroupBox();
+ void createDatesGroupBox();
+ void createTextFormatsGroupBox();
+ QComboBox* createColorComboBox();
+
+ QGroupBox* previewGroupBox;
+ QGridLayout* previewLayout;
+ QCalendarWidget* calendar;
+
+ QGroupBox* generalOptionsGroupBox;
+ QLabel* localeLabel;
+ QLabel* firstDayLabel;
+ QLabel* selectionModeLabel;
+ QLabel* horizontalHeaderLabel;
+ QLabel* verticalHeaderLabel;
+ QComboBox* localeCombo;
+ QComboBox* firstDayCombo;
+ QComboBox* selectionModeCombo;
+ QCheckBox* gridCheckBox;
+ QCheckBox* navigationCheckBox;
+ QComboBox* horizontalHeaderCombo;
+ QComboBox* verticalHeaderCombo;
+
+ QGroupBox* datesGroupBox;
+ QLabel* currentDateLabel;
+ QLabel* minimumDateLabel;
+ QLabel* maximumDateLabel;
+ QDateEdit* currentDateEdit;
+ QDateEdit* minimumDateEdit;
+ QDateEdit* maximumDateEdit;
+
+ QGroupBox* textFormatsGroupBox;
+ QLabel* weekdayColorLabel;
+ QLabel* weekendColorLabel;
+ QLabel* headerTextFormatLabel;
+ QComboBox* weekdayColorCombo;
+ QComboBox* weekendColorCombo;
+ QComboBox* headerTextFormatCombo;
+
+ QCheckBox* firstFridayCheckBox;
+ QCheckBox* mayFirstCheckBox;
+
+ Ui::Window* ui;
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/calwidget.ui b/Tests/QtAutogen/Complex/calwidget.ui
new file mode 100644
index 0000000..1c245ca
--- /dev/null
+++ b/Tests/QtAutogen/Complex/calwidget.ui
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Window</class>
+ <widget class="QWidget" name="Window">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <widget class="QPushButton" name="pushButton">
+ <property name="geometry">
+ <rect>
+ <x>90</x>
+ <y>180</y>
+ <width>94</width>
+ <height>24</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>PushButton</string>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/Complex/codeeditor.cpp b/Tests/QtAutogen/Complex/codeeditor.cpp
new file mode 100644
index 0000000..80d6a55
--- /dev/null
+++ b/Tests/QtAutogen/Complex/codeeditor.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ ** All rights reserved.
+ ** Contact: Nokia Corporation (qt-info@nokia.com)
+ **
+ ** This file is part of the examples of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:BSD$
+ ** You may use this file under the terms of the BSD license as follows:
+ **
+ ** "Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions are
+ ** met:
+ ** * Redistributions of source code must retain the above copyright
+ ** notice, this list of conditions and the following disclaimer.
+ ** * Redistributions in binary form must reproduce the above copyright
+ ** notice, this list of conditions and the following disclaimer in
+ ** the documentation and/or other materials provided with the
+ ** distribution.
+ ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+ ** the names of its contributors may be used to endorse or promote
+ ** products derived from this software without specific prior written
+ ** permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+#include "codeeditor.h"
+
+#include <QPainter>
+#include <QSize>
+#include <QTextBlock>
+#include <QWidget>
+
+CodeEditor::CodeEditor(QWidget* parent)
+ : QPlainTextEdit(parent)
+{
+ lineNumberArea = new LineNumberArea(this);
+
+ connect(this, SIGNAL(blockCountChanged(int)), this,
+ SLOT(updateLineNumberAreaWidth(int)));
+ connect(this, SIGNAL(updateRequest(QRect, int)), this,
+ SLOT(updateLineNumberArea(QRect, int)));
+ connect(this, SIGNAL(cursorPositionChanged()), this,
+ SLOT(highlightCurrentLine()));
+
+ updateLineNumberAreaWidth(0);
+ highlightCurrentLine();
+}
+
+int CodeEditor::lineNumberAreaWidth()
+{
+ int digits = 1;
+ int max = qMax(1, blockCount());
+ while (max >= 10) {
+ max /= 10;
+ ++digits;
+ }
+
+ int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits;
+
+ return space;
+}
+
+void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */)
+{
+ setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
+}
+
+void CodeEditor::updateLineNumberArea(const QRect& rect, int dy)
+{
+ if (dy)
+ lineNumberArea->scroll(0, dy);
+ else
+ lineNumberArea->update(0, rect.y(), lineNumberArea->width(),
+ rect.height());
+
+ if (rect.contains(viewport()->rect()))
+ updateLineNumberAreaWidth(0);
+}
+
+void CodeEditor::resizeEvent(QResizeEvent* e)
+{
+ QPlainTextEdit::resizeEvent(e);
+
+ QRect cr = contentsRect();
+ lineNumberArea->setGeometry(
+ QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
+}
+
+void CodeEditor::highlightCurrentLine()
+{
+ QList<QTextEdit::ExtraSelection> extraSelections;
+
+ if (!isReadOnly()) {
+ QTextEdit::ExtraSelection selection;
+
+ QColor lineColor = QColor(Qt::yellow).lighter(160);
+
+ selection.format.setBackground(lineColor);
+ selection.format.setProperty(QTextFormat::FullWidthSelection, true);
+ selection.cursor = textCursor();
+ selection.cursor.clearSelection();
+ extraSelections.append(selection);
+ }
+
+ setExtraSelections(extraSelections);
+}
+
+void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent* event)
+{
+ QPainter painter(lineNumberArea);
+ painter.fillRect(event->rect(), Qt::lightGray);
+
+ QTextBlock block = firstVisibleBlock();
+ int blockNumber = block.blockNumber();
+ int top =
+ (int)blockBoundingGeometry(block).translated(contentOffset()).top();
+ int bottom = top + (int)blockBoundingRect(block).height();
+
+ while (block.isValid() && top <= event->rect().bottom()) {
+ if (block.isVisible() && bottom >= event->rect().top()) {
+ QString number = QString::number(blockNumber + 1);
+ painter.setPen(Qt::black);
+ painter.drawText(0, top, lineNumberArea->width(), fontMetrics().height(),
+ Qt::AlignRight, number);
+ }
+
+ block = block.next();
+ top = bottom;
+ bottom = top + (int)blockBoundingRect(block).height();
+ ++blockNumber;
+ }
+}
+
+#include "codeeditor.moc"
diff --git a/Tests/QtAutogen/Complex/codeeditor.h b/Tests/QtAutogen/Complex/codeeditor.h
new file mode 100644
index 0000000..b410bd4
--- /dev/null
+++ b/Tests/QtAutogen/Complex/codeeditor.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CODEEDITOR_H
+#define CODEEDITOR_H
+
+#include <QObject>
+#include <QPlainTextEdit>
+
+class QPaintEvent;
+class QResizeEvent;
+class QSize;
+class QWidget;
+
+class LineNumberArea;
+
+class CodeEditor : public QPlainTextEdit
+{
+ Q_OBJECT
+
+public:
+ CodeEditor(QWidget* parent = 0);
+
+ void lineNumberAreaPaintEvent(QPaintEvent* event);
+ int lineNumberAreaWidth();
+
+protected:
+ void resizeEvent(QResizeEvent* event);
+
+private slots:
+ void updateLineNumberAreaWidth(int newBlockCount);
+ void highlightCurrentLine();
+ void updateLineNumberArea(const QRect&, int);
+
+private:
+ QWidget* lineNumberArea;
+};
+
+class LineNumberArea : public QWidget
+{
+public:
+ LineNumberArea(CodeEditor* editor)
+ : QWidget(editor)
+ {
+ codeEditor = editor;
+ }
+
+ QSize sizeHint() const
+ {
+ return QSize(codeEditor->lineNumberAreaWidth(), 0);
+ }
+
+protected:
+ void paintEvent(QPaintEvent* event)
+ {
+ codeEditor->lineNumberAreaPaintEvent(event);
+ }
+
+private:
+ CodeEditor* codeEditor;
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/debug_class.cpp b/Tests/QtAutogen/Complex/debug_class.cpp
new file mode 100644
index 0000000..3aaf79a
--- /dev/null
+++ b/Tests/QtAutogen/Complex/debug_class.cpp
@@ -0,0 +1,11 @@
+
+#include "debug_class.h"
+
+#include "ui_debug_class.h"
+
+DebugClass::DebugClass(QWidget* parent)
+ : QWidget(parent)
+ , ui(new Ui::DebugClass)
+{
+ ui->setupUi(this);
+}
diff --git a/Tests/QtAutogen/Complex/debug_class.h b/Tests/QtAutogen/Complex/debug_class.h
new file mode 100644
index 0000000..c02f0ed
--- /dev/null
+++ b/Tests/QtAutogen/Complex/debug_class.h
@@ -0,0 +1,19 @@
+
+#include <QWidget>
+
+namespace Ui {
+class DebugClass;
+}
+
+class DebugClass : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit DebugClass(QWidget* parent = 0);
+
+signals:
+ void someSignal();
+
+private:
+ Ui::DebugClass* ui;
+};
diff --git a/Tests/QtAutogen/Complex/debug_class.ui b/Tests/QtAutogen/Complex/debug_class.ui
new file mode 100644
index 0000000..dc2e1ac
--- /dev/null
+++ b/Tests/QtAutogen/Complex/debug_class.ui
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DebugClass</class>
+ <widget class="QWidget" name="DebugClass">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>DebugClass</string>
+ </property>
+ <widget class="QCheckBox" name="checkBox">
+ <property name="geometry">
+ <rect>
+ <x>50</x>
+ <y>20</y>
+ <width>82</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>CheckBox</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" name="pushButton">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>70</y>
+ <width>94</width>
+ <height>24</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>PushButton</string>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/Complex/debug_resource.qrc b/Tests/QtAutogen/Complex/debug_resource.qrc
new file mode 100644
index 0000000..db98b9b
--- /dev/null
+++ b/Tests/QtAutogen/Complex/debug_resource.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>debug_class.ui</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Complex/foo.cpp b/Tests/QtAutogen/Complex/foo.cpp
new file mode 100644
index 0000000..f665eee
--- /dev/null
+++ b/Tests/QtAutogen/Complex/foo.cpp
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "foo.h"
+
+#include <stdio.h>
+
+class FooFoo : public QObject
+{
+ Q_OBJECT
+public:
+ FooFoo()
+ : QObject()
+ {
+ }
+public slots:
+ int getValue() const { return 12; }
+};
+
+Foo::Foo()
+ : QObject()
+{
+}
+
+void Foo::doFoo()
+{
+ FooFoo ff;
+ printf("Hello automoc: %d\n", ff.getValue());
+}
+
+#include "foo.moc"
diff --git a/Tests/QtAutogen/Complex/foo.h b/Tests/QtAutogen/Complex/foo.h
new file mode 100644
index 0000000..3e03fe6
--- /dev/null
+++ b/Tests/QtAutogen/Complex/foo.h
@@ -0,0 +1,20 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef FOO_H
+#define FOO_H
+
+#include <QObject>
+
+class Foo
+#ifdef FOO
+ : public QObject
+#endif
+{
+ Q_OBJECT
+public:
+ Foo();
+public slots:
+ void doFoo();
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/gadget.cpp b/Tests/QtAutogen/Complex/gadget.cpp
new file mode 100644
index 0000000..23d95fa
--- /dev/null
+++ b/Tests/QtAutogen/Complex/gadget.cpp
@@ -0,0 +1,4 @@
+
+#include "gadget.h"
+
+#include "moc_gadget.cpp"
diff --git a/Tests/QtAutogen/Complex/gadget.h b/Tests/QtAutogen/Complex/gadget.h
new file mode 100644
index 0000000..3253e31
--- /dev/null
+++ b/Tests/QtAutogen/Complex/gadget.h
@@ -0,0 +1,19 @@
+
+#ifndef GADGET_H
+#define GADGET_H
+
+#include <QObject>
+
+class Gadget
+{
+ Q_GADGET
+ Q_ENUMS(Type)
+public:
+ enum Type
+ {
+ Type0,
+ Type1
+ };
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/generated.cpp b/Tests/QtAutogen/Complex/generated.cpp
new file mode 100644
index 0000000..d514c61
--- /dev/null
+++ b/Tests/QtAutogen/Complex/generated.cpp
@@ -0,0 +1,9 @@
+
+#include "generated.h"
+
+Generated::Generated(QObject* parent)
+ : QObject(parent)
+{
+}
+
+#include "moc_generated.cpp"
diff --git a/Tests/QtAutogen/Complex/generated.h b/Tests/QtAutogen/Complex/generated.h
new file mode 100644
index 0000000..cac14de
--- /dev/null
+++ b/Tests/QtAutogen/Complex/generated.h
@@ -0,0 +1,21 @@
+
+#ifndef GENERATED_H
+#define GENERATED_H
+
+#include <QObject>
+
+#include "myinterface.h"
+#include "myotherinterface.h"
+
+class Generated
+ : public QObject
+ , MyInterface
+ , MyOtherInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(MyInterface MyOtherInterface)
+public:
+ explicit Generated(QObject* parent = 0);
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/generated.txt.in b/Tests/QtAutogen/Complex/generated.txt.in
new file mode 100644
index 0000000..77507bb
--- /dev/null
+++ b/Tests/QtAutogen/Complex/generated.txt.in
@@ -0,0 +1 @@
+Some generated text file.
diff --git a/Tests/QtAutogen/Complex/generated_resource.qrc.in b/Tests/QtAutogen/Complex/generated_resource.qrc.in
new file mode 100644
index 0000000..da5fa62
--- /dev/null
+++ b/Tests/QtAutogen/Complex/generated_resource.qrc.in
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>generated.txt</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Complex/libC.cpp b/Tests/QtAutogen/Complex/libC.cpp
new file mode 100644
index 0000000..a3acff1
--- /dev/null
+++ b/Tests/QtAutogen/Complex/libC.cpp
@@ -0,0 +1,12 @@
+
+#include "libC.h"
+
+LibC::LibC(QObject* parent)
+ : QObject(parent)
+{
+}
+
+int LibC::foo()
+{
+ return b.foo();
+}
diff --git a/Tests/QtAutogen/Complex/libC.h b/Tests/QtAutogen/Complex/libC.h
new file mode 100644
index 0000000..51ea48d
--- /dev/null
+++ b/Tests/QtAutogen/Complex/libC.h
@@ -0,0 +1,22 @@
+
+#ifndef LIBC_H
+#define LIBC_H
+
+#include <QObject>
+
+#include "libB.h"
+#include "libc_export.h"
+
+class LIBC_EXPORT LibC : public QObject
+{
+ Q_OBJECT
+public:
+ explicit LibC(QObject* parent = 0);
+
+ int foo();
+
+private:
+ LibB b;
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/main.cpp b/Tests/QtAutogen/Complex/main.cpp
new file mode 100644
index 0000000..12f649f
--- /dev/null
+++ b/Tests/QtAutogen/Complex/main.cpp
@@ -0,0 +1,94 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ ** All rights reserved.
+ ** Contact: Nokia Corporation (qt-info@nokia.com)
+ **
+ ** This file is part of the examples of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:BSD$
+ ** You may use this file under the terms of the BSD license as follows:
+ **
+ ** "Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions are
+ ** met:
+ ** * Redistributions of source code must retain the above copyright
+ ** notice, this list of conditions and the following disclaimer.
+ ** * Redistributions in binary form must reproduce the above copyright
+ ** notice, this list of conditions and the following disclaimer in
+ ** the documentation and/or other materials provided with the
+ ** distribution.
+ ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+ ** the names of its contributors may be used to endorse or promote
+ ** products derived from this software without specific prior written
+ ** permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+#include <QCoreApplication>
+#include <QTimer>
+
+#include "abc.h"
+#include "blub.h"
+#include "calwidget.h"
+#include "codeeditor.h"
+#include "foo.h"
+#include "libC.h"
+#include "resourcetester.h"
+#include "sub/bar.h"
+#include "xyz.h"
+#include "yaf.h"
+#ifdef TEST_DEBUG_CLASS
+# include <iostream>
+
+# include "debug_class.h"
+#endif
+
+int main(int argv, char** args)
+{
+ QCoreApplication app(argv, args);
+
+ Foo foo;
+ foo.doFoo();
+
+ Blub b;
+ b.blubber();
+
+ Bar bar;
+ bar.doBar();
+
+ Abc abc;
+ abc.doAbc();
+
+ Xyz xyz;
+ xyz.doXyz();
+
+ Yaf yaf;
+ yaf.doYaf();
+
+ LibC lc;
+ lc.foo();
+
+ ResourceTester rt;
+
+ QTimer::singleShot(0, &rt, SLOT(doTest()));
+
+#ifdef TEST_DEBUG_CLASS
+ std::cout << DebugClass::staticMetaObject.className() << std::endl;
+#endif
+
+ return app.exec();
+}
diff --git a/Tests/QtAutogen/Complex/multiplewidgets.cpp b/Tests/QtAutogen/Complex/multiplewidgets.cpp
new file mode 100644
index 0000000..fda36ea
--- /dev/null
+++ b/Tests/QtAutogen/Complex/multiplewidgets.cpp
@@ -0,0 +1,19 @@
+
+#include "multiplewidgets.h"
+
+#include "ui_widget1.h"
+#include "ui_widget2.h"
+
+Widget1::Widget1(QWidget* parent)
+ : QWidget(parent)
+ , ui(new Ui::Widget1)
+{
+ ui->setupUi(this);
+}
+
+Widget2::Widget2(QWidget* parent)
+ : QWidget(parent)
+ , ui(new Ui::Widget2)
+{
+ ui->setupUi(this);
+}
diff --git a/Tests/QtAutogen/Complex/multiplewidgets.h b/Tests/QtAutogen/Complex/multiplewidgets.h
new file mode 100644
index 0000000..a4d0a50
--- /dev/null
+++ b/Tests/QtAutogen/Complex/multiplewidgets.h
@@ -0,0 +1,35 @@
+
+#ifndef MULTIPLEWIDGETS_H
+#define MULTIPLEWIDGETS_H
+
+#include <QWidget>
+
+namespace Ui {
+class Widget1;
+}
+
+class Widget1 : public QWidget
+{
+ Q_OBJECT
+public:
+ Widget1(QWidget* parent = 0);
+
+private:
+ Ui::Widget1* ui;
+};
+
+namespace Ui {
+class Widget2;
+}
+
+class Widget2 : public QWidget
+{
+ Q_OBJECT
+public:
+ Widget2(QWidget* parent = 0);
+
+private:
+ Ui::Widget2* ui;
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/myinterface.h.in b/Tests/QtAutogen/Complex/myinterface.h.in
new file mode 100644
index 0000000..c6c0ba1
--- /dev/null
+++ b/Tests/QtAutogen/Complex/myinterface.h.in
@@ -0,0 +1,14 @@
+
+#ifndef MYINTERFACE_H
+#define MYINTERFACE_H
+
+#include <QObject>
+
+class MyInterface
+{
+
+};
+
+Q_DECLARE_INTERFACE(MyInterface, "org.cmake.example.MyInterface")
+
+#endif
diff --git a/Tests/QtAutogen/Complex/myotherinterface.h.in b/Tests/QtAutogen/Complex/myotherinterface.h.in
new file mode 100644
index 0000000..d21e7af
--- /dev/null
+++ b/Tests/QtAutogen/Complex/myotherinterface.h.in
@@ -0,0 +1,14 @@
+
+#ifndef MYOTHERINTERFACE_H
+#define MYOTHERINTERFACE_H
+
+#include <QObject>
+
+class MyOtherInterface
+{
+
+};
+
+Q_DECLARE_INTERFACE(MyOtherInterface, "org.cmake.example.MyOtherInterface")
+
+#endif
diff --git a/Tests/QtAutogen/Complex/private_slot.cpp b/Tests/QtAutogen/Complex/private_slot.cpp
new file mode 100644
index 0000000..ab1682a
--- /dev/null
+++ b/Tests/QtAutogen/Complex/private_slot.cpp
@@ -0,0 +1,16 @@
+
+#include "private_slot.h"
+
+class PrivateSlotPrivate
+{
+public:
+ void privateSlot() {}
+};
+
+PrivateSlot::PrivateSlot(QObject* parent)
+ : QObject(parent)
+ , d(new PrivateSlotPrivate)
+{
+}
+
+#include "private_slot.moc"
diff --git a/Tests/QtAutogen/Complex/private_slot.h b/Tests/QtAutogen/Complex/private_slot.h
new file mode 100644
index 0000000..8041eb2
--- /dev/null
+++ b/Tests/QtAutogen/Complex/private_slot.h
@@ -0,0 +1,20 @@
+
+#ifndef PRIVATE_SLOT_H
+#define PRIVATE_SLOT_H
+
+#include <QObject>
+
+class PrivateSlotPrivate;
+
+class PrivateSlot : public QObject
+{
+ Q_OBJECT
+public:
+ PrivateSlot(QObject* parent = 0);
+
+private:
+ PrivateSlotPrivate* const d;
+ Q_PRIVATE_SLOT(d, void privateSlot())
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/resourcetester.cpp b/Tests/QtAutogen/Complex/resourcetester.cpp
new file mode 100644
index 0000000..4ecb6b4
--- /dev/null
+++ b/Tests/QtAutogen/Complex/resourcetester.cpp
@@ -0,0 +1,26 @@
+
+#include "resourcetester.h"
+
+#include <QApplication>
+#include <QDebug>
+#include <QFile>
+#include <QTimer>
+
+ResourceTester::ResourceTester(QObject* parent)
+ : QObject(parent)
+{
+}
+
+void ResourceTester::doTest()
+{
+ if (!QFile::exists(":/CMakeLists.txt"))
+ qApp->exit(EXIT_FAILURE);
+ if (!QFile::exists(":/main.cpp"))
+ qApp->exit(EXIT_FAILURE);
+#ifdef TEST_DEBUG_CLASS
+ if (!QFile::exists(":/debug_class.ui"))
+ qApp->exit(EXIT_FAILURE);
+#endif
+
+ QTimer::singleShot(0, qApp, SLOT(quit()));
+}
diff --git a/Tests/QtAutogen/Complex/resourcetester.h b/Tests/QtAutogen/Complex/resourcetester.h
new file mode 100644
index 0000000..dbdb3ad
--- /dev/null
+++ b/Tests/QtAutogen/Complex/resourcetester.h
@@ -0,0 +1,17 @@
+
+#ifndef RESOURCE_TESTER_H
+#define RESOURCE_TESTER_H
+
+#include <QObject>
+
+class ResourceTester : public QObject
+{
+ Q_OBJECT
+public:
+ explicit ResourceTester(QObject* parent = 0);
+
+private slots:
+ void doTest();
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/second_resource.qrc b/Tests/QtAutogen/Complex/second_resource.qrc
new file mode 100644
index 0000000..27bfb14
--- /dev/null
+++ b/Tests/QtAutogen/Complex/second_resource.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>main.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Complex/second_widget.cpp b/Tests/QtAutogen/Complex/second_widget.cpp
new file mode 100644
index 0000000..9f51a80
--- /dev/null
+++ b/Tests/QtAutogen/Complex/second_widget.cpp
@@ -0,0 +1,16 @@
+
+#include "second_widget.h"
+
+#include "ui_second_widget.h"
+
+SecondWidget::SecondWidget(QWidget* parent)
+ : QWidget(parent)
+ , ui(new Ui::SecondWidget)
+{
+ ui->setupUi(this);
+}
+
+SecondWidget::~SecondWidget()
+{
+ delete ui;
+}
diff --git a/Tests/QtAutogen/Complex/second_widget.h b/Tests/QtAutogen/Complex/second_widget.h
new file mode 100644
index 0000000..c7929c4
--- /dev/null
+++ b/Tests/QtAutogen/Complex/second_widget.h
@@ -0,0 +1,18 @@
+
+#include <QWidget>
+
+namespace Ui {
+class SecondWidget;
+}
+
+class SecondWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit SecondWidget(QWidget* parent = 0);
+
+ ~SecondWidget();
+
+private:
+ Ui::SecondWidget* ui;
+};
diff --git a/Tests/QtAutogen/Complex/second_widget.ui b/Tests/QtAutogen/Complex/second_widget.ui
new file mode 100644
index 0000000..4effa58
--- /dev/null
+++ b/Tests/QtAutogen/Complex/second_widget.ui
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SecondWidget</class>
+ <widget class="QWidget" name="SecondWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <widget class="QPushButton" name="pushButton">
+ <property name="geometry">
+ <rect>
+ <x>80</x>
+ <y>20</y>
+ <width>94</width>
+ <height>24</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>PushButton</string>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/Complex/sub/bar.h b/Tests/QtAutogen/Complex/sub/bar.h
new file mode 100644
index 0000000..e4093f6
--- /dev/null
+++ b/Tests/QtAutogen/Complex/sub/bar.h
@@ -0,0 +1,17 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef BAR_H
+#define BAR_H
+
+#include <QObject>
+
+class Bar : public QObject
+{
+ Q_OBJECT
+public:
+ Bar();
+public slots:
+ void doBar();
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/targetObjectsTest.cpp b/Tests/QtAutogen/Complex/targetObjectsTest.cpp
new file mode 100644
index 0000000..766b775
--- /dev/null
+++ b/Tests/QtAutogen/Complex/targetObjectsTest.cpp
@@ -0,0 +1,5 @@
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/QtAutogen/Complex/test.qrc b/Tests/QtAutogen/Complex/test.qrc
new file mode 100644
index 0000000..c3d4e3c
--- /dev/null
+++ b/Tests/QtAutogen/Complex/test.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>CMakeLists.txt</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Complex/widget1.ui b/Tests/QtAutogen/Complex/widget1.ui
new file mode 100644
index 0000000..8fce81a
--- /dev/null
+++ b/Tests/QtAutogen/Complex/widget1.ui
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Widget1</class>
+ <widget class="QWidget" name="Widget1">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <widget class="QPushButton" name="pushButton">
+ <property name="geometry">
+ <rect>
+ <x>140</x>
+ <y>80</y>
+ <width>80</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>PushButton</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" name="pushButton_2">
+ <property name="geometry">
+ <rect>
+ <x>190</x>
+ <y>170</y>
+ <width>80</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>PushButton</string>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/Complex/widget2.ui b/Tests/QtAutogen/Complex/widget2.ui
new file mode 100644
index 0000000..1f411b9
--- /dev/null
+++ b/Tests/QtAutogen/Complex/widget2.ui
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Widget2</class>
+ <widget class="QWidget" name="Widget1">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <widget class="QListWidget" name="listWidget">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>20</y>
+ <width>256</width>
+ <height>192</height>
+ </rect>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/Complex/xyz.cpp b/Tests/QtAutogen/Complex/xyz.cpp
new file mode 100644
index 0000000..e46c9d3
--- /dev/null
+++ b/Tests/QtAutogen/Complex/xyz.cpp
@@ -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. */
+#include "xyz.h"
+
+#include <stdio.h>
+
+Xyz::Xyz()
+ : QObject()
+{
+}
+
+void Xyz::doXyz()
+{
+ printf("This is xyz !\n");
+}
diff --git a/Tests/QtAutogen/Complex/xyz.h b/Tests/QtAutogen/Complex/xyz.h
new file mode 100644
index 0000000..8b813fd
--- /dev/null
+++ b/Tests/QtAutogen/Complex/xyz.h
@@ -0,0 +1,17 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef XYZ_H
+#define XYZ_H
+
+#include <QObject>
+
+class Xyz : public QObject
+{
+ Q_OBJECT
+public:
+ Xyz();
+public slots:
+ void doXyz();
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/yaf.cpp b/Tests/QtAutogen/Complex/yaf.cpp
new file mode 100644
index 0000000..10448c1
--- /dev/null
+++ b/Tests/QtAutogen/Complex/yaf.cpp
@@ -0,0 +1,20 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "yaf.h"
+
+#include <stdio.h>
+
+#include "yaf_p.h"
+
+Yaf::Yaf()
+{
+}
+
+void Yaf::doYaf()
+{
+ YafP yafP;
+ yafP.doYafP();
+}
+
+// check that including a moc file from a private header the wrong way works:
+#include "yaf_p.moc"
diff --git a/Tests/QtAutogen/Complex/yaf.h b/Tests/QtAutogen/Complex/yaf.h
new file mode 100644
index 0000000..f271061
--- /dev/null
+++ b/Tests/QtAutogen/Complex/yaf.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. */
+#ifndef YAF_H
+#define YAF_H
+
+class Yaf
+{
+public:
+ Yaf();
+
+public:
+ void doYaf();
+};
+
+#endif
diff --git a/Tests/QtAutogen/Complex/yaf_p.h b/Tests/QtAutogen/Complex/yaf_p.h
new file mode 100644
index 0000000..48fdd30
--- /dev/null
+++ b/Tests/QtAutogen/Complex/yaf_p.h
@@ -0,0 +1,19 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef YAF_P_H
+#define YAF_P_H
+
+#include <stdio.h>
+
+#include <QObject>
+
+class YafP : public QObject
+{
+ Q_OBJECT
+public:
+ YafP() {}
+public slots:
+ void doYafP() { printf("I am yet another file !\n"); }
+};
+
+#endif
diff --git a/Tests/QtAutogen/DefinesTest/CMakeLists.txt b/Tests/QtAutogen/DefinesTest/CMakeLists.txt
new file mode 100644
index 0000000..3761dd8
--- /dev/null
+++ b/Tests/QtAutogen/DefinesTest/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.10)
+project(DefinesTest)
+
+# Qt4 only definitions test
+if(NOT QT_TEST_VERSION EQUAL 4)
+ message(ERROR "Invalid Qt test version. This test is for Qt4 only.")
+endif()
+
+find_package(Qt4 REQUIRED)
+
+add_executable(DefinesTest defines_test.cpp)
+set_target_properties(DefinesTest PROPERTIES AUTOMOC TRUE)
+target_link_libraries(DefinesTest Qt4::QtGui)
diff --git a/Tests/QtAutogen/DefinesTest/defines_test.cpp b/Tests/QtAutogen/DefinesTest/defines_test.cpp
new file mode 100644
index 0000000..a533622
--- /dev/null
+++ b/Tests/QtAutogen/DefinesTest/defines_test.cpp
@@ -0,0 +1,38 @@
+
+#include <QObject>
+
+#ifdef QT_GUI_LIB
+# include <QTextDocument>
+
+class SomeDocument : public QTextDocument
+{
+ Q_OBJECT
+
+Q_SIGNALS:
+ void someSig();
+};
+#endif
+
+#ifdef QT_CORE_LIB
+class SomeObject : public QObject
+{
+ Q_OBJECT
+
+Q_SIGNALS:
+ void someSig();
+};
+#endif
+
+int main(int argc, char** argv)
+{
+#ifdef QT_CORE_LIB
+ QMetaObject sosmo = SomeObject::staticMetaObject;
+#endif
+#ifdef QT_GUI_LIB
+ QMetaObject sdsmo = SomeDocument::staticMetaObject;
+#endif
+
+ return 0;
+}
+
+#include "defines_test.moc"
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt b/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
new file mode 100644
index 0000000..e95c626
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
@@ -0,0 +1,126 @@
+cmake_minimum_required(VERSION 3.12)
+project(GlobalAutogenTarget)
+include("../AutogenCoreTest.cmake")
+
+# This tests
+# CMAKE_GLOBAL_AUTOGEN_TARGET,
+# CMAKE_GLOBAL_AUTORCC_TARGET,
+# CMAKE_GLOBAL_AUTOGEN_TARGET_NAME and
+# CMAKE_GLOBAL_AUTORCC_TARGET_NAME
+# for the latter two with different values in different subdirectories.
+
+# Directories
+set(GAT_SDIR "${CMAKE_CURRENT_SOURCE_DIR}/GAT")
+set(GAT_BDIR "${CMAKE_CURRENT_BINARY_DIR}/GAT")
+# Files
+set(MCA "sda/sda_autogen/mocs_compilation*.cpp")
+set(MCB "sdb/sdb_autogen/mocs_compilation*.cpp")
+set(MCC "sdc/sdc_autogen/mocs_compilation*.cpp")
+set(MCG "gat_autogen/mocs_compilation*.cpp")
+
+set(DRA "sda/sda_autogen/*qrc_data.cpp")
+set(DRB "sdb/sdb_autogen/*qrc_data.cpp")
+set(DRC "sdc/sdc_autogen/*qrc_data.cpp")
+set(DRG "gat_autogen/*qrc_data.cpp")
+
+# -- Utility macros
+macro(GAT_FIND_FILES VAR NAME)
+ file(GLOB_RECURSE ${VAR} ${GAT_BDIR}/*${NAME})
+endmacro()
+
+macro(GAT_FIND_FILE NAME)
+ GAT_FIND_FILES(LST ${NAME})
+ if(LST)
+ message("Good find ${LST}")
+ else()
+ message(SEND_ERROR "Expected to find ${GAT_BDIR}/${NAME}")
+ endif()
+ unset(LST)
+endmacro()
+
+macro(GAT_FIND_FILE_NOT NAME)
+ GAT_FIND_FILES(LST ${NAME})
+ if(LST)
+ message(SEND_ERROR "Not expected to find ${GAT_BDIR}/${NAME}")
+ else()
+ message("Good not find ${GAT_BDIR}/${NAME}")
+ endif()
+ unset(LST)
+endmacro()
+
+macro(GAT_BUILD_TARGET NAME)
+ message("___ Building GAT ${NAME} target ___")
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}" --build "${GAT_BDIR}" --target ${NAME}
+ WORKING_DIRECTORY "${GAT_BDIR}"
+ RESULT_VARIABLE result)
+ if (result)
+ message(SEND_ERROR "Building of GAT ${NAME} target failed")
+ endif()
+endmacro()
+
+
+# -- Remove and recreate build directory
+file(REMOVE_RECURSE ${GAT_BDIR})
+file(MAKE_DIRECTORY ${GAT_BDIR})
+
+
+# -- Configure project
+message("___ Configuring GAT project ___")
+execute_process(
+ COMMAND "${CMAKE_COMMAND}" "${GAT_SDIR}"
+ -G "${CMAKE_GENERATOR}"
+ -A "${CMAKE_GENERATOR_PLATFORM}"
+ -T "${CMAKE_GENERATOR_TOOLSET}"
+ "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
+ "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+ "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+ WORKING_DIRECTORY "${GAT_BDIR}"
+ OUTPUT_VARIABLE output
+ RESULT_VARIABLE result)
+if (result)
+ message(SEND_ERROR "Configuring of GAT project failed")
+else()
+ message("Configuring of GAT project succeeded")
+ message("${output}")
+endif()
+
+
+# -- Build autogen subtargets
+GAT_BUILD_TARGET("autogen")
+GAT_FIND_FILE("${MCA}")
+GAT_FIND_FILE_NOT("${MCB}")
+GAT_FIND_FILE_NOT("${MCC}")
+GAT_FIND_FILE("${MCG}")
+
+GAT_BUILD_TARGET("global_autogen_sdb")
+GAT_FIND_FILE("${MCA}")
+GAT_FIND_FILE("${MCB}")
+GAT_FIND_FILE_NOT("${MCC}")
+GAT_FIND_FILE("${MCG}")
+
+GAT_BUILD_TARGET("all_autogen")
+GAT_FIND_FILE("${MCA}")
+GAT_FIND_FILE("${MCB}")
+GAT_FIND_FILE("${MCC}")
+GAT_FIND_FILE("${MCG}")
+
+
+# -- Build autorcc subtargets
+GAT_BUILD_TARGET("autorcc")
+GAT_FIND_FILE("${DRA}")
+GAT_FIND_FILE_NOT("${DRB}")
+GAT_FIND_FILE_NOT("${DRC}")
+GAT_FIND_FILE("${DRG}")
+
+GAT_BUILD_TARGET("global_autorcc_sdb")
+GAT_FIND_FILE("${DRA}")
+GAT_FIND_FILE("${DRB}")
+GAT_FIND_FILE_NOT("${DRC}")
+GAT_FIND_FILE("${DRG}")
+
+GAT_BUILD_TARGET("all_autorcc")
+GAT_FIND_FILE("${DRA}")
+GAT_FIND_FILE("${DRB}")
+GAT_FIND_FILE("${DRC}")
+GAT_FIND_FILE("${DRG}")
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/CMakeLists.txt b/Tests/QtAutogen/GlobalAutogenTarget/GAT/CMakeLists.txt
new file mode 100644
index 0000000..3925197
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.12)
+project(GAT)
+include("../../AutogenCoreTest.cmake")
+
+# Include directories
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+# Enable AUTOMOC/UIC/RCC
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTORCC ON)
+# Disable ORIGN_DEPENDS and enable AUTOGEN global targets
+set(CMAKE_AUTOGEN_ORIGIN_DEPENDS OFF)
+set(CMAKE_GLOBAL_AUTOGEN_TARGET ON)
+set(CMAKE_GLOBAL_AUTORCC_TARGET ON)
+
+add_subdirectory(sda)
+add_subdirectory(sdb)
+add_subdirectory(sdc)
+
+# Add custom target that depends on all autogen/autorcc targets
+add_custom_target(all_autogen DEPENDS autogen global_autogen_sdb global_autogen_sdc)
+add_custom_target(all_autorcc DEPENDS autorcc global_autorcc_sdb global_autorcc_sdc)
+
+# Main target
+add_executable(gat data.qrc item.cpp main.cpp)
+target_link_libraries(gat ${QT_LIBRARIES})
+target_link_libraries(gat sda sdb sdc)
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/data.qrc b/Tests/QtAutogen/GlobalAutogenTarget/GAT/data.qrc
new file mode 100644
index 0000000..68d02c9
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/data.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/item.cpp b/Tests/QtAutogen/GlobalAutogenTarget/GAT/item.cpp
new file mode 100644
index 0000000..3d1fbe7
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/item.cpp
@@ -0,0 +1,20 @@
+#include "item.hpp"
+// Include ui_view.h in source and header
+#include <ui_view.h>
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ Ui_View ui;
+ MocLocal obj;
+}
+
+#include "item.moc"
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/item.hpp b/Tests/QtAutogen/GlobalAutogenTarget/GAT/item.hpp
new file mode 100644
index 0000000..75e83f4
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/item.hpp
@@ -0,0 +1,15 @@
+#ifndef ITEM_HPP
+#define ITEM_HPP
+
+#include <QObject>
+// Include ui_view.h in source and header
+#include <ui_view.h>
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+
+#endif
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/main.cpp b/Tests/QtAutogen/GlobalAutogenTarget/GAT/main.cpp
new file mode 100644
index 0000000..79c00b4
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/main.cpp
@@ -0,0 +1,15 @@
+#include "item.hpp"
+#include "sda/sda.hpp"
+#include "sdb/sdb.hpp"
+#include "sdc/sdc.hpp"
+
+int main(int argv, char** args)
+{
+ // Object instances
+ Item item;
+ // Library calls
+ sda();
+ sdb();
+ sdc();
+ return 0;
+}
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/CMakeLists.txt b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/CMakeLists.txt
new file mode 100644
index 0000000..795e91e
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(sda ../item.cpp ../data.qrc sda.cpp)
+target_link_libraries(sda ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/sda.cpp b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/sda.cpp
new file mode 100644
index 0000000..ec4dec8
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/sda.cpp
@@ -0,0 +1,6 @@
+#include <item.hpp>
+
+void sda()
+{
+ Item item;
+}
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/sda.hpp b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/sda.hpp
new file mode 100644
index 0000000..89ac744
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/sda.hpp
@@ -0,0 +1,6 @@
+#ifndef SDA_HPP
+#define SDA_HPP
+
+void sda();
+
+#endif
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/CMakeLists.txt b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/CMakeLists.txt
new file mode 100644
index 0000000..5c686fe
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(CMAKE_GLOBAL_AUTOGEN_TARGET_NAME "global_autogen_sdb")
+set(CMAKE_GLOBAL_AUTORCC_TARGET_NAME "global_autorcc_sdb")
+
+add_library(sdb ../item.cpp ../data.qrc sdb.cpp)
+target_link_libraries(sdb ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/sdb.cpp b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/sdb.cpp
new file mode 100644
index 0000000..e32c467
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/sdb.cpp
@@ -0,0 +1,6 @@
+#include <item.hpp>
+
+void sdb()
+{
+ Item item;
+}
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/sdb.hpp b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/sdb.hpp
new file mode 100644
index 0000000..a5b0f62
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/sdb.hpp
@@ -0,0 +1,6 @@
+#ifndef SDB_HPP
+#define SDB_HPP
+
+void sdb();
+
+#endif
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/CMakeLists.txt b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/CMakeLists.txt
new file mode 100644
index 0000000..2698bda
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(CMAKE_GLOBAL_AUTOGEN_TARGET_NAME "global_autogen_sdc")
+set(CMAKE_GLOBAL_AUTORCC_TARGET_NAME "global_autorcc_sdc")
+
+add_library(sdc ../item.cpp ../data.qrc sdc.cpp)
+target_link_libraries(sdc ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/sdc.cpp b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/sdc.cpp
new file mode 100644
index 0000000..a97cd42
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/sdc.cpp
@@ -0,0 +1,6 @@
+#include <item.hpp>
+
+void sdc()
+{
+ Item item;
+}
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/sdc.hpp b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/sdc.hpp
new file mode 100644
index 0000000..7e92179
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/sdc.hpp
@@ -0,0 +1,6 @@
+#ifndef SDC_HPP
+#define SDC_HPP
+
+void sdc();
+
+#endif
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/GAT/view.ui b/Tests/QtAutogen/GlobalAutogenTarget/GAT/view.ui
new file mode 100644
index 0000000..2ffe734
--- /dev/null
+++ b/Tests/QtAutogen/GlobalAutogenTarget/GAT/view.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>View</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/LowMinimumVersion/CMakeLists.txt b/Tests/QtAutogen/LowMinimumVersion/CMakeLists.txt
new file mode 100644
index 0000000..e1af3d8
--- /dev/null
+++ b/Tests/QtAutogen/LowMinimumVersion/CMakeLists.txt
@@ -0,0 +1,16 @@
+# Use a low minimum version
+cmake_minimum_required(VERSION 3.0)
+project(LowMinimumVersion)
+include("../AutogenGuiTest.cmake")
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTORCC ON)
+add_executable(lowMinimumVersion
+ main.cpp
+ item.hpp
+ item.cpp
+ view.ui
+ someText.txt
+ example.qrc)
+target_link_libraries(lowMinimumVersion ${QT_QTCORE_TARGET})
diff --git a/Tests/QtAutogen/LowMinimumVersion/example.qrc b/Tests/QtAutogen/LowMinimumVersion/example.qrc
new file mode 100644
index 0000000..551ecc8
--- /dev/null
+++ b/Tests/QtAutogen/LowMinimumVersion/example.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="Example">
+ <file>someText.txt</file>
+ </qresource>
+</RCC>
diff --git a/Tests/QtAutogen/LowMinimumVersion/item.cpp b/Tests/QtAutogen/LowMinimumVersion/item.cpp
new file mode 100644
index 0000000..511a1ca
--- /dev/null
+++ b/Tests/QtAutogen/LowMinimumVersion/item.cpp
@@ -0,0 +1,20 @@
+#include "item.hpp"
+
+#include <ui_view.h>
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ Ui_View ui;
+ MocLocal obj;
+}
+
+#include "item.moc"
diff --git a/Tests/QtAutogen/LowMinimumVersion/item.hpp b/Tests/QtAutogen/LowMinimumVersion/item.hpp
new file mode 100644
index 0000000..01255d4
--- /dev/null
+++ b/Tests/QtAutogen/LowMinimumVersion/item.hpp
@@ -0,0 +1,15 @@
+#ifndef ITEM_HPP
+#define ITEM_HPP
+
+#include <QObject>
+
+class Item : public QObject
+{
+ Q_OBJECT
+
+public:
+ Q_SLOT
+ void go();
+};
+
+#endif
diff --git a/Tests/QtAutogen/LowMinimumVersion/main.cpp b/Tests/QtAutogen/LowMinimumVersion/main.cpp
new file mode 100644
index 0000000..9f225a4
--- /dev/null
+++ b/Tests/QtAutogen/LowMinimumVersion/main.cpp
@@ -0,0 +1,10 @@
+#include "item.hpp"
+
+int main(int argc, char* argv[])
+{
+ Q_INIT_RESOURCE(example);
+ Item item;
+ item.go();
+
+ return 0;
+}
diff --git a/Tests/QtAutogen/LowMinimumVersion/someText.txt b/Tests/QtAutogen/LowMinimumVersion/someText.txt
new file mode 100644
index 0000000..750dae3
--- /dev/null
+++ b/Tests/QtAutogen/LowMinimumVersion/someText.txt
@@ -0,0 +1 @@
+Hello world, you're an interesting place.
diff --git a/Tests/QtAutogen/LowMinimumVersion/view.ui b/Tests/QtAutogen/LowMinimumVersion/view.ui
new file mode 100644
index 0000000..2ffe734
--- /dev/null
+++ b/Tests/QtAutogen/LowMinimumVersion/view.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>View</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/MacOsFW/CMakeLists.txt b/Tests/QtAutogen/MacOsFW/CMakeLists.txt
new file mode 100644
index 0000000..c08efc4
--- /dev/null
+++ b/Tests/QtAutogen/MacOsFW/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.10)
+project(MacOsFW)
+include("../AutogenGuiTest.cmake")
+
+find_package(Qt5Test REQUIRED)
+
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/bin)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/lib)
+set(CMAKE_INSTALL_NAME_DIR ${CMAKE_BINARY_DIR}/output/lib)
+
+if(POLICY CMP0042) # in CMake 3.0.0+
+ set (CMAKE_MACOSX_RPATH OFF) # otherwise ON by default
+endif(POLICY CMP0042)
+
+if(POLICY CMP0068) # in CMake 3.9+
+ cmake_policy(SET CMP0068 NEW)
+endif(POLICY CMP0068)
+
+add_subdirectory(src)
+add_subdirectory(test)
diff --git a/Tests/QtAutogen/MacOsFW/src/CMakeLists.txt b/Tests/QtAutogen/MacOsFW/src/CMakeLists.txt
new file mode 100644
index 0000000..a02be00
--- /dev/null
+++ b/Tests/QtAutogen/MacOsFW/src/CMakeLists.txt
@@ -0,0 +1,33 @@
+set(MACOS_FW_LIB_VERSION "0.1")
+set(MACOS_FW_LIB_SRCS
+ macos_fw_lib.cpp
+)
+set(MACOS_FW_LIB_HDRS
+ macos_fw_lib.h
+)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${Qt5Core_INCLUDE_DIRS}
+)
+
+add_library(macos_fw_lib SHARED
+ ${MACOS_FW_LIB_SRCS}
+ ${MACOS_FW_LIB_HDRS}
+)
+set_target_properties(macos_fw_lib PROPERTIES AUTOMOC TRUE)
+set_target_properties(macos_fw_lib PROPERTIES
+ CLEAN_DIRECT_OUTPUT 1
+ FRAMEWORK 1
+ FRAMEWORK_VERSION ${MACOS_FW_LIB_VERSION}
+ VERSION ${MACOS_FW_LIB_VERSION}
+ SOVERSION ${MACOS_FW_LIB_VERSION}
+ MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${MACOS_FW_LIB_VERSION}
+ MACOSX_FRAMEWORK_IDENTIFIER org.macos.fw_lib
+ POSITION_INDEPENDENT_CODE ON
+ PUBLIC_HEADER "${MACOS_FW_LIB_HDRS}"
+)
+target_link_libraries(macos_fw_lib
+ Qt5::Core
+)
diff --git a/Tests/QtAutogen/MacOsFW/src/macos_fw_lib.cpp b/Tests/QtAutogen/MacOsFW/src/macos_fw_lib.cpp
new file mode 100644
index 0000000..881a8c9
--- /dev/null
+++ b/Tests/QtAutogen/MacOsFW/src/macos_fw_lib.cpp
@@ -0,0 +1,17 @@
+#include "macos_fw_lib.h"
+
+#include <QString>
+#include <QtGlobal>
+
+MacosFWLib::MacosFWLib()
+{
+}
+
+MacosFWLib::~MacosFWLib()
+{
+}
+
+QString MacosFWLib::qtVersionString() const
+{
+ return QString(qVersion());
+}
diff --git a/Tests/QtAutogen/MacOsFW/src/macos_fw_lib.h b/Tests/QtAutogen/MacOsFW/src/macos_fw_lib.h
new file mode 100644
index 0000000..e66e0ea
--- /dev/null
+++ b/Tests/QtAutogen/MacOsFW/src/macos_fw_lib.h
@@ -0,0 +1,18 @@
+#ifndef MACOSFWLIB_H
+#define MACOSFWLIB_H
+
+#include <QObject>
+#include <QString>
+
+class __attribute__((visibility("default"))) MacosFWLib : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit MacosFWLib();
+ ~MacosFWLib();
+
+ QString qtVersionString() const;
+};
+
+#endif // MACOSFWLIB_H
diff --git a/Tests/QtAutogen/MacOsFW/test/CMakeLists.txt b/Tests/QtAutogen/MacOsFW/test/CMakeLists.txt
new file mode 100644
index 0000000..521c184
--- /dev/null
+++ b/Tests/QtAutogen/MacOsFW/test/CMakeLists.txt
@@ -0,0 +1,19 @@
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../src
+)
+include_directories(SYSTEM
+ ${Qt5Core_INCLUDE_DIRS}
+ ${Qt5Widgets_INCLUDE_DIRS}
+)
+
+set(testname AutomocMacosFWLib)
+add_executable(${testname} testMacosFWLib.cpp)
+set_target_properties(${testname} PROPERTIES AUTOMOC TRUE)
+target_link_libraries(${testname}
+ Qt5::Core
+ Qt5::Widgets
+ Qt5::Test
+ macos_fw_lib
+)
diff --git a/Tests/QtAutogen/MacOsFW/test/testMacosFWLib.cpp b/Tests/QtAutogen/MacOsFW/test/testMacosFWLib.cpp
new file mode 100644
index 0000000..edc9376
--- /dev/null
+++ b/Tests/QtAutogen/MacOsFW/test/testMacosFWLib.cpp
@@ -0,0 +1,43 @@
+#include "testMacosFWLib.h"
+
+#include <QObject>
+#include <QString>
+
+#include "macos_fw_lib.h"
+
+class TestMacosFWLib : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init() {}
+ void cleanup() {}
+
+ void testQtVersion();
+};
+
+void TestMacosFWLib::initTestCase()
+{
+}
+
+void TestMacosFWLib::cleanupTestCase()
+{
+}
+
+void TestMacosFWLib::testQtVersion()
+{
+ MacosFWLib* testLib = new MacosFWLib();
+ QVERIFY(testLib->qtVersionString().contains("5."));
+ testLib->deleteLater();
+}
+
+int main(int argc, char* argv[])
+{
+ QApplication app(argc, argv, false);
+ MacosFWLib testObject;
+ return QTest::qExec(&testObject, argc, argv);
+}
+
+#include "testMacosFWLib.moc"
diff --git a/Tests/QtAutogen/MacOsFW/test/testMacosFWLib.h b/Tests/QtAutogen/MacOsFW/test/testMacosFWLib.h
new file mode 100644
index 0000000..1fe8dae
--- /dev/null
+++ b/Tests/QtAutogen/MacOsFW/test/testMacosFWLib.h
@@ -0,0 +1,7 @@
+#ifndef TESTMACOSFWLIB_H
+#define TESTMACOSFWLIB_H
+
+#include "qapplication.h"
+#include <QtTest/QtTest>
+
+#endif // TESTMACOSFWLIB_H
diff --git a/Tests/QtAutogen/ManySources/CMakeLists.txt b/Tests/QtAutogen/ManySources/CMakeLists.txt
new file mode 100644
index 0000000..df8a2a6
--- /dev/null
+++ b/Tests/QtAutogen/ManySources/CMakeLists.txt
@@ -0,0 +1,35 @@
+cmake_minimum_required(VERSION 3.10)
+project(ManySources)
+include("../AutogenGuiTest.cmake")
+
+# Test AUTOMOC and AUTOUIC on many source files to stress the concurrent
+# parsing and processing framework.
+
+set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
+set(CBD ${CMAKE_CURRENT_BINARY_DIR})
+
+set(SRCS main.cpp)
+set(MAIN_INCLUDES "\n// Item includes\n")
+set(MAIN_ITEMS "\n// Items\n")
+
+set(NUM 24)
+foreach(III RANGE 1 ${NUM})
+ configure_file(${CSD}/object.h.in ${CBD}/object_${III}.h)
+ configure_file(${CSD}/item.h.in ${CBD}/item_${III}.h)
+ configure_file(${CSD}/item.cpp.in ${CBD}/item_${III}.cpp)
+ configure_file(${CSD}/view.ui.in ${CBD}/view_${III}.ui)
+ configure_file(${CSD}/data.qrc.in ${CBD}/data_${III}.qrc)
+
+ list(APPEND SRCS ${CBD}/item_${III}.cpp)
+ list(APPEND SRCS ${CBD}/data_${III}.qrc)
+
+ string(APPEND MAIN_INCLUDES "#include \"item_${III}.h\"\n")
+ string(APPEND MAIN_ITEMS "Item_${III} item_${III};\n")
+ string(APPEND MAIN_ITEMS "item_${III}.TheSlot();\n")
+endforeach()
+
+configure_file(${CSD}/main.cpp.in ${CBD}/main.cpp)
+
+add_executable(manySources ${SRCS} ${CBD}/main.cpp)
+target_link_libraries(manySources ${QT_LIBRARIES})
+set_target_properties(manySources PROPERTIES AUTOMOC 1 AUTOUIC 1 AUTORCC 1)
diff --git a/Tests/QtAutogen/ManySources/data.qrc.in b/Tests/QtAutogen/ManySources/data.qrc.in
new file mode 100644
index 0000000..870d486
--- /dev/null
+++ b/Tests/QtAutogen/ManySources/data.qrc.in
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>object_@III@.h</file>
+ <file>item_@III@.h</file>
+ <file>item_@III@.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/ManySources/item.cpp.in b/Tests/QtAutogen/ManySources/item.cpp.in
new file mode 100644
index 0000000..c34ad16
--- /dev/null
+++ b/Tests/QtAutogen/ManySources/item.cpp.in
@@ -0,0 +1,27 @@
+#include "item_@III@.h"
+#include "object_@III@.h"
+// AUTOUIC include
+#include <ui_view_@III@.h>
+
+class LocalObject_@III@ : public QObject
+{
+ Q_OBJECT;
+
+public:
+ LocalObject_@III@() = default;
+ ~LocalObject_@III@() = default;
+};
+
+void Item_@III@ ::TheSlot()
+{
+ LocalObject_@III@ localObject;
+ Object_@III@ obj;
+ obj.ObjectSlot();
+
+ Ui_View_@III@ ui_view;
+}
+
+// AUTOMOC includes
+#include "item_@III@.moc"
+#include "moc_item_@III@.cpp"
+#include "moc_object_@III@.cpp"
diff --git a/Tests/QtAutogen/ManySources/item.h.in b/Tests/QtAutogen/ManySources/item.h.in
new file mode 100644
index 0000000..67ad794
--- /dev/null
+++ b/Tests/QtAutogen/ManySources/item.h.in
@@ -0,0 +1,15 @@
+#ifndef ITEM_@III@HPP
+#define ITEM_@III@HPP
+
+#include <QObject>
+
+class Item_@III@ : public QObject
+{
+ Q_OBJECT
+
+public:
+ Q_SLOT
+ void TheSlot();
+};
+
+#endif
diff --git a/Tests/QtAutogen/ManySources/main.cpp.in b/Tests/QtAutogen/ManySources/main.cpp.in
new file mode 100644
index 0000000..e1dda40
--- /dev/null
+++ b/Tests/QtAutogen/ManySources/main.cpp.in
@@ -0,0 +1,7 @@
+@MAIN_INCLUDES@
+
+int main(int argv, char** args)
+{
+ @MAIN_ITEMS@
+ return 0;
+}
diff --git a/Tests/QtAutogen/ManySources/object.h.in b/Tests/QtAutogen/ManySources/object.h.in
new file mode 100644
index 0000000..a747cbc
--- /dev/null
+++ b/Tests/QtAutogen/ManySources/object.h.in
@@ -0,0 +1,15 @@
+#ifndef OBJECT_@III@H
+#define OBJECT_@III@H
+
+#include <QObject>
+
+class Object_@III@ : public QObject
+{
+ Q_OBJECT
+
+public:
+ Q_SLOT
+ void ObjectSlot(){};
+};
+
+#endif
diff --git a/Tests/QtAutogen/ManySources/view.ui.in b/Tests/QtAutogen/ManySources/view.ui.in
new file mode 100644
index 0000000..6901fe3
--- /dev/null
+++ b/Tests/QtAutogen/ManySources/view.ui.in
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>View_@III@</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/MocCMP0071/CMakeLists.txt b/Tests/QtAutogen/MocCMP0071/CMakeLists.txt
new file mode 100644
index 0000000..5c58a82
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0071/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.10)
+project(MocCMP0071)
+include("../AutogenCoreTest.cmake")
+
+add_subdirectory(OLD)
+add_subdirectory(NEW)
diff --git a/Tests/QtAutogen/MocCMP0071/NEW/CMakeLists.txt b/Tests/QtAutogen/MocCMP0071/NEW/CMakeLists.txt
new file mode 100644
index 0000000..954fe3d
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0071/NEW/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.10)
+cmake_policy(SET CMP0071 NEW)
+
+# *Generate* files
+set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
+set(CBD ${CMAKE_CURRENT_BINARY_DIR})
+add_custom_command(
+ OUTPUT ${CBD}/Obj_p.h ${CBD}/Obj.hpp ${CBD}/Obj.cpp ${CBD}/main.cpp
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/../Obj_p.h ${CBD}/Obj_p.h
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/../Obj.hpp ${CBD}/Obj.hpp
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/../Obj.cpp ${CBD}/Obj.cpp
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/../main.cpp ${CBD}/main.cpp)
+
+add_executable(mocCMP0071New ${CBD}/Obj.cpp ${CBD}/main.cpp)
+target_link_libraries(mocCMP0071New ${QT_LIBRARIES})
+set_target_properties(mocCMP0071New PROPERTIES AUTOMOC ON)
diff --git a/Tests/QtAutogen/MocCMP0071/OLD/CMakeLists.txt b/Tests/QtAutogen/MocCMP0071/OLD/CMakeLists.txt
new file mode 100644
index 0000000..68fa067
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0071/OLD/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.10)
+cmake_policy(SET CMP0071 OLD)
+
+# *Generate* files
+set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
+set(CBD ${CMAKE_CURRENT_BINARY_DIR})
+add_custom_command(
+ OUTPUT ${CBD}/Obj_p.h ${CBD}/Obj.hpp ${CBD}/Obj.cpp ${CBD}/main.cpp
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/../Obj_p.h ${CBD}/Obj_p.h
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/../Obj.hpp ${CBD}/Obj.hpp
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/../Obj.cpp ${CBD}/Obj.cpp
+ COMMAND ${CMAKE_COMMAND} -E copy ${CSD}/../main.cpp ${CBD}/main.cpp)
+
+# Generate moc files externally
+qtx_wrap_cpp(mocCMP0071OldMoc ${CBD}/Obj.hpp ${CBD}/Obj_p.h)
+add_executable(mocCMP0071Old ${CBD}/Obj.cpp ${CBD}/main.cpp ${mocCMP0071OldMoc})
+target_link_libraries(mocCMP0071Old ${QT_LIBRARIES})
+set_target_properties(mocCMP0071Old PROPERTIES AUTOMOC ON)
diff --git a/Tests/QtAutogen/MocCMP0071/Obj.cpp b/Tests/QtAutogen/MocCMP0071/Obj.cpp
new file mode 100644
index 0000000..25a291d
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0071/Obj.cpp
@@ -0,0 +1,21 @@
+#include "Obj.hpp"
+
+#include "Obj_p.h"
+
+ObjPrivate::ObjPrivate()
+{
+}
+
+ObjPrivate::~ObjPrivate()
+{
+}
+
+Obj::Obj()
+ : d(new ObjPrivate)
+{
+}
+
+Obj::~Obj()
+{
+ delete d;
+}
diff --git a/Tests/QtAutogen/MocCMP0071/Obj.hpp b/Tests/QtAutogen/MocCMP0071/Obj.hpp
new file mode 100644
index 0000000..f064e47
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0071/Obj.hpp
@@ -0,0 +1,19 @@
+#ifndef OBJ_HPP
+#define OBJ_HPP
+
+#include <QObject>
+
+// Object source comes without any _moc/.moc includes
+class ObjPrivate;
+class Obj : public QObject
+{
+ Q_OBJECT
+public:
+ Obj();
+ ~Obj();
+
+private:
+ ObjPrivate* const d;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocCMP0071/Obj_p.h b/Tests/QtAutogen/MocCMP0071/Obj_p.h
new file mode 100644
index 0000000..cb1e5df
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0071/Obj_p.h
@@ -0,0 +1,14 @@
+#ifndef OBJ_P_HPP
+#define OBJ_P_HPP
+
+#include <QObject>
+
+class ObjPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ ObjPrivate();
+ ~ObjPrivate();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocCMP0071/main.cpp b/Tests/QtAutogen/MocCMP0071/main.cpp
new file mode 100644
index 0000000..3887840
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0071/main.cpp
@@ -0,0 +1,7 @@
+#include "Obj.hpp"
+
+int main(int argv, char** args)
+{
+ Obj obj;
+ return 0;
+}
diff --git a/Tests/QtAutogen/MocCMP0100/CMakeLists.txt b/Tests/QtAutogen/MocCMP0100/CMakeLists.txt
new file mode 100644
index 0000000..559cffe
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.10)
+project(MocCMP0100)
+include("../AutogenCoreTest.cmake")
+
+set(CMAKE_AUTOMOC ON)
+set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
+
+add_subdirectory(OLD)
+add_subdirectory(NEW)
diff --git a/Tests/QtAutogen/MocCMP0100/NEW/CMakeLists.txt b/Tests/QtAutogen/MocCMP0100/NEW/CMakeLists.txt
new file mode 100644
index 0000000..654b31e
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/NEW/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.16)
+cmake_policy(SET CMP0100 NEW)
+
+add_executable(mocCMP0100New
+ ${CSD}/main.cpp
+ ${CSD}/Obj.hh # Manually include Obj.hh
+ ${CSD}/Obj.cpp
+ ${CSD}/Obj2.cpp # Let AUTOMOC detect Obj2.hh
+)
+target_link_libraries(mocCMP0100New ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/MocCMP0100/OLD/CMakeLists.txt b/Tests/QtAutogen/MocCMP0100/OLD/CMakeLists.txt
new file mode 100644
index 0000000..2be0535
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/OLD/CMakeLists.txt
@@ -0,0 +1,31 @@
+cmake_minimum_required(VERSION 3.16)
+cmake_policy(SET CMP0100 OLD)
+
+# Generate moc files externally.
+# If AUTOMOC generates the header moc files as well
+# (it should not in OLD behavior), the test will fail with a
+# multiple definition error when linking the executable.
+qtx_wrap_cpp(mocCMP0100OldMoc ${CSD}/Obj.hh ${CSD}/Obj2.hh)
+qtx_generate_moc(${CBD}/Obj.cpp ${CMAKE_CURRENT_BINARY_DIR}/Obj.moc)
+qtx_generate_moc(${CBD}/Obj2.cpp ${CMAKE_CURRENT_BINARY_DIR}/Obj2.moc)
+
+# Make sure AUTOGEN file skipping is disabled
+set_source_files_properties(
+ ${CSD}/Obj.hh
+ ${CBD}/Obj.cpp
+ ${CSD}/Obj2.hh
+ ${CBD}/Obj2.cpp
+ PROPERTIES
+ SKIP_AUTOGEN OFF
+ SKIP_AUTOMOC OFF
+)
+
+add_executable(mocCMP0100Old
+ ${CSD}/main.cpp
+ ${CSD}/Obj.hh # Manually include Obj.hh
+ ${CSD}/Obj.cpp
+ ${CSD}/Obj2.cpp # Let AUTOMOC detect Obj2.hh
+ ${mocCMP0100OldMoc}
+)
+target_link_libraries(mocCMP0100Old ${QT_LIBRARIES})
+target_include_directories(mocCMP0100Old PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/Tests/QtAutogen/MocCMP0100/Obj.cpp b/Tests/QtAutogen/MocCMP0100/Obj.cpp
new file mode 100644
index 0000000..bb6d0a0
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/Obj.cpp
@@ -0,0 +1,31 @@
+#include "Obj.hh"
+
+#include <QObject>
+
+class ObjPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ ObjPrivate();
+ ~ObjPrivate();
+};
+
+ObjPrivate::ObjPrivate()
+{
+}
+
+ObjPrivate::~ObjPrivate()
+{
+}
+
+Obj::Obj()
+ : d(new ObjPrivate)
+{
+}
+
+Obj::~Obj()
+{
+ delete d;
+}
+
+#include "Obj.moc"
diff --git a/Tests/QtAutogen/MocCMP0100/Obj.hh b/Tests/QtAutogen/MocCMP0100/Obj.hh
new file mode 100644
index 0000000..940bfc2
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/Obj.hh
@@ -0,0 +1,20 @@
+#ifndef OBJ_HH
+#define OBJ_HH
+
+#include <QObject>
+
+// Qt enabled private class
+class ObjPrivate;
+// Qt enabled class
+class Obj : public QObject
+{
+ Q_OBJECT
+public:
+ Obj();
+ ~Obj();
+
+private:
+ ObjPrivate* const d;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocCMP0100/Obj2.cpp b/Tests/QtAutogen/MocCMP0100/Obj2.cpp
new file mode 100644
index 0000000..8a359ad
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/Obj2.cpp
@@ -0,0 +1,31 @@
+#include "Obj2.hh"
+
+#include <QObject>
+
+class Obj2Private : public QObject
+{
+ Q_OBJECT
+public:
+ Obj2Private();
+ ~Obj2Private();
+};
+
+Obj2Private::Obj2Private()
+{
+}
+
+Obj2Private::~Obj2Private()
+{
+}
+
+Obj2::Obj2()
+ : d(new Obj2Private)
+{
+}
+
+Obj2::~Obj2()
+{
+ delete d;
+}
+
+#include "Obj2.moc"
diff --git a/Tests/QtAutogen/MocCMP0100/Obj2.hh b/Tests/QtAutogen/MocCMP0100/Obj2.hh
new file mode 100644
index 0000000..1c74cdd
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/Obj2.hh
@@ -0,0 +1,20 @@
+#ifndef OBJ2_HH
+#define OBJ2_HH
+
+#include <QObject>
+
+// Qt enabled private class
+class Obj2Private;
+// Qt enabled class
+class Obj2 : public QObject
+{
+ Q_OBJECT
+public:
+ Obj2();
+ ~Obj2();
+
+private:
+ Obj2Private* const d;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocCMP0100/main.cpp b/Tests/QtAutogen/MocCMP0100/main.cpp
new file mode 100644
index 0000000..17061da
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/main.cpp
@@ -0,0 +1,9 @@
+#include "Obj.hh"
+#include "Obj2.hh"
+
+int main(int argv, char** args)
+{
+ Obj obj;
+ Obj2 obj2;
+ return 0;
+}
diff --git a/Tests/QtAutogen/MocInclude/CMakeLists.txt b/Tests/QtAutogen/MocInclude/CMakeLists.txt
new file mode 100644
index 0000000..04c8baf
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/CMakeLists.txt
@@ -0,0 +1,112 @@
+cmake_minimum_required(VERSION 3.15)
+project(MocInclude)
+get_filename_component(CS_REAL ${CMAKE_CURRENT_SOURCE_DIR} REALPATH)
+include("${CS_REAL}/../AutogenCoreTest.cmake")
+
+# Test moc include patterns
+
+set(COM_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Common")
+
+macro(addCopyCommand from to)
+ add_custom_command(
+ OUTPUT ${to}
+ COMMAND ${CMAKE_COMMAND} -E copy ${from} ${to}
+ DEPENDS ${from})
+endmacro()
+
+# Create an executable
+function(makeExecutable TARGET_NAME)
+ # Utility variables
+ set(CB_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+
+ # Copy directory
+ file(REMOVE_RECURSE "${CB_DIR}/InIncludes")
+ file(COPY "${COM_DIR}/InIncludes.in" DESTINATION "${CB_DIR}")
+ file(RENAME "${CB_DIR}/InIncludes.in" "${CB_DIR}/InIncludes")
+
+ # Generate .moc file from the header externally and
+ # enabled SKIP_AUTOMOC on the source file
+ qtx_wrap_cpp(ExternDotMOC ${COM_DIR}/ExternDot.hpp OPTIONS "-p" "./")
+ addCopyCommand(${ExternDotMOC}
+ ${CB_DIR}/ExternDot.moc)
+ set_property(
+ SOURCE ${COM_DIR}/ExternDot.cpp
+ PROPERTY SKIP_AUTOMOC ON)
+
+ # Generate .moc file from the GENERATED header externally
+ # and enabled SKIP_AUTOMOC on the source file
+ addCopyCommand(${COM_DIR}/ExternDotGenerated.hpp.in
+ ${CB_DIR}/ExternDotGenerated.hpp)
+ addCopyCommand(${COM_DIR}/ExternDotGenerated.cpp.in
+ ${CB_DIR}/ExternDotGenerated.cpp)
+ qtx_wrap_cpp(ExternDotGeneratedMOC
+ ${CB_DIR}/ExternDotGenerated.hpp
+ OPTIONS "-p" "./")
+ addCopyCommand(${ExternDotGeneratedMOC}
+ ${CB_DIR}/ExternDotGenerated.moc)
+ set_property(
+ SOURCE ${CB_DIR}/ExternDotGenerated.cpp
+ PROPERTY SKIP_AUTOMOC ON)
+
+ # Generate header moc file externally with a custom name
+ # and enabled SKIP_AUTOMOC on the header
+ qtx_wrap_cpp(MixedCustomMOC
+ ${COM_DIR}/MixedCustom.hpp
+ OPTIONS "-p" "./")
+ addCopyCommand(${MixedCustomMOC}
+ ${CB_DIR}/MixedCustom_extMoc.cpp)
+ set_property(
+ SOURCE ${COM_DIR}/MixedCustom.hpp
+ PROPERTY SKIP_AUTOMOC ON)
+ # Custom target to depend on
+ add_custom_target("${TARGET_NAME}_MixedCustom"
+ DEPENDS ${CB_DIR}/MixedCustom_extMoc.cpp
+ BYPRODUCTS ${CB_DIR}/moc_MixedCustom.cpp
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${COM_DIR}/moc_MixedCustom.cpp.in
+ ${CB_DIR}/moc_MixedCustom.cpp)
+
+ add_executable(${TARGET_NAME}
+ # Test own "*.moc" and "moc_*.cpp" includes
+ ${COM_DIR}/None.cpp
+ ${COM_DIR}/OwnDot.cpp
+ ${COM_DIR}/OwnUnderscore.cpp
+ ${COM_DIR}/OwnDotUnderscore.cpp
+
+ # Test "moc_*.cpp" includes of other files
+ ${COM_DIR}/OtherUnderscore.cpp
+ ${COM_DIR}/OtherUnderscoreExtra.cpp
+ ${COM_DIR}/OtherUnderscoreSub.cpp
+ ${COM_DIR}/OtherUnderscoreSubDir/SubExtra.cpp
+
+ # Test relative ../../ path for moc includes
+ ${COM_DIR}/DualSub/Second/Second.cpp
+ ${COM_DIR}/DualSubMocked.cpp
+
+ # Test externally generated moc files
+ ${COM_DIR}/ExternDot.cpp
+ ${CB_DIR}/ExternDot.moc
+
+ # Test externally generated moc files for GENERATED source
+ ${CB_DIR}/ExternDotGenerated.cpp
+ ${CB_DIR}/ExternDotGenerated.moc
+
+ # Test externally generated moc files and SKIP_AUTOMOC enabled header
+ ${COM_DIR}/MixedSkipped.cpp
+ ${COM_DIR}/MixedCustom.hpp
+ ${COM_DIR}/MixedCustom.cpp
+
+ # Test sources in a subdirectory
+ ${CB_DIR}/InIncludes/SubOwnDot.cpp
+ ${COM_DIR}/InIncludesMoc.cpp
+ )
+ add_dependencies(${TARGET_NAME} "${TARGET_NAME}_MixedCustom")
+ target_include_directories(${TARGET_NAME} PRIVATE "${COM_DIR}")
+ target_include_directories(${TARGET_NAME} PRIVATE "${CB_DIR}")
+ target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
+ target_link_libraries(${TARGET_NAME} ${QT_LIBRARIES})
+ set_target_properties(${TARGET_NAME} PROPERTIES AUTOMOC ON)
+endfunction()
+
+add_subdirectory(Strict)
+add_subdirectory(Relaxed)
diff --git a/Tests/QtAutogen/MocInclude/Common/DualSub/Second/Second.cpp b/Tests/QtAutogen/MocInclude/Common/DualSub/Second/Second.cpp
new file mode 100644
index 0000000..453add1
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/DualSub/Second/Second.cpp
@@ -0,0 +1,11 @@
+#include "Second.hpp"
+
+Second::Second()
+{
+}
+
+Second::~Second()
+{
+}
+
+#include "../../moc_DualSubMocked.cpp"
diff --git a/Tests/QtAutogen/MocInclude/Common/DualSub/Second/Second.hpp b/Tests/QtAutogen/MocInclude/Common/DualSub/Second/Second.hpp
new file mode 100644
index 0000000..e1f3eac
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/DualSub/Second/Second.hpp
@@ -0,0 +1,14 @@
+#ifndef Second_HPP
+#define Second_HPP
+
+#include <QObject>
+
+class Second : public QObject
+{
+ Q_OBJECT
+public:
+ Second();
+ ~Second();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/DualSubMocked.cpp b/Tests/QtAutogen/MocInclude/Common/DualSubMocked.cpp
new file mode 100644
index 0000000..1d4658d
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/DualSubMocked.cpp
@@ -0,0 +1,9 @@
+#include "DualSubMocked.hpp"
+
+DualSubMocked::DualSubMocked()
+{
+}
+
+DualSubMocked::~DualSubMocked()
+{
+}
diff --git a/Tests/QtAutogen/MocInclude/Common/DualSubMocked.hpp b/Tests/QtAutogen/MocInclude/Common/DualSubMocked.hpp
new file mode 100644
index 0000000..58cb571
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/DualSubMocked.hpp
@@ -0,0 +1,15 @@
+#ifndef DualSubMocked_HPP
+#define DualSubMocked_HPP
+
+#include <QObject>
+
+// Header moc file is included by DualSub/Second/Second.cpp
+class DualSubMocked : public QObject
+{
+ Q_OBJECT
+public:
+ DualSubMocked();
+ ~DualSubMocked();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/ExternDot.cpp b/Tests/QtAutogen/MocInclude/Common/ExternDot.cpp
new file mode 100644
index 0000000..2495aa7
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/ExternDot.cpp
@@ -0,0 +1,11 @@
+#include "ExternDot.hpp"
+
+ExternDot::ExternDot()
+{
+}
+
+ExternDot::~ExternDot()
+{
+}
+
+#include "ExternDot.moc"
diff --git a/Tests/QtAutogen/MocInclude/Common/ExternDot.hpp b/Tests/QtAutogen/MocInclude/Common/ExternDot.hpp
new file mode 100644
index 0000000..7eaab2a
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/ExternDot.hpp
@@ -0,0 +1,15 @@
+#ifndef ExternDot_HPP
+#define ExternDot_HPP
+
+#include <QObject>
+
+// Object source includes externally generated .moc file
+class ExternDot : public QObject
+{
+ Q_OBJECT
+public:
+ ExternDot();
+ ~ExternDot();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/ExternDotGenerated.cpp.in b/Tests/QtAutogen/MocInclude/Common/ExternDotGenerated.cpp.in
new file mode 100644
index 0000000..09ce5cd
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/ExternDotGenerated.cpp.in
@@ -0,0 +1,11 @@
+#include "ExternDotGenerated.hpp"
+
+ExternDotGenerated::ExternDotGenerated()
+{
+}
+
+ExternDotGenerated::~ExternDotGenerated()
+{
+}
+
+#include "ExternDotGenerated.moc"
diff --git a/Tests/QtAutogen/MocInclude/Common/ExternDotGenerated.hpp.in b/Tests/QtAutogen/MocInclude/Common/ExternDotGenerated.hpp.in
new file mode 100644
index 0000000..21c69be
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/ExternDotGenerated.hpp.in
@@ -0,0 +1,15 @@
+#ifndef ExternDotGenerated_HPP
+#define ExternDotGenerated_HPP
+
+#include <QObject>
+
+// GENERATED Object source includes externally generated .moc file
+class ExternDotGenerated : public QObject
+{
+ Q_OBJECT
+public:
+ ExternDotGenerated();
+ ~ExternDotGenerated();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/InIncludes.in/SubOwnDot.cpp b/Tests/QtAutogen/MocInclude/Common/InIncludes.in/SubOwnDot.cpp
new file mode 100644
index 0000000..275754d
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/InIncludes.in/SubOwnDot.cpp
@@ -0,0 +1,44 @@
+#include "SubOwnDot.hpp"
+
+#include "SubOwnDot_p.hpp"
+
+namespace InIncludes {
+
+class SubOwnDotLocal : public QObject
+{
+ Q_OBJECT
+public:
+ SubOwnDotLocal();
+ ~SubOwnDotLocal();
+};
+
+SubOwnDotLocal::SubOwnDotLocal()
+{
+}
+
+SubOwnDotLocal::~SubOwnDotLocal()
+{
+}
+
+SubOwnDotPrivate::SubOwnDotPrivate()
+{
+}
+
+SubOwnDotPrivate::~SubOwnDotPrivate()
+{
+}
+
+SubOwnDot::SubOwnDot()
+{
+ SubOwnDotPrivate privateObj;
+ SubOwnDotLocal localObj;
+}
+
+SubOwnDot::~SubOwnDot()
+{
+}
+
+} // End of namespace
+
+// For the local QObject
+#include "SubOwnDot.moc"
diff --git a/Tests/QtAutogen/MocInclude/Common/InIncludes.in/SubOwnDot.hpp b/Tests/QtAutogen/MocInclude/Common/InIncludes.in/SubOwnDot.hpp
new file mode 100644
index 0000000..038ddfa
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/InIncludes.in/SubOwnDot.hpp
@@ -0,0 +1,17 @@
+#ifndef InIncludes_SubOwnDot_HPP
+#define InIncludes_SubOwnDot_HPP
+
+#include <QObject>
+
+namespace InIncludes {
+
+class SubOwnDot : public QObject
+{
+ Q_OBJECT
+public:
+ SubOwnDot();
+ ~SubOwnDot();
+};
+}
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/InIncludes.in/SubOwnDot_p.hpp b/Tests/QtAutogen/MocInclude/Common/InIncludes.in/SubOwnDot_p.hpp
new file mode 100644
index 0000000..626a9a8
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/InIncludes.in/SubOwnDot_p.hpp
@@ -0,0 +1,18 @@
+#ifndef InIncludes_SubOwnDot_P_HPP
+#define InIncludes_SubOwnDot_P_HPP
+
+#include <QObject>
+
+namespace InIncludes {
+
+class SubOwnDotPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ SubOwnDotPrivate();
+ ~SubOwnDotPrivate();
+};
+
+} // End of namespace
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/InIncludesMoc.cpp b/Tests/QtAutogen/MocInclude/Common/InIncludesMoc.cpp
new file mode 100644
index 0000000..88f53a4
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/InIncludesMoc.cpp
@@ -0,0 +1,4 @@
+
+// Moc a header that is not in the sources but in a directory that
+// is in the list of include directories.
+#include "InIncludes/moc_SubOwnDot.cpp"
diff --git a/Tests/QtAutogen/MocInclude/Common/MixedCustom.cpp b/Tests/QtAutogen/MocInclude/Common/MixedCustom.cpp
new file mode 100644
index 0000000..557cc62
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/MixedCustom.cpp
@@ -0,0 +1,32 @@
+#include "MixedCustom.hpp"
+
+class MixedCustomLocal : public QObject
+{
+ Q_OBJECT
+
+public:
+ MixedCustomLocal();
+ ~MixedCustomLocal();
+};
+
+MixedCustomLocal::MixedCustomLocal()
+{
+}
+
+MixedCustomLocal::~MixedCustomLocal()
+{
+}
+
+MixedCustom::MixedCustom()
+{
+ MixedCustomLocal local;
+}
+
+MixedCustom::~MixedCustom()
+{
+}
+
+// AUTOMOC generated source moc
+#include "MixedCustom.moc"
+// Externally generated header moc
+#include "MixedCustom_extMoc.cpp"
diff --git a/Tests/QtAutogen/MocInclude/Common/MixedCustom.hpp b/Tests/QtAutogen/MocInclude/Common/MixedCustom.hpp
new file mode 100644
index 0000000..6e8ff88
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/MixedCustom.hpp
@@ -0,0 +1,20 @@
+#ifndef MixedCustom_HPP
+#define MixedCustom_HPP
+
+#include <QObject>
+
+// Object source includes
+// - externally generated header moc file
+// - AUTOMOC generated source .moc file
+class MixedCustom : public QObject
+{
+ Q_OBJECT
+public:
+ MixedCustom();
+ ~MixedCustom();
+};
+
+// Function forward declaration
+void moc_MixedCustom(MixedCustom const& arg);
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/MixedSkipped.cpp b/Tests/QtAutogen/MocInclude/Common/MixedSkipped.cpp
new file mode 100644
index 0000000..6919ebc
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/MixedSkipped.cpp
@@ -0,0 +1,40 @@
+#include "MixedSkipped.hpp"
+
+#include "MixedCustom.hpp"
+
+class MixedSkippedLocal : public QObject
+{
+ Q_OBJECT
+
+public:
+ MixedSkippedLocal();
+ ~MixedSkippedLocal();
+};
+
+MixedSkippedLocal::MixedSkippedLocal()
+{
+}
+
+MixedSkippedLocal::~MixedSkippedLocal()
+{
+}
+
+MixedSkipped::MixedSkipped()
+{
+ MixedSkippedLocal local;
+ MixedCustom externCutom;
+ // Call moc named function
+ moc_MixedCustom(externCutom);
+}
+
+MixedSkipped::~MixedSkipped()
+{
+}
+
+// Include AUTOMOC generated moc files
+#include "MixedSkipped.moc"
+#include "moc_MixedSkipped.cpp"
+
+// Include externally generated moc_ named file that is not a moc file
+// and for which the relevant header is SKIP_AUTOMOC enabled
+#include "moc_MixedCustom.cpp"
diff --git a/Tests/QtAutogen/MocInclude/Common/MixedSkipped.hpp b/Tests/QtAutogen/MocInclude/Common/MixedSkipped.hpp
new file mode 100644
index 0000000..5f6c664
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/MixedSkipped.hpp
@@ -0,0 +1,17 @@
+#ifndef MixedSkipped_HPP
+#define MixedSkipped_HPP
+
+#include <QObject>
+
+// Object source includes
+// - Own moc_ and .moc files.
+// - externally generated moc_ file from a SKIP_AUTOMOC enabled header
+class MixedSkipped : public QObject
+{
+ Q_OBJECT
+public:
+ MixedSkipped();
+ ~MixedSkipped();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/None.cpp b/Tests/QtAutogen/MocInclude/Common/None.cpp
new file mode 100644
index 0000000..286ddb6
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/None.cpp
@@ -0,0 +1,21 @@
+#include "None.hpp"
+
+#include "None_p.h"
+
+NonePrivate::NonePrivate()
+{
+}
+
+NonePrivate::~NonePrivate()
+{
+}
+
+None::None()
+ : d(new NonePrivate)
+{
+}
+
+None::~None()
+{
+ delete d;
+}
diff --git a/Tests/QtAutogen/MocInclude/Common/None.hpp b/Tests/QtAutogen/MocInclude/Common/None.hpp
new file mode 100644
index 0000000..ca0713e
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/None.hpp
@@ -0,0 +1,19 @@
+#ifndef None_HPP
+#define None_HPP
+
+#include <QObject>
+
+// Object source comes without any _moc/.moc includes
+class NonePrivate;
+class None : public QObject
+{
+ Q_OBJECT
+public:
+ None();
+ ~None();
+
+private:
+ NonePrivate* const d;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/None_p.h b/Tests/QtAutogen/MocInclude/Common/None_p.h
new file mode 100644
index 0000000..e209aeb
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/None_p.h
@@ -0,0 +1,14 @@
+#ifndef None_P_HPP
+#define None_P_HPP
+
+#include <QObject>
+
+class NonePrivate : public QObject
+{
+ Q_OBJECT
+public:
+ NonePrivate();
+ ~NonePrivate();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/OtherUnderscore.cpp b/Tests/QtAutogen/MocInclude/Common/OtherUnderscore.cpp
new file mode 100644
index 0000000..df1c428
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OtherUnderscore.cpp
@@ -0,0 +1,45 @@
+#include "OtherUnderscore.hpp"
+
+#include "OtherUnderscoreExtra.hpp"
+#include "OtherUnderscore_p.hpp"
+
+class OtherUnderscoreLocal : public QObject
+{
+ Q_OBJECT
+public:
+ OtherUnderscoreLocal();
+ ~OtherUnderscoreLocal();
+};
+
+OtherUnderscoreLocal::OtherUnderscoreLocal()
+{
+}
+
+OtherUnderscoreLocal::~OtherUnderscoreLocal()
+{
+}
+
+OtherUnderscorePrivate::OtherUnderscorePrivate()
+{
+ OtherUnderscoreLocal localObj;
+ OtherUnderscoreExtra extraObj;
+}
+
+OtherUnderscorePrivate::~OtherUnderscorePrivate()
+{
+}
+
+OtherUnderscore::OtherUnderscore()
+ : d(new OtherUnderscorePrivate)
+{
+}
+
+OtherUnderscore::~OtherUnderscore()
+{
+ delete d;
+}
+
+// For OtherUnderscoreLocal
+#include "OtherUnderscore.moc"
+// - Not the own header
+#include "moc_OtherUnderscoreExtra.cpp"
diff --git a/Tests/QtAutogen/MocInclude/Common/OtherUnderscore.hpp b/Tests/QtAutogen/MocInclude/Common/OtherUnderscore.hpp
new file mode 100644
index 0000000..a4ff603
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OtherUnderscore.hpp
@@ -0,0 +1,19 @@
+#ifndef OtherUnderscore_HPP
+#define OtherUnderscore_HPP
+
+#include <QObject>
+
+// Sources includes a moc_ includes of an extra object
+class OtherUnderscorePrivate;
+class OtherUnderscore : public QObject
+{
+ Q_OBJECT
+public:
+ OtherUnderscore();
+ ~OtherUnderscore();
+
+private:
+ OtherUnderscorePrivate* const d;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreExtra.cpp b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreExtra.cpp
new file mode 100644
index 0000000..11ebd81
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreExtra.cpp
@@ -0,0 +1,21 @@
+#include "OtherUnderscoreExtra.hpp"
+
+#include "OtherUnderscoreExtra_p.hpp"
+
+OtherUnderscoreExtraPrivate::OtherUnderscoreExtraPrivate()
+{
+}
+
+OtherUnderscoreExtraPrivate::~OtherUnderscoreExtraPrivate()
+{
+}
+
+OtherUnderscoreExtra::OtherUnderscoreExtra()
+ : d(new OtherUnderscoreExtraPrivate)
+{
+}
+
+OtherUnderscoreExtra::~OtherUnderscoreExtra()
+{
+ delete d;
+}
diff --git a/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreExtra.hpp b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreExtra.hpp
new file mode 100644
index 0000000..5afe48c
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreExtra.hpp
@@ -0,0 +1,18 @@
+#ifndef OtherUnderscoreEXTRA_HPP
+#define OtherUnderscoreEXTRA_HPP
+
+#include <QObject>
+
+class OtherUnderscoreExtraPrivate;
+class OtherUnderscoreExtra : public QObject
+{
+ Q_OBJECT
+public:
+ OtherUnderscoreExtra();
+ ~OtherUnderscoreExtra();
+
+private:
+ OtherUnderscoreExtraPrivate* const d;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreExtra_p.hpp b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreExtra_p.hpp
new file mode 100644
index 0000000..2066ac3
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreExtra_p.hpp
@@ -0,0 +1,14 @@
+#ifndef OtherUnderscoreEXTRA_P_HPP
+#define OtherUnderscoreEXTRA_P_HPP
+
+#include <QObject>
+
+class OtherUnderscoreExtraPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ OtherUnderscoreExtraPrivate();
+ ~OtherUnderscoreExtraPrivate();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSub.cpp b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSub.cpp
new file mode 100644
index 0000000..712c540
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSub.cpp
@@ -0,0 +1,46 @@
+#include "OtherUnderscoreSub.hpp"
+
+#include "OtherUnderscoreSubDir/SubExtra.hpp"
+#include "OtherUnderscoreSub_p.hpp"
+
+class OtherUnderscoreSubLocal : public QObject
+{
+ Q_OBJECT
+public:
+ OtherUnderscoreSubLocal();
+ ~OtherUnderscoreSubLocal();
+};
+
+OtherUnderscoreSubLocal::OtherUnderscoreSubLocal()
+{
+}
+
+OtherUnderscoreSubLocal::~OtherUnderscoreSubLocal()
+{
+}
+
+OtherUnderscoreSubPrivate::OtherUnderscoreSubPrivate()
+{
+ OtherUnderscoreSubLocal localObj;
+ SubExtra extraObj;
+}
+
+OtherUnderscoreSubPrivate::~OtherUnderscoreSubPrivate()
+{
+}
+
+OtherUnderscoreSub::OtherUnderscoreSub()
+ : d(new OtherUnderscoreSubPrivate)
+{
+}
+
+OtherUnderscoreSub::~OtherUnderscoreSub()
+{
+ delete d;
+}
+
+// For OtherUnderscoreSubLocal
+#include "OtherUnderscoreSub.moc"
+// - Not the own header
+// - in a subdirectory
+#include "OtherUnderscoreSubDir/moc_SubExtra.cpp"
diff --git a/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSub.hpp b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSub.hpp
new file mode 100644
index 0000000..7feaa46
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSub.hpp
@@ -0,0 +1,19 @@
+#ifndef OtherUnderscoreSub_HPP
+#define OtherUnderscoreSub_HPP
+
+#include <QObject>
+
+// Sources includes a moc_ includes of an extra object in a subdirectory
+class OtherUnderscoreSubPrivate;
+class OtherUnderscoreSub : public QObject
+{
+ Q_OBJECT
+public:
+ OtherUnderscoreSub();
+ ~OtherUnderscoreSub();
+
+private:
+ OtherUnderscoreSubPrivate* const d;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSubDir/SubExtra.cpp b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSubDir/SubExtra.cpp
new file mode 100644
index 0000000..22501e4
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSubDir/SubExtra.cpp
@@ -0,0 +1,21 @@
+#include "SubExtra.hpp"
+
+#include "SubExtra_p.hpp"
+
+SubExtraPrivate::SubExtraPrivate()
+{
+}
+
+SubExtraPrivate::~SubExtraPrivate()
+{
+}
+
+SubExtra::SubExtra()
+ : d(new SubExtraPrivate)
+{
+}
+
+SubExtra::~SubExtra()
+{
+ delete d;
+}
diff --git a/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSubDir/SubExtra.hpp b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSubDir/SubExtra.hpp
new file mode 100644
index 0000000..5700634
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSubDir/SubExtra.hpp
@@ -0,0 +1,18 @@
+#ifndef SubExtra_HPP
+#define SubExtra_HPP
+
+#include <QObject>
+
+class SubExtraPrivate;
+class SubExtra : public QObject
+{
+ Q_OBJECT
+public:
+ SubExtra();
+ ~SubExtra();
+
+private:
+ SubExtraPrivate* const d;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSubDir/SubExtra_p.hpp b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSubDir/SubExtra_p.hpp
new file mode 100644
index 0000000..5a14a2d
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSubDir/SubExtra_p.hpp
@@ -0,0 +1,14 @@
+#ifndef SubExtra_P_HPP
+#define SubExtra_P_HPP
+
+#include <QObject>
+
+class SubExtraPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ SubExtraPrivate();
+ ~SubExtraPrivate();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSub_p.hpp b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSub_p.hpp
new file mode 100644
index 0000000..7d5999c
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OtherUnderscoreSub_p.hpp
@@ -0,0 +1,14 @@
+#ifndef OtherUnderscoreSub_P_HPP
+#define OtherUnderscoreSub_P_HPP
+
+#include <QObject>
+
+class OtherUnderscoreSubPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ OtherUnderscoreSubPrivate();
+ ~OtherUnderscoreSubPrivate();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/OtherUnderscore_p.hpp b/Tests/QtAutogen/MocInclude/Common/OtherUnderscore_p.hpp
new file mode 100644
index 0000000..96906cf
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OtherUnderscore_p.hpp
@@ -0,0 +1,14 @@
+#ifndef OtherUnderscore_P_HPP
+#define OtherUnderscore_P_HPP
+
+#include <QObject>
+
+class OtherUnderscorePrivate : public QObject
+{
+ Q_OBJECT
+public:
+ OtherUnderscorePrivate();
+ ~OtherUnderscorePrivate();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/OwnDot.cpp b/Tests/QtAutogen/MocInclude/Common/OwnDot.cpp
new file mode 100644
index 0000000..b7b7d85
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OwnDot.cpp
@@ -0,0 +1,40 @@
+#include "OwnDot.hpp"
+
+#include "OwnDot_p.h"
+
+class OwnDotLocal : public QObject
+{
+ Q_OBJECT
+public:
+ OwnDotLocal();
+ ~OwnDotLocal();
+};
+
+OwnDotLocal::OwnDotLocal()
+{
+}
+
+OwnDotLocal::~OwnDotLocal()
+{
+}
+
+OwnDotPrivate::OwnDotPrivate()
+{
+ OwnDotLocal localObj;
+}
+
+OwnDotPrivate::~OwnDotPrivate()
+{
+}
+
+OwnDot::OwnDot()
+ : d(new OwnDotPrivate)
+{
+}
+
+OwnDot::~OwnDot()
+{
+ delete d;
+}
+
+#include "OwnDot.moc"
diff --git a/Tests/QtAutogen/MocInclude/Common/OwnDot.hpp b/Tests/QtAutogen/MocInclude/Common/OwnDot.hpp
new file mode 100644
index 0000000..6f49f12
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OwnDot.hpp
@@ -0,0 +1,19 @@
+#ifndef OwnDot_HPP
+#define OwnDot_HPP
+
+#include <QObject>
+
+// Object source comes with a .moc include
+class OwnDotPrivate;
+class OwnDot : public QObject
+{
+ Q_OBJECT
+public:
+ OwnDot();
+ ~OwnDot();
+
+private:
+ OwnDotPrivate* const d;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/OwnDotUnderscore.cpp b/Tests/QtAutogen/MocInclude/Common/OwnDotUnderscore.cpp
new file mode 100644
index 0000000..056c0db
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OwnDotUnderscore.cpp
@@ -0,0 +1,41 @@
+#include "OwnDotUnderscore.hpp"
+
+#include "OwnDotUnderscore_p.h"
+
+class OwnDotUnderscoreLocal : public QObject
+{
+ Q_OBJECT
+public:
+ OwnDotUnderscoreLocal();
+ ~OwnDotUnderscoreLocal();
+};
+
+OwnDotUnderscoreLocal::OwnDotUnderscoreLocal()
+{
+}
+
+OwnDotUnderscoreLocal::~OwnDotUnderscoreLocal()
+{
+}
+
+OwnDotUnderscorePrivate::OwnDotUnderscorePrivate()
+{
+ OwnDotUnderscoreLocal localObj;
+}
+
+OwnDotUnderscorePrivate::~OwnDotUnderscorePrivate()
+{
+}
+
+OwnDotUnderscore::OwnDotUnderscore()
+ : d(new OwnDotUnderscorePrivate)
+{
+}
+
+OwnDotUnderscore::~OwnDotUnderscore()
+{
+ delete d;
+}
+
+#include "OwnDotUnderscore.moc"
+#include "moc_OwnDotUnderscore.cpp"
diff --git a/Tests/QtAutogen/MocInclude/Common/OwnDotUnderscore.hpp b/Tests/QtAutogen/MocInclude/Common/OwnDotUnderscore.hpp
new file mode 100644
index 0000000..478955c
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OwnDotUnderscore.hpp
@@ -0,0 +1,19 @@
+#ifndef LOwnDotUnderscore_HPP
+#define LOwnDotUnderscore_HPP
+
+#include <QObject>
+
+// Object source comes with a .moc and a _moc include
+class OwnDotUnderscorePrivate;
+class OwnDotUnderscore : public QObject
+{
+ Q_OBJECT
+public:
+ OwnDotUnderscore();
+ ~OwnDotUnderscore();
+
+private:
+ OwnDotUnderscorePrivate* const d;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/OwnDotUnderscore_p.h b/Tests/QtAutogen/MocInclude/Common/OwnDotUnderscore_p.h
new file mode 100644
index 0000000..6950b7f
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OwnDotUnderscore_p.h
@@ -0,0 +1,14 @@
+#ifndef OwnDotUnderscore_P_HPP
+#define OwnDotUnderscore_P_HPP
+
+#include <QObject>
+
+class OwnDotUnderscorePrivate : public QObject
+{
+ Q_OBJECT
+public:
+ OwnDotUnderscorePrivate();
+ ~OwnDotUnderscorePrivate();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/OwnDot_p.h b/Tests/QtAutogen/MocInclude/Common/OwnDot_p.h
new file mode 100644
index 0000000..f3aff32
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OwnDot_p.h
@@ -0,0 +1,14 @@
+#ifndef OwnDot_P_HPP
+#define OwnDot_P_HPP
+
+#include <QObject>
+
+class OwnDotPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ OwnDotPrivate();
+ ~OwnDotPrivate();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/OwnUnderscore.cpp b/Tests/QtAutogen/MocInclude/Common/OwnUnderscore.cpp
new file mode 100644
index 0000000..cb8f12c
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OwnUnderscore.cpp
@@ -0,0 +1,23 @@
+#include "OwnUnderscore.hpp"
+
+#include "OwnUnderscore_p.h"
+
+OwnUnderscorePrivate::OwnUnderscorePrivate()
+{
+}
+
+OwnUnderscorePrivate::~OwnUnderscorePrivate()
+{
+}
+
+OwnUnderscore::OwnUnderscore()
+ : d(new OwnUnderscorePrivate)
+{
+}
+
+OwnUnderscore::~OwnUnderscore()
+{
+ delete d;
+}
+
+#include "moc_OwnUnderscore.cpp"
diff --git a/Tests/QtAutogen/MocInclude/Common/OwnUnderscore.hpp b/Tests/QtAutogen/MocInclude/Common/OwnUnderscore.hpp
new file mode 100644
index 0000000..e6a6a6e
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OwnUnderscore.hpp
@@ -0,0 +1,19 @@
+#ifndef OwnUnderscore_HPP
+#define OwnUnderscore_HPP
+
+#include <QObject>
+
+// Object source comes with a _moc include
+class OwnUnderscorePrivate;
+class OwnUnderscore : public QObject
+{
+ Q_OBJECT
+public:
+ OwnUnderscore();
+ ~OwnUnderscore();
+
+private:
+ OwnUnderscorePrivate* const d;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/OwnUnderscore_p.h b/Tests/QtAutogen/MocInclude/Common/OwnUnderscore_p.h
new file mode 100644
index 0000000..a3a6b00
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/OwnUnderscore_p.h
@@ -0,0 +1,14 @@
+#ifndef OwnUnderscore_P_HPP
+#define OwnUnderscore_P_HPP
+
+#include <QObject>
+
+class OwnUnderscorePrivate : public QObject
+{
+ Q_OBJECT
+public:
+ OwnUnderscorePrivate();
+ ~OwnUnderscorePrivate();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Common/common.cpp.in b/Tests/QtAutogen/MocInclude/Common/common.cpp.in
new file mode 100644
index 0000000..b53e93d
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/common.cpp.in
@@ -0,0 +1,32 @@
+#include "DualSub/Second/Second.hpp"
+#include "DualSubMocked.hpp"
+#include "ExternDot.hpp"
+#include "ExternDotGenerated.hpp"
+#include "None.hpp"
+#include "OtherUnderscore.hpp"
+#include "OtherUnderscoreSub.hpp"
+#include "OwnDot.hpp"
+#include "OwnDotUnderscore.hpp"
+#include "OwnUnderscore.hpp"
+#include "InIncludes/SubOwnDot.hpp"
+
+bool @COMMON_FUNCTION_NAME@()
+{
+ None objNone;
+ OwnUnderscore objOwnUnderscore;
+ OwnDot objOwnDot;
+ OwnDotUnderscore objOwnDotUnderscore;
+
+ OtherUnderscore objOtherUnderscore;
+ OtherUnderscoreSub objOtherUnderscoreSub;
+
+ Second second;
+ DualSubMocked dualSubMocked;
+
+ ExternDot objExternDot;
+ ExternDotGenerated objGeneratedExternDot;
+
+ InIncludes::SubOwnDot subOwnDot;
+
+ return true;
+}
diff --git a/Tests/QtAutogen/MocInclude/Common/moc_MixedCustom.cpp.in b/Tests/QtAutogen/MocInclude/Common/moc_MixedCustom.cpp.in
new file mode 100644
index 0000000..6c44793
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Common/moc_MixedCustom.cpp.in
@@ -0,0 +1,5 @@
+
+void moc_MixedCustom(MixedCustom const & arg)
+{
+ (void)arg;
+}
diff --git a/Tests/QtAutogen/MocInclude/Relaxed/CMakeLists.txt b/Tests/QtAutogen/MocInclude/Relaxed/CMakeLists.txt
new file mode 100644
index 0000000..048b79c
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Relaxed/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Enable relaxed mode
+set(CMAKE_AUTOMOC_RELAXED_MODE TRUE)
+
+# Common test
+set(COMMON_FUNCTION_NAME commonRelaxed)
+configure_file(
+ "${COM_DIR}/common.cpp.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/commonRelaxed.cpp")
+
+makeExecutable(libRelaxed)
+target_sources(libRelaxed PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/commonRelaxed.cpp"
+ RObjA.cpp
+ RObjB.cpp
+ RObjC.cpp
+ relaxed.cpp
+ )
diff --git a/Tests/QtAutogen/MocInclude/Relaxed/RObjA.cpp b/Tests/QtAutogen/MocInclude/Relaxed/RObjA.cpp
new file mode 100644
index 0000000..2e2cf6a
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Relaxed/RObjA.cpp
@@ -0,0 +1,12 @@
+#include "RObjA.hpp"
+
+RObjA::RObjA()
+{
+}
+
+RObjA::~RObjA()
+{
+}
+
+// Relaxed include should moc the header instead
+#include "RObjA.moc"
diff --git a/Tests/QtAutogen/MocInclude/Relaxed/RObjA.hpp b/Tests/QtAutogen/MocInclude/Relaxed/RObjA.hpp
new file mode 100644
index 0000000..5974187
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Relaxed/RObjA.hpp
@@ -0,0 +1,14 @@
+#ifndef ROBJA_HPP
+#define ROBJA_HPP
+
+#include <QObject>
+
+class RObjA : public QObject
+{
+ Q_OBJECT
+public:
+ RObjA();
+ ~RObjA();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Relaxed/RObjB.cpp b/Tests/QtAutogen/MocInclude/Relaxed/RObjB.cpp
new file mode 100644
index 0000000..57d7daf
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Relaxed/RObjB.cpp
@@ -0,0 +1,23 @@
+#include "RObjB.hpp"
+
+#include "RObjBExtra.hpp"
+
+RObjBExtra::RObjBExtra()
+{
+}
+
+RObjBExtra::~RObjBExtra()
+{
+}
+
+RObjB::RObjB()
+{
+ RObjBExtra extraObject;
+}
+
+RObjB::~RObjB()
+{
+}
+
+// Relaxed mode should run moc on RObjBExtra.hpp instead
+#include "RObjBExtra.moc"
diff --git a/Tests/QtAutogen/MocInclude/Relaxed/RObjB.hpp b/Tests/QtAutogen/MocInclude/Relaxed/RObjB.hpp
new file mode 100644
index 0000000..d6d0474
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Relaxed/RObjB.hpp
@@ -0,0 +1,14 @@
+#ifndef ROBJB_HPP
+#define ROBJB_HPP
+
+#include <QObject>
+
+class RObjB : public QObject
+{
+ Q_OBJECT
+public:
+ RObjB();
+ ~RObjB();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Relaxed/RObjBExtra.hpp b/Tests/QtAutogen/MocInclude/Relaxed/RObjBExtra.hpp
new file mode 100644
index 0000000..5d6be75
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Relaxed/RObjBExtra.hpp
@@ -0,0 +1,14 @@
+#ifndef ROBJBEXTRA_HPP
+#define ROBJBEXTRA_HPP
+
+#include <QObject>
+
+class RObjBExtra : public QObject
+{
+ Q_OBJECT
+public:
+ RObjBExtra();
+ ~RObjBExtra();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Relaxed/RObjC.cpp b/Tests/QtAutogen/MocInclude/Relaxed/RObjC.cpp
new file mode 100644
index 0000000..3275216
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Relaxed/RObjC.cpp
@@ -0,0 +1,31 @@
+#include "RObjC.hpp"
+
+#include <QObject>
+
+class RObjCPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ RObjCPrivate();
+ ~RObjCPrivate();
+};
+
+RObjCPrivate::RObjCPrivate()
+{
+}
+
+RObjCPrivate::~RObjCPrivate()
+{
+}
+
+RObjC::RObjC()
+{
+ RObjCPrivate privateObject;
+}
+
+RObjC::~RObjC()
+{
+}
+
+// Relaxed include should moc this source instead of the header
+#include "moc_RObjC.cpp"
diff --git a/Tests/QtAutogen/MocInclude/Relaxed/RObjC.hpp b/Tests/QtAutogen/MocInclude/Relaxed/RObjC.hpp
new file mode 100644
index 0000000..5552ede
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Relaxed/RObjC.hpp
@@ -0,0 +1,14 @@
+#ifndef ROBJC_HPP
+#define ROBJC_HPP
+
+#include <QObject>
+
+class RObjC : public QObject
+{
+ Q_OBJECT
+public:
+ RObjC();
+ ~RObjC();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocInclude/Relaxed/relaxed.cpp b/Tests/QtAutogen/MocInclude/Relaxed/relaxed.cpp
new file mode 100644
index 0000000..5a511b6
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Relaxed/relaxed.cpp
@@ -0,0 +1,21 @@
+// AUTOMOC relaxed mode objects
+#include "RObjA.hpp"
+#include "RObjB.hpp"
+#include "RObjC.hpp"
+
+// Forward declaration
+bool commonRelaxed();
+
+int main(int argv, char** args)
+{
+ // Common tests
+ if (!commonRelaxed()) {
+ return -1;
+ }
+
+ // Relaxed tests
+ RObjA rObjA;
+ RObjB rObjB;
+ RObjC rObjC;
+ return 0;
+}
diff --git a/Tests/QtAutogen/MocInclude/Strict/CMakeLists.txt b/Tests/QtAutogen/MocInclude/Strict/CMakeLists.txt
new file mode 100644
index 0000000..12c503f
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Strict/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Disable relaxed mode
+set(CMAKE_AUTOMOC_RELAXED_MODE FALSE)
+
+# Common test
+set(COMMON_FUNCTION_NAME commonStrict)
+configure_file(
+ "${COM_DIR}/common.cpp.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/commonStrict.cpp")
+
+makeExecutable(libStrict)
+target_sources(libStrict PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/commonStrict.cpp"
+ strict.cpp
+ )
diff --git a/Tests/QtAutogen/MocInclude/Strict/strict.cpp b/Tests/QtAutogen/MocInclude/Strict/strict.cpp
new file mode 100644
index 0000000..dd24bb0
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/Strict/strict.cpp
@@ -0,0 +1,7 @@
+// Forward declaration
+bool commonStrict();
+
+int main(int argv, char** args)
+{
+ return commonStrict() ? 0 : -1;
+}
diff --git a/Tests/QtAutogen/MocInclude/main.cpp b/Tests/QtAutogen/MocInclude/main.cpp
new file mode 100644
index 0000000..371c5fd
--- /dev/null
+++ b/Tests/QtAutogen/MocInclude/main.cpp
@@ -0,0 +1,9 @@
+
+// Forward declaration
+bool libStrict();
+bool libRelaxed();
+
+int main(int argv, char** args)
+{
+ return (libStrict() && libRelaxed()) ? 0 : -1;
+}
diff --git a/Tests/QtAutogen/MocIncludeSymlink/CMakeLists.txt b/Tests/QtAutogen/MocIncludeSymlink/CMakeLists.txt
new file mode 100644
index 0000000..8b11b46
--- /dev/null
+++ b/Tests/QtAutogen/MocIncludeSymlink/CMakeLists.txt
@@ -0,0 +1,81 @@
+cmake_minimum_required(VERSION 3.15)
+project(MocIncludeSymlink)
+include("../AutogenCoreTest.cmake")
+
+#
+# Tests if MocInclude can be build when
+# - The source directory is a symbolic link
+# - The build directory is a symbolic link
+#
+
+# -- Utility variables
+set(CS_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+set(CB_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+
+# Absolute MocInclude path
+get_filename_component(MocIncludePath "../MocInclude" ABSOLUTE)
+message("MocIncludePath: ${MocIncludePath}")
+
+# Use nested subdirectories to ensure relatives paths are correct as well
+set(BUILD_DIR_NORMAL "${CB_DIR}/Build/Normal")
+set(BUILD_DIR_LINKED "${CB_DIR}/Build/Linked")
+
+set(SL_SOURCE_DIR "${CB_DIR}/SL_Source")
+set(SL_BUILD_DIR "${CB_DIR}/SL_Build")
+
+# -- Utility macros
+function(makeSymLink origin link)
+ message("Creating symbolic link\n Link: ${link}\n To: ${origin}")
+ file(CREATE_LINK ${origin} ${link} RESULT res SYMBOLIC)
+ if(NOT (${res} STREQUAL "0"))
+ message("Symlink creation failed.\n Link: ${link}\n To: ${origin}\n Result: ${res}")
+ endif()
+endfunction()
+
+# -- Make source directory symlink
+makeSymLink(${MocIncludePath} ${SL_SOURCE_DIR} linkResult)
+if(NOT EXISTS ${SL_SOURCE_DIR})
+ message("Directory symlink can't be created. Skipping test.")
+ return()
+endif()
+
+# -- Make normal build directory
+file(REMOVE_RECURSE ${BUILD_DIR_NORMAL})
+file(MAKE_DIRECTORY ${BUILD_DIR_NORMAL})
+
+# -- Make linked build directory and symlink
+file(REMOVE_RECURSE ${BUILD_DIR_LINKED})
+file(MAKE_DIRECTORY ${BUILD_DIR_LINKED})
+makeSymLink(${BUILD_DIR_LINKED} ${SL_BUILD_DIR} linkResult)
+if(NOT EXISTS ${SL_BUILD_DIR})
+ message("Directory symlink can't be created. Skipping test.")
+ return()
+endif()
+
+
+# -- Building
+macro(buildMocInclude sourceDir binaryDir)
+ message("Building MocInclude\n - source dir: ${sourceDir}\n - binary dir: ${binaryDir}\n")
+ try_compile(result
+ "${binaryDir}"
+ "${sourceDir}"
+ MocInclude
+ CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
+ "-DCMAKE_AUTOMOC_PATH_PREFIX=ON"
+ "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+ "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+ OUTPUT_VARIABLE output
+ )
+ if (result)
+ message(STATUS "--- Build success. ---")
+ else()
+ message(STATUS "\n### Building MocInclude failed. ###\n\n--- Output ---\n${output}")
+ message(FATAL_ERROR "--- Building MocInclude failed. End of output. ---")
+ endif()
+endmacro()
+
+message("\nTry building with\n - symbolic link source dir\n - non symbolic build dir\n")
+buildMocInclude(${SL_SOURCE_DIR} ${BUILD_DIR_NORMAL})
+
+message("\nTry building with\n - symbolic link source dir\n - symbolic link build dir\n")
+buildMocInclude(${SL_SOURCE_DIR} ${SL_BUILD_DIR})
diff --git a/Tests/QtAutogen/MocMacroName/CMakeLists.txt b/Tests/QtAutogen/MocMacroName/CMakeLists.txt
new file mode 100644
index 0000000..bf13d18
--- /dev/null
+++ b/Tests/QtAutogen/MocMacroName/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.10)
+project(MocMacroName)
+include("../AutogenCoreTest.cmake")
+
+# Test CMAKE_AUTOMOC_MACRO_NAMES and AUTOMOC_MACRO_NAMES
+list(APPEND CMAKE_AUTOMOC_MACRO_NAMES "QO1_ALIAS")
+
+add_executable(mocMacroName
+ main.cpp
+ Gadget.cpp
+ Object.cpp
+ Object1Aliased.cpp
+ Object2Aliased.cpp
+)
+set_property(TARGET mocMacroName PROPERTY AUTOMOC ON)
+set_property(TARGET mocMacroName APPEND PROPERTY AUTOMOC_MACRO_NAMES "QO2_ALIAS")
+target_link_libraries(mocMacroName ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/MocMacroName/CustomMacros.hpp b/Tests/QtAutogen/MocMacroName/CustomMacros.hpp
new file mode 100644
index 0000000..93e5bfd
--- /dev/null
+++ b/Tests/QtAutogen/MocMacroName/CustomMacros.hpp
@@ -0,0 +1,8 @@
+#ifndef CUSTOM_MACROS_HPP
+#define CUSTOM_MACROS_HPP
+
+#include <QObject>
+#define QO1_ALIAS Q_OBJECT
+#define QO2_ALIAS Q_OBJECT
+
+#endif
diff --git a/Tests/QtAutogen/MocMacroName/Gadget.cpp b/Tests/QtAutogen/MocMacroName/Gadget.cpp
new file mode 100644
index 0000000..d7cb515
--- /dev/null
+++ b/Tests/QtAutogen/MocMacroName/Gadget.cpp
@@ -0,0 +1,6 @@
+#include "Gadget.hpp"
+
+Gadget::Gadget()
+ : _test(0)
+{
+}
diff --git a/Tests/QtAutogen/MocMacroName/Gadget.hpp b/Tests/QtAutogen/MocMacroName/Gadget.hpp
new file mode 100644
index 0000000..cab792e
--- /dev/null
+++ b/Tests/QtAutogen/MocMacroName/Gadget.hpp
@@ -0,0 +1,19 @@
+#ifndef GADGET_HPP
+#define GADGET_HPP
+
+#include <QMetaType>
+
+class Gadget
+{
+ Q_GADGET
+ Q_PROPERTY(int test READ getTest)
+public:
+ Gadget();
+
+ int getTest() { return _test; }
+
+private:
+ int _test;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocMacroName/Object.cpp b/Tests/QtAutogen/MocMacroName/Object.cpp
new file mode 100644
index 0000000..800ebf3
--- /dev/null
+++ b/Tests/QtAutogen/MocMacroName/Object.cpp
@@ -0,0 +1,10 @@
+#include "Object.hpp"
+
+Object::Object()
+ : _test(0)
+{
+}
+
+void Object::aSlot()
+{
+}
diff --git a/Tests/QtAutogen/MocMacroName/Object.hpp b/Tests/QtAutogen/MocMacroName/Object.hpp
new file mode 100644
index 0000000..aadae1f
--- /dev/null
+++ b/Tests/QtAutogen/MocMacroName/Object.hpp
@@ -0,0 +1,22 @@
+#ifndef OBJECT_HPP
+#define OBJECT_HPP
+
+#include <QObject>
+
+class Object : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int test READ getTest)
+public:
+ Object();
+
+ int getTest() { return _test; }
+
+ Q_SLOT
+ void aSlot();
+
+private:
+ int _test;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocMacroName/Object1Aliased.cpp b/Tests/QtAutogen/MocMacroName/Object1Aliased.cpp
new file mode 100644
index 0000000..b8b4806
--- /dev/null
+++ b/Tests/QtAutogen/MocMacroName/Object1Aliased.cpp
@@ -0,0 +1,9 @@
+#include "Object1Aliased.hpp"
+
+Object1Aliased::Object1Aliased()
+{
+}
+
+void Object1Aliased::aSlot()
+{
+}
diff --git a/Tests/QtAutogen/MocMacroName/Object1Aliased.hpp b/Tests/QtAutogen/MocMacroName/Object1Aliased.hpp
new file mode 100644
index 0000000..6c6bb40
--- /dev/null
+++ b/Tests/QtAutogen/MocMacroName/Object1Aliased.hpp
@@ -0,0 +1,20 @@
+#ifndef OBJECTALIASED_HPP
+#define OBJECTALIASED_HPP
+
+#include "CustomMacros.hpp"
+
+// Test Qt object macro hidden in a macro (AUTOMOC_MACRO_NAMES)
+class Object1Aliased : public QObject
+{
+ QO1_ALIAS
+public:
+ Object1Aliased();
+
+signals:
+ void aSignal();
+
+public slots:
+ void aSlot();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocMacroName/Object2Aliased.cpp b/Tests/QtAutogen/MocMacroName/Object2Aliased.cpp
new file mode 100644
index 0000000..4b09dd1
--- /dev/null
+++ b/Tests/QtAutogen/MocMacroName/Object2Aliased.cpp
@@ -0,0 +1,9 @@
+#include "Object2Aliased.hpp"
+
+Object2Aliased::Object2Aliased()
+{
+}
+
+void Object2Aliased::aSlot()
+{
+}
diff --git a/Tests/QtAutogen/MocMacroName/Object2Aliased.hpp b/Tests/QtAutogen/MocMacroName/Object2Aliased.hpp
new file mode 100644
index 0000000..b9bdc12
--- /dev/null
+++ b/Tests/QtAutogen/MocMacroName/Object2Aliased.hpp
@@ -0,0 +1,20 @@
+#ifndef OBJECT2ALIASED_HPP
+#define OBJECT2ALIASED_HPP
+
+#include "CustomMacros.hpp"
+
+// Test Qt object macro hidden in a macro (AUTOMOC_MACRO_NAMES)
+class Object2Aliased : public QObject
+{
+ QO2_ALIAS
+public:
+ Object2Aliased();
+
+signals:
+ void aSignal();
+
+public slots:
+ void aSlot();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocMacroName/main.cpp b/Tests/QtAutogen/MocMacroName/main.cpp
new file mode 100644
index 0000000..3b45d04
--- /dev/null
+++ b/Tests/QtAutogen/MocMacroName/main.cpp
@@ -0,0 +1,13 @@
+#include "Gadget.hpp"
+#include "Object.hpp"
+#include "Object1Aliased.hpp"
+#include "Object2Aliased.hpp"
+
+int main(int argv, char** args)
+{
+ Gadget gadget;
+ Object object;
+ Object1Aliased object1Aliased;
+ Object2Aliased object2Aliased;
+ return 0;
+}
diff --git a/Tests/QtAutogen/MocOnly/CMakeLists.txt b/Tests/QtAutogen/MocOnly/CMakeLists.txt
new file mode 100644
index 0000000..f4fde58
--- /dev/null
+++ b/Tests/QtAutogen/MocOnly/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.10)
+project(MocOnly)
+include("../AutogenCoreTest.cmake")
+
+add_executable(mocOnly
+ main.cpp
+ # Test different Q_OBJECT position styles
+ StyleA.cpp
+ StyleB.cpp
+ # Test different moc_/.moc include positions
+ IncA.cpp
+ IncB.cpp
+)
+# XXX(xcode-per-cfg-src): Drop the NO_PER_CONFIG_SOURCES exclusion
+# when the Xcode generator supports per-config sources.
+if(NOT NO_PER_CONFIG_SOURCES)
+ target_sources(mocOnly PRIVATE
+ "$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/CfgDebug.cpp>"
+ "$<$<NOT:$<CONFIG:Debug>>:${CMAKE_CURRENT_SOURCE_DIR}/CfgOther.cpp>"
+ )
+ target_compile_definitions(mocOnly PRIVATE
+ "$<$<CONFIG:Debug>:HAVE_CFG_DEBUG>"
+ "$<$<NOT:$<CONFIG:Debug>>:HAVE_CFG_OTHER>"
+ )
+endif()
+set_property(TARGET mocOnly PROPERTY AUTOMOC ON)
+target_link_libraries(mocOnly ${QT_LIBRARIES})
+# Add compile definitions with unusual characters
+target_compile_definitions(mocOnly PUBLIC "TOKEN=\"hello\;\"" )
diff --git a/Tests/QtAutogen/MocOnly/CfgDebug.cpp b/Tests/QtAutogen/MocOnly/CfgDebug.cpp
new file mode 100644
index 0000000..07ca3fb
--- /dev/null
+++ b/Tests/QtAutogen/MocOnly/CfgDebug.cpp
@@ -0,0 +1,5 @@
+#include "CfgDebug.hpp"
+
+CfgDebug::CfgDebug()
+{
+}
diff --git a/Tests/QtAutogen/MocOnly/CfgDebug.hpp b/Tests/QtAutogen/MocOnly/CfgDebug.hpp
new file mode 100644
index 0000000..3cd90a4
--- /dev/null
+++ b/Tests/QtAutogen/MocOnly/CfgDebug.hpp
@@ -0,0 +1,15 @@
+#ifndef CFGDEBUG_HPP
+#define CFGDEBUG_HPP
+
+#include <QObject>
+
+/* clang-format off */
+class CfgDebug : public QObject
+{
+ Q_OBJECT
+public:
+ CfgDebug();
+};
+/* clang-format on */
+
+#endif
diff --git a/Tests/QtAutogen/MocOnly/CfgOther.cpp b/Tests/QtAutogen/MocOnly/CfgOther.cpp
new file mode 100644
index 0000000..0ccd433
--- /dev/null
+++ b/Tests/QtAutogen/MocOnly/CfgOther.cpp
@@ -0,0 +1,5 @@
+#include "CfgOther.hpp"
+
+CfgOther::CfgOther()
+{
+}
diff --git a/Tests/QtAutogen/MocOnly/CfgOther.hpp b/Tests/QtAutogen/MocOnly/CfgOther.hpp
new file mode 100644
index 0000000..7cacd52
--- /dev/null
+++ b/Tests/QtAutogen/MocOnly/CfgOther.hpp
@@ -0,0 +1,15 @@
+#ifndef CFGOTHER_HPP
+#define CFGOTHER_HPP
+
+#include <QObject>
+
+/* clang-format off */
+class CfgOther : public QObject
+{
+ Q_OBJECT
+public:
+ CfgOther();
+};
+/* clang-format on */
+
+#endif
diff --git a/Tests/QtAutogen/MocOnly/IncA.cpp b/Tests/QtAutogen/MocOnly/IncA.cpp
new file mode 100644
index 0000000..94610cd
--- /dev/null
+++ b/Tests/QtAutogen/MocOnly/IncA.cpp
@@ -0,0 +1,19 @@
+#include "moc_IncA.cpp"
+/// AUTOMOC moc_ include on the first line of the file!
+#include "IncA.hpp"
+
+/// @brief Source local QObject
+///
+class IncAPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ IncAPrivate(){};
+};
+
+IncA::IncA()
+{
+ IncAPrivate priv;
+}
+
+#include "IncA.moc"
diff --git a/Tests/QtAutogen/MocOnly/IncA.hpp b/Tests/QtAutogen/MocOnly/IncA.hpp
new file mode 100644
index 0000000..ecc889f
--- /dev/null
+++ b/Tests/QtAutogen/MocOnly/IncA.hpp
@@ -0,0 +1,15 @@
+#ifndef INCA_HPP
+#define INCA_HPP
+
+#include <QObject>
+
+/// @brief Test moc include pattern in the source file
+///
+class IncA : public QObject
+{
+ Q_OBJECT
+public:
+ IncA();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocOnly/IncB.cpp b/Tests/QtAutogen/MocOnly/IncB.cpp
new file mode 100644
index 0000000..bd441a9
--- /dev/null
+++ b/Tests/QtAutogen/MocOnly/IncB.cpp
@@ -0,0 +1,19 @@
+#include "IncB.hpp"
+
+/// @brief Source local QObject
+///
+class IncBPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ IncBPrivate(){};
+};
+
+IncB::IncB()
+{
+ IncBPrivate priv;
+}
+
+/// AUTOMOC moc_ include on the last line of the file!
+#include "IncB.moc"
+#include "moc_IncB.cpp"
diff --git a/Tests/QtAutogen/MocOnly/IncB.hpp b/Tests/QtAutogen/MocOnly/IncB.hpp
new file mode 100644
index 0000000..8331ea2
--- /dev/null
+++ b/Tests/QtAutogen/MocOnly/IncB.hpp
@@ -0,0 +1,15 @@
+#ifndef INCB_HPP
+#define INCB_HPP
+
+#include <QObject>
+
+/// @brief Test moc include pattern in the source file
+///
+class IncB : public QObject
+{
+ Q_OBJECT
+public:
+ IncB();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocOnly/StyleA.cpp b/Tests/QtAutogen/MocOnly/StyleA.cpp
new file mode 100644
index 0000000..ced1dd1
--- /dev/null
+++ b/Tests/QtAutogen/MocOnly/StyleA.cpp
@@ -0,0 +1,5 @@
+#include "StyleA.hpp"
+
+StyleA::StyleA()
+{
+}
diff --git a/Tests/QtAutogen/MocOnly/StyleA.hpp b/Tests/QtAutogen/MocOnly/StyleA.hpp
new file mode 100644
index 0000000..5ba0a87
--- /dev/null
+++ b/Tests/QtAutogen/MocOnly/StyleA.hpp
@@ -0,0 +1,17 @@
+#ifndef STYLEA_HPP
+#define STYLEA_HPP
+
+#include <QObject>
+
+/* clang-format off */
+/// Q_OBJECT on a single new line
+///
+class StyleA : public QObject
+{
+ Q_OBJECT
+public:
+ StyleA();
+};
+/* clang-format on */
+
+#endif
diff --git a/Tests/QtAutogen/MocOnly/StyleB.cpp b/Tests/QtAutogen/MocOnly/StyleB.cpp
new file mode 100644
index 0000000..bec6c1c
--- /dev/null
+++ b/Tests/QtAutogen/MocOnly/StyleB.cpp
@@ -0,0 +1,5 @@
+#include "StyleB.hpp"
+
+StyleB::StyleB()
+{
+}
diff --git a/Tests/QtAutogen/MocOnly/StyleB.hpp b/Tests/QtAutogen/MocOnly/StyleB.hpp
new file mode 100644
index 0000000..86abaa8
--- /dev/null
+++ b/Tests/QtAutogen/MocOnly/StyleB.hpp
@@ -0,0 +1,16 @@
+#ifndef STYLEB_HPP
+#define STYLEB_HPP
+
+#include <QObject>
+
+/* clang-format off */
+/// Q_OBJECT behind a brace on a new line
+///
+class StyleB : public QObject
+{ Q_OBJECT
+public:
+ StyleB();
+};
+/* clang-format on */
+
+#endif
diff --git a/Tests/QtAutogen/MocOnly/main.cpp b/Tests/QtAutogen/MocOnly/main.cpp
new file mode 100644
index 0000000..6c0f6f2
--- /dev/null
+++ b/Tests/QtAutogen/MocOnly/main.cpp
@@ -0,0 +1,27 @@
+#include <iostream>
+
+#include "IncA.hpp"
+#include "IncB.hpp"
+#include "StyleA.hpp"
+#include "StyleB.hpp"
+
+#ifdef HAVE_CFG_DEBUG
+# include "CfgDebug.hpp"
+#endif
+
+#ifdef HAVE_CFG_OTHER
+# include "CfgOther.hpp"
+#endif
+
+int main(int argv, char** args)
+{
+ StyleA styleA;
+ StyleB styleB;
+ IncA incA;
+ IncB incB;
+
+ // Test the TOKEN definition passed on the command line
+ std::string token(TOKEN);
+ std::cout << "std::string(TOKEN): \"" << token << "\"\n";
+ return (token == "hello;") ? 0 : -1;
+}
diff --git a/Tests/QtAutogen/MocOptions/CMakeLists.txt b/Tests/QtAutogen/MocOptions/CMakeLists.txt
new file mode 100644
index 0000000..19ee658
--- /dev/null
+++ b/Tests/QtAutogen/MocOptions/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.10)
+project(MocOptions)
+include("../AutogenCoreTest.cmake")
+
+# Test extra options passed to moc via AUTOMOC_MOC_OPTIONS
+add_executable(mocOptions Object.cpp main.cpp)
+set_property(TARGET mocOptions PROPERTY AUTOMOC ON)
+set_property(TARGET mocOptions PROPERTY AUTOMOC_MOC_OPTIONS "-nw")
+target_link_libraries(mocOptions ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/MocOptions/Object.cpp b/Tests/QtAutogen/MocOptions/Object.cpp
new file mode 100644
index 0000000..ad109f1
--- /dev/null
+++ b/Tests/QtAutogen/MocOptions/Object.cpp
@@ -0,0 +1,5 @@
+#include "Object.hpp"
+
+Object::Object()
+{
+}
diff --git a/Tests/QtAutogen/MocOptions/Object.hpp b/Tests/QtAutogen/MocOptions/Object.hpp
new file mode 100644
index 0000000..e7a6142
--- /dev/null
+++ b/Tests/QtAutogen/MocOptions/Object.hpp
@@ -0,0 +1,13 @@
+#ifndef Object_HPP
+#define Object_HPP
+
+#include <QObject>
+
+class Object : public QObject
+{
+ Q_OBJECT
+public:
+ Object();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocOptions/main.cpp b/Tests/QtAutogen/MocOptions/main.cpp
new file mode 100644
index 0000000..7aeab1a
--- /dev/null
+++ b/Tests/QtAutogen/MocOptions/main.cpp
@@ -0,0 +1,7 @@
+#include "Object.hpp"
+
+int main(int argv, char** args)
+{
+ Object object;
+ return 0;
+}
diff --git a/Tests/QtAutogen/MocOsMacros/CMakeLists.txt b/Tests/QtAutogen/MocOsMacros/CMakeLists.txt
new file mode 100644
index 0000000..b0125f6
--- /dev/null
+++ b/Tests/QtAutogen/MocOsMacros/CMakeLists.txt
@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 3.11)
+project(MocOsMacros)
+include("../AutogenCoreTest.cmake")
+
+# Tests if moc processes Q_OS_XXX macros
+
+message( "Qt5Core_VERSION: ${Qt5Core_VERSION}" )
+message(
+ "CMAKE_CXX_COMPILER_PREDEFINES_COMMAND: "
+ ${CMAKE_CXX_COMPILER_PREDEFINES_COMMAND} )
+
+# On some platforms (e.g. MAC) Q_OS_XXX requires moc to include moc_predefs.h
+# which is supported since Qt 5.8 and requires
+# CMAKE_CXX_COMPILER_PREDEFINES_COMMAND to be defined.
+if( ( ${Qt5Core_VERSION} VERSION_GREATER_EQUAL "5.8" ) AND
+ DEFINED CMAKE_CXX_COMPILER_PREDEFINES_COMMAND
+)
+ message( "Test enabled!" )
+ message(
+ "CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES: "
+ ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES} )
+
+ set(CMAKE_AUTOMOC True)
+ add_executable(mocOsMacros
+ main.cpp
+ TestClass.cpp
+ TestClass.hpp
+ )
+ target_link_libraries(mocOsMacros PRIVATE ${QT_QTCORE_TARGET})
+else()
+ message( "Test disabled!" )
+endif()
diff --git a/Tests/QtAutogen/MocOsMacros/TestClass.cpp b/Tests/QtAutogen/MocOsMacros/TestClass.cpp
new file mode 100644
index 0000000..babc08b
--- /dev/null
+++ b/Tests/QtAutogen/MocOsMacros/TestClass.cpp
@@ -0,0 +1,83 @@
+#include "TestClass.hpp"
+
+#include <iostream>
+
+void TestClass::open()
+{
+ std::cout << "open\n";
+}
+
+// -- Mac
+#ifndef Q_OS_MAC
+void TestClass::MacNotDef()
+{
+ std::cout << "MacNotDef\n";
+}
+#else
+void TestClass::MacNotDefElse()
+{
+ std::cout << "MacNotDefElse\n";
+}
+#endif
+
+#ifdef Q_OS_MAC
+void TestClass::MacDef()
+{
+ std::cout << "MacDef\n";
+}
+#else
+void TestClass::MacDefElse()
+{
+ std::cout << "MacDefElse\n";
+}
+#endif
+
+// -- Unix
+#ifndef Q_OS_UNIX
+void TestClass::UnixNotDef()
+{
+ std::cout << "UnixNotDef\n";
+}
+#else
+void TestClass::UnixNotDefElse()
+{
+ std::cout << "UnixNotDefElse\n";
+}
+#endif
+
+#ifdef Q_OS_UNIX
+void TestClass::UnixDef()
+{
+ std::cout << "UnixDef\n";
+}
+#else
+void TestClass::UnixDefElse()
+{
+ std::cout << "UnixDefElse\n";
+}
+#endif
+
+// -- Windows
+#ifndef Q_OS_WIN
+void TestClass::WindowsNotDef()
+{
+ std::cout << "WindowsNotDef\n";
+}
+#else
+void TestClass::WindowsNotDefElse()
+{
+ std::cout << "WindowsNotDefElse\n";
+}
+#endif
+
+#ifdef Q_OS_WIN
+void TestClass::WindowsDef()
+{
+ std::cout << "WindowsDef\n";
+}
+#else
+void TestClass::WindowsDefElse()
+{
+ std::cout << "WindowsDefElse\n";
+}
+#endif
diff --git a/Tests/QtAutogen/MocOsMacros/TestClass.hpp b/Tests/QtAutogen/MocOsMacros/TestClass.hpp
new file mode 100644
index 0000000..87fd494
--- /dev/null
+++ b/Tests/QtAutogen/MocOsMacros/TestClass.hpp
@@ -0,0 +1,57 @@
+#ifndef TestClass_hpp
+#define TestClass_hpp
+
+#include <QObject>
+#include <QtGlobal>
+// include qplatformdefs.h for #18669
+#include <qplatformdefs.h>
+
+class TestClass : public QObject
+{
+ Q_OBJECT
+public Q_SLOTS:
+
+ // Method named "open" to test if #18669 is fixed
+ void open();
+
+// -- Mac
+#ifndef Q_OS_MAC
+ void MacNotDef();
+#else
+ void MacNotDefElse();
+#endif
+
+#ifdef Q_OS_MAC
+ void MacDef();
+#else
+ void MacDefElse();
+#endif
+
+// -- Unix
+#ifndef Q_OS_UNIX
+ void UnixNotDef();
+#else
+ void UnixNotDefElse();
+#endif
+
+#ifdef Q_OS_UNIX
+ void UnixDef();
+#else
+ void UnixDefElse();
+#endif
+
+// -- Windows
+#ifndef Q_OS_WIN
+ void WindowsNotDef();
+#else
+ void WindowsNotDefElse();
+#endif
+
+#ifdef Q_OS_WIN
+ void WindowsDef();
+#else
+ void WindowsDefElse();
+#endif
+};
+
+#endif /* TestClass_hpp */
diff --git a/Tests/QtAutogen/MocOsMacros/main.cpp b/Tests/QtAutogen/MocOsMacros/main.cpp
new file mode 100644
index 0000000..c427345
--- /dev/null
+++ b/Tests/QtAutogen/MocOsMacros/main.cpp
@@ -0,0 +1,33 @@
+#include <QtGlobal>
+
+#include "TestClass.hpp"
+
+int main()
+{
+ TestClass a;
+#ifdef Q_OS_MAC
+ a.MacNotDefElse();
+ a.MacDef();
+#else
+ a.MacNotDef();
+ a.MacDefElse();
+#endif
+
+#ifdef Q_OS_UNIX
+ a.UnixNotDefElse();
+ a.UnixDef();
+#else
+ a.UnixNotDef();
+ a.UnixDefElse();
+#endif
+
+#ifdef Q_OS_WIN
+ a.WindowsNotDefElse();
+ a.WindowsDef();
+#else
+ a.WindowsNotDef();
+ a.WindowsDefElse();
+#endif
+
+ return 0;
+}
diff --git a/Tests/QtAutogen/MocSkipSource/CMakeLists.txt b/Tests/QtAutogen/MocSkipSource/CMakeLists.txt
new file mode 100644
index 0000000..c886736
--- /dev/null
+++ b/Tests/QtAutogen/MocSkipSource/CMakeLists.txt
@@ -0,0 +1,43 @@
+cmake_minimum_required(VERSION 3.10)
+project(MocSkipSource)
+include("../AutogenCoreTest.cmake")
+
+# Test for SKIP_AUTOMOC and SKIP_AUTOGEN on an AUTOMOC enabled target
+
+# Generate header mocs manually
+qtx_wrap_cpp(skipMocWrapMoc
+ qItemA.hpp
+ qItemB.hpp
+ qItemC.hpp
+ qItemD.hpp
+)
+set(skipMocSources
+ skipMoc.cpp
+ qItemA.cpp
+ qItemB.cpp
+ qItemC.cpp
+ qItemD.cpp
+)
+# When cpp files are skipped, the hpp won't be processed either,
+# unless they are mentioned in the sources - which they aren't.
+set_property(SOURCE qItemA.cpp PROPERTY SKIP_AUTOMOC ON)
+set_property(SOURCE qItemB.cpp PROPERTY SKIP_AUTOGEN ON)
+# When hpp files are skipped, the cpp still get processed.
+set_property(SOURCE qItemC.hpp PROPERTY SKIP_AUTOMOC ON)
+set_property(SOURCE qItemD.hpp PROPERTY SKIP_AUTOGEN ON)
+# AUTOMOC enabled only
+add_executable(skipMocA ${skipMocSources} ${skipMocWrapMoc})
+set_property(TARGET skipMocA PROPERTY AUTOMOC ON)
+target_link_libraries(skipMocA ${QT_LIBRARIES})
+
+if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12)
+ # FIXME: Fix AUTOMOC for the Xcode "new build system" to avoid
+ # duplicating custom commands in multiple _autogen targets.
+ return()
+endif()
+
+# AUTOMOC and AUTOUIC enabled
+add_executable(skipMocB ${skipMocSources} ${skipMocWrapMoc})
+set_property(TARGET skipMocB PROPERTY AUTOMOC ON)
+set_property(TARGET skipMocB PROPERTY AUTOUIC ON)
+target_link_libraries(skipMocB ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/MocSkipSource/qItemA.cpp b/Tests/QtAutogen/MocSkipSource/qItemA.cpp
new file mode 100644
index 0000000..522c2c7
--- /dev/null
+++ b/Tests/QtAutogen/MocSkipSource/qItemA.cpp
@@ -0,0 +1,5 @@
+#include "qItemA.hpp"
+
+void QItemA::go()
+{
+}
diff --git a/Tests/QtAutogen/MocSkipSource/qItemA.hpp b/Tests/QtAutogen/MocSkipSource/qItemA.hpp
new file mode 100644
index 0000000..d295faf
--- /dev/null
+++ b/Tests/QtAutogen/MocSkipSource/qItemA.hpp
@@ -0,0 +1,13 @@
+#ifndef QITEMA_HPP
+#define QITEMA_HPP
+
+#include <QObject>
+
+class QItemA : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocSkipSource/qItemB.cpp b/Tests/QtAutogen/MocSkipSource/qItemB.cpp
new file mode 100644
index 0000000..636e15d
--- /dev/null
+++ b/Tests/QtAutogen/MocSkipSource/qItemB.cpp
@@ -0,0 +1,5 @@
+#include "qItemB.hpp"
+
+void QItemB::go()
+{
+}
diff --git a/Tests/QtAutogen/MocSkipSource/qItemB.hpp b/Tests/QtAutogen/MocSkipSource/qItemB.hpp
new file mode 100644
index 0000000..1775915
--- /dev/null
+++ b/Tests/QtAutogen/MocSkipSource/qItemB.hpp
@@ -0,0 +1,13 @@
+#ifndef QITEMB_HPP
+#define QITEMB_HPP
+
+#include <QObject>
+
+class QItemB : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocSkipSource/qItemC.cpp b/Tests/QtAutogen/MocSkipSource/qItemC.cpp
new file mode 100644
index 0000000..622f282
--- /dev/null
+++ b/Tests/QtAutogen/MocSkipSource/qItemC.cpp
@@ -0,0 +1,17 @@
+#include "qItemC.hpp"
+
+class QItemC_Local : public QObject
+{
+ Q_OBJECT
+public:
+ QItemC_Local(){};
+ ~QItemC_Local(){};
+};
+
+void QItemC::go()
+{
+ QItemC_Local localObject;
+}
+
+// We need AUTOMOC processing
+#include "qItemC.moc"
diff --git a/Tests/QtAutogen/MocSkipSource/qItemC.hpp b/Tests/QtAutogen/MocSkipSource/qItemC.hpp
new file mode 100644
index 0000000..f06bda2
--- /dev/null
+++ b/Tests/QtAutogen/MocSkipSource/qItemC.hpp
@@ -0,0 +1,13 @@
+#ifndef QITEMC_HPP
+#define QITEMC_HPP
+
+#include <QObject>
+
+class QItemC : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocSkipSource/qItemD.cpp b/Tests/QtAutogen/MocSkipSource/qItemD.cpp
new file mode 100644
index 0000000..fe0f4e4
--- /dev/null
+++ b/Tests/QtAutogen/MocSkipSource/qItemD.cpp
@@ -0,0 +1,17 @@
+#include "qItemD.hpp"
+
+class QItemD_Local : public QObject
+{
+ Q_OBJECT
+public:
+ QItemD_Local(){};
+ ~QItemD_Local(){};
+};
+
+void QItemD::go()
+{
+ QItemD_Local localObject;
+}
+
+// We need AUTOMOC processing
+#include "qItemD.moc"
diff --git a/Tests/QtAutogen/MocSkipSource/qItemD.hpp b/Tests/QtAutogen/MocSkipSource/qItemD.hpp
new file mode 100644
index 0000000..99e0acb
--- /dev/null
+++ b/Tests/QtAutogen/MocSkipSource/qItemD.hpp
@@ -0,0 +1,13 @@
+#ifndef QITEMD_HPP
+#define QITEMD_HPP
+
+#include <QObject>
+
+class QItemD : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocSkipSource/skipMoc.cpp b/Tests/QtAutogen/MocSkipSource/skipMoc.cpp
new file mode 100644
index 0000000..c915334
--- /dev/null
+++ b/Tests/QtAutogen/MocSkipSource/skipMoc.cpp
@@ -0,0 +1,16 @@
+
+#include "qItemA.hpp"
+#include "qItemB.hpp"
+#include "qItemC.hpp"
+#include "qItemD.hpp"
+
+int main(int, char**)
+{
+ QItemA itemA;
+ QItemB itemB;
+ QItemC itemC;
+ QItemD itemD;
+
+ // Fails to link if the symbol is not present.
+ return 0;
+}
diff --git a/Tests/QtAutogen/ObjectLibrary/CMakeLists.txt b/Tests/QtAutogen/ObjectLibrary/CMakeLists.txt
new file mode 100644
index 0000000..ec204e7
--- /dev/null
+++ b/Tests/QtAutogen/ObjectLibrary/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.10)
+project(ObjectLibrary)
+include("../AutogenCoreTest.cmake")
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(CMAKE_AUTOMOC ON)
+
+# Object library a defined in a subdirectory
+add_subdirectory(a)
+
+# Object library b defined locally
+include_directories(b)
+add_library(b OBJECT b/classb.cpp)
+target_compile_features(b PRIVATE ${QT_COMPILE_FEATURES})
+
+# Executable with OBJECT library generator expressions
+add_executable(someProgram main.cpp $<TARGET_OBJECTS:a> $<TARGET_OBJECTS:b>)
+target_link_libraries(someProgram ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/ObjectLibrary/a/CMakeLists.txt b/Tests/QtAutogen/ObjectLibrary/a/CMakeLists.txt
new file mode 100644
index 0000000..fe76ac3
--- /dev/null
+++ b/Tests/QtAutogen/ObjectLibrary/a/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(a OBJECT classa.cpp)
+target_compile_features(a PRIVATE ${QT_COMPILE_FEATURES})
diff --git a/Tests/QtAutogen/ObjectLibrary/a/classa.cpp b/Tests/QtAutogen/ObjectLibrary/a/classa.cpp
new file mode 100644
index 0000000..a548652
--- /dev/null
+++ b/Tests/QtAutogen/ObjectLibrary/a/classa.cpp
@@ -0,0 +1,8 @@
+#include "classa.h"
+
+#include <QDebug>
+
+void ClassA::slotDoSomething()
+{
+ qDebug() << m_member;
+}
diff --git a/Tests/QtAutogen/ObjectLibrary/a/classa.h b/Tests/QtAutogen/ObjectLibrary/a/classa.h
new file mode 100644
index 0000000..fa5fed9
--- /dev/null
+++ b/Tests/QtAutogen/ObjectLibrary/a/classa.h
@@ -0,0 +1,23 @@
+#ifndef CLASSA_H
+#define CLASSA_H
+
+#include <QObject>
+#include <QString>
+
+class ClassA : public QObject
+{
+ Q_OBJECT
+public:
+ ClassA()
+ : m_member("Hello A")
+ {
+ }
+
+public slots:
+ void slotDoSomething();
+
+private:
+ QString m_member;
+};
+
+#endif
diff --git a/Tests/QtAutogen/ObjectLibrary/b/classb.cpp b/Tests/QtAutogen/ObjectLibrary/b/classb.cpp
new file mode 100644
index 0000000..e5cc2e7
--- /dev/null
+++ b/Tests/QtAutogen/ObjectLibrary/b/classb.cpp
@@ -0,0 +1,8 @@
+#include "classb.h"
+
+#include <QDebug>
+
+void ClassB::slotDoSomething()
+{
+ qDebug() << m_member;
+}
diff --git a/Tests/QtAutogen/ObjectLibrary/b/classb.h b/Tests/QtAutogen/ObjectLibrary/b/classb.h
new file mode 100644
index 0000000..783bb48
--- /dev/null
+++ b/Tests/QtAutogen/ObjectLibrary/b/classb.h
@@ -0,0 +1,23 @@
+#ifndef CLASSB_H
+#define CLASSB_H
+
+#include <QObject>
+#include <QString>
+
+class ClassB : public QObject
+{
+ Q_OBJECT
+public:
+ ClassB()
+ : m_member("Hello B")
+ {
+ }
+
+public slots:
+ void slotDoSomething();
+
+private:
+ QString m_member;
+};
+
+#endif
diff --git a/Tests/QtAutogen/ObjectLibrary/main.cpp b/Tests/QtAutogen/ObjectLibrary/main.cpp
new file mode 100644
index 0000000..cacf0fd
--- /dev/null
+++ b/Tests/QtAutogen/ObjectLibrary/main.cpp
@@ -0,0 +1,13 @@
+#include "a/classa.h"
+#include "b/classb.h"
+
+int main(int argc, char** argv)
+{
+ ClassA a;
+ a.slotDoSomething();
+
+ ClassB b;
+ b.slotDoSomething();
+
+ return 0;
+}
diff --git a/Tests/QtAutogen/Parallel/CMakeLists.txt b/Tests/QtAutogen/Parallel/CMakeLists.txt
new file mode 100644
index 0000000..299bcbf
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10)
+project(Parallel)
+include("../AutogenGuiTest.cmake")
+
+# Test different values for AUTOGEN_PARALLEL
+include("../Parallel/parallel.cmake")
+
+add_executable(parallel ${PARALLEL_SRC})
+set_target_properties(parallel PROPERTIES AUTOGEN_PARALLEL "")
+target_link_libraries(parallel ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/Parallel/aaa/bbb/data.qrc b/Tests/QtAutogen/Parallel/aaa/bbb/data.qrc
new file mode 100644
index 0000000..0ea3537
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/aaa/bbb/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="aaa/bbb">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Parallel/aaa/bbb/item.cpp b/Tests/QtAutogen/Parallel/aaa/bbb/item.cpp
new file mode 100644
index 0000000..850206f
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/aaa/bbb/item.cpp
@@ -0,0 +1,22 @@
+#include "item.hpp"
+
+namespace aaa {
+namespace bbb {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ MocLocal obj;
+}
+}
+}
+
+#include "aaa/bbb/item.moc"
diff --git a/Tests/QtAutogen/Parallel/aaa/bbb/item.hpp b/Tests/QtAutogen/Parallel/aaa/bbb/item.hpp
new file mode 100644
index 0000000..0855043
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/aaa/bbb/item.hpp
@@ -0,0 +1,18 @@
+#ifndef AAA_BBB_ITEM_HPP
+#define AAA_BBB_ITEM_HPP
+
+#include <QObject>
+
+namespace aaa {
+namespace bbb {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+}
+
+#endif
diff --git a/Tests/QtAutogen/Parallel/aaa/data.qrc b/Tests/QtAutogen/Parallel/aaa/data.qrc
new file mode 100644
index 0000000..379af60
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/aaa/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="aaa/">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Parallel/aaa/item.cpp b/Tests/QtAutogen/Parallel/aaa/item.cpp
new file mode 100644
index 0000000..e35d3d1
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/aaa/item.cpp
@@ -0,0 +1,22 @@
+#include "item.hpp"
+// Include ui_view.h only in header
+
+namespace aaa {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ Ui_ViewAAA ui;
+ MocLocal obj;
+}
+}
+
+#include "aaa/item.moc"
diff --git a/Tests/QtAutogen/Parallel/aaa/item.hpp b/Tests/QtAutogen/Parallel/aaa/item.hpp
new file mode 100644
index 0000000..875f72f
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/aaa/item.hpp
@@ -0,0 +1,18 @@
+#ifndef AAA_ITEM_HPP
+#define AAA_ITEM_HPP
+
+#include <QObject>
+// Include ui_view.h only in header
+#include <aaa/ui_view.h>
+
+namespace aaa {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+
+#endif
diff --git a/Tests/QtAutogen/Parallel/aaa/view.ui b/Tests/QtAutogen/Parallel/aaa/view.ui
new file mode 100644
index 0000000..0f09980
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/aaa/view.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ViewAAA</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/Parallel/bbb/aaa/data.qrc b/Tests/QtAutogen/Parallel/bbb/aaa/data.qrc
new file mode 100644
index 0000000..da98009
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/bbb/aaa/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="bbb/aaa/">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Parallel/bbb/aaa/item.cpp b/Tests/QtAutogen/Parallel/bbb/aaa/item.cpp
new file mode 100644
index 0000000..7ad01c3
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/bbb/aaa/item.cpp
@@ -0,0 +1,22 @@
+#include "item.hpp"
+
+namespace bbb {
+namespace aaa {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ MocLocal obj;
+}
+}
+}
+
+#include "bbb/aaa/item.moc"
diff --git a/Tests/QtAutogen/Parallel/bbb/aaa/item.hpp b/Tests/QtAutogen/Parallel/bbb/aaa/item.hpp
new file mode 100644
index 0000000..be07ca8
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/bbb/aaa/item.hpp
@@ -0,0 +1,18 @@
+#ifndef BBB_AAA_ITEM_HPP
+#define BBB_AAA_ITEM_HPP
+
+#include <QObject>
+
+namespace bbb {
+namespace aaa {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+}
+
+#endif
diff --git a/Tests/QtAutogen/Parallel/bbb/data.qrc b/Tests/QtAutogen/Parallel/bbb/data.qrc
new file mode 100644
index 0000000..5b080f5
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/bbb/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="bbb/">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Parallel/bbb/item.cpp b/Tests/QtAutogen/Parallel/bbb/item.cpp
new file mode 100644
index 0000000..9ef128e
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/bbb/item.cpp
@@ -0,0 +1,23 @@
+#include "item.hpp"
+// Include ui_view.h only in source
+#include <bbb/ui_view.h>
+
+namespace bbb {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ Ui_ViewBBB ui;
+ MocLocal obj;
+}
+}
+
+#include "bbb/item.moc"
diff --git a/Tests/QtAutogen/Parallel/bbb/item.hpp b/Tests/QtAutogen/Parallel/bbb/item.hpp
new file mode 100644
index 0000000..d39a9d7
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/bbb/item.hpp
@@ -0,0 +1,17 @@
+#ifndef BBB_ITEM_HPP
+#define BBB_ITEM_HPP
+
+#include <QObject>
+// Include ui_view.h only in source
+
+namespace bbb {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+
+#endif
diff --git a/Tests/QtAutogen/Parallel/bbb/view.ui b/Tests/QtAutogen/Parallel/bbb/view.ui
new file mode 100644
index 0000000..a8f506e
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/bbb/view.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ViewBBB</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/Parallel/ccc/data.qrc b/Tests/QtAutogen/Parallel/ccc/data.qrc
new file mode 100644
index 0000000..f934c39
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/ccc/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="ccc/">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Parallel/ccc/item.cpp b/Tests/QtAutogen/Parallel/ccc/item.cpp
new file mode 100644
index 0000000..ab8a281
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/ccc/item.cpp
@@ -0,0 +1,25 @@
+#include "item.hpp"
+// Include ui_view.h in source and header
+#include <ccc/ui_view.h>
+
+namespace ccc {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ Ui_ViewCCC ui;
+ MocLocal obj;
+}
+}
+
+// Include own moc files
+#include "ccc/item.moc"
+#include "moc_item.cpp"
diff --git a/Tests/QtAutogen/Parallel/ccc/item.hpp b/Tests/QtAutogen/Parallel/ccc/item.hpp
new file mode 100644
index 0000000..20d9dd9
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/ccc/item.hpp
@@ -0,0 +1,18 @@
+#ifndef CCC_ITEM_HPP
+#define CCC_ITEM_HPP
+
+#include <QObject>
+// Include ui_view.h in source and header
+#include <ccc/ui_view.h>
+
+namespace ccc {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+
+#endif
diff --git a/Tests/QtAutogen/Parallel/ccc/view.ui b/Tests/QtAutogen/Parallel/ccc/view.ui
new file mode 100644
index 0000000..7989c69
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/ccc/view.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ViewCCC</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/Parallel/data.qrc b/Tests/QtAutogen/Parallel/data.qrc
new file mode 100644
index 0000000..4ce0b4e
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/data.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>main.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/Parallel/item.cpp b/Tests/QtAutogen/Parallel/item.cpp
new file mode 100644
index 0000000..3d1fbe7
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/item.cpp
@@ -0,0 +1,20 @@
+#include "item.hpp"
+// Include ui_view.h in source and header
+#include <ui_view.h>
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ Ui_View ui;
+ MocLocal obj;
+}
+
+#include "item.moc"
diff --git a/Tests/QtAutogen/Parallel/item.hpp b/Tests/QtAutogen/Parallel/item.hpp
new file mode 100644
index 0000000..75e83f4
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/item.hpp
@@ -0,0 +1,15 @@
+#ifndef ITEM_HPP
+#define ITEM_HPP
+
+#include <QObject>
+// Include ui_view.h in source and header
+#include <ui_view.h>
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+
+#endif
diff --git a/Tests/QtAutogen/Parallel/main.cpp b/Tests/QtAutogen/Parallel/main.cpp
new file mode 100644
index 0000000..a4ffcb3
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/main.cpp
@@ -0,0 +1,16 @@
+#include "aaa/bbb/item.hpp"
+#include "aaa/item.hpp"
+#include "bbb/aaa/item.hpp"
+#include "bbb/item.hpp"
+#include "ccc/item.hpp"
+
+int main(int argv, char** args)
+{
+ // Object instances
+ ::aaa::Item aaa_item;
+ ::aaa::bbb::Item aaa_bbb_item;
+ ::bbb::Item bbb_item;
+ ::bbb::aaa::Item bbb_aaa_item;
+ ::ccc::Item ccc_item;
+ return 0;
+}
diff --git a/Tests/QtAutogen/Parallel/parallel.cmake b/Tests/QtAutogen/Parallel/parallel.cmake
new file mode 100644
index 0000000..551bcd8
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/parallel.cmake
@@ -0,0 +1,24 @@
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTORCC ON)
+
+
+set(PBASE ${CMAKE_CURRENT_LIST_DIR})
+set(PARALLEL_SRC
+ ${PBASE}/aaa/bbb/item.cpp
+ ${PBASE}/aaa/bbb/data.qrc
+ ${PBASE}/aaa/item.cpp
+ ${PBASE}/aaa/data.qrc
+
+ ${PBASE}/bbb/aaa/item.cpp
+ ${PBASE}/bbb/aaa/data.qrc
+ ${PBASE}/bbb/item.cpp
+ ${PBASE}/bbb/data.qrc
+
+ ${PBASE}/ccc/item.cpp
+ ${PBASE}/ccc/data.qrc
+
+ ${PBASE}/item.cpp
+ ${PBASE}/data.qrc
+ ${PBASE}/main.cpp
+)
diff --git a/Tests/QtAutogen/Parallel/view.ui b/Tests/QtAutogen/Parallel/view.ui
new file mode 100644
index 0000000..2ffe734
--- /dev/null
+++ b/Tests/QtAutogen/Parallel/view.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>View</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/Parallel1/CMakeLists.txt b/Tests/QtAutogen/Parallel1/CMakeLists.txt
new file mode 100644
index 0000000..5c7d547
--- /dev/null
+++ b/Tests/QtAutogen/Parallel1/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10)
+project(Parallel1)
+include("../AutogenGuiTest.cmake")
+
+# Test different values for AUTOGEN_PARALLEL
+include("../Parallel/parallel.cmake")
+
+add_executable(parallel1 ${PARALLEL_SRC})
+set_target_properties(parallel1 PROPERTIES AUTOGEN_PARALLEL 1)
+target_link_libraries(parallel1 ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/Parallel2/CMakeLists.txt b/Tests/QtAutogen/Parallel2/CMakeLists.txt
new file mode 100644
index 0000000..668aea4
--- /dev/null
+++ b/Tests/QtAutogen/Parallel2/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10)
+project(Parallel2)
+include("../AutogenGuiTest.cmake")
+
+# Test different values for AUTOGEN_PARALLEL
+include("../Parallel/parallel.cmake")
+
+add_executable(parallel2 ${PARALLEL_SRC})
+set_target_properties(parallel2 PROPERTIES AUTOGEN_PARALLEL 2)
+target_link_libraries(parallel2 ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/Parallel3/CMakeLists.txt b/Tests/QtAutogen/Parallel3/CMakeLists.txt
new file mode 100644
index 0000000..5c50f5e
--- /dev/null
+++ b/Tests/QtAutogen/Parallel3/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10)
+project(Parallel3)
+include("../AutogenGuiTest.cmake")
+
+# Test different values for AUTOGEN_PARALLEL
+include("../Parallel/parallel.cmake")
+
+add_executable(parallel3 ${PARALLEL_SRC})
+set_target_properties(parallel3 PROPERTIES AUTOGEN_PARALLEL 3)
+target_link_libraries(parallel3 ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/Parallel4/CMakeLists.txt b/Tests/QtAutogen/Parallel4/CMakeLists.txt
new file mode 100644
index 0000000..2c40c6a
--- /dev/null
+++ b/Tests/QtAutogen/Parallel4/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10)
+project(Parallel4)
+include("../AutogenGuiTest.cmake")
+
+# Test different values for AUTOGEN_PARALLEL
+include("../Parallel/parallel.cmake")
+
+add_executable(parallel4 ${PARALLEL_SRC})
+set_target_properties(parallel4 PROPERTIES AUTOGEN_PARALLEL 4)
+target_link_libraries(parallel4 ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/ParallelAUTO/CMakeLists.txt b/Tests/QtAutogen/ParallelAUTO/CMakeLists.txt
new file mode 100644
index 0000000..cddece3
--- /dev/null
+++ b/Tests/QtAutogen/ParallelAUTO/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10)
+project(ParallelAUTO)
+include("../AutogenGuiTest.cmake")
+
+# Test different values for AUTOGEN_PARALLEL
+include("../Parallel/parallel.cmake")
+
+add_executable(parallelAUTO ${PARALLEL_SRC})
+set_target_properties(parallelAUTO PROPERTIES AUTOGEN_PARALLEL "AUTO")
+target_link_libraries(parallelAUTO ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/RccEmpty/CMakeLists.txt b/Tests/QtAutogen/RccEmpty/CMakeLists.txt
new file mode 100644
index 0000000..a8e2af1
--- /dev/null
+++ b/Tests/QtAutogen/RccEmpty/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.10)
+project(RccEmpty)
+include("../AutogenCoreTest.cmake")
+
+# Test AUTORCC on a .qrc file with no resource files
+add_executable(rccEmpty rccEmpty.cpp rccEmptyRes.qrc)
+set_property(TARGET rccEmpty PROPERTY AUTORCC ON)
+target_link_libraries(rccEmpty ${QT_QTCORE_TARGET})
diff --git a/Tests/QtAutogen/RccEmpty/rccEmpty.cpp b/Tests/QtAutogen/RccEmpty/rccEmpty.cpp
new file mode 100644
index 0000000..7f2c527
--- /dev/null
+++ b/Tests/QtAutogen/RccEmpty/rccEmpty.cpp
@@ -0,0 +1,9 @@
+
+extern int qInitResources_rccEmptyRes();
+
+int main(int, char**)
+{
+ // Fails to link if the symbol is not present.
+ qInitResources_rccEmptyRes();
+ return 0;
+}
diff --git a/Tests/QtAutogen/RccEmpty/rccEmptyRes.qrc b/Tests/QtAutogen/RccEmpty/rccEmptyRes.qrc
new file mode 100644
index 0000000..4ca9cd5
--- /dev/null
+++ b/Tests/QtAutogen/RccEmpty/rccEmptyRes.qrc
@@ -0,0 +1,4 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/RccOffMocLibrary/CMakeLists.txt b/Tests/QtAutogen/RccOffMocLibrary/CMakeLists.txt
new file mode 100644
index 0000000..61b9601
--- /dev/null
+++ b/Tests/QtAutogen/RccOffMocLibrary/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.10)
+project(RccOffMocLibrary)
+include("../AutogenCoreTest.cmake")
+
+# Add not_generated_file.qrc to the source list to get the file-level
+# dependency, but don't generate a c++ file from it. Disable the AUTORCC
+# feature for this target. This tests that qrc files in the sources don't
+# have an effect on generation if AUTORCC is off.
+add_library(empty STATIC empty.cpp not_generated_file.qrc)
+set_target_properties(empty PROPERTIES AUTORCC OFF)
+set_target_properties(empty PROPERTIES AUTOMOC TRUE)
+target_link_libraries(empty no_link_language)
+add_library(no_link_language STATIC empty.h)
+set_target_properties(no_link_language PROPERTIES AUTOMOC TRUE)
+# Pass Qt compiler features to targets that don't link against Qt
+target_compile_features(no_link_language PRIVATE ${QT_COMPILE_FEATURES})
+target_compile_features(empty PRIVATE ${QT_COMPILE_FEATURES})
diff --git a/Tests/QtAutogen/RccOffMocLibrary/empty.cpp b/Tests/QtAutogen/RccOffMocLibrary/empty.cpp
new file mode 100644
index 0000000..ab32cf6
--- /dev/null
+++ b/Tests/QtAutogen/RccOffMocLibrary/empty.cpp
@@ -0,0 +1 @@
+// No content
diff --git a/Tests/QtAutogen/RccOffMocLibrary/empty.h b/Tests/QtAutogen/RccOffMocLibrary/empty.h
new file mode 100644
index 0000000..6bdd2ac
--- /dev/null
+++ b/Tests/QtAutogen/RccOffMocLibrary/empty.h
@@ -0,0 +1,9 @@
+
+#include <QObject>
+
+class Empty : public QObject
+{
+ Q_OBJECT
+public:
+ explicit Empty(QObject* parent = 0) {}
+};
diff --git a/Tests/QtAutogen/RccOffMocLibrary/not_generated_file.qrc b/Tests/QtAutogen/RccOffMocLibrary/not_generated_file.qrc
new file mode 100644
index 0000000..c769834
--- /dev/null
+++ b/Tests/QtAutogen/RccOffMocLibrary/not_generated_file.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>abc.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/RccOnly/CMakeLists.txt b/Tests/QtAutogen/RccOnly/CMakeLists.txt
new file mode 100644
index 0000000..f3776f5
--- /dev/null
+++ b/Tests/QtAutogen/RccOnly/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.10)
+project(RccOnly)
+include("../AutogenCoreTest.cmake")
+
+# Test AUTORCC being enabled only
+add_executable(rccOnly rccOnly.cpp rccOnlyRes.qrc)
+set_property(TARGET rccOnly PROPERTY AUTORCC ON)
+target_link_libraries(rccOnly ${QT_QTCORE_TARGET})
diff --git a/Tests/QtAutogen/RccOnly/rccOnly.cpp b/Tests/QtAutogen/RccOnly/rccOnly.cpp
new file mode 100644
index 0000000..61c7bf4
--- /dev/null
+++ b/Tests/QtAutogen/RccOnly/rccOnly.cpp
@@ -0,0 +1,9 @@
+
+extern int qInitResources_rccOnlyRes();
+
+int main(int, char**)
+{
+ // Fails to link if the symbol is not present.
+ qInitResources_rccOnlyRes();
+ return 0;
+}
diff --git a/Tests/QtAutogen/RccOnly/rccOnlyRes.qrc b/Tests/QtAutogen/RccOnly/rccOnlyRes.qrc
new file mode 100644
index 0000000..5551348
--- /dev/null
+++ b/Tests/QtAutogen/RccOnly/rccOnlyRes.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>rccOnly.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/RccSkipSource/CMakeLists.txt b/Tests/QtAutogen/RccSkipSource/CMakeLists.txt
new file mode 100644
index 0000000..4223274
--- /dev/null
+++ b/Tests/QtAutogen/RccSkipSource/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 3.10)
+project(RccSkipSource)
+include("../AutogenCoreTest.cmake")
+
+# Test for SKIP_AUTORCC and SKIP_AUTOGEN on an AUTORCC enabled target
+set(skipRccSources
+ skipRcc.cpp
+ skipRccBad1.qrc
+ skipRccBad2.qrc
+ skipRccGood.qrc
+)
+set_property(SOURCE skipRccBad1.qrc PROPERTY SKIP_AUTORCC ON)
+set_property(SOURCE skipRccBad2.qrc PROPERTY SKIP_AUTOGEN ON)
+# AUTORCC enabled
+add_executable(skipRccA ${skipRccSources})
+set_property(TARGET skipRccA PROPERTY AUTORCC ON)
+target_link_libraries(skipRccA ${QT_LIBRARIES})
+# AUTORCC, AUTOUIC and AUTOMOC enabled
+add_executable(skipRccB ${skipRccSources})
+set_property(TARGET skipRccB PROPERTY AUTORCC ON)
+set_property(TARGET skipRccB PROPERTY AUTOUIC ON)
+set_property(TARGET skipRccB PROPERTY AUTOMOC ON)
+target_link_libraries(skipRccB ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/RccSkipSource/skipRcc.cpp b/Tests/QtAutogen/RccSkipSource/skipRcc.cpp
new file mode 100644
index 0000000..ec57110
--- /dev/null
+++ b/Tests/QtAutogen/RccSkipSource/skipRcc.cpp
@@ -0,0 +1,9 @@
+
+extern int qInitResources_skipRccGood();
+
+int main(int, char**)
+{
+ // Fails to link if the symbol is not present.
+ qInitResources_skipRccGood();
+ return 0;
+}
diff --git a/Tests/QtAutogen/RccSkipSource/skipRccBad1.qrc b/Tests/QtAutogen/RccSkipSource/skipRccBad1.qrc
new file mode 100644
index 0000000..6cbd9ed
--- /dev/null
+++ b/Tests/QtAutogen/RccSkipSource/skipRccBad1.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>skipRccGood.cpp</file>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/RccSkipSource/skipRccBad2.qrc b/Tests/QtAutogen/RccSkipSource/skipRccBad2.qrc
new file mode 100644
index 0000000..b32c589
--- /dev/null
+++ b/Tests/QtAutogen/RccSkipSource/skipRccBad2.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><
+<qresource>
+ <file>skipRccGood.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/RccSkipSource/skipRccGood.qrc b/Tests/QtAutogen/RccSkipSource/skipRccGood.qrc
new file mode 100644
index 0000000..21a94b0
--- /dev/null
+++ b/Tests/QtAutogen/RccSkipSource/skipRccGood.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>skipRccBad1.qrc</file>
+ <file>skipRccBad2.qrc</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt b/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt
new file mode 100644
index 0000000..c53e857
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt
@@ -0,0 +1,161 @@
+cmake_minimum_required(VERSION 3.10)
+project(RerunMocBasic)
+include("../AutogenCoreTest.cmake")
+
+# Dummy executable to generate a clean target
+add_executable(dummy dummy.cpp)
+
+# Utility variables
+set(timeformat "%Y.%j.%H.%M%S")
+set(mocBasicSrcDir "${CMAKE_CURRENT_SOURCE_DIR}/MocBasic")
+set(mocBasicBinDir "${CMAKE_CURRENT_BINARY_DIR}/MocBasic")
+
+# Utility macros
+macro(sleep)
+ message(STATUS "Sleeping for a few seconds.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+endmacro()
+
+macro(acquire_timestamp When)
+ file(TIMESTAMP "${mocBasicBin}" time${When} "${timeformat}")
+endmacro()
+
+macro(rebuild buildName)
+ message(STATUS "Starting build ${buildName}.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocBasicBinDir}" RESULT_VARIABLE result)
+ if (result)
+ message(FATAL_ERROR "Build ${buildName} failed.")
+ else()
+ message(STATUS "Build ${buildName} finished.")
+ endif()
+endmacro()
+
+macro(require_change)
+ if (timeAfter VERSION_GREATER timeBefore)
+ message(STATUS "As expected the file ${mocBasicBin} changed.")
+ else()
+ message(SEND_ERROR "Unexpectedly the file ${mocBasicBin} did not change!\nTimestamp pre: ${timeBefore}\nTimestamp aft: ${timeAfter}\n")
+ endif()
+endmacro()
+
+macro(require_change_not)
+ if (timeAfter VERSION_GREATER timeBefore)
+ message(SEND_ERROR "Unexpectedly the file ${mocBasicBin} changed!\nTimestamp pre: ${timeBefore}\nTimestamp aft: ${timeAfter}\n")
+ else()
+ message(STATUS "As expected the file ${mocBasicBin} did not change.")
+ endif()
+endmacro()
+
+
+# Configure the test project
+configure_file("${mocBasicSrcDir}/test1a.h.in" "${mocBasicBinDir}/test1.h" COPYONLY)
+configure_file("${mocBasicSrcDir}/myobject3a.h.in" "${mocBasicBinDir}/myobject3.h" @ONLY)
+if(CMAKE_GENERATOR_INSTANCE)
+ set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE=${CMAKE_GENERATOR_INSTANCE}")
+else()
+ set(_D_CMAKE_GENERATOR_INSTANCE "")
+endif()
+execute_process(
+ COMMAND "${CMAKE_COMMAND}" -B "${mocBasicBinDir}" -S "${mocBasicSrcDir}"
+ -G "${CMAKE_GENERATOR}"
+ -A "${CMAKE_GENERATOR_PLATFORM}"
+ -T "${CMAKE_GENERATOR_TOOLSET}"
+ ${_D_CMAKE_GENERATOR_INSTANCE}
+ "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
+ "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+ "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+ RESULT_VARIABLE exit_code
+ OUTPUT_VARIABLE output
+)
+if(NOT exit_code EQUAL 0)
+ message(FATAL_ERROR "Initial configuration of mocBasic failed. Output: ${output}")
+endif()
+
+# Initial build
+execute_process(
+ COMMAND "${CMAKE_COMMAND}" --build "${mocBasicBinDir}"
+ RESULT_VARIABLE exit_code
+ OUTPUT_VARIABLE output
+)
+if(NOT exit_code EQUAL 0)
+ message(FATAL_ERROR "Initial build of mocBasic failed. Output: ${output}")
+endif()
+
+# Get name of the output binary
+file(STRINGS "${mocBasicBinDir}/mocBasic.txt" mocBasicList ENCODING UTF-8)
+list(GET mocBasicList 0 mocBasicBin)
+
+# To avoid a race condition where the binary has the same timestamp
+# as a source file and therefore gets rebuild
+# - sleep to ensure a timestamp change
+# - touch binary to ensure it has a new timestamp
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Touching binary file to ensure a new timestamps")
+file(TOUCH_NOCREATE "${mocBasicBin}")
+acquire_timestamp(After)
+require_change()
+
+
+# - Ensure that the timestamp will change
+# - Change header file content
+# - Rebuild
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Changing the header content for a MOC re-run")
+configure_file("${mocBasicSrcDir}/test1b.h.in" "${mocBasicBinDir}/test1.h" COPYONLY)
+sleep()
+rebuild(2)
+acquire_timestamp(After)
+require_change()
+
+
+# - Ensure that the timestamp would change
+# - Change nothing
+# - Rebuild
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Changing nothing for no MOC re-run")
+rebuild(3)
+acquire_timestamp(After)
+require_change_not()
+
+
+# - Ensure that the timestamp will change
+# - Remove Q_OBJECT from header
+# - Rebuild
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Remove Q_OBJECT from header file for a MOC re-run")
+configure_file("${mocBasicSrcDir}/test1c.h.in" "${mocBasicBinDir}/test1.h" COPYONLY)
+sleep()
+rebuild(4)
+acquire_timestamp(After)
+require_change()
+
+
+# - Ensure that the timestamp will change
+# - Add Q_OBJECT to header again
+# - Rebuild
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Add Q_OBJECT to test1.h for a MOC re-run")
+configure_file("${mocBasicSrcDir}/test1a.h.in" "${mocBasicBinDir}/test1.h" COPYONLY)
+sleep()
+rebuild(5)
+acquire_timestamp(After)
+require_change()
+
+
+# - Ensure that the timestamp will change
+# - Add Q_OBJECT to MyObject3
+# - Rebuild
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Add Q_OBJECT to myobject3.h file for a MOC re-run")
+set(CLASS_CONTENT "Q_OBJECT")
+configure_file("${mocBasicSrcDir}/myobject3a.h.in" "${mocBasicBinDir}/myobject3.h" @ONLY)
+sleep()
+rebuild(6)
+acquire_timestamp(After)
+require_change()
diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/CMakeLists.txt b/Tests/QtAutogen/RerunMocBasic/MocBasic/CMakeLists.txt
new file mode 100644
index 0000000..42f2f57
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.10)
+project(MocBasic)
+include("../../AutogenCoreTest.cmake")
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+
+# Generated source file
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
+ COMMAND ${CMAKE_COMMAND} -E sleep 2
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
+)
+
+add_executable(mocBasic
+ ${CMAKE_CURRENT_BINARY_DIR}/test1.h
+ ${CMAKE_CURRENT_BINARY_DIR}/myobject3.h
+ ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
+ plainobject.cpp
+ res1.qrc
+)
+target_include_directories(mocBasic PRIVATE
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+)
+target_link_libraries(mocBasic ${QT_QTCORE_TARGET})
+# Write target name to text file
+add_custom_command(TARGET mocBasic POST_BUILD COMMAND
+ ${CMAKE_COMMAND} -E echo "$<TARGET_FILE:mocBasic>" > mocBasic.txt
+)
diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/input.txt b/Tests/QtAutogen/RerunMocBasic/MocBasic/input.txt
new file mode 100644
index 0000000..da62762
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/input.txt
@@ -0,0 +1 @@
+Res1 input.
diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/main.cpp.in b/Tests/QtAutogen/RerunMocBasic/MocBasic/main.cpp.in
new file mode 100644
index 0000000..5accfd6
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/main.cpp.in
@@ -0,0 +1,25 @@
+#include "test1.h"
+#include "plainobject.h"
+
+extern int qInitResources_res1();
+
+class Test2 : public QObject
+{
+ Q_OBJECT
+public slots:
+ void onTst1() {}
+};
+
+int main()
+{
+ // Fails to link if the rcc generated symbol is not present.
+ qInitResources_res1();
+
+ Test1 test1;
+ Test2 test2;
+ PlainObject plainObject;
+
+ return 0;
+}
+
+#include "main.moc"
diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/myobject3a.h.in b/Tests/QtAutogen/RerunMocBasic/MocBasic/myobject3a.h.in
new file mode 100644
index 0000000..d62c314
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/myobject3a.h.in
@@ -0,0 +1,13 @@
+#ifndef MYOBJECT3_H
+#define MYOBJECT3_H
+
+#include <qobject.h>
+
+class MyObject3 : public QObject
+{
+ @CLASS_CONTENT@
+public:
+ MyObject3() {}
+};
+
+#endif
diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.cpp b/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.cpp
new file mode 100644
index 0000000..0ca785e
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.cpp
@@ -0,0 +1,12 @@
+#include "plainobject.h"
+
+#include "myobject3.h"
+
+PlainObject::PlainObject()
+{
+}
+
+void PlainObject::doSomething()
+{
+ MyObject3 obj3;
+}
diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.h b/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.h
new file mode 100644
index 0000000..8037858
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.h
@@ -0,0 +1,12 @@
+#ifndef PLAINOBJECT_H
+#define PLAINOBJECT_H
+
+// Class that is plain C++, no Qt involved.
+class PlainObject
+{
+public:
+ PlainObject();
+ void doSomething();
+};
+
+#endif
diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/res1.qrc b/Tests/QtAutogen/RerunMocBasic/MocBasic/res1.qrc
new file mode 100644
index 0000000..fb804b5
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/res1.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>input.txt</file>
+ </qresource>
+</RCC>
diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/test1a.h.in b/Tests/QtAutogen/RerunMocBasic/MocBasic/test1a.h.in
new file mode 100644
index 0000000..a335046
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/test1a.h.in
@@ -0,0 +1,8 @@
+#include <QObject>
+class Test1 : public QObject
+{
+ Q_OBJECT
+public slots:
+ void onTst1() {}
+ void onTst2() {}
+};
diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/test1b.h.in b/Tests/QtAutogen/RerunMocBasic/MocBasic/test1b.h.in
new file mode 100644
index 0000000..6128eeb
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/test1b.h.in
@@ -0,0 +1,7 @@
+#include <QObject>
+class Test1 : public QObject
+{
+ Q_OBJECT
+public slots:
+ void onTst1() {}
+};
diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/test1c.h.in b/Tests/QtAutogen/RerunMocBasic/MocBasic/test1c.h.in
new file mode 100644
index 0000000..d0b9868
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/test1c.h.in
@@ -0,0 +1,6 @@
+#include <QObject>
+class Test1
+{
+public:
+ void onTst1() {}
+};
diff --git a/Tests/QtAutogen/RerunMocBasic/dummy.cpp b/Tests/QtAutogen/RerunMocBasic/dummy.cpp
new file mode 100644
index 0000000..4837a76
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocBasic/dummy.cpp
@@ -0,0 +1,5 @@
+
+int main(int argv, char** args)
+{
+ return 0;
+}
diff --git a/Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt b/Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt
new file mode 100644
index 0000000..2677659
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt
@@ -0,0 +1,96 @@
+# This test checks whether adding a source file to the project triggers an AUTOMOC re-run.
+
+cmake_minimum_required(VERSION 3.10)
+project(RerunMocOnAddFile)
+include("../AutogenCoreTest.cmake")
+
+# Create an executable to generate a clean target
+set(main_source "${CMAKE_CURRENT_BINARY_DIR}/generated_main.cpp")
+file(WRITE "${main_source}" "int main() {}")
+add_executable(exe "${main_source}")
+
+# Utility variables
+set(timeformat "%Y.%j.%H.%M%S")
+set(testProjectTemplateDir "${CMAKE_CURRENT_SOURCE_DIR}/MocOnAddFile")
+set(testProjectSrc "${CMAKE_CURRENT_BINARY_DIR}/MocOnAddFile")
+set(testProjectBinDir "${CMAKE_CURRENT_BINARY_DIR}/MocOnAddFile-build")
+
+# Utility macros
+macro(sleep)
+ message(STATUS "Sleeping for a few seconds.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+endmacro()
+
+macro(acquire_timestamp When)
+ file(TIMESTAMP "${mocBasicBin}" time${When} "${timeformat}")
+endmacro()
+
+macro(rebuild buildName)
+ message(STATUS "Starting build ${buildName}.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${testProjectBinDir}" RESULT_VARIABLE result)
+ if (result)
+ message(FATAL_ERROR "Build ${buildName} failed.")
+ else()
+ message(STATUS "Build ${buildName} finished.")
+ endif()
+endmacro()
+
+macro(require_change)
+ if (timeAfter VERSION_GREATER timeBefore)
+ message(STATUS "As expected the file ${mocBasicBin} changed.")
+ else()
+ message(SEND_ERROR "Unexpectedly the file ${mocBasicBin} did not change!\nTimestamp pre: ${timeBefore}\nTimestamp aft: ${timeAfter}\n")
+ endif()
+endmacro()
+
+macro(require_change_not)
+ if (timeAfter VERSION_GREATER timeBefore)
+ message(SEND_ERROR "Unexpectedly the file ${mocBasicBin} changed!\nTimestamp pre: ${timeBefore}\nTimestamp aft: ${timeAfter}\n")
+ else()
+ message(STATUS "As expected the file ${mocBasicBin} did not change.")
+ endif()
+endmacro()
+
+# Create the test project from the template
+unset(additional_project_sources)
+unset(main_cpp_includes)
+configure_file("${testProjectTemplateDir}/CMakeLists.txt.in" "${testProjectSrc}/CMakeLists.txt")
+configure_file("${testProjectTemplateDir}/main.cpp.in" "${testProjectSrc}/main.cpp")
+
+# Initial build
+try_compile(MOC_RERUN
+ "${testProjectBinDir}"
+ "${testProjectSrc}"
+ MocOnAddFile
+ CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
+ "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+ "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+ OUTPUT_VARIABLE output
+)
+if (NOT MOC_RERUN)
+ message(FATAL_ERROR "Initial build of mocOnAddFile failed. Output: ${output}")
+endif()
+
+# Sleep to ensure new timestamps
+sleep()
+
+# Add a QObject class (defined in header) to the project and build
+set(additional_project_sources myobject.cpp)
+set(main_cpp_includes "#include \"myobject.h\"")
+configure_file("${testProjectTemplateDir}/CMakeLists.txt.in" "${testProjectSrc}/CMakeLists.txt"
+ @ONLY)
+configure_file("${testProjectTemplateDir}/main.cpp.in" "${testProjectSrc}/main.cpp" @ONLY)
+configure_file("${testProjectTemplateDir}/myobject.h" "${testProjectSrc}/myobject.h" COPYONLY)
+configure_file("${testProjectTemplateDir}/myobject.cpp" "${testProjectSrc}/myobject.cpp" COPYONLY)
+rebuild(2)
+
+# Sleep to ensure new timestamps
+sleep()
+
+# Add a QObject class (defined in source) to the project and build
+set(additional_project_sources myobject.cpp anotherobject.cpp)
+configure_file("${testProjectTemplateDir}/CMakeLists.txt.in" "${testProjectSrc}/CMakeLists.txt"
+ @ONLY)
+configure_file("${testProjectTemplateDir}/anotherobject.cpp" "${testProjectSrc}/anotherobject.cpp"
+ COPYONLY)
+rebuild(3)
diff --git a/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/CMakeLists.txt.in b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/CMakeLists.txt.in
new file mode 100644
index 0000000..9e5e21c
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/CMakeLists.txt.in
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.10)
+project(MocOnAddFile)
+include("@CMAKE_CURRENT_LIST_DIR@/../AutogenCoreTest.cmake")
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+
+add_executable(mocOnAddFile main.cpp @additional_project_sources@)
+target_link_libraries(mocOnAddFile ${QT_QTCORE_TARGET})
diff --git a/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/anotherobject.cpp b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/anotherobject.cpp
new file mode 100644
index 0000000..45c5af6
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/anotherobject.cpp
@@ -0,0 +1,15 @@
+#include <qobject.h>
+
+class AnotherObject : public QObject
+{
+ Q_OBJECT
+public:
+ AnotherObject() {}
+};
+
+AnotherObject* createAnotherObject()
+{
+ return new AnotherObject();
+}
+
+#include "anotherobject.moc"
diff --git a/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/main.cpp.in b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/main.cpp.in
new file mode 100644
index 0000000..f62027a
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/main.cpp.in
@@ -0,0 +1,6 @@
+@main_cpp_includes@
+
+int main(int argc, char *argv[])
+{
+ return 0;
+}
diff --git a/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.cpp b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.cpp
new file mode 100644
index 0000000..7a15300
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.cpp
@@ -0,0 +1,6 @@
+#include "myobject.h"
+
+MyObject::MyObject(QObject* parent)
+ : QObject(parent)
+{
+}
diff --git a/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.h b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.h
new file mode 100644
index 0000000..e373ee8
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.h
@@ -0,0 +1,13 @@
+#ifndef MYOBJECT_H
+#define MYOBJECT_H
+
+#include <qobject.h>
+
+class MyObject : public QObject
+{
+ Q_OBJECT
+public:
+ MyObject(QObject* parent = 0);
+};
+
+#endif
diff --git a/Tests/QtAutogen/RerunMocOnMissingDependency/CMakeLists.txt b/Tests/QtAutogen/RerunMocOnMissingDependency/CMakeLists.txt
new file mode 100644
index 0000000..c5811eb
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocOnMissingDependency/CMakeLists.txt
@@ -0,0 +1,80 @@
+# This test checks whether a missing dependency of the moc output triggers an AUTOMOC re-run.
+
+cmake_minimum_required(VERSION 3.10)
+project(RerunMocOnMissingDependency)
+include("../AutogenCoreTest.cmake")
+
+# Create an executable to generate a clean target
+set(main_source "${CMAKE_CURRENT_BINARY_DIR}/generated_main.cpp")
+file(WRITE "${main_source}" "int main() {}")
+add_executable(exe "${main_source}")
+
+# Utility variables
+set(testProjectTemplateDir "${CMAKE_CURRENT_SOURCE_DIR}/MocOnMissingDependency")
+set(testProjectSrc "${CMAKE_CURRENT_BINARY_DIR}/MocOnMissingDependency")
+set(testProjectBinDir "${CMAKE_CURRENT_BINARY_DIR}/MocOnMissingDependency-build")
+if(DEFINED Qt5Core_VERSION AND Qt5Core_VERSION VERSION_GREATER_EQUAL "5.15.0")
+ set(moc_depfiles_supported TRUE)
+else()
+ set(moc_depfiles_supported FALSE)
+endif()
+
+# Utility macros
+macro(sleep)
+ message(STATUS "Sleeping for a few seconds.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+endmacro()
+
+macro(rebuild buildName)
+ message(STATUS "Starting build ${buildName}.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${testProjectBinDir}"
+ RESULT_VARIABLE result OUTPUT_VARIABLE output)
+ if (result)
+ message(FATAL_ERROR "Build ${buildName} failed.")
+ else()
+ message(STATUS "Build ${buildName} finished.")
+ endif()
+endmacro()
+
+# Create the test project from the template
+file(COPY "${testProjectTemplateDir}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
+configure_file("${testProjectTemplateDir}/CMakeLists.txt.in" "${testProjectSrc}/CMakeLists.txt" @ONLY)
+
+# Initial build
+file(REMOVE_RECURSE "${testProjectBinDir}")
+try_compile(MOC_RERUN
+ "${testProjectBinDir}"
+ "${testProjectSrc}"
+ MocOnMissingDependency
+ CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
+ "-DCMAKE_AUTOGEN_VERBOSE=ON"
+ "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+ OUTPUT_VARIABLE output
+)
+if (NOT MOC_RERUN)
+ message(FATAL_ERROR "Initial build of mocOnMissingDependency failed. Output: ${output}")
+endif()
+
+# Sleep to ensure new timestamps
+sleep()
+
+if(moc_depfiles_supported)
+ # Remove the dependency inc1/foo.h and build again.
+ # We expect that the moc_XXX.cpp file gets re-generated. But only if we have depfile support.
+ file(REMOVE_RECURSE "${testProjectSrc}/inc1")
+ rebuild(2)
+ if(NOT output MATCHES "AutoMoc: Generating \"[^\"]*moc_myobject.cpp\"")
+ message(FATAL_ERROR "moc_myobject.cpp was not re-generated "
+ "after removing one of its dependencies")
+ endif()
+endif()
+
+# Sleep to ensure new timestamps
+sleep()
+
+# The next build should *not* re-renerate any moc outputs
+rebuild(3)
+if(output MATCHES "AutoMoc: Generating")
+ message(FATAL_ERROR "moc_myobject.cpp was not re-generated "
+ "after removing one of its dependencies")
+endif()
diff --git a/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/CMakeLists.txt.in b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/CMakeLists.txt.in
new file mode 100644
index 0000000..2155f45
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/CMakeLists.txt.in
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.18)
+project(MocOnMissingDependency)
+include("@CMAKE_CURRENT_LIST_DIR@/../AutogenCoreTest.cmake")
+set(CMAKE_AUTOMOC ON)
+add_executable(MocOnMissingDependency main.cpp myobject.cpp)
+target_include_directories(MocOnMissingDependency PRIVATE inc1 inc2)
+target_link_libraries(MocOnMissingDependency PRIVATE ${QT_QTCORE_TARGET})
diff --git a/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/inc1/foo.h b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/inc1/foo.h
new file mode 100644
index 0000000..cd8b2f9
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/inc1/foo.h
@@ -0,0 +1,2 @@
+
+#include <qobject.h>
diff --git a/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/inc2/foo.h b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/inc2/foo.h
new file mode 100644
index 0000000..cd8b2f9
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/inc2/foo.h
@@ -0,0 +1,2 @@
+
+#include <qobject.h>
diff --git a/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/main.cpp b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/main.cpp
new file mode 100644
index 0000000..36d51fa
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/main.cpp
@@ -0,0 +1,9 @@
+#include <iostream>
+
+#include "myobject.h"
+
+int main(int argc, char* argv[])
+{
+ MyObject obj;
+ return 0;
+}
diff --git a/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/myobject.cpp b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/myobject.cpp
new file mode 100644
index 0000000..7a15300
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/myobject.cpp
@@ -0,0 +1,6 @@
+#include "myobject.h"
+
+MyObject::MyObject(QObject* parent)
+ : QObject(parent)
+{
+}
diff --git a/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/myobject.h b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/myobject.h
new file mode 100644
index 0000000..25176cc
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/myobject.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <foo.h>
+
+class MyObject : public QObject
+{
+ Q_OBJECT
+public:
+ MyObject(QObject* parent = 0);
+};
diff --git a/Tests/QtAutogen/RerunMocPlugin/CMakeLists.txt b/Tests/QtAutogen/RerunMocPlugin/CMakeLists.txt
new file mode 100644
index 0000000..a7fb2d7
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/CMakeLists.txt
@@ -0,0 +1,134 @@
+cmake_minimum_required(VERSION 3.10)
+project(RerunMocPlugin)
+include("../AutogenCoreTest.cmake")
+
+# Tests Q_PLUGIN_METADATA and CMAKE_AUTOMOC_DEPEND_FILTERS
+# json file change detection
+
+# Dummy executable to generate a clean target
+add_executable(dummy dummy.cpp)
+
+# Utility variables
+set(timeformat "%Y.%j.%H.%M%S")
+set(mocPlugSrcDir "${CMAKE_CURRENT_SOURCE_DIR}/MocPlugin")
+set(mocPlugBinDir "${CMAKE_CURRENT_BINARY_DIR}/MocPlugin")
+
+# Utility macros
+macro(sleep)
+ message(STATUS "Sleeping for a few seconds.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+endmacro()
+
+macro(rebuild buildName)
+ message(STATUS "Starting build ${buildName}.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocPlugBinDir}" RESULT_VARIABLE result)
+ if (result)
+ message(FATAL_ERROR "Build ${buildName} failed.")
+ else()
+ message(STATUS "Build ${buildName} finished.")
+ endif()
+endmacro()
+
+macro(require_change PLG)
+ if (pl${PLG}After VERSION_GREATER pl${PLG}Before)
+ message(STATUS "As expected the file ${pl${PLG}File} changed.")
+ else()
+ message(SEND_ERROR
+ "Unexpectedly the file ${pl${PLG}File} did not change!\nTimestamp pre: ${pl${PLG}Before}\nTimestamp aft: ${pl${PLG}After}\n")
+ endif()
+endmacro()
+
+macro(require_change_not PLG)
+ if (pl${PLG}After VERSION_GREATER pl${PLG}Before)
+ message(SEND_ERROR
+ "Unexpectedly the file ${pl${PLG}File} changed!\nTimestamp pre: ${pl${PLG}Before}\nTimestamp aft: ${pl${PLG}After}\n")
+ else()
+ message(STATUS "As expected the file ${pl${PLG}File} did not change.")
+ endif()
+endmacro()
+
+macro(acquire_timestamps When)
+ file(TIMESTAMP "${plAFile}" plA${When} "${timeformat}")
+ file(TIMESTAMP "${plBFile}" plB${When} "${timeformat}")
+ file(TIMESTAMP "${plCFile}" plC${When} "${timeformat}")
+ file(TIMESTAMP "${plDFile}" plD${When} "${timeformat}")
+ file(TIMESTAMP "${plEFile}" plE${When} "${timeformat}")
+endmacro()
+
+
+# Initial build
+try_compile(MOC_PLUGIN
+ "${mocPlugBinDir}"
+ "${mocPlugSrcDir}"
+ MocPlugin
+ CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
+ "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+ "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+ OUTPUT_VARIABLE output
+)
+if (NOT MOC_PLUGIN)
+ message(FATAL_ERROR "Initial build of mocPlugin failed. Output: ${output}")
+endif()
+
+# Get names of the output binaries
+find_library(plAFile "PlugA" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
+find_library(plBFile "PlugB" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
+find_library(plCFile "PlugC" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
+find_library(plDFile "PlugD" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
+find_library(plEFile "PlugE" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH)
+
+# To avoid a race condition where the library has the same timestamp
+# as a source file and therefore gets rebuild
+# - sleep to ensure a timestamp change
+# - rebuild library to ensure it has a new timestamp
+sleep()
+message(STATUS "Rebuilding library files to ensure new timestamps")
+rebuild(1)
+
+
+# - Ensure that the timestamp will change.
+# - Change the json files referenced by Q_PLUGIN_METADATA
+# - Rebuild
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing json files.")
+configure_file("${mocPlugSrcDir}/jsonIn/StyleD.json" "${mocPlugBinDir}/jsonFiles/StyleC.json")
+configure_file("${mocPlugSrcDir}/jsonIn/StyleE.json" "${mocPlugBinDir}/jsonFiles/sub/StyleD.json")
+configure_file("${mocPlugSrcDir}/jsonIn/StyleC.json" "${mocPlugBinDir}/jsonFiles/StyleE.json")
+sleep()
+rebuild(2)
+acquire_timestamps(After)
+# Test changes
+require_change_not(A)
+require_change_not(B)
+require_change(C)
+require_change(D)
+# There's a bug in Ninja on Windows:
+# https://gitlab.kitware.com/cmake/cmake/-/issues/16776
+if(NOT ("${CMAKE_GENERATOR}" MATCHES "Ninja"))
+ require_change(E)
+endif()
+
+
+# - Ensure that the timestamp will change.
+# - Change the json files referenced by A_CUSTOM_MACRO
+# - Rebuild
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing json files")
+configure_file("${mocPlugSrcDir}/jsonIn/StyleE.json" "${mocPlugBinDir}/jsonFiles/StyleC_Custom.json")
+configure_file("${mocPlugSrcDir}/jsonIn/StyleC.json" "${mocPlugBinDir}/jsonFiles/sub/StyleD_Custom.json")
+configure_file("${mocPlugSrcDir}/jsonIn/StyleD.json" "${mocPlugBinDir}/jsonFiles/StyleE_Custom.json")
+sleep()
+rebuild(3)
+acquire_timestamps(After)
+# Test changes
+require_change_not(A)
+require_change_not(B)
+require_change(C)
+require_change(D)
+# There's a bug in Ninja on Windows
+# https://gitlab.kitware.com/cmake/cmake/-/issues/16776
+if(NOT ("${CMAKE_GENERATOR}" MATCHES "Ninja"))
+ require_change(E)
+endif()
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/CMakeLists.txt b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/CMakeLists.txt
new file mode 100644
index 0000000..5068289
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/CMakeLists.txt
@@ -0,0 +1,31 @@
+cmake_minimum_required(VERSION 3.10)
+project(MocPlugin)
+include("../../AutogenGuiTest.cmake")
+
+if (QT_TEST_VERSION LESS 5)
+ message(SEND_ERROR "Qt 5 or higher required.")
+endif()
+
+set(CMAKE_AUTOMOC_DEPEND_FILTERS
+ "A_CUSTOM_MACRO"
+ "[\n][ \t]*A_CUSTOM_MACRO[ \t\r\n]*\\([^,]+,[ \t\r\n]*\"([^\"]+)\""
+)
+
+configure_file(jsonIn/StyleC.json jsonFiles/StyleC.json)
+configure_file(jsonIn/StyleC.json jsonFiles/StyleC_Custom.json)
+configure_file(jsonIn/StyleD.json jsonFiles/sub/StyleD.json)
+configure_file(jsonIn/StyleD.json jsonFiles/sub/StyleD_Custom.json)
+configure_file(jsonIn/StyleE.json jsonFiles/StyleE.json)
+configure_file(jsonIn/StyleE.json jsonFiles/StyleE_Custom.json)
+
+# Enable AUTOMOC
+set(CMAKE_AUTOMOC TRUE)
+
+include_directories("${CMAKE_CURRENT_BINARY_DIR}/jsonFiles")
+link_libraries(Qt5::Widgets)
+
+add_library(PlugA STATIC StyleA.cpp)
+add_library(PlugB STATIC StyleB.cpp)
+add_library(PlugC STATIC StyleC.cpp)
+add_library(PlugD STATIC StyleD.cpp)
+add_library(PlugE STATIC StyleE.cpp)
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.cpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.cpp
new file mode 100644
index 0000000..b5e8753
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.cpp
@@ -0,0 +1,6 @@
+#include "StyleA.hpp"
+
+QStyle* StyleA::create(const QString& key)
+{
+ return 0;
+}
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.hpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.hpp
new file mode 100644
index 0000000..198ae98
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.hpp
@@ -0,0 +1,18 @@
+#ifndef STYLEA_HPP
+#define STYLEA_HPP
+
+#include <QStylePlugin>
+
+#include "UtilityMacros.hpp"
+
+class StyleA : public QStylePlugin
+{
+ Q_OBJECT
+ // Json file in source local directory
+ Q_PLUGIN_METADATA(IID "org.styles.A" FILE "StyleA.json")
+ A_CUSTOM_MACRO(org.styles.A, "StyleA_Custom.json", AnotherArg)
+public:
+ QStyle* create(const QString& key);
+};
+
+#endif
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.json b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.json
new file mode 100644
index 0000000..cc33953
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.json
@@ -0,0 +1 @@
+{ "Keys": [ "Rocket", "Starbuster" ] }
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA_Custom.json b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA_Custom.json
new file mode 100644
index 0000000..cc33953
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA_Custom.json
@@ -0,0 +1 @@
+{ "Keys": [ "Rocket", "Starbuster" ] }
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleB.cpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleB.cpp
new file mode 100644
index 0000000..17d4400
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleB.cpp
@@ -0,0 +1,6 @@
+#include "StyleB.hpp"
+
+QStyle* StyleB::create(const QString& key)
+{
+ return 0;
+}
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleB.hpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleB.hpp
new file mode 100644
index 0000000..8ce8d77
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleB.hpp
@@ -0,0 +1,18 @@
+#ifndef STYLEB_HPP
+#define STYLEB_HPP
+
+#include <QStylePlugin>
+
+#include "UtilityMacros.hpp"
+
+class StyleB : public QStylePlugin
+{
+ Q_OBJECT
+ // Json file in source local subdirectory
+ Q_PLUGIN_METADATA(IID "org.styles.B" FILE "jsonIn/StyleB.json")
+ A_CUSTOM_MACRO(org.styles.B, "jsonIn/StyleB_Custom.json", AnotherArg)
+public:
+ QStyle* create(const QString& key);
+};
+
+#endif
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleC.cpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleC.cpp
new file mode 100644
index 0000000..37e7564
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleC.cpp
@@ -0,0 +1,6 @@
+#include "StyleC.hpp"
+
+QStyle* StyleC::create(const QString& key)
+{
+ return 0;
+}
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleC.hpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleC.hpp
new file mode 100644
index 0000000..53171e3
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleC.hpp
@@ -0,0 +1,18 @@
+#ifndef STYLEC_HPP
+#define STYLEC_HPP
+
+#include <QStylePlugin>
+
+#include "UtilityMacros.hpp"
+
+class StyleC : public QStylePlugin
+{
+ Q_OBJECT
+ // Json file in global root directory
+ Q_PLUGIN_METADATA(IID "org.styles.C" FILE "StyleC.json")
+ A_CUSTOM_MACRO(org.styles.C, "StyleC_Custom.json", AnotherArg)
+public:
+ QStyle* create(const QString& key);
+};
+
+#endif
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleD.cpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleD.cpp
new file mode 100644
index 0000000..7e4b121
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleD.cpp
@@ -0,0 +1,6 @@
+#include "StyleD.hpp"
+
+QStyle* StyleD::create(const QString& key)
+{
+ return 0;
+}
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleD.hpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleD.hpp
new file mode 100644
index 0000000..29674f9
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleD.hpp
@@ -0,0 +1,18 @@
+#ifndef STYLED_HPP
+#define STYLED_HPP
+
+#include <QStylePlugin>
+
+#include "UtilityMacros.hpp"
+
+class StyleD : public QStylePlugin
+{
+ Q_OBJECT
+ // Json file in global sub director
+ Q_PLUGIN_METADATA(IID "org.styles.D" FILE "sub/StyleD.json")
+ A_CUSTOM_MACRO(org.styles.D, "sub/StyleD_Custom.json", AnotherArg)
+public:
+ QStyle* create(const QString& key);
+};
+
+#endif
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleE.cpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleE.cpp
new file mode 100644
index 0000000..3448319
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleE.cpp
@@ -0,0 +1,9 @@
+#include "StyleE.hpp"
+
+QStyle* StyleE::create(const QString& key)
+{
+ return 0;
+}
+
+// AUTOMOC the StyleEInclude.hpp header
+#include "moc_StyleEInclude.cpp"
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleE.hpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleE.hpp
new file mode 100644
index 0000000..a069034
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleE.hpp
@@ -0,0 +1,10 @@
+#ifndef STYLEE_HPP
+#define STYLEE_HPP
+
+// The included file is not in the sources list and won't be detected by
+// AUTOMOC source file with the same base name.
+// It is registered to AUTOMOCed via a moc_<NAME>.cpp include in StyleE.cpp
+// though.
+#include "StyleEInclude.hpp"
+
+#endif
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleEInclude.hpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleEInclude.hpp
new file mode 100644
index 0000000..7318220
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleEInclude.hpp
@@ -0,0 +1,18 @@
+#ifndef STYLEE_INCLUDE_HPP
+#define STYLEE_INCLUDE_HPP
+
+#include <QStylePlugin>
+
+#include "UtilityMacros.hpp"
+
+class StyleE : public QStylePlugin
+{
+ Q_OBJECT
+ // Json files in global root directory
+ Q_PLUGIN_METADATA(IID "org.styles.E" FILE "StyleE.json")
+ A_CUSTOM_MACRO(org.styles.E, "StyleE_Custom.json", AnotherArg)
+public:
+ QStyle* create(const QString& key);
+};
+
+#endif
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/UtilityMacros.hpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/UtilityMacros.hpp
new file mode 100644
index 0000000..2f558a8
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/UtilityMacros.hpp
@@ -0,0 +1,7 @@
+#ifndef UTILITYMACROS_HPP
+#define UTILITYMACROS_HPP
+
+#define A_CUSTOM_MACRO(url, jsonFile, pluginRegistrations) \
+ Q_PLUGIN_METADATA(IID #url FILE jsonFile)
+
+#endif
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleB.json b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleB.json
new file mode 100644
index 0000000..cd155dc
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleB.json
@@ -0,0 +1 @@
+{ "Keys": [ "Red", "Green" ] }
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleB_Custom.json b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleB_Custom.json
new file mode 100644
index 0000000..129cac4
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleB_Custom.json
@@ -0,0 +1 @@
+{ "Keys": [ "Rocket", "StarbusterB" ] }
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleC.json b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleC.json
new file mode 100644
index 0000000..119aaa4
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleC.json
@@ -0,0 +1 @@
+{ "Keys": [ "Boat", "Ship" ] }
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleD.json b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleD.json
new file mode 100644
index 0000000..732c547
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleD.json
@@ -0,0 +1 @@
+{ "Keys": [ "Bike", "Car" ] }
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleE.json b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleE.json
new file mode 100644
index 0000000..5412c94
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/jsonIn/StyleE.json
@@ -0,0 +1 @@
+{ "Keys": [ "Floor", "Ceiling" ] }
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/main.cpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/main.cpp
new file mode 100644
index 0000000..3ba2ddc
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/main.cpp
@@ -0,0 +1,6 @@
+#include "StyleA.hpp"
+
+int main(int argv, char** args)
+{
+ return 0;
+}
diff --git a/Tests/QtAutogen/RerunMocPlugin/dummy.cpp b/Tests/QtAutogen/RerunMocPlugin/dummy.cpp
new file mode 100644
index 0000000..4837a76
--- /dev/null
+++ b/Tests/QtAutogen/RerunMocPlugin/dummy.cpp
@@ -0,0 +1,5 @@
+
+int main(int argv, char** args)
+{
+ return 0;
+}
diff --git a/Tests/QtAutogen/RerunRccConfigChange/CMakeLists.txt b/Tests/QtAutogen/RerunRccConfigChange/CMakeLists.txt
new file mode 100644
index 0000000..33c01ac
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccConfigChange/CMakeLists.txt
@@ -0,0 +1,47 @@
+cmake_minimum_required(VERSION 3.11.2)
+project(RerunRccConfigChange)
+include("../AutogenCoreTest.cmake")
+
+# Tests rcc rebuilding after a configuration change
+
+# Dummy executable to generate a clean target
+add_executable(dummy dummy.cpp)
+
+# When a .qrc or a file listed in a .qrc file changes,
+# the target must be rebuilt
+set(rccDepSD "${CMAKE_CURRENT_SOURCE_DIR}/RccConfigChange")
+set(rccDepBD "${CMAKE_CURRENT_BINARY_DIR}/RccConfigChange")
+
+# Rebuild macro
+macro(rebuild CFG)
+ message(STATUS "Rebuilding rccConfigChange in ${CFG} configuration.")
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}" --build . --config "${CFG}"
+ WORKING_DIRECTORY "${rccDepBD}"
+ RESULT_VARIABLE result)
+ if (result)
+ message(FATAL_ERROR "${CFG} build of rccConfigChange failed.")
+ else()
+ message(STATUS "${CFG} build of rccConfigChange finished.")
+ endif()
+endmacro()
+
+# Initial build
+try_compile(RCC_DEPENDS
+ "${rccDepBD}"
+ "${rccDepSD}"
+ RccConfigChange
+ CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
+ "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+ "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+ OUTPUT_VARIABLE output
+)
+if (NOT RCC_DEPENDS)
+ message(FATAL_ERROR "Initial build of rccConfigChange failed. Output: ${output}")
+endif()
+
+# Rebuild: Release
+rebuild(Release)
+
+# Rebuild: Debug
+rebuild(Debug)
diff --git a/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/CMakeLists.txt b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/CMakeLists.txt
new file mode 100644
index 0000000..e2dd0ac
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/CMakeLists.txt
@@ -0,0 +1,26 @@
+cmake_minimum_required(VERSION 3.11.2)
+project(RccConfigChange)
+include("../../AutogenCoreTest.cmake")
+
+# Enable AUTORCC for all targets
+set(CMAKE_AUTORCC ON)
+
+# Initial resource files setup
+configure_file(resGen/input1.txt.in resGen/input1.txt COPYONLY)
+configure_file(resGen/input2.txt.in resGen/input2.txt COPYONLY)
+configure_file(resGen.qrc.in resGen.qrc COPYONLY)
+
+# Generated qrc file with dependency
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/resGen.qrc
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/resGen.qrc.in
+ COMMAND ${CMAKE_COMMAND} -E sleep 2
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/resGen.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/resGen.qrc
+)
+
+# Target that uses a plain .qrc file
+add_executable(rccConfigChangePlain main.cpp resPlain.qrc)
+target_link_libraries(rccConfigChangePlain ${QT_QTCORE_TARGET})
+
+# Target that uses a GENERATED .qrc file
+add_executable(rccConfigChangeGen main.cpp ${CMAKE_CURRENT_BINARY_DIR}/resGen.qrc )
+target_link_libraries(rccConfigChangeGen ${QT_QTCORE_TARGET})
diff --git a/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/main.cpp b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/main.cpp
new file mode 100644
index 0000000..766b775
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/main.cpp
@@ -0,0 +1,5 @@
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resGen.qrc.in b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resGen.qrc.in
new file mode 100644
index 0000000..9674772
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resGen.qrc.in
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/TextsGenerated">
+ <file>resGen/input1.txt</file>
+ <file>resGen/input2.txt</file>
+ </qresource>
+</RCC>
diff --git a/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resGen/input1.txt.in b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resGen/input1.txt.in
new file mode 100644
index 0000000..4f24589
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resGen/input1.txt.in
@@ -0,0 +1 @@
+Generated resource input.
diff --git a/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resGen/input2.txt.in b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resGen/input2.txt.in
new file mode 100644
index 0000000..4f24589
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resGen/input2.txt.in
@@ -0,0 +1 @@
+Generated resource input.
diff --git a/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resPlain.qrc b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resPlain.qrc
new file mode 100644
index 0000000..e448726
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resPlain.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/TextsPlain">
+ <file>resPlain/input1.txt</file>
+ <file>resPlain/input2.txt</file>
+ </qresource>
+</RCC>
diff --git a/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resPlain/input1.txt b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resPlain/input1.txt
new file mode 100644
index 0000000..03969c6
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resPlain/input1.txt
@@ -0,0 +1 @@
+Plain resource input.
diff --git a/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resPlain/input2.txt b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resPlain/input2.txt
new file mode 100644
index 0000000..03969c6
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/resPlain/input2.txt
@@ -0,0 +1 @@
+Plain resource input.
diff --git a/Tests/QtAutogen/RerunRccConfigChange/dummy.cpp b/Tests/QtAutogen/RerunRccConfigChange/dummy.cpp
new file mode 100644
index 0000000..4837a76
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccConfigChange/dummy.cpp
@@ -0,0 +1,5 @@
+
+int main(int argv, char** args)
+{
+ return 0;
+}
diff --git a/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt b/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt
new file mode 100644
index 0000000..1301550
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt
@@ -0,0 +1,153 @@
+cmake_minimum_required(VERSION 3.10)
+project(RerunRccDepends)
+include("../AutogenCoreTest.cmake")
+
+# Tests rcc rebuilding when a resource file changes
+# When a .qrc or a file listed in a .qrc file changes,
+# the target must be rebuilt
+
+# Dummy executable to generate a clean target
+add_executable(dummy dummy.cpp)
+
+# Utility variables
+set(timeformat "%Y.%j.%H.%M%S")
+set(rccDepSD "${CMAKE_CURRENT_SOURCE_DIR}/RccDepends")
+set(rccDepBD "${CMAKE_CURRENT_BINARY_DIR}/RccDepends")
+
+# Utility macros
+macro(sleep)
+ message(STATUS "Sleeping for a few seconds.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+endmacro()
+
+macro(acquire_timestamps When)
+ file(TIMESTAMP "${rccDepBinPlain}" rdPlain${When} "${timeformat}")
+ file(TIMESTAMP "${rccDepBinGenerated}" rdGenerated${When} "${timeformat}")
+endmacro()
+
+macro(rebuild buildName)
+ message(STATUS "Starting build ${buildName} of rccDepends.")
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}" --build .
+ WORKING_DIRECTORY "${rccDepBD}"
+ RESULT_VARIABLE result)
+ if (result)
+ message(FATAL_ERROR "Build ${buildName} of rccDepends failed.")
+ else()
+ message(STATUS "Build ${buildName} of rccDepends finished.")
+ endif()
+endmacro()
+
+macro(require_change type)
+ if (rd${type}After VERSION_GREATER rd${type}Before)
+ message(STATUS "As expected the ${type} .qrc file ${rccDepBin${type}} changed.")
+ else()
+ message(SEND_ERROR "Unexpectedly the ${type} .qrc file ${rccDepBin${type}} did not change!\nTimestamp pre: ${rd${type}Before}\nTimestamp aft: ${rd${type}After}\n")
+ endif()
+endmacro()
+
+macro(require_change_not type)
+ if (rd${type}After VERSION_GREATER rd${type}Before)
+ message(SEND_ERROR "Unexpectedly the ${type} .qrc file ${rccDepBin${type}} changed!\nTimestamp pre: ${rd${type}Before}\nTimestamp aft: ${rd${type}After}\n")
+ else()
+ message(STATUS "As expected the ${type} .qrc file ${rccDepBin${type}} did not change.")
+ endif()
+endmacro()
+
+
+# Initial configuration
+configure_file(${rccDepSD}/resPlainA.qrc.in ${rccDepBD}/resPlain.qrc COPYONLY)
+configure_file(${rccDepSD}/resGenA.qrc.in ${rccDepBD}/resGen.qrc.in COPYONLY)
+
+# Initial build
+try_compile(RCC_DEPENDS
+ "${rccDepBD}"
+ "${rccDepSD}"
+ RccDepends
+ CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
+ "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+ "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+ OUTPUT_VARIABLE output
+)
+if (NOT RCC_DEPENDS)
+ message(FATAL_ERROR "Initial build of rccDepends failed. Output: ${output}")
+endif()
+
+# Get name of the output binaries
+file(STRINGS "${rccDepBD}/targetPlain.txt" targetListPlain ENCODING UTF-8)
+file(STRINGS "${rccDepBD}/targetGen.txt" targetListGen ENCODING UTF-8)
+list(GET targetListPlain 0 rccDepBinPlain)
+list(GET targetListGen 0 rccDepBinGenerated)
+message(STATUS "Target that uses a plain .qrc file is:\n ${rccDepBinPlain}")
+message(STATUS "Target that uses a GENERATED .qrc file is:\n ${rccDepBinGenerated}")
+
+# To avoid a race condition where the binary has the same timestamp
+# as a source file and therefore gets rebuild
+# - sleep to ensure a timestamp change
+# - touch binary to ensure it has a new timestamp
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Touching binary files to ensure new timestamps")
+file(TOUCH_NOCREATE "${rccDepBinPlain}" "${rccDepBinGenerated}")
+acquire_timestamps(After)
+require_change(Plain)
+require_change(Generated)
+
+
+# - Ensure that the timestamp will change
+# - Change a resource files listed in the .qrc file
+# - Rebuild
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing a resource file listed in the .qrc file")
+file(TOUCH "${rccDepBD}/resPlain/input.txt" "${rccDepBD}/resGen/input.txt")
+sleep()
+rebuild(2)
+acquire_timestamps(After)
+# - Test if timestamps changed
+require_change(Plain)
+require_change(Generated)
+
+
+# - Ensure that the timestamp will change
+# - Change the .qrc file
+# - Rebuild
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing the .qrc file")
+configure_file(${rccDepSD}/resPlainB.qrc.in ${rccDepBD}/resPlain.qrc COPYONLY)
+configure_file(${rccDepSD}/resGenB.qrc.in ${rccDepBD}/resGen.qrc.in COPYONLY)
+sleep()
+rebuild(3)
+acquire_timestamps(After)
+# - Test if timestamps changed
+require_change(Plain)
+require_change(Generated)
+
+
+# - Ensure that the timestamp will change
+# - Change a newly added resource files listed in the .qrc file
+# - Rebuild
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing a newly added resource file listed in the .qrc file")
+file(TOUCH "${rccDepBD}/resPlain/inputAdded.txt" "${rccDepBD}/resGen/inputAdded.txt")
+sleep()
+rebuild(4)
+acquire_timestamps(After)
+# - Test if timestamps changed
+require_change(Plain)
+require_change(Generated)
+
+
+# - Ensure that the timestamp will change
+# - Change nothing
+# - Rebuild
+acquire_timestamps(Before)
+sleep()
+message(STATUS "Changing nothing in the .qrc file")
+rebuild(5)
+acquire_timestamps(After)
+# - Test if timestamps changed
+require_change_not(Plain)
+require_change_not(Generated)
diff --git a/Tests/QtAutogen/RerunRccDepends/RccDepends/CMakeLists.txt b/Tests/QtAutogen/RerunRccDepends/RccDepends/CMakeLists.txt
new file mode 100644
index 0000000..150f849
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccDepends/RccDepends/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 3.10)
+project(RccDepends)
+include("../../AutogenCoreTest.cmake")
+
+# Enable AUTORCC for all targets
+set(CMAKE_AUTORCC ON)
+
+# Initial resource files setup
+configure_file(resPlain/input.txt.in resPlain/input.txt COPYONLY)
+configure_file(resPlain/input.txt.in resPlain/inputAdded.txt COPYONLY)
+configure_file(resGen/input.txt.in resGen/input.txt COPYONLY)
+configure_file(resGen/input.txt.in resGen/inputAdded.txt COPYONLY)
+
+# Generated qrc file with dependency
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/resGen.qrc
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/resGen.qrc.in
+ COMMAND ${CMAKE_COMMAND} -E sleep 2
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/resGen.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/resGen.qrc
+)
+
+# Target that uses a plain .qrc file
+add_executable(rccDependsPlain main.cpp ${CMAKE_CURRENT_BINARY_DIR}/resPlain.qrc)
+target_link_libraries(rccDependsPlain ${QT_QTCORE_TARGET})
+add_custom_command(TARGET rccDependsPlain POST_BUILD COMMAND
+ ${CMAKE_COMMAND} -E echo "$<TARGET_FILE:rccDependsPlain>" > targetPlain.txt
+)
+
+# Target that uses a GENERATED .qrc file
+add_executable(rccDependsGen main.cpp ${CMAKE_CURRENT_BINARY_DIR}/resGen.qrc )
+target_link_libraries(rccDependsGen ${QT_QTCORE_TARGET})
+add_custom_command(TARGET rccDependsGen POST_BUILD COMMAND
+ ${CMAKE_COMMAND} -E echo "$<TARGET_FILE:rccDependsGen>" > targetGen.txt
+)
diff --git a/Tests/QtAutogen/RerunRccDepends/RccDepends/main.cpp b/Tests/QtAutogen/RerunRccDepends/RccDepends/main.cpp
new file mode 100644
index 0000000..766b775
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccDepends/RccDepends/main.cpp
@@ -0,0 +1,5 @@
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/QtAutogen/RerunRccDepends/RccDepends/resGen/input.txt.in b/Tests/QtAutogen/RerunRccDepends/RccDepends/resGen/input.txt.in
new file mode 100644
index 0000000..4f24589
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccDepends/RccDepends/resGen/input.txt.in
@@ -0,0 +1 @@
+Generated resource input.
diff --git a/Tests/QtAutogen/RerunRccDepends/RccDepends/resGen/inputAdded.txt.in b/Tests/QtAutogen/RerunRccDepends/RccDepends/resGen/inputAdded.txt.in
new file mode 100644
index 0000000..4f24589
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccDepends/RccDepends/resGen/inputAdded.txt.in
@@ -0,0 +1 @@
+Generated resource input.
diff --git a/Tests/QtAutogen/RerunRccDepends/RccDepends/resGenA.qrc.in b/Tests/QtAutogen/RerunRccDepends/RccDepends/resGenA.qrc.in
new file mode 100644
index 0000000..c131a34
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccDepends/RccDepends/resGenA.qrc.in
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/TextsGenerated">
+ <file>resGen/input.txt</file>
+ </qresource>
+</RCC>
diff --git a/Tests/QtAutogen/RerunRccDepends/RccDepends/resGenB.qrc.in b/Tests/QtAutogen/RerunRccDepends/RccDepends/resGenB.qrc.in
new file mode 100644
index 0000000..8c7e643
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccDepends/RccDepends/resGenB.qrc.in
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/TextsGenerated">
+ <file>resGen/input.txt</file>
+ <file alias="Added">resGen/inputAdded.txt</file>
+ </qresource>
+</RCC>
diff --git a/Tests/QtAutogen/RerunRccDepends/RccDepends/resPlain/input.txt.in b/Tests/QtAutogen/RerunRccDepends/RccDepends/resPlain/input.txt.in
new file mode 100644
index 0000000..a5e407a
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccDepends/RccDepends/resPlain/input.txt.in
@@ -0,0 +1 @@
+Plaint resource input.
diff --git a/Tests/QtAutogen/RerunRccDepends/RccDepends/resPlain/inputAdded.txt.in b/Tests/QtAutogen/RerunRccDepends/RccDepends/resPlain/inputAdded.txt.in
new file mode 100644
index 0000000..a5e407a
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccDepends/RccDepends/resPlain/inputAdded.txt.in
@@ -0,0 +1 @@
+Plaint resource input.
diff --git a/Tests/QtAutogen/RerunRccDepends/RccDepends/resPlainA.qrc.in b/Tests/QtAutogen/RerunRccDepends/RccDepends/resPlainA.qrc.in
new file mode 100644
index 0000000..c135d85
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccDepends/RccDepends/resPlainA.qrc.in
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/TextsPlain">
+ <file>resPlain/input.txt</file>
+ </qresource>
+</RCC>
diff --git a/Tests/QtAutogen/RerunRccDepends/RccDepends/resPlainB.qrc.in b/Tests/QtAutogen/RerunRccDepends/RccDepends/resPlainB.qrc.in
new file mode 100644
index 0000000..186b653
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccDepends/RccDepends/resPlainB.qrc.in
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/TextsPlain">
+ <file>resPlain/input.txt</file>
+ <file alias="Added">resPlain/inputAdded.txt</file>
+ </qresource>
+</RCC>
diff --git a/Tests/QtAutogen/RerunRccDepends/dummy.cpp b/Tests/QtAutogen/RerunRccDepends/dummy.cpp
new file mode 100644
index 0000000..4837a76
--- /dev/null
+++ b/Tests/QtAutogen/RerunRccDepends/dummy.cpp
@@ -0,0 +1,5 @@
+
+int main(int argv, char** args)
+{
+ return 0;
+}
diff --git a/Tests/QtAutogen/RerunUicOnFileChange/CMakeLists.txt b/Tests/QtAutogen/RerunUicOnFileChange/CMakeLists.txt
new file mode 100644
index 0000000..1f636af
--- /dev/null
+++ b/Tests/QtAutogen/RerunUicOnFileChange/CMakeLists.txt
@@ -0,0 +1,102 @@
+cmake_minimum_required(VERSION 3.17)
+project(RerunUicOnFileChange)
+include("../AutogenGuiTest.cmake")
+
+# Utility variables
+set(testProjectTemplateDir "${CMAKE_CURRENT_SOURCE_DIR}/UicOnFileChange")
+set(testProjectSrc "${CMAKE_CURRENT_BINARY_DIR}/UicOnFileChange")
+set(testProjectBinDir "${CMAKE_CURRENT_BINARY_DIR}/UicOnFileChange-build")
+
+set(TEST_CONFIG "Release")
+
+macro(sleep)
+ message(STATUS "Sleeping for a few seconds.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+endmacro()
+macro(rebuild buildName)
+ message(STATUS "Starting build ${buildName}.")
+ execute_process(COMMAND "${CMAKE_COMMAND}" --build . --config "${TEST_CONFIG}"
+ WORKING_DIRECTORY "${testProjectBinDir}" RESULT_VARIABLE result
+ )
+ if (result)
+ message(FATAL_ERROR "Build ${buildName} failed.")
+ else()
+ message(STATUS "Build ${buildName} finished.")
+ endif()
+endmacro()
+
+configure_file("${testProjectTemplateDir}/mocwidget.h" "${testProjectSrc}/mocwidget.h" COPYONLY)
+configure_file("${testProjectTemplateDir}/main.cpp" "${testProjectSrc}/main.cpp" COPYONLY)
+configure_file("${testProjectTemplateDir}/CMakeLists.txt.in" "${testProjectSrc}/CMakeLists.txt" @ONLY)
+
+set(Num 1)
+configure_file("${testProjectTemplateDir}/mainwindow.ui.in" "${testProjectSrc}/mainwindow.ui" @ONLY)
+
+if(CMAKE_GENERATOR_INSTANCE)
+ set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE=${CMAKE_GENERATOR_INSTANCE}")
+else()
+ set(_D_CMAKE_GENERATOR_INSTANCE "")
+endif()
+
+get_property(is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(is_multi)
+ set(build_type_extra "-DCMAKE_CONFIGURATION_TYPES=${TEST_CONFIG}")
+ set(extra_bin_path "${TEST_CONFIG}/")
+else()
+ set(build_type_extra "-DCMAKE_BUILD_TYPE=${TEST_CONFIG}")
+endif()
+
+# Set the environment PATH/LD_LIBRARY_PATH variables to run the resulting executable
+if(WIN32 AND TARGET ${QT_QTCORE_TARGET})
+ get_target_property(qtcore_path ${QT_QTCORE_TARGET} LOCATION)
+ if(NOT qtcore_path)
+ get_target_property(qtcore_path ${QT_QTCORE_TARGET} IMPORTED_LOCATION)
+ endif()
+ get_filename_component(qtcore_path "${qtcore_path}" DIRECTORY)
+ set(ENV{PATH} "${qtcore_path};$ENV{PATH}")
+endif()
+
+execute_process(
+ COMMAND "${CMAKE_COMMAND}" -B "${testProjectBinDir}" -S "${testProjectSrc}"
+ -G "${CMAKE_GENERATOR}"
+ -A "${CMAKE_GENERATOR_PLATFORM}"
+ -T "${CMAKE_GENERATOR_TOOLSET}"
+ ${_D_CMAKE_GENERATOR_INSTANCE}
+ "${build_type_extra}"
+ "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
+ "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+ "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+ RESULT_VARIABLE exit_code
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE output
+)
+if(NOT exit_code EQUAL 0)
+ message(FATAL_ERROR "Initial configuration of UicOnFileChange failed. Output: ${output}")
+endif()
+
+# Initial build
+execute_process(
+ COMMAND "${CMAKE_COMMAND}" --build "${testProjectBinDir}" --config "${TEST_CONFIG}"
+ RESULT_VARIABLE exit_code
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE output
+)
+if(NOT exit_code EQUAL 0)
+ message(FATAL_ERROR "Initial build of UicOnFileChange failed. Output: ${output}")
+endif()
+
+execute_process(COMMAND "${testProjectBinDir}/${extra_bin_path}UicOnFileChange" RESULT_VARIABLE result)
+if(NOT result EQUAL "1")
+ message(FATAL_ERROR "Initial build of UicOnFileChange test result is: ${result}")
+endif()
+
+sleep()
+
+set(Num 2)
+configure_file("${testProjectTemplateDir}/mainwindow.ui.in" "${testProjectSrc}/mainwindow.ui" @ONLY)
+rebuild(2)
+
+execute_process(COMMAND "${testProjectBinDir}/${extra_bin_path}UicOnFileChange" RESULT_VARIABLE result)
+if(NOT result EQUAL "0")
+ message(FATAL_ERROR "Rebuild of UicOnFileChange test result is: ${result}")
+endif()
diff --git a/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/CMakeLists.txt.in b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/CMakeLists.txt.in
new file mode 100644
index 0000000..fa9dd6b
--- /dev/null
+++ b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/CMakeLists.txt.in
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(UicOnFileChange)
+include("@CMAKE_CURRENT_LIST_DIR@/../AutogenGuiTest.cmake")
+
+# Enable CMAKE_AUTOUIC for all targets
+set(CMAKE_AUTOUIC ON)
+
+add_executable(UicOnFileChange main.cpp mainwindow.ui)
+target_include_directories(UicOnFileChange PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+target_link_libraries(UicOnFileChange ${QT_QTCORE_TARGET} ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/main.cpp b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/main.cpp
new file mode 100644
index 0000000..fd810fa
--- /dev/null
+++ b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/main.cpp
@@ -0,0 +1,9 @@
+#include "ui_mainwindow.h"
+
+int main(int argc, char* argv[])
+{
+ MocWidget mw;
+ Ui::Widget mwUi;
+ mwUi.setupUi(&mw);
+ return mw.objectName() == "Widget2" ? 0 : 1;
+}
diff --git a/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/mainwindow.ui.in b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/mainwindow.ui.in
new file mode 100644
index 0000000..8f39e55
--- /dev/null
+++ b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/mainwindow.ui.in
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Widget</class>
+ <widget class="MocWidget" name="Widget@Num@"/>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/mocwidget.h b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/mocwidget.h
new file mode 100644
index 0000000..87fc177
--- /dev/null
+++ b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/mocwidget.h
@@ -0,0 +1,5 @@
+#include <QtCore/QObject>
+
+class MocWidget : public QObject
+{
+};
diff --git a/Tests/QtAutogen/SameName/CMakeLists.txt b/Tests/QtAutogen/SameName/CMakeLists.txt
new file mode 100644
index 0000000..4ce8dbd
--- /dev/null
+++ b/Tests/QtAutogen/SameName/CMakeLists.txt
@@ -0,0 +1,48 @@
+cmake_minimum_required(VERSION 3.16.0)
+project(SameName)
+include("../AutogenGuiTest.cmake")
+
+# Process .hh headers in AUTOMOC
+cmake_policy(SET CMP0100 NEW)
+
+# Test AUTOMOC and AUTORCC on source files with the same name
+# but in different subdirectories
+
+add_executable(sameName
+ aaa/bbb/item.cpp
+ aaa/bbb/data.qrc
+ aaa/item.cpp
+ aaa/data.qrc
+ bbb/aaa/item.cpp
+ bbb/aaa/data.qrc
+ bbb/item.cpp
+ bbb/data.qrc
+ ccc/item.cpp
+ ccc/data.qrc
+ item.cpp
+ object.h
+ object.hh
+ object.h++
+ object.hpp
+ object.hxx
+ object_upper_ext.H
+ data.qrc
+ main.cpp
+)
+target_link_libraries(sameName ${QT_LIBRARIES})
+set_target_properties(sameName PROPERTIES
+ AUTOMOC TRUE
+ AUTOUIC TRUE
+ AUTORCC TRUE
+)
+
+# Set different compression levels
+if (QT_TEST_VERSION EQUAL 4)
+ set(rccCompress "-compress")
+else()
+ set(rccCompress "--compress")
+endif()
+set_target_properties(sameName PROPERTIES AUTORCC_OPTIONS "${rccCompress};1" )
+set_source_files_properties(aaa/data.qrc PROPERTIES AUTORCC_OPTIONS "${rccCompress};2" )
+set_source_files_properties(bbb/data.qrc PROPERTIES AUTORCC_OPTIONS "${rccCompress};3" )
+set_source_files_properties(ccc/data.qrc PROPERTIES AUTORCC_OPTIONS "${rccCompress};4" )
diff --git a/Tests/QtAutogen/SameName/aaa/bbb/data.qrc b/Tests/QtAutogen/SameName/aaa/bbb/data.qrc
new file mode 100644
index 0000000..0ea3537
--- /dev/null
+++ b/Tests/QtAutogen/SameName/aaa/bbb/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="aaa/bbb">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/SameName/aaa/bbb/item.cpp b/Tests/QtAutogen/SameName/aaa/bbb/item.cpp
new file mode 100644
index 0000000..850206f
--- /dev/null
+++ b/Tests/QtAutogen/SameName/aaa/bbb/item.cpp
@@ -0,0 +1,22 @@
+#include "item.hpp"
+
+namespace aaa {
+namespace bbb {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ MocLocal obj;
+}
+}
+}
+
+#include "aaa/bbb/item.moc"
diff --git a/Tests/QtAutogen/SameName/aaa/bbb/item.hpp b/Tests/QtAutogen/SameName/aaa/bbb/item.hpp
new file mode 100644
index 0000000..0855043
--- /dev/null
+++ b/Tests/QtAutogen/SameName/aaa/bbb/item.hpp
@@ -0,0 +1,18 @@
+#ifndef AAA_BBB_ITEM_HPP
+#define AAA_BBB_ITEM_HPP
+
+#include <QObject>
+
+namespace aaa {
+namespace bbb {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+}
+
+#endif
diff --git a/Tests/QtAutogen/SameName/aaa/data.qrc b/Tests/QtAutogen/SameName/aaa/data.qrc
new file mode 100644
index 0000000..379af60
--- /dev/null
+++ b/Tests/QtAutogen/SameName/aaa/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="aaa/">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/SameName/aaa/item.cpp b/Tests/QtAutogen/SameName/aaa/item.cpp
new file mode 100644
index 0000000..e35d3d1
--- /dev/null
+++ b/Tests/QtAutogen/SameName/aaa/item.cpp
@@ -0,0 +1,22 @@
+#include "item.hpp"
+// Include ui_view.h only in header
+
+namespace aaa {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ Ui_ViewAAA ui;
+ MocLocal obj;
+}
+}
+
+#include "aaa/item.moc"
diff --git a/Tests/QtAutogen/SameName/aaa/item.hpp b/Tests/QtAutogen/SameName/aaa/item.hpp
new file mode 100644
index 0000000..875f72f
--- /dev/null
+++ b/Tests/QtAutogen/SameName/aaa/item.hpp
@@ -0,0 +1,18 @@
+#ifndef AAA_ITEM_HPP
+#define AAA_ITEM_HPP
+
+#include <QObject>
+// Include ui_view.h only in header
+#include <aaa/ui_view.h>
+
+namespace aaa {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+
+#endif
diff --git a/Tests/QtAutogen/SameName/aaa/view.ui b/Tests/QtAutogen/SameName/aaa/view.ui
new file mode 100644
index 0000000..0f09980
--- /dev/null
+++ b/Tests/QtAutogen/SameName/aaa/view.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ViewAAA</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/SameName/bbb/aaa/data.qrc b/Tests/QtAutogen/SameName/bbb/aaa/data.qrc
new file mode 100644
index 0000000..da98009
--- /dev/null
+++ b/Tests/QtAutogen/SameName/bbb/aaa/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="bbb/aaa/">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/SameName/bbb/aaa/item.cpp b/Tests/QtAutogen/SameName/bbb/aaa/item.cpp
new file mode 100644
index 0000000..7ad01c3
--- /dev/null
+++ b/Tests/QtAutogen/SameName/bbb/aaa/item.cpp
@@ -0,0 +1,22 @@
+#include "item.hpp"
+
+namespace bbb {
+namespace aaa {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ MocLocal obj;
+}
+}
+}
+
+#include "bbb/aaa/item.moc"
diff --git a/Tests/QtAutogen/SameName/bbb/aaa/item.hpp b/Tests/QtAutogen/SameName/bbb/aaa/item.hpp
new file mode 100644
index 0000000..be07ca8
--- /dev/null
+++ b/Tests/QtAutogen/SameName/bbb/aaa/item.hpp
@@ -0,0 +1,18 @@
+#ifndef BBB_AAA_ITEM_HPP
+#define BBB_AAA_ITEM_HPP
+
+#include <QObject>
+
+namespace bbb {
+namespace aaa {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+}
+
+#endif
diff --git a/Tests/QtAutogen/SameName/bbb/data.qrc b/Tests/QtAutogen/SameName/bbb/data.qrc
new file mode 100644
index 0000000..5b080f5
--- /dev/null
+++ b/Tests/QtAutogen/SameName/bbb/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="bbb/">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/SameName/bbb/item.cpp b/Tests/QtAutogen/SameName/bbb/item.cpp
new file mode 100644
index 0000000..9ef128e
--- /dev/null
+++ b/Tests/QtAutogen/SameName/bbb/item.cpp
@@ -0,0 +1,23 @@
+#include "item.hpp"
+// Include ui_view.h only in source
+#include <bbb/ui_view.h>
+
+namespace bbb {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ Ui_ViewBBB ui;
+ MocLocal obj;
+}
+}
+
+#include "bbb/item.moc"
diff --git a/Tests/QtAutogen/SameName/bbb/item.hpp b/Tests/QtAutogen/SameName/bbb/item.hpp
new file mode 100644
index 0000000..d39a9d7
--- /dev/null
+++ b/Tests/QtAutogen/SameName/bbb/item.hpp
@@ -0,0 +1,17 @@
+#ifndef BBB_ITEM_HPP
+#define BBB_ITEM_HPP
+
+#include <QObject>
+// Include ui_view.h only in source
+
+namespace bbb {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+
+#endif
diff --git a/Tests/QtAutogen/SameName/bbb/view.ui b/Tests/QtAutogen/SameName/bbb/view.ui
new file mode 100644
index 0000000..a8f506e
--- /dev/null
+++ b/Tests/QtAutogen/SameName/bbb/view.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ViewBBB</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/SameName/ccc/data.qrc b/Tests/QtAutogen/SameName/ccc/data.qrc
new file mode 100644
index 0000000..f934c39
--- /dev/null
+++ b/Tests/QtAutogen/SameName/ccc/data.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="ccc/">
+ <file>item.hpp</file>
+ <file>item.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/SameName/ccc/item.cpp b/Tests/QtAutogen/SameName/ccc/item.cpp
new file mode 100644
index 0000000..ab8a281
--- /dev/null
+++ b/Tests/QtAutogen/SameName/ccc/item.cpp
@@ -0,0 +1,25 @@
+#include "item.hpp"
+// Include ui_view.h in source and header
+#include <ccc/ui_view.h>
+
+namespace ccc {
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ Ui_ViewCCC ui;
+ MocLocal obj;
+}
+}
+
+// Include own moc files
+#include "ccc/item.moc"
+#include "moc_item.cpp"
diff --git a/Tests/QtAutogen/SameName/ccc/item.hpp b/Tests/QtAutogen/SameName/ccc/item.hpp
new file mode 100644
index 0000000..20d9dd9
--- /dev/null
+++ b/Tests/QtAutogen/SameName/ccc/item.hpp
@@ -0,0 +1,18 @@
+#ifndef CCC_ITEM_HPP
+#define CCC_ITEM_HPP
+
+#include <QObject>
+// Include ui_view.h in source and header
+#include <ccc/ui_view.h>
+
+namespace ccc {
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+}
+
+#endif
diff --git a/Tests/QtAutogen/SameName/ccc/view.ui b/Tests/QtAutogen/SameName/ccc/view.ui
new file mode 100644
index 0000000..7989c69
--- /dev/null
+++ b/Tests/QtAutogen/SameName/ccc/view.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ViewCCC</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/SameName/data.qrc b/Tests/QtAutogen/SameName/data.qrc
new file mode 100644
index 0000000..4ce0b4e
--- /dev/null
+++ b/Tests/QtAutogen/SameName/data.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>main.cpp</file>
+</qresource>
+</RCC>
diff --git a/Tests/QtAutogen/SameName/item.cpp b/Tests/QtAutogen/SameName/item.cpp
new file mode 100644
index 0000000..3d1fbe7
--- /dev/null
+++ b/Tests/QtAutogen/SameName/item.cpp
@@ -0,0 +1,20 @@
+#include "item.hpp"
+// Include ui_view.h in source and header
+#include <ui_view.h>
+
+class MocLocal : public QObject
+{
+ Q_OBJECT;
+
+public:
+ MocLocal() = default;
+ ~MocLocal() = default;
+};
+
+void Item::go()
+{
+ Ui_View ui;
+ MocLocal obj;
+}
+
+#include "item.moc"
diff --git a/Tests/QtAutogen/SameName/item.hpp b/Tests/QtAutogen/SameName/item.hpp
new file mode 100644
index 0000000..75e83f4
--- /dev/null
+++ b/Tests/QtAutogen/SameName/item.hpp
@@ -0,0 +1,15 @@
+#ifndef ITEM_HPP
+#define ITEM_HPP
+
+#include <QObject>
+// Include ui_view.h in source and header
+#include <ui_view.h>
+
+class Item : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go();
+};
+
+#endif
diff --git a/Tests/QtAutogen/SameName/main.cpp b/Tests/QtAutogen/SameName/main.cpp
new file mode 100644
index 0000000..725f4cd
--- /dev/null
+++ b/Tests/QtAutogen/SameName/main.cpp
@@ -0,0 +1,31 @@
+#include "aaa/bbb/item.hpp"
+#include "aaa/item.hpp"
+#include "bbb/aaa/item.hpp"
+#include "bbb/item.hpp"
+#include "ccc/item.hpp"
+#include "item.hpp"
+#include "object.h"
+#include "object.h++"
+#include "object.hh"
+#include "object.hpp"
+#include "object.hxx"
+#include "object_upper_ext.H"
+
+int main(int argv, char** args)
+{
+ // Item instances
+ ::Item item;
+ ::aaa::Item aaa_item;
+ ::aaa::bbb::Item aaa_bbb_item;
+ ::bbb::Item bbb_item;
+ ::bbb::aaa::Item bbb_aaa_item;
+ ::ccc::Item ccc_item;
+ // Object instances
+ ::Object_h obj_h;
+ ::Object_hh obj_hh;
+ ::Object_hplpl obj_hplpl;
+ ::Object_hpp obj_hpp;
+ ::Object_hxx obj_hxx;
+ ::Object_Upper_Ext_H obj_upper_ext_h;
+ return 0;
+}
diff --git a/Tests/QtAutogen/SameName/object.h b/Tests/QtAutogen/SameName/object.h
new file mode 100644
index 0000000..8662094
--- /dev/null
+++ b/Tests/QtAutogen/SameName/object.h
@@ -0,0 +1,13 @@
+#ifndef OBJECT_H
+#define OBJECT_H
+
+#include <QObject>
+
+class Object_h : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go(){};
+};
+
+#endif
diff --git a/Tests/QtAutogen/SameName/object.h++ b/Tests/QtAutogen/SameName/object.h++
new file mode 100644
index 0000000..64222b7
--- /dev/null
+++ b/Tests/QtAutogen/SameName/object.h++
@@ -0,0 +1,13 @@
+#ifndef OBJECT_HPLPL
+#define OBJECT_HPLPL
+
+#include <QObject>
+
+class Object_hplpl : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go(){};
+};
+
+#endif
diff --git a/Tests/QtAutogen/SameName/object.hh b/Tests/QtAutogen/SameName/object.hh
new file mode 100644
index 0000000..3e16f83
--- /dev/null
+++ b/Tests/QtAutogen/SameName/object.hh
@@ -0,0 +1,13 @@
+#ifndef OBJECT_HH
+#define OBJECT_HH
+
+#include <QObject>
+
+class Object_hh : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go(){};
+};
+
+#endif
diff --git a/Tests/QtAutogen/SameName/object.hpp b/Tests/QtAutogen/SameName/object.hpp
new file mode 100644
index 0000000..035050e
--- /dev/null
+++ b/Tests/QtAutogen/SameName/object.hpp
@@ -0,0 +1,13 @@
+#ifndef OBJECT_HPP
+#define OBJECT_HPP
+
+#include <QObject>
+
+class Object_hpp : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go(){};
+};
+
+#endif
diff --git a/Tests/QtAutogen/SameName/object.hxx b/Tests/QtAutogen/SameName/object.hxx
new file mode 100644
index 0000000..c3c050f
--- /dev/null
+++ b/Tests/QtAutogen/SameName/object.hxx
@@ -0,0 +1,13 @@
+#ifndef OBJECT_HXX
+#define OBJECT_HXX
+
+#include <QObject>
+
+class Object_hxx : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go(){};
+};
+
+#endif
diff --git a/Tests/QtAutogen/SameName/object_upper_ext.H b/Tests/QtAutogen/SameName/object_upper_ext.H
new file mode 100644
index 0000000..3266087
--- /dev/null
+++ b/Tests/QtAutogen/SameName/object_upper_ext.H
@@ -0,0 +1,13 @@
+#ifndef OBJECT_UPPER_EXT_H
+#define OBJECT_UPPER_EXT_H
+
+#include <QObject>
+
+class Object_Upper_Ext_H : public QObject
+{
+ Q_OBJECT
+ Q_SLOT
+ void go(){};
+};
+
+#endif
diff --git a/Tests/QtAutogen/SameName/view.ui b/Tests/QtAutogen/SameName/view.ui
new file mode 100644
index 0000000..2ffe734
--- /dev/null
+++ b/Tests/QtAutogen/SameName/view.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>View</class>
+ <widget class="QWidget" name="Base">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/StaticLibraryCycle/CMakeLists.txt b/Tests/QtAutogen/StaticLibraryCycle/CMakeLists.txt
new file mode 100644
index 0000000..f3536ba
--- /dev/null
+++ b/Tests/QtAutogen/StaticLibraryCycle/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.10)
+project(StaticLibraryCycle)
+include("../AutogenCoreTest.cmake")
+
+# Test AUTOMOC on cyclic static libraries
+
+set(CMAKE_AUTOMOC ON)
+
+# Cyclic static libraries
+add_library(slc_a STATIC a.cpp)
+target_link_libraries(slc_a ${QT_LIBRARIES} slc_b)
+
+add_library(slc_b STATIC b.cpp)
+target_link_libraries(slc_b ${QT_LIBRARIES} slc_c)
+
+add_library(slc_c STATIC c.cpp)
+target_link_libraries(slc_c ${QT_LIBRARIES} slc_a)
+
+add_executable(slc main.cpp)
+target_link_libraries(slc ${QT_LIBRARIES} slc_a)
diff --git a/Tests/QtAutogen/StaticLibraryCycle/a.cpp b/Tests/QtAutogen/StaticLibraryCycle/a.cpp
new file mode 100644
index 0000000..8dd1803
--- /dev/null
+++ b/Tests/QtAutogen/StaticLibraryCycle/a.cpp
@@ -0,0 +1,13 @@
+#include "a.h"
+
+#include "b.h"
+
+bool A::recursed = false;
+
+A::A()
+{
+ if (!A::recursed) {
+ A::recursed = true;
+ B b;
+ }
+}
diff --git a/Tests/QtAutogen/StaticLibraryCycle/a.h b/Tests/QtAutogen/StaticLibraryCycle/a.h
new file mode 100644
index 0000000..f24398e
--- /dev/null
+++ b/Tests/QtAutogen/StaticLibraryCycle/a.h
@@ -0,0 +1,15 @@
+#ifndef CLASSA_HPP
+#define CLASSA_HPP
+
+#include <QObject>
+
+class A : public QObject
+{
+ Q_OBJECT
+ static bool recursed;
+
+public:
+ A();
+};
+
+#endif
diff --git a/Tests/QtAutogen/StaticLibraryCycle/b.cpp b/Tests/QtAutogen/StaticLibraryCycle/b.cpp
new file mode 100644
index 0000000..dee2617
--- /dev/null
+++ b/Tests/QtAutogen/StaticLibraryCycle/b.cpp
@@ -0,0 +1,8 @@
+#include "b.h"
+
+#include "c.h"
+
+B::B()
+{
+ C c;
+}
diff --git a/Tests/QtAutogen/StaticLibraryCycle/b.h b/Tests/QtAutogen/StaticLibraryCycle/b.h
new file mode 100644
index 0000000..ededbd8
--- /dev/null
+++ b/Tests/QtAutogen/StaticLibraryCycle/b.h
@@ -0,0 +1,13 @@
+#ifndef CLASSB_HPP
+#define CLASSB_HPP
+
+#include <QObject>
+
+class B : public QObject
+{
+ Q_OBJECT
+public:
+ B();
+};
+
+#endif
diff --git a/Tests/QtAutogen/StaticLibraryCycle/c.cpp b/Tests/QtAutogen/StaticLibraryCycle/c.cpp
new file mode 100644
index 0000000..2871f62
--- /dev/null
+++ b/Tests/QtAutogen/StaticLibraryCycle/c.cpp
@@ -0,0 +1,8 @@
+#include "c.h"
+
+#include "a.h"
+
+C::C()
+{
+ A a;
+}
diff --git a/Tests/QtAutogen/StaticLibraryCycle/c.h b/Tests/QtAutogen/StaticLibraryCycle/c.h
new file mode 100644
index 0000000..20f3725
--- /dev/null
+++ b/Tests/QtAutogen/StaticLibraryCycle/c.h
@@ -0,0 +1,13 @@
+#ifndef CLASSC_HPP
+#define CLASSC_HPP
+
+#include <QObject>
+
+class C : public QObject
+{
+ Q_OBJECT
+public:
+ C();
+};
+
+#endif
diff --git a/Tests/QtAutogen/StaticLibraryCycle/main.cpp b/Tests/QtAutogen/StaticLibraryCycle/main.cpp
new file mode 100644
index 0000000..f5b7fd2
--- /dev/null
+++ b/Tests/QtAutogen/StaticLibraryCycle/main.cpp
@@ -0,0 +1,8 @@
+#include "a.h"
+
+int main(int argv, char** args)
+{
+ // Object instances
+ A a;
+ return 0;
+}
diff --git a/Tests/QtAutogen/TestMacros.cmake b/Tests/QtAutogen/TestMacros.cmake
new file mode 100644
index 0000000..9dcf31f
--- /dev/null
+++ b/Tests/QtAutogen/TestMacros.cmake
@@ -0,0 +1,70 @@
+# Autogen build options
+set(Autogen_BUILD_OPTIONS "-DQT_TEST_VERSION=${QT_TEST_VERSION}")
+if(_isMultiConfig) # Set in Tests/CMakeLists.txt
+ list(APPEND Autogen_CTEST_OPTIONS --build-config $<CONFIGURATION>)
+else()
+ list(APPEND Autogen_BUILD_OPTIONS "-DCMAKE_BUILD_TYPE=$<CONFIGURATION>")
+endif()
+list(APPEND Autogen_BUILD_OPTIONS
+ "-DCMAKE_AUTOGEN_VERBOSE=1"
+ "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+)
+# XXX(xcode-per-cfg-src): Drop the NO_PER_CONFIG_SOURCES exclusion
+# when the Xcode generator supports per-config sources.
+if(CMAKE_GENERATOR STREQUAL "Xcode")
+ list(APPEND Autogen_BUILD_OPTIONS -DNO_PER_CONFIG_SOURCES=1)
+endif()
+
+# A macro to add a QtAutogen test
+macro(ADD_AUTOGEN_TEST NAME)
+ if(${ARGC} GREATER 1)
+ # On Windows there is no RPATH, so while Qt might be available for building,
+ # the required dlls may not be in the PATH, so we can't run the executables
+ # on that platform.
+ if(WIN32)
+ set(_TestCommand --test-command ${CMAKE_CTEST_COMMAND} -V)
+ else()
+ set(_TestCommand --test-command ${ARGN})
+ endif()
+ endif()
+
+ set(_QtXAutogen "Qt${QT_TEST_VERSION}Autogen")
+ set(_SourceDir "${CMake_SOURCE_DIR}/Tests/QtAutogen/${NAME}")
+ set(_BuildDir "${CMake_BINARY_DIR}/Tests/${_QtXAutogen}/${NAME}")
+ add_test(NAME "${_QtXAutogen}.${NAME}" COMMAND "${CMAKE_CTEST_COMMAND}"
+ --build-and-test
+ "${_SourceDir}"
+ "${_BuildDir}"
+ ${build_generator_args}
+ --build-project ${NAME}
+ ${Autogen_CTEST_OPTIONS}
+ --build-exe-dir "${_BuildDir}"
+ --force-new-ctest-process
+ --build-options ${build_options} ${Autogen_BUILD_OPTIONS}
+ ${_TestCommand}
+ )
+ set_tests_properties("${_QtXAutogen}.${NAME}" PROPERTIES LABELS "Qt${QT_TEST_VERSION}")
+ list(APPEND TEST_BUILD_DIRS "${_BuildDir}")
+ unset(_TestCommand)
+ unset(_QtXAutogen)
+ unset(_SourceDir)
+ unset(_BuildDir)
+endmacro()
+
+# Allow using qtx_wrap_cpp and qtx_generate_moc or not
+set(QT_TEST_ALLOW_QT_MACROS TRUE)
+# Do a simple check if there is are non ASCII character in the build path
+string(REGEX MATCH "[^ -~]+" NON_ASCII_BDIR ${CMAKE_CURRENT_BINARY_DIR})
+if(NON_ASCII_BDIR)
+ # Qt4 moc does not support utf8 paths in _parameter files generated by
+ # qtx_wrap_cpp
+ # https://bugreports.qt.io/browse/QTBUG-35480
+ if(QT_TEST_VERSION EQUAL 4)
+ set(QT_TEST_ALLOW_QT_MACROS FALSE)
+ endif()
+ # On windows qtx_wrap_cpp also fails in Qt5 when used on a path that
+ # contains non ASCII characters
+ if(WIN32)
+ set(QT_TEST_ALLOW_QT_MACROS FALSE)
+ endif()
+endif()
diff --git a/Tests/QtAutogen/Tests.cmake b/Tests/QtAutogen/Tests.cmake
new file mode 100644
index 0000000..ab5686a
--- /dev/null
+++ b/Tests/QtAutogen/Tests.cmake
@@ -0,0 +1,55 @@
+# Qt4 and Qt5 tests
+ADD_AUTOGEN_TEST(AutogenOriginDependsOff autogenOriginDependsOff)
+ADD_AUTOGEN_TEST(AutogenOriginDependsOn)
+ADD_AUTOGEN_TEST(AutogenTargetDepends)
+ADD_AUTOGEN_TEST(Complex QtAutogen)
+ADD_AUTOGEN_TEST(GlobalAutogenTarget)
+ADD_AUTOGEN_TEST(LowMinimumVersion lowMinimumVersion)
+ADD_AUTOGEN_TEST(ManySources manySources)
+ADD_AUTOGEN_TEST(MocOnly mocOnly)
+ADD_AUTOGEN_TEST(MocOptions mocOptions)
+ADD_AUTOGEN_TEST(ObjectLibrary someProgram)
+ADD_AUTOGEN_TEST(Parallel parallel)
+ADD_AUTOGEN_TEST(Parallel1 parallel1)
+ADD_AUTOGEN_TEST(Parallel2 parallel2)
+ADD_AUTOGEN_TEST(Parallel3 parallel3)
+ADD_AUTOGEN_TEST(Parallel4 parallel4)
+ADD_AUTOGEN_TEST(ParallelAUTO parallelAUTO)
+ADD_AUTOGEN_TEST(RccEmpty rccEmpty)
+ADD_AUTOGEN_TEST(RccOffMocLibrary)
+ADD_AUTOGEN_TEST(RccOnly rccOnly)
+ADD_AUTOGEN_TEST(RccSkipSource)
+ADD_AUTOGEN_TEST(RerunMocBasic)
+ADD_AUTOGEN_TEST(RerunMocOnAddFile)
+ADD_AUTOGEN_TEST(RerunMocOnMissingDependency)
+ADD_AUTOGEN_TEST(RerunRccConfigChange)
+ADD_AUTOGEN_TEST(RerunRccDepends)
+ADD_AUTOGEN_TEST(RerunUicOnFileChange)
+ADD_AUTOGEN_TEST(SameName sameName)
+ADD_AUTOGEN_TEST(StaticLibraryCycle slc)
+ADD_AUTOGEN_TEST(UicInclude uicInclude)
+ADD_AUTOGEN_TEST(UicInterface QtAutoUicInterface)
+ADD_AUTOGEN_TEST(UicNoGui uicNoGui)
+ADD_AUTOGEN_TEST(UicOnly uicOnly)
+ADD_AUTOGEN_TEST(UicSkipSource)
+ADD_AUTOGEN_TEST(UnityMocSource)
+
+if(QT_TEST_ALLOW_QT_MACROS)
+ ADD_AUTOGEN_TEST(MocCMP0071)
+ set_property(TEST "Qt${QT_TEST_VERSION}Autogen.MocCMP0071" APPEND PROPERTY LABELS "policy")
+ ADD_AUTOGEN_TEST(MocCMP0100)
+ set_property(TEST "Qt${QT_TEST_VERSION}Autogen.MocCMP0100" APPEND PROPERTY LABELS "policy")
+ ADD_AUTOGEN_TEST(MocInclude)
+ ADD_AUTOGEN_TEST(MocIncludeSymlink)
+ ADD_AUTOGEN_TEST(MocSkipSource)
+endif()
+
+# Qt5 only tests
+if(QT_TEST_VERSION GREATER 4)
+ ADD_AUTOGEN_TEST(MocMacroName mocMacroName)
+ ADD_AUTOGEN_TEST(MocOsMacros)
+ ADD_AUTOGEN_TEST(RerunMocPlugin)
+ if(APPLE)
+ ADD_AUTOGEN_TEST(MacOsFW)
+ endif()
+endif()
diff --git a/Tests/QtAutogen/UicInclude/CMakeLists.txt b/Tests/QtAutogen/UicInclude/CMakeLists.txt
new file mode 100644
index 0000000..929868b
--- /dev/null
+++ b/Tests/QtAutogen/UicInclude/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.10)
+project(UicInclude)
+include("../AutogenGuiTest.cmake")
+
+# Test uic include patterns
+set(CMAKE_AUTOUIC_SEARCH_PATHS "dirA")
+
+add_executable(uicInclude main.cpp)
+target_link_libraries(uicInclude ${QT_LIBRARIES})
+set_target_properties(uicInclude PROPERTIES AUTOUIC ON)
+set_property(TARGET uicInclude APPEND PROPERTY AUTOUIC_SEARCH_PATHS "dirB")
diff --git a/Tests/QtAutogen/UicInclude/PageC.ui b/Tests/QtAutogen/UicInclude/PageC.ui
new file mode 100644
index 0000000..bb2fb5e
--- /dev/null
+++ b/Tests/QtAutogen/UicInclude/PageC.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PageC</class>
+ <widget class="QWidget" name="PageC">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UicInclude/PageC2.ui b/Tests/QtAutogen/UicInclude/PageC2.ui
new file mode 100644
index 0000000..daab868
--- /dev/null
+++ b/Tests/QtAutogen/UicInclude/PageC2.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PageC2</class>
+ <widget class="QWidget" name="PageC2">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UicInclude/dirA/PageA.ui b/Tests/QtAutogen/UicInclude/dirA/PageA.ui
new file mode 100644
index 0000000..dd81802
--- /dev/null
+++ b/Tests/QtAutogen/UicInclude/dirA/PageA.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PageA</class>
+ <widget class="QWidget" name="PageA">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UicInclude/dirB/PageB.ui b/Tests/QtAutogen/UicInclude/dirB/PageB.ui
new file mode 100644
index 0000000..fa6dfa6
--- /dev/null
+++ b/Tests/QtAutogen/UicInclude/dirB/PageB.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PageB</class>
+ <widget class="QWidget" name="PageB">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UicInclude/dirB/PageB2.ui b/Tests/QtAutogen/UicInclude/dirB/PageB2.ui
new file mode 100644
index 0000000..2225150
--- /dev/null
+++ b/Tests/QtAutogen/UicInclude/dirB/PageB2.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PageB2</class>
+ <widget class="QWidget" name="PageB2">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UicInclude/dirB/subB/PageBsub.ui b/Tests/QtAutogen/UicInclude/dirB/subB/PageBsub.ui
new file mode 100644
index 0000000..873016e
--- /dev/null
+++ b/Tests/QtAutogen/UicInclude/dirB/subB/PageBsub.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PageBsub</class>
+ <widget class="QWidget" name="PageBsub">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UicInclude/main.cpp b/Tests/QtAutogen/UicInclude/main.cpp
new file mode 100644
index 0000000..c8e7609
--- /dev/null
+++ b/Tests/QtAutogen/UicInclude/main.cpp
@@ -0,0 +1,18 @@
+
+#include "main.hpp"
+
+int main(int argv, char** args)
+{
+ return 0;
+}
+
+// .ui files in CMAKE_AUTOUIC_SEARCH_PATHS
+#include "ui_PageA.h"
+// .ui files in AUTOUIC_SEARCH_PATHS
+#include "sub/gen/deep/ui_PageB2.h"
+#include "subB/ui_PageBsub.h"
+#include "ui_PageB.h"
+// .ui files in source's vicinity
+#include "sub/gen/deep/ui_PageC2.h"
+#include "subC/ui_PageCsub.h"
+#include "ui_PageC.h"
diff --git a/Tests/QtAutogen/UicInclude/main.hpp b/Tests/QtAutogen/UicInclude/main.hpp
new file mode 100644
index 0000000..58ddc26
--- /dev/null
+++ b/Tests/QtAutogen/UicInclude/main.hpp
@@ -0,0 +1,6 @@
+#ifndef MAIN_HPP
+#define MAIN_HPP
+
+#include "ui_PageA.h"
+
+#endif
diff --git a/Tests/QtAutogen/UicInclude/subC/PageCsub.ui b/Tests/QtAutogen/UicInclude/subC/PageCsub.ui
new file mode 100644
index 0000000..0268326
--- /dev/null
+++ b/Tests/QtAutogen/UicInclude/subC/PageCsub.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PageCsub</class>
+ <widget class="QWidget" name="PageCsub">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UicInterface/CMakeLists.txt b/Tests/QtAutogen/UicInterface/CMakeLists.txt
new file mode 100644
index 0000000..e022764
--- /dev/null
+++ b/Tests/QtAutogen/UicInterface/CMakeLists.txt
@@ -0,0 +1,58 @@
+cmake_minimum_required(VERSION 3.10)
+project(UicInterface)
+include("../AutogenGuiTest.cmake")
+
+set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+
+# BEGIN Upstream
+
+set(CMAKE_VERBOSE_MAKEFILE ON)
+
+add_library(KI18n klocalizedstring.cpp)
+target_link_libraries(KI18n ${QT_QTCORE_TARGET})
+
+set(autouic_options
+ -tr tr2$<$<NOT:$<BOOL:$<TARGET_PROPERTY:NO_KUIT_SEMANTIC>>>:x>i18n
+)
+if (NOT Qt5Widgets_VERSION VERSION_LESS 5.3.0)
+ list(APPEND autouic_options -include klocalizedstring.h)
+endif()
+
+set_property(TARGET KI18n APPEND PROPERTY
+ INTERFACE_AUTOUIC_OPTIONS ${autouic_options}
+)
+
+set(domainProp $<TARGET_PROPERTY:TRANSLATION_DOMAIN>)
+set(nameLower $<LOWER_CASE:$<MAKE_C_IDENTIFIER:$<TARGET_PROPERTY:NAME>>>)
+set(domain_logic
+ $<$<BOOL:${domainProp}>:${domainProp}>$<$<NOT:$<BOOL:${domainProp}>>:${nameLower}>
+)
+set_property(TARGET KI18n APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS "TRANSLATION_DOMAIN=${domain_logic}"
+)
+
+# END upstream
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+set(INC_DIR "include_$<CONFIG>" )
+else()
+set(INC_DIR "include" )
+endif()
+
+add_library(LibWidget libwidget.cpp)
+target_link_libraries(LibWidget KI18n ${QT_LIBRARIES})
+set_property(TARGET LibWidget PROPERTY NO_KUIT_SEMANTIC ON)
+set_property(TARGET LibWidget PROPERTY TRANSLATION_DOMAIN customdomain)
+
+add_library(MyWidget mywidget.cpp)
+target_link_libraries(MyWidget KI18n ${QT_LIBRARIES})
+
+add_executable(QtAutoUicInterface main.cpp)
+target_compile_definitions(QtAutoUicInterface
+ PRIVATE
+ UI_LIBWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/LibWidget_autogen/${INC_DIR}/ui_libwidget.h"
+ UI_MYWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/MyWidget_autogen/${INC_DIR}/ui_mywidget.h"
+)
diff --git a/Tests/QtAutogen/UicInterface/klocalizedstring.cpp b/Tests/QtAutogen/UicInterface/klocalizedstring.cpp
new file mode 100644
index 0000000..b629cd1
--- /dev/null
+++ b/Tests/QtAutogen/UicInterface/klocalizedstring.cpp
@@ -0,0 +1,12 @@
+
+#include "klocalizedstring.h"
+
+QString tr2xi18n(const char* text, const char*)
+{
+ return QLatin1String("TranslatedX") + QString::fromLatin1(text);
+}
+
+QString tr2i18n(const char* text, const char*)
+{
+ return QLatin1String("Translated") + QString::fromLatin1(text);
+}
diff --git a/Tests/QtAutogen/UicInterface/klocalizedstring.h b/Tests/QtAutogen/UicInterface/klocalizedstring.h
new file mode 100644
index 0000000..6129599
--- /dev/null
+++ b/Tests/QtAutogen/UicInterface/klocalizedstring.h
@@ -0,0 +1,17 @@
+
+#ifndef KLOCALIZEDSTRING_H
+#define KLOCALIZEDSTRING_H
+
+#include <QString>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ QString tr2xi18n(const char* text, const char* comment = 0);
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ QString tr2i18n(const char* text, const char* comment = 0);
+
+#endif
diff --git a/Tests/QtAutogen/UicInterface/libwidget.cpp b/Tests/QtAutogen/UicInterface/libwidget.cpp
new file mode 100644
index 0000000..008c22a
--- /dev/null
+++ b/Tests/QtAutogen/UicInterface/libwidget.cpp
@@ -0,0 +1,14 @@
+
+#include "libwidget.h"
+
+LibWidget::LibWidget(QWidget* parent)
+ : QWidget(parent)
+ , ui(new Ui::LibWidget)
+{
+ ui->setupUi(this);
+}
+
+LibWidget::~LibWidget()
+{
+ delete ui;
+}
diff --git a/Tests/QtAutogen/UicInterface/libwidget.h b/Tests/QtAutogen/UicInterface/libwidget.h
new file mode 100644
index 0000000..532ff1d
--- /dev/null
+++ b/Tests/QtAutogen/UicInterface/libwidget.h
@@ -0,0 +1,26 @@
+
+#ifndef LIBWIDGET_H
+#define LIBWIDGET_H
+
+#include <memory>
+
+#include <QWidget>
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 3, 0)
+# include <klocalizedstring.h>
+#endif
+
+#include "ui_libwidget.h"
+
+class LibWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit LibWidget(QWidget* parent = 0);
+ ~LibWidget();
+
+private:
+ Ui::LibWidget* ui;
+};
+
+#endif
diff --git a/Tests/QtAutogen/UicInterface/libwidget.ui b/Tests/QtAutogen/UicInterface/libwidget.ui
new file mode 100644
index 0000000..897371e
--- /dev/null
+++ b/Tests/QtAutogen/UicInterface/libwidget.ui
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LibWidget</class>
+ <widget class="QWidget" name="LibWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <widget class="QLabel" name="label">
+ <property name="geometry">
+ <rect>
+ <x>180</x>
+ <y>60</y>
+ <width>57</width>
+ <height>15</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>LibLabel</string>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UicInterface/main.cpp b/Tests/QtAutogen/UicInterface/main.cpp
new file mode 100644
index 0000000..68bd843
--- /dev/null
+++ b/Tests/QtAutogen/UicInterface/main.cpp
@@ -0,0 +1,67 @@
+
+#include <fstream>
+#include <iostream>
+#include <string>
+
+int main(int argc, char** argv)
+{
+ std::ifstream f;
+ f.open(UI_LIBWIDGET_H);
+ if (!f.is_open()) {
+ std::cout << "Could not open \"" UI_LIBWIDGET_H "\"." << std::endl;
+ return -1;
+ }
+
+ {
+ bool gotTr2i18n = false;
+
+ while (!f.eof()) {
+ std::string output;
+ getline(f, output);
+ if (!gotTr2i18n) {
+ gotTr2i18n = output.find("tr2i18n") != std::string::npos;
+ }
+ if (output.find("tr2xi18n") != std::string::npos) {
+ std::cout << "ui_libwidget,h uses tr2xi18n, though it should not."
+ << std::endl;
+ return -1;
+ }
+ }
+
+ if (!gotTr2i18n) {
+ std::cout << "Did not find tr2i18n in ui_libwidget.h" << std::endl;
+ return -1;
+ }
+ }
+
+ f.close();
+ f.open(UI_MYWIDGET_H);
+ if (!f.is_open()) {
+ std::cout << "Could not open \"" UI_MYWIDGET_H "\"." << std::endl;
+ return -1;
+ }
+
+ {
+ bool gotTr2xi18n = false;
+
+ while (!f.eof()) {
+ std::string output;
+ getline(f, output);
+ if (!gotTr2xi18n) {
+ gotTr2xi18n = output.find("tr2xi18n") != std::string::npos;
+ }
+ if (output.find("tr2i18n") != std::string::npos) {
+ std::cout << "ui_mywidget,h uses tr2i18n, though it should not."
+ << std::endl;
+ return -1;
+ }
+ }
+ if (!gotTr2xi18n) {
+ std::cout << "Did not find tr2xi18n in ui_mywidget.h" << std::endl;
+ return -1;
+ }
+ }
+ f.close();
+
+ return 0;
+}
diff --git a/Tests/QtAutogen/UicInterface/mywidget.cpp b/Tests/QtAutogen/UicInterface/mywidget.cpp
new file mode 100644
index 0000000..7cf1a13
--- /dev/null
+++ b/Tests/QtAutogen/UicInterface/mywidget.cpp
@@ -0,0 +1,14 @@
+
+#include "mywidget.h"
+
+MyWidget::MyWidget(QWidget* parent)
+ : QWidget(parent)
+ , ui(new Ui::MyWidget)
+{
+ ui->setupUi(this);
+}
+
+MyWidget::~MyWidget()
+{
+ delete ui;
+}
diff --git a/Tests/QtAutogen/UicInterface/mywidget.h b/Tests/QtAutogen/UicInterface/mywidget.h
new file mode 100644
index 0000000..320d433
--- /dev/null
+++ b/Tests/QtAutogen/UicInterface/mywidget.h
@@ -0,0 +1,26 @@
+
+#ifndef MYWIDGET_H
+#define MYWIDGET_H
+
+#include <memory>
+
+#include <QWidget>
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 3, 0)
+# include <klocalizedstring.h>
+#endif
+
+#include "ui_mywidget.h"
+
+class MyWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit MyWidget(QWidget* parent = 0);
+ ~MyWidget();
+
+private:
+ Ui::MyWidget* ui;
+};
+
+#endif
diff --git a/Tests/QtAutogen/UicInterface/mywidget.ui b/Tests/QtAutogen/UicInterface/mywidget.ui
new file mode 100644
index 0000000..b2b9cc5
--- /dev/null
+++ b/Tests/QtAutogen/UicInterface/mywidget.ui
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MyWidget</class>
+ <widget class="QWidget" name="MyWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <widget class="QPushButton" name="pushButton">
+ <property name="geometry">
+ <rect>
+ <x>110</x>
+ <y>40</y>
+ <width>81</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Special button</string>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UicNoGui/CMakeLists.txt b/Tests/QtAutogen/UicNoGui/CMakeLists.txt
new file mode 100644
index 0000000..076299d
--- /dev/null
+++ b/Tests/QtAutogen/UicNoGui/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.13)
+project(UicNoGui)
+include("../AutogenCoreTest.cmake")
+
+# This tests creates a target that has AUTOUIC enabled but does not
+# link against QtXWidgets.
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTORCC ON)
+
+add_subdirectory(MocOnly)
+add_subdirectory(NoQt)
+
+add_executable(uicNoGui main.cpp)
+target_link_libraries(uicNoGui mocOnly noQt)
diff --git a/Tests/QtAutogen/UicNoGui/MocOnly/CMakeLists.txt b/Tests/QtAutogen/UicNoGui/MocOnly/CMakeLists.txt
new file mode 100644
index 0000000..4fcd75f
--- /dev/null
+++ b/Tests/QtAutogen/UicNoGui/MocOnly/CMakeLists.txt
@@ -0,0 +1,3 @@
+# Library uses QtCore only (no Widgets)
+add_library(mocOnly main.cpp)
+target_link_libraries(mocOnly ${QT_QTCORE_TARGET})
diff --git a/Tests/QtAutogen/UicNoGui/MocOnly/main.cpp b/Tests/QtAutogen/UicNoGui/MocOnly/main.cpp
new file mode 100644
index 0000000..3091845
--- /dev/null
+++ b/Tests/QtAutogen/UicNoGui/MocOnly/main.cpp
@@ -0,0 +1,15 @@
+#include <QObject>
+
+class LocalObject : public QObject
+{
+ Q_OBJECT
+public:
+ LocalObject(){};
+};
+
+void mocOnly()
+{
+ LocalObject obj;
+}
+
+#include "main.moc"
diff --git a/Tests/QtAutogen/UicNoGui/NoQt/CMakeLists.txt b/Tests/QtAutogen/UicNoGui/NoQt/CMakeLists.txt
new file mode 100644
index 0000000..f2bf3ee
--- /dev/null
+++ b/Tests/QtAutogen/UicNoGui/NoQt/CMakeLists.txt
@@ -0,0 +1,2 @@
+# Library doesn't use or link against Qt at all
+add_library(noQt main.cpp)
diff --git a/Tests/QtAutogen/UicNoGui/NoQt/main.cpp b/Tests/QtAutogen/UicNoGui/NoQt/main.cpp
new file mode 100644
index 0000000..0052cc8
--- /dev/null
+++ b/Tests/QtAutogen/UicNoGui/NoQt/main.cpp
@@ -0,0 +1,4 @@
+
+void noQt()
+{
+}
diff --git a/Tests/QtAutogen/UicNoGui/main.cpp b/Tests/QtAutogen/UicNoGui/main.cpp
new file mode 100644
index 0000000..e90c60a
--- /dev/null
+++ b/Tests/QtAutogen/UicNoGui/main.cpp
@@ -0,0 +1,9 @@
+extern void mocOnly();
+extern void noQt();
+
+int main(int argc, char* argv[])
+{
+ mocOnly();
+ noQt();
+ return 0;
+}
diff --git a/Tests/QtAutogen/UicOnly/CMakeLists.txt b/Tests/QtAutogen/UicOnly/CMakeLists.txt
new file mode 100644
index 0000000..b163254
--- /dev/null
+++ b/Tests/QtAutogen/UicOnly/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.10)
+project(UicOnly)
+include("../AutogenGuiTest.cmake")
+
+# Test AUTOUIC being enabled only
+add_executable(uicOnly main.cpp UicOnly.cpp)
+set_property(TARGET uicOnly PROPERTY AUTOUIC ON)
+target_link_libraries(uicOnly ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/UicOnly/UicOnly.cpp b/Tests/QtAutogen/UicOnly/UicOnly.cpp
new file mode 100644
index 0000000..8eee6d2
--- /dev/null
+++ b/Tests/QtAutogen/UicOnly/UicOnly.cpp
@@ -0,0 +1,18 @@
+#include "ui_uiC.h"
+#include "ui_uiD.h"
+// AUTOUIC includes on the first two lines of a source file
+#include "UicOnly.hpp"
+
+UicOnly::UicOnly()
+ : uiA(new Ui::UiA)
+ , uiB(new Ui::UiB)
+{
+ Ui::UiC uiC;
+ Ui::UiD uiD;
+}
+
+UicOnly::~UicOnly()
+{
+ delete uiB;
+ delete uiA;
+}
diff --git a/Tests/QtAutogen/UicOnly/UicOnly.hpp b/Tests/QtAutogen/UicOnly/UicOnly.hpp
new file mode 100644
index 0000000..24e1e0b
--- /dev/null
+++ b/Tests/QtAutogen/UicOnly/UicOnly.hpp
@@ -0,0 +1,15 @@
+#include "ui_uiA.h"
+#include "ui_uiB.h"
+// AUTOUIC includes on the first two lines of a header file
+#include <QObject>
+
+class UicOnly : public QObject
+{
+public:
+ UicOnly();
+ ~UicOnly();
+
+private:
+ Ui::UiA* uiA;
+ Ui::UiB* uiB;
+};
diff --git a/Tests/QtAutogen/UicOnly/main.cpp b/Tests/QtAutogen/UicOnly/main.cpp
new file mode 100644
index 0000000..bdd242e
--- /dev/null
+++ b/Tests/QtAutogen/UicOnly/main.cpp
@@ -0,0 +1,7 @@
+#include "UicOnly.hpp"
+
+int main(int argc, char* argv[])
+{
+ UicOnly uicOnly;
+ return 0;
+}
diff --git a/Tests/QtAutogen/UicOnly/uiA.ui b/Tests/QtAutogen/UicOnly/uiA.ui
new file mode 100644
index 0000000..4c5762e
--- /dev/null
+++ b/Tests/QtAutogen/UicOnly/uiA.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UiA</class>
+ <widget class="QWidget" name="UiA">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UicOnly/uiB.ui b/Tests/QtAutogen/UicOnly/uiB.ui
new file mode 100644
index 0000000..6ca77de
--- /dev/null
+++ b/Tests/QtAutogen/UicOnly/uiB.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UiB</class>
+ <widget class="QWidget" name="UiB">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UicOnly/uiC.ui b/Tests/QtAutogen/UicOnly/uiC.ui
new file mode 100644
index 0000000..6802550
--- /dev/null
+++ b/Tests/QtAutogen/UicOnly/uiC.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UiC</class>
+ <widget class="QWidget" name="UiC">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UicOnly/uiD.ui b/Tests/QtAutogen/UicOnly/uiD.ui
new file mode 100644
index 0000000..aad79cf
--- /dev/null
+++ b/Tests/QtAutogen/UicOnly/uiD.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UiD</class>
+ <widget class="QWidget" name="UiD">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UicSkipSource/CMakeLists.txt b/Tests/QtAutogen/UicSkipSource/CMakeLists.txt
new file mode 100644
index 0000000..dc3b7d4e
--- /dev/null
+++ b/Tests/QtAutogen/UicSkipSource/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.10)
+project(UicSkipSource)
+include("../AutogenGuiTest.cmake")
+
+# Test for SKIP_AUTOUIC and SKIP_AUTOGEN on an AUTOUIC enabled target
+set(skipUicSources
+ skipUic.cpp
+ skipUicGen.cpp
+ skipUicNoGen1.cpp
+ skipUicNoGen2.cpp
+)
+set_property(SOURCE skipUicNoGen1.cpp PROPERTY SKIP_AUTOUIC ON)
+set_property(SOURCE skipUicNoGen2.cpp PROPERTY SKIP_AUTOGEN ON)
+# AUTOUIC enabled
+add_executable(skipUicA ${skipUicSources})
+set_property(TARGET skipUicA PROPERTY AUTOUIC ON)
+target_link_libraries(skipUicA ${QT_LIBRARIES})
+# AUTOUIC and AUTOMOC enabled
+add_executable(skipUicB ${skipUicSources})
+set_property(TARGET skipUicB PROPERTY AUTOUIC ON)
+set_property(TARGET skipUicB PROPERTY AUTOMOC ON)
+target_link_libraries(skipUicB ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/UicSkipSource/skipUic.cpp b/Tests/QtAutogen/UicSkipSource/skipUic.cpp
new file mode 100644
index 0000000..c4a7ce9
--- /dev/null
+++ b/Tests/QtAutogen/UicSkipSource/skipUic.cpp
@@ -0,0 +1,22 @@
+
+#include "skipUicGen.hpp"
+#include "skipUicNoGen1.hpp"
+#include "skipUicNoGen2.hpp"
+
+int main(int, char**)
+{
+ skipGen();
+ skipNoGen1();
+ skipNoGen2();
+
+ return 0;
+}
+
+// -- Function definitions
+void ui_nogen1()
+{
+}
+
+void ui_nogen2()
+{
+}
diff --git a/Tests/QtAutogen/UicSkipSource/skipUicGen.cpp b/Tests/QtAutogen/UicSkipSource/skipUicGen.cpp
new file mode 100644
index 0000000..ab3c454
--- /dev/null
+++ b/Tests/QtAutogen/UicSkipSource/skipUicGen.cpp
@@ -0,0 +1,8 @@
+
+#include "skipUicGen.hpp"
+
+#include "ui_uigen2.h"
+
+void skipGen()
+{
+}
diff --git a/Tests/QtAutogen/UicSkipSource/skipUicGen.hpp b/Tests/QtAutogen/UicSkipSource/skipUicGen.hpp
new file mode 100644
index 0000000..3669f0e
--- /dev/null
+++ b/Tests/QtAutogen/UicSkipSource/skipUicGen.hpp
@@ -0,0 +1,8 @@
+#ifndef SKIPUICGEN_HPP
+#define SKIPUICGEN_HPP
+
+#include "ui_uigen1.h"
+
+void skipGen();
+
+#endif
diff --git a/Tests/QtAutogen/UicSkipSource/skipUicNoGen1.cpp b/Tests/QtAutogen/UicSkipSource/skipUicNoGen1.cpp
new file mode 100644
index 0000000..d648d94
--- /dev/null
+++ b/Tests/QtAutogen/UicSkipSource/skipUicNoGen1.cpp
@@ -0,0 +1,8 @@
+
+#include "skipUicNoGen1.hpp"
+
+#include "ui_nogen2.h"
+
+void skipNoGen1()
+{
+}
diff --git a/Tests/QtAutogen/UicSkipSource/skipUicNoGen1.hpp b/Tests/QtAutogen/UicSkipSource/skipUicNoGen1.hpp
new file mode 100644
index 0000000..2864695
--- /dev/null
+++ b/Tests/QtAutogen/UicSkipSource/skipUicNoGen1.hpp
@@ -0,0 +1,8 @@
+#ifndef SKIPUICNOGEN1_H
+#define SKIPUICNOGEN1_H
+
+#include "ui_nogen1.h"
+
+void skipNoGen1();
+
+#endif
diff --git a/Tests/QtAutogen/UicSkipSource/skipUicNoGen2.cpp b/Tests/QtAutogen/UicSkipSource/skipUicNoGen2.cpp
new file mode 100644
index 0000000..aca58a4
--- /dev/null
+++ b/Tests/QtAutogen/UicSkipSource/skipUicNoGen2.cpp
@@ -0,0 +1,8 @@
+
+#include "skipUicNoGen2.hpp"
+
+#include "ui_nogen2.h"
+
+void skipNoGen2()
+{
+}
diff --git a/Tests/QtAutogen/UicSkipSource/skipUicNoGen2.hpp b/Tests/QtAutogen/UicSkipSource/skipUicNoGen2.hpp
new file mode 100644
index 0000000..7c38193
--- /dev/null
+++ b/Tests/QtAutogen/UicSkipSource/skipUicNoGen2.hpp
@@ -0,0 +1,8 @@
+#ifndef SKIPUICNOGEN2_H
+#define SKIPUICNOGEN2_H
+
+#include "ui_nogen1.h"
+
+void skipNoGen2();
+
+#endif
diff --git a/Tests/QtAutogen/UicSkipSource/ui_nogen1.h b/Tests/QtAutogen/UicSkipSource/ui_nogen1.h
new file mode 100644
index 0000000..a7be52b
--- /dev/null
+++ b/Tests/QtAutogen/UicSkipSource/ui_nogen1.h
@@ -0,0 +1,6 @@
+#ifndef UI_NOGEN1_H
+#define UI_NOGEN1_H
+
+void ui_nogen1();
+
+#endif
diff --git a/Tests/QtAutogen/UicSkipSource/ui_nogen2.h b/Tests/QtAutogen/UicSkipSource/ui_nogen2.h
new file mode 100644
index 0000000..4e500a4
--- /dev/null
+++ b/Tests/QtAutogen/UicSkipSource/ui_nogen2.h
@@ -0,0 +1,6 @@
+#ifndef UI_NOGEN2_H
+#define UI_NOGEN2_H
+
+void ui_nogen2();
+
+#endif
diff --git a/Tests/QtAutogen/UicSkipSource/uigen1.ui b/Tests/QtAutogen/UicSkipSource/uigen1.ui
new file mode 100644
index 0000000..fc7cb82
--- /dev/null
+++ b/Tests/QtAutogen/UicSkipSource/uigen1.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UiGen1</class>
+ <widget class="QWidget" name="UiGen1">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UicSkipSource/uigen2.ui b/Tests/QtAutogen/UicSkipSource/uigen2.ui
new file mode 100644
index 0000000..01f08d2
--- /dev/null
+++ b/Tests/QtAutogen/UicSkipSource/uigen2.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UiGen2</class>
+ <widget class="QWidget" name="UiGen2">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeView" name="treeView"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/UnityMocSource/CMakeLists.txt b/Tests/QtAutogen/UnityMocSource/CMakeLists.txt
new file mode 100644
index 0000000..d472319
--- /dev/null
+++ b/Tests/QtAutogen/UnityMocSource/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.16)
+project(UnityMocSource)
+include("../AutogenGuiTest.cmake")
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_UNITY_BUILD ON)
+
+add_library(library library.cpp)
+target_link_libraries(library ${QT_LIBRARIES})
+
+add_executable(unityMocSource main.cpp)
+target_link_libraries(unityMocSource PRIVATE library)
diff --git a/Tests/QtAutogen/UnityMocSource/library.cpp b/Tests/QtAutogen/UnityMocSource/library.cpp
new file mode 100644
index 0000000..1e30d4b
--- /dev/null
+++ b/Tests/QtAutogen/UnityMocSource/library.cpp
@@ -0,0 +1,6 @@
+#include <QObject>
+class Test : public QObject
+{
+ Q_OBJECT
+};
+#include "library.moc"
diff --git a/Tests/QtAutogen/UnityMocSource/main.cpp b/Tests/QtAutogen/UnityMocSource/main.cpp
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/QtAutogen/UnityMocSource/main.cpp
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/QtAutomocNoQt/CMakeLists.txt b/Tests/QtAutomocNoQt/CMakeLists.txt
new file mode 100644
index 0000000..655f12b
--- /dev/null
+++ b/Tests/QtAutomocNoQt/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(QtAutomocNoQt)
+
+set(CMAKE_AUTOMOC ON)
+
+add_executable(hello main.c)
diff --git a/Tests/QtAutomocNoQt/main.c b/Tests/QtAutomocNoQt/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/QtAutomocNoQt/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/README.rst b/Tests/README.rst
new file mode 100644
index 0000000..3e98938
--- /dev/null
+++ b/Tests/README.rst
@@ -0,0 +1,31 @@
+CMake Tests Directory
+*********************
+
+This directory contains the CMake test suite.
+See also the `CMake Source Code Guide`_.
+
+.. _`CMake Source Code Guide`: ../Help/dev/source.rst
+
+Many tests exist as immediate subdirectories, but some tests
+are organized as follows.
+
+* ``CMakeLib/``:
+ Source code, used for tests, that links to the ``CMakeLib`` library
+ defined over in ``Source/``.
+
+* ``CMakeOnly/``:
+ Deprecated. Tests that run CMake to generate a project but not build it.
+ Superseded by ``Tests/RunCMake/``.
+
+* ``Find*/``:
+ Tests for specific find modules that can only be run on machines with
+ the corresponding packages installed. They are enabled in
+ ``CMakeLists.txt`` by undocumented options used on CI builds.
+
+* ``Module/``:
+ Tests for specific CMake modules.
+
+* ``RunCMake/``:
+ Tests that run CMake and/or other tools while precisely checking
+ their return code and stdout/stderr content. Useful for testing
+ error cases and diagnostic output.
diff --git a/Tests/ReturnTest/CMakeLists.txt b/Tests/ReturnTest/CMakeLists.txt
new file mode 100644
index 0000000..78e3fc1
--- /dev/null
+++ b/Tests/ReturnTest/CMakeLists.txt
@@ -0,0 +1,147 @@
+# a simple C only test case
+cmake_minimum_required (VERSION 2.8.12)
+project (ReturnTest)
+
+function (FAILED testname)
+ message (SEND_ERROR "${testname} failed ${ARGN}")
+endfunction ()
+
+function (PASS testname)
+ message ("${testname} passed ${ARGN}")
+endfunction ()
+
+# test simple return
+function (simple)
+ set(simpleResult 1 PARENT_SCOPE)
+ return()
+ set(simpleResult 0 PARENT_SCOPE)
+endfunction ()
+simple()
+if ("${simpleResult}")
+ pass ("simple")
+else ()
+ failed ("simple got: ${simpleResult}")
+endif ()
+
+#test return in an if statement
+set (simple2IF 1)
+function (simple2)
+ set(simple2Result 1 PARENT_SCOPE)
+ if (simple2IF)
+ return()
+ endif ()
+ set(simple2Result 0 PARENT_SCOPE)
+endfunction ()
+simple2()
+if ("${simple2Result}")
+ pass ("simple2")
+else ()
+ failed ("simple2 got: ${simple2Result}")
+endif ()
+
+#test return in a foreach loop
+function (looptest)
+ foreach (iter RANGE 1 5)
+ set (looptestResult "${iter}" PARENT_SCOPE)
+ if ("${iter}" EQUAL 3)
+ return ()
+ endif ()
+ endforeach ()
+endfunction ()
+looptest()
+if ("${looptestResult}" EQUAL 3)
+ pass ("looptest")
+else ()
+ failed ("looptest got: ${looptestResult}")
+endif ()
+
+#test return in a while loop
+function (whiletest)
+ set (iter "a")
+ while(NOT "${iter}" STREQUAL "aaaaa")
+ set (whiletestResult "${iter}" PARENT_SCOPE)
+ if ("${iter}" STREQUAL "aaa")
+ return ()
+ endif ()
+ set (iter "${iter}a")
+ endwhile()
+endfunction ()
+whiletest()
+if ("${whiletestResult}" STREQUAL "aaa")
+ pass ("whiletest")
+else ()
+ failed ("whiletest got: ${whiletestResult}")
+endif ()
+
+# check subdir return
+add_subdirectory(subdir)
+get_directory_property(subdirResult DIRECTORY subdir DEFINITION subdirreturn)
+if ("${subdirResult}" EQUAL 1)
+ pass ("subdir")
+else ()
+ failed ("subdir got: ${subdirResult}")
+endif ()
+
+# check return from a file
+include(include_return.cmake)
+if ("${include_returnResult}" EQUAL 1)
+ pass ("include_return")
+else ()
+ failed ("include_return got: ${include_returnResult}")
+endif ()
+
+# check return from within a macro
+macro (mymacro)
+ set (foo 1)
+ if (foo)
+ return()
+ endif ()
+endmacro()
+
+# test simple return
+function (simple3)
+ set (bar 0)
+ set(simple3Result 1 PARENT_SCOPE)
+ if (bar)
+ else ()
+ mymacro()
+ endif()
+ set(simple3Result 0 PARENT_SCOPE)
+endfunction ()
+simple3()
+if ("${simple3Result}")
+ pass ("macrotest")
+else ()
+ failed ("macrotest got: ${simple3Result}")
+endif ()
+
+
+# test break command now in a foreach
+foreach (iter RANGE 1 5)
+ set (break1 "${iter}")
+ if ("${iter}" EQUAL 3)
+ break ()
+ endif ()
+endforeach ()
+if ("${break1}" EQUAL 3)
+ pass ("break in foreach")
+else ()
+ failed ("break in foreach got: ${break1}")
+endif ()
+
+# test break in a while loop
+set (iter "a")
+while(NOT "${iter}" STREQUAL "aaaaa")
+ if ("${iter}" STREQUAL "aaa")
+ break ()
+ endif ()
+ set (iter "${iter}a")
+endwhile()
+if ("${iter}" STREQUAL "aaa")
+ pass ("break in a while")
+else ()
+ failed ("break in a while got: ${whiletestResult}")
+endif ()
+
+
+add_executable (ReturnTest returnTest.c)
diff --git a/Tests/ReturnTest/include_return.cmake b/Tests/ReturnTest/include_return.cmake
new file mode 100644
index 0000000..7cea1fb
--- /dev/null
+++ b/Tests/ReturnTest/include_return.cmake
@@ -0,0 +1,3 @@
+set(include_returnResult 1)
+return()
+set(include_returnResult 0)
diff --git a/Tests/ReturnTest/returnTest.c b/Tests/ReturnTest/returnTest.c
new file mode 100644
index 0000000..e0ced6a
--- /dev/null
+++ b/Tests/ReturnTest/returnTest.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char* argv[])
+{
+ printf("Running command: %s with %d arguments\n", argv[0], argc);
+ return 0;
+}
diff --git a/Tests/ReturnTest/subdir/CMakeLists.txt b/Tests/ReturnTest/subdir/CMakeLists.txt
new file mode 100644
index 0000000..b951092
--- /dev/null
+++ b/Tests/ReturnTest/subdir/CMakeLists.txt
@@ -0,0 +1,3 @@
+set (subdirreturn 1)
+return()
+set (subdirreturn 0)
diff --git a/Tests/RunCMake/ABI/C-stdout.txt b/Tests/RunCMake/ABI/C-stdout.txt
new file mode 100644
index 0000000..5b67b84
--- /dev/null
+++ b/Tests/RunCMake/ABI/C-stdout.txt
@@ -0,0 +1 @@
+-- Check if the system is big endian
diff --git a/Tests/RunCMake/ABI/C.cmake b/Tests/RunCMake/ABI/C.cmake
new file mode 100644
index 0000000..92f5da4
--- /dev/null
+++ b/Tests/RunCMake/ABI/C.cmake
@@ -0,0 +1,22 @@
+enable_language(C)
+if(NOT CMAKE_C_BYTE_ORDER MATCHES "^(BIG_ENDIAN|LITTLE_ENDIAN)$")
+ if(CMAKE_OSX_ARCHITECTURES MATCHES ";ppc|ppc;")
+ return()
+ endif()
+ message(FATAL_ERROR "CMAKE_C_BYTE_ORDER has unexpected value '${CMAKE_C_BYTE_ORDER}'")
+endif()
+
+include(TestBigEndian)
+test_big_endian(IS_BIG_ENDIAN)
+if(IS_BIG_ENDIAN AND NOT CMAKE_C_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+ message(FATAL_ERROR "test_big_endian result does not match ABI result")
+endif()
+
+# Test legacy check.
+set(byte_order "${CMAKE_C_BYTE_ORDER}")
+unset(CMAKE_C_BYTE_ORDER)
+include(TestBigEndian)
+test_big_endian(IS_BIG)
+if(IS_BIG AND NOT byte_order STREQUAL "BIG_ENDIAN")
+ message(FATAL_ERROR "test_big_endian result does not match ABI result")
+endif()
diff --git a/Tests/RunCMake/ABI/CMakeLists.txt b/Tests/RunCMake/ABI/CMakeLists.txt
new file mode 100644
index 0000000..ab1a20c
--- /dev/null
+++ b/Tests/RunCMake/ABI/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/ABI/CUDA.cmake b/Tests/RunCMake/ABI/CUDA.cmake
new file mode 100644
index 0000000..8ede3a9
--- /dev/null
+++ b/Tests/RunCMake/ABI/CUDA.cmake
@@ -0,0 +1,13 @@
+enable_language(CUDA)
+if(NOT CMAKE_CUDA_BYTE_ORDER MATCHES "^(BIG_ENDIAN|LITTLE_ENDIAN)$")
+ if(CMAKE_OSX_ARCHITECTURES MATCHES ";ppc|ppc;")
+ return()
+ endif()
+ message(FATAL_ERROR "CMAKE_CUDA_BYTE_ORDER has unexpected value '${CMAKE_CUDA_BYTE_ORDER}'")
+endif()
+
+include(TestBigEndian)
+test_big_endian(IS_BIG_ENDIAN)
+if(IS_BIG_ENDIAN AND NOT CMAKE_CUDA_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+ message(FATAL_ERROR "test_big_endian result does not match ABI result")
+endif()
diff --git a/Tests/RunCMake/ABI/CXX-stdout.txt b/Tests/RunCMake/ABI/CXX-stdout.txt
new file mode 100644
index 0000000..5b67b84
--- /dev/null
+++ b/Tests/RunCMake/ABI/CXX-stdout.txt
@@ -0,0 +1 @@
+-- Check if the system is big endian
diff --git a/Tests/RunCMake/ABI/CXX.cmake b/Tests/RunCMake/ABI/CXX.cmake
new file mode 100644
index 0000000..2310002
--- /dev/null
+++ b/Tests/RunCMake/ABI/CXX.cmake
@@ -0,0 +1,22 @@
+enable_language(CXX)
+if(NOT CMAKE_CXX_BYTE_ORDER MATCHES "^(BIG_ENDIAN|LITTLE_ENDIAN)$")
+ if(CMAKE_OSX_ARCHITECTURES MATCHES ";ppc|ppc;")
+ return()
+ endif()
+ message(FATAL_ERROR "CMAKE_CXX_BYTE_ORDER has unexpected value '${CMAKE_CXX_BYTE_ORDER}'")
+endif()
+
+include(TestBigEndian)
+test_big_endian(IS_BIG_ENDIAN)
+if(IS_BIG_ENDIAN AND NOT CMAKE_CXX_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+ message(FATAL_ERROR "test_big_endian result does not match ABI result")
+endif()
+
+# Test legacy check.
+set(byte_order "${CMAKE_CXX_BYTE_ORDER}")
+unset(CMAKE_CXX_BYTE_ORDER)
+include(TestBigEndian)
+test_big_endian(IS_BIG)
+if(IS_BIG AND NOT byte_order STREQUAL "BIG_ENDIAN")
+ message(FATAL_ERROR "test_big_endian result does not match ABI result")
+endif()
diff --git a/Tests/RunCMake/ABI/OBJC.cmake b/Tests/RunCMake/ABI/OBJC.cmake
new file mode 100644
index 0000000..ab67459
--- /dev/null
+++ b/Tests/RunCMake/ABI/OBJC.cmake
@@ -0,0 +1,13 @@
+enable_language(OBJC)
+if(NOT CMAKE_OBJC_BYTE_ORDER MATCHES "^(BIG_ENDIAN|LITTLE_ENDIAN)$")
+ if(CMAKE_OSX_ARCHITECTURES MATCHES ";ppc|ppc;")
+ return()
+ endif()
+ message(FATAL_ERROR "CMAKE_OBJC_BYTE_ORDER has unexpected value '${CMAKE_OBJC_BYTE_ORDER}'")
+endif()
+
+include(TestBigEndian)
+test_big_endian(IS_BIG_ENDIAN)
+if(IS_BIG_ENDIAN AND NOT CMAKE_OBJC_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+ message(FATAL_ERROR "test_big_endian result does not match ABI result")
+endif()
diff --git a/Tests/RunCMake/ABI/OBJCXX.cmake b/Tests/RunCMake/ABI/OBJCXX.cmake
new file mode 100644
index 0000000..41a719e
--- /dev/null
+++ b/Tests/RunCMake/ABI/OBJCXX.cmake
@@ -0,0 +1,13 @@
+enable_language(OBJCXX)
+if(NOT CMAKE_OBJCXX_BYTE_ORDER MATCHES "^(BIG_ENDIAN|LITTLE_ENDIAN)$")
+ if(CMAKE_OSX_ARCHITECTURES MATCHES ";ppc|ppc;")
+ return()
+ endif()
+ message(FATAL_ERROR "CMAKE_OBJCXX_BYTE_ORDER has unexpected value '${CMAKE_OBJCXX_BYTE_ORDER}'")
+endif()
+
+include(TestBigEndian)
+test_big_endian(IS_BIG_ENDIAN)
+if(IS_BIG_ENDIAN AND NOT CMAKE_OBJCXX_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+ message(FATAL_ERROR "test_big_endian result does not match ABI result")
+endif()
diff --git a/Tests/RunCMake/ABI/RunCMakeTest.cmake b/Tests/RunCMake/ABI/RunCMakeTest.cmake
new file mode 100644
index 0000000..d9eabb7
--- /dev/null
+++ b/Tests/RunCMake/ABI/RunCMakeTest.cmake
@@ -0,0 +1,15 @@
+include(RunCMake)
+
+run_cmake(C)
+run_cmake(CXX)
+
+if(APPLE)
+ run_cmake(OBJC)
+ run_cmake(OBJCXX)
+endif()
+
+if(CMake_TEST_CUDA)
+ run_cmake(CUDA)
+endif()
+
+run_cmake(TestBigEndian-NoLang)
diff --git a/Tests/RunCMake/ABI/TestBigEndian-NoLang-result.txt b/Tests/RunCMake/ABI/TestBigEndian-NoLang-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/ABI/TestBigEndian-NoLang-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/ABI/TestBigEndian-NoLang-stderr.txt b/Tests/RunCMake/ABI/TestBigEndian-NoLang-stderr.txt
new file mode 100644
index 0000000..d0aa899
--- /dev/null
+++ b/Tests/RunCMake/ABI/TestBigEndian-NoLang-stderr.txt
@@ -0,0 +1,8 @@
+^CMake Error at [^
+]*/Modules/TestBigEndian.cmake:[0-9]+ \(message\):
+ TEST_BIG_ENDIAN needs either C or CXX language enabled
+Call Stack \(most recent call first\):
+ [^
+]*/Modules/TestBigEndian.cmake:[0-9]+ \(__TEST_BIG_ENDIAN_LEGACY_IMPL\)
+ TestBigEndian-NoLang.cmake:[0-9]+ \(test_big_endian\)
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/ABI/TestBigEndian-NoLang.cmake b/Tests/RunCMake/ABI/TestBigEndian-NoLang.cmake
new file mode 100644
index 0000000..8c10201
--- /dev/null
+++ b/Tests/RunCMake/ABI/TestBigEndian-NoLang.cmake
@@ -0,0 +1,2 @@
+include(TestBigEndian)
+test_big_endian(var)
diff --git a/Tests/RunCMake/Android/BadSYSROOT-result.txt b/Tests/RunCMake/Android/BadSYSROOT-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/Android/BadSYSROOT-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Android/BadSYSROOT-stderr.txt b/Tests/RunCMake/Android/BadSYSROOT-stderr.txt
new file mode 100644
index 0000000..e17ca03
--- /dev/null
+++ b/Tests/RunCMake/Android/BadSYSROOT-stderr.txt
@@ -0,0 +1,20 @@
+^CMake Error at .*/Modules/Platform/Android-Determine.cmake:[0-9]+ \(message\):
+ The value of CMAKE_SYSROOT:
+
+ .*
+
+ does not match any of the forms:
+
+ <ndk>/platforms/android-<api>/arch-<arch>
+ <standalone-toolchain>/sysroot
+
+ where:
+
+ <ndk> = Android NDK directory \(with forward slashes\)
+ <api> = Android API version number \(decimal digits\)
+ <arch> = Android ARCH name \(lower case\)
+ <standalone-toolchain> = Path to standalone toolchain prefix
+
+Call Stack \(most recent call first\):
+ .*/Modules/CMakeDetermineSystem.cmake:[0-9]+ \(include\)
+ CMakeLists.txt:2 \(project\)$
diff --git a/Tests/RunCMake/Android/BadSYSROOT.cmake b/Tests/RunCMake/Android/BadSYSROOT.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/Android/BadSYSROOT.cmake
diff --git a/Tests/RunCMake/Android/CMakeLists.txt b/Tests/RunCMake/Android/CMakeLists.txt
new file mode 100644
index 0000000..dc92486
--- /dev/null
+++ b/Tests/RunCMake/Android/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.6)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/Android/RunCMakeTest.cmake b/Tests/RunCMake/Android/RunCMakeTest.cmake
new file mode 100644
index 0000000..aa0cf4d
--- /dev/null
+++ b/Tests/RunCMake/Android/RunCMakeTest.cmake
@@ -0,0 +1,285 @@
+cmake_minimum_required(VERSION 3.6)
+
+include(RunCMake)
+foreach(v TEST_ANDROID_NDK TEST_ANDROID_STANDALONE_TOOLCHAIN)
+ string(REPLACE "|" ";" ${v} "${${v}}")
+endforeach()
+
+function(run_Android case)
+ set(RunCMake_TEST_OPTIONS
+ -DCMAKE_SYSTEM_NAME=Android
+ ${RunCMake_TEST_OPTIONS}
+ ${ARGN}
+ )
+
+ # Use a single build tree for a few tests without cleaning.
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ run_cmake(${case})
+ set(configs ".")
+ if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(configs Release Debug)
+ endif()
+ foreach(config IN LISTS configs)
+ set(build_suffix)
+ set(config_arg)
+ if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(build_suffix "-${config}")
+ set(config_arg --config "${config}")
+ endif()
+ run_cmake_command(${case}-build${build_suffix} ${CMAKE_COMMAND} --build . ${config_arg})
+ endforeach()
+endfunction()
+
+set(RunCMake_GENERATOR_PLATFORM_OLD "${RunCMake_GENERATOR_PLATFORM}")
+
+if(RunCMake_GENERATOR MATCHES "Visual Studio")
+ set(RunCMake_GENERATOR_PLATFORM "ARM")
+endif()
+set(RunCMake_TEST_OPTIONS
+ -DCMAKE_SYSTEM_NAME=Android
+ -DCMAKE_SYSROOT=${CMAKE_CURRENT_SOURCE_DIR}
+ )
+run_cmake(BadSYSROOT)
+unset(RunCMake_TEST_OPTIONS)
+set(RunCMake_GENERATOR_PLATFORM "${RunCMake_GENERATOR_PLATFORM_OLD}")
+
+foreach(ndk IN LISTS TEST_ANDROID_NDK)
+ # Load available toolchain versions and abis.
+ file(GLOB _config_mks
+ "${ndk}/build/core/toolchains/*/config.mk"
+ "${ndk}/toolchains/*/config.mk"
+ )
+ set(_versions "")
+ set(_latest_gcc 0)
+ set(_latest_clang "")
+ set(_latest_clang_vers 0)
+ foreach(config_mk IN LISTS _config_mks)
+ file(STRINGS "${config_mk}" _abis REGEX "^TOOLCHAIN_ABIS +:= +[^ ].*( |$)")
+ if(_abis AND "${config_mk}" MATCHES [[-((clang)?([0-9]\.[0-9]|))/config\.mk$]])
+ set(_version "${CMAKE_MATCH_1}")
+ set(_is_clang "${CMAKE_MATCH_2}")
+ set(_cur_vers "${CMAKE_MATCH_3}")
+ if(_is_clang)
+ if(_latest_clang_vers STREQUAL "")
+ # already the latest possible
+ elseif(_cur_vers STREQUAL "" OR _cur_vers VERSION_GREATER _latest_clang_vers)
+ set(_latest_clang_vers "${_cur_vers}")
+ set(_latest_clang "${_version}")
+ endif()
+ else()
+ if(_version VERSION_GREATER _latest_gcc)
+ set(_latest_gcc ${_version})
+ endif()
+ endif()
+ list(APPEND _versions "${_version}")
+ string(REGEX MATCHALL "[a-z][a-z0-9_-]+" _abis "${_abis}")
+ list(APPEND _abis_${_version} ${_abis})
+ endif()
+ endforeach()
+ set(_abis_clang ${_abis_${_latest_clang}})
+ if(_latest_gcc)
+ set(_abis_ ${_abis_${_latest_gcc}})
+ else()
+ set(_abis_ ${_abis_clang})
+ endif()
+ if(_versions MATCHES "clang")
+ set(_versions "clang" ${_versions})
+ endif()
+ if(RunCMake_GENERATOR MATCHES "Visual Studio")
+ set(_versions "clang")
+ endif()
+ list(REMOVE_DUPLICATES _versions)
+ list(SORT _versions)
+ set(_versions ";${_versions}")
+ foreach(vers IN LISTS _versions)
+ list(REMOVE_DUPLICATES _abis_${vers})
+ endforeach()
+
+ set(ndk_arg -DCMAKE_ANDROID_NDK=${ndk})
+ if(RunCMake_GENERATOR MATCHES "Visual Studio")
+ set(ndk_arg)
+ endif()
+
+ set(RunCMake_TEST_OPTIONS
+ -DCMAKE_SYSTEM_NAME=Android
+ -DCMAKE_FIND_ROOT_PATH=/tmp
+ ${ndk_arg}
+ )
+ run_cmake(ndk-search-order)
+
+ # Test failure cases.
+ message(STATUS "ndk='${ndk}'")
+ if(RunCMake_GENERATOR MATCHES "Visual Studio")
+ set(RunCMake_GENERATOR_PLATFORM "ARM")
+ endif()
+ set(RunCMake_TEST_OPTIONS
+ -DCMAKE_SYSTEM_NAME=Android
+ ${ndk_arg}
+ -DCMAKE_ANDROID_ARCH_ABI=badabi
+ )
+ run_cmake(ndk-badabi)
+ if(RunCMake_GENERATOR MATCHES "Visual Studio")
+ set(RunCMake_GENERATOR_PLATFORM "x86")
+ endif()
+ set(RunCMake_TEST_OPTIONS
+ -DCMAKE_SYSTEM_NAME=Android
+ ${ndk_arg}
+ -DCMAKE_ANDROID_ARCH_ABI=x86
+ -DCMAKE_ANDROID_ARM_MODE=0
+ )
+ run_cmake(ndk-badarm)
+ if(RunCMake_GENERATOR MATCHES "Visual Studio")
+ set(RunCMake_GENERATOR_PLATFORM "ARM")
+ endif()
+ if("armeabi" IN_LIST _abis_)
+ set(RunCMake_TEST_OPTIONS
+ -DCMAKE_SYSTEM_NAME=Android
+ ${ndk_arg}
+ -DCMAKE_ANDROID_ARM_NEON=0
+ )
+ run_cmake(ndk-badneon)
+ endif()
+ set(RunCMake_TEST_OPTIONS
+ -DCMAKE_SYSTEM_NAME=Android
+ ${ndk_arg}
+ -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=badver
+ )
+ run_cmake(ndk-badver)
+ set(RunCMake_TEST_OPTIONS
+ -DCMAKE_SYSTEM_NAME=Android
+ ${ndk_arg}
+ -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=1.0
+ )
+ run_cmake(ndk-badvernum)
+ set(RunCMake_TEST_OPTIONS
+ -DCMAKE_SYSTEM_NAME=Android
+ ${ndk_arg}
+ -DCMAKE_ANDROID_STL_TYPE=badstl
+ )
+ run_cmake(ndk-badstl)
+ unset(RunCMake_TEST_OPTIONS)
+
+ # Find a sysroot to test.
+ file(GLOB _sysroots "${ndk}/platforms/android-[0-9][0-9]/arch-arm")
+ if(_sysroots AND "armeabi" IN_LIST _abis_)
+ list(GET _sysroots 0 _sysroot)
+ set(RunCMake_TEST_OPTIONS
+ -DCMAKE_SYSTEM_NAME=Android
+ -DCMAKE_SYSROOT=${_sysroot}
+ )
+ run_cmake(ndk-sysroot-armeabi)
+ unset(RunCMake_TEST_OPTIONS)
+ endif()
+ set(RunCMake_GENERATOR_PLATFORM "${RunCMake_GENERATOR_PLATFORM_OLD}")
+
+ # Find available STLs.
+ set(stl_types
+ none
+ system
+ )
+
+ if(IS_DIRECTORY "${ndk}/sources/cxx-stl/gnu-libstdc++")
+ list(APPEND stl_types gnustl_static gnustl_shared)
+ endif()
+ if(IS_DIRECTORY "${ndk}/sources/cxx-stl/gabi++/libs")
+ list(APPEND stl_types gabi++_static gabi++_shared)
+ endif()
+ if(IS_DIRECTORY "${ndk}/sources/cxx-stl/stlport/libs")
+ list(APPEND stl_types stlport_static stlport_shared)
+ endif()
+ if(IS_DIRECTORY "${ndk}/sources/cxx-stl/llvm-libc++/libs")
+ list(APPEND stl_types c++_static c++_shared)
+ endif()
+
+ # List possible ABIs.
+ set(abi_names
+ armeabi
+ armeabi-v6
+ armeabi-v7a
+ arm64-v8a
+ x86
+ x86_64
+ )
+ if(NOT RunCMake_GENERATOR MATCHES "Visual Studio")
+ list(APPEND abi_names mips mips64)
+ endif()
+ set(abi_to_arch_armeabi ARM)
+ set(abi_to_arch_armeabi-v6 ARM)
+ set(abi_to_arch_armeabi-v7a ARM)
+ set(abi_to_arch_arm64-v8a ARM64)
+ set(abi_to_arch_x86 x86)
+ set(abi_to_arch_x86_64 x64)
+
+ # Test all combinations.
+ foreach(vers IN LISTS _versions)
+ foreach(stl IN LISTS stl_types)
+ set(configs Release Debug)
+ set(foreach_list "${configs}")
+ if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(foreach_list ".")
+ endif()
+ foreach(config IN LISTS foreach_list)
+ # Test this combination for all available abis.
+ set(config_status " config='${config}'")
+ set(build_type_arg "-DCMAKE_BUILD_TYPE=${config}")
+ if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(config_status)
+ string(REPLACE ";" "\\\\;" build_type_arg "-DCMAKE_CONFIGURATION_TYPES=${configs}")
+ endif()
+ message(STATUS "ndk='${ndk}' vers='${vers}' stl='${stl}'${config_status}")
+ set(RunCMake_TEST_OPTIONS
+ ${ndk_arg}
+ -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=${vers}
+ -DCMAKE_ANDROID_STL_TYPE=${stl}
+ "${build_type_arg}"
+ )
+ foreach(abi IN LISTS abi_names)
+ # Skip ABIs not supported by this compiler.
+ if(NOT ";${_abis_${vers}};" MATCHES ";${abi};")
+ continue()
+ endif()
+
+ # Run the tests for this combination.
+ if(RunCMake_GENERATOR MATCHES "Visual Studio")
+ set(RunCMake_GENERATOR_PLATFORM "${abi_to_arch_${abi}}")
+ endif()
+ if("${abi}" STREQUAL "armeabi")
+ run_Android(ndk-armeabi-thumb) # default: -DCMAKE_ANDROID_ARCH_ABI=armeabi -DCMAKE_ANDROID_ARM_MODE=0
+ run_Android(ndk-armeabi-arm -DCMAKE_ANDROID_ARM_MODE=1) # default: -DCMAKE_ANDROID_ARCH_ABI=armeabi
+ else()
+ run_Android(ndk-${abi} -DCMAKE_ANDROID_ARCH_ABI=${abi})
+ if("${abi}" STREQUAL "armeabi-v7a")
+ run_Android(ndk-${abi}-neon -DCMAKE_ANDROID_ARCH_ABI=${abi} -DCMAKE_ANDROID_ARM_NEON=1)
+ endif()
+ endif()
+ set(RunCMake_GENERATOR_PLATFORM "${RunCMake_GENERATOR_PLATFORM_OLD}")
+ endforeach()
+ unset(RunCMake_TEST_OPTIONS)
+ endforeach()
+ endforeach()
+ endforeach()
+endforeach()
+
+foreach(toolchain IN LISTS TEST_ANDROID_STANDALONE_TOOLCHAIN)
+ message(STATUS "toolchain='${toolchain}'")
+
+ set(RunCMake_TEST_OPTIONS
+ -DCMAKE_SYSTEM_NAME=Android
+ -DCMAKE_SYSROOT=${toolchain}/sysroot
+ )
+ run_cmake(standalone-sysroot)
+ unset(RunCMake_TEST_OPTIONS)
+
+ foreach(config Release Debug)
+ message(STATUS "toolchain='${toolchain}' config='${config}'")
+ set(RunCMake_TEST_OPTIONS
+ -DCMAKE_ANDROID_STANDALONE_TOOLCHAIN=${toolchain}
+ -DCMAKE_BUILD_TYPE=${config}
+ )
+ run_Android(standalone)
+ unset(RunCMake_TEST_OPTIONS)
+ endforeach()
+endforeach()
diff --git a/Tests/RunCMake/Android/android.c b/Tests/RunCMake/Android/android.c
new file mode 100644
index 0000000..30e8574
--- /dev/null
+++ b/Tests/RunCMake/Android/android.c
@@ -0,0 +1,6 @@
+#include "android.h"
+
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/Android/android.cxx b/Tests/RunCMake/Android/android.cxx
new file mode 100644
index 0000000..a6d8c55
--- /dev/null
+++ b/Tests/RunCMake/Android/android.cxx
@@ -0,0 +1,48 @@
+#include "android.h"
+
+#ifndef STL_NONE
+# include <cmath>
+# include <cstdio>
+# ifndef STL_SYSTEM
+# include <exception>
+# include <typeinfo>
+# ifndef STL_STLPORT
+# include <cxxabi.h>
+# endif
+# ifndef STL_GABI
+# include <iostream>
+# include <string>
+# endif
+# endif
+#endif
+
+int main()
+{
+#if !defined(STL_NONE)
+ // Require -lm implied by linking as C++.
+ std::printf("%p\n", static_cast<double (*)(double)>(&std::sin));
+#endif
+#if defined(STL_NONE)
+ return 0;
+#elif defined(STL_SYSTEM)
+ return 0;
+#else
+ try {
+ delete (new int);
+ } catch (std::exception const& e) {
+# if defined(STL_GABI)
+ e.what();
+ typeid(e).name();
+# else
+ std::cerr << e.what() << std::endl;
+ std::cerr << typeid(e).name() << std::endl;
+# endif
+ }
+# if defined(STL_GABI)
+ return 0;
+# else
+ std::string s;
+ return static_cast<int>(s.size());
+# endif
+#endif
+}
diff --git a/Tests/RunCMake/Android/android.h b/Tests/RunCMake/Android/android.h
new file mode 100644
index 0000000..2c5cd95
--- /dev/null
+++ b/Tests/RunCMake/Android/android.h
@@ -0,0 +1,103 @@
+#ifndef __ANDROID__
+# error "__ANDROID__ not defined"
+#endif
+
+#include <android/api-level.h>
+
+#if API_LEVEL != __ANDROID_API__
+# error "API levels do not match"
+#endif
+
+#ifdef COMPILER_IS_CLANG
+# ifndef __clang__
+# error "COMPILER_IS_CLANG but __clang__ is not defined"
+# endif
+#else
+# ifdef __clang__
+# error "!COMPILER_IS_CLANG but __clang__ is defined"
+# endif
+#endif
+
+#ifdef ARM_MODE
+# if ARM_MODE == 1 && defined(__thumb__)
+# error "ARM_MODE==1 but __thumb__ is defined"
+# elif ARM_MODE == 0 && !defined(__thumb__)
+# error "ARM_MODE==0 but __thumb__ is not defined"
+# endif
+#endif
+
+#ifdef ARM_NEON
+# if ARM_NEON == 0 && defined(__ARM_NEON__)
+# error "ARM_NEON==0 but __ARM_NEON__ is defined"
+# elif ARM_NEON == 1 && !defined(__ARM_NEON__)
+# error "ARM_NEON==1 but __ARM_NEON__ is not defined"
+# endif
+#endif
+
+#ifdef ABI_armeabi
+# ifndef __ARM_EABI__
+# error "ABI_armeabi: __ARM_EABI__ not defined"
+# endif
+# if __ARM_ARCH != 5
+# error "ABI_armeabi: __ARM_ARCH is not 5"
+# endif
+#endif
+
+#ifdef ABI_armeabi_v6
+# ifndef __ARM_EABI__
+# error "ABI_armeabi_v6: __ARM_EABI__ not defined"
+# endif
+# if __ARM_ARCH != 6
+# error "ABI_armeabi_v6: __ARM_ARCH is not 6"
+# endif
+#endif
+
+#ifdef ABI_armeabi_v7a
+# ifndef __ARM_EABI__
+# error "ABI_armeabi_v7a: __ARM_EABI__ not defined"
+# endif
+# if __ARM_ARCH != 7
+# error "ABI_armeabi_v7a: __ARM_ARCH is not 7"
+# endif
+#endif
+
+#ifdef ABI_arm64_v8a
+# ifdef __ARM_EABI__
+# error "ABI_arm64_v8a: __ARM_EABI__ defined"
+# endif
+# ifndef __aarch64__
+# error "ABI_arm64_v8a: __aarch64__ not defined"
+# endif
+#endif
+
+#ifdef ABI_mips
+# if __mips != 32
+# error "ABI_mips: __mips != 32"
+# endif
+# ifndef _ABIO32
+# error "ABI_mips: _ABIO32 not defined"
+# endif
+#endif
+
+#ifdef ABI_mips64
+# if __mips != 64
+# error "ABI_mips64: __mips != 64"
+# endif
+# ifndef _ABI64
+# error "ABI_mips: _ABI64 not defined"
+# endif
+#endif
+
+#ifdef ABI_x86
+# ifndef __i686__
+# error "ABI_x86: __i686__ not defined"
+# endif
+#endif
+
+#ifdef ABI_x86_64
+# ifndef __x86_64__
+# error "ABI_x86_64: __x86_64__ not defined"
+# endif
+#endif
+
+#include <stddef.h>
diff --git a/Tests/RunCMake/Android/android_lib.cxx b/Tests/RunCMake/Android/android_lib.cxx
new file mode 100644
index 0000000..82f9d27
--- /dev/null
+++ b/Tests/RunCMake/Android/android_lib.cxx
@@ -0,0 +1,4 @@
+int android_lib()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/Android/android_sysinc.c b/Tests/RunCMake/Android/android_sysinc.c
new file mode 100644
index 0000000..f7cc6f0
--- /dev/null
+++ b/Tests/RunCMake/Android/android_sysinc.c
@@ -0,0 +1,7 @@
+#include <dlfcn.h>
+
+#ifndef NOT_SYSTEM_DLFCN_HEADER
+# error "sysroot /usr/include appears too early"
+#endif
+
+#include "android.c"
diff --git a/Tests/RunCMake/Android/android_sysinc.cxx b/Tests/RunCMake/Android/android_sysinc.cxx
new file mode 100644
index 0000000..9379f14
--- /dev/null
+++ b/Tests/RunCMake/Android/android_sysinc.cxx
@@ -0,0 +1,7 @@
+#include <dlfcn.h>
+
+#ifndef NOT_SYSTEM_DLFCN_HEADER
+# error "sysroot /usr/include appears too early"
+#endif
+
+#include "android.cxx"
diff --git a/Tests/RunCMake/Android/check_binary.cmake b/Tests/RunCMake/Android/check_binary.cmake
new file mode 100644
index 0000000..1d1b01a
--- /dev/null
+++ b/Tests/RunCMake/Android/check_binary.cmake
@@ -0,0 +1,8 @@
+if(NOT EXISTS "${file}")
+ message(FATAL_ERROR "Missing file:\n ${file}")
+endif()
+execute_process(COMMAND "${objdump}" -p ${file} OUTPUT_VARIABLE out)
+if(out MATCHES "NEEDED[^\n]*stdc\\+\\+")
+ string(REPLACE "\n" "\n " out " ${out}")
+ message(FATAL_ERROR "File:\n ${file}\ndepends on libstdc++:\n${out}")
+endif()
diff --git a/Tests/RunCMake/Android/common.cmake b/Tests/RunCMake/Android/common.cmake
new file mode 100644
index 0000000..7c80a04
--- /dev/null
+++ b/Tests/RunCMake/Android/common.cmake
@@ -0,0 +1,140 @@
+enable_language(C)
+enable_language(CXX)
+
+if(NOT ANDROID)
+ message(SEND_ERROR "CMake variable 'ANDROID' is not set to a true value.")
+endif()
+
+set(files
+ "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}ar${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}"
+ )
+if(NOT CMAKE_ANDROID_NDK_VERSION VERSION_GREATER_EQUAL 22)
+ list(APPEND files
+ "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}ld${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}"
+ )
+endif()
+if(NOT CMAKE_ANDROID_NDK_VERSION VERSION_GREATER_EQUAL 19)
+ list(APPEND files
+ "${CMAKE_C_ANDROID_TOOLCHAIN_PREFIX}gcc${CMAKE_C_ANDROID_TOOLCHAIN_SUFFIX}"
+ "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}g++${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}"
+ )
+endif()
+foreach(f IN LISTS files)
+ if(NOT EXISTS "${f}")
+ message(SEND_ERROR "Expected file does not exist:\n \"${f}\"")
+ endif()
+endforeach()
+
+string(APPEND CMAKE_C_FLAGS " -Werror -Wno-attributes")
+string(APPEND CMAKE_CXX_FLAGS " -Werror -Wno-attributes")
+string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-no-undefined")
+
+if(CMAKE_ANDROID_NDK)
+ if(NOT CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION)
+ message(SEND_ERROR "CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION is not set!")
+ elseif(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION MATCHES "^clang")
+ add_definitions(-DCOMPILER_IS_CLANG)
+ elseif(NOT "${CMAKE_C_COMPILER}" MATCHES "toolchains/[^/]+-${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}/prebuilt")
+ message(SEND_ERROR "CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION is\n"
+ " ${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}\n"
+ "which does not appear in CMAKE_C_COMPILER:\n"
+ " ${CMAKE_C_COMPILER}")
+ endif()
+ if(NOT CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG)
+ message(SEND_ERROR "CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG is not set!")
+ elseif(NOT "${CMAKE_C_COMPILER}" MATCHES "prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}/bin")
+ message(SEND_ERROR "CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG is\n"
+ " ${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}\n"
+ "which does not appear in CMAKE_C_COMPILER:\n"
+ " ${CMAKE_C_COMPILER}")
+ endif()
+elseif(CMAKE_ANDROID_STANDALONE_TOOLCHAIN)
+ execute_process(
+ COMMAND ${CMAKE_ANDROID_STANDALONE_TOOLCHAIN}/bin/clang --version
+ OUTPUT_VARIABLE _out
+ ERROR_VARIABLE _err
+ RESULT_VARIABLE _res
+ )
+ if(_res EQUAL 0)
+ add_definitions(-DCOMPILER_IS_CLANG)
+ endif()
+endif()
+
+set(gcc ${CMAKE_C_ANDROID_TOOLCHAIN_PREFIX}gcc${CMAKE_C_ANDROID_TOOLCHAIN_SUFFIX})
+if(EXISTS "${gcc}")
+ execute_process(
+ COMMAND "${CMAKE_C_ANDROID_TOOLCHAIN_PREFIX}gcc${CMAKE_C_ANDROID_TOOLCHAIN_SUFFIX}" -dumpmachine
+ OUTPUT_VARIABLE _out OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE _err
+ RESULT_VARIABLE _res
+ )
+ if(NOT _res EQUAL 0)
+ message(SEND_ERROR "Failed to run 'gcc -dumpmachine':\n ${_res}")
+ endif()
+ string(REPLACE "--" "-" _out_check "${_out}")
+ if(NOT _out_check STREQUAL "${CMAKE_C_ANDROID_TOOLCHAIN_MACHINE}"
+ AND NOT (_out STREQUAL "arm--linux-android" AND CMAKE_C_ANDROID_TOOLCHAIN_MACHINE STREQUAL "arm-linux-androideabi"))
+ message(SEND_ERROR "'gcc -dumpmachine' produced:\n"
+ " ${_out}\n"
+ "which does not match CMAKE_C_ANDROID_TOOLCHAIN_MACHINE:\n"
+ " ${CMAKE_C_ANDROID_TOOLCHAIN_MACHINE}"
+ )
+ endif()
+endif()
+
+if(CMAKE_ANDROID_STL_TYPE STREQUAL "none")
+ add_definitions(-DSTL_NONE)
+elseif(CMAKE_ANDROID_STL_TYPE STREQUAL "system")
+ add_definitions(-DSTL_SYSTEM)
+elseif(CMAKE_ANDROID_STL_TYPE MATCHES [[^gabi\+\+]])
+ add_definitions(-DSTL_GABI)
+elseif(CMAKE_ANDROID_STL_TYPE MATCHES [[^stlport]])
+ add_definitions(-DSTL_STLPORT)
+endif()
+
+string(REPLACE "-" "_" abi "${CMAKE_ANDROID_ARCH_ABI}")
+add_definitions(-DABI_${abi})
+add_definitions(-DAPI_LEVEL=${CMAKE_SYSTEM_VERSION})
+if(CMAKE_ANDROID_ARCH_ABI MATCHES "^armeabi")
+ add_definitions(-DARM_MODE=${CMAKE_ANDROID_ARM_MODE})
+ message(STATUS "CMAKE_ANDROID_ARM_MODE=${CMAKE_ANDROID_ARM_MODE}")
+endif()
+if(CMAKE_ANDROID_ARCH_ABI STREQUAL "armeabi-v7a")
+ add_definitions(-DARM_NEON=${CMAKE_ANDROID_ARM_NEON})
+ message(STATUS "CMAKE_ANDROID_ARM_NEON=${CMAKE_ANDROID_ARM_NEON}")
+endif()
+add_executable(android_c android.c)
+add_executable(android_cxx android.cxx)
+add_library(android_cxx_lib SHARED android_lib.cxx)
+
+set(objdump "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}objdump${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}")
+if(NOT EXISTS "${objdump}")
+ message(FATAL_ERROR "Expected tool missing:\n ${objdump}")
+endif()
+
+if(NOT CMAKE_ANDROID_STL_TYPE MATCHES "^(system|stlport_static|stlport_shared)$")
+ foreach(tgt android_cxx android_cxx_lib)
+ add_custom_command(TARGET ${tgt} POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ -Dobjdump=${objdump}
+ -Dfile=$<TARGET_FILE:${tgt}>
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/check_binary.cmake
+ )
+ endforeach()
+endif()
+
+# Test that an explicit /usr/include is ignored in favor of
+# appearing as a standard include directory at the end.
+set(sysinc_dirs)
+if(CMAKE_ANDROID_NDK)
+ if(NOT CMAKE_ANDROID_NDK_DEPRECATED_HEADERS)
+ list(APPEND sysinc_dirs ${CMAKE_SYSROOT_COMPILE}/usr/include)
+ else()
+ list(APPEND sysinc_dirs ${CMAKE_SYSROOT}/usr/include)
+ endif()
+endif()
+list(APPEND sysinc_dirs ${CMAKE_CURRENT_SOURCE_DIR}/sysinc)
+add_executable(android_sysinc_c android_sysinc.c)
+target_include_directories(android_sysinc_c SYSTEM PRIVATE ${sysinc_dirs})
+add_executable(android_sysinc_cxx android_sysinc.cxx)
+target_include_directories(android_sysinc_cxx SYSTEM PRIVATE ${sysinc_dirs})
diff --git a/Tests/RunCMake/Android/ndk-arm64-v8a-stderr.txt b/Tests/RunCMake/Android/ndk-arm64-v8a-stderr.txt
new file mode 100644
index 0000000..a3b3634
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-arm64-v8a-stderr.txt
@@ -0,0 +1,7 @@
+^(CMake Warning:
+ You are using Visual Studio tools for Android, which does not support
+ standalone executables\. However, the following executable targets do not
+ have the ANDROID_GUI property set, and thus will not be built as expected\.
+ They will be built as shared libraries with executable filenames:
+
+ android_c, android_cxx, android_sysinc_c, android_sysinc_cxx)?$
diff --git a/Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt b/Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt
new file mode 100644
index 0000000..a228ccc
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt
@@ -0,0 +1,2 @@
+-- Android: Targeting API '[0-9]+' with architecture 'arm64', ABI 'arm64-v8a', and processor 'aarch64'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
diff --git a/Tests/RunCMake/Android/ndk-arm64-v8a.cmake b/Tests/RunCMake/Android/ndk-arm64-v8a.cmake
new file mode 100644
index 0000000..a3185fe
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-arm64-v8a.cmake
@@ -0,0 +1 @@
+include(common.cmake)
diff --git a/Tests/RunCMake/Android/ndk-armeabi-arm-stderr.txt b/Tests/RunCMake/Android/ndk-armeabi-arm-stderr.txt
new file mode 100644
index 0000000..a3b3634
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-armeabi-arm-stderr.txt
@@ -0,0 +1,7 @@
+^(CMake Warning:
+ You are using Visual Studio tools for Android, which does not support
+ standalone executables\. However, the following executable targets do not
+ have the ANDROID_GUI property set, and thus will not be built as expected\.
+ They will be built as shared libraries with executable filenames:
+
+ android_c, android_cxx, android_sysinc_c, android_sysinc_cxx)?$
diff --git a/Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt b/Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt
new file mode 100644
index 0000000..72ec00e
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt
@@ -0,0 +1,3 @@
+-- Android: Targeting API '[0-9]+' with architecture 'arm', ABI 'armeabi', and processor 'armv5te'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
+.*-- CMAKE_ANDROID_ARM_MODE=1
diff --git a/Tests/RunCMake/Android/ndk-armeabi-arm.cmake b/Tests/RunCMake/Android/ndk-armeabi-arm.cmake
new file mode 100644
index 0000000..a3185fe
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-armeabi-arm.cmake
@@ -0,0 +1 @@
+include(common.cmake)
diff --git a/Tests/RunCMake/Android/ndk-armeabi-thumb-stderr.txt b/Tests/RunCMake/Android/ndk-armeabi-thumb-stderr.txt
new file mode 100644
index 0000000..a3b3634
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-armeabi-thumb-stderr.txt
@@ -0,0 +1,7 @@
+^(CMake Warning:
+ You are using Visual Studio tools for Android, which does not support
+ standalone executables\. However, the following executable targets do not
+ have the ANDROID_GUI property set, and thus will not be built as expected\.
+ They will be built as shared libraries with executable filenames:
+
+ android_c, android_cxx, android_sysinc_c, android_sysinc_cxx)?$
diff --git a/Tests/RunCMake/Android/ndk-armeabi-thumb-stdout.txt b/Tests/RunCMake/Android/ndk-armeabi-thumb-stdout.txt
new file mode 100644
index 0000000..ce0dea2
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-armeabi-thumb-stdout.txt
@@ -0,0 +1,3 @@
+-- Android: Targeting API '[0-9]+' with architecture 'arm', ABI 'armeabi', and processor 'armv5te'
+-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
+.*-- CMAKE_ANDROID_ARM_MODE=0
diff --git a/Tests/RunCMake/Android/ndk-armeabi-thumb.cmake b/Tests/RunCMake/Android/ndk-armeabi-thumb.cmake
new file mode 100644
index 0000000..a3185fe
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-armeabi-thumb.cmake
@@ -0,0 +1 @@
+include(common.cmake)
diff --git a/Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stderr.txt b/Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stderr.txt
new file mode 100644
index 0000000..a3b3634
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stderr.txt
@@ -0,0 +1,7 @@
+^(CMake Warning:
+ You are using Visual Studio tools for Android, which does not support
+ standalone executables\. However, the following executable targets do not
+ have the ANDROID_GUI property set, and thus will not be built as expected\.
+ They will be built as shared libraries with executable filenames:
+
+ android_c, android_cxx, android_sysinc_c, android_sysinc_cxx)?$
diff --git a/Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stdout.txt b/Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stdout.txt
new file mode 100644
index 0000000..8bd87fa
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stdout.txt
@@ -0,0 +1,3 @@
+-- Android: Targeting API '[0-9]+' with architecture 'arm', ABI 'armeabi-v7a', and processor 'armv7-a'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
+.*-- CMAKE_ANDROID_ARM_NEON=1
diff --git a/Tests/RunCMake/Android/ndk-armeabi-v7a-neon.cmake b/Tests/RunCMake/Android/ndk-armeabi-v7a-neon.cmake
new file mode 100644
index 0000000..a3185fe
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-armeabi-v7a-neon.cmake
@@ -0,0 +1 @@
+include(common.cmake)
diff --git a/Tests/RunCMake/Android/ndk-armeabi-v7a-stderr.txt b/Tests/RunCMake/Android/ndk-armeabi-v7a-stderr.txt
new file mode 100644
index 0000000..a3b3634
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-armeabi-v7a-stderr.txt
@@ -0,0 +1,7 @@
+^(CMake Warning:
+ You are using Visual Studio tools for Android, which does not support
+ standalone executables\. However, the following executable targets do not
+ have the ANDROID_GUI property set, and thus will not be built as expected\.
+ They will be built as shared libraries with executable filenames:
+
+ android_c, android_cxx, android_sysinc_c, android_sysinc_cxx)?$
diff --git a/Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt b/Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt
new file mode 100644
index 0000000..554548e
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt
@@ -0,0 +1,3 @@
+-- Android: Targeting API '[0-9]+' with architecture 'arm', ABI 'armeabi-v7a', and processor 'armv7-a'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
+.*-- CMAKE_ANDROID_ARM_NEON=0
diff --git a/Tests/RunCMake/Android/ndk-armeabi-v7a.cmake b/Tests/RunCMake/Android/ndk-armeabi-v7a.cmake
new file mode 100644
index 0000000..a3185fe
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-armeabi-v7a.cmake
@@ -0,0 +1 @@
+include(common.cmake)
diff --git a/Tests/RunCMake/Android/ndk-badabi-result.txt b/Tests/RunCMake/Android/ndk-badabi-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badabi-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Android/ndk-badabi-stderr.txt b/Tests/RunCMake/Android/ndk-badabi-stderr.txt
new file mode 100644
index 0000000..c089235
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badabi-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at .*/Modules/Platform/Android-Determine.cmake:[0-9]+ \(message\):
+ Android: Unknown ABI CMAKE_ANDROID_ARCH_ABI='badabi'.
+Call Stack \(most recent call first\):
+ .*/Modules/CMakeDetermineSystem.cmake:[0-9]+ \(include\)
+ CMakeLists.txt:[0-9]+ \(project\)$
diff --git a/Tests/RunCMake/Android/ndk-badabi.cmake b/Tests/RunCMake/Android/ndk-badabi.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badabi.cmake
diff --git a/Tests/RunCMake/Android/ndk-badarm-result.txt b/Tests/RunCMake/Android/ndk-badarm-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badarm-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Android/ndk-badarm-stderr.txt b/Tests/RunCMake/Android/ndk-badarm-stderr.txt
new file mode 100644
index 0000000..f62bfc4
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badarm-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error at .*/Modules/Platform/Android-Determine.cmake:[0-9]+ \(message\):
+ Android: CMAKE_ANDROID_ARM_MODE is set but is valid only for 'armeabi'
+ architectures.
+Call Stack \(most recent call first\):
+ .*/Modules/CMakeDetermineSystem.cmake:[0-9]+ \(include\)
+ CMakeLists.txt:[0-9]+ \(project\)$
diff --git a/Tests/RunCMake/Android/ndk-badarm.cmake b/Tests/RunCMake/Android/ndk-badarm.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badarm.cmake
diff --git a/Tests/RunCMake/Android/ndk-badneon-result.txt b/Tests/RunCMake/Android/ndk-badneon-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badneon-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Android/ndk-badneon-stderr.txt b/Tests/RunCMake/Android/ndk-badneon-stderr.txt
new file mode 100644
index 0000000..1f0bf00
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badneon-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error at .*/Modules/Platform/Android-Determine.cmake:[0-9]+ \(message\):
+ Android: CMAKE_ANDROID_ARM_NEON is set but is valid only for 'armeabi-v7a'
+ architecture.
+Call Stack \(most recent call first\):
+ .*/Modules/CMakeDetermineSystem.cmake:[0-9]+ \(include\)
+ CMakeLists.txt:[0-9]+ \(project\)$
diff --git a/Tests/RunCMake/Android/ndk-badneon.cmake b/Tests/RunCMake/Android/ndk-badneon.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badneon.cmake
diff --git a/Tests/RunCMake/Android/ndk-badstl-result.txt b/Tests/RunCMake/Android/ndk-badstl-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badstl-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Android/ndk-badstl-stderr.txt b/Tests/RunCMake/Android/ndk-badstl-stderr.txt
new file mode 100644
index 0000000..c61824e
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badstl-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Error at .*/Modules/Platform/Android-Common.cmake:[0-9]+ \(message\):
+ The CMAKE_ANDROID_STL_TYPE 'badstl' is not one of the allowed values:
+
+ .*
+
+Call Stack \(most recent call first\):
+.*
+ ndk-badstl.cmake:1 \(enable_language\)
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/Android/ndk-badstl.cmake b/Tests/RunCMake/Android/ndk-badstl.cmake
new file mode 100644
index 0000000..fa2fc91
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badstl.cmake
@@ -0,0 +1 @@
+enable_language(CXX)
diff --git a/Tests/RunCMake/Android/ndk-badver-result.txt b/Tests/RunCMake/Android/ndk-badver-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badver-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Android/ndk-badver-stderr.txt b/Tests/RunCMake/Android/ndk-badver-stderr.txt
new file mode 100644
index 0000000..ce6bc4e
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badver-stderr.txt
@@ -0,0 +1,13 @@
+^CMake Error at .*/Modules/Platform/Android/Determine-Compiler-NDK.cmake:[0-9]+ \(message\):
+ Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value 'badver' is not(
+ supported by this NDK. It must be 'clang' or not set at all\.| one
+ of the allowed forms:
+
+ <major>.<minor> = GCC of specified version
+ clang<major>.<minor> = Clang of specified version
+ clang = Clang of most recent available version
+)
+Call Stack \(most recent call first\):
+.*
+ ndk-badver.cmake:1 \(enable_language\)
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/Android/ndk-badver.cmake b/Tests/RunCMake/Android/ndk-badver.cmake
new file mode 100644
index 0000000..c00af08
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badver.cmake
@@ -0,0 +1 @@
+enable_language(C)
diff --git a/Tests/RunCMake/Android/ndk-badvernum-result.txt b/Tests/RunCMake/Android/ndk-badvernum-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badvernum-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Android/ndk-badvernum-stderr.txt b/Tests/RunCMake/Android/ndk-badvernum-stderr.txt
new file mode 100644
index 0000000..aec91d9
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badvernum-stderr.txt
@@ -0,0 +1,15 @@
+^CMake Error at .*/Modules/Platform/Android/Determine-Compiler-NDK.cmake:[0-9]+ \(message\):(
+ Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value '1.0' is not
+ supported by this NDK. It must be 'clang' or not set at all.|
+ Android: No toolchain for ABI 'armeabi(-v7a)?' found in the NDK:
+
+ .*
+
+ of the version specified by CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION:
+
+ 1\.0
+)
+Call Stack \(most recent call first\):
+.*
+ ndk-badvernum.cmake:1 \(enable_language\)
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/Android/ndk-badvernum.cmake b/Tests/RunCMake/Android/ndk-badvernum.cmake
new file mode 100644
index 0000000..c00af08
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-badvernum.cmake
@@ -0,0 +1 @@
+enable_language(C)
diff --git a/Tests/RunCMake/Android/ndk-mips-stdout.txt b/Tests/RunCMake/Android/ndk-mips-stdout.txt
new file mode 100644
index 0000000..8ce544d
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-mips-stdout.txt
@@ -0,0 +1,2 @@
+-- Android: Targeting API '[0-9]+' with architecture 'mips', ABI 'mips', and processor 'mips'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
diff --git a/Tests/RunCMake/Android/ndk-mips.cmake b/Tests/RunCMake/Android/ndk-mips.cmake
new file mode 100644
index 0000000..a3185fe
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-mips.cmake
@@ -0,0 +1 @@
+include(common.cmake)
diff --git a/Tests/RunCMake/Android/ndk-mips64-stdout.txt b/Tests/RunCMake/Android/ndk-mips64-stdout.txt
new file mode 100644
index 0000000..1d7edea
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-mips64-stdout.txt
@@ -0,0 +1,2 @@
+-- Android: Targeting API '[0-9]+' with architecture 'mips64', ABI 'mips64', and processor 'mips64'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
diff --git a/Tests/RunCMake/Android/ndk-mips64.cmake b/Tests/RunCMake/Android/ndk-mips64.cmake
new file mode 100644
index 0000000..a3185fe
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-mips64.cmake
@@ -0,0 +1 @@
+include(common.cmake)
diff --git a/Tests/RunCMake/Android/ndk-search-order.cmake b/Tests/RunCMake/Android/ndk-search-order.cmake
new file mode 100644
index 0000000..498d775
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-search-order.cmake
@@ -0,0 +1,17 @@
+if(NOT CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+ return()
+endif()
+
+find_library(LIBDL dl)
+if(NOT LIBDL)
+ message(FATAL_ERROR "libdl not found.")
+endif()
+
+if(LIBDL MATCHES ".a$")
+ message(FATAL_ERROR "found libdl.a")
+endif()
+
+find_program(CLANG clang)
+if(NOT CLANG)
+ message(FATAL_ERROR "clang not found")
+endif()
diff --git a/Tests/RunCMake/Android/ndk-sysroot-armeabi-stdout.txt b/Tests/RunCMake/Android/ndk-sysroot-armeabi-stdout.txt
new file mode 100644
index 0000000..d309e72
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-sysroot-armeabi-stdout.txt
@@ -0,0 +1 @@
+-- Android: Targeting API '[0-9][0-9]' with architecture 'arm', ABI 'armeabi', and processor 'armv5te'
diff --git a/Tests/RunCMake/Android/ndk-sysroot-armeabi.cmake b/Tests/RunCMake/Android/ndk-sysroot-armeabi.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-sysroot-armeabi.cmake
diff --git a/Tests/RunCMake/Android/ndk-x86-stderr.txt b/Tests/RunCMake/Android/ndk-x86-stderr.txt
new file mode 100644
index 0000000..a3b3634
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-x86-stderr.txt
@@ -0,0 +1,7 @@
+^(CMake Warning:
+ You are using Visual Studio tools for Android, which does not support
+ standalone executables\. However, the following executable targets do not
+ have the ANDROID_GUI property set, and thus will not be built as expected\.
+ They will be built as shared libraries with executable filenames:
+
+ android_c, android_cxx, android_sysinc_c, android_sysinc_cxx)?$
diff --git a/Tests/RunCMake/Android/ndk-x86-stdout.txt b/Tests/RunCMake/Android/ndk-x86-stdout.txt
new file mode 100644
index 0000000..8d710fe
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-x86-stdout.txt
@@ -0,0 +1,2 @@
+-- Android: Targeting API '[0-9]+' with architecture 'x86', ABI 'x86', and processor 'i686'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
diff --git a/Tests/RunCMake/Android/ndk-x86.cmake b/Tests/RunCMake/Android/ndk-x86.cmake
new file mode 100644
index 0000000..a3185fe
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-x86.cmake
@@ -0,0 +1 @@
+include(common.cmake)
diff --git a/Tests/RunCMake/Android/ndk-x86_64-stderr.txt b/Tests/RunCMake/Android/ndk-x86_64-stderr.txt
new file mode 100644
index 0000000..a3b3634
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-x86_64-stderr.txt
@@ -0,0 +1,7 @@
+^(CMake Warning:
+ You are using Visual Studio tools for Android, which does not support
+ standalone executables\. However, the following executable targets do not
+ have the ANDROID_GUI property set, and thus will not be built as expected\.
+ They will be built as shared libraries with executable filenames:
+
+ android_c, android_cxx, android_sysinc_c, android_sysinc_cxx)?$
diff --git a/Tests/RunCMake/Android/ndk-x86_64-stdout.txt b/Tests/RunCMake/Android/ndk-x86_64-stdout.txt
new file mode 100644
index 0000000..695a088
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-x86_64-stdout.txt
@@ -0,0 +1,2 @@
+-- Android: Targeting API '[0-9]+' with architecture 'x86_64', ABI 'x86_64', and processor 'x86_64'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
diff --git a/Tests/RunCMake/Android/ndk-x86_64.cmake b/Tests/RunCMake/Android/ndk-x86_64.cmake
new file mode 100644
index 0000000..a3185fe
--- /dev/null
+++ b/Tests/RunCMake/Android/ndk-x86_64.cmake
@@ -0,0 +1 @@
+include(common.cmake)
diff --git a/Tests/RunCMake/Android/standalone-stdout.txt b/Tests/RunCMake/Android/standalone-stdout.txt
new file mode 100644
index 0000000..20b095c
--- /dev/null
+++ b/Tests/RunCMake/Android/standalone-stdout.txt
@@ -0,0 +1 @@
+-- Android: Targeting API '[0-9]+' with architecture '[a-z0-9_-]+', ABI '[a-z0-9_-]+', and processor '[a-z0-9_-]+'
diff --git a/Tests/RunCMake/Android/standalone-sysroot-stdout.txt b/Tests/RunCMake/Android/standalone-sysroot-stdout.txt
new file mode 100644
index 0000000..20b095c
--- /dev/null
+++ b/Tests/RunCMake/Android/standalone-sysroot-stdout.txt
@@ -0,0 +1 @@
+-- Android: Targeting API '[0-9]+' with architecture '[a-z0-9_-]+', ABI '[a-z0-9_-]+', and processor '[a-z0-9_-]+'
diff --git a/Tests/RunCMake/Android/standalone-sysroot.cmake b/Tests/RunCMake/Android/standalone-sysroot.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/Android/standalone-sysroot.cmake
diff --git a/Tests/RunCMake/Android/standalone.cmake b/Tests/RunCMake/Android/standalone.cmake
new file mode 100644
index 0000000..a3185fe
--- /dev/null
+++ b/Tests/RunCMake/Android/standalone.cmake
@@ -0,0 +1 @@
+include(common.cmake)
diff --git a/Tests/RunCMake/Android/sysinc/dlfcn.h b/Tests/RunCMake/Android/sysinc/dlfcn.h
new file mode 100644
index 0000000..273306c
--- /dev/null
+++ b/Tests/RunCMake/Android/sysinc/dlfcn.h
@@ -0,0 +1 @@
+#define NOT_SYSTEM_DLFCN_HEADER
diff --git a/Tests/RunCMake/AndroidMK/AndroidMK-check.cmake b/Tests/RunCMake/AndroidMK/AndroidMK-check.cmake
new file mode 100644
index 0000000..691e326
--- /dev/null
+++ b/Tests/RunCMake/AndroidMK/AndroidMK-check.cmake
@@ -0,0 +1,30 @@
+# This file does a regex file compare on the generated
+# Android.mk files from the AndroidMK test
+
+macro(compare_file_to_expected file expected_file)
+ file(READ "${file}" ANDROID_MK)
+ # clean up new lines
+ string(REGEX REPLACE "\r\n" "\n" ANDROID_MK "${ANDROID_MK}")
+ string(REGEX REPLACE "\n+$" "" ANDROID_MK "${ANDROID_MK}")
+ # read in the expected regex file
+ file(READ "${expected_file}" expected)
+ # clean up new lines
+ string(REGEX REPLACE "\r\n" "\n" expected "${expected}")
+ string(REGEX REPLACE "\n+$" "" expected "${expected}")
+ # compare the file to the expected regex and if there is not a match
+ # put an error message in RunCMake_TEST_FAILED
+ if(NOT "${ANDROID_MK}" MATCHES "${expected}")
+ set(RunCMake_TEST_FAILED
+ "${file} does not match ${expected_file}:
+
+Android.mk contents = [\n${ANDROID_MK}\n]
+Expected = [\n${expected}\n]")
+ endif()
+endmacro()
+
+compare_file_to_expected(
+"${RunCMake_BINARY_DIR}/AndroidMK-build/Android.mk"
+"${RunCMake_TEST_SOURCE_DIR}/expectedBuildAndroidMK.txt")
+compare_file_to_expected(
+"${RunCMake_BINARY_DIR}/AndroidMK-build/CMakeFiles/Export/share/ndk-modules/Android.mk"
+"${RunCMake_TEST_SOURCE_DIR}/expectedInstallAndroidMK.txt")
diff --git a/Tests/RunCMake/AndroidMK/AndroidMK.cmake b/Tests/RunCMake/AndroidMK/AndroidMK.cmake
new file mode 100644
index 0000000..9137f2b
--- /dev/null
+++ b/Tests/RunCMake/AndroidMK/AndroidMK.cmake
@@ -0,0 +1,13 @@
+project(build)
+set(CMAKE_BUILD_TYPE Debug)
+add_library(foo foo.cxx)
+add_library(car foo.cxx)
+add_library(bar bar.c)
+add_library(dog foo.cxx)
+target_link_libraries(foo PRIVATE car bar dog debug -lm)
+add_library(foo2 foo.cxx)
+target_link_options(foo2 INTERFACE -lm)
+export(TARGETS bar dog car foo foo2 ANDROID_MK
+ ${build_BINARY_DIR}/Android.mk)
+install(TARGETS bar dog car foo foo2 DESTINATION lib EXPORT myexp)
+install(EXPORT_ANDROID_MK myexp DESTINATION share/ndk-modules)
diff --git a/Tests/RunCMake/AndroidMK/CMakeLists.txt b/Tests/RunCMake/AndroidMK/CMakeLists.txt
new file mode 100644
index 0000000..576787a
--- /dev/null
+++ b/Tests/RunCMake/AndroidMK/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.5)
+project(${RunCMake_TEST} NONE) # or languages needed
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/AndroidMK/RunCMakeTest.cmake b/Tests/RunCMake/AndroidMK/RunCMakeTest.cmake
new file mode 100644
index 0000000..786d45b
--- /dev/null
+++ b/Tests/RunCMake/AndroidMK/RunCMakeTest.cmake
@@ -0,0 +1,2 @@
+include(RunCMake)
+run_cmake(AndroidMK)
diff --git a/Tests/RunCMake/AndroidMK/bar.c b/Tests/RunCMake/AndroidMK/bar.c
new file mode 100644
index 0000000..e1f4df6
--- /dev/null
+++ b/Tests/RunCMake/AndroidMK/bar.c
@@ -0,0 +1,3 @@
+void bar(void)
+{
+}
diff --git a/Tests/RunCMake/AndroidMK/expectedBuildAndroidMK.txt b/Tests/RunCMake/AndroidMK/expectedBuildAndroidMK.txt
new file mode 100644
index 0000000..a0e5044
--- /dev/null
+++ b/Tests/RunCMake/AndroidMK/expectedBuildAndroidMK.txt
@@ -0,0 +1,34 @@
+LOCAL_PATH.*call my-dir.*
+include.*CLEAR_VARS.*
+LOCAL_MODULE.*bar
+LOCAL_SRC_FILES.*bar.*
+include.*PREBUILT_STATIC_LIBRARY.*
+.*
+include.*CLEAR_VARS.*
+LOCAL_MODULE.*dog
+LOCAL_SRC_FILES.*.*dog.*
+LOCAL_HAS_CPP := true
+include.*PREBUILT_STATIC_LIBRARY.*
+.*
+include.*CLEAR_VARS.*
+LOCAL_MODULE.*car
+LOCAL_SRC_FILES.*.*car.*
+LOCAL_HAS_CPP := true
+include.*PREBUILT_STATIC_LIBRARY.*
+.*
+include.*CLEAR_VARS.*
+LOCAL_MODULE.*foo
+LOCAL_SRC_FILES.*.*foo.*
+LOCAL_CPP_FEATURES.*rtti exceptions
+LOCAL_STATIC_LIBRARIES.*car bar dog
+LOCAL_EXPORT_LDLIBS := -lm
+LOCAL_HAS_CPP := true
+include.*PREBUILT_STATIC_LIBRARY.*
+.*
+include.*CLEAR_VARS.*
+LOCAL_MODULE.*foo2
+LOCAL_SRC_FILES.*.*foo2.*
+LOCAL_CPP_FEATURES.*rtti exceptions
+LOCAL_EXPORT_LDFLAGS := -lm
+LOCAL_HAS_CPP := true
+include.*PREBUILT_STATIC_LIBRARY.*
diff --git a/Tests/RunCMake/AndroidMK/expectedInstallAndroidMK.txt b/Tests/RunCMake/AndroidMK/expectedInstallAndroidMK.txt
new file mode 100644
index 0000000..28b1c21
--- /dev/null
+++ b/Tests/RunCMake/AndroidMK/expectedInstallAndroidMK.txt
@@ -0,0 +1,36 @@
+LOCAL_PATH.*call my-dir.*
+_IMPORT_PREFIX.*LOCAL_PATH./../..
+
+include.*CLEAR_VARS.*
+LOCAL_MODULE.*bar
+LOCAL_SRC_FILES.*_IMPORT_PREFIX./lib.*bar.*
+include.*PREBUILT_STATIC_LIBRARY.*
+
+include.*CLEAR_VARS.
+LOCAL_MODULE.*dog
+LOCAL_SRC_FILES.*_IMPORT_PREFIX./lib.*dog.*
+LOCAL_HAS_CPP := true
+include.*PREBUILT_STATIC_LIBRARY.*
+
+include.*CLEAR_VARS.*
+LOCAL_MODULE.*car
+LOCAL_SRC_FILES.*_IMPORT_PREFIX./lib.*car.*
+LOCAL_HAS_CPP := true
+include.*PREBUILT_STATIC_LIBRARY.*
+
+include.*CLEAR_VARS.*
+LOCAL_MODULE.*foo
+LOCAL_SRC_FILES.*_IMPORT_PREFIX\)/lib.*foo.*
+LOCAL_CPP_FEATURES.*rtti exceptions
+LOCAL_STATIC_LIBRARIES.*car bar dog
+LOCAL_EXPORT_LDLIBS := -lm
+LOCAL_HAS_CPP := true
+include.*PREBUILT_STATIC_LIBRARY.*
+
+include.*CLEAR_VARS.*
+LOCAL_MODULE.*foo2
+LOCAL_SRC_FILES.*_IMPORT_PREFIX\)/lib.*foo2.*
+LOCAL_CPP_FEATURES.*rtti exceptions
+LOCAL_EXPORT_LDFLAGS := -lm
+LOCAL_HAS_CPP := true
+include.*PREBUILT_STATIC_LIBRARY.*
diff --git a/Tests/RunCMake/AndroidMK/foo.cxx b/Tests/RunCMake/AndroidMK/foo.cxx
new file mode 100644
index 0000000..3695dc9
--- /dev/null
+++ b/Tests/RunCMake/AndroidMK/foo.cxx
@@ -0,0 +1,3 @@
+void foo()
+{
+}
diff --git a/Tests/RunCMake/AndroidTestUtilities/CMakeLists.txt b/Tests/RunCMake/AndroidTestUtilities/CMakeLists.txt
new file mode 100644
index 0000000..dc92486
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.6)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/AndroidTestUtilities/RunCMakeTest.cmake b/Tests/RunCMake/AndroidTestUtilities/RunCMakeTest.cmake
new file mode 100644
index 0000000..7d031d4
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/RunCMakeTest.cmake
@@ -0,0 +1,21 @@
+include(RunCMake)
+
+function(run_ATU case target)
+ # Use a single build tree for a few tests without cleaning.
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ if(target)
+ set(build_args --target ${target})
+ else()
+ set(build_args)
+ endif()
+ run_cmake(${case})
+ run_cmake_command(${case}Build ${CMAKE_COMMAND} --build . --config Debug ${build_args})
+endfunction()
+
+run_ATU(SetupTest1 "")
+run_ATU(SetupTest2 "tests")
+run_ATU(SetupTest3 "tests")
+run_ATU(SetupTest4 "")
diff --git a/Tests/RunCMake/AndroidTestUtilities/SetupTest1.cmake b/Tests/RunCMake/AndroidTestUtilities/SetupTest1.cmake
new file mode 100644
index 0000000..1c9098b
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/SetupTest1.cmake
@@ -0,0 +1,17 @@
+enable_testing()
+include(AndroidTestUtilities)
+
+find_program(adb_executable adb)
+
+set(ExternalData_URL_TEMPLATES
+ "https://data.kitware.com/api/v1/file/hashsum/%(algo)/%(hash)/download"
+ )
+
+set(test_files "data/a.txt")
+
+set(ANDROID 1)
+
+android_add_test_data(setup_test
+ FILES ${test_files}
+ DEVICE_TEST_DIR "/data/local/tests/example1"
+ DEVICE_OBJECT_STORE "/sdcard/.ExternalData/SHA")
diff --git a/Tests/RunCMake/AndroidTestUtilities/SetupTest1Build-check.cmake b/Tests/RunCMake/AndroidTestUtilities/SetupTest1Build-check.cmake
new file mode 100644
index 0000000..ef7569d
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/SetupTest1Build-check.cmake
@@ -0,0 +1,5 @@
+include(${CMAKE_CURRENT_LIST_DIR}/check.cmake)
+compare_build_to_expected(FILES
+ "data/a.txt"
+ )
+check_for_setup_test()
diff --git a/Tests/RunCMake/AndroidTestUtilities/SetupTest2.cmake b/Tests/RunCMake/AndroidTestUtilities/SetupTest2.cmake
new file mode 100644
index 0000000..cf4c764
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/SetupTest2.cmake
@@ -0,0 +1,30 @@
+enable_testing()
+include(AndroidTestUtilities)
+
+add_custom_target(tests)
+find_program(adb_executable adb)
+
+set(ExternalData_URL_TEMPLATES
+ "https://data.kitware.com/api/v1/file/hashsum/%(algo)/%(hash)/download"
+ )
+set(test_files
+ "data/a.txt"
+ "data/subfolder/b.txt"
+ "data/subfolder/protobuffer.p"
+ )
+
+set(test_libs "data/subfolder/exampleLib.txt")
+
+set(ANDROID 1)
+
+android_add_test_data(setup_test
+ FILES ${test_files}
+ LIBS ${test_libs}
+ DEVICE_TEST_DIR "/data/local/tests/example2"
+ DEVICE_OBJECT_STORE "/sdcard/.ExternalData/SHA"
+ NO_LINK_REGEX "\\.p$")
+
+set_property(
+ TARGET setup_test
+ PROPERTY EXCLUDE_FROM_ALL 1)
+add_dependencies(tests setup_test)
diff --git a/Tests/RunCMake/AndroidTestUtilities/SetupTest2Build-check.cmake b/Tests/RunCMake/AndroidTestUtilities/SetupTest2Build-check.cmake
new file mode 100644
index 0000000..6adbd59
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/SetupTest2Build-check.cmake
@@ -0,0 +1,7 @@
+include(${CMAKE_CURRENT_LIST_DIR}/check.cmake)
+compare_build_to_expected(FILES
+ "data/a.txt"
+ "data/subfolder/b.txt"
+ "data/subfolder/protobuffer.p"
+ )
+check_for_setup_test()
diff --git a/Tests/RunCMake/AndroidTestUtilities/SetupTest3.cmake b/Tests/RunCMake/AndroidTestUtilities/SetupTest3.cmake
new file mode 100644
index 0000000..b32b6b1
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/SetupTest3.cmake
@@ -0,0 +1,33 @@
+enable_testing()
+include(AndroidTestUtilities)
+
+add_custom_target(tests)
+find_program(adb_executable adb)
+
+set(ExternalData_URL_TEMPLATES
+ "https://data.kitware.com/api/v1/file/hashsum/%(algo)/%(hash)/download"
+ )
+set(test_dir "/data/local/tests/example3")
+set(test_files
+ "data/a.txt"
+ "data/subfolder/b.txt"
+ )
+set(test_libs "libs/exampleLib.txt")
+set(files_dest "${test_dir}/storage_folder")
+set(libs_dest "${test_dir}/lib/lib/lib")
+
+set(ANDROID 1)
+
+android_add_test_data(setup_test
+ FILES ${test_files}
+ LIBS ${test_libs}
+ FILES_DEST ${files_dest}
+ LIBS_DEST ${libs_dest}
+ DEVICE_TEST_DIR "/data/local/tests/example3"
+ DEVICE_OBJECT_STORE "/sdcard/.ExternalData/SHA"
+ NO_LINK_REGEX "\\.p$")
+
+set_property(
+ TARGET setup_test
+ PROPERTY EXCLUDE_FROM_ALL 1)
+add_dependencies(tests setup_test)
diff --git a/Tests/RunCMake/AndroidTestUtilities/SetupTest3Build-check.cmake b/Tests/RunCMake/AndroidTestUtilities/SetupTest3Build-check.cmake
new file mode 100644
index 0000000..3062cdc
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/SetupTest3Build-check.cmake
@@ -0,0 +1,6 @@
+include(${CMAKE_CURRENT_LIST_DIR}/check.cmake)
+compare_build_to_expected(FILES
+ "data/a.txt"
+ "data/subfolder/b.txt"
+ )
+check_for_setup_test()
diff --git a/Tests/RunCMake/AndroidTestUtilities/SetupTest4.cmake b/Tests/RunCMake/AndroidTestUtilities/SetupTest4.cmake
new file mode 100644
index 0000000..9a27266
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/SetupTest4.cmake
@@ -0,0 +1,13 @@
+enable_testing()
+include(AndroidTestUtilities)
+
+find_program(adb_executable adb)
+
+set(test_files "data/a.txt")
+
+set(ANDROID 1)
+
+android_add_test_data(setup_test
+ FILES ${test_files}
+ DEVICE_TEST_DIR "/data/local/tests/example1"
+ DEVICE_OBJECT_STORE "/sdcard/.ExternalData/SHA")
diff --git a/Tests/RunCMake/AndroidTestUtilities/SetupTest4Build-check.cmake b/Tests/RunCMake/AndroidTestUtilities/SetupTest4Build-check.cmake
new file mode 100644
index 0000000..ef7569d
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/SetupTest4Build-check.cmake
@@ -0,0 +1,5 @@
+include(${CMAKE_CURRENT_LIST_DIR}/check.cmake)
+compare_build_to_expected(FILES
+ "data/a.txt"
+ )
+check_for_setup_test()
diff --git a/Tests/RunCMake/AndroidTestUtilities/check.cmake b/Tests/RunCMake/AndroidTestUtilities/check.cmake
new file mode 100644
index 0000000..ccd4d74
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/check.cmake
@@ -0,0 +1,20 @@
+function(compare_build_to_expected)
+ cmake_parse_arguments(_comp "" "" "FILES" ${ARGN})
+ set(missing)
+ foreach(file ${_comp_FILES})
+ if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${file}")
+ list(APPEND missing "${file}")
+ endif()
+ endforeach()
+ if(missing)
+ string(APPEND RunCMake_TEST_FAILED "Missing files:\n ${missing}")
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(check_for_setup_test)
+ file(STRINGS "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" output_var REGEX "add_test\\(setup_test.*")
+ if(NOT output_var)
+ set(RunCMake_TEST_FAILED "Could not find the test: setup_test" PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/AndroidTestUtilities/data/a.txt b/Tests/RunCMake/AndroidTestUtilities/data/a.txt
new file mode 100644
index 0000000..9d454fb
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/data/a.txt
@@ -0,0 +1 @@
+Here is a file to test.
diff --git a/Tests/RunCMake/AndroidTestUtilities/data/proto.proto b/Tests/RunCMake/AndroidTestUtilities/data/proto.proto
new file mode 100644
index 0000000..7402a3a
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/data/proto.proto
@@ -0,0 +1 @@
+proto.proto
diff --git a/Tests/RunCMake/AndroidTestUtilities/data/subfolder/b.txt b/Tests/RunCMake/AndroidTestUtilities/data/subfolder/b.txt
new file mode 100644
index 0000000..c8c6a89
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/data/subfolder/b.txt
@@ -0,0 +1 @@
+SetupTest2.cmake
diff --git a/Tests/RunCMake/AndroidTestUtilities/data/subfolder/protobuffer.p b/Tests/RunCMake/AndroidTestUtilities/data/subfolder/protobuffer.p
new file mode 100644
index 0000000..a5dc7d2
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/data/subfolder/protobuffer.p
@@ -0,0 +1 @@
+protobuffer.p
diff --git a/Tests/RunCMake/AndroidTestUtilities/libs/exampleLib.so b/Tests/RunCMake/AndroidTestUtilities/libs/exampleLib.so
new file mode 100644
index 0000000..f4cdf82
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/libs/exampleLib.so
@@ -0,0 +1 @@
+here is a fake lib.
diff --git a/Tests/RunCMake/AndroidTestUtilities/libs/exampleLib.txt b/Tests/RunCMake/AndroidTestUtilities/libs/exampleLib.txt
new file mode 100644
index 0000000..308921a
--- /dev/null
+++ b/Tests/RunCMake/AndroidTestUtilities/libs/exampleLib.txt
@@ -0,0 +1 @@
+here is an example lib!
diff --git a/Tests/RunCMake/AppleSilicon/CMakeLists.txt b/Tests/RunCMake/AppleSilicon/CMakeLists.txt
new file mode 100644
index 0000000..ab1a20c
--- /dev/null
+++ b/Tests/RunCMake/AppleSilicon/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/AppleSilicon/RunCMakeTest.cmake b/Tests/RunCMake/AppleSilicon/RunCMakeTest.cmake
new file mode 100644
index 0000000..39e462e
--- /dev/null
+++ b/Tests/RunCMake/AppleSilicon/RunCMakeTest.cmake
@@ -0,0 +1,27 @@
+include(RunCMake)
+
+# Isolate from caller's environment.
+set(ENV{CMAKE_APPLE_SILICON_PROCESSOR} "")
+set(ENV{CMAKE_OSX_ARCHITECTURES} "")
+
+function(run_arch case)
+ set(RunCMake_TEST_OPTIONS ${ARGN})
+ set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${case}-build")
+ run_cmake(${case})
+ unset(RunCMake_TEST_OPTIONS)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug)
+endfunction()
+
+run_arch(default)
+
+run_arch(arm64-var -DCMAKE_APPLE_SILICON_PROCESSOR=arm64)
+run_arch(x86_64-var -DCMAKE_APPLE_SILICON_PROCESSOR=x86_64)
+
+set(ENV{CMAKE_APPLE_SILICON_PROCESSOR} "arm64")
+run_arch(arm64-env)
+
+set(ENV{CMAKE_APPLE_SILICON_PROCESSOR} "x86_64")
+run_arch(x86_64-env)
+
+set(ENV{CMAKE_APPLE_SILICON_PROCESSOR} "")
diff --git a/Tests/RunCMake/AppleSilicon/arm64-common.cmake b/Tests/RunCMake/AppleSilicon/arm64-common.cmake
new file mode 100644
index 0000000..5a13728
--- /dev/null
+++ b/Tests/RunCMake/AppleSilicon/arm64-common.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+
+if(NOT CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
+ message(FATAL_ERROR "CMAKE_HOST_SYSTEM_PROCESSOR is '${CMAKE_HOST_SYSTEM_PROCESSOR}', not 'arm64'")
+endif()
+if(NOT CMAKE_OSX_ARCHITECTURES STREQUAL "")
+ message(FATAL_ERROR "CMAKE_OSX_ARCHITECTURES is '${CMAKE_OSX_ARCHITECTURES}', not empty ''")
+endif()
+
+add_library(arm64 arm64.c)
diff --git a/Tests/RunCMake/AppleSilicon/arm64-env.cmake b/Tests/RunCMake/AppleSilicon/arm64-env.cmake
new file mode 100644
index 0000000..8cb9dbc
--- /dev/null
+++ b/Tests/RunCMake/AppleSilicon/arm64-env.cmake
@@ -0,0 +1 @@
+include(arm64-common.cmake)
diff --git a/Tests/RunCMake/AppleSilicon/arm64-var.cmake b/Tests/RunCMake/AppleSilicon/arm64-var.cmake
new file mode 100644
index 0000000..8cb9dbc
--- /dev/null
+++ b/Tests/RunCMake/AppleSilicon/arm64-var.cmake
@@ -0,0 +1 @@
+include(arm64-common.cmake)
diff --git a/Tests/RunCMake/AppleSilicon/arm64.c b/Tests/RunCMake/AppleSilicon/arm64.c
new file mode 100644
index 0000000..d5f65fe
--- /dev/null
+++ b/Tests/RunCMake/AppleSilicon/arm64.c
@@ -0,0 +1,9 @@
+#ifndef __aarch64__
+# error "Not compiling as arm64"
+#endif
+#ifdef __x86_64__
+# error "Incorrectly compiling as x86_64"
+#endif
+void arm64_arch(void)
+{
+}
diff --git a/Tests/RunCMake/AppleSilicon/default.c b/Tests/RunCMake/AppleSilicon/default.c
new file mode 100644
index 0000000..7b0535b
--- /dev/null
+++ b/Tests/RunCMake/AppleSilicon/default.c
@@ -0,0 +1,14 @@
+#if defined(HOST_ARM64)
+# if !defined(__aarch64__)
+# error "Not compiling as host arm64"
+# endif
+#elif defined(HOST_X86_64)
+# if !defined(__x86_64__)
+# error "Not compiling as host x86_64"
+# endif
+#else
+# error "One of HOST_ARM64 or HOST_X86_64 must be defined."
+#endif
+void default_arch(void)
+{
+}
diff --git a/Tests/RunCMake/AppleSilicon/default.cmake b/Tests/RunCMake/AppleSilicon/default.cmake
new file mode 100644
index 0000000..f160e25
--- /dev/null
+++ b/Tests/RunCMake/AppleSilicon/default.cmake
@@ -0,0 +1,15 @@
+enable_language(C)
+
+if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
+ set(host_def HOST_ARM64)
+elseif(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
+ set(host_def HOST_X86_64)
+else()
+ message(FATAL_ERROR "CMAKE_HOST_SYSTEM_PROCESSOR is '${CMAKE_HOST_SYSTEM_PROCESSOR}', not 'arm64' or 'x86_64'")
+endif()
+if(NOT CMAKE_OSX_ARCHITECTURES STREQUAL "")
+ message(FATAL_ERROR "CMAKE_OSX_ARCHITECTURES is '${CMAKE_OSX_ARCHITECTURES}', not empty ''")
+endif()
+
+add_library(default default.c)
+target_compile_definitions(default PRIVATE ${host_def})
diff --git a/Tests/RunCMake/AppleSilicon/x86_64-common.cmake b/Tests/RunCMake/AppleSilicon/x86_64-common.cmake
new file mode 100644
index 0000000..602bf92
--- /dev/null
+++ b/Tests/RunCMake/AppleSilicon/x86_64-common.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+
+if(NOT CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
+ message(FATAL_ERROR "CMAKE_HOST_SYSTEM_PROCESSOR is '${CMAKE_HOST_SYSTEM_PROCESSOR}', not 'x86_64'")
+endif()
+if(NOT CMAKE_OSX_ARCHITECTURES STREQUAL "")
+ message(FATAL_ERROR "CMAKE_OSX_ARCHITECTURES is '${CMAKE_OSX_ARCHITECTURES}', not empty ''")
+endif()
+
+add_library(x86_64 x86_64.c)
diff --git a/Tests/RunCMake/AppleSilicon/x86_64-env.cmake b/Tests/RunCMake/AppleSilicon/x86_64-env.cmake
new file mode 100644
index 0000000..a44eaa4
--- /dev/null
+++ b/Tests/RunCMake/AppleSilicon/x86_64-env.cmake
@@ -0,0 +1 @@
+include(x86_64-common.cmake)
diff --git a/Tests/RunCMake/AppleSilicon/x86_64-var.cmake b/Tests/RunCMake/AppleSilicon/x86_64-var.cmake
new file mode 100644
index 0000000..a44eaa4
--- /dev/null
+++ b/Tests/RunCMake/AppleSilicon/x86_64-var.cmake
@@ -0,0 +1 @@
+include(x86_64-common.cmake)
diff --git a/Tests/RunCMake/AppleSilicon/x86_64.c b/Tests/RunCMake/AppleSilicon/x86_64.c
new file mode 100644
index 0000000..cd3cc9b
--- /dev/null
+++ b/Tests/RunCMake/AppleSilicon/x86_64.c
@@ -0,0 +1,9 @@
+#ifndef __x86_64__
+# error "Not compiling as x86_64"
+#endif
+#ifdef __aarch64__
+# error "Incorrectly compiling as arm64"
+#endif
+void x86_64_arch(void)
+{
+}
diff --git a/Tests/RunCMake/ArtifactOutputDirs/ArtifactOutputDirs.cmake b/Tests/RunCMake/ArtifactOutputDirs/ArtifactOutputDirs.cmake
new file mode 100644
index 0000000..d0accd7
--- /dev/null
+++ b/Tests/RunCMake/ArtifactOutputDirs/ArtifactOutputDirs.cmake
@@ -0,0 +1,27 @@
+enable_language(C)
+
+if(CMAKE_IMPORT_LIBRARY_SUFFIX)
+ set(expect_dll 1)
+else()
+ set(expect_dll 0)
+endif()
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/$<IF:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>,rtlib,rtbin>")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/$<IF:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>,sharedlib,others>")
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/$<IF:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>,staticlib,others>")
+
+add_executable(exe_tgt main.c)
+add_library(shared_tgt SHARED lib.c)
+add_library(static_tgt STATIC lib.c)
+
+add_custom_target(checkDirs ALL
+ COMMAND ${CMAKE_COMMAND}
+ -Dartifact_path=${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>
+ -Dexe_name=$<TARGET_FILE_NAME:exe_tgt>
+ -Dshared_name=$<TARGET_FILE_NAME:shared_tgt>
+ -Dstatic_name=$<TARGET_FILE_NAME:static_tgt>
+ -Dexpect_dll=${expect_dll}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake
+ )
+
+add_dependencies(checkDirs exe_tgt shared_tgt static_tgt)
diff --git a/Tests/RunCMake/ArtifactOutputDirs/CMakeLists.txt b/Tests/RunCMake/ArtifactOutputDirs/CMakeLists.txt
new file mode 100644
index 0000000..ab1a20c
--- /dev/null
+++ b/Tests/RunCMake/ArtifactOutputDirs/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/ArtifactOutputDirs/RunCMakeTest.cmake b/Tests/RunCMake/ArtifactOutputDirs/RunCMakeTest.cmake
new file mode 100644
index 0000000..1bf8438
--- /dev/null
+++ b/Tests/RunCMake/ArtifactOutputDirs/RunCMakeTest.cmake
@@ -0,0 +1,19 @@
+include(RunCMake)
+
+function(run_cmake_and_verify_after_build case)
+ set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${case}-build")
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ set(RunCMake_TEST_NO_CLEAN 1)
+ if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(RunCMake_TEST_OPTIONS -DCMAKE_CONFIGURATION_TYPES=Debug)
+ else()
+ set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+ endif()
+ run_cmake(${case})
+ run_cmake_command("${case}-build" ${CMAKE_COMMAND} --build .)
+ unset(RunCMake_TEST_NO_CLEAN)
+ unset(RunCMake_TEST_BINARY_DIR)
+endfunction()
+
+run_cmake_and_verify_after_build(ArtifactOutputDirs)
diff --git a/Tests/RunCMake/ArtifactOutputDirs/check.cmake b/Tests/RunCMake/ArtifactOutputDirs/check.cmake
new file mode 100644
index 0000000..ca37eba
--- /dev/null
+++ b/Tests/RunCMake/ArtifactOutputDirs/check.cmake
@@ -0,0 +1,21 @@
+set(expected ${artifact_path}/rtbin/${exe_name})
+if(NOT EXISTS "${expected}")
+ message(SEND_ERROR "executable artifact not created in the expected path:\n ${expected}")
+endif()
+
+set(expected ${artifact_path}/staticlib/${static_name})
+if(NOT EXISTS "${expected}")
+ message(SEND_ERROR "static artifact not created in the expected path:\n ${expected}")
+endif()
+
+if(expect_dll)
+ set(expected ${artifact_path}/rtlib/${shared_name})
+ if(NOT EXISTS "${expected}")
+ message(SEND_ERROR "dll artifact not created in the expected path:\n ${expected}")
+ endif()
+else()
+ set(expected ${artifact_path}/sharedlib/${shared_name})
+ if(NOT EXISTS "${expected}")
+ message(SEND_ERROR "shared artifact not created in the expected path:\n ${expected}")
+ endif()
+endif()
diff --git a/Tests/RunCMake/ArtifactOutputDirs/lib.c b/Tests/RunCMake/ArtifactOutputDirs/lib.c
new file mode 100644
index 0000000..22373f1
--- /dev/null
+++ b/Tests/RunCMake/ArtifactOutputDirs/lib.c
@@ -0,0 +1,4 @@
+int func(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/ArtifactOutputDirs/main.c b/Tests/RunCMake/ArtifactOutputDirs/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/ArtifactOutputDirs/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-result.txt b/Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-result.txt
new file mode 100644
index 0000000..d197c91
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-result.txt
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-stdout.txt b/Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-stdout.txt
new file mode 100644
index 0000000..760ba3c
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-stdout.txt
@@ -0,0 +1 @@
+ERROR: Undefined symbol: .AIXNotExported
diff --git a/Tests/RunCMake/AutoExportDll/AIXExportExplicit.cmake b/Tests/RunCMake/AutoExportDll/AIXExportExplicit.cmake
new file mode 100644
index 0000000..d23b172
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AIXExportExplicit.cmake
@@ -0,0 +1,7 @@
+enable_language(C)
+
+set(CMAKE_AIX_EXPORT_ALL_SYMBOLS OFF)
+add_library(AIXExportExplicitLib SHARED AIXExportExplicitLib.c)
+add_executable(AIXExportExplicitMain AIXExportExplicitMain.c)
+target_link_options(AIXExportExplicitLib PRIVATE LINKER:-bE:${CMAKE_CURRENT_SOURCE_DIR}/AIXExportExplicitLib.exp)
+target_link_libraries(AIXExportExplicitMain PRIVATE AIXExportExplicitLib)
diff --git a/Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.c b/Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.c
new file mode 100644
index 0000000..58fd5ac
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.c
@@ -0,0 +1,8 @@
+int AIXNotExported(void)
+{
+ return 0;
+}
+int AIXExportedSymbol(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.exp b/Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.exp
new file mode 100644
index 0000000..9eb7bf8
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.exp
@@ -0,0 +1 @@
+AIXExportedSymbol
diff --git a/Tests/RunCMake/AutoExportDll/AIXExportExplicitMain.c b/Tests/RunCMake/AutoExportDll/AIXExportExplicitMain.c
new file mode 100644
index 0000000..ad9c8ec
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AIXExportExplicitMain.c
@@ -0,0 +1,7 @@
+extern int AIXNotExported(void);
+extern int AIXExportedSymbol(void);
+
+int main(void)
+{
+ return AIXNotExported() + AIXExportedSymbol();
+}
diff --git a/Tests/RunCMake/AutoExportDll/AutoExport.cmake b/Tests/RunCMake/AutoExportDll/AutoExport.cmake
new file mode 100644
index 0000000..85eff7e
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AutoExport.cmake
@@ -0,0 +1,25 @@
+project(autoexport)
+set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${autoexport_BINARY_DIR}/bin)
+add_subdirectory(sub)
+add_library(objlib OBJECT objlib.c)
+set_property(TARGET objlib PROPERTY POSITION_INDEPENDENT_CODE 1)
+add_library(autoexport SHARED hello.cxx world.cxx foo.c $<TARGET_OBJECTS:objlib>)
+add_library(autoexport3 SHARED cppCLI.cxx)
+if(MSVC AND NOT MSVC_VERSION VERSION_LESS 1600)
+ set_property(TARGET autoexport3 PROPERTY COMMON_LANGUAGE_RUNTIME "")
+endif()
+
+add_executable(say say.cxx)
+if(MSVC)
+ set_target_properties(say PROPERTIES ENABLE_EXPORTS ON)
+ add_library(autoexport_for_exec SHARED hello2.c)
+ target_link_libraries(autoexport_for_exec say)
+ if(NOT MSVC_VERSION VERSION_LESS 1600)
+ enable_language(ASM_MASM)
+ target_sources(autoexport PRIVATE nop.asm)
+ set_property(SOURCE nop.asm PROPERTY COMPILE_FLAGS /safeseh)
+ target_compile_definitions(say PRIVATE HAS_JUSTNOP)
+ endif()
+endif()
+target_link_libraries(say autoexport autoexport2 autoexport3)
diff --git a/Tests/RunCMake/AutoExportDll/AutoExportBuild-stderr.txt b/Tests/RunCMake/AutoExportDll/AutoExportBuild-stderr.txt
new file mode 100644
index 0000000..d483c2c
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AutoExportBuild-stderr.txt
@@ -0,0 +1 @@
+^.*$
diff --git a/Tests/RunCMake/AutoExportDll/CMakeLists.txt b/Tests/RunCMake/AutoExportDll/CMakeLists.txt
new file mode 100644
index 0000000..18dfd26
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.2)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake b/Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake
new file mode 100644
index 0000000..75130f2
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake
@@ -0,0 +1,68 @@
+include(RunCMake)
+set(RunCMake_TEST_NO_CLEAN TRUE)
+set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/AutoExport-build")
+# start by cleaning up because we don't clean up along the way
+file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+# configure the AutoExport test
+run_cmake(AutoExport)
+unset(RunCMake_TEST_OPTIONS)
+# don't run this test on Watcom or Borland make as it is not supported
+if(RunCMake_GENERATOR MATCHES "Watcom WMake|Borland Makefiles")
+ return()
+endif()
+if(RunCMake_GENERATOR MATCHES "Ninja|Visual Studio" AND
+ CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ set(EXPORTS TRUE)
+endif()
+# we build debug so the say.exe will be found in Debug/say.exe for
+# Visual Studio generators
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(INTDIR "Debug/")
+endif()
+# build AutoExport
+run_cmake_command(AutoExportBuild ${CMAKE_COMMAND} --build
+ ${RunCMake_TEST_BINARY_DIR} --config Debug --clean-first)
+# save the current timestamp of exports.def
+if(EXPORTS)
+ set(EXPORTS_DEF "${RunCMake_TEST_BINARY_DIR}/say.dir/${INTDIR}exports.def")
+ if(NOT EXISTS "${EXPORTS_DEF}")
+ set(EXPORTS_DEF
+ "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/say.dir/${INTDIR}exports.def")
+ endif()
+ file(TIMESTAMP "${EXPORTS_DEF}" timestamp)
+ if(NOT timestamp)
+ message(SEND_ERROR "Could not get timestamp for \"${EXPORTS_DEF}\"")
+ endif()
+endif()
+# run the executable that uses symbols from the dll
+if(WIN32)
+ set(EXE_EXT ".exe")
+endif()
+run_cmake_command(AutoExportRun
+ ${RunCMake_TEST_BINARY_DIR}/bin/${INTDIR}say${EXE_EXT})
+# build AutoExport again without modification
+run_cmake_command(AutoExportBuildAgain ${CMAKE_COMMAND} --build
+ ${RunCMake_TEST_BINARY_DIR} --config Debug)
+# compare timestamps of exports.def to make sure it has not been updated
+if(EXPORTS)
+ file(TIMESTAMP "${EXPORTS_DEF}" timestamp_after)
+ if(NOT timestamp_after)
+ message(SEND_ERROR "Could not get timestamp for \"${EXPORTS_DEF}\"")
+ endif()
+ if (timestamp_after STREQUAL timestamp)
+ message(STATUS "AutoExportTimeStamp - PASSED")
+ else()
+ message(SEND_ERROR "\"${EXPORTS_DEF}\" has been updated.")
+ endif()
+endif()
+
+function(run_AIXExportExplicit)
+ set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/AIXExpotExplicit-build")
+ run_cmake(AIXExportExplicit)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ set(RunCMake_TEST_OUTPUT_MERGE TRUE)
+ run_cmake_command(AIXExportExplicit-build ${CMAKE_COMMAND} --build . --config Debug)
+endfunction()
+if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
+ run_AIXExportExplicit()
+endif()
diff --git a/Tests/RunCMake/AutoExportDll/cppCLI.cxx b/Tests/RunCMake/AutoExportDll/cppCLI.cxx
new file mode 100644
index 0000000..816bb6e
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/cppCLI.cxx
@@ -0,0 +1,22 @@
+#include <stdio.h>
+
+#ifdef __cplusplus_cli
+# include <msclr\marshal_cppstd.h>
+
+void cliFunction()
+{
+ System::String ^ result = "cliFunction";
+ result = result->Trim();
+ printf(msclr::interop::marshal_as<std::string>(result).c_str());
+}
+#else
+void cliFunction()
+{
+ printf("cliFunction (but /cli was not passed to the compiler)");
+}
+#endif
+
+void nonCliFunction()
+{
+ printf("nonCliFunction");
+}
diff --git a/Tests/RunCMake/AutoExportDll/foo.c b/Tests/RunCMake/AutoExportDll/foo.c
new file mode 100644
index 0000000..d13bc3e
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/foo.c
@@ -0,0 +1,15 @@
+#ifdef _MSC_VER
+# include "windows.h"
+#else
+# define WINAPI
+#endif
+
+int WINAPI foo()
+{
+ return 10;
+}
+
+int bar()
+{
+ return 5;
+}
diff --git a/Tests/RunCMake/AutoExportDll/hello.cxx b/Tests/RunCMake/AutoExportDll/hello.cxx
new file mode 100644
index 0000000..74e7a4e
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/hello.cxx
@@ -0,0 +1,14 @@
+#include "hello.h"
+
+#include <stdio.h>
+int Hello::Data = 0;
+void Hello::real()
+{
+ return;
+}
+void hello()
+{
+ printf("hello");
+}
+void Hello::operator delete[](void*){};
+void Hello::operator delete(void*){};
diff --git a/Tests/RunCMake/AutoExportDll/hello.h b/Tests/RunCMake/AutoExportDll/hello.h
new file mode 100644
index 0000000..7192f65
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/hello.h
@@ -0,0 +1,18 @@
+#ifndef _MSC_VER
+# define winexport
+#else
+# ifdef autoexport_EXPORTS
+# define winexport
+# else
+# define winexport __declspec(dllimport)
+# endif
+#endif
+
+class Hello
+{
+public:
+ static winexport int Data;
+ void real();
+ static void operator delete[](void*);
+ static void operator delete(void*);
+};
diff --git a/Tests/RunCMake/AutoExportDll/hello2.c b/Tests/RunCMake/AutoExportDll/hello2.c
new file mode 100644
index 0000000..d4d6b72
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/hello2.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+extern int own_auto_export_function(int i);
+
+void hello2()
+{
+ printf("hello exec:%i", own_auto_export_function(41));
+}
diff --git a/Tests/RunCMake/AutoExportDll/nop.asm b/Tests/RunCMake/AutoExportDll/nop.asm
new file mode 100644
index 0000000..fd6892f
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/nop.asm
@@ -0,0 +1,12 @@
+IFDEF RAX
+ELSE
+.MODEL FLAT,C
+ENDIF
+
+SOME SEGMENT EXECUTE READ
+
+public justnop
+justnop:
+ ret
+
+END
diff --git a/Tests/RunCMake/AutoExportDll/objlib.c b/Tests/RunCMake/AutoExportDll/objlib.c
new file mode 100644
index 0000000..54a9658
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/objlib.c
@@ -0,0 +1,4 @@
+int objlib()
+{
+ return 7;
+}
diff --git a/Tests/RunCMake/AutoExportDll/say.cxx b/Tests/RunCMake/AutoExportDll/say.cxx
new file mode 100644
index 0000000..8fc768a
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/say.cxx
@@ -0,0 +1,57 @@
+#include <stdio.h>
+
+#include "hello.h"
+#ifdef _MSC_VER
+# include "windows.h"
+#else
+# define WINAPI
+#endif
+
+extern "C" {
+// test __cdecl stuff
+int WINAPI foo();
+// test regular C
+int bar();
+int objlib();
+void justnop();
+}
+
+// test c++ functions
+// forward declare hello, world, cliFunction and nonCliFunction
+void hello();
+void world();
+void cliFunction();
+void nonCliFunction();
+
+// test exports for executable target
+extern "C" {
+int own_auto_export_function(int i)
+{
+ return i + 1;
+}
+}
+
+int main()
+{
+ // test static data (needs declspec to work)
+ Hello::Data = 120;
+ Hello h;
+ h.real();
+ hello();
+ printf(" ");
+ world();
+ printf("\n");
+ foo();
+ printf("\n");
+ bar();
+ objlib();
+ printf("\n");
+ cliFunction();
+ printf("\n");
+ nonCliFunction();
+ printf("\n");
+#ifdef HAS_JUSTNOP
+ justnop();
+#endif
+ return 0;
+}
diff --git a/Tests/RunCMake/AutoExportDll/sub/CMakeLists.txt b/Tests/RunCMake/AutoExportDll/sub/CMakeLists.txt
new file mode 100644
index 0000000..8b70e7d
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/sub/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_library(autoexport2 SHARED sub.cxx)
+if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ # Try msvc "big" object format.
+ target_compile_options(autoexport2 PRIVATE /bigobj)
+endif()
diff --git a/Tests/RunCMake/AutoExportDll/sub/sub.cxx b/Tests/RunCMake/AutoExportDll/sub/sub.cxx
new file mode 100644
index 0000000..9a3145e
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/sub/sub.cxx
@@ -0,0 +1,6 @@
+#include <stdio.h>
+int sub()
+{
+ printf("");
+ return 10;
+}
diff --git a/Tests/RunCMake/AutoExportDll/world.cxx b/Tests/RunCMake/AutoExportDll/world.cxx
new file mode 100644
index 0000000..3a54df3
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/world.cxx
@@ -0,0 +1,6 @@
+#include "stdio.h"
+
+void world()
+{
+ printf("world");
+}
diff --git a/Tests/RunCMake/Autogen/CMakeLists.txt b/Tests/RunCMake/Autogen/CMakeLists.txt
new file mode 100644
index 0000000..9a66cde
--- /dev/null
+++ b/Tests/RunCMake/Autogen/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.13)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/Autogen/NoQt-stderr.txt b/Tests/RunCMake/Autogen/NoQt-stderr.txt
new file mode 100644
index 0000000..1c6660a
--- /dev/null
+++ b/Tests/RunCMake/Autogen/NoQt-stderr.txt
@@ -0,0 +1,8 @@
+^CMake Warning \(dev\) in CMakeLists.txt:
+ AUTOGEN: No valid Qt version found for target main. AUTOMOC, AUTOUIC and
+ AUTORCC disabled. Consider adding:
+
+ find_package\(Qt<QTVERSION> COMPONENTS Widgets\)
+
+ to your CMakeLists.txt file.
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/Autogen/NoQt.cmake b/Tests/RunCMake/Autogen/NoQt.cmake
new file mode 100644
index 0000000..b2d375a
--- /dev/null
+++ b/Tests/RunCMake/Autogen/NoQt.cmake
@@ -0,0 +1,6 @@
+enable_language(CXX)
+
+add_executable(main empty.cpp)
+set_property(TARGET main PROPERTY AUTOMOC 1)
+set_property(TARGET main PROPERTY AUTORCC 1)
+set_property(TARGET main PROPERTY AUTOUIC 1)
diff --git a/Tests/RunCMake/Autogen/QtInFunction.cmake b/Tests/RunCMake/Autogen/QtInFunction.cmake
new file mode 100644
index 0000000..a44bc5a
--- /dev/null
+++ b/Tests/RunCMake/Autogen/QtInFunction.cmake
@@ -0,0 +1,13 @@
+enable_language(CXX)
+
+function (use_autogen target)
+ find_package(Qt5 REQUIRED COMPONENTS Core Widgets)
+ set(Qt5Core_VERSION_MAJOR "${Qt5Core_VERSION_MAJOR}" PARENT_SCOPE)
+ set(Qt5Core_VERSION_MINOR "${Qt5Core_VERSION_MINOR}" PARENT_SCOPE)
+ set_property(TARGET "${target}" PROPERTY AUTOMOC 1)
+ set_property(TARGET "${target}" PROPERTY AUTORCC 1)
+ set_property(TARGET "${target}" PROPERTY AUTOUIC 1)
+endfunction ()
+
+add_executable(main empty.cpp)
+use_autogen(main)
diff --git a/Tests/RunCMake/Autogen/QtInFunctionNested-stderr.txt b/Tests/RunCMake/Autogen/QtInFunctionNested-stderr.txt
new file mode 100644
index 0000000..1c6660a
--- /dev/null
+++ b/Tests/RunCMake/Autogen/QtInFunctionNested-stderr.txt
@@ -0,0 +1,8 @@
+^CMake Warning \(dev\) in CMakeLists.txt:
+ AUTOGEN: No valid Qt version found for target main. AUTOMOC, AUTOUIC and
+ AUTORCC disabled. Consider adding:
+
+ find_package\(Qt<QTVERSION> COMPONENTS Widgets\)
+
+ to your CMakeLists.txt file.
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/Autogen/QtInFunctionNested.cmake b/Tests/RunCMake/Autogen/QtInFunctionNested.cmake
new file mode 100644
index 0000000..5421ba0
--- /dev/null
+++ b/Tests/RunCMake/Autogen/QtInFunctionNested.cmake
@@ -0,0 +1,17 @@
+enable_language(CXX)
+
+function (use_autogen target)
+ find_package(Qt5 REQUIRED COMPONENTS Core Widgets)
+ set(Qt5Core_VERSION_MAJOR "${Qt5Core_VERSION_MAJOR}" PARENT_SCOPE)
+ set(Qt5Core_VERSION_MINOR "${Qt5Core_VERSION_MINOR}" PARENT_SCOPE)
+ set_property(TARGET "${target}" PROPERTY AUTOMOC 1)
+ set_property(TARGET "${target}" PROPERTY AUTORCC 1)
+ set_property(TARGET "${target}" PROPERTY AUTOUIC 1)
+endfunction ()
+
+function (wrap_autogen target)
+ use_autogen("${target}")
+endfunction ()
+
+add_executable(main empty.cpp)
+wrap_autogen(main)
diff --git a/Tests/RunCMake/Autogen/QtInFunctionProperty.cmake b/Tests/RunCMake/Autogen/QtInFunctionProperty.cmake
new file mode 100644
index 0000000..35f1cd1
--- /dev/null
+++ b/Tests/RunCMake/Autogen/QtInFunctionProperty.cmake
@@ -0,0 +1,21 @@
+enable_language(CXX)
+
+function (use_autogen target)
+ find_package(Qt5 REQUIRED COMPONENTS Core Widgets)
+ set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ PROPERTY
+ Qt5Core_VERSION_MAJOR "${Qt5Core_VERSION_MAJOR}")
+ set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ PROPERTY
+ Qt5Core_VERSION_MINOR "${Qt5Core_VERSION_MINOR}")
+ set_property(TARGET "${target}" PROPERTY AUTOMOC 1)
+ set_property(TARGET "${target}" PROPERTY AUTORCC 1)
+ set_property(TARGET "${target}" PROPERTY AUTOUIC 1)
+endfunction ()
+
+function (wrap_autogen target)
+ use_autogen("${target}")
+endfunction ()
+
+add_executable(main empty.cpp)
+wrap_autogen(main)
diff --git a/Tests/RunCMake/Autogen/RunCMakeTest.cmake b/Tests/RunCMake/Autogen/RunCMakeTest.cmake
new file mode 100644
index 0000000..a31b67c
--- /dev/null
+++ b/Tests/RunCMake/Autogen/RunCMakeTest.cmake
@@ -0,0 +1,8 @@
+include(RunCMake)
+
+run_cmake(NoQt)
+if (with_qt5)
+ run_cmake(QtInFunction)
+ run_cmake(QtInFunctionNested)
+ run_cmake(QtInFunctionProperty)
+endif ()
diff --git a/Tests/RunCMake/Autogen/empty.cpp b/Tests/RunCMake/Autogen/empty.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/Autogen/empty.cpp
diff --git a/Tests/RunCMake/BuildDepends/BuildUnderSource.c b/Tests/RunCMake/BuildDepends/BuildUnderSource.c
new file mode 100644
index 0000000..688a040
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/BuildUnderSource.c
@@ -0,0 +1,5 @@
+#include "BuildUnderSource.h"
+int main(void)
+{
+ return BUILD_UNDER_SOURCE;
+}
diff --git a/Tests/RunCMake/BuildDepends/BuildUnderSource.cmake b/Tests/RunCMake/BuildDepends/BuildUnderSource.cmake
new file mode 100644
index 0000000..aa2a44f
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/BuildUnderSource.cmake
@@ -0,0 +1,9 @@
+enable_language(C)
+include_directories(include)
+add_executable(BuildUnderSource BuildUnderSource.c)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+set(check_pairs
+ \"$<TARGET_FILE:BuildUnderSource>|${CMAKE_CURRENT_SOURCE_DIR}/include/BuildUnderSource.h\"
+ )
+")
diff --git a/Tests/RunCMake/BuildDepends/BuildUnderSource.step1.cmake b/Tests/RunCMake/BuildDepends/BuildUnderSource.step1.cmake
new file mode 100644
index 0000000..2cdd32b
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/BuildUnderSource.step1.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_SOURCE_DIR}/include/BuildUnderSource.h" [[
+#define BUILD_UNDER_SOURCE 1
+]])
diff --git a/Tests/RunCMake/BuildDepends/BuildUnderSource.step2.cmake b/Tests/RunCMake/BuildDepends/BuildUnderSource.step2.cmake
new file mode 100644
index 0000000..8e4b858
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/BuildUnderSource.step2.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_SOURCE_DIR}/include/BuildUnderSource.h" [[
+#define BUILD_UNDER_SOURCE 2
+]])
diff --git a/Tests/RunCMake/BuildDepends/C-Exe-Manifest.cmake b/Tests/RunCMake/BuildDepends/C-Exe-Manifest.cmake
new file mode 100644
index 0000000..87b0de0
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/C-Exe-Manifest.cmake
@@ -0,0 +1,19 @@
+enable_language(C)
+
+add_executable(main main.c ${CMAKE_CURRENT_BINARY_DIR}/test.manifest)
+
+if(MSVC AND NOT MSVC_VERSION LESS 1400)
+ set(EXTRA_CHECK [[
+file(STRINGS "$<TARGET_FILE:main>" content REGEX "name=\"Kitware.CMake.C-Exe-Manifest-step[0-9]\"")
+if(NOT "${content}" MATCHES "name=\"Kitware.CMake.C-Exe-Manifest-step${check_step}\"")
+ set(RunCMake_TEST_FAILED "Binary has no manifest with name=\"Kitware.CMake.C-Exe-Manifest-step${check_step}\":\n ${content}")
+endif()
+]])
+endif()
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+set(check_pairs
+ \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/test.manifest\"
+ )
+${EXTRA_CHECK}
+")
diff --git a/Tests/RunCMake/BuildDepends/C-Exe-Manifest.step1.cmake b/Tests/RunCMake/BuildDepends/C-Exe-Manifest.step1.cmake
new file mode 100644
index 0000000..c0b939d
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/C-Exe-Manifest.step1.cmake
@@ -0,0 +1,6 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/test.manifest" [[
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity type="win32" version="1.0.0.0"
+ name="Kitware.CMake.C-Exe-Manifest-step1"/>
+</assembly>
+]])
diff --git a/Tests/RunCMake/BuildDepends/C-Exe-Manifest.step2.cmake b/Tests/RunCMake/BuildDepends/C-Exe-Manifest.step2.cmake
new file mode 100644
index 0000000..a75bf21
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/C-Exe-Manifest.step2.cmake
@@ -0,0 +1,6 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/test.manifest" [[
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity type="win32" version="1.0.0.0"
+ name="Kitware.CMake.C-Exe-Manifest-step2"/>
+</assembly>
+]])
diff --git a/Tests/RunCMake/BuildDepends/C-Exe.cmake b/Tests/RunCMake/BuildDepends/C-Exe.cmake
new file mode 100644
index 0000000..ad5cd4d
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/C-Exe.cmake
@@ -0,0 +1,12 @@
+enable_language(C)
+
+add_executable(main ${CMAKE_CURRENT_BINARY_DIR}/main.c)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+set(check_pairs
+ \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c\"
+ )
+set(check_exes
+ \"$<TARGET_FILE:main>\"
+ )
+")
diff --git a/Tests/RunCMake/BuildDepends/C-Exe.step1.cmake b/Tests/RunCMake/BuildDepends/C-Exe.step1.cmake
new file mode 100644
index 0000000..08e2949
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/C-Exe.step1.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.c" [[
+int main(void) { return 1; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/C-Exe.step2.cmake b/Tests/RunCMake/BuildDepends/C-Exe.step2.cmake
new file mode 100644
index 0000000..ee4530c
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/C-Exe.step2.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.c" [[
+int main(void) { return 2; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/CMakeLists.txt b/Tests/RunCMake/BuildDepends/CMakeLists.txt
new file mode 100644
index 0000000..99f238b
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.3)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE)
diff --git a/Tests/RunCMake/BuildDepends/CompilerDependencies.cmake b/Tests/RunCMake/BuildDepends/CompilerDependencies.cmake
new file mode 100644
index 0000000..8a9e600
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CompilerDependencies.cmake
@@ -0,0 +1,46 @@
+enable_language(C)
+
+add_executable(main ${CMAKE_CURRENT_BINARY_DIR}/main.c)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+set(check_pairs
+ \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c\"
+ \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.h\"
+ )
+set(check_exes
+ \"$<TARGET_FILE:main>\"
+ )
+
+if (check_step EQUAL 2)
+ include(\"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Makefile.cmake\")
+ if (NOT CMAKE_DEPEND_INFO_FILES)
+ set(RunCMake_TEST_FAILED \"Variable CMAKE_DEPEND_INFO_FILES not found.\")
+ else()
+ include(\"${CMAKE_CURRENT_BINARY_DIR}/\${CMAKE_DEPEND_INFO_FILES}\")
+ if (NOT CMAKE_DEPENDS_DEPENDENCY_FILES)
+ set(RunCMake_TEST_FAILED \"Variable CMAKE_DEPENDS_DEPENDENCY_FILES not found.\")
+ else()
+ list(GET CMAKE_DEPENDS_DEPENDENCY_FILES 1 OBJECT_FILE)
+ list(GET CMAKE_DEPENDS_DEPENDENCY_FILES 3 DEP_FILE)
+ if (NOT EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/\${DEP_FILE}\")
+ set(RunCMake_TEST_FAILED \"File \${DEP_FILE} not found.\")
+ else()
+ set (TARGET_DEP_FILE \"${CMAKE_CURRENT_BINARY_DIR}/\${DEP_FILE}\")
+ cmake_path(REPLACE_FILENAME TARGET_DEP_FILE \"compiler_depend.make\")
+ file(READ \"\${TARGET_DEP_FILE}\" DEPENDS_CONTENT)
+ if (WIN32)
+ string (REPLACE \"\\\\\" \"/\" DEPENDS_CONTENT \"\${DEPENDS_CONTENT}\")
+ string (TOLOWER \"\${DEPENDS_CONTENT}\" DEPENDS_CONTENT)
+ string (TOLOWER \"\${OBJECT_FILE}\" OBJECT_FILE)
+ else()
+ string(REPLACE \"\\\\ \" \" \" DEPENDS_CONTENT \"\${DEPENDS_CONTENT}\")
+ endif()
+ if(NOT DEPENDS_CONTENT MATCHES \"\${OBJECT_FILE} *:.+main.c\"
+ OR NOT DEPENDS_CONTENT MATCHES \"main.h\")
+ set(RunCMake_TEST_FAILED \"Dependency file '\${TARGET_DEP_FILE}' badly generated.\")
+ endif()
+ endif()
+ endif()
+ endif()
+endif()
+")
diff --git a/Tests/RunCMake/BuildDepends/CompilerDependencies.step1.cmake b/Tests/RunCMake/BuildDepends/CompilerDependencies.step1.cmake
new file mode 100644
index 0000000..1da2593
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CompilerDependencies.step1.cmake
@@ -0,0 +1,9 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.h" [[
+#define COUNT 1
+]])
+
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.c" [[
+#include "main.h"
+
+int main(void) { return COUNT; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/CompilerDependencies.step2.cmake b/Tests/RunCMake/BuildDepends/CompilerDependencies.step2.cmake
new file mode 100644
index 0000000..e983665
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CompilerDependencies.step2.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.h" [[
+#define COUNT 2
+]])
diff --git a/Tests/RunCMake/BuildDepends/Custom-Always.cmake b/Tests/RunCMake/BuildDepends/Custom-Always.cmake
new file mode 100644
index 0000000..c7e7fb0
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/Custom-Always.cmake
@@ -0,0 +1,24 @@
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/before-always
+ COMMAND ${CMAKE_COMMAND} -E touch before-always
+ )
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/always
+ COMMAND ${CMAKE_COMMAND} -E touch always-updated
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/before-always
+ )
+set_property(SOURCE always PROPERTY SYMBOLIC 1)
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/after-always
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/always
+ COMMAND ${CMAKE_COMMAND} -E touch after-always
+ )
+
+add_custom_target(drive ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/after-always)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+set(check_pairs
+ \"${CMAKE_CURRENT_BINARY_DIR}/always-updated|${CMAKE_CURRENT_BINARY_DIR}/before-always\"
+ \"${CMAKE_CURRENT_BINARY_DIR}/after-always|${CMAKE_CURRENT_BINARY_DIR}/always-updated\"
+ )
+")
diff --git a/Tests/RunCMake/BuildDepends/Custom-Symbolic-and-Byproduct.cmake b/Tests/RunCMake/BuildDepends/Custom-Symbolic-and-Byproduct.cmake
new file mode 100644
index 0000000..1e1f22a
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/Custom-Symbolic-and-Byproduct.cmake
@@ -0,0 +1,29 @@
+add_custom_command(
+ OUTPUT gen-byproduct gen-byproduct-stamp
+ BYPRODUCTS byproduct
+ COMMAND ${CMAKE_COMMAND} -E touch gen-byproduct-stamp
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different gen-byproduct-stamp byproduct
+ )
+set_property(SOURCE gen-byproduct PROPERTY SYMBOLIC 1)
+add_custom_target(produce DEPENDS gen-byproduct)
+
+add_custom_command(
+ OUTPUT use-byproduct
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/byproduct
+ COMMAND ${CMAKE_COMMAND} -E sleep 1.125 # workaround buggy filesystem timestamps
+ COMMAND ${CMAKE_COMMAND} -E touch use-byproduct
+ )
+add_custom_target(drive ALL DEPENDS use-byproduct)
+add_dependencies(drive produce)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+if (check_step EQUAL 1)
+ set(check_pairs
+ \"${CMAKE_CURRENT_BINARY_DIR}/use-byproduct|${CMAKE_CURRENT_BINARY_DIR}/gen-byproduct-stamp\"
+ )
+else()
+ set(check_pairs
+ \"${CMAKE_CURRENT_BINARY_DIR}/gen-byproduct-stamp|${CMAKE_CURRENT_BINARY_DIR}/use-byproduct\"
+ )
+endif()
+")
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-result.txt b/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-stderr.txt b/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-stderr.txt
new file mode 100644
index 0000000..cddea3c
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at CustomCommandDependencies-BadArgs.cmake:[0-9]+ \(add_custom_command\):
+ add_custom_command IMPLICIT_DEPENDS and DEPFILE can not both be specified.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs.cmake
new file mode 100644
index 0000000..91ee338
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+
+add_custom_command(OUTPUT main.c
+ DEPFILE main.c.d
+ IMPLICIT_DEPENDS C main.c.in
+ COMMAND "${CMAKE_COMMAND}" -DINFILE=main.c.in -DOUTFILE=main.c -DDEPFILE=main.c.d
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/GenerateDepFile.cmake"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+
+add_custom_target(mainc ALL DEPENDS main.c)
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.cmake
new file mode 100644
index 0000000..28bbf11
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.cmake
@@ -0,0 +1,73 @@
+enable_language(C)
+
+add_custom_command(OUTPUT main.c
+ DEPFILE main.c.d
+ COMMAND "${CMAKE_COMMAND}" -DINFILE=main.c.in -DOUTFILE=main.c -DDEPFILE=main.c.d
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/GenerateDepFile.cmake"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+
+add_custom_target(mainc ALL DEPENDS main.c)
+
+add_executable(main ${CMAKE_CURRENT_BINARY_DIR}/main.c)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+cmake_minimum_required(VERSION 3.19)
+set(check_pairs
+ \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c.in\"
+ \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c\"
+ )
+set(check_exes
+ \"$<TARGET_FILE:main>\"
+ )
+
+if (check_step EQUAL 2)
+ include(\"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Makefile.cmake\")
+ if (NOT CMAKE_DEPEND_INFO_FILES)
+ set(RunCMake_TEST_FAILED \"Variable CMAKE_DEPEND_INFO_FILES not found.\")
+ else()
+ foreach(DEPEND_INFO_FILE IN LISTS CMAKE_DEPEND_INFO_FILES)
+ include(\"${CMAKE_CURRENT_BINARY_DIR}/\${DEPEND_INFO_FILE}\")
+ if (NOT CMAKE_DEPENDS_DEPENDENCY_FILES)
+ set(RunCMake_TEST_FAILED \"Variable CMAKE_DEPENDS_DEPENDENCY_FILES not found.\")
+ else()
+ list(LENGTH CMAKE_DEPENDS_DEPENDENCY_FILES DEPENDENCY_FILES_SIZE)
+ math(EXPR STOP_INDEX \"\${DEPENDENCY_FILES_SIZE} - 1\")
+ foreach(INDEX RANGE 0 \${STOP_INDEX} 4)
+ math(EXPR OBJECT_INDEX \"\${INDEX} + 1\")
+ math(EXPR FORMAT_INDEX \"\${INDEX} + 2\")
+ math(EXPR DEP_INDEX \"\${INDEX} + 3\")
+ list(GET CMAKE_DEPENDS_DEPENDENCY_FILES \${OBJECT_INDEX} OBJECT_FILE)
+ list(GET CMAKE_DEPENDS_DEPENDENCY_FILES \${FORMAT_INDEX} DEP_FORMAT)
+ list(GET CMAKE_DEPENDS_DEPENDENCY_FILES \${DEP_INDEX} DEP_FILE)
+ if (NOT EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/\${DEP_FILE}\")
+ set(RunCMake_TEST_FAILED \"File \${DEP_FILE} not found.\")
+ else()
+ cmake_path(APPEND TARGET_DEP_FILE \"${CMAKE_CURRENT_BINARY_DIR}\" \"\${DEPEND_INFO_FILE}\")
+ cmake_path(REPLACE_FILENAME TARGET_DEP_FILE \"compiler_depend.make\")
+ file(READ \"\${TARGET_DEP_FILE}\" DEPENDS_CONTENT)
+ if (WIN32)
+ string (REPLACE \"\\\\\" \"/\" DEPENDS_CONTENT \"\${DEPENDS_CONTENT}\")
+ string (TOLOWER \"\${DEPENDS_CONTENT}\" DEPENDS_CONTENT)
+ string (TOLOWER \"\${OBJECT_FILE}\" OBJECT_FILE)
+ else()
+ string(REPLACE \"\\\\ \" \" \" DEPENDS_CONTENT \"\${DEPENDS_CONTENT}\")
+ endif()
+ if(DEPEND_INFO_FILE MATCHES \"main\\\\.dir\")
+ if (DEP_FORMAT STREQUAL \"gcc\" AND NOT DEPENDS_CONTENT MATCHES \"\${OBJECT_FILE} *:.+main.c\")
+ set(RunCMake_TEST_FAILED \"Dependency file '\${TARGET_DEP_FILE}' badly generated:\\n\${DEPENDS_CONTENT}\")
+ endif()
+ if (DEP_FORMAT STREQUAL \"custom\" AND NOT DEPENDS_CONTENT MATCHES \"\${OBJECT_FILE} *:.+main.c.in\")
+ set(RunCMake_TEST_FAILED \"Dependency file '\${TARGET_DEP_FILE}' badly generated:\\n\${DEPENDS_CONTENT}\")
+ endif()
+ else()
+ if (NOT DEPENDS_CONTENT MATCHES \"\${OBJECT_FILE} *:.+main.c.in\")
+ set(RunCMake_TEST_FAILED \"Dependency file '\${TARGET_DEP_FILE}' badly generated:\\n\${DEPENDS_CONTENT}\")
+ endif()
+ endif()
+ endif()
+ endforeach()
+ endif()
+ endforeach()
+ endif()
+endif()
+")
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step1.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step1.cmake
new file mode 100644
index 0000000..87576eb
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step1.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.c.in" [[
+int main(void) { return 1; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step2.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step2.cmake
new file mode 100644
index 0000000..69b21b8
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step2.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.c.in" [[
+int main(void) { return 2; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake
new file mode 100644
index 0000000..e4fdb4a
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake
@@ -0,0 +1,61 @@
+cmake_policy(SET CMP0116 NEW)
+enable_language(C)
+
+add_custom_command(
+ OUTPUT topcc.c
+ DEPFILE topcc_$<CONFIG>.c.d
+ COMMAND ${CMAKE_COMMAND} -DOUTFILE=${CMAKE_CURRENT_BINARY_DIR}/topcc.c -DINFILE=topccdep.txt -DDEPFILE=topcc_$<CONFIG>.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
+ )
+add_custom_target(topcc ALL DEPENDS topcc.c)
+
+add_custom_command(
+ OUTPUT topexe.c
+ DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/topexe_$<CONFIG>.c.d
+ COMMAND ${CMAKE_COMMAND} -DOUTFILE=topexe.c "-DINFILE=${CMAKE_CURRENT_BINARY_DIR}/topexedep.txt" -DDEPFILE=topexe_$<CONFIG>.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
+ )
+add_executable(topexe "${CMAKE_CURRENT_BINARY_DIR}/topexe.c")
+
+add_custom_command(
+ OUTPUT toplib.c
+ DEPFILE toplib.c.d
+ COMMAND ${CMAKE_COMMAND} -DOUTFILE=toplib.c -DINFILE=toplibdep.txt -DDEPFILE=toplib.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
+ )
+add_library(toplib STATIC toplib.c)
+
+add_subdirectory(DepfileSubdir)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+function(check_exists file)
+ if(NOT EXISTS \"\${file}\")
+ string(APPEND RunCMake_TEST_FAILED \"\${file} does not exist\\n\")
+ endif()
+ set(RunCMake_TEST_FAILED \"\${RunCMake_TEST_FAILED}\" PARENT_SCOPE)
+endfunction()
+
+function(check_not_exists file)
+ if(EXISTS \"\${file}\")
+ string(APPEND RunCMake_TEST_FAILED \"\${file} exists\\n\")
+ endif()
+ set(RunCMake_TEST_FAILED \"\${RunCMake_TEST_FAILED}\" PARENT_SCOPE)
+endfunction()
+
+set(check_pairs
+ \"${CMAKE_BINARY_DIR}/topcc.c|${CMAKE_BINARY_DIR}/topccdep.txt\"
+ \"$<TARGET_FILE:topexe>|${CMAKE_BINARY_DIR}/topexedep.txt\"
+ \"$<TARGET_FILE:toplib>|${CMAKE_BINARY_DIR}/toplibdep.txt\"
+ \"${CMAKE_BINARY_DIR}/DepfileSubdir/subcc.c|${CMAKE_BINARY_DIR}/DepfileSubdir/subccdep.txt\"
+ \"$<TARGET_FILE:subexe>|${CMAKE_BINARY_DIR}/DepfileSubdir/subexedep.txt\"
+ \"$<TARGET_FILE:sublib>|${CMAKE_BINARY_DIR}/DepfileSubdir/sublibdep.txt\"
+ )
+
+if(check_step EQUAL 3)
+ list(APPEND check_pairs
+ \"${CMAKE_BINARY_DIR}/step3.timestamp|${CMAKE_BINARY_DIR}/topcc.c\"
+ \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:topexe>\"
+ \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:toplib>\"
+ \"${CMAKE_BINARY_DIR}/step3.timestamp|${CMAKE_BINARY_DIR}/DepfileSubdir/subcc.c\"
+ \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:subexe>\"
+ \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:sublib>\"
+ )
+endif()
+")
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake
new file mode 100644
index 0000000..0dfe78e
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake
@@ -0,0 +1,10 @@
+file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir")
+file(REMOVE "${RunCMake_TEST_BINARY_DIR}/../sublib.c")
+file(REMOVE "${RunCMake_TEST_BINARY_DIR}/step3.timestamp")
+
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topccdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topexedep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/toplibdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subccdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subexedep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/sublibdep.txt")
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake
new file mode 100644
index 0000000..c711514
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake
@@ -0,0 +1,6 @@
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topccdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topexedep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/toplibdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subccdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subexedep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/sublibdep.txt")
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step3.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step3.cmake
new file mode 100644
index 0000000..c55ccc1
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step3.cmake
@@ -0,0 +1 @@
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/step3.timestamp")
diff --git a/Tests/RunCMake/BuildDepends/DepfileSubdir/CMakeLists.txt b/Tests/RunCMake/BuildDepends/DepfileSubdir/CMakeLists.txt
new file mode 100644
index 0000000..f131751
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/DepfileSubdir/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_policy(SET CMP0116 NEW)
+
+add_custom_command(
+ OUTPUT subcc.c
+ DEPFILE subcc.c.d
+ COMMAND ${CMAKE_COMMAND} -DOUTFILE=${CMAKE_CURRENT_BINARY_DIR}/subcc.c -DINFILE=subccdep.txt -DDEPFILE=subcc.c.d -P "${CMAKE_CURRENT_LIST_DIR}/../WriteDepfile.cmake"
+ )
+add_custom_target(subcc ALL DEPENDS subcc.c)
+
+add_custom_command(
+ OUTPUT subexe.c
+ DEPFILE subexe.c.d
+ COMMAND ${CMAKE_COMMAND} -DOUTFILE=subexe.c -DINFILE=subexedep.txt -DDEPFILE=subexe.c.d -P "${CMAKE_CURRENT_LIST_DIR}/../WriteDepfile.cmake"
+ )
+add_executable(subexe subexe.c)
+
+add_custom_command(
+ OUTPUT ${CMAKE_BINARY_DIR}/../sublib.c
+ DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/sublib.c.d
+ COMMAND ${CMAKE_COMMAND} -DOUTFILE=${CMAKE_BINARY_DIR}/../sublib.c "-DINFILE=${CMAKE_CURRENT_BINARY_DIR}/sublibdep.txt" -DDEPFILE=sublib.c.d -P "${CMAKE_CURRENT_LIST_DIR}/../WriteDepfile.cmake"
+ )
+add_library(sublib STATIC "${CMAKE_BINARY_DIR}/../sublib.c")
diff --git a/Tests/RunCMake/BuildDepends/ExternalProject/CMakeLists.txt b/Tests/RunCMake/BuildDepends/ExternalProject/CMakeLists.txt
new file mode 100644
index 0000000..57a0f6e
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/ExternalProject/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.12)
+project(External NONE)
+
+if (DEFINED cache_arg)
+ message("configured with: ${cache_arg}")
+else ()
+ message("cache_arg is undefined")
+endif ()
+
+if (DEFINED second_cache_arg)
+ message("configured again with: ${second_cache_arg}")
+else ()
+ message("second_cache_arg is undefined")
+endif ()
diff --git a/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs-build1-stdout.txt b/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs-build1-stdout.txt
new file mode 100644
index 0000000..fea7fd9
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs-build1-stdout.txt
@@ -0,0 +1,2 @@
+.*configured with: first
+.*second_cache_arg is undefined
diff --git a/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs-build2-stdout.txt b/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs-build2-stdout.txt
new file mode 100644
index 0000000..e19e743
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs-build2-stdout.txt
@@ -0,0 +1,2 @@
+.*configured with: first
+.*configured again with: second
diff --git a/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs.cmake b/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs.cmake
new file mode 100644
index 0000000..fe69426
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs.cmake
@@ -0,0 +1,19 @@
+include("${CMAKE_CURRENT_BINARY_DIR}/data.cmake")
+
+include(ExternalProject)
+ExternalProject_add(external
+ SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/ExternalProject"
+ CMAKE_CACHE_ARGS
+ ${cache_args}
+ BUILD_COMMAND ""
+ INSTALL_COMMAND "")
+
+set(cache_args_path "<TMP_DIR>/external-cache-$<CONFIG>.cmake")
+set(cmake_cache_path "<BINARY_DIR>/CMakeCache.txt")
+_ep_replace_location_tags(external cache_args_path cmake_cache_path)
+
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake" CONTENT "
+set(check_pairs
+ \"${cmake_cache_path}|${cache_args_path}\"
+)
+")
diff --git a/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs.step1.cmake b/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs.step1.cmake
new file mode 100644
index 0000000..57c7ab7
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs.step1.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/data.cmake"
+ "set(cache_args -Dcache_arg:STRING=first)
+")
diff --git a/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs.step2.cmake b/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs.step2.cmake
new file mode 100644
index 0000000..cbb79e1
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/ExternalProjectCacheArgs.step2.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/data.cmake"
+ "set(cache_args -Dsecond_cache_arg:STRING=second)
+")
diff --git a/Tests/RunCMake/BuildDepends/GNU-AS-stdout.txt b/Tests/RunCMake/BuildDepends/GNU-AS-stdout.txt
new file mode 100644
index 0000000..c4326ae
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/GNU-AS-stdout.txt
@@ -0,0 +1,4 @@
+-- The ASM compiler identification is GNU
+-- Found assembler: [^
+]*/as(\.exe)?
+-- CMAKE_ASM_COMPILER_ID_VENDOR_MATCH='GNU assembler'
diff --git a/Tests/RunCMake/BuildDepends/GNU-AS.cmake b/Tests/RunCMake/BuildDepends/GNU-AS.cmake
new file mode 100644
index 0000000..0c7249a
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/GNU-AS.cmake
@@ -0,0 +1,14 @@
+enable_language(ASM)
+
+# Validate undocumented implementation detail.
+message(STATUS "CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_MATCH='${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_MATCH}'")
+
+add_library(gnu_as STATIC gnu_as.s)
+target_include_directories(gnu_as PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+target_compile_definitions(gnu_as PRIVATE "TEST_DEF=Hello")
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+set(check_pairs
+ \"$<TARGET_FILE:gnu_as>|${CMAKE_CURRENT_BINARY_DIR}/gnu_as.inc\"
+ )
+")
diff --git a/Tests/RunCMake/BuildDepends/GNU-AS.step1.cmake b/Tests/RunCMake/BuildDepends/GNU-AS.step1.cmake
new file mode 100644
index 0000000..15a5e96
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/GNU-AS.step1.cmake
@@ -0,0 +1 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/gnu_as.inc" "")
diff --git a/Tests/RunCMake/BuildDepends/GNU-AS.step2.cmake b/Tests/RunCMake/BuildDepends/GNU-AS.step2.cmake
new file mode 100644
index 0000000..15a5e96
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/GNU-AS.step2.cmake
@@ -0,0 +1 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/gnu_as.inc" "")
diff --git a/Tests/RunCMake/BuildDepends/GenerateDepFile.cmake b/Tests/RunCMake/BuildDepends/GenerateDepFile.cmake
new file mode 100644
index 0000000..f7d0f13
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/GenerateDepFile.cmake
@@ -0,0 +1,6 @@
+file(READ "${INFILE}" INCONTENT)
+file(WRITE "${OUTFILE}" "${INCONTENT}")
+
+string(REPLACE [[ ]] [[\ ]] OUTFILE "${OUTFILE}")
+string(REPLACE [[ ]] [[\ ]] INFILE "${INFILE}")
+file(WRITE "${DEPFILE}" "${OUTFILE}: ${INFILE}\n")
diff --git a/Tests/RunCMake/BuildDepends/MakeCustomIncludes.cmake b/Tests/RunCMake/BuildDepends/MakeCustomIncludes.cmake
new file mode 100644
index 0000000..8b2ae78
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/MakeCustomIncludes.cmake
@@ -0,0 +1,13 @@
+add_custom_command(
+ OUTPUT output.cxx
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/MakeCustomIncludes.cxx output.cxx
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/MakeCustomIncludes.cxx
+ IMPLICIT_DEPENDS CXX ${CMAKE_CURRENT_SOURCE_DIR}/MakeCustomIncludes.cxx)
+add_custom_target(generate ALL DEPENDS output.cxx)
+set_property(TARGET generate PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR})
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+set(check_pairs
+ \"${CMAKE_CURRENT_BINARY_DIR}/output.cxx|${CMAKE_CURRENT_BINARY_DIR}/MakeCustomIncludes.h\"
+ )
+")
diff --git a/Tests/RunCMake/BuildDepends/MakeCustomIncludes.cxx b/Tests/RunCMake/BuildDepends/MakeCustomIncludes.cxx
new file mode 100644
index 0000000..9a0edef
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/MakeCustomIncludes.cxx
@@ -0,0 +1,6 @@
+#include "MakeCustomIncludes.h"
+
+int main()
+{
+ return MakeCustomIncludes();
+}
diff --git a/Tests/RunCMake/BuildDepends/MakeCustomIncludes.step1.cmake b/Tests/RunCMake/BuildDepends/MakeCustomIncludes.step1.cmake
new file mode 100644
index 0000000..6bb01a6
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/MakeCustomIncludes.step1.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/MakeCustomIncludes.h" [[
+inline int MakeCustomIncludes() { return 1; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/MakeCustomIncludes.step2.cmake b/Tests/RunCMake/BuildDepends/MakeCustomIncludes.step2.cmake
new file mode 100644
index 0000000..6b3151d
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/MakeCustomIncludes.step2.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/MakeCustomIncludes.h" [[
+inline int MakeCustomIncludes() { return 2; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/MakeDependencies.cmake b/Tests/RunCMake/BuildDepends/MakeDependencies.cmake
new file mode 100644
index 0000000..33e8c7e
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/MakeDependencies.cmake
@@ -0,0 +1,13 @@
+enable_language(C)
+
+add_executable(main ${CMAKE_CURRENT_BINARY_DIR}/main.c)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+set(check_pairs
+ \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c\"
+ \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.h\"
+ )
+set(check_exes
+ \"$<TARGET_FILE:main>\"
+ )
+")
diff --git a/Tests/RunCMake/BuildDepends/MakeDependencies.step1.cmake b/Tests/RunCMake/BuildDepends/MakeDependencies.step1.cmake
new file mode 100644
index 0000000..c74f033
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/MakeDependencies.step1.cmake
@@ -0,0 +1,18 @@
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/main.c")
+foreach(i RANGE 1 20000)
+ file(WRITE "${RunCMake_TEST_BINARY_DIR}/temp_header_file_${i}.h"
+ "#define HEADER_${i} ${i}\n"
+ )
+ file(APPEND "${RunCMake_TEST_BINARY_DIR}/main.c"
+ "#include \"temp_header_file_${i}.h\"\n"
+ )
+endforeach()
+file(APPEND "${RunCMake_TEST_BINARY_DIR}/main.c"
+ "#include \"main.h\"\n"
+ )
+file(APPEND "${RunCMake_TEST_BINARY_DIR}/main.c"
+ "int main(void) { return COUNT; }\n"
+ )
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.h"
+ "#define COUNT 1\n"
+ )
diff --git a/Tests/RunCMake/BuildDepends/MakeDependencies.step2.cmake b/Tests/RunCMake/BuildDepends/MakeDependencies.step2.cmake
new file mode 100644
index 0000000..c826d3c
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/MakeDependencies.step2.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.h"
+ "#define COUNT 2\n"
+ )
diff --git a/Tests/RunCMake/BuildDepends/MakeInProjectOnly.c b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.c
new file mode 100644
index 0000000..0795aaa
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.c
@@ -0,0 +1,5 @@
+#include <MakeInProjectOnly.h>
+int main()
+{
+ return MakeInProjectOnly();
+}
diff --git a/Tests/RunCMake/BuildDepends/MakeInProjectOnly.cmake b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.cmake
new file mode 100644
index 0000000..af6ad86
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.cmake
@@ -0,0 +1,16 @@
+enable_language(C)
+get_filename_component(include_dir "${CMAKE_BINARY_DIR}" PATH)
+include_directories("${include_dir}")
+add_executable(MakeInProjectOnly MakeInProjectOnly.c)
+set(CMAKE_DEPENDS_IN_PROJECT_ONLY 1)
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+if (check_step EQUAL 1)
+ set(check_pairs
+ \"$<TARGET_FILE:MakeInProjectOnly>|${include_dir}/MakeInProjectOnly.h\"
+ )
+else()
+ set(check_pairs
+ \"${include_dir}/MakeInProjectOnly.h|\$<TARGET_FILE:MakeInProjectOnly>\"
+ )
+endif()
+")
diff --git a/Tests/RunCMake/BuildDepends/MakeInProjectOnly.step1.cmake b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.step1.cmake
new file mode 100644
index 0000000..d6551ab
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.step1.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/../MakeInProjectOnly.h" [[
+int MakeInProjectOnly(void) { return 0; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/MakeInProjectOnly.step2.cmake b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.step2.cmake
new file mode 100644
index 0000000..145605b
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.step2.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/../MakeInProjectOnly.h" [[
+int MakeInProjectOnly(void) { return 1; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/RepeatCMake-Custom-Script.cmake b/Tests/RunCMake/BuildDepends/RepeatCMake-Custom-Script.cmake
new file mode 100644
index 0000000..3e953b3
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/RepeatCMake-Custom-Script.cmake
@@ -0,0 +1,4 @@
+if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/exists-for-build2")
+ message(FATAL_ERROR "Custom command incorrectly re-ran after CMake re-ran!")
+endif()
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/out.txt")
diff --git a/Tests/RunCMake/BuildDepends/RepeatCMake-Custom.cmake b/Tests/RunCMake/BuildDepends/RepeatCMake-Custom.cmake
new file mode 100644
index 0000000..697e485
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/RepeatCMake-Custom.cmake
@@ -0,0 +1,5 @@
+add_custom_command(OUTPUT out.txt
+ COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/RepeatCMake-Custom-Script.cmake
+ DEPENDS ${CMAKE_CURRENT_LIST_DIR}/RepeatCMake-Custom-Script.cmake
+ )
+add_custom_target(drive ALL DEPENDS out.txt)
diff --git a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
new file mode 100644
index 0000000..6232634
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
@@ -0,0 +1,166 @@
+include(RunCMake)
+
+if(RunCMake_GENERATOR STREQUAL "Borland Makefiles" OR
+ RunCMake_GENERATOR STREQUAL "Watcom WMake")
+ set(fs_delay 3)
+else()
+ set(fs_delay 1.125)
+endif()
+
+function(run_BuildDepends CASE)
+ # Use a single build tree for a few tests without cleaning.
+ if(NOT RunCMake_TEST_BINARY_DIR)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${CASE}-build)
+ endif()
+ set(RunCMake_TEST_NO_CLEAN 1)
+ if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+ endif()
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ include(${RunCMake_SOURCE_DIR}/${CASE}.step1.cmake OPTIONAL)
+ run_cmake(${CASE})
+ set(RunCMake-check-file check.cmake)
+ set(check_step 1)
+ run_cmake_command(${CASE}-build1 ${CMAKE_COMMAND} --build . --config Debug)
+ if(run_BuildDepends_skip_step_2)
+ return()
+ endif()
+ execute_process(COMMAND ${CMAKE_COMMAND} -E sleep ${fs_delay}) # handle 1s resolution
+ include(${RunCMake_SOURCE_DIR}/${CASE}.step2.cmake OPTIONAL)
+ set(check_step 2)
+ run_cmake_command(${CASE}-build2 ${CMAKE_COMMAND} --build . --config Debug)
+ if(run_BuildDepends_skip_step_3)
+ return()
+ endif()
+ execute_process(COMMAND ${CMAKE_COMMAND} -E sleep ${fs_delay}) # handle 1s resolution
+ include(${RunCMake_SOURCE_DIR}/${CASE}.step3.cmake OPTIONAL)
+ set(check_step 3)
+ run_cmake_command(${CASE}-build3 ${CMAKE_COMMAND} --build . --config Debug)
+endfunction()
+
+set(run_BuildDepends_skip_step_3 1)
+
+run_BuildDepends(C-Exe)
+if(NOT RunCMake_GENERATOR STREQUAL "Xcode")
+ if(RunCMake_GENERATOR MATCHES "Visual Studio 10" OR
+ RunCMake_GENERATOR_TOOLSET MATCHES "^(v80|v90|v100)$")
+ # VS 10 forgets to re-link when a manifest changes
+ set(run_BuildDepends_skip_step_2 1)
+ endif()
+ run_BuildDepends(C-Exe-Manifest)
+ unset(run_BuildDepends_skip_step_2)
+endif()
+
+run_BuildDepends(Custom-Symbolic-and-Byproduct)
+run_BuildDepends(Custom-Always)
+
+set(RunCMake_TEST_OUTPUT_MERGE_save "${RunCMake_TEST_OUTPUT_MERGE}")
+set(RunCMake_TEST_OUTPUT_MERGE 1)
+run_BuildDepends(ExternalProjectCacheArgs)
+set(RunCMake_TEST_OUTPUT_MERGE "${RunCMake_TEST_OUTPUT_MERGE_save}")
+
+# Test header dependencies with a build tree underneath a source tree.
+set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/BuildUnderSource")
+set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/BuildUnderSource/build")
+file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
+file(MAKE_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}/include")
+foreach(f CMakeLists.txt BuildUnderSource.cmake BuildUnderSource.c)
+ configure_file("${RunCMake_SOURCE_DIR}/${f}" "${RunCMake_TEST_SOURCE_DIR}/${f}" COPYONLY)
+endforeach()
+run_BuildDepends(BuildUnderSource)
+unset(RunCMake_TEST_BINARY_DIR)
+unset(RunCMake_TEST_SOURCE_DIR)
+
+if(RunCMake_GENERATOR MATCHES "Make")
+ run_BuildDepends(MakeCustomIncludes)
+ if(NOT "${RunCMake_BINARY_DIR}" STREQUAL "${RunCMake_SOURCE_DIR}")
+ run_BuildDepends(MakeInProjectOnly)
+ endif()
+endif()
+
+function(run_RepeatCMake CASE)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${CASE}-build)
+ if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(RunCMake_TEST_OPTIONS -DCMAKE_CONFIGURATION_TYPES=Debug)
+ else()
+ set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+ endif()
+ run_cmake(${CASE})
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(${CASE}-build1 ${CMAKE_COMMAND} --build . --config Debug)
+ run_cmake_command(${CASE}-rerun1 ${CMAKE_COMMAND} .)
+ file(WRITE ${RunCMake_TEST_BINARY_DIR}/exists-for-build2 "")
+ run_cmake_command(${CASE}-build2 ${CMAKE_COMMAND} --build . --config Debug)
+endfunction()
+
+run_RepeatCMake(RepeatCMake-Custom)
+
+function(run_ReGeneration)
+ # test re-generation of project even if CMakeLists.txt files disappeared
+
+ # Use a single build tree for a few tests without cleaning.
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/regenerate-project-build)
+ set(RunCMake_TEST_SOURCE_DIR ${RunCMake_BINARY_DIR}/regenerate-project-source)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
+ set(ProjectHeader [=[
+ cmake_minimum_required(VERSION 3.5)
+ project(Regenerate-Project NONE)
+ ]=])
+
+ # create project with subdirectory
+ file(WRITE "${RunCMake_TEST_SOURCE_DIR}/CMakeLists.txt" "${ProjectHeader}"
+ "add_subdirectory(mysubdir)")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}/mysubdir")
+ file(WRITE "${RunCMake_TEST_SOURCE_DIR}/mysubdir/CMakeLists.txt" "# empty")
+
+ run_cmake(Regenerate-Project)
+ execute_process(COMMAND ${CMAKE_COMMAND} -E sleep ${fs_delay})
+
+ # now we delete the subdirectory and adjust the CMakeLists.txt
+ file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}/mysubdir")
+ file(WRITE "${RunCMake_TEST_SOURCE_DIR}/CMakeLists.txt" "${ProjectHeader}")
+
+ run_cmake_command(Regenerate-Project-Directory-Removed
+ ${CMAKE_COMMAND} --build "${RunCMake_TEST_BINARY_DIR}")
+
+ unset(RunCMake_TEST_BINARY_DIR)
+ unset(RunCMake_TEST_SOURCE_DIR)
+ unset(RunCMake_TEST_NO_CLEAN)
+endfunction()
+
+if(RunCMake_GENERATOR STREQUAL "Xcode")
+ run_ReGeneration(regenerate-project)
+endif()
+
+if(CMake_TEST_BuildDepends_GNU_AS)
+ set(ENV{ASM} "${CMake_TEST_BuildDepends_GNU_AS}")
+ run_BuildDepends(GNU-AS)
+endif()
+
+if ((RunCMake_GENERATOR STREQUAL "Unix Makefiles"
+ AND (CMAKE_C_COMPILER_ID STREQUAL "GNU"
+ OR CMAKE_C_COMPILER_ID STREQUAL "Clang"
+ OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang"))
+ OR (RunCMake_GENERATOR STREQUAL "NMake Makefiles"
+ AND MSVC_VERSION GREATER 1300
+ AND CMAKE_C_COMPILER_ID STREQUAL "MSVC"))
+ run_BuildDepends(CompilerDependencies)
+ run_BuildDepends(CustomCommandDependencies)
+endif()
+
+if (RunCMake_GENERATOR MATCHES "Makefiles")
+ run_cmake(CustomCommandDependencies-BadArgs)
+endif()
+
+if(RunCMake_GENERATOR MATCHES "Make|Ninja")
+ unset(run_BuildDepends_skip_step_3)
+ run_BuildDepends(CustomCommandDepfile)
+ set(run_BuildDepends_skip_step_3 1)
+endif()
+
+if(RunCMake_GENERATOR MATCHES "Make")
+ run_BuildDepends(MakeDependencies)
+endif()
diff --git a/Tests/RunCMake/BuildDepends/WriteDepfile.cmake b/Tests/RunCMake/BuildDepends/WriteDepfile.cmake
new file mode 100644
index 0000000..c958cde
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/WriteDepfile.cmake
@@ -0,0 +1,8 @@
+file(WRITE "${OUTFILE}" [[int main(void)
+{
+ return 0;
+}
+]])
+string(REPLACE [[ ]] [[\ ]] OUTFILE "${OUTFILE}")
+string(REPLACE [[ ]] [[\ ]] INFILE "${INFILE}")
+file(WRITE "${DEPFILE}" "${OUTFILE}: ${INFILE}\n")
diff --git a/Tests/RunCMake/BuildDepends/check.cmake b/Tests/RunCMake/BuildDepends/check.cmake
new file mode 100644
index 0000000..c7b5c3d
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/check.cmake
@@ -0,0 +1,37 @@
+if(EXISTS ${RunCMake_TEST_BINARY_DIR}/check-debug.cmake)
+ include(${RunCMake_TEST_BINARY_DIR}/check-debug.cmake)
+ if(RunCMake_TEST_FAILED)
+ return()
+ endif()
+ foreach(exe IN LISTS check_exes)
+ execute_process(COMMAND ${exe} RESULT_VARIABLE res)
+ if(NOT res EQUAL ${check_step})
+ string(APPEND RunCMake_TEST_FAILED "
+ '${exe}' returned '${res}' but expected '${check_step}'
+")
+ endif()
+ endforeach()
+ foreach(p IN LISTS check_pairs)
+ if("${p}" MATCHES "^(.*)\\|(.*)$")
+ set(lhs "${CMAKE_MATCH_1}")
+ set(rhs "${CMAKE_MATCH_2}")
+ if(NOT EXISTS "${lhs}")
+ string(APPEND RunCMake_TEST_FAILED "
+ '${lhs}' missing
+")
+ elseif(NOT EXISTS "${rhs}")
+ string(APPEND RunCMake_TEST_FAILED "
+ '${rhs}' missing
+")
+ elseif(NOT "${lhs}" IS_NEWER_THAN "${rhs}")
+ string(APPEND RunCMake_TEST_FAILED "
+ '${lhs}' is not newer than '${rhs}'
+")
+ endif()
+ endif()
+ endforeach()
+else()
+ set(RunCMake_TEST_FAILED "
+ '${RunCMake_TEST_BINARY_DIR}/check-debug.cmake' missing
+")
+endif()
diff --git a/Tests/RunCMake/BuildDepends/gnu_as.s b/Tests/RunCMake/BuildDepends/gnu_as.s
new file mode 100644
index 0000000..a2e7dfb
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/gnu_as.s
@@ -0,0 +1 @@
+.include "gnu_as.inc"
diff --git a/Tests/RunCMake/BuildDepends/main.c b/Tests/RunCMake/BuildDepends/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-COMMAND-OLD-stderr.txt b/Tests/RunCMake/BundleUtilities/CMP0080-COMMAND-OLD-stderr.txt
new file mode 100644
index 0000000..31a0207
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/CMP0080-COMMAND-OLD-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Deprecation Warning at [^
+]*/Tests/RunCMake/BundleUtilities/CMP0080-COMMAND.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0080 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.$
diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-COMMAND.cmake b/Tests/RunCMake/BundleUtilities/CMP0080-COMMAND.cmake
new file mode 100644
index 0000000..063a7f3
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/CMP0080-COMMAND.cmake
@@ -0,0 +1,5 @@
+if(DEFINED CMP0080_VALUE)
+ cmake_policy(SET CMP0080 ${CMP0080_VALUE})
+endif()
+
+include(BundleUtilities)
diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-NEW-result.txt b/Tests/RunCMake/BundleUtilities/CMP0080-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/CMP0080-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-NEW-stderr.txt b/Tests/RunCMake/BundleUtilities/CMP0080-NEW-stderr.txt
new file mode 100644
index 0000000..1454b0c
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/CMP0080-NEW-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error at .*/Modules/BundleUtilities\.cmake:[0-9]+ \(message\):
+ BundleUtilities cannot be included at configure time!
diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-NEW.cmake b/Tests/RunCMake/BundleUtilities/CMP0080-NEW.cmake
new file mode 100644
index 0000000..558c16d
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/CMP0080-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0080 NEW)
+include(BundleUtilities)
diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-OLD-stderr.txt b/Tests/RunCMake/BundleUtilities/CMP0080-OLD-stderr.txt
new file mode 100644
index 0000000..2ff5d60
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/CMP0080-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0080-OLD.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0080 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-OLD.cmake b/Tests/RunCMake/BundleUtilities/CMP0080-OLD.cmake
new file mode 100644
index 0000000..a65d92f
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/CMP0080-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0080 OLD)
+include(BundleUtilities)
diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-WARN-stderr.txt b/Tests/RunCMake/BundleUtilities/CMP0080-WARN-stderr.txt
new file mode 100644
index 0000000..c3d541e
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/CMP0080-WARN-stderr.txt
@@ -0,0 +1,10 @@
+CMake Warning \(dev\) at .*/Modules/BundleUtilities\.cmake:[0-9]+ \(message\):
+ Policy CMP0080 is not set: BundleUtilities cannot be included at configure
+ time\. Run "cmake --help-policy CMP0080" for policy details\. Use the
+ cmake_policy command to set the policy and suppress this warning\.
+
+Call Stack \(most recent call first\):
+ .*/Modules/BundleUtilities\.cmake:[0-9]+ \(_warn_cmp0080\)
+ CMP0080-WARN\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-WARN.cmake b/Tests/RunCMake/BundleUtilities/CMP0080-WARN.cmake
new file mode 100644
index 0000000..45f6f92
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/CMP0080-WARN.cmake
@@ -0,0 +1 @@
+include(BundleUtilities)
diff --git a/Tests/RunCMake/BundleUtilities/CMakeLists.txt b/Tests/RunCMake/BundleUtilities/CMakeLists.txt
new file mode 100644
index 0000000..6dd8cdf
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.4)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/BundleUtilities/ExecutableScripts.cmake b/Tests/RunCMake/BundleUtilities/ExecutableScripts.cmake
new file mode 100644
index 0000000..78a9b66
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/ExecutableScripts.cmake
@@ -0,0 +1,18 @@
+include(BundleUtilities)
+
+set(BU_CHMOD_BUNDLE_ITEMS ON)
+
+function(check_script script)
+ fixup_bundle_item(${script} ${script} "" "")
+endfunction()
+
+# Should not throw any errors
+# Shell script
+set(script_sh_EMBEDDED_ITEM ${CMAKE_CURRENT_LIST_DIR}/test.app/script.sh)
+check_script(${CMAKE_CURRENT_LIST_DIR}/test.app/script.sh)
+# Batch script
+set(script_bat_EMBEDDED_ITEM ${CMAKE_CURRENT_LIST_DIR}/test.app/script.bat)
+check_script(${CMAKE_CURRENT_LIST_DIR}/test.app/script.bat)
+# Shell script without extension
+set(script_EMBEDDED_ITEM ${CMAKE_CURRENT_LIST_DIR}/test.app/script)
+check_script(${CMAKE_CURRENT_LIST_DIR}/test.app/script)
diff --git a/Tests/RunCMake/BundleUtilities/RunCMakeTest.cmake b/Tests/RunCMake/BundleUtilities/RunCMakeTest.cmake
new file mode 100644
index 0000000..df28102
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/RunCMakeTest.cmake
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.4)
+include(RunCMake)
+
+# TODO Migrate Tests/BundleUtilities here
+
+run_cmake(CMP0080-OLD)
+run_cmake(CMP0080-NEW)
+run_cmake(CMP0080-WARN)
+run_cmake_command(CMP0080-COMMAND-OLD ${CMAKE_COMMAND} -DCMP0080_VALUE:STRING=OLD -P ${RunCMake_SOURCE_DIR}/CMP0080-COMMAND.cmake)
+run_cmake_command(CMP0080-COMMAND-NEW ${CMAKE_COMMAND} -DCMP0080_VALUE:STRING=NEW -P ${RunCMake_SOURCE_DIR}/CMP0080-COMMAND.cmake)
+run_cmake_command(CMP0080-COMMAND-WARN ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/CMP0080-COMMAND.cmake)
+run_cmake_command(ExecutableScripts ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/ExecutableScripts.cmake)
diff --git a/Tests/RunCMake/BundleUtilities/test.app/script b/Tests/RunCMake/BundleUtilities/test.app/script
new file mode 100755
index 0000000..23bf47c
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/test.app/script
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+echo "Hello World"
diff --git a/Tests/RunCMake/BundleUtilities/test.app/script.bat b/Tests/RunCMake/BundleUtilities/test.app/script.bat
new file mode 100755
index 0000000..dbb0ec2
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/test.app/script.bat
@@ -0,0 +1,3 @@
+@echo off
+
+echo "Hello world"
diff --git a/Tests/RunCMake/BundleUtilities/test.app/script.sh b/Tests/RunCMake/BundleUtilities/test.app/script.sh
new file mode 100755
index 0000000..23bf47c
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/test.app/script.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+echo "Hello World"
diff --git a/Tests/RunCMake/Byproducts/CMakeLists.txt b/Tests/RunCMake/Byproducts/CMakeLists.txt
new file mode 100644
index 0000000..bf2ef15
--- /dev/null
+++ b/Tests/RunCMake/Byproducts/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.10)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/Byproducts/CleanByproducts.cmake b/Tests/RunCMake/Byproducts/CleanByproducts.cmake
new file mode 100644
index 0000000..85d9582
--- /dev/null
+++ b/Tests/RunCMake/Byproducts/CleanByproducts.cmake
@@ -0,0 +1,93 @@
+cmake_minimum_required(VERSION 3.10)
+project(CleanByproducts)
+
+# Configurable parameters
+set(TEST_CLEAN_NO_CUSTOM FALSE CACHE BOOL "Value for the CLEAN_NO_CUSTOM PROPERTY")
+set(TEST_BUILD_EVENTS TRUE CACHE BOOL "Create byproducts with build events")
+set(TEST_CUSTOM_TARGET TRUE CACHE BOOL "Create a byproduct with a custom target")
+set(TEST_CUSTOM_COMMAND TRUE CACHE BOOL "Create a byproduct with a custom command")
+
+set_property(DIRECTORY PROPERTY CLEAN_NO_CUSTOM ${TEST_CLEAN_NO_CUSTOM})
+
+macro(add_build_event)
+ set(oneValueArgs EVENT)
+
+ cmake_parse_Arguments(ABE "" "${oneValueArgs}" "" ${ARGN})
+
+ # Create two byproducts and only declare one
+ add_custom_command(TARGET foo
+ ${ABE_EVENT}
+ COMMAND ${CMAKE_COMMAND} -E touch foo.${ABE_EVENT}
+ COMMAND ${CMAKE_COMMAND} -E touch foo.${ABE_EVENT}.notdeclared
+ COMMENT "Creating byproducts with ${ABE_EVENT}"
+ BYPRODUCTS foo.${ABE_EVENT}
+ )
+
+ # The nondeclared byproduct should always be present
+ list(APPEND EXPECTED_PRESENT foo.${ABE_EVENT}.notdeclared)
+
+ # If CLEAN_NO_CUSTOM is set, the declared byproduct should be present
+ if(TEST_CLEAN_NO_CUSTOM)
+ list(APPEND EXPECTED_PRESENT foo.${ABE_EVENT})
+ else()
+ list(APPEND EXPECTED_DELETED foo.${ABE_EVENT})
+ endif()
+endmacro()
+
+add_executable(foo foo.cpp)
+
+# Test build events
+if(TEST_BUILD_EVENTS)
+ add_build_event(EVENT "PRE_BUILD" ENABLE ${TEST_PRE_BUILD})
+ add_build_event(EVENT "PRE_LINK" ENABLE ${TEST_PRE_LINK})
+ add_build_event(EVENT "POST_BUILD" ENABLE ${TEST_POST_BUILD})
+endif()
+
+# Custom command that generates byproducts
+if(TEST_CUSTOM_COMMAND)
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bar.cpp.in "void bar() {}\n")
+ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/bar.cpp
+ COMMAND ${CMAKE_COMMAND} -E touch foo.customcommand
+ COMMAND ${CMAKE_COMMAND} -E touch foo.customcommand.notdeclared
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/bar.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/bar.cpp
+ BYPRODUCTS foo.customcommand
+ COMMENT "Creating byproducts with a custom command"
+ )
+
+ # The nondeclared byproduct should always be present
+ list(APPEND EXPECTED_PRESENT "foo.customcommand.notdeclared")
+
+ # If CLEAN_NO_CUSTOM is set, both the output and byproduct should be present
+ if(TEST_CLEAN_NO_CUSTOM)
+ list(APPEND EXPECTED_PRESENT "bar.cpp")
+ list(APPEND EXPECTED_PRESENT "foo.customcommand")
+ else()
+ list(APPEND EXPECTED_DELETED "bar.cpp")
+ list(APPEND EXPECTED_DELETED "foo.customcommand")
+ endif()
+
+ target_sources(foo PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/bar.cpp")
+endif()
+
+# Custom target that generates byproducts
+if(TEST_CUSTOM_TARGET)
+ add_custom_target(foo_file ALL
+ DEPENDS foo
+ COMMAND ${CMAKE_COMMAND} -E touch foo.customtarget
+ COMMAND ${CMAKE_COMMAND} -E touch foo.customtarget.notdeclared
+ BYPRODUCTS foo.customtarget
+ COMMENT "Creating byproducts with a custom target"
+ )
+
+ # The nondeclared byproduct should always be present
+ list(APPEND EXPECTED_PRESENT "foo.customtarget.notdeclared")
+
+ # If CLEAN_NO_CUSTOM is set, the declared byproduct should be present
+ if(TEST_CLEAN_NO_CUSTOM)
+ list(APPEND EXPECTED_PRESENT "foo.customtarget")
+ else()
+ list(APPEND EXPECTED_DELETED "foo.customtarget")
+ endif()
+endif()
+
+configure_file(files.cmake.in files.cmake)
diff --git a/Tests/RunCMake/Byproducts/RunCMakeTest.cmake b/Tests/RunCMake/Byproducts/RunCMakeTest.cmake
new file mode 100644
index 0000000..a7584ee
--- /dev/null
+++ b/Tests/RunCMake/Byproducts/RunCMakeTest.cmake
@@ -0,0 +1,58 @@
+include(RunCMake)
+
+function(run_CleanByproducts case)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CleanByproducts-${case}-build)
+ set(RunCMake_TEST_OPTIONS "${ARGN}")
+
+ run_cmake(CleanByproducts)
+ set(RunCMake_TEST_NO_CLEAN 1)
+
+ run_cmake_command(CleanByProducts-build ${CMAKE_COMMAND} --build .)
+ include("${RunCMake_TEST_BINARY_DIR}/files.cmake")
+
+ message("Checking that all expected files are present")
+ check_files(EXPECTED_PRESENT "${RunCMake_TEST_BINARY_DIR}" TRUE)
+ check_files(EXPECTED_DELETED "${RunCMake_TEST_BINARY_DIR}" TRUE)
+
+ run_cmake_command(CleanByProducts-clean ${CMAKE_COMMAND} --build . --target clean)
+
+ message("Checking that only the expected files are present after cleaning")
+ check_files(EXPECTED_PRESENT "${RunCMake_TEST_BINARY_DIR}" TRUE)
+ check_files(EXPECTED_DELETED "${RunCMake_TEST_BINARY_DIR}" FALSE)
+endfunction()
+
+function(check_files list path has_to_exist)
+ foreach(file IN LISTS ${list})
+ message("Checking ${file}")
+ set(file_exists FALSE)
+ if(EXISTS "${path}/${file}")
+ set(file_exists TRUE)
+ endif()
+
+ if(file_exists AND NOT has_to_exist)
+ message(FATAL_ERROR "${file} should have been deleted")
+ elseif(NOT file_exists AND has_to_exist)
+ message(FATAL_ERROR "${file} does not exist")
+ elseif(file_exists AND has_to_exist)
+ message("${file} found as expected")
+ elseif(NOT file_exists AND NOT has_to_exist)
+ message("${file} deleted as expected")
+ endif()
+
+ endforeach()
+endfunction()
+
+
+# Iterate through all possible test values
+set(counter 0)
+foreach(test_clean_no_custom TRUE FALSE)
+ foreach(test_build_events TRUE FALSE)
+ foreach(test_custom_command TRUE FALSE)
+ foreach(test_custom_target TRUE FALSE)
+ math(EXPR counter "${counter} + 1")
+ message("Test ${counter} - CLEAN_NO_CUSTOM: ${test_clean_no_custom}, Build events: ${test_build_events}, Custom command: ${test_custom_command}, Custom target: ${test_custom_target}")
+ run_CleanByproducts("buildevents${counter}" -DCLEAN_NO_CUSTOM=${test_clean_no_custom} -DTEST_BUILD_EVENTS=${test_build_events} -DTEST_CUSTOM_COMMAND=${test_custom_command} -DTEST_CUSTOM_TARGET=${test_custom_target})
+ endforeach()
+ endforeach()
+ endforeach()
+endforeach()
diff --git a/Tests/RunCMake/Byproducts/files.cmake.in b/Tests/RunCMake/Byproducts/files.cmake.in
new file mode 100644
index 0000000..a7d4831
--- /dev/null
+++ b/Tests/RunCMake/Byproducts/files.cmake.in
@@ -0,0 +1,2 @@
+set(EXPECTED_PRESENT "@EXPECTED_PRESENT@")
+set(EXPECTED_DELETED "@EXPECTED_DELETED@")
diff --git a/Tests/RunCMake/Byproducts/foo.cpp b/Tests/RunCMake/Byproducts/foo.cpp
new file mode 100644
index 0000000..d47cb91
--- /dev/null
+++ b/Tests/RunCMake/Byproducts/foo.cpp
@@ -0,0 +1,14 @@
+int bar(int y)
+{
+ return y * 6;
+}
+
+int foo(int x)
+{
+ return x * bar(x);
+}
+
+int main()
+{
+ return foo(4);
+}
diff --git a/Tests/RunCMake/CMP0004/CMP0004-NEW-result.txt b/Tests/RunCMake/CMP0004/CMP0004-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0004/CMP0004-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0004/CMP0004-NEW-stderr.txt b/Tests/RunCMake/CMP0004/CMP0004-NEW-stderr.txt
new file mode 100644
index 0000000..a21cb6a
--- /dev/null
+++ b/Tests/RunCMake/CMP0004/CMP0004-NEW-stderr.txt
@@ -0,0 +1,2 @@
+ Target "foo" links to item " bar " which has leading or trailing
+ whitespace. This is now an error according to policy CMP0004.
diff --git a/Tests/RunCMake/CMP0004/CMP0004-NEW.cmake b/Tests/RunCMake/CMP0004/CMP0004-NEW.cmake
new file mode 100644
index 0000000..f42d8e4
--- /dev/null
+++ b/Tests/RunCMake/CMP0004/CMP0004-NEW.cmake
@@ -0,0 +1,9 @@
+
+cmake_minimum_required(VERSION 2.8.4)
+
+cmake_policy(SET CMP0004 NEW)
+
+add_library(foo SHARED empty.cpp)
+add_library(bar SHARED empty.cpp)
+
+target_link_libraries(foo "$<1: bar >")
diff --git a/Tests/RunCMake/CMP0004/CMP0004-OLD-result.txt b/Tests/RunCMake/CMP0004/CMP0004-OLD-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0004/CMP0004-OLD-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0004/CMP0004-OLD-stderr.txt b/Tests/RunCMake/CMP0004/CMP0004-OLD-stderr.txt
new file mode 100644
index 0000000..782e45c
--- /dev/null
+++ b/Tests/RunCMake/CMP0004/CMP0004-OLD-stderr.txt
@@ -0,0 +1,2 @@
+ Target "bat" links to item " bar " which has leading or trailing
+ whitespace. This is now an error according to policy CMP0004.
diff --git a/Tests/RunCMake/CMP0004/CMP0004-OLD.cmake b/Tests/RunCMake/CMP0004/CMP0004-OLD.cmake
new file mode 100644
index 0000000..3fa58b6
--- /dev/null
+++ b/Tests/RunCMake/CMP0004/CMP0004-OLD.cmake
@@ -0,0 +1,21 @@
+
+cmake_minimum_required(VERSION 2.8.4)
+
+cmake_policy(SET CMP0004 OLD)
+
+add_library(foo SHARED empty.cpp)
+add_library(bar SHARED empty.cpp)
+add_library(bing SHARED empty.cpp)
+add_library(bung SHARED empty.cpp)
+
+cmake_policy(SET CMP0004 NEW)
+
+add_library(bat SHARED empty.cpp)
+
+target_link_libraries(foo "$<1: bar >")
+target_link_libraries(bing "$<$<NOT:$<TARGET_POLICY:CMP0004>>: bar >")
+target_link_libraries(bung "$<$<TARGET_POLICY:CMP0004>: bar >")
+
+# The line below causes the error because the policy is NEW when bat
+# is created.
+target_link_libraries(bat "$<1: bar >")
diff --git a/Tests/RunCMake/CMP0004/CMP0004-WARN-stderr.txt b/Tests/RunCMake/CMP0004/CMP0004-WARN-stderr.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMP0004/CMP0004-WARN-stderr.txt
diff --git a/Tests/RunCMake/CMP0004/CMP0004-policy-genex-result.txt b/Tests/RunCMake/CMP0004/CMP0004-policy-genex-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0004/CMP0004-policy-genex-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0004/CMP0004-policy-genex-stderr.txt b/Tests/RunCMake/CMP0004/CMP0004-policy-genex-stderr.txt
new file mode 100644
index 0000000..eed53e7
--- /dev/null
+++ b/Tests/RunCMake/CMP0004/CMP0004-policy-genex-stderr.txt
@@ -0,0 +1,2 @@
+ Target "foo" links to item " bat " which has leading or trailing
+ whitespace. This is now an error according to policy CMP0004.
diff --git a/Tests/RunCMake/CMP0004/CMP0004-policy-genex.cmake b/Tests/RunCMake/CMP0004/CMP0004-policy-genex.cmake
new file mode 100644
index 0000000..2970476
--- /dev/null
+++ b/Tests/RunCMake/CMP0004/CMP0004-policy-genex.cmake
@@ -0,0 +1,14 @@
+
+cmake_minimum_required(VERSION 2.8.4)
+
+cmake_policy(SET CMP0004 NEW)
+
+add_library(foo SHARED empty.cpp)
+add_library(bar SHARED empty.cpp)
+add_library(bat SHARED empty.cpp)
+
+# The negation here avoids the error.
+target_link_libraries(foo "$<$<NOT:$<TARGET_POLICY:CMP0004>>: bar >")
+
+# The below line causes the error.
+target_link_libraries(foo "$<$<TARGET_POLICY:CMP0004>: bat >")
diff --git a/Tests/RunCMake/CMP0004/CMakeLists.txt b/Tests/RunCMake/CMP0004/CMakeLists.txt
new file mode 100644
index 0000000..12cd3c7
--- /dev/null
+++ b/Tests/RunCMake/CMP0004/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.4)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0004/RunCMakeTest.cmake b/Tests/RunCMake/CMP0004/RunCMakeTest.cmake
new file mode 100644
index 0000000..950d0ed
--- /dev/null
+++ b/Tests/RunCMake/CMP0004/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0004-OLD)
+run_cmake(CMP0004-NEW)
+run_cmake(CMP0004-policy-genex)
diff --git a/Tests/RunCMake/CMP0004/empty.cpp b/Tests/RunCMake/CMP0004/empty.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMP0004/empty.cpp
diff --git a/Tests/RunCMake/CMP0019/CMP0019-NEW-stderr.txt b/Tests/RunCMake/CMP0019/CMP0019-NEW-stderr.txt
new file mode 100644
index 0000000..66a58fb
--- /dev/null
+++ b/Tests/RunCMake/CMP0019/CMP0019-NEW-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Deprecation Warning at CMakeLists.txt:1 \(cmake_minimum_required\):
+ Compatibility with CMake < 2.8.12 will be removed from a future version of
+ CMake.
+
+ Update the VERSION argument <min> value or use a ...<max> suffix to tell
+ CMake that the project does not need compatibility with older versions.$
diff --git a/Tests/RunCMake/CMP0019/CMP0019-NEW.cmake b/Tests/RunCMake/CMP0019/CMP0019-NEW.cmake
new file mode 100644
index 0000000..3091e66
--- /dev/null
+++ b/Tests/RunCMake/CMP0019/CMP0019-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0019 NEW)
+include(CMP0019-code.cmake)
diff --git a/Tests/RunCMake/CMP0019/CMP0019-OLD-stderr.txt b/Tests/RunCMake/CMP0019/CMP0019-OLD-stderr.txt
new file mode 100644
index 0000000..a446211
--- /dev/null
+++ b/Tests/RunCMake/CMP0019/CMP0019-OLD-stderr.txt
@@ -0,0 +1,17 @@
+^CMake Deprecation Warning at CMakeLists.txt:1 \(cmake_minimum_required\):
+ Compatibility with CMake < 2.8.12 will be removed from a future version of
+ CMake.
+
+ Update the VERSION argument <min> value or use a ...<max> suffix to tell
+ CMake that the project does not need compatibility with older versions.
++
+CMake Deprecation Warning at CMP0019-OLD.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0019 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0019/CMP0019-OLD.cmake b/Tests/RunCMake/CMP0019/CMP0019-OLD.cmake
new file mode 100644
index 0000000..0f02f9c
--- /dev/null
+++ b/Tests/RunCMake/CMP0019/CMP0019-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0019 OLD)
+include(CMP0019-code.cmake)
diff --git a/Tests/RunCMake/CMP0019/CMP0019-WARN-stderr.txt b/Tests/RunCMake/CMP0019/CMP0019-WARN-stderr.txt
new file mode 100644
index 0000000..f7b9c0e
--- /dev/null
+++ b/Tests/RunCMake/CMP0019/CMP0019-WARN-stderr.txt
@@ -0,0 +1,47 @@
+^CMake Deprecation Warning at CMakeLists.txt:1 \(cmake_minimum_required\):
+ Compatibility with CMake < 2.8.12 will be removed from a future version of
+ CMake.
+
+ Update the VERSION argument <min> value or use a ...<max> suffix to tell
+ CMake that the project does not need compatibility with older versions.
++
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0019 is not set: Do not re-expand variables in include and link
+ information. Run "cmake --help-policy CMP0019" for policy details. Use
+ the cmake_policy command to set the policy and suppress this warning.
+
+ The following variable evaluations were encountered:
+
+ Evaluated directory INCLUDE_DIRECTORIES
+
+ /usr/include/\${VAR_INCLUDE};/usr/include/normal
+
+ as
+
+ /usr/include/VAL_INCLUDE;/usr/include/normal
+
+ Evaluated target some_target INCLUDE_DIRECTORIES
+
+ /usr/include/\${VAR_INCLUDE};/usr/include/normal
+
+ as
+
+ /usr/include/VAL_INCLUDE;/usr/include/normal
+
+ Evaluated link directories
+
+ /usr/lib/\${VAR_LINK_DIRS};/usr/lib/normal
+
+ as
+
+ /usr/lib/VAL_LINK_DIRS;/usr/lib/normal
+
+ Evaluated link library
+
+ \${VAR_LINK_LIBS}
+
+ as
+
+ VAL_LINK_LIBS
+
+This warning is for project developers. Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/CMP0019/CMP0019-WARN.cmake b/Tests/RunCMake/CMP0019/CMP0019-WARN.cmake
new file mode 100644
index 0000000..a419f30
--- /dev/null
+++ b/Tests/RunCMake/CMP0019/CMP0019-WARN.cmake
@@ -0,0 +1 @@
+include(CMP0019-code.cmake)
diff --git a/Tests/RunCMake/CMP0019/CMP0019-code.cmake b/Tests/RunCMake/CMP0019/CMP0019-code.cmake
new file mode 100644
index 0000000..26c0e5b
--- /dev/null
+++ b/Tests/RunCMake/CMP0019/CMP0019-code.cmake
@@ -0,0 +1,9 @@
+set(VAR_INCLUDE "VAL_INCLUDE")
+set(VAR_LINK_DIRS "VAL_LINK_DIRS")
+set(VAR_LINK_LIBS "VAL_LINK_LIBS")
+add_custom_target(some_target)
+include_directories("/usr/include/\${VAR_INCLUDE}" /usr/include/normal)
+link_directories("/usr/lib/\${VAR_LINK_DIRS}" /usr/lib/normal)
+link_libraries("\${VAR_LINK_LIBS}" normal)
+add_custom_target(other_target)
+set_property(TARGET other_target PROPERTY INCLUDE_DIRECTORIES "")
diff --git a/Tests/RunCMake/CMP0019/CMakeLists.txt b/Tests/RunCMake/CMP0019/CMakeLists.txt
new file mode 100644
index 0000000..8f85fbf
--- /dev/null
+++ b/Tests/RunCMake/CMP0019/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.4)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE)
diff --git a/Tests/RunCMake/CMP0019/RunCMakeTest.cmake b/Tests/RunCMake/CMP0019/RunCMakeTest.cmake
new file mode 100644
index 0000000..119fc2b
--- /dev/null
+++ b/Tests/RunCMake/CMP0019/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0019-WARN)
+run_cmake(CMP0019-OLD)
+run_cmake(CMP0019-NEW)
diff --git a/Tests/RunCMake/CMP0022/CMP0022-NOWARN-exe-stderr.txt b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-exe-stderr.txt
new file mode 100644
index 0000000..66a58fb
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-exe-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Deprecation Warning at CMakeLists.txt:1 \(cmake_minimum_required\):
+ Compatibility with CMake < 2.8.12 will be removed from a future version of
+ CMake.
+
+ Update the VERSION argument <min> value or use a ...<max> suffix to tell
+ CMake that the project does not need compatibility with older versions.$
diff --git a/Tests/RunCMake/CMP0022/CMP0022-NOWARN-exe.cmake b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-exe.cmake
new file mode 100644
index 0000000..b0268c8
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-exe.cmake
@@ -0,0 +1,7 @@
+enable_language(CXX)
+
+add_library(testLib empty_vs6_1.cpp)
+add_executable(testExe empty_vs6_2.cpp)
+target_link_libraries(testExe testLib)
+
+export(TARGETS testExe FILE "${CMAKE_CURRENT_BINARY_DIR}/cmp0022NOWARN-exe.cmake")
diff --git a/Tests/RunCMake/CMP0022/CMP0022-NOWARN-shared-stderr.txt b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-shared-stderr.txt
new file mode 100644
index 0000000..66a58fb
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-shared-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Deprecation Warning at CMakeLists.txt:1 \(cmake_minimum_required\):
+ Compatibility with CMake < 2.8.12 will be removed from a future version of
+ CMake.
+
+ Update the VERSION argument <min> value or use a ...<max> suffix to tell
+ CMake that the project does not need compatibility with older versions.$
diff --git a/Tests/RunCMake/CMP0022/CMP0022-NOWARN-shared.cmake b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-shared.cmake
new file mode 100644
index 0000000..2e76ee0
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-shared.cmake
@@ -0,0 +1,10 @@
+enable_language(CXX)
+
+cmake_policy(SET CMP0042 NEW)
+
+add_library(foo SHARED empty_vs6_1.cpp)
+add_library(bar SHARED empty_vs6_2.cpp)
+target_link_libraries(bar foo)
+
+add_executable(zot empty.cpp)
+target_link_libraries(zot bar)
diff --git a/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-NEW-stderr.txt b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-NEW-stderr.txt
new file mode 100644
index 0000000..66a58fb
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-NEW-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Deprecation Warning at CMakeLists.txt:1 \(cmake_minimum_required\):
+ Compatibility with CMake < 2.8.12 will be removed from a future version of
+ CMake.
+
+ Update the VERSION argument <min> value or use a ...<max> suffix to tell
+ CMake that the project does not need compatibility with older versions.$
diff --git a/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-NEW.cmake b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-NEW.cmake
new file mode 100644
index 0000000..3fee15d
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-NEW.cmake
@@ -0,0 +1,14 @@
+
+project(CMP0022-NOWARN-static-NEW)
+
+cmake_policy(SET CMP0022 NEW)
+
+add_library(foo STATIC empty_vs6_1.cpp)
+add_library(bar STATIC empty_vs6_2.cpp)
+add_library(bat STATIC empty_vs6_3.cpp)
+target_link_libraries(foo bar)
+# The last element here needs to contain a space so that it is a single
+# element which is not a valid target name. As bar is a STATIC library,
+# this tests that the LINK_ONLY generator expression is not used for
+# that element, creating an error.
+target_link_libraries(bar LINK_PRIVATE bat "-lz -lm")
diff --git a/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-link_libraries-stderr.txt b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-link_libraries-stderr.txt
new file mode 100644
index 0000000..66a58fb
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-link_libraries-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Deprecation Warning at CMakeLists.txt:1 \(cmake_minimum_required\):
+ Compatibility with CMake < 2.8.12 will be removed from a future version of
+ CMake.
+
+ Update the VERSION argument <min> value or use a ...<max> suffix to tell
+ CMake that the project does not need compatibility with older versions.$
diff --git a/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-link_libraries.cmake b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-link_libraries.cmake
new file mode 100644
index 0000000..42c4084
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-link_libraries.cmake
@@ -0,0 +1,9 @@
+
+enable_language(CXX)
+
+add_subdirectory(dep1)
+add_subdirectory(dep2)
+add_subdirectory(dep3)
+
+add_library(somelib empty.cpp)
+target_link_libraries(somelib dep3)
diff --git a/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-stderr.txt b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-stderr.txt
new file mode 100644
index 0000000..66a58fb
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Deprecation Warning at CMakeLists.txt:1 \(cmake_minimum_required\):
+ Compatibility with CMake < 2.8.12 will be removed from a future version of
+ CMake.
+
+ Update the VERSION argument <min> value or use a ...<max> suffix to tell
+ CMake that the project does not need compatibility with older versions.$
diff --git a/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static.cmake b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static.cmake
new file mode 100644
index 0000000..3e4144f
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-NOWARN-static.cmake
@@ -0,0 +1,8 @@
+
+project(CMP0022-NOWARN-static)
+
+add_library(foo STATIC empty_vs6_1.cpp)
+add_library(bar STATIC empty_vs6_2.cpp)
+add_library(bat STATIC empty_vs6_3.cpp)
+target_link_libraries(foo bar)
+target_link_libraries(bar bat)
diff --git a/Tests/RunCMake/CMP0022/CMP0022-WARN-empty-old-result.txt b/Tests/RunCMake/CMP0022/CMP0022-WARN-empty-old-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-WARN-empty-old-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0022/CMP0022-WARN-empty-old-stderr.txt b/Tests/RunCMake/CMP0022/CMP0022-WARN-empty-old-stderr.txt
new file mode 100644
index 0000000..87404d3
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-WARN-empty-old-stderr.txt
@@ -0,0 +1,26 @@
+^CMake Deprecation Warning at CMakeLists.txt:1 \(cmake_minimum_required\):
+ Compatibility with CMake < 2.8.12 will be removed from a future version of
+ CMake.
+
+ Update the VERSION argument <min> value or use a ...<max> suffix to tell
+ CMake that the project does not need compatibility with older versions.
++
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0022 is not set: INTERFACE_LINK_LIBRARIES defines the link
+ interface. Run "cmake --help-policy CMP0022" for policy details. Use the
+ cmake_policy command to set the policy and suppress this warning.
+
+ Target "bar" has an INTERFACE_LINK_LIBRARIES property. This should be
+ preferred as the source of the link interface for this library but because
+ CMP0022 is not set CMake is ignoring the property and using the link
+ implementation as the link interface instead.
+
+ INTERFACE_LINK_LIBRARIES:
+
+ foo
+
+ Link implementation:
+
+ \(empty\)
+
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0022/CMP0022-WARN-empty-old.cmake b/Tests/RunCMake/CMP0022/CMP0022-WARN-empty-old.cmake
new file mode 100644
index 0000000..c5d3c29
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-WARN-empty-old.cmake
@@ -0,0 +1,10 @@
+
+project(CMP0022-WARN-empty-old)
+
+add_library(foo SHARED empty_vs6_1.cpp)
+add_library(bar SHARED empty_vs6_2.cpp)
+
+set_property(TARGET bar PROPERTY INTERFACE_LINK_LIBRARIES foo)
+
+add_library(user empty.cpp)
+target_link_libraries(user bar)
diff --git a/Tests/RunCMake/CMP0022/CMP0022-WARN-static-result.txt b/Tests/RunCMake/CMP0022/CMP0022-WARN-static-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-WARN-static-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0022/CMP0022-WARN-static-stderr.txt b/Tests/RunCMake/CMP0022/CMP0022-WARN-static-stderr.txt
new file mode 100644
index 0000000..1370c5e
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-WARN-static-stderr.txt
@@ -0,0 +1,19 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0022 is not set: INTERFACE_LINK_LIBRARIES defines the link
+ interface. Run "cmake --help-policy CMP0022" for policy details. Use the
+ cmake_policy command to set the policy and suppress this warning.
+
+ Target "bar" has an INTERFACE_LINK_LIBRARIES property. This should be
+ preferred as the source of the link interface for this library but because
+ CMP0022 is not set CMake is ignoring the property and using the link
+ implementation as the link interface instead.
+
+ INTERFACE_LINK_LIBRARIES:
+
+ foo
+
+ Link implementation:
+
+ bat
+
+This warning is for project developers. Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/CMP0022/CMP0022-WARN-static.cmake b/Tests/RunCMake/CMP0022/CMP0022-WARN-static.cmake
new file mode 100644
index 0000000..b3cb131
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-WARN-static.cmake
@@ -0,0 +1,11 @@
+
+project(CMP0022-WARN)
+
+add_library(foo STATIC empty_vs6_1.cpp)
+add_library(bar STATIC empty_vs6_2.cpp)
+add_library(bat STATIC empty_vs6_3.cpp)
+set_property(TARGET bar PROPERTY INTERFACE_LINK_LIBRARIES foo)
+set_property(TARGET bar PROPERTY LINK_LIBRARIES bat)
+
+add_library(user empty.cpp)
+target_link_libraries(user bar)
diff --git a/Tests/RunCMake/CMP0022/CMP0022-WARN-stderr.txt b/Tests/RunCMake/CMP0022/CMP0022-WARN-stderr.txt
new file mode 100644
index 0000000..5d75720
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-WARN-stderr.txt
@@ -0,0 +1,24 @@
+^CMake Deprecation Warning at CMakeLists.txt:1 \(cmake_minimum_required\):
+ Compatibility with CMake < 2.8.12 will be removed from a future version of
+ CMake.
+
+ Update the VERSION argument <min> value or use a ...<max> suffix to tell
+ CMake that the project does not need compatibility with older versions.
++
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0022 is not set: INTERFACE_LINK_LIBRARIES defines the link
+ interface. Run "cmake --help-policy CMP0022" for policy details. Use the
+ cmake_policy command to set the policy and suppress this warning.
+
+ Target "bar" has an INTERFACE_LINK_LIBRARIES property which differs from
+ its LINK_INTERFACE_LIBRARIES properties.
+
+ INTERFACE_LINK_LIBRARIES:
+
+ foo
+
+ LINK_INTERFACE_LIBRARIES:
+
+ bat
+
+This warning is for project developers. Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/CMP0022/CMP0022-WARN-tll-result.txt b/Tests/RunCMake/CMP0022/CMP0022-WARN-tll-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-WARN-tll-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0022/CMP0022-WARN-tll-stderr.txt b/Tests/RunCMake/CMP0022/CMP0022-WARN-tll-stderr.txt
new file mode 100644
index 0000000..5d39214
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-WARN-tll-stderr.txt
@@ -0,0 +1,17 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0022 is not set: INTERFACE_LINK_LIBRARIES defines the link
+ interface. Run "cmake --help-policy CMP0022" for policy details. Use the
+ cmake_policy command to set the policy and suppress this warning.
+
+ Target "bar" has an INTERFACE_LINK_LIBRARIES property which differs from
+ its LINK_INTERFACE_LIBRARIES(_DEBUG)? properties.
+
+ INTERFACE_LINK_LIBRARIES:
+
+ foo
+
+ LINK_INTERFACE_LIBRARIES(_DEBUG)?:
+
+ bat
+
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0022/CMP0022-WARN-tll.cmake b/Tests/RunCMake/CMP0022/CMP0022-WARN-tll.cmake
new file mode 100644
index 0000000..03223e8
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-WARN-tll.cmake
@@ -0,0 +1,13 @@
+
+project(CMP0022-WARN-tll)
+
+add_library(foo SHARED empty_vs6_1.cpp)
+add_library(bar SHARED empty_vs6_2.cpp)
+add_library(bat SHARED empty_vs6_3.cpp)
+target_link_libraries(bar LINK_PUBLIC foo)
+# Replace the compatibility values set by target_link_libraries
+set_property(TARGET bar PROPERTY LINK_INTERFACE_LIBRARIES bat)
+set_property(TARGET bar PROPERTY LINK_INTERFACE_LIBRARIES_DEBUG bat)
+
+add_library(user SHARED empty.cpp)
+target_link_libraries(user bar)
diff --git a/Tests/RunCMake/CMP0022/CMP0022-WARN.cmake b/Tests/RunCMake/CMP0022/CMP0022-WARN.cmake
new file mode 100644
index 0000000..e3552b2
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-WARN.cmake
@@ -0,0 +1,18 @@
+
+project(CMP0022-WARN)
+
+cmake_policy(SET CMP0042 NEW)
+
+add_library(foo SHARED empty_vs6_1.cpp)
+add_library(bar SHARED empty_vs6_2.cpp)
+add_library(bat SHARED empty_vs6_3.cpp)
+set_property(TARGET bar PROPERTY INTERFACE_LINK_LIBRARIES foo)
+set_property(TARGET bar PROPERTY LINK_INTERFACE_LIBRARIES bat)
+
+add_library(user empty.cpp)
+target_link_libraries(user bar)
+
+# Use "bar" again with a different "head" target to check
+# that the warning does not appear again.
+add_library(user2 empty_vs6_3.cpp)
+target_link_libraries(user2 bar)
diff --git a/Tests/RunCMake/CMP0022/CMP0022-export-exe-stderr.txt b/Tests/RunCMake/CMP0022/CMP0022-export-exe-stderr.txt
new file mode 100644
index 0000000..66a58fb
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-export-exe-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Deprecation Warning at CMakeLists.txt:1 \(cmake_minimum_required\):
+ Compatibility with CMake < 2.8.12 will be removed from a future version of
+ CMake.
+
+ Update the VERSION argument <min> value or use a ...<max> suffix to tell
+ CMake that the project does not need compatibility with older versions.$
diff --git a/Tests/RunCMake/CMP0022/CMP0022-export-exe.cmake b/Tests/RunCMake/CMP0022/CMP0022-export-exe.cmake
new file mode 100644
index 0000000..d832fac
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-export-exe.cmake
@@ -0,0 +1,9 @@
+enable_language(CXX)
+
+cmake_policy(SET CMP0022 NEW)
+
+add_library(testLib empty_vs6_1.cpp)
+add_executable(testExe empty_vs6_2.cpp)
+target_link_libraries(testExe testLib)
+
+export(TARGETS testExe FILE "${CMAKE_CURRENT_BINARY_DIR}/cmp0022NEW-exe.cmake")
diff --git a/Tests/RunCMake/CMP0022/CMP0022-export-result.txt b/Tests/RunCMake/CMP0022/CMP0022-export-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-export-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0022/CMP0022-export-stderr.txt b/Tests/RunCMake/CMP0022/CMP0022-export-stderr.txt
new file mode 100644
index 0000000..405dd8d
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-export-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error in CMakeLists.txt:
+ Target "cmp0022NEW" has policy CMP0022 enabled, but also has old-style
+ LINK_INTERFACE_LIBRARIES properties populated, but it was exported without
+ the EXPORT_LINK_INTERFACE_LIBRARIES to export the old-style properties
diff --git a/Tests/RunCMake/CMP0022/CMP0022-export.cmake b/Tests/RunCMake/CMP0022/CMP0022-export.cmake
new file mode 100644
index 0000000..06147f3
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-export.cmake
@@ -0,0 +1,11 @@
+
+project(cmp0022NEW)
+
+cmake_policy(SET CMP0022 NEW)
+
+add_library(cmp0022NEW SHARED empty_vs6_1.cpp)
+add_library(testLib SHARED empty_vs6_2.cpp)
+
+set_property(TARGET cmp0022NEW APPEND PROPERTY LINK_INTERFACE_LIBRARIES testLib)
+
+export(TARGETS cmp0022NEW testLib FILE "${CMAKE_CURRENT_BINARY_DIR}/cmp0022NEW.cmake")
diff --git a/Tests/RunCMake/CMP0022/CMP0022-install-export-result.txt b/Tests/RunCMake/CMP0022/CMP0022-install-export-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-install-export-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0022/CMP0022-install-export-stderr.txt b/Tests/RunCMake/CMP0022/CMP0022-install-export-stderr.txt
new file mode 100644
index 0000000..405dd8d
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-install-export-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error in CMakeLists.txt:
+ Target "cmp0022NEW" has policy CMP0022 enabled, but also has old-style
+ LINK_INTERFACE_LIBRARIES properties populated, but it was exported without
+ the EXPORT_LINK_INTERFACE_LIBRARIES to export the old-style properties
diff --git a/Tests/RunCMake/CMP0022/CMP0022-install-export.cmake b/Tests/RunCMake/CMP0022/CMP0022-install-export.cmake
new file mode 100644
index 0000000..171febe
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMP0022-install-export.cmake
@@ -0,0 +1,12 @@
+
+project(cmp0022NEW)
+
+cmake_policy(SET CMP0022 NEW)
+
+add_library(cmp0022NEW SHARED empty_vs6_1.cpp)
+add_library(testLib SHARED empty_vs6_2.cpp)
+
+set_property(TARGET cmp0022NEW APPEND PROPERTY LINK_INTERFACE_LIBRARIES testLib)
+
+install(TARGETS cmp0022NEW testLib EXPORT exp DESTINATION lib)
+install(EXPORT exp FILE expTargets.cmake DESTINATION lib/cmake/exp)
diff --git a/Tests/RunCMake/CMP0022/CMakeLists.txt b/Tests/RunCMake/CMP0022/CMakeLists.txt
new file mode 100644
index 0000000..72abfc8
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.11)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0022/RunCMakeTest.cmake b/Tests/RunCMake/CMP0022/RunCMakeTest.cmake
new file mode 100644
index 0000000..4c10996
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/RunCMakeTest.cmake
@@ -0,0 +1,14 @@
+include(RunCMake)
+
+run_cmake(CMP0022-WARN)
+run_cmake(CMP0022-WARN-tll)
+run_cmake(CMP0022-WARN-static)
+run_cmake(CMP0022-WARN-empty-old)
+run_cmake(CMP0022-NOWARN-exe)
+run_cmake(CMP0022-NOWARN-shared)
+run_cmake(CMP0022-NOWARN-static)
+run_cmake(CMP0022-NOWARN-static-NEW)
+run_cmake(CMP0022-NOWARN-static-link_libraries)
+run_cmake(CMP0022-export)
+run_cmake(CMP0022-export-exe)
+run_cmake(CMP0022-install-export)
diff --git a/Tests/RunCMake/CMP0022/dep1/CMakeLists.txt b/Tests/RunCMake/CMP0022/dep1/CMakeLists.txt
new file mode 100644
index 0000000..f0a8179
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/dep1/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+add_library(dep1 ../empty_vs6_1.cpp)
diff --git a/Tests/RunCMake/CMP0022/dep2/CMakeLists.txt b/Tests/RunCMake/CMP0022/dep2/CMakeLists.txt
new file mode 100644
index 0000000..4f90162
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/dep2/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+add_library(dep2 ../empty_vs6_2.cpp)
diff --git a/Tests/RunCMake/CMP0022/dep3/CMakeLists.txt b/Tests/RunCMake/CMP0022/dep3/CMakeLists.txt
new file mode 100644
index 0000000..e85cb54
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/dep3/CMakeLists.txt
@@ -0,0 +1,5 @@
+
+link_libraries(dep1)
+
+add_library(dep3 ../empty_vs6_3.cpp)
+target_link_libraries(dep3 dep2)
diff --git a/Tests/RunCMake/CMP0022/empty.cpp b/Tests/RunCMake/CMP0022/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0022/empty_vs6_1.cpp b/Tests/RunCMake/CMP0022/empty_vs6_1.cpp
new file mode 100644
index 0000000..7efedab
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/empty_vs6_1.cpp
@@ -0,0 +1 @@
+#include "empty.cpp"
diff --git a/Tests/RunCMake/CMP0022/empty_vs6_2.cpp b/Tests/RunCMake/CMP0022/empty_vs6_2.cpp
new file mode 100644
index 0000000..7efedab
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/empty_vs6_2.cpp
@@ -0,0 +1 @@
+#include "empty.cpp"
diff --git a/Tests/RunCMake/CMP0022/empty_vs6_3.cpp b/Tests/RunCMake/CMP0022/empty_vs6_3.cpp
new file mode 100644
index 0000000..7efedab
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/empty_vs6_3.cpp
@@ -0,0 +1 @@
+#include "empty.cpp"
diff --git a/Tests/RunCMake/CMP0022/empty_vs6_4.cpp b/Tests/RunCMake/CMP0022/empty_vs6_4.cpp
new file mode 100644
index 0000000..7efedab
--- /dev/null
+++ b/Tests/RunCMake/CMP0022/empty_vs6_4.cpp
@@ -0,0 +1 @@
+#include "empty.cpp"
diff --git a/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-NEW-result.txt b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-NEW-stderr.txt b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-NEW-stderr.txt
new file mode 100644
index 0000000..6a1f1bd
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-NEW-stderr.txt
@@ -0,0 +1,7 @@
+CMake Error at CMP0026-CONFIG-LOCATION-NEW.cmake:7 \(get_target_property\):
+ The LOCATION property may not be read from target "somelib". Use the
+ target name directly with add_custom_command, or use the generator
+ expression \$<TARGET_FILE>, as appropriate.
+
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-NEW.cmake b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-NEW.cmake
new file mode 100644
index 0000000..1b373e7
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-NEW.cmake
@@ -0,0 +1,7 @@
+
+enable_language(CXX)
+
+cmake_policy(SET CMP0026 NEW)
+
+add_library(somelib empty.cpp)
+get_target_property(_loc somelib Debug_LOCATION)
diff --git a/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-OLD-result.txt b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-OLD-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-OLD-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-OLD-stderr.txt b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-OLD-stderr.txt
new file mode 100644
index 0000000..84dec32
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0026-CONFIG-LOCATION-OLD.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0026 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-OLD.cmake b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-OLD.cmake
new file mode 100644
index 0000000..4166828
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-OLD.cmake
@@ -0,0 +1,7 @@
+
+enable_language(CXX)
+
+cmake_policy(SET CMP0026 OLD)
+
+add_library(somelib empty.cpp)
+get_target_property(_loc somelib Debug_LOCATION)
diff --git a/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-WARN-result.txt b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-WARN-stderr.txt b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-WARN-stderr.txt
new file mode 100644
index 0000000..d2209fd
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-WARN-stderr.txt
@@ -0,0 +1,12 @@
+CMake Warning \(dev\) at CMP0026-CONFIG-LOCATION-WARN.cmake:5 \(get_target_property\):
+ Policy CMP0026 is not set: Disallow use of the LOCATION target property.
+ Run "cmake --help-policy CMP0026" for policy details. Use the cmake_policy
+ command to set the policy and suppress this warning.
+
+ The LOCATION property should not be read from target "somelib". Use the
+ target name directly with add_custom_command, or use the generator
+ expression \$<TARGET_FILE>, as appropriate.
+
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-WARN.cmake b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-WARN.cmake
new file mode 100644
index 0000000..511056f
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-CONFIG-LOCATION-WARN.cmake
@@ -0,0 +1,5 @@
+
+enable_language(CXX)
+
+add_library(somelib empty.cpp)
+get_target_property(_loc somelib Debug_LOCATION)
diff --git a/Tests/RunCMake/CMP0026/CMP0026-IMPORTED-result.txt b/Tests/RunCMake/CMP0026/CMP0026-IMPORTED-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-IMPORTED-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0026/CMP0026-IMPORTED.cmake b/Tests/RunCMake/CMP0026/CMP0026-IMPORTED.cmake
new file mode 100644
index 0000000..ae62e79
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-IMPORTED.cmake
@@ -0,0 +1,7 @@
+
+enable_language(CXX)
+
+cmake_policy(SET CMP0111 OLD)
+add_library(someimportedlib SHARED IMPORTED)
+
+get_target_property(_loc someimportedlib LOCATION)
diff --git a/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-NEW-result.txt b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-NEW-stderr.txt b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-NEW-stderr.txt
new file mode 100644
index 0000000..1490103
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-NEW-stderr.txt
@@ -0,0 +1,7 @@
+CMake Error at CMP0026-LOCATION-CONFIG-NEW.cmake:7 \(get_target_property\):
+ The LOCATION property may not be read from target "somelib". Use the
+ target name directly with add_custom_command, or use the generator
+ expression \$<TARGET_FILE>, as appropriate.
+
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-NEW.cmake b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-NEW.cmake
new file mode 100644
index 0000000..e6aa509
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-NEW.cmake
@@ -0,0 +1,7 @@
+
+enable_language(CXX)
+
+cmake_policy(SET CMP0026 NEW)
+
+add_library(somelib empty.cpp)
+get_target_property(_loc somelib LOCATION_Debug)
diff --git a/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-OLD-result.txt b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-OLD-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-OLD-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-OLD-stderr.txt b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-OLD-stderr.txt
new file mode 100644
index 0000000..1fb4ef6
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0026-LOCATION-CONFIG-OLD.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0026 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-OLD.cmake b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-OLD.cmake
new file mode 100644
index 0000000..482373d
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-OLD.cmake
@@ -0,0 +1,7 @@
+
+enable_language(CXX)
+
+cmake_policy(SET CMP0026 OLD)
+
+add_library(somelib empty.cpp)
+get_target_property(_loc somelib LOCATION_Debug)
diff --git a/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-WARN-result.txt b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-WARN-stderr.txt b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-WARN-stderr.txt
new file mode 100644
index 0000000..8b4faf0
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-WARN-stderr.txt
@@ -0,0 +1,12 @@
+CMake Warning \(dev\) at CMP0026-LOCATION-CONFIG-WARN.cmake:5 \(get_target_property\):
+ Policy CMP0026 is not set: Disallow use of the LOCATION target property.
+ Run "cmake --help-policy CMP0026" for policy details. Use the cmake_policy
+ command to set the policy and suppress this warning.
+
+ The LOCATION property should not be read from target "somelib". Use the
+ target name directly with add_custom_command, or use the generator
+ expression \$<TARGET_FILE>, as appropriate.
+
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-WARN.cmake b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-WARN.cmake
new file mode 100644
index 0000000..85711c3
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-LOCATION-CONFIG-WARN.cmake
@@ -0,0 +1,5 @@
+
+enable_language(CXX)
+
+add_library(somelib empty.cpp)
+get_target_property(_loc somelib LOCATION_Debug)
diff --git a/Tests/RunCMake/CMP0026/CMP0026-NEW-result.txt b/Tests/RunCMake/CMP0026/CMP0026-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0026/CMP0026-NEW-stderr.txt b/Tests/RunCMake/CMP0026/CMP0026-NEW-stderr.txt
new file mode 100644
index 0000000..8c47c2a
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-NEW-stderr.txt
@@ -0,0 +1,7 @@
+CMake Error at CMP0026-NEW.cmake:7 \(get_target_property\):
+ The LOCATION property may not be read from target "somelib". Use the
+ target name directly with add_custom_command, or use the generator
+ expression \$<TARGET_FILE>, as appropriate.
+
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/CMP0026/CMP0026-NEW.cmake b/Tests/RunCMake/CMP0026/CMP0026-NEW.cmake
new file mode 100644
index 0000000..1659ffc
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-NEW.cmake
@@ -0,0 +1,7 @@
+
+enable_language(CXX)
+
+cmake_policy(SET CMP0026 NEW)
+
+add_library(somelib empty.cpp)
+get_target_property(_loc somelib LOCATION)
diff --git a/Tests/RunCMake/CMP0026/CMP0026-OLD-stderr.txt b/Tests/RunCMake/CMP0026/CMP0026-OLD-stderr.txt
new file mode 100644
index 0000000..b4282f5
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0026-OLD.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0026 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0026/CMP0026-OLD.cmake b/Tests/RunCMake/CMP0026/CMP0026-OLD.cmake
new file mode 100644
index 0000000..80497a3
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-OLD.cmake
@@ -0,0 +1,12 @@
+enable_language(CXX)
+
+cmake_policy(SET CMP0026 OLD)
+
+set(out ${CMAKE_CURRENT_BINARY_DIR}/out.txt)
+
+add_library(somelib empty.cpp ${out})
+get_target_property(_loc somelib LOCATION)
+
+file(WRITE "${out}"
+ "source file written by project code after getting target LOCATION\n"
+ )
diff --git a/Tests/RunCMake/CMP0026/CMP0026-WARN-Dir/CMakeLists.txt b/Tests/RunCMake/CMP0026/CMP0026-WARN-Dir/CMakeLists.txt
new file mode 100644
index 0000000..17a7db0
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-WARN-Dir/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(otherlib ../empty.cpp)
diff --git a/Tests/RunCMake/CMP0026/CMP0026-WARN-result.txt b/Tests/RunCMake/CMP0026/CMP0026-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0026/CMP0026-WARN-stderr.txt b/Tests/RunCMake/CMP0026/CMP0026-WARN-stderr.txt
new file mode 100644
index 0000000..0d39596
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-WARN-stderr.txt
@@ -0,0 +1,25 @@
+CMake Warning \(dev\) at CMP0026-WARN.cmake:5 \(get_target_property\):
+ Policy CMP0026 is not set: Disallow use of the LOCATION target property.
+ Run "cmake --help-policy CMP0026" for policy details. Use the cmake_policy
+ command to set the policy and suppress this warning.
+
+ The LOCATION property should not be read from target "somelib". Use the
+ target name directly with add_custom_command, or use the generator
+ expression \$<TARGET_FILE>, as appropriate.
+
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
++
+CMake Warning \(dev\) at CMP0026-WARN.cmake:8 \(get_target_property\):
+ Policy CMP0026 is not set: Disallow use of the LOCATION target property.
+ Run "cmake --help-policy CMP0026" for policy details. Use the cmake_policy
+ command to set the policy and suppress this warning.
+
+ The LOCATION property should not be read from target "otherlib". Use the
+ target name directly with add_custom_command, or use the generator
+ expression \$<TARGET_FILE>, as appropriate.
+
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0026/CMP0026-WARN.cmake b/Tests/RunCMake/CMP0026/CMP0026-WARN.cmake
new file mode 100644
index 0000000..bfc9203
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-WARN.cmake
@@ -0,0 +1,8 @@
+
+enable_language(CXX)
+
+add_library(somelib empty.cpp)
+get_target_property(_loc somelib LOCATION)
+
+add_subdirectory(CMP0026-WARN-Dir)
+get_target_property(_loc otherlib LOCATION)
diff --git a/Tests/RunCMake/CMP0026/CMakeLists.txt b/Tests/RunCMake/CMP0026/CMakeLists.txt
new file mode 100644
index 0000000..4b3de84
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0026/LOCATION-and-TARGET_OBJECTS-result.txt b/Tests/RunCMake/CMP0026/LOCATION-and-TARGET_OBJECTS-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/LOCATION-and-TARGET_OBJECTS-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0026/LOCATION-and-TARGET_OBJECTS-stderr.txt b/Tests/RunCMake/CMP0026/LOCATION-and-TARGET_OBJECTS-stderr.txt
new file mode 100644
index 0000000..6377921
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/LOCATION-and-TARGET_OBJECTS-stderr.txt
@@ -0,0 +1,12 @@
+CMake Warning \(dev\) at LOCATION-and-TARGET_OBJECTS.cmake:[0-9]+ \(get_target_property\):
+ Policy CMP0026 is not set: Disallow use of the LOCATION target property.
+ Run "cmake --help-policy CMP0026" for policy details. Use the cmake_policy
+ command to set the policy and suppress this warning.
+
+ The LOCATION property should not be read from target "bar". Use the target
+ name directly with add_custom_command, or use the generator expression
+ \$<TARGET_FILE>, as appropriate.
+
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0026/LOCATION-and-TARGET_OBJECTS.cmake b/Tests/RunCMake/CMP0026/LOCATION-and-TARGET_OBJECTS.cmake
new file mode 100644
index 0000000..ee5ed5b
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/LOCATION-and-TARGET_OBJECTS.cmake
@@ -0,0 +1,6 @@
+cmake_policy(SET CMP0118 NEW)
+enable_language(CXX)
+
+add_library(foo OBJECT empty.cpp)
+add_executable(bar $<TARGET_OBJECTS:foo>)
+get_target_property(location bar LOCATION)
diff --git a/Tests/RunCMake/CMP0026/ObjlibNotDefined-result.txt b/Tests/RunCMake/CMP0026/ObjlibNotDefined-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/ObjlibNotDefined-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0026/ObjlibNotDefined-stderr.txt b/Tests/RunCMake/CMP0026/ObjlibNotDefined-stderr.txt
new file mode 100644
index 0000000..360d987
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/ObjlibNotDefined-stderr.txt
@@ -0,0 +1,12 @@
+CMake Warning \(dev\) at ObjlibNotDefined.cmake:[0-9]+ \(get_target_property\):
+ Policy CMP0026 is not set: Disallow use of the LOCATION target property.
+ Run "cmake --help-policy CMP0026" for policy details. Use the cmake_policy
+ command to set the policy and suppress this warning.
+
+ The LOCATION property should not be read from target "objlibuser". Use the
+ target name directly with add_custom_command, or use the generator
+ expression \$<TARGET_FILE>, as appropriate.
+
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0026/ObjlibNotDefined.cmake b/Tests/RunCMake/CMP0026/ObjlibNotDefined.cmake
new file mode 100644
index 0000000..194760c
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/ObjlibNotDefined.cmake
@@ -0,0 +1,13 @@
+
+enable_language(CXX)
+
+add_executable(objlibuser
+ empty.cpp
+ $<TARGET_OBJECTS:bar>
+)
+
+get_target_property(_location objlibuser LOCATION)
+
+add_library(bar OBJECT
+ empty.cpp
+)
diff --git a/Tests/RunCMake/CMP0026/RunCMakeTest.cmake b/Tests/RunCMake/CMP0026/RunCMakeTest.cmake
new file mode 100644
index 0000000..047da28
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/RunCMakeTest.cmake
@@ -0,0 +1,15 @@
+include(RunCMake)
+
+run_cmake(CMP0026-WARN)
+run_cmake(CMP0026-OLD)
+run_cmake(CMP0026-NEW)
+run_cmake(CMP0026-IMPORTED)
+run_cmake(CMP0026-CONFIG-LOCATION-NEW)
+run_cmake(CMP0026-CONFIG-LOCATION-OLD)
+run_cmake(CMP0026-CONFIG-LOCATION-WARN)
+run_cmake(CMP0026-LOCATION-CONFIG-NEW)
+run_cmake(CMP0026-LOCATION-CONFIG-OLD)
+run_cmake(CMP0026-LOCATION-CONFIG-WARN)
+run_cmake(ObjlibNotDefined)
+run_cmake(LOCATION-and-TARGET_OBJECTS)
+run_cmake(clear-cached-information)
diff --git a/Tests/RunCMake/CMP0026/clear-cached-information-dir/CMakeLists.txt b/Tests/RunCMake/CMP0026/clear-cached-information-dir/CMakeLists.txt
new file mode 100644
index 0000000..c51e883
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/clear-cached-information-dir/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+add_executable(Hello ${CMAKE_CURRENT_BINARY_DIR}/main.c)
diff --git a/Tests/RunCMake/CMP0026/clear-cached-information-stderr.txt b/Tests/RunCMake/CMP0026/clear-cached-information-stderr.txt
new file mode 100644
index 0000000..3525704
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/clear-cached-information-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at clear-cached-information.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0026 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0026/clear-cached-information.cmake b/Tests/RunCMake/CMP0026/clear-cached-information.cmake
new file mode 100644
index 0000000..9916948
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/clear-cached-information.cmake
@@ -0,0 +1,14 @@
+cmake_policy(SET CMP0118 NEW)
+enable_language(C)
+
+cmake_policy(SET CMP0026 OLD)
+
+add_subdirectory(clear-cached-information-dir)
+
+# Critical: this needs to happen in root CMakeLists.txt and not inside
+# the subdir.
+get_target_property(mypath Hello LOCATION)
+# Now we create the file later, so you can see, ultimately no error should
+# happen e.g. during generate phase:
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/clear-cached-information-dir/main.c)
+set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/clear-cached-information-dir/main.c PROPERTIES GENERATED TRUE)
diff --git a/Tests/RunCMake/CMP0026/empty.cpp b/Tests/RunCMake/CMP0026/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0027/CMP0027-NEW-result.txt b/Tests/RunCMake/CMP0027/CMP0027-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0027/CMP0027-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0027/CMP0027-NEW-stderr.txt b/Tests/RunCMake/CMP0027/CMP0027-NEW-stderr.txt
new file mode 100644
index 0000000..5948ec8
--- /dev/null
+++ b/Tests/RunCMake/CMP0027/CMP0027-NEW-stderr.txt
@@ -0,0 +1,13 @@
+CMake Error in CMakeLists.txt:
+ Imported target "testTarget" includes non-existent path
+
+ "/does/not/exist"
+
+ in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:
+
+ \* The path was deleted, renamed, or moved to another location.
+
+ \* An install or uninstall procedure did not complete successfully.
+
+ \* The installation package was faulty and references files it does not
+ provide.
diff --git a/Tests/RunCMake/CMP0027/CMP0027-NEW.cmake b/Tests/RunCMake/CMP0027/CMP0027-NEW.cmake
new file mode 100644
index 0000000..8245085
--- /dev/null
+++ b/Tests/RunCMake/CMP0027/CMP0027-NEW.cmake
@@ -0,0 +1,10 @@
+
+enable_language(CXX)
+
+cmake_policy(SET CMP0027 NEW)
+
+add_library(testTarget UNKNOWN IMPORTED)
+set_property(TARGET testTarget PROPERTY INTERFACE_INCLUDE_DIRECTORIES "/does/not/exist")
+
+add_library(userTarget "${CMAKE_CURRENT_SOURCE_DIR}/empty.cpp")
+target_link_libraries(userTarget PRIVATE $<1:testTarget>)
diff --git a/Tests/RunCMake/CMP0027/CMP0027-OLD-result.txt b/Tests/RunCMake/CMP0027/CMP0027-OLD-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0027/CMP0027-OLD-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0027/CMP0027-OLD-stderr.txt b/Tests/RunCMake/CMP0027/CMP0027-OLD-stderr.txt
new file mode 100644
index 0000000..4c2b300
--- /dev/null
+++ b/Tests/RunCMake/CMP0027/CMP0027-OLD-stderr.txt
@@ -0,0 +1,13 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+ Imported target "testTarget" includes non-existent path
+
+ "/does/not/exist"
+
+ in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:
+
+ \* The path was deleted, renamed, or moved to another location.
+
+ \* An install or uninstall procedure did not complete successfully.
+
+ \* The installation package was faulty and references files it does not
+ provide.
diff --git a/Tests/RunCMake/CMP0027/CMP0027-OLD.cmake b/Tests/RunCMake/CMP0027/CMP0027-OLD.cmake
new file mode 100644
index 0000000..404217d
--- /dev/null
+++ b/Tests/RunCMake/CMP0027/CMP0027-OLD.cmake
@@ -0,0 +1,10 @@
+
+enable_language(CXX)
+
+cmake_policy(SET CMP0027 OLD)
+
+add_library(testTarget UNKNOWN IMPORTED)
+set_property(TARGET testTarget PROPERTY INTERFACE_INCLUDE_DIRECTORIES "/does/not/exist")
+
+add_library(userTarget "${CMAKE_CURRENT_SOURCE_DIR}/empty.cpp")
+target_link_libraries(userTarget PRIVATE $<1:testTarget>)
diff --git a/Tests/RunCMake/CMP0027/CMP0027-WARN-result.txt b/Tests/RunCMake/CMP0027/CMP0027-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0027/CMP0027-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0027/CMP0027-WARN-stderr.txt b/Tests/RunCMake/CMP0027/CMP0027-WARN-stderr.txt
new file mode 100644
index 0000000..9bcec3c
--- /dev/null
+++ b/Tests/RunCMake/CMP0027/CMP0027-WARN-stderr.txt
@@ -0,0 +1,18 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0027 is not set: Conditionally linked imported targets with
+ missing include directories. Run "cmake --help-policy CMP0027" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ Imported target "testTarget" includes non-existent path
+
+ "/does/not/exist"
+
+ in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:
+
+ \* The path was deleted, renamed, or moved to another location.
+
+ \* An install or uninstall procedure did not complete successfully.
+
+ \* The installation package was faulty and references files it does not
+ provide.
diff --git a/Tests/RunCMake/CMP0027/CMP0027-WARN.cmake b/Tests/RunCMake/CMP0027/CMP0027-WARN.cmake
new file mode 100644
index 0000000..8e5f9b5
--- /dev/null
+++ b/Tests/RunCMake/CMP0027/CMP0027-WARN.cmake
@@ -0,0 +1,8 @@
+
+enable_language(CXX)
+
+add_library(testTarget UNKNOWN IMPORTED)
+set_property(TARGET testTarget PROPERTY INTERFACE_INCLUDE_DIRECTORIES "/does/not/exist")
+
+add_library(userTarget "${CMAKE_CURRENT_SOURCE_DIR}/empty.cpp")
+target_link_libraries(userTarget PRIVATE $<1:testTarget>)
diff --git a/Tests/RunCMake/CMP0027/CMakeLists.txt b/Tests/RunCMake/CMP0027/CMakeLists.txt
new file mode 100644
index 0000000..4b3de84
--- /dev/null
+++ b/Tests/RunCMake/CMP0027/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0027/RunCMakeTest.cmake b/Tests/RunCMake/CMP0027/RunCMakeTest.cmake
new file mode 100644
index 0000000..1017f01
--- /dev/null
+++ b/Tests/RunCMake/CMP0027/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0027-NEW)
+run_cmake(CMP0027-OLD)
+run_cmake(CMP0027-WARN)
diff --git a/Tests/RunCMake/CMP0027/empty.cpp b/Tests/RunCMake/CMP0027/empty.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMP0027/empty.cpp
diff --git a/Tests/RunCMake/CMP0028/CMP0028-NEW-iface-result.txt b/Tests/RunCMake/CMP0028/CMP0028-NEW-iface-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-NEW-iface-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0028/CMP0028-NEW-iface-stderr.txt b/Tests/RunCMake/CMP0028/CMP0028-NEW-iface-stderr.txt
new file mode 100644
index 0000000..e2108f4
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-NEW-iface-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at CMP0028-NEW-iface.cmake:6 \(add_library\):
+ Target "foo" links to target "External::Library" but the target was not
+ found. Perhaps a find_package\(\) call is missing for an IMPORTED target, or
+ an ALIAS target is missing\?
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0028/CMP0028-NEW-iface.cmake b/Tests/RunCMake/CMP0028/CMP0028-NEW-iface.cmake
new file mode 100644
index 0000000..1a71433
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-NEW-iface.cmake
@@ -0,0 +1,7 @@
+
+cmake_policy(SET CMP0028 NEW)
+
+add_library(iface INTERFACE)
+target_link_libraries(iface INTERFACE External::Library)
+add_library(foo empty.cpp)
+target_link_libraries(foo iface)
diff --git a/Tests/RunCMake/CMP0028/CMP0028-NEW-result.txt b/Tests/RunCMake/CMP0028/CMP0028-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0028/CMP0028-NEW-stderr.txt b/Tests/RunCMake/CMP0028/CMP0028-NEW-stderr.txt
new file mode 100644
index 0000000..711ad0e
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-NEW-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at CMP0028-NEW.cmake:4 \(add_library\):
+ Target "foo" links to target "External::Library" but the target was not
+ found. Perhaps a find_package\(\) call is missing for an IMPORTED target, or
+ an ALIAS target is missing\?
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0028/CMP0028-NEW.cmake b/Tests/RunCMake/CMP0028/CMP0028-NEW.cmake
new file mode 100644
index 0000000..a0a6ae8
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-NEW.cmake
@@ -0,0 +1,5 @@
+
+cmake_policy(SET CMP0028 NEW)
+
+add_library(foo empty.cpp)
+target_link_libraries(foo PRIVATE External::Library)
diff --git a/Tests/RunCMake/CMP0028/CMP0028-OLD-iface-result.txt b/Tests/RunCMake/CMP0028/CMP0028-OLD-iface-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-OLD-iface-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0028/CMP0028-OLD-iface-stderr.txt b/Tests/RunCMake/CMP0028/CMP0028-OLD-iface-stderr.txt
new file mode 100644
index 0000000..b7a0755
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-OLD-iface-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0028-OLD-iface.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0028 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0028/CMP0028-OLD-iface.cmake b/Tests/RunCMake/CMP0028/CMP0028-OLD-iface.cmake
new file mode 100644
index 0000000..d7bd60e
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-OLD-iface.cmake
@@ -0,0 +1,7 @@
+
+cmake_policy(SET CMP0028 OLD)
+
+add_library(iface INTERFACE)
+target_link_libraries(iface INTERFACE External::Library)
+add_library(foo empty.cpp)
+target_link_libraries(foo iface)
diff --git a/Tests/RunCMake/CMP0028/CMP0028-OLD-result.txt b/Tests/RunCMake/CMP0028/CMP0028-OLD-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-OLD-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0028/CMP0028-OLD-stderr.txt b/Tests/RunCMake/CMP0028/CMP0028-OLD-stderr.txt
new file mode 100644
index 0000000..586a876
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0028-OLD.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0028 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0028/CMP0028-OLD.cmake b/Tests/RunCMake/CMP0028/CMP0028-OLD.cmake
new file mode 100644
index 0000000..d4a870b
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-OLD.cmake
@@ -0,0 +1,5 @@
+
+cmake_policy(SET CMP0028 OLD)
+
+add_library(foo empty.cpp)
+target_link_libraries(foo PRIVATE External::Library)
diff --git a/Tests/RunCMake/CMP0028/CMP0028-WARN-iface-result.txt b/Tests/RunCMake/CMP0028/CMP0028-WARN-iface-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-WARN-iface-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0028/CMP0028-WARN-iface-stderr.txt b/Tests/RunCMake/CMP0028/CMP0028-WARN-iface-stderr.txt
new file mode 100644
index 0000000..0c5c653
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-WARN-iface-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at CMP0028-WARN-iface.cmake:4 \(add_library\):
+ Policy CMP0028 is not set: Double colon in target name means ALIAS or
+ IMPORTED target. Run "cmake --help-policy CMP0028" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
+
+ Target "foo" links to target "External::Library" but the target was not
+ found. Perhaps a find_package\(\) call is missing for an IMPORTED target, or
+ an ALIAS target is missing\?
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0028/CMP0028-WARN-iface.cmake b/Tests/RunCMake/CMP0028/CMP0028-WARN-iface.cmake
new file mode 100644
index 0000000..9270023
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-WARN-iface.cmake
@@ -0,0 +1,5 @@
+
+add_library(iface INTERFACE)
+target_link_libraries(iface INTERFACE External::Library)
+add_library(foo empty.cpp)
+target_link_libraries(foo iface)
diff --git a/Tests/RunCMake/CMP0028/CMP0028-WARN-result.txt b/Tests/RunCMake/CMP0028/CMP0028-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0028/CMP0028-WARN-stderr.txt b/Tests/RunCMake/CMP0028/CMP0028-WARN-stderr.txt
new file mode 100644
index 0000000..41d7560
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-WARN-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at CMP0028-WARN.cmake:2 \(add_library\):
+ Policy CMP0028 is not set: Double colon in target name means ALIAS or
+ IMPORTED target. Run "cmake --help-policy CMP0028" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
+
+ Target "foo" links to target "External::Library" but the target was not
+ found. Perhaps a find_package\(\) call is missing for an IMPORTED target, or
+ an ALIAS target is missing\?
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0028/CMP0028-WARN.cmake b/Tests/RunCMake/CMP0028/CMP0028-WARN.cmake
new file mode 100644
index 0000000..70a6cc6
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMP0028-WARN.cmake
@@ -0,0 +1,3 @@
+
+add_library(foo empty.cpp)
+target_link_libraries(foo PRIVATE External::Library)
diff --git a/Tests/RunCMake/CMP0028/CMakeLists.txt b/Tests/RunCMake/CMP0028/CMakeLists.txt
new file mode 100644
index 0000000..4f867df
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE) # policy used at end of dir
diff --git a/Tests/RunCMake/CMP0028/RunCMakeTest.cmake b/Tests/RunCMake/CMP0028/RunCMakeTest.cmake
new file mode 100644
index 0000000..0c72ca2
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/RunCMakeTest.cmake
@@ -0,0 +1,8 @@
+include(RunCMake)
+
+run_cmake(CMP0028-NEW)
+run_cmake(CMP0028-OLD)
+run_cmake(CMP0028-WARN)
+run_cmake(CMP0028-NEW-iface)
+run_cmake(CMP0028-OLD-iface)
+run_cmake(CMP0028-WARN-iface)
diff --git a/Tests/RunCMake/CMP0028/empty.cpp b/Tests/RunCMake/CMP0028/empty.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMP0028/empty.cpp
diff --git a/Tests/RunCMake/CMP0037/CMP0037-NEW-colon-result.txt b/Tests/RunCMake/CMP0037/CMP0037-NEW-colon-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-NEW-colon-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0037/CMP0037-NEW-colon-stderr.txt b/Tests/RunCMake/CMP0037/CMP0037-NEW-colon-stderr.txt
new file mode 100644
index 0000000..ec2315f
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-NEW-colon-stderr.txt
@@ -0,0 +1,20 @@
+CMake Error at CMP0037-NEW-colon.cmake:4 \(add_library\):
+ The target name "lib:colon" is reserved or not valid for certain CMake
+ features, such as generator expressions, and may result in undefined
+ behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Error at CMP0037-NEW-colon.cmake:5 \(add_executable\):
+ The target name "exe:colon" is reserved or not valid for certain CMake
+ features, such as generator expressions, and may result in undefined
+ behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Error at CMP0037-NEW-colon.cmake:6 \(add_custom_target\):
+ The target name "custom:colon" is reserved or not valid for certain CMake
+ features, such as generator expressions, and may result in undefined
+ behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0037/CMP0037-NEW-colon.cmake b/Tests/RunCMake/CMP0037/CMP0037-NEW-colon.cmake
new file mode 100644
index 0000000..fd56e75
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-NEW-colon.cmake
@@ -0,0 +1,6 @@
+enable_language(CXX)
+cmake_policy(SET CMP0037 NEW)
+
+add_library("lib:colon" empty.cpp)
+add_executable("exe:colon" empty.cpp)
+add_custom_target("custom:colon")
diff --git a/Tests/RunCMake/CMP0037/CMP0037-NEW-reserved-result.txt b/Tests/RunCMake/CMP0037/CMP0037-NEW-reserved-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-NEW-reserved-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0037/CMP0037-NEW-reserved-stderr.txt b/Tests/RunCMake/CMP0037/CMP0037-NEW-reserved-stderr.txt
new file mode 100644
index 0000000..5789e38
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-NEW-reserved-stderr.txt
@@ -0,0 +1,18 @@
+CMake Error at CMP0037-NEW-reserved.cmake:4 \(add_library\):
+ The target name "all" is reserved or not valid for certain CMake features,
+ such as generator expressions, and may result in undefined behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Error at CMP0037-NEW-reserved.cmake:5 \(add_executable\):
+ The target name "clean" is reserved or not valid for certain CMake
+ features, such as generator expressions, and may result in undefined
+ behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Error at CMP0037-NEW-reserved.cmake:6 \(add_custom_target\):
+ The target name "help" is reserved or not valid for certain CMake features,
+ such as generator expressions, and may result in undefined behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0037/CMP0037-NEW-reserved.cmake b/Tests/RunCMake/CMP0037/CMP0037-NEW-reserved.cmake
new file mode 100644
index 0000000..83a7119
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-NEW-reserved.cmake
@@ -0,0 +1,6 @@
+enable_language(CXX)
+cmake_policy(SET CMP0037 NEW)
+
+add_library(all empty.cpp)
+add_executable(clean empty.cpp)
+add_custom_target(help)
diff --git a/Tests/RunCMake/CMP0037/CMP0037-NEW-space-result.txt b/Tests/RunCMake/CMP0037/CMP0037-NEW-space-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-NEW-space-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0037/CMP0037-NEW-space-stderr.txt b/Tests/RunCMake/CMP0037/CMP0037-NEW-space-stderr.txt
new file mode 100644
index 0000000..e14cec0
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-NEW-space-stderr.txt
@@ -0,0 +1,20 @@
+CMake Error at CMP0037-NEW-space.cmake:4 \(add_library\):
+ The target name "lib with spaces" is reserved or not valid for certain
+ CMake features, such as generator expressions, and may result in undefined
+ behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Error at CMP0037-NEW-space.cmake:5 \(add_executable\):
+ The target name "exe with spaces" is reserved or not valid for certain
+ CMake features, such as generator expressions, and may result in undefined
+ behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Error at CMP0037-NEW-space.cmake:6 \(add_custom_target\):
+ The target name "custom with spaces" is reserved or not valid for certain
+ CMake features, such as generator expressions, and may result in undefined
+ behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0037/CMP0037-NEW-space.cmake b/Tests/RunCMake/CMP0037/CMP0037-NEW-space.cmake
new file mode 100644
index 0000000..2a288cc
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-NEW-space.cmake
@@ -0,0 +1,6 @@
+enable_language(CXX)
+cmake_policy(SET CMP0037 NEW)
+
+add_library("lib with spaces" empty.cpp)
+add_executable("exe with spaces" empty.cpp)
+add_custom_target("custom with spaces")
diff --git a/Tests/RunCMake/CMP0037/CMP0037-OLD-reserved-stderr.txt b/Tests/RunCMake/CMP0037/CMP0037-OLD-reserved-stderr.txt
new file mode 100644
index 0000000..de09351
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-OLD-reserved-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0037-OLD-reserved.cmake:2 \(cmake_policy\):
+ The OLD behavior for policy CMP0037 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0037/CMP0037-OLD-reserved.cmake b/Tests/RunCMake/CMP0037/CMP0037-OLD-reserved.cmake
new file mode 100644
index 0000000..f52e4d2
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-OLD-reserved.cmake
@@ -0,0 +1,6 @@
+enable_language(CXX)
+cmake_policy(SET CMP0037 OLD)
+
+add_library(all empty.cpp)
+add_executable(clean empty.cpp)
+add_custom_target(help)
diff --git a/Tests/RunCMake/CMP0037/CMP0037-OLD-space-stderr.txt b/Tests/RunCMake/CMP0037/CMP0037-OLD-space-stderr.txt
new file mode 100644
index 0000000..4d13e59
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-OLD-space-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0037-OLD-space.cmake:2 \(cmake_policy\):
+ The OLD behavior for policy CMP0037 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0037/CMP0037-OLD-space.cmake b/Tests/RunCMake/CMP0037/CMP0037-OLD-space.cmake
new file mode 100644
index 0000000..c9fb6c8
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-OLD-space.cmake
@@ -0,0 +1,6 @@
+enable_language(CXX)
+cmake_policy(SET CMP0037 OLD)
+
+add_library("lib with spaces" empty.cpp)
+add_executable("exe with spaces" empty.cpp)
+add_custom_target("custom with spaces")
diff --git a/Tests/RunCMake/CMP0037/CMP0037-WARN-colon-result.txt b/Tests/RunCMake/CMP0037/CMP0037-WARN-colon-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-WARN-colon-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0037/CMP0037-WARN-colon-stderr.txt b/Tests/RunCMake/CMP0037/CMP0037-WARN-colon-stderr.txt
new file mode 100644
index 0000000..d3b0e17
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-WARN-colon-stderr.txt
@@ -0,0 +1,38 @@
+CMake Warning \(dev\) at CMP0037-WARN-colon.cmake:2 \(add_library\):
+ Policy CMP0037 is not set: Target names should not be reserved and should
+ match a validity pattern. Run "cmake --help-policy CMP0037" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ The target name "lib:colon" is reserved or not valid for certain CMake
+ features, such as generator expressions, and may result in undefined
+ behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
++
+CMake Warning \(dev\) at CMP0037-WARN-colon.cmake:3 \(add_executable\):
+ Policy CMP0037 is not set: Target names should not be reserved and should
+ match a validity pattern. Run "cmake --help-policy CMP0037" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ The target name "exe:colon" is reserved or not valid for certain CMake
+ features, such as generator expressions, and may result in undefined
+ behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
++
+CMake Warning \(dev\) at CMP0037-WARN-colon.cmake:4 \(add_custom_target\):
+ Policy CMP0037 is not set: Target names should not be reserved and should
+ match a validity pattern. Run "cmake --help-policy CMP0037" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ The target name "custom:colon" is reserved or not valid for certain CMake
+ features, such as generator expressions, and may result in undefined
+ behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0037/CMP0037-WARN-colon.cmake b/Tests/RunCMake/CMP0037/CMP0037-WARN-colon.cmake
new file mode 100644
index 0000000..1b1a405
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-WARN-colon.cmake
@@ -0,0 +1,4 @@
+enable_language(CXX)
+add_library("lib:colon" empty.cpp)
+add_executable("exe:colon" empty.cpp)
+add_custom_target("custom:colon")
diff --git a/Tests/RunCMake/CMP0037/CMP0037-WARN-reserved-stderr.txt b/Tests/RunCMake/CMP0037/CMP0037-WARN-reserved-stderr.txt
new file mode 100644
index 0000000..2d556a7
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-WARN-reserved-stderr.txt
@@ -0,0 +1,36 @@
+CMake Warning \(dev\) at CMP0037-WARN-reserved.cmake:2 \(add_library\):
+ Policy CMP0037 is not set: Target names should not be reserved and should
+ match a validity pattern. Run "cmake --help-policy CMP0037" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ The target name "all" is reserved or not valid for certain CMake features,
+ such as generator expressions, and may result in undefined behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
++
+CMake Warning \(dev\) at CMP0037-WARN-reserved.cmake:3 \(add_executable\):
+ Policy CMP0037 is not set: Target names should not be reserved and should
+ match a validity pattern. Run "cmake --help-policy CMP0037" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ The target name "clean" is reserved or not valid for certain CMake
+ features, such as generator expressions, and may result in undefined
+ behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
++
+CMake Warning \(dev\) at CMP0037-WARN-reserved.cmake:4 \(add_custom_target\):
+ Policy CMP0037 is not set: Target names should not be reserved and should
+ match a validity pattern. Run "cmake --help-policy CMP0037" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ The target name "help" is reserved or not valid for certain CMake features,
+ such as generator expressions, and may result in undefined behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0037/CMP0037-WARN-reserved.cmake b/Tests/RunCMake/CMP0037/CMP0037-WARN-reserved.cmake
new file mode 100644
index 0000000..a5e0f10
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-WARN-reserved.cmake
@@ -0,0 +1,4 @@
+enable_language(CXX)
+add_library(all empty.cpp)
+add_executable(clean empty.cpp)
+add_custom_target(help)
diff --git a/Tests/RunCMake/CMP0037/CMP0037-WARN-space-result.txt b/Tests/RunCMake/CMP0037/CMP0037-WARN-space-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-WARN-space-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0037/CMP0037-WARN-space-stderr.txt b/Tests/RunCMake/CMP0037/CMP0037-WARN-space-stderr.txt
new file mode 100644
index 0000000..e39477a
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-WARN-space-stderr.txt
@@ -0,0 +1,37 @@
+CMake Warning \(dev\) at CMP0037-WARN-space.cmake:2 \(add_library\):
+ Policy CMP0037 is not set: Target names should not be reserved and should
+ match a validity pattern. Run "cmake --help-policy CMP0037" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ The target name "lib with spaces" is reserved or not valid for certain
+ CMake features, such as generator expressions, and may result in undefined
+ behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
++
+CMake Warning \(dev\) at CMP0037-WARN-space.cmake:3 \(add_executable\):
+ Policy CMP0037 is not set: Target names should not be reserved and should
+ match a validity pattern. Run "cmake --help-policy CMP0037" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ The target name "exe with spaces" is reserved or not valid for certain
+ CMake features, such as generator expressions, and may result in undefined
+ behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
++
+CMake Warning \(dev\) at CMP0037-WARN-space.cmake:4 \(add_custom_target\):
+ Policy CMP0037 is not set: Target names should not be reserved and should
+ match a validity pattern. Run "cmake --help-policy CMP0037" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ The target name "custom with spaces" is reserved or not valid for certain
+ CMake features, such as generator expressions, and may result in undefined
+ behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0037/CMP0037-WARN-space.cmake b/Tests/RunCMake/CMP0037/CMP0037-WARN-space.cmake
new file mode 100644
index 0000000..e01b8e5
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMP0037-WARN-space.cmake
@@ -0,0 +1,4 @@
+enable_language(CXX)
+add_library("lib with spaces" empty.cpp)
+add_executable("exe with spaces" empty.cpp)
+add_custom_target("custom with spaces")
diff --git a/Tests/RunCMake/CMP0037/CMakeLists.txt b/Tests/RunCMake/CMP0037/CMakeLists.txt
new file mode 100644
index 0000000..4b3de84
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0037/NEW-cond-package-result.txt b/Tests/RunCMake/CMP0037/NEW-cond-package-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/NEW-cond-package-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0037/NEW-cond-package-stderr.txt b/Tests/RunCMake/CMP0037/NEW-cond-package-stderr.txt
new file mode 100644
index 0000000..270fa6d
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/NEW-cond-package-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at NEW-cond-package.cmake:4 \(add_custom_target\):
+ The target name "package" is reserved when CPack packaging is enabled.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0037/NEW-cond-package.cmake b/Tests/RunCMake/CMP0037/NEW-cond-package.cmake
new file mode 100644
index 0000000..ceea907
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/NEW-cond-package.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0037 NEW)
+file(WRITE "${CMAKE_BINARY_DIR}/CPackConfig.cmake" "")
+add_custom_target(test)
+add_custom_target(package)
+add_custom_target(package_source)
diff --git a/Tests/RunCMake/CMP0037/NEW-cond-package_source-result.txt b/Tests/RunCMake/CMP0037/NEW-cond-package_source-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/NEW-cond-package_source-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0037/NEW-cond-package_source-stderr.txt b/Tests/RunCMake/CMP0037/NEW-cond-package_source-stderr.txt
new file mode 100644
index 0000000..2d32147
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/NEW-cond-package_source-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at NEW-cond-package_source.cmake:5 \(add_custom_target\):
+ The target name "package_source" is reserved when CPack source packaging is
+ enabled.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0037/NEW-cond-package_source.cmake b/Tests/RunCMake/CMP0037/NEW-cond-package_source.cmake
new file mode 100644
index 0000000..3f8883b
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/NEW-cond-package_source.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0037 NEW)
+file(WRITE "${CMAKE_BINARY_DIR}/CPackSourceConfig.cmake" "")
+add_custom_target(test)
+add_custom_target(package)
+add_custom_target(package_source)
diff --git a/Tests/RunCMake/CMP0037/NEW-cond-test-result.txt b/Tests/RunCMake/CMP0037/NEW-cond-test-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/NEW-cond-test-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0037/NEW-cond-test-stderr.txt b/Tests/RunCMake/CMP0037/NEW-cond-test-stderr.txt
new file mode 100644
index 0000000..44b4741
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/NEW-cond-test-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at NEW-cond-test.cmake:3 \(add_custom_target\):
+ The target name "test" is reserved when CTest testing is enabled.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0037/NEW-cond-test.cmake b/Tests/RunCMake/CMP0037/NEW-cond-test.cmake
new file mode 100644
index 0000000..7eeaffc
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/NEW-cond-test.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0037 NEW)
+enable_testing()
+add_custom_target(test)
+add_custom_target(package)
+add_custom_target(package_source)
diff --git a/Tests/RunCMake/CMP0037/NEW-cond.cmake b/Tests/RunCMake/CMP0037/NEW-cond.cmake
new file mode 100644
index 0000000..d0dc77af
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/NEW-cond.cmake
@@ -0,0 +1,4 @@
+cmake_policy(SET CMP0037 NEW)
+add_custom_target(test)
+add_custom_target(package)
+add_custom_target(package_source)
diff --git a/Tests/RunCMake/CMP0037/OLD-cond-package-stderr.txt b/Tests/RunCMake/CMP0037/OLD-cond-package-stderr.txt
new file mode 100644
index 0000000..5a29a49
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/OLD-cond-package-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at OLD-cond-package.cmake:1 \(cmake_policy\):
+ The OLD behavior for policy CMP0037 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0037/OLD-cond-package.cmake b/Tests/RunCMake/CMP0037/OLD-cond-package.cmake
new file mode 100644
index 0000000..7a0afbe
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/OLD-cond-package.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0037 OLD)
+file(WRITE "${CMAKE_BINARY_DIR}/CPackConfig.cmake" "")
+add_custom_target(test)
+add_custom_target(package)
+add_custom_target(package_source)
diff --git a/Tests/RunCMake/CMP0037/OLD-cond-package_source-stderr.txt b/Tests/RunCMake/CMP0037/OLD-cond-package_source-stderr.txt
new file mode 100644
index 0000000..5f72e16
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/OLD-cond-package_source-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at OLD-cond-package_source.cmake:1 \(cmake_policy\):
+ The OLD behavior for policy CMP0037 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0037/OLD-cond-package_source.cmake b/Tests/RunCMake/CMP0037/OLD-cond-package_source.cmake
new file mode 100644
index 0000000..95616b6
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/OLD-cond-package_source.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0037 OLD)
+file(WRITE "${CMAKE_BINARY_DIR}/CPackSourceConfig.cmake" "")
+add_custom_target(test)
+add_custom_target(package)
+add_custom_target(package_source)
diff --git a/Tests/RunCMake/CMP0037/OLD-cond-stderr.txt b/Tests/RunCMake/CMP0037/OLD-cond-stderr.txt
new file mode 100644
index 0000000..94e4575
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/OLD-cond-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at OLD-cond.cmake:1 \(cmake_policy\):
+ The OLD behavior for policy CMP0037 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0037/OLD-cond-test-stderr.txt b/Tests/RunCMake/CMP0037/OLD-cond-test-stderr.txt
new file mode 100644
index 0000000..81e10ce
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/OLD-cond-test-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at OLD-cond-test.cmake:1 \(cmake_policy\):
+ The OLD behavior for policy CMP0037 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0037/OLD-cond-test.cmake b/Tests/RunCMake/CMP0037/OLD-cond-test.cmake
new file mode 100644
index 0000000..bfa32a9
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/OLD-cond-test.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0037 OLD)
+enable_testing()
+add_custom_target(test)
+add_custom_target(package)
+add_custom_target(package_source)
diff --git a/Tests/RunCMake/CMP0037/OLD-cond.cmake b/Tests/RunCMake/CMP0037/OLD-cond.cmake
new file mode 100644
index 0000000..abad680
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/OLD-cond.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0037 OLD)
+
+add_custom_target(test)
+add_custom_target(package)
+add_custom_target(package_source)
diff --git a/Tests/RunCMake/CMP0037/RunCMakeTest.cmake b/Tests/RunCMake/CMP0037/RunCMakeTest.cmake
new file mode 100644
index 0000000..5952279
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/RunCMakeTest.cmake
@@ -0,0 +1,51 @@
+include(RunCMake)
+
+if(RunCMake_GENERATOR MATCHES "^Ninja")
+ # Detect ninja version so we know what tests can be supported.
+ execute_process(
+ COMMAND "${RunCMake_MAKE_PROGRAM}" --version
+ OUTPUT_VARIABLE ninja_out
+ ERROR_VARIABLE ninja_out
+ RESULT_VARIABLE ninja_res
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if(ninja_res EQUAL 0 AND "x${ninja_out}" MATCHES "^x[0-9]+\\.[0-9]+")
+ set(ninja_version "${ninja_out}")
+ message(STATUS "ninja version: ${ninja_version}")
+ else()
+ message(FATAL_ERROR "'ninja --version' reported:\n${ninja_out}")
+ endif()
+else()
+ set(ninja_version "")
+endif()
+
+run_cmake(CMP0037-OLD-space)
+run_cmake(CMP0037-NEW-space)
+run_cmake(CMP0037-WARN-space)
+run_cmake(CMP0037-NEW-colon)
+
+if(NOT (WIN32 AND "${RunCMake_GENERATOR}" MATCHES "Make"))
+ run_cmake(CMP0037-WARN-colon)
+endif()
+
+if(NOT ninja_version VERSION_GREATER_EQUAL 1.10)
+ run_cmake(CMP0037-WARN-reserved)
+ run_cmake(CMP0037-OLD-reserved)
+endif()
+run_cmake(CMP0037-NEW-reserved)
+
+run_cmake(NEW-cond)
+run_cmake(NEW-cond-test)
+run_cmake(NEW-cond-package)
+run_cmake(OLD-cond)
+run_cmake(OLD-cond-test)
+run_cmake(OLD-cond-package)
+run_cmake(WARN-cond)
+run_cmake(WARN-cond-test)
+run_cmake(WARN-cond-package)
+
+if(RunCMake_GENERATOR MATCHES "Make|Ninja")
+ run_cmake(NEW-cond-package_source)
+ run_cmake(OLD-cond-package_source)
+ run_cmake(WARN-cond-package_source)
+endif()
diff --git a/Tests/RunCMake/CMP0037/WARN-cond-package-stderr.txt b/Tests/RunCMake/CMP0037/WARN-cond-package-stderr.txt
new file mode 100644
index 0000000..5960e51
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/WARN-cond-package-stderr.txt
@@ -0,0 +1,11 @@
+^CMake Warning \(dev\) at WARN-cond-package.cmake:4 \(add_custom_target\):
+ Policy CMP0037 is not set: Target names should not be reserved and should
+ match a validity pattern. Run "cmake --help-policy CMP0037" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ The target name "package" is reserved when CPack packaging is enabled. It
+ may result in undefined behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/CMP0037/WARN-cond-package.cmake b/Tests/RunCMake/CMP0037/WARN-cond-package.cmake
new file mode 100644
index 0000000..61cdc68
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/WARN-cond-package.cmake
@@ -0,0 +1,5 @@
+
+file(WRITE "${CMAKE_BINARY_DIR}/CPackConfig.cmake" "")
+add_custom_target(test)
+add_custom_target(package)
+add_custom_target(package_source)
diff --git a/Tests/RunCMake/CMP0037/WARN-cond-package_source-stderr.txt b/Tests/RunCMake/CMP0037/WARN-cond-package_source-stderr.txt
new file mode 100644
index 0000000..ae72909
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/WARN-cond-package_source-stderr.txt
@@ -0,0 +1,11 @@
+^CMake Warning \(dev\) at WARN-cond-package_source.cmake:5 \(add_custom_target\):
+ Policy CMP0037 is not set: Target names should not be reserved and should
+ match a validity pattern. Run "cmake --help-policy CMP0037" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ The target name "package_source" is reserved when CPack source packaging is
+ enabled. It may result in undefined behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/CMP0037/WARN-cond-package_source.cmake b/Tests/RunCMake/CMP0037/WARN-cond-package_source.cmake
new file mode 100644
index 0000000..468380c
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/WARN-cond-package_source.cmake
@@ -0,0 +1,5 @@
+
+file(WRITE "${CMAKE_BINARY_DIR}/CPackSourceConfig.cmake" "")
+add_custom_target(test)
+add_custom_target(package)
+add_custom_target(package_source)
diff --git a/Tests/RunCMake/CMP0037/WARN-cond-test-stderr.txt b/Tests/RunCMake/CMP0037/WARN-cond-test-stderr.txt
new file mode 100644
index 0000000..e7a3ee5
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/WARN-cond-test-stderr.txt
@@ -0,0 +1,11 @@
+^CMake Warning \(dev\) at WARN-cond-test.cmake:3 \(add_custom_target\):
+ Policy CMP0037 is not set: Target names should not be reserved and should
+ match a validity pattern. Run "cmake --help-policy CMP0037" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ The target name "test" is reserved when CTest testing is enabled. It may
+ result in undefined behavior.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/CMP0037/WARN-cond-test.cmake b/Tests/RunCMake/CMP0037/WARN-cond-test.cmake
new file mode 100644
index 0000000..982af36
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/WARN-cond-test.cmake
@@ -0,0 +1,5 @@
+
+enable_testing()
+add_custom_target(test)
+add_custom_target(package)
+add_custom_target(package_source)
diff --git a/Tests/RunCMake/CMP0037/WARN-cond.cmake b/Tests/RunCMake/CMP0037/WARN-cond.cmake
new file mode 100644
index 0000000..04a7f9d
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/WARN-cond.cmake
@@ -0,0 +1,4 @@
+
+add_custom_target(test)
+add_custom_target(package)
+add_custom_target(package_source)
diff --git a/Tests/RunCMake/CMP0037/empty.cpp b/Tests/RunCMake/CMP0037/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0037/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0038/CMP0038-NEW-result.txt b/Tests/RunCMake/CMP0038/CMP0038-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0038/CMP0038-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0038/CMP0038-NEW-stderr.txt b/Tests/RunCMake/CMP0038/CMP0038-NEW-stderr.txt
new file mode 100644
index 0000000..3d0a428
--- /dev/null
+++ b/Tests/RunCMake/CMP0038/CMP0038-NEW-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at CMP0038-NEW.cmake:3 \(add_library\):
+ Target "self_link" links to itself.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0038/CMP0038-NEW.cmake b/Tests/RunCMake/CMP0038/CMP0038-NEW.cmake
new file mode 100644
index 0000000..6296b83
--- /dev/null
+++ b/Tests/RunCMake/CMP0038/CMP0038-NEW.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0038 NEW)
+add_library(self_link empty.cpp)
+target_link_libraries(self_link self_link)
diff --git a/Tests/RunCMake/CMP0038/CMP0038-OLD-stderr.txt b/Tests/RunCMake/CMP0038/CMP0038-OLD-stderr.txt
new file mode 100644
index 0000000..c754128
--- /dev/null
+++ b/Tests/RunCMake/CMP0038/CMP0038-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0038-OLD.cmake:2 \(cmake_policy\):
+ The OLD behavior for policy CMP0038 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0038/CMP0038-OLD.cmake b/Tests/RunCMake/CMP0038/CMP0038-OLD.cmake
new file mode 100644
index 0000000..3752821
--- /dev/null
+++ b/Tests/RunCMake/CMP0038/CMP0038-OLD.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0038 OLD)
+add_library(self_link empty.cpp)
+target_link_libraries(self_link self_link)
diff --git a/Tests/RunCMake/CMP0038/CMP0038-WARN-result.txt b/Tests/RunCMake/CMP0038/CMP0038-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0038/CMP0038-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0038/CMP0038-WARN-stderr.txt b/Tests/RunCMake/CMP0038/CMP0038-WARN-stderr.txt
new file mode 100644
index 0000000..64631e7
--- /dev/null
+++ b/Tests/RunCMake/CMP0038/CMP0038-WARN-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMP0038-WARN.cmake:2 \(add_library\):
+ Policy CMP0038 is not set: Targets may not link directly to themselves.
+ Run "cmake --help-policy CMP0038" for policy details. Use the cmake_policy
+ command to set the policy and suppress this warning.
+
+ Target "self_link" links to itself.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0038/CMP0038-WARN.cmake b/Tests/RunCMake/CMP0038/CMP0038-WARN.cmake
new file mode 100644
index 0000000..5b92d09
--- /dev/null
+++ b/Tests/RunCMake/CMP0038/CMP0038-WARN.cmake
@@ -0,0 +1,3 @@
+
+add_library(self_link empty.cpp)
+target_link_libraries(self_link self_link)
diff --git a/Tests/RunCMake/CMP0038/CMakeLists.txt b/Tests/RunCMake/CMP0038/CMakeLists.txt
new file mode 100644
index 0000000..a06591c
--- /dev/null
+++ b/Tests/RunCMake/CMP0038/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0038/RunCMakeTest.cmake b/Tests/RunCMake/CMP0038/RunCMakeTest.cmake
new file mode 100644
index 0000000..fc3500a
--- /dev/null
+++ b/Tests/RunCMake/CMP0038/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0038-WARN)
+run_cmake(CMP0038-NEW)
+run_cmake(CMP0038-OLD)
diff --git a/Tests/RunCMake/CMP0038/empty.cpp b/Tests/RunCMake/CMP0038/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0038/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0039/CMP0039-NEW-result.txt b/Tests/RunCMake/CMP0039/CMP0039-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0039/CMP0039-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0039/CMP0039-NEW-stderr.txt b/Tests/RunCMake/CMP0039/CMP0039-NEW-stderr.txt
new file mode 100644
index 0000000..3d9d225
--- /dev/null
+++ b/Tests/RunCMake/CMP0039/CMP0039-NEW-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error at CMP0039-NEW.cmake:7 \(target_link_libraries\):
+ Utility target "utility" must not be used as the target of a
+ target_link_libraries call.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0039/CMP0039-NEW.cmake b/Tests/RunCMake/CMP0039/CMP0039-NEW.cmake
new file mode 100644
index 0000000..2032d64
--- /dev/null
+++ b/Tests/RunCMake/CMP0039/CMP0039-NEW.cmake
@@ -0,0 +1,7 @@
+
+cmake_policy(SET CMP0039 NEW)
+
+add_custom_target(utility
+ COMMAND ${CMAKE_COMMAND} -E echo test
+)
+target_link_libraries(utility m)
diff --git a/Tests/RunCMake/CMP0039/CMP0039-OLD-stderr.txt b/Tests/RunCMake/CMP0039/CMP0039-OLD-stderr.txt
new file mode 100644
index 0000000..d7863fd
--- /dev/null
+++ b/Tests/RunCMake/CMP0039/CMP0039-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0039-OLD.cmake:2 \(cmake_policy\):
+ The OLD behavior for policy CMP0039 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0039/CMP0039-OLD.cmake b/Tests/RunCMake/CMP0039/CMP0039-OLD.cmake
new file mode 100644
index 0000000..9a513f4
--- /dev/null
+++ b/Tests/RunCMake/CMP0039/CMP0039-OLD.cmake
@@ -0,0 +1,7 @@
+
+cmake_policy(SET CMP0039 OLD)
+
+add_custom_target(utility
+ COMMAND ${CMAKE_COMMAND} -E echo test
+)
+target_link_libraries(utility m)
diff --git a/Tests/RunCMake/CMP0039/CMP0039-WARN-result.txt b/Tests/RunCMake/CMP0039/CMP0039-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0039/CMP0039-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0039/CMP0039-WARN-stderr.txt b/Tests/RunCMake/CMP0039/CMP0039-WARN-stderr.txt
new file mode 100644
index 0000000..a8e6c70
--- /dev/null
+++ b/Tests/RunCMake/CMP0039/CMP0039-WARN-stderr.txt
@@ -0,0 +1,10 @@
+CMake Warning \(dev\) at CMP0039-WARN.cmake:5 \(target_link_libraries\):
+ Policy CMP0039 is not set: Utility targets may not have link dependencies.
+ Run "cmake --help-policy CMP0039" for policy details. Use the cmake_policy
+ command to set the policy and suppress this warning.
+
+ Utility target "utility" should not be used as the target of a
+ target_link_libraries call.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0039/CMP0039-WARN.cmake b/Tests/RunCMake/CMP0039/CMP0039-WARN.cmake
new file mode 100644
index 0000000..6249993
--- /dev/null
+++ b/Tests/RunCMake/CMP0039/CMP0039-WARN.cmake
@@ -0,0 +1,5 @@
+
+add_custom_target(utility
+ COMMAND ${CMAKE_COMMAND} -E echo test
+)
+target_link_libraries(utility m)
diff --git a/Tests/RunCMake/CMP0039/CMakeLists.txt b/Tests/RunCMake/CMP0039/CMakeLists.txt
new file mode 100644
index 0000000..a06591c
--- /dev/null
+++ b/Tests/RunCMake/CMP0039/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0039/RunCMakeTest.cmake b/Tests/RunCMake/CMP0039/RunCMakeTest.cmake
new file mode 100644
index 0000000..58e8ea9
--- /dev/null
+++ b/Tests/RunCMake/CMP0039/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0039-WARN)
+run_cmake(CMP0039-NEW)
+run_cmake(CMP0039-OLD)
diff --git a/Tests/RunCMake/CMP0040/CMP0040-NEW-existing-target-result.txt b/Tests/RunCMake/CMP0040/CMP0040-NEW-existing-target-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/CMP0040-NEW-existing-target-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0040/CMP0040-NEW-existing-target.cmake b/Tests/RunCMake/CMP0040/CMP0040-NEW-existing-target.cmake
new file mode 100644
index 0000000..880b178
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/CMP0040-NEW-existing-target.cmake
@@ -0,0 +1,7 @@
+cmake_policy(SET CMP0040 NEW)
+
+add_library(foobar empty.cpp)
+
+add_custom_command(TARGET foobar PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo hello world
+)
diff --git a/Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target-result.txt b/Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target-stderr.txt b/Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target-stderr.txt
new file mode 100644
index 0000000..4a1077c
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at CMP0040-NEW-missing-target.cmake:3 \(add_custom_command\):
+ No TARGET 'foobar' has been created in this directory.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target.cmake b/Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target.cmake
new file mode 100644
index 0000000..a9f764c
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/CMP0040-NEW-missing-target.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0040 NEW)
+
+add_custom_command(TARGET foobar PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E hello world
+)
diff --git a/Tests/RunCMake/CMP0040/CMP0040-OLD-existing-target-stderr.txt b/Tests/RunCMake/CMP0040/CMP0040-OLD-existing-target-stderr.txt
new file mode 100644
index 0000000..f38c03d
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/CMP0040-OLD-existing-target-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0040-OLD-existing-target.cmake:1 \(cmake_policy\):
+ The OLD behavior for policy CMP0040 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0040/CMP0040-OLD-existing-target.cmake b/Tests/RunCMake/CMP0040/CMP0040-OLD-existing-target.cmake
new file mode 100644
index 0000000..7a9e91e
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/CMP0040-OLD-existing-target.cmake
@@ -0,0 +1,7 @@
+cmake_policy(SET CMP0040 OLD)
+
+add_library(foobar empty.cpp)
+
+add_custom_command(TARGET foobar PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo hello world
+)
diff --git a/Tests/RunCMake/CMP0040/CMP0040-OLD-missing-target-stderr.txt b/Tests/RunCMake/CMP0040/CMP0040-OLD-missing-target-stderr.txt
new file mode 100644
index 0000000..61f4f03
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/CMP0040-OLD-missing-target-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0040-OLD-missing-target.cmake:1 \(cmake_policy\):
+ The OLD behavior for policy CMP0040 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0040/CMP0040-OLD-missing-target.cmake b/Tests/RunCMake/CMP0040/CMP0040-OLD-missing-target.cmake
new file mode 100644
index 0000000..0f5cd15
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/CMP0040-OLD-missing-target.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0040 OLD)
+
+add_custom_command(TARGET foobar PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo hello world
+)
diff --git a/Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target-result.txt b/Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target-stderr.txt b/Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target-stderr.txt
new file mode 100644
index 0000000..70ed05b
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target-stderr.txt
@@ -0,0 +1,10 @@
+CMake Warning \(dev\) at CMP0040-WARN-missing-target.cmake:2 \(add_custom_command\):
+ Policy CMP0040 is not set: The target in the TARGET signature of
+ add_custom_command\(\) must exist and must be defined in the current
+ directory. Run "cmake --help-policy CMP0040" for policy details. Use the
+ cmake_policy command to set the policy and suppress this warning.
++
+ No TARGET 'foobar' has been created in this directory.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target.cmake b/Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target.cmake
new file mode 100644
index 0000000..4efeaae
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/CMP0040-WARN-missing-target.cmake
@@ -0,0 +1,4 @@
+
+add_custom_command(TARGET foobar PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E hello world
+)
diff --git a/Tests/RunCMake/CMP0040/CMakeLists.txt b/Tests/RunCMake/CMP0040/CMakeLists.txt
new file mode 100644
index 0000000..a06591c
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0040/RunCMakeTest.cmake b/Tests/RunCMake/CMP0040/RunCMakeTest.cmake
new file mode 100644
index 0000000..13160e3
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/RunCMakeTest.cmake
@@ -0,0 +1,8 @@
+include(RunCMake)
+
+run_cmake(CMP0040-OLD-missing-target)
+run_cmake(CMP0040-NEW-missing-target)
+run_cmake(CMP0040-WARN-missing-target)
+
+run_cmake(CMP0040-OLD-existing-target)
+run_cmake(CMP0040-NEW-existing-target)
diff --git a/Tests/RunCMake/CMP0040/empty.cpp b/Tests/RunCMake/CMP0040/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0040/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0041/CMP0041-NEW-result.txt b/Tests/RunCMake/CMP0041/CMP0041-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0041/CMP0041-NEW-stderr.txt b/Tests/RunCMake/CMP0041/CMP0041-NEW-stderr.txt
new file mode 100644
index 0000000..2ec3aef
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-NEW-stderr.txt
@@ -0,0 +1,20 @@
+CMake Error in CMakeLists.txt:
+ Target "foo" INTERFACE_INCLUDE_DIRECTORIES property contains relative path:
+
+ "include/\$<TARGET_PROPERTY:NAME>"
+
+
+CMake Error in CMakeLists.txt:
+ Target "foo" INTERFACE_INCLUDE_DIRECTORIES property contains path:
+
+ ".*/Tests/RunCMake/CMP0041/include/\$<TARGET_PROPERTY:NAME>"
+
+ which is prefixed in the source directory.
+
+
+CMake Error in CMakeLists.txt:
+ Target "foo" INTERFACE_INCLUDE_DIRECTORIES property contains path:
+
+ ".*/Tests/RunCMake/CMP0041/CMP0041-NEW-build/include/\$<TARGET_PROPERTY:NAME>"
+
+ which is prefixed in the build directory.
diff --git a/Tests/RunCMake/CMP0041/CMP0041-NEW.cmake b/Tests/RunCMake/CMP0041/CMP0041-NEW.cmake
new file mode 100644
index 0000000..605b79a
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-NEW.cmake
@@ -0,0 +1,12 @@
+
+cmake_policy(SET CMP0041 NEW)
+
+add_library(foo empty.cpp)
+set_property(TARGET foo
+ PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+ include/$<TARGET_PROPERTY:NAME>
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/$<TARGET_PROPERTY:NAME>
+ ${CMAKE_CURRENT_BINARY_DIR}/include/$<TARGET_PROPERTY:NAME>
+)
+install(TARGETS foo EXPORT FooExport DESTINATION lib)
+install(EXPORT FooExport DESTINATION lib/cmake)
diff --git a/Tests/RunCMake/CMP0041/CMP0041-OLD-stderr.txt b/Tests/RunCMake/CMP0041/CMP0041-OLD-stderr.txt
new file mode 100644
index 0000000..1b736da
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0041-OLD.cmake:2 \(cmake_policy\):
+ The OLD behavior for policy CMP0041 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0041/CMP0041-OLD.cmake b/Tests/RunCMake/CMP0041/CMP0041-OLD.cmake
new file mode 100644
index 0000000..16cbced
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-OLD.cmake
@@ -0,0 +1,12 @@
+
+cmake_policy(SET CMP0041 OLD)
+
+add_library(foo empty.cpp)
+set_property(TARGET foo
+ PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+ include/$<TARGET_PROPERTY:NAME>
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/$<TARGET_PROPERTY:NAME>
+ ${CMAKE_CURRENT_BINARY_DIR}/include/$<TARGET_PROPERTY:NAME>
+)
+install(TARGETS foo EXPORT FooExport DESTINATION lib)
+install(EXPORT FooExport DESTINATION lib/cmake)
diff --git a/Tests/RunCMake/CMP0041/CMP0041-WARN-result.txt b/Tests/RunCMake/CMP0041/CMP0041-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0041/CMP0041-WARN-stderr.txt b/Tests/RunCMake/CMP0041/CMP0041-WARN-stderr.txt
new file mode 100644
index 0000000..a7d303e
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-WARN-stderr.txt
@@ -0,0 +1,32 @@
+CMake Warning in CMakeLists.txt:
+ Policy CMP0041 is not set: Error on relative include with generator
+ expression. Run "cmake --help-policy CMP0041" for policy details. Use the
+ cmake_policy command to set the policy and suppress this warning.
+
+ Target "foo" INTERFACE_INCLUDE_DIRECTORIES property contains relative path:
+
+ "include/\$<TARGET_PROPERTY:NAME>"
+
+
+CMake Warning in CMakeLists.txt:
+ Policy CMP0041 is not set: Error on relative include with generator
+ expression. Run "cmake --help-policy CMP0041" for policy details. Use the
+ cmake_policy command to set the policy and suppress this warning.
+
+ Target "foo" INTERFACE_INCLUDE_DIRECTORIES property contains path:
+
+ ".*/Tests/RunCMake/CMP0041/include/\$<TARGET_PROPERTY:NAME>"
+
+ which is prefixed in the source directory.
+
+
+CMake Warning in CMakeLists.txt:
+ Policy CMP0041 is not set: Error on relative include with generator
+ expression. Run "cmake --help-policy CMP0041" for policy details. Use the
+ cmake_policy command to set the policy and suppress this warning.
+
+ Target "foo" INTERFACE_INCLUDE_DIRECTORIES property contains path:
+
+ ".*/Tests/RunCMake/CMP0041/CMP0041-WARN-build/include/\$<TARGET_PROPERTY:NAME>"
+
+ which is prefixed in the build directory.
diff --git a/Tests/RunCMake/CMP0041/CMP0041-WARN.cmake b/Tests/RunCMake/CMP0041/CMP0041-WARN.cmake
new file mode 100644
index 0000000..873cbc7
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-WARN.cmake
@@ -0,0 +1,10 @@
+
+add_library(foo empty.cpp)
+set_property(TARGET foo
+ PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+ include/$<TARGET_PROPERTY:NAME>
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/$<TARGET_PROPERTY:NAME>
+ ${CMAKE_CURRENT_BINARY_DIR}/include/$<TARGET_PROPERTY:NAME>
+)
+install(TARGETS foo EXPORT FooExport DESTINATION lib)
+install(EXPORT FooExport DESTINATION lib/cmake)
diff --git a/Tests/RunCMake/CMP0041/CMP0041-tid-NEW-result.txt b/Tests/RunCMake/CMP0041/CMP0041-tid-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-tid-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0041/CMP0041-tid-NEW-stderr.txt b/Tests/RunCMake/CMP0041/CMP0041-tid-NEW-stderr.txt
new file mode 100644
index 0000000..9b0a214
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-tid-NEW-stderr.txt
@@ -0,0 +1,22 @@
+CMake Error in CMakeLists.txt:
+ Target "foo" INTERFACE_INCLUDE_DIRECTORIES property contains path:
+
+ ".*/Tests/RunCMake/CMP0041/include/\$<TARGET_PROPERTY:NAME>"
+
+ which is prefixed in the source directory.
+
+
+CMake Error in CMakeLists.txt:
+ Target "foo" INTERFACE_INCLUDE_DIRECTORIES property contains path:
+
+ ".*/Tests/RunCMake/CMP0041/include/\$<TARGET_PROPERTY:NAME>"
+
+ which is prefixed in the source directory.
+
+
+CMake Error in CMakeLists.txt:
+ Target "foo" INTERFACE_INCLUDE_DIRECTORIES property contains path:
+
+ ".*/Tests/RunCMake/CMP0041/CMP0041-tid-NEW-build/include/\$<TARGET_PROPERTY:NAME>"
+
+ which is prefixed in the build directory.
diff --git a/Tests/RunCMake/CMP0041/CMP0041-tid-NEW.cmake b/Tests/RunCMake/CMP0041/CMP0041-tid-NEW.cmake
new file mode 100644
index 0000000..3005108
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-tid-NEW.cmake
@@ -0,0 +1,11 @@
+
+cmake_policy(SET CMP0041 NEW)
+
+add_library(foo empty.cpp)
+target_include_directories(foo INTERFACE
+ include/$<TARGET_PROPERTY:NAME>
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/$<TARGET_PROPERTY:NAME>
+ ${CMAKE_CURRENT_BINARY_DIR}/include/$<TARGET_PROPERTY:NAME>
+)
+install(TARGETS foo EXPORT FooExport DESTINATION lib)
+install(EXPORT FooExport DESTINATION lib/cmake)
diff --git a/Tests/RunCMake/CMP0041/CMP0041-tid-OLD-stderr.txt b/Tests/RunCMake/CMP0041/CMP0041-tid-OLD-stderr.txt
new file mode 100644
index 0000000..dbc5167
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-tid-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0041-tid-OLD.cmake:2 \(cmake_policy\):
+ The OLD behavior for policy CMP0041 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0041/CMP0041-tid-OLD.cmake b/Tests/RunCMake/CMP0041/CMP0041-tid-OLD.cmake
new file mode 100644
index 0000000..b5c4e7f
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-tid-OLD.cmake
@@ -0,0 +1,11 @@
+
+cmake_policy(SET CMP0041 OLD)
+
+add_library(foo empty.cpp)
+target_include_directories(foo INTERFACE
+ include/$<TARGET_PROPERTY:NAME>
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/$<TARGET_PROPERTY:NAME>
+ ${CMAKE_CURRENT_BINARY_DIR}/include/$<TARGET_PROPERTY:NAME>
+)
+install(TARGETS foo EXPORT FooExport DESTINATION lib)
+install(EXPORT FooExport DESTINATION lib/cmake)
diff --git a/Tests/RunCMake/CMP0041/CMP0041-tid-WARN-result.txt b/Tests/RunCMake/CMP0041/CMP0041-tid-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-tid-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0041/CMP0041-tid-WARN-stderr.txt b/Tests/RunCMake/CMP0041/CMP0041-tid-WARN-stderr.txt
new file mode 100644
index 0000000..aae2c7a
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-tid-WARN-stderr.txt
@@ -0,0 +1,34 @@
+CMake Warning in CMakeLists.txt:
+ Policy CMP0041 is not set: Error on relative include with generator
+ expression. Run "cmake --help-policy CMP0041" for policy details. Use the
+ cmake_policy command to set the policy and suppress this warning.
+
+ Target "foo" INTERFACE_INCLUDE_DIRECTORIES property contains path:
+
+ ".*/Tests/RunCMake/CMP0041/include/\$<TARGET_PROPERTY:NAME>"
+
+ which is prefixed in the source directory.
+
+
+CMake Warning in CMakeLists.txt:
+ Policy CMP0041 is not set: Error on relative include with generator
+ expression. Run "cmake --help-policy CMP0041" for policy details. Use the
+ cmake_policy command to set the policy and suppress this warning.
+
+ Target "foo" INTERFACE_INCLUDE_DIRECTORIES property contains path:
+
+ ".*/Tests/RunCMake/CMP0041/include/\$<TARGET_PROPERTY:NAME>"
+
+ which is prefixed in the source directory.
+
+
+CMake Warning in CMakeLists.txt:
+ Policy CMP0041 is not set: Error on relative include with generator
+ expression. Run "cmake --help-policy CMP0041" for policy details. Use the
+ cmake_policy command to set the policy and suppress this warning.
+
+ Target "foo" INTERFACE_INCLUDE_DIRECTORIES property contains path:
+
+ ".*/Tests/RunCMake/CMP0041/CMP0041-tid-WARN-build/include/\$<TARGET_PROPERTY:NAME>"
+
+ which is prefixed in the build directory.
diff --git a/Tests/RunCMake/CMP0041/CMP0041-tid-WARN.cmake b/Tests/RunCMake/CMP0041/CMP0041-tid-WARN.cmake
new file mode 100644
index 0000000..ee4c2a6
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMP0041-tid-WARN.cmake
@@ -0,0 +1,9 @@
+
+add_library(foo empty.cpp)
+target_include_directories(foo INTERFACE
+ include/$<TARGET_PROPERTY:NAME>
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/$<TARGET_PROPERTY:NAME>
+ ${CMAKE_CURRENT_BINARY_DIR}/include/$<TARGET_PROPERTY:NAME>
+)
+install(TARGETS foo EXPORT FooExport DESTINATION lib)
+install(EXPORT FooExport DESTINATION lib/cmake)
diff --git a/Tests/RunCMake/CMP0041/CMakeLists.txt b/Tests/RunCMake/CMP0041/CMakeLists.txt
new file mode 100644
index 0000000..a06591c
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0041/RunCMakeTest.cmake b/Tests/RunCMake/CMP0041/RunCMakeTest.cmake
new file mode 100644
index 0000000..f47bb2e
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/RunCMakeTest.cmake
@@ -0,0 +1,15 @@
+include(RunCMake)
+
+# Protect tests from running inside the default install prefix.
+set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/NotDefaultPrefix")
+
+run_cmake(CMP0041-OLD)
+run_cmake(CMP0041-NEW)
+run_cmake(CMP0041-WARN)
+
+# Protect tests from running inside the default install prefix.
+set(RunCMake_TEST_OPTIONS "--install-prefix ${RunCMake_BINARY_DIR}/NotDefaultPrefix")
+
+run_cmake(CMP0041-tid-OLD)
+run_cmake(CMP0041-tid-NEW)
+run_cmake(CMP0041-tid-WARN)
diff --git a/Tests/RunCMake/CMP0041/empty.cpp b/Tests/RunCMake/CMP0041/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0041/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0042/CMP0042-NEW-result.txt b/Tests/RunCMake/CMP0042/CMP0042-NEW-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0042/CMP0042-NEW-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0042/CMP0042-NEW.cmake b/Tests/RunCMake/CMP0042/CMP0042-NEW.cmake
new file mode 100644
index 0000000..778a444
--- /dev/null
+++ b/Tests/RunCMake/CMP0042/CMP0042-NEW.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0042 NEW)
+
+add_library(foo SHARED empty.cpp)
diff --git a/Tests/RunCMake/CMP0042/CMP0042-OLD-stderr.txt b/Tests/RunCMake/CMP0042/CMP0042-OLD-stderr.txt
new file mode 100644
index 0000000..9d1488d
--- /dev/null
+++ b/Tests/RunCMake/CMP0042/CMP0042-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0042-OLD.cmake:2 \(cmake_policy\):
+ The OLD behavior for policy CMP0042 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0042/CMP0042-OLD.cmake b/Tests/RunCMake/CMP0042/CMP0042-OLD.cmake
new file mode 100644
index 0000000..1aede96
--- /dev/null
+++ b/Tests/RunCMake/CMP0042/CMP0042-OLD.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0042 OLD)
+
+add_library(foo SHARED empty.cpp)
diff --git a/Tests/RunCMake/CMP0042/CMP0042-WARN-result.txt b/Tests/RunCMake/CMP0042/CMP0042-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0042/CMP0042-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0042/CMP0042-WARN-stderr.txt b/Tests/RunCMake/CMP0042/CMP0042-WARN-stderr.txt
new file mode 100644
index 0000000..f3574a1
--- /dev/null
+++ b/Tests/RunCMake/CMP0042/CMP0042-WARN-stderr.txt
@@ -0,0 +1,10 @@
+CMake Warning \(dev\):
+ Policy CMP0042 is not set: MACOSX_RPATH is enabled by default. Run "cmake
+ --help-policy CMP0042" for policy details. Use the cmake_policy command to
+ set the policy and suppress this warning.
+
+ MACOSX_RPATH is not specified for the following targets:
+
+ foo
+
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0042/CMP0042-WARN.cmake b/Tests/RunCMake/CMP0042/CMP0042-WARN.cmake
new file mode 100644
index 0000000..3fa32b1
--- /dev/null
+++ b/Tests/RunCMake/CMP0042/CMP0042-WARN.cmake
@@ -0,0 +1,9 @@
+
+add_library(foo SHARED empty.cpp)
+add_library(foo-static STATIC empty.cpp)
+add_library(foo2 SHARED empty.cpp)
+set_target_properties(foo2 PROPERTIES MACOSX_RPATH 1)
+add_library(foo3 SHARED empty.cpp)
+set_target_properties(foo3 PROPERTIES BUILD_WITH_INSTALL_RPATH 1 INSTALL_NAME_DIR "@loader_path")
+add_library(foo4 SHARED empty.cpp)
+set_target_properties(foo4 PROPERTIES BUILD_WITH_INSTALL_RPATH 1 INSTALL_NAME_DIR "@rpath")
diff --git a/Tests/RunCMake/CMP0042/CMakeLists.txt b/Tests/RunCMake/CMP0042/CMakeLists.txt
new file mode 100644
index 0000000..a06591c
--- /dev/null
+++ b/Tests/RunCMake/CMP0042/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0042/RunCMakeTest.cmake b/Tests/RunCMake/CMP0042/RunCMakeTest.cmake
new file mode 100644
index 0000000..3b226d7
--- /dev/null
+++ b/Tests/RunCMake/CMP0042/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0042-OLD)
+run_cmake(CMP0042-NEW)
+run_cmake(CMP0042-WARN)
diff --git a/Tests/RunCMake/CMP0042/empty.cpp b/Tests/RunCMake/CMP0042/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0042/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0043/CMP0043-NEW-result.txt b/Tests/RunCMake/CMP0043/CMP0043-NEW-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0043/CMP0043-NEW-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0043/CMP0043-NEW.cmake b/Tests/RunCMake/CMP0043/CMP0043-NEW.cmake
new file mode 100644
index 0000000..857153d
--- /dev/null
+++ b/Tests/RunCMake/CMP0043/CMP0043-NEW.cmake
@@ -0,0 +1,7 @@
+
+cmake_policy(SET CMP0043 NEW)
+
+add_library(foo empty.cpp)
+set_property(TARGET foo
+ PROPERTY COMPILE_DEFINITIONS_DEBUG "DEBUG_MODE"
+)
diff --git a/Tests/RunCMake/CMP0043/CMP0043-OLD-stderr.txt b/Tests/RunCMake/CMP0043/CMP0043-OLD-stderr.txt
new file mode 100644
index 0000000..ebbb361
--- /dev/null
+++ b/Tests/RunCMake/CMP0043/CMP0043-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0043-OLD.cmake:2 \(cmake_policy\):
+ The OLD behavior for policy CMP0043 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0043/CMP0043-OLD.cmake b/Tests/RunCMake/CMP0043/CMP0043-OLD.cmake
new file mode 100644
index 0000000..f379430
--- /dev/null
+++ b/Tests/RunCMake/CMP0043/CMP0043-OLD.cmake
@@ -0,0 +1,7 @@
+
+cmake_policy(SET CMP0043 OLD)
+
+add_library(foo empty.cpp)
+set_property(TARGET foo
+ PROPERTY COMPILE_DEFINITIONS_DEBUG "DEBUG_MODE"
+)
diff --git a/Tests/RunCMake/CMP0043/CMP0043-WARN-result.txt b/Tests/RunCMake/CMP0043/CMP0043-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0043/CMP0043-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0043/CMP0043-WARN-stderr.txt b/Tests/RunCMake/CMP0043/CMP0043-WARN-stderr.txt
new file mode 100644
index 0000000..4769a63
--- /dev/null
+++ b/Tests/RunCMake/CMP0043/CMP0043-WARN-stderr.txt
@@ -0,0 +1,5 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0043 is not set: Ignore COMPILE_DEFINITIONS_<Config> properties.
+ Run "cmake --help-policy CMP0043" for policy details. Use the cmake_policy
+ command to set the policy and suppress this warning.
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0043/CMP0043-WARN.cmake b/Tests/RunCMake/CMP0043/CMP0043-WARN.cmake
new file mode 100644
index 0000000..161a60d
--- /dev/null
+++ b/Tests/RunCMake/CMP0043/CMP0043-WARN.cmake
@@ -0,0 +1,5 @@
+
+add_library(foo empty.cpp)
+set_property(TARGET foo
+ PROPERTY COMPILE_DEFINITIONS_DEBUG "DEBUG_MODE"
+)
diff --git a/Tests/RunCMake/CMP0043/CMakeLists.txt b/Tests/RunCMake/CMP0043/CMakeLists.txt
new file mode 100644
index 0000000..cc8a6f8
--- /dev/null
+++ b/Tests/RunCMake/CMP0043/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE) # policy used at end of dir
+
+if(CMAKE_BUILD_TYPE)
+ # Dummy variable use
+endif()
diff --git a/Tests/RunCMake/CMP0043/RunCMakeTest.cmake b/Tests/RunCMake/CMP0043/RunCMakeTest.cmake
new file mode 100644
index 0000000..7f9572e
--- /dev/null
+++ b/Tests/RunCMake/CMP0043/RunCMakeTest.cmake
@@ -0,0 +1,7 @@
+include(RunCMake)
+
+list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+
+run_cmake(CMP0043-OLD)
+run_cmake(CMP0043-NEW)
+run_cmake(CMP0043-WARN)
diff --git a/Tests/RunCMake/CMP0043/empty.cpp b/Tests/RunCMake/CMP0043/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0043/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0045/CMP0045-NEW-result.txt b/Tests/RunCMake/CMP0045/CMP0045-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0045/CMP0045-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0045/CMP0045-NEW-stderr.txt b/Tests/RunCMake/CMP0045/CMP0045-NEW-stderr.txt
new file mode 100644
index 0000000..805a85e
--- /dev/null
+++ b/Tests/RunCMake/CMP0045/CMP0045-NEW-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at CMP0045-NEW.cmake:4 \(get_target_property\):
+ get_target_property\(\) called with non-existent target "tgt".
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0045/CMP0045-NEW.cmake b/Tests/RunCMake/CMP0045/CMP0045-NEW.cmake
new file mode 100644
index 0000000..7b2a3cd
--- /dev/null
+++ b/Tests/RunCMake/CMP0045/CMP0045-NEW.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0045 NEW)
+
+get_target_property(result tgt TYPE)
diff --git a/Tests/RunCMake/CMP0045/CMP0045-OLD-stderr.txt b/Tests/RunCMake/CMP0045/CMP0045-OLD-stderr.txt
new file mode 100644
index 0000000..0dac20f
--- /dev/null
+++ b/Tests/RunCMake/CMP0045/CMP0045-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0045-OLD.cmake:2 \(cmake_policy\):
+ The OLD behavior for policy CMP0045 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0045/CMP0045-OLD.cmake b/Tests/RunCMake/CMP0045/CMP0045-OLD.cmake
new file mode 100644
index 0000000..90201a3
--- /dev/null
+++ b/Tests/RunCMake/CMP0045/CMP0045-OLD.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0045 OLD)
+
+get_target_property(result tgt TYPE)
diff --git a/Tests/RunCMake/CMP0045/CMP0045-WARN-result.txt b/Tests/RunCMake/CMP0045/CMP0045-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0045/CMP0045-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0045/CMP0045-WARN-stderr.txt b/Tests/RunCMake/CMP0045/CMP0045-WARN-stderr.txt
new file mode 100644
index 0000000..4c53224
--- /dev/null
+++ b/Tests/RunCMake/CMP0045/CMP0045-WARN-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMP0045-WARN.cmake:2 \(get_target_property\):
+ Policy CMP0045 is not set: Error on non-existent target in
+ get_target_property. Run "cmake --help-policy CMP0045" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
+
+ get_target_property\(\) called with non-existent target "tgt".
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0045/CMP0045-WARN.cmake b/Tests/RunCMake/CMP0045/CMP0045-WARN.cmake
new file mode 100644
index 0000000..86a99a0
--- /dev/null
+++ b/Tests/RunCMake/CMP0045/CMP0045-WARN.cmake
@@ -0,0 +1,2 @@
+
+get_target_property(result tgt TYPE)
diff --git a/Tests/RunCMake/CMP0045/CMakeLists.txt b/Tests/RunCMake/CMP0045/CMakeLists.txt
new file mode 100644
index 0000000..a06591c
--- /dev/null
+++ b/Tests/RunCMake/CMP0045/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0045/RunCMakeTest.cmake b/Tests/RunCMake/CMP0045/RunCMakeTest.cmake
new file mode 100644
index 0000000..7c0e8a2
--- /dev/null
+++ b/Tests/RunCMake/CMP0045/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0045-OLD)
+run_cmake(CMP0045-NEW)
+run_cmake(CMP0045-WARN)
diff --git a/Tests/RunCMake/CMP0045/empty.cpp b/Tests/RunCMake/CMP0045/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0045/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0046/CMP0046-Duplicate-result.txt b/Tests/RunCMake/CMP0046/CMP0046-Duplicate-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/CMP0046-Duplicate-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0046/CMP0046-Duplicate-stderr.txt b/Tests/RunCMake/CMP0046/CMP0046-Duplicate-stderr.txt
new file mode 100644
index 0000000..fb31d6d
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/CMP0046-Duplicate-stderr.txt
@@ -0,0 +1,10 @@
+CMake Warning \(dev\) at CMP0046-Duplicate.cmake:5 \(add_dependencies\):
+ Policy CMP0046 is not set: Error on non-existent dependency in
+ add_dependencies. Run "cmake --help-policy CMP0046" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
+
+ The dependency target "ctgt_no_exist" of target "dummy" does not exist.
+Call Stack \(most recent call first\):
+ CMP0046-Duplicate.cmake:8 \(add_dep\)
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0046/CMP0046-Duplicate.cmake b/Tests/RunCMake/CMP0046/CMP0046-Duplicate.cmake
new file mode 100644
index 0000000..26e640b
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/CMP0046-Duplicate.cmake
@@ -0,0 +1,9 @@
+
+add_library(dummy empty.cpp)
+
+macro(add_dep)
+ add_dependencies(dummy ctgt_no_exist)
+endmacro()
+
+add_dep()
+add_dep()
diff --git a/Tests/RunCMake/CMP0046/CMP0046-NEW-existing-dependency.cmake b/Tests/RunCMake/CMP0046/CMP0046-NEW-existing-dependency.cmake
new file mode 100644
index 0000000..0be290a
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/CMP0046-NEW-existing-dependency.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0046 NEW)
+
+add_custom_target(foo)
+add_custom_target(bar)
+add_dependencies(foo bar)
diff --git a/Tests/RunCMake/CMP0046/CMP0046-NEW-missing-dependency-result.txt b/Tests/RunCMake/CMP0046/CMP0046-NEW-missing-dependency-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/CMP0046-NEW-missing-dependency-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0046/CMP0046-NEW-missing-dependency-stderr.txt b/Tests/RunCMake/CMP0046/CMP0046-NEW-missing-dependency-stderr.txt
new file mode 100644
index 0000000..381647f
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/CMP0046-NEW-missing-dependency-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at CMP0046-NEW-missing-dependency.cmake:4 \(add_dependencies\):
+ The dependency target "bar" of target "foo" does not exist.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0046/CMP0046-NEW-missing-dependency.cmake b/Tests/RunCMake/CMP0046/CMP0046-NEW-missing-dependency.cmake
new file mode 100644
index 0000000..9bb6b90
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/CMP0046-NEW-missing-dependency.cmake
@@ -0,0 +1,4 @@
+cmake_policy(SET CMP0046 NEW)
+
+add_custom_target(foo)
+add_dependencies(foo bar)
diff --git a/Tests/RunCMake/CMP0046/CMP0046-OLD-existing-dependency-stderr.txt b/Tests/RunCMake/CMP0046/CMP0046-OLD-existing-dependency-stderr.txt
new file mode 100644
index 0000000..4444118
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/CMP0046-OLD-existing-dependency-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0046-OLD-existing-dependency.cmake:1 \(cmake_policy\):
+ The OLD behavior for policy CMP0046 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0046/CMP0046-OLD-existing-dependency.cmake b/Tests/RunCMake/CMP0046/CMP0046-OLD-existing-dependency.cmake
new file mode 100644
index 0000000..b22ab4f
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/CMP0046-OLD-existing-dependency.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0046 OLD)
+
+add_custom_target(foo)
+add_custom_target(bar)
+add_dependencies(foo bar)
diff --git a/Tests/RunCMake/CMP0046/CMP0046-OLD-missing-dependency-stderr.txt b/Tests/RunCMake/CMP0046/CMP0046-OLD-missing-dependency-stderr.txt
new file mode 100644
index 0000000..525954f
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/CMP0046-OLD-missing-dependency-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0046-OLD-missing-dependency.cmake:1 \(cmake_policy\):
+ The OLD behavior for policy CMP0046 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0046/CMP0046-OLD-missing-dependency.cmake b/Tests/RunCMake/CMP0046/CMP0046-OLD-missing-dependency.cmake
new file mode 100644
index 0000000..5ee3cb7
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/CMP0046-OLD-missing-dependency.cmake
@@ -0,0 +1,4 @@
+cmake_policy(SET CMP0046 OLD)
+
+add_custom_target(foo)
+add_dependencies(foo bar)
diff --git a/Tests/RunCMake/CMP0046/CMP0046-WARN-missing-dependency-stderr.txt b/Tests/RunCMake/CMP0046/CMP0046-WARN-missing-dependency-stderr.txt
new file mode 100644
index 0000000..fed36f1
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/CMP0046-WARN-missing-dependency-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMP0046-WARN-missing-dependency.cmake:2 \(add_dependencies\):
+ Policy CMP0046 is not set: Error on non-existent dependency in
+ add_dependencies. Run "cmake --help-policy CMP0046" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
++
+ The dependency target "bar" of target "foo" does not exist.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0046/CMP0046-WARN-missing-dependency.cmake b/Tests/RunCMake/CMP0046/CMP0046-WARN-missing-dependency.cmake
new file mode 100644
index 0000000..896fa40
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/CMP0046-WARN-missing-dependency.cmake
@@ -0,0 +1,2 @@
+add_custom_target(foo)
+add_dependencies(foo bar)
diff --git a/Tests/RunCMake/CMP0046/CMakeLists.txt b/Tests/RunCMake/CMP0046/CMakeLists.txt
new file mode 100644
index 0000000..a06591c
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0046/RunCMakeTest.cmake b/Tests/RunCMake/CMP0046/RunCMakeTest.cmake
new file mode 100644
index 0000000..0a39c76
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/RunCMakeTest.cmake
@@ -0,0 +1,9 @@
+include(RunCMake)
+
+run_cmake(CMP0046-OLD-missing-dependency)
+run_cmake(CMP0046-NEW-missing-dependency)
+run_cmake(CMP0046-WARN-missing-dependency)
+
+run_cmake(CMP0046-OLD-existing-dependency)
+run_cmake(CMP0046-NEW-existing-dependency)
+run_cmake(CMP0046-Duplicate)
diff --git a/Tests/RunCMake/CMP0046/empty.cpp b/Tests/RunCMake/CMP0046/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0046/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0049/CMP0049-NEW-result.txt b/Tests/RunCMake/CMP0049/CMP0049-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0049/CMP0049-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0049/CMP0049-NEW-stderr.txt b/Tests/RunCMake/CMP0049/CMP0049-NEW-stderr.txt
new file mode 100644
index 0000000..ff787e8
--- /dev/null
+++ b/Tests/RunCMake/CMP0049/CMP0049-NEW-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at CMP0049-NEW.cmake:5 \(add_library\):
+ Legacy variable expansion in source file "\${tgt_srcs}" expanded to
+ "empty.cpp" in target "tgt". This behavior will be removed in a future
+ version of CMake.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0049/CMP0049-NEW.cmake b/Tests/RunCMake/CMP0049/CMP0049-NEW.cmake
new file mode 100644
index 0000000..85b5aa8
--- /dev/null
+++ b/Tests/RunCMake/CMP0049/CMP0049-NEW.cmake
@@ -0,0 +1,5 @@
+
+cmake_policy(SET CMP0049 NEW)
+
+set(tgt_srcs empty.cpp)
+add_library(tgt \${tgt_srcs})
diff --git a/Tests/RunCMake/CMP0049/CMP0049-OLD-stderr.txt b/Tests/RunCMake/CMP0049/CMP0049-OLD-stderr.txt
new file mode 100644
index 0000000..b373970
--- /dev/null
+++ b/Tests/RunCMake/CMP0049/CMP0049-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0049-OLD.cmake:2 \(cmake_policy\):
+ The OLD behavior for policy CMP0049 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0049/CMP0049-OLD.cmake b/Tests/RunCMake/CMP0049/CMP0049-OLD.cmake
new file mode 100644
index 0000000..ae6fd3b
--- /dev/null
+++ b/Tests/RunCMake/CMP0049/CMP0049-OLD.cmake
@@ -0,0 +1,5 @@
+
+cmake_policy(SET CMP0049 OLD)
+
+set(tgt_srcs empty.cpp)
+add_library(tgt \${tgt_srcs})
diff --git a/Tests/RunCMake/CMP0049/CMP0049-WARN-result.txt b/Tests/RunCMake/CMP0049/CMP0049-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0049/CMP0049-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0049/CMP0049-WARN-stderr.txt b/Tests/RunCMake/CMP0049/CMP0049-WARN-stderr.txt
new file mode 100644
index 0000000..0cf5ce3
--- /dev/null
+++ b/Tests/RunCMake/CMP0049/CMP0049-WARN-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at CMP0049-WARN.cmake:3 \(add_library\):
+ Policy CMP0049 is not set: Do not expand variables in target source
+ entries. Run "cmake --help-policy CMP0049" for policy details. Use the
+ cmake_policy command to set the policy and suppress this warning.
+
+ Legacy variable expansion in source file "\${tgt_srcs}" expanded to
+ "empty.cpp" in target "tgt". This behavior will be removed in a future
+ version of CMake.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0049/CMP0049-WARN.cmake b/Tests/RunCMake/CMP0049/CMP0049-WARN.cmake
new file mode 100644
index 0000000..ada082e
--- /dev/null
+++ b/Tests/RunCMake/CMP0049/CMP0049-WARN.cmake
@@ -0,0 +1,3 @@
+
+set(tgt_srcs empty.cpp)
+add_library(tgt \${tgt_srcs})
diff --git a/Tests/RunCMake/CMP0049/CMakeLists.txt b/Tests/RunCMake/CMP0049/CMakeLists.txt
new file mode 100644
index 0000000..a06591c
--- /dev/null
+++ b/Tests/RunCMake/CMP0049/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0049/RunCMakeTest.cmake b/Tests/RunCMake/CMP0049/RunCMakeTest.cmake
new file mode 100644
index 0000000..a8aa9d9
--- /dev/null
+++ b/Tests/RunCMake/CMP0049/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0049-OLD)
+run_cmake(CMP0049-NEW)
+run_cmake(CMP0049-WARN)
diff --git a/Tests/RunCMake/CMP0049/empty.cpp b/Tests/RunCMake/CMP0049/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0049/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0050/CMP0050-NEW-result.txt b/Tests/RunCMake/CMP0050/CMP0050-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0050/CMP0050-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0050/CMP0050-NEW-stderr.txt b/Tests/RunCMake/CMP0050/CMP0050-NEW-stderr.txt
new file mode 100644
index 0000000..e913b3f
--- /dev/null
+++ b/Tests/RunCMake/CMP0050/CMP0050-NEW-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at CMP0050-NEW.cmake:5 \(add_custom_command\):
+ The SOURCE signatures of add_custom_command are no longer supported.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0050/CMP0050-NEW.cmake b/Tests/RunCMake/CMP0050/CMP0050-NEW.cmake
new file mode 100644
index 0000000..cdc65b8
--- /dev/null
+++ b/Tests/RunCMake/CMP0050/CMP0050-NEW.cmake
@@ -0,0 +1,13 @@
+
+cmake_policy(SET CMP0050 NEW)
+
+add_library(empty empty.cpp)
+add_custom_command(
+ TARGET empty
+ SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/input.h.in
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/input.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/input.h
+ OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/input.h
+ DEPENDS ${CMAKE_COMMAND}
+)
diff --git a/Tests/RunCMake/CMP0050/CMP0050-OLD-stderr.txt b/Tests/RunCMake/CMP0050/CMP0050-OLD-stderr.txt
new file mode 100644
index 0000000..3e7fa97
--- /dev/null
+++ b/Tests/RunCMake/CMP0050/CMP0050-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0050-OLD.cmake:2 \(cmake_policy\):
+ The OLD behavior for policy CMP0050 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0050/CMP0050-OLD.cmake b/Tests/RunCMake/CMP0050/CMP0050-OLD.cmake
new file mode 100644
index 0000000..efb37e5
--- /dev/null
+++ b/Tests/RunCMake/CMP0050/CMP0050-OLD.cmake
@@ -0,0 +1,13 @@
+
+cmake_policy(SET CMP0050 OLD)
+
+add_library(empty empty.cpp)
+add_custom_command(
+ TARGET empty
+ SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/input.h.in
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/input.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/input.h
+ OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/input.h
+ DEPENDS ${CMAKE_COMMAND}
+)
diff --git a/Tests/RunCMake/CMP0050/CMP0050-WARN-result.txt b/Tests/RunCMake/CMP0050/CMP0050-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0050/CMP0050-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0050/CMP0050-WARN-stderr.txt b/Tests/RunCMake/CMP0050/CMP0050-WARN-stderr.txt
new file mode 100644
index 0000000..c88d595
--- /dev/null
+++ b/Tests/RunCMake/CMP0050/CMP0050-WARN-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMP0050-WARN.cmake:3 \(add_custom_command\):
+ Policy CMP0050 is not set: Disallow add_custom_command SOURCE signatures.
+ Run "cmake --help-policy CMP0050" for policy details. Use the cmake_policy
+ command to set the policy and suppress this warning.
+
+ The SOURCE signatures of add_custom_command are no longer supported.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0050/CMP0050-WARN.cmake b/Tests/RunCMake/CMP0050/CMP0050-WARN.cmake
new file mode 100644
index 0000000..e57230e
--- /dev/null
+++ b/Tests/RunCMake/CMP0050/CMP0050-WARN.cmake
@@ -0,0 +1,11 @@
+
+add_library(empty empty.cpp)
+add_custom_command(
+ TARGET empty
+ SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/input.h.in
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/input.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/input.h
+ OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/input.h
+ DEPENDS ${CMAKE_COMMAND}
+)
diff --git a/Tests/RunCMake/CMP0050/CMakeLists.txt b/Tests/RunCMake/CMP0050/CMakeLists.txt
new file mode 100644
index 0000000..a06591c
--- /dev/null
+++ b/Tests/RunCMake/CMP0050/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0050/RunCMakeTest.cmake b/Tests/RunCMake/CMP0050/RunCMakeTest.cmake
new file mode 100644
index 0000000..b7de284
--- /dev/null
+++ b/Tests/RunCMake/CMP0050/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0050-OLD)
+run_cmake(CMP0050-NEW)
+run_cmake(CMP0050-WARN)
diff --git a/Tests/RunCMake/CMP0050/empty.cpp b/Tests/RunCMake/CMP0050/empty.cpp
new file mode 100644
index 0000000..bf7d5c9
--- /dev/null
+++ b/Tests/RunCMake/CMP0050/empty.cpp
@@ -0,0 +1,10 @@
+
+#include "input.h"
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0050/input.h.in b/Tests/RunCMake/CMP0050/input.h.in
new file mode 100644
index 0000000..d8c5d26
--- /dev/null
+++ b/Tests/RunCMake/CMP0050/input.h.in
@@ -0,0 +1,2 @@
+
+#define INPUT
diff --git a/Tests/RunCMake/CMP0051/CMP0051-NEW-result.txt b/Tests/RunCMake/CMP0051/CMP0051-NEW-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0051/CMP0051-NEW-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0051/CMP0051-NEW-stderr.txt b/Tests/RunCMake/CMP0051/CMP0051-NEW-stderr.txt
new file mode 100644
index 0000000..e5578ba
--- /dev/null
+++ b/Tests/RunCMake/CMP0051/CMP0051-NEW-stderr.txt
@@ -0,0 +1 @@
+^Sources: "empty.cpp;\$<TARGET_OBJECTS:objects>"$
diff --git a/Tests/RunCMake/CMP0051/CMP0051-NEW.cmake b/Tests/RunCMake/CMP0051/CMP0051-NEW.cmake
new file mode 100644
index 0000000..f304bf1
--- /dev/null
+++ b/Tests/RunCMake/CMP0051/CMP0051-NEW.cmake
@@ -0,0 +1,10 @@
+
+cmake_policy(SET CMP0051 NEW)
+
+add_library(objects OBJECT empty.cpp)
+
+add_library(empty empty.cpp $<TARGET_OBJECTS:objects>)
+
+get_target_property(srcs empty SOURCES)
+
+message("Sources: \"${srcs}\"")
diff --git a/Tests/RunCMake/CMP0051/CMP0051-OLD-stderr.txt b/Tests/RunCMake/CMP0051/CMP0051-OLD-stderr.txt
new file mode 100644
index 0000000..e1c44e5
--- /dev/null
+++ b/Tests/RunCMake/CMP0051/CMP0051-OLD-stderr.txt
@@ -0,0 +1,12 @@
+^CMake Deprecation Warning at CMP0051-OLD.cmake:2 \(cmake_policy\):
+ The OLD behavior for policy CMP0051 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+Sources: "empty.cpp"$
diff --git a/Tests/RunCMake/CMP0051/CMP0051-OLD.cmake b/Tests/RunCMake/CMP0051/CMP0051-OLD.cmake
new file mode 100644
index 0000000..0243e94
--- /dev/null
+++ b/Tests/RunCMake/CMP0051/CMP0051-OLD.cmake
@@ -0,0 +1,10 @@
+
+cmake_policy(SET CMP0051 OLD)
+
+add_library(objects OBJECT empty.cpp)
+
+add_library(empty empty.cpp $<TARGET_OBJECTS:objects>)
+
+get_target_property(srcs empty SOURCES)
+
+message("Sources: \"${srcs}\"")
diff --git a/Tests/RunCMake/CMP0051/CMP0051-WARN-Dir/CMakeLists.txt b/Tests/RunCMake/CMP0051/CMP0051-WARN-Dir/CMakeLists.txt
new file mode 100644
index 0000000..77cbad5
--- /dev/null
+++ b/Tests/RunCMake/CMP0051/CMP0051-WARN-Dir/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(empty2 ../empty.cpp $<TARGET_OBJECTS:objects>)
diff --git a/Tests/RunCMake/CMP0051/CMP0051-WARN-result.txt b/Tests/RunCMake/CMP0051/CMP0051-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0051/CMP0051-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0051/CMP0051-WARN-stderr.txt b/Tests/RunCMake/CMP0051/CMP0051-WARN-stderr.txt
new file mode 100644
index 0000000..78c6b6d
--- /dev/null
+++ b/Tests/RunCMake/CMP0051/CMP0051-WARN-stderr.txt
@@ -0,0 +1,31 @@
+CMake Warning \(dev\) at CMP0051-WARN.cmake:6 \(get_target_property\):
+ Policy CMP0051 is not set: List TARGET_OBJECTS in SOURCES target property.
+ Run "cmake --help-policy CMP0051" for policy details. Use the cmake_policy
+ command to set the policy and suppress this warning.
+
+ Target "empty" contains \$<TARGET_OBJECTS> generator expression in its
+ sources list. This content was not previously part of the SOURCES property
+ when that property was read at configure time. Code reading that property
+ needs to be adapted to ignore the generator expression using the
+ string\(GENEX_STRIP\) command.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+Sources: "empty.cpp"
+*
+CMake Warning \(dev\) at CMP0051-WARN.cmake:12 \(get_target_property\):
+ Policy CMP0051 is not set: List TARGET_OBJECTS in SOURCES target property.
+ Run "cmake --help-policy CMP0051" for policy details. Use the cmake_policy
+ command to set the policy and suppress this warning.
+
+ Target "empty2" contains \$<TARGET_OBJECTS> generator expression in its
+ sources list. This content was not previously part of the SOURCES property
+ when that property was read at configure time. Code reading that property
+ needs to be adapted to ignore the generator expression using the
+ string\(GENEX_STRIP\) command.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+Sources: "../empty.cpp"$
diff --git a/Tests/RunCMake/CMP0051/CMP0051-WARN.cmake b/Tests/RunCMake/CMP0051/CMP0051-WARN.cmake
new file mode 100644
index 0000000..744598f
--- /dev/null
+++ b/Tests/RunCMake/CMP0051/CMP0051-WARN.cmake
@@ -0,0 +1,14 @@
+
+add_library(objects OBJECT empty.cpp)
+
+add_library(empty empty.cpp $<TARGET_OBJECTS:objects>)
+
+get_target_property(srcs empty SOURCES)
+
+message("Sources: \"${srcs}\"")
+
+add_subdirectory(CMP0051-WARN-Dir)
+
+get_target_property(srcs empty2 SOURCES)
+
+message("Sources: \"${srcs}\"")
diff --git a/Tests/RunCMake/CMP0051/CMakeLists.txt b/Tests/RunCMake/CMP0051/CMakeLists.txt
new file mode 100644
index 0000000..3482e6b
--- /dev/null
+++ b/Tests/RunCMake/CMP0051/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.0)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0051/RunCMakeTest.cmake b/Tests/RunCMake/CMP0051/RunCMakeTest.cmake
new file mode 100644
index 0000000..621192d
--- /dev/null
+++ b/Tests/RunCMake/CMP0051/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0051-OLD)
+run_cmake(CMP0051-NEW)
+run_cmake(CMP0051-WARN)
diff --git a/Tests/RunCMake/CMP0051/empty.cpp b/Tests/RunCMake/CMP0051/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0051/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0053/CMP0053-NEW-stderr.txt b/Tests/RunCMake/CMP0053/CMP0053-NEW-stderr.txt
new file mode 100644
index 0000000..836b0ff
--- /dev/null
+++ b/Tests/RunCMake/CMP0053/CMP0053-NEW-stderr.txt
@@ -0,0 +1,2 @@
+^called
+--><--$
diff --git a/Tests/RunCMake/CMP0053/CMP0053-NEW.cmake b/Tests/RunCMake/CMP0053/CMP0053-NEW.cmake
new file mode 100644
index 0000000..6ffedc6
--- /dev/null
+++ b/Tests/RunCMake/CMP0053/CMP0053-NEW.cmake
@@ -0,0 +1,8 @@
+cmake_policy(SET CMP0053 NEW)
+
+function (watch_callback)
+ message("called")
+endfunction ()
+
+variable_watch(test watch_callback)
+message("-->${test}<--")
diff --git a/Tests/RunCMake/CMP0053/CMP0053-OLD-stderr.txt b/Tests/RunCMake/CMP0053/CMP0053-OLD-stderr.txt
new file mode 100644
index 0000000..2a0ddbaa
--- /dev/null
+++ b/Tests/RunCMake/CMP0053/CMP0053-OLD-stderr.txt
@@ -0,0 +1,13 @@
+^CMake Deprecation Warning at CMP0053-OLD.cmake:1 \(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.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+called
+--><--$
diff --git a/Tests/RunCMake/CMP0053/CMP0053-OLD.cmake b/Tests/RunCMake/CMP0053/CMP0053-OLD.cmake
new file mode 100644
index 0000000..41f5347
--- /dev/null
+++ b/Tests/RunCMake/CMP0053/CMP0053-OLD.cmake
@@ -0,0 +1,8 @@
+cmake_policy(SET CMP0053 OLD)
+
+function (watch_callback)
+ message("called")
+endfunction ()
+
+variable_watch(test watch_callback)
+message("-->${test}<--")
diff --git a/Tests/RunCMake/CMP0053/CMP0053-WARN-stderr.txt b/Tests/RunCMake/CMP0053/CMP0053-WARN-stderr.txt
new file mode 100644
index 0000000..836b0ff
--- /dev/null
+++ b/Tests/RunCMake/CMP0053/CMP0053-WARN-stderr.txt
@@ -0,0 +1,2 @@
+^called
+--><--$
diff --git a/Tests/RunCMake/CMP0053/CMP0053-WARN.cmake b/Tests/RunCMake/CMP0053/CMP0053-WARN.cmake
new file mode 100644
index 0000000..b010d13
--- /dev/null
+++ b/Tests/RunCMake/CMP0053/CMP0053-WARN.cmake
@@ -0,0 +1,6 @@
+function (watch_callback)
+ message("called")
+endfunction ()
+
+variable_watch(test watch_callback)
+message("-->${test}<--")
diff --git a/Tests/RunCMake/CMP0053/CMakeLists.txt b/Tests/RunCMake/CMP0053/CMakeLists.txt
new file mode 100644
index 0000000..3482e6b
--- /dev/null
+++ b/Tests/RunCMake/CMP0053/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.0)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0053/RunCMakeTest.cmake b/Tests/RunCMake/CMP0053/RunCMakeTest.cmake
new file mode 100644
index 0000000..6521ac0
--- /dev/null
+++ b/Tests/RunCMake/CMP0053/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0053-OLD)
+run_cmake(CMP0053-NEW)
+run_cmake(CMP0053-WARN)
diff --git a/Tests/RunCMake/CMP0054/CMP0054-NEW-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-NEW-stderr.txt
new file mode 100644
index 0000000..f5a8fbe
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-NEW-stderr.txt
@@ -0,0 +1 @@
+$^
diff --git a/Tests/RunCMake/CMP0054/CMP0054-NEW.cmake b/Tests/RunCMake/CMP0054/CMP0054-NEW.cmake
new file mode 100644
index 0000000..23a9124
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-NEW.cmake
@@ -0,0 +1,47 @@
+cmake_policy(SET CMP0054 NEW)
+
+set(FOO "BAR")
+set(BAZ "ZZZ")
+set(MYTRUE ON)
+set(MYNUMBER 3)
+set(MYVERSION 3.0)
+
+function(assert_unquoted PREFIX FIRST)
+ string(REPLACE ";" " " ARGN_SP "${ARGN}")
+ if(${PREFIX} ${FIRST} ${ARGN})
+ message(FATAL_ERROR "Assertion failed [${PREFIX} ${FIRST} ${ARGN_SP}]")
+ endif()
+endfunction()
+
+function(assert_quoted PREFIX FIRST)
+ string(REPLACE ";" " " ARGN_SP "${ARGN}")
+ if(${PREFIX} "${FIRST}" ${ARGN})
+ message(FATAL_ERROR "Assertion failed [${PREFIX} \"${FIRST}\" ${ARGN_SP}]")
+ endif()
+endfunction()
+
+function(assert FIRST)
+ assert_unquoted(NOT ${FIRST} ${ARGN})
+ assert_quoted("" ${FIRST} ${ARGN})
+endfunction()
+
+assert(MYTRUE)
+
+assert(FOO MATCHES "^BAR$")
+
+assert(MYNUMBER LESS 4)
+assert(MYNUMBER GREATER 2)
+assert(MYNUMBER EQUAL 3)
+
+assert(FOO STRLESS CCC)
+assert(BAZ STRGREATER CCC)
+assert(FOO STREQUAL BAR)
+
+assert_unquoted(NOT MYVERSION VERSION_LESS 3.1)
+assert_unquoted("" MYVERSION VERSION_LESS 2.9)
+
+assert_quoted(NOT MYVERSION VERSION_LESS 2.9)
+assert_quoted(NOT MYVERSION VERSION_LESS 3.1)
+
+assert(MYVERSION VERSION_GREATER 2.9)
+assert(MYVERSION VERSION_EQUAL 3.0)
diff --git a/Tests/RunCMake/CMP0054/CMP0054-OLD-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-OLD-stderr.txt
new file mode 100644
index 0000000..0500280
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0054-OLD.cmake:1 \(cmake_policy\):
+ The OLD behavior for policy CMP0054 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0054/CMP0054-OLD.cmake b/Tests/RunCMake/CMP0054/CMP0054-OLD.cmake
new file mode 100644
index 0000000..0c4cede
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-OLD.cmake
@@ -0,0 +1,47 @@
+cmake_policy(SET CMP0054 OLD)
+
+set(FOO "BAR")
+set(BAZ "ZZZ")
+set(MYTRUE ON)
+set(MYNUMBER 3)
+set(MYVERSION 3.0)
+
+function(assert_unquoted PREFIX FIRST)
+ string(REPLACE ";" " " ARGN_SP "${ARGN}")
+ if(${PREFIX} ${FIRST} ${ARGN})
+ message(FATAL_ERROR "Assertion failed [${PREFIX} ${FIRST} ${ARGN_SP}]")
+ endif()
+endfunction()
+
+function(assert_quoted PREFIX FIRST)
+ string(REPLACE ";" " " ARGN_SP "${ARGN}")
+ if(${PREFIX} "${FIRST}" ${ARGN})
+ message(FATAL_ERROR "Assertion failed [${PREFIX} \"${FIRST}\" ${ARGN_SP}]")
+ endif()
+endfunction()
+
+function(assert FIRST)
+ assert_unquoted(NOT ${FIRST} ${ARGN})
+ assert_quoted(NOT ${FIRST} ${ARGN})
+endfunction()
+
+assert(MYTRUE)
+
+assert(FOO MATCHES "^BAR$")
+
+assert(MYNUMBER LESS 4)
+assert(MYNUMBER GREATER 2)
+assert(MYNUMBER EQUAL 3)
+
+assert(FOO STRLESS CCC)
+assert(BAZ STRGREATER CCC)
+assert(FOO STREQUAL BAR)
+
+assert_unquoted(NOT MYVERSION VERSION_LESS 3.1)
+assert_unquoted("" MYVERSION VERSION_LESS 2.9)
+
+assert_quoted("" MYVERSION VERSION_LESS 2.9)
+assert_quoted(NOT MYVERSION VERSION_LESS 3.1)
+
+assert(MYVERSION VERSION_GREATER 2.9)
+assert(MYVERSION VERSION_EQUAL 3.0)
diff --git a/Tests/RunCMake/CMP0054/CMP0054-WARN-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-WARN-stderr.txt
new file mode 100644
index 0000000..3cfa5d2
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-WARN-stderr.txt
@@ -0,0 +1,23 @@
+CMake Warning \(dev\) at CMP0054-WARN.cmake:3 \(if\):
+ Policy CMP0054 is not set: Only interpret if\(\) arguments as variables or
+ keywords when unquoted. Run "cmake --help-policy CMP0054" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ Quoted variables like "FOO" will no longer be dereferenced when the policy
+ is set to NEW. Since the policy is not set the OLD behavior will be used.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
++
+CMake Warning \(dev\) at CMP0054-WARN.cmake:5 \(elseif\):
+ Policy CMP0054 is not set: Only interpret if\(\) arguments as variables or
+ keywords when unquoted. Run "cmake --help-policy CMP0054" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ Quoted variables like "FOO" will no longer be dereferenced when the policy
+ is set to NEW. Since the policy is not set the OLD behavior will be used.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0054/CMP0054-WARN.cmake b/Tests/RunCMake/CMP0054/CMP0054-WARN.cmake
new file mode 100644
index 0000000..a608929
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-WARN.cmake
@@ -0,0 +1,7 @@
+set(FOO "BAR")
+
+if(NOT "FOO" STREQUAL "BAR")
+ message(FATAL_ERROR "The given literals should match")
+elseif("FOO" STREQUAL "BING")
+ message(FATAL_ERROR "The given literals should not match")
+endif()
diff --git a/Tests/RunCMake/CMP0054/CMP0054-duplicate-warnings-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-duplicate-warnings-stderr.txt
new file mode 100644
index 0000000..485db52
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-duplicate-warnings-stderr.txt
@@ -0,0 +1,24 @@
+CMake Warning \(dev\) at CMP0054-duplicate-warnings.cmake:4 \(if\):
+ Policy CMP0054 is not set: Only interpret if\(\) arguments as variables or
+ keywords when unquoted. Run "cmake --help-policy CMP0054" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ Quoted variables like "FOO" will no longer be dereferenced when the policy
+ is set to NEW. Since the policy is not set the OLD behavior will be used.
+Call Stack \(most recent call first\):
+ CMP0054-duplicate-warnings.cmake:8 \(generate_warning\)
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\) at CMP0054-duplicate-warnings.cmake:11 \(if\):
+ Policy CMP0054 is not set: Only interpret if\(\) arguments as variables or
+ keywords when unquoted. Run "cmake --help-policy CMP0054" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ Quoted variables like "FOO" will no longer be dereferenced when the policy
+ is set to NEW. Since the policy is not set the OLD behavior will be used.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0054/CMP0054-duplicate-warnings.cmake b/Tests/RunCMake/CMP0054/CMP0054-duplicate-warnings.cmake
new file mode 100644
index 0000000..04fbe14
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-duplicate-warnings.cmake
@@ -0,0 +1,12 @@
+set(FOO "BAR")
+
+function(generate_warning)
+ if("FOO" STREQUAL "BAR")
+ endif()
+endfunction()
+
+generate_warning()
+generate_warning()
+
+if("FOO" STREQUAL "BAR")
+endif()
diff --git a/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW-result.txt b/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW-stderr.txt
new file mode 100644
index 0000000..f444684
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0054-keywords-NEW.cmake:23 \(if\):
+ if given arguments:
+
+ "NOT" "1"
+
+ Unknown arguments specified
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW.cmake b/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW.cmake
new file mode 100644
index 0000000..b957658
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-keywords-NEW.cmake
@@ -0,0 +1,25 @@
+cmake_policy(SET CMP0054 NEW)
+
+function(assert KEYWORD)
+ if("${KEYWORD}" STREQUAL "${KEYWORD}")
+ else()
+ message(FATAL_ERROR
+ "Assertion failed [\"${KEYWORD}\" STREQUAL \"${KEYWORD}\"]")
+ endif()
+endfunction()
+
+assert("NOT")
+assert("COMMAND")
+assert("POLICY")
+assert("TARGET")
+assert("EXISTS")
+assert("IS_DIRECTORY")
+assert("IS_SYMLINK")
+assert("IS_ABSOLUTE")
+assert("DEFINED")
+assert("(")
+assert(")")
+
+if("NOT" 1)
+ message(FATAL_ERROR "[\"NOT\" 1] evaluated true")
+endif()
diff --git a/Tests/RunCMake/CMP0054/CMP0054-keywords-OLD-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-keywords-OLD-stderr.txt
new file mode 100644
index 0000000..60303cd
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-keywords-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0054-keywords-OLD.cmake:1 \(cmake_policy\):
+ The OLD behavior for policy CMP0054 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0054/CMP0054-keywords-OLD.cmake b/Tests/RunCMake/CMP0054/CMP0054-keywords-OLD.cmake
new file mode 100644
index 0000000..a2a7f51
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-keywords-OLD.cmake
@@ -0,0 +1,9 @@
+cmake_policy(SET CMP0054 OLD)
+
+if(NOT 1)
+ message(FATAL_ERROR "[NOT 1] evaluated true")
+endif()
+
+if("NOT" 1)
+ message(FATAL_ERROR "[\"NOT\" 1] evaluated true")
+endif()
diff --git a/Tests/RunCMake/CMP0054/CMP0054-keywords-WARN-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-keywords-WARN-stderr.txt
new file mode 100644
index 0000000..5a8c263
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-keywords-WARN-stderr.txt
@@ -0,0 +1,25 @@
+CMake Warning \(dev\) at CMP0054-keywords-WARN.cmake:1 \(if\):
+ Policy CMP0054 is not set: Only interpret if\(\) arguments as variables or
+ keywords when unquoted. Run "cmake --help-policy CMP0054" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ Quoted keywords like "NOT" will no longer be interpreted as keywords when
+ the policy is set to NEW. Since the policy is not set the OLD behavior
+ will be used.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
++
+CMake Warning \(dev\) at CMP0054-keywords-WARN.cmake:3 \(elseif\):
+ Policy CMP0054 is not set: Only interpret if\(\) arguments as variables or
+ keywords when unquoted. Run "cmake --help-policy CMP0054" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ Quoted keywords like "DEFINED" will no longer be interpreted as keywords
+ when the policy is set to NEW. Since the policy is not set the OLD
+ behavior will be used.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0054/CMP0054-keywords-WARN.cmake b/Tests/RunCMake/CMP0054/CMP0054-keywords-WARN.cmake
new file mode 100644
index 0000000..118ab3d
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-keywords-WARN.cmake
@@ -0,0 +1,5 @@
+if("NOT" 1)
+ message(FATAL_ERROR "[\"NOT\" 1] evaluated true")
+elseif("DEFINED" NotDefined)
+ message(FATAL_ERROR "[\"DEFINED\" NotDefined] evaluated true")
+endif()
diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-command-scope-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-policy-command-scope-stderr.txt
new file mode 100644
index 0000000..1b35472
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-policy-command-scope-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0054-policy-command-scope.cmake:25 \(cmake_policy\):
+ The OLD behavior for policy CMP0054 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-command-scope.cmake b/Tests/RunCMake/CMP0054/CMP0054-policy-command-scope.cmake
new file mode 100644
index 0000000..b6b243c
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-policy-command-scope.cmake
@@ -0,0 +1,53 @@
+set(FOO BAR)
+
+cmake_policy(SET CMP0054 NEW)
+
+function(function_defined_new_called_old)
+ if(NOT FOO STREQUAL BAR)
+ message(FATAL_ERROR "The variable should match the string")
+ endif()
+
+ if("FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The strings should not match")
+ endif()
+endfunction()
+
+macro(macro_defined_new_called_old)
+ if(NOT FOO STREQUAL BAR)
+ message(FATAL_ERROR "The variable should match the string")
+ endif()
+
+ if("FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The strings should not match")
+ endif()
+endmacro()
+
+cmake_policy(SET CMP0054 OLD)
+
+function_defined_new_called_old()
+macro_defined_new_called_old()
+
+function(function_defined_old_called_new)
+ if(NOT FOO STREQUAL BAR)
+ message(FATAL_ERROR "The variable should match the string")
+ endif()
+
+ if(NOT "FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The quoted variable should match the string")
+ endif()
+endfunction()
+
+macro(macro_defined_old_called_new)
+ if(NOT FOO STREQUAL BAR)
+ message(FATAL_ERROR "The variable should match the string")
+ endif()
+
+ if(NOT "FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The quoted variable should match the string")
+ endif()
+endmacro()
+
+cmake_policy(SET CMP0054 NEW)
+
+function_defined_old_called_new()
+macro_defined_old_called_new()
diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-foreach-scope-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-policy-foreach-scope-stderr.txt
new file mode 100644
index 0000000..4eac90e
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-policy-foreach-scope-stderr.txt
@@ -0,0 +1,54 @@
+^CMake Deprecation Warning at CMP0054-policy-foreach-scope.cmake:14 \(cmake_policy\):
+ The OLD behavior for policy CMP0054 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Deprecation Warning at CMP0054-policy-foreach-scope.cmake:14 \(cmake_policy\):
+ The OLD behavior for policy CMP0054 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Deprecation Warning at CMP0054-policy-foreach-scope.cmake:27 \(cmake_policy\):
+ The OLD behavior for policy CMP0054 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Deprecation Warning at CMP0054-policy-foreach-scope.cmake:48 \(cmake_policy\):
+ The OLD behavior for policy CMP0054 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Deprecation Warning at CMP0054-policy-foreach-scope.cmake:48 \(cmake_policy\):
+ The OLD behavior for policy CMP0054 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-foreach-scope.cmake b/Tests/RunCMake/CMP0054/CMP0054-policy-foreach-scope.cmake
new file mode 100644
index 0000000..87c968a
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-policy-foreach-scope.cmake
@@ -0,0 +1,49 @@
+set(FOO BAR)
+
+cmake_policy(SET CMP0054 NEW)
+
+foreach(loop_var arg1 arg2)
+ if(NOT FOO STREQUAL BAR)
+ message(FATAL_ERROR "The variable should match the string")
+ endif()
+
+ if("FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The strings should not match")
+ endif()
+
+ cmake_policy(SET CMP0054 OLD)
+
+ if(NOT FOO STREQUAL BAR)
+ message(FATAL_ERROR "The variable should match the string")
+ endif()
+
+ if(NOT "FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The quoted variable should match the string")
+ endif()
+
+ cmake_policy(SET CMP0054 NEW)
+endforeach()
+
+cmake_policy(SET CMP0054 OLD)
+
+foreach(loop_var arg1 arg2)
+ if(NOT FOO STREQUAL BAR)
+ message(FATAL_ERROR "The variable should match the string")
+ endif()
+
+ if(NOT "FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The quoted variable should match the string")
+ endif()
+
+ cmake_policy(SET CMP0054 NEW)
+
+ if(NOT FOO STREQUAL BAR)
+ message(FATAL_ERROR "The variable should match the string")
+ endif()
+
+ if("FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The strings should not match")
+ endif()
+
+ cmake_policy(SET CMP0054 OLD)
+endforeach()
diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-nested-if-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-policy-nested-if-stderr.txt
new file mode 100644
index 0000000..a2dd62e
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-policy-nested-if-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0054-policy-nested-if.cmake:23 \(cmake_policy\):
+ The OLD behavior for policy CMP0054 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-nested-if.cmake b/Tests/RunCMake/CMP0054/CMP0054-policy-nested-if.cmake
new file mode 100644
index 0000000..dd7434d
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-policy-nested-if.cmake
@@ -0,0 +1,41 @@
+set(FOO BAR)
+
+cmake_policy(SET CMP0054 NEW)
+
+if("FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The strings should not match")
+
+ if("FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The strings should not match")
+ endif()
+
+ cmake_policy(SET CMP0054 OLD)
+
+ if(NOT "FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The quoted variable should match the string")
+ endif()
+endif()
+
+if("FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The strings should not match")
+endif()
+
+cmake_policy(SET CMP0054 OLD)
+
+if(NOT "FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The quoted variable should match the string")
+
+ if(NOT "FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The quoted variable should match the string")
+ endif()
+
+ cmake_policy(SET CMP0054 NEW)
+
+ if("FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The strings should not match")
+ endif()
+endif()
+
+if(NOT "FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The quoted variable should match the string")
+endif()
diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-while-scope-stderr.txt b/Tests/RunCMake/CMP0054/CMP0054-policy-while-scope-stderr.txt
new file mode 100644
index 0000000..718904d
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-policy-while-scope-stderr.txt
@@ -0,0 +1,54 @@
+^CMake Deprecation Warning at CMP0054-policy-while-scope.cmake:16 \(cmake_policy\):
+ The OLD behavior for policy CMP0054 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Deprecation Warning at CMP0054-policy-while-scope.cmake:16 \(cmake_policy\):
+ The OLD behavior for policy CMP0054 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Deprecation Warning at CMP0054-policy-while-scope.cmake:37 \(cmake_policy\):
+ The OLD behavior for policy CMP0054 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Deprecation Warning at CMP0054-policy-while-scope.cmake:58 \(cmake_policy\):
+ The OLD behavior for policy CMP0054 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Deprecation Warning at CMP0054-policy-while-scope.cmake:58 \(cmake_policy\):
+ The OLD behavior for policy CMP0054 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0054/CMP0054-policy-while-scope.cmake b/Tests/RunCMake/CMP0054/CMP0054-policy-while-scope.cmake
new file mode 100644
index 0000000..7fb836e
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMP0054-policy-while-scope.cmake
@@ -0,0 +1,65 @@
+set(FOO BAR)
+
+set(LOOP_VAR "")
+
+cmake_policy(SET CMP0054 NEW)
+
+while(NOT LOOP_VAR STREQUAL "xx")
+ if(NOT FOO STREQUAL BAR)
+ message(FATAL_ERROR "The variable should match the string")
+ endif()
+
+ if("FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The strings should not match")
+ endif()
+
+ cmake_policy(SET CMP0054 OLD)
+
+ if(NOT FOO STREQUAL BAR)
+ message(FATAL_ERROR "The variable should match the string")
+ endif()
+
+ if(NOT "FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The quoted variable should match the string")
+ endif()
+
+ cmake_policy(SET CMP0054 NEW)
+
+ string(APPEND LOOP_VAR "x")
+endwhile()
+
+while("FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The strings should not match")
+endwhile()
+
+set(LOOP_VAR "")
+
+cmake_policy(SET CMP0054 OLD)
+
+while(NOT LOOP_VAR STREQUAL "xx")
+ if(NOT FOO STREQUAL BAR)
+ message(FATAL_ERROR "The variable should match the string")
+ endif()
+
+ if(NOT "FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The quoted variable should match the string")
+ endif()
+
+ cmake_policy(SET CMP0054 NEW)
+
+ if(NOT FOO STREQUAL BAR)
+ message(FATAL_ERROR "The variable should match the string")
+ endif()
+
+ if("FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The strings should not match")
+ endif()
+
+ cmake_policy(SET CMP0054 OLD)
+
+ string(APPEND LOOP_VAR "x")
+endwhile()
+
+if(NOT "FOO" STREQUAL BAR)
+ message(FATAL_ERROR "The quoted variable should match the string")
+endif()
diff --git a/Tests/RunCMake/CMP0054/CMakeLists.txt b/Tests/RunCMake/CMP0054/CMakeLists.txt
new file mode 100644
index 0000000..2897109
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.0)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0054/RunCMakeTest.cmake b/Tests/RunCMake/CMP0054/RunCMakeTest.cmake
new file mode 100644
index 0000000..2f2fb76
--- /dev/null
+++ b/Tests/RunCMake/CMP0054/RunCMakeTest.cmake
@@ -0,0 +1,13 @@
+include(RunCMake)
+
+run_cmake(CMP0054-OLD)
+run_cmake(CMP0054-NEW)
+run_cmake(CMP0054-WARN)
+run_cmake(CMP0054-keywords-NEW)
+run_cmake(CMP0054-keywords-OLD)
+run_cmake(CMP0054-keywords-WARN)
+run_cmake(CMP0054-duplicate-warnings)
+run_cmake(CMP0054-policy-command-scope)
+run_cmake(CMP0054-policy-foreach-scope)
+run_cmake(CMP0054-policy-while-scope)
+run_cmake(CMP0054-policy-nested-if)
diff --git a/Tests/RunCMake/CMP0055/CMP0055-NEW-Out-of-Scope-result.txt b/Tests/RunCMake/CMP0055/CMP0055-NEW-Out-of-Scope-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-NEW-Out-of-Scope-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0055/CMP0055-NEW-Out-of-Scope-stderr.txt b/Tests/RunCMake/CMP0055/CMP0055-NEW-Out-of-Scope-stderr.txt
new file mode 100644
index 0000000..27e8140
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-NEW-Out-of-Scope-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at CMP0055-NEW-Out-of-Scope.cmake:4 \(break\):
+ A BREAK command was found outside of a proper FOREACH or WHILE loop scope.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0055/CMP0055-NEW-Out-of-Scope.cmake b/Tests/RunCMake/CMP0055/CMP0055-NEW-Out-of-Scope.cmake
new file mode 100644
index 0000000..53ac214
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-NEW-Out-of-Scope.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0055 NEW)
+
+break()
diff --git a/Tests/RunCMake/CMP0055/CMP0055-NEW-Reject-Arguments-result.txt b/Tests/RunCMake/CMP0055/CMP0055-NEW-Reject-Arguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-NEW-Reject-Arguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0055/CMP0055-NEW-Reject-Arguments-stderr.txt b/Tests/RunCMake/CMP0055/CMP0055-NEW-Reject-Arguments-stderr.txt
new file mode 100644
index 0000000..32947af
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-NEW-Reject-Arguments-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at CMP0055-NEW-Reject-Arguments.cmake:5 \(break\):
+ The BREAK command does not accept any arguments.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0055/CMP0055-NEW-Reject-Arguments.cmake b/Tests/RunCMake/CMP0055/CMP0055-NEW-Reject-Arguments.cmake
new file mode 100644
index 0000000..52eaa6a
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-NEW-Reject-Arguments.cmake
@@ -0,0 +1,6 @@
+
+cmake_policy(SET CMP0055 NEW)
+
+foreach(i RANGE 1 2)
+ break(1)
+endforeach() \ No newline at end of file
diff --git a/Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope-result.txt b/Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope-stderr.txt b/Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope-stderr.txt
new file mode 100644
index 0000000..d0a156c
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0055-OLD-Out-of-Scope.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0055 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope.cmake b/Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope.cmake
new file mode 100644
index 0000000..57195c2
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0055 OLD)
+
+break()
diff --git a/Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments-result.txt b/Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments-stderr.txt b/Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments-stderr.txt
new file mode 100644
index 0000000..937b352
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0055-OLD-Reject-Arguments.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0055 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments.cmake b/Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments.cmake
new file mode 100644
index 0000000..d8fdddf
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments.cmake
@@ -0,0 +1,6 @@
+
+cmake_policy(SET CMP0055 OLD)
+
+foreach(i RANGE 1 2)
+ break(1)
+endforeach() \ No newline at end of file
diff --git a/Tests/RunCMake/CMP0055/CMP0055-WARN-Out-of-Scope-result.txt b/Tests/RunCMake/CMP0055/CMP0055-WARN-Out-of-Scope-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-WARN-Out-of-Scope-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0055/CMP0055-WARN-Out-of-Scope-stderr.txt b/Tests/RunCMake/CMP0055/CMP0055-WARN-Out-of-Scope-stderr.txt
new file mode 100644
index 0000000..ad850ac
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-WARN-Out-of-Scope-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMP0055-WARN-Out-of-Scope.cmake:2 \(break\):
+ Policy CMP0055 is not set: Strict checking for break\(\) command. Run "cmake
+ --help-policy CMP0055" for policy details. Use the cmake_policy command to
+ set the policy and suppress this warning.
+
+ A BREAK command was found outside of a proper FOREACH or WHILE loop scope.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0055/CMP0055-WARN-Out-of-Scope.cmake b/Tests/RunCMake/CMP0055/CMP0055-WARN-Out-of-Scope.cmake
new file mode 100644
index 0000000..373a95a
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-WARN-Out-of-Scope.cmake
@@ -0,0 +1,2 @@
+
+break()
diff --git a/Tests/RunCMake/CMP0055/CMP0055-WARN-Reject-Arguments-result.txt b/Tests/RunCMake/CMP0055/CMP0055-WARN-Reject-Arguments-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-WARN-Reject-Arguments-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0055/CMP0055-WARN-Reject-Arguments-stderr.txt b/Tests/RunCMake/CMP0055/CMP0055-WARN-Reject-Arguments-stderr.txt
new file mode 100644
index 0000000..3cc686d
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-WARN-Reject-Arguments-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMP0055-WARN-Reject-Arguments.cmake:3 \(break\):
+ Policy CMP0055 is not set: Strict checking for break\(\) command. Run "cmake
+ --help-policy CMP0055" for policy details. Use the cmake_policy command to
+ set the policy and suppress this warning.
+
+ The BREAK command does not accept any arguments.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0055/CMP0055-WARN-Reject-Arguments.cmake b/Tests/RunCMake/CMP0055/CMP0055-WARN-Reject-Arguments.cmake
new file mode 100644
index 0000000..ec6b90f
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMP0055-WARN-Reject-Arguments.cmake
@@ -0,0 +1,4 @@
+
+foreach(i RANGE 1 2)
+ break(1)
+endforeach()
diff --git a/Tests/RunCMake/CMP0055/CMakeLists.txt b/Tests/RunCMake/CMP0055/CMakeLists.txt
new file mode 100644
index 0000000..ef2163c
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.1)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0055/RunCMakeTest.cmake b/Tests/RunCMake/CMP0055/RunCMakeTest.cmake
new file mode 100644
index 0000000..efcfcab
--- /dev/null
+++ b/Tests/RunCMake/CMP0055/RunCMakeTest.cmake
@@ -0,0 +1,9 @@
+include(RunCMake)
+
+run_cmake(CMP0055-OLD-Out-of-Scope)
+run_cmake(CMP0055-NEW-Out-of-Scope)
+run_cmake(CMP0055-WARN-Out-of-Scope)
+
+run_cmake(CMP0055-OLD-Reject-Arguments)
+run_cmake(CMP0055-NEW-Reject-Arguments)
+run_cmake(CMP0055-WARN-Reject-Arguments)
diff --git a/Tests/RunCMake/CMP0057/CMP0057-NEW.cmake b/Tests/RunCMake/CMP0057/CMP0057-NEW.cmake
new file mode 100644
index 0000000..ebd7ba5
--- /dev/null
+++ b/Tests/RunCMake/CMP0057/CMP0057-NEW.cmake
@@ -0,0 +1,31 @@
+cmake_policy(SET CMP0057 NEW)
+
+set(MY_NON_EXISTENT_LIST)
+
+set(MY_EMPTY_LIST "")
+
+set(MY_LIST foo bar)
+
+if(NOT "foo" IN_LIST MY_LIST)
+ message(FATAL_ERROR "expected item 'foo' not found in list MY_LIST")
+endif()
+
+if("baz" IN_LIST MY_LIST)
+ message(FATAL_ERROR "unexpected item 'baz' found in list MY_LIST")
+endif()
+
+if("foo" IN_LIST MY_NON_EXISTENT_LIST)
+ message(FATAL_ERROR
+ "unexpected item 'baz' found in non existent list MY_NON_EXISTENT_LIST")
+endif()
+
+if("foo" IN_LIST MY_EMPTY_LIST)
+ message(FATAL_ERROR
+ "unexpected item 'baz' found in empty list MY_EMPTY_LIST")
+endif()
+
+set(VAR "foo")
+
+if(NOT VAR IN_LIST MY_LIST)
+ message(FATAL_ERROR "expected item VAR not found in list MY_LIST")
+endif()
diff --git a/Tests/RunCMake/CMP0057/CMP0057-OLD-result.txt b/Tests/RunCMake/CMP0057/CMP0057-OLD-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0057/CMP0057-OLD-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0057/CMP0057-OLD-stderr.txt b/Tests/RunCMake/CMP0057/CMP0057-OLD-stderr.txt
new file mode 100644
index 0000000..f3fad8d
--- /dev/null
+++ b/Tests/RunCMake/CMP0057/CMP0057-OLD-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0057-OLD.cmake:5 \(if\):
+ if given arguments:
+
+ "foo" "IN_LIST" "MY_LIST"
+
+ Unknown arguments specified
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0057/CMP0057-OLD.cmake b/Tests/RunCMake/CMP0057/CMP0057-OLD.cmake
new file mode 100644
index 0000000..cf9ec89
--- /dev/null
+++ b/Tests/RunCMake/CMP0057/CMP0057-OLD.cmake
@@ -0,0 +1,7 @@
+cmake_policy(SET CMP0057 OLD)
+
+set(MY_LIST foo bar)
+
+if("foo" IN_LIST MY_LIST)
+ message("foo is in MY_LIST")
+endif()
diff --git a/Tests/RunCMake/CMP0057/CMP0057-WARN-result.txt b/Tests/RunCMake/CMP0057/CMP0057-WARN-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0057/CMP0057-WARN-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0057/CMP0057-WARN-stderr.txt b/Tests/RunCMake/CMP0057/CMP0057-WARN-stderr.txt
new file mode 100644
index 0000000..b1c9b63
--- /dev/null
+++ b/Tests/RunCMake/CMP0057/CMP0057-WARN-stderr.txt
@@ -0,0 +1,19 @@
+CMake Warning \(dev\) at CMP0057-WARN.cmake:3 \(if\):
+ Policy CMP0057 is not set: Support new IN_LIST if\(\) operator. Run "cmake
+ --help-policy CMP0057" for policy details. Use the cmake_policy command to
+ set the policy and suppress this warning.
+
+ IN_LIST will be interpreted as an operator when the policy is set to NEW.
+ Since the policy is not set the OLD behavior will be used.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+CMake Error at CMP0057-WARN.cmake:3 \(if\):
+ if given arguments:
+
+ "foo" "IN_LIST" "MY_LIST"
+
+ Unknown arguments specified
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CMP0057/CMP0057-WARN.cmake b/Tests/RunCMake/CMP0057/CMP0057-WARN.cmake
new file mode 100644
index 0000000..45f53a5
--- /dev/null
+++ b/Tests/RunCMake/CMP0057/CMP0057-WARN.cmake
@@ -0,0 +1,5 @@
+set(MY_LIST foo bar)
+
+if("foo" IN_LIST MY_LIST)
+ message("foo is in MY_LIST")
+endif()
diff --git a/Tests/RunCMake/CMP0057/CMakeLists.txt b/Tests/RunCMake/CMP0057/CMakeLists.txt
new file mode 100644
index 0000000..18dfd26
--- /dev/null
+++ b/Tests/RunCMake/CMP0057/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.2)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0057/RunCMakeTest.cmake b/Tests/RunCMake/CMP0057/RunCMakeTest.cmake
new file mode 100644
index 0000000..719e054
--- /dev/null
+++ b/Tests/RunCMake/CMP0057/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0057-OLD)
+run_cmake(CMP0057-WARN)
+run_cmake(CMP0057-NEW)
diff --git a/Tests/RunCMake/CMP0059/CMP0059-NEW-result.txt b/Tests/RunCMake/CMP0059/CMP0059-NEW-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0059/CMP0059-NEW-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0059/CMP0059-NEW-stderr.txt b/Tests/RunCMake/CMP0059/CMP0059-NEW-stderr.txt
new file mode 100644
index 0000000..76992d8
--- /dev/null
+++ b/Tests/RunCMake/CMP0059/CMP0059-NEW-stderr.txt
@@ -0,0 +1,2 @@
+DEFS:
+CUSTOM CONTENT:CUSTOM_CONTENT
diff --git a/Tests/RunCMake/CMP0059/CMP0059-NEW.cmake b/Tests/RunCMake/CMP0059/CMP0059-NEW.cmake
new file mode 100644
index 0000000..f7b9303
--- /dev/null
+++ b/Tests/RunCMake/CMP0059/CMP0059-NEW.cmake
@@ -0,0 +1,17 @@
+
+cmake_policy(SET CMP0059 NEW)
+
+add_definitions(-DSOME_DEF)
+
+get_property(defs DIRECTORY .
+ PROPERTY DEFINITIONS
+)
+message("DEFS:${defs}")
+
+set_property(DIRECTORY .
+ PROPERTY DEFINITIONS CUSTOM_CONTENT
+)
+get_property(content DIRECTORY .
+ PROPERTY DEFINITIONS
+)
+message("CUSTOM CONTENT:${content}")
diff --git a/Tests/RunCMake/CMP0059/CMP0059-OLD-result.txt b/Tests/RunCMake/CMP0059/CMP0059-OLD-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0059/CMP0059-OLD-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0059/CMP0059-OLD-stderr.txt b/Tests/RunCMake/CMP0059/CMP0059-OLD-stderr.txt
new file mode 100644
index 0000000..e35e8c5
--- /dev/null
+++ b/Tests/RunCMake/CMP0059/CMP0059-OLD-stderr.txt
@@ -0,0 +1,2 @@
+DEFS: -DSOME_DEF
+CUSTOM CONTENT: -DSOME_DEF
diff --git a/Tests/RunCMake/CMP0059/CMP0059-OLD.cmake b/Tests/RunCMake/CMP0059/CMP0059-OLD.cmake
new file mode 100644
index 0000000..2555774
--- /dev/null
+++ b/Tests/RunCMake/CMP0059/CMP0059-OLD.cmake
@@ -0,0 +1,17 @@
+
+cmake_policy(SET CMP0059 OLD)
+
+add_definitions(-DSOME_DEF)
+
+get_property(defs DIRECTORY .
+ PROPERTY DEFINITIONS
+)
+message("DEFS:${defs}")
+
+set_property(DIRECTORY .
+ PROPERTY DEFINITIONS CUSTOM_CONTENT
+)
+get_property(content DIRECTORY .
+ PROPERTY DEFINITIONS
+)
+message("CUSTOM CONTENT:${content}")
diff --git a/Tests/RunCMake/CMP0059/CMP0059-WARN-result.txt b/Tests/RunCMake/CMP0059/CMP0059-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0059/CMP0059-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0059/CMP0059-WARN-stderr.txt b/Tests/RunCMake/CMP0059/CMP0059-WARN-stderr.txt
new file mode 100644
index 0000000..06c7be3
--- /dev/null
+++ b/Tests/RunCMake/CMP0059/CMP0059-WARN-stderr.txt
@@ -0,0 +1,18 @@
+CMake Warning \(dev\) at CMP0059-WARN.cmake:6 \(get_property\):
+ Policy CMP0059 is not set: Do not treat DEFINITIONS as a built-in directory
+ property. Run "cmake --help-policy CMP0059" for policy details. Use the
+ cmake_policy command to set the policy and suppress this warning.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+DEFS: -DSOME_DEF
+CMake Warning \(dev\) at CMP0059-WARN.cmake:14 \(get_property\):
+ Policy CMP0059 is not set: Do not treat DEFINITIONS as a built-in directory
+ property. Run "cmake --help-policy CMP0059" for policy details. Use the
+ cmake_policy command to set the policy and suppress this warning.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+CUSTOM CONTENT: -DSOME_DEF
diff --git a/Tests/RunCMake/CMP0059/CMP0059-WARN.cmake b/Tests/RunCMake/CMP0059/CMP0059-WARN.cmake
new file mode 100644
index 0000000..9d0b49c
--- /dev/null
+++ b/Tests/RunCMake/CMP0059/CMP0059-WARN.cmake
@@ -0,0 +1,17 @@
+
+
+
+add_definitions(-DSOME_DEF)
+
+get_property(defs DIRECTORY .
+ PROPERTY DEFINITIONS
+)
+message("DEFS:${defs}")
+
+set_property(DIRECTORY .
+ PROPERTY DEFINITIONS CUSTOM_CONTENT
+)
+get_property(content DIRECTORY .
+ PROPERTY DEFINITIONS
+)
+message("CUSTOM CONTENT:${content}")
diff --git a/Tests/RunCMake/CMP0059/CMakeLists.txt b/Tests/RunCMake/CMP0059/CMakeLists.txt
new file mode 100644
index 0000000..ef2163c
--- /dev/null
+++ b/Tests/RunCMake/CMP0059/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.1)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0059/RunCMakeTest.cmake b/Tests/RunCMake/CMP0059/RunCMakeTest.cmake
new file mode 100644
index 0000000..9b57579
--- /dev/null
+++ b/Tests/RunCMake/CMP0059/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0059-OLD)
+run_cmake(CMP0059-NEW)
+run_cmake(CMP0059-WARN)
diff --git a/Tests/RunCMake/CMP0060/CMP0060-Common.cmake b/Tests/RunCMake/CMP0060/CMP0060-Common.cmake
new file mode 100644
index 0000000..06955ee
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/CMP0060-Common.cmake
@@ -0,0 +1,36 @@
+# Always build in a predictable configuration. For multi-config
+# generators we depend on RunCMakeTest.cmake to do this for us.
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(NOT _isMultiConfig)
+ set(CMAKE_BUILD_TYPE Debug)
+endif()
+
+# Convince CMake that it can instruct the linker to search for the
+# library of the proper linkage type, but do not really pass flags.
+set(CMAKE_EXE_LINK_STATIC_C_FLAGS " ")
+set(CMAKE_EXE_LINK_DYNAMIC_C_FLAGS " ")
+
+# Make a link line asking for the linker to search for the library
+# look like a missing object file so we will get predictable content
+# in the error message. This also ensures that cases expected to use
+# the full path can be verified by confirming that they link.
+set(CMAKE_LINK_LIBRARY_FLAG LINKFLAG_)
+set(CMAKE_LINK_LIBRARY_SUFFIX _LINKSUFFIX${CMAKE_C_OUTPUT_EXTENSION})
+
+# Convince CMake that our library is in an implicit linker search directory.
+list(APPEND CMAKE_C_IMPLICIT_LINK_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}/lib)
+
+# Create a simple library file. Place it in our library directory.
+add_library(CMP0060 STATIC cmp0060.c)
+set_property(TARGET CMP0060 PROPERTY
+ ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/lib)
+
+# Add a target to link the library file by full path.
+add_executable(main1 main.c)
+target_link_libraries(main1 $<TARGET_FILE:CMP0060>)
+add_dependencies(main1 CMP0060)
+
+# Add a second target to verify the warning only appears once.
+add_executable(main2 main.c)
+target_link_libraries(main2 $<TARGET_FILE:CMP0060>)
+add_dependencies(main2 CMP0060)
diff --git a/Tests/RunCMake/CMP0060/CMP0060-NEW.cmake b/Tests/RunCMake/CMP0060/CMP0060-NEW.cmake
new file mode 100644
index 0000000..0414e4b
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/CMP0060-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0060 NEW)
+include(CMP0060-Common.cmake)
diff --git a/Tests/RunCMake/CMP0060/CMP0060-OLD-Build-result.txt b/Tests/RunCMake/CMP0060/CMP0060-OLD-Build-result.txt
new file mode 100644
index 0000000..d197c91
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/CMP0060-OLD-Build-result.txt
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/CMP0060/CMP0060-OLD-Build-stdout.txt b/Tests/RunCMake/CMP0060/CMP0060-OLD-Build-stdout.txt
new file mode 100644
index 0000000..240764c
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/CMP0060-OLD-Build-stdout.txt
@@ -0,0 +1 @@
+LINKFLAG_CMP0060_LINKSUFFIX
diff --git a/Tests/RunCMake/CMP0060/CMP0060-OLD-stderr.txt b/Tests/RunCMake/CMP0060/CMP0060-OLD-stderr.txt
new file mode 100644
index 0000000..4658747
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/CMP0060-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0060-OLD.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0060 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0060/CMP0060-OLD.cmake b/Tests/RunCMake/CMP0060/CMP0060-OLD.cmake
new file mode 100644
index 0000000..a9cffef
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/CMP0060-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0060 OLD)
+include(CMP0060-Common.cmake)
diff --git a/Tests/RunCMake/CMP0060/CMP0060-WARN-OFF-Build-result.txt b/Tests/RunCMake/CMP0060/CMP0060-WARN-OFF-Build-result.txt
new file mode 100644
index 0000000..d197c91
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/CMP0060-WARN-OFF-Build-result.txt
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/CMP0060/CMP0060-WARN-OFF-Build-stdout.txt b/Tests/RunCMake/CMP0060/CMP0060-WARN-OFF-Build-stdout.txt
new file mode 100644
index 0000000..240764c
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/CMP0060-WARN-OFF-Build-stdout.txt
@@ -0,0 +1 @@
+LINKFLAG_CMP0060_LINKSUFFIX
diff --git a/Tests/RunCMake/CMP0060/CMP0060-WARN-OFF.cmake b/Tests/RunCMake/CMP0060/CMP0060-WARN-OFF.cmake
new file mode 100644
index 0000000..6b84565
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/CMP0060-WARN-OFF.cmake
@@ -0,0 +1 @@
+include(CMP0060-Common.cmake)
diff --git a/Tests/RunCMake/CMP0060/CMP0060-WARN-ON-Build-result.txt b/Tests/RunCMake/CMP0060/CMP0060-WARN-ON-Build-result.txt
new file mode 100644
index 0000000..d197c91
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/CMP0060-WARN-ON-Build-result.txt
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/CMP0060/CMP0060-WARN-ON-Build-stdout.txt b/Tests/RunCMake/CMP0060/CMP0060-WARN-ON-Build-stdout.txt
new file mode 100644
index 0000000..240764c
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/CMP0060-WARN-ON-Build-stdout.txt
@@ -0,0 +1 @@
+LINKFLAG_CMP0060_LINKSUFFIX
diff --git a/Tests/RunCMake/CMP0060/CMP0060-WARN-ON-stderr.txt b/Tests/RunCMake/CMP0060/CMP0060-WARN-ON-stderr.txt
new file mode 100644
index 0000000..e2c280e
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/CMP0060-WARN-ON-stderr.txt
@@ -0,0 +1,16 @@
+^CMake Warning \(dev\) at CMP0060-Common.cmake:[0-9]+ \(add_executable\):
+ Policy CMP0060 is not set: Link libraries by full path even in implicit
+ directories. Run "cmake --help-policy CMP0060" for policy details. Use
+ the cmake_policy command to set the policy and suppress this warning.
+
+ Some library files are in directories implicitly searched by the linker
+ when invoked for C:
+
+ .*/Tests/RunCMake/CMP0060/CMP0060-WARN-ON-build/lib/(lib)?CMP0060.(a|lib)
+
+ For compatibility with older versions of CMake, the generated link line
+ will ask the linker to search for these by library name.
+Call Stack \(most recent call first\):
+ CMP0060-WARN-ON.cmake:[0-9]+ \(include\)
+ CMakeLists.txt:4 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/CMP0060/CMP0060-WARN-ON.cmake b/Tests/RunCMake/CMP0060/CMP0060-WARN-ON.cmake
new file mode 100644
index 0000000..a0a7950
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/CMP0060-WARN-ON.cmake
@@ -0,0 +1,2 @@
+set(CMAKE_POLICY_WARNING_CMP0060 1)
+include(CMP0060-Common.cmake)
diff --git a/Tests/RunCMake/CMP0060/CMakeLists.txt b/Tests/RunCMake/CMP0060/CMakeLists.txt
new file mode 100644
index 0000000..291d34d
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.9)
+cmake_policy(VERSION 3.2)
+project(${RunCMake_TEST} C)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0060/RunCMakeTest.cmake b/Tests/RunCMake/CMP0060/RunCMakeTest.cmake
new file mode 100644
index 0000000..445156f
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/RunCMakeTest.cmake
@@ -0,0 +1,19 @@
+include(RunCMake)
+
+function(run_cmake_CMP0060 CASE)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0060-${CASE}-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+ run_cmake(CMP0060-${CASE})
+ set(RunCMake_TEST_OUTPUT_MERGE 1)
+ run_cmake_command(CMP0060-${CASE}-Build
+ ${CMAKE_COMMAND} --build . --config Debug
+ )
+endfunction()
+
+run_cmake_CMP0060(OLD)
+run_cmake_CMP0060(WARN-OFF)
+run_cmake_CMP0060(WARN-ON)
+run_cmake_CMP0060(NEW)
diff --git a/Tests/RunCMake/CMP0060/cmp0060.c b/Tests/RunCMake/CMP0060/cmp0060.c
new file mode 100644
index 0000000..a2da227
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/cmp0060.c
@@ -0,0 +1,4 @@
+int libCMP0060(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0060/main.c b/Tests/RunCMake/CMP0060/main.c
new file mode 100644
index 0000000..91848c2
--- /dev/null
+++ b/Tests/RunCMake/CMP0060/main.c
@@ -0,0 +1,5 @@
+extern int libCMP0060(void);
+int main(void)
+{
+ return libCMP0060();
+}
diff --git a/Tests/RunCMake/CMP0064/CMP0064-NEW.cmake b/Tests/RunCMake/CMP0064/CMP0064-NEW.cmake
new file mode 100644
index 0000000..cdf50e9
--- /dev/null
+++ b/Tests/RunCMake/CMP0064/CMP0064-NEW.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0064 NEW)
+
+if(NOT TEST TestThatDoesNotExist)
+ message(STATUS "if NOT TestThatDoesNotExist is true")
+endif()
diff --git a/Tests/RunCMake/CMP0064/CMP0064-OLD-stderr.txt b/Tests/RunCMake/CMP0064/CMP0064-OLD-stderr.txt
new file mode 100644
index 0000000..987a503
--- /dev/null
+++ b/Tests/RunCMake/CMP0064/CMP0064-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0064-OLD.cmake:1 \(cmake_policy\):
+ The OLD behavior for policy CMP0064 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CMP0064/CMP0064-OLD.cmake b/Tests/RunCMake/CMP0064/CMP0064-OLD.cmake
new file mode 100644
index 0000000..bffd3f3
--- /dev/null
+++ b/Tests/RunCMake/CMP0064/CMP0064-OLD.cmake
@@ -0,0 +1,7 @@
+cmake_policy(SET CMP0064 OLD)
+
+if(TEST)
+ message(FATAL_ERROR "TEST was not recognized to be undefined")
+else()
+ message(STATUS "TEST was treated as a variable")
+endif()
diff --git a/Tests/RunCMake/CMP0064/CMP0064-WARN-stderr.txt b/Tests/RunCMake/CMP0064/CMP0064-WARN-stderr.txt
new file mode 100644
index 0000000..71f1ab7
--- /dev/null
+++ b/Tests/RunCMake/CMP0064/CMP0064-WARN-stderr.txt
@@ -0,0 +1,10 @@
+CMake Warning \(dev\) at CMP0064-WARN.cmake:3 \(if\):
+ Policy CMP0064 is not set: Support new TEST if\(\) operator. Run "cmake
+ --help-policy CMP0064" for policy details. Use the cmake_policy command to
+ set the policy and suppress this warning.
+
+ TEST will be interpreted as an operator when the policy is set to NEW.
+ Since the policy is not set the OLD behavior will be used.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0064/CMP0064-WARN.cmake b/Tests/RunCMake/CMP0064/CMP0064-WARN.cmake
new file mode 100644
index 0000000..8f26ec6
--- /dev/null
+++ b/Tests/RunCMake/CMP0064/CMP0064-WARN.cmake
@@ -0,0 +1,7 @@
+
+
+if(TEST)
+ message(FATAL_ERROR "TEST was not recognized to be undefined")
+else()
+ message(STATUS "TEST was treated as a variable")
+endif()
diff --git a/Tests/RunCMake/CMP0064/CMakeLists.txt b/Tests/RunCMake/CMP0064/CMakeLists.txt
new file mode 100644
index 0000000..74b3ff8
--- /dev/null
+++ b/Tests/RunCMake/CMP0064/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.3)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0064/RunCMakeTest.cmake b/Tests/RunCMake/CMP0064/RunCMakeTest.cmake
new file mode 100644
index 0000000..26e0a91
--- /dev/null
+++ b/Tests/RunCMake/CMP0064/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0064-OLD)
+run_cmake(CMP0064-WARN)
+run_cmake(CMP0064-NEW)
diff --git a/Tests/RunCMake/CMP0065/BuildTargetInSubProject.cmake b/Tests/RunCMake/CMP0065/BuildTargetInSubProject.cmake
new file mode 100644
index 0000000..9339e46
--- /dev/null
+++ b/Tests/RunCMake/CMP0065/BuildTargetInSubProject.cmake
@@ -0,0 +1,15 @@
+function(BuildTargetInSubProject P T E)
+ try_compile(RESULTVAR
+ ${CMAKE_CURRENT_BINARY_DIR}/subproject
+ ${CMAKE_CURRENT_SOURCE_DIR}/subproject
+ ${P} ${T} OUTPUT_VARIABLE O)
+ if(E AND RESULTVAR)
+ message(STATUS "${P} target ${T} succeeded as expected")
+ elseif(E AND NOT RESULTVAR)
+ message(FATAL_ERROR "${P} target ${T} failed but should have succeeded. Output:${O}")
+ elseif(NOT E AND NOT RESULTVAR)
+ message(STATUS "${P} target ${T} failed as expected")
+ elseif(NOT E AND RESULTVAR)
+ message(FATAL_ERROR "${P} target ${T} succeeded but should have failed. Output:${O}")
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/CMP0065/CMakeLists.txt b/Tests/RunCMake/CMP0065/CMakeLists.txt
new file mode 100644
index 0000000..74b3ff8
--- /dev/null
+++ b/Tests/RunCMake/CMP0065/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.3)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0065/NEWBad.cmake b/Tests/RunCMake/CMP0065/NEWBad.cmake
new file mode 100644
index 0000000..79d9adb
--- /dev/null
+++ b/Tests/RunCMake/CMP0065/NEWBad.cmake
@@ -0,0 +1,4 @@
+enable_language(C)
+include(BuildTargetInSubProject.cmake)
+
+BuildTargetInSubProject(TestPolicyCMP0065 FooNEWBad FALSE)
diff --git a/Tests/RunCMake/CMP0065/NEWGood.cmake b/Tests/RunCMake/CMP0065/NEWGood.cmake
new file mode 100644
index 0000000..a5b5d04
--- /dev/null
+++ b/Tests/RunCMake/CMP0065/NEWGood.cmake
@@ -0,0 +1,4 @@
+enable_language(C)
+include(BuildTargetInSubProject.cmake)
+
+BuildTargetInSubProject(TestPolicyCMP0065 FooNEWGood TRUE)
diff --git a/Tests/RunCMake/CMP0065/OLDBad1.cmake b/Tests/RunCMake/CMP0065/OLDBad1.cmake
new file mode 100644
index 0000000..6d780b4
--- /dev/null
+++ b/Tests/RunCMake/CMP0065/OLDBad1.cmake
@@ -0,0 +1,4 @@
+enable_language(C)
+include(BuildTargetInSubProject.cmake)
+
+BuildTargetInSubProject(TestPolicyCMP0065 FooOLDBad1 FALSE)
diff --git a/Tests/RunCMake/CMP0065/OLDBad2.cmake b/Tests/RunCMake/CMP0065/OLDBad2.cmake
new file mode 100644
index 0000000..7196473
--- /dev/null
+++ b/Tests/RunCMake/CMP0065/OLDBad2.cmake
@@ -0,0 +1,4 @@
+enable_language(C)
+include(BuildTargetInSubProject.cmake)
+
+BuildTargetInSubProject(TestPolicyCMP0065 FooOLDBad2 FALSE)
diff --git a/Tests/RunCMake/CMP0065/RunCMakeTest.cmake b/Tests/RunCMake/CMP0065/RunCMakeTest.cmake
new file mode 100644
index 0000000..e86b50e
--- /dev/null
+++ b/Tests/RunCMake/CMP0065/RunCMakeTest.cmake
@@ -0,0 +1,11 @@
+include(RunCMake)
+
+run_cmake(OLDBad1)
+if(NOT CMAKE_SYSTEM_NAME STREQUAL "AIX")
+ # Tests with ENABLE_EXPORTS ON. For AIX we do not use the flags at all.
+ run_cmake(OLDBad2)
+ run_cmake(NEWBad)
+endif()
+run_cmake(NEWGood)
+run_cmake(WARN-OFF)
+run_cmake(WARN-ON)
diff --git a/Tests/RunCMake/CMP0065/WARN-OFF.cmake b/Tests/RunCMake/CMP0065/WARN-OFF.cmake
new file mode 100644
index 0000000..dbc9562
--- /dev/null
+++ b/Tests/RunCMake/CMP0065/WARN-OFF.cmake
@@ -0,0 +1,3 @@
+
+enable_language(C)
+add_executable(main subproject/main.c)
diff --git a/Tests/RunCMake/CMP0065/WARN-ON-stderr.txt b/Tests/RunCMake/CMP0065/WARN-ON-stderr.txt
new file mode 100644
index 0000000..c31ec38
--- /dev/null
+++ b/Tests/RunCMake/CMP0065/WARN-ON-stderr.txt
@@ -0,0 +1,10 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0065 is not set: Do not add flags to export symbols from
+ executables without the ENABLE_EXPORTS target property. Run "cmake
+ --help-policy CMP0065" for policy details. Use the cmake_policy command to
+ set the policy and suppress this warning.
+
+ For compatibility with older versions of CMake, additional flags may be
+ added to export symbols on all executables regardless of their
+ ENABLE_EXPORTS property.
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0065/WARN-ON.cmake b/Tests/RunCMake/CMP0065/WARN-ON.cmake
new file mode 100644
index 0000000..6ed4a41
--- /dev/null
+++ b/Tests/RunCMake/CMP0065/WARN-ON.cmake
@@ -0,0 +1,3 @@
+set(CMAKE_POLICY_WARNING_CMP0065 1)
+enable_language(C)
+add_executable(main subproject/main.c)
diff --git a/Tests/RunCMake/CMP0065/subproject/CMakeLists.txt b/Tests/RunCMake/CMP0065/subproject/CMakeLists.txt
new file mode 100644
index 0000000..bed5960
--- /dev/null
+++ b/Tests/RunCMake/CMP0065/subproject/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.3)
+
+project(TestPolicyCMP0065 C)
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS BADFLAGS)
+
+#----------------------------------------------------------------------
+cmake_policy(SET CMP0065 OLD)
+add_executable(FooOLDBad1 main.c)
+
+#----------------------------------------------------------------------
+cmake_policy(SET CMP0065 OLD)
+add_executable(FooOLDBad2 main.c)
+set_target_properties(FooOLDBad2 PROPERTIES ENABLE_EXPORTS ON)
+
+#----------------------------------------------------------------------
+cmake_policy(SET CMP0065 NEW)
+add_executable(FooNEWGood main.c)
+
+#----------------------------------------------------------------------
+cmake_policy(SET CMP0065 NEW)
+add_executable(FooNEWBad main.c)
+set_target_properties(FooNEWBad PROPERTIES ENABLE_EXPORTS ON)
diff --git a/Tests/RunCMake/CMP0065/subproject/main.c b/Tests/RunCMake/CMP0065/subproject/main.c
new file mode 100644
index 0000000..2adf396
--- /dev/null
+++ b/Tests/RunCMake/CMP0065/subproject/main.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char** argv)
+{
+ printf("Hello World\n");
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0068/CMP0068-NEW-result.txt b/Tests/RunCMake/CMP0068/CMP0068-NEW-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0068/CMP0068-NEW-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0068/CMP0068-NEW.cmake b/Tests/RunCMake/CMP0068/CMP0068-NEW.cmake
new file mode 100644
index 0000000..eb8cfa1
--- /dev/null
+++ b/Tests/RunCMake/CMP0068/CMP0068-NEW.cmake
@@ -0,0 +1,6 @@
+
+cmake_policy(SET CMP0068 NEW)
+cmake_policy(SET CMP0042 NEW)
+
+add_library(foo SHARED empty.cpp)
+set_target_properties(foo PROPERTIES INSTALL_NAME_DIR "@rpath" INSTALL_RPATH "@loader_path/" BUILD_WITH_INSTALL_RPATH 1)
diff --git a/Tests/RunCMake/CMP0068/CMP0068-OLD-result.txt b/Tests/RunCMake/CMP0068/CMP0068-OLD-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0068/CMP0068-OLD-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0068/CMP0068-OLD-stderr.txt b/Tests/RunCMake/CMP0068/CMP0068-OLD-stderr.txt
new file mode 100644
index 0000000..a736129
--- /dev/null
+++ b/Tests/RunCMake/CMP0068/CMP0068-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0068-OLD.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0068 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0068/CMP0068-OLD.cmake b/Tests/RunCMake/CMP0068/CMP0068-OLD.cmake
new file mode 100644
index 0000000..cf1040f
--- /dev/null
+++ b/Tests/RunCMake/CMP0068/CMP0068-OLD.cmake
@@ -0,0 +1,6 @@
+
+cmake_policy(SET CMP0068 OLD)
+cmake_policy(SET CMP0042 NEW)
+
+add_library(foo SHARED empty.cpp)
+set_target_properties(foo PROPERTIES INSTALL_NAME_DIR "@rpath" INSTALL_RPATH "@loader_path/" BUILD_WITH_INSTALL_RPATH 1)
diff --git a/Tests/RunCMake/CMP0068/CMP0068-WARN-result.txt b/Tests/RunCMake/CMP0068/CMP0068-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0068/CMP0068-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0068/CMP0068-WARN-stderr.txt b/Tests/RunCMake/CMP0068/CMP0068-WARN-stderr.txt
new file mode 100644
index 0000000..3cb5854
--- /dev/null
+++ b/Tests/RunCMake/CMP0068/CMP0068-WARN-stderr.txt
@@ -0,0 +1,12 @@
+CMake Warning \(dev\):
+ Policy CMP0068 is not set: RPATH settings on macOS do not affect
+ install_name. Run "cmake --help-policy CMP0068" for policy details. Use
+ the cmake_policy command to set the policy and suppress this warning.
+
+ For compatibility with older versions of CMake, the install_name fields for
+ the following targets are still affected by RPATH settings:
+
+ foo3
+ foo4
+
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0068/CMP0068-WARN.cmake b/Tests/RunCMake/CMP0068/CMP0068-WARN.cmake
new file mode 100644
index 0000000..b7ec480
--- /dev/null
+++ b/Tests/RunCMake/CMP0068/CMP0068-WARN.cmake
@@ -0,0 +1,12 @@
+cmake_policy(SET CMP0042 NEW)
+
+add_library(foo SHARED empty.cpp)
+add_library(foo-static STATIC empty.cpp)
+add_library(foo2 SHARED empty.cpp)
+set_target_properties(foo2 PROPERTIES MACOSX_RPATH 1)
+add_library(foo3 SHARED empty.cpp)
+set_target_properties(foo3 PROPERTIES BUILD_WITH_INSTALL_RPATH 1 INSTALL_NAME_DIR "@loader_path")
+add_library(foo4 SHARED empty.cpp)
+set_target_properties(foo4 PROPERTIES BUILD_WITH_INSTALL_RPATH 1 INSTALL_NAME_DIR "@rpath")
+add_library(foo5 SHARED empty.cpp)
+set_target_properties(foo5 PROPERTIES BUILD_WITH_INSTALL_RPATH 1 BUILD_WITH_INSTALL_NAME_DIR 1 INSTALL_NAME_DIR "@rpath")
diff --git a/Tests/RunCMake/CMP0068/CMakeLists.txt b/Tests/RunCMake/CMP0068/CMakeLists.txt
new file mode 100644
index 0000000..375cbdb
--- /dev/null
+++ b/Tests/RunCMake/CMP0068/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.8)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0068/RunCMakeTest.cmake b/Tests/RunCMake/CMP0068/RunCMakeTest.cmake
new file mode 100644
index 0000000..88a6225
--- /dev/null
+++ b/Tests/RunCMake/CMP0068/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0068-OLD)
+run_cmake(CMP0068-NEW)
+run_cmake(CMP0068-WARN)
diff --git a/Tests/RunCMake/CMP0068/empty.cpp b/Tests/RunCMake/CMP0068/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0068/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-result.txt b/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-stderr.txt b/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-stderr.txt
new file mode 100644
index 0000000..87ac88e
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error at CMP0069-NEW-cmake\.cmake:[0-9]+ \(add_executable\):
+ CMake doesn't support IPO for current compiler
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake.cmake b/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake.cmake
new file mode 100644
index 0000000..6968c8b
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake.cmake
@@ -0,0 +1,6 @@
+cmake_policy(SET CMP0069 NEW)
+
+set(_CMAKE_CXX_IPO_SUPPORTED_BY_CMAKE NO)
+
+add_executable(foo main.cpp)
+set_target_properties(foo PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-result.txt b/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-stderr.txt b/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-stderr.txt
new file mode 100644
index 0000000..cb9d19b
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error at CMP0069-NEW-compiler\.cmake:[0-9]+ \(add_executable\):
+ Compiler doesn't support IPO
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler.cmake b/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler.cmake
new file mode 100644
index 0000000..ecb197b
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler.cmake
@@ -0,0 +1,7 @@
+cmake_policy(SET CMP0069 NEW)
+
+set(_CMAKE_CXX_IPO_SUPPORTED_BY_CMAKE YES)
+set(_CMAKE_CXX_IPO_MAY_BE_SUPPORTED_BY_COMPILER NO)
+
+add_executable(foo main.cpp)
+set_target_properties(foo PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-generator-result.txt b/Tests/RunCMake/CMP0069/CMP0069-NEW-generator-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-generator-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-generator-stderr.txt b/Tests/RunCMake/CMP0069/CMP0069-NEW-generator-stderr.txt
new file mode 100644
index 0000000..1159ec0
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-generator-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error at CMP0069-NEW-generator\.cmake:[0-9]+ \(add_executable\):
+ CMake doesn't support IPO for current generator
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-generator.cmake b/Tests/RunCMake/CMP0069/CMP0069-NEW-generator.cmake
new file mode 100644
index 0000000..80d4e15
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-generator.cmake
@@ -0,0 +1,7 @@
+cmake_policy(SET CMP0069 NEW)
+
+set(_CMAKE_CXX_IPO_SUPPORTED_BY_CMAKE YES)
+set(_CMAKE_CXX_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
+
+add_executable(foo main.cpp)
+set_target_properties(foo PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
diff --git a/Tests/RunCMake/CMP0069/CMP0069-OLD-stderr.txt b/Tests/RunCMake/CMP0069/CMP0069-OLD-stderr.txt
new file mode 100644
index 0000000..f51a6f4
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMP0069-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0069-OLD.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0069 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0069/CMP0069-OLD.cmake b/Tests/RunCMake/CMP0069/CMP0069-OLD.cmake
new file mode 100644
index 0000000..cfe1e9d
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMP0069-OLD.cmake
@@ -0,0 +1,4 @@
+cmake_policy(SET CMP0069 OLD)
+
+add_executable(foo main.cpp)
+set_target_properties(foo PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
diff --git a/Tests/RunCMake/CMP0069/CMP0069-WARN-stderr.txt b/Tests/RunCMake/CMP0069/CMP0069-WARN-stderr.txt
new file mode 100644
index 0000000..314e180
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMP0069-WARN-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Warning \(dev\) at CMP0069-WARN\.cmake:[0-9]+ \(add_executable\):
+ Policy CMP0069 is not set: INTERPROCEDURAL_OPTIMIZATION is enforced when
+ enabled. Run "cmake --help-policy CMP0069" for policy details\. Use the
+ cmake_policy command to set the policy and suppress this warning\.
+
+ INTERPROCEDURAL_OPTIMIZATION property will be ignored for target 'foo'\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.$
diff --git a/Tests/RunCMake/CMP0069/CMP0069-WARN.cmake b/Tests/RunCMake/CMP0069/CMP0069-WARN.cmake
new file mode 100644
index 0000000..2049c9e
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMP0069-WARN.cmake
@@ -0,0 +1,4 @@
+set(_CMAKE_CXX_IPO_LEGACY_BEHAVIOR NO)
+
+add_executable(foo main.cpp)
+set_target_properties(foo PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
diff --git a/Tests/RunCMake/CMP0069/CMakeLists.txt b/Tests/RunCMake/CMP0069/CMakeLists.txt
new file mode 100644
index 0000000..375cbdb
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.8)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0069/RunCMakeTest.cmake b/Tests/RunCMake/CMP0069/RunCMakeTest.cmake
new file mode 100644
index 0000000..456e6a6
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/RunCMakeTest.cmake
@@ -0,0 +1,10 @@
+include(RunCMake)
+
+run_cmake(CMP0069-OLD)
+run_cmake(CMP0069-NEW-cmake)
+run_cmake(CMP0069-NEW-compiler)
+run_cmake(CMP0069-WARN)
+
+if(RunCMake_GENERATOR MATCHES "^Visual Studio 9 ")
+ run_cmake(CMP0069-NEW-generator)
+endif()
diff --git a/Tests/RunCMake/CMP0069/main.cpp b/Tests/RunCMake/CMP0069/main.cpp
new file mode 100644
index 0000000..5047a34
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/main.cpp
@@ -0,0 +1,3 @@
+int main()
+{
+}
diff --git a/Tests/RunCMake/CMP0081/CMP0081-Common.cmake b/Tests/RunCMake/CMP0081/CMP0081-Common.cmake
new file mode 100644
index 0000000..3ea5277
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-Common.cmake
@@ -0,0 +1,5 @@
+
+enable_language(CXX)
+
+add_library(foo SHARED empty.cpp)
+set_target_properties(foo PROPERTIES LINK_DIRECTORIES "../lib")
diff --git a/Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt b/Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt b/Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt
new file mode 100644
index 0000000..d31c149
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error in CMakeLists.txt:
+ Found relative path while evaluating link directories of "foo":
+
+ "../lib"
diff --git a/Tests/RunCMake/CMP0081/CMP0081-NEW.cmake b/Tests/RunCMake/CMP0081/CMP0081-NEW.cmake
new file mode 100644
index 0000000..9b927a2
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-NEW.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0081 NEW)
+
+include (CMP0081-Common.cmake)
diff --git a/Tests/RunCMake/CMP0081/CMP0081-OLD-stderr.txt b/Tests/RunCMake/CMP0081/CMP0081-OLD-stderr.txt
new file mode 100644
index 0000000..ff339fa
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0081-OLD.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0081 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0081/CMP0081-OLD.cmake b/Tests/RunCMake/CMP0081/CMP0081-OLD.cmake
new file mode 100644
index 0000000..2e91bf6
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-OLD.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0081 OLD)
+
+include (CMP0081-Common.cmake)
diff --git a/Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt b/Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt b/Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt
new file mode 100644
index 0000000..eac0648
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt
@@ -0,0 +1,10 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0081 is not set: Relative paths not allowed in LINK_DIRECTORIES
+ target property. Run "cmake --help-policy CMP0081" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
+
+ Found relative path while evaluating link directories of "foo":
+
+ "../lib"
+
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0081/CMP0081-WARN.cmake b/Tests/RunCMake/CMP0081/CMP0081-WARN.cmake
new file mode 100644
index 0000000..33bb21d
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-WARN.cmake
@@ -0,0 +1,2 @@
+
+include (CMP0081-Common.cmake)
diff --git a/Tests/RunCMake/CMP0081/CMakeLists.txt b/Tests/RunCMake/CMP0081/CMakeLists.txt
new file mode 100644
index 0000000..ef2163c
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.1)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0081/RunCMakeTest.cmake b/Tests/RunCMake/CMP0081/RunCMakeTest.cmake
new file mode 100644
index 0000000..335d8c5
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0081-OLD)
+run_cmake(CMP0081-NEW)
+run_cmake(CMP0081-WARN)
diff --git a/Tests/RunCMake/CMP0081/empty.cpp b/Tests/RunCMake/CMP0081/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0102/CMP0102-Common.cmake b/Tests/RunCMake/CMP0102/CMP0102-Common.cmake
new file mode 100644
index 0000000..61fdad6
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMP0102-Common.cmake
@@ -0,0 +1,2 @@
+
+mark_as_advanced(CMP0102_TEST_VARIABLE)
diff --git a/Tests/RunCMake/CMP0102/CMP0102-NEW.cmake b/Tests/RunCMake/CMP0102/CMP0102-NEW.cmake
new file mode 100644
index 0000000..bdf769f
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMP0102-NEW.cmake
@@ -0,0 +1,13 @@
+
+cmake_policy(SET CMP0102 NEW)
+
+include (CMP0102-Common.cmake)
+get_property(is_type_set CACHE CMP0102_TEST_VARIABLE
+ PROPERTY TYPE SET)
+if (is_type_set)
+ get_property(type CACHE CMP0102_TEST_VARIABLE
+ PROPERTY TYPE)
+ message(FATAL_ERROR
+ "There is a cache entry for an undefined variable after "
+ "`mark_as_advanced`.")
+endif ()
diff --git a/Tests/RunCMake/CMP0102/CMP0102-OLD.cmake b/Tests/RunCMake/CMP0102/CMP0102-OLD.cmake
new file mode 100644
index 0000000..5c20dd3
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMP0102-OLD.cmake
@@ -0,0 +1,18 @@
+
+cmake_policy(SET CMP0102 OLD)
+
+include (CMP0102-Common.cmake)
+get_property(is_type_set CACHE CMP0102_TEST_VARIABLE
+ PROPERTY TYPE SET)
+if (NOT is_type_set)
+ message(FATAL_ERROR
+ "There is a cache entry for an undefined variable after "
+ "`mark_as_advanced`.")
+endif ()
+get_property(type CACHE CMP0102_TEST_VARIABLE
+ PROPERTY TYPE)
+if (NOT type STREQUAL "UNINITIALIZED")
+ message(FATAL_ERROR
+ "The cache type for CMP0102_TEST_VARIABLE is not "
+ "UNINITIALIZED")
+endif ()
diff --git a/Tests/RunCMake/CMP0102/CMP0102-WARN-Default.cmake b/Tests/RunCMake/CMP0102/CMP0102-WARN-Default.cmake
new file mode 100644
index 0000000..d6ebe4d
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMP0102-WARN-Default.cmake
@@ -0,0 +1,16 @@
+
+include (CMP0102-Common.cmake)
+get_property(is_type_set CACHE CMP0102_TEST_VARIABLE
+ PROPERTY TYPE SET)
+if (NOT is_type_set)
+ message(FATAL_ERROR
+ "There is a cache entry for an undefined variable after "
+ "`mark_as_advanced`.")
+endif ()
+get_property(type CACHE CMP0102_TEST_VARIABLE
+ PROPERTY TYPE)
+if (NOT type STREQUAL "UNINITIALIZED")
+ message(FATAL_ERROR
+ "The cache type for CMP0102_TEST_VARIABLE is not "
+ "UNINITIALIZED")
+endif ()
diff --git a/Tests/RunCMake/CMP0102/CMP0102-WARN-stderr.txt b/Tests/RunCMake/CMP0102/CMP0102-WARN-stderr.txt
new file mode 100644
index 0000000..bb56ec2
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMP0102-WARN-stderr.txt
@@ -0,0 +1,10 @@
+CMake Warning \(dev\) at CMP0102-Common.cmake:2 \(mark_as_advanced\):
+ Policy CMP0102 is not set: The variable named "CMP0102_TEST_VARIABLE" is
+ not in the cache. This results in an empty cache entry which is no longer
+ created when policy CMP0102 is set to NEW. Run "cmake --help-policy
+ CMP0102" for policy details. Use the cmake_policy command to set the
+ policy and suppress this warning.
+Call Stack \(most recent call first\):
+ CMP0102-WARN.cmake:4 \(include\)
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0102/CMP0102-WARN.cmake b/Tests/RunCMake/CMP0102/CMP0102-WARN.cmake
new file mode 100644
index 0000000..e9a45f1
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMP0102-WARN.cmake
@@ -0,0 +1,18 @@
+
+set(CMAKE_POLICY_WARNING_CMP0102 1)
+
+include (CMP0102-Common.cmake)
+get_property(is_type_set CACHE CMP0102_TEST_VARIABLE
+ PROPERTY TYPE SET)
+if (NOT is_type_set)
+ message(FATAL_ERROR
+ "There is a cache entry for an undefined variable after "
+ "`mark_as_advanced`.")
+endif ()
+get_property(type CACHE CMP0102_TEST_VARIABLE
+ PROPERTY TYPE)
+if (NOT type STREQUAL "UNINITIALIZED")
+ message(FATAL_ERROR
+ "The cache type for CMP0102_TEST_VARIABLE is not "
+ "UNINITIALIZED")
+endif ()
diff --git a/Tests/RunCMake/CMP0102/CMakeLists.txt b/Tests/RunCMake/CMP0102/CMakeLists.txt
new file mode 100644
index 0000000..ef2163c
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.1)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0102/RunCMakeTest.cmake b/Tests/RunCMake/CMP0102/RunCMakeTest.cmake
new file mode 100644
index 0000000..9b5df74
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/RunCMakeTest.cmake
@@ -0,0 +1,6 @@
+include(RunCMake)
+
+run_cmake(CMP0102-OLD)
+run_cmake(CMP0102-NEW)
+run_cmake(CMP0102-WARN)
+run_cmake(CMP0102-WARN-Default)
diff --git a/Tests/RunCMake/CMP0104/CMP0104-Common.cmake b/Tests/RunCMake/CMP0104/CMP0104-Common.cmake
new file mode 100644
index 0000000..ca4c1aa2
--- /dev/null
+++ b/Tests/RunCMake/CMP0104/CMP0104-Common.cmake
@@ -0,0 +1,6 @@
+# Make sure CMP0104 isn't issued for CXX targets created prior to enabling CUDA. See #21341.
+enable_language(CXX)
+add_library(cxx main.cxx)
+
+enable_language(CUDA)
+add_library(cuda main.cu)
diff --git a/Tests/RunCMake/CMP0104/CMP0104-NEW.cmake b/Tests/RunCMake/CMP0104/CMP0104-NEW.cmake
new file mode 100644
index 0000000..732ab77
--- /dev/null
+++ b/Tests/RunCMake/CMP0104/CMP0104-NEW.cmake
@@ -0,0 +1,6 @@
+cmake_policy(SET CMP0104 NEW)
+include(CMP0104-Common.cmake)
+
+if(NOT CMAKE_CUDA_ARCHITECTURES)
+ message(FATAL_ERROR "CMAKE_CUDA_ARCHITECTURES is empty with CMP0104 enabled.")
+endif()
diff --git a/Tests/RunCMake/CMP0104/CMP0104-OFF.cmake b/Tests/RunCMake/CMP0104/CMP0104-OFF.cmake
new file mode 100644
index 0000000..f3b6682
--- /dev/null
+++ b/Tests/RunCMake/CMP0104/CMP0104-OFF.cmake
@@ -0,0 +1,3 @@
+include(CMP0104-Common.cmake)
+
+set_property(TARGET cuda PROPERTY CUDA_ARCHITECTURES OFF)
diff --git a/Tests/RunCMake/CMP0104/CMP0104-OLD.cmake b/Tests/RunCMake/CMP0104/CMP0104-OLD.cmake
new file mode 100644
index 0000000..6988447
--- /dev/null
+++ b/Tests/RunCMake/CMP0104/CMP0104-OLD.cmake
@@ -0,0 +1,14 @@
+set(ENV{CUDAARCHS})
+
+cmake_policy(SET CMP0104 OLD)
+include(CMP0104-Common.cmake)
+
+if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
+ if(CMAKE_CUDA_ARCHITECTURES)
+ message(FATAL_ERROR "CMAKE_CUDA_ARCHITECTURES isn't empty for NVIDIA with CMP0104 OLD.")
+ endif()
+else(NOT CMAKE_CUDA_COMPILER_ID STREQUAL "Unknown")
+ if(NOT CMAKE_CUDA_ARCHITECTURES)
+ message(FATAL_ERROR "CMAKE_CUDA_ARCHITECTURES isn't non-empty for non-NVIDIA with CMP0104 OLD.")
+ endif()
+endif()
diff --git a/Tests/RunCMake/CMP0104/CMP0104-WARN-stderr.txt b/Tests/RunCMake/CMP0104/CMP0104-WARN-stderr.txt
new file mode 100644
index 0000000..2c9b7d7
--- /dev/null
+++ b/Tests/RunCMake/CMP0104/CMP0104-WARN-stderr.txt
@@ -0,0 +1,8 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0104 is not set: CMAKE_CUDA_ARCHITECTURES now detected for NVCC,
+ empty CUDA_ARCHITECTURES not allowed. Run "cmake --help-policy CMP0104"
+ for policy details. Use the cmake_policy command to set the policy and
+ suppress this warning.
+
+ CUDA_ARCHITECTURES is empty for target "cuda".
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0104/CMP0104-WARN.cmake b/Tests/RunCMake/CMP0104/CMP0104-WARN.cmake
new file mode 100644
index 0000000..2b4a8f5
--- /dev/null
+++ b/Tests/RunCMake/CMP0104/CMP0104-WARN.cmake
@@ -0,0 +1,2 @@
+include(CMP0104-Common.cmake)
+set_property(TARGET cuda PROPERTY CUDA_ARCHITECTURES)
diff --git a/Tests/RunCMake/CMP0104/CMakeLists.txt b/Tests/RunCMake/CMP0104/CMakeLists.txt
new file mode 100644
index 0000000..2632ffa
--- /dev/null
+++ b/Tests/RunCMake/CMP0104/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.16)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0104/RunCMakeTest.cmake b/Tests/RunCMake/CMP0104/RunCMakeTest.cmake
new file mode 100644
index 0000000..b26f72a
--- /dev/null
+++ b/Tests/RunCMake/CMP0104/RunCMakeTest.cmake
@@ -0,0 +1,6 @@
+include(RunCMake)
+
+run_cmake(CMP0104-OLD)
+run_cmake(CMP0104-NEW)
+run_cmake(CMP0104-OFF)
+run_cmake(CMP0104-WARN)
diff --git a/Tests/RunCMake/CMP0104/main.cu b/Tests/RunCMake/CMP0104/main.cu
new file mode 100644
index 0000000..5047a34
--- /dev/null
+++ b/Tests/RunCMake/CMP0104/main.cu
@@ -0,0 +1,3 @@
+int main()
+{
+}
diff --git a/Tests/RunCMake/CMP0104/main.cxx b/Tests/RunCMake/CMP0104/main.cxx
new file mode 100644
index 0000000..5047a34
--- /dev/null
+++ b/Tests/RunCMake/CMP0104/main.cxx
@@ -0,0 +1,3 @@
+int main()
+{
+}
diff --git a/Tests/RunCMake/CMP0106/CMP0106-Common.cmake b/Tests/RunCMake/CMP0106/CMP0106-Common.cmake
new file mode 100644
index 0000000..a1f7908
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/CMP0106-Common.cmake
@@ -0,0 +1,10 @@
+include(Documentation OPTIONAL RESULT_VARIABLE found)
+if (NOT should_find AND found)
+ message(FATAL_ERROR
+ "The Documentation module should not have been found, but it was.")
+endif ()
+if (should_find AND NOT found)
+ message(FATAL_ERROR
+ "The Documentation module should have been found, but it was not.")
+endif ()
+include(${CMAKE_ROOT}/Modules/Documentation.cmake)
diff --git a/Tests/RunCMake/CMP0106/CMP0106-NEW-result.txt b/Tests/RunCMake/CMP0106/CMP0106-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/CMP0106-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0106/CMP0106-NEW-stderr.txt b/Tests/RunCMake/CMP0106/CMP0106-NEW-stderr.txt
new file mode 100644
index 0000000..8a4d7e4
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/CMP0106-NEW-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at .*/Modules/Documentation.cmake:[0-9]+ \(message\):
+ Documentation.cmake is VTK-specific code and should not be used in non-VTK
+ projects. This logic in this module is best shipped with the project using
+ it rather than with CMake. This is now an error according to policy
+ CMP0106.
+Call Stack \(most recent call first\):
+ CMP0106-Common.cmake:10 \(include\)
+ CMP0106-NEW.cmake:4 \(include\)
+ CMakeLists.txt:7 \(include\)
diff --git a/Tests/RunCMake/CMP0106/CMP0106-NEW.cmake b/Tests/RunCMake/CMP0106/CMP0106-NEW.cmake
new file mode 100644
index 0000000..e7d5bd1
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/CMP0106-NEW.cmake
@@ -0,0 +1,4 @@
+cmake_policy(SET CMP0106 NEW)
+
+set(should_find OFF)
+include(CMP0106-Common.cmake)
diff --git a/Tests/RunCMake/CMP0106/CMP0106-OLD.cmake b/Tests/RunCMake/CMP0106/CMP0106-OLD.cmake
new file mode 100644
index 0000000..730e846
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/CMP0106-OLD.cmake
@@ -0,0 +1,9 @@
+cmake_policy(SET CMP0106 OLD)
+
+set(should_find ON)
+include(CMP0106-Common.cmake)
+if (NOT DEFINED BUILD_DOCUMENTATION)
+ message(FATAL_ERROR
+ "Cache variables seem to have not been made with a `OLD` policy "
+ "setting.")
+endif ()
diff --git a/Tests/RunCMake/CMP0106/CMP0106-WARN-ParaView-stderr.txt b/Tests/RunCMake/CMP0106/CMP0106-WARN-ParaView-stderr.txt
new file mode 100644
index 0000000..b61889b
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/CMP0106-WARN-ParaView-stderr.txt
@@ -0,0 +1,8 @@
+CMake Warning \(dev\) at CMP0106-Common.cmake:1 \(include\):
+ Policy CMP0106 is not set: The Documentation module is removed. Run "cmake
+ --help-policy CMP0106" for policy details. Use the cmake_policy command to
+ set the policy and suppress this warning.
+
+Call Stack \(most recent call first\):
+ subdir/CMakeLists.txt:2 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0106/CMP0106-WARN-ParaView.cmake b/Tests/RunCMake/CMP0106/CMP0106-WARN-ParaView.cmake
new file mode 100644
index 0000000..309abcc
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/CMP0106-WARN-ParaView.cmake
@@ -0,0 +1,2 @@
+set(should_find ON)
+add_subdirectory(subdir)
diff --git a/Tests/RunCMake/CMP0106/CMP0106-WARN-VTK-stderr.txt b/Tests/RunCMake/CMP0106/CMP0106-WARN-VTK-stderr.txt
new file mode 100644
index 0000000..f8a754e
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/CMP0106-WARN-VTK-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMP0106-Common.cmake:1 \(include\):
+ Policy CMP0106 is not set: The Documentation module is removed. Run "cmake
+ --help-policy CMP0106" for policy details. Use the cmake_policy command to
+ set the policy and suppress this warning.
+
+Call Stack \(most recent call first\):
+ CMP0106-WARN-VTK.cmake:2 \(include\)
+ CMakeLists.txt:7 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0106/CMP0106-WARN-VTK.cmake b/Tests/RunCMake/CMP0106/CMP0106-WARN-VTK.cmake
new file mode 100644
index 0000000..99f6c39
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/CMP0106-WARN-VTK.cmake
@@ -0,0 +1,2 @@
+set(should_find ON)
+include(CMP0106-Common.cmake)
diff --git a/Tests/RunCMake/CMP0106/CMP0106-WARN-stderr.txt b/Tests/RunCMake/CMP0106/CMP0106-WARN-stderr.txt
new file mode 100644
index 0000000..af6bb05
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/CMP0106-WARN-stderr.txt
@@ -0,0 +1,37 @@
+CMake Warning \(dev\) at CMP0106-Common.cmake:1 \(include\):
+ Policy CMP0106 is not set: The Documentation module is removed. Run "cmake
+ --help-policy CMP0106" for policy details. Use the cmake_policy command to
+ set the policy and suppress this warning.
+
+Call Stack \(most recent call first\):
+ CMP0106-WARN.cmake:2 \(include\)
+ CMakeLists.txt:7 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\) at .*/Modules/Documentation.cmake:[0-9]+ \(message\):
+ Policy CMP0106 is not set: The Documentation module is removed. Run "cmake
+ --help-policy CMP0106" for policy details. Use the cmake_policy command to
+ set the policy and suppress this warning.
+
+ Documentation.cmake is VTK-specific code and should not be used in non-VTK
+ projects. This logic in this module is best shipped with the project using
+ it rather than with CMake.
+Call Stack \(most recent call first\):
+ CMP0106-Common.cmake:1 \(include\)
+ CMP0106-WARN.cmake:2 \(include\)
+ CMakeLists.txt:7 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\) at .*/Modules/Documentation.cmake:[0-9]+ \(message\):
+ Policy CMP0106 is not set: The Documentation module is removed. Run "cmake
+ --help-policy CMP0106" for policy details. Use the cmake_policy command to
+ set the policy and suppress this warning.
+
+ Documentation.cmake is VTK-specific code and should not be used in non-VTK
+ projects. This logic in this module is best shipped with the project using
+ it rather than with CMake.
+Call Stack \(most recent call first\):
+ CMP0106-Common.cmake:10 \(include\)
+ CMP0106-WARN.cmake:2 \(include\)
+ CMakeLists.txt:7 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0106/CMP0106-WARN.cmake b/Tests/RunCMake/CMP0106/CMP0106-WARN.cmake
new file mode 100644
index 0000000..99f6c39
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/CMP0106-WARN.cmake
@@ -0,0 +1,2 @@
+set(should_find ON)
+include(CMP0106-Common.cmake)
diff --git a/Tests/RunCMake/CMP0106/CMakeLists.txt b/Tests/RunCMake/CMP0106/CMakeLists.txt
new file mode 100644
index 0000000..eafa642
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.1)
+if (RunCMake_TEST STREQUAL "CMP0106-WARN-VTK")
+ project(VTK NONE)
+else ()
+ project(${RunCMake_TEST} NONE)
+endif ()
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0106/RunCMakeTest.cmake b/Tests/RunCMake/CMP0106/RunCMakeTest.cmake
new file mode 100644
index 0000000..acec054
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/RunCMakeTest.cmake
@@ -0,0 +1,7 @@
+include(RunCMake)
+
+run_cmake(CMP0106-OLD)
+run_cmake(CMP0106-NEW)
+run_cmake(CMP0106-WARN)
+run_cmake(CMP0106-WARN-VTK)
+run_cmake(CMP0106-WARN-ParaView)
diff --git a/Tests/RunCMake/CMP0106/subdir/CMakeLists.txt b/Tests/RunCMake/CMP0106/subdir/CMakeLists.txt
new file mode 100644
index 0000000..ed1dd05
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/subdir/CMakeLists.txt
@@ -0,0 +1,2 @@
+project(VTK NONE)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../CMP0106-Common.cmake)
diff --git a/Tests/RunCMake/CMP0111/CMP0111-Common.cmake b/Tests/RunCMake/CMP0111/CMP0111-Common.cmake
new file mode 100644
index 0000000..c31e4ba
--- /dev/null
+++ b/Tests/RunCMake/CMP0111/CMP0111-Common.cmake
@@ -0,0 +1,10 @@
+# Prevent duplicate errors on some platforms.
+set(CMAKE_IMPORT_LIBRARY_SUFFIX "placeholder")
+
+add_library(unknown_lib UNKNOWN IMPORTED)
+add_library(static_lib STATIC IMPORTED)
+add_library(shared_lib SHARED IMPORTED)
+add_library(interface_lib INTERFACE IMPORTED)
+
+add_library(module MODULE module.cpp)
+target_link_libraries(module unknown_lib static_lib shared_lib interface_lib)
diff --git a/Tests/RunCMake/CMP0111/CMP0111-NEW-result.txt b/Tests/RunCMake/CMP0111/CMP0111-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0111/CMP0111-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0111/CMP0111-NEW-stderr.txt b/Tests/RunCMake/CMP0111/CMP0111-NEW-stderr.txt
new file mode 100644
index 0000000..91a90e5
--- /dev/null
+++ b/Tests/RunCMake/CMP0111/CMP0111-NEW-stderr.txt
@@ -0,0 +1,17 @@
+^CMake Error in CMakeLists.txt:
+ IMPORTED_LOCATION not set for imported target "unknown_lib"( configuration
+ "[^"]+")?.
++
+CMake Error in CMakeLists.txt:
+ IMPORTED_LOCATION not set for imported target "static_lib"( configuration
+ "[^"]+")?.
++
+CMake Error in CMakeLists.txt:
+ IMPORTED_IMPLIB not set for imported target "shared_lib"( configuration
+ "[^"]+")?.(
++
+CMake Error in CMakeLists.txt:
+ IMPORTED_(LOCATION|IMPLIB) not set for imported target "(unknown|static|shared)_lib"( configuration
+ "[^"]+")?.)*
++
+CMake Generate step failed. Build files cannot be regenerated correctly.$
diff --git a/Tests/RunCMake/CMP0111/CMP0111-NEW.cmake b/Tests/RunCMake/CMP0111/CMP0111-NEW.cmake
new file mode 100644
index 0000000..d0c8dd3
--- /dev/null
+++ b/Tests/RunCMake/CMP0111/CMP0111-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0111 NEW)
+include(CMP0111-Common.cmake)
diff --git a/Tests/RunCMake/CMP0111/CMP0111-OLD.cmake b/Tests/RunCMake/CMP0111/CMP0111-OLD.cmake
new file mode 100644
index 0000000..d00847a
--- /dev/null
+++ b/Tests/RunCMake/CMP0111/CMP0111-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0111 OLD)
+include(CMP0111-Common.cmake)
diff --git a/Tests/RunCMake/CMP0111/CMP0111-WARN-stderr.txt b/Tests/RunCMake/CMP0111/CMP0111-WARN-stderr.txt
new file mode 100644
index 0000000..27af911
--- /dev/null
+++ b/Tests/RunCMake/CMP0111/CMP0111-WARN-stderr.txt
@@ -0,0 +1,39 @@
+^CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0111 is not set: An imported target missing its location property
+ fails during generation. Run "cmake --help-policy CMP0111" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ IMPORTED_LOCATION not set for imported target "unknown_lib"( configuration
+ "[^"]+")?.
+This warning is for project developers. Use -Wno-dev to suppress it.
++
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0111 is not set: An imported target missing its location property
+ fails during generation. Run "cmake --help-policy CMP0111" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ IMPORTED_LOCATION not set for imported target "static_lib"( configuration
+ "[^"]+")?.
+This warning is for project developers. Use -Wno-dev to suppress it.
++
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0111 is not set: An imported target missing its location property
+ fails during generation. Run "cmake --help-policy CMP0111" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ IMPORTED_IMPLIB not set for imported target "shared_lib"( configuration
+ "[^"]+")?.
+This warning is for project developers. Use -Wno-dev to suppress it.(
++
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0111 is not set: An imported target missing its location property
+ fails during generation. Run "cmake --help-policy CMP0111" for policy
+ details. Use the cmake_policy command to set the policy and suppress this
+ warning.
+
+ IMPORTED_(LOCATION|IMPLIB) not set for imported target "(unknown|static|shared)_lib"( configuration
+ "[^"]+")?.
+This warning is for project developers. Use -Wno-dev to suppress it.)*$
diff --git a/Tests/RunCMake/CMP0111/CMP0111-WARN.cmake b/Tests/RunCMake/CMP0111/CMP0111-WARN.cmake
new file mode 100644
index 0000000..0efe48c
--- /dev/null
+++ b/Tests/RunCMake/CMP0111/CMP0111-WARN.cmake
@@ -0,0 +1 @@
+include(CMP0111-Common.cmake)
diff --git a/Tests/RunCMake/CMP0111/CMakeLists.txt b/Tests/RunCMake/CMP0111/CMakeLists.txt
new file mode 100644
index 0000000..9f19a75
--- /dev/null
+++ b/Tests/RunCMake/CMP0111/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.17)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0111/RunCMakeTest.cmake b/Tests/RunCMake/CMP0111/RunCMakeTest.cmake
new file mode 100644
index 0000000..02e420a
--- /dev/null
+++ b/Tests/RunCMake/CMP0111/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0111-OLD)
+run_cmake(CMP0111-NEW)
+run_cmake(CMP0111-WARN)
diff --git a/Tests/RunCMake/CMP0111/module.cpp b/Tests/RunCMake/CMP0111/module.cpp
new file mode 100644
index 0000000..b82bb31
--- /dev/null
+++ b/Tests/RunCMake/CMP0111/module.cpp
@@ -0,0 +1,4 @@
+int module()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0115/CMP0115-NEW-result.txt b/Tests/RunCMake/CMP0115/CMP0115-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0115/CMP0115-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0115/CMP0115-NEW-stderr.txt b/Tests/RunCMake/CMP0115/CMP0115-NEW-stderr.txt
new file mode 100644
index 0000000..b63c53d
--- /dev/null
+++ b/Tests/RunCMake/CMP0115/CMP0115-NEW-stderr.txt
@@ -0,0 +1,17 @@
+^CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+ Cannot find source file:
+
+ main
+Call Stack \(most recent call first\):
+ CMP0115-NEW\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+ No SOURCES given to target: exe
+Call Stack \(most recent call first\):
+ CMP0115-NEW\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0115/CMP0115-NEW.cmake b/Tests/RunCMake/CMP0115/CMP0115-NEW.cmake
new file mode 100644
index 0000000..ddf5071
--- /dev/null
+++ b/Tests/RunCMake/CMP0115/CMP0115-NEW.cmake
@@ -0,0 +1 @@
+include(CMP0115.cmake)
diff --git a/Tests/RunCMake/CMP0115/CMP0115-OLD-result.txt b/Tests/RunCMake/CMP0115/CMP0115-OLD-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0115/CMP0115-OLD-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt b/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt
new file mode 100644
index 0000000..8b90311
--- /dev/null
+++ b/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt
@@ -0,0 +1,22 @@
+^CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+ Cannot find source file:
+
+ noexist
+
+ Tried extensions [^
+]*
+ [^
+]*
+Call Stack \(most recent call first\):
+ CMP0115-OLD\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+ No SOURCES given to target: exe
+Call Stack \(most recent call first\):
+ CMP0115-OLD\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0115/CMP0115-OLD.cmake b/Tests/RunCMake/CMP0115/CMP0115-OLD.cmake
new file mode 100644
index 0000000..ddf5071
--- /dev/null
+++ b/Tests/RunCMake/CMP0115/CMP0115-OLD.cmake
@@ -0,0 +1 @@
+include(CMP0115.cmake)
diff --git a/Tests/RunCMake/CMP0115/CMP0115-WARN-result.txt b/Tests/RunCMake/CMP0115/CMP0115-WARN-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0115/CMP0115-WARN-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt b/Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt
new file mode 100644
index 0000000..7b100b6
--- /dev/null
+++ b/Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt
@@ -0,0 +1,36 @@
+^CMake Warning \(dev\) at CMP0115\.cmake:[0-9]+ \(add_executable\):
+ Policy CMP0115 is not set: Source file extensions must be explicit\. Run
+ "cmake --help-policy CMP0115" for policy details\. Use the cmake_policy
+ command to set the policy and suppress this warning\.
+
+ File:
+
+ [^
+]*/Tests/RunCMake/CMP0115/main\.c
+Call Stack \(most recent call first\):
+ CMP0115-WARN\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
+
+CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+ Cannot find source file:
+
+ noexist
+
+ Tried extensions [^
+]*
+ [^
+]*
+Call Stack \(most recent call first\):
+ CMP0115-WARN\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+ No SOURCES given to target: exe
+Call Stack \(most recent call first\):
+ CMP0115-WARN\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0115/CMP0115-WARN.cmake b/Tests/RunCMake/CMP0115/CMP0115-WARN.cmake
new file mode 100644
index 0000000..ddf5071
--- /dev/null
+++ b/Tests/RunCMake/CMP0115/CMP0115-WARN.cmake
@@ -0,0 +1 @@
+include(CMP0115.cmake)
diff --git a/Tests/RunCMake/CMP0115/CMP0115.cmake b/Tests/RunCMake/CMP0115/CMP0115.cmake
new file mode 100644
index 0000000..be910a4
--- /dev/null
+++ b/Tests/RunCMake/CMP0115/CMP0115.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+
+add_executable(exe main noexist)
diff --git a/Tests/RunCMake/CMP0115/CMakeLists.txt b/Tests/RunCMake/CMP0115/CMakeLists.txt
new file mode 100644
index 0000000..b646c4a
--- /dev/null
+++ b/Tests/RunCMake/CMP0115/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.18)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0115/RunCMakeTest.cmake b/Tests/RunCMake/CMP0115/RunCMakeTest.cmake
new file mode 100644
index 0000000..58182ac
--- /dev/null
+++ b/Tests/RunCMake/CMP0115/RunCMakeTest.cmake
@@ -0,0 +1,12 @@
+include(RunCMake)
+
+function(run_cmp0115 status)
+ if(NOT status STREQUAL "WARN")
+ set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0115=${status})
+ endif()
+ run_cmake(CMP0115-${status})
+endfunction()
+
+run_cmp0115(OLD)
+run_cmp0115(WARN)
+run_cmp0115(NEW)
diff --git a/Tests/RunCMake/CMP0115/main.c b/Tests/RunCMake/CMP0115/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/CMP0115/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMP0116/CMP0116-Mixed-stderr.txt b/Tests/RunCMake/CMP0116/CMP0116-Mixed-stderr.txt
new file mode 100644
index 0000000..10e83a9
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/CMP0116-Mixed-stderr.txt
@@ -0,0 +1,17 @@
+^CMake Warning \(dev\) at CMP0116-Mixed\.cmake:1 \(add_custom_command\):
+ Policy CMP0116 is not set: Ninja generators transform DEPFILEs from
+ add_custom_command\(\)\. Run "cmake --help-policy CMP0116" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.(
+
+CMake Warning \(dev\) at CMP0116-Mixed\.cmake:1 \(add_custom_command\):
+ Policy CMP0116 is not set: Ninja generators transform DEPFILEs from
+ add_custom_command\(\)\. Run "cmake --help-policy CMP0116" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.)*$
diff --git a/Tests/RunCMake/CMP0116/CMP0116-Mixed.cmake b/Tests/RunCMake/CMP0116/CMP0116-Mixed.cmake
new file mode 100644
index 0000000..6cbbc09
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/CMP0116-Mixed.cmake
@@ -0,0 +1,18 @@
+add_custom_command(
+ OUTPUT warn.txt
+ COMMAND ${CMAKE_COMMAND} -E touch warn.txt
+ DEPFILE warn.d
+ )
+cmake_policy(SET CMP0116 OLD)
+add_custom_command(
+ OUTPUT old.txt
+ COMMAND ${CMAKE_COMMAND} -E touch old.txt
+ DEPFILE old.d
+ )
+cmake_policy(SET CMP0116 NEW)
+add_custom_command(
+ OUTPUT new.txt
+ COMMAND ${CMAKE_COMMAND} -E touch new.txt
+ DEPFILE new.d
+ )
+add_custom_target(cc ALL DEPENDS warn.txt old.txt new.txt)
diff --git a/Tests/RunCMake/CMP0116/CMP0116-NEW-NOWARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-NEW-NOWARN.cmake
new file mode 100644
index 0000000..f92fac6
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/CMP0116-NEW-NOWARN.cmake
@@ -0,0 +1,3 @@
+set(depdir)
+
+include(Common.cmake)
diff --git a/Tests/RunCMake/CMP0116/CMP0116-NEW-WARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-NEW-WARN.cmake
new file mode 100644
index 0000000..f92fac6
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/CMP0116-NEW-WARN.cmake
@@ -0,0 +1,3 @@
+set(depdir)
+
+include(Common.cmake)
diff --git a/Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN.cmake
new file mode 100644
index 0000000..665f485
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN.cmake
@@ -0,0 +1,3 @@
+set(depdir Subdirectory/)
+
+include(Common.cmake)
diff --git a/Tests/RunCMake/CMP0116/CMP0116-OLD-WARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-OLD-WARN.cmake
new file mode 100644
index 0000000..665f485
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/CMP0116-OLD-WARN.cmake
@@ -0,0 +1,3 @@
+set(depdir Subdirectory/)
+
+include(Common.cmake)
diff --git a/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN-stderr.txt b/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN-stderr.txt
new file mode 100644
index 0000000..843ff1c
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN-stderr.txt
@@ -0,0 +1,7 @@
+^(CMake Warning \(dev\) at Subdirectory/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ Policy CMP0116 is not set: Ninja generators transform DEPFILEs from
+ add_custom_command\(\)\. Run "cmake --help-policy CMP0116" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+This warning is for project developers\. Use -Wno-dev to suppress it\.
+*)+$
diff --git a/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN.cmake
new file mode 100644
index 0000000..665f485
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN.cmake
@@ -0,0 +1,3 @@
+set(depdir Subdirectory/)
+
+include(Common.cmake)
diff --git a/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN-stderr.txt b/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN-stderr.txt
new file mode 100644
index 0000000..e29af91
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN-stderr.txt
@@ -0,0 +1,16 @@
+^(CMake Warning \(dev\) at Common\.cmake:[0-9]+ \(add_custom_command\):
+ Policy CMP0116 is not set: Ninja generators transform DEPFILEs from
+ add_custom_command\(\)\. Run "cmake --help-policy CMP0116" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+Call Stack \(most recent call first\):
+ CMP0116-WARN-WARN\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+(CMake Warning \(dev\) at Subdirectory/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ Policy CMP0116 is not set: Ninja generators transform DEPFILEs from
+ add_custom_command\(\)\. Run "cmake --help-policy CMP0116" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+This warning is for project developers\. Use -Wno-dev to suppress it\.
+*)+$
diff --git a/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN.cmake
new file mode 100644
index 0000000..665f485
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN.cmake
@@ -0,0 +1,3 @@
+set(depdir Subdirectory/)
+
+include(Common.cmake)
diff --git a/Tests/RunCMake/CMP0116/CMakeLists.txt b/Tests/RunCMake/CMP0116/CMakeLists.txt
new file mode 100644
index 0000000..b646c4a
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.18)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0116/Common.cmake b/Tests/RunCMake/CMP0116/Common.cmake
new file mode 100644
index 0000000..472b162
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/Common.cmake
@@ -0,0 +1,8 @@
+add_custom_command(
+ OUTPUT top.txt
+ COMMAND ${CMAKE_COMMAND} -DOUTFILE=top.txt -DINFILE=topdep.txt -DDEPFILE=top.txt.d -DSTAMPFILE=topstamp.txt -DDEPDIR= -P ${CMAKE_SOURCE_DIR}/WriteDepfile.cmake
+ DEPFILE top.txt.d
+ )
+add_custom_target(top ALL DEPENDS top.txt)
+
+add_subdirectory(Subdirectory)
diff --git a/Tests/RunCMake/CMP0116/RunCMakeTest.cmake b/Tests/RunCMake/CMP0116/RunCMakeTest.cmake
new file mode 100644
index 0000000..ce3e86a
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/RunCMakeTest.cmake
@@ -0,0 +1,52 @@
+include(RunCMake)
+
+function(run_cmp0116 status warn)
+ if(warn)
+ set(name CMP0116-${status}-WARN)
+ else()
+ set(name CMP0116-${status}-NOWARN)
+ endif()
+ set(RunCMake_TEST_OPTIONS
+ -DCMAKE_POLICY_WARNING_CMP0116:BOOL=${warn}
+ )
+ if(NOT status STREQUAL "WARN")
+ list(APPEND RunCMake_TEST_OPTIONS
+ -DCMAKE_POLICY_DEFAULT_CMP0116:STRING=${status}
+ )
+ endif()
+
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build)
+ run_cmake(${name})
+ unset(RunCMake_TEST_OPTIONS)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ set(RunCMake-check-file check.cmake)
+
+ file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topdep.txt")
+ file(TOUCH "${RunCMake_TEST_BINARY_DIR}/Subdirectory/subdep.txt")
+ set(cmp0116_step 1)
+ run_cmake_command(${name}-build1 ${CMAKE_COMMAND} --build . --config Debug)
+ file(REMOVE "${RunCMake_TEST_BINARY_DIR}/topstamp.txt")
+ file(REMOVE "${RunCMake_TEST_BINARY_DIR}/Subdirectory/substamp.txt")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1.25)
+
+ file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topdep.txt")
+ file(TOUCH "${RunCMake_TEST_BINARY_DIR}/Subdirectory/subdep.txt")
+ set(cmp0116_step 2)
+ run_cmake_command(${name}-build2 ${CMAKE_COMMAND} --build . --config Debug)
+ file(REMOVE "${RunCMake_TEST_BINARY_DIR}/topstamp.txt")
+ file(REMOVE "${RunCMake_TEST_BINARY_DIR}/Subdirectory/substamp.txt")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1.25)
+
+ set(cmp0116_step 3)
+ run_cmake_command(${name}-build3 ${CMAKE_COMMAND} --build . --config Debug)
+endfunction()
+
+run_cmp0116(WARN OFF)
+run_cmp0116(OLD OFF)
+run_cmp0116(NEW OFF)
+run_cmp0116(WARN ON)
+run_cmp0116(OLD ON)
+run_cmp0116(NEW ON)
+
+set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_WARNING_CMP0116:BOOL=TRUE)
+run_cmake(CMP0116-Mixed)
diff --git a/Tests/RunCMake/CMP0116/Subdirectory/CMakeLists.txt b/Tests/RunCMake/CMP0116/Subdirectory/CMakeLists.txt
new file mode 100644
index 0000000..f0f60b2
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/Subdirectory/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_custom_command(
+ OUTPUT sub.txt
+ COMMAND ${CMAKE_COMMAND} -DOUTFILE=sub.txt -DINFILE=subdep.txt -DDEPFILE=sub.txt.d -DSTAMPFILE=substamp.txt -DDEPDIR=${depdir} -P ${CMAKE_SOURCE_DIR}/WriteDepfile.cmake
+ DEPFILE ${depdir}sub.txt.d
+ )
+add_custom_target(sub ALL DEPENDS sub.txt)
diff --git a/Tests/RunCMake/CMP0116/WriteDepfile.cmake b/Tests/RunCMake/CMP0116/WriteDepfile.cmake
new file mode 100644
index 0000000..1a74d2a
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/WriteDepfile.cmake
@@ -0,0 +1,3 @@
+file(TOUCH "${OUTFILE}")
+file(TOUCH "${STAMPFILE}")
+file(WRITE "${DEPFILE}" "${DEPDIR}${OUTFILE}: ${DEPDIR}${INFILE}\n")
diff --git a/Tests/RunCMake/CMP0116/check.cmake b/Tests/RunCMake/CMP0116/check.cmake
new file mode 100644
index 0000000..1b16748
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/check.cmake
@@ -0,0 +1,18 @@
+function(check_exists file)
+ if(NOT EXISTS "${file}")
+ string(APPEND RunCMake_TEST_FAILED "${file} does not exist\n")
+ endif()
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
+
+function(check_not_exists file)
+ if(EXISTS "${file}")
+ string(APPEND RunCMake_TEST_FAILED "${file} exists\n")
+ endif()
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
+
+if(cmp0116_step EQUAL 3)
+ check_not_exists("${RunCMake_TEST_BINARY_DIR}/topstamp.txt")
+ check_not_exists("${RunCMake_TEST_BINARY_DIR}/Subdirectory/substamp.txt")
+endif()
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Helper.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Helper.cmake
new file mode 100644
index 0000000..b237b7f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Helper.cmake
@@ -0,0 +1,14 @@
+macro(get_and_print_GENERATED_property filename)
+ get_property(prop SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${filename}" PROPERTY GENERATED)
+ message(NOTICE "${filename}: # 1a # GENERATED = `${prop}`")
+ get_source_file_property(prop "${CMAKE_CURRENT_BINARY_DIR}/${filename}" GENERATED)
+ message(NOTICE "${filename}: # 1b # GENERATED = `${prop}`")
+ get_property(prop SOURCE "${filename}" PROPERTY GENERATED)
+ message(NOTICE "${filename}: # 2a # GENERATED = `${prop}`")
+ get_source_file_property(prop "${filename}" GENERATED)
+ message(NOTICE "${filename}: # 2b # GENERATED = `${prop}`")
+ get_property(prop SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/${filename}" PROPERTY GENERATED)
+ message(NOTICE "${filename}: # 3a # GENERATED = `${prop}`")
+ get_source_file_property(prop "${CMAKE_CURRENT_SOURCE_DIR}/${filename}" GENERATED)
+ message(NOTICE "${filename}: # 3b # GENERATED = `${prop}`")
+endmacro()
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test1.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test1.cmake
new file mode 100644
index 0000000..2b66515
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test1.cmake
@@ -0,0 +1,9 @@
+add_custom_target(custom)
+target_sources(custom PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/GeneratedMain.txt"
+)
+
+get_property(prop SOURCE
+ "${CMAKE_CURRENT_BINARY_DIR}/GeneratedMain.txt"
+ PROPERTY GENERATED)
+message(NOTICE "prop: `${prop}`")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test10.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test10.cmake
new file mode 100644
index 0000000..d060207
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test10.cmake
@@ -0,0 +1,65 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+# The sources of custom0 will not be modified by set_property!
+add_custom_target(custom0)
+target_sources(custom0 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+# The sources of custom[1-6] will (tried to) be modified by set_property!
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+
+add_subdirectory(subdir-Common-Test10)
+
+get_and_print_GENERATED_property("Generated_source0.txt")
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test11.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test11.cmake
new file mode 100644
index 0000000..00b204e
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test11.cmake
@@ -0,0 +1,65 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+# The sources of custom0 will not be modified by set_property!
+add_custom_target(custom0)
+target_sources(custom0 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+# The sources of custom[1-6] will (tried to) be modified by set_property!
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+
+add_subdirectory(subdir-Common-Test11)
+
+get_and_print_GENERATED_property("Generated_source0.txt")
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test12.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test12.cmake
new file mode 100644
index 0000000..1182d17
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test12.cmake
@@ -0,0 +1,65 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+# The sources of custom0 will not be modified by set_property!
+add_custom_target(custom0)
+target_sources(custom0 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+# The sources of custom[1-6] will (tried to) be modified by set_property!
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+add_custom_command(TARGET custom0 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+add_custom_command(TARGET custom1 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_command(TARGET custom2 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_command(TARGET custom3 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+
+add_subdirectory(subdir-Common-Test12)
+
+get_and_print_GENERATED_property("Generated_source0.txt")
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test13.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test13.cmake
new file mode 100644
index 0000000..12f4ac1
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test13.cmake
@@ -0,0 +1,65 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+# The sources of custom0 will not be modified by set_property!
+add_custom_target(custom0)
+target_sources(custom0 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+# The sources of custom[1-6] will (tried to) be modified by set_property!
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+add_custom_command(TARGET custom0 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+add_custom_command(TARGET custom1 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_command(TARGET custom2 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_command(TARGET custom3 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+
+add_subdirectory(subdir-Common-Test13)
+
+get_and_print_GENERATED_property("Generated_source0.txt")
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test14.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test14.cmake
new file mode 100644
index 0000000..30e3edc
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test14.cmake
@@ -0,0 +1,65 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+# The sources of custom0 will not be modified by set_property!
+add_custom_target(custom0)
+target_sources(custom0 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+# The sources of custom[1-6] will (tried to) be modified by set_property!
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+add_custom_target(custom0_source_generator ALL
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+add_custom_target(custom1_source_generator ALL
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2_source_generator ALL
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3_source_generator ALL
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+
+add_subdirectory(subdir-Common-Test14)
+
+get_and_print_GENERATED_property("Generated_source0.txt")
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test15.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test15.cmake
new file mode 100644
index 0000000..fb05248
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test15.cmake
@@ -0,0 +1,65 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+# The sources of custom0 will not be modified by set_property!
+add_custom_target(custom0)
+target_sources(custom0 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+# The sources of custom[1-6] will (tried to) be modified by set_property!
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+add_custom_target(custom0_source_generator ALL
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+add_custom_target(custom1_source_generator ALL
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2_source_generator ALL
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3_source_generator ALL
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+
+add_subdirectory(subdir-Common-Test15)
+
+get_and_print_GENERATED_property("Generated_source0.txt")
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test2.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test2.cmake
new file mode 100644
index 0000000..1180b6b
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test2.cmake
@@ -0,0 +1,12 @@
+add_custom_target(custom)
+target_sources(custom PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/GeneratedMain.txt"
+)
+
+set_property(SOURCE
+ "${CMAKE_CURRENT_BINARY_DIR}/GeneratedMain.txt"
+ PROPERTY GENERATED "1")
+get_property(prop SOURCE
+ "${CMAKE_CURRENT_BINARY_DIR}/GeneratedMain.txt"
+ PROPERTY GENERATED)
+message(NOTICE "prop: `${prop}`")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test3.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test3.cmake
new file mode 100644
index 0000000..27516b7
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test3.cmake
@@ -0,0 +1,66 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path2.txt"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path3.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "Generated_with_relative_path1.txt"
+ "Generated_with_relative_path2.txt"
+ "Generated_with_relative_path3.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path1.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path2.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path3.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_path1.txt")
+
+set_property(SOURCE "Generated_with_full_path2.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_path3.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_relative_path1.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_relative_path1.txt")
+
+set_property(SOURCE "Generated_with_relative_path2.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_relative_path2.txt")
+
+set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_relative_path3.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_relative_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_source_path1.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_source_path1.txt")
+
+set_property(SOURCE "Generated_with_full_source_path2.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_source_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_source_path3.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_source_path3.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test3b.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test3b.cmake
new file mode 100644
index 0000000..3e03a1f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test3b.cmake
@@ -0,0 +1,66 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_path1.txt")
+
+set_property(SOURCE "Generated_with_full_path2.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_path3.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_relative_path1.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_relative_path1.txt")
+
+set_property(SOURCE "Generated_with_relative_path2.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_relative_path2.txt")
+
+set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_relative_path3.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_relative_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_source_path1.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_source_path1.txt")
+
+set_property(SOURCE "Generated_with_full_source_path2.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_source_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_source_path3.txt"
+ PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_source_path3.txt")
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path2.txt"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path3.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "Generated_with_relative_path1.txt"
+ "Generated_with_relative_path2.txt"
+ "Generated_with_relative_path3.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path1.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path2.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path3.txt"
+)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test4.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test4.cmake
new file mode 100644
index 0000000..953e26a
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test4.cmake
@@ -0,0 +1,66 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path2.txt"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path3.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "Generated_with_relative_path1.txt"
+ "Generated_with_relative_path2.txt"
+ "Generated_with_relative_path3.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path1.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path2.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path3.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_path1.txt")
+
+set_property(SOURCE "Generated_with_full_path2.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_path3.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_relative_path1.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_relative_path1.txt")
+
+set_property(SOURCE "Generated_with_relative_path2.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_relative_path2.txt")
+
+set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_relative_path3.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_relative_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_source_path1.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_source_path1.txt")
+
+set_property(SOURCE "Generated_with_full_source_path2.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_source_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_source_path3.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_source_path3.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test4b.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test4b.cmake
new file mode 100644
index 0000000..025caa8
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test4b.cmake
@@ -0,0 +1,66 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_path1.txt")
+
+set_property(SOURCE "Generated_with_full_path2.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_path3.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_relative_path1.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_relative_path1.txt")
+
+set_property(SOURCE "Generated_with_relative_path2.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_relative_path2.txt")
+
+set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_relative_path3.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_relative_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_source_path1.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_source_path1.txt")
+
+set_property(SOURCE "Generated_with_full_source_path2.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_source_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_source_path3.txt"
+ PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_source_path3.txt")
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path2.txt"
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path3.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "Generated_with_relative_path1.txt"
+ "Generated_with_relative_path2.txt"
+ "Generated_with_relative_path3.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path1.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path2.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path3.txt"
+)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test5.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test5.cmake
new file mode 100644
index 0000000..5349bff
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test5.cmake
@@ -0,0 +1,78 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "Generated_with_relative_path1.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "Generated_with_relative_path2.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+ "Generated_with_relative_path3.txt"
+)
+add_custom_target(custom7)
+target_sources(custom7 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path1.txt"
+)
+add_custom_target(custom8)
+target_sources(custom8 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path2.txt"
+)
+add_custom_target(custom9)
+target_sources(custom9 PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path3.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+ PROPERTY GENERATED "tRue")
+get_and_print_GENERATED_property("Generated_with_full_path1.txt")
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path2.txt"
+ PROPERTY GENERATED "SomeVar-NOTFOUND")
+get_and_print_GENERATED_property("Generated_with_full_path2.txt")
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path3.txt"
+ PROPERTY GENERATED "Junk-value")
+get_and_print_GENERATED_property("Generated_with_full_path3.txt")
+
+
+set_property(SOURCE "Generated_with_relative_path1.txt"
+ PROPERTY GENERATED "tRue")
+get_and_print_GENERATED_property("Generated_with_relative_path1.txt")
+
+set_property(SOURCE "Generated_with_relative_path2.txt"
+ PROPERTY GENERATED "SomeVar-NOTFOUND")
+get_and_print_GENERATED_property("Generated_with_relative_path2.txt")
+
+set_property(SOURCE "Generated_with_relative_path3.txt"
+ PROPERTY GENERATED "Junk-value")
+get_and_print_GENERATED_property("Generated_with_relative_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_source_path1.txt"
+ PROPERTY GENERATED "tRue")
+get_and_print_GENERATED_property("Generated_with_full_source_path1.txt")
+
+set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path2.txt"
+ PROPERTY GENERATED "SomeVar-NOTFOUND")
+get_and_print_GENERATED_property("Generated_with_full_source_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_source_path3.txt"
+ PROPERTY GENERATED "Junk-value")
+get_and_print_GENERATED_property("Generated_with_full_source_path3.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test6.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test6.cmake
new file mode 100644
index 0000000..a6f28aa
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test6.cmake
@@ -0,0 +1,44 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+ PROPERTY GENERATED "1")
+
+add_subdirectory(subdir-Common-Test6)
+
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test7.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test7.cmake
new file mode 100644
index 0000000..eed49b8
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test7.cmake
@@ -0,0 +1,44 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+ PROPERTY GENERATED "1")
+
+add_subdirectory(subdir-Common-Test7)
+
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test8.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test8.cmake
new file mode 100644
index 0000000..5cc6e99
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test8.cmake
@@ -0,0 +1,50 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+ CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+ CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+ CONTENT "int func();\nint main(){ return func(); }"
+)
+
+add_subdirectory(subdir-Common-Test8)
+
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test9.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test9.cmake
new file mode 100644
index 0000000..b7d36ef
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-Common-Test9.cmake
@@ -0,0 +1,50 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+ CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+ CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+ CONTENT "int func();\nint main(){ return func(); }"
+)
+
+add_subdirectory(subdir-Common-Test9)
+
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test1-result.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test1-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test1-stderr.txt
new file mode 100644
index 0000000..ec777f7
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test1-stderr.txt
@@ -0,0 +1,10 @@
+^prop: `0`
+CMake Error at CMP0118-Common-Test1\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-NEW-Test1-build/GeneratedMain\.txt
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test1\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test1.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test1.cmake
new file mode 100644
index 0000000..bbbee43
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test1.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test1.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test10-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test10-stderr.txt
new file mode 100644
index 0000000..2bd1cba
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test10-stderr.txt
@@ -0,0 +1,42 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test10.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test10.cmake
new file mode 100644
index 0000000..15a7178
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test10.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test10.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test11-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test11-stderr.txt
new file mode 100644
index 0000000..05b2353
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test11-stderr.txt
@@ -0,0 +1,55 @@
+^(CMake Warning \(dev\) at subdir-Common-Test11/CMakeLists\.txt:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+(CMake Warning \(dev\) at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_subdirectory\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test11\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+)+
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test11.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test11.cmake
new file mode 100644
index 0000000..cb87a86
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test11.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test11.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test12-result.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test12-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test12-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test12-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test12-stderr.txt
new file mode 100644
index 0000000..e6c429c
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test12-stderr.txt
@@ -0,0 +1,51 @@
+^CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test12.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test12.cmake
new file mode 100644
index 0000000..61bf977
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test12.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test12.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test13-result.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test13-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test13-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test13-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test13-stderr.txt
new file mode 100644
index 0000000..7802538
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test13-stderr.txt
@@ -0,0 +1,64 @@
+^CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+(CMake Warning \(dev\) at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+(CMake Warning \(dev\) at CMP0118-Common-Test13\.cmake:[0-9]+ \(add_subdirectory\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test13\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+)+
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test13.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test13.cmake
new file mode 100644
index 0000000..569e4c6
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test13.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test13.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test14-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test14-stderr.txt
new file mode 100644
index 0000000..2bd1cba
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test14-stderr.txt
@@ -0,0 +1,42 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test14.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test14.cmake
new file mode 100644
index 0000000..e7d8d77
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test14.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test14.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test15-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test15-stderr.txt
new file mode 100644
index 0000000..3166f45
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test15-stderr.txt
@@ -0,0 +1,55 @@
+^(CMake Warning \(dev\) at subdir-Common-Test15/CMakeLists\.txt:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+(CMake Warning \(dev\) at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_subdirectory\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test15\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+)+
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test15.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test15.cmake
new file mode 100644
index 0000000..93513ae
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test15.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test15.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test2-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test2-stderr.txt
new file mode 100644
index 0000000..403ce5a
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test2-stderr.txt
@@ -0,0 +1 @@
+^prop: `1`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test2.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test2.cmake
new file mode 100644
index 0000000..ee8233d
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test2.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test2.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3-result.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3-stderr.txt
new file mode 100644
index 0000000..f7d9f6b
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3-stderr.txt
@@ -0,0 +1,87 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test3\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test3\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test3\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test3\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3.cmake
new file mode 100644
index 0000000..b9533fd
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test3.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b-result.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b-stderr.txt
new file mode 100644
index 0000000..a876390
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b-stderr.txt
@@ -0,0 +1,87 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test3b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test3b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test3b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test3b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b.cmake
new file mode 100644
index 0000000..79631e7
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test3b.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4-result.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4-stderr.txt
new file mode 100644
index 0000000..b750ae7
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4-stderr.txt
@@ -0,0 +1,167 @@
+^CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4.cmake
new file mode 100644
index 0000000..8a7d35a
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test4.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b-result.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b-stderr.txt
new file mode 100644
index 0000000..580f04f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b-stderr.txt
@@ -0,0 +1,167 @@
+^CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4b-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4b-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4b-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4b-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4b-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b.cmake
new file mode 100644
index 0000000..c03a39d
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test4b.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test5-result.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test5-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test5-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test5-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test5-stderr.txt
new file mode 100644
index 0000000..e268a7a
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test5-stderr.txt
@@ -0,0 +1,174 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is set to NEW and the following non-boolean value given for
+ property 'GENERATED' is therefore not allowed:
+
+ Junk-value
+
+ Replace it with a boolean value!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is set to NEW and the following non-boolean value given for
+ property 'GENERATED' is therefore not allowed:
+
+ Junk-value
+
+ Replace it with a boolean value!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is set to NEW and the following non-boolean value given for
+ property 'GENERATED' is therefore not allowed:
+
+ Junk-value
+
+ Replace it with a boolean value!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test5.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test5.cmake
new file mode 100644
index 0000000..691f94a
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test5.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test5.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test6-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test6-stderr.txt
new file mode 100644
index 0000000..0c84cfe
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test6-stderr.txt
@@ -0,0 +1,36 @@
+^Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test6.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test6.cmake
new file mode 100644
index 0000000..09b87a5
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test6.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test6.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-result.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-stderr.txt
new file mode 100644
index 0000000..08eb682
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-stderr.txt
@@ -0,0 +1,74 @@
+^(CMake Warning \(dev\) at subdir-Common-Test7/CMakeLists\.txt:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+(CMake Warning \(dev\) at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_subdirectory\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+)+
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test7.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test7.cmake
new file mode 100644
index 0000000..ceb8beb
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test7.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test7.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test8-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test8-stderr.txt
new file mode 100644
index 0000000..f723875
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test8-stderr.txt
@@ -0,0 +1,36 @@
+^Generated_source1\.txt: # 1a # GENERATED = `0`
+Generated_source1\.txt: # 1b # GENERATED = `0`
+Generated_source1\.txt: # 2a # GENERATED = `0`
+Generated_source1\.txt: # 2b # GENERATED = `0`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test8.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test8.cmake
new file mode 100644
index 0000000..6878b94
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test8.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test8.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-result.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-stderr.txt
new file mode 100644
index 0000000..b7c496c
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-stderr.txt
@@ -0,0 +1,74 @@
+^(CMake Warning \(dev\) at subdir-Common-Test9/CMakeLists\.txt:[0-9]+ \(set_property\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+(CMake Warning \(dev\) at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_subdirectory\):
+ Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test9\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+)+
+Generated_source1\.txt: # 1a # GENERATED = `0`
+Generated_source1\.txt: # 1b # GENERATED = `0`
+Generated_source1\.txt: # 2a # GENERATED = `0`
+Generated_source1\.txt: # 2b # GENERATED = `0`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `0`
+Generated_source2\.txt: # 1b # GENERATED = `0`
+Generated_source2\.txt: # 2a # GENERATED = `0`
+Generated_source2\.txt: # 2b # GENERATED = `0`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `0`
+Generated_source3\.txt: # 1b # GENERATED = `0`
+Generated_source3\.txt: # 2a # GENERATED = `0`
+Generated_source3\.txt: # 2b # GENERATED = `0`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test9\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test9\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-NEW-Test9\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test9.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test9.cmake
new file mode 100644
index 0000000..00b05fd
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test9.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test9.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-stderr.txt
new file mode 100644
index 0000000..58144c8
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-stderr.txt
@@ -0,0 +1,10 @@
+^prop: `0`
+CMake Error at CMP0118-Common-Test1\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-build/GeneratedMain\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test1\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1.cmake
new file mode 100644
index 0000000..c18dd25
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test1.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-stderr.txt
new file mode 100644
index 0000000..1f1bc90
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-stderr.txt
@@ -0,0 +1,51 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test10\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test10\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10.cmake
new file mode 100644
index 0000000..b96973f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test10.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-stderr.txt
new file mode 100644
index 0000000..5c15f12
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-stderr.txt
@@ -0,0 +1,67 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test11\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test11\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test11\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11.cmake
new file mode 100644
index 0000000..d6ad7d2
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test11.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-stderr.txt
new file mode 100644
index 0000000..e6c429c
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-stderr.txt
@@ -0,0 +1,51 @@
+^CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12.cmake
new file mode 100644
index 0000000..b87b03a
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test12.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-stderr.txt
new file mode 100644
index 0000000..75dbf23
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-stderr.txt
@@ -0,0 +1,51 @@
+^CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13.cmake
new file mode 100644
index 0000000..17a135b
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test13.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-stderr.txt
new file mode 100644
index 0000000..12a913a
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-stderr.txt
@@ -0,0 +1,51 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test14\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test14\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14.cmake
new file mode 100644
index 0000000..0702291
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test14.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-stderr.txt
new file mode 100644
index 0000000..62db7ee
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-stderr.txt
@@ -0,0 +1,67 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test15\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test15\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test15\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15.cmake
new file mode 100644
index 0000000..c330d4e
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test15.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test2-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test2-stderr.txt
new file mode 100644
index 0000000..403ce5a
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test2-stderr.txt
@@ -0,0 +1 @@
+^prop: `1`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test2.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test2.cmake
new file mode 100644
index 0000000..3ea8800
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test2.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test2.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-stderr.txt
new file mode 100644
index 0000000..7f86d38
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-stderr.txt
@@ -0,0 +1,87 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test3\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test3\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test3\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test3\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3.cmake
new file mode 100644
index 0000000..c8f5a0e
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test3.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-stderr.txt
new file mode 100644
index 0000000..4104fc0
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-stderr.txt
@@ -0,0 +1,87 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test3b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test3b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test3b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test3b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b.cmake
new file mode 100644
index 0000000..0b046b4
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test3b.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-stderr.txt
new file mode 100644
index 0000000..7a16d0b
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-stderr.txt
@@ -0,0 +1,95 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4.cmake
new file mode 100644
index 0000000..2f77397
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test4.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-stderr.txt
new file mode 100644
index 0000000..5a5c4ec
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-stderr.txt
@@ -0,0 +1,95 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4b-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4b-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4b-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4b-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4b-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b.cmake
new file mode 100644
index 0000000..ce6726d
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test4b.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-stderr.txt
new file mode 100644
index 0000000..12fa617
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-stderr.txt
@@ -0,0 +1,111 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5.cmake
new file mode 100644
index 0000000..2de6d89
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test5.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-stderr.txt
new file mode 100644
index 0000000..7199f04
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-stderr.txt
@@ -0,0 +1,45 @@
+^Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test6\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test6\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6.cmake
new file mode 100644
index 0000000..b571052
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test6.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-stderr.txt
new file mode 100644
index 0000000..233fd8b
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-stderr.txt
@@ -0,0 +1,77 @@
+^Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `0`
+Generated_source2\.txt: # 1b # GENERATED = `0`
+Generated_source2\.txt: # 2a # GENERATED = `0`
+Generated_source2\.txt: # 2b # GENERATED = `0`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `0`
+Generated_source3\.txt: # 1b # GENERATED = `0`
+Generated_source3\.txt: # 2a # GENERATED = `0`
+Generated_source3\.txt: # 2b # GENERATED = `0`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7.cmake
new file mode 100644
index 0000000..551da23
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test7.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-stderr.txt
new file mode 100644
index 0000000..4aed2ed
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-stderr.txt
@@ -0,0 +1,45 @@
+^Generated_source1\.txt: # 1a # GENERATED = `0`
+Generated_source1\.txt: # 1b # GENERATED = `0`
+Generated_source1\.txt: # 2a # GENERATED = `0`
+Generated_source1\.txt: # 2b # GENERATED = `0`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test8\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test8\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8.cmake
new file mode 100644
index 0000000..2d9e3d3
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test8.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-stderr.txt
new file mode 100644
index 0000000..cea8c22
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-stderr.txt
@@ -0,0 +1,61 @@
+^Generated_source1\.txt: # 1a # GENERATED = `0`
+Generated_source1\.txt: # 1b # GENERATED = `0`
+Generated_source1\.txt: # 2a # GENERATED = `0`
+Generated_source1\.txt: # 2b # GENERATED = `0`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `0`
+Generated_source2\.txt: # 1b # GENERATED = `0`
+Generated_source2\.txt: # 2a # GENERATED = `0`
+Generated_source2\.txt: # 2b # GENERATED = `0`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `0`
+Generated_source3\.txt: # 1b # GENERATED = `0`
+Generated_source3\.txt: # 2a # GENERATED = `0`
+Generated_source3\.txt: # 2b # GENERATED = `0`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test9\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test9\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-OLD-Test9\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9.cmake
new file mode 100644
index 0000000..53f73d9
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test9.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-stderr.txt
new file mode 100644
index 0000000..e2a2cf5
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-stderr.txt
@@ -0,0 +1,10 @@
+^prop: `0`
+CMake Error at CMP0118-Common-Test1\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-build/GeneratedMain\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test1\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1.cmake
new file mode 100644
index 0000000..3c82f8e
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test1.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-stderr.txt
new file mode 100644
index 0000000..bce7681
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-stderr.txt
@@ -0,0 +1,51 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test10\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test10\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10.cmake
new file mode 100644
index 0000000..c639c40
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test10.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-stderr.txt
new file mode 100644
index 0000000..00c47e9
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-stderr.txt
@@ -0,0 +1,90 @@
+^((CMake Warning \(dev\) at subdir-Common-Test11/CMakeLists\.txt:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+
+(CMake Warning \(dev\) at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_subdirectory\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test11\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+)+
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test11\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test11\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test11\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11.cmake
new file mode 100644
index 0000000..4c9735d
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test11.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12-stderr.txt
new file mode 100644
index 0000000..e6c429c
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12-stderr.txt
@@ -0,0 +1,51 @@
+^CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12.cmake
new file mode 100644
index 0000000..79fa00a
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test12.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13-stderr.txt
new file mode 100644
index 0000000..6d59cb4
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13-stderr.txt
@@ -0,0 +1,74 @@
+^CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+ TARGET 'custom[4-6]' was not created in this directory\.
++
+((CMake Warning \(dev\) at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+
+(CMake Warning \(dev\) at CMP0118-Common-Test13\.cmake:[0-9]+ \(add_subdirectory\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test13\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+)+
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13.cmake
new file mode 100644
index 0000000..27f71c7
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test13.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-stderr.txt
new file mode 100644
index 0000000..5b7994c
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-stderr.txt
@@ -0,0 +1,51 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test14\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test14\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14.cmake
new file mode 100644
index 0000000..056f0ad
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test14.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-stderr.txt
new file mode 100644
index 0000000..c975c23
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-stderr.txt
@@ -0,0 +1,90 @@
+^((CMake Warning \(dev\) at subdir-Common-Test15/CMakeLists\.txt:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+
+(CMake Warning \(dev\) at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_subdirectory\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test15\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+)+
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test15\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test15\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test15\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15.cmake
new file mode 100644
index 0000000..acc8bf6
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test15.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test2-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test2-stderr.txt
new file mode 100644
index 0000000..403ce5a
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test2-stderr.txt
@@ -0,0 +1 @@
+^prop: `1`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test2.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test2.cmake
new file mode 100644
index 0000000..5a67974
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test2.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test2.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3-stderr.txt
new file mode 100644
index 0000000..142d8a0
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3-stderr.txt
@@ -0,0 +1,87 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test3\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test3\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test3\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test3\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3.cmake
new file mode 100644
index 0000000..7cdfacb
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test3.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b-stderr.txt
new file mode 100644
index 0000000..d4ef667
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b-stderr.txt
@@ -0,0 +1,87 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test3b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test3b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test3b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test3b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b.cmake
new file mode 100644
index 0000000..6dfc16a
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test3b.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4-stderr.txt
new file mode 100644
index 0000000..ceeb570
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4-stderr.txt
@@ -0,0 +1,212 @@
+^CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4.cmake
new file mode 100644
index 0000000..9d432a4
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test4.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b-stderr.txt
new file mode 100644
index 0000000..f8484d0
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b-stderr.txt
@@ -0,0 +1,212 @@
+^CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4b-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4b-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4b-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4b-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4b-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b.cmake
new file mode 100644
index 0000000..2e2c2bd
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test4b.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5-stderr.txt
new file mode 100644
index 0000000..0556391
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5-stderr.txt
@@ -0,0 +1,213 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Attempt to set property 'GENERATED' with the following non-boolean value
+ \(which will be interpreted as "0"\):
+
+ Junk-value
+
+ That exact value will not be retrievable\. A value of "0" will be returned
+ instead\.
+
+ This will be an error under policy CMP0118\.
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Attempt to set property 'GENERATED' with the following non-boolean value
+ \(which will be interpreted as "0"\):
+
+ Junk-value
+
+ That exact value will not be retrievable\. A value of "0" will be returned
+ instead\.
+
+ This will be an error under policy CMP0118\.
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Attempt to set property 'GENERATED' with the following non-boolean value
+ \(which will be interpreted as "0"\):
+
+ Junk-value
+
+ That exact value will not be retrievable\. A value of "0" will be returned
+ instead\.
+
+ This will be an error under policy CMP0118\.
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5.cmake
new file mode 100644
index 0000000..87e965e
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test5.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-stderr.txt
new file mode 100644
index 0000000..7d588a2
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-stderr.txt
@@ -0,0 +1,45 @@
+^Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test6\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test6\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6.cmake
new file mode 100644
index 0000000..6f1edbc
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test6.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-stderr.txt
new file mode 100644
index 0000000..8421061
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-stderr.txt
@@ -0,0 +1,100 @@
+^((CMake Warning \(dev\) at subdir-Common-Test7/CMakeLists\.txt:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+
+(CMake Warning \(dev\) at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_subdirectory\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+)+
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `0`
+Generated_source2\.txt: # 1b # GENERATED = `0`
+Generated_source2\.txt: # 2a # GENERATED = `0`
+Generated_source2\.txt: # 2b # GENERATED = `0`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `0`
+Generated_source3\.txt: # 1b # GENERATED = `0`
+Generated_source3\.txt: # 2a # GENERATED = `0`
+Generated_source3\.txt: # 2b # GENERATED = `0`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test7\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7.cmake
new file mode 100644
index 0000000..86af20d
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test7.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-stderr.txt
new file mode 100644
index 0000000..e0f17e6
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-stderr.txt
@@ -0,0 +1,45 @@
+^Generated_source1\.txt: # 1a # GENERATED = `0`
+Generated_source1\.txt: # 1b # GENERATED = `0`
+Generated_source1\.txt: # 2a # GENERATED = `0`
+Generated_source1\.txt: # 2b # GENERATED = `0`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test8\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test8\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8.cmake
new file mode 100644
index 0000000..6a0bb4c
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test8.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-stderr.txt
new file mode 100644
index 0000000..80f3edf
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-stderr.txt
@@ -0,0 +1,84 @@
+^((CMake Warning \(dev\) at subdir-Common-Test9/CMakeLists\.txt:[0-9]+ \(set_property\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+
+(CMake Warning \(dev\) at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_subdirectory\):
+ Policy CMP0118 is not set: The GENERATED source file property is now
+ visible in all directories\. Run "cmake --help-policy CMP0118" for policy
+ details\. Use the cmake_policy command to set the policy and suppress this
+ warning\.
+
+ Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test9\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
++)+)+
+Generated_source1\.txt: # 1a # GENERATED = `0`
+Generated_source1\.txt: # 1b # GENERATED = `0`
+Generated_source1\.txt: # 2a # GENERATED = `0`
+Generated_source1\.txt: # 2b # GENERATED = `0`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `0`
+Generated_source2\.txt: # 1b # GENERATED = `0`
+Generated_source2\.txt: # 2a # GENERATED = `0`
+Generated_source2\.txt: # 2b # GENERATED = `0`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `0`
+Generated_source3\.txt: # 1b # GENERATED = `0`
+Generated_source3\.txt: # 2a # GENERATED = `0`
+Generated_source3\.txt: # 2b # GENERATED = `0`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test9\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test9\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+ CMP0118-WARN-Test9\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9.cmake
new file mode 100644
index 0000000..c48c64e
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9.cmake
@@ -0,0 +1 @@
+include(CMP0118-Common-Test9.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMakeLists.txt b/Tests/RunCMake/CMP0118/CMakeLists.txt
new file mode 100644
index 0000000..957fe03
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.19)
+cmake_policy(SET CMP0115 NEW)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE)
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-Common.cmake b/Tests/RunCMake/CMP0118/GenInSubdir-Common.cmake
new file mode 100644
index 0000000..6012c79
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/GenInSubdir-Common.cmake
@@ -0,0 +1,2 @@
+add_custom_target(top)
+add_subdirectory(GenInSubdir)
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-NEW.cmake b/Tests/RunCMake/CMP0118/GenInSubdir-NEW.cmake
new file mode 100644
index 0000000..373e73d
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/GenInSubdir-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(GenInSubdir-Common.cmake)
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-OLD-result.txt b/Tests/RunCMake/CMP0118/GenInSubdir-OLD-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/GenInSubdir-OLD-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-OLD-stderr.txt b/Tests/RunCMake/CMP0118/GenInSubdir-OLD-stderr.txt
new file mode 100644
index 0000000..d3aa546
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/GenInSubdir-OLD-stderr.txt
@@ -0,0 +1,8 @@
+^CMake Error at GenInSubdir-Common.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+ [^
+]*/Tests/RunCMake/CMP0118/GenInSubdir-OLD-build/GenInSubdir/sub.txt
+Call Stack \(most recent call first\):
+ GenInSubdir-OLD.cmake:[0-9]+ \(include\)
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-OLD.cmake b/Tests/RunCMake/CMP0118/GenInSubdir-OLD.cmake
new file mode 100644
index 0000000..48be27e
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/GenInSubdir-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(GenInSubdir-Common.cmake)
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-WARN-result.txt b/Tests/RunCMake/CMP0118/GenInSubdir-WARN-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/GenInSubdir-WARN-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-WARN-stderr.txt b/Tests/RunCMake/CMP0118/GenInSubdir-WARN-stderr.txt
new file mode 100644
index 0000000..5eb8a34
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/GenInSubdir-WARN-stderr.txt
@@ -0,0 +1,8 @@
+^CMake Error at GenInSubdir-Common.cmake:[0-9]+ \(add_custom_target\):
+ Cannot find source file:
+
+ [^
+]*/Tests/RunCMake/CMP0118/GenInSubdir-WARN-build/GenInSubdir/sub.txt
+Call Stack \(most recent call first\):
+ GenInSubdir-WARN.cmake:[0-9]+ \(include\)
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-WARN.cmake b/Tests/RunCMake/CMP0118/GenInSubdir-WARN.cmake
new file mode 100644
index 0000000..8e7e395
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/GenInSubdir-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(GenInSubdir-Common.cmake)
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir/CMakeLists.txt b/Tests/RunCMake/CMP0118/GenInSubdir/CMakeLists.txt
new file mode 100644
index 0000000..3f1ce8d
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/GenInSubdir/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_custom_command(
+ OUTPUT sub.txt
+ COMMAND ${CMAKE_COMMAND} -E touch sub.txt
+ VERBATIM
+ )
+add_custom_target(gen DEPENDS sub.txt)
+
+add_dependencies(top gen)
+target_sources(top PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/sub.txt)
diff --git a/Tests/RunCMake/CMP0118/RunCMakeTest.cmake b/Tests/RunCMake/CMP0118/RunCMakeTest.cmake
new file mode 100644
index 0000000..f7f135e
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/RunCMakeTest.cmake
@@ -0,0 +1,59 @@
+include(RunCMake)
+
+run_cmake(GenInSubdir-OLD)
+run_cmake(GenInSubdir-WARN)
+run_cmake(GenInSubdir-NEW)
+
+run_cmake(CMP0118-OLD-Test1)
+run_cmake(CMP0118-OLD-Test2)
+run_cmake(CMP0118-OLD-Test3)
+run_cmake(CMP0118-OLD-Test3b)
+run_cmake(CMP0118-OLD-Test4)
+run_cmake(CMP0118-OLD-Test4b)
+run_cmake(CMP0118-OLD-Test5)
+run_cmake(CMP0118-OLD-Test6)
+run_cmake(CMP0118-OLD-Test7)
+run_cmake(CMP0118-OLD-Test8)
+run_cmake(CMP0118-OLD-Test9)
+run_cmake(CMP0118-OLD-Test10)
+run_cmake(CMP0118-OLD-Test11)
+run_cmake(CMP0118-OLD-Test12)
+run_cmake(CMP0118-OLD-Test13)
+run_cmake(CMP0118-OLD-Test14)
+run_cmake(CMP0118-OLD-Test15)
+
+run_cmake(CMP0118-WARN-Test1)
+run_cmake(CMP0118-WARN-Test2)
+run_cmake(CMP0118-WARN-Test3)
+run_cmake(CMP0118-WARN-Test3b)
+run_cmake(CMP0118-WARN-Test4)
+run_cmake(CMP0118-WARN-Test4b)
+run_cmake(CMP0118-WARN-Test5)
+run_cmake(CMP0118-WARN-Test6)
+run_cmake(CMP0118-WARN-Test7)
+run_cmake(CMP0118-WARN-Test8)
+run_cmake(CMP0118-WARN-Test9)
+run_cmake(CMP0118-WARN-Test10)
+run_cmake(CMP0118-WARN-Test11)
+run_cmake(CMP0118-WARN-Test12)
+run_cmake(CMP0118-WARN-Test13)
+run_cmake(CMP0118-WARN-Test14)
+run_cmake(CMP0118-WARN-Test15)
+
+run_cmake(CMP0118-NEW-Test1)
+run_cmake(CMP0118-NEW-Test2)
+run_cmake(CMP0118-NEW-Test3)
+run_cmake(CMP0118-NEW-Test3b)
+run_cmake(CMP0118-NEW-Test4)
+run_cmake(CMP0118-NEW-Test4b)
+run_cmake(CMP0118-NEW-Test5)
+run_cmake(CMP0118-NEW-Test6)
+run_cmake(CMP0118-NEW-Test7)
+run_cmake(CMP0118-NEW-Test8)
+run_cmake(CMP0118-NEW-Test9)
+run_cmake(CMP0118-NEW-Test10)
+run_cmake(CMP0118-NEW-Test11)
+run_cmake(CMP0118-NEW-Test12)
+run_cmake(CMP0118-NEW-Test13)
+run_cmake(CMP0118-NEW-Test14)
+run_cmake(CMP0118-NEW-Test15)
diff --git a/Tests/RunCMake/CMP0118/source.cpp.in b/Tests/RunCMake/CMP0118/source.cpp.in
new file mode 100644
index 0000000..678cd7a
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/source.cpp.in
@@ -0,0 +1,5 @@
+int func();
+int main()
+{
+ return func();
+}
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test10/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test10/CMakeLists.txt
new file mode 100644
index 0000000..6bc99cb
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/subdir-Common-Test10/CMakeLists.txt
@@ -0,0 +1,33 @@
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+)
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+)
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "1")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test11/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test11/CMakeLists.txt
new file mode 100644
index 0000000..fbd7e6f
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/subdir-Common-Test11/CMakeLists.txt
@@ -0,0 +1,33 @@
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+)
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+)
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "0")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test12/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test12/CMakeLists.txt
new file mode 100644
index 0000000..916725c
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/subdir-Common-Test12/CMakeLists.txt
@@ -0,0 +1,33 @@
+add_custom_command(TARGET custom4 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+)
+add_custom_command(TARGET custom5 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+)
+add_custom_command(TARGET custom6 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "1")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test13/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test13/CMakeLists.txt
new file mode 100644
index 0000000..f2929aa
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/subdir-Common-Test13/CMakeLists.txt
@@ -0,0 +1,33 @@
+add_custom_command(TARGET custom4 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+)
+add_custom_command(TARGET custom5 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+)
+add_custom_command(TARGET custom6 PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "0")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test14/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test14/CMakeLists.txt
new file mode 100644
index 0000000..7397db9
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/subdir-Common-Test14/CMakeLists.txt
@@ -0,0 +1,33 @@
+add_custom_target(custom4_source_generator ALL
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+)
+add_custom_target(custom5_source_generator ALL
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+)
+add_custom_target(custom6_source_generator ALL
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "1")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test15/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test15/CMakeLists.txt
new file mode 100644
index 0000000..314e427
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/subdir-Common-Test15/CMakeLists.txt
@@ -0,0 +1,33 @@
+add_custom_target(custom4_source_generator ALL
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+)
+add_custom_target(custom5_source_generator ALL
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+)
+add_custom_target(custom6_source_generator ALL
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "0")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test6/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test6/CMakeLists.txt
new file mode 100644
index 0000000..fa307d1
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/subdir-Common-Test6/CMakeLists.txt
@@ -0,0 +1,16 @@
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "1")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test7/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test7/CMakeLists.txt
new file mode 100644
index 0000000..6362f78
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/subdir-Common-Test7/CMakeLists.txt
@@ -0,0 +1,16 @@
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "0")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test8/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test8/CMakeLists.txt
new file mode 100644
index 0000000..55debd1
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/subdir-Common-Test8/CMakeLists.txt
@@ -0,0 +1,30 @@
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+ CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+ CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+ CONTENT "int func();\nint main(){ return func(); }"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "1")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test9/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test9/CMakeLists.txt
new file mode 100644
index 0000000..cdb8884
--- /dev/null
+++ b/Tests/RunCMake/CMP0118/subdir-Common-Test9/CMakeLists.txt
@@ -0,0 +1,30 @@
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+ CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+ CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+ CONTENT "int func();\nint main(){ return func(); }"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+ DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+ TARGET_DIRECTORY custom1
+ PROPERTY GENERATED "0")
diff --git a/Tests/RunCMake/CMP0119/AltExtC.zzz b/Tests/RunCMake/CMP0119/AltExtC.zzz
new file mode 100644
index 0000000..5b240eb
--- /dev/null
+++ b/Tests/RunCMake/CMP0119/AltExtC.zzz
@@ -0,0 +1,4 @@
+int main(void) {
+ int class = 0;
+ return class;
+}
diff --git a/Tests/RunCMake/CMP0119/AltExtCXX.zzz b/Tests/RunCMake/CMP0119/AltExtCXX.zzz
new file mode 100644
index 0000000..3c521ed
--- /dev/null
+++ b/Tests/RunCMake/CMP0119/AltExtCXX.zzz
@@ -0,0 +1,3 @@
+int main() {
+ return static_cast<int>(0);
+}
diff --git a/Tests/RunCMake/CMP0119/CMP0119-Common.cmake b/Tests/RunCMake/CMP0119/CMP0119-Common.cmake
new file mode 100644
index 0000000..f45895b
--- /dev/null
+++ b/Tests/RunCMake/CMP0119/CMP0119-Common.cmake
@@ -0,0 +1,4 @@
+enable_language(C)
+
+add_executable(AltExtC AltExtC.zzz)
+set_property(SOURCE AltExtC.zzz PROPERTY LANGUAGE C)
diff --git a/Tests/RunCMake/CMP0119/CMP0119-NEW.cmake b/Tests/RunCMake/CMP0119/CMP0119-NEW.cmake
new file mode 100644
index 0000000..df0ed48
--- /dev/null
+++ b/Tests/RunCMake/CMP0119/CMP0119-NEW.cmake
@@ -0,0 +1,6 @@
+cmake_policy(SET CMP0119 NEW)
+include(CMP0119-Common.cmake)
+
+enable_language(CXX)
+add_executable(AltExtCXX AltExtCXX.zzz)
+set_property(SOURCE AltExtCXX.zzz PROPERTY LANGUAGE CXX)
diff --git a/Tests/RunCMake/CMP0119/CMP0119-OLD-build-result.txt b/Tests/RunCMake/CMP0119/CMP0119-OLD-build-result.txt
new file mode 100644
index 0000000..d197c91
--- /dev/null
+++ b/Tests/RunCMake/CMP0119/CMP0119-OLD-build-result.txt
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/CMP0119/CMP0119-OLD-build-stderr.txt b/Tests/RunCMake/CMP0119/CMP0119-OLD-build-stderr.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/CMP0119/CMP0119-OLD-build-stderr.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/CMP0119/CMP0119-OLD.cmake b/Tests/RunCMake/CMP0119/CMP0119-OLD.cmake
new file mode 100644
index 0000000..9eaa200
--- /dev/null
+++ b/Tests/RunCMake/CMP0119/CMP0119-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0119 OLD)
+include(CMP0119-Common.cmake)
diff --git a/Tests/RunCMake/CMP0119/CMP0119-WARN-build-result.txt b/Tests/RunCMake/CMP0119/CMP0119-WARN-build-result.txt
new file mode 100644
index 0000000..d197c91
--- /dev/null
+++ b/Tests/RunCMake/CMP0119/CMP0119-WARN-build-result.txt
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/CMP0119/CMP0119-WARN-build-stderr.txt b/Tests/RunCMake/CMP0119/CMP0119-WARN-build-stderr.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/CMP0119/CMP0119-WARN-build-stderr.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/CMP0119/CMP0119-WARN.cmake b/Tests/RunCMake/CMP0119/CMP0119-WARN.cmake
new file mode 100644
index 0000000..00281e9
--- /dev/null
+++ b/Tests/RunCMake/CMP0119/CMP0119-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0119-Common.cmake)
diff --git a/Tests/RunCMake/CMP0119/CMakeLists.txt b/Tests/RunCMake/CMP0119/CMakeLists.txt
new file mode 100644
index 0000000..ab1a20c
--- /dev/null
+++ b/Tests/RunCMake/CMP0119/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0119/RunCMakeTest.cmake b/Tests/RunCMake/CMP0119/RunCMakeTest.cmake
new file mode 100644
index 0000000..e547ef5
--- /dev/null
+++ b/Tests/RunCMake/CMP0119/RunCMakeTest.cmake
@@ -0,0 +1,17 @@
+include(RunCMake)
+
+function(run_CMP0119 status)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0119-${status}-build)
+ run_cmake(CMP0119-${status})
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(CMP0119-${status}-build "${CMAKE_COMMAND}" --build . --config Debug)
+endfunction()
+
+if(NOT RunCMake_GENERATOR MATCHES "Visual Studio|Xcode" AND
+ NOT CMAKE_C_COMPILER_ID MATCHES "(Borland|Embarcadero|Watcom)")
+ run_CMP0119(WARN)
+ run_CMP0119(OLD)
+endif()
+if((CMAKE_C_COMPILER_ID MATCHES "(GNU|Clang|MSVC|Borland|Embarcadero|Intel|TI)"))
+ run_CMP0119(NEW)
+endif()
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-Common.cmake b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-Common.cmake
new file mode 100644
index 0000000..5594be8
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-Common.cmake
@@ -0,0 +1,8 @@
+set(listvar a b c d e)
+
+list(GET listvar
+ 18446744073709551616 # 2^64
+ 2147483648 # 2^31
+ 4294967296 # 2^32; errors out-of-range as -2147483643 due to underflow
+ out)
+message("ERANGE: -->${out}<--")
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW-result.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW-stderr.txt
new file mode 100644
index 0000000..0166e14
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0121-ERANGE-Common.cmake:3 \(list\):
+ list index: 18446744073709551616 is not a valid index
+Call Stack \(most recent call first\):
+ CMP0121-ERANGE-NEW.cmake:2 \(include\)
+ CMakeLists.txt:3 \(include\)
+
+
+ERANGE: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW.cmake b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW.cmake
new file mode 100644
index 0000000..68e564d
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 NEW)
+include(CMP0121-ERANGE-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-result.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-stderr.txt
new file mode 100644
index 0000000..5a03559
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0121-ERANGE-Common.cmake:3 \(list\):
+ list index: (-2147483643|2147483647) out of range \(-5, 4\)
+Call Stack \(most recent call first\):
+ CMP0121-ERANGE-OLD.cmake:2 \(include\)
+ CMakeLists.txt:3 \(include\)
+
+
+ERANGE: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD.cmake b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD.cmake
new file mode 100644
index 0000000..32f0b56
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 OLD)
+include(CMP0121-ERANGE-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-result.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt
new file mode 100644
index 0000000..1e7b127
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt
@@ -0,0 +1,18 @@
+CMake Warning \(dev\) at CMP0121-ERANGE-Common.cmake:3 \(list\):
+ Policy CMP0121 is not set: The list\(\) command now validates parsing of
+ index arguments. Run "cmake --help-policy CMP0121" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
+ Invalid list index "18446744073709551616".
+Call Stack \(most recent call first\):
+ CMP0121-ERANGE-WARN.cmake:2 \(include\)
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+CMake Error at CMP0121-ERANGE-Common.cmake:3 \(list\):
+ list index: (-2147483643|2147483647) out of range \(-5, 4\)
+Call Stack \(most recent call first\):
+ CMP0121-ERANGE-WARN.cmake:2 \(include\)
+ CMakeLists.txt:3 \(include\)
+
+
+ERANGE: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN.cmake b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN.cmake
new file mode 100644
index 0000000..9655290
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0121-ERANGE-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-Common.cmake b/Tests/RunCMake/CMP0121/CMP0121-GET-Common.cmake
new file mode 100644
index 0000000..e4986f0
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-Common.cmake
@@ -0,0 +1,4 @@
+set(listvar a b c d e)
+
+list(GET listvar 0 2junk out)
+message("GET: -->${out}<--")
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-NEW-result.txt b/Tests/RunCMake/CMP0121/CMP0121-GET-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-NEW-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-GET-NEW-stderr.txt
new file mode 100644
index 0000000..d502b86
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-NEW-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0121-GET-Common.cmake:3 \(list\):
+ list index: 2junk is not a valid index
+Call Stack \(most recent call first\):
+ CMP0121-GET-NEW.cmake:2 \(include\)
+ CMakeLists.txt:3 \(include\)
+
+
+GET: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-NEW.cmake b/Tests/RunCMake/CMP0121/CMP0121-GET-NEW.cmake
new file mode 100644
index 0000000..1ab054d
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 NEW)
+include(CMP0121-GET-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-OLD-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-GET-OLD-stderr.txt
new file mode 100644
index 0000000..96375e9
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-OLD-stderr.txt
@@ -0,0 +1 @@
+GET: -->a;c<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-OLD.cmake b/Tests/RunCMake/CMP0121/CMP0121-GET-OLD.cmake
new file mode 100644
index 0000000..ef4526f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 OLD)
+include(CMP0121-GET-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-WARN-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-GET-WARN-stderr.txt
new file mode 100644
index 0000000..ecfad2c
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-WARN-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at CMP0121-GET-Common.cmake:3 \(list\):
+ Policy CMP0121 is not set: The list\(\) command now validates parsing of
+ index arguments. Run "cmake --help-policy CMP0121" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
+ Invalid list index "2junk".
+Call Stack \(most recent call first\):
+ CMP0121-GET-WARN.cmake:2 \(include\)
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+GET: -->a;c<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-WARN.cmake b/Tests/RunCMake/CMP0121/CMP0121-GET-WARN.cmake
new file mode 100644
index 0000000..b08620b
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0121-GET-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-Common.cmake b/Tests/RunCMake/CMP0121/CMP0121-INSERT-Common.cmake
new file mode 100644
index 0000000..4950881
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-Common.cmake
@@ -0,0 +1,4 @@
+set(listvar a b c d e)
+
+list(INSERT listvar junk2 new)
+message("INSERT: -->${listvar}<--")
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW-result.txt b/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW-stderr.txt
new file mode 100644
index 0000000..2241962
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0121-INSERT-Common.cmake:3 \(list\):
+ list index: junk2 is not a valid index
+Call Stack \(most recent call first\):
+ CMP0121-INSERT-NEW.cmake:2 \(include\)
+ CMakeLists.txt:3 \(include\)
+
+
+INSERT: -->a;b;c;d;e<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW.cmake b/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW.cmake
new file mode 100644
index 0000000..db627d1
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 NEW)
+include(CMP0121-INSERT-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-OLD-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-INSERT-OLD-stderr.txt
new file mode 100644
index 0000000..52f34ad
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-OLD-stderr.txt
@@ -0,0 +1 @@
+INSERT: -->new;a;b;c;d;e<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-OLD.cmake b/Tests/RunCMake/CMP0121/CMP0121-INSERT-OLD.cmake
new file mode 100644
index 0000000..60364d7
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 OLD)
+include(CMP0121-INSERT-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-WARN-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-INSERT-WARN-stderr.txt
new file mode 100644
index 0000000..5fa7d17
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-WARN-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at CMP0121-INSERT-Common.cmake:3 \(list\):
+ Policy CMP0121 is not set: The list\(\) command now validates parsing of
+ index arguments. Run "cmake --help-policy CMP0121" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
+ Invalid list index "junk2".
+Call Stack \(most recent call first\):
+ CMP0121-INSERT-WARN.cmake:2 \(include\)
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+INSERT: -->new;a;b;c;d;e<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-WARN.cmake b/Tests/RunCMake/CMP0121/CMP0121-INSERT-WARN.cmake
new file mode 100644
index 0000000..55f13e2
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0121-INSERT-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-Common.cmake b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-Common.cmake
new file mode 100644
index 0000000..ec92387
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-Common.cmake
@@ -0,0 +1,4 @@
+set(listvar a b c d e)
+
+list(REMOVE_AT listvar 0 invalid)
+message("REMOVE_AT: -->${listvar}<--")
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW-result.txt b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW-stderr.txt
new file mode 100644
index 0000000..f17bafd
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0121-REMOVE_AT-Common.cmake:3 \(list\):
+ list index: invalid is not a valid index
+Call Stack \(most recent call first\):
+ CMP0121-REMOVE_AT-NEW.cmake:2 \(include\)
+ CMakeLists.txt:3 \(include\)
+
+
+REMOVE_AT: -->a;b;c;d;e<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW.cmake b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW.cmake
new file mode 100644
index 0000000..d1f09e3
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 NEW)
+include(CMP0121-REMOVE_AT-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-OLD-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-OLD-stderr.txt
new file mode 100644
index 0000000..09af1ae
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-OLD-stderr.txt
@@ -0,0 +1 @@
+REMOVE_AT: -->b;c;d;e<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-OLD.cmake b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-OLD.cmake
new file mode 100644
index 0000000..ac83226
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 OLD)
+include(CMP0121-REMOVE_AT-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-WARN-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-WARN-stderr.txt
new file mode 100644
index 0000000..e2d47af
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-WARN-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at CMP0121-REMOVE_AT-Common.cmake:3 \(list\):
+ Policy CMP0121 is not set: The list\(\) command now validates parsing of
+ index arguments. Run "cmake --help-policy CMP0121" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
+ Invalid list index "invalid".
+Call Stack \(most recent call first\):
+ CMP0121-REMOVE_AT-WARN.cmake:2 \(include\)
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+REMOVE_AT: -->b;c;d;e<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-WARN.cmake b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-WARN.cmake
new file mode 100644
index 0000000..2b4a824
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0121-REMOVE_AT-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-Common.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-Common.cmake
new file mode 100644
index 0000000..93f46c5
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-Common.cmake
@@ -0,0 +1,4 @@
+set(listvar a b c d e)
+
+list(SUBLIST listvar 0 invalid out)
+message("SUBLIST-length: -->${out}<--")
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW-result.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW-stderr.txt
new file mode 100644
index 0000000..28bd362
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0121-SUBLIST-length-Common.cmake:3 \(list\):
+ list index: invalid is not a valid index
+Call Stack \(most recent call first\):
+ CMP0121-SUBLIST-length-NEW.cmake:2 \(include\)
+ CMakeLists.txt:3 \(include\)
+
+
+SUBLIST-length: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW.cmake
new file mode 100644
index 0000000..c7875cb
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 NEW)
+include(CMP0121-SUBLIST-length-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-OLD-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-OLD-stderr.txt
new file mode 100644
index 0000000..00fcf07
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-OLD-stderr.txt
@@ -0,0 +1 @@
+SUBLIST-length: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-OLD.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-OLD.cmake
new file mode 100644
index 0000000..e9b78ee
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 OLD)
+include(CMP0121-SUBLIST-length-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-WARN-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-WARN-stderr.txt
new file mode 100644
index 0000000..bd06c2f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-WARN-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at CMP0121-SUBLIST-length-Common.cmake:3 \(list\):
+ Policy CMP0121 is not set: The list\(\) command now validates parsing of
+ index arguments. Run "cmake --help-policy CMP0121" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
+ Invalid list index "invalid".
+Call Stack \(most recent call first\):
+ CMP0121-SUBLIST-length-WARN.cmake:2 \(include\)
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+SUBLIST-length: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-WARN.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-WARN.cmake
new file mode 100644
index 0000000..27318bf
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0121-SUBLIST-length-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-Common.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-Common.cmake
new file mode 100644
index 0000000..33f57a3
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-Common.cmake
@@ -0,0 +1,4 @@
+set(listvar a b c d e)
+
+list(SUBLIST listvar invalid 2 out)
+message("SUBLIST-start: -->${out}<--")
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW-result.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW-stderr.txt
new file mode 100644
index 0000000..9819f95
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0121-SUBLIST-start-Common.cmake:3 \(list\):
+ list index: invalid is not a valid index
+Call Stack \(most recent call first\):
+ CMP0121-SUBLIST-start-NEW.cmake:2 \(include\)
+ CMakeLists.txt:3 \(include\)
+
+
+SUBLIST-start: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW.cmake
new file mode 100644
index 0000000..3d676a3
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 NEW)
+include(CMP0121-SUBLIST-start-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-OLD-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-OLD-stderr.txt
new file mode 100644
index 0000000..8da2881
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-OLD-stderr.txt
@@ -0,0 +1 @@
+SUBLIST-start: -->a;b<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-OLD.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-OLD.cmake
new file mode 100644
index 0000000..268f317
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 OLD)
+include(CMP0121-SUBLIST-start-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-WARN-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-WARN-stderr.txt
new file mode 100644
index 0000000..39d0e0e
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-WARN-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at CMP0121-SUBLIST-start-Common.cmake:3 \(list\):
+ Policy CMP0121 is not set: The list\(\) command now validates parsing of
+ index arguments. Run "cmake --help-policy CMP0121" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
+ Invalid list index "invalid".
+Call Stack \(most recent call first\):
+ CMP0121-SUBLIST-start-WARN.cmake:2 \(include\)
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+SUBLIST-start: -->a;b<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-WARN.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-WARN.cmake
new file mode 100644
index 0000000..a407879
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0121-SUBLIST-start-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMakeLists.txt b/Tests/RunCMake/CMP0121/CMakeLists.txt
new file mode 100644
index 0000000..7cabeb6
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.20)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0121/RunCMakeTest.cmake b/Tests/RunCMake/CMP0121/RunCMakeTest.cmake
new file mode 100644
index 0000000..1ed5b1a
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/RunCMakeTest.cmake
@@ -0,0 +1,7 @@
+include(RunCMake)
+
+foreach (subcommand IN ITEMS ERANGE GET INSERT REMOVE_AT SUBLIST-length SUBLIST-start)
+ run_cmake(CMP0121-${subcommand}-WARN)
+ run_cmake(CMP0121-${subcommand}-OLD)
+ run_cmake(CMP0121-${subcommand}-NEW)
+endforeach ()
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
new file mode 100644
index 0000000..5f23c05
--- /dev/null
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -0,0 +1,837 @@
+# See adjacent README.rst for documentation of this test infrastructure.
+
+# Note that the _isMultiConfig variable is set in the parent directory's
+# CMakeLists.txt (slightly complex logic to support CMake versions before 3.9)
+
+macro(add_RunCMake_test test)
+ set(TEST_ARGS ${ARGN})
+ if ("${ARGV1}" STREQUAL "TEST_DIR")
+ if ("${ARGV2}" STREQUAL "")
+ message(FATAL_ERROR "Invalid args")
+ endif()
+ set(Test_Dir ${ARGV2})
+ list(REMOVE_AT TEST_ARGS 0)
+ list(REMOVE_AT TEST_ARGS 0)
+ else()
+ set(Test_Dir ${test})
+ endif()
+ add_test(NAME RunCMake.${test} COMMAND ${CMAKE_CMAKE_COMMAND}
+ -DCMAKE_MODULE_PATH=${CMAKE_CURRENT_SOURCE_DIR}
+ -DRunCMake_GENERATOR_IS_MULTI_CONFIG=${_isMultiConfig}
+ -DRunCMake_GENERATOR=${CMAKE_GENERATOR}
+ -DRunCMake_GENERATOR_INSTANCE=${CMAKE_GENERATOR_INSTANCE}
+ -DRunCMake_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
+ -DRunCMake_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
+ -DRunCMake_MAKE_PROGRAM=${CMake_TEST_EXPLICIT_MAKE_PROGRAM}
+ -DRunCMake_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/${Test_Dir}
+ -DRunCMake_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/${test}
+ ${${test}_ARGS}
+ ${TEST_ARGS}
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/${Test_Dir}/RunCMakeTest.cmake"
+ )
+ set_tests_properties("RunCMake.${test}" PROPERTIES LABELS "CMake;run")
+ if(${test} MATCHES ^CMP)
+ set_property(TEST "RunCMake.${test}" APPEND PROPERTY LABELS "policy")
+ endif()
+endmacro()
+
+function(add_RunCMake_test_group test types)
+ # create directory for common content
+ set(TEST_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}/${test}/conf")
+ file(REMOVE_RECURSE "${TEST_CONFIG_DIR}")
+ file(MAKE_DIRECTORY "${TEST_CONFIG_DIR}")
+
+ foreach(type IN LISTS types)
+ # generate prerequirements config file in cmake as ctest doesn't have as
+ # much system information so it is easier to set programs and environment
+ # values here
+ unset(${test}_${type}_FOUND_PREREQUIREMENTS)
+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${test}/${type}/Prerequirements.cmake")
+ include("${CMAKE_CURRENT_SOURCE_DIR}/${test}/${type}/Prerequirements.cmake")
+ else()
+ string(REGEX MATCH "^[^.]*" main_type "${type}")
+ include("${CMAKE_CURRENT_SOURCE_DIR}/${test}/${main_type}/Prerequirements.cmake")
+ endif()
+ get_test_prerequirements("${test}_${type}_FOUND_PREREQUIREMENTS"
+ "${TEST_CONFIG_DIR}/${type}_config.cmake")
+
+ # only add the test if prerequirements are met
+ if(${test}_${type}_FOUND_PREREQUIREMENTS)
+ add_test(NAME RunCMake.${test}_${type} COMMAND ${CMAKE_CMAKE_COMMAND}
+ -DTEST_TYPE=${type}
+ -DCMAKE_MODULE_PATH=${CMAKE_CURRENT_SOURCE_DIR}
+ -DRunCMake_GENERATOR_IS_MULTI_CONFIG=${_isMultiConfig}
+ -DRunCMake_GENERATOR=${CMAKE_GENERATOR}
+ -DRunCMake_GENERATOR_INSTANCE=${CMAKE_GENERATOR_INSTANCE}
+ -DRunCMake_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
+ -DRunCMake_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
+ -DRunCMake_MAKE_PROGRAM=${CMake_TEST_EXPLICIT_MAKE_PROGRAM}
+ -DRunCMake_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/${test}
+ -DRunCMake_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/${type}/${test}
+ -Dconfig_file=${TEST_CONFIG_DIR}/${type}_config.cmake
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/${test}/RunCMakeTest.cmake"
+ )
+ endif()
+ endforeach()
+endfunction()
+
+# Some tests use python for extra checks.
+find_package(PythonInterp QUIET)
+
+if(XCODE_VERSION AND "${XCODE_VERSION}" VERSION_LESS 6.1)
+ set(Swift_ARGS -DXCODE_BELOW_6_1=1)
+endif()
+
+# Test MSVC for older host CMake versions, and test
+# WIN32/CMAKE_C_COMPILER_ID to fix check on Intel for Windows.
+if(MSVC OR (WIN32 AND CMAKE_C_COMPILER_ID MATCHES "MSVC|Intel"))
+ set(LINKER_SUPPORTS_PDB 1)
+else()
+ set(LINKER_SUPPORTS_PDB 0)
+endif()
+
+add_RunCMake_test(CMP0019)
+add_RunCMake_test(CMP0022)
+add_RunCMake_test(CMP0026)
+add_RunCMake_test(CMP0027)
+add_RunCMake_test(CMP0028)
+add_RunCMake_test(CMP0037)
+add_RunCMake_test(CMP0038)
+add_RunCMake_test(CMP0039)
+add_RunCMake_test(CMP0040)
+add_RunCMake_test(CMP0041)
+if(CMAKE_SYSTEM_NAME MATCHES Darwin AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG)
+ add_RunCMake_test(CMP0042)
+endif()
+add_RunCMake_test(CMP0043)
+add_RunCMake_test(CMP0045)
+add_RunCMake_test(CMP0046)
+add_RunCMake_test(CMP0049)
+add_RunCMake_test(CMP0050)
+add_RunCMake_test(CMP0051)
+add_RunCMake_test(CMP0053)
+add_RunCMake_test(CMP0054)
+add_RunCMake_test(CMP0055)
+add_RunCMake_test(CMP0057)
+add_RunCMake_test(CMP0059)
+add_RunCMake_test(CMP0060)
+add_RunCMake_test(CMP0064)
+if(CMAKE_SYSTEM_NAME MATCHES Darwin AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG)
+ add_RunCMake_test(CMP0068)
+endif()
+add_RunCMake_test(CMP0069)
+add_RunCMake_test(CMP0081)
+add_RunCMake_test(CMP0102)
+if(CMake_TEST_CUDA)
+ add_RunCMake_test(CMP0104)
+ set_property(TEST RunCMake.CMP0104 APPEND
+ PROPERTY LABELS "CUDA")
+endif()
+add_RunCMake_test(CMP0106)
+add_RunCMake_test(CMP0111)
+add_RunCMake_test(CMP0115)
+if(CMAKE_GENERATOR MATCHES "Ninja")
+ add_RunCMake_test(CMP0116)
+endif()
+add_RunCMake_test(CMP0118)
+add_RunCMake_test(CMP0119 -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
+add_RunCMake_test(CMP0121)
+
+# The test for Policy 65 requires the use of the
+# CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode
+# generators ignore. The policy will have no effect on those generators.
+if(NOT CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
+ add_RunCMake_test(CMP0065 -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME})
+endif()
+if(CMAKE_GENERATOR MATCHES "Make")
+ add_RunCMake_test(Make -DMAKE_IS_GNU=${MAKE_IS_GNU})
+endif()
+if(CMake_TEST_Qt5)
+ find_package(Qt5Widgets QUIET NO_MODULE)
+endif()
+if(CMAKE_GENERATOR MATCHES "Ninja")
+ set(Ninja_ARGS
+ -DCMAKE_C_OUTPUT_EXTENSION=${CMAKE_C_OUTPUT_EXTENSION}
+ -DCMAKE_SHARED_LIBRARY_PREFIX=${CMAKE_SHARED_LIBRARY_PREFIX}
+ -DCMAKE_SHARED_LIBRARY_SUFFIX=${CMAKE_SHARED_LIBRARY_SUFFIX})
+ if(CMAKE_Fortran_COMPILER)
+ list(APPEND Ninja_ARGS -DTEST_Fortran=1)
+ endif()
+ if(CMake_TEST_Qt5 AND Qt5Core_FOUND)
+ list(APPEND Ninja_ARGS -DCMake_TEST_Qt5=1 -DQt5Core_DIR=${Qt5Core_DIR} -DCMAKE_TEST_Qt5Core_Version=${Qt5Core_VERSION})
+ if(Qt5Widgets_FOUND)
+ list(APPEND Ninja_ARGS -DQt5Widgets_DIR=${Qt5Widgets_DIR})
+ endif()
+ endif()
+ add_RunCMake_test(Ninja)
+ set(NinjaMultiConfig_ARGS
+ -DCYGWIN=${CYGWIN}
+ )
+ if(CMake_TEST_Qt5 AND Qt5Core_FOUND)
+ list(APPEND NinjaMultiConfig_ARGS -DCMake_TEST_Qt5=1 -DQt5Core_DIR=${Qt5Core_DIR} -DCMAKE_TEST_Qt5Core_Version=${Qt5Core_VERSION})
+ endif()
+ if(DEFINED CMake_TEST_CUDA)
+ list(APPEND NinjaMultiConfig_ARGS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
+ endif()
+ add_RunCMake_test(NinjaMultiConfig)
+ set_property(TEST RunCMake.NinjaMultiConfig APPEND
+ PROPERTY LABELS "CUDA")
+endif()
+add_RunCMake_test(CTest)
+
+if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ add_RunCMake_test(ctest_memcheck
+ -DPSEUDO_BC=$<TARGET_FILE:pseudo_BC>
+ -DPSEUDO_PURIFY=$<TARGET_FILE:pseudo_purify>
+ -DPSEUDO_VALGRIND=$<TARGET_FILE:pseudo_valgrind>
+ -DPSEUDO_CUDA_SANITIZER=$<TARGET_FILE:pseudo_cuda-memcheck>
+ -DPSEUDO_BC_NOLOG=$<TARGET_FILE:pseudonl_BC>
+ -DPSEUDO_PURIFY_NOLOG=$<TARGET_FILE:pseudonl_purify>
+ -DPSEUDO_VALGRIND_NOLOG=$<TARGET_FILE:pseudonl_valgrind>
+ -DMEMCHECK_FAIL=$<TARGET_FILE:memcheck_fail>
+ )
+endif()
+
+add_RunCMake_test(ABI -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
+set_property(TEST RunCMake.ABI APPEND
+ PROPERTY LABELS "CUDA")
+
+add_RunCMake_test(AndroidTestUtilities)
+if(CMake_TEST_APPLE_SILICON)
+ add_RunCMake_test(AppleSilicon)
+endif()
+set(autogen_with_qt5 FALSE)
+if(CMake_TEST_Qt5 AND Qt5Widgets_FOUND)
+ set(autogen_with_qt5 TRUE)
+endif ()
+add_RunCMake_test(Autogen -Dwith_qt5=${autogen_with_qt5})
+
+add_RunCMake_test(ArtifactOutputDirs)
+
+if(NOT DEFINED CMake_TEST_BuildDepends_GNU_AS
+ AND CMAKE_C_COMPILER_ID STREQUAL "GNU"
+ AND CMAKE_GENERATOR MATCHES "^Ninja"
+ )
+ execute_process(COMMAND "${CMAKE_C_COMPILER}" -print-prog-name=as
+ RESULT_VARIABLE _gnu_res
+ OUTPUT_VARIABLE _gnu_as OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
+ if(_gnu_res EQUAL 0 AND _gnu_as)
+ set(CMake_TEST_BuildDepends_GNU_AS "${_gnu_as}")
+ endif()
+endif()
+
+add_RunCMake_test(BuildDepends
+ -DMSVC_VERSION=${MSVC_VERSION}
+ -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
+ -DCMake_TEST_BuildDepends_GNU_AS=${CMake_TEST_BuildDepends_GNU_AS}
+ )
+if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja")
+ add_RunCMake_test(Byproducts)
+endif()
+add_RunCMake_test(CMakeRoleGlobalProperty)
+add_RunCMake_test(CMakeRelease -DCMake_TEST_JQ=${CMake_TEST_JQ})
+if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja")
+ add_RunCMake_test(CompilerChange)
+endif()
+add_RunCMake_test(CompilerNotFound)
+add_RunCMake_test(Configure -DMSVC_IDE=${MSVC_IDE})
+add_RunCMake_test(DisallowedCommands)
+if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja")
+ add_RunCMake_test(ExportCompileCommands)
+endif()
+add_RunCMake_test(ExcludeFromAll)
+add_RunCMake_test(ExternalData)
+add_RunCMake_test(FeatureSummary)
+add_RunCMake_test(FPHSA)
+add_RunCMake_test(FileAPI -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}
+ -DCMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID})
+add_RunCMake_test(FindBoost)
+add_RunCMake_test(FindLua)
+add_RunCMake_test(FindOpenGL)
+add_RunCMake_test(InitialFlags)
+if(CMake_TEST_FindOpenSSL)
+ add_RunCMake_test(FindOpenSSL)
+endif()
+if(CMake_TEST_UseSWIG)
+ add_RunCMake_test(FindSWIG)
+ add_RunCMake_test(UseSWIG -DCMake_TEST_FindPython=${CMake_TEST_FindPython})
+endif()
+if(NOT CMAKE_C_COMPILER_ID MATCHES "Watcom")
+ add_RunCMake_test(GenerateExportHeader)
+endif()
+add_RunCMake_test(GenEx-COMPILE_LANGUAGE)
+add_RunCMake_test(GenEx-COMPILE_LANG_AND_ID)
+add_RunCMake_test(GenEx-LINK_LANGUAGE)
+add_RunCMake_test(GenEx-LINK_LANG_AND_ID)
+add_RunCMake_test(GenEx-HOST_LINK)
+add_RunCMake_test(GenEx-DEVICE_LINK)
+add_RunCMake_test(GenEx-TARGET_FILE -DLINKER_SUPPORTS_PDB=${LINKER_SUPPORTS_PDB})
+add_RunCMake_test(GenEx-GENEX_EVAL)
+add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS)
+add_RunCMake_test(GeneratorExpression)
+add_RunCMake_test(GeneratorInstance)
+add_RunCMake_test(GeneratorPlatform)
+if(XCODE_VERSION)
+ set(GeneratorToolset_ARGS -DXCODE_VERSION=${XCODE_VERSION})
+endif()
+add_RunCMake_test(GeneratorToolset)
+add_RunCMake_test(GetPrerequisites)
+add_RunCMake_test(GNUInstallDirs -DSYSTEM_NAME=${CMAKE_SYSTEM_NAME})
+add_RunCMake_test(GoogleTest) # Note: does not actually depend on Google Test
+add_RunCMake_test(Graphviz)
+add_RunCMake_test(TargetPropertyGeneratorExpressions)
+add_RunCMake_test(Languages)
+add_RunCMake_test(LinkStatic)
+if(CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|Fujitsu|FujitsuClang)$")
+ add_RunCMake_test(MetaCompileFeatures)
+endif()
+if(MSVC)
+ add_RunCMake_test(MSVCRuntimeLibrary)
+ add_RunCMake_test(MSVCRuntimeTypeInfo)
+ add_RunCMake_test(MSVCWarningFlags)
+endif()
+add_RunCMake_test(ObjectLibrary)
+add_RunCMake_test(ParseImplicitIncludeInfo)
+add_RunCMake_test(ParseImplicitLinkInfo)
+if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+ add_RunCMake_test(RuntimePath)
+endif()
+add_RunCMake_test(ScriptMode)
+add_RunCMake_test(Swift -DCMAKE_Swift_COMPILER=${CMAKE_Swift_COMPILER})
+add_RunCMake_test(TargetObjects)
+add_RunCMake_test(TargetSources)
+add_RunCMake_test(TargetProperties)
+add_RunCMake_test(ToolchainFile)
+add_RunCMake_test(find_dependency)
+add_RunCMake_test(CompileDefinitions)
+add_RunCMake_test(CompileFeatures)
+add_RunCMake_test(Policy)
+add_RunCMake_test(PolicyScope)
+add_RunCMake_test(WriteBasicConfigVersionFile)
+add_RunCMake_test(WriteCompilerDetectionHeader)
+add_RunCMake_test(SourceProperties)
+if(NOT WIN32)
+ add_RunCMake_test(PositionIndependentCode -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
+ -DCMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID})
+endif()
+if(NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+ add_RunCMake_test(VisibilityPreset)
+endif()
+if (QT4_FOUND)
+ set(CompatibleInterface_ARGS -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE})
+endif()
+add_RunCMake_test(CompatibleInterface)
+add_RunCMake_test(Syntax)
+add_RunCMake_test(WorkingDirectory)
+add_RunCMake_test(MaxRecursionDepth)
+
+add_RunCMake_test(add_custom_command)
+add_RunCMake_test(add_custom_target)
+add_RunCMake_test(add_dependencies)
+add_RunCMake_test(add_executable)
+add_RunCMake_test(add_library)
+add_RunCMake_test(add_subdirectory)
+add_RunCMake_test(add_test)
+add_RunCMake_test(build_command)
+add_executable(exit_code exit_code.c)
+set(execute_process_ARGS
+ -DEXIT_CODE_EXE=$<TARGET_FILE:exit_code>
+ -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}
+ )
+if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ list(APPEND execute_process_ARGS -DTEST_ENCODING_EXE=$<TARGET_FILE:testEncoding>)
+endif()
+add_RunCMake_test(execute_process)
+add_RunCMake_test(export)
+add_RunCMake_test(cmake_language)
+add_RunCMake_test(cmake_minimum_required)
+add_RunCMake_test(cmake_parse_arguments)
+add_RunCMake_test(cmake_path)
+add_RunCMake_test(continue)
+add_executable(color_warning color_warning.c)
+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)
+ add_RunCMake_test(ctest_coverage -DCOVERAGE_COMMAND=${COVERAGE_COMMAND})
+endif()
+add_RunCMake_test(ctest_start)
+add_RunCMake_test(ctest_submit)
+add_RunCMake_test(ctest_test)
+add_RunCMake_test(ctest_disabled_test)
+add_RunCMake_test(ctest_skipped_test)
+add_RunCMake_test(ctest_update)
+add_RunCMake_test(ctest_upload)
+add_RunCMake_test(ctest_fixtures)
+add_RunCMake_test(file)
+add_RunCMake_test(file-CHMOD)
+if(HAVE_ELF_H OR CMAKE_SYSTEM_NAME STREQUAL "AIX")
+ add_RunCMake_test(file-RPATH -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DHAVE_ELF_H=${HAVE_ELF_H})
+endif()
+add_RunCMake_test(find_file)
+add_RunCMake_test(find_library -DCYGWIN=${CYGWIN})
+add_RunCMake_test(find_package)
+add_RunCMake_test(find_path)
+add_RunCMake_test(find_program -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME})
+add_RunCMake_test(foreach)
+add_RunCMake_test(function)
+add_RunCMake_test(get_filename_component)
+add_RunCMake_test(get_property)
+add_RunCMake_test(if)
+add_RunCMake_test(include)
+add_RunCMake_test(include_directories)
+add_RunCMake_test(include_guard)
+add_RunCMake_test(list)
+add_RunCMake_test(load_cache)
+add_RunCMake_test(math)
+add_RunCMake_test(message)
+add_RunCMake_test(option)
+add_RunCMake_test(project -DCMake_TEST_RESOURCES=${CMake_TEST_RESOURCES})
+add_RunCMake_test(project_injected)
+add_RunCMake_test(return)
+add_RunCMake_test(separate_arguments)
+add_RunCMake_test(set_property)
+add_RunCMake_test(string)
+add_RunCMake_test(test_include_dirs)
+add_RunCMake_test(BundleUtilities)
+if(APPLE)
+ add_RunCMake_test(INSTALL_NAME_DIR)
+ add_RunCMake_test(MacOSVersions)
+endif()
+
+function(add_RunCMake_test_try_compile)
+ if(CMAKE_VERSION VERSION_LESS 3.9.20170907 AND "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
+ # Older CMake versions do not know about MSVC language standards.
+ # Approximate our logic from MSVC-CXX.cmake.
+ if ((NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0.24215.1 AND
+ CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) OR
+ NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10.25017)
+ set(CMAKE_CXX_STANDARD_DEFAULT 14)
+ elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0)
+ set(CMAKE_CXX_STANDARD_DEFAULT "")
+ else()
+ unset(CMAKE_CXX_STANDARD_DEFAULT)
+ endif()
+ endif()
+ if(CMAKE_VERSION VERSION_LESS 3.18.20200813 AND "x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC")
+ # Older CMake versions do not know about MSVC language standards.
+ # Approximate our logic from MSVC-C.cmake.
+ if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 19.27)
+ set(CMAKE_C_STANDARD_DEFAULT 99)
+ else()
+ set(CMAKE_C_STANDARD_DEFAULT "")
+ endif()
+ endif()
+ if(CMAKE_VERSION VERSION_LESS 3.20.20210225 AND "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")
+ # Older CMake versions do not know about Clang MSVC compatibility mode
+ # standards. Approximate the logic from Clang-C.cmake.
+ if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 11.0)
+ set(CMAKE_C_STANDARD_DEFAULT 17)
+ elseif(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.5.2)
+ set(CMAKE_C_STANDARD_DEFAULT 11)
+ endif()
+ endif()
+ foreach(var
+ CMAKE_SYSTEM_NAME
+ CMAKE_C_COMPILER_ID
+ CMAKE_C_COMPILER_VERSION
+ CMAKE_C_STANDARD_DEFAULT
+ CMAKE_CXX_COMPILER_ID
+ CMAKE_CXX_COMPILER_VERSION
+ CMAKE_CXX_STANDARD_DEFAULT
+ CMake_TEST_CUDA
+ CMake_TEST_ISPC
+ CMake_TEST_FILESYSTEM_1S
+ CMAKE_OBJC_STANDARD_DEFAULT
+ CMAKE_OBJCXX_STANDARD_DEFAULT
+ )
+ if(DEFINED ${var})
+ list(APPEND try_compile_ARGS -D${var}=${${var}})
+ endif()
+ endforeach()
+ add_RunCMake_test(try_compile)
+ set_property(TEST RunCMake.try_compile APPEND
+ PROPERTY LABELS "CUDA;ISPC")
+endfunction()
+add_RunCMake_test_try_compile()
+
+add_RunCMake_test(try_run -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
+ -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
+add_RunCMake_test(set)
+add_RunCMake_test(variable_watch)
+add_RunCMake_test(while)
+add_RunCMake_test(CMP0004)
+add_RunCMake_test(TargetPolicies)
+add_RunCMake_test(alias_targets)
+add_RunCMake_test(InterfaceLibrary)
+add_RunCMake_test(no_install_prefix)
+add_RunCMake_test(configure_file)
+add_RunCMake_test(CTestTimeout -DTIMEOUT=${CTestTestTimeout_TIME})
+add_RunCMake_test(CTestTimeoutAfterMatch)
+add_RunCMake_test(DependencyGraph -DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER})
+
+# ctresalloc links against CMakeLib and CTestLib, which means it can't be built
+# if CMake_TEST_EXTERNAL_CMAKE is activated (the compiler might be different.)
+# So, it has to be provided in the original build tree.
+if(CMake_TEST_EXTERNAL_CMAKE)
+ set(no_package_root_path)
+ if(NOT CMAKE_VERSION VERSION_LESS 3.12)
+ set(no_package_root_path NO_PACKAGE_ROOT_PATH)
+ endif()
+ find_program(ctresalloc ctresalloc PATHS ${CMake_TEST_EXTERNAL_CMAKE}
+ NO_DEFAULT_PATH
+ ${no_package_root_path}
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH
+ NO_CMAKE_FIND_ROOT_PATH
+ )
+ if(ctresalloc)
+ add_executable(ctresalloc IMPORTED)
+ set_property(TARGET ctresalloc PROPERTY IMPORTED_LOCATION ${ctresalloc})
+ endif()
+else()
+ add_executable(ctresalloc CTestResourceAllocation/ctresalloc.cxx)
+ target_link_libraries(ctresalloc CTestLib)
+ target_include_directories(ctresalloc PRIVATE
+ ${CMake_BINARY_DIR}/Source
+ ${CMake_SOURCE_DIR}/Source
+ ${CMake_SOURCE_DIR}/Source/CTest
+ )
+ set_property(TARGET ctresalloc PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMake_BIN_DIR})
+endif()
+
+if(TARGET ctresalloc)
+ add_RunCMake_test(CTestResourceAllocation -DCTRESALLOC_COMMAND=$<TARGET_FILE:ctresalloc>)
+else()
+ message(STATUS "Could not find ctresalloc")
+endif()
+
+if(NOT WIN32)
+ add_RunCMake_test(SymlinkTrees)
+endif ()
+
+find_package(Qt4 QUIET)
+find_package(Qt5Core QUIET)
+if (QT4_FOUND AND Qt5Core_FOUND AND NOT Qt5Core_VERSION VERSION_LESS 5.1.0)
+ add_RunCMake_test(IncompatibleQt)
+endif()
+if (QT4_FOUND)
+ add_RunCMake_test(ObsoleteQtMacros -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE})
+endif()
+
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ add_RunCMake_test(FindPkgConfig)
+endif()
+
+if(CMake_TEST_FindGTK2)
+ add_RunCMake_test(FindGTK2)
+endif()
+
+if("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
+ add_RunCMake_test(include_external_msproject -DVS_PLATFORM_NAME=${CMAKE_VS_PLATFORM_NAME})
+ if("${CMAKE_GENERATOR}" MATCHES "Visual Studio (9|10)" AND NOT CMAKE_VS_DEVENV_COMMAND)
+ set(NO_USE_FOLDERS 1)
+ endif()
+ add_RunCMake_test(VSSolution -DNO_USE_FOLDERS=${NO_USE_FOLDERS})
+endif()
+
+if("${CMAKE_GENERATOR}" MATCHES "Visual Studio ([^9]|9[0-9])")
+ add_RunCMake_test(VS10Project
+ -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
+ -DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION}
+ )
+ if( vs12 AND wince )
+ add_RunCMake_test( VS10ProjectWinCE "-DRunCMake_GENERATOR_PLATFORM=${wince_sdk}")
+ endif()
+endif()
+
+if(XCODE_VERSION)
+ add_RunCMake_test(XcodeProject -DXCODE_VERSION=${XCODE_VERSION})
+ add_RunCMake_test(XcodeProject-Embed)
+
+ # This test can take a very long time due to lots of combinations.
+ # Use a long default timeout and provide an option to customize it.
+ if(NOT DEFINED CMake_TEST_XcodeProject_TIMEOUT)
+ set(CMake_TEST_XcodeProject_TIMEOUT 2000)
+ endif()
+ set_property(TEST RunCMake.XcodeProject PROPERTY TIMEOUT ${CMake_TEST_XcodeProject_TIMEOUT})
+endif()
+
+if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang"
+ AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.0)
+ add_RunCMake_test(Framework)
+endif()
+
+add_RunCMake_test(File_Archive)
+add_RunCMake_test(File_Configure)
+add_RunCMake_test(File_Generate)
+add_RunCMake_test(ExportWithoutLanguage)
+add_RunCMake_test(target_link_directories)
+add_RunCMake_test(target_link_libraries)
+add_RunCMake_test(target_link_libraries-ALIAS)
+add_RunCMake_test(target_link_libraries-LINK_LANGUAGE)
+add_RunCMake_test(target_link_libraries-LINK_LANG_AND_ID)
+add_RunCMake_test(add_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
+add_RunCMake_test(target_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
+ -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
+set_property(TEST RunCMake.target_link_options APPEND
+ PROPERTY LABELS "CUDA")
+
+add_RunCMake_test(target_compile_definitions)
+add_RunCMake_test(target_compile_features)
+add_RunCMake_test(target_compile_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
+add_RunCMake_test(target_include_directories)
+add_RunCMake_test(target_sources)
+add_RunCMake_test(CheckCompilerFlag -DCMake_TEST_CUDA=${CMake_TEST_CUDA}
+ -DCMake_TEST_ISPC=${CMake_TEST_ISPC}
+ -DCMAKE_Fortran_COMPILER_ID=${CMAKE_Fortran_COMPILER_ID})
+add_RunCMake_test(CheckSourceCompiles -DCMake_TEST_CUDA=${CMake_TEST_CUDA}
+ -DCMake_TEST_ISPC=${CMake_TEST_ISPC}
+ -DCMAKE_Fortran_COMPILER_ID=${CMAKE_Fortran_COMPILER_ID})
+add_RunCMake_test(CheckSourceRuns -DCMake_TEST_CUDA=${CMake_TEST_CUDA}
+ -DCMAKE_Fortran_COMPILER_ID=${CMAKE_Fortran_COMPILER_ID})
+set_property(TEST RunCMake.CheckCompilerFlag
+ RunCMake.CheckSourceCompiles
+ RunCMake.CheckSourceRuns
+ APPEND PROPERTY LABELS "CUDA")
+set_property(TEST RunCMake.CheckSourceCompiles
+ RunCMake.CheckCompilerFlag
+ APPEND PROPERTY LABELS "ISPC")
+add_RunCMake_test(CheckModules)
+add_RunCMake_test(CheckIPOSupported)
+if (CMAKE_SYSTEM_NAME MATCHES "(Linux|Darwin)"
+ AND (CMAKE_C_COMPILER_ID MATCHES "Clang|GNU" OR CMAKE_Fortran_COMPILER_ID MATCHES "GNU"))
+ add_RunCMake_test(CheckLinkerFlag -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
+ -DCMAKE_Fortran_COMPILER_ID=${CMAKE_Fortran_COMPILER_ID}
+ -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
+ set_property(TEST RunCMake.CheckLinkerFlag APPEND PROPERTY LABELS "CUDA")
+endif()
+
+
+add_executable(pseudo_llvm-rc pseudo_llvm-rc.c)
+add_RunCMake_test(CommandLine -DLLVM_RC=$<TARGET_FILE:pseudo_llvm-rc> -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DCYGWIN=${CYGWIN} -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE})
+add_RunCMake_test(CommandLineTar)
+
+if(CMAKE_PLATFORM_NO_VERSIONED_SONAME OR (NOT CMAKE_SHARED_LIBRARY_SONAME_FLAG AND NOT CMAKE_SHARED_LIBRARY_SONAME_C_FLAG))
+ set(NO_NAMELINK 1)
+else()
+ set(NO_NAMELINK 0)
+endif()
+
+add_RunCMake_test(install -DNO_NAMELINK=${NO_NAMELINK} -DCYGWIN=${CYGWIN}
+ -DCMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN=${CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN}
+ -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
+ -DCMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG=${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG}
+ -DCMAKE_EXECUTABLE_FORMAT=${CMAKE_EXECUTABLE_FORMAT}
+ -DCMake_TEST_ISPC=${CMake_TEST_ISPC}
+ )
+set_property(TEST RunCMake.install APPEND
+ PROPERTY LABELS "ISPC")
+
+add_RunCMake_test(file-GET_RUNTIME_DEPENDENCIES
+ -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
+ -DCMake_INSTALL_NAME_TOOL_BUG=${CMake_INSTALL_NAME_TOOL_BUG}
+ )
+
+add_RunCMake_test(CPackCommandLine)
+add_RunCMake_test(CPackConfig)
+add_RunCMake_test(CPackInstallProperties)
+if(XCODE_VERSION)
+ set(ExternalProject_ARGS -DXCODE_VERSION=${XCODE_VERSION})
+endif()
+add_RunCMake_test(ExternalProject)
+add_RunCMake_test(FetchContent)
+set(CTestCommandLine_ARGS -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE})
+if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ list(APPEND CTestCommandLine_ARGS -DTEST_AFFINITY=$<TARGET_FILE:testAffinity>)
+endif()
+add_executable(print_stdin print_stdin.c)
+add_RunCMake_test(CTestCommandLine -DTEST_PRINT_STDIN=$<TARGET_FILE:print_stdin>)
+add_RunCMake_test(CacheNewline)
+# Only run this test on unix platforms that support
+# symbolic links
+if(UNIX)
+ add_RunCMake_test(CPackSymlinks)
+endif()
+
+set(IfacePaths_INCDIRS_ARGS -DTEST_PROP=INCLUDE_DIRECTORIES)
+add_RunCMake_test(IfacePaths_INCDIRS TEST_DIR IfacePaths)
+
+set(IfacePaths_SOURCES_ARGS -DTEST_PROP=SOURCES)
+add_RunCMake_test(IfacePaths_SOURCES TEST_DIR IfacePaths)
+
+# Matlab module related tests
+if(CMake_TEST_FindMatlab OR CMake_TEST_FindMatlab_MCR OR (NOT "${CMake_TEST_FindMatlab_MCR_ROOT_DIR}" STREQUAL ""))
+ set(FindMatlab_additional_test_options )
+ if(CMake_TEST_FindMatlab_MCR OR NOT "${CMake_TEST_FindMatlab_MCR_ROOT_DIR}" STREQUAL "")
+ set(FindMatlab_additional_test_options -DIS_MCR=TRUE)
+ endif()
+ if(NOT "${CMake_TEST_FindMatlab_MCR_ROOT_DIR}" STREQUAL "")
+ set(FindMatlab_additional_test_options ${FindMatlab_additional_test_options} "-DMCR_ROOT:FILEPATH=${CMake_TEST_FindMatlab_MCR_ROOT_DIR}")
+ endif()
+
+ add_RunCMake_test(FindMatlab ${FindMatlab_additional_test_options})
+endif()
+
+add_executable(pseudo_emulator pseudo_emulator.c)
+add_executable(pseudo_emulator_custom_command pseudo_emulator_custom_command.c)
+add_executable(pseudo_emulator_custom_command_arg pseudo_emulator_custom_command_arg.c)
+add_RunCMake_test(CrosscompilingEmulator
+ -DPSEUDO_EMULATOR=$<TARGET_FILE:pseudo_emulator>
+ -DPSEUDO_EMULATOR_CUSTOM_COMMAND=$<TARGET_FILE:pseudo_emulator_custom_command>
+ -DPSEUDO_EMULATOR_CUSTOM_COMMAND_ARG=$<TARGET_FILE:pseudo_emulator_custom_command_arg>)
+if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
+ if(UNIX AND NOT CYGWIN)
+ execute_process(COMMAND ldd --help
+ OUTPUT_VARIABLE LDD_HELP
+ ERROR_VARIABLE LDD_ERR)
+ if("${LDD_HELP}" MATCHES
+ "(-r, --function-relocs.*process data and function relocations.*-u, --unused.*print unused direct dependencies)")
+ add_RunCMake_test(LinkWhatYouUse)
+ endif()
+ endif()
+ add_executable(pseudo_tidy pseudo_tidy.c)
+ add_executable(pseudo_iwyu pseudo_iwyu.c)
+ add_executable(pseudo_cpplint pseudo_cpplint.c)
+ add_executable(pseudo_cppcheck pseudo_cppcheck.c)
+ add_RunCMake_test(ClangTidy -DPSEUDO_TIDY=$<TARGET_FILE:pseudo_tidy>)
+ add_RunCMake_test(IncludeWhatYouUse -DPSEUDO_IWYU=$<TARGET_FILE:pseudo_iwyu>)
+ add_RunCMake_test(Cpplint -DPSEUDO_CPPLINT=$<TARGET_FILE:pseudo_cpplint>)
+ add_RunCMake_test(Cppcheck -DPSEUDO_CPPCHECK=$<TARGET_FILE:pseudo_cppcheck>)
+ add_RunCMake_test(MultiLint
+ -DPSEUDO_TIDY=$<TARGET_FILE:pseudo_tidy>
+ -DPSEUDO_IWYU=$<TARGET_FILE:pseudo_iwyu>
+ -DPSEUDO_CPPLINT=$<TARGET_FILE:pseudo_cpplint>
+ -DPSEUDO_CPPCHECK=$<TARGET_FILE:pseudo_cppcheck>
+ )
+ if(DEFINED CMake_TEST_CUDA)
+ list(APPEND CompilerLauncher_ARGS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
+ endif()
+ if(DEFINED CMake_TEST_ISPC)
+ list(APPEND CompilerLauncher_ARGS -DCMake_TEST_ISPC=${CMake_TEST_ISPC})
+ endif()
+ if(CMAKE_Fortran_COMPILER)
+ list(APPEND CompilerLauncher_ARGS -DCMake_TEST_Fortran=1)
+ endif()
+ if (APPLE AND CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
+ list(APPEND CompilerLauncher_ARGS -DCMake_TEST_OBJC=1)
+ endif()
+ add_RunCMake_test(CompilerLauncher)
+ set_property(TEST RunCMake.CompilerLauncher APPEND
+ PROPERTY LABELS "CUDA;ISPC")
+ add_RunCMake_test(ctest_labels_for_subprojects)
+ add_RunCMake_test(CompilerArgs)
+endif()
+
+set(cpack_tests
+ DEB.CUSTOM_NAMES
+ DEB.DEBUGINFO
+ DEB.DEFAULT_PERMISSIONS
+ DEB.DEPENDENCIES
+ DEB.EMPTY_DIR
+ DEB.VERSION
+ DEB.EXTRA
+ DEB.GENERATE_SHLIBS
+ DEB.GENERATE_SHLIBS_LDCONFIG
+ DEB.LONG_FILENAMES
+ DEB.MINIMAL
+ DEB.PER_COMPONENT_FIELDS
+ DEB.TIMESTAMPS
+ DEB.MD5SUMS
+ DEB.DEB_PACKAGE_VERSION_BACK_COMPATIBILITY
+ DEB.DEB_DESCRIPTION
+ DEB.PROJECT_META
+
+ RPM.CUSTOM_BINARY_SPEC_FILE
+ RPM.CUSTOM_NAMES
+ RPM.DEBUGINFO
+ RPM.DEFAULT_PERMISSIONS
+ RPM.DEPENDENCIES
+ RPM.DIST
+ RPM.EMPTY_DIR
+ RPM.VERSION
+ RPM.INSTALL_SCRIPTS
+ RPM.MAIN_COMPONENT
+ RPM.MINIMAL
+ RPM.PARTIALLY_RELOCATABLE_WARNING
+ RPM.PER_COMPONENT_FIELDS
+ RPM.SINGLE_DEBUGINFO
+ RPM.EXTRA_SLASH_IN_PATH
+ RPM.SOURCE_PACKAGE
+ RPM.SUGGESTS
+ RPM.SYMLINKS
+ RPM.USER_FILELIST
+ RPM.PROJECT_META
+
+ 7Z
+ TBZ2
+ TGZ
+ TXZ
+ TZ
+ ZIP
+ STGZ
+ External
+ )
+if(APPLE)
+ list(APPEND cpack_tests DragNDrop)
+endif()
+add_RunCMake_test_group(CPack "${cpack_tests}")
+# add a test to make sure symbols are exported from a shared library
+# for MSVC compilers CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS property is used
+add_RunCMake_test(AutoExportDll
+ -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
+ -DCMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}
+ )
+
+add_RunCMake_test(AndroidMK)
+
+if(CMake_TEST_ANDROID_NDK OR CMake_TEST_ANDROID_STANDALONE_TOOLCHAIN)
+ if(NOT "${CMAKE_GENERATOR}" MATCHES "Make|Ninja|Visual Studio 1[456]")
+ message(FATAL_ERROR "Android tests supported only by Makefile, Ninja, and Visual Studio >= 14 generators")
+ endif()
+ foreach(v TEST_ANDROID_NDK TEST_ANDROID_STANDALONE_TOOLCHAIN)
+ if(CMake_${v})
+ string(REPLACE ";" "|" ${v} "${CMake_${v}}")
+ list(APPEND Android_ARGS "-D${v}=${${v}}")
+ endif()
+ endforeach()
+
+ add_RunCMake_test(Android)
+
+ # This test can take a very long time due to lots of combinations.
+ # Use a long default timeout and provide an option to customize it.
+ if(NOT DEFINED CMake_TEST_ANDROID_TIMEOUT)
+ set(CMake_TEST_ANDROID_TIMEOUT 3000)
+ endif()
+ set_property(TEST RunCMake.Android PROPERTY TIMEOUT ${CMake_TEST_ANDROID_TIMEOUT})
+endif()
+
+if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|9[0-9])")
+ add_RunCMake_test(CSharpCustomCommand)
+ add_RunCMake_test(CSharpReferenceImport)
+endif()
+
+add_RunCMake_test("CTestCommandExpandLists")
+
+add_RunCMake_test(PrecompileHeaders -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
+ -DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION})
+
+add_RunCMake_test("UnityBuild")
+add_RunCMake_test(CMakePresets -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA})
+add_RunCMake_test(CMakePresetsBuild -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA})
+add_RunCMake_test(CMakePresetsTest -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA})
+
+if(${CMAKE_GENERATOR} MATCHES "Make|Ninja")
+ add_RunCMake_test(TransformDepfile)
+endif()
+
+if(WIN32)
+ add_RunCMake_test(Win32GenEx)
+endif()
diff --git a/Tests/RunCMake/CMakePresets/ArchToolsetStrategyDefault-result.txt b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyDefault-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyDefault-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/ArchToolsetStrategyDefault-stderr.txt b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyDefault-stderr.txt
new file mode 100644
index 0000000..a3b79b6
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyDefault-stderr.txt
@@ -0,0 +1,11 @@
+^CMake Error at CMakeLists\.txt:[0-9]+ \(project\):
+ Generator
+
+ [^
+]*
+
+ does not support platform specification, but platform
+
+ a
+
+ was specified\.$
diff --git a/Tests/RunCMake/CMakePresets/ArchToolsetStrategyIgnore.cmake b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyIgnore.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyIgnore.cmake
diff --git a/Tests/RunCMake/CMakePresets/ArchToolsetStrategyNone-result.txt b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyNone-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyNone-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/ArchToolsetStrategyNone-stderr.txt b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyNone-stderr.txt
new file mode 100644
index 0000000..a3b79b6
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ArchToolsetStrategyNone-stderr.txt
@@ -0,0 +1,11 @@
+^CMake Error at CMakeLists\.txt:[0-9]+ \(project\):
+ Generator
+
+ [^
+]*
+
+ does not support platform specification, but platform
+
+ a
+
+ was specified\.$
diff --git a/Tests/RunCMake/CMakePresets/CMakeLists.txt.in b/Tests/RunCMake/CMakePresets/CMakeLists.txt.in
new file mode 100644
index 0000000..67c2d48
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/CMakeLists.txt.in
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.18)
+project(${RunCMake_TEST} NONE)
+set(RunCMake_SOURCE_DIR [==[@RunCMake_SOURCE_DIR@]==])
+include("${RunCMake_SOURCE_DIR}/${RunCMake_TEST}.cmake")
diff --git a/Tests/RunCMake/CMakePresets/CMakePresets.json.in b/Tests/RunCMake/CMakePresets/CMakePresets.json.in
new file mode 100644
index 0000000..c6f943c
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/CMakePresets.json.in
@@ -0,0 +1,506 @@
+{
+ "version": 1,
+ "cmakeMinimumRequired": {
+ "major": 3,
+ "minor": 18,
+ "patch": 0
+ },
+ "vendor": {
+ "example.com/ExampleIDE/1.0": true
+ },
+ "configurePresets": [
+ {
+ "name": "Good",
+ "displayName": "Good Preset",
+ "description": "This preset is meant to test most of the fields when set correctly.",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cmakeExecutable": "/path/does/not/exist/cmake",
+ "vendor": {
+ "example.com/ExampleIDE/1.0": {
+ "transmogrify": true
+ }
+ },
+ "cacheVariables": {
+ "TEST_SOURCE_DIR": {
+ "type": "PATH",
+ "value": "${sourceDir}"
+ },
+ "TEST_SOURCE_PARENT_DIR": {
+ "type": "PATH",
+ "value": "${sourceParentDir}"
+ },
+ "TEST_SOURCE_LIST": {
+ "type": "FILEPATH",
+ "value": "${sourceDir}/CMakeLists.txt"
+ },
+ "TEST_TRUE": {
+ "type": "BOOL",
+ "value": "TRUE"
+ },
+ "TEST_OFF": {
+ "type": "BOOL",
+ "value": "OFF"
+ },
+ "TEST_BOOL_TRUE": true,
+ "TEST_BOOL_FALSE": false,
+ "TEST_TYPED_BOOL_TRUE": {
+ "type": "STRING",
+ "value": true
+ },
+ "TEST_TYPED_BOOL_FALSE": {
+ "type": "STRING",
+ "value": false
+ },
+ "TEST_UNTYPED_BOOL_TRUE": {
+ "value": true
+ },
+ "TEST_UNTYPED_BOOL_FALSE": {
+ "value": false
+ },
+ "TEST_PRESET_NAME": {
+ "type": "STRING",
+ "value": "x${presetName}x"
+ },
+ "TEST_GENERATOR": {
+ "value": "x${generator}x"
+ },
+ "TEST_DOLLAR": {
+ "value": "${dollar}"
+ },
+ "TEST_SOURCE_DIR_NAME": "${sourceDirName}",
+ "TEST_ENV_REF": "$env{TEST_ENV_REF}",
+ "TEST_ENV": "$env{TEST_ENV}",
+ "TEST_D_ENV_REF": "$env{TEST_D_ENV_REF}",
+ "TEST_ENV_OVERRIDE": "$env{TEST_ENV_OVERRIDE}",
+ "TEST_PENV": "$env{TEST_PENV}",
+ "TEST_ENV_REF_PENV": "$env{TEST_ENV_REF_PENV}",
+ "TEST_ENV_REF_P": "$penv{TEST_ENV_REF}",
+ "TEST_ENV_P": "$penv{TEST_ENV}",
+ "TEST_D_ENV_REF_P": "$penv{TEST_D_ENV_REF}",
+ "TEST_ENV_OVERRIDE_P": "$penv{TEST_ENV_OVERRIDE}",
+ "TEST_PENV_P": "$penv{TEST_PENV}",
+ "TEST_ENV_REF_PENV_P": "$penv{TEST_ENV_REF_PENV}",
+ "TEST_MULTIPLE_MACROS": "${presetName} ${generator}",
+ "TEST_EXPANSION": "\\${presetName} ${dollar}{dollar} $unknown{namespace} $en{NOT_ENV} $enve{NOT_ENV} $ \\$ $a",
+ "TEST_TRAILING_DOLLAR": "a $",
+ "TEST_TRAILING_BACKSLASH": "a \\",
+ "TEST_TRAILING_UNKNOWN_NAMESPACE": "$unknown{namespace",
+ "TEST_OVERRIDE_1": {
+ "type": "STRING",
+ "value": "Default value"
+ },
+ "TEST_OVERRIDE_2": "Default value",
+ "TEST_OVERRIDE_3": {
+ "type": "STRING",
+ "value": "Default value"
+ },
+ "TEST_OVERRIDE_4": {
+ "type": "STRING",
+ "value": "Default value"
+ },
+ "TEST_UNDEF": "undef"
+ },
+ "environment": {
+ "TEST_ENV_REF": "$env{TEST_ENV}",
+ "TEST_ENV": "Environment variable",
+ "TEST_D_ENV_REF": "x$env{TEST_ENV_REF}x",
+ "TEST_ENV_OVERRIDE": "Overridden environment variable",
+ "TEST_ENV_REF_PENV": "prefix+$penv{TEST_ENV_REF_PENV}",
+ "TEST_PENV": null
+ }
+ },
+ {
+ "name": "GoodNoArgs",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "GoodBinaryUp",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/../GoodBinaryUp-build"
+ },
+ {
+ "name": "GoodBinaryRelative",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "build"
+ },
+ {
+ "name": "Good Spaces",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "GOOD_SPACES": {
+ "type": "STRING",
+ "value": "1"
+ }
+ }
+ },
+ {
+ "name": "GoodWindowsBackslash",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}\\build"
+ },
+ {
+ "name": "GoodBinaryCmdLine",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "GoodGeneratorCmdLine",
+ "generator": "Invalid Generator",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "InvalidGeneratorCmdLine",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "GoodNoS",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "GoodNoSCachePrep",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceParentDir}/GoodNoSCachePrep-build"
+ },
+ {
+ "name": "GoodNoSCache",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "GoodNoSourceArg",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "GoodInheritanceParentBase",
+ "hidden": true,
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "TEST_VARIABLE": {
+ "type": "STRING",
+ "value": "Some string"
+ }
+ },
+ "environment": {
+ "TEST_ENV": "Some environment variable"
+ }
+ },
+ {
+ "name": "GoodInheritanceParent",
+ "inherits": "GoodInheritanceParentBase"
+ },
+ {
+ "name": "GoodInheritanceChildBase",
+ "hidden": true
+ },
+ {
+ "name": "GoodInheritanceChild",
+ "inherits": "GoodInheritanceChildBase",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "TEST_VARIABLE": {
+ "type": "STRING",
+ "value": "Some string"
+ }
+ },
+ "environment": {
+ "TEST_ENV": "Some environment variable"
+ }
+ },
+ {
+ "name": "GoodInheritanceOverrideBase",
+ "hidden": true,
+ "generator": "Invalid Generator",
+ "binaryDir": "${sourceDir}/../GoodInheritanceBase-build",
+ "cacheVariables": {
+ "PARENT_VARIABLE": {
+ "type": "STRING",
+ "value": "Parent variable"
+ },
+ "OVERRIDDEN_VARIABLE": {
+ "type": "BOOL",
+ "value": "ON"
+ },
+ "DELETED_VARIABLE": "This variable will be deleted"
+ },
+ "environment": {
+ "PARENT_ENV": "Parent environment variable",
+ "OVERRIDDEN_ENV": "This environment variable will be overridden",
+ "DELETED_ENV": "This environment variable will be deleted"
+ }
+ },
+ {
+ "name": "GoodInheritanceOverride",
+ "inherits": "GoodInheritanceOverrideBase",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "OVERRIDDEN_VARIABLE": {
+ "type": "STRING",
+ "value": "Overridden variable"
+ },
+ "CHILD_VARIABLE": {
+ "type": "STRING",
+ "value": "Child variable"
+ },
+ "DELETED_VARIABLE": null
+ },
+ "environment": {
+ "OVERRIDDEN_ENV": "Overridden environment variable",
+ "CHILD_ENV": "Child environment variable",
+ "DELETED_ENV": null
+ }
+ },
+ {
+ "name": "GoodInheritanceOverrideDummy",
+ "inherits": "GoodInheritanceOverride"
+ },
+ {
+ "name": "GoodInheritanceMulti1",
+ "hidden": true,
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "FIRST_VARIABLE": {
+ "type": "STRING",
+ "value": "First variable"
+ },
+ "OVERRIDDEN_VARIABLE": {
+ "type": "STRING",
+ "value": "Overridden variable"
+ }
+ },
+ "environment": {
+ "FIRST_ENV": "First environment variable",
+ "OVERRIDDEN_ENV": "Overridden environment variable"
+ }
+ },
+ {
+ "name": "GoodInheritanceMulti2",
+ "hidden": true,
+ "generator": "Invalid Generator",
+ "binaryDir": "${sourceDir}/../GoodInheritanceMulti2-build",
+ "cacheVariables": {
+ "SECOND_VARIABLE": {
+ "type": "STRING",
+ "value": "Second variable"
+ },
+ "OVERRIDDEN_VARIABLE": {
+ "type": "BOOL",
+ "value": "ON"
+ }
+ },
+ "environment": {
+ "SECOND_ENV": "Second environment variable",
+ "OVERRIDDEN_ENV": "This will be overridden"
+ }
+ },
+ {
+ "name": "GoodInheritanceMulti",
+ "inherits": [
+ "GoodInheritanceMulti1",
+ "GoodInheritanceMulti2"
+ ]
+ },
+ {
+ "name": "GoodInheritanceMultiSecond1",
+ "hidden": true
+ },
+ {
+ "name": "GoodInheritanceMultiSecond2",
+ "hidden": true,
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "GoodInheritanceMultiSecond",
+ "inherits": [
+ "GoodInheritanceMultiSecond1",
+ "GoodInheritanceMultiSecond2"
+ ]
+ },
+ {
+ "name": "GoodInheritanceMacroBase",
+ "hidden": true,
+ "cacheVariables": {
+ "PRESET_NAME": "${presetName}"
+ }
+ },
+ {
+ "name": "GoodInheritanceMacro",
+ "inherits": "GoodInheritanceMacroBase",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "VendorMacro",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "$vendor{unknown.unknownMacro}"
+ },
+ {
+ "name": "InvalidGenerator",
+ "generator": "Invalid Generator",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "UseHiddenPreset",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "hidden": true
+ },
+ {
+ "name": "VisualStudioGeneratorArch",
+ "generator": "@RunCMake_GENERATOR@ Win64",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "VisualStudioWin32",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "architecture": "Win32"
+ },
+ {
+ "name": "VisualStudioWin64",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "architecture": "x64"
+ },
+ {
+ "name": "VisualStudioWin32Override",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "architecture": "Win32"
+ },
+ {
+ "name": "VisualStudioToolset",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "toolset": "Test Toolset"
+ },
+ {
+ "name": "VisualStudioToolsetOverride",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "toolset": "Invalid Toolset"
+ },
+ {
+ "name": "VisualStudioInheritanceParentBase",
+ "hidden": true,
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "architecture": "Test Platform",
+ "toolset": "Test Toolset"
+ },
+ {
+ "name": "VisualStudioInheritanceParent",
+ "inherits": "VisualStudioInheritanceParentBase"
+ },
+ {
+ "name": "VisualStudioInheritanceChildBase",
+ "hidden": true
+ },
+ {
+ "name": "VisualStudioInheritanceChild",
+ "inherits": "VisualStudioInheritanceChildBase",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "architecture": "Test Platform",
+ "toolset": "Test Toolset"
+ },
+ {
+ "name": "VisualStudioInheritanceOverrideBase",
+ "hidden": true,
+ "architecture": "Invalid Platform",
+ "toolset": "Invalid Toolset"
+ },
+ {
+ "name": "VisualStudioInheritanceOverride",
+ "inherits": "VisualStudioInheritanceOverrideBase",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "architecture": "Test Platform",
+ "toolset": "Test Toolset"
+ },
+ {
+ "name": "VisualStudioInheritanceMulti1",
+ "hidden": true,
+ "architecture": "Test Platform",
+ "toolset": "Test Toolset"
+ },
+ {
+ "name": "VisualStudioInheritanceMulti2",
+ "hidden": true,
+ "architecture": "Invalid Platform",
+ "toolset": "Invalid Toolset"
+ },
+ {
+ "name": "VisualStudioInheritanceMulti",
+ "inherits": [
+ "VisualStudioInheritanceMulti1",
+ "VisualStudioInheritanceMulti2"
+ ],
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "VisualStudioInheritanceMultiSecond1",
+ "hidden": true
+ },
+ {
+ "name": "VisualStudioInheritanceMultiSecond2",
+ "hidden": true,
+ "architecture": "Test Platform",
+ "toolset": "Test Toolset"
+ },
+ {
+ "name": "VisualStudioInheritanceMultiSecond",
+ "inherits": [
+ "VisualStudioInheritanceMultiSecond1",
+ "VisualStudioInheritanceMultiSecond2"
+ ],
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "ArchToolsetStrategyNone",
+ "generator": "@RunCMake_GENERATOR@",
+ "architecture": "a",
+ "toolset": "a",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "ArchToolsetStrategyBase",
+ "generator": "@RunCMake_GENERATOR@",
+ "architecture": {
+ "value": "a",
+ "strategy": "external"
+ },
+ "toolset": {
+ "value": "a",
+ "strategy": "external"
+ },
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "ArchToolsetStrategyDefault",
+ "inherits": "ArchToolsetStrategyBase",
+ "architecture": {
+ "strategy": "set"
+ },
+ "toolset": {
+ "strategy": "set"
+ }
+ },
+ {
+ "name": "ArchToolsetStrategyIgnore",
+ "inherits": "ArchToolsetStrategyBase"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/CacheOverride.cmake b/Tests/RunCMake/CMakePresets/CacheOverride.cmake
new file mode 100644
index 0000000..d0ebe17
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/CacheOverride.cmake
@@ -0,0 +1,2 @@
+set(TEST_OVERRIDE_3 "Overridden value" CACHE STRING "")
+set(TEST_OVERRIDE_4 "Overridden value" CACHE INTERNAL "")
diff --git a/Tests/RunCMake/CMakePresets/Comment-result.txt b/Tests/RunCMake/CMakePresets/Comment-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/Comment-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/Comment-stderr.txt b/Tests/RunCMake/CMakePresets/Comment-stderr.txt
new file mode 100644
index 0000000..2f404bc
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/Comment-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/Comment: JSON parse error$
diff --git a/Tests/RunCMake/CMakePresets/Comment.json.in b/Tests/RunCMake/CMakePresets/Comment.json.in
new file mode 100644
index 0000000..0f7120c
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/Comment.json.in
@@ -0,0 +1,11 @@
+// Comment
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "Comment",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/ConditionFuture-result.txt b/Tests/RunCMake/CMakePresets/ConditionFuture-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ConditionFuture-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/ConditionFuture-stderr.txt b/Tests/RunCMake/CMakePresets/ConditionFuture-stderr.txt
new file mode 100644
index 0000000..ea5f47f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ConditionFuture-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/ConditionFuture: File version must be 3 or higher for condition support$
diff --git a/Tests/RunCMake/CMakePresets/ConditionFuture.json.in b/Tests/RunCMake/CMakePresets/ConditionFuture.json.in
new file mode 100644
index 0000000..9d4798b
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ConditionFuture.json.in
@@ -0,0 +1,11 @@
+{
+ "version": 2,
+ "configurePresets": [
+ {
+ "name": "ConditionFuture",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "condition": true
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/Conditions.json.in b/Tests/RunCMake/CMakePresets/Conditions.json.in
new file mode 100644
index 0000000..9c0c6bd
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/Conditions.json.in
@@ -0,0 +1,406 @@
+{
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "Base",
+ "hidden": true,
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "SimpleTrue",
+ "inherits": "Base",
+ "condition": true
+ },
+ {
+ "name": "SimpleFalse",
+ "inherits": "Base",
+ "condition": false
+ },
+ {
+ "name": "Null",
+ "inherits": "Base",
+ "condition": null
+ },
+ {
+ "name": "ConstTrue",
+ "inherits": "Base",
+ "condition": {
+ "type": "const",
+ "value": true
+ }
+ },
+ {
+ "name": "ConstFalse",
+ "inherits": "Base",
+ "condition": {
+ "type": "const",
+ "value": false
+ }
+ },
+ {
+ "name": "EqualsTrue",
+ "inherits": "Base",
+ "condition": {
+ "type": "equals",
+ "lhs": "abc",
+ "rhs": "abc"
+ }
+ },
+ {
+ "name": "EqualsFalse",
+ "inherits": "Base",
+ "condition": {
+ "type": "equals",
+ "lhs": "abc",
+ "rhs": "abcd"
+ }
+ },
+ {
+ "name": "EqualsMacroLeft",
+ "inherits": "Base",
+ "condition": {
+ "type": "equals",
+ "lhs": "${presetName}",
+ "rhs": "EqualsMacroLeft"
+ }
+ },
+ {
+ "name": "EqualsMacroRight",
+ "inherits": "Base",
+ "condition": {
+ "type": "equals",
+ "lhs": "EqualsMacroRight",
+ "rhs": "${presetName}"
+ }
+ },
+ {
+ "name": "NotEqualsTrue",
+ "inherits": "Base",
+ "condition": {
+ "type": "notEquals",
+ "lhs": "abc",
+ "rhs": "abcd"
+ }
+ },
+ {
+ "name": "NotEqualsFalse",
+ "inherits": "Base",
+ "condition": {
+ "type": "notEquals",
+ "lhs": "abc",
+ "rhs": "abc"
+ }
+ },
+ {
+ "name": "InListTrue",
+ "inherits": "Base",
+ "condition": {
+ "type": "inList",
+ "string": "b",
+ "list": [
+ "a",
+ "b",
+ "c"
+ ]
+ }
+ },
+ {
+ "name": "InListFalse",
+ "inherits": "Base",
+ "condition": {
+ "type": "inList",
+ "string": "d",
+ "list": [
+ "a",
+ "b",
+ "c"
+ ]
+ }
+ },
+ {
+ "name": "InListMacroString",
+ "inherits": "Base",
+ "condition": {
+ "type": "inList",
+ "string": "${presetName}",
+ "list": [
+ "InListMacroString",
+ "AnotherString"
+ ]
+ }
+ },
+ {
+ "name": "InListMacroList",
+ "inherits": "Base",
+ "condition": {
+ "type": "inList",
+ "string": "InListMacroList",
+ "list": [
+ "${presetName}",
+ "AnotherString"
+ ]
+ }
+ },
+ {
+ "name": "InListShortCircuit",
+ "inherits": "Base",
+ "condition": {
+ "type": "inList",
+ "string": "a",
+ "list": [
+ "a",
+ "${invalidMacro}"
+ ]
+ }
+ },
+ {
+ "name": "NotInListTrue",
+ "inherits": "Base",
+ "condition": {
+ "type": "notInList",
+ "string": "d",
+ "list": [
+ "a",
+ "b",
+ "c"
+ ]
+ }
+ },
+ {
+ "name": "NotInListFalse",
+ "inherits": "Base",
+ "condition": {
+ "type": "notInList",
+ "string": "a",
+ "list": [
+ "a",
+ "b",
+ "c"
+ ]
+ }
+ },
+ {
+ "name": "MatchesTrue",
+ "inherits": "Base",
+ "condition": {
+ "type": "matches",
+ "string": "aaa",
+ "regex": "^a*$"
+ }
+ },
+ {
+ "name": "MatchesFalse",
+ "inherits": "Base",
+ "condition": {
+ "type": "matches",
+ "string": "aab",
+ "regex": "^a*$"
+ }
+ },
+ {
+ "name": "MatchesMacroString",
+ "inherits": "Base",
+ "condition": {
+ "type": "matches",
+ "string": "${presetName}",
+ "regex": "^Matches"
+ }
+ },
+ {
+ "name": "MatchesMacroRegex",
+ "inherits": "Base",
+ "condition": {
+ "type": "matches",
+ "string": "stuff",
+ "regex": "$env{CONDITION_REGEX}"
+ },
+ "environment": {
+ "CONDITION_REGEX": "^stuf*$"
+ }
+ },
+ {
+ "name": "NotMatchesTrue",
+ "inherits": "Base",
+ "condition": {
+ "type": "notMatches",
+ "string": "aab",
+ "regex": "^a*$"
+ }
+ },
+ {
+ "name": "NotMatchesFalse",
+ "inherits": "Base",
+ "condition": {
+ "type": "notMatches",
+ "string": "aaa",
+ "regex": "^a*$"
+ }
+ },
+ {
+ "name": "AnyOfTrue1",
+ "inherits": "Base",
+ "condition": {
+ "type": "anyOf",
+ "conditions": [
+ true,
+ false
+ ]
+ }
+ },
+ {
+ "name": "AnyOfTrue2",
+ "inherits": "Base",
+ "condition": {
+ "type": "anyOf",
+ "conditions": [
+ false,
+ true
+ ]
+ }
+ },
+ {
+ "name": "AnyOfFalse",
+ "inherits": "Base",
+ "condition": {
+ "type": "anyOf",
+ "conditions": [
+ false,
+ {
+ "type": "equals",
+ "lhs": "abc",
+ "rhs": "abcd"
+ }
+ ]
+ }
+ },
+ {
+ "name": "AnyOfShortCircuit",
+ "inherits": "Base",
+ "condition": {
+ "type": "anyOf",
+ "conditions": [
+ true,
+ {
+ "type": "equals",
+ "lhs": "${invalidMacro}",
+ "rhs": ""
+ }
+ ]
+ }
+ },
+ {
+ "name": "AnyOfEmpty",
+ "inherits": "Base",
+ "condition": {
+ "type": "anyOf",
+ "conditions": []
+ }
+ },
+ {
+ "name": "AllOfTrue",
+ "inherits": "Base",
+ "condition": {
+ "type": "allOf",
+ "conditions": [
+ true,
+ {
+ "type": "equals",
+ "lhs": "abc",
+ "rhs": "abc"
+ }
+ ]
+ }
+ },
+ {
+ "name": "AllOfFalse1",
+ "inherits": "Base",
+ "condition": {
+ "type": "allOf",
+ "conditions": [
+ false,
+ true
+ ]
+ }
+ },
+ {
+ "name": "AllOfFalse2",
+ "inherits": "Base",
+ "condition": {
+ "type": "allOf",
+ "conditions": [
+ true,
+ false
+ ]
+ }
+ },
+ {
+ "name": "AllOfShortCircuit",
+ "inherits": "Base",
+ "condition": {
+ "type": "allOf",
+ "conditions": [
+ false,
+ {
+ "type": "equals",
+ "lhs": "${invalidMacro}",
+ "rhs": ""
+ }
+ ]
+ }
+ },
+ {
+ "name": "AllOfEmpty",
+ "inherits": "Base",
+ "condition": {
+ "type": "allOf",
+ "conditions": []
+ }
+ },
+ {
+ "name": "NotTrue",
+ "inherits": "Base",
+ "condition": {
+ "type": "not",
+ "condition": true
+ }
+ },
+ {
+ "name": "NotFalse",
+ "inherits": "Base",
+ "condition": {
+ "type": "not",
+ "condition": false
+ }
+ },
+ {
+ "name": "InheritanceBase",
+ "inherits": "Base",
+ "hidden": true,
+ "condition": {
+ "type": "equals",
+ "lhs": "${presetName}",
+ "rhs": "InheritanceChildTrue"
+ }
+ },
+ {
+ "name": "InheritanceChildTrue",
+ "inherits": "InheritanceBase"
+ },
+ {
+ "name": "InheritanceChildFalse",
+ "inherits": "InheritanceBase"
+ },
+ {
+ "name": "InheritanceNull",
+ "inherits": "Null"
+ },
+ {
+ "name": "InheritanceNullFalse",
+ "inherits": [
+ "Null",
+ "SimpleFalse"
+ ]
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/CyclicInheritance0-result.txt b/Tests/RunCMake/CMakePresets/CyclicInheritance0-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/CyclicInheritance0-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/CyclicInheritance0-stderr.txt b/Tests/RunCMake/CMakePresets/CyclicInheritance0-stderr.txt
new file mode 100644
index 0000000..895afcb
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/CyclicInheritance0-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/CyclicInheritance0: Cyclic preset inheritance$
diff --git a/Tests/RunCMake/CMakePresets/CyclicInheritance0.json.in b/Tests/RunCMake/CMakePresets/CyclicInheritance0.json.in
new file mode 100644
index 0000000..3468936
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/CyclicInheritance0.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "CyclicInheritance0",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "inherits": [
+ "CyclicInheritance0"
+ ]
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/CyclicInheritance1-result.txt b/Tests/RunCMake/CMakePresets/CyclicInheritance1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/CyclicInheritance1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/CyclicInheritance1-stderr.txt b/Tests/RunCMake/CMakePresets/CyclicInheritance1-stderr.txt
new file mode 100644
index 0000000..1e59e92
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/CyclicInheritance1-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/CyclicInheritance1: Cyclic preset inheritance$
diff --git a/Tests/RunCMake/CMakePresets/CyclicInheritance1.json.in b/Tests/RunCMake/CMakePresets/CyclicInheritance1.json.in
new file mode 100644
index 0000000..fabd4af
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/CyclicInheritance1.json.in
@@ -0,0 +1,21 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "CyclicInheritance0",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "inherits": [
+ "CyclicInheritance1"
+ ]
+ },
+ {
+ "name": "CyclicInheritance1",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "inherits": [
+ "CyclicInheritance0"
+ ]
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/CyclicInheritance2-result.txt b/Tests/RunCMake/CMakePresets/CyclicInheritance2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/CyclicInheritance2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/CyclicInheritance2-stderr.txt b/Tests/RunCMake/CMakePresets/CyclicInheritance2-stderr.txt
new file mode 100644
index 0000000..56e630b
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/CyclicInheritance2-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/CyclicInheritance2: Cyclic preset inheritance$
diff --git a/Tests/RunCMake/CMakePresets/CyclicInheritance2.json.in b/Tests/RunCMake/CMakePresets/CyclicInheritance2.json.in
new file mode 100644
index 0000000..0e1d7d4
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/CyclicInheritance2.json.in
@@ -0,0 +1,29 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "CyclicInheritance0",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "inherits": [
+ "CyclicInheritance1"
+ ]
+ },
+ {
+ "name": "CyclicInheritance1",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "inherits": [
+ "CyclicInheritance2"
+ ]
+ },
+ {
+ "name": "CyclicInheritance2",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "inherits": [
+ "CyclicInheritance0"
+ ]
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/Debug-stderr.txt b/Tests/RunCMake/CMakePresets/Debug-stderr.txt
new file mode 100644
index 0000000..7fdb8b3
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/Debug-stderr.txt
@@ -0,0 +1 @@
+ find_package considered the following locations for the Config module:
diff --git a/Tests/RunCMake/CMakePresets/Debug-stdout.txt b/Tests/RunCMake/CMakePresets/Debug-stdout.txt
new file mode 100644
index 0000000..7d1f388
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/Debug-stdout.txt
@@ -0,0 +1,4 @@
+-- Generating [^
+]*/Tests/RunCMake/CMakePresets/Debug/build
+ Called from: \[1\][^
+]*/Tests/RunCMake/CMakePresets/Debug/CMakeLists\.txt
diff --git a/Tests/RunCMake/CMakePresets/Debug.cmake b/Tests/RunCMake/CMakePresets/Debug.cmake
new file mode 100644
index 0000000..19c7db2
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/Debug.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/DebugBase.cmake)
+if(NOT EXISTS "${CMAKE_BINARY_DIR}/CMakeFiles/CMakeTmp/CMakeLists.txt")
+ message(SEND_ERROR "Debugging try_compile() did not work")
+endif()
diff --git a/Tests/RunCMake/CMakePresets/Debug.json.in b/Tests/RunCMake/CMakePresets/Debug.json.in
new file mode 100644
index 0000000..500700e
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/Debug.json.in
@@ -0,0 +1,19 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "NoDebug",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "Debug",
+ "inherits": "NoDebug",
+ "debug": {
+ "output": true,
+ "find": true,
+ "tryCompile": true
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/DebugBase.cmake b/Tests/RunCMake/CMakePresets/DebugBase.cmake
new file mode 100644
index 0000000..870f31c
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/DebugBase.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+try_compile(_result ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_LIST_DIR}/main.c)
+find_package(ThisPackageHopefullyDoesNotExist CONFIG)
diff --git a/Tests/RunCMake/CMakePresets/DisableWarningFlags.cmake b/Tests/RunCMake/CMakePresets/DisableWarningFlags.cmake
new file mode 100644
index 0000000..5de7687
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/DisableWarningFlags.cmake
@@ -0,0 +1 @@
+include(${CMAKE_CURRENT_LIST_DIR}/WarningsBase.cmake)
diff --git a/Tests/RunCMake/CMakePresets/DocumentationExample.cmake b/Tests/RunCMake/CMakePresets/DocumentationExample.cmake
new file mode 100644
index 0000000..d459e9e
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/DocumentationExample.cmake
@@ -0,0 +1,5 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(FIRST_CACHE_VARIABLE "BOOL" "OFF")
+test_variable(SECOND_CACHE_VARIABLE "UNINITIALIZED" "ON")
+test_environment_variable(MY_ENVIRONMENT_VARIABLE "Test")
diff --git a/Tests/RunCMake/CMakePresets/DuplicatePresets-result.txt b/Tests/RunCMake/CMakePresets/DuplicatePresets-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/DuplicatePresets-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/DuplicatePresets-stderr.txt b/Tests/RunCMake/CMakePresets/DuplicatePresets-stderr.txt
new file mode 100644
index 0000000..c9361ae
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/DuplicatePresets-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/DuplicatePresets: Duplicate presets$
diff --git a/Tests/RunCMake/CMakePresets/DuplicatePresets.json.in b/Tests/RunCMake/CMakePresets/DuplicatePresets.json.in
new file mode 100644
index 0000000..cf388e7
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/DuplicatePresets.json.in
@@ -0,0 +1,15 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "DuplicatePresets",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "DuplicatePresets",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/EmptyCacheKey-result.txt b/Tests/RunCMake/CMakePresets/EmptyCacheKey-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyCacheKey-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/EmptyCacheKey-stderr.txt b/Tests/RunCMake/CMakePresets/EmptyCacheKey-stderr.txt
new file mode 100644
index 0000000..749d306
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyCacheKey-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/EmptyCacheKey: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/EmptyCacheKey.json.in b/Tests/RunCMake/CMakePresets/EmptyCacheKey.json.in
new file mode 100644
index 0000000..ea9c9e4
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyCacheKey.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "EmptyCacheKey",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "": "value"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/EmptyEnv-result.txt b/Tests/RunCMake/CMakePresets/EmptyEnv-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyEnv-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/EmptyEnv-stderr.txt b/Tests/RunCMake/CMakePresets/EmptyEnv-stderr.txt
new file mode 100644
index 0000000..723ac21
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyEnv-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/EmptyEnv: Invalid macro expansion$
diff --git a/Tests/RunCMake/CMakePresets/EmptyEnv.json.in b/Tests/RunCMake/CMakePresets/EmptyEnv.json.in
new file mode 100644
index 0000000..ef0d575
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyEnv.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "EmptyEnv",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "MY_VAR": "$env{}"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/EmptyEnvKey-result.txt b/Tests/RunCMake/CMakePresets/EmptyEnvKey-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyEnvKey-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/EmptyEnvKey-stderr.txt b/Tests/RunCMake/CMakePresets/EmptyEnvKey-stderr.txt
new file mode 100644
index 0000000..365f537
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyEnvKey-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/EmptyEnvKey: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/EmptyEnvKey.json.in b/Tests/RunCMake/CMakePresets/EmptyEnvKey.json.in
new file mode 100644
index 0000000..d87c159
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyEnvKey.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "EmptyEnvKey",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "environment": {
+ "": "value"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/EmptyPenv-result.txt b/Tests/RunCMake/CMakePresets/EmptyPenv-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyPenv-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/EmptyPenv-stderr.txt b/Tests/RunCMake/CMakePresets/EmptyPenv-stderr.txt
new file mode 100644
index 0000000..880cee6
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyPenv-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/EmptyPenv: Invalid macro expansion$
diff --git a/Tests/RunCMake/CMakePresets/EmptyPenv.json.in b/Tests/RunCMake/CMakePresets/EmptyPenv.json.in
new file mode 100644
index 0000000..9081fe5
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyPenv.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "EmptyPenv",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "MY_VAR": "$penv{}"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/EmptyPresetName-result.txt b/Tests/RunCMake/CMakePresets/EmptyPresetName-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyPresetName-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/EmptyPresetName-stderr.txt b/Tests/RunCMake/CMakePresets/EmptyPresetName-stderr.txt
new file mode 100644
index 0000000..6970674
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyPresetName-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/EmptyPresetName: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/EmptyPresetName.json.in b/Tests/RunCMake/CMakePresets/EmptyPresetName.json.in
new file mode 100644
index 0000000..fd4bedd
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EmptyPresetName.json.in
@@ -0,0 +1,10 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/EnvCycle-result.txt b/Tests/RunCMake/CMakePresets/EnvCycle-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EnvCycle-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/EnvCycle-stderr.txt b/Tests/RunCMake/CMakePresets/EnvCycle-stderr.txt
new file mode 100644
index 0000000..1d22b87
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EnvCycle-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/EnvCycle: Invalid macro expansion$
diff --git a/Tests/RunCMake/CMakePresets/EnvCycle.json.in b/Tests/RunCMake/CMakePresets/EnvCycle.json.in
new file mode 100644
index 0000000..25a1349
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/EnvCycle.json.in
@@ -0,0 +1,14 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "EnvCycle",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "environment": {
+ "ENV_1": "$env{ENV_2}",
+ "ENV_2": "$env{ENV_1}"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/ErrorDeprecated-result.txt b/Tests/RunCMake/CMakePresets/ErrorDeprecated-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ErrorDeprecated-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/ErrorDeprecated-stderr.txt b/Tests/RunCMake/CMakePresets/ErrorDeprecated-stderr.txt
new file mode 100644
index 0000000..964a504
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ErrorDeprecated-stderr.txt
@@ -0,0 +1,7 @@
+^CMake Deprecation Error at [^
+]*/Tests/RunCMake/CMakePresets/WarningsBase\.cmake:[0-9]+ \(message\):
+ Deprecation warning
+Call Stack \(most recent call first\):
+ [^
+]*/Tests/RunCMake/CMakePresets/ErrorDeprecated\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMakePresets/ErrorDeprecated.cmake b/Tests/RunCMake/CMakePresets/ErrorDeprecated.cmake
new file mode 100644
index 0000000..5de7687
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ErrorDeprecated.cmake
@@ -0,0 +1 @@
+include(${CMAKE_CURRENT_LIST_DIR}/WarningsBase.cmake)
diff --git a/Tests/RunCMake/CMakePresets/ErrorDev-result.txt b/Tests/RunCMake/CMakePresets/ErrorDev-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ErrorDev-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/ErrorDev-stderr.txt b/Tests/RunCMake/CMakePresets/ErrorDev-stderr.txt
new file mode 100644
index 0000000..f76478c
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ErrorDev-stderr.txt
@@ -0,0 +1,8 @@
+^CMake Error \(dev\) at [^
+]*/Tests/RunCMake/CMakePresets/WarningsBase\.cmake:[0-9]+ \(message\):
+ Dev warning
+Call Stack \(most recent call first\):
+ [^
+]*/Tests/RunCMake/CMakePresets/ErrorDev\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This error is for project developers\. Use -Wno-error=dev to suppress it\.$
diff --git a/Tests/RunCMake/CMakePresets/ErrorDev.cmake b/Tests/RunCMake/CMakePresets/ErrorDev.cmake
new file mode 100644
index 0000000..5de7687
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ErrorDev.cmake
@@ -0,0 +1 @@
+include(${CMAKE_CURRENT_LIST_DIR}/WarningsBase.cmake)
diff --git a/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated-result.txt b/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated-stderr.txt b/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated-stderr.txt
new file mode 100644
index 0000000..3221345
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated.json.in b/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated.json.in
new file mode 100644
index 0000000..664b3ee
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated.json.in
@@ -0,0 +1,16 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "ErrorNoWarningDeprecated",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "warnings": {
+ "deprecated": false
+ },
+ "errors": {
+ "deprecated": true
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/ErrorNoWarningDev-result.txt b/Tests/RunCMake/CMakePresets/ErrorNoWarningDev-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ErrorNoWarningDev-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/ErrorNoWarningDev-stderr.txt b/Tests/RunCMake/CMakePresets/ErrorNoWarningDev-stderr.txt
new file mode 100644
index 0000000..d2ddb90
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ErrorNoWarningDev-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/ErrorNoWarningDev: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/ErrorNoWarningDev.json.in b/Tests/RunCMake/CMakePresets/ErrorNoWarningDev.json.in
new file mode 100644
index 0000000..d681b2a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ErrorNoWarningDev.json.in
@@ -0,0 +1,16 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "ErrorNoWarningDev",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "warnings": {
+ "dev": false
+ },
+ "errors": {
+ "dev": true
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/ExtraPresetField-result.txt b/Tests/RunCMake/CMakePresets/ExtraPresetField-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ExtraPresetField-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/ExtraPresetField-stderr.txt b/Tests/RunCMake/CMakePresets/ExtraPresetField-stderr.txt
new file mode 100644
index 0000000..559e3c2
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ExtraPresetField-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/ExtraPresetField: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/ExtraPresetField.json.in b/Tests/RunCMake/CMakePresets/ExtraPresetField.json.in
new file mode 100644
index 0000000..b529758
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ExtraPresetField.json.in
@@ -0,0 +1,11 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "ExtraPresetField",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "invalid": true
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/ExtraRootField-result.txt b/Tests/RunCMake/CMakePresets/ExtraRootField-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ExtraRootField-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/ExtraRootField-stderr.txt b/Tests/RunCMake/CMakePresets/ExtraRootField-stderr.txt
new file mode 100644
index 0000000..bb281be
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ExtraRootField-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/ExtraRootField: Invalid root object$
diff --git a/Tests/RunCMake/CMakePresets/ExtraRootField.json.in b/Tests/RunCMake/CMakePresets/ExtraRootField.json.in
new file mode 100644
index 0000000..bcfa68b
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ExtraRootField.json.in
@@ -0,0 +1,11 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "ExtraRootField",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ],
+ "invalid": true
+}
diff --git a/Tests/RunCMake/CMakePresets/ExtraVariableField-result.txt b/Tests/RunCMake/CMakePresets/ExtraVariableField-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ExtraVariableField-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/ExtraVariableField-stderr.txt b/Tests/RunCMake/CMakePresets/ExtraVariableField-stderr.txt
new file mode 100644
index 0000000..9b346e7
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ExtraVariableField-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/ExtraVariableField: Invalid CMake variable definition$
diff --git a/Tests/RunCMake/CMakePresets/ExtraVariableField.json.in b/Tests/RunCMake/CMakePresets/ExtraVariableField.json.in
new file mode 100644
index 0000000..a810560
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ExtraVariableField.json.in
@@ -0,0 +1,16 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "ExtraVariableField",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "EXTRA": {
+ "value": "",
+ "invalid": true
+ }
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField-result.txt b/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField-stderr.txt b/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField-stderr.txt
new file mode 100644
index 0000000..36123bd
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField: File version must be 3 or higher for installDir preset support.$
diff --git a/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField.json.in b/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField.json.in
new file mode 100644
index 0000000..2e5f7d5
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField.json.in
@@ -0,0 +1,11 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "FuturePresetInstallDirField",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "installDir": "${sourceDir}/install"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/Good-stdout.txt b/Tests/RunCMake/CMakePresets/Good-stdout.txt
new file mode 100644
index 0000000..75003c7
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/Good-stdout.txt
@@ -0,0 +1,53 @@
+Preset CMake variables:
+
+ TEST_BOOL_FALSE:BOOL="FALSE"
+ TEST_BOOL_TRUE:BOOL="TRUE"
+ TEST_DOLLAR="\$"
+ TEST_D_ENV_REF="xEnvironment variablex"
+ TEST_D_ENV_REF_P=""
+ TEST_ENV="Environment variable"
+ TEST_ENV_OVERRIDE="Overridden environment variable"
+ TEST_ENV_OVERRIDE_P="This environment variable will be overridden"
+ TEST_ENV_P=""
+ TEST_ENV_REF="Environment variable"
+ TEST_ENV_REF_P=""
+ TEST_ENV_REF_PENV="prefix\+suffix"
+ TEST_ENV_REF_PENV_P="suffix"
+ TEST_EXPANSION="\\Good \${dollar} \$unknown{namespace} \$en{NOT_ENV} \$enve{NOT_ENV} \$ \\\$ \$a"
+ TEST_GENERATOR="x[^
+]*x"
+ TEST_MULTIPLE_MACROS="Good [^
+]*"
+ TEST_OFF:BOOL="OFF"
+ TEST_OVERRIDE_3:STRING="Default value"
+ TEST_OVERRIDE_4:STRING="Default value"
+ TEST_PENV="Process environment variable"
+ TEST_PENV_P="Process environment variable"
+ TEST_PRESET_NAME:STRING="xGoodx"
+ TEST_SOURCE_DIR:PATH="[^
+]*/Tests/RunCMake/CMakePresets/Good"
+ TEST_SOURCE_DIR_NAME="Good"
+ TEST_SOURCE_LIST:FILEPATH="[^
+]*/Tests/RunCMake/CMakePresets/Good/CMakeLists\.txt"
+ TEST_SOURCE_PARENT_DIR:PATH="[^
+]*/Tests/RunCMake/CMakePresets"
+ TEST_TRAILING_BACKSLASH="a \\"
+ TEST_TRAILING_DOLLAR="a \$"
+ TEST_TRAILING_UNKNOWN_NAMESPACE="\$unknown{namespace"
+ TEST_TRUE:BOOL="TRUE"
+ TEST_TYPED_BOOL_FALSE:STRING="FALSE"
+ TEST_TYPED_BOOL_TRUE:STRING="TRUE"
+ TEST_UNTYPED_BOOL_FALSE="FALSE"
+ TEST_UNTYPED_BOOL_TRUE="TRUE"
+
+Preset environment variables:
+
+ TEST_D_ENV_REF="xEnvironment variablex"
+ TEST_ENV="Environment variable"
+ TEST_ENV_OVERRIDE="Overridden environment variable"
+ TEST_ENV_REF="Environment variable"
+ TEST_ENV_REF_PENV="prefix\+suffix"
+
+(-- Selecting Windows SDK version [^
+]*
+)?-- Configuring done
diff --git a/Tests/RunCMake/CMakePresets/Good.cmake b/Tests/RunCMake/CMakePresets/Good.cmake
new file mode 100644
index 0000000..73a618d
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/Good.cmake
@@ -0,0 +1,52 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+get_filename_component(_parent_dir "${CMAKE_SOURCE_DIR}" DIRECTORY)
+test_variable(CMAKE_BINARY_DIR "" "${CMAKE_SOURCE_DIR}/build")
+test_variable(CMAKE_GENERATOR "" "${RunCMake_GENERATOR}")
+test_variable(TEST_SOURCE_DIR "PATH" "${CMAKE_SOURCE_DIR}")
+test_variable(TEST_SOURCE_PARENT_DIR "PATH" "${_parent_dir}")
+test_variable(TEST_SOURCE_LIST "FILEPATH" "${CMAKE_SOURCE_DIR}/CMakeLists.txt")
+test_variable(TEST_TRUE "BOOL" "TRUE")
+test_variable(TEST_OFF "BOOL" "OFF")
+test_variable(TEST_BOOL_TRUE "BOOL" "TRUE")
+test_variable(TEST_BOOL_FALSE "BOOL" "FALSE")
+test_variable(TEST_TYPED_BOOL_TRUE "STRING" "TRUE")
+test_variable(TEST_TYPED_BOOL_FALSE "STRING" "FALSE")
+test_variable(TEST_UNTYPED_BOOL_TRUE "UNINITIALIZED" "TRUE")
+test_variable(TEST_UNTYPED_BOOL_FALSE "UNINITIALIZED" "FALSE")
+test_variable(TEST_PRESET_NAME "STRING" "xGoodx")
+test_variable(TEST_GENERATOR "UNINITIALIZED" "x${CMAKE_GENERATOR}x")
+test_variable(TEST_DOLLAR "UNINITIALIZED" "$")
+test_variable(TEST_SOURCE_DIR_NAME "UNINITIALIZED" "Good")
+test_variable(TEST_ENV_REF "UNINITIALIZED" "Environment variable")
+test_variable(TEST_ENV "UNINITIALIZED" "Environment variable")
+test_variable(TEST_D_ENV_REF "UNINITIALIZED" "xEnvironment variablex")
+test_variable(TEST_ENV_OVERRIDE "UNINITIALIZED" "Overridden environment variable")
+test_variable(TEST_PENV "UNINITIALIZED" "Process environment variable")
+test_variable(TEST_ENV_REF_PENV "UNINITIALIZED" "prefix+suffix")
+test_variable(TEST_ENV_REF_P "UNINITIALIZED" "")
+test_variable(TEST_ENV_P "UNINITIALIZED" "")
+test_variable(TEST_D_ENV_REF_P "UNINITIALIZED" "")
+test_variable(TEST_ENV_OVERRIDE_P "UNINITIALIZED" "This environment variable will be overridden")
+test_variable(TEST_PENV_P "UNINITIALIZED" "Process environment variable")
+test_variable(TEST_ENV_REF_PENV_P "UNINITIALIZED" "suffix")
+test_variable(TEST_MULTIPLE_MACROS "UNINITIALIZED" "Good ${CMAKE_GENERATOR}")
+test_variable(TEST_EXPANSION "UNINITIALIZED" "\\Good \${dollar} \$unknown{namespace} \$en{NOT_ENV} \$enve{NOT_ENV} $ \\$ $a")
+test_variable(TEST_TRAILING_DOLLAR "UNINITIALIZED" "a $")
+test_variable(TEST_TRAILING_BACKSLASH "UNINITIALIZED" "a \\")
+test_variable(TEST_TRAILING_UNKNOWN_NAMESPACE "UNINITIALIZED" "\$unknown{namespace")
+test_variable(TEST_OVERRIDE_1 "UNINITIALIZED" "Overridden value")
+test_variable(TEST_OVERRIDE_2 "STRING" "Overridden value")
+test_variable(TEST_OVERRIDE_3 "STRING" "Default value")
+test_variable(TEST_OVERRIDE_4 "INTERNAL" "Overridden value")
+
+if(DEFINED TEST_UNDEF OR DEFINED CACHE{TEST_UNDEF})
+ message(SEND_ERROR "TEST_UNDEF should not be defined")
+endif()
+
+test_environment_variable(TEST_ENV_REF "Environment variable")
+test_environment_variable(TEST_ENV "Environment variable")
+test_environment_variable(TEST_D_ENV_REF "xEnvironment variablex")
+test_environment_variable(TEST_ENV_OVERRIDE "Overridden environment variable")
+test_environment_variable(TEST_PENV "Process environment variable")
+test_environment_variable(TEST_ENV_REF_PENV "prefix+suffix")
diff --git a/Tests/RunCMake/CMakePresets/GoodBOM.cmake b/Tests/RunCMake/CMakePresets/GoodBOM.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodBOM.cmake
diff --git a/Tests/RunCMake/CMakePresets/GoodBOM.json.in b/Tests/RunCMake/CMakePresets/GoodBOM.json.in
new file mode 100644
index 0000000..2152511
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodBOM.json.in
@@ -0,0 +1,10 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "GoodBOM",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/GoodBinaryCmdLine.cmake b/Tests/RunCMake/CMakePresets/GoodBinaryCmdLine.cmake
new file mode 100644
index 0000000..9f928fe
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodBinaryCmdLine.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+get_filename_component(_parent "${CMAKE_SOURCE_DIR}" DIRECTORY)
+test_variable(CMAKE_BINARY_DIR "" "${_parent}/GoodBinaryCmdLine-build")
diff --git a/Tests/RunCMake/CMakePresets/GoodBinaryRelative.cmake b/Tests/RunCMake/CMakePresets/GoodBinaryRelative.cmake
new file mode 100644
index 0000000..49e7a25
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodBinaryRelative.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_BINARY_DIR "" "${CMAKE_SOURCE_DIR}/build")
diff --git a/Tests/RunCMake/CMakePresets/GoodBinaryUp.cmake b/Tests/RunCMake/CMakePresets/GoodBinaryUp.cmake
new file mode 100644
index 0000000..f7fb224
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodBinaryUp.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+get_filename_component(_parent "${CMAKE_SOURCE_DIR}" DIRECTORY)
+test_variable(CMAKE_BINARY_DIR "" "${_parent}/GoodBinaryUp-build")
diff --git a/Tests/RunCMake/CMakePresets/GoodGeneratorCmdLine.cmake b/Tests/RunCMake/CMakePresets/GoodGeneratorCmdLine.cmake
new file mode 100644
index 0000000..4319e72
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodGeneratorCmdLine.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_GENERATOR "" "${RunCMake_GENERATOR}")
diff --git a/Tests/RunCMake/CMakePresets/GoodInheritanceChild.cmake b/Tests/RunCMake/CMakePresets/GoodInheritanceChild.cmake
new file mode 100644
index 0000000..cfc93be
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInheritanceChild.cmake
@@ -0,0 +1,6 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_BINARY_DIR "" "${CMAKE_SOURCE_DIR}/build")
+test_variable(TEST_VARIABLE "STRING" "Some string")
+
+test_environment_variable(TEST_ENV "Some environment variable")
diff --git a/Tests/RunCMake/CMakePresets/GoodInheritanceMacro.cmake b/Tests/RunCMake/CMakePresets/GoodInheritanceMacro.cmake
new file mode 100644
index 0000000..96fede0
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInheritanceMacro.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(PRESET_NAME "UNINITIALIZED" "GoodInheritanceMacro")
diff --git a/Tests/RunCMake/CMakePresets/GoodInheritanceMulti.cmake b/Tests/RunCMake/CMakePresets/GoodInheritanceMulti.cmake
new file mode 100644
index 0000000..6430f4d
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInheritanceMulti.cmake
@@ -0,0 +1,10 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_BINARY_DIR "" "${CMAKE_SOURCE_DIR}/build")
+test_variable(FIRST_VARIABLE "STRING" "First variable")
+test_variable(SECOND_VARIABLE "STRING" "Second variable")
+test_variable(OVERRIDDEN_VARIABLE "STRING" "Overridden variable")
+
+test_environment_variable(FIRST_ENV "First environment variable")
+test_environment_variable(SECOND_ENV "Second environment variable")
+test_environment_variable(OVERRIDDEN_ENV "Overridden environment variable")
diff --git a/Tests/RunCMake/CMakePresets/GoodInheritanceMultiSecond.cmake b/Tests/RunCMake/CMakePresets/GoodInheritanceMultiSecond.cmake
new file mode 100644
index 0000000..49e7a25
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInheritanceMultiSecond.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_BINARY_DIR "" "${CMAKE_SOURCE_DIR}/build")
diff --git a/Tests/RunCMake/CMakePresets/GoodInheritanceOverride.cmake b/Tests/RunCMake/CMakePresets/GoodInheritanceOverride.cmake
new file mode 100644
index 0000000..5231803
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInheritanceOverride.cmake
@@ -0,0 +1,18 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_BINARY_DIR "" "${CMAKE_SOURCE_DIR}/build")
+test_variable(PARENT_VARIABLE "STRING" "Parent variable")
+test_variable(OVERRIDDEN_VARIABLE "STRING" "Overridden variable")
+test_variable(CHILD_VARIABLE "STRING" "Child variable")
+
+if(DEFINED DELETED_VARIABLE OR DEFINED CACHE{DELETED_VARIABLE})
+ message(SEND_ERROR "DELETED_VARIABLE should not be defined")
+endif()
+
+test_environment_variable(PARENT_ENV "Parent environment variable")
+test_environment_variable(CHILD_ENV "Child environment variable")
+test_environment_variable(OVERRIDDEN_ENV "Overridden environment variable")
+
+if(DEFINED ENV{DELETED_ENV})
+ message(SEND_ERROR "DELETED_ENV should not be defined")
+endif()
diff --git a/Tests/RunCMake/CMakePresets/GoodInheritanceParent.cmake b/Tests/RunCMake/CMakePresets/GoodInheritanceParent.cmake
new file mode 100644
index 0000000..cfc93be
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInheritanceParent.cmake
@@ -0,0 +1,6 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_BINARY_DIR "" "${CMAKE_SOURCE_DIR}/build")
+test_variable(TEST_VARIABLE "STRING" "Some string")
+
+test_environment_variable(TEST_ENV "Some environment variable")
diff --git a/Tests/RunCMake/CMakePresets/GoodInstall.json.in b/Tests/RunCMake/CMakePresets/GoodInstall.json.in
new file mode 100644
index 0000000..6287c65
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInstall.json.in
@@ -0,0 +1,30 @@
+{
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "GoodInstallDefault",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build/${presetName}",
+ "installDir": "${sourceDir}/build/install_dir1"
+ },
+ {
+ "name": "GoodInstallInherit",
+ "inherits": "GoodInstallDefault",
+ "cacheVariables": {
+ "CMAKE_INSTALL_PREFIX": {
+ "type": "PATH",
+ "value": "${sourceDir}/build/bad_path"
+ }
+ }
+ },
+ {
+ "name": "GoodInstallOverride",
+ "inherits": "GoodInstallInherit",
+ "installDir": "${sourceDir}/build/install_dir2"
+ },
+ {
+ "name": "GoodInstallCommandLine",
+ "inherits": "GoodInstallOverride"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/GoodInstallCommandLine.cmake b/Tests/RunCMake/CMakePresets/GoodInstallCommandLine.cmake
new file mode 100644
index 0000000..a4f6178
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInstallCommandLine.cmake
@@ -0,0 +1,3 @@
+include("${RunCMake_SOURCE_DIR}/TestVariable.cmake")
+
+test_variable("CMAKE_INSTALL_PREFIX" "PATH" "${RunCMake_SOURCE_DIR}/path/passed/on/command_line")
diff --git a/Tests/RunCMake/CMakePresets/GoodInstallDefault.cmake b/Tests/RunCMake/CMakePresets/GoodInstallDefault.cmake
new file mode 100644
index 0000000..656fda0
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInstallDefault.cmake
@@ -0,0 +1,3 @@
+include("${RunCMake_SOURCE_DIR}/TestVariable.cmake")
+
+test_variable("CMAKE_INSTALL_PREFIX" "PATH" "${CMAKE_SOURCE_DIR}/build/install_dir1")
diff --git a/Tests/RunCMake/CMakePresets/GoodInstallInherit.cmake b/Tests/RunCMake/CMakePresets/GoodInstallInherit.cmake
new file mode 100644
index 0000000..656fda0
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInstallInherit.cmake
@@ -0,0 +1,3 @@
+include("${RunCMake_SOURCE_DIR}/TestVariable.cmake")
+
+test_variable("CMAKE_INSTALL_PREFIX" "PATH" "${CMAKE_SOURCE_DIR}/build/install_dir1")
diff --git a/Tests/RunCMake/CMakePresets/GoodInstallOverride.cmake b/Tests/RunCMake/CMakePresets/GoodInstallOverride.cmake
new file mode 100644
index 0000000..3d12b07
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInstallOverride.cmake
@@ -0,0 +1,3 @@
+include("${RunCMake_SOURCE_DIR}/TestVariable.cmake")
+
+test_variable("CMAKE_INSTALL_PREFIX" "PATH" "${CMAKE_SOURCE_DIR}/build/install_dir2")
diff --git a/Tests/RunCMake/CMakePresets/GoodNoArgs.cmake b/Tests/RunCMake/CMakePresets/GoodNoArgs.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodNoArgs.cmake
diff --git a/Tests/RunCMake/CMakePresets/GoodNoS.cmake b/Tests/RunCMake/CMakePresets/GoodNoS.cmake
new file mode 100644
index 0000000..49e7a25
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodNoS.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_BINARY_DIR "" "${CMAKE_SOURCE_DIR}/build")
diff --git a/Tests/RunCMake/CMakePresets/GoodNoSCache.cmake b/Tests/RunCMake/CMakePresets/GoodNoSCache.cmake
new file mode 100644
index 0000000..df58e72
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodNoSCache.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+get_filename_component(_parent "${CMAKE_SOURCE_DIR}" DIRECTORY)
+test_variable(CMAKE_BINARY_DIR "" "${_parent}/GoodNoSCachePrep-build")
diff --git a/Tests/RunCMake/CMakePresets/GoodNoSCachePrep.cmake b/Tests/RunCMake/CMakePresets/GoodNoSCachePrep.cmake
new file mode 100644
index 0000000..df58e72
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodNoSCachePrep.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+get_filename_component(_parent "${CMAKE_SOURCE_DIR}" DIRECTORY)
+test_variable(CMAKE_BINARY_DIR "" "${_parent}/GoodNoSCachePrep-build")
diff --git a/Tests/RunCMake/CMakePresets/GoodNoSourceArg.cmake b/Tests/RunCMake/CMakePresets/GoodNoSourceArg.cmake
new file mode 100644
index 0000000..49e7a25
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodNoSourceArg.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_BINARY_DIR "" "${CMAKE_SOURCE_DIR}/build")
diff --git a/Tests/RunCMake/CMakePresets/GoodSpaces-stdout.txt b/Tests/RunCMake/CMakePresets/GoodSpaces-stdout.txt
new file mode 100644
index 0000000..d106c45
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodSpaces-stdout.txt
@@ -0,0 +1,3 @@
+Preset CMake variables:
+
+ GOOD_SPACES:STRING="1"
diff --git a/Tests/RunCMake/CMakePresets/GoodSpaces.cmake b/Tests/RunCMake/CMakePresets/GoodSpaces.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodSpaces.cmake
diff --git a/Tests/RunCMake/CMakePresets/GoodSpacesEq-stdout.txt b/Tests/RunCMake/CMakePresets/GoodSpacesEq-stdout.txt
new file mode 100644
index 0000000..d106c45
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodSpacesEq-stdout.txt
@@ -0,0 +1,3 @@
+Preset CMake variables:
+
+ GOOD_SPACES:STRING="1"
diff --git a/Tests/RunCMake/CMakePresets/GoodSpacesEq.cmake b/Tests/RunCMake/CMakePresets/GoodSpacesEq.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodSpacesEq.cmake
diff --git a/Tests/RunCMake/CMakePresets/GoodUserFromMain.cmake b/Tests/RunCMake/CMakePresets/GoodUserFromMain.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodUserFromMain.cmake
diff --git a/Tests/RunCMake/CMakePresets/GoodUserFromMain.json.in b/Tests/RunCMake/CMakePresets/GoodUserFromMain.json.in
new file mode 100644
index 0000000..348443e
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodUserFromMain.json.in
@@ -0,0 +1,10 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "GoodUserFromMain",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/GoodUserFromMainUser.json.in b/Tests/RunCMake/CMakePresets/GoodUserFromMainUser.json.in
new file mode 100644
index 0000000..77b4ef6
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodUserFromMainUser.json.in
@@ -0,0 +1,4 @@
+{
+ "version": 1,
+ "configurePresets": []
+}
diff --git a/Tests/RunCMake/CMakePresets/GoodUserFromUser.cmake b/Tests/RunCMake/CMakePresets/GoodUserFromUser.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodUserFromUser.cmake
diff --git a/Tests/RunCMake/CMakePresets/GoodUserFromUser.json.in b/Tests/RunCMake/CMakePresets/GoodUserFromUser.json.in
new file mode 100644
index 0000000..77b4ef6
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodUserFromUser.json.in
@@ -0,0 +1,4 @@
+{
+ "version": 1,
+ "configurePresets": []
+}
diff --git a/Tests/RunCMake/CMakePresets/GoodUserFromUserUser.json.in b/Tests/RunCMake/CMakePresets/GoodUserFromUserUser.json.in
new file mode 100644
index 0000000..83196be
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodUserFromUserUser.json.in
@@ -0,0 +1,10 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "GoodUserFromUser",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/GoodUserOnly.cmake b/Tests/RunCMake/CMakePresets/GoodUserOnly.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodUserOnly.cmake
diff --git a/Tests/RunCMake/CMakePresets/GoodUserOnlyUser.json.in b/Tests/RunCMake/CMakePresets/GoodUserOnlyUser.json.in
new file mode 100644
index 0000000..274f4c7
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodUserOnlyUser.json.in
@@ -0,0 +1,10 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "GoodUserOnly",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/GoodWindowsBackslash.cmake b/Tests/RunCMake/CMakePresets/GoodWindowsBackslash.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodWindowsBackslash.cmake
diff --git a/Tests/RunCMake/CMakePresets/HighVersion-result.txt b/Tests/RunCMake/CMakePresets/HighVersion-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/HighVersion-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/HighVersion-stderr.txt b/Tests/RunCMake/CMakePresets/HighVersion-stderr.txt
new file mode 100644
index 0000000..d8622f2
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/HighVersion-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/HighVersion: Unrecognized "version" field$
diff --git a/Tests/RunCMake/CMakePresets/HighVersion.json.in b/Tests/RunCMake/CMakePresets/HighVersion.json.in
new file mode 100644
index 0000000..8107842
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/HighVersion.json.in
@@ -0,0 +1,4 @@
+{
+ "version": 1000,
+ "configurePresets": []
+}
diff --git a/Tests/RunCMake/CMakePresets/HostSystemName.cmake b/Tests/RunCMake/CMakePresets/HostSystemName.cmake
new file mode 100644
index 0000000..dc0998a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/HostSystemName.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(TEST_HOST_SYSTEM_NAME "" "${CMAKE_HOST_SYSTEM_NAME}")
diff --git a/Tests/RunCMake/CMakePresets/HostSystemName.json.in b/Tests/RunCMake/CMakePresets/HostSystemName.json.in
new file mode 100644
index 0000000..7fcd8c8
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/HostSystemName.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "HostSystemName",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "TEST_HOST_SYSTEM_NAME": "${hostSystemName}"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/HostSystemNameFuture-result.txt b/Tests/RunCMake/CMakePresets/HostSystemNameFuture-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/HostSystemNameFuture-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/HostSystemNameFuture-stderr.txt b/Tests/RunCMake/CMakePresets/HostSystemNameFuture-stderr.txt
new file mode 100644
index 0000000..7f4bb9a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/HostSystemNameFuture-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/HostSystemNameFuture: Invalid macro expansion$
diff --git a/Tests/RunCMake/CMakePresets/HostSystemNameFuture.json.in b/Tests/RunCMake/CMakePresets/HostSystemNameFuture.json.in
new file mode 100644
index 0000000..7a2f0aa
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/HostSystemNameFuture.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 2,
+ "configurePresets": [
+ {
+ "name": "HostSystemNameFuture",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "TEST_HOST_SYSTEM_NAME": "${hostSystemName}"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy-result.txt b/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy-stderr.txt
new file mode 100644
index 0000000..4a4d4ce
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy.json.in b/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy.json.in
new file mode 100644
index 0000000..9ec2cee
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidArchitectureStrategy.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "InvalidArchitectureStrategy",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "architecture": {
+ "strategy": {}
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidGenerator-result.txt b/Tests/RunCMake/CMakePresets/InvalidGenerator-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidGenerator-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidGenerator-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidGenerator-stderr.txt
new file mode 100644
index 0000000..c7dd19b
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidGenerator-stderr.txt
@@ -0,0 +1,3 @@
+^CMake Error: Could not create named generator Invalid Generator
+
+Generators
diff --git a/Tests/RunCMake/CMakePresets/InvalidGeneratorCmdLine-result.txt b/Tests/RunCMake/CMakePresets/InvalidGeneratorCmdLine-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidGeneratorCmdLine-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidGeneratorCmdLine-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidGeneratorCmdLine-stderr.txt
new file mode 100644
index 0000000..c7dd19b
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidGeneratorCmdLine-stderr.txt
@@ -0,0 +1,3 @@
+^CMake Error: Could not create named generator Invalid Generator
+
+Generators
diff --git a/Tests/RunCMake/CMakePresets/InvalidInheritance-result.txt b/Tests/RunCMake/CMakePresets/InvalidInheritance-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidInheritance-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidInheritance-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidInheritance-stderr.txt
new file mode 100644
index 0000000..97f3876
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidInheritance-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidInheritance: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/InvalidInheritance.json.in b/Tests/RunCMake/CMakePresets/InvalidInheritance.json.in
new file mode 100644
index 0000000..77bd9a3
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidInheritance.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "InvalidInheritance",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "inherits": [
+ "NoExist"
+ ]
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresetBinaryDir-result.txt b/Tests/RunCMake/CMakePresets/InvalidPresetBinaryDir-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresetBinaryDir-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresetBinaryDir-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidPresetBinaryDir-stderr.txt
new file mode 100644
index 0000000..2fe8c66
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresetBinaryDir-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidPresetBinaryDir: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresetBinaryDir.json.in b/Tests/RunCMake/CMakePresets/InvalidPresetBinaryDir.json.in
new file mode 100644
index 0000000..2bb95d9
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresetBinaryDir.json.in
@@ -0,0 +1,10 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "InvalidPresetBinaryDir",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": []
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresetGenerator-result.txt b/Tests/RunCMake/CMakePresets/InvalidPresetGenerator-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresetGenerator-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresetGenerator-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidPresetGenerator-stderr.txt
new file mode 100644
index 0000000..9572875
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresetGenerator-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidPresetGenerator: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresetGenerator.json.in b/Tests/RunCMake/CMakePresets/InvalidPresetGenerator.json.in
new file mode 100644
index 0000000..95e6e65
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresetGenerator.json.in
@@ -0,0 +1,10 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "InvalidPresetGenerator",
+ "generator": [],
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresetName-result.txt b/Tests/RunCMake/CMakePresets/InvalidPresetName-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresetName-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresetName-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidPresetName-stderr.txt
new file mode 100644
index 0000000..8f6ff7c
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresetName-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidPresetName: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresetName.json.in b/Tests/RunCMake/CMakePresets/InvalidPresetName.json.in
new file mode 100644
index 0000000..08361da
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresetName.json.in
@@ -0,0 +1,10 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": [],
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresetVendor-result.txt b/Tests/RunCMake/CMakePresets/InvalidPresetVendor-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresetVendor-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresetVendor-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidPresetVendor-stderr.txt
new file mode 100644
index 0000000..89a424a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresetVendor-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidPresetVendor: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresetVendor.json.in b/Tests/RunCMake/CMakePresets/InvalidPresetVendor.json.in
new file mode 100644
index 0000000..2a5d9ba
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresetVendor.json.in
@@ -0,0 +1,11 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "InvalidPresetVendor",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "vendor": true
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresets-result.txt b/Tests/RunCMake/CMakePresets/InvalidPresets-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresets-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresets-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidPresets-stderr.txt
new file mode 100644
index 0000000..2b0f560
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresets-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidPresets: Invalid "configurePresets" field$
diff --git a/Tests/RunCMake/CMakePresets/InvalidPresets.json.in b/Tests/RunCMake/CMakePresets/InvalidPresets.json.in
new file mode 100644
index 0000000..facfd57
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidPresets.json.in
@@ -0,0 +1,4 @@
+{
+ "version": 1,
+ "configurePresets": {}
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidRegex-result.txt b/Tests/RunCMake/CMakePresets/InvalidRegex-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidRegex-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidRegex-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidRegex-stderr.txt
new file mode 100644
index 0000000..5b500e4
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidRegex-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidRegex: Invalid macro expansion$
diff --git a/Tests/RunCMake/CMakePresets/InvalidRegex.json.in b/Tests/RunCMake/CMakePresets/InvalidRegex.json.in
new file mode 100644
index 0000000..69114d2
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidRegex.json.in
@@ -0,0 +1,15 @@
+{
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "InvalidRegex",
+ "binaryDir": "${sourceDir}/build",
+ "generator": "@RunCMake_GENERATOR@",
+ "condition": {
+ "type": "matches",
+ "string": "a",
+ "regex": "+"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidRoot-result.txt b/Tests/RunCMake/CMakePresets/InvalidRoot-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidRoot-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidRoot-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidRoot-stderr.txt
new file mode 100644
index 0000000..e5c434d
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidRoot-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidRoot: Invalid root object$
diff --git a/Tests/RunCMake/CMakePresets/InvalidRoot.json.in b/Tests/RunCMake/CMakePresets/InvalidRoot.json.in
new file mode 100644
index 0000000..fe51488
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidRoot.json.in
@@ -0,0 +1 @@
+[]
diff --git a/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy-result.txt b/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy-stderr.txt
new file mode 100644
index 0000000..fab3766
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy.json.in b/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy.json.in
new file mode 100644
index 0000000..7d2ab1f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidToolsetStrategy.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "InvalidToolsetStrategy",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "toolset": {
+ "strategy": {}
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidVariableValue-result.txt b/Tests/RunCMake/CMakePresets/InvalidVariableValue-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidVariableValue-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidVariableValue-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidVariableValue-stderr.txt
new file mode 100644
index 0000000..0ab07c3
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidVariableValue-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidVariableValue: Invalid CMake variable definition$
diff --git a/Tests/RunCMake/CMakePresets/InvalidVariableValue.json.in b/Tests/RunCMake/CMakePresets/InvalidVariableValue.json.in
new file mode 100644
index 0000000..55c7644
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidVariableValue.json.in
@@ -0,0 +1,15 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "InvalidVariableValue",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "VAR": {
+ "value": []
+ }
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidVariables-result.txt b/Tests/RunCMake/CMakePresets/InvalidVariables-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidVariables-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidVariables-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidVariables-stderr.txt
new file mode 100644
index 0000000..6d9102a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidVariables-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidVariables: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/InvalidVariables.json.in b/Tests/RunCMake/CMakePresets/InvalidVariables.json.in
new file mode 100644
index 0000000..30dcaf0
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidVariables.json.in
@@ -0,0 +1,11 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "InvalidVariables",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": []
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidVendor-result.txt b/Tests/RunCMake/CMakePresets/InvalidVendor-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidVendor-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidVendor-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidVendor-stderr.txt
new file mode 100644
index 0000000..af923f0
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidVendor-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidVendor: Invalid root object$
diff --git a/Tests/RunCMake/CMakePresets/InvalidVendor.json.in b/Tests/RunCMake/CMakePresets/InvalidVendor.json.in
new file mode 100644
index 0000000..2315b72
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidVendor.json.in
@@ -0,0 +1,5 @@
+{
+ "version": 1,
+ "vendor": true,
+ "configurePresets": []
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidVersion-result.txt b/Tests/RunCMake/CMakePresets/InvalidVersion-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidVersion-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidVersion-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidVersion-stderr.txt
new file mode 100644
index 0000000..7e0fcfd
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidVersion-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidVersion: Invalid "version" field$
diff --git a/Tests/RunCMake/CMakePresets/InvalidVersion.json.in b/Tests/RunCMake/CMakePresets/InvalidVersion.json.in
new file mode 100644
index 0000000..e6e19bc
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidVersion.json.in
@@ -0,0 +1,4 @@
+{
+ "version": "1.0",
+ "configurePresets": []
+}
diff --git a/Tests/RunCMake/CMakePresets/JSONParseError-result.txt b/Tests/RunCMake/CMakePresets/JSONParseError-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/JSONParseError-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/JSONParseError-stderr.txt b/Tests/RunCMake/CMakePresets/JSONParseError-stderr.txt
new file mode 100644
index 0000000..a43bf77
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/JSONParseError-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/JSONParseError: JSON parse error$
diff --git a/Tests/RunCMake/CMakePresets/JSONParseError.json.in b/Tests/RunCMake/CMakePresets/JSONParseError.json.in
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/JSONParseError.json.in
diff --git a/Tests/RunCMake/CMakePresets/ListConditions-stdout.txt b/Tests/RunCMake/CMakePresets/ListConditions-stdout.txt
new file mode 100644
index 0000000..91e0017
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ListConditions-stdout.txt
@@ -0,0 +1,26 @@
+Available configure presets:
+
+ "SimpleTrue"
+ "Null"
+ "ConstTrue"
+ "EqualsTrue"
+ "EqualsMacroLeft"
+ "EqualsMacroRight"
+ "NotEqualsTrue"
+ "InListTrue"
+ "InListMacroString"
+ "InListMacroList"
+ "InListShortCircuit"
+ "NotInListTrue"
+ "MatchesTrue"
+ "MatchesMacroString"
+ "MatchesMacroRegex"
+ "NotMatchesTrue"
+ "AnyOfTrue1"
+ "AnyOfTrue2"
+ "AnyOfShortCircuit"
+ "AllOfTrue"
+ "AllOfEmpty"
+ "NotFalse"
+ "InheritanceChildTrue"
+ "InheritanceNull"$
diff --git a/Tests/RunCMake/CMakePresets/ListPresets-stdout.txt b/Tests/RunCMake/CMakePresets/ListPresets-stdout.txt
new file mode 100644
index 0000000..60d6adb
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ListPresets-stdout.txt
@@ -0,0 +1,6 @@
+^Not searching for unused variables given on the command line\.
+Available configure presets:
+
+ "zzzzzz" - Sleepy
+ "aaaaaaaa" - Screaming
+ "mmmmmm"$
diff --git a/Tests/RunCMake/CMakePresets/ListPresets.json.in b/Tests/RunCMake/CMakePresets/ListPresets.json.in
new file mode 100644
index 0000000..2ef3797
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ListPresets.json.in
@@ -0,0 +1,36 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "zzzzzz",
+ "displayName": "Sleepy",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build/zzzzzz"
+ },
+ {
+ "name": "aaaaaaaa",
+ "displayName": "Screaming",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build/aaaaaaaa"
+ },
+ {
+ "name": "mmmmmm",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build/mmmmmm"
+ },
+ {
+ "name": "invalid-generator",
+ "generator": "Invalid Generator",
+ "binaryDir": "${sourceDir}/build/invalid"
+ },
+ {
+ "name": "invalid-macro",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "$vendor{noexist}"
+ },
+ {
+ "name": "ListPresetsHidden",
+ "hidden": true
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/ListPresetsHidden-result.txt b/Tests/RunCMake/CMakePresets/ListPresetsHidden-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ListPresetsHidden-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/ListPresetsHidden-stderr.txt b/Tests/RunCMake/CMakePresets/ListPresetsHidden-stderr.txt
new file mode 100644
index 0000000..1403814
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ListPresetsHidden-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Cannot use hidden preset in [^
+]*/Tests/RunCMake/CMakePresets/ListPresetsHidden: "ListPresetsHidden"$
diff --git a/Tests/RunCMake/CMakePresets/ListPresetsHidden-stdout.txt b/Tests/RunCMake/CMakePresets/ListPresetsHidden-stdout.txt
new file mode 100644
index 0000000..60d6adb
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ListPresetsHidden-stdout.txt
@@ -0,0 +1,6 @@
+^Not searching for unused variables given on the command line\.
+Available configure presets:
+
+ "zzzzzz" - Sleepy
+ "aaaaaaaa" - Screaming
+ "mmmmmm"$
diff --git a/Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset-result.txt b/Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset-stderr.txt b/Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset-stderr.txt
new file mode 100644
index 0000000..eea1b99
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: No such preset in [^
+]*/Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset: "ListPresetsNoSuchPreset"$
diff --git a/Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset-stdout.txt b/Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset-stdout.txt
new file mode 100644
index 0000000..60d6adb
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset-stdout.txt
@@ -0,0 +1,6 @@
+^Not searching for unused variables given on the command line\.
+Available configure presets:
+
+ "zzzzzz" - Sleepy
+ "aaaaaaaa" - Screaming
+ "mmmmmm"$
diff --git a/Tests/RunCMake/CMakePresets/ListPresetsWorkingDir-stdout.txt b/Tests/RunCMake/CMakePresets/ListPresetsWorkingDir-stdout.txt
new file mode 100644
index 0000000..60d6adb
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ListPresetsWorkingDir-stdout.txt
@@ -0,0 +1,6 @@
+^Not searching for unused variables given on the command line\.
+Available configure presets:
+
+ "zzzzzz" - Sleepy
+ "aaaaaaaa" - Screaming
+ "mmmmmm"$
diff --git a/Tests/RunCMake/CMakePresets/LowVersion-result.txt b/Tests/RunCMake/CMakePresets/LowVersion-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/LowVersion-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/LowVersion-stderr.txt b/Tests/RunCMake/CMakePresets/LowVersion-stderr.txt
new file mode 100644
index 0000000..92b3723
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/LowVersion-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/LowVersion: Unrecognized "version" field$
diff --git a/Tests/RunCMake/CMakePresets/LowVersion.json.in b/Tests/RunCMake/CMakePresets/LowVersion.json.in
new file mode 100644
index 0000000..e03afa9
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/LowVersion.json.in
@@ -0,0 +1,4 @@
+{
+ "version": 0,
+ "configurePresets": []
+}
diff --git a/Tests/RunCMake/CMakePresets/MinimumRequiredEmpty.cmake b/Tests/RunCMake/CMakePresets/MinimumRequiredEmpty.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/MinimumRequiredEmpty.cmake
diff --git a/Tests/RunCMake/CMakePresets/MinimumRequiredEmpty.json.in b/Tests/RunCMake/CMakePresets/MinimumRequiredEmpty.json.in
new file mode 100644
index 0000000..37740ef
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/MinimumRequiredEmpty.json.in
@@ -0,0 +1,11 @@
+{
+ "version": 1,
+ "cmakeMinimumRequired": {},
+ "configurePresets": [
+ {
+ "name": "MinimumRequiredEmpty",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/MinimumRequiredInvalid-result.txt b/Tests/RunCMake/CMakePresets/MinimumRequiredInvalid-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/MinimumRequiredInvalid-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/MinimumRequiredInvalid-stderr.txt b/Tests/RunCMake/CMakePresets/MinimumRequiredInvalid-stderr.txt
new file mode 100644
index 0000000..6548caf
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/MinimumRequiredInvalid-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/MinimumRequiredInvalid: Invalid "cmakeMinimumRequired" field$
diff --git a/Tests/RunCMake/CMakePresets/MinimumRequiredInvalid.json.in b/Tests/RunCMake/CMakePresets/MinimumRequiredInvalid.json.in
new file mode 100644
index 0000000..da79603
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/MinimumRequiredInvalid.json.in
@@ -0,0 +1,11 @@
+{
+ "version": 1,
+ "cmakeMinimumRequired": "3.18",
+ "configurePresets": [
+ {
+ "name": "MinimumRequiredInvalid",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/MinimumRequiredMajor-result.txt b/Tests/RunCMake/CMakePresets/MinimumRequiredMajor-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/MinimumRequiredMajor-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/MinimumRequiredMajor-stderr.txt b/Tests/RunCMake/CMakePresets/MinimumRequiredMajor-stderr.txt
new file mode 100644
index 0000000..6036fe3
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/MinimumRequiredMajor-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/MinimumRequiredMajor: "cmakeMinimumRequired" version too new$
diff --git a/Tests/RunCMake/CMakePresets/MinimumRequiredMajor.json.in b/Tests/RunCMake/CMakePresets/MinimumRequiredMajor.json.in
new file mode 100644
index 0000000..a17cdf6
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/MinimumRequiredMajor.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "cmakeMinimumRequired": {
+ "major": 1000
+ },
+ "configurePresets": [
+ {
+ "name": "MinimumRequiredMajor",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/MinimumRequiredMinor-result.txt b/Tests/RunCMake/CMakePresets/MinimumRequiredMinor-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/MinimumRequiredMinor-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/MinimumRequiredMinor-stderr.txt b/Tests/RunCMake/CMakePresets/MinimumRequiredMinor-stderr.txt
new file mode 100644
index 0000000..bdee4cd
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/MinimumRequiredMinor-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/MinimumRequiredMinor: "cmakeMinimumRequired" version too new$
diff --git a/Tests/RunCMake/CMakePresets/MinimumRequiredMinor.json.in b/Tests/RunCMake/CMakePresets/MinimumRequiredMinor.json.in
new file mode 100644
index 0000000..33a8816
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/MinimumRequiredMinor.json.in
@@ -0,0 +1,14 @@
+{
+ "version": 1,
+ "cmakeMinimumRequired": {
+ "major": @CMAKE_MAJOR_VERSION@,
+ "minor": 1000
+ },
+ "configurePresets": [
+ {
+ "name": "MinimumRequiredMinor",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/MinimumRequiredPatch-result.txt b/Tests/RunCMake/CMakePresets/MinimumRequiredPatch-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/MinimumRequiredPatch-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/MinimumRequiredPatch-stderr.txt b/Tests/RunCMake/CMakePresets/MinimumRequiredPatch-stderr.txt
new file mode 100644
index 0000000..b5d3a39
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/MinimumRequiredPatch-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/MinimumRequiredPatch: "cmakeMinimumRequired" version too new$
diff --git a/Tests/RunCMake/CMakePresets/MinimumRequiredPatch.json.in b/Tests/RunCMake/CMakePresets/MinimumRequiredPatch.json.in
new file mode 100644
index 0000000..4a53f8d
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/MinimumRequiredPatch.json.in
@@ -0,0 +1,15 @@
+{
+ "version": 1,
+ "cmakeMinimumRequired": {
+ "major": @CMAKE_MAJOR_VERSION@,
+ "minor": @CMAKE_MINOR_VERSION@,
+ "patch": 50000000
+ },
+ "configurePresets": [
+ {
+ "name": "MinimumRequiredPatch",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/NoCMakePresets-result.txt b/Tests/RunCMake/CMakePresets/NoCMakePresets-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoCMakePresets-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/NoCMakePresets-stderr.txt b/Tests/RunCMake/CMakePresets/NoCMakePresets-stderr.txt
new file mode 100644
index 0000000..c807ffc
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoCMakePresets-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/NoCMakePresets: File not found$
diff --git a/Tests/RunCMake/CMakePresets/NoDebug-stdout.txt b/Tests/RunCMake/CMakePresets/NoDebug-stdout.txt
new file mode 100644
index 0000000..c23ab89
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoDebug-stdout.txt
@@ -0,0 +1,2 @@
+-- Configuring done
+-- Generating done
diff --git a/Tests/RunCMake/CMakePresets/NoDebug.cmake b/Tests/RunCMake/CMakePresets/NoDebug.cmake
new file mode 100644
index 0000000..f2b3d4a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoDebug.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/DebugBase.cmake)
+if(EXISTS "${CMAKE_BINARY_DIR}/CMakeFiles/CMakeTmp/CMakeLists.txt")
+ message(SEND_ERROR "Not debugging try_compile() did not work")
+endif()
diff --git a/Tests/RunCMake/CMakePresets/NoPresetArgument-result.txt b/Tests/RunCMake/CMakePresets/NoPresetArgument-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresetArgument-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/NoPresetArgument-stderr.txt b/Tests/RunCMake/CMakePresets/NoPresetArgument-stderr.txt
new file mode 100644
index 0000000..a53682d
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresetArgument-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: No preset specified for --preset
+CMake Error: Run 'cmake --help' for all supported options.$
diff --git a/Tests/RunCMake/CMakePresets/NoPresetArgumentEq-result.txt b/Tests/RunCMake/CMakePresets/NoPresetArgumentEq-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresetArgumentEq-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/NoPresetArgumentEq-stderr.txt b/Tests/RunCMake/CMakePresets/NoPresetArgumentEq-stderr.txt
new file mode 100644
index 0000000..a53682d
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresetArgumentEq-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: No preset specified for --preset
+CMake Error: Run 'cmake --help' for all supported options.$
diff --git a/Tests/RunCMake/CMakePresets/NoPresetBinaryDir-result.txt b/Tests/RunCMake/CMakePresets/NoPresetBinaryDir-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresetBinaryDir-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/NoPresetBinaryDir-stderr.txt b/Tests/RunCMake/CMakePresets/NoPresetBinaryDir-stderr.txt
new file mode 100644
index 0000000..b525fc3
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresetBinaryDir-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/NoPresetBinaryDir: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/NoPresetBinaryDir.json.in b/Tests/RunCMake/CMakePresets/NoPresetBinaryDir.json.in
new file mode 100644
index 0000000..8989cfd
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresetBinaryDir.json.in
@@ -0,0 +1,9 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "NoPresetBinaryDir",
+ "generator": "@RunCMake_GENERATOR@"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/NoPresetGenerator-result.txt b/Tests/RunCMake/CMakePresets/NoPresetGenerator-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresetGenerator-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/NoPresetGenerator-stderr.txt b/Tests/RunCMake/CMakePresets/NoPresetGenerator-stderr.txt
new file mode 100644
index 0000000..6c0c9f7
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresetGenerator-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/NoPresetGenerator: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/NoPresetGenerator.json.in b/Tests/RunCMake/CMakePresets/NoPresetGenerator.json.in
new file mode 100644
index 0000000..74f83b7
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresetGenerator.json.in
@@ -0,0 +1,9 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "NoPresetGenerator",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/NoPresetName-result.txt b/Tests/RunCMake/CMakePresets/NoPresetName-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresetName-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/NoPresetName-stderr.txt b/Tests/RunCMake/CMakePresets/NoPresetName-stderr.txt
new file mode 100644
index 0000000..0ee338a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresetName-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/NoPresetName: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/NoPresetName.json.in b/Tests/RunCMake/CMakePresets/NoPresetName.json.in
new file mode 100644
index 0000000..373591d
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresetName.json.in
@@ -0,0 +1,9 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/NoPresets-result.txt b/Tests/RunCMake/CMakePresets/NoPresets-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresets-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/NoPresets-stderr.txt b/Tests/RunCMake/CMakePresets/NoPresets-stderr.txt
new file mode 100644
index 0000000..5ff3d33
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresets-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: No such preset in [^
+]*/Tests/RunCMake/CMakePresets/NoPresets: "NoPresets"$
diff --git a/Tests/RunCMake/CMakePresets/NoPresets-stdout.txt b/Tests/RunCMake/CMakePresets/NoPresets-stdout.txt
new file mode 100644
index 0000000..cb01a02
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresets-stdout.txt
@@ -0,0 +1 @@
+^Not searching for unused variables given on the command line\.$
diff --git a/Tests/RunCMake/CMakePresets/NoPresets.json.in b/Tests/RunCMake/CMakePresets/NoPresets.json.in
new file mode 100644
index 0000000..61a2092
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoPresets.json.in
@@ -0,0 +1,3 @@
+{
+ "version": 1
+}
diff --git a/Tests/RunCMake/CMakePresets/NoSuchMacro-result.txt b/Tests/RunCMake/CMakePresets/NoSuchMacro-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoSuchMacro-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/NoSuchMacro-stderr.txt b/Tests/RunCMake/CMakePresets/NoSuchMacro-stderr.txt
new file mode 100644
index 0000000..7dafe62
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoSuchMacro-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/NoSuchMacro: Invalid macro expansion$
diff --git a/Tests/RunCMake/CMakePresets/NoSuchMacro.json.in b/Tests/RunCMake/CMakePresets/NoSuchMacro.json.in
new file mode 100644
index 0000000..94d0b76
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoSuchMacro.json.in
@@ -0,0 +1,10 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "NoSuchMacro",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${noexist}"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/NoSuchPreset-result.txt b/Tests/RunCMake/CMakePresets/NoSuchPreset-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoSuchPreset-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/NoSuchPreset-stderr.txt b/Tests/RunCMake/CMakePresets/NoSuchPreset-stderr.txt
new file mode 100644
index 0000000..9a2d0d5
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoSuchPreset-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: No such preset in [^
+]*/Tests/RunCMake/CMakePresets/NoSuchPreset: "NoSuchPreset"$
diff --git a/Tests/RunCMake/CMakePresets/NoVariableValue-result.txt b/Tests/RunCMake/CMakePresets/NoVariableValue-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoVariableValue-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/NoVariableValue-stderr.txt b/Tests/RunCMake/CMakePresets/NoVariableValue-stderr.txt
new file mode 100644
index 0000000..cdab32f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoVariableValue-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/NoVariableValue: Invalid CMake variable definition$
diff --git a/Tests/RunCMake/CMakePresets/NoVariableValue.json.in b/Tests/RunCMake/CMakePresets/NoVariableValue.json.in
new file mode 100644
index 0000000..482700d
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoVariableValue.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "NoVariableValue",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "VAR": {}
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/NoVersion-result.txt b/Tests/RunCMake/CMakePresets/NoVersion-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoVersion-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/NoVersion-stderr.txt b/Tests/RunCMake/CMakePresets/NoVersion-stderr.txt
new file mode 100644
index 0000000..d4f07e4
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoVersion-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/NoVersion: No "version" field$
diff --git a/Tests/RunCMake/CMakePresets/NoVersion.json.in b/Tests/RunCMake/CMakePresets/NoVersion.json.in
new file mode 100644
index 0000000..3fe8332
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoVersion.json.in
@@ -0,0 +1,3 @@
+{
+ "configurePresets": []
+}
diff --git a/Tests/RunCMake/CMakePresets/NoWarningFlags-stderr.txt b/Tests/RunCMake/CMakePresets/NoWarningFlags-stderr.txt
new file mode 100644
index 0000000..a16d362
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoWarningFlags-stderr.txt
@@ -0,0 +1,23 @@
+^CMake Warning \(dev\) at [^
+]*/Tests/RunCMake/CMakePresets/WarningsBase\.cmake:[0-9]+ \(message\):
+ Dev warning
+Call Stack \(most recent call first\):
+ [^
+]*/Tests/RunCMake/CMakePresets/NoWarningFlags\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
+
+CMake Deprecation Warning at [^
+]*/Tests/RunCMake/CMakePresets/WarningsBase\.cmake:[0-9]+ \(message\):
+ Deprecation warning
+Call Stack \(most recent call first\):
+ [^
+]*/Tests/RunCMake/CMakePresets/NoWarningFlags\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Warning:
+ Manually-specified variables were not used by the project:
+
+ RunCMake_GENERATOR
+ UNUSED_VARIABLE$
diff --git a/Tests/RunCMake/CMakePresets/NoWarningFlags.cmake b/Tests/RunCMake/CMakePresets/NoWarningFlags.cmake
new file mode 100644
index 0000000..5de7687
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/NoWarningFlags.cmake
@@ -0,0 +1 @@
+include(${CMAKE_CURRENT_LIST_DIR}/WarningsBase.cmake)
diff --git a/Tests/RunCMake/CMakePresets/OptionalBinaryDirField.cmake b/Tests/RunCMake/CMakePresets/OptionalBinaryDirField.cmake
new file mode 100644
index 0000000..49e7a25
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/OptionalBinaryDirField.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_BINARY_DIR "" "${CMAKE_SOURCE_DIR}/build")
diff --git a/Tests/RunCMake/CMakePresets/OptionalBinaryDirField.json.in b/Tests/RunCMake/CMakePresets/OptionalBinaryDirField.json.in
new file mode 100644
index 0000000..ee17a22
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/OptionalBinaryDirField.json.in
@@ -0,0 +1,9 @@
+{
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "OptionalBinaryDirField",
+ "generator": "@RunCMake_GENERATOR@"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/OptionalGeneratorField.cmake b/Tests/RunCMake/CMakePresets/OptionalGeneratorField.cmake
new file mode 100644
index 0000000..4319e72
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/OptionalGeneratorField.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_GENERATOR "" "${RunCMake_GENERATOR}")
diff --git a/Tests/RunCMake/CMakePresets/OptionalGeneratorField.json.in b/Tests/RunCMake/CMakePresets/OptionalGeneratorField.json.in
new file mode 100644
index 0000000..920d056
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/OptionalGeneratorField.json.in
@@ -0,0 +1,9 @@
+{
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "OptionalGeneratorField",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/PresetNotObject-result.txt b/Tests/RunCMake/CMakePresets/PresetNotObject-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/PresetNotObject-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/PresetNotObject-stderr.txt b/Tests/RunCMake/CMakePresets/PresetNotObject-stderr.txt
new file mode 100644
index 0000000..6604a14
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/PresetNotObject-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/PresetNotObject: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/PresetNotObject.json.in b/Tests/RunCMake/CMakePresets/PresetNotObject.json.in
new file mode 100644
index 0000000..d5892fc
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/PresetNotObject.json.in
@@ -0,0 +1,6 @@
+{
+ "version": 1,
+ "configurePresets": [
+ []
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
new file mode 100644
index 0000000..bcbd177
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
@@ -0,0 +1,289 @@
+cmake_minimum_required(VERSION 3.19) # CMP0053
+
+include(RunCMake)
+
+# Fix Visual Studio generator name
+if(RunCMake_GENERATOR MATCHES "^(Visual Studio [0-9]+ [0-9]+) ")
+ set(RunCMake_GENERATOR "${CMAKE_MATCH_1}")
+endif()
+
+set(RunCMake-check-file check.cmake)
+
+include("${RunCMake_SOURCE_DIR}/validate_schema.cmake")
+
+function(run_cmake_presets name)
+ set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/${name}")
+ set(_source_arg "${RunCMake_TEST_SOURCE_DIR}")
+ if(CMakePresets_SOURCE_ARG)
+ set(_source_arg "${CMakePresets_SOURCE_ARG}")
+ endif()
+ file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}")
+ configure_file("${RunCMake_SOURCE_DIR}/CMakeLists.txt.in" "${RunCMake_TEST_SOURCE_DIR}/CMakeLists.txt" @ONLY)
+
+ if(NOT CMakePresets_FILE)
+ set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/${name}.json.in")
+ endif()
+ if(EXISTS "${CMakePresets_FILE}")
+ configure_file("${CMakePresets_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakePresets.json" @ONLY)
+ endif()
+
+ if(NOT CMakeUserPresets_FILE)
+ set(CMakeUserPresets_FILE "${RunCMake_SOURCE_DIR}/${name}User.json.in")
+ endif()
+ if(EXISTS "${CMakeUserPresets_FILE}")
+ configure_file("${CMakeUserPresets_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" @ONLY)
+ endif()
+
+ set(_s_arg -S)
+ if(CMakePresets_NO_S_ARG)
+ set(_s_arg)
+ endif()
+ set(_source_args ${_s_arg} ${_source_arg})
+ if(CMakePresets_NO_SOURCE_ARGS)
+ set(_source_args)
+ endif()
+ set(_unused_cli --no-warn-unused-cli)
+ if(CMakePresets_WARN_UNUSED_CLI)
+ set(_unused_cli)
+ endif()
+
+ set(RunCMake_TEST_COMMAND ${CMAKE_COMMAND}
+ ${_source_args}
+ -DRunCMake_TEST=${name}
+ -DRunCMake_GENERATOR=${RunCMake_GENERATOR}
+ -DCMAKE_MAKE_PROGRAM=${RunCMake_MAKE_PROGRAM}
+ ${_unused_cli}
+ --preset=${name}
+ ${ARGN}
+ )
+ run_cmake(${name})
+endfunction()
+
+# Test CMakePresets.json errors
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
+run_cmake_presets(NoCMakePresets)
+run_cmake_presets(Comment)
+run_cmake_presets(JSONParseError)
+run_cmake_presets(InvalidRoot)
+run_cmake_presets(NoVersion)
+run_cmake_presets(InvalidVersion)
+run_cmake_presets(LowVersion)
+run_cmake_presets(HighVersion)
+run_cmake_presets(InvalidVendor)
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+run_cmake_presets(NoPresets)
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
+run_cmake_presets(InvalidPresets)
+run_cmake_presets(PresetNotObject)
+run_cmake_presets(NoPresetName)
+run_cmake_presets(InvalidPresetName)
+run_cmake_presets(EmptyPresetName)
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+run_cmake_presets(NoPresetGenerator)
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
+run_cmake_presets(InvalidPresetGenerator)
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+run_cmake_presets(NoPresetBinaryDir)
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
+run_cmake_presets(InvalidPresetBinaryDir)
+run_cmake_presets(InvalidVariables)
+run_cmake_presets(VariableNotObject)
+run_cmake_presets(NoVariableValue)
+run_cmake_presets(InvalidVariableValue)
+run_cmake_presets(ExtraRootField)
+run_cmake_presets(ExtraPresetField)
+run_cmake_presets(ExtraVariableField)
+run_cmake_presets(FuturePresetInstallDirField)
+run_cmake_presets(InvalidPresetVendor)
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+run_cmake_presets(DuplicatePresets)
+run_cmake_presets(CyclicInheritance0)
+run_cmake_presets(CyclicInheritance1)
+run_cmake_presets(CyclicInheritance2)
+run_cmake_presets(InvalidInheritance)
+run_cmake_presets(ErrorNoWarningDev)
+run_cmake_presets(ErrorNoWarningDeprecated)
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
+run_cmake_presets(InvalidArchitectureStrategy)
+run_cmake_presets(UnknownArchitectureStrategy)
+run_cmake_presets(InvalidToolsetStrategy)
+run_cmake_presets(UnknownToolsetStrategy)
+run_cmake_presets(EmptyCacheKey)
+run_cmake_presets(EmptyEnvKey)
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+run_cmake_presets(UnclosedMacro)
+run_cmake_presets(NoSuchMacro)
+run_cmake_presets(EnvCycle)
+run_cmake_presets(EmptyEnv)
+run_cmake_presets(EmptyPenv)
+run_cmake_presets(InvalidRegex)
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
+run_cmake_presets(ConditionFuture)
+run_cmake_presets(SubConditionNull)
+
+# Test cmakeMinimumRequired field
+run_cmake_presets(MinimumRequiredInvalid)
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+run_cmake_presets(MinimumRequiredEmpty)
+run_cmake_presets(MinimumRequiredMajor)
+run_cmake_presets(MinimumRequiredMinor)
+run_cmake_presets(MinimumRequiredPatch)
+
+# Test properly working CMakePresets.json
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/CMakePresets.json.in")
+unset(ENV{TEST_ENV})
+unset(ENV{TEST_ENV_REF})
+unset(ENV{TEST_D_ENV_REF})
+set(ENV{TEST_ENV_OVERRIDE} "This environment variable will be overridden")
+set(ENV{TEST_PENV} "Process environment variable")
+set(ENV{TEST_ENV_REF_PENV} "suffix")
+run_cmake_presets(Good "-DTEST_OVERRIDE_1=Overridden value" "-DTEST_OVERRIDE_2:STRING=Overridden value" -C "${RunCMake_SOURCE_DIR}/CacheOverride.cmake" "-UTEST_UNDEF")
+unset(ENV{TEST_ENV_OVERRIDE})
+unset(ENV{TEST_PENV})
+unset(ENV{TEST_ENV_REF_PENV})
+run_cmake_presets(GoodNoArgs)
+file(REMOVE_RECURSE ${RunCMake_BINARY_DIR}/GoodBinaryUp-build)
+run_cmake_presets(GoodBinaryUp)
+set(CMakePresets_SOURCE_ARG "../GoodBinaryRelative")
+run_cmake_presets(GoodBinaryRelative)
+unset(CMakePresets_SOURCE_ARG)
+run_cmake_presets(GoodSpaces "--preset" "Good Spaces")
+run_cmake_presets(GoodSpacesEq "--preset=Good Spaces")
+if(WIN32)
+ run_cmake_presets(GoodWindowsBackslash)
+endif()
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/GoodBOM.json.in")
+run_cmake_presets(GoodBOM)
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/CMakePresets.json.in")
+file(REMOVE_RECURSE ${RunCMake_BINARY_DIR}/GoodBinaryCmdLine-build)
+run_cmake_presets(GoodBinaryCmdLine -B ${RunCMake_BINARY_DIR}/GoodBinaryCmdLine-build)
+run_cmake_presets(GoodGeneratorCmdLine -G ${RunCMake_GENERATOR})
+run_cmake_presets(InvalidGeneratorCmdLine -G "Invalid Generator")
+set(CMakePresets_NO_S_ARG TRUE)
+run_cmake_presets(GoodNoS)
+set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/GoodNoSCachePrep-build")
+run_cmake_presets(GoodNoSCachePrep)
+set(CMakePresets_SOURCE_ARG ".")
+set(RunCMake_TEST_NO_CLEAN 1)
+run_cmake_presets(GoodNoSCache)
+unset(RunCMake_TEST_NO_CLEAN)
+unset(CMakePresets_SOURCE_ARG)
+unset(RunCMake_TEST_BINARY_DIR)
+unset(CMakePresets_NO_S_ARG)
+set(CMakePresets_NO_SOURCE_ARGS 1)
+set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/GoodNoSourceArg")
+set(RunCMake_TEST_NO_CLEAN 1)
+run_cmake_presets(GoodNoSourceArg)
+unset(RunCMake_TEST_NO_CLEAN)
+unset(RunCMake_TEST_BINARY_DIR)
+unset(CMakePresets_NO_SOURCE_ARGS)
+run_cmake_presets(GoodInheritanceParent)
+run_cmake_presets(GoodInheritanceChild)
+run_cmake_presets(GoodInheritanceOverride)
+run_cmake_presets(GoodInheritanceMulti)
+run_cmake_presets(GoodInheritanceMultiSecond)
+run_cmake_presets(GoodInheritanceMacro)
+
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/GoodInstall.json.in")
+run_cmake_presets(GoodInstallDefault)
+run_cmake_presets(GoodInstallInherit)
+run_cmake_presets(GoodInstallOverride)
+run_cmake_presets(GoodInstallCommandLine "--install-prefix=${RunCMake_SOURCE_DIR}/path/passed/on/command_line")
+
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/CMakePresets.json.in")
+# Test bad preset arguments
+run_cmake_presets(VendorMacro)
+run_cmake_presets(InvalidGenerator)
+
+# Test Visual Studio-specific stuff
+if(RunCMake_GENERATOR MATCHES "^Visual Studio ")
+ run_cmake_presets(VisualStudioGeneratorArch)
+ run_cmake_presets(VisualStudioWin32)
+ run_cmake_presets(VisualStudioWin64)
+ run_cmake_presets(VisualStudioWin32Override -A x64)
+ if(NOT RunCMake_GENERATOR STREQUAL "Visual Studio 9 2008")
+ run_cmake_presets(VisualStudioToolset)
+ run_cmake_presets(VisualStudioToolsetOverride -T "Test Toolset")
+ run_cmake_presets(VisualStudioInheritanceParent)
+ run_cmake_presets(VisualStudioInheritanceChild)
+ run_cmake_presets(VisualStudioInheritanceOverride)
+ run_cmake_presets(VisualStudioInheritanceMulti)
+ run_cmake_presets(VisualStudioInheritanceMultiSecond)
+ endif()
+else()
+ run_cmake_presets(ArchToolsetStrategyNone)
+ run_cmake_presets(ArchToolsetStrategyDefault)
+ run_cmake_presets(ArchToolsetStrategyIgnore)
+endif()
+
+# Test bad command line arguments
+run_cmake_presets(NoSuchPreset)
+run_cmake_presets(NoPresetArgument --preset)
+run_cmake_presets(NoPresetArgumentEq --preset= -DA=B)
+run_cmake_presets(UseHiddenPreset)
+
+# Test CMakeUserPresets.json
+unset(CMakePresets_FILE)
+run_cmake_presets(GoodUserOnly)
+run_cmake_presets(GoodUserFromMain)
+run_cmake_presets(GoodUserFromUser)
+
+# Test CMakeUserPresets.json errors
+run_cmake_presets(UserDuplicateInUser)
+run_cmake_presets(UserDuplicateCross)
+run_cmake_presets(UserInheritance)
+
+# Test listing presets
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/ListPresets.json.in")
+run_cmake_presets(ListPresets --list-presets)
+
+set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/ListPresetsWorkingDir")
+set(RunCMake_TEST_NO_CLEAN 1)
+set(CMakePresets_NO_SOURCE_ARGS 1)
+run_cmake_presets(ListPresetsWorkingDir --list-presets)
+unset(CMakePresets_NO_SOURCE_ARGS)
+unset(RunCMake_TEST_NO_CLEAN)
+unset(RunCMake_TEST_BINARY_DIR)
+
+run_cmake_presets(ListPresetsNoSuchPreset)
+run_cmake_presets(ListPresetsHidden)
+
+# Test warning and error flags
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/Warnings.json.in")
+set(CMakePresets_WARN_UNUSED_CLI 1)
+run_cmake_presets(NoWarningFlags)
+run_cmake_presets(WarningFlags)
+run_cmake_presets(DisableWarningFlags)
+run_cmake_presets(ErrorDev)
+run_cmake_presets(ErrorDeprecated)
+unset(CMakePresets_WARN_UNUSED_CLI)
+
+# Test debug
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/Debug.json.in")
+run_cmake_presets(NoDebug)
+run_cmake_presets(Debug)
+
+# Test ${hostSystemName} macro
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/HostSystemName.json.in")
+run_cmake_presets(HostSystemName)
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/HostSystemNameFuture.json.in")
+run_cmake_presets(HostSystemNameFuture)
+
+# Test conditions
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/Conditions.json.in")
+run_cmake_presets(ListConditions --list-presets)
+run_cmake_presets(SimpleTrue)
+run_cmake_presets(SimpleFalse)
+unset(CMakePresets_FILE)
+
+# Test optional generator and buildDir fields
+run_cmake_presets(OptionalBinaryDirField -B "${RunCMake_BINARY_DIR}/OptionalBinaryDirField/build")
+run_cmake_presets(OptionalGeneratorField -G "${RunCMake_GENERATOR}")
+
+# Test the example from the documentation
+file(READ "${RunCMake_SOURCE_DIR}/../../../Help/manual/presets/example.json" _example)
+string(REPLACE "\"generator\": \"Ninja\"" "\"generator\": \"@RunCMake_GENERATOR@\"" _example "${_example}")
+file(WRITE "${RunCMake_BINARY_DIR}/example.json.in" "${_example}")
+set(CMakePresets_FILE "${RunCMake_BINARY_DIR}/example.json.in")
+run_cmake_presets(DocumentationExample --preset=default)
diff --git a/Tests/RunCMake/CMakePresets/SimpleFalse-result.txt b/Tests/RunCMake/CMakePresets/SimpleFalse-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/SimpleFalse-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/SimpleFalse-stderr.txt b/Tests/RunCMake/CMakePresets/SimpleFalse-stderr.txt
new file mode 100644
index 0000000..6a9a7de
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/SimpleFalse-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: Could not use disabled preset "SimpleFalse"$
diff --git a/Tests/RunCMake/CMakePresets/SimpleTrue.cmake b/Tests/RunCMake/CMakePresets/SimpleTrue.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/SimpleTrue.cmake
diff --git a/Tests/RunCMake/CMakePresets/SubConditionNull-result.txt b/Tests/RunCMake/CMakePresets/SubConditionNull-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/SubConditionNull-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/SubConditionNull-stderr.txt b/Tests/RunCMake/CMakePresets/SubConditionNull-stderr.txt
new file mode 100644
index 0000000..42b74d6
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/SubConditionNull-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/SubConditionNull: Invalid preset condition$
diff --git a/Tests/RunCMake/CMakePresets/SubConditionNull.json.in b/Tests/RunCMake/CMakePresets/SubConditionNull.json.in
new file mode 100644
index 0000000..eed3da6
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/SubConditionNull.json.in
@@ -0,0 +1,14 @@
+{
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "SubConditionNull",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "condition": {
+ "type": "not",
+ "condition": null
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/TestVariable.cmake b/Tests/RunCMake/CMakePresets/TestVariable.cmake
new file mode 100644
index 0000000..934af52
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/TestVariable.cmake
@@ -0,0 +1,25 @@
+function(test_variable name expected_type expected_value)
+ if(NOT DEFINED "${name}")
+ message(SEND_ERROR "${name} is not defined")
+ elseif(NOT "${${name}}" STREQUAL expected_value)
+ message(SEND_ERROR "Expected value of ${name}: \"${expected_value}\"\nActual value: \"${${name}}\"")
+ endif()
+ if(expected_type)
+ if(NOT DEFINED "CACHE{${name}}")
+ message(SEND_ERROR "Cache entry ${name} does not exist")
+ else()
+ get_property(type CACHE ${name} PROPERTY TYPE)
+ if(NOT type STREQUAL expected_type)
+ message(SEND_ERROR "Expected type of ${name}: \"${expected_type}\"\nActual type: \"${type}\"")
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function(test_environment_variable name expected_value)
+ if(NOT DEFINED "ENV{${name}}")
+ message(SEND_ERROR "Environment variable ${name} is not defined")
+ elseif(NOT "$ENV{${name}}" STREQUAL expected_value)
+ message(SEND_ERROR "Expected value of environment variable ${name}: \"${expected_value}\"\nActual value: \"$ENV{${name}}\"")
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/CMakePresets/UnclosedMacro-result.txt b/Tests/RunCMake/CMakePresets/UnclosedMacro-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UnclosedMacro-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/UnclosedMacro-stderr.txt b/Tests/RunCMake/CMakePresets/UnclosedMacro-stderr.txt
new file mode 100644
index 0000000..f9481f0
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UnclosedMacro-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/UnclosedMacro: Invalid macro expansion$
diff --git a/Tests/RunCMake/CMakePresets/UnclosedMacro.json.in b/Tests/RunCMake/CMakePresets/UnclosedMacro.json.in
new file mode 100644
index 0000000..ad6cf7d
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UnclosedMacro.json.in
@@ -0,0 +1,10 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "UnclosedMacro",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy-result.txt b/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy-stderr.txt b/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy-stderr.txt
new file mode 100644
index 0000000..cf17881
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy.json.in b/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy.json.in
new file mode 100644
index 0000000..a3bf7c8
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UnknownArchitectureStrategy.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "UnknownArchitectureStrategy",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "architecture": {
+ "strategy": "unknown"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy-result.txt b/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy-stderr.txt b/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy-stderr.txt
new file mode 100644
index 0000000..8f9be29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy: Invalid preset$
diff --git a/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy.json.in b/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy.json.in
new file mode 100644
index 0000000..1668700
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UnknownToolsetStrategy.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "UnknownToolsetStrategy",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "toolset": {
+ "strategy": "unknown"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/UseHiddenPreset-result.txt b/Tests/RunCMake/CMakePresets/UseHiddenPreset-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UseHiddenPreset-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/UseHiddenPreset-stderr.txt b/Tests/RunCMake/CMakePresets/UseHiddenPreset-stderr.txt
new file mode 100644
index 0000000..45b4cd4
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UseHiddenPreset-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Cannot use hidden preset in [^
+]*/Tests/RunCMake/CMakePresets/UseHiddenPreset: "UseHiddenPreset"$
diff --git a/Tests/RunCMake/CMakePresets/UserDuplicateCross-result.txt b/Tests/RunCMake/CMakePresets/UserDuplicateCross-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UserDuplicateCross-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/UserDuplicateCross-stderr.txt b/Tests/RunCMake/CMakePresets/UserDuplicateCross-stderr.txt
new file mode 100644
index 0000000..125265f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UserDuplicateCross-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/UserDuplicateCross: Duplicate presets$
diff --git a/Tests/RunCMake/CMakePresets/UserDuplicateCross.json.in b/Tests/RunCMake/CMakePresets/UserDuplicateCross.json.in
new file mode 100644
index 0000000..172cfba
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UserDuplicateCross.json.in
@@ -0,0 +1,10 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "UserDuplicateCross",
+ "generator": "@RunCMake_GENERATOR",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/UserDuplicateCrossUser.json.in b/Tests/RunCMake/CMakePresets/UserDuplicateCrossUser.json.in
new file mode 100644
index 0000000..172cfba
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UserDuplicateCrossUser.json.in
@@ -0,0 +1,10 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "UserDuplicateCross",
+ "generator": "@RunCMake_GENERATOR",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/UserDuplicateInUser-result.txt b/Tests/RunCMake/CMakePresets/UserDuplicateInUser-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UserDuplicateInUser-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/UserDuplicateInUser-stderr.txt b/Tests/RunCMake/CMakePresets/UserDuplicateInUser-stderr.txt
new file mode 100644
index 0000000..1071b17
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UserDuplicateInUser-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/UserDuplicateInUser: Duplicate presets$
diff --git a/Tests/RunCMake/CMakePresets/UserDuplicateInUserUser.json.in b/Tests/RunCMake/CMakePresets/UserDuplicateInUserUser.json.in
new file mode 100644
index 0000000..365fafe
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UserDuplicateInUserUser.json.in
@@ -0,0 +1,15 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "UserDuplicateInUser",
+ "generator": "@RunCMake_GENERATOR",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "UserDuplicateInUser",
+ "generator": "@RunCMake_GENERATOR",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/UserInheritance-result.txt b/Tests/RunCMake/CMakePresets/UserInheritance-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UserInheritance-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/UserInheritance-stderr.txt b/Tests/RunCMake/CMakePresets/UserInheritance-stderr.txt
new file mode 100644
index 0000000..213215a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UserInheritance-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/UserInheritance: Project preset inherits from user preset$
diff --git a/Tests/RunCMake/CMakePresets/UserInheritance.json.in b/Tests/RunCMake/CMakePresets/UserInheritance.json.in
new file mode 100644
index 0000000..d9973d7
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UserInheritance.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "UserInheritance",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "inherits": [
+ "UserInheritanceUser"
+ ]
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/UserInheritanceUser.json.in b/Tests/RunCMake/CMakePresets/UserInheritanceUser.json.in
new file mode 100644
index 0000000..1321a73
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/UserInheritanceUser.json.in
@@ -0,0 +1,10 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "UserInheritanceUser",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/VariableNotObject-result.txt b/Tests/RunCMake/CMakePresets/VariableNotObject-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VariableNotObject-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/VariableNotObject-stderr.txt b/Tests/RunCMake/CMakePresets/VariableNotObject-stderr.txt
new file mode 100644
index 0000000..8cacb0a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VariableNotObject-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/VariableNotObject: Invalid CMake variable definition$
diff --git a/Tests/RunCMake/CMakePresets/VariableNotObject.json.in b/Tests/RunCMake/CMakePresets/VariableNotObject.json.in
new file mode 100644
index 0000000..51298f5
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VariableNotObject.json.in
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "VariableNotObject",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "VAR": []
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/VendorMacro-result.txt b/Tests/RunCMake/CMakePresets/VendorMacro-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VendorMacro-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/VendorMacro-stderr.txt b/Tests/RunCMake/CMakePresets/VendorMacro-stderr.txt
new file mode 100644
index 0000000..2e98019
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VendorMacro-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: Could not evaluate preset "VendorMacro": Invalid macro expansion$
diff --git a/Tests/RunCMake/CMakePresets/VisualStudioGeneratorArch-result.txt b/Tests/RunCMake/CMakePresets/VisualStudioGeneratorArch-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VisualStudioGeneratorArch-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/VisualStudioGeneratorArch-stderr.txt b/Tests/RunCMake/CMakePresets/VisualStudioGeneratorArch-stderr.txt
new file mode 100644
index 0000000..a311321
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VisualStudioGeneratorArch-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error: Could not create named generator Visual Studio [^
+]* Win64
+Using platforms in Visual Studio generator names is not supported in CMakePresets\.json\.
+
+Generators
diff --git a/Tests/RunCMake/CMakePresets/VisualStudioInheritanceChild.cmake b/Tests/RunCMake/CMakePresets/VisualStudioInheritanceChild.cmake
new file mode 100644
index 0000000..d485ab3
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VisualStudioInheritanceChild.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_VS_PLATFORM_NAME "" "Test Platform")
+test_variable(CMAKE_VS_PLATFORM_TOOLSET "" "Test Toolset")
diff --git a/Tests/RunCMake/CMakePresets/VisualStudioInheritanceMulti.cmake b/Tests/RunCMake/CMakePresets/VisualStudioInheritanceMulti.cmake
new file mode 100644
index 0000000..d485ab3
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VisualStudioInheritanceMulti.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_VS_PLATFORM_NAME "" "Test Platform")
+test_variable(CMAKE_VS_PLATFORM_TOOLSET "" "Test Toolset")
diff --git a/Tests/RunCMake/CMakePresets/VisualStudioInheritanceMultiSecond.cmake b/Tests/RunCMake/CMakePresets/VisualStudioInheritanceMultiSecond.cmake
new file mode 100644
index 0000000..d485ab3
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VisualStudioInheritanceMultiSecond.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_VS_PLATFORM_NAME "" "Test Platform")
+test_variable(CMAKE_VS_PLATFORM_TOOLSET "" "Test Toolset")
diff --git a/Tests/RunCMake/CMakePresets/VisualStudioInheritanceOverride.cmake b/Tests/RunCMake/CMakePresets/VisualStudioInheritanceOverride.cmake
new file mode 100644
index 0000000..d485ab3
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VisualStudioInheritanceOverride.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_VS_PLATFORM_NAME "" "Test Platform")
+test_variable(CMAKE_VS_PLATFORM_TOOLSET "" "Test Toolset")
diff --git a/Tests/RunCMake/CMakePresets/VisualStudioInheritanceParent.cmake b/Tests/RunCMake/CMakePresets/VisualStudioInheritanceParent.cmake
new file mode 100644
index 0000000..d485ab3
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VisualStudioInheritanceParent.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_VS_PLATFORM_NAME "" "Test Platform")
+test_variable(CMAKE_VS_PLATFORM_TOOLSET "" "Test Toolset")
diff --git a/Tests/RunCMake/CMakePresets/VisualStudioToolset.cmake b/Tests/RunCMake/CMakePresets/VisualStudioToolset.cmake
new file mode 100644
index 0000000..722e976
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VisualStudioToolset.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_VS_PLATFORM_TOOLSET "" "Test Toolset")
diff --git a/Tests/RunCMake/CMakePresets/VisualStudioToolsetOverride.cmake b/Tests/RunCMake/CMakePresets/VisualStudioToolsetOverride.cmake
new file mode 100644
index 0000000..722e976
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VisualStudioToolsetOverride.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_VS_PLATFORM_TOOLSET "" "Test Toolset")
diff --git a/Tests/RunCMake/CMakePresets/VisualStudioWin32.cmake b/Tests/RunCMake/CMakePresets/VisualStudioWin32.cmake
new file mode 100644
index 0000000..a1c61b4
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VisualStudioWin32.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_VS_PLATFORM_NAME "" "Win32")
diff --git a/Tests/RunCMake/CMakePresets/VisualStudioWin32Override.cmake b/Tests/RunCMake/CMakePresets/VisualStudioWin32Override.cmake
new file mode 100644
index 0000000..b3464d6
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VisualStudioWin32Override.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_VS_PLATFORM_NAME "" "x64")
diff --git a/Tests/RunCMake/CMakePresets/VisualStudioWin64.cmake b/Tests/RunCMake/CMakePresets/VisualStudioWin64.cmake
new file mode 100644
index 0000000..b3464d6
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/VisualStudioWin64.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_VS_PLATFORM_NAME "" "x64")
diff --git a/Tests/RunCMake/CMakePresets/WarningFlags-stderr.txt b/Tests/RunCMake/CMakePresets/WarningFlags-stderr.txt
new file mode 100644
index 0000000..6e488a9
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/WarningFlags-stderr.txt
@@ -0,0 +1,34 @@
+^CMake Warning \(dev\) at [^
+]*/Modules/[^/
+]*:[0-9]+ \([a-zA-Z_][a-zA-Z0-9_]*\):
+ uninitialized variable '[^
+]*'
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(project\)
+This warning is for project developers\. Use -Wno-dev to suppress it\..*
+CMake Warning \(dev\) at [^
+]*/Tests/RunCMake/CMakePresets/WarningsBase\.cmake:[0-9]+ \(message\):
+ Dev warning
+Call Stack \(most recent call first\):
+ [^
+]*/Tests/RunCMake/CMakePresets/WarningFlags\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
+
+CMake Deprecation Warning at [^
+]*/Tests/RunCMake/CMakePresets/WarningsBase\.cmake:[0-9]+ \(message\):
+ Deprecation warning
+Call Stack \(most recent call first\):
+ [^
+]*/Tests/RunCMake/CMakePresets/WarningFlags\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Warning \(dev\) at [^
+]*/Tests/RunCMake/CMakePresets/WarningsBase\.cmake:[0-9]+ \(set\):
+ uninitialized variable 'UNINITIALIZED_VARIABLE'
+Call Stack \(most recent call first\):
+ [^
+]*/Tests/RunCMake/CMakePresets/WarningFlags\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.$
diff --git a/Tests/RunCMake/CMakePresets/WarningFlags.cmake b/Tests/RunCMake/CMakePresets/WarningFlags.cmake
new file mode 100644
index 0000000..5de7687
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/WarningFlags.cmake
@@ -0,0 +1 @@
+include(${CMAKE_CURRENT_LIST_DIR}/WarningsBase.cmake)
diff --git a/Tests/RunCMake/CMakePresets/Warnings.json.in b/Tests/RunCMake/CMakePresets/Warnings.json.in
new file mode 100644
index 0000000..40ec6ce
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/Warnings.json.in
@@ -0,0 +1,50 @@
+{
+ "version": 1,
+ "configurePresets": [
+ {
+ "name": "NoWarningFlags",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "UNUSED_VARIABLE": "Unused"
+ }
+ },
+ {
+ "name": "WarningFlags",
+ "inherits": "NoWarningFlags",
+ "warnings": {
+ "dev": true,
+ "deprecated": true,
+ "uninitialized": true,
+ "unusedCli": false,
+ "systemVars": true
+ }
+ },
+ {
+ "name": "DisableWarningFlags",
+ "inherits": "NoWarningFlags",
+ "warnings": {
+ "dev": false,
+ "deprecated": false,
+ "unusedCli": false
+ }
+ },
+ {
+ "name": "ErrorDev",
+ "inherits": "NoWarningFlags",
+ "errors": {
+ "dev": true
+ }
+ },
+ {
+ "name": "ErrorDeprecated",
+ "inherits": "NoWarningFlags",
+ "warnings": {
+ "dev": false
+ },
+ "errors": {
+ "deprecated": true
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresets/WarningsBase.cmake b/Tests/RunCMake/CMakePresets/WarningsBase.cmake
new file mode 100644
index 0000000..1a434dc
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/WarningsBase.cmake
@@ -0,0 +1,3 @@
+message(AUTHOR_WARNING "Dev warning")
+message(DEPRECATION "Deprecation warning")
+set(_uninitialized "${UNINITIALIZED_VARIABLE}")
diff --git a/Tests/RunCMake/CMakePresets/check.cmake b/Tests/RunCMake/CMakePresets/check.cmake
new file mode 100644
index 0000000..bf43c7e
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/check.cmake
@@ -0,0 +1,15 @@
+if(PYTHON_EXECUTABLE AND CMake_TEST_JSON_SCHEMA)
+ if(NOT CMakePresets_SCHEMA_EXPECTED_RESULT)
+ set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+ endif()
+ if(EXISTS "${RunCMake_TEST_SOURCE_DIR}/CMakePresets.json")
+ validate_schema("${RunCMake_TEST_SOURCE_DIR}/CMakePresets.json" "${CMakePresets_SCHEMA_EXPECTED_RESULT}")
+ endif()
+
+ if(NOT CMakeUserPresets_SCHEMA_EXPECTED_RESULT)
+ set(CMakeUserPresets_SCHEMA_EXPECTED_RESULT 0)
+ endif()
+ if(EXISTS "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json")
+ validate_schema("${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" "${CMakeUserPresets_SCHEMA_EXPECTED_RESULT}")
+ endif()
+endif()
diff --git a/Tests/RunCMake/CMakePresets/main.c b/Tests/RunCMake/CMakePresets/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMakePresets/validate_schema.cmake b/Tests/RunCMake/CMakePresets/validate_schema.cmake
new file mode 100644
index 0000000..68b638f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/validate_schema.cmake
@@ -0,0 +1,19 @@
+function(validate_schema file expected_result)
+ if (NOT CMakePresets_VALIDATE_SCRIPT_PATH)
+ set(CMakePresets_VALIDATE_SCRIPT_PATH "${RunCMake_SOURCE_DIR}/validate_schema.py")
+ endif()
+
+ execute_process(
+ COMMAND "${PYTHON_EXECUTABLE}" "${CMakePresets_VALIDATE_SCRIPT_PATH}" "${file}"
+ RESULT_VARIABLE _result
+ OUTPUT_VARIABLE _output
+ ERROR_VARIABLE _error
+ )
+ if(NOT _result STREQUAL expected_result)
+ string(REPLACE "\n" "\n " _output_p "${_output}")
+ string(REPLACE "\n" "\n " _error_p "${_error}")
+ string(APPEND RunCMake_TEST_FAILED "Expected result of validating ${file}: ${expected_result}\nActual result: ${_result}\nOutput:\n ${_output_p}\nError:\n ${_error_p}\n")
+ endif()
+
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CMakePresets/validate_schema.py b/Tests/RunCMake/CMakePresets/validate_schema.py
new file mode 100644
index 0000000..b2a67fc
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/validate_schema.py
@@ -0,0 +1,16 @@
+import json
+import jsonschema
+import os.path
+import sys
+
+
+with open(sys.argv[1], "rb") as f:
+ contents = json.loads(f.read().decode("utf-8-sig"))
+
+schema_file = os.path.join(
+ os.path.dirname(__file__),
+ "..", "..", "..", "Help", "manual", "presets", "schema.json")
+with open(schema_file) as f:
+ schema = json.load(f)
+
+jsonschema.validate(contents, schema)
diff --git a/Tests/RunCMake/CMakePresetsBuild/CMakeLists.txt.in b/Tests/RunCMake/CMakePresetsBuild/CMakeLists.txt.in
new file mode 100644
index 0000000..129184a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/CMakeLists.txt.in
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project("@CASE_NAME@" NONE)
+include("@CASE_SOURCE_DIR@/@CASE_NAME@.cmake")
diff --git a/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-result.txt b/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-stderr.txt
new file mode 100644
index 0000000..c35f5d7
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Cannot use disabled build preset in [^
+]*/Tests/RunCMake/CMakePresetsBuild/Condition: "disabled"$
diff --git a/Tests/RunCMake/CMakePresetsBuild/Condition.cmake b/Tests/RunCMake/CMakePresetsBuild/Condition.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Condition.cmake
diff --git a/Tests/RunCMake/CMakePresetsBuild/Condition.json.in b/Tests/RunCMake/CMakePresetsBuild/Condition.json.in
new file mode 100644
index 0000000..aaee96a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Condition.json.in
@@ -0,0 +1,22 @@
+{
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "default",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ],
+ "buildPresets": [
+ {
+ "name": "enabled",
+ "configurePreset": "default",
+ "condition": true
+ },
+ {
+ "name": "disabled",
+ "configurePreset": "default",
+ "condition": false
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-result.txt b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-stderr.txt
new file mode 100644
index 0000000..f08f4c1
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsBuild/ConditionFuture: File version must be 3 or higher for condition support$
diff --git a/Tests/RunCMake/CMakePresetsBuild/ConditionFuture.json.in b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture.json.in
new file mode 100644
index 0000000..2f3f7d8
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture.json.in
@@ -0,0 +1,17 @@
+{
+ "version": 2,
+ "configurePresets": [
+ {
+ "name": "default",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ],
+ "buildPresets": [
+ {
+ "name": "conditionFuture",
+ "configurePreset": "default",
+ "condition": true
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/Good-build-build-other-check.cmake b/Tests/RunCMake/CMakePresetsBuild/Good-build-build-other-check.cmake
new file mode 100644
index 0000000..b2699db
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Good-build-build-other-check.cmake
@@ -0,0 +1,5 @@
+include("${RunCMake_SOURCE_DIR}/TestVariable.cmake")
+
+test_environment_variable("TEST_ENV_" "other")
+
+include("${RunCMake_SOURCE_DIR}/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsBuild/Good-build-macros-check.cmake b/Tests/RunCMake/CMakePresetsBuild/Good-build-macros-check.cmake
new file mode 100644
index 0000000..7801c3d
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Good-build-macros-check.cmake
@@ -0,0 +1,14 @@
+include("${RunCMake_SOURCE_DIR}/TestVariable.cmake")
+
+if(RunCMake_GENERATOR STREQUAL "NMake Makefiles JOM")
+ # JOM removes the '$' and content following it.
+else()
+ test_environment_variable("TEST_DOLLAR" "x\\$x")
+endif()
+test_environment_variable("TEST_GENERATOR" "${RunCMake_GENERATOR}")
+test_environment_variable("TEST_PRESET_NAME" "xmacrosx")
+test_environment_variable("TEST_SOURCE_DIR_" "x[^\n]*[/\\\\]Tests[/\\\\]RunCMake[/\\\\]CMakePresetsBuild[/\\\\]Goodx")
+test_environment_variable("TEST_SOURCE_DIR_NAME" "xGoodx")
+test_environment_variable("TEST_SOURCE_PARENT_DIR" "x[^\n]*[/\\\\]Tests[/\\\\]RunCMake[/\\\\]CMakePresetsBuildx")
+
+include("${RunCMake_SOURCE_DIR}/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsBuild/Good-build-noEnvironment-check.cmake b/Tests/RunCMake/CMakePresetsBuild/Good-build-noEnvironment-check.cmake
new file mode 100644
index 0000000..94a54ca
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Good-build-noEnvironment-check.cmake
@@ -0,0 +1,6 @@
+string(FIND "${actual_stdout}" "TEST_ENV_" TEST_ENV_POS)
+if (NOT TEST_ENV_POS EQUAL -1)
+ message(FATAL_ERROR "Found TEST_ENV_ in environment")
+endif()
+
+include("${RunCMake_SOURCE_DIR}/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsBuild/Good-build-withEnvironment-check.cmake b/Tests/RunCMake/CMakePresetsBuild/Good-build-withEnvironment-check.cmake
new file mode 100644
index 0000000..9c6b5c2
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Good-build-withEnvironment-check.cmake
@@ -0,0 +1,8 @@
+include("${RunCMake_SOURCE_DIR}/TestVariable.cmake")
+
+test_environment_variable("TEST_ENV_" "Environment variable")
+test_environment_variable("TEST_ENV_OVERRIDE_" "Overridden")
+test_environment_variable("TEST_ENV_OVERRIDE_REF" "xOverriddenx")
+test_environment_variable("TEST_ENV_REF" "xEnvironment variablex")
+
+include("${RunCMake_SOURCE_DIR}/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsBuild/Good.cmake b/Tests/RunCMake/CMakePresetsBuild/Good.cmake
new file mode 100644
index 0000000..491d367
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Good.cmake
@@ -0,0 +1,3 @@
+add_custom_target(good ALL)
+add_custom_command(TARGET good PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E environment)
diff --git a/Tests/RunCMake/CMakePresetsBuild/Good.json.in b/Tests/RunCMake/CMakePresetsBuild/Good.json.in
new file mode 100644
index 0000000..fd43c4e
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Good.json.in
@@ -0,0 +1,78 @@
+{
+ "version": 2,
+ "configurePresets": [
+ {
+ "name": "default",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build/${presetName}",
+ "environment": {
+ "TEST_ENV_": "Environment variable",
+ "TEST_ENV_OVERRIDE_": "Environment variable",
+ "TEST_ENV_OVERRIDE_REF": "x$env{TEST_ENV_OVERRIDE_}x"
+ }
+ },
+ {
+ "name": "other",
+ "inherits": "default",
+ "environment": {
+ "TEST_ENV_": "other"
+ }
+ }
+ ],
+ "buildPresets": [
+ {
+ "name": "build-default",
+ "hidden": true,
+ "inherits": [],
+ "configurePreset": "default",
+ "vendor": {},
+ "displayName": "",
+ "description": "",
+ "inheritConfigureEnvironment": true,
+ "environment": {},
+ "jobs": 0,
+ "targets": [],
+ "configuration": "",
+ "verbose": true,
+ "nativeToolOptions": []
+ },
+ {
+ "name": "build-other",
+ "configurePreset": "other"
+ },
+ {
+ "name": "withEnvironment",
+ "inherits": "build-default",
+ "environment": {
+ "TEST_ENV_OVERRIDE_": "Overridden",
+ "TEST_ENV_REF": "x$env{TEST_ENV_}x",
+ "TEST_ENV_OVERRIDE_REF": "x$env{TEST_ENV_OVERRIDE_}x"
+ }
+ },
+ {
+ "name": "noEnvironment",
+ "inherits": "build-default",
+ "inheritConfigureEnvironment": false
+ },
+ {
+ "name": "macros",
+ "inherits": "build-default",
+ "inheritConfigureEnvironment": false,
+ "environment": {
+ "TEST_SOURCE_DIR_": "x${sourceDir}x",
+ "TEST_SOURCE_PARENT_DIR": "x${sourceParentDir}x",
+ "TEST_SOURCE_DIR_NAME": "x${sourceDirName}x",
+ "TEST_PRESET_NAME": "x${presetName}x",
+ "TEST_GENERATOR": "x${generator}x",
+ "TEST_DOLLAR": "x${dollar}x"
+ }
+ },
+ {
+ "name": "vendorObject",
+ "configurePreset": "default",
+ "vendor": {
+ "example.com": "value"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid-build-badConfigurePreset-result.txt b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-badConfigurePreset-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-badConfigurePreset-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid-build-badConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-badConfigurePreset-stderr.txt
new file mode 100644
index 0000000..7c3255d
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-badConfigurePreset-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error: No such configure preset in [^
+]*/Tests/RunCMake/CMakePresetsBuild/Invalid: "dne"
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid-build-hidden-result.txt b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-hidden-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-hidden-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid-build-hidden-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-hidden-stderr.txt
new file mode 100644
index 0000000..f10c7b8
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-hidden-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error: Cannot use hidden build preset in [^
+]*/Tests/RunCMake/CMakePresetsBuild/Invalid: "hidden"
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid-build-vendorMacro-result.txt b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-vendorMacro-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-vendorMacro-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid-build-vendorMacro-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-vendorMacro-stderr.txt
new file mode 100644
index 0000000..a3b951f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-vendorMacro-stderr.txt
@@ -0,0 +1 @@
+CMake Error: Could not evaluate build preset "vendorMacro": Invalid macro expansion
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid.cmake b/Tests/RunCMake/CMakePresetsBuild/Invalid.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Invalid.cmake
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid.json.in b/Tests/RunCMake/CMakePresetsBuild/Invalid.json.in
new file mode 100644
index 0000000..c22fdec
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Invalid.json.in
@@ -0,0 +1,23 @@
+{
+ "version": 2,
+ "configurePresets": [
+ {
+ "name": "default",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build/${presetName}"
+ }
+ ],
+ "buildPresets": [
+ {
+ "name": "hidden",
+ "hidden": true
+ },
+ {
+ "name": "vendorMacro",
+ "configurePreset": "default",
+ "environment": {
+ "TEST": "$vendor{bad.TEST}"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-build-badConfigurePreset-result.txt b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-build-badConfigurePreset-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-build-badConfigurePreset-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-build-badConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-build-badConfigurePreset-stderr.txt
new file mode 100644
index 0000000..303632e
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-build-badConfigurePreset-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset: Invalid "configurePreset" field
diff --git a/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-configure-default-result.txt b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-configure-default-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-configure-default-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-configure-default-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-configure-default-stderr.txt
new file mode 100644
index 0000000..303632e
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-configure-default-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset: Invalid "configurePreset" field
diff --git a/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset.cmake b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset.cmake
diff --git a/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset.json.in b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset.json.in
new file mode 100644
index 0000000..c0429d5
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset.json.in
@@ -0,0 +1,16 @@
+{
+ "version": 2,
+ "configurePresets": [
+ {
+ "name": "default",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build/${presetName}"
+ }
+ ],
+ "buildPresets": [
+ {
+ "name": "badConfigurePreset",
+ "configurePreset": "dne"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt b/Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt
new file mode 100644
index 0000000..2d362d4
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt
@@ -0,0 +1,6 @@
+^Available build presets:
+
+ "build-default" - build-default displayName
+ "empty"
+ "display" - display displayName
+ "true"$
diff --git a/Tests/RunCMake/CMakePresetsBuild/ListPresets.cmake b/Tests/RunCMake/CMakePresetsBuild/ListPresets.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/ListPresets.cmake
diff --git a/Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in b/Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in
new file mode 100644
index 0000000..26504d3
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in
@@ -0,0 +1,41 @@
+{
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "default",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build/${presetName}"
+ }
+ ],
+ "buildPresets": [
+ {
+ "name": "build-default",
+ "configurePreset": "default",
+ "displayName": "build-default displayName",
+ "description": "build-default description"
+ },
+ {
+ "name": "empty",
+ "inherits": "build-default"
+ },
+ {
+ "name": "display",
+ "inherits": "build-default",
+ "displayName": "display displayName"
+ },
+ {
+ "name": "hidden",
+ "hidden": true
+ },
+ {
+ "name": "true",
+ "inherits": "build-default",
+ "condition": true
+ },
+ {
+ "name": "false",
+ "inherits": "build-default",
+ "condition": false
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-result.txt b/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-stderr.txt
new file mode 100644
index 0000000..fcb37bc
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset: Invalid preset
diff --git a/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset.cmake b/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset.cmake
diff --git a/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset.json.in b/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset.json.in
new file mode 100644
index 0000000..81b2cde
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset.json.in
@@ -0,0 +1,15 @@
+{
+ "version": 2,
+ "configurePresets": [
+ {
+ "name": "default",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build/${presetName}"
+ }
+ ],
+ "buildPresets": [
+ {
+ "name": "noConfigurePreset"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported-build-x-result.txt b/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported-build-x-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported-build-x-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported-build-x-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported-build-x-stderr.txt
new file mode 100644
index 0000000..d6ae62d
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported-build-x-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported: File version must be 2 or higher for build and test preset support.
diff --git a/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported.json.in b/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported.json.in
new file mode 100644
index 0000000..0028239
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported.json.in
@@ -0,0 +1,7 @@
+{
+ "version": 1,
+ "configurePresets": [
+ ],
+ "buildPresets": [
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
new file mode 100644
index 0000000..afa22eb
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
@@ -0,0 +1,78 @@
+include(RunCMake)
+
+# Presets do not support legacy VS generator name architecture suffix.
+if(RunCMake_GENERATOR MATCHES "^(Visual Studio [0-9]+ [0-9]+) ")
+ set(RunCMake_GENERATOR "${CMAKE_MATCH_1}")
+endif()
+
+function(run_cmake_build_presets name CMakePresetsBuild_CONFIGURE_PRESETS CMakePresetsBuild_BUILD_PRESETS)
+ set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/${name}")
+ set(RunCMake_TEST_BINARY_DIR "${RunCMake_TEST_SOURCE_DIR}/build")
+ set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}")
+
+ set(RunCMake_TEST_NO_CLEAN TRUE)
+
+ file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+ set(CASE_NAME "${name}")
+ set(CASE_SOURCE_DIR "${RunCMake_SOURCE_DIR}")
+ configure_file("${RunCMake_SOURCE_DIR}/CMakeLists.txt.in" "${RunCMake_TEST_SOURCE_DIR}/CMakeLists.txt" @ONLY)
+
+ if(NOT CMakePresetsBuild_FILE)
+ set(CMakePresetsBuild_FILE "${RunCMake_SOURCE_DIR}/${name}.json.in")
+ endif()
+ if(EXISTS "${CMakePresetsBuild_FILE}")
+ configure_file("${CMakePresetsBuild_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakePresets.json" @ONLY)
+ endif()
+
+ if(NOT CMakeUserPresets_FILE)
+ set(CMakeUserPresets_FILE "${RunCMake_SOURCE_DIR}/${name}User.json.in")
+ endif()
+ if(EXISTS "${CMakeUserPresets_FILE}")
+ configure_file("${CMakeUserPresets_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" @ONLY)
+ endif()
+
+ if (NOT CMakePresetsBuild_BUILD_ONLY)
+ foreach(CONFIGURE_PRESET ${CMakePresetsBuild_CONFIGURE_PRESETS})
+ run_cmake_command("${name}-configure-${CONFIGURE_PRESET}"
+ "${CMAKE_COMMAND}" "--preset" "${CONFIGURE_PRESET}")
+ endforeach()
+ endif()
+
+ set(eq 0)
+ foreach(BUILD_PRESET ${CMakePresetsBuild_BUILD_PRESETS})
+ if (EXISTS "${RunCMake_SOURCE_DIR}/${name}-build-${BUILD_PRESET}-check.cmake")
+ set(RunCMake-check-file "${name}-build-${BUILD_PRESET}-check.cmake")
+ else()
+ set(RunCMake-check-file "check.cmake")
+ endif()
+
+ if(eq)
+ run_cmake_command(${name}-build-${BUILD_PRESET}
+ ${CMAKE_COMMAND} "--build" "--preset=${BUILD_PRESET}" ${ARGN})
+ set(eq 0)
+ else()
+ run_cmake_command(${name}-build-${BUILD_PRESET}
+ ${CMAKE_COMMAND} "--build" "--preset" "${BUILD_PRESET}" ${ARGN})
+ set(eq 1)
+ endif()
+ endforeach()
+endfunction()
+
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+
+run_cmake_build_presets(Good "default;other" "build-other;withEnvironment;noEnvironment;macros;vendorObject")
+run_cmake_build_presets(InvalidConfigurePreset "default" "badConfigurePreset")
+run_cmake_build_presets(Condition "default" "enabled;disabled")
+
+set(CMakePresetsBuild_BUILD_ONLY 1)
+run_cmake_build_presets(ListPresets "x" "x" "--list-presets")
+run_cmake_build_presets(NoConfigurePreset "x" "noConfigurePreset")
+run_cmake_build_presets(Invalid "x" "hidden;vendorMacro")
+
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
+run_cmake_build_presets(PresetsUnsupported "x" "x")
+run_cmake_build_presets(ConditionFuture "x" "conditionFuture")
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+set(CMakePresetsBuild_BUILD_ONLY 0)
diff --git a/Tests/RunCMake/CMakePresetsBuild/TestVariable.cmake b/Tests/RunCMake/CMakePresetsBuild/TestVariable.cmake
new file mode 100644
index 0000000..3113dcc
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/TestVariable.cmake
@@ -0,0 +1,14 @@
+function(test_environment_variable name expected_value)
+ string(REGEX MATCH "${name}=([^\n]*)" REGEX_RESULT "${actual_stdout}")
+ if(NOT REGEX_RESULT)
+ string(APPEND RunCMake_TEST_FAILED "Environment variable '${name}' is not defined.\n")
+ else()
+ set(actual_value "${CMAKE_MATCH_1}")
+ if(NOT "${actual_value}" MATCHES "${expected_value}")
+ string(REPLACE "\n" "\n " _actual "${expected_value}")
+ string(REPLACE "\n" "\n " _expect "${actual_value}")
+ string(APPEND RunCMake_TEST_FAILED "Expected value of environment variable '${name}':\n ${_expect}\nActual value:\n ${_actual}\n")
+ endif()
+ endif()
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CMakePresetsBuild/check.cmake b/Tests/RunCMake/CMakePresetsBuild/check.cmake
new file mode 100644
index 0000000..e79c4f1
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/check.cmake
@@ -0,0 +1,3 @@
+set(CMakePresets_VALIDATE_SCRIPT_PATH "${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.py")
+include("${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.cmake")
+include("${RunCMake_SOURCE_DIR}/../CMakePresets/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsTest/CMakeLists.txt.in b/Tests/RunCMake/CMakePresetsTest/CMakeLists.txt.in
new file mode 100644
index 0000000..129184a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/CMakeLists.txt.in
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project("@CASE_NAME@" NONE)
+include("@CASE_SOURCE_DIR@/@CASE_NAME@.cmake")
diff --git a/Tests/RunCMake/CMakePresetsTest/Condition.json.in b/Tests/RunCMake/CMakePresetsTest/Condition.json.in
new file mode 100644
index 0000000..0baf176
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Condition.json.in
@@ -0,0 +1,22 @@
+{
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "default",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ],
+ "testPresets": [
+ {
+ "name": "enabled",
+ "configurePreset": "default",
+ "condition": true
+ },
+ {
+ "name": "disabled",
+ "configurePreset": "default",
+ "condition": false
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-result.txt b/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-stderr.txt b/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-stderr.txt
new file mode 100644
index 0000000..b814bbb
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsTest/ConditionFuture: File version must be 3 or higher for condition support$
diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionFuture.json.in b/Tests/RunCMake/CMakePresetsTest/ConditionFuture.json.in
new file mode 100644
index 0000000..4b9f33f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ConditionFuture.json.in
@@ -0,0 +1,17 @@
+{
+ "version": 2,
+ "configurePresets": [
+ {
+ "name": "default",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build"
+ }
+ ],
+ "testPresets": [
+ {
+ "name": "conditionFuture",
+ "configurePreset": "default",
+ "condition": true
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionListPresets-test-x-stdout.txt b/Tests/RunCMake/CMakePresetsTest/ConditionListPresets-test-x-stdout.txt
new file mode 100644
index 0000000..11918e5
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ConditionListPresets-test-x-stdout.txt
@@ -0,0 +1,3 @@
+^Available test presets:
+
+ "enabled"$
diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-result.txt b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-stderr.txt b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-stderr.txt
new file mode 100644
index 0000000..5db3b77
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Cannot use disabled test preset in [^
+]*/Tests/RunCMake/CMakePresetsTest/ConditionRunTests: "disabled"$
diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionRunTests.cmake b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests.cmake
new file mode 100644
index 0000000..b29161e
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests.cmake
@@ -0,0 +1,2 @@
+enable_testing()
+add_test(true ${CMAKE_COMMAND} -E true)
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-indexFile.txt b/Tests/RunCMake/CMakePresetsTest/Good-indexFile.txt
new file mode 100644
index 0000000..4ac2314
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Good-indexFile.txt
@@ -0,0 +1 @@
+2,,2
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-config-debug-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-config-debug-stdout.txt
new file mode 100644
index 0000000..c281c81
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Good-test-config-debug-stdout.txt
@@ -0,0 +1,5 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+ Start 6: debug-only
+.*
+100% tests passed, 0 tests failed out of 1
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-config-release-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-config-release-stdout.txt
new file mode 100644
index 0000000..66bfd22
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Good-test-config-release-stdout.txt
@@ -0,0 +1,5 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+ Start 6: release-only
+.*
+100% tests passed, 0 tests failed out of 1
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-exclude-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-exclude-stdout.txt
new file mode 100644
index 0000000..5e990de
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Good-test-exclude-stdout.txt
@@ -0,0 +1,7 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+ Start 3: testc
+.*
+ Start 4: testd
+.*
+100% tests passed, 0 tests failed out of 2
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-index-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-index-stdout.txt
new file mode 100644
index 0000000..2df6fcb
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Good-test-index-stdout.txt
@@ -0,0 +1,7 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+ Start 1: testa
+.*
+ Start 3: testc
+.*
+100% tests passed, 0 tests failed out of 2
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-indexFile-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-indexFile-stdout.txt
new file mode 100644
index 0000000..1366876
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Good-test-indexFile-stdout.txt
@@ -0,0 +1,7 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+ Start 2: testb
+.*
+ Start 4: testd
+.*
+100% tests passed, 0 tests failed out of 2
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-noEnvironment-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-noEnvironment-stdout.txt
new file mode 100644
index 0000000..8b4845e
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Good-test-noEnvironment-stdout.txt
@@ -0,0 +1,8 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+.*
+ Start 5: test-env
+.*
+5: TEST_ENV_REF=xx
+.*
+100% tests passed, 0 tests failed out of 1
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-showOnly-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-showOnly-stdout.txt
new file mode 100644
index 0000000..67ddd4f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Good-test-showOnly-stdout.txt
@@ -0,0 +1,8 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+ Test #1: testa
+ Test #2: testb
+ Test #3: testc
+ Test #4: testd
+
+Total Tests: 4
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-withEnvironment-check.cmake b/Tests/RunCMake/CMakePresetsTest/Good-withEnvironment-check.cmake
new file mode 100644
index 0000000..0c19556
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Good-withEnvironment-check.cmake
@@ -0,0 +1,8 @@
+include("${RunCMake_SOURCE_DIR}/../CMakePresetsBuild/TestVariable.cmake")
+
+test_environment_variable("TEST_ENV" "Environment variable")
+test_environment_variable("TEST_ENV_OVERRIDE" "Override")
+test_environment_variable("TEST_ENV_OVERRIDE_REF" "xOverridex")
+test_environment_variable("TEST_ENV_REF" "xEnvironment variablex")
+
+include("${RunCMake_SOURCE_DIR}/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsTest/Good.cmake b/Tests/RunCMake/CMakePresetsTest/Good.cmake
new file mode 100644
index 0000000..0a6cf57
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Good.cmake
@@ -0,0 +1,27 @@
+enable_testing()
+add_test(testa ${CMAKE_COMMAND} -E echo testa)
+add_test(testb ${CMAKE_COMMAND} -E echo testb)
+add_test(testc ${CMAKE_COMMAND} -E echo testc)
+add_test(testd ${CMAKE_COMMAND} -E echo testd)
+
+set_tests_properties(testa testb testc testd
+ PROPERTIES LABELS "echo")
+set_property(TEST testa testb
+ APPEND PROPERTY LABELS ab)
+set_property(TEST testb testc
+ APPEND PROPERTY LABELS bc)
+set_property(TEST testc testd
+ APPEND PROPERTY LABELS cd)
+
+add_test(test-env ${CMAKE_COMMAND} -E environment | sort)
+set_tests_properties(test-env PROPERTIES LABELS "env")
+
+add_test(NAME debug-only
+ COMMAND ${CMAKE_COMMAND} -E echo debug-only
+ CONFIGURATIONS Debug)
+add_test(NAME release-only
+ COMMAND ${CMAKE_COMMAND} -E echo release-only
+ CONFIGURATIONS Release)
+
+set_tests_properties(debug-only release-only
+ PROPERTIES LABELS "config")
diff --git a/Tests/RunCMake/CMakePresetsTest/Good.json.in b/Tests/RunCMake/CMakePresetsTest/Good.json.in
new file mode 100644
index 0000000..57be5a5
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Good.json.in
@@ -0,0 +1,175 @@
+{
+ "version": 2,
+ "configurePresets": [
+ {
+ "name": "default",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build/${presetName}",
+ "environment": {
+ "TEST_ENV": "Environment variable",
+ "TEST_ENV_OVERRIDE": "Overridden environment variable"
+ }
+ }
+ ],
+ "buildPresets": [
+ {
+ "name": "build-default-debug",
+ "configurePreset": "default",
+ "configuration": "Debug"
+ },
+ {
+ "name": "build-default-release",
+ "inherits": "build-default-debug",
+ "configuration": "Release"
+ }
+ ],
+ "testPresets": [
+ {
+ "name": "minimal",
+ "configurePreset": "default"
+ },
+ {
+ "name": "defaults",
+ "hidden": false,
+ "inherits": [],
+ "vendor": {},
+ "displayName": "",
+ "description": "",
+ "environment": {},
+ "configurePreset": "default",
+ "inheritConfigureEnvironment": true,
+ "configuration": "",
+ "overwriteConfigurationFile": [],
+ "output": {
+ "shortProgress": false,
+ "verbosity": "default",
+ "debug": false,
+ "outputOnFailure": false,
+ "quiet": false,
+ "outputLogFile": "",
+ "labelSummary": true,
+ "subprojectSummary": true
+ },
+ "filter": {
+ "include": {
+ "name": "",
+ "label": "",
+ "useUnion": false,
+ "index": ""
+ },
+ "exclude": {
+ "name": "",
+ "label": "",
+ "fixtures": {
+ "any": "",
+ "setup": "",
+ "cleanup": ""
+ }
+ }
+ },
+ "execution": {
+ "stopOnFailure": false,
+ "enableFailover": false,
+ "jobs": 0,
+ "resourceSpecFile": "",
+ "showOnly": "human",
+ "repeat": {
+ "mode": "until-pass",
+ "count": 1
+ },
+ "interactiveDebugging": false,
+ "scheduleRandom": false,
+ "noTestsAction": "default"
+ }
+ },
+ {
+ "name": "noEnvironment",
+ "configurePreset": "default",
+ "inheritConfigureEnvironment": false,
+ "environment": {
+ "TEST_ENV_REF": "x$env{TEST_ENV}x"
+ },
+ "filter": {
+ "include": {
+ "name": "test-env"
+ }
+ },
+ "output": {
+ "verbosity": "verbose"
+ }
+ },
+ {
+ "name": "withEnvironment",
+ "inherits": "noEnvironment",
+ "inheritConfigureEnvironment": true,
+ "environment": {
+ "TEST_ENV_OVERRIDE": "Override",
+ "TEST_ENV_OVERRIDE_REF": "x$env{TEST_ENV_OVERRIDE}x",
+ "TEST_ENV_REF": "x$env{TEST_ENV}x"
+ }
+ },
+ {
+ "name": "config-debug",
+ "inherits": "minimal",
+ "configuration": "Debug",
+ "filter": {
+ "include": {
+ "label": "config"
+ }
+ }
+ },
+ {
+ "name": "config-release",
+ "inherits": "minimal",
+ "configuration": "Release",
+ "filter": {
+ "include": {
+ "label": "config"
+ }
+ }
+ },
+ {
+ "name": "exclude",
+ "inherits": "minimal",
+ "filter": {
+ "exclude": {
+ "name": "test-env",
+ "label": "(ab|config)"
+ }
+ }
+ },
+ {
+ "name": "index",
+ "inherits": "minimal",
+ "filter": {
+ "include": {
+ "index": {
+ "end": 4,
+ "stride": 2
+ }
+ }
+ }
+ },
+ {
+ "name": "indexFile",
+ "inherits": "minimal",
+ "filter": {
+ "include": {
+ "index": "${sourceDir}/Good-indexFile.txt"
+ }
+ }
+ },
+ {
+ "name": "showOnly",
+ "inherits": "minimal",
+ "filter": {
+ "include": {
+ "label": "echo"
+ }
+ },
+ "execution": {
+ "showOnly": "human"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid-test-badConfigurePreset-result.txt b/Tests/RunCMake/CMakePresetsTest/Invalid-test-badConfigurePreset-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Invalid-test-badConfigurePreset-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid-test-badConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresetsTest/Invalid-test-badConfigurePreset-stderr.txt
new file mode 100644
index 0000000..9cf9987
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Invalid-test-badConfigurePreset-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error: No such configure preset in [^
+]*/Tests/RunCMake/CMakePresetsTest/Invalid: "dne"
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid-test-hidden-result.txt b/Tests/RunCMake/CMakePresetsTest/Invalid-test-hidden-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Invalid-test-hidden-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid-test-hidden-stderr.txt b/Tests/RunCMake/CMakePresetsTest/Invalid-test-hidden-stderr.txt
new file mode 100644
index 0000000..41b1b4e
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Invalid-test-hidden-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error: Cannot use hidden test preset in [^
+]*/Tests/RunCMake/CMakePresetsTest/Invalid: "hidden"
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid-test-vendorMacro-result.txt b/Tests/RunCMake/CMakePresetsTest/Invalid-test-vendorMacro-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Invalid-test-vendorMacro-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid-test-vendorMacro-stderr.txt b/Tests/RunCMake/CMakePresetsTest/Invalid-test-vendorMacro-stderr.txt
new file mode 100644
index 0000000..ed5bb98
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Invalid-test-vendorMacro-stderr.txt
@@ -0,0 +1 @@
+CMake Error: Could not evaluate test preset "vendorMacro": Invalid macro expansion
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid.cmake b/Tests/RunCMake/CMakePresetsTest/Invalid.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Invalid.cmake
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid.json.in b/Tests/RunCMake/CMakePresetsTest/Invalid.json.in
new file mode 100644
index 0000000..cfcf4b7
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Invalid.json.in
@@ -0,0 +1,23 @@
+{
+ "version": 2,
+ "configurePresets": [
+ {
+ "name": "default",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build/${presetName}"
+ }
+ ],
+ "testPresets": [
+ {
+ "name": "hidden",
+ "hidden": true
+ },
+ {
+ "name": "vendorMacro",
+ "configurePreset": "default",
+ "environment": {
+ "TEST": "$vendor{bad.TEST}"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-configure-default-result.txt b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-configure-default-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-configure-default-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-configure-default-stderr.txt b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-configure-default-stderr.txt
new file mode 100644
index 0000000..3d7cdd0
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-configure-default-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset: Invalid "configurePreset" field
diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-test-badConfigurePreset-result.txt b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-test-badConfigurePreset-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-test-badConfigurePreset-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-test-badConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-test-badConfigurePreset-stderr.txt
new file mode 100644
index 0000000..3d7cdd0
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-test-badConfigurePreset-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset: Invalid "configurePreset" field
diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset.cmake b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset.cmake
diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset.json.in b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset.json.in
new file mode 100644
index 0000000..e305c42
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset.json.in
@@ -0,0 +1,16 @@
+{
+ "version": 2,
+ "configurePresets": [
+ {
+ "name": "default",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build/${presetName}"
+ }
+ ],
+ "testPresets": [
+ {
+ "name": "badConfigurePreset",
+ "configurePreset": "dne"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt b/Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt
new file mode 100644
index 0000000..46ffbcf
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt
@@ -0,0 +1,12 @@
+Available test presets:
+
+ "minimal"
+ "defaults"
+ "noEnvironment"
+ "withEnvironment"
+ "config-debug"
+ "config-release"
+ "exclude"
+ "index"
+ "indexFile"
+ "showOnly"
diff --git a/Tests/RunCMake/CMakePresetsTest/ListPresets.cmake b/Tests/RunCMake/CMakePresetsTest/ListPresets.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ListPresets.cmake
diff --git a/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-result.txt b/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-stderr.txt
new file mode 100644
index 0000000..b167f68
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset: Invalid preset
diff --git a/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset.cmake b/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset.cmake
diff --git a/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset.json.in b/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset.json.in
new file mode 100644
index 0000000..4591cc8
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset.json.in
@@ -0,0 +1,15 @@
+{
+ "version": 2,
+ "configurePresets": [
+ {
+ "name": "default",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build/${presetName}"
+ }
+ ],
+ "testPresets": [
+ {
+ "name": "noConfigurePreset"
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/NoTestsAction-test-noTestsAction-result.txt b/Tests/RunCMake/CMakePresetsTest/NoTestsAction-test-noTestsAction-result.txt
new file mode 100644
index 0000000..45a4fb7
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/NoTestsAction-test-noTestsAction-result.txt
@@ -0,0 +1 @@
+8
diff --git a/Tests/RunCMake/CMakePresetsTest/NoTestsAction-test-noTestsAction-stderr.txt b/Tests/RunCMake/CMakePresetsTest/NoTestsAction-test-noTestsAction-stderr.txt
new file mode 100644
index 0000000..eafba1c
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/NoTestsAction-test-noTestsAction-stderr.txt
@@ -0,0 +1 @@
+No tests were found!!!
diff --git a/Tests/RunCMake/CMakePresetsTest/NoTestsAction.cmake b/Tests/RunCMake/CMakePresetsTest/NoTestsAction.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/NoTestsAction.cmake
diff --git a/Tests/RunCMake/CMakePresetsTest/NoTestsAction.json.in b/Tests/RunCMake/CMakePresetsTest/NoTestsAction.json.in
new file mode 100644
index 0000000..20a50d6
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/NoTestsAction.json.in
@@ -0,0 +1,19 @@
+{
+ "version": 2,
+ "configurePresets": [
+ {
+ "name": "default",
+ "generator": "@RunCMake_GENERATOR@",
+ "binaryDir": "${sourceDir}/build/${presetName}"
+ }
+ ],
+ "testPresets": [
+ {
+ "name": "noTestsAction",
+ "configurePreset": "default",
+ "execution": {
+ "noTestsAction": "error"
+ }
+ }
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported-test-x-result.txt b/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported-test-x-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported-test-x-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported-test-x-stderr.txt b/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported-test-x-stderr.txt
new file mode 100644
index 0000000..eb0ec1a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported-test-x-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*Tests/RunCMake/CMakePresetsTest/PresetsUnsupported: File version must be 2 or higher for build and test preset support.
diff --git a/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported.json.in b/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported.json.in
new file mode 100644
index 0000000..ff1b000
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported.json.in
@@ -0,0 +1,7 @@
+{
+ "version": 1,
+ "configurePresets": [
+ ],
+ "testPresets": [
+ ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake
new file mode 100644
index 0000000..70d25d4
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake
@@ -0,0 +1,111 @@
+include(RunCMake)
+
+# Presets do not support legacy VS generator name architecture suffix.
+if(RunCMake_GENERATOR MATCHES "^(Visual Studio [0-9]+ [0-9]+) ")
+ set(RunCMake_GENERATOR "${CMAKE_MATCH_1}")
+endif()
+
+function(run_cmake_test_presets name CMakePresetsTest_CONFIGURE_PRESETS CMakePresetsTest_BUILD_PRESETS CMakePresetsTest_TEST_PRESETS)
+ set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/${name}")
+ set(RunCMake_TEST_BINARY_DIR "${RunCMake_TEST_SOURCE_DIR}/build")
+ set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}")
+
+ set(RunCMake_TEST_NO_CLEAN TRUE)
+
+ file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+ set(CASE_NAME "${name}")
+ set(CASE_SOURCE_DIR "${RunCMake_SOURCE_DIR}")
+ configure_file("${RunCMake_SOURCE_DIR}/CMakeLists.txt.in" "${RunCMake_TEST_SOURCE_DIR}/CMakeLists.txt" @ONLY)
+
+ if(NOT CMakePresetsTest_FILE)
+ set(CMakePresetsTest_FILE "${RunCMake_SOURCE_DIR}/${name}.json.in")
+ endif()
+ if(EXISTS "${CMakePresetsTest_FILE}")
+ configure_file("${CMakePresetsTest_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakePresets.json" @ONLY)
+ endif()
+
+ if(NOT CMakeUserPresets_FILE)
+ set(CMakeUserPresets_FILE "${RunCMake_SOURCE_DIR}/${name}User.json.in")
+ endif()
+ if(EXISTS "${CMakeUserPresets_FILE}")
+ configure_file("${CMakeUserPresets_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" @ONLY)
+ endif()
+
+ foreach(ASSET ${CMakePresetsTest_ASSETS})
+ configure_file("${RunCMake_SOURCE_DIR}/${ASSET}" "${RunCMake_TEST_SOURCE_DIR}" COPYONLY)
+ endforeach()
+
+ if (NOT CMakePresetsTest_NO_CONFIGURE)
+ foreach(CONFIGURE_PRESET ${CMakePresetsTest_CONFIGURE_PRESETS})
+ run_cmake_command("${name}-configure-${CONFIGURE_PRESET}"
+ "${CMAKE_COMMAND}" "--preset" "${CONFIGURE_PRESET}")
+ endforeach()
+ endif()
+
+ if (NOT CMakePresetsTest_NO_BUILD)
+ foreach(BUILD_PRESET ${CMakePresetsTest_BUILD_PRESETS})
+ run_cmake_command("${name}-build-${BUILD_PRESET}"
+ "${CMAKE_COMMAND}" "--build" "--preset" "${BUILD_PRESET}")
+ endforeach()
+ endif()
+
+ set(eq 0)
+ foreach(TEST_PRESET ${CMakePresetsTest_TEST_PRESETS})
+ if (EXISTS "${RunCMake_SOURCE_DIR}/${name}-test-${TEST_PRESET}-check.cmake")
+ set(RunCMake-check-file "${name}-test-${TEST_PRESET}-check.cmake")
+ else()
+ set(RunCMake-check-file "check.cmake")
+ endif()
+
+ if(eq)
+ run_cmake_command(${name}-test-${TEST_PRESET}
+ ${CMAKE_CTEST_COMMAND} "--preset=${TEST_PRESET}" ${ARGN})
+ set(eq 0)
+ else()
+ run_cmake_command(${name}-test-${TEST_PRESET}
+ ${CMAKE_CTEST_COMMAND} "--preset" "${TEST_PRESET}" ${ARGN})
+ set(eq 1)
+ endif()
+ endforeach()
+endfunction()
+
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+set(CMakePresetsTest_NO_BUILD 1)
+
+set(CMakePresetsTest_ASSETS "Good-indexFile.txt")
+set(GoodTestPresets
+ "minimal;defaults;noEnvironment;withEnvironment"
+ "config-debug;config-release"
+ "exclude;index;indexFile;showOnly")
+run_cmake_test_presets(Good
+ "default"
+ ""
+ "${GoodTestPresets}")
+unset(CMakePresetsTest_ASSETS)
+
+run_cmake_test_presets(InvalidConfigurePreset "default" "" "badConfigurePreset")
+
+set(CMakePresetsTest_NO_CONFIGURE 1)
+set(CMakePresetsTest_FILE "${RunCMake_SOURCE_DIR}/Good.json.in")
+run_cmake_test_presets(ListPresets "" "" "x" "--list-presets")
+
+set(CMakePresetsTest_FILE "${RunCMake_SOURCE_DIR}/Condition.json.in")
+run_cmake_test_presets(ConditionListPresets "" "" "x" "--list-presets")
+unset(CMakePresetsTest_NO_CONFIGURE)
+run_cmake_test_presets(ConditionRunTests "default" "" "enabled;disabled")
+set(CMakePresetsTest_NO_CONFIGURE 1)
+unset(CMakePresetsTest_FILE)
+
+run_cmake_test_presets(NoConfigurePreset "" "" "noConfigurePreset")
+run_cmake_test_presets(NoTestsAction "default" "" "noTestsAction")
+run_cmake_test_presets(Invalid "" "" "hidden;vendorMacro")
+
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
+run_cmake_test_presets(PresetsUnsupported "" "" "x")
+run_cmake_test_presets(ConditionFuture "" "" "x")
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+set(CMakePresetsTest_NO_CONFIGURE 0)
+
+set(CMakePresetsTest_NO_BUILD 0)
diff --git a/Tests/RunCMake/CMakePresetsTest/check.cmake b/Tests/RunCMake/CMakePresetsTest/check.cmake
new file mode 100644
index 0000000..e79c4f1
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/check.cmake
@@ -0,0 +1,3 @@
+set(CMakePresets_VALIDATE_SCRIPT_PATH "${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.py")
+include("${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.cmake")
+include("${RunCMake_SOURCE_DIR}/../CMakePresets/check.cmake")
diff --git a/Tests/RunCMake/CMakeRelease/FileTable-stdout.txt b/Tests/RunCMake/CMakeRelease/FileTable-stdout.txt
new file mode 100644
index 0000000..37eb91e
--- /dev/null
+++ b/Tests/RunCMake/CMakeRelease/FileTable-stdout.txt
@@ -0,0 +1,44 @@
+^-- query: \.version \| \.major , \.minor , \.patch , \.suffix, \.string
+1
+2
+3
+"rc4"
+"@version@"
+-- query: \.files\[\]\.name
+"cmake-@version@-linux-aarch64\.sh"
+"cmake-@version@-linux-aarch64\.tar\.gz"
+"cmake-@version@-linux-x86_64\.sh"
+"cmake-@version@-linux-x86_64\.tar\.gz"
+"cmake-@version@-macos-universal\.dmg"
+"cmake-@version@-macos-universal\.tar\.gz"
+"cmake-@version@-macos10\.10-universal\.dmg"
+"cmake-@version@-macos10\.10-universal\.tar\.gz"
+"cmake-@version@-windows-i386\.msi"
+"cmake-@version@-windows-i386\.zip"
+"cmake-@version@-windows-x86_64\.msi"
+"cmake-@version@-windows-x86_64\.zip"
+"cmake-@version@\.tar\.gz"
+"cmake-@version@\.zip"
+-- query: \.files\[\] \| select\(\.os\[\] \| \. == "source"\) \| \.name
+"cmake-@version@\.tar\.gz"
+"cmake-@version@\.zip"
+-- query: \.files\[\] \| select\(\(\.os\[\] \| \. == "macOS"\) and \(\.class == "volume"\)\) \| \.name
+"cmake-@version@-macos-universal\.dmg"
+-- query: \.files\[\] \| select\(\(\.os\[\] \| \. == "macos10\.10"\) and \(\.class == "archive"\)\) \| \.name
+"cmake-@version@-macos10\.10-universal\.tar\.gz"
+-- query: \.files\[\] \| select\(\(\.os\[\] \| \. == "windows"\) and \(\.architecture\[\] \| \. == "i386"\) and \(\.class == "installer"\)\) \| \.name
+"cmake-@version@-windows-i386\.msi"
+-- query: \.files\[\] \| select\(\.architecture\[\] \| \. == "x86_64"\) \| \.name
+"cmake-@version@-linux-x86_64\.sh"
+"cmake-@version@-linux-x86_64\.tar\.gz"
+"cmake-@version@-macos-universal\.dmg"
+"cmake-@version@-macos-universal\.tar\.gz"
+"cmake-@version@-macos10\.10-universal\.dmg"
+"cmake-@version@-macos10\.10-universal\.tar\.gz"
+"cmake-@version@-windows-x86_64\.msi"
+"cmake-@version@-windows-x86_64\.zip"
+-- query: \.files\[\] \| select\(\[\.macOSmin\] \| inside\(\["10\.10", "10\.11", "10\.12"\]\)\) \| \.name
+"cmake-@version@-macos10\.10-universal\.dmg"
+"cmake-@version@-macos10\.10-universal\.tar\.gz"
+-- query: \.hashFiles\[\] \| select\(\.algorithm\[\] \| \. == "SHA-256"\) \| \.name
+"cmake-@version@-SHA-256\.txt"$
diff --git a/Tests/RunCMake/CMakeRelease/FileTable.cmake b/Tests/RunCMake/CMakeRelease/FileTable.cmake
new file mode 100644
index 0000000..f46535c
--- /dev/null
+++ b/Tests/RunCMake/CMakeRelease/FileTable.cmake
@@ -0,0 +1,21 @@
+set(version "@version@")
+set(version_major "1")
+set(version_minor "2")
+set(version_patch "3")
+set(maybe_version_suffix "\"suffix\": \"rc4\",")
+configure_file("${CMAKE_CURRENT_LIST_DIR}/../../../Utilities/Release/files-v1.json.in" "files-v1.json" @ONLY)
+
+foreach(query
+ ".version | .major , .minor , .patch , .suffix, .string"
+ ".files[].name"
+ ".files[] | select(.os[] | . == \"source\") | .name"
+ ".files[] | select((.os[] | . == \"macOS\") and (.class == \"volume\")) | .name"
+ ".files[] | select((.os[] | . == \"macos10.10\") and (.class == \"archive\")) | .name"
+ ".files[] | select((.os[] | . == \"windows\") and (.architecture[] | . == \"i386\") and (.class == \"installer\")) | .name"
+ ".files[] | select(.architecture[] | . == \"x86_64\") | .name"
+ ".files[] | select([.macOSmin] | inside([\"10.10\", \"10.11\", \"10.12\"])) | .name"
+ ".hashFiles[] | select(.algorithm[] | . == \"SHA-256\") | .name"
+ )
+ message(STATUS "query: ${query}")
+ execute_process(COMMAND ${JQ} "${query}" files-v1.json)
+endforeach()
diff --git a/Tests/RunCMake/CMakeRelease/RunCMakeTest.cmake b/Tests/RunCMake/CMakeRelease/RunCMakeTest.cmake
new file mode 100644
index 0000000..9a08ff3
--- /dev/null
+++ b/Tests/RunCMake/CMakeRelease/RunCMakeTest.cmake
@@ -0,0 +1,10 @@
+include(RunCMake)
+
+if(CMake_TEST_JQ)
+ set(JQ "${CMake_TEST_JQ}")
+else()
+ find_program(JQ NAMES jq)
+endif()
+if(JQ)
+ run_cmake_script(FileTable -DJQ=${JQ})
+endif()
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/BuildAndTest/CMakeLists.txt b/Tests/RunCMake/CMakeRoleGlobalProperty/BuildAndTest/CMakeLists.txt
new file mode 100644
index 0000000..332b023
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/BuildAndTest/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.12)
+project(CMakeRoleGlobalPropertyBuildAndTest NONE)
+include(CTest)
+
+get_property(role GLOBAL PROPERTY CMAKE_ROLE)
+if(NOT role STREQUAL "PROJECT")
+ message(SEND_ERROR "CMAKE_ROLE property is \"${role}\", should be \"PROJECT\"")
+endif()
+
+add_test(NAME RunCMakeVersion COMMAND "${CMAKE_COMMAND}" --version)
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt b/Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt
new file mode 100644
index 0000000..44025d3
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.12)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt.in b/Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt.in
new file mode 100644
index 0000000..bb8f9c1
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt.in
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.12)
+project(CMakeRoleGlobalProperty@CASE_NAME@ NONE)
+include(CTest)
+add_test(NAME RunCMakeVersion COMMAND "${CMAKE_COMMAND}" --version)
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/FindDummyPackage.cmake b/Tests/RunCMake/CMakeRoleGlobalProperty/FindDummyPackage.cmake
new file mode 100644
index 0000000..8299042
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/FindDummyPackage.cmake
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.12)
+
+get_property(role GLOBAL PROPERTY CMAKE_ROLE)
+if(NOT role STREQUAL "FIND_PACKAGE")
+ message(SEND_ERROR "CMAKE_ROLE property is \"${role}\", should be \"FIND_PACKAGE\"")
+endif()
+
+set(DummyPackage_FOUND 1)
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/Project.cmake b/Tests/RunCMake/CMakeRoleGlobalProperty/Project.cmake
new file mode 100644
index 0000000..22cad2b
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/Project.cmake
@@ -0,0 +1,10 @@
+get_property(role GLOBAL PROPERTY CMAKE_ROLE)
+
+file(WRITE "${CMAKE_BINARY_DIR}/test.cmake" "# a")
+include("${CMAKE_BINARY_DIR}/test.cmake")
+
+if(NOT role STREQUAL "PROJECT")
+ message(SEND_ERROR "CMAKE_ROLE property is \"${role}\", should be \"PROJECT\"")
+endif()
+
+add_subdirectory(sub)
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/RunCMakeTest.cmake b/Tests/RunCMake/CMakeRoleGlobalProperty/RunCMakeTest.cmake
new file mode 100644
index 0000000..7b29c28
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/RunCMakeTest.cmake
@@ -0,0 +1,17 @@
+include(RunCMake)
+include(RunCTest)
+
+run_cmake(Project)
+file(WRITE "${RunCMake_BINARY_DIR}/Project-build/test.cmake" "# b")
+run_cmake_command(ProjectBuild "${CMAKE_COMMAND}" --build "${RunCMake_BINARY_DIR}/Project-build")
+
+run_cmake_command(Script "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_LIST_DIR}/Script.cmake")
+run_cmake_command(FindPackage "${CMAKE_COMMAND}" --find-package -DNAME=DummyPackage -DCOMPILER_ID=GNU -DLANGUAGE=CXX -DMODE=EXIST "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}")
+run_ctest(CTest)
+run_cmake_command(BuildAndTest "${CMAKE_CTEST_COMMAND}"
+ --build-and-test
+ "${RunCMake_SOURCE_DIR}/BuildAndTest"
+ "${RunCMake_BINARY_DIR}/BuildAndTest-build"
+ --build-project CMakeRoleGlobalPropertyBuildAndTest
+ --build-generator "${RunCMake_GENERATOR}"
+ )
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/Script.cmake b/Tests/RunCMake/CMakeRoleGlobalProperty/Script.cmake
new file mode 100644
index 0000000..371edbc
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/Script.cmake
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.12)
+
+get_property(role GLOBAL PROPERTY CMAKE_ROLE)
+if(NOT role STREQUAL "SCRIPT")
+ message(SEND_ERROR "CMAKE_ROLE property is \"${role}\", should be \"SCRIPT\"")
+endif()
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/sub/CMakeLists.txt b/Tests/RunCMake/CMakeRoleGlobalProperty/sub/CMakeLists.txt
new file mode 100644
index 0000000..8ecf671
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/sub/CMakeLists.txt
@@ -0,0 +1,4 @@
+get_property(role GLOBAL PROPERTY CMAKE_ROLE)
+if(NOT role STREQUAL "PROJECT")
+ message(SEND_ERROR "CMAKE_ROLE property is \"${role}\", should be \"PROJECT\"")
+endif()
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/test.cmake.in b/Tests/RunCMake/CMakeRoleGlobalProperty/test.cmake.in
new file mode 100644
index 0000000..4e2c085
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/test.cmake.in
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.12)
+set(CTEST_RUN_CURRENT_SCRIPT 0)
+
+get_property(role GLOBAL PROPERTY CMAKE_ROLE)
+if(NOT role STREQUAL "CTEST")
+ message(SEND_ERROR "CMAKE_ROLE property is \"${role}\", should be \"CTEST\"")
+endif()
diff --git a/Tests/RunCMake/CPack/7Z/Helpers.cmake b/Tests/RunCMake/CPack/7Z/Helpers.cmake
new file mode 100644
index 0000000..f256a42
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "7z")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/7Z/Prerequirements.cmake b/Tests/RunCMake/CPack/7Z/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+ file(WRITE "${config_file}" "")
+ set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/7Z/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/7Z/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/ArchiveCommon/common_helpers.cmake b/Tests/RunCMake/CPack/ArchiveCommon/common_helpers.cmake
new file mode 100644
index 0000000..948c6ab
--- /dev/null
+++ b/Tests/RunCMake/CPack/ArchiveCommon/common_helpers.cmake
@@ -0,0 +1,71 @@
+set(ALL_FILES_GLOB "*.${cpack_archive_extension_}")
+
+function(getPackageContent FILE RESULT_VAR)
+ # TODO for some types this only works because libarchive handles it... (not
+ # part of for e.g. gnu tar)
+ execute_process(COMMAND ${CMAKE_COMMAND} -E tar -xtf ${FILE}
+ OUTPUT_VARIABLE package_content_
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ set(${RESULT_VAR} "${package_content_}" PARENT_SCOPE)
+endfunction()
+
+function(getPackageNameGlobexpr NAME COMPONENT VERSION REVISION FILE_NO RESULT_VAR)
+ if(COMPONENT)
+ set(COMPONENT "-${COMPONENT}")
+ endif()
+
+ set(${RESULT_VAR}
+ "${NAME}-${VERSION}-*${COMPONENT}.${cpack_archive_extension_}" PARENT_SCOPE)
+endfunction()
+
+function(getPackageContentList FILE RESULT_VAR)
+ getPackageContent("${FILE}" package_content_)
+
+ string(REPLACE "\n" ";" package_content_ "${package_content_}")
+ foreach(i_ IN LISTS package_content_)
+ string(REGEX REPLACE "/$" "" result_ "${i_}")
+ list(APPEND items_ "${result_}")
+ endforeach()
+
+ set(${RESULT_VAR} "${items_}" PARENT_SCOPE)
+endfunction()
+
+function(toExpectedContentList FILE_NO CONTENT_VAR)
+ findExpectedFile("${FILE_NO}" "file_" "glob_expr_")
+
+ # component and monolithic packages differ for some reason by either having
+ # package filename prefix in path or not
+ if(PACKAGING_TYPE STREQUAL "MONOLITHIC")
+ get_filename_component(prefix_ "${file_}" NAME)
+ # NAME_WE removes everything after the dot and dot is in version so replace instead
+ string(REPLACE ".${cpack_archive_extension_}" "/" prefix_ "${prefix_}")
+ else()
+ unset(prefix_)
+ endif()
+
+ # add install prefix to expected paths
+ if(DEFINED EXPECTED_FILE_${FILE_NO}_PACKAGING_PREFIX)
+ set(EXPECTED_FILE_PACKAGING_PREFIX
+ "${EXPECTED_FILE_${FILE_NO}_PACKAGING_PREFIX}")
+ elseif(NOT DEFINED EXPECTED_FILE_PACKAGING_PREFIX)
+ # default CPack Archive packaging install prefix
+ set(EXPECTED_FILE_PACKAGING_PREFIX "/")
+ endif()
+ set(prepared_ "${EXPECTED_FILE_PACKAGING_PREFIX}")
+ foreach(part_ IN LISTS ${CONTENT_VAR})
+ list(APPEND prepared_ "${EXPECTED_FILE_PACKAGING_PREFIX}${part_}")
+ endforeach()
+
+ unset(filtered_)
+ foreach(part_ IN LISTS prepared_)
+ string(REGEX REPLACE "^/" "" part_ "${part_}")
+
+ if(part_)
+ list(APPEND filtered_ "${prefix_}${part_}")
+ endif()
+ endforeach()
+
+ set(${CONTENT_VAR} "${filtered_}" PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/CMakeLists.txt b/Tests/RunCMake/CPack/CMakeLists.txt
new file mode 100644
index 0000000..1b3dbb2
--- /dev/null
+++ b/Tests/RunCMake/CPack/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+
+set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "")
+
+project(${RunCMake_TEST} CXX)
+
+if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${GENERATOR_TYPE}/packaging_${PACKAGING_TYPE}_default.cmake")
+ include(${GENERATOR_TYPE}/packaging_${PACKAGING_TYPE}_default.cmake)
+endif()
+
+# set default test name (can be overwritten in test.cmake or specifics.cmake)
+string(TOLOWER "${RunCMake_TEST_FILE_PREFIX}" CPACK_PACKAGE_NAME)
+
+include(tests/${RunCMake_TEST_FILE_PREFIX}/test.cmake)
+
+set(CPACK_GENERATOR "${GENERATOR_TYPE}")
+include(CPack)
+
+if(COMMAND run_after_include_cpack)
+ run_after_include_cpack()
+endif()
diff --git a/Tests/RunCMake/CPack/CPackTestHelpers.cmake b/Tests/RunCMake/CPack/CPackTestHelpers.cmake
new file mode 100644
index 0000000..3ec4c69
--- /dev/null
+++ b/Tests/RunCMake/CPack/CPackTestHelpers.cmake
@@ -0,0 +1,157 @@
+cmake_policy(SET CMP0057 NEW)
+
+function(run_cpack_test_common_ TEST_NAME types build SUBTEST_SUFFIX source PACKAGING_TYPE package_target)
+ if(TEST_TYPE IN_LIST types)
+ string(REGEX MATCH "^[^.]*" GENERATOR_TYPE "${TEST_TYPE}")
+ set(RunCMake_TEST_NO_CLEAN TRUE)
+ if(package_target)
+ set(full_test_name_ "${TEST_NAME}-package-target")
+ else()
+ set(full_test_name_ "${TEST_NAME}")
+ endif()
+ set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${full_test_name_}-build")
+
+ if(SUBTEST_SUFFIX)
+ set(RunCMake_TEST_BINARY_DIR "${RunCMake_TEST_BINARY_DIR}-${SUBTEST_SUFFIX}-subtest")
+ set(full_test_name_ "${full_test_name_}-${SUBTEST_SUFFIX}-subtest")
+ endif()
+
+ string(APPEND full_test_name_ "-${PACKAGING_TYPE}-type")
+
+ # TODO this should be executed only once per ctest run (not per generator)
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ # Set permissions to those expected by the test
+ file(CHMOD "${RunCMake_TEST_BINARY_DIR}"
+ PERMISSIONS
+ OWNER_READ OWNER_WRITE OWNER_EXECUTE
+ GROUP_READ GROUP_EXECUTE
+ WORLD_READ WORLD_EXECUTE)
+
+ if(EXISTS "${RunCMake_SOURCE_DIR}/tests/${TEST_NAME}/${GENERATOR_TYPE}-Prerequirements.cmake")
+ include("${RunCMake_SOURCE_DIR}/tests/${TEST_NAME}/${GENERATOR_TYPE}-Prerequirements.cmake")
+
+ set(FOUND_PREREQUIREMENTS false)
+ get_test_prerequirements("FOUND_PREREQUIREMENTS" "${config_file}")
+
+ # skip the test if prerequirements are not met
+ if(NOT FOUND_PREREQUIREMENTS)
+ message(STATUS "${TEST_NAME} - SKIPPED")
+ return()
+ endif()
+ endif()
+
+ # execute cmake
+ set(RunCMake_TEST_OPTIONS "-DGENERATOR_TYPE=${GENERATOR_TYPE}"
+ "-DRunCMake_TEST_FILE_PREFIX=${TEST_NAME}"
+ "-DRunCMake_SUBTEST_SUFFIX=${SUBTEST_SUFFIX}"
+ "-DPACKAGING_TYPE=${PACKAGING_TYPE}")
+
+ foreach(o out err)
+ if(SUBTEST_SUFFIX AND EXISTS ${RunCMake_SOURCE_DIR}/tests/${TEST_NAME}/configure-${PACKAGING_TYPE}-${SUBTEST_SUFFIX}-std${o}.txt)
+ set(RunCMake-std${o}-file "tests/${TEST_NAME}/configure-${PACKAGING_TYPE}-${SUBTEST_SUFFIX}-std${o}.txt")
+ elseif(SUBTEST_SUFFIX AND EXISTS ${RunCMake_SOURCE_DIR}/tests/${TEST_NAME}/configure-${SUBTEST_SUFFIX}-std${o}.txt)
+ set(RunCMake-std${o}-file "tests/${TEST_NAME}/configure-${SUBTEST_SUFFIX}-std${o}.txt")
+ elseif(EXISTS ${RunCMake_SOURCE_DIR}/tests/${TEST_NAME}/configure-${PACKAGING_TYPE}-std${o}.txt)
+ set(RunCMake-std${o}-file "tests/${TEST_NAME}/configure-${PACKAGING_TYPE}-std${o}.txt")
+ elseif(EXISTS ${RunCMake_SOURCE_DIR}/tests/${TEST_NAME}/configure-std${o}.txt)
+ set(RunCMake-std${o}-file "tests/${TEST_NAME}/configure-std${o}.txt")
+ else()
+ unset(RunCMake-std${o}-file)
+ endif()
+ endforeach()
+
+ run_cmake(${full_test_name_})
+
+ # execute optional build step
+ if(build)
+ unset(RunCMake-stdout-file)
+ unset(RunCMake-stderr-file)
+ run_cmake_command(${full_test_name_}-Build "${CMAKE_COMMAND}" --build "${RunCMake_TEST_BINARY_DIR}")
+ endif()
+
+ if(source)
+ set(pack_params_ -G ${GENERATOR_TYPE} --config ./CPackSourceConfig.cmake)
+ FILE(APPEND ${RunCMake_TEST_BINARY_DIR}/CPackSourceConfig.cmake
+ "\nset(CPACK_RPM_SOURCE_PKG_BUILD_PARAMS \"-DRunCMake_TEST:STRING=${full_test_name_} -DRunCMake_TEST_FILE_PREFIX:STRING=${TEST_NAME} -DGENERATOR_TYPE:STRING=${GENERATOR_TYPE}\")")
+ else()
+ unset(pack_params_)
+ endif()
+
+ if(package_target)
+ set(cpack_command_ ${CMAKE_COMMAND} --build "${RunCMake_TEST_BINARY_DIR}" --target package)
+ else()
+ set(cpack_command_ ${CMAKE_CPACK_COMMAND} ${pack_params_} -C Debug)
+ endif()
+
+ # execute cpack
+ set(SETENV)
+ if(ENVIRONMENT)
+ set(SETENV ${CMAKE_COMMAND} -E env "${ENVIRONMENT}")
+ endif()
+ execute_process(
+ COMMAND ${SETENV} ${cpack_command_}
+ WORKING_DIRECTORY "${RunCMake_TEST_BINARY_DIR}"
+ RESULT_VARIABLE "result_"
+ OUTPUT_FILE "${RunCMake_TEST_BINARY_DIR}/test_output.txt"
+ ERROR_FILE "${RunCMake_TEST_BINARY_DIR}/test_error.txt"
+ )
+
+ foreach(o out err)
+ if(SUBTEST_SUFFIX AND EXISTS ${RunCMake_SOURCE_DIR}/tests/${TEST_NAME}/${GENERATOR_TYPE}-${PACKAGING_TYPE}-${SUBTEST_SUFFIX}-std${o}.txt)
+ set(RunCMake-std${o}-file "tests/${TEST_NAME}/${GENERATOR_TYPE}-${PACKAGING_TYPE}-${SUBTEST_SUFFIX}-std${o}.txt")
+ elseif(EXISTS ${RunCMake_SOURCE_DIR}/tests/${TEST_NAME}/${GENERATOR_TYPE}-${PACKAGING_TYPE}-std${o}.txt)
+ set(RunCMake-std${o}-file "tests/${TEST_NAME}/${GENERATOR_TYPE}-${PACKAGING_TYPE}-std${o}.txt")
+ elseif(SUBTEST_SUFFIX AND EXISTS ${RunCMake_SOURCE_DIR}/tests/${TEST_NAME}/${GENERATOR_TYPE}-${SUBTEST_SUFFIX}-std${o}.txt)
+ set(RunCMake-std${o}-file "tests/${TEST_NAME}/${GENERATOR_TYPE}-${SUBTEST_SUFFIX}-std${o}.txt")
+ elseif(EXISTS ${RunCMake_SOURCE_DIR}/tests/${TEST_NAME}/${GENERATOR_TYPE}-std${o}.txt)
+ set(RunCMake-std${o}-file "tests/${TEST_NAME}/${GENERATOR_TYPE}-std${o}.txt")
+ elseif(SUBTEST_SUFFIX AND EXISTS ${RunCMake_SOURCE_DIR}/tests/${TEST_NAME}/${SUBTEST_SUFFIX}-std${o}.txt)
+ set(RunCMake-std${o}-file "tests/${TEST_NAME}/${SUBTEST_SUFFIX}-std${o}.txt")
+ elseif(EXISTS ${RunCMake_SOURCE_DIR}/${GENERATOR_TYPE}/default_expected_std${o}.txt)
+ set(RunCMake-std${o}-file "${GENERATOR_TYPE}/default_expected_std${o}.txt")
+ else()
+ unset(RunCMake-std${o}-file)
+ endif()
+ endforeach()
+
+ # verify result
+ run_cmake_command(
+ ${GENERATOR_TYPE}/${full_test_name_}
+ "${CMAKE_COMMAND}"
+ -DRunCMake_TEST=${full_test_name_}
+ -DRunCMake_TEST_FILE_PREFIX=${TEST_NAME}
+ -DRunCMake_SUBTEST_SUFFIX=${SUBTEST_SUFFIX}
+ -DGENERATOR_TYPE=${GENERATOR_TYPE}
+ -DPACKAGING_TYPE=${PACKAGING_TYPE}
+ "-Dsrc_dir=${RunCMake_SOURCE_DIR}"
+ "-Dbin_dir=${RunCMake_TEST_BINARY_DIR}"
+ "-Dconfig_file=${config_file}"
+ -P "${RunCMake_SOURCE_DIR}/VerifyResult.cmake"
+ )
+ endif()
+endfunction()
+
+function(run_cpack_test TEST_NAME types build PACKAGING_TYPES)
+ foreach(packaging_type_ IN LISTS PACKAGING_TYPES)
+ run_cpack_test_common_("${TEST_NAME}" "${types}" "${build}" "" false "${packaging_type_}" false)
+ endforeach()
+endfunction()
+
+function(run_cpack_test_package_target TEST_NAME types build PACKAGING_TYPES)
+ foreach(packaging_type_ IN LISTS PACKAGING_TYPES)
+ run_cpack_test_common_("${TEST_NAME}" "${types}" "${build}" "" false "${packaging_type_}" true)
+ endforeach()
+endfunction()
+
+function(run_cpack_test_subtests TEST_NAME SUBTEST_SUFFIXES types build PACKAGING_TYPES)
+ foreach(suffix_ IN LISTS SUBTEST_SUFFIXES)
+ foreach(packaging_type_ IN LISTS PACKAGING_TYPES)
+ run_cpack_test_common_("${TEST_NAME}" "${types}" "${build}" "${suffix_}" false "${packaging_type_}" false)
+ endforeach()
+ endforeach()
+endfunction()
+
+function(run_cpack_source_test TEST_NAME types)
+ run_cpack_test_common_("${TEST_NAME}" "${types}" false "" true "" false)
+endfunction()
diff --git a/Tests/RunCMake/CPack/DEB/Helpers.cmake b/Tests/RunCMake/CPack/DEB/Helpers.cmake
new file mode 100644
index 0000000..9b98ed4
--- /dev/null
+++ b/Tests/RunCMake/CPack/DEB/Helpers.cmake
@@ -0,0 +1,176 @@
+set(ALL_FILES_GLOB "*.deb" "*.ddeb")
+
+function(getPackageContent FILE RESULT_VAR)
+ execute_process(COMMAND ${CMAKE_COMMAND} -E env TZ=Etc/UTC ${DPKG_EXECUTABLE} -c "${FILE}"
+ OUTPUT_VARIABLE package_content_
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ set(${RESULT_VAR} "${package_content_}" PARENT_SCOPE)
+endfunction()
+
+function(getPackageNameGlobexpr NAME COMPONENT VERSION REVISION FILE_NO RESULT_VAR)
+ if(COMPONENT)
+ set(COMPONENT "-${COMPONENT}")
+ endif()
+
+ if(DEFINED EXPECTED_FILE_${FILE_NO}_FILENAME_GENERATOR_SPECIFIC_FORMAT)
+ set(GENERATOR_SPECIFIC_FORMAT "${EXPECTED_FILE_${FILE_NO}_FILENAME_GENERATOR_SPECIFIC_FORMAT}")
+ elseif(DEFINED EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT)
+ set(GENERATOR_SPECIFIC_FORMAT "${EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT}")
+ else()
+ set(GENERATOR_SPECIFIC_FORMAT FALSE)
+ endif()
+
+ if(GENERATOR_SPECIFIC_FORMAT)
+ set(${RESULT_VAR} "${NAME}${COMPONENT}_${VERSION}_*.deb" PARENT_SCOPE)
+ else()
+ set(${RESULT_VAR} "${NAME}-${VERSION}-*${COMPONENT}.deb" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(getPackageContentList FILE RESULT_VAR)
+ execute_process(COMMAND ${DPKG_EXECUTABLE} -c "${FILE}"
+ OUTPUT_VARIABLE package_content_
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ unset(items_)
+ string(REPLACE "\n" ";" package_content_ "${package_content_}")
+ foreach(i_ IN LISTS package_content_)
+ string(REGEX REPLACE "^.* \.(/[^$]*)$" "\\1" result_ "${i_}")
+ string(REGEX REPLACE "/$" "" result_ "${result_}")
+ list(APPEND items_ "${result_}")
+ endforeach()
+
+ set(${RESULT_VAR} "${items_}" PARENT_SCOPE)
+endfunction()
+
+function(toExpectedContentList FILE_NO CONTENT_VAR)
+ # add install prefix to expected paths
+ if(DEFINED EXPECTED_FILE_${FILE_NO}_PACKAGING_PREFIX)
+ set(EXPECTED_FILE_PACKAGING_PREFIX
+ "${EXPECTED_FILE_${FILE_NO}_PACKAGING_PREFIX}")
+ elseif(NOT DEFINED EXPECTED_FILE_PACKAGING_PREFIX)
+ # default CPackDeb packaging install prefix
+ set(EXPECTED_FILE_PACKAGING_PREFIX "/usr")
+ endif()
+ set(prepared_ "${EXPECTED_FILE_PACKAGING_PREFIX}")
+ foreach(part_ IN LISTS ${CONTENT_VAR})
+ list(APPEND prepared_ "${EXPECTED_FILE_PACKAGING_PREFIX}${part_}")
+ endforeach()
+
+ set(${CONTENT_VAR} "${prepared_}" PARENT_SCOPE)
+endfunction()
+
+function(getMissingShlibsErrorExtra FILE RESULT_VAR)
+ execute_process(COMMAND ${DPKG_EXECUTABLE} -x "${FILE}" data_${PREFIX}
+ ERROR_VARIABLE err_)
+
+ if(err_)
+ set(error_extra " Extra: Could not unpack package content: '${err}'")
+ else()
+ cmake_policy(PUSH)
+ # Tell file(GLOB_RECURSE) not to follow directory symlinks
+ # even if the project does not set this policy to NEW.
+ cmake_policy(SET CMP0009 NEW)
+ file(GLOB_RECURSE FILE_PATHS_ LIST_DIRECTORIES false "${CMAKE_CURRENT_BINARY_DIR}/data_${PREFIX}/*")
+ cmake_policy(POP)
+
+ # get file info so that we can determine if file is executable or not
+ foreach(FILE_ IN LISTS FILE_PATHS_)
+ execute_process(COMMAND file "${FILE_}"
+ WORKING_DIRECTORY "${WDIR}"
+ OUTPUT_VARIABLE INSTALL_FILE_
+ ERROR_VARIABLE err_)
+
+ if(NOT err_)
+ list(APPEND deb_install_files "${INSTALL_FILE_}")
+ else()
+ list(APPEND deb_install_files_errors "'${FILE_}': '${err_}'\n")
+ endif()
+ endforeach()
+
+ set(error_extra " Extra: install files '${deb_install_files}'")
+
+ if(deb_install_files_errors)
+ string(APPEND error_extra "; errors \"${deb_install_files_errors}\"")
+ endif()
+
+ if(READELF_EXECUTABLE)
+ string(APPEND error_extra "; readelf \"\n")
+
+ # Only dynamically linked ELF files are included
+ # Extract only file name infront of ":"
+ foreach(_FILE IN LISTS deb_install_files)
+ if(_FILE MATCHES "ELF.*shared object")
+ string(REGEX MATCH "(^.*):" _FILE_NAME "${_FILE}")
+
+ execute_process(COMMAND ${READELF_EXECUTABLE} -d "${CMAKE_MATCH_1}"
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE err_
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ string(APPEND error_extra " name '${CMAKE_MATCH_1}'\n result '${result}'\n output '${output}'\n error '${err_}'\n")
+ endif()
+ endforeach()
+
+ string(APPEND error_extra "\"")
+ else()
+ string(APPEND error_extra "; error readelf missing")
+ endif()
+ endif()
+
+ set(${RESULT_VAR} "${error_extra}" PARENT_SCOPE)
+endfunction()
+
+function(verifyDebControl FILE PREFIX VERIFY_FILES)
+ execute_process(COMMAND ${DPKG_EXECUTABLE} --control "${FILE}" control_${PREFIX}
+ ERROR_VARIABLE err_)
+
+ if(err_)
+ message(FATAL_ERROR "Debian control verification failed for file: "
+ "'${FILE}'; error output: '${err_}'")
+ endif()
+
+ foreach(FILE_ IN LISTS VERIFY_FILES)
+ if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/control_${PREFIX}/${FILE_}")
+ if(FILE_ STREQUAL "shlibs")
+ getMissingShlibsErrorExtra("${FILE}" error_extra)
+ endif()
+
+ message(FATAL_ERROR "Expected Debian control file does not exist: '${FILE_}'${error_extra}")
+ endif()
+
+ file(READ "${CMAKE_CURRENT_BINARY_DIR}/control_${PREFIX}/${FILE_}" content_)
+ if(NOT content_ MATCHES "${${PREFIX}_${FILE_}}")
+ message(FATAL_ERROR "Unexpected content in for '${PREFIX}_${FILE_}'!"
+ " Content: '${content_}'")
+ endif()
+
+ execute_process(COMMAND ls -l "${CMAKE_CURRENT_BINARY_DIR}/control_${PREFIX}/${FILE_}"
+ OUTPUT_VARIABLE package_permissions_
+ ERROR_VARIABLE package_permissions_error_
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(NOT package_permissions_error_)
+ if(NOT package_permissions_ MATCHES "${${PREFIX}_${FILE_}_permissions_regex}")
+ message(FATAL_ERROR "Unexpected file permissions for ${PREFIX}_${FILE_}: '${package_permissions_}'!")
+ endif()
+ else()
+ message(FATAL_ERROR "Listing file permissions failed (${package_permissions_error_})!")
+ endif()
+ endforeach()
+endfunction()
+
+function(getPackageInfo FILE RESULT_VAR)
+ execute_process(COMMAND ${DPKG_EXECUTABLE} -I ${FILE}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE package_info_
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ set(${RESULT_VAR} "${package_info_}" PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/DEB/Prerequirements.cmake b/Tests/RunCMake/CPack/DEB/Prerequirements.cmake
new file mode 100644
index 0000000..60d02e7
--- /dev/null
+++ b/Tests/RunCMake/CPack/DEB/Prerequirements.cmake
@@ -0,0 +1,22 @@
+function(get_test_prerequirements found_var config_file)
+ find_program(DPKG_EXECUTABLE dpkg)
+
+ if(DPKG_EXECUTABLE)
+ file(WRITE "${config_file}" "set(DPKG_EXECUTABLE \"${DPKG_EXECUTABLE}\")")
+ set(${found_var} true PARENT_SCOPE)
+ endif()
+
+ # optional tool for some tests
+ find_program(FAKEROOT_EXECUTABLE fakeroot)
+ if(FAKEROOT_EXECUTABLE)
+ file(APPEND "${config_file}"
+ "\nset(FAKEROOT_EXECUTABLE \"${FAKEROOT_EXECUTABLE}\")")
+ endif()
+
+ # optional tool for some tests
+ find_program(READELF_EXECUTABLE NAMES readelf)
+ if(READELF_EXECUTABLE)
+ file(APPEND "${config_file}"
+ "\nset(READELF_EXECUTABLE \"${READELF_EXECUTABLE}\")")
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/DEB/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/DEB/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..4219b0c
--- /dev/null
+++ b/Tests/RunCMake/CPack/DEB/packaging_COMPONENT_default.cmake
@@ -0,0 +1,2 @@
+set(CPACK_DEB_COMPONENT_INSTALL "ON")
+set(CPACK_PACKAGE_CONTACT "someone")
diff --git a/Tests/RunCMake/CPack/DEB/packaging_MONOLITHIC_default.cmake b/Tests/RunCMake/CPack/DEB/packaging_MONOLITHIC_default.cmake
new file mode 100644
index 0000000..8821ab9
--- /dev/null
+++ b/Tests/RunCMake/CPack/DEB/packaging_MONOLITHIC_default.cmake
@@ -0,0 +1 @@
+set(CPACK_PACKAGE_CONTACT "someone")
diff --git a/Tests/RunCMake/CPack/DragNDrop/Accept.txt b/Tests/RunCMake/CPack/DragNDrop/Accept.txt
new file mode 100644
index 0000000..975fbec
--- /dev/null
+++ b/Tests/RunCMake/CPack/DragNDrop/Accept.txt
@@ -0,0 +1 @@
+y
diff --git a/Tests/RunCMake/CPack/DragNDrop/Helpers.cmake b/Tests/RunCMake/CPack/DragNDrop/Helpers.cmake
new file mode 100644
index 0000000..896fba7
--- /dev/null
+++ b/Tests/RunCMake/CPack/DragNDrop/Helpers.cmake
@@ -0,0 +1,55 @@
+set(ALL_FILES_GLOB "*.dmg")
+
+function(getPackageContent FILE RESULT_VAR)
+ get_filename_component(path_ "${FILE}" DIRECTORY)
+ file(REMOVE_RECURSE "${path_}/content")
+ file(MAKE_DIRECTORY "${path_}/content")
+ execute_process(COMMAND ${HDIUTIL_EXECUTABLE} attach -mountroot ${path_}/content -nobrowse ${FILE}
+ INPUT_FILE "${src_dir}/DragNDrop/Accept.txt"
+ RESULT_VARIABLE attach_result_
+ ERROR_VARIABLE attach_error_
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(attach_result_)
+ message(FATAL_ERROR "Failed to attach DMG: '${attach_result_}';"
+ " '${attach_error_}'.")
+ endif()
+
+ file(GLOB_RECURSE package_content_ LIST_DIRECTORIES true RELATIVE
+ "${path_}/content" "${path_}/content/*")
+ # Some versions of macOS have .Trashes, others do not.
+ list(FILTER package_content_ EXCLUDE REGEX "/.Trashes$")
+ set(${RESULT_VAR} "${package_content_}" PARENT_SCOPE)
+
+ execute_process(COMMAND ${HDIUTIL_EXECUTABLE} detach ${path_}/content/volume-name
+ RESULT_VARIABLE detach_result_
+ ERROR_VARIABLE detach_error_
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(detach_result_)
+ message(FATAL_ERROR "Failed to detach DMG: '${detach_result_}';"
+ " '${detach_error_}'.")
+ endif()
+endfunction()
+
+function(getPackageNameGlobexpr NAME COMPONENT VERSION REVISION FILE_NO RESULT_VAR)
+ if(COMPONENT)
+ set(COMPONENT "-${COMPONENT}")
+ endif()
+
+ set(${RESULT_VAR} "${NAME}-${VERSION}-Darwin${COMPONENT}.dmg" PARENT_SCOPE)
+endfunction()
+
+function(getPackageContentList FILE RESULT_VAR)
+ getPackageContent("${FILE}" package_content_)
+
+ set(${RESULT_VAR} "${package_content_}" PARENT_SCOPE)
+endfunction()
+
+function(toExpectedContentList FILE_NO CONTENT_VAR)
+ set(prefix_ "volume-name")
+ list(TRANSFORM ${CONTENT_VAR} PREPEND "${prefix_}" OUTPUT_VARIABLE prepared_)
+ list(APPEND prepared_ "${prefix_}")
+
+ set(${CONTENT_VAR} "${prepared_}" PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/DragNDrop/Prerequirements.cmake b/Tests/RunCMake/CPack/DragNDrop/Prerequirements.cmake
new file mode 100644
index 0000000..f0aaf2c
--- /dev/null
+++ b/Tests/RunCMake/CPack/DragNDrop/Prerequirements.cmake
@@ -0,0 +1,8 @@
+function(get_test_prerequirements found_var config_file)
+ find_program(HDIUTIL_EXECUTABLE hdiutil)
+
+ if(HDIUTIL_EXECUTABLE)
+ file(WRITE "${config_file}" "set(HDIUTIL_EXECUTABLE \"${HDIUTIL_EXECUTABLE}\")")
+ set(${found_var} true PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/DragNDrop/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/DragNDrop/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..aa6c8ff
--- /dev/null
+++ b/Tests/RunCMake/CPack/DragNDrop/packaging_COMPONENT_default.cmake
@@ -0,0 +1,3 @@
+set(CPACK_COMPONENTS_GROUPING "IGNORE")
+set(CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK ON)
+set(CPACK_DMG_VOLUME_NAME "volume-name")
diff --git a/Tests/RunCMake/CPack/DragNDrop/packaging_MONOLITHIC_default.cmake b/Tests/RunCMake/CPack/DragNDrop/packaging_MONOLITHIC_default.cmake
new file mode 100644
index 0000000..ca27890
--- /dev/null
+++ b/Tests/RunCMake/CPack/DragNDrop/packaging_MONOLITHIC_default.cmake
@@ -0,0 +1,2 @@
+set(CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK ON)
+set(CPACK_DMG_VOLUME_NAME "volume-name")
diff --git a/Tests/RunCMake/CPack/External/Helpers.cmake b/Tests/RunCMake/CPack/External/Helpers.cmake
new file mode 100644
index 0000000..2c67e06
--- /dev/null
+++ b/Tests/RunCMake/CPack/External/Helpers.cmake
@@ -0,0 +1,31 @@
+function(getPackageNameGlobexpr NAME COMPONENT VERSION REVISION FILE_NO RESULT_VAR)
+ set(${RESULT_VAR} "${NAME}-${VERSION}-*.json" PARENT_SCOPE)
+endfunction()
+
+function(getPackageContentList FILE RESULT_VAR)
+ set("${RESULT_VAR}" "" PARENT_SCOPE)
+endfunction()
+
+function(toExpectedContentList FILE_NO CONTENT_VAR)
+ set("${CONTENT_VAR}" "" PARENT_SCOPE)
+endfunction()
+
+set(ALL_FILES_GLOB "*.json")
+
+function(check_ext_json EXPECTED_FILE ACTUAL_FILE)
+ file(READ "${EXPECTED_FILE}" _expected_regex)
+ file(READ "${ACTUAL_FILE}" _actual_contents)
+
+ string(REGEX REPLACE "\n+$" "" _expected_regex "${_expected_regex}")
+ string(REGEX REPLACE "\n+$" "" _actual_contents "${_actual_contents}")
+
+ if(NOT "${_actual_contents}" MATCHES "${_expected_regex}")
+ message(FATAL_ERROR
+ "Output JSON does not match expected regex.\n"
+ "Expected regex:\n"
+ "${_expected_regex}\n"
+ "Actual output:\n"
+ "${_actual_contents}\n"
+ )
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/External/Prerequirements.cmake b/Tests/RunCMake/CPack/External/Prerequirements.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CPack/External/Prerequirements.cmake
diff --git a/Tests/RunCMake/CPack/README.txt b/Tests/RunCMake/CPack/README.txt
new file mode 100644
index 0000000..2165125
--- /dev/null
+++ b/Tests/RunCMake/CPack/README.txt
@@ -0,0 +1,256 @@
+RunCMake.CPack is a test module that is intended for testing of package
+generators that can be validated from command line.
+
+-------------
+Adding a test
+-------------
+
+CPack test root directory: 'Tests/RunCMake/CPack/tests'.
+
+All phases are executed separately for each generator that is bound to a test.
+Tests for each generator are subtests of test 'RunCMake.CPack_<generator_name>'.
+
+Each test must also be added to 'RunCMakeTest.cmake' script located in CPack
+test root directory.
+
+Line that adds a test is:
+run_cpack_test(<test_name> "<generator_name_list>" <compile_stage>
+ "<packaging_type_list>")
+
+<generator_name_list> may be one generator e.g. "RPM" or multiple e.g. "RPM;DEB"
+and will be run for all listed generators. In test and verification scripts
+current generator can be accessed through GENERATOR_TYPE variable.
+
+<compile_stage> is a boolean variable that enables or disables compile stage -
+most tests don't require compilation as a non binary file can be used for
+package content but sometimes an executable or a library has to be created
+before the packaging stage.
+
+<packaging_type_list> can be a list of one or more packaging types: MONOLITHIC,
+COMPONENT or GROUP - each type sets per generator default variables which can
+be overwritten in the test if needed
+(see <generator_type>/packaging_<packaging_type>_default.cmake for the variables
+that are set by default for each packaging type).
+Alternatively CUSTOM value can be set which means that default values will not
+be set and that values will be set manually in the test itself.
+
+Alternatively a test with subtests can be added:
+run_cpack_test_subtests(<test_name> "<subtests_list>" "<generator_name_list>"
+ <compile_stage> "<packaging_type_list>")
+
+<subtests_list> is the only new parameter and it is a list of names that will
+be used for subtests. In test and verification scripts subtest name can be
+accessed through RunCMake_SUBTEST_SUFFIX variable.
+
+Also source package tests can be added:
+run_cpack_source_test(<test_name> "<generator_name_list>" true)
+
+Test consists of
+- test prerequirements phase (optional)
+- CMake execution phase
+- build phase (optional and not available for source package tests)
+- CPack execution phase
+- verification of generated files
+
+The phases are executed once per specified generator, packaging type and subtest
+combinatiion.
+
+test prerequirements phase (optional):
+--------------------------------------
+
+In some cases individual tests for certain generator need additional
+prerequirements met.
+
+In such cases '<test_name>/<generator_name>-Prerequirements.cmake' file
+containing 'function(get_test_prerequirements found_var config_file)' should be
+created. Function should return true in found_var if all prerequirements are
+met. config_file variable contains the location of config file generated by the
+generator so that this function can check if prerequired variable is set in the
+file.
+NOTE: All required programs should be searched for in generator prerequirements
+function and only checked for the variable in configure file in per test
+function.
+
+If prerequirements are not met test will be skipped outputting
+'<test_name> - SKIPPED' string. Note that this doesn't fail the entire test
+group.
+
+TODO: skipped tests should provide expected error string so test should fail
+ if error string is not found in the output of run test (this would add
+ 'EXPECTED FAIL' string on success and 'ERROR' on failure).
+
+CMake execution phase:
+----------------------
+
+To add a new CPack test we first create a '<test_name>/test.cmake' script that
+contains CMake commands that should be used as a preparation script for
+generation of different types of packages. This script is placed into CPack
+test root directory.
+
+If test will be used for multiple generators but some of them require some
+generator specific commands then those commands should be added to 'test.cmake'
+script wrapped with 'if(GENERATOR_TYPE STREQUAL <name_of_the_generator>)'.
+
+NOTE: In some cases (for example when testing CPackComponent.cmake functions)
+the test has to run some functions after CPack.cmake is included. In such cases
+a function run_after_include_cpack can be declared in test.cmake file and that
+function will run after the inclusion of CPack.cmake.
+
+NOTE: During CMake configure stage developer warnings may be expected. In such
+cases an expected output regular expression can be provided by creating
+'<test_name>/configure-stdout.txt' and/or '<test_name>/configure-stderr.txt'
+file. There are also more specialized versions of the file available:
+- configure-${PACKAGING_TYPE}-${SUBTEST_SUFFIX}-std${o}.txt
+- configure-${SUBTEST_SUFFIX}-std${o}.txt
+- configure-${PACKAGING_TYPE}-std${o}.txt
+
+build phase (optional and not available for source package tests)
+-----------------------------------------------------------------
+
+This phase only runs make command.
+
+NOTE: By default all tests have CMAKE_BUILD_TYPE variable set to Debug.
+
+CPack execution phase:
+----------------------
+
+Only executes CPack for content that was generated during CMake execution
+phase.
+
+NOTE: By default CPACK_PACKAGE_NAME variable is set to lower case test name.
+
+Verification of generated files:
+--------------------------------
+
+Verification of generated files consists of two phases
+- mandatory verification phase
+- optional verification phase
+
+Mandatory verification phase checks that expected files were generated and
+contain expected files.
+Mandatory verification phase also checks that no other unexpected package files
+were generated (this is executed even if EXPECTED_FILES_COUNT contains 0 in
+order to verify that no files were generated).
+CMake script '<test_name>/ExpectedFiles.cmake' is required by
+this step and must contain
+- EXPECTED_FILES_COUNT variable that contains the number of expected files that
+ will be generated (0 or more)
+
+- EXPECTED_FILE_<file_number_starting_with_1> that contains globing expression
+ that uniquely defines expected file name (will be used to find expected file)
+ and should be present once for each expected file.
+ NOTE: This variable should be used only as last resort as it sets generator
+ specific globbing expression. Each generator can recreate file name from
+ parts that are already populated by default but can always be
+ overwritten if needed:
+ - EXPECTED_FILE_<file_number_starting_with_1>_NAME is the name component of
+ the file (by default it is set to package name that is same as test name
+ in lowercase)
+ - EXPECTED_FILE_<file_number_starting_with_1>_VERSION is the version of the
+ package (by default it is set to '0.1.1')
+ - EXPECTED_FILE_<file_number_starting_with_1>_REVISION is the revision of the
+ package (by default it is set to '1')
+
+- EXPECTED_FILE_CONTENT_<file_number_starting_with_1> that contains regular
+ expression of files that should be present in generated file and should be
+ present once for each expected file
+ NOTE: This variable should be used only as last resort as it sets generator
+ specific regular expression.
+ EXPECTED_FILE_CONTENT_<file_number_starting_with_1>_LIST should be
+ preferred as it requires a list of expected files and directories that
+ is later changed automatically depending on the generator so expected
+ package content can be written only once per test for all generators.
+
+- EXPECTED_FILE_PACKAGING_PREFIX and
+ EXPECTED_FILE_<file_number_starting_with_1>_PACKAGING_PREFIX variables can be
+ set to explicitly specified CPACK_PACKAGING_PREFIX value. By default this
+ variable does not need to be set as it is implicitly set to package generator
+ specific prefix.
+
+Optional verification phase is generator specific and is optionally executed.
+This phase is executed if '<test_name>/VerifyResult.cmake' script exists.
+
+VerifyResult.cmake script also automatically prints out standard output and
+standard error from CPack execution phase that is compared with
+'<test_name>/<generator_name>-stdout.txt' regular expression and
+'<test_name>/<generator_name>-stderr.txt' regular expresson respectively.
+NOTE: For subtests generator name can also be suffixed with subtest name and/or
+ packaging type (MONOLITHIC, COMPONENT, GROUP) and in such cases the
+ preferences of which file will be used are as follows:
+ - generator name + packaging type + subtest name
+ - generator name + packaging type
+ - generator name + subtest name
+ - generator name
+ - subtest name
+ - default generator
+ File name format: '<generator_name>-<packaging_type>-<subtest_name>-std<type>.txt'
+ where <type> can either be 'out' or 'err'.
+ File name format: '<generator_name>-<packaging_type>-std<type>.txt'
+ where <type> can either be 'out' or 'err'.
+ File name format: '<generator_name>-<subtest_name>-std<type>.txt' where
+ <type> can either be 'out' or 'err'.
+NOTE: If none of the comparison files are present then the default generator
+ file is used if present.
+
+----------------------
+Adding a new generator
+----------------------
+
+To add a new generator we must
+- add new generator directory (e.g. RPM for RPM generator) to CPack test root
+ directory that contains 'Helpers.cmake' script.
+ - In this script some functions must exist:
+ - getPackageContent: This function should list files that are contained in
+ a package.
+ Function parameters:
+ + FILE variable that will contain path to file for which the content
+ should be listed
+ + RESULT_VAR that will tell the function which variable in parent scope
+ should contain the result (list of files inside package file)
+ - getPackageNameGlobexpr: This function should generate package name
+ globbing expression.
+ Function parameters:
+ + NAME that will contain the expected package name
+ + COMPONENT that will contain the expected package component
+ + VERSION that will contain the expected package version
+ + REVISION that will contain the expected package revision number
+ + FILE_NO that will contain the file number for which the globbing
+ expression is generated
+ + RESULT_VAR that will tell the function which variable in parent scope
+ should contain the result (file name globbing expression)
+ - getPackageContentList: This function should return a list of files and
+ directories that are in the provided package.
+ Function parameters:
+ + FILE that will contain the package file for which the package content
+ should be returned.
+ + RESULT_VAR that will tell the function which variable in parent scope
+ should contain the result (list of package content)
+ - toExpectedContentList: This function should convert an expected package
+ content list into one that is expected for the
+ generator (e.g. rpm packages have install/relocate
+ path prefixes which aren't part of the package so
+ those paths have to be removed from the expected
+ content list).
+ Function parameters:
+ + FILE_NO that will contain the file number for which the conversion
+ should be performed
+ + CONTENT_VAR that will contain the input list and is also the variable
+ in parent scope which should contain the result (converted content list)
+- add 'Prerequirements.cmake' script to generator directory. In this script a
+ function named 'get_test_prerequirements' must exist. This function should
+ set a variable in parent scope (name of the variable is the first parameter)
+ that tells if prerequirements for test execution are met (certain programs,
+ OS specifics, ...) and create a config file (name of the variable which
+ contains file name and path is provided with the second parameter) that
+ should contain 'set' commands for variables that will later be used in tests
+ (e.g. location of dpkg program for DEB packages)
+- add tests the same way as described above
+- add generator to 'add_RunCMake_test_group' function call that is located in
+ RunCMake CMakeLists.txt file
+- if needed add 'packaging_<packaging_type>_default.cmake' scripts that define
+ default variables that will be set for each packaging type (MONOLITHIC,
+ COMPONENT and GROUP)
+- if needed add 'default_expected_std<type>.txt' files where <type> is either
+ 'out' or 'err' which will contain default expected output of package
+ generation regular expression.
+- add generator to list of other CPack generators in RunCMake/CMakeLists.txt
diff --git a/Tests/RunCMake/CPack/RPM/Helpers.cmake b/Tests/RunCMake/CPack/RPM/Helpers.cmake
new file mode 100644
index 0000000..a29c020
--- /dev/null
+++ b/Tests/RunCMake/CPack/RPM/Helpers.cmake
@@ -0,0 +1,94 @@
+set(ALL_FILES_GLOB "*.rpm")
+
+function(getPackageContent FILE RESULT_VAR)
+ execute_process(COMMAND ${RPM_EXECUTABLE} -pql ${FILE}
+ OUTPUT_VARIABLE package_content_
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ set(${RESULT_VAR} "${package_content_}" PARENT_SCOPE)
+endfunction()
+
+function(getPackageNameGlobexpr NAME COMPONENT VERSION REVISION FILE_NO RESULT_VAR)
+ if(COMPONENT)
+ set(COMPONENT "-${COMPONENT}")
+ endif()
+
+ if(DEFINED EXPECTED_FILE_${FILE_NO}_FILENAME_GENERATOR_SPECIFIC_FORMAT)
+ set(GENERATOR_SPECIFIC_FORMAT "${EXPECTED_FILE_${FILE_NO}_FILENAME_GENERATOR_SPECIFIC_FORMAT}")
+ elseif(DEFINED EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT)
+ set(GENERATOR_SPECIFIC_FORMAT "${EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT}")
+ else()
+ set(GENERATOR_SPECIFIC_FORMAT FALSE)
+ endif()
+
+ if(GENERATOR_SPECIFIC_FORMAT)
+ if(NOT REVISION)
+ set(REVISION "1")
+ endif()
+ set(${RESULT_VAR} "${NAME}${COMPONENT}-${VERSION}-${REVISION}.*.rpm" PARENT_SCOPE)
+ else()
+ set(${RESULT_VAR} "${NAME}-${VERSION}-*${COMPONENT}.rpm" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(getPackageContentList FILE RESULT_VAR)
+ execute_process(COMMAND ${RPM_EXECUTABLE} -pql ${FILE}
+ OUTPUT_VARIABLE package_content_
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ string(REGEX REPLACE "\n" ";" package_content_ "${package_content_}")
+
+ # never versions of rpmbuild (introduced in rpm 4.13.0.1) add build_id links
+ # to packages - tests should ignore them
+ list(FILTER package_content_ EXCLUDE REGEX ".*\.build-id.*")
+
+ set(${RESULT_VAR} "${package_content_}" PARENT_SCOPE)
+endfunction()
+
+function(toExpectedContentList FILE_NO CONTENT_VAR)
+ # add install prefix to expected paths
+ if(DEFINED EXPECTED_FILE_${FILE_NO}_PACKAGING_PREFIX)
+ set(EXPECTED_FILE_PACKAGING_PREFIX
+ "${EXPECTED_FILE_${FILE_NO}_PACKAGING_PREFIX}")
+ elseif(NOT DEFINED EXPECTED_FILE_PACKAGING_PREFIX)
+ # default CPackRPM packaging install prefix
+ set(EXPECTED_FILE_PACKAGING_PREFIX "/usr")
+ endif()
+ set(prepared_ "${EXPECTED_FILE_PACKAGING_PREFIX}")
+ foreach(part_ IN LISTS ${CONTENT_VAR})
+ list(APPEND prepared_ "${EXPECTED_FILE_PACKAGING_PREFIX}${part_}")
+ endforeach()
+
+ # remove paths that are excluded from auto packaging
+ if(NOT DEFINED CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST)
+ set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST
+ /etc /etc/init.d /usr /usr/bin /usr/include /usr/lib
+ /usr/libx32 /usr/lib64 /usr/share /usr/share/aclocal /usr/share/doc)
+ endif()
+ unset(filtered_)
+ foreach(part_ IN LISTS prepared_)
+ unset(dont_add_)
+ foreach(for_removal_ IN LISTS CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST)
+ if(part_ STREQUAL for_removal_)
+ set(dont_add_ TRUE)
+ break()
+ endif()
+ endforeach()
+
+ if(NOT dont_add_)
+ list(APPEND filtered_ "${part_}")
+ endif()
+ endforeach()
+
+ set(${CONTENT_VAR} "${filtered_}" PARENT_SCOPE)
+endfunction()
+
+function(getPackageInfo FILE RESULT_VAR)
+ execute_process(COMMAND ${RPM_EXECUTABLE} -pqi ${FILE}
+ OUTPUT_VARIABLE info_content
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ set(${RESULT_VAR} "${info_content}" PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/RPM/Prerequirements.cmake b/Tests/RunCMake/CPack/RPM/Prerequirements.cmake
new file mode 100644
index 0000000..e95cd15
--- /dev/null
+++ b/Tests/RunCMake/CPack/RPM/Prerequirements.cmake
@@ -0,0 +1,23 @@
+function(get_test_prerequirements found_var config_file)
+ if(CMAKE_CURRENT_BINARY_DIR MATCHES " ")
+ # rpmbuild can't handle spaces in path
+ return()
+ endif()
+
+ find_program(RPM_EXECUTABLE rpm)
+ find_program(RPMBUILD_EXECUTABLE rpmbuild)
+
+ if(RPM_EXECUTABLE AND RPMBUILD_EXECUTABLE)
+ file(WRITE "${config_file}" "set(RPM_EXECUTABLE \"${RPM_EXECUTABLE}\")")
+ file(APPEND "${config_file}"
+ "\nset(RPMBUILD_EXECUTABLE \"${RPMBUILD_EXECUTABLE}\")")
+ set(${found_var} true PARENT_SCOPE)
+ endif()
+
+ # optional tool for some tests
+ find_program(OBJDUMP_EXECUTABLE objdump)
+ if(OBJDUMP_EXECUTABLE)
+ file(APPEND "${config_file}"
+ "\nset(OBJDUMP_EXECUTABLE \"${OBJDUMP_EXECUTABLE}\")")
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/RPM/default_expected_stderr.txt b/Tests/RunCMake/CPack/RPM/default_expected_stderr.txt
new file mode 100644
index 0000000..6c87ca0
--- /dev/null
+++ b/Tests/RunCMake/CPack/RPM/default_expected_stderr.txt
@@ -0,0 +1 @@
+^(CPackRPM: Will use GENERATED spec file: (/[^/]*)*/Tests/RunCMake/RPM\.[^/]*/CPack/[^-]*(-package-target)?-build((-[^-]*-subtest/)|/)_CPack_Packages/.*/RPM/SPECS/[^\.]*\.spec(\n|$))*$
diff --git a/Tests/RunCMake/CPack/RPM/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/RPM/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..c8b93e9
--- /dev/null
+++ b/Tests/RunCMake/CPack/RPM/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_RPM_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake
new file mode 100644
index 0000000..a3c72a1
--- /dev/null
+++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake
@@ -0,0 +1,50 @@
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+
+include(RunCMake)
+include("${RunCMake_SOURCE_DIR}/CPackTestHelpers.cmake")
+
+# run_cpack_test args: TEST_NAME "GENERATORS" RUN_CMAKE_BUILD_STEP "PACKAGING_TYPES"
+run_cpack_test(CUSTOM_BINARY_SPEC_FILE "RPM.CUSTOM_BINARY_SPEC_FILE" false "MONOLITHIC;COMPONENT")
+run_cpack_test(CUSTOM_NAMES "RPM.CUSTOM_NAMES;DEB.CUSTOM_NAMES;TGZ;DragNDrop" true "COMPONENT")
+run_cpack_test(DEBUGINFO "RPM.DEBUGINFO;DEB.DEBUGINFO" true "COMPONENT")
+run_cpack_test_subtests(DEFAULT_PERMISSIONS "CMAKE_var_set;CPACK_var_set;both_set;invalid_CMAKE_var;invalid_CPACK_var" "RPM.DEFAULT_PERMISSIONS;DEB.DEFAULT_PERMISSIONS" false "MONOLITHIC;COMPONENT")
+run_cpack_test(DEPENDENCIES "RPM.DEPENDENCIES;DEB.DEPENDENCIES" true "COMPONENT")
+run_cpack_test(DIST "RPM.DIST" false "MONOLITHIC")
+run_cpack_test(DMG_SLA "DragNDrop" false "MONOLITHIC")
+run_cpack_test(EMPTY_DIR "RPM.EMPTY_DIR;DEB.EMPTY_DIR;TGZ" true "MONOLITHIC;COMPONENT")
+run_cpack_test(VERSION "RPM.VERSION;DEB.VERSION" false "MONOLITHIC;COMPONENT")
+run_cpack_test(EXTRA "DEB.EXTRA" false "COMPONENT")
+run_cpack_test_subtests(GENERATE_SHLIBS "soversion_not_zero;soversion_zero" "DEB.GENERATE_SHLIBS" true "COMPONENT")
+run_cpack_test(GENERATE_SHLIBS_LDCONFIG "DEB.GENERATE_SHLIBS_LDCONFIG" true "COMPONENT")
+run_cpack_test_subtests(INSTALL_SCRIPTS "default;single_debug_info;no_scripts;no_scripts_single_debug_info" "RPM.INSTALL_SCRIPTS" false "COMPONENT")
+run_cpack_test(LONG_FILENAMES "DEB.LONG_FILENAMES" false "MONOLITHIC")
+run_cpack_test_subtests(MAIN_COMPONENT "invalid;found" "RPM.MAIN_COMPONENT" false "COMPONENT")
+run_cpack_test(MINIMAL "RPM.MINIMAL;DEB.MINIMAL;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ;External" false "MONOLITHIC;COMPONENT")
+run_cpack_test_package_target(MINIMAL "RPM.MINIMAL;DEB.MINIMAL;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ;External" false "MONOLITHIC;COMPONENT")
+run_cpack_test_package_target(THREADED_ALL "TXZ;DEB" false "MONOLITHIC;COMPONENT")
+run_cpack_test_package_target(THREADED "TXZ;DEB" false "MONOLITHIC;COMPONENT")
+run_cpack_test_subtests(PACKAGE_CHECKSUM "invalid;MD5;SHA1;SHA224;SHA256;SHA384;SHA512" "TGZ" false "MONOLITHIC")
+run_cpack_test(PARTIALLY_RELOCATABLE_WARNING "RPM.PARTIALLY_RELOCATABLE_WARNING" false "COMPONENT")
+run_cpack_test(PER_COMPONENT_FIELDS "RPM.PER_COMPONENT_FIELDS;DEB.PER_COMPONENT_FIELDS" false "COMPONENT")
+run_cpack_test_subtests(SINGLE_DEBUGINFO "no_main_component;one_component;one_component_main;no_debuginfo;one_component_no_debuginfo;no_components;valid" "RPM.SINGLE_DEBUGINFO" true "CUSTOM")
+run_cpack_test(EXTRA_SLASH_IN_PATH "RPM.EXTRA_SLASH_IN_PATH" true "COMPONENT")
+run_cpack_source_test(SOURCE_PACKAGE "RPM.SOURCE_PACKAGE")
+run_cpack_test(SUGGESTS "RPM.SUGGESTS" false "MONOLITHIC")
+run_cpack_test(SYMLINKS "RPM.SYMLINKS;TGZ" false "MONOLITHIC;COMPONENT")
+set(ENVIRONMENT "SOURCE_DATE_EPOCH=123456789")
+run_cpack_test(TIMESTAMPS "DEB.TIMESTAMPS;TGZ" false "COMPONENT")
+unset(ENVIRONMENT)
+run_cpack_test(USER_FILELIST "RPM.USER_FILELIST" false "MONOLITHIC")
+run_cpack_test(MD5SUMS "DEB.MD5SUMS" false "MONOLITHIC;COMPONENT")
+run_cpack_test_subtests(CPACK_INSTALL_SCRIPTS "singular;plural;both" "ZIP" false "MONOLITHIC")
+run_cpack_test(DEB_PACKAGE_VERSION_BACK_COMPATIBILITY "DEB.DEB_PACKAGE_VERSION_BACK_COMPATIBILITY" false "MONOLITHIC;COMPONENT")
+run_cpack_test_subtests(EXTERNAL "none;good;good_multi;bad_major;bad_minor;invalid_good;invalid_bad;stage_and_package" "External" false "MONOLITHIC;COMPONENT")
+run_cpack_test_subtests(
+ DEB_DESCRIPTION
+ "CPACK_DEBIAN_PACKAGE_DESCRIPTION;CPACK_PACKAGE_DESCRIPTION;CPACK_COMPONENT_COMP_DESCRIPTION;CPACK_PACKAGE_DESCRIPTION_FILE;CPACK_NO_PACKAGE_DESCRIPTION"
+ "DEB.DEB_DESCRIPTION"
+ false
+ "MONOLITHIC;COMPONENT"
+)
+run_cpack_test(PROJECT_META "RPM.PROJECT_META;DEB.PROJECT_META" false "MONOLITHIC;COMPONENT")
+run_cpack_test_package_target(PRE_POST_SCRIPTS "ZIP" false "MONOLITHIC;COMPONENT")
diff --git a/Tests/RunCMake/CPack/STGZ/Helpers.cmake b/Tests/RunCMake/CPack/STGZ/Helpers.cmake
new file mode 100644
index 0000000..1756645
--- /dev/null
+++ b/Tests/RunCMake/CPack/STGZ/Helpers.cmake
@@ -0,0 +1,75 @@
+set(ALL_FILES_GLOB "*.sh")
+
+function(getPackageContent FILE RESULT_VAR)
+ get_filename_component(path_ "${FILE}" DIRECTORY)
+ file(REMOVE_RECURSE "${path_}/content")
+ file(MAKE_DIRECTORY "${path_}/content")
+ execute_process(COMMAND ${FILE} --prefix=${path_}/content --include-subdir
+ RESULT_VARIABLE extract_result_
+ ERROR_VARIABLE extract_error_
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(extract_result_)
+ message(FATAL_ERROR "Extracting STGZ archive failed: '${extract_result_}';"
+ " '${extract_error_}'.")
+ endif()
+
+ file(GLOB_RECURSE package_content_ LIST_DIRECTORIES true RELATIVE
+ "${path_}/content" "${path_}/content/*")
+
+ set(${RESULT_VAR} "${package_content_}" PARENT_SCOPE)
+endfunction()
+
+function(getPackageNameGlobexpr NAME COMPONENT VERSION REVISION FILE_NO RESULT_VAR)
+ if(COMPONENT)
+ set(COMPONENT "-${COMPONENT}")
+ endif()
+
+ set(${RESULT_VAR} "${NAME}-${VERSION}-*${COMPONENT}.sh" PARENT_SCOPE)
+endfunction()
+
+function(getPackageContentList FILE RESULT_VAR)
+ getPackageContent("${FILE}" package_content_)
+
+ set(${RESULT_VAR} "${package_content_}" PARENT_SCOPE)
+endfunction()
+
+function(toExpectedContentList FILE_NO CONTENT_VAR)
+ findExpectedFile("${FILE_NO}" "file_" "glob_expr_")
+
+ get_filename_component(prefix_ "${file_}" NAME)
+ # NAME_WE removes everything after the dot and dot is in version so replace instead
+ string(REPLACE ".sh" "" prefix_ "${prefix_}")
+
+ if(NOT PACKAGING_TYPE STREQUAL "MONOLITHIC")
+ # STGZ packages don't have component dir prefix in subdir
+ string(FIND "${prefix_}" "-" pos_ REVERSE)
+ string(SUBSTRING "${prefix_}" 0 ${pos_} prefix_)
+ endif()
+
+ # add install prefix to expected paths
+ if(DEFINED EXPECTED_FILE_${FILE_NO}_PACKAGING_PREFIX)
+ set(EXPECTED_FILE_PACKAGING_PREFIX
+ "${EXPECTED_FILE_${FILE_NO}_PACKAGING_PREFIX}")
+ elseif(NOT DEFINED EXPECTED_FILE_PACKAGING_PREFIX)
+ # default CPack Archive packaging install prefix
+ set(EXPECTED_FILE_PACKAGING_PREFIX "/")
+ endif()
+
+ # remove trailing slash otherwise path concatenation will cause double slashes
+ string(REGEX REPLACE "/$" "" EXPECTED_FILE_PACKAGING_PREFIX
+ "${EXPECTED_FILE_PACKAGING_PREFIX}")
+
+ if(EXPECTED_FILE_PACKAGING_PREFIX)
+ set(prepared_ "${prefix_}")
+ else()
+ unset(prepared_)
+ endif()
+
+ list(APPEND prepared_ "${prefix_}${EXPECTED_FILE_PACKAGING_PREFIX}")
+ foreach(part_ IN LISTS ${CONTENT_VAR})
+ list(APPEND prepared_ "${prefix_}${EXPECTED_FILE_PACKAGING_PREFIX}${part_}")
+ endforeach()
+
+ set(${CONTENT_VAR} "${prepared_}" PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/STGZ/Prerequirements.cmake b/Tests/RunCMake/CPack/STGZ/Prerequirements.cmake
new file mode 100644
index 0000000..3b015ca
--- /dev/null
+++ b/Tests/RunCMake/CPack/STGZ/Prerequirements.cmake
@@ -0,0 +1,11 @@
+function(get_test_prerequirements found_var config_file)
+ if(EXISTS "/bin/sh")
+ #gunzip is not part of posix so we should not rely on it being installed
+ find_program(GUNZIP_EXECUTABLE gunzip)
+
+ if(GUNZIP_EXECUTABLE)
+ file(WRITE "${config_file}" "")
+ set(${found_var} true PARENT_SCOPE)
+ endif()
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/STGZ/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/STGZ/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/STGZ/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/TBZ2/Helpers.cmake b/Tests/RunCMake/CPack/TBZ2/Helpers.cmake
new file mode 100644
index 0000000..292b691
--- /dev/null
+++ b/Tests/RunCMake/CPack/TBZ2/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "tar.bz2")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/TBZ2/Prerequirements.cmake b/Tests/RunCMake/CPack/TBZ2/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/TBZ2/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+ file(WRITE "${config_file}" "")
+ set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/TBZ2/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/TBZ2/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/TBZ2/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/TGZ/Helpers.cmake b/Tests/RunCMake/CPack/TGZ/Helpers.cmake
new file mode 100644
index 0000000..4357a59
--- /dev/null
+++ b/Tests/RunCMake/CPack/TGZ/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "tar.gz")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/TGZ/Prerequirements.cmake b/Tests/RunCMake/CPack/TGZ/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/TGZ/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+ file(WRITE "${config_file}" "")
+ set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/TGZ/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/TGZ/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/TGZ/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/TXZ/Helpers.cmake b/Tests/RunCMake/CPack/TXZ/Helpers.cmake
new file mode 100644
index 0000000..f390cb4
--- /dev/null
+++ b/Tests/RunCMake/CPack/TXZ/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "tar.xz")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/TXZ/Prerequirements.cmake b/Tests/RunCMake/CPack/TXZ/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/TXZ/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+ file(WRITE "${config_file}" "")
+ set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/TXZ/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/TXZ/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/TXZ/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/TZ/Helpers.cmake b/Tests/RunCMake/CPack/TZ/Helpers.cmake
new file mode 100644
index 0000000..117cd24
--- /dev/null
+++ b/Tests/RunCMake/CPack/TZ/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "tar.Z")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/TZ/Prerequirements.cmake b/Tests/RunCMake/CPack/TZ/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/TZ/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+ file(WRITE "${config_file}" "")
+ set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/TZ/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/TZ/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/TZ/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/VerifyResult.cmake b/Tests/RunCMake/CPack/VerifyResult.cmake
new file mode 100644
index 0000000..0ab545a
--- /dev/null
+++ b/Tests/RunCMake/CPack/VerifyResult.cmake
@@ -0,0 +1,142 @@
+cmake_minimum_required(VERSION ${CMAKE_VERSION} FATAL_ERROR)
+
+function(findExpectedFile FILE_NO RESULT_VAR GLOBING_EXPR_VAR)
+ if(NOT DEFINED EXPECTED_FILE_${FILE_NO}) # explicit file name regex was not provided - construct one from other data
+ # set defaults if parameters are not provided
+ if(NOT DEFINED EXPECTED_FILE_${FILE_NO}_NAME)
+ string(TOLOWER "${RunCMake_TEST_FILE_PREFIX}" EXPECTED_FILE_${FILE_NO}_NAME)
+ endif()
+ if(NOT DEFINED EXPECTED_FILE_${FILE_NO}_VERSION)
+ set(EXPECTED_FILE_${FILE_NO}_VERSION "0.1.1")
+ set(EXPECTED_FILE_${FILE_NO}_VERSION "0.1.1" PARENT_SCOPE)
+ endif()
+
+ getPackageNameGlobexpr("${EXPECTED_FILE_${FILE_NO}_NAME}"
+ "${EXPECTED_FILE_${FILE_NO}_COMPONENT}" "${EXPECTED_FILE_${FILE_NO}_VERSION}"
+ "${EXPECTED_FILE_${FILE_NO}_REVISION}" "${FILE_NO}" "EXPECTED_FILE_${FILE_NO}")
+ endif()
+
+ file(GLOB found_file_ RELATIVE "${bin_dir}" "${EXPECTED_FILE_${FILE_NO}}")
+
+ set(${RESULT_VAR} "${found_file_}" PARENT_SCOPE)
+ set(${GLOBING_EXPR_VAR} "${EXPECTED_FILE_${FILE_NO}}" PARENT_SCOPE)
+endfunction()
+
+include("${config_file}")
+include("${src_dir}/${GENERATOR_TYPE}/Helpers.cmake")
+
+file(READ "${bin_dir}/test_output.txt" output)
+file(READ "${bin_dir}/test_error.txt" error)
+file(READ "${config_file}" config_file_content)
+
+set(output_error_message
+ "\nCPack output: '${output}'\nCPack error: '${error}';\nCPack result: '${PACKAGING_RESULT}';\nconfig file: '${config_file_content}'")
+
+# generate default expected files data
+include("${src_dir}/tests/${RunCMake_TEST_FILE_PREFIX}/ExpectedFiles.cmake")
+
+# check that expected generated files exist and contain expected content
+if(NOT EXPECTED_FILES_COUNT EQUAL 0)
+ foreach(file_no_ RANGE 1 ${EXPECTED_FILES_COUNT})
+ findExpectedFile("${file_no_}" "FOUND_FILE_${file_no_}"
+ "EXPECTED_FILE_${file_no_}")
+ list(APPEND foundFiles_ "${FOUND_FILE_${file_no_}}")
+ list(LENGTH FOUND_FILE_${file_no_} foundFilesCount_)
+
+ if(foundFilesCount_ EQUAL 1)
+ unset(PACKAGE_CONTENT)
+
+ if(DEFINED EXPECTED_FILE_CONTENT_${file_no_})
+ getPackageContent("${bin_dir}/${FOUND_FILE_${file_no_}}" "PACKAGE_CONTENT")
+
+ string(REGEX MATCH "${EXPECTED_FILE_CONTENT_${file_no_}}"
+ expected_content_list "${PACKAGE_CONTENT}")
+ else() # use content list
+ getPackageContentList("${bin_dir}/${FOUND_FILE_${file_no_}}" "PACKAGE_CONTENT")
+ set(EXPECTED_FILE_CONTENT_${file_no_} "${EXPECTED_FILE_CONTENT_${file_no_}_LIST}")
+ toExpectedContentList("${file_no_}" "EXPECTED_FILE_CONTENT_${file_no_}")
+
+ if(NOT PACKAGE_CONTENT STREQUAL "")
+ list(SORT PACKAGE_CONTENT)
+ endif()
+ if(NOT EXPECTED_FILE_CONTENT_${file_no_} STREQUAL "")
+ list(SORT EXPECTED_FILE_CONTENT_${file_no_})
+ endif()
+
+ if(PACKAGE_CONTENT STREQUAL EXPECTED_FILE_CONTENT_${file_no_})
+ set(expected_content_list TRUE)
+ else()
+ set(expected_content_list FALSE)
+ endif()
+ endif()
+
+ if(NOT expected_content_list)
+ string(REPLACE "\n" "\n actual> " msg_actual "\n${PACKAGE_CONTENT}")
+ string(REPLACE "\n" "\n expect> " msg_expected "\n${EXPECTED_FILE_CONTENT_${file_no_}}")
+ message(FATAL_ERROR
+ "Unexpected file content for file No. '${file_no_}'!\n"
+ "The content was:${msg_actual}\n"
+ "which does not match:${msg_expected}\n"
+ "${output_error_message}")
+ endif()
+ elseif(foundFilescount_ EQUAL 0)
+ message(FATAL_ERROR
+ "Found no files for file No. '${file_no_}'!"
+ " Globbing expression: '${EXPECTED_FILE_${file_no_}}'"
+ "${output_error_message}")
+ else()
+ message(FATAL_ERROR
+ "Found more than one file for file No. '${file_no_}'!"
+ " Found files count '${foundFilesCount_}'."
+ " Files: '${FOUND_FILE_${file_no_}}'"
+ " Globbing expression: '${EXPECTED_FILE_${file_no_}}'"
+ "${output_error_message}")
+ endif()
+ endforeach()
+
+ # check that there were no extra files generated
+ foreach(all_files_glob_ IN LISTS ALL_FILES_GLOB)
+ file(GLOB foundAll_ RELATIVE "${bin_dir}" "${all_files_glob_}")
+ list(APPEND allFoundFiles_ ${foundAll_})
+ endforeach()
+
+ list(LENGTH foundFiles_ foundFilesCount_)
+ list(LENGTH allFoundFiles_ allFoundFilesCount_)
+
+ if(NOT foundFilesCount_ EQUAL allFoundFilesCount_)
+ message(FATAL_ERROR
+ "Found more files than expected! Found files: '${allFoundFiles_}'"
+ "${output_error_message}")
+ endif()
+
+ # sanity check that we didn't accidentally list wrong files with our regular
+ # expressions
+ foreach(expected_ IN LISTS allFoundFiles_)
+ list(FIND foundFiles_ "${expected_}" found_)
+
+ if(found_ EQUAL -1)
+ message(FATAL_ERROR
+ "Expected files don't match found files! Found files:"
+ " '${allFoundFiles_}'"
+ "${output_error_message}")
+ endif()
+ endforeach()
+else()
+ # there should be no generated files present
+ foreach(missing_file_glob_ IN LISTS ALL_FILES_GLOB)
+ file(GLOB checkMissingFiles_ RELATIVE "${bin_dir}" "${missing_file_glob_}")
+
+ if(checkMissingFiles_)
+ message(FATAL_ERROR "Unexpected files found: '${checkMissingFiles_}'"
+ "${output_error_message}")
+ endif()
+ endforeach()
+endif()
+
+# handle additional result verifications
+if(EXISTS "${src_dir}/tests/${RunCMake_TEST_FILE_PREFIX}/VerifyResult.cmake")
+ include("${src_dir}/tests/${RunCMake_TEST_FILE_PREFIX}/VerifyResult.cmake")
+endif()
+
+message(STATUS "${output}")
+message("${error}")
diff --git a/Tests/RunCMake/CPack/ZIP/Helpers.cmake b/Tests/RunCMake/CPack/ZIP/Helpers.cmake
new file mode 100644
index 0000000..3710bcf
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "zip")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/ZIP/Prerequirements.cmake b/Tests/RunCMake/CPack/ZIP/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+ file(WRITE "${config_file}" "")
+ set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/ZIP/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/ZIP/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/ExpectedFiles.cmake
new file mode 100644
index 0000000..02a7821
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/ExpectedFiles.cmake
@@ -0,0 +1,3 @@
+set(EXPECTED_FILES_COUNT "1")
+
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/abc.txt")
diff --git a/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/both-stderr.txt b/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/both-stderr.txt
new file mode 100644
index 0000000..666030e
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/both-stderr.txt
@@ -0,0 +1 @@
+CPack Warning: Both CPACK_INSTALL_SCRIPTS and CPACK_INSTALL_SCRIPT are set, the latter will be ignored.
diff --git a/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/test.cmake b/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/test.cmake
new file mode 100644
index 0000000..249d2e6
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/CPACK_INSTALL_SCRIPTS/test.cmake
@@ -0,0 +1,26 @@
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/abc.txt" "test content")
+set(user_script_ "${CMAKE_CURRENT_BINARY_DIR}/user-script.cmake")
+file(WRITE "${user_script_}"
+ "file(INSTALL DESTINATION \"\${CMAKE_INSTALL_PREFIX}/foo\"
+ TYPE FILE FILES \"${CMAKE_CURRENT_BINARY_DIR}/abc.txt\")")
+
+if(RunCMake_SUBTEST_SUFFIX STREQUAL "both")
+ set(CPACK_INSTALL_SCRIPT "${user_script_}")
+ set(CPACK_INSTALL_SCRIPTS "${CPACK_INSTALL_SCRIPT}")
+
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "singular")
+ set(CPACK_INSTALL_SCRIPT "${user_script_}")
+
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "plural")
+ set(CPACK_INSTALL_SCRIPTS "${user_script_}")
+
+else()
+ message(FATAL_ERROR "Unexpected subtest name: ${RunCMake_SUBTEST_SUFFIX}")
+
+endif()
+
+function(run_after_include_cpack)
+ file(READ "${CPACK_OUTPUT_CONFIG_FILE}" conf_file_)
+ string(REGEX REPLACE "SET\\(CPACK_INSTALL_CMAKE_PROJECTS [^)]*\\)" "" conf_file_ "${conf_file_}")
+ file(WRITE "${CPACK_OUTPUT_CONFIG_FILE}" "${conf_file_}")
+endfunction()
diff --git a/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/ExpectedFiles.cmake
new file mode 100644
index 0000000..6d895ec
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/ExpectedFiles.cmake
@@ -0,0 +1,9 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(EXPECTED_FILES_COUNT "2")
+ set(EXPECTED_FILE_1_COMPONENT "test")
+ set(EXPECTED_FILE_2_COMPONENT "test2")
+ set(EXPECTED_FILE_CONTENT_2_LIST "/bar;/bar/CMakeLists.txt")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/RPM-COMPONENT-stderr.txt b/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/RPM-COMPONENT-stderr.txt
new file mode 100644
index 0000000..b050262
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/RPM-COMPONENT-stderr.txt
@@ -0,0 +1,2 @@
+^CPackRPM: Will use USER specified spec file: (/[^/]*)*/CUSTOM_BINARY_SPEC_FILE/custom\.spec\.in
+CPackRPM: Will use GENERATED spec file:.*/Tests/RunCMake/RPM\.CUSTOM_BINARY_SPEC_FILE/CPack/CUSTOM_BINARY_SPEC_FILE-build/_CPack_Packages/.*/RPM/SPECS/custom_binary_spec_file-test2\.spec$
diff --git a/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/RPM-MONOLITHIC-stderr.txt b/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/RPM-MONOLITHIC-stderr.txt
new file mode 100644
index 0000000..d7bb7af
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/RPM-MONOLITHIC-stderr.txt
@@ -0,0 +1 @@
+CPackRPM: Will use USER specified spec file: (/[^/]*)*/CUSTOM_BINARY_SPEC_FILE/custom\.spec\.in
diff --git a/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/custom.spec.in b/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/custom.spec.in
new file mode 100644
index 0000000..db0ac6f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/custom.spec.in
@@ -0,0 +1,80 @@
+# -*- rpm-spec -*-
+BuildRoot: %_topdir/@CPACK_PACKAGE_FILE_NAME@@CPACK_RPM_PACKAGE_COMPONENT_PART_PATH@
+Summary: @CPACK_RPM_PACKAGE_SUMMARY@
+Name: @CPACK_RPM_PACKAGE_NAME@
+Version: @CPACK_RPM_PACKAGE_VERSION@
+Release: @CPACK_RPM_PACKAGE_RELEASE@
+License: @CPACK_RPM_PACKAGE_LICENSE@
+Group: @CPACK_RPM_PACKAGE_GROUP@
+Vendor: @CPACK_RPM_PACKAGE_VENDOR@
+
+@TMP_RPM_URL@
+@TMP_RPM_REQUIRES@
+@TMP_RPM_REQUIRES_PRE@
+@TMP_RPM_REQUIRES_POST@
+@TMP_RPM_REQUIRES_PREUN@
+@TMP_RPM_REQUIRES_POSTUN@
+@TMP_RPM_PROVIDES@
+@TMP_RPM_OBSOLETES@
+@TMP_RPM_CONFLICTS@
+@TMP_RPM_SUGGESTS@
+@TMP_RPM_AUTOPROV@
+@TMP_RPM_AUTOREQ@
+@TMP_RPM_AUTOREQPROV@
+@TMP_RPM_BUILDARCH@
+@TMP_RPM_PREFIXES@
+
+@TMP_RPM_DEBUGINFO@
+
+%define _rpmdir %_topdir/RPMS
+%define _srcrpmdir %_topdir/SRPMS
+@FILE_NAME_DEFINE@
+%define _unpackaged_files_terminate_build 0
+@TMP_RPM_SPEC_INSTALL_POST@
+@CPACK_RPM_SPEC_MORE_DEFINE@
+@CPACK_RPM_COMPRESSION_TYPE_TMP@
+
+%description
+@CPACK_RPM_PACKAGE_DESCRIPTION@
+
+# This is a shortcutted spec file generated by CMake RPM generator
+# we skip _install step because CPack does that for us.
+# We do only save CPack installed tree in _prepr
+# and then restore it in build.
+%prep
+mv $RPM_BUILD_ROOT %_topdir/tmpBBroot
+
+%install
+if [ -e $RPM_BUILD_ROOT ];
+then
+ rm -rf $RPM_BUILD_ROOT
+fi
+mv %_topdir/tmpBBroot $RPM_BUILD_ROOT
+
+@TMP_RPM_DEBUGINFO_INSTALL@
+
+%clean
+
+%post
+@RPM_SYMLINK_POSTINSTALL@
+@CPACK_RPM_SPEC_POSTINSTALL@
+
+%postun
+@CPACK_RPM_SPEC_POSTUNINSTALL@
+
+%pre
+@CPACK_RPM_SPEC_PREINSTALL@
+
+%preun
+@CPACK_RPM_SPEC_PREUNINSTALL@
+
+%files
+%defattr(@TMP_DEFAULT_FILE_PERMISSIONS@,@TMP_DEFAULT_USER@,@TMP_DEFAULT_GROUP@,@TMP_DEFAULT_DIR_PERMISSIONS@)
+@CPACK_RPM_INSTALL_FILES@
+@CPACK_RPM_ABSOLUTE_INSTALL_FILES@
+@CPACK_RPM_USER_INSTALL_FILES@
+
+%changelog
+@CPACK_RPM_SPEC_CHANGELOG@
+
+@TMP_OTHER_COMPONENTS@
diff --git a/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/test.cmake b/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/test.cmake
new file mode 100644
index 0000000..a604863
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/CUSTOM_BINARY_SPEC_FILE/test.cmake
@@ -0,0 +1,9 @@
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
+
+if(PACKAGING_TYPE STREQUAL "MONOLITHIC")
+ set(CPACK_RPM_USER_BINARY_SPECFILE "${CMAKE_CURRENT_LIST_DIR}/custom.spec.in")
+elseif(PACKAGING_TYPE STREQUAL "COMPONENT")
+ install(FILES CMakeLists.txt DESTINATION bar COMPONENT test2)
+ set(CPACK_RPM_TEST_USER_BINARY_SPECFILE
+ "${CMAKE_CURRENT_LIST_DIR}/custom.spec.in")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake
new file mode 100644
index 0000000..9ac19e2
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake
@@ -0,0 +1,18 @@
+set(EXPECTED_FILES_COUNT "3")
+set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
+set(EXPECTED_FILE_1_COMPONENT "pkg_1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
+set(EXPECTED_FILE_2_NAME "second")
+set(EXPECTED_FILE_CONTENT_2_LIST "/foo;/foo/CMakeLists.txt")
+set(EXPECTED_FILE_CONTENT_3_LIST "/foo;/foo/CMakeLists.txt")
+
+if(GENERATOR_TYPE STREQUAL "DEB" OR GENERATOR_TYPE STREQUAL "RPM")
+ string(TOLOWER "${GENERATOR_TYPE}" file_extension_)
+ set(EXPECTED_FILE_3 "pkg_3_abc.${file_extension_}")
+elseif(GENERATOR_TYPE STREQUAL "TGZ")
+ set(EXPECTED_FILE_2 "second.tar.gz")
+ set(EXPECTED_FILE_3 "pkg_3_abc.tar.gz")
+elseif(GENERATOR_TYPE STREQUAL "DragNDrop")
+ set(EXPECTED_FILE_2 "second.dmg")
+ set(EXPECTED_FILE_3 "pkg_3_abc.dmg")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake
new file mode 100644
index 0000000..899258e
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake
@@ -0,0 +1,20 @@
+if(GENERATOR_TYPE STREQUAL "DEB" OR GENERATOR_TYPE STREQUAL "RPM")
+ if(GENERATOR_TYPE STREQUAL "DEB")
+ set(generator_type_suffix_ "IAN") # not entirely compatible...
+ endif()
+
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_FILE_NAME "${GENERATOR_TYPE}-DEFAULT")
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_PKG_2_PACKAGE_NAME "second")
+ string(TOLOWER "${GENERATOR_TYPE}" file_extension_)
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_PKG_3_FILE_NAME "pkg_3_abc.${file_extension_}")
+elseif(GENERATOR_TYPE STREQUAL "TGZ")
+ set(CPACK_ARCHIVE_PKG_2_FILE_NAME "second")
+ set(CPACK_ARCHIVE_PKG_3_FILE_NAME "pkg_3_abc")
+elseif(GENERATOR_TYPE STREQUAL "DragNDrop")
+ set(CPACK_DMG_PKG_2_FILE_NAME "second")
+ set(CPACK_DMG_PKG_3_FILE_NAME "pkg_3_abc")
+endif()
+
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT pkg_1)
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT pkg_2)
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT pkg_3)
diff --git a/Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake
new file mode 100644
index 0000000..cf4aa51
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake
@@ -0,0 +1,44 @@
+set(whitespaces_ "[\t\n\r ]*")
+
+set(EXPECTED_FILES_COUNT "6")
+set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
+
+if(GENERATOR_TYPE STREQUAL "RPM")
+ set(NAME "Debuginfo")
+ set(DEBUG_SUFFIX "debuginfo")
+ set(PKG "rpm")
+ set(DEBUG_PKG "rpm")
+elseif(GENERATOR_TYPE STREQUAL "DEB")
+ set(NAME "debuginfo")
+ set(DEBUG_SUFFIX "dbgsym")
+ set(PKG "deb")
+ set(DEBUG_PKG "ddeb")
+endif()
+
+set(EXPECTED_FILE_1_NAME "${NAME}")
+set(EXPECTED_FILE_1_COMPONENT "applications")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/test_prog")
+
+set(EXPECTED_FILE_2 "TestDinfo-pkg*-headers.${PKG}")
+set(EXPECTED_FILE_CONTENT_2_LIST "/bar;/bar/CMakeLists.txt")
+
+set(EXPECTED_FILE_3 "TestDinfo-pkg*-libs.${PKG}")
+set(EXPECTED_FILE_CONTENT_3_LIST "/bas;/bas/libtest_lib.so")
+
+set(EXPECTED_FILE_4 "${NAME}-applications-${DEBUG_SUFFIX}*.${DEBUG_PKG}")
+if(GENERATOR_TYPE STREQUAL "RPM")
+ set(EXPECTED_FILE_CONTENT_4 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/main.cpp.*\.debug.*")
+elseif(GENERATOR_TYPE STREQUAL "DEB")
+ set(EXPECTED_FILE_CONTENT_4 ".*/usr/lib/debug/.build-id/.*\.debug.*")
+endif()
+
+if(GENERATOR_TYPE STREQUAL "RPM")
+ set(EXPECTED_FILE_5 "libs-DebugInfoPackage.rpm")
+ set(EXPECTED_FILE_CONTENT_5 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/test_lib.cpp.*\.debug.*")
+elseif(GENERATOR_TYPE STREQUAL "DEB")
+ set(EXPECTED_FILE_5 "TestDinfo-pkg-libs-dbgsym.ddeb")
+ set(EXPECTED_FILE_CONTENT_5 ".*/usr/lib/debug/.build-id/.*\.debug.*")
+endif()
+
+set(EXPECTED_FILE_6 "TestDinfo-pkg*-appheaders.${PKG}")
+set(EXPECTED_FILE_CONTENT_6_LIST "/include;/include/test_lib.hpp")
diff --git a/Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake b/Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake
new file mode 100644
index 0000000..9ff1f8a
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake
@@ -0,0 +1,53 @@
+set(CMAKE_BUILD_WITH_INSTALL_RPATH 1)
+
+# Some compilers do not add build id to binaries by default.
+if(CMAKE_CXX_COMPILER_ID MATCHES "^(IntelLLVM|PGI|NVHPC)$")
+ string(APPEND CMAKE_EXE_LINKER_FLAGS "-Wl,--build-id")
+ string(APPEND CMAKE_SHARED_LINKER_FLAGS "-Wl,--build-id")
+endif()
+
+set(CMAKE_BUILD_TYPE Debug)
+
+# for rpm packages execute flag must be set for shared libs if debuginfo
+# packages are generated
+set(CPACK_RPM_INSTALL_WITH_EXEC TRUE)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.hpp"
+ "int test_lib();\n")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp"
+ "#include \"test_lib.hpp\"\nint test_lib() {return 0;}\n")
+add_library(test_lib SHARED "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+ "#include \"test_lib.hpp\"\nint main() {return test_lib();}\n")
+add_executable(test_prog "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+target_link_libraries(test_prog test_lib)
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/test_lib.hpp" DESTINATION include COMPONENT appheaders)
+install(TARGETS test_prog DESTINATION foo COMPONENT applications)
+install(FILES CMakeLists.txt DESTINATION bar COMPONENT headers)
+install(TARGETS test_lib DESTINATION bas COMPONENT libs)
+
+set(CPACK_RPM_APPLICATIONS_FILE_NAME "RPM-DEFAULT")
+set(CPACK_RPM_APPLICATIONS_DEBUGINFO_PACKAGE ON)
+set(CPACK_DEBIAN_APPLICATIONS_FILE_NAME "DEB-DEFAULT")
+set(CPACK_DEBIAN_APPLICATIONS_DEBUGINFO_PACKAGE ON)
+
+# test that components with debuginfo enabled still honor
+# CPACK_PACKAGE_FILE_NAME setting
+set(CPACK_RPM_PACKAGE_NAME "Debuginfo")
+set(CPACK_PACKAGE_FILE_NAME "TestDinfo-pkg")
+set(CPACK_RPM_LIBS_DEBUGINFO_PACKAGE ON)
+set(CPACK_DEBIAN_PACKAGE_NAME "Debuginfo")
+set(CPACK_DEBIAN_LIBS_DEBUGINFO_PACKAGE ON)
+
+# Test that a component with debug info requested but without any debug info produces none
+set(CPACK_RPM_APPHEADERS_DEBUGINFO_PACKAGE ON)
+set(CPACK_DEBIAN_APPHEADERS_DEBUGINFO_PACKAGE ON)
+
+# test debuginfo package rename
+set(CPACK_RPM_DEBUGINFO_FILE_NAME
+ "@cpack_component@-DebugInfoPackage.rpm")
+set(CPACK_RPM_APPLICATIONS_DEBUGINFO_FILE_NAME "RPM-DEFAULT")
+
+set(CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX "/src")
diff --git a/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/ExpectedFiles.cmake
new file mode 100644
index 0000000..39f18a3
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/ExpectedFiles.cmake
@@ -0,0 +1,16 @@
+set(EXPECTED_FILES_COUNT_MONOLITHIC "1")
+set(EXPECTED_FILES_COUNT_COMPONENT "2")
+set(EXPECTED_FILES_COUNT "${EXPECTED_FILES_COUNT_${PACKAGING_TYPE}}")
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(EXPECTED_FILE_1 "deb_description-0.1.1-*-satu.deb")
+ set(EXPECTED_FILE_2 "deb_description-0.1.1-*-dua.deb")
+ set(EXPECTED_FILE_CONTENT_1_LIST "/satu;/satu/CMakeLists.txt")
+ set(EXPECTED_FILE_CONTENT_2_LIST "/dua;/dua/CMakeLists.txt")
+
+elseif(PACKAGING_TYPE STREQUAL "MONOLITHIC")
+ set(EXPECTED_FILE_CONTENT_1_LIST "/dua;/dua/CMakeLists.txt;/satu;/satu/CMakeLists.txt")
+
+endif()
+
+# kate: indent-width 2;
diff --git a/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/VerifyResult.cmake
new file mode 100644
index 0000000..6e841fc
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/VerifyResult.cmake
@@ -0,0 +1,59 @@
+function(checkPackageDescription FILE EXPECTED_DESCRIPTION)
+ getPackageInfo("${FILE}" "_file_info")
+ string(UUID uuid NAMESPACE 00000000-0000-0000-0000-000000000000 TYPE SHA1)
+ string(REPLACE ";" "${uuid}" _file_info "${_file_info}")
+ string(REPLACE ";" "${uuid}" EXPECTED_DESCRIPTION "${EXPECTED_DESCRIPTION}")
+ string(REPLACE "\n" ";" _file_info "${_file_info}")
+
+ set(_actual_description)
+ set(_parse_description FALSE)
+ foreach(_line IN LISTS _file_info)
+ if(_line MATCHES " Description:.*")
+ set(_parse_description TRUE)
+ list(APPEND _actual_description "${_line}")
+ elseif(_parse_description)
+ if(_line MATCHES " [A-Z][A-Za-z\-]+: .*")
+ set(_parse_description FALSE)
+ else()
+ list(APPEND _actual_description "${_line}")
+ endif()
+ endif()
+ endforeach()
+ list(JOIN _actual_description "\n" _actual_description)
+
+ if(NOT _actual_description STREQUAL EXPECTED_DESCRIPTION)
+ set(_error "---[BEGIN Expected description]---\n${EXPECTED_DESCRIPTION}---[END Expected description]---\n")
+ string(APPEND _error "---[BEGIN Actual description]---\n${_actual_description}---[END Actual description]---\n")
+ string(REPLACE "${uuid}" ";" _error "${_error}")
+ message(FATAL_ERROR "${_error}")
+ endif()
+endfunction()
+
+# ALERT The output of `dpkg -I *.deb` indented by one space
+set(_expected_description [[ Description: This is the summary line
+ This is the Debian package multiline description.
+ .
+ It must be formatted properly! Otherwise, the result `*.deb`
+ package become broken and cannot be installed!
+ .
+ It may contains `;` characters (even like this `;;;;`). Example:
+ .
+ - one;
+ - two;
+ - three;
+ .
+ ... and they are properly handled by the automatic description formatter!
+ .
+ See also: https://www.debian.org/doc/debian-policy/ch-controlfields.html#description]])
+
+if(RunCMake_SUBTEST_SUFFIX STREQUAL "CPACK_NO_PACKAGE_DESCRIPTION")
+ set(_expected_description [[ Description: This is the summary line]])
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "CPACK_COMPONENT_COMP_DESCRIPTION")
+ set(_expected_description [[ Description: One line description]])
+endif()
+
+foreach(_file_no RANGE 1 ${EXPECTED_FILES_COUNT})
+ checkPackageDescription("${FOUND_FILE_${_file_no}}" "${_expected_description}")
+endforeach()
+
+# kate: indent-width 2;
diff --git a/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/test.cmake b/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/test.cmake
new file mode 100644
index 0000000..2a27b46
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/test.cmake
@@ -0,0 +1,55 @@
+install(FILES CMakeLists.txt DESTINATION satu COMPONENT satu)
+install(FILES CMakeLists.txt DESTINATION dua COMPONENT dua)
+
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "This is the summary line")
+set(_description [[This is the Debian package multiline description.
+
+It must be formatted properly! Otherwise, the result `*.deb`
+package become broken and cannot be installed!
+
+It may contains `;` characters (even like this `;;;;`). Example:
+
+ - one;
+ - two;
+ - three;
+
+... and they are properly handled by the automatic description formatter!
+
+See also: https://www.debian.org/doc/debian-policy/ch-controlfields.html#description]])
+
+if(RunCMake_SUBTEST_SUFFIX STREQUAL "CPACK_DEBIAN_PACKAGE_DESCRIPTION")
+ if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(CPACK_DEBIAN_SATU_DESCRIPTION "${_description}")
+ set(CPACK_DEBIAN_DUA_DESCRIPTION "${_description}")
+ else()
+ set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${_description}")
+ endif()
+
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "CPACK_PACKAGE_DESCRIPTION")
+ # NOTE Documented fallback variable
+ if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(CPACK_COMPONENT_SATU_DESCRIPTION "${_description}")
+ set(CPACK_COMPONENT_DUA_DESCRIPTION "${_description}")
+ else()
+ set(CPACK_PACKAGE_DESCRIPTION "${_description}")
+ endif()
+
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "CPACK_COMPONENT_COMP_DESCRIPTION")
+ # NOTE Documented fallback variable without CPACK_PACKAGE_DESCRIPTION_SUMMARY
+ if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(CPACK_COMPONENT_SATU_DESCRIPTION "One line description")
+ set(CPACK_COMPONENT_DUA_DESCRIPTION "One line description")
+ else()
+ set(CPACK_PACKAGE_DESCRIPTION "One line description")
+ endif()
+ unset(CPACK_PACKAGE_DESCRIPTION_SUMMARY)
+
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "CPACK_PACKAGE_DESCRIPTION_FILE")
+ # NOTE Getting the description from the file
+ set(_file "${CMAKE_CURRENT_BINARY_DIR}/description.txt")
+ file(WRITE "${_file}" "${_description}")
+ set(CPACK_PACKAGE_DESCRIPTION_FILE "${_file}")
+
+endif()
+
+# kate: indent-width 2;
diff --git a/Tests/RunCMake/CPack/tests/DEB_PACKAGE_VERSION_BACK_COMPATIBILITY/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/DEB_PACKAGE_VERSION_BACK_COMPATIBILITY/ExpectedFiles.cmake
new file mode 100644
index 0000000..d1a3a5f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEB_PACKAGE_VERSION_BACK_COMPATIBILITY/ExpectedFiles.cmake
@@ -0,0 +1,2 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/DEB_PACKAGE_VERSION_BACK_COMPATIBILITY/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/DEB_PACKAGE_VERSION_BACK_COMPATIBILITY/VerifyResult.cmake
new file mode 100644
index 0000000..771cc10
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEB_PACKAGE_VERSION_BACK_COMPATIBILITY/VerifyResult.cmake
@@ -0,0 +1,11 @@
+function(checkPackageInfo_ TYPE FILE REGEX)
+ getPackageInfo("${FILE}" "FILE_INFO_")
+ if(NOT FILE_INFO_ MATCHES "${REGEX}")
+ message(FATAL_ERROR "Unexpected ${TYPE} in '${FILE}' ${EXPECTED_FILE_1_VERSION} ${EXPECTED_FILE_1_REVISION}; file info: '${FILE_INFO_}'")
+ endif()
+endfunction()
+
+set(whitespaces_ "[\t\n\r ]*")
+
+checkPackageInfo_("version" "${FOUND_FILE_1}"
+ ".*Version${whitespaces_}:${whitespaces_}5.0.1-71-g884852e")
diff --git a/Tests/RunCMake/CPack/tests/DEB_PACKAGE_VERSION_BACK_COMPATIBILITY/test.cmake b/Tests/RunCMake/CPack/tests/DEB_PACKAGE_VERSION_BACK_COMPATIBILITY/test.cmake
new file mode 100644
index 0000000..403e60d
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEB_PACKAGE_VERSION_BACK_COMPATIBILITY/test.cmake
@@ -0,0 +1,7 @@
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
+
+set(CPACK_DEBIAN_PACKAGE_VERSION "5.0.1-71-g884852e")
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(CPACK_COMPONENTS_ALL test)
+endif()
diff --git a/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/ExpectedFiles.cmake
new file mode 100644
index 0000000..b6fcc17
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/ExpectedFiles.cmake
@@ -0,0 +1,6 @@
+if(${RunCMake_SUBTEST_SUFFIX} MATCHES "invalid_.*_var")
+ set(EXPECTED_FILES_COUNT "0")
+else()
+ set(EXPECTED_FILES_COUNT "1")
+ set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/VerifyResult.cmake
new file mode 100644
index 0000000..16ebcdc
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/VerifyResult.cmake
@@ -0,0 +1,39 @@
+if(NOT ${RunCMake_SUBTEST_SUFFIX} MATCHES "invalid_.*_var")
+ if(GENERATOR_TYPE STREQUAL "RPM")
+ function(checkContentPermissions_ FILE REGEX)
+ execute_process(COMMAND ${RPM_EXECUTABLE} -qp --dump ${FILE}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE PERMISSIONS_
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(NOT PERMISSIONS_ MATCHES "${REGEX}")
+ message(FATAL_ERROR "Permissions in '${FILE}'. Permissions: '${PERMISSIONS_}'")
+ endif()
+ endfunction()
+
+ if(${RunCMake_SUBTEST_SUFFIX} MATCHES "CMAKE_var_set")
+ checkContentPermissions_("${FOUND_FILE_1}"
+ "/usr/foo .*740 root root.*")
+ else()
+ checkContentPermissions_("${FOUND_FILE_1}"
+ "/usr/foo .*700 root root.*")
+ endif()
+ else() # DEB
+ function(checkContentPermissions_ FILE REGEX)
+ getPackageContent("${FILE}" PERMISSIONS_)
+
+ if(NOT PERMISSIONS_ MATCHES "${REGEX}")
+ message(FATAL_ERROR "Permissions in '${FILE}'. Permissions: '${PERMISSIONS_}'")
+ endif()
+ endfunction()
+
+ if(${RunCMake_SUBTEST_SUFFIX} MATCHES "CMAKE_var_set")
+ checkContentPermissions_("${FOUND_FILE_1}"
+ "drwxr----- root/root .* ./usr/\ndrwxr----- root/root .* ./usr/foo/\n.*")
+ else()
+ checkContentPermissions_("${FOUND_FILE_1}"
+ "drwx------ root/root .* ./usr/\ndrwx------ root/root .* ./usr/foo/\n.*")
+ endif()
+ endif()
+endif()
diff --git a/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/invalid_CMAKE_var-stderr.txt b/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/invalid_CMAKE_var-stderr.txt
new file mode 100644
index 0000000..541763a
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/invalid_CMAKE_var-stderr.txt
@@ -0,0 +1 @@
+.*CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS value is invalid.*
diff --git a/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/invalid_CPACK_var-stderr.txt b/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/invalid_CPACK_var-stderr.txt
new file mode 100644
index 0000000..541763a
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/invalid_CPACK_var-stderr.txt
@@ -0,0 +1 @@
+.*CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS value is invalid.*
diff --git a/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/test.cmake b/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/test.cmake
new file mode 100644
index 0000000..afe9390
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEFAULT_PERMISSIONS/test.cmake
@@ -0,0 +1,34 @@
+if(${RunCMake_SUBTEST_SUFFIX} MATCHES "CMAKE_var_set" OR
+ ${RunCMake_SUBTEST_SUFFIX} MATCHES "both_set")
+
+ set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
+ OWNER_READ
+ OWNER_WRITE
+ OWNER_EXECUTE
+ GROUP_READ
+ )
+endif()
+
+if(${RunCMake_SUBTEST_SUFFIX} MATCHES "invalid_CMAKE_var")
+ list(APPEND CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS "INVALID")
+endif()
+
+if(${RunCMake_SUBTEST_SUFFIX} MATCHES "CPACK_var_set" OR
+ ${RunCMake_SUBTEST_SUFFIX} MATCHES "both_set")
+
+ set(CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
+ OWNER_READ
+ OWNER_WRITE
+ OWNER_EXECUTE
+ )
+endif()
+
+if(${RunCMake_SUBTEST_SUFFIX} MATCHES "invalid_CPACK_var")
+ list(APPEND CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS "INVALID")
+endif()
+
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(CPACK_COMPONENTS_ALL test)
+endif()
diff --git a/Tests/RunCMake/CPack/tests/DEPENDENCIES/DEB-stderr.txt b/Tests/RunCMake/CPack/tests/DEPENDENCIES/DEB-stderr.txt
new file mode 100644
index 0000000..5df274a
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEPENDENCIES/DEB-stderr.txt
@@ -0,0 +1 @@
+^CPackDeb: ((- Generating dependency list)|(Using only user-provided dependencies because dpkg-shlibdeps is not found\.))$
diff --git a/Tests/RunCMake/CPack/tests/DEPENDENCIES/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/DEPENDENCIES/ExpectedFiles.cmake
new file mode 100644
index 0000000..be7ba07
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEPENDENCIES/ExpectedFiles.cmake
@@ -0,0 +1,18 @@
+set(EXPECTED_FILES_COUNT "5")
+set(EXPECTED_FILE_1_COMPONENT "applications")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/test_prog")
+set(EXPECTED_FILE_2_COMPONENT "applications_auto")
+set(EXPECTED_FILE_CONTENT_2_LIST "/foo_auto;/foo_auto/test_prog")
+set(EXPECTED_FILE_3_COMPONENT "headers")
+set(EXPECTED_FILE_CONTENT_3_LIST "/bar;/bar/CMakeLists.txt")
+set(EXPECTED_FILE_4_COMPONENT "libs")
+set(EXPECTED_FILE_CONTENT_4_LIST "/bas;/bas/libtest_lib.so")
+set(EXPECTED_FILE_5_COMPONENT "libs_auto")
+set(EXPECTED_FILE_CONTENT_5_LIST "/bas_auto;/bas_auto/libtest_lib.so")
+
+if(GENERATOR_TYPE STREQUAL "DEB")
+ set(whitespaces_ "[\t\n\r ]*")
+ # dynamic lib extension is .so on Linux and .dylib on Mac so we will use a wildcard .* for it
+ set(EXPECTED_FILE_CONTENT_4 "^.*/usr/bas${whitespaces_}.*/usr/bas/libtest_lib\\..*$")
+ set(EXPECTED_FILE_CONTENT_5 "^.*/usr/bas_auto${whitespaces_}.*/usr/bas_auto/libtest_lib\\..*$")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/DEPENDENCIES/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/DEPENDENCIES/VerifyResult.cmake
new file mode 100644
index 0000000..7923148
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEPENDENCIES/VerifyResult.cmake
@@ -0,0 +1,82 @@
+if(GENERATOR_TYPE STREQUAL "DEB")
+ function(checkDependencies_ FILE REGEX)
+ set(whitespaces_ "[\t\n\r ]*")
+
+ getPackageInfo("${FILE}" "FILE_INFO_")
+ if(NOT FILE_INFO_ MATCHES "${REGEX}")
+ message(FATAL_ERROR "Unexpected dependencies in '${FILE}'; file info: '${FILE_INFO_}'")
+ endif()
+ endfunction()
+
+ foreach(dependency_type_ DEPENDS CONFLICTS ENHANCES BREAKS REPLACES RECOMMENDS SUGGESTS)
+ string(TOLOWER "${dependency_type_}" lower_dependency_type_)
+ string(SUBSTRING ${lower_dependency_type_} 1 -1 lower_dependency_type_tail_)
+ string(SUBSTRING ${dependency_type_} 0 1 dependency_type_head_)
+ set(dependency_type_name_ "${dependency_type_head_}${lower_dependency_type_tail_}")
+
+ checkDependencies_("${FOUND_FILE_1}" ".*${dependency_type_name_}${whitespaces_}:${whitespaces_}${lower_dependency_type_}-application, ${lower_dependency_type_}-application-b.*")
+ checkDependencies_("${FOUND_FILE_2}" ".*${dependency_type_name_}${whitespaces_}:${whitespaces_}.*${lower_dependency_type_}-application, ${lower_dependency_type_}-application-b.*")
+ checkDependencies_("${FOUND_FILE_3}" ".*${dependency_type_name_}${whitespaces_}:${whitespaces_}${lower_dependency_type_}-headers.*")
+ checkDependencies_("${FOUND_FILE_4}" ".*${dependency_type_name_}${whitespaces_}:${whitespaces_}${lower_dependency_type_}-default, ${lower_dependency_type_}-default-b.*")
+ checkDependencies_("${FOUND_FILE_5}" ".*${dependency_type_name_}${whitespaces_}:${whitespaces_}${lower_dependency_type_}-default, ${lower_dependency_type_}-default-b.*")
+ endforeach()
+
+ checkDependencies_("${FOUND_FILE_1}" ".*Provides${whitespaces_}:${whitespaces_}provided-default, provided-default-b")
+ checkDependencies_("${FOUND_FILE_2}" ".*Provides${whitespaces_}:${whitespaces_}provided-default, provided-default-b")
+ checkDependencies_("${FOUND_FILE_3}" ".*Provides${whitespaces_}:${whitespaces_}provided-default, provided-default-b")
+ checkDependencies_("${FOUND_FILE_4}" ".*Provides${whitespaces_}:${whitespaces_}provided-lib.*")
+ checkDependencies_("${FOUND_FILE_5}" ".*Provides${whitespaces_}:${whitespaces_}provided-lib_auto.*, provided-lib_auto-b.*")
+
+ # PREDEPENDS
+ checkDependencies_("${FOUND_FILE_1}" ".*Pre-Depends${whitespaces_}:${whitespaces_}predepends-application, predepends-application-b.*")
+ checkDependencies_("${FOUND_FILE_2}" ".*Pre-Depends${whitespaces_}:${whitespaces_}.*predepends-application, predepends-application-b.*")
+ checkDependencies_("${FOUND_FILE_3}" ".*Pre-Depends${whitespaces_}:${whitespaces_}predepends-headers.*")
+ checkDependencies_("${FOUND_FILE_4}" ".*Pre-Depends${whitespaces_}:${whitespaces_}predepends-default, predepends-default-b.*")
+ checkDependencies_("${FOUND_FILE_5}" ".*Pre-Depends${whitespaces_}:${whitespaces_}predepends-default, predepends-default-b.*")
+elseif(GENERATOR_TYPE STREQUAL "RPM")
+ function(checkDependencies_ FILE TYPE COMPARE_LIST)
+ set(whitespaces_ "[\t\n\r ]*")
+
+ execute_process(COMMAND ${RPM_EXECUTABLE} -qp --${TYPE} ${FILE}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE FILE_DEPENDENCIES_
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ string(REPLACE "\n" ";" FILE_DEPENDENCIES_LIST_ "${FILE_DEPENDENCIES_}")
+
+ foreach(COMPARE_REGEX_ IN LISTS COMPARE_LIST)
+ unset(FOUND_)
+
+ foreach(COMPARE_ IN LISTS FILE_DEPENDENCIES_LIST_)
+ if(COMPARE_ MATCHES "${COMPARE_REGEX_}")
+ set(FOUND_ true)
+ break()
+ endif()
+ endforeach()
+
+ if(NOT FOUND_)
+ message(FATAL_ERROR "Missing dependencies in '${FILE}'; check type: '${TYPE}'; file info: '${FILE_DEPENDENCIES_}'; missing: '${COMPARE_REGEX_}'")
+ endif()
+ endforeach()
+ endfunction()
+
+ # TODO add tests for what should not be present in lists
+ checkDependencies_("${FOUND_FILE_1}" "requires" "depend-application;depend-application-b")
+ checkDependencies_("${FOUND_FILE_2}" "requires" "depend-application;depend-application-b;libtest_lib\\.so.*")
+ checkDependencies_("${FOUND_FILE_3}" "requires" "depend-headers")
+ checkDependencies_("${FOUND_FILE_4}" "requires" "depend-default;depend-default-b")
+ checkDependencies_("${FOUND_FILE_5}" "requires" "depend-default;depend-default-b")
+
+ checkDependencies_("${FOUND_FILE_1}" "conflicts" "conflicts-application;conflicts-application-b")
+ checkDependencies_("${FOUND_FILE_2}" "conflicts" "conflicts-application;conflicts-application-b")
+ checkDependencies_("${FOUND_FILE_3}" "conflicts" "conflicts-headers")
+ checkDependencies_("${FOUND_FILE_4}" "conflicts" "conflicts-default;conflicts-default-b")
+ checkDependencies_("${FOUND_FILE_5}" "conflicts" "conflicts-default;conflicts-default-b")
+
+ checkDependencies_("${FOUND_FILE_1}" "provides" "provided-default;provided-default-b")
+ checkDependencies_("${FOUND_FILE_2}" "provides" "provided-default;provided-default-b")
+ checkDependencies_("${FOUND_FILE_3}" "provides" "provided-default;provided-default-b")
+ checkDependencies_("${FOUND_FILE_4}" "provides" "provided-lib")
+ checkDependencies_("${FOUND_FILE_5}" "provides" "provided-lib_auto;provided-lib_auto-b")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/DEPENDENCIES/test.cmake b/Tests/RunCMake/CPack/tests/DEPENDENCIES/test.cmake
new file mode 100644
index 0000000..fbd786e
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DEPENDENCIES/test.cmake
@@ -0,0 +1,60 @@
+if(GENERATOR_TYPE STREQUAL "DEB" OR GENERATOR_TYPE STREQUAL "RPM")
+ if(GENERATOR_TYPE STREQUAL "DEB")
+ # false by default
+ set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS FALSE)
+ # FIXME can not be tested as libraries first have to be part of a package in order
+ # to determine their dependencies and we can not be certain if there will be any
+ set(CPACK_DEBIAN_APPLICATIONS_AUTO_PACKAGE_SHLIBDEPS TRUE)
+
+ foreach(dependency_type_ DEPENDS PREDEPENDS ENHANCES BREAKS REPLACES RECOMMENDS SUGGESTS)
+ string(TOLOWER "${dependency_type_}" lower_dependency_type_)
+
+ set(CPACK_DEBIAN_PACKAGE_${dependency_type_} "${lower_dependency_type_}-default, ${lower_dependency_type_}-default-b")
+ set(CPACK_DEBIAN_APPLICATIONS_PACKAGE_${dependency_type_} "${lower_dependency_type_}-application, ${lower_dependency_type_}-application-b")
+ set(CPACK_DEBIAN_APPLICATIONS_AUTO_PACKAGE_${dependency_type_} "${lower_dependency_type_}-application, ${lower_dependency_type_}-application-b")
+ set(CPACK_DEBIAN_HEADERS_PACKAGE_${dependency_type_} "${lower_dependency_type_}-headers")
+ endforeach()
+
+ set(generator_type_suffix_ "IAN") # not entirely compatible...
+ else() # RPM
+ # FIXME auto autoprov is not tested at the moment as Ubuntu 15.04 rpmbuild
+ # does not use them correctly: https://bugs.launchpad.net/rpm/+bug/1475755
+ set(CPACK_RPM_PACKAGE_AUTOREQ "no")
+ set(CPACK_RPM_PACKAGE_AUTOPROV "no")
+ set(CPACK_RPM_APPLICATIONS_AUTO_PACKAGE_AUTOREQPROV "yes")
+ set(CPACK_RPM_LIBS_AUTO_PACKAGE_AUTOREQPROV "yes")
+
+ set(CPACK_RPM_PACKAGE_REQUIRES "depend-default, depend-default-b")
+ set(CPACK_RPM_APPLICATIONS_PACKAGE_REQUIRES "depend-application, depend-application-b")
+ set(CPACK_RPM_APPLICATIONS_AUTO_PACKAGE_REQUIRES "depend-application, depend-application-b")
+ set(CPACK_RPM_HEADERS_PACKAGE_REQUIRES "depend-headers")
+ endif()
+
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_PACKAGE_CONFLICTS "conflicts-default, conflicts-default-b")
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_APPLICATIONS_PACKAGE_CONFLICTS "conflicts-application, conflicts-application-b")
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_APPLICATIONS_AUTO_PACKAGE_CONFLICTS "conflicts-application, conflicts-application-b")
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_HEADERS_PACKAGE_CONFLICTS "conflicts-headers")
+
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_PACKAGE_PROVIDES "provided-default, provided-default-b")
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_LIBS_PACKAGE_PROVIDES "provided-lib")
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_LIBS_AUTO_PACKAGE_PROVIDES "provided-lib_auto, provided-lib_auto-b")
+endif()
+
+set(CMAKE_BUILD_WITH_INSTALL_RPATH 1)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.hpp"
+ "int test_lib();\n")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp"
+ "#include \"test_lib.hpp\"\nint test_lib() {return 0;}\n")
+add_library(test_lib SHARED "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+ "#include \"test_lib.hpp\"\nint main() {return test_lib();}\n")
+add_executable(test_prog "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+target_link_libraries(test_prog test_lib)
+
+install(TARGETS test_prog DESTINATION foo COMPONENT applications)
+install(TARGETS test_prog DESTINATION foo_auto COMPONENT applications_auto)
+install(FILES CMakeLists.txt DESTINATION bar COMPONENT headers)
+install(TARGETS test_lib DESTINATION bas COMPONENT libs)
+install(TARGETS test_lib DESTINATION bas_auto COMPONENT libs_auto)
diff --git a/Tests/RunCMake/CPack/tests/DIST/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/DIST/ExpectedFiles.cmake
new file mode 100644
index 0000000..d1a3a5f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DIST/ExpectedFiles.cmake
@@ -0,0 +1,2 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/DIST/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/DIST/VerifyResult.cmake
new file mode 100644
index 0000000..1b2eb48
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DIST/VerifyResult.cmake
@@ -0,0 +1,16 @@
+execute_process(COMMAND ${RPMBUILD_EXECUTABLE} -E %{?dist}
+ OUTPUT_VARIABLE DIST_TAG
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+set(whitespaces_ "[\t\n\r ]*")
+
+# since we have no control over dist tag value we should try to escape
+# the content for use as a regular expression
+string(REPLACE "+" "\\+" DIST_TAG "${DIST_TAG}")
+string(REPLACE "." "\\." DIST_TAG "${DIST_TAG}")
+
+getPackageInfo("${FOUND_FILE_1}" "FILE_INFO_")
+if(NOT FILE_INFO_ MATCHES ".*Release${whitespaces_}:${whitespaces_}1${DIST_TAG}")
+ message(FATAL_ERROR "Unexpected Release in '${FOUND_FILE_1}'; file info: '${FILE_INFO_}'")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/DIST/test.cmake b/Tests/RunCMake/CPack/tests/DIST/test.cmake
new file mode 100644
index 0000000..6bdd2c0
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DIST/test.cmake
@@ -0,0 +1,3 @@
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
+
+set(CPACK_RPM_PACKAGE_RELEASE_DIST ON)
diff --git a/Tests/RunCMake/CPack/tests/DMG_SLA/English.license.rtf b/Tests/RunCMake/CPack/tests/DMG_SLA/English.license.rtf
new file mode 100644
index 0000000..c1da711
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DMG_SLA/English.license.rtf
@@ -0,0 +1,7 @@
+{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Calibri;}}
+{\colortbl ;\red0\green0\blue255;}
+{\*\generator Riched20 10.0.18362}\viewkind4\uc1
+\pard\sa200\sl276\slmult1\b\f0\fs22\lang9 LICENSE\b0\par
+This is an installer created using CPack ({{\field{\*\fldinst{HYPERLINK https://cmake.org }}{\fldrslt{https://cmake.org\ul0\cf0}}}}\f0\fs22 ). No license provided.\par
+\par
+}
diff --git a/Tests/RunCMake/CPack/tests/DMG_SLA/English.menu.txt b/Tests/RunCMake/CPack/tests/DMG_SLA/English.menu.txt
new file mode 100644
index 0000000..b2cbc25
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DMG_SLA/English.menu.txt
@@ -0,0 +1,9 @@
+English
+Agree
+Disagree
+Print
+Save...
+You agree to the License Agreement terms when you click the "Agree" button.
+Software License Agreement
+This text cannot be saved. This disk may be full or locked or the file may be locked.
+Unable to print. Make sure you have selected a printer.
diff --git a/Tests/RunCMake/CPack/tests/DMG_SLA/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/DMG_SLA/ExpectedFiles.cmake
new file mode 100644
index 0000000..d1a3a5f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DMG_SLA/ExpectedFiles.cmake
@@ -0,0 +1,2 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/DMG_SLA/German.license.txt b/Tests/RunCMake/CPack/tests/DMG_SLA/German.license.txt
new file mode 100644
index 0000000..0edd1f2
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DMG_SLA/German.license.txt
@@ -0,0 +1,3 @@
+LIZENZ
+------
+Dies ist ein Installationsprogramm, das mit erstellt wurde CPack (https://cmake.org). Keine Lizenz angegeben.
diff --git a/Tests/RunCMake/CPack/tests/DMG_SLA/German.menu.txt b/Tests/RunCMake/CPack/tests/DMG_SLA/German.menu.txt
new file mode 100644
index 0000000..7724818
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DMG_SLA/German.menu.txt
@@ -0,0 +1,9 @@
+German
+Akzeptieren
+Ablehnen
+Drucken
+Speichern...
+Klicken Sie auf "Akzeptieren", wenn Sie mit den Bestimmungen des Software-Lizenzvertrages einverstanden sind.
+Software-Lizenzvertrag
+Dieser Text kann nicht gesichert werden. Diese Festplatte ist mšglicherweise voll oder geschŸtzt oder der Ordner ist geschŸtzt.
+Es kann nicht gedruckt werden. Bitte stellen Sie sicher, dass ein Drucker ausgewŠhlt ist.
diff --git a/Tests/RunCMake/CPack/tests/DMG_SLA/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/DMG_SLA/VerifyResult.cmake
new file mode 100644
index 0000000..010e14c
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DMG_SLA/VerifyResult.cmake
@@ -0,0 +1,33 @@
+set(dmg "${bin_dir}/${FOUND_FILE_1}")
+execute_process(COMMAND hdiutil udifderez -xml "${dmg}" OUTPUT_VARIABLE out ERROR_VARIABLE err RESULT_VARIABLE res)
+if(NOT res EQUAL 0)
+ string(REPLACE "\n" "\n " err " ${err}")
+ message(FATAL_ERROR "Running 'hdiutil udifderez -xml' on\n ${dmg}\nfailed with:\n${err}")
+endif()
+foreach(key "LPic" "STR#" "TEXT" "RTF ")
+ if(NOT out MATCHES "<key>${key}</key>")
+ string(REPLACE "\n" "\n " out " ${out}")
+ message(FATAL_ERROR "error: running 'hdiutil udifderez -xml' on\n ${dmg}\ndid not show '${key}' key:\n${out}")
+ endif()
+endforeach()
+foreach(line
+ # LPic
+ "\tAAAAAgAAAAAAAAADAAEAAA==\n"
+ # STR# English first and last base64 lines
+ "\tAAkHRW5nbGlzaAVBZ3JlZQhEaXNhZ3JlZQVQcmludAdTYXZlLi4u\n"
+ "\tZCBhIHByaW50ZXIu\n"
+ # STR# German first and last base64 lines
+ "\tAAkGR2VybWFuC0FremVwdGllcmVuCEFibGVobmVuB0RydWNrZW4M\n"
+ "\tYXVzZ2V3wopobHQgaXN0Lg==\n"
+ # RTF English first and last base64 lines
+ "\te1xydGYxXGFuc2lcYW5zaWNwZzEyNTJcZGVmZjBcbm91aWNvbXBh\n"
+ "\tdmlkZWQuXHBhcg1ccGFyDX0NDQ==\n"
+ # TEXT German first and last base64 lines
+ "\tTElaRU5aDS0tLS0tLQ1EaWVzIGlzdCBlaW4gSW5zdGFsbGF0aW9u\n"
+ "\tZ2ViZW4uDQ0=\n"
+ )
+ if(NOT out MATCHES "${line}")
+ string(REPLACE "\n" "\n " out " ${out}")
+ message(FATAL_ERROR "error: running 'hdiutil udifderez -xml' on\n ${dmg}\ndid not show '${line}':\n${out}")
+ endif()
+endforeach()
diff --git a/Tests/RunCMake/CPack/tests/DMG_SLA/test.cmake b/Tests/RunCMake/CPack/tests/DMG_SLA/test.cmake
new file mode 100644
index 0000000..2804b0b
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/DMG_SLA/test.cmake
@@ -0,0 +1,3 @@
+install(FILES CMakeLists.txt DESTINATION foo)
+set(CPACK_DMG_SLA_DIR "${CMAKE_CURRENT_LIST_DIR}")
+set(CPACK_DMG_SLA_LANGUAGES English German)
diff --git a/Tests/RunCMake/CPack/tests/EMPTY_DIR/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/EMPTY_DIR/ExpectedFiles.cmake
new file mode 100644
index 0000000..8df6831
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EMPTY_DIR/ExpectedFiles.cmake
@@ -0,0 +1,7 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
+set(EXPECTED_FILE_CONTENT_1_LIST "/empty")
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(EXPECTED_FILE_1_COMPONENT "test")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/EMPTY_DIR/test.cmake b/Tests/RunCMake/CPack/tests/EMPTY_DIR/test.cmake
new file mode 100644
index 0000000..cd2c9fd
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EMPTY_DIR/test.cmake
@@ -0,0 +1,14 @@
+if(GENERATOR_TYPE STREQUAL "DEB" OR GENERATOR_TYPE STREQUAL "RPM")
+ if(GENERATOR_TYPE STREQUAL "DEB")
+ set(generator_type_suffix_ "IAN") # not entirely compatible...
+ endif()
+
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_FILE_NAME "${GENERATOR_TYPE}-DEFAULT")
+endif()
+
+install(DIRECTORY DESTINATION empty
+ COMPONENT test)
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(CPACK_COMPONENTS_ALL test)
+endif()
diff --git a/Tests/RunCMake/CPack/tests/EXTERNAL/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/EXTERNAL/ExpectedFiles.cmake
new file mode 100644
index 0000000..91608c9
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTERNAL/ExpectedFiles.cmake
@@ -0,0 +1,7 @@
+if(RunCMake_SUBTEST_SUFFIX MATCHES "^(none|good(_multi)?|invalid_good)$"
+ OR RunCMake_SUBTEST_SUFFIX STREQUAL "stage_and_package")
+ set(EXPECTED_FILES_COUNT "1")
+ set(EXPECTED_FILE_CONTENT_1_LIST "/share;/share/cpack-test;/share/cpack-test/f1.txt;/share/cpack-test/f2.txt;/share/cpack-test/f3.txt;/share/cpack-test/f4.txt")
+else()
+ set(EXPECTED_FILES_COUNT "0")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/EXTERNAL/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/EXTERNAL/VerifyResult.cmake
new file mode 100644
index 0000000..bc19d7e
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTERNAL/VerifyResult.cmake
@@ -0,0 +1,3 @@
+if(RunCMake_SUBTEST_SUFFIX MATCHES "^(none|good(_multi)?|invalid_good)")
+ check_ext_json("${src_dir}/tests/EXTERNAL/expected-json-1.0.txt" "${FOUND_FILE_1}")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/EXTERNAL/bad_major-stderr.txt b/Tests/RunCMake/CPack/tests/EXTERNAL/bad_major-stderr.txt
new file mode 100644
index 0000000..f2e160e
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTERNAL/bad_major-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at .*/Modules/Internal/CPack/CPackExternal\.cmake:[0-9]+ \(message\):
+ Could not find a suitable version in CPACK_EXTERNAL_REQUESTED_VERSIONS
+
+
+CPack Error: Error while executing CPackExternal\.cmake
+CPack Error: Cannot initialize the generator External
diff --git a/Tests/RunCMake/CPack/tests/EXTERNAL/bad_minor-stderr.txt b/Tests/RunCMake/CPack/tests/EXTERNAL/bad_minor-stderr.txt
new file mode 100644
index 0000000..f2e160e
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTERNAL/bad_minor-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at .*/Modules/Internal/CPack/CPackExternal\.cmake:[0-9]+ \(message\):
+ Could not find a suitable version in CPACK_EXTERNAL_REQUESTED_VERSIONS
+
+
+CPack Error: Error while executing CPackExternal\.cmake
+CPack Error: Cannot initialize the generator External
diff --git a/Tests/RunCMake/CPack/tests/EXTERNAL/create_package.cmake b/Tests/RunCMake/CPack/tests/EXTERNAL/create_package.cmake
new file mode 100644
index 0000000..3db8014
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTERNAL/create_package.cmake
@@ -0,0 +1,39 @@
+message("This script could run an external packaging tool")
+
+get_property(role GLOBAL PROPERTY CMAKE_ROLE)
+if(NOT role STREQUAL "CPACK")
+ message(SEND_ERROR "CMAKE_ROLE property is \"${role}\", should be \"CPACK\"")
+endif()
+
+function(expect_variable VAR)
+ if(NOT ${VAR})
+ message(FATAL_ERROR "${VAR} is unexpectedly not set")
+ endif()
+endfunction()
+
+function(expect_file FILE)
+ if(NOT EXISTS "${FILE}")
+ message(FATAL_ERROR "${FILE} is unexpectedly missing")
+ endif()
+endfunction()
+
+expect_variable(CPACK_COMPONENTS_ALL)
+expect_variable(CPACK_TOPLEVEL_DIRECTORY)
+expect_variable(CPACK_TEMPORARY_DIRECTORY)
+expect_variable(CPACK_PACKAGE_DIRECTORY)
+expect_variable(CPACK_PACKAGE_FILE_NAME)
+
+expect_file(${CPACK_TEMPORARY_DIRECTORY}/f1/share/cpack-test/f1.txt)
+expect_file(${CPACK_TEMPORARY_DIRECTORY}/f2/share/cpack-test/f2.txt)
+expect_file(${CPACK_TEMPORARY_DIRECTORY}/f3/share/cpack-test/f3.txt)
+expect_file(${CPACK_TEMPORARY_DIRECTORY}/f4/share/cpack-test/f4.txt)
+
+message(STATUS "This status message is expected to be visible")
+
+set(
+ CPACK_EXTERNAL_BUILT_PACKAGES
+ ${CPACK_TEMPORARY_DIRECTORY}/f1/share/cpack-test/f1.txt
+ ${CPACK_TEMPORARY_DIRECTORY}/f2/share/cpack-test/f2.txt
+ ${CPACK_TEMPORARY_DIRECTORY}/f3/share/cpack-test/f3.txt
+ ${CPACK_TEMPORARY_DIRECTORY}/f4/share/cpack-test/f4.txt
+ )
diff --git a/Tests/RunCMake/CPack/tests/EXTERNAL/expected-json-1.0.txt b/Tests/RunCMake/CPack/tests/EXTERNAL/expected-json-1.0.txt
new file mode 100644
index 0000000..ca25b1e
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTERNAL/expected-json-1.0.txt
@@ -0,0 +1,177 @@
+^\{
+ ("buildConfig" : "Debug",
+)? "componentGroups" :[ ]
+ \{
+ "f12" :[ ]
+ \{
+ "components" :[ ]
+ \[
+ "f1",
+ "f2"
+ \],
+ "description" : "Component group for files 1 and 2",
+ "displayName" : "Files 1 and 2",
+ "isBold" : false,
+ "isExpandedByDefault" : false,
+ "name" : "f12",
+ "parentGroup" : "f1234",
+ "subgroups" : \[\]
+ \},
+ "f1234" :[ ]
+ \{
+ "components" : \[\],
+ "description" : "Component group for all files",
+ "displayName" : "Files 1-4",
+ "isBold" : false,
+ "isExpandedByDefault" : false,
+ "name" : "f1234",
+ "subgroups" :[ ]
+ \[
+ "f12",
+ "f34"
+ \]
+ \},
+ "f34" :[ ]
+ \{
+ "components" :[ ]
+ \[
+ "f3",
+ "f4"
+ \],
+ "description" : "Component group for files 3 and 4",
+ "displayName" : "Files 3 and 4",
+ "isBold" : false,
+ "isExpandedByDefault" : false,
+ "name" : "f34",
+ "parentGroup" : "f1234",
+ "subgroups" : \[\]
+ \}
+ \},
+ "components" :[ ]
+ \{
+ "f1" :[ ]
+ \{
+ "archiveFile" : "",
+ "dependencies" : \[\],
+ "description" : "Component for file 1",
+ "displayName" : "File 1",
+ "group" : "f12",
+ "installationTypes" :[ ]
+ \[
+ "full",
+ "f12"
+ \],
+ "isDisabledByDefault" : false,
+ "isDownloaded" : false,
+ "isHidden" : false,
+ "isRequired" : false,
+ "name" : "f1"
+ \},
+ "f2" :[ ]
+ \{
+ "archiveFile" : "",
+ "dependencies" :[ ]
+ \[
+ "f1"
+ \],
+ "description" : "Component for file 2",
+ "displayName" : "File 2",
+ "group" : "f12",
+ "installationTypes" :[ ]
+ \[
+ "full",
+ "f12"
+ \],
+ "isDisabledByDefault" : false,
+ "isDownloaded" : false,
+ "isHidden" : false,
+ "isRequired" : false,
+ "name" : "f2"
+ \},
+ "f3" :[ ]
+ \{
+ "archiveFile" : "",
+ "dependencies" :[ ]
+ \[
+ "f1",
+ "f2"
+ \],
+ "description" : "Component for file 3",
+ "displayName" : "File 3",
+ "group" : "f34",
+ "installationTypes" :[ ]
+ \[
+ "full"
+ \],
+ "isDisabledByDefault" : false,
+ "isDownloaded" : false,
+ "isHidden" : false,
+ "isRequired" : false,
+ "name" : "f3"
+ \},
+ "f4" :[ ]
+ \{
+ "archiveFile" : "",
+ "dependencies" :[ ]
+ \[
+ "f2",
+ "f3",
+ "f1"
+ \],
+ "description" : "Component for file 4",
+ "displayName" : "File 4",
+ "group" : "f34",
+ "installationTypes" :[ ]
+ \[
+ "full"
+ \],
+ "isDisabledByDefault" : false,
+ "isDownloaded" : false,
+ "isHidden" : false,
+ "isRequired" : false,
+ "name" : "f4"
+ \}
+ \},
+ "errorOnAbsoluteInstallDestination" : false,
+ "formatVersionMajor" : 1,
+ "formatVersionMinor" : 0,
+ "installationTypes" :[ ]
+ \{
+ "f12" :[ ]
+ \{
+ "displayName" : "Only files 1 and 2",
+ "index" : 2,
+ "name" : "f12"
+ \},
+ "full" :[ ]
+ \{
+ "displayName" : "Full installation",
+ "index" : 1,
+ "name" : "full"
+ \}
+ \},
+ "packageDescriptionFile" : ".*/Templates/CPack\.GenericDescription\.txt",
+ "packageDescriptionSummary" : "EXTERNAL-(none|good(_multi)?|invalid_good)-subtest-(MONOLITHIC|COMPONENT)-type built using CMake",
+ "packageName" : "external",
+ "packageVersion" : "0\.1\.1",
+ "projects" :[ ]
+ \[
+ \{
+ "component" : "ALL",
+ "components" :[ ]
+ \[
+ "f1",
+ "f2",
+ "f3",
+ "f4"
+ \],
+ "directory" : ".*/Tests/RunCMake/External/CPack/EXTERNAL-build-(none|good(_multi)?|invalid_good)-subtest",
+ "installationTypes" : \[\],
+ "projectName" : "EXTERNAL-(none|good(_multi)?|invalid_good)-subtest-(MONOLITHIC|COMPONENT)-type",
+ "subDirectory" : "/"
+ \}
+ \],
+ "setDestdir" : false,
+ "stripFiles" : false,
+ "warnOnAbsoluteInstallDestination" : false
+\}$
diff --git a/Tests/RunCMake/CPack/tests/EXTERNAL/invalid_bad-stderr.txt b/Tests/RunCMake/CPack/tests/EXTERNAL/invalid_bad-stderr.txt
new file mode 100644
index 0000000..f2e160e
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTERNAL/invalid_bad-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at .*/Modules/Internal/CPack/CPackExternal\.cmake:[0-9]+ \(message\):
+ Could not find a suitable version in CPACK_EXTERNAL_REQUESTED_VERSIONS
+
+
+CPack Error: Error while executing CPackExternal\.cmake
+CPack Error: Cannot initialize the generator External
diff --git a/Tests/RunCMake/CPack/tests/EXTERNAL/stage_and_package-stderr.txt b/Tests/RunCMake/CPack/tests/EXTERNAL/stage_and_package-stderr.txt
new file mode 100644
index 0000000..40f2743
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTERNAL/stage_and_package-stderr.txt
@@ -0,0 +1 @@
+^This script could run an external packaging tool$
diff --git a/Tests/RunCMake/CPack/tests/EXTERNAL/stage_and_package-stdout.txt b/Tests/RunCMake/CPack/tests/EXTERNAL/stage_and_package-stdout.txt
new file mode 100644
index 0000000..587b2e8
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTERNAL/stage_and_package-stdout.txt
@@ -0,0 +1,11 @@
+-- This status message is expected to be visible
+CPack: - package: .*/Tests/RunCMake/External/CPack/EXTERNAL-build-stage_and_package-subtest/external-0\.1\.1-.*\.json generated\.
+CPack: - checksum file: .*/Tests/RunCMake/External/CPack/EXTERNAL-build-stage_and_package-subtest/external-0\.1\.1-.*\.json\.sha1 generated\.
+CPack: - package: .*/Tests/RunCMake/External/CPack/EXTERNAL-build-stage_and_package-subtest/f1\.txt generated\.
+CPack: - checksum file: .*/Tests/RunCMake/External/CPack/EXTERNAL-build-stage_and_package-subtest/f1\.txt\.sha1 generated\.
+CPack: - package: .*/Tests/RunCMake/External/CPack/EXTERNAL-build-stage_and_package-subtest/f2\.txt generated\.
+CPack: - checksum file: .*/Tests/RunCMake/External/CPack/EXTERNAL-build-stage_and_package-subtest/f2\.txt\.sha1 generated\.
+CPack: - package: .*/Tests/RunCMake/External/CPack/EXTERNAL-build-stage_and_package-subtest/f3\.txt generated\.
+CPack: - checksum file: .*/Tests/RunCMake/External/CPack/EXTERNAL-build-stage_and_package-subtest/f3\.txt\.sha1 generated\.
+CPack: - package: .*/Tests/RunCMake/External/CPack/EXTERNAL-build-stage_and_package-subtest/f4\.txt generated\.
+CPack: - checksum file: .*/Tests/RunCMake/External/CPack/EXTERNAL-build-stage_and_package-subtest/f4\.txt\.sha1 generated\.
diff --git a/Tests/RunCMake/CPack/tests/EXTERNAL/test.cmake b/Tests/RunCMake/CPack/tests/EXTERNAL/test.cmake
new file mode 100644
index 0000000..d4781ba
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTERNAL/test.cmake
@@ -0,0 +1,87 @@
+include(CPackComponent)
+
+if(RunCMake_SUBTEST_SUFFIX STREQUAL "none")
+ unset(CPACK_EXTERNAL_REQUESTED_VERSIONS)
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "good")
+ set(CPACK_EXTERNAL_REQUESTED_VERSIONS "1.0")
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "good_multi")
+ set(CPACK_EXTERNAL_REQUESTED_VERSIONS "1.0;2.0")
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "bad_major")
+ set(CPACK_EXTERNAL_REQUESTED_VERSIONS "2.0")
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "bad_minor")
+ set(CPACK_EXTERNAL_REQUESTED_VERSIONS "1.1")
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "invalid_good")
+ set(CPACK_EXTERNAL_REQUESTED_VERSIONS "1;1.0")
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "invalid_bad")
+ set(CPACK_EXTERNAL_REQUESTED_VERSIONS "1")
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "stage_and_package")
+ set(CPACK_EXTERNAL_ENABLE_STAGING 1)
+ set(CPACK_EXTERNAL_PACKAGE_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/create_package.cmake")
+ set(CPACK_PACKAGE_CHECKSUM SHA1)
+endif()
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/f1.txt" test1)
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/f2.txt" test2)
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/f3.txt" test3)
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/f4.txt" test4)
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/f1.txt" DESTINATION share/cpack-test COMPONENT f1)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/f2.txt" DESTINATION share/cpack-test COMPONENT f2)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/f3.txt" DESTINATION share/cpack-test COMPONENT f3)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/f4.txt" DESTINATION share/cpack-test COMPONENT f4)
+
+cpack_add_component(f1
+ DISPLAY_NAME "File 1"
+ DESCRIPTION "Component for file 1"
+ GROUP f12
+ INSTALL_TYPES full f12
+)
+
+cpack_add_component(f2
+ DISPLAY_NAME "File 2"
+ DESCRIPTION "Component for file 2"
+ GROUP f12
+ DEPENDS f1
+ INSTALL_TYPES full f12
+)
+
+cpack_add_component(f3
+ DISPLAY_NAME "File 3"
+ DESCRIPTION "Component for file 3"
+ GROUP f34
+ DEPENDS f1 f2
+ INSTALL_TYPES full
+)
+
+cpack_add_component(f4
+ DISPLAY_NAME "File 4"
+ DESCRIPTION "Component for file 4"
+ GROUP f34
+ DEPENDS f2 f3 f1
+ INSTALL_TYPES full
+)
+
+cpack_add_component_group(f12
+ DISPLAY_NAME "Files 1 and 2"
+ DESCRIPTION "Component group for files 1 and 2"
+ PARENT_GROUP f1234
+)
+
+cpack_add_component_group(f34
+ DISPLAY_NAME "Files 3 and 4"
+ DESCRIPTION "Component group for files 3 and 4"
+ PARENT_GROUP f1234
+)
+
+cpack_add_component_group(f1234
+ DISPLAY_NAME "Files 1-4"
+ DESCRIPTION "Component group for all files"
+)
+
+cpack_add_install_type(full
+ DISPLAY_NAME "Full installation"
+)
+
+cpack_add_install_type(f12
+ DISPLAY_NAME "Only files 1 and 2"
+)
diff --git a/Tests/RunCMake/CPack/tests/EXTRA/DEB-stderr.txt b/Tests/RunCMake/CPack/tests/EXTRA/DEB-stderr.txt
new file mode 100644
index 0000000..37360e8
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTRA/DEB-stderr.txt
@@ -0,0 +1,6 @@
+CPack Warning: Adding file to tar:
+#top level directory: .*/Tests/RunCMake/DEB.EXTRA/CPack/EXTRA-build/_CPack_Packages/Linux/DEB/extra-0.1.1-Linux/bas
+#missing file: .*/Tests/RunCMake/DEB.EXTRA/CPack/EXTRA-build/conffiles
+CPack Warning: Adding file to tar:
+#top level directory: .*/Tests/RunCMake/DEB.EXTRA/CPack/EXTRA-build/_CPack_Packages/Linux/DEB/extra-0.1.1-Linux/foo
+#missing file: .*/Tests/RunCMake/DEB.EXTRA/CPack/EXTRA-build/conffiles
diff --git a/Tests/RunCMake/CPack/tests/EXTRA/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/EXTRA/ExpectedFiles.cmake
new file mode 100644
index 0000000..407cbe6
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTRA/ExpectedFiles.cmake
@@ -0,0 +1,8 @@
+set(EXPECTED_FILES_COUNT "3")
+set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
+set(EXPECTED_FILE_1_COMPONENT "foo")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
+set(EXPECTED_FILE_2_COMPONENT "bar")
+set(EXPECTED_FILE_CONTENT_2_LIST "/bar;/bar/CMakeLists.txt")
+set(EXPECTED_FILE_3_COMPONENT "bas")
+set(EXPECTED_FILE_CONTENT_3_LIST "/bas;/bas/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/EXTRA/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/EXTRA/VerifyResult.cmake
new file mode 100644
index 0000000..85e137f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTRA/VerifyResult.cmake
@@ -0,0 +1,18 @@
+set(foo_preinst "^echo default_preinst$")
+# NOTE: optional dot at the end of permissions regex is for SELinux enabled systems
+set(foo_preinst_permissions_regex "-rwxr-xr-x\.? .*")
+set(foo_prerm "^echo default_prerm$")
+set(foo_prerm_permissions_regex "-rwxr-xr-x\.? .*")
+verifyDebControl("${FOUND_FILE_1}" "foo" "preinst;prerm")
+
+set(bar_preinst "^echo bar_preinst$")
+set(bar_preinst_permissions_regex "-rwx------\.? .*")
+set(bar_prerm "^echo bar_prerm$")
+set(bar_prerm_permissions_regex "-rwx------\.? .*")
+verifyDebControl("${FOUND_FILE_2}" "bar" "preinst;prerm")
+
+set(bas_preinst "^echo default_preinst$")
+set(bas_preinst_permissions_regex "-rwxr-xr-x\.? .*")
+set(bas_prerm "^echo default_prerm$")
+set(bas_prerm_permissions_regex "-rwxr-xr-x\.? .*")
+verifyDebControl("${FOUND_FILE_3}" "bas" "preinst;prerm")
diff --git a/Tests/RunCMake/CPack/tests/EXTRA/test.cmake b/Tests/RunCMake/CPack/tests/EXTRA/test.cmake
new file mode 100644
index 0000000..efa6dac
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTRA/test.cmake
@@ -0,0 +1,35 @@
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT foo)
+install(FILES CMakeLists.txt DESTINATION bar COMPONENT bar)
+install(FILES CMakeLists.txt DESTINATION bas COMPONENT bas)
+
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/tmp/preinst "echo default_preinst")
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/tmp/prerm "echo default_prerm")
+
+foreach(file_ preinst prerm)
+ file(COPY ${CMAKE_CURRENT_BINARY_DIR}/tmp/${file_}
+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
+ FILE_PERMISSIONS
+ OWNER_READ OWNER_WRITE OWNER_EXECUTE
+ GROUP_READ GROUP_EXECUTE
+ WORLD_READ WORLD_EXECUTE)
+endforeach()
+
+set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
+ "${CMAKE_CURRENT_BINARY_DIR}/preinst;${CMAKE_CURRENT_BINARY_DIR}/prerm;${CMAKE_CURRENT_BINARY_DIR}/conffiles")
+
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bar_tmp/preinst "echo bar_preinst")
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bar_tmp/prerm "echo bar_prerm")
+
+foreach(file_ preinst prerm)
+ # not acceptable permissions for lintian but we need to check that
+ # permissions are preserved
+ file(COPY ${CMAKE_CURRENT_BINARY_DIR}/bar_tmp/${file_}
+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/bar
+ FILE_PERMISSIONS
+ OWNER_READ OWNER_WRITE OWNER_EXECUTE)
+endforeach()
+
+set(CPACK_DEBIAN_BAR_PACKAGE_CONTROL_EXTRA
+ "${CMAKE_CURRENT_BINARY_DIR}/bar/preinst;${CMAKE_CURRENT_BINARY_DIR}/bar/prerm")
+
+set(CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT")
diff --git a/Tests/RunCMake/CPack/tests/EXTRA_SLASH_IN_PATH/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/EXTRA_SLASH_IN_PATH/ExpectedFiles.cmake
new file mode 100644
index 0000000..3fb0534
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTRA_SLASH_IN_PATH/ExpectedFiles.cmake
@@ -0,0 +1,17 @@
+set(whitespaces_ "[\t\n\r ]*")
+
+set(EXPECTED_FILES_COUNT "5")
+set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
+set(EXPECTED_FILE_PACKAGING_PREFIX "")
+
+set(EXPECTED_FILE_1_COMPONENT "applications")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/test_prog")
+set(EXPECTED_FILE_2 "extra_slash_in_path*-headers.rpm")
+set(EXPECTED_FILE_CONTENT_2_LIST "/bar;/bar/CMakeLists.txt")
+set(EXPECTED_FILE_3 "extra_slash_in_path*-libs.rpm")
+set(EXPECTED_FILE_CONTENT_3_LIST "/bas;/bas/libtest_lib.so")
+
+set(EXPECTED_FILE_4_COMPONENT "applications-debuginfo")
+set(EXPECTED_FILE_CONTENT_4 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/main.cpp.*\.debug.*")
+set(EXPECTED_FILE_5_COMPONENT "libs-debuginfo")
+set(EXPECTED_FILE_CONTENT_5 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/test_lib.cpp.*\.debug.*")
diff --git a/Tests/RunCMake/CPack/tests/EXTRA_SLASH_IN_PATH/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/EXTRA_SLASH_IN_PATH/VerifyResult.cmake
new file mode 100644
index 0000000..bfef720
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTRA_SLASH_IN_PATH/VerifyResult.cmake
@@ -0,0 +1,7 @@
+# check that relocation path is /foo and not //foo
+getPackageInfo("${FOUND_FILE_1}" "FILE_INFO_")
+set(whitespaces_ "[\t\n\r ]*")
+if(NOT FILE_INFO_ MATCHES "Relocations${whitespaces_}:${whitespaces_}/${whitespaces_}/foo")
+ message(FATAL_ERROR "Unexpected relocation path in file '${FOUND_FILE_1}';"
+ " file info: '${FILE_INFO_}'")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/EXTRA_SLASH_IN_PATH/test.cmake b/Tests/RunCMake/CPack/tests/EXTRA_SLASH_IN_PATH/test.cmake
new file mode 100644
index 0000000..7cee188
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXTRA_SLASH_IN_PATH/test.cmake
@@ -0,0 +1,41 @@
+set(CMAKE_BUILD_WITH_INSTALL_RPATH 1)
+
+# PGI compiler doesn't add build id to binaries by default
+if(CMAKE_CXX_COMPILER_ID STREQUAL "PGI")
+ string(APPEND CMAKE_EXE_LINKER_FLAGS "-Wl,--build-id")
+ string(APPEND CMAKE_SHARED_LINKER_FLAGS "-Wl,--build-id")
+endif()
+
+set(CMAKE_BUILD_TYPE Debug)
+
+# for rpm packages execute flag must be set for shared libs if debuginfo
+# packages are generated
+set(CPACK_RPM_INSTALL_WITH_EXEC TRUE)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.hpp"
+ "int test_lib();\n")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp"
+ "#include \"test_lib.hpp\"\nint test_lib() {return 0;}\n")
+add_library(test_lib SHARED "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+ "#include \"test_lib.hpp\"\nint main() {return test_lib();}\n")
+add_executable(test_prog "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+target_link_libraries(test_prog test_lib)
+
+install(TARGETS test_prog DESTINATION foo COMPONENT applications)
+install(FILES CMakeLists.txt DESTINATION bar COMPONENT headers)
+install(TARGETS test_lib DESTINATION bas COMPONENT libs)
+
+set(CPACK_RPM_APPLICATIONS_FILE_NAME "RPM-DEFAULT")
+set(CPACK_RPM_APPLICATIONS_DEBUGINFO_PACKAGE ON)
+set(CPACK_RPM_LIBS_DEBUGINFO_PACKAGE ON)
+
+# extra trailing slash at the end that should be removed
+set(CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX "/src/")
+
+# combination should not cause //foo to apper as an relocation path
+# should be only /foo (extra slashes cause path comparisons to fail)
+set(CPACK_PACKAGING_INSTALL_PREFIX "/")
+# extra trailing slash at the end that should be removed
+set(CPACK_RPM_RELOCATION_PATHS "foo/")
diff --git a/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/DEB-Prerequirements.cmake b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/DEB-Prerequirements.cmake
new file mode 100644
index 0000000..be44b2e
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/DEB-Prerequirements.cmake
@@ -0,0 +1,7 @@
+function(get_test_prerequirements found_var config_file)
+ include(${config_file})
+
+ if(READELF_EXECUTABLE)
+ set(${found_var} true PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/ExpectedFiles.cmake
new file mode 100644
index 0000000..ccb5ef0
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/ExpectedFiles.cmake
@@ -0,0 +1,6 @@
+set(whitespaces_ "[\t\n\r ]*")
+
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
+# dynamic lib extension is .so on Linux and .dylib on Mac so we will use a wildcard .* for it
+set(EXPECTED_FILE_CONTENT_1 "^.*/usr/foo${whitespaces_}.*/usr/foo/libtest_lib\\..*$")
diff --git a/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/VerifyResult.cmake
new file mode 100644
index 0000000..8cefeea
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/VerifyResult.cmake
@@ -0,0 +1,9 @@
+if(RunCMake_SUBTEST_SUFFIX STREQUAL "soversion_not_zero")
+ set(shlibs_shlibs "^libtest_lib 0\\.8 generate_shlibs \\(\\= 0\\.1\\.1\\)\n$")
+else() # soversion_zero
+ set(shlibs_shlibs "^libtest_lib 0 generate_shlibs \\(\\= 0\\.1\\.1\\)\n$")
+endif()
+
+# optional dot at the end of permissions regex is for SELinux enabled systems
+set(shlibs_shlibs_permissions_regex "-rw-r--r--\.? .*")
+verifyDebControl("${FOUND_FILE_1}" "shlibs" "shlibs")
diff --git a/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/test.cmake b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/test.cmake
new file mode 100644
index 0000000..e0eb67b
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS/test.cmake
@@ -0,0 +1,19 @@
+set(CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT")
+
+set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS "ON")
+
+set(CMAKE_BUILD_WITH_INSTALL_RPATH 1)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.hpp"
+ "int test_lib();\n")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp"
+ "#include \"test_lib.hpp\"\nint test_lib() {return 0;}\n")
+add_library(test_lib SHARED "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp")
+
+if(RunCMake_SUBTEST_SUFFIX STREQUAL "soversion_not_zero")
+ set_target_properties(test_lib PROPERTIES SOVERSION "0.8")
+else() # soversion_zero
+ set_target_properties(test_lib PROPERTIES SOVERSION "0")
+endif()
+
+install(TARGETS test_lib DESTINATION foo COMPONENT libs)
diff --git a/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/DEB-Prerequirements.cmake b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/DEB-Prerequirements.cmake
new file mode 100644
index 0000000..be44b2e
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/DEB-Prerequirements.cmake
@@ -0,0 +1,7 @@
+function(get_test_prerequirements found_var config_file)
+ include(${config_file})
+
+ if(READELF_EXECUTABLE)
+ set(${found_var} true PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/ExpectedFiles.cmake
new file mode 100644
index 0000000..d66c044
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/ExpectedFiles.cmake
@@ -0,0 +1,6 @@
+set(whitespaces_ "[\t\n\r ]*")
+
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
+# dynamic lib extension is .so on Linux and .dylib on Mac so we will use a wildcard .* for it
+set(EXPECTED_FILE_CONTENT_1 "^.*/usr/lib${whitespaces_}.*/usr/lib/libtest_lib\\..*$")
diff --git a/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/VerifyResult.cmake
new file mode 100644
index 0000000..422cfbe
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/VerifyResult.cmake
@@ -0,0 +1,8 @@
+set(shlibs_shlibs "^libtest_lib 0\\.8 generate_shlibs_ldconfig \\(>\\= 0\\.1\\.1\\)\n$")
+# NOTE: optional dot at the end of permissions regex is for SELinux enabled systems
+set(shlibs_shlibs_permissions_regex "-rw-r--r--\.? .*")
+set(shlibs_postinst ".*ldconfig.*")
+set(shlibs_postinst_permissions_regex "-rwxr-xr-x\.? .*")
+set(shlibs_postrm ".*ldconfig.*")
+set(shlibs_postrm_permissions_regex "-rwxr-xr-x\.? .*")
+verifyDebControl("${FOUND_FILE_1}" "shlibs" "shlibs;postinst;postrm")
diff --git a/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/test.cmake b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/test.cmake
new file mode 100644
index 0000000..15c496b
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/GENERATE_SHLIBS_LDCONFIG/test.cmake
@@ -0,0 +1,15 @@
+set(CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT")
+
+set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS "ON")
+set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY ">=")
+
+set(CMAKE_BUILD_WITH_INSTALL_RPATH 1)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.hpp"
+ "int test_lib();\n")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp"
+ "#include \"test_lib.hpp\"\nint test_lib() {return 0;}\n")
+add_library(test_lib SHARED "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp")
+set_target_properties(test_lib PROPERTIES SOVERSION "0.8")
+
+install(TARGETS test_lib LIBRARY DESTINATION lib COMPONENT libs NAMELINK_SKIP)
diff --git a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/ExpectedFiles.cmake
new file mode 100644
index 0000000..5a87c44
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/ExpectedFiles.cmake
@@ -0,0 +1,10 @@
+if(RunCMake_SUBTEST_SUFFIX MATCHES ".*single_debug_info")
+ set(EXPECTED_FILE_1 "install_scripts-0.1.1-1.*.rpm")
+else()
+ set(EXPECTED_FILE_1_COMPONENT "foo")
+endif()
+
+set(EXPECTED_FILES_COUNT "2")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
+set(EXPECTED_FILE_2_COMPONENT "bar")
+set(EXPECTED_FILE_CONTENT_2_LIST "/bar;/bar/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-COMPONENT-no_scripts_single_debug_info-stderr.txt b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-COMPONENT-no_scripts_single_debug_info-stderr.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-COMPONENT-no_scripts_single_debug_info-stderr.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-COMPONENT-single_debug_info-stderr.txt b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-COMPONENT-single_debug_info-stderr.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-COMPONENT-single_debug_info-stderr.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-Prerequirements.cmake b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-Prerequirements.cmake
new file mode 100644
index 0000000..90cfe44
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-Prerequirements.cmake
@@ -0,0 +1,11 @@
+function(get_test_prerequirements found_var config_file)
+ if(SUBTEST_SUFFIX MATCHES ".*single_debug_info")
+ include(${config_file})
+
+ if(OBJDUMP_EXECUTABLE)
+ set(${found_var} true PARENT_SCOPE)
+ endif()
+ else()
+ set(${found_var} true PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/VerifyResult.cmake
new file mode 100644
index 0000000..0c42d90
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/VerifyResult.cmake
@@ -0,0 +1,40 @@
+function(checkScripts_ FILE COMPARE_LIST)
+ set(whitespaces_ "[\t\n\r ]*")
+
+ execute_process(COMMAND ${RPM_EXECUTABLE} -qp --scripts ${FILE}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE FILE_SCRIPTS_
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(COMPARE_LIST STREQUAL "")
+ if(NOT FILE_SCRIPTS_ STREQUAL "")
+ message(FATAL_ERROR "No scripts were expected in '${FILE}'; file info: '${FILE_SCRIPTS_}'")
+ endif()
+ else()
+ string(REPLACE "\n" ";" FILE_SCRIPTS_LIST_ "${FILE_SCRIPTS_}")
+
+ foreach(COMPARE_REGEX_ IN LISTS COMPARE_LIST)
+ unset(FOUND_)
+
+ foreach(COMPARE_ IN LISTS FILE_SCRIPTS_LIST_)
+ if(COMPARE_ MATCHES "${COMPARE_REGEX_}")
+ set(FOUND_ true)
+ break()
+ endif()
+ endforeach()
+
+ if(NOT FOUND_)
+ message(FATAL_ERROR "Missing scripts in '${FILE}'; file info: '${FILE_SCRIPTS_}'; missing: '${COMPARE_REGEX_}'")
+ endif()
+ endforeach()
+ endif()
+endfunction()
+
+if(RunCMake_SUBTEST_SUFFIX MATCHES "no_scripts.*")
+ checkScripts_("${FOUND_FILE_1}" "")
+ checkScripts_("${FOUND_FILE_2}" "")
+else()
+ checkScripts_("${FOUND_FILE_1}" "echo \"pre install foo\";echo \"post install foo\";echo \"pre uninstall foo\";echo \"post uninstall foo\";echo \"pre trans foo\";echo \"post trans foo\"")
+ checkScripts_("${FOUND_FILE_2}" "echo \"pre install\";echo \"post install\";echo \"pre uninstall\";echo \"post uninstall\";echo \"pre trans\";echo \"post trans\"")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/test.cmake b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/test.cmake
new file mode 100644
index 0000000..ce5db0c
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/test.cmake
@@ -0,0 +1,70 @@
+if(GENERATOR_TYPE STREQUAL "RPM")
+ if(RunCMake_SUBTEST_SUFFIX MATCHES ".*single_debug_info")
+ set(CPACK_RPM_MAIN_COMPONENT "foo")
+ set(CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE ON)
+ set(CPACK_RPM_FOO_FILE_NAME "RPM-DEFAULT")
+ endif()
+endif()
+
+set(CMAKE_BUILD_WITH_INSTALL_RPATH 1)
+
+if(NOT RunCMake_SUBTEST_SUFFIX MATCHES "no_scripts.*")
+ if(GENERATOR_TYPE STREQUAL "RPM")
+ set(CPACK_RPM_PRE_INSTALL_SCRIPT_FILE
+ "${CMAKE_CURRENT_BINARY_DIR}/pre_install.sh")
+ set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE
+ "${CMAKE_CURRENT_BINARY_DIR}/post_install.sh")
+ set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE
+ "${CMAKE_CURRENT_BINARY_DIR}/pre_uninstall.sh")
+ set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE
+ "${CMAKE_CURRENT_BINARY_DIR}/post_uninstall.sh")
+ set(CPACK_RPM_PRE_TRANS_SCRIPT_FILE
+ "${CMAKE_CURRENT_BINARY_DIR}/pre_trans.sh")
+ set(CPACK_RPM_POST_TRANS_SCRIPT_FILE
+ "${CMAKE_CURRENT_BINARY_DIR}/post_trans.sh")
+
+ set(CPACK_RPM_foo_PRE_INSTALL_SCRIPT_FILE
+ "${CMAKE_CURRENT_BINARY_DIR}/pre_install_foo.sh")
+ set(CPACK_RPM_foo_POST_INSTALL_SCRIPT_FILE
+ "${CMAKE_CURRENT_BINARY_DIR}/post_install_foo.sh")
+ set(CPACK_RPM_foo_PRE_UNINSTALL_SCRIPT_FILE
+ "${CMAKE_CURRENT_BINARY_DIR}/pre_uninstall_foo.sh")
+ set(CPACK_RPM_foo_POST_UNINSTALL_SCRIPT_FILE
+ "${CMAKE_CURRENT_BINARY_DIR}/post_uninstall_foo.sh")
+ set(CPACK_RPM_foo_PRE_TRANS_SCRIPT_FILE
+ "${CMAKE_CURRENT_BINARY_DIR}/pre_trans_foo.sh")
+ set(CPACK_RPM_foo_POST_TRANS_SCRIPT_FILE
+ "${CMAKE_CURRENT_BINARY_DIR}/post_trans_foo.sh")
+ endif()
+
+ # default
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_install.sh"
+ "echo \"pre install\"\n")
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_install.sh"
+ "echo \"post install\"\n")
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_uninstall.sh"
+ "echo \"pre uninstall\"\n")
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_uninstall.sh"
+ "echo \"post uninstall\"\n")
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_trans.sh"
+ "echo \"pre trans\"\n")
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_trans.sh"
+ "echo \"post trans\"\n")
+
+ # specific
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_install_foo.sh"
+ "echo \"pre install foo\"\n")
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_install_foo.sh"
+ "echo \"post install foo\"\n")
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_uninstall_foo.sh"
+ "echo \"pre uninstall foo\"\n")
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_uninstall_foo.sh"
+ "echo \"post uninstall foo\"\n")
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_trans_foo.sh"
+ "echo \"pre trans foo\"\n")
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_trans_foo.sh"
+ "echo \"post trans foo\"\n")
+endif()
+
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT foo)
+install(FILES CMakeLists.txt DESTINATION bar COMPONENT bar)
diff --git a/Tests/RunCMake/CPack/tests/LONG_FILENAMES/DEB-Prerequirements.cmake b/Tests/RunCMake/CPack/tests/LONG_FILENAMES/DEB-Prerequirements.cmake
new file mode 100644
index 0000000..ddd16e5
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/LONG_FILENAMES/DEB-Prerequirements.cmake
@@ -0,0 +1,7 @@
+function(get_test_prerequirements found_var config_file)
+ include(${config_file})
+
+ if(FAKEROOT_EXECUTABLE)
+ set(${found_var} true PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/tests/LONG_FILENAMES/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/LONG_FILENAMES/ExpectedFiles.cmake
new file mode 100644
index 0000000..4cb8dd0
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/LONG_FILENAMES/ExpectedFiles.cmake
@@ -0,0 +1,3 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/llllllllll_oooooooooo_nnnnnnnnnn_gggggggggg_ffffffffff_iiiiiiiiii_llllllllll_eeeeeeeeee_nnnnnnnnnn_aaaaaaaaaa_mmmmmmmmmm_eeeeeeeeee.txt")
diff --git a/Tests/RunCMake/CPack/tests/LONG_FILENAMES/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/LONG_FILENAMES/VerifyResult.cmake
new file mode 100644
index 0000000..0452343
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/LONG_FILENAMES/VerifyResult.cmake
@@ -0,0 +1,26 @@
+# create structure required by non root dpkg install
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/root_dir")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/root_dir/admindir")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/root_dir/admindir/updates")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/root_dir/admindir/info")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/root_dir/admindir/available" "")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/root_dir/admindir/status" "")
+
+# some programs used by fakeroot require sbin in path so we should not
+# leave this to chance (programs: ldconfig and start-stop-daemon)
+set(ENV{PATH} "$ENV{PATH}:/usr/local/sbin:/usr/sbin:/sbin")
+
+execute_process(COMMAND ${FAKEROOT_EXECUTABLE} ${DPKG_EXECUTABLE}
+ -i --force-not-root --root=${CMAKE_CURRENT_BINARY_DIR}/root_dir
+ --admindir=${CMAKE_CURRENT_BINARY_DIR}/root_dir/admindir
+ --log=${CMAKE_CURRENT_BINARY_DIR}/root_dir/dpkg.log
+ ${FOUND_FILE_1}
+ RESULT_VARIABLE install_result_
+ ERROR_VARIABLE install_error_
+ OUTPUT_QUIET
+ )
+
+if(install_result_)
+ message(FATAL_ERROR "LONG_FILENAMES package error - result:"
+ " '${install_result_}'; text: '${install_error_}'")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/LONG_FILENAMES/test.cmake b/Tests/RunCMake/CPack/tests/LONG_FILENAMES/test.cmake
new file mode 100644
index 0000000..f235d47
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/LONG_FILENAMES/test.cmake
@@ -0,0 +1,13 @@
+if(GENERATOR_TYPE STREQUAL "DEB")
+ set(CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT")
+ set(CPACK_DEBIAN_ARCHIVE_TYPE "gnutar")
+endif()
+
+set(LONG_FILENAME
+ "${CMAKE_CURRENT_BINARY_DIR}/llllllllll_oooooooooo_nnnnnnnnnn_gggggggggg_ffffffffff_iiiiiiiiii_llllllllll_eeeeeeeeee_nnnnnnnnnn_aaaaaaaaaa_mmmmmmmmmm_eeeeeeeeee.txt")
+
+file(WRITE
+ "${LONG_FILENAME}"
+ "long_filename_test")
+
+install(FILES ${LONG_FILENAME} DESTINATION foo)
diff --git a/Tests/RunCMake/CPack/tests/MAIN_COMPONENT/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/MAIN_COMPONENT/ExpectedFiles.cmake
new file mode 100644
index 0000000..629be9e
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/MAIN_COMPONENT/ExpectedFiles.cmake
@@ -0,0 +1,11 @@
+set(EXPECTED_FILES_COUNT "0")
+
+if(NOT RunCMake_SUBTEST_SUFFIX STREQUAL "invalid")
+ set(EXPECTED_FILES_COUNT "3")
+ set(EXPECTED_FILE_1 "main_component-0.1.1-1.*.rpm")
+ set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
+ set(EXPECTED_FILE_2_COMPONENT "headers")
+ set(EXPECTED_FILE_CONTENT_2_LIST "/bar;/bar/CMakeLists.txt")
+ set(EXPECTED_FILE_3_COMPONENT "libs")
+ set(EXPECTED_FILE_CONTENT_3_LIST "/bas;/bas/CMakeLists.txt")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/MAIN_COMPONENT/RPM-invalid-stderr.txt b/Tests/RunCMake/CPack/tests/MAIN_COMPONENT/RPM-invalid-stderr.txt
new file mode 100644
index 0000000..4d8ac6e
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/MAIN_COMPONENT/RPM-invalid-stderr.txt
@@ -0,0 +1 @@
+CPACK_RPM_MAIN_COMPONENT set to non existing component.
diff --git a/Tests/RunCMake/CPack/tests/MAIN_COMPONENT/test.cmake b/Tests/RunCMake/CPack/tests/MAIN_COMPONENT/test.cmake
new file mode 100644
index 0000000..791c586
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/MAIN_COMPONENT/test.cmake
@@ -0,0 +1,10 @@
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT applications)
+install(FILES CMakeLists.txt DESTINATION bar COMPONENT headers)
+install(FILES CMakeLists.txt DESTINATION bas COMPONENT libs)
+
+if(RunCMake_SUBTEST_SUFFIX STREQUAL "invalid")
+ set(CPACK_RPM_MAIN_COMPONENT "")
+else()
+ set(CPACK_RPM_MAIN_COMPONENT "applications")
+ set(CPACK_RPM_APPLICATIONS_FILE_NAME "RPM-DEFAULT")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/MD5SUMS/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/MD5SUMS/ExpectedFiles.cmake
new file mode 100644
index 0000000..d1a3a5f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/MD5SUMS/ExpectedFiles.cmake
@@ -0,0 +1,2 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/MD5SUMS/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/MD5SUMS/VerifyResult.cmake
new file mode 100644
index 0000000..fbdda9c
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/MD5SUMS/VerifyResult.cmake
@@ -0,0 +1,3 @@
+set(whitespaces_ "[\t\n\r ]*")
+set(md5sums_md5sums "^.* usr/foo/CMakeLists\.txt${whitespaces_}$")
+verifyDebControl("${FOUND_FILE_1}" "md5sums" "md5sums")
diff --git a/Tests/RunCMake/CPack/tests/MD5SUMS/test.cmake b/Tests/RunCMake/CPack/tests/MD5SUMS/test.cmake
new file mode 100644
index 0000000..15c5892
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/MD5SUMS/test.cmake
@@ -0,0 +1,5 @@
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(CPACK_COMPONENTS_ALL test)
+endif()
diff --git a/Tests/RunCMake/CPack/tests/MINIMAL/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/MINIMAL/ExpectedFiles.cmake
new file mode 100644
index 0000000..d1a3a5f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/MINIMAL/ExpectedFiles.cmake
@@ -0,0 +1,2 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/MINIMAL/test.cmake b/Tests/RunCMake/CPack/tests/MINIMAL/test.cmake
new file mode 100644
index 0000000..15c5892
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/MINIMAL/test.cmake
@@ -0,0 +1,5 @@
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(CPACK_COMPONENTS_ALL test)
+endif()
diff --git a/Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/ExpectedFiles.cmake
new file mode 100644
index 0000000..c375aca
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/ExpectedFiles.cmake
@@ -0,0 +1,6 @@
+set(EXPECTED_FILES_COUNT "0")
+
+if(NOT ${RunCMake_SUBTEST_SUFFIX} MATCHES "invalid")
+ set(EXPECTED_FILES_COUNT "1")
+ set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/TGZ-invalid-stderr.txt b/Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/TGZ-invalid-stderr.txt
new file mode 100644
index 0000000..abf6d8c
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/TGZ-invalid-stderr.txt
@@ -0,0 +1,2 @@
+^CPack Error: Cannot recognize algorithm: invalid
+CPack Error: Error when generating package: package_checksum$
diff --git a/Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/VerifyResult.cmake
new file mode 100644
index 0000000..2bb4d3f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/VerifyResult.cmake
@@ -0,0 +1,11 @@
+if(NOT ${RunCMake_SUBTEST_SUFFIX} MATCHES "invalid")
+ string(TOLOWER ${RunCMake_SUBTEST_SUFFIX} CHECKSUM_EXTENSION)
+ file(GLOB PACKAGE RELATIVE ${bin_dir} "*.tar.gz")
+ file(STRINGS ${PACKAGE}.${CHECKSUM_EXTENSION} CHSUM_VALUE)
+ file(${RunCMake_SUBTEST_SUFFIX} ${PACKAGE} expected_value )
+ set(expected_value "${expected_value} ${PACKAGE}")
+
+ if(NOT expected_value STREQUAL CHSUM_VALUE)
+ message(FATAL_ERROR "Generated checksum is not valid! Expected [${expected_value}] Got [${CHSUM_VALUE}]")
+ endif()
+endif()
diff --git a/Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/test.cmake b/Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/test.cmake
new file mode 100644
index 0000000..0838063
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PACKAGE_CHECKSUM/test.cmake
@@ -0,0 +1,3 @@
+install(FILES CMakeLists.txt DESTINATION foo)
+
+set(CPACK_PACKAGE_CHECKSUM ${RunCMake_SUBTEST_SUFFIX})
diff --git a/Tests/RunCMake/CPack/tests/PARTIALLY_RELOCATABLE_WARNING/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/PARTIALLY_RELOCATABLE_WARNING/ExpectedFiles.cmake
new file mode 100644
index 0000000..137da47
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PARTIALLY_RELOCATABLE_WARNING/ExpectedFiles.cmake
@@ -0,0 +1,4 @@
+set(EXPECTED_FILES_COUNT "1")
+# don't set the prefix here as we have absolute paths that should not be prefixed
+set(EXPECTED_FILE_PACKAGING_PREFIX "")
+set(EXPECTED_FILE_CONTENT_1_LIST "/not_relocatable;/not_relocatable/CMakeLists.txt;/opt")
diff --git a/Tests/RunCMake/CPack/tests/PARTIALLY_RELOCATABLE_WARNING/RPM-stderr.txt b/Tests/RunCMake/CPack/tests/PARTIALLY_RELOCATABLE_WARNING/RPM-stderr.txt
new file mode 100644
index 0000000..3b63d5b
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PARTIALLY_RELOCATABLE_WARNING/RPM-stderr.txt
@@ -0,0 +1 @@
+CPackRPM:Warning: Path /not_relocatable/CMakeLists.txt is not on one of the.*relocatable paths! Package will be partially relocatable.
diff --git a/Tests/RunCMake/CPack/tests/PARTIALLY_RELOCATABLE_WARNING/test.cmake b/Tests/RunCMake/CPack/tests/PARTIALLY_RELOCATABLE_WARNING/test.cmake
new file mode 100644
index 0000000..4698fb3
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PARTIALLY_RELOCATABLE_WARNING/test.cmake
@@ -0,0 +1,4 @@
+install(FILES CMakeLists.txt DESTINATION /not_relocatable COMPONENT static)
+
+set(CPACK_PACKAGE_RELOCATABLE TRUE)
+set(CPACK_PACKAGING_INSTALL_PREFIX "/opt")
diff --git a/Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/ExpectedFiles.cmake
new file mode 100644
index 0000000..26fa1df
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/ExpectedFiles.cmake
@@ -0,0 +1,8 @@
+set(EXPECTED_FILES_COUNT "3")
+set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
+set(EXPECTED_FILE_1_COMPONENT "pkg_1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
+set(EXPECTED_FILE_2_NAME "second")
+set(EXPECTED_FILE_CONTENT_2_LIST "/foo;/foo/CMakeLists.txt")
+set(EXPECTED_FILE_3_COMPONENT "pkg_3")
+set(EXPECTED_FILE_CONTENT_3_LIST "/foo;/foo/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/VerifyResult.cmake
new file mode 100644
index 0000000..b4bdb61
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/VerifyResult.cmake
@@ -0,0 +1,38 @@
+function(checkPackageInfo_ TYPE FILE REGEX)
+ getPackageInfo("${FILE}" "FILE_INFO_")
+ if(NOT FILE_INFO_ MATCHES "${REGEX}")
+ message(FATAL_ERROR "Unexpected ${TYPE} in '${FILE}'; file info: '${FILE_INFO_}'; does not match '${REGEX}'")
+ endif()
+endfunction()
+
+if(GENERATOR_TYPE STREQUAL "DEB")
+ set(name_ "Package")
+ set(group_ "Section")
+elseif(GENERATOR_TYPE STREQUAL "RPM")
+ set(name_ "Name")
+ set(group_ "Group")
+endif()
+
+set(whitespaces_ "[\t\n\r ]*")
+
+# check package name
+checkPackageInfo_("name" "${FOUND_FILE_1}" ".*${name_}${whitespaces_}:${whitespaces_}per_component_fields-pkg_1")
+checkPackageInfo_("name" "${FOUND_FILE_2}" ".*${name_}${whitespaces_}:${whitespaces_}second")
+checkPackageInfo_("name" "${FOUND_FILE_3}" ".*${name_}${whitespaces_}:${whitespaces_}per_component_fields-pkg_3")
+
+# check package group
+checkPackageInfo_("group" "${FOUND_FILE_1}" ".*${group_}${whitespaces_}:${whitespaces_}default")
+checkPackageInfo_("group" "${FOUND_FILE_2}" ".*${group_}${whitespaces_}:${whitespaces_}second_group")
+checkPackageInfo_("group" "${FOUND_FILE_3}" ".*${group_}${whitespaces_}:${whitespaces_}default")
+
+# check package summaries (not available in DEB)
+if(GENERATOR_TYPE STREQUAL "RPM")
+ checkPackageInfo_("summary" "${FOUND_FILE_1}" ".*Summary${whitespaces_}:${whitespaces_}Global summary")
+ checkPackageInfo_("summary" "${FOUND_FILE_2}" ".*Summary${whitespaces_}:${whitespaces_}Summary for pkg_2")
+ checkPackageInfo_("summary" "${FOUND_FILE_3}" ".*Summary${whitespaces_}:${whitespaces_}Global summary")
+endif()
+
+# check package description
+checkPackageInfo_("description" "${FOUND_FILE_1}" ".*Description${whitespaces_}:${whitespaces_}Description for pkg_1")
+checkPackageInfo_("description" "${FOUND_FILE_2}" ".*Description${whitespaces_}:${whitespaces_}Description for pkg_2")
+checkPackageInfo_("description" "${FOUND_FILE_3}" ".*Description${whitespaces_}:${whitespaces_}Description for pkg_3")
diff --git a/Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/test.cmake b/Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/test.cmake
new file mode 100644
index 0000000..dc61d0a
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PER_COMPONENT_FIELDS/test.cmake
@@ -0,0 +1,25 @@
+if(GENERATOR_TYPE STREQUAL "DEB" OR GENERATOR_TYPE STREQUAL "RPM")
+ if(GENERATOR_TYPE STREQUAL "DEB")
+ set(generator_type_suffix_ "IAN") # not entirely compatible...
+ set(group_ "SECTION")
+ else()
+ set(group_ "GROUP")
+ endif()
+
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_FILE_NAME "${GENERATOR_TYPE}-DEFAULT")
+
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_PACKAGE_${group_} "default")
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_PKG_2_PACKAGE_NAME "second")
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_PKG_2_PACKAGE_${group_} "second_group")
+
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_PACKAGE_SUMMARY "Global summary") # not used for DEB
+ set(CPACK_${GENERATOR_TYPE}${generator_type_suffix_}_PKG_2_PACKAGE_SUMMARY "Summary for pkg_2") # not used for DEB
+
+ set(CPACK_COMPONENT_PKG_1_DESCRIPTION "Description for pkg_1")
+ set(CPACK_COMPONENT_PKG_2_DESCRIPTION "Description for pkg_2")
+ set(CPACK_COMPONENT_PKG_3_DESCRIPTION "Description for pkg_3")
+endif()
+
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT pkg_1)
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT pkg_2)
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT pkg_3)
diff --git a/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/ExpectedFiles.cmake
new file mode 100644
index 0000000..63a36a3
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/ExpectedFiles.cmake
@@ -0,0 +1,19 @@
+set(SATU "/satu;/satu/CMakeLists.txt")
+set(DUA "/dua;/dua/CMakeLists.txt")
+
+if(GENERATOR_TYPE STREQUAL ZIP)
+ set(_ext "zip")
+elseif(GENERATOR_TYPE STREQUAL TGZ)
+ set(_ext "tar.gz")
+endif()
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(EXPECTED_FILES_COUNT "2")
+ set(EXPECTED_FILE_1 "*-satu.${_ext}")
+ set(EXPECTED_FILE_CONTENT_1_LIST ${SATU})
+ set(EXPECTED_FILE_2 "*-dua.${_ext}")
+ set(EXPECTED_FILE_CONTENT_2_LIST ${DUA})
+else()
+ set(EXPECTED_FILES_COUNT "1")
+ set(EXPECTED_FILE_CONTENT_1_LIST ${SATU} ${DUA})
+endif()
diff --git a/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/ZIP_COMPONENT-stdout.txt b/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/ZIP_COMPONENT-stdout.txt
new file mode 100644
index 0000000..319d0da
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/ZIP_COMPONENT-stdout.txt
@@ -0,0 +1,4 @@
+-- The message from .*/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/pre\.cmake and generator ZIP
+.*
+-- The message from .*/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/post\.cmake and generator ZIP
+-- Built packages: .*/_CPack_Packages/.*/pre_post_scripts-.*-dua.zip;.*/_CPack_Packages/.*/pre_post_scripts-.*-satu.zip
diff --git a/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/ZIP_MONOLITHIC-stdout.txt b/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/ZIP_MONOLITHIC-stdout.txt
new file mode 100644
index 0000000..632c4d1
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/ZIP_MONOLITHIC-stdout.txt
@@ -0,0 +1,4 @@
+-- The message from .*/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/pre\.cmake and generator ZIP
+.*
+-- The message from .*/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/post\.cmake and generator ZIP
+-- Built packages: .*/_CPack_Packages/.*/pre_post_scripts-0\.1\.1-.*\.zip
diff --git a/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/post.cmake b/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/post.cmake
new file mode 100644
index 0000000..cf0b149
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/post.cmake
@@ -0,0 +1,2 @@
+message(STATUS "The message from ${CMAKE_CURRENT_LIST_FILE} and generator ${CPACK_GENERATOR}")
+message(STATUS "Built packages: ${CPACK_PACKAGE_FILES}")
diff --git a/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/pre.cmake b/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/pre.cmake
new file mode 100644
index 0000000..b04aa6b
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/pre.cmake
@@ -0,0 +1 @@
+message(STATUS "The message from ${CMAKE_CURRENT_LIST_FILE} and generator ${CPACK_GENERATOR}")
diff --git a/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/test.cmake b/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/test.cmake
new file mode 100644
index 0000000..f1b6d5f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PRE_POST_SCRIPTS/test.cmake
@@ -0,0 +1,9 @@
+install(FILES CMakeLists.txt DESTINATION satu COMPONENT satu)
+install(FILES CMakeLists.txt DESTINATION dua COMPONENT dua)
+
+set(CPACK_PRE_BUILD_SCRIPTS "${CMAKE_CURRENT_LIST_DIR}/pre.cmake")
+set(CPACK_POST_BUILD_SCRIPTS "${CMAKE_CURRENT_LIST_DIR}/post.cmake")
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(CPACK_COMPONENTS_ALL satu dua)
+endif()
diff --git a/Tests/RunCMake/CPack/tests/PROJECT_META/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/PROJECT_META/ExpectedFiles.cmake
new file mode 100644
index 0000000..448ed2b
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PROJECT_META/ExpectedFiles.cmake
@@ -0,0 +1,9 @@
+if(GENERATOR_TYPE STREQUAL DEB)
+ set(EXPECTED_FILE_1 "project_meta-1.2.3*.deb")
+elseif(GENERATOR_TYPE STREQUAL RPM)
+ set(EXPECTED_FILE_1 "project_meta-1.2.3*.rpm")
+else()
+ message(FATAL_ERROR "Unexpected CPack generator")
+endif()
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/PROJECT_META/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/PROJECT_META/VerifyResult.cmake
new file mode 100644
index 0000000..35a93d6
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PROJECT_META/VerifyResult.cmake
@@ -0,0 +1,30 @@
+function(checkPackageURL FILE TAG EXPECTED_URL)
+ getPackageInfo("${FILE}" "_file_info")
+ string(REPLACE "\n" ";" _file_info "${_file_info}")
+
+ set(_seen_url FALSE)
+ foreach(_line IN LISTS _file_info)
+ if(_line MATCHES "${TAG}: (.*)")
+ set(_seen_url TRUE)
+ if(NOT CMAKE_MATCH_1 STREQUAL EXPECTED_URL)
+ message(FATAL_ERROR "Unexpected `Homepage` URL: `${CMAKE_MATCH_1}` != `${EXPECTED_URL}`")
+ endif()
+ break()
+ endif()
+ endforeach()
+ if(NOT _seen_url)
+ message(FATAL_ERROR "The package `${FILE}` do not have URL as expected")
+ endif()
+endfunction()
+
+if(GENERATOR_TYPE STREQUAL DEB)
+ set(_tag " Homepage") # NOTE The leading space
+elseif(GENERATOR_TYPE STREQUAL RPM)
+ set(_tag "URL.*")
+else()
+ message(FATAL_ERROR "Unexpected CPack generator")
+endif()
+
+checkPackageURL("${FOUND_FILE_1}" "${_tag}" "https://meta.test.info")
+
+# kate: indent-width 2;
diff --git a/Tests/RunCMake/CPack/tests/PROJECT_META/test.cmake b/Tests/RunCMake/CPack/tests/PROJECT_META/test.cmake
new file mode 100644
index 0000000..9c5266a
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PROJECT_META/test.cmake
@@ -0,0 +1,11 @@
+project(
+ MetaInfoTest
+ VERSION 1.2.3
+ DESCRIPTION "This is going to be a summary"
+ HOMEPAGE_URL "https://meta.test.info"
+)
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(CPACK_COMPONENTS_ALL test)
+endif()
diff --git a/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/ExpectedFiles.cmake
new file mode 100644
index 0000000..1dc7084
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/ExpectedFiles.cmake
@@ -0,0 +1,30 @@
+set(whitespaces_ "[\t\n\r ]*")
+set(EXPECTED_FILES_COUNT "0")
+set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
+
+if(RunCMake_SUBTEST_SUFFIX STREQUAL "valid" OR RunCMake_SUBTEST_SUFFIX STREQUAL "no_debuginfo")
+ set(EXPECTED_FILES_COUNT "4")
+ set(EXPECTED_FILE_1 "single_debuginfo-0.1.1-1.*.rpm")
+ set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/test_prog")
+ set(EXPECTED_FILE_2 "single_debuginfo*-headers.rpm")
+ set(EXPECTED_FILE_CONTENT_2_LIST "/bar;/bar/CMakeLists.txt")
+ set(EXPECTED_FILE_3 "single_debuginfo*-libs.rpm")
+ set(EXPECTED_FILE_CONTENT_3_LIST "/bas;/bas/libtest_lib.so;/empty_dir")
+
+ set(EXPECTED_FILE_4_COMPONENT "debuginfo")
+ set(EXPECTED_FILE_CONTENT_4 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/main.cpp${whitespaces_}/src/src_1/test_lib.cpp.*\.debug.*")
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "one_component" OR RunCMake_SUBTEST_SUFFIX STREQUAL "one_component_no_debuginfo")
+ set(EXPECTED_FILES_COUNT "2")
+ set(EXPECTED_FILE_1 "single_debuginfo-0*-applications.rpm")
+ set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/test_prog")
+
+ set(EXPECTED_FILE_2 "single_debuginfo-applications-debuginfo*.rpm")
+ set(EXPECTED_FILE_CONTENT_2 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/main.cpp.*\.debug.*")
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "one_component_main" OR RunCMake_SUBTEST_SUFFIX STREQUAL "no_components")
+ set(EXPECTED_FILES_COUNT "2")
+ set(EXPECTED_FILE_1 "single_debuginfo-0*.rpm")
+ set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/test_prog")
+
+ set(EXPECTED_FILE_2 "single_debuginfo-debuginfo*.rpm")
+ set(EXPECTED_FILE_CONTENT_2 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/main.cpp.*\.debug.*")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/RPM-no_main_component-stderr.txt b/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/RPM-no_main_component-stderr.txt
new file mode 100644
index 0000000..454283c
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/RPM-no_main_component-stderr.txt
@@ -0,0 +1 @@
+CPack Error: CPACK_RPM_MAIN_COMPONENT not set but it is mandatory with CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE being set.
diff --git a/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/test.cmake b/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/test.cmake
new file mode 100644
index 0000000..064539e
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/test.cmake
@@ -0,0 +1,57 @@
+set(CMAKE_BUILD_WITH_INSTALL_RPATH 1)
+
+# PGI compiler doesn't add build id to binaries by default
+if(CMAKE_CXX_COMPILER_ID STREQUAL "PGI")
+ string(APPEND CMAKE_EXE_LINKER_FLAGS "-Wl,--build-id")
+ string(APPEND CMAKE_SHARED_LINKER_FLAGS "-Wl,--build-id")
+endif()
+
+if(NOT RunCMake_SUBTEST_SUFFIX STREQUAL "no_components")
+ set(CPACK_RPM_COMPONENT_INSTALL "ON")
+endif()
+
+set(CMAKE_BUILD_TYPE Debug)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.hpp"
+ "int test_lib();\n")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp"
+ "#include \"test_lib.hpp\"\nint test_lib() {return 0;}\n")
+add_library(test_lib SHARED "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+ "#include \"test_lib.hpp\"\nint main() {return test_lib();}\n")
+add_executable(test_prog "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+target_link_libraries(test_prog test_lib)
+
+install(TARGETS test_prog DESTINATION foo COMPONENT applications)
+
+if(RunCMake_SUBTEST_SUFFIX STREQUAL "valid"
+ OR RunCMake_SUBTEST_SUFFIX STREQUAL "no_main_component"
+ OR RunCMake_SUBTEST_SUFFIX STREQUAL "no_debuginfo")
+ install(FILES CMakeLists.txt DESTINATION bar COMPONENT headers)
+ install(TARGETS test_lib DESTINATION bas COMPONENT libs)
+
+ # test that we correctly handle empty dir in non main component
+ install(DIRECTORY DESTINATION empty_dir COMPONENT libs)
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "one_component"
+ OR RunCMake_SUBTEST_SUFFIX STREQUAL "one_component_no_debuginfo")
+ set(CPACK_COMPONENTS_ALL applications)
+endif()
+
+set(CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE ON)
+
+if(RunCMake_SUBTEST_SUFFIX STREQUAL "valid"
+ OR RunCMake_SUBTEST_SUFFIX STREQUAL "one_component_main"
+ OR RunCMake_SUBTEST_SUFFIX STREQUAL "no_debuginfo")
+ set(CPACK_RPM_MAIN_COMPONENT "applications")
+ set(CPACK_RPM_APPLICATIONS_FILE_NAME "RPM-DEFAULT")
+endif()
+
+if(RunCMake_SUBTEST_SUFFIX STREQUAL "valid"
+ OR RunCMake_SUBTEST_SUFFIX STREQUAL "no_main_component"
+ OR RunCMake_SUBTEST_SUFFIX STREQUAL "one_component")
+ set(CPACK_RPM_APPLICATIONS_DEBUGINFO_PACKAGE ON)
+ set(CPACK_RPM_LIBS_DEBUGINFO_PACKAGE ON)
+endif()
+
+set(CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX "/src")
diff --git a/Tests/RunCMake/CPack/tests/SOURCE_PACKAGE/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/SOURCE_PACKAGE/ExpectedFiles.cmake
new file mode 100644
index 0000000..d78f222
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/SOURCE_PACKAGE/ExpectedFiles.cmake
@@ -0,0 +1,3 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_PACKAGING_PREFIX "")
+set(EXPECTED_FILE_CONTENT_1_LIST "source_package-0.1.1.tar.gz;source_package.spec")
diff --git a/Tests/RunCMake/CPack/tests/SOURCE_PACKAGE/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/SOURCE_PACKAGE/VerifyResult.cmake
new file mode 100644
index 0000000..73d7481
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/SOURCE_PACKAGE/VerifyResult.cmake
@@ -0,0 +1,67 @@
+set(whitespaces_ "[\t\n\r ]*")
+
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/BUILD")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/BUILDROOT")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/SOURCES")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/SPECS")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/SRPMS")
+
+# make sure that we are using the version of cmake and cpack that we are testing
+get_filename_component(cpack_path_ "${CMAKE_CPACK_COMMAND}" DIRECTORY)
+set(ENV{PATH} "${cpack_path_}:$ENV{PATH}")
+
+execute_process(COMMAND ${RPMBUILD_EXECUTABLE} --define "_topdir ${CMAKE_CURRENT_BINARY_DIR}/test_rpm" --rebuild ${FOUND_FILE_1}
+ RESULT_VARIABLE result_
+ ERROR_VARIABLE error_
+ OUTPUT_QUIET
+ )
+
+set(output_error_message_
+ "\n${RPMBUILD_EXECUTABLE} error: '${error_}';\nresult: '${result_}';\n${output_error_message}")
+
+# expected file content are test_prog and optional build-id links that are
+# generated by rpmbuild (introduced in rpm 4.13.0.1)
+set(EXPECTED_FILE_CONTENT_ "^/foo${whitespaces_}/foo/test_prog(${whitespaces_}.*\.build-id.*)*$")
+
+file(GLOB_RECURSE FOUND_FILE_ RELATIVE "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS" "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS/*.rpm")
+list(APPEND foundFiles_ "${FOUND_FILE_}")
+list(LENGTH FOUND_FILE_ foundFilesCount_)
+
+if(foundFilesCount_ EQUAL 1)
+ unset(PACKAGE_CONTENT)
+ getPackageContent("${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS/${FOUND_FILE_}" "PACKAGE_CONTENT")
+
+ string(REGEX MATCH "${EXPECTED_FILE_CONTENT_}"
+ expected_content_list "${PACKAGE_CONTENT}")
+
+ if(NOT expected_content_list)
+ message(FATAL_ERROR
+ "Unexpected file content!\n"
+ " Content: '${PACKAGE_CONTENT}'\n\n"
+ " Expected: '${EXPECTED_FILE_CONTENT_}'"
+ "${output_error_message_}")
+ endif()
+else()
+ message(FATAL_ERROR
+ "Found more than one file!"
+ " Found files count '${foundFilesCount_}'."
+ " Files: '${FOUND_FILE_}'"
+ "${output_error_message_}")
+endif()
+
+# check that there were no extra files generated
+foreach(all_files_glob_ IN LISTS ALL_FILES_GLOB)
+ file(GLOB foundAll_ RELATIVE "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS" "${all_files_glob_}")
+ list(APPEND allFoundFiles_ "${foundAll_}")
+endforeach()
+
+list(LENGTH foundFiles_ foundFilesCount_)
+list(LENGTH allFoundFiles_ allFoundFilesCount_)
+
+if(NOT foundFilesCount_ EQUAL allFoundFilesCount_)
+ message(FATAL_ERROR
+ "Found more files than expected! Found files: '${allFoundFiles_}'"
+ "${output_error_message_}")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/SOURCE_PACKAGE/test.cmake b/Tests/RunCMake/CPack/tests/SOURCE_PACKAGE/test.cmake
new file mode 100644
index 0000000..359b98f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/SOURCE_PACKAGE/test.cmake
@@ -0,0 +1,7 @@
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+ "int main() {return 0;}\n")
+add_executable(test_prog "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+
+install(TARGETS test_prog DESTINATION foo COMPONENT applications)
+
+set(CPACK_RPM_FILE_NAME "RPM-DEFAULT")
diff --git a/Tests/RunCMake/CPack/tests/SUGGESTS/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/SUGGESTS/ExpectedFiles.cmake
new file mode 100644
index 0000000..d1a3a5f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/SUGGESTS/ExpectedFiles.cmake
@@ -0,0 +1,2 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/SUGGESTS/RPM-stderr.txt b/Tests/RunCMake/CPack/tests/SUGGESTS/RPM-stderr.txt
new file mode 100644
index 0000000..53d71d9
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/SUGGESTS/RPM-stderr.txt
@@ -0,0 +1 @@
+^(.*CPackRPM:Warning: SUGGESTS not supported in provided rpmbuild.*)?CPackRPM: Will use GENERATED spec file: (/[^/]*)*/Tests/RunCMake/RPM\.SUGGESTS/CPack/[^-]*-build/_CPack_Packages/.*/RPM/SPECS/[^\.]*\.spec$
diff --git a/Tests/RunCMake/CPack/tests/SUGGESTS/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/SUGGESTS/VerifyResult.cmake
new file mode 100644
index 0000000..61ce752
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/SUGGESTS/VerifyResult.cmake
@@ -0,0 +1,31 @@
+execute_process(COMMAND ${RPMBUILD_EXECUTABLE} --querytags
+ OUTPUT_VARIABLE RPMBUILD_CAPS
+ RESULT_VARIABLE RPMBUILD_CAPS_RESULT)
+
+if(NOT RPMBUILD_CAPS_RESULT)
+ string(REPLACE "\n" ";" RPMBUILD_CAPS "${RPMBUILD_CAPS}")
+ cmake_policy(PUSH)
+ cmake_policy(SET CMP0057 NEW)
+ if(SUGGESTS IN_LIST RPMBUILD_CAPS)
+ set(should_contain_suggests_tag_ true)
+ endif()
+ cmake_policy(POP)
+endif()
+
+# Only verify that suggests tag is present only if that tag is supported.
+# If it is not supported the rpm package was correctly generated by ignoring
+# that tag and that was already checked by expected files test.
+if(should_contain_suggests_tag_)
+ execute_process(COMMAND ${RPM_EXECUTABLE} -q --suggests -p "${FOUND_FILE_1}"
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ RESULT_VARIABLE rpm_result_
+ OUTPUT_VARIABLE rpm_output_
+ ERROR_VARIABLE error_variable_
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(rpm_result_ OR NOT rpm_output_ STREQUAL "libsuggested")
+ message(FATAL_ERROR "RPM_SUGGESTED package error: no suggested packages"
+ " (result: '${rpm_result_}'; output: '${rpm_output_}';"
+ " error: '${error_variable_}')")
+ endif()
+endif()
diff --git a/Tests/RunCMake/CPack/tests/SUGGESTS/test.cmake b/Tests/RunCMake/CPack/tests/SUGGESTS/test.cmake
new file mode 100644
index 0000000..dc90ae8
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/SUGGESTS/test.cmake
@@ -0,0 +1,3 @@
+install(FILES CMakeLists.txt DESTINATION foo)
+
+set(CPACK_RPM_PACKAGE_SUGGESTS "libsuggested")
diff --git a/Tests/RunCMake/CPack/tests/SYMLINKS/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/SYMLINKS/ExpectedFiles.cmake
new file mode 100644
index 0000000..e8281a8
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/SYMLINKS/ExpectedFiles.cmake
@@ -0,0 +1,12 @@
+set(EXPECTED_FILES_COUNT "1")
+
+set(EXPECTED_FILE_CONTENT_1_LIST
+ "/empty_dir"
+ "/non_empty_dir"
+ "/non_empty_dir/CMakeLists.txt"
+ "/symlink_to_empty_dir"
+ "/symlink_to_non_empty_dir")
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(EXPECTED_FILE_1_COMPONENT "links")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/SYMLINKS/TGZ-Prerequirements.cmake b/Tests/RunCMake/CPack/tests/SYMLINKS/TGZ-Prerequirements.cmake
new file mode 100644
index 0000000..f3df46b
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/SYMLINKS/TGZ-Prerequirements.cmake
@@ -0,0 +1,5 @@
+function(get_test_prerequirements found_var config_file)
+ if(UNIX) # limit test to platforms that support symlinks
+ set(${found_var} true PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/tests/SYMLINKS/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/SYMLINKS/VerifyResult.cmake
new file mode 100644
index 0000000..0632319
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/SYMLINKS/VerifyResult.cmake
@@ -0,0 +1,26 @@
+set(whitespaces "[\\t\\n\\r ]*")
+
+#######################
+# verify generated symbolic links
+#######################
+file(GLOB_RECURSE symlink_files RELATIVE "${bin_dir}" "${bin_dir}/*/symlink_*")
+
+foreach(check_symlink IN LISTS symlink_files)
+ get_filename_component(symlink_name "${check_symlink}" NAME)
+ execute_process(COMMAND ls -la "${check_symlink}"
+ WORKING_DIRECTORY "${bin_dir}"
+ OUTPUT_VARIABLE SYMLINK_POINT_
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if("${symlink_name}" STREQUAL "symlink_to_empty_dir")
+ string(REGEX MATCH "^.*${whitespaces}->${whitespaces}empty_dir$" check_symlink "${SYMLINK_POINT_}")
+ elseif("${symlink_name}" STREQUAL "symlink_to_non_empty_dir")
+ string(REGEX MATCH "^.*${whitespaces}->${whitespaces}non_empty_dir$" check_symlink "${SYMLINK_POINT_}")
+ else()
+ message(FATAL_ERROR "error: unexpected rpm symbolic link '${check_symlink}'")
+ endif()
+
+ if(NOT check_symlink)
+ message(FATAL_ERROR "symlink points to unexpected location '${SYMLINK_POINT_}'")
+ endif()
+endforeach()
diff --git a/Tests/RunCMake/CPack/tests/SYMLINKS/test.cmake b/Tests/RunCMake/CPack/tests/SYMLINKS/test.cmake
new file mode 100644
index 0000000..fef765c
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/SYMLINKS/test.cmake
@@ -0,0 +1,14 @@
+install(DIRECTORY DESTINATION empty_dir COMPONENT links)
+install(FILES CMakeLists.txt DESTINATION non_empty_dir COMPONENT links)
+
+# test symbolic link to an empty dir
+execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink empty_dir symlink_to_empty_dir)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_to_empty_dir DESTINATION "." COMPONENT links)
+
+# test symbolic link to a non empty dir
+execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink non_empty_dir symlink_to_non_empty_dir)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_to_non_empty_dir DESTINATION "." COMPONENT links)
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(CPACK_COMPONENTS_ALL links)
+endif()
diff --git a/Tests/RunCMake/CPack/tests/THREADED/DEB-Prerequirements.cmake b/Tests/RunCMake/CPack/tests/THREADED/DEB-Prerequirements.cmake
new file mode 100644
index 0000000..7b2692c
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/THREADED/DEB-Prerequirements.cmake
@@ -0,0 +1 @@
+set(CPACK_DEBIAN_COMPRESSION_TYPE xz)
diff --git a/Tests/RunCMake/CPack/tests/THREADED/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/THREADED/ExpectedFiles.cmake
new file mode 100644
index 0000000..d1a3a5f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/THREADED/ExpectedFiles.cmake
@@ -0,0 +1,2 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/THREADED/test.cmake b/Tests/RunCMake/CPack/tests/THREADED/test.cmake
new file mode 100644
index 0000000..9e82e8c
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/THREADED/test.cmake
@@ -0,0 +1,7 @@
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
+
+set(CPACK_THREADS 2)
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(CPACK_COMPONENTS_ALL test)
+endif()
diff --git a/Tests/RunCMake/CPack/tests/THREADED_ALL/DEB-Prerequirements.cmake b/Tests/RunCMake/CPack/tests/THREADED_ALL/DEB-Prerequirements.cmake
new file mode 100644
index 0000000..7b2692c
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/THREADED_ALL/DEB-Prerequirements.cmake
@@ -0,0 +1 @@
+set(CPACK_DEBIAN_COMPRESSION_TYPE xz)
diff --git a/Tests/RunCMake/CPack/tests/THREADED_ALL/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/THREADED_ALL/ExpectedFiles.cmake
new file mode 100644
index 0000000..d1a3a5f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/THREADED_ALL/ExpectedFiles.cmake
@@ -0,0 +1,2 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/THREADED_ALL/test.cmake b/Tests/RunCMake/CPack/tests/THREADED_ALL/test.cmake
new file mode 100644
index 0000000..6f37201
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/THREADED_ALL/test.cmake
@@ -0,0 +1,7 @@
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
+
+set(CPACK_THREADS 0)
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(CPACK_COMPONENTS_ALL test)
+endif()
diff --git a/Tests/RunCMake/CPack/tests/TIMESTAMPS/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/TIMESTAMPS/ExpectedFiles.cmake
new file mode 100644
index 0000000..d1a3a5f
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/TIMESTAMPS/ExpectedFiles.cmake
@@ -0,0 +1,2 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/TIMESTAMPS/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/TIMESTAMPS/VerifyResult.cmake
new file mode 100644
index 0000000..e7e2645
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/TIMESTAMPS/VerifyResult.cmake
@@ -0,0 +1,58 @@
+macro(getFileMetadata_ FILE RESULT_VAR)
+ if(GENERATOR_TYPE STREQUAL "TGZ")
+ # getPackageContent defined for archives omit the metadata (non-verbose)
+ execute_process(COMMAND ${CMAKE_COMMAND} -E env TZ=Etc/UTC ${CMAKE_COMMAND} -E tar -xtvf ${FILE}
+ OUTPUT_VARIABLE ${RESULT_VAR}
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ else()
+ getPackageContent("${FILE}" ${RESULT_VAR})
+ endif()
+endmacro()
+
+function(checkContentTimestamp FILE REGEX)
+ getFileMetadata_("${FILE}" METADATA_)
+
+ if(NOT METADATA_ MATCHES "${REGEX}")
+ string(REPLACE "\n" "\n " metadata_indented "${METADATA_}")
+ message(FATAL_ERROR
+ "Wrong timestamps in file:\n"
+ " ${FILE}\n"
+ "Expected timestamps to match:\n"
+ " ${REGEX}\n"
+ "Actual timestamps:\n"
+ " ${metadata_indented}")
+ endif()
+endfunction()
+
+function(checkTimestamp FILE_NAME)
+ file(READ ${FILE_NAME} ACTUAL_TIMESTAMP OFFSET 4 LIMIT 4 HEX)
+
+ if(NOT ACTUAL_TIMESTAMP STREQUAL "00000000")
+ message(FATAL_ERROR "${FILE_NAME} contains a timestamp [0x${ACTUAL_TIMESTAMP}]")
+ endif()
+endfunction()
+
+# Expected timestamp is UNIX time 123456789
+if(GENERATOR_TYPE STREQUAL "TGZ")
+ set(EXPECTED_TIMESTAMP "29 Nov +1973")
+ set(EXPECTED_FILES foo/ foo/CMakeLists.txt)
+else()
+ set(EXPECTED_TIMESTAMP "1973-11-29 21:33")
+ set(EXPECTED_FILES ./usr/ ./usr/foo/ ./usr/foo/CMakeLists.txt)
+endif()
+
+set(EXPECTED_METADATA)
+foreach(FILE ${EXPECTED_FILES})
+ list(APPEND EXPECTED_METADATA ".* ${EXPECTED_TIMESTAMP} ${FILE}")
+endforeach()
+list(JOIN EXPECTED_METADATA ".*" EXPECTED_REGEX)
+checkContentTimestamp("${FOUND_FILE_1}" "${EXPECTED_REGEX}")
+
+if(GENERATOR_TYPE STREQUAL "TGZ")
+ checkTimestamp("${FOUND_FILE_1}")
+else()
+ execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${FOUND_FILE_1}")
+ checkTimestamp("data.tar.gz")
+ checkTimestamp("control.tar.gz")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/TIMESTAMPS/test.cmake b/Tests/RunCMake/CPack/tests/TIMESTAMPS/test.cmake
new file mode 100644
index 0000000..a193852
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/TIMESTAMPS/test.cmake
@@ -0,0 +1,3 @@
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
+
+set(CPACK_COMPONENTS_ALL test)
diff --git a/Tests/RunCMake/CPack/tests/USER_FILELIST/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/USER_FILELIST/ExpectedFiles.cmake
new file mode 100644
index 0000000..8420986
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/USER_FILELIST/ExpectedFiles.cmake
@@ -0,0 +1,2 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/one;/one/foo.txt;/one/two;/one/two/bar.txt;/three;/three/baz.txt;/three/qux.txt")
diff --git a/Tests/RunCMake/CPack/tests/USER_FILELIST/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/USER_FILELIST/VerifyResult.cmake
new file mode 100644
index 0000000..57444ed
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/USER_FILELIST/VerifyResult.cmake
@@ -0,0 +1,12 @@
+execute_process(COMMAND ${RPM_EXECUTABLE} -qpd ${FOUND_FILE_1}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE DOC_FILES_
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+string(REPLACE "\n" ";" DOC_FILES_ "${DOC_FILES_}")
+
+set(DOC_FILES_WANTED_ "/usr/one/foo.txt;/usr/one/two/bar.txt;/usr/three/baz.txt")
+if (NOT "${DOC_FILES_}" STREQUAL "${DOC_FILES_WANTED_}")
+ message(FATAL_ERROR "USER_FILELIST handling error: Check filelist in spec file. Doc files were: ${DOC_FILES_}. Should have been ${DOC_FILES_WANTED_}")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/USER_FILELIST/test.cmake b/Tests/RunCMake/CPack/tests/USER_FILELIST/test.cmake
new file mode 100644
index 0000000..acfee42
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/USER_FILELIST/test.cmake
@@ -0,0 +1,13 @@
+install(FILES CMakeLists.txt DESTINATION one RENAME foo.txt)
+install(FILES CMakeLists.txt DESTINATION one/two RENAME bar.txt)
+install(FILES CMakeLists.txt DESTINATION three RENAME baz.txt)
+install(FILES CMakeLists.txt DESTINATION three RENAME qux.txt)
+
+# We are verifying the USER_FILELIST works by comparing what
+# ends up with a %doc tag in the final rpm with what we expect
+# from this USER_FILELIST.
+set(CPACK_RPM_USER_FILELIST
+ "%doc /usr/one/foo.txt"
+ "%doc %attr(640,root,root) /usr/one/two/bar.txt"
+ "%attr(600, -, root) %doc /usr/three/baz.txt"
+)
diff --git a/Tests/RunCMake/CPack/tests/VERSION/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/VERSION/ExpectedFiles.cmake
new file mode 100644
index 0000000..372f71b
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/VERSION/ExpectedFiles.cmake
@@ -0,0 +1,3 @@
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
+set(EXPECTED_FILE_1_REVISION "1")
diff --git a/Tests/RunCMake/CPack/tests/VERSION/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/VERSION/VerifyResult.cmake
new file mode 100644
index 0000000..eed9696
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/VERSION/VerifyResult.cmake
@@ -0,0 +1,17 @@
+function(checkPackageInfo_ TYPE FILE REGEX)
+ getPackageInfo("${FILE}" "FILE_INFO_")
+ if(NOT FILE_INFO_ MATCHES "${REGEX}")
+ message(FATAL_ERROR "Unexpected ${TYPE} in '${FILE}' ${EXPECTED_FILE_1_VERSION} ${EXPECTED_FILE_1_REVISION}; file info: '${FILE_INFO_}'")
+ endif()
+endfunction()
+
+set(whitespaces_ "[\t\n\r ]*")
+
+if(GENERATOR_TYPE STREQUAL "RPM")
+ checkPackageInfo_("package version" "${FOUND_FILE_1}" "Version${whitespaces_}:${whitespaces_}${EXPECTED_FILE_1_VERSION}")
+ checkPackageInfo_("package revision" "${FOUND_FILE_1}" "Release${whitespaces_}:${whitespaces_}${EXPECTED_FILE_1_REVISION}")
+ checkPackageInfo_("epoch version" "${FOUND_FILE_1}" "Epoch${whitespaces_}:${whitespaces_}3")
+else() # DEB
+ checkPackageInfo_("version" "${FOUND_FILE_1}"
+ ".*Version${whitespaces_}:${whitespaces_}3:${EXPECTED_FILE_1_VERSION}-${EXPECTED_FILE_1_REVISION}")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/VERSION/test.cmake b/Tests/RunCMake/CPack/tests/VERSION/test.cmake
new file mode 100644
index 0000000..301ab61
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/VERSION/test.cmake
@@ -0,0 +1,14 @@
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
+
+if(GENERATOR_TYPE STREQUAL "DEB")
+ set(package_type_ "DEBIAN")
+ set(CPACK_DEBIAN_PACKAGE_RELEASE "1")
+else()
+ set(package_type_ "${GENERATOR_TYPE}")
+endif()
+
+set(CPACK_${package_type_}_PACKAGE_EPOCH "3")
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+ set(CPACK_COMPONENTS_ALL test)
+endif()
diff --git a/Tests/RunCMake/CPackCommandLine/CMakeLists.txt b/Tests/RunCMake/CPackCommandLine/CMakeLists.txt
new file mode 100644
index 0000000..2632ffa
--- /dev/null
+++ b/Tests/RunCMake/CPackCommandLine/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.16)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CPackCommandLine/MultiConfig-check-stdout.txt b/Tests/RunCMake/CPackCommandLine/MultiConfig-check-stdout.txt
new file mode 100644
index 0000000..f2ae844
--- /dev/null
+++ b/Tests/RunCMake/CPackCommandLine/MultiConfig-check-stdout.txt
@@ -0,0 +1,4 @@
+MultiConfig-0\.1\.1-[^/
+]*/lib/(lib|)foo_dbg\.(a|lib)
+MultiConfig-0\.1\.1-[^/
+]*/lib/(lib|)foo_rel\.(a|lib)
diff --git a/Tests/RunCMake/CPackCommandLine/MultiConfig-package-stdout.txt b/Tests/RunCMake/CPackCommandLine/MultiConfig-package-stdout.txt
new file mode 100644
index 0000000..4fb8181
--- /dev/null
+++ b/Tests/RunCMake/CPackCommandLine/MultiConfig-package-stdout.txt
@@ -0,0 +1,8 @@
+^CPack: Create package using ZIP
+CPack: Install projects
+CPack: - Install project: MultiConfig \[Debug\]
+CPack: - Install project: MultiConfig \[Release\]
+CPack: Create package
+CPack: - package: [^
+]*/Tests/RunCMake/CPackCommandLine/MultiConfig-build/MultiConfig-0.1.1-[^
+]*.zip generated.$
diff --git a/Tests/RunCMake/CPackCommandLine/MultiConfig.cmake b/Tests/RunCMake/CPackCommandLine/MultiConfig.cmake
new file mode 100644
index 0000000..71fd189
--- /dev/null
+++ b/Tests/RunCMake/CPackCommandLine/MultiConfig.cmake
@@ -0,0 +1,9 @@
+enable_language(C)
+
+include(CPack)
+
+add_library(foo foo.c)
+set_property(TARGET foo PROPERTY DEBUG_POSTFIX _dbg)
+set_property(TARGET foo PROPERTY RELEASE_POSTFIX _rel)
+
+install(TARGETS foo)
diff --git a/Tests/RunCMake/CPackCommandLine/NotAGenerator-result.txt b/Tests/RunCMake/CPackCommandLine/NotAGenerator-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CPackCommandLine/NotAGenerator-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CPackCommandLine/NotAGenerator-stderr.txt b/Tests/RunCMake/CPackCommandLine/NotAGenerator-stderr.txt
new file mode 100644
index 0000000..a553bde
--- /dev/null
+++ b/Tests/RunCMake/CPackCommandLine/NotAGenerator-stderr.txt
@@ -0,0 +1 @@
+^CPack Error: Could not create CPack generator: NotAGenerator
diff --git a/Tests/RunCMake/CPackCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CPackCommandLine/RunCMakeTest.cmake
new file mode 100644
index 0000000..53f4e4f
--- /dev/null
+++ b/Tests/RunCMake/CPackCommandLine/RunCMakeTest.cmake
@@ -0,0 +1,33 @@
+include(RunCMake)
+set(RunCMake_TEST_TIMEOUT 60)
+
+file(WRITE "${RunCMake_BINARY_DIR}/NotAGenerator-build/CPackConfig.cmake" [[
+set(CPACK_PACKAGE_NAME "Test")
+set(CPACK_PACKAGE_VERSION "1")
+]])
+set(RunCMake_TEST_NO_CLEAN 1)
+run_cmake_command(NotAGenerator ${CMAKE_CPACK_COMMAND} -G NotAGenerator)
+unset(RunCMake_TEST_NO_CLEAN)
+
+function(run_MultiConfig)
+ set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/MultiConfig-build")
+ run_cmake(MultiConfig)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(MultiConfig-build-dbg ${CMAKE_COMMAND} --build . --config Debug)
+ run_cmake_command(MultiConfig-build-rel ${CMAKE_COMMAND} --build . --config Release)
+ run_cmake_command(MultiConfig-package ${CMAKE_CPACK_COMMAND} -G ZIP -C "Debug\;Release")
+ set(zip_glob "${RunCMake_TEST_BINARY_DIR}/MultiConfig-0.1.1-*.zip")
+ file(GLOB zips "${zip_glob}")
+ set(zip_found 0)
+ foreach(zip IN LISTS zips)
+ set(zip_found 1)
+ run_cmake_command(MultiConfig-check ${CMAKE_COMMAND} -E tar tf "${zip}")
+ endforeach()
+ if(NOT zip_found)
+ message(SEND_ERROR "No package file found at\n ${zip_glob}")
+ endif()
+endfunction()
+
+if(RunCMake_GENERATOR MATCHES "Visual Studio|Xcode")
+ run_MultiConfig()
+endif()
diff --git a/Tests/RunCMake/CPackCommandLine/foo.c b/Tests/RunCMake/CPackCommandLine/foo.c
new file mode 100644
index 0000000..c83d856
--- /dev/null
+++ b/Tests/RunCMake/CPackCommandLine/foo.c
@@ -0,0 +1,4 @@
+int foo(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CPackConfig/CMakeLists.txt b/Tests/RunCMake/CPackConfig/CMakeLists.txt
new file mode 100644
index 0000000..9a9e7b4
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.3)
+
+project(${RunCMake_TEST})
+include(${RunCMake_TEST}.cmake)
+
+include(CPack)
diff --git a/Tests/RunCMake/CPackConfig/Default-check.cmake b/Tests/RunCMake/CPackConfig/Default-check.cmake
new file mode 100644
index 0000000..b67fe81
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/Default-check.cmake
@@ -0,0 +1,7 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+
+test_variable(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "Foo\\Bar")
+test_variable(CPACK_NSIS_PACKAGE_NAME "Bar\\Foo")
+
+test_variable(CPACK_SOURCE_IGNORE_FILES
+ "/CVS/;/\\.svn/;/\\.bzr/;/\\.hg/;/\\.git/;\\.swp$;\\.#;/#")
diff --git a/Tests/RunCMake/CPackConfig/Default.cmake b/Tests/RunCMake/CPackConfig/Default.cmake
new file mode 100644
index 0000000..3b3beb3
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/Default.cmake
@@ -0,0 +1,3 @@
+# two levels of escaping to pass through CPackConfig.cmake
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "Foo\\\\Bar")
+set(CPACK_NSIS_DISPLAY_NAME "Bar\\\\Foo")
diff --git a/Tests/RunCMake/CPackConfig/RunCMakeTest.cmake b/Tests/RunCMake/CPackConfig/RunCMakeTest.cmake
new file mode 100644
index 0000000..8f2196d
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/RunCMakeTest.cmake
@@ -0,0 +1,9 @@
+include(RunCMake)
+
+run_cmake(Simple)
+run_cmake(Default)
+run_cmake(Special)
+run_cmake(Verbatim)
+run_cmake(Version1)
+run_cmake(Version2)
+run_cmake(Version3)
diff --git a/Tests/RunCMake/CPackConfig/Simple-check.cmake b/Tests/RunCMake/CPackConfig/Simple-check.cmake
new file mode 100644
index 0000000..6e0cf6f
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/Simple-check.cmake
@@ -0,0 +1,3 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+
+test_variable(CPACK_FOO "bar baz;quux")
diff --git a/Tests/RunCMake/CPackConfig/Simple.cmake b/Tests/RunCMake/CPackConfig/Simple.cmake
new file mode 100644
index 0000000..c9f6541
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/Simple.cmake
@@ -0,0 +1 @@
+set(CPACK_FOO "bar baz;quux")
diff --git a/Tests/RunCMake/CPackConfig/Special-check.cmake b/Tests/RunCMake/CPackConfig/Special-check.cmake
new file mode 100644
index 0000000..0624b79
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/Special-check.cmake
@@ -0,0 +1,5 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+
+test_variable(CPACK_BACKSLASH "\\")
+test_variable(CPACK_QUOTE "a;b;c")
+test_variable(CPACK_DOLLAR "ab")
diff --git a/Tests/RunCMake/CPackConfig/Special.cmake b/Tests/RunCMake/CPackConfig/Special.cmake
new file mode 100644
index 0000000..9442c93
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/Special.cmake
@@ -0,0 +1,3 @@
+set(CPACK_BACKSLASH "\\\\")
+set(CPACK_QUOTE "a\" b \"c")
+set(CPACK_DOLLAR "a\${NOTHING}b")
diff --git a/Tests/RunCMake/CPackConfig/Verbatim-check.cmake b/Tests/RunCMake/CPackConfig/Verbatim-check.cmake
new file mode 100644
index 0000000..958547d
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/Verbatim-check.cmake
@@ -0,0 +1,10 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+
+test_variable(CPACK_BACKSLASH "\\\\")
+test_variable(CPACK_QUOTE "a\" b \"c")
+test_variable(CPACK_DOLLAR "a\${NOTHING}b")
+
+# make sure the default for this is still set correctly with
+# CPACK_VERBATIM_VARIABLES on
+test_variable(CPACK_SOURCE_IGNORE_FILES
+ "/CVS/;/\\.svn/;/\\.bzr/;/\\.hg/;/\\.git/;\\.swp$;\\.#;/#")
diff --git a/Tests/RunCMake/CPackConfig/Verbatim.cmake b/Tests/RunCMake/CPackConfig/Verbatim.cmake
new file mode 100644
index 0000000..4d271c3
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/Verbatim.cmake
@@ -0,0 +1,5 @@
+set(CPACK_VERBATIM_VARIABLES YES)
+
+set(CPACK_BACKSLASH "\\\\")
+set(CPACK_QUOTE "a\" b \"c")
+set(CPACK_DOLLAR "a\${NOTHING}b")
diff --git a/Tests/RunCMake/CPackConfig/Version1-check.cmake b/Tests/RunCMake/CPackConfig/Version1-check.cmake
new file mode 100644
index 0000000..0f5347f
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/Version1-check.cmake
@@ -0,0 +1,6 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+
+test_variable(CPACK_PACKAGE_VERSION "0")
+test_variable(CPACK_PACKAGE_VERSION_MAJOR "0")
+test_variable(CPACK_PACKAGE_VERSION_MINOR "")
+test_variable(CPACK_PACKAGE_VERSION_PATCH "")
diff --git a/Tests/RunCMake/CPackConfig/Version1.cmake b/Tests/RunCMake/CPackConfig/Version1.cmake
new file mode 100644
index 0000000..703485c
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/Version1.cmake
@@ -0,0 +1 @@
+project(Version LANGUAGES NONE VERSION 0)
diff --git a/Tests/RunCMake/CPackConfig/Version2-check.cmake b/Tests/RunCMake/CPackConfig/Version2-check.cmake
new file mode 100644
index 0000000..3a2d572
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/Version2-check.cmake
@@ -0,0 +1,6 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+
+test_variable(CPACK_PACKAGE_VERSION "1.0")
+test_variable(CPACK_PACKAGE_VERSION_MAJOR "1")
+test_variable(CPACK_PACKAGE_VERSION_MINOR "0")
+test_variable(CPACK_PACKAGE_VERSION_PATCH "")
diff --git a/Tests/RunCMake/CPackConfig/Version2.cmake b/Tests/RunCMake/CPackConfig/Version2.cmake
new file mode 100644
index 0000000..c084137
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/Version2.cmake
@@ -0,0 +1 @@
+project(Version LANGUAGES NONE VERSION 1.0)
diff --git a/Tests/RunCMake/CPackConfig/Version3-check.cmake b/Tests/RunCMake/CPackConfig/Version3-check.cmake
new file mode 100644
index 0000000..d4a3983
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/Version3-check.cmake
@@ -0,0 +1,6 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+
+test_variable(CPACK_PACKAGE_VERSION "1.1.0")
+test_variable(CPACK_PACKAGE_VERSION_MAJOR "1")
+test_variable(CPACK_PACKAGE_VERSION_MINOR "1")
+test_variable(CPACK_PACKAGE_VERSION_PATCH "0")
diff --git a/Tests/RunCMake/CPackConfig/Version3.cmake b/Tests/RunCMake/CPackConfig/Version3.cmake
new file mode 100644
index 0000000..4df28bb
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/Version3.cmake
@@ -0,0 +1 @@
+project(Version LANGUAGES NONE VERSION 1.1.0)
diff --git a/Tests/RunCMake/CPackConfig/check.cmake b/Tests/RunCMake/CPackConfig/check.cmake
new file mode 100644
index 0000000..ca6229e
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/check.cmake
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION ${CMAKE_VERSION} FATAL_ERROR)
+
+function(test_variable NAME EXPECTED_VALUE)
+ if(NOT "${${NAME}}" STREQUAL "${EXPECTED_VALUE}")
+ message(FATAL_ERROR "${NAME}: variable mismatch; expected [${EXPECTED_VALUE}] actual [${${NAME}}]")
+ endif()
+endfunction()
+
+include(${RunCMake_TEST_BINARY_DIR}/CPackConfig.cmake)
+include(${RunCMake_TEST_BINARY_DIR}/CPackSourceConfig.cmake)
diff --git a/Tests/RunCMake/CPackInstallProperties/Append-check.cmake b/Tests/RunCMake/CPackInstallProperties/Append-check.cmake
new file mode 100644
index 0000000..017b30d
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/Append-check.cmake
@@ -0,0 +1,3 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+
+test_property("append.txt" CPACK_TEST_PROP "value1;value2;value3")
diff --git a/Tests/RunCMake/CPackInstallProperties/Append.cmake b/Tests/RunCMake/CPackInstallProperties/Append.cmake
new file mode 100644
index 0000000..cecc45f
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/Append.cmake
@@ -0,0 +1,2 @@
+set_property(INSTALL append.txt PROPERTY CPACK_TEST_PROP value1)
+set_property(INSTALL append.txt PROPERTY CPACK_TEST_PROP value2 value3 APPEND)
diff --git a/Tests/RunCMake/CPackInstallProperties/CMakeLists.txt b/Tests/RunCMake/CPackInstallProperties/CMakeLists.txt
new file mode 100644
index 0000000..89ff7c4
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)
+
+include(CPack)
diff --git a/Tests/RunCMake/CPackInstallProperties/FilenameGenex-check.cmake b/Tests/RunCMake/CPackInstallProperties/FilenameGenex-check.cmake
new file mode 100644
index 0000000..8c9e967
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/FilenameGenex-check.cmake
@@ -0,0 +1,3 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+
+test_property(${EXPECTED_MYTEST_NAME} CPACK_TEST_PROP2 PROP_VALUE2)
diff --git a/Tests/RunCMake/CPackInstallProperties/FilenameGenex.cmake b/Tests/RunCMake/CPackInstallProperties/FilenameGenex.cmake
new file mode 100644
index 0000000..8fc1218
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/FilenameGenex.cmake
@@ -0,0 +1,7 @@
+add_executable(mytest test.cpp)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/runtest_info.cmake CONTENT [[
+set(EXPECTED_MYTEST_NAME "$<TARGET_FILE_NAME:mytest>")
+]])
+
+set_property(INSTALL $<TARGET_FILE_NAME:mytest> PROPERTY CPACK_TEST_PROP2 PROP_VALUE2)
diff --git a/Tests/RunCMake/CPackInstallProperties/MultipleValues-check.cmake b/Tests/RunCMake/CPackInstallProperties/MultipleValues-check.cmake
new file mode 100644
index 0000000..91278ba
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/MultipleValues-check.cmake
@@ -0,0 +1,3 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+
+test_property("multiple_values.txt" CPACK_TEST_PROP "value1;value2;value3")
diff --git a/Tests/RunCMake/CPackInstallProperties/MultipleValues.cmake b/Tests/RunCMake/CPackInstallProperties/MultipleValues.cmake
new file mode 100644
index 0000000..26db52a
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/MultipleValues.cmake
@@ -0,0 +1 @@
+set_property(INSTALL multiple_values.txt PROPERTY CPACK_TEST_PROP value1 value2 value3)
diff --git a/Tests/RunCMake/CPackInstallProperties/PerConfigValue-check.cmake b/Tests/RunCMake/CPackInstallProperties/PerConfigValue-check.cmake
new file mode 100644
index 0000000..2966d88
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/PerConfigValue-check.cmake
@@ -0,0 +1,13 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+
+file(GLOB INFO_FILES ${RunCMake_TEST_BINARY_DIR}/runtest_info_*.cmake)
+
+if(NOT INFO_FILES)
+ message(FATAL_ERROR "missing expected info files")
+endif()
+
+foreach(INFO_FILE IN LISTS INFO_FILES)
+ include(${INFO_FILE})
+ include(${RunCMake_TEST_BINARY_DIR}/CPackProperties.cmake)
+ test_property("config.cpp" FOO ${EXPECTED_MYTEST_NAME})
+endforeach()
diff --git a/Tests/RunCMake/CPackInstallProperties/PerConfigValue.cmake b/Tests/RunCMake/CPackInstallProperties/PerConfigValue.cmake
new file mode 100644
index 0000000..b23d3c7
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/PerConfigValue.cmake
@@ -0,0 +1,14 @@
+add_executable(mytest test.cpp)
+
+foreach(CONFIG IN LISTS CMAKE_CONFIGURATION_TYPES)
+ string(TOUPPER ${CONFIG} UPPER_CONFIG)
+ set_property(TARGET mytest PROPERTY
+ OUTPUT_NAME_${UPPER_CONFIG} bar_${CONFIG})
+endforeach()
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/runtest_info_$<CONFIG>.cmake CONTENT [[
+set(CPACK_BUILD_CONFIG "$<CONFIG>")
+set(EXPECTED_MYTEST_NAME "$<TARGET_FILE_NAME:mytest>")
+]])
+
+set_property(INSTALL config.cpp PROPERTY FOO $<TARGET_FILE_NAME:mytest>)
diff --git a/Tests/RunCMake/CPackInstallProperties/Replace-check.cmake b/Tests/RunCMake/CPackInstallProperties/Replace-check.cmake
new file mode 100644
index 0000000..6e492e7
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/Replace-check.cmake
@@ -0,0 +1,3 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+
+test_property("replace.txt" CPACK_TEST_PROP "value2")
diff --git a/Tests/RunCMake/CPackInstallProperties/Replace.cmake b/Tests/RunCMake/CPackInstallProperties/Replace.cmake
new file mode 100644
index 0000000..104d5a4
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/Replace.cmake
@@ -0,0 +1,2 @@
+set_property(INSTALL replace.txt PROPERTY CPACK_TEST_PROP value1)
+set_property(INSTALL replace.txt PROPERTY CPACK_TEST_PROP value2)
diff --git a/Tests/RunCMake/CPackInstallProperties/RunCMakeTest.cmake b/Tests/RunCMake/CPackInstallProperties/RunCMakeTest.cmake
new file mode 100644
index 0000000..d244ac5
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/RunCMakeTest.cmake
@@ -0,0 +1,9 @@
+include(RunCMake)
+
+run_cmake(Simple)
+run_cmake(FilenameGenex)
+run_cmake(ValueGenex)
+run_cmake(MultipleValues)
+run_cmake(Append)
+run_cmake(Replace)
+run_cmake(PerConfigValue)
diff --git a/Tests/RunCMake/CPackInstallProperties/Simple-check.cmake b/Tests/RunCMake/CPackInstallProperties/Simple-check.cmake
new file mode 100644
index 0000000..6a7ee2a
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/Simple-check.cmake
@@ -0,0 +1,3 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+
+test_property("foo/test.cpp" CPACK_TEST_PROP PROP_VALUE)
diff --git a/Tests/RunCMake/CPackInstallProperties/Simple.cmake b/Tests/RunCMake/CPackInstallProperties/Simple.cmake
new file mode 100644
index 0000000..2eb8755
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/Simple.cmake
@@ -0,0 +1 @@
+set_property(INSTALL foo/test.cpp PROPERTY CPACK_TEST_PROP PROP_VALUE)
diff --git a/Tests/RunCMake/CPackInstallProperties/ValueGenex-check.cmake b/Tests/RunCMake/CPackInstallProperties/ValueGenex-check.cmake
new file mode 100644
index 0000000..cdfbcda
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/ValueGenex-check.cmake
@@ -0,0 +1,3 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+
+test_property("bar/test.cpp" CPACK_TEST_PROP ${EXPECTED_MYTEST_NAME})
diff --git a/Tests/RunCMake/CPackInstallProperties/ValueGenex.cmake b/Tests/RunCMake/CPackInstallProperties/ValueGenex.cmake
new file mode 100644
index 0000000..2001d9f
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/ValueGenex.cmake
@@ -0,0 +1,7 @@
+add_executable(mytest test.cpp)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/runtest_info.cmake CONTENT [[
+set(EXPECTED_MYTEST_NAME "$<TARGET_FILE_NAME:mytest>")
+]])
+
+set_property(INSTALL bar/test.cpp PROPERTY CPACK_TEST_PROP $<TARGET_FILE_NAME:mytest>)
diff --git a/Tests/RunCMake/CPackInstallProperties/check.cmake b/Tests/RunCMake/CPackInstallProperties/check.cmake
new file mode 100644
index 0000000..65aa467
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/check.cmake
@@ -0,0 +1,12 @@
+function(test_property FILE NAME EXPECTED_VALUE)
+ get_property(ACTUAL_VALUE INSTALL "${FILE}" PROPERTY "${NAME}")
+
+ if(NOT "${ACTUAL_VALUE}" STREQUAL "${EXPECTED_VALUE}")
+ message(FATAL_ERROR "${NAME}@${FILE}: property mismatch expected [${EXPECTED_VALUE}] actual [${ACTUAL_VALUE}] (Config:${CPACK_BUILD_CONFIG})")
+ endif()
+endfunction()
+
+set(CPACK_BUILD_CONFIG Debug)
+include(${RunCMake_TEST_BINARY_DIR}/CPackProperties.cmake)
+
+include(${RunCMake_TEST_BINARY_DIR}/runtest_info.cmake OPTIONAL)
diff --git a/Tests/RunCMake/CPackInstallProperties/test.cpp b/Tests/RunCMake/CPackInstallProperties/test.cpp
new file mode 100644
index 0000000..5047a34
--- /dev/null
+++ b/Tests/RunCMake/CPackInstallProperties/test.cpp
@@ -0,0 +1,3 @@
+int main()
+{
+}
diff --git a/Tests/RunCMake/CPackSymlinks/RunCMakeTest.cmake b/Tests/RunCMake/CPackSymlinks/RunCMakeTest.cmake
new file mode 100644
index 0000000..5a8b7a0
--- /dev/null
+++ b/Tests/RunCMake/CPackSymlinks/RunCMakeTest.cmake
@@ -0,0 +1,21 @@
+include(RunCMake)
+
+function(run_cpack_symlink_test)
+ set(RunCMake_TEST_NO_CLEAN TRUE)
+ set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/SrcSymlinks-build")
+ set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/SrcSymlinks")
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}")
+ run_cmake_command(SrcSymlinksTar
+ ${CMAKE_COMMAND} -E chdir ${RunCMake_TEST_SOURCE_DIR}
+ ${CMAKE_COMMAND} -E tar xvf ${RunCMake_SOURCE_DIR}/testcpacksym.tar
+ )
+ run_cmake(SrcSymlinksCMake)
+ run_cmake_command(SrcSymlinksCPack
+ ${CMAKE_CPACK_COMMAND} --config CPackSourceConfig.cmake
+ )
+ run_cmake_script(SrcSymlinksCheck)
+endfunction()
+
+run_cpack_symlink_test()
diff --git a/Tests/RunCMake/CPackSymlinks/SrcSymlinksCheck.cmake b/Tests/RunCMake/CPackSymlinks/SrcSymlinksCheck.cmake
new file mode 100644
index 0000000..0041c92
--- /dev/null
+++ b/Tests/RunCMake/CPackSymlinks/SrcSymlinksCheck.cmake
@@ -0,0 +1,21 @@
+set(dir ${CMAKE_CURRENT_SOURCE_DIR})
+
+set(tarball ${dir}/SrcSymlinks-0.1-Source.tar.gz)
+set(extrdir ${dir}/SrcSymlinks-0.1-Source)
+
+message(STATUS "Extracting ${tarball} in ${dir}...")
+execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ${tarball}
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE output
+ WORKING_DIRECTORY ${dir})
+message(STATUS "result='${result}'")
+message(STATUS "output='${output}'")
+
+if(NOT ${result} EQUAL 0)
+ message(FATAL_ERROR "Cannot unpack source tarball")
+endif()
+
+if(NOT EXISTS ${extrdir}/dirlink/src.h)
+ message(FATAL_ERROR "${extrdir}/dirlink/src.h not found")
+endif()
diff --git a/Tests/RunCMake/CPackSymlinks/SrcSymlinksTar-stdout.txt b/Tests/RunCMake/CPackSymlinks/SrcSymlinksTar-stdout.txt
new file mode 100644
index 0000000..8b1ae57
--- /dev/null
+++ b/Tests/RunCMake/CPackSymlinks/SrcSymlinksTar-stdout.txt
@@ -0,0 +1,9 @@
+^x build.sh
+x CMakeLists.txt
+x dirlink
+x include/
+x include/src.h
+x link.h
+x real.h
+x src/
+x src/src.h$
diff --git a/Tests/RunCMake/CPackSymlinks/testcpacksym.tar b/Tests/RunCMake/CPackSymlinks/testcpacksym.tar
new file mode 100644
index 0000000..c24af48
--- /dev/null
+++ b/Tests/RunCMake/CPackSymlinks/testcpacksym.tar
Binary files differ
diff --git a/Tests/RunCMake/CSharpCustomCommand/CMakeLists.txt b/Tests/RunCMake/CSharpCustomCommand/CMakeLists.txt
new file mode 100644
index 0000000..74b3ff8
--- /dev/null
+++ b/Tests/RunCMake/CSharpCustomCommand/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.3)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CSharpCustomCommand/CommandWithOutput-check.cmake b/Tests/RunCMake/CSharpCustomCommand/CommandWithOutput-check.cmake
new file mode 100644
index 0000000..60d77eb
--- /dev/null
+++ b/Tests/RunCMake/CSharpCustomCommand/CommandWithOutput-check.cmake
@@ -0,0 +1,21 @@
+if(checkLevel EQUAL 0)
+ message("checking generation (${srcName} does not exist)")
+ if(EXISTS "${generatedFileName}")
+ set(RunCMake_TEST_FAILED "file \"${generatedFileName}\" should not exist")
+ endif()
+elseif(checkLevel EQUAL 1)
+ message("checking build 1 (generate ${srcName})")
+ if(NOT "${actual_stdout}" MATCHES "${commandComment}")
+ set(RunCMake_TEST_FAILED "command not executed")
+ endif()
+elseif(checkLevel EQUAL 2)
+ message("checking build 2 (no change in ${srcName}.in)")
+ if("${actual_stdout}" MATCHES "${commandComment}")
+ set(RunCMake_TEST_FAILED "command executed")
+ endif()
+elseif(checkLevel EQUAL 3)
+ message("checking build 3 (update ${srcName})")
+ if(NOT "${actual_stdout}" MATCHES "${commandComment}")
+ set(RunCMake_TEST_FAILED "command not executed")
+ endif()
+endif()
diff --git a/Tests/RunCMake/CSharpCustomCommand/CommandWithOutput.cmake b/Tests/RunCMake/CSharpCustomCommand/CommandWithOutput.cmake
new file mode 100644
index 0000000..68341fa
--- /dev/null
+++ b/Tests/RunCMake/CSharpCustomCommand/CommandWithOutput.cmake
@@ -0,0 +1,13 @@
+enable_language(CSharp)
+
+add_executable(CSharpCustomCommand dummy.cs)
+
+add_custom_command(OUTPUT ${generatedFileName}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${inputFileName} ${generatedFileName}
+ MAIN_DEPENDENCY ${inputFileName}
+ COMMENT "${commandComment}")
+
+target_sources(CSharpCustomCommand PRIVATE
+ ${inputFileName}
+ ${generatedFileName})
diff --git a/Tests/RunCMake/CSharpCustomCommand/RunCMakeTest.cmake b/Tests/RunCMake/CSharpCustomCommand/RunCMakeTest.cmake
new file mode 100644
index 0000000..ab3e51b
--- /dev/null
+++ b/Tests/RunCMake/CSharpCustomCommand/RunCMakeTest.cmake
@@ -0,0 +1,42 @@
+include(RunCMake)
+
+function(run_TargetWithCommand)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/TargetWithCommand-build)
+ run_cmake(TargetWithCommand)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(TargetWithCommand-build ${CMAKE_COMMAND} --build . --config Debug)
+endfunction()
+run_TargetWithCommand()
+
+# Use a single build tree for a few tests without cleaning.
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CommandWithOutput-build)
+set(RunCMake_TEST_NO_CLEAN 1)
+file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+set(RunCMake-check-file CommandWithOutput-check.cmake)
+
+set(srcName "test.cs")
+set(srcFileName "${CMAKE_CURRENT_LIST_DIR}/${srcName}.in")
+set(inputFileName "${RunCMake_TEST_BINARY_DIR}/${srcName}.in")
+set(generatedFileName "${RunCMake_TEST_BINARY_DIR}/${srcName}")
+set(commandComment "Generating ${srcName}")
+
+# copy the input file to build dir to avoid changing files in cmake
+# source tree.
+file(COPY "${srcFileName}" DESTINATION "${RunCMake_TEST_BINARY_DIR}")
+
+set(RunCMake_TEST_OPTIONS ${RunCMake_TEST_OPTIONS}
+ "-DinputFileName=${inputFileName}"
+ "-DgeneratedFileName=${generatedFileName}"
+ "-DcommandComment=${commandComment}")
+
+set(checkLevel 0)
+run_cmake(CommandWithOutput)
+set(checkLevel 1)
+run_cmake_command(CommandWithOutput-build1 ${CMAKE_COMMAND} --build . --config Debug)
+set(checkLevel 2)
+run_cmake_command(CommandWithOutput-build2 ${CMAKE_COMMAND} --build . --config Debug)
+# change file content to trigger custom command with next build
+file(APPEND ${inputFileName} "\n")
+set(checkLevel 3)
+run_cmake_command(CommandWithOutput-build3 ${CMAKE_COMMAND} --build . --config Debug)
diff --git a/Tests/RunCMake/CSharpCustomCommand/TargetWithCommand-build-stdout.txt b/Tests/RunCMake/CSharpCustomCommand/TargetWithCommand-build-stdout.txt
new file mode 100644
index 0000000..c212a8f
--- /dev/null
+++ b/Tests/RunCMake/CSharpCustomCommand/TargetWithCommand-build-stdout.txt
@@ -0,0 +1 @@
+Custom target with CSharp source
diff --git a/Tests/RunCMake/CSharpCustomCommand/TargetWithCommand.cmake b/Tests/RunCMake/CSharpCustomCommand/TargetWithCommand.cmake
new file mode 100644
index 0000000..fdaea5c
--- /dev/null
+++ b/Tests/RunCMake/CSharpCustomCommand/TargetWithCommand.cmake
@@ -0,0 +1,4 @@
+enable_language(CSharp)
+
+add_custom_target(drive ALL SOURCES dummy.cs
+ COMMAND ${CMAKE_COMMAND} -E echo "Custom target with CSharp source")
diff --git a/Tests/RunCMake/CSharpCustomCommand/dummy.cs b/Tests/RunCMake/CSharpCustomCommand/dummy.cs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CSharpCustomCommand/dummy.cs
diff --git a/Tests/RunCMake/CSharpCustomCommand/test.cs.in b/Tests/RunCMake/CSharpCustomCommand/test.cs.in
new file mode 100644
index 0000000..05a7531
--- /dev/null
+++ b/Tests/RunCMake/CSharpCustomCommand/test.cs.in
@@ -0,0 +1,8 @@
+class TestCs
+{
+ public static int Main(string[] args)
+ {
+ System.Console.WriteLine("Test C#");
+ return 0;
+ }
+}
diff --git a/Tests/RunCMake/CSharpReferenceImport/CMakeLists.txt b/Tests/RunCMake/CSharpReferenceImport/CMakeLists.txt
new file mode 100644
index 0000000..74b3ff8
--- /dev/null
+++ b/Tests/RunCMake/CSharpReferenceImport/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.3)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLib.cmake b/Tests/RunCMake/CSharpReferenceImport/ImportLib.cmake
new file mode 100644
index 0000000..5ad6e76
--- /dev/null
+++ b/Tests/RunCMake/CSharpReferenceImport/ImportLib.cmake
@@ -0,0 +1,45 @@
+enable_language(CXX CSharp)
+
+if(NOT DEFINED exportFileName OR
+ NOT DEFINED exportNameSpace OR
+ NOT DEFINED exportTargetName)
+ message(FATAL_ERROR "export information missing")
+endif()
+
+add_library(${exportTargetName}CSharp SHARED
+ ImportLib.cs)
+
+# native c++ dll
+add_library(${exportTargetName}Native SHARED
+ ImportLibNative.h
+ ImportLibNative.cxx)
+
+# mixed c++ dll
+add_library(${exportTargetName}Mixed SHARED
+ ImportLibMixed.cxx
+ ImportLibMixedNative.h
+ ImportLibMixedNative.cxx)
+set_target_properties(${exportTargetName}Mixed PROPERTIES
+ COMMON_LANGUAGE_RUNTIME "")
+
+# pure c++ dll
+add_library(${exportTargetName}Pure SHARED
+ ImportLibPure.cxx)
+set_target_properties(${exportTargetName}Pure PROPERTIES
+ COMMON_LANGUAGE_RUNTIME "pure")
+
+# safe c++ dll
+add_library(${exportTargetName}Safe SHARED
+ ImportLibSafe.cxx)
+set_target_properties(${exportTargetName}Safe PROPERTIES
+ COMMON_LANGUAGE_RUNTIME "safe")
+
+# generate export file
+export(TARGETS
+ ${exportTargetName}CSharp
+ ${exportTargetName}Native
+ ${exportTargetName}Mixed
+ ${exportTargetName}Pure
+ ${exportTargetName}Safe
+ NAMESPACE "${exportNameSpace}:"
+ FILE "${exportFileName}")
diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLib.cs b/Tests/RunCMake/CSharpReferenceImport/ImportLib.cs
new file mode 100644
index 0000000..4eb28af
--- /dev/null
+++ b/Tests/RunCMake/CSharpReferenceImport/ImportLib.cs
@@ -0,0 +1,8 @@
+using System;
+
+public
+class ImportLibCSharp
+{
+public
+ static void Message() { Console.WriteLine("ImportLibCSharp"); }
+}
diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLibMixed.cxx b/Tests/RunCMake/CSharpReferenceImport/ImportLibMixed.cxx
new file mode 100644
index 0000000..d0b810e
--- /dev/null
+++ b/Tests/RunCMake/CSharpReferenceImport/ImportLibMixed.cxx
@@ -0,0 +1,8 @@
+using namespace System;
+
+public
+ref class ImportLibMixed
+{
+public:
+ static void Message() { Console::WriteLine("ImportLibMixed"); }
+};
diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.cxx b/Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.cxx
new file mode 100644
index 0000000..c85a776
--- /dev/null
+++ b/Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.cxx
@@ -0,0 +1,8 @@
+#include "ImportLibMixedNative.h"
+
+#include <iostream>
+
+void ImportLibMixedNative::Message()
+{
+ std::cout << "ImportLibMixedNative" << std::endl;
+}
diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.h b/Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.h
new file mode 100644
index 0000000..76b97c4
--- /dev/null
+++ b/Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#ifdef ImportLibMixed_EXPORTS
+# define mixedAPI __declspec(dllexport)
+#else
+# define mixedAPI __declspec(dllimport)
+#endif
+
+class mixedAPI ImportLibMixedNative
+{
+public:
+ static void Message();
+};
diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLibNative.cxx b/Tests/RunCMake/CSharpReferenceImport/ImportLibNative.cxx
new file mode 100644
index 0000000..8e08b9a
--- /dev/null
+++ b/Tests/RunCMake/CSharpReferenceImport/ImportLibNative.cxx
@@ -0,0 +1,8 @@
+#include "ImportLibNative.h"
+
+#include <iostream>
+
+void ImportLibNative::Message()
+{
+ std::cout << "ImportLibNative" << std::endl;
+}
diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLibNative.h b/Tests/RunCMake/CSharpReferenceImport/ImportLibNative.h
new file mode 100644
index 0000000..77bcb82
--- /dev/null
+++ b/Tests/RunCMake/CSharpReferenceImport/ImportLibNative.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#ifdef ImportLibNative_EXPORTS
+# define nativeAPI __declspec(dllexport)
+#else
+# define nativeAPI __declspec(dllimport)
+#endif
+
+class nativeAPI ImportLibNative
+{
+public:
+ static void Message();
+};
diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLibPure.cxx b/Tests/RunCMake/CSharpReferenceImport/ImportLibPure.cxx
new file mode 100644
index 0000000..271e375
--- /dev/null
+++ b/Tests/RunCMake/CSharpReferenceImport/ImportLibPure.cxx
@@ -0,0 +1,8 @@
+using namespace System;
+
+public
+ref class ImportLibPure
+{
+public:
+ static void Message() { Console::WriteLine("ImportLibPure"); }
+};
diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLibSafe.cxx b/Tests/RunCMake/CSharpReferenceImport/ImportLibSafe.cxx
new file mode 100644
index 0000000..13b40da
--- /dev/null
+++ b/Tests/RunCMake/CSharpReferenceImport/ImportLibSafe.cxx
@@ -0,0 +1,8 @@
+using namespace System;
+
+public
+ref class ImportLibSafe
+{
+public:
+ static void Message() { Console::WriteLine("ImportLibSafe"); }
+};
diff --git a/Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cmake b/Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cmake
new file mode 100644
index 0000000..c65f623
--- /dev/null
+++ b/Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cmake
@@ -0,0 +1,88 @@
+enable_language(CXX CSharp)
+
+if(NOT DEFINED exportFileName OR
+ NOT DEFINED exportNameSpace OR
+ NOT DEFINED exportTargetName)
+ message(FATAL_ERROR "export information missing")
+endif()
+
+# Include generated export file.
+if(NOT EXISTS "${exportFileName}")
+ message(FATAL_ERROR "exportFileNameCSharp does not exist: ${exportFileName}")
+endif()
+include(${exportFileName})
+
+# Verify expected targets are imported
+set(linkNames linkNameCSharp linkNameNative linkNameMixed
+ linkNamePure linkNameSafe)
+set(linkNameCSharp "${exportNameSpace}:${exportTargetName}CSharp")
+set(linkNameNative "${exportNameSpace}:${exportTargetName}Native")
+set(linkNameMixed "${exportNameSpace}:${exportTargetName}Mixed")
+set(linkNamePure "${exportNameSpace}:${exportTargetName}Pure")
+set(linkNameSafe "${exportNameSpace}:${exportTargetName}Safe")
+foreach(l ${linkNames})
+ if(NOT TARGET ${${l}})
+ message(FATAL_ERROR "imported target not found (${${l}})")
+ endif()
+endforeach()
+
+# Test referencing managed assemblies from C# executable.
+add_executable(ReferenceImportCSharp ReferenceImport.cs)
+target_link_libraries(ReferenceImportCSharp
+ ${linkNameCSharp}
+ ${linkNameNative} # ignored
+ ${linkNameMixed}
+ ${linkNamePure}
+ ${linkNameSafe}
+ )
+
+# native C++ executable.
+add_executable(ReferenceImportNative ReferenceImportNative.cxx)
+target_link_libraries(ReferenceImportNative
+ ${linkNameCSharp} # ignored
+ ${linkNameNative}
+ ${linkNameMixed}
+ ${linkNamePure} # ignored
+ ${linkNameSafe} # ignored
+ )
+add_custom_command(TARGET ReferenceImportNative POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "$<TARGET_FILE:${linkNameNative}>"
+ "${CMAKE_BINARY_DIR}/$<CONFIG>"
+ )
+
+# mixed C++ executable.
+add_executable(ReferenceImportMixed ReferenceImportMixed.cxx)
+target_link_libraries(ReferenceImportMixed
+ ${linkNameCSharp}
+ ${linkNameNative}
+ ${linkNameMixed}
+ ${linkNamePure}
+ ${linkNameSafe}
+ )
+set_target_properties(ReferenceImportMixed PROPERTIES
+ COMMON_LANGUAGE_RUNTIME "")
+
+# pure C++ executable.
+add_executable(ReferenceImportPure ReferenceImportPure.cxx)
+target_link_libraries(ReferenceImportPure
+ ${linkNameCSharp}
+ ${linkNameNative} # ignored
+ ${linkNameMixed}
+ ${linkNamePure}
+ ${linkNameSafe}
+ )
+set_target_properties(ReferenceImportPure PROPERTIES
+ COMMON_LANGUAGE_RUNTIME "pure")
+
+# native C++ executable.
+add_executable(ReferenceImportSafe ReferenceImportSafe.cxx)
+target_link_libraries(ReferenceImportSafe
+ ${linkNameCSharp}
+ ${linkNameNative} # ignored
+ ${linkNameMixed}
+ ${linkNamePure}
+ ${linkNameSafe}
+ )
+set_target_properties(ReferenceImportSafe PROPERTIES
+ COMMON_LANGUAGE_RUNTIME "safe")
diff --git a/Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cs b/Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cs
new file mode 100644
index 0000000..24175f6
--- /dev/null
+++ b/Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cs
@@ -0,0 +1,13 @@
+using System;
+
+public class ReferenceImport
+{
+ public static void Main()
+ {
+ Console.WriteLine("ReferenceImportCSharp");
+ ImportLibMixed.Message();
+ ImportLibPure.Message();
+ ImportLibSafe.Message();
+ ImportLibCSharp.Message();
+ }
+}
diff --git a/Tests/RunCMake/CSharpReferenceImport/ReferenceImportMixed.cxx b/Tests/RunCMake/CSharpReferenceImport/ReferenceImportMixed.cxx
new file mode 100644